@wrongstack/core 0.297.0 → 0.298.0
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/dist/chronicle/index.js +126 -22
- package/dist/chronicle/project-server-client.d.ts +12 -0
- package/dist/chronicle/project-server-protocol.d.ts +22 -0
- package/dist/chronicle/project-server.js +238 -157
- package/dist/coordination/agents/index.js +136 -1
- package/dist/coordination/agents/role-skills.d.ts +3 -2
- package/dist/coordination/brain-trace.d.ts +2 -1
- package/dist/coordination/director/director-task-registry.d.ts +12 -0
- package/dist/coordination/fleet-supervisor.d.ts +21 -0
- package/dist/coordination/index.d.ts +23 -21
- package/dist/coordination/index.js +16493 -16068
- package/dist/coordination/mail-tools.d.ts +3 -3
- package/dist/coordination/mailbox-credential-store.d.ts +22 -2
- package/dist/coordination/mailbox-credential-throttle.d.ts +63 -0
- package/dist/coordination/mailbox-project-server-client.d.ts +16 -0
- package/dist/coordination/mailbox-project-server-protocol.d.ts +43 -5
- package/dist/coordination/mailbox-project-server.js +508 -253
- package/dist/coordination/provider-status-tracker.d.ts +2 -0
- package/dist/coordination/remote-mailbox-credential-store.d.ts +5 -5
- package/dist/coordination/remote-mailbox.d.ts +8 -4
- package/dist/coordination/sqlite-mailbox-credentials.d.ts +11 -0
- package/dist/core/fallback-profile-manager.d.ts +14 -0
- package/dist/core/index.js +451 -137
- package/dist/core/instruction-bundle.d.ts +12 -0
- package/dist/core/system-prompt-builder.d.ts +14 -0
- package/dist/core/system-prompt-skill-bodies.d.ts +1 -1
- package/dist/core/system-prompt-skill-text.d.ts +1 -2
- package/dist/defaults/index.js +2081 -1102
- package/dist/design/index.js +47 -8
- package/dist/execution/design-materialize.d.ts +22 -0
- package/dist/execution/index.js +495 -248
- package/dist/execution/skill-loader.d.ts +10 -1
- package/dist/execution/tool-error-taxonomy.d.ts +31 -0
- package/dist/execution/tool-executor.d.ts +1 -0
- package/dist/goal/index.js +3 -1
- package/dist/hooks/index.js +5 -0
- package/dist/hq/auth-audit.d.ts +6 -0
- package/dist/hq/auth-store.d.ts +59 -3
- package/dist/hq/index.js +401 -101
- package/dist/hq/kanban-store.d.ts +3 -0
- package/dist/hq/protocol/core.d.ts +3 -15
- package/dist/hq/protocol/envelope.d.ts +29 -0
- package/dist/hq/protocol/governance.d.ts +34 -0
- package/dist/hq/protocol/project.d.ts +3 -0
- package/dist/hq/protocol/resume.d.ts +1 -1
- package/dist/hq/protocol.d.ts +9 -8
- package/dist/hq/protocol.js +675 -0
- package/dist/index.js +8518 -6416
- package/dist/infrastructure/index.js +198 -101
- package/dist/kernel/events/session-events.d.ts +3 -0
- package/dist/kernel/events/tool-events.d.ts +3 -1
- package/dist/models/index.js +1 -1
- package/dist/observability/index.js +27 -0
- package/dist/observability/prometheus.d.ts +11 -0
- package/dist/plugin/index.d.ts +5 -1
- package/dist/plugin/index.js +950 -509
- package/dist/plugins/review-store-maintenance.d.ts +26 -0
- package/dist/plugins/review-types.d.ts +6 -0
- package/dist/security/capabilities.d.ts +45 -1
- package/dist/security/error-sanitize.d.ts +49 -0
- package/dist/security/file-permissions.d.ts +41 -0
- package/dist/security/index.d.ts +9 -6
- package/dist/security/index.js +3007 -2032
- package/dist/security/permission-policy.d.ts +55 -3
- package/dist/security/secret-vault.d.ts +17 -0
- package/dist/security/totp.d.ts +86 -0
- package/dist/skills/frontmatter.d.ts +12 -1
- package/dist/skills/github-fetcher.d.ts +48 -0
- package/dist/skills/index.js +137 -26
- package/dist/skills/limits.d.ts +19 -0
- package/dist/skills/skill-installer.d.ts +13 -0
- package/dist/storage/index.js +928 -732
- package/dist/storage/provider-config-watcher.d.ts +1 -0
- package/dist/storage/session-helpers.d.ts +1 -0
- package/dist/storage/session-store.d.ts +9 -2
- package/dist/storage/session-workspace-checkpoints.d.ts +5 -0
- package/dist/tools/fallback-manage-tools.d.ts +6 -0
- package/dist/tools/index.js +287 -131
- package/dist/tools/mcp-use.d.ts +1 -1
- package/dist/types/blocks.d.ts +7 -0
- package/dist/types/config/autonomy.d.ts +12 -3
- package/dist/types/config/mcp-features.d.ts +9 -1
- package/dist/types/config/root.d.ts +10 -4
- package/dist/types/context-window.d.ts +15 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/secret-vault.d.ts +8 -0
- package/dist/types/session.d.ts +2 -0
- package/dist/types/skill.d.ts +56 -0
- package/dist/types/tool-executor.d.ts +2 -0
- package/dist/utils/env-typed.d.ts +64 -0
- package/dist/utils/glob-match.d.ts +21 -1
- package/dist/utils/heap-watchdog.js +1 -1
- package/dist/utils/incoming-images.d.ts +19 -0
- package/dist/utils/index.d.ts +15 -12
- package/dist/utils/index.js +3083 -2801
- package/dist/utils/path-segment.d.ts +29 -0
- package/dist/utils/win32-cmd.d.ts +25 -0
- package/dist/worktree/index.js +5 -0
- package/package.json +8 -3
- package/skills/chimera/SKILL.md +16 -4
- package/skills/data-governance/SKILL.md +92 -0
- package/skills/wrongstack-kanban/SKILL.md +125 -64
- package/dist/agent-status-helpers.d.ts.map +0 -1
- package/dist/agent-status-tracker.d.ts.map +0 -1
- package/dist/boot.d.ts.map +0 -1
- package/dist/chronicle/context.d.ts.map +0 -1
- package/dist/chronicle/decision-adapter.d.ts.map +0 -1
- package/dist/chronicle/domain-adapter.d.ts.map +0 -1
- package/dist/chronicle/event-hash.d.ts.map +0 -1
- package/dist/chronicle/file-observer.d.ts.map +0 -1
- package/dist/chronicle/health-monitor.d.ts.map +0 -1
- package/dist/chronicle/identity.d.ts.map +0 -1
- package/dist/chronicle/index.d.ts.map +0 -1
- package/dist/chronicle/index.js.map +0 -7
- package/dist/chronicle/journal.d.ts.map +0 -1
- package/dist/chronicle/legacy-journal-import.d.ts.map +0 -1
- package/dist/chronicle/metrics-store.d.ts.map +0 -1
- package/dist/chronicle/partition-filename.d.ts.map +0 -1
- package/dist/chronicle/partition-range-cache.d.ts.map +0 -1
- package/dist/chronicle/process-adapter.d.ts.map +0 -1
- package/dist/chronicle/project-access.d.ts.map +0 -1
- package/dist/chronicle/project-server-client.d.ts.map +0 -1
- package/dist/chronicle/project-server-endpoint.d.ts.map +0 -1
- package/dist/chronicle/project-server-protocol.d.ts.map +0 -1
- package/dist/chronicle/project-server.d.ts.map +0 -1
- package/dist/chronicle/project-server.js.map +0 -7
- package/dist/chronicle/prompt-manifest.d.ts.map +0 -1
- package/dist/chronicle/provider-adapter.d.ts.map +0 -1
- package/dist/chronicle/query.d.ts.map +0 -1
- package/dist/chronicle/review-adapter.d.ts.map +0 -1
- package/dist/chronicle/rollup-adapter.d.ts.map +0 -1
- package/dist/chronicle/sink.d.ts.map +0 -1
- package/dist/chronicle/sqlite-journal.d.ts.map +0 -1
- package/dist/chronicle/sqlite-query.d.ts.map +0 -1
- package/dist/chronicle/stream-adapter.d.ts.map +0 -1
- package/dist/chronicle/tool-adapter.d.ts.map +0 -1
- package/dist/chronicle/types.d.ts.map +0 -1
- package/dist/coordination/adaptive-concurrency.d.ts.map +0 -1
- package/dist/coordination/agent-bridge.d.ts.map +0 -1
- package/dist/coordination/agent-monitor.d.ts.map +0 -1
- package/dist/coordination/agent-subagent-runner.d.ts.map +0 -1
- package/dist/coordination/agents/agent-prompts.d.ts.map +0 -1
- package/dist/coordination/agents/index.d.ts.map +0 -1
- package/dist/coordination/agents/index.js.map +0 -7
- package/dist/coordination/agents/phase1-discovery.d.ts.map +0 -1
- package/dist/coordination/agents/phase2-planning.d.ts.map +0 -1
- package/dist/coordination/agents/phase3-build.d.ts.map +0 -1
- package/dist/coordination/agents/phase3-techstack.d.ts.map +0 -1
- package/dist/coordination/agents/phase3-wave1-platform.d.ts.map +0 -1
- package/dist/coordination/agents/phase3-wave2-meta.d.ts.map +0 -1
- package/dist/coordination/agents/phase4-verify.d.ts.map +0 -1
- package/dist/coordination/agents/phase5-review.d.ts.map +0 -1
- package/dist/coordination/agents/phase6-domain.d.ts.map +0 -1
- package/dist/coordination/agents/phase7-knowledge.d.ts.map +0 -1
- package/dist/coordination/agents/phase8-delivery.d.ts.map +0 -1
- package/dist/coordination/agents/phase8-wave3-products.d.ts.map +0 -1
- package/dist/coordination/agents/phase9-meta.d.ts.map +0 -1
- package/dist/coordination/agents/phase9-wave4-platform-meta.d.ts.map +0 -1
- package/dist/coordination/agents/project-agent-config-validation.d.ts.map +0 -1
- package/dist/coordination/agents/project-agent-consolidation.d.ts.map +0 -1
- package/dist/coordination/agents/project-agent-files.d.ts.map +0 -1
- package/dist/coordination/agents/project-agent-identity-types.d.ts.map +0 -1
- package/dist/coordination/agents/project-agent-identity.d.ts.map +0 -1
- package/dist/coordination/agents/project-agent-knowledge-manifests.d.ts.map +0 -1
- package/dist/coordination/agents/project-agent-learning-entries.d.ts.map +0 -1
- package/dist/coordination/agents/project-agent-learning-normalize.d.ts.map +0 -1
- package/dist/coordination/agents/project-agent-learning-policy.d.ts.map +0 -1
- package/dist/coordination/agents/project-agent-learning-structured.d.ts.map +0 -1
- package/dist/coordination/agents/project-agent-paths.d.ts.map +0 -1
- package/dist/coordination/agents/project-agent-profile.d.ts.map +0 -1
- package/dist/coordination/agents/role-skills.d.ts.map +0 -1
- package/dist/coordination/agents/types.d.ts.map +0 -1
- package/dist/coordination/agents.d.ts.map +0 -1
- package/dist/coordination/auto-extend.d.ts.map +0 -1
- package/dist/coordination/autonomous-brain.d.ts.map +0 -1
- package/dist/coordination/autonomous-coordinator.d.ts.map +0 -1
- package/dist/coordination/brain-cache.d.ts.map +0 -1
- package/dist/coordination/brain-heuristics.d.ts.map +0 -1
- package/dist/coordination/brain-ledger.d.ts.map +0 -1
- package/dist/coordination/brain-monitor.d.ts.map +0 -1
- package/dist/coordination/brain-rules.d.ts.map +0 -1
- package/dist/coordination/brain-telemetry.d.ts.map +0 -1
- package/dist/coordination/brain-trace.d.ts.map +0 -1
- package/dist/coordination/brain.d.ts.map +0 -1
- package/dist/coordination/change-manager.d.ts.map +0 -1
- package/dist/coordination/checkpoint-wiring.d.ts.map +0 -1
- package/dist/coordination/collab-bus.d.ts.map +0 -1
- package/dist/coordination/collab-debug-types.d.ts.map +0 -1
- package/dist/coordination/collab-debug.d.ts.map +0 -1
- package/dist/coordination/collab-director-host.d.ts.map +0 -1
- package/dist/coordination/commit-safety.d.ts.map +0 -1
- package/dist/coordination/consensus-protocol.d.ts.map +0 -1
- package/dist/coordination/coordinator/error-classifier.d.ts.map +0 -1
- package/dist/coordination/delegate-tool.d.ts.map +0 -1
- package/dist/coordination/dep-watcher-bridge.d.ts.map +0 -1
- package/dist/coordination/dep-watcher.d.ts.map +0 -1
- package/dist/coordination/director/director-btw-notes.d.ts.map +0 -1
- package/dist/coordination/director/director-budget-policy.d.ts.map +0 -1
- package/dist/coordination/director/director-collab.d.ts.map +0 -1
- package/dist/coordination/director/director-errors.d.ts.map +0 -1
- package/dist/coordination/director/director-task-registry.d.ts.map +0 -1
- package/dist/coordination/director/director-toolset.d.ts.map +0 -1
- package/dist/coordination/director-basic-tools.d.ts.map +0 -1
- package/dist/coordination/director-collab-tools.d.ts.map +0 -1
- package/dist/coordination/director-host-contracts.d.ts.map +0 -1
- package/dist/coordination/director-input-helpers.d.ts.map +0 -1
- package/dist/coordination/director-kanban-queue-helpers.d.ts.map +0 -1
- package/dist/coordination/director-options.d.ts.map +0 -1
- package/dist/coordination/director-prompts.d.ts.map +0 -1
- package/dist/coordination/director-quality-gate-tool.d.ts.map +0 -1
- package/dist/coordination/director-session.d.ts.map +0 -1
- package/dist/coordination/director-spawn-model.d.ts.map +0 -1
- package/dist/coordination/director-tools.d.ts.map +0 -1
- package/dist/coordination/director.d.ts.map +0 -1
- package/dist/coordination/dispatcher.d.ts.map +0 -1
- package/dist/coordination/file-author-tracker.d.ts.map +0 -1
- package/dist/coordination/fleet-bus.d.ts.map +0 -1
- package/dist/coordination/fleet-event-validation.d.ts.map +0 -1
- package/dist/coordination/fleet-manager.d.ts.map +0 -1
- package/dist/coordination/fleet-spawn.d.ts.map +0 -1
- package/dist/coordination/fleet-status-tool.d.ts.map +0 -1
- package/dist/coordination/fleet-supervisor.d.ts.map +0 -1
- package/dist/coordination/fleet.d.ts.map +0 -1
- package/dist/coordination/global-mailbox-completion.d.ts.map +0 -1
- package/dist/coordination/global-mailbox-paths.d.ts.map +0 -1
- package/dist/coordination/icoordinator.d.ts.map +0 -1
- package/dist/coordination/ifleet-manager.d.ts.map +0 -1
- package/dist/coordination/in-memory-transport.d.ts.map +0 -1
- package/dist/coordination/index.d.ts.map +0 -1
- package/dist/coordination/index.js.map +0 -7
- package/dist/coordination/knowledge-graph.d.ts.map +0 -1
- package/dist/coordination/large-answer-store.d.ts.map +0 -1
- package/dist/coordination/mail-tools.d.ts.map +0 -1
- package/dist/coordination/mailbox-actions.d.ts.map +0 -1
- package/dist/coordination/mailbox-auth-types.d.ts.map +0 -1
- package/dist/coordination/mailbox-codecs.d.ts.map +0 -1
- package/dist/coordination/mailbox-constants.d.ts.map +0 -1
- package/dist/coordination/mailbox-credential-store.d.ts.map +0 -1
- package/dist/coordination/mailbox-events.d.ts.map +0 -1
- package/dist/coordination/mailbox-health.d.ts.map +0 -1
- package/dist/coordination/mailbox-hooks.d.ts.map +0 -1
- package/dist/coordination/mailbox-http-auth.d.ts.map +0 -1
- package/dist/coordination/mailbox-http-rate-limit.d.ts.map +0 -1
- package/dist/coordination/mailbox-http-router.d.ts.map +0 -1
- package/dist/coordination/mailbox-http-validation.d.ts.map +0 -1
- package/dist/coordination/mailbox-message-codec.d.ts.map +0 -1
- package/dist/coordination/mailbox-parse-state.d.ts.map +0 -1
- package/dist/coordination/mailbox-project-server-client.d.ts.map +0 -1
- package/dist/coordination/mailbox-project-server-endpoint.d.ts.map +0 -1
- package/dist/coordination/mailbox-project-server-protocol.d.ts.map +0 -1
- package/dist/coordination/mailbox-project-server.d.ts.map +0 -1
- package/dist/coordination/mailbox-project-server.js.map +0 -7
- package/dist/coordination/mailbox-receipt-folding.d.ts.map +0 -1
- package/dist/coordination/mailbox-registry-codec.d.ts.map +0 -1
- package/dist/coordination/mailbox-retention-state.d.ts.map +0 -1
- package/dist/coordination/mailbox-status-mappers.d.ts.map +0 -1
- package/dist/coordination/mailbox-tool.d.ts.map +0 -1
- package/dist/coordination/mailbox-type-properties.d.ts.map +0 -1
- package/dist/coordination/mailbox-types.d.ts.map +0 -1
- package/dist/coordination/model-matrix.d.ts.map +0 -1
- package/dist/coordination/multi-agent-coordinator.d.ts.map +0 -1
- package/dist/coordination/multi-agent-timeout.d.ts.map +0 -1
- package/dist/coordination/null-fleet-bus.d.ts.map +0 -1
- package/dist/coordination/package-author-tracker.d.ts.map +0 -1
- package/dist/coordination/package-outdated-watcher.d.ts.map +0 -1
- package/dist/coordination/provider-status-tracker.d.ts.map +0 -1
- package/dist/coordination/remote-mailbox-credential-store.d.ts.map +0 -1
- package/dist/coordination/remote-mailbox.d.ts.map +0 -1
- package/dist/coordination/single-instance-mailbox.d.ts.map +0 -1
- package/dist/coordination/spawn-budget.d.ts.map +0 -1
- package/dist/coordination/sqlite-mailbox-compaction.d.ts.map +0 -1
- package/dist/coordination/sqlite-mailbox-credentials.d.ts.map +0 -1
- package/dist/coordination/sqlite-mailbox-rows.d.ts.map +0 -1
- package/dist/coordination/sqlite-mailbox-schema.d.ts.map +0 -1
- package/dist/coordination/sqlite-mailbox.d.ts.map +0 -1
- package/dist/coordination/subagent-budget.d.ts.map +0 -1
- package/dist/coordination/subagent-nicknames.d.ts.map +0 -1
- package/dist/coordination/subagent-result-tool.d.ts.map +0 -1
- package/dist/coordination/task-auctioneer.d.ts.map +0 -1
- package/dist/coordination/task-dag.d.ts.map +0 -1
- package/dist/coordination/techstack-mailbox-consumer.d.ts.map +0 -1
- package/dist/coordination/transport.d.ts.map +0 -1
- package/dist/coordination/worktree-task-runner.d.ts.map +0 -1
- package/dist/core/agent-internals.d.ts.map +0 -1
- package/dist/core/agent-loop.d.ts.map +0 -1
- package/dist/core/agent-response.d.ts.map +0 -1
- package/dist/core/agent-tools.d.ts.map +0 -1
- package/dist/core/agent-types.d.ts.map +0 -1
- package/dist/core/agent.d.ts.map +0 -1
- package/dist/core/btw.d.ts.map +0 -1
- package/dist/core/context.d.ts.map +0 -1
- package/dist/core/continue-intent.d.ts.map +0 -1
- package/dist/core/continue-to-next-iteration.d.ts.map +0 -1
- package/dist/core/conversation-state.d.ts.map +0 -1
- package/dist/core/fallback-model.d.ts.map +0 -1
- package/dist/core/fallback-profile-manager.d.ts.map +0 -1
- package/dist/core/fleet-pulse.d.ts.map +0 -1
- package/dist/core/index.d.ts.map +0 -1
- package/dist/core/index.js.map +0 -7
- package/dist/core/input-builder.d.ts.map +0 -1
- package/dist/core/instruction-bundle.d.ts.map +0 -1
- package/dist/core/iteration-limit.d.ts.map +0 -1
- package/dist/core/mailbox-loop.d.ts.map +0 -1
- package/dist/core/model-availability-calendar.d.ts.map +0 -1
- package/dist/core/model-ref.d.ts.map +0 -1
- package/dist/core/model-ref.js.map +0 -7
- package/dist/core/modes/brief.d.ts.map +0 -1
- package/dist/core/modes/default.d.ts.map +0 -1
- package/dist/core/modes/teach.d.ts.map +0 -1
- package/dist/core/provider-runner.d.ts.map +0 -1
- package/dist/core/queued-messages.d.ts.map +0 -1
- package/dist/core/request-provider-binding.d.ts.map +0 -1
- package/dist/core/run-env.d.ts.map +0 -1
- package/dist/core/streaming-response-builder.d.ts.map +0 -1
- package/dist/core/system-prompt-blocks.d.ts.map +0 -1
- package/dist/core/system-prompt-builder.d.ts.map +0 -1
- package/dist/core/system-prompt-environment-probes.d.ts.map +0 -1
- package/dist/core/system-prompt-environment.d.ts.map +0 -1
- package/dist/core/system-prompt-memory-skills.d.ts.map +0 -1
- package/dist/core/system-prompt-plan.d.ts.map +0 -1
- package/dist/core/system-prompt-shell.d.ts.map +0 -1
- package/dist/core/system-prompt-skill-bodies.d.ts.map +0 -1
- package/dist/core/system-prompt-skill-text.d.ts.map +0 -1
- package/dist/defaults/index.d.ts.map +0 -1
- package/dist/defaults/index.js.map +0 -7
- package/dist/design/index.d.ts.map +0 -1
- package/dist/design/index.js.map +0 -7
- package/dist/execution/auto-compaction-middleware.d.ts.map +0 -1
- package/dist/execution/autonomous-runner.d.ts.map +0 -1
- package/dist/execution/autonomy-brain.d.ts.map +0 -1
- package/dist/execution/autonomy-prompt-contributor.d.ts.map +0 -1
- package/dist/execution/brain-chain.d.ts.map +0 -1
- package/dist/execution/brain-circuit.d.ts.map +0 -1
- package/dist/execution/brain-evaluation.d.ts.map +0 -1
- package/dist/execution/brain-runtime-constants.d.ts.map +0 -1
- package/dist/execution/brain-runtime.d.ts.map +0 -1
- package/dist/execution/compaction-core.d.ts.map +0 -1
- package/dist/execution/compaction-scoring.d.ts.map +0 -1
- package/dist/execution/compaction-summary-cache.d.ts.map +0 -1
- package/dist/execution/compactor.d.ts.map +0 -1
- package/dist/execution/council-brain.d.ts.map +0 -1
- package/dist/execution/council-orchestrator.d.ts.map +0 -1
- package/dist/execution/council-personas.d.ts.map +0 -1
- package/dist/execution/council-profiles.d.ts.map +0 -1
- package/dist/execution/council-prompts.d.ts.map +0 -1
- package/dist/execution/council-resolution.d.ts.map +0 -1
- package/dist/execution/design-color.d.ts.map +0 -1
- package/dist/execution/design-detect.d.ts.map +0 -1
- package/dist/execution/design-kit-loader.d.ts.map +0 -1
- package/dist/execution/design-materialize.d.ts.map +0 -1
- package/dist/execution/design-project-store.d.ts.map +0 -1
- package/dist/execution/design-tune.d.ts.map +0 -1
- package/dist/execution/design-verify.d.ts.map +0 -1
- package/dist/execution/enhance-recovery.d.ts.map +0 -1
- package/dist/execution/error-handler.d.ts.map +0 -1
- package/dist/execution/eternal-autonomy-types.d.ts.map +0 -1
- package/dist/execution/eternal-autonomy.d.ts.map +0 -1
- package/dist/execution/goal-preamble.d.ts.map +0 -1
- package/dist/execution/index.d.ts.map +0 -1
- package/dist/execution/index.js.map +0 -7
- package/dist/execution/intelligent-compactor.d.ts.map +0 -1
- package/dist/execution/model-runtime.d.ts.map +0 -1
- package/dist/execution/one-shot-llm.d.ts.map +0 -1
- package/dist/execution/parallel-eternal-engine.d.ts.map +0 -1
- package/dist/execution/prompt-enhancer.d.ts.map +0 -1
- package/dist/execution/prompt-enhancer.js.map +0 -7
- package/dist/execution/prompt-loader.d.ts.map +0 -1
- package/dist/execution/provider-runner-impl.d.ts.map +0 -1
- package/dist/execution/regex-patterns.d.ts.map +0 -1
- package/dist/execution/retry-policy.d.ts.map +0 -1
- package/dist/execution/selective-compactor.d.ts.map +0 -1
- package/dist/execution/skill-loader.d.ts.map +0 -1
- package/dist/execution/strategy-compactor.d.ts.map +0 -1
- package/dist/execution/subagent-compaction.d.ts.map +0 -1
- package/dist/execution/tool-executor-logging.d.ts.map +0 -1
- package/dist/execution/tool-executor-results.d.ts.map +0 -1
- package/dist/execution/tool-executor-stream.d.ts.map +0 -1
- package/dist/execution/tool-executor-support.d.ts.map +0 -1
- package/dist/execution/tool-executor.d.ts.map +0 -1
- package/dist/extension/extension-points.d.ts.map +0 -1
- package/dist/extension/index.d.ts.map +0 -1
- package/dist/extension/index.js.map +0 -7
- package/dist/extension/registry.d.ts.map +0 -1
- package/dist/fleet-notifier.d.ts.map +0 -1
- package/dist/goal/checkpoint.d.ts.map +0 -1
- package/dist/goal/goal-assessor.d.ts.map +0 -1
- package/dist/goal/goal-planner.d.ts.map +0 -1
- package/dist/goal/goal-runner.d.ts.map +0 -1
- package/dist/goal/index.d.ts.map +0 -1
- package/dist/goal/index.js.map +0 -7
- package/dist/goal/phase-board-mutations.d.ts.map +0 -1
- package/dist/goal/phase-graph-builder.d.ts.map +0 -1
- package/dist/goal/phase-orchestrator-integration.d.ts.map +0 -1
- package/dist/goal/phase-orchestrator-queries.d.ts.map +0 -1
- package/dist/goal/phase-orchestrator-runtime.d.ts.map +0 -1
- package/dist/goal/phase-orchestrator-types.d.ts.map +0 -1
- package/dist/goal/phase-orchestrator.d.ts.map +0 -1
- package/dist/goal/phase-store.d.ts.map +0 -1
- package/dist/goal/types.d.ts.map +0 -1
- package/dist/hooks/http-executor.d.ts.map +0 -1
- package/dist/hooks/index.d.ts.map +0 -1
- package/dist/hooks/index.js.map +0 -7
- package/dist/hooks/registry.d.ts.map +0 -1
- package/dist/hooks/runner.d.ts.map +0 -1
- package/dist/hooks/shell-executor.d.ts.map +0 -1
- package/dist/hooks/shell-hooks-equal.d.ts.map +0 -1
- package/dist/hq/alerts.d.ts.map +0 -1
- package/dist/hq/auth-audit.d.ts.map +0 -1
- package/dist/hq/auth-store.d.ts.map +0 -1
- package/dist/hq/bootstrap-store.d.ts.map +0 -1
- package/dist/hq/brain-bridge.d.ts.map +0 -1
- package/dist/hq/bridge-context.d.ts.map +0 -1
- package/dist/hq/commands.d.ts.map +0 -1
- package/dist/hq/cost-bridge.d.ts.map +0 -1
- package/dist/hq/exposure.d.ts.map +0 -1
- package/dist/hq/factory.d.ts.map +0 -1
- package/dist/hq/fleet-bridge.d.ts.map +0 -1
- package/dist/hq/index.d.ts.map +0 -1
- package/dist/hq/index.js.map +0 -7
- package/dist/hq/kanban-store.d.ts.map +0 -1
- package/dist/hq/mailbox-mapper.d.ts.map +0 -1
- package/dist/hq/persistence/event-log.d.ts.map +0 -1
- package/dist/hq/persistence/jsonl-io.d.ts.map +0 -1
- package/dist/hq/persistence/simple-log.d.ts.map +0 -1
- package/dist/hq/persistence/snapshot-store.d.ts.map +0 -1
- package/dist/hq/persistence/timeseries-store.d.ts.map +0 -1
- package/dist/hq/persistence.d.ts.map +0 -1
- package/dist/hq/protocol/brain.d.ts.map +0 -1
- package/dist/hq/protocol/browser.d.ts.map +0 -1
- package/dist/hq/protocol/client.d.ts.map +0 -1
- package/dist/hq/protocol/core.d.ts.map +0 -1
- package/dist/hq/protocol/fleet.d.ts.map +0 -1
- package/dist/hq/protocol/kanban.d.ts.map +0 -1
- package/dist/hq/protocol/mailbox.d.ts.map +0 -1
- package/dist/hq/protocol/mcp.d.ts.map +0 -1
- package/dist/hq/protocol/peer.d.ts.map +0 -1
- package/dist/hq/protocol/project.d.ts.map +0 -1
- package/dist/hq/protocol/resume.d.ts.map +0 -1
- package/dist/hq/protocol/session.d.ts.map +0 -1
- package/dist/hq/protocol/tool.d.ts.map +0 -1
- package/dist/hq/protocol.d.ts.map +0 -1
- package/dist/hq/publisher.d.ts.map +0 -1
- package/dist/hq/redaction.d.ts.map +0 -1
- package/dist/hq/session-bridge.d.ts.map +0 -1
- package/dist/hq/tool-bridge.d.ts.map +0 -1
- package/dist/hq/transcript-mapper.d.ts.map +0 -1
- package/dist/hq/worktree-bridge.d.ts.map +0 -1
- package/dist/hq/write-queues.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -7
- package/dist/infrastructure/context-manager.d.ts.map +0 -1
- package/dist/infrastructure/index.d.ts.map +0 -1
- package/dist/infrastructure/index.js.map +0 -7
- package/dist/infrastructure/logger.d.ts.map +0 -1
- package/dist/infrastructure/mcp-servers.d.ts.map +0 -1
- package/dist/infrastructure/path-resolver.d.ts.map +0 -1
- package/dist/infrastructure/provider-cache-ledger.d.ts.map +0 -1
- package/dist/infrastructure/token-counter.d.ts.map +0 -1
- package/dist/kernel/container.d.ts.map +0 -1
- package/dist/kernel/events/agent-events.d.ts.map +0 -1
- package/dist/kernel/events/brain-events.d.ts.map +0 -1
- package/dist/kernel/events/file-events.d.ts.map +0 -1
- package/dist/kernel/events/fleet-events.d.ts.map +0 -1
- package/dist/kernel/events/memory-events.d.ts.map +0 -1
- package/dist/kernel/events/network-events.d.ts.map +0 -1
- package/dist/kernel/events/process-events.d.ts.map +0 -1
- package/dist/kernel/events/provider-events.d.ts.map +0 -1
- package/dist/kernel/events/sdd-events.d.ts.map +0 -1
- package/dist/kernel/events/session-events.d.ts.map +0 -1
- package/dist/kernel/events/tool-events.d.ts.map +0 -1
- package/dist/kernel/events/worktree-events.d.ts.map +0 -1
- package/dist/kernel/events.d.ts.map +0 -1
- package/dist/kernel/index.d.ts.map +0 -1
- package/dist/kernel/index.js.map +0 -7
- package/dist/kernel/pipeline.d.ts.map +0 -1
- package/dist/kernel/run-controller.d.ts.map +0 -1
- package/dist/kernel/tokens.d.ts.map +0 -1
- package/dist/mailbox-attach.d.ts.map +0 -1
- package/dist/middleware/collab-pause.d.ts.map +0 -1
- package/dist/models/alibaba-token-plan-catalog.d.ts.map +0 -1
- package/dist/models/codex-catalog.d.ts.map +0 -1
- package/dist/models/index.d.ts.map +0 -1
- package/dist/models/index.js.map +0 -7
- package/dist/models/llm-selector.d.ts.map +0 -1
- package/dist/models/mode-store.d.ts.map +0 -1
- package/dist/models/model-intelligence.d.ts.map +0 -1
- package/dist/models/model-router.d.ts.map +0 -1
- package/dist/models/models-registry.d.ts.map +0 -1
- package/dist/models/provider-model-resolve.d.ts.map +0 -1
- package/dist/notifications/index.d.ts.map +0 -1
- package/dist/notifications/index.js.map +0 -7
- package/dist/notifications/notifier-impl.d.ts.map +0 -1
- package/dist/notifications/notifier.d.ts.map +0 -1
- package/dist/notifications/types.d.ts.map +0 -1
- package/dist/observability/event-bridge.d.ts.map +0 -1
- package/dist/observability/health.d.ts.map +0 -1
- package/dist/observability/index.d.ts.map +0 -1
- package/dist/observability/index.js.map +0 -7
- package/dist/observability/metrics.d.ts.map +0 -1
- package/dist/observability/network-telemetry.d.ts.map +0 -1
- package/dist/observability/otel-tracer.d.ts.map +0 -1
- package/dist/observability/otlp-metrics.d.ts.map +0 -1
- package/dist/observability/otlp-traces.d.ts.map +0 -1
- package/dist/observability/process-telemetry.d.ts.map +0 -1
- package/dist/observability/prometheus.d.ts.map +0 -1
- package/dist/observability/redact-command.d.ts.map +0 -1
- package/dist/observability/tracer.d.ts.map +0 -1
- package/dist/plugin/api.d.ts.map +0 -1
- package/dist/plugin/config.d.ts.map +0 -1
- package/dist/plugin/index.d.ts.map +0 -1
- package/dist/plugin/index.js.map +0 -7
- package/dist/plugin/loader.d.ts.map +0 -1
- package/dist/plugins/auto-review-plugin.d.ts.map +0 -1
- package/dist/plugins/chimera-plugin.d.ts.map +0 -1
- package/dist/plugins/prompts-plugin.d.ts.map +0 -1
- package/dist/plugins/review-claim-registry.d.ts.map +0 -1
- package/dist/plugins/review-context-builder.d.ts.map +0 -1
- package/dist/plugins/review-finding-commands.d.ts.map +0 -1
- package/dist/plugins/review-finding-integration.d.ts.map +0 -1
- package/dist/plugins/review-finding-parser.d.ts.map +0 -1
- package/dist/plugins/review-finding-store.d.ts.map +0 -1
- package/dist/plugins/review-finding-types.d.ts.map +0 -1
- package/dist/plugins/review-report-integration.d.ts.map +0 -1
- package/dist/plugins/review-report-store.d.ts.map +0 -1
- package/dist/plugins/review-report-types.d.ts.map +0 -1
- package/dist/plugins/review-types.d.ts.map +0 -1
- package/dist/plugins/skills-plugin.d.ts.map +0 -1
- package/dist/plugins/sync-plugin.d.ts.map +0 -1
- package/dist/prompts/index.d.ts.map +0 -1
- package/dist/prompts/prompt-installer.d.ts.map +0 -1
- package/dist/prompts/prompt-manifest-store.d.ts.map +0 -1
- package/dist/registry/index.d.ts.map +0 -1
- package/dist/registry/index.js.map +0 -7
- package/dist/registry/provider-registry.d.ts.map +0 -1
- package/dist/registry/slash-command-registry.d.ts.map +0 -1
- package/dist/registry/tool-registry.d.ts.map +0 -1
- package/dist/replay/hash.d.ts.map +0 -1
- package/dist/replay/index.d.ts.map +0 -1
- package/dist/replay/index.js.map +0 -7
- package/dist/replay/replay-provider-runner.d.ts.map +0 -1
- package/dist/security/capabilities.d.ts.map +0 -1
- package/dist/security/config-secrets.d.ts.map +0 -1
- package/dist/security/directory-permission-policy.d.ts.map +0 -1
- package/dist/security/directory-policy-schema.d.ts.map +0 -1
- package/dist/security/index.d.ts.map +0 -1
- package/dist/security/index.js.map +0 -7
- package/dist/security/kanban-boundary.d.ts.map +0 -1
- package/dist/security/permission-policy-schema.d.ts.map +0 -1
- package/dist/security/permission-policy.d.ts.map +0 -1
- package/dist/security/readonly-permission-policy.d.ts.map +0 -1
- package/dist/security/secret-scrubber.d.ts.map +0 -1
- package/dist/security/secret-vault.d.ts.map +0 -1
- package/dist/security/trust-boundary.d.ts.map +0 -1
- package/dist/security/yolo-risk.d.ts.map +0 -1
- package/dist/session-registry-atomic-file.d.ts.map +0 -1
- package/dist/session-registry-types.d.ts.map +0 -1
- package/dist/session-registry.d.ts.map +0 -1
- package/dist/skills/foreign-sources.d.ts.map +0 -1
- package/dist/skills/frontmatter.d.ts.map +0 -1
- package/dist/skills/github-fetcher.d.ts.map +0 -1
- package/dist/skills/index.d.ts.map +0 -1
- package/dist/skills/index.js.map +0 -7
- package/dist/skills/limits.d.ts.map +0 -1
- package/dist/skills/manifest-store.d.ts.map +0 -1
- package/dist/skills/registry/github-direct-adapter.d.ts.map +0 -1
- package/dist/skills/registry/registry-adapter.d.ts.map +0 -1
- package/dist/skills/registry/skills-sh-adapter.d.ts.map +0 -1
- package/dist/skills/skill-generator.d.ts.map +0 -1
- package/dist/skills/skill-installer.d.ts.map +0 -1
- package/dist/storage/annotations-store.d.ts.map +0 -1
- package/dist/storage/attachment-store.d.ts.map +0 -1
- package/dist/storage/cloud-sync.d.ts.map +0 -1
- package/dist/storage/completed-work-checkpoint.d.ts.map +0 -1
- package/dist/storage/config-loader/bootstrap.d.ts.map +0 -1
- package/dist/storage/config-loader/default-repair.d.ts.map +0 -1
- package/dist/storage/config-loader/defaults.d.ts.map +0 -1
- package/dist/storage/config-loader/diagnostics.d.ts.map +0 -1
- package/dist/storage/config-loader/env-overrides.d.ts.map +0 -1
- package/dist/storage/config-loader/in-project-policy.d.ts.map +0 -1
- package/dist/storage/config-loader/inline-provider-models.d.ts.map +0 -1
- package/dist/storage/config-loader/legacy-sage-migration.d.ts.map +0 -1
- package/dist/storage/config-loader/path-identity.d.ts.map +0 -1
- package/dist/storage/config-loader/types.d.ts.map +0 -1
- package/dist/storage/config-loader/validation.d.ts.map +0 -1
- package/dist/storage/config-loader.d.ts.map +0 -1
- package/dist/storage/config-migration.d.ts.map +0 -1
- package/dist/storage/config-store.d.ts.map +0 -1
- package/dist/storage/director-state.d.ts.map +0 -1
- package/dist/storage/file-session-writer.d.ts.map +0 -1
- package/dist/storage/goal-coordination.d.ts.map +0 -1
- package/dist/storage/goal-kanban.d.ts.map +0 -1
- package/dist/storage/goal-store.d.ts.map +0 -1
- package/dist/storage/index.d.ts.map +0 -1
- package/dist/storage/index.js.map +0 -7
- package/dist/storage/input-history-store.d.ts.map +0 -1
- package/dist/storage/memory-backend.d.ts.map +0 -1
- package/dist/storage/memory-consolidator.d.ts.map +0 -1
- package/dist/storage/memory-graph-backend.d.ts.map +0 -1
- package/dist/storage/plan-store.d.ts.map +0 -1
- package/dist/storage/plan-templates.d.ts.map +0 -1
- package/dist/storage/prompt-store.d.ts.map +0 -1
- package/dist/storage/prompt-usage-store.d.ts.map +0 -1
- package/dist/storage/provider-config-watcher.d.ts.map +0 -1
- package/dist/storage/queue-store.d.ts.map +0 -1
- package/dist/storage/recovery-lock.d.ts.map +0 -1
- package/dist/storage/replay-log-store.d.ts.map +0 -1
- package/dist/storage/session-analyzer.d.ts.map +0 -1
- package/dist/storage/session-checkpoint-cas.d.ts.map +0 -1
- package/dist/storage/session-event-bridge.d.ts.map +0 -1
- package/dist/storage/session-helpers.d.ts.map +0 -1
- package/dist/storage/session-id-resolver.d.ts.map +0 -1
- package/dist/storage/session-id.d.ts.map +0 -1
- package/dist/storage/session-read-scrubber.d.ts.map +0 -1
- package/dist/storage/session-reader.d.ts.map +0 -1
- package/dist/storage/session-recovery.d.ts.map +0 -1
- package/dist/storage/session-resume-validation.d.ts.map +0 -1
- package/dist/storage/session-rewind-apply.d.ts.map +0 -1
- package/dist/storage/session-rewinder.d.ts.map +0 -1
- package/dist/storage/session-store/delete-session-artifacts.d.ts.map +0 -1
- package/dist/storage/session-store/delete-session-guards.d.ts.map +0 -1
- package/dist/storage/session-store/directory-scan.d.ts.map +0 -1
- package/dist/storage/session-store/directory-session-files.d.ts.map +0 -1
- package/dist/storage/session-store/events.d.ts.map +0 -1
- package/dist/storage/session-store/fork-session.d.ts.map +0 -1
- package/dist/storage/session-store/index-reader.d.ts.map +0 -1
- package/dist/storage/session-store/load-cache.d.ts.map +0 -1
- package/dist/storage/session-store/load-session-data.d.ts.map +0 -1
- package/dist/storage/session-store/paths.d.ts.map +0 -1
- package/dist/storage/session-store/prune-helpers.d.ts.map +0 -1
- package/dist/storage/session-store/replay.d.ts.map +0 -1
- package/dist/storage/session-store/search-events.d.ts.map +0 -1
- package/dist/storage/session-store/shard-manifest.d.ts.map +0 -1
- package/dist/storage/session-store/summary-builder.d.ts.map +0 -1
- package/dist/storage/session-store/summary-header.d.ts.map +0 -1
- package/dist/storage/session-store/types.d.ts.map +0 -1
- package/dist/storage/session-store.d.ts.map +0 -1
- package/dist/storage/session-summary.d.ts.map +0 -1
- package/dist/storage/session-tool-call-ends.d.ts.map +0 -1
- package/dist/storage/session-writer-scrubber.d.ts.map +0 -1
- package/dist/storage/session-writer-truncate.d.ts.map +0 -1
- package/dist/storage/storage-concurrency.d.ts.map +0 -1
- package/dist/storage/task-store.d.ts.map +0 -1
- package/dist/storage/todos-checkpoint.d.ts.map +0 -1
- package/dist/storage/tool-audit-log.d.ts.map +0 -1
- package/dist/tasking/index.d.ts.map +0 -1
- package/dist/tasking/index.js.map +0 -7
- package/dist/tasking/task-store.d.ts.map +0 -1
- package/dist/tasking/task-tracker.d.ts.map +0 -1
- package/dist/tools/council-tool.d.ts.map +0 -1
- package/dist/tools/fallback-chain-manage-tool.d.ts.map +0 -1
- package/dist/tools/fallback-favorite-manage-tool.d.ts.map +0 -1
- package/dist/tools/fallback-manage-helpers.d.ts.map +0 -1
- package/dist/tools/fallback-manage-tool-options.d.ts.map +0 -1
- package/dist/tools/fallback-manage-tools.d.ts.map +0 -1
- package/dist/tools/fallback-model-ref-parse.d.ts.map +0 -1
- package/dist/tools/fallback-provider-key-store.d.ts.map +0 -1
- package/dist/tools/fallback-system-config-view-tool.d.ts.map +0 -1
- package/dist/tools/index.d.ts.map +0 -1
- package/dist/tools/index.js.map +0 -7
- package/dist/tools/mcp-control.d.ts.map +0 -1
- package/dist/tools/mcp-use.d.ts.map +0 -1
- package/dist/tools/one-shot-llm-tool.d.ts.map +0 -1
- package/dist/tools/plugin-manager.d.ts.map +0 -1
- package/dist/types/agent-bridge.d.ts.map +0 -1
- package/dist/types/attachment.d.ts.map +0 -1
- package/dist/types/autonomy.d.ts.map +0 -1
- package/dist/types/blocks.d.ts.map +0 -1
- package/dist/types/compactor.d.ts.map +0 -1
- package/dist/types/config/autonomy.d.ts.map +0 -1
- package/dist/types/config/context.d.ts.map +0 -1
- package/dist/types/config/fleet-chat.d.ts.map +0 -1
- package/dist/types/config/mcp-features.d.ts.map +0 -1
- package/dist/types/config/providers.d.ts.map +0 -1
- package/dist/types/config/root.d.ts.map +0 -1
- package/dist/types/config/runtime.d.ts.map +0 -1
- package/dist/types/config/skills-fleet-brain.d.ts.map +0 -1
- package/dist/types/config/tools.d.ts.map +0 -1
- package/dist/types/config.d.ts.map +0 -1
- package/dist/types/context-evidence.d.ts.map +0 -1
- package/dist/types/context-window.d.ts.map +0 -1
- package/dist/types/council.d.ts.map +0 -1
- package/dist/types/default-config.d.ts.map +0 -1
- package/dist/types/design-kit.d.ts.map +0 -1
- package/dist/types/error-handler.d.ts.map +0 -1
- package/dist/types/errors.d.ts.map +0 -1
- package/dist/types/file-event-record.d.ts.map +0 -1
- package/dist/types/hooks.d.ts.map +0 -1
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/index.js.map +0 -7
- package/dist/types/input-reader.d.ts.map +0 -1
- package/dist/types/logger.d.ts.map +0 -1
- package/dist/types/memory.d.ts.map +0 -1
- package/dist/types/messages.d.ts.map +0 -1
- package/dist/types/mode-prompts.d.ts.map +0 -1
- package/dist/types/mode.d.ts.map +0 -1
- package/dist/types/models-registry.d.ts.map +0 -1
- package/dist/types/multi-agent.d.ts.map +0 -1
- package/dist/types/observability.d.ts.map +0 -1
- package/dist/types/one-shot-llm.d.ts.map +0 -1
- package/dist/types/path-resolver.d.ts.map +0 -1
- package/dist/types/permission.d.ts.map +0 -1
- package/dist/types/plugin.d.ts.map +0 -1
- package/dist/types/prompt-registry.d.ts.map +0 -1
- package/dist/types/prompt.d.ts.map +0 -1
- package/dist/types/provider-runner.d.ts.map +0 -1
- package/dist/types/provider.d.ts.map +0 -1
- package/dist/types/quota-regex.d.ts.map +0 -1
- package/dist/types/renderer.d.ts.map +0 -1
- package/dist/types/retry-policy.d.ts.map +0 -1
- package/dist/types/secret-scrubber.d.ts.map +0 -1
- package/dist/types/secret-vault.d.ts.map +0 -1
- package/dist/types/selector.d.ts.map +0 -1
- package/dist/types/session-markers.d.ts.map +0 -1
- package/dist/types/session-markers.js.map +0 -7
- package/dist/types/session-reader.d.ts.map +0 -1
- package/dist/types/session-rewinder.d.ts.map +0 -1
- package/dist/types/session.d.ts.map +0 -1
- package/dist/types/side-effect.d.ts.map +0 -1
- package/dist/types/skill.d.ts.map +0 -1
- package/dist/types/slash-command.d.ts.map +0 -1
- package/dist/types/spec.d.ts.map +0 -1
- package/dist/types/system-prompt-contributor.d.ts.map +0 -1
- package/dist/types/system-prompt.d.ts.map +0 -1
- package/dist/types/task-graph.d.ts.map +0 -1
- package/dist/types/token-counter.d.ts.map +0 -1
- package/dist/types/tool-executor.d.ts.map +0 -1
- package/dist/types/tool-markers.d.ts.map +0 -1
- package/dist/types/tool.d.ts.map +0 -1
- package/dist/types/utility-types.d.ts.map +0 -1
- package/dist/utils/assert-never.d.ts.map +0 -1
- package/dist/utils/atomic-write.d.ts.map +0 -1
- package/dist/utils/cache-key.d.ts.map +0 -1
- package/dist/utils/child-env.d.ts.map +0 -1
- package/dist/utils/color.d.ts.map +0 -1
- package/dist/utils/compaction-preview.d.ts.map +0 -1
- package/dist/utils/config-backup.d.ts.map +0 -1
- package/dist/utils/config-json.d.ts.map +0 -1
- package/dist/utils/connectivity.d.ts.map +0 -1
- package/dist/utils/context-breakdown.d.ts.map +0 -1
- package/dist/utils/context-evidence.d.ts.map +0 -1
- package/dist/utils/continuous-memory-profiler.d.ts.map +0 -1
- package/dist/utils/crash-shield.d.ts.map +0 -1
- package/dist/utils/deep-merge.d.ts.map +0 -1
- package/dist/utils/diff.d.ts.map +0 -1
- package/dist/utils/error.d.ts.map +0 -1
- package/dist/utils/error.js.map +0 -7
- package/dist/utils/expect-defined.d.ts.map +0 -1
- package/dist/utils/expect-defined.js.map +0 -7
- package/dist/utils/glob-expand.d.ts.map +0 -1
- package/dist/utils/glob-match.d.ts.map +0 -1
- package/dist/utils/heap-watchdog-types.d.ts.map +0 -1
- package/dist/utils/heap-watchdog.d.ts.map +0 -1
- package/dist/utils/heap-watchdog.js.map +0 -7
- package/dist/utils/incoming-images.d.ts.map +0 -1
- package/dist/utils/index.d.ts.map +0 -1
- package/dist/utils/index.js.map +0 -7
- package/dist/utils/instruction-file.d.ts.map +0 -1
- package/dist/utils/ip-guard.d.ts.map +0 -1
- package/dist/utils/json-repair.d.ts.map +0 -1
- package/dist/utils/json-schema-validate.d.ts.map +0 -1
- package/dist/utils/lru-cache.d.ts.map +0 -1
- package/dist/utils/memory-flight-recorder.d.ts.map +0 -1
- package/dist/utils/merge-custom-models.d.ts.map +0 -1
- package/dist/utils/merge-models-payload.d.ts.map +0 -1
- package/dist/utils/message-invariants.d.ts.map +0 -1
- package/dist/utils/newline-normalize.d.ts.map +0 -1
- package/dist/utils/perf-profile.d.ts.map +0 -1
- package/dist/utils/pid.d.ts.map +0 -1
- package/dist/utils/project-identity.d.ts.map +0 -1
- package/dist/utils/project-watch.d.ts.map +0 -1
- package/dist/utils/regex-guard.d.ts.map +0 -1
- package/dist/utils/safe-json.d.ts.map +0 -1
- package/dist/utils/sage-output-block.d.ts.map +0 -1
- package/dist/utils/session-scoped-path.d.ts.map +0 -1
- package/dist/utils/sleep.d.ts.map +0 -1
- package/dist/utils/slug.d.ts.map +0 -1
- package/dist/utils/socket-path.d.ts.map +0 -1
- package/dist/utils/sqlite-warning.d.ts.map +0 -1
- package/dist/utils/string.d.ts.map +0 -1
- package/dist/utils/task-format.d.ts.map +0 -1
- package/dist/utils/term.d.ts.map +0 -1
- package/dist/utils/todos-format.d.ts.map +0 -1
- package/dist/utils/token-estimate.d.ts.map +0 -1
- package/dist/utils/tool-description-mode.d.ts.map +0 -1
- package/dist/utils/tool-name.d.ts.map +0 -1
- package/dist/utils/tool-output-serializer.d.ts.map +0 -1
- package/dist/utils/tool-result-render-mode.d.ts.map +0 -1
- package/dist/utils/tool-subject.d.ts.map +0 -1
- package/dist/utils/tool-wire-compact.d.ts.map +0 -1
- package/dist/utils/tree-kill.d.ts.map +0 -1
- package/dist/utils/tree-kill.js.map +0 -7
- package/dist/utils/ulid.d.ts.map +0 -1
- package/dist/utils/walk-ignore.d.ts.map +0 -1
- package/dist/utils/wstack-paths.d.ts.map +0 -1
- package/dist/worktree/index.d.ts.map +0 -1
- package/dist/worktree/index.js.map +0 -7
- package/dist/worktree/worktree-git.d.ts.map +0 -1
- package/dist/worktree/worktree-managed-ops.d.ts.map +0 -1
- package/dist/worktree/worktree-manager.d.ts.map +0 -1
- package/dist/worktree/worktree-types.d.ts.map +0 -1
package/dist/plugin/index.js.map
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../src/utils/error.ts", "../../src/types/errors.ts", "../../src/utils/atomic-write.ts", "../../src/plugins/review-finding-types.ts", "../../src/plugins/review-finding-store.ts", "../../src/plugins/review-report-types.ts", "../../src/plugins/review-report-store.ts", "../../src/utils/expect-defined.ts", "../../src/extension/registry.ts", "../../src/plugin/loader.ts", "../../src/utils/json-schema-validate.ts", "../../src/plugin/config.ts", "../../src/plugin/api.ts", "../../src/plugins/auto-review-plugin.ts", "../../src/core/model-ref.ts", "../../src/core/model-availability-calendar.ts", "../../src/core/fallback-profile-manager.ts", "../../src/plugins/review-claim-registry.ts", "../../src/plugins/review-context-builder.ts", "../../src/chronicle/project-access.ts", "../../src/utils/wstack-paths.ts", "../../src/chronicle/identity.ts", "../../src/chronicle/journal.ts", "../../src/chronicle/event-hash.ts", "../../src/chronicle/partition-filename.ts", "../../src/chronicle/types.ts", "../../src/chronicle/metrics-store.ts", "../../src/utils/sqlite-warning.ts", "../../src/chronicle/query.ts", "../../src/chronicle/partition-range-cache.ts", "../../src/chronicle/legacy-journal-import.ts", "../../src/chronicle/sqlite-journal.ts", "../../src/utils/index.ts", "../../src/utils/term.ts", "../../src/utils/color.ts", "../../src/skills/limits.ts", "../../src/utils/instruction-file.ts", "../../src/utils/ulid.ts", "../../src/utils/slug.ts", "../../src/chronicle/sqlite-query.ts", "../../src/chronicle/project-server-client.ts", "../../src/chronicle/project-server-endpoint.ts", "../../src/chronicle/project-server-protocol.ts", "../../src/plugins/chimera-plugin.ts", "../../src/plugins/review-finding-commands.ts", "../../src/plugins/review-finding-parser.ts", "../../src/plugins/review-report-integration.ts", "../../src/plugins/review-finding-integration.ts", "../../src/plugins/prompts-plugin.ts", "../../src/execution/prompt-loader.ts", "../../src/storage/prompt-store.ts", "../../src/types/prompt.ts", "../../src/storage/prompt-usage-store.ts", "../../src/plugins/skills-plugin.ts", "../../src/skills/foreign-sources.ts", "../../src/skills/registry/github-direct-adapter.ts", "../../src/skills/registry/skills-sh-adapter.ts", "../../src/skills/skill-generator.ts", "../../src/skills/frontmatter.ts", "../../src/skills/skill-installer.ts", "../../src/skills/github-fetcher.ts", "../../src/skills/manifest-store.ts", "../../src/plugins/sync-plugin.ts", "../../src/storage/cloud-sync.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Converts an unknown error value to a human-readable string.\n * Used in 40+ files across the codebase to normalize error messaging.\n */\nexport function toErrorMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n", "import { toErrorMessage } from '../utils/error.js';\n\n/**\n * WrongStack error hierarchy.\n *\n * Every error thrown by the framework is a `WrongStackError` with a\n * machine-readable `code`, a `subsystem` tag, and a `severity` level.\n * This lets consumers (CLI, TUI, plugins, tests) branch on structured\n * data instead of parsing error messages.\n */\n\n// \u2500\u2500 Error codes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Machine-readable error codes as frozen constants.\n *\n * Use `ERROR_CODES.X` instead of raw string literals for:\n * - IDE autocomplete and compile-time validation\n * - Safe refactoring (rename updates all usages)\n * - Plugin extensibility (extend the object to add custom codes)\n *\n * The `ErrorCode` type is derived from this object, so adding a new\n * code here automatically updates the type without extra changes.\n */\nexport const ERROR_CODES = {\n // Provider\n PROVIDER_RATE_LIMITED: 'PROVIDER_RATE_LIMITED',\n PROVIDER_AUTH_FAILED: 'PROVIDER_AUTH_FAILED',\n PROVIDER_OVERLOADED: 'PROVIDER_OVERLOADED',\n PROVIDER_INVALID_REQUEST: 'PROVIDER_INVALID_REQUEST',\n PROVIDER_SERVER_ERROR: 'PROVIDER_SERVER_ERROR',\n PROVIDER_NETWORK_ERROR: 'PROVIDER_NETWORK_ERROR',\n PROVIDER_CONTEXT_OVERFLOW: 'PROVIDER_CONTEXT_OVERFLOW',\n // Tool\n TOOL_NOT_FOUND: 'TOOL_NOT_FOUND',\n TOOL_PERMISSION_DENIED: 'TOOL_PERMISSION_DENIED',\n TOOL_EXECUTION_FAILED: 'TOOL_EXECUTION_FAILED',\n TOOL_TIMEOUT: 'TOOL_TIMEOUT',\n TOOL_INPUT_INVALID: 'TOOL_INPUT_INVALID',\n // Config\n CONFIG_INVALID: 'CONFIG_INVALID',\n CONFIG_NOT_FOUND: 'CONFIG_NOT_FOUND',\n CONFIG_PARSE_FAILED: 'CONFIG_PARSE_FAILED',\n CONFIG_MIGRATION_NEEDED: 'CONFIG_MIGRATION_NEEDED',\n // Plugin\n PLUGIN_LOAD_FAILED: 'PLUGIN_LOAD_FAILED',\n PLUGIN_API_MISMATCH: 'PLUGIN_API_MISMATCH',\n PLUGIN_MISSING_DEPENDENCY: 'PLUGIN_MISSING_DEPENDENCY',\n // Agent\n AGENT_ITERATION_LIMIT: 'AGENT_ITERATION_LIMIT',\n AGENT_CONTEXT_OVERFLOW: 'AGENT_CONTEXT_OVERFLOW',\n AGENT_ABORTED: 'AGENT_ABORTED',\n AGENT_RUN_FAILED: 'AGENT_RUN_FAILED',\n // Session\n SESSION_NOT_FOUND: 'SESSION_NOT_FOUND',\n SESSION_CORRUPTED: 'SESSION_CORRUPTED',\n SESSION_WRITE_FAILED: 'SESSION_WRITE_FAILED',\n // Container / Registry\n CONTAINER_TOKEN_ALREADY_BOUND: 'CONTAINER_TOKEN_ALREADY_BOUND',\n CONTAINER_TOKEN_NOT_BOUND: 'CONTAINER_TOKEN_NOT_BOUND',\n CONTAINER_CIRCULAR_DEPENDENCY: 'CONTAINER_CIRCULAR_DEPENDENCY',\n REGISTRY_DUPLICATE: 'REGISTRY_DUPLICATE',\n REGISTRY_NOT_FOUND: 'REGISTRY_NOT_FOUND',\n REGISTRY_INVALID: 'REGISTRY_INVALID',\n // File system\n FS_READ_FAILED: 'FS_READ_FAILED',\n FS_WRITE_FAILED: 'FS_WRITE_FAILED',\n FS_MKDIR_FAILED: 'FS_MKDIR_FAILED',\n FS_DELETE_FAILED: 'FS_DELETE_FAILED',\n FS_ATOMIC_WRITE_FAILED: 'FS_ATOMIC_WRITE_FAILED',\n // SDD (Spec-Driven Development)\n SDD_VALIDATION_FAILED: 'SDD_VALIDATION_FAILED',\n SDD_PARSE_FAILED: 'SDD_PARSE_FAILED',\n SDD_INVALID_STATE: 'SDD_INVALID_STATE',\n SDD_NOT_READY: 'SDD_NOT_READY',\n // General\n VALIDATION_ERROR: 'VALIDATION_ERROR',\n PARSE_FAILED: 'PARSE_FAILED',\n UNKNOWN: 'UNKNOWN',\n} as const;\n\n/**\n * Union type derived from `ERROR_CODES`. Using `typeof ERROR_CODES[keyof typeof ERROR_CODES]`\n * instead of a string literal union means TypeScript auto-updates the type whenever\n * a new code is added to `ERROR_CODES` \u2014 no need to keep two lists in sync.\n */\nexport type ErrorCode = (typeof ERROR_CODES)[keyof typeof ERROR_CODES];\n\nexport type ErrorSubsystem =\n | 'provider'\n | 'tool'\n | 'config'\n | 'plugin'\n | 'agent'\n | 'session'\n | 'sdd'\n | 'container'\n | 'fs'\n | 'general';\nexport type ErrorSeverity = 'fatal' | 'error' | 'warning';\n\n// \u2500\u2500 Base error class \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class WrongStackError extends Error {\n readonly code: ErrorCode;\n readonly subsystem: ErrorSubsystem;\n readonly severity: ErrorSeverity;\n readonly recoverable: boolean;\n readonly context?: Record<string, unknown> | undefined;\n\n constructor(opts: {\n message: string;\n code: ErrorCode;\n subsystem: ErrorSubsystem;\n severity?: ErrorSeverity | undefined;\n recoverable?: boolean | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super(opts.message, { cause: opts.cause });\n this.name = 'WrongStackError';\n this.code = opts.code;\n this.subsystem = opts.subsystem;\n this.severity = opts.severity ?? 'error';\n this.recoverable = opts.recoverable ?? false;\n this.context = opts.context;\n }\n\n /**\n * Render a one-line user-facing description.\n * Subclasses should override for domain-specific formatting.\n */\n describe(): string {\n const ctx = this.context ? ` ${formatContext(this.context)}` : '';\n return `${this.code}: ${this.message}${ctx}`;\n }\n}\n\nfunction formatContext(ctx: Record<string, unknown>): string {\n const parts = Object.entries(ctx)\n .filter(([, v]) => v !== undefined)\n .slice(0, 3)\n .map(([k, v]) => `${k}=${String(v)}`);\n return parts.length > 0 ? `[${parts.join(' ')}]` : '';\n}\n\n// \u2500\u2500 Specific error classes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Tool execution errors \u2014 thrown by ToolExecutor and individual tools.\n */\nexport class ToolError extends WrongStackError {\n readonly toolName: string;\n\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n | 'TOOL_NOT_FOUND'\n | 'TOOL_PERMISSION_DENIED'\n | 'TOOL_EXECUTION_FAILED'\n | 'TOOL_TIMEOUT'\n | 'TOOL_INPUT_INVALID'\n >;\n toolName: string;\n recoverable?: boolean | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'tool',\n recoverable: opts.recoverable,\n context: { tool: opts.toolName, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'ToolError';\n this.toolName = opts.toolName;\n }\n}\n\n/**\n * Config loading / validation errors.\n */\nexport class ConfigError extends WrongStackError {\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n 'CONFIG_INVALID' | 'CONFIG_NOT_FOUND' | 'CONFIG_PARSE_FAILED' | 'CONFIG_MIGRATION_NEEDED'\n >;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'config',\n severity: 'fatal',\n recoverable: false,\n context: opts.context,\n cause: opts.cause,\n });\n this.name = 'ConfigError';\n }\n}\n\n/**\n * Plugin loading / lifecycle errors.\n */\nexport class PluginError extends WrongStackError {\n readonly pluginName: string;\n\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n 'PLUGIN_LOAD_FAILED' | 'PLUGIN_API_MISMATCH' | 'PLUGIN_MISSING_DEPENDENCY'\n >;\n pluginName: string;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'plugin',\n severity: 'error',\n recoverable: opts.code === ERROR_CODES.PLUGIN_MISSING_DEPENDENCY,\n context: { plugin: opts.pluginName, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'PluginError';\n this.pluginName = opts.pluginName;\n }\n}\n\n/**\n * Agent runtime errors \u2014 thrown by Agent.run when a non-WrongStackError\n * escapes the inner loop, so callers always see a structured error.\n */\nexport class AgentError extends WrongStackError {\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n 'AGENT_ITERATION_LIMIT' | 'AGENT_CONTEXT_OVERFLOW' | 'AGENT_ABORTED' | 'AGENT_RUN_FAILED'\n >;\n recoverable?: boolean | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'agent',\n severity: opts.code === ERROR_CODES.AGENT_ABORTED ? 'warning' : 'error',\n recoverable: opts.recoverable ?? opts.code === ERROR_CODES.AGENT_ITERATION_LIMIT,\n context: opts.context,\n cause: opts.cause,\n });\n this.name = 'AgentError';\n }\n}\n\n/**\n * Wrap an arbitrary thrown value into a `WrongStackError` so the caller\n * always gets a structured error. Pass-throughs WrongStackError instances\n * unchanged; raw `Error`s and primitives get an `AGENT_RUN_FAILED` wrapper\n * with the original preserved as `cause`.\n */\nexport function toWrongStackError(\n err: unknown,\n code: Extract<ErrorCode, 'AGENT_RUN_FAILED' | 'AGENT_ABORTED' | 'UNKNOWN'> = ERROR_CODES.AGENT_RUN_FAILED,\n): WrongStackError {\n if (err instanceof WrongStackError) return err;\n const message = toErrorMessage(err);\n return new AgentError({\n message,\n code: code === 'UNKNOWN' ? ERROR_CODES.AGENT_RUN_FAILED : code,\n cause: err,\n });\n}\n\n/**\n * Session storage errors.\n */\nexport class SessionError extends WrongStackError {\n readonly sessionId?: string | undefined;\n\n constructor(opts: {\n message: string;\n code: Extract<ErrorCode, 'SESSION_NOT_FOUND' | 'SESSION_CORRUPTED' | 'SESSION_WRITE_FAILED'>;\n sessionId?: string | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'session',\n severity: opts.code === ERROR_CODES.SESSION_WRITE_FAILED ? 'error' : 'warning',\n recoverable: opts.code !== ERROR_CODES.SESSION_CORRUPTED,\n context: { sessionId: opts.sessionId, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'SessionError';\n this.sessionId = opts.sessionId;\n }\n}\n\n/**\n * SDD (Spec-Driven Development) errors \u2014 spec validation, parsing, and\n * state machine violations in the AISpecBuilder, TaskFlow, and TaskTracker.\n */\nexport class SddError extends WrongStackError {\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n 'SDD_VALIDATION_FAILED' | 'SDD_PARSE_FAILED' | 'SDD_INVALID_STATE' | 'SDD_NOT_READY'\n >;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'sdd',\n severity: opts.code === ERROR_CODES.SDD_PARSE_FAILED ? 'warning' : 'error',\n recoverable: opts.code === ERROR_CODES.SDD_NOT_READY,\n context: opts.context,\n cause: opts.cause,\n });\n this.name = 'SddError';\n }\n}\n\n/**\n * File system operation errors.\n */\nexport class FsError extends WrongStackError {\n readonly path?: string | undefined;\n\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n 'FS_READ_FAILED' | 'FS_WRITE_FAILED' | 'FS_MKDIR_FAILED' | 'FS_DELETE_FAILED' | 'FS_ATOMIC_WRITE_FAILED'\n >;\n path?: string | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'fs',\n severity: 'error',\n recoverable: opts.code !== ERROR_CODES.FS_READ_FAILED,\n context: { path: opts.path, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'FsError';\n this.path = opts.path;\n }\n}\n\n/**\n * HTTP fetch error \u2014 thrown when a network request returns a non-OK status.\n * Carries the response status so {@link classifyToolError} can branch on it\n * (429 \u2192 transient, 404 \u2192 not_found, 401 \u2192 permission) without duck-typing\n * the error via `'response' in err`.\n *\n * P3 #18 (before-release.md): the previous `'response' in err` check caught\n * any Error with a `response` property, including custom errors, proxy\n * objects, or mocked errors in tests. `instanceof FetchError` is reliable.\n *\n * Tools and providers that make HTTP requests and need the executor to\n * classify their failures should throw `new FetchError({ status, message })`\n * instead of a bare `Error` with an ad-hoc `response` field.\n */\nexport class FetchError extends WrongStackError {\n readonly status: number;\n\n constructor(opts: {\n message: string;\n status: number;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: ERROR_CODES.VALIDATION_ERROR,\n subsystem: 'general',\n severity: 'error',\n recoverable: opts.status === 429 || opts.status >= 500,\n context: { status: opts.status, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'FetchError';\n this.status = opts.status;\n }\n}\n\n/**\n * Tool input validation error \u2014 thrown when a tool's input fails a validation\n * check that the JSON Schema cannot express (e.g. `old_string === new_string`\n * in edit, or a cross-field invariant). Use this instead of a bare\n * `throw new Error('...validation...')` so {@link classifyToolError} can\n * match on `instanceof` rather than a locale-dependent message substring.\n *\n * P2 #6 (before-release.md): the previous `err.message.includes('validation')`\n * check misclassified any error whose message happened to contain \"validation\"\n * (e.g. a third-party \"input validation timeout\") as a VALIDATION error.\n *\n * Named `ToolValidationError` (not `ValidationError`) to avoid colliding with\n * the existing `ValidationError` interface exported by json-schema-validate.ts\n * (a validation-result shape, not an Error subclass).\n */\nexport class ToolValidationError extends WrongStackError {\n constructor(opts: {\n message: string;\n /** Field path or tool name that failed validation, for diagnostics. */\n field?: string | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: ERROR_CODES.VALIDATION_ERROR,\n subsystem: 'general',\n severity: 'error',\n recoverable: false,\n context: { field: opts.field, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'ToolValidationError';\n }\n}\n\n/**\n * Response / payload parse error \u2014 thrown when an upstream HTTP response,\n * file, or data structure is well-formed at the transport layer (HTTP 200,\n * valid JSON) but is missing required fields or has an unexpected shape.\n *\n * Distinct from `ConfigError(CONFIG_PARSE_FAILED)` (which is specifically\n * for config-file parsing) and `FetchError` (which covers HTTP non-OK\n * responses). `ParseError` fills the gap: the request succeeded but the\n * response body couldn't be interpreted.\n *\n * Common sites: OAuth token responses missing `access_token`, device-code\n * responses missing `device_code`, registry responses with unexpected\n * schemas.\n */\nexport class ParseError extends WrongStackError {\n readonly source?: string | undefined;\n\n constructor(opts: {\n message: string;\n /**\n * What was being parsed \u2014 e.g. `'oauth-token-response'`,\n * `'device-code-response'`. Lets consumers distinguish parse failures\n * from different upstream APIs without parsing the message.\n */\n source?: string | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: ERROR_CODES.PARSE_FAILED,\n subsystem: 'general',\n severity: 'error',\n recoverable: false,\n context: { source: opts.source, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'ParseError';\n this.source = opts.source;\n }\n}\n\n// \u2500\u2500 Type guards \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport function isWrongStackError(err: unknown): err is WrongStackError {\n return err instanceof WrongStackError;\n}\n\nexport function isToolError(err: unknown): err is ToolError {\n return err instanceof ToolError;\n}\n\nexport function isConfigError(err: unknown): err is ConfigError {\n return err instanceof ConfigError;\n}\n\nexport function isPluginError(err: unknown): err is PluginError {\n return err instanceof PluginError;\n}\n\nexport function isSessionError(err: unknown): err is SessionError {\n return err instanceof SessionError;\n}\n\nexport function isAgentError(err: unknown): err is AgentError {\n return err instanceof AgentError;\n}\n\nexport function isFsError(err: unknown): err is FsError {\n return err instanceof FsError;\n}\n\nexport function isToolValidationError(err: unknown): err is ToolValidationError {\n return err instanceof ToolValidationError;\n}\n\nexport function isFetchError(err: unknown): err is FetchError {\n return err instanceof FetchError;\n}\n\nexport function isParseError(err: unknown): err is ParseError {\n return err instanceof ParseError;\n}\n\nexport function isSddError(err: unknown): err is SddError {\n return err instanceof SddError;\n}\n", "import type { FileHandle } from 'node:fs/promises';\nimport {\n type AtomicWriteOptions,\n createPersistencePrimitives,\n type FileLockOptions,\n} from '@wrongstack/persistence';\nimport { FsError } from '../types/errors.js';\n\nexport type { AtomicWriteOptions, FileLockOptions } from '@wrongstack/persistence';\n\nconst primitives = createPersistencePrimitives({\n createLockTimeoutError: ({ targetPath, timeoutMs }) =>\n new FsError({\n message: `Timed out waiting for file lock: ${targetPath}`,\n code: 'FS_ATOMIC_WRITE_FAILED',\n path: targetPath,\n context: { timeoutMs },\n }),\n});\n\nexport const atomicWrite: (\n targetPath: string,\n content: string | Uint8Array,\n opts?: AtomicWriteOptions,\n) => Promise<void> = primitives.atomicWrite;\n/**\n * Atomic replace that streams its new contents instead of taking them as one\n * buffer. Use when the replacement is large enough that materializing it would\n * itself be the memory problem (log rotation, tail compaction).\n */\nexport const atomicReplaceWithWriter: <T>(\n targetPath: string,\n write: (handle: FileHandle) => Promise<T>,\n opts?: AtomicWriteOptions,\n) => Promise<T> = primitives.atomicReplaceWithWriter;\nexport const ensureDir: (dir: string) => Promise<void> = primitives.ensureDir;\nexport const withFileLock: <T>(\n targetPath: string,\n fn: () => Promise<T>,\n opts?: FileLockOptions,\n) => Promise<T> = primitives.withFileLock;\n", "/**\n * Core data types for the Chimera Finding Store.\n *\n * FS-P0.0: Every finding is produced by parsing a Chimera review report,\n * deduplicated by fingerprint, and tracked through a documented lifecycle\n * state machine.\n *\n * @module review-finding-types\n */\n\n// \u2500\u2500 Severity and status \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Severity level from the report heading. */\nexport type FindingSeverity = 'critical' | 'high' | 'medium' | 'low';\n\n/**\n * Current lifecycle status of a finding.\n *\n * ```\n * found (created) \u2192 triaged \u2192 in_progress \u2192 resolved\n * \u2502 \u2502 \u2502\n * \u2514\u2192 ignored \u2500\u2500\u2500\u2500\u2500\u2500\u2192\u2502\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n * (found again) (reopened)\n * ```\n */\nexport type FindingStatus = 'active' | 'triaged' | 'in_progress' | 'resolved' | 'ignored';\n\n/** How a resolved finding was concluded. */\nexport type ResolutionOutcome =\n | 'fixed'\n | 'wontfix'\n | 'duplicate'\n | 'false_positive'\n | 'stale';\n\n/** What type of agent produced the review report. */\nexport type FindingSource = 'auto' | 'chimera' | 'cascade' | 'security-scanner';\n\n/** What kind of actor performed a lifecycle transition. */\nexport type ActorKind = 'agent' | 'operator' | 'system';\n\n// \u2500\u2500 Core types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface ChimeraFindingLocation {\n /** Project-relative file path. */\n file: string;\n /** Line number within the file, if known. */\n line?: number | undefined;\n}\n\nexport interface ChimeraFindingOrigin {\n /** Unique report run ID. */\n reportId: string;\n /** Session that triggered the review. */\n sessionId: string;\n /** Agent that was being reviewed. */\n agentId: string;\n /** Model that produced the review report. */\n reviewerModel: string;\n}\n\nexport interface ChimeraFindingResolution {\n outcome: ResolutionOutcome;\n resolvedAt: string; // ISO8601\n resolvedBy: string; // actor ID\n commitSha?: string | undefined;\n committedAt?: string | undefined;\n notes?: string | undefined;\n}\n\n/** Full finding record, written once and never mutated. */\nexport interface ChimeraFinding {\n /** Immutable UUID. */\n id: string;\n /** Content fingerprint for deduplication. */\n fingerprint: string;\n /** Severity from the report heading. */\n severity: FindingSeverity;\n /** Review kind that produced this finding. */\n source: FindingSource;\n /** Where the issue was found. */\n location?: ChimeraFindingLocation | undefined;\n /** One-line title extracted from the report item. */\n title: string;\n /** Full description paragraphs. */\n description: string;\n /** Suggested fix, if the reviewer provided one. */\n suggestedFix?: string | undefined;\n /** ISO8601 \u2014 when the finding was first created. */\n createdAt: string;\n /** Materialized current status (derived from latest lifecycle event). */\n status: FindingStatus;\n /** Set only when status === 'resolved'. */\n resolution?: ChimeraFindingResolution | undefined;\n /** Original review context that produced this finding. */\n originReport: ChimeraFindingOrigin;\n}\n\n// \u2500\u2500 Lifecycle event types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport type FindingEventType =\n | 'created'\n | 'relinked'\n | 'reopened'\n | 'triaged'\n | 'started'\n | 'resolved'\n | 'ignored'\n | 'compacted';\n\n/** A single state-transition event in a finding's lifecycle. */\nexport interface FindingLifecycleEvent {\n id: string;\n findingId: string;\n eventType: FindingEventType;\n fromStatus: FindingStatus | null;\n toStatus: FindingStatus;\n actorId: string;\n actorKind: ActorKind;\n timestamp: string; // ISO8601\n reason?: string | undefined;\n}\n\n// \u2500\u2500 Error classes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class FindingNotFoundError extends Error {\n readonly findingId: string;\n constructor(findingId: string) {\n super(`Finding not found: ${findingId}`);\n this.name = 'FindingNotFoundError';\n this.findingId = findingId;\n }\n}\n\nexport class InvalidTransitionError extends Error {\n readonly from: FindingStatus;\n readonly to: FindingStatus;\n constructor(from: FindingStatus, to: FindingStatus, reason?: string) {\n const msg = reason ?? `Invalid transition from \"${from}\" to \"${to}\"`;\n super(msg);\n this.name = 'InvalidTransitionError';\n this.from = from;\n this.to = to;\n }\n}\n\nexport class FindingStoreLockError extends Error {\n readonly path: string;\n constructor(path: string, cause?: string) {\n super(`Could not acquire finding store lock: ${path}${cause ? ` (${cause})` : ''}`);\n this.name = 'FindingStoreLockError';\n this.path = path;\n }\n}\n\n// \u2500\u2500 Fingerprint \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nimport { createHash } from 'node:crypto';\n\n/** Normalize a title for fingerprinting: lowercase, strip trailing punctuation, collapse whitespace. */\nexport function normalizeFingerprintTitle(title: string): string {\n return title\n .trim()\n .toLowerCase()\n .replace(/[^\\w\\s]/g, '') // strip punctuation\n .replace(/\\s+/g, ' ') // collapse whitespace\n .trim();\n}\n\n/**\n * Generate a deterministic fingerprint for a finding.\n *\n * Fingerprint = SHA256(file + \":\" + line + \":\" + normalizedTitle).\n *\n * When `line` is null/undefined, 0 is used so the fingerprint still\n * provides deduplication for findings without a specific line.\n */\nexport function computeFindingFingerprint(\n file: string,\n line: number | undefined | null,\n title: string,\n): string {\n const normalizedTitle = normalizeFingerprintTitle(title);\n const normalizedFile = file.replace(/\\\\/g, '/').trim().toLowerCase();\n const lineStr = line != null && line >= 0 ? String(line) : '0';\n const hash = createHash('sha256');\n hash.update(`${normalizedFile}:${lineStr}:${normalizedTitle}`);\n return hash.digest('hex');\n}\n\n// \u2500\u2500 Transition state machine \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst TRANSITION_MATRIX: Record<FindingStatus, ReadonlySet<FindingStatus>> = {\n active: new Set(['triaged', 'ignored', 'resolved']),\n triaged: new Set(['in_progress', 'ignored', 'resolved']),\n in_progress: new Set(['resolved', 'active']),\n ignored: new Set(['active']),\n resolved: new Set(['active']),\n};\n\n/**\n * Check whether a status transition is valid per the state machine.\n * Throws InvalidTransitionError for invalid transitions.\n */\nexport function validateTransition(\n from: FindingStatus,\n to: FindingStatus,\n): void {\n if (from === to) return; // same status is idempotent\n const allowed = TRANSITION_MATRIX[from];\n if (!allowed?.has(to)) {\n throw new InvalidTransitionError(from, to);\n }\n}\n\n/**\n * Resolve transitions requires an outcome.\n */\nexport function validateResolution(\n status: FindingStatus,\n outcome?: ResolutionOutcome | undefined,\n): void {\n if (status !== 'resolved') return;\n if (!outcome) {\n throw new InvalidTransitionError(\n 'active',\n 'resolved',\n 'A resolution outcome is required when transitioning to \"resolved\"',\n );\n }\n}\n", "/**\n * Chimera Finding Store \u2014 persistent JSONL store with lifecycle tracking.\n *\n * FS-P0.1 through FS-P0.4\n *\n * @module review-finding-store\n */\n\nimport { randomUUID } from 'node:crypto';\nimport * as fsp from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { atomicWrite, withFileLock } from '../utils/atomic-write.js';\nimport type {\n ChimeraFinding,\n FindingEventType,\n FindingLifecycleEvent,\n FindingSeverity,\n FindingStatus,\n ResolutionOutcome,\n} from './review-finding-types.js';\nimport {\n validateTransition,\n validateResolution,\n} from './review-finding-types.js';\n\n// \u2500\u2500 Constants \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Default retention for resolved findings (30 days in ms). */\nexport const FINDING_RESOLVED_RETENTION_MS = 30 * 24 * 60 * 60 * 1000;\n\n/** Default retention for ignored/wontfix findings (14 days in ms). */\nexport const FINDING_IGNORED_RETENTION_MS = 14 * 24 * 60 * 60 * 1000;\n\n/** Max findings returned by list() without a limit. */\nexport const FINDING_DEFAULT_PAGE_SIZE = 50;\n\n/** JSONL separator. */\nconst NL = '\\n';\nconst LINE_SEPARATOR = NL;\n\n// \u2500\u2500 File name \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** File name for the finding store JSONL file. */\nexport const FINDING_STORE_FILE = 'review-findings.jsonl';\n\n/** Resolve the absolute path to the finding store file. */\nexport function resolveFindingStorePath(projectDir: string): string {\n return path.join(projectDir, FINDING_STORE_FILE);\n}\n\n// \u2500\u2500 JSONL record types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** JSONL record discriminator for a finding record. */\ninterface FindingRecord {\n __finding: 1;\n data: ChimeraFinding;\n}\n\n/** JSONL record discriminator for a lifecycle event. */\ninterface LifecycleEventRecord {\n __findingEvent: 1;\n data: FindingLifecycleEvent;\n}\n\n/** JSONL record discriminator for a compaction marker. */\ninterface CompactMarker {\n __findingCompact: 1;\n compactedAt: string;\n removedFindings: number;\n foldedEvents: number;\n}\n\n// \u2500\u2500 Store implementation \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface UpsertResult {\n created: number;\n relinked: number;\n reopened: number;\n}\n\nexport interface UpsertContext {\n sessionId: string;\n reportId: string;\n agentId: string;\n model: string;\n}\n\nexport interface ListOptions {\n severities?: FindingSeverity[] | undefined;\n statuses?: FindingStatus[] | undefined;\n file?: string | undefined;\n /** Filter to findings from a specific review report. */\n reportId?: string | undefined;\n limit?: number | undefined;\n}\n\nexport interface CompactOptions {\n /** Resolved/ignored findings older than this (ms) are eligible. Default: FINDING_RESOLVED_RETENTION_MS. */\n resolvedMaxAgeMs?: number | undefined;\n /** Ignored findings use this separately. Default: FINDING_IGNORED_RETENTION_MS. */\n ignoredMaxAgeMs?: number | undefined;\n}\n\nexport interface FindingStore {\n upsert(findings: ChimeraFinding[], context: UpsertContext): Promise<UpsertResult>;\n transition(\n findingId: string,\n to: FindingStatus,\n actor: { id: string; kind: 'agent' | 'operator' | 'system' },\n opts?: { reason?: string; outcome?: ResolutionOutcome },\n ): Promise<ChimeraFinding>;\n list(opts?: ListOptions): Promise<ChimeraFinding[]>;\n get(idOrFingerprint: string): Promise<ChimeraFinding | null>;\n getEvents(findingId: string): Promise<FindingLifecycleEvent[]>;\n compact(opts?: CompactOptions): Promise<{ removed: number; eventsFolded: number }>;\n}\n\nexport class JsonlFindingStore implements FindingStore {\n private readonly filePath: string;\n\n constructor(projectDir: string) {\n this.filePath = resolveFindingStorePath(projectDir);\n }\n\n get storePath(): string {\n return this.filePath;\n }\n\n // \u2500\u2500 Path helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n async upsert(\n newFindings: ChimeraFinding[],\n context: UpsertContext,\n ): Promise<UpsertResult> {\n if (newFindings.length === 0) return { created: 0, relinked: 0, reopened: 0 };\n\n const result: UpsertResult = { created: 0, relinked: 0, reopened: 0 };\n\n const existing = await this._readAll();\n\n return withFileLock(this.filePath, async () => {\n for (const finding of newFindings) {\n const match = existing.find((e) => e.finding.fingerprint === finding.fingerprint);\n if (match) {\n // Materialize current status from events before checking reopen eligibility.\n const materialized = this._materialize(match);\n if (materialized.status === 'resolved' || materialized.status === 'ignored') {\n const reopenEvent = this._makeEvent(match.finding.id, 'reopened', materialized.status, 'active', context);\n match.finding.status = 'active';\n match.finding.resolution = undefined;\n // Re-persist the finding record so status + cleared resolution survive reads.\n const updatedRecord: FindingRecord = { __finding: 1, data: match.finding };\n await fsp.appendFile(\n this.filePath,\n JSON.stringify(updatedRecord) + LINE_SEPARATOR +\n JSON.stringify({ __findingEvent: 1, data: reopenEvent }) + LINE_SEPARATOR,\n 'utf8',\n );\n result.reopened++;\n } else {\n const relinkEvent = this._makeEvent(match.finding.id, 'relinked', match.finding.status, match.finding.status, context);\n await fsp.appendFile(this.filePath, JSON.stringify({ __findingEvent: 1, data: relinkEvent }) + LINE_SEPARATOR, 'utf8');\n result.relinked++;\n }\n } else {\n // New finding \u2014 append the record and a created event.\n const record: FindingRecord = { __finding: 1, data: finding };\n const createdEvent = this._makeEvent(finding.id, 'created', null, 'active', context);\n const lines =\n JSON.stringify(record) + LINE_SEPARATOR +\n JSON.stringify({ __findingEvent: 1, data: createdEvent }) + LINE_SEPARATOR;\n await fsp.appendFile(this.filePath, lines, 'utf8');\n result.created++;\n }\n }\n return result;\n });\n }\n\n async transition(\n findingId: string,\n to: FindingStatus,\n actor: { id: string; kind: 'agent' | 'operator' | 'system' },\n opts?: { reason?: string; outcome?: ResolutionOutcome },\n ): Promise<ChimeraFinding> {\n const all = await this._readAll();\n const entry = all.find((e) => e.finding.id === findingId);\n if (!entry) throw new Error(`Finding not found: ${findingId}`);\n\n const from = entry.finding.status;\n validateTransition(from, to);\n validateResolution(to, opts?.outcome);\n\n const event: FindingLifecycleEvent = {\n id: randomUUID(),\n findingId,\n eventType: to === 'resolved' ? 'resolved' : to === 'ignored' ? 'ignored' : this._eventTypeFor(to),\n fromStatus: from,\n toStatus: to,\n actorId: actor.id,\n actorKind: actor.kind,\n timestamp: new Date().toISOString(),\n reason: opts?.reason,\n };\n\n entry.finding.status = to;\n if (to === 'resolved' && opts?.outcome) {\n entry.finding.resolution = {\n outcome: opts.outcome,\n resolvedAt: event.timestamp,\n resolvedBy: actor.id,\n notes: opts.reason,\n };\n }\n\n // Re-persist the finding record so non-event fields (resolution, etc.)\n // survive _readAll + _materialize. The latest record wins on read.\n const updatedRecord: FindingRecord = { __finding: 1, data: entry.finding };\n await fsp.appendFile(\n this.filePath,\n JSON.stringify(updatedRecord) + LINE_SEPARATOR +\n JSON.stringify({ __findingEvent: 1, data: event }) + LINE_SEPARATOR,\n 'utf8',\n );\n\n return { ...entry.finding };\n }\n\n async list(opts?: ListOptions): Promise<ChimeraFinding[]> {\n const all = await this._readAll();\n let findings = all.map((e) => this._materialize(e));\n\n if (opts?.severities && opts.severities.length > 0) {\n const sevs = new Set(opts.severities);\n findings = findings.filter((f) => sevs.has(f.severity));\n }\n if (opts?.statuses && opts.statuses.length > 0) {\n const sts = new Set(opts.statuses);\n findings = findings.filter((f) => sts.has(f.status));\n }\n if (opts?.file) {\n const pattern = opts.file.toLowerCase();\n findings = findings.filter((f) => f.location?.file.toLowerCase().includes(pattern));\n }\n if (opts?.reportId) {\n findings = findings.filter((f) => f.originReport.reportId === opts.reportId);\n }\n\n // Sort by severity (critical first), then by age (oldest first).\n const severityRank: Record<FindingSeverity, number> = { critical: 0, high: 1, medium: 2, low: 3 };\n findings.sort((a, b) => {\n const sa = severityRank[a.severity] - severityRank[b.severity];\n if (sa !== 0) return sa;\n return a.createdAt.localeCompare(b.createdAt);\n });\n\n const limit = opts?.limit ?? FINDING_DEFAULT_PAGE_SIZE;\n return findings.slice(0, limit);\n }\n\n async get(idOrFingerprint: string): Promise<ChimeraFinding | null> {\n const all = await this._readAll();\n const entry = all.find(\n (e) => e.finding.id === idOrFingerprint || e.finding.fingerprint === idOrFingerprint,\n );\n return entry ? this._materialize(entry) : null;\n }\n\n async getEvents(findingId: string): Promise<FindingLifecycleEvent[]> {\n const all = await this._readAllLines();\n const events: FindingLifecycleEvent[] = [];\n for (const line of all) {\n try {\n const parsed = JSON.parse(line) as unknown;\n if (this._isLifecycleEvent(parsed) && parsed.data.findingId === findingId) {\n events.push(parsed.data);\n }\n } catch {\n // Skip malformed lines.\n }\n }\n return events.sort((a, b) => a.timestamp.localeCompare(b.timestamp));\n }\n\n async compact(opts?: CompactOptions): Promise<{ removed: number; eventsFolded: number }> {\n const resolvedMaxAge = opts?.resolvedMaxAgeMs ?? FINDING_RESOLVED_RETENTION_MS;\n const ignoredMaxAge = opts?.ignoredMaxAgeMs ?? FINDING_IGNORED_RETENTION_MS;\n const now = Date.now();\n\n const all = await this._readAll();\n const kept: Array<{ record: FindingRecord | null; events: FindingLifecycleEvent[] }> = [];\n let removed = 0;\n let eventsFolded = 0;\n\n for (const entry of all) {\n const age = now - new Date(entry.finding.createdAt).getTime();\n const isResolved = entry.finding.status === 'resolved';\n const isIgnored = entry.finding.status === 'ignored';\n const maxAge = isResolved ? resolvedMaxAge : isIgnored ? ignoredMaxAge : Infinity;\n\n if (age > maxAge && (isResolved || isIgnored)) {\n removed++;\n eventsFolded += entry.events.length;\n continue;\n }\n\n // Fold events older than maxAge into a single compacted marker.\n const oldEvents = entry.events.filter((ev) => now - new Date(ev.timestamp).getTime() > maxAge);\n if (oldEvents.length > 1) {\n eventsFolded += oldEvents.length - 1;\n // Keep only the newest event before maxAge (fold the rest).\n const newestOld = oldEvents.sort((a, b) => b.timestamp.localeCompare(a.timestamp))[0]!;\n entry.events = [newestOld, ...entry.events.filter((ev) => now - new Date(ev.timestamp).getTime() <= maxAge)];\n }\n kept.push({ record: { __finding: 1, data: entry.finding }, events: entry.events });\n }\n\n // Rewrite the file.\n const lines: string[] = [];\n for (const { record, events } of kept) {\n if (record) lines.push(JSON.stringify(record));\n for (const ev of events) {\n lines.push(JSON.stringify({ __findingEvent: 1, data: ev }));\n }\n }\n // Append a compaction marker.\n lines.push(JSON.stringify({\n __findingCompact: 1,\n compactedAt: new Date().toISOString(),\n removedFindings: removed,\n foldedEvents: eventsFolded,\n } as CompactMarker));\n\n await atomicWrite(this.filePath, lines.join(LINE_SEPARATOR) + LINE_SEPARATOR, { mode: 0o600 });\n\n return { removed, eventsFolded };\n }\n\n // \u2500\u2500 Private helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n private async _readAllLines(): Promise<string[]> {\n try {\n const raw = await fsp.readFile(this.filePath, 'utf8');\n return raw.split(LINE_SEPARATOR).filter((l) => l.trim().length > 0);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return [];\n throw err;\n }\n }\n\n private _isFindingRecord(v: unknown): v is FindingRecord {\n return typeof v === 'object' && v !== null && (v as Record<string, unknown>)['__finding'] === 1;\n }\n\n private _isLifecycleEvent(v: unknown): v is LifecycleEventRecord {\n return typeof v === 'object' && v !== null && (v as Record<string, unknown>)['__findingEvent'] === 1;\n }\n\n private async _readAll(): Promise<Array<{ finding: ChimeraFinding; events: FindingLifecycleEvent[] }>> {\n const lines = await this._readAllLines();\n const findings = new Map<string, ChimeraFinding>();\n const eventsMap = new Map<string, FindingLifecycleEvent[]>();\n\n for (const line of lines) {\n try {\n const parsed = JSON.parse(line) as unknown;\n if (this._isFindingRecord(parsed)) {\n findings.set(parsed.data.id, parsed.data);\n if (!eventsMap.has(parsed.data.id)) eventsMap.set(parsed.data.id, []);\n } else if (this._isLifecycleEvent(parsed)) {\n const list = eventsMap.get(parsed.data.findingId);\n if (list) list.push(parsed.data);\n }\n // Compact markers are informational \u2014 skip for materialization.\n } catch {\n // Skip malformed lines.\n }\n }\n\n return Array.from(findings.entries()).map(([id, finding]) => ({\n finding,\n events: eventsMap.get(id) ?? [],\n }));\n }\n\n /** Materialize a finding's current status from its events. */\n private _materialize(entry: { finding: ChimeraFinding; events: FindingLifecycleEvent[] }): ChimeraFinding {\n if (entry.events.length === 0) return { ...entry.finding };\n\n // Events are already sorted by timestamp (appended in order).\n // The latest status event defines the materialized status.\n const sorted = [...entry.events].sort((a, b) => a.timestamp.localeCompare(b.timestamp));\n const latest = sorted[sorted.length - 1]!;\n return {\n ...entry.finding,\n status: latest.toStatus,\n };\n }\n\n private _makeEvent(\n findingId: string,\n eventType: FindingEventType,\n fromStatus: FindingStatus | null,\n toStatus: FindingStatus,\n context: UpsertContext,\n ): FindingLifecycleEvent {\n return {\n id: randomUUID(),\n findingId,\n eventType,\n fromStatus,\n toStatus,\n actorId: context.agentId,\n actorKind: 'agent',\n timestamp: new Date().toISOString(),\n reason: `session:${context.sessionId} report:${context.reportId}`,\n };\n }\n\n private _eventTypeFor(to: FindingStatus): FindingEventType {\n switch (to) {\n case 'triaged': return 'triaged';\n case 'in_progress': return 'started';\n case 'resolved': return 'resolved';\n case 'ignored': return 'ignored';\n case 'active': return 'reopened';\n default: return 'created';\n }\n }\n}\n", "/**\n * Core data types for the Chimera Review Report Store.\n *\n * A ReviewReport is the top-level record produced by each completed review\n * run. It captures the full report metadata (when, who, what model, which\n * files), the raw Markdown text, severity counts, and a lifecycle that\n * tracks what was done with the report over time.\n *\n * Reports link to individual findings via a shared `reportId` (stored on\n * each finding's `originReport.reportId`). The report store is a separate\n * JSONL file from the finding store so the two have independent lifecycles\n * and retention windows.\n *\n * @module review-report-types\n */\n\nimport type { FindingSource } from './review-finding-types.js';\n\n// \u2500\u2500 Lifecycle \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Lifecycle status of a review report.\n *\n * ```\n * open (review just completed)\n * \u251C\u2192 actioned (at least one finding is being worked on or was fixed)\n * \u251C\u2192 completed (all findings resolved or ignored; report closed out)\n * \u2514\u2192 skipped (operator/agent decided not to act on this report)\n *\n * completed / skipped \u2192 open (reopened \u2014 findings resurfaced)\n * actioned \u2192 completed / skipped\n * ```\n */\nexport type ReportLifecycleStatus = 'open' | 'actioned' | 'completed' | 'skipped';\n\n/** What kind of actor performed a lifecycle transition. */\nexport type ReportActorKind = 'agent' | 'operator' | 'system';\n\n// \u2500\u2500 Core record \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Severity counts extracted from the parsed report. */\nexport interface ReviewReportCounts {\n critical: number;\n high: number;\n medium: number;\n low: number;\n}\n\n/** A file that was part of the reviewed change set. */\nexport interface ReviewReportFile {\n path: string;\n status: 'added' | 'modified';\n}\n\n/**\n * A completed Chimera review report \u2014 the full record of one review run.\n *\n * One report is created per `chimera.review_complete` event. It is linked\n * to the finding store via `id` (which equals `finding.originReport.reportId`).\n */\nexport interface ReviewReport {\n /** Immutable UUID \u2014 links to findings' `originReport.reportId`. */\n id: string;\n /** When the review completed (ISO8601). */\n reviewedAt: string;\n /** Session that triggered the review. */\n sessionId: string;\n /** Agent that was being reviewed. */\n agentId: string;\n /** Model that produced the review report. */\n reviewerModel: string;\n /** Review kind that produced this report. */\n source: FindingSource;\n /** Whether the review subagent succeeded or failed. */\n reviewStatus: 'success' | 'failed';\n /** Materialized lifecycle status (derived from latest lifecycle event). */\n lifecycle: ReportLifecycleStatus;\n /** Files that were reviewed. */\n files: ReviewReportFile[];\n /** Severity counts from the parsed report. */\n counts: ReviewReportCounts;\n /** Total findings parsed from the report. */\n totalFindings: number;\n /** Severity-counted items that could not be parsed individually. */\n unparseableCount: number;\n /** Review duration in seconds, if reported. */\n durationSeconds?: number | undefined;\n /** The full raw Markdown report text. */\n rawText: string;\n /** Cascade iteration depth (0 for initial review). */\n cascadeDepth?: number | undefined;\n}\n\n// \u2500\u2500 Lifecycle event \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport type ReportEventType =\n | 'created'\n | 'actioned'\n | 'completed'\n | 'skipped'\n | 'reopened'\n | 'note_added';\n\n/** A single state-transition or annotation event in a report's lifecycle. */\nexport interface ReviewReportEvent {\n id: string;\n reportId: string;\n eventType: ReportEventType;\n fromLifecycle: ReportLifecycleStatus | null;\n toLifecycle: ReportLifecycleStatus;\n actorId: string;\n actorKind: ReportActorKind;\n timestamp: string; // ISO8601\n reason?: string | undefined;\n}\n\n// \u2500\u2500 Error classes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class ReportNotFoundError extends Error {\n readonly reportId: string;\n constructor(reportId: string) {\n super(`Review report not found: ${reportId}`);\n this.name = 'ReportNotFoundError';\n this.reportId = reportId;\n }\n}\n\nexport class InvalidReportTransitionError extends Error {\n readonly from: ReportLifecycleStatus;\n readonly to: ReportLifecycleStatus;\n constructor(from: ReportLifecycleStatus, to: ReportLifecycleStatus, reason?: string) {\n const msg = reason ?? `Invalid report transition from \"${from}\" to \"${to}\"`;\n super(msg);\n this.name = 'InvalidReportTransitionError';\n this.from = from;\n this.to = to;\n }\n}\n\n// \u2500\u2500 Transition state machine \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst REPORT_TRANSITION_MATRIX: Record<ReportLifecycleStatus, ReadonlySet<ReportLifecycleStatus>> = {\n open: new Set(['actioned', 'completed', 'skipped']),\n actioned: new Set(['completed', 'skipped']),\n completed: new Set(['open']),\n skipped: new Set(['open']),\n};\n\n/**\n * Check whether a report lifecycle transition is valid per the state machine.\n * Throws InvalidReportTransitionError for invalid transitions.\n *\n * `note_added` events are always allowed regardless of current status \u2014 they\n * are annotations, not transitions, and the caller should validate them\n * separately (this function is for real status moves only).\n */\nexport function validateReportTransition(\n from: ReportLifecycleStatus,\n to: ReportLifecycleStatus,\n): void {\n if (from === to) return; // idempotent\n const allowed = REPORT_TRANSITION_MATRIX[from];\n if (!allowed?.has(to)) {\n throw new InvalidReportTransitionError(from, to);\n }\n}\n\n/** Map a target lifecycle status to its corresponding event type. */\nexport function reportEventTypeFor(to: ReportLifecycleStatus): ReportEventType {\n switch (to) {\n case 'actioned': return 'actioned';\n case 'completed': return 'completed';\n case 'skipped': return 'skipped';\n default: return 'reopened';\n }\n}\n", "/**\n * Chimera Review Report Store \u2014 persistent JSONL store with lifecycle tracking.\n *\n * Each completed Chimera review produces one ReviewReport record here. The\n * raw Markdown text is preserved (`rawText`) alongside structured metadata\n * (severity counts, files, duration, provenance) so reports can be browsed\n * and audited over time.\n *\n * Reports are linked to the finding store via the shared `id` field, which\n * equals each finding's `originReport.reportId`. The two stores have\n * independent lifecycles and retention windows.\n *\n * @module review-report-store\n */\n\nimport { randomUUID } from 'node:crypto';\nimport * as fsp from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { atomicWrite, withFileLock } from '../utils/atomic-write.js';\nimport type {\n ReviewReport,\n ReviewReportCounts,\n ReviewReportEvent,\n ReviewReportFile,\n} from './review-report-types.js';\nimport {\n reportEventTypeFor,\n validateReportTransition,\n type ReportActorKind,\n type ReportLifecycleStatus,\n} from './review-report-types.js';\n\n// \u2500\u2500 Constants \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Default retention for completed/skipped reports (90 days in ms). */\nexport const REPORT_RETENTION_MS = 90 * 24 * 60 * 60 * 1000;\n\n/** Max reports returned by list() without a limit. */\nexport const REPORT_DEFAULT_PAGE_SIZE = 25;\n\nconst NL = '\\n';\n\n/** File name for the report store JSONL file. */\nexport const REPORT_STORE_FILE = 'review-reports.jsonl';\n\n/** Resolve the absolute path to the report store file. */\nexport function resolveReportStorePath(projectDir: string): string {\n return path.join(projectDir, REPORT_STORE_FILE);\n}\n\n// \u2500\u2500 JSONL record types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ninterface ReportRecord {\n __report: 1;\n data: ReviewReport;\n}\n\ninterface ReportEventRecord {\n __reportEvent: 1;\n data: ReviewReportEvent;\n}\n\ninterface ReportCompactMarker {\n __reportCompact: 1;\n compactedAt: string;\n removedReports: number;\n foldedEvents: number;\n}\n\n// \u2500\u2500 Persist input \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Structured input for creating a report record. */\nexport interface PersistReportInput {\n /** Report UUID \u2014 should match the findings' originReport.reportId. */\n id: string;\n sessionId: string;\n agentId: string;\n reviewerModel: string;\n source: ReviewReport['source'];\n reviewStatus: 'success' | 'failed';\n files: ReviewReportFile[];\n counts: ReviewReportCounts;\n totalFindings: number;\n unparseableCount: number;\n durationSeconds?: number | undefined;\n rawText: string;\n cascadeDepth?: number | undefined;\n}\n\n/** Context for who is creating/transitioning a report. */\nexport interface ReportActor {\n id: string;\n kind: ReportActorKind;\n}\n\nexport interface ListReportsOptions {\n statuses?: ReportLifecycleStatus[] | undefined;\n sources?: ReviewReport['source'][] | undefined;\n limit?: number | undefined;\n}\n\nexport interface ReportStore {\n persist(input: PersistReportInput): Promise<ReviewReport>;\n transition(\n reportId: string,\n to: ReportLifecycleStatus,\n actor: ReportActor,\n opts?: { reason?: string },\n ): Promise<ReviewReport>;\n addNote(reportId: string, actor: ReportActor, note: string): Promise<ReviewReport>;\n list(opts?: ListReportsOptions): Promise<ReviewReport[]>;\n get(id: string): Promise<ReviewReport | null>;\n getEvents(reportId: string): Promise<ReviewReportEvent[]>;\n compact(opts?: { maxAgeMs?: number }): Promise<{ removed: number; eventsFolded: number }>;\n}\n\n// \u2500\u2500 Implementation \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class JsonlReportStore implements ReportStore {\n private readonly filePath: string;\n\n constructor(projectDir: string) {\n this.filePath = resolveReportStorePath(projectDir);\n }\n\n get storePath(): string {\n return this.filePath;\n }\n\n // \u2500\u2500 Persist (create or reopen) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n async persist(input: PersistReportInput): Promise<ReviewReport> {\n return withFileLock(this.filePath, async () => {\n const existing = await this._findRecord(input.id);\n\n if (existing) {\n // Report already persisted (e.g. cascade re-review of same reportId).\n // Update materialized counts/rawText but don't duplicate the created event.\n const updated: ReviewReport = {\n ...existing,\n counts: input.counts,\n totalFindings: input.totalFindings,\n unparseableCount: input.unparseableCount,\n durationSeconds: input.durationSeconds ?? existing.durationSeconds,\n rawText: input.rawText || existing.rawText,\n files: input.files.length > 0 ? input.files : existing.files,\n };\n await fsp.appendFile(\n this.filePath,\n JSON.stringify({ __report: 1, data: updated }) + NL,\n 'utf8',\n );\n return updated;\n }\n\n const report: ReviewReport = {\n id: input.id,\n reviewedAt: new Date().toISOString(),\n sessionId: input.sessionId,\n agentId: input.agentId,\n reviewerModel: input.reviewerModel,\n source: input.source,\n reviewStatus: input.reviewStatus,\n lifecycle: 'open',\n files: input.files,\n counts: input.counts,\n totalFindings: input.totalFindings,\n unparseableCount: input.unparseableCount,\n durationSeconds: input.durationSeconds,\n rawText: input.rawText,\n ...(input.cascadeDepth !== undefined ? { cascadeDepth: input.cascadeDepth } : {}),\n };\n\n const createdEvent: ReviewReportEvent = {\n id: randomUUID(),\n reportId: report.id,\n eventType: 'created',\n fromLifecycle: null,\n toLifecycle: 'open',\n actorId: 'system',\n actorKind: 'system',\n timestamp: report.reviewedAt,\n };\n\n const lines =\n JSON.stringify({ __report: 1, data: report }) + NL +\n JSON.stringify({ __reportEvent: 1, data: createdEvent }) + NL;\n await fsp.appendFile(this.filePath, lines, 'utf8');\n return report;\n });\n }\n\n // \u2500\u2500 Lifecycle transitions \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n async transition(\n reportId: string,\n to: ReportLifecycleStatus,\n actor: ReportActor,\n opts?: { reason?: string },\n ): Promise<ReviewReport> {\n const all = await this._readAll();\n const entry = all.find((e) => e.report.id === reportId);\n if (!entry) throw new Error(`Review report not found: ${reportId}`);\n\n // Materialize current lifecycle from events \u2014 the stored record's\n // lifecycle field is the original value (set at creation time); only\n // events reflect subsequent transitions.\n const from = this._materialize(entry).lifecycle;\n validateReportTransition(from, to);\n\n const event: ReviewReportEvent = {\n id: randomUUID(),\n reportId,\n eventType: reportEventTypeFor(to),\n fromLifecycle: from,\n toLifecycle: to,\n actorId: actor.id,\n actorKind: actor.kind,\n timestamp: new Date().toISOString(),\n reason: opts?.reason,\n };\n\n entry.report.lifecycle = to;\n\n await fsp.appendFile(\n this.filePath,\n JSON.stringify({ __reportEvent: 1, data: event }) + NL,\n 'utf8',\n );\n\n return { ...entry.report };\n }\n\n async addNote(reportId: string, actor: ReportActor, note: string): Promise<ReviewReport> {\n const all = await this._readAll();\n const entry = all.find((e) => e.report.id === reportId);\n if (!entry) throw new Error(`Review report not found: ${reportId}`);\n\n const event: ReviewReportEvent = {\n id: randomUUID(),\n reportId,\n eventType: 'note_added',\n fromLifecycle: entry.report.lifecycle,\n toLifecycle: entry.report.lifecycle,\n actorId: actor.id,\n actorKind: actor.kind,\n timestamp: new Date().toISOString(),\n reason: note,\n };\n\n await fsp.appendFile(\n this.filePath,\n JSON.stringify({ __reportEvent: 1, data: event }) + NL,\n 'utf8',\n );\n\n return { ...entry.report };\n }\n\n // \u2500\u2500 Query \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n async list(opts?: ListReportsOptions): Promise<ReviewReport[]> {\n const all = await this._readAll();\n let reports = all.map((e) => this._materialize(e));\n\n if (opts?.statuses && opts.statuses.length > 0) {\n const set = new Set(opts.statuses);\n reports = reports.filter((r) => set.has(r.lifecycle));\n }\n if (opts?.sources && opts.sources.length > 0) {\n const set = new Set(opts.sources);\n reports = reports.filter((r) => set.has(r.source));\n }\n\n // Sort newest first.\n reports.sort((a, b) => b.reviewedAt.localeCompare(a.reviewedAt));\n\n const limit = opts?.limit ?? REPORT_DEFAULT_PAGE_SIZE;\n return reports.slice(0, limit);\n }\n\n async get(id: string): Promise<ReviewReport | null> {\n const all = await this._readAll();\n const entry = all.find((e) => e.report.id === id);\n return entry ? this._materialize(entry) : null;\n }\n\n async getEvents(reportId: string): Promise<ReviewReportEvent[]> {\n const all = await this._readAllLines();\n const events: ReviewReportEvent[] = [];\n for (const line of all) {\n try {\n const parsed = JSON.parse(line) as unknown;\n if (this._isEventRecord(parsed) && parsed.data.reportId === reportId) {\n events.push(parsed.data);\n }\n } catch {\n // skip malformed\n }\n }\n return events.sort((a, b) => a.timestamp.localeCompare(b.timestamp));\n }\n\n // \u2500\u2500 Compaction \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n async compact(opts?: { maxAgeMs?: number }): Promise<{ removed: number; eventsFolded: number }> {\n const maxAge = opts?.maxAgeMs ?? REPORT_RETENTION_MS;\n const now = Date.now();\n\n const all = await this._readAll();\n const kept: Array<{ record: ReportRecord | null; events: ReviewReportEvent[] }> = [];\n let removed = 0;\n let eventsFolded = 0;\n\n for (const entry of all) {\n const age = now - new Date(entry.report.reviewedAt).getTime();\n const materialized = this._materialize(entry);\n const isTerminal = materialized.lifecycle === 'completed' || materialized.lifecycle === 'skipped';\n\n if (isTerminal && age > maxAge) {\n removed++;\n eventsFolded += entry.events.length;\n continue;\n }\n\n // Fold old events into a single marker per report.\n const oldEvents = entry.events.filter((ev) => now - new Date(ev.timestamp).getTime() > maxAge);\n if (oldEvents.length > 1) {\n eventsFolded += oldEvents.length - 1;\n const newestOld = oldEvents.sort((a, b) => b.timestamp.localeCompare(a.timestamp))[0]!;\n entry.events = [newestOld, ...entry.events.filter((ev) => now - new Date(ev.timestamp).getTime() <= maxAge)];\n }\n kept.push({ record: { __report: 1, data: entry.report }, events: entry.events });\n }\n\n const lines: string[] = [];\n for (const { record, events } of kept) {\n if (record) lines.push(JSON.stringify(record));\n for (const ev of events) {\n lines.push(JSON.stringify({ __reportEvent: 1, data: ev }));\n }\n }\n lines.push(JSON.stringify({\n __reportCompact: 1,\n compactedAt: new Date().toISOString(),\n removedReports: removed,\n foldedEvents: eventsFolded,\n } as ReportCompactMarker));\n\n await atomicWrite(this.filePath, lines.join(NL) + NL, { mode: 0o600 });\n return { removed, eventsFolded };\n }\n\n // \u2500\u2500 Private helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n private async _readAllLines(): Promise<string[]> {\n try {\n const raw = await fsp.readFile(this.filePath, 'utf8');\n return raw.split(NL).filter((l) => l.trim().length > 0);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return [];\n throw err;\n }\n }\n\n private _isReportRecord(v: unknown): v is ReportRecord {\n return typeof v === 'object' && v !== null && (v as Record<string, unknown>)['__report'] === 1;\n }\n\n private _isEventRecord(v: unknown): v is ReportEventRecord {\n return typeof v === 'object' && v !== null && (v as Record<string, unknown>)['__reportEvent'] === 1;\n }\n\n private async _readAll(): Promise<Array<{ report: ReviewReport; events: ReviewReportEvent[] }>> {\n const lines = await this._readAllLines();\n const reports = new Map<string, ReviewReport>();\n const eventsMap = new Map<string, ReviewReportEvent[]>();\n\n for (const line of lines) {\n try {\n const parsed = JSON.parse(line) as unknown;\n if (this._isReportRecord(parsed)) {\n reports.set(parsed.data.id, parsed.data);\n if (!eventsMap.has(parsed.data.id)) eventsMap.set(parsed.data.id, []);\n } else if (this._isEventRecord(parsed)) {\n const list = eventsMap.get(parsed.data.reportId);\n if (list) list.push(parsed.data);\n }\n } catch {\n // skip malformed\n }\n }\n\n return Array.from(reports.entries()).map(([id, report]) => ({\n report,\n events: eventsMap.get(id) ?? [],\n }));\n }\n\n private async _findRecord(id: string): Promise<ReviewReport | null> {\n const all = await this._readAll();\n const entry = all.find((e) => e.report.id === id);\n return entry ? this._materialize(entry) : null;\n }\n\n private _materialize(entry: { report: ReviewReport; events: ReviewReportEvent[] }): ReviewReport {\n if (entry.events.length === 0) return { ...entry.report };\n const sorted = [...entry.events].sort((a, b) => a.timestamp.localeCompare(b.timestamp));\n const latest = sorted[sorted.length - 1]!;\n // Only lifecycle-affecting events override the materialized status.\n if (latest.eventType !== 'note_added') {\n return { ...entry.report, lifecycle: latest.toLifecycle };\n }\n return { ...entry.report };\n }\n}\n", "/** Assert a value is neither null nor undefined. Throws if it is.\n * Useful after optional chaining and indexed access when the\n * control flow guarantees the value exists but TypeScript can't\n * prove it (e.g. after a check on a related field). */\nexport function expectDefined<T>(value: T | null | undefined, label?: string): T {\n if (value === null || value === undefined) {\n const err = new Error(label ? `Expected ${label} to be defined` : 'Expected value to be defined');\n err.name = 'ExpectDefinedError';\n throw err;\n }\n return value;\n}\n", "import { expectDefined } from '../utils/expect-defined.js';\n/**\n * ExtensionRegistry \u2014 manages AgentExtension registrations.\n *\n * Extensions are called in registration order at each lifecycle phase.\n * Each extension hook failure is caught and logged independently so\n * one bad extension can't take down the agent.\n */\n\nimport type { TextBlock } from '../types/blocks.js';\nimport { WrongStackError, ERROR_CODES } from '../types/errors.js';\nimport type { Logger } from '../types/logger.js';\nimport type { SystemPromptContributor } from '../types/system-prompt-contributor.js';\nimport type {\n AfterIterationHook,\n AfterRunHook,\n AfterToolExecutionHook,\n AgentExtension,\n BeforeIterationHook,\n BeforeRunHook,\n BeforeToolExecutionHook,\n OnErrorHook,\n ProviderRunnerFn,\n} from './extension-points.js';\nexport class ExtensionRegistry {\n private readonly extensions: AgentExtension[] = [];\n private readonly promptContributors: SystemPromptContributor[] = [];\n private log: Logger | undefined;\n\n setLogger(log: Logger): void {\n this.log = log;\n }\n\n /**\n * Register a system prompt contributor. Returns an unregister function.\n * Contributors are called on every system prompt build in registration\n * order. Their output blocks are inserted after the core environment\n * block, before the mode and plan blocks.\n */\n registerSystemPromptContributor(c: SystemPromptContributor): () => void {\n this.promptContributors.push(c);\n return () => {\n const idx = this.promptContributors.indexOf(c);\n if (idx >= 0) this.promptContributors.splice(idx, 1);\n };\n }\n\n /**\n * Build all registered system prompt contributions.\n * Failures are caught and logged \u2014 one bad contributor doesn't\n * break the prompt assembly.\n */\n async buildSystemPromptContributions(\n ctx: Parameters<SystemPromptContributor>[0],\n ): Promise<TextBlock[]> {\n const blocks: TextBlock[] = [];\n // Snapshot before iterating so mid-iteration registration doesn't cause\n // skipped or duplicate contributor invocations during this phase.\n const snapshot = [...this.promptContributors];\n for (const c of snapshot) {\n try {\n const contributed = await c(ctx);\n blocks.push(...contributed);\n } catch (err) {\n this.log?.error('SystemPromptContributor failed', err);\n }\n }\n return blocks;\n }\n\n /**\n * Returns the live array of contributors (readonly snapshot for\n * passing to DefaultSystemPromptBuilder at build time).\n */\n listSystemPromptContributors(): readonly SystemPromptContributor[] {\n return this.promptContributors;\n }\n\n /**\n * Register an extension. Duplicate names are rejected.\n * Returns an unregister function.\n */\n register(ext: AgentExtension): () => void {\n if (this.extensions.some((e) => e.name === ext.name)) {\n throw new WrongStackError({\n message: `Extension \"${ext.name}\" already registered`,\n code: ERROR_CODES.REGISTRY_DUPLICATE,\n subsystem: 'container',\n context: { extension: ext.name },\n });\n }\n this.extensions.push(ext);\n return () => this.unregister(ext.name);\n }\n\n /**\n * Register an extension, silently replacing any previous registration\n * with the same name. Use this when overriding a default extension.\n */\n registerOrReplace(ext: AgentExtension): () => void {\n const idx = this.extensions.findIndex((e) => e.name === ext.name);\n if (idx >= 0) this.extensions.splice(idx, 1);\n return this.register(ext);\n }\n\n /**\n * Unregister an extension by name. Returns true if found.\n */\n unregister(name: string): boolean {\n const idx = this.extensions.findIndex((e) => e.name === name);\n if (idx === -1) return false;\n this.extensions.splice(idx, 1);\n return true;\n }\n\n /**\n * List registered extension names in order.\n */\n list(): readonly string[] {\n return this.extensions.map((e) => e.name);\n }\n\n /**\n * Check if an extension with the given name is registered.\n */\n has(name: string): boolean {\n return this.extensions.some((e) => e.name === name);\n }\n\n /**\n * Remove all registered extensions and contributors.\n */\n clear(): void {\n this.extensions.length = 0;\n this.promptContributors.length = 0;\n }\n\n // \u2500\u2500 Hook runners \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n async runBeforeRun(...args: Parameters<BeforeRunHook>): Promise<void> {\n const snapshot = [...this.extensions];\n for (const ext of snapshot) {\n if (!ext.beforeRun) continue;\n try {\n await ext.beforeRun(...args);\n } catch (err) {\n this.log?.error(`Extension \"${ext.name}\" beforeRun hook failed`, err);\n }\n }\n }\n\n async runAfterRun(...args: Parameters<AfterRunHook>): Promise<void> {\n const snapshot = [...this.extensions];\n for (const ext of snapshot) {\n if (!ext.afterRun) continue;\n try {\n await ext.afterRun(...args);\n } catch (err) {\n this.log?.error(`Extension \"${ext.name}\" afterRun hook failed`, err);\n }\n }\n }\n\n async runBeforeIteration(...args: Parameters<BeforeIterationHook>): Promise<void> {\n const snapshot = [...this.extensions];\n for (const ext of snapshot) {\n if (!ext.beforeIteration) continue;\n try {\n await ext.beforeIteration(...args);\n } catch (err) {\n this.log?.error(`Extension \"${ext.name}\" beforeIteration hook failed`, err);\n }\n }\n }\n\n async runAfterIteration(...args: Parameters<AfterIterationHook>): Promise<void> {\n const snapshot = [...this.extensions];\n for (const ext of snapshot) {\n if (!ext.afterIteration) continue;\n try {\n await ext.afterIteration(...args);\n } catch (err) {\n this.log?.error(`Extension \"${ext.name}\" afterIteration hook failed`, err);\n }\n }\n }\n\n /**\n * Run onError hooks in order. The first hook that returns a non-void\n * result wins; subsequent hooks are skipped.\n */\n async runOnError(\n ...args: Parameters<OnErrorHook>\n ): Promise<\n { action: 'retry'; model?: string | undefined } | { action: 'fail' } | { action: 'continue' } | void\n > {\n const snapshot = [...this.extensions];\n for (const ext of snapshot) {\n if (!ext.onError) continue;\n try {\n const result = await ext.onError(...args);\n if (result) return result;\n } catch (err) {\n this.log?.error(`Extension \"${ext.name}\" onError hook failed`, err);\n }\n }\n }\n\n /**\n * Build a composed provider runner. Extensions with `wrapProviderRunner`\n * form a middleware-style chain: the innermost extension wraps the\n * default runner, each subsequent wrapper wraps the previous.\n */\n wrapProviderRunner(inner: ProviderRunnerFn): ProviderRunnerFn {\n const wrappers = this.extensions\n .filter((e) => e.wrapProviderRunner)\n .map((e) => ({ name: e.name, wrap: expectDefined(e.wrapProviderRunner) }));\n\n if (wrappers.length === 0) return inner;\n\n // Build chain from innermost to outermost\n let composed: ProviderRunnerFn = inner;\n for (let i = wrappers.length - 1; i >= 0; i--) {\n const wrapper = wrappers[i];\n if (!wrapper) continue;\n const next = composed;\n composed = async (ctx, req) => {\n try {\n return await wrapper.wrap(ctx, req, next);\n } catch (err) {\n this.log?.error(`Extension \"${wrapper.name}\" wrapProviderRunner failed`, err);\n throw err;\n }\n };\n }\n return composed;\n }\n\n async runBeforeToolExecution(\n ...args: Parameters<BeforeToolExecutionHook>\n ): Promise<Parameters<BeforeToolExecutionHook>[1]> {\n let toolUses = args[1];\n const snapshot = [...this.extensions];\n for (const ext of snapshot) {\n if (!ext.beforeToolExecution) continue;\n try {\n toolUses = await ext.beforeToolExecution(args[0], toolUses);\n } catch (err) {\n this.log?.error(`Extension \"${ext.name}\" beforeToolExecution hook failed`, err);\n }\n }\n return toolUses;\n }\n\n async runAfterToolExecution(...args: Parameters<AfterToolExecutionHook>): Promise<void> {\n const snapshot = [...this.extensions];\n for (const ext of snapshot) {\n if (!ext.afterToolExecution) continue;\n try {\n await ext.afterToolExecution(...args);\n } catch (err) {\n this.log?.error(`Extension \"${ext.name}\" afterToolExecution hook failed`, err);\n }\n }\n }\n}\n", "import { ERROR_CODES, PluginError } from '../types/errors.js';\nimport type { Logger } from '../types/logger.js';\nimport type { Plugin, PluginAPI, PluginDependency } from '../types/plugin.js';\nimport { toErrorMessage } from '../utils/error.js';\nimport { validateAgainstSchema } from '../utils/json-schema-validate.js';\nimport { resolvePluginManifestConfig, validatePluginConfigMetadata } from './config.js';\n\ninterface PluginRegistration {\n plugin: Plugin;\n api: PluginAPI;\n cleanupApi: PluginAPI & { drainCleanup?: (() => void) | undefined };\n cleanupDrained: boolean;\n disposed: boolean;\n}\n\n/**\n * Compatibility registry for callers that still use `unloadPlugins(loaded)`.\n * New hosts should use the handle returned by `loadPlugins`; that handle owns\n * an exact, isolated registration set even when two hosts load the same Plugin\n * object concurrently.\n */\nconst legacyRegistrations = new WeakMap<Plugin, PluginRegistration[]>();\n\nexport interface PluginLoadFailure {\n plugin: Plugin;\n err: unknown;\n}\n\nexport interface PluginHostHandle {\n loaded: Plugin[];\n failed: PluginLoadFailure[];\n readonly disposed: boolean;\n /** Dispose successfully loaded plugins in reverse dependency order. */\n dispose(): Promise<void>;\n}\n\nclass PluginLifecycleTimeoutError extends Error {\n constructor(\n readonly pluginName: string,\n readonly phase: 'setup' | 'teardown',\n readonly timeoutMs: number,\n ) {\n super(`Plugin \"${pluginName}\" ${phase} exceeded ${timeoutMs} ms`);\n this.name = 'PluginLifecycleTimeoutError';\n }\n}\n\n/**\n * Stable plugin API contract version. This is intentionally independent of\n * the package version: bump only when the surface visible to plugins\n * (PluginAPI, types/plugin) changes in a way that breaks existing setup\n * functions. Plugins declare `apiVersion: \"^1.0\"` to opt into this contract.\n *\n * 0.1.9: additive \u2014 `FleetSpawnBudgetError|FleetCostCapError` plus `FLEET_ROSTER` and the\n * pre-built fleet agent configs (Audit Log, Bug Hunter, Refactor Planner,\n * Security Scanner) now exported from `@wrongstack/core`.\n * 0.1.10: additive \u2014 extended-thinking stream events, core subpath\n * exports, tool output size chips on `tool.executed`. Plugin contract\n * unchanged otherwise; 0.1.x range still loads cleanly.\n *\n * Note: the package shipped as 0.2.0, but the *plugin contract* didn't\n * change in a breaking way \u2014 `SubagentError`, `subagent.tool_executed`,\n * `transcriptPath`, `planTool`, `delegate`, `runText`, and Director\n * sessionWriter are all additive to the surface. We deliberately keep\n * the kernel API at 0.1.10 so plugins pinning `apiVersion: \"^0.1\"`\n * keep loading. Bump to 1.0 when we stabilize and want the freedom to\n * remove deprecated surfaces.\n */\nexport const KERNEL_API_VERSION = '0.1.10';\n\nexport interface LoadPluginsOptions {\n apiFactory: (plugin: Plugin, resolvedOptions: Readonly<Record<string, unknown>>) => PluginAPI;\n log: Logger;\n kernelApiVersion?: string | undefined;\n /**\n * Per-plugin options keyed by plugin name. When a plugin declares\n * `configSchema`, the loader validates `pluginOptions[plugin.name]`\n * against it before calling `setup`. Pass `Config.plugins` shaped\n * `{ [name]: { options } }` or any flat record.\n */\n pluginOptions?: Record<string, Record<string, unknown>>;\n /**\n * When true, the loader throws a PluginError if a plugin calls an API\n * method that contradicts its declared `capabilities` \u2014 instead of\n * just logging a warning. Use in CI/strict deployments to enforce\n * manifest honesty. Default: false (log-only, backward-compatible).\n */\n enforceCapabilities?: boolean | undefined;\n /**\n * Timeout in milliseconds for each plugin's `setup()` call. If the\n * plugin's setup exceeds this deadline it is treated as a failure\n * and the plugin is not loaded. Default: 30 000 ms.\n */\n setupTimeoutMs?: number | undefined;\n /**\n * Timeout in milliseconds for each plugin's `teardown()` call. If the\n * plugin's teardown exceeds this deadline it is treated as a best-effort\n * failure (logged but not propagated). Default: 10 000 ms.\n */\n teardownTimeoutMs?: number | undefined;\n}\n\nfunction parseSemver(v: string): [number, number, number] {\n const parts = v\n .replace(/^[^0-9]*/, '')\n .split('.')\n .map((s) => Number.parseInt(s, 10) || 0);\n return [parts[0] ?? 0, parts[1] ?? 0, parts[2] ?? 0];\n}\n\nfunction satisfies(range: string, version: string): boolean {\n const [vMaj, vMin, vPatch] = parseSemver(version);\n const trimmed = range.trim();\n const op = trimmed.startsWith('^') ? '^' : trimmed.startsWith('~') ? '~' : '=';\n const ver = trimmed.replace(/^[\\^~=]/, '');\n const [rMaj, rMin, rPatch] = parseSemver(ver);\n if (op === '^') {\n if (rMaj === 0) return vMaj === 0 && vMin === rMin && vPatch >= rPatch;\n return vMaj === rMaj && (vMin > rMin || (vMin === rMin && vPatch >= rPatch));\n }\n if (op === '~') {\n return vMaj === rMaj && vMin === rMin && vPatch >= rPatch;\n }\n return vMaj === rMaj && vMin === rMin && vPatch === rPatch;\n}\n\n/** Normalize either `string` or `PluginDependency` into the structured form. */\nfunction normalizeDep(d: string | PluginDependency): PluginDependency {\n return typeof d === 'string' ? { name: d } : d;\n}\n\n/**\n * Shallow-merge defaults with overrides. Override keys take precedence;\n * defaults fill in where overrides are missing. Nested objects are\n * NOT deep-merged \u2014 the override value replaces wholesale.\n */\nfunction topoSort(plugins: Plugin[]): Plugin[] {\n const map = new Map<string, Plugin>();\n for (const p of plugins) map.set(p.name, p);\n const visited = new Set<string>();\n const visiting = new Set<string>();\n const order: Plugin[] = [];\n\n const visit = (p: Plugin, stack: string[]) => {\n if (visited.has(p.name)) return;\n if (visiting.has(p.name)) {\n throw new PluginError({\n message: `Plugin dependency cycle: ${[...stack, p.name].join(' -> ')}`,\n code: ERROR_CODES.PLUGIN_LOAD_FAILED,\n pluginName: p.name,\n });\n }\n visiting.add(p.name);\n for (const raw of p.dependsOn ?? []) {\n const dep = normalizeDep(raw);\n const d = map.get(dep.name);\n if (!d) {\n throw new PluginError({\n message: `Plugin \"${p.name}\" depends on missing plugin \"${dep.name}\"`,\n code: ERROR_CODES.PLUGIN_MISSING_DEPENDENCY,\n pluginName: p.name,\n context: { dependency: dep.name },\n });\n }\n // Version constraint check \u2014 only when both declared range and the\n // dependency's actual version are available. Missing either side is\n // tolerated: plugins without `version` are treated as wildcard.\n if (dep.version && d.version && !satisfies(dep.version, d.version)) {\n throw new PluginError({\n message: `Plugin \"${p.name}\" requires \"${dep.name}@${dep.version}\", found ${d.version}`,\n code: ERROR_CODES.PLUGIN_LOAD_FAILED,\n pluginName: p.name,\n context: { dependency: dep.name, required: dep.version, found: d.version },\n });\n }\n visit(d, [...stack, p.name]);\n }\n // Optional deps are silently skipped if the plugin is not loaded.\n for (const raw of p.optionalDeps ?? []) {\n const dep = normalizeDep(raw);\n const d = map.get(dep.name);\n if (d) {\n if (dep.version && d.version && !satisfies(dep.version, d.version)) {\n throw new PluginError({\n message: `Plugin \"${p.name}\" optional dep \"${dep.name}@${dep.version}\" found ${d.version}`,\n code: ERROR_CODES.PLUGIN_LOAD_FAILED,\n pluginName: p.name,\n context: { dependency: dep.name, required: dep.version, found: d.version },\n });\n }\n visit(d, [...stack, p.name]);\n }\n }\n visiting.delete(p.name);\n visited.add(p.name);\n order.push(p);\n };\n\n for (const p of plugins) visit(p, []);\n return order;\n}\n\nfunction lifecycleTimeoutMs(\n configured: number | undefined,\n fallback: number,\n phase: 'setup' | 'teardown',\n): number {\n const value = configured ?? fallback;\n if (!Number.isFinite(value) || value < 0) {\n throw new RangeError(`Plugin ${phase} timeout must be a finite non-negative number`);\n }\n return value;\n}\n\nasync function runWithDeadline(\n plugin: Plugin,\n phase: 'setup' | 'teardown',\n timeoutMs: number,\n operation: (signal: AbortSignal) => void | Promise<void>,\n): Promise<void> {\n const controller = new AbortController();\n let timer: ReturnType<typeof setTimeout> | undefined;\n const timeoutError = new PluginLifecycleTimeoutError(plugin.name, phase, timeoutMs);\n const deadline = new Promise<never>((_resolve, reject) => {\n timer = setTimeout(() => {\n controller.abort(timeoutError);\n reject(timeoutError);\n }, timeoutMs);\n });\n const work = Promise.resolve().then(() => operation(controller.signal));\n try {\n await Promise.race([work, deadline]);\n } finally {\n if (timer !== undefined) clearTimeout(timer);\n }\n}\n\nfunction registerLegacy(registration: PluginRegistration): void {\n const registrations = legacyRegistrations.get(registration.plugin) ?? [];\n registrations.push(registration);\n legacyRegistrations.set(registration.plugin, registrations);\n}\n\nfunction unregisterLegacy(registration: PluginRegistration): void {\n const registrations = legacyRegistrations.get(registration.plugin);\n if (!registrations) return;\n const index = registrations.indexOf(registration);\n if (index >= 0) registrations.splice(index, 1);\n if (registrations.length === 0) legacyRegistrations.delete(registration.plugin);\n}\n\nfunction drainCleanup(registration: PluginRegistration, log: Logger): void {\n if (registration.cleanupDrained) return;\n registration.cleanupDrained = true;\n try {\n registration.cleanupApi.drainCleanup?.call(registration.cleanupApi);\n } catch (err) {\n log.error(`Plugin \"${registration.plugin.name}\" cleanup drain failed`, { err });\n }\n}\n\nasync function disposeRegistration(\n registration: PluginRegistration,\n opts: LoadPluginsOptions,\n context: 'shutdown' | 'setup rollback',\n): Promise<void> {\n if (registration.disposed) return;\n registration.disposed = true;\n const { plugin, api } = registration;\n try {\n if (typeof plugin.teardown === 'function') {\n const timeoutMs = lifecycleTimeoutMs(opts.teardownTimeoutMs, 10_000, 'teardown');\n await runWithDeadline(plugin, 'teardown', timeoutMs, (signal) =>\n plugin.teardown!(api, { signal }),\n );\n }\n opts.log.info(`Plugin \"${plugin.name}\" disposed (${context})`);\n } catch (err) {\n opts.log.error(`Plugin \"${plugin.name}\" teardown failed during ${context}`, {\n err,\n reason: err instanceof PluginLifecycleTimeoutError ? 'teardown deadline exceeded' : undefined,\n });\n } finally {\n drainCleanup(registration, opts.log);\n unregisterLegacy(registration);\n }\n}\n\nasync function disposeRegistrations(\n registrations: PluginRegistration[],\n opts: LoadPluginsOptions,\n): Promise<void> {\n for (const registration of [...registrations].reverse()) {\n await disposeRegistration(registration, opts, 'shutdown');\n }\n}\n\nexport async function loadPlugins(\n plugins: Plugin[],\n opts: LoadPluginsOptions,\n): Promise<PluginHostHandle> {\n const kernelVersion = opts.kernelApiVersion ?? KERNEL_API_VERSION;\n const loaded: Plugin[] = [];\n const failed: PluginLoadFailure[] = [];\n const registrations: PluginRegistration[] = [];\n\n // Conflict check\n const names = new Set(plugins.map((p) => p.name));\n for (const p of plugins) {\n for (const c of p.conflictsWith ?? []) {\n if (names.has(c)) {\n throw new PluginError({\n message: `Plugin \"${p.name}\" conflicts with loaded plugin \"${c}\"`,\n code: ERROR_CODES.PLUGIN_LOAD_FAILED,\n pluginName: p.name,\n context: { conflictsWith: c },\n });\n }\n }\n }\n\n let sorted: Plugin[];\n try {\n sorted = topoSort(plugins);\n } catch (err) {\n const message = toErrorMessage(err);\n opts.log.error('Plugin dependency sort failed', message);\n throw new PluginError({\n message: `Plugin dependency sort failed: ${message}`,\n code: ERROR_CODES.PLUGIN_LOAD_FAILED,\n pluginName: '(topological sort)',\n context: { pluginCount: plugins.length },\n cause: err,\n });\n }\n\n for (const plugin of sorted) {\n if (!satisfies(plugin.apiVersion, kernelVersion)) {\n const err = new PluginError({\n message: `Plugin \"${plugin.name}\" requires apiVersion ${plugin.apiVersion}; kernel is ${kernelVersion}`,\n code: ERROR_CODES.PLUGIN_API_MISMATCH,\n pluginName: plugin.name,\n context: { required: plugin.apiVersion, kernel: kernelVersion },\n });\n opts.log.error(err.message);\n failed.push({ plugin, err });\n continue;\n }\n const metadataIssues = validatePluginConfigMetadata(plugin);\n if (metadataIssues.length > 0) {\n const err = new PluginError({\n message: `Plugin \"${plugin.name}\" config metadata invalid \u2014 ${metadataIssues.join('; ')}`,\n code: ERROR_CODES.PLUGIN_LOAD_FAILED,\n pluginName: plugin.name,\n context: { issues: metadataIssues },\n });\n opts.log.error(err.message);\n failed.push({ plugin, err });\n continue;\n }\n\n const resolution = resolvePluginManifestConfig(\n plugin,\n undefined,\n opts.pluginOptions?.[plugin.name],\n );\n const hasResolvedOptions = plugin.defaultConfig !== undefined || resolution.configured;\n if (opts.pluginOptions && hasResolvedOptions) {\n opts.pluginOptions[plugin.name] = resolution.options;\n }\n\n // configSchema validation \u2014 runs before setup() so a bad config never\n // reaches plugin code. The plugin's options are looked up by plugin name\n // in the host-supplied options bag.\n if (plugin.configSchema && hasResolvedOptions) {\n const result = validateAgainstSchema(resolution.options, plugin.configSchema);\n if (!result.ok) {\n const firstErr = result.errors[0];\n const detail = firstErr ? `${firstErr.path}: ${firstErr.message}` : 'config invalid';\n const err = new PluginError({\n message: `Plugin \"${plugin.name}\" config invalid \u2014 ${detail}`,\n code: ERROR_CODES.PLUGIN_LOAD_FAILED,\n pluginName: plugin.name,\n context: { errors: result.errors },\n });\n opts.log.error(err.message);\n failed.push({ plugin, err });\n continue;\n }\n }\n let registration: PluginRegistration | undefined;\n try {\n const rawApi = opts.apiFactory(\n plugin,\n resolution.options,\n ) as PluginRegistration['cleanupApi'];\n const api = plugin.capabilities\n ? wrapApiForCapabilityCheck(plugin, rawApi, opts.log, opts.enforceCapabilities)\n : rawApi;\n registration = {\n plugin,\n api,\n cleanupApi: rawApi,\n cleanupDrained: false,\n disposed: false,\n };\n const setupTimeoutMs = lifecycleTimeoutMs(opts.setupTimeoutMs, 30_000, 'setup');\n await runWithDeadline(plugin, 'setup', setupTimeoutMs, (signal) =>\n plugin.setup(api, { signal }),\n );\n registrations.push(registration);\n registerLegacy(registration);\n loaded.push(plugin);\n opts.log.info(`Plugin \"${plugin.name}\" loaded`);\n } catch (err) {\n opts.log.error(`Plugin \"${plugin.name}\" setup failed`, {\n err,\n reason: err instanceof PluginLifecycleTimeoutError ? 'setup deadline exceeded' : undefined,\n });\n failed.push({ plugin, err });\n if (registration) await disposeRegistration(registration, opts, 'setup rollback');\n }\n }\n let disposed = false;\n let disposePromise: Promise<void> | undefined;\n return {\n loaded,\n failed,\n get disposed() {\n return disposed;\n },\n dispose() {\n if (!disposePromise) {\n disposed = true;\n disposePromise = disposeRegistrations(registrations, opts);\n }\n return disposePromise;\n },\n };\n}\n\n/**\n * Tear down loaded plugins in reverse-dependency order. `teardown()` is\n * best-effort: errors are caught and logged so a single misbehaving plugin\n * can't abort the host shutdown sequence.\n *\n * @deprecated Prefer `loadPlugins(...).dispose()`. The handle has exact host\n * ownership and remains unambiguous when the same Plugin object is loaded by\n * more than one host. This legacy path shares a process-wide registry, so\n * when multiple hosts load the same Plugin object, `unloadPlugins` may\n * dispose another host's registration. Use the handle's `dispose()` instead.\n */\nexport async function unloadPlugins(\n loadedPlugins: Plugin[],\n opts: LoadPluginsOptions,\n): Promise<void> {\n const ordered = [...loadedPlugins].reverse();\n for (const plugin of ordered) {\n const candidates = legacyRegistrations.get(plugin);\n let registration: PluginRegistration | undefined;\n if (candidates) {\n for (let index = candidates.length - 1; index >= 0; index -= 1) {\n if (!candidates[index]!.disposed) {\n registration = candidates[index];\n break;\n }\n }\n }\n if (!registration) {\n opts.log.error(`Plugin \"${plugin.name}\" has no active loader registration`);\n continue;\n }\n await disposeRegistration(registration, opts, 'shutdown');\n }\n}\n\n/**\n * Wrap the PluginAPI so calls that contradict the plugin's declared\n * capabilities are caught. By default violations are logged as warnings\n * (backward-compatible). When `enforce` is true, violations throw a\n * PluginError so the host can reject misbehaving plugins at setup time.\n */\nfunction wrapApiForCapabilityCheck(\n plugin: Plugin,\n api: PluginAPI,\n log: {\n error(msg: string, ctx?: unknown): void | undefined;\n warn?(msg: string, ctx?: unknown): void | undefined;\n info?(msg: string, ctx?: unknown): void | undefined;\n },\n enforce = false,\n): PluginAPI {\n const caps = plugin.capabilities ?? {};\n const violate = (subsystem: string, detail: string) => {\n const msg = `Plugin \"${plugin.name}\" used ${subsystem} without declaring capabilities.${subsystem} \u2014 ${detail}`;\n if (enforce) {\n throw new PluginError({\n message: msg,\n code: ERROR_CODES.PLUGIN_LOAD_FAILED,\n pluginName: plugin.name,\n context: { subsystem, detail },\n });\n }\n if (typeof log.warn === 'function') log.warn(msg);\n else log.error(msg);\n };\n\n // Wrap tools.register\n const wrappedTools =\n caps.tools !== false\n ? api.tools\n : new Proxy(api.tools, {\n get(target, prop, receiver) {\n if (prop === 'register') {\n return (t: unknown) => {\n violate(\n 'tools',\n `register(${(t as { name?: string | undefined })?.name ?? '<unknown>'})`,\n );\n return (target.register as (x: unknown) => unknown)(t);\n };\n }\n return Reflect.get(target, prop, receiver);\n },\n });\n // Wrap providers.register\n const wrappedProviders =\n caps.providers !== false\n ? api.providers\n : new Proxy(api.providers, {\n get(target, prop, receiver) {\n if (prop === 'register') {\n return (f: unknown) => {\n violate(\n 'providers',\n `register(${(f as { type?: string | undefined })?.type ?? '<unknown>'})`,\n );\n return (target.register as (x: unknown) => unknown)(f);\n };\n }\n return Reflect.get(target, prop, receiver);\n },\n });\n // Wrap slashCommands.register\n const wrappedSlash =\n caps.slashCommands !== false\n ? api.slashCommands\n : new Proxy(api.slashCommands, {\n get(target, prop, receiver) {\n if (prop === 'register') {\n return (c: unknown) => {\n violate(\n 'slashCommands',\n `register(${(c as { name?: string | undefined })?.name ?? '<unknown>'})`,\n );\n return (target.register as (x: unknown) => unknown)(c);\n };\n }\n return Reflect.get(target, prop, receiver);\n },\n });\n // Wrap mcp.start\n const wrappedMcp =\n caps.mcp !== false\n ? api.mcp\n : new Proxy(api.mcp, {\n get(target, prop, receiver) {\n if (prop === 'start') {\n return (cfg: unknown) => {\n violate(\n 'mcp',\n `start(${(cfg as { name?: string | undefined })?.name ?? '<unknown>'})`,\n );\n return (target.start as (x: unknown) => unknown)(cfg);\n };\n }\n return Reflect.get(target, prop, receiver);\n },\n });\n // Wrap api.llm.complete. The facade is optional on minimal hosts; when it\n // exists, an explicit `llm: false` declaration is treated like the other\n // capability contradictions while still preserving warn-only compatibility.\n const wrappedLlm =\n caps.llm !== false || !api.llm\n ? api.llm\n : new Proxy(api.llm, {\n get(target, prop, receiver) {\n if (prop === 'complete') {\n return (prompt: string, options?: unknown) => {\n violate('llm', `complete(${prompt.length} chars)`);\n const complete = target.complete as (p: string, o?: unknown) => unknown;\n return options === undefined ? complete(prompt) : complete(prompt, options);\n };\n }\n return Reflect.get(target, prop, receiver);\n },\n });\n // Wrap registerHook \u2014 same pattern as the other subsystems. A plugin that\n // explicitly declared `hooks: false` gets warned/throws on registerHook.\n // Per-hook matchers and payloads are unchanged; only the call is gated.\n const wrappedHooks =\n caps.hooks !== false\n ? api\n : new Proxy(api, {\n get(target, prop, receiver) {\n if (prop === 'registerHook') {\n return (event: unknown, matcher: unknown, hook: unknown, options?: unknown) => {\n const ev = typeof event === 'string' ? event : '<unknown>';\n const m = typeof matcher === 'string' ? matcher : '*';\n violate('hooks', `registerHook(${ev}, ${m})`);\n const register = target.registerHook as (\n e: unknown,\n m: unknown,\n h: unknown,\n o?: unknown,\n ) => unknown;\n return options === undefined\n ? register(event, matcher, hook)\n : register(event, matcher, hook, options);\n };\n }\n return Reflect.get(target, prop, receiver);\n },\n });\n\n return new Proxy(api, {\n get(target, prop, receiver) {\n switch (prop) {\n case 'tools':\n return wrappedTools;\n case 'providers':\n return wrappedProviders;\n case 'slashCommands':\n return wrappedSlash;\n case 'mcp':\n return wrappedMcp;\n case 'llm':\n return wrappedLlm;\n case 'registerHook':\n // The hooks gate wraps the API itself (because registerHook is on\n // the API, not on a sub-registry). Forward to wrappedHooks so the\n // capability check fires.\n return (wrappedHooks as unknown as Record<PropertyKey, unknown>)[prop];\n default:\n return Reflect.get(target, prop, receiver);\n }\n },\n });\n}\n", "/**\n * Minimal JSON Schema validator \u2014 covers the subset needed for plugin\n * configSchema validation and tool inputSchema sanity checks. Intentionally\n * small (~80 lines, zero deps) and tolerant: unknown keywords are ignored so\n * authors can mix in non-standard extensions without breaking validation.\n *\n * NOT for full JSON Schema 2020-12 conformance. If a plugin needs $ref,\n * conditional schemas, format validation, or anything else exotic, it should\n * bring its own ajv-based validator and call this only for the cheap path.\n */\nimport type { JSONSchema } from '../types/tool.js';\n\nexport interface ValidationError {\n path: string;\n message: string;\n}\n\nexport interface ValidationResult {\n ok: boolean;\n errors: ValidationError[];\n}\n\nexport function validateAgainstSchema(value: unknown, schema: JSONSchema): ValidationResult {\n const errors: ValidationError[] = [];\n walk(value, schema, '', errors, 0);\n return { ok: errors.length === 0, errors };\n}\n\n/**\n * Maximum nesting depth before the validator stops recursing and reports a\n * \"schema too deep\" error. Deeply nested input (e.g. batch_tool_use with 100\n * nested calls \u2192 tool_use \u2192 input) can otherwise hit `RangeError: Maximum\n * call stack size exceeded` and crash the tool executor.\n *\n * 64 is generous: real-world tool schemas rarely nest beyond 5-6 levels, and\n * even pathological inputs (deeply recursive JSON) stay well under this.\n * The limit is a safety net against unbounded recursion, not a tight bound.\n */\nconst MAX_SCHEMA_DEPTH = 64;\n\nfunction walk(\n value: unknown,\n schema: JSONSchema,\n path: string,\n errors: ValidationError[],\n depth: number,\n): void {\n // P2 #8 (before-release.md): cap recursion depth to prevent\n // `RangeError: Maximum call stack size exceeded` on deeply nested input.\n // Push a validation error and stop descending \u2014 the caller still gets a\n // usable (ok: false) result instead of a crash.\n if (depth > MAX_SCHEMA_DEPTH) {\n errors.push({\n path: path || '<root>',\n message: `schema nesting exceeds maximum depth (${MAX_SCHEMA_DEPTH})`,\n });\n return;\n }\n if (schema.enum !== undefined) {\n if (!enumIncludes(schema.enum, value)) {\n errors.push({\n path: path || '<root>',\n message: `expected one of ${JSON.stringify(schema.enum)}, got ${JSON.stringify(value)}`,\n });\n return;\n }\n }\n\n if (typeof schema.type === 'string') {\n if (!checkType(value, schema.type)) {\n errors.push({\n path: path || '<root>',\n message: `expected ${schema.type}, got ${describeType(value)} (${previewValue(value)})`,\n });\n return;\n }\n }\n\n if (schema.type === 'object' && isPlainObject(value)) {\n const obj = value as Record<string, unknown>;\n for (const req of schema.required ?? []) {\n if (!(req in obj)) {\n const expected = schema.properties?.[req]?.type;\n errors.push({\n path: joinPath(path, req),\n message: `required property missing${typeof expected === 'string' ? ` (expected ${expected})` : ''}`,\n });\n }\n }\n if (schema.properties) {\n for (const [key, subSchema] of Object.entries(schema.properties)) {\n if (key in obj) {\n walk(obj[key], subSchema, joinPath(path, key), errors, depth + 1);\n }\n }\n }\n }\n\n if (schema.type === 'array' && Array.isArray(value) && schema.items) {\n for (let i = 0; i < value.length; i++) {\n walk(value[i], schema.items as JSONSchema, `${path}[${i}]`, errors, depth + 1);\n }\n }\n}\n\nexport interface CoercionResult {\n value: unknown;\n /** True when at least one leaf was rewritten. */\n changed: boolean;\n}\n\n/**\n * Best-effort, lossless coercion of a value toward a JSON Schema. Models \u2014\n * especially through OpenAI-compatible proxies \u2014 frequently deliver\n * arguments with the right *content* in the wrong *type*: numbers and\n * booleans encoded as strings (\"5\", \"true\"), scalars where a string is\n * expected, or a whole nested object serialized into a JSON string.\n *\n * Only conversions that cannot lose information are applied:\n * - string \u2192 number/integer when the whole trimmed string parses cleanly\n * - string \"true\"/\"false\" \u2192 boolean\n * - number/boolean \u2192 string when a string is expected\n * - JSON-serialized string \u2192 object/array when the parse yields that shape\n * Recurses into `properties`/`items`. Returns the (possibly new) value and\n * whether anything changed \u2014 callers should re-validate before trusting it.\n */\nexport function coerceAgainstSchema(value: unknown, schema: JSONSchema): CoercionResult {\n return coerceWalk(value, schema, 0);\n}\n\nfunction coerceWalk(value: unknown, schema: JSONSchema, depth: number): CoercionResult {\n if (depth > MAX_SCHEMA_DEPTH) return { value, changed: false };\n\n const type = typeof schema.type === 'string' ? schema.type : undefined;\n\n // Leaf conversions (only when the current type does NOT already match).\n if (type && !checkType(value, type)) {\n if (type === 'string' && (typeof value === 'number' || typeof value === 'boolean')) {\n return { value: String(value), changed: true };\n }\n if ((type === 'number' || type === 'integer') && typeof value === 'string') {\n const trimmed = value.trim();\n if (trimmed !== '' && /^-?(\\d+\\.?\\d*|\\.\\d+)([eE][+-]?\\d+)?$/.test(trimmed)) {\n const num = Number(trimmed);\n if (!Number.isNaN(num) && (type === 'number' || Number.isInteger(num))) {\n return { value: num, changed: true };\n }\n }\n return { value, changed: false };\n }\n if (type === 'boolean' && typeof value === 'string') {\n const lowered = value.trim().toLowerCase();\n if (lowered === 'true') return { value: true, changed: true };\n if (lowered === 'false') return { value: false, changed: true };\n return { value, changed: false };\n }\n if ((type === 'object' || type === 'array') && typeof value === 'string') {\n // A nested structure serialized into a string (double-encoded args).\n try {\n const parsed: unknown = JSON.parse(value);\n if (checkType(parsed, type)) {\n // Recurse so leaves inside the revived structure also coerce.\n return { value: coerceWalk(parsed, schema, depth + 1).value, changed: true };\n }\n } catch {\n // fall through \u2014 leave as-is, validation will report it\n }\n return { value, changed: false };\n }\n return { value, changed: false };\n }\n\n // Structural recursion.\n if (type === 'object' && isPlainObject(value) && schema.properties) {\n const obj = value as Record<string, unknown>;\n let changed = false;\n const out: Record<string, unknown> = { ...obj };\n for (const [key, subSchema] of Object.entries(schema.properties)) {\n if (!(key in obj)) continue;\n const r = coerceWalk(obj[key], subSchema, depth + 1);\n if (r.changed) {\n out[key] = r.value;\n changed = true;\n }\n }\n return changed ? { value: out, changed } : { value, changed: false };\n }\n\n if (type === 'array' && Array.isArray(value) && schema.items) {\n let changed = false;\n const out = value.map((item) => {\n const r = coerceWalk(item, schema.items as JSONSchema, depth + 1);\n if (r.changed) changed = true;\n return r.value;\n });\n return changed ? { value: out, changed } : { value, changed: false };\n }\n\n return { value, changed: false };\n}\n\nfunction checkType(value: unknown, type: string): boolean {\n switch (type) {\n case 'string':\n return typeof value === 'string';\n case 'number':\n return typeof value === 'number' && !Number.isNaN(value);\n case 'integer':\n return typeof value === 'number' && Number.isInteger(value);\n case 'boolean':\n return typeof value === 'boolean';\n case 'null':\n return value === null;\n case 'array':\n return Array.isArray(value);\n case 'object':\n return isPlainObject(value);\n default:\n return true;\n }\n}\n\nfunction isPlainObject(v: unknown): boolean {\n return typeof v === 'object' && v !== null && !Array.isArray(v);\n}\n\nfunction describeType(v: unknown): string {\n if (v === null) return 'null';\n if (Array.isArray(v)) return 'array';\n return typeof v;\n}\n\n/** Short serialized preview of the offending value for error messages. */\nfunction previewValue(v: unknown): string {\n try {\n const s = JSON.stringify(v);\n if (s === undefined) return String(v);\n return s.length > 80 ? `${s.slice(0, 80)}\u2026` : s;\n } catch {\n return String(v);\n }\n}\n\nfunction joinPath(parent: string, key: string): string {\n if (!parent) return key;\n return `${parent}.${key}`;\n}\n\nfunction enumIncludes(values: readonly unknown[], value: unknown): boolean {\n if (value === null || typeof value !== 'object') return values.includes(value);\n return values.some((candidate) => deepEqual(candidate, value));\n}\n\nfunction deepEqual(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (typeof a !== typeof b) return false;\n if (a === null || b === null) return a === b;\n if (Array.isArray(a) && Array.isArray(b)) {\n return a.length === b.length && a.every((v, i) => deepEqual(v, b[i]));\n }\n if (typeof a === 'object' && typeof b === 'object') {\n const ak = Object.keys(a as object);\n const bk = Object.keys(b as object);\n if (ak.length !== bk.length) return false;\n return ak.every((k) =>\n deepEqual((a as Record<string, unknown>)[k], (b as Record<string, unknown>)[k]),\n );\n }\n return false;\n}\n", "import type { Config, PluginConfig } from '../types/config.js';\nimport type {\n Plugin,\n PluginConfigFieldLifecycle,\n PluginConfigFieldMetadata,\n} from '../types/plugin.js';\n\nexport interface ResolvePluginConfigInput {\n name: string;\n aliases?: readonly string[] | undefined;\n defaults?: Readonly<Record<string, unknown>> | undefined;\n config?: Partial<Pick<Config, 'plugins' | 'extensions'>> | undefined;\n /** Highest-precedence host override, primarily for embedding APIs. */\n explicitOptions?: Readonly<Record<string, unknown>> | undefined;\n}\n\nexport type PluginConfigSource =\n | 'legacy-plugin-map'\n | 'plugin-entry'\n | 'extension'\n | 'explicit-options';\n\nexport interface ResolvedPluginConfig {\n options: Record<string, unknown>;\n configured: boolean;\n sources: PluginConfigSource[];\n}\n\nexport interface PluginConfigChange {\n key: string;\n lifecycle: PluginConfigFieldLifecycle;\n secret: boolean;\n previous: unknown;\n next: unknown;\n}\n\n/**\n * Resolve one plugin namespace with a single shallow precedence rule:\n * defaults < legacy plugin map < ordered plugin entries < aliases/canonical\n * extension namespaces < explicit host options. Canonical extension names\n * beat aliases, making migrations deterministic regardless of object order.\n */\nexport function resolvePluginConfig(input: ResolvePluginConfigInput): ResolvedPluginConfig {\n const names = [...new Set([...(input.aliases ?? []), input.name])];\n const options: Record<string, unknown> = { ...(input.defaults ?? {}) };\n const sources: PluginConfigSource[] = [];\n let configured = false;\n const merge = (value: unknown, source: PluginConfigSource): void => {\n if (!isRecord(value)) return;\n Object.assign(options, value);\n configured = true;\n if (!sources.includes(source)) sources.push(source);\n };\n\n const plugins = input.config?.plugins as unknown;\n if (isRecord(plugins)) {\n for (const name of names) merge(plugins[name], 'legacy-plugin-map');\n } else if (Array.isArray(plugins)) {\n for (const candidate of plugins) {\n if (!isPluginEntry(candidate) || !names.includes(candidate.name)) continue;\n merge(candidate.options, 'plugin-entry');\n }\n }\n\n const extensions = input.config?.extensions;\n for (const name of names) merge(extensions?.[name], 'extension');\n merge(input.explicitOptions, 'explicit-options');\n\n return { options, configured, sources };\n}\n\nexport function resolvePluginManifestConfig(\n plugin: Pick<Plugin, 'name' | 'configAliases' | 'defaultConfig'>,\n config?: ResolvePluginConfigInput['config'],\n explicitOptions?: Readonly<Record<string, unknown>>,\n): ResolvedPluginConfig {\n return resolvePluginConfig({\n name: plugin.name,\n aliases: plugin.configAliases,\n defaults: plugin.defaultConfig,\n config,\n explicitOptions,\n });\n}\n\n/** Unknown fields are immutable by default so a new option cannot silently hot-reload. */\nexport function diffPluginConfig(\n previous: Readonly<Record<string, unknown>>,\n next: Readonly<Record<string, unknown>>,\n fields: Readonly<Record<string, PluginConfigFieldMetadata>>,\n): PluginConfigChange[] {\n const keys = new Set([...Object.keys(previous), ...Object.keys(next)]);\n const changes: PluginConfigChange[] = [];\n for (const key of keys) {\n if (valuesEqual(previous[key], next[key])) continue;\n const metadata = fields[key];\n changes.push({\n key,\n lifecycle: metadata?.lifecycle ?? 'immutable',\n secret: metadata?.secret === true,\n previous: metadata?.secret === true ? '[REDACTED]' : previous[key],\n next: metadata?.secret === true ? '[REDACTED]' : next[key],\n });\n }\n return changes;\n}\n\nexport function redactPluginConfig(\n options: Readonly<Record<string, unknown>>,\n fields: Readonly<Record<string, PluginConfigFieldMetadata>>,\n): Record<string, unknown> {\n const redacted = { ...options };\n for (const [key, metadata] of Object.entries(fields)) {\n if (metadata.secret === true && key in redacted) redacted[key] = '[REDACTED]';\n }\n return redacted;\n}\n\n/** Validate an opted-in metadata map against the manifest's schema/default keys. */\nexport function validatePluginConfigMetadata(\n plugin: Pick<Plugin, 'configFields' | 'configSchema' | 'defaultConfig'>,\n): string[] {\n if (!plugin.configFields) return [];\n const declared = plugin.configFields;\n const expected = new Set([\n ...Object.keys(plugin.configSchema?.properties ?? {}),\n ...Object.keys(plugin.defaultConfig ?? {}),\n ]);\n const issues: string[] = [];\n for (const key of expected) {\n if (!declared[key]) issues.push(`missing configFields metadata for \"${key}\"`);\n }\n for (const [key, metadata] of Object.entries(declared)) {\n if (!['hot', 'restart', 'immutable'].includes(metadata.lifecycle)) {\n issues.push(`invalid lifecycle for configFields.\"${key}\"`);\n }\n }\n return issues;\n}\n\nfunction isPluginEntry(value: unknown): value is PluginConfig {\n return isRecord(value) && typeof value['name'] === 'string';\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction valuesEqual(left: unknown, right: unknown): boolean {\n if (Object.is(left, right)) return true;\n if (Array.isArray(left) && Array.isArray(right)) {\n return (\n left.length === right.length && left.every((value, index) => valuesEqual(value, right[index]))\n );\n }\n if (isRecord(left) && isRecord(right)) {\n const leftKeys = Object.keys(left);\n const rightKeys = Object.keys(right);\n return (\n leftKeys.length === rightKeys.length &&\n leftKeys.every((key) => key in right && valuesEqual(left[key], right[key]))\n );\n }\n return false;\n}\n", "import type { Mailbox } from '../coordination/mailbox-types.js';\nimport { ExtensionRegistry } from '../extension/registry.js';\nimport type { HookRegistry } from '../hooks/registry.js';\nimport type { Container } from '../kernel/container.js';\nimport type { EventBus, EventName, Listener } from '../kernel/events.js';\nimport type { Pipeline } from '../kernel/pipeline.js';\nimport type { ProviderRegistry } from '../registry/provider-registry.js';\nimport type { SlashCommandRegistry } from '../registry/slash-command-registry.js';\nimport type { ToolRegistry, ToolWrapper } from '../registry/tool-registry.js';\nimport type { Config } from '../types/config.js';\nimport type { HookEvent, HookMatcher, InProcessHook } from '../types/hooks.js';\nimport type { Logger } from '../types/logger.js';\nimport type { ModelsRegistry } from '../types/models-registry.js';\nimport type {\n MCPRegistryView,\n MetricsSinkView,\n Notifier,\n PluginAPI,\n PluginCapabilities,\n PluginDependency,\n PluginLLM,\n PluginLLMOptions,\n PluginLLMResult,\n PluginPipelines,\n ProviderFactory,\n ProviderRegistryView,\n SessionWriterView,\n SlashCommandRegistryView,\n ToolRegistryView,\n} from '../types/plugin.js';\nimport type { Provider, Request } from '../types/provider.js';\nimport type { SystemPromptContributor } from '../types/system-prompt-contributor.js';\nimport type { JSONSchema, Tool } from '../types/tool.js';\nimport { KERNEL_API_VERSION } from './loader.js';\n\nexport interface PluginAPIInit {\n ownerName: string;\n container: Container;\n events: EventBus;\n /**\n * The agent's concrete pipelines. `DefaultPluginAPI` converts each to a\n * `ReadonlyPipeline` before exposing them to the plugin \u2014 plugins can\n * inspect and invoke pipelines but cannot mutate them.\n */\n pipelines: PluginPipelines;\n toolRegistry: ToolRegistry;\n providerRegistry: ProviderRegistry;\n slashCommandRegistry?: SlashCommandRegistry | undefined;\n mcpRegistry?: MCPRegistryView | undefined;\n /**\n * The agent's extension registry. Plugins register AgentExtension\n * instances here to hook into agent lifecycle events.\n */\n extensions?: ExtensionRegistry | undefined;\n /**\n * The host's lifecycle hook registry. When provided, `api.registerHook`\n * adds in-process hooks here. When absent, `registerHook` is a noop.\n */\n hookRegistry?: HookRegistry | undefined;\n /**\n * The active session writer. Plugins append custom events here.\n * When not provided, a noop writer is used.\n */\n sessionWriter?: SessionWriterView | undefined;\n /**\n * The host's metrics sink. When set, the plugin gets a scoped view\n * that auto-prefixes metric names with `plugin.<pluginName>.`.\n * When not provided, a noop sink is used.\n */\n metricsSink?: MetricsSinkView | undefined;\n /**\n * The host's models registry (models.dev-backed catalog of providers,\n * models, and per-token pricing). When provided, plugins that need\n * model metadata (cost-tracker, billing reports) can query it instead\n * of relying on bundled tables. Optional \u2014 minimal hosts/tests may\n * omit it.\n */\n modelsRegistry?: ModelsRegistry | undefined;\n /**\n * The host's project-level mailbox. When provided, plugins that publish\n * to other agents (todo-listener, session-recap) can call `api.mailbox.send`.\n * When not provided, those plugins should gracefully no-op.\n */\n mailbox?: Mailbox | undefined;\n /**\n * Notification router for one-way channel delivery. Plugins that\n * implement `NotificationChannel` register their channel here during\n * `setup()`. Optional \u2014 minimal hosts/tests may omit it.\n */\n notifier?: Notifier | undefined;\n /**\n * LLM wiring for `api.llm`. When provided, `DefaultPluginAPI` exposes a\n * `PluginLLM` that routes completions through the host's provider layer:\n *\n * - `provider` \u2014 the host session's live default Provider instance\n * - `model` \u2014 the host session's default model id\n * - `createProvider` \u2014 optional factory used when a plugin requests a\n * DIFFERENT provider by name (per-call `opts.provider` or the plugin's\n * `config.extensions[<name>].llm.provider`). The CLI host passes an\n * implementation backed by the provider registry + saved provider\n * configs; when absent, `DefaultPluginAPI` falls back to\n * `providerRegistry.create({ ...config.providers[name], type: name })`.\n *\n * Omit entirely on minimal hosts \u2014 `api.llm` stays undefined and plugins\n * must guard.\n */\n llm?:\n | {\n provider: Provider;\n model: string;\n getProvider?: (() => Provider) | undefined;\n getModel?: (() => string) | undefined;\n createProvider?: ((name: string, model?: string) => Provider) | undefined;\n }\n | undefined;\n config: Config;\n /**\n * The host's ConfigStore. Used to wire `api.onConfigChange()`.\n * When not provided, `onConfigChange` is a noop.\n */\n configStore?: { watch(cb: (next: unknown, prev: unknown) => void): () => void };\n log: Logger;\n /**\n * Whether this plugin is first-party (\"official\"). Set by the host based on\n * the plugin's load source (e.g. shipped in the built-in factory list), NOT\n * self-declared by the plugin. Official plugins may register bare slash\n * command names and override built-ins; external plugins are namespaced.\n * Defaults to false.\n */\n official?: boolean | undefined;\n /**\n * Declared capabilities of the plugin. Used for capability-based\n * authorization checks (e.g. tool mutation permissions).\n */\n capabilities?: PluginCapabilities | undefined;\n}\n\nexport class DefaultPluginAPI implements PluginAPI {\n readonly container: Container;\n readonly events: EventBus;\n readonly pipelines: PluginPipelines;\n readonly tools: ToolRegistryView;\n readonly providers: ProviderRegistryView;\n readonly mcp: MCPRegistryView;\n readonly slashCommands: SlashCommandRegistryView;\n readonly extensions: ExtensionRegistry;\n readonly session: SessionWriterView;\n readonly metrics: MetricsSinkView;\n readonly config: Config;\n readonly log: Logger;\n readonly modelsRegistry: ModelsRegistry | undefined;\n readonly mailbox: Mailbox | undefined;\n readonly notifier: Notifier | undefined;\n readonly llm: PluginLLM | undefined;\n private readonly configStore:\n | { watch(cb: (next: unknown, prev: unknown) => void): () => void }\n | undefined;\n private readonly hookRegistry: HookRegistry | undefined;\n private readonly ownerName: string;\n private readonly pluginCleanupFns: Array<() => void> = [];\n\n constructor(init: PluginAPIInit) {\n const owner = init.ownerName;\n this.ownerName = owner;\n this.hookRegistry = init.hookRegistry;\n this.container = init.container;\n this.events = init.events;\n this.config = init.config;\n this.configStore = init.configStore;\n this.log = init.log.child({ plugin: owner });\n this.extensions = init.extensions ?? new ExtensionRegistry();\n this.session = init.sessionWriter ?? noopSession;\n this.metrics = init.metricsSink ? scopedMetrics(init.metricsSink, owner) : noopMetrics;\n this.modelsRegistry = init.modelsRegistry;\n this.mailbox = init.mailbox;\n this.notifier = init.notifier;\n // Live view of config.extensions: `/plugin llm <name> \u2026` updates flow\n // through ConfigStore.update(), and api.llm should honour the new\n // per-plugin override WITHOUT a restart. When no ConfigStore is wired\n // (minimal hosts), the setup-time snapshot stands.\n let liveConfig: Config | undefined;\n if (init.configStore) {\n const off = init.configStore.watch((next) => {\n const n = next as Config | undefined;\n if (n && typeof n === 'object') liveConfig = n;\n });\n this.pluginCleanupFns.push(off);\n }\n this.llm = init.llm\n ? makePluginLLM(\n owner,\n init.llm,\n init.providerRegistry,\n init.config,\n () => liveConfig,\n this.metrics,\n this.log,\n )\n : undefined;\n\n // Convert concrete pipelines to read-only views before passing to plugins.\n const pipelines = init.pipelines as never as Record<string, Pipeline<unknown>>;\n const readonlyPipelines: PluginPipelines = {} as PluginPipelines;\n for (const [key, pipeline] of Object.entries(pipelines)) {\n readonlyPipelines[key] = pipeline.asReadonly() as PluginPipelines[typeof key];\n }\n this.pipelines = readonlyPipelines;\n\n const tr = init.toolRegistry;\n const isOfficial = init.official === true;\n const capabilities = init.capabilities;\n // Trust tiers for the tool registry, mirroring the slash-command registry:\n // only first-party (\"official\") plugins (and core) may mutate a tool they\n // do not own. An external plugin can register, wrap, and unregister its OWN\n // tools, but must not silently downgrade a built-in's `permission` via\n // `wrap`, nor `unregister` another owner's safeguard. Officiality is set by\n // the host from the load source \u2014 never self-declared. (`register` is\n // already collision-safe: it throws on a duplicate name, so an external\n // plugin cannot shadow a built-in by re-registering it.)\n const assertCanMutateTool = (name: string, op: string): void => {\n if (isOfficial) return;\n const currentOwner = tr.ownerOf(name);\n // undefined: tool doesn't exist \u2014 let the downstream call no-op/throw.\n if (currentOwner === undefined) return;\n // `wrap` records a chain owner like \"core+plugin\"; a tool this plugin\n // solely registered and (re)wrapped is \"plugin\" or \"plugin+plugin\".\n // The plugin owns the tool only if EVERY segment is itself \u2014 so a core\n // tool (\"core\") or one another plugin touched (\"core+plugin\") is denied.\n const ownedSolelyByMe = currentOwner.split('+').every((seg) => seg === owner);\n if (ownedSolelyByMe) return;\n\n // 2026-06-13: Capability-based mutation check for non-official plugins\n // that don't own the tool. If the plugin declares toolMutateCapabilities\n // matching the tool's capabilities, allow the mutation.\n const toolCaps = tr.get(name)?.capabilities ?? [];\n const pluginMutateCaps = capabilities?.toolMutateCapabilities ?? [];\n const hasRequiredCap = toolCaps.some((c) => pluginMutateCaps.includes(c));\n\n if (!hasRequiredCap) {\n throw new Error(\n `Plugin \"${owner}\" may not ${op} tool \"${name}\" \u2014 it is owned by \"${currentOwner}\". ` +\n `Tool capabilities: [${toolCaps.join(', ') || 'none'}]. ` +\n `Plugin toolMutateCapabilities: [${pluginMutateCaps.join(', ') || 'none'}]. ` +\n `Missing required capability to mutate this tool.`,\n );\n }\n };\n this.tools = {\n register: (t: Tool) => tr.register(t, owner),\n unregister: (name: string) => {\n assertCanMutateTool(name, 'unregister');\n return tr.unregister(name);\n },\n wrap: (name: string, wrapper: ToolWrapper) => {\n assertCanMutateTool(name, 'wrap');\n tr.wrap(name, wrapper, owner);\n },\n get: (name: string) => tr.get(name),\n list: () => tr.list(),\n };\n\n const pr = init.providerRegistry;\n this.providers = {\n register: (f: ProviderFactory) => pr.register(f),\n unregister: (type: string) => pr.unregister(type),\n create: (cfg) => pr.create(cfg as { type: string }),\n list: () => pr.list(),\n };\n\n this.mcp = init.mcpRegistry ?? noopMcp;\n\n const scr = init.slashCommandRegistry;\n const official = init.official === true;\n this.slashCommands = scr\n ? {\n register: (cmd) => scr.register(cmd, owner, { official }),\n unregister: (name) => scr.unregister(name),\n get: (name) => scr.get(name),\n list: () => scr.list(),\n }\n : noopSlashCommands;\n }\n\n onEvent<K extends EventName>(event: K, handler: Listener<K>): () => void {\n const off = this.events.on(event, handler);\n this.pluginCleanupFns.push(off);\n return off;\n }\n\n onPattern(pattern: string, handler: (event: string, payload: unknown) => void): () => void {\n const off = this.events.onPattern(pattern, handler);\n this.pluginCleanupFns.push(off);\n return off;\n }\n\n emitCustom(event: string, payload: unknown): void {\n this.events.emitCustom(event, payload);\n }\n\n onConfigChange(handler: (next: Readonly<Config>, prev: Readonly<Config>) => void): () => void {\n if (!this.configStore) return () => {};\n return this.configStore.watch(handler as (next: unknown, prev: unknown) => void);\n }\n\n /** Called by the plugin loader when uninstalling the plugin. */\n drainCleanup(): void {\n for (const fn of this.pluginCleanupFns.splice(0)) {\n try {\n fn();\n } catch {\n /* best-effort */\n }\n }\n // Belt-and-braces: drain any hooks this plugin still owns. If `setup()`\n // threw partway through, the unsubscribe functions above may not cover\n // every registered hook (the push happens *after* registerInProcess\n // returns). Sweeping by owner guarantees no closure outlives its plugin.\n if (this.hookRegistry) this.hookRegistry.drainByOwner(this.ownerName);\n }\n\n registerSystemPromptContributor(c: SystemPromptContributor): () => void {\n return this.extensions.registerSystemPromptContributor(c);\n }\n\n registerHook(\n event: HookEvent,\n matcher: HookMatcher | undefined,\n hook: InProcessHook,\n options?: import('../types/hooks.js').HookRegistrationOptions | undefined,\n ): () => void {\n if (!this.hookRegistry) return () => {};\n const off = this.hookRegistry.registerInProcess(event, matcher, hook, this.ownerName, options);\n this.pluginCleanupFns.push(off);\n return off;\n }\n}\n\nconst noopMcp: MCPRegistryView = {\n start: async () => undefined,\n stop: async () => undefined,\n restart: async () => undefined,\n list: () => [],\n};\n\nconst noopSlashCommands: SlashCommandRegistryView = {\n register() {\n /* noop */\n },\n unregister() {\n return false;\n },\n get() {\n return undefined;\n },\n list() {\n return [];\n },\n};\n\nconst noopSession: SessionWriterView = {\n append: async () => {\n /* noop */\n },\n};\n\nconst noopMetrics: MetricsSinkView = {\n counter() {},\n histogram() {},\n gauge() {},\n};\n\n/**\n * Build the `api.llm` facade for one plugin.\n *\n * Resolution order for provider/model on every call:\n * 1. per-call `PluginLLMOptions.provider` / `.model`\n * 2. per-plugin config: `config.extensions[<owner>].llm.{provider,model}`\n * 3. host defaults (`init.llm.provider` / `init.llm.model`)\n *\n * Providers other than the host default are created lazily via the\n * host-supplied `createProvider` (preferred \u2014 it knows about saved\n * provider configs and non-catalog wire families) or, as a fallback,\n * `providerRegistry.create({ ...config.providers[name], type: name })`.\n * Created instances are cached per `(name, model)` for the lifetime of\n * the API object.\n */\nfunction makePluginLLM(\n owner: string,\n hostLLM: {\n provider: Provider;\n model: string;\n getProvider?: (() => Provider) | undefined;\n getModel?: (() => string) | undefined;\n createProvider?: ((name: string, model?: string) => Provider) | undefined;\n },\n providerRegistry: ProviderRegistry,\n config: Config,\n getLiveConfig: () => Config | undefined,\n metrics: MetricsSinkView,\n log: Logger,\n): PluginLLM {\n const providerCache = new Map<string, Provider>();\n const PROVIDER_CACHE_MAX = 32;\n let providerCacheConfigRef: Config | undefined = config;\n const currentConfig = (): Config => getLiveConfig() ?? config;\n const currentProvider = (): Provider => hostLLM.getProvider?.() ?? hostLLM.provider;\n const currentModel = (): string => hostLLM.getModel?.() ?? hostLLM.model;\n // Keep plugin calls bounded \u2014 a plugin should never be able to ask for\n // an effectively unbounded generation on the user's bill.\n const DEFAULT_MAX_TOKENS = 2_048;\n const HARD_MAX_TOKENS = 32_768;\n\n const pluginDefaults = (): {\n provider?: string;\n model?: string;\n maxTokens?: number;\n temperature?: number;\n } => {\n // Once a ConfigStore update has been observed, the live extensions\n // map REPLACES the setup-time snapshot \u2014 so a cleared override falls\n // back to the session default instead of resurrecting the old value.\n const extensions = currentConfig().extensions;\n const raw = extensions?.[owner]?.['llm'];\n if (!raw || typeof raw !== 'object') return {};\n const r = raw as Record<string, unknown>;\n return {\n ...(typeof r['provider'] === 'string' && r['provider'] ? { provider: r['provider'] } : {}),\n ...(typeof r['model'] === 'string' && r['model'] ? { model: r['model'] } : {}),\n ...(typeof r['maxTokens'] === 'number' ? { maxTokens: r['maxTokens'] } : {}),\n ...(typeof r['temperature'] === 'number' ? { temperature: r['temperature'] } : {}),\n };\n };\n\n const resolveProvider = (\n name: string | undefined,\n model: string,\n ): { provider: Provider; providerName: string } => {\n const defaults = pluginDefaults();\n const liveProvider = currentProvider();\n const liveConfig = currentConfig();\n if (liveConfig !== providerCacheConfigRef) {\n providerCache.clear();\n providerCacheConfigRef = liveConfig;\n }\n const providerName = name ?? defaults.provider ?? liveProvider.id;\n // The host session's own provider serves the default name directly \u2014\n // no re-creation, and per-model capabilities stay as the host resolved them.\n if (providerName === liveProvider.id) {\n return { provider: liveProvider, providerName };\n }\n const cacheKey = `${providerName}|${model}`;\n const cached = providerCache.get(cacheKey);\n if (cached) return { provider: cached, providerName };\n let created: Provider;\n if (hostLLM.createProvider) {\n created = hostLLM.createProvider(providerName, model);\n } else {\n const savedCfg = liveConfig.providers?.[providerName];\n const factoryType = savedCfg?.type ?? providerName;\n created = providerRegistry.create(\n { ...(savedCfg ?? {}), type: providerName, model },\n factoryType,\n );\n }\n while (providerCache.size >= PROVIDER_CACHE_MAX) {\n const oldest = providerCache.keys().next().value as string | undefined;\n if (oldest === undefined) break;\n providerCache.delete(oldest);\n }\n providerCache.set(cacheKey, created);\n return { provider: created, providerName };\n };\n\n return {\n defaults() {\n const d = pluginDefaults();\n return {\n provider: d.provider ?? currentProvider().id,\n model: d.model ?? currentModel(),\n };\n },\n async complete(prompt: string, opts?: PluginLLMOptions): Promise<PluginLLMResult> {\n const defaults = pluginDefaults();\n const model = opts?.model ?? defaults.model ?? currentModel();\n const { provider, providerName } = resolveProvider(opts?.provider, model);\n const maxTokens = Math.min(\n HARD_MAX_TOKENS,\n opts?.maxTokens ?? defaults.maxTokens ?? DEFAULT_MAX_TOKENS,\n );\n const temperature = opts?.temperature ?? defaults.temperature;\n const request: Request = {\n model,\n messages: [{ role: 'user', content: [{ type: 'text', text: prompt }] }],\n maxTokens,\n ...(temperature !== undefined ? { temperature } : {}),\n ...(opts?.system ? { system: [{ type: 'text', text: opts.system }] } : {}),\n ...(opts?.responseFormat === 'json'\n ? { responseFormat: { type: 'json_object' as const } }\n : {}),\n };\n const signal = opts?.signal ?? new AbortController().signal;\n metrics.counter('llm.calls', 1, { provider: providerName, model });\n try {\n const response = await provider.complete(request, { signal });\n const text = response.content\n .filter((b): b is { type: 'text'; text: string } => b.type === 'text')\n .map((b) => b.text)\n .join('');\n metrics.counter('llm.tokens_in', response.usage.input);\n metrics.counter('llm.tokens_out', response.usage.output);\n return {\n text,\n model: response.model,\n provider: providerName,\n usage: { input: response.usage.input, output: response.usage.output },\n stopReason: response.stopReason,\n };\n } catch (err) {\n metrics.counter('llm.errors', 1, { provider: providerName, model });\n log.warn(`plugin \"${owner}\" llm.complete failed`, {\n provider: providerName,\n model,\n error: err instanceof Error ? err.message : String(err),\n });\n throw err;\n }\n },\n };\n}\n\n/**\n * Wrap a MetricsSinkView so every metric name is prefixed with\n * `plugin.<pluginName>.`. This prevents metric name collisions\n * between plugins and keeps the Prometheus output organized.\n */\nfunction scopedMetrics(sink: MetricsSinkView, pluginName: string): MetricsSinkView {\n const prefix = `plugin.${pluginName}.`;\n return {\n counter(name, value, labels) {\n sink.counter(`${prefix}${name}`, value, labels);\n },\n histogram(name, value, labels) {\n sink.histogram(`${prefix}${name}`, value, labels);\n },\n gauge(name, value, labels) {\n sink.gauge(`${prefix}${name}`, value, labels);\n },\n };\n}\n\n/**\n * Define a plugin with automatic `apiVersion` injection and optional\n * TypeScript type inference for the plugin options schema.\n *\n * The `options` generic is inferred from the `factory` function's second\n * parameter, so annotating it gives you fully-typed options throughout:\n *\n * @example\n * ```ts\n * import { definePlugin } from '@wrongstack/core';\n *\n * interface MyOptions {\n * threshold: number;\n * enabled: boolean;\n * }\n *\n * const myPlugin = definePlugin(\n * {\n * name: 'my-plugin',\n * version: '0.1.0',\n * description: 'My example plugin',\n * capabilities: { tools: true },\n * configSchema: {\n * type: 'object',\n * properties: {\n * threshold: { type: 'number', default: 100 },\n * enabled: { type: 'boolean', default: true },\n * },\n * },\n * defaultConfig: { threshold: 100, enabled: true },\n * },\n * (api, options) => {\n * // options.threshold is `number` here, not `unknown`\n * api.tools.register({\n * name: 'my-tool',\n * description: `Threshold is ${options.threshold}`,\n * // ...\n * });\n * },\n * );\n *\n * export default myPlugin;\n * ```\n *\n * Plugins that don't need typed options can omit the interface and let\n * TypeScript infer from `defaultConfig`, or omit `defaultConfig` entirely\n * (options will be `undefined` at runtime, accessible via `api.config`):\n *\n * @example\n * ```ts\n * const simplePlugin = definePlugin(\n * { name: 'simple' },\n * (api) => {\n * api.tools.register({ name: 'ping', description: 'Ping the service' });\n * },\n * );\n * ```\n *\n * The `apiVersion` is automatically set to the current `KERNEL_API_VERSION`\n * so plugins are always compatible with the kernel that loaded them.\n * Plugins that need to pin to a specific kernel version can override it\n * in the returned object before exporting.\n */\nexport function definePlugin<const TOptions extends Record<string, unknown> | undefined>(\n metadata: {\n name: string;\n version?: string | undefined;\n description?: string | undefined;\n capabilities?: PluginCapabilities | undefined;\n configSchema?: JSONSchema | undefined;\n defaultConfig?: TOptions | undefined;\n dependsOn?: (string | PluginDependency)[] | undefined;\n optionalDeps?: (string | PluginDependency)[] | undefined;\n conflictsWith?: string[] | undefined;\n },\n factory: (api: PluginAPI, options: TOptions) => void | Promise<void>,\n): {\n name: string;\n version?: string | undefined;\n description?: string | undefined;\n apiVersion: string;\n capabilities?: PluginCapabilities | undefined;\n configSchema?: JSONSchema | undefined;\n defaultConfig?: TOptions | undefined;\n dependsOn?: (string | PluginDependency)[] | undefined;\n optionalDeps?: (string | PluginDependency)[] | undefined;\n conflictsWith?: string[] | undefined;\n setup: (api: PluginAPI) => void | Promise<void>;\n} {\n return {\n name: metadata.name,\n version: metadata.version,\n description: metadata.description,\n capabilities: metadata.capabilities,\n configSchema: metadata.configSchema,\n defaultConfig: metadata.defaultConfig,\n dependsOn: metadata.dependsOn,\n optionalDeps: metadata.optionalDeps,\n conflictsWith: metadata.conflictsWith,\n apiVersion: KERNEL_API_VERSION,\n // Cast the factory to match the Plugin.setup signature.\n // The opts parameter ({ signal }) is accepted by Plugin.setup but the\n // definePlugin factory doesn't need to declare it \u2014 the host always passes\n // it at the call site; the factory just doesn't have to care about it.\n setup: (api: PluginAPI) => factory(api, metadata.defaultConfig as TOptions),\n };\n}\n", "import { spawn } from 'node:child_process';\nimport { createHash } from 'node:crypto';\nimport * as fsp from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { FallbackProfileManager } from '../core/fallback-profile-manager.js';\nimport { parseModelRef } from '../core/model-ref.js';\nimport type { EventMap } from '../kernel/events.js';\nimport type { Config } from '../types/config.js';\nimport type { Plugin } from '../types/plugin.js';\nimport type { SlashCommand } from '../types/slash-command.js';\nimport { toErrorMessage } from '../utils/error.js';\nimport type {\n CascadeAgentKind,\n ChimeraCascadeNeededPayload,\n ChimeraReviewCompletePayload,\n ChimeraReviewNeededPayload,\n} from './chimera-plugin.js';\nimport { emitReviewIfChanged } from './review-claim-registry.js';\nimport { buildReviewContext } from './review-context-builder.js';\n\n// ---------------------------------------------------------------------------\n// Auto-review configuration \u2014 read from config.extensions['wstack-auto-review']\n// ---------------------------------------------------------------------------\nexport interface AutoReviewConfig {\n enabled?: boolean | undefined;\n /** Provider for review subagents. Falls back to session provider. */\n provider?: string | undefined;\n /** Model for review subagents. Falls back to session model. */\n model?: string | undefined;\n /**\n * Named fallback profile from config.fallbackProfiles.\n * Resolved via FallbackProfileManager. The first valid entry\n * becomes the primary provider/model (when provider/model are\n * omitted), and the remaining entries form the fallback chain.\n */\n fallbackProfile?: string | undefined;\n /** Debounce window in ms \u2014 wait for quiet before firing review (default 15000). */\n debounceMs?: number | undefined;\n /** Max files per review batch (default 15). */\n maxFilesPerBatch?: number | undefined;\n /** Max concurrent in-flight reviews (default 2). */\n maxConcurrentReviews?: number | undefined;\n /**\n * Cascade severity threshold: when a review finds findings at or above this\n * level, spawn follow-up agents automatically. \"off\" disables cascading,\n * \"high\" cascades on High+, \"critical\" cascades only on Critical.\n * Default: \"off\".\n */\n cascadeOn?: 'off' | 'critical' | 'high' | undefined;\n /**\n * Maximum cascade iterations (fix \u2192 re-review cycles) before the\n * self-correcting loop stops. Prevents infinite cycles. Default: 2.\n * 0 disables re-review (cascade agents investigate/fix once, no re-check).\n */\n maxCascadeDepth?: number | undefined;\n}\n\nexport interface ResolvedAutoReviewConfig {\n enabled: boolean;\n provider: string;\n model: string;\n fallbackModels: string[];\n debounceMs: number;\n maxFilesPerBatch: number;\n maxConcurrentReviews: number;\n cascadeOn: 'off' | 'critical' | 'high';\n maxCascadeDepth: number;\n}\n\nconst DEFAULT_DEBOUNCE_MS = 15_000;\nconst DEFAULT_MAX_FILES_PER_BATCH = 15;\nconst DEFAULT_MAX_CONCURRENT_REVIEWS = 2;\nconst DEFAULT_MAX_CASCADE_DEPTH = 2;\n\n/** Hard cap on `knownFingerprints` retention (RAM-leak audit 2026-07-31, MEDIUM). */\nconst MAX_KNOWN_FINGERPRINTS = 5_000;\n\n/**\n * Evict the oldest fingerprint entries past the cap (Map insertion order =\n * oldest first). Exported as a pure helper so the cap is unit-testable; the\n * plugin applies it on every `knownFingerprints` write.\n */\nexport function trimKnownFingerprints(map: Map<string, string>, max: number): void {\n while (map.size > max) {\n const oldest = map.keys().next().value;\n if (oldest === undefined) break;\n map.delete(oldest);\n }\n}\n\n/**\n * Primary + fallback assignment for a single Chimera reviewer spawn.\n * Produced by {@link selectRoundRobinReviewerAssignment} so concurrent\n * reviewers start on different models and only share a provider after\n * their own in-place retries are exhausted.\n */\nexport interface ReviewerModelAssignment {\n provider: string;\n model: string;\n /** Remaining pool entries after the selected primary, wrap-around order. */\n fallbackModels: string[];\n /** Cursor to pass on the next spawn (`cursor + 1`). */\n nextCursor: number;\n}\n\n/**\n * Build the deduped provider/model pool a reviewer can start on.\n *\n * Order is stable: configured primary first, then the fallback chain.\n * Entries must be `provider/model` (or parseable refs); bare blanks are dropped.\n */\nexport function buildReviewerModelPool(\n provider: string,\n model: string,\n fallbackModels: readonly string[] = [],\n): string[] {\n const primaryProvider = provider.trim();\n const primaryModel = model.trim();\n const primaryRef = primaryProvider && primaryModel ? `${primaryProvider}/${primaryModel}` : '';\n const seen = new Set<string>();\n const pool: string[] = [];\n for (const raw of [primaryRef, ...fallbackModels]) {\n const ref = raw.trim();\n if (!ref || seen.has(ref)) continue;\n const parsed = parseModelRef(ref);\n // Need a provider so the subagent never spawns with a bare model id that\n // 401s as \"Model is not supported\" on multi-provider hosts.\n if (!parsed.provider?.trim() || !parsed.model.trim()) continue;\n const normalized = `${parsed.provider.trim()}/${parsed.model.trim()}`;\n if (seen.has(normalized)) continue;\n // Track both spellings: `ref` rejects exact repeats cheaply, while\n // `normalized` collapses equivalent refs whose parsed whitespace differs.\n seen.add(ref);\n seen.add(normalized);\n pool.push(normalized);\n }\n return pool;\n}\n\n/**\n * Pick primary + fallback chain for the Nth concurrent reviewer via round-robin.\n *\n * Index `cursor % pool.length` becomes the primary; the rest of the pool is\n * rotated so the former primary lands last (still available after rate limits).\n * The pool must be pre-filtered by {@link buildReviewerModelPool} so every\n * non-empty entry contains both a provider and a model.\n * Pure: the caller owns the cursor (typically a process-local counter).\n */\nexport function selectRoundRobinReviewerAssignment(\n pool: readonly string[],\n cursor: number,\n /** Used only when the selected ref is somehow unparseable \u2014 defensive. */\n fallbackProvider = '',\n fallbackModel = '',\n): ReviewerModelAssignment {\n if (pool.length === 0) {\n return {\n provider: fallbackProvider,\n model: fallbackModel,\n fallbackModels: [],\n nextCursor: cursor + 1,\n };\n }\n const len = pool.length;\n const idx = ((cursor % len) + len) % len;\n const primaryRef = pool[idx]!;\n const parsed = parseModelRef(primaryRef);\n const provider = parsed.provider?.trim() || fallbackProvider;\n const model = parsed.model.trim() || fallbackModel;\n const fallbackModels = [...pool.slice(idx + 1), ...pool.slice(0, idx)];\n return {\n provider,\n model,\n fallbackModels,\n nextCursor: (idx + 1) % len,\n };\n}\n\nexport function resolveAutoReviewConfig(\n cfg: AutoReviewConfig,\n sessionConfig: Config,\n): ResolvedAutoReviewConfig {\n const mgr = new FallbackProfileManager(sessionConfig);\n const chain = cfg.fallbackProfile\n ? mgr.resolve(cfg.fallbackProfile)\n : mgr.resolveEffective({ fallbackAuto: true });\n // Normalize: empty strings are equivalent to undefined \u2014 treat them the same\n // so a config with provider: \"\" doesn't produce an empty provider string that\n // bypasses the ?? fallback below.\n const rawProvider = cfg.provider?.trim();\n const rawModel = cfg.model?.trim();\n const resolvedProvider =\n rawProvider || (chain.length > 0 ? chain[0]!.providerId : sessionConfig.provider);\n const resolvedModel = rawModel || (chain.length > 0 ? chain[0]!.model : sessionConfig.model);\n const profileFallbackModels = chain\n .filter((entry) => entry.providerId !== resolvedProvider || entry.model !== resolvedModel)\n .map((entry) => `${entry.providerId}/${entry.model}`);\n\n // Use only configured/effective fallback-profile entries plus the session's\n // own provider/model as a final known-working target. Chimera must not inject\n // a hard-coded provider/model rotation of its own.\n const sessionRef = `${sessionConfig.provider}/${sessionConfig.model}`;\n const fallbackModels = [\n ...profileFallbackModels.filter((ref) => ref !== sessionRef),\n sessionRef,\n ].filter((ref) => ref !== `${resolvedProvider}/${resolvedModel}`);\n\n return {\n enabled: cfg.enabled === true,\n provider: resolvedProvider,\n model: resolvedModel,\n fallbackModels,\n debounceMs: cfg.debounceMs ?? DEFAULT_DEBOUNCE_MS,\n maxFilesPerBatch: cfg.maxFilesPerBatch ?? DEFAULT_MAX_FILES_PER_BATCH,\n maxConcurrentReviews: cfg.maxConcurrentReviews ?? DEFAULT_MAX_CONCURRENT_REVIEWS,\n cascadeOn: cfg.cascadeOn ?? 'off',\n maxCascadeDepth: cfg.maxCascadeDepth ?? DEFAULT_MAX_CASCADE_DEPTH,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Severity parsing + cascade decision (exported for unit testing)\n// ---------------------------------------------------------------------------\n\nexport interface ParsedSeverities {\n critical: number;\n high: number;\n medium: number;\n}\n\n/**\n * Extract Critical/High/Medium finding counts from a Chimera review report.\n *\n * The report format (from llm/chimera-review.md) uses section headers like\n * `### Critical (2)`, `### High (1)`, `### Medium (3)`. We match the count\n * in parentheses. Falls back to counting `1.`, `2.` list-item markers under\n * a severity heading when no `(N)` is present (defensive \u2014 the prompt asks\n * for both, but LLMs sometimes omit the count).\n *\n * Returns all-zero when the text doesn't match (clean report or unparseable).\n */\nexport function parseReviewSeverity(text: string): ParsedSeverities {\n const result: ParsedSeverities = { critical: 0, high: 0, medium: 0 };\n if (!text) return result;\n\n for (const level of ['critical', 'high', 'medium'] as const) {\n // Primary pattern: \"### Critical (2)\" \u2014 the canonical report format\n const countRe = new RegExp(`###\\\\s*${level}\\\\s*\\\\((\\\\d+)\\\\)`, 'i');\n const countMatch = text.match(countRe);\n if (countMatch?.[1]) {\n result[level] = Number.parseInt(countMatch[1], 10);\n continue;\n }\n // Fallback: count ordered-list items under the heading until the next\n // heading or end. Matches \"1. [BUG] ...\" style entries.\n const sectionRe = new RegExp(`###\\\\s*${level}[^\\\\n]*\\\\n([\\\\s\\\\S]*?)(?=###|$)`, 'i');\n const sectionMatch = text.match(sectionRe);\n if (sectionMatch?.[1]) {\n const items = sectionMatch[1].match(/^\\s*\\d+\\.\\s/gm);\n result[level] = items ? items.length : 0;\n }\n }\n return result;\n}\n\n/**\n * Keywords that indicate a security-class finding. When present in a\n * Critical or High finding line, the security-scanner cascade agent is\n * selected alongside bug-hunter.\n */\nconst SECURITY_KEYWORDS = [\n 'injection',\n 'xss',\n 'csrf',\n 'ssrf',\n 'sql',\n 'secret',\n 'credential',\n 'password',\n 'api key',\n 'token',\n 'auth',\n 'shell injection',\n 'command injection',\n 'innerhtml',\n 'deserialization',\n 'path traversal',\n 'hardcoded',\n 'privilege',\n 'owasp',\n] as const;\n\n/**\n * Decide which follow-up cascade agents to spawn based on the review text.\n *\n * - `security-scanner` is selected when any Critical/High finding mentions\n * a security keyword (injection, secret, XSS, etc.).\n * - `bug-hunter` is selected whenever the threshold is crossed at all \u2014\n * any High+ finding warrants a focused bug hunt.\n *\n * Both may be returned in parallel when a finding is both severe and\n * security-related.\n */\nexport function decideCascadeAgents(\n text: string,\n severities: ParsedSeverities,\n): CascadeAgentKind[] {\n const agents = new Set<CascadeAgentKind>();\n\n // Any High+ finding \u2192 bug-hunter investigates the correctness concerns\n if (severities.critical > 0 || severities.high > 0) {\n agents.add('bug-hunter');\n }\n\n // Scan only the Critical and High sections for security keywords\n const lower = text.toLowerCase();\n const criticalHighRe = /###\\s*(?:critical|high)[^\\n]*\\n([\\s\\S]*?)(?=###|$)/gi;\n let section = criticalHighRe.exec(lower);\n while (section !== null) {\n const body = section[1] ?? '';\n if (SECURITY_KEYWORDS.some((kw) => body.includes(kw))) {\n agents.add('security-scanner');\n break;\n }\n section = criticalHighRe.exec(lower);\n }\n return [...agents];\n}\n\n/**\n * Determine whether a review result should trigger a cascade, given the\n * configured threshold and parsed severities. Returns the crossed\n * threshold, or `null` when the cascade should not fire.\n *\n * - `'high'` \u2192 fires on any High OR Critical finding\n * - `'critical'` \u2192 fires only on Critical findings\n * - `'off'` \u2192 never fires\n */\nexport function shouldCascade(\n cascadeOn: 'off' | 'critical' | 'high',\n severities: ParsedSeverities,\n): 'high' | 'critical' | null {\n if (cascadeOn === 'off') return null;\n if (severities.critical > 0) return 'critical';\n if (cascadeOn === 'high' && severities.high > 0) return 'high';\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Git helpers\n// ---------------------------------------------------------------------------\nasync function runGit(\n args: string[],\n cwd: string,\n): Promise<{ stdout: string; stderr: string; code: number }> {\n return new Promise((resolve, reject) => {\n let child;\n try {\n child = spawn('git', args, {\n cwd,\n stdio: ['ignore', 'pipe', 'pipe'],\n signal: AbortSignal.timeout(15_000),\n windowsHide: true,\n });\n } catch (err) {\n reject(err);\n return;\n }\n let stdout = '';\n let stderr = '';\n child.stdout?.on('data', (d) => {\n stdout += d;\n });\n child.stderr?.on('data', (d) => {\n stderr += d;\n });\n child.on('error', () => resolve({ stdout, stderr, code: 1 }));\n child.on('close', (code) => resolve({ stdout, stderr, code: code ?? 0 }));\n });\n}\n\nasync function isGitRepo(cwd: string): Promise<boolean> {\n const r = await runGit(['rev-parse', '--git-dir'], cwd);\n return r.code === 0;\n}\n\ninterface ChangedFile {\n path: string;\n status: 'added' | 'modified';\n}\n\nasync function getChangedFiles(cwd: string): Promise<ChangedFile[]> {\n const r = await runGit(['status', '--porcelain', '--untracked-files=no'], cwd);\n if (r.code !== 0) return [];\n const files: ChangedFile[] = [];\n for (const line of r.stdout.split('\\n')) {\n if (!line.trim()) continue;\n const x = line[0] ?? ' ';\n const y = line[1] ?? ' ';\n const rawPath = line.slice(3).trim();\n // R (rename) / C (copy) porcelain format: \"R old -> new\"\n const filePath =\n x === 'R' || x === 'C' ? (rawPath.split(' -> ').pop()?.trim() ?? rawPath) : rawPath;\n if (x === 'A' || y === 'A') {\n files.push({ path: filePath, status: 'added' });\n } else if (x === 'M' || y === 'M' || x === 'R' || x === 'C') {\n files.push({ path: filePath, status: 'modified' });\n }\n }\n return files;\n}\n\ninterface ChangedFileSnapshot extends ChangedFile {\n content: string;\n fingerprint: string;\n}\n\n/**\n * A single file bigger than this is not review material (lockfiles, changelogs,\n * generated i18n bundles, architecture dumps). Reading them only inflates the\n * snapshot: the reviewer never gets a useful signal out of them.\n */\nconst MAX_SNAPSHOT_FILE_BYTES = 256 * 1024;\n\n/**\n * Ceiling on the bytes one snapshot pass may hold at once. Reached only on\n * unusually large working trees; the remaining files are simply not snapshotted\n * this pass and get picked up once the earlier ones stop being reported.\n */\nconst MAX_SNAPSHOT_TOTAL_BYTES = 8 * 1024 * 1024;\n\nasync function snapshotChangedFiles(cwd: string): Promise<ChangedFileSnapshot[]> {\n const snapshots: ChangedFileSnapshot[] = [];\n let budget = MAX_SNAPSHOT_TOTAL_BYTES;\n for (const file of await getChangedFiles(cwd)) {\n // Filter before reading, not after \u2014 the caller drops these anyway, and\n // reading them first is what makes the pass expensive.\n if (file.path.startsWith('.wrongstack/')) continue;\n if (budget <= 0) break;\n try {\n const stat = await fsp.stat(path.join(cwd, file.path));\n if (!stat.isFile() || stat.size > MAX_SNAPSHOT_FILE_BYTES) continue;\n const content = await fsp.readFile(path.join(cwd, file.path), 'utf8');\n budget -= content.length;\n snapshots.push({\n ...file,\n content,\n fingerprint: createHash('sha256').update(content).digest('hex'),\n });\n } catch {\n // File deleted, unreadable, or not a regular UTF-8 file \u2014 skip it.\n }\n }\n return snapshots;\n}\n\n// ---------------------------------------------------------------------------\n// In-flight review tracking\n// ---------------------------------------------------------------------------\ninterface InFlightReview {\n files: string[]; // file paths being reviewed\n startedAt: number;\n subagentType: 'review' | 'cascade';\n}\n\n// ---------------------------------------------------------------------------\n// Slash command\n// ---------------------------------------------------------------------------\nfunction buildAutoReviewCommand(\n getConfig: () => ResolvedAutoReviewConfig,\n getInFlightCount: () => number,\n): SlashCommand {\n return {\n name: 'auto-review',\n category: 'Session',\n description: 'Show continuous auto-review status and configuration.',\n help: [\n '\u2554\u2550\u2550\u2550 Auto Review \u2550\u2550\u2550\u2557',\n '',\n 'Continuous code review that fires on every change during a session.',\n 'Detects git-tracked file edits and dispatches review subagents',\n 'with configurable provider/model/fallback.',\n '',\n 'When a review report contains findings at or above the cascadeOn',\n 'threshold, follow-up agents (security-scanner, bug-hunter) are',\n 'automatically spawned to investigate.',\n '',\n 'Commands:',\n ' /auto-review Show current status and config',\n ' /auto-review on Enable auto-review',\n ' /auto-review off Disable auto-review',\n '',\n 'Configuration (edit config.json extensions.wstack-auto-review):',\n ' enabled true | false',\n ' provider provider id for review agents',\n ' model model id for review agents',\n ' fallbackProfile named profile from config.fallbackProfiles',\n ' debounceMs debounce window (default 15000)',\n ' maxFilesPerBatch max files per review (default 15)',\n ' maxConcurrentReviews max parallel reviews (default 2)',\n ' cascadeOn \"off\" | \"critical\" | \"high\" (default off)',\n ' Spawns security-scanner/bug-hunter when',\n ' findings reach this severity. \"high\" fires',\n ' on any High+ finding; \"critical\" only on Critical.',\n ' maxCascadeDepth max fix+re-review cycles (default 2, 0=off)',\n ].join('\\n'),\n async run(args: string) {\n const cfg = getConfig();\n const trimmed = (args ?? '').trim().toLowerCase();\n if (trimmed === 'on' || trimmed === 'enable') {\n return {\n message:\n 'Auto-review enable/disable via config.json extensions.wstack-auto-review.enabled',\n };\n }\n if (trimmed === 'off' || trimmed === 'disable') {\n return {\n message:\n 'Auto-review enable/disable via config.json extensions.wstack-auto-review.enabled',\n };\n }\n\n const inFlight = getInFlightCount();\n const cascadeDesc =\n cfg.cascadeOn === 'off'\n ? 'disabled'\n : `on ${cfg.cascadeOn}+ \u2192 spawns security-scanner/bug-hunter`;\n return {\n message: [\n `\uD83D\uDCCB Auto Review \u2014 ${cfg.enabled ? '\u2705 enabled' : '\u23F8\uFE0F disabled'}`,\n '',\n ` Provider: ${cfg.provider}`,\n ` Model: ${cfg.model}`,\n ` Fallback: ${cfg.fallbackModels.length > 0 ? cfg.fallbackModels.join(', ') : '(none)'}`,\n ` Debounce: ${cfg.debounceMs} ms`,\n ` Max files: ${cfg.maxFilesPerBatch}`,\n ` Max parallel: ${cfg.maxConcurrentReviews}`,\n ` Cascade: ${cascadeDesc}`,\n ` Max depth: ${cfg.maxCascadeDepth} re-review cycle(s)`,\n ` In-flight: ${inFlight} review(s)`,\n '',\n 'Fires on every git-tracked file change during the session.',\n 'Disabled by default. Enable via config.json.',\n ].join('\\n'),\n };\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Plugin\n// ---------------------------------------------------------------------------\nexport function createAutoReviewPlugin(): Plugin {\n return {\n name: 'wstack-auto-review',\n version: '1.0.0',\n description: 'Continuous auto-review that fires on every code change during a session.',\n apiVersion: '^0.1',\n capabilities: { slashCommands: true },\n defaultConfig: {},\n\n setup(api) {\n // \u2500\u2500 Reactive config \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const recompute = (): ResolvedAutoReviewConfig => {\n const raw: AutoReviewConfig =\n (api.config.extensions?.['wstack-auto-review'] as AutoReviewConfig | undefined) ?? {};\n return resolveAutoReviewConfig(raw, api.config);\n };\n let resolved = recompute();\n const inFlight: InFlightReview[] = [];\n const expireInFlight = (entry: InFlightReview): void => {\n const timer = setTimeout(\n () => {\n const idx = inFlight.indexOf(entry);\n if (idx !== -1) inFlight.splice(idx, 1);\n },\n 5 * 60 * 1000,\n );\n timer.unref();\n };\n\n api.onConfigChange(() => {\n const old = resolved;\n resolved = recompute();\n if (\n old.enabled !== resolved.enabled ||\n old.provider !== resolved.provider ||\n old.model !== resolved.model\n ) {\n api.log.info(\n `[auto-review] config changed \u2014 enabled=${resolved.enabled} provider=${resolved.provider} model=${resolved.model}`,\n );\n }\n });\n\n if (!resolved.enabled) {\n api.log.info('[auto-review] disabled by config');\n return;\n }\n\n api.log.info(\n `[auto-review] loaded \u2014 provider=${resolved.provider} model=${resolved.model} debounce=${resolved.debounceMs}ms cascade=${resolved.cascadeOn}`,\n );\n\n // \u2500\u2500 State: track reviewed content and changes awaiting review \u2500\n const knownFingerprints = new Map<string, string>();\n const pendingFiles = new Map<string, ChangedFileSnapshot>();\n let reviewCounter = 0;\n let pendingReviewTimer: ReturnType<typeof setTimeout> | undefined;\n let pendingReviewWork: Promise<void> | undefined;\n let sessionEnded = false;\n let latestIterationPayload: EventMap['iteration.completed'] | undefined;\n\n /**\n * Record a reviewed file fingerprint with LRU semantics (re-insert so a\n * hot file is least likely evicted) and oldest-first eviction past the\n * cap \u2014 mirroring Context.MAX_TRACKED_FILES discipline. Without the cap,\n * one entry per distinct file path ever touched accumulates for the\n * whole session (RAM-leak audit 2026-07-31, MEDIUM).\n */\n const rememberKnownFingerprint = (filePath: string, fingerprint: string): void => {\n if (knownFingerprints.has(filePath)) knownFingerprints.delete(filePath);\n knownFingerprints.set(filePath, fingerprint);\n trimKnownFingerprints(knownFingerprints, MAX_KNOWN_FINGERPRINTS);\n };\n\n /**\n * A snapshot pass reads every changed file in the working tree, so it can\n * easily outlast one agent iteration. Without this guard the passes\n * overlap and each in-flight pass retains every file it has read so far \u2014\n * on a tree with ~90 changed files that measured 1.28GB of live strings\n * held by ~180 stacked passes. One pass at a time; skip, don't queue,\n * because the next iteration re-reads the same tree anyway.\n */\n let snapshotInFlight = false;\n const withSnapshotLock = async <T>(fn: () => Promise<T>): Promise<T | undefined> => {\n if (snapshotInFlight) {\n api.log.info('[auto-review] snapshot pass already in flight, skipping');\n return undefined;\n }\n snapshotInFlight = true;\n try {\n return await fn();\n } finally {\n snapshotInFlight = false;\n }\n };\n\n // Seed current snapshots on session start; only later content changes trigger.\n api.onEvent('agent.run.started', async () => {\n try {\n const cwd = api.config.cwd ?? process.cwd();\n if (!(await isGitRepo(cwd))) return;\n const snapshots = await withSnapshotLock(() => snapshotChangedFiles(cwd));\n if (!snapshots) return;\n for (const file of snapshots) {\n rememberKnownFingerprint(file.path, file.fingerprint);\n }\n api.log.info(`[auto-review] seeded ${knownFingerprints.size} known file snapshot(s)`);\n } catch {\n /* best-effort */\n }\n });\n\n // \u2500\u2500 /auto-review command \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n api.slashCommands.register(\n buildAutoReviewCommand(\n () => resolved,\n () => inFlight.length,\n ),\n );\n\n const cancelPendingReviewTimer = (): void => {\n if (!pendingReviewTimer) return;\n clearTimeout(pendingReviewTimer);\n pendingReviewTimer = undefined;\n };\n\n let handleIterationCompleted:\n | ((\n payload: EventMap['iteration.completed'] | undefined,\n fromQuietTimer?: boolean,\n ) => Promise<void>)\n | undefined;\n\n const schedulePendingReview = (delayMs: number): void => {\n cancelPendingReviewTimer();\n if (sessionEnded || pendingFiles.size === 0) return;\n\n const timer = setTimeout(\n async () => {\n if (pendingReviewTimer === timer) pendingReviewTimer = undefined;\n if (sessionEnded) return;\n const work = handleIterationCompleted?.(latestIterationPayload, true);\n if (!work) return;\n pendingReviewWork = work;\n try {\n await work;\n } finally {\n if (pendingReviewWork === work) pendingReviewWork = undefined;\n }\n },\n Math.max(0, delayMs),\n );\n pendingReviewTimer = timer;\n timer.unref();\n };\n\n const refreshPendingFiles = (snapshots: ChangedFileSnapshot[]): boolean => {\n let pendingChanged = false;\n const observedPaths = new Set<string>();\n for (const file of snapshots) {\n if (file.path.startsWith('.wrongstack/')) continue;\n observedPaths.add(file.path);\n if (knownFingerprints.get(file.path) !== file.fingerprint) {\n if (pendingFiles.get(file.path)?.fingerprint !== file.fingerprint) {\n pendingChanged = true;\n }\n pendingFiles.set(file.path, file);\n } else if (pendingFiles.delete(file.path)) {\n // The file reverted to the last reviewed content while queued.\n pendingChanged = true;\n }\n }\n for (const pendingPath of pendingFiles.keys()) {\n if (!observedPaths.has(pendingPath)) {\n // The path was reverted clean, deleted, or became unreadable.\n pendingFiles.delete(pendingPath);\n pendingChanged = true;\n }\n }\n return pendingChanged;\n };\n\n // \u2500\u2500 iteration.completed \u2192 detect changes \u2192 wait for quiet \u2192 emit review \u2500\u2500\n handleIterationCompleted = async (payload, fromQuietTimer = false) => {\n try {\n const cfg = resolved;\n if (!cfg.enabled || sessionEnded) return;\n if (payload) latestIterationPayload = payload;\n\n const cwd = api.config.cwd ?? process.cwd();\n if (!(await isGitRepo(cwd))) return;\n\n // Extract todos from ctx for P1 enrichment.\n // iteration.completed payload carries { ctx: Context } which has todos.\n const ctxTodos = payload?.ctx?.todos;\n\n const snapshots = await withSnapshotLock(() => snapshotChangedFiles(cwd));\n if (!snapshots) {\n if (fromQuietTimer) schedulePendingReview(cfg.debounceMs);\n return; // a pass is already walking the tree\n }\n if (sessionEnded) return;\n const now = Date.now();\n\n // Queue the latest content snapshot for every tracked file whose content\n // differs from the last emitted snapshot. Pending entries survive both\n // debounce and concurrency limits and are replaced by newer edits.\n const pendingChanged = refreshPendingFiles(snapshots);\n\n if (pendingFiles.size === 0) {\n cancelPendingReviewTimer();\n return;\n }\n\n if (cfg.debounceMs > 0) {\n if (!fromQuietTimer) {\n // A newly observed edit restarts the trailing quiet window. An\n // unchanged iteration leaves the existing deadline alone.\n if (pendingChanged || !pendingReviewTimer) {\n schedulePendingReview(cfg.debounceMs);\n api.log.info(\n `[auto-review] waiting ${cfg.debounceMs}ms for ${pendingFiles.size} pending file(s) to settle`,\n );\n }\n return;\n }\n\n // Re-read at timer expiry. If content changed without another\n // iteration event, wait for a fresh quiet window instead of\n // reviewing the stale snapshot.\n if (pendingChanged) {\n schedulePendingReview(cfg.debounceMs);\n api.log.info(\n `[auto-review] file activity continued, restarting ${cfg.debounceMs}ms quiet window for ${pendingFiles.size} pending file(s)`,\n );\n return;\n }\n }\n\n if (inFlight.length >= cfg.maxConcurrentReviews) {\n api.log.info(\n `[auto-review] at max concurrent (${cfg.maxConcurrentReviews}), retaining ${pendingFiles.size} pending file(s)`,\n );\n return;\n }\n\n // Batch: drain only the emitted entries; overflow remains pending.\n const toReview = [...pendingFiles.values()].slice(0, cfg.maxFilesPerBatch);\n if (toReview.length === 0) return;\n\n const filesWithContent: ChimeraReviewNeededPayload['files'] = toReview.map((file) => ({\n path: file.path,\n status: file.status,\n content: file.content,\n }));\n\n reviewCounter++;\n\n // \u2500\u2500 Build enriched review context (diffs, siblings, commits) \u2500\u2500\n const bundle = await buildReviewContext({\n cwd,\n config: {\n enabled: true,\n provider: cfg.provider,\n model: cfg.model,\n maxFiles: cfg.maxFilesPerBatch,\n autoFix: 'off',\n cascadeOn: 'off',\n maxCascadeDepth: 0,\n },\n files: filesWithContent,\n activeTodos: ctxTodos,\n cascadeOn: cfg.cascadeOn,\n maxCascadeDepth: cfg.maxCascadeDepth,\n });\n bundle.reviewFallbackModels = [...cfg.fallbackModels];\n const trackedChangedPaths = new Set(\n snapshots\n .filter((file) => !file.path.startsWith('.wrongstack/'))\n .map((file) => file.path),\n );\n bundle.allChangedFiles = bundle.allChangedFiles?.filter((file) =>\n trackedChangedPaths.has(file.path),\n );\n\n // session.ended owns all work from this point forward. This second\n // check closes the race where the quiet timer started building\n // context immediately before the session transitioned.\n if (sessionEnded) return;\n\n api.log.info(\n `[auto-review] #${reviewCounter} emitting review_needed (${filesWithContent.length} files, provider=${cfg.provider} model=${cfg.model})`,\n );\n\n const emittedBundle = emitReviewIfChanged(api, bundle);\n if (!emittedBundle) {\n api.log.info(\n `[auto-review] #${reviewCounter} skipped \u2014 file content already has a review in progress`,\n );\n return;\n }\n const emittedPaths = new Set(emittedBundle.files.map((file) => file.path));\n const inflightEntry: InFlightReview = {\n files: [...emittedPaths],\n startedAt: now,\n subagentType: 'review',\n };\n inFlight.push(inflightEntry);\n for (const file of toReview) {\n if (!emittedPaths.has(file.path)) continue;\n rememberKnownFingerprint(file.path, file.fingerprint);\n pendingFiles.delete(file.path);\n }\n // requires the Director (--director flag). Without it, reviews are\n // silently skipped. If reviews don't appear, check that the session\n // runs with --director or enable Director in your config.\n api.log.info(\n `[auto-review] #${reviewCounter} event emitted \u2014 ${emittedBundle.files.length}/${filesWithContent.length} files; requires Director (--director) for subagent spawning`,\n );\n\n // \u2500\u2500 Cascade: handled by the chimera.review_complete listener \u2500\u2500\n // When the review subagent finishes, execution.ts emits\n // chimera.review_complete. The listener registered below parses\n // severity from the report and emits chimera.cascade_needed when\n // findings cross the cascadeOn threshold. execution.ts then spawns\n // follow-up agents (security-scanner, bug-hunter).\n\n // Clean in-flight after a timeout (reviews complete asynchronously)\n expireInFlight(inflightEntry);\n\n if (pendingFiles.size > 0 && cfg.debounceMs > 0) {\n schedulePendingReview(cfg.debounceMs);\n }\n } catch (err) {\n api.log.warn(`[auto-review] iteration.completed handler failed: ${toErrorMessage(err)}`);\n }\n };\n\n api.onEvent('iteration.completed', async (payload) => {\n await handleIterationCompleted?.(payload);\n });\n\n // \u2500\u2500 session.ended \u2192 final review of everything \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n api.onEvent('session.ended', async () => {\n sessionEnded = true;\n const handedOffFiles = pendingFiles.size;\n cancelPendingReviewTimer();\n if (handedOffFiles > 0) {\n api.log.info(\n `[auto-review] session ended \u2014 handed ${handedOffFiles} pending mid-session file(s) to post-session review`,\n );\n }\n // If the quiet timer already started reading, wait for that pass to\n // observe sessionEnded and unwind before post-session claims the files.\n await pendingReviewWork;\n try {\n const cfg = resolved;\n if (!cfg.enabled) return;\n\n const cwd = api.config.cwd ?? process.cwd();\n if (!(await isGitRepo(cwd))) return;\n\n const allChanged = await getChangedFiles(cwd);\n const existing: ChangedFile[] = [];\n for (const f of allChanged) {\n if (f.path.startsWith('.wrongstack/')) continue;\n try {\n await fsp.access(path.join(cwd, f.path));\n existing.push(f);\n } catch {\n /* deleted */\n }\n }\n\n if (existing.length === 0) return;\n\n const toReview = existing.slice(0, cfg.maxFilesPerBatch);\n\n const filesWithContent: ChimeraReviewNeededPayload['files'] = [];\n for (const f of toReview) {\n try {\n const absPath = path.join(cwd, f.path);\n const content = await fsp.readFile(absPath, 'utf8');\n filesWithContent.push({ path: f.path, status: f.status, content });\n } catch {\n /* skip */\n }\n }\n\n if (filesWithContent.length === 0) return;\n\n // Track in-flight (honors maxConcurrentReviews cap)\n if (inFlight.length >= cfg.maxConcurrentReviews) {\n api.log.info(\n `[auto-review] session end \u2014 at max concurrent (${cfg.maxConcurrentReviews}), skipping final review`,\n );\n return;\n }\n\n // \u2500\u2500 Build enriched review context (diffs, siblings, commits) \u2500\u2500\n const bundle = await buildReviewContext({\n cwd,\n config: {\n enabled: true,\n provider: cfg.provider,\n model: cfg.model,\n maxFiles: cfg.maxFilesPerBatch,\n autoFix: 'off',\n cascadeOn: 'off',\n maxCascadeDepth: 0,\n },\n files: filesWithContent,\n cascadeOn: cfg.cascadeOn,\n maxCascadeDepth: cfg.maxCascadeDepth,\n });\n bundle.reviewFallbackModels = [...cfg.fallbackModels];\n const trackedChangedPaths = new Set(existing.map((file) => file.path));\n bundle.allChangedFiles = bundle.allChangedFiles?.filter((file) =>\n trackedChangedPaths.has(file.path),\n );\n\n const emittedBundle = emitReviewIfChanged(api, bundle);\n if (!emittedBundle) {\n api.log.info(\n '[auto-review] session end \u2014 unchanged files already have reviews in progress',\n );\n return;\n }\n const inflightEntry: InFlightReview = {\n files: emittedBundle.files.map((file) => file.path),\n startedAt: Date.now(),\n subagentType: 'review',\n };\n inFlight.push(inflightEntry);\n expireInFlight(inflightEntry);\n\n api.log.info(\n `[auto-review] session end \u2014 final review (${emittedBundle.files.length} files)`,\n );\n } catch (err) {\n api.log.warn(`[auto-review] session.ended handler failed: ${toErrorMessage(err)}`);\n }\n });\n\n // \u2500\u2500 chimera.review_complete \u2192 parse severity \u2192 emit cascade_needed \u2500\u2500\n //\n // When the review subagent finishes, execution.ts emits\n // chimera.review_complete carrying the report text + the original\n // bundle. Here we:\n // 1. Parse the finding counts from the report.\n // 2. Gate on bundle.cascadeOn (only auto-review triggers set it).\n // 3. If the threshold is crossed, decide which follow-up agents\n // to spawn (security-scanner, bug-hunter) and emit\n // chimera.cascade_needed \u2014 which execution.ts consumes to\n // spawn the follow-up subagents via the Director.\n //\n // This listener fires synchronously within the pendingChimeraWork\n // IIFE, so the cascade_needed emission reaches execution.ts before\n // the session-close await resolves.\n api.onPattern('chimera.review_complete', (_event, payload) => {\n try {\n const p = payload as ChimeraReviewCompletePayload;\n if (!p.reviewText) return; // failed review or empty report\n\n const cascadeOn = p.bundle.cascadeOn ?? 'off';\n if (cascadeOn === 'off') return;\n\n const severities = parseReviewSeverity(p.reviewText);\n const threshold = shouldCascade(cascadeOn, severities);\n if (!threshold) return;\n\n const agents = decideCascadeAgents(p.reviewText, severities);\n if (agents.length === 0) {\n // Threshold crossed but no agent selected \u2014 shouldn't happen\n // (High+ always selects bug-hunter), but guard defensively.\n return;\n }\n\n const cascadePayload: ChimeraCascadeNeededPayload = {\n bundle: p.bundle,\n reviewText: p.reviewText,\n severities,\n threshold,\n agents,\n };\n\n api.emitCustom('chimera.cascade_needed', cascadePayload);\n api.log.info(\n `[auto-review] cascade_needed emitted \u2014 ${severities.critical} critical, ${severities.high} high, ${severities.medium} medium; agents: ${agents.join(', ')}`,\n );\n } catch (err) {\n api.log.warn(\n `[auto-review] review_complete cascade handler failed: ${toErrorMessage(err)}`,\n );\n }\n });\n },\n\n teardown(api) {\n api.slashCommands.unregister('auto-review');\n api.log.info('[auto-review] unloaded');\n },\n\n async health() {\n return { ok: true, message: 'auto-review ready' };\n },\n };\n}\n", "/** A provider-qualified or provider-relative model reference. */\nexport interface ModelRef {\n provider?: string | undefined;\n model: string;\n}\n\n/** Parse `model`, `provider/model`, or `provider model`. */\nexport function parseModelRef(ref: string): ModelRef {\n const trimmed = ref.trim();\n const slash = trimmed.indexOf('/');\n if (slash !== -1) {\n return {\n provider: trimmed.slice(0, slash) || undefined,\n model: trimmed.slice(slash + 1).trim(),\n };\n }\n const parts = trimmed.split(/\\s+/);\n if (parts.length >= 2) {\n return { provider: parts[0], model: parts.slice(1).join(' ') };\n }\n return { model: trimmed };\n}\n\nexport function formatModelRef(ref: ModelRef, defaultProvider?: string | undefined): string {\n const provider = ref.provider ?? defaultProvider;\n return provider ? `${provider}/${ref.model}` : ref.model;\n}\n\nexport function normalizeModelRef(ref: string, defaultProvider?: string | undefined): string {\n return formatModelRef(parseModelRef(ref), defaultProvider);\n}\n", "export interface ModelBlackoutRule {\n id: string;\n enabled?: boolean | undefined;\n provider?: string | undefined;\n model?: string | undefined;\n /** JavaScript weekday numbers: Sunday=0 \u2026 Saturday=6. Empty means every day. */\n days?: number[] | undefined;\n /** Inclusive local start, HH:mm. */\n start: string;\n /** Exclusive local end, HH:mm. Equal to start means all day. */\n end: string;\n /** IANA timezone. Defaults to the host timezone. */\n timezone?: string | undefined;\n label?: string | undefined;\n /** `blackout`: deny inside. `allow_only`: deny outside all matching allow windows. */\n mode?: 'blackout' | 'allow_only' | undefined;\n}\n\nexport interface ModelCalendarDecision {\n allowed: boolean;\n rule?: ModelBlackoutRule | undefined;\n}\n\nexport function logicalCalendarTarget(\n providerId: string,\n model: string,\n): {\n providerId: string;\n model: string;\n} {\n if (providerId !== 'omniroute') return { providerId, model };\n const slash = model.indexOf('/');\n return slash > 0 && slash < model.length - 1\n ? { providerId: model.slice(0, slash), model: model.slice(slash + 1) }\n : { providerId, model };\n}\n\nconst WEEKDAYS: Record<string, number> = {\n Sun: 0,\n Mon: 1,\n Tue: 2,\n Wed: 3,\n Thu: 4,\n Fri: 5,\n Sat: 6,\n};\n\nfunction minuteOfDay(value: string): number | undefined {\n const match = /^(\\d{2}):(\\d{2})$/.exec(value);\n if (!match) return undefined;\n const hour = Number(match[1]);\n const minute = Number(match[2]);\n if (hour > 23 || minute > 59) return undefined;\n return hour * 60 + minute;\n}\n\nfunction clockAt(date: Date, timezone?: string): { day: number; minute: number } | undefined {\n try {\n const parts = new Intl.DateTimeFormat('en-US', {\n timeZone: timezone,\n weekday: 'short',\n hour: '2-digit',\n minute: '2-digit',\n hourCycle: 'h23',\n }).formatToParts(date);\n const weekday = parts.find((part) => part.type === 'weekday')?.value;\n const hour = Number(parts.find((part) => part.type === 'hour')?.value);\n const minute = Number(parts.find((part) => part.type === 'minute')?.value);\n if (!weekday || WEEKDAYS[weekday] === undefined || !Number.isFinite(hour + minute))\n return undefined;\n return { day: WEEKDAYS[weekday], minute: hour * 60 + minute };\n } catch {\n return undefined;\n }\n}\n\nfunction targetMatches(rule: ModelBlackoutRule, providerId: string, model: string): boolean {\n if (rule.provider && rule.provider !== providerId) return false;\n if (rule.model && rule.model !== model) return false;\n return Boolean(rule.provider || rule.model);\n}\n\nfunction timeMatches(rule: ModelBlackoutRule, day: number, minute: number): boolean {\n const start = minuteOfDay(rule.start);\n const end = minuteOfDay(rule.end);\n if (start === undefined || end === undefined) return false;\n const days = rule.days?.length ? new Set(rule.days) : undefined;\n if (start === end) return !days || days.has(day);\n if (start < end) return (!days || days.has(day)) && minute >= start && minute < end;\n // Overnight: Monday 22:00\u201307:00 includes early Tuesday morning.\n if (minute >= start) return !days || days.has(day);\n const previousDay = (day + 6) % 7;\n return minute < end && (!days || days.has(previousDay));\n}\n\nexport function evaluateModelCalendar(\n rules: readonly ModelBlackoutRule[] | undefined,\n providerId: string,\n model: string,\n at = new Date(),\n): ModelCalendarDecision {\n ({ providerId, model } = logicalCalendarTarget(providerId, model));\n const allowRules: ModelBlackoutRule[] = [];\n let allowMatched = false;\n for (const rule of rules ?? []) {\n if (rule.enabled === false || !targetMatches(rule, providerId, model)) continue;\n const clock = clockAt(at, rule.timezone);\n if (!clock || minuteOfDay(rule.start) === undefined || minuteOfDay(rule.end) === undefined)\n continue;\n if (rule.mode === 'allow_only') {\n allowRules.push(rule);\n if (timeMatches(rule, clock.day, clock.minute)) allowMatched = true;\n } else if (timeMatches(rule, clock.day, clock.minute)) {\n return { allowed: false, rule };\n }\n }\n if (allowRules.length > 0 && !allowMatched) return { allowed: false, rule: allowRules[0] };\n return { allowed: true };\n}\n", "/**\n * FallbackProfileManager \u2014 centralized, decoupled fallback profile resolution.\n *\n * Every consumer (fallback-model, council orchestrator, one-shot LLM, plugins)\n * resolves its fallback chain through this single manager instead of parsing\n * config.fallbackProfiles independently. This guarantees consistent resolution,\n * provider-health filtering, and a single reload point on config changes.\n *\n * Design:\n * - Stable service identity: `reload()` atomically replaces the manager's\n * immutable config/profile snapshot so injected consumers stay live.\n * - Immutable outputs: every resolved chain is frozen.\n * - Provider-aware: each profile entry is checked against live provider config\n * (has API key?) before inclusion.\n * - Zero coupling: consumers only see `readonly FallbackChainEntry[]` \u2014\n * no awareness of profile names, config shape, or provider internals.\n */\n\nimport type { ProviderModelStatusTracker } from '../coordination/provider-status-tracker.js';\nimport type { Config, ProviderConfig } from '../types/config.js';\nimport { parseModelRef } from './model-ref.js';\nimport { evaluateModelCalendar } from './model-availability-calendar.js';\n\n// \u2500\u2500 Public types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** One resolved entry in a fallback chain. */\nexport interface FallbackChainEntry {\n /** Resolved provider id. */\n readonly providerId: string;\n /** Resolved model id. */\n readonly model: string;\n /** Whether this entry uses a different provider than the primary. */\n readonly providerSwitched: boolean;\n}\n\n/** Immutable fallback chain returned by the manager. */\nexport type FallbackChain = readonly FallbackChainEntry[];\n\n/**\n * Configuration-level provider health used while resolving fallback chains.\n *\n * This deliberately answers whether the runtime has enough configuration to\n * construct the provider; it does not perform a network probe. Keyless\n * self-hosted endpoints are usable when they declare a `baseUrl`.\n */\nexport interface ProviderHealth {\n readonly providerId: string;\n readonly hasKey: boolean;\n readonly hasEndpoint: boolean;\n readonly hasModels: boolean;\n readonly usable: boolean;\n}\n\n// \u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction hasText(value: unknown): value is string {\n return typeof value === 'string' && value.trim().length > 0;\n}\n\nfunction providerHasKey(entry: ProviderConfig | undefined): boolean {\n if (!entry) return false;\n if (hasText(entry.apiKey)) return true;\n if (Array.isArray(entry.apiKeys) && entry.apiKeys.some((k) => hasText(k?.apiKey))) return true;\n if (Array.isArray(entry.envVars) && entry.envVars.some((v) => hasText(process.env[v])))\n return true;\n return false;\n}\n\nfunction visibleProviderModels(\n config: Config,\n providerId: string,\n providerModels: string[],\n): string[] {\n const entry = config.providers?.[providerId];\n return entry?.models !== undefined ? [...entry.models] : providerModels;\n}\n\nfunction buildProfiles(config: Config): ReadonlyMap<string, readonly string[]> {\n const entries = new Map<string, readonly string[]>();\n for (const [name, chain] of Object.entries(config.fallbackProfiles ?? {})) {\n if (Array.isArray(chain) && chain.length > 0) {\n entries.set(name, Object.freeze([...chain]));\n }\n }\n return entries;\n}\n\n// \u2500\u2500 Manager \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class FallbackProfileManager {\n /** Immutable snapshot of config.fallbackProfiles for the active config. */\n private profiles: ReadonlyMap<string, readonly string[]>;\n /** Active frozen config snapshot for provider lookups. */\n private config: Config;\n /** Optional shared runtime status tracker. */\n private statusTracker: ProviderModelStatusTracker | undefined;\n\n constructor(config: Config, opts?: { statusTracker?: ProviderModelStatusTracker | undefined }) {\n this.config = config;\n this.profiles = buildProfiles(config);\n this.statusTracker = opts?.statusTracker;\n }\n\n /**\n * Bind (or replace) the shared runtime status tracker.\n * Called by the boot path after the tracker is created.\n */\n setStatusTracker(tracker: ProviderModelStatusTracker | undefined): void {\n this.statusTracker = tracker;\n }\n\n // \u2500\u2500 Profile existence \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n hasProfile(name: string): boolean {\n return this.profiles.has(name);\n }\n\n listProfiles(): readonly string[] {\n return Object.freeze([...this.profiles.keys()]);\n }\n\n // \u2500\u2500 Resolution \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n /**\n * Resolve a named fallback profile to a validated, provider-filtered chain.\n *\n * Returns an empty chain when:\n * - The profile doesn't exist.\n * - Every entry's provider is missing, has no key, or has no matching model.\n *\n * @param name - Profile name from config.fallbackProfiles.\n * @param defaultProvider - Used when an entry has no explicit provider.\n * @param exclude - Optional { providerId, model } to skip (avoid self-fallback).\n */\n resolve(\n name: string,\n opts: {\n defaultProvider?: string | undefined;\n exclude?: { providerId: string; model: string } | undefined;\n } = {},\n ): FallbackChain {\n const defaultProvider = opts.defaultProvider ?? this.config.provider;\n const chain = this.profiles.get(name);\n if (!chain) return FREEZER_EMPTY;\n\n const excludeKey = opts.exclude\n ? `${opts.exclude.providerId}/${opts.exclude.model}`\n : undefined;\n\n const resolved: FallbackChainEntry[] = [];\n const seen = new Set<string>();\n\n for (const ref of chain) {\n const parsed = parseModelRef(ref);\n if (!parsed.model) continue;\n\n const providerId = parsed.provider ?? defaultProvider;\n const key = `${providerId}/${parsed.model}`;\n if (seen.has(key)) continue;\n seen.add(key);\n\n // Skip self-reference\n if (excludeKey && key === excludeKey) continue;\n\n const health = this.checkProvider(providerId);\n if (!health.usable) continue;\n\n // Skip entries that are blocked by the runtime status tracker\n if (this.statusTracker && !this.statusTracker.isAvailable(providerId, parsed.model)) continue;\n if (\n !evaluateModelCalendar(this.config.modelAvailabilitySchedule, providerId, parsed.model)\n .allowed\n )\n continue;\n\n // Skip entries whose provider has no matching model in its allow-list\n // (provider may restrict which models are available).\n const allowedModels = this.config.providers?.[providerId]?.models;\n if (allowedModels && !allowedModels.includes(parsed.model)) continue;\n\n resolved.push({\n providerId,\n model: parsed.model,\n providerSwitched: providerId !== (opts.exclude?.providerId ?? this.config.provider),\n });\n }\n\n return Object.freeze(resolved);\n }\n\n /**\n * Resolve the effective fallback chain for a session: explicit fallbackModels\n * first, then named profile, then smart default (unless disabled).\n *\n * Mirrors the previous `effectiveFallbackChain()` logic but centralized.\n */\n resolveEffective(\n opts: {\n fallbackModels?: readonly string[] | undefined;\n fallbackProfile?: string | undefined;\n fallbackAuto?: boolean | undefined;\n exclude?: { providerId: string; model: string } | undefined;\n } = {},\n ): FallbackChain {\n // 1. Explicit fallbackModels (already resolved refs)\n // Only return if non-empty; empty chain falls through to next source.\n if (opts.fallbackModels && opts.fallbackModels.length > 0) {\n const resolved = this.resolveRefs(opts.fallbackModels, opts.exclude);\n if (resolved.length > 0) return resolved;\n }\n\n // 2. Named profile \u2014 only return if non-empty\n if (opts.fallbackProfile) {\n const resolved = this.resolve(opts.fallbackProfile, { exclude: opts.exclude });\n if (resolved.length > 0) return resolved;\n }\n\n // 3. Smart default\n if (opts.fallbackAuto !== false) {\n return this.smartDefault(opts.exclude);\n }\n\n return FREEZER_EMPTY;\n }\n\n // \u2500\u2500 Provider availability (read-only) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n checkProvider(providerId: string): ProviderHealth {\n const entry = this.config.providers?.[providerId];\n const isPrimary = providerId === this.config.provider;\n const hasKey = providerHasKey(entry) || (isPrimary && hasText(this.config.apiKey));\n const hasEndpoint = hasText(entry?.baseUrl) || (isPrimary && hasText(this.config.baseUrl));\n const hasModels =\n (Array.isArray(entry?.models) && entry.models.length > 0) ||\n (isPrimary && hasText(this.config.model));\n return Object.freeze({\n providerId,\n hasKey,\n hasEndpoint,\n hasModels,\n usable: hasKey || hasEndpoint,\n });\n }\n\n // \u2500\u2500 Rebuild on config change \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n /**\n * Atomically replace the active immutable snapshot while preserving this\n * service identity for every injected consumer.\n */\n reload(newConfig: Config): void {\n this.config = newConfig;\n this.profiles = buildProfiles(newConfig);\n }\n\n // \u2500\u2500 Internal helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n /**\n * Resolve an array of model ref strings (from explicit fallbackModels config).\n * Public so consumers like one-shot-llm can use it directly.\n */\n resolveRefs(\n refs: readonly string[],\n exclude?: { providerId: string; model: string },\n ): FallbackChain {\n const excludeKey = exclude ? `${exclude.providerId}/${exclude.model}` : undefined;\n const resolved: FallbackChainEntry[] = [];\n const seen = new Set<string>();\n\n for (const ref of refs) {\n const parsed = parseModelRef(ref);\n if (!parsed.model) continue;\n\n const providerId = parsed.provider ?? this.config.provider;\n const key = `${providerId}/${parsed.model}`;\n if (seen.has(key)) continue;\n seen.add(key);\n if (excludeKey && key === excludeKey) continue;\n\n // Skip entries blocked by the runtime status tracker\n if (this.statusTracker && !this.statusTracker.isAvailable(providerId, parsed.model)) continue;\n if (\n !evaluateModelCalendar(this.config.modelAvailabilitySchedule, providerId, parsed.model)\n .allowed\n )\n continue;\n\n resolved.push({\n providerId,\n model: parsed.model,\n providerSwitched: providerId !== (exclude?.providerId ?? this.config.provider),\n });\n }\n\n return Object.freeze(resolved);\n }\n\n /**\n * Derive a smart default chain from configured providers when nothing\n * explicit is set. Same-provider alternatives first, then cross-provider.\n * Limited to 4 entries to avoid burning through models on a transient blip.\n */\n private smartDefault(exclude?: { providerId: string; model: string }): FallbackChain {\n const leaderProvider = this.config.provider;\n const leaderModel = this.config.model;\n const providers = this.config.providers ?? {};\n const favoriteSet = new Set(\n (this.config.favoriteModels ?? []).map((ref) => {\n const p = parseModelRef(ref);\n return `${p.provider ?? leaderProvider}/${p.model}`;\n }),\n );\n const hasFavorites = favoriteSet.size > 0;\n const favoritesOnly = this.config.favoriteModelsOnly === true;\n const seen = new Set<string>();\n const favorites: string[] = [];\n const sameProvider: string[] = [];\n const crossProvider: string[] = [];\n\n const excludeKey = exclude ? `${exclude.providerId}/${exclude.model}` : undefined;\n\n const ids = Object.keys(providers).sort((a, b) =>\n a === leaderProvider ? -1 : b === leaderProvider ? 1 : a.localeCompare(b),\n );\n\n for (const id of ids) {\n const entry = providers[id];\n if (!this.checkProvider(id).usable) continue;\n // Skip the entire provider if it's blocked at the provider level\n // (all its models would be blocked too, but we check per-model below)\n const models = visibleProviderModels(this.config, id, entry?.models ?? []);\n for (const model of models) {\n if (id === leaderProvider && model === leaderModel) continue;\n const ref = `${id}/${model}`;\n if (seen.has(ref)) continue;\n seen.add(ref);\n if (excludeKey && ref === excludeKey) continue;\n // Skip models blocked by the runtime status tracker\n if (this.statusTracker && !this.statusTracker.isAvailable(id, model)) continue;\n if (!evaluateModelCalendar(this.config.modelAvailabilitySchedule, id, model).allowed)\n continue;\n if (favoriteSet.has(ref)) {\n favorites.push(ref);\n continue;\n }\n if (favoritesOnly && hasFavorites) continue;\n (id === leaderProvider ? sameProvider : crossProvider).push(ref);\n }\n }\n\n const MAX = 4;\n const all = [...favorites, ...sameProvider, ...crossProvider].slice(0, MAX);\n return Object.freeze(\n all.map((ref) => {\n const p = parseModelRef(ref);\n return {\n providerId: p.provider ?? leaderProvider,\n model: p.model,\n providerSwitched:\n (p.provider ?? leaderProvider) !== (exclude?.providerId ?? leaderProvider),\n } satisfies FallbackChainEntry;\n }),\n );\n }\n}\n\nconst FREEZER_EMPTY: FallbackChain = Object.freeze([]);\n", "import { createHash } from 'node:crypto';\nimport type { EventBus } from '../kernel/events.js';\nimport type { PluginAPI } from '../types/plugin.js';\nimport type { ReviewContextBundle, ReviewFileEntry } from './review-types.js';\n\ninterface ReviewClaim {\n key: string;\n fingerprint: string;\n}\n\ninterface ClaimedReview {\n bundle: ReviewContextBundle;\n claims: ReviewClaim[];\n}\n\ninterface StartedReview {\n events: EventBus;\n claims: ReviewClaim[];\n}\n\n/**\n * Review claims are scoped to the host EventBus, which is shared by the\n * Chimera and auto-review plugins for one session and garbage-collected with\n * that session. A claim means that a review has been scheduled for this exact\n * file content, not that the review has already completed.\n */\nconst claimsByEventBus = new WeakMap<EventBus, Map<string, Set<string>>>();\nconst startedReviews = new WeakMap<ReviewContextBundle, StartedReview>();\n\nfunction fingerprint(content: string): string {\n return createHash('sha256').update(content).digest('hex');\n}\n\nfunction claimKey(cwd: string, filePath: string): string {\n return `${cwd}\\0${filePath}`;\n}\n\nfunction ledgerFor(events: EventBus): Map<string, Set<string>> {\n let ledger = claimsByEventBus.get(events);\n if (!ledger) {\n ledger = new Map<string, Set<string>>();\n claimsByEventBus.set(events, ledger);\n }\n return ledger;\n}\n\nfunction claimFiles(\n events: EventBus,\n cwd: string,\n files: ReviewFileEntry[],\n): ClaimedReview['claims'] {\n const ledger = ledgerFor(events);\n const claims: ReviewClaim[] = [];\n\n for (const file of files) {\n const key = claimKey(cwd, file.path);\n const fileFingerprint = fingerprint(file.content);\n let activeFingerprints = ledger.get(key);\n if (!activeFingerprints) {\n activeFingerprints = new Set<string>();\n ledger.set(key, activeFingerprints);\n }\n if (activeFingerprints.has(fileFingerprint)) continue;\n activeFingerprints.add(fileFingerprint);\n claims.push({ key, fingerprint: fileFingerprint });\n }\n\n return claims;\n}\n\nfunction releaseClaims(events: EventBus, claims: ReviewClaim[]): void {\n const ledger = ledgerFor(events);\n for (const claim of claims) {\n const activeFingerprints = ledger.get(claim.key);\n if (!activeFingerprints) continue;\n activeFingerprints.delete(claim.fingerprint);\n if (activeFingerprints.size === 0) ledger.delete(claim.key);\n }\n}\n\n/**\n * Record review events emitted outside the automatic plugin paths, such as\n * `/review`, so the post-session pass also avoids repeating those files.\n */\nexport function recordStartedReview(events: EventBus, payload: unknown): void {\n if (!payload || typeof payload !== 'object') return;\n const candidate = payload as Partial<ReviewContextBundle>;\n if (typeof candidate.cwd !== 'string' || !Array.isArray(candidate.files)) return;\n\n const files = candidate.files.filter(\n (file): file is ReviewFileEntry =>\n Boolean(file) &&\n typeof file === 'object' &&\n typeof (file as ReviewFileEntry).path === 'string' &&\n typeof (file as ReviewFileEntry).content === 'string',\n );\n const claims = claimFiles(events, candidate.cwd, files);\n if (claims.length > 0) {\n startedReviews.set(payload as ReviewContextBundle, { events, claims });\n }\n}\n\n/**\n * Release the exact claims associated with a completed review bundle. Bundle\n * identity prevents an older completion from removing newer in-flight claims.\n */\nexport function recordCompletedReview(events: EventBus, payload: unknown): void {\n if (!payload || typeof payload !== 'object') return;\n const bundle = (payload as { bundle?: unknown }).bundle;\n if (!bundle || typeof bundle !== 'object') return;\n\n const startedReview = startedReviews.get(bundle as ReviewContextBundle);\n if (!startedReview || startedReview.events !== events) return;\n releaseClaims(events, startedReview.claims);\n startedReviews.delete(bundle as ReviewContextBundle);\n}\n\n/**\n * Atomically claim review inputs and emit only files whose exact content does\n * not already have a review in progress. The returned bundle contains only\n * claimed files and may be a strict subset of the input.\n *\n * Claims are installed immediately before the synchronous event emission, so\n * concurrent mid/post-session handlers cannot enqueue the same content twice.\n * A synchronous emit failure rolls the claims back.\n */\nexport function emitReviewIfChanged(\n api: Pick<PluginAPI, 'events' | 'emitCustom'>,\n bundle: ReviewContextBundle,\n): ReviewContextBundle | null {\n const claims = claimFiles(api.events, bundle.cwd, bundle.files);\n if (claims.length === 0) return null;\n\n const claimedKeys = new Set(claims.map((claim) => claim.key));\n const claimedBundle: ReviewContextBundle = {\n ...bundle,\n files: bundle.files.filter((file) => claimedKeys.has(claimKey(bundle.cwd, file.path))),\n };\n\n startedReviews.set(claimedBundle, { events: api.events, claims });\n try {\n api.emitCustom('chimera.review_needed', claimedBundle);\n return claimedBundle;\n } catch (err) {\n startedReviews.delete(claimedBundle);\n releaseClaims(api.events, claims);\n throw err;\n }\n}\n", "import { spawn } from 'node:child_process';\nimport type { KanbanTask } from '@wrongstack/kanban';\nimport type { ChronicleFileLineageRow } from '../chronicle/metrics-store.js';\nimport { createChronicleProjectAccess } from '../chronicle/project-access.js';\nimport type {\n ResolvedChimeraConfig,\n ReviewContextBundle,\n ReviewFileEntry,\n} from './review-types.js';\n\n// ---------------------------------------------------------------------------\n// Git helpers (shared with chimera-plugin.ts, intentionally duplicated\n// to keep this module self-contained for testing).\n// ---------------------------------------------------------------------------\n\nconst GIT_TIMEOUT_MS = 15_000;\nconst MAX_DIFF_BYTES = 50_000; // cap individual file diffs to ~50KB\nconst MAX_RECENT_COMMITS = 10;\n\nasync function runGit(\n args: string[],\n cwd: string,\n): Promise<{ stdout: string; stderr: string; code: number }> {\n return new Promise((resolve, reject) => {\n let child;\n try {\n child = spawn('git', args, {\n cwd,\n stdio: ['ignore', 'pipe', 'pipe'],\n signal: AbortSignal.timeout(GIT_TIMEOUT_MS),\n windowsHide: true,\n });\n } catch (err) {\n reject(err);\n return;\n }\n let stdout = '';\n let stderr = '';\n child.stdout?.on('data', (d: Buffer | string) => {\n stdout += d;\n });\n child.stderr?.on('data', (d: Buffer | string) => {\n stderr += d;\n });\n child.on('error', () => resolve({ stdout, stderr, code: 1 }));\n child.on('close', (code) => resolve({ stdout, stderr, code: code ?? 0 }));\n });\n}\n\n/**\n * Get the unified diff for a single file against HEAD.\n * Returns `undefined` when the file is untracked (added) or git fails.\n */\nasync function getFileDiff(cwd: string, filePath: string): Promise<string | undefined> {\n const r = await runGit(['diff', 'HEAD', '--', filePath], cwd);\n if (r.code !== 0 || !r.stdout.trim()) return undefined;\n return r.stdout.length > MAX_DIFF_BYTES\n ? `${r.stdout.slice(0, MAX_DIFF_BYTES)}\\n... (diff truncated at ${MAX_DIFF_BYTES} bytes)`\n : r.stdout;\n}\n\n/**\n * List all changed files in the working tree (porcelain status).\n * Includes both tracked modifications and untracked additions.\n *\n * Uses NUL-delimited porcelain output so Git returns raw path bytes instead of\n * C-style quoted/escaped names. Rename and copy entries contain an additional\n * source-path record; the first record is the destination path we review.\n */\nexport function parsePorcelainStatusZ(stdout: string): Array<{ path: string; status: string }> {\n const records = stdout.split('\\0');\n const out: Array<{ path: string; status: string }> = [];\n for (let index = 0; index < records.length; index++) {\n const record = records[index];\n if (!record || record.length < 3) continue;\n const statusCode = record.slice(0, 2).trim();\n const filePath = record.slice(3);\n if (filePath) out.push({ path: filePath, status: statusCode });\n if (statusCode.includes('R') || statusCode.includes('C')) index++;\n }\n return out;\n}\n\nasync function getAllChangedFiles(cwd: string): Promise<Array<{ path: string; status: string }>> {\n const r = await runGit(['status', '--porcelain', '-z'], cwd);\n return r.code === 0 ? parsePorcelainStatusZ(r.stdout) : [];\n}\n\n/**\n * Get recent commit messages (oneline), newest first.\n */\nasync function getRecentCommits(cwd: string): Promise<string[]> {\n const r = await runGit(['log', `-${MAX_RECENT_COMMITS}`, '--oneline', '--format=%s'], cwd);\n if (r.code !== 0) return [];\n return r.stdout.split('\\n').filter(Boolean);\n}\n\n// ---------------------------------------------------------------------------\n// Context builder\n// ---------------------------------------------------------------------------\n\nexport interface BuildReviewContextOptions {\n cwd: string;\n config: ResolvedChimeraConfig;\n /** Files to review, with content already read. */\n files: Array<{ path: string; status: 'added' | 'modified'; content: string }>;\n /**\n * Active todo items from the session Context (P1 enrichment).\n * Available from `ctx.todos` in the iteration.completed handler.\n * Passed in by the caller \u2014 the builder itself has no ctx access.\n */\n activeTodos?: Array<{ id: string; content: string; status: string }> | undefined;\n /**\n * Cascade severity threshold from the auto-review plugin config.\n * Threaded into the bundle so execution.ts and the cascade listener\n * can decide whether findings warrant a follow-up agent. Absent for\n * non-auto-review triggers (chimera plugin, /review slash command).\n */\n cascadeOn?: 'off' | 'critical' | 'high' | undefined;\n /**\n * Current cascade depth (0 = initial review). Increments on each\n * fix+re-review cycle; the cascade stops at maxCascadeDepth.\n */\n cascadeDepth?: number | undefined;\n /**\n * Maximum cascade iterations before the self-correcting loop stops.\n * Default 2. Absent for non-auto-review triggers.\n */\n maxCascadeDepth?: number | undefined;\n}\n\n/**\n * Enrich a bare file list with diffs, sibling-change awareness, and\n * recent commit history \u2014 the minimal \"story\" a reviewer needs to\n * judge changes in context rather than in isolation.\n *\n * This is the P0 subset: diffs + siblings + commits.\n * Future additions: todos, kanban card, prompt chain, prior findings.\n *\n * The function never throws \u2014 all enrichment is best-effort. If a git\n * operation fails, the corresponding field is simply left `undefined`,\n * and the caller still gets a valid bundle with the original file data.\n */\nexport async function buildReviewContext(\n opts: BuildReviewContextOptions,\n): Promise<ReviewContextBundle> {\n const { cwd, config } = opts;\n\n // \u2500\u2500 Enrich files with diffs \u2500\u2500\n const filesWithDiffs: ReviewFileEntry[] = [];\n for (const f of opts.files) {\n const entry: ReviewFileEntry = {\n path: f.path,\n status: f.status,\n content: f.content,\n };\n if (f.status === 'modified') {\n // Best-effort diff \u2014 undefined if git fails or file is untracked\n try {\n entry.diff = await getFileDiff(cwd, f.path);\n } catch {\n // leave diff undefined\n }\n }\n filesWithDiffs.push(entry);\n }\n\n // \u2500\u2500 Sibling changes (all working-tree changes) \u2500\u2500\n let allChangedFiles: Array<{ path: string; status: string }> | undefined;\n try {\n allChangedFiles = await getAllChangedFiles(cwd);\n } catch {\n // leave undefined\n }\n\n // \u2500\u2500 Recent commits \u2500\u2500\n let recentCommits: string[] | undefined;\n try {\n recentCommits = await getRecentCommits(cwd);\n if (recentCommits.length === 0) recentCommits = undefined;\n } catch {\n // leave undefined\n }\n\n // \u2500\u2500 Active todos (passed in from caller) \u2500\u2500\n const activeTodos =\n opts.activeTodos && opts.activeTodos.length > 0 ? opts.activeTodos : undefined;\n\n // \u2500\u2500 Cascade threshold (passed in from caller) \u2500\u2500\n const cascadeOn = opts.cascadeOn ?? undefined;\n const cascadeDepth = opts.cascadeDepth ?? undefined;\n const maxCascadeDepth = opts.maxCascadeDepth ?? undefined;\n\n // \u2500\u2500 Kanban card (P1: find active running/review task across all boards) \u2500\u2500\n let kanbanCard: ReviewContextBundle['kanbanCard'];\n try {\n kanbanCard = await findActiveKanbanCard(cwd);\n } catch {\n // kanban not configured or not installed \u2014 leave undefined\n }\n\n // \u2500\u2500 File provenance from Chronicle (P1: last event per file path) \u2500\u2500\n let fileProvenance: ReviewContextBundle['fileProvenance'];\n try {\n const paths = opts.files.map((f) => f.path);\n fileProvenance = await findFileProvenance(cwd, paths);\n if (fileProvenance.length === 0) fileProvenance = undefined;\n } catch {\n // chronicle not configured or journal unreadable \u2014 leave undefined\n }\n\n return {\n config,\n cwd,\n files: filesWithDiffs,\n allChangedFiles,\n recentCommits,\n activeTodos,\n cascadeOn,\n cascadeDepth,\n maxCascadeDepth,\n kanbanCard,\n fileProvenance,\n };\n}\n\n// ---------------------------------------------------------------------------\n// P1 enrichment: kanban card lookup\n// ---------------------------------------------------------------------------\n\n/**\n * Find the active (in_progress/review status or running/review lifecycle stage)\n * kanban task across all boards. Enrichment is safe only when exactly one card\n * is active; concurrent active cards are ambiguous and could attach another\n * task's criteria.\n *\n * Uses dynamic import so the builder doesn't hard-depend on @wrongstack/kanban\n * (which may not be installed in all contexts). Best-effort: returns\n * undefined if kanban isn't available, no boards exist, or the active card\n * cannot be identified unambiguously.\n */\nasync function findActiveKanbanCard(\n projectRoot: string,\n): Promise<ReviewContextBundle['kanbanCard']> {\n let kanbanApi: typeof import('@wrongstack/kanban');\n try {\n kanbanApi = await import('@wrongstack/kanban');\n } catch {\n return undefined; // kanban package not available\n }\n\n const activeTasks: KanbanTask[] = [];\n const boards = await kanbanApi.listBoards(projectRoot);\n for (const board of boards) {\n const data = await kanbanApi.getBoard(projectRoot, board.id);\n if (!data?.tasks) continue;\n activeTasks.push(\n ...data.tasks.filter(\n (task) =>\n task.status === 'in_progress' ||\n task.status === 'review' ||\n task.lifecycle?.currentStage === 'running' ||\n task.lifecycle?.currentStage === 'review',\n ),\n );\n }\n\n if (activeTasks.length !== 1) return undefined;\n const task = activeTasks[0];\n if (!task) return undefined;\n return {\n id: task.id,\n title: task.title,\n description: task.description,\n successCriteria: task.successCriteria?.map((criterion) => criterion.description),\n };\n}\n\n// ---------------------------------------------------------------------------\n// P1 enrichment: Chronicle file provenance\n// ---------------------------------------------------------------------------\n\n/**\n * Query the Chronicle journal for the most recent event touching each\n * changed file path. Returns agent/session/task attribution so the\n * reviewer knows WHO made the change and in what task context.\n *\n * Uses the canonical per-project Chronicle gateway. Best-effort: returns []\n * if Chronicle isn't available or the journal is empty.\n */\nasync function findFileProvenance(\n projectRoot: string,\n filePaths: string[],\n): Promise<NonNullable<ReviewContextBundle['fileProvenance']>> {\n if (filePaths.length === 0) return [];\n\n // Chronicle now raises rather than silently handing back a process-local\n // journal, so obtaining the gateway is itself a failure point. Provenance\n // enriches a review; it never gates one.\n let access: ReturnType<typeof createChronicleProjectAccess>;\n try {\n access = createChronicleProjectAccess({ projectRoot });\n } catch {\n return [];\n }\n const provenance: NonNullable<ReviewContextBundle['fileProvenance']> = [];\n try {\n // Read the derived SQLite lineage projection in one indexed query. The old\n // loop performed one full reverse scan of every raw Chronicle partition\n // per file \u2014 an 80-file review over a multi-GB journal could pin a CPU\n // core and allocate Buffers/strings inside the TUI process for minutes.\n const uniquePaths = [...new Set(filePaths)];\n const result = await access.call('metrics', {\n view: 'files',\n refresh: false,\n files: {\n paths: uniquePaths,\n latestPerPath: true,\n limit: Math.min(10_000, uniquePaths.length),\n },\n });\n const rows = result.data as ChronicleFileLineageRow[];\n const byPath = new Map(\n rows.map((row) => [normalizeReviewPath(row.path), row] as const),\n );\n for (const filePath of uniquePaths) {\n const row = byPath.get(normalizeReviewPath(filePath));\n if (!row) continue;\n provenance.push({\n path: filePath,\n agentId: row.agentId || undefined,\n taskId: row.taskId || undefined,\n eventType: lineageEventType(row),\n observedAt: row.occurredAt,\n });\n }\n } finally {\n await access.close();\n }\n return provenance;\n}\n\nfunction normalizeReviewPath(filePath: string): string {\n return filePath.replaceAll('\\\\', '/').toLocaleLowerCase();\n}\n\nfunction lineageEventType(row: ChronicleFileLineageRow): string {\n return row.source === 'external'\n ? `file.external.${row.operation || 'modified'}`\n : 'file.event';\n}\n", "import * as fsPromises from 'node:fs/promises';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { resolveWstackPaths } from '../utils/wstack-paths.js';\nimport { type ChronicleRuntimeLocation, resolveChronicleRuntimeLocation } from './identity.js';\nimport { ChronicleJournal, type ChronicleJournalStats } from './journal.js';\nimport { ChronicleMetricsStore } from './metrics-store.js';\nimport { importLegacyChronicleJournal } from './legacy-journal-import.js';\nimport { ChronicleSqliteJournal } from './sqlite-journal.js';\nimport type { ChronicleSqliteQueryEngine } from './sqlite-query.js';\nimport {\n type ChronicleProjectServerCallOptions,\n ChronicleProjectServerClient,\n type ChronicleProjectServerClientOptions,\n ChronicleRemoteJournal,\n isChronicleProjectServerAvailable,\n resolveChronicleDaemonAvailability,\n} from './project-server-client.js';\nimport type {\n ChronicleProjectServerHealth,\n ChronicleServerOperationName,\n ChronicleServerOperations,\n} from './project-server-protocol.js';\nimport { CHRONICLE_PROJECT_SERVER_PROTOCOL_VERSION } from './project-server-protocol.js';\nimport { ChronicleQueryEngine } from './query.js';\nimport type { ChronicleEventSink } from './sink.js';\nimport type { ChronicleEvent, ChronicleEventInput } from './types.js';\n\nexport interface ChronicleProjectAccessOptions {\n projectRoot: string;\n userHome?: string | undefined;\n retentionDays?: number | undefined;\n projectPaths?:\n | {\n globalRoot: string;\n projectId: string;\n projectDir: string;\n workspaceId: string;\n }\n | undefined;\n}\n\nexport interface ChronicleProjectAccess {\n readonly mode: 'server' | 'inline';\n call<O extends ChronicleServerOperationName>(\n op: O,\n args: ChronicleServerOperations[O]['args'],\n options?: ChronicleProjectServerCallOptions,\n ): Promise<ChronicleServerOperations[O]['result']>;\n close(): Promise<void>;\n}\n\nexport interface ChronicleEventJournalHandle {\n journal: ChronicleEventSink;\n identity: ChronicleRuntimeLocation;\n serverBacked: boolean;\n dispose(): Promise<void>;\n}\n\nexport function resolveChronicleProjectServerOptions(\n options: ChronicleProjectAccessOptions,\n): ChronicleProjectServerClientOptions {\n if (options.projectPaths) {\n return {\n projectRoot: path.resolve(options.projectRoot),\n ...options.projectPaths,\n ...(options.retentionDays !== undefined ? { retentionDays: options.retentionDays } : {}),\n };\n }\n const paths = resolveWstackPaths({\n projectRoot: options.projectRoot,\n userHome: options.userHome ?? os.homedir(),\n });\n return {\n projectRoot: path.resolve(options.projectRoot),\n globalRoot: paths.globalRoot,\n projectId: paths.projectHash,\n projectDir: paths.projectDir,\n workspaceId: paths.projectSlug,\n ...(options.retentionDays !== undefined ? { retentionDays: options.retentionDays } : {}),\n };\n}\n\n/**\n * Canonical read/process/control gateway for Chronicle consumers.\n *\n * Production builds use the per-project IPC owner. Explicit recovery mode\n * stays functional through the inline implementation; a missing daemon build\n * fails closed instead of silently creating a process-local journal.\n */\nexport function createChronicleProjectAccess(\n options: ChronicleProjectAccessOptions,\n): ChronicleProjectAccess {\n const resolved = resolveChronicleProjectServerOptions(options);\n if (isChronicleProjectServerAvailable()) {\n const client = new ChronicleProjectServerClient(resolved);\n return {\n mode: 'server',\n call: <O extends ChronicleServerOperationName>(\n op: O,\n args: ChronicleServerOperations[O]['args'],\n callOptions?: ChronicleProjectServerCallOptions,\n ) => client.call(op, args, callOptions),\n close: () => client.close(),\n };\n }\n assertInlineWasRequested('createChronicleProjectAccess');\n return new InlineChronicleProjectAccess(resolved);\n}\n\n/**\n * Refuse to run in-process unless the operator asked for it.\n *\n * Chronicle is a per-project singleton: one daemon owns the journal so every\n * terminal appends to the same hash chain. Dropping to an in-process journal\n * because the build could not be located gives each process its own chain\n * instead \u2014 no error, just silently divergent history. A missing build is a\n * defect to fix, not a mode to enter.\n */\nfunction assertInlineWasRequested(caller: string): void {\n if (resolveChronicleDaemonAvailability().kind !== 'missing-build') return;\n throw new Error(\n `${caller}: built Chronicle project server is unavailable. Build @wrongstack/core, ` +\n 'or set WRONGSTACK_CHRONICLE_INLINE=1 to explicitly accept a process-local journal.',\n );\n}\n\n/** Canonical producer sink selection used by CLI/TUI session wiring. */\nexport function createChronicleEventJournal(\n options: ChronicleProjectAccessOptions,\n): ChronicleEventJournalHandle {\n const resolved = resolveChronicleProjectServerOptions(options);\n const identity = resolveChronicleRuntimeLocation({\n globalRoot: resolved.globalRoot,\n projectId: resolved.projectId,\n projectDir: resolved.projectDir,\n });\n if (isChronicleProjectServerAvailable()) {\n const journal = new ChronicleRemoteJournal(resolved);\n return {\n journal,\n identity,\n serverBacked: true,\n dispose: () => journal.dispose(),\n };\n }\n assertInlineWasRequested('createChronicleEventJournal');\n if (useSqliteStore()) {\n const journal = new ChronicleSqliteEventSink(path.join(resolved.projectDir, 'chronicle'));\n return {\n journal,\n identity,\n serverBacked: false,\n dispose: () => journal.close(),\n };\n }\n const journal = new ChronicleJournal({\n filePath: legacyPartitionPath(identity),\n retentionDays: options.retentionDays,\n });\n return {\n journal,\n identity,\n serverBacked: false,\n dispose: () => journal.flush(),\n };\n}\n\n/** Compose the legacy partition path a `ChronicleJournal` writes to. */\nfunction legacyPartitionPath(location: { chronicleDirectory: string; day: string }): string {\n return path.join(location.chronicleDirectory, `${location.day}.events.jsonl`);\n}\n\n/**\n * Storage backend for the in-process path.\n *\n * SQLite is the default; `WRONGSTACK_CHRONICLE_STORE=jsonl` restores the legacy\n * partition writer. The escape hatch exists because the cut-over is the one\n * step of `chronicle-sqlite-journal-v1` that cannot be undone by re-reading the\n * old files \u2014 once events are appended to `chronicle.sqlite` they are not\n * mirrored back.\n */\nfunction useSqliteStore(): boolean {\n return process.env['WRONGSTACK_CHRONICLE_STORE'] !== 'jsonl';\n}\n\n/**\n * Producer sink over the SQLite journal.\n *\n * `createChronicleEventJournal` is synchronous but opening the store has to\n * import the legacy partitions first, so every append is queued behind that one\n * promise. Without the queue a session's first events could be written before\n * the import, landing *after* imported history in a chain that must stay dense.\n */\nclass ChronicleSqliteEventSink implements ChronicleEventSink {\n private readonly ready: Promise<ChronicleSqliteJournal>;\n private last: ChronicleJournalStats | undefined;\n\n constructor(directory: string) {\n this.ready = (async () => {\n await fsPromises.mkdir(directory, { recursive: true });\n const journal = new ChronicleSqliteJournal({ directory });\n try {\n await importLegacyChronicleJournal(journal, directory);\n } catch (error) {\n journal.close();\n throw error;\n }\n return journal;\n })();\n }\n\n async append(input: ChronicleEventInput): Promise<ChronicleEvent> {\n const journal = await this.ready;\n const event = await journal.append(input);\n this.last = journal.stats();\n return event;\n }\n\n async flush(): Promise<void> {\n await this.ready;\n }\n\n stats(): ChronicleJournalStats {\n return this.last ?? EMPTY_JOURNAL_STATS;\n }\n\n async close(): Promise<void> {\n (await this.ready).close();\n }\n}\n\nconst EMPTY_JOURNAL_STATS: ChronicleJournalStats = {\n acceptedEvents: 0,\n persistedEvents: 0,\n rejectedEvents: 0,\n failedEvents: 0,\n batches: 0,\n pendingEvents: 0,\n maxObservedPending: 0,\n largestBatch: 0,\n partitionRolls: 0,\n};\n\nclass InlineChronicleProjectAccess implements ChronicleProjectAccess {\n readonly mode = 'inline' as const;\n private readonly journals = new Map<string, ChronicleJournal>();\n private sqlite: Promise<ChronicleSqliteJournal> | undefined;\n\n constructor(private readonly options: ChronicleProjectServerClientOptions) {}\n\n /**\n * Open the SQLite journal, importing the legacy partitions the first time.\n *\n * The import is part of opening rather than a separate migration step so no\n * caller can read a half-migrated store: until it finishes, this promise has\n * not resolved and every operation is still queued behind it.\n */\n private store(): Promise<ChronicleSqliteJournal> {\n this.sqlite ??= (async () => {\n await fsPromises.mkdir(this.chronicleDirectory, { recursive: true });\n const journal = new ChronicleSqliteJournal({ directory: this.chronicleDirectory });\n try {\n await importLegacyChronicleJournal(journal, this.chronicleDirectory);\n } catch (error) {\n // Mirrors the daemon: a cached rejection would make every later call\n // fail identically while the handle holds the WAL open.\n this.sqlite = undefined;\n journal.close();\n throw error;\n }\n return journal;\n })();\n return this.sqlite;\n }\n\n async call<O extends ChronicleServerOperationName>(\n op: O,\n rawArgs: ChronicleServerOperations[O]['args'],\n _callOptions?: ChronicleProjectServerCallOptions,\n ): Promise<ChronicleServerOperations[O]['result']> {\n switch (op) {\n case 'ping':\n return this.health() as ChronicleServerOperations[O]['result'];\n case 'append': {\n const args = rawArgs as ChronicleServerOperations['append']['args'];\n if (useSqliteStore()) {\n const store = await this.store();\n return (await store.appendBatch(args.inputs)) as ChronicleServerOperations[O]['result'];\n }\n return (await Promise.all(\n args.inputs.map((input) => this.journalForToday().append(input)),\n )) as ChronicleServerOperations[O]['result'];\n }\n case 'flush':\n await this.flush();\n return undefined as ChronicleServerOperations[O]['result'];\n case 'purge': {\n const args = rawArgs as ChronicleServerOperations['purge']['args'];\n if (useSqliteStore()) {\n const store = await this.store();\n return (await store.purge(args)) as ChronicleServerOperations[O]['result'];\n }\n return (await this.journalForToday().purge(args)) as ChronicleServerOperations[O]['result'];\n }\n case 'query': {\n const args = rawArgs as ChronicleServerOperations['query']['args'];\n return (await (\n await this.queryEngine()\n ).query(args.query)) as ChronicleServerOperations[O]['result'];\n }\n case 'facet': {\n const args = rawArgs as ChronicleServerOperations['facet']['args'];\n const engine = await this.queryEngine();\n return {\n values: await engine.facet(args.field, args.query, args.limit),\n diagnostics: engine.diagnostics,\n } as ChronicleServerOperations[O]['result'];\n }\n case 'facets': {\n const args = rawArgs as ChronicleServerOperations['facets']['args'];\n const engine = await this.queryEngine();\n return {\n values: await engine.facets(args.fields, args.query, args.limit),\n diagnostics: engine.diagnostics,\n } as ChronicleServerOperations[O]['result'];\n }\n case 'graph': {\n const args = rawArgs as ChronicleServerOperations['graph']['args'];\n return (await (\n await this.queryEngine()\n ).graph(args.seed, args.hops, args.maxNodes)) as ChronicleServerOperations[O]['result'];\n }\n case 'metrics': {\n const args = rawArgs as ChronicleServerOperations['metrics']['args'];\n const store = ChronicleMetricsStore.open(this.chronicleDirectory);\n try {\n const refreshed = args.refresh === false\n ? { ingestedEvents: 0, ingestedBytes: 0, sourceFiles: 0, invalidLines: 0 }\n : await store.refresh();\n const data =\n args.view === 'providers'\n ? store.providerDaily(args.providers)\n : args.view === 'tasks'\n ? store.taskOutcomes(args.tasks)\n : args.view === 'files'\n ? store.fileLineage(args.files)\n : store.summary();\n return { refreshed, data } as ChronicleServerOperations[O]['result'];\n } finally {\n store.close();\n }\n }\n }\n }\n\n async close(): Promise<void> {\n await this.flush();\n // Releasing the SQLite handle is part of closing, not an optimization: the\n // connection holds `-wal` and `-shm` sidecars open, so leaving it dangling\n // leaks a file handle per access object and blocks directory removal.\n if (this.sqlite) {\n const store = await this.sqlite;\n this.sqlite = undefined;\n store.close();\n }\n }\n\n private get chronicleDirectory(): string {\n return path.join(this.options.projectDir, 'chronicle');\n }\n\n private journalForToday(): ChronicleJournal {\n const now = new Date();\n const day = now.toISOString().slice(0, 10);\n let journal = this.journals.get(day);\n if (!journal) {\n const identity = resolveChronicleRuntimeLocation({\n globalRoot: this.options.globalRoot,\n projectId: this.options.projectId,\n projectDir: this.options.projectDir,\n now,\n });\n journal = new ChronicleJournal({\n filePath: legacyPartitionPath(identity),\n retentionDays: this.options.retentionDays,\n });\n this.journals.set(day, journal);\n }\n return journal;\n }\n\n /**\n * Both engines expose the same read surface, so every `call()` branch is\n * backend-agnostic. The SQLite one shares the journal's connection, which is\n * also what makes the legacy import a precondition of reading.\n */\n private async queryEngine(): Promise<ChronicleQueryEngine | ChronicleSqliteQueryEngine> {\n if (useSqliteStore()) return (await this.store()).queryEngine();\n return ChronicleQueryEngine.fromDirectory(this.chronicleDirectory);\n }\n\n private async flush(): Promise<void> {\n if (useSqliteStore()) {\n // Writes are transactional, so this only has to wait for an in-flight\n // open (and its legacy import) rather than drain a buffer.\n if (this.sqlite) await this.sqlite;\n return;\n }\n await Promise.all([...this.journals.values()].map((journal) => journal.flush()));\n }\n\n private health(): ChronicleProjectServerHealth {\n const memory = process.memoryUsage();\n return {\n protocolVersion: CHRONICLE_PROJECT_SERVER_PROTOCOL_VERSION,\n pid: process.pid,\n projectRoot: this.options.projectRoot,\n projectDir: this.options.projectDir,\n chronicleDirectory: this.chronicleDirectory,\n endpoint: 'inline',\n startedAt: new Date(Date.now() - process.uptime() * 1_000).toISOString(),\n checkedAt: Date.now(),\n uptimeMs: Math.round(process.uptime() * 1_000),\n clients: 1,\n activeRequests: 0,\n journal: this.journalForToday().stats(),\n watcher: { active: false, watchedFiles: 0 },\n memory: {\n rss: memory.rss,\n heapUsed: memory.heapUsed,\n heapTotal: memory.heapTotal,\n external: memory.external,\n },\n };\n }\n}\n", "import { createHash } from 'node:crypto';\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\n\n/**\n * Path layout. All developer-level state lives in ~/.wrongstack/.\n * Per-project state is keyed by the canonical project root under\n * ~/.wrongstack/projects/<slug>/. Linked Git worktrees resolve to their main\n * checkout so coordination and durable state are shared across worktrees.\n *\n * The ONLY thing inside the project tree is the optional\n * .wrongstack/AGENTS.md (committed) and .wrongstack/skills/ (committed).\n */\n\nexport interface WstackPaths {\n /** ~/.wrongstack \u2014 global root. */\n globalRoot: string;\n /** Active profile name resolved from the bootstrap config. */\n profileName: string;\n /** ~/.wrongstack/profiles/<activeProfile> \u2014 active user-profile root. */\n profileDir: string;\n /** Absolute project root. */\n projectRoot: string;\n /** Home directory (~) \u2014 base for foreign tool state (~/.codex, ~/.agents, \u2026). */\n homeDir: string;\n /**\n * ~/.wrongstack/profiles/<activeProfile> \u2014 directory for profile-scoped\n * user state (mode.json, statusline.json, custom-context-modes.json, \u2026).\n */\n configDir: string;\n /** ~/.wrongstack/config.json \u2014 bootstrap config (activeProfile + version). */\n globalConfig: string;\n /**\n * ~/.wrongstack/profiles \u2014 directory containing per-profile configs.\n * Each profile has its own subdirectory with a config.json.\n */\n profilesDir: string;\n /**\n * Resolve the config path for a named profile.\n * Returns ~/.wrongstack/profiles/<name>/config.json.\n */\n profileConfig: (name: string) => string;\n /** Resolve ~/.wrongstack/profiles/<name>/statusline.json */\n profileStatuslineConfig: (name: string) => string;\n /** Resolve ~/.wrongstack/profiles/<name>/mode.json */\n profileModeConfig: (name: string) => string;\n /** Resolve ~/.wrongstack/profiles/<name>/provider-status.json */\n profileProviderStatus: (name: string) => string;\n /** Resolve ~/.wrongstack/profiles/<name>/update-cache.json */\n profileUpdateCache: (name: string) => string;\n /** ~/.wrongstack/.key \u2014 32 random bytes, mode 0600, AES-GCM key for the secret vault. */\n secretsKey: string;\n /** ~/.wrongstack/profiles/<activeProfile>/memory.md \u2014 profile memory. */\n globalMemory: string;\n /** ~/.wrongstack/profiles/<activeProfile>/skills \u2014 profile skills. */\n globalSkills: string;\n /** ~/.claude/skills \u2014 user-global skills from foreign coding agents (Claude Code, Codex, \u2026). Read-only. */\n globalClaudeSkills: string;\n /** ~/.wrongstack/profiles/<activeProfile>/design-kits \u2014 profile Design Studio kits. */\n globalDesignKits: string;\n /** ~/.wrongstack/profiles/<activeProfile>/prompts \u2014 profile prompt library. */\n globalPrompts: string;\n /** ~/.wrongstack/profiles/<activeProfile>/instructions \u2014 profile instruction overrides. */\n globalInstructions: string;\n /** ~/.wrongstack/profiles/<activeProfile>/prompt-usage.json \u2014 prompt usage. */\n promptUsage: string;\n /** ~/.wrongstack/cache \u2014 fetched data (models.dev, etc.). */\n cacheDir: string;\n /** ~/.wrongstack/cache/models.dev.json */\n modelsCache: string;\n /** ~/.wrongstack/cache/models-overlay.json \u2014 cached curated overlay. */\n modelsOverlayCache: string;\n /**\n * Per-project codebase symbol index (SQLite). Lives under the global project\n * dir \u2014 NOT inside the repo \u2014 so it never clutters the working tree or needs\n * gitignoring. `~/.wrongstack/projects/<hash>/codebase-index`.\n */\n projectCodebaseIndex: string;\n /** ~/.wrongstack/profiles/<activeProfile>/history \u2014 REPL line history. */\n historyFile: string;\n /** ~/.wrongstack/logs/wrongstack.log */\n logFile: string;\n /** ~/.wrongstack/projects/<hash> */\n projectDir: string;\n /** ~/.wrongstack/projects/<hash>/memory.md */\n projectMemory: string;\n /** ~/.wrongstack/projects/<hash>/sessions */\n projectSessions: string;\n /** ~/.wrongstack/projects/<hash>/trust.json */\n projectTrust: string;\n /** ~/.wrongstack/projects/<hash>/meta.json */\n projectMeta: string;\n /** ~/.wrongstack/projects/<hash>/config.local.json \u2014 optional override */\n projectLocalConfig: string;\n /** <project>/.wrongstack/config.json \u2014 per-project settings (safe fields only).\n * This lives inside the project root so it can be gitignored or shared. */\n inProjectConfig: string;\n /** <project>/.wrongstack/AGENTS.md \u2014 committed project memory. */\n inProjectAgentsFile: string;\n /** <project>/.wrongstack/skills \u2014 committed project skills. */\n inProjectSkills: string;\n /** <project>/.claude/skills \u2014 project skills authored for foreign coding agents (Claude Code, \u2026). Read-only. */\n inProjectClaudeSkills: string;\n /** <project>/.wrongstack/prompts \u2014 committed project prompt library. */\n inProjectPrompts: string;\n /** <project>/.wrongstack/instructions \u2014 committed project instruction overrides. */\n inProjectInstructions: string;\n /** <project>/.wrongstack/design-kits \u2014 committed project Design Studio kits. */\n inProjectDesignKits: string;\n /** <project>/.wrongstack/worktrees \u2014 git worktrees for per-phase isolation (gitignored). */\n inProjectWorktrees: string;\n /** Stable hash for the canonical project root (shared by linked Git worktrees). */\n projectHash: string;\n /** Human-readable canonical project slug, shared by linked Git worktrees. */\n projectSlug: string;\n /** ~/.wrongstack/projects/<hash>/goal.json \u2014 goal persistence */\n projectGoal: string;\n /** ~/.wrongstack/projects/<hash>/input-history.json \u2014 TUI prompt input history */\n projectInputHistory: string;\n /** ~/.wrongstack/projects/<hash>/specs \u2014 SDD spec files */\n projectSpecs: string;\n /** ~/.wrongstack/projects/<hash>/task-graphs \u2014 SDD task graphs */\n projectTaskGraphs: string;\n /** ~/.wrongstack/projects/<hash>/sdd-session.json \u2014 SDD session state */\n projectSddSession: string;\n /** ~/.wrongstack/projects/<hash>/plan.json \u2014 plan persistence */\n projectPlan: string;\n /** ~/.wrongstack/projects/<hash>/autophase \u2014 Goal phase-graph JSON files (dir name kept for backward compat) */\n projectAutophase: string;\n /** ~/.wrongstack/projects/<hash>/sdd-boards \u2014 live SDD board snapshots + JSONL event logs */\n projectSddBoards: string;\n /** ~/.wrongstack/profiles/<activeProfile>/sync.json \u2014 CloudSync configuration */\n syncConfig: string;\n /** ~/.wrongstack/config-history \u2014 timestamped backups on every config write */\n configHistoryDir: string;\n /** Function to get the status.json path for a project given its hash. */\n projectStatus: (projectHash: string) => string;\n}\n\n/**\n * Resolve the stable project identity root used by global WrongStack state.\n *\n * A linked Git worktree has its own checkout path and a `.git` *file* that\n * points into `<main>/.git/worktrees/<name>`. Its `commondir` points back to\n * the main checkout's `.git` directory. Treating the linked checkout path as\n * the project identity would split one repository into multiple session,\n * registry, and mailbox directories \u2014 agents in different worktrees would be\n * unable to see or message each other.\n *\n * Project-local paths still use the caller's actual checkout. Only global\n * state identity is canonicalized. Non-Git projects, normal checkouts, Git\n * submodules, and separate-git-dir layouts keep their existing identity.\n */\nexport function canonicalProjectRoot(absRoot: string): string {\n const checkoutRoot = path.resolve(absRoot);\n const dotGit = path.join(checkoutRoot, '.git');\n\n try {\n if (!fs.statSync(dotGit).isFile()) return checkoutRoot;\n\n const gitDirLine = fs.readFileSync(dotGit, 'utf8').trim();\n const match = /^gitdir:\\s*(.+)$/i.exec(gitDirLine);\n if (!match?.[1]) return checkoutRoot;\n\n const gitDir = path.resolve(checkoutRoot, match[1].trim());\n const commonDirFile = path.join(gitDir, 'commondir');\n if (!fs.statSync(commonDirFile).isFile()) return checkoutRoot;\n\n const commonDir = path.resolve(gitDir, fs.readFileSync(commonDirFile, 'utf8').trim());\n // Linked worktrees created by Git share the main checkout's `.git` dir.\n // A submodule or --separate-git-dir layout may point elsewhere; do not\n // guess a working-tree root for those shapes.\n if (path.basename(commonDir).toLowerCase() !== '.git') return checkoutRoot;\n return path.dirname(commonDir);\n } catch {\n // Missing/malformed administrative files must never make path resolution\n // fail. Falling back preserves the pre-canonicalization behavior.\n return checkoutRoot;\n }\n}\n\nexport function projectHash(absRoot: string): string {\n return createHash('sha256').update(canonicalProjectRoot(absRoot)).digest('hex').slice(0, 12);\n}\n\n/**\n * Human-readable project directory name: slugified folder name + short hash\n * suffix for uniqueness. e.g. `wrongstack-a1b2c3` instead of `3024e5e6fa58`.\n */\nexport function projectSlug(absRoot: string): string {\n const identityRoot = canonicalProjectRoot(absRoot);\n const base = slugify(path.basename(identityRoot));\n const hash = createHash('sha256').update(identityRoot).digest('hex').slice(0, 6);\n return `${base}-${hash}`;\n}\n\n/** Turn a folder name into a filesystem-safe lowercase slug. */\nfunction slugify(name: string): string {\n return (\n name\n .toLowerCase()\n // Collapse any run of non-alphanumeric chars into a single hyphen.\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, 40) || 'project'\n );\n}\n\nexport interface WstackPathOptions {\n userHome?: string | undefined;\n projectRoot: string;\n /** Override the global root (e.g. for tests). Default: `${userHome}/.wrongstack`. */\n globalRoot?: string | undefined;\n /** Explicit profile override. Otherwise read from the root bootstrap config. */\n profileName?: string | undefined;\n}\n\n/** Make an untrusted profile name safe for use as one path segment. */\nexport function safeProfileName(name: string | undefined): string {\n const safe = (name ?? '').replace(/[/\\\\:]/g, '_').replace(/\\.\\./g, '_').trim();\n return safe || 'default';\n}\n\n/**\n * Resolve the selected profile from ~/.wrongstack/config.json. The root file\n * is bootstrap metadata only; a missing/corrupt bootstrap selects `default`.\n */\nexport function activeProfileName(globalRoot: string): string {\n try {\n const parsed = JSON.parse(fs.readFileSync(path.join(globalRoot, 'config.json'), 'utf8')) as {\n activeProfile?: unknown;\n };\n return safeProfileName(typeof parsed.activeProfile === 'string' ? parsed.activeProfile : undefined);\n } catch {\n return 'default';\n }\n}\n\n/**\n * The global `~/.wrongstack` root, honoring the `WRONGSTACK_HOME` env\n * override. The override exists so tests (and sandboxed runs) can redirect\n * ALL global state \u2014 config, secrets, logs, projects/, mailboxes \u2014 away from\n * the real user home. Before it existed, `pnpm test` booted runtimes against\n * the real `~/.wrongstack`: it read the user's real config.json (starting a\n * second live Telegram poller), appended to the real wrongstack.log, and left\n * ~20k orphaned fixture dirs under projects/.\n *\n * Every code path that wants the global dir must come through here (or\n * through `resolveWstackPaths`) instead of `path.join(os.homedir(), '.wrongstack')`.\n */\nexport function wstackGlobalRoot(): string {\n const fromEnv = process.env['WRONGSTACK_HOME'];\n if (fromEnv && fromEnv.trim().length > 0) return path.resolve(fromEnv);\n return path.join(os.homedir(), '.wrongstack');\n}\n\nexport function resolveWstackPaths(opts: WstackPathOptions): WstackPaths {\n // Precedence: explicit globalRoot > explicit userHome (callers/tests that\n // pass one expect paths under it) > WRONGSTACK_HOME env > real home dir.\n const globalRoot =\n opts.globalRoot ?? (opts.userHome ? path.join(opts.userHome, '.wrongstack') : wstackGlobalRoot());\n // Home dir for FOREIGN tool state (Claude Code's ~/.claude). Independent of\n // WRONGSTACK_HOME, which redirects only WrongStack state: a real user's\n // Claude skills live in their real home, but tests pass `userHome` to keep\n // both `.wrongstack` and `.claude` under a temp dir.\n const homeDir = opts.userHome ?? os.homedir();\n const profileName = safeProfileName(opts.profileName ?? activeProfileName(globalRoot));\n const profileDir = path.join(globalRoot, 'profiles', profileName);\n const hash = projectHash(opts.projectRoot);\n const slug = projectSlug(opts.projectRoot);\n const projectDir = path.join(globalRoot, 'projects', slug);\n return {\n globalRoot,\n profileName,\n profileDir,\n projectRoot: opts.projectRoot,\n homeDir,\n configDir: profileDir,\n globalConfig: path.join(globalRoot, 'config.json'),\n profilesDir: path.join(globalRoot, 'profiles'),\n profileConfig: (name: string) => {\n return path.join(globalRoot, 'profiles', safeProfileName(name), 'config.json');\n },\n profileStatuslineConfig: (name: string) => {\n return path.join(globalRoot, 'profiles', safeProfileName(name), 'statusline.json');\n },\n profileModeConfig: (name: string) => {\n return path.join(globalRoot, 'profiles', safeProfileName(name), 'mode.json');\n },\n profileProviderStatus: (name: string) => {\n return path.join(globalRoot, 'profiles', safeProfileName(name), 'provider-status.json');\n },\n profileUpdateCache: (name: string) => {\n return path.join(globalRoot, 'profiles', safeProfileName(name), 'update-cache.json');\n },\n secretsKey: path.join(globalRoot, '.key'),\n globalMemory: path.join(profileDir, 'memory.md'),\n globalSkills: path.join(profileDir, 'skills'),\n globalClaudeSkills: path.join(homeDir, '.claude', 'skills'),\n globalDesignKits: path.join(profileDir, 'design-kits'),\n globalPrompts: path.join(profileDir, 'prompts'),\n globalInstructions: path.join(profileDir, 'instructions'),\n promptUsage: path.join(profileDir, 'prompt-usage.json'),\n cacheDir: path.join(globalRoot, 'cache'),\n modelsCache: path.join(globalRoot, 'cache', 'models.dev.json'),\n modelsOverlayCache: path.join(globalRoot, 'cache', 'models-overlay.json'),\n historyFile: path.join(profileDir, 'history'),\n logFile: path.join(globalRoot, 'logs', 'wrongstack.log'),\n projectDir,\n projectCodebaseIndex: path.join(projectDir, 'codebase-index'),\n projectMemory: path.join(projectDir, 'memory.md'),\n projectSessions: path.join(projectDir, 'sessions'),\n projectTrust: path.join(projectDir, 'trust.json'),\n projectMeta: path.join(projectDir, 'meta.json'),\n projectLocalConfig: path.join(projectDir, 'config.local.json'),\n inProjectConfig: path.join(opts.projectRoot, '.wrongstack', 'config.json'),\n inProjectAgentsFile: path.join(opts.projectRoot, '.wrongstack', 'AGENTS.md'),\n inProjectSkills: path.join(opts.projectRoot, '.wrongstack', 'skills'),\n inProjectClaudeSkills: path.join(opts.projectRoot, '.claude', 'skills'),\n inProjectPrompts: path.join(opts.projectRoot, '.wrongstack', 'prompts'),\n inProjectInstructions: path.join(opts.projectRoot, '.wrongstack', 'instructions'),\n inProjectDesignKits: path.join(opts.projectRoot, '.wrongstack', 'design-kits'),\n inProjectWorktrees: path.join(opts.projectRoot, '.wrongstack', 'worktrees'),\n projectHash: hash,\n projectSlug: slug,\n projectGoal: path.join(projectDir, 'goal.json'),\n projectInputHistory: path.join(projectDir, 'input-history.json'),\n projectSpecs: path.join(projectDir, 'specs'),\n projectTaskGraphs: path.join(projectDir, 'task-graphs'),\n projectSddSession: path.join(projectDir, 'sdd-session.json'),\n projectPlan: path.join(projectDir, 'plan.json'),\n projectAutophase: path.join(projectDir, 'autophase'),\n projectSddBoards: path.join(projectDir, 'sdd-boards'),\n syncConfig: path.join(profileDir, 'sync.json'),\n configHistoryDir: path.join(globalRoot, 'config-history'),\n projectStatus: (projectHash: string) => path.join(globalRoot, 'projects', projectHash, 'status.json'),\n };\n}\n", "import { createHash } from 'node:crypto';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\n\nexport interface ChronicleRuntimeIdentityInput {\n globalRoot: string;\n projectId: string;\n projectDir: string;\n now?: Date | undefined;\n}\n\nexport interface ChronicleRuntimeLocation {\n installationId: string;\n machineId: string;\n projectId: string;\n /** Directory holding this project's Chronicle storage, whatever its format. */\n chronicleDirectory: string;\n /**\n * Day this location was resolved for, `YYYY-MM-DD` UTC.\n *\n * It is also the chain scope: the legacy writer used it to name a partition\n * file, and SQLite uses it as the `day` column. Exposing the day rather than\n * a `.jsonl` path keeps identity resolution independent of storage format.\n */\n day: string;\n}\n\n/**\n * Resolve privacy-preserving stable IDs and the UTC day that scopes a chain.\n * Raw host names and global paths never enter the journal envelope.\n */\nexport function resolveChronicleRuntimeLocation(\n input: ChronicleRuntimeIdentityInput,\n): ChronicleRuntimeLocation {\n const day = (input.now ?? new Date()).toISOString().slice(0, 10);\n return {\n installationId: stableId('installation', path.resolve(input.globalRoot)),\n machineId: stableId('machine', `${os.hostname()}\\0${os.platform()}\\0${os.arch()}`),\n projectId: input.projectId,\n chronicleDirectory: path.join(input.projectDir, 'chronicle'),\n day,\n };\n}\n\nfunction stableId(prefix: string, value: string): string {\n return `${prefix}_${createHash('sha256').update(value).digest('hex').slice(0, 24)}`;\n}\n", "import { randomUUID } from 'node:crypto';\nimport { createReadStream } from 'node:fs';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { createInterface } from 'node:readline';\nimport { atomicWrite, withFileLock } from '../utils/atomic-write.js';\nimport { GENESIS_HASH, hashValue } from './event-hash.js';\nimport { comparePartitionPaths } from './partition-filename.js';\nimport {\n CHRONICLE_SCHEMA_VERSION,\n type ChronicleEvent,\n type ChronicleEventInput,\n type ChronicleVerifyResult,\n} from './types.js';\n\nconst DEFAULT_MAX_PARTITION_BYTES = 100 * 1024 * 1024;\nconst DEFAULT_ROTATION_WINDOW_MS = 60 * 60 * 1000;\nconst RETENTION_CHECKPOINT_VERSION = 1;\n\nexport interface ChronicleRetentionCheckpoint {\n version: typeof RETENTION_CHECKPOINT_VERSION;\n sequence: number;\n hash: string;\n}\n\nexport interface ChronicleJournalOptions {\n filePath: string;\n now?: (() => Date) | undefined;\n monotonicNow?: (() => bigint) | undefined;\n idFactory?: (() => string) | undefined;\n maxPending?: number | undefined;\n batchWindowMs?: number | undefined;\n maxPartitionSizeBytes?: number | undefined;\n rotationWindowMs?: number | undefined;\n retentionDays?: number | undefined;\n autoPurgeIntervalMs?: number | undefined;\n}\nexport interface ChronicleJournalStats {\n acceptedEvents: number; persistedEvents: number; rejectedEvents: number; failedEvents: number;\n batches: number; pendingEvents: number; maxObservedPending: number; largestBatch: number;\n lastBatchDurationMs?: number | undefined;\n partitionRolls: number;\n}\nexport interface ChroniclePurgeOptions {\n retentionDays: number;\n dryRun?: boolean | undefined;\n files?: string[] | undefined;\n}\nexport interface ChroniclePurgeResult {\n deletedCount: number;\n deletedBytes: number;\n skippedCount: number;\n errors: Array<{ file: string; reason: string }>;\n candidates?: string[] | undefined;\n}\n\nexport class ChronicleJournal {\n private readonly basePath: string;\n private readonly now: () => Date;\n private readonly monotonicNow: () => bigint;\n private readonly idFactory: () => string;\n private readonly maxPending: number;\n private readonly batchWindowMs: number;\n private readonly maxPartitionSizeBytes: number;\n private readonly rotationWindowMs: number;\n private readonly retentionDays: number;\n private readonly autoPurgeIntervalMs: number;\n private pending: Array<{ input: ChronicleEventInput; resolve: (event: ChronicleEvent) => void; reject: (error: unknown) => void; }> = [];\n private drainPromise: Promise<void> | undefined;\n private drainScheduled = false;\n private drainTimer: ReturnType<typeof setTimeout> | undefined;\n private readonly counters = { acceptedEvents: 0, persistedEvents: 0, rejectedEvents: 0, failedEvents: 0, batches: 0, maxObservedPending: 0, largestBatch: 0, partitionRolls: 0 };\n private lastBatchDurationMs: number | undefined;\n private partitionIndex = 0;\n private partitionStartedAt: number;\n private partitionSizeBytes = 0;\n private stateInitialized = false;\n private lastSequence = 0;\n private lastHash: string = GENESIS_HASH;\n private lastAutoPurgeAt = 0;\n\n constructor(options: ChronicleJournalOptions) {\n this.basePath = path.resolve(options.filePath);\n this.now = options.now ?? (() => new Date());\n this.monotonicNow = options.monotonicNow ?? (() => process.hrtime.bigint());\n this.idFactory = options.idFactory ?? randomUUID;\n this.maxPending = Math.max(1, options.maxPending ?? 100_000);\n this.batchWindowMs = Math.max(0, options.batchWindowMs ?? 5);\n this.maxPartitionSizeBytes = options.maxPartitionSizeBytes ?? DEFAULT_MAX_PARTITION_BYTES;\n this.rotationWindowMs = options.rotationWindowMs ?? DEFAULT_ROTATION_WINDOW_MS;\n this.retentionDays = options.retentionDays && Number.isFinite(options.retentionDays) && options.retentionDays > 0 ? options.retentionDays : 0;\n this.autoPurgeIntervalMs = Math.max(0, options.autoPurgeIntervalMs ?? 3_600_000);\n this.partitionStartedAt = Date.now();\n }\n\n get path(): string { return this.partitionIndex === 0 ? this.basePath : rotatedPath(this.basePath, this.partitionIndex); }\n\n stats(): ChronicleJournalStats {\n return { ...this.counters, pendingEvents: this.pending.length, ...(this.lastBatchDurationMs !== undefined ? { lastBatchDurationMs: this.lastBatchDurationMs } : {}) };\n }\n\n append(input: ChronicleEventInput): Promise<ChronicleEvent> {\n if (this.pending.length >= this.maxPending) { this.counters.rejectedEvents++; return Promise.reject(new Error(`Chronicle backpressure limit reached (${this.maxPending} pending events)`)); }\n const promise = new Promise<ChronicleEvent>((resolve, reject) => { this.pending.push({ input, resolve, reject }); });\n this.counters.acceptedEvents++;\n this.counters.maxObservedPending = Math.max(this.counters.maxObservedPending, this.pending.length);\n this.scheduleDrain();\n return promise;\n }\n\n async readAll(): Promise<ChronicleEvent[]> {\n await this.flush();\n const files = await collectPartitions(this.basePath);\n const entries: ChronicleEvent[] = [];\n for (const file of files) entries.push(...(await readEntriesStrict(file)));\n return entries;\n }\n\n async flush(): Promise<void> {\n if (this.drainTimer) { clearTimeout(this.drainTimer); this.drainTimer = undefined; this.drainScheduled = false; }\n while (this.pending.length > 0 || this.drainPromise) {\n if (this.pending.length > 0 && !this.drainPromise) this.startDrain();\n await this.drainPromise;\n }\n }\n\n async verify(): Promise<ChronicleVerifyResult> {\n await this.flush();\n const files = await collectPartitions(this.basePath);\n const checkpointResult = await readRetentionCheckpoint(this.basePath);\n if (checkpointResult.error) return { ok: false, entries: 0, brokenAt: 0, reason: checkpointResult.error };\n return verifyPartitionFiles(files, checkpointResult.checkpoint);\n }\n\n async purge(options: ChroniclePurgeOptions): Promise<ChroniclePurgeResult> {\n await this.flush();\n if (!Number.isFinite(options.retentionDays) || options.retentionDays <= 0) {\n throw new TypeError('Chronicle retentionDays must be a positive finite number');\n }\n await this.refreshStateFromDisk();\n const cutoff = Date.now() - options.retentionDays * 86400000;\n const activePath = path.resolve(this.path);\n const errors: ChroniclePurgeResult['errors'] = [];\n let dc = 0, db = 0, sc = 0;\n const suppliedFiles = options.files === undefined\n ? await collectJournalPartitions(this.basePath)\n : [...options.files];\n const eligible = new Set<string>();\n for (const suppliedPath of new Set(suppliedFiles)) {\n const file = path.resolve(suppliedPath);\n if (!isJournalPartition(file, path.dirname(this.basePath), this.basePath)) {\n errors.push({ file: suppliedPath, reason: 'not a Chronicle journal partition in this journal directory' });\n sc++;\n continue;\n }\n if (file === activePath) { sc++; continue; }\n let mtimeMs: number;\n try {\n const fileStat = await fs.lstat(file);\n if (!fileStat.isFile()) { sc++; continue; }\n mtimeMs = fileStat.mtimeMs;\n } catch (error) { if (isNotFound(error)) continue; errors.push({ file, reason: errorMessage(error) }); sc++; continue; }\n if (mtimeMs > cutoff) { sc++; continue; }\n eligible.add(file);\n }\n\n const candidates: string[] = [];\n const allPartitions = await collectJournalPartitions(this.basePath);\n for (const family of groupPartitionsByFamily(allPartitions).values()) {\n for (const file of family) {\n if (file === activePath || !eligible.has(file)) break;\n candidates.push(file);\n eligible.delete(file);\n }\n }\n sc += eligible.size;\n\n if (!options.dryRun) {\n for (const file of candidates) {\n try {\n const familyBase = partitionFamilyBase(file);\n let deletedBytes: number | undefined;\n await withFileLock(familyBase, async () => {\n const fileStat = await fs.lstat(file);\n if (!fileStat.isFile() || fileStat.mtimeMs > cutoff) return;\n const checkpointResult = await readRetentionCheckpoint(familyBase);\n if (checkpointResult.error) throw new Error(checkpointResult.error);\n const checkpoint = checkpointResult.checkpoint;\n const nextCheckpoint = await verifyRetainedPrefix(streamEntriesStrict(file), checkpoint);\n if (!nextCheckpoint) throw new Error('partition does not extend the trusted Chronicle chain');\n if (nextCheckpoint.sequence > (checkpoint?.sequence ?? 0)) {\n await writeRetentionCheckpoint(familyBase, nextCheckpoint);\n }\n deletedBytes = fileStat.size;\n await fs.unlink(file);\n });\n if (deletedBytes === undefined) { sc++; break; }\n db += deletedBytes;\n dc++;\n } catch (error) {\n errors.push({ file, reason: errorMessage(error) });\n sc++;\n // Candidates form an oldest-first prefix. Do not advance the\n // checkpoint beyond a partition that could not be removed: if its\n // checkpoint-covered bytes remain on disk, verify() must still be\n // able to anchor and validate them against that checkpoint.\n break;\n }\n }\n }\n return { deletedCount: dc, deletedBytes: db, skippedCount: sc, errors, ...(options.dryRun ? { candidates } : {}) };\n }\n\n private async maybeAutoPurge(): Promise<void> {\n if (this.retentionDays <= 0) return;\n const n = Date.now();\n if (n - this.lastAutoPurgeAt < this.autoPurgeIntervalMs) return;\n this.lastAutoPurgeAt = n;\n try { await this.purge({ retentionDays: this.retentionDays }); } catch { /* best-effort */ }\n }\n\n private scheduleDrain(): void {\n if (this.drainScheduled || this.drainPromise) return;\n this.drainScheduled = true;\n if (this.batchWindowMs === 0) {\n queueMicrotask(() => {\n this.drainScheduled = false;\n this.startDrain();\n });\n return;\n }\n this.drainTimer = setTimeout(() => { this.drainTimer = undefined; this.drainScheduled = false; this.startDrain(); }, this.batchWindowMs);\n }\n\n private startDrain(): void {\n if (this.drainPromise || this.pending.length === 0) return;\n const batch = this.pending.splice(0);\n const drain = this.persistBatch(batch);\n this.drainPromise = drain.finally(() => { this.drainPromise = undefined; if (this.pending.length > 0) this.scheduleDrain(); });\n }\n\n private async refreshStateFromDisk(): Promise<void> {\n const files = await collectPartitions(this.basePath);\n const latest = files[files.length - 1] ?? this.basePath;\n this.partitionIndex = partitionIndex(latest, this.basePath);\n const state = await readLastEntryState(latest);\n const entry = state.entry;\n // A non-empty active partition already carries the latest sequence and\n // hash-chain anchor. The retention checkpoint is only needed when no\n // retained event exists, so avoid opening (or probing for) the sidecar on\n // every normal append batch.\n const checkpointResult = entry ? {} : await readRetentionCheckpoint(this.basePath);\n if (checkpointResult.error) throw new Error(checkpointResult.error);\n const checkpoint = checkpointResult.checkpoint;\n this.lastSequence = entry?.sequence ?? checkpoint?.sequence ?? 0;\n this.lastHash = entry?.hash ?? checkpoint?.hash ?? GENESIS_HASH;\n this.partitionSizeBytes = state.size;\n this.partitionStartedAt = state.birthtimeMs ?? Date.now();\n this.stateInitialized = true;\n }\n\n private async canReuseDiskState(): Promise<boolean> {\n if (!this.stateInitialized) return false;\n const nextPartition = rotatedPath(this.basePath, this.partitionIndex + 1);\n const [currentStat, nextExists] = await Promise.all([\n fs.stat(this.path).catch((error: unknown) => {\n if (isNotFound(error)) return undefined;\n throw error;\n }),\n fs.access(nextPartition).then(\n () => true,\n (error: unknown) => {\n if (isNotFound(error)) return false;\n throw error;\n },\n ),\n ]);\n // Appends change the active partition size; rotations create the next\n // numbered partition. If neither happened since our last successful\n // batch, the cached sequence/hash anchor is still current and there is no\n // need to rescan the directory or read the JSONL tail again.\n return currentStat?.isFile() === true && currentStat.size === this.partitionSizeBytes && !nextExists;\n }\n\n private async checkRotation(): Promise<void> {\n if (this.partitionIndex === 0 && this.lastSequence === 0) return;\n if (Number.isFinite(this.rotationWindowMs) && Date.now() - this.partitionStartedAt >= this.rotationWindowMs) { this.rotate(); return; }\n if (Number.isFinite(this.maxPartitionSizeBytes) && this.partitionSizeBytes >= this.maxPartitionSizeBytes) this.rotate();\n }\n\n private rotate(): void { this.partitionIndex++; this.partitionStartedAt = Date.now(); this.partitionSizeBytes = 0; this.counters.partitionRolls++; }\n\n private async persistBatch(batch: typeof this.pending): Promise<void> {\n const started = performance.now();\n this.counters.batches++;\n this.counters.largestBatch = Math.max(this.counters.largestBatch, batch.length);\n try {\n let recorded: ChronicleEvent[] = [];\n await withFileLock(this.basePath, async () => {\n if (!(await this.canReuseDiskState())) await this.refreshStateFromDisk();\n await this.checkRotation();\n const cp = this.path;\n let prev: { sequence: number; hash: string } | undefined = this.lastSequence > 0 ? { sequence: this.lastSequence, hash: this.lastHash } : undefined;\n recorded = batch.map(({ input }) => {\n const instant = this.now().toISOString();\n const uh = { ...input, occurredAt: input.occurredAt ?? instant, monotonicNs: input.monotonicNs ?? this.monotonicNow().toString(), schemaVersion: CHRONICLE_SCHEMA_VERSION, eventId: this.idFactory(), observedAt: instant, persistedAt: instant, sequence: (prev?.sequence ?? 0) + 1, previousHash: prev?.hash ?? GENESIS_HASH };\n const event: ChronicleEvent = { ...uh, hash: hashValue(uh) };\n prev = event;\n return event;\n });\n const serialized = recorded.map((e) => JSON.stringify(e)).join('\\n') + '\\n';\n await fs.appendFile(cp, serialized, 'utf8');\n this.partitionSizeBytes += Buffer.byteLength(serialized);\n });\n const last = recorded[recorded.length - 1]!;\n this.lastSequence = last.sequence;\n this.lastHash = last.hash;\n batch.forEach((item, i) => { item.resolve(recorded[i]!); });\n this.counters.persistedEvents += batch.length;\n void this.maybeAutoPurge();\n } catch (error) {\n // appendFile can fail after a partial write. Force the next batch to\n // rebuild its chain anchor from disk instead of trusting local counters.\n this.stateInitialized = false;\n this.counters.failedEvents += batch.length;\n batch.forEach((item) => { item.reject(error); });\n } finally { this.lastBatchDurationMs = performance.now() - started; }\n }\n}\n\nfunction rotatedPath(basePath: string, index: number): string {\n const dir = path.dirname(basePath);\n const ext = path.extname(basePath);\n const base = path.basename(basePath, ext);\n return path.join(dir, `${base}.${String(index).padStart(5, '0')}${ext}`);\n}\n\n/**\n * Exported for the SQLite migration only (`legacy-journal-import.ts`).\n *\n * The importer has to walk partitions in exactly the order the writer produced\n * them and parse them with exactly the same strictness, so it reuses these\n * rather than growing a second implementation that could disagree about\n * rotation order or malformed lines. All three go away with the legacy reader\n * in phase 4 of `chronicle-sqlite-journal-v1`.\n */\nexport async function collectPartitions(basePath: string): Promise<string[]> {\n const dir = path.dirname(basePath);\n const ext = path.extname(basePath);\n const base = path.basename(basePath, ext);\n const pattern = new RegExp(`^${escapeRegex(base)}(?:\\\\.\\\\d{5})?${escapeRegex(ext)}$`);\n const result: string[] = [];\n try {\n const entries = await fs.readdir(dir, { withFileTypes: true });\n for (const entry of entries) if (entry.isFile() && pattern.test(entry.name)) result.push(path.join(dir, entry.name));\n } catch { /* ok */ }\n const baseFile = path.join(dir, base + ext);\n const rotated = result.filter((file) => file !== baseFile).sort((left, right) => parseIndex(left, base, ext) - parseIndex(right, base, ext));\n return [baseFile, ...rotated];\n}\n\nasync function collectJournalPartitions(basePath: string): Promise<string[]> {\n const directory = path.dirname(basePath);\n const result: string[] = [];\n try {\n const entries = await fs.readdir(directory, { withFileTypes: true });\n for (const entry of entries) {\n const file = path.join(directory, entry.name);\n if (entry.isFile() && isJournalPartition(file, directory, basePath)) result.push(file);\n }\n } catch { /* ok */ }\n return result.sort(comparePartitionPaths);\n}\n\nfunction isJournalPartition(filePath: string, directory: string, basePath?: string): boolean {\n if (path.dirname(path.resolve(filePath)) !== path.resolve(directory)) return false;\n const fileName = path.basename(filePath);\n if (!basePath) return false;\n const baseName = path.basename(basePath);\n const dailyFamily = /^\\d{4}-\\d{2}-\\d{2}\\.events(?:\\.\\d{5})?\\.jsonl$/;\n if (/^\\d{4}-\\d{2}-\\d{2}\\.events\\.jsonl$/.test(baseName)) return dailyFamily.test(fileName);\n return partitionFamilyBase(path.resolve(filePath)) === partitionFamilyBase(path.resolve(basePath));\n}\n\nfunction groupPartitionsByFamily(files: string[]): Map<string, string[]> {\n const groups = new Map<string, string[]>();\n for (const file of files) {\n const family = partitionFamilyBase(file);\n const group = groups.get(family) ?? [];\n group.push(file);\n groups.set(family, group);\n }\n return groups;\n}\n\nfunction partitionFamilyBase(filePath: string): string {\n return filePath.replace(/\\.\\d{5}(?=\\.jsonl$)/, '');\n}\n\nfunction retentionCheckpointPath(basePath: string): string {\n return `${partitionFamilyBase(basePath)}.retention.json`;\n}\n\nasync function verifyRetainedPrefix(\n entries: AsyncIterable<ChronicleEvent>,\n checkpoint: ChronicleRetentionCheckpoint | undefined,\n): Promise<ChronicleRetentionCheckpoint | undefined> {\n let sequence = checkpoint?.sequence ?? 0;\n let hash = checkpoint?.hash ?? GENESIS_HASH;\n let advanced = false;\n let sawEntry = false;\n for await (const entry of entries) {\n sawEntry = true;\n if (entry.sequence <= sequence) continue;\n if (entry.sequence !== sequence + 1 || entry.previousHash !== hash) return undefined;\n const { hash: recordedHash, ...content } = entry;\n if (hashValue(content) !== recordedHash) return undefined;\n sequence = entry.sequence;\n hash = recordedHash;\n advanced = true;\n }\n if (!sawEntry) return undefined;\n if (!advanced) return checkpoint;\n return { version: RETENTION_CHECKPOINT_VERSION, sequence, hash };\n}\n\nasync function verifyPartitionFiles(\n files: string[],\n checkpoint: ChronicleRetentionCheckpoint | undefined,\n): Promise<ChronicleVerifyResult> {\n const checkpointSequence = checkpoint?.sequence ?? 0;\n let previousHash = checkpoint?.hash ?? GENESIS_HASH;\n let entries = 0;\n let lastSequence = checkpointSequence;\n let coveredPrevious: ChronicleEvent | undefined;\n for (const file of files) {\n try {\n for await (const entry of streamEntriesStrict(file)) {\n const { hash: recordedHash, ...content } = entry;\n if (entry.sequence <= checkpointSequence) {\n // A checkpoint can be durably renamed just before its source\n // partition fails to unlink. Such retained bytes are still evidence:\n // validate them rather than treating every covered sequence as absent.\n if (hashValue(content) !== recordedHash) return { ok: false, entries, brokenAt: entries, reason: 'entry hash mismatch' };\n if (coveredPrevious && entry.sequence !== coveredPrevious.sequence + 1) {\n return { ok: false, entries, brokenAt: entries, reason: `sequence ${entry.sequence} is not ${coveredPrevious.sequence + 1}` };\n }\n if (coveredPrevious && entry.previousHash !== coveredPrevious.hash) {\n return { ok: false, entries, brokenAt: entries, reason: 'previous hash mismatch' };\n }\n if (entry.sequence === checkpointSequence && recordedHash !== checkpoint?.hash) {\n return { ok: false, entries, brokenAt: entries, reason: 'retention checkpoint hash mismatch' };\n }\n coveredPrevious = entry;\n continue;\n }\n const index = entries++;\n if (entry.sequence !== lastSequence + 1) return { ok: false, entries, brokenAt: index, reason: `sequence ${entry.sequence} is not ${lastSequence + 1}` };\n if (entry.previousHash !== previousHash) return { ok: false, entries, brokenAt: index, reason: 'previous hash mismatch' };\n if (hashValue(content) !== recordedHash) return { ok: false, entries, brokenAt: index, reason: 'entry hash mismatch' };\n previousHash = recordedHash;\n lastSequence = entry.sequence;\n }\n } catch (error) { return { ok: false, entries, brokenAt: entries, reason: errorMessage(error) }; }\n }\n if (\n coveredPrevious &&\n (coveredPrevious.sequence !== checkpointSequence || coveredPrevious.hash !== checkpoint?.hash)\n ) {\n return { ok: false, entries, brokenAt: entries, reason: 'retention checkpoint hash mismatch' };\n }\n return { ok: true, entries, lastSequence, lastHash: previousHash };\n}\n\nexport async function readRetentionCheckpoint(basePath: string): Promise<{\n checkpoint?: ChronicleRetentionCheckpoint | undefined;\n error?: string | undefined;\n}> {\n const checkpointPath = retentionCheckpointPath(basePath);\n let raw: string;\n try { raw = await fs.readFile(checkpointPath, 'utf8'); } catch (error) {\n return isNotFound(error) ? {} : { error: `cannot read retention checkpoint: ${errorMessage(error)}` };\n }\n try {\n const parsed = JSON.parse(raw) as Partial<ChronicleRetentionCheckpoint>;\n if (parsed.version !== RETENTION_CHECKPOINT_VERSION || !Number.isSafeInteger(parsed.sequence) || (parsed.sequence ?? -1) < 0 || !isHash(parsed.hash)) {\n return { error: 'invalid Chronicle retention checkpoint' };\n }\n return { checkpoint: parsed as ChronicleRetentionCheckpoint };\n } catch { return { error: 'invalid Chronicle retention checkpoint JSON' }; }\n}\n\nasync function writeRetentionCheckpoint(basePath: string, checkpoint: ChronicleRetentionCheckpoint): Promise<void> {\n await atomicWrite(retentionCheckpointPath(basePath), `${JSON.stringify(checkpoint)}\\n`, { mode: 0o600 });\n}\n\nfunction isHash(value: unknown): value is string {\n return typeof value === 'string' && /^[a-f0-9]{64}$/.test(value);\n}\n\nfunction parseIndex(filePath: string, base: string, ext: string): number {\n const suffix = path.basename(filePath).slice(base.length + 1, -ext.length);\n return suffix ? parseInt(suffix, 10) : 0;\n}\n\nfunction partitionIndex(filePath: string, basePath: string): number {\n const ext = path.extname(basePath);\n return parseIndex(filePath, path.basename(basePath, ext), ext);\n}\n\nfunction escapeRegex(text: string): string { return text.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'); }\n\nasync function readLastEntryState(filePath: string): Promise<{\n entry?: ChronicleEvent | undefined;\n size: number;\n birthtimeMs?: number | undefined;\n}> {\n let handle: fs.FileHandle;\n try { handle = await fs.open(filePath, 'r'); } catch (error) { if (isNotFound(error)) return { size: 0 }; throw error; }\n try {\n const stat = await handle.stat();\n const size = stat.size;\n let position = size, suffix = '';\n while (position > 0) {\n const length = Math.min(65536, position);\n position -= length;\n const buf = Buffer.allocUnsafe(length);\n await handle.read(buf, 0, length, position);\n suffix = buf.toString('utf8') + suffix;\n const lines = suffix.split('\\n');\n const start = position === 0 ? 0 : 1;\n for (let i = lines.length - 1; i >= start; i--) {\n const trimmed = lines[i]!.trim();\n if (!trimmed) continue;\n try { return { entry: JSON.parse(trimmed) as ChronicleEvent, size, birthtimeMs: stat.birthtimeMs }; } catch { /* scan earlier */ }\n }\n suffix = lines[0] ?? '';\n }\n return { size, birthtimeMs: stat.birthtimeMs };\n } finally { await handle.close(); }\n}\n\n/** Stream entries line by line. Reading a whole partition into one string\n * breaks past V8's max string length (~512MB) \u2014 purge and verify must work\n * on partitions of any size, so only individual lines are materialized. */\nexport async function* streamEntriesStrict(filePath: string): AsyncGenerator<ChronicleEvent> {\n let lineNumber = 0;\n try {\n const input = createReadStream(filePath, { encoding: 'utf8', highWaterMark: 256 * 1024 });\n const lines = createInterface({ input, crlfDelay: Infinity });\n for await (const line of lines) {\n lineNumber++;\n const trimmed = line.trim();\n if (!trimmed) continue;\n let entry: ChronicleEvent;\n try { entry = JSON.parse(trimmed) as ChronicleEvent; } catch { throw new Error(`invalid JSON at line ${lineNumber} in ${path.basename(filePath)}`); }\n yield entry;\n }\n } catch (error) {\n if (isNotFound(error)) return;\n throw error;\n }\n}\n\nasync function readEntriesStrict(filePath: string): Promise<ChronicleEvent[]> {\n const entries: ChronicleEvent[] = [];\n for await (const entry of streamEntriesStrict(filePath)) entries.push(entry);\n return entries;\n}\n\nfunction isNotFound(error: unknown): boolean { return typeof error === 'object' && error !== null && 'code' in error && error.code === 'ENOENT'; }\nfunction errorMessage(error: unknown): string { return error instanceof Error ? error.message : String(error); }\n\nexport { GENESIS_HASH };\n", "/**\n * The one implementation of Chronicle's tamper-evident hash.\n *\n * Chronicle events form a chain: each carries the `hash` of its predecessor in\n * `previousHash`, anchored at {@link GENESIS_HASH}. Verification recomputes\n * every `hash` from the stored event, so the canonicalization below is part of\n * the durable format \u2014 two subtly different implementations would produce two\n * incompatible chains, and the divergence would only surface later as a\n * \"corrupt journal\" report on data that was never actually tampered with.\n *\n * It therefore lives here rather than beside any one store, and both the JSONL\n * journal and the SQLite journal import it.\n */\nimport { createHash } from 'node:crypto';\nimport type { ChronicleEvent } from './types.js';\n\n/** `previousHash` of the first event in a chain. */\nexport const GENESIS_HASH = '0'.repeat(64);\n\n/**\n * Deterministic JSON encoding: object keys sorted, `undefined` members dropped,\n * `undefined` array elements encoded as `null`.\n *\n * Note this is NOT what gets written to disk \u2014 the JSONL journal stores\n * `JSON.stringify(event)` in V8 property order. The stored bytes are a record;\n * the preimage is always re-derived from the parsed event.\n */\nexport function stableStringify(value: unknown): string {\n if (value === null || typeof value !== 'object') return JSON.stringify(value);\n if (Array.isArray(value)) {\n return `[${value.map((item) => (item === undefined ? 'null' : stableStringify(item))).join(',')}]`;\n }\n const obj = value as Record<string, unknown>;\n return `{${Object.keys(obj)\n .sort()\n .filter((key) => obj[key] !== undefined)\n .map((key) => `${JSON.stringify(key)}:${stableStringify(obj[key])}`)\n .join(',')}}`;\n}\n\nexport function hashValue(value: unknown): string {\n return createHash('sha256').update(stableStringify(value), 'utf8').digest('hex');\n}\n\n/**\n * Recompute the hash a stored event should carry.\n *\n * The `hash` field is excluded from its own preimage, so verification of an\n * event read back from any store is `chronicleEventHash(event) === event.hash`.\n */\nexport function chronicleEventHash(event: ChronicleEvent): string {\n const { hash: _hash, ...unhashed } = event;\n return hashValue(unhashed);\n}\n", "import * as path from 'node:path';\n\n/** Matches both rotated (`*.events.NNNNN.jsonl`) and unrotated (`*.events.jsonl`) partition files. */\nexport const PARTITION_FILE_PATTERN = /^(.*\\.events)(?:\\.(\\d{5}))?\\.jsonl$/;\n\nfunction partitionFamily(filePath: string): string {\n const match = PARTITION_FILE_PATTERN.exec(path.basename(filePath));\n return path.join(path.dirname(filePath), match?.[1] ?? path.basename(filePath));\n}\n\nfunction partitionSequence(filePath: string): number {\n const match = PARTITION_FILE_PATTERN.exec(path.basename(filePath));\n return Number(match?.[2] ?? 0);\n}\n\n/** Orders partitions by family, then by rotation sequence \u2014 the unrotated file (no sequence) sorts first. */\nexport function comparePartitionPaths(left: string, right: string): number {\n const familyOrder = partitionFamily(left).localeCompare(partitionFamily(right));\n return familyOrder || partitionSequence(left) - partitionSequence(right);\n}\n", "/** Schema version for the first durable WrongStack Chronicle event envelope. */\nexport const CHRONICLE_SCHEMA_VERSION = 1 as const;\n\nexport type ChronicleOutcome =\n | 'started'\n | 'success'\n | 'failure'\n | 'cancelled'\n | 'denied'\n | 'abandoned'\n | 'unknown';\n\n/** Stable identities used to project one event into global and project views. */\nexport interface ChronicleScope {\n installationId: string;\n machineId: string;\n projectId?: string | undefined;\n repositoryId?: string | undefined;\n workspaceId?: string | undefined;\n worktreeId?: string | undefined;\n sessionId?: string | undefined;\n turnId?: string | undefined;\n iterationId?: string | undefined;\n agentId?: string | undefined;\n goalId?: string | undefined;\n planId?: string | undefined;\n taskId?: string | undefined;\n kanbanBoardId?: string | undefined;\n}\n\nexport interface ChronicleCorrelation {\n traceId: string;\n spanId: string;\n parentSpanId?: string | undefined;\n logicalRequestId?: string | undefined;\n attemptId?: string | undefined;\n toolCallId?: string | undefined;\n}\n\nexport interface ChronicleRuntimeIdentity {\n providerId?: string | undefined;\n modelId?: string | undefined;\n modelRevision?: string | undefined;\n processId?: number | undefined;\n parentProcessId?: number | undefined;\n}\n\nexport interface ChronicleResourceRef {\n kind: 'file' | 'symbol' | 'memory' | 'task' | 'kanban' | 'process' | 'network' | 'artifact' | 'other';\n id: string;\n path?: string | undefined;\n lineStart?: number | undefined;\n lineEnd?: number | undefined;\n contentHashBefore?: string | undefined;\n contentHashAfter?: string | undefined;\n}\n\nexport interface ChronicleEventInput {\n eventType: string;\n scope: ChronicleScope;\n correlation: ChronicleCorrelation;\n runtime?: ChronicleRuntimeIdentity | undefined;\n resource?: ChronicleResourceRef | undefined;\n outcome?: ChronicleOutcome | undefined;\n durationNs?: string | undefined;\n occurredAt?: string | undefined;\n monotonicNs?: string | undefined;\n attributes?: Record<string, unknown> | undefined;\n tags?: Record<string, string> | undefined;\n}\n\n/**\n * Lossless durable envelope. All wall-clock timestamps are UTC ISO-8601;\n * monotonicNs is used for elapsed-time ordering inside one process.\n */\nexport interface ChronicleEvent extends ChronicleEventInput {\n schemaVersion: typeof CHRONICLE_SCHEMA_VERSION;\n eventId: string;\n observedAt: string;\n persistedAt: string;\n sequence: number;\n previousHash: string;\n hash: string;\n}\n\nexport type ChronicleVerifyResult =\n | { ok: true; entries: number; lastSequence: number; lastHash: string }\n | { ok: false; entries: number; brokenAt: number; reason: string };\n", "/**\n * ChronicleMetricsStore \u2014 derived, queryable aggregates over the raw\n * Chronicle journal (\"process, don't hoard\").\n *\n * The journal is the durable evidence log; this store is a disposable\n * projection kept in `<chronicleDir>/metrics.db` (node:sqlite, WAL). Each\n * `refresh()` incrementally consumes only the journal bytes appended since\n * the previous run (per-partition byte offsets in `ingest_state`), so the\n * raw JSONL partitions can be purged by retention without losing metrics:\n *\n * - `provider_daily` \u2014 provider\u00D7model\u00D7day attempt/success/failure/retry/\n * fallback counts, token totals, duration stats.\n * - `task_outcomes` \u2014 one row per task (kanban/SDD/subagent) with status,\n * timing, retry counts, and board/run/session lineage.\n * - `file_lineage` \u2014 one row per observed file mutation with full\n * session/agent/task/board/tool/model attribution.\n * - `token_cost` \u2014 latest cumulative token.accounted cost snapshot per\n * scope (same latest-wins semantics as the query\n * engine's summary).\n * - `daily_counters`, `family_daily`, `agent_daily`, `logical_request_daily`,\n * `file_seen_daily` \u2014 per-day scalar counters and dedup sets backing\n * `defaultSummary()`, a `ChronicleSummary` for the common unfiltered/\n * time-bounded dashboard view. Any genuinely ad hoc filter (free text,\n * path, session, provider, model) falls back to the raw-scan summary in\n * query.ts \u2014 fixed-dimension aggregation fundamentally can't answer those.\n *\n * The schema is a cache: on version mismatch it is dropped and re-ingested\n * from whatever journal partitions still exist.\n */\n\nimport * as fs from 'node:fs/promises';\nimport { createRequire } from 'node:module';\nimport * as path from 'node:path';\nimport type { DatabaseSync } from 'node:sqlite';\nimport { withFileLock } from '../utils/atomic-write.js';\nimport { withSqliteExperimentalWarningSuppressed } from '../utils/sqlite-warning.js';\nimport { findChroniclePartitions, isTerminalFailure, signalFamily } from './query.js';\nimport type { ChronicleEvent } from './types.js';\nimport type { ChronicleSignalFamily, ChronicleSummary } from './query.js';\n\nconst SCHEMA_VERSION = 3;\nconst READ_CHUNK_BYTES = 1024 * 1024;\nconst EMPTY_FAMILIES: Record<ChronicleSignalFamily, number> = {\n llm: 0, agent: 0, tool: 0, file: 0, memory: 0, task: 0, decision: 0, runtime: 0, finding: 0,\n};\n\nexport interface ChronicleMetricsRefreshResult {\n ingestedEvents: number;\n ingestedBytes: number;\n sourceFiles: number;\n invalidLines: number;\n}\n\nexport interface ChronicleProviderDailyRow {\n day: string;\n providerId: string;\n modelId: string;\n attempts: number;\n completed: number;\n failed: number;\n retries: number;\n fallbacks: number;\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens: number;\n cacheWriteTokens: number;\n avgDurationMs: number;\n maxDurationMs: number;\n}\n\nexport interface ChronicleTaskOutcomeRow {\n taskId: string;\n runId: string;\n boardId: string;\n sessionId: string;\n agentId: string;\n status: string;\n startedAt: string | null;\n endedAt: string | null;\n durationMs: number | null;\n retries: number;\n verificationFailures: number;\n filesTouched: number;\n}\n\nexport interface ChronicleFileLineageRow {\n path: string;\n operation: string;\n occurredAt: string;\n sessionId: string;\n agentId: string;\n taskId: string;\n boardId: string;\n runId: string;\n toolName: string;\n providerId: string;\n modelId: string;\n source: string;\n}\n\nexport interface ChronicleMetricsSummary {\n providers: { attempts: number; completed: number; failed: number; successRate: number };\n tasks: Record<string, number>;\n files: { mutations: number; uniquePaths: number };\n estimatedCostUsd: number;\n}\n\n// \u2500\u2500\u2500 node:sqlite lazy loader (mirrors SAGE's pattern, compacted) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nlet Ctor: typeof DatabaseSync | null | undefined;\n\nfunction loadDatabaseSync(): typeof DatabaseSync {\n if (Ctor) return Ctor;\n if (Ctor === null) throw new Error('node:sqlite is unavailable in this runtime');\n try {\n Ctor = withSqliteExperimentalWarningSuppressed(\n () => (createRequire(import.meta.url)('node:sqlite') as typeof import('node:sqlite')).DatabaseSync,\n );\n return Ctor;\n } catch (error) {\n Ctor = null;\n throw new Error(\n \"Chronicle metrics need Node's built-in SQLite (node:sqlite, Node >= 22.5): \" +\n (error instanceof Error ? error.message : String(error)),\n );\n }\n}\n\n/** Non-throwing availability probe for callers that degrade gracefully. */\nexport function isChronicleMetricsAvailable(): boolean {\n try {\n loadDatabaseSync();\n return true;\n } catch {\n return false;\n }\n}\n\n// \u2500\u2500\u2500 Store \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class ChronicleMetricsStore {\n private readonly db: DatabaseSync;\n private readonly directory: string;\n private readonly dbPath: string;\n\n private constructor(directory: string) {\n this.directory = path.resolve(directory);\n this.dbPath = path.join(this.directory, 'metrics.db');\n const Database = loadDatabaseSync();\n this.db = new Database(this.dbPath);\n this.db.exec('PRAGMA journal_mode = WAL');\n this.ensureSchema();\n }\n\n static open(chronicleDirectory: string): ChronicleMetricsStore {\n return new ChronicleMetricsStore(chronicleDirectory);\n }\n\n close(): void {\n this.db.close();\n }\n\n /** Incrementally ingest journal bytes appended since the last refresh.\n * Safe across processes: guarded by a file lock on the database path. */\n async refresh(): Promise<ChronicleMetricsRefreshResult> {\n const result: ChronicleMetricsRefreshResult = {\n ingestedEvents: 0,\n ingestedBytes: 0,\n sourceFiles: 0,\n invalidLines: 0,\n };\n await withFileLock(this.dbPath, async () => {\n const files = await findChroniclePartitions(this.directory);\n const offsets = this.loadOffsets();\n for (const file of files) {\n const key = normalizeKey(path.relative(this.directory, file));\n const consumed = offsets.get(key) ?? 0;\n const ingested = await this.ingestFile(file, key, consumed, result);\n if (ingested) result.sourceFiles++;\n }\n this.pruneOffsets(files);\n });\n return result;\n }\n\n providerDaily(options: { from?: string; to?: string } = {}): ChronicleProviderDailyRow[] {\n const clauses: string[] = [];\n const params: string[] = [];\n if (options.from) {\n clauses.push('day >= ?');\n params.push(options.from.slice(0, 10));\n }\n if (options.to) {\n clauses.push('day <= ?');\n params.push(options.to.slice(0, 10));\n }\n const where = clauses.length > 0 ? ` WHERE ${clauses.join(' AND ')}` : '';\n const rows = this.db\n .prepare(\n `SELECT day, provider_id, model_id, attempts, completed, failed, retries, fallbacks,\n input_tokens, output_tokens, cache_read_tokens, cache_write_tokens,\n duration_ms_total, duration_ms_max, duration_count\n FROM provider_daily${where} ORDER BY day DESC, provider_id, model_id`,\n )\n .all(...params) as Array<Record<string, string | number>>;\n return rows.map((row) => ({\n day: String(row.day),\n providerId: String(row.provider_id),\n modelId: String(row.model_id),\n attempts: Number(row.attempts),\n completed: Number(row.completed),\n failed: Number(row.failed),\n retries: Number(row.retries),\n fallbacks: Number(row.fallbacks),\n inputTokens: Number(row.input_tokens),\n outputTokens: Number(row.output_tokens),\n cacheReadTokens: Number(row.cache_read_tokens),\n cacheWriteTokens: Number(row.cache_write_tokens),\n avgDurationMs:\n Number(row.duration_count) > 0\n ? Number(row.duration_ms_total) / Number(row.duration_count)\n : 0,\n maxDurationMs: Number(row.duration_ms_max),\n }));\n }\n\n taskOutcomes(\n options: {\n runId?: string;\n boardId?: string;\n sessionId?: string;\n status?: string;\n limit?: number;\n } = {},\n ): ChronicleTaskOutcomeRow[] {\n const clauses: string[] = [];\n const params: Array<string | number> = [];\n if (options.runId) {\n clauses.push('t.run_id = ?');\n params.push(options.runId);\n }\n if (options.boardId) {\n clauses.push('t.board_id = ?');\n params.push(options.boardId);\n }\n if (options.sessionId) {\n clauses.push('t.session_id = ?');\n params.push(options.sessionId);\n }\n if (options.status) {\n clauses.push('t.status = ?');\n params.push(options.status);\n }\n const where = clauses.length > 0 ? ` WHERE ${clauses.join(' AND ')}` : '';\n params.push(clampLimit(options.limit, 100));\n const rows = this.db\n .prepare(\n `SELECT t.*, (SELECT COUNT(*) FROM file_lineage f WHERE f.task_id = t.task_id) AS files_touched\n FROM task_outcomes t${where}\n ORDER BY COALESCE(t.started_at, '') DESC LIMIT ?`,\n )\n .all(...params) as Array<Record<string, string | number | null>>;\n return rows.map((row) => ({\n taskId: String(row.task_id),\n runId: String(row.run_id),\n boardId: String(row.board_id),\n sessionId: String(row.session_id),\n agentId: String(row.agent_id),\n status: String(row.status),\n startedAt: row.started_at === null ? null : String(row.started_at),\n endedAt: row.ended_at === null ? null : String(row.ended_at),\n durationMs: row.duration_ms === null ? null : Number(row.duration_ms),\n retries: Number(row.retries),\n verificationFailures: Number(row.verification_failures),\n filesTouched: Number(row.files_touched),\n }));\n }\n\n fileLineage(\n options: {\n path?: string;\n paths?: string[];\n latestPerPath?: boolean;\n taskId?: string;\n boardId?: string;\n sessionId?: string;\n limit?: number;\n } = {},\n ): ChronicleFileLineageRow[] {\n const clauses: string[] = [];\n const params: Array<string | number> = [];\n if (options.path) {\n clauses.push('path_key = ?');\n params.push(normalizePathKey(options.path));\n }\n if (options.paths) {\n const pathKeys = [...new Set(options.paths.map(normalizePathKey))];\n if (pathKeys.length === 0) return [];\n clauses.push(`path_key IN (${pathKeys.map(() => '?').join(',')})`);\n params.push(...pathKeys);\n }\n if (options.taskId) {\n clauses.push('task_id = ?');\n params.push(options.taskId);\n }\n if (options.boardId) {\n clauses.push('board_id = ?');\n params.push(options.boardId);\n }\n if (options.sessionId) {\n clauses.push('session_id = ?');\n params.push(options.sessionId);\n }\n const where = clauses.length > 0 ? ` WHERE ${clauses.join(' AND ')}` : '';\n params.push(clampLimit(options.limit, 200));\n const projection =\n `path, operation, occurred_at, session_id, agent_id, task_id, board_id, run_id,\n tool_name, provider_id, model_id, source`;\n const sql = options.latestPerPath\n ? `SELECT ${projection} FROM (\n SELECT ${projection}, ROW_NUMBER() OVER (\n PARTITION BY path_key ORDER BY occurred_at DESC, event_id DESC\n ) AS path_rank\n FROM file_lineage${where}\n ) WHERE path_rank = 1 ORDER BY occurred_at DESC LIMIT ?`\n : `SELECT ${projection}\n FROM file_lineage${where} ORDER BY occurred_at DESC LIMIT ?`;\n const rows = this.db\n .prepare(sql)\n .all(...params) as Array<Record<string, string>>;\n return rows.map((row) => ({\n path: row.path!,\n operation: row.operation!,\n occurredAt: row.occurred_at!,\n sessionId: row.session_id!,\n agentId: row.agent_id!,\n taskId: row.task_id!,\n boardId: row.board_id!,\n runId: row.run_id!,\n toolName: row.tool_name!,\n providerId: row.provider_id!,\n modelId: row.model_id!,\n source: row.source!,\n }));\n }\n\n summary(): ChronicleMetricsSummary {\n const provider = this.db\n .prepare(\n 'SELECT COALESCE(SUM(attempts),0) a, COALESCE(SUM(completed),0) c, COALESCE(SUM(failed),0) f FROM provider_daily',\n )\n .get() as { a: number; c: number; f: number };\n const tasks: Record<string, number> = {};\n for (const row of this.db\n .prepare('SELECT status, COUNT(*) n FROM task_outcomes GROUP BY status')\n .all() as Array<{ status: string; n: number }>) {\n tasks[row.status] = Number(row.n);\n }\n const files = this.db\n .prepare('SELECT COUNT(*) n, COUNT(DISTINCT path) p FROM file_lineage')\n .get() as { n: number; p: number };\n const cost = this.db.prepare('SELECT COALESCE(SUM(cost),0) c FROM token_cost').get() as {\n c: number;\n };\n const terminal = Number(provider.c) + Number(provider.f);\n return {\n providers: {\n attempts: Number(provider.a),\n completed: Number(provider.c),\n failed: Number(provider.f),\n successRate: terminal > 0 ? Number(provider.c) / terminal : 0,\n },\n tasks,\n files: { mutations: Number(files.n), uniquePaths: Number(files.p) },\n estimatedCostUsd: Number(cost.c),\n };\n }\n\n /**\n * A `ChronicleSummary` for the default/unfiltered dashboard view \u2014 only\n * `from`/`to` (day-precision) narrow it. Any other ad hoc filter (text,\n * path, provider, model, session) can't be answered from these\n * fixed-dimension aggregates; callers must fall back to query.ts's\n * raw-scan summary for those.\n */\n defaultSummary(options: { from?: string; to?: string } = {}): ChronicleSummary {\n const fromDay = options.from?.slice(0, 10);\n const toDay = options.to?.slice(0, 10);\n const dayFilter = (column: string): { where: string; params: string[] } => {\n const clauses: string[] = [];\n const params: string[] = [];\n if (fromDay) { clauses.push(`${column} >= ?`); params.push(fromDay); }\n if (toDay) { clauses.push(`${column} <= ?`); params.push(toDay); }\n return { where: clauses.length > 0 ? ` WHERE ${clauses.join(' AND ')}` : '', params };\n };\n\n const providerRange = dayFilter('day');\n const provider = this.db\n .prepare(\n `SELECT COALESCE(SUM(attempts),0) attempts, COALESCE(SUM(completed),0) completed, COALESCE(SUM(failed),0) failed,\n COALESCE(SUM(retries),0) retries, COALESCE(SUM(fallbacks),0) fallbacks,\n COUNT(DISTINCT provider_id) providers, COUNT(DISTINCT model_id) models,\n COALESCE(SUM(input_tokens),0) inputTokens, COALESCE(SUM(output_tokens),0) outputTokens,\n COALESCE(SUM(cache_read_tokens),0) cacheReadTokens, COALESCE(SUM(cache_write_tokens),0) cacheWriteTokens,\n COALESCE(SUM(duration_ms_total),0) durationTotal, COALESCE(MAX(duration_ms_max),0) durationMax,\n COALESCE(SUM(duration_count),0) durationCount\n FROM provider_daily${providerRange.where}`,\n )\n .get(...providerRange.params) as Record<string, number>;\n\n const counterRange = dayFilter('day');\n const counters = this.db\n .prepare(\n `SELECT COALESCE(SUM(tool_calls),0) toolCalls, COALESCE(SUM(completed_tools),0) completedTools,\n COALESCE(SUM(failed_tools),0) failedTools, COALESCE(SUM(tool_duration_ms_total),0) toolDurationTotal,\n COALESCE(SUM(tool_duration_count),0) toolDurationCount, COALESCE(SUM(processes),0) processes,\n COALESCE(SUM(failed_processes),0) failedProcesses, COALESCE(SUM(file_events_all),0) fileEvents,\n COALESCE(SUM(decisions),0) decisions, COALESCE(SUM(escalations),0) escalations,\n COALESCE(SUM(agent_events),0) agentEvents, COALESCE(SUM(failures),0) failures,\n COALESCE(SUM(cancellations),0) cancellations\n FROM daily_counters${counterRange.where}`,\n )\n .get(...counterRange.params) as Record<string, number>;\n\n const familyRange = dayFilter('day');\n const familyRows = this.db\n .prepare(`SELECT family, count, failure_count FROM family_daily${familyRange.where}`)\n .all(...familyRange.params) as Array<{ family: string; count: number; failure_count: number }>;\n const families = { ...EMPTY_FAMILIES };\n const failuresByFamily = { ...EMPTY_FAMILIES };\n for (const row of familyRows) {\n const family = row.family as ChronicleSignalFamily;\n families[family] = Number(row.count);\n failuresByFamily[family] = Number(row.failure_count);\n }\n\n const agentRange = dayFilter('day');\n const uniqueAgents = (\n this.db.prepare(`SELECT COUNT(DISTINCT agent_id) n FROM agent_daily${agentRange.where}`).get(...agentRange.params) as { n: number }\n ).n;\n const requestRange = dayFilter('day');\n const logicalRequests = (\n this.db.prepare(`SELECT COUNT(DISTINCT logical_request_id) n FROM logical_request_daily${requestRange.where}`).get(...requestRange.params) as { n: number }\n ).n;\n const fileRange = dayFilter('day');\n const uniqueFiles = (\n this.db.prepare(`SELECT COUNT(DISTINCT path_key) n FROM file_seen_daily${fileRange.where}`).get(...fileRange.params) as { n: number }\n ).n;\n const costRange = dayFilter('day');\n const cost = (\n this.db.prepare(`SELECT COALESCE(SUM(cost),0) c FROM token_cost${costRange.where}`).get(...costRange.params) as { c: number }\n ).c;\n\n return {\n logicalRequests: Number(logicalRequests),\n modelAttempts: Number(provider.attempts),\n completedAttempts: Number(provider.completed),\n failedAttempts: Number(provider.failed),\n scheduledRetries: Number(provider.retries),\n fallbacks: Number(provider.fallbacks),\n providers: Number(provider.providers),\n models: Number(provider.models),\n inputTokens: Number(provider.inputTokens),\n outputTokens: Number(provider.outputTokens),\n cacheReadTokens: Number(provider.cacheReadTokens),\n cacheWriteTokens: Number(provider.cacheWriteTokens),\n estimatedCostUsd: Number(cost),\n providerAvgDurationMs: Number(provider.durationCount) > 0 ? Number(provider.durationTotal) / Number(provider.durationCount) : 0,\n // True p95 needs a retained distribution; this per-day aggregate only\n // keeps sum/max/count, so approximate with the observed max rather\n // than adding a per-attempt histogram write (would add the same kind\n // of per-event overhead this whole effort is trying to remove).\n providerP95DurationMs: Number(provider.durationMax),\n toolCalls: Number(counters.toolCalls),\n completedTools: Number(counters.completedTools),\n failedTools: Number(counters.failedTools),\n toolAvgDurationMs: Number(counters.toolDurationCount) > 0 ? Number(counters.toolDurationTotal) / Number(counters.toolDurationCount) : 0,\n processes: Number(counters.processes),\n failedProcesses: Number(counters.failedProcesses),\n fileEvents: Number(counters.fileEvents),\n uniqueFiles: Number(uniqueFiles),\n agentEvents: Number(counters.agentEvents),\n uniqueAgents: Number(uniqueAgents),\n decisions: Number(counters.decisions),\n escalations: Number(counters.escalations),\n failures: Number(counters.failures),\n cancellations: Number(counters.cancellations),\n families,\n failuresByFamily,\n };\n }\n\n // \u2500\u2500\u2500 Ingest internals \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n private ensureSchema(): void {\n const version = (this.db.prepare('PRAGMA user_version').get() as { user_version: number })\n .user_version;\n if (version !== 0 && version !== SCHEMA_VERSION) {\n // Derived cache \u2014 drop and re-ingest from whatever journal remains.\n this.db.exec(\n 'DROP TABLE IF EXISTS ingest_state; DROP TABLE IF EXISTS provider_daily;' +\n 'DROP TABLE IF EXISTS task_outcomes; DROP TABLE IF EXISTS file_lineage;' +\n 'DROP TABLE IF EXISTS token_cost; DROP TABLE IF EXISTS daily_counters;' +\n 'DROP TABLE IF EXISTS family_daily; DROP TABLE IF EXISTS agent_daily;' +\n 'DROP TABLE IF EXISTS logical_request_daily; DROP TABLE IF EXISTS file_seen_daily;',\n );\n }\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS ingest_state (\n file TEXT PRIMARY KEY,\n bytes INTEGER NOT NULL\n );\n CREATE TABLE IF NOT EXISTS provider_daily (\n day TEXT NOT NULL,\n provider_id TEXT NOT NULL,\n model_id TEXT NOT NULL,\n attempts INTEGER NOT NULL DEFAULT 0,\n completed INTEGER NOT NULL DEFAULT 0,\n failed INTEGER NOT NULL DEFAULT 0,\n retries INTEGER NOT NULL DEFAULT 0,\n fallbacks INTEGER NOT NULL DEFAULT 0,\n input_tokens INTEGER NOT NULL DEFAULT 0,\n output_tokens INTEGER NOT NULL DEFAULT 0,\n cache_read_tokens INTEGER NOT NULL DEFAULT 0,\n cache_write_tokens INTEGER NOT NULL DEFAULT 0,\n duration_ms_total REAL NOT NULL DEFAULT 0,\n duration_ms_max REAL NOT NULL DEFAULT 0,\n duration_count INTEGER NOT NULL DEFAULT 0,\n PRIMARY KEY (day, provider_id, model_id)\n );\n CREATE TABLE IF NOT EXISTS task_outcomes (\n task_id TEXT PRIMARY KEY,\n run_id TEXT NOT NULL DEFAULT '',\n board_id TEXT NOT NULL DEFAULT '',\n session_id TEXT NOT NULL DEFAULT '',\n agent_id TEXT NOT NULL DEFAULT '',\n status TEXT NOT NULL DEFAULT 'started',\n started_at TEXT,\n ended_at TEXT,\n duration_ms REAL,\n retries INTEGER NOT NULL DEFAULT 0,\n verification_failures INTEGER NOT NULL DEFAULT 0\n );\n CREATE TABLE IF NOT EXISTS file_lineage (\n event_id TEXT PRIMARY KEY,\n path TEXT NOT NULL,\n path_key TEXT NOT NULL,\n operation TEXT NOT NULL,\n occurred_at TEXT NOT NULL,\n session_id TEXT NOT NULL DEFAULT '',\n agent_id TEXT NOT NULL DEFAULT '',\n task_id TEXT NOT NULL DEFAULT '',\n board_id TEXT NOT NULL DEFAULT '',\n run_id TEXT NOT NULL DEFAULT '',\n tool_name TEXT NOT NULL DEFAULT '',\n provider_id TEXT NOT NULL DEFAULT '',\n model_id TEXT NOT NULL DEFAULT '',\n source TEXT NOT NULL DEFAULT ''\n );\n -- Lookups filter on the case-normalized path_key (matching the query\n -- engine); the path column retains original casing for display.\n CREATE INDEX IF NOT EXISTS idx_file_lineage_path ON file_lineage(path_key, occurred_at);\n CREATE INDEX IF NOT EXISTS idx_file_lineage_task ON file_lineage(task_id);\n CREATE TABLE IF NOT EXISTS token_cost (\n scope_key TEXT PRIMARY KEY,\n day TEXT NOT NULL,\n occurred_at TEXT NOT NULL,\n sequence INTEGER NOT NULL,\n cost REAL NOT NULL\n );\n -- Backing store for defaultSummary(): per-day scalar counters plus\n -- dedup sets, populated for every ingested event (not just the\n -- provider/task/file families above).\n CREATE TABLE IF NOT EXISTS daily_counters (\n day TEXT PRIMARY KEY,\n tool_calls INTEGER NOT NULL DEFAULT 0,\n completed_tools INTEGER NOT NULL DEFAULT 0,\n failed_tools INTEGER NOT NULL DEFAULT 0,\n tool_duration_ms_total REAL NOT NULL DEFAULT 0,\n tool_duration_ms_max REAL NOT NULL DEFAULT 0,\n tool_duration_count INTEGER NOT NULL DEFAULT 0,\n processes INTEGER NOT NULL DEFAULT 0,\n failed_processes INTEGER NOT NULL DEFAULT 0,\n file_events_all INTEGER NOT NULL DEFAULT 0,\n decisions INTEGER NOT NULL DEFAULT 0,\n escalations INTEGER NOT NULL DEFAULT 0,\n agent_events INTEGER NOT NULL DEFAULT 0,\n failures INTEGER NOT NULL DEFAULT 0,\n cancellations INTEGER NOT NULL DEFAULT 0\n );\n CREATE TABLE IF NOT EXISTS family_daily (\n day TEXT NOT NULL,\n family TEXT NOT NULL,\n count INTEGER NOT NULL DEFAULT 0,\n failure_count INTEGER NOT NULL DEFAULT 0,\n PRIMARY KEY (day, family)\n );\n CREATE TABLE IF NOT EXISTS agent_daily (day TEXT NOT NULL, agent_id TEXT NOT NULL, PRIMARY KEY (day, agent_id));\n CREATE TABLE IF NOT EXISTS logical_request_daily (day TEXT NOT NULL, logical_request_id TEXT NOT NULL, PRIMARY KEY (day, logical_request_id));\n CREATE TABLE IF NOT EXISTS file_seen_daily (day TEXT NOT NULL, path_key TEXT NOT NULL, PRIMARY KEY (day, path_key));\n PRAGMA user_version = ${SCHEMA_VERSION};\n `);\n }\n\n private loadOffsets(): Map<string, number> {\n const rows = this.db.prepare('SELECT file, bytes FROM ingest_state').all() as Array<{\n file: string;\n bytes: number;\n }>;\n return new Map(rows.map((row) => [row.file, Number(row.bytes)]));\n }\n\n private pruneOffsets(existingFiles: string[]): void {\n const keep = new Set(\n existingFiles.map((file) => normalizeKey(path.relative(this.directory, file))),\n );\n for (const row of this.db.prepare('SELECT file FROM ingest_state').all() as Array<{\n file: string;\n }>) {\n if (!keep.has(row.file))\n this.db.prepare('DELETE FROM ingest_state WHERE file = ?').run(row.file);\n }\n }\n\n /** Read complete lines appended after `consumed` bytes. The trailing\n * partial line of an actively-written partition is left for the next\n * refresh \u2014 `ingest_state.bytes` only ever advances past full lines. */\n private async ingestFile(\n file: string,\n key: string,\n consumed: number,\n result: ChronicleMetricsRefreshResult,\n ): Promise<boolean> {\n let handle: fs.FileHandle;\n try {\n handle = await fs.open(file, 'r');\n } catch {\n return false;\n }\n try {\n const size = (await handle.stat()).size;\n if (size <= consumed) return false;\n let position = consumed;\n let remainder = Buffer.alloc(0);\n let advanced = consumed;\n this.db.exec('BEGIN');\n try {\n while (position < size) {\n const length = Math.min(READ_CHUNK_BYTES, size - position);\n const buffer = Buffer.allocUnsafe(length);\n const { bytesRead } = await handle.read(buffer, 0, length, position);\n if (bytesRead <= 0) break;\n position += bytesRead;\n const data =\n remainder.length > 0\n ? Buffer.concat([remainder, buffer.subarray(0, bytesRead)])\n : buffer.subarray(0, bytesRead);\n const lastNewline = data.lastIndexOf(0x0a);\n if (lastNewline < 0) {\n remainder = Buffer.from(data);\n continue;\n }\n // '\\n' is a single byte in UTF-8, so complete-line slices always\n // fall on character boundaries.\n for (const line of data.subarray(0, lastNewline).toString('utf8').split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n try {\n this.ingestEvent(JSON.parse(trimmed) as ChronicleEvent);\n result.ingestedEvents++;\n } catch {\n result.invalidLines++;\n }\n }\n // `data` always begins at absolute offset `advanced` (remainder is\n // exactly the unconsumed bytes), so the newline index maps directly.\n advanced += lastNewline + 1;\n remainder = Buffer.from(data.subarray(lastNewline + 1));\n }\n this.db\n .prepare(\n 'INSERT INTO ingest_state (file, bytes) VALUES (?, ?) ' +\n 'ON CONFLICT(file) DO UPDATE SET bytes = excluded.bytes',\n )\n .run(key, advanced);\n this.db.exec('COMMIT');\n } catch (error) {\n this.db.exec('ROLLBACK');\n throw error;\n }\n result.ingestedBytes += advanced - consumed;\n return advanced > consumed;\n } finally {\n await handle.close();\n }\n }\n\n private ingestEvent(event: ChronicleEvent): void {\n if (typeof event?.eventType !== 'string' || !event.scope) return;\n this.ingestDailyCounters(event);\n const type = event.eventType;\n if (type.startsWith('provider.attempt.') || type === 'provider.fallback') {\n this.ingestProvider(event);\n } else if (type === 'token.accounted') {\n this.ingestTokenCost(event);\n } else if (/^(?:sdd|subagent|kanban)\\.task[._]/.test(type)) {\n this.ingestTask(event);\n } else if (type === 'file.event' || /^file\\.(?:tool|external)\\./.test(type)) {\n this.ingestFileEvent(event);\n }\n }\n\n /** Runs for every ingested event (not just the type-specific branches\n * below) \u2014 mirrors query.ts's updateSummary() closely enough that\n * defaultSummary() matches what a raw scan of the same window would say. */\n private ingestDailyCounters(event: ChronicleEvent): void {\n const day = eventDay(event);\n this.db.prepare('INSERT OR IGNORE INTO daily_counters (day) VALUES (?)').run(day);\n const bump = (sql: string, ...params: Array<string | number>) =>\n this.db.prepare(`UPDATE daily_counters SET ${sql} WHERE day = ?`).run(...params, day);\n\n const family = signalFamily(event);\n const failed = isTerminalFailure(event) ? 1 : 0;\n this.db\n .prepare(\n `INSERT INTO family_daily (day, family, count, failure_count) VALUES (?, ?, 1, ?)\n ON CONFLICT(day, family) DO UPDATE SET count = count + 1, failure_count = failure_count + excluded.failure_count`,\n )\n .run(day, family, failed);\n if (failed) bump('failures = failures + 1');\n if (event.outcome === 'cancelled' || event.outcome === 'abandoned') bump('cancellations = cancellations + 1');\n if (family === 'agent') bump('agent_events = agent_events + 1');\n\n if (event.correlation.logicalRequestId) {\n this.db\n .prepare('INSERT OR IGNORE INTO logical_request_daily (day, logical_request_id) VALUES (?, ?)')\n .run(day, event.correlation.logicalRequestId);\n }\n if (event.scope.agentId) {\n this.db.prepare('INSERT OR IGNORE INTO agent_daily (day, agent_id) VALUES (?, ?)').run(day, event.scope.agentId);\n }\n\n const type = event.eventType;\n if (type === 'decision.requested') bump('decisions = decisions + 1');\n else if (type === 'decision.escalated') bump('escalations = escalations + 1');\n else if (type === 'tool.started') bump('tool_calls = tool_calls + 1');\n else if (type === 'tool.executed' || type === 'tool.failed') {\n const dur = durationMs(event);\n const durationCount = dur > 0 ? 1 : 0;\n bump(\n `${type === 'tool.executed' ? 'completed_tools' : 'failed_tools'} = ${type === 'tool.executed' ? 'completed_tools' : 'failed_tools'} + 1,\n tool_duration_ms_total = tool_duration_ms_total + ?, tool_duration_ms_max = MAX(tool_duration_ms_max, ?), tool_duration_count = tool_duration_count + ?`,\n dur, dur, durationCount,\n );\n } else if (type === 'process.started') bump('processes = processes + 1');\n else if (type === 'process.completed' && event.outcome === 'failure') bump('failed_processes = failed_processes + 1');\n\n if (event.resource?.kind === 'file' || type.startsWith('file.')) {\n bump('file_events_all = file_events_all + 1');\n if (event.resource?.path) {\n this.db\n .prepare('INSERT OR IGNORE INTO file_seen_daily (day, path_key) VALUES (?, ?)')\n .run(day, normalizePathKey(event.resource.path));\n }\n }\n }\n\n private ingestProvider(event: ChronicleEvent): void {\n const day = eventDay(event);\n // provider.fallback carries no top-level runtime identity \u2014 it belongs to\n // the provider being fallen back FROM, held in attributes.from. Attribute\n // it there rather than letting it manufacture a phantom ('', '') row.\n const providerId =\n event.runtime?.providerId ?? asString(readPath(event.attributes ?? {}, 'from.providerId')) ?? '';\n const modelId =\n event.runtime?.modelId ?? asString(readPath(event.attributes ?? {}, 'from.model')) ?? '';\n // No identity at all \u2192 not attributable to any provider row; skip.\n if (!providerId && !modelId) return;\n this.db\n .prepare('INSERT OR IGNORE INTO provider_daily (day, provider_id, model_id) VALUES (?, ?, ?)')\n .run(day, providerId, modelId);\n const update = (sql: string, ...params: Array<string | number>) =>\n this.db\n .prepare(\n `UPDATE provider_daily SET ${sql} WHERE day = ? AND provider_id = ? AND model_id = ?`,\n )\n .run(...params, day, providerId, modelId);\n const duration = durationMs(event);\n switch (event.eventType) {\n case 'provider.attempt.started':\n update('attempts = attempts + 1');\n break;\n case 'provider.attempt.completed':\n update(\n 'completed = completed + 1, input_tokens = input_tokens + ?, output_tokens = output_tokens + ?, ' +\n 'cache_read_tokens = cache_read_tokens + ?, cache_write_tokens = cache_write_tokens + ?, ' +\n 'duration_ms_total = duration_ms_total + ?, duration_ms_max = MAX(duration_ms_max, ?), ' +\n 'duration_count = duration_count + ?',\n numberAt(event, 'usage.input'),\n numberAt(event, 'usage.output'),\n numberAt(event, 'usage.cacheRead'),\n numberAt(event, 'usage.cacheWrite'),\n duration,\n duration,\n duration > 0 ? 1 : 0,\n );\n break;\n case 'provider.attempt.failed':\n update(\n 'failed = failed + 1, retries = retries + ?, duration_ms_total = duration_ms_total + ?, ' +\n 'duration_ms_max = MAX(duration_ms_max, ?), duration_count = duration_count + ?',\n event.attributes?.retryScheduled === true ? 1 : 0,\n duration,\n duration,\n duration > 0 ? 1 : 0,\n );\n break;\n case 'provider.fallback':\n update('fallbacks = fallbacks + 1');\n break;\n default:\n break;\n }\n }\n\n private ingestTokenCost(event: ChronicleEvent): void {\n const cost = readPath(event.attributes ?? {}, 'cost.total');\n if (typeof cost !== 'number' || !Number.isFinite(cost)) return;\n const scopeKey = `${event.scope.projectId ?? ''}\\0${event.scope.sessionId ?? ''}\\0${event.scope.agentId ?? ''}`;\n const occurredAt = event.occurredAt ?? event.observedAt;\n // Latest-wins per scope: token.accounted carries a cumulative snapshot.\n this.db\n .prepare(\n `INSERT INTO token_cost (scope_key, day, occurred_at, sequence, cost) VALUES (?, ?, ?, ?, ?)\n ON CONFLICT(scope_key) DO UPDATE SET\n day = excluded.day, occurred_at = excluded.occurred_at,\n sequence = excluded.sequence, cost = excluded.cost\n WHERE excluded.occurred_at > token_cost.occurred_at\n OR (excluded.occurred_at = token_cost.occurred_at AND excluded.sequence > token_cost.sequence)`,\n )\n .run(scopeKey, eventDay(event), occurredAt, event.sequence, cost);\n }\n\n private ingestTask(event: ChronicleEvent): void {\n const attributes = event.attributes ?? {};\n const taskId = event.scope.taskId ?? stringAt(attributes, 'taskId');\n if (!taskId) return;\n const occurredAt = event.occurredAt ?? event.observedAt;\n this.db.prepare('INSERT OR IGNORE INTO task_outcomes (task_id) VALUES (?)').run(taskId);\n const set = (sql: string, ...params: Array<string | number>) =>\n this.db.prepare(`UPDATE task_outcomes SET ${sql} WHERE task_id = ?`).run(...params, taskId);\n // Lineage columns: last non-empty observation wins.\n const lineage: Array<[string, string | undefined]> = [\n ['run_id', stringAt(attributes, 'runId')],\n ['board_id', event.scope.kanbanBoardId ?? stringAt(attributes, 'boardId')],\n ['session_id', event.scope.sessionId],\n ['agent_id', event.scope.agentId ?? stringAt(attributes, 'subagentId')],\n ];\n for (const [column, value] of lineage) {\n if (value) set(`${column} = ?`, value);\n }\n const base = event.eventType.replace(/^(?:sdd|subagent|kanban)\\.task[._]/, '');\n switch (base) {\n case 'started':\n set(\"status = 'started', started_at = COALESCE(started_at, ?)\", occurredAt);\n break;\n case 'completed':\n set(\n \"status = 'completed', ended_at = ?, duration_ms = ?\",\n occurredAt,\n numberOrDuration(event, attributes),\n );\n break;\n case 'failed':\n set(\"status = 'failed', ended_at = ?\", occurredAt);\n break;\n case 'retrying':\n set('retries = retries + 1');\n break;\n case 'verification_failed':\n set('verification_failures = verification_failures + 1');\n break;\n case 'merged':\n set(\"status = 'merged'\");\n break;\n case 'conflict':\n set(\"status = 'conflict'\");\n break;\n default:\n break;\n }\n }\n\n private ingestFileEvent(event: ChronicleEvent): void {\n const attributes = event.attributes ?? {};\n const operation = stringAt(attributes, 'operation') ?? '';\n if (!operation || operation === 'read') return;\n const filePath = event.resource?.path ?? stringAt(attributes, 'filePath');\n if (!filePath) return;\n this.db\n .prepare(\n `INSERT OR IGNORE INTO file_lineage\n (event_id, path, path_key, operation, occurred_at, session_id, agent_id, task_id, board_id, run_id,\n tool_name, provider_id, model_id, source)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n )\n .run(\n event.eventId,\n normalizeKey(filePath),\n normalizePathKey(filePath),\n operation,\n event.occurredAt ?? event.observedAt,\n event.scope.sessionId ?? '',\n event.scope.agentId ?? '',\n event.scope.taskId ?? stringAt(attributes, 'taskId') ?? '',\n event.scope.kanbanBoardId ?? stringAt(attributes, 'boardId') ?? '',\n stringAt(attributes, 'runId') ?? '',\n stringAt(attributes, 'toolName') ?? '',\n event.runtime?.providerId ?? stringAt(attributes, 'provider') ?? '',\n event.runtime?.modelId ?? stringAt(attributes, 'model') ?? '',\n stringAt(attributes, 'source') ?? (event.eventType === 'file.event' ? 'tool' : 'external'),\n );\n }\n}\n\n// \u2500\u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction eventDay(event: ChronicleEvent): string {\n return (event.occurredAt ?? event.observedAt).slice(0, 10);\n}\n\nfunction durationMs(event: ChronicleEvent): number {\n const value = Number(event.durationNs ?? 0) / 1_000_000;\n return Number.isFinite(value) && value > 0 ? value : 0;\n}\n\nfunction numberOrDuration(event: ChronicleEvent, attributes: Record<string, unknown>): number {\n const explicit = attributes.durationMs;\n if (typeof explicit === 'number' && Number.isFinite(explicit)) return explicit;\n return durationMs(event);\n}\n\nfunction numberAt(event: ChronicleEvent, dotPath: string): number {\n const value = readPath(event.attributes ?? {}, dotPath);\n return typeof value === 'number' && Number.isFinite(value) ? value : 0;\n}\n\nfunction readPath(value: Record<string, unknown>, key: string): unknown {\n return key\n .split('.')\n .reduce<unknown>(\n (current, part) =>\n current && typeof current === 'object'\n ? (current as Record<string, unknown>)[part]\n : undefined,\n value,\n );\n}\n\nfunction stringAt(record: Record<string, unknown>, key: string): string | undefined {\n const value = record[key];\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n}\n\nfunction asString(value: unknown): string | undefined {\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n}\n\nfunction clampLimit(limit: number | undefined, fallback: number): number {\n if (typeof limit !== 'number' || !Number.isFinite(limit) || limit <= 0) return fallback;\n return Math.min(Math.floor(limit), 10_000);\n}\n\nfunction normalizeKey(value: string): string {\n return value.replaceAll('\\\\', '/');\n}\n\n/** Case-normalized path key for lineage lookups. Mirrors the query engine's\n * path comparison (lowercase + forward-slash) and additionally strips a\n * leading `./` so a repo-relative path matches however the tool reported it \u2014\n * case differences on Windows are the common mismatch. */\nfunction normalizePathKey(value: string): string {\n return value.replaceAll('\\\\', '/').replace(/^\\.\\//, '').toLowerCase();\n}\n", "const SQLITE_EXPERIMENTAL_WARNING_RE = /sqlite is an experimental feature/i;\n\nfunction isSqliteExperimentalWarning(warning: unknown, rest: readonly unknown[]): boolean {\n const message = typeof warning === 'string' ? warning : warning instanceof Error ? warning.message : '';\n const typeOrOptions = rest[0];\n const warningType =\n typeof warning === 'string'\n ? typeof typeOrOptions === 'string'\n ? typeOrOptions\n : typeof typeOrOptions === 'object' &&\n typeOrOptions !== null &&\n 'type' in typeOrOptions &&\n typeof typeOrOptions.type === 'string'\n ? typeOrOptions.type\n : ''\n : warning instanceof Error\n ? warning.name\n : '';\n const warningCode =\n typeof warning === 'string'\n ? typeof typeOrOptions === 'object' &&\n typeOrOptions !== null &&\n 'code' in typeOrOptions &&\n typeof typeOrOptions.code === 'string'\n ? typeOrOptions.code\n : typeof rest[1] === 'string'\n ? rest[1]\n : ''\n : warning instanceof Error && 'code' in warning && typeof warning.code === 'string'\n ? warning.code\n : '';\n\n return (\n SQLITE_EXPERIMENTAL_WARNING_RE.test(message) &&\n (warningType === 'ExperimentalWarning' || warningCode === 'ExperimentalWarning')\n );\n}\n\n/**\n * Run a synchronous `node:sqlite` load while filtering only Node's built-in\n * SQLite ExperimentalWarning. All other warnings still go through the original\n * process warning path, and the patch is removed before returning.\n */\nexport function withSqliteExperimentalWarningSuppressed<T>(run: () => T): T {\n const originalEmitWarning = process.emitWarning;\n const forwardWarning = originalEmitWarning.bind(process) as (\n warning: unknown,\n ...rest: unknown[]\n ) => void;\n\n process.emitWarning = ((warning: unknown, ...rest: unknown[]): void => {\n if (isSqliteExperimentalWarning(warning, rest)) return;\n forwardWarning(warning, ...rest);\n }) as typeof process.emitWarning;\n\n try {\n return run();\n } finally {\n process.emitWarning = originalEmitWarning;\n }\n}\n", "import { createHash } from 'node:crypto';\nimport { createReadStream } from 'node:fs';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { createInterface } from 'node:readline';\nimport { comparePartitionPaths, PARTITION_FILE_PATTERN } from './partition-filename.js';\nimport { type ChroniclePartitionRange, ChroniclePartitionRangeCache } from './partition-range-cache.js';\nimport type { ChronicleEvent, ChronicleOutcome, ChronicleResourceRef } from './types.js';\n\nexport interface ChronicleQuery {\n eventId?: string;\n eventTypes?: string[]; outcomes?: ChronicleOutcome[]; from?: string; to?: string;\n projectId?: string; sessionId?: string; agentId?: string; taskId?: string;\n providerId?: string; modelId?: string; traceId?: string; logicalRequestId?: string;\n attemptId?: string; toolCallId?: string; resourceKind?: ChronicleResourceRef['kind'];\n resourceId?: string; path?: string; line?: number; tags?: Record<string, string>;\n attributes?: Record<string, unknown>; text?: string; order?: 'asc' | 'desc';\n limit?: number; cursor?: string;\n}\n\nexport interface ChronicleQueryResult {\n events: ChronicleEvent[]; total: number; nextCursor?: string;\n scannedEvents: number; sourceFiles: number; invalidLines: number;\n summary: ChronicleSummary;\n}\n\n/** Derived once from all matching events; never from the paginated UI sample. */\nexport interface ChronicleSummary {\n logicalRequests: number; modelAttempts: number; completedAttempts: number; failedAttempts: number;\n scheduledRetries: number; fallbacks: number; providers: number; models: number;\n inputTokens: number; outputTokens: number; cacheReadTokens: number; cacheWriteTokens: number;\n estimatedCostUsd: number;\n providerAvgDurationMs: number; providerP95DurationMs: number;\n toolCalls: number; completedTools: number; failedTools: number; toolAvgDurationMs: number;\n processes: number; failedProcesses: number; fileEvents: number; uniqueFiles: number;\n agentEvents: number; uniqueAgents: number; decisions: number; escalations: number;\n failures: number; cancellations: number;\n families: Record<ChronicleSignalFamily, number>;\n failuresByFamily: Record<ChronicleSignalFamily, number>;\n}\nexport type ChronicleSignalFamily = 'llm'|'agent'|'tool'|'file'|'memory'|'task'|'decision'|'runtime'|'finding';\n\nexport type ChronicleFacet = 'eventType' | 'outcome' | 'projectId' | 'sessionId' |\n 'agentId' | 'taskId' | 'providerId' | 'modelId' | 'resourceKind' | 'resourcePath' | 'toolCallId';\nexport interface ChronicleFacetValue { value: string; count: number }\nexport type ChronicleFacetResults = Partial<Record<ChronicleFacet, ChronicleFacetValue[]>>;\n\n/**\n * The complete set of valid {@link ChronicleFacet} values. Shared by both\n * the CLI-embedded and standalone WebUI message routers so they can validate\n * `chronicle.facet` / `chronicle.facets` payloads against a single source of\n * truth \u2014 if `ChronicleFacet` grows a member, this set is the only place\n * that needs updating.\n */\nexport const CHRONICLE_FACET_FIELDS: ReadonlySet<ChronicleFacet> = new Set<ChronicleFacet>([\n 'eventType',\n 'outcome',\n 'projectId',\n 'sessionId',\n 'agentId',\n 'taskId',\n 'providerId',\n 'modelId',\n 'resourceKind',\n 'resourcePath',\n 'toolCallId',\n]);\nexport type ChronicleRelationKind = 'parent_span' | 'trace' | 'tool_call' | 'logical_request' |\n 'attempt' | 'decision' | 'network_request' | 'prompt_manifest' | 'resource_lineage';\nexport interface ChronicleGraphEdge { from: string; to: string; kind: ChronicleRelationKind; confidence: 'explicit' | 'correlated' | 'inferred' }\nexport interface ChronicleGraphResult { nodes: ChronicleEvent[]; edges: ChronicleGraphEdge[]; truncated: boolean }\n\ninterface ChronicleOrderKey {\n occurredAt: string;\n persistedAt: string;\n sequence: number;\n eventId: string;\n}\n\ninterface ChronicleSnapshotEntry {\n id: string;\n size: number;\n}\n\ninterface ChronicleCursor {\n version: 1;\n order: 'asc' | 'desc';\n queryHash: string;\n after: ChronicleOrderKey;\n snapshot: ChronicleSnapshotEntry[];\n}\n\ninterface SnapshotFile extends ChronicleSnapshotEntry {\n file: string;\n}\n\nconst MAX_CURSOR_SNAPSHOT_ENTRIES = 10_000;\n\n// \u2500\u2500 Streaming line-by-line reader \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction streamLines(filePath: string, maxBytes?: number): AsyncIterableIterator<string> {\n const stream = createReadStream(filePath, {\n encoding: 'utf8',\n highWaterMark: 256 * 1024,\n ...(maxBytes !== undefined ? { end: maxBytes - 1 } : {}),\n });\n const rl = createInterface({ input: stream, crlfDelay: Infinity });\n return rl[Symbol.asyncIterator]() as AsyncIterableIterator<string>;\n}\n\n/** One dedicated full pass over a closed file to learn its true occurredAt bounds. */\nasync function computeOccurredAtRange(\n file: string,\n size: number,\n): Promise<{ min: string; max: string } | undefined> {\n let min: string | undefined;\n let max: string | undefined;\n for await (const line of streamLines(file, size)) {\n if (!line.trim()) continue;\n let event: ChronicleEvent;\n try {\n event = JSON.parse(line) as ChronicleEvent;\n if (!isChronicleEvent(event)) continue;\n } catch { continue; }\n const occurredAt = event.occurredAt ?? event.observedAt;\n if (min === undefined || occurredAt < min) min = occurredAt;\n if (max === undefined || occurredAt > max) max = occurredAt;\n }\n return min === undefined ? undefined : { min, max: max! };\n}\n\nfunction rangeOverlaps(range: ChroniclePartitionRange, query: ChronicleQuery): boolean {\n if (range.empty) return false;\n if (query.from && range.maxOccurredAt! < query.from) return false;\n if (query.to && range.minOccurredAt! > query.to) return false;\n return true;\n}\n\n// \u2500\u2500 Streaming query engine (no pre-loaded events) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Queryable projection over immutable Chronicle JSONL partitions.\n * Events are streamed on demand \u2014 no full-file load into memory. */\nexport interface ChronicleQueryEngineOptions {\n /** Shared, longer-lived cache of closed partitions' observed occurredAt ranges. */\n rangeCache?: ChroniclePartitionRangeCache;\n}\n\nexport class ChronicleQueryEngine {\n private readonly partitionFiles: string[];\n private readonly rangeCache: ChroniclePartitionRangeCache | undefined;\n /** The one file (if any) that could still be actively appended to \u2014 never cache-checked or skipped. */\n private readonly activeFile: string | undefined;\n\n private constructor(\n files: string[],\n readonly diagnostics: { sourceFiles: number; invalidLines: number },\n rangeCache?: ChroniclePartitionRangeCache,\n activeFile?: string,\n ) {\n this.partitionFiles = files;\n this.rangeCache = rangeCache;\n this.activeFile = activeFile;\n }\n\n static async fromDirectory(\n directory: string,\n options?: ChronicleQueryEngineOptions,\n ): Promise<ChronicleQueryEngine> {\n const resolved = path.resolve(directory);\n const files = await findPartitions(resolved);\n const rangeCache = options?.rangeCache ?? new ChroniclePartitionRangeCache(resolved);\n return new ChronicleQueryEngine(\n files,\n { sourceFiles: files.length, invalidLines: 0 },\n rangeCache,\n files.at(-1),\n );\n }\n\n static async fromFiles(files: string[]): Promise<ChronicleQueryEngine> {\n return new ChronicleQueryEngine(files, { sourceFiles: files.length, invalidLines: 0 });\n }\n\n /**\n * Returns the file's observed (min, max) `occurredAt` range, computing and\n * caching it on first use. Only ever called for closed/immutable files\n * (never `this.activeFile`) \u2014 see the skip-check call sites.\n */\n private async getOrComputeRange(file: string, size: number): Promise<ChroniclePartitionRange> {\n const cached = await this.rangeCache!.get(file, size);\n if (cached) return cached;\n const computed = await computeOccurredAtRange(file, size);\n const range: ChroniclePartitionRange = computed\n ? { size, minOccurredAt: computed.min, maxOccurredAt: computed.max }\n : { size, empty: true };\n this.rangeCache!.set(file, range);\n return range;\n }\n\n /** True when a closed file's cached range provably cannot contain a match for `query`. */\n private async canSkip(file: string, size: number, query: ChronicleQuery): Promise<boolean> {\n if (!this.rangeCache || (!query.from && !query.to) || file === this.activeFile) return false;\n const range = await this.getOrComputeRange(file, size);\n return !rangeOverlaps(range, query);\n }\n\n /** Stream all partitions, filter, and return the requested page + summary. */\n async query(query: ChronicleQuery = {}): Promise<ChronicleQueryResult> {\n const order = query.order ?? 'desc';\n const limit = Math.max(1, Math.min(query.limit ?? 100, 10_000));\n const queryHash = hashQuery(query);\n const cursor = decodeCursor(query.cursor, order, queryHash);\n const snapshotFiles = cursor\n ? await resolveSnapshotFiles(this.partitionFiles, cursor.snapshot)\n : await captureSnapshot(this.partitionFiles);\n const files = order === 'asc' ? snapshotFiles : snapshotFiles.slice().reverse();\n const summaryAcc = createSummaryAccumulator();\n const orderedCandidates: ChronicleEvent[] = [];\n const pageOrder = (left: ChronicleEvent, right: ChronicleEvent) =>\n compareEvents(left, right) * (order === 'asc' ? 1 : -1);\n let totalCount = 0;\n let remainingCount = 0;\n let scannedEvents = 0;\n let invalidLines = 0;\n\n for (const snapshotFile of files) {\n try {\n if (snapshotFile.size === 0) continue;\n // A closed file whose observed occurredAt range can't overlap [from, to]\n // is skipped with zero I/O. scannedEvents/invalidLines below reflect\n // only lines actually read this call, so a skip legitimately lowers\n // them \u2014 that's the optimization working, not a regression.\n if (await this.canSkip(snapshotFile.file, snapshotFile.size, query)) continue;\n const lines = order === 'asc'\n ? streamLines(snapshotFile.file, snapshotFile.size)\n : reverseLines(snapshotFile.file, snapshotFile.size);\n\n for await (const line of lines) {\n if (!line.trim()) continue;\n let event: ChronicleEvent;\n try {\n event = JSON.parse(line) as ChronicleEvent;\n if (!isChronicleEvent(event)) { invalidLines++; continue; }\n } catch { invalidLines++; continue; }\n scannedEvents++;\n\n if (!matches(event, query)) continue;\n totalCount++;\n updateSummary(summaryAcc, event);\n\n if (cursor && compareEventToKey(event, cursor.after) * (order === 'asc' ? 1 : -1) <= 0) {\n continue;\n }\n remainingCount++;\n\n // Keyset pagination retains only this page's best `limit` matches.\n // Cursor depth and journal size therefore cannot grow page memory.\n const insertionIndex = findInsertionIndex(orderedCandidates, event, pageOrder);\n if (insertionIndex < limit) {\n orderedCandidates.splice(insertionIndex, 0, event);\n if (orderedCandidates.length > limit) orderedCandidates.pop();\n }\n }\n } catch {\n // Skip unreadable partitions\n }\n }\n\n const pageEvents = orderedCandidates;\n const lastEvent = pageEvents.at(-1);\n\n if (this.rangeCache) {\n this.rangeCache.prune(this.partitionFiles);\n await this.rangeCache.flush();\n }\n\n return {\n events: pageEvents,\n total: totalCount,\n summary: finalizeSummary(summaryAcc),\n ...(lastEvent && pageEvents.length < remainingCount\n ? { nextCursor: encodeCursor({\n version: 1,\n order,\n queryHash,\n after: orderKey(lastEvent),\n snapshot: snapshotFiles.map(({ id, size }) => ({ id, size })),\n }) } : {}),\n scannedEvents,\n sourceFiles: snapshotFiles.length,\n invalidLines,\n };\n }\n\n /** Stream all partitions once and compute value counts for every requested facet. */\n async facets(\n fields: readonly ChronicleFacet[],\n query: ChronicleQuery = {},\n limit = 100,\n ): Promise<ChronicleFacetResults> {\n const uniqueFields = [...new Set(fields)];\n if (uniqueFields.length === 0) return {};\n const counts = new Map(uniqueFields.map((field) => [field, new Map<string, number>()]));\n const snapshotFiles = await captureSnapshot(this.partitionFiles);\n let invalidLines = 0;\n for (const snapshotFile of snapshotFiles) {\n try {\n if (snapshotFile.size === 0) continue;\n if (await this.canSkip(snapshotFile.file, snapshotFile.size, query)) continue;\n for await (const line of streamLines(snapshotFile.file, snapshotFile.size)) {\n if (!line.trim()) continue;\n let event: ChronicleEvent;\n try {\n event = JSON.parse(line) as ChronicleEvent;\n if (!isChronicleEvent(event)) { invalidLines++; continue; }\n } catch { invalidLines++; continue; }\n if (!matches(event, query)) continue;\n for (const field of uniqueFields) {\n const value = facetValue(event, field);\n const fieldCounts = counts.get(field)!;\n if (value !== undefined) fieldCounts.set(value, (fieldCounts.get(value) ?? 0) + 1);\n }\n }\n } catch { /* skip unreadable */ }\n }\n this.diagnostics.invalidLines = invalidLines;\n if (this.rangeCache) {\n this.rangeCache.prune(this.partitionFiles);\n await this.rangeCache.flush();\n }\n const result: ChronicleFacetResults = {};\n for (const field of uniqueFields) {\n result[field] = [...counts.get(field)!]\n .map(([value, count]) => ({ value, count }))\n .sort((a, b) => b.count - a.count || a.value.localeCompare(b.value))\n .slice(0, Math.max(0, limit));\n }\n return result;\n }\n\n /** Stream all partitions and compute one facet's value counts. */\n async facet(field: ChronicleFacet, query: ChronicleQuery = {}, limit = 100): Promise<ChronicleFacetValue[]> {\n return (await this.facets([field], query, limit))[field] ?? [];\n }\n\n /** Expand explicit and typed correlation edges; temporal proximity alone never creates causality. */\n async graph(seed: ChronicleQuery = {}, hops = 2, maxNodes = 1_000): Promise<ChronicleGraphResult> {\n const nodeLimit = Math.max(0, Math.floor(maxNodes));\n const selected = new Map<string, ChronicleEvent>();\n let seedCount = 0;\n\n // Pass 1 retains only the bounded seed set.\n for await (const event of streamEvents(this.partitionFiles)) {\n if (!matches(event, seed)) continue;\n seedCount++;\n if (selected.size < nodeLimit) selected.set(event.eventId, event);\n }\n\n let frontier = [...selected.values()];\n const depthLimit = Math.max(0, Math.min(hops, 10));\n for (let depth = 0; depth < depthLimit && frontier.length > 0 && selected.size < nodeLimit; depth++) {\n const frontierKeys = new Set(frontier.flatMap((event) => relationKeys(event).map((relation) => relation.key)));\n const next: ChronicleEvent[] = [];\n\n // Each hop is another streaming pass. Only related nodes up to maxNodes\n // are retained, so journal size cannot determine graph memory usage.\n for await (const event of streamEvents(this.partitionFiles)) {\n if (selected.has(event.eventId)) continue;\n if (!relationKeys(event).some((relation) => frontierKeys.has(relation.key))) continue;\n selected.set(event.eventId, event);\n next.push(event);\n if (selected.size >= nodeLimit) break;\n }\n frontier = next;\n }\n\n const nodes = [...selected.values()].sort(compareEvents);\n const byKey = new Map<string, ChronicleEvent[]>();\n for (const node of nodes) for (const relation of relationKeys(node)) {\n const related = byKey.get(relation.key) ?? [];\n related.push(node);\n byKey.set(relation.key, related);\n }\n\n const edges: ChronicleGraphEdge[] = [];\n const seen = new Set<string>();\n for (const node of nodes) for (const relation of relationKeys(node)) for (const candidate of byKey.get(relation.key) ?? []) {\n if (candidate.eventId === node.eventId) continue;\n const [from, to] = compareEvents(node, candidate) <= 0 ? [node, candidate] : [candidate, node];\n const id = `${from.eventId}:${to.eventId}:${relation.kind}`;\n if (!seen.has(id)) { seen.add(id); edges.push({ from: from.eventId, to: to.eventId, kind: relation.kind, confidence: relation.confidence }); }\n }\n return { nodes, edges, truncated: seedCount > nodeLimit || selected.size >= nodeLimit };\n }\n}\n\nasync function* streamEvents(files: readonly string[]): AsyncGenerator<ChronicleEvent> {\n for (const file of files) {\n try {\n for await (const line of streamLines(file)) {\n if (!line.trim()) continue;\n try {\n const event = JSON.parse(line) as ChronicleEvent;\n if (isChronicleEvent(event)) yield event;\n } catch { /* skip invalid lines */ }\n }\n } catch { /* skip unreadable partitions */ }\n }\n}\n\n// \u2500\u2500 Reverse line reader (reads a file from end to start) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nasync function* reverseLines(filePath: string, maxBytes?: number): AsyncGenerator<string> {\n const CHUNK = 64 * 1024;\n const NEWLINE = 0x0a;\n let handle: fs.FileHandle;\n try { handle = await fs.open(filePath, 'r'); } catch { return; }\n try {\n const fileSize = (await handle.stat()).size;\n const size = Math.min(fileSize, maxBytes ?? fileSize);\n let position = size;\n let suffix = Buffer.alloc(0);\n while (position > 0) {\n const length = Math.min(CHUNK, position);\n position -= length;\n const buffer = Buffer.allocUnsafe(length);\n await handle.read(buffer, 0, length, position);\n const data = suffix.length === 0 ? buffer : Buffer.concat([buffer, suffix]);\n let lineEnd = data.length;\n let firstNewline = -1;\n for (let index = data.length - 1; index >= 0; index--) {\n if (data[index] !== NEWLINE) continue;\n const trimmed = data.subarray(index + 1, lineEnd).toString('utf8').trim();\n if (trimmed) yield trimmed;\n lineEnd = index;\n firstNewline = index;\n }\n suffix = firstNewline >= 0 ? Buffer.from(data.subarray(0, firstNewline)) : data;\n }\n const trimmed = suffix.toString('utf8').trim();\n if (trimmed) yield trimmed;\n } finally { await handle.close(); }\n}\n\n// \u2500\u2500 Running summary accumulator (replaces scan-then-summarize) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface SummaryAcc {\n logicalRequestIds: Set<string>;\n modelAttempts: number; completedAttempts: number; failedAttempts: number;\n scheduledRetries: number; fallbacks: number;\n providers: Set<string>; models: Set<string>;\n inputTokens: number; outputTokens: number;\n cacheReadTokens: number; cacheWriteTokens: number;\n costByScope: Map<string, { cost: number; event: ChronicleEvent }>;\n providerDurations: number[];\n toolCalls: number; completedTools: number; failedTools: number;\n toolDurations: number[];\n processes: number; failedProcesses: number;\n fileEvents: number; uniqueFiles: Set<string>;\n agentEvents: number; uniqueAgents: Set<string>;\n decisions: number; escalations: number;\n failures: number; cancellations: number;\n families: Record<ChronicleSignalFamily, number>;\n failuresByFamily: Record<ChronicleSignalFamily, number>;\n /** One-per-scope token.accounted cost snapshot. Updated when a later\n * token.accounted event has a later timestamp for the same scope. */\n}\n\n/**\n * Exported for the SQLite query engine (`sqlite-query.ts`).\n *\n * Filtering and summarisation are the parts of `ChronicleQuery` with real\n * semantics \u2014 family classification, nested `usage.*` attribute paths, cost\n * de-duplication by scope, a p95 over every matching duration. Re-expressing\n * those in SQL would create a second definition that drifts from this one, and\n * the drift would show up as quietly different numbers rather than an error.\n * The SQLite engine therefore uses SQL only to narrow candidates, then runs\n * these exact functions over the parsed events.\n */\nexport function createSummaryAccumulator(): SummaryAcc {\n return {\n logicalRequestIds: new Set(), modelAttempts: 0, completedAttempts: 0, failedAttempts: 0,\n scheduledRetries: 0, fallbacks: 0, providers: new Set(), models: new Set(),\n inputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0,\n costByScope: new Map(), providerDurations: [],\n toolCalls: 0, completedTools: 0, failedTools: 0, toolDurations: [],\n processes: 0, failedProcesses: 0,\n fileEvents: 0, uniqueFiles: new Set(), agentEvents: 0, uniqueAgents: new Set(),\n decisions: 0, escalations: 0, failures: 0, cancellations: 0,\n families: { llm: 0, agent: 0, tool: 0, file: 0, memory: 0, task: 0, decision: 0, runtime: 0, finding: 0 },\n failuresByFamily: { llm: 0, agent: 0, tool: 0, file: 0, memory: 0, task: 0, decision: 0, runtime: 0, finding: 0 },\n };\n}\n\nexport function updateSummary(acc: SummaryAcc, event: ChronicleEvent): void {\n // Families\n const family = signalFamily(event);\n acc.families[family]++;\n if (isTerminalFailure(event)) acc.failuresByFamily[family]++;\n\n // Running counts per event type\n if (event.correlation.logicalRequestId) acc.logicalRequestIds.add(event.correlation.logicalRequestId);\n if (event.runtime?.providerId) acc.providers.add(event.runtime.providerId);\n if (event.runtime?.modelId) acc.models.add(event.runtime.modelId);\n\n if (event.eventType === 'provider.attempt.started') acc.modelAttempts++;\n else if (event.eventType === 'provider.attempt.completed') {\n acc.completedAttempts++;\n acc.inputTokens += numberAt(event, 'usage.input');\n acc.outputTokens += numberAt(event, 'usage.output');\n acc.cacheReadTokens += numberAt(event, 'usage.cacheRead');\n acc.cacheWriteTokens += numberAt(event, 'usage.cacheWrite');\n const dur = durationMs(event);\n if (dur > 0) acc.providerDurations.push(dur);\n } else if (event.eventType === 'provider.attempt.failed') {\n acc.failedAttempts++;\n if (event.attributes?.retryScheduled === true) acc.scheduledRetries++;\n const dur = durationMs(event);\n if (dur > 0) acc.providerDurations.push(dur);\n } else if (event.eventType === 'provider.fallback') acc.fallbacks++;\n else if (event.eventType === 'tool.started') acc.toolCalls++;\n else if (event.eventType === 'tool.executed') {\n acc.completedTools++;\n const dur = durationMs(event);\n if (dur > 0) acc.toolDurations.push(dur);\n } else if (event.eventType === 'tool.failed') {\n acc.failedTools++;\n const dur = durationMs(event);\n if (dur > 0) acc.toolDurations.push(dur);\n } else if (event.eventType === 'process.started') acc.processes++;\n else if (event.eventType === 'process.completed' && event.outcome === 'failure') acc.failedProcesses++;\n else if (event.eventType === 'decision.requested') acc.decisions++;\n else if (event.eventType === 'decision.escalated') acc.escalations++;\n\n // Token accounted \u2014 keep the latest finite snapshot per scope. Zero is a\n // meaningful reset, and compareEvents makes ties independent of scan order.\n if (event.eventType === 'token.accounted') {\n const cost = readPath(event.attributes ?? {}, 'cost.total');\n if (typeof cost === 'number' && Number.isFinite(cost)) {\n const key = scopeKey(event);\n const existing = acc.costByScope.get(key);\n if (!existing || compareEvents(event, existing.event) > 0) {\n acc.costByScope.set(key, { cost, event });\n }\n }\n }\n\n // File evidence\n if (event.resource?.kind === 'file' || event.eventType.startsWith('file.')) {\n acc.fileEvents++;\n if (event.resource?.path) acc.uniqueFiles.add(event.resource.path);\n }\n\n // Agent events\n if (family === 'agent') acc.agentEvents++;\n if (event.scope.agentId) acc.uniqueAgents.add(event.scope.agentId);\n\n // Terminal failures and cancellations\n if (isTerminalFailure(event)) acc.failures++;\n if (event.outcome === 'cancelled' || event.outcome === 'abandoned') acc.cancellations++;\n}\n\nexport function finalizeSummary(acc: SummaryAcc): ChronicleSummary {\n const sortedProviderDurations = acc.providerDurations.slice().sort((a, b) => a - b);\n const sortedToolDurations = acc.toolDurations.slice().sort((a, b) => a - b);\n const totalCost = [...acc.costByScope.values()].reduce((sum, entry) => sum + entry.cost, 0);\n return {\n logicalRequests: acc.logicalRequestIds.size,\n modelAttempts: acc.modelAttempts,\n completedAttempts: acc.completedAttempts,\n failedAttempts: acc.failedAttempts,\n scheduledRetries: acc.scheduledRetries,\n fallbacks: acc.fallbacks,\n providers: acc.providers.size,\n models: acc.models.size,\n inputTokens: acc.inputTokens,\n outputTokens: acc.outputTokens,\n cacheReadTokens: acc.cacheReadTokens,\n cacheWriteTokens: acc.cacheWriteTokens,\n estimatedCostUsd: totalCost,\n providerAvgDurationMs: average(sortedProviderDurations),\n providerP95DurationMs: percentile(sortedProviderDurations, 0.95),\n toolCalls: acc.toolCalls,\n completedTools: acc.completedTools,\n failedTools: acc.failedTools,\n toolAvgDurationMs: average(sortedToolDurations),\n processes: acc.processes,\n failedProcesses: acc.failedProcesses,\n fileEvents: acc.fileEvents,\n uniqueFiles: acc.uniqueFiles.size,\n agentEvents: acc.agentEvents,\n uniqueAgents: acc.uniqueAgents.size,\n decisions: acc.decisions,\n escalations: acc.escalations,\n failures: acc.failures,\n cancellations: acc.cancellations,\n families: acc.families,\n failuresByFamily: acc.failuresByFamily,\n };\n}\n\n// \u2500\u2500 Partition discovery (no pre-loading) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** The partition files list is stored on the prototype for legacy callers\n * that reference engine.partitionFiles directly. */\nObject.defineProperty(ChronicleQueryEngine.prototype, 'partitionFiles', {\n get() { throw new Error('ChronicleQueryEngine no longer loads events on construction. Use async query().'); },\n set(this: ChronicleQueryEngine, _val: string[]) {\n // Allow fromFiles/fromDirectory to attach the list for graph()\n Object.defineProperty(this, 'partitionFiles', { value: _val, writable: false, configurable: false });\n },\n});\n\n/** Recursively locate journal partition files under a Chronicle directory,\n * ordered family-first then rotation index. Shared with the metrics store. */\nexport async function findChroniclePartitions(root: string): Promise<string[]> {\n return findPartitions(root);\n}\n\nasync function findPartitions(root: string): Promise<string[]> {\n const result: string[] = [];\n const visit = async (directory: string): Promise<void> => {\n let entries: import('node:fs').Dirent[];\n try { entries = await fs.readdir(directory, { withFileTypes: true }); } catch { return; }\n for (const entry of entries) {\n const full = path.join(directory, entry.name);\n if (entry.isDirectory()) await visit(full);\n else if (entry.isFile() && PARTITION_FILE_PATTERN.test(entry.name)) result.push(full);\n }\n };\n await visit(root);\n return result.sort(comparePartitionPaths);\n}\n\n// \u2500\u2500 Helper functions \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction numberAt(event: ChronicleEvent, dotPath: string): number {\n const value = readPath(event.attributes ?? {}, dotPath);\n return typeof value === 'number' && Number.isFinite(value) ? value : 0;\n}\n\nfunction durationMs(event: ChronicleEvent): number {\n const value = Number(event.durationNs ?? 0) / 1_000_000;\n return Number.isFinite(value) ? value : 0;\n}\n\nfunction average(values: number[]): number {\n return values.length ? values.reduce((sum, v) => sum + v, 0) / values.length : 0;\n}\n\nfunction percentile(sorted: number[], quantile: number): number {\n return sorted.length ? sorted[Math.min(sorted.length - 1, Math.max(0, Math.ceil(sorted.length * quantile) - 1))]! : 0;\n}\n\nfunction scopeKey(event: ChronicleEvent): string {\n return `${event.scope.projectId ?? ''}\\0${event.scope.sessionId ?? ''}\\0${event.scope.agentId ?? ''}`;\n}\n\n/** Shared with ChronicleMetricsStore so its default-view summary classifies\n * events identically to the raw-scan summary it stands in for. */\nexport function signalFamily(event: ChronicleEvent): ChronicleSignalFamily {\n if (/^(?:decision|brain|permission)\\./.test(event.eventType)) return 'decision';\n if (event.resource?.kind === 'file' || event.resource?.kind === 'symbol' || /^(?:file|worktree)\\./.test(event.eventType)) return 'file';\n if (/^(?:provider|token|context|ctx|compaction)\\./.test(event.eventType)) return 'llm';\n if (/^(?:agent|subagent|delegate|fleet|concurrency)\\./.test(event.eventType)) return 'agent';\n if (/^(?:tool|process|mcp|network)\\./.test(event.eventType)) return 'tool';\n if (/^(?:memory|storage|trust)\\./.test(event.eventType)) return 'memory';\n if (/^(?:sdd|task|kanban|checkpoint|session|iteration|in_flight)\\./.test(event.eventType)) return 'task';\n if (/^(?:finding|review)\\./.test(event.eventType)) return 'finding';\n return 'runtime';\n}\n\n/** Shared with ChronicleMetricsStore \u2014 see signalFamily(). */\nexport function isTerminalFailure(event: ChronicleEvent): boolean {\n if (event.eventType === 'provider.attempt.failed') return event.attributes?.retryScheduled !== true;\n return event.eventType === 'tool.failed' ||\n (event.eventType === 'process.completed' && event.outcome === 'failure') ||\n /^(?:agent\\.run\\.error|sdd\\.task\\.failed|compaction\\.failed|network\\.request\\.failed)$/.test(event.eventType);\n}\n\n/**\n * Exported for the SQLite engine. Which correlation keys an event carries \u2014 and\n * with what confidence \u2014 is the definition of a Chronicle edge; a second copy\n * would let the two engines draw different graphs from the same data.\n */\nexport function relationKeys(event: ChronicleEvent): Array<{ key: string; kind: ChronicleRelationKind; confidence: ChronicleGraphEdge['confidence'] }> {\n const result: Array<{ key: string; kind: ChronicleRelationKind; confidence: ChronicleGraphEdge['confidence'] }> = [];\n const add = (kind: ChronicleRelationKind, value: unknown, confidence: ChronicleGraphEdge['confidence']) => {\n if (typeof value === 'string' && value) result.push({ key: `${kind}:${value}`, kind, confidence });\n };\n add('trace', event.correlation.traceId, 'correlated');\n add('tool_call', event.correlation.toolCallId, 'explicit');\n add('logical_request', event.correlation.logicalRequestId, 'explicit');\n add('attempt', event.correlation.attemptId, 'explicit');\n add('decision', event.attributes?.decisionId, 'explicit');\n add('network_request', event.attributes?.requestId, 'explicit');\n add('prompt_manifest', (event.attributes?.promptManifest as Record<string, unknown> | undefined)?.manifestId, 'explicit');\n add('resource_lineage', event.resource?.id, 'inferred');\n // tool.resource.observed is windowed into one metrics.rollup event per\n // tool call (rollup-adapter.ts) carrying a bounded `resources` list rather\n // than a single top-level `resource` \u2014 surface each as its own edge so a\n // rolled-up \"observed\" touch still participates in the same resource\n // lineage group as a mutation event for the same resource id.\n if (event.eventType === 'metrics.rollup' && event.attributes?.signal === 'tool.resource.observed') {\n const resources = event.attributes.resources as Array<{ id?: unknown }> | undefined;\n for (const resource of resources ?? []) {\n if (typeof resource?.id === 'string') add('resource_lineage', resource.id, 'inferred');\n }\n }\n if (event.correlation.parentSpanId) add('parent_span', event.correlation.parentSpanId, 'explicit');\n add('parent_span', event.correlation.spanId, 'explicit');\n return result;\n}\n\nexport function matches(event: ChronicleEvent, query: ChronicleQuery): boolean {\n if (query.eventId && event.eventId !== query.eventId) return false;\n if (query.eventTypes && !query.eventTypes.includes(event.eventType)) return false;\n if (query.outcomes && (!event.outcome || !query.outcomes.includes(event.outcome))) return false;\n const occurredAt = event.occurredAt ?? event.observedAt;\n if (query.from && occurredAt < query.from || query.to && occurredAt > query.to) return false;\n if (!equal(query.projectId, event.scope.projectId) || !equal(query.sessionId, event.scope.sessionId)) return false;\n if (!equal(query.agentId, event.scope.agentId) || !equal(query.taskId, event.scope.taskId)) return false;\n if (!equal(query.providerId, event.runtime?.providerId) || !equal(query.modelId, event.runtime?.modelId)) return false;\n if (!equal(query.traceId, event.correlation.traceId) || !equal(query.logicalRequestId, event.correlation.logicalRequestId)) return false;\n if (!equal(query.attemptId, event.correlation.attemptId) || !equal(query.toolCallId, event.correlation.toolCallId)) return false;\n if (!equal(query.resourceKind, event.resource?.kind) || !equal(query.resourceId, event.resource?.id)) return false;\n if (query.path && normalize(event.resource?.path) !== normalize(query.path)) return false;\n if (query.line !== undefined && !lineContains(event, query.line)) return false;\n if (query.tags && !objectContains(event.tags, query.tags)) return false;\n if (query.attributes && !objectContains(event.attributes, query.attributes)) return false;\n if (query.text && !JSON.stringify(event).toLocaleLowerCase().includes(query.text.toLocaleLowerCase())) return false;\n return true;\n}\n\nfunction equal<T>(expected: T | undefined, actual: T | undefined): boolean { return expected === undefined || expected === actual; }\nfunction normalize(value: string | undefined): string | undefined { return value?.replaceAll('\\\\', '/').toLocaleLowerCase(); }\nfunction lineContains(event: ChronicleEvent, line: number): boolean {\n const start = event.resource?.lineStart; const end = event.resource?.lineEnd ?? start;\n return start !== undefined && end !== undefined && line >= start && line <= end;\n}\nfunction objectContains(actual: Record<string, unknown> | undefined, expected: Record<string, unknown>): boolean {\n return Boolean(actual && Object.entries(expected).every(([key, value]) => deepEqual(readPath(actual, key), value)));\n}\nfunction readPath(value: Record<string, unknown>, key: string): unknown {\n return key.split('.').reduce<unknown>((current, part) => current && typeof current === 'object'\n ? (current as Record<string, unknown>)[part] : undefined, value);\n}\nfunction deepEqual(left: unknown, right: unknown): boolean { return JSON.stringify(left) === JSON.stringify(right); }\nfunction findInsertionIndex(\n events: readonly ChronicleEvent[],\n event: ChronicleEvent,\n compare: (left: ChronicleEvent, right: ChronicleEvent) => number,\n): number {\n let low = 0;\n let high = events.length;\n while (low < high) {\n const middle = (low + high) >>> 1;\n if (compare(events[middle]!, event) <= 0) low = middle + 1;\n else high = middle;\n }\n return low;\n}\nexport function compareEvents(a: ChronicleEvent, b: ChronicleEvent): number {\n return compareEventToKey(a, orderKey(b));\n}\nfunction compareEventToKey(event: ChronicleEvent, key: ChronicleOrderKey): number {\n return (event.occurredAt ?? event.observedAt).localeCompare(key.occurredAt) ||\n event.persistedAt.localeCompare(key.persistedAt) || event.sequence - key.sequence ||\n event.eventId.localeCompare(key.eventId);\n}\nfunction orderKey(event: ChronicleEvent): ChronicleOrderKey {\n return {\n occurredAt: event.occurredAt ?? event.observedAt,\n persistedAt: event.persistedAt,\n sequence: event.sequence,\n eventId: event.eventId,\n };\n}\nfunction hashQuery(query: ChronicleQuery): string {\n const { cursor: _cursor, limit: _limit, order: _order, ...filters } = query;\n return createHash('sha256').update(stableStringify(filters), 'utf8').digest('base64url');\n}\nfunction encodeCursor(cursor: ChronicleCursor): string {\n return Buffer.from(JSON.stringify(cursor), 'utf8').toString('base64url');\n}\nfunction decodeCursor(\n encoded: string | undefined,\n order: 'asc' | 'desc',\n queryHash: string,\n): ChronicleCursor | undefined {\n if (!encoded) return undefined;\n if (encoded.length > 1_000_000) throw new Error('Invalid Chronicle cursor');\n try {\n const parsed = JSON.parse(Buffer.from(encoded, 'base64url').toString('utf8')) as unknown;\n if (!isCursor(parsed) || parsed.order !== order || parsed.queryHash !== queryHash) {\n throw new Error('cursor does not match the query');\n }\n return parsed;\n } catch (error) {\n throw new Error(`Invalid Chronicle cursor: ${error instanceof Error ? error.message : String(error)}`);\n }\n}\nfunction isCursor(value: unknown): value is ChronicleCursor {\n if (!value || typeof value !== 'object') return false;\n const cursor = value as Partial<ChronicleCursor>;\n const after = cursor.after as Partial<ChronicleOrderKey> | undefined;\n if (cursor.version !== 1 || (cursor.order !== 'asc' && cursor.order !== 'desc') ||\n typeof cursor.queryHash !== 'string' || !after ||\n typeof after.occurredAt !== 'string' || typeof after.persistedAt !== 'string' ||\n !Number.isSafeInteger(after.sequence) || typeof after.eventId !== 'string' ||\n !Array.isArray(cursor.snapshot) || cursor.snapshot.length > MAX_CURSOR_SNAPSHOT_ENTRIES) return false;\n\n const snapshotIds = new Set<string>();\n for (const entry of cursor.snapshot) {\n if (!entry || typeof entry.id !== 'string' || !entry.id ||\n !Number.isSafeInteger(entry.size) || entry.size < 0 || snapshotIds.has(entry.id)) return false;\n snapshotIds.add(entry.id);\n }\n return true;\n}\nasync function captureSnapshot(files: readonly string[]): Promise<SnapshotFile[]> {\n if (files.length > MAX_CURSOR_SNAPSHOT_ENTRIES) {\n throw new Error('Chronicle snapshot contains too many partitions');\n }\n return Promise.all(files.map(async (file) => {\n let size = 0;\n try { size = (await fs.stat(file)).size; } catch { /* preserve missing source as empty */ }\n return { file, id: fileId(file), size };\n }));\n}\nasync function resolveSnapshotFiles(\n files: readonly string[],\n snapshot: readonly ChronicleSnapshotEntry[],\n): Promise<SnapshotFile[]> {\n const currentFiles = new Map(files.map((file) => [fileId(file), file]));\n return Promise.all(snapshot.map(async (entry) => {\n const file = currentFiles.get(entry.id);\n if (!file) throw new Error('Chronicle cursor snapshot has expired');\n let currentSize: number;\n try { currentSize = (await fs.stat(file)).size; } catch { throw new Error('Chronicle cursor snapshot has expired'); }\n if (currentSize < entry.size) throw new Error('Chronicle cursor snapshot has expired');\n return { file, ...entry };\n }));\n}\nfunction fileId(file: string): string {\n return createHash('sha256').update(path.resolve(file), 'utf8').digest('base64url');\n}\nfunction stableStringify(value: unknown): string {\n if (value === null || typeof value !== 'object') return JSON.stringify(value);\n if (Array.isArray(value)) return `[${value.map(stableStringify).join(',')}]`;\n const object = value as Record<string, unknown>;\n return `{${Object.keys(object).sort().map((key) => `${JSON.stringify(key)}:${stableStringify(object[key])}`).join(',')}}`;\n}\nfunction isChronicleEvent(value: unknown): value is ChronicleEvent {\n if (!isRecord(value) || !isRecord(value.scope) || !isRecord(value.correlation)) return false;\n return value.schemaVersion === 1 &&\n typeof value.eventId === 'string' && typeof value.eventType === 'string' &&\n typeof value.occurredAt === 'string' && typeof value.observedAt === 'string' &&\n typeof value.persistedAt === 'string' && Number.isSafeInteger(value.sequence) &&\n (value.sequence as number) >= 0 && typeof value.previousHash === 'string' &&\n typeof value.hash === 'string' && typeof value.scope.installationId === 'string' &&\n typeof value.scope.machineId === 'string' && optionalStrings(value.scope, [\n 'projectId', 'repositoryId', 'workspaceId', 'worktreeId', 'sessionId', 'turnId',\n 'iterationId', 'agentId', 'goalId', 'planId', 'taskId', 'kanbanBoardId',\n ]) && typeof value.correlation.traceId === 'string' &&\n typeof value.correlation.spanId === 'string' && optionalStrings(value.correlation, [\n 'parentSpanId', 'logicalRequestId', 'attemptId', 'toolCallId',\n ]) && isRuntime(value.runtime) && isResource(value.resource) &&\n (value.attributes === undefined || isRecord(value.attributes)) &&\n (value.tags === undefined || isStringRecord(value.tags));\n}\nfunction isRuntime(value: unknown): boolean {\n return value === undefined || isRecord(value) &&\n optionalStrings(value, ['providerId', 'modelId', 'modelRevision']) &&\n optionalFiniteNumbers(value, ['processId', 'parentProcessId']);\n}\nfunction isResource(value: unknown): boolean {\n if (value === undefined) return true;\n if (!isRecord(value) || !['file', 'symbol', 'memory', 'task', 'kanban', 'process',\n 'network', 'artifact', 'other'].includes(String(value.kind)) || typeof value.id !== 'string') return false;\n return optionalStrings(value, ['path', 'contentHashBefore', 'contentHashAfter']) &&\n optionalFiniteNumbers(value, ['lineStart', 'lineEnd']);\n}\nfunction optionalStrings(value: Record<string, unknown>, keys: readonly string[]): boolean {\n return keys.every((key) => value[key] === undefined || typeof value[key] === 'string');\n}\nfunction optionalFiniteNumbers(value: Record<string, unknown>, keys: readonly string[]): boolean {\n return keys.every((key) => value[key] === undefined || typeof value[key] === 'number' && Number.isFinite(value[key]));\n}\nfunction isStringRecord(value: unknown): value is Record<string, string> {\n return isRecord(value) && Object.values(value).every((entry) => typeof entry === 'string');\n}\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value && typeof value === 'object' && !Array.isArray(value));\n}\nexport function facetValue(event: ChronicleEvent, field: ChronicleFacet): string | undefined {\n const values: Record<ChronicleFacet, string | undefined> = {\n eventType: event.eventType, outcome: event.outcome, projectId: event.scope.projectId,\n sessionId: event.scope.sessionId, agentId: event.scope.agentId, taskId: event.scope.taskId,\n providerId: event.runtime?.providerId, modelId: event.runtime?.modelId,\n resourceKind: event.resource?.kind, resourcePath: event.resource?.path,\n toolCallId: event.correlation.toolCallId,\n };\n return values[field];\n}\n", "import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { atomicWrite, withFileLock } from '../utils/atomic-write.js';\n\nconst CACHE_VERSION = 1;\n\nexport interface ChroniclePartitionRange {\n size: number;\n minOccurredAt?: string;\n maxOccurredAt?: string;\n /** No valid events were found in the file. */\n empty?: boolean;\n}\n\ninterface CacheFile {\n version: number;\n entries: Record<string, ChroniclePartitionRange>;\n}\n\nfunction isRange(value: unknown): value is ChroniclePartitionRange {\n if (!value || typeof value !== 'object') return false;\n const range = value as Partial<ChroniclePartitionRange>;\n return (\n typeof range.size === 'number' &&\n (range.minOccurredAt === undefined || typeof range.minOccurredAt === 'string') &&\n (range.maxOccurredAt === undefined || typeof range.maxOccurredAt === 'string') &&\n (range.empty === undefined || typeof range.empty === 'boolean')\n );\n}\n\n/**\n * Persisted cache of each closed (immutable) Chronicle partition file's\n * observed min/max `occurredAt`, so query()/facets() can skip a file\n * entirely instead of re-streaming its contents when it can't overlap a\n * time-bounded query. Keyed by (path, size) so a file whose size ever\n * unexpectedly changes just misses and gets recomputed.\n */\nexport class ChroniclePartitionRangeCache {\n private readonly cachePath: string;\n private entries: Map<string, ChroniclePartitionRange> | undefined;\n private dirty = false;\n\n constructor(private readonly directory: string) {\n this.cachePath = path.join(directory, 'range-cache.json');\n }\n\n private toKey(filePath: string): string {\n return path.relative(this.directory, filePath).split(path.sep).join('/');\n }\n\n private async load(): Promise<Map<string, ChroniclePartitionRange>> {\n if (this.entries) return this.entries;\n const entries = new Map<string, ChroniclePartitionRange>();\n try {\n const raw = await fs.readFile(this.cachePath, 'utf8');\n const parsed = JSON.parse(raw) as Partial<CacheFile>;\n if (parsed.version === CACHE_VERSION && parsed.entries && typeof parsed.entries === 'object') {\n for (const [key, range] of Object.entries(parsed.entries)) {\n if (isRange(range)) entries.set(key, range);\n }\n }\n } catch {\n // Missing, corrupt, or unreadable sidecar: self-heal by starting\n // empty rather than failing the query it's meant to speed up.\n }\n this.entries = entries;\n return entries;\n }\n\n async get(filePath: string, currentSize: number): Promise<ChroniclePartitionRange | undefined> {\n const entries = await this.load();\n const range = entries.get(this.toKey(filePath));\n return range && range.size === currentSize ? range : undefined;\n }\n\n set(filePath: string, range: ChroniclePartitionRange): void {\n this.entries ??= new Map();\n this.entries.set(this.toKey(filePath), range);\n this.dirty = true;\n }\n\n /** Drop entries for files no longer present (e.g. removed by retention purge). */\n prune(existingFiles: readonly string[]): void {\n if (!this.entries) return;\n const keep = new Set(existingFiles.map((file) => this.toKey(file)));\n for (const key of this.entries.keys()) {\n if (!keep.has(key)) {\n this.entries.delete(key);\n this.dirty = true;\n }\n }\n }\n\n async flush(): Promise<void> {\n if (!this.dirty || !this.entries) return;\n const payload: CacheFile = { version: CACHE_VERSION, entries: Object.fromEntries(this.entries) };\n try {\n await withFileLock(this.cachePath, async () => {\n await atomicWrite(this.cachePath, `${JSON.stringify(payload)}\\n`, { mode: 0o600 });\n });\n this.dirty = false;\n } catch {\n // Best-effort persistence: the cache still works in-memory for this\n // process even if the sidecar couldn't be written this time.\n }\n }\n}\n", "/**\n * One-shot import of the legacy JSONL journal into SQLite\n * (phase 2 of `chronicle-sqlite-journal-v1`).\n *\n * The events being moved are an audit record, so this is deliberately strict:\n * every event is verified against the running chain *before* it is inserted,\n * and a single break aborts that day inside a rolled-back transaction.\n * Repairing a broken chain silently would defeat the purpose of having one \u2014\n * the operator is told exactly where it broke and decides.\n *\n * Chains are scoped to a day family (`<day>.events.jsonl` plus its `.NNNNN`\n * rotations), not to the journal as a whole: `sequence` restarts at 1 each day.\n * Each family is therefore imported as its own chain and its own transaction,\n * seeded from that family's `*.retention.json` checkpoint when its prefix was\n * already purged.\n *\n * A family that fails verification is quarantined \u2014 never imported, never\n * repaired, recorded by day so health can report it \u2014 and the remaining days\n * still move. Scoping the abort to the journal instead made every future day\n * hostage to the worst day on disk: one multi-writer partition from before the\n * single-daemon invariant, and the store could never finish opening, so\n * Chronicle recorded nothing at all from then on.\n */\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { chronicleEventHash, GENESIS_HASH } from './event-hash.js';\nimport { collectPartitions, readRetentionCheckpoint, streamEntriesStrict } from './journal.js';\nimport { PARTITION_FILE_PATTERN } from './partition-filename.js';\nimport type {\n ChronicleQuarantinedFamily,\n ChronicleSqliteJournal,\n} from './sqlite-journal.js';\n\nexport interface ChronicleLegacyImportResult {\n /** True when the marker was already set and nothing was read. */\n alreadyImported: boolean;\n /** Day families imported. */\n families: number;\n /** Events imported across all families. */\n events: number;\n /** Day families refused for a broken chain; none of their events landed. */\n quarantined: ChronicleQuarantinedFamily[];\n}\n\n/** A chain break found while importing; carries enough context to act on. */\nexport class ChronicleImportError extends Error {\n constructor(\n message: string,\n readonly day: string,\n readonly sequence: number,\n ) {\n super(message);\n this.name = 'ChronicleImportError';\n }\n}\n\n/**\n * Discover the day families in a chronicle directory.\n *\n * `PARTITION_FILE_PATTERN` captures the family base (`<day>.events`) separately\n * from the rotation index, so rotations collapse onto the family they belong\n * to instead of being mistaken for separate days.\n */\nasync function discoverFamilies(directory: string): Promise<string[]> {\n let entries: string[];\n try {\n entries = await fs.readdir(directory);\n } catch {\n return [];\n }\n const bases = new Set<string>();\n for (const entry of entries) {\n const match = PARTITION_FILE_PATTERN.exec(entry);\n if (match?.[1]) bases.add(match[1]);\n }\n return [...bases].sort();\n}\n\n/** `2026-07-28.events` \u2192 `2026-07-28`. */\nfunction dayOfFamily(familyBase: string): string {\n return familyBase.replace(/\\.events$/u, '');\n}\n\nexport async function importLegacyChronicleJournal(\n journal: ChronicleSqliteJournal,\n directory: string,\n): Promise<ChronicleLegacyImportResult> {\n if (journal.hasImportedLegacyJournal()) {\n return {\n alreadyImported: true,\n families: 0,\n events: 0,\n quarantined: journal.quarantinedFamilies(),\n };\n }\n\n const families = await discoverFamilies(directory);\n const quarantined: ChronicleQuarantinedFamily[] = [];\n let importedEvents = 0;\n let importedFamilies = 0;\n\n for (const familyBase of families) {\n const day = dayOfFamily(familyBase);\n const basePath = path.join(directory, `${familyBase}.jsonl`);\n let familyEvents = 0;\n\n // Resume rather than restart. Families commit one at a time, so a run cut\n // short \u2014 the daemon restarted, the machine rebooted \u2014 leaves whole days\n // already stored. Re-reading them would abort on the `(day, sequence)`\n // primary key and put the import back to square one every time.\n if (journal.hasImportedDay(day)) continue;\n\n try {\n // One transaction per family: a break below rolls back this day only,\n // leaving the days already committed \u2014 and every future day \u2014 intact.\n await journal.runFamilyImport(async (sink) => {\n familyEvents = 0;\n\n const checkpointResult = await readRetentionCheckpoint(basePath);\n if (checkpointResult.error) {\n throw new ChronicleImportError(checkpointResult.error, day, 0);\n }\n const checkpoint = checkpointResult.checkpoint;\n if (checkpoint) sink.checkpoint(day, checkpoint.sequence, checkpoint.hash);\n\n let expectedSequence = (checkpoint?.sequence ?? 0) + 1;\n let previousHash = checkpoint?.hash ?? GENESIS_HASH;\n\n for (const partition of await collectPartitions(basePath)) {\n for await (const event of streamEntriesStrict(partition)) {\n if (event.sequence !== expectedSequence) {\n throw new ChronicleImportError(\n `sequence gap in ${day}: expected ${expectedSequence}, found ${event.sequence}`,\n day,\n event.sequence,\n );\n }\n if (event.previousHash !== previousHash) {\n throw new ChronicleImportError(\n `previous hash mismatch in ${day} at sequence ${event.sequence}`,\n day,\n event.sequence,\n );\n }\n if (chronicleEventHash(event) !== event.hash) {\n throw new ChronicleImportError(\n `entry hash mismatch in ${day} at sequence ${event.sequence}`,\n day,\n event.sequence,\n );\n }\n sink.insert(day, event);\n familyEvents += 1;\n expectedSequence = event.sequence + 1;\n previousHash = event.hash;\n }\n }\n });\n } catch (error) {\n // A broken chain is data the operator has to decide about, so it is\n // quarantined and reported. Anything else \u2014 an unreadable file, a full\n // disk, SQLite refusing to write \u2014 is an infrastructure failure that\n // would corrupt the import if treated as \"just skip that day\".\n if (!(error instanceof ChronicleImportError)) throw error;\n quarantined.push({ day, sequence: error.sequence, reason: error.message });\n continue;\n }\n\n if (familyEvents > 0) importedFamilies += 1;\n importedEvents += familyEvents;\n }\n\n journal.recordQuarantinedFamilies(quarantined);\n journal.markLegacyJournalImported();\n\n return {\n alreadyImported: false,\n families: importedFamilies,\n events: importedEvents,\n quarantined,\n };\n}\n", "/**\n * SQLite-backed Chronicle journal (phase 1 of `chronicle-sqlite-journal-v1`).\n *\n * Same durable contract as `ChronicleJournal`, different storage: events become\n * rows instead of lines in `<day>.events.jsonl` partitions. The tamper-evident\n * chain is unchanged and deliberately so \u2014 `sequence`, `previousHash` and\n * `hash` mean exactly what they mean in the JSONL journal, and the hash is\n * computed by the shared `event-hash.ts` so the two stores can never drift.\n *\n * Why the payload is stored verbatim: the `hash` preimage is the canonical\n * encoding of the event *minus* its own `hash`. Reconstructing an event from\n * projected columns and re-hashing it would silently depend on the column set\n * staying lossless forever. Storing `JSON.stringify(event)` and re-deriving the\n * preimage from the parsed payload keeps verification independent of the\n * projection \u2014 the columns are a read-path index, never the source of truth.\n *\n * Only the project daemon opens this database, after it has won the endpoint\n * election, so the writer is single by construction and `BEGIN IMMEDIATE` is\n * enough. See `packages/core/tests/architecture/project-daemon-boundary.test.ts`.\n */\nimport { randomUUID } from 'node:crypto';\nimport { createRequire } from 'node:module';\nimport * as path from 'node:path';\nimport type { DatabaseSync } from 'node:sqlite';\nimport { withSqliteExperimentalWarningSuppressed } from '../utils/index.js';\nimport { chronicleEventHash, GENESIS_HASH, hashValue } from './event-hash.js';\nimport type { ChronicleJournalStats, ChroniclePurgeResult } from './journal.js';\nimport {\n ChronicleSqliteQueryEngine,\n type ChronicleSqliteQueryEngineOptions,\n} from './sqlite-query.js';\nimport {\n CHRONICLE_SCHEMA_VERSION,\n type ChronicleEvent,\n type ChronicleEventInput,\n type ChronicleVerifyResult,\n} from './types.js';\n\nexport const CHRONICLE_SQLITE_FILE = 'chronicle.sqlite';\n\n/** Marker written once the legacy JSONL partitions have been imported. */\nexport const LEGACY_JSONL_MIGRATION_KEY = 'legacy-jsonl-v1';\n\n/** Day families the import refused to move, recorded so they are never retried silently. */\nexport const LEGACY_JSONL_QUARANTINE_KEY = 'legacy-jsonl-v1:quarantine';\n\nconst SCHEMA_VERSION = 1;\n\nexport interface ChronicleSqliteJournalOptions {\n /** Directory holding the journal, i.e. `<projectDir>/chronicle`. */\n directory: string;\n now?: (() => Date) | undefined;\n monotonicNow?: (() => bigint) | undefined;\n idFactory?: (() => string) | undefined;\n}\n\nexport interface ChronicleSqlitePurgeOptions {\n retentionDays: number;\n dryRun?: boolean | undefined;\n}\n\ninterface ChainAnchor {\n sequence: number;\n hash: string;\n}\n\n/** A day family the import refused to move, and why. */\nexport interface ChronicleQuarantinedFamily {\n day: string;\n sequence: number;\n reason: string;\n}\n\n/** Write surface handed to a legacy import; see {@link ChronicleSqliteJournal.runFamilyImport}. */\nexport interface ChronicleImportSink {\n /**\n * Store an event with its recorded `sequence`, `previousHash` and `hash`.\n *\n * The payload is re-serialized rather than copied byte-for-byte from the\n * JSONL line, which is safe because the hash preimage is the *canonical*\n * encoding derived from the parsed event (\u00A73.1 of the spec) \u2014 not the stored\n * bytes. `JSON.parse` round-trips it exactly, so verification is unaffected.\n */\n insert(day: string, event: ChronicleEvent): void;\n /** Carry a legacy day-family retention checkpoint over. */\n checkpoint(day: string, sequence: number, hash: string): void;\n}\n\n// \u2500\u2500\u2500 node:sqlite lazy loader (mirrors metrics-store.ts) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nlet Ctor: typeof DatabaseSync | null | undefined;\n\nfunction loadDatabaseSync(): typeof DatabaseSync {\n if (Ctor) return Ctor;\n if (Ctor === null) throw new Error('node:sqlite is unavailable in this runtime');\n try {\n Ctor = withSqliteExperimentalWarningSuppressed(\n () =>\n (createRequire(import.meta.url)('node:sqlite') as typeof import('node:sqlite')).DatabaseSync,\n );\n return Ctor;\n } catch (error) {\n Ctor = null;\n throw new Error(\n \"The Chronicle journal needs Node's built-in SQLite (node:sqlite, Node >= 22.5): \" +\n (error instanceof Error ? error.message : String(error)),\n );\n }\n}\n\n// \u2500\u2500\u2500 Store \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class ChronicleSqliteJournal {\n private readonly db: DatabaseSync;\n private readonly dbPath: string;\n private readonly now: () => Date;\n private readonly monotonicNow: () => bigint;\n private readonly idFactory: () => string;\n\n /**\n * Cached chain head per day. Cleared wholesale on any write failure so the\n * next append rebuilds from the database rather than trusting a counter that\n * may have advanced past what actually committed.\n */\n private readonly anchors = new Map<string, ChainAnchor>();\n\n private readonly counters = {\n acceptedEvents: 0,\n persistedEvents: 0,\n rejectedEvents: 0,\n failedEvents: 0,\n batches: 0,\n maxObservedPending: 0,\n largestBatch: 0,\n };\n private lastBatchDurationMs: number | undefined;\n\n constructor(options: ChronicleSqliteJournalOptions) {\n this.dbPath = path.join(path.resolve(options.directory), CHRONICLE_SQLITE_FILE);\n this.now = options.now ?? (() => new Date());\n this.monotonicNow = options.monotonicNow ?? (() => process.hrtime.bigint());\n this.idFactory = options.idFactory ?? (() => randomUUID());\n const Database = loadDatabaseSync();\n this.db = new Database(this.dbPath);\n this.db.exec('PRAGMA journal_mode = WAL');\n this.ensureSchema();\n }\n\n close(): void {\n this.db.close();\n }\n\n stats(): ChronicleJournalStats {\n return {\n ...this.counters,\n pendingEvents: 0,\n // Retained at zero for wire compatibility: partitions do not exist here,\n // but `ChronicleJournalStats` is part of the IPC health payload.\n partitionRolls: 0,\n ...(this.lastBatchDurationMs !== undefined\n ? { lastBatchDurationMs: this.lastBatchDurationMs }\n : {}),\n };\n }\n\n /**\n * Writes are synchronous and transactional, so there is nothing buffered to\n * flush. Kept to satisfy `ChronicleEventSink`.\n */\n async flush(): Promise<void> {\n return Promise.resolve();\n }\n\n async append(input: ChronicleEventInput): Promise<ChronicleEvent> {\n const [event] = await this.appendBatch([input]);\n // appendBatch either returns one event per input or throws.\n return event as ChronicleEvent;\n }\n\n /**\n * Append a batch as one transaction.\n *\n * The chain is computed in memory from a single anchor, so a partially\n * applied batch would leave a hole in `sequence` that verification can never\n * reconcile. Rollback plus anchor invalidation is what prevents that.\n */\n async appendBatch(inputs: readonly ChronicleEventInput[]): Promise<ChronicleEvent[]> {\n if (inputs.length === 0) return [];\n const started = performance.now();\n this.counters.acceptedEvents += inputs.length;\n this.counters.batches += 1;\n this.counters.largestBatch = Math.max(this.counters.largestBatch, inputs.length);\n\n const instant = this.now().toISOString();\n // The chain scope is the wall-clock day of the append, matching the file\n // `journalForToday()` would have opened \u2014 not the event's `occurredAt`,\n // which a caller may back-date.\n const day = instant.slice(0, 10);\n const events: ChronicleEvent[] = [];\n let previous = this.readAnchor(day);\n\n for (const input of inputs) {\n const unhashed = {\n ...input,\n occurredAt: input.occurredAt ?? instant,\n monotonicNs: input.monotonicNs ?? this.monotonicNow().toString(),\n schemaVersion: CHRONICLE_SCHEMA_VERSION,\n eventId: this.idFactory(),\n observedAt: instant,\n persistedAt: instant,\n sequence: previous.sequence + 1,\n previousHash: previous.hash,\n };\n const event: ChronicleEvent = { ...unhashed, hash: hashValue(unhashed) };\n events.push(event);\n previous = { sequence: event.sequence, hash: event.hash };\n }\n\n try {\n this.db.exec('BEGIN IMMEDIATE');\n const insert = this.db.prepare(\n `INSERT INTO events (\n day, sequence, event_id, hash, previous_hash, occurred_at, event_type, outcome,\n project_id, session_id, agent_id, task_id, trace_id, logical_request_id,\n resource_kind, resource_id, resource_path, duration_ns, payload\n ) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`,\n );\n for (const event of events) {\n const row = projectEvent(event);\n insert.run(\n day,\n event.sequence,\n event.eventId,\n event.hash,\n event.previousHash,\n row.occurredAt,\n event.eventType,\n row.outcome,\n row.projectId,\n row.sessionId,\n row.agentId,\n row.taskId,\n row.traceId,\n row.logicalRequestId,\n row.resourceKind,\n row.resourceId,\n row.resourcePath,\n row.durationNs,\n JSON.stringify(event),\n );\n }\n this.db.exec('COMMIT');\n } catch (error) {\n try {\n this.db.exec('ROLLBACK');\n } catch {\n // A failed BEGIN leaves no transaction to roll back.\n }\n this.anchors.clear();\n this.counters.failedEvents += inputs.length;\n this.lastBatchDurationMs = performance.now() - started;\n throw error;\n }\n\n this.anchors.set(day, previous);\n this.counters.persistedEvents += events.length;\n this.lastBatchDurationMs = performance.now() - started;\n return events;\n }\n\n async readAll(): Promise<ChronicleEvent[]> {\n const rows = this.db\n .prepare('SELECT payload FROM events ORDER BY day, sequence')\n .all() as Array<{ payload: string }>;\n return rows.map((row) => JSON.parse(row.payload) as ChronicleEvent);\n }\n\n /**\n * Walk every chain and prove none has been edited.\n *\n * Chronicle chains are scoped to a day, not to the journal: the JSONL writer\n * anchors each `<day>.events.jsonl` family at `GENESIS_HASH` independently,\n * so `sequence` restarts at 1 every day. Verification mirrors that \u2014 each day\n * is validated on its own, and a break in one does not implicate the others.\n *\n * Three independent properties per day, because each catches a different\n * failure: a dense `sequence` catches deletions from the middle, the\n * `previousHash` link catches reordering, and re-hashing the payload catches\n * an in-place edit that left the links intact.\n */\n async verify(): Promise<ChronicleVerifyResult> {\n let entries = 0;\n let lastSequence = 0;\n let lastHash = GENESIS_HASH;\n\n for (const day of this.days()) {\n const checkpoint = this.readCheckpoint(day);\n let expectedSequence = (checkpoint?.sequence ?? 0) + 1;\n let previousHash = checkpoint?.hash ?? GENESIS_HASH;\n\n const rows = this.db\n .prepare(\n 'SELECT sequence, hash, previous_hash, payload FROM events WHERE day = ? ORDER BY sequence',\n )\n .all(day) as Array<{\n sequence: number;\n hash: string;\n previous_hash: string;\n payload: string;\n }>;\n\n for (const row of rows) {\n if (row.sequence !== expectedSequence) {\n return {\n ok: false,\n entries,\n brokenAt: entries,\n reason: `sequence gap in ${day}: expected ${expectedSequence}, found ${row.sequence}`,\n };\n }\n if (row.previous_hash !== previousHash) {\n return { ok: false, entries, brokenAt: entries, reason: 'previous hash mismatch' };\n }\n let event: ChronicleEvent;\n try {\n event = JSON.parse(row.payload) as ChronicleEvent;\n } catch {\n return { ok: false, entries, brokenAt: entries, reason: 'invalid payload JSON' };\n }\n if (chronicleEventHash(event) !== row.hash) {\n return { ok: false, entries, brokenAt: entries, reason: 'entry hash mismatch' };\n }\n entries += 1;\n expectedSequence = row.sequence + 1;\n previousHash = row.hash;\n }\n\n lastSequence = expectedSequence - 1;\n lastHash = previousHash;\n }\n\n return { ok: true, entries, lastSequence, lastHash };\n }\n\n /**\n * Drop events older than the retention window.\n *\n * Retention is day-granular and chains are day-scoped, so a purge removes\n * whole chains rather than truncating one. That is why nothing needs to be\n * checkpointed here: there is no surviving suffix left dangling without an\n * anchor. Any checkpoint imported from a partially-purged legacy day family\n * is dropped alongside its events.\n */\n async purge(options: ChronicleSqlitePurgeOptions): Promise<ChroniclePurgeResult> {\n const empty: ChroniclePurgeResult = {\n deletedCount: 0,\n deletedBytes: 0,\n skippedCount: 0,\n errors: [],\n };\n if (!Number.isFinite(options.retentionDays) || options.retentionDays <= 0) return empty;\n\n const cutoff = new Date(this.now().getTime() - options.retentionDays * 86_400_000)\n .toISOString()\n .slice(0, 10);\n\n const count = (\n this.db.prepare('SELECT COUNT(*) AS n FROM events WHERE day < ?').get(cutoff) as {\n n: number;\n }\n ).n;\n if (count === 0) return empty;\n\n if (options.dryRun) {\n const days = this.db\n .prepare('SELECT DISTINCT day FROM events WHERE day < ? ORDER BY day')\n .all(cutoff) as Array<{ day: string }>;\n return { ...empty, deletedCount: count, candidates: days.map((row) => row.day) };\n }\n\n try {\n this.db.exec('BEGIN IMMEDIATE');\n this.db.prepare('DELETE FROM events WHERE day < ?').run(cutoff);\n this.db.prepare('DELETE FROM chain_checkpoint WHERE day < ?').run(cutoff);\n this.db.exec('COMMIT');\n } catch (error) {\n try {\n this.db.exec('ROLLBACK');\n } catch {\n // Nothing to unwind.\n }\n return {\n ...empty,\n errors: [\n {\n file: this.dbPath,\n reason: error instanceof Error ? error.message : String(error),\n },\n ],\n };\n }\n\n this.anchors.clear();\n return { ...empty, deletedCount: count };\n }\n\n /**\n * Run one day family's legacy import inside its own transaction.\n *\n * Deliberately separate from `appendBatch`: the append path *computes*\n * `sequence`, `previousHash` and `hash`, while an import must carry them over\n * untouched. Fusing the two would put a code path one refactor away from\n * re-hashing historical events, which is the one change that silently\n * destroys their tamper evidence.\n *\n * The transaction is scoped to a single family because chains are: `sequence`\n * restarts at 1 each day, so one day's break says nothing about the next\n * day's integrity. A whole-journal transaction made every future day hostage\n * to the worst day on disk \u2014 one corrupt family and the daemon could never\n * open its store again. The family is still all-or-nothing: a break rolls\n * back that day entirely, so no partial chain is ever visible.\n */\n async runFamilyImport(load: (sink: ChronicleImportSink) => Promise<void>): Promise<void> {\n const insert = this.db.prepare(\n `INSERT INTO events (\n day, sequence, event_id, hash, previous_hash, occurred_at, event_type, outcome,\n project_id, session_id, agent_id, task_id, trace_id, logical_request_id,\n resource_kind, resource_id, resource_path, duration_ns, payload\n ) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`,\n );\n const checkpoint = this.db.prepare(\n `INSERT INTO chain_checkpoint (day, sequence, hash) VALUES (?, ?, ?)\n ON CONFLICT(day) DO UPDATE SET sequence = excluded.sequence, hash = excluded.hash`,\n );\n\n this.db.exec('BEGIN IMMEDIATE');\n try {\n await load({\n insert: (day, event) => {\n const row = projectEvent(event);\n insert.run(\n day,\n event.sequence,\n event.eventId,\n event.hash,\n event.previousHash,\n row.occurredAt,\n event.eventType,\n row.outcome,\n row.projectId,\n row.sessionId,\n row.agentId,\n row.taskId,\n row.traceId,\n row.logicalRequestId,\n row.resourceKind,\n row.resourceId,\n row.resourcePath,\n row.durationNs,\n JSON.stringify(event),\n );\n },\n checkpoint: (day, sequence, hash) => {\n checkpoint.run(day, sequence, hash);\n },\n });\n this.db.exec('COMMIT');\n } catch (error) {\n try {\n this.db.exec('ROLLBACK');\n } catch {\n // Nothing to unwind.\n }\n throw error;\n } finally {\n this.anchors.clear();\n }\n }\n\n /**\n * A read engine over this journal's own connection.\n *\n * Sharing the connection rather than opening a second one keeps the\n * single-writer guarantee intact and means a reader can never observe a\n * half-applied batch: SQLite serialises statements on one handle.\n */\n queryEngine(options?: ChronicleSqliteQueryEngineOptions): ChronicleSqliteQueryEngine {\n return new ChronicleSqliteQueryEngine(this.db, options);\n }\n\n /** Has the legacy JSONL import already run? */\n hasImportedLegacyJournal(): boolean {\n return this.readMeta(LEGACY_JSONL_MIGRATION_KEY) !== undefined;\n }\n\n markLegacyJournalImported(): void {\n this.db\n .prepare(\n `INSERT INTO chronicle_meta (key, value) VALUES (?, 'done')\n ON CONFLICT(key) DO UPDATE SET value = 'done'`,\n )\n .run(LEGACY_JSONL_MIGRATION_KEY);\n }\n\n /**\n * Record the day families the import refused to move.\n *\n * Persisted rather than merely logged because the import runs once: after the\n * marker is set nothing re-reads the JSONL, so this row is the only surviving\n * evidence that a day was dropped. Health reports read it back to say\n * \"degraded, and here is exactly what is missing\" instead of quietly serving\n * a journal with a hole in it.\n */\n recordQuarantinedFamilies(families: readonly ChronicleQuarantinedFamily[]): void {\n if (families.length === 0) return;\n this.db\n .prepare(\n `INSERT INTO chronicle_meta (key, value) VALUES (?, ?)\n ON CONFLICT(key) DO UPDATE SET value = excluded.value`,\n )\n .run(LEGACY_JSONL_QUARANTINE_KEY, JSON.stringify(families));\n }\n\n /**\n * Does this day already hold rows?\n *\n * Each family commits on its own, so an import interrupted between families\n * leaves a database that is complete for the days it reached. `(day,\n * sequence)` is the primary key, so re-inserting one of those days would\n * abort on a constraint violation rather than start over \u2014 this is what lets\n * the next run resume at the first day it never got to.\n */\n hasImportedDay(day: string): boolean {\n const row = this.db.prepare('SELECT 1 AS present FROM events WHERE day = ? LIMIT 1').get(day) as\n | { present: number }\n | undefined;\n return row !== undefined;\n }\n\n /** Day families the legacy import refused to move, oldest first. */\n quarantinedFamilies(): ChronicleQuarantinedFamily[] {\n const raw = this.readMeta(LEGACY_JSONL_QUARANTINE_KEY);\n if (!raw) return [];\n try {\n const parsed: unknown = JSON.parse(raw);\n return Array.isArray(parsed) ? (parsed as ChronicleQuarantinedFamily[]) : [];\n } catch {\n return [];\n }\n }\n\n // \u2500\u2500\u2500 internals \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n private readMeta(key: string): string | undefined {\n const row = this.db.prepare('SELECT value FROM chronicle_meta WHERE key = ?').get(key) as\n | { value: string }\n | undefined;\n return row?.value;\n }\n\n private readCheckpoint(day: string): ChainAnchor | undefined {\n return this.db.prepare('SELECT sequence, hash FROM chain_checkpoint WHERE day = ?').get(day) as\n | ChainAnchor\n | undefined;\n }\n\n /** Days that currently hold at least one event, oldest first. */\n private days(): string[] {\n const rows = this.db.prepare('SELECT DISTINCT day FROM events ORDER BY day').all() as Array<{\n day: string;\n }>;\n return rows.map((row) => row.day);\n }\n\n /**\n * Resolve the chain head, in the same precedence the JSONL journal uses: the\n * newest event, else the retention checkpoint (every event before it was\n * purged), else genesis.\n */\n private readAnchor(day: string): ChainAnchor {\n const cached = this.anchors.get(day);\n if (cached) return cached;\n const last = this.db\n .prepare('SELECT sequence, hash FROM events WHERE day = ? ORDER BY sequence DESC LIMIT 1')\n .get(day) as ChainAnchor | undefined;\n const anchor = last ?? this.readCheckpoint(day) ?? { sequence: 0, hash: GENESIS_HASH };\n this.anchors.set(day, anchor);\n return anchor;\n }\n\n private ensureSchema(): void {\n const version = (this.db.prepare('PRAGMA user_version').get() as { user_version: number })\n .user_version;\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS events (\n day TEXT NOT NULL,\n sequence INTEGER NOT NULL,\n event_id TEXT NOT NULL UNIQUE,\n hash TEXT NOT NULL,\n previous_hash TEXT NOT NULL,\n occurred_at TEXT NOT NULL,\n event_type TEXT NOT NULL,\n outcome TEXT,\n project_id TEXT,\n session_id TEXT,\n agent_id TEXT,\n task_id TEXT,\n trace_id TEXT,\n logical_request_id TEXT,\n resource_kind TEXT,\n resource_id TEXT,\n resource_path TEXT,\n duration_ns TEXT,\n payload TEXT NOT NULL,\n PRIMARY KEY (day, sequence)\n );\n CREATE INDEX IF NOT EXISTS events_occurred_at ON events(occurred_at);\n CREATE INDEX IF NOT EXISTS events_type_outcome ON events(event_type, outcome);\n CREATE INDEX IF NOT EXISTS events_session ON events(session_id, day, sequence);\n CREATE INDEX IF NOT EXISTS events_trace ON events(trace_id);\n CREATE INDEX IF NOT EXISTS events_logical_request ON events(logical_request_id);\n CREATE INDEX IF NOT EXISTS events_resource_path ON events(resource_path);\n\n CREATE TABLE IF NOT EXISTS chain_checkpoint (\n day TEXT PRIMARY KEY,\n sequence INTEGER NOT NULL,\n hash TEXT NOT NULL\n );\n\n CREATE TABLE IF NOT EXISTS chronicle_meta (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n );\n `);\n if (version !== SCHEMA_VERSION) {\n this.db.exec(`PRAGMA user_version = ${SCHEMA_VERSION}`);\n }\n }\n}\n\ninterface ProjectedRow {\n occurredAt: string;\n outcome: string | null;\n projectId: string | null;\n sessionId: string | null;\n agentId: string | null;\n taskId: string | null;\n traceId: string | null;\n logicalRequestId: string | null;\n resourceKind: string | null;\n resourceId: string | null;\n resourcePath: string | null;\n durationNs: string | null;\n}\n\n/**\n * Derive the indexed columns from an event.\n *\n * Every value here is recoverable from `payload`; nothing is stored only in a\n * column. That is what lets the projection change in a later release without\n * touching a single stored hash.\n *\n * `day` is deliberately absent: it is the chain scope, not a projection. The\n * legacy writer picks it from the wall clock when the batch is appended (see\n * `journalForToday`), so an event carrying a back-dated `occurredAt` still\n * belongs to the chain of the day it was written on.\n */\nfunction projectEvent(event: ChronicleEvent): ProjectedRow {\n const occurredAt = event.occurredAt ?? event.observedAt;\n return {\n occurredAt,\n outcome: event.outcome ?? null,\n projectId: event.scope.projectId ?? null,\n sessionId: event.scope.sessionId ?? null,\n agentId: event.scope.agentId ?? null,\n taskId: event.scope.taskId ?? null,\n traceId: event.correlation?.traceId ?? null,\n logicalRequestId: event.correlation?.logicalRequestId ?? null,\n resourceKind: event.resource?.kind ?? null,\n resourceId: event.resource?.id ?? null,\n resourcePath: event.resource?.path ?? null,\n durationNs: event.durationNs ?? null,\n };\n}\n", "export * from './assert-never.js';\nexport * from './atomic-write.js';\nexport * from './child-env.js';\nexport * from './color.js';\nexport * from './config-backup.js';\nexport { checkConnectivity, resetConnectivityCache } from './connectivity.js';\nexport { deriveCachePrefixKey } from './cache-key.js';\nexport * from './config-json.js';\nexport { type ContextBreakdown, getContextBreakdown } from './context-breakdown.js';\nexport {\n buildCompletedWorkLedgerBlock,\n buildContextEvidenceDigest,\n COMPLETED_WORK_LEDGER_MARKER,\n createContextEvidenceState,\n formatCompletedWorkLedger,\n markAssistantReferencedEvidence,\n type RecordCompletedWorkInput,\n type RecordToolOutputEvidenceInput,\n recordCompletedWorkEvidence,\n recordToolOutputEvidence,\n recordUserIntentEvidence,\n repeatedReadPressure,\n syncCompletedWorkLedgerBlock,\n} from './context-evidence.js';\nexport {\n type DeepMergeOptions,\n deepMerge,\n FORBIDDEN_PROTO_KEYS,\n isPrimitiveArray,\n} from './deep-merge.js';\nexport * from './diff.js';\nexport type { HttpDispatcher, HttpsAgentAsDispatcher } from './dispatcher-types.js';\nexport { toErrorMessage } from './error.js';\nexport * from './expect-defined.js';\nexport { expandGlob } from './glob-expand.js';\nexport * from './glob-match.js';\nexport {\n buildUserContentBlocks,\n IncomingImageError,\n type IncomingImagePayload,\n MAX_INCOMING_IMAGE_BYTES,\n MAX_INCOMING_IMAGES,\n parseIncomingImages,\n} from './incoming-images.js';\nexport { assertNotPrivateHost, expandIPv6, isPrivateIPv4, isPrivateIPv6 } from './ip-guard.js';\nexport { readBundledInstructionText, renderInstructionTemplate } from './instruction-file.js';\nexport { completePartialObject } from './json-repair.js';\nexport {\n type CoercionResult,\n coerceAgainstSchema,\n type ValidationError,\n type ValidationResult,\n validateAgainstSchema,\n} from './json-schema-validate.js';\nexport { mergeCustomModelDefs } from './merge-custom-models.js';\nexport { mergeModelsPayload } from './merge-models-payload.js';\nexport {\n hasMeaningfulContent,\n type MessageRepairReport,\n type MessageRepairResult,\n repairToolUseAdjacency,\n} from './message-invariants.js';\nexport * from './newline-normalize.js';\nexport {\n getPerfProfile,\n indexParallelBatchSize,\n isFrugalPerf,\n type PerfProfile,\n sqliteCachePragmas,\n SageCachePragmas,\n tuiStreamFlushMs,\n useDaemonPerfDefaults,\n} from './perf-profile.js';\nexport { isPidAlive } from './pid.js';\nexport * from './project-identity.js';\nexport { type CompileFail, type CompileResult, compileUserRegex } from './regex-guard.js';\nexport * from './safe-json.js';\nexport { sessionScopedPath } from './session-scoped-path.js';\nexport * from './socket-path.js';\nexport { withSqliteExperimentalWarningSuppressed } from './sqlite-warning.js';\nexport * from './sleep.js';\nexport { slugify } from './slug.js';\nexport * from './string.js';\nexport { writeErr, writeOut } from './term.js';\nexport * from './task-format.js';\nexport {\n buildSgrSequence,\n buildTitleSequence,\n type ColorDepth,\n detectTerminal,\n ESCAPE_TERMINATOR,\n type EscapeEmitResult,\n type EscapeSequence,\n type MouseProtocol,\n safeEmit,\n setTitle,\n type TerminalCapability,\n TerminalLifecycle,\n isStdinTTY,\n onResize,\n setOutputLineGuard,\n setRawMode,\n} from './term.js';\nexport * from './todos-format.js';\nexport {\n computeMessageTokens,\n estimateMessageTokens,\n estimateRequestTokens,\n estimateRequestTokensCalibrated,\n estimateTextTokens,\n estimateToolDefTokens,\n estimateToolInputTokens,\n estimateToolResultTokens,\n getCalibrationState,\n type RequestTokenBreakdown,\n recordActualUsage,\n resetCalibration,\n} from './token-estimate.js';\nexport {\n applyToolDescriptionModes,\n applyToolDescriptionModeToTool,\n DEFAULT_TOOL_DESCRIPTION_MODE,\n getToolDescriptionMode,\n normalizeToolDescriptionMode,\n resolveToolDescriptionMode,\n setToolDescriptionMode,\n simplifyToolDescription,\n type ToolDescriptionRegistryLike,\n} from './tool-description-mode.js';\nexport {\n createToolOutputSerializer,\n type ToolOutputSerializerOptions,\n} from './tool-output-serializer.js';\nexport {\n applyToolResultRenderModes,\n DEFAULT_TOOL_RESULT_RENDER_MODE,\n getToolResultRenderMode,\n normalizeToolResultRenderMode,\n resolveToolResultRenderMode,\n setToolResultRenderMode,\n type ToolResultRenderModeRegistryLike,\n} from './tool-result-render-mode.js';\nexport * from './tool-subject.js';\nexport {\n mcpQualifiedToolName,\n mcpServerToolPrefix,\n sanitizeWireToolName,\n WIRE_TOOL_NAME_MAX_LENGTH,\n WIRE_TOOL_NAME_PATTERN,\n} from './tool-name.js';\nexport {\n type CompactToolDefinitionForWireOptions,\n type CompactWireToolDefinition,\n compactSchemaDescriptions,\n compactToolDefinitionForWire,\n normalizeTopLevelToolSchema,\n type ToolWireDefinitionLike,\n} from './tool-wire-compact.js';\nexport { isUlid, ulid } from './ulid.js';\nexport {\n type ProjectWatchEvent,\n type ProjectWatchSubscription,\n watchProjectTree,\n} from './project-watch.js';\nexport { DEFAULT_WALK_IGNORE_DIRS, DEFAULT_WALK_IGNORE_SET } from './walk-ignore.js';\nexport * from './wstack-paths.js';\nexport {\n type HeapDiagnosticFields,\n type HeapDiagnosticValue,\n type HeapSample,\n type HeapWatchdogOptions,\n startSharedHeapWatchdog,\n startHeapWatchdog,\n takeHeapSample,\n defaultHeapLogPath,\n} from './heap-watchdog.js';\n", "/**\n * TTY detection helpers \u2014 the single source of truth for \"is this process\n * running against a real terminal?\". Replaces ad-hoc `process.stdin.isTTY`\n * / `process.stdout.isTTY` checks scattered across the codebase so that:\n *\n * 1. test code can mock a single module instead of stubbing `isTTY` on\n * every ReadStream/WriteStream the test happens to touch;\n * 2. a future TTY-detection source (an env var override, a Windows\n * ConPTY workaround, \u2026) lands in one place;\n * 3. `isInteractive()` encodes the rule the project already used inline\n * (\"both streams are TTYs AND we're not running under CI\") in one\n * testable helper instead of the same 3-condition check in two\n * different files.\n *\n * Scope: detection only. Raw-mode control (`setRawMode`), resize\n * subscriptions, and write-injection belong to a future, larger TTY\n * abstraction; this module is the smallest pull that gives us a\n * testable seam and dedups 20+ call sites.\n */\n\nconst hasStdout = (): boolean => typeof process !== 'undefined' && !!process.stdout;\nconst hasStdin = (): boolean => typeof process !== 'undefined' && !!process.stdin;\n\n/** True when `process.stdout` is attached to a terminal (not a pipe/file). */\nexport function isStdoutTTY(): boolean {\n return hasStdout() && Boolean(process.stdout.isTTY);\n}\n\n/** True when `process.stdin` is attached to a terminal (not a pipe/file). */\nexport function isStdinTTY(): boolean {\n return hasStdin() && Boolean(process.stdin.isTTY);\n}\n\n/**\n * True when the current process is an interactive session: both stdin and\n * stdout are TTYs. Callers that also need a \"not a single-shot invocation\"\n * or \"not under CI\" check should layer that on top \u2014 keeping this helper\n * minimal preserves the original inline checks it replaces.\n */\nexport function isInteractive(): boolean {\n return isStdinTTY() && isStdoutTTY();\n}\n\n/** Current terminal size in characters, with a 24\u00D780 fallback for non-TTYs. */\nexport function getTermSize(): { rows: number; cols: number } {\n if (!hasStdout()) return { rows: 24, cols: 80 };\n return {\n rows: process.stdout.rows ?? 24,\n cols: process.stdout.columns ?? 80,\n };\n}\n\n/**\n * Subscribe to terminal resize events. `cb` is called with the new size each\n * time the underlying stream emits `resize`. Returns a cleanup function the\n * caller MUST call on dispose to remove the listener \u2014 leaving a stale\n * `resize` listener on a disposed component leaks the closure (and the\n * component itself, transitively) until the process exits.\n *\n * The stream argument defaults to `process.stdout`. Pass an explicit\n * `NodeJS.WriteStream` when the caller already owns one (e.g. a status line\n * that targets an injected `out` for testability). For non-TTY streams no\n * listener is registered and the returned cleanup is a no-op.\n */\nexport function onResize(\n cb: (size: { rows: number; cols: number }) => void,\n stream: NodeJS.WriteStream = process.stdout,\n): () => void {\n if (!stream || typeof stream.on !== 'function') return () => {};\n const handler = (): void => {\n cb({\n rows: stream.rows ?? 24,\n cols: stream.columns ?? 80,\n });\n };\n stream.on('resize', handler);\n return () => {\n stream.off('resize', handler);\n };\n}\n\n/**\n * Toggle raw mode on a TTY stdin stream. Returns `true` when the toggle was\n * applied, `false` when the stream is null, not a TTY, or doesn't expose\n * `setRawMode` (pipes, file descriptors, Windows ConPTY edge cases). Callers\n * that need to restore the previous mode should snapshot `input.isRaw`\n * BEFORE the call and pass the value to a second call to flip back.\n *\n * Use this helper to drop the now-redundant\n * `if (input.isTTY) input.setRawMode(...)` ceremony at every call site.\n */\nexport function setRawMode(input: NodeJS.ReadStream, mode: boolean): boolean {\n if (input?.isTTY !== true) return false;\n if (typeof input.setRawMode !== 'function') return false;\n input.setRawMode(mode);\n return true;\n}\n\n/**\n * Bracket installed by the interactive input reader while a `readline`\n * prompt is on screen. Out-of-band terminal writes \u2014 logger WARN/INFO\n * lines, async activity from the Telegram bridge, etc. \u2014 go to the same\n * physical terminal as the half-typed prompt but readline has no idea they\n * happened, so it never repaints. The result is the classic corruption the\n * user sees: every async line strands the in-progress draft as a fresh\n * scrollback row (sometimes with its cursor underline).\n *\n * The guard closes that gap. `suspend()` wipes the draft row so the message\n * prints clean; `resume()` repaints the prompt + draft (cursor preserved).\n * When no prompt is active the guard is `null` and writes pass straight\n * through \u2014 so agent-turn output (spinner, renderer) is untouched.\n */\nexport interface OutputLineGuard {\n /** Clear the current input row right before an out-of-band write. */\n suspend(): void;\n /** Repaint the prompt + in-progress draft right after the write. */\n resume(): void;\n}\n\nlet activeOutputGuard: OutputLineGuard | null = null;\n\n/**\n * Register (or clear, with `null`) the guard that brackets out-of-band\n * writes. Installed by {@link writeOut}/{@link writeErr} consumers \u2014 in\n * practice the CLI's readline input reader \u2014 only while a prompt is live.\n * Idempotent; the most recent caller wins.\n */\nexport function setOutputLineGuard(guard: OutputLineGuard | null): void {\n activeOutputGuard = guard;\n}\n\n/**\n * Stream-agnostic write primitive. Returns `false` when the stream is\n * missing or doesn't expose `write` so callers can degrade silently under\n * hostile host environments (closed pipe, mock injects `null`, test\n * replaces the stream with a stub).\n *\n * When an {@link OutputLineGuard} is installed (a readline prompt is on\n * screen) the write is bracketed by `suspend()`/`resume()` so the user's\n * half-typed input survives the interruption instead of being stranded in\n * scrollback. The guard's own redraw uses raw stream writes \u2014 never\n * `writeOut`/`writeErr` \u2014 so there is no re-entrancy here.\n *\n * **Not exported in the public API.** Exposed only inside `term.ts` for\n * `writeOut` / `writeErr` to share a single implementation. If a caller\n * needs to write to an arbitrary stream, they should call `writeOut` (or\n * `writeErr`) with an explicit `stream` argument \u2014 the named functions\n * are the public surface so the \"this is the standard error stream\"\n * intent stays visible at every call site.\n */\nfunction writeTo(\n s: string,\n stream: NodeJS.WriteStream | undefined,\n): boolean {\n if (!stream || typeof stream.write !== 'function') return false;\n const guard = activeOutputGuard;\n if (!guard) {\n stream.write(s);\n return true;\n }\n // A prompt is live \u2014 wipe the draft row, emit the message, repaint.\n guard.suspend();\n stream.write(s);\n guard.resume();\n return true;\n}\n\n/**\n * Write `s` to `stream` (defaults to `process.stdout`). Returns `false`\n * when the stream is missing or doesn't expose `write` so callers can\n * degrade silently under hostile host environments (closed pipe, mock\n * injects `null`, test replaces the stream with a stub).\n *\n * Why a helper:\n * 1. **Single seam for output capture in tests** \u2014 stub `writeOut` once\n * and assert on what the rest of the codebase intended to print,\n * without spying on `process.stdout.write` (which is brittle and\n * leaks across parallel test files).\n * 2. **Stream swap without grep** \u2014 routing the CLI's output to a\n * logger or `out.log` becomes a one-line change at process boot.\n * 3. **Defensive default** \u2014 closes the \"what if `process.stdout` is\n * `null`\" gap that currently exists at ~50 call sites that just\n * call `process.stdout.write(s)` and crash on certain Windows\n * redirect invocations.\n *\n * Call-site migration is staged: this commit introduces the helper, a\n * follow-up commit replaces the 50+ `process.stdout.write(...)` sites\n * with `writeOut(...)`. Until that migration lands, both forms coexist\n * and `writeOut` is the preferred form for new code.\n */\nexport function writeOut(\n s: string,\n stream: NodeJS.WriteStream = process.stdout,\n): boolean {\n return writeTo(s, stream);\n}\n\n/**\n * Symmetric partner of `writeOut` for the standard error stream. Same shape,\n * same defensive contract, same single-seam-for-tests story \u2014 just defaults to\n * `process.stderr` instead of `process.stdout`.\n *\n * Use this in code paths that emit error/diagnostic/warning text. Keeping\n * these two helpers split (rather than a single `writeTo(s, stream)`) means\n * the call site reads as a clear intent signal: \"I am writing an error\" vs.\n * \"I am writing a result\" \u2014 which matters for callers that decide between\n * stdout/stderr routing (e.g. `--quiet` flags, log-level filtering,\n * structured-log rewriters that fork on stream).\n *\n * Stderr writes from the core logger (see `infrastructure/logger.ts`) and from\n * the TUI guard (see `tui/run-tui.ts`) used to call `process.stderr.write`\n * directly. Routing them through this helper lets tests stub the stream at\n * one boundary and lets future logging middleware (e.g. a JSON-line rewriter)\n * swap the destination for the entire process in one place.\n */\nexport function writeErr(\n s: string,\n stream: NodeJS.WriteStream = process.stderr,\n): boolean {\n return writeTo(s, stream);\n}\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// TerminalCapability \u2014 startup capability profile\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Color depth the terminal can render.\n *\n * 0 = no color (dumb, redirected, `TERM=dumb`)\n * 1 = 16 colors (basic ANSI)\n * 2 = 256 colors (ANSI 256 + bright variants)\n * 3 = 16.7M / 24-bit truecolor\n */\nexport type ColorDepth = 0 | 1 | 2 | 3;\n\n/**\n * Mouse tracking protocol the terminal speaks.\n *\n * 'none' \u2014 no mouse reporting\n * 'x10' \u2014 basic button press/release, capped at 223 columns\n * 'urxvt'\u2014 URXVT extension, supports >223 cols\n * 'sgr' \u2014 SGR extended mode, modern standard, no column cap\n */\nexport type MouseProtocol = 'none' | 'x10' | 'urxvt' | 'sgr';\n\n/**\n * A snapshot of the terminal's capabilities and identity, computed once at\n * startup. Call {@link detectTerminal} once and pass the result through your\n * app \u2014 never re-detect mid-session.\n *\n * Query once \u2192 adapt once. Re-querying on every render is wrong because\n * `$TERM` is static for the process lifetime and stdout.isTTY can only go\n * from true\u2192false (never the reverse), so a mid-session change means the\n * process was started in a terminal and then something went wrong.\n */\nexport interface TerminalCapability {\n /** True when both stdin and stdout are attached to a terminal. */\n isRealTTY: boolean;\n /**\n * Whether the terminal speaks color.\n *\n * Uses the industry-standard precedence:\n * `FORCE_COLOR=0` \u2192 0 (disabled)\n * `FORCE_COLOR` \u2192 3 (force truecolor)\n * `NO_COLOR=\u2026` \u2192 0 (opted out)\n * `COLORTERM=truecolor|24bit` \u2192 3\n * `TERM=\u2026truecolor|24bit` \u2192 3 (some emulators advertise it)\n * `TERM=\u2026256color` \u2192 2\n * fallback \u2192 1\n *\n * Note: `TERM=dumb` always produces 0 even if `COLORTERM=truecolor` is set \u2014\n * `dumb` terminals are non-interactive by definition.\n */\n colorDepth: ColorDepth;\n /**\n * Whether `stdout` can be written to. Determined once at startup from\n * `stdout?.isTTY ?? false`. Even when `isRealTTY` is true, `stdout` may be\n * writable=false (e.g. the terminal was closed mid-session).\n */\n stdoutWritable: boolean;\n /**\n * Best mouse protocol the terminal speaks. Progressive enhancement:\n * attempt SGR first, fall back to URXVT, then X10, then 'none'.\n *\n * The caller (typically the App component) decides whether to enable\n * tracking at all \u2014 this only reports what the terminal CAN understand.\n */\n mouseProtocol: MouseProtocol;\n /**\n * Whether the terminal title can be set via OSC 0 / OSC 2.\n * True when stdout is a TTY and `$TERM` is not `dumb`.\n */\n canSetTitle: boolean;\n /**\n * Whether the terminal understands the tmux DCS passthrough prefix.\n * Detected by seeing `$TERM=tmux*`. When true, escape sequences should be\n * wrapped: `\\x1bPtmux;\\x1b${seq}\\x1b\\\\`.\n */\n isTmux: boolean;\n /**\n * Whether the terminal is on Windows using the legacy conhost backend\n * (cmd.exe, PowerShell non-ConPTY) rather than ConPTY (Windows Terminal,\n * VS Code Integrated Terminal). Used to apply Windows-specific raw-mode\n * handoff logic.\n *\n * Detected by: platform === 'win32' AND `!process.stdout.getColorDepth?.()`\n * (ConPTY exposes color depth; conhost does not). Also false on non-Windows.\n */\n isWindowsConhost: boolean;\n}\n\n/**\n * Parse `process.env.TERM` into a color-depth guess.\n *\n * We intentionally do NOT use the `supports-color` npm package here because\n * (a) it adds a dependency, (b) it resolves at module-import time, and (c) we\n * need to factor in `FORCE_COLOR` / `NO_COLOR` which may be set after import.\n * This pure function is trivial to test and predictable regardless of import\n * order.\n */\nfunction parseColorDepth(env: { FORCE_COLOR?: string; NO_COLOR?: string; COLORTERM?: string; TERM?: string; }): ColorDepth {\n // `FORCE_COLOR=0` is an explicit opt-out, even when `COLORTERM=truecolor`.\n if (env.FORCE_COLOR === '0') return 0;\n // `FORCE_COLOR` with no value or any truthy value forces truecolor.\n if (env.FORCE_COLOR !== undefined) return 3;\n // Explicit user opt-out.\n if (typeof env.NO_COLOR === 'string' && env.NO_COLOR !== '') return 0;\n // Explicit terminal advertisement.\n const colorterm = (env.COLORTERM ?? '').toLowerCase();\n if (colorterm === 'truecolor' || colorterm === '24bit') return 3;\n // TERM strings that advertise rich color.\n const term = (env.TERM ?? '').toLowerCase();\n if (term.includes('truecolor') || term.includes('24bit')) return 3;\n if (term.includes('256color')) return 2;\n // TERM=dumb = no interactive capability at all.\n if (term === 'dumb') return 0;\n // Default to 16-color \u2014 the safest floor. Modern terminals all override this.\n return 1;\n}\n\n/**\n * Detect the best mouse protocol the terminal speaks.\n *\n * Uses the `$TERM` string as a proxy since Node.js has no runtime query for\n * mouse capability (DECSET 1000/1002/1003 responses are not standardized for\n * programmatic use). The approximation is:\n * - `tmux` + `screen` = SGR (they proxy it)\n * - `xterm*`, `rxvt*`, `konsole`, `gnome*` = SGR (post-2013)\n * - `linux`, `vt100`, `dumb` = none\n * - Everything else = URXVT / X10 (try SGR, fall back gracefully in mouse.ts)\n *\n * This is advisory only. The App component gates mouse tracking behind an\n * explicit user/setting opt-in; false positives just mean the tracking enable\n * sequence is ignored harmlessly.\n */\nfunction parseMouseProtocol(term: string): MouseProtocol {\n const t = term.toLowerCase();\n // Terminals that reliably support SGR (1006) mode.\n if (\n t.startsWith('xterm') ||\n t.startsWith('tmux') ||\n t.startsWith('screen') ||\n t.includes('rxvt-unicode') ||\n t.includes('urxvt') ||\n t.includes('konsole') ||\n t.includes('gnome') ||\n t.includes('foot') ||\n t.includes('alacritty') ||\n t.includes('wezterm') ||\n t.includes('kitty') ||\n t.includes('vscode') ||\n t.includes('Apple_Terminal')\n ) {\n return 'sgr';\n }\n // Known mouse-capable but older terminals.\n if (t.startsWith('rxvt') || t.startsWith('linux') || t.includes('Eterm')) {\n return 'urxvt';\n }\n // vt100 / dumb \u2014 no mouse.\n if (t === 'vt100' || t === 'dumb') return 'none';\n // Default: assume SGR is safe to try; mouse.ts falls back silently.\n return 'sgr';\n}\n\n/**\n * Detect the terminal's capabilities and identity at startup.\n *\n * Call once, early in process boot, before any event-loop async has had a\n * chance to corrupt the read of `process.stdout.isTTY`. Store the result and\n * pass it through the app \u2014 do NOT call this on every render.\n *\n * All `env` lookups default gracefully to safe values when the env var is\n * absent or empty, so the return value is deterministic regardless of what\n * the host's environment looks like.\n */\nexport function detectTerminal(\n opts: {\n stdin?: NodeJS.ReadStream | null;\n stdout?: NodeJS.WriteStream | null;\n env?: typeof process.env;\n } = {},\n): TerminalCapability {\n const stdin = opts.stdin ?? process.stdin;\n const stdout = opts.stdout ?? process.stdout;\n const env = opts.env ?? process.env;\n\n const isRealTTY = (stdin?.isTTY ?? false) && (stdout?.isTTY ?? false);\n const stdoutWritable = isRealTTY && typeof stdout?.write === 'function';\n const term = env.TERM ?? '';\n const isTmux = term.toLowerCase().startsWith('tmux');\n const isWindowsConhost = isRealTTY\n && process.platform === 'win32'\n && typeof (stdout as NodeJS.WriteStream & { getColorDepth?: unknown }).getColorDepth !== 'function';\n\n return {\n isRealTTY,\n colorDepth: isRealTTY ? parseColorDepth(env) : 0,\n stdoutWritable,\n mouseProtocol: parseMouseProtocol(term),\n canSetTitle: isRealTTY && term !== 'dumb',\n isTmux,\n isWindowsConhost,\n };\n}\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// TerminalLifecycle \u2014 raw-mode lifecycle manager\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Lifecycle owner for the TTY stdin raw-mode state machine.\n *\n * Raw mode is the most dangerous primitive in TUI code. Getting it wrong leaves\n * the user's terminal in a broken state (line-buffered, no echo) that requires\n * closing and reopening the terminal to recover. This class enforces a strict\n * acquire \u2192 hold \u2192 release lifecycle:\n *\n * - `acquire()` may be called only once (idempotent \u2014 subsequent calls no-op).\n * - `release()` restores the previous mode exactly once.\n * - `release()` is called automatically on process `exit` and `beforeExit`.\n * - Any signal handler (SIGINT, SIGTERM, SIGHUP) that calls `release()` clears\n * its own registration so double-signals don't double-restore.\n *\n * Use this instead of calling `setRawMode()` directly at every call site. The\n * single instance lives at module scope in `run-tui.ts`; components that need\n * to signal \"TUI is shutting down\" call `terminalLifecycle.requestExit()` rather\n * than calling `release()` directly.\n */\nexport class TerminalLifecycle {\n private _active = false;\n\n /**\n * The stdin stream we took raw mode on. Set by `acquire()`; undefined before\n * first call. Used by `release()` and by the ConPTY race-closer in\n * `acquire()`.\n */\n private _stdin: NodeJS.ReadStream | undefined;\n\n /**\n * The `isRaw` snapshot captured before the first `acquire()` call, so\n * `release()` restores to the pre-TUI state rather than blindly disabling\n * raw mode. Null when `acquire()` has never been called.\n */\n private _wasRaw: boolean | null = null;\n\n /**\n * Whether stdin was paused before the TUI took ownership. Readline closes\n * its interface by pausing the shared process stream, so raw mode alone is\n * not enough to make Ink receive bytes during the boot-prompt -> TUI handoff.\n */\n private _wasPaused: boolean | null = null;\n\n /**\n * Request the process to exit. Set the flag, trigger any registered\n * `onRequestExit` callback (typically Ink's `unmount()`), and arm a\n * deadline timer. When the timer fires the process is hard-exited.\n *\n * Safe to call multiple times: subsequent calls no-op after the first.\n */\n requestExit: (exitCode?: number) => void;\n\n /**\n * Callback invoked when `requestExit` is called. Registered by the Ink\n * mount point so unmount() runs before the deadline timer fires.\n */\n onRequestExit: (() => void | Promise<void>) | null = null;\n\n constructor() {\n // Build the requestExit closure here so subclasses / tests can override\n // `requestExit` before calling `acquire()`.\n let exitCode = 0;\n let requested = false;\n this.requestExit = (code = 0) => {\n exitCode = code;\n if (requested) return;\n requested = true;\n // Let the Ink unmount handler run (if registered).\n try {\n this.onRequestExit?.();\n } catch {\n // unmount handler threw \u2014 proceed to hard exit.\n }\n // Hard-exit deadline. `unref()` so the timer doesn't keep the event\n // loop alive if everything else has settled.\n setTimeout(() => process.exit(exitCode), 5_000).unref();\n };\n }\n\n /** True while raw mode is held. */\n get active(): boolean {\n return this._active;\n }\n\n /**\n * Acquire raw mode on `stdin`. Idempotent \u2014 calling twice is safe; only the\n * first call has any effect.\n *\n * On Windows ConPTY, calls `setRawMode` twice: once immediately, then again\n * after the next event-loop tick. This closes the ConPTY race where\n * `readline`'s cleanup (registered before this class is constructed) can\n * restore the original cooked mode after we set raw mode but before Ink's\n * render loop takes over the stdin fd. The double-call ensures the last\n * writer wins.\n *\n * @param stdin - The stdin stream (defaults to `process.stdin`).\n * @returns `true` if raw mode was acquired; `false` if stdin is not a TTY\n * or already shut down.\n */\n acquire(stdin: NodeJS.ReadStream = process.stdin): boolean {\n if (this._active) return false;\n\n // Guard: must be a real TTY, must have setRawMode.\n if (stdin?.isTTY !== true) return false;\n if (typeof stdin.setRawMode !== 'function') return false;\n\n // Snapshot the pre-TUI raw state so release() restores correctly.\n this._wasRaw = stdin.isRaw ?? false;\n this._wasPaused = stdin.isPaused();\n this._stdin = stdin;\n\n stdin.setRawMode(true);\n // A preceding readline prompt normally leaves process.stdin paused.\n // Explicitly start the stream before Ink installs its input listener;\n // otherwise the UI can render perfectly while every key appears dead.\n stdin.resume();\n this._active = true;\n\n // Windows ConPTY double-acquire: schedule a second setRawMode on the next\n // tick so we win the race against readline's \"restore original mode\".\n // Safe on non-Windows (no-op: process.platform !== 'win32').\n if (process.platform === 'win32') {\n setImmediate(() => {\n if (this._active && this._stdin?.isTTY) {\n this._stdin.setRawMode?.(true);\n }\n });\n }\n\n return true;\n }\n\n /**\n * Release raw mode and restore the terminal to the state it was in before\n * `acquire()` was called. Idempotent \u2014 subsequent calls are no-ops.\n *\n * Call this on: SIGINT, SIGTERM, SIGHUP, SIGBREAK, and `process.exit`.\n *\n * \u26A0 **Windows caveat**: `setRawMode(false)` on ConPTY restores the original\n * console mode captured when the process started \u2014 not the mode captured by\n * `acquire()`. On ConPTY, the original mode was already raw (ConPTY starts\n * raw), so this call is typically a no-op on Windows Terminal. On conhost.exe\n * it may restore cooked mode, which is correct for that backend.\n */\n release(): void {\n if (!this._active) return;\n this._active = false;\n\n const stdin = this._stdin;\n if (stdin?.isTTY === true) {\n // Restore to pre-TUI state rather than blindly disabling raw mode.\n stdin.setRawMode?.(this._wasRaw ?? false);\n if (this._wasPaused) stdin.pause();\n }\n this._stdin = undefined;\n this._wasRaw = null;\n this._wasPaused = null;\n }\n\n /**\n * Synchronously reset all terminal state written by the TUI layer:\n * raw mode, SGR attributes, cursor visibility, and mouse tracking.\n *\n * Intended for the final `process.on('exit')` handler where async is\n * impossible. Uses `\\x1b[0m` (SGR reset), `\\x1b[?25h` (cursor show),\n * and `\\x1b[?9l` (mouse off) \u2014 all safe to emit even if the terminal does\n * not understand them (unknown CSI sequences are silently ignored).\n *\n * Safe to call multiple times from multiple exit paths because each write\n * is a constant-time synchronous stream write.\n *\n * @param stdout - Stream to reset (defaults to `process.stdout`).\n */\n reset(stdout: NodeJS.WriteStream = process.stdout): void {\n if (typeof stdout?.write !== 'function') return;\n // SGR reset \u2014 clears bold, color, underline, etc.\n stdout.write('\\x1b[0m');\n // Cursor show (in case Ink's unmount left it hidden).\n stdout.write('\\x1b[?25h');\n // Mouse tracking off (all three DECRST sequences \u2014 safe no-ops if never set).\n stdout.write('\\x1b[?1003l\\x1b[?1002l\\x1b[?1000l');\n }\n}\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// safeEscape \u2014 guarded escape-sequence emitter\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Result of emitting an escape sequence. Distinguishes the three distinct\n * failure modes so callers can degrade gracefully.\n */\nexport interface EscapeEmitResult {\n /** `true` when the sequence was written to the stream. */\n ok: boolean;\n /**\n * Human-readable reason when `ok` is `false`. One of:\n * `'not_a_tty'` \u2014 stdout is not a terminal (pipe / redirect / CI)\n * `'unwritable'` \u2014 stdout.write is missing or threw\n * `'empty'` \u2014 `sequence` was the empty string\n */\n reason: 'not_a_tty' | 'unwritable' | 'empty';\n}\n\n/**\n * A terminal escape sequence with its optional string terminator.\n *\n * OSC (title, color palette) sequences MUST be terminated with `BEL (\\x07)`\n * or `ST (\\x1b\\\\)` or the terminal stays in command mode and corrupts\n * subsequent output. CSI sequences (colors, cursor movement) are\n * self-terminating and do not need a terminator byte.\n */\nexport interface EscapeSequence {\n /** The raw sequence, e.g. `\\x1b[38;2;255;0;0m`. */\n raw: string;\n /**\n * Optional terminator byte required by OSC/DCS families.\n * `undefined` for CSI sequences; `\\x07` (BEL) for OSC; `\\x1b\\\\` (ST) for DCS.\n */\n terminator?: string;\n}\n\n/**\n * Shared OSC/DCS terminator bytes.\n *\n * BEL (`\\x07`) is understood by iTerm2, Konsole, mintty, foot, and\n * Windows Terminal. ST (`\\x1b\\\\`) is the strict DEC standard equivalent.\n * Prefer BEL for compatibility; fall back to ST if the terminal's response\n * to BEL is observed to be garbled.\n */\nexport const ESCAPE_TERMINATOR = Object.freeze({\n BEL: '\\x07', // OSC 0 / OSC 2 (title)\n ST: '\\x1b\\\\', // DCS / strict OSC\n});\n\n/**\n * Emit a terminal escape sequence safely.\n *\n * Rules enforced:\n * 1. Empty string \u2192 returns `ok: false, reason: 'empty'`, no write.\n * 2. Not a TTY \u2192 returns `ok: false, reason: 'not_a_tty'`, no write.\n * 3. Stream write throws \u2192 returns `ok: false, reason: 'unwritable'`.\n * 4. OSC/DCS sequences MUST have a terminator byte (guarded assertion).\n * A missing terminator on an OSC sequence corrupts output on terminals\n * that don't understand the sequence \u2014 this function refuses to emit it.\n *\n * @param sequence - The sequence to emit. CSI sequences need no terminator.\n * OSC/DCS sequences must carry `terminator: '\\x07'` or `'\\x1b\\\\'`.\n * @param stdout - Stream to write to (defaults to `process.stdout`).\n * @returns Result indicating success or the specific failure mode.\n */\nexport function safeEmit(\n sequence: EscapeSequence | string,\n stdout: NodeJS.WriteStream = process.stdout,\n): EscapeEmitResult {\n const raw = typeof sequence === 'string' ? sequence : sequence.raw;\n const term = typeof sequence === 'string' ? undefined : sequence.terminator;\n\n if (!raw) {\n return { ok: false, reason: 'empty' };\n }\n if (stdout?.isTTY !== true) {\n return { ok: false, reason: 'not_a_tty' };\n }\n\n // For OSC/DCS sequences (which include `[` or `]` in the body), verify a\n // terminator is present. CSI sequences start with `\\x1b[` and are\n // self-terminating; we treat any sequence that is not a known OSC/DCS\n // as CSI and allow through. OSC starts with `\\x1b]`; DCS with `\\x1bP`.\n if (raw.startsWith('\\x1b]') || raw.startsWith('\\x1bP')) {\n // Assertion: terminator must be provided. Belt-and-suspenders against\n // callers that forget to append `\\x07` \u2014 this prevents corrupted output.\n if (!term) {\n // Defensive: append BEL rather than crashing. This is the only case\n // where we mutate the sequence. The assert-then-fallback pattern is\n // intentional: we catch programmer error in development but degrade\n // safely in production rather than throwing.\n void term; // suppress unused-variable warning\n const safe = `${raw}\\x07`;\n try {\n stdout.write(safe);\n } catch {\n return { ok: false, reason: 'unwritable' };\n }\n return { ok: true, reason: 'empty' }; // reason field is ignored when ok=true\n }\n try {\n stdout.write(`${raw}${term}`);\n } catch {\n return { ok: false, reason: 'unwritable' };\n }\n return { ok: true, reason: 'empty' };\n }\n\n // CSI sequence \u2014 self-terminating.\n try {\n stdout.write(raw);\n } catch {\n return { ok: false, reason: 'unwritable' };\n }\n return { ok: true, reason: 'empty' };\n}\n\n/**\n * Build an OSC 0 / OSC 2 (window/tab title) sequence with a safe terminator.\n *\n * The terminator defaults to `BEL (\\x07)` for broad terminal compatibility.\n * Use `terminator: ESCAPE_TERMINATOR.ST` for stricter terminals that interpret\n * BEL as a beep.\n *\n * @param title - The title string. Embedded BEL bytes are stripped.\n * @param terminator - Defaults to `ESCAPE_TERMINATOR.BEL`.\n */\nexport function buildTitleSequence(\n title: string,\n terminator: string = ESCAPE_TERMINATOR.BEL,\n): EscapeSequence {\n return {\n raw: `\\x1b]0;${title.replace(/\\x07/g, '')}`,\n terminator,\n };\n}\n\n/**\n * Build an SGR (Select Graphic Rendition) color/style sequence.\n *\n * @param codes - SGR parameter list, e.g. `[31]` (red foreground),\n * `[1;32]` (bold green), `[38;2;255;128;0]` (truecolor orange).\n */\nexport function buildSgrSequence(...codes: number[]): EscapeSequence {\n return { raw: `\\x1b[${codes.join(';')}m` };\n}\n\n/**\n * Emit a title sequence. Convenience wrapper around `safeEmit` + `buildTitleSequence`.\n *\n * @param title - The title string.\n * @param stdout - Target stream.\n */\nexport function setTitle(\n title: string,\n stdout: NodeJS.WriteStream = process.stdout,\n): boolean {\n return safeEmit(buildTitleSequence(title), stdout).ok;\n}\n", "import { isStdoutTTY } from './term.js';\n\nconst isColorTty = (): boolean => {\n if (envFlag(process.env.NO_COLOR)) return false;\n if (envFlag(process.env.FORCE_COLOR)) return true;\n return isStdoutTTY();\n};\n\nfunction envFlag(value: string | undefined): boolean {\n if (value === undefined) return false;\n if (value.trim() === '') return false;\n return !/^(0|false|no|off)$/i.test(value.trim());\n}\n\nconst COLOR = isColorTty();\n\nconst wrap =\n (open: string, close: string) =>\n (s: string): string =>\n COLOR ? `\\x1b[${open}m${s}\\x1b[${close}m` : s;\n\nexport const color = {\n reset: wrap('0', '0'),\n bold: wrap('1', '22'),\n dim: wrap('2', '22'),\n italic: wrap('3', '23'),\n underline: wrap('4', '24'),\n red: wrap('31', '39'),\n green: wrap('32', '39'),\n yellow: wrap('33', '39'),\n blue: wrap('34', '39'),\n magenta: wrap('35', '39'),\n cyan: wrap('36', '39'),\n gray: wrap('90', '39'),\n amber: wrap('38;5;214', '39'),\n pink: wrap('38;5;205', '39'),\n bgRed: wrap('41', '49'),\n bgGreen: wrap('42', '49'),\n};\n\nexport function stripAnsi(s: string): string {\n return s.replace(/\\x1b\\[[0-9;]*[A-Za-z]/g, '');\n}\n", "/**\n * Centralized skill system limits.\n *\n * Before this file existed, the magic numbers below were scattered across five\n * modules (`skill-installer`, `github-fetcher`, `skill` tool, system-prompt\n * builder, skill-loader), sometimes duplicated (e.g. per-skill body cap was\n * defined independently in the builder and the tool). Centralizing them here\n * keeps the budget model coherent \u2014 change one, change everywhere \u2014 and makes\n * the trade-offs visible in one place.\n *\n * Values are frozen at their pre-centralization defaults so this is a pure\n * refactor (no behavior change).\n */\nexport const SKILL_LIMITS = {\n /**\n * Per-skill body cap when injecting a full skill body into the system prompt\n * (eager mode), and when returning a skill body from the `skill` tool.\n * ~4k tokens. Oversized bodies are truncated at a paragraph boundary.\n *\n * Consumers: `system-prompt-builder.capSkillBody`, `skill` tool body return.\n */\n MAX_SKILL_BODY_CHARS: 16_000,\n\n /**\n * Per-resource cap when the `skill` tool loads a bundled file\n * (`scripts/`, `references/`, `assets/`). ~8k tokens.\n *\n * Consumer: `skill` tool `loadResource`.\n */\n MAX_RESOURCE_CHARS: 32_000,\n\n /**\n * Maximum number of bundled resource paths the `skill` tool lists in one\n * response. Caps a pathological skill (huge `assets/` tree) from blowing up\n * the tool result.\n *\n * Consumer: `skill` tool resource listing.\n */\n MAX_LISTED_RESOURCES: 100,\n\n /**\n * Max size of a single installed skill file (SKILL.md or a bundled resource).\n * Guards against a malicious registry skill shipping a multi-MB blob that\n * then flows into the prompt. 100KB.\n *\n * Consumer: `SkillInstaller.install` / `importFromDir`.\n */\n MAX_SKILL_FILE_SIZE: 100 * 1024,\n\n /**\n * Max size of a GitHub tarball downloaded by the skill installer. Guards\n * against a repo accidentally (or maliciously) shipping a giant tarball that\n * would be extracted into a temp dir. 50MB.\n *\n * Consumer: `downloadGitHubTarball`.\n */\n MAX_TARBALL_SIZE: 50 * 1024 * 1024,\n\n /**\n * Default total char budget for skill bodies injected in eager mode when\n * `config.skills.eagerMaxChars` is unset. ~6k tokens. Skills are injected\n * highest-priority first; once the budget is exhausted the remaining skills\n * are listed as a manifest the agent loads via the `skill` tool. Set very\n * high to effectively disable budgeting.\n *\n * Consumer: `DefaultSystemPromptBuilder.buildMemoryAndSkills` (default for\n * `skillEagerMaxChars`).\n */\n EAGER_DEFAULT_MAX_CHARS: 24_000,\n\n /**\n * Auto-compact body limits (the token-saving fallback used when a skill has\n * no hand-crafted `SKILL.save.md`). The Overview and Rules sections are\n * extracted and trimmed to these char budgets, then the total is capped.\n *\n * Consumer: `DefaultSkillLoader.compactSkillBody`.\n */\n COMPACT_OVERVIEW_MAX: 200,\n COMPACT_RULES_MAX: 350,\n COMPACT_TOTAL_MAX: 450,\n\n /**\n * Max length of a skill name (agentskills.io spec). Enforced by the\n * frontmatter validator's format regex plus this length bound.\n *\n * Consumer: `isValidSkillNameFormat`.\n */\n SKILL_NAME_MAX_LEN: 64,\n\n /**\n * Soft line limit for a SKILL.md body, per the bundled `skill-creator` rule.\n * Not enforced in code (a skill can exceed it) \u2014 surfaced by `/skill-gen\n * validate` and the `skill-creator` skill as guidance to move deep material\n * into `references/`.\n *\n * Consumer: `skill-creator` skill, `/skill-gen validate` advisory.\n */\n SKILL_BODY_LINE_LIMIT: 500,\n} as const;\n", "import { readFileSync, statSync } from 'node:fs';\nimport * as path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\n/**\n * Cache of resolved instruction text, keyed by the relative path. Bundled\n * instruction files are immutable for the process lifetime, so re-reading them\n * on every call (some callers do so per LLM request) is wasted disk I/O.\n */\nconst textCache = new Map<string, string>();\n\n/** Resolved once \u2014 the candidate roots only depend on this module's location. */\nlet rootCandidates: string[] | undefined;\n\nexport function readBundledInstructionText(relativePath: string): string {\n const cached = textCache.get(relativePath);\n if (cached !== undefined) return cached;\n\n let resolved = '';\n for (const root of instructionRootCandidates()) {\n try {\n resolved = readFileSync(path.join(root, relativePath), 'utf8').trimEnd();\n break;\n } catch {\n // try next candidate\n }\n }\n textCache.set(relativePath, resolved);\n return resolved;\n}\n\nexport function renderInstructionTemplate(\n template: string,\n values: Record<string, string>,\n): string {\n return template.replace(/\\{\\{\\s*([a-zA-Z0-9_.-]+)\\s*\\}\\}/g, (match, key: string) =>\n Object.hasOwn(values, key) ? (values[key] ?? '') : match,\n );\n}\n\nfunction instructionRootCandidates(): string[] {\n if (rootCandidates !== undefined) return rootCandidates;\n const here = path.dirname(fileURLToPath(import.meta.url));\n const candidates = [\n path.resolve(here, '../../instructions'),\n path.resolve(here, '../instructions'),\n path.resolve(here, 'instructions'),\n ];\n rootCandidates = candidates.sort((a, b) => Number(!isDirectory(a)) - Number(!isDirectory(b)));\n return rootCandidates;\n}\n\nfunction isDirectory(candidate: string): boolean {\n try {\n return statSync(candidate).isDirectory();\n } catch {\n return false;\n }\n}\n", "import { randomBytes } from 'node:crypto';\n\n/**\n * Crockford base32 alphabet (excludes I, L, O, U to avoid ambiguity).\n */\nconst ENCODING = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';\nconst ENCODING_LEN = ENCODING.length;\nconst TIME_LEN = 10;\nconst RANDOM_LEN = 16;\n\nfunction encodeTime(now: number, len: number): string {\n let mod: number;\n let str = '';\n for (let i = len - 1; i >= 0; i--) {\n mod = now % ENCODING_LEN;\n str = ENCODING[mod] + str;\n now = (now - mod) / ENCODING_LEN;\n }\n return str;\n}\n\nfunction encodeRandom(len: number): string {\n const bytes = randomBytes(len);\n let str = '';\n for (let i = 0; i < len; i++) {\n str += ENCODING[(bytes[i] as number) % ENCODING_LEN];\n }\n return str;\n}\n\n/**\n * Generate a ULID \u2014 a 26-char Crockford-base32 identifier whose first 10 chars\n * encode the millisecond timestamp (so IDs sort lexicographically by creation\n * time) followed by 16 chars of randomness. Zero runtime dependencies.\n *\n * The codebase convention is \"IDs are ULIDs\"; use this for any new store key.\n */\nexport function ulid(seedTime: number = Date.now()): string {\n return encodeTime(seedTime, TIME_LEN) + encodeRandom(RANDOM_LEN);\n}\n\n/** True for a well-formed 26-char Crockford-base32 ULID. */\nexport function isUlid(value: string): boolean {\n if (value.length !== TIME_LEN + RANDOM_LEN) return false;\n for (const ch of value) {\n if (!ENCODING.includes(ch)) return false;\n }\n return true;\n}\n", "/**\n * Turn an arbitrary string into a filesystem- and URL-safe lowercase slug.\n *\n * Collapses every run of non-alphanumeric characters into a single hyphen,\n * trims leading/trailing hyphens, and caps the length. Returns `fallback`\n * when the input slugifies to the empty string.\n *\n * Used as the stable dedup + registry key for prompts. (Distinct from the\n * project-folder slug in `wstack-paths.ts`, which has its own `'project'`\n * fallback and shorter cap.)\n */\nexport function slugify(name: string, fallback = 'prompt', maxLen = 64): string {\n return (\n name\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, maxLen)\n .replace(/-+$/g, '') || fallback\n );\n}\n", "/**\n * SQLite read path for Chronicle (phase 3 of `chronicle-sqlite-journal-v1`).\n *\n * The division of labour is the whole point of this file:\n *\n * - **SQL narrows.** Indexed columns turn \"parse every line of every partition\n * that overlaps the range\" into an index seek. Only predicates that map\n * cleanly onto a column are pushed down.\n * - **JavaScript decides.** The pushed-down predicate is a deliberate\n * *superset*: every candidate row is parsed and then passed through the same\n * `matches()` the JSONL engine uses. Nothing is filtered out by SQL that\n * `matches()` would have kept.\n *\n * That split is what makes parity provable rather than hoped for. A SQL\n * re-expression of `ChronicleQuery` would have to restate tag/attribute\n * lookups, path normalisation and line-range containment, and each restatement\n * is a place where the two engines could silently disagree. Here they cannot\n * disagree about *which* events match \u2014 only about how fast the candidates are\n * found.\n *\n * The summary is built with the JSONL engine's own accumulator for the same\n * reason: family classification, `usage.*` paths, cost de-duplication and the\n * p95 are semantics, not arithmetic.\n */\nimport type { DatabaseSync } from 'node:sqlite';\nimport type { ChronicleEvent } from './types.js';\nimport {\n type ChronicleFacet,\n type ChronicleFacetResults,\n type ChronicleFacetValue,\n type ChronicleGraphEdge,\n type ChronicleGraphResult,\n type ChronicleQuery,\n type ChronicleQueryResult,\n compareEvents,\n createSummaryAccumulator,\n facetValue,\n finalizeSummary,\n matches,\n relationKeys,\n updateSummary,\n} from './query.js';\n\n/** Hard ceiling mirroring `ChronicleQueryEngine.query`. */\nconst MAX_LIMIT = 10_000;\n\n/**\n * Keyset position in the `(day, sequence)` total order.\n *\n * Deliberately not interchangeable with the JSONL engine's cursor, which\n * encodes a snapshot of partition files. A cursor is opaque and belongs to the\n * engine that issued it; carrying one across would be meaningless.\n */\ninterface SqliteCursor {\n day: string;\n sequence: number;\n}\n\nfunction encodeCursor(cursor: SqliteCursor): string {\n return Buffer.from(`${cursor.day}:${cursor.sequence}`, 'utf8').toString('base64url');\n}\n\nfunction decodeCursor(raw: string | undefined): SqliteCursor | undefined {\n if (!raw) return undefined;\n try {\n const [day, sequence] = Buffer.from(raw, 'base64url').toString('utf8').split(':');\n if (!day || sequence === undefined) return undefined;\n const parsed = Number(sequence);\n return Number.isSafeInteger(parsed) ? { day, sequence: parsed } : undefined;\n } catch {\n return undefined;\n }\n}\n\ninterface PushedDown {\n clause: string;\n params: (string | number)[];\n}\n\n/**\n * Translate the parts of a query that map onto indexed columns.\n *\n * Anything absent here is simply not narrowed \u2014 `matches()` still applies it.\n * Adding a predicate to this list is an optimization; forgetting one is not a\n * correctness bug. That asymmetry is intentional.\n */\nfunction pushDown(query: ChronicleQuery): PushedDown {\n const clauses: string[] = [];\n const params: (string | number)[] = [];\n\n const eq = (column: string, value: string | undefined): void => {\n if (value === undefined) return;\n clauses.push(`${column} = ?`);\n params.push(value);\n };\n\n eq('event_id', query.eventId);\n eq('project_id', query.projectId);\n eq('session_id', query.sessionId);\n eq('agent_id', query.agentId);\n eq('task_id', query.taskId);\n eq('trace_id', query.traceId);\n eq('logical_request_id', query.logicalRequestId);\n eq('resource_kind', query.resourceKind);\n eq('resource_id', query.resourceId);\n\n if (query.eventTypes?.length) {\n clauses.push(`event_type IN (${query.eventTypes.map(() => '?').join(',')})`);\n params.push(...query.eventTypes);\n }\n if (query.outcomes?.length) {\n clauses.push(`outcome IN (${query.outcomes.map(() => '?').join(',')})`);\n params.push(...query.outcomes);\n }\n // `occurred_at` is an ISO-8601 UTC string, so lexicographic comparison is\n // chronological \u2014 the same assumption `matches()` makes.\n if (query.from) {\n clauses.push('occurred_at >= ?');\n params.push(query.from);\n }\n if (query.to) {\n clauses.push('occurred_at <= ?');\n params.push(query.to);\n }\n\n return { clause: clauses.length ? clauses.join(' AND ') : '1=1', params };\n}\n\nexport interface ChronicleSqliteQueryEngineOptions {\n /** Rows pulled from SQLite per batch while streaming candidates. */\n batchSize?: number | undefined;\n}\n\nexport class ChronicleSqliteQueryEngine {\n readonly diagnostics = { sourceFiles: 1, invalidLines: 0 };\n private readonly batchSize: number;\n\n constructor(\n private readonly db: DatabaseSync,\n options: ChronicleSqliteQueryEngineOptions = {},\n ) {\n this.batchSize = Math.max(1, options.batchSize ?? 1_000);\n }\n\n async query(query: ChronicleQuery = {}): Promise<ChronicleQueryResult> {\n const order = query.order ?? 'desc';\n const limit = Math.max(1, Math.min(query.limit ?? 100, MAX_LIMIT));\n const cursor = decodeCursor(query.cursor);\n const pushed = pushDown(query);\n\n const direction = order === 'asc' ? 'ASC' : 'DESC';\n const comparison = order === 'asc' ? '>' : '<';\n const keyset = cursor ? ` AND (day, sequence) ${comparison} (?, ?)` : '';\n const sql =\n `SELECT day, sequence, payload FROM events WHERE ${pushed.clause}${keyset}` +\n ` ORDER BY day ${direction}, sequence ${direction} LIMIT ? OFFSET ?`;\n\n const summary = createSummaryAccumulator();\n const page: ChronicleEvent[] = [];\n let total = 0;\n let scannedEvents = 0;\n let last: SqliteCursor | undefined;\n let offset = 0;\n\n // Every matching event feeds the summary, which is defined over the whole\n // result set rather than the page (see `ChronicleSummary`). Candidates are\n // streamed in batches so a wide query does not materialise the table.\n for (;;) {\n const params = [...pushed.params];\n if (cursor) params.push(cursor.day, cursor.sequence);\n params.push(this.batchSize, offset);\n const rows = this.db.prepare(sql).all(...params) as Array<{\n day: string;\n sequence: number;\n payload: string;\n }>;\n if (rows.length === 0) break;\n offset += rows.length;\n\n for (const row of rows) {\n scannedEvents++;\n let event: ChronicleEvent;\n try {\n event = JSON.parse(row.payload) as ChronicleEvent;\n } catch {\n this.diagnostics.invalidLines++;\n continue;\n }\n if (!matches(event, query)) continue;\n total++;\n updateSummary(summary, event);\n if (page.length < limit) {\n page.push(event);\n last = { day: row.day, sequence: row.sequence };\n }\n }\n if (rows.length < this.batchSize) break;\n }\n\n // The JSONL engine returns the page in `compareEvents` order; keyset order\n // is `(day, sequence)`, which can differ when events share a timestamp.\n // Sorting here keeps both engines' pages identical.\n page.sort((left, right) => compareEvents(left, right) * (order === 'asc' ? 1 : -1));\n\n const result: ChronicleQueryResult = {\n events: page,\n total,\n scannedEvents,\n sourceFiles: this.diagnostics.sourceFiles,\n invalidLines: this.diagnostics.invalidLines,\n summary: finalizeSummary(summary),\n };\n if (total > page.length && last) {\n return { ...result, nextCursor: encodeCursor(last) };\n }\n return result;\n }\n\n /**\n * Value counts per facet field.\n *\n * Not a SQL `GROUP BY`: `facetValue()` reads fields that live inside the\n * payload \u2014 provider, model, tool call, tag \u2014 so grouping in SQL would only\n * work for the handful that happen to be columns and would need a second,\n * divergent definition for the rest. The narrowing is still done by SQL; the\n * counting uses the JSONL engine's own projection.\n */\n async facets(\n fields: readonly ChronicleFacet[],\n query: ChronicleQuery = {},\n limit = 100,\n ): Promise<ChronicleFacetResults> {\n const uniqueFields = [...new Set(fields)];\n if (uniqueFields.length === 0) return {};\n const counts = new Map(uniqueFields.map((field) => [field, new Map<string, number>()]));\n\n for (const event of this.eachMatch(query)) {\n for (const field of uniqueFields) {\n const value = facetValue(event, field);\n if (value === undefined) continue;\n const fieldCounts = counts.get(field);\n fieldCounts?.set(value, (fieldCounts.get(value) ?? 0) + 1);\n }\n }\n\n const result: ChronicleFacetResults = {};\n for (const field of uniqueFields) {\n result[field] = [...(counts.get(field) ?? new Map<string, number>())]\n .map(([value, count]) => ({ value, count }))\n // Ties broken by value so both engines agree on an otherwise arbitrary\n // order \u2014 the same comparator `ChronicleQueryEngine.facets` uses.\n .sort((left, right) => right.count - left.count || left.value.localeCompare(right.value))\n .slice(0, Math.max(0, limit));\n }\n return result;\n }\n\n async facet(\n field: ChronicleFacet,\n query: ChronicleQuery = {},\n limit = 100,\n ): Promise<ChronicleFacetValue[]> {\n return (await this.facets([field], query, limit))[field] ?? [];\n }\n\n /**\n * Expand explicit and typed correlation edges around a seed set.\n *\n * The traversal is the JSONL engine's, moved onto rows: `relationKeys()`\n * defines the edges, `compareEvents` orders the nodes, and each hop is\n * another ordered pass. Order is load-bearing rather than cosmetic \u2014 both\n * `maxNodes` truncations stop at whatever they reach first, so a differently\n * ordered scan would return a different subgraph rather than the same one\n * shuffled. `ORDER BY day, sequence` reproduces `comparePartitionPaths`\n * (family, then rotation index) followed by line order within a partition.\n */\n async graph(\n seed: ChronicleQuery = {},\n hops = 2,\n maxNodes = 1_000,\n ): Promise<ChronicleGraphResult> {\n const nodeLimit = Math.max(0, Math.floor(maxNodes));\n const selected = new Map<string, ChronicleEvent>();\n let seedCount = 0;\n\n for (const event of this.eachMatch(seed)) {\n seedCount++;\n if (selected.size < nodeLimit) selected.set(event.eventId, event);\n }\n\n let frontier = [...selected.values()];\n const depthLimit = Math.max(0, Math.min(hops, 10));\n for (\n let depth = 0;\n depth < depthLimit && frontier.length > 0 && selected.size < nodeLimit;\n depth++\n ) {\n const frontierKeys = new Set(\n frontier.flatMap((event) => relationKeys(event).map((relation) => relation.key)),\n );\n const next: ChronicleEvent[] = [];\n for (const event of this.eachMatch({})) {\n if (selected.has(event.eventId)) continue;\n if (!relationKeys(event).some((relation) => frontierKeys.has(relation.key))) continue;\n selected.set(event.eventId, event);\n next.push(event);\n if (selected.size >= nodeLimit) break;\n }\n frontier = next;\n }\n\n const nodes = [...selected.values()].sort(compareEvents);\n const byKey = new Map<string, ChronicleEvent[]>();\n for (const node of nodes) {\n for (const relation of relationKeys(node)) {\n const related = byKey.get(relation.key) ?? [];\n related.push(node);\n byKey.set(relation.key, related);\n }\n }\n\n const edges: ChronicleGraphEdge[] = [];\n const seen = new Set<string>();\n for (const node of nodes) {\n for (const relation of relationKeys(node)) {\n for (const candidate of byKey.get(relation.key) ?? []) {\n if (candidate.eventId === node.eventId) continue;\n const [from, to] =\n compareEvents(node, candidate) <= 0 ? [node, candidate] : [candidate, node];\n const id = `${from.eventId}:${to.eventId}:${relation.kind}`;\n if (seen.has(id)) continue;\n seen.add(id);\n edges.push({\n from: from.eventId,\n to: to.eventId,\n kind: relation.kind,\n confidence: relation.confidence,\n });\n }\n }\n }\n\n return {\n nodes,\n edges,\n truncated: seedCount > nodeLimit || selected.size >= nodeLimit,\n };\n }\n\n /** Every event satisfying `query`, pulled in batches so a wide scan stays bounded. */\n private *eachMatch(query: ChronicleQuery): Generator<ChronicleEvent> {\n const pushed = pushDown(query);\n const sql =\n `SELECT payload FROM events WHERE ${pushed.clause}` +\n ' ORDER BY day, sequence LIMIT ? OFFSET ?';\n let offset = 0;\n for (;;) {\n const rows = this.db.prepare(sql).all(...pushed.params, this.batchSize, offset) as Array<{\n payload: string;\n }>;\n if (rows.length === 0) return;\n offset += rows.length;\n for (const row of rows) {\n let event: ChronicleEvent;\n try {\n event = JSON.parse(row.payload) as ChronicleEvent;\n } catch {\n this.diagnostics.invalidLines++;\n continue;\n }\n if (matches(event, query)) yield event;\n }\n if (rows.length < this.batchSize) return;\n }\n }\n}\n", "import { spawn } from 'node:child_process';\nimport * as fs from 'node:fs';\nimport * as net from 'node:net';\nimport * as path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { ChronicleJournalStats } from './journal.js';\nimport { chronicleProjectServerEndpoint } from './project-server-endpoint.js';\nimport {\n CHRONICLE_PROJECT_SERVER_MAX_FRAME_CHARS,\n CHRONICLE_PROJECT_SERVER_PROTOCOL_VERSION,\n type ChronicleProjectServerHealth,\n type ChronicleProjectServerInfo,\n type ChronicleProjectServerMessage,\n type ChronicleServerOperationName,\n type ChronicleServerOperations,\n encodeChronicleProjectServerMessage,\n} from './project-server-protocol.js';\nimport type { ChronicleEventSink } from './sink.js';\nimport type { ChronicleEvent, ChronicleEventInput } from './types.js';\n\nconst CONNECT_ATTEMPT_TIMEOUT_MS = 750;\nconst SERVER_START_TIMEOUT_MS = 10_000;\nconst DEFAULT_CALL_TIMEOUT_MS = 30_000;\nconst APPEND_CALL_TIMEOUT_MS = 60_000;\nconst DEFAULT_BATCH_WINDOW_MS = 5;\nconst DEFAULT_MAX_PENDING = 100_000;\n\ninterface PendingRequest {\n resolve(value: unknown): void;\n reject(error: unknown): void;\n timer: ReturnType<typeof setTimeout>;\n}\n\nexport interface ChronicleProjectServerClientOptions {\n projectRoot: string;\n globalRoot: string;\n projectId: string;\n projectDir: string;\n workspaceId: string;\n retentionDays?: number | undefined;\n}\n\nexport interface ChronicleProjectServerCallOptions {\n timeoutMs?: number | undefined;\n}\n\n/**\n * Locate the detached Chronicle entry from both regular ESM output and the\n * bundled core entrypoints. In an esbuild bundle `import.meta.url` belongs to\n * the bundle (for example `dist/plugin/index.js`), not this source module, so\n * a single relative lookup silently selects the inline fallback.\n */\n/**\n * Why the Chronicle daemon is or is not usable.\n *\n * `resolveChronicleProjectServerUrl` collapses two very different situations\n * into one `null`: the operator asked for in-process mode, or the built server\n * simply could not be found. Callers that fall back on `null` therefore treat a\n * broken build exactly like a deliberate choice \u2014 and since the lookup is\n * relative to `import.meta.url`, a change in bundle layout alone is enough to\n * silently give every process its own private journal.\n */\nexport type ChronicleDaemonAvailability =\n | { readonly kind: 'available'; readonly url: URL }\n /** `WRONGSTACK_CHRONICLE_INLINE` / `WRONGSTACK_CHRONICLE_SERVER=0` was set. */\n | { readonly kind: 'inline-requested' }\n /** No server entry point exists in any known output layout. */\n | { readonly kind: 'missing-build' };\n\nexport function resolveChronicleDaemonAvailability(\n moduleUrl = import.meta.url,\n exists: (filePath: string) => boolean = fs.existsSync,\n): ChronicleDaemonAvailability {\n if (\n process.env['WRONGSTACK_CHRONICLE_INLINE'] ||\n process.env['WRONGSTACK_CHRONICLE_SERVER'] === '0'\n ) {\n return { kind: 'inline-requested' };\n }\n const url = locateChronicleProjectServer(moduleUrl, exists);\n return url ? { kind: 'available', url } : { kind: 'missing-build' };\n}\n\nexport function resolveChronicleProjectServerUrl(\n moduleUrl = import.meta.url,\n exists: (filePath: string) => boolean = fs.existsSync,\n): URL | null {\n const availability = resolveChronicleDaemonAvailability(moduleUrl, exists);\n return availability.kind === 'available' ? availability.url : null;\n}\n\nfunction locateChronicleProjectServer(\n moduleUrl: string,\n exists: (filePath: string) => boolean,\n): URL | null {\n const candidates = [\n // Normal unbundled output: dist/chronicle/project-server-client.js.\n './project-server.js',\n // Core plugin bundle: dist/plugin/index.js.\n '../chronicle/project-server.js',\n // Core root bundle: dist/index.js.\n './chronicle/project-server.js',\n ];\n for (const relativePath of candidates) {\n try {\n const url = new URL(relativePath, moduleUrl);\n if (url.protocol === 'file:' && exists(fileURLToPath(url))) return url;\n } catch {\n // Try the next known output layout.\n }\n }\n return null;\n}\n\nexport function isChronicleProjectServerAvailable(): boolean {\n return resolveChronicleProjectServerUrl() !== null;\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Multiplexed IPC client for the single Chronicle owner of a local project.\n */\nexport class ChronicleProjectServerClient {\n readonly endpoint: string;\n private socket: net.Socket | null = null;\n private info: ChronicleProjectServerInfo | null = null;\n private buffer = '';\n private connecting: Promise<void> | null = null;\n private connectResolve: (() => void) | null = null;\n private connectReject: ((error: unknown) => void) | null = null;\n private nextId = 1;\n private readonly pending = new Map<number, PendingRequest>();\n\n constructor(readonly options: ChronicleProjectServerClientOptions) {\n this.endpoint = chronicleProjectServerEndpoint(options.projectDir);\n }\n\n async call<O extends ChronicleServerOperationName>(\n op: O,\n args: ChronicleServerOperations[O]['args'],\n options: ChronicleProjectServerCallOptions = {},\n ): Promise<ChronicleServerOperations[O]['result']> {\n await this.ensureConnected(true);\n return this.request<ChronicleServerOperations[O]['result']>(\n { type: 'request', op, args },\n options.timeoutMs ?? DEFAULT_CALL_TIMEOUT_MS,\n );\n }\n\n ping(): Promise<ChronicleProjectServerHealth> {\n return this.call('ping', {}, { timeoutMs: 3_000 });\n }\n\n /**\n * Request the Chronicle project server to shut down cleanly.\n *\n * Returns the server PID and acknowledgment. Does not throw if the server\n * is already offline or unreachable \u2014 the caller is assumed to want the\n * server stopped regardless of current state.\n */\n async shutdown(reason?: string): Promise<{ stopped: boolean; pid?: number; reason?: string }> {\n try {\n await this.ensureConnected(false);\n } catch {\n return { stopped: false, reason: 'offline' };\n }\n const pid = this.info?.pid;\n try {\n const result = (await this.request<{ stopped: boolean; pid?: number; reason?: string }>(\n { type: 'shutdown', reason },\n 5_000,\n )) ?? { stopped: true };\n return { ...result, ...(pid !== undefined && result.pid === undefined ? { pid } : {}) };\n } catch {\n return { stopped: false, ...(pid !== undefined ? { pid } : {}), reason: 'write-failed' };\n }\n }\n\n async close(): Promise<void> {\n const socket = this.socket;\n this.socket = null;\n this.info = null;\n if (socket && !socket.destroyed) {\n await new Promise<void>((resolve) => {\n socket.once('close', resolve);\n socket.end();\n });\n }\n }\n\n private async ensureConnected(spawnIfMissing: boolean): Promise<void> {\n if (this.socket && !this.socket.destroyed && this.info) return;\n if (this.connecting) return this.connecting;\n if (!isChronicleProjectServerAvailable()) {\n throw new Error(\n 'Built Chronicle project server is unavailable. Build @wrongstack/core or use the inline journal.',\n );\n }\n this.connecting = this.connectWithElection(spawnIfMissing).finally(() => {\n this.connecting = null;\n });\n return this.connecting;\n }\n\n private async connectWithElection(spawnIfMissing: boolean): Promise<void> {\n const deadline =\n Date.now() + (spawnIfMissing ? SERVER_START_TIMEOUT_MS : CONNECT_ATTEMPT_TIMEOUT_MS);\n let spawned = false;\n let lastError: unknown = new Error('Chronicle project server unavailable');\n while (Date.now() < deadline) {\n try {\n await this.connectOnce();\n return;\n } catch (error) {\n lastError = error;\n }\n if (!spawnIfMissing) break;\n if (!spawned) {\n this.spawnDetachedServer();\n spawned = true;\n }\n await delay(75);\n }\n throw lastError;\n }\n\n private connectOnce(): Promise<void> {\n this.socket?.destroy();\n this.socket = null;\n this.info = null;\n this.buffer = '';\n return new Promise<void>((resolve, reject) => {\n const socket = net.createConnection(this.endpoint);\n this.socket = socket;\n socket.setEncoding('utf8');\n const timer = setTimeout(() => {\n reject(new Error('Chronicle project server handshake timed out'));\n socket.destroy();\n }, CONNECT_ATTEMPT_TIMEOUT_MS);\n timer.unref?.();\n this.connectResolve = () => {\n clearTimeout(timer);\n this.connectResolve = null;\n this.connectReject = null;\n resolve();\n };\n this.connectReject = (error) => {\n clearTimeout(timer);\n this.connectResolve = null;\n this.connectReject = null;\n reject(error);\n };\n socket.on('data', (chunk: string) => this.onData(socket, chunk));\n socket.on('error', (error) => {\n if (!this.info) this.connectReject?.(error);\n });\n socket.on('close', () => this.onClose(socket));\n });\n }\n\n private request<T>(\n message:\n | { type: 'request'; op: ChronicleServerOperationName; args: unknown }\n | { type: 'shutdown'; reason?: string | undefined },\n timeoutMs: number,\n ): Promise<T> {\n const socket = this.socket;\n if (!socket || socket.destroyed) {\n return Promise.reject(new Error('Chronicle project server connection is unavailable'));\n }\n const id = this.nextId++;\n const encoded = encodeChronicleProjectServerMessage({ ...message, id });\n if (encoded.length > CHRONICLE_PROJECT_SERVER_MAX_FRAME_CHARS) {\n return Promise.reject(new Error('Chronicle project server request exceeded frame limit'));\n }\n const label = message.type === 'request' ? message.op : message.type;\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => {\n const pending = this.pending.get(id);\n if (!pending) return;\n this.pending.delete(id);\n pending.reject(new Error(`Chronicle ${label} exceeded its ${timeoutMs}ms timeout`));\n }, timeoutMs);\n timer.unref?.();\n this.pending.set(id, { resolve, reject, timer });\n socket.write(encoded);\n });\n }\n\n private onData(socket: net.Socket, chunk: string): void {\n if (socket !== this.socket) return;\n this.buffer += chunk;\n if (this.buffer.length > CHRONICLE_PROJECT_SERVER_MAX_FRAME_CHARS) {\n socket.destroy(new Error('Chronicle project server response exceeded frame limit'));\n return;\n }\n while (true) {\n const newline = this.buffer.indexOf('\\n');\n if (newline < 0) return;\n const line = this.buffer.slice(0, newline);\n this.buffer = this.buffer.slice(newline + 1);\n if (!line) continue;\n let message: ChronicleProjectServerMessage;\n try {\n message = JSON.parse(line) as ChronicleProjectServerMessage;\n } catch {\n socket.destroy(new Error('Invalid Chronicle project server response'));\n return;\n }\n this.onMessage(message);\n }\n }\n\n private onMessage(message: ChronicleProjectServerMessage): void {\n if (message.type === 'hello') {\n if (message.protocolVersion !== CHRONICLE_PROJECT_SERVER_PROTOCOL_VERSION) {\n this.connectReject?.(\n new Error(\n `Chronicle protocol mismatch: client=${CHRONICLE_PROJECT_SERVER_PROTOCOL_VERSION}, server=${message.protocolVersion}`,\n ),\n );\n this.socket?.destroy();\n return;\n }\n if (\n normalizePath(message.projectRoot) !== normalizePath(this.options.projectRoot) ||\n normalizePath(message.projectDir) !== normalizePath(this.options.projectDir)\n ) {\n this.connectReject?.(new Error('Chronicle project server identity mismatch'));\n this.socket?.destroy();\n return;\n }\n this.info = message;\n this.connectResolve?.();\n return;\n }\n const pending = this.pending.get(message.id);\n if (!pending) return;\n this.pending.delete(message.id);\n clearTimeout(pending.timer);\n if (message.ok) pending.resolve(message.result);\n else {\n const error = new Error(message.error);\n if (message.errorName) error.name = message.errorName;\n pending.reject(error);\n }\n }\n\n private onClose(socket: net.Socket): void {\n if (socket !== this.socket) return;\n this.socket = null;\n this.info = null;\n const error = new Error('Chronicle project server connection closed');\n this.connectReject?.(error);\n this.connectResolve = null;\n this.connectReject = null;\n const pending = [...this.pending.values()];\n this.pending.clear();\n for (const request of pending) {\n clearTimeout(request.timer);\n request.reject(error);\n }\n }\n\n private spawnDetachedServer(): void {\n const url = resolveChronicleProjectServerUrl();\n if (!url) throw new Error('Built Chronicle project server is unavailable');\n const args = [\n fileURLToPath(url),\n '--project-root',\n this.options.projectRoot,\n '--global-root',\n this.options.globalRoot,\n '--project-id',\n this.options.projectId,\n '--project-dir',\n this.options.projectDir,\n '--workspace-id',\n this.options.workspaceId,\n ];\n if (this.options.retentionDays !== undefined) {\n args.push('--retention-days', String(this.options.retentionDays));\n }\n const child = spawn(process.execPath, args, {\n detached: true,\n stdio: 'ignore',\n windowsHide: true,\n env: process.env,\n });\n child.unref();\n }\n}\n\ninterface QueuedAppend {\n input: ChronicleEventInput;\n resolve(event: ChronicleEvent): void;\n reject(error: unknown): void;\n}\n\n/**\n * ChronicleEventSink backed by the project server. A short client-side batch\n * window keeps high-frequency EventBus adapters from turning into one IPC\n * round trip per event.\n */\nexport class ChronicleRemoteJournal implements ChronicleEventSink {\n private readonly client: ChronicleProjectServerClient;\n private readonly maxPending: number;\n private readonly batchWindowMs: number;\n private pending: QueuedAppend[] = [];\n private timer: ReturnType<typeof setTimeout> | undefined;\n private readonly inflight = new Set<Promise<void>>();\n private readonly counters = {\n acceptedEvents: 0,\n persistedEvents: 0,\n rejectedEvents: 0,\n failedEvents: 0,\n batches: 0,\n maxObservedPending: 0,\n largestBatch: 0,\n partitionRolls: 0,\n };\n private lastBatchDurationMs: number | undefined;\n\n constructor(\n options: ChronicleProjectServerClientOptions & {\n maxPending?: number | undefined;\n batchWindowMs?: number | undefined;\n },\n client = new ChronicleProjectServerClient(options),\n ) {\n this.client = client;\n this.maxPending = Math.max(1, options.maxPending ?? DEFAULT_MAX_PENDING);\n this.batchWindowMs = Math.max(0, options.batchWindowMs ?? DEFAULT_BATCH_WINDOW_MS);\n }\n\n append(input: ChronicleEventInput): Promise<ChronicleEvent> {\n if (this.pending.length >= this.maxPending) {\n this.counters.rejectedEvents++;\n return Promise.reject(\n new Error(`Chronicle backpressure limit reached (${this.maxPending} pending events)`),\n );\n }\n const promise = new Promise<ChronicleEvent>((resolve, reject) => {\n this.pending.push({ input, resolve, reject });\n });\n this.counters.acceptedEvents++;\n this.counters.maxObservedPending = Math.max(\n this.counters.maxObservedPending,\n this.pending.length,\n );\n this.schedule();\n return promise;\n }\n\n stats(): ChronicleJournalStats {\n return {\n ...this.counters,\n pendingEvents: this.pending.length,\n ...(this.lastBatchDurationMs !== undefined\n ? { lastBatchDurationMs: this.lastBatchDurationMs }\n : {}),\n };\n }\n\n async flush(): Promise<void> {\n if (this.timer) {\n clearTimeout(this.timer);\n this.timer = undefined;\n }\n while (this.pending.length > 0 || this.inflight.size > 0) {\n if (this.pending.length > 0) this.startBatch();\n await Promise.all([...this.inflight]);\n }\n if (this.counters.acceptedEvents === 0) return;\n await this.client.call('flush', {}, { timeoutMs: APPEND_CALL_TIMEOUT_MS });\n }\n\n async dispose(): Promise<void> {\n await this.flush();\n await this.client.close();\n }\n\n private schedule(): void {\n if (this.timer) return;\n if (this.batchWindowMs === 0) {\n queueMicrotask(() => this.startBatch());\n return;\n }\n this.timer = setTimeout(() => {\n this.timer = undefined;\n this.startBatch();\n }, this.batchWindowMs);\n this.timer.unref?.();\n }\n\n private startBatch(): void {\n if (this.timer) {\n clearTimeout(this.timer);\n this.timer = undefined;\n }\n if (this.pending.length === 0) return;\n const batch = this.pending.splice(0);\n const started = performance.now();\n this.counters.batches++;\n this.counters.largestBatch = Math.max(this.counters.largestBatch, batch.length);\n const run = this.client\n .call(\n 'append',\n { inputs: batch.map((entry) => entry.input) },\n { timeoutMs: APPEND_CALL_TIMEOUT_MS },\n )\n .then((events) => {\n if (events.length !== batch.length) {\n throw new Error(\n `Chronicle server returned ${events.length} events for ${batch.length} inputs`,\n );\n }\n batch.forEach((entry, index) => {\n entry.resolve(events[index]!);\n });\n this.counters.persistedEvents += batch.length;\n })\n .catch((error) => {\n this.counters.failedEvents += batch.length;\n for (const entry of batch) entry.reject(error);\n })\n .finally(() => {\n this.lastBatchDurationMs = performance.now() - started;\n this.inflight.delete(run);\n if (this.pending.length > 0) this.schedule();\n });\n this.inflight.add(run);\n }\n}\n\nfunction normalizePath(value: string): string {\n const resolved = path.resolve(value);\n return process.platform === 'win32' ? resolved.toLowerCase() : resolved;\n}\n", "import { createHash } from 'node:crypto';\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { assertUnixSocketPathWithinLimit } from '../utils/socket-path.js';\nimport { CHRONICLE_PROJECT_SERVER_PROTOCOL_VERSION } from './project-server-protocol.js';\n\nexport const CHRONICLE_PROJECT_SERVER_METADATA_FILE = 'server.json';\n\nfunction normalizedPath(value: string): string {\n const resolved = path.resolve(value);\n return process.platform === 'win32' ? resolved.toLowerCase() : resolved;\n}\n\nexport function chronicleProjectServerKey(projectDir: string): string {\n return createHash('sha256')\n .update(normalizedPath(path.join(projectDir, 'chronicle')))\n .digest('hex')\n .slice(0, 24);\n}\n\n/**\n * Deterministic per-project chronicle IPC endpoint.\n *\n * The Unix subdirectory is the short `wsch-v<V>/` (was\n * `wrongstack-chronicle-v<V>/`, which left a single byte of macOS `sun_path`\n * headroom under the ~48-byte per-user TMPDIR \u2014 see the codebase-index macOS\n * incident and `@wrongstack/persistence` socket-path helpers). ~86 bytes\n * worst-case macOS now.\n *\n * Migration: the protocol version stays embedded in the path, so this rename\n * behaves exactly like a protocol bump \u2014 old daemons keep listening on the old\n * `wrongstack-chronicle-v<V>/` path, are never contacted again, and exit on\n * their idle timeout. No coexistence window: a client build always talks only\n * to the endpoint scheme it derives. Bump\n * `CHRONICLE_PROJECT_SERVER_PROTOCOL_VERSION` for wire changes as before; the\n * prefix itself must not grow without re-checking the byte budget.\n * The Windows pipe name keeps the long prefix \u2014 named pipes have no\n * `sun_path` limit.\n */\nexport function chronicleProjectServerEndpoint(projectDir: string): string {\n const key = chronicleProjectServerKey(projectDir);\n if (process.platform === 'win32') {\n return `\\\\\\\\.\\\\pipe\\\\wrongstack-chronicle-v${CHRONICLE_PROJECT_SERVER_PROTOCOL_VERSION}-${key}`;\n }\n return path.join(\n os.tmpdir(),\n `wsch-v${CHRONICLE_PROJECT_SERVER_PROTOCOL_VERSION}`,\n `${key}.sock`,\n );\n}\n\nexport function chronicleProjectServerMetadataPath(projectDir: string): string {\n return path.join(projectDir, 'chronicle', CHRONICLE_PROJECT_SERVER_METADATA_FILE);\n}\n\nexport function ensureChronicleProjectServerSocketDirectory(endpoint: string): void {\n if (process.platform !== 'win32') {\n // ~86 bytes under a canonical macOS TMPDIR since the wsch-v1/ rename.\n // Assert so growth fails loudly instead of as a silent bind error in the\n // detached daemon (see the codebase-index macOS incident).\n assertUnixSocketPathWithinLimit(endpoint, 'chronicle');\n fs.mkdirSync(path.dirname(endpoint), { recursive: true, mode: 0o700 });\n }\n}\n", "import type { ChronicleJournalStats, ChroniclePurgeResult } from './journal.js';\nimport type { ChronicleMetricsRefreshResult } from './metrics-store.js';\nimport type {\n ChronicleFacet,\n ChronicleFacetResults,\n ChronicleFacetValue,\n ChronicleGraphResult,\n ChronicleQuery,\n ChronicleQueryResult,\n} from './query.js';\nimport type { ChronicleEvent, ChronicleEventInput } from './types.js';\n\nexport const CHRONICLE_PROJECT_SERVER_PROTOCOL_VERSION = 2;\nexport const CHRONICLE_PROJECT_SERVER_MAX_FRAME_CHARS = 64 * 1024 * 1024;\n\nexport interface ChronicleProjectServerInfo {\n protocolVersion: number;\n pid: number;\n projectRoot: string;\n projectDir: string;\n chronicleDirectory: string;\n endpoint: string;\n startedAt: string;\n}\n\nexport interface ChronicleProjectServerHealth extends ChronicleProjectServerInfo {\n checkedAt: number;\n uptimeMs: number;\n clients: number;\n activeRequests: number;\n journal: ChronicleJournalStats;\n watcher: {\n active: boolean;\n watchedFiles: number;\n lastError?: string | undefined;\n };\n /**\n * Day families the legacy JSONL import refused to move for a broken chain.\n *\n * Present and non-empty means the journal has a known hole: those days were\n * never imported and never will be. Health surfaces it as degraded rather\n * than healthy \u2014 a store that silently serves an incomplete audit record is\n * worse than one that says which day is missing.\n */\n quarantinedFamilies?: Array<{ day: string; sequence: number; reason: string }> | undefined;\n memory: {\n rss: number;\n heapUsed: number;\n heapTotal: number;\n external: number;\n };\n}\n\nexport type ChronicleMetricsView = 'summary' | 'providers' | 'tasks' | 'files';\n\nexport interface ChronicleMetricsRequest {\n view: ChronicleMetricsView;\n /**\n * When false, serve the current derived projection immediately and refresh\n * it in the background. Latency-sensitive enrichment must not wait for a\n * multi-GB historical backlog to be indexed.\n */\n refresh?: boolean;\n providers?: { from?: string; to?: string };\n tasks?: {\n runId?: string;\n boardId?: string;\n sessionId?: string;\n status?: string;\n limit?: number;\n };\n files?: {\n path?: string;\n paths?: string[];\n latestPerPath?: boolean;\n taskId?: string;\n boardId?: string;\n sessionId?: string;\n limit?: number;\n };\n}\n\nexport interface ChronicleMetricsResponse {\n refreshed: ChronicleMetricsRefreshResult;\n data: unknown;\n}\n\nexport interface ChronicleServerOperations {\n ping: { args: Record<string, never>; result: ChronicleProjectServerHealth };\n append: { args: { inputs: ChronicleEventInput[] }; result: ChronicleEvent[] };\n flush: { args: Record<string, never>; result: void };\n purge: {\n args: { retentionDays: number; dryRun?: boolean };\n result: ChroniclePurgeResult;\n };\n query: { args: { query: ChronicleQuery }; result: ChronicleQueryResult };\n facet: {\n args: { field: ChronicleFacet; query: ChronicleQuery; limit?: number | undefined };\n result: {\n values: ChronicleFacetValue[];\n diagnostics: { sourceFiles: number; invalidLines: number };\n };\n };\n facets: {\n args: { fields: ChronicleFacet[]; query: ChronicleQuery; limit?: number | undefined };\n result: {\n values: ChronicleFacetResults;\n diagnostics: { sourceFiles: number; invalidLines: number };\n };\n };\n graph: {\n args: { seed: ChronicleQuery; hops?: number | undefined; maxNodes?: number | undefined };\n result: ChronicleGraphResult;\n };\n metrics: { args: ChronicleMetricsRequest; result: ChronicleMetricsResponse };\n}\n\nexport type ChronicleServerOperationName = keyof ChronicleServerOperations;\n\nexport type ChronicleProjectServerClientMessage =\n | {\n type: 'request';\n id: number;\n op: ChronicleServerOperationName;\n args: unknown;\n }\n | { type: 'shutdown'; id: number; reason?: string | undefined };\n\nexport type ChronicleProjectServerMessage =\n | ({ type: 'hello' } & ChronicleProjectServerInfo)\n | { type: 'response'; id: number; ok: true; result: unknown }\n | {\n type: 'response';\n id: number;\n ok: false;\n error: string;\n errorName?: string | undefined;\n };\n\nexport function encodeChronicleProjectServerMessage(message: object): string {\n return `${JSON.stringify(message)}\\n`;\n}\n", "import { randomUUID } from 'node:crypto';\nimport { spawn } from 'node:child_process';\nimport * as fsp from 'node:fs/promises';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport type { EventBus } from '../kernel/events.js';\nimport type { Plugin } from '../types/plugin.js';\nimport type { SlashCommand } from '../types/slash-command.js';\nimport { toErrorMessage } from '../utils/error.js';\nimport { readBundledInstructionText } from '../utils/instruction-file.js';\nimport { projectSlug } from '../utils/wstack-paths.js';\nimport {\n emitReviewIfChanged,\n recordCompletedReview,\n recordStartedReview,\n} from './review-claim-registry.js';\nimport { buildReviewContext } from './review-context-builder.js';\nimport type {\n ChimeraReviewCompletePayload,\n ResolvedChimeraConfig,\n ReviewContextBundle,\n ReviewFileEntry,\n} from './review-types.js';\nimport { executeFindingCommand } from './review-finding-commands.js';\nimport { integrateFindings } from './review-finding-integration.js';\nimport { persistReviewReport } from './review-report-integration.js';\n\n// Re-export the shared review types so existing importers keep resolving them\n// from './chimera-plugin.js' (and the package barrel). Their definitions live\n// in the leaf './review-types.js' module to keep the helper imports one-way.\nexport type {\n CascadeAgentKind,\n ChimeraCascadeNeededPayload,\n ChimeraReviewCompletePayload,\n ChimeraReviewNeededPayload,\n ResolvedChimeraConfig,\n ReviewContextBundle,\n ReviewFileEntry,\n} from './review-types.js';\n\n// ---------------------------------------------------------------------------\n// Chimera configuration \u2014 read from config.extensions['wstack-chimera']\n// ---------------------------------------------------------------------------\ninterface ChimeraConfig {\n enabled?: boolean | undefined;\n provider?: string | undefined;\n model?: string | undefined;\n maxFiles?: number | undefined;\n /**\n * How to handle chimera review findings:\n * - `off` (default): Send result to mailbox; leader waits for user command.\n * - `ask`: Send ask to mailbox; leader prompts user for permission.\n * - `auto`: Spawn a fix subagent automatically with the review report.\n */\n autoFix?: 'off' | 'ask' | 'auto' | undefined;\n /**\n * Cascade severity threshold for follow-up agents. When the post-session\n * review finds findings at or above this level, security-scanner and/or\n * bug-hunter agents are spawned to investigate and fix. Mirrors the\n * auto-review plugin's cascadeOn. Default: \"off\" (no cascade).\n */\n cascadeOn?: 'off' | 'critical' | 'high' | undefined;\n /**\n * Maximum cascade fix\u2192re-review cycles before the self-correcting loop\n * stops. Default: 2. 0 disables re-review (fix agents run once, no\n * re-check). Mirrors the auto-review plugin's maxCascadeDepth.\n */\n maxCascadeDepth?: number | undefined;\n /**\n * @deprecated Removed. The subagent's `Request.maxTokens` now defaults to\n * the provider's `capabilities.maxOutput`, so Chimera reports can run up\n * to the selected model's native ceiling. Kept on the config interface as an `unknown` sink\n * so old config files don't crash \u2014 but it's no longer read.\n */\n maxTokens?: unknown;\n}\n\nconst DEFAULT_MAX_FILES = 15;\nconst DEFAULT_CASCADE_ON = 'off' as const;\nconst DEFAULT_MAX_CASCADE_DEPTH = 2;\n\nexport function resolveChimeraConfig(\n cfg: ChimeraConfig,\n sessionProvider: string,\n sessionModel: string,\n): ResolvedChimeraConfig {\n return {\n enabled: cfg.enabled !== false,\n provider: cfg.provider ?? sessionProvider,\n model: cfg.model ?? sessionModel,\n maxFiles: cfg.maxFiles ?? DEFAULT_MAX_FILES,\n autoFix: cfg.autoFix ?? 'off',\n cascadeOn: cfg.cascadeOn ?? DEFAULT_CASCADE_ON,\n maxCascadeDepth: cfg.maxCascadeDepth ?? DEFAULT_MAX_CASCADE_DEPTH,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Event payload emitted on session.ended when chimera is enabled\n// ---------------------------------------------------------------------------\n\n// ---------------------------------------------------------------------------\n// System prompt for the subagent (matches packages/core/skills/chimera/SKILL.md)\n// ---------------------------------------------------------------------------\nexport const CHIMERA_REVIEW_PROMPT = readBundledInstructionText('llm/chimera-review.md');\n\n// ---------------------------------------------------------------------------\n// Git helpers\n// ---------------------------------------------------------------------------\nasync function runGit(\n args: string[],\n cwd: string,\n): Promise<{ stdout: string; stderr: string; code: number }> {\n return new Promise((resolve, reject) => {\n let child;\n try {\n child = spawn('git', args, {\n cwd,\n stdio: ['ignore', 'pipe', 'pipe'],\n signal: AbortSignal.timeout(15_000),\n windowsHide: true,\n });\n } catch (err) {\n // `spawn` throws synchronously when the binary is not found (e.g.,\n // git not installed on Windows). Reject the promise so callers can\n // handle it gracefully instead of surfacing as an unhandled rejection.\n reject(err);\n return;\n }\n let stdout = '';\n let stderr = '';\n child.stdout?.on('data', (d) => { stdout += d; });\n child.stderr?.on('data', (d) => { stderr += d; });\n child.on('error', () => resolve({ stdout, stderr, code: 1 }));\n child.on('close', (code) => resolve({ stdout, stderr, code: code ?? 0 }));\n });\n}\n\nasync function isGitRepo(cwd: string): Promise<boolean> {\n const r = await runGit(['rev-parse', '--git-dir'], cwd);\n return r.code === 0;\n}\n\ninterface ChangedFile {\n path: string;\n status: 'added' | 'modified';\n}\n\nasync function getChangedFiles(cwd: string): Promise<ChangedFile[]> {\n const r = await runGit(['status', '--porcelain'], cwd);\n if (r.code !== 0) return [];\n const files: ChangedFile[] = [];\n for (const line of r.stdout.split('\\n')) {\n if (!line.trim()) continue;\n const statusCode = line.slice(0, 2).trim();\n const filePath = line.slice(3).trim();\n if (statusCode === 'A' || statusCode === 'A ' || statusCode === ' A' || statusCode === '??') {\n files.push({ path: filePath, status: 'added' });\n } else if (statusCode.includes('M')) {\n files.push({ path: filePath, status: 'modified' });\n }\n }\n return files;\n}\n\n// ---------------------------------------------------------------------------\n// Slash command\n// ---------------------------------------------------------------------------\nfunction buildChimeraCommand(\n getConfig: () => ResolvedChimeraConfig,\n events: EventBus,\n): SlashCommand {\n return {\n name: 'chimera',\n category: 'Session',\n description: 'Show Chimera post-session review agent status and configuration.',\n help: [\n '\u2554\u2550\u2550\u2550 Chimera \u2550\u2550\u2550\u2557',\n '',\n 'Post-session code quality guardian. Reviews files changed during',\n 'each session using a dedicated read-only subagent.',\n '',\n 'Commands:',\n ' /chimera Show current status',\n ' /review Manually review changed files now',\n '',\n 'Configuration (edit config.json):',\n ' extensions.wstack-chimera.enabled true | false',\n ' extensions.wstack-chimera.provider provider id',\n ' extensions.wstack-chimera.model model id',\n ' extensions.wstack-chimera.maxFiles max files (default 15)',\n ' extensions.wstack-chimera.autoFix off | ask | auto (default off)',\n ' extensions.wstack-chimera.cascadeOn off | critical | high (default off)',\n ' extensions.wstack-chimera.maxCascadeDepth max fix+re-review cycles (default 2)',\n '',\n 'Output cap: the subagent runs up to the provider\\'s model-native',\n 'output ceiling (Anthropic 64K, OpenAI 16K, Gemini 8K). No manual cap.',\n ].join('\\n'),\n async run(args) {\n const cfg = getConfig();\n const trimmed = (args ?? '').trim();\n\n // Subcommand: /chimera autoFix <off|ask|auto>\n if (trimmed.startsWith('autoFix') || trimmed.startsWith('autofix')) {\n const mode = trimmed.split(/\\s+/)[1]?.toLowerCase();\n if (!mode || !['off', 'ask', 'auto'].includes(mode)) {\n return {\n message: [\n `Usage: /chimera autoFix <off|ask|auto>`,\n `Current: ${cfg.autoFix}`,\n '',\n ' off \u2014 send review result to mailbox; leader waits for your command.',\n ' ask \u2014 send review as an ask; leader prompts you for permission.',\n ' auto \u2014 send review result AND spawn a fix subagent automatically.',\n ].join('\\n'),\n };\n }\n // Emit a custom event so the execution layer can update agent.ctx.meta in real time.\n (events as never as { emit: (name: string, payload: { mode: string }) => void }).emit('chimera.set_autofix', { mode });\n return {\n message: `\u2705 Chimera autoFix set to \"${mode}\" for this session (config file unchanged).`,\n };\n }\n\n return {\n message: [\n `\uD83E\uDD82 Chimera \u2014 ${cfg.enabled ? 'enabled' : 'disabled'}`,\n '',\n ` Provider: ${cfg.provider}`,\n ` Model: ${cfg.model}`,\n ` Max files: ${cfg.maxFiles}`,\n ` Auto-fix: ${cfg.autoFix}`,\n ` Cascade: ${cfg.cascadeOn === 'off' ? 'disabled' : `on ${cfg.cascadeOn}+ \u2192 spawns security-scanner/bug-hunter`}`,\n ` Max depth: ${cfg.maxCascadeDepth} re-review cycle(s)`,\n ` Max output: model-native (no cap)`,\n '',\n cfg.enabled\n ? 'Auto-review runs after each session. /review triggers manually.'\n : 'Set extensions.wstack-chimera.enabled = true to enable.',\n ].join('\\n'),\n };\n },\n };\n}\n\n// \u2500\u2500 /review finding-store command \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nfunction buildReviewCommand(\n _getConfig: () => ResolvedChimeraConfig,\n): SlashCommand {\n return {\n name: 'review',\n category: 'Session',\n description: 'Query the Chimera Finding Store.',\n help: [\n 'Usage: /review findings [--severity <s>] [--status <s>] [--limit <n>]',\n ' /review finding <id>',\n ' /review status',\n '',\n 'The finding store persists structured findings from every Chimera review.',\n 'Use this to track what issues were found, their lifecycle, and outcomes.',\n ].join('\\n'),\n async run(args) {\n const cwd = process.cwd();\n const slug = projectSlug(cwd);\n const globalRoot = path.join(os.homedir(), '.wrongstack');\n const projectDir = path.join(globalRoot, 'projects', slug);\n const trimmed = (args ?? '').trim();\n const parts = trimmed.split(/\\s+/).filter(Boolean);\n return {\n message: await executeFindingCommand(parts, { projectDir }),\n };\n },\n };\n}\n\n// \u2500\u2500 Finding + report store persistence helper \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nasync function tryPersistFindings(payload: unknown): Promise<void> {\n if (!payload || typeof payload !== 'object') return;\n const p = payload as { bundle?: { cwd?: string }; reviewText?: string; status?: string; cwd?: string };\n const cwd = p.cwd ?? p.bundle?.cwd;\n if (!cwd) return;\n const slug = projectSlug(cwd);\n const globalRoot = path.join(os.homedir(), '.wrongstack');\n const projectDir = path.join(globalRoot, 'projects', slug);\n\n // One shared reportId links the finding store and the report store.\n const reportId = randomUUID();\n\n // Persist the report first (parent record), then findings (children).\n // If the process crashes between writes, an orphan report with no findings\n // is recoverable; orphan findings pointing at a nonexistent reportId are not.\n await persistReviewReport(payload as ChimeraReviewCompletePayload, reportId, projectDir);\n await integrateFindings(payload as ChimeraReviewCompletePayload, projectDir, reportId);\n}\n\n// ---------------------------------------------------------------------------\n// Plugin\n// ---------------------------------------------------------------------------\nexport function createChimeraPlugin(): Plugin {\n return {\n name: 'wstack-chimera',\n version: '1.0.0',\n description: 'Post-session code quality guardian with subagent review.',\n apiVersion: '^0.1',\n capabilities: { slashCommands: true },\n defaultConfig: {},\n\n setup(api) {\n // \u2500\u2500 Reactive config \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const recompute = (): ResolvedChimeraConfig => {\n const raw: ChimeraConfig =\n (api.config.extensions?.['wstack-chimera'] as ChimeraConfig | undefined) ?? {};\n return resolveChimeraConfig(raw, api.config.provider, api.config.model);\n };\n let resolved = recompute();\n\n api.onConfigChange(() => {\n const old = resolved;\n resolved = recompute();\n if (old.enabled !== resolved.enabled || old.provider !== resolved.provider || old.model !== resolved.model) {\n api.log.info(\n `[chimera] config changed \u2014 enabled=${resolved.enabled} provider=${resolved.provider} model=${resolved.model}`,\n );\n }\n });\n\n // Claim bookkeeping is cross-cutting session state, not Chimera feature\n // work. Keep it registered while disabled so config changes and reviews\n // emitted by other paths cannot leave stale in-flight claims behind.\n api.onPattern('chimera.review_needed', (_event, payload) => {\n recordStartedReview(api.events, payload);\n });\n api.onPattern('chimera.review_complete', (_event, payload) => {\n recordCompletedReview(api.events, payload);\n\n // FS-P0.6: Persist findings from the review into the finding store.\n // This runs even when chimera is disabled so findings from manual\n // reviews and other sessions are captured too.\n tryPersistFindings(payload).catch((err) => {\n api.log.warn(`[review-finding] failed to persist findings: ${toErrorMessage(err)}`);\n });\n });\n\n if (!resolved.enabled) {\n api.log.info('[chimera] disabled by config');\n return;\n }\n\n api.log.info(\n `[chimera] loaded \u2014 provider=${resolved.provider} model=${resolved.model} maxFiles=${resolved.maxFiles}`,\n );\n\n // \u2500\u2500 /chimera command \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n api.slashCommands.register(buildChimeraCommand(() => resolved, api.events));\n\n // \u2500\u2500 /review command (finding store) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n api.slashCommands.register(buildReviewCommand(() => resolved));\n\n // \u2500\u2500 session.ended \u2192 emit review event \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n api.onEvent('session.ended', async () => {\n try {\n const cfg = resolved;\n if (!cfg.enabled) return;\n\n const cwd = api.config.cwd ?? process.cwd();\n if (!(await isGitRepo(cwd))) {\n api.log.info('[chimera] skipped \u2014 not a git repo');\n return;\n }\n\n const allChanged = await getChangedFiles(cwd);\n const existing: ChangedFile[] = [];\n for (const f of allChanged) {\n if (f.path.startsWith('.wrongstack/')) continue;\n try { await fsp.access(path.join(cwd, f.path)); existing.push(f); } catch { /* deleted */ }\n }\n\n if (existing.length === 0) {\n api.log.info('[chimera] no changed files to review');\n return;\n }\n\n const toReview = existing.slice(0, cfg.maxFiles);\n if (existing.length > cfg.maxFiles) {\n api.log.info(`[chimera] capping review at ${cfg.maxFiles} of ${existing.length} files`);\n }\n\n // Read file contents\n const filesWithContent: ReviewFileEntry[] = [];\n for (const f of toReview) {\n try {\n const absPath = path.join(cwd, f.path);\n const content = await fsp.readFile(absPath, 'utf8');\n filesWithContent.push({ path: f.path, status: f.status, content });\n } catch { /* skip */ }\n }\n\n if (filesWithContent.length === 0) {\n api.log.info('[chimera] could not read changed files');\n return;\n }\n\n // \u2500\u2500 Build enriched review context (diffs, siblings, commits) \u2500\u2500\n const bundle: ReviewContextBundle = await buildReviewContext({\n cwd,\n config: cfg,\n files: filesWithContent,\n cascadeOn: cfg.cascadeOn,\n maxCascadeDepth: cfg.maxCascadeDepth,\n });\n\n // Atomically skip exact file content already claimed by a mid-session,\n // manual, or competing post-session review.\n const emittedBundle = emitReviewIfChanged(api, bundle);\n if (!emittedBundle) {\n api.log.info('[chimera] skipped \u2014 changed files already have reviews in progress');\n return;\n }\n\n api.log.info(`[chimera] emitted review_needed event (${emittedBundle.files.length} files)`);\n } catch (err) {\n api.log.warn(`[chimera] session.ended handler failed: ${toErrorMessage(err)}`);\n }\n });\n },\n\n teardown(api) {\n api.slashCommands.unregister('chimera');\n api.slashCommands.unregister('review');\n api.log.info('[chimera] unloaded');\n },\n\n async health() {\n return { ok: true, message: 'chimera ready' };\n },\n };\n}\n", "/**\n * Finding-store slash commands.\n *\n * FS-P0.5: Provides `/review findings` and `/review finding <id>` commands\n * for viewing persisted Chimera review findings.\n *\n * @module review-finding-commands\n */\n\nimport { FINDING_DEFAULT_PAGE_SIZE } from './review-finding-store.js';\nimport { syncReportCompletion, syncReportReopen } from './review-report-integration.js';\nimport type { ReviewReport, ReportLifecycleStatus } from './review-report-types.js';\nimport type { FindingSeverity, FindingStatus, ResolutionOutcome } from './review-finding-types.js';\n\n/**\n * Run the review findings command.\n *\n * Usage:\n * /review findings [--severity <s>] [--status <s>] [--limit <n>]\n * /review finding <id>\n * /review findings --help\n *\n * Reads the project's finding store from the project root.\n */\nexport interface FindingCommandContext {\n /** Project root directory (~/.wrongstack/projects/<slug>) */\n projectDir: string;\n}\n\n/**\n * Execute a finding-store command.\n */\nexport async function executeFindingCommand(\n args: string[],\n ctx: FindingCommandContext,\n): Promise<string> {\n if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {\n return helpText();\n }\n\n const subcommand = args[0]!;\n\n if (subcommand === 'findings' || subcommand === 'list') {\n return listFindings(args.slice(1), ctx);\n }\n\n if (subcommand === 'finding') {\n const id = args[1];\n if (!id) return 'Usage: /review finding <id> [resolve|ignore|reopen|triage|start]';\n const action = args[2];\n if (action === 'resolve' || action === 'ignore' || action === 'reopen' || action === 'triage' || action === 'start') {\n return transitionFinding(id, action, args.slice(3), ctx);\n }\n return showFinding(id, ctx);\n }\n\n if (subcommand === 'reports') {\n return listReports(args.slice(1), ctx);\n }\n\n if (subcommand === 'report') {\n const id = args[1];\n if (!id) return 'Usage: /review report <id> [complete|skip|action|note]';\n const action = args[2];\n if (action === 'complete' || action === 'skip' || action === 'action') {\n return transitionReport(id, action, args.slice(3), ctx);\n }\n if (action === 'note') {\n return addReportNote(id, args.slice(3), ctx);\n }\n return showReport(id, ctx);\n }\n\n if (subcommand === 'status') {\n return showStatus(ctx);\n }\n\n return `Unknown subcommand: ${subcommand}. Use /review findings --help for usage.`;\n}\n\nfunction helpText(): string {\n return [\n '## /review \u2014 Chimera Review Store',\n '',\n '| Command | Description |',\n '|---|---|',\n '| `/review findings` | List all active findings grouped by severity |',\n '| `/review findings --status <s>` | Filter by status (active, triaged, in_progress, resolved, ignored) |',\n '| `/review findings --severity <s>` | Filter by severity (critical, high, medium, low) |',\n '| `/review findings --limit <n>` | Max results (default 20) |',\n '| `/review finding <id>` | Show a single finding with full lifecycle |',\n '| `/review finding <id> resolve --outcome <fixed|wontfix|duplicate|false_positive|stale> [--reason \"...\"]` | Mark a finding resolved |',\n '| `/review finding <id> ignore [--reason \"...\"]` | Ignore a finding (wontfix) |',\n '| `/review finding <id> reopen [--reason \"...\"]` | Reopen a resolved/ignored finding back to active |',\n '| `/review finding <id> triage [--reason \"...\"]` | Acknowledge a finding (active \u2192 triaged) |',\n '| `/review finding <id> start [--reason \"...\"]` | Start work on a finding (triaged \u2192 in_progress) |',\n '| `/review reports` | List recent review reports |',\n '| `/review reports --status <s>` | Filter reports by lifecycle (open, actioned, completed, skipped) |',\n '| `/review report <id>` | Show a report with raw text, counts, and lifecycle events |',\n '| `/review report <id> complete [--reason \"...\"]` | Mark a report completed |',\n '| `/review report <id> skip [--reason \"...\"]` | Skip a report (wontfix) |',\n '| `/review report <id> action [--reason \"...\"]` | Mark a report as being actioned |',\n '| `/review report <id> note <message>` | Add an annotation without changing lifecycle |',\n '| `/review status` | Show store statistics |',\n '',\n 'Findings: `~/.wrongstack/projects/<slug>/review-findings.jsonl`',\n 'Reports: `~/.wrongstack/projects/<slug>/review-reports.jsonl`',\n ].join('\\n');\n}\n\nasync function loadStore(ctx: FindingCommandContext) {\n const { JsonlFindingStore } = await import('./review-finding-store.js');\n const store = new JsonlFindingStore(ctx.projectDir);\n return store;\n}\n\nasync function listFindings(\n args: string[],\n ctx: FindingCommandContext,\n): Promise<string> {\n let severityFilter: string | undefined;\n let statusFilter: string | undefined;\n let limit = 20;\n\n for (let i = 0; i < args.length; i++) {\n if (args[i] === '--severity' && i + 1 < args.length) {\n severityFilter = args[++i]!;\n } else if (args[i] === '--status' && i + 1 < args.length) {\n statusFilter = args[++i]!;\n } else if (args[i] === '--limit' && i + 1 < args.length) {\n limit = Number.parseInt(args[++i]!, 10) || 20;\n }\n }\n\n const store = await loadStore(ctx);\n const all = await store.list({\n ...(severityFilter ? { severities: [severityFilter as FindingSeverity] } : {}),\n ...(statusFilter ? { statuses: [statusFilter as FindingStatus] } : {}),\n limit,\n });\n\n if (all.length === 0) {\n const filters = [severityFilter && `severity=${severityFilter}`, statusFilter && `status=${statusFilter}`]\n .filter(Boolean).join(', ');\n return `No findings found${filters ? ` (${filters})` : ''}.`;\n }\n\n const lines: string[] = ['| Severity | Status | File | Title |',\n '|---|---|---|---|'];\n for (const f of all) {\n const location = f.location?.file ?? 'unknown';\n const file = location.substring(location.lastIndexOf('/') + 1).substring(location.lastIndexOf('\\\\') + 1) || location;\n const severityEmoji = f.severity === 'critical' ? '\uD83D\uDD34' : f.severity === 'high' ? '\uD83D\uDFE0' : f.severity === 'medium' ? '\uD83D\uDFE1' : '\u26AA';\n const title = f.title.length > 60 ? f.title.substring(0, 57) + '...' : f.title;\n lines.push(`| ${severityEmoji} ${f.severity} | ${f.status} | \\`${file}\\` | ${title} |`);\n }\n\n lines.push('', `_${all.length} finding(s) shown. Use \\`/review finding <id>\\` for details._`);\n return lines.join('\\n');\n}\n\nasync function showFinding(id: string, ctx: FindingCommandContext): Promise<string> {\n const store = await loadStore(ctx);\n const finding = await store.get(id);\n if (!finding) return `Finding not found: ${id}`;\n\n const lines: string[] = [\n `## ${finding.severity.toUpperCase()}: ${finding.title}`,\n '',\n `**ID:** \\`${finding.id}\\``,\n `**File:** \\`${finding.location?.file ?? 'unknown'}\\`${finding.location?.line ? `:${finding.location.line}` : ''}`,\n `**Severity:** ${finding.severity}`,\n `**Status:** ${finding.status}`,\n `**Source:** ${finding.source}`,\n `**Created:** ${finding.createdAt}`,\n '',\n finding.description,\n ];\n\n if (finding.suggestedFix) {\n lines.push('', '**Suggested fix:**', finding.suggestedFix);\n }\n\n const events = await store.getEvents(id);\n if (events.length > 0) {\n lines.push('', '**Lifecycle:**', '');\n for (const ev of events) {\n const eventLine = `- \\`${ev.timestamp}\\` ${ev.fromStatus ?? 'none'} \u2192 ${ev.toStatus} (${ev.eventType}) by ${ev.actorId}`;\n lines.push(eventLine);\n if (ev.reason) lines.push(` _${ev.reason}_`);\n }\n }\n\n lines.push('', `_Fingerprint: \\`${finding.fingerprint.substring(0, 16)}\u2026\\`_`);\n return lines.join('\\n');\n}\n\n// \u2500\u2500 Finding lifecycle commands \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Valid resolution outcomes for the `resolve` action. */\nconst VALID_RESOLUTION_OUTCOMES: readonly ResolutionOutcome[] = ['fixed', 'wontfix', 'duplicate', 'false_positive', 'stale'];\n\n/**\n * Transition a finding's lifecycle, then sync the parent report.\n *\n * - `resolve` \u2192 finding becomes resolved, report may auto-complete\n * - `ignore` \u2192 finding becomes ignored, report may auto-complete\n * - `reopen` \u2192 finding becomes active, terminal report auto-reopens\n * - `triage` \u2192 finding becomes triaged (acknowledged, pending work)\n * - `start` \u2192 finding becomes in_progress (work actively started)\n *\n * Usage: /review finding <id> resolve [--reason \"...\"] [--outcome <outcome>]\n * /review finding <id> ignore [--reason \"...\"]\n * /review finding <id> reopen [--reason \"...\"]\n * /review finding <id> triage [--reason \"...\"]\n * /review finding <id> start [--reason \"...\"]\n */\nasync function transitionFinding(\n id: string,\n action: 'resolve' | 'ignore' | 'reopen' | 'triage' | 'start',\n extraArgs: string[],\n ctx: FindingCommandContext,\n): Promise<string> {\n // Parse optional --reason and --outcome from extra args.\n let reason: string | undefined;\n let outcome: string | undefined;\n for (let i = 0; i < extraArgs.length; i++) {\n if (extraArgs[i] === '--reason' && i + 1 < extraArgs.length) {\n reason = extraArgs[++i];\n } else if (extraArgs[i] === '--outcome' && i + 1 < extraArgs.length) {\n outcome = extraArgs[++i];\n }\n }\n\n const store = await loadStore(ctx);\n const finding = await store.get(id);\n if (!finding) return `Finding not found: ${id}`;\n\n // Treat empty/whitespace-only reason as undefined.\n const cleanReason = reason && reason.trim().length > 0 ? reason : undefined;\n\n // Normalize outcome: treat empty/whitespace-only as undefined (like reason).\n const cleanOutcome = outcome && outcome.trim().length > 0 ? outcome : undefined;\n\n // \u2500\u2500 Reopen path \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n if (action === 'reopen') {\n if (cleanOutcome) {\n return `\u26A0\uFE0F \\`--outcome\\` only applies to \\`resolve\\`. Usage: \\`/review finding ${id} reopen --reason \"...\"\\``;\n }\n try {\n await store.transition(finding.id, 'active', { id: 'operator', kind: 'operator' }, {\n ...(cleanReason !== undefined ? { reason: cleanReason } : {}),\n });\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return `Could not reopen finding ${id}: ${msg}`;\n }\n\n const lines: string[] = [\n `\u2705 Finding \\`${id}\\` reopened as **active**.`,\n ];\n\n // Auto-reopen: if the parent report was completed/skipped, reopen it.\n const reportId = finding.originReport?.reportId;\n if (reportId) {\n try {\n const reopenResult = await syncReportReopen(reportId, ctx.projectDir, {\n id: 'operator',\n kind: 'operator',\n }, cleanReason);\n if (reopenResult.reopened) {\n lines.push('', `\uD83D\uDD35 Report \\`${reportId}\\` auto-reopened \u2014 was ${reopenResult.previousLifecycle}.`);\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.warn(JSON.stringify({ level: 'warn', event: 'review_auto_reopen_failed', reportId, message: msg }));\n }\n }\n\n return lines.join('\\n');\n }\n\n // \u2500\u2500 Triage path \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n if (action === 'triage') {\n if (cleanOutcome) {\n return `\u26A0\uFE0F \\`--outcome\\` only applies to \\`resolve\\`. Usage: \\`/review finding ${id} triage --reason \"...\"\\``;\n }\n try {\n await store.transition(finding.id, 'triaged', { id: 'operator', kind: 'operator' }, {\n ...(cleanReason !== undefined ? { reason: cleanReason } : {}),\n });\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return `Could not triage finding ${id}: ${msg}`;\n }\n\n return `\u2705 Finding \\`${id}\\` marked as **triaged**.`;\n }\n\n // \u2500\u2500 Start path \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n if (action === 'start') {\n if (cleanOutcome) {\n return `\u26A0\uFE0F \\`--outcome\\` only applies to \\`resolve\\`. Usage: \\`/review finding ${id} start --reason \"...\"\\``;\n }\n try {\n await store.transition(finding.id, 'in_progress', { id: 'operator', kind: 'operator' }, {\n ...(cleanReason !== undefined ? { reason: cleanReason } : {}),\n });\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return `Could not start finding ${id}: ${msg}`;\n }\n\n return `\u2705 Finding \\`${id}\\` marked as **in_progress**.`;\n }\n\n // \u2500\u2500 Resolve / Ignore path \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const targetStatus = action === 'resolve' ? 'resolved' : 'ignored';\n\n // --outcome has no meaning for ignore; reject rather than silently discard.\n if (action === 'ignore' && cleanOutcome) {\n return `\u26A0\uFE0F \\`--outcome\\` only applies to \\`resolve\\`. Usage: \\`/review finding ${id} ignore --reason \"...\"\\``;\n }\n\n // Validate outcome against the known ResolutionOutcome union.\n // When resolving without an explicit outcome, default to 'fixed'.\n if (action === 'resolve' && cleanOutcome && !VALID_RESOLUTION_OUTCOMES.includes(cleanOutcome as ResolutionOutcome)) {\n return `Invalid outcome \"${cleanOutcome}\". Valid values: ${VALID_RESOLUTION_OUTCOMES.join(', ')}`;\n }\n const resolvedOutcome: ResolutionOutcome | undefined =\n action === 'resolve'\n ? ((cleanOutcome as ResolutionOutcome | undefined) ?? 'fixed')\n : undefined;\n\n try {\n await store.transition(finding.id, targetStatus, { id: 'operator', kind: 'operator' }, {\n ...(cleanReason !== undefined ? { reason: cleanReason } : {}),\n ...(resolvedOutcome ? { outcome: resolvedOutcome } : {}),\n });\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return `Could not transition finding ${id} to ${targetStatus}: ${msg}`;\n }\n\n const lines: string[] = [\n `\u2705 Finding \\`${id}\\` marked as **${targetStatus}**.`,\n ];\n\n // Auto-completion: check if the parent report can be closed.\n // originReport is typed as required, but corrupt JSONL or old-format data\n // may be missing it \u2014 guard to keep auto-completion best-effort.\n const reportId = finding.originReport?.reportId;\n if (reportId) {\n try {\n const syncResult = await syncReportCompletion(reportId, ctx.projectDir, {\n id: 'operator',\n kind: 'operator',\n });\n if (syncResult.completed) {\n lines.push('', `\uD83D\uDFE2 Report \\`${reportId}\\` auto-completed \u2014 all ${syncResult.totalFindings} finding(s) resolved or ignored.`);\n } else if (syncResult.totalFindings > 0 && syncResult.remaining > 0) {\n lines.push(`_Report \\`${reportId}\\`: ${syncResult.remaining} of ${syncResult.totalFindings} finding(s) still open._`);\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.warn(JSON.stringify({ level: 'warn', event: 'review_auto_completion_failed', reportId, message: msg }));\n }\n }\n\n return lines.join('\\n');\n}\n\n// \u2500\u2500 Report commands \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nasync function loadReportStore(ctx: FindingCommandContext) {\n const { JsonlReportStore } = await import('./review-report-store.js');\n return new JsonlReportStore(ctx.projectDir);\n}\n\nconst LIFECYCLE_EMOJI: Record<string, string> = {\n open: '\uD83D\uDD35',\n actioned: '\uD83D\uDFE1',\n completed: '\uD83D\uDFE2',\n skipped: '\u26AA',\n};\n\nasync function listReports(\n args: string[],\n ctx: FindingCommandContext,\n): Promise<string> {\n let statusFilter: string | undefined;\n let limit = 15;\n\n for (let i = 0; i < args.length; i++) {\n if (args[i] === '--status' && i + 1 < args.length) {\n statusFilter = args[++i]!;\n } else if (args[i] === '--limit' && i + 1 < args.length) {\n limit = Number.parseInt(args[++i]!, 10) || 15;\n }\n }\n\n const store = await loadReportStore(ctx);\n const reports = await store.list({\n ...(statusFilter ? { statuses: [statusFilter as ReportLifecycleStatus] } : {}),\n limit,\n });\n\n if (reports.length === 0) {\n return `No reports found${statusFilter ? ` (status=${statusFilter})` : ''}.`;\n }\n\n const lines: string[] = [\n '| Lifecycle | Source | Findings | Reviewed | Report |',\n '|---|---|---|---|---|',\n ];\n for (const r of reports) {\n const emoji = LIFECYCLE_EMOJI[r.lifecycle] ?? '\u26AA';\n const total = r.counts.critical + r.counts.high + r.counts.medium + r.counts.low;\n const sevSummary = total === 0 ? 'clean' : [\n r.counts.critical > 0 && `${r.counts.critical}\uD83D\uDD34`,\n r.counts.high > 0 && `${r.counts.high}\uD83D\uDFE0`,\n r.counts.medium > 0 && `${r.counts.medium}\uD83D\uDFE1`,\n r.counts.low > 0 && `${r.counts.low}\u26AA`,\n ].filter(Boolean).join(' ');\n const date = r.reviewedAt.substring(0, 10);\n const id = r.id.substring(0, 8);\n lines.push(`| ${emoji} ${r.lifecycle} | ${r.source} | ${sevSummary} | ${date} | \\`${id}\\` |`);\n }\n\n lines.push('', `_${reports.length} report(s). Use \\`/review report <id>\\` for details._`);\n return lines.join('\\n');\n}\n\n/**\n * Resolve a report by exact ID or short-ID prefix (\u22658 chars).\n * Exported for integration testing.\n */\nexport async function resolveReportId(\n store: Awaited<ReturnType<typeof loadReportStore>>,\n id: string,\n): Promise<ReviewReport | null> {\n const report = await store.get(id);\n if (report) return report;\n if (id.length >= 8) {\n const all = await store.list({ limit: 9999 });\n const match = all.find((r) => r.id.startsWith(id));\n if (match) return match;\n }\n return null;\n}\n\nasync function showReport(id: string, ctx: FindingCommandContext): Promise<string> {\n const store = await loadReportStore(ctx);\n const report = await resolveReportId(store, id);\n if (!report) return `Report not found: ${id}`;\n\n const emoji = LIFECYCLE_EMOJI[report.lifecycle] ?? '\u26AA';\n const lines: string[] = [\n `## ${emoji} Review Report \u2014 ${report.lifecycle}`,\n '',\n `**ID:** \\`${report.id}\\``,\n `**Reviewed:** ${report.reviewedAt}`,\n `**Source:** ${report.source}`,\n `**Reviewer model:** ${report.reviewerModel}`,\n `**Review status:** ${report.reviewStatus}`,\n ...(report.cascadeDepth !== undefined ? [`**Cascade depth:** ${report.cascadeDepth}`] : []),\n ...(report.durationSeconds !== undefined ? [`**Duration:** ${report.durationSeconds}s`] : []),\n '',\n '**Severity counts:**',\n ` \uD83D\uDD34 Critical: ${report.counts.critical}`,\n ` \uD83D\uDFE0 High: ${report.counts.high}`,\n ` \uD83D\uDFE1 Medium: ${report.counts.medium}`,\n ` \u26AA Low: ${report.counts.low}`,\n ` **Total findings:** ${report.totalFindings}`,\n ...(report.unparseableCount > 0 ? [` _${report.unparseableCount} unparseable_`] : []),\n ];\n\n if (report.files.length > 0) {\n lines.push('', '**Files reviewed:**');\n for (const f of report.files.slice(0, 20)) {\n lines.push(` - \\`${f.path}\\` (${f.status})`);\n }\n if (report.files.length > 20) {\n lines.push(` _...and ${report.files.length - 20} more_`);\n }\n }\n\n const events = await store.getEvents(report.id);\n if (events.length > 0) {\n lines.push('', '**Lifecycle events:**', '');\n for (const ev of events) {\n const transition = ev.fromLifecycle\n ? `${ev.fromLifecycle} \u2192 ${ev.toLifecycle}`\n : `\u2192 ${ev.toLifecycle}`;\n lines.push(`- \\`${ev.timestamp}\\` ${transition} (${ev.eventType}) by ${ev.actorId}`);\n if (ev.reason) lines.push(` _${ev.reason}_`);\n }\n }\n\n if (report.rawText?.trim()) {\n lines.push('', '<details><summary>Raw report text</summary>', '', report.rawText, '', '</details>');\n }\n\n return lines.join('\\n');\n}\n\n// \u2500\u2500 Report lifecycle commands \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Manually transition a report's lifecycle.\n *\n * Usage: /review report <id> complete [--reason \"...\"]\n * /review report <id> skip [--reason \"...\"]\n * /review report <id> action [--reason \"...\"]\n *\n * Maps to: complete \u2192 completed, skip \u2192 skipped, action \u2192 actioned.\n */\nexport async function transitionReport(\n id: string,\n action: 'complete' | 'skip' | 'action',\n extraArgs: string[],\n ctx: FindingCommandContext,\n): Promise<string> {\n // Parse optional --reason.\n let reason: string | undefined;\n for (let i = 0; i < extraArgs.length; i++) {\n if (extraArgs[i] === '--reason' && i + 1 < extraArgs.length) {\n reason = extraArgs[++i];\n }\n }\n\n const cleanReason = reason && reason.trim().length > 0 ? reason : undefined;\n\n const targetMap = { complete: 'completed', skip: 'skipped', action: 'actioned' } as const;\n const targetStatus = targetMap[action];\n\n const store = await loadReportStore(ctx);\n\n // Resolve short-ID prefix via shared helper.\n const report = await resolveReportId(store, id);\n if (!report) return `Report not found: ${id}`;\n\n try {\n await store.transition(report.id, targetStatus, { id: 'operator', kind: 'operator' }, {\n ...(cleanReason !== undefined ? { reason: cleanReason } : {}),\n });\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return `Could not transition report \\`${report.id}\\` to ${targetStatus}: ${msg}`;\n }\n\n const emoji = LIFECYCLE_EMOJI[targetStatus] ?? '\u26AA';\n return `${emoji} Report \\`${report.id}\\` marked as **${targetStatus}**.`;\n}\n\n/**\n * Add an annotation note to a report without changing its lifecycle status.\n *\n * Usage: /review report <id> note <message>\n */\nasync function addReportNote(\n id: string,\n extraArgs: string[],\n ctx: FindingCommandContext,\n): Promise<string> {\n // The note is everything after \"note\" \u2014 join the remaining args.\n const note = extraArgs.join(' ').trim();\n if (!note) {\n return 'Usage: /review report <id> note <message>';\n }\n\n const store = await loadReportStore(ctx);\n const report = await resolveReportId(store, id);\n if (!report) return `Report not found: ${id}`;\n\n try {\n await store.addNote(report.id, { id: 'operator', kind: 'operator' }, note);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return `Could not add note to report ${id}: ${msg}`;\n }\n\n return `\uD83D\uDCDD Note added to report \\`${report.id}\\`.`;\n}\n\nasync function showStatus(ctx: FindingCommandContext): Promise<string> {\n const store = await loadStore(ctx);\n const all = await store.list({ limit: 9999 });\n\n const counts: Record<string, number> = {};\n const severityCounts: Record<string, number> = {};\n for (const f of all) {\n counts[f.status] = (counts[f.status] || 0) + 1;\n severityCounts[f.severity] = (severityCounts[f.severity] || 0) + 1;\n }\n\n return [\n '## Finding Store Status',\n '',\n `**Total findings:** ${all.length}`,\n '',\n '**By status:**',\n ...Object.entries(counts).map(([k, v]) => ` - ${k}: ${v}`),\n '',\n '**By severity:**',\n ...Object.entries(severityCounts).map(([k, v]) => ` - ${k}: ${v}`),\n '',\n `_Page size: ${FINDING_DEFAULT_PAGE_SIZE}_`,\n ].join('\\n');\n}\n", "/**\n * Chimera review finding parser.\n *\n * FS-P0.2: Extracts structured ChimeraFinding[] from the canonical\n * Chimera review report format (### Severity (N) + numbered list items).\n *\n * The known report format is:\n * ### Critical (2)\n * 1. [BUG] path/file.ts:42 \u2014 title description\n * \u2192 Suggested fix line\n * 2. ...\n *\n * ### High (1)\n * 1. ...\n *\n * @module review-finding-parser\n */\n\nimport { randomUUID } from 'node:crypto';\nimport type { ChimeraFinding, FindingSeverity, FindingSource } from './review-finding-types.js';\nimport { computeFindingFingerprint } from './review-finding-types.js';\n\n/**\n * Parsed result from a Chimera review report.\n */\nexport interface ParsedReviewReport {\n /** All extracted findings (parsable items). */\n findings: ChimeraFinding[];\n /** Number of severity-counted items that could NOT be parsed individually. */\n unparseableCount: number;\n /** Total time for the review, extracted from \"Duration: Xs\" line. */\n durationSeconds?: number | undefined;\n}\n\n/** Match a `\u2192` or `->` suggestion line. */\nconst SUGGEST_LINE = /^\\s*(?:\u2192|->|=>)\\s*(.+)$/;\n\n/** Match a `Duration: 123s` line. */\nconst DURATION_LINE = /^Duration:\\s*(\\d+)s\\s*$/im;\n\n/**\n * Parse a Chimera review report text into structured findings.\n *\n * @param reportText - Full Markdown report from a Chimera review.\n * @param context - Session/report context for stamping findings.\n * @returns Parsed findings and metadata.\n */\nexport function parseChimeraReviewReport(\n reportText: string,\n context: {\n sessionId?: string | undefined;\n agentId?: string | undefined;\n reviewType?: string | undefined;\n reviewerModel?: string | undefined;\n reportId?: string | undefined;\n } = {},\n): ParsedReviewReport {\n if (!reportText || reportText.trim().length === 0) {\n return { findings: [], unparseableCount: 0 };\n }\n\n const findings: ChimeraFinding[] = [];\n const reportId = context.reportId ?? randomUUID();\n let unparseableCount = 0;\n let durationSeconds: number | undefined;\n\n let currentSeverity: FindingSeverity | null = null;\n let currentLines: string[] = [];\n\n const lines = reportText.split('\\n');\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!;\n\n // Check for severity heading\n const headingMatch = line.trim().match(/^###\\s+(critical|high|medium|low)\\b/i);\n if (headingMatch) {\n // Flush previous section\n flushSection();\n\n currentSeverity = headingMatch[1]!.toLowerCase() as FindingSeverity;\n continue;\n }\n\n // Check for duration line\n const durMatch = line.match(DURATION_LINE);\n if (durMatch) {\n durationSeconds = Number.parseInt(durMatch[1]!, 10);\n continue;\n }\n\n // Accumulate lines in the current section\n if (currentSeverity !== null) {\n currentLines.push(line);\n }\n }\n\n // Flush the last section\n flushSection();\n\n return { findings, unparseableCount, durationSeconds };\n\n /** Parse accumulated section lines into findings. */\n function flushSection(): void {\n if (currentSeverity === null || currentLines.length === 0) {\n currentSeverity = null;\n currentLines = [];\n return;\n }\n\n const combined = currentLines.join('\\n');\n // Split by numbered items\n const segments = combined.split(/\\n\\s*(?=\\d+\\.\\s)/).filter((s) => s.trim().length > 0);\n\n for (const segment of segments) {\n const finding = parseFindingSegment(segment, currentSeverity!, { ...context, reportId });\n if (finding) {\n findings.push(finding);\n } else {\n unparseableCount++;\n }\n }\n\n currentSeverity = null;\n // expectedCount was not stored; reset is implicit in severity/lines\n currentLines = [];\n }\n}\n\n/**\n * Parse a single finding segment (one numbered item + its suggestion lines).\n */\nfunction parseFindingSegment(\n segment: string,\n severity: FindingSeverity,\n context: {\n sessionId?: string | undefined;\n agentId?: string | undefined;\n reviewType?: string | undefined;\n reviewerModel?: string | undefined;\n reportId?: string | undefined;\n },\n): ChimeraFinding | null {\n const lines = segment.split('\\n').map((l) => l.trim()).filter((l) => l.length > 0);\n if (lines.length === 0) return null;\n\n // The first line should be the finding line: \"N. [TAG] file:line \u2014 Description\"\n const first = lines[0]!;\n const match = first.match(/^\\d+\\.\\s+(.*)$/);\n if (!match) return null;\n\n const content = match[1]!.trim();\n\n // Extract [TAG] prefix if present\n let remaining = content;\n const tagMatch = content.match(/^\\[(\\w+)\\]\\s*/);\n if (tagMatch) {\n remaining = content.slice(tagMatch[0].length).trim();\n }\n\n // Extract file:line reference before the ` \u2014 ` or ` - ` separator\n let file: string | undefined;\n let line: number | undefined;\n let desc = remaining;\n\n const refMatch = remaining.match(/^(.+?)(?::(\\d+))?\\s*[\u2014\u2013-]\\s*(.+)$/);\n if (refMatch) {\n file = refMatch[1]!.trim();\n if (refMatch[2] !== undefined) {\n line = Number.parseInt(refMatch[2]!, 10);\n }\n desc = refMatch[3]!.trim();\n }\n\n // Fallback: if the remaining text contains a colon-separated path, extract\n if (!file) {\n const pathMatch = remaining.match(/^([a-zA-Z_./\\\\][a-zA-Z0-9_./\\\\-]*\\.\\w+)(?::(\\d+))?/);\n if (pathMatch) {\n file = pathMatch[1]!.trim();\n if (pathMatch[2] !== undefined) {\n line = Number.parseInt(pathMatch[2]!, 10);\n }\n // Remove the file ref from the description\n const afterFile = remaining.slice(pathMatch[0].length).trim();\n desc = afterFile.replace(/^[\u2014\u2013-]\\s*/, '').trim() || desc;\n }\n }\n\n const cleanDesc = desc.replace(/^[\u2014\u2013-]\\s*/, '').trim();\n\n // Collect suggestion lines (\u2192 or -> or =>)\n const suggestions: string[] = [];\n for (let i = 1; i < lines.length; i++) {\n const suggest = lines[i]!.match(SUGGEST_LINE);\n if (suggest) {\n suggestions.push(suggest[1]!.trim());\n }\n }\n\n // Build title from description (first sentence or truncated)\n const title = cleanDesc.split(/\\.\\s/)[0]!.trim() || content;\n // Full description includes the description + suggestions\n const fullDesc = suggestions.length > 0\n ? cleanDesc + '\\n' + suggestions.map((s) => ' \u2192 ' + s).join('\\n')\n : cleanDesc;\n\n const suggestedFix = suggestions.length > 0 ? suggestions.join('\\n') : undefined;\n\n return {\n id: randomUUID(),\n fingerprint: computeFindingFingerprint(file ?? '', line ?? null, title),\n severity,\n source: normalizeFindingSource(context.reviewType),\n ...(file ? { location: { file, ...(line !== undefined ? { line } : {}) } } : {}),\n title,\n description: fullDesc,\n ...(suggestedFix ? { suggestedFix } : {}),\n createdAt: new Date().toISOString(),\n status: 'active',\n originReport: {\n reportId: context.reportId ?? randomUUID(),\n sessionId: context.sessionId ?? '',\n agentId: context.agentId ?? '',\n reviewerModel: context.reviewerModel ?? '',\n },\n };\n}\n\nfunction normalizeFindingSource(reviewType: string | undefined): FindingSource {\n switch (reviewType) {\n case 'auto':\n case 'chimera':\n case 'cascade':\n case 'security-scanner':\n return reviewType;\n default:\n return 'chimera';\n }\n}\n", "/**\n * Chimera review report integration.\n *\n * Hooks into the chimera.review_complete event to persist a full ReviewReport\n * record (metadata + raw text + severity counts) for each completed review.\n *\n * This is the report-level complement to review-finding-integration.ts:\n * - finding-integration \u2192 individual findings (deduplicated, lifecycle-tracked)\n * - report-integration \u2192 the report as a whole (raw text, provenance, lifecycle)\n *\n * The two share the same `reportId` so `/review report <id>` can cross-link\n * to the findings that came from that report.\n *\n * @module review-report-integration\n */\n\nimport type { ChimeraReviewCompletePayload } from './review-types.js';\nimport { parseChimeraReviewReport } from './review-finding-parser.js';\nimport { JsonlFindingStore } from './review-finding-store.js';\nimport type { FindingSource } from './review-finding-types.js';\nimport { JsonlReportStore, type PersistReportInput } from './review-report-store.js';\nimport type { ReviewReportCounts, ReviewReportFile } from './review-report-types.js';\n\n/**\n * Result of a report integration run.\n */\nexport interface ReportIntegrationResult {\n /** The persisted report's ID. */\n reportId: string;\n /** Whether this was a new record or an update to an existing one. */\n created: boolean;\n /** Total findings parsed from the report text. */\n totalFindings: number;\n}\n\n/**\n * Persist a completed Chimera review as a structured report record.\n *\n * Extracts metadata from the payload (provenance, files, cascade depth) and\n * parses the raw review text for severity counts and duration. The full raw\n * text is stored verbatim so it can be displayed later.\n *\n * @param payload - The chimera.review_complete event payload.\n * @param reportId - The UUID to assign (should match findings' originReport.reportId).\n * @param projectDir - Project root (~/.wrongstack/projects/<slug>).\n * @returns Integration result summary.\n */\nexport async function persistReviewReport(\n payload: ChimeraReviewCompletePayload,\n reportId: string,\n projectDir: string,\n): Promise<ReportIntegrationResult> {\n const store = new JsonlReportStore(projectDir);\n const existed = await store.get(reportId);\n\n const source = classifySource(payload);\n const agentId = payload.bundle.fileProvenance?.find((entry) => entry.agentId)?.agentId\n ?? 'chimera-review';\n const sessionId = payload.sessionId ?? payload.cwd;\n const model = payload.bundle.config.model;\n const cascadeDepth = payload.bundle.cascadeDepth;\n\n const files: ReviewReportFile[] = payload.bundle.files.map((f) => ({\n path: f.path,\n status: f.status,\n }));\n\n const reviewStatus: 'success' | 'failed' =\n payload.status === 'success' ? 'success' : 'failed';\n\n // Parse the report for counts + duration. For failed reviews, rawText may\n // be empty \u2014 we still persist the record so there's an audit trail of the\n // attempt.\n const parsed = reviewStatus === 'success'\n ? parseChimeraReviewReport(payload.reviewText, { reportId })\n : { findings: [], unparseableCount: 0, durationSeconds: undefined };\n\n const counts: ReviewReportCounts = { critical: 0, high: 0, medium: 0, low: 0 };\n for (const finding of parsed.findings) {\n counts[finding.severity]++;\n }\n\n const input: PersistReportInput = {\n id: reportId,\n sessionId,\n agentId,\n reviewerModel: model,\n source,\n reviewStatus,\n files,\n counts,\n totalFindings: parsed.findings.length,\n unparseableCount: parsed.unparseableCount,\n durationSeconds: parsed.durationSeconds,\n rawText: payload.reviewText,\n ...(cascadeDepth !== undefined ? { cascadeDepth } : {}),\n };\n\n await store.persist(input);\n\n return {\n reportId,\n created: !existed,\n totalFindings: parsed.findings.length,\n };\n}\n\n/**\n * Result of a report-completion sync check.\n */\nexport interface ReportSyncResult {\n /** The report ID that was checked. */\n reportId: string;\n /** Whether the report was transitioned to completed. */\n completed: boolean;\n /** Total findings linked to this report. */\n totalFindings: number;\n /** How many are still in a non-terminal status. */\n remaining: number;\n}\n\n/**\n * Check whether all findings linked to a report are in terminal states\n * (resolved or ignored) and transition the report to `completed` if so.\n *\n * Called after a finding transition to provide auto-completion of the\n * parent report. This function is idempotent: if the report is already\n * completed/skipped, it does nothing.\n *\n * Edge cases:\n * - Zero findings: no-op (an empty report stays open until manually closed).\n * - Report not found: returns `{ completed: false }`.\n * - Report already terminal: no-op.\n *\n * @param reportId - The report to check.\n * @param projectDir - Project root (~/.wrongstack/projects/<slug>).\n * @param actor - Who/what is triggering the sync.\n */\nexport async function syncReportCompletion(\n reportId: string,\n projectDir: string,\n actor: { id: string; kind: 'agent' | 'operator' | 'system' },\n): Promise<ReportSyncResult> {\n const reportStore = new JsonlReportStore(projectDir);\n const findingStore = new JsonlFindingStore(projectDir);\n\n const report = await reportStore.get(reportId);\n if (!report) {\n return { reportId, completed: false, totalFindings: 0, remaining: 0 };\n }\n\n // Already closed out \u2014 nothing to do.\n if (report.lifecycle === 'completed' || report.lifecycle === 'skipped') {\n return { reportId, completed: false, totalFindings: 0, remaining: 0 };\n }\n\n const findings = await findingStore.list({ reportId, limit: 9999 });\n const total = findings.length;\n\n // Don't auto-complete reports with zero findings \u2014 they need manual closure.\n if (total === 0) {\n return { reportId, completed: false, totalFindings: 0, remaining: 0 };\n }\n\n const remaining = findings.filter(\n (f) => f.status !== 'resolved' && f.status !== 'ignored',\n ).length;\n\n if (remaining > 0) {\n return { reportId, completed: false, totalFindings: total, remaining };\n }\n\n // All findings are terminal \u2014 transition the report.\n await reportStore.transition(reportId, 'completed', actor, {\n reason: `All ${total} finding(s) resolved or ignored`,\n });\n\n return { reportId, completed: true, totalFindings: total, remaining: 0 };\n}\n\n/**\n * Result of a report-reopen sync check.\n */\nexport interface ReportReopenResult {\n /** The report ID that was checked. */\n reportId: string;\n /** Whether the report was transitioned from terminal back to open. */\n reopened: boolean;\n /** The lifecycle status the report had before the check. */\n previousLifecycle: string;\n}\n\n/**\n * Reopen a completed or skipped report when one of its findings transitions\n * back to an active state.\n *\n * This is the inverse of `syncReportCompletion`: when a finding in a\n * terminal report is reopened (e.g. resolved \u2192 active), the parent report\n * should also reopen so it's not falsely marked as done.\n *\n * Edge cases:\n * - Report already open/actioned: no-op.\n * - Report not found: returns `{ reopened: false }`.\n * - Report completed or skipped: transitions to `open`.\n *\n * @param reportId - The report to check.\n * @param projectDir - Project root (~/.wrongstack/projects/<slug>).\n * @param actor - Who/what is triggering the sync.\n * @param reason - Optional reason for the reopen.\n */\nexport async function syncReportReopen(\n reportId: string,\n projectDir: string,\n actor: { id: string; kind: 'agent' | 'operator' | 'system' },\n reason?: string,\n): Promise<ReportReopenResult> {\n const reportStore = new JsonlReportStore(projectDir);\n\n const report = await reportStore.get(reportId);\n if (!report) {\n return { reportId, reopened: false, previousLifecycle: 'not_found' };\n }\n\n // Only terminal reports need reopening.\n if (report.lifecycle !== 'completed' && report.lifecycle !== 'skipped') {\n return { reportId, reopened: false, previousLifecycle: report.lifecycle };\n }\n\n await reportStore.transition(reportId, 'open', actor, {\n reason: reason ?? `Finding reopened \u2014 report was ${report.lifecycle}`,\n });\n\n return { reportId, reopened: true, previousLifecycle: report.lifecycle };\n}\n\n/**\n * Classify the review source from the payload bundle.\n *\n * Mirrors the logic in review-finding-integration.ts so reports and findings\n * agree on source classification.\n */\nfunction classifySource(payload: ChimeraReviewCompletePayload): FindingSource {\n const cascadeDepth = payload.bundle.cascadeDepth ?? 0;\n if (cascadeDepth > 0) return 'cascade';\n const cascadeOn = payload.bundle.cascadeOn;\n if (cascadeOn !== undefined && cascadeOn !== 'off') return 'auto';\n return 'chimera';\n}\n", "/**\n * Chimera finding auto-integration.\n *\n * FS-P0.6: Hooks into the chimera.review_complete event to persist\n * structured findings from every review report.\n *\n * @module review-finding-integration\n */\n\nimport type { ChimeraReviewCompletePayload } from './review-types.js';\nimport { parseChimeraReviewReport } from './review-finding-parser.js';\nimport { JsonlFindingStore } from './review-finding-store.js';\n\n/**\n * Result of a findings integration run.\n */\nexport interface FindingsIntegrationResult {\n /** Number of new findings created. */\n created: number;\n /** Number of existing findings relinked. */\n relinked: number;\n /** Number of resolved/ignored findings reopened. */\n reopened: number;\n /** Report ID if any findings were upserted. */\n reportId?: string | undefined;\n /** Total findings count in the report. */\n totalFindings: number;\n /** Unparseable item count. */\n unparseableCount: number;\n}\n\n/**\n * Integrate findings from a completed Chimera review into the\n * project's finding store.\n *\n * Parses the review report text, upserts all findings, and\n * returns a summary.\n */\nexport async function integrateFindings(\n payload: ChimeraReviewCompletePayload,\n projectDir: string,\n reportId: string,\n): Promise<FindingsIntegrationResult> {\n if (!payload.reviewText || payload.reviewText.trim().length === 0) {\n return { created: 0, relinked: 0, reopened: 0, totalFindings: 0, unparseableCount: 0 };\n }\n\n const store = new JsonlFindingStore(projectDir);\n const source = (payload.bundle.cascadeDepth ?? 0) > 0\n ? 'cascade'\n : payload.bundle.cascadeOn !== undefined && payload.bundle.cascadeOn !== 'off'\n ? 'auto'\n : 'chimera';\n const agentId = payload.bundle.fileProvenance?.find((entry) => entry.agentId)?.agentId\n ?? 'chimera-review';\n const sessionId = payload.sessionId ?? payload.cwd;\n const model = payload.bundle.config.model;\n\n const parsed = parseChimeraReviewReport(payload.reviewText, {\n sessionId,\n agentId,\n reviewerModel: model,\n reviewType: source,\n reportId,\n });\n\n if (parsed.findings.length === 0) {\n return {\n created: 0, relinked: 0, reopened: 0,\n totalFindings: 0, unparseableCount: parsed.unparseableCount,\n };\n }\n\n const result = await store.upsert(parsed.findings, {\n sessionId,\n reportId,\n agentId,\n model,\n });\n\n return {\n created: result.created,\n relinked: result.relinked,\n reopened: result.reopened,\n reportId,\n totalFindings: parsed.findings.length,\n unparseableCount: parsed.unparseableCount,\n };\n}\n", "import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { DefaultPromptLoader, renderPrompt } from '../execution/prompt-loader.js';\nimport { DefaultPromptStore, migratePromptEntry } from '../storage/prompt-store.js';\nimport { PromptUsageStore } from '../storage/prompt-usage-store.js';\nimport type { PromptEntry, PromptLoader, PromptVariable } from '../types/prompt.js';\nimport type { WstackPaths } from '../utils/wstack-paths.js';\nimport { expectDefined } from '../utils/expect-defined.js';\nimport {\n readBundledInstructionText,\n renderInstructionTemplate,\n} from '../utils/instruction-file.js';\nimport type { Plugin } from '../types/plugin.js';\nimport type { SlashCommand, Context } from '../index.js';\n\ninterface PromptsPluginOptions {\n store?: DefaultPromptStore | undefined;\n loader?: PromptLoader | undefined;\n usage?: PromptUsageStore | undefined;\n paths?: WstackPaths | undefined;\n}\n\n/**\n * PromptsPlugin \u2014 built-in prompt library.\n *\n * Registers three slash commands:\n * - `/prompts` manage your library (list/view/add/edit/delete/favorite/extend)\n * - `/prompt` search the merged library (builtin + user + project) and insert\n * - `/prompt-gen` AI-guided authoring of a new high-quality prompt\n *\n * Active by default for all WrongStack sessions. The host injects a\n * `PromptLoader` (cross-layer read + copy-on-write) via `config.promptLoader`;\n * without one the commands degrade to the writable user store only.\n */\nexport function createPromptsPlugin(opts?: PromptsPluginOptions): Plugin {\n let store: DefaultPromptStore | null = null;\n let loader: PromptLoader | null = null;\n let usage: PromptUsageStore | null = null;\n\n return {\n name: 'wstack-prompts',\n version: '1.0.0',\n description: 'Prompt library with 100+ builtin prompts, search, and AI authoring',\n apiVersion: '^0.1',\n capabilities: { slashCommands: true },\n defaultConfig: {},\n\n setup(api) {\n const rawConfig = api.config as never as Record<string, unknown>;\n const paths = opts?.paths ?? (rawConfig['paths'] as WstackPaths | undefined);\n store = opts?.store ?? (paths ? new DefaultPromptStore(paths) : null);\n loader =\n opts?.loader ??\n (rawConfig['promptLoader'] as PromptLoader | undefined) ??\n (paths\n ? new DefaultPromptLoader({\n paths,\n bundledDir: rawConfig['bundledPromptsDir'] as string | undefined,\n })\n : null);\n\n usage = opts?.usage ?? (paths ? new PromptUsageStore(paths.promptUsage) : null);\n\n api.slashCommands.register(buildPromptsCommand(() => store, () => loader));\n api.slashCommands.register(buildPromptSearchCommand(() => loader, () => usage));\n api.slashCommands.register(buildPromptGenCommand(() => loader));\n api.log.info('[prompts] loaded \u2014 /prompts, /prompt, /prompt-gen available');\n },\n\n teardown(api) {\n api.slashCommands.unregister('prompts');\n api.slashCommands.unregister('prompt');\n api.slashCommands.unregister('prompt-gen');\n api.log.info('[prompts] unloaded');\n },\n\n async health() {\n return { ok: true, message: 'Prompt store accessible' };\n },\n };\n}\n\n// \u2500\u2500 /prompts \u2014 library manager \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction buildPromptsCommand(\n getStore: () => DefaultPromptStore | null,\n getLoader: () => PromptLoader | null,\n): SlashCommand {\n return {\n name: 'prompts',\n description:\n 'Manage your prompt library: /prompts [list|view|add|edit|delete|favorite|extend]',\n async run(args: string, ctx: Context) {\n const store = getStore();\n const loader = getLoader();\n if (!store) return { message: 'Prompt store not available.' };\n\n const [verb, ...rest] = args.trim().split(/\\s+/);\n const restJoined = rest.join(' ');\n\n switch (verb) {\n case '':\n case 'list':\n case 'ls': {\n const entries = await store.list();\n if (entries.length === 0) {\n return { message: 'Prompt library empty. Add: /prompts add \"title\" \"content\"' };\n }\n const lines = entries.map(\n (e) => ` ${e.favorite ? '\u2605 ' : ''}${e.title} ${dim(e.id)} ${e.tags.join(', ') || ''}`,\n );\n return { message: `Prompt library (${entries.length}):\\n${lines.join('\\n')}\\n` };\n }\n\n case 'view':\n case 'show': {\n if (!restJoined) return { message: 'Usage: /prompts view <title>' };\n const matches = await store.find(restJoined);\n if (matches.length === 0) return { message: `No prompt matching \"${restJoined}\".` };\n const entry =\n matches.find((m) => m.title.toLowerCase() === restJoined.toLowerCase()) ??\n expectDefined(matches[0]);\n return { message: formatPrompt(entry) };\n }\n\n case 'add':\n case 'new': {\n const { flags, positional } = parseFlags(restJoined);\n const parsed = parseTitleContent(positional);\n if (!parsed.title) return { message: 'Usage: /prompts add \"title\" \"prompt content\"' };\n const category = flags['category'] ?? flags['cat'];\n const variables = parseVarFlags(flags['var']);\n const entry = store.createNew(parsed.title, parsed.content, parseTags(flags['tags']), {\n description: flags['description'] ?? flags['desc'] ?? '',\n ...(category ? { category } : {}),\n ...(variables ? { variables } : {}),\n });\n await store.save(entry);\n getLoader()?.invalidateCache();\n return { message: `Added prompt \"${entry.title}\" (${entry.slug}).` };\n }\n\n case 'delete':\n case 'rm': {\n if (!restJoined) return { message: 'Usage: /prompts delete <title>' };\n const matches = await store.find(restJoined);\n if (matches.length === 0) return { message: `No prompt matching \"${restJoined}\".` };\n const exact =\n matches.find((m) => m.title.toLowerCase() === restJoined.toLowerCase()) ??\n expectDefined(matches[0]);\n const deleted = await store.delete(exact.id);\n getLoader()?.invalidateCache();\n return { message: deleted ? `Deleted \"${exact.title}\".` : 'Delete failed.' };\n }\n\n case 'edit':\n case 'update': {\n const parsed = parseTitleContent(restJoined);\n if (!parsed.title) return { message: 'Usage: /prompts edit \"title\" \"new content\"' };\n const matches = await store.find(parsed.title);\n if (matches.length === 0) return { message: `No prompt matching \"${parsed.title}\".` };\n const exact =\n matches.find((m) => m.title.toLowerCase() === parsed.title?.toLowerCase()) ??\n expectDefined(matches[0]);\n exact.content = parsed.content;\n exact.updatedAt = new Date().toISOString();\n await store.save(exact);\n getLoader()?.invalidateCache();\n return { message: `Updated \"${exact.title}\".` };\n }\n\n case 'favorite':\n case 'star': {\n if (!restJoined) return { message: 'Usage: /prompts favorite <slug-or-title>' };\n // Prefer the loader so favoriting a builtin copies it into the user layer.\n if (loader) {\n const updated = await loader.setFavorite(restJoined, true);\n if (!updated) return { message: `No prompt matching \"${restJoined}\".` };\n return { message: `\u2605 Favorited \"${updated.title}\" (${updated.slug}).` };\n }\n const matches = await store.find(restJoined);\n if (matches.length === 0) return { message: `No prompt matching \"${restJoined}\".` };\n const exact = expectDefined(matches[0]);\n exact.favorite = true;\n exact.updatedAt = new Date().toISOString();\n await store.save(exact);\n return { message: `\u2605 Favorited \"${exact.title}\".` };\n }\n\n case 'extend': {\n if (!restJoined) return { message: 'Usage: /prompts extend \"title\" <instructions>' };\n const parsed = parseTitleContent(restJoined);\n if (!parsed.title) return { message: 'Usage: /prompts extend \"title\" <instructions>' };\n const matches = await store.find(parsed.title);\n if (matches.length === 0) return { message: `No prompt matching \"${parsed.title}\".` };\n const exact =\n matches.find((m) => m.title.toLowerCase() === parsed.title?.toLowerCase()) ??\n expectDefined(matches[0]);\n\n const prov = ctx.provider as never as {\n complete?: (model: string | undefined, text: string) => Promise<string>;\n };\n if (!prov?.complete) return { message: 'LLM not available. Configure a provider first.' };\n\n const enhanced = await prov.complete(\n ctx.model,\n renderInstructionTemplate(readBundledInstructionText('llm/prompt-extend.md'), {\n existingPrompt: exact.content,\n additionalInstructions: parsed.content,\n }),\n );\n\n exact.content = enhanced.trim();\n exact.updatedAt = new Date().toISOString();\n await store.save(exact);\n getLoader()?.invalidateCache();\n return { message: `Extended \"${exact.title}\".\\n\\n${dim('New content:')}\\n${exact.content}` };\n }\n\n case 'export': {\n if (!loader) return { message: 'Prompt library not available.' };\n // Export only user-authored prompts (builtins are shipped already).\n const own = (await loader.list()).filter((e) => e.source !== 'builtin');\n if (own.length === 0) {\n return { message: 'No user prompts to export. (Builtin prompts ship with WrongStack.)' };\n }\n const target = resolveIoPath(restJoined || 'wrongstack-prompts.json', ctx);\n const payload = JSON.stringify(\n { version: 2, exportedAt: new Date().toISOString(), prompts: own },\n null,\n 2,\n );\n try {\n await fs.writeFile(target, payload, 'utf8');\n return { message: `Exported ${own.length} prompt(s) \u2192 ${target}` };\n } catch (err) {\n return { message: `Export failed: ${err instanceof Error ? err.message : String(err)}` };\n }\n }\n\n case 'import': {\n if (!loader) return { message: 'Prompt library not available.' };\n if (!restJoined) return { message: 'Usage: /prompts import <path-to.json>' };\n const src = resolveIoPath(restJoined, ctx);\n let raw: unknown;\n try {\n raw = JSON.parse(await fs.readFile(src, 'utf8'));\n } catch (err) {\n return { message: `Import failed: ${err instanceof Error ? err.message : String(err)}` };\n }\n const list = Array.isArray(raw)\n ? raw\n : Array.isArray((raw as { prompts?: unknown }).prompts)\n ? (raw as { prompts: unknown[] }).prompts\n : null;\n if (!list) return { message: 'Import failed: expected a JSON array or { prompts: [...] }.' };\n\n let imported = 0;\n let skipped = 0;\n for (const item of list) {\n const entry = migratePromptEntry(item);\n if (!entry) {\n skipped++;\n continue;\n }\n entry.source = 'user';\n entry.updatedAt = new Date().toISOString();\n // Overwrite an existing same-slug user/project prompt in place.\n const existing = await loader.find(entry.slug);\n if (existing && existing.source !== 'builtin') entry.id = existing.id;\n await loader.save(entry);\n imported++;\n }\n return {\n message: `Imported ${imported} prompt(s)${skipped ? ` (${skipped} skipped \u2014 invalid)` : ''} from ${src}.`,\n };\n }\n\n default:\n return {\n message: `Unknown subcommand \"${verb}\". Try: list | view | add | edit | delete | favorite | export | import | extend`,\n };\n }\n },\n };\n}\n\n// \u2500\u2500 /prompt \u2014 search the merged library and insert \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction buildPromptSearchCommand(\n getLoader: () => PromptLoader | null,\n getUsage: () => PromptUsageStore | null,\n): SlashCommand {\n return {\n name: 'prompt',\n description: 'Search the prompt library and insert one: /prompt <query> | /prompt insert <slug>',\n argsHint: '<query> | insert <slug> [var=value \u2026] | recent | favorites',\n async run(args: string) {\n const loader = getLoader();\n if (!loader) return { message: 'Prompt library not available.' };\n const trimmed = args.trim();\n\n // /prompt insert <slug> [k=v ...]\n if (trimmed.startsWith('insert ') || trimmed.startsWith('use ')) {\n const rest = trimmed.slice(trimmed.indexOf(' ') + 1).trim();\n const [slug, ...kvs] = rest.split(/\\s+/);\n if (!slug) return { message: 'Usage: /prompt insert <slug> [var=value \u2026]' };\n const entry = await loader.find(slug);\n if (!entry) return { message: `No prompt with slug/id \"${slug}\". Try /prompt ${slug}` };\n const values = parseKeyValues(kvs);\n const { text, missing, invalid } = renderPrompt(entry, values);\n if (invalid.length > 0) {\n const hint = (entry.variables ?? [])\n .filter((v) => invalid.includes(v.name))\n .map((v) => ` ${v.name}: one of ${(v.enum ?? []).join(' | ')}`)\n .join('\\n');\n return {\n message: `\"${entry.title}\" got an out-of-range value for: ${invalid.join(', ')}\\n${hint}`,\n };\n }\n if (missing.length > 0) {\n const hint = (entry.variables ?? [])\n .filter((v) => missing.includes(v.name))\n .map((v) => {\n const opts = v.enum && v.enum.length > 0 ? ` [${v.enum.join(' | ')}]` : '';\n return ` ${v.name}=\u2026${v.description ? ` (${v.description})` : ''}${opts}`;\n })\n .join('\\n');\n return {\n message: `\"${entry.title}\" needs values for: ${missing.join(', ')}\\n${hint}\\n\\nRe-run: /prompt insert ${entry.slug} ${missing.map((m) => `${m}=\u2026`).join(' ')}`,\n };\n }\n // Record usage (best-effort) then inject the rendered prompt as the next turn.\n try {\n await getUsage()?.record(entry.slug);\n } catch {\n // usage tracking is non-essential\n }\n return { message: `Inserted \"${entry.title}\".`, runText: text };\n }\n\n // /prompt recent \u2014 most-recently-inserted prompts\n if (trimmed === 'recent' || trimmed === 'popular') {\n const u = getUsage();\n if (!u) return { message: 'Usage tracking not available.' };\n const top = trimmed === 'popular' ? await u.top(15) : await u.recent(15);\n if (top.length === 0) {\n return { message: 'No prompt usage yet. Insert one with /prompt insert <slug>.' };\n }\n const lines: string[] = [];\n for (const { slug, usage } of top) {\n const e = await loader.find(slug);\n const title = e?.title ?? slug;\n lines.push(` ${e ? sourceGlyph(e) : '\u2022'} ${title} ${dim(slug)} ${dim(`\u00D7${usage.count}`)}`);\n }\n return {\n message: `${trimmed === 'popular' ? 'Most-used' : 'Recent'} prompts:\\n${lines.join('\\n')}\\n\\nInsert: /prompt insert <slug>`,\n };\n }\n\n // /prompt favorites \u2014 list starred prompts only\n if (trimmed === 'favorites' || trimmed === 'fav' || trimmed === 'starred') {\n const favs = (await loader.list()).filter((e) => e.favorite);\n if (favs.length === 0) {\n return { message: 'No favorites yet. Star one with /prompts favorite <slug>.' };\n }\n const lines = favs.map(\n (e) => ` ${sourceGlyph(e)} \u2605 ${e.title} ${dim(e.slug)} ${dim(`[${e.category}]`)}`,\n );\n return { message: `Favorites (${favs.length}):\\n${lines.join('\\n')}\\n\\nInsert: /prompt insert <slug>` };\n }\n\n // /prompt (no query) \u2192 overview\n if (!trimmed) {\n const cats = await loader.categories();\n const total = cats.reduce((n, c) => n + c.count, 0);\n const catLine = cats.map((c) => `${c.label} (${c.count})`).join(' \u00B7 ');\n return {\n message: [\n `Prompt library: ${total} prompts.`,\n catLine,\n '',\n 'Search: /prompt <query> \u00B7 Recent: /prompt recent \u00B7 Favorites: /prompt favorites \u00B7 Insert: /prompt insert <slug>',\n ].join('\\n'),\n };\n }\n\n // /prompt <query> \u2192 ranked results\n const results = await loader.search(trimmed, { limit: 15 });\n if (results.length === 0) return { message: `No prompts matching \"${trimmed}\".` };\n const lines = results.map(\n (e) =>\n ` ${sourceGlyph(e)} ${e.favorite ? '\u2605 ' : ''}${e.title} ${dim(e.slug)} ${dim(`[${e.category}]`)}\\n ${e.description}`,\n );\n return {\n message: `${results.length} match(es) for \"${trimmed}\":\\n${lines.join('\\n')}\\n\\nInsert: /prompt insert <slug>`,\n };\n },\n };\n}\n\n// \u2500\u2500 /prompt-gen \u2014 AI-guided authoring \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction buildPromptGenCommand(getLoader: () => PromptLoader | null): SlashCommand {\n return {\n name: 'prompt-gen',\n description: 'Create a new reusable prompt with AI guidance. The AI will interview you.',\n help: [\n '\u2554\u2550\u2550\u2550 Prompt Generator \u2550\u2550\u2550\u2557',\n '',\n 'Create a high-quality, reusable prompt with AI guidance.',\n '',\n 'Usage:',\n ' /prompt-gen Start AI-guided authoring',\n ' /prompt-gen list List prompts in your library',\n ' /prompt-gen edit <slug> View an existing prompt',\n '',\n 'The AI asks about purpose, task and variables, drafts a strong',\n 'prompt, then saves it via /prompts add.',\n ].join('\\n'),\n async run(args: string) {\n const loader = getLoader();\n const trimmed = args.trim();\n\n if (trimmed === 'list' || trimmed === 'ls') {\n if (!loader) return { message: 'Prompt library not available.' };\n const all = await loader.list();\n if (all.length === 0) return { message: 'No prompts found.' };\n const lines = all\n .slice(0, 50)\n .map((e) => ` ${sourceGlyph(e)} ${e.title} ${dim(e.slug)}`);\n return { message: `Prompts (${all.length}):\\n${lines.join('\\n')}` };\n }\n\n if (trimmed.startsWith('edit ') || trimmed.startsWith('view ')) {\n if (!loader) return { message: 'Prompt library not available.' };\n const slug = trimmed.slice(trimmed.indexOf(' ') + 1).trim();\n const entry = await loader.find(slug);\n if (!entry) return { message: `Prompt \"${slug}\" not found.` };\n return { message: formatPrompt(entry) };\n }\n\n // AI-guided creation \u2014 drive the agent with runText.\n return {\n message:\n '\u2554\u2550\u2550\u2550 Prompt Generator \u2550\u2550\u2550\u2557\\n\\nThe AI will guide you through creating a new prompt.\\nAnswer its questions naturally.',\n runText: [\n 'I want to create a new reusable prompt for my prompt library.',\n 'Read the `prompt-engineering` skill and use it as your playbook.',\n 'Interview me ONE question at a time to elicit:',\n ' 1. the purpose and the exact task the prompt should accomplish,',\n ' 2. the inputs that change each time (these become {{variables}}),',\n ' 3. the desired output format and tone.',\n 'Then draft a high-quality prompt that uses {{double-brace}} placeholders for the variables.',\n 'Show me the draft for approval, then SAVE it by calling:',\n ' /prompts add --category <category> --description \"<one-line summary>\" --tags <comma,separated> --var <name:description> \"<Title>\" \"<prompt content>\"',\n 'Pick the best-fitting category from: coding, debugging, refactoring, testing, code-review, architecture, devops, documentation, data-analysis, writing, research, product, agentic-workflows, meta-prompting.',\n ].join('\\n'),\n };\n },\n };\n}\n\n// \u2500\u2500 helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction formatPrompt(entry: PromptEntry): string {\n const tags = entry.tags.length > 0 ? ` [${entry.tags.join(', ')}]` : '';\n const vars =\n entry.variables && entry.variables.length > 0\n ? `\\n\\nVariables: ${entry.variables.map((v) => `{{${v.name}}}${v.required ? '*' : ''}`).join(', ')}`\n : '';\n return [\n `# ${entry.title}${tags}`,\n entry.description ? `\\n${entry.description}` : '',\n `\\n${entry.content}${vars}`,\n `\\n${dim(`slug: ${entry.slug} | category: ${entry.category} | source: ${entry.source}`)}`,\n ].join('\\n');\n}\n\n/** Resolve a user-supplied export/import path against the project root (or cwd). */\nfunction resolveIoPath(p: string, ctx: Context): string {\n const cleaned = p.trim().replace(/^[\"']|[\"']$/g, '');\n if (path.isAbsolute(cleaned)) return cleaned;\n const base = (ctx as { projectRoot?: string }).projectRoot ?? process.cwd();\n return path.resolve(base, cleaned);\n}\n\nfunction sourceGlyph(e: PromptEntry): string {\n return e.source === 'project' ? '\uD83D\uDCC1' : e.source === 'user' ? '\uD83D\uDC64' : e.source === 'synced' ? '\u2601' : '\uD83D\uDCE6';\n}\n\n/** Parse leading `--flag value` / `--flag=value` pairs; return the rest as positional. */\nfunction parseFlags(input: string): { flags: Record<string, string>; positional: string } {\n const flags: Record<string, string> = {};\n let s = input.trim();\n // Repeatedly consume a leading --flag (with =value, \"quoted value\", or bare token).\n const flagRe = /^--([a-zA-Z][\\w-]*)(?:=(\"[^\"]*\"|'[^']*'|\\S+)|\\s+(\"[^\"]*\"|'[^']*'|\\S+))?\\s*/;\n let m: RegExpExecArray | null;\n // Only consume flags while the string still starts with `--`.\n // biome-ignore lint/suspicious/noAssignInExpressions: idiomatic RegExp.exec loop\n while (s.startsWith('--') && (m = flagRe.exec(s))) {\n const name = expectDefined(m[1]);\n const rawVal = m[2] ?? m[3] ?? 'true';\n flags[name] = unquote(rawVal);\n s = s.slice(m[0].length);\n }\n return { flags, positional: s.trim() };\n}\n\nfunction unquote(v: string): string {\n if ((v.startsWith('\"') && v.endsWith('\"')) || (v.startsWith(\"'\") && v.endsWith(\"'\"))) {\n return v.slice(1, -1);\n }\n return v;\n}\n\nfunction parseTags(raw: string | undefined): string[] {\n if (!raw) return [];\n return raw\n .split(',')\n .map((t) => t.trim())\n .filter(Boolean);\n}\n\n/**\n * `--var name:description` may repeat; we accept a comma-separated list too.\n * An optional `::meta` suffix declares richness: `::multiline` for a textarea\n * hint and `::enum=a|b|c` for a closed value set. Examples:\n * name:What it does\n * code:Paste the snippet::multiline\n * flavor:Regex flavor::enum=PCRE|JS|Python\n */\nfunction parseVarFlags(raw: string | undefined): PromptVariable[] | undefined {\n if (!raw) return undefined;\n const out: PromptVariable[] = [];\n for (const part of raw.split(',')) {\n const trimmed = part.trim();\n if (!trimmed) continue;\n // Split the optional `::meta` tail off first so a `:` in the description\n // (before `::`) still parses as part of the description.\n const metaAt = trimmed.indexOf('::');\n const head = metaAt === -1 ? trimmed : trimmed.slice(0, metaAt).trim();\n const meta = metaAt === -1 ? '' : trimmed.slice(metaAt + 2).trim();\n const colon = head.indexOf(':');\n const name = colon === -1 ? head : head.slice(0, colon).trim();\n const description = colon === -1 ? undefined : head.slice(colon + 1).trim();\n if (!name) continue;\n const v: PromptVariable = { name, description, required: true };\n for (const token of meta.split('::').map((t) => t.trim()).filter(Boolean)) {\n if (token === 'multiline') v.multiline = true;\n else if (token.startsWith('enum=')) {\n const opts = token\n .slice(5)\n .split('|')\n .map((o) => o.trim())\n .filter(Boolean);\n if (opts.length > 0) v.enum = opts;\n }\n }\n out.push(v);\n }\n return out.length > 0 ? out : undefined;\n}\n\nfunction parseKeyValues(kvs: string[]): Record<string, string> {\n const out: Record<string, string> = {};\n for (const kv of kvs) {\n const eq = kv.indexOf('=');\n if (eq > 0) out[kv.slice(0, eq)] = unquote(kv.slice(eq + 1));\n }\n return out;\n}\n\nfunction parseTitleContent(args: string): { title: string; content: string } {\n const trimmed = args.trim();\n if (!trimmed) return { title: '', content: '' };\n const doubleMatch =\n /^\"([^\"]+)\"\\s+\"([^\"]+)\"$/.exec(trimmed) || /^'([^']+)'\\s+'([^']+)'$/.exec(trimmed);\n if (doubleMatch)\n return { title: expectDefined(doubleMatch[1]), content: expectDefined(doubleMatch[2]) };\n const singleMatch = /^'([^']+)'\\s+(.+)$/.exec(trimmed);\n if (singleMatch) return { title: expectDefined(singleMatch[1]), content: expectDefined(singleMatch[2]) };\n const firstSpace = trimmed.indexOf(' ');\n if (firstSpace === -1) return { title: trimmed, content: '' };\n return { title: trimmed.slice(0, firstSpace), content: trimmed.slice(firstSpace + 1) };\n}\n\nfunction dim(s: string): string {\n return `\\x1b[2m${s}\\x1b[0m`;\n}\n", "import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { DefaultPromptStore, migratePromptEntry } from '../storage/prompt-store.js';\nimport {\n isBuiltinCategory,\n PROMPT_CATEGORY_LABELS,\n type PromptCategoryCount,\n type PromptEntry,\n type PromptLoader,\n type PromptSearchOptions,\n} from '../types/prompt.js';\nimport type { WstackPaths } from '../utils/wstack-paths.js';\n\nexport interface PromptLoaderOptions {\n paths: WstackPaths;\n /** Directory containing the bundled dataset (`data/prompts`), if shipped. */\n bundledDir?: string | undefined;\n}\n\n/**\n * DefaultPromptLoader \u2014 read-side view over the three prompt layers, merged and\n * de-duplicated by `slug`. Mirrors `DefaultSkillLoader`.\n *\n * Discovery order (higher priority shadows lower by slug):\n * 1. Project-committed: <project>/.wrongstack/prompts/ (writable, source 'project')\n * 2. User profile: ~/.wrongstack/profiles/<name>/prompts/ (writable, source 'user'/'synced')\n * 3. Bundled with build: <core>/data/prompts/prompts/** (read-only, source 'builtin')\n *\n * Writes go to the user layer by default (or the project layer when\n * `scope:'project'`). Favoriting/editing a builtin copies it down into the user\n * layer (copy-on-write) so the read-only dataset is never mutated.\n */\nexport class DefaultPromptLoader implements PromptLoader {\n private readonly projectStore?: DefaultPromptStore | undefined;\n private readonly userStore?: DefaultPromptStore | undefined;\n private readonly builtinDir?: string | undefined;\n private cache?: PromptEntry[] | undefined;\n private builtinCache?: PromptEntry[] | undefined;\n\n constructor(opts: PromptLoaderOptions) {\n // Guard each layer dir: a partial WstackPaths (or a globalRoot-only test\n // setup) may omit one. A missing dir just means that layer is empty.\n this.projectStore =\n typeof opts.paths.inProjectPrompts === 'string'\n ? new DefaultPromptStore(opts.paths.inProjectPrompts)\n : undefined;\n this.userStore =\n typeof opts.paths.globalPrompts === 'string'\n ? new DefaultPromptStore(opts.paths.globalPrompts)\n : undefined;\n this.builtinDir = opts.bundledDir ? path.join(opts.bundledDir, 'prompts') : undefined;\n }\n\n async list(): Promise<PromptEntry[]> {\n if (this.cache) return this.cache;\n const seen = new Set<string>();\n const out: PromptEntry[] = [];\n const layers: PromptEntry[][] = [\n (await (this.projectStore?.list() ?? Promise.resolve([]))).map((e) => ({\n ...e,\n source: 'project' as const,\n })),\n await (this.userStore?.list() ?? Promise.resolve([])), // keeps stored source ('user' or 'synced')\n await this.readBuiltin(),\n ];\n for (const layer of layers) {\n for (const e of layer) {\n if (seen.has(e.slug)) continue;\n seen.add(e.slug);\n out.push(e);\n }\n }\n this.cache = out;\n return out;\n }\n\n async find(slugOrId: string): Promise<PromptEntry | undefined> {\n const all = await this.list();\n return all.find((e) => e.slug === slugOrId) ?? all.find((e) => e.id === slugOrId);\n }\n\n async search(query: string, opts: PromptSearchOptions = {}): Promise<PromptEntry[]> {\n let pool = await this.list();\n if (opts.category) pool = pool.filter((e) => e.category === opts.category);\n\n const q = query.trim().toLowerCase();\n let results: PromptEntry[];\n if (!q) {\n results = pool;\n } else {\n const tokens = q.split(/\\s+/).filter(Boolean);\n results = pool\n .map((e) => ({ e, score: scorePrompt(e, tokens) }))\n .filter((r) => r.score > 0)\n .sort((a, b) => b.score - a.score)\n .map((r) => r.e);\n }\n return typeof opts.limit === 'number' ? results.slice(0, opts.limit) : results;\n }\n\n async categories(): Promise<PromptCategoryCount[]> {\n const all = await this.list();\n const counts = new Map<string, number>();\n for (const e of all) counts.set(e.category, (counts.get(e.category) ?? 0) + 1);\n return [...counts.entries()]\n .map(([id, count]) => ({\n id,\n label: isBuiltinCategory(id) ? PROMPT_CATEGORY_LABELS[id] : id,\n count,\n }))\n .sort((a, b) => b.count - a.count || a.label.localeCompare(b.label));\n }\n\n async save(entry: PromptEntry, opts: { scope?: 'user' | 'project' } = {}): Promise<void> {\n const store = opts.scope === 'project' ? this.projectStore : this.userStore;\n if (!store)\n throw new Error(`Prompt ${opts.scope ?? 'user'} layer is not writable (no directory).`);\n // Never persist `source:'builtin'` into a writable layer \u2014 that would let a\n // user copy masquerade as read-only. Demote to the layer it's written to.\n const normalized: PromptEntry =\n entry.source === 'builtin'\n ? {\n ...entry,\n source: opts.scope === 'project' ? 'project' : 'user',\n forkedFrom: entry.forkedFrom ?? entry.slug,\n }\n : entry;\n await store.save(normalized);\n this.invalidateCache();\n }\n\n async delete(slugOrId: string): Promise<boolean> {\n const entry = await this.find(slugOrId);\n if (!entry) return false;\n if (entry.source === 'builtin') return false; // read-only\n const store = entry.source === 'project' ? this.projectStore : this.userStore;\n if (!store) return false;\n const ok = await store.delete(entry.id);\n if (ok) this.invalidateCache();\n return ok;\n }\n\n async setFavorite(slugOrId: string, favorite: boolean): Promise<PromptEntry | undefined> {\n const entry = await this.find(slugOrId);\n if (!entry) return undefined;\n const now = new Date().toISOString();\n\n if (entry.source === 'builtin') {\n // Copy-on-write: materialize a user-layer copy that shadows the builtin.\n if (!this.userStore) return undefined;\n const copy: PromptEntry = {\n ...entry,\n favorite,\n source: 'user',\n forkedFrom: entry.slug,\n updatedAt: now,\n };\n await this.userStore.save(copy);\n this.invalidateCache();\n return copy;\n }\n\n const updated: PromptEntry = { ...entry, favorite, updatedAt: now };\n const store = entry.source === 'project' ? this.projectStore : this.userStore;\n if (!store) return undefined;\n await store.save(updated);\n this.invalidateCache();\n return updated;\n }\n\n invalidateCache(): void {\n this.cache = undefined;\n this.builtinCache = undefined;\n }\n\n private async readBuiltin(): Promise<PromptEntry[]> {\n if (this.builtinCache) return this.builtinCache;\n const dir = this.builtinDir;\n if (!dir) {\n this.builtinCache = [];\n return [];\n }\n const out: PromptEntry[] = [];\n const files = await walkJson(dir);\n for (const file of files) {\n try {\n const parsed = JSON.parse(await fs.readFile(file, 'utf8'));\n // Builtin files store a bare PromptEntry (no { version, entry } wrapper).\n const migrated = migratePromptEntry(parsed);\n if (migrated) out.push({ ...migrated, source: 'builtin' });\n } catch {\n // skip malformed builtin file\n }\n }\n this.builtinCache = out;\n return out;\n }\n}\n\n/** Recursively collect `*.json` paths under `dir` (skips `index.json`/`schema.json`). */\nasync function walkJson(dir: string): Promise<string[]> {\n const out: string[] = [];\n let entries: import('node:fs').Dirent[];\n try {\n entries = await fs.readdir(dir, { withFileTypes: true });\n } catch {\n return out;\n }\n for (const e of entries) {\n const full = path.join(dir, e.name);\n if (e.isDirectory()) {\n out.push(...(await walkJson(full)));\n } else if (e.name.endsWith('.json') && e.name !== 'index.json' && e.name !== 'schema.json') {\n out.push(full);\n }\n }\n return out;\n}\n\nfunction scorePrompt(e: PromptEntry, tokens: string[]): number {\n const title = e.title.toLowerCase();\n const slug = e.slug.toLowerCase();\n const desc = e.description.toLowerCase();\n const cat = e.category.toLowerCase();\n const tags = e.tags.map((t) => t.toLowerCase());\n const content = e.content.toLowerCase();\n\n let score = 0;\n for (const tok of tokens) {\n let hit = 0;\n if (title.includes(tok)) hit += 5;\n if (slug.includes(tok)) hit += 4;\n if (tags.some((t) => t.includes(tok))) hit += 3;\n if (desc.includes(tok)) hit += 2;\n if (cat.includes(tok)) hit += 2;\n if (content.includes(tok)) hit += 1;\n // Fuzzy fallback: a typo / abbreviation (\"dpl\" \u2192 \"deploy\") still matches if\n // the token's characters appear in order in the most relevant fields. Scored\n // low so exact substring hits always rank above fuzzy ones.\n if (hit === 0 && tok.length >= 3) {\n if (isSubsequence(tok, title)) hit += 2;\n else if (isSubsequence(tok, slug)) hit += 2;\n else if (tags.some((t) => isSubsequence(tok, t))) hit += 1;\n }\n if (hit === 0) return 0; // every token must match somewhere (AND semantics)\n score += hit;\n }\n if (e.favorite) score += 1; // gentle tiebreak toward favorites\n return score;\n}\n\n/** True when every char of `needle` appears in `hay`, in order (subsequence). */\nfunction isSubsequence(needle: string, hay: string): boolean {\n let i = 0;\n for (let j = 0; j < hay.length && i < needle.length; j++) {\n if (hay[j] === needle[i]) i++;\n }\n return i === needle.length;\n}\n\n/**\n * Fill a prompt's `{{variable}}` placeholders with `values`. Unknown\n * placeholders are left intact unless a declared variable supplies a `default`.\n * Returns the rendered string, any required variables left unfilled\n * (`missing`), and any supplied values outside a variable's declared `enum`\n * (`invalid`).\n */\nexport function renderPrompt(\n entry: PromptEntry,\n values: Record<string, string> = {},\n): { text: string; missing: string[]; invalid: string[] } {\n const declared = new Map((entry.variables ?? []).map((v) => [v.name, v]));\n const missing: string[] = [];\n const invalid: string[] = [];\n\n const text = entry.content.replace(/\\{\\{\\s*([\\w.-]+)\\s*\\}\\}/g, (whole, rawName: string) => {\n const name = rawName.trim();\n if (Object.hasOwn(values, name) && values[name] !== undefined) {\n return values[name] as string;\n }\n const decl = declared.get(name);\n if (decl?.default !== undefined) return decl.default;\n if (decl?.required) missing.push(name);\n return whole; // leave the placeholder untouched\n });\n\n // Surface declared-but-never-referenced required vars too.\n for (const v of entry.variables ?? []) {\n if (v.required && !(v.name in values) && v.default === undefined && !missing.includes(v.name)) {\n // Only report if the placeholder actually exists in content; otherwise ignore.\n if (new RegExp(`\\\\{\\\\{\\\\s*${escapeRegExp(v.name)}\\\\s*\\\\}\\\\}`).test(entry.content)) {\n missing.push(v.name);\n }\n }\n // Reject a supplied value that isn't one of the declared enum options.\n if (\n v.enum &&\n v.enum.length > 0 &&\n Object.hasOwn(values, v.name) &&\n values[v.name] !== undefined &&\n values[v.name] !== '' &&\n !v.enum.includes(values[v.name] as string)\n ) {\n invalid.push(v.name);\n }\n }\n\n return { text, missing, invalid };\n}\n\nfunction escapeRegExp(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n", "import { createHash } from 'node:crypto';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type { PromptEntry, PromptVariable } from '../types/prompt.js';\nimport { atomicWrite, ensureDir } from '../utils/atomic-write.js';\nimport { slugify } from '../utils/slug.js';\nimport { ulid } from '../utils/ulid.js';\nimport type { WstackPaths } from '../utils/wstack-paths.js';\n\nexport type { PromptEntry, PromptSource, PromptVariable } from '../types/prompt.js';\n\nexport interface PromptStore {\n list(): Promise<PromptEntry[]>;\n get(id: string): Promise<PromptEntry | null>;\n save(entry: PromptEntry): Promise<void>;\n delete(id: string): Promise<boolean>;\n find(query: string): Promise<PromptEntry[]>;\n}\n\n/** Current on-disk schema version. */\nconst SCHEMA_VERSION = 2;\n\ninterface RawPromptFile {\n version: number;\n entry: unknown;\n}\n\n/** sha256 of a prompt's content \u2014 used for builtin/synced integrity checks. */\nexport function promptChecksum(content: string): string {\n return createHash('sha256').update(content, 'utf8').digest('hex');\n}\n\n/**\n * Upgrade any persisted prompt record (v1 or v2) to a fully-populated v2\n * `PromptEntry`. Pure \u2014 does not touch disk. v1 records (only\n * `id/title/content/tags/createdAt/updatedAt`) get sensible defaults:\n * slug from title, empty description, `uncategorized` category, `user` source.\n */\nexport function migratePromptEntry(raw: unknown): PromptEntry | null {\n if (!raw || typeof raw !== 'object') return null;\n const r = raw as Record<string, unknown>;\n if (typeof r['id'] !== 'string' || typeof r['title'] !== 'string') return null;\n\n const title = r['title'];\n const content = typeof r['content'] === 'string' ? r['content'] : '';\n const now = typeof r['createdAt'] === 'string' ? r['createdAt'] : new Date(0).toISOString();\n const tags = Array.isArray(r['tags'])\n ? (r['tags'].filter((t) => typeof t === 'string') as string[])\n : [];\n\n return {\n id: r['id'],\n slug: typeof r['slug'] === 'string' && r['slug'].length > 0 ? r['slug'] : slugify(title),\n title,\n description: typeof r['description'] === 'string' ? r['description'] : '',\n content,\n category:\n typeof r['category'] === 'string' && r['category'].length > 0\n ? r['category']\n : 'uncategorized',\n tags,\n source: isPromptSource(r['source']) ? r['source'] : 'user',\n favorite: r['favorite'] === true,\n variables: normalizeVariables(r['variables']),\n author: typeof r['author'] === 'string' ? r['author'] : undefined,\n version: typeof r['version'] === 'string' ? r['version'] : undefined,\n license: typeof r['license'] === 'string' ? r['license'] : undefined,\n checksum: typeof r['checksum'] === 'string' ? r['checksum'] : undefined,\n forkedFrom: typeof r['forkedFrom'] === 'string' ? r['forkedFrom'] : undefined,\n createdAt: now,\n updatedAt: typeof r['updatedAt'] === 'string' ? r['updatedAt'] : now,\n };\n}\n\nfunction isPromptSource(v: unknown): v is PromptEntry['source'] {\n return v === 'builtin' || v === 'user' || v === 'project' || v === 'synced';\n}\n\nfunction normalizeVariables(v: unknown): PromptVariable[] | undefined {\n if (!Array.isArray(v)) return undefined;\n const out: PromptVariable[] = [];\n for (const item of v) {\n if (\n item &&\n typeof item === 'object' &&\n typeof (item as Record<string, unknown>)['name'] === 'string'\n ) {\n const o = item as Record<string, unknown>;\n const enumVals =\n Array.isArray(o['enum']) && o['enum'].every((x) => typeof x === 'string')\n ? (o['enum'] as string[])\n : undefined;\n out.push({\n name: o['name'] as string,\n description: typeof o['description'] === 'string' ? o['description'] : undefined,\n default: typeof o['default'] === 'string' ? o['default'] : undefined,\n required: o['required'] === true ? true : undefined,\n enum: enumVals && enumVals.length > 0 ? enumVals : undefined,\n multiline: o['multiline'] === true ? true : undefined,\n });\n }\n }\n return out.length > 0 ? out : undefined;\n}\n\n/**\n * DefaultPromptStore \u2014 file-per-prompt JSON in a single directory (the global\n * the active profile's `prompts` directory by default, or a layer dir the loader passes in).\n * Reads tolerate legacy v1 files via `migratePromptEntry`; writes always emit\n * the current v2 schema.\n */\nexport class DefaultPromptStore implements PromptStore {\n private readonly dir: string;\n\n constructor(pathsOrDir: WstackPaths | string) {\n this.dir = typeof pathsOrDir === 'string' ? pathsOrDir : pathsOrDir.globalPrompts;\n }\n\n async list(): Promise<PromptEntry[]> {\n await ensureDir(this.dir);\n const entries: PromptEntry[] = [];\n try {\n const files = await fs.readdir(this.dir);\n for (const file of files) {\n if (!file.endsWith('.json')) continue;\n try {\n const raw: RawPromptFile = JSON.parse(\n await fs.readFile(path.join(this.dir, file), 'utf8'),\n );\n const migrated = migratePromptEntry(raw.entry);\n if (migrated) entries.push(migrated);\n } catch {\n // skip corrupt files\n }\n }\n } catch {\n // dir doesn't exist yet\n }\n return entries.sort(\n (a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime(),\n );\n }\n\n async get(id: string): Promise<PromptEntry | null> {\n const file = path.join(this.dir, `${id}.json`);\n try {\n const raw: RawPromptFile = JSON.parse(await fs.readFile(file, 'utf8'));\n return migratePromptEntry(raw.entry);\n } catch {\n return null;\n }\n }\n\n async save(entry: PromptEntry): Promise<void> {\n await ensureDir(this.dir);\n const file = path.join(this.dir, `${entry.id}.json`);\n const raw: RawPromptFile = { version: SCHEMA_VERSION, entry };\n await atomicWrite(file, JSON.stringify(raw, null, 2));\n }\n\n async delete(id: string): Promise<boolean> {\n const file = path.join(this.dir, `${id}.json`);\n try {\n await fs.unlink(file);\n return true;\n } catch {\n return false;\n }\n }\n\n async find(query: string): Promise<PromptEntry[]> {\n const all = await this.list();\n const lower = query.toLowerCase();\n return all.filter(\n (e) =>\n e.title.toLowerCase().includes(lower) ||\n e.description.toLowerCase().includes(lower) ||\n e.content.toLowerCase().includes(lower) ||\n e.category.toLowerCase().includes(lower) ||\n e.tags.some((t) => t.toLowerCase().includes(lower)),\n );\n }\n\n /** Create a new v2 entry and return it. Does NOT persist \u2014 call save() afterwards. */\n createNew(\n title: string,\n content: string,\n tags: string[] = [],\n extra: Partial<\n Omit<PromptEntry, 'id' | 'title' | 'content' | 'tags' | 'createdAt' | 'updatedAt'>\n > = {},\n ): PromptEntry {\n const now = new Date().toISOString();\n return {\n id: ulid(),\n slug: extra.slug && extra.slug.length > 0 ? extra.slug : slugify(title),\n title,\n description: extra.description ?? '',\n content,\n category: extra.category ?? 'uncategorized',\n tags,\n source: extra.source ?? 'user',\n favorite: extra.favorite ?? false,\n variables: extra.variables,\n author: extra.author,\n version: extra.version,\n license: extra.license,\n checksum: extra.checksum,\n forkedFrom: extra.forkedFrom,\n createdAt: now,\n updatedAt: now,\n };\n }\n}\n", "/**\n * Prompt library types \u2014 the canonical home for the prompt data model and the\n * loader/registry contracts. Has no internal dependencies so both `storage/`\n * (the writable store) and `execution/` (the layered loader) can import it\n * without creating a cycle.\n */\n\n/** Provenance of a prompt \u2014 which layer it came from. */\nexport type PromptSource = 'builtin' | 'user' | 'project' | 'synced';\n\n/**\n * The fourteen first-party categories shipped with the builtin dataset, plus\n * the `uncategorized` sentinel used when migrating legacy v1 entries. Builtin\n * prompts MUST use one of these (enforced by the dataset schema test); user and\n * project prompts may use any free-form string.\n */\nexport const BUILTIN_PROMPT_CATEGORIES = [\n 'coding',\n 'debugging',\n 'refactoring',\n 'testing',\n 'code-review',\n 'architecture',\n 'devops',\n 'documentation',\n 'data-analysis',\n 'writing',\n 'research',\n 'product',\n 'agentic-workflows',\n 'meta-prompting',\n 'uncategorized',\n] as const;\n\nexport type BuiltinPromptCategory = (typeof BUILTIN_PROMPT_CATEGORIES)[number];\n\n/**\n * Human-readable labels for the builtin categories (for UI chips / pickers).\n */\nexport const PROMPT_CATEGORY_LABELS: Record<BuiltinPromptCategory, string> = {\n coding: 'Coding',\n debugging: 'Debugging',\n refactoring: 'Refactoring',\n testing: 'Testing',\n 'code-review': 'Code Review',\n architecture: 'Architecture',\n devops: 'DevOps',\n documentation: 'Documentation',\n 'data-analysis': 'Data Analysis',\n writing: 'Writing',\n research: 'Research',\n product: 'Product',\n 'agentic-workflows': 'Agentic Workflows',\n 'meta-prompting': 'Meta-Prompting',\n uncategorized: 'Uncategorized',\n};\n\n/**\n * A prompt's category. Typed as a free-form string because user/project prompts\n * may invent their own; the builtin dataset is constrained to\n * {@link BUILTIN_PROMPT_CATEGORIES} by its schema.\n */\nexport type PromptCategory = BuiltinPromptCategory | (string & {});\n\nexport function isBuiltinCategory(value: string): value is BuiltinPromptCategory {\n return (BUILTIN_PROMPT_CATEGORIES as readonly string[]).includes(value);\n}\n\n/** A `{{name}}` placeholder declared by a prompt. */\nexport interface PromptVariable {\n /** Placeholder name as it appears between `{{ }}` (case-sensitive). */\n name: string;\n description?: string | undefined;\n default?: string | undefined;\n required?: boolean | undefined;\n /**\n * Closed set of allowed values. When present, surfaces render a dropdown\n * instead of a free text field and a supplied value outside the set is\n * reported as invalid by {@link renderPrompt}.\n */\n enum?: string[] | undefined;\n /**\n * UI hint: the value is expected to span multiple lines (pasted code, a\n * diff, a long passage). Surfaces render a textarea instead of a one-line\n * input. Has no effect on rendering \u2014 purely presentational.\n */\n multiline?: boolean | undefined;\n}\n\n/**\n * A reusable prompt. v2 schema. Legacy v1 entries (only `id/title/content/tags/\n * createdAt/updatedAt`) are upgraded lazily on read by `migratePromptEntry`.\n */\nexport interface PromptEntry {\n /** Stable unique handle (ULID for new entries; legacy short hex tolerated). */\n id: string;\n /** kebab-case stable key \u2014 the dedup key across layers and registry key. */\n slug: string;\n title: string;\n /** One-line summary shown in lists/pickers. */\n description: string;\n content: string;\n category: PromptCategory;\n /** Secondary facets (free-form). */\n tags: string[];\n source: PromptSource;\n favorite: boolean;\n /** `{{placeholder}}` variables this prompt expects, if any. */\n variables?: PromptVariable[] | undefined;\n author?: string | undefined;\n version?: string | undefined;\n license?: string | undefined;\n /** sha256 of `content` \u2014 set for builtin/synced entries for integrity. */\n checksum?: string | undefined;\n /** When a builtin was copy-on-written into the user layer, its origin slug. */\n forkedFrom?: string | undefined;\n createdAt: string;\n updatedAt: string;\n}\n\n/** One category with its prompt count, for picker chips. */\nexport interface PromptCategoryCount {\n id: PromptCategory;\n label: string;\n count: number;\n}\n\nexport interface PromptSearchOptions {\n category?: PromptCategory | undefined;\n /** Max results (default: unbounded). */\n limit?: number | undefined;\n}\n\n/**\n * Read-side contract over the three prompt layers (project > user > builtin),\n * merged and de-duplicated by slug. Mirrors `SkillLoader` in shape.\n */\nexport interface PromptLoader {\n /** All prompts across layers, project/user shadowing builtin by slug. */\n list(): Promise<PromptEntry[]>;\n /** Resolve by slug first, then by id. */\n find(slugOrId: string): Promise<PromptEntry | undefined>;\n /** Ranked search over title/description/content/tags, optional category filter. */\n search(query: string, opts?: PromptSearchOptions): Promise<PromptEntry[]>;\n /** Category counts across all layers, for UI chips. */\n categories(): Promise<PromptCategoryCount[]>;\n /**\n * Persist into the writable (user, or project when `scope:'project'`) layer.\n * Throws if the resolved target is the read-only builtin layer.\n */\n save(entry: PromptEntry, opts?: { scope?: 'user' | 'project' }): Promise<void>;\n /** Delete from a writable layer. Returns false if not found / builtin. */\n delete(slugOrId: string): Promise<boolean>;\n /**\n * Mark/unmark a prompt as favorite. Favoriting a builtin copies it down into\n * the user layer (copy-on-write, `source:'user'`, `forkedFrom:<slug>`).\n */\n setFavorite(slugOrId: string, favorite: boolean): Promise<PromptEntry | undefined>;\n /** Clear the internal cache so the next read re-scans disk. */\n invalidateCache(): void;\n}\n\n/**\n * The packed builtin index (also the shape a remote registry manifest mirrors\n * \u2014 see `types/prompt-registry.ts`).\n */\nexport interface PromptManifest {\n datasetVersion: number;\n generatedAt: string;\n count: number;\n categories: PromptCategoryCount[];\n prompts: PromptManifestRef[];\n}\n\nexport interface PromptManifestRef {\n id: string;\n slug: string;\n title: string;\n description: string;\n category: PromptCategory;\n tags: string[];\n checksum: string;\n /** Relative path of the per-prompt file within the dataset. */\n file: string;\n}\n", "import * as fs from 'node:fs/promises';\nimport { atomicWrite, withFileLock } from '../utils/atomic-write.js';\n\nexport interface PromptUsage {\n count: number;\n lastUsedAt: string;\n}\n\ninterface RawUsageFile {\n version: 1;\n usage: Record<string, PromptUsage>;\n}\n\ninterface FileSignature {\n size: number;\n mtimeMs: number;\n ctimeMs: number;\n}\n\ninterface PendingRecord {\n slug: string;\n at: string;\n resolve: (usage: PromptUsage) => void;\n reject: (reason?: unknown) => void;\n}\n\n/**\n * Tracks how often each prompt is inserted, keyed by slug, in a single JSON\n * file (`profiles/<name>/prompt-usage.json`). Kept SEPARATE from the prompt\n * entries so usage can be recorded for read-only builtin prompts without\n * copy-on-writing them into the user layer. Surfaces \"recent / most-used\"\n * views and a gentle search-ranking boost.\n */\nexport class PromptUsageStore {\n private cachedUsage: Record<string, PromptUsage> | null = null;\n private cachedSignature: FileSignature | null = null;\n private readonly pendingRecords: PendingRecord[] = [];\n private drainScheduled = false;\n private draining = false;\n\n constructor(private readonly file: string) {}\n\n async load(): Promise<Record<string, PromptUsage>> {\n return cloneUsage(await this.loadInternal());\n }\n\n private async loadInternal(): Promise<Record<string, PromptUsage>> {\n const signature = await this.fileSignature();\n if (this.cachedUsage && sameSignature(signature, this.cachedSignature)) {\n return this.cachedUsage;\n }\n\n try {\n const raw: RawUsageFile = JSON.parse(await fs.readFile(this.file, 'utf8'));\n if (raw && typeof raw === 'object' && raw.usage && typeof raw.usage === 'object') {\n this.cachedUsage = raw.usage;\n this.cachedSignature = signature;\n return this.cachedUsage;\n }\n } catch {\n // missing or corrupt \u2192 empty\n }\n this.cachedUsage = {};\n this.cachedSignature = signature;\n return this.cachedUsage;\n }\n\n async record(slug: string, at: string = new Date().toISOString()): Promise<PromptUsage> {\n return await new Promise<PromptUsage>((resolve, reject) => {\n this.pendingRecords.push({ slug, at, resolve, reject });\n this.scheduleDrain();\n });\n }\n\n async get(slug: string): Promise<PromptUsage | undefined> {\n return (await this.load())[slug];\n }\n\n /** Slugs ordered by most-recently-used (then by count), capped at `limit`. */\n async recent(limit = 15): Promise<{ slug: string; usage: PromptUsage }[]> {\n const usage = await this.load();\n return Object.entries(usage)\n .map(([slug, u]) => ({ slug, usage: u }))\n .sort(\n (a, b) =>\n new Date(b.usage.lastUsedAt).getTime() - new Date(a.usage.lastUsedAt).getTime() ||\n b.usage.count - a.usage.count,\n )\n .slice(0, limit);\n }\n\n /** Slugs ordered by usage count (then recency), capped at `limit`. */\n async top(limit = 15): Promise<{ slug: string; usage: PromptUsage }[]> {\n const usage = await this.load();\n return Object.entries(usage)\n .map(([slug, u]) => ({ slug, usage: u }))\n .sort(\n (a, b) =>\n b.usage.count - a.usage.count ||\n new Date(b.usage.lastUsedAt).getTime() - new Date(a.usage.lastUsedAt).getTime(),\n )\n .slice(0, limit);\n }\n\n private scheduleDrain(): void {\n if (this.drainScheduled || this.draining) return;\n this.drainScheduled = true;\n queueMicrotask(() => {\n this.drainScheduled = false;\n void this.drainPending();\n });\n }\n\n private async drainPending(): Promise<void> {\n if (this.draining || this.pendingRecords.length === 0) return;\n this.draining = true;\n const batch = this.pendingRecords.splice(0);\n\n try {\n const results = await withFileLock(this.file, async () => {\n // Validate the cache after taking the cross-process lock. A peer may\n // have updated the file since our last read; size/mtime/ctime makes\n // that visible without re-reading unchanged JSON on every record.\n const usage = { ...(await this.loadInternal()) };\n const nextValues: PromptUsage[] = [];\n for (const item of batch) {\n const previous = usage[item.slug];\n const next: PromptUsage = {\n count: (previous?.count ?? 0) + 1,\n lastUsedAt: item.at,\n };\n usage[item.slug] = next;\n nextValues.push(next);\n }\n\n await atomicWrite(\n this.file,\n JSON.stringify({ version: 1, usage } satisfies RawUsageFile, null, 2),\n );\n this.cachedUsage = usage;\n this.cachedSignature = await this.fileSignature();\n return nextValues;\n });\n\n for (let index = 0; index < batch.length; index++) {\n batch[index]!.resolve(results[index]!);\n }\n } catch (error) {\n for (const item of batch) item.reject(error);\n } finally {\n this.draining = false;\n if (this.pendingRecords.length > 0) this.scheduleDrain();\n }\n }\n\n private async fileSignature(): Promise<FileSignature | null> {\n try {\n const stat = await fs.stat(this.file);\n return { size: stat.size, mtimeMs: stat.mtimeMs, ctimeMs: stat.ctimeMs };\n } catch {\n return null;\n }\n }\n}\n\nfunction sameSignature(a: FileSignature | null, b: FileSignature | null): boolean {\n if (a === null || b === null) return a === b;\n return a.size === b.size && a.mtimeMs === b.mtimeMs && a.ctimeMs === b.ctimeMs;\n}\n\nfunction cloneUsage(usage: Record<string, PromptUsage>): Record<string, PromptUsage> {\n return Object.fromEntries(Object.entries(usage).map(([slug, value]) => [slug, { ...value }]));\n}\n", "import * as os from 'node:os';\nimport * as path from 'node:path';\nimport type { Context, SlashCommand } from '../index.js';\nimport { FOREIGN_SKILL_TOOLS, securityScoreToTier } from '../skills/foreign-sources.js';\nimport { githubDirectAdapter } from '../skills/registry/github-direct-adapter.js';\nimport type { SkillRegistryAdapter } from '../skills/registry/registry-adapter.js';\nimport {\n createSkillsShAdapter,\n DEFAULT_SKILLS_SH_URL,\n} from '../skills/registry/skills-sh-adapter.js';\nimport {\n bodyLineAdvisory,\n extractSkillFromPrompt,\n generateSkillSkeleton,\n openInEditor,\n validateSkillNameAvailable,\n writeSkeletonSkill,\n} from '../skills/skill-generator.js';\nimport { SkillInstaller } from '../skills/skill-installer.js';\nimport type { Plugin } from '../types/plugin.js';\nimport type { SkillLoader } from '../types/skill.js';\nimport { color } from '../utils/color.js';\nimport { toErrorMessage } from '../utils/error.js';\nimport { resolveWstackPaths } from '../utils/wstack-paths.js';\n\ninterface SkillsPluginOptions {\n skillLoader?: SkillLoader | undefined;\n /**\n * Registry adapters. When unset the plugin wires the github-direct adapter\n * (for `user/repo` installs) plus a skills.sh adapter pointed at\n * `config.skills.registryUrl` (default {@link DEFAULT_SKILLS_SH_URL}).\n */\n registryAdapters?: SkillRegistryAdapter[] | undefined;\n}\n\n/**\n * SkillsPlugin \u2014 skill library + installer + authoring toolkit.\n *\n * Registers `/skill`, `/skill-gen`, `/skill-search`, `/skill-install`,\n * `/skill-import`, `/skill-update`, `/skill-uninstall`. First-party (\"official\")\n * plugin, so the commands keep their bare names. Needs a `SkillLoader` (injected\n * by the host via `config.skillLoader`); without one the commands report that\n * and no-op.\n */\nexport function createSkillsPlugin(opts?: SkillsPluginOptions): Plugin {\n return {\n name: 'wstack-skills',\n version: '1.1.0',\n description:\n 'Skill library, registry search, installer and authoring toolkit: /skill, /skill-gen, /skill-search, /skill-install, ...',\n apiVersion: '^0.1',\n capabilities: { slashCommands: true },\n defaultConfig: {},\n\n setup(api) {\n const rawConfig = api.config as never as Record<string, unknown>;\n const skillLoader = opts?.skillLoader ?? (rawConfig.skillLoader as SkillLoader | undefined);\n const registryUrl =\n (rawConfig.skills as { registryUrl?: string } | undefined)?.registryUrl?.trim() ||\n undefined;\n\n const registryAdapters = opts?.registryAdapters ?? [\n githubDirectAdapter,\n createSkillsShAdapter(registryUrl ? { baseUrl: registryUrl } : {}),\n ];\n\n api.slashCommands.register(buildSkillCommand(skillLoader));\n api.slashCommands.register(buildSkillGeneratorCommand(skillLoader));\n api.slashCommands.register(buildSkillSearchCommand(skillLoader, registryAdapters));\n api.slashCommands.register(buildSkillInstallCommand(skillLoader, registryAdapters));\n api.slashCommands.register(buildSkillImportCommand(skillLoader));\n api.slashCommands.register(buildSkillUpdateCommand(skillLoader, registryAdapters));\n api.slashCommands.register(buildSkillUninstallCommand(skillLoader));\n api.log.info(\n '[skills] loaded \u2014 /skill, /skill-gen, /skill-search, /skill-install, /skill-import, /skill-update/uninstall available',\n );\n },\n\n teardown(api) {\n for (const name of [\n 'skill',\n 'skill-gen',\n 'skill-search',\n 'skill-install',\n 'skill-import',\n 'skill-update',\n 'skill-uninstall',\n ]) {\n api.slashCommands.unregister(name);\n }\n api.log.info('[skills] unloaded');\n },\n\n async health() {\n return { ok: true, message: 'skills ready' };\n },\n };\n}\n\nfunction makeInstaller(\n skillLoader: SkillLoader | undefined,\n projectRoot: string,\n registryAdapters?: SkillRegistryAdapter[],\n): SkillInstaller {\n const paths = resolveWstackPaths({ projectRoot });\n return new SkillInstaller({\n manifestPath: path.join(paths.configDir, 'installed-skills.json'),\n projectSkillsDir: paths.inProjectSkills,\n globalSkillsDir: paths.globalSkills,\n projectHash: paths.projectHash,\n skillLoader,\n ...(registryAdapters ? { registryAdapters } : {}),\n });\n}\n\nexport function buildSkillCommand(skillLoader?: SkillLoader): SlashCommand {\n return {\n name: 'skill',\n description:\n 'Show skill details or list available skills. Use /skill-gen to create new skills.',\n async run(args: string) {\n if (!skillLoader) return { message: 'No skill loader configured.' };\n if (!args.trim()) {\n const entries = await skillLoader.listEntries();\n if (entries.length === 0) return { message: 'No skills found.' };\n const lines = entries.map((e) => {\n const scopeTag =\n e.scope.length > 0 ? ` ${color.dim(`(${e.scope.slice(0, 3).join(', ')})`)}` : '';\n return ` ${color.bold(e.name)}${scopeTag}\\n Use when: ${e.trigger}`;\n });\n return { message: `Available skills:\\n${lines.join('\\n\\n')}\\n` };\n }\n const skill = await skillLoader.find(args.trim());\n if (!skill) return { message: `Skill \"${args.trim()}\" not found.` };\n return { message: await skillLoader.readBody(skill.name) };\n },\n };\n}\n\nexport function buildSkillGeneratorCommand(skillLoader?: SkillLoader): SlashCommand {\n return {\n name: 'skill-gen',\n description:\n 'Create or validate skills. /skill-gen (wizard) | validate <name> | skeleton <name> | from-prompt <text> | view <name> | edit <name> | list',\n help: [\n '\u2554\u2550\u2550\u2550 Skill Generator \u2550\u2550\u2550\u2557',\n '',\n 'Create and validate AI skills.',\n '',\n 'Usage:',\n ' /skill-gen Start the interactive AI-guided wizard',\n ' /skill-gen list List existing skills (with source)',\n ' /skill-gen validate <name> Validate a skill name (format + collisions)',\n ' /skill-gen skeleton <name> Generate a SKILL.md skeleton to draft',\n ' [--desc \"...\"] [--trigger a,b,c] [--global] [--force]',\n ' /skill-gen from-prompt <text> Turn a prompt into a skill draft',\n ' [--global] [--force]',\n \" /skill-gen view <name> Show a skill's body (read-only)\",\n ' /skill-gen edit <name> Open a skill in $EDITOR/$VISUAL',\n '',\n 'Skeletons are written to .wrongstack/skills/<name>/SKILL.md (--global: active profile/skills/).',\n 'The interactive wizard reads the bundled `skill-creator` skill and guides you step by step.',\n ].join('\\n'),\n async run(args: string, ctx: Context) {\n const trimmed = args.trim();\n const [sub, ...rest] = trimmed.split(/\\s+/);\n\n // \u2500\u2500 list \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n if (sub === 'list' || sub === 'ls') {\n if (!skillLoader) return { message: 'No skill loader configured.' };\n const entries = await skillLoader.listEntries();\n if (entries.length === 0) return { message: 'No skills found.' };\n const lines = entries.map((e) => {\n const src =\n e.source === 'project'\n ? '\uD83D\uDCC1'\n : e.source === 'user'\n ? '\uD83D\uDC64'\n : e.source === 'claude-project' || e.source === 'claude-user'\n ? '\uD83C\uDF10'\n : e.source === 'foreign'\n ? `\uD83C\uDF10(${e.originTool ?? '?'})`\n : e.source === 'extra'\n ? '\u2795'\n : '\uD83D\uDCE6';\n return ` ${src} ${e.name}\\n ${e.trigger}`;\n });\n return { message: `Available Skills:\\n${lines.join('\\n\\n')}\\n` };\n }\n\n // \u2500\u2500 validate <name> \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n if (sub === 'validate') {\n const name = rest[0];\n if (!name) return { message: 'Usage: /skill-gen validate <name>' };\n const result = await validateSkillNameAvailable(name, skillLoader);\n const lines: string[] = [`Validating \"${name}\":`];\n if (result.formatViolations.length > 0) {\n lines.push(` \u2717 Format issues:`);\n for (const v of result.formatViolations) lines.push(` - ${v}`);\n } else {\n lines.push(` \u2713 Format: valid kebab-case`);\n }\n if (result.conflicts.length > 0) {\n const sameLayer = result.conflicts.filter(\n (c) => c.source === 'project' || c.source === 'user',\n );\n const shadowing = result.conflicts.filter(\n (c) => c.source !== 'project' && c.source !== 'user',\n );\n if (sameLayer.length > 0) {\n lines.push(` \u2717 Collisions (same layer \u2014 would overwrite):`);\n for (const c of sameLayer) lines.push(` - ${c.name} (${c.source})`);\n }\n if (shadowing.length > 0) {\n lines.push(` \u26A0 Shadows lower-priority skills (intentional override):`);\n for (const c of shadowing) lines.push(` - ${c.name} (${c.source})`);\n }\n } else {\n lines.push(` \u2713 No collisions`);\n }\n lines.push(result.ok ? ` \u2192 Ready to use.` : ` \u2192 Fix the issues above first.`);\n return { message: lines.join('\\n') };\n }\n\n // \u2500\u2500 skeleton <name> [--desc ...] [--trigger a,b] [--global] [--force]\n if (sub === 'skeleton') {\n return runSkeleton(rest, ctx, skillLoader);\n }\n\n // \u2500\u2500 from-prompt <text> [--global] [--force] \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n if (sub === 'from-prompt') {\n return runFromPrompt(rest, ctx, skillLoader);\n }\n\n // \u2500\u2500 view <name> \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n if (sub === 'view') {\n const skillName = rest[0];\n if (!skillName) return { message: 'Usage: /skill-gen view <name>' };\n if (!skillLoader) return { message: 'No skill loader configured.' };\n const skill = await skillLoader.find(skillName);\n if (!skill) return { message: `Skill \"${skillName}\" not found.` };\n const body = await skillLoader.readBody(skillName);\n return { message: [`Skill: ${skillName}`, `Path: ${skill.path}`, '', body].join('\\n') };\n }\n\n // \u2500\u2500 edit <name> \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n if (sub === 'edit') {\n const skillName = rest[0];\n if (!skillName) return { message: 'Usage: /skill-gen edit <name>' };\n if (!skillLoader) return { message: 'No skill loader configured.' };\n const skill = await skillLoader.find(skillName);\n if (!skill) return { message: `Skill \"${skillName}\" not found.` };\n try {\n await openInEditor(skill.path);\n return { message: `Opening ${skill.path} in your editor\u2026` };\n } catch (err) {\n return { message: `\u2717 ${toErrorMessage(err)}` };\n }\n }\n\n // \u2500\u2500 default: interactive wizard (legacy `edit <name>` kept as alias) \u2500\n // Accept `/skill-gen edit <name>` as a legacy alias for `view` only when\n // someone passes it without the new semantics \u2014 but we already handled\n // `edit` above, so this only fires for bare `/skill-gen` or unknown args.\n if (trimmed.startsWith('edit ')) {\n // Back-compat: old `edit <name>` meant \"view\". Re-route to view.\n return buildSkillGeneratorCommand(skillLoader).run(`view ${rest.join(' ')}`, ctx);\n }\n\n // AI-guided creation: return runText so the AI reads the skill-creator\n // skill and walks the user through it.\n return {\n message:\n '\u2554\u2550\u2550\u2550 Skill Generator \u2550\u2550\u2550\u2557\\n\\nThe AI will guide you through creating a new skill.\\nAnswer its questions naturally. (Or use /skill-gen skeleton <name> for a quick scaffold.)',\n runText:\n 'I want to create a new AI skill. Read the skill-creator skill and guide me through the process. Ask me questions one at a time \u2014 name, description, what to cover \u2014 then create the SKILL.md file. After writing it, run /skill-gen validate <name> to confirm.',\n };\n },\n };\n}\n\n/** Parse and run the `skeleton` sub-command. */\nasync function runSkeleton(\n rest: string[],\n ctx: Context,\n skillLoader?: SkillLoader,\n): Promise<{ message: string }> {\n const name = rest.find((p) => !p.startsWith('--'));\n if (!name) {\n return {\n message:\n 'Usage: /skill-gen skeleton <name> [--desc \"...\"] [--trigger a,b,c] [--global] [--force]',\n };\n }\n const desc = parseFlagValue(rest, '--desc');\n const triggers = parseFlagValue(rest, '--trigger')\n ?.split(',')\n .map((t) => t.trim())\n .filter(Boolean);\n const isGlobal = rest.includes('--global');\n const force = rest.includes('--force');\n\n // Validate before writing.\n const validation = await validateSkillNameAvailable(name, skillLoader);\n if (!validation.ok) {\n const issues = [...validation.formatViolations];\n for (const c of validation.conflicts) {\n if (c.source === 'project' || c.source === 'user') {\n issues.push(\n `collides with existing ${c.source} skill \"${c.name}\" (use --force to overwrite)`,\n );\n }\n }\n return { message: `\u2717 Cannot scaffold \"${name}\":\\n - ${issues.join('\\n - ')}` };\n }\n\n const body = generateSkillSkeleton({ name, description: desc ?? '', triggerKeywords: triggers });\n const paths = resolveWstackPaths({ projectRoot: ctx.projectRoot });\n const skillsDir = isGlobal ? paths.globalSkills : paths.inProjectSkills;\n try {\n const written = await writeSkeletonSkill(skillsDir, body, { overwrite: force });\n const advisory = bodyLineAdvisory(body);\n return {\n message: [\n `\u2713 Scaffolded ${name} \u2192 ${written}`,\n advisory.over ? ` \u26A0 Body is ${advisory.lines} lines (skill-creator recommends \u2264500).` : '',\n ` Next: edit the body, then /skill-gen validate ${name}.`,\n ]\n .filter(Boolean)\n .join('\\n'),\n };\n } catch (err) {\n return { message: `\u2717 ${toErrorMessage(err)}` };\n }\n}\n\n/** Parse and run the `from-prompt` sub-command. */\nasync function runFromPrompt(\n rest: string[],\n ctx: Context,\n skillLoader?: SkillLoader,\n): Promise<{ message: string }> {\n // Everything that isn't a flag is the prompt text.\n const promptText = rest\n .filter((p) => !p.startsWith('--'))\n .join(' ')\n .trim();\n if (!promptText) {\n return { message: 'Usage: /skill-gen from-prompt <text> [--global] [--force]' };\n }\n const isGlobal = rest.includes('--global');\n const force = rest.includes('--force');\n\n const draft = extractSkillFromPrompt(promptText);\n if (!draft.suggestedName) {\n return { message: '\u2717 Could not derive a skill name from the prompt. Provide a # heading.' };\n }\n // Validate the derived name (don't block on shadowing).\n const validation = await validateSkillNameAvailable(draft.suggestedName, skillLoader);\n if (!validation.ok) {\n return {\n message:\n `\u2717 Derived name \"${draft.suggestedName}\" has issues:\\n - ` +\n [\n ...validation.formatViolations,\n ...validation.conflicts.map((c) => `collides with ${c.name}`),\n ].join('\\n - '),\n };\n }\n\n const body = generateSkillSkeleton({\n name: draft.suggestedName,\n description: draft.description,\n triggerKeywords: draft.triggerKeywords,\n });\n // Splice the extracted body into the skeleton's Overview.\n const withBody = draft.body\n ? body.replace('## Overview\\n', `## Overview\\n\\n${draft.body}\\n`)\n : body;\n const paths = resolveWstackPaths({ projectRoot: ctx.projectRoot });\n const skillsDir = isGlobal ? paths.globalSkills : paths.inProjectSkills;\n try {\n const written = await writeSkeletonSkill(skillsDir, withBody, { overwrite: force });\n return {\n message:\n `\u2713 Drafted ${draft.suggestedName} from prompt \u2192 ${written}\\n` +\n ` Triggers: ${draft.triggerKeywords.join(', ') || '(none detected)'}\\n` +\n ` Next: review and edit the body, then /skill-gen validate ${draft.suggestedName}.`,\n };\n } catch (err) {\n return { message: `\u2717 ${toErrorMessage(err)}` };\n }\n}\n\n/** Extract the value following a `--flag` from a token list. */\nfunction parseFlagValue(tokens: string[], flag: string): string | undefined {\n const idx = tokens.indexOf(flag);\n if (idx === -1) return undefined;\n const next = tokens[idx + 1];\n return next && !next.startsWith('--') ? next : undefined;\n}\n\nexport function buildSkillSearchCommand(\n _skillLoader: SkillLoader | undefined,\n registryAdapters: SkillRegistryAdapter[],\n): SlashCommand {\n return {\n name: 'skill-search',\n description: 'Search the skill registry (skills.sh) for installable skills.',\n argsHint: '<query> [--page N] [--pageSize N]',\n help: [\n '\u2554\u2550\u2550\u2550 Skill Search \u2550\u2550\u2550\u2557',\n '',\n 'Search the skill registry for installable skills.',\n 'Results show name, author, installs, security score, and the install ref.',\n '',\n 'Usage:',\n ' /skill-search react Search for \"react\" skills',\n ' /skill-search \"code review\" --page 2 Second page of results',\n '',\n `Registries: ${registryAdapters.map((a) => a.id).join(', ')}.`,\n 'To install a hit: /skill-install <owner/repo> (or the full install ref shown).',\n ].join('\\n'),\n async run(args: string) {\n const parts = args.trim().split(/\\s+/).filter(Boolean);\n const query = parts\n .filter((p) => !p.startsWith('--'))\n .join(' ')\n .trim();\n if (!query) return { message: 'Usage: /skill-search <query> [--page N]' };\n const page = parseFlagValue(parts, '--page');\n const pageSize = parseFlagValue(parts, '--pageSize');\n\n // Use a throwaway installer just to fan out across adapters (search()\n // doesn't touch the manifest or filesystem).\n const tmpInstaller = new SkillInstaller({\n manifestPath: ':memory:', // never written \u2014 search() is read-only\n projectSkillsDir: '/dev/null',\n globalSkillsDir: '/dev/null',\n projectHash: 'search',\n registryAdapters,\n });\n try {\n const perAdapter = await tmpInstaller.search(query, {\n ...(page ? { page: Number(page) } : {}),\n ...(pageSize ? { pageSize: Number(pageSize) } : {}),\n });\n const total = perAdapter.reduce((n, b) => n + b.results.length, 0);\n if (total === 0) {\n return {\n message: `No skills found for \"${query}\" in ${registryAdapters.map((a) => a.id).join(', ')}.`,\n };\n }\n const lines: string[] = [`Found ${total} skill(s) for \"${query}\":`];\n for (const block of perAdapter) {\n if (block.results.length === 0) continue;\n lines.push(`\\n${color.bold(block.adapterId)}:`);\n for (const r of block.results) {\n const tier = r.securityScore != null ? securityScoreToTier(r.securityScore) : undefined;\n const scoreMark =\n tier === 'low'\n ? ` \u26A0${r.securityScore}`\n : r.securityScore != null\n ? ` \u2713${r.securityScore}`\n : '';\n const installs = r.installs != null ? ` \u00B7 ${formatCount(r.installs)} installs` : '';\n const author = r.author ? ` ${color.dim(r.author)}` : '';\n lines.push(` ${color.bold(r.name)}${author}${scoreMark}${installs}`);\n if (r.description) lines.push(` ${truncate(r.description, 90)}`);\n lines.push(` ${color.dim('\u2192 /skill-install ' + r.installRef)}`);\n }\n }\n return { message: lines.join('\\n') };\n } catch (err) {\n return { message: `\u2717 Search failed: ${toErrorMessage(err)}` };\n }\n },\n };\n}\n\nexport function buildSkillInstallCommand(\n skillLoader?: SkillLoader,\n registryAdapters?: SkillRegistryAdapter[],\n): SlashCommand {\n return {\n name: 'skill-install',\n description: 'Install skills from a GitHub repository or a registry hit (skills.sh:<id>).',\n argsHint: '<user/repo[@ref] | skills.sh:<owner/repo> | registry:<id>> [--global]',\n help: [\n '\u2554\u2550\u2550\u2550 Skill Install \u2550\u2550\u2550\u2557',\n '',\n 'Install skills from GitHub (direct) or a registry (resolved to GitHub).',\n '',\n 'Usage:',\n ' /skill-install <user/repo> Install from default branch (main)',\n ' /skill-install <user/repo@ref> Install specific tag/branch/commit',\n ' /skill-install <user/repo> --global Install to user-global skills',\n ' /skill-install skills.sh:<owner/repo> Resolve a skills.sh hit and install',\n '',\n 'Supports single-skill repos (SKILL.md at root) and multi-skill repos (skills/).',\n 'Use /skill-search to find skills, then install with the shown install ref.',\n '',\n 'Private repos: set GITHUB_TOKEN (or GH_TOKEN) in your environment.',\n ].join('\\n'),\n async run(args: string, ctx: Context) {\n const parts = args.trim().split(/\\s+/);\n const ref = parts.find((p) => !p.startsWith('--'));\n const isGlobal = parts.includes('--global');\n\n if (!ref) {\n return {\n message:\n 'Usage: /skill-install <user/repo[@ref] | skills.sh:<owner/repo>> [--global]\\nUse /skill-search to find skills.',\n };\n }\n\n const installer = makeInstaller(skillLoader, ctx.projectRoot, registryAdapters);\n\n try {\n const results = await installer.install(ref, { global: isGlobal });\n if (results.length === 0) return { message: 'No skills found in the repository.' };\n\n const scope = isGlobal ? 'user-global' : 'project';\n const lines = [`Installed ${results.length} skill(s) [${scope}]:`];\n for (const r of results) {\n lines.push(` \u2713 ${r.name} (${r.source}@${r.ref})`);\n lines.push(` \u2192 ${r.path}`);\n }\n return { message: lines.join('\\n') };\n } catch (err) {\n const msg = toErrorMessage(err);\n return { message: `\u2717 Install failed: ${msg}` };\n }\n },\n };\n}\n\n/** Importable tool sources: Claude plus the other foreign agents. */\nconst IMPORT_SOURCE_TOOLS: ReadonlyArray<{ id: string; subdir: string }> = [\n { id: 'claude', subdir: 'skills' },\n ...FOREIGN_SKILL_TOOLS,\n];\n\n/**\n * Resolve a `--from <tool>` source directory for `/skill-import`. Returns the\n * project-level dir (`<project>/.<tool>/<subdir>`) or user-level (`~/.<tool>/<subdir>`\n * when `global`), or `undefined` for an unknown tool id. Exported for testing.\n */\nexport function resolveImportSourceDir(\n tool: string,\n opts: { global: boolean; projectRoot: string; homeDir?: string },\n): string | undefined {\n const entry = IMPORT_SOURCE_TOOLS.find((t) => t.id === tool);\n if (!entry) return undefined;\n const base = opts.global ? (opts.homeDir ?? os.homedir()) : opts.projectRoot;\n return path.join(base, '.' + entry.id, entry.subdir);\n}\n\nexport function buildSkillImportCommand(skillLoader?: SkillLoader): SlashCommand {\n return {\n name: 'skill-import',\n description: 'Import skills from a local directory or another agent into .wrongstack/skills.',\n argsHint: '[<src-dir> | --from <tool> | --from-claude] [--global] [--link]',\n help: [\n '\u2554\u2550\u2550\u2550 Skill Import \u2550\u2550\u2550\u2557',\n '',\n 'Copy (or symlink) skills into .wrongstack/skills so you can edit and commit',\n 'them. Foreign skills are already readable without importing \u2014 this takes ownership.',\n '',\n 'Usage:',\n ' /skill-import --from cursor Import project .cursor/skills',\n ' /skill-import --from codex --global Import ~/.codex/skills',\n ' /skill-import --from claude Import project .claude/skills (--from-claude alias)',\n ' /skill-import /path/to/skills Import from any directory',\n ' /skill-import --from trae --link Symlink instead of copy',\n '',\n `Known tools: ${IMPORT_SOURCE_TOOLS.map((t) => t.id).join(', ')}.`,\n 'Each subdirectory with a valid SKILL.md is imported.',\n ].join('\\n'),\n async run(args: string, ctx: Context) {\n const parts = args.trim().split(/\\s+/).filter(Boolean);\n const isGlobal = parts.includes('--global');\n const link = parts.includes('--link');\n const fromIdx = parts.indexOf('--from');\n let tool: string | undefined;\n if (fromIdx !== -1) tool = parts[fromIdx + 1];\n else if (parts.includes('--from-claude')) tool = 'claude';\n const positional = parts.find((p) => !p.startsWith('--') && p !== tool);\n\n let srcDir: string | undefined;\n if (tool) {\n srcDir = resolveImportSourceDir(tool, { global: isGlobal, projectRoot: ctx.projectRoot });\n if (!srcDir) {\n return {\n message: `Unknown tool \"${tool}\". Known: ${IMPORT_SOURCE_TOOLS.map((t) => t.id).join(', ')}`,\n };\n }\n } else if (positional) {\n srcDir = path.resolve(ctx.projectRoot, positional);\n } else {\n return {\n message:\n 'Usage: /skill-import <src-dir> | --from <tool> | --from-claude [--global] [--link]',\n };\n }\n\n const installer = makeInstaller(skillLoader, ctx.projectRoot);\n try {\n const results = await installer.importFromDir(srcDir, { global: isGlobal, link });\n if (results.length === 0) {\n return { message: `No valid skills found in ${srcDir}.` };\n }\n const scope = isGlobal ? 'user-global' : 'project';\n const lines = [\n `Imported ${results.length} skill(s) [${scope}]${link ? ' (symlinked)' : ''}:`,\n ];\n for (const r of results) {\n lines.push(` \u2713 ${r.name}`);\n lines.push(` \u2192 ${r.path}`);\n }\n return { message: lines.join('\\n') };\n } catch (err) {\n return { message: `\u2717 Import failed: ${toErrorMessage(err)}` };\n }\n },\n };\n}\n\nexport function buildSkillUpdateCommand(\n skillLoader?: SkillLoader,\n registryAdapters?: SkillRegistryAdapter[],\n): SlashCommand {\n return {\n name: 'skill-update',\n description: 'Update installed skills from their GitHub source.',\n argsHint: '[name|ref] [--global]',\n help: [\n '\u2554\u2550\u2550\u2550 Skill Update \u2550\u2550\u2550\u2557',\n '',\n 'Update installed skills from their GitHub source.',\n '',\n 'Usage:',\n ' /skill-update Update all installed skills',\n ' /skill-update <name> Update a specific skill',\n ' /skill-update <user/repo@ref> Update to a different ref',\n ' /skill-update <name> --global Update a global skill',\n ].join('\\n'),\n async run(args: string, ctx: Context) {\n const parts = args.trim().split(/\\s+/);\n const nameOrRef = parts.find((p) => !p.startsWith('--'));\n const isGlobal = parts.includes('--global');\n\n const installer = makeInstaller(skillLoader, ctx.projectRoot, registryAdapters);\n\n try {\n const result = await installer.update(nameOrRef, { global: isGlobal });\n const lines: string[] = [];\n\n if (result.updated.length > 0) {\n lines.push(`Updated ${result.updated.length} skill(s):`);\n for (const u of result.updated) {\n lines.push(\n u.oldRef !== u.newRef\n ? ` \u2713 ${u.name} (${u.oldRef} \u2192 ${u.newRef})`\n : ` \u2713 ${u.name} (refreshed)`,\n );\n }\n }\n if (result.unchanged.length > 0) lines.push(`Up to date: ${result.unchanged.join(', ')}`);\n if (result.errors.length > 0) {\n for (const e of result.errors) lines.push(` \u2717 ${e.name}: ${e.error}`);\n }\n if (lines.length === 0) return { message: 'No installed skills to update.' };\n\n return { message: lines.join('\\n') };\n } catch (err) {\n const msg = toErrorMessage(err);\n return { message: `\u2717 Update failed: ${msg}` };\n }\n },\n };\n}\n\nexport function buildSkillUninstallCommand(skillLoader?: SkillLoader): SlashCommand {\n return {\n name: 'skill-uninstall',\n description: 'Remove an installed skill.',\n argsHint: '<name> [--global]',\n help: [\n '\u2554\u2550\u2550\u2550 Skill Uninstall \u2550\u2550\u2550\u2557',\n '',\n 'Remove an installed skill and its files.',\n '',\n 'Usage:',\n ' /skill-uninstall <name> Remove from project skills',\n ' /skill-uninstall <name> --global Remove from user-global skills',\n ].join('\\n'),\n async run(args: string, ctx: Context) {\n const parts = args.trim().split(/\\s+/);\n const name = parts.find((p) => !p.startsWith('--'));\n const isGlobal = parts.includes('--global');\n\n if (!name) {\n // List installed skills when no name given\n const installer = makeInstaller(skillLoader, ctx.projectRoot);\n const installed = await installer.listInstalled();\n if (installed.length === 0) return { message: 'No installed skills found.' };\n const scope = isGlobal ? 'user' : 'project';\n const filtered = installed.filter((s) => s.scope === scope);\n if (filtered.length === 0) {\n return { message: `No installed skills found (${scope} scope).` };\n }\n const lines = [`Installed skills (${scope}):`];\n for (const s of filtered) {\n lines.push(` ${s.name} ${s.source}@${s.ref} (${s.installedAt.slice(0, 10)})`);\n }\n lines.push('', 'Use /skill-uninstall <name> to remove.');\n return { message: lines.join('\\n') };\n }\n\n const installer = makeInstaller(skillLoader, ctx.projectRoot);\n\n try {\n await installer.uninstall(name, { global: isGlobal });\n return { message: `\u2713 Skill \"${name}\" uninstalled.` };\n } catch (err) {\n const msg = toErrorMessage(err);\n return { message: `\u2717 Uninstall failed: ${msg}` };\n }\n },\n };\n}\n\n// \u2500\u2500 Formatting helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction formatCount(n: number): string {\n if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;\n if (n >= 1_000) return `${(n / 1_000).toFixed(1)}k`;\n return String(n);\n}\n\nfunction truncate(s: string, max: number): string {\n return s.length > max ? s.slice(0, max - 1) + '\u2026' : s;\n}\n", "/**\n * Well-known foreign coding-agent skill directories. All follow the\n * agentskills.io `SKILL.md` format, so the same loader reads them \u2014 this just\n * tells it WHERE each agent keeps them.\n *\n * Claude is handled separately by the loader (`claude-project` / `claude-user`\n * sources); this list covers the OTHER agents. Every tool here stores skills\n * under `~/.<tool>/skills` (+ `<project>/.<tool>/skills`).\n *\n * Dirs that don't exist are skipped gracefully, so listing many is cheap.\n *\n * NOTE: Cursor previously used a non-standard `skills-cursor` subdir. As of the\n * 2026-07 alignment with the broader skills.sh / antfu-skills-cli / vercel-labs\n * ecosystem, Cursor uses the standard `skills` subdir like everyone else.\n * (`skills-cursor` was WrongStack-only and meant real Cursor skills were never\n * discovered \u2014 see docs/skills.md.)\n */\nexport interface ForeignSkillTool {\n /** Tool id \u2014 also the directory name segment (`~/.<id>/\u2026`). */\n id: string;\n /** Skills subdirectory name under `~/.<id>/`. */\n subdir: string;\n}\n\nexport const FOREIGN_SKILL_TOOLS: readonly ForeignSkillTool[] = [\n { id: 'agents', subdir: 'skills' }, // shared store (asm / agentskills.io ecosystem)\n { id: 'codex', subdir: 'skills' }, // OpenAI Codex CLI\n { id: 'gemini', subdir: 'skills' }, // Gemini CLI\n { id: 'cursor', subdir: 'skills' }, // Cursor (standard subdir, aligned with skills.sh ecosystem)\n { id: 'qwen', subdir: 'skills' }, // Qwen Code\n { id: 'trae', subdir: 'skills' }, // Trae\n { id: 'windsurf', subdir: 'skills' }, // Windsurf\n];\n\n/** Set of known tool ids \u2014 used to flag typos in `config.skills.foreignSources`. */\nconst KNOWN_FOREIGN_IDS = new Set(FOREIGN_SKILL_TOOLS.map((t) => t.id));\n\n/** Result of resolving a `foreignSources` config option. */\nexport interface ResolvedForeignTools {\n /** Tool ids that will be scanned (subset of {@link FOREIGN_SKILL_TOOLS}). */\n ids: string[];\n /** Tool ids the user asked for that aren't known \u2014 likely typos (e.g. `corser`). */\n unknownIds: string[];\n}\n\n/**\n * Resolve the `config.skills.foreignSources` option into the list of tool ids\n * to scan. Kept for backward compatibility (returns only `ids`).\n * - `false` \u2192 none\n * - `string[]` \u2192 only those ids (unknown ids silently dropped \u2014 see\n * {@link resolveForeignToolIdsWithWarnings} to surface them)\n * - `true` / `undefined` \u2192 all well-known tools\n */\nexport function resolveForeignToolIds(opt: boolean | string[] | undefined): string[] {\n return resolveForeignToolIdsWithWarnings(opt).ids;\n}\n\n/**\n * Like {@link resolveForeignToolIds}, but also returns tool ids the caller asked\n * for that don't match any known agent. Callers that want to warn the user\n * about a likely typo (e.g. `foreignSources: [\"corser\"]`) should prefer this.\n *\n * - `false` \u2192 none\n * - `string[]` \u2192 known ids included, unknown ones returned in `unknownIds`\n * - `true` / `undefined` \u2192 all well-known tools (no unknowns possible)\n */\nexport function resolveForeignToolIdsWithWarnings(\n opt: boolean | string[] | undefined,\n): ResolvedForeignTools {\n if (opt === false) return { ids: [], unknownIds: [] };\n if (Array.isArray(opt)) {\n const ids: string[] = [];\n const unknownIds: string[] = [];\n for (const id of opt) {\n if (KNOWN_FOREIGN_IDS.has(id)) ids.push(id);\n else unknownIds.push(id);\n }\n return { ids, unknownIds };\n }\n return { ids: FOREIGN_SKILL_TOOLS.map((t) => t.id), unknownIds: [] };\n}\n\n/**\n * Security tier bucket for a registry skill's `securityScore` (0\u2013100).\n * Mirrors the ags (agentskill-sh/ags) thresholds: skills below 30 need\n * explicit confirmation before install.\n */\nexport type SkillSecurityTier = 'low' | 'medium' | 'high';\n\n/** Classify a 0\u2013100 security score into a tier. 0/undefined \u2192 unknown \u2192 `low`. */\nexport function securityScoreToTier(score: number | undefined | null): SkillSecurityTier {\n if (score == null || Number.isNaN(score)) return 'low';\n if (score < 30) return 'low';\n if (score < 70) return 'medium';\n return 'high';\n}\n", "/**\n * GitHub-direct registry adapter.\n *\n * This is the original pre-registry install path wrapped in the adapter\n * interface: the user types `user/repo[@ref]` directly. It does NOT search\n * (GitHub code search is a separate API with its own auth/rate-limit story and\n * isn't a skill catalog), so `search()` returns an empty result. Its job is\n * solely to make `user/repo` flow through the same `<adapterId>:<registryId>`\n * resolution as the skills.sh adapter \u2014 except here the \"registry id\" IS the\n * install ref already.\n *\n * Registered as the fallback adapter so `/skill-install user/repo` keeps\n * working unchanged when no `<adapterId>:` prefix is given.\n */\nimport type {\n RegistrySearchOptions,\n RegistrySearchResult,\n SkillRegistryAdapter,\n} from './registry-adapter.js';\n\nexport const githubDirectAdapter: SkillRegistryAdapter = {\n id: 'github',\n displayName: 'GitHub (direct)',\n\n async search(_query: string, _opts: RegistrySearchOptions = {}): Promise<RegistrySearchResult> {\n // GitHub direct is not a searchable catalog. Returning empty keeps the\n // unified `/skill-search` UX (it just shows results from other adapters).\n return { adapterId: 'github', results: [], hasMore: false };\n },\n\n resolveInstallRef(registryId: string): string {\n // For the direct adapter the registry id is already the install ref.\n // Light validation: must contain a slash (owner/repo). Full parsing is done\n // by `parseSkillRef` downstream.\n const trimmed = registryId.trim();\n if (!trimmed.includes('/')) {\n // Defer to parseSkillRef for the structured error message.\n return trimmed;\n }\n return trimmed;\n },\n};\n", "/**\n * skills.sh registry adapter.\n *\n * skills.sh is the open agent-skills marketplace (backed by mastra-ai/skills-api)\n * indexing 34k+ skills from 2.8k+ GitHub repos. Every entry is an\n * agentskills.io `SKILL.md` skill whose source repo is known, so resolving a\n * registry hit to a `user/repo@ref` install ref is just a lookup.\n *\n * API shape (https://skills.sh/api/skills):\n * GET /api/skills?query=<q>&page=<p>&pageSize=<ps>&sortBy=installs\n * \u2192 { results: Array<{ name, description, owner, repo, ref?, installs?, score?, updatedAt? }> }\n *\n * The base URL is configurable (`config.skills.registryUrl`, user-config only \u2014\n * stripped from in-project config because the parsed response flows into the\n * prompt and a repo-controlled URL would be an SSRF / prompt-injection vector).\n *\n * This adapter is defensive about the response schema: skills.sh is a\n * third-party service and its exact JSON shape has changed before. We parse\n * loosely (missing fields become `undefined`) and throw `ParseError` only when\n * the response isn't the expected shape at all (no `results` array), so a\n * minor additive schema change degrades gracefully instead of crashing the\n * command.\n */\nimport { FetchError, ParseError } from '../../types/errors.js';\nimport type {\n RegistrySearchOptions,\n RegistrySearchResult,\n RegistrySkillSummary,\n SkillRegistryAdapter,\n} from './registry-adapter.js';\n\n/** Default skills.sh base URL. Override via `config.skills.registryUrl`. */\nexport const DEFAULT_SKILLS_SH_URL = 'https://skills.sh';\n\nconst SEARCH_TIMEOUT_MS = 15_000;\nconst MAX_PAGE_SIZE = 50;\n\n/** Injectable fetcher (mirrors the `prompt-installer` JsonFetcher pattern). */\nexport type SkillsShFetcher = (url: string) => Promise<unknown>;\n\nconst defaultFetcher: SkillsShFetcher = async (url) => {\n let res: Response;\n try {\n res = await fetch(url, {\n signal: AbortSignal.timeout(SEARCH_TIMEOUT_MS),\n headers: {\n Accept: 'application/json',\n 'User-Agent': 'wrongstack-skill-installer',\n },\n redirect: 'follow',\n });\n } catch (err) {\n throw new FetchError({\n message: `Network error querying skill registry: ${\n err instanceof Error ? err.message : String(err)\n }`,\n status: 0,\n context: { url, op: 'skills.sh.search' },\n cause: err,\n });\n }\n if (!res.ok) {\n // 429 / 5xx are recoverable; everything else is a hard failure.\n throw new FetchError({\n message: `Skill registry returned ${res.status} ${res.statusText}`,\n status: res.status,\n context: { url, op: 'skills.sh.search' },\n });\n }\n try {\n return await res.json();\n } catch (err) {\n throw new ParseError({\n message: `Skill registry response was not valid JSON: ${\n err instanceof Error ? err.message : String(err)\n }`,\n source: 'skills.sh.search',\n context: { url },\n cause: err,\n });\n }\n};\n\nexport interface SkillsShAdapterOptions {\n /** Base URL (no trailing slash). Defaults to {@link DEFAULT_SKILLS_SH_URL}. */\n baseUrl?: string | undefined;\n /** Injectable fetcher for tests. */\n fetcher?: SkillsShFetcher | undefined;\n}\n\nexport function createSkillsShAdapter(opts: SkillsShAdapterOptions = {}): SkillRegistryAdapter {\n const baseUrl = (opts.baseUrl ?? DEFAULT_SKILLS_SH_URL).replace(/\\/+$/, '');\n const fetcher = opts.fetcher ?? defaultFetcher;\n const id = 'skills.sh';\n\n return {\n id,\n displayName: 'skills.sh',\n\n async search(query: string, sopts: RegistrySearchOptions = {}): Promise<RegistrySearchResult> {\n const page = Math.max(1, sopts.page ?? 1);\n const pageSize = Math.min(MAX_PAGE_SIZE, Math.max(1, sopts.pageSize ?? 20));\n const q = query.trim();\n if (!q) return { adapterId: id, results: [], hasMore: false };\n\n const url =\n `${baseUrl}/api/skills?query=${encodeURIComponent(q)}` +\n `&page=${page}&pageSize=${pageSize}&sortBy=installs`;\n\n const raw = await fetcher(url);\n const results = parseResults(raw, url);\n\n return {\n adapterId: id,\n results,\n hasMore: results.length === pageSize,\n };\n },\n\n resolveInstallRef(registryId: string): string {\n // skills.sh ids are `<owner>/<repo>` (optionally `@<ref>`). We accept both\n // the bare id and an explicit `@ref` suffix; if a ref isn't given we let\n // the github-fetcher default to `main`.\n const trimmed = registryId.trim();\n if (!trimmed) {\n throw new ParseError({\n message: 'Empty skills.sh registry id.',\n source: 'skills.sh.resolveInstallRef',\n });\n }\n // Validate it looks like owner/repo (with optional @ref).\n const atIdx = trimmed.indexOf('@');\n const repoPart = atIdx > 0 ? trimmed.slice(0, atIdx) : trimmed;\n const segs = repoPart.split('/').filter(Boolean);\n if (segs.length !== 2) {\n throw new ParseError({\n message:\n `Invalid skills.sh id \"${registryId}\". Expected \"<owner>/<repo>\" or ` +\n `\"<owner>/<repo>@<ref>\".`,\n source: 'skills.sh.resolveInstallRef',\n context: { registryId },\n });\n }\n return trimmed;\n },\n };\n}\n\n/**\n * Parse the skills.sh search response into normalized summaries.\n *\n * The schema is parsed defensively: the top-level must be an object with a\n * `results` array (else `ParseError`), but individual entries may miss fields \u2014\n * those become `undefined` on the summary. An entry without a usable\n * `installRef` (`owner` + `repo`) is dropped since the installer can't act on it.\n */\nfunction parseResults(raw: unknown, url: string): RegistrySkillSummary[] {\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {\n throw new ParseError({\n message: 'Skill registry response was not a JSON object.',\n source: 'skills.sh.search',\n context: { url },\n });\n }\n const results = (raw as { results?: unknown }).results;\n if (!Array.isArray(results)) {\n // Some deployments wrap results differently. Treat a missing/Non-array\n // `results` field as an empty result set rather than crashing \u2014 the user\n // just sees \"no matches\", which is correct if the schema shifted.\n return [];\n }\n\n const out: RegistrySkillSummary[] = [];\n for (let i = 0; i < results.length; i++) {\n const entry = results[i] as Record<string, unknown> | null;\n if (!entry || typeof entry !== 'object') continue;\n\n const name = strField(entry, 'name') ?? strField(entry, 'slug');\n const description = strField(entry, 'description') ?? '';\n const owner = strField(entry, 'owner') ?? strField(entry, 'author');\n const repo = strField(entry, 'repo') ?? strField(entry, 'repository');\n if (!name || !owner || !repo) continue; // can't build an install ref\n\n const ref = strField(entry, 'ref') ?? strField(entry, 'branch') ?? strField(entry, 'tag');\n const installRef = ref ? `${owner}/${repo}@${ref}` : `${owner}/${repo}`;\n\n out.push({\n id: strField(entry, 'id') ?? `${owner}/${repo}`,\n name,\n description,\n author: owner,\n installs: numField(entry, 'installs') ?? numField(entry, 'installCount'),\n stars: numField(entry, 'stars') ?? numField(entry, 'starCount'),\n securityScore: numField(entry, 'securityScore') ?? numField(entry, 'score'),\n updatedAt: strField(entry, 'updatedAt') ?? strField(entry, 'updated_at'),\n installRef,\n });\n }\n return out;\n}\n\nfunction strField(rec: Record<string, unknown>, key: string): string | undefined {\n const v = rec[key];\n return typeof v === 'string' && v.length > 0 ? v : undefined;\n}\n\nfunction numField(rec: Record<string, unknown>, key: string): number | undefined {\n const v = rec[key];\n if (typeof v === 'number' && Number.isFinite(v)) return v;\n if (typeof v === 'string' && /^\\d+(\\.\\d+)?$/.test(v.trim())) {\n const n = Number(v);\n if (Number.isFinite(n)) return n;\n }\n return undefined;\n}\n", "/**\n * Skill authoring helpers \u2014 deterministic (no LLM) utilities that power the\n * `/skill-gen` sub-commands: validate, skeleton, from-prompt, edit.\n *\n * These are pure functions over the skill loader + filesystem so they're trivial\n * to test and don't need a running agent. The interactive `/skill-gen` wizard\n * (default, no sub-command) still delegates to the `skill-creator` skill via\n * `runText` \u2014 that's the right call for the open-ended \"help me write one\"\n * flow. These utilities cover the deterministic parts: name/format checks,\n * scaffold generation, prompt\u2192skill extraction, and opening in `$EDITOR`.\n *\n * Distinct from `security-scanner/skill-generator.ts`, which deterministically\n * generates a *security-scanning* skill from a tech stack \u2014 that one builds a\n * specific skill from a fixed pattern library; this one is the general-purpose\n * authoring toolkit.\n */\nimport { spawn } from 'node:child_process';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { ERROR_CODES, WrongStackError } from '../types/errors.js';\nimport type { SkillEntry, SkillLoader } from '../types/skill.js';\nimport { isValidSkillNameFormat, parseSkillFrontmatter, validateSkillName } from './frontmatter.js';\nimport { SKILL_LIMITS } from './limits.js';\n\n/** Result of validating a proposed skill name. */\nexport interface SkillNameValidation {\n /** Whether the name is valid kebab-case AND free of collisions. */\n ok: boolean;\n /** Format violations (empty when the name is valid kebab-case). */\n formatViolations: string[];\n /** Existing skills with the same name (empty when there's no collision). */\n conflicts: SkillEntry[];\n}\n\n/**\n * Validate a proposed skill name: format (kebab-case, \u226464 chars) plus collision\n * check against every skill the loader can see (project, user, foreign,\n * bundled). A collision isn't fatal \u2014 project skills intentionally shadow\n * lower layers \u2014 so `ok` is true when the only collision is with a foreign or\n * bundled skill (intended shadowing), but `conflicts` is still populated so the\n * user can decide. A collision with another project or user skill of the same\n * name does fail (`ok: false`), since that would silently overwrite it.\n */\nexport async function validateSkillNameAvailable(\n name: string,\n loader?: SkillLoader,\n): Promise<SkillNameValidation> {\n const formatViolations = validateSkillName(name);\n const conflicts = loader ? (await loader.listEntries()).filter((e) => e.name === name) : [];\n const formatOk = formatViolations.length === 0;\n // A collision with a same-or-higher priority layer (project\u2194project, user\u2194user)\n // is a real conflict. Collisions with foreign/bundled skills are intended\n // shadowing (project skills win by priority) and don't fail validation.\n const collisionBlocks = conflicts.some((c) => c.source === 'project' || c.source === 'user');\n return {\n ok: formatOk && !collisionBlocks,\n formatViolations,\n conflicts,\n };\n}\n\nexport interface SkillSkeletonOptions {\n name: string;\n description: string;\n /** Trigger keywords for the `Triggers:` line. */\n triggerKeywords?: string[] | undefined;\n /** Optional version (default `1.0.0`). */\n version?: string | undefined;\n}\n\n/**\n * Generate a SKILL.md body (with frontmatter) following the agentskills.io\n * format and the `skill-creator` skill's recommended skeleton. Deterministic:\n * the same inputs always produce the same output, and the result round-trips\n * through `parseSkillFrontmatter` (so what we write is what the loader reads).\n *\n * The body is a skeleton \u2014 the user fills in Rules/Patterns/etc. The\n * `skill-creator` skill is the right tool for the open-ended authoring; this\n * is the scaffold.\n */\nexport function generateSkillSkeleton(opts: SkillSkeletonOptions): string {\n const name = opts.name.trim();\n if (!isValidSkillNameFormat(name)) {\n throw new WrongStackError({\n message: `Cannot generate skeleton: invalid skill name \"${name}\". Names must be kebab-case (a-z0-9 and hyphens), \u226464 chars.`,\n code: ERROR_CODES.VALIDATION_ERROR,\n subsystem: 'general',\n context: { name },\n });\n }\n const description = opts.description.trim();\n const triggers = (opts.triggerKeywords ?? [])\n .map((k) => k.trim())\n .filter(Boolean)\n .map((k) => `\"${k}\"`)\n .join(', ');\n const triggerLine = triggers ? `\\n Triggers: user says ${triggers}.` : '';\n const version = opts.version?.trim() || '1.0.0';\n const title = name\n .split('-')\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1))\n .join(' ');\n\n return `---\nname: ${name}\ndescription: |\n ${description || `Use this skill when <trigger situation>.`}${triggerLine}\nversion: ${version}\n---\n\n# ${title}\n\n## Overview\n\n${description || 'One-line description of what this skill does.'}\n\n## Rules\n\n1. Rule one\n2. Rule two\n\n## Patterns\n\n### Do\n\n\\`\\`\\`ts\n// good example\n\\`\\`\\`\n\n### Don't\n\n\\`\\`\\`ts\n// bad example\n\\`\\`\\`\n\n## Skills in scope\n\n- \\`other-skill\\` \u2014 for delegation when this skill needs help\n`;\n}\n\n/** Result of extracting a skill draft from a free-form prompt. */\nexport interface ExtractedSkillDraft {\n /** Suggested name (kebab-case) derived from the prompt, or empty. */\n suggestedName: string;\n /** Description (first paragraph of the prompt). */\n description: string;\n /** Remaining prompt text, used as the skill body. */\n body: string;\n /** Trigger keywords extracted from the prompt. */\n triggerKeywords: string[];\n}\n\n/**\n * Heuristically extract a skill draft from a free-form prompt. No LLM \u2014 just\n * light structure detection:\n * - First non-empty paragraph \u2192 `description`.\n * - A `# heading` or the first line \u2192 suggested kebab-case `suggestedName`.\n * - Remaining text \u2192 `body`.\n * - Quoted tokens and the heading words \u2192 `triggerKeywords`.\n *\n * The output is a starting point the user (or the skill-creator wizard) refines.\n */\nexport function extractSkillFromPrompt(prompt: string): ExtractedSkillDraft {\n const text = prompt.trim();\n if (!text) {\n return { suggestedName: '', description: '', body: '', triggerKeywords: [] };\n }\n\n // Detect a markdown heading as the title; fall back to the first line.\n const headingMatch = text.match(/^#{1,6}\\s+(.+?)\\s*$/m);\n const firstLine =\n text\n .split('\\n')\n .find((l) => l.trim().length > 0)\n ?.trim() ?? text;\n const titleSource = headingMatch?.[1] ?? firstLine.replace(/^#+\\s*/, '');\n const suggestedName = toKebab(titleSource).slice(0, SKILL_LIMITS.SKILL_NAME_MAX_LEN);\n\n // Split into paragraphs (blocks separated by blank lines).\n const paragraphs = text\n .split(/\\n\\s*\\n/)\n .map((p) => p.trim())\n .filter(Boolean);\n const description = paragraphs[0]?.replace(/^#{1,6}\\s+/m, '').trim() ?? titleSource;\n const body = paragraphs.slice(1).join('\\n\\n');\n\n // Trigger keywords: quoted tokens (\"...\"), plus a few significant words from\n // the title (lowercased, >3 chars, not stopwords).\n const quoted = [...text.matchAll(/\"([^\"]{2,40})\"/g)]\n .map((m) => m[1])\n .filter((q): q is string => typeof q === 'string')\n .map((q) => q.toLowerCase());\n const titleWords = titleSource\n .split(/\\W+/)\n .map((w) => w.toLowerCase())\n .filter((w) => w.length > 3 && !STOPWORDS.has(w));\n const triggerKeywords = dedupe([...quoted, ...titleWords]).slice(0, 8);\n\n return { suggestedName, description, body, triggerKeywords };\n}\n\n/**\n * Open a file in the user's editor (`$VISUAL` \u2192 `$EDITOR` \u2192 platform default).\n * Detached + unref'd so the editor outlives the WrongStack process. Throws a\n * `WrongStackError` when no editor can be resolved.\n */\nexport async function openInEditor(\n filePath: string,\n env: NodeJS.ProcessEnv = process.env,\n): Promise<void> {\n const editor =\n (env['VISUAL']?.trim() && env['VISUAL']) ||\n (env['EDITOR']?.trim() && env['EDITOR']) ||\n defaultEditor();\n if (!editor) {\n throw new WrongStackError({\n message:\n 'No editor found. Set the EDITOR or VISUAL environment variable ' +\n '(e.g. `export EDITOR=code` or `export EDITOR=vim`).',\n code: ERROR_CODES.VALIDATION_ERROR,\n subsystem: 'general',\n context: { filePath },\n });\n }\n const shell = process.platform === 'win32';\n // Split editor into command + args (e.g. `code --wait`). The file path is\n // appended last so it works whether the editor is a single binary or a\n // command-with-flags string.\n const parts = editor.split(/\\s+/).filter(Boolean);\n if (parts.length === 0) {\n throw new WrongStackError({\n message: 'Resolved editor command is empty.',\n code: ERROR_CODES.VALIDATION_ERROR,\n subsystem: 'general',\n context: { filePath },\n });\n }\n const child = spawn(parts[0] as string, [...parts.slice(1), filePath], {\n stdio: 'ignore',\n detached: true,\n shell,\n });\n child.unref();\n}\n\n/**\n * Write a skeleton skill to `<skillsDir>/<name>/SKILL.md`. Returns the written\n * path. Used by `/skill-gen skeleton` and `/skill-gen from-prompt`. Refuses to\n * overwrite an existing SKILL.md unless `overwrite` is set \u2014 a guard against\n * clobbering a hand-edited skill.\n */\nexport async function writeSkeletonSkill(\n skillsDir: string,\n body: string,\n opts: { overwrite?: boolean | undefined } = {},\n): Promise<string> {\n // Parse the frontmatter to find the name (so the dir matches the skill name).\n const fm = parseSkillFrontmatter(body);\n const name = fm.name;\n if (!name || !isValidSkillNameFormat(name)) {\n throw new WrongStackError({\n message: 'Skeleton body has no valid `name` in its frontmatter.',\n code: ERROR_CODES.VALIDATION_ERROR,\n subsystem: 'general',\n });\n }\n const skillDir = path.join(skillsDir, name);\n const skillFile = path.join(skillDir, 'SKILL.md');\n if (!opts.overwrite) {\n try {\n await fs.access(skillFile);\n throw new WrongStackError({\n message: `A skill already exists at ${skillFile}. Use --force to overwrite.`,\n code: ERROR_CODES.VALIDATION_ERROR,\n subsystem: 'general',\n context: { skillFile },\n });\n } catch (err) {\n // re-throw the WrongStackError from above; swallow ENOENT (file absent).\n if (err instanceof WrongStackError) throw err;\n }\n }\n await fs.mkdir(skillDir, { recursive: true });\n await fs.writeFile(skillFile, body, 'utf8');\n return skillFile;\n}\n\n/** Soft length advisory for a SKILL.md body (the `skill-creator` 500-line rule). */\nexport function bodyLineAdvisory(body: string): { lines: number; over: boolean } {\n const lines = body.split('\\n').length;\n return { lines, over: lines > SKILL_LIMITS.SKILL_BODY_LINE_LIMIT };\n}\n\n// \u2500\u2500 Utilities \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst STOPWORDS = new Set([\n 'the',\n 'and',\n 'for',\n 'with',\n 'that',\n 'this',\n 'from',\n 'your',\n 'have',\n 'will',\n 'are',\n 'was',\n 'were',\n 'been',\n 'into',\n 'when',\n 'use',\n 'skill',\n 'about',\n]);\n\nfunction toKebab(s: string): string {\n return (\n s\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, SKILL_LIMITS.SKILL_NAME_MAX_LEN) || 'skill'\n );\n}\n\nfunction dedupe<T>(arr: T[]): T[] {\n return [...new Set(arr)];\n}\n\nfunction defaultEditor(): string | undefined {\n if (process.platform === 'win32') return 'notepad';\n if (process.platform === 'darwin') return 'open';\n return undefined; // linux: require explicit EDITOR/VISUAL\n}\n", "/**\n * Shared SKILL.md frontmatter parser + agentskills.io name validation.\n *\n * The SKILL.md format (https://agentskills.io/specification) is YAML\n * frontmatter between `---` markers followed by a Markdown body. This parser is\n * intentionally minimal \u2014 it handles the fields skills actually use, with YAML\n * block scalars (`|` / `>`) for multi-line values and an indented map for\n * `metadata`. It is NOT a general YAML parser; skill files are trusted markdown.\n */\nexport interface ParsedSkillFrontmatter {\n name?: string | undefined;\n description?: string | undefined;\n /** WrongStack extension; informational only. */\n version?: string | undefined;\n license?: string | undefined;\n compatibility?: string | undefined;\n metadata?: Record<string, string> | undefined;\n /** `allowed-tools` (spec, experimental) \u2192 split on whitespace. */\n allowedTools?: string[] | undefined;\n}\n\n/** Fields whose value is a single scalar string. */\nconst SCALAR_KEYS = new Set(['name', 'description', 'version', 'license', 'compatibility']);\n\n/**\n * Parse the YAML frontmatter block from a raw SKILL.md file. Returns `{}` when\n * there is no (or unclosed) frontmatter \u2014 callers treat that as \"skip\".\n *\n * Line endings are normalized first: CRLF (and lone CR) would otherwise leave a\n * trailing `\\r` on each line, and since `.` / `$` don't match `\\r`, the\n * `key: value` regex would fail on every line and silently drop the whole\n * frontmatter. Real skill files are frequently CRLF (Windows / some editors).\n */\nexport function parseSkillFrontmatter(raw: string): ParsedSkillFrontmatter {\n const text = normalizeLineEndings(raw);\n if (!text.startsWith('---')) return {};\n const end = text.indexOf('\\n---', 4);\n if (end === -1) return {};\n return parseFrontmatterBlock(text.slice(4, end));\n}\n\n/** Strip leading YAML frontmatter (`---\\n\u2026\\n---`) from a SKILL.md file. */\nexport function stripFrontmatter(raw: string): string {\n const text = normalizeLineEndings(raw);\n if (!text.startsWith('---')) return text;\n const end = text.indexOf('\\n---', 4);\n if (end === -1) return text;\n let body = text.slice(end + 4);\n if (body.startsWith('\\n')) body = body.slice(1);\n return body;\n}\n\n/** Normalize CRLF and lone CR to LF. */\nfunction normalizeLineEndings(s: string): string {\n return s.replace(/\\r\\n?/g, '\\n');\n}\n\nfunction parseFrontmatterBlock(block: string): ParsedSkillFrontmatter {\n const out: ParsedSkillFrontmatter = {};\n const lines = block.split('\\n');\n let i = 0;\n while (i < lines.length) {\n const line = lines[i] ?? '';\n const m = /^([a-zA-Z][a-zA-Z0-9_-]*):\\s*(.*)$/.exec(line);\n if (!m) {\n i++;\n continue;\n }\n const key = m[1] ?? '';\n const rest = (m[2] ?? '').trim();\n\n if (key === 'metadata') {\n const map: Record<string, string> = {};\n i++;\n while (i < lines.length) {\n const sub = lines[i] ?? '';\n const sm = /^\\s+([a-zA-Z0-9_.-]+):\\s*(.*)$/.exec(sub);\n if (!sm) break;\n map[sm[1] ?? ''] = unquote((sm[2] ?? '').trim());\n i++;\n }\n if (Object.keys(map).length > 0) out.metadata = map;\n continue;\n }\n\n if (rest === '|' || rest === '>') {\n // Block scalar \u2014 collect following indented (or blank) lines.\n const collected: string[] = [];\n i++;\n while (i < lines.length) {\n const sub = lines[i] ?? '';\n if (sub === '' || sub.startsWith(' ') || sub.startsWith('\\t')) {\n collected.push(sub.replace(/^\\s+/, ''));\n i++;\n } else break;\n }\n (out as Record<string, unknown>)[normalizeKey(key)] = collected.join('\\n').trim();\n continue;\n }\n\n if (key === 'allowed-tools' || key === 'allowedTools') {\n // Spec: space-separated; tolerate comma-separated (common in real skills).\n out.allowedTools = rest.split(/[\\s,]+/).filter(Boolean);\n i++;\n continue;\n }\n\n if (SCALAR_KEYS.has(key)) {\n (out as Record<string, unknown>)[key] = unquote(rest);\n i++;\n continue;\n }\n\n // Unknown key \u2014 ignore.\n i++;\n }\n return out;\n}\n\n/** `allowed-tools` (hyphen) \u2192 `allowedTools` (camel); other keys pass through. */\nfunction normalizeKey(key: string): string {\n return key === 'allowed-tools' ? 'allowedTools' : key;\n}\n\n/** Strip surrounding single/double YAML quotes from a scalar value. */\nfunction unquote(s: string): string {\n if (\n s.length >= 2 &&\n ((s.startsWith('\"') && s.endsWith('\"')) || (s.startsWith(\"'\") && s.endsWith(\"'\")))\n ) {\n return s.slice(1, -1);\n }\n return s;\n}\n\n/** True when `name` matches the agentskills.io name format (chars + length only). */\nexport function isValidSkillNameFormat(name: string): boolean {\n return name.length >= 1 && name.length <= 64 && /^[a-z0-9]+(-[a-z0-9]+)*$/.test(name);\n}\n\n/**\n * Validate a skill `name` against the agentskills.io spec:\n * 1-64 chars; lowercase letters, digits, and single hyphens only; no\n * leading/trailing/consecutive hyphens. Pass the parent directory name to also\n * enforce the \"name must match the parent directory\" rule.\n *\n * Returns a list of human-readable violations (empty = valid).\n */\nexport function validateSkillName(name: string, parentDirName?: string): string[] {\n const errors: string[] = [];\n if (!name || name.trim().length === 0) {\n errors.push('name is empty');\n return errors;\n }\n if (name.length > 64) errors.push(`name is ${name.length} characters (max 64)`);\n if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(name)) {\n errors.push(\n 'name must be lowercase letters, digits, and single hyphens only ' +\n '(no leading/trailing/consecutive hyphens)',\n );\n }\n if (parentDirName !== undefined && name !== parentDirName) {\n errors.push(`name \"${name}\" must match its parent directory \"${parentDirName}\"`);\n }\n return errors;\n}\n", "import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { ERROR_CODES, FsError, WrongStackError } from '../types/errors.js';\nimport type { SkillLoader } from '../types/skill.js';\nimport { toErrorMessage } from '../utils/error.js';\nimport { expectDefined } from '../utils/expect-defined.js';\nimport { isValidSkillNameFormat, parseSkillFrontmatter } from './frontmatter.js';\nimport { downloadGitHubTarball, parseSkillRef } from './github-fetcher.js';\nimport { SKILL_LIMITS } from './limits.js';\nimport { type InstalledSkillEntry, SkillManifestStore } from './manifest-store.js';\nimport { githubDirectAdapter } from './registry/github-direct-adapter.js';\nimport type {\n RegistrySearchOptions,\n RegistrySearchResult,\n RegistrySkillSummary,\n SkillRegistryAdapter,\n} from './registry/registry-adapter.js';\nexport interface SkillInstallerOptions {\n /** Path to the profile manifest file (profiles/<name>/installed-skills.json) */\n manifestPath: string;\n /** Path to project-level skills dir (<project>/.wrongstack/skills/) */\n projectSkillsDir: string;\n /** Path to profile skills dir (~/.wrongstack/profiles/<name>/skills/) */\n globalSkillsDir: string;\n /** Current project hash (for manifest tracking) */\n projectHash: string;\n /** Skill loader \u2014 cache will be invalidated after mutations */\n skillLoader?: SkillLoader | undefined;\n /** Logger for status messages */\n log?: ((msg: string) => void) | undefined;\n /**\n * Skill registries used to resolve `<adapterId>:<registryId>` refs and to\n * serve `/skill-search`. Defaults to `[githubDirectAdapter]` (the original\n * direct `user/repo` install path). Add a skills.sh adapter to enable\n * searching the marketplace and installing registry hits by id.\n */\n registryAdapters?: SkillRegistryAdapter[] | undefined;\n}\n\nexport interface InstallResult {\n name: string;\n path: string;\n scope: 'project' | 'user';\n source: string;\n ref: string;\n skillCount: number;\n}\n\nexport interface UpdateResult {\n updated: Array<{ name: string; oldRef: string; newRef: string }>;\n unchanged: string[];\n errors: Array<{ name: string; error: string }>;\n}\n\nconst MAX_SKILL_FILE_SIZE = SKILL_LIMITS.MAX_SKILL_FILE_SIZE;\n\nexport class SkillInstaller {\n private readonly opts: SkillInstallerOptions;\n private readonly manifest: SkillManifestStore;\n private readonly adapters: SkillRegistryAdapter[];\n\n constructor(opts: SkillInstallerOptions) {\n this.opts = opts;\n this.manifest = new SkillManifestStore(opts.manifestPath);\n this.adapters = opts.registryAdapters?.length ? opts.registryAdapters : [githubDirectAdapter];\n }\n\n /**\n * Install skills from a skill reference.\n *\n * Accepts two ref formats:\n * - `user/repo[@ref]` \u2014 direct GitHub install (original path)\n * - `<adapterId>:<registryId>` \u2014 registry-resolved (e.g.\n * `skills.sh:owner/repo@v1`); the\n * adapter resolves it to a `user/repo`\n * ref and the install proceeds as above.\n *\n * Supports both single-skill repos (SKILL.md at root) and multi-skill repos\n * (skills/ subdirectory). The manifest records the GitHub source as\n * `github:owner/repo` (so `/skill-update` keeps working) plus the originating\n * registry in `registryFrom` when the install came through a registry.\n */\n async install(\n refInput: string,\n opts?: { global?: boolean | undefined },\n ): Promise<InstallResult[]> {\n const resolved = this.resolveRef(refInput);\n const parsed = parseSkillRef(resolved.installRef);\n const scope: 'project' | 'user' = opts?.global ? 'user' : 'project';\n const targetDir = scope === 'project' ? this.opts.projectSkillsDir : this.opts.globalSkillsDir;\n const source = `github:${parsed.owner}/${parsed.repo}`;\n\n this.opts.log?.(\n resolved.fromRegistry\n ? `Resolving ${refInput} \u2192 ${resolved.installRef} (${resolved.adapterId}), downloading...`\n : `Downloading ${parsed.owner}/${parsed.repo}@${parsed.ref}...`,\n );\n\n const { tempDir } = await downloadGitHubTarball(parsed);\n\n try {\n // Detect skill structure\n const skills = await this.detectSkills(tempDir);\n\n if (skills.length === 0) {\n throw new WrongStackError({\n message:\n 'No skills found in repository. Expected SKILL.md at root or skills/ subdirectory.',\n code: ERROR_CODES.VALIDATION_ERROR,\n subsystem: 'general',\n context: { owner: parsed.owner, repo: parsed.repo, ref: parsed.ref },\n });\n }\n\n const results: InstallResult[] = [];\n\n for (const skill of skills) {\n // Check for overwrite\n const existing = await this.manifest.findByName(skill.name);\n const existingInScope = existing.find((e) => e.scope === scope);\n if (existingInScope) {\n this.opts.log?.(`Overwriting existing skill \"${skill.name}\" (${scope})...`);\n await this.removeSkillFiles(skill.name, scope);\n }\n\n // Copy skill files\n const destDir = path.join(targetDir, skill.name);\n await fs.mkdir(destDir, { recursive: true });\n const copiedFiles: string[] = [];\n\n for (const file of skill.files) {\n const srcPath = path.join(skill.baseDir, file);\n const destPath = path.join(destDir, file);\n\n // Path traversal check\n const resolved = path.resolve(destPath);\n if (!resolved.startsWith(path.resolve(destDir))) {\n throw new FsError({\n message: `Path traversal detected in skill file: ${file}`,\n code: ERROR_CODES.FS_DELETE_FAILED,\n path: destPath,\n context: { reason: 'path_traversal', skillName: skill.name },\n });\n }\n\n // Size check\n const stat = await fs.stat(srcPath);\n if (stat.size > MAX_SKILL_FILE_SIZE) {\n throw new FsError({\n message:\n `Skill file \"${file}\" is too large (${(stat.size / 1024).toFixed(1)}KB). ` +\n `Max: ${MAX_SKILL_FILE_SIZE / 1024}KB`,\n code: ERROR_CODES.FS_WRITE_FAILED,\n path: srcPath,\n context: { skillName: skill.name, fileSize: stat.size, maxSize: MAX_SKILL_FILE_SIZE },\n });\n }\n\n await fs.mkdir(path.dirname(destPath), { recursive: true });\n await fs.copyFile(srcPath, destPath);\n copiedFiles.push(file);\n }\n\n // Write manifest entry\n const entry: InstalledSkillEntry = {\n name: skill.name,\n source,\n ref: parsed.ref,\n scope,\n projectHash: scope === 'project' ? this.opts.projectHash : undefined,\n installedAt: new Date().toISOString(),\n files: copiedFiles,\n // When the install came through a registry (e.g. skills.sh), record\n // which adapter + registry id resolved to this GitHub repo, so the\n // source is traceable. `source` stays `github:owner/repo` for\n // backward compat with `/skill-update`.\n ...(resolved.fromRegistry\n ? { registryFrom: { adapterId: resolved.adapterId, registryId: resolved.registryId } }\n : {}),\n };\n await this.manifest.addEntry(entry);\n\n results.push({\n name: skill.name,\n path: destDir,\n scope,\n source,\n ref: parsed.ref,\n skillCount: 1,\n });\n }\n\n this.invalidateLoaderCache();\n return results;\n } finally {\n // Clean up temp directory\n await fs.rm(tempDir, { recursive: true, force: true }).catch(() => {});\n }\n }\n\n /**\n * Import skills from a local directory (e.g. `.claude/skills`) into the\n * project or user skills dir, optionally as symlinks. Used by `/skill-import`\n * to take ownership of foreign skills so they can be edited/committed.\n * Each direct subdirectory containing a valid `SKILL.md` is copied verbatim.\n */\n async importFromDir(\n srcDir: string,\n opts?: { global?: boolean | undefined; link?: boolean | undefined },\n ): Promise<InstallResult[]> {\n const scope: 'project' | 'user' = opts?.global ? 'user' : 'project';\n const targetDir = scope === 'project' ? this.opts.projectSkillsDir : this.opts.globalSkillsDir;\n let entries: import('node:fs').Dirent[];\n try {\n entries = await fs.readdir(srcDir, { withFileTypes: true });\n } catch {\n throw new WrongStackError({\n message: `Source directory not found or not readable: ${srcDir}`,\n code: ERROR_CODES.VALIDATION_ERROR,\n subsystem: 'general',\n context: { srcDir },\n });\n }\n\n const results: InstallResult[] = [];\n for (const e of entries) {\n if (!(await entryIsDirectory(srcDir, e))) continue;\n const skillMdPath = path.join(srcDir, e.name, 'SKILL.md');\n let content: string;\n try {\n content = await fs.readFile(skillMdPath, 'utf8');\n } catch {\n continue; // subdirectory without a SKILL.md \u2014 not a skill\n }\n const fm = parseSkillFrontmatter(content);\n if (!fm.name || !fm.description || !isValidSkillNameFormat(fm.name)) continue;\n\n const existing = await this.manifest.findByName(fm.name);\n if (existing.find((x) => x.scope === scope)) {\n await this.removeSkillFiles(fm.name, scope);\n }\n\n const destDir = path.join(targetDir, fm.name);\n await fs.mkdir(destDir, { recursive: true });\n const srcSkillDir = path.join(srcDir, e.name);\n const files = await collectFiles(srcSkillDir, srcSkillDir);\n const copiedFiles: string[] = [];\n for (const file of files) {\n const srcPath = path.join(srcSkillDir, file);\n const destPath = path.join(destDir, file);\n const resolved = path.resolve(destPath);\n if (!resolved.startsWith(path.resolve(destDir))) {\n throw new FsError({\n message: `Path traversal detected in skill file: ${file}`,\n code: ERROR_CODES.FS_DELETE_FAILED,\n path: destPath,\n context: { reason: 'path_traversal', skillName: fm.name },\n });\n }\n await fs.mkdir(path.dirname(destPath), { recursive: true });\n if (opts?.link) {\n try {\n await fs.symlink(srcPath, destPath);\n } catch (err) {\n // Symlink unavailable (e.g. Windows without Developer Mode) \u2014 copy.\n await fs.copyFile(srcPath, destPath);\n this.opts.log?.(`symlink failed for ${file} (${toErrorMessage(err)}); copied instead`);\n }\n } else {\n await fs.copyFile(srcPath, destPath);\n }\n copiedFiles.push(file);\n }\n\n await this.manifest.addEntry({\n name: fm.name,\n source: `import:${srcDir}`,\n ref: '-',\n scope,\n projectHash: scope === 'project' ? this.opts.projectHash : undefined,\n installedAt: new Date().toISOString(),\n files: copiedFiles,\n });\n results.push({\n name: fm.name,\n path: destDir,\n scope,\n source: `import:${srcDir}`,\n ref: '-',\n skillCount: 1,\n });\n }\n\n this.invalidateLoaderCache();\n return results;\n }\n\n /**\n * Update installed skills.\n * - No args: update all\n * - Name: update that specific skill\n * - Name + newRef: update to a different ref\n */\n async update(\n nameOrRef?: string | undefined,\n _opts?: { global?: boolean | undefined } | undefined,\n ): Promise<UpdateResult> {\n const result: UpdateResult = { updated: [], unchanged: [], errors: [] };\n const allEntries = await this.manifest.listAll();\n\n let targets: InstalledSkillEntry[];\n if (nameOrRef) {\n // Check if it's a name or a ref (user/repo@ref)\n const byName = allEntries.filter((e) => e.name === nameOrRef);\n if (byName.length > 0) {\n targets = byName;\n } else {\n // Treat as a new ref \u2014 find matching source\n try {\n const parsed = parseSkillRef(nameOrRef);\n const source = `github:${parsed.owner}/${parsed.repo}`;\n targets = allEntries.filter((e) => e.source === source);\n if (targets.length === 0) {\n result.errors.push({\n name: nameOrRef,\n error: `No installed skills found matching \"${nameOrRef}\"`,\n });\n return result;\n }\n } catch {\n result.errors.push({\n name: nameOrRef,\n error: `Invalid reference: ${nameOrRef}`,\n });\n return result;\n }\n }\n } else {\n targets = allEntries;\n }\n\n // Group by source to avoid downloading the same repo multiple times\n const bySource = new Map<string, InstalledSkillEntry[]>();\n for (const entry of targets) {\n const key = `${entry.source}@${entry.ref}`;\n if (!bySource.has(key)) bySource.set(key, []);\n bySource.get(key)?.push(entry);\n }\n\n for (const [, entries] of bySource) {\n const first = expectDefined(entries[0]);\n const scope = first.scope;\n const isGlobal = scope === 'user';\n\n try {\n // Parse the original source to get the ref\n const sourceRepo = first.source.replace('github:', '');\n let refToInstall = first.ref;\n\n // If nameOrRef looks like a new ref, use it\n if (nameOrRef && !allEntries.find((e) => e.name === nameOrRef)) {\n try {\n const parsed = parseSkillRef(nameOrRef);\n refToInstall = parsed.ref;\n } catch {\n // keep original ref\n }\n }\n\n this.opts.log?.(`Updating ${first.source}@${refToInstall}...`);\n const results = await this.install(`${sourceRepo}@${refToInstall}`, { global: isGlobal });\n\n for (const r of results) {\n result.updated.push({\n name: r.name,\n oldRef: first.ref,\n newRef: refToInstall,\n });\n }\n } catch (err) {\n const msg = toErrorMessage(err);\n for (const entry of entries) {\n result.errors.push({ name: entry.name, error: msg });\n }\n }\n }\n\n return result;\n }\n\n /**\n * Uninstall a skill by name.\n */\n async uninstall(name: string, opts?: { global?: boolean | undefined }): Promise<void> {\n const scope: 'project' | 'user' = opts?.global ? 'user' : 'project';\n const entries = await this.manifest.findByName(name);\n const entry = entries.find((e) => e.scope === scope);\n\n if (!entry) {\n throw new WrongStackError({\n message: `Skill \"${name}\" is not installed${scope === 'user' ? ' (global)' : ''}.`,\n code: ERROR_CODES.VALIDATION_ERROR,\n subsystem: 'general',\n context: { skillName: name, scope },\n });\n }\n\n // Remove files\n await this.removeSkillFiles(name, scope);\n\n // Remove from manifest\n await this.manifest.removeEntry(name, scope);\n this.invalidateLoaderCache();\n }\n\n /**\n * List all installed skills from the manifest.\n */\n async listInstalled(): Promise<InstalledSkillEntry[]> {\n return this.manifest.listAll();\n }\n\n /**\n * Search across all configured registry adapters. Results from each adapter\n * are merged (deduplicated by `installRef`, adapters earlier in the list win\n * conflicts). Adapters that don't support search (e.g. github-direct)\n * contribute nothing.\n */\n async search(query: string, opts?: RegistrySearchOptions): Promise<RegistrySearchResult[]> {\n const settled = await Promise.allSettled(this.adapters.map((a) => a.search(query, opts)));\n const perAdapter: RegistrySearchResult[] = [];\n const errors: string[] = [];\n settled.forEach((s, i) => {\n if (s.status === 'fulfilled') perAdapter.push(s.value);\n else {\n const id = this.adapters[i]?.id ?? '?';\n errors.push(`${id}: ${toErrorMessage(s.reason)}`);\n }\n });\n // Surface adapter errors via the log so a single broken registry doesn't\n // silently hide results \u2014 but don't throw, since other adapters may have\n // returned useful results.\n if (errors.length > 0) {\n this.opts.log?.(`Some registries failed during search: ${errors.join('; ')}`);\n }\n return dedupeSearchResults(perAdapter);\n }\n\n // \u2500\u2500 Private helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n /**\n * Detect skills in an extracted repository.\n * Returns an array of detected skills with their files.\n */\n private async detectSkills(\n baseDir: string,\n ): Promise<Array<{ name: string; baseDir: string; files: string[] }>> {\n const results: Array<{ name: string; baseDir: string; files: string[] }> = [];\n\n // Check for SKILL.md at root (single-skill repo)\n const rootSkillMd = path.join(baseDir, 'SKILL.md');\n try {\n await fs.access(rootSkillMd);\n const content = await fs.readFile(rootSkillMd, 'utf8');\n const fm = parseSkillFrontmatter(content);\n if (fm.name && fm.description && isValidSkillNameFormat(fm.name)) {\n results.push({\n name: fm.name,\n baseDir,\n files: ['SKILL.md'],\n });\n return results; // Single-skill repo \u2014 don't look for skills/\n }\n } catch {\n // No root SKILL.md\n }\n\n // Check for skills/ subdirectory (multi-skill repo)\n const skillsDir = path.join(baseDir, 'skills');\n try {\n const entries = await fs.readdir(skillsDir, { withFileTypes: true });\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n const skillFile = path.join(skillsDir, entry.name, 'SKILL.md');\n try {\n const content = await fs.readFile(skillFile, 'utf8');\n const fm = parseSkillFrontmatter(content);\n if (fm.name && fm.description && isValidSkillNameFormat(fm.name)) {\n // Collect all files in the skill directory\n const skillDir = path.join(skillsDir, entry.name);\n const files = await collectFiles(skillDir, skillDir);\n results.push({\n name: fm.name,\n baseDir: skillDir,\n files,\n });\n }\n } catch {\n // Skip malformed skills\n }\n }\n } catch {\n // No skills/ directory\n }\n\n return results;\n }\n\n /**\n * Remove all files for an installed skill.\n */\n private async removeSkillFiles(name: string, scope: 'project' | 'user'): Promise<void> {\n const targetDir = scope === 'project' ? this.opts.projectSkillsDir : this.opts.globalSkillsDir;\n const skillDir = path.join(targetDir, name);\n await fs.rm(skillDir, { recursive: true, force: true });\n }\n\n /**\n * Invalidate the skill loader's cache so newly installed skills appear.\n */\n private invalidateLoaderCache(): void {\n // The SkillLoader interface has a cache internally.\n // We access it via the 'any' cast to call invalidateCache if available.\n const loader = this.opts.skillLoader as never as { invalidateCache?: () => void };\n if (loader && typeof loader.invalidateCache === 'function') {\n loader.invalidateCache();\n }\n }\n\n /**\n * Resolve an install ref, dispatching registry-prefixed refs to the matching\n * adapter. Returns the concrete `user/repo[@ref]` install ref plus provenance\n * (which adapter resolved it, if any).\n */\n private resolveRef(refInput: string): {\n installRef: string;\n fromRegistry: boolean;\n adapterId: string;\n registryId: string;\n } {\n const trimmed = refInput.trim();\n const colonIdx = trimmed.indexOf(':');\n // A colon prefix matches `<adapterId>:<registryId>`. We require the segment\n // before the colon to be a known adapter id so plain `user/repo` refs (and\n // Windows-style `C:\\...` paths that should never reach here) aren't\n // misread as registry refs.\n if (colonIdx > 0) {\n const maybeAdapterId = trimmed.slice(0, colonIdx);\n const adapter = this.adapters.find((a) => a.id === maybeAdapterId);\n if (adapter) {\n const registryId = trimmed.slice(colonIdx + 1);\n const installRef = adapter.resolveInstallRef(registryId);\n return { installRef, fromRegistry: true, adapterId: adapter.id, registryId };\n }\n }\n return { installRef: trimmed, fromRegistry: false, adapterId: '', registryId: '' };\n }\n}\n\n// \u2500\u2500 Utilities \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * True if `entry` is a directory, following symlinks (Claude Code/agents\n * symlink skill dirs \u2014 see DefaultSkillLoader.entryIsDirectory).\n */\nasync function entryIsDirectory(dir: string, entry: import('node:fs').Dirent): Promise<boolean> {\n if (entry.isDirectory()) return true;\n if (entry.isSymbolicLink()) {\n try {\n return (await fs.stat(path.join(dir, entry.name))).isDirectory();\n } catch {\n return false; // broken symlink\n }\n }\n return false;\n}\n\n/**\n * Recursively collect all files in a directory (relative paths).\n */\nasync function collectFiles(dir: string, baseDir: string): Promise<string[]> {\n const results: string[] = [];\n const entries = await fs.readdir(dir, { withFileTypes: true });\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name);\n const relPath = path.relative(baseDir, fullPath);\n if (entry.isDirectory()) {\n // Skip hidden dirs and node_modules\n if (entry.name.startsWith('.') || entry.name === 'node_modules') continue;\n results.push(...(await collectFiles(fullPath, baseDir)));\n } else {\n results.push(relPath);\n }\n }\n return results;\n}\n\n/**\n * Merge per-adapter search results, deduplicating by `installRef`.\n *\n * Two adapters may index the same GitHub repo (e.g. skills.sh and a future\n * internal hub both list `obra/superpowers`). When they do, the first adapter\n * in the configured order wins \u2014 its metadata (security score, install count)\n * is the one shown, and the dedup key is the concrete `user/repo[@ref]` so a\n * ref difference still surfaces both. Per-adapter result boundaries are\n * preserved (the caller renders them grouped by adapter).\n */\nfunction dedupeSearchResults(perAdapter: RegistrySearchResult[]): RegistrySearchResult[] {\n const seen = new Set<string>();\n const out: RegistrySearchResult[] = [];\n for (const block of perAdapter) {\n const kept: RegistrySkillSummary[] = [];\n for (const r of block.results) {\n const key = r.installRef;\n if (seen.has(key)) continue;\n seen.add(key);\n kept.push(r);\n }\n if (kept.length > 0 || block.results.length > 0) {\n out.push({ ...block, results: kept });\n }\n }\n return out;\n}\n", "import * as fs from 'node:fs/promises';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { Readable } from 'node:stream';\nimport { pipeline } from 'node:stream/promises';\nimport { createGunzip } from 'node:zlib';\nimport { ERROR_CODES, FetchError, WrongStackError } from '../types/errors.js';\nimport { expectDefined } from '../utils/expect-defined.js';\nimport { SKILL_LIMITS } from './limits.js';\n\nexport interface ParsedRef {\n owner: string;\n repo: string;\n ref: string;\n}\n\n/**\n * Parse a skill reference string.\n * Formats: `user/repo` (default ref: main), `user/repo@ref`\n */\nexport function parseSkillRef(input: string): ParsedRef {\n const trimmed = input\n .trim()\n .replace(/^https?:\\/\\/github\\.com\\//, '')\n .replace(/\\.git$/, '');\n const atIdx = trimmed.indexOf('@');\n let refPath: string;\n let ref: string;\n if (atIdx > 0) {\n refPath = trimmed.slice(0, atIdx);\n ref = trimmed.slice(atIdx + 1);\n } else {\n refPath = trimmed;\n ref = 'main';\n }\n const parts = refPath.split('/').filter(Boolean);\n if (parts.length < 2) {\n throw new WrongStackError({\n message: `Invalid skill reference \"${input}\". Expected format: user/repo or user/repo@ref`,\n code: ERROR_CODES.UNKNOWN,\n subsystem: 'general',\n context: { input },\n });\n }\n return { owner: expectDefined(parts[0]), repo: expectDefined(parts[1]), ref };\n}\n\nexport interface DownloadResult {\n /** Temp directory containing the extracted repo. Caller must clean up. */\n tempDir: string;\n}\n\n/**\n * Resolve a GitHub auth token, if one is configured.\n *\n * Order: `WRONGSTACK_GITHUB_TOKEN` (WrongStack-specific override) \u2192 `GITHUB_TOKEN`\n * \u2192 `GH_TOKEN` (the gh CLI convention). Returns `undefined` when none are set,\n * which means only public repos can be fetched.\n *\n * Exposed for testing and for the installer's user-facing messaging (so it can\n * say \"set GITHUB_TOKEN to install private repos\" rather than just \"403\").\n */\nexport function resolveGitHubToken(env: NodeJS.ProcessEnv = process.env): string | undefined {\n const raw = env['WRONGSTACK_GITHUB_TOKEN'] ?? env['GITHUB_TOKEN'] ?? env['GH_TOKEN'];\n if (!raw) return undefined;\n const trimmed = raw.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n}\n\n/**\n * Download and extract a GitHub repository tarball.\n *\n * Auth: reads `WRONGSTACK_GITHUB_TOKEN` / `GITHUB_TOKEN` / `GH_TOKEN` (in that\n * order). Without a token only public repos work; with one, private repos the\n * token can read also work, and the API rate limit is the authenticated\n * (much higher) limit instead of the anonymous 60/hour.\n *\n * Returns the path to a temp directory with the extracted contents. The caller\n * must remove it (the installer does this in a `finally`).\n */\nexport async function downloadGitHubTarball(parsed: ParsedRef): Promise<DownloadResult> {\n const url = `https://api.github.com/repos/${parsed.owner}/${parsed.repo}/tarball/${parsed.ref}`;\n const token = resolveGitHubToken();\n\n const headers: Record<string, string> = {\n Accept: 'application/vnd.github+json',\n 'User-Agent': 'wrongstack-skill-installer',\n };\n if (token) headers['Authorization'] = `Bearer ${token}`;\n\n let response: Response;\n try {\n response = await fetch(url, {\n signal: AbortSignal.timeout(30_000),\n headers,\n redirect: 'follow',\n });\n } catch (err) {\n // Network error / timeout \u2014 surface as a recoverable FetchError so callers\n // can retry if they want. Don't leak the raw error (may contain the URL).\n throw new FetchError({\n message: `Network error fetching ${parsed.owner}/${parsed.repo}: ${\n err instanceof Error ? err.message : String(err)\n }`,\n status: 0,\n context: { owner: parsed.owner, repo: parsed.repo, ref: parsed.ref, op: 'tarball' },\n cause: err,\n });\n }\n\n if (!response.ok) {\n if (response.status === 404) {\n throw new WrongStackError({\n message:\n `Repository not found: ${parsed.owner}/${parsed.repo}` +\n (parsed.ref !== 'main' ? ` (ref: ${parsed.ref})` : '') +\n (token ? '' : '. If this is a private repo, set GITHUB_TOKEN (or GH_TOKEN).'),\n code: ERROR_CODES.UNKNOWN,\n subsystem: 'general',\n context: { owner: parsed.owner, repo: parsed.repo, ref: parsed.ref, status: 404 },\n });\n }\n if (response.status === 403) {\n // Distinguish rate-limit (anonymous 60/hour) from a real access denial.\n const remaining = response.headers.get('x-ratelimit-remaining');\n const isRateLimited = remaining === '0';\n throw new WrongStackError({\n message: isRateLimited\n ? `GitHub API rate limit exceeded. Set GITHUB_TOKEN (or GH_TOKEN) to use the higher authenticated limit.`\n : `Access denied: ${parsed.owner}/${parsed.repo}. The repository may be private (set GITHUB_TOKEN to install private repos) or rate-limited.`,\n code: ERROR_CODES.UNKNOWN,\n subsystem: 'general',\n context: {\n owner: parsed.owner,\n repo: parsed.repo,\n status: 403,\n rateLimited: isRateLimited,\n hasToken: Boolean(token),\n },\n });\n }\n throw new WrongStackError({\n message: `GitHub API error (${response.status}): ${response.statusText}`,\n code: ERROR_CODES.UNKNOWN,\n subsystem: 'general',\n context: { owner: parsed.owner, repo: parsed.repo, status: response.status },\n });\n }\n\n const contentLength = response.headers.get('content-length');\n if (contentLength && Number.parseInt(contentLength, 10) > SKILL_LIMITS.MAX_TARBALL_SIZE) {\n throw new WrongStackError({\n message:\n `Tarball too large (${(Number.parseInt(contentLength, 10) / 1024 / 1024).toFixed(1)}MB). ` +\n `Max: ${SKILL_LIMITS.MAX_TARBALL_SIZE / 1024 / 1024}MB`,\n code: ERROR_CODES.UNKNOWN,\n subsystem: 'general',\n context: {\n owner: parsed.owner,\n repo: parsed.repo,\n contentLengthBytes: Number.parseInt(contentLength, 10),\n maxBytes: SKILL_LIMITS.MAX_TARBALL_SIZE,\n },\n });\n }\n\n const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'wskill-'));\n\n try {\n if (!response.body) {\n throw new WrongStackError({\n message: 'Empty response body from GitHub API',\n code: ERROR_CODES.UNKNOWN,\n subsystem: 'general',\n context: { owner: parsed.owner, repo: parsed.repo },\n });\n }\n\n // Gunzip the response body, then extract the tar stream\n const nodeStream = Readable.fromWeb(response.body as import('node:stream/web').ReadableStream);\n const gunzip = createGunzip();\n\n // Collect the uncompressed tar data into a buffer, then extract\n const chunks: Buffer[] = [];\n await pipeline(nodeStream, gunzip, async (source) => {\n for await (const chunk of source) {\n chunks.push(Buffer.from(chunk));\n }\n });\n const tarBuf = Buffer.concat(chunks);\n\n // Extract tar archive (POSIX ustar format)\n await extractTar(tarBuf, tempDir);\n\n return { tempDir };\n } catch (err) {\n await fs.rm(tempDir, { recursive: true, force: true }).catch(() => {});\n throw err;\n }\n}\n\n/**\n * Minimal POSIX tar extractor. Handles the ustar format produced by GitHub.\n * Only extracts regular files and directories \u2014 symlinks and special entries\n * are skipped for security.\n */\nasync function extractTar(buf: Buffer, destDir: string): Promise<void> {\n let offset = 0;\n\n while (offset + 512 <= buf.length) {\n // Check for end-of-archive (two consecutive zero blocks)\n const header = buf.subarray(offset, offset + 512);\n if (header.every((b) => b === 0)) break;\n\n // Parse ustar header\n const name = readTarString(buf, offset, 100); // name field\n const prefix = readTarString(buf, offset + 345, 155); // ustar prefix\n const size = Number.parseInt(readTarString(buf, offset + 124, 12).trim(), 8) || 0;\n const typeflag = buf[offset + 156] ?? 0;\n\n // Full path: prefix/name (ustar) or just name\n const fullPath = prefix ? `${prefix}/${name}` : name;\n // Strip the top-level directory (GitHub tarballs have owner-repo-sha/)\n const relPath = stripTopDir(fullPath);\n\n if (relPath && relPath !== '.' && relPath !== '..') {\n const destPath = path.join(destDir, relPath);\n\n // Zip-slip guard: reject any entry whose resolved path escapes destDir\n // (e.g. a crafted entry name like `x/../../../etc/cron.d/evil`). GitHub\n // tarballs are built from git trees and so cannot carry `..` components,\n // but this extractor is generic \u2014 never trust archive entry names.\n const resolvedDest = path.resolve(destPath);\n const resolvedRoot = path.resolve(destDir);\n if (resolvedDest !== resolvedRoot && !resolvedDest.startsWith(resolvedRoot + path.sep)) {\n // Skip the entry entirely; advance past its data below.\n offset += 512 + Math.ceil(size / 512) * 512;\n continue;\n }\n\n // typeflag: '0' or '\\0' = regular file, '5' = directory\n if (typeflag === 0x35 || typeflag === 0) {\n // Directory\n if (relPath.endsWith('/') || typeflag === 0x35) {\n await fs.mkdir(destPath, { recursive: true });\n }\n }\n\n if ((typeflag === 0x30 || typeflag === 0 || typeflag === 0x00) && size > 0) {\n // Regular file\n const dir = path.dirname(destPath);\n await fs.mkdir(dir, { recursive: true });\n const dataStart = offset + 512;\n const dataEnd = dataStart + size;\n if (dataEnd > buf.length) break; // truncated archive\n await fs.writeFile(destPath, buf.subarray(dataStart, dataEnd));\n }\n }\n\n // Advance: 512-byte header + data padded to 512-byte boundary\n offset += 512 + Math.ceil(size / 512) * 512;\n }\n}\n\nfunction readTarString(buf: Buffer, start: number, maxLen: number): string {\n let end = start;\n while (end < start + maxLen && end < buf.length && buf[end] !== 0) {\n end++;\n }\n return buf.subarray(start, end).toString('utf8');\n}\n\n/**\n * Strip the top-level directory from a tar path.\n * GitHub tarballs have a single root dir like `owner-repo-sha/`.\n */\nfunction stripTopDir(p: string): string {\n const idx = p.indexOf('/');\n if (idx === -1) return ''; // top-level file, skip\n return p.slice(idx + 1);\n}\n", "import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { atomicWrite } from '../utils/atomic-write.js';\n\nexport interface InstalledSkillEntry {\n name: string;\n /** Source identifier, e.g. \"github:user/repo\" */\n source: string;\n /** Git ref that was installed (branch, tag, commit) */\n ref: string;\n /** Installation scope */\n scope: 'project' | 'user';\n /** Project hash \u2014 only set when scope=project */\n projectHash?: string | undefined;\n /** ISO 8601 timestamp */\n installedAt: string;\n /** List of files that were installed (relative to skill dir) */\n files: string[];\n /**\n * When the install was resolved through a registry (e.g. `skills.sh`), the\n * adapter id + registry id that mapped to the GitHub `source`. Absent for\n * direct `user/repo` installs.\n */\n registryFrom?: { adapterId: string; registryId: string } | undefined;\n}\n\nexport interface ManifestData {\n skills: InstalledSkillEntry[];\n}\n\nexport class SkillManifestStore {\n private readonly manifestPath: string;\n private cache?: ManifestData | undefined;\n\n constructor(manifestPath: string) {\n this.manifestPath = manifestPath;\n }\n\n async read(): Promise<ManifestData> {\n if (this.cache) return this.cache;\n try {\n const raw = await fs.readFile(this.manifestPath, 'utf8');\n const data = JSON.parse(raw) as ManifestData;\n if (!Array.isArray(data.skills)) {\n this.cache = { skills: [] };\n } else {\n this.cache = data;\n }\n } catch {\n this.cache = { skills: [] };\n }\n return this.cache;\n }\n\n async write(data: ManifestData): Promise<void> {\n const dir = path.dirname(this.manifestPath);\n await fs.mkdir(dir, { recursive: true });\n await atomicWrite(this.manifestPath, JSON.stringify(data, null, 2) + '\\n');\n this.cache = data;\n }\n\n async addEntry(entry: InstalledSkillEntry): Promise<void> {\n const data = await this.read();\n // Remove existing entry with the same name + scope\n data.skills = data.skills.filter((s) => !(s.name === entry.name && s.scope === entry.scope));\n data.skills.push(entry);\n await this.write(data);\n }\n\n async removeEntry(name: string, scope: 'project' | 'user'): Promise<boolean> {\n const data = await this.read();\n const before = data.skills.length;\n data.skills = data.skills.filter((s) => !(s.name === name && s.scope === scope));\n if (data.skills.length === before) return false;\n await this.write(data);\n return true;\n }\n\n async findByName(name: string): Promise<InstalledSkillEntry[]> {\n const data = await this.read();\n return data.skills.filter((s) => s.name === name);\n }\n\n async findBySource(source: string): Promise<InstalledSkillEntry[]> {\n const data = await this.read();\n return data.skills.filter((s) => s.source === source);\n }\n\n async listAll(): Promise<InstalledSkillEntry[]> {\n const data = await this.read();\n return data.skills;\n }\n\n /** Invalidate the in-memory cache (e.g. after external file changes). */\n invalidateCache(): void {\n this.cache = undefined;\n }\n}\n", "import * as path from 'node:path';\nimport { expectDefined } from '../utils/expect-defined.js';\nimport { toErrorMessage } from '../utils/error.js';\nimport type { Plugin } from '../types/plugin.js';\nimport type { SlashCommand, Context } from '../index.js';\nimport type { SyncCategory, SyncConfig } from '../types/config.js';\nimport { CloudSync, ALL_SYNC_CATEGORIES } from '../storage/cloud-sync.js';\nimport type { WstackPaths } from '../utils/wstack-paths.js';\nimport type { ConfigStore } from '../types/config.js';\nimport { atomicWrite } from '../utils/atomic-write.js';\ninterface SyncPluginOptions {\n paths?: WstackPaths | undefined;\n configStore?: ConfigStore | undefined;\n /** Secret vault for encrypting the GitHub token before persisting to disk. */\n vault?: { encrypt(plaintext: string): string; decrypt?(value: string): string };\n}\n\n/**\n * SyncPlugin \u2014 GitHub-backed cloud sync for WrongStack user data.\n *\n * Registers `/sync` slash command. Users can push/pull their prompts,\n * skills, settings, memory, and history to a private GitHub repo.\n * Active by default; configure once with `/sync enable owner/repo TOKEN`.\n */\nexport function createSyncPlugin(opts?: SyncPluginOptions): Plugin {\n let cloud: CloudSync | null = null;\n let configStore: ConfigStore | undefined;\n let vault: { encrypt(plaintext: string): string; decrypt?(value: string): string } | undefined;\n\n return {\n name: 'wstack-sync',\n version: '1.0.0',\n description: 'GitHub cloud sync for prompts, skills, settings, memory and history',\n apiVersion: '^0.1',\n capabilities: { slashCommands: true },\n defaultConfig: {},\n\n setup(api) {\n const rawConfig = api.config as never as Record<string, unknown>;\n const paths = opts?.paths ?? (rawConfig.paths as WstackPaths | undefined);\n configStore = opts?.configStore ?? (rawConfig.configStore as ConfigStore | undefined);\n vault = opts?.vault ?? (rawConfig.vault as typeof vault | undefined);\n\n if (!paths || !configStore || !paths.configDir) {\n api.log.warn('[sync] paths, configStore, or configDir not available \u2014 /sync disabled');\n return;\n }\n const syncConfigPath = paths.syncConfig ?? path.join(paths.configDir, 'sync.json');\n\n cloud = new CloudSync(\n paths,\n () => {\n const cfg = configStore?.get();\n return (cfg as Record<string, unknown>).sync as {\n enabled: boolean; repo: string; githubToken: string; categories: SyncCategory[]\n } | null;\n },\n async (cfg) => {\n await persistSyncConfig(syncConfigPath, cfg, vault);\n configStore?.update({ sync: cfg } as Parameters<ConfigStore['update']>[0]);\n },\n () => path.join(paths.configDir, 'config.json'),\n );\n\n void cloud.loadState();\n api.slashCommands.register(buildSyncCommand(cloud, configStore, vault, syncConfigPath));\n api.log.info('[sync] loaded \u2014 /sync available. Run /sync to get started.');\n },\n\n teardown(api) {\n api.slashCommands.unregister('sync');\n api.log.info('[sync] unloaded');\n },\n\n async health() {\n return { ok: true, message: 'CloudSync ready' };\n },\n };\n}\n\nasync function persistSyncConfig(\n syncConfigPath: string,\n cfg: SyncConfig,\n vault: { encrypt(plaintext: string): string } | undefined,\n): Promise<void> {\n let githubToken = cfg.githubToken;\n if (githubToken && !githubToken.startsWith('enc:')) {\n if (!vault) {\n throw new Error('Secure token storage is unavailable; refusing to persist a plaintext token.');\n }\n const encryptedToken = vault.encrypt(githubToken);\n if (encryptedToken === githubToken || !encryptedToken.startsWith('enc:')) {\n throw new Error('Secure token storage failed; refusing to persist a plaintext token.');\n }\n githubToken = encryptedToken;\n }\n await atomicWrite(syncConfigPath, JSON.stringify({ ...cfg, githubToken }, null, 2), { mode: 0o600 });\n}\n\nfunction buildSyncCommand(\n cloud: CloudSync,\n configStore: ConfigStore,\n vault: { encrypt(plaintext: string): string; decrypt?(value: string): string } | undefined,\n syncConfigPath: string,\n): SlashCommand {\n const setSyncConfig = async (cfg: SyncConfig): Promise<void> => {\n await persistSyncConfig(syncConfigPath, cfg, vault);\n configStore.update({ sync: cfg } as Parameters<ConfigStore['update']>[0]);\n };\n\n return {\n name: 'sync',\n description: 'Cloud sync: /sync [status|enable|disable|push|pull|categories]',\n async run(args: string, _ctx: Context) {\n const [verb, ...rest] = args.trim().split(/\\s+/);\n const restJoined = rest.join(' ');\n\n switch (verb) {\n case '':\n case 'status': {\n const msg = await cloud.status();\n return { message: msg };\n }\n\n case 'enable': {\n const parts = restJoined.trim().split(/\\s+/);\n if (parts.length < 2) {\n return {\n message: [\n 'Usage: /sync enable owner/repo TOKEN [cat1 cat2 ...]',\n ' e.g. /sync enable myname/wrongstack-data ghp_xxx',\n ` Categories (default: all): ${ALL_SYNC_CATEGORIES.join(', ')}`,\n ].join('\\n'),\n };\n }\n const [repo, token, ...cats] = parts;\n if (!repo?.includes('/')) {\n return { message: 'Invalid repo format. Expected \"owner/repo\".' };\n }\n\n if (!vault) {\n return { message: 'Secure token storage is unavailable; refusing to enable CloudSync.' };\n }\n // Keep plaintext in memory for GitHub requests; persistSyncConfig encrypts\n // the token in sync.json before it reaches disk.\n const invalidCategories = cats.filter(\n (cat) => !ALL_SYNC_CATEGORIES.includes(cat as SyncCategory),\n );\n if (invalidCategories.length > 0) {\n return {\n message: `Unknown categories: ${invalidCategories.join(', ')}. Available: ${ALL_SYNC_CATEGORIES.join(', ')}`,\n };\n }\n const syncConfig: SyncConfig = {\n enabled: true,\n repo,\n githubToken: expectDefined(token),\n categories: cats.length > 0 ? cats as SyncCategory[] : ALL_SYNC_CATEGORIES,\n lastSyncedAt: undefined,\n };\n\n // Persist to the active profile's sync.json (separate from config.json\n // to avoid accidental commits). Use atomicWrite so a crash never\n // produces a half-written token file.\n await setSyncConfig(syncConfig);\n await cloud.loadState();\n\n return {\n message: [\n `CloudSync enabled for ${repo}`,\n ` categories: ${syncConfig.categories.join(', ')}`,\n '',\n 'Run `/sync push` to upload your data to GitHub.',\n ].join('\\n'),\n };\n }\n\n case 'disable': {\n const msg = await cloud.disable();\n return { message: msg };\n }\n\n case 'push': {\n const cfg = (configStore.get() as Record<string, unknown>).sync as SyncConfig | null;\n if (!cfg?.enabled) return { message: 'CloudSync not enabled. Run `/sync enable`.' };\n if (!cfg?.githubToken) return { message: 'No GitHub token found. Run `/sync enable owner/repo TOKEN`.' };\n\n let result;\n try {\n result = await cloud.push(cfg.githubToken);\n } catch (err) {\n return { message: `Push failed: ${toErrorMessage(err)}` };\n }\n\n if (result.ok) {\n try {\n await setSyncConfig({ ...cfg, lastSyncedAt: new Date().toISOString() });\n } catch (err) {\n return {\n message: `${result.message}\\nWarning: sync completed, but metadata persistence failed: ${toErrorMessage(err)}`,\n };\n }\n }\n\n return { message: result.message };\n }\n\n case 'pull': {\n const cfg = (configStore.get() as Record<string, unknown>).sync as SyncConfig | null;\n if (!cfg?.enabled) return { message: 'CloudSync not enabled. Run `/sync enable`.' };\n if (!cfg?.githubToken) return { message: 'No GitHub token. Run `/sync enable owner/repo TOKEN`.' };\n\n let result;\n try {\n result = await cloud.pull(cfg.githubToken);\n } catch (err) {\n return { message: `Pull failed: ${toErrorMessage(err)}` };\n }\n\n if (result.ok) {\n try {\n await setSyncConfig({ ...cfg, lastSyncedAt: new Date().toISOString() });\n } catch (err) {\n return {\n message: `${result.message}\\nWarning: sync completed, but metadata persistence failed: ${toErrorMessage(err)}`,\n };\n }\n }\n\n return { message: result.message };\n }\n\n case 'categories': {\n const [action, ...catRest] = restJoined.trim().split(/\\s+/);\n const cfg = (configStore.get() as Record<string, unknown>).sync as SyncConfig | null;\n\n if (!cfg?.enabled) return { message: 'CloudSync not enabled. Run `/sync enable`.' };\n\n if (action === 'list' || !action) {\n return {\n message: [\n `Synced categories: ${cfg.categories.join(', ')}`,\n `Available: ${ALL_SYNC_CATEGORIES.join(', ')}`,\n 'Update: /sync categories add <name> | remove <name>',\n ].join('\\n'),\n };\n }\n\n if (action === 'add') {\n const catName = catRest[0] as SyncCategory;\n if (!ALL_SYNC_CATEGORIES.includes(catName)) {\n return { message: `Unknown. Available: ${ALL_SYNC_CATEGORIES.join(', ')}` };\n }\n if (cfg.categories.includes(catName)) return { message: `\"${catName}\" already synced.` };\n await setSyncConfig({ ...cfg, categories: [...cfg.categories, catName] });\n return { message: `Added \"${catName}\" to sync categories.` };\n }\n\n if (action === 'remove') {\n const catName = catRest[0] as SyncCategory;\n if (!cfg.categories.includes(catName)) return { message: `\"${catName}\" not in sync categories.` };\n await setSyncConfig({\n ...cfg,\n categories: cfg.categories.filter((c: SyncCategory) => c !== catName),\n });\n return { message: `Removed \"${catName}\" from sync categories.` };\n }\n\n return { message: 'Usage: /sync categories list | add <name> | remove <name>' };\n }\n\n default:\n return {\n message: [\n '/sync \u2014 Cloud Sync',\n '',\n ' /sync status Show current sync status',\n ' /sync enable owner/repo TOKEN Enable for a repo (TOKEN = fine-grained PAT)',\n ' /sync disable Disable sync (keeps local data)',\n ' /sync push Upload selected categories',\n ' /sync pull Download from repo',\n ' /sync categories list|add|remove Manage synced categories',\n '',\n `Categories: ${ALL_SYNC_CATEGORIES.join(', ')}`,\n ].join('\\n'),\n };\n }\n },\n };\n}\n", "import { expectDefined } from '../utils/expect-defined.js';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { atomicWrite } from '../utils/atomic-write.js';\nimport { createHash } from 'node:crypto';\nimport type { WstackPaths } from '../utils/wstack-paths.js';\nimport type { SyncCategory, SyncConfig } from '../types/config.js';\nimport { FsError, WrongStackError, ERROR_CODES } from '../types/errors.js';\nexport const ALL_SYNC_CATEGORIES: SyncCategory[] = ['settings', 'skills', 'prompts', 'memory', 'history'];\n\nexport interface SyncResult {\n ok: boolean;\n action: 'push' | 'pull';\n categories: SyncCategory[];\n committedAt?: string | undefined;\n message: string;\n}\n\ntype LocalTreeEntry = { path: string; content: string; mode: string };\ntype GitTreeEntry = LocalTreeEntry | { path: string; sha: null; mode: string };\ntype RemoteTreeEntry = { path: string; sha: string; type: 'blob' | 'tree' };\n\ninterface SyncStateFile {\n version: 1;\n /** Last pushed/pulled commit SHA. */\n sha: string;\n /** Tree SHA paired with `sha`; absent in legacy state files. */\n treeSha?: string | undefined;\n lastSyncedAt: string;\n localRev: string;\n}\n\n/**\n * CloudSync \u2014 push/pull user-selected ~/.wrongstack categories to a\n * private GitHub repo. No git CLI needed; uses GitHub REST API via fetch.\n * The token is stored encrypted via SecretVault (field named `githubToken`\n * so the vault walker picks it up automatically).\n */\nexport class CloudSync {\n private readonly statePath: string;\n private state: SyncStateFile | null = null;\n private readonly getSettingsConfigPath: () => string;\n\n constructor(\n private readonly paths: WstackPaths,\n private readonly getConfig: () => SyncConfig | null,\n private readonly setConfig: (c: SyncConfig) => Promise<void>,\n getSettingsConfigPath?: (() => string) | undefined,\n ) {\n this.statePath = path.join(paths.configDir, 'sync-state.json');\n // Settings belong to the resolved profile. `configDir` is already pinned\n // to that profile, so narrow embedders do not need to implement the named\n // profile resolver and can never silently jump to `default`.\n this.getSettingsConfigPath =\n getSettingsConfigPath ??\n (() => path.join(this.paths.configDir, 'config.json'));\n }\n\n // \u2500\u2500 Public API \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n async status(): Promise<string> {\n const cfg = this.getConfig();\n if (!cfg?.enabled) {\n return 'CloudSync: disabled. Run `/sync enable` to activate.';\n }\n const last = this.state?.lastSyncedAt;\n const since = last ? timeAgo(last) : 'never';\n return [\n `CloudSync: enabled`,\n ` repo: ${cfg.repo}`,\n ` categories: ${cfg.categories.join(', ')}`,\n ` last sync: ${since}`,\n ].join('\\n');\n }\n\n async enable(_repo: string, _categories: SyncCategory[]): Promise<string> {\n // Persisted by the slash command via configStore.update.\n return 'Enable via /sync enable.';\n }\n\n async disable(): Promise<string> {\n const cfg = this.getConfig();\n if (!cfg) return 'CloudSync is not configured.';\n const next = { ...cfg, enabled: false };\n await this.setConfig(next);\n return 'CloudSync disabled. Local data kept.';\n }\n\n async push(token: string): Promise<SyncResult> {\n const cfg = this.getConfig();\n if (!cfg?.enabled) return { ok: false, action: 'push', categories: [], message: 'Not enabled.' };\n\n const parts = cfg.repo.split('/');\n const owner = expectDefined(parts[0]);\n const repoName = expectDefined(parts[1]);\n const branch = 'main';\n const remoteHead = await this.getOptionalRef(token, owner, repoName, branch);\n let parentCommitSha = remoteHead?.object?.sha;\n let baseTreeSha: string | undefined;\n let remoteEntries: RemoteTreeEntry[] = [];\n if (parentCommitSha) {\n baseTreeSha =\n parentCommitSha === this.state?.sha && this.state.treeSha\n ? this.state.treeSha\n : (await this.getCommit(token, owner, repoName, parentCommitSha)).tree.sha;\n remoteEntries = await this.getTreeEntries(token, owner, repoName, baseTreeSha);\n }\n\n const { treeEntries: localEntries, rev } = await this.buildLocalTree(cfg.categories);\n let treeEntries = this.buildPushTree(localEntries, remoteEntries, cfg.categories);\n let newTreeSha = await this.createGitTree(token, owner, repoName, treeEntries, baseTreeSha);\n\n let commitSha = await this.createCommit(\n token, owner, repoName, newTreeSha,\n parentCommitSha,\n `Sync ${cfg.categories.join(', ')} \u2014 ${new Date().toISOString()}`,\n );\n\n try {\n if (parentCommitSha) {\n await this.updateRef(token, owner, repoName, branch, commitSha);\n } else {\n await this.createRef(token, owner, repoName, branch, commitSha);\n }\n } catch (err) {\n // 422 = not a fast forward \u2014 remote branch moved. Fetch latest SHA and retry.\n if (err instanceof Error && err.message.includes('422')) {\n const remote = await this.getRef(token, owner, repoName, branch);\n parentCommitSha = remote.object.sha;\n baseTreeSha = (await this.getCommit(token, owner, repoName, parentCommitSha)).tree.sha;\n // Rebuild on the latest remote tree so concurrent files/categories are\n // preserved and deletions are recalculated after the conflict.\n remoteEntries = await this.getTreeEntries(token, owner, repoName, baseTreeSha);\n treeEntries = this.buildPushTree(localEntries, remoteEntries, cfg.categories);\n newTreeSha = await this.createGitTree(token, owner, repoName, treeEntries, baseTreeSha);\n commitSha = await this.createCommit(\n token, owner, repoName, newTreeSha,\n parentCommitSha,\n `Sync ${cfg.categories.join(', ')} \u2014 ${new Date().toISOString()}`,\n );\n await this.updateRef(token, owner, repoName, branch, commitSha);\n } else {\n throw err;\n }\n }\n\n const syncState: SyncStateFile = {\n version: 1,\n sha: commitSha,\n treeSha: newTreeSha,\n lastSyncedAt: new Date().toISOString(),\n localRev: rev,\n };\n await atomicWrite(this.statePath, JSON.stringify(syncState, null, 2));\n this.state = syncState;\n\n return {\n ok: true,\n action: 'push',\n categories: cfg.categories,\n committedAt: commitSha,\n message: `Pushed ${cfg.categories.join(', ')} to ${cfg.repo}. Commit: ${commitSha.slice(0, 7)}`,\n };\n }\n\n async pull(token: string): Promise<SyncResult> {\n const cfg = this.getConfig();\n if (!cfg?.enabled) return { ok: false, action: 'pull', categories: [], message: 'Not enabled.' };\n\n const pullParts = cfg.repo.split('/');\n const owner = expectDefined(pullParts[0]);\n const repoName = expectDefined(pullParts[1]);\n\n const branchData = await this.getRef(token, owner, repoName, 'main');\n const currentSha = branchData.object.sha;\n\n const commitData = await this.getCommit(token, owner, repoName, currentSha);\n const treeSha = commitData.tree.sha;\n\n const treeEntries = await this.getTreeEntries(token, owner, repoName, treeSha);\n\n for (const entry of treeEntries) {\n if (entry.type !== 'blob') continue;\n\n // Paths look like \"data/{category}/...\" \u2014 extract the category\n const segments = entry.path.split('/');\n if (segments[0] !== 'data' || !segments[1]) continue;\n const cat = segments[1] as SyncCategory;\n if (!ALL_SYNC_CATEGORIES.includes(cat) || !cfg.categories.includes(cat)) continue;\n\n const localPath = this.categoryToPath(cat);\n if (!localPath) continue;\n\n // Reconstruct relative path under the category dir. Remote trees are\n // untrusted input: a compromised sync repo could contain paths like\n // data/skills/../../config.json. Keep every write inside the selected\n // category root, and only allow subpaths for directory-backed categories.\n const rel = segments.slice(2).join('/');\n const destPath = resolvePulledCategoryPath(cat, localPath, rel, entry.path);\n\n await preparePulledDestination(cat, localPath, destPath, entry.path);\n const blobData = await this.getBlob(token, owner, repoName, entry.sha);\n // Atomic write: pulled blobs land on live files (config.json, memory,\n // history). A bare writeFile truncated by a crash/ENOSPC mid-write would\n // corrupt the live file; atomicWrite writes a temp + fsync + rename.\n await atomicWrite(destPath, Buffer.from(blobData, 'base64'));\n }\n\n const localRev = await this.hashLocalCategories(cfg.categories);\n const syncState: SyncStateFile = {\n version: 1,\n sha: currentSha,\n treeSha,\n lastSyncedAt: new Date().toISOString(),\n localRev,\n };\n await atomicWrite(this.statePath, JSON.stringify(syncState, null, 2));\n this.state = syncState;\n\n return {\n ok: true,\n action: 'pull',\n categories: cfg.categories,\n committedAt: currentSha,\n message: `Pulled ${cfg.categories.join(', ')} from ${cfg.repo}. Commit: ${currentSha.slice(0, 7)}`,\n };\n }\n\n async hasLocalChanges(): Promise<boolean> {\n if (!this.state) return true;\n const cfg = this.getConfig();\n if (!cfg) return true;\n const current = await this.hashLocalCategories(cfg.categories);\n return current !== this.state.localRev;\n }\n\n async loadState(): Promise<void> {\n try {\n const raw = await fs.readFile(this.statePath, 'utf8');\n this.state = JSON.parse(raw) as SyncStateFile;\n } catch {\n this.state = null;\n }\n }\n\n // \u2500\u2500 GitHub API helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n private async githubFetch(\n token: string,\n owner: string,\n repo: string,\n method: 'GET' | 'POST' | 'PUT' | 'PATCH',\n pathSegment: string,\n body?: unknown | undefined,\n ): Promise<unknown> {\n const url = `https://api.github.com/repos/${owner}/${repo}${pathSegment}`;\n const init: RequestInit = {\n signal: AbortSignal.timeout(15_000),\n method,\n headers: {\n Authorization: `Bearer ${token}`,\n Accept: 'application/vnd.github+json',\n 'X-GitHub-Api-Version': '2022-11-28',\n 'Content-Type': 'application/json',\n },\n };\n if (body !== undefined) init.body = JSON.stringify(body);\n const res = await fetch(url, init);\n\n if (!res.ok) {\n const errText = await res.text();\n throw new WrongStackError({\n message: `GitHub API ${method} ${pathSegment} failed (${res.status}): ${errText}`,\n code: ERROR_CODES.UNKNOWN,\n subsystem: 'general',\n context: { method, pathSegment, status: res.status, repo: `${owner}/${repo}` },\n });\n }\n\n const text = await res.text();\n return text ? JSON.parse(text) : {};\n }\n\n private async getRef(token: string, owner: string, repo: string, ref: string) {\n return (await this.githubFetch(token, owner, repo, 'GET', `/git/refs/heads/${ref}`)) as {\n object: { sha: string };\n };\n }\n\n private async getOptionalRef(token: string, owner: string, repo: string, ref: string) {\n try {\n return await this.getRef(token, owner, repo, ref);\n } catch (err) {\n if (err instanceof Error && err.message.includes('failed (404)')) return null;\n if (err instanceof Error && err.message.includes('failed (409)')) {\n throw new WrongStackError({\n message: 'GitHub repository is empty. Initialize it with a README or first commit, then retry `/sync push`.',\n code: ERROR_CODES.UNKNOWN,\n subsystem: 'general',\n context: { repo: `${owner}/${repo}`, ref },\n cause: err,\n });\n }\n throw err;\n }\n }\n\n private async createRef(token: string, owner: string, repo: string, ref: string, sha: string) {\n await this.githubFetch(token, owner, repo, 'POST', '/git/refs', {\n ref: `refs/heads/${ref}`,\n sha,\n });\n }\n\n private async updateRef(token: string, owner: string, repo: string, ref: string, sha: string) {\n await this.githubFetch(token, owner, repo, 'PATCH', `/git/refs/heads/${ref}`, {\n sha,\n force: false,\n });\n }\n\n private async getCommit(token: string, owner: string, repo: string, sha: string) {\n return (await this.githubFetch(token, owner, repo, 'GET', `/git/commits/${sha}`)) as {\n tree: { sha: string };\n message: string;\n };\n }\n\n private async getTreeEntries(\n token: string,\n owner: string,\n repo: string,\n treeSha: string,\n ): Promise<RemoteTreeEntry[]> {\n // GitHub returns `{ sha, tree: [...], truncated }`, NOT a bare array \u2014 the\n // previous cast made `for (const entry of ...)` throw \"not iterable\", so\n // pull never actually ran. Unwrap `.tree`, and refuse a truncated result\n // rather than silently syncing a partial file set.\n const res = (await this.githubFetch(\n token,\n owner,\n repo,\n 'GET',\n `/git/trees/${treeSha}?recursive=1`,\n )) as {\n tree?: Array<{ path: string; sha: string; type: 'blob' | 'tree' }>;\n truncated?: boolean;\n };\n if (res.truncated) {\n throw new WrongStackError({\n message:\n 'Sync tree is too large \u2014 GitHub truncated the result; refusing a partial pull.',\n code: ERROR_CODES.UNKNOWN,\n subsystem: 'general',\n });\n }\n return res.tree ?? [];\n }\n\n private async createCommit(\n token: string, owner: string, repo: string,\n treeSha: string, parentSha?: string | undefined, message = 'sync',\n ) {\n const body: Record<string, unknown> = { message, tree: treeSha };\n if (parentSha) body.parents = [parentSha];\n const result = (await this.githubFetch(token, owner, repo, 'POST', '/git/commits', body)) as { sha: string };\n return result.sha;\n }\n\n private async createGitTree(\n token: string, owner: string, repo: string,\n entries: GitTreeEntry[],\n baseTreeSha?: string | undefined,\n ): Promise<string> {\n const tree = entries.map((entry) =>\n 'sha' in entry\n ? { path: entry.path, mode: entry.mode, type: 'blob', sha: entry.sha }\n : { path: entry.path, mode: entry.mode, type: 'blob', content: entry.content },\n );\n const body: Record<string, unknown> = { tree };\n if (baseTreeSha) body.base_tree = baseTreeSha;\n const result = (await this.githubFetch(token, owner, repo, 'POST', '/git/trees', body)) as { sha: string };\n return result.sha;\n }\n\n private async getBlob(token: string, owner: string, repo: string, sha: string): Promise<string> {\n const result = (await this.githubFetch(token, owner, repo, 'GET', `/git/blobs/${sha}`)) as { content: string };\n return result.content;\n }\n\n // \u2500\u2500 Local file helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n private buildPushTree(\n localEntries: LocalTreeEntry[],\n remoteEntries: RemoteTreeEntry[],\n categories: SyncCategory[],\n ): GitTreeEntry[] {\n const selected = new Set(categories.map((category) => `data/${category}`));\n const localPaths = new Set(localEntries.map((entry) => entry.path));\n const deletions: GitTreeEntry[] = [];\n for (const entry of remoteEntries) {\n if (entry.type !== 'blob' || localPaths.has(entry.path)) continue;\n const selectedCategory = [...selected].some(\n (prefix) => entry.path === prefix || entry.path.startsWith(`${prefix}/`),\n );\n if (selectedCategory) deletions.push({ path: entry.path, sha: null, mode: '100644' });\n }\n return [...localEntries, ...deletions];\n }\n\n private async buildLocalTree(categories: SyncCategory[]): Promise<{\n treeEntries: LocalTreeEntry[];\n rev: string;\n }> {\n const entries: Array<{ path: string; content: string; mode: string }> = [];\n const hashes: string[] = [];\n\n for (const cat of categories) {\n const localPath = this.categoryToPath(cat);\n if (!localPath) continue;\n try {\n const stat = await fs.lstat(localPath);\n if (stat.isSymbolicLink()) continue;\n if (stat.isDirectory()) {\n const files = await this.walkDir(localPath, localPath);\n for (const file of files) {\n const content = await fs.readFile(file, 'utf8');\n const rel = path.relative(localPath, file).replace(/\\\\/g, '/');\n entries.push({ path: `data/${cat}/${rel}`, content, mode: '100644' });\n hashes.push(`${cat}/${rel}\\0${content}`);\n }\n } else {\n const content = await fs.readFile(localPath, 'utf8');\n entries.push({ path: `data/${cat}`, content, mode: '100644' });\n hashes.push(`${cat}\\0${content}`);\n }\n } catch {\n // skip missing files/dirs\n }\n }\n\n const rev = createHash('sha256').update(hashes.join('')).digest('hex').slice(0, 12);\n return { treeEntries: entries, rev };\n }\n\n private async hashLocalCategories(categories: SyncCategory[]): Promise<string> {\n const hashes: string[] = [];\n for (const cat of categories) {\n const localPath = this.categoryToPath(cat);\n if (!localPath) continue;\n try {\n const stat = await fs.lstat(localPath);\n if (stat.isSymbolicLink()) continue;\n if (stat.isDirectory()) {\n const files = await this.walkDir(localPath, localPath);\n for (const file of files) {\n const content = await fs.readFile(file, 'utf8');\n const rel = path.relative(localPath, file).replace(/\\\\/g, '/');\n hashes.push(`${cat}/${rel}\\0${content}`);\n }\n } else {\n const content = await fs.readFile(localPath, 'utf8');\n hashes.push(`${cat}\\0${content}`);\n }\n } catch {\n // skip\n }\n }\n return createHash('sha256').update(hashes.join('')).digest('hex').slice(0, 12);\n }\n\n private categoryToPath(cat: SyncCategory): string | null {\n switch (cat) {\n case 'settings': return this.getSettingsConfigPath();\n case 'skills': return this.paths.globalSkills;\n case 'prompts': return this.paths.globalPrompts;\n case 'memory': return this.paths.globalMemory;\n case 'history': return this.paths.historyFile;\n /* v8 ignore next -- unreachable: SyncCategory is exhaustively matched above */\n default: return null;\n }\n }\n\n private async walkDir(dir: string, base: string): Promise<string[]> {\n const results: string[] = [];\n const entries = await fs.readdir(dir, { withFileTypes: true });\n entries.sort((a, b) => a.name.localeCompare(b.name));\n for (const entry of entries) {\n const full = path.join(dir, entry.name);\n if (entry.isSymbolicLink()) continue;\n if (entry.isDirectory()) {\n results.push(...(await this.walkDir(full, base)));\n } else if (entry.isFile()) {\n results.push(full);\n }\n }\n return results;\n }\n}\n\nasync function preparePulledDestination(\n cat: SyncCategory,\n localPath: string,\n destPath: string,\n remotePath: string,\n): Promise<void> {\n const directoryBacked = cat === 'skills' || cat === 'prompts';\n const rootPath = directoryBacked ? localPath : path.dirname(localPath);\n const rootStat = await lstatIfExists(rootPath);\n if (rootStat?.isSymbolicLink()) {\n throw unsafePulledSymlinkError(remotePath, rootPath);\n }\n\n if (directoryBacked) {\n const relativeParent = path.relative(rootPath, path.dirname(destPath));\n let cursor = rootPath;\n if (relativeParent) {\n for (const segment of relativeParent.split(path.sep)) {\n cursor = path.join(cursor, segment);\n const stat = await lstatIfExists(cursor);\n if (stat?.isSymbolicLink()) throw unsafePulledSymlinkError(remotePath, cursor);\n }\n }\n }\n\n const destStat = await lstatIfExists(destPath);\n if (destStat?.isSymbolicLink()) throw unsafePulledSymlinkError(remotePath, destPath);\n await fs.mkdir(path.dirname(destPath), { recursive: true });\n}\n\nasync function lstatIfExists(filePath: string): Promise<Awaited<ReturnType<typeof fs.lstat>> | null> {\n try {\n return await fs.lstat(filePath);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return null;\n throw err;\n }\n}\n\nfunction unsafePulledSymlinkError(remotePath: string, symlinkPath: string): FsError {\n return new FsError({\n message: `Refusing CloudSync write through symlink: ${remotePath}`,\n code: ERROR_CODES.FS_DELETE_FAILED,\n path: remotePath,\n context: { reason: 'symlink_destination', symlinkPath },\n });\n}\n\nfunction resolvePulledCategoryPath(\n cat: SyncCategory,\n localPath: string,\n rel: string,\n remotePath: string,\n): string {\n const directoryBacked = cat === 'skills' || cat === 'prompts';\n if (!directoryBacked) {\n if (rel) throw new FsError({\n message: `Refusing nested CloudSync path for file category: ${remotePath}`,\n code: ERROR_CODES.FS_DELETE_FAILED,\n path: remotePath,\n context: { reason: 'nested_file_category', category: cat },\n });\n return localPath;\n }\n\n if (!rel) return localPath;\n const normalizedRel = path.normalize(rel);\n const traversesUp = normalizedRel === '..' || normalizedRel.startsWith(`..${path.sep}`);\n if (path.isAbsolute(normalizedRel) || traversesUp) {\n throw new FsError({\n message: `Refusing CloudSync path traversal: ${remotePath}`,\n code: ERROR_CODES.FS_DELETE_FAILED,\n path: remotePath,\n context: { reason: 'path_traversal', normalizedRel },\n });\n }\n\n const dest = path.resolve(localPath, normalizedRel);\n const root = path.resolve(localPath);\n const relative = path.relative(root, dest);\n // On POSIX, a backslash is not a path separator, so an input such as\n // `..\\\\secret` reaches this containment check even though the first guard\n // rejects ordinary `../secret` traversal.\n if (relative.startsWith('..') || path.isAbsolute(relative)) {\n throw new FsError({\n message: `Refusing CloudSync path outside category root: ${remotePath}`,\n code: ERROR_CODES.FS_DELETE_FAILED,\n path: remotePath,\n context: { reason: 'outside_category_root', category: cat },\n });\n }\n return dest;\n}\n\nfunction timeAgo(iso: string): string {\n const diff = Date.now() - new Date(iso).getTime();\n const mins = Math.floor(diff / 60_000);\n if (mins < 1) return 'just now';\n if (mins < 60) return `${mins}m ago`;\n const hrs = Math.floor(mins / 60);\n if (hrs < 24) return `${hrs}h ago`;\n const days = Math.floor(hrs / 24);\n return `${days}d ago`;\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["createHash", "randomUUID", "fsp", "path", "randomUUID", "fsp", "path", "NL", "path", "pipeline", "spawn", "createHash", "path", "spawn", "os", "path", "createHash", "projectHash", "createHash", "os", "path", "fs", "path", "createHash", "path", "resolve", "stat", "fs", "path", "createHash", "createReadStream", "fs", "path", "createInterface", "fs", "path", "createReadStream", "createInterface", "trimmed", "deepEqual", "createHash", "stableStringify", "isRecord", "durationMs", "readPath", "numberAt", "scopeKey", "fs", "path", "randomUUID", "createRequire", "path", "open", "readFileSync", "statSync", "path", "slugify", "encodeCursor", "decodeCursor", "SCHEMA_VERSION", "Ctor", "loadDatabaseSync", "createRequire", "randomUUID", "fs", "path", "fileURLToPath", "createHash", "os", "path", "createHash", "fileURLToPath", "resolve", "resolve", "spawn", "task", "access", "runGit", "resolve", "spawn", "stat", "createHash", "fingerprint", "randomUUID", "spawn", "fsp", "os", "path", "randomUUID", "JsonlFindingStore", "lines", "reportId", "JsonlReportStore", "DEFAULT_MAX_CASCADE_DEPTH", "runGit", "resolve", "spawn", "isGitRepo", "getChangedFiles", "randomUUID", "fs", "path", "fs", "path", "fs", "path", "SCHEMA_VERSION", "slugify", "SCHEMA_VERSION", "fs", "resolve", "stat", "matches", "lines", "os", "path", "spawn", "fs", "path", "unquote", "normalizeKey", "spawn", "fs", "path", "fs", "os", "path", "fs", "path", "resolved", "stat", "installer", "path", "fs", "path", "createHash", "stat", "relative"]
|
|
7
|
-
}
|