@wrongstack/core 0.296.4 → 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 +1076 -283
- package/dist/coordination/agents/index.js +136 -1
- package/dist/coordination/agents/role-skills.d.ts +3 -2
- package/dist/coordination/brain-cache.d.ts +14 -0
- 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 +16514 -15945
- 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-http-router.d.ts +6 -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 +1270 -289
- 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 +30 -4
- package/dist/coordination/sqlite-mailbox-credentials.d.ts +11 -0
- package/dist/core/context.d.ts +5 -5
- package/dist/core/fallback-profile-manager.d.ts +14 -0
- package/dist/core/index.js +624 -168
- 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 +2393 -1302
- package/dist/design/index.js +47 -8
- package/dist/execution/design-materialize.d.ts +22 -0
- package/dist/execution/index.js +582 -285
- 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 +71 -17
- package/dist/goal/phase-store.d.ts +7 -0
- 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 +680 -163
- package/dist/hq/kanban-store.d.ts +3 -0
- package/dist/hq/persistence/event-log.d.ts +25 -0
- package/dist/hq/persistence.d.ts +1 -1
- package/dist/hq/protocol/browser.d.ts +2 -1
- package/dist/hq/protocol/client.d.ts +18 -1
- package/dist/hq/protocol/core.d.ts +5 -16
- package/dist/hq/protocol/envelope.d.ts +29 -0
- package/dist/hq/protocol/governance.d.ts +34 -0
- package/dist/hq/protocol/peer.d.ts +55 -0
- package/dist/hq/protocol/project.d.ts +3 -0
- package/dist/hq/protocol/resume.d.ts +56 -0
- package/dist/hq/protocol.d.ts +11 -8
- package/dist/hq/protocol.js +675 -0
- package/dist/hq/publisher.d.ts +31 -2
- package/dist/hq/session-bridge.d.ts +8 -0
- package/dist/index.js +7197 -4006
- 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.d.ts +1 -1
- package/dist/observability/index.js +103 -5
- package/dist/observability/metrics.d.ts +37 -0
- package/dist/observability/prometheus.d.ts +11 -0
- package/dist/plugin/index.d.ts +5 -1
- package/dist/plugin/index.js +965 -511
- package/dist/plugins/auto-review-plugin.d.ts +6 -0
- 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/file-session-writer.d.ts +23 -0
- package/dist/storage/index.js +1140 -905
- package/dist/storage/provider-config-watcher.d.ts +1 -0
- package/dist/storage/session-helpers.d.ts +1 -0
- package/dist/storage/session-reader.d.ts +0 -7
- package/dist/storage/session-store/types.d.ts +12 -1
- package/dist/storage/session-store.d.ts +11 -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 +305 -133
- 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 +15 -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/observability.d.ts +13 -0
- package/dist/types/secret-vault.d.ts +8 -0
- package/dist/types/session.d.ts +42 -0
- package/dist/types/skill.d.ts +56 -0
- package/dist/types/tool-executor.d.ts +2 -0
- package/dist/utils/continuous-memory-profiler.d.ts +35 -0
- package/dist/utils/env-typed.d.ts +64 -0
- package/dist/utils/glob-match.d.ts +21 -1
- package/dist/utils/heap-watchdog-types.d.ts +62 -0
- package/dist/utils/heap-watchdog.d.ts +15 -34
- package/dist/utils/heap-watchdog.js +592 -18
- package/dist/utils/incoming-images.d.ts +19 -0
- package/dist/utils/index.d.ts +15 -11
- package/dist/utils/index.js +1425 -545
- package/dist/utils/memory-flight-recorder.d.ts +47 -0
- package/dist/utils/path-segment.d.ts +29 -0
- package/dist/utils/tool-name.d.ts +34 -0
- package/dist/utils/win32-cmd.d.ts +25 -0
- package/dist/worktree/index.js +5 -0
- package/package.json +11 -3
- package/skills/chimera/SKILL.md +16 -4
- package/skills/data-governance/SKILL.md +92 -0
- package/skills/wrongstack-kanban/SKILL.md +129 -0
- package/skills/wrongstack-kanban/agents/openai.yaml +4 -0
- package/skills/wrongstack-mailbox-mcp/SKILL.md +72 -0
- package/skills/wrongstack-mailbox-mcp/agents/openai.yaml +4 -0
- 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/project.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/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.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/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-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/storage/index.js
CHANGED
|
@@ -2,67 +2,80 @@
|
|
|
2
2
|
import * as fsp12 from "node:fs/promises";
|
|
3
3
|
import * as path13 from "node:path";
|
|
4
4
|
|
|
5
|
+
// src/security/file-permissions.ts
|
|
6
|
+
var SECRET_FILE_MODE = 384;
|
|
7
|
+
|
|
5
8
|
// src/security/secret-scrubber.ts
|
|
6
9
|
var PATTERNS = [
|
|
7
10
|
// Anchored at the start where possible so partial matches inside larger
|
|
8
11
|
// strings don't trigger false positives.
|
|
9
12
|
{
|
|
10
13
|
type: "anthropic_key",
|
|
11
|
-
regex: /(?<![A-Za-z0-9])sk-ant-api\d+-[A-Za-z0-9_-]{20,}(?![A-Za-z0-9])/g
|
|
14
|
+
regex: /(?<![A-Za-z0-9])sk-ant-api\d+-[A-Za-z0-9_-]{20,}(?![A-Za-z0-9])/g,
|
|
15
|
+
anchor: "sk-ant-"
|
|
12
16
|
},
|
|
13
|
-
{ type: "openai_key", regex: /(?<![A-Za-z0-9])sk-(?:proj-)?[A-Za-z0-9_-]{20,}(?![A-Za-z0-9])/g },
|
|
14
|
-
{ type: "github_pat", regex: /(?<![A-Za-z0-9])ghp_[A-Za-z0-9]{36,}(?![A-Za-z0-9])/g },
|
|
15
|
-
{ type: "github_pat_v2", regex: /(?<![A-Za-z0-9])github_pat_[A-Za-z0-9_]{50,}(?![A-Za-z0-9])/g },
|
|
16
|
-
{ type: "aws_access_key", regex: /(?<![A-Za-z0-9])AKIA[0-9A-Z]{16}(?![A-Za-z0-9])/g },
|
|
17
|
-
{ type: "gcp_key", regex: /(?<![A-Za-z0-9])AIza[0-9A-Za-z_-]{35}(?![A-Za-z0-9])/g },
|
|
18
|
-
{ type: "slack_token", regex: /(?<![A-Za-z0-9-])xox[abpos]-[A-Za-z0-9-]{10,}(?![A-Za-z0-9-])/g },
|
|
17
|
+
{ type: "openai_key", regex: /(?<![A-Za-z0-9])sk-(?:proj-)?[A-Za-z0-9_-]{20,}(?![A-Za-z0-9])/g, anchor: "sk-" },
|
|
18
|
+
{ type: "github_pat", regex: /(?<![A-Za-z0-9])ghp_[A-Za-z0-9]{36,}(?![A-Za-z0-9])/g, anchor: "ghp_" },
|
|
19
|
+
{ type: "github_pat_v2", regex: /(?<![A-Za-z0-9])github_pat_[A-Za-z0-9_]{50,}(?![A-Za-z0-9])/g, anchor: "github_pat_" },
|
|
20
|
+
{ type: "aws_access_key", regex: /(?<![A-Za-z0-9])AKIA[0-9A-Z]{16}(?![A-Za-z0-9])/g, anchor: "AKIA" },
|
|
21
|
+
{ type: "gcp_key", regex: /(?<![A-Za-z0-9])AIza[0-9A-Za-z_-]{35}(?![A-Za-z0-9])/g, anchor: "AIza" },
|
|
22
|
+
{ type: "slack_token", regex: /(?<![A-Za-z0-9-])xox[abpos]-[A-Za-z0-9-]{10,}(?![A-Za-z0-9-])/g, anchor: "xox" },
|
|
19
23
|
{
|
|
20
24
|
type: "stripe_key",
|
|
21
|
-
regex: /(?<![A-Za-z0-9])sk_(?:live|test)_[A-Za-z0-9]{24,}(?![A-Za-z0-9])/g
|
|
25
|
+
regex: /(?<![A-Za-z0-9])sk_(?:live|test)_[A-Za-z0-9]{24,}(?![A-Za-z0-9])/g,
|
|
26
|
+
anchor: "sk_"
|
|
22
27
|
},
|
|
23
28
|
{
|
|
24
29
|
type: "twilio_sid",
|
|
25
|
-
regex: /(?<![A-Za-z0-9])AC[a-f0-9]{32}(?![A-Za-z0-9])/g
|
|
30
|
+
regex: /(?<![A-Za-z0-9])AC[a-f0-9]{32}(?![A-Za-z0-9])/g,
|
|
31
|
+
anchor: "AC"
|
|
26
32
|
},
|
|
27
33
|
{
|
|
28
34
|
type: "telegram_bot_token",
|
|
29
35
|
// Telegram tokens are of the form bot<digits>:<alphanum> in URL paths
|
|
30
|
-
regex: /\/bot\d+:[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g
|
|
36
|
+
regex: /\/bot\d+:[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g,
|
|
37
|
+
anchor: "/bot"
|
|
31
38
|
},
|
|
32
39
|
{
|
|
33
40
|
type: "jwt",
|
|
34
41
|
// Anchored: look for literal "eyJ" which is unambiguous for JWT header
|
|
35
|
-
regex: /(?<![A-Za-z0-9/+=])eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}(?![A-Za-z0-9/+=])/g
|
|
42
|
+
regex: /(?<![A-Za-z0-9/+=])eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}(?![A-Za-z0-9/+=])/g,
|
|
43
|
+
anchor: "eyJ"
|
|
36
44
|
},
|
|
37
45
|
{
|
|
38
46
|
type: "private_key",
|
|
39
47
|
// Anchored: start must be BEGIN, end must be END with no extra dashes after END
|
|
40
|
-
regex: /(?:^|\n)-----BEGIN (?:RSA|EC|OPENSSH|DSA|PGP)? ?PRIVATE KEY-----[\s\S]*?-----END[^-]*-----(?:\n|$)/g
|
|
48
|
+
regex: /(?:^|\n)-----BEGIN (?:RSA|EC|OPENSSH|DSA|PGP)? ?PRIVATE KEY-----[\s\S]*?-----END[^-]*-----(?:\n|$)/g,
|
|
49
|
+
anchor: "-----BEGIN"
|
|
41
50
|
},
|
|
42
|
-
{ type: "mongodb_uri", regex: /mongodb(?:\+srv)?:\/\/[^\s"'`]+/g },
|
|
43
|
-
{ type: "postgres_uri", regex: /postgres(?:ql)?:\/\/[^\s"'`]+/g },
|
|
44
|
-
{ type: "mysql_uri", regex: /mysql:\/\/[^\s"'`]+/g },
|
|
45
|
-
{ type: "redis_uri", regex: /redis:\/\/[^\s"'`]+/g },
|
|
51
|
+
{ type: "mongodb_uri", regex: /mongodb(?:\+srv)?:\/\/[^\s"'`]+/g, anchor: "mongodb" },
|
|
52
|
+
{ type: "postgres_uri", regex: /postgres(?:ql)?:\/\/[^\s"'`]+/g, anchor: "postgres" },
|
|
53
|
+
{ type: "mysql_uri", regex: /mysql:\/\/[^\s"'`]+/g, anchor: "mysql://" },
|
|
54
|
+
{ type: "redis_uri", regex: /redis:\/\/[^\s"'`]+/g, anchor: "redis://" },
|
|
46
55
|
// AI/ML provider keys — modern LLM services with well-known prefixes
|
|
47
56
|
{
|
|
48
57
|
type: "huggingface_token",
|
|
49
58
|
// HuggingFace tokens: hf_ followed by 34 alphanumeric chars
|
|
50
|
-
regex: /(?<![A-Za-z0-9])hf_[A-Za-z0-9]{34}(?![A-Za-z0-9])/g
|
|
59
|
+
regex: /(?<![A-Za-z0-9])hf_[A-Za-z0-9]{34}(?![A-Za-z0-9])/g,
|
|
60
|
+
anchor: "hf_"
|
|
51
61
|
},
|
|
52
62
|
{
|
|
53
63
|
type: "replicate_token",
|
|
54
64
|
// Replicate tokens: r8_ followed by 40+ alphanumeric chars
|
|
55
|
-
regex: /(?<![A-Za-z0-9])r8_[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g
|
|
65
|
+
regex: /(?<![A-Za-z0-9])r8_[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g,
|
|
66
|
+
anchor: "r8_"
|
|
56
67
|
},
|
|
57
68
|
{
|
|
58
69
|
type: "perplexity_key",
|
|
59
70
|
// Perplexity API keys: pplx- followed by 40+ alphanumeric chars
|
|
60
|
-
regex: /(?<![A-Za-z0-9])pplx-[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g
|
|
71
|
+
regex: /(?<![A-Za-z0-9])pplx-[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g,
|
|
72
|
+
anchor: "pplx-"
|
|
61
73
|
},
|
|
62
74
|
{
|
|
63
75
|
type: "groq_key",
|
|
64
76
|
// Groq API keys: gsk_ followed by 40+ alphanumeric chars
|
|
65
|
-
regex: /(?<![A-Za-z0-9])gsk_[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g
|
|
77
|
+
regex: /(?<![A-Za-z0-9])gsk_[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g,
|
|
78
|
+
anchor: "gsk_"
|
|
66
79
|
},
|
|
67
80
|
{
|
|
68
81
|
type: "bearer_token",
|
|
@@ -75,7 +88,8 @@ var PATTERNS = [
|
|
|
75
88
|
// tokens sharing a single delimiter (`Bearer a… Bearer b…`) must both be
|
|
76
89
|
// redacted. A consuming trailing delimiter would eat the separator the
|
|
77
90
|
// next match needs for its leading anchor, leaking the second token.
|
|
78
|
-
regex: /(?:^|[^A-Za-z0-9_.~+/-])Bearer\s+[A-Za-z0-9._~+/-]{12,512}=*(?=$|[^A-Za-z0-9_.~+/-])/g
|
|
91
|
+
regex: /(?:^|[^A-Za-z0-9_.~+/-])Bearer\s+[A-Za-z0-9._~+/-]{12,512}=*(?=$|[^A-Za-z0-9_.~+/-])/g,
|
|
92
|
+
anchor: "Bearer"
|
|
79
93
|
},
|
|
80
94
|
{
|
|
81
95
|
type: "high_entropy_env",
|
|
@@ -91,7 +105,89 @@ var PATTERNS = [
|
|
|
91
105
|
// replacement so the separator between adjacent secrets is preserved
|
|
92
106
|
// rather than collapsed. Capture groups are therefore: 1=leading
|
|
93
107
|
// delimiter, 2=key name, 3=value.
|
|
94
|
-
regex: /(^|\s)([A-Z_]{4,}(?:KEY|TOKEN|SECRET|PASSWORD|PWD))\s*[:=]\s*['"]?([A-Za-z0-9_/+=-]{20,512})['"]?(?=\s|$)/g
|
|
108
|
+
regex: /(^|\s)([A-Z_]{4,}(?:KEY|TOKEN|SECRET|PASSWORD|PWD))\s*[:=]\s*['"]?([A-Za-z0-9_/+=-]{20,512})['"]?(?=\s|$)/g,
|
|
109
|
+
anchor: ["KEY", "TOKEN", "SECRET", "PASSWORD", "PWD"]
|
|
110
|
+
},
|
|
111
|
+
// ── Ported from packages/plugins credential-patterns.ts (WS-034) ─────────
|
|
112
|
+
// The plugin runtime carried 37 patterns while this scrubber — the one that
|
|
113
|
+
// guards session JSONL, chronicle, HQ broadcast, WebUI events and the auth
|
|
114
|
+
// audit — carried 22. The plugin side already had a parity test; it just did
|
|
115
|
+
// not cover core. Most consequential: WrongStack mints `gho_` tokens itself
|
|
116
|
+
// in the Copilot OAuth flow, and `gh[ousr]_` was absent here.
|
|
117
|
+
{
|
|
118
|
+
type: "github_oauth_token",
|
|
119
|
+
regex: /(?<![A-Za-z0-9])gh[ousr]_[A-Za-z0-9]{36,}(?![A-Za-z0-9])/g,
|
|
120
|
+
anchor: ["gho_", "ghu_", "ghs_", "ghr_"]
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
type: "gitlab_pat",
|
|
124
|
+
regex: /(?<![A-Za-z0-9])glpat-[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g,
|
|
125
|
+
anchor: "glpat-"
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
type: "gitlab_runner_token",
|
|
129
|
+
regex: /(?<![A-Za-z0-9])glrt-[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g,
|
|
130
|
+
anchor: "glrt-"
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
type: "npm_token",
|
|
134
|
+
regex: /(?<![A-Za-z0-9])npm_[A-Za-z0-9]{36}(?![A-Za-z0-9])/g,
|
|
135
|
+
anchor: "npm_"
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
type: "slack_app_token",
|
|
139
|
+
regex: /(?<![A-Za-z0-9-])xapp-\d-[A-Za-z0-9-]{10,}(?![A-Za-z0-9-])/g,
|
|
140
|
+
anchor: "xapp-"
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
type: "slack_webhook",
|
|
144
|
+
regex: /https:\/\/hooks\.slack\.com\/services\/T[A-Za-z0-9_-]+\/B[A-Za-z0-9_-]+\/[A-Za-z0-9]{16,}/g,
|
|
145
|
+
anchor: "hooks.slack.com"
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
type: "sendgrid_key",
|
|
149
|
+
regex: /(?<![A-Za-z0-9])SG\.[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g,
|
|
150
|
+
anchor: "SG."
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
type: "digitalocean_token",
|
|
154
|
+
regex: /(?<![A-Za-z0-9])dop_v1_[a-f0-9]{64}(?![A-Za-z0-9])/g,
|
|
155
|
+
anchor: "dop_v1_"
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
type: "doppler_token",
|
|
159
|
+
regex: /(?<![A-Za-z0-9])dp\.(?:pt|st|sa|scim|audit)\.[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g,
|
|
160
|
+
anchor: "dp."
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
type: "shopify_token",
|
|
164
|
+
regex: /(?<![A-Za-z0-9])shp(?:at|ca|pa|ss)_[a-fA-F0-9]{32}(?![A-Za-z0-9])/g,
|
|
165
|
+
anchor: "shp"
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
type: "docker_pat",
|
|
169
|
+
regex: /(?<![A-Za-z0-9])dckr_pat_[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g,
|
|
170
|
+
anchor: "dckr_pat_"
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
type: "linear_key",
|
|
174
|
+
regex: /(?<![A-Za-z0-9])lin_api_[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g,
|
|
175
|
+
anchor: "lin_api_"
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
type: "atlassian_token",
|
|
179
|
+
regex: /(?<![A-Za-z0-9])ATATT3[A-Za-z0-9_\-=]{40,}(?![A-Za-z0-9_\-=])/g,
|
|
180
|
+
anchor: "ATATT3"
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
type: "square_token",
|
|
184
|
+
regex: /(?<![A-Za-z0-9])(?:sq0(?:atp|csp)-|EAAA)[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g,
|
|
185
|
+
anchor: ["sq0atp-", "sq0csp-", "EAAA"]
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
type: "google_oauth_client_secret",
|
|
189
|
+
regex: /(?<![A-Za-z0-9_-])GOCSPX-[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g,
|
|
190
|
+
anchor: "GOCSPX-"
|
|
95
191
|
}
|
|
96
192
|
];
|
|
97
193
|
var SIMPLE_PATTERNS = PATTERNS.filter((p) => p.type !== "high_entropy_env");
|
|
@@ -100,32 +196,32 @@ var HIGH_ENTROPY_REGEX = PATTERNS.find((p) => p.type === "high_entropy_env").reg
|
|
|
100
196
|
var COMBINED_REPLACEMENTS = SIMPLE_PATTERNS.map((p) => `[REDACTED:${p.type}]`);
|
|
101
197
|
var SCRUB_CHUNK_BYTES = 64 * 1024;
|
|
102
198
|
var SCRUB_OVERLAP_BYTES = 1024;
|
|
199
|
+
var PATTERN_ANCHORS = [
|
|
200
|
+
...new Set(
|
|
201
|
+
PATTERNS.flatMap(
|
|
202
|
+
(pattern) => typeof pattern.anchor === "string" ? [pattern.anchor] : [...pattern.anchor]
|
|
203
|
+
)
|
|
204
|
+
)
|
|
205
|
+
];
|
|
206
|
+
var JSON_KEY_ANCHORS = [
|
|
207
|
+
'"apiKey"',
|
|
208
|
+
'"api_key"',
|
|
209
|
+
'"token"',
|
|
210
|
+
'"secret"',
|
|
211
|
+
'"password"',
|
|
212
|
+
'"authorization"',
|
|
213
|
+
'"bearer"',
|
|
214
|
+
'"private_key"',
|
|
215
|
+
'"access_token"',
|
|
216
|
+
'"refresh_token"',
|
|
217
|
+
'"client_secret"'
|
|
218
|
+
];
|
|
219
|
+
var ALL_ANCHORS = [...PATTERN_ANCHORS, ...JSON_KEY_ANCHORS];
|
|
103
220
|
function hasCredentialAnchors(text) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
text.includes("github_pat_") || // GitHub PAT v2
|
|
109
|
-
text.includes("eyJ") || // JWT
|
|
110
|
-
text.includes("AKIA") || // AWS access key
|
|
111
|
-
text.includes("AIza") || // GCP service key
|
|
112
|
-
text.includes("xox") || // Slack token (xoxa/xoxb/xoxp/xoxo/xoxs)
|
|
113
|
-
text.includes("Bearer ") || // Bearer token (space suffix reduces false positives)
|
|
114
|
-
text.includes("/bot") || // Telegram bot token (URL path pattern)
|
|
115
|
-
text.includes("hf_") || // HuggingFace token
|
|
116
|
-
text.includes("r8_") || // Replicate token
|
|
117
|
-
text.includes("pplx-") || // Perplexity API key
|
|
118
|
-
text.includes("gsk_") || // Groq API key
|
|
119
|
-
text.includes("_KEY=") || // High-entropy env vars: API_KEY=, SECRET_KEY=, ...
|
|
120
|
-
text.includes("_TOKEN=") || // ACCESS_TOKEN=, AUTH_TOKEN=, ...
|
|
121
|
-
text.includes("_SECRET=") || // API_SECRET=, CLIENT_SECRET=, ...
|
|
122
|
-
text.includes("_PASSWORD=") || // DB_PASSWORD=, ROOT_PASSWORD=, ...
|
|
123
|
-
text.includes("mongodb://") || text.includes("mongodb+srv://") || text.includes("postgres://") || text.includes("postgresql://") || text.includes("mysql://") || text.includes("redis://") || // JSON-style credential keys: tool outputs often serialise objects as
|
|
124
|
-
// raw JSON strings rather than parsed objects. The value may not start
|
|
125
|
-
// with a recognisable prefix (sk-, ghp_, etc.), so we anchor on common
|
|
126
|
-
// key names. The `"` prefix avoids matching prose that happens to mention
|
|
127
|
-
// these words — JSON serialisation always quotes string keys.
|
|
128
|
-
text.includes('"apiKey"') || text.includes('"api_key"') || text.includes('"token"') || text.includes('"secret"') || text.includes('"password"') || text.includes('"authorization"') || text.includes('"bearer"') || text.includes('"private_key"') || text.includes('"access_token"') || text.includes('"refresh_token"') || text.includes('"client_secret"');
|
|
221
|
+
for (const anchor of ALL_ANCHORS) {
|
|
222
|
+
if (text.includes(anchor)) return true;
|
|
223
|
+
}
|
|
224
|
+
return false;
|
|
129
225
|
}
|
|
130
226
|
var DefaultSecretScrubber = class {
|
|
131
227
|
scrub(text) {
|
|
@@ -388,6 +484,11 @@ var SECRET_NAME_PARTS = [
|
|
|
388
484
|
"SECRET",
|
|
389
485
|
"PASSWORD",
|
|
390
486
|
"PASSWD",
|
|
487
|
+
// WRONGSTACK_VAULT_PASSPHRASE is the vault KEK. Without this entry it matched
|
|
488
|
+
// no rule here and fell through to the `WRONGSTACK_` prefix allow-rule, so the
|
|
489
|
+
// key that protects the credential vault was forwarded to every child process
|
|
490
|
+
// — including the agent's own exec/bash tools and MCP stdio servers (WS-033).
|
|
491
|
+
"PASSPHRASE",
|
|
391
492
|
"AUTH",
|
|
392
493
|
"CRED",
|
|
393
494
|
"BEARER",
|
|
@@ -558,6 +659,65 @@ async function backupConfigFile(filePath, paths) {
|
|
|
558
659
|
}
|
|
559
660
|
}
|
|
560
661
|
|
|
662
|
+
// src/utils/deep-merge.ts
|
|
663
|
+
var FORBIDDEN_PROTO_KEYS = /* @__PURE__ */ new Set([
|
|
664
|
+
"__proto__",
|
|
665
|
+
"constructor",
|
|
666
|
+
"prototype",
|
|
667
|
+
"__defineGetter__",
|
|
668
|
+
"__defineSetter__",
|
|
669
|
+
"__lookupGetter__",
|
|
670
|
+
"__lookupSetter__"
|
|
671
|
+
]);
|
|
672
|
+
function isPrimitiveArray(a) {
|
|
673
|
+
return a.every((v) => v === null || typeof v !== "object" && typeof v !== "function");
|
|
674
|
+
}
|
|
675
|
+
function deepMerge(base, patch, options = {}) {
|
|
676
|
+
const {
|
|
677
|
+
conflictResolution = "prefer-patch",
|
|
678
|
+
arrayMode = "replace",
|
|
679
|
+
protectProto = true,
|
|
680
|
+
onNonPrimitiveArrayReplace
|
|
681
|
+
} = options;
|
|
682
|
+
if (typeof base !== "object" || base === null) {
|
|
683
|
+
return conflictResolution === "prefer-patch" ? patch : base;
|
|
684
|
+
}
|
|
685
|
+
if (typeof patch !== "object" || patch === null) {
|
|
686
|
+
return conflictResolution === "prefer-patch" ? patch : base;
|
|
687
|
+
}
|
|
688
|
+
if (Array.isArray(base) && Array.isArray(patch)) {
|
|
689
|
+
if (arrayMode === "concat-primitives" && isPrimitiveArray(base) && isPrimitiveArray(patch)) {
|
|
690
|
+
return [.../* @__PURE__ */ new Set([...base, ...patch])];
|
|
691
|
+
}
|
|
692
|
+
return conflictResolution === "prefer-patch" ? patch : base;
|
|
693
|
+
}
|
|
694
|
+
if (Array.isArray(base) || Array.isArray(patch)) {
|
|
695
|
+
return conflictResolution === "prefer-patch" ? patch : base;
|
|
696
|
+
}
|
|
697
|
+
const baseObj = base;
|
|
698
|
+
const patchObj = patch;
|
|
699
|
+
const out = { ...baseObj };
|
|
700
|
+
for (const [k, v] of Object.entries(patchObj)) {
|
|
701
|
+
if (protectProto && FORBIDDEN_PROTO_KEYS.has(k)) continue;
|
|
702
|
+
const existing = out[k];
|
|
703
|
+
if (v !== null && typeof v === "object" && !Array.isArray(v) && existing !== null && typeof existing === "object" && !Array.isArray(existing)) {
|
|
704
|
+
out[k] = deepMerge(existing, v, options);
|
|
705
|
+
} else if (Array.isArray(v) && Array.isArray(existing)) {
|
|
706
|
+
if (onNonPrimitiveArrayReplace && !isPrimitiveArray(v)) {
|
|
707
|
+
onNonPrimitiveArrayReplace(k, existing.length, v.length);
|
|
708
|
+
}
|
|
709
|
+
out[k] = deepMerge(existing, v, options);
|
|
710
|
+
} else if (v !== void 0) {
|
|
711
|
+
if (onNonPrimitiveArrayReplace && Array.isArray(v) && !isPrimitiveArray(v)) {
|
|
712
|
+
const existingLen = Array.isArray(existing) ? existing.length : 0;
|
|
713
|
+
onNonPrimitiveArrayReplace(k, existingLen, v.length);
|
|
714
|
+
}
|
|
715
|
+
out[k] = v;
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
return out;
|
|
719
|
+
}
|
|
720
|
+
|
|
561
721
|
// src/utils/expect-defined.ts
|
|
562
722
|
function expectDefined(value, label) {
|
|
563
723
|
if (value === null || value === void 0) {
|
|
@@ -677,68 +837,137 @@ function isEmptyMessage(msg) {
|
|
|
677
837
|
// src/types/config/runtime.ts
|
|
678
838
|
var DEFAULT_TUI_THINKING_WORD = "thinking";
|
|
679
839
|
|
|
680
|
-
// src/utils/
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
"
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
}
|
|
700
|
-
|
|
701
|
-
return conflictResolution === "prefer-patch" ? patch : base;
|
|
702
|
-
}
|
|
703
|
-
if (typeof patch !== "object" || patch === null) {
|
|
704
|
-
return conflictResolution === "prefer-patch" ? patch : base;
|
|
705
|
-
}
|
|
706
|
-
if (Array.isArray(base) && Array.isArray(patch)) {
|
|
707
|
-
if (arrayMode === "concat-primitives" && isPrimitiveArray(base) && isPrimitiveArray(patch)) {
|
|
708
|
-
return [.../* @__PURE__ */ new Set([...base, ...patch])];
|
|
709
|
-
}
|
|
710
|
-
return conflictResolution === "prefer-patch" ? patch : base;
|
|
711
|
-
}
|
|
712
|
-
if (Array.isArray(base) || Array.isArray(patch)) {
|
|
713
|
-
return conflictResolution === "prefer-patch" ? patch : base;
|
|
840
|
+
// src/utils/wstack-paths.ts
|
|
841
|
+
import { createHash } from "node:crypto";
|
|
842
|
+
import * as fs2 from "node:fs";
|
|
843
|
+
import * as os from "node:os";
|
|
844
|
+
import * as path2 from "node:path";
|
|
845
|
+
function canonicalProjectRoot(absRoot) {
|
|
846
|
+
const checkoutRoot = path2.resolve(absRoot);
|
|
847
|
+
const dotGit = path2.join(checkoutRoot, ".git");
|
|
848
|
+
try {
|
|
849
|
+
if (!fs2.statSync(dotGit).isFile()) return checkoutRoot;
|
|
850
|
+
const gitDirLine = fs2.readFileSync(dotGit, "utf8").trim();
|
|
851
|
+
const match = /^gitdir:\s*(.+)$/i.exec(gitDirLine);
|
|
852
|
+
if (!match?.[1]) return checkoutRoot;
|
|
853
|
+
const gitDir = path2.resolve(checkoutRoot, match[1].trim());
|
|
854
|
+
const commonDirFile = path2.join(gitDir, "commondir");
|
|
855
|
+
if (!fs2.statSync(commonDirFile).isFile()) return checkoutRoot;
|
|
856
|
+
const commonDir = path2.resolve(gitDir, fs2.readFileSync(commonDirFile, "utf8").trim());
|
|
857
|
+
if (path2.basename(commonDir).toLowerCase() !== ".git") return checkoutRoot;
|
|
858
|
+
return path2.dirname(commonDir);
|
|
859
|
+
} catch {
|
|
860
|
+
return checkoutRoot;
|
|
714
861
|
}
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
862
|
+
}
|
|
863
|
+
function projectHash(absRoot) {
|
|
864
|
+
return createHash("sha256").update(canonicalProjectRoot(absRoot)).digest("hex").slice(0, 12);
|
|
865
|
+
}
|
|
866
|
+
function projectSlug(absRoot) {
|
|
867
|
+
const identityRoot = canonicalProjectRoot(absRoot);
|
|
868
|
+
const base = slugify(path2.basename(identityRoot));
|
|
869
|
+
const hash = createHash("sha256").update(identityRoot).digest("hex").slice(0, 6);
|
|
870
|
+
return `${base}-${hash}`;
|
|
871
|
+
}
|
|
872
|
+
function slugify(name) {
|
|
873
|
+
return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40) || "project";
|
|
874
|
+
}
|
|
875
|
+
function safeProfileName(name) {
|
|
876
|
+
const safe = (name ?? "").replace(/[/\\:]/g, "_").replace(/\.\./g, "_").trim();
|
|
877
|
+
return safe || "default";
|
|
878
|
+
}
|
|
879
|
+
function activeProfileName(globalRoot) {
|
|
880
|
+
try {
|
|
881
|
+
const parsed = JSON.parse(fs2.readFileSync(path2.join(globalRoot, "config.json"), "utf8"));
|
|
882
|
+
return safeProfileName(typeof parsed.activeProfile === "string" ? parsed.activeProfile : void 0);
|
|
883
|
+
} catch {
|
|
884
|
+
return "default";
|
|
735
885
|
}
|
|
736
|
-
|
|
886
|
+
}
|
|
887
|
+
function wstackGlobalRoot() {
|
|
888
|
+
const fromEnv = process.env["WRONGSTACK_HOME"];
|
|
889
|
+
if (fromEnv && fromEnv.trim().length > 0) return path2.resolve(fromEnv);
|
|
890
|
+
return path2.join(os.homedir(), ".wrongstack");
|
|
891
|
+
}
|
|
892
|
+
function resolveWstackPaths(opts) {
|
|
893
|
+
const globalRoot = opts.globalRoot ?? (opts.userHome ? path2.join(opts.userHome, ".wrongstack") : wstackGlobalRoot());
|
|
894
|
+
const homeDir = opts.userHome ?? os.homedir();
|
|
895
|
+
const profileName = safeProfileName(opts.profileName ?? activeProfileName(globalRoot));
|
|
896
|
+
const profileDir = path2.join(globalRoot, "profiles", profileName);
|
|
897
|
+
const hash = projectHash(opts.projectRoot);
|
|
898
|
+
const slug = projectSlug(opts.projectRoot);
|
|
899
|
+
const projectDir = path2.join(globalRoot, "projects", slug);
|
|
900
|
+
return {
|
|
901
|
+
globalRoot,
|
|
902
|
+
profileName,
|
|
903
|
+
profileDir,
|
|
904
|
+
projectRoot: opts.projectRoot,
|
|
905
|
+
homeDir,
|
|
906
|
+
configDir: profileDir,
|
|
907
|
+
globalConfig: path2.join(globalRoot, "config.json"),
|
|
908
|
+
profilesDir: path2.join(globalRoot, "profiles"),
|
|
909
|
+
profileConfig: (name) => {
|
|
910
|
+
return path2.join(globalRoot, "profiles", safeProfileName(name), "config.json");
|
|
911
|
+
},
|
|
912
|
+
profileStatuslineConfig: (name) => {
|
|
913
|
+
return path2.join(globalRoot, "profiles", safeProfileName(name), "statusline.json");
|
|
914
|
+
},
|
|
915
|
+
profileModeConfig: (name) => {
|
|
916
|
+
return path2.join(globalRoot, "profiles", safeProfileName(name), "mode.json");
|
|
917
|
+
},
|
|
918
|
+
profileProviderStatus: (name) => {
|
|
919
|
+
return path2.join(globalRoot, "profiles", safeProfileName(name), "provider-status.json");
|
|
920
|
+
},
|
|
921
|
+
profileUpdateCache: (name) => {
|
|
922
|
+
return path2.join(globalRoot, "profiles", safeProfileName(name), "update-cache.json");
|
|
923
|
+
},
|
|
924
|
+
secretsKey: path2.join(globalRoot, ".key"),
|
|
925
|
+
globalMemory: path2.join(profileDir, "memory.md"),
|
|
926
|
+
globalSkills: path2.join(profileDir, "skills"),
|
|
927
|
+
globalClaudeSkills: path2.join(homeDir, ".claude", "skills"),
|
|
928
|
+
globalDesignKits: path2.join(profileDir, "design-kits"),
|
|
929
|
+
globalPrompts: path2.join(profileDir, "prompts"),
|
|
930
|
+
globalInstructions: path2.join(profileDir, "instructions"),
|
|
931
|
+
promptUsage: path2.join(profileDir, "prompt-usage.json"),
|
|
932
|
+
cacheDir: path2.join(globalRoot, "cache"),
|
|
933
|
+
modelsCache: path2.join(globalRoot, "cache", "models.dev.json"),
|
|
934
|
+
modelsOverlayCache: path2.join(globalRoot, "cache", "models-overlay.json"),
|
|
935
|
+
historyFile: path2.join(profileDir, "history"),
|
|
936
|
+
logFile: path2.join(globalRoot, "logs", "wrongstack.log"),
|
|
937
|
+
projectDir,
|
|
938
|
+
projectCodebaseIndex: path2.join(projectDir, "codebase-index"),
|
|
939
|
+
projectMemory: path2.join(projectDir, "memory.md"),
|
|
940
|
+
projectSessions: path2.join(projectDir, "sessions"),
|
|
941
|
+
projectTrust: path2.join(projectDir, "trust.json"),
|
|
942
|
+
projectMeta: path2.join(projectDir, "meta.json"),
|
|
943
|
+
projectLocalConfig: path2.join(projectDir, "config.local.json"),
|
|
944
|
+
inProjectConfig: path2.join(opts.projectRoot, ".wrongstack", "config.json"),
|
|
945
|
+
inProjectAgentsFile: path2.join(opts.projectRoot, ".wrongstack", "AGENTS.md"),
|
|
946
|
+
inProjectSkills: path2.join(opts.projectRoot, ".wrongstack", "skills"),
|
|
947
|
+
inProjectClaudeSkills: path2.join(opts.projectRoot, ".claude", "skills"),
|
|
948
|
+
inProjectPrompts: path2.join(opts.projectRoot, ".wrongstack", "prompts"),
|
|
949
|
+
inProjectInstructions: path2.join(opts.projectRoot, ".wrongstack", "instructions"),
|
|
950
|
+
inProjectDesignKits: path2.join(opts.projectRoot, ".wrongstack", "design-kits"),
|
|
951
|
+
inProjectWorktrees: path2.join(opts.projectRoot, ".wrongstack", "worktrees"),
|
|
952
|
+
projectHash: hash,
|
|
953
|
+
projectSlug: slug,
|
|
954
|
+
projectGoal: path2.join(projectDir, "goal.json"),
|
|
955
|
+
projectInputHistory: path2.join(projectDir, "input-history.json"),
|
|
956
|
+
projectSpecs: path2.join(projectDir, "specs"),
|
|
957
|
+
projectTaskGraphs: path2.join(projectDir, "task-graphs"),
|
|
958
|
+
projectSddSession: path2.join(projectDir, "sdd-session.json"),
|
|
959
|
+
projectPlan: path2.join(projectDir, "plan.json"),
|
|
960
|
+
projectAutophase: path2.join(projectDir, "autophase"),
|
|
961
|
+
projectSddBoards: path2.join(projectDir, "sdd-boards"),
|
|
962
|
+
syncConfig: path2.join(profileDir, "sync.json"),
|
|
963
|
+
configHistoryDir: path2.join(globalRoot, "config-history"),
|
|
964
|
+
projectStatus: (projectHash2) => path2.join(globalRoot, "projects", projectHash2, "status.json")
|
|
965
|
+
};
|
|
737
966
|
}
|
|
738
967
|
|
|
739
968
|
// src/utils/instruction-file.ts
|
|
740
|
-
import { readFileSync, statSync } from "node:fs";
|
|
741
|
-
import * as
|
|
969
|
+
import { readFileSync as readFileSync2, statSync as statSync2 } from "node:fs";
|
|
970
|
+
import * as path3 from "node:path";
|
|
742
971
|
import { fileURLToPath } from "node:url";
|
|
743
972
|
var textCache = /* @__PURE__ */ new Map();
|
|
744
973
|
var rootCandidates;
|
|
@@ -748,7 +977,7 @@ function readBundledInstructionText(relativePath) {
|
|
|
748
977
|
let resolved = "";
|
|
749
978
|
for (const root of instructionRootCandidates()) {
|
|
750
979
|
try {
|
|
751
|
-
resolved =
|
|
980
|
+
resolved = readFileSync2(path3.join(root, relativePath), "utf8").trimEnd();
|
|
752
981
|
break;
|
|
753
982
|
} catch {
|
|
754
983
|
}
|
|
@@ -764,18 +993,18 @@ function renderInstructionTemplate(template, values) {
|
|
|
764
993
|
}
|
|
765
994
|
function instructionRootCandidates() {
|
|
766
995
|
if (rootCandidates !== void 0) return rootCandidates;
|
|
767
|
-
const here =
|
|
996
|
+
const here = path3.dirname(fileURLToPath(import.meta.url));
|
|
768
997
|
const candidates = [
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
998
|
+
path3.resolve(here, "../../instructions"),
|
|
999
|
+
path3.resolve(here, "../instructions"),
|
|
1000
|
+
path3.resolve(here, "instructions")
|
|
772
1001
|
];
|
|
773
1002
|
rootCandidates = candidates.sort((a, b) => Number(!isDirectory(a)) - Number(!isDirectory(b)));
|
|
774
1003
|
return rootCandidates;
|
|
775
1004
|
}
|
|
776
1005
|
function isDirectory(candidate) {
|
|
777
1006
|
try {
|
|
778
|
-
return
|
|
1007
|
+
return statSync2(candidate).isDirectory();
|
|
779
1008
|
} catch {
|
|
780
1009
|
return false;
|
|
781
1010
|
}
|
|
@@ -875,14 +1104,14 @@ function safeParse(input, maxBytes = 5e6) {
|
|
|
875
1104
|
}
|
|
876
1105
|
|
|
877
1106
|
// src/utils/session-scoped-path.ts
|
|
878
|
-
import * as
|
|
1107
|
+
import * as path4 from "node:path";
|
|
879
1108
|
function sessionScopedPath(dir, sessionId, suffix) {
|
|
880
1109
|
if (!sessionId || sessionId.includes("\\") || sessionId.includes("..")) {
|
|
881
1110
|
throw invalid(sessionId);
|
|
882
1111
|
}
|
|
883
|
-
const resolved =
|
|
884
|
-
const rel =
|
|
885
|
-
if (rel.startsWith("..") ||
|
|
1112
|
+
const resolved = path4.resolve(dir, `${sessionId}${suffix}`);
|
|
1113
|
+
const rel = path4.relative(path4.resolve(dir), resolved);
|
|
1114
|
+
if (rel.startsWith("..") || path4.isAbsolute(rel)) {
|
|
886
1115
|
throw invalid(sessionId);
|
|
887
1116
|
}
|
|
888
1117
|
return resolved;
|
|
@@ -897,144 +1126,33 @@ function invalid(sessionId) {
|
|
|
897
1126
|
}
|
|
898
1127
|
|
|
899
1128
|
// src/utils/slug.ts
|
|
900
|
-
function
|
|
1129
|
+
function slugify2(name, fallback = "prompt", maxLen = 64) {
|
|
901
1130
|
return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, maxLen).replace(/-+$/g, "") || fallback;
|
|
902
1131
|
}
|
|
903
1132
|
|
|
904
|
-
// src/
|
|
905
|
-
import {
|
|
906
|
-
import * as
|
|
907
|
-
import * as
|
|
908
|
-
import
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
const gitDirLine = fs2.readFileSync(dotGit, "utf8").trim();
|
|
915
|
-
const match = /^gitdir:\s*(.+)$/i.exec(gitDirLine);
|
|
916
|
-
if (!match?.[1]) return checkoutRoot;
|
|
917
|
-
const gitDir = path4.resolve(checkoutRoot, match[1].trim());
|
|
918
|
-
const commonDirFile = path4.join(gitDir, "commondir");
|
|
919
|
-
if (!fs2.statSync(commonDirFile).isFile()) return checkoutRoot;
|
|
920
|
-
const commonDir = path4.resolve(gitDir, fs2.readFileSync(commonDirFile, "utf8").trim());
|
|
921
|
-
if (path4.basename(commonDir).toLowerCase() !== ".git") return checkoutRoot;
|
|
922
|
-
return path4.dirname(commonDir);
|
|
923
|
-
} catch {
|
|
924
|
-
return checkoutRoot;
|
|
1133
|
+
// src/storage/file-session-writer.ts
|
|
1134
|
+
import { closeSync, createReadStream, fsyncSync, openSync, writeSync } from "node:fs";
|
|
1135
|
+
import * as fsp2 from "node:fs/promises";
|
|
1136
|
+
import * as path5 from "node:path";
|
|
1137
|
+
import { createInterface } from "node:readline";
|
|
1138
|
+
|
|
1139
|
+
// src/storage/session-workspace-checkpoints.ts
|
|
1140
|
+
function requiredCheckpointCas(checkpointCas, operation) {
|
|
1141
|
+
if (!checkpointCas) {
|
|
1142
|
+
throw new Error(`Workspace checkpoint ${operation} requires a projectRoot-aware session store`);
|
|
925
1143
|
}
|
|
1144
|
+
return checkpointCas;
|
|
926
1145
|
}
|
|
927
|
-
function
|
|
928
|
-
return
|
|
929
|
-
}
|
|
930
|
-
function projectSlug(absRoot) {
|
|
931
|
-
const identityRoot = canonicalProjectRoot(absRoot);
|
|
932
|
-
const base = slugify2(path4.basename(identityRoot));
|
|
933
|
-
const hash = createHash("sha256").update(identityRoot).digest("hex").slice(0, 6);
|
|
934
|
-
return `${base}-${hash}`;
|
|
935
|
-
}
|
|
936
|
-
function slugify2(name) {
|
|
937
|
-
return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40) || "project";
|
|
1146
|
+
function captureCheckpoint(checkpointCas, sessionId, promptIndex) {
|
|
1147
|
+
return requiredCheckpointCas(checkpointCas, "capture").capture(sessionId, promptIndex);
|
|
938
1148
|
}
|
|
939
|
-
function
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
try {
|
|
945
|
-
const parsed = JSON.parse(fs2.readFileSync(path4.join(globalRoot, "config.json"), "utf8"));
|
|
946
|
-
return safeProfileName(typeof parsed.activeProfile === "string" ? parsed.activeProfile : void 0);
|
|
947
|
-
} catch {
|
|
948
|
-
return "default";
|
|
949
|
-
}
|
|
950
|
-
}
|
|
951
|
-
function wstackGlobalRoot() {
|
|
952
|
-
const fromEnv = process.env["WRONGSTACK_HOME"];
|
|
953
|
-
if (fromEnv && fromEnv.trim().length > 0) return path4.resolve(fromEnv);
|
|
954
|
-
return path4.join(os.homedir(), ".wrongstack");
|
|
955
|
-
}
|
|
956
|
-
function resolveWstackPaths(opts) {
|
|
957
|
-
const globalRoot = opts.globalRoot ?? (opts.userHome ? path4.join(opts.userHome, ".wrongstack") : wstackGlobalRoot());
|
|
958
|
-
const homeDir = opts.userHome ?? os.homedir();
|
|
959
|
-
const profileName = safeProfileName(opts.profileName ?? activeProfileName(globalRoot));
|
|
960
|
-
const profileDir = path4.join(globalRoot, "profiles", profileName);
|
|
961
|
-
const hash = projectHash(opts.projectRoot);
|
|
962
|
-
const slug = projectSlug(opts.projectRoot);
|
|
963
|
-
const projectDir = path4.join(globalRoot, "projects", slug);
|
|
964
|
-
return {
|
|
965
|
-
globalRoot,
|
|
966
|
-
profileName,
|
|
967
|
-
profileDir,
|
|
968
|
-
projectRoot: opts.projectRoot,
|
|
969
|
-
homeDir,
|
|
970
|
-
configDir: profileDir,
|
|
971
|
-
globalConfig: path4.join(globalRoot, "config.json"),
|
|
972
|
-
profilesDir: path4.join(globalRoot, "profiles"),
|
|
973
|
-
profileConfig: (name) => {
|
|
974
|
-
return path4.join(globalRoot, "profiles", safeProfileName(name), "config.json");
|
|
975
|
-
},
|
|
976
|
-
profileStatuslineConfig: (name) => {
|
|
977
|
-
return path4.join(globalRoot, "profiles", safeProfileName(name), "statusline.json");
|
|
978
|
-
},
|
|
979
|
-
profileModeConfig: (name) => {
|
|
980
|
-
return path4.join(globalRoot, "profiles", safeProfileName(name), "mode.json");
|
|
981
|
-
},
|
|
982
|
-
profileProviderStatus: (name) => {
|
|
983
|
-
return path4.join(globalRoot, "profiles", safeProfileName(name), "provider-status.json");
|
|
984
|
-
},
|
|
985
|
-
profileUpdateCache: (name) => {
|
|
986
|
-
return path4.join(globalRoot, "profiles", safeProfileName(name), "update-cache.json");
|
|
987
|
-
},
|
|
988
|
-
secretsKey: path4.join(globalRoot, ".key"),
|
|
989
|
-
globalMemory: path4.join(profileDir, "memory.md"),
|
|
990
|
-
globalSkills: path4.join(profileDir, "skills"),
|
|
991
|
-
globalClaudeSkills: path4.join(homeDir, ".claude", "skills"),
|
|
992
|
-
globalDesignKits: path4.join(profileDir, "design-kits"),
|
|
993
|
-
globalPrompts: path4.join(profileDir, "prompts"),
|
|
994
|
-
globalInstructions: path4.join(profileDir, "instructions"),
|
|
995
|
-
promptUsage: path4.join(profileDir, "prompt-usage.json"),
|
|
996
|
-
cacheDir: path4.join(globalRoot, "cache"),
|
|
997
|
-
modelsCache: path4.join(globalRoot, "cache", "models.dev.json"),
|
|
998
|
-
modelsOverlayCache: path4.join(globalRoot, "cache", "models-overlay.json"),
|
|
999
|
-
historyFile: path4.join(profileDir, "history"),
|
|
1000
|
-
logFile: path4.join(globalRoot, "logs", "wrongstack.log"),
|
|
1001
|
-
projectDir,
|
|
1002
|
-
projectCodebaseIndex: path4.join(projectDir, "codebase-index"),
|
|
1003
|
-
projectMemory: path4.join(projectDir, "memory.md"),
|
|
1004
|
-
projectSessions: path4.join(projectDir, "sessions"),
|
|
1005
|
-
projectTrust: path4.join(projectDir, "trust.json"),
|
|
1006
|
-
projectMeta: path4.join(projectDir, "meta.json"),
|
|
1007
|
-
projectLocalConfig: path4.join(projectDir, "config.local.json"),
|
|
1008
|
-
inProjectConfig: path4.join(opts.projectRoot, ".wrongstack", "config.json"),
|
|
1009
|
-
inProjectAgentsFile: path4.join(opts.projectRoot, ".wrongstack", "AGENTS.md"),
|
|
1010
|
-
inProjectSkills: path4.join(opts.projectRoot, ".wrongstack", "skills"),
|
|
1011
|
-
inProjectClaudeSkills: path4.join(opts.projectRoot, ".claude", "skills"),
|
|
1012
|
-
inProjectPrompts: path4.join(opts.projectRoot, ".wrongstack", "prompts"),
|
|
1013
|
-
inProjectInstructions: path4.join(opts.projectRoot, ".wrongstack", "instructions"),
|
|
1014
|
-
inProjectDesignKits: path4.join(opts.projectRoot, ".wrongstack", "design-kits"),
|
|
1015
|
-
inProjectWorktrees: path4.join(opts.projectRoot, ".wrongstack", "worktrees"),
|
|
1016
|
-
projectHash: hash,
|
|
1017
|
-
projectSlug: slug,
|
|
1018
|
-
projectGoal: path4.join(projectDir, "goal.json"),
|
|
1019
|
-
projectInputHistory: path4.join(projectDir, "input-history.json"),
|
|
1020
|
-
projectSpecs: path4.join(projectDir, "specs"),
|
|
1021
|
-
projectTaskGraphs: path4.join(projectDir, "task-graphs"),
|
|
1022
|
-
projectSddSession: path4.join(projectDir, "sdd-session.json"),
|
|
1023
|
-
projectPlan: path4.join(projectDir, "plan.json"),
|
|
1024
|
-
projectAutophase: path4.join(projectDir, "autophase"),
|
|
1025
|
-
projectSddBoards: path4.join(projectDir, "sdd-boards"),
|
|
1026
|
-
syncConfig: path4.join(profileDir, "sync.json"),
|
|
1027
|
-
configHistoryDir: path4.join(globalRoot, "config-history"),
|
|
1028
|
-
projectStatus: (projectHash2) => path4.join(globalRoot, "projects", projectHash2, "status.json")
|
|
1029
|
-
};
|
|
1149
|
+
function materializeCheckpoint(checkpointCas, checkpoint, targetRoot) {
|
|
1150
|
+
return requiredCheckpointCas(checkpointCas, "materialization").materialize(
|
|
1151
|
+
checkpoint,
|
|
1152
|
+
targetRoot
|
|
1153
|
+
);
|
|
1030
1154
|
}
|
|
1031
1155
|
|
|
1032
|
-
// src/storage/file-session-writer.ts
|
|
1033
|
-
import { closeSync, createReadStream, fsyncSync, openSync, writeSync } from "node:fs";
|
|
1034
|
-
import * as fsp2 from "node:fs/promises";
|
|
1035
|
-
import * as path5 from "node:path";
|
|
1036
|
-
import { createInterface } from "node:readline";
|
|
1037
|
-
|
|
1038
1156
|
// src/storage/session-helpers.ts
|
|
1039
1157
|
function consumeControlString(value, start) {
|
|
1040
1158
|
let index = start;
|
|
@@ -1259,6 +1377,16 @@ function scrubSessionWriterEvent(event, secretScrubber) {
|
|
|
1259
1377
|
if (event.type === "llm_response") {
|
|
1260
1378
|
return { ...event, content: secretScrubber.scrubObject(event.content) };
|
|
1261
1379
|
}
|
|
1380
|
+
if (event.type === "file_snapshot") {
|
|
1381
|
+
return {
|
|
1382
|
+
...event,
|
|
1383
|
+
files: event.files.map((f) => ({
|
|
1384
|
+
...f,
|
|
1385
|
+
before: f.before !== null ? secretScrubber.scrub(f.before) : null,
|
|
1386
|
+
after: f.after !== null ? secretScrubber.scrub(f.after) : null
|
|
1387
|
+
}))
|
|
1388
|
+
};
|
|
1389
|
+
}
|
|
1262
1390
|
return event;
|
|
1263
1391
|
}
|
|
1264
1392
|
|
|
@@ -1275,6 +1403,8 @@ var FileSessionWriter = class _FileSessionWriter {
|
|
|
1275
1403
|
this.filePath = opts.filePath ?? "";
|
|
1276
1404
|
this.secretScrubber = opts.secretScrubber;
|
|
1277
1405
|
this.checkpointCas = opts.checkpointCas;
|
|
1406
|
+
this._onAppend = opts.onAppend;
|
|
1407
|
+
this._onAppendBatch = opts.onAppendBatch;
|
|
1278
1408
|
this.onCloseCb = opts.onClose;
|
|
1279
1409
|
this.resolveNameCb = opts.resolveName;
|
|
1280
1410
|
this.summary = opts.initialSummary ? { ...opts.initialSummary, id } : {
|
|
@@ -1330,12 +1460,44 @@ var FileSessionWriter = class _FileSessionWriter {
|
|
|
1330
1460
|
lastAppendWarnAt = 0;
|
|
1331
1461
|
secretScrubber;
|
|
1332
1462
|
checkpointCas;
|
|
1463
|
+
/** Mutable slot for onAppend callback — constructor opts seed it, setOnAppend replaces it. */
|
|
1464
|
+
_onAppend;
|
|
1465
|
+
/** Implements SessionWriter.onAppend — public getter/setter for direct property access. */
|
|
1466
|
+
get onAppend() {
|
|
1467
|
+
return this._onAppend;
|
|
1468
|
+
}
|
|
1469
|
+
set onAppend(cb) {
|
|
1470
|
+
this._onAppend = cb;
|
|
1471
|
+
}
|
|
1472
|
+
/** Mutable slot for onAppendBatch callback. */
|
|
1473
|
+
_onAppendBatch;
|
|
1474
|
+
/** Implements SessionWriter.onAppendBatch — public getter/setter for direct property access. */
|
|
1475
|
+
get onAppendBatch() {
|
|
1476
|
+
return this._onAppendBatch;
|
|
1477
|
+
}
|
|
1478
|
+
set onAppendBatch(cb) {
|
|
1479
|
+
this._onAppendBatch = cb;
|
|
1480
|
+
}
|
|
1333
1481
|
onCloseCb;
|
|
1334
1482
|
resolveNameCb;
|
|
1335
1483
|
/** Implements SessionWriter.traceId — propagated from ContextInit.traceId. */
|
|
1336
1484
|
traceId;
|
|
1337
1485
|
// ── Write buffer — batches events to reduce per-event disk I/O ──────────────
|
|
1338
1486
|
//
|
|
1487
|
+
/**
|
|
1488
|
+
* Set or replace the onAppend callback. Used by telemetry bridges that
|
|
1489
|
+
* receive the writer as an already-constructed dependency.
|
|
1490
|
+
*/
|
|
1491
|
+
setOnAppend(cb) {
|
|
1492
|
+
this._onAppend = cb;
|
|
1493
|
+
}
|
|
1494
|
+
/**
|
|
1495
|
+
* Set or replace the onAppendBatch callback.
|
|
1496
|
+
*/
|
|
1497
|
+
setOnAppendBatch(cb) {
|
|
1498
|
+
this._onAppendBatch = cb;
|
|
1499
|
+
}
|
|
1500
|
+
//
|
|
1339
1501
|
// Every append() pushes the scrubbed event into an in-memory buffer instead
|
|
1340
1502
|
// of calling handle.appendFile() synchronously. The buffer flushes to disk
|
|
1341
1503
|
// when it reaches FLUSH_SIZE events OR after FLUSH_INTERVAL_MS of inactivity.
|
|
@@ -1442,7 +1604,12 @@ var FileSessionWriter = class _FileSessionWriter {
|
|
|
1442
1604
|
if (this.closed) return;
|
|
1443
1605
|
void this.ensureInit();
|
|
1444
1606
|
this.observeForSummary(event);
|
|
1445
|
-
|
|
1607
|
+
const appendEvent = event.type === "file_snapshot" ? scrubSessionWriterEvent(event, this.secretScrubber) : event;
|
|
1608
|
+
try {
|
|
1609
|
+
this._onAppend?.(appendEvent);
|
|
1610
|
+
} catch {
|
|
1611
|
+
}
|
|
1612
|
+
this.pushWriteBuffer(appendEvent);
|
|
1446
1613
|
if (this.writeBuffer.length >= _FileSessionWriter.FLUSH_SIZE) {
|
|
1447
1614
|
if (this.flushTimer) {
|
|
1448
1615
|
clearTimeout(this.flushTimer);
|
|
@@ -1524,6 +1691,10 @@ var FileSessionWriter = class _FileSessionWriter {
|
|
|
1524
1691
|
await this.ensureInit();
|
|
1525
1692
|
const scrubbed = scrubSessionWriterEvent(event, this.secretScrubber);
|
|
1526
1693
|
this.observeForSummary(scrubbed);
|
|
1694
|
+
try {
|
|
1695
|
+
this._onAppend?.(scrubbed);
|
|
1696
|
+
} catch {
|
|
1697
|
+
}
|
|
1527
1698
|
this.pushWriteBuffer(scrubbed);
|
|
1528
1699
|
if (this.writeBuffer.length >= _FileSessionWriter.FLUSH_SIZE) {
|
|
1529
1700
|
if (this.flushTimer) {
|
|
@@ -1539,11 +1710,22 @@ var FileSessionWriter = class _FileSessionWriter {
|
|
|
1539
1710
|
async appendBatch(events) {
|
|
1540
1711
|
if (this.closed || events.length === 0) return;
|
|
1541
1712
|
await this.ensureInit();
|
|
1713
|
+
const scrubbedBatch = [];
|
|
1542
1714
|
for (const event of events) {
|
|
1543
1715
|
const scrubbed = scrubSessionWriterEvent(event, this.secretScrubber);
|
|
1544
1716
|
this.observeForSummary(scrubbed);
|
|
1717
|
+
try {
|
|
1718
|
+
this._onAppend?.(scrubbed);
|
|
1719
|
+
} catch {
|
|
1720
|
+
}
|
|
1545
1721
|
this.pushWriteBuffer(scrubbed);
|
|
1722
|
+
scrubbedBatch.push(scrubbed);
|
|
1723
|
+
}
|
|
1724
|
+
try {
|
|
1725
|
+
this._onAppendBatch?.(scrubbedBatch);
|
|
1726
|
+
} catch {
|
|
1546
1727
|
}
|
|
1728
|
+
;
|
|
1547
1729
|
if (this.writeBuffer.length >= _FileSessionWriter.FLUSH_SIZE) {
|
|
1548
1730
|
if (this.flushTimer) {
|
|
1549
1731
|
clearTimeout(this.flushTimer);
|
|
@@ -1946,7 +2128,8 @@ var FileSessionWriter = class _FileSessionWriter {
|
|
|
1946
2128
|
promptIndex,
|
|
1947
2129
|
promptPreview,
|
|
1948
2130
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1949
|
-
fileCount
|
|
2131
|
+
fileCount,
|
|
2132
|
+
...workspaceCheckpoint ? { workspaceCheckpoint } : {}
|
|
1950
2133
|
});
|
|
1951
2134
|
}
|
|
1952
2135
|
async writeFileSnapshot(promptIndex, files) {
|
|
@@ -2052,6 +2235,10 @@ var FileSessionWriter = class _FileSessionWriter {
|
|
|
2052
2235
|
this.activePromptIndex = null;
|
|
2053
2236
|
this.pendingFileSnapshots = [];
|
|
2054
2237
|
this.pendingFileSnapshotBytes = 0;
|
|
2238
|
+
this.appendFailCount = 0;
|
|
2239
|
+
this.lastAppendWarnAt = 0;
|
|
2240
|
+
this.bufferOverflowCount = 0;
|
|
2241
|
+
this.lastBufferOverflowWarnAt = 0;
|
|
2055
2242
|
}
|
|
2056
2243
|
/**
|
|
2057
2244
|
* Write an in-flight marker. The agent loop should call
|
|
@@ -2188,8 +2375,8 @@ var SessionCheckpointCas = class {
|
|
|
2188
2375
|
return null;
|
|
2189
2376
|
}
|
|
2190
2377
|
try {
|
|
2191
|
-
const
|
|
2192
|
-
if (
|
|
2378
|
+
const stat15 = await fsp3.lstat(absolute);
|
|
2379
|
+
if (stat15.isSymbolicLink()) {
|
|
2193
2380
|
const linkTarget = await fsp3.readlink(absolute);
|
|
2194
2381
|
const resolvedLink = path6.resolve(path6.dirname(absolute), linkTarget);
|
|
2195
2382
|
if (path6.isAbsolute(linkTarget) || !isInside(this.projectRoot, resolvedLink)) {
|
|
@@ -2201,29 +2388,29 @@ var SessionCheckpointCas = class {
|
|
|
2201
2388
|
}
|
|
2202
2389
|
return { path: relative8, state: "symlink", linkTarget };
|
|
2203
2390
|
}
|
|
2204
|
-
if (!
|
|
2391
|
+
if (!stat15.isFile()) {
|
|
2205
2392
|
unresolved.push({ path: relative8, reason: "changed path is not a regular file" });
|
|
2206
2393
|
return null;
|
|
2207
2394
|
}
|
|
2208
|
-
if (
|
|
2395
|
+
if (stat15.size > MAX_BLOB_BYTES) {
|
|
2209
2396
|
unresolved.push({
|
|
2210
2397
|
path: relative8,
|
|
2211
2398
|
reason: `file exceeds ${MAX_BLOB_BYTES}-byte checkpoint blob limit`
|
|
2212
2399
|
});
|
|
2213
2400
|
return null;
|
|
2214
2401
|
}
|
|
2215
|
-
if (scheduledBytes +
|
|
2402
|
+
if (scheduledBytes + stat15.size > MAX_CHECKPOINT_BYTES) {
|
|
2216
2403
|
unresolved.push({
|
|
2217
2404
|
path: relative8,
|
|
2218
2405
|
reason: `checkpoint exceeds ${MAX_CHECKPOINT_BYTES}-byte aggregate blob limit`
|
|
2219
2406
|
});
|
|
2220
2407
|
return null;
|
|
2221
2408
|
}
|
|
2222
|
-
scheduledBytes +=
|
|
2409
|
+
scheduledBytes += stat15.size;
|
|
2223
2410
|
const content = await fsp3.readFile(absolute);
|
|
2224
2411
|
const blobHash = sha256(content);
|
|
2225
2412
|
await this.putBlob(blobHash, content);
|
|
2226
|
-
return { path: relative8, state: "file", blobHash, mode:
|
|
2413
|
+
return { path: relative8, state: "file", blobHash, mode: stat15.mode & 511 };
|
|
2227
2414
|
} catch (err) {
|
|
2228
2415
|
if (err.code === "ENOENT") {
|
|
2229
2416
|
return { path: relative8, state: "absent" };
|
|
@@ -2612,11 +2799,11 @@ async function validateOne(observation, lexicalRoot, realRoot) {
|
|
|
2612
2799
|
};
|
|
2613
2800
|
}
|
|
2614
2801
|
try {
|
|
2615
|
-
const
|
|
2616
|
-
if (!
|
|
2802
|
+
const stat15 = await fsp4.stat(realFile);
|
|
2803
|
+
if (!stat15.isFile()) {
|
|
2617
2804
|
return { ...base, status: "unreadable", detail: "Path is no longer a regular file." };
|
|
2618
2805
|
}
|
|
2619
|
-
if (
|
|
2806
|
+
if (stat15.size > MAX_REVALIDATE_BYTES) {
|
|
2620
2807
|
return {
|
|
2621
2808
|
...base,
|
|
2622
2809
|
status: "unreadable",
|
|
@@ -2674,57 +2861,82 @@ function formatInterruptedToolNotice(pendingToolUseCount) {
|
|
|
2674
2861
|
].join("\n");
|
|
2675
2862
|
}
|
|
2676
2863
|
|
|
2677
|
-
// src/storage/session-store/
|
|
2864
|
+
// src/storage/session-store/delete-session-artifacts.ts
|
|
2678
2865
|
import * as fsp5 from "node:fs/promises";
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2866
|
+
import * as path10 from "node:path";
|
|
2867
|
+
|
|
2868
|
+
// src/storage/session-store/paths.ts
|
|
2869
|
+
import * as path9 from "node:path";
|
|
2870
|
+
function sessionPath(storeDir, id, ext) {
|
|
2871
|
+
return sessionScopedPath(storeDir, id, ext);
|
|
2872
|
+
}
|
|
2873
|
+
function shardManifestPath(storeDir, shardKey) {
|
|
2874
|
+
return shardKey ? path9.join(storeDir, shardKey, "_manifest.json") : path9.join(storeDir, "_manifest.json");
|
|
2875
|
+
}
|
|
2876
|
+
function shardKeyForSessionId(id) {
|
|
2877
|
+
const dirName = path9.dirname(id);
|
|
2878
|
+
return dirName === "." ? "" : dirName;
|
|
2879
|
+
}
|
|
2880
|
+
async function ensureShardDir(storeDir, id) {
|
|
2881
|
+
const dirPath = path9.dirname(sessionScopedPath(storeDir, id, ""));
|
|
2882
|
+
await ensureDir(dirPath);
|
|
2883
|
+
return dirPath;
|
|
2884
|
+
}
|
|
2885
|
+
|
|
2886
|
+
// src/storage/session-store/delete-session-artifacts.ts
|
|
2887
|
+
async function deleteSessionArtifacts({
|
|
2888
|
+
rootDir,
|
|
2889
|
+
id,
|
|
2890
|
+
jsonlPath
|
|
2891
|
+
}) {
|
|
2892
|
+
const shardDir = path10.dirname(jsonlPath);
|
|
2893
|
+
const base = path10.basename(id);
|
|
2894
|
+
const sessDir = path10.join(shardDir, base);
|
|
2895
|
+
const deletions = [
|
|
2896
|
+
fsp5.unlink(jsonlPath),
|
|
2897
|
+
fsp5.unlink(sessionPath(rootDir, id, ".summary.json")),
|
|
2898
|
+
fsp5.unlink(sessionPath(rootDir, id, ".plan.json")),
|
|
2899
|
+
fsp5.unlink(sessionPath(rootDir, id, ".tasks.json")),
|
|
2900
|
+
fsp5.unlink(sessionPath(rootDir, id, ".todos.json"))
|
|
2901
|
+
];
|
|
2902
|
+
const results = await Promise.allSettled(deletions);
|
|
2903
|
+
for (const result of results) {
|
|
2904
|
+
if (result.status === "rejected") {
|
|
2905
|
+
warnDeleteFailure(id, result.reason);
|
|
2693
2906
|
}
|
|
2694
2907
|
}
|
|
2908
|
+
await fsp5.rm(sessDir, { recursive: true, force: true }).catch((err) => {
|
|
2909
|
+
console.warn(
|
|
2910
|
+
JSON.stringify({
|
|
2911
|
+
level: "warn",
|
|
2912
|
+
event: "session_store.rmdir_failed",
|
|
2913
|
+
sessionId: id,
|
|
2914
|
+
message: toErrorMessage(err),
|
|
2915
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
2916
|
+
})
|
|
2917
|
+
);
|
|
2918
|
+
});
|
|
2695
2919
|
}
|
|
2696
|
-
|
|
2697
|
-
const
|
|
2698
|
-
if (
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
} catch {
|
|
2717
|
-
completeLength = lastNewline + 1;
|
|
2718
|
-
}
|
|
2719
|
-
}
|
|
2720
|
-
return {
|
|
2721
|
-
raw: buffer.subarray(0, completeLength).toString("utf8"),
|
|
2722
|
-
end: start + completeLength
|
|
2723
|
-
};
|
|
2724
|
-
} catch {
|
|
2725
|
-
return null;
|
|
2726
|
-
} finally {
|
|
2727
|
-
await handle?.close().catch(() => void 0);
|
|
2920
|
+
function warnDeleteFailure(id, reason) {
|
|
2921
|
+
const msg = reason instanceof Error ? reason.message : String(reason);
|
|
2922
|
+
if (reason?.code === "ENOENT") return;
|
|
2923
|
+
console.warn(
|
|
2924
|
+
JSON.stringify({
|
|
2925
|
+
level: "warn",
|
|
2926
|
+
event: "session_store.delete_failed",
|
|
2927
|
+
sessionId: id,
|
|
2928
|
+
message: msg,
|
|
2929
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
2930
|
+
})
|
|
2931
|
+
);
|
|
2932
|
+
}
|
|
2933
|
+
|
|
2934
|
+
// src/storage/session-store/delete-session-guards.ts
|
|
2935
|
+
async function assertSessionCanBeDeleted(sessionId, isSessionInUse) {
|
|
2936
|
+
if (!isSessionInUse) return;
|
|
2937
|
+
const reason = await isSessionInUse(sessionId);
|
|
2938
|
+
if (reason) {
|
|
2939
|
+
throw new Error(`Session ${sessionId} is in use (${reason}) and cannot be deleted.`);
|
|
2728
2940
|
}
|
|
2729
2941
|
}
|
|
2730
2942
|
|
|
@@ -2738,7 +2950,7 @@ function isSessionJsonlFileName(name) {
|
|
|
2738
2950
|
|
|
2739
2951
|
// src/storage/session-store/directory-session-files.ts
|
|
2740
2952
|
import * as fsp6 from "node:fs/promises";
|
|
2741
|
-
import * as
|
|
2953
|
+
import * as path11 from "node:path";
|
|
2742
2954
|
function sessionIdForFile(prefix, name) {
|
|
2743
2955
|
const base = name.replace(/\.jsonl$/, "");
|
|
2744
2956
|
return prefix ? `${prefix}/${base}` : base;
|
|
@@ -2760,12 +2972,12 @@ async function collectSessionFiles(dir, prefix = "", depth = 0) {
|
|
|
2760
2972
|
if (entry.isDirectory()) {
|
|
2761
2973
|
dirEntries.push(entry);
|
|
2762
2974
|
} else if (entry.isFile() && isSessionJsonlFileName(entry.name)) {
|
|
2763
|
-
files.push({ id: sessionIdForFile(prefix, entry.name), filePath:
|
|
2975
|
+
files.push({ id: sessionIdForFile(prefix, entry.name), filePath: path11.join(dir, entry.name) });
|
|
2764
2976
|
}
|
|
2765
2977
|
}
|
|
2766
2978
|
const childFileArrays = await Promise.all(
|
|
2767
2979
|
dirEntries.map(
|
|
2768
|
-
(entry) => collectSessionFiles(
|
|
2980
|
+
(entry) => collectSessionFiles(path11.join(dir, entry.name), childPrefixFor(entry, prefix, depth), depth + 1)
|
|
2769
2981
|
)
|
|
2770
2982
|
);
|
|
2771
2983
|
return [...childFileArrays.flat(), ...files];
|
|
@@ -2789,230 +3001,55 @@ async function collectSessionIds(dir, prefix = "", depth = 0) {
|
|
|
2789
3001
|
}
|
|
2790
3002
|
const childIdArrays = await Promise.all(
|
|
2791
3003
|
dirEntries.map(
|
|
2792
|
-
(entry) => collectSessionIds(
|
|
3004
|
+
(entry) => collectSessionIds(path11.join(dir, entry.name), childPrefixFor(entry, prefix, depth), depth + 1)
|
|
2793
3005
|
)
|
|
2794
3006
|
);
|
|
2795
3007
|
return [...childIdArrays.flat(), ...fileIds];
|
|
2796
3008
|
}
|
|
2797
3009
|
|
|
2798
|
-
// src/storage/session-store/
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
3010
|
+
// src/storage/session-store/events.ts
|
|
3011
|
+
function emitSessionStoreRead(events, sessionId, filePath, operation, outcome, durationMs, error) {
|
|
3012
|
+
events?.emit("storage.read", {
|
|
3013
|
+
sessionId,
|
|
3014
|
+
store: "session",
|
|
3015
|
+
filePath,
|
|
3016
|
+
operation,
|
|
3017
|
+
outcome,
|
|
3018
|
+
durationMs,
|
|
3019
|
+
...error !== void 0 ? { error } : {}
|
|
3020
|
+
});
|
|
2809
3021
|
}
|
|
2810
|
-
function
|
|
2811
|
-
|
|
2812
|
-
|
|
3022
|
+
function emitSessionStoreWrite(events, sessionId, filePath, operation, outcome, durationMs, eventCount, error) {
|
|
3023
|
+
events?.emit("storage.write", {
|
|
3024
|
+
sessionId,
|
|
3025
|
+
store: "session",
|
|
3026
|
+
filePath,
|
|
3027
|
+
operation,
|
|
3028
|
+
outcome,
|
|
3029
|
+
durationMs,
|
|
3030
|
+
...eventCount !== void 0 ? { eventCount } : {},
|
|
3031
|
+
...error !== void 0 ? { error } : {}
|
|
3032
|
+
});
|
|
2813
3033
|
}
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
3034
|
+
function emitSessionStoreError(events, sessionId, filePath, operation, error, recoverable) {
|
|
3035
|
+
events?.emit("storage.error", {
|
|
3036
|
+
sessionId,
|
|
3037
|
+
store: "session",
|
|
3038
|
+
filePath,
|
|
3039
|
+
operation,
|
|
3040
|
+
error,
|
|
3041
|
+
recoverable
|
|
3042
|
+
});
|
|
2818
3043
|
}
|
|
2819
3044
|
|
|
2820
|
-
// src/storage/session-store/
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
const
|
|
2827
|
-
|
|
2828
|
-
const sessDir = path11.join(shardDir, base);
|
|
2829
|
-
const deletions = [
|
|
2830
|
-
fsp7.unlink(jsonlPath),
|
|
2831
|
-
fsp7.unlink(sessionPath(rootDir, id, ".summary.json")),
|
|
2832
|
-
fsp7.unlink(sessionPath(rootDir, id, ".plan.json")),
|
|
2833
|
-
fsp7.unlink(sessionPath(rootDir, id, ".tasks.json")),
|
|
2834
|
-
fsp7.unlink(sessionPath(rootDir, id, ".todos.json"))
|
|
2835
|
-
];
|
|
2836
|
-
const results = await Promise.allSettled(deletions);
|
|
2837
|
-
for (const result of results) {
|
|
2838
|
-
if (result.status === "rejected") {
|
|
2839
|
-
warnDeleteFailure(id, result.reason);
|
|
2840
|
-
}
|
|
2841
|
-
}
|
|
2842
|
-
await fsp7.rm(sessDir, { recursive: true, force: true }).catch((err) => {
|
|
2843
|
-
console.warn(
|
|
2844
|
-
JSON.stringify({
|
|
2845
|
-
level: "warn",
|
|
2846
|
-
event: "session_store.rmdir_failed",
|
|
2847
|
-
sessionId: id,
|
|
2848
|
-
message: toErrorMessage(err),
|
|
2849
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
2850
|
-
})
|
|
2851
|
-
);
|
|
2852
|
-
});
|
|
2853
|
-
}
|
|
2854
|
-
function warnDeleteFailure(id, reason) {
|
|
2855
|
-
const msg = reason instanceof Error ? reason.message : String(reason);
|
|
2856
|
-
if (reason?.code === "ENOENT") return;
|
|
2857
|
-
console.warn(
|
|
2858
|
-
JSON.stringify({
|
|
2859
|
-
level: "warn",
|
|
2860
|
-
event: "session_store.delete_failed",
|
|
2861
|
-
sessionId: id,
|
|
2862
|
-
message: msg,
|
|
2863
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
2864
|
-
})
|
|
2865
|
-
);
|
|
2866
|
-
}
|
|
2867
|
-
|
|
2868
|
-
// src/storage/session-store/delete-session-guards.ts
|
|
2869
|
-
async function assertSessionCanBeDeleted(sessionId, isSessionInUse) {
|
|
2870
|
-
if (!isSessionInUse) return;
|
|
2871
|
-
const reason = await isSessionInUse(sessionId);
|
|
2872
|
-
if (reason) {
|
|
2873
|
-
throw new Error(`Session ${sessionId} is in use (${reason}) and cannot be deleted.`);
|
|
2874
|
-
}
|
|
2875
|
-
}
|
|
2876
|
-
|
|
2877
|
-
// src/storage/session-store/load-cache.ts
|
|
2878
|
-
var LOAD_CACHE_MAX_ENTRIES = 50;
|
|
2879
|
-
var LOAD_CACHE_MAX_BYTES = 64 * 1024 * 1024;
|
|
2880
|
-
var SessionLoadCache = class {
|
|
2881
|
-
constructor(entries = /* @__PURE__ */ new Map()) {
|
|
2882
|
-
this.entries = entries;
|
|
2883
|
-
}
|
|
2884
|
-
entries;
|
|
2885
|
-
bytes = 0;
|
|
2886
|
-
clear(sessionId) {
|
|
2887
|
-
if (sessionId !== void 0) {
|
|
2888
|
-
this.delete(sessionId);
|
|
2889
|
-
return;
|
|
2890
|
-
}
|
|
2891
|
-
this.entries.clear();
|
|
2892
|
-
this.bytes = 0;
|
|
2893
|
-
}
|
|
2894
|
-
getFresh(id, stat16, full) {
|
|
2895
|
-
const cached = this.entries.get(id);
|
|
2896
|
-
if (!cached || cached.mtimeMs !== stat16.mtimeMs || cached.size !== stat16.size) {
|
|
2897
|
-
return null;
|
|
2898
|
-
}
|
|
2899
|
-
this.entries.delete(id);
|
|
2900
|
-
this.entries.set(id, cached);
|
|
2901
|
-
if (full) return cached.data;
|
|
2902
|
-
return { ...cached.data, messages: [] };
|
|
2903
|
-
}
|
|
2904
|
-
set(id, stat16, data) {
|
|
2905
|
-
this.delete(id);
|
|
2906
|
-
while (stat16.size <= LOAD_CACHE_MAX_BYTES && (this.entries.size >= LOAD_CACHE_MAX_ENTRIES || this.bytes + stat16.size > LOAD_CACHE_MAX_BYTES)) {
|
|
2907
|
-
const oldest = this.entries.keys().next().value;
|
|
2908
|
-
if (oldest === void 0) break;
|
|
2909
|
-
this.delete(oldest);
|
|
2910
|
-
}
|
|
2911
|
-
if (stat16.size <= LOAD_CACHE_MAX_BYTES) {
|
|
2912
|
-
this.entries.set(id, { mtimeMs: stat16.mtimeMs, size: stat16.size, data });
|
|
2913
|
-
this.bytes += stat16.size;
|
|
2914
|
-
}
|
|
2915
|
-
}
|
|
2916
|
-
delete(sessionId) {
|
|
2917
|
-
const cached = this.entries.get(sessionId);
|
|
2918
|
-
if (cached) this.bytes = Math.max(0, this.bytes - cached.size);
|
|
2919
|
-
this.entries.delete(sessionId);
|
|
2920
|
-
}
|
|
2921
|
-
};
|
|
2922
|
-
|
|
2923
|
-
// src/storage/session-store/prune-helpers.ts
|
|
2924
|
-
import * as fsp8 from "node:fs/promises";
|
|
2925
|
-
import * as path12 from "node:path";
|
|
2926
|
-
function isPrunableSessionJsonl(name) {
|
|
2927
|
-
return name.endsWith(".jsonl") && name !== "_index.jsonl" && name !== "_mailbox.jsonl" && !name.endsWith(".replay.jsonl") && !name.endsWith(".audit.jsonl");
|
|
2928
|
-
}
|
|
2929
|
-
async function pruneSessionFiles(storeDir, maxAgeDays, deleteSession) {
|
|
2930
|
-
const cutoff = Date.now() - maxAgeDays * 864e5;
|
|
2931
|
-
let deleted = 0;
|
|
2932
|
-
const pruneFile = async (dir, name, prefix) => {
|
|
2933
|
-
const jsonlPath = path12.join(dir, name);
|
|
2934
|
-
try {
|
|
2935
|
-
const stat16 = await fsp8.stat(jsonlPath);
|
|
2936
|
-
if (stat16.mtimeMs >= cutoff) return;
|
|
2937
|
-
} catch {
|
|
2938
|
-
return;
|
|
2939
|
-
}
|
|
2940
|
-
const base = name.replace(/\.jsonl$/, "");
|
|
2941
|
-
const id = prefix ? `${prefix}/${base}` : base;
|
|
2942
|
-
await deleteSession(id);
|
|
2943
|
-
deleted++;
|
|
2944
|
-
};
|
|
2945
|
-
const entries = await fsp8.readdir(storeDir, { withFileTypes: true }).catch(() => []);
|
|
2946
|
-
for (const entry of entries) {
|
|
2947
|
-
if (entry.isFile()) {
|
|
2948
|
-
if (isPrunableSessionJsonl(entry.name)) await pruneFile(storeDir, entry.name, "");
|
|
2949
|
-
continue;
|
|
2950
|
-
}
|
|
2951
|
-
if (!entry.isDirectory()) continue;
|
|
2952
|
-
const dateDir = path12.join(storeDir, entry.name);
|
|
2953
|
-
const files = await fsp8.readdir(dateDir, { withFileTypes: true }).catch(() => []);
|
|
2954
|
-
for (const file of files) {
|
|
2955
|
-
if (!file.isFile() || !isPrunableSessionJsonl(file.name)) continue;
|
|
2956
|
-
await pruneFile(dateDir, file.name, entry.name);
|
|
2957
|
-
}
|
|
2958
|
-
}
|
|
2959
|
-
for (const entry of entries) {
|
|
2960
|
-
if (!entry.isDirectory()) continue;
|
|
2961
|
-
const dateDir = path12.join(storeDir, entry.name);
|
|
2962
|
-
try {
|
|
2963
|
-
const remaining = await fsp8.readdir(dateDir);
|
|
2964
|
-
if (remaining.length === 0) {
|
|
2965
|
-
await fsp8.rmdir(dateDir).catch(() => void 0);
|
|
2966
|
-
}
|
|
2967
|
-
} catch {
|
|
2968
|
-
}
|
|
2969
|
-
}
|
|
2970
|
-
return deleted;
|
|
2971
|
-
}
|
|
2972
|
-
|
|
2973
|
-
// src/storage/session-store/events.ts
|
|
2974
|
-
function emitSessionStoreRead(events, sessionId, filePath, operation, outcome, durationMs, error) {
|
|
2975
|
-
events?.emit("storage.read", {
|
|
2976
|
-
sessionId,
|
|
2977
|
-
store: "session",
|
|
2978
|
-
filePath,
|
|
2979
|
-
operation,
|
|
2980
|
-
outcome,
|
|
2981
|
-
durationMs,
|
|
2982
|
-
...error !== void 0 ? { error } : {}
|
|
2983
|
-
});
|
|
2984
|
-
}
|
|
2985
|
-
function emitSessionStoreWrite(events, sessionId, filePath, operation, outcome, durationMs, eventCount, error) {
|
|
2986
|
-
events?.emit("storage.write", {
|
|
2987
|
-
sessionId,
|
|
2988
|
-
store: "session",
|
|
2989
|
-
filePath,
|
|
2990
|
-
operation,
|
|
2991
|
-
outcome,
|
|
2992
|
-
durationMs,
|
|
2993
|
-
...eventCount !== void 0 ? { eventCount } : {},
|
|
2994
|
-
...error !== void 0 ? { error } : {}
|
|
2995
|
-
});
|
|
2996
|
-
}
|
|
2997
|
-
function emitSessionStoreError(events, sessionId, filePath, operation, error, recoverable) {
|
|
2998
|
-
events?.emit("storage.error", {
|
|
2999
|
-
sessionId,
|
|
3000
|
-
store: "session",
|
|
3001
|
-
filePath,
|
|
3002
|
-
operation,
|
|
3003
|
-
error,
|
|
3004
|
-
recoverable
|
|
3005
|
-
});
|
|
3006
|
-
}
|
|
3007
|
-
|
|
3008
|
-
// src/storage/session-store/fork-session.ts
|
|
3009
|
-
import { createHash as createHash4 } from "node:crypto";
|
|
3010
|
-
|
|
3011
|
-
// src/storage/session-store/replay.ts
|
|
3012
|
-
function isReplayableMessage(value) {
|
|
3013
|
-
if (!value || typeof value !== "object") return false;
|
|
3014
|
-
const candidate = value;
|
|
3015
|
-
return (candidate.role === "user" || candidate.role === "assistant" || candidate.role === "system") && (typeof candidate.content === "string" || Array.isArray(candidate.content));
|
|
3045
|
+
// src/storage/session-store/fork-session.ts
|
|
3046
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
3047
|
+
|
|
3048
|
+
// src/storage/session-store/replay.ts
|
|
3049
|
+
function isReplayableMessage(value) {
|
|
3050
|
+
if (!value || typeof value !== "object") return false;
|
|
3051
|
+
const candidate = value;
|
|
3052
|
+
return (candidate.role === "user" || candidate.role === "assistant" || candidate.role === "system") && (typeof candidate.content === "string" || Array.isArray(candidate.content));
|
|
3016
3053
|
}
|
|
3017
3054
|
function trackMessageToolState(message, openToolUses) {
|
|
3018
3055
|
if (!Array.isArray(message.content)) return;
|
|
@@ -3119,6 +3156,106 @@ async function forkSession(host, id, opts = {}) {
|
|
|
3119
3156
|
}
|
|
3120
3157
|
}
|
|
3121
3158
|
|
|
3159
|
+
// src/storage/session-store/index-reader.ts
|
|
3160
|
+
import * as fsp7 from "node:fs/promises";
|
|
3161
|
+
function applySessionIndexLines(raw, byId, deleted) {
|
|
3162
|
+
for (const line of raw.split("\n")) {
|
|
3163
|
+
if (!line.trim()) continue;
|
|
3164
|
+
try {
|
|
3165
|
+
const entry = JSON.parse(line);
|
|
3166
|
+
if (entry.action === "delete" && entry.id) {
|
|
3167
|
+
deleted.add(entry.id);
|
|
3168
|
+
byId.delete(entry.id);
|
|
3169
|
+
continue;
|
|
3170
|
+
}
|
|
3171
|
+
if (entry.id && !deleted.has(entry.id)) {
|
|
3172
|
+
byId.set(entry.id, entry);
|
|
3173
|
+
}
|
|
3174
|
+
} catch {
|
|
3175
|
+
}
|
|
3176
|
+
}
|
|
3177
|
+
}
|
|
3178
|
+
async function readFileRange(file, start, end) {
|
|
3179
|
+
const length = end - start;
|
|
3180
|
+
if (length <= 0) return { raw: "", end: start };
|
|
3181
|
+
const buffer = Buffer.allocUnsafe(length);
|
|
3182
|
+
let offset = 0;
|
|
3183
|
+
let handle;
|
|
3184
|
+
try {
|
|
3185
|
+
handle = await fsp7.open(file, "r");
|
|
3186
|
+
while (offset < length) {
|
|
3187
|
+
const { bytesRead } = await handle.read(buffer, offset, length - offset, start + offset);
|
|
3188
|
+
if (bytesRead === 0) return null;
|
|
3189
|
+
offset += bytesRead;
|
|
3190
|
+
}
|
|
3191
|
+
let completeLength = buffer.length;
|
|
3192
|
+
if (buffer.at(-1) !== 10) {
|
|
3193
|
+
const lastNewline = buffer.lastIndexOf(10);
|
|
3194
|
+
const trailing = buffer.subarray(lastNewline + 1).toString("utf8").trim();
|
|
3195
|
+
try {
|
|
3196
|
+
if (trailing) JSON.parse(trailing);
|
|
3197
|
+
else completeLength = lastNewline + 1;
|
|
3198
|
+
} catch {
|
|
3199
|
+
completeLength = lastNewline + 1;
|
|
3200
|
+
}
|
|
3201
|
+
}
|
|
3202
|
+
return {
|
|
3203
|
+
raw: buffer.subarray(0, completeLength).toString("utf8"),
|
|
3204
|
+
end: start + completeLength
|
|
3205
|
+
};
|
|
3206
|
+
} catch {
|
|
3207
|
+
return null;
|
|
3208
|
+
} finally {
|
|
3209
|
+
await handle?.close().catch(() => void 0);
|
|
3210
|
+
}
|
|
3211
|
+
}
|
|
3212
|
+
|
|
3213
|
+
// src/storage/session-store/load-cache.ts
|
|
3214
|
+
var LOAD_CACHE_MAX_ENTRIES = 50;
|
|
3215
|
+
var LOAD_CACHE_MAX_BYTES = 64 * 1024 * 1024;
|
|
3216
|
+
var SessionLoadCache = class {
|
|
3217
|
+
constructor(entries = /* @__PURE__ */ new Map()) {
|
|
3218
|
+
this.entries = entries;
|
|
3219
|
+
}
|
|
3220
|
+
entries;
|
|
3221
|
+
bytes = 0;
|
|
3222
|
+
clear(sessionId) {
|
|
3223
|
+
if (sessionId !== void 0) {
|
|
3224
|
+
this.delete(sessionId);
|
|
3225
|
+
return;
|
|
3226
|
+
}
|
|
3227
|
+
this.entries.clear();
|
|
3228
|
+
this.bytes = 0;
|
|
3229
|
+
}
|
|
3230
|
+
getFresh(id, stat15, full) {
|
|
3231
|
+
const cached = this.entries.get(id);
|
|
3232
|
+
if (!cached || cached.mtimeMs !== stat15.mtimeMs || cached.size !== stat15.size) {
|
|
3233
|
+
return null;
|
|
3234
|
+
}
|
|
3235
|
+
this.entries.delete(id);
|
|
3236
|
+
this.entries.set(id, cached);
|
|
3237
|
+
if (full) return cached.data;
|
|
3238
|
+
return { ...cached.data, messages: [] };
|
|
3239
|
+
}
|
|
3240
|
+
set(id, stat15, data) {
|
|
3241
|
+
this.delete(id);
|
|
3242
|
+
while (stat15.size <= LOAD_CACHE_MAX_BYTES && (this.entries.size >= LOAD_CACHE_MAX_ENTRIES || this.bytes + stat15.size > LOAD_CACHE_MAX_BYTES)) {
|
|
3243
|
+
const oldest = this.entries.keys().next().value;
|
|
3244
|
+
if (oldest === void 0) break;
|
|
3245
|
+
this.delete(oldest);
|
|
3246
|
+
}
|
|
3247
|
+
if (stat15.size <= LOAD_CACHE_MAX_BYTES) {
|
|
3248
|
+
this.entries.set(id, { mtimeMs: stat15.mtimeMs, size: stat15.size, data });
|
|
3249
|
+
this.bytes += stat15.size;
|
|
3250
|
+
}
|
|
3251
|
+
}
|
|
3252
|
+
delete(sessionId) {
|
|
3253
|
+
const cached = this.entries.get(sessionId);
|
|
3254
|
+
if (cached) this.bytes = Math.max(0, this.bytes - cached.size);
|
|
3255
|
+
this.entries.delete(sessionId);
|
|
3256
|
+
}
|
|
3257
|
+
};
|
|
3258
|
+
|
|
3122
3259
|
// src/storage/session-store/load-session-data.ts
|
|
3123
3260
|
import { createReadStream as createReadStream2 } from "node:fs";
|
|
3124
3261
|
import { createInterface as createInterface2 } from "node:readline";
|
|
@@ -3373,6 +3510,178 @@ function emitDamaged(params, detail) {
|
|
|
3373
3510
|
});
|
|
3374
3511
|
}
|
|
3375
3512
|
|
|
3513
|
+
// src/storage/session-store/prune-helpers.ts
|
|
3514
|
+
import * as fsp8 from "node:fs/promises";
|
|
3515
|
+
import * as path12 from "node:path";
|
|
3516
|
+
function isPrunableSessionJsonl(name) {
|
|
3517
|
+
return name.endsWith(".jsonl") && name !== "_index.jsonl" && name !== "_mailbox.jsonl" && !name.endsWith(".replay.jsonl") && !name.endsWith(".audit.jsonl");
|
|
3518
|
+
}
|
|
3519
|
+
async function pruneSessionFiles(storeDir, maxAgeDays, deleteSession) {
|
|
3520
|
+
const cutoff = Date.now() - maxAgeDays * 864e5;
|
|
3521
|
+
let deleted = 0;
|
|
3522
|
+
const pruneFile = async (dir, name, prefix) => {
|
|
3523
|
+
const jsonlPath = path12.join(dir, name);
|
|
3524
|
+
try {
|
|
3525
|
+
const stat15 = await fsp8.stat(jsonlPath);
|
|
3526
|
+
if (stat15.mtimeMs >= cutoff) return;
|
|
3527
|
+
} catch {
|
|
3528
|
+
return;
|
|
3529
|
+
}
|
|
3530
|
+
const base = name.replace(/\.jsonl$/, "");
|
|
3531
|
+
const id = prefix ? `${prefix}/${base}` : base;
|
|
3532
|
+
await deleteSession(id);
|
|
3533
|
+
deleted++;
|
|
3534
|
+
};
|
|
3535
|
+
const entries = await fsp8.readdir(storeDir, { withFileTypes: true }).catch(() => []);
|
|
3536
|
+
for (const entry of entries) {
|
|
3537
|
+
if (entry.isFile()) {
|
|
3538
|
+
if (isPrunableSessionJsonl(entry.name)) await pruneFile(storeDir, entry.name, "");
|
|
3539
|
+
continue;
|
|
3540
|
+
}
|
|
3541
|
+
if (!entry.isDirectory()) continue;
|
|
3542
|
+
const dateDir = path12.join(storeDir, entry.name);
|
|
3543
|
+
const files = await fsp8.readdir(dateDir, { withFileTypes: true }).catch(() => []);
|
|
3544
|
+
for (const file of files) {
|
|
3545
|
+
if (!file.isFile() || !isPrunableSessionJsonl(file.name)) continue;
|
|
3546
|
+
await pruneFile(dateDir, file.name, entry.name);
|
|
3547
|
+
}
|
|
3548
|
+
}
|
|
3549
|
+
for (const entry of entries) {
|
|
3550
|
+
if (!entry.isDirectory()) continue;
|
|
3551
|
+
const dateDir = path12.join(storeDir, entry.name);
|
|
3552
|
+
try {
|
|
3553
|
+
const remaining = await fsp8.readdir(dateDir);
|
|
3554
|
+
if (remaining.length === 0) {
|
|
3555
|
+
await fsp8.rmdir(dateDir).catch(() => void 0);
|
|
3556
|
+
}
|
|
3557
|
+
} catch {
|
|
3558
|
+
}
|
|
3559
|
+
}
|
|
3560
|
+
return deleted;
|
|
3561
|
+
}
|
|
3562
|
+
|
|
3563
|
+
// src/storage/session-store/search-events.ts
|
|
3564
|
+
import * as fsp9 from "node:fs/promises";
|
|
3565
|
+
async function searchSessionEvents(args) {
|
|
3566
|
+
const { file, secretScrubber, predicate, limit, signal } = args;
|
|
3567
|
+
const out = [];
|
|
3568
|
+
let stat15;
|
|
3569
|
+
try {
|
|
3570
|
+
stat15 = await fsp9.stat(file);
|
|
3571
|
+
} catch (err) {
|
|
3572
|
+
if (err.code === "ENOENT") return [];
|
|
3573
|
+
throw err;
|
|
3574
|
+
}
|
|
3575
|
+
if (stat15.size === 0) return [];
|
|
3576
|
+
let fh;
|
|
3577
|
+
try {
|
|
3578
|
+
fh = await fsp9.open(file, "r");
|
|
3579
|
+
const CHUNK = 64 * 1024;
|
|
3580
|
+
const buf = Buffer.alloc(CHUNK);
|
|
3581
|
+
let leftover = "";
|
|
3582
|
+
let eventIndex = 0;
|
|
3583
|
+
for (let position = 0; ; position += buf.byteLength) {
|
|
3584
|
+
if (signal?.aborted) {
|
|
3585
|
+
const reason = signal.reason ?? new DOMException("Aborted", "AbortError");
|
|
3586
|
+
throw reason;
|
|
3587
|
+
}
|
|
3588
|
+
const { bytesRead } = await fh.read(buf, 0, CHUNK, position);
|
|
3589
|
+
if (bytesRead === 0) break;
|
|
3590
|
+
const text = leftover + buf.subarray(0, bytesRead).toString("utf8");
|
|
3591
|
+
const parts = text.split("\n");
|
|
3592
|
+
leftover = parts.pop() ?? "";
|
|
3593
|
+
for (const line of parts) {
|
|
3594
|
+
if (!line) continue;
|
|
3595
|
+
const ev = parseSessionEventLine(line, secretScrubber);
|
|
3596
|
+
if (!ev) continue;
|
|
3597
|
+
if (predicate(ev, eventIndex, ev.ts)) {
|
|
3598
|
+
out.push({ event: ev, eventIndex, ts: ev.ts });
|
|
3599
|
+
if (limit !== void 0 && out.length >= limit) return out;
|
|
3600
|
+
}
|
|
3601
|
+
eventIndex++;
|
|
3602
|
+
}
|
|
3603
|
+
}
|
|
3604
|
+
const trailing = parseSessionEventLine(leftover.trim() ? leftover : "", secretScrubber);
|
|
3605
|
+
if (trailing && predicate(trailing, eventIndex, trailing.ts)) {
|
|
3606
|
+
out.push({ event: trailing, eventIndex, ts: trailing.ts });
|
|
3607
|
+
}
|
|
3608
|
+
return out;
|
|
3609
|
+
} finally {
|
|
3610
|
+
if (fh) await fh.close().catch(() => void 0);
|
|
3611
|
+
}
|
|
3612
|
+
}
|
|
3613
|
+
function parseSessionEventLine(line, secretScrubber) {
|
|
3614
|
+
if (!line) return null;
|
|
3615
|
+
try {
|
|
3616
|
+
const parsed = JSON.parse(line);
|
|
3617
|
+
if (parsed === null || typeof parsed !== "object" || typeof parsed.type !== "string" || typeof parsed.ts !== "string") {
|
|
3618
|
+
return null;
|
|
3619
|
+
}
|
|
3620
|
+
return scrubPersistedSessionEvent(parsed, secretScrubber);
|
|
3621
|
+
} catch {
|
|
3622
|
+
return null;
|
|
3623
|
+
}
|
|
3624
|
+
}
|
|
3625
|
+
|
|
3626
|
+
// src/storage/session-store/shard-manifest.ts
|
|
3627
|
+
import * as fsp10 from "node:fs/promises";
|
|
3628
|
+
|
|
3629
|
+
// src/storage/session-summary.ts
|
|
3630
|
+
function compareSessionSummaries(a, b) {
|
|
3631
|
+
const aActivity = a.lastActivityAt ?? a.endedAt ?? a.startedAt;
|
|
3632
|
+
const bActivity = b.lastActivityAt ?? b.endedAt ?? b.startedAt;
|
|
3633
|
+
if (aActivity < bActivity) return 1;
|
|
3634
|
+
if (aActivity > bActivity) return -1;
|
|
3635
|
+
if (a.startedAt < b.startedAt) return 1;
|
|
3636
|
+
if (a.startedAt > b.startedAt) return -1;
|
|
3637
|
+
return a.id.localeCompare(b.id);
|
|
3638
|
+
}
|
|
3639
|
+
function matchesSessionFilter(summary, criteria) {
|
|
3640
|
+
if (criteria.since && summary.startedAt < criteria.since) return false;
|
|
3641
|
+
if (criteria.until && summary.startedAt > criteria.until) return false;
|
|
3642
|
+
if (criteria.provider && summary.provider !== criteria.provider) return false;
|
|
3643
|
+
if (criteria.model && summary.model !== criteria.model) return false;
|
|
3644
|
+
if (criteria.minTokens !== void 0 && summary.tokenTotal < criteria.minTokens) return false;
|
|
3645
|
+
if (criteria.titleContains) {
|
|
3646
|
+
const needle = criteria.titleContains.toLocaleLowerCase();
|
|
3647
|
+
if (!summary.title.toLocaleLowerCase().includes(needle)) return false;
|
|
3648
|
+
}
|
|
3649
|
+
return true;
|
|
3650
|
+
}
|
|
3651
|
+
|
|
3652
|
+
// src/storage/session-store/shard-manifest.ts
|
|
3653
|
+
async function readOrBuildShardManifestEntry(opts) {
|
|
3654
|
+
try {
|
|
3655
|
+
const raw = await fsp10.readFile(opts.manifestPath, "utf8");
|
|
3656
|
+
const parsed = JSON.parse(raw);
|
|
3657
|
+
return {
|
|
3658
|
+
summaries: Array.isArray(parsed.summaries) ? parsed.summaries : [],
|
|
3659
|
+
ids: Array.isArray(parsed.ids) ? parsed.ids : []
|
|
3660
|
+
};
|
|
3661
|
+
} catch {
|
|
3662
|
+
}
|
|
3663
|
+
const refs = await opts.collectSessionFilesInShard(opts.shardKey);
|
|
3664
|
+
const candidates = await mapWithConcurrency(
|
|
3665
|
+
refs,
|
|
3666
|
+
opts.concurrency,
|
|
3667
|
+
async (ref) => {
|
|
3668
|
+
const manifest = await opts.readSummaryManifest(ref.id);
|
|
3669
|
+
if (manifest) return { summary: manifest, needsBackfill: false };
|
|
3670
|
+
const summary = await opts.summaryHeaderFor(ref);
|
|
3671
|
+
if (!summary) return null;
|
|
3672
|
+
const hydrated = await opts.summaryFor(summary.id).catch(() => summary);
|
|
3673
|
+
return { summary: hydrated, needsBackfill: false };
|
|
3674
|
+
}
|
|
3675
|
+
);
|
|
3676
|
+
const summaries = candidates.filter((candidate) => candidate !== null).map((candidate) => candidate.summary);
|
|
3677
|
+
summaries.sort(compareSessionSummaries);
|
|
3678
|
+
const entry = { summaries, ids: summaries.map((summary) => summary.id) };
|
|
3679
|
+
await atomicWrite(opts.manifestPath, JSON.stringify(entry), { mode: 384 }).catch(
|
|
3680
|
+
() => void 0
|
|
3681
|
+
);
|
|
3682
|
+
return entry;
|
|
3683
|
+
}
|
|
3684
|
+
|
|
3376
3685
|
// src/storage/session-store/summary-builder.ts
|
|
3377
3686
|
import { createReadStream as createReadStream3 } from "node:fs";
|
|
3378
3687
|
import { createInterface as createInterface3 } from "node:readline";
|
|
@@ -3512,13 +3821,13 @@ async function* iterateSessionEvents(file, secretScrubber) {
|
|
|
3512
3821
|
}
|
|
3513
3822
|
|
|
3514
3823
|
// src/storage/session-store/summary-header.ts
|
|
3515
|
-
import * as
|
|
3824
|
+
import * as fsp11 from "node:fs/promises";
|
|
3516
3825
|
async function readSessionSummaryHeader(ref, secretScrubber) {
|
|
3517
3826
|
let mtime = (/* @__PURE__ */ new Date(0)).toISOString();
|
|
3518
3827
|
try {
|
|
3519
|
-
const
|
|
3520
|
-
if (!
|
|
3521
|
-
mtime =
|
|
3828
|
+
const stat15 = await fsp11.stat(ref.filePath);
|
|
3829
|
+
if (!stat15.isFile()) return damagedSummary(ref.id, stat15.mtime.toISOString());
|
|
3830
|
+
mtime = stat15.mtime.toISOString();
|
|
3522
3831
|
} catch {
|
|
3523
3832
|
return null;
|
|
3524
3833
|
}
|
|
@@ -3561,128 +3870,6 @@ function damagedSummary(id, startedAt) {
|
|
|
3561
3870
|
};
|
|
3562
3871
|
}
|
|
3563
3872
|
|
|
3564
|
-
// src/storage/session-store/shard-manifest.ts
|
|
3565
|
-
import * as fsp10 from "node:fs/promises";
|
|
3566
|
-
|
|
3567
|
-
// src/storage/session-summary.ts
|
|
3568
|
-
function compareSessionSummaries(a, b) {
|
|
3569
|
-
const aActivity = a.lastActivityAt ?? a.endedAt ?? a.startedAt;
|
|
3570
|
-
const bActivity = b.lastActivityAt ?? b.endedAt ?? b.startedAt;
|
|
3571
|
-
if (aActivity < bActivity) return 1;
|
|
3572
|
-
if (aActivity > bActivity) return -1;
|
|
3573
|
-
if (a.startedAt < b.startedAt) return 1;
|
|
3574
|
-
if (a.startedAt > b.startedAt) return -1;
|
|
3575
|
-
return a.id.localeCompare(b.id);
|
|
3576
|
-
}
|
|
3577
|
-
function matchesSessionFilter(summary, criteria) {
|
|
3578
|
-
if (criteria.since && summary.startedAt < criteria.since) return false;
|
|
3579
|
-
if (criteria.until && summary.startedAt > criteria.until) return false;
|
|
3580
|
-
if (criteria.provider && summary.provider !== criteria.provider) return false;
|
|
3581
|
-
if (criteria.model && summary.model !== criteria.model) return false;
|
|
3582
|
-
if (criteria.minTokens !== void 0 && summary.tokenTotal < criteria.minTokens) return false;
|
|
3583
|
-
if (criteria.titleContains) {
|
|
3584
|
-
const needle = criteria.titleContains.toLocaleLowerCase();
|
|
3585
|
-
if (!summary.title.toLocaleLowerCase().includes(needle)) return false;
|
|
3586
|
-
}
|
|
3587
|
-
return true;
|
|
3588
|
-
}
|
|
3589
|
-
|
|
3590
|
-
// src/storage/session-store/shard-manifest.ts
|
|
3591
|
-
async function readOrBuildShardManifestEntry(opts) {
|
|
3592
|
-
try {
|
|
3593
|
-
const raw = await fsp10.readFile(opts.manifestPath, "utf8");
|
|
3594
|
-
const parsed = JSON.parse(raw);
|
|
3595
|
-
return {
|
|
3596
|
-
summaries: Array.isArray(parsed.summaries) ? parsed.summaries : [],
|
|
3597
|
-
ids: Array.isArray(parsed.ids) ? parsed.ids : []
|
|
3598
|
-
};
|
|
3599
|
-
} catch {
|
|
3600
|
-
}
|
|
3601
|
-
const refs = await opts.collectSessionFilesInShard(opts.shardKey);
|
|
3602
|
-
const candidates = await mapWithConcurrency(
|
|
3603
|
-
refs,
|
|
3604
|
-
opts.concurrency,
|
|
3605
|
-
async (ref) => {
|
|
3606
|
-
const manifest = await opts.readSummaryManifest(ref.id);
|
|
3607
|
-
if (manifest) return { summary: manifest, needsBackfill: false };
|
|
3608
|
-
const summary = await opts.summaryHeaderFor(ref);
|
|
3609
|
-
if (!summary) return null;
|
|
3610
|
-
const hydrated = await opts.summaryFor(summary.id).catch(() => summary);
|
|
3611
|
-
return { summary: hydrated, needsBackfill: false };
|
|
3612
|
-
}
|
|
3613
|
-
);
|
|
3614
|
-
const summaries = candidates.filter((candidate) => candidate !== null).map((candidate) => candidate.summary);
|
|
3615
|
-
summaries.sort(compareSessionSummaries);
|
|
3616
|
-
const entry = { summaries, ids: summaries.map((summary) => summary.id) };
|
|
3617
|
-
await atomicWrite(opts.manifestPath, JSON.stringify(entry), { mode: 384 }).catch(
|
|
3618
|
-
() => void 0
|
|
3619
|
-
);
|
|
3620
|
-
return entry;
|
|
3621
|
-
}
|
|
3622
|
-
|
|
3623
|
-
// src/storage/session-store/search-events.ts
|
|
3624
|
-
import * as fsp11 from "node:fs/promises";
|
|
3625
|
-
async function searchSessionEvents(args) {
|
|
3626
|
-
const { file, secretScrubber, predicate, limit, signal } = args;
|
|
3627
|
-
const out = [];
|
|
3628
|
-
let stat16;
|
|
3629
|
-
try {
|
|
3630
|
-
stat16 = await fsp11.stat(file);
|
|
3631
|
-
} catch (err) {
|
|
3632
|
-
if (err.code === "ENOENT") return [];
|
|
3633
|
-
throw err;
|
|
3634
|
-
}
|
|
3635
|
-
if (stat16.size === 0) return [];
|
|
3636
|
-
let fh;
|
|
3637
|
-
try {
|
|
3638
|
-
fh = await fsp11.open(file, "r");
|
|
3639
|
-
const CHUNK = 64 * 1024;
|
|
3640
|
-
const buf = Buffer.alloc(CHUNK);
|
|
3641
|
-
let leftover = "";
|
|
3642
|
-
let eventIndex = 0;
|
|
3643
|
-
for (let position = 0; ; position += buf.byteLength) {
|
|
3644
|
-
if (signal?.aborted) {
|
|
3645
|
-
const reason = signal.reason ?? new DOMException("Aborted", "AbortError");
|
|
3646
|
-
throw reason;
|
|
3647
|
-
}
|
|
3648
|
-
const { bytesRead } = await fh.read(buf, 0, CHUNK, position);
|
|
3649
|
-
if (bytesRead === 0) break;
|
|
3650
|
-
const text = leftover + buf.subarray(0, bytesRead).toString("utf8");
|
|
3651
|
-
const parts = text.split("\n");
|
|
3652
|
-
leftover = parts.pop() ?? "";
|
|
3653
|
-
for (const line of parts) {
|
|
3654
|
-
if (!line) continue;
|
|
3655
|
-
const ev = parseSessionEventLine(line, secretScrubber);
|
|
3656
|
-
if (!ev) continue;
|
|
3657
|
-
if (predicate(ev, eventIndex, ev.ts)) {
|
|
3658
|
-
out.push({ event: ev, eventIndex, ts: ev.ts });
|
|
3659
|
-
if (limit !== void 0 && out.length >= limit) return out;
|
|
3660
|
-
}
|
|
3661
|
-
eventIndex++;
|
|
3662
|
-
}
|
|
3663
|
-
}
|
|
3664
|
-
const trailing = parseSessionEventLine(leftover.trim() ? leftover : "", secretScrubber);
|
|
3665
|
-
if (trailing && predicate(trailing, eventIndex, trailing.ts)) {
|
|
3666
|
-
out.push({ event: trailing, eventIndex, ts: trailing.ts });
|
|
3667
|
-
}
|
|
3668
|
-
return out;
|
|
3669
|
-
} finally {
|
|
3670
|
-
if (fh) await fh.close().catch(() => void 0);
|
|
3671
|
-
}
|
|
3672
|
-
}
|
|
3673
|
-
function parseSessionEventLine(line, secretScrubber) {
|
|
3674
|
-
if (!line) return null;
|
|
3675
|
-
try {
|
|
3676
|
-
const parsed = JSON.parse(line);
|
|
3677
|
-
if (parsed === null || typeof parsed !== "object" || typeof parsed.type !== "string" || typeof parsed.ts !== "string") {
|
|
3678
|
-
return null;
|
|
3679
|
-
}
|
|
3680
|
-
return scrubPersistedSessionEvent(parsed, secretScrubber);
|
|
3681
|
-
} catch {
|
|
3682
|
-
return null;
|
|
3683
|
-
}
|
|
3684
|
-
}
|
|
3685
|
-
|
|
3686
3873
|
// src/storage/session-store.ts
|
|
3687
3874
|
var DefaultSessionStore = class _DefaultSessionStore {
|
|
3688
3875
|
dir;
|
|
@@ -3692,6 +3879,8 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
3692
3879
|
checkpointCas;
|
|
3693
3880
|
isSessionInUse;
|
|
3694
3881
|
logger;
|
|
3882
|
+
onAppend;
|
|
3883
|
+
onAppendBatch;
|
|
3695
3884
|
/**
|
|
3696
3885
|
* In-memory cache for load() results, keyed by session ID. The cache is
|
|
3697
3886
|
* invalidated when the file's mtimeMs or size changes (indicating the
|
|
@@ -3718,6 +3907,8 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
3718
3907
|
this.secretScrubber = opts.secretScrubber ?? new DefaultSecretScrubber();
|
|
3719
3908
|
this.isSessionInUse = opts.isSessionInUse;
|
|
3720
3909
|
this.logger = opts.logger;
|
|
3910
|
+
this.onAppend = opts.onAppend;
|
|
3911
|
+
this.onAppendBatch = opts.onAppendBatch;
|
|
3721
3912
|
}
|
|
3722
3913
|
/**
|
|
3723
3914
|
* Emit a structured warning. Uses the configured Logger when available;
|
|
@@ -3794,6 +3985,8 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
3794
3985
|
filePath: file,
|
|
3795
3986
|
secretScrubber: this.secretScrubber,
|
|
3796
3987
|
checkpointCas: this.checkpointCas,
|
|
3988
|
+
onAppend: this.onAppend,
|
|
3989
|
+
onAppendBatch: this.onAppendBatch,
|
|
3797
3990
|
resolveName: async () => {
|
|
3798
3991
|
const current = await this.readSummaryManifest(id);
|
|
3799
3992
|
if (!current) return null;
|
|
@@ -3817,21 +4010,25 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
3817
4010
|
async fork(id, opts = {}) {
|
|
3818
4011
|
return forkSession(this, id, opts);
|
|
3819
4012
|
}
|
|
4013
|
+
/**
|
|
4014
|
+
* Capture the deterministic post-tool workspace identity through the store-owned CAS.
|
|
4015
|
+
*/
|
|
4016
|
+
async captureWorkspaceCheckpoint(sessionId, promptIndex) {
|
|
4017
|
+
return captureCheckpoint(this.checkpointCas, sessionId, promptIndex);
|
|
4018
|
+
}
|
|
4019
|
+
/**
|
|
4020
|
+
* Materialize a store-owned checkpoint into an already isolated workspace.
|
|
4021
|
+
*/
|
|
3820
4022
|
async materializeWorkspaceCheckpoint(checkpoint, targetRoot) {
|
|
3821
|
-
|
|
3822
|
-
throw new Error(
|
|
3823
|
-
"Workspace checkpoint materialization requires a projectRoot-aware session store"
|
|
3824
|
-
);
|
|
3825
|
-
}
|
|
3826
|
-
return this.checkpointCas.materialize(checkpoint, targetRoot);
|
|
4023
|
+
return materializeCheckpoint(this.checkpointCas, checkpoint, targetRoot);
|
|
3827
4024
|
}
|
|
3828
4025
|
async resolveId(query) {
|
|
3829
4026
|
const normalized = query.trim();
|
|
3830
4027
|
if (!normalized) throw new Error("Session not found: (empty query)");
|
|
3831
4028
|
if (normalized) {
|
|
3832
4029
|
try {
|
|
3833
|
-
const
|
|
3834
|
-
if (
|
|
4030
|
+
const stat15 = await fsp12.stat(this.sessionPath(normalized, ".jsonl"));
|
|
4031
|
+
if (stat15.isFile()) return normalized;
|
|
3835
4032
|
} catch {
|
|
3836
4033
|
}
|
|
3837
4034
|
}
|
|
@@ -3908,9 +4105,12 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
3908
4105
|
handle = await fsp12.open(file, "a", 384);
|
|
3909
4106
|
} catch (err) {
|
|
3910
4107
|
emitSessionStoreError(this.events, canonicalId, file, "resume", toErrorMessage(err), false);
|
|
3911
|
-
throw new Error(
|
|
3912
|
-
|
|
3913
|
-
|
|
4108
|
+
throw new Error(
|
|
4109
|
+
`Failed to open session "${canonicalId}" for append: ${toErrorMessage(err)}`,
|
|
4110
|
+
{
|
|
4111
|
+
cause: err
|
|
4112
|
+
}
|
|
4113
|
+
);
|
|
3914
4114
|
}
|
|
3915
4115
|
try {
|
|
3916
4116
|
const writer = new FileSessionWriter(
|
|
@@ -3926,13 +4126,15 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
3926
4126
|
{
|
|
3927
4127
|
resumed: true,
|
|
3928
4128
|
initialSummary,
|
|
3929
|
-
// Shard directory (sessions/<date>/)
|
|
4129
|
+
// Shard directory (sessions/<date>/) — must match create() so the
|
|
3930
4130
|
// .summary.json sidecar lands next to the JSONL instead of the
|
|
3931
4131
|
// sessions root (where summaryFor() would never find it).
|
|
3932
4132
|
dir: path13.dirname(file),
|
|
3933
4133
|
filePath: file,
|
|
3934
4134
|
secretScrubber: this.secretScrubber,
|
|
3935
4135
|
checkpointCas: this.checkpointCas,
|
|
4136
|
+
onAppend: this.onAppend,
|
|
4137
|
+
onAppendBatch: this.onAppendBatch,
|
|
3936
4138
|
resolveName: async () => {
|
|
3937
4139
|
const current = await this.readSummaryManifest(canonicalId);
|
|
3938
4140
|
if (!current) return null;
|
|
@@ -3982,8 +4184,8 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
3982
4184
|
let cacheHit = false;
|
|
3983
4185
|
try {
|
|
3984
4186
|
const s = await fsp12.stat(file);
|
|
3985
|
-
const
|
|
3986
|
-
const cached = this.loadCache.getFresh(id,
|
|
4187
|
+
const stat15 = { mtimeMs: s.mtimeMs, size: s.size };
|
|
4188
|
+
const cached = this.loadCache.getFresh(id, stat15, mode.full);
|
|
3987
4189
|
if (cached) {
|
|
3988
4190
|
cacheHit = true;
|
|
3989
4191
|
return cached;
|
|
@@ -3996,7 +4198,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
3996
4198
|
secretScrubber: this.secretScrubber
|
|
3997
4199
|
});
|
|
3998
4200
|
if (mode.full) {
|
|
3999
|
-
this.loadCache.set(id,
|
|
4201
|
+
this.loadCache.set(id, stat15, data);
|
|
4000
4202
|
}
|
|
4001
4203
|
return data;
|
|
4002
4204
|
} catch (err) {
|
|
@@ -4105,7 +4307,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
4105
4307
|
await withFileLock(this.indexFile, async () => {
|
|
4106
4308
|
await this.invalidateShardManifestBySessionId(summary.id);
|
|
4107
4309
|
const line = JSON.stringify(summary) + "\n";
|
|
4108
|
-
await fsp12.appendFile(this.indexFile, line, "utf8");
|
|
4310
|
+
await fsp12.appendFile(this.indexFile, line, { encoding: "utf8", mode: SECRET_FILE_MODE });
|
|
4109
4311
|
this._indexCache = null;
|
|
4110
4312
|
this.indexAppendCount++;
|
|
4111
4313
|
if (this.indexAppendCount >= _DefaultSessionStore.COMPACT_EVERY) {
|
|
@@ -4128,7 +4330,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
4128
4330
|
await ensureDir(this.dir);
|
|
4129
4331
|
await withFileLock(this.indexFile, async () => {
|
|
4130
4332
|
const line = JSON.stringify({ action: "delete", id }) + "\n";
|
|
4131
|
-
await fsp12.appendFile(this.indexFile, line, "utf8");
|
|
4333
|
+
await fsp12.appendFile(this.indexFile, line, { encoding: "utf8", mode: SECRET_FILE_MODE });
|
|
4132
4334
|
this._indexCache = null;
|
|
4133
4335
|
await this.invalidateShardManifestBySessionId(id);
|
|
4134
4336
|
this.indexAppendCount++;
|
|
@@ -4183,26 +4385,26 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
4183
4385
|
* Returns empty array when the index doesn't exist or is corrupt.
|
|
4184
4386
|
*/
|
|
4185
4387
|
async readIndex() {
|
|
4186
|
-
let
|
|
4388
|
+
let stat15;
|
|
4187
4389
|
try {
|
|
4188
4390
|
const s = await fsp12.stat(this.indexFile);
|
|
4189
|
-
|
|
4391
|
+
stat15 = { mtimeMs: s.mtimeMs, size: s.size, ino: s.ino, birthtimeMs: s.birthtimeMs };
|
|
4190
4392
|
} catch {
|
|
4191
4393
|
this._indexCache = null;
|
|
4192
4394
|
return [];
|
|
4193
4395
|
}
|
|
4194
|
-
if (this._indexCache !== null && this._indexCache.mtimeMs ===
|
|
4396
|
+
if (this._indexCache !== null && this._indexCache.mtimeMs === stat15.mtimeMs && this._indexCache.size === stat15.size && this._indexCache.ino === stat15.ino && this._indexCache.birthtimeMs === stat15.birthtimeMs) {
|
|
4195
4397
|
return this._indexCache.summaries;
|
|
4196
4398
|
}
|
|
4197
4399
|
const cached = this._indexCache;
|
|
4198
|
-
const sameFile = cached !== null && cached.ino ===
|
|
4199
|
-
if (cached && sameFile &&
|
|
4200
|
-
const appended = await readFileRange(this.indexFile, cached.size,
|
|
4400
|
+
const sameFile = cached !== null && cached.ino === stat15.ino && cached.birthtimeMs === stat15.birthtimeMs;
|
|
4401
|
+
if (cached && sameFile && stat15.size > cached.size) {
|
|
4402
|
+
const appended = await readFileRange(this.indexFile, cached.size, stat15.size);
|
|
4201
4403
|
if (appended !== null) {
|
|
4202
4404
|
applySessionIndexLines(appended.raw, cached.byId, cached.deleted);
|
|
4203
4405
|
const summaries2 = Array.from(cached.byId.values()).sort(compareSessionSummaries);
|
|
4204
4406
|
this._indexCache = {
|
|
4205
|
-
...
|
|
4407
|
+
...stat15,
|
|
4206
4408
|
size: appended.end,
|
|
4207
4409
|
summaries: summaries2,
|
|
4208
4410
|
byId: cached.byId,
|
|
@@ -4223,7 +4425,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
4223
4425
|
applySessionIndexLines(raw, byId, deleted);
|
|
4224
4426
|
const summaries = Array.from(byId.values());
|
|
4225
4427
|
summaries.sort(compareSessionSummaries);
|
|
4226
|
-
this._indexCache = { ...
|
|
4428
|
+
this._indexCache = { ...stat15, summaries, byId, deleted };
|
|
4227
4429
|
return summaries;
|
|
4228
4430
|
}
|
|
4229
4431
|
/**
|
|
@@ -4323,8 +4525,8 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
4323
4525
|
if (fromManifest) return fromManifest;
|
|
4324
4526
|
try {
|
|
4325
4527
|
const full = this.sessionPath(id, ".jsonl");
|
|
4326
|
-
const
|
|
4327
|
-
const summary = await this.summarize(id,
|
|
4528
|
+
const stat15 = await fsp12.stat(full);
|
|
4529
|
+
const summary = await this.summarize(id, stat15.mtime.toISOString());
|
|
4328
4530
|
await atomicWrite(manifest, JSON.stringify(summary), { mode: 384 }).catch((err) => {
|
|
4329
4531
|
const msg = toErrorMessage(err);
|
|
4330
4532
|
emitSessionStoreError(this.events, id, manifest, "summary_fallback", msg, true);
|
|
@@ -4336,12 +4538,28 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
4336
4538
|
});
|
|
4337
4539
|
outcome = "failure";
|
|
4338
4540
|
errorMsg = "summary fallback \xE2\u20AC\u201D manifest rebuilt";
|
|
4339
|
-
emitSessionStoreRead(
|
|
4541
|
+
emitSessionStoreRead(
|
|
4542
|
+
this.events,
|
|
4543
|
+
id,
|
|
4544
|
+
manifest,
|
|
4545
|
+
"summary",
|
|
4546
|
+
outcome,
|
|
4547
|
+
Date.now() - t0,
|
|
4548
|
+
errorMsg
|
|
4549
|
+
);
|
|
4340
4550
|
return summary;
|
|
4341
4551
|
} catch (err) {
|
|
4342
4552
|
outcome = "failure";
|
|
4343
4553
|
errorMsg = toErrorMessage(err);
|
|
4344
|
-
emitSessionStoreRead(
|
|
4554
|
+
emitSessionStoreRead(
|
|
4555
|
+
this.events,
|
|
4556
|
+
id,
|
|
4557
|
+
manifest,
|
|
4558
|
+
"summary",
|
|
4559
|
+
outcome,
|
|
4560
|
+
Date.now() - t0,
|
|
4561
|
+
errorMsg
|
|
4562
|
+
);
|
|
4345
4563
|
return {
|
|
4346
4564
|
id,
|
|
4347
4565
|
title: "(damaged)",
|
|
@@ -4356,14 +4574,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
4356
4574
|
const manifest = this.sessionPath(id, ".summary.json");
|
|
4357
4575
|
try {
|
|
4358
4576
|
const raw = await fsp12.readFile(manifest, "utf8");
|
|
4359
|
-
emitSessionStoreRead(
|
|
4360
|
-
this.events,
|
|
4361
|
-
id,
|
|
4362
|
-
manifest,
|
|
4363
|
-
"summary",
|
|
4364
|
-
"success",
|
|
4365
|
-
Date.now() - startTime
|
|
4366
|
-
);
|
|
4577
|
+
emitSessionStoreRead(this.events, id, manifest, "summary", "success", Date.now() - startTime);
|
|
4367
4578
|
return JSON.parse(raw);
|
|
4368
4579
|
} catch {
|
|
4369
4580
|
return null;
|
|
@@ -4578,12 +4789,12 @@ var QueueStore = class {
|
|
|
4578
4789
|
const t0 = Date.now();
|
|
4579
4790
|
let raw;
|
|
4580
4791
|
try {
|
|
4581
|
-
const
|
|
4582
|
-
if (
|
|
4792
|
+
const stat15 = await fsp13.stat(this.file);
|
|
4793
|
+
if (stat15.size > QUEUE_MAX_BYTES) {
|
|
4583
4794
|
this.logWarn("Queue file exceeds the safe read budget; ignoring it", {
|
|
4584
4795
|
event: "queue_store.read_budget_exceeded",
|
|
4585
4796
|
path: this.file,
|
|
4586
|
-
bytes:
|
|
4797
|
+
bytes: stat15.size,
|
|
4587
4798
|
maxBytes: QUEUE_MAX_BYTES
|
|
4588
4799
|
});
|
|
4589
4800
|
this.events?.emit("storage.read", {
|
|
@@ -5034,8 +5245,8 @@ var FileMemoryBackend = class {
|
|
|
5034
5245
|
}
|
|
5035
5246
|
async getMtime(file) {
|
|
5036
5247
|
try {
|
|
5037
|
-
const
|
|
5038
|
-
return
|
|
5248
|
+
const stat15 = await fs3.stat(file);
|
|
5249
|
+
return stat15.mtimeMs;
|
|
5039
5250
|
} catch {
|
|
5040
5251
|
return 0;
|
|
5041
5252
|
}
|
|
@@ -5086,15 +5297,15 @@ var FileMemoryBackend = class {
|
|
|
5086
5297
|
const line = `- [${entry.ts}] ${id}${meta} ${entry.text.replace(/\n/g, " ")}
|
|
5087
5298
|
`;
|
|
5088
5299
|
await withFileLock(file, async () => {
|
|
5089
|
-
const handle = await fs3.open(file, "a+");
|
|
5300
|
+
const handle = await fs3.open(file, "a+", SECRET_FILE_MODE);
|
|
5090
5301
|
try {
|
|
5091
|
-
const
|
|
5302
|
+
const stat15 = await handle.stat();
|
|
5092
5303
|
let prefix = "";
|
|
5093
|
-
if (
|
|
5304
|
+
if (stat15.size === 0) {
|
|
5094
5305
|
prefix = "# Agent Memory\n\n";
|
|
5095
5306
|
} else {
|
|
5096
5307
|
const tail = Buffer.allocUnsafe(1);
|
|
5097
|
-
const { bytesRead } = await handle.read(tail, 0, 1,
|
|
5308
|
+
const { bytesRead } = await handle.read(tail, 0, 1, stat15.size - 1);
|
|
5098
5309
|
if (bytesRead === 1 && tail[0] !== 10) prefix = "\n";
|
|
5099
5310
|
}
|
|
5100
5311
|
await handle.appendFile(`${prefix}${line}`, "utf8");
|
|
@@ -6095,6 +6306,9 @@ async function readProviderSnapshot(configPath, vault, warn) {
|
|
|
6095
6306
|
if (typeof decrypted.uiLocale === "string" && decrypted.uiLocale)
|
|
6096
6307
|
snapshot.uiLocale = decrypted.uiLocale;
|
|
6097
6308
|
if (Array.isArray(decrypted.fallbackModels)) snapshot.fallbackModels = decrypted.fallbackModels;
|
|
6309
|
+
if (typeof decrypted.fallbackBridge === "string" && decrypted.fallbackBridge.trim()) {
|
|
6310
|
+
snapshot.fallbackBridge = decrypted.fallbackBridge.trim();
|
|
6311
|
+
}
|
|
6098
6312
|
if (decrypted.fallbackProfiles) snapshot.fallbackProfiles = decrypted.fallbackProfiles;
|
|
6099
6313
|
if (Array.isArray(decrypted.favoriteModels)) snapshot.favoriteModels = decrypted.favoriteModels;
|
|
6100
6314
|
if (typeof decrypted.favoriteModelsOnly === "boolean")
|
|
@@ -6112,6 +6326,7 @@ function serializeSnapshot(s) {
|
|
|
6112
6326
|
baseUrl: s.baseUrl ?? null,
|
|
6113
6327
|
uiLocale: s.uiLocale ?? null,
|
|
6114
6328
|
fallbackModels: s.fallbackModels ?? null,
|
|
6329
|
+
fallbackBridge: s.fallbackBridge ?? null,
|
|
6115
6330
|
fallbackProfiles: s.fallbackProfiles ?? null,
|
|
6116
6331
|
favoriteModels: s.favoriteModels ?? null,
|
|
6117
6332
|
favoriteModelsOnly: s.favoriteModelsOnly ?? null,
|
|
@@ -6326,7 +6541,13 @@ var CONFIG_BEHAVIOR_DEFAULTS = {
|
|
|
6326
6541
|
// models still get cost savings without capability loss. Explicit tiers
|
|
6327
6542
|
// are respected verbatim.
|
|
6328
6543
|
tokenSavingMode: "auto",
|
|
6329
|
-
|
|
6544
|
+
// Derived, never written by hand: this and `tools.restrictToProjectRoot`
|
|
6545
|
+
// (line 41) are the two halves of one switch, and they used to be declared
|
|
6546
|
+
// independently in this same object — one `true`, one `true` — with
|
|
6547
|
+
// session.ts resolving the contradiction via `??` in favour of the
|
|
6548
|
+
// permissive half. The confinement guard therefore shipped disabled on a
|
|
6549
|
+
// fresh install even though the other half asked for it (WS-075).
|
|
6550
|
+
allowOutsideProjectRoot: !DEFAULT_TOOLS_CONFIG.restrictToProjectRoot
|
|
6330
6551
|
},
|
|
6331
6552
|
Sage: {
|
|
6332
6553
|
enabled: true,
|
|
@@ -6405,7 +6626,9 @@ var CONFIG_BEHAVIOR_DEFAULTS = {
|
|
|
6405
6626
|
enhance: true,
|
|
6406
6627
|
enhanceDelayMs: 6e4,
|
|
6407
6628
|
enhanceLanguage: "original",
|
|
6408
|
-
|
|
6629
|
+
// Product-wide statusline density default. Mirrored by the TUI's
|
|
6630
|
+
// DEFAULT_STATUSLINE_MODE (packages/tui/src/components/settings-picker-model.ts).
|
|
6631
|
+
statuslineMode: "minimum",
|
|
6409
6632
|
thinkingWord: DEFAULT_TUI_THINKING_WORD,
|
|
6410
6633
|
showAgentSwarmPanel: true
|
|
6411
6634
|
},
|
|
@@ -6574,6 +6797,7 @@ var IN_PROJECT_ALLOWED_KEYS = /* @__PURE__ */ new Set([
|
|
|
6574
6797
|
"maxConcurrent",
|
|
6575
6798
|
"uiLocale",
|
|
6576
6799
|
"fallbackModels",
|
|
6800
|
+
"fallbackBridge",
|
|
6577
6801
|
"fallbackProfiles",
|
|
6578
6802
|
"favoriteModels",
|
|
6579
6803
|
"favoriteModelsOnly",
|
|
@@ -6636,6 +6860,7 @@ var KNOWN_CONFIG_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set([
|
|
|
6636
6860
|
"tools",
|
|
6637
6861
|
"mcpServers",
|
|
6638
6862
|
"fallbackModels",
|
|
6863
|
+
"fallbackBridge",
|
|
6639
6864
|
"fallbackProfiles",
|
|
6640
6865
|
"favoriteModels",
|
|
6641
6866
|
"favoriteModelsOnly",
|
|
@@ -6670,6 +6895,75 @@ var KNOWN_CONFIG_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set([
|
|
|
6670
6895
|
"brain",
|
|
6671
6896
|
"git"
|
|
6672
6897
|
]);
|
|
6898
|
+
var IN_PROJECT_DENIED_PATHS = [
|
|
6899
|
+
{
|
|
6900
|
+
path: "tools.exec.allow",
|
|
6901
|
+
reason: "Extends the exec allow-list; a repo could authorise its own binaries."
|
|
6902
|
+
},
|
|
6903
|
+
{ path: "tools.exec.danger", reason: "Weakens the destructive-command banner." },
|
|
6904
|
+
{ path: "skills.extraDirs", reason: "Loads skill definitions from repo-chosen directories." },
|
|
6905
|
+
{ path: "skills.registryUrl", reason: "Redirects skill installs to a repo-chosen host." },
|
|
6906
|
+
// Deliberately NOT denied: skills.mode and skills.eagerMaxChars. The audit
|
|
6907
|
+
// suggested stripping both, but config-loader-extra.test.ts classifies `mode`
|
|
6908
|
+
// as a safe preference with a stated rationale, and a repo can only use these
|
|
6909
|
+
// to move injection volume in either direction — the trust problem was that
|
|
6910
|
+
// repo-supplied skill bodies were indistinguishable from the user's own, which
|
|
6911
|
+
// the provenance tag in system-prompt-skill-bodies.ts now fixes. Re-classifying
|
|
6912
|
+
// them is a product call.
|
|
6913
|
+
{ path: "Sage.storage.directory", reason: "Redirects memory storage outside the profile." },
|
|
6914
|
+
{
|
|
6915
|
+
path: "autonomy.yolo",
|
|
6916
|
+
reason: "Alias for the denied top-level `yolo`, and it wins over the user setting \u2014 a repo-committed config could disable every permission prompt."
|
|
6917
|
+
},
|
|
6918
|
+
{
|
|
6919
|
+
path: "autonomy.defaultMode",
|
|
6920
|
+
reason: "Sets the startup autonomy mode; autonomy is user-owned, never repo-owned."
|
|
6921
|
+
},
|
|
6922
|
+
// Deliberately NOT denied: autonomy.autoProceedDelayMs and
|
|
6923
|
+
// autoProceedMaxIterations. They tune a mode the user has already switched on
|
|
6924
|
+
// rather than granting it, and config-loader-extra.test.ts classifies the
|
|
6925
|
+
// delay as a benign project preference. Re-classifying them is a product call.
|
|
6926
|
+
{
|
|
6927
|
+
path: "launch.autonomy",
|
|
6928
|
+
reason: "Launch-time autonomy mode; same user-owned boundary as autonomy.defaultMode."
|
|
6929
|
+
},
|
|
6930
|
+
{
|
|
6931
|
+
path: "features.allowOutsideProjectRoot",
|
|
6932
|
+
reason: "Short-circuits both the project-root containment check and the symlink realpath check in the file tools."
|
|
6933
|
+
},
|
|
6934
|
+
{
|
|
6935
|
+
path: "tools.restrictToProjectRoot",
|
|
6936
|
+
reason: "The other half of the filesystem confinement switch."
|
|
6937
|
+
}
|
|
6938
|
+
];
|
|
6939
|
+
function deleteNestedPath(target, path30) {
|
|
6940
|
+
const segments = path30.split(".");
|
|
6941
|
+
const last = segments[segments.length - 1];
|
|
6942
|
+
if (last === void 0) return false;
|
|
6943
|
+
let cursor = target;
|
|
6944
|
+
const chain = [];
|
|
6945
|
+
for (const segment of segments.slice(0, -1)) {
|
|
6946
|
+
const next = cursor[segment];
|
|
6947
|
+
if (!next || typeof next !== "object" || Array.isArray(next)) return false;
|
|
6948
|
+
chain.push({ parent: cursor, key: segment });
|
|
6949
|
+
cursor = next;
|
|
6950
|
+
}
|
|
6951
|
+
if (!(last in cursor)) return false;
|
|
6952
|
+
const clonedLeaf = { ...cursor };
|
|
6953
|
+
delete clonedLeaf[last];
|
|
6954
|
+
let replacement = clonedLeaf;
|
|
6955
|
+
for (let i = chain.length - 1; i >= 0; i--) {
|
|
6956
|
+
const link2 = chain[i];
|
|
6957
|
+
if (!link2) continue;
|
|
6958
|
+
replacement = { ...link2.parent, [link2.key]: replacement };
|
|
6959
|
+
if (i === 0) {
|
|
6960
|
+
for (const [k, v] of Object.entries(replacement)) target[k] = v;
|
|
6961
|
+
return true;
|
|
6962
|
+
}
|
|
6963
|
+
}
|
|
6964
|
+
for (const [k, v] of Object.entries(replacement)) target[k] = v;
|
|
6965
|
+
return true;
|
|
6966
|
+
}
|
|
6673
6967
|
function assertInProjectAllowListComplete() {
|
|
6674
6968
|
const missingFromBoth = [];
|
|
6675
6969
|
for (const key of KNOWN_CONFIG_TOP_LEVEL_KEYS) {
|
|
@@ -6699,6 +6993,22 @@ function assertInProjectAllowListComplete() {
|
|
|
6699
6993
|
`field(s) appear in BOTH IN_PROJECT_ALLOWED_KEYS and KNOWN_DENIED_IN_PROJECT: ` + duplicate.join(", ") + ". The allow-list wins at runtime; remove from one of the two."
|
|
6700
6994
|
);
|
|
6701
6995
|
}
|
|
6996
|
+
const orphanedPaths = IN_PROJECT_DENIED_PATHS.filter(
|
|
6997
|
+
({ path: path30 }) => !IN_PROJECT_ALLOWED_KEYS.has(path30.split(".")[0] ?? "")
|
|
6998
|
+
).map(({ path: path30 }) => path30);
|
|
6999
|
+
if (orphanedPaths.length > 0) {
|
|
7000
|
+
problems.push(
|
|
7001
|
+
`IN_PROJECT_DENIED_PATHS entr(ies) whose top-level parent is not allowed: ` + orphanedPaths.join(", ") + ". The parent is already stripped wholesale, so the nested denial is dead \u2014 remove it."
|
|
7002
|
+
);
|
|
7003
|
+
}
|
|
7004
|
+
const malformedPaths = IN_PROJECT_DENIED_PATHS.filter(
|
|
7005
|
+
({ path: path30 }) => path30.split(".").length < 2 || path30.split(".").some((s) => s.length === 0)
|
|
7006
|
+
).map(({ path: path30 }) => path30);
|
|
7007
|
+
if (malformedPaths.length > 0) {
|
|
7008
|
+
problems.push(
|
|
7009
|
+
`IN_PROJECT_DENIED_PATHS entr(ies) are not dotted nested paths: ` + malformedPaths.join(", ") + ". Top-level keys belong in KNOWN_DENIED_IN_PROJECT instead."
|
|
7010
|
+
);
|
|
7011
|
+
}
|
|
6702
7012
|
if (problems.length > 0) {
|
|
6703
7013
|
throw new Error(
|
|
6704
7014
|
`stripUnsafeInProjectFields drift check failed:
|
|
@@ -6721,58 +7031,8 @@ function stripUnsafeInProjectFields(inProject, sourcePath, warn = (msg) => conso
|
|
|
6721
7031
|
}
|
|
6722
7032
|
stripped.push(k);
|
|
6723
7033
|
}
|
|
6724
|
-
const
|
|
6725
|
-
|
|
6726
|
-
const execCfg = outTools["exec"];
|
|
6727
|
-
if (execCfg && typeof execCfg === "object") {
|
|
6728
|
-
const hasAllow = "allow" in execCfg;
|
|
6729
|
-
const hasDanger = "danger" in execCfg;
|
|
6730
|
-
if (hasAllow || hasDanger) {
|
|
6731
|
-
const clonedExec = { ...execCfg };
|
|
6732
|
-
if (hasAllow) {
|
|
6733
|
-
delete clonedExec["allow"];
|
|
6734
|
-
stripped.push("tools.exec.allow");
|
|
6735
|
-
}
|
|
6736
|
-
if (hasDanger) {
|
|
6737
|
-
delete clonedExec["danger"];
|
|
6738
|
-
stripped.push("tools.exec.danger");
|
|
6739
|
-
}
|
|
6740
|
-
out["tools"] = {
|
|
6741
|
-
...outTools,
|
|
6742
|
-
exec: clonedExec
|
|
6743
|
-
};
|
|
6744
|
-
}
|
|
6745
|
-
}
|
|
6746
|
-
}
|
|
6747
|
-
const outSkills = out["skills"];
|
|
6748
|
-
if (outSkills && typeof outSkills === "object") {
|
|
6749
|
-
const skillsRec = outSkills;
|
|
6750
|
-
const needsClone = "extraDirs" in skillsRec || "registryUrl" in skillsRec;
|
|
6751
|
-
if (needsClone) {
|
|
6752
|
-
const clonedSkills = { ...skillsRec };
|
|
6753
|
-
if ("extraDirs" in clonedSkills) {
|
|
6754
|
-
delete clonedSkills["extraDirs"];
|
|
6755
|
-
stripped.push("skills.extraDirs");
|
|
6756
|
-
}
|
|
6757
|
-
if ("registryUrl" in clonedSkills) {
|
|
6758
|
-
delete clonedSkills["registryUrl"];
|
|
6759
|
-
stripped.push("skills.registryUrl");
|
|
6760
|
-
}
|
|
6761
|
-
out["skills"] = clonedSkills;
|
|
6762
|
-
}
|
|
6763
|
-
}
|
|
6764
|
-
const outSage = out["Sage"];
|
|
6765
|
-
if (outSage && typeof outSage === "object") {
|
|
6766
|
-
const storage = outSage["storage"];
|
|
6767
|
-
if (storage && typeof storage === "object" && "directory" in storage) {
|
|
6768
|
-
const clonedStorage = { ...storage };
|
|
6769
|
-
delete clonedStorage["directory"];
|
|
6770
|
-
out["Sage"] = {
|
|
6771
|
-
...outSage,
|
|
6772
|
-
storage: clonedStorage
|
|
6773
|
-
};
|
|
6774
|
-
stripped.push("Sage.storage.directory");
|
|
6775
|
-
}
|
|
7034
|
+
for (const { path: path30 } of IN_PROJECT_DENIED_PATHS) {
|
|
7035
|
+
if (deleteNestedPath(out, path30)) stripped.push(path30);
|
|
6776
7036
|
}
|
|
6777
7037
|
if (stripped.length > 0) {
|
|
6778
7038
|
warn(
|
|
@@ -7233,8 +7493,8 @@ var DefaultConfigLoader = class _DefaultConfigLoader {
|
|
|
7233
7493
|
const t0 = Date.now();
|
|
7234
7494
|
let mtimeMs = null;
|
|
7235
7495
|
try {
|
|
7236
|
-
const
|
|
7237
|
-
mtimeMs =
|
|
7496
|
+
const stat15 = await fs6.stat(file);
|
|
7497
|
+
mtimeMs = stat15.mtimeMs;
|
|
7238
7498
|
const cached = this.jsonCache.get(file);
|
|
7239
7499
|
if (cached && cached.mtimeMs === mtimeMs) {
|
|
7240
7500
|
return structuredClone(cached.value);
|
|
@@ -7572,72 +7832,15 @@ function isLockFile(v) {
|
|
|
7572
7832
|
var defaultIsPidAlive = isPidAlive;
|
|
7573
7833
|
|
|
7574
7834
|
// src/storage/session-reader.ts
|
|
7575
|
-
|
|
7576
|
-
var DefaultSessionReader = class _DefaultSessionReader {
|
|
7835
|
+
var DefaultSessionReader = class {
|
|
7577
7836
|
store;
|
|
7578
7837
|
secretScrubber;
|
|
7579
|
-
eventCache = /* @__PURE__ */ new Map();
|
|
7580
|
-
eventCacheMtimes = /* @__PURE__ */ new Map();
|
|
7581
|
-
eventCacheSizes = /* @__PURE__ */ new Map();
|
|
7582
|
-
eventCacheBytes = 0;
|
|
7583
|
-
static EVENT_CACHE_MAX_ENTRIES = 32;
|
|
7584
|
-
static EVENT_CACHE_MAX_BYTES = 32 * 1024 * 1024;
|
|
7585
7838
|
constructor(opts) {
|
|
7586
7839
|
this.store = opts.store;
|
|
7587
7840
|
this.secretScrubber = opts.secretScrubber ?? new DefaultSecretScrubber();
|
|
7588
7841
|
}
|
|
7589
7842
|
async loadCachedSessionData(sessionId) {
|
|
7590
|
-
|
|
7591
|
-
const rootDir = storeWithPath.dir;
|
|
7592
|
-
if (!rootDir) {
|
|
7593
|
-
return scrubPersistedSessionData(await this.store.load(sessionId), this.secretScrubber);
|
|
7594
|
-
}
|
|
7595
|
-
const sessionPath2 = sessionScopedPath(rootDir, sessionId, ".jsonl");
|
|
7596
|
-
let mtimeMs = null;
|
|
7597
|
-
let fileSize = 0;
|
|
7598
|
-
try {
|
|
7599
|
-
const stat16 = await fs7.stat(sessionPath2);
|
|
7600
|
-
mtimeMs = stat16.mtimeMs;
|
|
7601
|
-
fileSize = stat16.size;
|
|
7602
|
-
} catch {
|
|
7603
|
-
this.deleteEventCacheEntry(sessionId);
|
|
7604
|
-
return scrubPersistedSessionData(await this.store.load(sessionId), this.secretScrubber);
|
|
7605
|
-
}
|
|
7606
|
-
const cachedMtime = this.eventCacheMtimes.get(sessionId);
|
|
7607
|
-
const cachedData = this.eventCache.get(sessionId);
|
|
7608
|
-
if (cachedData && cachedMtime === mtimeMs) {
|
|
7609
|
-
this.eventCache.delete(sessionId);
|
|
7610
|
-
this.eventCacheMtimes.delete(sessionId);
|
|
7611
|
-
this.eventCacheSizes.delete(sessionId);
|
|
7612
|
-
this.eventCache.set(sessionId, cachedData);
|
|
7613
|
-
this.eventCacheMtimes.set(sessionId, mtimeMs);
|
|
7614
|
-
this.eventCacheSizes.set(sessionId, fileSize);
|
|
7615
|
-
return cachedData;
|
|
7616
|
-
}
|
|
7617
|
-
const data = scrubPersistedSessionData(await this.store.load(sessionId), this.secretScrubber);
|
|
7618
|
-
this.deleteEventCacheEntry(sessionId);
|
|
7619
|
-
if (fileSize <= _DefaultSessionReader.EVENT_CACHE_MAX_BYTES) {
|
|
7620
|
-
while (this.eventCache.size >= _DefaultSessionReader.EVENT_CACHE_MAX_ENTRIES || this.eventCacheBytes + fileSize > _DefaultSessionReader.EVENT_CACHE_MAX_BYTES) {
|
|
7621
|
-
const oldest = this.eventCache.keys().next().value;
|
|
7622
|
-
if (oldest === void 0) break;
|
|
7623
|
-
this.deleteEventCacheEntry(oldest);
|
|
7624
|
-
}
|
|
7625
|
-
this.eventCache.set(sessionId, data);
|
|
7626
|
-
this.eventCacheMtimes.set(sessionId, mtimeMs);
|
|
7627
|
-
this.eventCacheSizes.set(sessionId, fileSize);
|
|
7628
|
-
this.eventCacheBytes += fileSize;
|
|
7629
|
-
}
|
|
7630
|
-
if (data.metadata.endedAt) {
|
|
7631
|
-
storeWithPath.clearLoadCache?.(sessionId);
|
|
7632
|
-
}
|
|
7633
|
-
return data;
|
|
7634
|
-
}
|
|
7635
|
-
deleteEventCacheEntry(sessionId) {
|
|
7636
|
-
const size = this.eventCacheSizes.get(sessionId) ?? 0;
|
|
7637
|
-
this.eventCache.delete(sessionId);
|
|
7638
|
-
this.eventCacheMtimes.delete(sessionId);
|
|
7639
|
-
this.eventCacheSizes.delete(sessionId);
|
|
7640
|
-
this.eventCacheBytes = Math.max(0, this.eventCacheBytes - size);
|
|
7843
|
+
return scrubPersistedSessionData(await this.store.load(sessionId), this.secretScrubber);
|
|
7641
7844
|
}
|
|
7642
7845
|
async query(q = {}) {
|
|
7643
7846
|
const storeWithFilter = this.store;
|
|
@@ -7727,11 +7930,12 @@ var DefaultSessionReader = class _DefaultSessionReader {
|
|
|
7727
7930
|
id,
|
|
7728
7931
|
(rawEvent, eventIndex) => {
|
|
7729
7932
|
const ev = scrubPersistedSessionEvent(rawEvent, this.secretScrubber);
|
|
7730
|
-
scrubbedByIndex.set(eventIndex, ev);
|
|
7731
7933
|
if (allowedTypes && !allowedTypes.has(ev.type)) return false;
|
|
7732
7934
|
const text = eventText(ev);
|
|
7733
7935
|
if (text === null) return false;
|
|
7734
|
-
|
|
7936
|
+
const matched2 = matcher(text) !== null;
|
|
7937
|
+
if (matched2) scrubbedByIndex.set(eventIndex, ev);
|
|
7938
|
+
return matched2;
|
|
7735
7939
|
},
|
|
7736
7940
|
{ limit: limit - hits.length }
|
|
7737
7941
|
);
|
|
@@ -7979,7 +8183,7 @@ function renderPlainText(meta, events) {
|
|
|
7979
8183
|
|
|
7980
8184
|
// src/storage/annotations-store.ts
|
|
7981
8185
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
7982
|
-
import * as
|
|
8186
|
+
import * as fs7 from "node:fs/promises";
|
|
7983
8187
|
var FILE_VERSION = 1;
|
|
7984
8188
|
var MAX_TEXT_LENGTH = 2e3;
|
|
7985
8189
|
var MAX_ANNOTATIONS = 1e3;
|
|
@@ -8206,7 +8410,7 @@ var AnnotationsStore = class {
|
|
|
8206
8410
|
const fp = this.filePath(sessionId);
|
|
8207
8411
|
let raw;
|
|
8208
8412
|
try {
|
|
8209
|
-
raw = await
|
|
8413
|
+
raw = await fs7.readFile(fp, "utf8");
|
|
8210
8414
|
} catch (err) {
|
|
8211
8415
|
if (err.code === "ENOENT") return null;
|
|
8212
8416
|
throw err;
|
|
@@ -8244,7 +8448,7 @@ var AnnotationsStore = class {
|
|
|
8244
8448
|
};
|
|
8245
8449
|
|
|
8246
8450
|
// src/storage/replay-log-store.ts
|
|
8247
|
-
import * as
|
|
8451
|
+
import * as fs8 from "node:fs/promises";
|
|
8248
8452
|
import * as path21 from "node:path";
|
|
8249
8453
|
|
|
8250
8454
|
// src/replay/hash.ts
|
|
@@ -8335,12 +8539,12 @@ var ReplayLogStore = class _ReplayLogStore {
|
|
|
8335
8539
|
const line = JSON.stringify(entry) + "\n";
|
|
8336
8540
|
let offset2 = 0;
|
|
8337
8541
|
try {
|
|
8338
|
-
const
|
|
8339
|
-
offset2 =
|
|
8542
|
+
const stat15 = await fs8.stat(fp);
|
|
8543
|
+
offset2 = stat15.size;
|
|
8340
8544
|
} catch (err) {
|
|
8341
8545
|
if (err.code !== "ENOENT") throw err;
|
|
8342
8546
|
}
|
|
8343
|
-
await
|
|
8547
|
+
await fs8.appendFile(fp, line, { encoding: "utf8", mode: SECRET_FILE_MODE });
|
|
8344
8548
|
cache.set(hash, { entry, offset: offset2, length: Buffer.byteLength(line, "utf8") });
|
|
8345
8549
|
this.diskCount.set(input.sessionId, currentCount + 1);
|
|
8346
8550
|
this.events?.emit("storage.write", {
|
|
@@ -8468,7 +8672,7 @@ var ReplayLogStore = class _ReplayLogStore {
|
|
|
8468
8672
|
const scan = async (dir, prefix, depth) => {
|
|
8469
8673
|
let entries;
|
|
8470
8674
|
try {
|
|
8471
|
-
entries = await
|
|
8675
|
+
entries = await fs8.readdir(dir, { withFileTypes: true });
|
|
8472
8676
|
} catch (err) {
|
|
8473
8677
|
if (depth === 0 && err.code !== "ENOENT") {
|
|
8474
8678
|
console.warn(
|
|
@@ -8508,7 +8712,7 @@ var ReplayLogStore = class _ReplayLogStore {
|
|
|
8508
8712
|
return sessionScopedPath(this.dir, sessionId, ".replay.jsonl");
|
|
8509
8713
|
}
|
|
8510
8714
|
async countEntries(filePath) {
|
|
8511
|
-
const handle = await
|
|
8715
|
+
const handle = await fs8.open(filePath, "r");
|
|
8512
8716
|
const buffer = Buffer.allocUnsafe(64 * 1024);
|
|
8513
8717
|
let count = 0;
|
|
8514
8718
|
let hasNonWhitespace2 = false;
|
|
@@ -8549,7 +8753,7 @@ var ReplayLogStore = class _ReplayLogStore {
|
|
|
8549
8753
|
async readAll(sessionId) {
|
|
8550
8754
|
const fp = this.filePath(sessionId);
|
|
8551
8755
|
try {
|
|
8552
|
-
const raw = await
|
|
8756
|
+
const raw = await fs8.readFile(fp, "utf8");
|
|
8553
8757
|
const out = [];
|
|
8554
8758
|
for (const line of raw.split("\n")) {
|
|
8555
8759
|
if (!line.trim()) continue;
|
|
@@ -8589,7 +8793,7 @@ var ReplayLogStore = class _ReplayLogStore {
|
|
|
8589
8793
|
const fp = this.filePath(sessionId);
|
|
8590
8794
|
cache = /* @__PURE__ */ new Map();
|
|
8591
8795
|
try {
|
|
8592
|
-
const handle = await
|
|
8796
|
+
const handle = await fs8.open(fp, "r");
|
|
8593
8797
|
const CHUNK = 64 * 1024;
|
|
8594
8798
|
const buffer = Buffer.alloc(CHUNK);
|
|
8595
8799
|
let leftover = "";
|
|
@@ -8675,7 +8879,7 @@ var ReplayLogStore = class _ReplayLogStore {
|
|
|
8675
8879
|
const fp = this.filePath(sessionId);
|
|
8676
8880
|
let handle;
|
|
8677
8881
|
try {
|
|
8678
|
-
handle = await
|
|
8882
|
+
handle = await fs8.open(fp, "r");
|
|
8679
8883
|
} catch {
|
|
8680
8884
|
return null;
|
|
8681
8885
|
}
|
|
@@ -8703,7 +8907,7 @@ var ReplayLogStore = class _ReplayLogStore {
|
|
|
8703
8907
|
|
|
8704
8908
|
// src/storage/session-recovery.ts
|
|
8705
8909
|
import { createReadStream as createReadStream4 } from "node:fs";
|
|
8706
|
-
import * as
|
|
8910
|
+
import * as fs9 from "node:fs/promises";
|
|
8707
8911
|
import * as path22 from "node:path";
|
|
8708
8912
|
import { createInterface as createInterface4 } from "node:readline";
|
|
8709
8913
|
var SessionRecovery = class _SessionRecovery {
|
|
@@ -8741,16 +8945,16 @@ var SessionRecovery = class _SessionRecovery {
|
|
|
8741
8945
|
}
|
|
8742
8946
|
async detectStaleExact(sessionId) {
|
|
8743
8947
|
const fp = this.filePath(sessionId);
|
|
8744
|
-
let
|
|
8948
|
+
let stat15;
|
|
8745
8949
|
try {
|
|
8746
|
-
|
|
8950
|
+
stat15 = await fs9.stat(fp);
|
|
8747
8951
|
} catch (err) {
|
|
8748
8952
|
if (err.code === "ENOENT") return null;
|
|
8749
8953
|
return null;
|
|
8750
8954
|
}
|
|
8751
|
-
if (
|
|
8955
|
+
if (stat15.size === 0) return null;
|
|
8752
8956
|
try {
|
|
8753
|
-
const scan = await scanLatestLifecycleBoundary(fp,
|
|
8957
|
+
const scan = await scanLatestLifecycleBoundary(fp, stat15.size);
|
|
8754
8958
|
if (scan?.boundary.type !== "in_flight_start") return null;
|
|
8755
8959
|
return {
|
|
8756
8960
|
sessionId,
|
|
@@ -8843,7 +9047,7 @@ var SessionRecovery = class _SessionRecovery {
|
|
|
8843
9047
|
const collect = async (dir, prefix, depth) => {
|
|
8844
9048
|
let entries;
|
|
8845
9049
|
try {
|
|
8846
|
-
entries = await
|
|
9050
|
+
entries = await fs9.readdir(dir, { withFileTypes: true });
|
|
8847
9051
|
} catch {
|
|
8848
9052
|
return;
|
|
8849
9053
|
}
|
|
@@ -8894,7 +9098,7 @@ function hasNonWhitespace(line) {
|
|
|
8894
9098
|
}
|
|
8895
9099
|
async function scanLatestLifecycleBoundary(filePath, size) {
|
|
8896
9100
|
const CHUNK_SIZE2 = 64 * 1024;
|
|
8897
|
-
const handle = await
|
|
9101
|
+
const handle = await fs9.open(filePath, "r");
|
|
8898
9102
|
let position = size;
|
|
8899
9103
|
let laterLineFragment = Buffer.alloc(0);
|
|
8900
9104
|
let latestBoundary = null;
|
|
@@ -8933,7 +9137,7 @@ async function scanLatestLifecycleBoundary(filePath, size) {
|
|
|
8933
9137
|
|
|
8934
9138
|
// src/storage/tool-audit-log.ts
|
|
8935
9139
|
import { createHash as createHash6, randomUUID as randomUUID4 } from "node:crypto";
|
|
8936
|
-
import * as
|
|
9140
|
+
import * as fs10 from "node:fs/promises";
|
|
8937
9141
|
var GENESIS_PREV = "0".repeat(64);
|
|
8938
9142
|
var DEFAULT_FSYNC_EVERY = 100;
|
|
8939
9143
|
var ToolAuditLog = class {
|
|
@@ -9003,9 +9207,15 @@ var ToolAuditLog = class {
|
|
|
9003
9207
|
isError: input.isError,
|
|
9004
9208
|
index
|
|
9005
9209
|
};
|
|
9006
|
-
await
|
|
9210
|
+
await fs10.appendFile(fp, JSON.stringify(entry) + "\n", {
|
|
9211
|
+
encoding: "utf8",
|
|
9212
|
+
// WS-035: this file records raw tool INPUT and OUTPUT. Created
|
|
9213
|
+
// without a mode it lands 0644 — world-readable — while its
|
|
9214
|
+
// siblings under the same directory correctly use 0600.
|
|
9215
|
+
mode: SECRET_FILE_MODE
|
|
9216
|
+
});
|
|
9007
9217
|
try {
|
|
9008
|
-
const st = await
|
|
9218
|
+
const st = await fs10.stat(fp);
|
|
9009
9219
|
this.tailStat.set(input.sessionId, { mtimeMs: st.mtimeMs, size: st.size });
|
|
9010
9220
|
} catch {
|
|
9011
9221
|
}
|
|
@@ -9052,7 +9262,7 @@ var ToolAuditLog = class {
|
|
|
9052
9262
|
const cachedStat = this.tailStat.get(sessionId);
|
|
9053
9263
|
if (cachedHash !== void 0 && cachedIndex !== void 0 && cachedStat) {
|
|
9054
9264
|
try {
|
|
9055
|
-
const st = await
|
|
9265
|
+
const st = await fs10.stat(fp);
|
|
9056
9266
|
if (st.mtimeMs === cachedStat.mtimeMs && st.size === cachedStat.size) {
|
|
9057
9267
|
return { prevHash: cachedHash, nextIndex: cachedIndex };
|
|
9058
9268
|
}
|
|
@@ -9073,7 +9283,7 @@ var ToolAuditLog = class {
|
|
|
9073
9283
|
this.tailHash.set(sessionId, prevHash);
|
|
9074
9284
|
this.tailIndex.set(sessionId, nextIndex);
|
|
9075
9285
|
try {
|
|
9076
|
-
const st = await
|
|
9286
|
+
const st = await fs10.stat(fp);
|
|
9077
9287
|
this.tailStat.set(sessionId, { mtimeMs: st.mtimeMs, size: st.size });
|
|
9078
9288
|
} catch {
|
|
9079
9289
|
}
|
|
@@ -9194,7 +9404,7 @@ var ToolAuditLog = class {
|
|
|
9194
9404
|
async readAll(sessionId) {
|
|
9195
9405
|
const fp = this.filePath(sessionId);
|
|
9196
9406
|
try {
|
|
9197
|
-
const raw = await
|
|
9407
|
+
const raw = await fs10.readFile(fp, "utf8");
|
|
9198
9408
|
const out = [];
|
|
9199
9409
|
for (const line of raw.split("\n")) {
|
|
9200
9410
|
if (!line.trim()) continue;
|
|
@@ -9232,7 +9442,7 @@ var ToolAuditLog = class {
|
|
|
9232
9442
|
}
|
|
9233
9443
|
async sync(sessionId, fp) {
|
|
9234
9444
|
try {
|
|
9235
|
-
const fh = await
|
|
9445
|
+
const fh = await fs10.open(fp, "r+");
|
|
9236
9446
|
try {
|
|
9237
9447
|
await fh.sync();
|
|
9238
9448
|
} finally {
|
|
@@ -9240,7 +9450,7 @@ var ToolAuditLog = class {
|
|
|
9240
9450
|
}
|
|
9241
9451
|
} catch {
|
|
9242
9452
|
} finally {
|
|
9243
|
-
this.unSyncedWrites.
|
|
9453
|
+
this.unSyncedWrites.delete(sessionId);
|
|
9244
9454
|
}
|
|
9245
9455
|
}
|
|
9246
9456
|
enqueue(sessionId, fn) {
|
|
@@ -9371,29 +9581,29 @@ var SessionAnalyzer = class {
|
|
|
9371
9581
|
};
|
|
9372
9582
|
|
|
9373
9583
|
// src/session-registry.ts
|
|
9374
|
-
import * as
|
|
9584
|
+
import * as fs12 from "node:fs/promises";
|
|
9375
9585
|
import * as path24 from "node:path";
|
|
9376
9586
|
|
|
9377
9587
|
// src/session-registry-atomic-file.ts
|
|
9378
9588
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
9379
|
-
import * as
|
|
9589
|
+
import * as fs11 from "node:fs/promises";
|
|
9380
9590
|
import * as path23 from "node:path";
|
|
9381
9591
|
var STALE_LOCK_MS = 1e4;
|
|
9382
9592
|
var STALE_TMP_MS = 6e4;
|
|
9383
9593
|
var MAX_STALE_TMP_FILES = 20;
|
|
9384
9594
|
async function breakStaleLock(lockPath) {
|
|
9385
9595
|
try {
|
|
9386
|
-
const [
|
|
9387
|
-
|
|
9596
|
+
const [stat15, content] = await Promise.all([
|
|
9597
|
+
fs11.stat(lockPath),
|
|
9388
9598
|
/* v8 ignore start -- best-effort lock-content read; .catch only fires if the lock vanished */
|
|
9389
|
-
|
|
9599
|
+
fs11.readFile(lockPath, "utf8").catch(() => "")
|
|
9390
9600
|
/* v8 ignore stop */
|
|
9391
9601
|
]);
|
|
9392
|
-
const ageMs = Date.now() -
|
|
9602
|
+
const ageMs = Date.now() - stat15.mtimeMs;
|
|
9393
9603
|
const ownerPid = Number.parseInt(content.trim(), 10);
|
|
9394
9604
|
const ownerDead = Number.isInteger(ownerPid) && ownerPid > 0 && ownerPid !== process.pid && !isPidAlive(ownerPid);
|
|
9395
9605
|
if (ownerDead || ageMs > STALE_LOCK_MS) {
|
|
9396
|
-
await
|
|
9606
|
+
await fs11.unlink(lockPath).catch(() => void 0);
|
|
9397
9607
|
return true;
|
|
9398
9608
|
}
|
|
9399
9609
|
return false;
|
|
@@ -9408,7 +9618,7 @@ async function writeAtomicFile(filePath, registry) {
|
|
|
9408
9618
|
);
|
|
9409
9619
|
let tmpPersisted = false;
|
|
9410
9620
|
try {
|
|
9411
|
-
const handle = await
|
|
9621
|
+
const handle = await fs11.open(tmp, "w");
|
|
9412
9622
|
try {
|
|
9413
9623
|
await handle.writeFile(JSON.stringify(registry, null, 2), "utf8");
|
|
9414
9624
|
await handle.sync().catch(() => void 0);
|
|
@@ -9417,14 +9627,14 @@ async function writeAtomicFile(filePath, registry) {
|
|
|
9417
9627
|
}
|
|
9418
9628
|
tmpPersisted = true;
|
|
9419
9629
|
try {
|
|
9420
|
-
await
|
|
9630
|
+
await fs11.rename(tmp, filePath);
|
|
9421
9631
|
tmpPersisted = false;
|
|
9422
9632
|
} catch (renameErr) {
|
|
9423
9633
|
const code = renameErr?.code;
|
|
9424
9634
|
if (code === "EPERM" || code === "EBUSY" || code === "EACCES") {
|
|
9425
|
-
await
|
|
9635
|
+
await fs11.copyFile(tmp, filePath);
|
|
9426
9636
|
try {
|
|
9427
|
-
const destHandle = await
|
|
9637
|
+
const destHandle = await fs11.open(filePath, "r+");
|
|
9428
9638
|
try {
|
|
9429
9639
|
await destHandle.sync().catch(() => void 0);
|
|
9430
9640
|
} finally {
|
|
@@ -9432,14 +9642,14 @@ async function writeAtomicFile(filePath, registry) {
|
|
|
9432
9642
|
}
|
|
9433
9643
|
} catch {
|
|
9434
9644
|
}
|
|
9435
|
-
await
|
|
9645
|
+
await fs11.unlink(tmp).catch(() => void 0);
|
|
9436
9646
|
tmpPersisted = false;
|
|
9437
9647
|
} else {
|
|
9438
9648
|
throw renameErr;
|
|
9439
9649
|
}
|
|
9440
9650
|
}
|
|
9441
9651
|
} catch (err) {
|
|
9442
|
-
if (tmpPersisted) await
|
|
9652
|
+
if (tmpPersisted) await fs11.unlink(tmp).catch(() => void 0);
|
|
9443
9653
|
throw err;
|
|
9444
9654
|
}
|
|
9445
9655
|
}
|
|
@@ -9449,17 +9659,17 @@ async function pruneStaleTempFiles(filePath) {
|
|
|
9449
9659
|
const base = path23.basename(filePath);
|
|
9450
9660
|
const now = Date.now();
|
|
9451
9661
|
const stale = [];
|
|
9452
|
-
for (const name of await
|
|
9662
|
+
for (const name of await fs11.readdir(dir)) {
|
|
9453
9663
|
const isTemp = (name.startsWith(`${base}.`) || name.startsWith(`.${base}.`)) && name.endsWith(".tmp");
|
|
9454
9664
|
if (!isTemp) continue;
|
|
9455
|
-
const
|
|
9456
|
-
if (!
|
|
9457
|
-
if (now -
|
|
9665
|
+
const stat15 = await fs11.stat(path23.join(dir, name)).catch(() => null);
|
|
9666
|
+
if (!stat15) continue;
|
|
9667
|
+
if (now - stat15.mtimeMs > STALE_TMP_MS) stale.push({ name, mtimeMs: stat15.mtimeMs });
|
|
9458
9668
|
}
|
|
9459
9669
|
stale.sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
9460
9670
|
await Promise.all(
|
|
9461
9671
|
stale.slice(MAX_STALE_TMP_FILES).map(async ({ name }) => {
|
|
9462
|
-
await
|
|
9672
|
+
await fs11.unlink(path23.join(dir, name)).catch(() => void 0);
|
|
9463
9673
|
})
|
|
9464
9674
|
);
|
|
9465
9675
|
} catch {
|
|
@@ -9762,7 +9972,7 @@ var SessionRegistry = class {
|
|
|
9762
9972
|
}
|
|
9763
9973
|
async readAndPrune() {
|
|
9764
9974
|
try {
|
|
9765
|
-
const raw = await
|
|
9975
|
+
const raw = await fs12.readFile(this.filePath, "utf8");
|
|
9766
9976
|
const registry = parseRegistry(raw);
|
|
9767
9977
|
const observed = new Map(
|
|
9768
9978
|
Object.entries(registry).map(([id, entry]) => [
|
|
@@ -9833,7 +10043,7 @@ var SessionRegistry = class {
|
|
|
9833
10043
|
const deadline = Date.now() + waitBudgetMs;
|
|
9834
10044
|
let attempt = 0;
|
|
9835
10045
|
try {
|
|
9836
|
-
await
|
|
10046
|
+
await fs12.mkdir(path24.dirname(this.filePath), { recursive: true });
|
|
9837
10047
|
await this.maybePruneStaleTempFiles();
|
|
9838
10048
|
} catch (err) {
|
|
9839
10049
|
if (required) {
|
|
@@ -9845,10 +10055,10 @@ var SessionRegistry = class {
|
|
|
9845
10055
|
}
|
|
9846
10056
|
while (true) {
|
|
9847
10057
|
try {
|
|
9848
|
-
let lockHandle = await
|
|
10058
|
+
let lockHandle = await fs12.open(lockPath, "wx").catch(() => null);
|
|
9849
10059
|
if (!lockHandle) {
|
|
9850
10060
|
if (await breakStaleLock(lockPath)) {
|
|
9851
|
-
lockHandle = await
|
|
10061
|
+
lockHandle = await fs12.open(lockPath, "wx").catch(() => null);
|
|
9852
10062
|
}
|
|
9853
10063
|
if (!lockHandle) {
|
|
9854
10064
|
const remainingMs = deadline - Date.now();
|
|
@@ -9863,14 +10073,14 @@ var SessionRegistry = class {
|
|
|
9863
10073
|
}
|
|
9864
10074
|
try {
|
|
9865
10075
|
await lockHandle.writeFile(String(process.pid)).catch(() => void 0);
|
|
9866
|
-
const raw = await
|
|
10076
|
+
const raw = await fs12.readFile(this.filePath, "utf8").catch(() => "{}");
|
|
9867
10077
|
const registry = parseRegistry(raw);
|
|
9868
10078
|
fn(registry);
|
|
9869
10079
|
await this.writeAtomicWithRetry(registry);
|
|
9870
10080
|
return;
|
|
9871
10081
|
} finally {
|
|
9872
10082
|
await lockHandle.close();
|
|
9873
|
-
await
|
|
10083
|
+
await fs12.unlink(lockPath).catch(() => void 0);
|
|
9874
10084
|
}
|
|
9875
10085
|
} catch (err) {
|
|
9876
10086
|
if (err instanceof SessionOwnershipConflictError) throw err;
|
|
@@ -10706,7 +10916,7 @@ var AgentStatusTracker = class _AgentStatusTracker {
|
|
|
10706
10916
|
};
|
|
10707
10917
|
|
|
10708
10918
|
// src/fleet-notifier.ts
|
|
10709
|
-
import * as
|
|
10919
|
+
import * as fs13 from "node:fs/promises";
|
|
10710
10920
|
import * as path25 from "node:path";
|
|
10711
10921
|
var INSTANCES_FILE = "webui-instances.json";
|
|
10712
10922
|
var DISCOVERY_TTL_MS = 2500;
|
|
@@ -10766,7 +10976,7 @@ var FleetNotifier = class {
|
|
|
10766
10976
|
}
|
|
10767
10977
|
async discover() {
|
|
10768
10978
|
try {
|
|
10769
|
-
const raw = await
|
|
10979
|
+
const raw = await fs13.readFile(path25.join(this.baseDir, INSTANCES_FILE), "utf8");
|
|
10770
10980
|
const data = JSON.parse(raw);
|
|
10771
10981
|
const list = Array.isArray(data?.instances) ? data.instances : [];
|
|
10772
10982
|
return list.filter((i) => i && typeof i.httpPort === "number").filter((i) => i.pid !== this.selfPid).filter((i) => normRoot(i.projectRoot) === this.projectRoot).filter((i) => pidAlive2(i.pid)).map((i) => {
|
|
@@ -12322,6 +12532,11 @@ function applyGoalDeliverableCompletions(goal, completed) {
|
|
|
12322
12532
|
(item, index) => completedIndices.has(index) && !isGoalDeliverableComplete(item) ? `\u2705 ${item}` : item
|
|
12323
12533
|
)
|
|
12324
12534
|
};
|
|
12535
|
+
next = appendGoalDeliverableJournals(next, completed);
|
|
12536
|
+
return recomputeGoalProgress(next);
|
|
12537
|
+
}
|
|
12538
|
+
function appendGoalDeliverableJournals(goal, completed) {
|
|
12539
|
+
let next = goal;
|
|
12325
12540
|
for (const item of completed) {
|
|
12326
12541
|
next = appendJournal(next, {
|
|
12327
12542
|
source: "deliverable",
|
|
@@ -12330,7 +12545,7 @@ function applyGoalDeliverableCompletions(goal, completed) {
|
|
|
12330
12545
|
note: `[DONE: ${item.index + 1}]`
|
|
12331
12546
|
});
|
|
12332
12547
|
}
|
|
12333
|
-
return
|
|
12548
|
+
return next;
|
|
12334
12549
|
}
|
|
12335
12550
|
function recomputeGoalProgress(goal) {
|
|
12336
12551
|
const deliverables = goal.deliverables ?? [];
|
|
@@ -12343,10 +12558,19 @@ async function coordinateGoalIteration(options) {
|
|
|
12343
12558
|
const current = await loadGoal(options.goalPath, options.events);
|
|
12344
12559
|
if (!current) return null;
|
|
12345
12560
|
const completed = parseCompletedGoalDeliverables(options.finalText, current.deliverables ?? []);
|
|
12346
|
-
|
|
12347
|
-
|
|
12348
|
-
|
|
12349
|
-
|
|
12561
|
+
const board = await resolveGoalBoard(options.projectRoot, current);
|
|
12562
|
+
let kanbanUpdatedTaskIds = [];
|
|
12563
|
+
let goal;
|
|
12564
|
+
if (board) {
|
|
12565
|
+
kanbanUpdatedTaskIds = await refreshGoalKanban(options.projectRoot, current, completed, board);
|
|
12566
|
+
goal = await recomputeGoalProgressFromKanban(options.projectRoot, current);
|
|
12567
|
+
const confirmed = completed.filter(
|
|
12568
|
+
(item) => !isGoalDeliverableComplete(current.deliverables?.[item.index] ?? "") && isGoalDeliverableComplete(goal.deliverables?.[item.index] ?? "")
|
|
12569
|
+
);
|
|
12570
|
+
goal = appendGoalDeliverableJournals(goal, confirmed);
|
|
12571
|
+
} else {
|
|
12572
|
+
goal = applyGoalDeliverableCompletions(current, completed);
|
|
12573
|
+
}
|
|
12350
12574
|
let reached = false;
|
|
12351
12575
|
const allComplete = (goal.deliverables?.length ?? 0) > 0 && goal.deliverables?.every(isGoalDeliverableComplete) === true;
|
|
12352
12576
|
if (allComplete && options.brain) {
|
|
@@ -12411,9 +12635,9 @@ async function resolveGoalBoard(projectRoot, goal) {
|
|
|
12411
12635
|
}
|
|
12412
12636
|
return findGoalBoardByTag(projectRoot, goal);
|
|
12413
12637
|
}
|
|
12414
|
-
async function refreshGoalKanban(projectRoot, goal, completed) {
|
|
12638
|
+
async function refreshGoalKanban(projectRoot, goal, completed, resolvedBoard) {
|
|
12415
12639
|
if (completed.length === 0) return [];
|
|
12416
|
-
const board = await resolveGoalBoard(projectRoot, goal);
|
|
12640
|
+
const board = resolvedBoard ?? await resolveGoalBoard(projectRoot, goal);
|
|
12417
12641
|
if (!board) return [];
|
|
12418
12642
|
const doneColumn = board.columns.find((column) => column.title.toLowerCase() === "done");
|
|
12419
12643
|
if (!doneColumn) return [];
|
|
@@ -12422,7 +12646,7 @@ async function refreshGoalKanban(projectRoot, goal, completed) {
|
|
|
12422
12646
|
const updated = [];
|
|
12423
12647
|
for (const task of board.tasks) {
|
|
12424
12648
|
const originMatch = task.origin?.system === "goal" && task.origin?.taskId ? originKeys.has(task.origin.taskId) : false;
|
|
12425
|
-
const titleMatch = completedTitles.has(normalizeTitle(task.title));
|
|
12649
|
+
const titleMatch = !task.origin?.taskId && completedTitles.has(normalizeTitle(task.title));
|
|
12426
12650
|
if (!originMatch && !titleMatch) continue;
|
|
12427
12651
|
const result = await updateTask(
|
|
12428
12652
|
projectRoot,
|
|
@@ -12441,12 +12665,17 @@ async function refreshGoalKanban(projectRoot, goal, completed) {
|
|
|
12441
12665
|
async function recomputeGoalProgressFromKanban(projectRoot, goal) {
|
|
12442
12666
|
const board = await resolveGoalBoard(projectRoot, goal);
|
|
12443
12667
|
if (!board || !goal.deliverables?.length) return recomputeGoalProgress(goal);
|
|
12444
|
-
const
|
|
12445
|
-
board.tasks.filter((task) => task.
|
|
12668
|
+
const tasksByOrigin = new Map(
|
|
12669
|
+
board.tasks.filter((task) => task.origin?.system === "goal" && task.origin.taskId).map((task) => [task.origin.taskId, task])
|
|
12446
12670
|
);
|
|
12447
|
-
const
|
|
12448
|
-
|
|
12449
|
-
|
|
12671
|
+
const completedLegacyTitles = new Set(
|
|
12672
|
+
board.tasks.filter((task) => !task.origin?.taskId && task.status === "completed").map((task) => normalizeTitle(task.title))
|
|
12673
|
+
);
|
|
12674
|
+
const deliverables = goal.deliverables.map((item, index) => {
|
|
12675
|
+
const text = stripGoalDeliverableMarker(item);
|
|
12676
|
+
const originTask = tasksByOrigin.get(`deliverable:${index}`);
|
|
12677
|
+
const complete = originTask ? originTask.status === "completed" : completedLegacyTitles.has(normalizeTitle(text)) || isGoalDeliverableComplete(item);
|
|
12678
|
+
return complete ? `\u2705 ${text}` : text;
|
|
12450
12679
|
});
|
|
12451
12680
|
return recomputeGoalProgress({ ...goal, deliverables });
|
|
12452
12681
|
}
|
|
@@ -12456,7 +12685,7 @@ function normalizeTitle(value) {
|
|
|
12456
12685
|
|
|
12457
12686
|
// src/storage/prompt-store.ts
|
|
12458
12687
|
import { createHash as createHash7 } from "node:crypto";
|
|
12459
|
-
import * as
|
|
12688
|
+
import * as fs14 from "node:fs/promises";
|
|
12460
12689
|
import * as path27 from "node:path";
|
|
12461
12690
|
var SCHEMA_VERSION = 2;
|
|
12462
12691
|
function promptChecksum(content) {
|
|
@@ -12472,7 +12701,7 @@ function migratePromptEntry(raw) {
|
|
|
12472
12701
|
const tags = Array.isArray(r["tags"]) ? r["tags"].filter((t) => typeof t === "string") : [];
|
|
12473
12702
|
return {
|
|
12474
12703
|
id: r["id"],
|
|
12475
|
-
slug: typeof r["slug"] === "string" && r["slug"].length > 0 ? r["slug"] :
|
|
12704
|
+
slug: typeof r["slug"] === "string" && r["slug"].length > 0 ? r["slug"] : slugify2(title),
|
|
12476
12705
|
title,
|
|
12477
12706
|
description: typeof r["description"] === "string" ? r["description"] : "",
|
|
12478
12707
|
content,
|
|
@@ -12521,12 +12750,12 @@ var DefaultPromptStore = class {
|
|
|
12521
12750
|
await ensureDir(this.dir);
|
|
12522
12751
|
const entries = [];
|
|
12523
12752
|
try {
|
|
12524
|
-
const files = await
|
|
12753
|
+
const files = await fs14.readdir(this.dir);
|
|
12525
12754
|
for (const file of files) {
|
|
12526
12755
|
if (!file.endsWith(".json")) continue;
|
|
12527
12756
|
try {
|
|
12528
12757
|
const raw = JSON.parse(
|
|
12529
|
-
await
|
|
12758
|
+
await fs14.readFile(path27.join(this.dir, file), "utf8")
|
|
12530
12759
|
);
|
|
12531
12760
|
const migrated = migratePromptEntry(raw.entry);
|
|
12532
12761
|
if (migrated) entries.push(migrated);
|
|
@@ -12542,7 +12771,7 @@ var DefaultPromptStore = class {
|
|
|
12542
12771
|
async get(id) {
|
|
12543
12772
|
const file = path27.join(this.dir, `${id}.json`);
|
|
12544
12773
|
try {
|
|
12545
|
-
const raw = JSON.parse(await
|
|
12774
|
+
const raw = JSON.parse(await fs14.readFile(file, "utf8"));
|
|
12546
12775
|
return migratePromptEntry(raw.entry);
|
|
12547
12776
|
} catch {
|
|
12548
12777
|
return null;
|
|
@@ -12557,7 +12786,7 @@ var DefaultPromptStore = class {
|
|
|
12557
12786
|
async delete(id) {
|
|
12558
12787
|
const file = path27.join(this.dir, `${id}.json`);
|
|
12559
12788
|
try {
|
|
12560
|
-
await
|
|
12789
|
+
await fs14.unlink(file);
|
|
12561
12790
|
return true;
|
|
12562
12791
|
} catch {
|
|
12563
12792
|
return false;
|
|
@@ -12575,7 +12804,7 @@ var DefaultPromptStore = class {
|
|
|
12575
12804
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
12576
12805
|
return {
|
|
12577
12806
|
id: ulid(),
|
|
12578
|
-
slug: extra.slug && extra.slug.length > 0 ? extra.slug :
|
|
12807
|
+
slug: extra.slug && extra.slug.length > 0 ? extra.slug : slugify2(title),
|
|
12579
12808
|
title,
|
|
12580
12809
|
description: extra.description ?? "",
|
|
12581
12810
|
content,
|
|
@@ -12596,7 +12825,7 @@ var DefaultPromptStore = class {
|
|
|
12596
12825
|
};
|
|
12597
12826
|
|
|
12598
12827
|
// src/storage/prompt-usage-store.ts
|
|
12599
|
-
import * as
|
|
12828
|
+
import * as fs15 from "node:fs/promises";
|
|
12600
12829
|
var PromptUsageStore = class {
|
|
12601
12830
|
constructor(file) {
|
|
12602
12831
|
this.file = file;
|
|
@@ -12616,7 +12845,7 @@ var PromptUsageStore = class {
|
|
|
12616
12845
|
return this.cachedUsage;
|
|
12617
12846
|
}
|
|
12618
12847
|
try {
|
|
12619
|
-
const raw = JSON.parse(await
|
|
12848
|
+
const raw = JSON.parse(await fs15.readFile(this.file, "utf8"));
|
|
12620
12849
|
if (raw && typeof raw === "object" && raw.usage && typeof raw.usage === "object") {
|
|
12621
12850
|
this.cachedUsage = raw.usage;
|
|
12622
12851
|
this.cachedSignature = signature;
|
|
@@ -12696,8 +12925,8 @@ var PromptUsageStore = class {
|
|
|
12696
12925
|
}
|
|
12697
12926
|
async fileSignature() {
|
|
12698
12927
|
try {
|
|
12699
|
-
const
|
|
12700
|
-
return { size:
|
|
12928
|
+
const stat15 = await fs15.stat(this.file);
|
|
12929
|
+
return { size: stat15.size, mtimeMs: stat15.mtimeMs, ctimeMs: stat15.ctimeMs };
|
|
12701
12930
|
} catch {
|
|
12702
12931
|
return null;
|
|
12703
12932
|
}
|
|
@@ -12712,7 +12941,7 @@ function cloneUsage(usage) {
|
|
|
12712
12941
|
}
|
|
12713
12942
|
|
|
12714
12943
|
// src/storage/input-history-store.ts
|
|
12715
|
-
import * as
|
|
12944
|
+
import * as fs16 from "node:fs/promises";
|
|
12716
12945
|
import * as path28 from "node:path";
|
|
12717
12946
|
var INPUT_HISTORY_DEFAULT_MAX = 100;
|
|
12718
12947
|
var InputHistoryStore = class {
|
|
@@ -12735,7 +12964,7 @@ var InputHistoryStore = class {
|
|
|
12735
12964
|
*/
|
|
12736
12965
|
async load() {
|
|
12737
12966
|
try {
|
|
12738
|
-
const raw = JSON.parse(await
|
|
12967
|
+
const raw = JSON.parse(await fs16.readFile(this.file, "utf8"));
|
|
12739
12968
|
if (raw && typeof raw === "object" && Array.isArray(raw.entries) && raw.entries.every((e) => typeof e === "string")) {
|
|
12740
12969
|
return raw.entries.slice(0, this.maxEntries);
|
|
12741
12970
|
}
|
|
@@ -12792,7 +13021,7 @@ var InputHistoryStore = class {
|
|
|
12792
13021
|
};
|
|
12793
13022
|
|
|
12794
13023
|
// src/storage/cloud-sync.ts
|
|
12795
|
-
import * as
|
|
13024
|
+
import * as fs17 from "node:fs/promises";
|
|
12796
13025
|
import * as path29 from "node:path";
|
|
12797
13026
|
import { createHash as createHash8 } from "node:crypto";
|
|
12798
13027
|
var ALL_SYNC_CATEGORIES = ["settings", "skills", "prompts", "memory", "history"];
|
|
@@ -12957,7 +13186,7 @@ var CloudSync = class {
|
|
|
12957
13186
|
}
|
|
12958
13187
|
async loadState() {
|
|
12959
13188
|
try {
|
|
12960
|
-
const raw = await
|
|
13189
|
+
const raw = await fs17.readFile(this.statePath, "utf8");
|
|
12961
13190
|
this.state = JSON.parse(raw);
|
|
12962
13191
|
} catch {
|
|
12963
13192
|
this.state = null;
|
|
@@ -13082,18 +13311,18 @@ var CloudSync = class {
|
|
|
13082
13311
|
const localPath = this.categoryToPath(cat);
|
|
13083
13312
|
if (!localPath) continue;
|
|
13084
13313
|
try {
|
|
13085
|
-
const
|
|
13086
|
-
if (
|
|
13087
|
-
if (
|
|
13314
|
+
const stat15 = await fs17.lstat(localPath);
|
|
13315
|
+
if (stat15.isSymbolicLink()) continue;
|
|
13316
|
+
if (stat15.isDirectory()) {
|
|
13088
13317
|
const files = await this.walkDir(localPath, localPath);
|
|
13089
13318
|
for (const file of files) {
|
|
13090
|
-
const content = await
|
|
13319
|
+
const content = await fs17.readFile(file, "utf8");
|
|
13091
13320
|
const rel = path29.relative(localPath, file).replace(/\\/g, "/");
|
|
13092
13321
|
entries.push({ path: `data/${cat}/${rel}`, content, mode: "100644" });
|
|
13093
13322
|
hashes.push(`${cat}/${rel}\0${content}`);
|
|
13094
13323
|
}
|
|
13095
13324
|
} else {
|
|
13096
|
-
const content = await
|
|
13325
|
+
const content = await fs17.readFile(localPath, "utf8");
|
|
13097
13326
|
entries.push({ path: `data/${cat}`, content, mode: "100644" });
|
|
13098
13327
|
hashes.push(`${cat}\0${content}`);
|
|
13099
13328
|
}
|
|
@@ -13109,17 +13338,17 @@ var CloudSync = class {
|
|
|
13109
13338
|
const localPath = this.categoryToPath(cat);
|
|
13110
13339
|
if (!localPath) continue;
|
|
13111
13340
|
try {
|
|
13112
|
-
const
|
|
13113
|
-
if (
|
|
13114
|
-
if (
|
|
13341
|
+
const stat15 = await fs17.lstat(localPath);
|
|
13342
|
+
if (stat15.isSymbolicLink()) continue;
|
|
13343
|
+
if (stat15.isDirectory()) {
|
|
13115
13344
|
const files = await this.walkDir(localPath, localPath);
|
|
13116
13345
|
for (const file of files) {
|
|
13117
|
-
const content = await
|
|
13346
|
+
const content = await fs17.readFile(file, "utf8");
|
|
13118
13347
|
const rel = path29.relative(localPath, file).replace(/\\/g, "/");
|
|
13119
13348
|
hashes.push(`${cat}/${rel}\0${content}`);
|
|
13120
13349
|
}
|
|
13121
13350
|
} else {
|
|
13122
|
-
const content = await
|
|
13351
|
+
const content = await fs17.readFile(localPath, "utf8");
|
|
13123
13352
|
hashes.push(`${cat}\0${content}`);
|
|
13124
13353
|
}
|
|
13125
13354
|
} catch {
|
|
@@ -13146,7 +13375,7 @@ var CloudSync = class {
|
|
|
13146
13375
|
}
|
|
13147
13376
|
async walkDir(dir, base) {
|
|
13148
13377
|
const results = [];
|
|
13149
|
-
const entries = await
|
|
13378
|
+
const entries = await fs17.readdir(dir, { withFileTypes: true });
|
|
13150
13379
|
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
13151
13380
|
for (const entry of entries) {
|
|
13152
13381
|
const full = path29.join(dir, entry.name);
|
|
@@ -13173,18 +13402,18 @@ async function preparePulledDestination(cat, localPath, destPath, remotePath) {
|
|
|
13173
13402
|
if (relativeParent) {
|
|
13174
13403
|
for (const segment of relativeParent.split(path29.sep)) {
|
|
13175
13404
|
cursor = path29.join(cursor, segment);
|
|
13176
|
-
const
|
|
13177
|
-
if (
|
|
13405
|
+
const stat15 = await lstatIfExists(cursor);
|
|
13406
|
+
if (stat15?.isSymbolicLink()) throw unsafePulledSymlinkError(remotePath, cursor);
|
|
13178
13407
|
}
|
|
13179
13408
|
}
|
|
13180
13409
|
}
|
|
13181
13410
|
const destStat = await lstatIfExists(destPath);
|
|
13182
13411
|
if (destStat?.isSymbolicLink()) throw unsafePulledSymlinkError(remotePath, destPath);
|
|
13183
|
-
await
|
|
13412
|
+
await fs17.mkdir(path29.dirname(destPath), { recursive: true });
|
|
13184
13413
|
}
|
|
13185
13414
|
async function lstatIfExists(filePath) {
|
|
13186
13415
|
try {
|
|
13187
|
-
return await
|
|
13416
|
+
return await fs17.lstat(filePath);
|
|
13188
13417
|
} catch (err) {
|
|
13189
13418
|
if (err.code === "ENOENT") return null;
|
|
13190
13419
|
throw err;
|
|
@@ -13335,6 +13564,9 @@ function createSessionEventBridge(writer, level = "standard", options = {}) {
|
|
|
13335
13564
|
async append(event) {
|
|
13336
13565
|
const target = resolveWriter();
|
|
13337
13566
|
if (!target) return;
|
|
13567
|
+
if (event.type === "tool_call_end") {
|
|
13568
|
+
progressCounters.delete(event.id);
|
|
13569
|
+
}
|
|
13338
13570
|
if (!isAllowed(event.type, currentLevel)) return;
|
|
13339
13571
|
if (!shouldSample(event)) return;
|
|
13340
13572
|
try {
|
|
@@ -13345,6 +13577,9 @@ function createSessionEventBridge(writer, level = "standard", options = {}) {
|
|
|
13345
13577
|
async appendBatch(events) {
|
|
13346
13578
|
const target = resolveWriter();
|
|
13347
13579
|
if (!target || events.length === 0) return;
|
|
13580
|
+
for (const e of events) {
|
|
13581
|
+
if (e.type === "tool_call_end") progressCounters.delete(e.id);
|
|
13582
|
+
}
|
|
13348
13583
|
const allowed = events.filter((e) => isAllowed(e.type, currentLevel) && shouldSample(e));
|
|
13349
13584
|
if (allowed.length === 0) return;
|
|
13350
13585
|
try {
|