session-orchestrator 3.24.0 → 4.0.1
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 +3 -2
- package/.codex-plugin/skills/architecture/SKILL.md +20 -0
- package/.codex-plugin/skills/autopilot/SKILL.md +21 -0
- package/.codex-plugin/skills/autopilot/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/bootstrap/SKILL.md +22 -0
- package/.codex-plugin/skills/bootstrap/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/brainstorm/SKILL.md +22 -0
- package/.codex-plugin/skills/brainstorm/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/claude-md-drift-check/SKILL.md +17 -0
- package/.codex-plugin/skills/close/SKILL.md +21 -0
- package/.codex-plugin/skills/close/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/convergence-monitoring/SKILL.md +24 -0
- package/.codex-plugin/skills/debug/SKILL.md +21 -0
- package/.codex-plugin/skills/debug/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/discovery/SKILL.md +21 -0
- package/.codex-plugin/skills/discovery/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/dispatcher/SKILL.md +21 -0
- package/.codex-plugin/skills/dispatcher/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/docs-orchestrator/SKILL.md +20 -0
- package/.codex-plugin/skills/ecosystem-health/SKILL.md +22 -0
- package/.codex-plugin/skills/eli5/SKILL.md +21 -0
- package/.codex-plugin/skills/eli5/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/eval/SKILL.md +21 -0
- package/.codex-plugin/skills/eval/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/evolve/SKILL.md +21 -0
- package/.codex-plugin/skills/evolve/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/frontmatter-guard/SKILL.md +17 -0
- package/.codex-plugin/skills/gitlab-ops/SKILL.md +22 -0
- package/.codex-plugin/skills/gitlab-portfolio/SKILL.md +17 -0
- package/.codex-plugin/skills/go/SKILL.md +22 -0
- package/.codex-plugin/skills/go/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/grill/SKILL.md +21 -0
- package/.codex-plugin/skills/grill/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/harness-audit/SKILL.md +19 -0
- package/.codex-plugin/skills/harness-audit/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/hook-development/SKILL.md +17 -0
- package/.codex-plugin/skills/mcp-builder/SKILL.md +17 -0
- package/.codex-plugin/skills/memory-cleanup/SKILL.md +21 -0
- package/.codex-plugin/skills/memory-cleanup/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/mode-selector/SKILL.md +19 -0
- package/.codex-plugin/skills/npm-publish/SKILL.md +18 -0
- package/.codex-plugin/skills/peekaboo-driver/SKILL.md +20 -0
- package/.codex-plugin/skills/persona-panel/SKILL.md +22 -0
- package/.codex-plugin/skills/persona-panel/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/plan/SKILL.md +22 -0
- package/.codex-plugin/skills/plan/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/playwright-driver/SKILL.md +22 -0
- package/.codex-plugin/skills/portfolio/SKILL.md +21 -0
- package/.codex-plugin/skills/portfolio/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/quality-gates/SKILL.md +22 -0
- package/.codex-plugin/skills/reconcile/SKILL.md +21 -0
- package/.codex-plugin/skills/reconcile/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/release/SKILL.md +22 -0
- package/.codex-plugin/skills/release/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/remote-offload/SKILL.md +22 -0
- package/.codex-plugin/skills/repo-audit/SKILL.md +19 -0
- package/.codex-plugin/skills/repo-audit/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/session/SKILL.md +21 -0
- package/.codex-plugin/skills/session/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/session-end/SKILL.md +22 -0
- package/.codex-plugin/skills/session-plan/SKILL.md +22 -0
- package/.codex-plugin/skills/session-start/SKILL.md +22 -0
- package/.codex-plugin/skills/spinout/SKILL.md +21 -0
- package/.codex-plugin/skills/spinout/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/sunset-review/SKILL.md +21 -0
- package/.codex-plugin/skills/sunset-review/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/templates-ack/SKILL.md +21 -0
- package/.codex-plugin/skills/templates-ack/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/test/SKILL.md +21 -0
- package/.codex-plugin/skills/test/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/test-runner/SKILL.md +22 -0
- package/.codex-plugin/skills/tmux-layout/SKILL.md +23 -0
- package/.codex-plugin/skills/using-orchestrator/SKILL.md +19 -0
- package/.codex-plugin/skills/vault-mirror/SKILL.md +17 -0
- package/.codex-plugin/skills/vault-sync/SKILL.md +17 -0
- package/.codex-plugin/skills/wave-executor/SKILL.md +22 -0
- package/.codex-plugin/skills/write-executable-plan/SKILL.md +24 -0
- 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 +1 -1
- package/.cursor-plugin/plugin.json +30 -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 +1314 -2
- package/NOTICE +11 -6
- package/README.md +135 -94
- 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 +108 -62
- package/docs/codex-setup.md +107 -29
- package/docs/components.md +38 -16
- package/docs/cursor-setup.md +6 -2
- package/docs/events-schema.md +9 -6
- package/docs/instruction-delivery.md +69 -0
- package/{agents/memory-proposal-collector.md → docs/memory-proposal-flow.md} +1 -8
- package/docs/migration-v4.md +365 -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 +5 -5
- package/docs/session-config-reference.md +57 -56
- package/docs/session-config-template.md +6 -29
- package/docs/telemetry.md +157 -3
- package/docs/vault-docs-architecture.md +50 -11
- package/hooks/_lib/hook-import-set.json +1488 -0
- package/hooks/_lib/subagent-transcript.mjs +562 -0
- package/hooks/config-protection.mjs +2 -2
- package/hooks/cwd-change-restore.mjs +2 -2
- package/hooks/enforce-commands.mjs +69 -0
- 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 +2 -2
- package/hooks/on-session-start.mjs +103 -2
- package/hooks/on-stop.mjs +60 -14
- package/hooks/operator-steer.mjs +2 -2
- package/hooks/post-bash-write-verify.mjs +85 -0
- package/hooks/post-edit-import-probe.mjs +344 -0
- package/hooks/post-subagent-discovery-validator.mjs +187 -431
- package/hooks/post-tool-batch-wave-signal.mjs +118 -4
- package/hooks/post-tool-failure-corrective-context.mjs +2 -2
- package/hooks/post-tooluse-frontend-slop.mjs +3 -3
- package/hooks/pre-bash-destructive-guard.mjs +39 -13
- package/hooks/skill-invocation-telemetry.mjs +17 -5
- package/hooks/subagent-telemetry.mjs +13 -4
- package/monitors/monitors.json +3 -3
- package/package.json +9 -1
- package/pi/prompts/session.md +2 -2
- package/scripts/backfill-abandoned-sessions.mjs +50 -4
- package/scripts/backfill-learnings-from-vault.mjs +9 -3
- package/scripts/dialectic-deriver.mjs +73 -8
- package/scripts/export-hw-learnings.mjs +113 -1
- package/scripts/generate-agents-skills.mjs +378 -0
- package/scripts/generate-codex-skills.mjs +246 -0
- package/scripts/generate-cursor-adapter.mjs +45 -8
- package/scripts/generate-hook-import-set.mjs +292 -0
- package/scripts/lib/agent-status.mjs +13 -2
- 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/ci-status-banner.mjs +220 -75
- package/scripts/lib/codex/plugin-contract.mjs +88 -6
- package/scripts/lib/config/auto-dream.mjs +2 -1
- package/scripts/lib/config/block-header.mjs +8 -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 +2 -1
- 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 +7 -2
- package/scripts/lib/config/host-paths.mjs +20 -4
- 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 +2 -1
- 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/convergence-monitor.mjs +82 -16
- 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.mjs +22 -6
- package/scripts/lib/frontmatter-guard.mjs +131 -13
- package/scripts/lib/gates/gate-full.mjs +30 -0
- package/scripts/lib/gates/gate-helpers.mjs +76 -0
- package/scripts/lib/hardware-pattern-detector.mjs +18 -1
- 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-proposals/store.mjs +30 -22
- package/scripts/lib/owner-config-banner.mjs +41 -6
- package/scripts/lib/owner-config-loader.mjs +21 -10
- package/scripts/lib/owner-interview.mjs +3 -3
- package/scripts/lib/owner-yaml.mjs +215 -15
- package/scripts/lib/platform.mjs +108 -15
- package/scripts/lib/plugin-update-banner.mjs +414 -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 +51 -11
- package/scripts/lib/reconcile/idempotency.mjs +37 -4
- package/scripts/lib/reconcile/writer.mjs +40 -18
- package/scripts/lib/session-close-backfill.mjs +67 -9
- package/scripts/lib/session-id.mjs +12 -23
- package/scripts/lib/session-identity/own-session.mjs +125 -10
- 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 +64 -3
- package/scripts/lib/session-schema/validator.mjs +38 -4
- package/scripts/lib/session-start-probes.mjs +30 -1
- 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 +202 -9
- package/scripts/lib/telemetry/sync.mjs +368 -12
- package/scripts/lib/telemetry-flush-health-banner.mjs +211 -0
- package/scripts/lib/validate/check-agents-skills.mjs +327 -0
- package/scripts/lib/validate/check-agents.mjs +3 -3
- package/scripts/lib/validate/check-codex-skills.mjs +191 -0
- package/scripts/lib/validate/check-cursor-adapter.mjs +234 -72
- package/scripts/lib/validate/check-hooks-symmetry.mjs +45 -16
- package/scripts/lib/validate/check-owner-leakage.mjs +319 -22
- package/scripts/lib/validate/check-skill-links.mjs +193 -0
- package/scripts/lib/validate/check-skill-script-paths.mjs +47 -28
- package/scripts/lib/validate/check-test-git-config-target.mjs +192 -12
- package/scripts/lib/validate/check-unwired-features.mjs +163 -15
- package/scripts/lib/validate/check-validator-registration.mjs +10 -4
- package/scripts/lib/validate/confidential-names.mjs +95 -30
- package/scripts/lib/validate/enumerate-repo-files.mjs +317 -0
- package/scripts/lib/validate/repo-files.mjs +48 -14
- 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/narrative-mirror.mjs +127 -18
- 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 +5 -7
- package/scripts/lib/wave-resource-gate.mjs +8 -2
- package/scripts/lib/wave-sizing.mjs +4 -1
- package/scripts/lib/wave-transcript-tail.mjs +118 -4
- package/scripts/materialize-wave-scope.mjs +12 -5
- package/scripts/memory-propose.mjs +19 -5
- package/scripts/migrate-cold-start-seed.mjs +4 -1
- package/scripts/parse-config.mjs +60 -3
- package/scripts/release.mjs +430 -31
- package/scripts/repair-invalid-sessions.mjs +3 -3
- package/scripts/run-quality-gate.mjs +128 -11
- package/scripts/site-numbers.mjs +344 -8
- 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 +164 -0
- package/scripts/validate-wave-scope.mjs +28 -8
- package/scripts/wave-scope-binding.mjs +215 -0
- package/skills/_shared/instruction-file-resolution.md +10 -0
- package/skills/_shared/parallel-aware-preamble.md +1 -0
- 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/evolve/SKILL.md +65 -26
- package/skills/frontmatter-guard/SKILL.md +11 -5
- package/skills/npm-publish/SKILL.md +1 -1
- package/skills/reconcile/SKILL.md +33 -0
- package/skills/remote-offload/SKILL.md +1 -1
- package/skills/session-end/SKILL.md +18 -905
- package/skills/session-end/phase-3-6-tail.md +10 -3
- 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 +22 -904
- 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 +160 -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/SKILL.md +10 -0
- package/skills/vault-sync/validator.mjs +21 -27
- package/skills/wave-executor/SKILL.md +15 -1
- 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 -1309
- 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 -270
- 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
|
@@ -80,12 +80,40 @@ function parseFrontmatter(content) {
|
|
|
80
80
|
return fields;
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
/**
|
|
84
|
+
* Values that YAML would read as a non-string scalar even though every
|
|
85
|
+
* character in them is "safe". `argument-hint: no` is a boolean, not the
|
|
86
|
+
* string "no"; `description: 3` is an integer. A consumer asserting
|
|
87
|
+
* `typeof value === 'string'` fails on a file that looks perfectly fine.
|
|
88
|
+
*/
|
|
89
|
+
const YAML_SCALAR_LOOKALIKE = /^(?:true|false|yes|no|on|off|null|nan|[-+]?\.?inf|~)$/i;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* A value safe to emit as a YAML *plain* (unquoted) scalar.
|
|
93
|
+
*
|
|
94
|
+
* Deliberately an ALLOW-list. Its predecessor was a deny-list of special
|
|
95
|
+
* characters, which is unenumerable by construction: it caught `[` and `:`
|
|
96
|
+
* but not a leading `-` (block-sequence entry), not surrounding whitespace,
|
|
97
|
+
* and not the scalar look-alikes above. An allow-list fails closed — an
|
|
98
|
+
* unforeseen shape gets quoted, which is never wrong, only noisier.
|
|
99
|
+
*/
|
|
100
|
+
const YAML_PLAIN_SAFE = /^[A-Za-z0-9_][A-Za-z0-9 _.,()/-]*$/;
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Render a frontmatter VALUE as YAML.
|
|
104
|
+
*
|
|
105
|
+
* @param {unknown} value
|
|
106
|
+
* @returns {string|null} the YAML scalar, or `null` when there is nothing to emit
|
|
107
|
+
*/
|
|
83
108
|
function yamlQuote(value) {
|
|
84
|
-
if (value === undefined || value === '') return null;
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
return
|
|
109
|
+
if (value === undefined || value === null || value === '') return null;
|
|
110
|
+
const text = String(value);
|
|
111
|
+
if (text.trim() === '') return null;
|
|
112
|
+
if (text !== text.trim()) return JSON.stringify(text);
|
|
113
|
+
if (!YAML_PLAIN_SAFE.test(text)) return JSON.stringify(text);
|
|
114
|
+
if (YAML_SCALAR_LOOKALIKE.test(text)) return JSON.stringify(text);
|
|
115
|
+
if (/^\d/.test(text)) return JSON.stringify(text);
|
|
116
|
+
return text;
|
|
89
117
|
}
|
|
90
118
|
|
|
91
119
|
function frontmatterLine(key, value) {
|
|
@@ -103,10 +131,16 @@ function renderCommand(commandFile) {
|
|
|
103
131
|
const commandPath = path.join(COMMANDS_DIR, commandFile);
|
|
104
132
|
const commandName = commandFile.replace(/\.md$/, '');
|
|
105
133
|
const fields = parseFrontmatter(readFileSync(commandPath, 'utf8'));
|
|
134
|
+
// EVERY value goes through yamlQuote(). `argument-hint` did not, and its
|
|
135
|
+
// canonical form is a bare bracket list (`[mode] [--flag]`) — a YAML flow
|
|
136
|
+
// sequence, which is GH#54: Copilot CLI >= 1.0.65 silently DROPS a command
|
|
137
|
+
// file whose `argument-hint` is not a string. Fixed in `commands/` and
|
|
138
|
+
// `pi/prompts/` by 93b40dd (v3.16.0) and re-introduced here on every
|
|
139
|
+
// generation, because this mirror re-derived the frontmatter by hand.
|
|
106
140
|
const frontmatter = [
|
|
107
141
|
'---',
|
|
108
|
-
frontmatterLine('description', yamlQuote(fields.description)
|
|
109
|
-
frontmatterLine('argument-hint', fields['argument-hint']),
|
|
142
|
+
frontmatterLine('description', yamlQuote(fields.description)),
|
|
143
|
+
frontmatterLine('argument-hint', yamlQuote(fields['argument-hint'])),
|
|
110
144
|
'---',
|
|
111
145
|
].filter(Boolean).join('\n');
|
|
112
146
|
|
|
@@ -132,9 +166,12 @@ function renderSkill(skillName) {
|
|
|
132
166
|
const skillPath = path.join(SKILLS_DIR, skillName, 'SKILL.md');
|
|
133
167
|
const fields = parseFrontmatter(readFileSync(skillPath, 'utf8'));
|
|
134
168
|
const description = clampDescription(fields.description || `Session Orchestrator skill: ${skillName}`);
|
|
169
|
+
// Same rule as renderCommand: no frontmatter value is emitted raw. `name` is
|
|
170
|
+
// a directory basename today, so it is plain-safe in practice — routing it
|
|
171
|
+
// through yamlQuote() is what keeps that true after the next skill is added.
|
|
135
172
|
const lines = [
|
|
136
173
|
'---',
|
|
137
|
-
`name: ${skillName}`,
|
|
174
|
+
`name: ${yamlQuote(skillName)}`,
|
|
138
175
|
`description: ${yamlQuote(description)}`,
|
|
139
176
|
];
|
|
140
177
|
if (!isUserInvocable(fields['user-invocable'])) {
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* generate-hook-import-set.mjs — build the committed allowlist of modules that
|
|
4
|
+
* are transitively reachable from a hook entry file (GitLab #1224).
|
|
5
|
+
*
|
|
6
|
+
* WHY: a hook entry file imports a helper module on EVERY tool call. A helper
|
|
7
|
+
* saved in a broken intermediate state (2026-09-04: a call to a function that
|
|
8
|
+
* did not exist yet) turns every Bash/Edit/Write call into "Internal hook error
|
|
9
|
+
* — request blocked", host-wide, for every session sharing the working copy.
|
|
10
|
+
* `hooks/post-edit-import-probe.mjs` checks a file right after it is edited —
|
|
11
|
+
* but only when the file is in THIS set, so the probe stays cheap.
|
|
12
|
+
*
|
|
13
|
+
* The set is a COMMITTED artefact (`hooks/_lib/hook-import-set.json`) rather
|
|
14
|
+
* than a runtime crawl: the probe runs inside a 5 s PostToolUse budget and must
|
|
15
|
+
* not walk 142 modules per edit. `--check` re-generates and diffs, which is the
|
|
16
|
+
* drift guard that keeps the committed copy honest.
|
|
17
|
+
*
|
|
18
|
+
* Usage:
|
|
19
|
+
* node scripts/generate-hook-import-set.mjs [--plugin-root <dir>] [--out <file>] [--check]
|
|
20
|
+
* node scripts/generate-hook-import-set.mjs --help
|
|
21
|
+
*
|
|
22
|
+
* Exit codes: 0 = written / in sync (or --help); 1 = drift (with --check);
|
|
23
|
+
* 2 = usage error (unknown flag, or a valued flag missing its value) — the
|
|
24
|
+
* write is NEVER performed on a usage error.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import { readFileSync, writeFileSync, existsSync, statSync, realpathSync } from 'node:fs';
|
|
28
|
+
import path from 'node:path';
|
|
29
|
+
import { fileURLToPath } from 'node:url';
|
|
30
|
+
import { execFileSync } from 'node:child_process';
|
|
31
|
+
|
|
32
|
+
/** The four hook manifests whose entry files seed the crawl. */
|
|
33
|
+
export const HOOK_MANIFESTS = [
|
|
34
|
+
'hooks.json',
|
|
35
|
+
'hooks-codex.json',
|
|
36
|
+
'hooks-cursor.json',
|
|
37
|
+
'hooks-pi.json',
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
/** Module extensions the crawl resolves an extension-less specifier against. */
|
|
41
|
+
const RESOLVE_EXTS = ['.mjs', '.js', '.cjs'];
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Collect every `<something>.mjs` path mentioned in a hook manifest's command
|
|
45
|
+
* strings. The manifests differ per platform ($CLAUDE_PLUGIN_ROOT /
|
|
46
|
+
* $PI_PLUGIN_ROOT / ${PLUGIN_ROOT}), so match on the hooks/-relative tail
|
|
47
|
+
* rather than on any one variable spelling.
|
|
48
|
+
*
|
|
49
|
+
* @param {string} json - raw manifest contents
|
|
50
|
+
* @returns {string[]} plugin-root-relative entry paths (e.g. "hooks/enforce-scope.mjs")
|
|
51
|
+
*/
|
|
52
|
+
export function extractEntryFiles(json) {
|
|
53
|
+
const out = new Set();
|
|
54
|
+
for (const m of json.matchAll(/hooks\/((?:[\w.-]+\/)*[\w.-]+\.mjs)/g)) {
|
|
55
|
+
const rel = `hooks/${m[1]}`;
|
|
56
|
+
// run-node.sh is the launcher, never an entry module; .../hooks/_lib/* is
|
|
57
|
+
// reached through imports, not through a manifest command.
|
|
58
|
+
out.add(rel);
|
|
59
|
+
}
|
|
60
|
+
return [...out].sort();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Extract relative module specifiers (static import/export-from and dynamic
|
|
65
|
+
* `import()`) from a module's source.
|
|
66
|
+
*
|
|
67
|
+
* @param {string} src
|
|
68
|
+
* @returns {string[]} relative specifiers, e.g. ["./_lib/profile-gate.mjs"]
|
|
69
|
+
*/
|
|
70
|
+
export function extractRelativeSpecifiers(src) {
|
|
71
|
+
const out = new Set();
|
|
72
|
+
const patterns = [
|
|
73
|
+
/(?:^|[\s;}])(?:import|export)\s[^;'"]*?\sfrom\s*['"](\.[^'"]+)['"]/g,
|
|
74
|
+
/(?:^|[\s;}])import\s*['"](\.[^'"]+)['"]/g,
|
|
75
|
+
/\bimport\s*\(\s*['"](\.[^'"]+)['"]\s*\)/g,
|
|
76
|
+
];
|
|
77
|
+
for (const re of patterns) {
|
|
78
|
+
for (const m of src.matchAll(re)) out.add(m[1]);
|
|
79
|
+
}
|
|
80
|
+
return [...out];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Resolve a relative specifier against the importing file.
|
|
85
|
+
*
|
|
86
|
+
* @param {string} fromFile - absolute path of the importing module
|
|
87
|
+
* @param {string} spec - relative specifier
|
|
88
|
+
* @returns {string|null} absolute path of an existing file, or null
|
|
89
|
+
*/
|
|
90
|
+
function resolveSpecifier(fromFile, spec) {
|
|
91
|
+
const base = path.resolve(path.dirname(fromFile), spec);
|
|
92
|
+
const candidates = [base, ...RESOLVE_EXTS.map((e) => base + e),
|
|
93
|
+
...RESOLVE_EXTS.map((e) => path.join(base, `index${e}`))];
|
|
94
|
+
for (const c of candidates) {
|
|
95
|
+
try {
|
|
96
|
+
if (existsSync(c) && statSync(c).isFile()) return c;
|
|
97
|
+
} catch { /* unreadable → not a resolution */ }
|
|
98
|
+
}
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Crawl every hook entry file transitively and return the reachable module set.
|
|
104
|
+
*
|
|
105
|
+
* @param {string} pluginRoot
|
|
106
|
+
* @returns {{file: string, reachable_from: string[]}[]} sorted by `file`
|
|
107
|
+
*/
|
|
108
|
+
export function buildImportSet(pluginRoot) {
|
|
109
|
+
/** @type {Map<string, Set<string>>} rel path → set of hook entry basenames */
|
|
110
|
+
const reach = new Map();
|
|
111
|
+
|
|
112
|
+
const entries = new Set();
|
|
113
|
+
for (const manifest of HOOK_MANIFESTS) {
|
|
114
|
+
const abs = path.join(pluginRoot, 'hooks', manifest);
|
|
115
|
+
if (!existsSync(abs)) continue;
|
|
116
|
+
for (const rel of extractEntryFiles(readFileSync(abs, 'utf8'))) {
|
|
117
|
+
if (existsSync(path.join(pluginRoot, rel))) entries.add(rel);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
for (const entryRel of [...entries].sort()) {
|
|
122
|
+
const entryName = path.basename(entryRel);
|
|
123
|
+
const stack = [path.join(pluginRoot, entryRel)];
|
|
124
|
+
const seen = new Set();
|
|
125
|
+
while (stack.length > 0) {
|
|
126
|
+
const abs = stack.pop();
|
|
127
|
+
if (seen.has(abs)) continue;
|
|
128
|
+
seen.add(abs);
|
|
129
|
+
|
|
130
|
+
const rel = path.relative(pluginRoot, abs).split(path.sep).join('/');
|
|
131
|
+
if (!reach.has(rel)) reach.set(rel, new Set());
|
|
132
|
+
reach.get(rel).add(entryName);
|
|
133
|
+
|
|
134
|
+
let src;
|
|
135
|
+
try { src = readFileSync(abs, 'utf8'); } catch { continue; }
|
|
136
|
+
for (const spec of extractRelativeSpecifiers(src)) {
|
|
137
|
+
const next = resolveSpecifier(abs, spec);
|
|
138
|
+
if (next) stack.push(next);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return [...reach.entries()]
|
|
144
|
+
.sort((a, b) => (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0))
|
|
145
|
+
.map(([file, from]) => ({ file, reachable_from: [...from].sort() }));
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Current HEAD sha of the plugin root, or "unknown" outside a git checkout.
|
|
150
|
+
*
|
|
151
|
+
* @param {string} pluginRoot
|
|
152
|
+
* @returns {string}
|
|
153
|
+
*/
|
|
154
|
+
function headSha(pluginRoot) {
|
|
155
|
+
try {
|
|
156
|
+
return execFileSync('git', ['rev-parse', 'HEAD'], {
|
|
157
|
+
cwd: pluginRoot,
|
|
158
|
+
encoding: 'utf8',
|
|
159
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
160
|
+
}).trim();
|
|
161
|
+
} catch {
|
|
162
|
+
return 'unknown';
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Build the full artefact payload.
|
|
168
|
+
*
|
|
169
|
+
* @param {string} pluginRoot
|
|
170
|
+
* @returns {{generated_at: string, head: string, entries: {file: string, reachable_from: string[]}[]}}
|
|
171
|
+
*/
|
|
172
|
+
export function buildArtifact(pluginRoot) {
|
|
173
|
+
return {
|
|
174
|
+
generated_at: new Date().toISOString(),
|
|
175
|
+
head: headSha(pluginRoot),
|
|
176
|
+
entries: buildImportSet(pluginRoot),
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// ---------------------------------------------------------------------------
|
|
181
|
+
// CLI
|
|
182
|
+
// ---------------------------------------------------------------------------
|
|
183
|
+
|
|
184
|
+
const USAGE = [
|
|
185
|
+
'Usage: node scripts/generate-hook-import-set.mjs [--plugin-root <dir>] [--out <file>] [--check]',
|
|
186
|
+
'',
|
|
187
|
+
' --plugin-root <dir> repository/plugin root to crawl (default: the repo this script lives in)',
|
|
188
|
+
' --out <file> artefact path (default: <plugin-root>/hooks/_lib/hook-import-set.json)',
|
|
189
|
+
' --check re-crawl and diff against the committed artefact instead of writing',
|
|
190
|
+
' --help, -h print this help',
|
|
191
|
+
'',
|
|
192
|
+
'Exit codes: 0 = written / in sync; 1 = drift (with --check); 2 = usage error.',
|
|
193
|
+
].join('\n');
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* @param {string[]} argv
|
|
197
|
+
* @returns {number} process exit code
|
|
198
|
+
*/
|
|
199
|
+
export function main(argv) {
|
|
200
|
+
const args = argv.slice(2);
|
|
201
|
+
|
|
202
|
+
/** @type {{'--plugin-root': string|null, '--out': string|null}} */
|
|
203
|
+
const valued = { '--plugin-root': null, '--out': null };
|
|
204
|
+
let check = false;
|
|
205
|
+
|
|
206
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
207
|
+
const arg = args[i];
|
|
208
|
+
if (arg === '--help' || arg === '-h') {
|
|
209
|
+
process.stdout.write(`${USAGE}\n`);
|
|
210
|
+
return 0;
|
|
211
|
+
}
|
|
212
|
+
if (arg === '--check') {
|
|
213
|
+
check = true;
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
if (arg === '--plugin-root' || arg === '--out') {
|
|
217
|
+
// A valued flag whose value is missing — or whose "value" is the next FLAG
|
|
218
|
+
// — is a usage error, not a silent default. Without the leading-dash test,
|
|
219
|
+
// `--out --check` swallows `--check` as the artefact path: checking is
|
|
220
|
+
// disabled, the WRITE branch runs, and a file literally named `--check`
|
|
221
|
+
// lands in the cwd.
|
|
222
|
+
const value = args[i + 1];
|
|
223
|
+
if (value === undefined || value.startsWith('-')) {
|
|
224
|
+
process.stderr.write(`✗ hook-import-set: ${arg} requires a value\n${USAGE}\n`);
|
|
225
|
+
return 2;
|
|
226
|
+
}
|
|
227
|
+
valued[arg] = value;
|
|
228
|
+
i += 1;
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
process.stderr.write(`✗ hook-import-set: unknown argument "${arg}"\n${USAGE}\n`);
|
|
232
|
+
return 2;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const pluginRoot = path.resolve(valued['--plugin-root'] ?? path.resolve(import.meta.dirname, '..'));
|
|
236
|
+
const out = path.resolve(valued['--out'] ?? path.join(pluginRoot, 'hooks', '_lib', 'hook-import-set.json'));
|
|
237
|
+
|
|
238
|
+
const fresh = buildArtifact(pluginRoot);
|
|
239
|
+
|
|
240
|
+
if (check) {
|
|
241
|
+
if (!existsSync(out)) {
|
|
242
|
+
process.stderr.write(`✗ hook-import-set: ${path.relative(pluginRoot, out)} is missing — run generate-hook-import-set.mjs\n`);
|
|
243
|
+
return 1;
|
|
244
|
+
}
|
|
245
|
+
let committed;
|
|
246
|
+
try { committed = JSON.parse(readFileSync(out, 'utf8')); } catch {
|
|
247
|
+
process.stderr.write('✗ hook-import-set: committed file is not valid JSON\n');
|
|
248
|
+
return 1;
|
|
249
|
+
}
|
|
250
|
+
// Only `entries` is compared — generated_at/head are provenance, not content.
|
|
251
|
+
const a = JSON.stringify(committed.entries ?? null);
|
|
252
|
+
const b = JSON.stringify(fresh.entries);
|
|
253
|
+
if (a !== b) {
|
|
254
|
+
process.stderr.write('✗ hook-import-set: committed set differs from a fresh crawl — run `node scripts/generate-hook-import-set.mjs`\n');
|
|
255
|
+
return 1;
|
|
256
|
+
}
|
|
257
|
+
process.stdout.write(`✓ hook-import-set: ${fresh.entries.length} modules, in sync\n`);
|
|
258
|
+
return 0;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
writeFileSync(out, JSON.stringify(fresh, null, 2) + '\n', 'utf8');
|
|
262
|
+
process.stdout.write(`✓ hook-import-set: wrote ${fresh.entries.length} modules to ${path.relative(pluginRoot, out)}\n`);
|
|
263
|
+
return 0;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* True when this module was launched as the process entry script.
|
|
268
|
+
*
|
|
269
|
+
* A string compare of `import.meta.url` against `file://${process.argv[1]}` is
|
|
270
|
+
* fragile in exactly the invocations CI and husky use: any symlinked or
|
|
271
|
+
* realpath-differing path (measured: `/tmp` → `/private/tmp` on macOS) makes
|
|
272
|
+
* the compare false, so the whole CLI body becomes a silent no-op that still
|
|
273
|
+
* exits 0 — a fail-OPEN drift gate. A space or `#` in the path breaks the
|
|
274
|
+
* hand-built URL the same way. Same shape as `hooks/post-bash-write-verify.mjs`.
|
|
275
|
+
*
|
|
276
|
+
* @returns {boolean}
|
|
277
|
+
*/
|
|
278
|
+
function invokedAsScript() {
|
|
279
|
+
const entry = process.argv[1];
|
|
280
|
+
if (!entry) return false;
|
|
281
|
+
const self = fileURLToPath(import.meta.url);
|
|
282
|
+
try {
|
|
283
|
+
return realpathSync(entry) === realpathSync(self);
|
|
284
|
+
} catch {
|
|
285
|
+
// argv[1] unresolvable (deleted/renamed mid-run) — best-effort raw compare.
|
|
286
|
+
return entry === self;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (invokedAsScript()) {
|
|
291
|
+
process.exit(main(process.argv));
|
|
292
|
+
}
|
|
@@ -166,7 +166,11 @@ function releaseLock(lockFile, _myBody) {
|
|
|
166
166
|
}
|
|
167
167
|
|
|
168
168
|
/**
|
|
169
|
-
* Read the current LWW map from disk. Returns {} on
|
|
169
|
+
* Read the current LWW map from disk. Returns {} on a missing file (ENOENT)
|
|
170
|
+
* silently; an unreadable/unparseable one (EACCES/EISDIR/malformed JSON/…)
|
|
171
|
+
* also returns {} but with a stderr WARN (#1210 — ENOENT and other failures
|
|
172
|
+
* are different facts, same split as `sessions-canonical.mjs`
|
|
173
|
+
* `readCanonicalSessions`).
|
|
170
174
|
* @param {string} currentFile
|
|
171
175
|
* @returns {Record<string, object>}
|
|
172
176
|
*/
|
|
@@ -176,7 +180,14 @@ function readCurrentMap(currentFile) {
|
|
|
176
180
|
const obj = JSON.parse(raw);
|
|
177
181
|
if (obj && typeof obj === 'object' && !Array.isArray(obj)) return obj;
|
|
178
182
|
return {};
|
|
179
|
-
} catch {
|
|
183
|
+
} catch (err) {
|
|
184
|
+
if (!err || err.code !== 'ENOENT') {
|
|
185
|
+
process.stderr.write(
|
|
186
|
+
`⚠ readCurrentMap: cannot read ${currentFile} ` +
|
|
187
|
+
`(${err?.code ?? '?'}: ${err?.message ?? String(err)}) — ` +
|
|
188
|
+
'treating as EMPTY, counts below are floors\n',
|
|
189
|
+
);
|
|
190
|
+
}
|
|
180
191
|
return {};
|
|
181
192
|
}
|
|
182
193
|
}
|
|
@@ -25,6 +25,7 @@ import { existsSync, statSync } from 'node:fs';
|
|
|
25
25
|
import { randomUUID } from 'node:crypto';
|
|
26
26
|
import path from 'node:path';
|
|
27
27
|
|
|
28
|
+
import { readCanonicalSessions } from './sessions-canonical.mjs';
|
|
28
29
|
import { filterRealSessions } from './session-schema.mjs';
|
|
29
30
|
|
|
30
31
|
// ---------------------------------------------------------------------------
|
|
@@ -61,49 +62,50 @@ export async function readDreamSignals({ repoRoot, memoryDir }) {
|
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
// 2. Read sessions.jsonl entries to compute lastCleanupAt + sessionsSinceCleanup
|
|
65
|
+
//
|
|
66
|
+
// #1209: migrated from a hand-rolled parse loop to `readCanonicalSessions`
|
|
67
|
+
// — the raw file is APPEND-ONLY (a physical session can carry more than one
|
|
68
|
+
// LINE: crash-recovery re-appends, #1068 stub/supersede pairs), and the
|
|
69
|
+
// hand-rolled loop counted every line. `sessionsSinceCleanup` is a CADENCE
|
|
70
|
+
// count ("how many sessions since the last cleanup"), so counting a
|
|
71
|
+
// duplicated line twice inflated it — this migration LOWERS the count,
|
|
72
|
+
// which is the fix, not a side effect. `canonicalizeSessions` also drops
|
|
73
|
+
// lines with no `session_id` (they cannot be deduplicated, so they were
|
|
74
|
+
// never a countable "session" to begin with); the existing fixtures below
|
|
75
|
+
// were given synthetic `session_id` values so their asserted counts still
|
|
76
|
+
// reflect the same intended scenario post-migration.
|
|
64
77
|
let lastCleanupAt = null;
|
|
65
78
|
let sessionsSinceCleanup = 0;
|
|
66
79
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
80
|
+
const entries = readCanonicalSessions({ filePath: sessionsFilePath });
|
|
81
|
+
|
|
82
|
+
// Abandoned-session filter (#834): sessions.jsonl carries phantom
|
|
83
|
+
// `status: 'abandoned'` stubs (session-close-backfill records for
|
|
84
|
+
// sessions that ended without a real close). They are legitimate DATA
|
|
85
|
+
// but not legitimate SIGNAL — a burst of abandoned stubs must not fire
|
|
86
|
+
// /memory-cleanup off zero real work. filterRealSessions() is the
|
|
87
|
+
// shared, tested implementation (scripts/lib/session-schema/filters.mjs).
|
|
88
|
+
const realEntries = filterRealSessions(entries);
|
|
89
|
+
|
|
90
|
+
// Find the most recent memory_cleanup_at timestamp across all REAL entries.
|
|
91
|
+
for (const entry of realEntries) {
|
|
92
|
+
const ts = entry.memory_cleanup_at;
|
|
93
|
+
if (typeof ts === 'string' && ts.length > 0) {
|
|
94
|
+
if (lastCleanupAt === null || ts > lastCleanupAt) {
|
|
95
|
+
lastCleanupAt = ts;
|
|
76
96
|
}
|
|
77
97
|
}
|
|
98
|
+
}
|
|
78
99
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
// shared, tested implementation (scripts/lib/session-schema/filters.mjs).
|
|
85
|
-
const realEntries = filterRealSessions(entries);
|
|
86
|
-
|
|
87
|
-
// Find the most recent memory_cleanup_at timestamp across all REAL entries.
|
|
100
|
+
// Count REAL entries newer than the last cleanup (or total REAL entries
|
|
101
|
+
// when no cleanup ever ran).
|
|
102
|
+
if (lastCleanupAt === null) {
|
|
103
|
+
sessionsSinceCleanup = realEntries.length;
|
|
104
|
+
} else {
|
|
88
105
|
for (const entry of realEntries) {
|
|
89
|
-
const
|
|
90
|
-
if (typeof
|
|
91
|
-
|
|
92
|
-
lastCleanupAt = ts;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Count REAL entries newer than the last cleanup (or total REAL entries
|
|
98
|
-
// when no cleanup ever ran).
|
|
99
|
-
if (lastCleanupAt === null) {
|
|
100
|
-
sessionsSinceCleanup = realEntries.length;
|
|
101
|
-
} else {
|
|
102
|
-
for (const entry of realEntries) {
|
|
103
|
-
const startedAt = entry.started_at;
|
|
104
|
-
if (typeof startedAt === 'string' && startedAt > lastCleanupAt) {
|
|
105
|
-
sessionsSinceCleanup += 1;
|
|
106
|
-
}
|
|
106
|
+
const startedAt = entry.started_at;
|
|
107
|
+
if (typeof startedAt === 'string' && startedAt > lastCleanupAt) {
|
|
108
|
+
sessionsSinceCleanup += 1;
|
|
107
109
|
}
|
|
108
110
|
}
|
|
109
111
|
}
|
|
@@ -158,6 +158,12 @@ export function computeSuitabilityVerdict(deps = {}) {
|
|
|
158
158
|
const ciNotRed = ciStatus !== 'red'; // null status (absent/malformed) passes
|
|
159
159
|
if (ciAbsent) warnings.push('CI signal absent');
|
|
160
160
|
else if (ciMalformed) warnings.push('CI signal malformed — treated as absent');
|
|
161
|
+
// `{status:'unknown'}` is a WELL-FORMED reading that establishes nothing —
|
|
162
|
+
// since #1031 it is what a degraded probe produces, and it hits neither
|
|
163
|
+
// branch above. Without this line it passed G3 with NO warning at all, i.e.
|
|
164
|
+
// more quietly than the plain-absent case it is strictly weaker than. The
|
|
165
|
+
// gate stays non-blocking (only a literal 'red' fails); only the silence goes.
|
|
166
|
+
else if (ciStatus === 'unknown') warnings.push('CI signal unknown — treated as absent');
|
|
161
167
|
const ciSegment = ciAbsent ? 'absent' : ciMalformed ? 'malformed' : `${ciStatus}`;
|
|
162
168
|
|
|
163
169
|
// --- G4 — resource gate (green/warn/degraded/null pass; only 'critical' fails)
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
finalizeState,
|
|
21
21
|
} from './telemetry.mjs';
|
|
22
22
|
import { durableCommit } from './durable-telemetry.mjs';
|
|
23
|
-
import {
|
|
23
|
+
import { getStateDir } from '../platform.mjs';
|
|
24
24
|
|
|
25
25
|
// Internal clamp — mirrors flags.mjs internal; not re-exported there.
|
|
26
26
|
function clampNumber(value, { min, max, fallback }) {
|
|
@@ -311,7 +311,7 @@ export async function runLoop(opts = {}) {
|
|
|
311
311
|
files: [
|
|
312
312
|
jsonlPath.replace(process.cwd() + '/', ''),
|
|
313
313
|
'.orchestrator/metrics/sessions.jsonl',
|
|
314
|
-
`${
|
|
314
|
+
`${getStateDir()}/STATE.md`,
|
|
315
315
|
],
|
|
316
316
|
enabled: false,
|
|
317
317
|
});
|