Dashboard › opencode › Distillation
206b975c-6dd0-4176-9a33-f1e295e9a00d["lore_tm_v1_sGhaRX2fsOLTSrA332WUYNu-YwuCosV-hZehSuCv7Tc","lore_tm_v1_z75nFqqQphL2FQRE0hoQOieJRk9Ivs66ORllH3PLw4s","lore_tm_v1_XSTPCkjiTyzCejmz3oaWFKQ6EFbu3bTerm5Bbfi6GfQ","lore_tm_v1_5oqopt4UjJi6FRY9WHh0674wdBllh8Mf235ALT23NRc","lore_tm_v1_f4pUag7RJm3RSwh9Lrhu8yG2SlBghcmqd90CukyWW-k","lore_tm_v1_Vtte4yy9Em1CG_u2NAscaH6rm1qIKQgExqFB5Vgrlcg","lore_tm_v1_ZwW_RGOY1KgUnFkjTdjPp9dW2XjpWF4Yw4O3EoKAl8E","lore_tm_v1_BcIQFi0Tcc28ocKxuh8al8U1Q1uJsBmn-q3Opj2dazY","lore_tm_v1_lVEeucrfA2VMRto1z3XPoC3oqobXfS_xAgYWYJd1lpc"]
Date: Sep 9, 2026
/home/byk/Code/opencode-v2-pilot/packages/core/test/plugin/module.test.ts has 2 live loader/watcher tests: 1. loading a plugin that imports missing shared/new/nested/helper.ts initially fails, creation of that helper produces a change within "5 seconds", and reloading yields plugin { id: "appeared" }; 2. closing the loader Scope while native module evaluation is waiting interrupts pending watcher setup, completes its Effect.ensuring(...) cleanup, and allows the uncancellable import to finish without an unhandled rejection after a 50 ms wait./home/byk/Code/opencode-v2-pilot/packages/core/test/plugin-failure.test.ts verifies a failed plugin loses its command, shell.create.before hook, and RPC handler while a healthy plugin remains active; after commands.reload(), plugin states are exactly ["failed", "active"], invoking broken RPC returns { type: "rpc.unavailable" }, and cleanup completes within "1 second"."reload" and "teardown": queued cleanup from a failed old generation must not block activation of revision "2"; activation must succeed within "250 millis", the replacement state must be { status: "active" }, and command "changing" must have description "new".["1", "2"], plugin "replacement" stays failed, and its command is absent."pending" and "reported" plugin failures survive changes, reordering, and removal of other plugins without reloading the failed generation; expected initial loads are ["earlier@1", "broken@1", "later@1", "earlier@2", "later@1"], the failure retains the same err_... ref, "broken@1" loads exactly once, and changing it to revision "2" loads "broken@2" exactly once and restores active state.Plugin.Event.Updated observer dies with "observer failed": plugins.awaitActivation succeeds within "250 millis", both plugins become failed, cleanup records exactly ["first", "second"] after sorting, and the command list becomes empty./home/byk/Code/opencode-lore/packages/opencode/src/index.ts keeps helper functions in ./internal.ts because OpenCode’s legacy loader invokes every function export as a plugin and throws on non-function exports; the entry module must export only named LorePlugin and the same-reference default, guarded by the "plugin entry module export shape" test in test/index.test.ts.LORE_REMOTE_URL, then LORE_GATEWAY_URL, then the @loreai/gateway port file, then known ports 3207 and 5673; unreachable remote/explicit URLs fall through to local discovery, and startGateway({ quiet: true, local: true }) handles fallback 3207 → 5673 → random.processInitDone, processLoreActive, processLoreBase, and memoized loreInitPromise; per-project state is stored in projectState, keyed by ctx.project.id, with { projectPath, gitRemote, lastSeenAt }, while currentProject is only a fallback for requests bypassing chat.headers."git-remote magnet".SESSION_STATE_TTL_MS = 24 * 60 * 60 * 1000 (24 hours) applies to stale projectState and sessionParent entries; estimated storage is approximately 200 bytes per entry, so 100 projects use approximately 20 KB.resolveParentSession() caches both a parent session ID and successful null results because a session’s parentID is immutable; failures are not cached so transient failures retry on the next turn rather than permanently misclassifying a sub-agent.resolveParentSession() catches failures and returns null.chat.headers to “never blocks or throws on failure.”parentID through client.session.get({ path: { id: sessionID } }) and, when non-null, emits it as x-parent-session-id so the gateway can size LTM injection as described in issue #1300.NODE_ENV === "test" or any process.argv entry contains ".test."; LORE_OPENCODE_FORCE_ACTIVE=1 overrides inertness while preserving test logging/database behavior, paralleling LORE_PI_FORCE_ACTIVE.log.silenceStderr() suppresses terminal output while logs still go to the file and Sentry sink and remain visible through lore logs.surfaceGatewayUnavailable(ctx.client, msg) because silenced log.error is invisible in the TUI; stale-build-like errors additionally recommend pnpm --filter @loreai/gateway run bundle or run build for a development checkout.{ auto: false, prune: false } and defines 3 hidden workers under legacy cfg.agent: 1. "lore-distill" — mode: "subagent", description "Lore memory distillation worker"; 2. "lore-curator" — mode: "subagent", description "Lore knowledge curator worker"; 3. "lore-query-expand" — mode: "subagent", description "Lore query expansion worker". mode: "subagent" is required because OpenCode defaults agents to "all" and only honors hidden: true for subagent-mode agents.chat.headers hook emits gateway access headers plus x-lore-session-id, x-lore-agent, optional x-parent-session-id, x-lore-project, x-lore-git-remote, and runtime provider .id as x-lore-provider; local/self-hosted provider upstreams come from LORE_UPSTREAM_${providerID.toUpperCase().replace(/-/g, "_")} and populate x-lore-upstream-url only when it is not already present.LORE_UPSTREAM_EXTRA_HEADERS is parsed line-by-line on /\r?\n/, splitting each non-empty line at its first colon; only names accepted by shouldForwardUpstreamExtraHeader(name) are copied, preventing clobbering of gateway-managed headers.installFetchInterceptor(...) once per process when active; getHeaders() includes gatewayAccessHeadersForRemote(gatewayBase) and the paired currentProject.path/currentProject.gitRemote, then logs routing through ${gatewayBase} and dashboard: ${gatewayBase}/ui./home/byk/Code/opencode-v2-pilot/packages/core/src/plugin/hooks.ts defines hook domains aisdk, session, permission, shell, and tool; only tool.execute.before may fail with Tool.Error, while all other hook failure channels are never.PluginHooks.Interface exposes has(domain, name, providerID?), scoped register(domain, name, callback, options?), and trigger(domain, name, event); registrations append callbacks in order, return an idempotent { dispose }, and are automatically disposed through Scope.addFinalizer.event.model.providerID; callbacks with no options.providerID match all events, while callbacks with a provider restriction run only when it exactly equals the event provider ID. trigger() executes matching callbacks sequentially and returns the mutated event./home/byk/Code/opencode-v2-pilot/packages/core/test/session-owned.test.ts verifies prompt preparation remains interruptible: interrupting a "session.prompt" hook blocked on Effect.never admits no inbox input, preserves the staged revert and boundary context, creates no wakes, and does not acquire additional locations; after explicit revert commit, the staged revert and stored context are cleared.