diff --git a/.github/AGENTS.md b/.github/AGENTS.md deleted file mode 100644 index 63e3022..0000000 --- a/.github/AGENTS.md +++ /dev/null @@ -1,44 +0,0 @@ -# .github/ - -## Purpose - -GitHub repository configuration: CI/CD workflows, release automation, and issue/PR templates. Defines what runs on `main` pushes, PRs, and version tags. - -## Ownership - -### Workflows (`workflows/`) -- `ci.yml` — CI on push/PR to `main`. Steps: `bun install` → `bun run typecheck` → `bun run build` → `bun run test` → `bun audit` (non-blocking: `continue-on-error: true`, dev-only findings don't gate `main`). Permissions: `contents: read` -- `sonarcloud.yml` — Runs `bun run test:coverage` and uploads the LCOV report to SonarCloud on push/PR to `main`. Coverage exclusions in `sonar-project.properties` (repo root) -- `release.yml` — Triggered by `v*` tag pushes. Runs typecheck, build, test; checks if the version is already on npm and if a GitHub release exists; publishes to npm (Node 24, `NPM_TOKEN` secret, `https://registry.npmjs.org`) and creates a GitHub Release with body extracted from `docs/CHANGELOG.md` plus auto-generated PR notes. Idempotent — re-runs won't duplicate publishes/releases -- `opencode.yml` — OpenCode-related workflow - -### Templates and community files (repo root of `.github/`) -- `pull_request_template.md` — PR checklist (typecheck, test, build, style, JSDoc, README/CHANGELOG) -- `ISSUE_TEMPLATE/bug_report.md`, `ISSUE_TEMPLATE/feature_request.md` — Issue templates -- `CONTRIBUTING.md` — Contributor guide including Release Process, Contributor Credits, and Version Numbering sections; the canonical contributor reference is `docs/DEVELOPMENT.md` + `docs/TESTING.md` -- `SECURITY.md` — Private vulnerability reporting policy (GitHub security advisory or direct contact to @ZeR020). Supported versions and disclosure timeline -- `CODE_OF_CONDUCT.md` — Contributor Covenant -- README assets (banner, screenshots) moved to `docs/assets/` - -## Local Contracts - -- CI gates on `main`: typecheck, build, test must pass. `bun audit` runs but is non-blocking (dev-only vulnerabilities don't gate CI). The same checks run on PRs -- Release is tag-driven (`v*`) only; never publish to npm outside the release workflow. `NPM_TOKEN` is the required repository secret -- The release workflow is idempotent (checks `npm view` and `gh release view` before acting) — preserve those guards -- `permissions` blocks are scoped (`contents: read` for CI, `contents: write` for release) — do not broaden them -- SonarCloud coverage exclusions live in `sonar-project.properties`; keep them aligned with `vitest.config.ts` coverage excludes - -## Work Guidance - -- New CI check → add to `ci.yml` and to the local verification list in the root AGENTS.md and `docs/DEVELOPMENT.md` -- Release process: bump `package.json`, update `docs/CHANGELOG.md`, commit, tag `v*`, push `main --tags`. See `docs/DEVELOPMENT.md` -- Security issues are reported privately per `SECURITY.md` — never via a public issue or workflow change - -## Verification - -- CI runs on every push/PR to `main` and must be green -- Release workflow is verified end-to-end only on an actual `v*` tag; dry-run by checking the `release_state` step logic locally - -## Child DOX Index - -No child AGENTS.md files. This is a leaf boundary. diff --git a/.husky/AGENTS.md b/.husky/AGENTS.md deleted file mode 100644 index 6490c14..0000000 --- a/.husky/AGENTS.md +++ /dev/null @@ -1,33 +0,0 @@ -# .husky/ - -## Purpose - -Git hooks managed by Husky. Enforces security checks, type safety, formatting, and DeepSource-equivalent linting before commits and pushes reach CI. - -## Ownership - -- `pre-commit` — Runs on `git commit`. (1) Blocks staging of sensitive file patterns (`.env*`, `.pem`, `.key`, secrets, credentials, archives, editor cruft, `.opencode/*`, `.planning/*`, etc.) and sensitive directories. (2) Scans staged text files for common secret/API key patterns (`sk-...`, `ghp_...`, `AKIA...`, `glpat-...`, `npm_...`, etc.) and warns interactively. (3) Flags tracked files matching `.gitignore`. (4) Runs `bun run typecheck && bunx lint-staged` (Prettier auto-format on staged files) -- `pre-push` — Runs on `git push`. Invokes `bash scripts/lint-deepsource.sh` to catch DeepSource JS analyzer issues (async-without-await, `var`, loose equality, `console.*` outside logger, empty catch, non-null `!` / `any` without `skipcq`) before they fail CI - -## Local Contracts - -- Both hooks are load-bearing gates; the rules they encode mirror the root AGENTS.md `Local Contracts` and `scripts/lint-deepsource.sh`. Keep all three in sync when a rule changes -- `pre-commit` blocks (not just warns) on sensitive file patterns and directories — do not weaken this. Bypass only via `git commit --no-verify` in genuine test/mock cases -- `lint-staged` runs Prettier on staged `*.{ts,tsx,js,jsx,css,html,json,md}` (config in `package.json`) -- Husky is installed via `npm run prepare` → `husky` (wired in `package.json` `scripts.prepare`) - -## Work Guidance - -- Adding a sensitive pattern → add to the `pre-commit` `case` block and note it in the root AGENTS.md -- Adding a DeepSource rule → add to `scripts/lint-deepsource.sh` (which `pre-push` runs) and the root `Local Contracts` -- Hooks are shell scripts (`#!/bin/sh`) — keep them POSIX-compatible - -## Verification - -- A blocked file pattern aborts the commit with a non-zero exit -- `pre-commit` runs `bun run typecheck` (strict) — any type error aborts the commit -- `pre-push` runs the DeepSource lint — any finding aborts the push - -## Child DOX Index - -No child AGENTS.md files. This is a leaf boundary. diff --git a/AGENTS.md b/AGENTS.md deleted file mode 100644 index 6929ee0..0000000 --- a/AGENTS.md +++ /dev/null @@ -1,145 +0,0 @@ -# DOX framework - -- DOX is highly performant AGENTS.md hierarchy installed here -- Agent must follow DOX instructions across any edits - -## Core Contract - -- AGENTS.md files are binding work contracts for their subtrees -- Work products, source materials, instructions, records, assets, and durable docs must stay understandable from the nearest applicable AGENTS.md plus every parent AGENTS.md above it - -## Read Before Editing - -1. Read the root AGENTS.md -2. Identify every file or folder you expect to touch -3. Walk from the repository root to each target path -4. Read every AGENTS.md found along each route -5. If a parent AGENTS.md lists a child AGENTS.md whose scope contains the path, read that child and continue from there -6. Use the nearest AGENTS.md as the local contract and parent docs for repo-wide rules -7. If docs conflict, the closer doc controls local work details, but no child doc may weaken DOX - -Do not rely on memory. Re-read the applicable DOX chain in the current session before editing. - -## Update After Editing - -Every meaningful change requires a DOX pass before the task is done. - -Update the closest owning AGENTS.md when a change affects: - -- purpose, scope, ownership, or responsibilities -- durable structure, contracts, workflows, or operating rules -- required inputs, outputs, permissions, constraints, side effects, or artifacts -- user preferences about behavior, communication, process, organization, or quality -- AGENTS.md creation, deletion, move, rename, or index contents - -Update parent docs when parent-level structure, ownership, workflow, or child index changes. Update child docs when parent changes alter local rules. Remove stale or contradictory text immediately. Small edits that do not change behavior or contracts may leave docs unchanged, but the DOX pass still must happen. - -## Hierarchy - -- Root AGENTS.md is the DOX rail: project-wide instructions, global preferences, durable workflow rules, and the top-level Child DOX Index -- Child AGENTS.md files own domain-specific instructions and their own Child DOX Index -- Each parent explains what its direct children cover and what stays owned by the parent -- The closer a doc is to the work, the more specific and practical it must be - -## Child Doc Shape - -- Create a child AGENTS.md when a folder becomes a durable boundary with its own purpose, rules, responsibilities, workflow, materials, or quality standards -- Work Guidance must reflect the current standards of the project or user instructions; if there are no specific standards or instructions yet, leave it empty -- Verification must reflect an existing check; if no verification framework exists yet, leave it empty and update it when one exists - -Default section order: - -- Purpose -- Ownership -- Local Contracts -- Work Guidance -- Verification -- Child DOX Index - -## Style - -- Keep docs concise, current, and operational -- Document stable contracts, not diary entries -- Put broad rules in parent docs and concrete details in child docs -- Prefer direct bullets with explicit names -- Do not duplicate rules across many files unless each scope needs a local version -- Delete stale notes instead of explaining history -- Trim obvious statements, repeated rules, misplaced detail, and warnings for risks that no longer exist - -## Closeout - -1. Re-check changed paths against the DOX chain -2. Update nearest owning docs and any affected parents or children -3. Refresh every affected Child DOX Index -4. Remove stale or contradictory text -5. Run existing verification when relevant -6. Report any docs intentionally left unchanged and why - -## User Preferences - -When the user requests a durable behavior change, record it here or in the relevant child AGENTS.md - ---- - -# opencode-mem0 - -## Purpose - -OpenCode plugin that gives coding agents persistent, private long-term memory via a local vector database (SQLite + usearch). No cloud services required — all data stays on the user's machine. The plugin intercepts OpenCode chat/session events, stores technical knowledge as vector-embedded memories, and injects relevant context back into agent conversations. - -Cognitive enhancement fork of `tickernelz/opencode-mem`, published to npm as `opencode-mem0`. Maintained by ZeR020 under the MIT license. - -## Ownership - -- Repository: `github.com/ZeR020/opencode-mem0`, default branch `main` -- Package: `opencode-mem0` on npm; published artifacts are `dist/`, `package.json`, `README.md`, `LICENSE`, `docs/CHANGELOG.md` -- Runtime: Bun >= 1.0.0 (primary, Linux/macOS, native `bun:sqlite`) or Node.js >= 20.0.0 (fallback, any platform, `better-sqlite3`) -- Language: strict TypeScript, ESM (`"type": "module"`) -- Versioning/release: Conventional Commits, automated via `.github/workflows/release.yml` on `v*` tags - -## Local Contracts - -- TypeScript strict mode is mandatory: `strict`, `noUncheckedIndexedAccess`, `noImplicitOverride`, `noFallthroughCasesInSwitch`, `verbatimModuleSyntax`. Prefer explicit types over `any`; use `unknown` then narrow when the type is truly unknown -- JSDoc required on all public functions, classes, and exported constants (`@param`, `@returns`, behavior + side effects) -- Prettier is the formatter: semicolons, double quotes, 2-space indent, 100 char width, ES5 trailing commas, LF. Run `bun run format` before committing -- Conventional Commits only: `type(scope): description`, present tense. Valid types: `feat`, `fix`, `chore`, `docs`, `refactor`, `test`, `ci` -- No `console.*` outside the logger module; no `var`; no loose `==`/`!=` outside null checks; no empty catch blocks; no non-null `!` or explicit `any` without `skipcq` annotation (DeepSource rules enforced by `scripts/lint-deepsource.sh`) -- New AI providers and embedding backends integrate through the existing factory/abstraction seams — never bypass `AIProviderFactory` or the `VectorBackend` interface -- All data stays local. Never add cloud telemetry, remote reporting, or outbound network calls beyond the user-configured embedding/AI endpoints -- Privacy boundaries are load-bearing: secrets and PII are stripped by `privacy.ts` before any LLM call; preserve that invariant in any capture path -- **No direct commits to `main`** — branch protection is enforced for all users including admins. Every change goes through a PR: branch → commit → push → PR → CI → merge. Branch naming: `fix/`, `feat/`, `refactor/`, `chore/`, `docs/` -- **PR titles use Conventional Commits** — `fix(scope): description`, `feat(scope): description`, etc. Link issues with `Fixes #N` in the PR body so GitHub auto-closes them on merge and credits the reporter in release notes -- **Squash merge only** — `required_linear_history` is enabled. PRs are squash-merged to keep `main` history clean with one commit per PR -- **Release process**: bump version in `package.json` → write `docs/CHANGELOG.md` entry (Added/Fixed/Removed/Changed/Closed/Contributors) → commit → tag `vX.Y.Z` → push tag. The release workflow auto-publishes to npm and creates the GitHub release from the changelog -- **Contributor credits**: community contributors who report issues or submit PRs are credited by GitHub username in the `docs/CHANGELOG.md` Contributors section for the release that ships their contribution - -## Work Guidance - -- Reuse existing patterns before introducing new ones. A second convention beside an existing one is prohibited -- Run `lsp references` before modifying exported symbols — missed callsites are bugs -- New services go in `src/services/.ts`, get JSDoc, integrate through `src/services/client.ts` when part of the primary API surface, and ship with `tests/.test.ts` -- Keep PRs focused; separate unrelated changes. Verify locally before opening: `bun run typecheck && bun run test && bun run build && bun run format:check && bash scripts/lint-deepsource.sh` -- When changing user-facing behavior, update the matching doc in `docs/` (`CONFIGURATION.md`, `GETTING-STARTED.md`, `DEVELOPMENT.md`, `ARCHITECTURE.md`) and any JSON schema/example configs - -## Verification - -- `bun run typecheck` — strict `tsc --noEmit`, zero errors -- `bun run test` — full Vitest suite (`tests/**/*.test.ts`, 430+ tests, node env, `tests/setup-home.ts` isolates HOME) -- `bun run build` — `tsc` to `dist/` + copy `src/web/` to `dist/web/` via `scripts/build.mjs` -- `bun audit` — dependency vulnerability scan (non-blocking in CI: dev-only findings don't gate `main`) -- `bun run format:check` — Prettier check -- `bash scripts/lint-deepsource.sh` — local DeepSource-equivalent lint (runs on pre-push) -- CI (`.github/workflows/ci.yml`): typecheck → build → test → audit (non-blocking), all gates pass on `main` - -## Child DOX Index - -| Path | Scope | -| ------------------- | ------------------------------------------------------------------------ | -| `src/AGENTS.md` | Source root: plugin entry point, config layer, shared types, plugin shim | -| `tests/AGENTS.md` | Vitest test suite conventions and mocking patterns | -| `scripts/AGENTS.md` | Build, lint, and migration scripts | -| `docs/AGENTS.md` | Project documentation set | -| `.github/AGENTS.md` | CI workflows, issue/PR templates, release automation | -| `.husky/AGENTS.md` | Git hooks (pre-commit, pre-push) | - -Source service subsystems are indexed under `src/AGENTS.md` → `src/services/AGENTS.md`, which owns the service-layer children (`sqlite/`, `vector-backends/`, `ai/`, `user-profile/`). The `src/web/` UI assets are indexed directly under `src/AGENTS.md` (they sit under `src/`, not `src/services/`). The `src/services/handlers/` directory has no separate AGENTS.md — see `src/services/AGENTS.md`. diff --git a/docs/AGENTS.md b/docs/AGENTS.md deleted file mode 100644 index b417536..0000000 --- a/docs/AGENTS.md +++ /dev/null @@ -1,40 +0,0 @@ -# docs/ - -## Purpose - -Project documentation set. User-facing and contributor-facing docs covering setup, configuration, architecture, development, testing, and release history. `docs/CHANGELOG.md` is shipped in the published package; the rest are repo-only. - -## Ownership - -- `README.md` (repo root, not here) — Project overview, install, usage, config reference. The public face of the package -- `GETTING-STARTED.md` — First-run guide: prerequisites, install steps, minimal config, verification, next steps -- `CONFIGURATION.md` — Full configuration reference: file locations, deep-merge order, every setting with default and description. The source of truth for config fields -- `ARCHITECTURE.md` — System overview, data flow (memory injection, storage, auto-capture, lifecycle, compaction recovery), key abstractions, directory structure, storage layout, vector search pipeline, configuration layer -- `DEVELOPMENT.md` — Contributor guide: setup, build commands, code style (Prettier, strict TS, DeepSource lint, JSDoc), branch conventions, PR process, project structure, release process -- `TESTING.md` — Test framework, running tests, writing new tests, mocking patterns, HOME isolation, coverage, CI integration -- `CHANGELOG.md` — Keep a Changelog format, Semantic Versioning. **Shipped in the published package** (`package.json` `files`). Updated per release -- `assets/` — README screenshots and banner images (moved from `.github/`) - -## Local Contracts - -- These docs carry a `` header marking their origin; treat them as maintained prose, not auto-generated throwaway -- `CONFIGURATION.md` is the source of truth for config fields. Adding/removing/renaming a field in `src/config.ts` requires a matching update here and in the Zod schema -- `ARCHITECTURE.md` describes the system data flow and key abstractions; structural changes (new service, changed flow, new abstraction) require an update here -- `CHANGELOG.md` is the only doc shipped to npm — keep entries user-facing and grouped under Keep a Changelog categories (`Added`, `Changed`, `Fixed`, `Security & Reliability`, etc.) -- `DEVELOPMENT.md` and `TESTING.md` encode the contributor workflow that the root and `tests/` AGENTS.md files also reference — keep them consistent - -## Work Guidance - -- User-facing behavior change → update the relevant doc here plus `README.md` -- Config field change → update `CONFIGURATION.md` and the Zod schema together -- Release → bump `package.json` version, add a `CHANGELOG.md` entry, tag `v*` (see `DEVELOPMENT.md` release process) -- Prefer editing existing docs over creating new ones - -## Verification - -- No automated doc lint exists. Manual review on PR; the PR template asks for doc updates when behavior changes -- `CHANGELOG.md` accuracy is verified at release time against the git log - -## Child DOX Index - -No child AGENTS.md files. This is a leaf boundary. diff --git a/scripts/AGENTS.md b/scripts/AGENTS.md deleted file mode 100644 index 05c8536..0000000 --- a/scripts/AGENTS.md +++ /dev/null @@ -1,33 +0,0 @@ -# scripts/ - -## Purpose - -Build, lint, and data-migration scripts. Not shipped in the published package (excluded from `package.json` `files`); used for development, CI, and one-off operations. - -## Ownership - -- `build.mjs` — Build script run by `bun run build`. (1) Compiles TypeScript via `tsc` (resolved through `createRequire` to avoid the platform shim) to `dist/` with `.d.ts` + declaration maps. (2) Copies `src/web/` → `dist/web/` verbatim. Annotated `skipcq JS-0833` for an ESM/DeepSource false positive -- `lint-deepsource.sh` — Local pre-push lint catching DeepSource JS analyzer issues before CI fails. Checks: async-without-await (JS-0116), `var` (JS-0239), loose `==`/`!=` outside null checks, `console.*` outside logger (JS-E1009), empty catch blocks, non-null `!` without `skipcq`, explicit `any` without `skipcq`. Uses `rg`; run via `bash scripts/lint-deepsource.sh` -- `migrate-v1-to-v2.ts` — One-off V1→V2 schema migration utility. Detects v1 databases by missing `store_type`/`strength` columns, adds v2 scoring/lifecycle columns, creates the conflicts table and transcripts DB. Imports source via `.ts` paths (run under Bun). CLI entry validates the storage path via `resolveStoragePath` — resolves to absolute and constrains to the user's home directory, rejecting traversal/escape attempts from untrusted CLI args (SonarCloud `tssecurity:S8707`) - -## Local Contracts - -- `build.mjs` is the only build entry point; `package.json` `files` controls what ships (`dist/`, `package.json`, `README.md`, `LICENSE`, `docs/CHANGELOG.md`) -- `lint-deepsource.sh` encodes the DeepSource rules that CI enforces — the rules in the root AGENTS.md `Local Contracts` mirror this script. Keep them in sync when adding a rule -- `migrate-v1-to-v2.ts` imports source modules directly (`.ts`), so it runs under Bun, not the compiled `dist/` - -## Work Guidance - -- A new DeepSource rule → add the check here and to the root `Local Contracts` together -- Build script changes must keep the `tsc` resolve-via-`createRequire` pattern (the platform shim breaks direct invocation) -- Migration scripts are one-off; do not wire them into the normal build or test runs - -## Verification - -- `bun run build` succeeds and `dist/` + `dist/web/` are populated -- `bash scripts/lint-deepsource.sh` exits 0 before push (also enforced by `.husky/pre-push`) -- `migrate-v1-to-v2.ts` is not covered by the test suite; run manually against a backed-up data dir - -## Child DOX Index - -No child AGENTS.md files. This is a leaf boundary. diff --git a/src/AGENTS.md b/src/AGENTS.md deleted file mode 100644 index de209ff..0000000 --- a/src/AGENTS.md +++ /dev/null @@ -1,39 +0,0 @@ -# src/ - -## Purpose - -Source root for the opencode-mem0 plugin. Contains the plugin entry point and lifecycle hooks, the configuration layer, shared types, and the `services/` subtree that holds all runtime logic. - -## Ownership - -- `src/index.ts` — Plugin entry point. Exports `OpenCodeMemPlugin` (the `Plugin` object loaded by OpenCode). Wires all OpenCode hooks (`chat.message`, `session.idle`, `session.compacted`, `session.end`), defines the `memory` tool (modes: `add`, `search`, `profile`, `list`, `forget`, `help`), starts/stops background jobs (scoring recalculation, lifecycle maintenance), and launches the Web UI server. This is the single integration seam with the OpenCode host -- `src/plugin.ts` — Plugin loader shim. Dynamically imports `index.js`, exports `{ id, server: OpenCodeMemPlugin }` satisfying `PluginModule`. The `console.error` here is the one sanctioned `console.*` outside the logger (annotated `skipcq JS-0002`) -- `src/config.ts` — Configuration loading, validation, defaults, and global/project merge. Defines `OpenCodeMemConfig`, `VectorBackendConfig`, the Zod schema `OpenCodeMemConfigSchema`, and exports `CONFIG`, `isConfigured`, `initConfig`. Loads from `~/.config/opencode/opencode-mem0.jsonc|.json` (global) and `/.opencode/opencode-mem0.jsonc|.json` (project, overrides global). Secrets resolved via `services/secret-resolver.js` `resolveSecretValue()` (env var indirection). Known tech debt (noted in-file): 85+ `as` casts on SQL results from `bun:sqlite` `.all()` returning `unknown[]` -- `src/types/index.ts` — Shared, stable types: `MemoryType` (semantic string alias), `MemoryMetadata` (with `[key: string]: unknown` extension seam), `AIProviderType` union (`"openai-chat" | "openai-responses" | "anthropic" | "google-gemini"`) - -## Local Contracts - -- The OpenCode host loads `src/plugin.ts`; everything else is reached through `index.ts` or via `services/client.ts` as the primary programmatic API surface -- The `memory` tool modes in `index.ts` are the agent-facing contract: `add`, `search`, `profile`, `list`, `forget`, `help`. Adding a mode is a user-facing change — update README, tool schema, and tests -- Configuration fields are public contract. Adding/removing/renaming a field in `config.ts` requires updating `docs/CONFIGURATION.md` and the Zod schema together -- `MemoryMetadata` and `AIProviderType` in `types/index.ts` are shared across services; widen via the `[key: string]: unknown` index signature rather than breaking existing fields -- Privacy invariant: every chat/transcript path into an LLM passes through `services/privacy.ts` (`stripPrivateContent` / `isFullyPrivate`) — `index.ts` enforces this at the capture boundaries - -## Work Guidance - -- New runtime logic belongs in `src/services/.ts`, integrated through `services/client.ts` when part of the primary API. See `src/services/AGENTS.md` -- The Web UI assets live in `src/web/` and are copied verbatim to `dist/web/` by the build — see `src/web/AGENTS.md` -- Prefer named exports. Dynamic `import()` is used deliberately in `plugin.ts` to surface load failures with the plugin id - -## Verification - -- `bun run typecheck` (strict `tsc --noEmit`) covers all of `src/` -- `bun run build` compiles `src/` → `dist/` with declaration files and copies `src/web/` → `dist/web/` -- Per-module behavior is verified by the matching `tests/*.test.ts` — see `tests/AGENTS.md` - -## Child DOX Index - -| Path | Scope | -| ------------------------ | ------------------------------------------------------------------------------------------------------- | -| `src/services/AGENTS.md` | Service layer: memory client, scoring, lifecycle, retrieval, capture, storage, AI providers, web server | -| `src/web/AGENTS.md` | Web UI static assets (SPA shell, app logic, styles, i18n) | diff --git a/src/services/AGENTS.md b/src/services/AGENTS.md deleted file mode 100644 index d233c9b..0000000 --- a/src/services/AGENTS.md +++ /dev/null @@ -1,94 +0,0 @@ -# src/services/ - -## Purpose - -The service layer — all runtime logic of the plugin. A thin plugin entry point (`src/index.ts`) delegates here. Services follow a service-oriented pattern: a central orchestrator coordinates specialized services for storage, scoring, retrieval, lifecycle, capture, conflict detection, and the web UI. - -## Ownership - -### Primary API surface - -- `client.ts` — `LocalMemoryClient` (exported as `memoryClient` singleton). Central orchestrator for all memory operations: `addMemory`, `searchMemories`, `deleteMemory`, `listMemories`, `searchMemoriesBySessionID`. Coordinates embedding, scoring, lifecycle, deduplication, conflict detection, and storage. Exports `MemoryScope` type (`"project" | "all-projects"`). New services that are part of the primary API integrate through this client - -### Memory scoring, lifecycle, retrieval - -- `memory-scoring.ts` — 7-factor scoring (`calculateAllScores`, `computeStrength`): recency (Ebbinghaus half-life), frequency, importance, utility, novelty (Jaccard), confidence, interference. Weighted sum → `strength`. Configurable via `MemoryScoringWeights` -- `memory-scoring-service.ts` — Periodic scoring recalculation job (`startScoringRecalculation`/`stopScoringRecalculation`/`runOneTimeScoringRecalculation`), default every 60 min -- `memory-lifecycle.ts` — STM/LTM dual-store with Ebbinghaus decay. `classifyMemory` assigns `storeType` + `decayRate`. Promotion at `promotionThreshold` (0.7), archival below `archiveThreshold` (0.2). `startLifecycleJob`/`stopLifecycleJob`/`runLifecycleMaintenance` -- `memory-conflicts.ts` — LLM-backed contradiction detection (`detectConflicts`/`resolveConflict`) with heuristic fallback; stores conflicts in a dedicated table -- `retrieval-context.ts` — Query intent classification, context boost, diversity penalty for search reranking. `RetrievalContext` defines the query analysis result shape -- `deduplication-service.ts` — Ingest-time near-duplicate detection (≥0.9 cosine) and batch dedup across shards - -### Capture and context - -- `context.ts` — `formatContextForPrompt`: scores memories for query relevance, applies `injection.tokenBudget`, includes user profile if `injectProfile`, formats as `plain`/`xml`/`yaml` -- `auto-capture.ts` — `performAutoCapture`: session idle → LLM extracts technical knowledge → stores as memory. Privacy-filtered input -- `transcript-capture.ts` — Raw transcript storage/cleanup (`cleanupOldTranscripts`); FTS5-indexed -- `user-memory-learning.ts` — `performUserProfileLearning`: analyzes unanalyzed user prompts to build/update the user profile -- `privacy.ts` — `stripPrivateContent`/`isFullyPrivate`: strips API keys, tokens, PII before any LLM call. Load-bearing invariant — every capture path routes through this -- `language-detector.ts` — Language detection via `franc-min`; display names via `Intl.DisplayNames` - -### Storage and infrastructure - -- `sqlite/` — Database layer: connections, schema, vector search, sharding, transcripts. See `src/services/sqlite/AGENTS.md` -- `vector-backends/` — Pluggable vector index backends. See `src/services/vector-backends/AGENTS.md` -- `embedding.ts` — `EmbeddingService` singleton (`embeddingService`): local Xenova/transformers.js (`Xenova/nomic-embed-text-v1`) or remote OpenAI-compatible API. SHA-256-keyed LRU cache (100 entries). `warmup`/`isWarmedUp`/`embedWithTimeout` -- `web-server.ts` — `WebServer` / `startWebServer`: HTTP server for the Memory Explorer UI + REST API (default `127.0.0.1:4747`) -- `api-handlers.ts` — REST API endpoint handlers (CRUD, search, stats, conflicts, deduplication, migration), consumed by `web-server.ts` -- `platform-server.ts` — Platform-agnostic HTTP server abstraction (Bun vs Node) -- `tags.ts` — Project/user tag generation from git config and directory. Git executable resolved from a fixed list of trusted paths only (no ambient `PATH` lookup — SonarCloud `typescript:S4036`) -- `secret-resolver.ts` — `resolveSecretValue`: secret resolution from env vars (used by `config.ts`) -- `jsonc.ts` — JSONC (JSON with comments) parser (used by `config.ts`) -- `logger.ts` — Structured logging with level control. The only module permitted to use `console.*` -- `cleanup-service.ts` — Old memory and transcript cleanup -- `migration-service.ts` — V1→V2 data migration - -### AI providers - -- `ai/` — Provider factory, session management, tool schemas, validators, and provider implementations. See `src/services/ai/AGENTS.md` - -### HTTP request handlers - -- `handlers/` — `memory.ts`, `search.ts`, `profile.ts`, `transcripts.ts`, `conflicts.ts`, `admin.ts` request handlers; `shared.ts`/`shared-types.ts` shared handler utilities and types. Consumed by `api-handlers.ts` - -### User profile and prompt - -- `user-profile/` — Profile manager, types, context, utils. See `src/services/user-profile/AGENTS.md` -- `user-prompt/user-prompt-manager.ts` — User prompt storage/retrieval for learning - -### Utilities - -- `utils/safe-transforms.ts` — `safeJSONParse`, safe date conversion -- `utils/text-analysis.ts` — Text analysis helpers -- `utils/memory-mapper.ts` — DB row → list/session result mappers - -## Local Contracts - -- `memoryClient` (`client.ts`) is the primary API surface. Other services are composed by it; do not bypass it for memory operations from the plugin entry point -- Scoring weights, lifecycle thresholds, and decay curves are config-driven (`config.ts`) — hardcoding them is prohibited -- The `VectorBackend` interface (`vector-backends/types.ts`) is the only seam for new vector index implementations -- `AIProviderFactory` (`ai/ai-provider-factory.ts`) is the only seam for new AI providers; a new provider also extends `AIProviderType` in `src/types/index.ts` -- `privacy.ts` stripping is mandatory before any LLM call in any capture path — never ship a capture path that bypasses it -- `logger.ts` owns `console.*`. No other service may call `console.*` directly (DeepSource JS-E1009) - -## Work Guidance - -- Adding a new service: create `src/services/.ts`, add JSDoc, integrate through `client.ts` if part of the primary API, add `tests/.test.ts`. See `src/AGENTS.md` -- Adding an AI provider: extend `AIProviderType`, implement under `ai/providers/`, register in `ai-provider-factory.ts`. See `src/services/ai/AGENTS.md` -- Adding a vector backend: implement `VectorBackend`, register in `backend-factory.ts`. See `src/services/vector-backends/AGENTS.md` -- Background jobs must be started in `src/index.ts` and export start/stop functions; never leave a job running after plugin teardown - -## Verification - -- Each service module has a matching `tests/.test.ts` (e.g. `tests/memory-scoring.test.ts` ↔ `src/services/memory-scoring.ts`). See `tests/AGENTS.md` -- `bun run typecheck` covers all services under strict mode -- Vector backend integration is verified by `tests/vector-backends/` and `tests/vector-search-backend-integration.test.ts` - -## Child DOX Index - -| Path | Scope | -| ---------------------------------------- | -------------------------------------------------------------------------------- | -| `src/services/sqlite/AGENTS.md` | SQLite database layer: connections, schema, vector search, sharding, transcripts | -| `src/services/vector-backends/AGENTS.md` | Pluggable vector index backends (usearch, exact-scan) | -| `src/services/ai/AGENTS.md` | AI provider factory, session, tools, validators, and provider implementations | -| `src/services/user-profile/AGENTS.md` | User profile manager, types, context, utils | diff --git a/src/services/ai/AGENTS.md b/src/services/ai/AGENTS.md deleted file mode 100644 index 9f3999b..0000000 --- a/src/services/ai/AGENTS.md +++ /dev/null @@ -1,40 +0,0 @@ -# src/services/ai/ - -## Purpose - -AI provider subsystem used by auto-capture and conflict detection to extract technical knowledge and resolve contradictions via LLMs. Supports OpenAI-compatible chat and responses APIs, Anthropic, and Google Gemini, plus a bridge to OpenCode's own connected providers. - -## Ownership - -- `ai-provider-factory.ts` — `AIProviderFactory`. Static factory with a `PROVIDERS` registry mapping `AIProviderType` → provider constructor. `createProvider()` is the only seam for constructing providers -- `provider-config.ts` — `buildMemoryProviderConfig()`: assembles a `ProviderConfig` from the runtime config fields (`memoryModel`, `memoryApiUrl`, `memoryApiKey`, `memoryTemperature`, `memoryExtraParams`) plus iteration/timeout overrides. Throws if the external API is not configured -- `opencode-provider.ts` — Bridge to OpenCode's connected AI providers (`opencodeProvider`/`opencodeModel` config). Reuses the host's main model instead of a separate API endpoint -- `session/session-types.ts` — `AIProviderType` (re-exported), session types -- `session/ai-session-manager.ts` — `AISessionManager` (via `getAISessionManager()`): AI provider session management with expiration. Retention via `aiSessionRetentionDays`. Expired-session cleanup is scheduled inline by `src/index.ts` via `setInterval` -- `tools/tool-schema.ts` — Structured output tool definitions handed to providers -- `validators/user-profile-validator.ts` — Output validation schemas for profile extraction -- `providers/` — Provider implementations. See `src/services/ai/providers/AGENTS.md` - -## Local Contracts - -- New providers extend `BaseAIProvider` (`providers/base-provider.ts`), implement `executeToolCall`/`getProviderName`, register in the `PROVIDERS` map, and add their key to `AIProviderType` (`src/types/index.ts` and `session/session-types.ts`) -- `ProviderConfig` (`providers/base-provider.ts`) is the shared config shape; `buildMemoryProviderConfig()` is the constructor for it -- `applySafeExtraParams()` guards against prototype-pollution and request-clobbering keys (`UNSAFE_KEYS` set) — never bypass it when merging `memoryExtraParams` into a request body -- Provider construction goes through `AIProviderFactory.createProvider()` only; never `new` a provider directly at call sites -- Without a configured provider, auto-capture and conflict detection silently skip with a log warning — preserve that graceful degradation - -## Work Guidance - -- Adding a provider: see `src/services/ai/providers/AGENTS.md` -- Session cleanup is scheduled inline by `src/index.ts` (`setInterval` → `getAISessionManager().cleanupExpiredSessions()`); the factory no longer owns the cleanup schedule -- The OpenCode provider bridge (`opencode-provider.ts`) is the zero-config path; the external providers are the explicit-config path. Keep both working - -## Verification - -- `tests/ai-provider-config.test.ts`, `tests/ai-session-manager.test.ts`, `tests/opencode-provider.test.ts`, `tests/openai-chat-completion-provider.test.ts`, `tests/openai-responses.test.ts`, `tests/anthropic-messages.test.ts`, `tests/anthropic-provider.test.ts`, `tests/google-gemini.test.ts` - -## Child DOX Index - -| Path | Scope | -| ------------------------------------- | ------------------------------------------------------------------------------- | -| `src/services/ai/providers/AGENTS.md` | Provider implementations: base, OpenAI chat/responses, Anthropic, Google Gemini | diff --git a/src/services/ai/providers/AGENTS.md b/src/services/ai/providers/AGENTS.md deleted file mode 100644 index 0ee4e1b..0000000 --- a/src/services/ai/providers/AGENTS.md +++ /dev/null @@ -1,36 +0,0 @@ -# src/services/ai/providers/ - -## Purpose - -AI provider implementations. Each adapts a vendor API (or OpenCode's host provider) to the common `BaseAIProvider` contract so auto-capture and conflict detection can call any provider uniformly. - -## Ownership - -- `base-provider.ts` — `BaseAIProvider` abstract class and the shared contracts: `ProviderConfig`, `ToolCallResult`, `applySafeExtraParams()`. The `UNSAFE_KEYS` set blocks prototype-pollution / request-clobbering keys (`model`, `messages`, `tools`, `__proto__`, etc.) from `extraParams` merges -- `openai-chat-completion.ts` — `OpenAIChatCompletionProvider`: any OpenAI-compatible Chat Completions API (the `openai-chat` type, default `memoryProvider`) -- `openai-responses.ts` — `OpenAIResponsesProvider`: OpenAI Responses API (`openai-responses` type) -- `anthropic-messages.ts` — `AnthropicMessagesProvider`: Anthropic Messages API (`anthropic` type) -- `google-gemini.ts` — `GoogleGeminiProvider`: Google Gemini API (`google-gemini` type) - -## Local Contracts - -- Every provider extends `BaseAIProvider` and implements `executeToolCall(systemPrompt, userPrompt, toolSchema, sessionId)`, `getProviderName()` -- Providers are registered in `ai-provider-factory.ts`'s `PROVIDERS` map and keyed by an `AIProviderType` member in `src/types/index.ts` -- All `extraParams` merges go through `applySafeExtraParams()` — never spread `memoryExtraParams` directly into a request body -- Providers receive a `ProviderConfig` (built by `provider-config.ts`) and an `AISessionManager`; they do not read `CONFIG` directly -- Vendor-specific request/response shaping stays inside the provider file; the factory and call sites see only `ToolCallResult` - -## Work Guidance - -- Adding a provider: create `.ts` extending `BaseAIProvider`; add the key to `AIProviderType`; register in the `PROVIDERS` map; add `tests/.test.ts` mocking the vendor HTTP surface -- Keep vendor SDK imports lazy/optional where the SDK is heavy — the plugin must load even when a provider's SDK is unused -- Error handling must return a `ToolCallResult` with `success: false` and a message rather than throwing out of `executeToolCall`, so auto-capture can degrade gracefully - -## Verification - -- `tests/openai-chat-completion-provider.test.ts`, `tests/openai-responses.test.ts`, `tests/anthropic-messages.test.ts`, `tests/anthropic-provider.test.ts`, `tests/google-gemini.test.ts` -- `tests/ai-provider-config.test.ts` covers `ProviderConfig` construction - -## Child DOX Index - -No child AGENTS.md files. This is a leaf boundary. diff --git a/src/services/sqlite/AGENTS.md b/src/services/sqlite/AGENTS.md deleted file mode 100644 index dfa2d3a..0000000 --- a/src/services/sqlite/AGENTS.md +++ /dev/null @@ -1,40 +0,0 @@ -# src/services/sqlite/ - -## Purpose - -The database layer. Persists all memories, transcripts, and shard metadata to local SQLite databases with WAL journaling, schema migrations, sharding, and hybrid vector + FTS5 search. Runtime-agnostic: uses native `bun:sqlite` under Bun or `better-sqlite3` under Node. - -## Ownership - -- `sqlite-bootstrap.ts` — Runtime abstraction over SQLite. Detects Bun vs Node, defines the `Database` and `Statement` interfaces used throughout the layer, and wraps the underlying driver into a common shape. All other modules import `Database`/`Statement` types from here -- `connection-manager.ts` — `ConnectionManager` (exported as `connectionManager` singleton). LRU connection pool (max 20 connections). Handles WAL mode, 64MB cache, schema migrations, batch writes, and checkpointing. The single owner of open database handles -- `shard-manager.ts` — `ShardManager` (exported as `shardManager` singleton). Manages shards per scope (`user`/`project`) and scope hash. Auto-creates new shards when `maxVectorsPerShard` (default 50,000) is reached. Exports `extractScopeFromContainerTag` -- `vector-search.ts` — `VectorSearch` (exported as `vectorSearch` singleton). Hybrid search engine: vector similarity via pluggable backend + FTS5 text search + multi-factor ranking with context boost and diversity filtering. `insertVector` writes records with all scoring/metadata/vector blob fields -- `transcript-manager.ts` — `TranscriptManager`. Stores raw session transcripts with FTS5 full-text search. Retention via `transcriptStorage.maxAgeDays` -- `schema.ts` — Schema version tracking and migrations. `CURRENT_SCHEMA_VERSION`, `MIGRATIONS` map, `getCurrentVersion`, `runMigrations`. Idempotent migration runner that skips already-applied `ALTER TABLE`/`ADD COLUMN` -- `types.ts` — Shared SQLite-layer types: `ShardInfo`, `MemoryRecord` (with scoring + lifecycle fields), `SearchResult` (with retrieval scoring fields), `MemoryConflict` - -## Local Contracts - -- All database access goes through `connection-manager.ts`. Do not open SQLite handles directly elsewhere -- Schema changes require a new migration entry in `MIGRATIONS` and a bumped `CURRENT_SCHEMA_VERSION`. Migrations must be idempotent (the runner skips already-applied alters) -- `Database`/`Statement` interfaces from `sqlite-bootstrap.ts` are the only SQL surface — never import the raw Bun/Node driver directly in other modules -- `MemoryRecord`, `SearchResult`, `ShardInfo`, `MemoryConflict` in `types.ts` are the row/record contracts shared with `client.ts` and the scoring/lifecycle services -- Storage layout (under `storagePath`, default `~/.opencode-mem0/data/`): `metadata.db` (shard registry), `users/` and `projects/` shard DBs, `transcripts.db`, `.cache/` (embedding model cache). Preserve this layout -- Vector blobs are written by `vector-search.ts` alongside scoring, lifecycle, and metadata columns in the `memories` table — keep the column set in sync with `MemoryRecord` - -## Work Guidance - -- New SQL columns: add a migration in `schema.ts`, extend `MemoryRecord`/`SearchResult` in `types.ts`, update `vector-search.ts` insert/read queries, and account for the `as` casts noted as tech debt in `src/config.ts` -- Connection pool exhaustion (max 20) is a real ceiling under heavy concurrency — profile before raising it -- WAL checkpointing and batch writes are owned by `connection-manager.ts`; rely on them rather than ad-hoc `PRAGMA` calls - -## Verification - -- `tests/connection-manager`, `tests/shard-manager`, `tests/vector-search-backend-integration.test.ts`, `tests/schema-version.test.ts`, `tests/wal-batch.test.ts` cover this layer -- `tests/vector-backends/` covers the backend integration with `vector-search.ts` -- `bun run typecheck` enforces the `Database`/`Statement` interface usage - -## Child DOX Index - -No child AGENTS.md files. This is a leaf boundary. diff --git a/src/services/user-profile/AGENTS.md b/src/services/user-profile/AGENTS.md deleted file mode 100644 index a3efef9..0000000 --- a/src/services/user-profile/AGENTS.md +++ /dev/null @@ -1,32 +0,0 @@ -# src/services/user-profile/ - -## Purpose - -User profile subsystem. Learns preferences, behavioral patterns, and workflows from session history and stores them per-user for personalized context injection into agent conversations. - -## Ownership - -- `types.ts` — Profile types: `UserProfilePreference` (category, description, confidence, evidence, lastUpdated), `UserProfilePattern`, `UserProfileWorkflow`, `UserProfileData` (preferences + patterns + workflows), `UserProfile`, `UserProfileChangelog` -- `user-profile-manager.ts` — `UserProfileManager`. Profile CRUD, merge, versioning, and confidence decay. Owns `user-profiles.db` (under `storagePath`), created via `connectionManager.getConnection`. Cap `maxPreferences`/`maxPatterns`/`maxWorkflows` from config; confidence decays after `userProfileConfidenceDecayDays`; changelog retained up to `userProfileChangelogRetentionCount` -- `profile-context.ts` — Profile context extraction for injection (used by `services/context.ts` when `injectProfile` is enabled) - -## Local Contracts - -- Profile data is keyed by user identity (`userName`/`userEmail`, overridable via `userEmailOverride`/`userNameOverride` in config) -- All DB access goes through `connectionManager` — this module opens no SQLite handles directly (it reuses the connection for `user-profiles.db`) -- `UserProfileData` is the stable shape injected into prompts; widening it requires updating `profile-context.ts` and the `max*` caps in config -- `UserProfileChangelog` retention is bounded by `userProfileChangelogRetentionCount` (default 5) — do not let it grow unbounded - -## Work Guidance - -- Profile learning is triggered by `services/user-memory-learning.ts` `performUserProfileLearning`, which runs on session idle at the interval set by `userProfileAnalysisInterval` -- Injected profile items are capped at `maxProfileItems` (default 5) — `profile-context.ts` selects the top items by confidence -- New profile categories extend `UserProfilePreference.category`/`UserProfilePattern.category` as free-form strings; no fixed enum - -## Verification - -- `tests/profile-write.test.ts`, `tests/profile-context.test.ts`, `tests/user-profile-validator.test.ts`, `tests/profile-tool-runtime.test.ts`, `tests/user-memory-learning.test.ts` - -## Child DOX Index - -No child AGENTS.md files. This is a leaf boundary. diff --git a/src/services/vector-backends/AGENTS.md b/src/services/vector-backends/AGENTS.md deleted file mode 100644 index 36c4df1..0000000 --- a/src/services/vector-backends/AGENTS.md +++ /dev/null @@ -1,36 +0,0 @@ -# src/services/vector-backends/ - -## Purpose - -Pluggable vector index backends for similarity search. Decouples the indexing algorithm from the storage layer so `vector-search.ts` can use usearch HNSW or brute-force exact scan, with an automatic fallback chain. - -## Ownership - -- `types.ts` — The `VectorBackend` interface (the only seam for new backends), `VectorBackendFactoryOptions`, `BackendSearchResult`, `BackendInsertItem`, `VectorBackendSearchParams`, `VectorKind` (`"content" | "tags"`) -- `backend-factory.ts` — `createVectorBackend()` factory. Builds a `FallbackAwareBackend` (internal, not exported) that wraps a primary + fallback backend, with a 3-transient-error retry loop and a 60s recovery window. Strategies: `usearch-first` (default), `usearch`, `exact-scan` -- `usearch-backend.ts` — `USearchBackend`: HNSW index via the usearch native binding -- `exact-scan-backend.ts` — `ExactScanBackend`: brute-force cosine similarity fallback (no index overhead) -- `shared.ts` — Shared helpers across backend implementations - -## Local Contracts - -- New backends implement `VectorBackend` from `types.ts` — that interface is the only contract. Do not add backend-specific methods to the interface -- Backends are constructed only through `createVectorBackend()` in `backend-factory.ts`. The factory wires the fallback chain; do not instantiate backends directly in `vector-search.ts` -- `VectorKind` distinguishes content vectors from tag vectors — backends must maintain separate indexes per kind -- Strategy selection is config-driven (`vectorBackend` in `config.ts`); `usearch-first` is the default and must remain a safe choice across platforms -- `FallbackAwareBackend` degrades to exact-scan after 3 transient errors and resets after 60s of error-free operation — preserve this recovery behavior - -## Work Guidance - -- Adding a backend: implement `VectorBackend`, add a strategy key to `VectorBackendFactoryOptions` and `VectorBackendConfig` (`src/config.ts`), register it in `createVectorBackend()`, add `tests/vector-backends/-backend.test.ts` -- The usearch native binding is platform-sensitive (Linux/macOS primary); exact-scan is the cross-platform safety net. Keep exact-scan dependency-free -- Backend operations take `ShardInfo` and `db: unknown` — backends must not assume a specific driver - -## Verification - -- `tests/vector-backends/usearch-backend.test.ts`, `tests/vector-backends/exact-scan-backend.test.ts`, `tests/vector-backends/migration-fallback.test.ts`, `tests/vector-backends/backend-factory.test.ts` -- `tests/vector-search-backend-integration.test.ts` covers integration with `vector-search.ts` - -## Child DOX Index - -No child AGENTS.md files. This is a leaf boundary. diff --git a/src/web/AGENTS.md b/src/web/AGENTS.md deleted file mode 100644 index e05d76c..0000000 --- a/src/web/AGENTS.md +++ /dev/null @@ -1,35 +0,0 @@ -# src/web/ - -## Purpose - -Static assets for the Memory Explorer Web UI — a single-page application served by `services/web-server.ts` at `http://127.0.0.1:4747` (default). Lets users browse, search, and manage stored memories, transcripts, conflicts, and the user profile. - -## Ownership - -- `index.html` — SPA shell. Loads CDN scripts (lucide icons, marked, DOMPurify, jsonrepair) and local `i18n.js`. Renders the header, stats bar, and view containers -- `app.js` — SPA application logic (~1800 lines). Manages UI state (memories, tags, pagination, search, selected set, auto-refresh, user profile, conflicts, transcripts), talks to the REST API (relative `API_BASE`), renders markdown via marked + DOMPurify -- `styles.css` — UI styles -- `i18n.js` — Internationalization (`getLanguage`/`setLanguage`/`t`), toggled via the in-app language button -- `favicon.ico` — Icon - -## Local Contracts - -- These assets are copied verbatim from `src/web/` to `dist/web/` by `scripts/build.mjs`. No compilation step — edits land as-is in the published package -- The SPA calls the REST API served by `services/api-handlers.ts` via a relative `API_BASE` (same origin). API key, if configured (`webServerApiKey`), is stored client-side under `opencodeMemApiKey` -- Markdown rendering must go through `marked` + `DOMPurify` (XSS boundary) — never inject unescaped memory content into the DOM -- CDN dependencies (lucide, marked, DOMPurify, jsonrepair) are dev-tool dependencies with floating versions and no SRI, annotated `NOSONAR` in `index.html` — preserve that annotation if touching the script tags - -## Work Guidance - -- UI iteration: edit here, run `bun run build` to copy to `dist/web/`, restart OpenCode. No TypeScript applies to these assets -- New API endpoints consumed by the UI require a matching handler in `services/api-handlers.ts` (see `src/services/AGENTS.md`) -- Keep the SPA dependency-free at build time — CDN scripts only, no npm deps for the UI - -## Verification - -- `tests/web-server.test.ts` and `tests/web-server-routes.test.ts` verify the server that serves these assets and its routes -- No automated UI test exists; manual verification at `http://127.0.0.1:4747` after `bun run build` - -## Child DOX Index - -No child AGENTS.md files. This is a leaf boundary. diff --git a/tests/AGENTS.md b/tests/AGENTS.md deleted file mode 100644 index 5224ebe..0000000 --- a/tests/AGENTS.md +++ /dev/null @@ -1,43 +0,0 @@ -# tests/ - -## Purpose - -The Vitest test suite. One test file per source module, mirroring the `src/services/` layout. 710+ tests across 60+ files, running in a Node environment with an isolated temporary HOME so tests never touch real `~/.opencode-mem0` data. - -## Ownership - -- `setup-home.ts` — Global setup file (wired in `vitest.config.ts`). Creates a temp `HOME`/`USERPROFILE` under `os.tmpdir()`, ensures `~/.opencode-mem0` exists, and in `afterAll` flushes logger buffers (source + built) and removes the temp dir. Prevents tests from polluting real user data and prevents hanging logger handles -- `*.test.ts` — One top-level `describe` per file named after the module under test, with nested `describe` blocks for logical groupings -- `vector-backends/` — Vector backend tests (`usearch-backend.test.ts`, `exact-scan-backend.test.ts`, `migration-fallback.test.ts`, `backend-factory.test.ts`) plus `vector-search-backend-integration.test.ts` at the top level - -## Local Contracts - -- Framework: Vitest ^3.2.4, V8 coverage provider. Config in `vitest.config.ts` -- `globals: false` — always import test functions explicitly: `import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"` -- File naming: `tests/.test.ts` mirrors `src/services/.ts`; vector backend tests live in `tests/vector-backends/` -- Test timeout 30s, hook timeout 30s -- HOME isolation is mandatory for any test that loads modules reading from `~/.opencode-mem0`. The global `setup-home.ts` covers the common case; tests that import modules before HOME is set must set HOME themselves before importing (see TESTING.md pattern) -- Mocking is via `vi.mock()`. Common mocks: `logger.js` (suppress output), `embedding.js` (avoid ML models), `sqlite/connection-manager.js` (in-memory stubs), `sqlite/shard-manager.js`, `sqlite/vector-search.js`, `config.js` (override defaults) -- No minimum coverage threshold is enforced; coverage is informational and feeds SonarCloud -- Coverage excludes: tests, types, web UI, examples, scripts, config files, `src/services/ai/session-types.ts` (see `vitest.config.ts`) - -## Work Guidance - -- New feature → add `tests/.test.ts`. Bug fix → add a regression test that fails before the fix and passes after -- Use descriptive test names: `it("should reject invalid API keys", ...)` over `it("test 7", ...)` -- Avoid loading real ML models in tests — mock `embedding.js` -- Run `bun run test` (Vitest directly) rather than `bun test` (Bun's runner has incomplete Vitest API compatibility) -- Coverage report: `bun run test:coverage` → `./coverage/` (text, LCOV, HTML) - -## Verification - -- `bun run test` — full suite (`tests/**/*.test.ts`) -- `bun run test:coverage` — suite + V8 coverage to `./coverage/` -- Single file: `vitest run tests/.test.ts`; filter by name: `vitest run -t "name"` -- CI (`.github/workflows/ci.yml`) and SonarCloud (`.github/workflows/sonarcloud.yml`) run the suite on `main` - -## Child DOX Index - -| Path | Scope | -| ------------------------ | ----------------------------------------------------------------------------- | -| `tests/vector-backends/` | Vector backend unit tests (no separate AGENTS.md — follow parent conventions) |