@wrongstack/core 0.297.0 → 0.298.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chronicle/index.js +126 -22
- package/dist/chronicle/project-server-client.d.ts +12 -0
- package/dist/chronicle/project-server-protocol.d.ts +22 -0
- package/dist/chronicle/project-server.js +238 -157
- package/dist/coordination/agents/index.js +136 -1
- package/dist/coordination/agents/role-skills.d.ts +3 -2
- package/dist/coordination/brain-trace.d.ts +2 -1
- package/dist/coordination/director/director-task-registry.d.ts +12 -0
- package/dist/coordination/fleet-supervisor.d.ts +21 -0
- package/dist/coordination/index.d.ts +23 -21
- package/dist/coordination/index.js +16493 -16068
- package/dist/coordination/mail-tools.d.ts +3 -3
- package/dist/coordination/mailbox-credential-store.d.ts +22 -2
- package/dist/coordination/mailbox-credential-throttle.d.ts +63 -0
- package/dist/coordination/mailbox-project-server-client.d.ts +16 -0
- package/dist/coordination/mailbox-project-server-protocol.d.ts +43 -5
- package/dist/coordination/mailbox-project-server.js +508 -253
- package/dist/coordination/provider-status-tracker.d.ts +2 -0
- package/dist/coordination/remote-mailbox-credential-store.d.ts +5 -5
- package/dist/coordination/remote-mailbox.d.ts +8 -4
- package/dist/coordination/sqlite-mailbox-credentials.d.ts +11 -0
- package/dist/core/fallback-profile-manager.d.ts +14 -0
- package/dist/core/index.js +451 -137
- package/dist/core/instruction-bundle.d.ts +12 -0
- package/dist/core/system-prompt-builder.d.ts +14 -0
- package/dist/core/system-prompt-skill-bodies.d.ts +1 -1
- package/dist/core/system-prompt-skill-text.d.ts +1 -2
- package/dist/defaults/index.js +2081 -1102
- package/dist/design/index.js +47 -8
- package/dist/execution/design-materialize.d.ts +22 -0
- package/dist/execution/index.js +495 -248
- package/dist/execution/skill-loader.d.ts +10 -1
- package/dist/execution/tool-error-taxonomy.d.ts +31 -0
- package/dist/execution/tool-executor.d.ts +1 -0
- package/dist/goal/index.js +3 -1
- package/dist/hooks/index.js +5 -0
- package/dist/hq/auth-audit.d.ts +6 -0
- package/dist/hq/auth-store.d.ts +59 -3
- package/dist/hq/index.js +401 -101
- package/dist/hq/kanban-store.d.ts +3 -0
- package/dist/hq/protocol/core.d.ts +3 -15
- package/dist/hq/protocol/envelope.d.ts +29 -0
- package/dist/hq/protocol/governance.d.ts +34 -0
- package/dist/hq/protocol/project.d.ts +3 -0
- package/dist/hq/protocol/resume.d.ts +1 -1
- package/dist/hq/protocol.d.ts +9 -8
- package/dist/hq/protocol.js +675 -0
- package/dist/index.js +8518 -6416
- package/dist/infrastructure/index.js +198 -101
- package/dist/kernel/events/session-events.d.ts +3 -0
- package/dist/kernel/events/tool-events.d.ts +3 -1
- package/dist/models/index.js +1 -1
- package/dist/observability/index.js +27 -0
- package/dist/observability/prometheus.d.ts +11 -0
- package/dist/plugin/index.d.ts +5 -1
- package/dist/plugin/index.js +950 -509
- package/dist/plugins/review-store-maintenance.d.ts +26 -0
- package/dist/plugins/review-types.d.ts +6 -0
- package/dist/security/capabilities.d.ts +45 -1
- package/dist/security/error-sanitize.d.ts +49 -0
- package/dist/security/file-permissions.d.ts +41 -0
- package/dist/security/index.d.ts +9 -6
- package/dist/security/index.js +3007 -2032
- package/dist/security/permission-policy.d.ts +55 -3
- package/dist/security/secret-vault.d.ts +17 -0
- package/dist/security/totp.d.ts +86 -0
- package/dist/skills/frontmatter.d.ts +12 -1
- package/dist/skills/github-fetcher.d.ts +48 -0
- package/dist/skills/index.js +137 -26
- package/dist/skills/limits.d.ts +19 -0
- package/dist/skills/skill-installer.d.ts +13 -0
- package/dist/storage/index.js +928 -732
- package/dist/storage/provider-config-watcher.d.ts +1 -0
- package/dist/storage/session-helpers.d.ts +1 -0
- package/dist/storage/session-store.d.ts +9 -2
- package/dist/storage/session-workspace-checkpoints.d.ts +5 -0
- package/dist/tools/fallback-manage-tools.d.ts +6 -0
- package/dist/tools/index.js +287 -131
- package/dist/tools/mcp-use.d.ts +1 -1
- package/dist/types/blocks.d.ts +7 -0
- package/dist/types/config/autonomy.d.ts +12 -3
- package/dist/types/config/mcp-features.d.ts +9 -1
- package/dist/types/config/root.d.ts +10 -4
- package/dist/types/context-window.d.ts +15 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/secret-vault.d.ts +8 -0
- package/dist/types/session.d.ts +2 -0
- package/dist/types/skill.d.ts +56 -0
- package/dist/types/tool-executor.d.ts +2 -0
- package/dist/utils/env-typed.d.ts +64 -0
- package/dist/utils/glob-match.d.ts +21 -1
- package/dist/utils/heap-watchdog.js +1 -1
- package/dist/utils/incoming-images.d.ts +19 -0
- package/dist/utils/index.d.ts +15 -12
- package/dist/utils/index.js +3083 -2801
- package/dist/utils/path-segment.d.ts +29 -0
- package/dist/utils/win32-cmd.d.ts +25 -0
- package/dist/worktree/index.js +5 -0
- package/package.json +8 -3
- package/skills/chimera/SKILL.md +16 -4
- package/skills/data-governance/SKILL.md +92 -0
- package/skills/wrongstack-kanban/SKILL.md +125 -64
- package/dist/agent-status-helpers.d.ts.map +0 -1
- package/dist/agent-status-tracker.d.ts.map +0 -1
- package/dist/boot.d.ts.map +0 -1
- package/dist/chronicle/context.d.ts.map +0 -1
- package/dist/chronicle/decision-adapter.d.ts.map +0 -1
- package/dist/chronicle/domain-adapter.d.ts.map +0 -1
- package/dist/chronicle/event-hash.d.ts.map +0 -1
- package/dist/chronicle/file-observer.d.ts.map +0 -1
- package/dist/chronicle/health-monitor.d.ts.map +0 -1
- package/dist/chronicle/identity.d.ts.map +0 -1
- package/dist/chronicle/index.d.ts.map +0 -1
- package/dist/chronicle/index.js.map +0 -7
- package/dist/chronicle/journal.d.ts.map +0 -1
- package/dist/chronicle/legacy-journal-import.d.ts.map +0 -1
- package/dist/chronicle/metrics-store.d.ts.map +0 -1
- package/dist/chronicle/partition-filename.d.ts.map +0 -1
- package/dist/chronicle/partition-range-cache.d.ts.map +0 -1
- package/dist/chronicle/process-adapter.d.ts.map +0 -1
- package/dist/chronicle/project-access.d.ts.map +0 -1
- package/dist/chronicle/project-server-client.d.ts.map +0 -1
- package/dist/chronicle/project-server-endpoint.d.ts.map +0 -1
- package/dist/chronicle/project-server-protocol.d.ts.map +0 -1
- package/dist/chronicle/project-server.d.ts.map +0 -1
- package/dist/chronicle/project-server.js.map +0 -7
- package/dist/chronicle/prompt-manifest.d.ts.map +0 -1
- package/dist/chronicle/provider-adapter.d.ts.map +0 -1
- package/dist/chronicle/query.d.ts.map +0 -1
- package/dist/chronicle/review-adapter.d.ts.map +0 -1
- package/dist/chronicle/rollup-adapter.d.ts.map +0 -1
- package/dist/chronicle/sink.d.ts.map +0 -1
- package/dist/chronicle/sqlite-journal.d.ts.map +0 -1
- package/dist/chronicle/sqlite-query.d.ts.map +0 -1
- package/dist/chronicle/stream-adapter.d.ts.map +0 -1
- package/dist/chronicle/tool-adapter.d.ts.map +0 -1
- package/dist/chronicle/types.d.ts.map +0 -1
- package/dist/coordination/adaptive-concurrency.d.ts.map +0 -1
- package/dist/coordination/agent-bridge.d.ts.map +0 -1
- package/dist/coordination/agent-monitor.d.ts.map +0 -1
- package/dist/coordination/agent-subagent-runner.d.ts.map +0 -1
- package/dist/coordination/agents/agent-prompts.d.ts.map +0 -1
- package/dist/coordination/agents/index.d.ts.map +0 -1
- package/dist/coordination/agents/index.js.map +0 -7
- package/dist/coordination/agents/phase1-discovery.d.ts.map +0 -1
- package/dist/coordination/agents/phase2-planning.d.ts.map +0 -1
- package/dist/coordination/agents/phase3-build.d.ts.map +0 -1
- package/dist/coordination/agents/phase3-techstack.d.ts.map +0 -1
- package/dist/coordination/agents/phase3-wave1-platform.d.ts.map +0 -1
- package/dist/coordination/agents/phase3-wave2-meta.d.ts.map +0 -1
- package/dist/coordination/agents/phase4-verify.d.ts.map +0 -1
- package/dist/coordination/agents/phase5-review.d.ts.map +0 -1
- package/dist/coordination/agents/phase6-domain.d.ts.map +0 -1
- package/dist/coordination/agents/phase7-knowledge.d.ts.map +0 -1
- package/dist/coordination/agents/phase8-delivery.d.ts.map +0 -1
- package/dist/coordination/agents/phase8-wave3-products.d.ts.map +0 -1
- package/dist/coordination/agents/phase9-meta.d.ts.map +0 -1
- package/dist/coordination/agents/phase9-wave4-platform-meta.d.ts.map +0 -1
- package/dist/coordination/agents/project-agent-config-validation.d.ts.map +0 -1
- package/dist/coordination/agents/project-agent-consolidation.d.ts.map +0 -1
- package/dist/coordination/agents/project-agent-files.d.ts.map +0 -1
- package/dist/coordination/agents/project-agent-identity-types.d.ts.map +0 -1
- package/dist/coordination/agents/project-agent-identity.d.ts.map +0 -1
- package/dist/coordination/agents/project-agent-knowledge-manifests.d.ts.map +0 -1
- package/dist/coordination/agents/project-agent-learning-entries.d.ts.map +0 -1
- package/dist/coordination/agents/project-agent-learning-normalize.d.ts.map +0 -1
- package/dist/coordination/agents/project-agent-learning-policy.d.ts.map +0 -1
- package/dist/coordination/agents/project-agent-learning-structured.d.ts.map +0 -1
- package/dist/coordination/agents/project-agent-paths.d.ts.map +0 -1
- package/dist/coordination/agents/project-agent-profile.d.ts.map +0 -1
- package/dist/coordination/agents/role-skills.d.ts.map +0 -1
- package/dist/coordination/agents/types.d.ts.map +0 -1
- package/dist/coordination/agents.d.ts.map +0 -1
- package/dist/coordination/auto-extend.d.ts.map +0 -1
- package/dist/coordination/autonomous-brain.d.ts.map +0 -1
- package/dist/coordination/autonomous-coordinator.d.ts.map +0 -1
- package/dist/coordination/brain-cache.d.ts.map +0 -1
- package/dist/coordination/brain-heuristics.d.ts.map +0 -1
- package/dist/coordination/brain-ledger.d.ts.map +0 -1
- package/dist/coordination/brain-monitor.d.ts.map +0 -1
- package/dist/coordination/brain-rules.d.ts.map +0 -1
- package/dist/coordination/brain-telemetry.d.ts.map +0 -1
- package/dist/coordination/brain-trace.d.ts.map +0 -1
- package/dist/coordination/brain.d.ts.map +0 -1
- package/dist/coordination/change-manager.d.ts.map +0 -1
- package/dist/coordination/checkpoint-wiring.d.ts.map +0 -1
- package/dist/coordination/collab-bus.d.ts.map +0 -1
- package/dist/coordination/collab-debug-types.d.ts.map +0 -1
- package/dist/coordination/collab-debug.d.ts.map +0 -1
- package/dist/coordination/collab-director-host.d.ts.map +0 -1
- package/dist/coordination/commit-safety.d.ts.map +0 -1
- package/dist/coordination/consensus-protocol.d.ts.map +0 -1
- package/dist/coordination/coordinator/error-classifier.d.ts.map +0 -1
- package/dist/coordination/delegate-tool.d.ts.map +0 -1
- package/dist/coordination/dep-watcher-bridge.d.ts.map +0 -1
- package/dist/coordination/dep-watcher.d.ts.map +0 -1
- package/dist/coordination/director/director-btw-notes.d.ts.map +0 -1
- package/dist/coordination/director/director-budget-policy.d.ts.map +0 -1
- package/dist/coordination/director/director-collab.d.ts.map +0 -1
- package/dist/coordination/director/director-errors.d.ts.map +0 -1
- package/dist/coordination/director/director-task-registry.d.ts.map +0 -1
- package/dist/coordination/director/director-toolset.d.ts.map +0 -1
- package/dist/coordination/director-basic-tools.d.ts.map +0 -1
- package/dist/coordination/director-collab-tools.d.ts.map +0 -1
- package/dist/coordination/director-host-contracts.d.ts.map +0 -1
- package/dist/coordination/director-input-helpers.d.ts.map +0 -1
- package/dist/coordination/director-kanban-queue-helpers.d.ts.map +0 -1
- package/dist/coordination/director-options.d.ts.map +0 -1
- package/dist/coordination/director-prompts.d.ts.map +0 -1
- package/dist/coordination/director-quality-gate-tool.d.ts.map +0 -1
- package/dist/coordination/director-session.d.ts.map +0 -1
- package/dist/coordination/director-spawn-model.d.ts.map +0 -1
- package/dist/coordination/director-tools.d.ts.map +0 -1
- package/dist/coordination/director.d.ts.map +0 -1
- package/dist/coordination/dispatcher.d.ts.map +0 -1
- package/dist/coordination/file-author-tracker.d.ts.map +0 -1
- package/dist/coordination/fleet-bus.d.ts.map +0 -1
- package/dist/coordination/fleet-event-validation.d.ts.map +0 -1
- package/dist/coordination/fleet-manager.d.ts.map +0 -1
- package/dist/coordination/fleet-spawn.d.ts.map +0 -1
- package/dist/coordination/fleet-status-tool.d.ts.map +0 -1
- package/dist/coordination/fleet-supervisor.d.ts.map +0 -1
- package/dist/coordination/fleet.d.ts.map +0 -1
- package/dist/coordination/global-mailbox-completion.d.ts.map +0 -1
- package/dist/coordination/global-mailbox-paths.d.ts.map +0 -1
- package/dist/coordination/icoordinator.d.ts.map +0 -1
- package/dist/coordination/ifleet-manager.d.ts.map +0 -1
- package/dist/coordination/in-memory-transport.d.ts.map +0 -1
- package/dist/coordination/index.d.ts.map +0 -1
- package/dist/coordination/index.js.map +0 -7
- package/dist/coordination/knowledge-graph.d.ts.map +0 -1
- package/dist/coordination/large-answer-store.d.ts.map +0 -1
- package/dist/coordination/mail-tools.d.ts.map +0 -1
- package/dist/coordination/mailbox-actions.d.ts.map +0 -1
- package/dist/coordination/mailbox-auth-types.d.ts.map +0 -1
- package/dist/coordination/mailbox-codecs.d.ts.map +0 -1
- package/dist/coordination/mailbox-constants.d.ts.map +0 -1
- package/dist/coordination/mailbox-credential-store.d.ts.map +0 -1
- package/dist/coordination/mailbox-events.d.ts.map +0 -1
- package/dist/coordination/mailbox-health.d.ts.map +0 -1
- package/dist/coordination/mailbox-hooks.d.ts.map +0 -1
- package/dist/coordination/mailbox-http-auth.d.ts.map +0 -1
- package/dist/coordination/mailbox-http-rate-limit.d.ts.map +0 -1
- package/dist/coordination/mailbox-http-router.d.ts.map +0 -1
- package/dist/coordination/mailbox-http-validation.d.ts.map +0 -1
- package/dist/coordination/mailbox-message-codec.d.ts.map +0 -1
- package/dist/coordination/mailbox-parse-state.d.ts.map +0 -1
- package/dist/coordination/mailbox-project-server-client.d.ts.map +0 -1
- package/dist/coordination/mailbox-project-server-endpoint.d.ts.map +0 -1
- package/dist/coordination/mailbox-project-server-protocol.d.ts.map +0 -1
- package/dist/coordination/mailbox-project-server.d.ts.map +0 -1
- package/dist/coordination/mailbox-project-server.js.map +0 -7
- package/dist/coordination/mailbox-receipt-folding.d.ts.map +0 -1
- package/dist/coordination/mailbox-registry-codec.d.ts.map +0 -1
- package/dist/coordination/mailbox-retention-state.d.ts.map +0 -1
- package/dist/coordination/mailbox-status-mappers.d.ts.map +0 -1
- package/dist/coordination/mailbox-tool.d.ts.map +0 -1
- package/dist/coordination/mailbox-type-properties.d.ts.map +0 -1
- package/dist/coordination/mailbox-types.d.ts.map +0 -1
- package/dist/coordination/model-matrix.d.ts.map +0 -1
- package/dist/coordination/multi-agent-coordinator.d.ts.map +0 -1
- package/dist/coordination/multi-agent-timeout.d.ts.map +0 -1
- package/dist/coordination/null-fleet-bus.d.ts.map +0 -1
- package/dist/coordination/package-author-tracker.d.ts.map +0 -1
- package/dist/coordination/package-outdated-watcher.d.ts.map +0 -1
- package/dist/coordination/provider-status-tracker.d.ts.map +0 -1
- package/dist/coordination/remote-mailbox-credential-store.d.ts.map +0 -1
- package/dist/coordination/remote-mailbox.d.ts.map +0 -1
- package/dist/coordination/single-instance-mailbox.d.ts.map +0 -1
- package/dist/coordination/spawn-budget.d.ts.map +0 -1
- package/dist/coordination/sqlite-mailbox-compaction.d.ts.map +0 -1
- package/dist/coordination/sqlite-mailbox-credentials.d.ts.map +0 -1
- package/dist/coordination/sqlite-mailbox-rows.d.ts.map +0 -1
- package/dist/coordination/sqlite-mailbox-schema.d.ts.map +0 -1
- package/dist/coordination/sqlite-mailbox.d.ts.map +0 -1
- package/dist/coordination/subagent-budget.d.ts.map +0 -1
- package/dist/coordination/subagent-nicknames.d.ts.map +0 -1
- package/dist/coordination/subagent-result-tool.d.ts.map +0 -1
- package/dist/coordination/task-auctioneer.d.ts.map +0 -1
- package/dist/coordination/task-dag.d.ts.map +0 -1
- package/dist/coordination/techstack-mailbox-consumer.d.ts.map +0 -1
- package/dist/coordination/transport.d.ts.map +0 -1
- package/dist/coordination/worktree-task-runner.d.ts.map +0 -1
- package/dist/core/agent-internals.d.ts.map +0 -1
- package/dist/core/agent-loop.d.ts.map +0 -1
- package/dist/core/agent-response.d.ts.map +0 -1
- package/dist/core/agent-tools.d.ts.map +0 -1
- package/dist/core/agent-types.d.ts.map +0 -1
- package/dist/core/agent.d.ts.map +0 -1
- package/dist/core/btw.d.ts.map +0 -1
- package/dist/core/context.d.ts.map +0 -1
- package/dist/core/continue-intent.d.ts.map +0 -1
- package/dist/core/continue-to-next-iteration.d.ts.map +0 -1
- package/dist/core/conversation-state.d.ts.map +0 -1
- package/dist/core/fallback-model.d.ts.map +0 -1
- package/dist/core/fallback-profile-manager.d.ts.map +0 -1
- package/dist/core/fleet-pulse.d.ts.map +0 -1
- package/dist/core/index.d.ts.map +0 -1
- package/dist/core/index.js.map +0 -7
- package/dist/core/input-builder.d.ts.map +0 -1
- package/dist/core/instruction-bundle.d.ts.map +0 -1
- package/dist/core/iteration-limit.d.ts.map +0 -1
- package/dist/core/mailbox-loop.d.ts.map +0 -1
- package/dist/core/model-availability-calendar.d.ts.map +0 -1
- package/dist/core/model-ref.d.ts.map +0 -1
- package/dist/core/model-ref.js.map +0 -7
- package/dist/core/modes/brief.d.ts.map +0 -1
- package/dist/core/modes/default.d.ts.map +0 -1
- package/dist/core/modes/teach.d.ts.map +0 -1
- package/dist/core/provider-runner.d.ts.map +0 -1
- package/dist/core/queued-messages.d.ts.map +0 -1
- package/dist/core/request-provider-binding.d.ts.map +0 -1
- package/dist/core/run-env.d.ts.map +0 -1
- package/dist/core/streaming-response-builder.d.ts.map +0 -1
- package/dist/core/system-prompt-blocks.d.ts.map +0 -1
- package/dist/core/system-prompt-builder.d.ts.map +0 -1
- package/dist/core/system-prompt-environment-probes.d.ts.map +0 -1
- package/dist/core/system-prompt-environment.d.ts.map +0 -1
- package/dist/core/system-prompt-memory-skills.d.ts.map +0 -1
- package/dist/core/system-prompt-plan.d.ts.map +0 -1
- package/dist/core/system-prompt-shell.d.ts.map +0 -1
- package/dist/core/system-prompt-skill-bodies.d.ts.map +0 -1
- package/dist/core/system-prompt-skill-text.d.ts.map +0 -1
- package/dist/defaults/index.d.ts.map +0 -1
- package/dist/defaults/index.js.map +0 -7
- package/dist/design/index.d.ts.map +0 -1
- package/dist/design/index.js.map +0 -7
- package/dist/execution/auto-compaction-middleware.d.ts.map +0 -1
- package/dist/execution/autonomous-runner.d.ts.map +0 -1
- package/dist/execution/autonomy-brain.d.ts.map +0 -1
- package/dist/execution/autonomy-prompt-contributor.d.ts.map +0 -1
- package/dist/execution/brain-chain.d.ts.map +0 -1
- package/dist/execution/brain-circuit.d.ts.map +0 -1
- package/dist/execution/brain-evaluation.d.ts.map +0 -1
- package/dist/execution/brain-runtime-constants.d.ts.map +0 -1
- package/dist/execution/brain-runtime.d.ts.map +0 -1
- package/dist/execution/compaction-core.d.ts.map +0 -1
- package/dist/execution/compaction-scoring.d.ts.map +0 -1
- package/dist/execution/compaction-summary-cache.d.ts.map +0 -1
- package/dist/execution/compactor.d.ts.map +0 -1
- package/dist/execution/council-brain.d.ts.map +0 -1
- package/dist/execution/council-orchestrator.d.ts.map +0 -1
- package/dist/execution/council-personas.d.ts.map +0 -1
- package/dist/execution/council-profiles.d.ts.map +0 -1
- package/dist/execution/council-prompts.d.ts.map +0 -1
- package/dist/execution/council-resolution.d.ts.map +0 -1
- package/dist/execution/design-color.d.ts.map +0 -1
- package/dist/execution/design-detect.d.ts.map +0 -1
- package/dist/execution/design-kit-loader.d.ts.map +0 -1
- package/dist/execution/design-materialize.d.ts.map +0 -1
- package/dist/execution/design-project-store.d.ts.map +0 -1
- package/dist/execution/design-tune.d.ts.map +0 -1
- package/dist/execution/design-verify.d.ts.map +0 -1
- package/dist/execution/enhance-recovery.d.ts.map +0 -1
- package/dist/execution/error-handler.d.ts.map +0 -1
- package/dist/execution/eternal-autonomy-types.d.ts.map +0 -1
- package/dist/execution/eternal-autonomy.d.ts.map +0 -1
- package/dist/execution/goal-preamble.d.ts.map +0 -1
- package/dist/execution/index.d.ts.map +0 -1
- package/dist/execution/index.js.map +0 -7
- package/dist/execution/intelligent-compactor.d.ts.map +0 -1
- package/dist/execution/model-runtime.d.ts.map +0 -1
- package/dist/execution/one-shot-llm.d.ts.map +0 -1
- package/dist/execution/parallel-eternal-engine.d.ts.map +0 -1
- package/dist/execution/prompt-enhancer.d.ts.map +0 -1
- package/dist/execution/prompt-enhancer.js.map +0 -7
- package/dist/execution/prompt-loader.d.ts.map +0 -1
- package/dist/execution/provider-runner-impl.d.ts.map +0 -1
- package/dist/execution/regex-patterns.d.ts.map +0 -1
- package/dist/execution/retry-policy.d.ts.map +0 -1
- package/dist/execution/selective-compactor.d.ts.map +0 -1
- package/dist/execution/skill-loader.d.ts.map +0 -1
- package/dist/execution/strategy-compactor.d.ts.map +0 -1
- package/dist/execution/subagent-compaction.d.ts.map +0 -1
- package/dist/execution/tool-executor-logging.d.ts.map +0 -1
- package/dist/execution/tool-executor-results.d.ts.map +0 -1
- package/dist/execution/tool-executor-stream.d.ts.map +0 -1
- package/dist/execution/tool-executor-support.d.ts.map +0 -1
- package/dist/execution/tool-executor.d.ts.map +0 -1
- package/dist/extension/extension-points.d.ts.map +0 -1
- package/dist/extension/index.d.ts.map +0 -1
- package/dist/extension/index.js.map +0 -7
- package/dist/extension/registry.d.ts.map +0 -1
- package/dist/fleet-notifier.d.ts.map +0 -1
- package/dist/goal/checkpoint.d.ts.map +0 -1
- package/dist/goal/goal-assessor.d.ts.map +0 -1
- package/dist/goal/goal-planner.d.ts.map +0 -1
- package/dist/goal/goal-runner.d.ts.map +0 -1
- package/dist/goal/index.d.ts.map +0 -1
- package/dist/goal/index.js.map +0 -7
- package/dist/goal/phase-board-mutations.d.ts.map +0 -1
- package/dist/goal/phase-graph-builder.d.ts.map +0 -1
- package/dist/goal/phase-orchestrator-integration.d.ts.map +0 -1
- package/dist/goal/phase-orchestrator-queries.d.ts.map +0 -1
- package/dist/goal/phase-orchestrator-runtime.d.ts.map +0 -1
- package/dist/goal/phase-orchestrator-types.d.ts.map +0 -1
- package/dist/goal/phase-orchestrator.d.ts.map +0 -1
- package/dist/goal/phase-store.d.ts.map +0 -1
- package/dist/goal/types.d.ts.map +0 -1
- package/dist/hooks/http-executor.d.ts.map +0 -1
- package/dist/hooks/index.d.ts.map +0 -1
- package/dist/hooks/index.js.map +0 -7
- package/dist/hooks/registry.d.ts.map +0 -1
- package/dist/hooks/runner.d.ts.map +0 -1
- package/dist/hooks/shell-executor.d.ts.map +0 -1
- package/dist/hooks/shell-hooks-equal.d.ts.map +0 -1
- package/dist/hq/alerts.d.ts.map +0 -1
- package/dist/hq/auth-audit.d.ts.map +0 -1
- package/dist/hq/auth-store.d.ts.map +0 -1
- package/dist/hq/bootstrap-store.d.ts.map +0 -1
- package/dist/hq/brain-bridge.d.ts.map +0 -1
- package/dist/hq/bridge-context.d.ts.map +0 -1
- package/dist/hq/commands.d.ts.map +0 -1
- package/dist/hq/cost-bridge.d.ts.map +0 -1
- package/dist/hq/exposure.d.ts.map +0 -1
- package/dist/hq/factory.d.ts.map +0 -1
- package/dist/hq/fleet-bridge.d.ts.map +0 -1
- package/dist/hq/index.d.ts.map +0 -1
- package/dist/hq/index.js.map +0 -7
- package/dist/hq/kanban-store.d.ts.map +0 -1
- package/dist/hq/mailbox-mapper.d.ts.map +0 -1
- package/dist/hq/persistence/event-log.d.ts.map +0 -1
- package/dist/hq/persistence/jsonl-io.d.ts.map +0 -1
- package/dist/hq/persistence/simple-log.d.ts.map +0 -1
- package/dist/hq/persistence/snapshot-store.d.ts.map +0 -1
- package/dist/hq/persistence/timeseries-store.d.ts.map +0 -1
- package/dist/hq/persistence.d.ts.map +0 -1
- package/dist/hq/protocol/brain.d.ts.map +0 -1
- package/dist/hq/protocol/browser.d.ts.map +0 -1
- package/dist/hq/protocol/client.d.ts.map +0 -1
- package/dist/hq/protocol/core.d.ts.map +0 -1
- package/dist/hq/protocol/fleet.d.ts.map +0 -1
- package/dist/hq/protocol/kanban.d.ts.map +0 -1
- package/dist/hq/protocol/mailbox.d.ts.map +0 -1
- package/dist/hq/protocol/mcp.d.ts.map +0 -1
- package/dist/hq/protocol/peer.d.ts.map +0 -1
- package/dist/hq/protocol/project.d.ts.map +0 -1
- package/dist/hq/protocol/resume.d.ts.map +0 -1
- package/dist/hq/protocol/session.d.ts.map +0 -1
- package/dist/hq/protocol/tool.d.ts.map +0 -1
- package/dist/hq/protocol.d.ts.map +0 -1
- package/dist/hq/publisher.d.ts.map +0 -1
- package/dist/hq/redaction.d.ts.map +0 -1
- package/dist/hq/session-bridge.d.ts.map +0 -1
- package/dist/hq/tool-bridge.d.ts.map +0 -1
- package/dist/hq/transcript-mapper.d.ts.map +0 -1
- package/dist/hq/worktree-bridge.d.ts.map +0 -1
- package/dist/hq/write-queues.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -7
- package/dist/infrastructure/context-manager.d.ts.map +0 -1
- package/dist/infrastructure/index.d.ts.map +0 -1
- package/dist/infrastructure/index.js.map +0 -7
- package/dist/infrastructure/logger.d.ts.map +0 -1
- package/dist/infrastructure/mcp-servers.d.ts.map +0 -1
- package/dist/infrastructure/path-resolver.d.ts.map +0 -1
- package/dist/infrastructure/provider-cache-ledger.d.ts.map +0 -1
- package/dist/infrastructure/token-counter.d.ts.map +0 -1
- package/dist/kernel/container.d.ts.map +0 -1
- package/dist/kernel/events/agent-events.d.ts.map +0 -1
- package/dist/kernel/events/brain-events.d.ts.map +0 -1
- package/dist/kernel/events/file-events.d.ts.map +0 -1
- package/dist/kernel/events/fleet-events.d.ts.map +0 -1
- package/dist/kernel/events/memory-events.d.ts.map +0 -1
- package/dist/kernel/events/network-events.d.ts.map +0 -1
- package/dist/kernel/events/process-events.d.ts.map +0 -1
- package/dist/kernel/events/provider-events.d.ts.map +0 -1
- package/dist/kernel/events/sdd-events.d.ts.map +0 -1
- package/dist/kernel/events/session-events.d.ts.map +0 -1
- package/dist/kernel/events/tool-events.d.ts.map +0 -1
- package/dist/kernel/events/worktree-events.d.ts.map +0 -1
- package/dist/kernel/events.d.ts.map +0 -1
- package/dist/kernel/index.d.ts.map +0 -1
- package/dist/kernel/index.js.map +0 -7
- package/dist/kernel/pipeline.d.ts.map +0 -1
- package/dist/kernel/run-controller.d.ts.map +0 -1
- package/dist/kernel/tokens.d.ts.map +0 -1
- package/dist/mailbox-attach.d.ts.map +0 -1
- package/dist/middleware/collab-pause.d.ts.map +0 -1
- package/dist/models/alibaba-token-plan-catalog.d.ts.map +0 -1
- package/dist/models/codex-catalog.d.ts.map +0 -1
- package/dist/models/index.d.ts.map +0 -1
- package/dist/models/index.js.map +0 -7
- package/dist/models/llm-selector.d.ts.map +0 -1
- package/dist/models/mode-store.d.ts.map +0 -1
- package/dist/models/model-intelligence.d.ts.map +0 -1
- package/dist/models/model-router.d.ts.map +0 -1
- package/dist/models/models-registry.d.ts.map +0 -1
- package/dist/models/provider-model-resolve.d.ts.map +0 -1
- package/dist/notifications/index.d.ts.map +0 -1
- package/dist/notifications/index.js.map +0 -7
- package/dist/notifications/notifier-impl.d.ts.map +0 -1
- package/dist/notifications/notifier.d.ts.map +0 -1
- package/dist/notifications/types.d.ts.map +0 -1
- package/dist/observability/event-bridge.d.ts.map +0 -1
- package/dist/observability/health.d.ts.map +0 -1
- package/dist/observability/index.d.ts.map +0 -1
- package/dist/observability/index.js.map +0 -7
- package/dist/observability/metrics.d.ts.map +0 -1
- package/dist/observability/network-telemetry.d.ts.map +0 -1
- package/dist/observability/otel-tracer.d.ts.map +0 -1
- package/dist/observability/otlp-metrics.d.ts.map +0 -1
- package/dist/observability/otlp-traces.d.ts.map +0 -1
- package/dist/observability/process-telemetry.d.ts.map +0 -1
- package/dist/observability/prometheus.d.ts.map +0 -1
- package/dist/observability/redact-command.d.ts.map +0 -1
- package/dist/observability/tracer.d.ts.map +0 -1
- package/dist/plugin/api.d.ts.map +0 -1
- package/dist/plugin/config.d.ts.map +0 -1
- package/dist/plugin/index.d.ts.map +0 -1
- package/dist/plugin/index.js.map +0 -7
- package/dist/plugin/loader.d.ts.map +0 -1
- package/dist/plugins/auto-review-plugin.d.ts.map +0 -1
- package/dist/plugins/chimera-plugin.d.ts.map +0 -1
- package/dist/plugins/prompts-plugin.d.ts.map +0 -1
- package/dist/plugins/review-claim-registry.d.ts.map +0 -1
- package/dist/plugins/review-context-builder.d.ts.map +0 -1
- package/dist/plugins/review-finding-commands.d.ts.map +0 -1
- package/dist/plugins/review-finding-integration.d.ts.map +0 -1
- package/dist/plugins/review-finding-parser.d.ts.map +0 -1
- package/dist/plugins/review-finding-store.d.ts.map +0 -1
- package/dist/plugins/review-finding-types.d.ts.map +0 -1
- package/dist/plugins/review-report-integration.d.ts.map +0 -1
- package/dist/plugins/review-report-store.d.ts.map +0 -1
- package/dist/plugins/review-report-types.d.ts.map +0 -1
- package/dist/plugins/review-types.d.ts.map +0 -1
- package/dist/plugins/skills-plugin.d.ts.map +0 -1
- package/dist/plugins/sync-plugin.d.ts.map +0 -1
- package/dist/prompts/index.d.ts.map +0 -1
- package/dist/prompts/prompt-installer.d.ts.map +0 -1
- package/dist/prompts/prompt-manifest-store.d.ts.map +0 -1
- package/dist/registry/index.d.ts.map +0 -1
- package/dist/registry/index.js.map +0 -7
- package/dist/registry/provider-registry.d.ts.map +0 -1
- package/dist/registry/slash-command-registry.d.ts.map +0 -1
- package/dist/registry/tool-registry.d.ts.map +0 -1
- package/dist/replay/hash.d.ts.map +0 -1
- package/dist/replay/index.d.ts.map +0 -1
- package/dist/replay/index.js.map +0 -7
- package/dist/replay/replay-provider-runner.d.ts.map +0 -1
- package/dist/security/capabilities.d.ts.map +0 -1
- package/dist/security/config-secrets.d.ts.map +0 -1
- package/dist/security/directory-permission-policy.d.ts.map +0 -1
- package/dist/security/directory-policy-schema.d.ts.map +0 -1
- package/dist/security/index.d.ts.map +0 -1
- package/dist/security/index.js.map +0 -7
- package/dist/security/kanban-boundary.d.ts.map +0 -1
- package/dist/security/permission-policy-schema.d.ts.map +0 -1
- package/dist/security/permission-policy.d.ts.map +0 -1
- package/dist/security/readonly-permission-policy.d.ts.map +0 -1
- package/dist/security/secret-scrubber.d.ts.map +0 -1
- package/dist/security/secret-vault.d.ts.map +0 -1
- package/dist/security/trust-boundary.d.ts.map +0 -1
- package/dist/security/yolo-risk.d.ts.map +0 -1
- package/dist/session-registry-atomic-file.d.ts.map +0 -1
- package/dist/session-registry-types.d.ts.map +0 -1
- package/dist/session-registry.d.ts.map +0 -1
- package/dist/skills/foreign-sources.d.ts.map +0 -1
- package/dist/skills/frontmatter.d.ts.map +0 -1
- package/dist/skills/github-fetcher.d.ts.map +0 -1
- package/dist/skills/index.d.ts.map +0 -1
- package/dist/skills/index.js.map +0 -7
- package/dist/skills/limits.d.ts.map +0 -1
- package/dist/skills/manifest-store.d.ts.map +0 -1
- package/dist/skills/registry/github-direct-adapter.d.ts.map +0 -1
- package/dist/skills/registry/registry-adapter.d.ts.map +0 -1
- package/dist/skills/registry/skills-sh-adapter.d.ts.map +0 -1
- package/dist/skills/skill-generator.d.ts.map +0 -1
- package/dist/skills/skill-installer.d.ts.map +0 -1
- package/dist/storage/annotations-store.d.ts.map +0 -1
- package/dist/storage/attachment-store.d.ts.map +0 -1
- package/dist/storage/cloud-sync.d.ts.map +0 -1
- package/dist/storage/completed-work-checkpoint.d.ts.map +0 -1
- package/dist/storage/config-loader/bootstrap.d.ts.map +0 -1
- package/dist/storage/config-loader/default-repair.d.ts.map +0 -1
- package/dist/storage/config-loader/defaults.d.ts.map +0 -1
- package/dist/storage/config-loader/diagnostics.d.ts.map +0 -1
- package/dist/storage/config-loader/env-overrides.d.ts.map +0 -1
- package/dist/storage/config-loader/in-project-policy.d.ts.map +0 -1
- package/dist/storage/config-loader/inline-provider-models.d.ts.map +0 -1
- package/dist/storage/config-loader/legacy-sage-migration.d.ts.map +0 -1
- package/dist/storage/config-loader/path-identity.d.ts.map +0 -1
- package/dist/storage/config-loader/types.d.ts.map +0 -1
- package/dist/storage/config-loader/validation.d.ts.map +0 -1
- package/dist/storage/config-loader.d.ts.map +0 -1
- package/dist/storage/config-migration.d.ts.map +0 -1
- package/dist/storage/config-store.d.ts.map +0 -1
- package/dist/storage/director-state.d.ts.map +0 -1
- package/dist/storage/file-session-writer.d.ts.map +0 -1
- package/dist/storage/goal-coordination.d.ts.map +0 -1
- package/dist/storage/goal-kanban.d.ts.map +0 -1
- package/dist/storage/goal-store.d.ts.map +0 -1
- package/dist/storage/index.d.ts.map +0 -1
- package/dist/storage/index.js.map +0 -7
- package/dist/storage/input-history-store.d.ts.map +0 -1
- package/dist/storage/memory-backend.d.ts.map +0 -1
- package/dist/storage/memory-consolidator.d.ts.map +0 -1
- package/dist/storage/memory-graph-backend.d.ts.map +0 -1
- package/dist/storage/plan-store.d.ts.map +0 -1
- package/dist/storage/plan-templates.d.ts.map +0 -1
- package/dist/storage/prompt-store.d.ts.map +0 -1
- package/dist/storage/prompt-usage-store.d.ts.map +0 -1
- package/dist/storage/provider-config-watcher.d.ts.map +0 -1
- package/dist/storage/queue-store.d.ts.map +0 -1
- package/dist/storage/recovery-lock.d.ts.map +0 -1
- package/dist/storage/replay-log-store.d.ts.map +0 -1
- package/dist/storage/session-analyzer.d.ts.map +0 -1
- package/dist/storage/session-checkpoint-cas.d.ts.map +0 -1
- package/dist/storage/session-event-bridge.d.ts.map +0 -1
- package/dist/storage/session-helpers.d.ts.map +0 -1
- package/dist/storage/session-id-resolver.d.ts.map +0 -1
- package/dist/storage/session-id.d.ts.map +0 -1
- package/dist/storage/session-read-scrubber.d.ts.map +0 -1
- package/dist/storage/session-reader.d.ts.map +0 -1
- package/dist/storage/session-recovery.d.ts.map +0 -1
- package/dist/storage/session-resume-validation.d.ts.map +0 -1
- package/dist/storage/session-rewind-apply.d.ts.map +0 -1
- package/dist/storage/session-rewinder.d.ts.map +0 -1
- package/dist/storage/session-store/delete-session-artifacts.d.ts.map +0 -1
- package/dist/storage/session-store/delete-session-guards.d.ts.map +0 -1
- package/dist/storage/session-store/directory-scan.d.ts.map +0 -1
- package/dist/storage/session-store/directory-session-files.d.ts.map +0 -1
- package/dist/storage/session-store/events.d.ts.map +0 -1
- package/dist/storage/session-store/fork-session.d.ts.map +0 -1
- package/dist/storage/session-store/index-reader.d.ts.map +0 -1
- package/dist/storage/session-store/load-cache.d.ts.map +0 -1
- package/dist/storage/session-store/load-session-data.d.ts.map +0 -1
- package/dist/storage/session-store/paths.d.ts.map +0 -1
- package/dist/storage/session-store/prune-helpers.d.ts.map +0 -1
- package/dist/storage/session-store/replay.d.ts.map +0 -1
- package/dist/storage/session-store/search-events.d.ts.map +0 -1
- package/dist/storage/session-store/shard-manifest.d.ts.map +0 -1
- package/dist/storage/session-store/summary-builder.d.ts.map +0 -1
- package/dist/storage/session-store/summary-header.d.ts.map +0 -1
- package/dist/storage/session-store/types.d.ts.map +0 -1
- package/dist/storage/session-store.d.ts.map +0 -1
- package/dist/storage/session-summary.d.ts.map +0 -1
- package/dist/storage/session-tool-call-ends.d.ts.map +0 -1
- package/dist/storage/session-writer-scrubber.d.ts.map +0 -1
- package/dist/storage/session-writer-truncate.d.ts.map +0 -1
- package/dist/storage/storage-concurrency.d.ts.map +0 -1
- package/dist/storage/task-store.d.ts.map +0 -1
- package/dist/storage/todos-checkpoint.d.ts.map +0 -1
- package/dist/storage/tool-audit-log.d.ts.map +0 -1
- package/dist/tasking/index.d.ts.map +0 -1
- package/dist/tasking/index.js.map +0 -7
- package/dist/tasking/task-store.d.ts.map +0 -1
- package/dist/tasking/task-tracker.d.ts.map +0 -1
- package/dist/tools/council-tool.d.ts.map +0 -1
- package/dist/tools/fallback-chain-manage-tool.d.ts.map +0 -1
- package/dist/tools/fallback-favorite-manage-tool.d.ts.map +0 -1
- package/dist/tools/fallback-manage-helpers.d.ts.map +0 -1
- package/dist/tools/fallback-manage-tool-options.d.ts.map +0 -1
- package/dist/tools/fallback-manage-tools.d.ts.map +0 -1
- package/dist/tools/fallback-model-ref-parse.d.ts.map +0 -1
- package/dist/tools/fallback-provider-key-store.d.ts.map +0 -1
- package/dist/tools/fallback-system-config-view-tool.d.ts.map +0 -1
- package/dist/tools/index.d.ts.map +0 -1
- package/dist/tools/index.js.map +0 -7
- package/dist/tools/mcp-control.d.ts.map +0 -1
- package/dist/tools/mcp-use.d.ts.map +0 -1
- package/dist/tools/one-shot-llm-tool.d.ts.map +0 -1
- package/dist/tools/plugin-manager.d.ts.map +0 -1
- package/dist/types/agent-bridge.d.ts.map +0 -1
- package/dist/types/attachment.d.ts.map +0 -1
- package/dist/types/autonomy.d.ts.map +0 -1
- package/dist/types/blocks.d.ts.map +0 -1
- package/dist/types/compactor.d.ts.map +0 -1
- package/dist/types/config/autonomy.d.ts.map +0 -1
- package/dist/types/config/context.d.ts.map +0 -1
- package/dist/types/config/fleet-chat.d.ts.map +0 -1
- package/dist/types/config/mcp-features.d.ts.map +0 -1
- package/dist/types/config/providers.d.ts.map +0 -1
- package/dist/types/config/root.d.ts.map +0 -1
- package/dist/types/config/runtime.d.ts.map +0 -1
- package/dist/types/config/skills-fleet-brain.d.ts.map +0 -1
- package/dist/types/config/tools.d.ts.map +0 -1
- package/dist/types/config.d.ts.map +0 -1
- package/dist/types/context-evidence.d.ts.map +0 -1
- package/dist/types/context-window.d.ts.map +0 -1
- package/dist/types/council.d.ts.map +0 -1
- package/dist/types/default-config.d.ts.map +0 -1
- package/dist/types/design-kit.d.ts.map +0 -1
- package/dist/types/error-handler.d.ts.map +0 -1
- package/dist/types/errors.d.ts.map +0 -1
- package/dist/types/file-event-record.d.ts.map +0 -1
- package/dist/types/hooks.d.ts.map +0 -1
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/index.js.map +0 -7
- package/dist/types/input-reader.d.ts.map +0 -1
- package/dist/types/logger.d.ts.map +0 -1
- package/dist/types/memory.d.ts.map +0 -1
- package/dist/types/messages.d.ts.map +0 -1
- package/dist/types/mode-prompts.d.ts.map +0 -1
- package/dist/types/mode.d.ts.map +0 -1
- package/dist/types/models-registry.d.ts.map +0 -1
- package/dist/types/multi-agent.d.ts.map +0 -1
- package/dist/types/observability.d.ts.map +0 -1
- package/dist/types/one-shot-llm.d.ts.map +0 -1
- package/dist/types/path-resolver.d.ts.map +0 -1
- package/dist/types/permission.d.ts.map +0 -1
- package/dist/types/plugin.d.ts.map +0 -1
- package/dist/types/prompt-registry.d.ts.map +0 -1
- package/dist/types/prompt.d.ts.map +0 -1
- package/dist/types/provider-runner.d.ts.map +0 -1
- package/dist/types/provider.d.ts.map +0 -1
- package/dist/types/quota-regex.d.ts.map +0 -1
- package/dist/types/renderer.d.ts.map +0 -1
- package/dist/types/retry-policy.d.ts.map +0 -1
- package/dist/types/secret-scrubber.d.ts.map +0 -1
- package/dist/types/secret-vault.d.ts.map +0 -1
- package/dist/types/selector.d.ts.map +0 -1
- package/dist/types/session-markers.d.ts.map +0 -1
- package/dist/types/session-markers.js.map +0 -7
- package/dist/types/session-reader.d.ts.map +0 -1
- package/dist/types/session-rewinder.d.ts.map +0 -1
- package/dist/types/session.d.ts.map +0 -1
- package/dist/types/side-effect.d.ts.map +0 -1
- package/dist/types/skill.d.ts.map +0 -1
- package/dist/types/slash-command.d.ts.map +0 -1
- package/dist/types/spec.d.ts.map +0 -1
- package/dist/types/system-prompt-contributor.d.ts.map +0 -1
- package/dist/types/system-prompt.d.ts.map +0 -1
- package/dist/types/task-graph.d.ts.map +0 -1
- package/dist/types/token-counter.d.ts.map +0 -1
- package/dist/types/tool-executor.d.ts.map +0 -1
- package/dist/types/tool-markers.d.ts.map +0 -1
- package/dist/types/tool.d.ts.map +0 -1
- package/dist/types/utility-types.d.ts.map +0 -1
- package/dist/utils/assert-never.d.ts.map +0 -1
- package/dist/utils/atomic-write.d.ts.map +0 -1
- package/dist/utils/cache-key.d.ts.map +0 -1
- package/dist/utils/child-env.d.ts.map +0 -1
- package/dist/utils/color.d.ts.map +0 -1
- package/dist/utils/compaction-preview.d.ts.map +0 -1
- package/dist/utils/config-backup.d.ts.map +0 -1
- package/dist/utils/config-json.d.ts.map +0 -1
- package/dist/utils/connectivity.d.ts.map +0 -1
- package/dist/utils/context-breakdown.d.ts.map +0 -1
- package/dist/utils/context-evidence.d.ts.map +0 -1
- package/dist/utils/continuous-memory-profiler.d.ts.map +0 -1
- package/dist/utils/crash-shield.d.ts.map +0 -1
- package/dist/utils/deep-merge.d.ts.map +0 -1
- package/dist/utils/diff.d.ts.map +0 -1
- package/dist/utils/error.d.ts.map +0 -1
- package/dist/utils/error.js.map +0 -7
- package/dist/utils/expect-defined.d.ts.map +0 -1
- package/dist/utils/expect-defined.js.map +0 -7
- package/dist/utils/glob-expand.d.ts.map +0 -1
- package/dist/utils/glob-match.d.ts.map +0 -1
- package/dist/utils/heap-watchdog-types.d.ts.map +0 -1
- package/dist/utils/heap-watchdog.d.ts.map +0 -1
- package/dist/utils/heap-watchdog.js.map +0 -7
- package/dist/utils/incoming-images.d.ts.map +0 -1
- package/dist/utils/index.d.ts.map +0 -1
- package/dist/utils/index.js.map +0 -7
- package/dist/utils/instruction-file.d.ts.map +0 -1
- package/dist/utils/ip-guard.d.ts.map +0 -1
- package/dist/utils/json-repair.d.ts.map +0 -1
- package/dist/utils/json-schema-validate.d.ts.map +0 -1
- package/dist/utils/lru-cache.d.ts.map +0 -1
- package/dist/utils/memory-flight-recorder.d.ts.map +0 -1
- package/dist/utils/merge-custom-models.d.ts.map +0 -1
- package/dist/utils/merge-models-payload.d.ts.map +0 -1
- package/dist/utils/message-invariants.d.ts.map +0 -1
- package/dist/utils/newline-normalize.d.ts.map +0 -1
- package/dist/utils/perf-profile.d.ts.map +0 -1
- package/dist/utils/pid.d.ts.map +0 -1
- package/dist/utils/project-identity.d.ts.map +0 -1
- package/dist/utils/project-watch.d.ts.map +0 -1
- package/dist/utils/regex-guard.d.ts.map +0 -1
- package/dist/utils/safe-json.d.ts.map +0 -1
- package/dist/utils/sage-output-block.d.ts.map +0 -1
- package/dist/utils/session-scoped-path.d.ts.map +0 -1
- package/dist/utils/sleep.d.ts.map +0 -1
- package/dist/utils/slug.d.ts.map +0 -1
- package/dist/utils/socket-path.d.ts.map +0 -1
- package/dist/utils/sqlite-warning.d.ts.map +0 -1
- package/dist/utils/string.d.ts.map +0 -1
- package/dist/utils/task-format.d.ts.map +0 -1
- package/dist/utils/term.d.ts.map +0 -1
- package/dist/utils/todos-format.d.ts.map +0 -1
- package/dist/utils/token-estimate.d.ts.map +0 -1
- package/dist/utils/tool-description-mode.d.ts.map +0 -1
- package/dist/utils/tool-name.d.ts.map +0 -1
- package/dist/utils/tool-output-serializer.d.ts.map +0 -1
- package/dist/utils/tool-result-render-mode.d.ts.map +0 -1
- package/dist/utils/tool-subject.d.ts.map +0 -1
- package/dist/utils/tool-wire-compact.d.ts.map +0 -1
- package/dist/utils/tree-kill.d.ts.map +0 -1
- package/dist/utils/tree-kill.js.map +0 -7
- package/dist/utils/ulid.d.ts.map +0 -1
- package/dist/utils/walk-ignore.d.ts.map +0 -1
- package/dist/utils/wstack-paths.d.ts.map +0 -1
- package/dist/worktree/index.d.ts.map +0 -1
- package/dist/worktree/index.js.map +0 -7
- package/dist/worktree/worktree-git.d.ts.map +0 -1
- package/dist/worktree/worktree-managed-ops.d.ts.map +0 -1
- package/dist/worktree/worktree-manager.d.ts.map +0 -1
- package/dist/worktree/worktree-types.d.ts.map +0 -1
package/dist/plugin/index.js
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
|
}
|
|
@@ -6554,7 +6883,12 @@ function selectRoundRobinReviewerAssignment(pool, cursor, fallbackProvider = "",
|
|
|
6554
6883
|
}
|
|
6555
6884
|
function resolveAutoReviewConfig(cfg, sessionConfig) {
|
|
6556
6885
|
const mgr = new FallbackProfileManager(sessionConfig);
|
|
6557
|
-
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
|
+
});
|
|
6558
6892
|
const rawProvider = cfg.provider?.trim();
|
|
6559
6893
|
const rawModel = cfg.model?.trim();
|
|
6560
6894
|
const resolvedProvider = rawProvider || (chain.length > 0 ? chain[0].providerId : sessionConfig.provider);
|
|
@@ -6698,8 +7032,8 @@ async function snapshotChangedFiles(cwd) {
|
|
|
6698
7032
|
if (file.path.startsWith(".wrongstack/")) continue;
|
|
6699
7033
|
if (budget <= 0) break;
|
|
6700
7034
|
try {
|
|
6701
|
-
const
|
|
6702
|
-
if (!
|
|
7035
|
+
const stat7 = await fsp.stat(path14.join(cwd, file.path));
|
|
7036
|
+
if (!stat7.isFile() || stat7.size > MAX_SNAPSHOT_FILE_BYTES) continue;
|
|
6703
7037
|
const content = await fsp.readFile(path14.join(cwd, file.path), "utf8");
|
|
6704
7038
|
budget -= content.length;
|
|
6705
7039
|
snapshots.push({
|
|
@@ -7157,7 +7491,6 @@ function createAutoReviewPlugin() {
|
|
|
7157
7491
|
|
|
7158
7492
|
// src/plugins/chimera-plugin.ts
|
|
7159
7493
|
init_error();
|
|
7160
|
-
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
7161
7494
|
import { spawn as spawn4 } from "node:child_process";
|
|
7162
7495
|
import * as fsp4 from "node:fs/promises";
|
|
7163
7496
|
import * as os5 from "node:os";
|
|
@@ -7233,10 +7566,20 @@ function parseFindingSegment(segment, severity, context) {
|
|
|
7233
7566
|
if (tagMatch) {
|
|
7234
7567
|
remaining = content.slice(tagMatch[0].length).trim();
|
|
7235
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
|
+
}
|
|
7236
7577
|
let file;
|
|
7237
7578
|
let line;
|
|
7238
7579
|
let desc = remaining;
|
|
7239
|
-
const refMatch = remaining.match(
|
|
7580
|
+
const refMatch = remaining.match(
|
|
7581
|
+
/^([a-zA-Z_./\\][a-zA-Z0-9_./\\-]*\.\w+)(?::(\d+))?\s+(?:[—–]|-)\s+(.+)$/
|
|
7582
|
+
);
|
|
7240
7583
|
if (refMatch) {
|
|
7241
7584
|
file = refMatch[1].trim();
|
|
7242
7585
|
if (refMatch[2] !== void 0) {
|
|
@@ -7334,12 +7677,26 @@ async function persistReviewReport(payload, reportId, projectDir) {
|
|
|
7334
7677
|
...cascadeDepth !== void 0 ? { cascadeDepth } : {}
|
|
7335
7678
|
};
|
|
7336
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
|
+
}
|
|
7337
7690
|
return {
|
|
7338
7691
|
reportId,
|
|
7339
7692
|
created: !existed,
|
|
7340
7693
|
totalFindings: parsed.findings.length
|
|
7341
7694
|
};
|
|
7342
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
|
+
}
|
|
7343
7700
|
async function syncReportCompletion(reportId, projectDir, actor) {
|
|
7344
7701
|
const reportStore = new JsonlReportStore(projectDir);
|
|
7345
7702
|
const findingStore = new JsonlFindingStore(projectDir);
|
|
@@ -7812,49 +8169,6 @@ async function showStatus(ctx) {
|
|
|
7812
8169
|
].join("\n");
|
|
7813
8170
|
}
|
|
7814
8171
|
|
|
7815
|
-
// src/plugins/review-finding-integration.ts
|
|
7816
|
-
init_review_finding_store();
|
|
7817
|
-
async function integrateFindings(payload, projectDir, reportId) {
|
|
7818
|
-
if (!payload.reviewText || payload.reviewText.trim().length === 0) {
|
|
7819
|
-
return { created: 0, relinked: 0, reopened: 0, totalFindings: 0, unparseableCount: 0 };
|
|
7820
|
-
}
|
|
7821
|
-
const store = new JsonlFindingStore(projectDir);
|
|
7822
|
-
const source = (payload.bundle.cascadeDepth ?? 0) > 0 ? "cascade" : payload.bundle.cascadeOn !== void 0 && payload.bundle.cascadeOn !== "off" ? "auto" : "chimera";
|
|
7823
|
-
const agentId = payload.bundle.fileProvenance?.find((entry) => entry.agentId)?.agentId ?? "chimera-review";
|
|
7824
|
-
const sessionId = payload.sessionId ?? payload.cwd;
|
|
7825
|
-
const model = payload.bundle.config.model;
|
|
7826
|
-
const parsed = parseChimeraReviewReport(payload.reviewText, {
|
|
7827
|
-
sessionId,
|
|
7828
|
-
agentId,
|
|
7829
|
-
reviewerModel: model,
|
|
7830
|
-
reviewType: source,
|
|
7831
|
-
reportId
|
|
7832
|
-
});
|
|
7833
|
-
if (parsed.findings.length === 0) {
|
|
7834
|
-
return {
|
|
7835
|
-
created: 0,
|
|
7836
|
-
relinked: 0,
|
|
7837
|
-
reopened: 0,
|
|
7838
|
-
totalFindings: 0,
|
|
7839
|
-
unparseableCount: parsed.unparseableCount
|
|
7840
|
-
};
|
|
7841
|
-
}
|
|
7842
|
-
const result = await store.upsert(parsed.findings, {
|
|
7843
|
-
sessionId,
|
|
7844
|
-
reportId,
|
|
7845
|
-
agentId,
|
|
7846
|
-
model
|
|
7847
|
-
});
|
|
7848
|
-
return {
|
|
7849
|
-
created: result.created,
|
|
7850
|
-
relinked: result.relinked,
|
|
7851
|
-
reopened: result.reopened,
|
|
7852
|
-
reportId,
|
|
7853
|
-
totalFindings: parsed.findings.length,
|
|
7854
|
-
unparseableCount: parsed.unparseableCount
|
|
7855
|
-
};
|
|
7856
|
-
}
|
|
7857
|
-
|
|
7858
8172
|
// src/plugins/chimera-plugin.ts
|
|
7859
8173
|
var DEFAULT_MAX_FILES = 15;
|
|
7860
8174
|
var DEFAULT_CASCADE_ON = "off";
|
|
@@ -8010,18 +8324,6 @@ function buildReviewCommand(_getConfig) {
|
|
|
8010
8324
|
}
|
|
8011
8325
|
};
|
|
8012
8326
|
}
|
|
8013
|
-
async function tryPersistFindings(payload) {
|
|
8014
|
-
if (!payload || typeof payload !== "object") return;
|
|
8015
|
-
const p = payload;
|
|
8016
|
-
const cwd = p.cwd ?? p.bundle?.cwd;
|
|
8017
|
-
if (!cwd) return;
|
|
8018
|
-
const slug = projectSlug(cwd);
|
|
8019
|
-
const globalRoot = path17.join(os5.homedir(), ".wrongstack");
|
|
8020
|
-
const projectDir = path17.join(globalRoot, "projects", slug);
|
|
8021
|
-
const reportId = randomUUID6();
|
|
8022
|
-
await persistReviewReport(payload, reportId, projectDir);
|
|
8023
|
-
await integrateFindings(payload, projectDir, reportId);
|
|
8024
|
-
}
|
|
8025
8327
|
function createChimeraPlugin() {
|
|
8026
8328
|
return {
|
|
8027
8329
|
name: "wstack-chimera",
|
|
@@ -8050,9 +8352,6 @@ function createChimeraPlugin() {
|
|
|
8050
8352
|
});
|
|
8051
8353
|
api.onPattern("chimera.review_complete", (_event, payload) => {
|
|
8052
8354
|
recordCompletedReview(api.events, payload);
|
|
8053
|
-
tryPersistFindings(payload).catch((err) => {
|
|
8054
|
-
api.log.warn(`[review-finding] failed to persist findings: ${toErrorMessage(err)}`);
|
|
8055
|
-
});
|
|
8056
8355
|
});
|
|
8057
8356
|
if (!resolved.enabled) {
|
|
8058
8357
|
api.log.info("[chimera] disabled by config");
|
|
@@ -8634,8 +8933,8 @@ var PromptUsageStore = class {
|
|
|
8634
8933
|
}
|
|
8635
8934
|
async fileSignature() {
|
|
8636
8935
|
try {
|
|
8637
|
-
const
|
|
8638
|
-
return { size:
|
|
8936
|
+
const stat7 = await fs10.stat(this.file);
|
|
8937
|
+
return { size: stat7.size, mtimeMs: stat7.mtimeMs, ctimeMs: stat7.ctimeMs };
|
|
8639
8938
|
} catch {
|
|
8640
8939
|
return null;
|
|
8641
8940
|
}
|
|
@@ -9045,12 +9344,12 @@ function parseFlags(input) {
|
|
|
9045
9344
|
while (s.startsWith("--") && (m = flagRe.exec(s))) {
|
|
9046
9345
|
const name = expectDefined(m[1]);
|
|
9047
9346
|
const rawVal = m[2] ?? m[3] ?? "true";
|
|
9048
|
-
flags[name] =
|
|
9347
|
+
flags[name] = unquote2(rawVal);
|
|
9049
9348
|
s = s.slice(m[0].length);
|
|
9050
9349
|
}
|
|
9051
9350
|
return { flags, positional: s.trim() };
|
|
9052
9351
|
}
|
|
9053
|
-
function
|
|
9352
|
+
function unquote2(v) {
|
|
9054
9353
|
if (v.startsWith('"') && v.endsWith('"') || v.startsWith("'") && v.endsWith("'")) {
|
|
9055
9354
|
return v.slice(1, -1);
|
|
9056
9355
|
}
|
|
@@ -9089,7 +9388,7 @@ function parseKeyValues(kvs) {
|
|
|
9089
9388
|
const out = {};
|
|
9090
9389
|
for (const kv of kvs) {
|
|
9091
9390
|
const eq = kv.indexOf("=");
|
|
9092
|
-
if (eq > 0) out[kv.slice(0, eq)] =
|
|
9391
|
+
if (eq > 0) out[kv.slice(0, eq)] = unquote2(kv.slice(eq + 1));
|
|
9093
9392
|
}
|
|
9094
9393
|
return out;
|
|
9095
9394
|
}
|
|
@@ -9109,9 +9408,123 @@ function dim(s) {
|
|
|
9109
9408
|
return `\x1B[2m${s}\x1B[0m`;
|
|
9110
9409
|
}
|
|
9111
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
|
+
|
|
9112
9525
|
// src/plugins/skills-plugin.ts
|
|
9113
9526
|
import * as os7 from "node:os";
|
|
9114
|
-
import * as
|
|
9527
|
+
import * as path26 from "node:path";
|
|
9115
9528
|
|
|
9116
9529
|
// src/skills/foreign-sources.ts
|
|
9117
9530
|
var FOREIGN_SKILL_TOOLS = [
|
|
@@ -9294,104 +9707,7 @@ function numField(rec, key) {
|
|
|
9294
9707
|
init_errors();
|
|
9295
9708
|
import { spawn as spawn5 } from "node:child_process";
|
|
9296
9709
|
import * as fs12 from "node:fs/promises";
|
|
9297
|
-
import * as
|
|
9298
|
-
|
|
9299
|
-
// src/skills/frontmatter.ts
|
|
9300
|
-
var SCALAR_KEYS = /* @__PURE__ */ new Set(["name", "description", "version", "license", "compatibility"]);
|
|
9301
|
-
function parseSkillFrontmatter(raw) {
|
|
9302
|
-
const text = normalizeLineEndings(raw);
|
|
9303
|
-
if (!text.startsWith("---")) return {};
|
|
9304
|
-
const end = text.indexOf("\n---", 4);
|
|
9305
|
-
if (end === -1) return {};
|
|
9306
|
-
return parseFrontmatterBlock(text.slice(4, end));
|
|
9307
|
-
}
|
|
9308
|
-
function normalizeLineEndings(s) {
|
|
9309
|
-
return s.replace(/\r\n?/g, "\n");
|
|
9310
|
-
}
|
|
9311
|
-
function parseFrontmatterBlock(block) {
|
|
9312
|
-
const out = {};
|
|
9313
|
-
const lines = block.split("\n");
|
|
9314
|
-
let i = 0;
|
|
9315
|
-
while (i < lines.length) {
|
|
9316
|
-
const line = lines[i] ?? "";
|
|
9317
|
-
const m = /^([a-zA-Z][a-zA-Z0-9_-]*):\s*(.*)$/.exec(line);
|
|
9318
|
-
if (!m) {
|
|
9319
|
-
i++;
|
|
9320
|
-
continue;
|
|
9321
|
-
}
|
|
9322
|
-
const key = m[1] ?? "";
|
|
9323
|
-
const rest = (m[2] ?? "").trim();
|
|
9324
|
-
if (key === "metadata") {
|
|
9325
|
-
const map = {};
|
|
9326
|
-
i++;
|
|
9327
|
-
while (i < lines.length) {
|
|
9328
|
-
const sub = lines[i] ?? "";
|
|
9329
|
-
const sm = /^\s+([a-zA-Z0-9_.-]+):\s*(.*)$/.exec(sub);
|
|
9330
|
-
if (!sm) break;
|
|
9331
|
-
map[sm[1] ?? ""] = unquote2((sm[2] ?? "").trim());
|
|
9332
|
-
i++;
|
|
9333
|
-
}
|
|
9334
|
-
if (Object.keys(map).length > 0) out.metadata = map;
|
|
9335
|
-
continue;
|
|
9336
|
-
}
|
|
9337
|
-
if (rest === "|" || rest === ">") {
|
|
9338
|
-
const collected = [];
|
|
9339
|
-
i++;
|
|
9340
|
-
while (i < lines.length) {
|
|
9341
|
-
const sub = lines[i] ?? "";
|
|
9342
|
-
if (sub === "" || sub.startsWith(" ") || sub.startsWith(" ")) {
|
|
9343
|
-
collected.push(sub.replace(/^\s+/, ""));
|
|
9344
|
-
i++;
|
|
9345
|
-
} else break;
|
|
9346
|
-
}
|
|
9347
|
-
out[normalizeKey2(key)] = collected.join("\n").trim();
|
|
9348
|
-
continue;
|
|
9349
|
-
}
|
|
9350
|
-
if (key === "allowed-tools" || key === "allowedTools") {
|
|
9351
|
-
out.allowedTools = rest.split(/[\s,]+/).filter(Boolean);
|
|
9352
|
-
i++;
|
|
9353
|
-
continue;
|
|
9354
|
-
}
|
|
9355
|
-
if (SCALAR_KEYS.has(key)) {
|
|
9356
|
-
out[key] = unquote2(rest);
|
|
9357
|
-
i++;
|
|
9358
|
-
continue;
|
|
9359
|
-
}
|
|
9360
|
-
i++;
|
|
9361
|
-
}
|
|
9362
|
-
return out;
|
|
9363
|
-
}
|
|
9364
|
-
function normalizeKey2(key) {
|
|
9365
|
-
return key === "allowed-tools" ? "allowedTools" : key;
|
|
9366
|
-
}
|
|
9367
|
-
function unquote2(s) {
|
|
9368
|
-
if (s.length >= 2 && (s.startsWith('"') && s.endsWith('"') || s.startsWith("'") && s.endsWith("'"))) {
|
|
9369
|
-
return s.slice(1, -1);
|
|
9370
|
-
}
|
|
9371
|
-
return s;
|
|
9372
|
-
}
|
|
9373
|
-
function isValidSkillNameFormat(name) {
|
|
9374
|
-
return name.length >= 1 && name.length <= 64 && /^[a-z0-9]+(-[a-z0-9]+)*$/.test(name);
|
|
9375
|
-
}
|
|
9376
|
-
function validateSkillName(name, parentDirName) {
|
|
9377
|
-
const errors = [];
|
|
9378
|
-
if (!name || name.trim().length === 0) {
|
|
9379
|
-
errors.push("name is empty");
|
|
9380
|
-
return errors;
|
|
9381
|
-
}
|
|
9382
|
-
if (name.length > 64) errors.push(`name is ${name.length} characters (max 64)`);
|
|
9383
|
-
if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(name)) {
|
|
9384
|
-
errors.push(
|
|
9385
|
-
"name must be lowercase letters, digits, and single hyphens only (no leading/trailing/consecutive hyphens)"
|
|
9386
|
-
);
|
|
9387
|
-
}
|
|
9388
|
-
if (parentDirName !== void 0 && name !== parentDirName) {
|
|
9389
|
-
errors.push(`name "${name}" must match its parent directory "${parentDirName}"`);
|
|
9390
|
-
}
|
|
9391
|
-
return errors;
|
|
9392
|
-
}
|
|
9393
|
-
|
|
9394
|
-
// src/skills/skill-generator.ts
|
|
9710
|
+
import * as path22 from "node:path";
|
|
9395
9711
|
async function validateSkillNameAvailable(name, loader) {
|
|
9396
9712
|
const formatViolations = validateSkillName(name);
|
|
9397
9713
|
const conflicts = loader ? (await loader.listEntries()).filter((e) => e.name === name) : [];
|
|
@@ -9510,8 +9826,8 @@ async function writeSkeletonSkill(skillsDir, body, opts = {}) {
|
|
|
9510
9826
|
subsystem: "general"
|
|
9511
9827
|
});
|
|
9512
9828
|
}
|
|
9513
|
-
const skillDir =
|
|
9514
|
-
const skillFile =
|
|
9829
|
+
const skillDir = path22.join(skillsDir, name);
|
|
9830
|
+
const skillFile = path22.join(skillDir, "SKILL.md");
|
|
9515
9831
|
if (!opts.overwrite) {
|
|
9516
9832
|
try {
|
|
9517
9833
|
await fs12.access(skillFile);
|
|
@@ -9570,13 +9886,14 @@ function defaultEditor() {
|
|
|
9570
9886
|
init_errors();
|
|
9571
9887
|
init_error();
|
|
9572
9888
|
import * as fs15 from "node:fs/promises";
|
|
9573
|
-
import * as
|
|
9889
|
+
import * as path25 from "node:path";
|
|
9574
9890
|
|
|
9575
9891
|
// src/skills/github-fetcher.ts
|
|
9576
9892
|
init_errors();
|
|
9893
|
+
import { createWriteStream } from "node:fs";
|
|
9577
9894
|
import * as fs13 from "node:fs/promises";
|
|
9578
9895
|
import * as os6 from "node:os";
|
|
9579
|
-
import * as
|
|
9896
|
+
import * as path23 from "node:path";
|
|
9580
9897
|
import { Readable } from "node:stream";
|
|
9581
9898
|
import { pipeline } from "node:stream/promises";
|
|
9582
9899
|
import { createGunzip } from "node:zlib";
|
|
@@ -9603,6 +9920,46 @@ function parseSkillRef(input) {
|
|
|
9603
9920
|
}
|
|
9604
9921
|
return { owner: expectDefined(parts[0]), repo: expectDefined(parts[1]), ref };
|
|
9605
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
|
+
}
|
|
9606
9963
|
function resolveGitHubToken(env = process.env) {
|
|
9607
9964
|
const raw = env["WRONGSTACK_GITHUB_TOKEN"] ?? env["GITHUB_TOKEN"] ?? env["GH_TOKEN"];
|
|
9608
9965
|
if (!raw) return void 0;
|
|
@@ -9678,7 +10035,7 @@ async function downloadGitHubTarball(parsed) {
|
|
|
9678
10035
|
}
|
|
9679
10036
|
});
|
|
9680
10037
|
}
|
|
9681
|
-
const tempDir = await fs13.mkdtemp(
|
|
10038
|
+
const tempDir = await fs13.mkdtemp(path23.join(os6.tmpdir(), "wskill-"));
|
|
9682
10039
|
try {
|
|
9683
10040
|
if (!response.body) {
|
|
9684
10041
|
throw new WrongStackError({
|
|
@@ -9689,15 +10046,14 @@ async function downloadGitHubTarball(parsed) {
|
|
|
9689
10046
|
});
|
|
9690
10047
|
}
|
|
9691
10048
|
const nodeStream = Readable.fromWeb(response.body);
|
|
9692
|
-
const
|
|
9693
|
-
|
|
9694
|
-
|
|
9695
|
-
|
|
9696
|
-
|
|
9697
|
-
|
|
9698
|
-
|
|
9699
|
-
|
|
9700
|
-
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
|
+
}
|
|
9701
10057
|
return { tempDir };
|
|
9702
10058
|
} catch (err) {
|
|
9703
10059
|
await fs13.rm(tempDir, { recursive: true, force: true }).catch(() => {
|
|
@@ -9705,6 +10061,44 @@ async function downloadGitHubTarball(parsed) {
|
|
|
9705
10061
|
throw err;
|
|
9706
10062
|
}
|
|
9707
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
|
+
}
|
|
9708
10102
|
async function extractTar(buf, destDir) {
|
|
9709
10103
|
let offset = 0;
|
|
9710
10104
|
while (offset + 512 <= buf.length) {
|
|
@@ -9712,15 +10106,15 @@ async function extractTar(buf, destDir) {
|
|
|
9712
10106
|
if (header.every((b) => b === 0)) break;
|
|
9713
10107
|
const name = readTarString(buf, offset, 100);
|
|
9714
10108
|
const prefix = readTarString(buf, offset + 345, 155);
|
|
9715
|
-
const size =
|
|
10109
|
+
const size = readTarSize(buf, offset + 124);
|
|
9716
10110
|
const typeflag = buf[offset + 156] ?? 0;
|
|
9717
10111
|
const fullPath = prefix ? `${prefix}/${name}` : name;
|
|
9718
10112
|
const relPath = stripTopDir(fullPath);
|
|
9719
10113
|
if (relPath && relPath !== "." && relPath !== "..") {
|
|
9720
|
-
const destPath =
|
|
9721
|
-
const resolvedDest =
|
|
9722
|
-
const resolvedRoot =
|
|
9723
|
-
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)) {
|
|
9724
10118
|
offset += 512 + Math.ceil(size / 512) * 512;
|
|
9725
10119
|
continue;
|
|
9726
10120
|
}
|
|
@@ -9730,7 +10124,7 @@ async function extractTar(buf, destDir) {
|
|
|
9730
10124
|
}
|
|
9731
10125
|
}
|
|
9732
10126
|
if ((typeflag === 48 || typeflag === 0 || typeflag === 0) && size > 0) {
|
|
9733
|
-
const dir =
|
|
10127
|
+
const dir = path23.dirname(destPath);
|
|
9734
10128
|
await fs13.mkdir(dir, { recursive: true });
|
|
9735
10129
|
const dataStart = offset + 512;
|
|
9736
10130
|
const dataEnd = dataStart + size;
|
|
@@ -9741,23 +10135,11 @@ async function extractTar(buf, destDir) {
|
|
|
9741
10135
|
offset += 512 + Math.ceil(size / 512) * 512;
|
|
9742
10136
|
}
|
|
9743
10137
|
}
|
|
9744
|
-
function readTarString(buf, start, maxLen) {
|
|
9745
|
-
let end = start;
|
|
9746
|
-
while (end < start + maxLen && end < buf.length && buf[end] !== 0) {
|
|
9747
|
-
end++;
|
|
9748
|
-
}
|
|
9749
|
-
return buf.subarray(start, end).toString("utf8");
|
|
9750
|
-
}
|
|
9751
|
-
function stripTopDir(p) {
|
|
9752
|
-
const idx = p.indexOf("/");
|
|
9753
|
-
if (idx === -1) return "";
|
|
9754
|
-
return p.slice(idx + 1);
|
|
9755
|
-
}
|
|
9756
10138
|
|
|
9757
10139
|
// src/skills/manifest-store.ts
|
|
9758
10140
|
init_atomic_write();
|
|
9759
10141
|
import * as fs14 from "node:fs/promises";
|
|
9760
|
-
import * as
|
|
10142
|
+
import * as path24 from "node:path";
|
|
9761
10143
|
var SkillManifestStore = class {
|
|
9762
10144
|
manifestPath;
|
|
9763
10145
|
cache;
|
|
@@ -9780,7 +10162,7 @@ var SkillManifestStore = class {
|
|
|
9780
10162
|
return this.cache;
|
|
9781
10163
|
}
|
|
9782
10164
|
async write(data) {
|
|
9783
|
-
const dir =
|
|
10165
|
+
const dir = path24.dirname(this.manifestPath);
|
|
9784
10166
|
await fs14.mkdir(dir, { recursive: true });
|
|
9785
10167
|
await atomicWrite(this.manifestPath, JSON.stringify(data, null, 2) + "\n");
|
|
9786
10168
|
this.cache = data;
|
|
@@ -9818,6 +10200,10 @@ var SkillManifestStore = class {
|
|
|
9818
10200
|
};
|
|
9819
10201
|
|
|
9820
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
|
+
}
|
|
9821
10207
|
var MAX_SKILL_FILE_SIZE = SKILL_LIMITS.MAX_SKILL_FILE_SIZE;
|
|
9822
10208
|
var SkillInstaller = class {
|
|
9823
10209
|
opts;
|
|
@@ -9871,14 +10257,14 @@ var SkillInstaller = class {
|
|
|
9871
10257
|
this.opts.log?.(`Overwriting existing skill "${skill.name}" (${scope})...`);
|
|
9872
10258
|
await this.removeSkillFiles(skill.name, scope);
|
|
9873
10259
|
}
|
|
9874
|
-
const destDir =
|
|
10260
|
+
const destDir = path25.join(targetDir, skill.name);
|
|
9875
10261
|
await fs15.mkdir(destDir, { recursive: true });
|
|
9876
10262
|
const copiedFiles = [];
|
|
9877
10263
|
for (const file of skill.files) {
|
|
9878
|
-
const srcPath =
|
|
9879
|
-
const destPath =
|
|
9880
|
-
const resolved2 =
|
|
9881
|
-
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)) {
|
|
9882
10268
|
throw new FsError({
|
|
9883
10269
|
message: `Path traversal detected in skill file: ${file}`,
|
|
9884
10270
|
code: ERROR_CODES.FS_DELETE_FAILED,
|
|
@@ -9886,16 +10272,16 @@ var SkillInstaller = class {
|
|
|
9886
10272
|
context: { reason: "path_traversal", skillName: skill.name }
|
|
9887
10273
|
});
|
|
9888
10274
|
}
|
|
9889
|
-
const
|
|
9890
|
-
if (
|
|
10275
|
+
const stat7 = await fs15.stat(srcPath);
|
|
10276
|
+
if (stat7.size > MAX_SKILL_FILE_SIZE) {
|
|
9891
10277
|
throw new FsError({
|
|
9892
|
-
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`,
|
|
9893
10279
|
code: ERROR_CODES.FS_WRITE_FAILED,
|
|
9894
10280
|
path: srcPath,
|
|
9895
|
-
context: { skillName: skill.name, fileSize:
|
|
10281
|
+
context: { skillName: skill.name, fileSize: stat7.size, maxSize: MAX_SKILL_FILE_SIZE }
|
|
9896
10282
|
});
|
|
9897
10283
|
}
|
|
9898
|
-
await fs15.mkdir(
|
|
10284
|
+
await fs15.mkdir(path25.dirname(destPath), { recursive: true });
|
|
9899
10285
|
await fs15.copyFile(srcPath, destPath);
|
|
9900
10286
|
copiedFiles.push(file);
|
|
9901
10287
|
}
|
|
@@ -9953,7 +10339,7 @@ var SkillInstaller = class {
|
|
|
9953
10339
|
const results = [];
|
|
9954
10340
|
for (const e of entries) {
|
|
9955
10341
|
if (!await entryIsDirectory(srcDir, e)) continue;
|
|
9956
|
-
const skillMdPath =
|
|
10342
|
+
const skillMdPath = path25.join(srcDir, e.name, "SKILL.md");
|
|
9957
10343
|
let content;
|
|
9958
10344
|
try {
|
|
9959
10345
|
content = await fs15.readFile(skillMdPath, "utf8");
|
|
@@ -9966,16 +10352,16 @@ var SkillInstaller = class {
|
|
|
9966
10352
|
if (existing.find((x) => x.scope === scope)) {
|
|
9967
10353
|
await this.removeSkillFiles(fm.name, scope);
|
|
9968
10354
|
}
|
|
9969
|
-
const destDir =
|
|
10355
|
+
const destDir = path25.join(targetDir, fm.name);
|
|
9970
10356
|
await fs15.mkdir(destDir, { recursive: true });
|
|
9971
|
-
const srcSkillDir =
|
|
10357
|
+
const srcSkillDir = path25.join(srcDir, e.name);
|
|
9972
10358
|
const files = await collectFiles(srcSkillDir, srcSkillDir);
|
|
9973
10359
|
const copiedFiles = [];
|
|
9974
10360
|
for (const file of files) {
|
|
9975
|
-
const srcPath =
|
|
9976
|
-
const destPath =
|
|
9977
|
-
const resolved =
|
|
9978
|
-
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)) {
|
|
9979
10365
|
throw new FsError({
|
|
9980
10366
|
message: `Path traversal detected in skill file: ${file}`,
|
|
9981
10367
|
code: ERROR_CODES.FS_DELETE_FAILED,
|
|
@@ -9983,7 +10369,7 @@ var SkillInstaller = class {
|
|
|
9983
10369
|
context: { reason: "path_traversal", skillName: fm.name }
|
|
9984
10370
|
});
|
|
9985
10371
|
}
|
|
9986
|
-
await fs15.mkdir(
|
|
10372
|
+
await fs15.mkdir(path25.dirname(destPath), { recursive: true });
|
|
9987
10373
|
if (opts?.link) {
|
|
9988
10374
|
try {
|
|
9989
10375
|
await fs15.symlink(srcPath, destPath);
|
|
@@ -10146,7 +10532,7 @@ var SkillInstaller = class {
|
|
|
10146
10532
|
*/
|
|
10147
10533
|
async detectSkills(baseDir) {
|
|
10148
10534
|
const results = [];
|
|
10149
|
-
const rootSkillMd =
|
|
10535
|
+
const rootSkillMd = path25.join(baseDir, "SKILL.md");
|
|
10150
10536
|
try {
|
|
10151
10537
|
await fs15.access(rootSkillMd);
|
|
10152
10538
|
const content = await fs15.readFile(rootSkillMd, "utf8");
|
|
@@ -10161,17 +10547,17 @@ var SkillInstaller = class {
|
|
|
10161
10547
|
}
|
|
10162
10548
|
} catch {
|
|
10163
10549
|
}
|
|
10164
|
-
const skillsDir =
|
|
10550
|
+
const skillsDir = path25.join(baseDir, "skills");
|
|
10165
10551
|
try {
|
|
10166
10552
|
const entries = await fs15.readdir(skillsDir, { withFileTypes: true });
|
|
10167
10553
|
for (const entry of entries) {
|
|
10168
10554
|
if (!entry.isDirectory()) continue;
|
|
10169
|
-
const skillFile =
|
|
10555
|
+
const skillFile = path25.join(skillsDir, entry.name, "SKILL.md");
|
|
10170
10556
|
try {
|
|
10171
10557
|
const content = await fs15.readFile(skillFile, "utf8");
|
|
10172
10558
|
const fm = parseSkillFrontmatter(content);
|
|
10173
10559
|
if (fm.name && fm.description && isValidSkillNameFormat(fm.name)) {
|
|
10174
|
-
const skillDir =
|
|
10560
|
+
const skillDir = path25.join(skillsDir, entry.name);
|
|
10175
10561
|
const files = await collectFiles(skillDir, skillDir);
|
|
10176
10562
|
results.push({
|
|
10177
10563
|
name: fm.name,
|
|
@@ -10189,9 +10575,31 @@ var SkillInstaller = class {
|
|
|
10189
10575
|
/**
|
|
10190
10576
|
* Remove all files for an installed skill.
|
|
10191
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
|
+
*/
|
|
10192
10591
|
async removeSkillFiles(name, scope) {
|
|
10193
10592
|
const targetDir = scope === "project" ? this.opts.projectSkillsDir : this.opts.globalSkillsDir;
|
|
10194
|
-
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
|
+
}
|
|
10195
10603
|
await fs15.rm(skillDir, { recursive: true, force: true });
|
|
10196
10604
|
}
|
|
10197
10605
|
/**
|
|
@@ -10227,7 +10635,7 @@ async function entryIsDirectory(dir, entry) {
|
|
|
10227
10635
|
if (entry.isDirectory()) return true;
|
|
10228
10636
|
if (entry.isSymbolicLink()) {
|
|
10229
10637
|
try {
|
|
10230
|
-
return (await fs15.stat(
|
|
10638
|
+
return (await fs15.stat(path25.join(dir, entry.name))).isDirectory();
|
|
10231
10639
|
} catch {
|
|
10232
10640
|
return false;
|
|
10233
10641
|
}
|
|
@@ -10238,8 +10646,8 @@ async function collectFiles(dir, baseDir) {
|
|
|
10238
10646
|
const results = [];
|
|
10239
10647
|
const entries = await fs15.readdir(dir, { withFileTypes: true });
|
|
10240
10648
|
for (const entry of entries) {
|
|
10241
|
-
const fullPath =
|
|
10242
|
-
const relPath =
|
|
10649
|
+
const fullPath = path25.join(dir, entry.name);
|
|
10650
|
+
const relPath = path25.relative(baseDir, fullPath);
|
|
10243
10651
|
if (entry.isDirectory()) {
|
|
10244
10652
|
if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
|
|
10245
10653
|
results.push(...await collectFiles(fullPath, baseDir));
|
|
@@ -10318,7 +10726,7 @@ function createSkillsPlugin(opts) {
|
|
|
10318
10726
|
function makeInstaller(skillLoader, projectRoot, registryAdapters) {
|
|
10319
10727
|
const paths = resolveWstackPaths({ projectRoot });
|
|
10320
10728
|
return new SkillInstaller({
|
|
10321
|
-
manifestPath:
|
|
10729
|
+
manifestPath: path26.join(paths.configDir, "installed-skills.json"),
|
|
10322
10730
|
projectSkillsDir: paths.inProjectSkills,
|
|
10323
10731
|
globalSkillsDir: paths.globalSkills,
|
|
10324
10732
|
projectHash: paths.projectHash,
|
|
@@ -10346,7 +10754,8 @@ ${lines.join("\n\n")}
|
|
|
10346
10754
|
}
|
|
10347
10755
|
const skill = await skillLoader.find(args.trim());
|
|
10348
10756
|
if (!skill) return { message: `Skill "${args.trim()}" not found.` };
|
|
10349
|
-
|
|
10757
|
+
const body = capSkillBody(stripFrontmatter(await skillLoader.readBody(skill.name)));
|
|
10758
|
+
return { message: body };
|
|
10350
10759
|
}
|
|
10351
10760
|
};
|
|
10352
10761
|
}
|
|
@@ -10385,9 +10794,32 @@ function buildSkillGeneratorCommand(skillLoader) {
|
|
|
10385
10794
|
return ` ${src} ${e.name}
|
|
10386
10795
|
${e.trigger}`;
|
|
10387
10796
|
});
|
|
10388
|
-
|
|
10797
|
+
let message = `Available Skills:
|
|
10389
10798
|
${lines.join("\n\n")}
|
|
10390
|
-
|
|
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 };
|
|
10391
10823
|
}
|
|
10392
10824
|
if (sub === "validate") {
|
|
10393
10825
|
const name = rest[0];
|
|
@@ -10444,7 +10876,10 @@ ${lines.join("\n\n")}
|
|
|
10444
10876
|
if (!skill) return { message: `Skill "${skillName}" not found.` };
|
|
10445
10877
|
try {
|
|
10446
10878
|
await openInEditor(skill.path);
|
|
10447
|
-
|
|
10879
|
+
skillLoader.invalidateCache();
|
|
10880
|
+
return {
|
|
10881
|
+
message: `Opening ${skill.path} in your editor\u2026 (skill cache cleared \u2014 changes load on next use)`
|
|
10882
|
+
};
|
|
10448
10883
|
} catch (err) {
|
|
10449
10884
|
return { message: `\u2717 ${toErrorMessage(err)}` };
|
|
10450
10885
|
}
|
|
@@ -10670,7 +11105,7 @@ function resolveImportSourceDir(tool, opts) {
|
|
|
10670
11105
|
const entry = IMPORT_SOURCE_TOOLS.find((t) => t.id === tool);
|
|
10671
11106
|
if (!entry) return void 0;
|
|
10672
11107
|
const base = opts.global ? opts.homeDir ?? os7.homedir() : opts.projectRoot;
|
|
10673
|
-
return
|
|
11108
|
+
return path26.join(base, "." + entry.id, entry.subdir);
|
|
10674
11109
|
}
|
|
10675
11110
|
function buildSkillImportCommand(skillLoader) {
|
|
10676
11111
|
return {
|
|
@@ -10711,7 +11146,7 @@ function buildSkillImportCommand(skillLoader) {
|
|
|
10711
11146
|
};
|
|
10712
11147
|
}
|
|
10713
11148
|
} else if (positional) {
|
|
10714
|
-
srcDir =
|
|
11149
|
+
srcDir = path26.resolve(ctx.projectRoot, positional);
|
|
10715
11150
|
} else {
|
|
10716
11151
|
return {
|
|
10717
11152
|
message: "Usage: /skill-import <src-dir> | --from <tool> | --from-claude [--global] [--link]"
|
|
@@ -10838,14 +11273,14 @@ function truncate(s, max) {
|
|
|
10838
11273
|
}
|
|
10839
11274
|
|
|
10840
11275
|
// src/plugins/sync-plugin.ts
|
|
10841
|
-
import * as
|
|
11276
|
+
import * as path28 from "node:path";
|
|
10842
11277
|
init_error();
|
|
10843
11278
|
|
|
10844
11279
|
// src/storage/cloud-sync.ts
|
|
10845
11280
|
init_atomic_write();
|
|
10846
11281
|
init_errors();
|
|
10847
11282
|
import * as fs16 from "node:fs/promises";
|
|
10848
|
-
import * as
|
|
11283
|
+
import * as path27 from "node:path";
|
|
10849
11284
|
import { createHash as createHash9 } from "node:crypto";
|
|
10850
11285
|
var ALL_SYNC_CATEGORIES = ["settings", "skills", "prompts", "memory", "history"];
|
|
10851
11286
|
var CloudSync = class {
|
|
@@ -10853,8 +11288,8 @@ var CloudSync = class {
|
|
|
10853
11288
|
this.paths = paths;
|
|
10854
11289
|
this.getConfig = getConfig;
|
|
10855
11290
|
this.setConfig = setConfig;
|
|
10856
|
-
this.statePath =
|
|
10857
|
-
this.getSettingsConfigPath = getSettingsConfigPath ?? (() =>
|
|
11291
|
+
this.statePath = path27.join(paths.configDir, "sync-state.json");
|
|
11292
|
+
this.getSettingsConfigPath = getSettingsConfigPath ?? (() => path27.join(this.paths.configDir, "config.json"));
|
|
10858
11293
|
}
|
|
10859
11294
|
paths;
|
|
10860
11295
|
getConfig;
|
|
@@ -11134,13 +11569,13 @@ var CloudSync = class {
|
|
|
11134
11569
|
const localPath = this.categoryToPath(cat);
|
|
11135
11570
|
if (!localPath) continue;
|
|
11136
11571
|
try {
|
|
11137
|
-
const
|
|
11138
|
-
if (
|
|
11139
|
-
if (
|
|
11572
|
+
const stat7 = await fs16.lstat(localPath);
|
|
11573
|
+
if (stat7.isSymbolicLink()) continue;
|
|
11574
|
+
if (stat7.isDirectory()) {
|
|
11140
11575
|
const files = await this.walkDir(localPath, localPath);
|
|
11141
11576
|
for (const file of files) {
|
|
11142
11577
|
const content = await fs16.readFile(file, "utf8");
|
|
11143
|
-
const rel =
|
|
11578
|
+
const rel = path27.relative(localPath, file).replace(/\\/g, "/");
|
|
11144
11579
|
entries.push({ path: `data/${cat}/${rel}`, content, mode: "100644" });
|
|
11145
11580
|
hashes.push(`${cat}/${rel}\0${content}`);
|
|
11146
11581
|
}
|
|
@@ -11161,13 +11596,13 @@ var CloudSync = class {
|
|
|
11161
11596
|
const localPath = this.categoryToPath(cat);
|
|
11162
11597
|
if (!localPath) continue;
|
|
11163
11598
|
try {
|
|
11164
|
-
const
|
|
11165
|
-
if (
|
|
11166
|
-
if (
|
|
11599
|
+
const stat7 = await fs16.lstat(localPath);
|
|
11600
|
+
if (stat7.isSymbolicLink()) continue;
|
|
11601
|
+
if (stat7.isDirectory()) {
|
|
11167
11602
|
const files = await this.walkDir(localPath, localPath);
|
|
11168
11603
|
for (const file of files) {
|
|
11169
11604
|
const content = await fs16.readFile(file, "utf8");
|
|
11170
|
-
const rel =
|
|
11605
|
+
const rel = path27.relative(localPath, file).replace(/\\/g, "/");
|
|
11171
11606
|
hashes.push(`${cat}/${rel}\0${content}`);
|
|
11172
11607
|
}
|
|
11173
11608
|
} else {
|
|
@@ -11201,7 +11636,7 @@ var CloudSync = class {
|
|
|
11201
11636
|
const entries = await fs16.readdir(dir, { withFileTypes: true });
|
|
11202
11637
|
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
11203
11638
|
for (const entry of entries) {
|
|
11204
|
-
const full =
|
|
11639
|
+
const full = path27.join(dir, entry.name);
|
|
11205
11640
|
if (entry.isSymbolicLink()) continue;
|
|
11206
11641
|
if (entry.isDirectory()) {
|
|
11207
11642
|
results.push(...await this.walkDir(full, base));
|
|
@@ -11214,25 +11649,25 @@ var CloudSync = class {
|
|
|
11214
11649
|
};
|
|
11215
11650
|
async function preparePulledDestination(cat, localPath, destPath, remotePath) {
|
|
11216
11651
|
const directoryBacked = cat === "skills" || cat === "prompts";
|
|
11217
|
-
const rootPath = directoryBacked ? localPath :
|
|
11652
|
+
const rootPath = directoryBacked ? localPath : path27.dirname(localPath);
|
|
11218
11653
|
const rootStat = await lstatIfExists(rootPath);
|
|
11219
11654
|
if (rootStat?.isSymbolicLink()) {
|
|
11220
11655
|
throw unsafePulledSymlinkError(remotePath, rootPath);
|
|
11221
11656
|
}
|
|
11222
11657
|
if (directoryBacked) {
|
|
11223
|
-
const relativeParent =
|
|
11658
|
+
const relativeParent = path27.relative(rootPath, path27.dirname(destPath));
|
|
11224
11659
|
let cursor = rootPath;
|
|
11225
11660
|
if (relativeParent) {
|
|
11226
|
-
for (const segment of relativeParent.split(
|
|
11227
|
-
cursor =
|
|
11228
|
-
const
|
|
11229
|
-
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);
|
|
11230
11665
|
}
|
|
11231
11666
|
}
|
|
11232
11667
|
}
|
|
11233
11668
|
const destStat = await lstatIfExists(destPath);
|
|
11234
11669
|
if (destStat?.isSymbolicLink()) throw unsafePulledSymlinkError(remotePath, destPath);
|
|
11235
|
-
await fs16.mkdir(
|
|
11670
|
+
await fs16.mkdir(path27.dirname(destPath), { recursive: true });
|
|
11236
11671
|
}
|
|
11237
11672
|
async function lstatIfExists(filePath) {
|
|
11238
11673
|
try {
|
|
@@ -11262,9 +11697,9 @@ function resolvePulledCategoryPath(cat, localPath, rel, remotePath) {
|
|
|
11262
11697
|
return localPath;
|
|
11263
11698
|
}
|
|
11264
11699
|
if (!rel) return localPath;
|
|
11265
|
-
const normalizedRel =
|
|
11266
|
-
const traversesUp = normalizedRel === ".." || normalizedRel.startsWith(`..${
|
|
11267
|
-
if (
|
|
11700
|
+
const normalizedRel = path27.normalize(rel);
|
|
11701
|
+
const traversesUp = normalizedRel === ".." || normalizedRel.startsWith(`..${path27.sep}`);
|
|
11702
|
+
if (path27.isAbsolute(normalizedRel) || traversesUp) {
|
|
11268
11703
|
throw new FsError({
|
|
11269
11704
|
message: `Refusing CloudSync path traversal: ${remotePath}`,
|
|
11270
11705
|
code: ERROR_CODES.FS_DELETE_FAILED,
|
|
@@ -11272,10 +11707,10 @@ function resolvePulledCategoryPath(cat, localPath, rel, remotePath) {
|
|
|
11272
11707
|
context: { reason: "path_traversal", normalizedRel }
|
|
11273
11708
|
});
|
|
11274
11709
|
}
|
|
11275
|
-
const dest =
|
|
11276
|
-
const root =
|
|
11277
|
-
const relative5 =
|
|
11278
|
-
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)) {
|
|
11279
11714
|
throw new FsError({
|
|
11280
11715
|
message: `Refusing CloudSync path outside category root: ${remotePath}`,
|
|
11281
11716
|
code: ERROR_CODES.FS_DELETE_FAILED,
|
|
@@ -11318,7 +11753,7 @@ function createSyncPlugin(opts) {
|
|
|
11318
11753
|
api.log.warn("[sync] paths, configStore, or configDir not available \u2014 /sync disabled");
|
|
11319
11754
|
return;
|
|
11320
11755
|
}
|
|
11321
|
-
const syncConfigPath = paths.syncConfig ??
|
|
11756
|
+
const syncConfigPath = paths.syncConfig ?? path28.join(paths.configDir, "sync.json");
|
|
11322
11757
|
cloud = new CloudSync(
|
|
11323
11758
|
paths,
|
|
11324
11759
|
() => {
|
|
@@ -11329,7 +11764,7 @@ function createSyncPlugin(opts) {
|
|
|
11329
11764
|
await persistSyncConfig(syncConfigPath, cfg, vault);
|
|
11330
11765
|
configStore?.update({ sync: cfg });
|
|
11331
11766
|
},
|
|
11332
|
-
() =>
|
|
11767
|
+
() => path28.join(paths.configDir, "config.json")
|
|
11333
11768
|
);
|
|
11334
11769
|
void cloud.loadState();
|
|
11335
11770
|
api.slashCommands.register(buildSyncCommand(cloud, configStore, vault, syncConfigPath));
|
|
@@ -11532,8 +11967,14 @@ export {
|
|
|
11532
11967
|
definePlugin,
|
|
11533
11968
|
diffPluginConfig,
|
|
11534
11969
|
emitReviewIfChanged,
|
|
11970
|
+
integrateFindings,
|
|
11535
11971
|
loadPlugins,
|
|
11972
|
+
maybeCompactReviewStores,
|
|
11973
|
+
parseChimeraReviewReport,
|
|
11536
11974
|
parseReviewSeverity,
|
|
11975
|
+
persistReviewReport,
|
|
11976
|
+
recordCompletedReview,
|
|
11977
|
+
recordStartedReview,
|
|
11537
11978
|
redactPluginConfig,
|
|
11538
11979
|
resolvePluginConfig,
|
|
11539
11980
|
resolvePluginManifestConfig,
|