@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/plugin/index.js
CHANGED
|
@@ -179,6 +179,15 @@ var init_errors = __esm({
|
|
|
179
179
|
}
|
|
180
180
|
});
|
|
181
181
|
|
|
182
|
+
// src/security/file-permissions.ts
|
|
183
|
+
var SECRET_FILE_MODE;
|
|
184
|
+
var init_file_permissions = __esm({
|
|
185
|
+
"src/security/file-permissions.ts"() {
|
|
186
|
+
"use strict";
|
|
187
|
+
SECRET_FILE_MODE = 384;
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
|
|
182
191
|
// src/utils/atomic-write.ts
|
|
183
192
|
import {
|
|
184
193
|
createPersistencePrimitives
|
|
@@ -278,6 +287,7 @@ var FINDING_RESOLVED_RETENTION_MS, FINDING_IGNORED_RETENTION_MS, FINDING_DEFAULT
|
|
|
278
287
|
var init_review_finding_store = __esm({
|
|
279
288
|
"src/plugins/review-finding-store.ts"() {
|
|
280
289
|
"use strict";
|
|
290
|
+
init_file_permissions();
|
|
281
291
|
init_atomic_write();
|
|
282
292
|
init_review_finding_types();
|
|
283
293
|
FINDING_RESOLVED_RETENTION_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
@@ -298,33 +308,49 @@ var init_review_finding_store = __esm({
|
|
|
298
308
|
async upsert(newFindings, context) {
|
|
299
309
|
if (newFindings.length === 0) return { created: 0, relinked: 0, reopened: 0 };
|
|
300
310
|
const result = { created: 0, relinked: 0, reopened: 0 };
|
|
301
|
-
const existing = await this._readAll();
|
|
302
311
|
return withFileLock(this.filePath, async () => {
|
|
312
|
+
const existing = await this._readAll();
|
|
303
313
|
for (const finding of newFindings) {
|
|
304
314
|
const match = existing.find((e) => e.finding.fingerprint === finding.fingerprint);
|
|
305
315
|
if (match) {
|
|
306
316
|
const materialized = this._materialize(match);
|
|
307
317
|
if (materialized.status === "resolved" || materialized.status === "ignored") {
|
|
308
|
-
const reopenEvent = this._makeEvent(
|
|
318
|
+
const reopenEvent = this._makeEvent(
|
|
319
|
+
match.finding.id,
|
|
320
|
+
"reopened",
|
|
321
|
+
materialized.status,
|
|
322
|
+
"active",
|
|
323
|
+
context
|
|
324
|
+
);
|
|
309
325
|
match.finding.status = "active";
|
|
310
326
|
match.finding.resolution = void 0;
|
|
311
327
|
const updatedRecord = { __finding: 1, data: match.finding };
|
|
312
328
|
await fsp2.appendFile(
|
|
313
329
|
this.filePath,
|
|
314
330
|
JSON.stringify(updatedRecord) + LINE_SEPARATOR + JSON.stringify({ __findingEvent: 1, data: reopenEvent }) + LINE_SEPARATOR,
|
|
315
|
-
"utf8"
|
|
331
|
+
{ encoding: "utf8", mode: SECRET_FILE_MODE }
|
|
316
332
|
);
|
|
317
333
|
result.reopened++;
|
|
318
334
|
} else {
|
|
319
|
-
const relinkEvent = this._makeEvent(
|
|
320
|
-
|
|
335
|
+
const relinkEvent = this._makeEvent(
|
|
336
|
+
match.finding.id,
|
|
337
|
+
"relinked",
|
|
338
|
+
match.finding.status,
|
|
339
|
+
match.finding.status,
|
|
340
|
+
context
|
|
341
|
+
);
|
|
342
|
+
await fsp2.appendFile(
|
|
343
|
+
this.filePath,
|
|
344
|
+
JSON.stringify({ __findingEvent: 1, data: relinkEvent }) + LINE_SEPARATOR,
|
|
345
|
+
{ encoding: "utf8", mode: SECRET_FILE_MODE }
|
|
346
|
+
);
|
|
321
347
|
result.relinked++;
|
|
322
348
|
}
|
|
323
349
|
} else {
|
|
324
350
|
const record = { __finding: 1, data: finding };
|
|
325
351
|
const createdEvent = this._makeEvent(finding.id, "created", null, "active", context);
|
|
326
352
|
const lines = JSON.stringify(record) + LINE_SEPARATOR + JSON.stringify({ __findingEvent: 1, data: createdEvent }) + LINE_SEPARATOR;
|
|
327
|
-
await fsp2.appendFile(this.filePath, lines, "utf8");
|
|
353
|
+
await fsp2.appendFile(this.filePath, lines, { encoding: "utf8", mode: SECRET_FILE_MODE });
|
|
328
354
|
result.created++;
|
|
329
355
|
}
|
|
330
356
|
}
|
|
@@ -332,39 +358,41 @@ var init_review_finding_store = __esm({
|
|
|
332
358
|
});
|
|
333
359
|
}
|
|
334
360
|
async transition(findingId, to, actor, opts) {
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
entry.finding.status = to;
|
|
353
|
-
if (to === "resolved" && opts?.outcome) {
|
|
354
|
-
entry.finding.resolution = {
|
|
355
|
-
outcome: opts.outcome,
|
|
356
|
-
resolvedAt: event.timestamp,
|
|
357
|
-
resolvedBy: actor.id,
|
|
358
|
-
notes: opts.reason
|
|
361
|
+
return withFileLock(this.filePath, async () => {
|
|
362
|
+
const all = await this._readAll();
|
|
363
|
+
const entry = all.find((e) => e.finding.id === findingId);
|
|
364
|
+
if (!entry) throw new Error(`Finding not found: ${findingId}`);
|
|
365
|
+
const from = this._materialize(entry).status;
|
|
366
|
+
validateTransition(from, to);
|
|
367
|
+
validateResolution(to, opts?.outcome);
|
|
368
|
+
const event = {
|
|
369
|
+
id: randomUUID3(),
|
|
370
|
+
findingId,
|
|
371
|
+
eventType: to === "resolved" ? "resolved" : to === "ignored" ? "ignored" : this._eventTypeFor(to),
|
|
372
|
+
fromStatus: from,
|
|
373
|
+
toStatus: to,
|
|
374
|
+
actorId: actor.id,
|
|
375
|
+
actorKind: actor.kind,
|
|
376
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
377
|
+
reason: opts?.reason
|
|
359
378
|
};
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
379
|
+
entry.finding.status = to;
|
|
380
|
+
if (to === "resolved" && opts?.outcome) {
|
|
381
|
+
entry.finding.resolution = {
|
|
382
|
+
outcome: opts.outcome,
|
|
383
|
+
resolvedAt: event.timestamp,
|
|
384
|
+
resolvedBy: actor.id,
|
|
385
|
+
notes: opts.reason
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
const updatedRecord = { __finding: 1, data: entry.finding };
|
|
389
|
+
await fsp2.appendFile(
|
|
390
|
+
this.filePath,
|
|
391
|
+
JSON.stringify(updatedRecord) + LINE_SEPARATOR + JSON.stringify({ __findingEvent: 1, data: event }) + LINE_SEPARATOR,
|
|
392
|
+
{ encoding: "utf8", mode: SECRET_FILE_MODE }
|
|
393
|
+
);
|
|
394
|
+
return { ...entry.finding };
|
|
395
|
+
});
|
|
368
396
|
}
|
|
369
397
|
async list(opts) {
|
|
370
398
|
const all = await this._readAll();
|
|
@@ -384,7 +412,12 @@ var init_review_finding_store = __esm({
|
|
|
384
412
|
if (opts?.reportId) {
|
|
385
413
|
findings = findings.filter((f) => f.originReport.reportId === opts.reportId);
|
|
386
414
|
}
|
|
387
|
-
const severityRank = {
|
|
415
|
+
const severityRank = {
|
|
416
|
+
critical: 0,
|
|
417
|
+
high: 1,
|
|
418
|
+
medium: 2,
|
|
419
|
+
low: 3
|
|
420
|
+
};
|
|
388
421
|
findings.sort((a, b) => {
|
|
389
422
|
const sa = severityRank[a.severity] - severityRank[b.severity];
|
|
390
423
|
if (sa !== 0) return sa;
|
|
@@ -415,46 +448,57 @@ var init_review_finding_store = __esm({
|
|
|
415
448
|
return events.sort((a, b) => a.timestamp.localeCompare(b.timestamp));
|
|
416
449
|
}
|
|
417
450
|
async compact(opts) {
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
const
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
451
|
+
return withFileLock(this.filePath, async () => {
|
|
452
|
+
const resolvedMaxAge = opts?.resolvedMaxAgeMs ?? FINDING_RESOLVED_RETENTION_MS;
|
|
453
|
+
const ignoredMaxAge = opts?.ignoredMaxAgeMs ?? FINDING_IGNORED_RETENTION_MS;
|
|
454
|
+
const now = Date.now();
|
|
455
|
+
const all = await this._readAll();
|
|
456
|
+
const kept = [];
|
|
457
|
+
let removed = 0;
|
|
458
|
+
let eventsFolded = 0;
|
|
459
|
+
for (const entry of all) {
|
|
460
|
+
const age = now - new Date(entry.finding.createdAt).getTime();
|
|
461
|
+
const isResolved = entry.finding.status === "resolved";
|
|
462
|
+
const isIgnored = entry.finding.status === "ignored";
|
|
463
|
+
const maxAge = isResolved ? resolvedMaxAge : isIgnored ? ignoredMaxAge : Infinity;
|
|
464
|
+
if (age > maxAge && (isResolved || isIgnored)) {
|
|
465
|
+
removed++;
|
|
466
|
+
eventsFolded += entry.events.length;
|
|
467
|
+
continue;
|
|
468
|
+
}
|
|
469
|
+
const oldEvents = entry.events.filter(
|
|
470
|
+
(ev) => now - new Date(ev.timestamp).getTime() > maxAge
|
|
471
|
+
);
|
|
472
|
+
if (oldEvents.length > 1) {
|
|
473
|
+
eventsFolded += oldEvents.length - 1;
|
|
474
|
+
const newestOld = oldEvents.sort((a, b) => b.timestamp.localeCompare(a.timestamp))[0];
|
|
475
|
+
entry.events = [
|
|
476
|
+
newestOld,
|
|
477
|
+
...entry.events.filter((ev) => now - new Date(ev.timestamp).getTime() <= maxAge)
|
|
478
|
+
];
|
|
479
|
+
}
|
|
480
|
+
kept.push({ record: { __finding: 1, data: entry.finding }, events: entry.events });
|
|
440
481
|
}
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
lines.push(JSON.stringify({ __findingEvent: 1, data: ev }));
|
|
482
|
+
const lines = [];
|
|
483
|
+
for (const { record, events } of kept) {
|
|
484
|
+
if (record) lines.push(JSON.stringify(record));
|
|
485
|
+
for (const ev of events) {
|
|
486
|
+
lines.push(JSON.stringify({ __findingEvent: 1, data: ev }));
|
|
487
|
+
}
|
|
448
488
|
}
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
489
|
+
lines.push(
|
|
490
|
+
JSON.stringify({
|
|
491
|
+
__findingCompact: 1,
|
|
492
|
+
compactedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
493
|
+
removedFindings: removed,
|
|
494
|
+
foldedEvents: eventsFolded
|
|
495
|
+
})
|
|
496
|
+
);
|
|
497
|
+
await atomicWrite(this.filePath, lines.join(LINE_SEPARATOR) + LINE_SEPARATOR, {
|
|
498
|
+
mode: 384
|
|
499
|
+
});
|
|
500
|
+
return { removed, eventsFolded };
|
|
501
|
+
});
|
|
458
502
|
}
|
|
459
503
|
// ── Private helpers ──────────────────────────────────────────────
|
|
460
504
|
async _readAllLines() {
|
|
@@ -600,6 +644,7 @@ var REPORT_RETENTION_MS, REPORT_DEFAULT_PAGE_SIZE, NL2, REPORT_STORE_FILE, Jsonl
|
|
|
600
644
|
var init_review_report_store = __esm({
|
|
601
645
|
"src/plugins/review-report-store.ts"() {
|
|
602
646
|
"use strict";
|
|
647
|
+
init_file_permissions();
|
|
603
648
|
init_atomic_write();
|
|
604
649
|
init_review_report_types();
|
|
605
650
|
REPORT_RETENTION_MS = 90 * 24 * 60 * 60 * 1e3;
|
|
@@ -628,11 +673,10 @@ var init_review_report_store = __esm({
|
|
|
628
673
|
rawText: input.rawText || existing.rawText,
|
|
629
674
|
files: input.files.length > 0 ? input.files : existing.files
|
|
630
675
|
};
|
|
631
|
-
await fsp3.appendFile(
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
);
|
|
676
|
+
await fsp3.appendFile(this.filePath, JSON.stringify({ __report: 1, data: updated }) + NL2, {
|
|
677
|
+
encoding: "utf8",
|
|
678
|
+
mode: SECRET_FILE_MODE
|
|
679
|
+
});
|
|
636
680
|
return updated;
|
|
637
681
|
}
|
|
638
682
|
const report = {
|
|
@@ -663,57 +707,60 @@ var init_review_report_store = __esm({
|
|
|
663
707
|
timestamp: report.reviewedAt
|
|
664
708
|
};
|
|
665
709
|
const lines = JSON.stringify({ __report: 1, data: report }) + NL2 + JSON.stringify({ __reportEvent: 1, data: createdEvent }) + NL2;
|
|
666
|
-
await fsp3.appendFile(this.filePath, lines, "utf8");
|
|
710
|
+
await fsp3.appendFile(this.filePath, lines, { encoding: "utf8", mode: SECRET_FILE_MODE });
|
|
667
711
|
return report;
|
|
668
712
|
});
|
|
669
713
|
}
|
|
670
714
|
// ── Lifecycle transitions ────────────────────────────────────────
|
|
671
715
|
async transition(reportId, to, actor, opts) {
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
this.filePath,
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
716
|
+
return withFileLock(this.filePath, async () => {
|
|
717
|
+
const all = await this._readAll();
|
|
718
|
+
const entry = all.find((e) => e.report.id === reportId);
|
|
719
|
+
if (!entry) throw new Error(`Review report not found: ${reportId}`);
|
|
720
|
+
const from = this._materialize(entry).lifecycle;
|
|
721
|
+
validateReportTransition(from, to);
|
|
722
|
+
const event = {
|
|
723
|
+
id: randomUUID5(),
|
|
724
|
+
reportId,
|
|
725
|
+
eventType: reportEventTypeFor(to),
|
|
726
|
+
fromLifecycle: from,
|
|
727
|
+
toLifecycle: to,
|
|
728
|
+
actorId: actor.id,
|
|
729
|
+
actorKind: actor.kind,
|
|
730
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
731
|
+
reason: opts?.reason
|
|
732
|
+
};
|
|
733
|
+
entry.report.lifecycle = to;
|
|
734
|
+
await fsp3.appendFile(this.filePath, JSON.stringify({ __reportEvent: 1, data: event }) + NL2, {
|
|
735
|
+
encoding: "utf8",
|
|
736
|
+
mode: SECRET_FILE_MODE
|
|
737
|
+
});
|
|
738
|
+
return { ...entry.report };
|
|
739
|
+
});
|
|
695
740
|
}
|
|
696
741
|
async addNote(reportId, actor, note) {
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
JSON.stringify({ __reportEvent: 1, data: event }) + NL2,
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
742
|
+
return withFileLock(this.filePath, async () => {
|
|
743
|
+
const all = await this._readAll();
|
|
744
|
+
const entry = all.find((e) => e.report.id === reportId);
|
|
745
|
+
if (!entry) throw new Error(`Review report not found: ${reportId}`);
|
|
746
|
+
const materialized = this._materialize(entry);
|
|
747
|
+
const event = {
|
|
748
|
+
id: randomUUID5(),
|
|
749
|
+
reportId,
|
|
750
|
+
eventType: "note_added",
|
|
751
|
+
fromLifecycle: materialized.lifecycle,
|
|
752
|
+
toLifecycle: materialized.lifecycle,
|
|
753
|
+
actorId: actor.id,
|
|
754
|
+
actorKind: actor.kind,
|
|
755
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
756
|
+
reason: note
|
|
757
|
+
};
|
|
758
|
+
await fsp3.appendFile(this.filePath, JSON.stringify({ __reportEvent: 1, data: event }) + NL2, {
|
|
759
|
+
encoding: "utf8",
|
|
760
|
+
mode: SECRET_FILE_MODE
|
|
761
|
+
});
|
|
762
|
+
return materialized;
|
|
763
|
+
});
|
|
717
764
|
}
|
|
718
765
|
// ── Query ────────────────────────────────────────────────────────
|
|
719
766
|
async list(opts) {
|
|
@@ -752,44 +799,53 @@ var init_review_report_store = __esm({
|
|
|
752
799
|
}
|
|
753
800
|
// ── Compaction ───────────────────────────────────────────────────
|
|
754
801
|
async compact(opts) {
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
const
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
802
|
+
return withFileLock(this.filePath, async () => {
|
|
803
|
+
const maxAge = opts?.maxAgeMs ?? REPORT_RETENTION_MS;
|
|
804
|
+
const now = Date.now();
|
|
805
|
+
const all = await this._readAll();
|
|
806
|
+
const kept = [];
|
|
807
|
+
let removed = 0;
|
|
808
|
+
let eventsFolded = 0;
|
|
809
|
+
for (const entry of all) {
|
|
810
|
+
const age = now - new Date(entry.report.reviewedAt).getTime();
|
|
811
|
+
const materialized = this._materialize(entry);
|
|
812
|
+
const isTerminal = materialized.lifecycle === "completed" || materialized.lifecycle === "skipped";
|
|
813
|
+
if (isTerminal && age > maxAge) {
|
|
814
|
+
removed++;
|
|
815
|
+
eventsFolded += entry.events.length;
|
|
816
|
+
continue;
|
|
817
|
+
}
|
|
818
|
+
const oldEvents = entry.events.filter(
|
|
819
|
+
(ev) => now - new Date(ev.timestamp).getTime() > maxAge
|
|
820
|
+
);
|
|
821
|
+
if (oldEvents.length > 1) {
|
|
822
|
+
eventsFolded += oldEvents.length - 1;
|
|
823
|
+
const newestOld = oldEvents.sort((a, b) => b.timestamp.localeCompare(a.timestamp))[0];
|
|
824
|
+
entry.events = [
|
|
825
|
+
newestOld,
|
|
826
|
+
...entry.events.filter((ev) => now - new Date(ev.timestamp).getTime() <= maxAge)
|
|
827
|
+
];
|
|
828
|
+
}
|
|
829
|
+
kept.push({ record: { __report: 1, data: entry.report }, events: entry.events });
|
|
775
830
|
}
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
lines.push(JSON.stringify({ __reportEvent: 1, data: ev }));
|
|
831
|
+
const lines = [];
|
|
832
|
+
for (const { record, events } of kept) {
|
|
833
|
+
if (record) lines.push(JSON.stringify(record));
|
|
834
|
+
for (const ev of events) {
|
|
835
|
+
lines.push(JSON.stringify({ __reportEvent: 1, data: ev }));
|
|
836
|
+
}
|
|
783
837
|
}
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
838
|
+
lines.push(
|
|
839
|
+
JSON.stringify({
|
|
840
|
+
__reportCompact: 1,
|
|
841
|
+
compactedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
842
|
+
removedReports: removed,
|
|
843
|
+
foldedEvents: eventsFolded
|
|
844
|
+
})
|
|
845
|
+
);
|
|
846
|
+
await atomicWrite(this.filePath, lines.join(NL2) + NL2, { mode: 384 });
|
|
847
|
+
return { removed, eventsFolded };
|
|
848
|
+
});
|
|
793
849
|
}
|
|
794
850
|
// ── Private helpers ──────────────────────────────────────────────
|
|
795
851
|
async _readAllLines() {
|
|
@@ -1079,10 +1135,10 @@ function validateAgainstSchema(value, schema) {
|
|
|
1079
1135
|
return { ok: errors.length === 0, errors };
|
|
1080
1136
|
}
|
|
1081
1137
|
var MAX_SCHEMA_DEPTH = 64;
|
|
1082
|
-
function walk(value, schema,
|
|
1138
|
+
function walk(value, schema, path29, errors, depth) {
|
|
1083
1139
|
if (depth > MAX_SCHEMA_DEPTH) {
|
|
1084
1140
|
errors.push({
|
|
1085
|
-
path:
|
|
1141
|
+
path: path29 || "<root>",
|
|
1086
1142
|
message: `schema nesting exceeds maximum depth (${MAX_SCHEMA_DEPTH})`
|
|
1087
1143
|
});
|
|
1088
1144
|
return;
|
|
@@ -1090,7 +1146,7 @@ function walk(value, schema, path28, errors, depth) {
|
|
|
1090
1146
|
if (schema.enum !== void 0) {
|
|
1091
1147
|
if (!enumIncludes(schema.enum, value)) {
|
|
1092
1148
|
errors.push({
|
|
1093
|
-
path:
|
|
1149
|
+
path: path29 || "<root>",
|
|
1094
1150
|
message: `expected one of ${JSON.stringify(schema.enum)}, got ${JSON.stringify(value)}`
|
|
1095
1151
|
});
|
|
1096
1152
|
return;
|
|
@@ -1099,7 +1155,7 @@ function walk(value, schema, path28, errors, depth) {
|
|
|
1099
1155
|
if (typeof schema.type === "string") {
|
|
1100
1156
|
if (!checkType(value, schema.type)) {
|
|
1101
1157
|
errors.push({
|
|
1102
|
-
path:
|
|
1158
|
+
path: path29 || "<root>",
|
|
1103
1159
|
message: `expected ${schema.type}, got ${describeType(value)} (${previewValue(value)})`
|
|
1104
1160
|
});
|
|
1105
1161
|
return;
|
|
@@ -1111,7 +1167,7 @@ function walk(value, schema, path28, errors, depth) {
|
|
|
1111
1167
|
if (!(req in obj)) {
|
|
1112
1168
|
const expected = schema.properties?.[req]?.type;
|
|
1113
1169
|
errors.push({
|
|
1114
|
-
path: joinPath(
|
|
1170
|
+
path: joinPath(path29, req),
|
|
1115
1171
|
message: `required property missing${typeof expected === "string" ? ` (expected ${expected})` : ""}`
|
|
1116
1172
|
});
|
|
1117
1173
|
}
|
|
@@ -1119,14 +1175,14 @@ function walk(value, schema, path28, errors, depth) {
|
|
|
1119
1175
|
if (schema.properties) {
|
|
1120
1176
|
for (const [key, subSchema] of Object.entries(schema.properties)) {
|
|
1121
1177
|
if (key in obj) {
|
|
1122
|
-
walk(obj[key], subSchema, joinPath(
|
|
1178
|
+
walk(obj[key], subSchema, joinPath(path29, key), errors, depth + 1);
|
|
1123
1179
|
}
|
|
1124
1180
|
}
|
|
1125
1181
|
}
|
|
1126
1182
|
}
|
|
1127
1183
|
if (schema.type === "array" && Array.isArray(value) && schema.items) {
|
|
1128
1184
|
for (let i = 0; i < value.length; i++) {
|
|
1129
|
-
walk(value[i], schema.items, `${
|
|
1185
|
+
walk(value[i], schema.items, `${path29}[${i}]`, errors, depth + 1);
|
|
1130
1186
|
}
|
|
1131
1187
|
}
|
|
1132
1188
|
}
|
|
@@ -2054,23 +2110,6 @@ import { createHash as createHash7 } from "node:crypto";
|
|
|
2054
2110
|
import * as fsp from "node:fs/promises";
|
|
2055
2111
|
import * as path14 from "node:path";
|
|
2056
2112
|
|
|
2057
|
-
// src/core/model-ref.ts
|
|
2058
|
-
function parseModelRef(ref) {
|
|
2059
|
-
const trimmed = ref.trim();
|
|
2060
|
-
const slash = trimmed.indexOf("/");
|
|
2061
|
-
if (slash !== -1) {
|
|
2062
|
-
return {
|
|
2063
|
-
provider: trimmed.slice(0, slash) || void 0,
|
|
2064
|
-
model: trimmed.slice(slash + 1).trim()
|
|
2065
|
-
};
|
|
2066
|
-
}
|
|
2067
|
-
const parts = trimmed.split(/\s+/);
|
|
2068
|
-
if (parts.length >= 2) {
|
|
2069
|
-
return { provider: parts[0], model: parts.slice(1).join(" ") };
|
|
2070
|
-
}
|
|
2071
|
-
return { model: trimmed };
|
|
2072
|
-
}
|
|
2073
|
-
|
|
2074
2113
|
// src/core/model-availability-calendar.ts
|
|
2075
2114
|
function logicalCalendarTarget(providerId, model) {
|
|
2076
2115
|
if (providerId !== "omniroute") return { providerId, model };
|
|
@@ -2149,6 +2188,23 @@ function evaluateModelCalendar(rules, providerId, model, at = /* @__PURE__ */ ne
|
|
|
2149
2188
|
return { allowed: true };
|
|
2150
2189
|
}
|
|
2151
2190
|
|
|
2191
|
+
// src/core/model-ref.ts
|
|
2192
|
+
function parseModelRef(ref) {
|
|
2193
|
+
const trimmed = ref.trim();
|
|
2194
|
+
const slash = trimmed.indexOf("/");
|
|
2195
|
+
if (slash !== -1) {
|
|
2196
|
+
return {
|
|
2197
|
+
provider: trimmed.slice(0, slash) || void 0,
|
|
2198
|
+
model: trimmed.slice(slash + 1).trim()
|
|
2199
|
+
};
|
|
2200
|
+
}
|
|
2201
|
+
const parts = trimmed.split(/\s+/);
|
|
2202
|
+
if (parts.length >= 2) {
|
|
2203
|
+
return { provider: parts[0], model: parts.slice(1).join(" ") };
|
|
2204
|
+
}
|
|
2205
|
+
return { model: trimmed };
|
|
2206
|
+
}
|
|
2207
|
+
|
|
2152
2208
|
// src/core/fallback-profile-manager.ts
|
|
2153
2209
|
function hasText(value) {
|
|
2154
2210
|
return typeof value === "string" && value.trim().length > 0;
|
|
@@ -2249,18 +2305,42 @@ var FallbackProfileManager = class {
|
|
|
2249
2305
|
* Mirrors the previous `effectiveFallbackChain()` logic but centralized.
|
|
2250
2306
|
*/
|
|
2251
2307
|
resolveEffective(opts = {}) {
|
|
2308
|
+
const bridge = this.resolveBridge(opts.exclude);
|
|
2309
|
+
let selected = FREEZER_EMPTY;
|
|
2252
2310
|
if (opts.fallbackModels && opts.fallbackModels.length > 0) {
|
|
2253
2311
|
const resolved = this.resolveRefs(opts.fallbackModels, opts.exclude);
|
|
2254
|
-
if (resolved.length > 0)
|
|
2312
|
+
if (resolved.length > 0) selected = resolved;
|
|
2255
2313
|
}
|
|
2256
|
-
if (opts.fallbackProfile) {
|
|
2314
|
+
if (selected.length === 0 && opts.fallbackProfile) {
|
|
2257
2315
|
const resolved = this.resolve(opts.fallbackProfile, { exclude: opts.exclude });
|
|
2258
|
-
if (resolved.length > 0)
|
|
2316
|
+
if (resolved.length > 0) selected = resolved;
|
|
2259
2317
|
}
|
|
2260
|
-
if (opts.fallbackAuto !== false) {
|
|
2261
|
-
|
|
2318
|
+
if (selected.length === 0 && opts.fallbackAuto !== false) {
|
|
2319
|
+
selected = this.smartDefault(opts.exclude);
|
|
2262
2320
|
}
|
|
2263
|
-
return
|
|
2321
|
+
if (bridge.length === 0) return selected;
|
|
2322
|
+
if (selected.length === 0) return bridge;
|
|
2323
|
+
const seen = new Set(bridge.map((entry) => `${entry.providerId}/${entry.model}`));
|
|
2324
|
+
return Object.freeze([
|
|
2325
|
+
...bridge,
|
|
2326
|
+
...selected.filter((entry) => !seen.has(`${entry.providerId}/${entry.model}`))
|
|
2327
|
+
]);
|
|
2328
|
+
}
|
|
2329
|
+
/** Resolve the optional, fully-qualified emergency continuity route. */
|
|
2330
|
+
resolveBridge(exclude) {
|
|
2331
|
+
const ref = this.config.fallbackBridge?.trim();
|
|
2332
|
+
if (!ref) return FREEZER_EMPTY;
|
|
2333
|
+
const parsed = parseModelRef(ref);
|
|
2334
|
+
if (!parsed.provider || !parsed.model) return FREEZER_EMPTY;
|
|
2335
|
+
return this.resolveRefs([ref], exclude);
|
|
2336
|
+
}
|
|
2337
|
+
/**
|
|
2338
|
+
* Resolve every usable configured target as an uncapped last-resort chain.
|
|
2339
|
+
* Normal smart defaults stay bounded; callers append this only after the
|
|
2340
|
+
* preferred chain and only when automatic fallback is enabled.
|
|
2341
|
+
*/
|
|
2342
|
+
resolveAllConfigured(exclude) {
|
|
2343
|
+
return this.smartDefault(exclude, Number.POSITIVE_INFINITY);
|
|
2264
2344
|
}
|
|
2265
2345
|
// ── Provider availability (read-only) ──────────────────────────────────
|
|
2266
2346
|
checkProvider(providerId) {
|
|
@@ -2319,7 +2399,7 @@ var FallbackProfileManager = class {
|
|
|
2319
2399
|
* explicit is set. Same-provider alternatives first, then cross-provider.
|
|
2320
2400
|
* Limited to 4 entries to avoid burning through models on a transient blip.
|
|
2321
2401
|
*/
|
|
2322
|
-
smartDefault(exclude) {
|
|
2402
|
+
smartDefault(exclude, maxCandidates = 4) {
|
|
2323
2403
|
const leaderProvider = this.config.provider;
|
|
2324
2404
|
const leaderModel = this.config.model;
|
|
2325
2405
|
const providers = this.config.providers ?? {};
|
|
@@ -2360,8 +2440,18 @@ var FallbackProfileManager = class {
|
|
|
2360
2440
|
(id === leaderProvider ? sameProvider : crossProvider).push(ref);
|
|
2361
2441
|
}
|
|
2362
2442
|
}
|
|
2363
|
-
const
|
|
2364
|
-
const all =
|
|
2443
|
+
const ordered = [...favorites, ...sameProvider, ...crossProvider];
|
|
2444
|
+
const all = Number.isFinite(maxCandidates) ? ordered.slice(0, Math.max(0, maxCandidates)) : [...ordered];
|
|
2445
|
+
const firstCrossProvider = ordered.find((ref) => {
|
|
2446
|
+
const parsed = parseModelRef(ref);
|
|
2447
|
+
return (parsed.provider ?? leaderProvider) !== leaderProvider;
|
|
2448
|
+
});
|
|
2449
|
+
if (all.length > 0 && firstCrossProvider && !all.some((ref) => {
|
|
2450
|
+
const parsed = parseModelRef(ref);
|
|
2451
|
+
return (parsed.provider ?? leaderProvider) !== leaderProvider;
|
|
2452
|
+
})) {
|
|
2453
|
+
all[all.length - 1] = firstCrossProvider;
|
|
2454
|
+
}
|
|
2365
2455
|
return Object.freeze(
|
|
2366
2456
|
all.map((ref) => {
|
|
2367
2457
|
const p = parseModelRef(ref);
|
|
@@ -2618,6 +2708,7 @@ function stableId(prefix, value) {
|
|
|
2618
2708
|
}
|
|
2619
2709
|
|
|
2620
2710
|
// src/chronicle/journal.ts
|
|
2711
|
+
init_file_permissions();
|
|
2621
2712
|
init_atomic_write();
|
|
2622
2713
|
import { randomUUID } from "node:crypto";
|
|
2623
2714
|
import { createReadStream } from "node:fs";
|
|
@@ -2682,7 +2773,16 @@ var ChronicleJournal = class {
|
|
|
2682
2773
|
drainPromise;
|
|
2683
2774
|
drainScheduled = false;
|
|
2684
2775
|
drainTimer;
|
|
2685
|
-
counters = {
|
|
2776
|
+
counters = {
|
|
2777
|
+
acceptedEvents: 0,
|
|
2778
|
+
persistedEvents: 0,
|
|
2779
|
+
rejectedEvents: 0,
|
|
2780
|
+
failedEvents: 0,
|
|
2781
|
+
batches: 0,
|
|
2782
|
+
maxObservedPending: 0,
|
|
2783
|
+
largestBatch: 0,
|
|
2784
|
+
partitionRolls: 0
|
|
2785
|
+
};
|
|
2686
2786
|
lastBatchDurationMs;
|
|
2687
2787
|
partitionIndex = 0;
|
|
2688
2788
|
partitionStartedAt;
|
|
@@ -2708,18 +2808,27 @@ var ChronicleJournal = class {
|
|
|
2708
2808
|
return this.partitionIndex === 0 ? this.basePath : rotatedPath(this.basePath, this.partitionIndex);
|
|
2709
2809
|
}
|
|
2710
2810
|
stats() {
|
|
2711
|
-
return {
|
|
2811
|
+
return {
|
|
2812
|
+
...this.counters,
|
|
2813
|
+
pendingEvents: this.pending.length,
|
|
2814
|
+
...this.lastBatchDurationMs !== void 0 ? { lastBatchDurationMs: this.lastBatchDurationMs } : {}
|
|
2815
|
+
};
|
|
2712
2816
|
}
|
|
2713
2817
|
append(input) {
|
|
2714
2818
|
if (this.pending.length >= this.maxPending) {
|
|
2715
2819
|
this.counters.rejectedEvents++;
|
|
2716
|
-
return Promise.reject(
|
|
2820
|
+
return Promise.reject(
|
|
2821
|
+
new Error(`Chronicle backpressure limit reached (${this.maxPending} pending events)`)
|
|
2822
|
+
);
|
|
2717
2823
|
}
|
|
2718
2824
|
const promise = new Promise((resolve16, reject) => {
|
|
2719
2825
|
this.pending.push({ input, resolve: resolve16, reject });
|
|
2720
2826
|
});
|
|
2721
2827
|
this.counters.acceptedEvents++;
|
|
2722
|
-
this.counters.maxObservedPending = Math.max(
|
|
2828
|
+
this.counters.maxObservedPending = Math.max(
|
|
2829
|
+
this.counters.maxObservedPending,
|
|
2830
|
+
this.pending.length
|
|
2831
|
+
);
|
|
2723
2832
|
this.scheduleDrain();
|
|
2724
2833
|
return promise;
|
|
2725
2834
|
}
|
|
@@ -2745,7 +2854,8 @@ var ChronicleJournal = class {
|
|
|
2745
2854
|
await this.flush();
|
|
2746
2855
|
const files = await collectPartitions(this.basePath);
|
|
2747
2856
|
const checkpointResult = await readRetentionCheckpoint(this.basePath);
|
|
2748
|
-
if (checkpointResult.error)
|
|
2857
|
+
if (checkpointResult.error)
|
|
2858
|
+
return { ok: false, entries: 0, brokenAt: 0, reason: checkpointResult.error };
|
|
2749
2859
|
return verifyPartitionFiles(files, checkpointResult.checkpoint);
|
|
2750
2860
|
}
|
|
2751
2861
|
async purge(options) {
|
|
@@ -2763,7 +2873,10 @@ var ChronicleJournal = class {
|
|
|
2763
2873
|
for (const suppliedPath of new Set(suppliedFiles)) {
|
|
2764
2874
|
const file = path4.resolve(suppliedPath);
|
|
2765
2875
|
if (!isJournalPartition(file, path4.dirname(this.basePath), this.basePath)) {
|
|
2766
|
-
errors.push({
|
|
2876
|
+
errors.push({
|
|
2877
|
+
file: suppliedPath,
|
|
2878
|
+
reason: "not a Chronicle journal partition in this journal directory"
|
|
2879
|
+
});
|
|
2767
2880
|
sc++;
|
|
2768
2881
|
continue;
|
|
2769
2882
|
}
|
|
@@ -2812,8 +2925,12 @@ var ChronicleJournal = class {
|
|
|
2812
2925
|
const checkpointResult = await readRetentionCheckpoint(familyBase);
|
|
2813
2926
|
if (checkpointResult.error) throw new Error(checkpointResult.error);
|
|
2814
2927
|
const checkpoint = checkpointResult.checkpoint;
|
|
2815
|
-
const nextCheckpoint = await verifyRetainedPrefix(
|
|
2816
|
-
|
|
2928
|
+
const nextCheckpoint = await verifyRetainedPrefix(
|
|
2929
|
+
streamEntriesStrict(file),
|
|
2930
|
+
checkpoint
|
|
2931
|
+
);
|
|
2932
|
+
if (!nextCheckpoint)
|
|
2933
|
+
throw new Error("partition does not extend the trusted Chronicle chain");
|
|
2817
2934
|
if (nextCheckpoint.sequence > (checkpoint?.sequence ?? 0)) {
|
|
2818
2935
|
await writeRetentionCheckpoint(familyBase, nextCheckpoint);
|
|
2819
2936
|
}
|
|
@@ -2833,7 +2950,13 @@ var ChronicleJournal = class {
|
|
|
2833
2950
|
}
|
|
2834
2951
|
}
|
|
2835
2952
|
}
|
|
2836
|
-
return {
|
|
2953
|
+
return {
|
|
2954
|
+
deletedCount: dc,
|
|
2955
|
+
deletedBytes: db,
|
|
2956
|
+
skippedCount: sc,
|
|
2957
|
+
errors,
|
|
2958
|
+
...options.dryRun ? { candidates } : {}
|
|
2959
|
+
};
|
|
2837
2960
|
}
|
|
2838
2961
|
async maybeAutoPurge() {
|
|
2839
2962
|
if (this.retentionDays <= 0) return;
|
|
@@ -2909,7 +3032,8 @@ var ChronicleJournal = class {
|
|
|
2909
3032
|
this.rotate();
|
|
2910
3033
|
return;
|
|
2911
3034
|
}
|
|
2912
|
-
if (Number.isFinite(this.maxPartitionSizeBytes) && this.partitionSizeBytes >= this.maxPartitionSizeBytes)
|
|
3035
|
+
if (Number.isFinite(this.maxPartitionSizeBytes) && this.partitionSizeBytes >= this.maxPartitionSizeBytes)
|
|
3036
|
+
this.rotate();
|
|
2913
3037
|
}
|
|
2914
3038
|
rotate() {
|
|
2915
3039
|
this.partitionIndex++;
|
|
@@ -2930,13 +3054,23 @@ var ChronicleJournal = class {
|
|
|
2930
3054
|
let prev = this.lastSequence > 0 ? { sequence: this.lastSequence, hash: this.lastHash } : void 0;
|
|
2931
3055
|
recorded = batch.map(({ input }) => {
|
|
2932
3056
|
const instant = this.now().toISOString();
|
|
2933
|
-
const uh = {
|
|
3057
|
+
const uh = {
|
|
3058
|
+
...input,
|
|
3059
|
+
occurredAt: input.occurredAt ?? instant,
|
|
3060
|
+
monotonicNs: input.monotonicNs ?? this.monotonicNow().toString(),
|
|
3061
|
+
schemaVersion: CHRONICLE_SCHEMA_VERSION,
|
|
3062
|
+
eventId: this.idFactory(),
|
|
3063
|
+
observedAt: instant,
|
|
3064
|
+
persistedAt: instant,
|
|
3065
|
+
sequence: (prev?.sequence ?? 0) + 1,
|
|
3066
|
+
previousHash: prev?.hash ?? GENESIS_HASH
|
|
3067
|
+
};
|
|
2934
3068
|
const event = { ...uh, hash: hashValue(uh) };
|
|
2935
3069
|
prev = event;
|
|
2936
3070
|
return event;
|
|
2937
3071
|
});
|
|
2938
3072
|
const serialized = recorded.map((e) => JSON.stringify(e)).join("\n") + "\n";
|
|
2939
|
-
await fs2.appendFile(cp, serialized, "utf8");
|
|
3073
|
+
await fs2.appendFile(cp, serialized, { encoding: "utf8", mode: SECRET_FILE_MODE });
|
|
2940
3074
|
this.partitionSizeBytes += Buffer.byteLength(serialized);
|
|
2941
3075
|
});
|
|
2942
3076
|
const last = recorded[recorded.length - 1];
|
|
@@ -2972,7 +3106,8 @@ async function collectPartitions(basePath) {
|
|
|
2972
3106
|
const result = [];
|
|
2973
3107
|
try {
|
|
2974
3108
|
const entries = await fs2.readdir(dir, { withFileTypes: true });
|
|
2975
|
-
for (const entry of entries)
|
|
3109
|
+
for (const entry of entries)
|
|
3110
|
+
if (entry.isFile() && pattern.test(entry.name)) result.push(path4.join(dir, entry.name));
|
|
2976
3111
|
} catch {
|
|
2977
3112
|
}
|
|
2978
3113
|
const baseFile = path4.join(dir, base + ext);
|
|
@@ -3047,23 +3182,42 @@ async function verifyPartitionFiles(files, checkpoint) {
|
|
|
3047
3182
|
for await (const entry of streamEntriesStrict(file)) {
|
|
3048
3183
|
const { hash: recordedHash, ...content } = entry;
|
|
3049
3184
|
if (entry.sequence <= checkpointSequence) {
|
|
3050
|
-
if (hashValue(content) !== recordedHash)
|
|
3185
|
+
if (hashValue(content) !== recordedHash)
|
|
3186
|
+
return { ok: false, entries, brokenAt: entries, reason: "entry hash mismatch" };
|
|
3051
3187
|
if (coveredPrevious && entry.sequence !== coveredPrevious.sequence + 1) {
|
|
3052
|
-
return {
|
|
3188
|
+
return {
|
|
3189
|
+
ok: false,
|
|
3190
|
+
entries,
|
|
3191
|
+
brokenAt: entries,
|
|
3192
|
+
reason: `sequence ${entry.sequence} is not ${coveredPrevious.sequence + 1}`
|
|
3193
|
+
};
|
|
3053
3194
|
}
|
|
3054
3195
|
if (coveredPrevious && entry.previousHash !== coveredPrevious.hash) {
|
|
3055
3196
|
return { ok: false, entries, brokenAt: entries, reason: "previous hash mismatch" };
|
|
3056
3197
|
}
|
|
3057
3198
|
if (entry.sequence === checkpointSequence && recordedHash !== checkpoint?.hash) {
|
|
3058
|
-
return {
|
|
3199
|
+
return {
|
|
3200
|
+
ok: false,
|
|
3201
|
+
entries,
|
|
3202
|
+
brokenAt: entries,
|
|
3203
|
+
reason: "retention checkpoint hash mismatch"
|
|
3204
|
+
};
|
|
3059
3205
|
}
|
|
3060
3206
|
coveredPrevious = entry;
|
|
3061
3207
|
continue;
|
|
3062
3208
|
}
|
|
3063
3209
|
const index = entries++;
|
|
3064
|
-
if (entry.sequence !== lastSequence + 1)
|
|
3065
|
-
|
|
3066
|
-
|
|
3210
|
+
if (entry.sequence !== lastSequence + 1)
|
|
3211
|
+
return {
|
|
3212
|
+
ok: false,
|
|
3213
|
+
entries,
|
|
3214
|
+
brokenAt: index,
|
|
3215
|
+
reason: `sequence ${entry.sequence} is not ${lastSequence + 1}`
|
|
3216
|
+
};
|
|
3217
|
+
if (entry.previousHash !== previousHash)
|
|
3218
|
+
return { ok: false, entries, brokenAt: index, reason: "previous hash mismatch" };
|
|
3219
|
+
if (hashValue(content) !== recordedHash)
|
|
3220
|
+
return { ok: false, entries, brokenAt: index, reason: "entry hash mismatch" };
|
|
3067
3221
|
previousHash = recordedHash;
|
|
3068
3222
|
lastSequence = entry.sequence;
|
|
3069
3223
|
}
|
|
@@ -3096,7 +3250,9 @@ async function readRetentionCheckpoint(basePath) {
|
|
|
3096
3250
|
}
|
|
3097
3251
|
async function writeRetentionCheckpoint(basePath, checkpoint) {
|
|
3098
3252
|
await atomicWrite(retentionCheckpointPath(basePath), `${JSON.stringify(checkpoint)}
|
|
3099
|
-
`, {
|
|
3253
|
+
`, {
|
|
3254
|
+
mode: 384
|
|
3255
|
+
});
|
|
3100
3256
|
}
|
|
3101
3257
|
function isHash(value) {
|
|
3102
3258
|
return typeof value === "string" && /^[a-f0-9]{64}$/.test(value);
|
|
@@ -3121,8 +3277,8 @@ async function readLastEntryState(filePath) {
|
|
|
3121
3277
|
throw error;
|
|
3122
3278
|
}
|
|
3123
3279
|
try {
|
|
3124
|
-
const
|
|
3125
|
-
const size =
|
|
3280
|
+
const stat7 = await handle.stat();
|
|
3281
|
+
const size = stat7.size;
|
|
3126
3282
|
let position = size, suffix = "";
|
|
3127
3283
|
while (position > 0) {
|
|
3128
3284
|
const length = Math.min(65536, position);
|
|
@@ -3136,13 +3292,17 @@ async function readLastEntryState(filePath) {
|
|
|
3136
3292
|
const trimmed = lines[i].trim();
|
|
3137
3293
|
if (!trimmed) continue;
|
|
3138
3294
|
try {
|
|
3139
|
-
return {
|
|
3295
|
+
return {
|
|
3296
|
+
entry: JSON.parse(trimmed),
|
|
3297
|
+
size,
|
|
3298
|
+
birthtimeMs: stat7.birthtimeMs
|
|
3299
|
+
};
|
|
3140
3300
|
} catch {
|
|
3141
3301
|
}
|
|
3142
3302
|
}
|
|
3143
3303
|
suffix = lines[0] ?? "";
|
|
3144
3304
|
}
|
|
3145
|
-
return { size, birthtimeMs:
|
|
3305
|
+
return { size, birthtimeMs: stat7.birthtimeMs };
|
|
3146
3306
|
} finally {
|
|
3147
3307
|
await handle.close();
|
|
3148
3308
|
}
|
|
@@ -3561,8 +3721,8 @@ async function* reverseLines(filePath, maxBytes) {
|
|
|
3561
3721
|
return;
|
|
3562
3722
|
}
|
|
3563
3723
|
try {
|
|
3564
|
-
const
|
|
3565
|
-
const size = Math.min(
|
|
3724
|
+
const fileSize2 = (await handle.stat()).size;
|
|
3725
|
+
const size = Math.min(fileSize2, maxBytes ?? fileSize2);
|
|
3566
3726
|
let position = size;
|
|
3567
3727
|
let suffix = Buffer.alloc(0);
|
|
3568
3728
|
while (position > 0) {
|
|
@@ -4925,6 +5085,14 @@ var SKILL_LIMITS = {
|
|
|
4925
5085
|
* Consumer: `downloadGitHubTarball`.
|
|
4926
5086
|
*/
|
|
4927
5087
|
MAX_TARBALL_SIZE: 50 * 1024 * 1024,
|
|
5088
|
+
/**
|
|
5089
|
+
* Maximum size of a GitHub skill tarball after gzip decompression. The
|
|
5090
|
+
* compressed download limit alone does not protect against highly
|
|
5091
|
+
* compressible archives expanding until the process runs out of memory.
|
|
5092
|
+
*
|
|
5093
|
+
* Consumer: `downloadGitHubTarball`.
|
|
5094
|
+
*/
|
|
5095
|
+
MAX_UNCOMPRESSED_TARBALL_SIZE: 64 * 1024 * 1024,
|
|
4928
5096
|
/**
|
|
4929
5097
|
* Default total char budget for skill bodies injected in eager mode when
|
|
4930
5098
|
* `config.skills.eagerMaxChars` is unset. ~6k tokens. Skills are injected
|
|
@@ -4936,6 +5104,17 @@ var SKILL_LIMITS = {
|
|
|
4936
5104
|
* `skillEagerMaxChars`).
|
|
4937
5105
|
*/
|
|
4938
5106
|
EAGER_DEFAULT_MAX_CHARS: 24e3,
|
|
5107
|
+
/**
|
|
5108
|
+
* Default total char budget for compact (token-saving) skill bodies injected
|
|
5109
|
+
* by `buildCompactSkillBodiesText`. Mirrors the eager ceiling so compact mode
|
|
5110
|
+
* can never inject more total skill text than eager mode. Before this bound
|
|
5111
|
+
* existed, compact mode injected EVERY skill's compact body with no cap, so
|
|
5112
|
+
* the section grew linearly with the number of installed skills. Skills past
|
|
5113
|
+
* the budget overflow to a name list the agent loads via the `skill` tool.
|
|
5114
|
+
*
|
|
5115
|
+
* Consumer: `buildCompactSkillBodiesText` (default for its `budget` param).
|
|
5116
|
+
*/
|
|
5117
|
+
COMPACT_DEFAULT_MAX_CHARS: 24e3,
|
|
4939
5118
|
/**
|
|
4940
5119
|
* Auto-compact body limits (the token-saving fallback used when a skill has
|
|
4941
5120
|
* no hand-crafted `SKILL.save.md`). The Overview and Rules sections are
|
|
@@ -4964,34 +5143,148 @@ var SKILL_LIMITS = {
|
|
|
4964
5143
|
SKILL_BODY_LINE_LIMIT: 500
|
|
4965
5144
|
};
|
|
4966
5145
|
|
|
4967
|
-
// src/
|
|
4968
|
-
|
|
4969
|
-
|
|
4970
|
-
|
|
4971
|
-
|
|
4972
|
-
|
|
4973
|
-
|
|
4974
|
-
|
|
4975
|
-
|
|
4976
|
-
|
|
4977
|
-
|
|
4978
|
-
|
|
4979
|
-
|
|
4980
|
-
|
|
4981
|
-
|
|
5146
|
+
// src/skills/frontmatter.ts
|
|
5147
|
+
var SCALAR_KEYS = /* @__PURE__ */ new Set(["name", "description", "trigger", "version", "license", "compatibility"]);
|
|
5148
|
+
function parseSkillFrontmatter(raw) {
|
|
5149
|
+
const text = normalizeLineEndings(raw);
|
|
5150
|
+
if (!text.startsWith("---")) return {};
|
|
5151
|
+
const end = text.indexOf("\n---", 4);
|
|
5152
|
+
if (end === -1) return {};
|
|
5153
|
+
return parseFrontmatterBlock(text.slice(4, end));
|
|
5154
|
+
}
|
|
5155
|
+
function stripFrontmatter(raw) {
|
|
5156
|
+
const text = normalizeLineEndings(raw);
|
|
5157
|
+
if (!text.startsWith("---")) return text;
|
|
5158
|
+
const end = text.indexOf("\n---", 4);
|
|
5159
|
+
if (end === -1) return text;
|
|
5160
|
+
let body = text.slice(end + 4);
|
|
5161
|
+
if (body.startsWith("\n")) body = body.slice(1);
|
|
5162
|
+
return body;
|
|
5163
|
+
}
|
|
5164
|
+
function normalizeLineEndings(s) {
|
|
5165
|
+
return s.replace(/\r\n?/g, "\n");
|
|
5166
|
+
}
|
|
5167
|
+
function parseFrontmatterBlock(block) {
|
|
5168
|
+
const out = {};
|
|
5169
|
+
const lines = block.split("\n");
|
|
5170
|
+
let i = 0;
|
|
5171
|
+
while (i < lines.length) {
|
|
5172
|
+
const line = lines[i] ?? "";
|
|
5173
|
+
const m = /^([a-zA-Z][a-zA-Z0-9_-]*):\s*(.*)$/.exec(line);
|
|
5174
|
+
if (!m) {
|
|
5175
|
+
i++;
|
|
5176
|
+
continue;
|
|
5177
|
+
}
|
|
5178
|
+
const key = m[1] ?? "";
|
|
5179
|
+
const rest = (m[2] ?? "").trim();
|
|
5180
|
+
if (key === "metadata") {
|
|
5181
|
+
const map = {};
|
|
5182
|
+
i++;
|
|
5183
|
+
while (i < lines.length) {
|
|
5184
|
+
const sub = lines[i] ?? "";
|
|
5185
|
+
const sm = /^\s+([a-zA-Z0-9_.-]+):\s*(.*)$/.exec(sub);
|
|
5186
|
+
if (!sm) break;
|
|
5187
|
+
map[sm[1] ?? ""] = unquote((sm[2] ?? "").trim());
|
|
5188
|
+
i++;
|
|
5189
|
+
}
|
|
5190
|
+
if (Object.keys(map).length > 0) out.metadata = map;
|
|
5191
|
+
continue;
|
|
5192
|
+
}
|
|
5193
|
+
if (rest === "|" || rest === ">") {
|
|
5194
|
+
const collected = [];
|
|
5195
|
+
i++;
|
|
5196
|
+
while (i < lines.length) {
|
|
5197
|
+
const sub = lines[i] ?? "";
|
|
5198
|
+
if (sub === "" || sub.startsWith(" ") || sub.startsWith(" ")) {
|
|
5199
|
+
collected.push(sub.replace(/^\s+/, ""));
|
|
5200
|
+
i++;
|
|
5201
|
+
} else break;
|
|
5202
|
+
}
|
|
5203
|
+
out[normalizeKey2(key)] = collected.join("\n").trim();
|
|
5204
|
+
continue;
|
|
5205
|
+
}
|
|
5206
|
+
if (key === "allowed-tools" || key === "allowedTools") {
|
|
5207
|
+
out.allowedTools = rest.split(/[\s,]+/).filter(Boolean);
|
|
5208
|
+
i++;
|
|
5209
|
+
continue;
|
|
5210
|
+
}
|
|
5211
|
+
if (SCALAR_KEYS.has(key)) {
|
|
5212
|
+
out[key] = unquote(rest);
|
|
5213
|
+
i++;
|
|
5214
|
+
continue;
|
|
4982
5215
|
}
|
|
5216
|
+
i++;
|
|
4983
5217
|
}
|
|
4984
|
-
|
|
4985
|
-
return resolved;
|
|
5218
|
+
return out;
|
|
4986
5219
|
}
|
|
4987
|
-
function
|
|
4988
|
-
return
|
|
4989
|
-
/\{\{\s*([a-zA-Z0-9_.-]+)\s*\}\}/g,
|
|
4990
|
-
(match, key) => Object.hasOwn(values, key) ? values[key] ?? "" : match
|
|
4991
|
-
);
|
|
5220
|
+
function normalizeKey2(key) {
|
|
5221
|
+
return key === "allowed-tools" ? "allowedTools" : key;
|
|
4992
5222
|
}
|
|
4993
|
-
function
|
|
4994
|
-
if (
|
|
5223
|
+
function unquote(s) {
|
|
5224
|
+
if (s.length >= 2 && (s.startsWith('"') && s.endsWith('"') || s.startsWith("'") && s.endsWith("'"))) {
|
|
5225
|
+
return s.slice(1, -1);
|
|
5226
|
+
}
|
|
5227
|
+
return s;
|
|
5228
|
+
}
|
|
5229
|
+
function isValidSkillNameFormat(name) {
|
|
5230
|
+
return name.length >= 1 && name.length <= 64 && /^[a-z0-9]+(-[a-z0-9]+)*$/.test(name);
|
|
5231
|
+
}
|
|
5232
|
+
function validateSkillName(name, parentDirName) {
|
|
5233
|
+
const errors = [];
|
|
5234
|
+
if (!name || name.trim().length === 0) {
|
|
5235
|
+
errors.push("name is empty");
|
|
5236
|
+
return errors;
|
|
5237
|
+
}
|
|
5238
|
+
if (name.length > 64) errors.push(`name is ${name.length} characters (max 64)`);
|
|
5239
|
+
if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(name)) {
|
|
5240
|
+
errors.push(
|
|
5241
|
+
"name must be lowercase letters, digits, and single hyphens only (no leading/trailing/consecutive hyphens)"
|
|
5242
|
+
);
|
|
5243
|
+
}
|
|
5244
|
+
if (parentDirName !== void 0 && name !== parentDirName) {
|
|
5245
|
+
errors.push(`name "${name}" must match its parent directory "${parentDirName}"`);
|
|
5246
|
+
}
|
|
5247
|
+
return errors;
|
|
5248
|
+
}
|
|
5249
|
+
|
|
5250
|
+
// src/core/system-prompt-skill-text.ts
|
|
5251
|
+
function capSkillBody(body) {
|
|
5252
|
+
const max = SKILL_LIMITS.MAX_SKILL_BODY_CHARS;
|
|
5253
|
+
if (body.length <= max) return body;
|
|
5254
|
+
const budget = max - 1;
|
|
5255
|
+
const cut = body.lastIndexOf("\n\n", budget);
|
|
5256
|
+
const truncated = cut > budget / 2 ? body.slice(0, cut) : body.slice(0, budget);
|
|
5257
|
+
return truncated + "\u2026";
|
|
5258
|
+
}
|
|
5259
|
+
|
|
5260
|
+
// src/utils/instruction-file.ts
|
|
5261
|
+
import { readFileSync as readFileSync2, statSync as statSync2 } from "node:fs";
|
|
5262
|
+
import * as path9 from "node:path";
|
|
5263
|
+
import { fileURLToPath } from "node:url";
|
|
5264
|
+
var textCache = /* @__PURE__ */ new Map();
|
|
5265
|
+
var rootCandidates;
|
|
5266
|
+
function readBundledInstructionText(relativePath) {
|
|
5267
|
+
const cached = textCache.get(relativePath);
|
|
5268
|
+
if (cached !== void 0) return cached;
|
|
5269
|
+
let resolved = "";
|
|
5270
|
+
for (const root of instructionRootCandidates()) {
|
|
5271
|
+
try {
|
|
5272
|
+
resolved = readFileSync2(path9.join(root, relativePath), "utf8").trimEnd();
|
|
5273
|
+
break;
|
|
5274
|
+
} catch {
|
|
5275
|
+
}
|
|
5276
|
+
}
|
|
5277
|
+
textCache.set(relativePath, resolved);
|
|
5278
|
+
return resolved;
|
|
5279
|
+
}
|
|
5280
|
+
function renderInstructionTemplate(template, values) {
|
|
5281
|
+
return template.replace(
|
|
5282
|
+
/\{\{\s*([a-zA-Z0-9_.-]+)\s*\}\}/g,
|
|
5283
|
+
(match, key) => Object.hasOwn(values, key) ? values[key] ?? "" : match
|
|
5284
|
+
);
|
|
5285
|
+
}
|
|
5286
|
+
function instructionRootCandidates() {
|
|
5287
|
+
if (rootCandidates !== void 0) return rootCandidates;
|
|
4995
5288
|
const here = path9.dirname(fileURLToPath(import.meta.url));
|
|
4996
5289
|
const candidates = [
|
|
4997
5290
|
path9.resolve(here, "../../instructions"),
|
|
@@ -5786,6 +6079,7 @@ function encodeChronicleProjectServerMessage(message) {
|
|
|
5786
6079
|
}
|
|
5787
6080
|
|
|
5788
6081
|
// src/chronicle/project-server-endpoint.ts
|
|
6082
|
+
var CHRONICLE_PROJECT_SERVER_METADATA_FILE = "server.json";
|
|
5789
6083
|
function normalizedPath(value) {
|
|
5790
6084
|
const resolved = path11.resolve(value);
|
|
5791
6085
|
return process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
@@ -5804,6 +6098,9 @@ function chronicleProjectServerEndpoint(projectDir) {
|
|
|
5804
6098
|
`${key}.sock`
|
|
5805
6099
|
);
|
|
5806
6100
|
}
|
|
6101
|
+
function chronicleProjectServerMetadataPath(projectDir) {
|
|
6102
|
+
return path11.join(projectDir, "chronicle", CHRONICLE_PROJECT_SERVER_METADATA_FILE);
|
|
6103
|
+
}
|
|
5807
6104
|
|
|
5808
6105
|
// src/chronicle/project-server-client.ts
|
|
5809
6106
|
var CONNECT_ATTEMPT_TIMEOUT_MS = 750;
|
|
@@ -5858,6 +6155,8 @@ var ChronicleProjectServerClient = class {
|
|
|
5858
6155
|
connectResolve = null;
|
|
5859
6156
|
connectReject = null;
|
|
5860
6157
|
nextId = 1;
|
|
6158
|
+
/** WS-027: read from the owner-only metadata file — see currentAuthToken. */
|
|
6159
|
+
authToken;
|
|
5861
6160
|
pending = /* @__PURE__ */ new Map();
|
|
5862
6161
|
async call(op, args, options = {}) {
|
|
5863
6162
|
await this.ensureConnected(true);
|
|
@@ -5940,6 +6239,7 @@ var ChronicleProjectServerClient = class {
|
|
|
5940
6239
|
connectOnce() {
|
|
5941
6240
|
this.socket?.destroy();
|
|
5942
6241
|
this.socket = null;
|
|
6242
|
+
this.authToken = void 0;
|
|
5943
6243
|
this.info = null;
|
|
5944
6244
|
this.buffer = "";
|
|
5945
6245
|
return new Promise((resolve16, reject) => {
|
|
@@ -5970,13 +6270,42 @@ var ChronicleProjectServerClient = class {
|
|
|
5970
6270
|
socket.on("close", () => this.onClose(socket));
|
|
5971
6271
|
});
|
|
5972
6272
|
}
|
|
6273
|
+
/**
|
|
6274
|
+
* WS-027: the per-process token, read from the daemon's owner-only metadata
|
|
6275
|
+
* file — never from the `hello` frame, which the daemon sends to every
|
|
6276
|
+
* socket that connects (the mistake WS-028 found in the SAGE daemon).
|
|
6277
|
+
*
|
|
6278
|
+
* Read lazily and re-read while unknown: the daemon starts listening before
|
|
6279
|
+
* it writes metadata (endpoint ownership has to be won first), and a
|
|
6280
|
+
* respawned daemon mints a new token, so a cached wrong one would be sticky.
|
|
6281
|
+
*/
|
|
6282
|
+
currentAuthToken() {
|
|
6283
|
+
if (this.authToken === void 0) {
|
|
6284
|
+
try {
|
|
6285
|
+
const raw = fs7.readFileSync(
|
|
6286
|
+
chronicleProjectServerMetadataPath(this.options.projectDir),
|
|
6287
|
+
"utf8"
|
|
6288
|
+
);
|
|
6289
|
+
const parsed = JSON.parse(raw);
|
|
6290
|
+
if (typeof parsed.authToken === "string" && parsed.authToken.length > 0) {
|
|
6291
|
+
this.authToken = parsed.authToken;
|
|
6292
|
+
}
|
|
6293
|
+
} catch {
|
|
6294
|
+
}
|
|
6295
|
+
}
|
|
6296
|
+
return this.authToken;
|
|
6297
|
+
}
|
|
5973
6298
|
request(message, timeoutMs) {
|
|
5974
6299
|
const socket = this.socket;
|
|
5975
6300
|
if (!socket || socket.destroyed) {
|
|
5976
6301
|
return Promise.reject(new Error("Chronicle project server connection is unavailable"));
|
|
5977
6302
|
}
|
|
5978
6303
|
const id = this.nextId++;
|
|
5979
|
-
const encoded = encodeChronicleProjectServerMessage({
|
|
6304
|
+
const encoded = encodeChronicleProjectServerMessage({
|
|
6305
|
+
...message,
|
|
6306
|
+
id,
|
|
6307
|
+
authToken: this.currentAuthToken()
|
|
6308
|
+
});
|
|
5980
6309
|
if (encoded.length > CHRONICLE_PROJECT_SERVER_MAX_FRAME_CHARS) {
|
|
5981
6310
|
return Promise.reject(new Error("Chronicle project server request exceeded frame limit"));
|
|
5982
6311
|
}
|
|
@@ -6502,6 +6831,14 @@ var DEFAULT_DEBOUNCE_MS = 15e3;
|
|
|
6502
6831
|
var DEFAULT_MAX_FILES_PER_BATCH = 15;
|
|
6503
6832
|
var DEFAULT_MAX_CONCURRENT_REVIEWS = 2;
|
|
6504
6833
|
var DEFAULT_MAX_CASCADE_DEPTH = 2;
|
|
6834
|
+
var MAX_KNOWN_FINGERPRINTS = 5e3;
|
|
6835
|
+
function trimKnownFingerprints(map, max) {
|
|
6836
|
+
while (map.size > max) {
|
|
6837
|
+
const oldest = map.keys().next().value;
|
|
6838
|
+
if (oldest === void 0) break;
|
|
6839
|
+
map.delete(oldest);
|
|
6840
|
+
}
|
|
6841
|
+
}
|
|
6505
6842
|
function buildReviewerModelPool(provider, model, fallbackModels = []) {
|
|
6506
6843
|
const primaryProvider = provider.trim();
|
|
6507
6844
|
const primaryModel = model.trim();
|
|
@@ -6546,7 +6883,12 @@ function selectRoundRobinReviewerAssignment(pool, cursor, fallbackProvider = "",
|
|
|
6546
6883
|
}
|
|
6547
6884
|
function resolveAutoReviewConfig(cfg, sessionConfig) {
|
|
6548
6885
|
const mgr = new FallbackProfileManager(sessionConfig);
|
|
6549
|
-
const chain =
|
|
6886
|
+
const chain = mgr.resolveEffective({
|
|
6887
|
+
...cfg.fallbackProfile ? { fallbackProfile: cfg.fallbackProfile, fallbackAuto: false } : {
|
|
6888
|
+
fallbackModels: sessionConfig.fallbackModels,
|
|
6889
|
+
fallbackAuto: sessionConfig.fallbackAuto
|
|
6890
|
+
}
|
|
6891
|
+
});
|
|
6550
6892
|
const rawProvider = cfg.provider?.trim();
|
|
6551
6893
|
const rawModel = cfg.model?.trim();
|
|
6552
6894
|
const resolvedProvider = rawProvider || (chain.length > 0 ? chain[0].providerId : sessionConfig.provider);
|
|
@@ -6690,8 +7032,8 @@ async function snapshotChangedFiles(cwd) {
|
|
|
6690
7032
|
if (file.path.startsWith(".wrongstack/")) continue;
|
|
6691
7033
|
if (budget <= 0) break;
|
|
6692
7034
|
try {
|
|
6693
|
-
const
|
|
6694
|
-
if (!
|
|
7035
|
+
const stat7 = await fsp.stat(path14.join(cwd, file.path));
|
|
7036
|
+
if (!stat7.isFile() || stat7.size > MAX_SNAPSHOT_FILE_BYTES) continue;
|
|
6695
7037
|
const content = await fsp.readFile(path14.join(cwd, file.path), "utf8");
|
|
6696
7038
|
budget -= content.length;
|
|
6697
7039
|
snapshots.push({
|
|
@@ -6823,6 +7165,11 @@ function createAutoReviewPlugin() {
|
|
|
6823
7165
|
let pendingReviewWork;
|
|
6824
7166
|
let sessionEnded = false;
|
|
6825
7167
|
let latestIterationPayload;
|
|
7168
|
+
const rememberKnownFingerprint = (filePath, fingerprint2) => {
|
|
7169
|
+
if (knownFingerprints.has(filePath)) knownFingerprints.delete(filePath);
|
|
7170
|
+
knownFingerprints.set(filePath, fingerprint2);
|
|
7171
|
+
trimKnownFingerprints(knownFingerprints, MAX_KNOWN_FINGERPRINTS);
|
|
7172
|
+
};
|
|
6826
7173
|
let snapshotInFlight = false;
|
|
6827
7174
|
const withSnapshotLock = async (fn) => {
|
|
6828
7175
|
if (snapshotInFlight) {
|
|
@@ -6843,7 +7190,7 @@ function createAutoReviewPlugin() {
|
|
|
6843
7190
|
const snapshots = await withSnapshotLock(() => snapshotChangedFiles(cwd));
|
|
6844
7191
|
if (!snapshots) return;
|
|
6845
7192
|
for (const file of snapshots) {
|
|
6846
|
-
|
|
7193
|
+
rememberKnownFingerprint(file.path, file.fingerprint);
|
|
6847
7194
|
}
|
|
6848
7195
|
api.log.info(`[auto-review] seeded ${knownFingerprints.size} known file snapshot(s)`);
|
|
6849
7196
|
} catch {
|
|
@@ -7000,7 +7347,7 @@ function createAutoReviewPlugin() {
|
|
|
7000
7347
|
inFlight.push(inflightEntry);
|
|
7001
7348
|
for (const file of toReview) {
|
|
7002
7349
|
if (!emittedPaths.has(file.path)) continue;
|
|
7003
|
-
|
|
7350
|
+
rememberKnownFingerprint(file.path, file.fingerprint);
|
|
7004
7351
|
pendingFiles.delete(file.path);
|
|
7005
7352
|
}
|
|
7006
7353
|
api.log.info(
|
|
@@ -7144,7 +7491,6 @@ function createAutoReviewPlugin() {
|
|
|
7144
7491
|
|
|
7145
7492
|
// src/plugins/chimera-plugin.ts
|
|
7146
7493
|
init_error();
|
|
7147
|
-
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
7148
7494
|
import { spawn as spawn4 } from "node:child_process";
|
|
7149
7495
|
import * as fsp4 from "node:fs/promises";
|
|
7150
7496
|
import * as os5 from "node:os";
|
|
@@ -7220,10 +7566,20 @@ function parseFindingSegment(segment, severity, context) {
|
|
|
7220
7566
|
if (tagMatch) {
|
|
7221
7567
|
remaining = content.slice(tagMatch[0].length).trim();
|
|
7222
7568
|
}
|
|
7569
|
+
const citationMatch = remaining.match(
|
|
7570
|
+
/^(`+)([a-zA-Z_./\\:][^`]*[a-zA-Z0-9_./\\:])\1(?=\s*[—–-]|\s*$)/
|
|
7571
|
+
);
|
|
7572
|
+
if (citationMatch) {
|
|
7573
|
+
const inner = citationMatch[2];
|
|
7574
|
+
const afterCitation = remaining.slice(citationMatch[0].length);
|
|
7575
|
+
remaining = `${inner}${afterCitation}`;
|
|
7576
|
+
}
|
|
7223
7577
|
let file;
|
|
7224
7578
|
let line;
|
|
7225
7579
|
let desc = remaining;
|
|
7226
|
-
const refMatch = remaining.match(
|
|
7580
|
+
const refMatch = remaining.match(
|
|
7581
|
+
/^([a-zA-Z_./\\][a-zA-Z0-9_./\\-]*\.\w+)(?::(\d+))?\s+(?:[—–]|-)\s+(.+)$/
|
|
7582
|
+
);
|
|
7227
7583
|
if (refMatch) {
|
|
7228
7584
|
file = refMatch[1].trim();
|
|
7229
7585
|
if (refMatch[2] !== void 0) {
|
|
@@ -7321,12 +7677,26 @@ async function persistReviewReport(payload, reportId, projectDir) {
|
|
|
7321
7677
|
...cascadeDepth !== void 0 ? { cascadeDepth } : {}
|
|
7322
7678
|
};
|
|
7323
7679
|
await store.persist(input);
|
|
7680
|
+
if (reviewStatus === "success" && parsed.findings.length === 0 && parsed.unparseableCount === 0 && isExplicitAllClearReview(payload.reviewText)) {
|
|
7681
|
+
await store.transition(
|
|
7682
|
+
reportId,
|
|
7683
|
+
"completed",
|
|
7684
|
+
{ id: "chimera", kind: "system" },
|
|
7685
|
+
{
|
|
7686
|
+
reason: "Successful Chimera review produced no actionable findings"
|
|
7687
|
+
}
|
|
7688
|
+
);
|
|
7689
|
+
}
|
|
7324
7690
|
return {
|
|
7325
7691
|
reportId,
|
|
7326
7692
|
created: !existed,
|
|
7327
7693
|
totalFindings: parsed.findings.length
|
|
7328
7694
|
};
|
|
7329
7695
|
}
|
|
7696
|
+
function isExplicitAllClearReview(text) {
|
|
7697
|
+
const normalized = text.trim().toLowerCase();
|
|
7698
|
+
return normalized.startsWith("## \u{1F982} chimera review \u2014 all clear") || normalized.includes("chimera review: all clear");
|
|
7699
|
+
}
|
|
7330
7700
|
async function syncReportCompletion(reportId, projectDir, actor) {
|
|
7331
7701
|
const reportStore = new JsonlReportStore(projectDir);
|
|
7332
7702
|
const findingStore = new JsonlFindingStore(projectDir);
|
|
@@ -7799,49 +8169,6 @@ async function showStatus(ctx) {
|
|
|
7799
8169
|
].join("\n");
|
|
7800
8170
|
}
|
|
7801
8171
|
|
|
7802
|
-
// src/plugins/review-finding-integration.ts
|
|
7803
|
-
init_review_finding_store();
|
|
7804
|
-
async function integrateFindings(payload, projectDir, reportId) {
|
|
7805
|
-
if (!payload.reviewText || payload.reviewText.trim().length === 0) {
|
|
7806
|
-
return { created: 0, relinked: 0, reopened: 0, totalFindings: 0, unparseableCount: 0 };
|
|
7807
|
-
}
|
|
7808
|
-
const store = new JsonlFindingStore(projectDir);
|
|
7809
|
-
const source = (payload.bundle.cascadeDepth ?? 0) > 0 ? "cascade" : payload.bundle.cascadeOn !== void 0 && payload.bundle.cascadeOn !== "off" ? "auto" : "chimera";
|
|
7810
|
-
const agentId = payload.bundle.fileProvenance?.find((entry) => entry.agentId)?.agentId ?? "chimera-review";
|
|
7811
|
-
const sessionId = payload.sessionId ?? payload.cwd;
|
|
7812
|
-
const model = payload.bundle.config.model;
|
|
7813
|
-
const parsed = parseChimeraReviewReport(payload.reviewText, {
|
|
7814
|
-
sessionId,
|
|
7815
|
-
agentId,
|
|
7816
|
-
reviewerModel: model,
|
|
7817
|
-
reviewType: source,
|
|
7818
|
-
reportId
|
|
7819
|
-
});
|
|
7820
|
-
if (parsed.findings.length === 0) {
|
|
7821
|
-
return {
|
|
7822
|
-
created: 0,
|
|
7823
|
-
relinked: 0,
|
|
7824
|
-
reopened: 0,
|
|
7825
|
-
totalFindings: 0,
|
|
7826
|
-
unparseableCount: parsed.unparseableCount
|
|
7827
|
-
};
|
|
7828
|
-
}
|
|
7829
|
-
const result = await store.upsert(parsed.findings, {
|
|
7830
|
-
sessionId,
|
|
7831
|
-
reportId,
|
|
7832
|
-
agentId,
|
|
7833
|
-
model
|
|
7834
|
-
});
|
|
7835
|
-
return {
|
|
7836
|
-
created: result.created,
|
|
7837
|
-
relinked: result.relinked,
|
|
7838
|
-
reopened: result.reopened,
|
|
7839
|
-
reportId,
|
|
7840
|
-
totalFindings: parsed.findings.length,
|
|
7841
|
-
unparseableCount: parsed.unparseableCount
|
|
7842
|
-
};
|
|
7843
|
-
}
|
|
7844
|
-
|
|
7845
8172
|
// src/plugins/chimera-plugin.ts
|
|
7846
8173
|
var DEFAULT_MAX_FILES = 15;
|
|
7847
8174
|
var DEFAULT_CASCADE_ON = "off";
|
|
@@ -7997,18 +8324,6 @@ function buildReviewCommand(_getConfig) {
|
|
|
7997
8324
|
}
|
|
7998
8325
|
};
|
|
7999
8326
|
}
|
|
8000
|
-
async function tryPersistFindings(payload) {
|
|
8001
|
-
if (!payload || typeof payload !== "object") return;
|
|
8002
|
-
const p = payload;
|
|
8003
|
-
const cwd = p.cwd ?? p.bundle?.cwd;
|
|
8004
|
-
if (!cwd) return;
|
|
8005
|
-
const slug = projectSlug(cwd);
|
|
8006
|
-
const globalRoot = path17.join(os5.homedir(), ".wrongstack");
|
|
8007
|
-
const projectDir = path17.join(globalRoot, "projects", slug);
|
|
8008
|
-
const reportId = randomUUID6();
|
|
8009
|
-
await persistReviewReport(payload, reportId, projectDir);
|
|
8010
|
-
await integrateFindings(payload, projectDir, reportId);
|
|
8011
|
-
}
|
|
8012
8327
|
function createChimeraPlugin() {
|
|
8013
8328
|
return {
|
|
8014
8329
|
name: "wstack-chimera",
|
|
@@ -8037,9 +8352,6 @@ function createChimeraPlugin() {
|
|
|
8037
8352
|
});
|
|
8038
8353
|
api.onPattern("chimera.review_complete", (_event, payload) => {
|
|
8039
8354
|
recordCompletedReview(api.events, payload);
|
|
8040
|
-
tryPersistFindings(payload).catch((err) => {
|
|
8041
|
-
api.log.warn(`[review-finding] failed to persist findings: ${toErrorMessage(err)}`);
|
|
8042
|
-
});
|
|
8043
8355
|
});
|
|
8044
8356
|
if (!resolved.enabled) {
|
|
8045
8357
|
api.log.info("[chimera] disabled by config");
|
|
@@ -8621,8 +8933,8 @@ var PromptUsageStore = class {
|
|
|
8621
8933
|
}
|
|
8622
8934
|
async fileSignature() {
|
|
8623
8935
|
try {
|
|
8624
|
-
const
|
|
8625
|
-
return { size:
|
|
8936
|
+
const stat7 = await fs10.stat(this.file);
|
|
8937
|
+
return { size: stat7.size, mtimeMs: stat7.mtimeMs, ctimeMs: stat7.ctimeMs };
|
|
8626
8938
|
} catch {
|
|
8627
8939
|
return null;
|
|
8628
8940
|
}
|
|
@@ -9032,12 +9344,12 @@ function parseFlags(input) {
|
|
|
9032
9344
|
while (s.startsWith("--") && (m = flagRe.exec(s))) {
|
|
9033
9345
|
const name = expectDefined(m[1]);
|
|
9034
9346
|
const rawVal = m[2] ?? m[3] ?? "true";
|
|
9035
|
-
flags[name] =
|
|
9347
|
+
flags[name] = unquote2(rawVal);
|
|
9036
9348
|
s = s.slice(m[0].length);
|
|
9037
9349
|
}
|
|
9038
9350
|
return { flags, positional: s.trim() };
|
|
9039
9351
|
}
|
|
9040
|
-
function
|
|
9352
|
+
function unquote2(v) {
|
|
9041
9353
|
if (v.startsWith('"') && v.endsWith('"') || v.startsWith("'") && v.endsWith("'")) {
|
|
9042
9354
|
return v.slice(1, -1);
|
|
9043
9355
|
}
|
|
@@ -9076,7 +9388,7 @@ function parseKeyValues(kvs) {
|
|
|
9076
9388
|
const out = {};
|
|
9077
9389
|
for (const kv of kvs) {
|
|
9078
9390
|
const eq = kv.indexOf("=");
|
|
9079
|
-
if (eq > 0) out[kv.slice(0, eq)] =
|
|
9391
|
+
if (eq > 0) out[kv.slice(0, eq)] = unquote2(kv.slice(eq + 1));
|
|
9080
9392
|
}
|
|
9081
9393
|
return out;
|
|
9082
9394
|
}
|
|
@@ -9096,9 +9408,123 @@ function dim(s) {
|
|
|
9096
9408
|
return `\x1B[2m${s}\x1B[0m`;
|
|
9097
9409
|
}
|
|
9098
9410
|
|
|
9411
|
+
// src/plugins/review-finding-integration.ts
|
|
9412
|
+
init_review_finding_store();
|
|
9413
|
+
async function integrateFindings(payload, projectDir, reportId) {
|
|
9414
|
+
if (!payload.reviewText || payload.reviewText.trim().length === 0) {
|
|
9415
|
+
return { created: 0, relinked: 0, reopened: 0, totalFindings: 0, unparseableCount: 0 };
|
|
9416
|
+
}
|
|
9417
|
+
const store = new JsonlFindingStore(projectDir);
|
|
9418
|
+
const source = (payload.bundle.cascadeDepth ?? 0) > 0 ? "cascade" : payload.bundle.cascadeOn !== void 0 && payload.bundle.cascadeOn !== "off" ? "auto" : "chimera";
|
|
9419
|
+
const agentId = payload.bundle.fileProvenance?.find((entry) => entry.agentId)?.agentId ?? "chimera-review";
|
|
9420
|
+
const sessionId = payload.sessionId ?? payload.cwd;
|
|
9421
|
+
const model = payload.bundle.config.model;
|
|
9422
|
+
const parsed = parseChimeraReviewReport(payload.reviewText, {
|
|
9423
|
+
sessionId,
|
|
9424
|
+
agentId,
|
|
9425
|
+
reviewerModel: model,
|
|
9426
|
+
reviewType: source,
|
|
9427
|
+
reportId
|
|
9428
|
+
});
|
|
9429
|
+
if (parsed.findings.length === 0) {
|
|
9430
|
+
return {
|
|
9431
|
+
created: 0,
|
|
9432
|
+
relinked: 0,
|
|
9433
|
+
reopened: 0,
|
|
9434
|
+
totalFindings: 0,
|
|
9435
|
+
unparseableCount: parsed.unparseableCount
|
|
9436
|
+
};
|
|
9437
|
+
}
|
|
9438
|
+
const result = await store.upsert(parsed.findings, {
|
|
9439
|
+
sessionId,
|
|
9440
|
+
reportId,
|
|
9441
|
+
agentId,
|
|
9442
|
+
model
|
|
9443
|
+
});
|
|
9444
|
+
return {
|
|
9445
|
+
created: result.created,
|
|
9446
|
+
relinked: result.relinked,
|
|
9447
|
+
reopened: result.reopened,
|
|
9448
|
+
reportId,
|
|
9449
|
+
totalFindings: parsed.findings.length,
|
|
9450
|
+
unparseableCount: parsed.unparseableCount
|
|
9451
|
+
};
|
|
9452
|
+
}
|
|
9453
|
+
|
|
9454
|
+
// src/plugins/review-store-maintenance.ts
|
|
9455
|
+
init_atomic_write();
|
|
9456
|
+
init_review_finding_store();
|
|
9457
|
+
init_review_report_store();
|
|
9458
|
+
import * as fsp5 from "node:fs/promises";
|
|
9459
|
+
import * as path21 from "node:path";
|
|
9460
|
+
var REVIEW_STORE_COMPACTION_THRESHOLD_BYTES = 8 * 1024 * 1024;
|
|
9461
|
+
var REVIEW_STORE_COMPACTION_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
9462
|
+
var REVIEW_STORE_MAINTENANCE_FILE = ".review-store-maintenance.json";
|
|
9463
|
+
async function maybeCompactReviewStores(projectDir, opts = {}) {
|
|
9464
|
+
const thresholdBytes = opts.thresholdBytes ?? REVIEW_STORE_COMPACTION_THRESHOLD_BYTES;
|
|
9465
|
+
const intervalMs = opts.intervalMs ?? REVIEW_STORE_COMPACTION_INTERVAL_MS;
|
|
9466
|
+
const now = opts.now ?? Date.now();
|
|
9467
|
+
const maintenancePath = path21.join(projectDir, REVIEW_STORE_MAINTENANCE_FILE);
|
|
9468
|
+
return withFileLock(maintenancePath, async () => {
|
|
9469
|
+
const totalBytes = await fileSize(resolveReportStorePath(projectDir)) + await fileSize(resolveFindingStorePath(projectDir));
|
|
9470
|
+
if (totalBytes < thresholdBytes) {
|
|
9471
|
+
return emptyResult("below_threshold", totalBytes);
|
|
9472
|
+
}
|
|
9473
|
+
const state = await readMaintenanceState(maintenancePath);
|
|
9474
|
+
if (state && now - new Date(state.compactedAt).getTime() < intervalMs) {
|
|
9475
|
+
return emptyResult("interval", totalBytes);
|
|
9476
|
+
}
|
|
9477
|
+
const reportResult = await new JsonlReportStore(projectDir).compact();
|
|
9478
|
+
const findingResult = await new JsonlFindingStore(projectDir).compact();
|
|
9479
|
+
const nextState = {
|
|
9480
|
+
compactedAt: new Date(now).toISOString(),
|
|
9481
|
+
totalBytesBefore: totalBytes
|
|
9482
|
+
};
|
|
9483
|
+
await atomicWrite(maintenancePath, `${JSON.stringify(nextState)}
|
|
9484
|
+
`, { mode: 384 });
|
|
9485
|
+
return {
|
|
9486
|
+
compacted: true,
|
|
9487
|
+
totalBytes,
|
|
9488
|
+
reason: "compacted",
|
|
9489
|
+
removedReports: reportResult.removed,
|
|
9490
|
+
removedFindings: findingResult.removed,
|
|
9491
|
+
eventsFolded: reportResult.eventsFolded + findingResult.eventsFolded
|
|
9492
|
+
};
|
|
9493
|
+
});
|
|
9494
|
+
}
|
|
9495
|
+
function emptyResult(reason, totalBytes) {
|
|
9496
|
+
return {
|
|
9497
|
+
compacted: false,
|
|
9498
|
+
totalBytes,
|
|
9499
|
+
reason,
|
|
9500
|
+
removedReports: 0,
|
|
9501
|
+
removedFindings: 0,
|
|
9502
|
+
eventsFolded: 0
|
|
9503
|
+
};
|
|
9504
|
+
}
|
|
9505
|
+
async function fileSize(filePath) {
|
|
9506
|
+
try {
|
|
9507
|
+
return (await fsp5.stat(filePath)).size;
|
|
9508
|
+
} catch (error) {
|
|
9509
|
+
if (error.code === "ENOENT") return 0;
|
|
9510
|
+
throw error;
|
|
9511
|
+
}
|
|
9512
|
+
}
|
|
9513
|
+
async function readMaintenanceState(filePath) {
|
|
9514
|
+
try {
|
|
9515
|
+
const parsed = JSON.parse(await fsp5.readFile(filePath, "utf8"));
|
|
9516
|
+
return typeof parsed.compactedAt === "string" && Number.isFinite(parsed.totalBytesBefore) ? parsed : null;
|
|
9517
|
+
} catch (error) {
|
|
9518
|
+
if (error.code === "ENOENT" || error instanceof SyntaxError) {
|
|
9519
|
+
return null;
|
|
9520
|
+
}
|
|
9521
|
+
throw error;
|
|
9522
|
+
}
|
|
9523
|
+
}
|
|
9524
|
+
|
|
9099
9525
|
// src/plugins/skills-plugin.ts
|
|
9100
9526
|
import * as os7 from "node:os";
|
|
9101
|
-
import * as
|
|
9527
|
+
import * as path26 from "node:path";
|
|
9102
9528
|
|
|
9103
9529
|
// src/skills/foreign-sources.ts
|
|
9104
9530
|
var FOREIGN_SKILL_TOOLS = [
|
|
@@ -9281,104 +9707,7 @@ function numField(rec, key) {
|
|
|
9281
9707
|
init_errors();
|
|
9282
9708
|
import { spawn as spawn5 } from "node:child_process";
|
|
9283
9709
|
import * as fs12 from "node:fs/promises";
|
|
9284
|
-
import * as
|
|
9285
|
-
|
|
9286
|
-
// src/skills/frontmatter.ts
|
|
9287
|
-
var SCALAR_KEYS = /* @__PURE__ */ new Set(["name", "description", "version", "license", "compatibility"]);
|
|
9288
|
-
function parseSkillFrontmatter(raw) {
|
|
9289
|
-
const text = normalizeLineEndings(raw);
|
|
9290
|
-
if (!text.startsWith("---")) return {};
|
|
9291
|
-
const end = text.indexOf("\n---", 4);
|
|
9292
|
-
if (end === -1) return {};
|
|
9293
|
-
return parseFrontmatterBlock(text.slice(4, end));
|
|
9294
|
-
}
|
|
9295
|
-
function normalizeLineEndings(s) {
|
|
9296
|
-
return s.replace(/\r\n?/g, "\n");
|
|
9297
|
-
}
|
|
9298
|
-
function parseFrontmatterBlock(block) {
|
|
9299
|
-
const out = {};
|
|
9300
|
-
const lines = block.split("\n");
|
|
9301
|
-
let i = 0;
|
|
9302
|
-
while (i < lines.length) {
|
|
9303
|
-
const line = lines[i] ?? "";
|
|
9304
|
-
const m = /^([a-zA-Z][a-zA-Z0-9_-]*):\s*(.*)$/.exec(line);
|
|
9305
|
-
if (!m) {
|
|
9306
|
-
i++;
|
|
9307
|
-
continue;
|
|
9308
|
-
}
|
|
9309
|
-
const key = m[1] ?? "";
|
|
9310
|
-
const rest = (m[2] ?? "").trim();
|
|
9311
|
-
if (key === "metadata") {
|
|
9312
|
-
const map = {};
|
|
9313
|
-
i++;
|
|
9314
|
-
while (i < lines.length) {
|
|
9315
|
-
const sub = lines[i] ?? "";
|
|
9316
|
-
const sm = /^\s+([a-zA-Z0-9_.-]+):\s*(.*)$/.exec(sub);
|
|
9317
|
-
if (!sm) break;
|
|
9318
|
-
map[sm[1] ?? ""] = unquote2((sm[2] ?? "").trim());
|
|
9319
|
-
i++;
|
|
9320
|
-
}
|
|
9321
|
-
if (Object.keys(map).length > 0) out.metadata = map;
|
|
9322
|
-
continue;
|
|
9323
|
-
}
|
|
9324
|
-
if (rest === "|" || rest === ">") {
|
|
9325
|
-
const collected = [];
|
|
9326
|
-
i++;
|
|
9327
|
-
while (i < lines.length) {
|
|
9328
|
-
const sub = lines[i] ?? "";
|
|
9329
|
-
if (sub === "" || sub.startsWith(" ") || sub.startsWith(" ")) {
|
|
9330
|
-
collected.push(sub.replace(/^\s+/, ""));
|
|
9331
|
-
i++;
|
|
9332
|
-
} else break;
|
|
9333
|
-
}
|
|
9334
|
-
out[normalizeKey2(key)] = collected.join("\n").trim();
|
|
9335
|
-
continue;
|
|
9336
|
-
}
|
|
9337
|
-
if (key === "allowed-tools" || key === "allowedTools") {
|
|
9338
|
-
out.allowedTools = rest.split(/[\s,]+/).filter(Boolean);
|
|
9339
|
-
i++;
|
|
9340
|
-
continue;
|
|
9341
|
-
}
|
|
9342
|
-
if (SCALAR_KEYS.has(key)) {
|
|
9343
|
-
out[key] = unquote2(rest);
|
|
9344
|
-
i++;
|
|
9345
|
-
continue;
|
|
9346
|
-
}
|
|
9347
|
-
i++;
|
|
9348
|
-
}
|
|
9349
|
-
return out;
|
|
9350
|
-
}
|
|
9351
|
-
function normalizeKey2(key) {
|
|
9352
|
-
return key === "allowed-tools" ? "allowedTools" : key;
|
|
9353
|
-
}
|
|
9354
|
-
function unquote2(s) {
|
|
9355
|
-
if (s.length >= 2 && (s.startsWith('"') && s.endsWith('"') || s.startsWith("'") && s.endsWith("'"))) {
|
|
9356
|
-
return s.slice(1, -1);
|
|
9357
|
-
}
|
|
9358
|
-
return s;
|
|
9359
|
-
}
|
|
9360
|
-
function isValidSkillNameFormat(name) {
|
|
9361
|
-
return name.length >= 1 && name.length <= 64 && /^[a-z0-9]+(-[a-z0-9]+)*$/.test(name);
|
|
9362
|
-
}
|
|
9363
|
-
function validateSkillName(name, parentDirName) {
|
|
9364
|
-
const errors = [];
|
|
9365
|
-
if (!name || name.trim().length === 0) {
|
|
9366
|
-
errors.push("name is empty");
|
|
9367
|
-
return errors;
|
|
9368
|
-
}
|
|
9369
|
-
if (name.length > 64) errors.push(`name is ${name.length} characters (max 64)`);
|
|
9370
|
-
if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(name)) {
|
|
9371
|
-
errors.push(
|
|
9372
|
-
"name must be lowercase letters, digits, and single hyphens only (no leading/trailing/consecutive hyphens)"
|
|
9373
|
-
);
|
|
9374
|
-
}
|
|
9375
|
-
if (parentDirName !== void 0 && name !== parentDirName) {
|
|
9376
|
-
errors.push(`name "${name}" must match its parent directory "${parentDirName}"`);
|
|
9377
|
-
}
|
|
9378
|
-
return errors;
|
|
9379
|
-
}
|
|
9380
|
-
|
|
9381
|
-
// src/skills/skill-generator.ts
|
|
9710
|
+
import * as path22 from "node:path";
|
|
9382
9711
|
async function validateSkillNameAvailable(name, loader) {
|
|
9383
9712
|
const formatViolations = validateSkillName(name);
|
|
9384
9713
|
const conflicts = loader ? (await loader.listEntries()).filter((e) => e.name === name) : [];
|
|
@@ -9497,8 +9826,8 @@ async function writeSkeletonSkill(skillsDir, body, opts = {}) {
|
|
|
9497
9826
|
subsystem: "general"
|
|
9498
9827
|
});
|
|
9499
9828
|
}
|
|
9500
|
-
const skillDir =
|
|
9501
|
-
const skillFile =
|
|
9829
|
+
const skillDir = path22.join(skillsDir, name);
|
|
9830
|
+
const skillFile = path22.join(skillDir, "SKILL.md");
|
|
9502
9831
|
if (!opts.overwrite) {
|
|
9503
9832
|
try {
|
|
9504
9833
|
await fs12.access(skillFile);
|
|
@@ -9557,13 +9886,14 @@ function defaultEditor() {
|
|
|
9557
9886
|
init_errors();
|
|
9558
9887
|
init_error();
|
|
9559
9888
|
import * as fs15 from "node:fs/promises";
|
|
9560
|
-
import * as
|
|
9889
|
+
import * as path25 from "node:path";
|
|
9561
9890
|
|
|
9562
9891
|
// src/skills/github-fetcher.ts
|
|
9563
9892
|
init_errors();
|
|
9893
|
+
import { createWriteStream } from "node:fs";
|
|
9564
9894
|
import * as fs13 from "node:fs/promises";
|
|
9565
9895
|
import * as os6 from "node:os";
|
|
9566
|
-
import * as
|
|
9896
|
+
import * as path23 from "node:path";
|
|
9567
9897
|
import { Readable } from "node:stream";
|
|
9568
9898
|
import { pipeline } from "node:stream/promises";
|
|
9569
9899
|
import { createGunzip } from "node:zlib";
|
|
@@ -9590,6 +9920,46 @@ function parseSkillRef(input) {
|
|
|
9590
9920
|
}
|
|
9591
9921
|
return { owner: expectDefined(parts[0]), repo: expectDefined(parts[1]), ref };
|
|
9592
9922
|
}
|
|
9923
|
+
async function writeBoundedGzipStream(source, outputPath, maxBytes, maxCompressedBytes = SKILL_LIMITS.MAX_TARBALL_SIZE) {
|
|
9924
|
+
let compressedBytes = 0;
|
|
9925
|
+
let writtenBytes = 0;
|
|
9926
|
+
await pipeline(
|
|
9927
|
+
source,
|
|
9928
|
+
async function* (chunks) {
|
|
9929
|
+
for await (const chunk of chunks) {
|
|
9930
|
+
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
9931
|
+
compressedBytes += buffer.byteLength;
|
|
9932
|
+
if (compressedBytes > maxCompressedBytes) {
|
|
9933
|
+
throw new WrongStackError({
|
|
9934
|
+
message: `Compressed tarball too large. Max: ${maxCompressedBytes / 1024 / 1024}MB`,
|
|
9935
|
+
code: ERROR_CODES.UNKNOWN,
|
|
9936
|
+
subsystem: "general",
|
|
9937
|
+
context: { compressedBytes, maxBytes: maxCompressedBytes }
|
|
9938
|
+
});
|
|
9939
|
+
}
|
|
9940
|
+
yield buffer;
|
|
9941
|
+
}
|
|
9942
|
+
},
|
|
9943
|
+
createGunzip(),
|
|
9944
|
+
async function* (chunks) {
|
|
9945
|
+
for await (const chunk of chunks) {
|
|
9946
|
+
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
9947
|
+
writtenBytes += buffer.byteLength;
|
|
9948
|
+
if (writtenBytes > maxBytes) {
|
|
9949
|
+
throw new WrongStackError({
|
|
9950
|
+
message: `Uncompressed tarball too large. Max: ${maxBytes / 1024 / 1024}MB`,
|
|
9951
|
+
code: ERROR_CODES.UNKNOWN,
|
|
9952
|
+
subsystem: "general",
|
|
9953
|
+
context: { uncompressedBytes: writtenBytes, maxBytes }
|
|
9954
|
+
});
|
|
9955
|
+
}
|
|
9956
|
+
yield buffer;
|
|
9957
|
+
}
|
|
9958
|
+
},
|
|
9959
|
+
createWriteStream(outputPath, { flags: "wx" })
|
|
9960
|
+
);
|
|
9961
|
+
return writtenBytes;
|
|
9962
|
+
}
|
|
9593
9963
|
function resolveGitHubToken(env = process.env) {
|
|
9594
9964
|
const raw = env["WRONGSTACK_GITHUB_TOKEN"] ?? env["GITHUB_TOKEN"] ?? env["GH_TOKEN"];
|
|
9595
9965
|
if (!raw) return void 0;
|
|
@@ -9665,7 +10035,7 @@ async function downloadGitHubTarball(parsed) {
|
|
|
9665
10035
|
}
|
|
9666
10036
|
});
|
|
9667
10037
|
}
|
|
9668
|
-
const tempDir = await fs13.mkdtemp(
|
|
10038
|
+
const tempDir = await fs13.mkdtemp(path23.join(os6.tmpdir(), "wskill-"));
|
|
9669
10039
|
try {
|
|
9670
10040
|
if (!response.body) {
|
|
9671
10041
|
throw new WrongStackError({
|
|
@@ -9676,15 +10046,14 @@ async function downloadGitHubTarball(parsed) {
|
|
|
9676
10046
|
});
|
|
9677
10047
|
}
|
|
9678
10048
|
const nodeStream = Readable.fromWeb(response.body);
|
|
9679
|
-
const
|
|
9680
|
-
|
|
9681
|
-
|
|
9682
|
-
|
|
9683
|
-
|
|
9684
|
-
|
|
9685
|
-
|
|
9686
|
-
|
|
9687
|
-
await extractTar(tarBuf, tempDir);
|
|
10049
|
+
const tarPath = path23.join(tempDir, ".wrongstack-download.tar");
|
|
10050
|
+
await writeBoundedGzipStream(nodeStream, tarPath, SKILL_LIMITS.MAX_UNCOMPRESSED_TARBALL_SIZE);
|
|
10051
|
+
const tarBuf = await fs13.readFile(tarPath);
|
|
10052
|
+
try {
|
|
10053
|
+
await extractTar(tarBuf, tempDir);
|
|
10054
|
+
} finally {
|
|
10055
|
+
await fs13.rm(tarPath, { force: true });
|
|
10056
|
+
}
|
|
9688
10057
|
return { tempDir };
|
|
9689
10058
|
} catch (err) {
|
|
9690
10059
|
await fs13.rm(tempDir, { recursive: true, force: true }).catch(() => {
|
|
@@ -9692,6 +10061,44 @@ async function downloadGitHubTarball(parsed) {
|
|
|
9692
10061
|
throw err;
|
|
9693
10062
|
}
|
|
9694
10063
|
}
|
|
10064
|
+
function readTarSize(buf, start) {
|
|
10065
|
+
const first = buf[start] ?? 0;
|
|
10066
|
+
if ((first & 128) !== 0) {
|
|
10067
|
+
if (first === 255) {
|
|
10068
|
+
throw new Error("tar: negative base-256 size field");
|
|
10069
|
+
}
|
|
10070
|
+
let value = first & 127;
|
|
10071
|
+
for (let i = start + 1; i < start + 12; i++) {
|
|
10072
|
+
value = value * 256 + (buf[i] ?? 0);
|
|
10073
|
+
if (!Number.isSafeInteger(value)) {
|
|
10074
|
+
throw new Error("tar: base-256 size exceeds the safe integer range");
|
|
10075
|
+
}
|
|
10076
|
+
}
|
|
10077
|
+
return value;
|
|
10078
|
+
}
|
|
10079
|
+
const text = readTarString(buf, start, 12).trim();
|
|
10080
|
+
if (text === "") return 0;
|
|
10081
|
+
if (!/^[0-7]+$/.test(text)) {
|
|
10082
|
+
throw new Error(`tar: unparseable size field ${JSON.stringify(text)}`);
|
|
10083
|
+
}
|
|
10084
|
+
const parsed = Number.parseInt(text, 8);
|
|
10085
|
+
if (!Number.isSafeInteger(parsed) || parsed < 0) {
|
|
10086
|
+
throw new Error("tar: size field out of range");
|
|
10087
|
+
}
|
|
10088
|
+
return parsed;
|
|
10089
|
+
}
|
|
10090
|
+
function readTarString(buf, start, maxLen) {
|
|
10091
|
+
let end = start;
|
|
10092
|
+
while (end < start + maxLen && end < buf.length && buf[end] !== 0) {
|
|
10093
|
+
end++;
|
|
10094
|
+
}
|
|
10095
|
+
return buf.subarray(start, end).toString("utf8");
|
|
10096
|
+
}
|
|
10097
|
+
function stripTopDir(p) {
|
|
10098
|
+
const idx = p.indexOf("/");
|
|
10099
|
+
if (idx === -1) return "";
|
|
10100
|
+
return p.slice(idx + 1);
|
|
10101
|
+
}
|
|
9695
10102
|
async function extractTar(buf, destDir) {
|
|
9696
10103
|
let offset = 0;
|
|
9697
10104
|
while (offset + 512 <= buf.length) {
|
|
@@ -9699,15 +10106,15 @@ async function extractTar(buf, destDir) {
|
|
|
9699
10106
|
if (header.every((b) => b === 0)) break;
|
|
9700
10107
|
const name = readTarString(buf, offset, 100);
|
|
9701
10108
|
const prefix = readTarString(buf, offset + 345, 155);
|
|
9702
|
-
const size =
|
|
10109
|
+
const size = readTarSize(buf, offset + 124);
|
|
9703
10110
|
const typeflag = buf[offset + 156] ?? 0;
|
|
9704
10111
|
const fullPath = prefix ? `${prefix}/${name}` : name;
|
|
9705
10112
|
const relPath = stripTopDir(fullPath);
|
|
9706
10113
|
if (relPath && relPath !== "." && relPath !== "..") {
|
|
9707
|
-
const destPath =
|
|
9708
|
-
const resolvedDest =
|
|
9709
|
-
const resolvedRoot =
|
|
9710
|
-
if (resolvedDest !== resolvedRoot && !resolvedDest.startsWith(resolvedRoot +
|
|
10114
|
+
const destPath = path23.join(destDir, relPath);
|
|
10115
|
+
const resolvedDest = path23.resolve(destPath);
|
|
10116
|
+
const resolvedRoot = path23.resolve(destDir);
|
|
10117
|
+
if (resolvedDest !== resolvedRoot && !resolvedDest.startsWith(resolvedRoot + path23.sep)) {
|
|
9711
10118
|
offset += 512 + Math.ceil(size / 512) * 512;
|
|
9712
10119
|
continue;
|
|
9713
10120
|
}
|
|
@@ -9717,7 +10124,7 @@ async function extractTar(buf, destDir) {
|
|
|
9717
10124
|
}
|
|
9718
10125
|
}
|
|
9719
10126
|
if ((typeflag === 48 || typeflag === 0 || typeflag === 0) && size > 0) {
|
|
9720
|
-
const dir =
|
|
10127
|
+
const dir = path23.dirname(destPath);
|
|
9721
10128
|
await fs13.mkdir(dir, { recursive: true });
|
|
9722
10129
|
const dataStart = offset + 512;
|
|
9723
10130
|
const dataEnd = dataStart + size;
|
|
@@ -9728,23 +10135,11 @@ async function extractTar(buf, destDir) {
|
|
|
9728
10135
|
offset += 512 + Math.ceil(size / 512) * 512;
|
|
9729
10136
|
}
|
|
9730
10137
|
}
|
|
9731
|
-
function readTarString(buf, start, maxLen) {
|
|
9732
|
-
let end = start;
|
|
9733
|
-
while (end < start + maxLen && end < buf.length && buf[end] !== 0) {
|
|
9734
|
-
end++;
|
|
9735
|
-
}
|
|
9736
|
-
return buf.subarray(start, end).toString("utf8");
|
|
9737
|
-
}
|
|
9738
|
-
function stripTopDir(p) {
|
|
9739
|
-
const idx = p.indexOf("/");
|
|
9740
|
-
if (idx === -1) return "";
|
|
9741
|
-
return p.slice(idx + 1);
|
|
9742
|
-
}
|
|
9743
10138
|
|
|
9744
10139
|
// src/skills/manifest-store.ts
|
|
9745
10140
|
init_atomic_write();
|
|
9746
10141
|
import * as fs14 from "node:fs/promises";
|
|
9747
|
-
import * as
|
|
10142
|
+
import * as path24 from "node:path";
|
|
9748
10143
|
var SkillManifestStore = class {
|
|
9749
10144
|
manifestPath;
|
|
9750
10145
|
cache;
|
|
@@ -9767,7 +10162,7 @@ var SkillManifestStore = class {
|
|
|
9767
10162
|
return this.cache;
|
|
9768
10163
|
}
|
|
9769
10164
|
async write(data) {
|
|
9770
|
-
const dir =
|
|
10165
|
+
const dir = path24.dirname(this.manifestPath);
|
|
9771
10166
|
await fs14.mkdir(dir, { recursive: true });
|
|
9772
10167
|
await atomicWrite(this.manifestPath, JSON.stringify(data, null, 2) + "\n");
|
|
9773
10168
|
this.cache = data;
|
|
@@ -9805,6 +10200,10 @@ var SkillManifestStore = class {
|
|
|
9805
10200
|
};
|
|
9806
10201
|
|
|
9807
10202
|
// src/skills/skill-installer.ts
|
|
10203
|
+
function isInside(resolved, destDir) {
|
|
10204
|
+
const root = path25.resolve(destDir);
|
|
10205
|
+
return resolved === root || resolved.startsWith(root + path25.sep);
|
|
10206
|
+
}
|
|
9808
10207
|
var MAX_SKILL_FILE_SIZE = SKILL_LIMITS.MAX_SKILL_FILE_SIZE;
|
|
9809
10208
|
var SkillInstaller = class {
|
|
9810
10209
|
opts;
|
|
@@ -9858,14 +10257,14 @@ var SkillInstaller = class {
|
|
|
9858
10257
|
this.opts.log?.(`Overwriting existing skill "${skill.name}" (${scope})...`);
|
|
9859
10258
|
await this.removeSkillFiles(skill.name, scope);
|
|
9860
10259
|
}
|
|
9861
|
-
const destDir =
|
|
10260
|
+
const destDir = path25.join(targetDir, skill.name);
|
|
9862
10261
|
await fs15.mkdir(destDir, { recursive: true });
|
|
9863
10262
|
const copiedFiles = [];
|
|
9864
10263
|
for (const file of skill.files) {
|
|
9865
|
-
const srcPath =
|
|
9866
|
-
const destPath =
|
|
9867
|
-
const resolved2 =
|
|
9868
|
-
if (!resolved2
|
|
10264
|
+
const srcPath = path25.join(skill.baseDir, file);
|
|
10265
|
+
const destPath = path25.join(destDir, file);
|
|
10266
|
+
const resolved2 = path25.resolve(destPath);
|
|
10267
|
+
if (!isInside(resolved2, destDir)) {
|
|
9869
10268
|
throw new FsError({
|
|
9870
10269
|
message: `Path traversal detected in skill file: ${file}`,
|
|
9871
10270
|
code: ERROR_CODES.FS_DELETE_FAILED,
|
|
@@ -9873,16 +10272,16 @@ var SkillInstaller = class {
|
|
|
9873
10272
|
context: { reason: "path_traversal", skillName: skill.name }
|
|
9874
10273
|
});
|
|
9875
10274
|
}
|
|
9876
|
-
const
|
|
9877
|
-
if (
|
|
10275
|
+
const stat7 = await fs15.stat(srcPath);
|
|
10276
|
+
if (stat7.size > MAX_SKILL_FILE_SIZE) {
|
|
9878
10277
|
throw new FsError({
|
|
9879
|
-
message: `Skill file "${file}" is too large (${(
|
|
10278
|
+
message: `Skill file "${file}" is too large (${(stat7.size / 1024).toFixed(1)}KB). Max: ${MAX_SKILL_FILE_SIZE / 1024}KB`,
|
|
9880
10279
|
code: ERROR_CODES.FS_WRITE_FAILED,
|
|
9881
10280
|
path: srcPath,
|
|
9882
|
-
context: { skillName: skill.name, fileSize:
|
|
10281
|
+
context: { skillName: skill.name, fileSize: stat7.size, maxSize: MAX_SKILL_FILE_SIZE }
|
|
9883
10282
|
});
|
|
9884
10283
|
}
|
|
9885
|
-
await fs15.mkdir(
|
|
10284
|
+
await fs15.mkdir(path25.dirname(destPath), { recursive: true });
|
|
9886
10285
|
await fs15.copyFile(srcPath, destPath);
|
|
9887
10286
|
copiedFiles.push(file);
|
|
9888
10287
|
}
|
|
@@ -9940,7 +10339,7 @@ var SkillInstaller = class {
|
|
|
9940
10339
|
const results = [];
|
|
9941
10340
|
for (const e of entries) {
|
|
9942
10341
|
if (!await entryIsDirectory(srcDir, e)) continue;
|
|
9943
|
-
const skillMdPath =
|
|
10342
|
+
const skillMdPath = path25.join(srcDir, e.name, "SKILL.md");
|
|
9944
10343
|
let content;
|
|
9945
10344
|
try {
|
|
9946
10345
|
content = await fs15.readFile(skillMdPath, "utf8");
|
|
@@ -9953,16 +10352,16 @@ var SkillInstaller = class {
|
|
|
9953
10352
|
if (existing.find((x) => x.scope === scope)) {
|
|
9954
10353
|
await this.removeSkillFiles(fm.name, scope);
|
|
9955
10354
|
}
|
|
9956
|
-
const destDir =
|
|
10355
|
+
const destDir = path25.join(targetDir, fm.name);
|
|
9957
10356
|
await fs15.mkdir(destDir, { recursive: true });
|
|
9958
|
-
const srcSkillDir =
|
|
10357
|
+
const srcSkillDir = path25.join(srcDir, e.name);
|
|
9959
10358
|
const files = await collectFiles(srcSkillDir, srcSkillDir);
|
|
9960
10359
|
const copiedFiles = [];
|
|
9961
10360
|
for (const file of files) {
|
|
9962
|
-
const srcPath =
|
|
9963
|
-
const destPath =
|
|
9964
|
-
const resolved =
|
|
9965
|
-
if (!resolved
|
|
10361
|
+
const srcPath = path25.join(srcSkillDir, file);
|
|
10362
|
+
const destPath = path25.join(destDir, file);
|
|
10363
|
+
const resolved = path25.resolve(destPath);
|
|
10364
|
+
if (!isInside(resolved, destDir)) {
|
|
9966
10365
|
throw new FsError({
|
|
9967
10366
|
message: `Path traversal detected in skill file: ${file}`,
|
|
9968
10367
|
code: ERROR_CODES.FS_DELETE_FAILED,
|
|
@@ -9970,7 +10369,7 @@ var SkillInstaller = class {
|
|
|
9970
10369
|
context: { reason: "path_traversal", skillName: fm.name }
|
|
9971
10370
|
});
|
|
9972
10371
|
}
|
|
9973
|
-
await fs15.mkdir(
|
|
10372
|
+
await fs15.mkdir(path25.dirname(destPath), { recursive: true });
|
|
9974
10373
|
if (opts?.link) {
|
|
9975
10374
|
try {
|
|
9976
10375
|
await fs15.symlink(srcPath, destPath);
|
|
@@ -10133,7 +10532,7 @@ var SkillInstaller = class {
|
|
|
10133
10532
|
*/
|
|
10134
10533
|
async detectSkills(baseDir) {
|
|
10135
10534
|
const results = [];
|
|
10136
|
-
const rootSkillMd =
|
|
10535
|
+
const rootSkillMd = path25.join(baseDir, "SKILL.md");
|
|
10137
10536
|
try {
|
|
10138
10537
|
await fs15.access(rootSkillMd);
|
|
10139
10538
|
const content = await fs15.readFile(rootSkillMd, "utf8");
|
|
@@ -10148,17 +10547,17 @@ var SkillInstaller = class {
|
|
|
10148
10547
|
}
|
|
10149
10548
|
} catch {
|
|
10150
10549
|
}
|
|
10151
|
-
const skillsDir =
|
|
10550
|
+
const skillsDir = path25.join(baseDir, "skills");
|
|
10152
10551
|
try {
|
|
10153
10552
|
const entries = await fs15.readdir(skillsDir, { withFileTypes: true });
|
|
10154
10553
|
for (const entry of entries) {
|
|
10155
10554
|
if (!entry.isDirectory()) continue;
|
|
10156
|
-
const skillFile =
|
|
10555
|
+
const skillFile = path25.join(skillsDir, entry.name, "SKILL.md");
|
|
10157
10556
|
try {
|
|
10158
10557
|
const content = await fs15.readFile(skillFile, "utf8");
|
|
10159
10558
|
const fm = parseSkillFrontmatter(content);
|
|
10160
10559
|
if (fm.name && fm.description && isValidSkillNameFormat(fm.name)) {
|
|
10161
|
-
const skillDir =
|
|
10560
|
+
const skillDir = path25.join(skillsDir, entry.name);
|
|
10162
10561
|
const files = await collectFiles(skillDir, skillDir);
|
|
10163
10562
|
results.push({
|
|
10164
10563
|
name: fm.name,
|
|
@@ -10176,9 +10575,31 @@ var SkillInstaller = class {
|
|
|
10176
10575
|
/**
|
|
10177
10576
|
* Remove all files for an installed skill.
|
|
10178
10577
|
*/
|
|
10578
|
+
/**
|
|
10579
|
+
* Delete an installed skill's directory.
|
|
10580
|
+
*
|
|
10581
|
+
* The containment check is not ceremonial: this is a `recursive: true,
|
|
10582
|
+
* force: true` delete whose target is built from a skill NAME taken from
|
|
10583
|
+
* manifest frontmatter. `path.join` normalises `..`, so a crafted name
|
|
10584
|
+
* escapes `targetDir` and takes the recursive delete with it. This file
|
|
10585
|
+
* already had `isInside` and applied it on the copy path but not here.
|
|
10586
|
+
*
|
|
10587
|
+
* The strict-subdirectory requirement matters separately: `isInside` allows
|
|
10588
|
+
* equality by design, and an empty or `.` name resolves `skillDir` to
|
|
10589
|
+
* `targetDir` itself — deleting every installed skill (WS-097).
|
|
10590
|
+
*/
|
|
10179
10591
|
async removeSkillFiles(name, scope) {
|
|
10180
10592
|
const targetDir = scope === "project" ? this.opts.projectSkillsDir : this.opts.globalSkillsDir;
|
|
10181
|
-
const
|
|
10593
|
+
const root = path25.resolve(targetDir);
|
|
10594
|
+
const skillDir = path25.resolve(path25.join(targetDir, name));
|
|
10595
|
+
if (skillDir === root || !isInside(skillDir, root)) {
|
|
10596
|
+
throw new FsError({
|
|
10597
|
+
message: `Refusing to delete skill files outside the skills directory: ${name}`,
|
|
10598
|
+
code: ERROR_CODES.FS_DELETE_FAILED,
|
|
10599
|
+
path: skillDir,
|
|
10600
|
+
context: { reason: "path_traversal", skillName: name, scope }
|
|
10601
|
+
});
|
|
10602
|
+
}
|
|
10182
10603
|
await fs15.rm(skillDir, { recursive: true, force: true });
|
|
10183
10604
|
}
|
|
10184
10605
|
/**
|
|
@@ -10214,7 +10635,7 @@ async function entryIsDirectory(dir, entry) {
|
|
|
10214
10635
|
if (entry.isDirectory()) return true;
|
|
10215
10636
|
if (entry.isSymbolicLink()) {
|
|
10216
10637
|
try {
|
|
10217
|
-
return (await fs15.stat(
|
|
10638
|
+
return (await fs15.stat(path25.join(dir, entry.name))).isDirectory();
|
|
10218
10639
|
} catch {
|
|
10219
10640
|
return false;
|
|
10220
10641
|
}
|
|
@@ -10225,8 +10646,8 @@ async function collectFiles(dir, baseDir) {
|
|
|
10225
10646
|
const results = [];
|
|
10226
10647
|
const entries = await fs15.readdir(dir, { withFileTypes: true });
|
|
10227
10648
|
for (const entry of entries) {
|
|
10228
|
-
const fullPath =
|
|
10229
|
-
const relPath =
|
|
10649
|
+
const fullPath = path25.join(dir, entry.name);
|
|
10650
|
+
const relPath = path25.relative(baseDir, fullPath);
|
|
10230
10651
|
if (entry.isDirectory()) {
|
|
10231
10652
|
if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
|
|
10232
10653
|
results.push(...await collectFiles(fullPath, baseDir));
|
|
@@ -10305,7 +10726,7 @@ function createSkillsPlugin(opts) {
|
|
|
10305
10726
|
function makeInstaller(skillLoader, projectRoot, registryAdapters) {
|
|
10306
10727
|
const paths = resolveWstackPaths({ projectRoot });
|
|
10307
10728
|
return new SkillInstaller({
|
|
10308
|
-
manifestPath:
|
|
10729
|
+
manifestPath: path26.join(paths.configDir, "installed-skills.json"),
|
|
10309
10730
|
projectSkillsDir: paths.inProjectSkills,
|
|
10310
10731
|
globalSkillsDir: paths.globalSkills,
|
|
10311
10732
|
projectHash: paths.projectHash,
|
|
@@ -10333,7 +10754,8 @@ ${lines.join("\n\n")}
|
|
|
10333
10754
|
}
|
|
10334
10755
|
const skill = await skillLoader.find(args.trim());
|
|
10335
10756
|
if (!skill) return { message: `Skill "${args.trim()}" not found.` };
|
|
10336
|
-
|
|
10757
|
+
const body = capSkillBody(stripFrontmatter(await skillLoader.readBody(skill.name)));
|
|
10758
|
+
return { message: body };
|
|
10337
10759
|
}
|
|
10338
10760
|
};
|
|
10339
10761
|
}
|
|
@@ -10372,9 +10794,32 @@ function buildSkillGeneratorCommand(skillLoader) {
|
|
|
10372
10794
|
return ` ${src} ${e.name}
|
|
10373
10795
|
${e.trigger}`;
|
|
10374
10796
|
});
|
|
10375
|
-
|
|
10797
|
+
let message = `Available Skills:
|
|
10376
10798
|
${lines.join("\n\n")}
|
|
10377
|
-
|
|
10799
|
+
`;
|
|
10800
|
+
const diag = skillLoader.diagnostics?.();
|
|
10801
|
+
if (diag && (diag.shadowed.length > 0 || diag.skipped.length > 0)) {
|
|
10802
|
+
const notes = [];
|
|
10803
|
+
if (diag.shadowed.length > 0) {
|
|
10804
|
+
notes.push(color.dim("Shadowed (hidden by a higher-priority layer):"));
|
|
10805
|
+
for (const s of diag.shadowed) {
|
|
10806
|
+
notes.push(
|
|
10807
|
+
color.dim(` \u26A0 ${s.name} (${s.source}) \u2190 overridden by ${s.shadowedBy}`)
|
|
10808
|
+
);
|
|
10809
|
+
}
|
|
10810
|
+
}
|
|
10811
|
+
if (diag.skipped.length > 0) {
|
|
10812
|
+
notes.push(color.dim("Skipped (malformed SKILL.md):"));
|
|
10813
|
+
for (const k of diag.skipped) {
|
|
10814
|
+
const name = k.name ? ` "${k.name}"` : "";
|
|
10815
|
+
notes.push(color.dim(` \u2717 ${k.entry}${name} \u2014 ${k.reason}`));
|
|
10816
|
+
}
|
|
10817
|
+
}
|
|
10818
|
+
message += `
|
|
10819
|
+
${notes.join("\n")}
|
|
10820
|
+
`;
|
|
10821
|
+
}
|
|
10822
|
+
return { message };
|
|
10378
10823
|
}
|
|
10379
10824
|
if (sub === "validate") {
|
|
10380
10825
|
const name = rest[0];
|
|
@@ -10431,7 +10876,10 @@ ${lines.join("\n\n")}
|
|
|
10431
10876
|
if (!skill) return { message: `Skill "${skillName}" not found.` };
|
|
10432
10877
|
try {
|
|
10433
10878
|
await openInEditor(skill.path);
|
|
10434
|
-
|
|
10879
|
+
skillLoader.invalidateCache();
|
|
10880
|
+
return {
|
|
10881
|
+
message: `Opening ${skill.path} in your editor\u2026 (skill cache cleared \u2014 changes load on next use)`
|
|
10882
|
+
};
|
|
10435
10883
|
} catch (err) {
|
|
10436
10884
|
return { message: `\u2717 ${toErrorMessage(err)}` };
|
|
10437
10885
|
}
|
|
@@ -10657,7 +11105,7 @@ function resolveImportSourceDir(tool, opts) {
|
|
|
10657
11105
|
const entry = IMPORT_SOURCE_TOOLS.find((t) => t.id === tool);
|
|
10658
11106
|
if (!entry) return void 0;
|
|
10659
11107
|
const base = opts.global ? opts.homeDir ?? os7.homedir() : opts.projectRoot;
|
|
10660
|
-
return
|
|
11108
|
+
return path26.join(base, "." + entry.id, entry.subdir);
|
|
10661
11109
|
}
|
|
10662
11110
|
function buildSkillImportCommand(skillLoader) {
|
|
10663
11111
|
return {
|
|
@@ -10698,7 +11146,7 @@ function buildSkillImportCommand(skillLoader) {
|
|
|
10698
11146
|
};
|
|
10699
11147
|
}
|
|
10700
11148
|
} else if (positional) {
|
|
10701
|
-
srcDir =
|
|
11149
|
+
srcDir = path26.resolve(ctx.projectRoot, positional);
|
|
10702
11150
|
} else {
|
|
10703
11151
|
return {
|
|
10704
11152
|
message: "Usage: /skill-import <src-dir> | --from <tool> | --from-claude [--global] [--link]"
|
|
@@ -10825,14 +11273,14 @@ function truncate(s, max) {
|
|
|
10825
11273
|
}
|
|
10826
11274
|
|
|
10827
11275
|
// src/plugins/sync-plugin.ts
|
|
10828
|
-
import * as
|
|
11276
|
+
import * as path28 from "node:path";
|
|
10829
11277
|
init_error();
|
|
10830
11278
|
|
|
10831
11279
|
// src/storage/cloud-sync.ts
|
|
10832
11280
|
init_atomic_write();
|
|
10833
11281
|
init_errors();
|
|
10834
11282
|
import * as fs16 from "node:fs/promises";
|
|
10835
|
-
import * as
|
|
11283
|
+
import * as path27 from "node:path";
|
|
10836
11284
|
import { createHash as createHash9 } from "node:crypto";
|
|
10837
11285
|
var ALL_SYNC_CATEGORIES = ["settings", "skills", "prompts", "memory", "history"];
|
|
10838
11286
|
var CloudSync = class {
|
|
@@ -10840,8 +11288,8 @@ var CloudSync = class {
|
|
|
10840
11288
|
this.paths = paths;
|
|
10841
11289
|
this.getConfig = getConfig;
|
|
10842
11290
|
this.setConfig = setConfig;
|
|
10843
|
-
this.statePath =
|
|
10844
|
-
this.getSettingsConfigPath = getSettingsConfigPath ?? (() =>
|
|
11291
|
+
this.statePath = path27.join(paths.configDir, "sync-state.json");
|
|
11292
|
+
this.getSettingsConfigPath = getSettingsConfigPath ?? (() => path27.join(this.paths.configDir, "config.json"));
|
|
10845
11293
|
}
|
|
10846
11294
|
paths;
|
|
10847
11295
|
getConfig;
|
|
@@ -11121,13 +11569,13 @@ var CloudSync = class {
|
|
|
11121
11569
|
const localPath = this.categoryToPath(cat);
|
|
11122
11570
|
if (!localPath) continue;
|
|
11123
11571
|
try {
|
|
11124
|
-
const
|
|
11125
|
-
if (
|
|
11126
|
-
if (
|
|
11572
|
+
const stat7 = await fs16.lstat(localPath);
|
|
11573
|
+
if (stat7.isSymbolicLink()) continue;
|
|
11574
|
+
if (stat7.isDirectory()) {
|
|
11127
11575
|
const files = await this.walkDir(localPath, localPath);
|
|
11128
11576
|
for (const file of files) {
|
|
11129
11577
|
const content = await fs16.readFile(file, "utf8");
|
|
11130
|
-
const rel =
|
|
11578
|
+
const rel = path27.relative(localPath, file).replace(/\\/g, "/");
|
|
11131
11579
|
entries.push({ path: `data/${cat}/${rel}`, content, mode: "100644" });
|
|
11132
11580
|
hashes.push(`${cat}/${rel}\0${content}`);
|
|
11133
11581
|
}
|
|
@@ -11148,13 +11596,13 @@ var CloudSync = class {
|
|
|
11148
11596
|
const localPath = this.categoryToPath(cat);
|
|
11149
11597
|
if (!localPath) continue;
|
|
11150
11598
|
try {
|
|
11151
|
-
const
|
|
11152
|
-
if (
|
|
11153
|
-
if (
|
|
11599
|
+
const stat7 = await fs16.lstat(localPath);
|
|
11600
|
+
if (stat7.isSymbolicLink()) continue;
|
|
11601
|
+
if (stat7.isDirectory()) {
|
|
11154
11602
|
const files = await this.walkDir(localPath, localPath);
|
|
11155
11603
|
for (const file of files) {
|
|
11156
11604
|
const content = await fs16.readFile(file, "utf8");
|
|
11157
|
-
const rel =
|
|
11605
|
+
const rel = path27.relative(localPath, file).replace(/\\/g, "/");
|
|
11158
11606
|
hashes.push(`${cat}/${rel}\0${content}`);
|
|
11159
11607
|
}
|
|
11160
11608
|
} else {
|
|
@@ -11188,7 +11636,7 @@ var CloudSync = class {
|
|
|
11188
11636
|
const entries = await fs16.readdir(dir, { withFileTypes: true });
|
|
11189
11637
|
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
11190
11638
|
for (const entry of entries) {
|
|
11191
|
-
const full =
|
|
11639
|
+
const full = path27.join(dir, entry.name);
|
|
11192
11640
|
if (entry.isSymbolicLink()) continue;
|
|
11193
11641
|
if (entry.isDirectory()) {
|
|
11194
11642
|
results.push(...await this.walkDir(full, base));
|
|
@@ -11201,25 +11649,25 @@ var CloudSync = class {
|
|
|
11201
11649
|
};
|
|
11202
11650
|
async function preparePulledDestination(cat, localPath, destPath, remotePath) {
|
|
11203
11651
|
const directoryBacked = cat === "skills" || cat === "prompts";
|
|
11204
|
-
const rootPath = directoryBacked ? localPath :
|
|
11652
|
+
const rootPath = directoryBacked ? localPath : path27.dirname(localPath);
|
|
11205
11653
|
const rootStat = await lstatIfExists(rootPath);
|
|
11206
11654
|
if (rootStat?.isSymbolicLink()) {
|
|
11207
11655
|
throw unsafePulledSymlinkError(remotePath, rootPath);
|
|
11208
11656
|
}
|
|
11209
11657
|
if (directoryBacked) {
|
|
11210
|
-
const relativeParent =
|
|
11658
|
+
const relativeParent = path27.relative(rootPath, path27.dirname(destPath));
|
|
11211
11659
|
let cursor = rootPath;
|
|
11212
11660
|
if (relativeParent) {
|
|
11213
|
-
for (const segment of relativeParent.split(
|
|
11214
|
-
cursor =
|
|
11215
|
-
const
|
|
11216
|
-
if (
|
|
11661
|
+
for (const segment of relativeParent.split(path27.sep)) {
|
|
11662
|
+
cursor = path27.join(cursor, segment);
|
|
11663
|
+
const stat7 = await lstatIfExists(cursor);
|
|
11664
|
+
if (stat7?.isSymbolicLink()) throw unsafePulledSymlinkError(remotePath, cursor);
|
|
11217
11665
|
}
|
|
11218
11666
|
}
|
|
11219
11667
|
}
|
|
11220
11668
|
const destStat = await lstatIfExists(destPath);
|
|
11221
11669
|
if (destStat?.isSymbolicLink()) throw unsafePulledSymlinkError(remotePath, destPath);
|
|
11222
|
-
await fs16.mkdir(
|
|
11670
|
+
await fs16.mkdir(path27.dirname(destPath), { recursive: true });
|
|
11223
11671
|
}
|
|
11224
11672
|
async function lstatIfExists(filePath) {
|
|
11225
11673
|
try {
|
|
@@ -11249,9 +11697,9 @@ function resolvePulledCategoryPath(cat, localPath, rel, remotePath) {
|
|
|
11249
11697
|
return localPath;
|
|
11250
11698
|
}
|
|
11251
11699
|
if (!rel) return localPath;
|
|
11252
|
-
const normalizedRel =
|
|
11253
|
-
const traversesUp = normalizedRel === ".." || normalizedRel.startsWith(`..${
|
|
11254
|
-
if (
|
|
11700
|
+
const normalizedRel = path27.normalize(rel);
|
|
11701
|
+
const traversesUp = normalizedRel === ".." || normalizedRel.startsWith(`..${path27.sep}`);
|
|
11702
|
+
if (path27.isAbsolute(normalizedRel) || traversesUp) {
|
|
11255
11703
|
throw new FsError({
|
|
11256
11704
|
message: `Refusing CloudSync path traversal: ${remotePath}`,
|
|
11257
11705
|
code: ERROR_CODES.FS_DELETE_FAILED,
|
|
@@ -11259,10 +11707,10 @@ function resolvePulledCategoryPath(cat, localPath, rel, remotePath) {
|
|
|
11259
11707
|
context: { reason: "path_traversal", normalizedRel }
|
|
11260
11708
|
});
|
|
11261
11709
|
}
|
|
11262
|
-
const dest =
|
|
11263
|
-
const root =
|
|
11264
|
-
const relative5 =
|
|
11265
|
-
if (relative5.startsWith("..") ||
|
|
11710
|
+
const dest = path27.resolve(localPath, normalizedRel);
|
|
11711
|
+
const root = path27.resolve(localPath);
|
|
11712
|
+
const relative5 = path27.relative(root, dest);
|
|
11713
|
+
if (relative5.startsWith("..") || path27.isAbsolute(relative5)) {
|
|
11266
11714
|
throw new FsError({
|
|
11267
11715
|
message: `Refusing CloudSync path outside category root: ${remotePath}`,
|
|
11268
11716
|
code: ERROR_CODES.FS_DELETE_FAILED,
|
|
@@ -11305,7 +11753,7 @@ function createSyncPlugin(opts) {
|
|
|
11305
11753
|
api.log.warn("[sync] paths, configStore, or configDir not available \u2014 /sync disabled");
|
|
11306
11754
|
return;
|
|
11307
11755
|
}
|
|
11308
|
-
const syncConfigPath = paths.syncConfig ??
|
|
11756
|
+
const syncConfigPath = paths.syncConfig ?? path28.join(paths.configDir, "sync.json");
|
|
11309
11757
|
cloud = new CloudSync(
|
|
11310
11758
|
paths,
|
|
11311
11759
|
() => {
|
|
@@ -11316,7 +11764,7 @@ function createSyncPlugin(opts) {
|
|
|
11316
11764
|
await persistSyncConfig(syncConfigPath, cfg, vault);
|
|
11317
11765
|
configStore?.update({ sync: cfg });
|
|
11318
11766
|
},
|
|
11319
|
-
() =>
|
|
11767
|
+
() => path28.join(paths.configDir, "config.json")
|
|
11320
11768
|
);
|
|
11321
11769
|
void cloud.loadState();
|
|
11322
11770
|
api.slashCommands.register(buildSyncCommand(cloud, configStore, vault, syncConfigPath));
|
|
@@ -11519,8 +11967,14 @@ export {
|
|
|
11519
11967
|
definePlugin,
|
|
11520
11968
|
diffPluginConfig,
|
|
11521
11969
|
emitReviewIfChanged,
|
|
11970
|
+
integrateFindings,
|
|
11522
11971
|
loadPlugins,
|
|
11972
|
+
maybeCompactReviewStores,
|
|
11973
|
+
parseChimeraReviewReport,
|
|
11523
11974
|
parseReviewSeverity,
|
|
11975
|
+
persistReviewReport,
|
|
11976
|
+
recordCompletedReview,
|
|
11977
|
+
recordStartedReview,
|
|
11524
11978
|
redactPluginConfig,
|
|
11525
11979
|
resolvePluginConfig,
|
|
11526
11980
|
resolvePluginManifestConfig,
|