session-orchestrator 3.24.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 +1 -1
- 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 +1125 -2
- package/NOTICE +11 -6
- package/README.md +127 -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 +65 -21
- package/docs/components.md +36 -15
- package/docs/cursor-setup.md +6 -2
- package/docs/events-schema.md +9 -6
- 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 +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 +1487 -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 +36 -11
- 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/plugin.json +27 -0
- 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-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/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 +82 -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/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 +26 -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 +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/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 +13 -4
- 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 +36 -2
- package/scripts/lib/session-schema/validator.mjs +38 -4
- package/scripts/lib/session-start-probes.mjs +18 -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 +181 -9
- package/scripts/lib/telemetry/sync.mjs +368 -12
- 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-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 +47 -28
- package/scripts/lib/validate/check-unwired-features.mjs +0 -2
- package/scripts/lib/validate/check-validator-registration.mjs +10 -4
- package/scripts/lib/validate/enumerate-repo-files.mjs +317 -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/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 +337 -29
- package/scripts/repair-invalid-sessions.mjs +3 -3
- package/scripts/run-quality-gate.mjs +128 -11
- 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 +161 -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 +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 +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
|
@@ -3,8 +3,22 @@
|
|
|
3
3
|
* Checks CI status for the current HEAD commit and returns a structured
|
|
4
4
|
* result for session-start Phase 4 banner rendering.
|
|
5
5
|
*
|
|
6
|
-
* Plain-JS — no Zod dependency. Never throws.
|
|
7
|
-
*
|
|
6
|
+
* Plain-JS — no Zod dependency. Never throws.
|
|
7
|
+
*
|
|
8
|
+
* THREE return states (#1031), not two:
|
|
9
|
+
* - `null` — read, and there is nothing to report (a
|
|
10
|
+
* benign ABSENCE: no VCS remote, no pipeline
|
|
11
|
+
* worth a banner, green with no soft failures)
|
|
12
|
+
* - `{status, ok, details, …}` — a real CI reading (`green` | `red` |
|
|
13
|
+
* `unknown`)
|
|
14
|
+
* - `{severity, message, degraded, ok:false}` — the state could NOT be read.
|
|
15
|
+
* `degraded` is a member of the frozen {@link DEGRADED_REASONS} enum
|
|
16
|
+
* exported below. This must NEVER be read as "CI is green".
|
|
17
|
+
*
|
|
18
|
+
* Until #1031 every unreadable state collapsed onto `null`, which in the banner
|
|
19
|
+
* contract reads as all-clear — the exact confusion #1022 (`gh repo view -R` →
|
|
20
|
+
* `unknown shorthand flag`) hid behind on every GitHub repo. The shape is the
|
|
21
|
+
* one `scripts/lib/mirror-issues-banner.mjs` established.
|
|
8
22
|
*
|
|
9
23
|
* Supports GitLab (via glab) and GitHub (via gh).
|
|
10
24
|
* VCS is auto-detected from the repo's git remotes via
|
|
@@ -29,6 +43,78 @@ const execFileAsync = promisify(_execFile);
|
|
|
29
43
|
/** Default timeout in milliseconds for CLI invocations. */
|
|
30
44
|
export const DEFAULT_TIMEOUT_MS = 8000;
|
|
31
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Closed set of `degraded` reasons (#1031). A degraded result means "the CI
|
|
48
|
+
* state was NOT successfully read" — never "CI is green".
|
|
49
|
+
*
|
|
50
|
+
* Deliberately THIS module's own enum rather than a merged one shared with
|
|
51
|
+
* `mirror-issues-banner.mjs` / `git-config-drift.mjs`: those two already carry
|
|
52
|
+
* DIFFERENT member sets for their own failure surfaces, and a merged superset
|
|
53
|
+
* would hand every consumer members its probe can never emit — an enum whose
|
|
54
|
+
* members are not exhaustively reachable cannot be switched on exhaustively,
|
|
55
|
+
* which is the only reason to freeze one. The members here are exactly what
|
|
56
|
+
* this probe can fail at:
|
|
57
|
+
*
|
|
58
|
+
* - `cli-missing` a required binary (`git`, `glab`, `gh`) is not on PATH.
|
|
59
|
+
* - `timeout` a subprocess outlived its budget. Not silent since #1031:
|
|
60
|
+
* a hang is not actionable, but "state unknown" IS the
|
|
61
|
+
* finding, and silence renders identically to green.
|
|
62
|
+
* - `parse-error` a CLI answered with output this module could not read
|
|
63
|
+
* (unparseable JSON, or valid JSON of the wrong shape).
|
|
64
|
+
* - `query-failed` residual bucket — a present CLI ran and rejected the
|
|
65
|
+
* invocation, or a resolvable remote whose API target could
|
|
66
|
+
* not be derived. Folding these into `parse-error` would
|
|
67
|
+
* mislabel a rejected flag as malformed output.
|
|
68
|
+
* - `git-error` the VCS probe itself failed (`git remote -v` non-zero for
|
|
69
|
+
* a reason other than "not a work tree"). Distinct from
|
|
70
|
+
* `query-failed` because it means the module never got as
|
|
71
|
+
* far as choosing a CI platform.
|
|
72
|
+
*
|
|
73
|
+
* @type {readonly ['cli-missing','timeout','parse-error','query-failed','git-error']}
|
|
74
|
+
*/
|
|
75
|
+
export const DEGRADED_REASONS = Object.freeze([
|
|
76
|
+
'cli-missing',
|
|
77
|
+
'timeout',
|
|
78
|
+
'parse-error',
|
|
79
|
+
'query-failed',
|
|
80
|
+
'git-error',
|
|
81
|
+
]);
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Build the third return state. Distinct from `null` on purpose: `null` in the
|
|
85
|
+
* banner contract reads as "all clear", which a failed read has NOT
|
|
86
|
+
* established.
|
|
87
|
+
*
|
|
88
|
+
* The `detail` is appended bounded (BV-004: 200 chars — long enough for a
|
|
89
|
+
* `Command failed: <argv>` first line, short enough not to bury the
|
|
90
|
+
* session-start banner it prints beside; revisit if a CLI starts emitting a
|
|
91
|
+
* diagnostic that needs more). Callers pass ALREADY-redacted text — every
|
|
92
|
+
* source here is either a fixed string or a `redactUrlCredentials` result.
|
|
93
|
+
*
|
|
94
|
+
* @param {'cli-missing'|'timeout'|'parse-error'|'query-failed'|'git-error'} reason
|
|
95
|
+
* @param {string} [detail] Optional, already-redacted diagnostic tail
|
|
96
|
+
* @returns {{ severity: 'warn', ok: false, message: string, degraded: string }}
|
|
97
|
+
*/
|
|
98
|
+
function degradedResult(reason, detail) {
|
|
99
|
+
// Redaction (the callers' job) and control-byte escaping are DIFFERENT
|
|
100
|
+
// protections: `redactUrlCredentials` removes secrets, it does not neutralise
|
|
101
|
+
// ANSI/CR. `parseCliJson` already escapes the text it embeds (see the call at
|
|
102
|
+
// the JSON.parse catch), but the degraded tail reaches the operator's terminal
|
|
103
|
+
// by a second route — a CLI stderr quoted into `err.message` — and skipped it.
|
|
104
|
+
// Escape here so BOTH routes are covered at their common exit. Slice first,
|
|
105
|
+
// escape after: the budget is 200 chars of DETAIL, and escaping cannot then
|
|
106
|
+
// leave a cut mid-`\uXXXX`.
|
|
107
|
+
const tail = detail ? ` — ${escapeControlBytes(String(detail).trim().slice(0, 200))}` : '';
|
|
108
|
+
return {
|
|
109
|
+
severity: 'warn',
|
|
110
|
+
ok: false,
|
|
111
|
+
message:
|
|
112
|
+
`⚠ ci-status: CI status for HEAD could not be determined (${reason}) — ` +
|
|
113
|
+
`state UNKNOWN, not "green".${tail}`,
|
|
114
|
+
degraded: reason,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
32
118
|
/**
|
|
33
119
|
* Wraps execFile with a per-call timeout race.
|
|
34
120
|
*
|
|
@@ -148,10 +234,10 @@ function parseCliJson(stdout, label, expect) {
|
|
|
148
234
|
// `cause` preserves the original for a debugger; the reason is ALSO
|
|
149
235
|
// inlined into the message because the outer catch reads `err.message`
|
|
150
236
|
// only — a cause-only wrapper would lose it on the operator-facing line.
|
|
151
|
-
throw new Error(
|
|
237
|
+
throw tagParseError(new Error(
|
|
152
238
|
`${label} returned unparseable JSON (${reason}) — ${shown}`,
|
|
153
239
|
{ cause: err },
|
|
154
|
-
);
|
|
240
|
+
));
|
|
155
241
|
}
|
|
156
242
|
|
|
157
243
|
// A shape mismatch reports the JSON TYPE, never the payload. The parse
|
|
@@ -161,25 +247,47 @@ function parseCliJson(stdout, label, expect) {
|
|
|
161
247
|
// its contents echoed anywhere. A type name carries no body content.
|
|
162
248
|
const actual = jsonTypeOf(parsed);
|
|
163
249
|
if (expect === 'array' && actual !== 'array') {
|
|
164
|
-
throw new Error(`${label} returned JSON of an unexpected shape — expected an array, got ${actual}`);
|
|
250
|
+
throw tagParseError(new Error(`${label} returned JSON of an unexpected shape — expected an array, got ${actual}`));
|
|
165
251
|
}
|
|
166
252
|
if (expect === 'object' && actual !== 'object') {
|
|
167
|
-
throw new Error(`${label} returned JSON of an unexpected shape — expected an object, got ${actual}`);
|
|
253
|
+
throw tagParseError(new Error(`${label} returned JSON of an unexpected shape — expected an object, got ${actual}`));
|
|
168
254
|
}
|
|
169
255
|
return parsed;
|
|
170
256
|
}
|
|
171
257
|
|
|
258
|
+
/**
|
|
259
|
+
* Stamp the `parse-error` degraded reason onto an error raised by
|
|
260
|
+
* {@link parseCliJson}.
|
|
261
|
+
*
|
|
262
|
+
* Carried on the error object rather than re-derived from its message text in
|
|
263
|
+
* the outer catch: a message-substring test would silently reclassify the
|
|
264
|
+
* moment a wording changes, and the two failures (`unparseable JSON`, wrong
|
|
265
|
+
* shape) are one class only because THIS function says so.
|
|
266
|
+
*
|
|
267
|
+
* @param {Error} err
|
|
268
|
+
* @returns {Error}
|
|
269
|
+
*/
|
|
270
|
+
function tagParseError(err) {
|
|
271
|
+
return Object.assign(err, { degradedReason: 'parse-error' });
|
|
272
|
+
}
|
|
273
|
+
|
|
172
274
|
/**
|
|
173
275
|
* The one failure this probe can produce that the frozen
|
|
174
276
|
* `REMOTE_RESOLUTION_REASONS` set has no member for: the async timeout race
|
|
175
277
|
* every subprocess here runs under has no counterpart in the SYNCHRONOUS
|
|
176
278
|
* `vcs-repo-spec.mjs` core (it uses `execFileSync`, which cannot time out).
|
|
177
279
|
*
|
|
178
|
-
* Deliberately NOT a query-failure for
|
|
179
|
-
*
|
|
180
|
-
*
|
|
181
|
-
*
|
|
182
|
-
*
|
|
280
|
+
* Deliberately NOT a query-failure for WARNING purposes — a timeout emits no
|
|
281
|
+
* `console.warn`, matching how `checkCiStatus`'s outer catch has always
|
|
282
|
+
* treated one, and warning on a hung `git` but not on a hung `glab` would be
|
|
283
|
+
* an inconsistency inside a single banner.
|
|
284
|
+
*
|
|
285
|
+
* It is no longer SILENT, though (#1031). The old argument — "a hang is not a
|
|
286
|
+
* fact an operator can act on the way 'git is not installed' is" — is
|
|
287
|
+
* superseded: what the operator acts on is not the hang, it is that CI state
|
|
288
|
+
* is UNKNOWN, and returning `null` rendered that identically to green. A
|
|
289
|
+
* timeout therefore yields `degradedResult('timeout')` on both this path and
|
|
290
|
+
* the outer catch.
|
|
183
291
|
*/
|
|
184
292
|
const PROBE_TIMEOUT = 'probe-timeout';
|
|
185
293
|
|
|
@@ -203,6 +311,32 @@ const PROBE_TIMEOUT = 'probe-timeout';
|
|
|
203
311
|
*/
|
|
204
312
|
const SILENT_QUERY_FAILURES = new Set(['not-a-git-repo']);
|
|
205
313
|
|
|
314
|
+
/**
|
|
315
|
+
* Project a `REMOTE_RESOLUTION_REASONS` query failure onto this module's own
|
|
316
|
+
* {@link DEGRADED_REASONS} member.
|
|
317
|
+
*
|
|
318
|
+
* Written as explicit branches rather than a lookup table so that EVERY reason
|
|
319
|
+
* literal this module can emit sits inside a literal call to the builder
|
|
320
|
+
* call — which is what makes the enum-membership census in
|
|
321
|
+
* `tests/lib/ci-status-banner.test.mjs` a regex over the source instead of a
|
|
322
|
+
* hand-typed list that drifts.
|
|
323
|
+
*
|
|
324
|
+
* The fallthrough is `query-failed`, not a throw: a reason added to the frozen
|
|
325
|
+
* upstream set must degrade visibly (fail-toward-visible), never crash the
|
|
326
|
+
* probe or slip back onto the silent path.
|
|
327
|
+
*
|
|
328
|
+
* @param {string} reason
|
|
329
|
+
* @param {string} [detail] Already-redacted git stderr
|
|
330
|
+
* @returns {{ severity: 'warn', ok: false, message: string, degraded: string }}
|
|
331
|
+
*/
|
|
332
|
+
function degradedForVcsReason(reason, detail) {
|
|
333
|
+
// git itself is a CLI, and "not on PATH" is the same fact for it as for
|
|
334
|
+
// glab/gh — one member, not two spellings of it.
|
|
335
|
+
if (reason === 'git-unavailable') return degradedResult('cli-missing', detail);
|
|
336
|
+
if (reason === 'git-error') return degradedResult('git-error', detail);
|
|
337
|
+
return degradedResult('query-failed', detail);
|
|
338
|
+
}
|
|
339
|
+
|
|
206
340
|
/**
|
|
207
341
|
* Classify a rejected ASYNC `execFile` into a `REMOTE_RESOLUTION_REASONS`
|
|
208
342
|
* member.
|
|
@@ -651,24 +785,22 @@ async function checkGithub(repoRoot, deps = {}) {
|
|
|
651
785
|
/**
|
|
652
786
|
* Checks CI status for the current HEAD commit.
|
|
653
787
|
*
|
|
654
|
-
* Returns `null` (silent no-op)
|
|
655
|
-
*
|
|
656
|
-
*
|
|
657
|
-
*
|
|
658
|
-
*
|
|
659
|
-
*
|
|
660
|
-
*
|
|
661
|
-
*
|
|
662
|
-
*
|
|
663
|
-
* module could not parse (see {@link parseCliJson}).
|
|
664
|
-
*
|
|
665
|
-
*
|
|
666
|
-
*
|
|
667
|
-
*
|
|
668
|
-
*
|
|
669
|
-
*
|
|
670
|
-
* one test covering it asserted only the `null` and let the file-wide
|
|
671
|
-
* `console.warn` spy swallow the rest.
|
|
788
|
+
* Returns `null` (silent no-op) ONLY for a measured ABSENCE: the repo has no
|
|
789
|
+
* usable VCS remote (not a git repo, no remotes at all, or >= 2 remotes with no
|
|
790
|
+
* preference match). That is a complete answer — there is no CI here.
|
|
791
|
+
*
|
|
792
|
+
* Returns a DEGRADED result (`{severity:'warn', ok:false, message, degraded}`,
|
|
793
|
+
* see {@link DEGRADED_REASONS}) when the state could not be read: the
|
|
794
|
+
* VCS-detection query itself failed (`git` not on PATH, `git remote -v`
|
|
795
|
+
* erroring), a required CLI is missing, an invocation timed out, a present CLI
|
|
796
|
+
* rejected its invocation, a GitLab API target could not be derived, or a CLI
|
|
797
|
+
* returned output this module could not parse (see {@link parseCliJson}).
|
|
798
|
+
* Callers MUST treat that as "state unknown", never as clean — the generic
|
|
799
|
+
* degraded path in `scripts/lib/session-start-probes.mjs` does exactly that.
|
|
800
|
+
*
|
|
801
|
+
* Missing-CLI and timeout additionally stay SILENT on the `console.warn`
|
|
802
|
+
* channel (they are normal states on a CLI-less machine); every other degraded
|
|
803
|
+
* reason also emits a warn.
|
|
672
804
|
*
|
|
673
805
|
* @param {{
|
|
674
806
|
* repoRoot?: string,
|
|
@@ -686,6 +818,11 @@ async function checkGithub(repoRoot, deps = {}) {
|
|
|
686
818
|
* `resolveGitlabProjectTarget`, which proves host and project path from one
|
|
687
819
|
* sanitized remote; GitHub retains the #872 spec/host resolvers.
|
|
688
820
|
* @returns {Promise<null | {
|
|
821
|
+
* severity: 'warn',
|
|
822
|
+
* ok: false,
|
|
823
|
+
* message: string,
|
|
824
|
+
* degraded: 'cli-missing'|'timeout'|'parse-error'|'query-failed'|'git-error',
|
|
825
|
+
* } | {
|
|
689
826
|
* status: 'green'|'red'|'unknown',
|
|
690
827
|
* ok: boolean,
|
|
691
828
|
* lastGreen?: { sha: string, pipelineId: number, ageCommits: number, ageDays: number|null },
|
|
@@ -723,24 +860,31 @@ export async function checkCiStatus(opts = {}, deps = {}) {
|
|
|
723
860
|
if (!vcs) {
|
|
724
861
|
const detected = await detectVcs(repoRoot, depsWithExec);
|
|
725
862
|
if (!detected.ok) {
|
|
726
|
-
//
|
|
727
|
-
//
|
|
728
|
-
//
|
|
729
|
-
//
|
|
730
|
-
//
|
|
731
|
-
//
|
|
732
|
-
//
|
|
733
|
-
//
|
|
734
|
-
//
|
|
735
|
-
|
|
863
|
+
// An ABSENCE (`no-remotes`, `no-matching-remote`, `unsafe-value`) is a
|
|
864
|
+
// real, benign answer and stays `null` AND silent — degrading there
|
|
865
|
+
// would print a banner on every session-start in a remote-less repo and
|
|
866
|
+
// train operators to ignore this line, which is the more expensive
|
|
867
|
+
// error. A QUERY FAILURE (`git-unavailable`, `git-error`) means the
|
|
868
|
+
// question could not be asked at all: since #1031 that is the third
|
|
869
|
+
// state, no longer a warn-only side channel on top of an all-clear
|
|
870
|
+
// `null`. `not-a-git-repo` is the one query failure this banner reads
|
|
871
|
+
// as an absence — see {@link SILENT_QUERY_FAILURES}.
|
|
872
|
+
if (detected.reason === PROBE_TIMEOUT) {
|
|
873
|
+
return degradedResult('timeout');
|
|
874
|
+
}
|
|
736
875
|
if (isQueryFailure(detected.reason) && !SILENT_QUERY_FAILURES.has(detected.reason)) {
|
|
737
|
-
const
|
|
738
|
-
?
|
|
876
|
+
const stderr = detected.stderr
|
|
877
|
+
? redactUrlCredentials(detected.stderr).trim()
|
|
739
878
|
: '';
|
|
879
|
+
const detail = stderr ? ` — ${stderr}` : '';
|
|
740
880
|
console.warn(
|
|
741
881
|
`WARN ci-status-banner: VCS detection failed (${detected.reason}), banner suppressed — ` +
|
|
742
882
|
`CI state is UNKNOWN, not "green".${detail}`,
|
|
743
883
|
);
|
|
884
|
+
return degradedForVcsReason(
|
|
885
|
+
detected.reason,
|
|
886
|
+
stderr ? `${detected.reason}: ${stderr}` : detected.reason,
|
|
887
|
+
);
|
|
744
888
|
}
|
|
745
889
|
return null;
|
|
746
890
|
}
|
|
@@ -765,7 +909,10 @@ export async function checkCiStatus(opts = {}, deps = {}) {
|
|
|
765
909
|
'WARN ci-status-banner: a GitLab remote was detected but its host/project path ' +
|
|
766
910
|
'could not be derived, banner suppressed — CI state is UNKNOWN, not "green".',
|
|
767
911
|
);
|
|
768
|
-
return
|
|
912
|
+
return degradedResult(
|
|
913
|
+
'query-failed',
|
|
914
|
+
'a GitLab remote was detected but its host/project path could not be derived',
|
|
915
|
+
);
|
|
769
916
|
}
|
|
770
917
|
return await checkGitlab(repoRoot, now, { ...depsWithExec, gitlabProject });
|
|
771
918
|
}
|
|
@@ -779,47 +926,45 @@ export async function checkCiStatus(opts = {}, deps = {}) {
|
|
|
779
926
|
// Unknown VCS value — silent no-op.
|
|
780
927
|
return null;
|
|
781
928
|
} catch (err) {
|
|
782
|
-
//
|
|
783
|
-
// These are all no-op conditions per the spec.
|
|
929
|
+
// Never throws: every failure below leaves as the third return state.
|
|
784
930
|
const msg = err instanceof Error ? err.message : String(err);
|
|
785
931
|
|
|
786
|
-
// Timeout and ENOENT (missing CLI)
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
932
|
+
// Timeout and ENOENT (missing CLI) stay SILENT on the warn channel — a
|
|
933
|
+
// machine without `glab` is a normal state, and a warn on every
|
|
934
|
+
// session-start there drowns the #1022 signal this channel carries. Since
|
|
935
|
+
// #1031 they are no longer silent on the RETURN channel: neither state
|
|
936
|
+
// established that CI is green, so both degrade.
|
|
937
|
+
if (msg === 'timeout') return degradedResult('timeout');
|
|
938
|
+
if (err && err.code === 'ENOENT') {
|
|
939
|
+
return degradedResult('cli-missing', redactUrlCredentials(msg));
|
|
792
940
|
}
|
|
793
941
|
|
|
794
942
|
// Everything else means the CLI was PRESENT but the invocation failed —
|
|
795
|
-
// non-zero exit, rejected flag, unparseable output.
|
|
796
|
-
//
|
|
797
|
-
// is exactly how #1022 (`gh repo view -R` → `unknown
|
|
798
|
-
// stayed invisible on every GitHub repo.
|
|
799
|
-
// contract (null ⇒ silent no-op) for backwards compatibility with the
|
|
800
|
-
// Phase-4 callers already written against it, so leave a stderr trace
|
|
801
|
-
// instead: non-blocking, but the next defect of this class is no longer
|
|
802
|
-
// silent. Credentials redacted defense-in-depth (#907) — the message can
|
|
803
|
-
// quote the failed argv, which carries the repo spec.
|
|
943
|
+
// non-zero exit, rejected flag, unparseable output. A bare `null` here made
|
|
944
|
+
// that state indistinguishable from "CLI not installed" AND from "CI is
|
|
945
|
+
// green", which is exactly how #1022 (`gh repo view -R` → `unknown
|
|
946
|
+
// shorthand flag: 'R'`) stayed invisible on every GitHub repo.
|
|
804
947
|
//
|
|
805
|
-
//
|
|
806
|
-
//
|
|
807
|
-
//
|
|
808
|
-
//
|
|
809
|
-
//
|
|
948
|
+
// #1031 finished the migration this comment used to describe as pending:
|
|
949
|
+
// the third state `{ severity, message, degraded }` — the shape
|
|
950
|
+
// `scripts/lib/mirror-issues-banner.mjs` established — now leaves here too,
|
|
951
|
+
// alongside (not instead of) the stderr trace. `parse-error` is carried on
|
|
952
|
+
// the error by `tagParseError`; everything else is the residual
|
|
953
|
+
// `query-failed`.
|
|
810
954
|
//
|
|
811
|
-
//
|
|
812
|
-
//
|
|
813
|
-
//
|
|
814
|
-
|
|
815
|
-
// collapses every CLI-side failure onto `null`, which a caller reads as
|
|
816
|
-
// all-clear, and it cannot be widened without changing a return contract
|
|
817
|
-
// 13 sibling banners share. Same verdict, stated caller-side, in
|
|
818
|
-
// `skills/session-start/SKILL.md` § Phase 4 (the mirror-issues
|
|
819
|
-
// paragraph): "Do not reproduce it."
|
|
955
|
+
// Credentials redacted defense-in-depth (#907) — the message can quote the
|
|
956
|
+
// failed argv, which carries the repo spec — and the redacted text is what
|
|
957
|
+
// reaches BOTH the warn and the operator-facing `message`.
|
|
958
|
+
const redacted = redactUrlCredentials(msg);
|
|
820
959
|
console.warn(
|
|
821
|
-
`WARN ci-status-banner: CI status check failed, banner suppressed — ${
|
|
960
|
+
`WARN ci-status-banner: CI status check failed, banner suppressed — ${redacted}`,
|
|
822
961
|
);
|
|
823
|
-
|
|
962
|
+
// Literal reasons on BOTH branches, never `degradedResult(reason)` with a
|
|
963
|
+
// computed variable: the enum census in the test file is a regex over this
|
|
964
|
+
// source, and a variable hides the member from it.
|
|
965
|
+
if (err && typeof err === 'object' && err.degradedReason === 'parse-error') {
|
|
966
|
+
return degradedResult('parse-error', redacted);
|
|
967
|
+
}
|
|
968
|
+
return degradedResult('query-failed', redacted);
|
|
824
969
|
}
|
|
825
970
|
}
|
|
@@ -43,18 +43,94 @@ const REQUIRED_CODEX_EVENTS = [
|
|
|
43
43
|
'Stop',
|
|
44
44
|
];
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
46
|
+
/**
|
|
47
|
+
* Every hook event the Codex runtime knows, MEASURED — not quoted from release
|
|
48
|
+
* notes. Read out of the `codex` binary shipped as codex-cli **0.144.4**
|
|
49
|
+
* (`@openai/codex-darwin-arm64/vendor/aarch64-apple-darwin/bin/codex`,
|
|
50
|
+
* 2026-09-06), which embeds one JSON Schema pair per event:
|
|
51
|
+
*
|
|
52
|
+
* strings -a <codex> | grep '"title": "'
|
|
53
|
+
* -> pre-tool-use / post-tool-use / permission-request / pre-compact
|
|
54
|
+
* / post-compact / session-start / subagent-start / subagent-stop
|
|
55
|
+
* / user-prompt-submit / stop .command.{input,output} (10 pairs)
|
|
56
|
+
*
|
|
57
|
+
* The same binary carries the manifest deserializer's key list
|
|
58
|
+
* (`PreToolUse PermissionRequest PostToolUse PreCompact PostCompact
|
|
59
|
+
* SessionStart SubagentStart SubagentStop` + the substring-deduped `Stop` /
|
|
60
|
+
* `UserPromptSubmit`) directly beside its `unexpected map key` error string —
|
|
61
|
+
* so an event key outside this set is rejected, and rejecting one key rejects
|
|
62
|
+
* the manifest that carries it.
|
|
63
|
+
*
|
|
64
|
+
* **`SessionEnd` and `Interrupt` are NOT in it.** They are not merely unwired
|
|
65
|
+
* here: at 0.144.4 they do not exist, and adding either to hooks-codex.json
|
|
66
|
+
* risks taking every already-working hook down with it. Newer Codex releases
|
|
67
|
+
* (0.148+ async hooks, 0.150+ `Interrupt`) are documented-but-unverified on
|
|
68
|
+
* this host — re-measure against the shipped binary before widening this set,
|
|
69
|
+
* never against a changelog.
|
|
70
|
+
*/
|
|
71
|
+
export const CODEX_NATIVE_EVENTS = new Set([
|
|
72
|
+
'SessionStart',
|
|
73
|
+
'UserPromptSubmit',
|
|
74
|
+
'PreToolUse',
|
|
75
|
+
'PermissionRequest',
|
|
76
|
+
'PostToolUse',
|
|
77
|
+
'PreCompact',
|
|
78
|
+
'PostCompact',
|
|
79
|
+
'SubagentStart',
|
|
80
|
+
'SubagentStop',
|
|
81
|
+
'Stop',
|
|
51
82
|
]);
|
|
52
83
|
|
|
53
|
-
|
|
84
|
+
/**
|
|
85
|
+
* Claude hook events this repo wires that Codex 0.144.4 has no counterpart for.
|
|
86
|
+
* DERIVED from {@link CODEX_NATIVE_EVENTS} rather than hand-listed, so a new
|
|
87
|
+
* Claude event is forbidden on Codex by construction until someone measures it
|
|
88
|
+
* into the native set above.
|
|
89
|
+
*/
|
|
90
|
+
const FORBIDDEN_CODEX_EVENTS = new Set(
|
|
91
|
+
['SessionEnd', 'PostToolUseFailure', 'PostToolBatch', 'CwdChanged', 'Interrupt']
|
|
92
|
+
.filter((event) => !CODEX_NATIVE_EVENTS.has(event)),
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* The tool-name vocabulary Codex puts in `tool_name`, measured at 0.144.4 from
|
|
97
|
+
* the same binary. This is the load-bearing incompatibility, and it is NOT the
|
|
98
|
+
* one the older comments in `check-hooks-symmetry.mjs` claimed.
|
|
99
|
+
*
|
|
100
|
+
* `pre-tool-use.command.input` REQUIRES `tool_name` and `tool_input` (alongside
|
|
101
|
+
* `cwd`, `hook_event_name`, `model`, `permission_mode`, `session_id`,
|
|
102
|
+
* `tool_use_id`, `transcript_path`, `turn_id`) — so the payload fields ARE
|
|
103
|
+
* delivered. What differs is their VALUES: Codex has no `Bash`, `Edit`, `Write`
|
|
104
|
+
* or `MultiEdit` tool (`strings -a <codex> | grep -c '"Bash"'` -> 0). Every
|
|
105
|
+
* PreToolUse guard in `hooks/` opens with an equality gate on one of those four
|
|
106
|
+
* names and returns `emitAllow()` otherwise, so wiring one here yields a
|
|
107
|
+
* handler that runs, matches nothing, and allows everything — false
|
|
108
|
+
* enforcement, which is worse than a registered gap.
|
|
109
|
+
*
|
|
110
|
+
* The adapter this actually needs is a tool-name MAP (shell/exec_command/
|
|
111
|
+
* unified_exec -> Bash, apply_patch -> Edit/Write), not a payload bridge.
|
|
112
|
+
*/
|
|
113
|
+
export const CODEX_TOOL_NAMES = Object.freeze([
|
|
114
|
+
'shell',
|
|
115
|
+
'exec_command',
|
|
116
|
+
'unified_exec',
|
|
117
|
+
'apply_patch',
|
|
118
|
+
'update_plan',
|
|
119
|
+
'view_image',
|
|
120
|
+
]);
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Hook handlers that read an Edit/Write `tool_input.file_path` payload. Codex
|
|
124
|
+
* emits `apply_patch` payloads of a different shape, so wiring one of these into
|
|
125
|
+
* hooks-codex.json produces a handler that silently never fires. Exported so the
|
|
126
|
+
* contract test can assert the census rather than re-list it.
|
|
127
|
+
*/
|
|
128
|
+
export const DISALLOWED_EDIT_HANDLERS = [
|
|
54
129
|
'enforce-scope.mjs',
|
|
55
130
|
'config-protection.mjs',
|
|
56
131
|
'post-edit-validate.mjs',
|
|
57
132
|
'post-tooluse-frontend-slop.mjs',
|
|
133
|
+
'post-edit-import-probe.mjs',
|
|
58
134
|
];
|
|
59
135
|
|
|
60
136
|
const CODEX_HOOK_WRAPPER_COMMAND =
|
|
@@ -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
|
* auto-dream.mjs — Parser for the top-level `auto-dream:` YAML block (issue #566).
|
|
@@ -32,7 +33,7 @@ export function _parseAutoDream(content) {
|
|
|
32
33
|
'min-confidence': 0.5,
|
|
33
34
|
};
|
|
34
35
|
|
|
35
|
-
const lines = content
|
|
36
|
+
const lines = preprocessBlockLines(content);
|
|
36
37
|
let inBlock = false;
|
|
37
38
|
const blockLines = [];
|
|
38
39
|
|
|
@@ -32,6 +32,14 @@
|
|
|
32
32
|
* The two `**` markers are independent (`**key:` and `key:**` both match),
|
|
33
33
|
* mirroring the tolerant #823 vault-integration regex.
|
|
34
34
|
*
|
|
35
|
+
* COMMENT-STRIPPING IS THE CALLER'S JOB (#1222). Every matcher here sees RAW
|
|
36
|
+
* lines: a header inside a `<!-- … -->` HTML comment matches exactly like a live
|
|
37
|
+
* one. That is deliberate — stripping comments needs the `block-preprocess.mjs`
|
|
38
|
+
* state machine, and importing it would end this module's zero-import leaf
|
|
39
|
+
* status. A caller that must agree with a comment-STRIPPING parser preprocesses
|
|
40
|
+
* its content first (`preprocessBlockLinesNoDash(content).join('\n')`) — see
|
|
41
|
+
* `dispatcher-autonomy-capture.mjs` `isDispatcherAutonomyBlockPresent()`.
|
|
42
|
+
*
|
|
35
43
|
* `matchBlockHeaderDetailed` (#1185) is a SEPARATE, additive matcher below for
|
|
36
44
|
* parsers that need what this contract deliberately rejects — an indented
|
|
37
45
|
* (nested) header and/or an inline value. It does not change the contract
|