session-orchestrator 3.23.0 → 4.0.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/.agents/skills/architecture/SKILL.md +18 -0
- package/.agents/skills/autopilot/SKILL.md +17 -0
- package/.agents/skills/bootstrap/SKILL.md +20 -0
- package/.agents/skills/brainstorm/SKILL.md +22 -0
- package/.agents/skills/claude-md-drift-check/SKILL.md +15 -0
- package/.agents/skills/convergence-monitoring/SKILL.md +22 -0
- package/.agents/skills/debug/SKILL.md +22 -0
- package/.agents/skills/discovery/SKILL.md +20 -0
- package/.agents/skills/dispatcher/SKILL.md +15 -0
- package/.agents/skills/docs-orchestrator/SKILL.md +18 -0
- package/.agents/skills/ecosystem-health/SKILL.md +20 -0
- package/.agents/skills/eli5/SKILL.md +20 -0
- package/.agents/skills/eval/SKILL.md +21 -0
- package/.agents/skills/evolve/SKILL.md +21 -0
- package/.agents/skills/frontmatter-guard/SKILL.md +15 -0
- package/.agents/skills/gitlab-ops/SKILL.md +20 -0
- package/.agents/skills/gitlab-portfolio/SKILL.md +15 -0
- package/.agents/skills/grill/SKILL.md +22 -0
- package/.agents/skills/hook-development/SKILL.md +15 -0
- package/.agents/skills/mcp-builder/SKILL.md +15 -0
- package/.agents/skills/memory-cleanup/SKILL.md +21 -0
- package/.agents/skills/mode-selector/SKILL.md +17 -0
- package/.agents/skills/npm-publish/SKILL.md +16 -0
- package/.agents/skills/peekaboo-driver/SKILL.md +18 -0
- package/.agents/skills/persona-panel/SKILL.md +17 -0
- package/.agents/skills/plan/SKILL.md +20 -0
- package/.agents/skills/playwright-driver/SKILL.md +20 -0
- package/.agents/skills/quality-gates/SKILL.md +20 -0
- package/.agents/skills/reconcile/SKILL.md +21 -0
- package/.agents/skills/remote-offload/SKILL.md +20 -0
- package/.agents/skills/repo-audit/SKILL.md +16 -0
- package/.agents/skills/session-end/SKILL.md +20 -0
- package/.agents/skills/session-plan/SKILL.md +20 -0
- package/.agents/skills/session-start/SKILL.md +20 -0
- package/.agents/skills/spinout/SKILL.md +16 -0
- package/.agents/skills/sunset-review/SKILL.md +16 -0
- package/.agents/skills/test-runner/SKILL.md +20 -0
- package/.agents/skills/tmux-layout/SKILL.md +21 -0
- package/.agents/skills/using-orchestrator/SKILL.md +17 -0
- package/.agents/skills/vault-mirror/SKILL.md +15 -0
- package/.agents/skills/vault-sync/SKILL.md +15 -0
- package/.agents/skills/wave-executor/SKILL.md +20 -0
- package/.agents/skills/write-executable-plan/SKILL.md +22 -0
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.cursor/commands/autopilot.md +2 -2
- package/.cursor/commands/bootstrap.md +1 -1
- package/.cursor/commands/brainstorm.md +1 -1
- package/.cursor/commands/debug.md +1 -1
- package/.cursor/commands/discovery.md +1 -1
- package/.cursor/commands/dispatcher.md +2 -2
- package/.cursor/commands/eli5.md +2 -2
- package/.cursor/commands/eval.md +2 -2
- package/.cursor/commands/evolve.md +1 -1
- package/.cursor/commands/go.md +1 -1
- package/.cursor/commands/grill.md +2 -2
- package/.cursor/commands/memory-cleanup.md +2 -2
- package/.cursor/commands/persona-panel.md +1 -1
- package/.cursor/commands/plan.md +1 -1
- package/.cursor/commands/portfolio.md +1 -1
- package/.cursor/commands/reconcile.md +2 -2
- package/.cursor/commands/release.md +2 -2
- package/.cursor/commands/session.md +2 -2
- package/.cursor/commands/spinout.md +2 -2
- package/.cursor/commands/sunset-review.md +2 -2
- package/.cursor/commands/templates-ack.md +2 -2
- package/.cursor/commands/test.md +2 -2
- package/.cursor/skills/brainstorm/SKILL.md +1 -1
- package/.cursor/skills/eval/SKILL.md +1 -1
- package/.cursor/skills/quality-gates/SKILL.md +1 -1
- package/.cursor/skills/remote-offload/SKILL.md +13 -0
- package/.orchestrator/policy/blocked-commands.json +121 -0
- package/.orchestrator/policy/ecosystem.schema.json +66 -0
- package/.orchestrator/policy/quality-gates.example.json +16 -0
- package/.orchestrator/policy/quality-gates.schema.json +38 -0
- package/.orchestrator/policy/templates-policy.json +27 -0
- package/.orchestrator/policy/test-profiles.json +47 -0
- package/AGENTS.md +225 -0
- package/CHANGELOG.md +1401 -0
- package/NOTICE +11 -6
- package/README.md +127 -92
- package/agents/db-specialist.md +0 -1
- package/agents/eval-judge.md +1 -1
- package/agents/skill-applied-judge.md +1 -1
- package/assets/wave-lifecycle.svg +98 -0
- package/commands/release.md +6 -3
- package/commands/session.md +18 -3
- package/docs/README.md +4 -0
- package/{agents/AGENTS.md → docs/agent-authoring.md} +19 -26
- package/docs/baseline.md +67 -0
- package/docs/ci-setup.md +249 -48
- package/docs/codex-setup.md +66 -22
- package/docs/components.md +37 -16
- package/docs/cursor-setup.md +6 -2
- package/docs/events-schema.md +51 -10
- package/docs/instruction-delivery.md +62 -0
- package/{agents/memory-proposal-collector.md → docs/memory-proposal-flow.md} +1 -8
- package/docs/migration-v4.md +341 -0
- package/docs/pi-setup.md +6 -1
- package/docs/plugin-architecture-v3.md +1 -1
- package/docs/rule-authoring.md +85 -19
- package/docs/scope-collision-guard.md +8 -8
- package/docs/session-config-reference.md +120 -61
- package/docs/session-config-template.md +40 -33
- package/docs/telemetry/telemetry-claims.md +11 -10
- package/docs/telemetry.md +187 -4
- package/docs/vault-docs-architecture.md +50 -11
- package/hooks/_lib/atomic-json.mjs +111 -0
- package/hooks/_lib/hook-import-set.json +1487 -0
- package/hooks/_lib/subagent-paths.mjs +143 -0
- package/hooks/_lib/subagent-transcript.mjs +562 -0
- package/hooks/config-protection.mjs +2 -2
- package/hooks/cwd-change-restore.mjs +11 -31
- package/hooks/enforce-commands.mjs +69 -0
- package/hooks/enforce-scope.mjs +35 -6
- package/hooks/hooks-codex.json +1 -1
- package/hooks/hooks-cursor.json +10 -0
- package/hooks/hooks-pi.json +5 -0
- package/hooks/hooks.json +6 -1
- package/hooks/loop-guard.mjs +3 -3
- package/hooks/on-session-end.mjs +280 -14
- package/hooks/on-session-start.mjs +153 -4
- package/hooks/on-stop.mjs +371 -17
- package/hooks/operator-steer.mjs +2 -2
- package/hooks/post-bash-write-verify.mjs +189 -4
- package/hooks/post-edit-import-probe.mjs +344 -0
- package/hooks/post-subagent-discovery-validator.mjs +278 -392
- package/hooks/post-tool-batch-wave-signal.mjs +272 -44
- package/hooks/post-tool-failure-corrective-context.mjs +11 -34
- package/hooks/post-tooluse-frontend-slop.mjs +3 -3
- package/hooks/pre-bash-destructive-guard.mjs +39 -13
- package/hooks/pre-bash-memory-propose-audit.mjs +13 -7
- package/hooks/skill-invocation-telemetry.mjs +17 -5
- package/hooks/subagent-telemetry.mjs +24 -30
- package/monitors/monitors.json +3 -3
- package/package.json +9 -1
- package/pi/prompts/session.md +2 -2
- package/plugin.json +27 -0
- package/scripts/autopilot.mjs +26 -12
- package/scripts/backfill-abandoned-sessions.mjs +130 -15
- package/scripts/backfill-learnings-from-vault.mjs +9 -3
- package/scripts/dialectic-deriver.mjs +73 -8
- package/scripts/emit-event.mjs +10 -2
- package/scripts/export-hw-learnings.mjs +113 -1
- package/scripts/generate-agents-skills.mjs +378 -0
- package/scripts/generate-cursor-adapter.mjs +45 -8
- package/scripts/generate-hook-import-set.mjs +249 -0
- package/scripts/lib/agent-status.mjs +13 -2
- package/scripts/lib/auq/parse.mjs +5 -29
- package/scripts/lib/auto-dialectic.mjs +68 -0
- package/scripts/lib/auto-dream.mjs +38 -36
- package/scripts/lib/autonomy/suitability.mjs +6 -0
- package/scripts/lib/autopilot/loop.mjs +2 -2
- package/scripts/lib/autopilot/worktree-pipeline.mjs +82 -6
- package/scripts/lib/build-live-signals.mjs +25 -22
- package/scripts/lib/ci-status-banner.mjs +220 -75
- package/scripts/lib/codex/plugin-contract.mjs +82 -6
- package/scripts/lib/cold-start-detector.mjs +23 -14
- package/scripts/lib/config/auto-dream.mjs +2 -1
- package/scripts/lib/config/block-header.mjs +63 -0
- package/scripts/lib/config/block-preprocess.mjs +177 -0
- package/scripts/lib/config/broken-window.mjs +2 -1
- package/scripts/lib/config/cold-start.mjs +2 -1
- package/scripts/lib/config/config-protection.mjs +22 -2
- package/scripts/lib/config/context-coverage.mjs +2 -1
- package/scripts/lib/config/cross-repo.mjs +2 -1
- package/scripts/lib/config/custom-phases.mjs +2 -1
- package/scripts/lib/config/dialectic.mjs +2 -1
- package/scripts/lib/config/discovery-validator.mjs +9 -3
- package/scripts/lib/config/dispatcher-autonomy-capture.mjs +24 -1
- package/scripts/lib/config/dispatcher-autonomy.mjs +2 -1
- package/scripts/lib/config/docs-orchestrator.mjs +2 -1
- package/scripts/lib/config/docs-staleness.mjs +2 -1
- package/scripts/lib/config/drift-check.mjs +2 -1
- package/scripts/lib/config/eval.mjs +2 -1
- package/scripts/lib/config/events-rotation.mjs +2 -1
- package/scripts/lib/config/evolve.mjs +8 -2
- package/scripts/lib/config/frontend-slop-hook.mjs +7 -3
- package/scripts/lib/config/gitlab-portfolio.mjs +2 -1
- package/scripts/lib/config/handover-gate.mjs +2 -1
- package/scripts/lib/config/health-endpoints.mjs +388 -0
- package/scripts/lib/config/issue-budget.mjs +2 -1
- package/scripts/lib/config/loop-guard.mjs +2 -1
- package/scripts/lib/config/memory.mjs +2 -1
- package/scripts/lib/config/moc-staleness.mjs +2 -1
- package/scripts/lib/config/persona-gate-wave.mjs +2 -1
- package/scripts/lib/config/private-config-dir.mjs +67 -0
- package/scripts/lib/config/reconcile.mjs +2 -1
- package/scripts/lib/config/remote-hosts.mjs +234 -0
- package/scripts/lib/config/section-extractor.mjs +7 -1
- package/scripts/lib/config/skill-evolution.mjs +2 -1
- package/scripts/lib/config/slopcheck.mjs +2 -1
- package/scripts/lib/config/state-md-lock.mjs +2 -1
- package/scripts/lib/config/templates-first.mjs +2 -1
- package/scripts/lib/config/test.mjs +2 -1
- package/scripts/lib/config/vault-integration.mjs +7 -1
- package/scripts/lib/config/vault-mirror-quality.mjs +2 -1
- package/scripts/lib/config/vault-staleness.mjs +2 -1
- package/scripts/lib/config/vault-sync.mjs +2 -1
- package/scripts/lib/config/verification-auto-fix.mjs +2 -1
- package/scripts/lib/config/wave-reviewers.mjs +2 -1
- package/scripts/lib/config/worktree-orphans.mjs +2 -1
- package/scripts/lib/config.mjs +31 -3
- package/scripts/lib/convergence-monitor.mjs +82 -16
- package/scripts/lib/dispatcher/enumerate.mjs +2 -17
- package/scripts/lib/dispatcher/rank.mjs +124 -48
- package/scripts/lib/ecosystem-health.mjs +16 -2
- package/scripts/lib/eval/engine.mjs +9 -1
- package/scripts/lib/eval/session-resolve.mjs +23 -4
- package/scripts/lib/events-schema.mjs +48 -0
- package/scripts/lib/events.mjs +256 -7
- package/scripts/lib/evolve/autonomy-verdict.mjs +9 -4
- package/scripts/lib/evolve/autopilot-effectiveness.mjs +18 -1
- package/scripts/lib/frontmatter-guard.mjs +131 -13
- package/scripts/lib/gates/gate-full.mjs +26 -0
- package/scripts/lib/gates/gate-helpers.mjs +76 -0
- package/scripts/lib/gitlab-portfolio/cli.mjs +3 -15
- package/scripts/lib/hardware-pattern-detector.mjs +18 -1
- package/scripts/lib/harness-audit/categories/category1.mjs +17 -6
- package/scripts/lib/harness-audit/categories/category4.mjs +31 -11
- package/scripts/lib/host-identity.mjs +50 -11
- package/scripts/lib/instruction-budget-guard.mjs +171 -5
- package/scripts/lib/learnings/evolve-telemetry.mjs +178 -0
- package/scripts/lib/learnings/io.mjs +60 -6
- package/scripts/lib/memory-banner.mjs +20 -8
- package/scripts/lib/memory-proposals/store.mjs +30 -22
- package/scripts/lib/owner-config-banner.mjs +43 -6
- package/scripts/lib/owner-config-loader.mjs +21 -10
- package/scripts/lib/owner-interview.mjs +3 -3
- package/scripts/lib/owner-yaml.mjs +207 -14
- package/scripts/lib/peer-discovery.mjs +20 -2
- package/scripts/lib/platform.mjs +108 -15
- package/scripts/lib/plugin-update-banner.mjs +406 -0
- package/scripts/lib/project-hygiene.mjs +38 -2
- package/scripts/lib/qg-command-drift-banner.mjs +50 -12
- package/scripts/lib/quality-gate.mjs +133 -44
- package/scripts/lib/reconcile/emitter.mjs +68 -6
- package/scripts/lib/reconcile/engine.mjs +249 -9
- package/scripts/lib/reconcile/idempotency.mjs +37 -4
- package/scripts/lib/reconcile/writer.mjs +40 -18
- package/scripts/lib/scope-gate.mjs +36 -0
- package/scripts/lib/session-close-backfill.mjs +125 -18
- package/scripts/lib/session-discovery.mjs +57 -3
- package/scripts/lib/session-end/phase-skip.mjs +2 -2
- package/scripts/lib/session-id.mjs +12 -23
- package/scripts/lib/session-identity/own-session.mjs +187 -11
- package/scripts/lib/session-lock-shape.mjs +43 -0
- package/scripts/lib/session-lock.mjs +5 -10
- package/scripts/lib/session-registry.mjs +25 -9
- package/scripts/lib/session-schema/constants.mjs +36 -2
- package/scripts/lib/session-schema/validator.mjs +38 -4
- package/scripts/lib/session-start-probes.mjs +18 -1
- package/scripts/lib/session-transition.mjs +1 -1
- package/scripts/lib/sessions-canonical.mjs +446 -0
- package/scripts/lib/sessions-staleness-banner.mjs +18 -11
- package/scripts/lib/skill-health/join.mjs +17 -4
- package/scripts/lib/state-md.mjs +78 -0
- package/scripts/lib/sunset/walker.mjs +6 -0
- package/scripts/lib/telemetry/schema.mjs +255 -17
- package/scripts/lib/telemetry/sync.mjs +417 -24
- package/scripts/lib/tmux-layout/telemetry.mjs +14 -2
- package/scripts/lib/validate/check-agents-skills.mjs +327 -0
- package/scripts/lib/validate/check-agents.mjs +3 -3
- package/scripts/lib/validate/check-cursor-adapter.mjs +234 -72
- package/scripts/lib/validate/check-doc-cli-commands.mjs +9 -33
- package/scripts/lib/validate/check-hooks-emit-event-guard.mjs +370 -0
- package/scripts/lib/validate/check-hooks-symmetry.mjs +45 -16
- package/scripts/lib/validate/check-owner-leakage.mjs +281 -20
- package/scripts/lib/validate/check-skill-links.mjs +163 -0
- package/scripts/lib/validate/check-skill-script-paths.mjs +455 -0
- package/scripts/lib/validate/check-untracked-test-deps.mjs +10 -0
- package/scripts/lib/validate/check-unwired-features.mjs +0 -9
- package/scripts/lib/validate/check-validator-registration.mjs +254 -0
- package/scripts/lib/validate/check-vcs-repo-flag.mjs +6 -28
- package/scripts/lib/validate/enumerate-repo-files.mjs +317 -0
- package/scripts/lib/validate/markdown-fences.mjs +196 -0
- package/scripts/lib/vault-backfill/template.mjs +63 -6
- package/scripts/lib/vault-mirror/process.mjs +165 -42
- package/scripts/lib/vault-mirror/telemetry.mjs +2 -2
- package/scripts/lib/vault-status/board-lock.mjs +185 -0
- package/scripts/lib/vault-status/board-writer.mjs +174 -135
- package/scripts/lib/vault-status/narrative-mirror.mjs +129 -37
- package/scripts/lib/wave-executor/dispatch-common.mjs +164 -0
- package/scripts/lib/wave-executor/foreign-dispatch.mjs +7 -142
- package/scripts/lib/wave-executor/remote-dispatch.mjs +502 -0
- package/scripts/lib/wave-resource-gate.mjs +133 -7
- package/scripts/lib/wave-sizing.mjs +4 -1
- package/scripts/lib/wave-transcript-tail.mjs +142 -8
- package/scripts/materialize-wave-scope.mjs +32 -9
- package/scripts/memory-propose.mjs +146 -8
- package/scripts/migrate-cold-start-seed.mjs +4 -1
- package/scripts/parse-config.mjs +60 -3
- package/scripts/promote-vault-strict.mjs +4 -15
- package/scripts/release.mjs +337 -29
- package/scripts/repair-invalid-sessions.mjs +3 -3
- package/scripts/run-quality-gate.mjs +128 -11
- package/scripts/site-numbers.mjs +36 -4
- package/scripts/sweep-expired-learnings.mjs +90 -0
- package/scripts/sync-vault-schema.mjs +3 -1
- package/scripts/telemetry.mjs +2 -2
- package/scripts/validate-plugin.mjs +187 -0
- package/scripts/validate-wave-scope.mjs +28 -8
- package/scripts/vault-consolidate.mjs +3 -11
- package/scripts/vault-integration-watcher.mjs +2 -4
- package/scripts/vault-mirror.mjs +111 -26
- package/scripts/wave-scope-binding.mjs +215 -0
- package/skills/_shared/instruction-file-resolution.md +10 -0
- package/skills/_shared/parallel-aware-auq.md +31 -2
- package/skills/_shared/parallel-aware-preamble.md +18 -4
- package/skills/_shared/platform-tools.md +1 -1
- package/skills/_shared/state-ownership.md +1 -1
- package/skills/architecture/SKILL.md +7 -5
- package/skills/{domain-model/SKILL.md → architecture/references/domain-model.md} +9 -9
- package/skills/autopilot/SKILL.md +4 -18
- package/skills/claude-md-drift-check/SKILL.md +5 -1
- package/skills/claude-md-drift-check/checker.mjs +62 -2
- package/skills/convergence-monitoring/SIGNALS.md +55 -0
- package/skills/discovery/probes/vault-staleness.mjs +37 -13
- package/skills/discovery/probes-arch.md +20 -18
- package/skills/dispatcher/SKILL.md +3 -2
- package/skills/ecosystem-health/SKILL.md +4 -1
- package/skills/ecosystem-health/wizard.md +5 -0
- package/skills/evolve/SKILL.md +87 -11
- package/skills/frontmatter-guard/SKILL.md +11 -5
- package/skills/npm-publish/SKILL.md +1 -1
- package/skills/reconcile/SKILL.md +38 -2
- package/skills/remote-offload/SKILL.md +89 -0
- package/skills/session-end/SKILL.md +18 -905
- package/skills/session-end/phase-3-6-tail.md +19 -9
- package/skills/session-end/plan-verification.md +221 -155
- package/skills/session-end/references/phase-2-quality-gate.md +93 -0
- package/skills/session-end/references/phase-3-documentation-updates.md +229 -0
- package/skills/session-end/references/phase-4a-worktree-cleanup.md +120 -0
- package/skills/session-end/references/phase-4b-worktree-orphan-sweep.md +58 -0
- package/skills/session-end/references/phase-5-issue-cleanup.md +104 -0
- package/skills/session-end/references/session-summary-template.md +62 -0
- package/skills/session-plan/SKILL.md +49 -0
- package/skills/session-start/SKILL.md +41 -900
- package/skills/session-start/phase-8-5-express-path.md +1 -1
- package/skills/session-start/references/phase-1-1-dispatcher-autonomy-capture.md +55 -0
- package/skills/session-start/references/phase-1-2-session-lock.md +140 -0
- package/skills/session-start/references/phase-1-5-session-continuity.md +254 -0
- package/skills/session-start/references/phase-1-7-vault-status-board.md +53 -0
- package/skills/session-start/references/phase-2-7-portfolio-snapshot.md +75 -0
- package/skills/session-start/references/phase-4-ssot-environment-check.md +155 -0
- package/skills/session-start/references/phase-6-5-forced-reads.md +75 -0
- package/skills/session-start/references/phase-6-6-project-intelligence.md +81 -0
- package/skills/session-start/references/phase-6-7-memory-banner-telemetry-consent.md +103 -0
- package/skills/vault-sync/validator.mjs +21 -27
- package/skills/wave-executor/SKILL.md +16 -2
- package/skills/wave-executor/references/wave-loop-dispatch.md +612 -0
- package/skills/wave-executor/references/wave-loop-review.md +570 -0
- package/skills/wave-executor/references/wave-loop-scope-manifest.md +162 -0
- package/skills/wave-executor/wave-loop.md +14 -1271
- package/templates/_shared/journey-manifest.md +10 -6
- package/.cursor/commands/autopilot-multi.md +0 -14
- package/.cursor/commands/contract-version-bump.md +0 -14
- package/.cursor/commands/journey-audit.md +0 -14
- package/.cursor/skills/contract-version-bump/SKILL.md +0 -12
- package/.cursor/skills/daily/SKILL.md +0 -12
- package/.cursor/skills/domain-model/SKILL.md +0 -13
- package/.cursor/skills/journey-audit/SKILL.md +0 -13
- package/.cursor/skills/skill-creator/SKILL.md +0 -13
- package/.cursor/skills/ubiquitous-language/SKILL.md +0 -13
- package/commands/autopilot-multi.md +0 -74
- package/commands/contract-version-bump.md +0 -28
- package/commands/journey-audit.md +0 -43
- package/pi/prompts/autopilot-multi.md +0 -12
- package/pi/prompts/contract-version-bump.md +0 -12
- package/pi/prompts/journey-audit.md +0 -12
- package/scripts/autopilot-multi.mjs +0 -885
- package/scripts/backfill-learnings-expires.mjs +0 -196
- package/scripts/backfill-learnings.mjs +0 -203
- package/scripts/fleet-instruction-scan.mjs +0 -141
- package/scripts/lib/autopilot/dep-graph.mjs +0 -417
- package/scripts/lib/autopilot/multi-killswitch.mjs +0 -184
- package/scripts/lib/webhook-url.mjs +0 -105
- package/scripts/lifecycle-sim-v6.mjs +0 -347
- package/scripts/migrate-learnings-jsonl.mjs +0 -189
- package/scripts/migrate-subagents-jsonl.mjs +0 -196
- package/scripts/upload-social-preview.mjs +0 -316
- package/skills/_shared/model-selection.md +0 -64
- package/skills/contract-version-bump/SKILL.md +0 -219
- package/skills/daily/SKILL.md +0 -222
- package/skills/daily/generate.sh +0 -92
- package/skills/daily/templates/daily.md.tpl +0 -36
- package/skills/journey-audit/SKILL.md +0 -269
- package/skills/skill-creator/SKILL.md +0 -168
- package/skills/ubiquitous-language/SKILL.md +0 -97
- package/skills/vault-sync/package-lock.json +0 -40
- /package/skills/{domain-model → architecture/references}/ADR-FORMAT.md +0 -0
- /package/skills/{domain-model → architecture/references}/CONTEXT-FORMAT.md +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { matchBlockHeader } from './block-header.mjs';
|
|
2
|
+
import { preprocessBlockLines } from './block-preprocess.mjs';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* moc-staleness.mjs — Parser for the top-level `moc-staleness:` YAML block.
|
|
@@ -31,7 +32,7 @@ export function _parseMocStaleness(content) {
|
|
|
31
32
|
mode: 'warn',
|
|
32
33
|
};
|
|
33
34
|
|
|
34
|
-
const lines = content
|
|
35
|
+
const lines = preprocessBlockLines(content);
|
|
35
36
|
let inBlock = false;
|
|
36
37
|
const blockLines = [];
|
|
37
38
|
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
import { parseThreshold } from '../persona-panel/threshold.mjs';
|
|
21
21
|
import { ALLOWED_MODEL_ALIASES, MODEL_ID_RE } from '../agent-frontmatter.mjs';
|
|
22
22
|
import { matchBlockHeader } from './block-header.mjs';
|
|
23
|
+
import { preprocessBlockLines } from './block-preprocess.mjs';
|
|
23
24
|
|
|
24
25
|
const ALLOWED_AFTER = new Set(['quality', 'impl-polish']);
|
|
25
26
|
const ALLOWED_MODE = new Set(['off', 'warn', 'strict']);
|
|
@@ -169,7 +170,7 @@ export function _normalizePersonaGateWave(parsed) {
|
|
|
169
170
|
* @returns {string[]}
|
|
170
171
|
*/
|
|
171
172
|
function _extractBlock(content, key) {
|
|
172
|
-
const lines = content
|
|
173
|
+
const lines = preprocessBlockLines(content);
|
|
173
174
|
const blockLines = [];
|
|
174
175
|
let inBlock = false;
|
|
175
176
|
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* private-config-dir.mjs — THE resolver for the host-private config directory (#1223).
|
|
3
|
+
*
|
|
4
|
+
* Every per-host artefact below that directory (`host-private.json`,
|
|
5
|
+
* `owner.yaml`, the self-alias ledger) moves with it, so the precedence has to
|
|
6
|
+
* live in exactly ONE place. Before #1223 three copies with three different
|
|
7
|
+
* precedences existed: `owner-yaml.mjs`'s import-time homedir-only
|
|
8
|
+
* `OWNER_YAML_PATH`, `owner-config-loader.mjs`'s XDG-only + untrimmed
|
|
9
|
+
* `resolveOwnerConfigPath()`, and `host-identity.mjs`'s `_privateDir()`. The
|
|
10
|
+
* live consequence: `SO_CONFIG_HOME=<sandbox>` moved the alias ledger but NOT
|
|
11
|
+
* owner.yaml, which kept being read from the operator's REAL home — the
|
|
12
|
+
* CLAUDE.md (Codex CLI alias: AGENTS.md) "vault-dir resolves HOST-LOCALLY"
|
|
13
|
+
* hazard class.
|
|
14
|
+
*
|
|
15
|
+
* ── Why this is a standalone ZERO-IMPORT leaf ────────────────────────────────
|
|
16
|
+
*
|
|
17
|
+
* Two independent consumers constrain it, and neither tolerates the other's
|
|
18
|
+
* import graph:
|
|
19
|
+
*
|
|
20
|
+
* 1. `host-identity.mjs` is reachable from LIVE hooks (via `session-lock.mjs`),
|
|
21
|
+
* `hooks/on-stop.mjs` among them. on-stop must degrade with one actionable
|
|
22
|
+
* line when `node_modules` is absent (GH#63), so nothing on ITS subgraph —
|
|
23
|
+
* this leaf included — may pull a bare specifier. Putting the resolver in
|
|
24
|
+
* `owner-yaml.mjs` dragged `js-yaml` onto that subgraph and turned the GH#63
|
|
25
|
+
* contract red with `ERR_MODULE_NOT_FOUND: Cannot find package 'js-yaml'`.
|
|
26
|
+
* Since GitLab #1230 (2026-09-06) `owner-yaml.mjs` resolves `js-yaml`
|
|
27
|
+
* lazily, so that particular collision can no longer recur — but the
|
|
28
|
+
* constraint on THIS file is unchanged, because it is what let the resolver
|
|
29
|
+
* be shared in the first place. Measured 2026-09-06 over a `hooks/` +
|
|
30
|
+
* `scripts/` copy with no `node_modules`, the four hooks that reach
|
|
31
|
+
* `owner-yaml.mjs` (on-session-start, on-session-end, post-edit-validate,
|
|
32
|
+
* skill-invocation-telemetry) now load instead of throwing.
|
|
33
|
+
* 2. `tests/husky/pre-commit-owner-leakage.test.mjs` copies the CP11 scanner's
|
|
34
|
+
* import chain FILE BY FILE into a tmp repo. Every repo-local import added
|
|
35
|
+
* to a file on that chain must be added to the copied-file list there.
|
|
36
|
+
*
|
|
37
|
+
* Hence: `node:os` + `node:path` only. No repo-local imports, no bare
|
|
38
|
+
* specifiers beyond the two Node builtins.
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
import { homedir } from 'node:os';
|
|
42
|
+
import { join } from 'node:path';
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Resolve the host-private config directory.
|
|
46
|
+
*
|
|
47
|
+
* Precedence, most specific first: `SO_CONFIG_HOME` names the private dir
|
|
48
|
+
* ITSELF; `XDG_CONFIG_HOME` names its PARENT (the `session-orchestrator`
|
|
49
|
+
* segment is appended); without either, `~/.config/session-orchestrator`.
|
|
50
|
+
*
|
|
51
|
+
* `.trim() || fallback` throughout — a whitespace-only env var is truthy and
|
|
52
|
+
* would short-circuit a bare `||`, returning the spaces verbatim
|
|
53
|
+
* (`.claude/rules/development.md` § Error Handling, env-var fallback
|
|
54
|
+
* whitespace trap).
|
|
55
|
+
*
|
|
56
|
+
* Reads env at CALL time, so a test may stub `process.env` after import.
|
|
57
|
+
*
|
|
58
|
+
* @param {{ env?: Record<string, string|undefined> }} [opts]
|
|
59
|
+
* @returns {string} absolute path to the host-private config directory
|
|
60
|
+
*/
|
|
61
|
+
export function resolvePrivateConfigDir({ env = process.env } = {}) {
|
|
62
|
+
const own = (env.SO_CONFIG_HOME || '').trim();
|
|
63
|
+
if (own) return own;
|
|
64
|
+
const xdg = (env.XDG_CONFIG_HOME || '').trim();
|
|
65
|
+
if (xdg) return join(xdg, 'session-orchestrator');
|
|
66
|
+
return join(homedir(), '.config', 'session-orchestrator');
|
|
67
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { matchBlockHeader } from './block-header.mjs';
|
|
2
|
+
import { preprocessBlockLines } from './block-preprocess.mjs';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* reconcile.mjs — Parser for the top-level `reconcile:` YAML block.
|
|
@@ -169,7 +170,7 @@ export function _parseReconcile(content) {
|
|
|
169
170
|
'max-proposals-per-run': 10,
|
|
170
171
|
};
|
|
171
172
|
|
|
172
|
-
const lines = content
|
|
173
|
+
const lines = preprocessBlockLines(content);
|
|
173
174
|
let inBlock = false;
|
|
174
175
|
const blockLines = [];
|
|
175
176
|
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { matchBlockHeader } from './block-header.mjs';
|
|
2
|
+
import { preprocessBlockLinesNoDash } from './block-preprocess.mjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* remote-hosts.mjs — Parser for the `remote-hosts:` Session Config block (#1160).
|
|
6
|
+
*
|
|
7
|
+
* Lets a repo DECLARE ssh-reachable hosts that heavy wave roles (test / ui / perf)
|
|
8
|
+
* may be offloaded to instead of shrinking the wave under local resource pressure.
|
|
9
|
+
* This module only declares — it never probes the network, never dispatches, and
|
|
10
|
+
* never decides. Placement is `scripts/lib/wave-resource-gate.mjs`; the dispatch
|
|
11
|
+
* adapter lives in `scripts/lib/wave-executor/`.
|
|
12
|
+
*
|
|
13
|
+
* Exports:
|
|
14
|
+
* REMOTE_HOST_DEFAULTS — per-host defaults
|
|
15
|
+
* ALLOWED_REMOTE_ROLES — the agent-mapping roles a host may accept
|
|
16
|
+
* _parseRemoteHosts(content) — PURE, no side effects beyond a stderr WARN when a
|
|
17
|
+
* record is dropped. Returns [] when absent/empty.
|
|
18
|
+
*
|
|
19
|
+
* Block shape:
|
|
20
|
+
* remote-hosts:
|
|
21
|
+
* - alias: m5 # required; becomes `-H <alias>` argv
|
|
22
|
+
* roles-allowed: [test, ui, perf] # subset of ALLOWED_REMOTE_ROLES
|
|
23
|
+
* repo-path: ~/Projects/Alice # optional
|
|
24
|
+
* claude-path: ~/.local/bin/claude # optional
|
|
25
|
+
*
|
|
26
|
+
* Modelled on custom-phases.mjs (per-entry SAFE-regex validation, drop-with-warn,
|
|
27
|
+
* column-0 block termination, silent enum fallback). The one shape it adds is the
|
|
28
|
+
* inline `[a, b]` list for `roles-allowed`.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
/** Per-host defaults. */
|
|
32
|
+
export const REMOTE_HOST_DEFAULTS = Object.freeze({
|
|
33
|
+
'roles-allowed': ['test', 'ui', 'perf'],
|
|
34
|
+
'repo-path': null,
|
|
35
|
+
'claude-path': null,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The roles a remote host may accept. A deliberate SUBSET of `ALLOWED_ROLES` in
|
|
40
|
+
* scripts/lib/config.mjs — impl / db / security / compliance / docs stay local.
|
|
41
|
+
*
|
|
42
|
+
* NOT the wave-role enum ("Impl-Core", "Quality", …): those are two different
|
|
43
|
+
* enums and conflating them is the documented trap (see resolveApwCap's docstring
|
|
44
|
+
* in wave-resource-gate.mjs). The wave→agent-mapping-role translation is
|
|
45
|
+
* `OFFLOADABLE_WAVE_ROLES` in that same module.
|
|
46
|
+
*
|
|
47
|
+
* @type {readonly string[]}
|
|
48
|
+
*/
|
|
49
|
+
export const ALLOWED_REMOTE_ROLES = Object.freeze(['test', 'ui', 'perf']);
|
|
50
|
+
|
|
51
|
+
// A host `alias` is an ssh destination that reaches argv as `-H <alias>`: letters,
|
|
52
|
+
// digits, hyphen, underscore, dot only. No spaces, no shell metacharacters.
|
|
53
|
+
//
|
|
54
|
+
// The first character is anchored separately from the rest because a charset
|
|
55
|
+
// cannot express a POSITION: an alias of `-H` passes any hyphen-inclusive
|
|
56
|
+
// allowlist and then reaches argv as an OPTION token, where the CLI swallows the
|
|
57
|
+
// operand behind it. Interior hyphens (`m5-box`) stay legal.
|
|
58
|
+
const SAFE_NAME_RE = /^[A-Za-z0-9._][A-Za-z0-9._-]*$/;
|
|
59
|
+
|
|
60
|
+
// `repo-path` / `claude-path` are filesystem paths handed to a remote shell —
|
|
61
|
+
// same allowlist as custom-phases' `review`, with the same leading-hyphen anchor
|
|
62
|
+
// as SAFE_NAME_RE above (`--x` is a flag, not a path).
|
|
63
|
+
const SAFE_PATH_RE = /^[A-Za-z0-9._~/][A-Za-z0-9._~/-]*$/;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Parse the top-level `remote-hosts:` YAML list block from markdown content.
|
|
67
|
+
*
|
|
68
|
+
* A record missing `alias`, or carrying an unsafe `alias` / `repo-path` /
|
|
69
|
+
* `claude-path`, is DROPPED with a stderr WARN. Unknown entries in
|
|
70
|
+
* `roles-allowed` are filtered out with a WARN; a record whose list is empty
|
|
71
|
+
* after filtering is dropped (it could never be selected anyway).
|
|
72
|
+
*
|
|
73
|
+
* @param {string} content — full CLAUDE.md / AGENTS.md file content
|
|
74
|
+
* @returns {Array<{alias: string, 'roles-allowed': string[], 'repo-path': string|null, 'claude-path': string|null}>}
|
|
75
|
+
*/
|
|
76
|
+
export function _parseRemoteHosts(content) {
|
|
77
|
+
const lines = preprocessBlockLinesNoDash(String(content ?? ''));
|
|
78
|
+
let inBlock = false;
|
|
79
|
+
const blockLines = [];
|
|
80
|
+
|
|
81
|
+
for (const rawLine of lines) {
|
|
82
|
+
const line = rawLine.replace(/\r$/, '');
|
|
83
|
+
|
|
84
|
+
if (!inBlock) {
|
|
85
|
+
if (matchBlockHeader(line, 'remote-hosts')) inBlock = true;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Block terminates at the first non-indented, non-empty line (next top-level key).
|
|
90
|
+
if (line.length > 0 && !/^\s/.test(line)) break;
|
|
91
|
+
|
|
92
|
+
blockLines.push(line);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (blockLines.length === 0) return [];
|
|
96
|
+
|
|
97
|
+
const records = [];
|
|
98
|
+
/** @type {Record<string, string>|null} */
|
|
99
|
+
let current = null;
|
|
100
|
+
|
|
101
|
+
const flush = () => {
|
|
102
|
+
if (current === null) return;
|
|
103
|
+
const rec = _validateRecord(current);
|
|
104
|
+
if (rec !== null) records.push(rec);
|
|
105
|
+
current = null;
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
for (const rawLine of blockLines) {
|
|
109
|
+
// Strip inline comments + trailing whitespace, preserve leading indent.
|
|
110
|
+
const clean = rawLine.replace(/\s*#.*$/, '').replace(/\s+$/, '');
|
|
111
|
+
if (!clean.trim()) continue;
|
|
112
|
+
|
|
113
|
+
const dashMatch = clean.match(/^\s*-\s+(.*)$/);
|
|
114
|
+
if (dashMatch) {
|
|
115
|
+
flush();
|
|
116
|
+
current = {};
|
|
117
|
+
const inlineKv = dashMatch[1].match(/^([a-zA-Z][a-zA-Z0-9_-]*):\s*(.*)$/);
|
|
118
|
+
if (inlineKv) _assignKv(current, inlineKv[1], inlineKv[2]);
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const kvMatch = clean.match(/^\s+([a-zA-Z][a-zA-Z0-9_-]*):\s*(.*)$/);
|
|
123
|
+
if (kvMatch && current !== null) {
|
|
124
|
+
_assignKv(current, kvMatch[1], kvMatch[2]);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
flush();
|
|
129
|
+
|
|
130
|
+
return records;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Assign a raw key/value onto a record being built, stripping surrounding quotes.
|
|
135
|
+
* Unknown keys are silently ignored (additive-friendly).
|
|
136
|
+
*
|
|
137
|
+
* @param {Record<string, string>} record
|
|
138
|
+
* @param {string} key
|
|
139
|
+
* @param {string} rawValue
|
|
140
|
+
*/
|
|
141
|
+
function _assignKv(record, key, rawValue) {
|
|
142
|
+
let v = rawValue.trim();
|
|
143
|
+
if (v.startsWith('"') && v.endsWith('"') && v.length >= 2) v = v.slice(1, -1);
|
|
144
|
+
else if (v.startsWith("'") && v.endsWith("'") && v.length >= 2) v = v.slice(1, -1);
|
|
145
|
+
|
|
146
|
+
switch (key) {
|
|
147
|
+
case 'alias':
|
|
148
|
+
case 'roles-allowed':
|
|
149
|
+
case 'repo-path':
|
|
150
|
+
case 'claude-path':
|
|
151
|
+
record[key] = v;
|
|
152
|
+
break;
|
|
153
|
+
default:
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Parse an inline `[a, b]` (or bare `a, b`) list into trimmed non-empty strings.
|
|
160
|
+
*
|
|
161
|
+
* @param {string} raw
|
|
162
|
+
* @returns {string[]}
|
|
163
|
+
*/
|
|
164
|
+
function _parseInlineList(raw) {
|
|
165
|
+
const inner = raw.trim().replace(/^\[/, '').replace(/\]$/, '');
|
|
166
|
+
return inner
|
|
167
|
+
.split(',')
|
|
168
|
+
.map((s) => s.trim().replace(/^["']|["']$/g, ''))
|
|
169
|
+
.filter((s) => s !== '');
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Validate + normalise a raw record.
|
|
174
|
+
*
|
|
175
|
+
* @param {Record<string, string>} raw
|
|
176
|
+
* @returns {{alias: string, 'roles-allowed': string[], 'repo-path': string|null, 'claude-path': string|null}|null}
|
|
177
|
+
*/
|
|
178
|
+
function _validateRecord(raw) {
|
|
179
|
+
const alias = (raw.alias ?? '').trim();
|
|
180
|
+
if (alias === '') {
|
|
181
|
+
process.stderr.write('remote-hosts: dropped record missing required field: alias\n');
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
if (!SAFE_NAME_RE.test(alias)) {
|
|
185
|
+
process.stderr.write(
|
|
186
|
+
`remote-hosts: dropped record with unsafe alias: ${JSON.stringify(alias)}\n`,
|
|
187
|
+
);
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
let rolesAllowed = [...REMOTE_HOST_DEFAULTS['roles-allowed']];
|
|
192
|
+
const rawRoles = (raw['roles-allowed'] ?? '').trim();
|
|
193
|
+
if (rawRoles !== '') {
|
|
194
|
+
const declared = _parseInlineList(rawRoles);
|
|
195
|
+
const kept = declared.filter((r) => ALLOWED_REMOTE_ROLES.includes(r));
|
|
196
|
+
const dropped = declared.filter((r) => !ALLOWED_REMOTE_ROLES.includes(r));
|
|
197
|
+
if (dropped.length > 0) {
|
|
198
|
+
process.stderr.write(
|
|
199
|
+
`remote-hosts: host '${alias}' declares unknown role(s) ${dropped.join(', ')} ` +
|
|
200
|
+
`(allowed: ${ALLOWED_REMOTE_ROLES.join(', ')}) — ignored\n`,
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
if (kept.length === 0) {
|
|
204
|
+
process.stderr.write(
|
|
205
|
+
`remote-hosts: dropped record '${alias}' — roles-allowed is empty after filtering\n`,
|
|
206
|
+
);
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
rolesAllowed = kept;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const paths = {};
|
|
213
|
+
for (const key of ['repo-path', 'claude-path']) {
|
|
214
|
+
let value = REMOTE_HOST_DEFAULTS[key];
|
|
215
|
+
const rawPath = (raw[key] ?? '').trim();
|
|
216
|
+
if (rawPath !== '' && rawPath !== 'null' && rawPath !== 'none') {
|
|
217
|
+
if (!SAFE_PATH_RE.test(rawPath)) {
|
|
218
|
+
process.stderr.write(
|
|
219
|
+
`remote-hosts: dropped record '${alias}' with shell metacharacter in ${key}: ${JSON.stringify(rawPath)}\n`,
|
|
220
|
+
);
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
value = rawPath;
|
|
224
|
+
}
|
|
225
|
+
paths[key] = value;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return {
|
|
229
|
+
alias,
|
|
230
|
+
'roles-allowed': rolesAllowed,
|
|
231
|
+
'repo-path': paths['repo-path'],
|
|
232
|
+
'claude-path': paths['claude-path'],
|
|
233
|
+
};
|
|
234
|
+
}
|
|
@@ -214,10 +214,16 @@ function isCodeFence(line) {
|
|
|
214
214
|
* this repo's own convention encourages. Revisit if a fleet CLAUDE.md is ever
|
|
215
215
|
* measured opening a multi-line comment after a value.
|
|
216
216
|
*
|
|
217
|
+
* EXPORTED since #1162 for a third consumer: `block-preprocess.mjs`, which
|
|
218
|
+
* gives the ~36 block parsers under `scripts/lib/config/` the same
|
|
219
|
+
* commented-out-is-not-live-config semantics. Same argument as the export of
|
|
220
|
+
* `isSessionConfigHeading` — a fourth copy of this state machine that drifts
|
|
221
|
+
* loose is worse than no check at all. Behaviour is unchanged by the export.
|
|
222
|
+
*
|
|
217
223
|
* @returns {(line: string) => boolean} true when the line is inside (or opens)
|
|
218
224
|
* a multi-line HTML comment and must be ignored by both consumers.
|
|
219
225
|
*/
|
|
220
|
-
function htmlCommentSkipper() {
|
|
226
|
+
export function htmlCommentSkipper() {
|
|
221
227
|
let inComment = false;
|
|
222
228
|
return function skipHtmlComment(line) {
|
|
223
229
|
if (inComment) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { matchBlockHeader } from './block-header.mjs';
|
|
2
|
+
import { preprocessBlockLines } from './block-preprocess.mjs';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* skill-evolution.mjs — Parser for the top-level `skill-evolution:` YAML block
|
|
@@ -39,7 +40,7 @@ export function _parseSkillEvolution(content) {
|
|
|
39
40
|
'judge-budget-tokens': 8000,
|
|
40
41
|
};
|
|
41
42
|
|
|
42
|
-
const lines = content
|
|
43
|
+
const lines = preprocessBlockLines(content);
|
|
43
44
|
let inBlock = false;
|
|
44
45
|
const blockLines = [];
|
|
45
46
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { matchBlockHeader } from './block-header.mjs';
|
|
2
|
+
import { preprocessBlockLines } from './block-preprocess.mjs';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* slopcheck.mjs — Parser for the top-level `slopcheck:` YAML block
|
|
@@ -36,7 +37,7 @@ export function _parseSlopcheck(content) {
|
|
|
36
37
|
sources: [...DEFAULT_SOURCES],
|
|
37
38
|
};
|
|
38
39
|
|
|
39
|
-
const lines = content
|
|
40
|
+
const lines = preprocessBlockLines(content);
|
|
40
41
|
let inBlock = false;
|
|
41
42
|
const blockLines = [];
|
|
42
43
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { matchBlockHeader } from './block-header.mjs';
|
|
2
|
+
import { preprocessBlockLines } from './block-preprocess.mjs';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* state-md-lock.mjs — Parser for the top-level `state-md-lock:` YAML block
|
|
@@ -30,7 +31,7 @@ export function _parseStateMdLock(content) {
|
|
|
30
31
|
'timeout-ms': 10000,
|
|
31
32
|
};
|
|
32
33
|
|
|
33
|
-
const lines = content
|
|
34
|
+
const lines = preprocessBlockLines(content);
|
|
34
35
|
let inBlock = false;
|
|
35
36
|
const blockLines = [];
|
|
36
37
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { matchBlockHeader } from './block-header.mjs';
|
|
2
|
+
import { preprocessBlockLines } from './block-preprocess.mjs';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* templates-first.mjs — Parser for the top-level `templates-first:` YAML block
|
|
@@ -34,7 +35,7 @@ export function _parseTemplatesFirst(content) {
|
|
|
34
35
|
hosts: [...DEFAULT_HOSTS],
|
|
35
36
|
};
|
|
36
37
|
|
|
37
|
-
const lines = content
|
|
38
|
+
const lines = preprocessBlockLines(content);
|
|
38
39
|
let inBlock = false;
|
|
39
40
|
const blockLines = [];
|
|
40
41
|
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import { validatePathInsideProject } from '../path-utils.mjs';
|
|
10
10
|
import { matchBlockHeader } from './block-header.mjs';
|
|
11
|
+
import { preprocessBlockLines } from './block-preprocess.mjs';
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* Parse the top-level `test:` YAML block from markdown content.
|
|
@@ -27,7 +28,7 @@ export function _parseTest(content) {
|
|
|
27
28
|
'retention-days': 30,
|
|
28
29
|
};
|
|
29
30
|
|
|
30
|
-
const lines = content
|
|
31
|
+
const lines = preprocessBlockLines(content);
|
|
31
32
|
let inBlock = false;
|
|
32
33
|
const blockLines = [];
|
|
33
34
|
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
|
|
23
23
|
import { _coerceBoolean, _coerceInteger } from './coercers.mjs';
|
|
24
24
|
import { matchBlockHeader } from './block-header.mjs';
|
|
25
|
+
import { preprocessBlockLines } from './block-preprocess.mjs';
|
|
25
26
|
|
|
26
27
|
// ---------------------------------------------------------------------------
|
|
27
28
|
// vault-integration
|
|
@@ -68,7 +69,12 @@ export function _parseVaultIntegration(content) {
|
|
|
68
69
|
const defaults = { enabled: false, 'vault-dir': null, mode: 'warn', 'vault-name': null };
|
|
69
70
|
if (typeof content !== 'string' || content === '') return defaults;
|
|
70
71
|
|
|
71
|
-
|
|
72
|
+
// #1162: NOT a raw split. `preprocessBlockLines` drops HTML-commented lines
|
|
73
|
+
// (a commented-out block was read as live config) and rewrites bold-bullet
|
|
74
|
+
// sub-keys (`- **enabled:** true` fell back to the `false` default). This
|
|
75
|
+
// parser has no dash-RECORD body, so the bold pass is safe here — see the
|
|
76
|
+
// named risk in block-preprocess.mjs.
|
|
77
|
+
const lines = preprocessBlockLines(content);
|
|
72
78
|
|
|
73
79
|
// Pass 1: inline-object form. Matches `vault-integration: { ... }` with or
|
|
74
80
|
// without a leading `- ` (baseline list-item form per #497).
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { matchBlockHeader } from './block-header.mjs';
|
|
2
|
+
import { preprocessBlockLines } from './block-preprocess.mjs';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* vault-mirror-quality.mjs — Parser for the top-level `vault-mirror:` YAML block,
|
|
@@ -30,7 +31,7 @@ export function _parseVaultMirrorQuality(content) {
|
|
|
30
31
|
},
|
|
31
32
|
};
|
|
32
33
|
|
|
33
|
-
const lines = content
|
|
34
|
+
const lines = preprocessBlockLines(content);
|
|
34
35
|
let inBlock = false;
|
|
35
36
|
const blockLines = [];
|
|
36
37
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { matchBlockHeader } from './block-header.mjs';
|
|
2
|
+
import { preprocessBlockLines } from './block-preprocess.mjs';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* vault-staleness.mjs — Parser for the top-level `vault-staleness:` YAML block.
|
|
@@ -17,7 +18,7 @@ export function _parseVaultStaleness(content) {
|
|
|
17
18
|
mode: 'warn',
|
|
18
19
|
};
|
|
19
20
|
|
|
20
|
-
const lines = content
|
|
21
|
+
const lines = preprocessBlockLines(content);
|
|
21
22
|
let inBlock = false;
|
|
22
23
|
const blockLines = [];
|
|
23
24
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { matchBlockHeader } from './block-header.mjs';
|
|
2
|
+
import { preprocessBlockLines } from './block-preprocess.mjs';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* vault-sync.mjs — Parser for the top-level `vault-sync:` YAML block.
|
|
@@ -16,7 +17,7 @@ import { matchBlockHeader } from './block-header.mjs';
|
|
|
16
17
|
export function _parseVaultSync(content) {
|
|
17
18
|
const defaults = { enabled: false, mode: 'warn', 'vault-dir': null, exclude: [] };
|
|
18
19
|
|
|
19
|
-
const lines = content
|
|
20
|
+
const lines = preprocessBlockLines(content);
|
|
20
21
|
let inBlock = false;
|
|
21
22
|
const blockLines = [];
|
|
22
23
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { matchBlockHeader } from './block-header.mjs';
|
|
2
|
+
import { preprocessBlockLines } from './block-preprocess.mjs';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* verification-auto-fix.mjs — Parser for the top-level `verification-auto-fix:`
|
|
@@ -31,7 +32,7 @@ export function _parseVerificationAutoFix(content) {
|
|
|
31
32
|
'max-retries': 2,
|
|
32
33
|
};
|
|
33
34
|
|
|
34
|
-
const lines = content
|
|
35
|
+
const lines = preprocessBlockLines(content);
|
|
35
36
|
let inBlock = false;
|
|
36
37
|
const blockLines = [];
|
|
37
38
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { matchBlockHeader } from './block-header.mjs';
|
|
2
|
+
import { preprocessBlockLines } from './block-preprocess.mjs';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* wave-reviewers.mjs — Parser for the `wave-reviewers` / `persona-reviewers` sub-block.
|
|
@@ -58,7 +59,7 @@ export function _parseWaveReviewers(content) {
|
|
|
58
59
|
* @returns {string[]}
|
|
59
60
|
*/
|
|
60
61
|
function _extractBlock(content, key) {
|
|
61
|
-
const lines = content
|
|
62
|
+
const lines = preprocessBlockLines(content);
|
|
62
63
|
const blockLines = [];
|
|
63
64
|
let inBlock = false;
|
|
64
65
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { matchBlockHeader } from './block-header.mjs';
|
|
2
|
+
import { preprocessBlockLines } from './block-preprocess.mjs';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* worktree-orphans.mjs — Parser for the top-level `worktree-orphans:` YAML block.
|
|
@@ -85,7 +86,7 @@ export function _parseWorktreeOrphans(content) {
|
|
|
85
86
|
|
|
86
87
|
if (typeof content !== 'string' || content === '') return defaults;
|
|
87
88
|
|
|
88
|
-
const lines = content
|
|
89
|
+
const lines = preprocessBlockLines(content);
|
|
89
90
|
let inBlock = false;
|
|
90
91
|
const blockLines = [];
|
|
91
92
|
|
package/scripts/lib/config.mjs
CHANGED
|
@@ -61,6 +61,7 @@ import { _parseAutoDream } from './config/auto-dream.mjs';
|
|
|
61
61
|
import { _parseStateMdLock } from './config/state-md-lock.mjs';
|
|
62
62
|
import { _parseHandoverGate } from './config/handover-gate.mjs';
|
|
63
63
|
import { _parseIssueBudget } from './config/issue-budget.mjs';
|
|
64
|
+
import { _parseHealthEndpoints, _parseEcosystemHealthBlockEnabled } from './config/health-endpoints.mjs';
|
|
64
65
|
import { _parseBrokenWindow } from './config/broken-window.mjs';
|
|
65
66
|
import { _parseSlopcheck } from './config/slopcheck.mjs';
|
|
66
67
|
import { _parseDiscoveryValidator } from './config/discovery-validator.mjs';
|
|
@@ -71,6 +72,7 @@ import { _parseEval } from './config/eval.mjs';
|
|
|
71
72
|
import { _parseMemory } from './config/memory.mjs';
|
|
72
73
|
import { _parseReconcile } from './config/reconcile.mjs';
|
|
73
74
|
import { _parseCustomPhases } from './config/custom-phases.mjs';
|
|
75
|
+
import { _parseRemoteHosts } from './config/remote-hosts.mjs';
|
|
74
76
|
import { _parseEvolve, _parseEvolveDecay } from './config/evolve.mjs';
|
|
75
77
|
import { _parseSkillEvolution } from './config/skill-evolution.mjs';
|
|
76
78
|
import { _parseDispatcherAutonomy, resolveDispatcherAutonomy } from './config/dispatcher-autonomy.mjs';
|
|
@@ -198,7 +200,14 @@ export function parseSessionConfig(mdContent, { hostPaths } = {}) {
|
|
|
198
200
|
|
|
199
201
|
// Boolean fields
|
|
200
202
|
const persistence = _coerceBoolean(kv, 'persistence', true);
|
|
201
|
-
|
|
203
|
+
// ecosystem-health has TWO spellings and only the scalar one reaches `kv`:
|
|
204
|
+
// the wizard writes a valueless `ecosystem-health:` header opening a block,
|
|
205
|
+
// which carries no `key: value` pair and is therefore invisible to the KV
|
|
206
|
+
// map (#1174). Scalar wins when present; otherwise the block form decides.
|
|
207
|
+
const ecosystemHealth =
|
|
208
|
+
_getVal(kv, 'ecosystem-health', undefined) !== undefined
|
|
209
|
+
? _coerceBoolean(kv, 'ecosystem-health', false)
|
|
210
|
+
: (_parseEcosystemHealthBlockEnabled(mdContent) ?? false);
|
|
202
211
|
const discoveryOnClose = _coerceBoolean(kv, 'discovery-on-close', false);
|
|
203
212
|
const reasoningOutput = _coerceBoolean(kv, 'reasoning-output', false);
|
|
204
213
|
const groundingCheck = _coerceBoolean(kv, 'grounding-check', true);
|
|
@@ -214,7 +223,6 @@ export function parseSessionConfig(mdContent, { hostPaths } = {}) {
|
|
|
214
223
|
const ssotFiles = _coerceList(kv, 'ssot-files', undefined);
|
|
215
224
|
const discoveryProbes = _coerceList(kv, 'discovery-probes', '[all]');
|
|
216
225
|
const discoveryExcludePaths = _coerceList(kv, 'discovery-exclude-paths', '[]');
|
|
217
|
-
const healthEndpoints = _coerceList(kv, 'health-endpoints', undefined);
|
|
218
226
|
const worktreeExclude = _coerceList(
|
|
219
227
|
kv,
|
|
220
228
|
'worktree-exclude',
|
|
@@ -230,6 +238,11 @@ export function parseSessionConfig(mdContent, { hostPaths } = {}) {
|
|
|
230
238
|
// follow-up (see docs/session-config-reference.md). This wires the parser + value only.
|
|
231
239
|
const worktreeCleanup = _coerceEnum(kv, 'worktree-cleanup', 'default', ['default', 'aggressive']);
|
|
232
240
|
|
|
241
|
+
// remote-hosts: opt-in ssh-reachable hosts heavy roles may be offloaded to (#1160).
|
|
242
|
+
// Parsed HERE, before agent-mapping, because the `ssh:<alias>` channel below
|
|
243
|
+
// validates its target against the declared aliases. Defaults to [].
|
|
244
|
+
const remoteHosts = _parseRemoteHosts(mdContent);
|
|
245
|
+
|
|
233
246
|
// Object fields
|
|
234
247
|
const agentMapping = _coerceObject(kv, 'agent-mapping');
|
|
235
248
|
if (agentMapping !== null) {
|
|
@@ -240,10 +253,11 @@ export function parseSessionConfig(mdContent, { hostPaths } = {}) {
|
|
|
240
253
|
// dispatched natively, exactly as before.
|
|
241
254
|
// impl: code-implementer → native Agent dispatch (unchanged)
|
|
242
255
|
// impl: cursor:composer-2.5 → foreign model over the Cursor channel
|
|
256
|
+
// test: ssh:m5 → same Claude, another host (#1160)
|
|
243
257
|
// An unknown prefix is a typo or a channel this build cannot route, and
|
|
244
258
|
// must fail loudly: silently accepting it would dispatch to an agent that
|
|
245
259
|
// does not exist, which surfaces only as an empty wave much later.
|
|
246
|
-
const KNOWN_CHANNELS = ['cursor', 'session-orchestrator'];
|
|
260
|
+
const KNOWN_CHANNELS = ['cursor', 'session-orchestrator', 'ssh'];
|
|
247
261
|
// Accumulate every defect, then report once. A config with two bad entries
|
|
248
262
|
// must name BOTH — throwing on the first one makes the operator re-run the
|
|
249
263
|
// parse per defect, and each re-run hides the ones behind it.
|
|
@@ -272,6 +286,15 @@ export function parseSessionConfig(mdContent, { hostPaths } = {}) {
|
|
|
272
286
|
`role '${k}' has channel '${channel}' but no target in value '${v}' ` +
|
|
273
287
|
`(expected '${channel}:<model-or-agent>')`
|
|
274
288
|
);
|
|
289
|
+
} else if (channel === 'ssh' && !remoteHosts.some((h) => h.alias === target)) {
|
|
290
|
+
// An ssh target is a host ALIAS, and the only place aliases are declared
|
|
291
|
+
// is the remote-hosts: block. An undeclared alias would reach argv as
|
|
292
|
+
// `-H <target>` and fail at connect time, one wave too late.
|
|
293
|
+
const declared = remoteHosts.map((h) => h.alias).join(', ') || 'none';
|
|
294
|
+
valueProblems.push(
|
|
295
|
+
`role '${k}' names ssh host '${target}' which is not declared in remote-hosts: ` +
|
|
296
|
+
`(declared: ${declared})`
|
|
297
|
+
);
|
|
275
298
|
}
|
|
276
299
|
}
|
|
277
300
|
}
|
|
@@ -442,6 +465,10 @@ export function parseSessionConfig(mdContent, { hostPaths } = {}) {
|
|
|
442
465
|
const evolveDecay = _parseEvolveDecay(mdContent);
|
|
443
466
|
|
|
444
467
|
// persona-gate-wave: opt-in mid-wave persona-panel hook (#458). Returns null when absent.
|
|
468
|
+
// health-endpoints: content-scoped (NOT _coerceList, which bails to null on
|
|
469
|
+
// any '{' and cannot see the wizard's nested block form at all) — #1174.
|
|
470
|
+
const healthEndpoints = _parseHealthEndpoints(mdContent);
|
|
471
|
+
|
|
445
472
|
const personaGateWave = _parsePersonaGateWave(mdContent);
|
|
446
473
|
if (personaGateWave !== null && personaGateWave.enabled === true && personaGateWave.mode === 'off') {
|
|
447
474
|
process.stderr.write(
|
|
@@ -538,6 +565,7 @@ export function parseSessionConfig(mdContent, { hostPaths } = {}) {
|
|
|
538
565
|
'wave-reviewers': waveReviewers,
|
|
539
566
|
'persona-gate-wave': personaGateWave,
|
|
540
567
|
'custom-phases': customPhases,
|
|
568
|
+
'remote-hosts': remoteHosts,
|
|
541
569
|
'evolve.extra-sources': evolveExtraSources,
|
|
542
570
|
'evolve.decay': evolveDecay,
|
|
543
571
|
};
|