@caupulican/pi-adaptative 0.81.4 → 0.81.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/dist/core/agent-session.d.ts +8 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +125 -66
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/background-lane-controller.d.ts.map +1 -1
- package/dist/core/background-lane-controller.js +3 -0
- package/dist/core/background-lane-controller.js.map +1 -1
- package/dist/core/billing-failover-controller.d.ts +2 -2
- package/dist/core/billing-failover-controller.d.ts.map +1 -1
- package/dist/core/billing-failover-controller.js +2 -8
- package/dist/core/billing-failover-controller.js.map +1 -1
- package/dist/core/compaction-support.d.ts +3 -0
- package/dist/core/compaction-support.d.ts.map +1 -1
- package/dist/core/compaction-support.js +18 -4
- package/dist/core/compaction-support.js.map +1 -1
- package/dist/core/context-pipeline.d.ts +1 -0
- package/dist/core/context-pipeline.d.ts.map +1 -1
- package/dist/core/context-pipeline.js +12 -0
- package/dist/core/context-pipeline.js.map +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +33 -9
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/models/local-registration.d.ts +1 -0
- package/dist/core/models/local-registration.d.ts.map +1 -1
- package/dist/core/models/local-registration.js +3 -2
- package/dist/core/models/local-registration.js.map +1 -1
- package/dist/core/research/model-fitness.d.ts +16 -0
- package/dist/core/research/model-fitness.d.ts.map +1 -1
- package/dist/core/research/model-fitness.js +74 -1
- package/dist/core/research/model-fitness.js.map +1 -1
- package/dist/core/session-tree-navigator.d.ts.map +1 -1
- package/dist/core/session-tree-navigator.js +1 -0
- package/dist/core/session-tree-navigator.js.map +1 -1
- package/dist/core/trust-manager.d.ts.map +1 -1
- package/dist/core/trust-manager.js +6 -3
- package/dist/core/trust-manager.js.map +1 -1
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +7 -1
- package/dist/migrations.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +2 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +102 -91
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/session-flow-commands.d.ts.map +1 -1
- package/dist/modes/interactive/session-flow-commands.js +10 -7
- package/dist/modes/interactive/session-flow-commands.js.map +1 -1
- package/docs/bug-ledger.md +24 -21
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +12 -12
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context-pipeline.js","sourceRoot":"","sources":["../../src/core/context-pipeline.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Context pipeline: the session's per-turn context-shaping subsystem — the observe-only context\n * audit, the shadow prompt-policy plan and its correlation with legacy context-gc, the enforcement\n * pilot, the relevance-curation queue + the fitness-gated curation model resolver / brain-curation\n * drain + compaction pre-digest, the legacy context-gc pass and its packed-artifact reference\n * release, the tool-output artifact store, and the current-context token estimate.\n *\n * Extracted verbatim from agent-session.ts (god-file decomposition). Owns the latest\n * audit/policy/correlation/enforcement/gc reports, the {@link BrainCurator} sidecar and its last\n * skip reasons, and the lazily-built tool-artifact store. Everything else it needs — the turn\n * index, the session/settings managers, the model registry, agent/workspace dirs, the active tool\n * names, the disposed flag, the isolated-completion primitive, spawned-usage accounting, and the\n * live {@link MemoryManager} — is reached through narrow deps accessors rather than the whole\n * AgentSession.\n *\n * Context-transform boundary (deliberate): the per-turn stages ({@link estimateCurrentContextTokens},\n * {@link runContextAudit}, {@link runPromptPolicyPlanning}, {@link applyContextGc},\n * {@link correlatePromptPolicyWithContextGc}, {@link runPromptEnforcement},\n * {@link enqueueRelevanceCuration}, {@link maybeDrainBrainCuration}) are invoked from the session's\n * context transform as one-line delegations, so the transform stays the single owner of the pass\n * ordering. This controller reaches {@link MemoryController} functionality only through\n * {@link ContextPipelineDeps.getMemoryManager} (never imports it), and MemoryController never imports\n * the pipeline — keeping the transform the one place the two subsystems meet.\n */\n\nimport { join } from \"node:path\";\nimport type { AgentMessage } from \"@caupulican/pi-agent-core\";\nimport {\n\testimateContextTokens,\n\tgetLatestCompactionEntry,\n\ttype SessionManager,\n\tTokenBudget,\n} from \"@caupulican/pi-agent-core/node\";\nimport type { Api, AssistantMessage, Model, Usage } from \"@caupulican/pi-ai\";\nimport type { IsolatedCompletionOptions, IsolatedCompletionResult } from \"./agent-session.ts\";\nimport { BrainCurator, type CurationTelemetrySnapshot, preDigestConversationText } from \"./context/brain-curator.ts\";\nimport { type ArtifactStore, createFileArtifactStore } from \"./context/context-artifacts.ts\";\nimport { type ContextAuditReport, runContextAudit } from \"./context/context-audit.ts\";\nimport { enforcePromptPolicy, type PromptEnforcementReport } from \"./context/context-prompt-enforcement.ts\";\nimport {\n\tcorrelateWithContextGc,\n\ttype PromptPolicyGcCorrelationReport,\n\ttype PromptPolicyShadowReport,\n\tplanPromptPolicy,\n} from \"./context/context-prompt-policy.ts\";\nimport { applyContextGc, type ContextGcReport } from \"./context-gc.ts\";\nimport type { MemoryManager } from \"./memory/memory-manager.ts\";\nimport type { ModelRegistry } from \"./model-registry.ts\";\nimport { resolveCliModel } from \"./model-resolver.ts\";\nimport { evaluateSurfaceFitness } from \"./model-router/fitness-gate.ts\";\nimport { FitnessStore } from \"./models/fitness-store.ts\";\nimport type { SettingsManager } from \"./settings-manager.ts\";\n\n/** Latest user prompt text in the provider-visible array (curation goal line; bounded by caller). */\nexport function latestUserPromptText(messages: AgentMessage[]): string {\n\tfor (let index = messages.length - 1; index >= 0; index--) {\n\t\tconst message = messages[index];\n\t\tif (!message || message.role !== \"user\") continue;\n\t\tif (typeof message.content === \"string\") return message.content;\n\t\tconst text = message.content\n\t\t\t.filter((part): part is { type: \"text\"; text: string } => (part as { type?: string }).type === \"text\")\n\t\t\t.map((part) => part.text)\n\t\t\t.join(\"\\n\");\n\t\tif (text.length > 0) return text;\n\t}\n\treturn \"\";\n}\n\n/** Read a packed grep/find tool result's `details.artifactId`, if present, without `any`. */\nfunction extractArtifactId(message: AgentMessage | undefined): string | undefined {\n\tif (!message || message.role !== \"toolResult\") return undefined;\n\tconst details = (message as { details?: unknown }).details;\n\tif (typeof details !== \"object\" || details === null) return undefined;\n\tconst artifactId = (details as { artifactId?: unknown }).artifactId;\n\treturn typeof artifactId === \"string\" ? artifactId : undefined;\n}\n\nexport interface ContextPipelineDeps {\n\t/** Current turn index, stamped into audit/policy/enforcement reports. */\n\tgetTurnIndex(): number;\n\t/** Session log: audit lookup, gc/artifact storage dirs, curation entries, token-estimate compaction anchor. */\n\tgetSessionManager(): SessionManager;\n\t/** Context-gc / prompt-enforcement / curation settings (all opt-in gates). */\n\tgetSettingsManager(): SettingsManager;\n\t/** Resolves a configured curation model pattern against configured auth. */\n\tgetModelRegistry(): ModelRegistry;\n\t/** Root dir the host-keyed {@link FitnessStore} and per-session gc/artifact storage live under. */\n\tgetAgentDir(): string;\n\t/** Workspace root, passed to the context-gc pass. */\n\tgetCwd(): string;\n\t/** Currently-active tool names — enforcement checks whether artifact_retrieve is a live affordance. */\n\tgetActiveToolNames(): string[];\n\t/** A disposed session must never persist a curation/pre-digest entry. */\n\tisDisposed(): boolean;\n\t/** The live memory manager — the active providers' page markers feed the semantic-gc scan. */\n\tgetMemoryManager(): MemoryManager;\n\t/** Roll a curation drain's spawned usage into session accounting (idempotent per reportId). */\n\taddSpawnedUsage(\n\t\tusage: Usage,\n\t\topts?: { label?: string; sourceSessionId?: string; reportId?: string },\n\t): string | undefined;\n\t/** One-shot LLM call fully isolated from the main session — the curation/pre-digest execution primitive. */\n\trunIsolatedCompletion(opts: IsolatedCompletionOptions): Promise<IsolatedCompletionResult>;\n}\n\nexport class ContextPipeline {\n\tprivate _latestContextGcReport: ContextGcReport | undefined = undefined;\n\t/** Brain-curation sidecar (design: brain-context-curation-design.md). Inert unless the\n\t * contextPolicy.curation setting is enabled AND the model passes the digest fitness gate. */\n\tprivate readonly _brainCurator = new BrainCurator();\n\tprivate _lastCurationSkipReason: string | undefined = undefined;\n\tprivate _lastPreDigestSkipReason: string | undefined = undefined;\n\tprivate _toolArtifactStore: ArtifactStore | undefined = undefined;\n\tprivate _latestContextAuditReport: ContextAuditReport | undefined = undefined;\n\tprivate _latestPromptPolicyReport: PromptPolicyShadowReport | undefined = undefined;\n\tprivate _latestPromptPolicyGcCorrelation: PromptPolicyGcCorrelationReport | undefined = undefined;\n\tprivate _latestPromptEnforcementReport: PromptEnforcementReport | undefined = undefined;\n\tprivate readonly _tokenBudget = new TokenBudget();\n\n\tprivate readonly deps: ContextPipelineDeps;\n\n\tconstructor(deps: ContextPipelineDeps) {\n\t\tthis.deps = deps;\n\t}\n\n\tprivate _contextGcStorageDir(): string {\n\t\treturn join(this.deps.getAgentDir(), \"context-gc\", this.deps.getSessionManager().getSessionId());\n\t}\n\n\tprivate _toolArtifactsDir(): string {\n\t\treturn join(this.deps.getAgentDir(), \"context-artifacts\", this.deps.getSessionManager().getSessionId());\n\t}\n\n\t/**\n\t * Session-scoped, filesystem-backed artifact store for first-capture-then-bound tool\n\t * output (grep/find only, for now -- see tool-output-artifacts.md). Lazily created and\n\t * cached so every tool construction in this session shares one store instance.\n\t *\n\t * `packToolOutput()` registers a reference (the packing tool call's id) at pack time\n\t * and fails closed, so packed artifacts are never prematurely collected.\n\t * `_releaseGcPackedArtifactReferences()` (called from `applyContextGc()`) releases\n\t * that reference once context-gc packs the result out of live context, and\n\t * opportunistically reclaims now-unreferenced artifacts via `cleanup()`.\n\t * Remaining carry-forward gap: cleanup() now also runs at dispose(), but only reclaims\n\t * already-released (zero-reference) artifacts. A session that ends before context-gc\n\t * ever evicts a result never releases that reference, so its artifact stays on disk by\n\t * design (resolvable on resume). Reclaiming those requires an explicit cross-session\n\t * expiry/liveness policy, not just a sweep.\n\t */\n\tgetToolArtifactStore(): ArtifactStore {\n\t\tthis._toolArtifactStore ??= createFileArtifactStore({ baseDir: this._toolArtifactsDir() });\n\t\treturn this._toolArtifactStore;\n\t}\n\n\t/**\n\t * Best-effort final sweep of any already-released (zero-reference) tool-output artifact at\n\t * session dispose. Reads the field (not the getter) so a session that never packed anything\n\t * doesn't force-create a store/dir just to sweep it.\n\t */\n\tcleanupToolArtifactStoreOnDispose(): void {\n\t\tthis._toolArtifactStore?.cleanup();\n\t}\n\n\t/**\n\t * One pass over the current branch, mapping each toolResult's toolCallId to its\n\t * persisted session-entry id. Rebuilt every audit pass (O(branch) per turn), so this is\n\t * O(n^2) over a long session. Fine at current scale; after the artifact-read fix this is\n\t * the next per-turn audit cost to optimize if it ever matters (e.g. cache/incrementally\n\t * update instead of a full rebuild).\n\t */\n\tprivate _buildSessionEntryIdLookup(): (toolCallId: string) => string | undefined {\n\t\tconst map = new Map<string, string>();\n\t\tfor (const entry of this.deps.getSessionManager().getBranch()) {\n\t\t\tif (entry.type === \"message\" && entry.message.role === \"toolResult\") {\n\t\t\t\tmap.set(entry.message.toolCallId, entry.id);\n\t\t\t}\n\t\t}\n\t\treturn (toolCallId: string) => map.get(toolCallId);\n\t}\n\n\t/**\n\t * Phase 1 observe-only audit pass (see context/context-audit.ts): converts live\n\t * toolResult messages into ContextItems and runs the existing retention/hard-constraint\n\t * evaluators over them, storing the latest deterministic report for tests/debugging.\n\t * Read-only with respect to messages, the transcript, and artifact references -- uses\n\t * `_toolArtifactStore` (the field), not `getToolArtifactStore()` (the getter), so a\n\t * session that never packed anything doesn't force-create a store/dir just to audit.\n\t * Never throws into a live turn: any failure degrades to an empty report.\n\t */\n\trunContextAudit(messages: AgentMessage[]): ContextAuditReport {\n\t\ttry {\n\t\t\tconst report = runContextAudit(messages, {\n\t\t\t\tturnIndex: this.deps.getTurnIndex(),\n\t\t\t\tartifactStore: this._toolArtifactStore,\n\t\t\t\tsessionEntryIdForToolCallId: this._buildSessionEntryIdLookup(),\n\t\t\t});\n\t\t\tthis._latestContextAuditReport = report;\n\t\t\treturn report;\n\t\t} catch {\n\t\t\tconst report: ContextAuditReport = { turnIndex: this.deps.getTurnIndex(), items: [] };\n\t\t\tthis._latestContextAuditReport = report;\n\t\t\treturn report;\n\t\t}\n\t}\n\n\t/**\n\t * Read-only inspection of the context audit. With `messages`, recomputes fresh against\n\t * the given array (still no mutation of messages/transcript/artifact refs); without,\n\t * returns the last report computed during a real transform pass.\n\t */\n\tgetContextAuditReport(messages?: AgentMessage[]): ContextAuditReport {\n\t\tif (messages) return this.runContextAudit(messages);\n\t\treturn this._latestContextAuditReport ?? { turnIndex: this.deps.getTurnIndex(), items: [] };\n\t}\n\n\t/**\n\t * Observe-first shadow/planning pass (see context/context-prompt-policy.ts): re-shapes\n\t * the audit report into a per-item policy plan whose `appliedAction` is always\n\t * \"keep_raw\" -- this never enforces anything, it only records what the policy engine\n\t * would say. Never throws into a live turn: any failure degrades to an empty report.\n\t */\n\trunPromptPolicyPlanning(auditReport: ContextAuditReport): PromptPolicyShadowReport {\n\t\ttry {\n\t\t\tconst report = planPromptPolicy(auditReport);\n\t\t\tthis._latestPromptPolicyReport = report;\n\t\t\treturn report;\n\t\t} catch {\n\t\t\tconst report: PromptPolicyShadowReport = { turnIndex: this.deps.getTurnIndex(), items: [] };\n\t\t\tthis._latestPromptPolicyReport = report;\n\t\t\treturn report;\n\t\t}\n\t}\n\n\t/**\n\t * Read-only inspection of the shadow policy plan. With `messages`, recomputes fresh\n\t * (audit + plan) against the given array; without, returns the last plan computed\n\t * during a real transform pass. Never mutates messages/transcript/artifact refs.\n\t */\n\tgetPromptPolicyReport(messages?: AgentMessage[]): PromptPolicyShadowReport {\n\t\tif (messages) return this.runPromptPolicyPlanning(this.runContextAudit(messages));\n\t\treturn this._latestPromptPolicyReport ?? { turnIndex: this.deps.getTurnIndex(), items: [] };\n\t}\n\n\t/**\n\t * Report-only correlation between the shadow plan just computed this turn and what the\n\t * legacy context-gc pass actually packed. Runs after `applyContextGc()` has already\n\t * produced its report; never influences context-gc itself. Never throws into a live\n\t * turn: any failure degrades to an empty correlation.\n\t */\n\tcorrelatePromptPolicyWithContextGc(gcReport: ContextGcReport): void {\n\t\tconst shadowReport = this._latestPromptPolicyReport ?? { turnIndex: this.deps.getTurnIndex(), items: [] };\n\t\ttry {\n\t\t\tthis._latestPromptPolicyGcCorrelation = correlateWithContextGc(shadowReport, gcReport);\n\t\t} catch {\n\t\t\tthis._latestPromptPolicyGcCorrelation = { turnIndex: this.deps.getTurnIndex(), entries: [] };\n\t\t}\n\t}\n\n\t/** Read-only inspection of the latest shadow-plan/legacy-gc correlation, for tests/debugging. */\n\tgetPromptPolicyGcCorrelation(): PromptPolicyGcCorrelationReport {\n\t\treturn this._latestPromptPolicyGcCorrelation ?? { turnIndex: this.deps.getTurnIndex(), entries: [] };\n\t}\n\n\t/**\n\t * First enforcement pilot (see context/context-prompt-enforcement.ts): opt-in,\n\t * default-disabled stub-in-place of stale artifact-backed tool_output results in the\n\t * provider-visible message array only. Runs on `messages` AFTER context-gc has already\n\t * produced its own result, so legacy context-gc's own packing/reporting is completely\n\t * unaffected by this pass -- it only ever acts on messages gc left untouched this turn.\n\t * Never throws into a live turn: any failure degrades to returning `messages` unchanged.\n\t */\n\trunPromptEnforcement(\n\t\tmessages: AgentMessage[],\n\t\tshadowReport: PromptPolicyShadowReport,\n\t): { messages: AgentMessage[]; report: PromptEnforcementReport } {\n\t\ttry {\n\t\t\tconst persistedSettings = this.deps.getSettingsManager().getContextPromptEnforcementSettings();\n\t\t\tconst curationEnabled = this.deps.getSettingsManager().getContextCurationSettings().enabled;\n\t\t\tconst settings = {\n\t\t\t\t...persistedSettings,\n\t\t\t\t// Runtime fact, never assumed: artifact_retrieve is a companion affordance\n\t\t\t\t// (auto-activated alongside grep/find), not a default/global tool, so active\n\t\t\t\t// tools can differ turn to turn -- see context-prompt-enforcement.ts's doc\n\t\t\t\t// comment on why this is checked separately from hasAvailableRetrievalPath.\n\t\t\t\tretrievalToolAvailable: this.deps.getActiveToolNames().includes(\"artifact_retrieve\"),\n\t\t\t\tbrainRelevance: curationEnabled ? (itemId: string) => this._brainCurator.getRelevance(itemId) : undefined,\n\t\t\t};\n\t\t\tconst result = enforcePromptPolicy(messages, shadowReport, settings);\n\t\t\tthis._latestPromptEnforcementReport = result.report;\n\t\t\treturn result;\n\t\t} catch {\n\t\t\tconst report: PromptEnforcementReport = { turnIndex: this.deps.getTurnIndex(), items: [] };\n\t\t\tthis._latestPromptEnforcementReport = report;\n\t\t\treturn { messages, report };\n\t\t}\n\t}\n\n\t/**\n\t * Enqueue relevance-scoring jobs for stale, artifact-backed tool outputs the enforcement\n\t * pilot could act on. Pure queueing — the verdicts only ever take effect through the\n\t * asymmetric advisory lever inside enforcePromptPolicy. Never throws into a turn.\n\t */\n\tenqueueRelevanceCuration(messages: AgentMessage[], shadowReport: PromptPolicyShadowReport): void {\n\t\ttry {\n\t\t\tconst settings = this.deps.getSettingsManager().getContextCurationSettings();\n\t\t\tif (!settings.enabled) return;\n\t\t\tconst goal = latestUserPromptText(messages).slice(0, 400);\n\t\t\tfor (const item of shadowReport.items) {\n\t\t\t\tif (!item.hasAvailableRetrievalPath) continue;\n\t\t\t\tconst message = messages[item.messageIndex];\n\t\t\t\tif (!message || message.role !== \"toolResult\" || message.toolCallId !== item.toolCallId) continue;\n\t\t\t\tif (message.isError) continue;\n\t\t\t\tconst details = message.details as\n\t\t\t\t\t| { contextGc?: { packed?: unknown }; promptPolicy?: { enforced?: unknown } }\n\t\t\t\t\t| undefined;\n\t\t\t\tif (details?.contextGc?.packed === true || details?.promptPolicy?.enforced === true) continue;\n\t\t\t\tconst text = message.content\n\t\t\t\t\t.filter((part): part is { type: \"text\"; text: string } => part.type === \"text\")\n\t\t\t\t\t.map((part) => part.text)\n\t\t\t\t\t.join(\"\\n\");\n\t\t\t\tif (text.length === 0) continue;\n\t\t\t\tthis._brainCurator.enqueue({ kind: \"relevance\", key: item.itemId, content: text.slice(0, 4000), goal });\n\t\t\t}\n\t\t} catch {\n\t\t\t// curation is a sidecar; it must never disrupt a turn\n\t\t}\n\t}\n\n\t/**\n\t * Drain gate: settings on, model configured+authed, and the model has PASSED the digest\n\t * fitness probe on THIS host (design: unfit or unprobed models are refused with a visible\n\t * reason, never silently degraded). Fire-and-forget; never throws into a turn.\n\t */\n\t/**\n\t * Resolve the curation model IFF every gate passes: setting enabled, model configured,\n\t * resolvable+authed, and digest-fitness-proven on THIS host (canonical \"provider/id\" ref —\n\t * runModelFitness stores reports under it, while settings.model may be a bare id or pattern).\n\t * Sets _lastCurationSkipReason on refusal; never throws.\n\t */\n\tresolveCurationModelIfFit(): Model<Api> | undefined {\n\t\tconst settings = this.deps.getSettingsManager().getContextCurationSettings();\n\t\tif (!settings.enabled) {\n\t\t\t// Never surface a stale refusal reason for a feature the user has since disabled.\n\t\t\tthis._lastCurationSkipReason = undefined;\n\t\t\treturn undefined;\n\t\t}\n\t\tif (!settings.model) {\n\t\t\tthis._lastCurationSkipReason = \"curation_model_unset\";\n\t\t\treturn undefined;\n\t\t}\n\t\tconst resolved = resolveCliModel({ cliModel: settings.model, modelRegistry: this.deps.getModelRegistry() });\n\t\tif (!resolved.model || !this.deps.getModelRegistry().hasConfiguredAuth(resolved.model)) {\n\t\t\tthis._lastCurationSkipReason = \"curation_model_unresolved\";\n\t\t\treturn undefined;\n\t\t}\n\t\tconst canonicalRef = `${resolved.model.provider}/${resolved.model.id}`;\n\t\tconst fitness = FitnessStore.forAgentDir(this.deps.getAgentDir())\n\t\t\t.getForHost()\n\t\t\t.find((entry) => entry.model === canonicalRef);\n\t\tconst verdict = evaluateSurfaceFitness(\"curation\", fitness?.report);\n\t\tif (!verdict.fit) {\n\t\t\tthis._lastCurationSkipReason =\n\t\t\t\tverdict.reason === \"unprobed\" ? \"curation_model_unprobed\" : \"curation_model_digest_unfit\";\n\t\t\treturn undefined;\n\t\t}\n\t\tthis._lastCurationSkipReason = undefined;\n\t\treturn resolved.model;\n\t}\n\n\tmaybeDrainBrainCuration(): void {\n\t\ttry {\n\t\t\tif (!this._brainCurator.hasWork() || this._brainCurator.isDraining) return;\n\t\t\tconst model = this.resolveCurationModelIfFit();\n\t\t\tif (!model) return;\n\t\t\tconst settings = this.deps.getSettingsManager().getContextCurationSettings();\n\t\t\tvoid this._drainBrainCuration(model, settings.maxJobsPerTurn);\n\t\t} catch {\n\t\t\t// curation is a sidecar; it must never disrupt a turn\n\t\t}\n\t}\n\n\t/**\n\t * Compaction pre-digest gate (design surface 3): everything the drain gate requires PLUS a\n\t * RUNTIME reliability proof — the curator must have run >=5 jobs on this session with a parse\n\t * failure rate <=5% before it is trusted to pre-digest compaction input. Returns undefined\n\t * (verbatim compaction, byte-for-byte today's behavior) whenever any gate refuses.\n\t */\n\tbuildCompactionPreDigest(): ((text: string, signal?: AbortSignal) => Promise<string>) | undefined {\n\t\ttry {\n\t\t\tconst model = this.resolveCurationModelIfFit();\n\t\t\tif (!model) return undefined;\n\t\t\tconst telemetry = this._brainCurator.telemetry();\n\t\t\tif (telemetry.jobsRun < 5 || telemetry.parseFailures / telemetry.jobsRun > 0.05) {\n\t\t\t\tthis._lastPreDigestSkipReason = \"curation_predigest_reliability_unproven\";\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tthis._lastPreDigestSkipReason = undefined;\n\t\t\treturn async (text, signal) => {\n\t\t\t\tconst result = await preDigestConversationText({\n\t\t\t\t\ttext,\n\t\t\t\t\tsignal,\n\t\t\t\t\tcomplete: async ({ systemPrompt, userPrompt, signal: chunkSignal }) => {\n\t\t\t\t\t\tconst completion = await this.deps.runIsolatedCompletion({\n\t\t\t\t\t\t\tsystemPrompt,\n\t\t\t\t\t\t\tmessages: [{ role: \"user\", content: [{ type: \"text\", text: userPrompt }], timestamp: Date.now() }],\n\t\t\t\t\t\t\tmodel,\n\t\t\t\t\t\t\tthinkingLevel: \"off\",\n\t\t\t\t\t\t\tmaxTokens: 512,\n\t\t\t\t\t\t\tsignal: chunkSignal,\n\t\t\t\t\t\t\tcacheRetention: \"short\",\n\t\t\t\t\t\t});\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\ttext: completion.text,\n\t\t\t\t\t\t\tcostUsd: completion.usage.cost.total,\n\t\t\t\t\t\t\tstopReason: String(completion.stopReason),\n\t\t\t\t\t\t};\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\tif (!this.deps.isDisposed() && result.totalChunks > 0) {\n\t\t\t\t\tthis.deps.getSessionManager().appendCustomEntry(\"brain-curation-predigest\", {\n\t\t\t\t\t\tversion: 1,\n\t\t\t\t\t\ttotalChunks: result.totalChunks,\n\t\t\t\t\t\tdigested: result.digested,\n\t\t\t\t\t\tfailed: result.failed,\n\t\t\t\t\t\tcharsBefore: text.length,\n\t\t\t\t\t\tcharsAfter: result.text.length,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn result.text;\n\t\t\t};\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\tprivate async _drainBrainCuration(model: Model<Api>, maxJobs: number): Promise<void> {\n\t\ttry {\n\t\t\t// ACCUMULATE across all drained jobs (the drain runs the completer once PER job) —\n\t\t\t// keeping only the last job's usage would under-report every multi-job drain.\n\t\t\tlet spentUsage: AssistantMessage[\"usage\"] | undefined;\n\t\t\tconst results = await this._brainCurator.drain({\n\t\t\t\tmaxJobs,\n\t\t\t\tcomplete: async ({ systemPrompt, userPrompt, signal }) => {\n\t\t\t\t\tconst completion = await this.deps.runIsolatedCompletion({\n\t\t\t\t\t\tsystemPrompt,\n\t\t\t\t\t\tmessages: [{ role: \"user\", content: [{ type: \"text\", text: userPrompt }], timestamp: Date.now() }],\n\t\t\t\t\t\tmodel,\n\t\t\t\t\t\tthinkingLevel: \"off\",\n\t\t\t\t\t\tmaxTokens: 256,\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t\t// Both curation system prompts are static — the provider can cache the prefix.\n\t\t\t\t\t\tcacheRetention: \"short\",\n\t\t\t\t\t});\n\t\t\t\t\tconst usage = completion.usage;\n\t\t\t\t\tif (!spentUsage) {\n\t\t\t\t\t\tspentUsage = structuredClone(usage);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tspentUsage.input += usage.input;\n\t\t\t\t\t\tspentUsage.output += usage.output;\n\t\t\t\t\t\tspentUsage.cacheRead += usage.cacheRead;\n\t\t\t\t\t\tspentUsage.cacheWrite += usage.cacheWrite;\n\t\t\t\t\t\tspentUsage.totalTokens += usage.totalTokens;\n\t\t\t\t\t\tspentUsage.cost.input += usage.cost.input;\n\t\t\t\t\t\tspentUsage.cost.output += usage.cost.output;\n\t\t\t\t\t\tspentUsage.cost.cacheRead += usage.cost.cacheRead;\n\t\t\t\t\t\tspentUsage.cost.cacheWrite += usage.cost.cacheWrite;\n\t\t\t\t\t\tspentUsage.cost.total += usage.cost.total;\n\t\t\t\t\t}\n\t\t\t\t\treturn {\n\t\t\t\t\t\ttext: completion.text,\n\t\t\t\t\t\tcostUsd: completion.usage.cost.total,\n\t\t\t\t\t\tstopReason: String(completion.stopReason),\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t});\n\t\t\t// Honest accounting even for free local models: token visibility is the contract.\n\t\t\tif (spentUsage && (spentUsage.cost.total > 0 || spentUsage.totalTokens > 0)) {\n\t\t\t\tthis.deps.addSpawnedUsage(spentUsage, { label: \"context-curator\" });\n\t\t\t}\n\t\t\tif (this.deps.isDisposed() || results.length === 0) return;\n\t\t\tthis.deps.getSessionManager().appendCustomEntry(\"brain-curation\", {\n\t\t\t\tversion: 1,\n\t\t\t\tresults: results.map((result) => ({\n\t\t\t\t\tkey: result.key,\n\t\t\t\t\tkind: result.kind,\n\t\t\t\t\tok: result.ok,\n\t\t\t\t\tms: result.ms,\n\t\t\t\t\t...(result.digest !== undefined ? { digest: result.digest } : {}),\n\t\t\t\t\t...(result.relevant !== undefined ? { relevant: result.relevant, confidence: result.confidence } : {}),\n\t\t\t\t})),\n\t\t\t\ttelemetry: this._brainCurator.telemetry(),\n\t\t\t});\n\t\t} catch {\n\t\t\t// curation is a sidecar; it must never disrupt a turn\n\t\t}\n\t}\n\n\t/** Curation status for diagnostics/dashboard: settings, live telemetry, last refusal reason. */\n\tgetContextCurationStatus(): {\n\t\tenabled: boolean;\n\t\tmodel?: string;\n\t\ttelemetry: CurationTelemetrySnapshot;\n\t\tlastSkipReason?: string;\n\t\tlastPreDigestSkipReason?: string;\n\t} {\n\t\tconst settings = this.deps.getSettingsManager().getContextCurationSettings();\n\t\treturn {\n\t\t\tenabled: settings.enabled,\n\t\t\tmodel: settings.model,\n\t\t\ttelemetry: this._brainCurator.telemetry(),\n\t\t\tlastSkipReason: this._lastCurationSkipReason,\n\t\t\tlastPreDigestSkipReason: this._lastPreDigestSkipReason,\n\t\t};\n\t}\n\n\t/** Read-only inspection of the latest prompt-enforcement report, for tests/debugging. */\n\tgetPromptEnforcementReport(): PromptEnforcementReport {\n\t\treturn this._latestPromptEnforcementReport ?? { turnIndex: this.deps.getTurnIndex(), items: [] };\n\t}\n\n\tapplyContextGc(\n\t\tmessages: AgentMessage[],\n\t\twritePayloads: boolean,\n\t): { messages: AgentMessage[]; report: ContextGcReport } {\n\t\ttry {\n\t\t\tconst settings = this.deps.getSettingsManager().getContextGcSettings();\n\t\t\t// Merge the ACTIVE memory providers' own page markers (e.g. transcript-recall's\n\t\t\t// \"<memory_context\") into the semantic-memory marker list. The settings default is\n\t\t\t// provider-agnostic and non-empty, so without this merge the recall pages the bundled\n\t\t\t// default provider actually emits are never recognized as semantic-memory pages and\n\t\t\t// accumulate raw for the life of the session — the exact growth Bug #7 GC exists to stop.\n\t\t\tconst providerMarkers = this.deps.getMemoryManager().getContextMarkers();\n\t\t\tconst curationSettings = this.deps.getSettingsManager().getContextCurationSettings();\n\t\t\tconst result = applyContextGc(messages, {\n\t\t\t\t...settings,\n\t\t\t\tsemanticMemory: {\n\t\t\t\t\t...settings.semanticMemory,\n\t\t\t\t\tmarkers: [...new Set([...settings.semanticMemory.markers, ...providerMarkers])],\n\t\t\t\t},\n\t\t\t\tcwd: this.deps.getCwd(),\n\t\t\t\tstorageDir: this._contextGcStorageDir(),\n\t\t\t\twritePayloads,\n\t\t\t\tcuration: curationSettings.enabled\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tresolveDigest: (digestKey) => {\n\t\t\t\t\t\t\t\tconst digest = this._brainCurator.getDigest(digestKey);\n\t\t\t\t\t\t\t\t// Count serves on the REAL per-turn pass only, never the report path.\n\t\t\t\t\t\t\t\tif (digest !== undefined && writePayloads) this._brainCurator.noteDigestServed();\n\t\t\t\t\t\t\t\treturn digest;\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t// Only the real per-turn pass enqueues work; the read-only report path\n\t\t\t\t\t\t\t// (writePayloads=false) stays side-effect free.\n\t\t\t\t\t\t\tonPacked: writePayloads\n\t\t\t\t\t\t\t\t? (record, originalText) => {\n\t\t\t\t\t\t\t\t\t\tthis._brainCurator.enqueue({\n\t\t\t\t\t\t\t\t\t\t\tkind: \"stub_digest\",\n\t\t\t\t\t\t\t\t\t\t\tkey: record.key ?? record.toolCallId,\n\t\t\t\t\t\t\t\t\t\t\tcontent: originalText,\n\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\t\t}\n\t\t\t\t\t: undefined,\n\t\t\t});\n\t\t\tthis._latestContextGcReport = result.report;\n\t\t\t// Only release/reclaim on the real per-turn pass (writePayloads=true), never on\n\t\t\t// the read-only status-report path (getContextGcReport with writePayloads=false),\n\t\t\t// so merely inspecting the report can't have side effects.\n\t\t\tif (writePayloads && result.report.packedCount > 0) {\n\t\t\t\tthis._releaseGcPackedArtifactReferences(messages, result.report);\n\t\t\t}\n\t\t\treturn result;\n\t\t} catch {\n\t\t\tconst report: ContextGcReport = {\n\t\t\t\tenabled: false,\n\t\t\t\tpackedCount: 0,\n\t\t\t\toriginalTokens: 0,\n\t\t\t\tpackedTokens: 0,\n\t\t\t\tsavedTokens: 0,\n\t\t\t\trecords: [],\n\t\t\t};\n\t\t\tthis._latestContextGcReport = report;\n\t\t\treturn { messages, report };\n\t\t}\n\t}\n\n\t/**\n\t * Reference-release + cleanup lifecycle: once context-gc has packed a grep/find tool\n\t * result out of the live prompt (the message is no longer current/active working\n\t * context -- see contracts-and-retention.md's \"ephemeral\"/\"expired\" retention\n\t * classes), release the pack-time reference `packToolOutput()` registered for it, and\n\t * opportunistically reclaim now-unreferenced artifacts. This is the other half of the\n\t * D2b-1 gate: artifacts were being registered but never released, so they accumulated\n\t * for the life of the session.\n\t *\n\t * `record.toolCallId` (from context-gc's packed record) is exactly the holder id\n\t * `packToolOutput()` used when it called `addReference()` -- both trace back to the\n\t * same tool call's id -- so no separate bookkeeping is needed to find it.\n\t */\n\tprivate _releaseGcPackedArtifactReferences(messages: AgentMessage[], report: ContextGcReport): void {\n\t\tconst store = this._toolArtifactStore;\n\t\tif (!store) return; // no store was ever constructed, so nothing could have been packed to one\n\n\t\tlet releasedAny = false;\n\t\tfor (const record of report.records) {\n\t\t\tif (record.toolName !== \"grep\" && record.toolName !== \"find\") continue;\n\t\t\tconst artifactId = extractArtifactId(messages[record.messageIndex]);\n\t\t\tif (!artifactId) continue;\n\t\t\tif (store.removeReference(artifactId, record.toolCallId)) releasedAny = true;\n\t\t}\n\t\t// Cleanup only runs immediately after a release actually happened in this pass, so\n\t\t// a long session doesn't re-scan the artifact directory on every turn once nothing\n\t\t// new became eligible for release.\n\t\tif (releasedAny) store.cleanup();\n\t}\n\n\tgetContextGcReport(messages?: AgentMessage[]): ContextGcReport {\n\t\tif (messages) return this.applyContextGc(messages, false).report;\n\t\treturn (\n\t\t\tthis._latestContextGcReport ?? {\n\t\t\t\tenabled: this.deps.getSettingsManager().getContextGcSettings().enabled,\n\t\t\t\tpackedCount: 0,\n\t\t\t\toriginalTokens: 0,\n\t\t\t\tpackedTokens: 0,\n\t\t\t\tsavedTokens: 0,\n\t\t\t\trecords: [],\n\t\t\t}\n\t\t);\n\t}\n\n\testimateCurrentContextTokens(messages: AgentMessage[]): number {\n\t\tconst estimate = estimateContextTokens(messages);\n\t\tif (estimate.lastUsageIndex === null) {\n\t\t\treturn this._tokenBudget.estimateDelta(estimateConversationChars(messages));\n\t\t}\n\n\t\tconst usageMessage = messages[estimate.lastUsageIndex];\n\t\tconst compactionEntry = getLatestCompactionEntry(this.deps.getSessionManager().getBranch());\n\t\tif (usageMessage?.role !== \"assistant\" || !compactionEntry) {\n\t\t\treturn estimate.tokens;\n\t\t}\n\t\tconst usageTimestamp = (usageMessage as AssistantMessage).timestamp;\n\t\tconst compactionTimestamp = new Date(compactionEntry.timestamp).getTime();\n\t\tif (usageTimestamp <= compactionTimestamp) {\n\t\t\treturn this._tokenBudget.estimateDelta(estimateConversationChars(messages));\n\t\t}\n\n\t\tconst coveredChars = estimateConversationChars(messages, 0, estimate.lastUsageIndex + 1);\n\t\tconst deltaChars = estimateConversationChars(messages, estimate.lastUsageIndex + 1, messages.length);\n\t\tthis._tokenBudget.anchor(estimate.usageTokens, coveredChars);\n\t\treturn this._tokenBudget.current(deltaChars, estimate.tokens);\n\t}\n}\n\n/**\n * Estimate covered characters from the provider-visible context messages.\n */\nfunction estimateConversationChars(messages: AgentMessage[], start = 0, end = messages.length): number {\n\tlet total = 0;\n\tfor (let index = Math.max(0, start); index < Math.min(messages.length, end); index++) {\n\t\tconst message = messages[index];\n\t\tif (!message) continue;\n\t\tconst rawContent = (message as { content?: unknown }).content;\n\t\tif (typeof rawContent === \"string\") {\n\t\t\ttotal += rawContent.length;\n\t\t\tcontinue;\n\t\t}\n\t\tif (!Array.isArray(rawContent)) {\n\t\t\tcontinue;\n\t\t}\n\t\tfor (const block of rawContent) {\n\t\t\tif (typeof block === \"string\") {\n\t\t\t\ttotal += block.length;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (!block || typeof block !== \"object\") {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (typeof (block as { text?: unknown }).text === \"string\") {\n\t\t\t\ttotal += (block as { text?: string }).text?.length ?? 0;\n\t\t\t}\n\t\t\tif (typeof (block as { thinking?: unknown }).thinking === \"string\") {\n\t\t\t\ttotal += (block as { thinking?: string }).thinking?.length ?? 0;\n\t\t\t}\n\t\t}\n\t}\n\treturn total;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"context-pipeline.js","sourceRoot":"","sources":["../../src/core/context-pipeline.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Context pipeline: the session's per-turn context-shaping subsystem — the observe-only context\n * audit, the shadow prompt-policy plan and its correlation with legacy context-gc, the enforcement\n * pilot, the relevance-curation queue + the fitness-gated curation model resolver / brain-curation\n * drain + compaction pre-digest, the legacy context-gc pass and its packed-artifact reference\n * release, the tool-output artifact store, and the current-context token estimate.\n *\n * Extracted verbatim from agent-session.ts (god-file decomposition). Owns the latest\n * audit/policy/correlation/enforcement/gc reports, the {@link BrainCurator} sidecar and its last\n * skip reasons, and the lazily-built tool-artifact store. Everything else it needs — the turn\n * index, the session/settings managers, the model registry, agent/workspace dirs, the active tool\n * names, the disposed flag, the isolated-completion primitive, spawned-usage accounting, and the\n * live {@link MemoryManager} — is reached through narrow deps accessors rather than the whole\n * AgentSession.\n *\n * Context-transform boundary (deliberate): the per-turn stages ({@link estimateCurrentContextTokens},\n * {@link runContextAudit}, {@link runPromptPolicyPlanning}, {@link applyContextGc},\n * {@link correlatePromptPolicyWithContextGc}, {@link runPromptEnforcement},\n * {@link enqueueRelevanceCuration}, {@link maybeDrainBrainCuration}) are invoked from the session's\n * context transform as one-line delegations, so the transform stays the single owner of the pass\n * ordering. This controller reaches {@link MemoryController} functionality only through\n * {@link ContextPipelineDeps.getMemoryManager} (never imports it), and MemoryController never imports\n * the pipeline — keeping the transform the one place the two subsystems meet.\n */\n\nimport { join } from \"node:path\";\nimport type { AgentMessage } from \"@caupulican/pi-agent-core\";\nimport {\n\testimateContextTokens,\n\tgetLatestCompactionEntry,\n\ttype SessionManager,\n\tTokenBudget,\n} from \"@caupulican/pi-agent-core/node\";\nimport type { Api, AssistantMessage, Model, Usage } from \"@caupulican/pi-ai\";\nimport type { IsolatedCompletionOptions, IsolatedCompletionResult } from \"./agent-session.ts\";\nimport { BrainCurator, type CurationTelemetrySnapshot, preDigestConversationText } from \"./context/brain-curator.ts\";\nimport { type ArtifactStore, createFileArtifactStore } from \"./context/context-artifacts.ts\";\nimport { type ContextAuditReport, runContextAudit } from \"./context/context-audit.ts\";\nimport { enforcePromptPolicy, type PromptEnforcementReport } from \"./context/context-prompt-enforcement.ts\";\nimport {\n\tcorrelateWithContextGc,\n\ttype PromptPolicyGcCorrelationReport,\n\ttype PromptPolicyShadowReport,\n\tplanPromptPolicy,\n} from \"./context/context-prompt-policy.ts\";\nimport { applyContextGc, type ContextGcReport } from \"./context-gc.ts\";\nimport type { MemoryManager } from \"./memory/memory-manager.ts\";\nimport type { ModelRegistry } from \"./model-registry.ts\";\nimport { resolveCliModel } from \"./model-resolver.ts\";\nimport { evaluateSurfaceFitness } from \"./model-router/fitness-gate.ts\";\nimport { FitnessStore } from \"./models/fitness-store.ts\";\nimport type { SettingsManager } from \"./settings-manager.ts\";\n\n/** Latest user prompt text in the provider-visible array (curation goal line; bounded by caller). */\nexport function latestUserPromptText(messages: AgentMessage[]): string {\n\tfor (let index = messages.length - 1; index >= 0; index--) {\n\t\tconst message = messages[index];\n\t\tif (!message || message.role !== \"user\") continue;\n\t\tif (typeof message.content === \"string\") return message.content;\n\t\tconst text = message.content\n\t\t\t.filter((part): part is { type: \"text\"; text: string } => (part as { type?: string }).type === \"text\")\n\t\t\t.map((part) => part.text)\n\t\t\t.join(\"\\n\");\n\t\tif (text.length > 0) return text;\n\t}\n\treturn \"\";\n}\n\n/** Read a packed grep/find tool result's `details.artifactId`, if present, without `any`. */\nfunction extractArtifactId(message: AgentMessage | undefined): string | undefined {\n\tif (!message || message.role !== \"toolResult\") return undefined;\n\tconst details = (message as { details?: unknown }).details;\n\tif (typeof details !== \"object\" || details === null) return undefined;\n\tconst artifactId = (details as { artifactId?: unknown }).artifactId;\n\treturn typeof artifactId === \"string\" ? artifactId : undefined;\n}\n\nexport interface ContextPipelineDeps {\n\t/** Current turn index, stamped into audit/policy/enforcement reports. */\n\tgetTurnIndex(): number;\n\t/** Session log: audit lookup, gc/artifact storage dirs, curation entries, token-estimate compaction anchor. */\n\tgetSessionManager(): SessionManager;\n\t/** Context-gc / prompt-enforcement / curation settings (all opt-in gates). */\n\tgetSettingsManager(): SettingsManager;\n\t/** Resolves a configured curation model pattern against configured auth. */\n\tgetModelRegistry(): ModelRegistry;\n\t/** Root dir the host-keyed {@link FitnessStore} and per-session gc/artifact storage live under. */\n\tgetAgentDir(): string;\n\t/** Workspace root, passed to the context-gc pass. */\n\tgetCwd(): string;\n\t/** Currently-active tool names — enforcement checks whether artifact_retrieve is a live affordance. */\n\tgetActiveToolNames(): string[];\n\t/** A disposed session must never persist a curation/pre-digest entry. */\n\tisDisposed(): boolean;\n\t/** The live memory manager — the active providers' page markers feed the semantic-gc scan. */\n\tgetMemoryManager(): MemoryManager;\n\t/** Roll a curation drain's spawned usage into session accounting (idempotent per reportId). */\n\taddSpawnedUsage(\n\t\tusage: Usage,\n\t\topts?: { label?: string; sourceSessionId?: string; reportId?: string },\n\t): string | undefined;\n\t/** One-shot LLM call fully isolated from the main session — the curation/pre-digest execution primitive. */\n\trunIsolatedCompletion(opts: IsolatedCompletionOptions): Promise<IsolatedCompletionResult>;\n}\n\nexport class ContextPipeline {\n\tprivate _latestContextGcReport: ContextGcReport | undefined = undefined;\n\t/** Brain-curation sidecar (design: brain-context-curation-design.md). Inert unless the\n\t * contextPolicy.curation setting is enabled AND the model passes the digest fitness gate. */\n\tprivate readonly _brainCurator = new BrainCurator();\n\tprivate _lastCurationSkipReason: string | undefined = undefined;\n\tprivate _lastPreDigestSkipReason: string | undefined = undefined;\n\tprivate _toolArtifactStore: ArtifactStore | undefined = undefined;\n\tprivate _latestContextAuditReport: ContextAuditReport | undefined = undefined;\n\tprivate _latestPromptPolicyReport: PromptPolicyShadowReport | undefined = undefined;\n\tprivate _latestPromptPolicyGcCorrelation: PromptPolicyGcCorrelationReport | undefined = undefined;\n\tprivate _latestPromptEnforcementReport: PromptEnforcementReport | undefined = undefined;\n\tprivate readonly _tokenBudget = new TokenBudget();\n\n\tprivate readonly deps: ContextPipelineDeps;\n\n\tconstructor(deps: ContextPipelineDeps) {\n\t\tthis.deps = deps;\n\t}\n\n\tprivate _contextGcStorageDir(): string {\n\t\treturn join(this.deps.getAgentDir(), \"context-gc\", this.deps.getSessionManager().getSessionId());\n\t}\n\n\tprivate _toolArtifactsDir(): string {\n\t\treturn join(this.deps.getAgentDir(), \"context-artifacts\", this.deps.getSessionManager().getSessionId());\n\t}\n\n\t/**\n\t * Session-scoped, filesystem-backed artifact store for first-capture-then-bound tool\n\t * output (grep/find only, for now -- see tool-output-artifacts.md). Lazily created and\n\t * cached so every tool construction in this session shares one store instance.\n\t *\n\t * `packToolOutput()` registers a reference (the packing tool call's id) at pack time\n\t * and fails closed, so packed artifacts are never prematurely collected.\n\t * `_releaseGcPackedArtifactReferences()` (called from `applyContextGc()`) releases\n\t * that reference once context-gc packs the result out of live context, and\n\t * opportunistically reclaims now-unreferenced artifacts via `cleanup()`.\n\t * Remaining carry-forward gap: cleanup() now also runs at dispose(), but only reclaims\n\t * already-released (zero-reference) artifacts. A session that ends before context-gc\n\t * ever evicts a result never releases that reference, so its artifact stays on disk by\n\t * design (resolvable on resume). Reclaiming those requires an explicit cross-session\n\t * expiry/liveness policy, not just a sweep.\n\t */\n\tgetToolArtifactStore(): ArtifactStore {\n\t\tthis._toolArtifactStore ??= createFileArtifactStore({ baseDir: this._toolArtifactsDir() });\n\t\treturn this._toolArtifactStore;\n\t}\n\n\t/**\n\t * Best-effort final sweep of any already-released (zero-reference) tool-output artifact at\n\t * session dispose. Reads the field (not the getter) so a session that never packed anything\n\t * doesn't force-create a store/dir just to sweep it.\n\t */\n\tcleanupToolArtifactStoreOnDispose(): void {\n\t\tthis._toolArtifactStore?.cleanup();\n\t}\n\n\t/**\n\t * One pass over the current branch, mapping each toolResult's toolCallId to its\n\t * persisted session-entry id. Rebuilt every audit pass (O(branch) per turn), so this is\n\t * O(n^2) over a long session. Fine at current scale; after the artifact-read fix this is\n\t * the next per-turn audit cost to optimize if it ever matters (e.g. cache/incrementally\n\t * update instead of a full rebuild).\n\t */\n\tprivate _buildSessionEntryIdLookup(): (toolCallId: string) => string | undefined {\n\t\tconst map = new Map<string, string>();\n\t\tfor (const entry of this.deps.getSessionManager().getBranch()) {\n\t\t\tif (entry.type === \"message\" && entry.message.role === \"toolResult\") {\n\t\t\t\tmap.set(entry.message.toolCallId, entry.id);\n\t\t\t}\n\t\t}\n\t\treturn (toolCallId: string) => map.get(toolCallId);\n\t}\n\n\t/**\n\t * Phase 1 observe-only audit pass (see context/context-audit.ts): converts live\n\t * toolResult messages into ContextItems and runs the existing retention/hard-constraint\n\t * evaluators over them, storing the latest deterministic report for tests/debugging.\n\t * Read-only with respect to messages, the transcript, and artifact references -- uses\n\t * `_toolArtifactStore` (the field), not `getToolArtifactStore()` (the getter), so a\n\t * session that never packed anything doesn't force-create a store/dir just to audit.\n\t * Never throws into a live turn: any failure degrades to an empty report.\n\t */\n\trunContextAudit(messages: AgentMessage[]): ContextAuditReport {\n\t\ttry {\n\t\t\tconst report = runContextAudit(messages, {\n\t\t\t\tturnIndex: this.deps.getTurnIndex(),\n\t\t\t\tartifactStore: this._toolArtifactStore,\n\t\t\t\tsessionEntryIdForToolCallId: this._buildSessionEntryIdLookup(),\n\t\t\t});\n\t\t\tthis._latestContextAuditReport = report;\n\t\t\treturn report;\n\t\t} catch {\n\t\t\tconst report: ContextAuditReport = { turnIndex: this.deps.getTurnIndex(), items: [] };\n\t\t\tthis._latestContextAuditReport = report;\n\t\t\treturn report;\n\t\t}\n\t}\n\n\t/**\n\t * Read-only inspection of the context audit. With `messages`, recomputes fresh against\n\t * the given array (still no mutation of messages/transcript/artifact refs); without,\n\t * returns the last report computed during a real transform pass.\n\t */\n\tgetContextAuditReport(messages?: AgentMessage[]): ContextAuditReport {\n\t\tif (messages) return this.runContextAudit(messages);\n\t\treturn this._latestContextAuditReport ?? { turnIndex: this.deps.getTurnIndex(), items: [] };\n\t}\n\n\t/**\n\t * Observe-first shadow/planning pass (see context/context-prompt-policy.ts): re-shapes\n\t * the audit report into a per-item policy plan whose `appliedAction` is always\n\t * \"keep_raw\" -- this never enforces anything, it only records what the policy engine\n\t * would say. Never throws into a live turn: any failure degrades to an empty report.\n\t */\n\trunPromptPolicyPlanning(auditReport: ContextAuditReport): PromptPolicyShadowReport {\n\t\ttry {\n\t\t\tconst report = planPromptPolicy(auditReport);\n\t\t\tthis._latestPromptPolicyReport = report;\n\t\t\treturn report;\n\t\t} catch {\n\t\t\tconst report: PromptPolicyShadowReport = { turnIndex: this.deps.getTurnIndex(), items: [] };\n\t\t\tthis._latestPromptPolicyReport = report;\n\t\t\treturn report;\n\t\t}\n\t}\n\n\t/**\n\t * Read-only inspection of the shadow policy plan. With `messages`, recomputes fresh\n\t * (audit + plan) against the given array; without, returns the last plan computed\n\t * during a real transform pass. Never mutates messages/transcript/artifact refs.\n\t */\n\tgetPromptPolicyReport(messages?: AgentMessage[]): PromptPolicyShadowReport {\n\t\tif (messages) return this.runPromptPolicyPlanning(this.runContextAudit(messages));\n\t\treturn this._latestPromptPolicyReport ?? { turnIndex: this.deps.getTurnIndex(), items: [] };\n\t}\n\n\t/**\n\t * Report-only correlation between the shadow plan just computed this turn and what the\n\t * legacy context-gc pass actually packed. Runs after `applyContextGc()` has already\n\t * produced its report; never influences context-gc itself. Never throws into a live\n\t * turn: any failure degrades to an empty correlation.\n\t */\n\tcorrelatePromptPolicyWithContextGc(gcReport: ContextGcReport): void {\n\t\tconst shadowReport = this._latestPromptPolicyReport ?? { turnIndex: this.deps.getTurnIndex(), items: [] };\n\t\ttry {\n\t\t\tthis._latestPromptPolicyGcCorrelation = correlateWithContextGc(shadowReport, gcReport);\n\t\t} catch {\n\t\t\tthis._latestPromptPolicyGcCorrelation = { turnIndex: this.deps.getTurnIndex(), entries: [] };\n\t\t}\n\t}\n\n\t/** Read-only inspection of the latest shadow-plan/legacy-gc correlation, for tests/debugging. */\n\tgetPromptPolicyGcCorrelation(): PromptPolicyGcCorrelationReport {\n\t\treturn this._latestPromptPolicyGcCorrelation ?? { turnIndex: this.deps.getTurnIndex(), entries: [] };\n\t}\n\n\t/**\n\t * First enforcement pilot (see context/context-prompt-enforcement.ts): opt-in,\n\t * default-disabled stub-in-place of stale artifact-backed tool_output results in the\n\t * provider-visible message array only. Runs on `messages` AFTER context-gc has already\n\t * produced its own result, so legacy context-gc's own packing/reporting is completely\n\t * unaffected by this pass -- it only ever acts on messages gc left untouched this turn.\n\t * Never throws into a live turn: any failure degrades to returning `messages` unchanged.\n\t */\n\trunPromptEnforcement(\n\t\tmessages: AgentMessage[],\n\t\tshadowReport: PromptPolicyShadowReport,\n\t): { messages: AgentMessage[]; report: PromptEnforcementReport } {\n\t\ttry {\n\t\t\tconst persistedSettings = this.deps.getSettingsManager().getContextPromptEnforcementSettings();\n\t\t\tconst curationEnabled = this.deps.getSettingsManager().getContextCurationSettings().enabled;\n\t\t\tconst settings = {\n\t\t\t\t...persistedSettings,\n\t\t\t\t// Runtime fact, never assumed: artifact_retrieve is a companion affordance\n\t\t\t\t// (auto-activated alongside grep/find), not a default/global tool, so active\n\t\t\t\t// tools can differ turn to turn -- see context-prompt-enforcement.ts's doc\n\t\t\t\t// comment on why this is checked separately from hasAvailableRetrievalPath.\n\t\t\t\tretrievalToolAvailable: this.deps.getActiveToolNames().includes(\"artifact_retrieve\"),\n\t\t\t\tbrainRelevance: curationEnabled ? (itemId: string) => this._brainCurator.getRelevance(itemId) : undefined,\n\t\t\t};\n\t\t\tconst result = enforcePromptPolicy(messages, shadowReport, settings);\n\t\t\tthis._latestPromptEnforcementReport = result.report;\n\t\t\treturn result;\n\t\t} catch {\n\t\t\tconst report: PromptEnforcementReport = { turnIndex: this.deps.getTurnIndex(), items: [] };\n\t\t\tthis._latestPromptEnforcementReport = report;\n\t\t\treturn { messages, report };\n\t\t}\n\t}\n\n\t/**\n\t * Enqueue relevance-scoring jobs for stale, artifact-backed tool outputs the enforcement\n\t * pilot could act on. Pure queueing — the verdicts only ever take effect through the\n\t * asymmetric advisory lever inside enforcePromptPolicy. Never throws into a turn.\n\t */\n\tenqueueRelevanceCuration(messages: AgentMessage[], shadowReport: PromptPolicyShadowReport): void {\n\t\ttry {\n\t\t\tconst settings = this.deps.getSettingsManager().getContextCurationSettings();\n\t\t\tif (!settings.enabled) return;\n\t\t\tconst goal = latestUserPromptText(messages).slice(0, 400);\n\t\t\tfor (const item of shadowReport.items) {\n\t\t\t\tif (!item.hasAvailableRetrievalPath) continue;\n\t\t\t\tconst message = messages[item.messageIndex];\n\t\t\t\tif (!message || message.role !== \"toolResult\" || message.toolCallId !== item.toolCallId) continue;\n\t\t\t\tif (message.isError) continue;\n\t\t\t\tconst details = message.details as\n\t\t\t\t\t| { contextGc?: { packed?: unknown }; promptPolicy?: { enforced?: unknown } }\n\t\t\t\t\t| undefined;\n\t\t\t\tif (details?.contextGc?.packed === true || details?.promptPolicy?.enforced === true) continue;\n\t\t\t\tconst text = message.content\n\t\t\t\t\t.filter((part): part is { type: \"text\"; text: string } => part.type === \"text\")\n\t\t\t\t\t.map((part) => part.text)\n\t\t\t\t\t.join(\"\\n\");\n\t\t\t\tif (text.length === 0) continue;\n\t\t\t\tthis._brainCurator.enqueue({ kind: \"relevance\", key: item.itemId, content: text.slice(0, 4000), goal });\n\t\t\t}\n\t\t} catch {\n\t\t\t// curation is a sidecar; it must never disrupt a turn\n\t\t}\n\t}\n\n\t/**\n\t * Drain gate: settings on, model configured+authed, and the model has PASSED the digest\n\t * fitness probe on THIS host (design: unfit or unprobed models are refused with a visible\n\t * reason, never silently degraded). Fire-and-forget; never throws into a turn.\n\t */\n\t/**\n\t * Resolve the curation model IFF every gate passes: setting enabled, model configured,\n\t * resolvable+authed, and digest-fitness-proven on THIS host (canonical \"provider/id\" ref —\n\t * runModelFitness stores reports under it, while settings.model may be a bare id or pattern).\n\t * Sets _lastCurationSkipReason on refusal; never throws.\n\t */\n\tprivate _effectiveContextWindowFromFitness(model: Model<Api>): number {\n\t\tconst registered = model.contextWindow > 0 ? model.contextWindow : Number.POSITIVE_INFINITY;\n\t\tconst capacity = FitnessStore.forAgentDir(this.deps.getAgentDir())\n\t\t\t.getForHost()\n\t\t\t.find((entry) => entry.model === `${model.provider}/${model.id}`)?.report.capacity?.servedContextWindow;\n\t\treturn capacity && capacity > 0 ? Math.min(registered, capacity) : registered;\n\t}\n\n\tresolveCurationModelIfFit(): Model<Api> | undefined {\n\t\tconst settings = this.deps.getSettingsManager().getContextCurationSettings();\n\t\tif (!settings.enabled) {\n\t\t\t// Never surface a stale refusal reason for a feature the user has since disabled.\n\t\t\tthis._lastCurationSkipReason = undefined;\n\t\t\treturn undefined;\n\t\t}\n\t\tif (!settings.model) {\n\t\t\tthis._lastCurationSkipReason = \"curation_model_unset\";\n\t\t\treturn undefined;\n\t\t}\n\t\tconst resolved = resolveCliModel({ cliModel: settings.model, modelRegistry: this.deps.getModelRegistry() });\n\t\tif (!resolved.model || !this.deps.getModelRegistry().hasConfiguredAuth(resolved.model)) {\n\t\t\tthis._lastCurationSkipReason = \"curation_model_unresolved\";\n\t\t\treturn undefined;\n\t\t}\n\t\tconst canonicalRef = `${resolved.model.provider}/${resolved.model.id}`;\n\t\tconst fitness = FitnessStore.forAgentDir(this.deps.getAgentDir())\n\t\t\t.getForHost()\n\t\t\t.find((entry) => entry.model === canonicalRef);\n\t\tconst verdict = evaluateSurfaceFitness(\"curation\", fitness?.report);\n\t\tif (!verdict.fit) {\n\t\t\tthis._lastCurationSkipReason =\n\t\t\t\tverdict.reason === \"unprobed\" ? \"curation_model_unprobed\" : \"curation_model_digest_unfit\";\n\t\t\treturn undefined;\n\t\t}\n\t\tthis._lastCurationSkipReason = undefined;\n\t\treturn resolved.model;\n\t}\n\n\tmaybeDrainBrainCuration(): void {\n\t\ttry {\n\t\t\tif (!this._brainCurator.hasWork() || this._brainCurator.isDraining) return;\n\t\t\tconst model = this.resolveCurationModelIfFit();\n\t\t\tif (!model) return;\n\t\t\tconst settings = this.deps.getSettingsManager().getContextCurationSettings();\n\t\t\tvoid this._drainBrainCuration(model, settings.maxJobsPerTurn);\n\t\t} catch {\n\t\t\t// curation is a sidecar; it must never disrupt a turn\n\t\t}\n\t}\n\n\t/**\n\t * Compaction pre-digest gate (design surface 3): everything the drain gate requires PLUS a\n\t * RUNTIME reliability proof — the curator must have run >=5 jobs on this session with a parse\n\t * failure rate <=5% before it is trusted to pre-digest compaction input. Returns undefined\n\t * (verbatim compaction, byte-for-byte today's behavior) whenever any gate refuses.\n\t */\n\tbuildCompactionPreDigest(): ((text: string, signal?: AbortSignal) => Promise<string>) | undefined {\n\t\ttry {\n\t\t\tconst model = this.resolveCurationModelIfFit();\n\t\t\tif (!model) return undefined;\n\t\t\tconst telemetry = this._brainCurator.telemetry();\n\t\t\tif (telemetry.jobsRun < 5 || telemetry.parseFailures / telemetry.jobsRun > 0.05) {\n\t\t\t\tthis._lastPreDigestSkipReason = \"curation_predigest_reliability_unproven\";\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tthis._lastPreDigestSkipReason = undefined;\n\t\t\treturn async (text, signal) => {\n\t\t\t\tconst effectiveWindow = this._effectiveContextWindowFromFitness(model);\n\t\t\t\tconst chunkChars = Number.isFinite(effectiveWindow)\n\t\t\t\t\t? Math.max(1_000, Math.floor((effectiveWindow - 1024) * 4))\n\t\t\t\t\t: undefined;\n\t\t\t\tconst result = await preDigestConversationText({\n\t\t\t\t\ttext,\n\t\t\t\t\tsignal,\n\t\t\t\t\tchunkChars,\n\t\t\t\t\tcomplete: async ({ systemPrompt, userPrompt, signal: chunkSignal }) => {\n\t\t\t\t\t\tconst completion = await this.deps.runIsolatedCompletion({\n\t\t\t\t\t\t\tsystemPrompt,\n\t\t\t\t\t\t\tmessages: [{ role: \"user\", content: [{ type: \"text\", text: userPrompt }], timestamp: Date.now() }],\n\t\t\t\t\t\t\tmodel,\n\t\t\t\t\t\t\tthinkingLevel: \"off\",\n\t\t\t\t\t\t\tmaxTokens: 512,\n\t\t\t\t\t\t\tsignal: chunkSignal,\n\t\t\t\t\t\t\tcacheRetention: \"short\",\n\t\t\t\t\t\t});\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\ttext: completion.text,\n\t\t\t\t\t\t\tcostUsd: completion.usage.cost.total,\n\t\t\t\t\t\t\tstopReason: String(completion.stopReason),\n\t\t\t\t\t\t};\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\tif (!this.deps.isDisposed() && result.totalChunks > 0) {\n\t\t\t\t\tthis.deps.getSessionManager().appendCustomEntry(\"brain-curation-predigest\", {\n\t\t\t\t\t\tversion: 1,\n\t\t\t\t\t\ttotalChunks: result.totalChunks,\n\t\t\t\t\t\tdigested: result.digested,\n\t\t\t\t\t\tfailed: result.failed,\n\t\t\t\t\t\tcharsBefore: text.length,\n\t\t\t\t\t\tcharsAfter: result.text.length,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn result.text;\n\t\t\t};\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\tprivate async _drainBrainCuration(model: Model<Api>, maxJobs: number): Promise<void> {\n\t\ttry {\n\t\t\t// ACCUMULATE across all drained jobs (the drain runs the completer once PER job) —\n\t\t\t// keeping only the last job's usage would under-report every multi-job drain.\n\t\t\tlet spentUsage: AssistantMessage[\"usage\"] | undefined;\n\t\t\tconst results = await this._brainCurator.drain({\n\t\t\t\tmaxJobs,\n\t\t\t\tcomplete: async ({ systemPrompt, userPrompt, signal }) => {\n\t\t\t\t\tconst completion = await this.deps.runIsolatedCompletion({\n\t\t\t\t\t\tsystemPrompt,\n\t\t\t\t\t\tmessages: [{ role: \"user\", content: [{ type: \"text\", text: userPrompt }], timestamp: Date.now() }],\n\t\t\t\t\t\tmodel,\n\t\t\t\t\t\tthinkingLevel: \"off\",\n\t\t\t\t\t\tmaxTokens: 256,\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t\t// Both curation system prompts are static — the provider can cache the prefix.\n\t\t\t\t\t\tcacheRetention: \"short\",\n\t\t\t\t\t});\n\t\t\t\t\tconst usage = completion.usage;\n\t\t\t\t\tif (!spentUsage) {\n\t\t\t\t\t\tspentUsage = structuredClone(usage);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tspentUsage.input += usage.input;\n\t\t\t\t\t\tspentUsage.output += usage.output;\n\t\t\t\t\t\tspentUsage.cacheRead += usage.cacheRead;\n\t\t\t\t\t\tspentUsage.cacheWrite += usage.cacheWrite;\n\t\t\t\t\t\tspentUsage.totalTokens += usage.totalTokens;\n\t\t\t\t\t\tspentUsage.cost.input += usage.cost.input;\n\t\t\t\t\t\tspentUsage.cost.output += usage.cost.output;\n\t\t\t\t\t\tspentUsage.cost.cacheRead += usage.cost.cacheRead;\n\t\t\t\t\t\tspentUsage.cost.cacheWrite += usage.cost.cacheWrite;\n\t\t\t\t\t\tspentUsage.cost.total += usage.cost.total;\n\t\t\t\t\t}\n\t\t\t\t\treturn {\n\t\t\t\t\t\ttext: completion.text,\n\t\t\t\t\t\tcostUsd: completion.usage.cost.total,\n\t\t\t\t\t\tstopReason: String(completion.stopReason),\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t});\n\t\t\t// Honest accounting even for free local models: token visibility is the contract.\n\t\t\tif (spentUsage && (spentUsage.cost.total > 0 || spentUsage.totalTokens > 0)) {\n\t\t\t\tthis.deps.addSpawnedUsage(spentUsage, { label: \"context-curator\" });\n\t\t\t}\n\t\t\tif (this.deps.isDisposed() || results.length === 0) return;\n\t\t\tthis.deps.getSessionManager().appendCustomEntry(\"brain-curation\", {\n\t\t\t\tversion: 1,\n\t\t\t\tresults: results.map((result) => ({\n\t\t\t\t\tkey: result.key,\n\t\t\t\t\tkind: result.kind,\n\t\t\t\t\tok: result.ok,\n\t\t\t\t\tms: result.ms,\n\t\t\t\t\t...(result.digest !== undefined ? { digest: result.digest } : {}),\n\t\t\t\t\t...(result.relevant !== undefined ? { relevant: result.relevant, confidence: result.confidence } : {}),\n\t\t\t\t})),\n\t\t\t\ttelemetry: this._brainCurator.telemetry(),\n\t\t\t});\n\t\t} catch {\n\t\t\t// curation is a sidecar; it must never disrupt a turn\n\t\t}\n\t}\n\n\t/** Curation status for diagnostics/dashboard: settings, live telemetry, last refusal reason. */\n\tgetContextCurationStatus(): {\n\t\tenabled: boolean;\n\t\tmodel?: string;\n\t\ttelemetry: CurationTelemetrySnapshot;\n\t\tlastSkipReason?: string;\n\t\tlastPreDigestSkipReason?: string;\n\t} {\n\t\tconst settings = this.deps.getSettingsManager().getContextCurationSettings();\n\t\treturn {\n\t\t\tenabled: settings.enabled,\n\t\t\tmodel: settings.model,\n\t\t\ttelemetry: this._brainCurator.telemetry(),\n\t\t\tlastSkipReason: this._lastCurationSkipReason,\n\t\t\tlastPreDigestSkipReason: this._lastPreDigestSkipReason,\n\t\t};\n\t}\n\n\t/** Read-only inspection of the latest prompt-enforcement report, for tests/debugging. */\n\tgetPromptEnforcementReport(): PromptEnforcementReport {\n\t\treturn this._latestPromptEnforcementReport ?? { turnIndex: this.deps.getTurnIndex(), items: [] };\n\t}\n\n\tapplyContextGc(\n\t\tmessages: AgentMessage[],\n\t\twritePayloads: boolean,\n\t): { messages: AgentMessage[]; report: ContextGcReport } {\n\t\ttry {\n\t\t\tconst settings = this.deps.getSettingsManager().getContextGcSettings();\n\t\t\t// Merge the ACTIVE memory providers' own page markers (e.g. transcript-recall's\n\t\t\t// \"<memory_context\") into the semantic-memory marker list. The settings default is\n\t\t\t// provider-agnostic and non-empty, so without this merge the recall pages the bundled\n\t\t\t// default provider actually emits are never recognized as semantic-memory pages and\n\t\t\t// accumulate raw for the life of the session — the exact growth Bug #7 GC exists to stop.\n\t\t\tconst providerMarkers = this.deps.getMemoryManager().getContextMarkers();\n\t\t\tconst curationSettings = this.deps.getSettingsManager().getContextCurationSettings();\n\t\t\tconst result = applyContextGc(messages, {\n\t\t\t\t...settings,\n\t\t\t\tsemanticMemory: {\n\t\t\t\t\t...settings.semanticMemory,\n\t\t\t\t\tmarkers: [...new Set([...settings.semanticMemory.markers, ...providerMarkers])],\n\t\t\t\t},\n\t\t\t\tcwd: this.deps.getCwd(),\n\t\t\t\tstorageDir: this._contextGcStorageDir(),\n\t\t\t\twritePayloads,\n\t\t\t\tcuration: curationSettings.enabled\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tresolveDigest: (digestKey) => {\n\t\t\t\t\t\t\t\tconst digest = this._brainCurator.getDigest(digestKey);\n\t\t\t\t\t\t\t\t// Count serves on the REAL per-turn pass only, never the report path.\n\t\t\t\t\t\t\t\tif (digest !== undefined && writePayloads) this._brainCurator.noteDigestServed();\n\t\t\t\t\t\t\t\treturn digest;\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t// Only the real per-turn pass enqueues work; the read-only report path\n\t\t\t\t\t\t\t// (writePayloads=false) stays side-effect free.\n\t\t\t\t\t\t\tonPacked: writePayloads\n\t\t\t\t\t\t\t\t? (record, originalText) => {\n\t\t\t\t\t\t\t\t\t\tthis._brainCurator.enqueue({\n\t\t\t\t\t\t\t\t\t\t\tkind: \"stub_digest\",\n\t\t\t\t\t\t\t\t\t\t\tkey: record.key ?? record.toolCallId,\n\t\t\t\t\t\t\t\t\t\t\tcontent: originalText,\n\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\t\t}\n\t\t\t\t\t: undefined,\n\t\t\t});\n\t\t\tthis._latestContextGcReport = result.report;\n\t\t\t// Only release/reclaim on the real per-turn pass (writePayloads=true), never on\n\t\t\t// the read-only status-report path (getContextGcReport with writePayloads=false),\n\t\t\t// so merely inspecting the report can't have side effects.\n\t\t\tif (writePayloads && result.report.packedCount > 0) {\n\t\t\t\tthis._releaseGcPackedArtifactReferences(messages, result.report);\n\t\t\t}\n\t\t\treturn result;\n\t\t} catch {\n\t\t\tconst report: ContextGcReport = {\n\t\t\t\tenabled: false,\n\t\t\t\tpackedCount: 0,\n\t\t\t\toriginalTokens: 0,\n\t\t\t\tpackedTokens: 0,\n\t\t\t\tsavedTokens: 0,\n\t\t\t\trecords: [],\n\t\t\t};\n\t\t\tthis._latestContextGcReport = report;\n\t\t\treturn { messages, report };\n\t\t}\n\t}\n\n\t/**\n\t * Reference-release + cleanup lifecycle: once context-gc has packed a grep/find tool\n\t * result out of the live prompt (the message is no longer current/active working\n\t * context -- see contracts-and-retention.md's \"ephemeral\"/\"expired\" retention\n\t * classes), release the pack-time reference `packToolOutput()` registered for it, and\n\t * opportunistically reclaim now-unreferenced artifacts. This is the other half of the\n\t * D2b-1 gate: artifacts were being registered but never released, so they accumulated\n\t * for the life of the session.\n\t *\n\t * `record.toolCallId` (from context-gc's packed record) is exactly the holder id\n\t * `packToolOutput()` used when it called `addReference()` -- both trace back to the\n\t * same tool call's id -- so no separate bookkeeping is needed to find it.\n\t */\n\tprivate _releaseGcPackedArtifactReferences(messages: AgentMessage[], report: ContextGcReport): void {\n\t\tconst store = this._toolArtifactStore;\n\t\tif (!store) return; // no store was ever constructed, so nothing could have been packed to one\n\n\t\tlet releasedAny = false;\n\t\tfor (const record of report.records) {\n\t\t\tif (record.toolName !== \"grep\" && record.toolName !== \"find\") continue;\n\t\t\tconst artifactId = extractArtifactId(messages[record.messageIndex]);\n\t\t\tif (!artifactId) continue;\n\t\t\tif (store.removeReference(artifactId, record.toolCallId)) releasedAny = true;\n\t\t}\n\t\t// Cleanup only runs immediately after a release actually happened in this pass, so\n\t\t// a long session doesn't re-scan the artifact directory on every turn once nothing\n\t\t// new became eligible for release.\n\t\tif (releasedAny) store.cleanup();\n\t}\n\n\tgetContextGcReport(messages?: AgentMessage[]): ContextGcReport {\n\t\tif (messages) return this.applyContextGc(messages, false).report;\n\t\treturn (\n\t\t\tthis._latestContextGcReport ?? {\n\t\t\t\tenabled: this.deps.getSettingsManager().getContextGcSettings().enabled,\n\t\t\t\tpackedCount: 0,\n\t\t\t\toriginalTokens: 0,\n\t\t\t\tpackedTokens: 0,\n\t\t\t\tsavedTokens: 0,\n\t\t\t\trecords: [],\n\t\t\t}\n\t\t);\n\t}\n\n\testimateCurrentContextTokens(messages: AgentMessage[]): number {\n\t\tconst estimate = estimateContextTokens(messages);\n\t\tif (estimate.lastUsageIndex === null) {\n\t\t\treturn this._tokenBudget.estimateDelta(estimateConversationChars(messages));\n\t\t}\n\n\t\tconst usageMessage = messages[estimate.lastUsageIndex];\n\t\tconst compactionEntry = getLatestCompactionEntry(this.deps.getSessionManager().getBranch());\n\t\tif (usageMessage?.role !== \"assistant\" || !compactionEntry) {\n\t\t\treturn estimate.tokens;\n\t\t}\n\t\tconst usageTimestamp = (usageMessage as AssistantMessage).timestamp;\n\t\tconst compactionTimestamp = new Date(compactionEntry.timestamp).getTime();\n\t\tif (usageTimestamp <= compactionTimestamp) {\n\t\t\treturn this._tokenBudget.estimateDelta(estimateConversationChars(messages));\n\t\t}\n\n\t\tconst coveredChars = estimateConversationChars(messages, 0, estimate.lastUsageIndex + 1);\n\t\tconst deltaChars = estimateConversationChars(messages, estimate.lastUsageIndex + 1, messages.length);\n\t\tthis._tokenBudget.anchor(estimate.usageTokens, coveredChars);\n\t\treturn this._tokenBudget.current(deltaChars, estimate.tokens);\n\t}\n}\n\n/**\n * Estimate covered characters from the provider-visible context messages.\n */\nfunction estimateConversationChars(messages: AgentMessage[], start = 0, end = messages.length): number {\n\tlet total = 0;\n\tfor (let index = Math.max(0, start); index < Math.min(messages.length, end); index++) {\n\t\tconst message = messages[index];\n\t\tif (!message) continue;\n\t\tconst rawContent = (message as { content?: unknown }).content;\n\t\tif (typeof rawContent === \"string\") {\n\t\t\ttotal += rawContent.length;\n\t\t\tcontinue;\n\t\t}\n\t\tif (!Array.isArray(rawContent)) {\n\t\t\tcontinue;\n\t\t}\n\t\tfor (const block of rawContent) {\n\t\t\tif (typeof block === \"string\") {\n\t\t\t\ttotal += block.length;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (!block || typeof block !== \"object\") {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (typeof (block as { text?: unknown }).text === \"string\") {\n\t\t\t\ttotal += (block as { text?: string }).text?.length ?? 0;\n\t\t\t}\n\t\t\tif (typeof (block as { thinking?: unknown }).thinking === \"string\") {\n\t\t\t\ttotal += (block as { thinking?: string }).thinking?.length ?? 0;\n\t\t\t}\n\t\t}\n\t}\n\treturn total;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/core/extensions/loader.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAuBH,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAIhE,OAAO,KAAK,EACX,SAAS,EAET,gBAAgB,EAChB,gBAAgB,EAChB,oBAAoB,EAKpB,MAAM,YAAY,CAAC;AA6HpB;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,gBAAgB,CAuDzD;AAgPD;;;;;GAKG;AACH,wBAAsB,kCAAkC,CAAC,UAAU,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAyB/F;AAED,wBAAsB,aAAa,CAClC,aAAa,EAAE,MAAM,EACrB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,gBAAgB,EACzB,IAAI,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GACxB,OAAO,CAAC;IAAE,SAAS,EAAE,SAAS,GAAG,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,CAkBhE;AAmFD;;GAEG;AACH,wBAAsB,wBAAwB,CAC7C,OAAO,EAAE,gBAAgB,EACzB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,gBAAgB,EACzB,aAAa,SAAa,GACxB,OAAO,CAAC,SAAS,CAAC,CAMpB;AAED;;GAEG;AACH,wBAAsB,cAAc,CACnC,KAAK,EAAE,KAAK,CAAC,MAAM,GAAG,iBAAiB,CAAC,EACxC,GAAG,EAAE,MAAM,EACX,QAAQ,CAAC,EAAE,QAAQ,GACjB,OAAO,CAAC,oBAAoB,CAAC,CA0C/B;AAED,UAAU,gBAAgB;IACzB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,8FAA8F;IAC9F,SAAS,CAAC,EAAE,OAAO,CAAC;CACpB;AAaD,UAAU,iBAAiB;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,gBAAgB,EAAE,CAAC;CAC/B;AA2ID;;GAEG;AACH,wBAAsB,yBAAyB,CAC9C,eAAe,EAAE,MAAM,EAAE,EACzB,GAAG,EAAE,MAAM,EACX,QAAQ,GAAE,MAAsB,EAChC,QAAQ,CAAC,EAAE,QAAQ,GACjB,OAAO,CAAC,oBAAoB,CAAC,CA4C/B","sourcesContent":["/**\n * Extension loader - loads TypeScript extension modules using jiti.\n *\n */\n\nimport * as fs from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport * as _bundledPiAgentCore from \"@caupulican/pi-agent-core\";\nimport * as _bundledPiAi from \"@caupulican/pi-ai\";\nimport * as _bundledPiAiOauth from \"@caupulican/pi-ai/oauth\";\nimport type { KeyId } from \"@caupulican/pi-tui\";\nimport * as _bundledPiTui from \"@caupulican/pi-tui\";\nimport { createJiti } from \"jiti/static\";\n// Static imports of packages that extensions may use.\n// These MUST be static so Bun bundles them into the compiled binary.\n// The virtualModules option then makes them available to extensions.\nimport * as _bundledTypebox from \"typebox\";\nimport * as _bundledTypeboxCompile from \"typebox/compile\";\nimport * as _bundledTypeboxValue from \"typebox/value\";\nimport { CONFIG_DIR_NAME, getAgentDir, isBunBinary } from \"../../config.ts\";\n// NOTE: This import works because loader.ts exports are NOT re-exported from index.ts,\n// avoiding a circular dependency. Extensions can import from @caupulican/pi-adaptative.\nimport * as _bundledPiCodingAgent from \"../../index.ts\";\nimport { resolvePath } from \"../../utils/paths.ts\";\nimport { createEventBus, type EventBus } from \"../event-bus.ts\";\nimport type { ExecOptions } from \"../exec.ts\";\nimport { execCommand } from \"../exec.ts\";\nimport { createSyntheticSourceInfo } from \"../source-info.ts\";\nimport type {\n\tExtension,\n\tExtensionAPI,\n\tExtensionFactory,\n\tExtensionRuntime,\n\tLoadExtensionsResult,\n\tMessageRenderer,\n\tProviderConfig,\n\tRegisteredCommand,\n\tToolDefinition,\n} from \"./types.ts\";\n\n/** Modules available to extensions via virtualModules (for compiled Bun binary) */\nconst VIRTUAL_MODULES: Record<string, unknown> = {\n\ttypebox: _bundledTypebox,\n\t\"typebox/compile\": _bundledTypeboxCompile,\n\t\"typebox/value\": _bundledTypeboxValue,\n\t\"@sinclair/typebox\": _bundledTypebox,\n\t\"@sinclair/typebox/compile\": _bundledTypeboxCompile,\n\t\"@sinclair/typebox/value\": _bundledTypeboxValue,\n\t\"@caupulican/pi-agent-core\": _bundledPiAgentCore,\n\t\"@caupulican/pi-tui\": _bundledPiTui,\n\t\"@caupulican/pi-ai\": _bundledPiAi,\n\t\"@caupulican/pi-ai/oauth\": _bundledPiAiOauth,\n\t\"@caupulican/pi-adaptative\": _bundledPiCodingAgent,\n\t\"@earendil-works/pi-agent-core\": _bundledPiAgentCore,\n\t\"@earendil-works/pi-tui\": _bundledPiTui,\n\t\"@earendil-works/pi-ai\": _bundledPiAi,\n\t\"@earendil-works/pi-ai/oauth\": _bundledPiAiOauth,\n\t\"@earendil-works/pi-coding-agent\": _bundledPiCodingAgent,\n\t\"@mariozechner/pi-agent-core\": _bundledPiAgentCore,\n\t\"@mariozechner/pi-tui\": _bundledPiTui,\n\t\"@mariozechner/pi-ai\": _bundledPiAi,\n\t\"@mariozechner/pi-ai/oauth\": _bundledPiAiOauth,\n\t\"@mariozechner/pi-coding-agent\": _bundledPiCodingAgent,\n};\n\nfunction uniquePaths(paths: string[]): string[] {\n\treturn [...new Set(paths)];\n}\n\nfunction safeRealpath(filePath: string): string {\n\ttry {\n\t\treturn fs.realpathSync(filePath);\n\t} catch {\n\t\treturn filePath;\n\t}\n}\n\n/**\n * Get aliases for jiti (used in Node.js/development mode).\n * In Bun binary mode, virtualModules is used instead.\n */\nlet _aliases: Record<string, string> | null = null;\n\nfunction getAliases(): Record<string, string> {\n\tif (_aliases) return _aliases;\n\n\tconst loaderFile = fileURLToPath(import.meta.url);\n\tconst realLoaderFile = safeRealpath(loaderFile);\n\tconst __dirname = path.dirname(loaderFile);\n\tconst realDirname = path.dirname(realLoaderFile);\n\tconst packageIndex = path.resolve(__dirname, \"../..\", \"index.js\");\n\n\tconst moduleRequires = uniquePaths([loaderFile, realLoaderFile]).map((file) => createRequire(file));\n\tconst resolveModule = (specifier: string): string => {\n\t\tfor (const moduleRequire of moduleRequires) {\n\t\t\ttry {\n\t\t\t\treturn moduleRequire.resolve(specifier);\n\t\t\t} catch {\n\t\t\t\t// Try the next resolution base. Linked global installs may resolve the\n\t\t\t\t// loader through the global symlink path while workspace dependencies are\n\t\t\t\t// hoisted beside the real source path.\n\t\t\t}\n\t\t}\n\t\treturn fileURLToPath(import.meta.resolve(specifier));\n\t};\n\n\tconst typeboxEntry = resolveModule(\"typebox\");\n\tconst typeboxCompileEntry = resolveModule(\"typebox/compile\");\n\tconst typeboxValueEntry = resolveModule(\"typebox/value\");\n\n\tconst packagesRoots = uniquePaths([\n\t\tpath.resolve(__dirname, \"../../../../\"),\n\t\tpath.resolve(realDirname, \"../../../../\"),\n\t]);\n\tconst resolveWorkspaceOrImport = (workspaceRelativePath: string, specifier: string): string => {\n\t\tfor (const packagesRoot of packagesRoots) {\n\t\t\tconst workspacePath = path.join(packagesRoot, workspaceRelativePath);\n\t\t\tif (fs.existsSync(workspacePath)) {\n\t\t\t\treturn workspacePath;\n\t\t\t}\n\t\t}\n\t\treturn resolveModule(specifier);\n\t};\n\n\tconst piCodingAgentEntry = packageIndex;\n\tconst piAgentCoreEntry = resolveWorkspaceOrImport(\"agent/dist/index.js\", \"@caupulican/pi-agent-core\");\n\tconst piTuiEntry = resolveWorkspaceOrImport(\"tui/dist/index.js\", \"@caupulican/pi-tui\");\n\tconst piAiEntry = resolveWorkspaceOrImport(\"ai/dist/index.js\", \"@caupulican/pi-ai\");\n\tconst piAiOauthEntry = resolveWorkspaceOrImport(\"ai/dist/oauth.js\", \"@caupulican/pi-ai/oauth\");\n\n\t_aliases = {\n\t\t\"@caupulican/pi-adaptative\": piCodingAgentEntry,\n\t\t\"@caupulican/pi-agent-core\": piAgentCoreEntry,\n\t\t\"@caupulican/pi-tui\": piTuiEntry,\n\t\t\"@caupulican/pi-ai\": piAiEntry,\n\t\t\"@caupulican/pi-ai/oauth\": piAiOauthEntry,\n\t\t\"@earendil-works/pi-coding-agent\": piCodingAgentEntry,\n\t\t\"@earendil-works/pi-agent-core\": piAgentCoreEntry,\n\t\t\"@earendil-works/pi-tui\": piTuiEntry,\n\t\t\"@earendil-works/pi-ai\": piAiEntry,\n\t\t\"@earendil-works/pi-ai/oauth\": piAiOauthEntry,\n\t\t\"@mariozechner/pi-coding-agent\": piCodingAgentEntry,\n\t\t\"@mariozechner/pi-agent-core\": piAgentCoreEntry,\n\t\t\"@mariozechner/pi-tui\": piTuiEntry,\n\t\t\"@mariozechner/pi-ai\": piAiEntry,\n\t\t\"@mariozechner/pi-ai/oauth\": piAiOauthEntry,\n\t\ttypebox: typeboxEntry,\n\t\t\"typebox/compile\": typeboxCompileEntry,\n\t\t\"typebox/value\": typeboxValueEntry,\n\t\t\"@sinclair/typebox\": typeboxEntry,\n\t\t\"@sinclair/typebox/compile\": typeboxCompileEntry,\n\t\t\"@sinclair/typebox/value\": typeboxValueEntry,\n\t};\n\n\treturn _aliases;\n}\n\ntype HandlerFn = (...args: unknown[]) => Promise<unknown>;\n\nfunction yieldToEventLoop(): Promise<void> {\n\treturn new Promise((resolve) => setImmediate(resolve));\n}\n\n/**\n * Create a runtime with throwing stubs for action methods.\n * Runner.bindCore() replaces these with real implementations.\n */\nexport function createExtensionRuntime(): ExtensionRuntime {\n\tconst notInitialized = () => {\n\t\tthrow new Error(\"Extension runtime not initialized. Action methods cannot be called during extension loading.\");\n\t};\n\tconst state: { staleMessage?: string } = {};\n\tconst assertActive = () => {\n\t\tif (state.staleMessage) {\n\t\t\tthrow new Error(state.staleMessage);\n\t\t}\n\t};\n\n\tconst providersByExtension = new Map<string, Set<string>>();\n\n\tconst runtime: ExtensionRuntime = {\n\t\tsendMessage: notInitialized,\n\t\tsendUserMessage: notInitialized,\n\t\tappendEntry: notInitialized,\n\t\tsetSessionName: notInitialized,\n\t\tgetSessionName: notInitialized,\n\t\tsetLabel: notInitialized,\n\t\tgetActiveTools: notInitialized,\n\t\tgetAllTools: notInitialized,\n\t\tsetActiveTools: notInitialized,\n\t\t// registerTool() is valid during extension load; refresh is only needed post-bind.\n\t\trefreshTools: () => {},\n\t\tgetCommands: notInitialized,\n\t\tsetModel: () => Promise.reject(new Error(\"Extension runtime not initialized\")),\n\t\tgetThinkingLevel: notInitialized,\n\t\tsetThinkingLevel: notInitialized,\n\t\tgetExternalResourceRoots: notInitialized,\n\t\tregisterMemoryProvider: notInitialized,\n\t\treportSpawnedUsage: notInitialized,\n\t\tflagValues: new Map(),\n\t\tpendingProviderRegistrations: [],\n\t\tassertActive,\n\t\tinvalidate: (message) => {\n\t\t\tstate.staleMessage ??=\n\t\t\t\tmessage ??\n\t\t\t\t\"This extension ctx is stale after session replacement or reload. Do not use a captured pi or command ctx after ctx.newSession(), ctx.fork(), ctx.switchSession(), or ctx.reload(). For newSession, fork, and switchSession, move post-replacement work into withSession and use the ctx passed to withSession. For reload, do not use the old ctx after await ctx.reload().\";\n\t\t},\n\t\t// Pre-bind: queue registrations so bindCore() can flush them once the\n\t\t// model registry is available. bindCore() replaces both with direct calls.\n\t\tregisterProvider: (name, config, extensionPath = \"<unknown>\") => {\n\t\t\truntime.pendingProviderRegistrations.push({ name, config, extensionPath });\n\t\t},\n\t\tunregisterProvider: (name) => {\n\t\t\truntime.pendingProviderRegistrations = runtime.pendingProviderRegistrations.filter((r) => r.name !== name);\n\t\t},\n\t\tprovidersByExtension,\n\t\tgetProvidersForExtension: (extensionPath: string) => {\n\t\t\treturn [...(providersByExtension.get(extensionPath) ?? [])];\n\t\t},\n\t};\n\n\treturn runtime;\n}\n\n/**\n * Create the ExtensionAPI for an extension.\n * Registration methods write to the extension object.\n * Action methods delegate to the shared runtime.\n */\nfunction createExtensionAPI(\n\textension: Extension,\n\truntime: ExtensionRuntime,\n\tcwd: string,\n\teventBus: EventBus,\n): ExtensionAPI {\n\tconst api = {\n\t\t// Registration methods - write to extension\n\t\ton(event: string, handler: HandlerFn): void {\n\t\t\truntime.assertActive();\n\t\t\tconst list = extension.handlers.get(event) ?? [];\n\t\t\tlist.push(handler);\n\t\t\textension.handlers.set(event, list);\n\t\t},\n\n\t\tregisterTool(tool: ToolDefinition): void {\n\t\t\truntime.assertActive();\n\t\t\textension.tools.set(tool.name, {\n\t\t\t\tdefinition: tool,\n\t\t\t\tsourceInfo: extension.sourceInfo,\n\t\t\t});\n\t\t\truntime.refreshTools();\n\t\t},\n\n\t\tregisterCommand(name: string, options: Omit<RegisteredCommand, \"name\" | \"sourceInfo\">): void {\n\t\t\truntime.assertActive();\n\t\t\textension.commands.set(name, {\n\t\t\t\tname,\n\t\t\t\tsourceInfo: extension.sourceInfo,\n\t\t\t\t...options,\n\t\t\t});\n\t\t},\n\n\t\tregisterShortcut(\n\t\t\tshortcut: KeyId,\n\t\t\toptions: {\n\t\t\t\tdescription?: string;\n\t\t\t\thandler: (ctx: import(\"./types.ts\").ExtensionContext) => Promise<void> | void;\n\t\t\t},\n\t\t): void {\n\t\t\truntime.assertActive();\n\t\t\textension.shortcuts.set(shortcut, { shortcut, extensionPath: extension.path, ...options });\n\t\t},\n\n\t\tregisterFlag(\n\t\t\tname: string,\n\t\t\toptions: { description?: string; type: \"boolean\" | \"string\"; default?: boolean | string },\n\t\t): void {\n\t\t\truntime.assertActive();\n\t\t\textension.flags.set(name, { name, extensionPath: extension.path, ...options });\n\t\t\tif (options.default !== undefined && !runtime.flagValues.has(name)) {\n\t\t\t\truntime.flagValues.set(name, options.default);\n\t\t\t}\n\t\t},\n\n\t\tregisterMessageRenderer<T>(customType: string, renderer: MessageRenderer<T>): void {\n\t\t\truntime.assertActive();\n\t\t\textension.messageRenderers.set(customType, renderer as MessageRenderer);\n\t\t},\n\n\t\t// Flag access - checks extension registered it, reads from runtime\n\t\tgetFlag(name: string): boolean | string | undefined {\n\t\t\truntime.assertActive();\n\t\t\tif (!extension.flags.has(name)) return undefined;\n\t\t\treturn runtime.flagValues.get(name);\n\t\t},\n\n\t\t// Action methods - delegate to shared runtime\n\t\tsendMessage(message, options): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.sendMessage(message, options);\n\t\t},\n\n\t\tsendUserMessage(content, options): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.sendUserMessage(content, options);\n\t\t},\n\n\t\tappendEntry(customType: string, data?: unknown): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.appendEntry(customType, data);\n\t\t},\n\n\t\tsetSessionName(name: string): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.setSessionName(name);\n\t\t},\n\n\t\tgetSessionName(): string | undefined {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getSessionName();\n\t\t},\n\n\t\tsetLabel(entryId: string, label: string | undefined): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.setLabel(entryId, label);\n\t\t},\n\n\t\texec(command: string, args: string[], options?: ExecOptions) {\n\t\t\truntime.assertActive();\n\t\t\treturn execCommand(command, args, options?.cwd ?? cwd, options);\n\t\t},\n\n\t\tgetActiveTools(): string[] {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getActiveTools();\n\t\t},\n\n\t\tgetAllTools() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getAllTools();\n\t\t},\n\n\t\tsetActiveTools(toolNames: string[]): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.setActiveTools(toolNames);\n\t\t},\n\n\t\tgetCommands() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getCommands();\n\t\t},\n\n\t\tgetExternalResourceRoots() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getExternalResourceRoots();\n\t\t},\n\n\t\tregisterMemoryProvider(provider) {\n\t\t\truntime.assertActive();\n\t\t\truntime.registerMemoryProvider(provider);\n\t\t},\n\n\t\treportSpawnedUsage(usage, opts) {\n\t\t\truntime.assertActive();\n\t\t\truntime.reportSpawnedUsage(usage, opts);\n\t\t},\n\n\t\tsetModel(model) {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.setModel(model);\n\t\t},\n\n\t\tgetThinkingLevel() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getThinkingLevel();\n\t\t},\n\n\t\tsetThinkingLevel(level) {\n\t\t\truntime.assertActive();\n\t\t\truntime.setThinkingLevel(level);\n\t\t},\n\n\t\tregisterProvider(name: string, config: ProviderConfig) {\n\t\t\truntime.assertActive();\n\t\t\truntime.registerProvider(name, config, extension.path);\n\t\t},\n\n\t\tunregisterProvider(name: string) {\n\t\t\truntime.assertActive();\n\t\t\truntime.unregisterProvider(name, extension.path);\n\t\t},\n\n\t\tonDispose(fn: () => void | Promise<void>): void {\n\t\t\truntime.assertActive();\n\t\t\textension.disposers.push(fn);\n\t\t},\n\n\t\t// Track bus subscriptions per extension generation so hot reloads can\n\t\t// unsubscribe replaced generations (see disposeExtensionEventSubscriptions).\n\t\tevents: {\n\t\t\temit: (channel: string, data: unknown) => {\n\t\t\t\truntime.assertActive();\n\t\t\t\teventBus.emit(channel, data);\n\t\t\t},\n\t\t\ton: (channel: string, handler: (data: unknown) => void) => {\n\t\t\t\truntime.assertActive();\n\t\t\t\tconst unsubscribe = eventBus.on(channel, handler);\n\t\t\t\textension.eventUnsubscribes.push(unsubscribe);\n\t\t\t\treturn unsubscribe;\n\t\t\t},\n\t\t},\n\t} as ExtensionAPI;\n\n\treturn api;\n}\n\nasync function loadExtensionModule(extensionPath: string, opts?: { fresh?: boolean }) {\n\tconst jiti = createJiti(import.meta.url, {\n\t\tmoduleCache: false,\n\t\t// In Bun binary: use virtualModules for bundled packages (no filesystem resolution)\n\t\t// Also disable tryNative so jiti handles ALL imports (not just the entry point)\n\t\t// In Node.js/dev: use aliases to resolve to node_modules paths\n\t\t...(isBunBinary ? { virtualModules: VIRTUAL_MODULES, tryNative: false } : { alias: getAliases() }),\n\t});\n\n\t// When fresh mode is enabled, append a cache-busting query string to force re-import\n\tlet resolvedPath = extensionPath;\n\tif (opts?.fresh) {\n\t\tconst separator = extensionPath.includes(\"?\") ? \"&\" : \"?\";\n\t\tresolvedPath = `${extensionPath}${separator}fresh=${Date.now()}`;\n\t}\n\n\tconst module = await jiti.import(resolvedPath, { default: true });\n\tconst factory = module as ExtensionFactory;\n\treturn typeof factory !== \"function\" ? undefined : factory;\n}\n\n/**\n * Create an Extension object with empty collections.\n */\nfunction createExtension(extensionPath: string, resolvedPath: string): Extension {\n\tconst source =\n\t\textensionPath.startsWith(\"<\") && extensionPath.endsWith(\">\")\n\t\t\t? extensionPath.slice(1, -1).split(\":\")[0] || \"temporary\"\n\t\t\t: \"local\";\n\tconst baseDir = extensionPath.startsWith(\"<\") ? undefined : path.dirname(resolvedPath);\n\n\treturn {\n\t\tpath: extensionPath,\n\t\tresolvedPath,\n\t\tsourceInfo: createSyntheticSourceInfo(extensionPath, { source, baseDir }),\n\t\thandlers: new Map(),\n\t\ttools: new Map(),\n\t\tmessageRenderers: new Map(),\n\t\tcommands: new Map(),\n\t\tflags: new Map(),\n\t\tshortcuts: new Map(),\n\t\teventUnsubscribes: [],\n\t\tdisposers: [],\n\t};\n}\n\n/**\n * Unsubscribe a replaced extension generation's pi.events handlers from the shared\n * event bus and invoke cleanup callbacks. Without this, every hot reload leaves the\n * previous generation's handlers subscribed, pinning the old module graph in memory\n * and double-processing events.\n */\nexport async function disposeExtensionEventSubscriptions(extensions: Extension[]): Promise<void> {\n\tfor (const extension of extensions) {\n\t\t// Unsubscribe event listeners\n\t\tfor (const unsubscribe of extension.eventUnsubscribes) {\n\t\t\ttry {\n\t\t\t\tunsubscribe();\n\t\t\t} catch {\n\t\t\t\t// Disposal must never break a reload.\n\t\t\t}\n\t\t}\n\t\textension.eventUnsubscribes.length = 0;\n\n\t\t// Invoke cleanup callbacks\n\t\tfor (const disposer of extension.disposers) {\n\t\t\ttry {\n\t\t\t\tconst result = disposer();\n\t\t\t\tif (result instanceof Promise) {\n\t\t\t\t\tawait result;\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Disposal must never break a reload.\n\t\t\t}\n\t\t}\n\t\textension.disposers.length = 0;\n\t}\n}\n\nexport async function loadExtension(\n\textensionPath: string,\n\tcwd: string,\n\teventBus: EventBus,\n\truntime: ExtensionRuntime,\n\topts?: { fresh?: boolean },\n): Promise<{ extension: Extension | null; error: string | null }> {\n\tconst resolvedPath = resolvePath(extensionPath, cwd, { normalizeUnicodeSpaces: true });\n\n\ttry {\n\t\tconst factory = await loadExtensionModule(resolvedPath, opts);\n\t\tif (!factory) {\n\t\t\treturn { extension: null, error: `Extension does not export a valid factory function: ${extensionPath}` };\n\t\t}\n\n\t\tconst extension = createExtension(extensionPath, resolvedPath);\n\t\tconst api = createExtensionAPI(extension, runtime, cwd, eventBus);\n\t\tawait factory(api);\n\n\t\treturn { extension, error: null };\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\treturn { extension: null, error: `Failed to load extension: ${message}` };\n\t}\n}\n\nfunction createLazyToolDefinition(\n\textension: Extension,\n\tmanifest: LazyToolManifest,\n\tload: () => Promise<void>,\n): ToolDefinition {\n\tconst name = String(manifest.name).trim();\n\tconst definition: ToolDefinition = {\n\t\tname,\n\t\tlabel: typeof manifest.label === \"string\" && manifest.label.trim() ? manifest.label : name,\n\t\tdescription:\n\t\t\ttypeof manifest.description === \"string\" && manifest.description.trim()\n\t\t\t\t? manifest.description\n\t\t\t\t: `Lazy extension tool ${name}`,\n\t\tparameters: (manifest.parameters ?? defaultLazyToolParameters()) as ToolDefinition[\"parameters\"],\n\t\tpromptSnippet: typeof manifest.promptSnippet === \"string\" ? manifest.promptSnippet : undefined,\n\t\tpromptGuidelines: Array.isArray(manifest.promptGuidelines)\n\t\t\t? manifest.promptGuidelines.filter((item): item is string => typeof item === \"string\")\n\t\t\t: undefined,\n\t\ttoolGroup: typeof manifest.toolGroup === \"string\" ? manifest.toolGroup : undefined,\n\t\texecutionMode:\n\t\t\tmanifest.executionMode === \"parallel\" || manifest.executionMode === \"sequential\"\n\t\t\t\t? manifest.executionMode\n\t\t\t\t: undefined,\n\t\texecute: async (toolCallId, params, signal, onUpdate, ctx) => {\n\t\t\tawait load();\n\t\t\tconst loadedDefinition = extension.tools.get(name)?.definition;\n\t\t\tif (!loadedDefinition || loadedDefinition === definition) {\n\t\t\t\tthrow new Error(`Lazy extension ${extension.path} did not register tool ${name}`);\n\t\t\t}\n\t\t\treturn loadedDefinition.execute(toolCallId, params, signal, onUpdate, ctx);\n\t\t},\n\t};\n\treturn definition;\n}\n\nfunction createLazyExtension(\n\textensionPath: string,\n\tresolvedPath: string,\n\tcwd: string,\n\teventBus: EventBus,\n\truntime: ExtensionRuntime,\n\tlazyTools: LazyToolManifest[],\n): Extension {\n\tconst extension = createExtension(extensionPath, resolvedPath);\n\tconst load = async (): Promise<void> => {\n\t\tif (extension.lazy?.loaded) return;\n\t\tif (extension.lazy?.loading) return extension.lazy.loading;\n\n\t\tconst loading = (async () => {\n\t\t\tconst factory = await loadExtensionModule(resolvedPath);\n\t\t\tif (!factory) {\n\t\t\t\tthrow new Error(`Extension does not export a valid factory function: ${extensionPath}`);\n\t\t\t}\n\t\t\tconst api = createExtensionAPI(extension, runtime, cwd, eventBus);\n\t\t\tawait factory(api);\n\t\t\tif (extension.lazy) {\n\t\t\t\textension.lazy.loaded = true;\n\t\t\t\textension.lazy.loading = undefined;\n\t\t\t}\n\t\t})();\n\n\t\tif (extension.lazy) extension.lazy.loading = loading;\n\t\ttry {\n\t\t\tawait loading;\n\t\t} catch (err) {\n\t\t\tif (extension.lazy) extension.lazy.loading = undefined;\n\t\t\tthrow err;\n\t\t}\n\t};\n\n\textension.lazy = { loaded: false, load };\n\tfor (const tool of lazyTools) {\n\t\tconst name = String(tool.name).trim();\n\t\textension.tools.set(name, {\n\t\t\tdefinition: createLazyToolDefinition(extension, tool, load),\n\t\t\tsourceInfo: extension.sourceInfo,\n\t\t});\n\t}\n\treturn extension;\n}\n\n/**\n * Create an Extension from an inline factory function.\n */\nexport async function loadExtensionFromFactory(\n\tfactory: ExtensionFactory,\n\tcwd: string,\n\teventBus: EventBus,\n\truntime: ExtensionRuntime,\n\textensionPath = \"<inline>\",\n): Promise<Extension> {\n\tconst extension = createExtension(extensionPath, extensionPath);\n\tconst resolvedCwd = resolvePath(cwd);\n\tconst api = createExtensionAPI(extension, runtime, resolvedCwd, eventBus);\n\tawait factory(api);\n\treturn extension;\n}\n\n/**\n * Load extensions from paths.\n */\nexport async function loadExtensions(\n\tpaths: Array<string | ExtensionLoadSpec>,\n\tcwd: string,\n\teventBus?: EventBus,\n): Promise<LoadExtensionsResult> {\n\tconst extensions: Extension[] = [];\n\tconst errors: Array<{ path: string; error: string }> = [];\n\tconst resolvedCwd = resolvePath(cwd);\n\tconst resolvedEventBus = eventBus ?? createEventBus();\n\tconst runtime = createExtensionRuntime();\n\n\tfor (const spec of paths) {\n\t\tconst normalized = typeof spec === \"string\" ? { path: spec } : spec;\n\t\tconst extPath = normalized.path;\n\t\tconst resolvedPath = resolvePath(extPath, resolvedCwd, { normalizeUnicodeSpaces: true });\n\t\tconst lazyTools = (normalized.lazyTools ?? inferLazyToolsForExtensionPath(resolvedPath))?.filter(\n\t\t\t(tool) => typeof tool.name === \"string\" && tool.name.trim(),\n\t\t);\n\t\t// Extension imports can be CPU-heavy under jiti. Yield around each load so\n\t\t// interactive reloads can repaint/status-update instead of freezing the TUI\n\t\t// for the whole extension set. Lazy tool manifests skip import entirely here.\n\t\tawait yieldToEventLoop();\n\t\tif (lazyTools?.length) {\n\t\t\textensions.push(createLazyExtension(extPath, resolvedPath, resolvedCwd, resolvedEventBus, runtime, lazyTools));\n\t\t\tawait yieldToEventLoop();\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst { extension, error } = await loadExtension(extPath, resolvedCwd, resolvedEventBus, runtime);\n\t\tawait yieldToEventLoop();\n\n\t\tif (error) {\n\t\t\terrors.push({ path: extPath, error });\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (extension) {\n\t\t\textensions.push(extension);\n\t\t}\n\t}\n\n\treturn {\n\t\textensions,\n\t\terrors,\n\t\truntime,\n\t};\n}\n\ninterface LazyToolManifest {\n\tname?: unknown;\n\tlabel?: unknown;\n\tdescription?: unknown;\n\tparameters?: unknown;\n\tpromptSnippet?: unknown;\n\tpromptGuidelines?: unknown;\n\ttoolGroup?: unknown;\n\texecutionMode?: unknown;\n\t/** Optional extension entry this tool belongs to when a package declares multiple entries. */\n\textension?: unknown;\n}\n\ninterface PiManifest {\n\textensions?: string[];\n\tthemes?: string[];\n\tskills?: string[];\n\tprompts?: string[];\n\t/** Tool metadata for opt-in lazy extension loading. Factories stay unloaded until one of these tools runs. */\n\tlazyTools?: LazyToolManifest[];\n\t/** Alternate nested spelling: { tools: [...] }. */\n\tlazy?: { tools?: LazyToolManifest[] } | boolean;\n}\n\ninterface ExtensionLoadSpec {\n\tpath: string;\n\tlazyTools?: LazyToolManifest[];\n}\n\nfunction getManifestLazyTools(manifest: PiManifest | null): LazyToolManifest[] | undefined {\n\tif (!manifest) return undefined;\n\tconst tools = Array.isArray(manifest.lazyTools)\n\t\t? manifest.lazyTools\n\t\t: typeof manifest.lazy === \"object\" && Array.isArray(manifest.lazy.tools)\n\t\t\t? manifest.lazy.tools\n\t\t\t: undefined;\n\treturn tools?.filter((tool) => tool && typeof tool.name === \"string\" && tool.name.trim());\n}\n\nfunction defaultLazyToolParameters(): ToolDefinition[\"parameters\"] {\n\treturn { type: \"object\", properties: {}, additionalProperties: false } as ToolDefinition[\"parameters\"];\n}\n\nfunction lazyToolsForEntry(tools: LazyToolManifest[] | undefined, dir: string, entryPath: string, entryCount: number) {\n\tif (!tools?.length) return undefined;\n\tconst selected = tools.filter((tool) => {\n\t\tif (typeof tool.extension !== \"string\" || !tool.extension.trim()) {\n\t\t\treturn entryCount === 1;\n\t\t}\n\t\treturn path.resolve(dir, tool.extension) === entryPath;\n\t});\n\treturn selected.length > 0 ? selected : undefined;\n}\n\nfunction inferLazyToolsForExtensionPath(resolvedPath: string): LazyToolManifest[] | undefined {\n\tconst dir = path.dirname(resolvedPath);\n\tconst manifest = readPiManifest(path.join(dir, \"package.json\"));\n\tconst lazyTools = getManifestLazyTools(manifest);\n\tif (!manifest?.extensions?.length || !lazyTools?.length) return undefined;\n\tconst resolvedEntries = manifest.extensions.map((extPath) => path.resolve(dir, extPath));\n\tif (!resolvedEntries.includes(resolvedPath)) return undefined;\n\treturn lazyToolsForEntry(lazyTools, dir, resolvedPath, resolvedEntries.length);\n}\n\nfunction readPiManifest(packageJsonPath: string): PiManifest | null {\n\ttry {\n\t\tconst content = fs.readFileSync(packageJsonPath, \"utf-8\");\n\t\tconst pkg = JSON.parse(content);\n\t\tif (pkg.pi && typeof pkg.pi === \"object\") {\n\t\t\treturn pkg.pi as PiManifest;\n\t\t}\n\t\treturn null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction isExtensionFile(name: string): boolean {\n\treturn name.endsWith(\".ts\") || name.endsWith(\".js\");\n}\n\n/**\n * Resolve extension entry points from a directory.\n *\n * Checks for:\n * 1. package.json with \"pi.extensions\" field -> returns declared paths\n * 2. index.ts or index.js -> returns the index file\n *\n * Returns resolved paths or null if no entry points found.\n */\nfunction resolveExtensionEntries(dir: string): ExtensionLoadSpec[] | null {\n\t// Check for package.json with \"pi\" field first\n\tconst packageJsonPath = path.join(dir, \"package.json\");\n\tif (fs.existsSync(packageJsonPath)) {\n\t\tconst manifest = readPiManifest(packageJsonPath);\n\t\tif (manifest?.extensions?.length) {\n\t\t\tconst resolvedEntries = manifest.extensions\n\t\t\t\t.map((extPath) => path.resolve(dir, extPath))\n\t\t\t\t.filter((resolvedExtPath) => fs.existsSync(resolvedExtPath));\n\t\t\tif (resolvedEntries.length > 0) {\n\t\t\t\tconst lazyTools = getManifestLazyTools(manifest);\n\t\t\t\treturn resolvedEntries.map((entryPath) => ({\n\t\t\t\t\tpath: entryPath,\n\t\t\t\t\tlazyTools: lazyToolsForEntry(lazyTools, dir, entryPath, resolvedEntries.length),\n\t\t\t\t}));\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check for index.ts or index.js\n\tconst indexTs = path.join(dir, \"index.ts\");\n\tconst indexJs = path.join(dir, \"index.js\");\n\tif (fs.existsSync(indexTs)) {\n\t\treturn [{ path: indexTs }];\n\t}\n\tif (fs.existsSync(indexJs)) {\n\t\treturn [{ path: indexJs }];\n\t}\n\n\treturn null;\n}\n\n/**\n * Discover extensions in a directory.\n *\n * Discovery rules:\n * 1. Direct files: `extensions/*.ts` or `*.js` → load\n * 2. Subdirectory with index: `extensions/* /index.ts` or `index.js` → load\n * 3. Subdirectory with package.json: `extensions/* /package.json` with \"pi\" field → load what it declares\n *\n * No recursion beyond one level. Complex packages must use package.json manifest.\n */\nfunction discoverExtensionsInDir(dir: string): ExtensionLoadSpec[] {\n\tif (!fs.existsSync(dir)) {\n\t\treturn [];\n\t}\n\n\tconst discovered: ExtensionLoadSpec[] = [];\n\n\ttry {\n\t\tconst entries = fs.readdirSync(dir, { withFileTypes: true });\n\n\t\tfor (const entry of entries) {\n\t\t\tconst entryPath = path.join(dir, entry.name);\n\n\t\t\t// 1. Direct files: *.ts or *.js\n\t\t\tif ((entry.isFile() || entry.isSymbolicLink()) && isExtensionFile(entry.name)) {\n\t\t\t\tdiscovered.push({ path: entryPath });\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// 2 & 3. Subdirectories\n\t\t\tif (entry.isDirectory() || entry.isSymbolicLink()) {\n\t\t\t\tconst entries = resolveExtensionEntries(entryPath);\n\t\t\t\tif (entries) {\n\t\t\t\t\tdiscovered.push(...entries);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch {\n\t\treturn [];\n\t}\n\n\treturn discovered;\n}\n\n/**\n * Discover and load extensions from standard locations.\n */\nexport async function discoverAndLoadExtensions(\n\tconfiguredPaths: string[],\n\tcwd: string,\n\tagentDir: string = getAgentDir(),\n\teventBus?: EventBus,\n): Promise<LoadExtensionsResult> {\n\tconst resolvedCwd = resolvePath(cwd);\n\tconst resolvedAgentDir = resolvePath(agentDir);\n\tconst allPaths: ExtensionLoadSpec[] = [];\n\tconst seen = new Set<string>();\n\n\tconst addPaths = (paths: Array<string | ExtensionLoadSpec>) => {\n\t\tfor (const spec of paths) {\n\t\t\tconst normalized = typeof spec === \"string\" ? { path: spec } : spec;\n\t\t\tconst resolved = path.resolve(normalized.path);\n\t\t\tif (!seen.has(resolved)) {\n\t\t\t\tseen.add(resolved);\n\t\t\t\tallPaths.push(normalized);\n\t\t\t}\n\t\t}\n\t};\n\n\t// 1. Project-local extensions: cwd/${CONFIG_DIR_NAME}/extensions/\n\tconst localExtDir = path.join(resolvedCwd, CONFIG_DIR_NAME, \"extensions\");\n\taddPaths(discoverExtensionsInDir(localExtDir));\n\n\t// 2. Global extensions: agentDir/extensions/\n\tconst globalExtDir = path.join(resolvedAgentDir, \"extensions\");\n\taddPaths(discoverExtensionsInDir(globalExtDir));\n\n\t// 3. Explicitly configured paths\n\tfor (const p of configuredPaths) {\n\t\tconst resolved = resolvePath(p, resolvedCwd, { normalizeUnicodeSpaces: true });\n\t\tif (fs.existsSync(resolved) && fs.statSync(resolved).isDirectory()) {\n\t\t\t// Check for package.json with pi manifest or index.ts\n\t\t\tconst entries = resolveExtensionEntries(resolved);\n\t\t\tif (entries) {\n\t\t\t\taddPaths(entries);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// No explicit entries - discover individual files in directory\n\t\t\taddPaths(discoverExtensionsInDir(resolved));\n\t\t\tcontinue;\n\t\t}\n\n\t\taddPaths([resolved]);\n\t}\n\n\treturn loadExtensions(allPaths, resolvedCwd, eventBus);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/core/extensions/loader.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAuBH,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAIhE,OAAO,KAAK,EACX,SAAS,EAET,gBAAgB,EAChB,gBAAgB,EAChB,oBAAoB,EAKpB,MAAM,YAAY,CAAC;AA6HpB;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,gBAAgB,CAuDzD;AAgPD;;;;;GAKG;AACH,wBAAsB,kCAAkC,CAAC,UAAU,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAyB/F;AAED,wBAAsB,aAAa,CAClC,aAAa,EAAE,MAAM,EACrB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,gBAAgB,EACzB,IAAI,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GACxB,OAAO,CAAC;IAAE,SAAS,EAAE,SAAS,GAAG,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,CAuBhE;AA+FD;;GAEG;AACH,wBAAsB,wBAAwB,CAC7C,OAAO,EAAE,gBAAgB,EACzB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,gBAAgB,EACzB,aAAa,SAAa,GACxB,OAAO,CAAC,SAAS,CAAC,CAWpB;AAED;;GAEG;AACH,wBAAsB,cAAc,CACnC,KAAK,EAAE,KAAK,CAAC,MAAM,GAAG,iBAAiB,CAAC,EACxC,GAAG,EAAE,MAAM,EACX,QAAQ,CAAC,EAAE,QAAQ,GACjB,OAAO,CAAC,oBAAoB,CAAC,CA0C/B;AAED,UAAU,gBAAgB;IACzB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,8FAA8F;IAC9F,SAAS,CAAC,EAAE,OAAO,CAAC;CACpB;AAaD,UAAU,iBAAiB;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,gBAAgB,EAAE,CAAC;CAC/B;AA2ID;;GAEG;AACH,wBAAsB,yBAAyB,CAC9C,eAAe,EAAE,MAAM,EAAE,EACzB,GAAG,EAAE,MAAM,EACX,QAAQ,GAAE,MAAsB,EAChC,QAAQ,CAAC,EAAE,QAAQ,GACjB,OAAO,CAAC,oBAAoB,CAAC,CA4C/B","sourcesContent":["/**\n * Extension loader - loads TypeScript extension modules using jiti.\n *\n */\n\nimport * as fs from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport * as _bundledPiAgentCore from \"@caupulican/pi-agent-core\";\nimport * as _bundledPiAi from \"@caupulican/pi-ai\";\nimport * as _bundledPiAiOauth from \"@caupulican/pi-ai/oauth\";\nimport type { KeyId } from \"@caupulican/pi-tui\";\nimport * as _bundledPiTui from \"@caupulican/pi-tui\";\nimport { createJiti } from \"jiti/static\";\n// Static imports of packages that extensions may use.\n// These MUST be static so Bun bundles them into the compiled binary.\n// The virtualModules option then makes them available to extensions.\nimport * as _bundledTypebox from \"typebox\";\nimport * as _bundledTypeboxCompile from \"typebox/compile\";\nimport * as _bundledTypeboxValue from \"typebox/value\";\nimport { CONFIG_DIR_NAME, getAgentDir, isBunBinary } from \"../../config.ts\";\n// NOTE: This import works because loader.ts exports are NOT re-exported from index.ts,\n// avoiding a circular dependency. Extensions can import from @caupulican/pi-adaptative.\nimport * as _bundledPiCodingAgent from \"../../index.ts\";\nimport { resolvePath } from \"../../utils/paths.ts\";\nimport { createEventBus, type EventBus } from \"../event-bus.ts\";\nimport type { ExecOptions } from \"../exec.ts\";\nimport { execCommand } from \"../exec.ts\";\nimport { createSyntheticSourceInfo } from \"../source-info.ts\";\nimport type {\n\tExtension,\n\tExtensionAPI,\n\tExtensionFactory,\n\tExtensionRuntime,\n\tLoadExtensionsResult,\n\tMessageRenderer,\n\tProviderConfig,\n\tRegisteredCommand,\n\tToolDefinition,\n} from \"./types.ts\";\n\n/** Modules available to extensions via virtualModules (for compiled Bun binary) */\nconst VIRTUAL_MODULES: Record<string, unknown> = {\n\ttypebox: _bundledTypebox,\n\t\"typebox/compile\": _bundledTypeboxCompile,\n\t\"typebox/value\": _bundledTypeboxValue,\n\t\"@sinclair/typebox\": _bundledTypebox,\n\t\"@sinclair/typebox/compile\": _bundledTypeboxCompile,\n\t\"@sinclair/typebox/value\": _bundledTypeboxValue,\n\t\"@caupulican/pi-agent-core\": _bundledPiAgentCore,\n\t\"@caupulican/pi-tui\": _bundledPiTui,\n\t\"@caupulican/pi-ai\": _bundledPiAi,\n\t\"@caupulican/pi-ai/oauth\": _bundledPiAiOauth,\n\t\"@caupulican/pi-adaptative\": _bundledPiCodingAgent,\n\t\"@earendil-works/pi-agent-core\": _bundledPiAgentCore,\n\t\"@earendil-works/pi-tui\": _bundledPiTui,\n\t\"@earendil-works/pi-ai\": _bundledPiAi,\n\t\"@earendil-works/pi-ai/oauth\": _bundledPiAiOauth,\n\t\"@earendil-works/pi-coding-agent\": _bundledPiCodingAgent,\n\t\"@mariozechner/pi-agent-core\": _bundledPiAgentCore,\n\t\"@mariozechner/pi-tui\": _bundledPiTui,\n\t\"@mariozechner/pi-ai\": _bundledPiAi,\n\t\"@mariozechner/pi-ai/oauth\": _bundledPiAiOauth,\n\t\"@mariozechner/pi-coding-agent\": _bundledPiCodingAgent,\n};\n\nfunction uniquePaths(paths: string[]): string[] {\n\treturn [...new Set(paths)];\n}\n\nfunction safeRealpath(filePath: string): string {\n\ttry {\n\t\treturn fs.realpathSync(filePath);\n\t} catch {\n\t\treturn filePath;\n\t}\n}\n\n/**\n * Get aliases for jiti (used in Node.js/development mode).\n * In Bun binary mode, virtualModules is used instead.\n */\nlet _aliases: Record<string, string> | null = null;\n\nfunction getAliases(): Record<string, string> {\n\tif (_aliases) return _aliases;\n\n\tconst loaderFile = fileURLToPath(import.meta.url);\n\tconst realLoaderFile = safeRealpath(loaderFile);\n\tconst __dirname = path.dirname(loaderFile);\n\tconst realDirname = path.dirname(realLoaderFile);\n\tconst packageIndex = path.resolve(__dirname, \"../..\", \"index.js\");\n\n\tconst moduleRequires = uniquePaths([loaderFile, realLoaderFile]).map((file) => createRequire(file));\n\tconst resolveModule = (specifier: string): string => {\n\t\tfor (const moduleRequire of moduleRequires) {\n\t\t\ttry {\n\t\t\t\treturn moduleRequire.resolve(specifier);\n\t\t\t} catch {\n\t\t\t\t// Try the next resolution base. Linked global installs may resolve the\n\t\t\t\t// loader through the global symlink path while workspace dependencies are\n\t\t\t\t// hoisted beside the real source path.\n\t\t\t}\n\t\t}\n\t\treturn fileURLToPath(import.meta.resolve(specifier));\n\t};\n\n\tconst typeboxEntry = resolveModule(\"typebox\");\n\tconst typeboxCompileEntry = resolveModule(\"typebox/compile\");\n\tconst typeboxValueEntry = resolveModule(\"typebox/value\");\n\n\tconst packagesRoots = uniquePaths([\n\t\tpath.resolve(__dirname, \"../../../../\"),\n\t\tpath.resolve(realDirname, \"../../../../\"),\n\t]);\n\tconst resolveWorkspaceOrImport = (workspaceRelativePath: string, specifier: string): string => {\n\t\tfor (const packagesRoot of packagesRoots) {\n\t\t\tconst workspacePath = path.join(packagesRoot, workspaceRelativePath);\n\t\t\tif (fs.existsSync(workspacePath)) {\n\t\t\t\treturn workspacePath;\n\t\t\t}\n\t\t}\n\t\treturn resolveModule(specifier);\n\t};\n\n\tconst piCodingAgentEntry = packageIndex;\n\tconst piAgentCoreEntry = resolveWorkspaceOrImport(\"agent/dist/index.js\", \"@caupulican/pi-agent-core\");\n\tconst piTuiEntry = resolveWorkspaceOrImport(\"tui/dist/index.js\", \"@caupulican/pi-tui\");\n\tconst piAiEntry = resolveWorkspaceOrImport(\"ai/dist/index.js\", \"@caupulican/pi-ai\");\n\tconst piAiOauthEntry = resolveWorkspaceOrImport(\"ai/dist/oauth.js\", \"@caupulican/pi-ai/oauth\");\n\n\t_aliases = {\n\t\t\"@caupulican/pi-adaptative\": piCodingAgentEntry,\n\t\t\"@caupulican/pi-agent-core\": piAgentCoreEntry,\n\t\t\"@caupulican/pi-tui\": piTuiEntry,\n\t\t\"@caupulican/pi-ai\": piAiEntry,\n\t\t\"@caupulican/pi-ai/oauth\": piAiOauthEntry,\n\t\t\"@earendil-works/pi-coding-agent\": piCodingAgentEntry,\n\t\t\"@earendil-works/pi-agent-core\": piAgentCoreEntry,\n\t\t\"@earendil-works/pi-tui\": piTuiEntry,\n\t\t\"@earendil-works/pi-ai\": piAiEntry,\n\t\t\"@earendil-works/pi-ai/oauth\": piAiOauthEntry,\n\t\t\"@mariozechner/pi-coding-agent\": piCodingAgentEntry,\n\t\t\"@mariozechner/pi-agent-core\": piAgentCoreEntry,\n\t\t\"@mariozechner/pi-tui\": piTuiEntry,\n\t\t\"@mariozechner/pi-ai\": piAiEntry,\n\t\t\"@mariozechner/pi-ai/oauth\": piAiOauthEntry,\n\t\ttypebox: typeboxEntry,\n\t\t\"typebox/compile\": typeboxCompileEntry,\n\t\t\"typebox/value\": typeboxValueEntry,\n\t\t\"@sinclair/typebox\": typeboxEntry,\n\t\t\"@sinclair/typebox/compile\": typeboxCompileEntry,\n\t\t\"@sinclair/typebox/value\": typeboxValueEntry,\n\t};\n\n\treturn _aliases;\n}\n\ntype HandlerFn = (...args: unknown[]) => Promise<unknown>;\n\nfunction yieldToEventLoop(): Promise<void> {\n\treturn new Promise((resolve) => setImmediate(resolve));\n}\n\n/**\n * Create a runtime with throwing stubs for action methods.\n * Runner.bindCore() replaces these with real implementations.\n */\nexport function createExtensionRuntime(): ExtensionRuntime {\n\tconst notInitialized = () => {\n\t\tthrow new Error(\"Extension runtime not initialized. Action methods cannot be called during extension loading.\");\n\t};\n\tconst state: { staleMessage?: string } = {};\n\tconst assertActive = () => {\n\t\tif (state.staleMessage) {\n\t\t\tthrow new Error(state.staleMessage);\n\t\t}\n\t};\n\n\tconst providersByExtension = new Map<string, Set<string>>();\n\n\tconst runtime: ExtensionRuntime = {\n\t\tsendMessage: notInitialized,\n\t\tsendUserMessage: notInitialized,\n\t\tappendEntry: notInitialized,\n\t\tsetSessionName: notInitialized,\n\t\tgetSessionName: notInitialized,\n\t\tsetLabel: notInitialized,\n\t\tgetActiveTools: notInitialized,\n\t\tgetAllTools: notInitialized,\n\t\tsetActiveTools: notInitialized,\n\t\t// registerTool() is valid during extension load; refresh is only needed post-bind.\n\t\trefreshTools: () => {},\n\t\tgetCommands: notInitialized,\n\t\tsetModel: () => Promise.reject(new Error(\"Extension runtime not initialized\")),\n\t\tgetThinkingLevel: notInitialized,\n\t\tsetThinkingLevel: notInitialized,\n\t\tgetExternalResourceRoots: notInitialized,\n\t\tregisterMemoryProvider: notInitialized,\n\t\treportSpawnedUsage: notInitialized,\n\t\tflagValues: new Map(),\n\t\tpendingProviderRegistrations: [],\n\t\tassertActive,\n\t\tinvalidate: (message) => {\n\t\t\tstate.staleMessage ??=\n\t\t\t\tmessage ??\n\t\t\t\t\"This extension ctx is stale after session replacement or reload. Do not use a captured pi or command ctx after ctx.newSession(), ctx.fork(), ctx.switchSession(), or ctx.reload(). For newSession, fork, and switchSession, move post-replacement work into withSession and use the ctx passed to withSession. For reload, do not use the old ctx after await ctx.reload().\";\n\t\t},\n\t\t// Pre-bind: queue registrations so bindCore() can flush them once the\n\t\t// model registry is available. bindCore() replaces both with direct calls.\n\t\tregisterProvider: (name, config, extensionPath = \"<unknown>\") => {\n\t\t\truntime.pendingProviderRegistrations.push({ name, config, extensionPath });\n\t\t},\n\t\tunregisterProvider: (name) => {\n\t\t\truntime.pendingProviderRegistrations = runtime.pendingProviderRegistrations.filter((r) => r.name !== name);\n\t\t},\n\t\tprovidersByExtension,\n\t\tgetProvidersForExtension: (extensionPath: string) => {\n\t\t\treturn [...(providersByExtension.get(extensionPath) ?? [])];\n\t\t},\n\t};\n\n\treturn runtime;\n}\n\n/**\n * Create the ExtensionAPI for an extension.\n * Registration methods write to the extension object.\n * Action methods delegate to the shared runtime.\n */\nfunction createExtensionAPI(\n\textension: Extension,\n\truntime: ExtensionRuntime,\n\tcwd: string,\n\teventBus: EventBus,\n): ExtensionAPI {\n\tconst api = {\n\t\t// Registration methods - write to extension\n\t\ton(event: string, handler: HandlerFn): void {\n\t\t\truntime.assertActive();\n\t\t\tconst list = extension.handlers.get(event) ?? [];\n\t\t\tlist.push(handler);\n\t\t\textension.handlers.set(event, list);\n\t\t},\n\n\t\tregisterTool(tool: ToolDefinition): void {\n\t\t\truntime.assertActive();\n\t\t\textension.tools.set(tool.name, {\n\t\t\t\tdefinition: tool,\n\t\t\t\tsourceInfo: extension.sourceInfo,\n\t\t\t});\n\t\t\truntime.refreshTools();\n\t\t},\n\n\t\tregisterCommand(name: string, options: Omit<RegisteredCommand, \"name\" | \"sourceInfo\">): void {\n\t\t\truntime.assertActive();\n\t\t\textension.commands.set(name, {\n\t\t\t\tname,\n\t\t\t\tsourceInfo: extension.sourceInfo,\n\t\t\t\t...options,\n\t\t\t});\n\t\t},\n\n\t\tregisterShortcut(\n\t\t\tshortcut: KeyId,\n\t\t\toptions: {\n\t\t\t\tdescription?: string;\n\t\t\t\thandler: (ctx: import(\"./types.ts\").ExtensionContext) => Promise<void> | void;\n\t\t\t},\n\t\t): void {\n\t\t\truntime.assertActive();\n\t\t\textension.shortcuts.set(shortcut, { shortcut, extensionPath: extension.path, ...options });\n\t\t},\n\n\t\tregisterFlag(\n\t\t\tname: string,\n\t\t\toptions: { description?: string; type: \"boolean\" | \"string\"; default?: boolean | string },\n\t\t): void {\n\t\t\truntime.assertActive();\n\t\t\textension.flags.set(name, { name, extensionPath: extension.path, ...options });\n\t\t\tif (options.default !== undefined && !runtime.flagValues.has(name)) {\n\t\t\t\truntime.flagValues.set(name, options.default);\n\t\t\t}\n\t\t},\n\n\t\tregisterMessageRenderer<T>(customType: string, renderer: MessageRenderer<T>): void {\n\t\t\truntime.assertActive();\n\t\t\textension.messageRenderers.set(customType, renderer as MessageRenderer);\n\t\t},\n\n\t\t// Flag access - checks extension registered it, reads from runtime\n\t\tgetFlag(name: string): boolean | string | undefined {\n\t\t\truntime.assertActive();\n\t\t\tif (!extension.flags.has(name)) return undefined;\n\t\t\treturn runtime.flagValues.get(name);\n\t\t},\n\n\t\t// Action methods - delegate to shared runtime\n\t\tsendMessage(message, options): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.sendMessage(message, options);\n\t\t},\n\n\t\tsendUserMessage(content, options): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.sendUserMessage(content, options);\n\t\t},\n\n\t\tappendEntry(customType: string, data?: unknown): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.appendEntry(customType, data);\n\t\t},\n\n\t\tsetSessionName(name: string): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.setSessionName(name);\n\t\t},\n\n\t\tgetSessionName(): string | undefined {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getSessionName();\n\t\t},\n\n\t\tsetLabel(entryId: string, label: string | undefined): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.setLabel(entryId, label);\n\t\t},\n\n\t\texec(command: string, args: string[], options?: ExecOptions) {\n\t\t\truntime.assertActive();\n\t\t\treturn execCommand(command, args, options?.cwd ?? cwd, options);\n\t\t},\n\n\t\tgetActiveTools(): string[] {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getActiveTools();\n\t\t},\n\n\t\tgetAllTools() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getAllTools();\n\t\t},\n\n\t\tsetActiveTools(toolNames: string[]): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.setActiveTools(toolNames);\n\t\t},\n\n\t\tgetCommands() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getCommands();\n\t\t},\n\n\t\tgetExternalResourceRoots() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getExternalResourceRoots();\n\t\t},\n\n\t\tregisterMemoryProvider(provider) {\n\t\t\truntime.assertActive();\n\t\t\truntime.registerMemoryProvider(provider);\n\t\t},\n\n\t\treportSpawnedUsage(usage, opts) {\n\t\t\truntime.assertActive();\n\t\t\truntime.reportSpawnedUsage(usage, opts);\n\t\t},\n\n\t\tsetModel(model) {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.setModel(model);\n\t\t},\n\n\t\tgetThinkingLevel() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getThinkingLevel();\n\t\t},\n\n\t\tsetThinkingLevel(level) {\n\t\t\truntime.assertActive();\n\t\t\truntime.setThinkingLevel(level);\n\t\t},\n\n\t\tregisterProvider(name: string, config: ProviderConfig) {\n\t\t\truntime.assertActive();\n\t\t\truntime.registerProvider(name, config, extension.path);\n\t\t},\n\n\t\tunregisterProvider(name: string) {\n\t\t\truntime.assertActive();\n\t\t\truntime.unregisterProvider(name, extension.path);\n\t\t},\n\n\t\tonDispose(fn: () => void | Promise<void>): void {\n\t\t\truntime.assertActive();\n\t\t\textension.disposers.push(fn);\n\t\t},\n\n\t\t// Track bus subscriptions per extension generation so hot reloads can\n\t\t// unsubscribe replaced generations (see disposeExtensionEventSubscriptions).\n\t\tevents: {\n\t\t\temit: (channel: string, data: unknown) => {\n\t\t\t\truntime.assertActive();\n\t\t\t\teventBus.emit(channel, data);\n\t\t\t},\n\t\t\ton: (channel: string, handler: (data: unknown) => void) => {\n\t\t\t\truntime.assertActive();\n\t\t\t\tconst unsubscribe = eventBus.on(channel, handler);\n\t\t\t\textension.eventUnsubscribes.push(unsubscribe);\n\t\t\t\treturn unsubscribe;\n\t\t\t},\n\t\t},\n\t} as ExtensionAPI;\n\n\treturn api;\n}\n\nasync function loadExtensionModule(extensionPath: string, opts?: { fresh?: boolean }) {\n\tconst jiti = createJiti(import.meta.url, {\n\t\tmoduleCache: false,\n\t\t// In Bun binary: use virtualModules for bundled packages (no filesystem resolution)\n\t\t// Also disable tryNative so jiti handles ALL imports (not just the entry point)\n\t\t// In Node.js/dev: use aliases to resolve to node_modules paths\n\t\t...(isBunBinary ? { virtualModules: VIRTUAL_MODULES, tryNative: false } : { alias: getAliases() }),\n\t});\n\n\t// When fresh mode is enabled, append a cache-busting query string to force re-import\n\tlet resolvedPath = extensionPath;\n\tif (opts?.fresh) {\n\t\tconst separator = extensionPath.includes(\"?\") ? \"&\" : \"?\";\n\t\tresolvedPath = `${extensionPath}${separator}fresh=${Date.now()}`;\n\t}\n\n\tconst module = await jiti.import(resolvedPath, { default: true });\n\tconst factory = module as ExtensionFactory;\n\treturn typeof factory !== \"function\" ? undefined : factory;\n}\n\n/**\n * Create an Extension object with empty collections.\n */\nfunction createExtension(extensionPath: string, resolvedPath: string): Extension {\n\tconst source =\n\t\textensionPath.startsWith(\"<\") && extensionPath.endsWith(\">\")\n\t\t\t? extensionPath.slice(1, -1).split(\":\")[0] || \"temporary\"\n\t\t\t: \"local\";\n\tconst baseDir = extensionPath.startsWith(\"<\") ? undefined : path.dirname(resolvedPath);\n\n\treturn {\n\t\tpath: extensionPath,\n\t\tresolvedPath,\n\t\tsourceInfo: createSyntheticSourceInfo(extensionPath, { source, baseDir }),\n\t\thandlers: new Map(),\n\t\ttools: new Map(),\n\t\tmessageRenderers: new Map(),\n\t\tcommands: new Map(),\n\t\tflags: new Map(),\n\t\tshortcuts: new Map(),\n\t\teventUnsubscribes: [],\n\t\tdisposers: [],\n\t};\n}\n\n/**\n * Unsubscribe a replaced extension generation's pi.events handlers from the shared\n * event bus and invoke cleanup callbacks. Without this, every hot reload leaves the\n * previous generation's handlers subscribed, pinning the old module graph in memory\n * and double-processing events.\n */\nexport async function disposeExtensionEventSubscriptions(extensions: Extension[]): Promise<void> {\n\tfor (const extension of extensions) {\n\t\t// Unsubscribe event listeners\n\t\tfor (const unsubscribe of extension.eventUnsubscribes) {\n\t\t\ttry {\n\t\t\t\tunsubscribe();\n\t\t\t} catch {\n\t\t\t\t// Disposal must never break a reload.\n\t\t\t}\n\t\t}\n\t\textension.eventUnsubscribes.length = 0;\n\n\t\t// Invoke cleanup callbacks\n\t\tfor (const disposer of extension.disposers) {\n\t\t\ttry {\n\t\t\t\tconst result = disposer();\n\t\t\t\tif (result instanceof Promise) {\n\t\t\t\t\tawait result;\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Disposal must never break a reload.\n\t\t\t}\n\t\t}\n\t\textension.disposers.length = 0;\n\t}\n}\n\nexport async function loadExtension(\n\textensionPath: string,\n\tcwd: string,\n\teventBus: EventBus,\n\truntime: ExtensionRuntime,\n\topts?: { fresh?: boolean },\n): Promise<{ extension: Extension | null; error: string | null }> {\n\tconst resolvedPath = resolvePath(extensionPath, cwd, { normalizeUnicodeSpaces: true });\n\n\ttry {\n\t\tconst factory = await loadExtensionModule(resolvedPath, opts);\n\t\tif (!factory) {\n\t\t\treturn { extension: null, error: `Extension does not export a valid factory function: ${extensionPath}` };\n\t\t}\n\n\t\tconst extension = createExtension(extensionPath, resolvedPath);\n\t\tconst api = createExtensionAPI(extension, runtime, cwd, eventBus);\n\t\ttry {\n\t\t\tawait factory(api);\n\t\t} catch (err) {\n\t\t\tawait disposeExtensionEventSubscriptions([extension]);\n\t\t\tthrow err;\n\t\t}\n\n\t\treturn { extension, error: null };\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\treturn { extension: null, error: `Failed to load extension: ${message}` };\n\t}\n}\n\nfunction createLazyToolDefinition(\n\textension: Extension,\n\tmanifest: LazyToolManifest,\n\tload: () => Promise<void>,\n): ToolDefinition {\n\tconst name = String(manifest.name).trim();\n\tconst definition: ToolDefinition = {\n\t\tname,\n\t\tlabel: typeof manifest.label === \"string\" && manifest.label.trim() ? manifest.label : name,\n\t\tdescription:\n\t\t\ttypeof manifest.description === \"string\" && manifest.description.trim()\n\t\t\t\t? manifest.description\n\t\t\t\t: `Lazy extension tool ${name}`,\n\t\tparameters: (manifest.parameters ?? defaultLazyToolParameters()) as ToolDefinition[\"parameters\"],\n\t\tpromptSnippet: typeof manifest.promptSnippet === \"string\" ? manifest.promptSnippet : undefined,\n\t\tpromptGuidelines: Array.isArray(manifest.promptGuidelines)\n\t\t\t? manifest.promptGuidelines.filter((item): item is string => typeof item === \"string\")\n\t\t\t: undefined,\n\t\ttoolGroup: typeof manifest.toolGroup === \"string\" ? manifest.toolGroup : undefined,\n\t\texecutionMode:\n\t\t\tmanifest.executionMode === \"parallel\" || manifest.executionMode === \"sequential\"\n\t\t\t\t? manifest.executionMode\n\t\t\t\t: undefined,\n\t\texecute: async (toolCallId, params, signal, onUpdate, ctx) => {\n\t\t\tawait load();\n\t\t\tconst loadedDefinition = extension.tools.get(name)?.definition;\n\t\t\tif (!loadedDefinition || loadedDefinition === definition) {\n\t\t\t\tthrow new Error(`Lazy extension ${extension.path} did not register tool ${name}`);\n\t\t\t}\n\t\t\treturn loadedDefinition.execute(toolCallId, params, signal, onUpdate, ctx);\n\t\t},\n\t};\n\treturn definition;\n}\n\nfunction createLazyExtension(\n\textensionPath: string,\n\tresolvedPath: string,\n\tcwd: string,\n\teventBus: EventBus,\n\truntime: ExtensionRuntime,\n\tlazyTools: LazyToolManifest[],\n): Extension {\n\tconst extension = createExtension(extensionPath, resolvedPath);\n\tlet restoreLazyToolPlaceholders = (): void => {};\n\tconst load = async (): Promise<void> => {\n\t\tif (extension.lazy?.loaded) return;\n\t\tif (extension.lazy?.loading) return extension.lazy.loading;\n\n\t\tconst loading = (async () => {\n\t\t\tconst factory = await loadExtensionModule(resolvedPath);\n\t\t\tif (!factory) {\n\t\t\t\tthrow new Error(`Extension does not export a valid factory function: ${extensionPath}`);\n\t\t\t}\n\t\t\tconst api = createExtensionAPI(extension, runtime, cwd, eventBus);\n\t\t\tawait factory(api);\n\t\t\tif (extension.lazy) {\n\t\t\t\textension.lazy.loaded = true;\n\t\t\t\textension.lazy.loading = undefined;\n\t\t\t}\n\t\t})();\n\n\t\tif (extension.lazy) extension.lazy.loading = loading;\n\t\ttry {\n\t\t\tawait loading;\n\t\t} catch (err) {\n\t\t\tawait disposeExtensionEventSubscriptions([extension]);\n\t\t\textension.handlers.clear();\n\t\t\textension.messageRenderers.clear();\n\t\t\textension.commands.clear();\n\t\t\textension.flags.clear();\n\t\t\textension.shortcuts.clear();\n\t\t\textension.tools.clear();\n\t\t\trestoreLazyToolPlaceholders();\n\t\t\tif (extension.lazy) extension.lazy.loading = undefined;\n\t\t\tthrow err;\n\t\t}\n\t};\n\n\textension.lazy = { loaded: false, load };\n\trestoreLazyToolPlaceholders = () => {\n\t\tfor (const tool of lazyTools) {\n\t\t\tconst name = String(tool.name).trim();\n\t\t\textension.tools.set(name, {\n\t\t\t\tdefinition: createLazyToolDefinition(extension, tool, load),\n\t\t\t\tsourceInfo: extension.sourceInfo,\n\t\t\t});\n\t\t}\n\t};\n\trestoreLazyToolPlaceholders();\n\treturn extension;\n}\n\n/**\n * Create an Extension from an inline factory function.\n */\nexport async function loadExtensionFromFactory(\n\tfactory: ExtensionFactory,\n\tcwd: string,\n\teventBus: EventBus,\n\truntime: ExtensionRuntime,\n\textensionPath = \"<inline>\",\n): Promise<Extension> {\n\tconst extension = createExtension(extensionPath, extensionPath);\n\tconst resolvedCwd = resolvePath(cwd);\n\tconst api = createExtensionAPI(extension, runtime, resolvedCwd, eventBus);\n\ttry {\n\t\tawait factory(api);\n\t} catch (err) {\n\t\tawait disposeExtensionEventSubscriptions([extension]);\n\t\tthrow err;\n\t}\n\treturn extension;\n}\n\n/**\n * Load extensions from paths.\n */\nexport async function loadExtensions(\n\tpaths: Array<string | ExtensionLoadSpec>,\n\tcwd: string,\n\teventBus?: EventBus,\n): Promise<LoadExtensionsResult> {\n\tconst extensions: Extension[] = [];\n\tconst errors: Array<{ path: string; error: string }> = [];\n\tconst resolvedCwd = resolvePath(cwd);\n\tconst resolvedEventBus = eventBus ?? createEventBus();\n\tconst runtime = createExtensionRuntime();\n\n\tfor (const spec of paths) {\n\t\tconst normalized = typeof spec === \"string\" ? { path: spec } : spec;\n\t\tconst extPath = normalized.path;\n\t\tconst resolvedPath = resolvePath(extPath, resolvedCwd, { normalizeUnicodeSpaces: true });\n\t\tconst lazyTools = (normalized.lazyTools ?? inferLazyToolsForExtensionPath(resolvedPath))?.filter(\n\t\t\t(tool) => typeof tool.name === \"string\" && tool.name.trim(),\n\t\t);\n\t\t// Extension imports can be CPU-heavy under jiti. Yield around each load so\n\t\t// interactive reloads can repaint/status-update instead of freezing the TUI\n\t\t// for the whole extension set. Lazy tool manifests skip import entirely here.\n\t\tawait yieldToEventLoop();\n\t\tif (lazyTools?.length) {\n\t\t\textensions.push(createLazyExtension(extPath, resolvedPath, resolvedCwd, resolvedEventBus, runtime, lazyTools));\n\t\t\tawait yieldToEventLoop();\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst { extension, error } = await loadExtension(extPath, resolvedCwd, resolvedEventBus, runtime);\n\t\tawait yieldToEventLoop();\n\n\t\tif (error) {\n\t\t\terrors.push({ path: extPath, error });\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (extension) {\n\t\t\textensions.push(extension);\n\t\t}\n\t}\n\n\treturn {\n\t\textensions,\n\t\terrors,\n\t\truntime,\n\t};\n}\n\ninterface LazyToolManifest {\n\tname?: unknown;\n\tlabel?: unknown;\n\tdescription?: unknown;\n\tparameters?: unknown;\n\tpromptSnippet?: unknown;\n\tpromptGuidelines?: unknown;\n\ttoolGroup?: unknown;\n\texecutionMode?: unknown;\n\t/** Optional extension entry this tool belongs to when a package declares multiple entries. */\n\textension?: unknown;\n}\n\ninterface PiManifest {\n\textensions?: string[];\n\tthemes?: string[];\n\tskills?: string[];\n\tprompts?: string[];\n\t/** Tool metadata for opt-in lazy extension loading. Factories stay unloaded until one of these tools runs. */\n\tlazyTools?: LazyToolManifest[];\n\t/** Alternate nested spelling: { tools: [...] }. */\n\tlazy?: { tools?: LazyToolManifest[] } | boolean;\n}\n\ninterface ExtensionLoadSpec {\n\tpath: string;\n\tlazyTools?: LazyToolManifest[];\n}\n\nfunction getManifestLazyTools(manifest: PiManifest | null): LazyToolManifest[] | undefined {\n\tif (!manifest) return undefined;\n\tconst tools = Array.isArray(manifest.lazyTools)\n\t\t? manifest.lazyTools\n\t\t: typeof manifest.lazy === \"object\" && Array.isArray(manifest.lazy.tools)\n\t\t\t? manifest.lazy.tools\n\t\t\t: undefined;\n\treturn tools?.filter((tool) => tool && typeof tool.name === \"string\" && tool.name.trim());\n}\n\nfunction defaultLazyToolParameters(): ToolDefinition[\"parameters\"] {\n\treturn { type: \"object\", properties: {}, additionalProperties: false } as ToolDefinition[\"parameters\"];\n}\n\nfunction lazyToolsForEntry(tools: LazyToolManifest[] | undefined, dir: string, entryPath: string, entryCount: number) {\n\tif (!tools?.length) return undefined;\n\tconst selected = tools.filter((tool) => {\n\t\tif (typeof tool.extension !== \"string\" || !tool.extension.trim()) {\n\t\t\treturn entryCount === 1;\n\t\t}\n\t\treturn path.resolve(dir, tool.extension) === entryPath;\n\t});\n\treturn selected.length > 0 ? selected : undefined;\n}\n\nfunction inferLazyToolsForExtensionPath(resolvedPath: string): LazyToolManifest[] | undefined {\n\tconst dir = path.dirname(resolvedPath);\n\tconst manifest = readPiManifest(path.join(dir, \"package.json\"));\n\tconst lazyTools = getManifestLazyTools(manifest);\n\tif (!manifest?.extensions?.length || !lazyTools?.length) return undefined;\n\tconst resolvedEntries = manifest.extensions.map((extPath) => path.resolve(dir, extPath));\n\tif (!resolvedEntries.includes(resolvedPath)) return undefined;\n\treturn lazyToolsForEntry(lazyTools, dir, resolvedPath, resolvedEntries.length);\n}\n\nfunction readPiManifest(packageJsonPath: string): PiManifest | null {\n\ttry {\n\t\tconst content = fs.readFileSync(packageJsonPath, \"utf-8\");\n\t\tconst pkg = JSON.parse(content);\n\t\tif (pkg.pi && typeof pkg.pi === \"object\") {\n\t\t\treturn pkg.pi as PiManifest;\n\t\t}\n\t\treturn null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction isExtensionFile(name: string): boolean {\n\treturn name.endsWith(\".ts\") || name.endsWith(\".js\");\n}\n\n/**\n * Resolve extension entry points from a directory.\n *\n * Checks for:\n * 1. package.json with \"pi.extensions\" field -> returns declared paths\n * 2. index.ts or index.js -> returns the index file\n *\n * Returns resolved paths or null if no entry points found.\n */\nfunction resolveExtensionEntries(dir: string): ExtensionLoadSpec[] | null {\n\t// Check for package.json with \"pi\" field first\n\tconst packageJsonPath = path.join(dir, \"package.json\");\n\tif (fs.existsSync(packageJsonPath)) {\n\t\tconst manifest = readPiManifest(packageJsonPath);\n\t\tif (manifest?.extensions?.length) {\n\t\t\tconst resolvedEntries = manifest.extensions\n\t\t\t\t.map((extPath) => path.resolve(dir, extPath))\n\t\t\t\t.filter((resolvedExtPath) => fs.existsSync(resolvedExtPath));\n\t\t\tif (resolvedEntries.length > 0) {\n\t\t\t\tconst lazyTools = getManifestLazyTools(manifest);\n\t\t\t\treturn resolvedEntries.map((entryPath) => ({\n\t\t\t\t\tpath: entryPath,\n\t\t\t\t\tlazyTools: lazyToolsForEntry(lazyTools, dir, entryPath, resolvedEntries.length),\n\t\t\t\t}));\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check for index.ts or index.js\n\tconst indexTs = path.join(dir, \"index.ts\");\n\tconst indexJs = path.join(dir, \"index.js\");\n\tif (fs.existsSync(indexTs)) {\n\t\treturn [{ path: indexTs }];\n\t}\n\tif (fs.existsSync(indexJs)) {\n\t\treturn [{ path: indexJs }];\n\t}\n\n\treturn null;\n}\n\n/**\n * Discover extensions in a directory.\n *\n * Discovery rules:\n * 1. Direct files: `extensions/*.ts` or `*.js` → load\n * 2. Subdirectory with index: `extensions/* /index.ts` or `index.js` → load\n * 3. Subdirectory with package.json: `extensions/* /package.json` with \"pi\" field → load what it declares\n *\n * No recursion beyond one level. Complex packages must use package.json manifest.\n */\nfunction discoverExtensionsInDir(dir: string): ExtensionLoadSpec[] {\n\tif (!fs.existsSync(dir)) {\n\t\treturn [];\n\t}\n\n\tconst discovered: ExtensionLoadSpec[] = [];\n\n\ttry {\n\t\tconst entries = fs.readdirSync(dir, { withFileTypes: true });\n\n\t\tfor (const entry of entries) {\n\t\t\tconst entryPath = path.join(dir, entry.name);\n\n\t\t\t// 1. Direct files: *.ts or *.js\n\t\t\tif ((entry.isFile() || entry.isSymbolicLink()) && isExtensionFile(entry.name)) {\n\t\t\t\tdiscovered.push({ path: entryPath });\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// 2 & 3. Subdirectories\n\t\t\tif (entry.isDirectory() || entry.isSymbolicLink()) {\n\t\t\t\tconst entries = resolveExtensionEntries(entryPath);\n\t\t\t\tif (entries) {\n\t\t\t\t\tdiscovered.push(...entries);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch {\n\t\treturn [];\n\t}\n\n\treturn discovered;\n}\n\n/**\n * Discover and load extensions from standard locations.\n */\nexport async function discoverAndLoadExtensions(\n\tconfiguredPaths: string[],\n\tcwd: string,\n\tagentDir: string = getAgentDir(),\n\teventBus?: EventBus,\n): Promise<LoadExtensionsResult> {\n\tconst resolvedCwd = resolvePath(cwd);\n\tconst resolvedAgentDir = resolvePath(agentDir);\n\tconst allPaths: ExtensionLoadSpec[] = [];\n\tconst seen = new Set<string>();\n\n\tconst addPaths = (paths: Array<string | ExtensionLoadSpec>) => {\n\t\tfor (const spec of paths) {\n\t\t\tconst normalized = typeof spec === \"string\" ? { path: spec } : spec;\n\t\t\tconst resolved = path.resolve(normalized.path);\n\t\t\tif (!seen.has(resolved)) {\n\t\t\t\tseen.add(resolved);\n\t\t\t\tallPaths.push(normalized);\n\t\t\t}\n\t\t}\n\t};\n\n\t// 1. Project-local extensions: cwd/${CONFIG_DIR_NAME}/extensions/\n\tconst localExtDir = path.join(resolvedCwd, CONFIG_DIR_NAME, \"extensions\");\n\taddPaths(discoverExtensionsInDir(localExtDir));\n\n\t// 2. Global extensions: agentDir/extensions/\n\tconst globalExtDir = path.join(resolvedAgentDir, \"extensions\");\n\taddPaths(discoverExtensionsInDir(globalExtDir));\n\n\t// 3. Explicitly configured paths\n\tfor (const p of configuredPaths) {\n\t\tconst resolved = resolvePath(p, resolvedCwd, { normalizeUnicodeSpaces: true });\n\t\tif (fs.existsSync(resolved) && fs.statSync(resolved).isDirectory()) {\n\t\t\t// Check for package.json with pi manifest or index.ts\n\t\t\tconst entries = resolveExtensionEntries(resolved);\n\t\t\tif (entries) {\n\t\t\t\taddPaths(entries);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// No explicit entries - discover individual files in directory\n\t\t\taddPaths(discoverExtensionsInDir(resolved));\n\t\t\tcontinue;\n\t\t}\n\n\t\taddPaths([resolved]);\n\t}\n\n\treturn loadExtensions(allPaths, resolvedCwd, eventBus);\n}\n"]}
|
|
@@ -425,7 +425,13 @@ export async function loadExtension(extensionPath, cwd, eventBus, runtime, opts)
|
|
|
425
425
|
}
|
|
426
426
|
const extension = createExtension(extensionPath, resolvedPath);
|
|
427
427
|
const api = createExtensionAPI(extension, runtime, cwd, eventBus);
|
|
428
|
-
|
|
428
|
+
try {
|
|
429
|
+
await factory(api);
|
|
430
|
+
}
|
|
431
|
+
catch (err) {
|
|
432
|
+
await disposeExtensionEventSubscriptions([extension]);
|
|
433
|
+
throw err;
|
|
434
|
+
}
|
|
429
435
|
return { extension, error: null };
|
|
430
436
|
}
|
|
431
437
|
catch (err) {
|
|
@@ -463,6 +469,7 @@ function createLazyToolDefinition(extension, manifest, load) {
|
|
|
463
469
|
}
|
|
464
470
|
function createLazyExtension(extensionPath, resolvedPath, cwd, eventBus, runtime, lazyTools) {
|
|
465
471
|
const extension = createExtension(extensionPath, resolvedPath);
|
|
472
|
+
let restoreLazyToolPlaceholders = () => { };
|
|
466
473
|
const load = async () => {
|
|
467
474
|
if (extension.lazy?.loaded)
|
|
468
475
|
return;
|
|
@@ -486,19 +493,30 @@ function createLazyExtension(extensionPath, resolvedPath, cwd, eventBus, runtime
|
|
|
486
493
|
await loading;
|
|
487
494
|
}
|
|
488
495
|
catch (err) {
|
|
496
|
+
await disposeExtensionEventSubscriptions([extension]);
|
|
497
|
+
extension.handlers.clear();
|
|
498
|
+
extension.messageRenderers.clear();
|
|
499
|
+
extension.commands.clear();
|
|
500
|
+
extension.flags.clear();
|
|
501
|
+
extension.shortcuts.clear();
|
|
502
|
+
extension.tools.clear();
|
|
503
|
+
restoreLazyToolPlaceholders();
|
|
489
504
|
if (extension.lazy)
|
|
490
505
|
extension.lazy.loading = undefined;
|
|
491
506
|
throw err;
|
|
492
507
|
}
|
|
493
508
|
};
|
|
494
509
|
extension.lazy = { loaded: false, load };
|
|
495
|
-
|
|
496
|
-
const
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
510
|
+
restoreLazyToolPlaceholders = () => {
|
|
511
|
+
for (const tool of lazyTools) {
|
|
512
|
+
const name = String(tool.name).trim();
|
|
513
|
+
extension.tools.set(name, {
|
|
514
|
+
definition: createLazyToolDefinition(extension, tool, load),
|
|
515
|
+
sourceInfo: extension.sourceInfo,
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
};
|
|
519
|
+
restoreLazyToolPlaceholders();
|
|
502
520
|
return extension;
|
|
503
521
|
}
|
|
504
522
|
/**
|
|
@@ -508,7 +526,13 @@ export async function loadExtensionFromFactory(factory, cwd, eventBus, runtime,
|
|
|
508
526
|
const extension = createExtension(extensionPath, extensionPath);
|
|
509
527
|
const resolvedCwd = resolvePath(cwd);
|
|
510
528
|
const api = createExtensionAPI(extension, runtime, resolvedCwd, eventBus);
|
|
511
|
-
|
|
529
|
+
try {
|
|
530
|
+
await factory(api);
|
|
531
|
+
}
|
|
532
|
+
catch (err) {
|
|
533
|
+
await disposeExtensionEventSubscriptions([extension]);
|
|
534
|
+
throw err;
|
|
535
|
+
}
|
|
512
536
|
return extension;
|
|
513
537
|
}
|
|
514
538
|
/**
|