Dashboard › opencode › Distillation
159a96fc-d96c-471d-b081-9e31fd42a328["lore_tm_v1_Y7H1jmK8c4DunkBxDs8spMinGweKGgA8Uag_Lq1Yauo","lore_tm_v1_r4gFIJ5vTJlbAOZ6OONOea_MnI8wgj6Wu0PBDe32szs","lore_tm_v1_qe5p8Xel78GIY4cM2N6KZx0bbl_tee8D6RVOtTMMrgE","lore_tm_v1_g4RuTH-3lkgU6qyDATQ_YggY-CFzutXy32GDIIFbOnU"]
/home/byk/Code/opencode-lore/packages/opencode/package.json: package @loreai/opencode version 0.40.0, ESM ("type": "module"), license FSL-1.1-Apache-2.0, description “Three-tier memory architecture for OpenCode — distillation, not summarization,” and raw TypeScript entry/types/exports at ./src/index.ts.@loreai/opencode scripts: "typecheck": "tsc --noEmit" and "build": "echo '@loreai/opencode ships raw TS — no build step needed'".@loreai/opencode dependency configuration: peer dependency @opencode-ai/plugin >=1.1.0; workspace dependencies @loreai/core and @loreai/gateway; dev dependencies @opencode-ai/plugin ^1.1.39, @opencode-ai/sdk ^1.1.39, and @types/bun ^1.2.0.@loreai/opencode publishes src/, README.md, and LICENSE; repository is git+https://github.com/BYK/loreai.git under packages/opencode; npm access is public; author is BYK./home/byk/Code/opencode-lore/AGENTS.md requires every non-trivial PR to receive an adversarial correctness review before merge and points to quality/REVIEW.md for regression-test discipline, adversarial-order state setup, fan-out registry coverage, recurring bug-class batteries, and the two-reviewer rule.>= 22.5 for development/tests/production; TypeScript monorepo using pnpm workspaces; SQLite database in WAL mode with FTS5 full-text search at ~/.local/share/lore/lore.db.@loreai/core at packages/core/ is the shared memory engine; @loreai/gateway at packages/gateway/ is the transparent LLM proxy and lore CLI; @loreai/opencode at packages/opencode/ is the OpenCode plugin adapter; @loreai/pi at packages/pi/ is the Pi extension adapter. gateway, opencode, and pi consume core; gateway bundles core as one CJS file via esbuild, while opencode ships raw TypeScript.packages/gateway/src/cli/bin.ts → packages/gateway/src/cli/main.ts (_cli()), with commands: run (default, cli/run.ts, starts gateway and auto-detects/launches an AI agent), start (cli/start.ts, gateway only), data (cli/data.ts, list/show/clear/delete/merge/recover), recall (cli/recall-cmd.ts, terminal memory search), and upgrade (cli/upgrade.ts, self-update).cli/agents.ts scans $PATH for Claude Code, Codex, Pi, and OpenCode, then sets routing environment variables such as ANTHROPIC_BASE_URL.packages/core/src/temporal.ts: store() converts message parts to text and stores them in temporal_messages with FTS5 indexing; messages use a distilled=0/1 flag; chunk separator is \x1f (ASCII Unit Separator).packages/core/src/distillation.ts: run() executes resetOrphans() → fetch undistilled messages → detectSegments() split by time gaps/token limits with maximum 16K tokens per segment → distillSegment() using an LLM observer prompt → generation-0 storage. When generation-0 count exceeds 20, metaDistill() consolidates into generation 1+; generation-0 segments remain archived/searchable through recall but are excluded from the in-context prefix.packages/core/src/gradient.ts: transform() runs on every message transform and uses 4 layers—Layer 0 full passthrough, Layer 1 distilled prefix plus compressed raw context, Layer 2 aggressive tool-output stripping, and Layer 3 emergency compression—with calibration from real API token counts and cost-aware limits based on model pricing.packages/core/src/ltm.ts: categories decision, pattern, preference, architecture, and gotcha; fields id (UUIDv7), project_id, category, title, content (maximum 1200 characters), confidence (0.0-1.0), and cross_project.packages/core/src/curator.ts, periodically returning create/update/delete operations from conversation plus existing entries; 2. regex-based, non-LLM Pattern Extraction in packages/core/src/pattern-extract.ts after each distillation; 3. File Import in packages/core/src/agents-file.ts, parsing .lore.md markers of the form <!-- lore:UUID -->; 4. curator.ts consolidate(), merging/trimming via LLM when entry count exceeds maxEntries (25).packages/core/src/ltm.ts behavior: create()/update()/remove() provide CRUD with a dedup guard; forSession() returns relevance-ranked, budget-capped entries for system-prompt injection; search()/searchScored() use FTS5 BM25 with a LIKE fallback..lore.md behavior: entries are alphabetically sorted by title within category; exportLoreFile() in agents-file.ts builds from the DB and skips writes when the content hash is unchanged; importLoreFile() updates a known UUID whose content changed and creates an entry for an unknown UUID; shouldImportLoreFile() checks mtime first, then compares content hashes.exportToFile() writes the Lore pointer section between markers, while splitFile() preserves all content outside those markers, making manual content outside the managed section safe.pnpm install, pnpm test, pnpm run typecheck, pnpm run lint, pnpm run lint:fix, pnpm run format, pnpm run format:check, and pnpm run build; lint uses type-aware oxlint and formatting uses oxfmt.packages/core/test/setup.ts and never the production DB.packages/gateway/script/build.ts produces a CJS gateway bundle; script/bundle.ts creates a standalone binary; packages/core/script/build.ts produces Node.js-compatible CJS output.CHANGELOG.md; Craft handles both automatically./home/byk/Code/opencode-lore/packages/gateway/src/cli/start.ts found startGateway() at line 868, startGatewayLocked() at line 877, and shutdown-related logic beginning around lines 1122-1124.startGateway() in /home/byk/Code/opencode-lore/packages/gateway/src/cli/start.ts executes startGatewayLocked() under withLifecycleLock("gateway-start", ...).startGatewayLocked() merges realStartGatewayIO with ioOverrides, loads configuration via loadConfig(), and applies CLI overrides for port, hosts, debug, and allowRemoteManagement; an explicit opts.port also sets config.portExplicit = true.quiet: true because any stdout/stderr write can corrupt their full-screen TUI; notifications then use file-based, terminal-suppressed log.warn(), while normal lore start uses console.error("[lore] ...").opts.local sets config.hostedMode = !opts.local; absent opts.local and absent LORE_HOSTED_MODE defaults lore start to hosted mode; otherwise loadConfig()’s environment result is retained. lore run, lore import, OpenCode, and Pi pass local: true.local: true because hosted mode is process-wide and disables filesystem operations in @loreai/core; enabling it in-process breaks getGitRemote(), .lore.md import, config loading, and file watching.--local always disables remote mode: it sets config.remoteGateway = false and config.remoteGatewayAutoDetected = false.--local, LORE_REMOTE_GATEWAY, or LORE_HOSTED_MODE, lore start preserves bind-address auto-detection if already enabled; otherwise it defaults config.remoteGateway = true and marks config.remoteGatewayCommandDefault = true. assertGatewayAccessConfigured(config) runs only after CLI/environment/default precedence is fully applied.3207 → 5673 → 0, where 0 requests an OS-assigned random port.32-byte random controlToken encoded as base64url; processIdentity uses currentProcessIdentity() or falls back on Windows to unverified:${controlToken}, allowing discovery while destructive stop fails closed.GatewayHandle has owned: false, the persisted managementToken, and a no-op shutdown; the process record—not public health or the port file—is the source of identity./health never establishes gateway identity; only an authenticated owner process record does. Public health merely classifies an unauthenticated occupant as foreign.0; for nonzero ports it authenticates a matching process record or probes a deduplicated host list containing 127.0.0.1, configured hosts, and matching-record hosts. An explicit occupied port throws an error advising --port/LORE_LISTEN_PORT; a default occupied port logs the fallback and continues.startServer() must be awaited inside the try because it binds each host and surfaces EADDRINUSE from that await, enabling the catch path to authenticate/reuse an existing gateway rather than crash. server.ready is then awaited although already resolved, for clarity.GatewayProcessRecord has version: 2, pid, actual port, bound hosts, token, and processIdentity.pid, token, and processIdentity all match. If listener closure also fails, retain discovery evidence and throw an AggregateError containing both errors with message “Gateway publication failed and the live listener could not be closed; discovery evidence was retained.”shutdownPromise and runs under withLifecycleLock("gateway-shutdown", ...) with timeout Math.max(1, Math.floor(SHUTDOWN_DEADLINE_MS / 2)).boundServer.stop() first to stop accepting work; call io.resetPipelineState({ fast: true }); await listener closure; stop and settle temporalEmbeddingQueue with EMBED_DRAIN_DEADLINE_MS; settle document embeds with the same deadline; call embedding.resetProvider(); call shutdownVectorPoolAsync(VECTOR_POOL_SHUTDOWN_DEADLINE_MS); then closeDb().Database close warning: ... but does not wedge shutdown or preserve an otherwise stale process record because SQLite recovery handles a failed best-effort checkpoint.pid, token, and processIdentity.process.exitCode = 1; later remote shutdown uses the process-bound shutdown controller when present, otherwise calls shutdown() and reports failures while setting exit code 1.3207 and 5673 are unavailable, binding port 0 logs the actual OS-assigned port and returns an owned handle with owned: true, managementToken: controlToken, shutdown, and optional processShutdown.EADDRINUSE are retried; all other errors are rethrown.0 always succeeds or throws a non-EADDRINUSE error, making the terminal throw new Error("Failed to bind to any port.") unreachable.