session-orchestrator 3.16.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/.claude-plugin/marketplace.json +29 -0
- package/.claude-plugin/plugin.json +18 -0
- package/.codex-plugin/agents/explorer.toml +14 -0
- package/.codex-plugin/agents/session-reviewer.toml +23 -0
- package/.codex-plugin/agents/wave-worker.toml +15 -0
- package/.codex-plugin/config.toml +20 -0
- package/.codex-plugin/plugin.json +37 -0
- package/.cursor/rules/000-session-orchestrator.mdc +73 -0
- package/.cursor/rules/010-session-workflow.mdc +170 -0
- package/.cursor/rules/020-quality-gates.mdc +128 -0
- package/.cursor/rules/030-wave-execution.mdc +216 -0
- package/.cursor/rules/040-discovery.mdc +242 -0
- package/.cursor/rules/050-plan.mdc +235 -0
- package/.cursor/rules/060-evolve.mdc +232 -0
- package/.cursor/rules/070-gitlab-ops.mdc +246 -0
- package/.cursor/rules/080-ecosystem-health.mdc +145 -0
- package/.mcp.json +8 -0
- package/CHANGELOG.md +1544 -0
- package/LICENSE +21 -0
- package/NOTICE +64 -0
- package/README.md +242 -0
- package/SECURITY.md +90 -0
- package/agents/AGENTS.md +136 -0
- package/agents/analyst.md +99 -0
- package/agents/architect-reviewer.md +93 -0
- package/agents/code-implementer.md +106 -0
- package/agents/db-specialist.md +104 -0
- package/agents/dialectic-deriver.md +139 -0
- package/agents/docs-writer.md +113 -0
- package/agents/eval-judge.md +146 -0
- package/agents/memory-proposal-collector.md +297 -0
- package/agents/qa-strategist.md +102 -0
- package/agents/schemas/analyst.schema.json +46 -0
- package/agents/schemas/architect-reviewer.schema.json +50 -0
- package/agents/schemas/code-implementer.schema.json +61 -0
- package/agents/schemas/db-specialist.schema.json +80 -0
- package/agents/schemas/docs-writer.schema.json +56 -0
- package/agents/schemas/persona-panel-sidecar.schema.json +245 -0
- package/agents/schemas/qa-strategist.schema.json +46 -0
- package/agents/schemas/security-reviewer.schema.json +86 -0
- package/agents/schemas/session-reviewer.schema.json +69 -0
- package/agents/schemas/test-writer.schema.json +69 -0
- package/agents/schemas/ui-developer.schema.json +90 -0
- package/agents/schemas/ux-evaluator.schema.json +51 -0
- package/agents/security-reviewer.md +236 -0
- package/agents/session-reviewer.md +201 -0
- package/agents/skill-applied-judge.md +122 -0
- package/agents/test-writer.md +123 -0
- package/agents/ui-developer.md +109 -0
- package/agents/ux-evaluator.md +161 -0
- package/assets/icon.svg +11 -0
- package/assets/og-card.png +0 -0
- package/assets/og-card.svg +47 -0
- package/commands/autopilot-multi.md +74 -0
- package/commands/autopilot.md +80 -0
- package/commands/bootstrap.md +56 -0
- package/commands/brainstorm.md +48 -0
- package/commands/close.md +24 -0
- package/commands/debug.md +36 -0
- package/commands/discovery.md +32 -0
- package/commands/dispatcher.md +59 -0
- package/commands/eval.md +28 -0
- package/commands/evolve.md +10 -0
- package/commands/go.md +41 -0
- package/commands/grill.md +45 -0
- package/commands/harness-audit.md +26 -0
- package/commands/memory-cleanup.md +25 -0
- package/commands/persona-panel.md +121 -0
- package/commands/plan.md +15 -0
- package/commands/portfolio.md +97 -0
- package/commands/reconcile.md +23 -0
- package/commands/repo-audit.md +24 -0
- package/commands/session.md +30 -0
- package/commands/spinout.md +15 -0
- package/commands/sunset-review.md +27 -0
- package/commands/templates-ack.md +96 -0
- package/commands/test.md +97 -0
- package/docs/README.md +105 -0
- package/docs/USER-GUIDE.md +1403 -0
- package/docs/ci-setup.md +81 -0
- package/docs/codex-setup.md +142 -0
- package/docs/components.md +74 -0
- package/docs/cursor-setup.md +104 -0
- package/docs/events-schema.md +81 -0
- package/docs/migration-v3.md +148 -0
- package/docs/owner-config-schema.md +154 -0
- package/docs/persona-panel.md +433 -0
- package/docs/pi-setup.md +115 -0
- package/docs/plugin-architecture-v3.md +296 -0
- package/docs/pm-skills-marketplace.md +114 -0
- package/docs/policy-cache-validation-2026-04-28.md +118 -0
- package/docs/rule-authoring.md +316 -0
- package/docs/session-config-reference.md +1439 -0
- package/docs/session-config-template.md +961 -0
- package/docs/vault-docs-architecture.md +297 -0
- package/hooks/_lib/lock-bootstrap.mjs +272 -0
- package/hooks/_lib/lock-reconcile.mjs +93 -0
- package/hooks/_lib/profile-gate.mjs +95 -0
- package/hooks/_lib/transcript-history.mjs +211 -0
- package/hooks/agent-teams-h3-test.sh +362 -0
- package/hooks/config-protection.mjs +0 -0
- package/hooks/cwd-change-restore.mjs +131 -0
- package/hooks/enforce-commands.mjs +179 -0
- package/hooks/enforce-scope.mjs +273 -0
- package/hooks/hooks-codex.json +60 -0
- package/hooks/hooks-cursor.json +15 -0
- package/hooks/hooks-pi.json +115 -0
- package/hooks/hooks.json +215 -0
- package/hooks/loop-guard.mjs +260 -0
- package/hooks/on-session-end.mjs +217 -0
- package/hooks/on-session-start.mjs +660 -0
- package/hooks/on-stop.mjs +294 -0
- package/hooks/operator-steer.mjs +64 -0
- package/hooks/post-edit-validate.mjs +225 -0
- package/hooks/post-subagent-discovery-validator.mjs +398 -0
- package/hooks/post-tool-batch-wave-signal.mjs +328 -0
- package/hooks/post-tool-failure-corrective-context.mjs +248 -0
- package/hooks/post-tooluse-frontend-slop.mjs +184 -0
- package/hooks/pre-bash-destructive-guard.mjs +515 -0
- package/hooks/pre-bash-memory-propose-audit.mjs +206 -0
- package/hooks/pre-bash-staging-fence.mjs +223 -0
- package/hooks/pre-bash-templates-first.mjs +404 -0
- package/hooks/run-node.sh +72 -0
- package/hooks/skill-invocation-telemetry.mjs +99 -0
- package/hooks/subagent-telemetry.mjs +249 -0
- package/hooks/wave-scope-commit-guard.mjs +191 -0
- package/monitors/monitors.json +14 -0
- package/output-styles/finding-report.md +48 -0
- package/output-styles/session-report.md +53 -0
- package/output-styles/wave-summary.md +38 -0
- package/package.json +94 -0
- package/pi/extensions/session-orchestrator.ts +25 -0
- package/pi/prompts/autopilot-multi.md +12 -0
- package/pi/prompts/autopilot.md +12 -0
- package/pi/prompts/bootstrap.md +12 -0
- package/pi/prompts/brainstorm.md +12 -0
- package/pi/prompts/close.md +11 -0
- package/pi/prompts/debug.md +12 -0
- package/pi/prompts/discovery.md +12 -0
- package/pi/prompts/dispatcher.md +12 -0
- package/pi/prompts/eval.md +12 -0
- package/pi/prompts/evolve.md +12 -0
- package/pi/prompts/go.md +12 -0
- package/pi/prompts/grill.md +12 -0
- package/pi/prompts/harness-audit.md +12 -0
- package/pi/prompts/memory-cleanup.md +12 -0
- package/pi/prompts/persona-panel.md +12 -0
- package/pi/prompts/plan.md +12 -0
- package/pi/prompts/portfolio.md +12 -0
- package/pi/prompts/reconcile.md +12 -0
- package/pi/prompts/repo-audit.md +12 -0
- package/pi/prompts/session.md +12 -0
- package/pi/prompts/spinout.md +12 -0
- package/pi/prompts/sunset-review.md +12 -0
- package/pi/prompts/templates-ack.md +12 -0
- package/pi/prompts/test.md +12 -0
- package/rules/_index.md +51 -0
- package/rules/always-on/commit-discipline.md +26 -0
- package/rules/always-on/npm-quality-gates.md +26 -0
- package/rules/always-on/parallel-sessions.md +43 -0
- package/rules/opt-in-domain/prompt-caching.md +270 -0
- package/rules/opt-in-stack/backend-data.md +188 -0
- package/rules/opt-in-stack/backend.md +390 -0
- package/rules/opt-in-stack/frontend.md +98 -0
- package/rules/opt-in-stack/security-web.md +194 -0
- package/rules/opt-in-stack/swift.md +65 -0
- package/scripts/archive-closed-prds.mjs +416 -0
- package/scripts/autopilot-multi.mjs +802 -0
- package/scripts/autopilot.mjs +383 -0
- package/scripts/backfill-abandoned-sessions.mjs +265 -0
- package/scripts/backfill-learnings-expires.mjs +196 -0
- package/scripts/backfill-learnings.mjs +203 -0
- package/scripts/backfill-sessions.mjs +282 -0
- package/scripts/check-doc-consistency.sh +279 -0
- package/scripts/check-package-manager.mjs +445 -0
- package/scripts/ci/assert-vitest-green.mjs +267 -0
- package/scripts/codex-install.mjs +435 -0
- package/scripts/compute-grounding-injection.sh +186 -0
- package/scripts/cursor-install.mjs +113 -0
- package/scripts/dialectic-deriver.mjs +573 -0
- package/scripts/emit-event.mjs +160 -0
- package/scripts/emit-session.mjs +212 -0
- package/scripts/eval-session.mjs +262 -0
- package/scripts/export-hw-learnings.mjs +437 -0
- package/scripts/gc-stale-worktrees.mjs +666 -0
- package/scripts/generate-pi-prompts.mjs +127 -0
- package/scripts/harness-audit.mjs +287 -0
- package/scripts/lib/agent-frontmatter.mjs +266 -0
- package/scripts/lib/agent-output-schema.mjs +166 -0
- package/scripts/lib/agent-status.mjs +303 -0
- package/scripts/lib/ajv-loader.mjs +34 -0
- package/scripts/lib/auto-dialectic.mjs +382 -0
- package/scripts/lib/auto-dream.mjs +471 -0
- package/scripts/lib/autonomy/suitability.mjs +212 -0
- package/scripts/lib/autopilot/dep-graph.mjs +417 -0
- package/scripts/lib/autopilot/durable-telemetry.mjs +121 -0
- package/scripts/lib/autopilot/flags.mjs +104 -0
- package/scripts/lib/autopilot/kill-switches.mjs +174 -0
- package/scripts/lib/autopilot/loop.mjs +320 -0
- package/scripts/lib/autopilot/mr-draft.mjs +520 -0
- package/scripts/lib/autopilot/multi-killswitch.mjs +184 -0
- package/scripts/lib/autopilot/recent-runs.mjs +106 -0
- package/scripts/lib/autopilot/stall-sampler.mjs +97 -0
- package/scripts/lib/autopilot/telemetry.mjs +224 -0
- package/scripts/lib/autopilot/worktree-pipeline.mjs +605 -0
- package/scripts/lib/autopilot-telemetry.mjs +11 -0
- package/scripts/lib/autopilot.mjs +39 -0
- package/scripts/lib/backlog-scan.mjs +179 -0
- package/scripts/lib/bootstrap-lock-freshness.mjs +260 -0
- package/scripts/lib/bootstrap-lock-refresh.mjs +186 -0
- package/scripts/lib/build-live-signals.mjs +150 -0
- package/scripts/lib/ci-status-banner.mjs +425 -0
- package/scripts/lib/claude-md-budget-lint.mjs +246 -0
- package/scripts/lib/cli-flags.mjs +158 -0
- package/scripts/lib/codex/plugin-contract.mjs +610 -0
- package/scripts/lib/cold-start-detector.mjs +240 -0
- package/scripts/lib/command-blocker.mjs +458 -0
- package/scripts/lib/common.mjs +333 -0
- package/scripts/lib/config/auto-dream.mjs +77 -0
- package/scripts/lib/config/block-header.mjs +94 -0
- package/scripts/lib/config/broken-window.mjs +114 -0
- package/scripts/lib/config/coercers.mjs +248 -0
- package/scripts/lib/config/cold-start.mjs +92 -0
- package/scripts/lib/config/config-protection.mjs +120 -0
- package/scripts/lib/config/cross-repo.mjs +104 -0
- package/scripts/lib/config/custom-phases.mjs +213 -0
- package/scripts/lib/config/dialectic.mjs +92 -0
- package/scripts/lib/config/discovery-validator.mjs +75 -0
- package/scripts/lib/config/dispatcher-autonomy-capture.mjs +240 -0
- package/scripts/lib/config/dispatcher-autonomy.mjs +152 -0
- package/scripts/lib/config/docs-orchestrator.mjs +90 -0
- package/scripts/lib/config/docs-staleness.mjs +96 -0
- package/scripts/lib/config/drift-check.mjs +155 -0
- package/scripts/lib/config/eval.mjs +130 -0
- package/scripts/lib/config/events-rotation.mjs +74 -0
- package/scripts/lib/config/evolve.mjs +308 -0
- package/scripts/lib/config/frontend-slop-hook.mjs +104 -0
- package/scripts/lib/config/gitlab-portfolio.mjs +150 -0
- package/scripts/lib/config/handover-gate.mjs +106 -0
- package/scripts/lib/config/host-paths.mjs +76 -0
- package/scripts/lib/config/io.mjs +54 -0
- package/scripts/lib/config/loop-guard.mjs +117 -0
- package/scripts/lib/config/memory.mjs +150 -0
- package/scripts/lib/config/persona-gate-wave.mjs +258 -0
- package/scripts/lib/config/reconcile.mjs +205 -0
- package/scripts/lib/config/section-extractor.mjs +100 -0
- package/scripts/lib/config/skill-evolution.mjs +112 -0
- package/scripts/lib/config/slopcheck.mjs +99 -0
- package/scripts/lib/config/state-md-lock.mjs +83 -0
- package/scripts/lib/config/templates-first.mjs +94 -0
- package/scripts/lib/config/test.mjs +113 -0
- package/scripts/lib/config/vault-integration.mjs +201 -0
- package/scripts/lib/config/vault-mirror-quality.mjs +99 -0
- package/scripts/lib/config/vault-staleness.mjs +84 -0
- package/scripts/lib/config/vault-sync.mjs +96 -0
- package/scripts/lib/config/verification-auto-fix.mjs +84 -0
- package/scripts/lib/config/wave-reviewers.mjs +133 -0
- package/scripts/lib/config-schema.mjs +345 -0
- package/scripts/lib/config.mjs +474 -0
- package/scripts/lib/convergence-monitor.mjs +389 -0
- package/scripts/lib/coordinator-snapshot.mjs +371 -0
- package/scripts/lib/crypto-digest-utils.mjs +91 -0
- package/scripts/lib/discovery/helpers.mjs +127 -0
- package/scripts/lib/discovery/triage-state.mjs +279 -0
- package/scripts/lib/dispatcher/cli.mjs +257 -0
- package/scripts/lib/dispatcher/enumerate.mjs +243 -0
- package/scripts/lib/dispatcher/rank.mjs +363 -0
- package/scripts/lib/ecosystem-health.mjs +224 -0
- package/scripts/lib/ecosystem-wizard/ci-detector.mjs +18 -0
- package/scripts/lib/ecosystem-wizard/config-parser.mjs +54 -0
- package/scripts/lib/ecosystem-wizard/config-writer.mjs +287 -0
- package/scripts/lib/ecosystem-wizard/package-manager-detector.mjs +42 -0
- package/scripts/lib/ecosystem-wizard/wizard-prompt.mjs +246 -0
- package/scripts/lib/ecosystem-wizard.mjs +48 -0
- package/scripts/lib/env-check.mjs +89 -0
- package/scripts/lib/eval/engine.mjs +605 -0
- package/scripts/lib/eval/judge.mjs +433 -0
- package/scripts/lib/eval/report.mjs +367 -0
- package/scripts/lib/eval/schema.mjs +618 -0
- package/scripts/lib/eval/session-resolve.mjs +137 -0
- package/scripts/lib/eval/sink.mjs +77 -0
- package/scripts/lib/events-rotation.mjs +86 -0
- package/scripts/lib/events-schema.mjs +81 -0
- package/scripts/lib/events.mjs +80 -0
- package/scripts/lib/evolve/autonomy-verdict.mjs +461 -0
- package/scripts/lib/evolve/autopilot-effectiveness.mjs +293 -0
- package/scripts/lib/exclusivity-matrix.mjs +68 -0
- package/scripts/lib/fetch-baseline.mjs +311 -0
- package/scripts/lib/file-lock.mjs +512 -0
- package/scripts/lib/frontend-detect/detect.mjs +138 -0
- package/scripts/lib/frontend-detect/rules.mjs +295 -0
- package/scripts/lib/frontmatter-guard.mjs +241 -0
- package/scripts/lib/gates/echo-stub-detect.mjs +39 -0
- package/scripts/lib/gates/gate-baseline.mjs +42 -0
- package/scripts/lib/gates/gate-full.mjs +85 -0
- package/scripts/lib/gates/gate-helpers.mjs +231 -0
- package/scripts/lib/gates/gate-incremental.mjs +76 -0
- package/scripts/lib/gates/gate-per-file.mjs +55 -0
- package/scripts/lib/gitlab-ops/stale-mr-sweep.mjs +447 -0
- package/scripts/lib/gitlab-portfolio/aggregator.mjs +383 -0
- package/scripts/lib/gitlab-portfolio/cli.mjs +428 -0
- package/scripts/lib/gitlab-portfolio/markdown-writer.mjs +289 -0
- package/scripts/lib/gitlab-portfolio/vcs-detect.mjs +182 -0
- package/scripts/lib/handover-gate.mjs +222 -0
- package/scripts/lib/hardening.mjs +43 -0
- package/scripts/lib/hardware-pattern-detector.mjs +238 -0
- package/scripts/lib/harness-audit/categories/category1.mjs +123 -0
- package/scripts/lib/harness-audit/categories/category2.mjs +145 -0
- package/scripts/lib/harness-audit/categories/category3.mjs +143 -0
- package/scripts/lib/harness-audit/categories/category4.mjs +202 -0
- package/scripts/lib/harness-audit/categories/category5.mjs +152 -0
- package/scripts/lib/harness-audit/categories/category6.mjs +211 -0
- package/scripts/lib/harness-audit/categories/category7.mjs +125 -0
- package/scripts/lib/harness-audit/categories/category8.mjs +328 -0
- package/scripts/lib/harness-audit/categories/category9.mjs +294 -0
- package/scripts/lib/harness-audit/categories/helpers.mjs +165 -0
- package/scripts/lib/harness-audit/categories.mjs +19 -0
- package/scripts/lib/historical-guard.mjs +15 -0
- package/scripts/lib/host-identity.mjs +262 -0
- package/scripts/lib/instruction-budget-guard.mjs +332 -0
- package/scripts/lib/io.mjs +304 -0
- package/scripts/lib/issue-close-strip-labels.mjs +161 -0
- package/scripts/lib/language-mappers/README.md +57 -0
- package/scripts/lib/language-mappers/index.mjs +165 -0
- package/scripts/lib/language-mappers/markdown.mjs +149 -0
- package/scripts/lib/language-mappers/python.mjs +249 -0
- package/scripts/lib/language-mappers/swift.mjs +201 -0
- package/scripts/lib/language-mappers/typescript.mjs +433 -0
- package/scripts/lib/learnings/expiry-sweep.mjs +164 -0
- package/scripts/lib/learnings/filters.mjs +43 -0
- package/scripts/lib/learnings/io.mjs +255 -0
- package/scripts/lib/learnings/schema.mjs +518 -0
- package/scripts/lib/learnings/surface.mjs +207 -0
- package/scripts/lib/learnings.mjs +42 -0
- package/scripts/lib/lock-reaper.mjs +648 -0
- package/scripts/lib/locks/index.mjs +31 -0
- package/scripts/lib/locks/lock-body.mjs +62 -0
- package/scripts/lib/locks/staging-fence-lock.mjs +267 -0
- package/scripts/lib/locks/state-md-lock.mjs +351 -0
- package/scripts/lib/loop-readiness-banner.mjs +144 -0
- package/scripts/lib/memory-banner.mjs +478 -0
- package/scripts/lib/memory-cleanup/worktree-sweep.mjs +108 -0
- package/scripts/lib/memory-cleanup-stamp.mjs +56 -0
- package/scripts/lib/memory-paths.mjs +31 -0
- package/scripts/lib/memory-proposals/collector.mjs +334 -0
- package/scripts/lib/memory-proposals/schema.mjs +289 -0
- package/scripts/lib/memory-proposals/sink.mjs +507 -0
- package/scripts/lib/memory-proposals/store.mjs +441 -0
- package/scripts/lib/mission-status-schema.mjs +114 -0
- package/scripts/lib/mode-selector/alternatives.mjs +64 -0
- package/scripts/lib/mode-selector/constants.mjs +29 -0
- package/scripts/lib/mode-selector/context-pressure.mjs +157 -0
- package/scripts/lib/mode-selector/rationale.mjs +55 -0
- package/scripts/lib/mode-selector/scoring.mjs +221 -0
- package/scripts/lib/mode-selector-accuracy.mjs +121 -0
- package/scripts/lib/mode-selector.mjs +160 -0
- package/scripts/lib/multi-provider-build/providers.mjs +64 -0
- package/scripts/lib/multi-provider-build/templating.mjs +130 -0
- package/scripts/lib/named-baseline-resolver.mjs +233 -0
- package/scripts/lib/named-vault-resolver.mjs +433 -0
- package/scripts/lib/owner-config/coerce.mjs +29 -0
- package/scripts/lib/owner-config/constants.mjs +21 -0
- package/scripts/lib/owner-config/defaults.mjs +50 -0
- package/scripts/lib/owner-config/error.mjs +19 -0
- package/scripts/lib/owner-config/index.mjs +13 -0
- package/scripts/lib/owner-config/merge.mjs +52 -0
- package/scripts/lib/owner-config/validate.mjs +259 -0
- package/scripts/lib/owner-config-banner.mjs +126 -0
- package/scripts/lib/owner-config-loader.mjs +159 -0
- package/scripts/lib/owner-config.example.yaml +72 -0
- package/scripts/lib/owner-config.mjs +28 -0
- package/scripts/lib/owner-interview.mjs +243 -0
- package/scripts/lib/owner-yaml.mjs +571 -0
- package/scripts/lib/package-manager.mjs +160 -0
- package/scripts/lib/path-utils.mjs +217 -0
- package/scripts/lib/peer-cards/merger.mjs +310 -0
- package/scripts/lib/peer-cards/reader.mjs +125 -0
- package/scripts/lib/peer-cards/schema.mjs +230 -0
- package/scripts/lib/peer-cards/staleness-banner.mjs +86 -0
- package/scripts/lib/peer-cards/writer.mjs +138 -0
- package/scripts/lib/peer-discovery.mjs +200 -0
- package/scripts/lib/persona-panel/catalog-loader.mjs +577 -0
- package/scripts/lib/persona-panel/consolidator.mjs +370 -0
- package/scripts/lib/persona-panel/persona-runner.mjs +375 -0
- package/scripts/lib/persona-panel/threshold.mjs +130 -0
- package/scripts/lib/pi-hook-bridge.mjs +328 -0
- package/scripts/lib/platform.mjs +266 -0
- package/scripts/lib/playwright-driver/runner.mjs +297 -0
- package/scripts/lib/plugin-root.mjs +210 -0
- package/scripts/lib/pre-dispatch-check.mjs +126 -0
- package/scripts/lib/product-repo-detect.mjs +121 -0
- package/scripts/lib/profiles/registry.mjs +176 -0
- package/scripts/lib/profiles/schema.mjs +209 -0
- package/scripts/lib/qg-command-drift-banner.mjs +88 -0
- package/scripts/lib/quality-gate/diagnostics.mjs +92 -0
- package/scripts/lib/quality-gate.mjs +536 -0
- package/scripts/lib/quality-gates-cache.mjs +228 -0
- package/scripts/lib/quality-gates-policy.mjs +95 -0
- package/scripts/lib/recommendations-v0.mjs +156 -0
- package/scripts/lib/reconcile/eligibility.mjs +203 -0
- package/scripts/lib/reconcile/emitter.mjs +244 -0
- package/scripts/lib/reconcile/engine.mjs +412 -0
- package/scripts/lib/reconcile/idempotency.mjs +239 -0
- package/scripts/lib/reconcile/renderer.mjs +211 -0
- package/scripts/lib/reconcile/writer.mjs +293 -0
- package/scripts/lib/reconcile-nudge-banner.mjs +284 -0
- package/scripts/lib/resource-probe/evaluate.mjs +190 -0
- package/scripts/lib/resource-probe/parsers.mjs +181 -0
- package/scripts/lib/resource-probe/probe-platform.mjs +300 -0
- package/scripts/lib/resource-probe.mjs +95 -0
- package/scripts/lib/rule-loader.mjs +552 -0
- package/scripts/lib/rules-sync.mjs +439 -0
- package/scripts/lib/scope-gate.mjs +496 -0
- package/scripts/lib/session-close-backfill.mjs +539 -0
- package/scripts/lib/session-discovery.mjs +256 -0
- package/scripts/lib/session-end/phase-skip.mjs +357 -0
- package/scripts/lib/session-end/worktree-cleanup.mjs +112 -0
- package/scripts/lib/session-id.mjs +362 -0
- package/scripts/lib/session-lock.mjs +703 -0
- package/scripts/lib/session-registry.mjs +355 -0
- package/scripts/lib/session-schema/aliases.mjs +71 -0
- package/scripts/lib/session-schema/constants.mjs +115 -0
- package/scripts/lib/session-schema/normalizer.mjs +66 -0
- package/scripts/lib/session-schema/timestamps.mjs +64 -0
- package/scripts/lib/session-schema/validator.mjs +453 -0
- package/scripts/lib/session-schema.mjs +71 -0
- package/scripts/lib/session-token-rollup.mjs +137 -0
- package/scripts/lib/sessions-staleness-banner.mjs +247 -0
- package/scripts/lib/skill-evolution/blast-radius-classifier.mjs +114 -0
- package/scripts/lib/skill-evolution/candidate-intake.mjs +270 -0
- package/scripts/lib/skill-evolution/config-validation-gate.mjs +279 -0
- package/scripts/lib/skill-evolution/engine.mjs +719 -0
- package/scripts/lib/skill-evolution/idempotency.mjs +279 -0
- package/scripts/lib/skill-evolution/mr-opener.mjs +507 -0
- package/scripts/lib/skill-health/join.mjs +181 -0
- package/scripts/lib/skill-health/score.mjs +123 -0
- package/scripts/lib/skill-invocations-schema.mjs +214 -0
- package/scripts/lib/skill-judge.mjs +348 -0
- package/scripts/lib/skill-judgments-schema.mjs +264 -0
- package/scripts/lib/slopcheck.mjs +501 -0
- package/scripts/lib/soul-resolve.mjs +118 -0
- package/scripts/lib/spiral-carryover.mjs +495 -0
- package/scripts/lib/state-md/body-sections.mjs +851 -0
- package/scripts/lib/state-md/frontmatter-mutators.mjs +453 -0
- package/scripts/lib/state-md/mission-status.mjs +247 -0
- package/scripts/lib/state-md/recommendations.mjs +57 -0
- package/scripts/lib/state-md/yaml-parser.mjs +234 -0
- package/scripts/lib/state-md-peer-guard.mjs +232 -0
- package/scripts/lib/state-md.mjs +53 -0
- package/scripts/lib/subagents-schema.mjs +309 -0
- package/scripts/lib/sunset/walker.mjs +1192 -0
- package/scripts/lib/test-runner/artifact-paths.mjs +94 -0
- package/scripts/lib/test-runner/fingerprint.mjs +33 -0
- package/scripts/lib/test-runner/issue-reconcile.mjs +770 -0
- package/scripts/lib/tmux-layout/layouts.mjs +224 -0
- package/scripts/lib/tmux-layout/telemetry-stats.mjs +100 -0
- package/scripts/lib/tmux-layout/telemetry.mjs +88 -0
- package/scripts/lib/tmux-layout/tmux-shell.mjs +82 -0
- package/scripts/lib/tmux-layout/vcs-detector.mjs +88 -0
- package/scripts/lib/validate/check-agents.mjs +457 -0
- package/scripts/lib/validate/check-codex-plugin.mjs +37 -0
- package/scripts/lib/validate/check-commands.mjs +148 -0
- package/scripts/lib/validate/check-component-paths.mjs +112 -0
- package/scripts/lib/validate/check-dead-bridge.mjs +180 -0
- package/scripts/lib/validate/check-hooks-symmetry.mjs +258 -0
- package/scripts/lib/validate/check-json-files.mjs +116 -0
- package/scripts/lib/validate/check-owner-leakage.mjs +1011 -0
- package/scripts/lib/validate/check-path-utils-canary.mjs +175 -0
- package/scripts/lib/validate/check-peekaboo-driver-canary.mjs +201 -0
- package/scripts/lib/validate/check-pi-package.mjs +110 -0
- package/scripts/lib/validate/check-pi-prompts.mjs +43 -0
- package/scripts/lib/validate/check-playwright-mcp-canary.mjs +154 -0
- package/scripts/lib/validate/check-plugin-json.mjs +96 -0
- package/scripts/lib/validate/check-plugin-monitors.mjs +206 -0
- package/scripts/lib/validate/check-plugin-schema.mjs +137 -0
- package/scripts/lib/validate/check-rules.mjs +143 -0
- package/scripts/lib/validate/check-session-plan-routing.mjs +154 -0
- package/scripts/lib/validate/check-test-fixture-shapes.mjs +280 -0
- package/scripts/lib/validate/check-unicode-safety.mjs +533 -0
- package/scripts/lib/validate/confidential-names.mjs +169 -0
- package/scripts/lib/validate/dead-bridge-corpus.mjs +141 -0
- package/scripts/lib/validate/dead-bridge-detectors.mjs +568 -0
- package/scripts/lib/validate/tier-inference.mjs +100 -0
- package/scripts/lib/validate-vendored-rules.mjs +519 -0
- package/scripts/lib/vault-archive.mjs +404 -0
- package/scripts/lib/vault-backfill/glab.mjs +164 -0
- package/scripts/lib/vault-backfill/manifest.mjs +75 -0
- package/scripts/lib/vault-backfill/template.mjs +130 -0
- package/scripts/lib/vault-consolidate-fs.mjs +331 -0
- package/scripts/lib/vault-migration-rules.mjs +155 -0
- package/scripts/lib/vault-mirror/auto-commit.mjs +203 -0
- package/scripts/lib/vault-mirror/namespace.mjs +152 -0
- package/scripts/lib/vault-mirror/process.mjs +567 -0
- package/scripts/lib/vault-mirror/pseudonym-map.mjs +164 -0
- package/scripts/lib/vault-mirror/render-learnings.mjs +201 -0
- package/scripts/lib/vault-mirror/render-sessions.mjs +367 -0
- package/scripts/lib/vault-mirror/render.mjs +8 -0
- package/scripts/lib/vault-mirror/utils.mjs +217 -0
- package/scripts/lib/vault-relocation-rules.mjs +555 -0
- package/scripts/lib/vault-repo-backfill.mjs +235 -0
- package/scripts/lib/vault-staleness-banner.mjs +142 -0
- package/scripts/lib/vault-status/board-writer.mjs +769 -0
- package/scripts/lib/vault-status/narrative-mirror.mjs +544 -0
- package/scripts/lib/vault-sync-baseline.mjs +152 -0
- package/scripts/lib/wave-context.mjs +29 -0
- package/scripts/lib/wave-executor/pool.mjs +248 -0
- package/scripts/lib/wave-resource-gate.mjs +204 -0
- package/scripts/lib/wave-sizing.mjs +75 -0
- package/scripts/lib/webhook-url.mjs +105 -0
- package/scripts/lib/workspace.mjs +198 -0
- package/scripts/lib/worktree/constants.mjs +35 -0
- package/scripts/lib/worktree/index.mjs +17 -0
- package/scripts/lib/worktree/lifecycle.mjs +287 -0
- package/scripts/lib/worktree/listing.mjs +118 -0
- package/scripts/lib/worktree/meta.mjs +64 -0
- package/scripts/lib/worktree-freshness.mjs +313 -0
- package/scripts/lib/worktree.mjs +15 -0
- package/scripts/lifecycle-sim-v6.mjs +347 -0
- package/scripts/lock-reaper.mjs +185 -0
- package/scripts/mcp-server.sh +241 -0
- package/scripts/measure-policy-cache-effectiveness.mjs +427 -0
- package/scripts/memory-propose.mjs +464 -0
- package/scripts/migrate-cold-start-seed.mjs +404 -0
- package/scripts/migrate-learnings-jsonl.mjs +189 -0
- package/scripts/migrate-legacy-learnings.sh +61 -0
- package/scripts/migrate-sessions-jsonl.mjs +448 -0
- package/scripts/migrate-subagents-jsonl.mjs +196 -0
- package/scripts/migrate-vault-paths.mjs +796 -0
- package/scripts/parse-config.mjs +149 -0
- package/scripts/pi-install.mjs +117 -0
- package/scripts/print-applicable-rules.mjs +247 -0
- package/scripts/promote-vault-strict.mjs +496 -0
- package/scripts/relocate-vault-corpus.mjs +1178 -0
- package/scripts/run-migrate-v2-cross-repo.mjs +385 -0
- package/scripts/run-quality-gate.mjs +216 -0
- package/scripts/spikes/h3-agent-teams/preflight.sh +53 -0
- package/scripts/spikes/h3-agent-teams/run-h3.sh +112 -0
- package/scripts/spikes/h3-agent-teams/setup.sh +137 -0
- package/scripts/spikes/h3-agent-teams/toggle.sh +38 -0
- package/scripts/sweep-expired-learnings.mjs +135 -0
- package/scripts/sync-vault-schema.mjs +376 -0
- package/scripts/tests/fixtures/fetch-baseline/sample-rule.md +8 -0
- package/scripts/tmux-layout.mjs +245 -0
- package/scripts/token-audit.sh +191 -0
- package/scripts/typecheck.mjs +42 -0
- package/scripts/upload-social-preview.mjs +316 -0
- package/scripts/validate-config.mjs +46 -0
- package/scripts/validate-plugin-manifests.mjs +163 -0
- package/scripts/validate-plugin.mjs +264 -0
- package/scripts/validate-wave-scope.mjs +289 -0
- package/scripts/vault-backfill.mjs +404 -0
- package/scripts/vault-consolidate.mjs +596 -0
- package/scripts/vault-integration-watcher.mjs +394 -0
- package/scripts/vault-mirror.mjs +430 -0
- package/skills/_shared/bootstrap-gate.md +111 -0
- package/skills/_shared/config-reading.md +226 -0
- package/skills/_shared/instruction-file-resolution.md +79 -0
- package/skills/_shared/model-selection.md +64 -0
- package/skills/_shared/monitor-patterns.md +300 -0
- package/skills/_shared/parallel-aware-auq.md +121 -0
- package/skills/_shared/parallel-aware-preamble.md +185 -0
- package/skills/_shared/platform-tools.md +96 -0
- package/skills/_shared/state-ownership.md +221 -0
- package/skills/architecture/DEEPENING.md +37 -0
- package/skills/architecture/INTERFACE-DESIGN.md +44 -0
- package/skills/architecture/LANGUAGE.md +53 -0
- package/skills/architecture/SKILL.md +92 -0
- package/skills/autopilot/SKILL.md +419 -0
- package/skills/bootstrap/SKILL.md +592 -0
- package/skills/bootstrap/STATE.md.template +24 -0
- package/skills/bootstrap/_shared-template.md +243 -0
- package/skills/bootstrap/deep-template.md +659 -0
- package/skills/bootstrap/fast-template.md +251 -0
- package/skills/bootstrap/intensity-heuristic.md +80 -0
- package/skills/bootstrap/public-fallback.md +342 -0
- package/skills/bootstrap/standard-template.md +736 -0
- package/skills/bootstrap/templates/agents/project-code-review.md +18 -0
- package/skills/bootstrap/templates/agents/project-discovery.md +18 -0
- package/skills/bootstrap/templates/agents/project-quality-gate.md +18 -0
- package/skills/brainstorm/SKILL.md +268 -0
- package/skills/brainstorm/soul.md +49 -0
- package/skills/claude-md-drift-check/SKILL.md +186 -0
- package/skills/claude-md-drift-check/checker.mjs +1380 -0
- package/skills/claude-md-drift-check/checker.sh +37 -0
- package/skills/claude-md-drift-check/package.json +16 -0
- package/skills/convergence-monitoring/README.md +39 -0
- package/skills/convergence-monitoring/SIGNALS.md +246 -0
- package/skills/convergence-monitoring/SKILL.md +285 -0
- package/skills/daily/SKILL.md +222 -0
- package/skills/daily/generate.sh +92 -0
- package/skills/daily/templates/daily.md.tpl +36 -0
- package/skills/debug/SKILL.md +188 -0
- package/skills/debug/soul.md +35 -0
- package/skills/discovery/SKILL.md +567 -0
- package/skills/discovery/issue-templates.md +237 -0
- package/skills/discovery/probes/docs-staleness.mjs +195 -0
- package/skills/discovery/probes/frontend-slop.mjs +186 -0
- package/skills/discovery/probes/ssot-code-diff.mjs +310 -0
- package/skills/discovery/probes/supply-chain-slopcheck.mjs +440 -0
- package/skills/discovery/probes/vault-narrative-staleness.mjs +355 -0
- package/skills/discovery/probes/vault-staleness.mjs +272 -0
- package/skills/discovery/probes-arch.md +252 -0
- package/skills/discovery/probes-audit.md +95 -0
- package/skills/discovery/probes-code.md +329 -0
- package/skills/discovery/probes-docs.md +76 -0
- package/skills/discovery/probes-feature.md +150 -0
- package/skills/discovery/probes-infra.md +138 -0
- package/skills/discovery/probes-intro.md +25 -0
- package/skills/discovery/probes-session.md +495 -0
- package/skills/discovery/probes-supply-chain.md +94 -0
- package/skills/discovery/probes-ui.md +147 -0
- package/skills/discovery/probes-vault.md +64 -0
- package/skills/discovery/slop-patterns.md +115 -0
- package/skills/dispatcher/SKILL.md +173 -0
- package/skills/docs-orchestrator/SKILL.md +362 -0
- package/skills/docs-orchestrator/audience-mapping.md +140 -0
- package/skills/domain-model/ADR-FORMAT.md +47 -0
- package/skills/domain-model/CONTEXT-FORMAT.md +77 -0
- package/skills/domain-model/SKILL.md +85 -0
- package/skills/ecosystem-health/SKILL.md +119 -0
- package/skills/ecosystem-health/wizard.md +193 -0
- package/skills/eval/SKILL.md +293 -0
- package/skills/eval/rubric-v1.md +218 -0
- package/skills/evolve/SKILL.md +546 -0
- package/skills/frontmatter-guard/SKILL.md +126 -0
- package/skills/gitlab-ops/SKILL.md +368 -0
- package/skills/gitlab-portfolio/SKILL.md +196 -0
- package/skills/grill/SKILL.md +185 -0
- package/skills/grill/soul.md +55 -0
- package/skills/hook-development/SKILL.md +413 -0
- package/skills/mcp-builder/SKILL.md +260 -0
- package/skills/memory-cleanup/SKILL.md +310 -0
- package/skills/mode-selector/SKILL.md +226 -0
- package/skills/peekaboo-driver/SKILL.md +237 -0
- package/skills/peekaboo-driver/soul.md +32 -0
- package/skills/persona-panel/SKILL.md +365 -0
- package/skills/persona-panel/persona-format.md +205 -0
- package/skills/persona-panel/presets/designer-lens.md +87 -0
- package/skills/persona-panel/presets/engineer-lens.md +88 -0
- package/skills/persona-panel/presets/pm-lens.md +86 -0
- package/skills/plan/SKILL.md +496 -0
- package/skills/plan/mode-feature.md +141 -0
- package/skills/plan/mode-new.md +297 -0
- package/skills/plan/mode-retro.md +271 -0
- package/skills/plan/prd-feature-template.md +132 -0
- package/skills/plan/prd-full-template.md +151 -0
- package/skills/plan/prd-reviewer-prompt.md +103 -0
- package/skills/plan/retro-template.md +75 -0
- package/skills/plan/soul.md +62 -0
- package/skills/playwright-driver/SKILL.md +226 -0
- package/skills/playwright-driver/soul.md +30 -0
- package/skills/quality-gates/SKILL.md +212 -0
- package/skills/reconcile/SKILL.md +324 -0
- package/skills/repo-audit/SKILL.md +272 -0
- package/skills/session-end/SKILL.md +1044 -0
- package/skills/session-end/discovery-scan.md +37 -0
- package/skills/session-end/drift-operations.md +97 -0
- package/skills/session-end/learning-patterns.md +78 -0
- package/skills/session-end/metrics-collection.md +175 -0
- package/skills/session-end/phase-3-2-docs-verification.md +148 -0
- package/skills/session-end/phase-3-6-tail.md +344 -0
- package/skills/session-end/phase-3-7a-recommendations.md +86 -0
- package/skills/session-end/plan-verification.md +288 -0
- package/skills/session-end/session-metrics-write.md +223 -0
- package/skills/session-end/vault-operations.md +50 -0
- package/skills/session-end/verification-checklist.md +20 -0
- package/skills/session-plan/SKILL.md +554 -0
- package/skills/session-plan/wave-template.md +37 -0
- package/skills/session-start/SKILL.md +1043 -0
- package/skills/session-start/phase-2-5-docs-planning.md +119 -0
- package/skills/session-start/phase-4-5-resource-health.md +49 -0
- package/skills/session-start/phase-7-1-premise-check.md +47 -0
- package/skills/session-start/phase-7-5-mode-selector.md +237 -0
- package/skills/session-start/phase-8-5-express-path.md +61 -0
- package/skills/session-start/presentation-format.md +81 -0
- package/skills/session-start/soul.md +57 -0
- package/skills/skill-creator/SKILL.md +168 -0
- package/skills/spinout/SKILL.md +76 -0
- package/skills/sunset-review/SKILL.md +96 -0
- package/skills/test-runner/SKILL.md +362 -0
- package/skills/test-runner/rubric-v1.md +388 -0
- package/skills/test-runner/soul.md +46 -0
- package/skills/tmux-layout/SKILL.md +104 -0
- package/skills/ubiquitous-language/SKILL.md +97 -0
- package/skills/using-orchestrator/SKILL.md +144 -0
- package/skills/vault-mirror/SKILL.md +234 -0
- package/skills/vault-sync/SKILL.md +319 -0
- package/skills/vault-sync/package-lock.json +40 -0
- package/skills/vault-sync/package.json +11 -0
- package/skills/vault-sync/tests/fixtures/archive-test-vault/90-archive/bad-archived.md +8 -0
- package/skills/vault-sync/tests/fixtures/archive-test-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/archive-test-vault/live-note.md +8 -0
- package/skills/vault-sync/tests/fixtures/broken-frontmatter-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/broken-frontmatter-vault/bad-type.md +8 -0
- package/skills/vault-sync/tests/fixtures/broken-frontmatter-vault/good-note.md +8 -0
- package/skills/vault-sync/tests/fixtures/clean-vault/.obsidian/config.md +8 -0
- package/skills/vault-sync/tests/fixtures/clean-vault/01-projects/foo/projects-baseline.md +10 -0
- package/skills/vault-sync/tests/fixtures/clean-vault/03-daily/daily-2026-04-13.md +8 -0
- package/skills/vault-sync/tests/fixtures/clean-vault/README.md +3 -0
- package/skills/vault-sync/tests/fixtures/clean-vault/hello-world.md +11 -0
- package/skills/vault-sync/tests/fixtures/dangling-link-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/dangling-link-vault/has-dangling.md +9 -0
- package/skills/vault-sync/tests/fixtures/dangling-link-vault/real-target.md +8 -0
- package/skills/vault-sync/tests/fixtures/empty-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/missing-field-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/missing-field-vault/missing-id.md +7 -0
- package/skills/vault-sync/tests/fixtures/nested-tag-vault/03-daily/daily-2026-04-13.md +9 -0
- package/skills/vault-sync/tests/fixtures/nested-tag-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/nested-tag-vault/nested-tags-note.md +11 -0
- package/skills/vault-sync/tests/fixtures/no-frontmatter-vault/README.md +3 -0
- package/skills/vault-sync/tests/fixtures/no-frontmatter-vault/_MOC.md +3 -0
- package/skills/vault-sync/tests/fixtures/no-frontmatter-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/with-moc-vault/_MOC.md +11 -0
- package/skills/vault-sync/tests/fixtures/with-moc-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/with-moc-vault/hello-world.md +11 -0
- package/skills/vault-sync/tests/schema-drift.test.mjs +133 -0
- package/skills/vault-sync/validator.mjs +658 -0
- package/skills/vault-sync/validator.sh +55 -0
- package/skills/wave-executor/SKILL.md +496 -0
- package/skills/wave-executor/circuit-breaker.md +169 -0
- package/skills/wave-executor/wave-loop.md +1043 -0
- package/skills/write-executable-plan/SKILL.md +237 -0
- package/skills/write-executable-plan/plan-template.md +154 -0
- package/templates/_minimal/CLAUDE.md.tmpl +41 -0
- package/templates/_minimal/README.md.tmpl +15 -0
- package/templates/_minimal/gitignore.tmpl +47 -0
- package/templates/_shared/harte-regeln.md +16 -0
- package/templates/_shared/loop.md +90 -0
- package/templates/_shared/rules/parallel-sessions.md +77 -0
- package/templates/nextjs-minimal/README.md +30 -0
- package/templates/nextjs-minimal/app/layout.tsx +18 -0
- package/templates/nextjs-minimal/app/page.tsx +7 -0
- package/templates/nextjs-minimal/eslint.config.mjs +16 -0
- package/templates/nextjs-minimal/next.config.mjs +4 -0
- package/templates/nextjs-minimal/package.json +27 -0
- package/templates/nextjs-minimal/tsconfig.json +23 -0
- package/templates/node-minimal/README.md +33 -0
- package/templates/node-minimal/eslint.config.mjs +10 -0
- package/templates/node-minimal/package.json +21 -0
- package/templates/node-minimal/src/index.ts +1 -0
- package/templates/node-minimal/tests/sanity.test.ts +5 -0
- package/templates/node-minimal/tsconfig.json +17 -0
- package/templates/personas/README.md +150 -0
- package/templates/personas/accounting-compliance.v1.md +120 -0
- package/templates/personas/accounting-tax-advisor.v1.md +116 -0
- package/templates/personas/buyer-p1-cto.v1.md +125 -0
- package/templates/personas/buyer-p2-kanzlei.v1.md +134 -0
- package/templates/personas/buyer-p3-build.v1.md +130 -0
- package/templates/personas/buyer-p4-tech-veto.v1.md +130 -0
- package/templates/personas/buyer-p5-solo.v1.md +132 -0
- package/templates/personas/buyer-p6-ld.v1.md +130 -0
- package/templates/personas/klima-ai-expert.v1.md +114 -0
- package/templates/personas/klima-physicist.v1.md +117 -0
- package/templates/python-uv/README.md +28 -0
- package/templates/python-uv/pyproject.toml +32 -0
- package/templates/python-uv/src/__PROJECT_NAME__/__init__.py +0 -0
- package/templates/python-uv/src/__PROJECT_NAME__/main.py +6 -0
- package/templates/python-uv/tests/test_sanity.py +2 -0
- package/templates/static-html/README.md +19 -0
- package/templates/static-html/index.html +15 -0
- package/templates/static-html/script.js +1 -0
- package/templates/static-html/styles.css +26 -0
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* common.mjs — Shared I/O utilities for session-orchestrator scripts.
|
|
3
|
+
*
|
|
4
|
+
* Pure ESM, Node stdlib only. Replaces the generic helpers from common.sh.
|
|
5
|
+
*
|
|
6
|
+
* Part of v3.0.0 migration (Epic #124, issue #136).
|
|
7
|
+
* Shell-helper ports added for issue #218.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import os from 'node:os';
|
|
11
|
+
import path from 'node:path';
|
|
12
|
+
import crypto from 'node:crypto';
|
|
13
|
+
import { promises as fs, existsSync, statSync } from 'node:fs';
|
|
14
|
+
import { fileURLToPath } from 'node:url';
|
|
15
|
+
import { execSync } from 'node:child_process';
|
|
16
|
+
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
// Path helpers
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Returns a unique temp path (does NOT create the file/directory).
|
|
23
|
+
* @param {string} prefix - non-empty string prepended to the filename
|
|
24
|
+
* @returns {string}
|
|
25
|
+
*/
|
|
26
|
+
export function makeTmpPath(prefix) {
|
|
27
|
+
if (typeof prefix !== 'string' || prefix.length === 0) {
|
|
28
|
+
throw new TypeError('makeTmpPath: prefix must be a non-empty string');
|
|
29
|
+
}
|
|
30
|
+
const rand = crypto.randomBytes(4).toString('hex');
|
|
31
|
+
return path.join(os.tmpdir(), `${prefix}-${Date.now()}-${rand}`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Expand a leading `~` (home-directory shorthand) to the current user's home
|
|
36
|
+
* directory. Non-`~`-prefixed strings, non-strings, and the empty string pass
|
|
37
|
+
* through unchanged.
|
|
38
|
+
*
|
|
39
|
+
* Canonical shared implementation for vault-dir-consuming call-sites added
|
|
40
|
+
* under Epic #774 (docs Public-Split) — see `scripts/lib/vault-archive.mjs`
|
|
41
|
+
* and `scripts/export-hw-learnings.mjs`. Several pre-existing inline copies
|
|
42
|
+
* of this exact shape (e.g. `scripts/lib/vault-status/board-writer.mjs`,
|
|
43
|
+
* `narrative-mirror.mjs`, `scripts/lib/dispatcher/enumerate.mjs`) are
|
|
44
|
+
* intentionally NOT migrated to this shared helper here — that consolidation
|
|
45
|
+
* is a separate follow-up, not this fix's scope.
|
|
46
|
+
*
|
|
47
|
+
* @param {string} p
|
|
48
|
+
* @returns {string}
|
|
49
|
+
*/
|
|
50
|
+
export function expandTilde(p) {
|
|
51
|
+
if (typeof p !== 'string' || p.length === 0) return p;
|
|
52
|
+
if (p === '~') return os.homedir();
|
|
53
|
+
if (p.startsWith('~/')) return path.join(os.homedir(), p.slice(2));
|
|
54
|
+
return p;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ---------------------------------------------------------------------------
|
|
58
|
+
// Timestamp helpers
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
|
|
61
|
+
/** Returns the current time as an ISO 8601 UTC string. */
|
|
62
|
+
export function utcTimestamp() {
|
|
63
|
+
return new Date().toISOString();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Returns the current Unix time in milliseconds. */
|
|
67
|
+
export function epochMs() {
|
|
68
|
+
return Date.now();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
// JSON file helpers
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Reads and parses a JSON file; throws on missing file or parse error.
|
|
77
|
+
* @param {string} filePath
|
|
78
|
+
* @returns {Promise<unknown>}
|
|
79
|
+
*/
|
|
80
|
+
export async function readJson(filePath) {
|
|
81
|
+
const raw = await fs.readFile(filePath, 'utf8');
|
|
82
|
+
return JSON.parse(raw);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Serialises obj as pretty-printed JSON and writes it to filePath,
|
|
87
|
+
* creating any missing parent directories automatically.
|
|
88
|
+
* @param {string} filePath
|
|
89
|
+
* @param {unknown} obj
|
|
90
|
+
* @returns {Promise<void>}
|
|
91
|
+
*/
|
|
92
|
+
export async function writeJson(filePath, obj) {
|
|
93
|
+
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
94
|
+
await fs.writeFile(filePath, JSON.stringify(obj, null, 2) + '\n', 'utf8');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Appends obj as a single JSONL line to filePath, creating missing parent
|
|
99
|
+
* directories automatically. Single appendFile call — atomic for lines under
|
|
100
|
+
* PIPE_BUF (4 KiB).
|
|
101
|
+
* @param {string} filePath
|
|
102
|
+
* @param {unknown} obj
|
|
103
|
+
* @returns {Promise<void>}
|
|
104
|
+
*/
|
|
105
|
+
export async function appendJsonl(filePath, obj) {
|
|
106
|
+
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
107
|
+
await fs.appendFile(filePath, JSON.stringify(obj) + '\n', 'utf8');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// ---------------------------------------------------------------------------
|
|
111
|
+
// Shell-helper ports (issue #218) — equivalents of common.sh functions
|
|
112
|
+
// ---------------------------------------------------------------------------
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Print an error message to stderr and exit with code 1.
|
|
116
|
+
* Equivalent to die() in common.sh.
|
|
117
|
+
* @param {string} message
|
|
118
|
+
* @returns {never}
|
|
119
|
+
*/
|
|
120
|
+
export function die(message) {
|
|
121
|
+
process.stderr.write(`ERROR: ${message}\n`);
|
|
122
|
+
process.exit(1);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Print a warning message to stderr (does not exit).
|
|
127
|
+
* Equivalent to warn() in common.sh.
|
|
128
|
+
* @param {string} message
|
|
129
|
+
*/
|
|
130
|
+
export function warn(message) {
|
|
131
|
+
process.stderr.write(`WARNING: ${message}\n`);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Verify that jq is available on PATH.
|
|
136
|
+
* Throws an Error if jq is not found (instead of exiting, so callers can decide).
|
|
137
|
+
* For scripts that want exit-on-failure behaviour, wrap with die():
|
|
138
|
+
* try { requireJq(); } catch (e) { die(e.message); }
|
|
139
|
+
* Equivalent to require_jq() in common.sh.
|
|
140
|
+
* @returns {void}
|
|
141
|
+
* @throws {Error} when jq is not on PATH
|
|
142
|
+
*/
|
|
143
|
+
export function requireJq() {
|
|
144
|
+
try {
|
|
145
|
+
execSync('command -v jq', { stdio: 'ignore', shell: true });
|
|
146
|
+
} catch {
|
|
147
|
+
throw new Error('jq is required but not installed. Install via: brew install jq');
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// ---------------------------------------------------------------------------
|
|
152
|
+
// Internal helpers for project/plugin root detection
|
|
153
|
+
// ---------------------------------------------------------------------------
|
|
154
|
+
|
|
155
|
+
/** Return true when `dir` exists as a directory. */
|
|
156
|
+
function _isDirSync(dir) {
|
|
157
|
+
try { return statSync(dir).isDirectory(); } catch { return false; }
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/** Return true when `file` exists (file or directory). */
|
|
161
|
+
function _isFileSync(file) {
|
|
162
|
+
return existsSync(file);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Walk up the directory tree from `startDir` until a directory satisfying
|
|
167
|
+
* `predicate(dir)` is found. Returns the matching directory or null.
|
|
168
|
+
* @param {string} startDir
|
|
169
|
+
* @param {(dir: string) => boolean} predicate
|
|
170
|
+
* @returns {string|null}
|
|
171
|
+
*/
|
|
172
|
+
function _walkUpUntil(startDir, predicate) {
|
|
173
|
+
let dir = path.resolve(startDir);
|
|
174
|
+
while (true) {
|
|
175
|
+
if (predicate(dir)) return dir;
|
|
176
|
+
const parent = path.dirname(dir);
|
|
177
|
+
if (parent === dir) break; // reached filesystem root
|
|
178
|
+
dir = parent;
|
|
179
|
+
}
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// ---------------------------------------------------------------------------
|
|
184
|
+
// findProjectRoot
|
|
185
|
+
// ---------------------------------------------------------------------------
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Walk up from `startDir` (defaults to process.cwd()) looking for CLAUDE.md,
|
|
189
|
+
* .claude/, AGENTS.md, .codex/, or .pi/ markers. Returns the found project root, or
|
|
190
|
+
* `startDir` if nothing is found.
|
|
191
|
+
*
|
|
192
|
+
* Respects CLAUDE_PROJECT_DIR, CODEX_PROJECT_DIR, and PI_PROJECT_DIR environment variables as
|
|
193
|
+
* fast-paths (same semantics as common.sh find_project_root).
|
|
194
|
+
*
|
|
195
|
+
* Equivalent to find_project_root() in common.sh.
|
|
196
|
+
*
|
|
197
|
+
* @param {string} [startDir] - directory to start the walk from (default: process.cwd())
|
|
198
|
+
* @returns {string} Absolute path of the project root
|
|
199
|
+
*/
|
|
200
|
+
export function findProjectRoot(startDir) {
|
|
201
|
+
const base = startDir ? path.resolve(startDir) : process.cwd();
|
|
202
|
+
|
|
203
|
+
// Fast path: CLAUDE_PROJECT_DIR
|
|
204
|
+
const claudeDir = process.env.CLAUDE_PROJECT_DIR;
|
|
205
|
+
if (claudeDir) {
|
|
206
|
+
if (_isFileSync(path.join(claudeDir, 'CLAUDE.md')) || _isDirSync(path.join(claudeDir, '.claude'))) {
|
|
207
|
+
return claudeDir;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Fast path: CODEX_PROJECT_DIR
|
|
212
|
+
const codexDir = process.env.CODEX_PROJECT_DIR;
|
|
213
|
+
if (codexDir) {
|
|
214
|
+
if (_isFileSync(path.join(codexDir, 'AGENTS.md')) || _isDirSync(path.join(codexDir, '.codex'))) {
|
|
215
|
+
return codexDir;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Fast path: PI_PROJECT_DIR
|
|
220
|
+
const piDir = process.env.PI_PROJECT_DIR;
|
|
221
|
+
if (piDir) {
|
|
222
|
+
if (_isFileSync(path.join(piDir, 'AGENTS.md')) || _isDirSync(path.join(piDir, '.pi'))) {
|
|
223
|
+
return piDir;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const found = _walkUpUntil(base, (dir) =>
|
|
228
|
+
_isFileSync(path.join(dir, 'CLAUDE.md')) ||
|
|
229
|
+
_isDirSync(path.join(dir, '.claude')) ||
|
|
230
|
+
_isFileSync(path.join(dir, 'AGENTS.md')) ||
|
|
231
|
+
_isDirSync(path.join(dir, '.codex')) ||
|
|
232
|
+
_isDirSync(path.join(dir, '.pi')),
|
|
233
|
+
);
|
|
234
|
+
|
|
235
|
+
return found ?? base;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// ---------------------------------------------------------------------------
|
|
239
|
+
// resolvePluginRoot
|
|
240
|
+
// ---------------------------------------------------------------------------
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Resolve the session-orchestrator plugin root directory.
|
|
244
|
+
*
|
|
245
|
+
* Resolution order (stops at first success):
|
|
246
|
+
* 1. CLAUDE_PLUGIN_ROOT env var
|
|
247
|
+
* 2. CODEX_PLUGIN_ROOT env var
|
|
248
|
+
* 3. PI_PLUGIN_ROOT env var
|
|
249
|
+
* 4. Walk up from import.meta.url of this file looking for plugin.json / skills/ / .codex-plugin/
|
|
250
|
+
* 5. Walk up from process.cwd() looking for the same markers
|
|
251
|
+
*
|
|
252
|
+
* Equivalent to resolve_plugin_root() in common.sh, but throws instead of calling die()
|
|
253
|
+
* so that callers in a non-process context (tests) can catch the error.
|
|
254
|
+
*
|
|
255
|
+
* @param {string} [callerUrl] - import.meta.url of the calling module (optional override for level-3 walk)
|
|
256
|
+
* @returns {string} Absolute path to the plugin root
|
|
257
|
+
* @throws {Error} when all resolution levels fail
|
|
258
|
+
*/
|
|
259
|
+
export function resolvePluginRoot(callerUrl) {
|
|
260
|
+
const isPluginDir = (dir) =>
|
|
261
|
+
_isFileSync(path.join(dir, 'plugin.json')) ||
|
|
262
|
+
_isDirSync(path.join(dir, 'skills')) ||
|
|
263
|
+
_isDirSync(path.join(dir, '.codex-plugin'));
|
|
264
|
+
|
|
265
|
+
// Level 1: CLAUDE_PLUGIN_ROOT
|
|
266
|
+
const claudeRoot = process.env.CLAUDE_PLUGIN_ROOT;
|
|
267
|
+
if (claudeRoot && _isDirSync(claudeRoot)) return claudeRoot;
|
|
268
|
+
|
|
269
|
+
// Level 2: CODEX_PLUGIN_ROOT
|
|
270
|
+
const codexRoot = process.env.CODEX_PLUGIN_ROOT;
|
|
271
|
+
if (codexRoot && _isDirSync(codexRoot)) return codexRoot;
|
|
272
|
+
|
|
273
|
+
// Level 3: PI_PLUGIN_ROOT
|
|
274
|
+
const piRoot = process.env.PI_PLUGIN_ROOT;
|
|
275
|
+
if (piRoot && _isDirSync(piRoot)) return piRoot;
|
|
276
|
+
|
|
277
|
+
// Level 4: walk up from caller / this file
|
|
278
|
+
const startFromFile = callerUrl
|
|
279
|
+
? path.dirname(fileURLToPath(callerUrl))
|
|
280
|
+
: path.dirname(fileURLToPath(import.meta.url));
|
|
281
|
+
const byFile = _walkUpUntil(startFromFile, isPluginDir);
|
|
282
|
+
if (byFile) return byFile;
|
|
283
|
+
|
|
284
|
+
// Level 5: walk up from cwd
|
|
285
|
+
const byCwd = _walkUpUntil(process.cwd(), isPluginDir);
|
|
286
|
+
if (byCwd) return byCwd;
|
|
287
|
+
|
|
288
|
+
throw new Error(
|
|
289
|
+
'Could not locate plugin root. Set CLAUDE_PLUGIN_ROOT, CODEX_PLUGIN_ROOT, or PI_PLUGIN_ROOT to the plugin directory, ' +
|
|
290
|
+
'or ensure plugin.json / skills/ exists in an ancestor of the cwd.',
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// ---------------------------------------------------------------------------
|
|
295
|
+
// resolveInstructionFile (issue #33)
|
|
296
|
+
// ---------------------------------------------------------------------------
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Resolve the canonical project-instruction file at the given repo root.
|
|
300
|
+
*
|
|
301
|
+
* `CLAUDE.md` (Claude Code / Cursor IDE) and `AGENTS.md` (Codex CLI) are
|
|
302
|
+
* transparent aliases. Precedence:
|
|
303
|
+
*
|
|
304
|
+
* 1. `<repoRoot>/CLAUDE.md` exists and is non-empty → kind: 'claude'
|
|
305
|
+
* 2. `<repoRoot>/AGENTS.md` exists and is non-empty → kind: 'agents'
|
|
306
|
+
* 3. otherwise → null (caller decides what to do)
|
|
307
|
+
*
|
|
308
|
+
* Never merge both. Never read both. Pick one.
|
|
309
|
+
*
|
|
310
|
+
* SSOT for the alias rule: `skills/_shared/instruction-file-resolution.md`.
|
|
311
|
+
*
|
|
312
|
+
* @param {string} [repoRoot] - absolute repo root (default: findProjectRoot())
|
|
313
|
+
* @returns {{ path: string, kind: 'claude' | 'agents' } | null}
|
|
314
|
+
*/
|
|
315
|
+
export function resolveInstructionFile(repoRoot) {
|
|
316
|
+
const root = repoRoot ?? findProjectRoot();
|
|
317
|
+
if (!root) return null;
|
|
318
|
+
const candidates = [
|
|
319
|
+
{ file: 'CLAUDE.md', kind: 'claude' },
|
|
320
|
+
{ file: 'AGENTS.md', kind: 'agents' },
|
|
321
|
+
];
|
|
322
|
+
for (const c of candidates) {
|
|
323
|
+
const p = path.join(root, c.file);
|
|
324
|
+
if (existsSync(p)) {
|
|
325
|
+
try {
|
|
326
|
+
if (statSync(p).size > 0) return { path: p, kind: c.kind };
|
|
327
|
+
} catch {
|
|
328
|
+
// stat failure (race, permissions) — skip this candidate, try next
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return null;
|
|
333
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { matchBlockHeader } from './block-header.mjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* auto-dream.mjs — Parser for the top-level `auto-dream:` YAML block (issue #566).
|
|
5
|
+
*
|
|
6
|
+
* Returns `{ "min-confidence": float in [0.0, 1.0] }`.
|
|
7
|
+
* Tolerant parser: malformed values silently fall back to defaults.
|
|
8
|
+
*
|
|
9
|
+
* Consumer: `scripts/lib/memory-proposals/collector.mjs` reads the value via
|
|
10
|
+
* Session Config and applies the filter inside `collectProposals()` at
|
|
11
|
+
* session-end Phase 3.6.3 (collect-emit time). This is a SECOND confidence
|
|
12
|
+
* gate above the existing write-time `memory.proposals.confidence-floor`
|
|
13
|
+
* floor enforced by `scripts/memory-propose.mjs`.
|
|
14
|
+
*
|
|
15
|
+
* Structurally mirrors `scripts/lib/config/cold-start.mjs` (single-level
|
|
16
|
+
* nested block, top-level boundary detection). Float-range validation copied
|
|
17
|
+
* verbatim from `scripts/lib/config/vault-mirror-quality.mjs:69-73`.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Parse the top-level `auto-dream:` YAML block from markdown content.
|
|
22
|
+
* Independent of the `## Session Config` section boundary.
|
|
23
|
+
*
|
|
24
|
+
* Defaults:
|
|
25
|
+
* min-confidence: 0.5 (float in [0.0, 1.0])
|
|
26
|
+
*
|
|
27
|
+
* @param {string} content — full file contents
|
|
28
|
+
* @returns {{ "min-confidence": number }}
|
|
29
|
+
*/
|
|
30
|
+
export function _parseAutoDream(content) {
|
|
31
|
+
const defaults = {
|
|
32
|
+
'min-confidence': 0.5,
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const lines = content.split(/\r?\n/);
|
|
36
|
+
let inBlock = false;
|
|
37
|
+
const blockLines = [];
|
|
38
|
+
|
|
39
|
+
for (const rawLine of lines) {
|
|
40
|
+
const line = rawLine.replace(/\r$/, '');
|
|
41
|
+
if (!inBlock) {
|
|
42
|
+
if (matchBlockHeader(line, 'auto-dream')) inBlock = true;
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (line.length > 0 && !/^\s/.test(line)) break;
|
|
46
|
+
blockLines.push(line);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (blockLines.length === 0) return defaults;
|
|
50
|
+
|
|
51
|
+
let minConfidence = 0.5;
|
|
52
|
+
|
|
53
|
+
for (const rawLine of blockLines) {
|
|
54
|
+
const clean = rawLine.replace(/\s*#.*$/, '').replace(/\s+$/, '');
|
|
55
|
+
if (!clean.trim()) continue;
|
|
56
|
+
|
|
57
|
+
const kvMatch = clean.match(/^\s+([a-zA-Z_-]+):\s*(.*)/);
|
|
58
|
+
if (!kvMatch) continue;
|
|
59
|
+
|
|
60
|
+
const k = kvMatch[1];
|
|
61
|
+
let v = kvMatch[2].trim();
|
|
62
|
+
if (v.startsWith('"') && v.endsWith('"') && v.length >= 2) v = v.slice(1, -1);
|
|
63
|
+
else if (v.startsWith("'") && v.endsWith("'") && v.length >= 2) v = v.slice(1, -1);
|
|
64
|
+
|
|
65
|
+
if (k === 'min-confidence') {
|
|
66
|
+
// Float-range validation copied verbatim from vault-mirror-quality.mjs:69-73.
|
|
67
|
+
if (/^\d+(\.\d+)?$/.test(v)) {
|
|
68
|
+
const f = parseFloat(v);
|
|
69
|
+
if (Number.isFinite(f) && f >= 0.0 && f <= 1.0) minConfidence = f;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
'min-confidence': minConfidence,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* block-header.mjs — Shared bold-tolerant top-level block-header matcher (#830).
|
|
3
|
+
*
|
|
4
|
+
* Session Config blocks in CLAUDE.md / AGENTS.md may render as a bold-bullet
|
|
5
|
+
* `- **key:**` markdown form rather than a plain `key:` line. Parsers that used
|
|
6
|
+
* the strict `/^<key>:\s*$/` regex silently MISSED the bold form → the block was
|
|
7
|
+
* never entered → all defaults applied with no error surfaced anywhere. #823
|
|
8
|
+
* fixed only vault-integration.mjs; this module generalises the tolerance so
|
|
9
|
+
* every block parser matches the same set of header forms.
|
|
10
|
+
*
|
|
11
|
+
* ZERO IMPORTS by design: tests/lib/config/cycle-guard.test.mjs forbids any
|
|
12
|
+
* scripts/lib/config/*.mjs from importing ../config.mjs. This module keeps a
|
|
13
|
+
* clean leaf with no dependencies at all so every sub-parser can adopt it
|
|
14
|
+
* without any cycle risk.
|
|
15
|
+
*
|
|
16
|
+
* RAW-PARITY constraint (#830 / claude-md-drift-check): the checker imports these
|
|
17
|
+
* parsers directly and feeds RAW file content. Normalisation therefore lives
|
|
18
|
+
* INSIDE the helper each parser calls — never in a preprocessing step in
|
|
19
|
+
* config.mjs — so both the config.mjs path and the direct-import checker path
|
|
20
|
+
* see identical tolerance by construction.
|
|
21
|
+
*
|
|
22
|
+
* LOAD-BEARING semantics — the accepted / rejected form set is a contract:
|
|
23
|
+
* MATCH (top-level block header for `key`), each with optional trailing ws:
|
|
24
|
+
* key: - key: **key:** - **key:**
|
|
25
|
+
* NO MATCH (intentionally):
|
|
26
|
+
* key: value — a header carrying a value is not a block-opener
|
|
27
|
+
* key: # note — inline comment on the header line (the documented
|
|
28
|
+
* custom-phases / eval gotcha stays broken-by-design)
|
|
29
|
+
* ' key:' — indented line (a sub-key of some other block)
|
|
30
|
+
* other-key: — a different key
|
|
31
|
+
*
|
|
32
|
+
* The two `**` markers are independent (`**key:` and `key:**` both match),
|
|
33
|
+
* mirroring the tolerant #823 vault-integration regex.
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Escape regex metacharacters in a literal key so a key like `a.b` or `a+b`
|
|
38
|
+
* is matched literally rather than as a pattern. Defensive: current keys are
|
|
39
|
+
* plain `[a-z-]` slugs (`-` is a literal outside a character class), but the
|
|
40
|
+
* dynamic callers (persona-gate-wave / wave-reviewers) pass a variable `key`.
|
|
41
|
+
*
|
|
42
|
+
* @param {string} s
|
|
43
|
+
* @returns {string}
|
|
44
|
+
*/
|
|
45
|
+
function escapeRegExp(s) {
|
|
46
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Build the single-line block-header regex for a key.
|
|
51
|
+
*
|
|
52
|
+
* Equivalent to: `^(?:-\s+)?(?:\*\*)?<key>:(?:\*\*)?\s*$`. Not multiline — it is
|
|
53
|
+
* tested against one already-split line.
|
|
54
|
+
*
|
|
55
|
+
* @param {string} key
|
|
56
|
+
* @returns {RegExp}
|
|
57
|
+
*/
|
|
58
|
+
function blockHeaderRe(key) {
|
|
59
|
+
return new RegExp('^(?:-\\s+)?(?:\\*\\*)?' + escapeRegExp(key) + ':(?:\\*\\*)?\\s*$');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* True when `line` opens the top-level block for `key` — tolerant of the
|
|
64
|
+
* bold-bullet markdown rendering (`- **key:**`). Pure boolean, no side effects.
|
|
65
|
+
*
|
|
66
|
+
* @param {string} line — a single line (callers strip the trailing `\n`; a stray
|
|
67
|
+
* trailing `\r` is tolerated by the `\s*$` tail)
|
|
68
|
+
* @param {string} key — the literal block key (e.g. 'eval', 'broken-window-budget')
|
|
69
|
+
* @returns {boolean}
|
|
70
|
+
*/
|
|
71
|
+
export function matchBlockHeader(line, key) {
|
|
72
|
+
if (typeof line !== 'string' || typeof key !== 'string' || key === '') return false;
|
|
73
|
+
return blockHeaderRe(key).test(line);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Multiline presence variant: true when ANY line of `content` opens the
|
|
78
|
+
* top-level block for `key`. For whole-file PRESENCE guards (e.g.
|
|
79
|
+
* dispatcher-autonomy-capture's `BLOCK_HEADER_RE`). Pure boolean.
|
|
80
|
+
*
|
|
81
|
+
* @param {string} content — full file contents
|
|
82
|
+
* @param {string} key
|
|
83
|
+
* @returns {boolean}
|
|
84
|
+
*/
|
|
85
|
+
export function hasBlockHeader(content, key) {
|
|
86
|
+
if (typeof content !== 'string' || content === '' || typeof key !== 'string' || key === '') {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
const re = blockHeaderRe(key);
|
|
90
|
+
for (const rawLine of content.split(/\r?\n/)) {
|
|
91
|
+
if (re.test(rawLine)) return true;
|
|
92
|
+
}
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { matchBlockHeader } from './block-header.mjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* broken-window.mjs — Parser for the top-level `broken-window-budget:` YAML block
|
|
5
|
+
* (#730 Epic H / H5 — "Broken-Window Budget").
|
|
6
|
+
*
|
|
7
|
+
* Drives session-end Phase 2.6: a "shipped-but-broken" shipment (Full-Gate PASS
|
|
8
|
+
* with documented exceptions, overridden findings) mechanically files a
|
|
9
|
+
* hard-terminated closure issue + Override-Ratio tracking via events.jsonl.
|
|
10
|
+
*
|
|
11
|
+
* Returns `{ enabled, "due-days" }`.
|
|
12
|
+
* Tolerant parser: malformed values silently fall back to defaults, EXCEPT
|
|
13
|
+
* `due-days` — a malformed, non-positive, or non-integer value emits a stderr
|
|
14
|
+
* WARN before falling back (mirrors the handover-gate `max-open-questions`
|
|
15
|
+
* WARN discipline: a runtime-critical bound deserves a loud fallback).
|
|
16
|
+
*
|
|
17
|
+
* Consumer: `scripts/lib/config.mjs`, `skills/session-end/SKILL.md` Phase 2.6.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
// Upper bound for due-days (~10 years). Guards against Date#setUTCDate
|
|
21
|
+
// overflowing into an Invalid Date downstream (#794 GAP-4).
|
|
22
|
+
const MAX_DUE_DAYS = 3650;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Parse the top-level `broken-window-budget:` YAML block from markdown content.
|
|
26
|
+
* Independent of the `## Session Config` section boundary.
|
|
27
|
+
*
|
|
28
|
+
* Defaults:
|
|
29
|
+
* enabled: false (opt-in — the whole Phase 2.6 is silent when disabled)
|
|
30
|
+
* due-days: 7 (integer >= 1 and <= 3650 [~10 years]; the closure issue's hard
|
|
31
|
+
* due-date = today + this). Malformed, non-integer, < 1, or > 3650
|
|
32
|
+
* input falls back to 7 and emits a stderr WARN. The upper bound
|
|
33
|
+
* guards against `Date#setUTCDate` overflowing into an Invalid Date
|
|
34
|
+
* (RangeError on `.toISOString()` downstream in
|
|
35
|
+
* `spiral-carryover.mjs` `computeDueDate` — #794 GAP-4).
|
|
36
|
+
*
|
|
37
|
+
* YAML shape:
|
|
38
|
+
* broken-window-budget:
|
|
39
|
+
* enabled: false
|
|
40
|
+
* due-days: 7
|
|
41
|
+
*
|
|
42
|
+
* @param {string} content — full file contents
|
|
43
|
+
* @returns {{ enabled: boolean, "due-days": number }}
|
|
44
|
+
*/
|
|
45
|
+
export function _parseBrokenWindow(content) {
|
|
46
|
+
const defaults = {
|
|
47
|
+
enabled: false,
|
|
48
|
+
'due-days': 7,
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const lines = String(content ?? '').split(/\r?\n/);
|
|
52
|
+
let inBlock = false;
|
|
53
|
+
const blockLines = [];
|
|
54
|
+
|
|
55
|
+
for (const rawLine of lines) {
|
|
56
|
+
const line = rawLine.replace(/\r$/, '');
|
|
57
|
+
if (!inBlock) {
|
|
58
|
+
if (matchBlockHeader(line, 'broken-window-budget')) inBlock = true;
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
// Stop at next column-0 non-empty line (sibling top-level key or H2 heading)
|
|
62
|
+
if (line.length > 0 && !/^\s/.test(line)) break;
|
|
63
|
+
blockLines.push(line);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (blockLines.length === 0) return defaults;
|
|
67
|
+
|
|
68
|
+
let enabled = false;
|
|
69
|
+
let dueDays = 7;
|
|
70
|
+
|
|
71
|
+
for (const rawLine of blockLines) {
|
|
72
|
+
// Strip inline comments and trailing whitespace
|
|
73
|
+
const clean = rawLine.replace(/\s*#.*$/, '').replace(/\s+$/, '');
|
|
74
|
+
if (!clean.trim()) continue;
|
|
75
|
+
|
|
76
|
+
const kvMatch = clean.match(/^\s+([a-zA-Z_-]+):\s*(.*)/);
|
|
77
|
+
if (!kvMatch) continue;
|
|
78
|
+
|
|
79
|
+
const k = kvMatch[1];
|
|
80
|
+
let v = kvMatch[2].trim();
|
|
81
|
+
if (v.startsWith('"') && v.endsWith('"') && v.length >= 2) v = v.slice(1, -1);
|
|
82
|
+
else if (v.startsWith("'") && v.endsWith("'") && v.length >= 2) v = v.slice(1, -1);
|
|
83
|
+
|
|
84
|
+
switch (k) {
|
|
85
|
+
case 'enabled':
|
|
86
|
+
// Default is false → only flip to true on explicit "true"
|
|
87
|
+
enabled = v.toLowerCase() === 'true';
|
|
88
|
+
break;
|
|
89
|
+
|
|
90
|
+
case 'due-days': {
|
|
91
|
+
const parsed = /^\d+$/.test(v) ? parseInt(v, 10) : NaN;
|
|
92
|
+
if (Number.isInteger(parsed) && parsed >= 1 && parsed <= MAX_DUE_DAYS) {
|
|
93
|
+
// Positive integer within bounds (>= 1 — a 0-day due-date is
|
|
94
|
+
// nonsensical for a hard-terminated closure issue; <= MAX_DUE_DAYS —
|
|
95
|
+
// guards against Date overflow downstream, #794 GAP-4).
|
|
96
|
+
dueDays = parsed;
|
|
97
|
+
} else {
|
|
98
|
+
// Malformed (non-numeric, empty), non-integer, < 1, or > MAX_DUE_DAYS
|
|
99
|
+
// — emit a stderr WARN on this fallback path (handover-gate parity).
|
|
100
|
+
process.stderr.write(
|
|
101
|
+
`⚠ broken-window-budget.due-days: '${v}' invalid — falling back to 7\n`
|
|
102
|
+
);
|
|
103
|
+
dueDays = 7;
|
|
104
|
+
}
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
enabled,
|
|
112
|
+
'due-days': dueDays,
|
|
113
|
+
};
|
|
114
|
+
}
|