session-orchestrator 5.1.0 → 5.3.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 +3 -1
- package/.agents/skills/autopilot/SKILL.md +6 -1
- package/.agents/skills/autopilot/agents/openai.yaml +5 -0
- package/.agents/skills/bootstrap/SKILL.md +7 -1
- package/.agents/skills/bootstrap/agents/openai.yaml +5 -0
- package/.agents/skills/brainstorm/SKILL.md +8 -1
- package/.agents/skills/brainstorm/agents/openai.yaml +5 -0
- package/.agents/skills/claude-md-drift-check/SKILL.md +3 -1
- package/.agents/skills/close/SKILL.md +21 -0
- package/.agents/skills/close/agents/openai.yaml +5 -0
- package/.agents/skills/convergence-monitoring/SKILL.md +4 -2
- package/.agents/skills/debug/SKILL.md +7 -1
- package/.agents/skills/debug/agents/openai.yaml +5 -0
- package/.agents/skills/discovery/SKILL.md +7 -2
- package/.agents/skills/discovery/agents/openai.yaml +5 -0
- package/.agents/skills/dispatcher/SKILL.md +7 -1
- package/.agents/skills/dispatcher/agents/openai.yaml +5 -0
- package/.agents/skills/docs-orchestrator/SKILL.md +3 -1
- package/.agents/skills/ecosystem-health/SKILL.md +3 -1
- package/.agents/skills/eli5/SKILL.md +7 -1
- package/.agents/skills/eli5/agents/openai.yaml +5 -0
- package/.agents/skills/eval/SKILL.md +7 -2
- package/.agents/skills/eval/agents/openai.yaml +5 -0
- package/.agents/skills/evolve/SKILL.md +8 -3
- package/.agents/skills/evolve/agents/openai.yaml +5 -0
- package/.agents/skills/frontmatter-guard/SKILL.md +3 -1
- package/.agents/skills/gitlab-ops/SKILL.md +3 -1
- package/.agents/skills/gitlab-portfolio/SKILL.md +3 -1
- package/.agents/skills/go/SKILL.md +22 -0
- package/.agents/skills/go/agents/openai.yaml +5 -0
- package/.agents/skills/grill/SKILL.md +7 -1
- package/.agents/skills/grill/agents/openai.yaml +5 -0
- package/.agents/skills/harness-audit/SKILL.md +20 -0
- package/.agents/skills/harness-audit/agents/openai.yaml +5 -0
- package/.agents/skills/hook-development/SKILL.md +3 -1
- package/.agents/skills/mcp-builder/SKILL.md +3 -1
- package/.agents/skills/memory-cleanup/SKILL.md +6 -1
- package/.agents/skills/memory-cleanup/agents/openai.yaml +5 -0
- package/.agents/skills/mode-selector/SKILL.md +3 -1
- package/.agents/skills/npm-publish/SKILL.md +4 -2
- package/.agents/skills/peekaboo-driver/SKILL.md +3 -1
- package/.agents/skills/persona-panel/SKILL.md +6 -1
- package/.agents/skills/persona-panel/agents/openai.yaml +5 -0
- package/.agents/skills/plan/SKILL.md +8 -2
- package/.agents/skills/plan/agents/openai.yaml +5 -0
- package/.agents/skills/playwright-driver/SKILL.md +3 -1
- package/.agents/skills/portfolio/SKILL.md +21 -0
- package/.agents/skills/portfolio/agents/openai.yaml +5 -0
- package/.agents/skills/quality-gates/SKILL.md +3 -1
- package/.agents/skills/reconcile/SKILL.md +6 -1
- package/.agents/skills/reconcile/agents/openai.yaml +5 -0
- package/.agents/skills/release/SKILL.md +22 -0
- package/.agents/skills/release/agents/openai.yaml +5 -0
- package/.agents/skills/remote-offload/SKILL.md +3 -1
- package/.agents/skills/repo-audit/SKILL.md +6 -1
- package/.agents/skills/repo-audit/agents/openai.yaml +5 -0
- package/.agents/skills/session/SKILL.md +21 -0
- package/.agents/skills/session/agents/openai.yaml +5 -0
- package/.agents/skills/session-end/SKILL.md +3 -1
- package/.agents/skills/session-plan/SKILL.md +3 -1
- package/.agents/skills/session-start/SKILL.md +3 -1
- package/.agents/skills/spinout/SKILL.md +6 -1
- package/.agents/skills/spinout/agents/openai.yaml +5 -0
- package/.agents/skills/sunset-review/SKILL.md +7 -1
- package/.agents/skills/sunset-review/agents/openai.yaml +5 -0
- package/.agents/skills/templates-ack/SKILL.md +21 -0
- package/.agents/skills/templates-ack/agents/openai.yaml +5 -0
- package/.agents/skills/test/SKILL.md +21 -0
- package/.agents/skills/test/agents/openai.yaml +5 -0
- package/.agents/skills/test-runner/SKILL.md +3 -1
- package/.agents/skills/tmux-layout/SKILL.md +3 -1
- package/.agents/skills/using-orchestrator/SKILL.md +3 -1
- package/.agents/skills/ux-grill/SKILL.md +7 -1
- package/.agents/skills/ux-grill/agents/openai.yaml +5 -0
- package/.agents/skills/vault-mirror/SKILL.md +3 -1
- package/.agents/skills/vault-sync/SKILL.md +3 -1
- package/.agents/skills/wave-executor/SKILL.md +3 -1
- package/.agents/skills/write-executable-plan/SKILL.md +3 -1
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +4 -4
- package/.codex-plugin/skills/autopilot/SKILL.md +5 -4
- package/.codex-plugin/skills/bootstrap/SKILL.md +8 -4
- package/.codex-plugin/skills/brainstorm/SKILL.md +11 -4
- package/.codex-plugin/skills/close/SKILL.md +3 -3
- package/.codex-plugin/skills/convergence-monitoring/SKILL.md +1 -1
- package/.codex-plugin/skills/debug/SKILL.md +11 -4
- package/.codex-plugin/skills/discovery/SKILL.md +8 -4
- package/.codex-plugin/skills/dispatcher/SKILL.md +4 -4
- package/.codex-plugin/skills/eli5/SKILL.md +9 -4
- package/.codex-plugin/skills/eval/SKILL.md +9 -4
- package/.codex-plugin/skills/evolve/SKILL.md +9 -4
- package/.codex-plugin/skills/go/SKILL.md +3 -3
- package/.codex-plugin/skills/grill/SKILL.md +11 -4
- package/.codex-plugin/skills/harness-audit/SKILL.md +4 -3
- package/.codex-plugin/skills/memory-cleanup/SKILL.md +9 -4
- package/.codex-plugin/skills/npm-publish/SKILL.md +1 -1
- package/.codex-plugin/skills/persona-panel/SKILL.md +5 -5
- package/.codex-plugin/skills/plan/SKILL.md +8 -4
- package/.codex-plugin/skills/portfolio/SKILL.md +3 -3
- package/.codex-plugin/skills/reconcile/SKILL.md +9 -4
- package/.codex-plugin/skills/release/SKILL.md +3 -3
- package/.codex-plugin/skills/repo-audit/SKILL.md +6 -4
- package/.codex-plugin/skills/session/SKILL.md +1 -1
- package/.codex-plugin/skills/spinout/SKILL.md +4 -4
- package/.codex-plugin/skills/sunset-review/SKILL.md +5 -4
- package/.codex-plugin/skills/test/SKILL.md +3 -3
- package/.codex-plugin/skills/ux-grill/SKILL.md +11 -4
- package/.cursor/commands/autopilot.md +4 -4
- package/.cursor/commands/bootstrap.md +5 -4
- package/.cursor/commands/brainstorm.md +5 -4
- package/.cursor/commands/close.md +4 -3
- package/.cursor/commands/debug.md +4 -4
- package/.cursor/commands/discovery.md +4 -4
- package/.cursor/commands/dispatcher.md +4 -4
- package/.cursor/commands/eli5.md +4 -4
- package/.cursor/commands/eval.md +4 -4
- package/.cursor/commands/evolve.md +4 -4
- package/.cursor/commands/go.md +4 -3
- package/.cursor/commands/grill.md +4 -4
- package/.cursor/commands/harness-audit.md +3 -3
- package/.cursor/commands/memory-cleanup.md +4 -4
- package/.cursor/commands/persona-panel.md +4 -4
- package/.cursor/commands/plan.md +5 -4
- package/.cursor/commands/portfolio.md +3 -3
- package/.cursor/commands/reconcile.md +4 -4
- package/.cursor/commands/release.md +4 -3
- package/.cursor/commands/repo-audit.md +4 -4
- package/.cursor/commands/session.md +1 -1
- package/.cursor/commands/spinout.md +4 -4
- package/.cursor/commands/sunset-review.md +4 -4
- package/.cursor/commands/test.md +3 -3
- package/.cursor/commands/ux-grill.md +4 -4
- package/.cursor/rules/000-session-orchestrator.mdc +0 -2
- package/.cursor/rules/010-session-workflow.mdc +2 -2
- package/.cursor/rules/050-plan.mdc +1 -1
- package/.cursor/skills/bootstrap/SKILL.md +1 -0
- package/.cursor/skills/close/SKILL.md +13 -0
- package/.cursor/skills/convergence-monitoring/SKILL.md +1 -0
- package/.cursor/skills/debug/SKILL.md +0 -1
- package/.cursor/skills/discovery/SKILL.md +0 -1
- package/.cursor/skills/dispatcher/SKILL.md +0 -1
- package/.cursor/skills/eli5/SKILL.md +0 -1
- package/.cursor/skills/eval/SKILL.md +1 -1
- package/.cursor/skills/evolve/SKILL.md +0 -1
- package/.cursor/skills/go/SKILL.md +13 -0
- package/.cursor/skills/grill/SKILL.md +0 -1
- package/.cursor/skills/harness-audit/SKILL.md +12 -0
- package/.cursor/skills/npm-publish/SKILL.md +1 -0
- package/.cursor/skills/portfolio/SKILL.md +12 -0
- package/.cursor/skills/release/SKILL.md +13 -0
- package/.cursor/skills/repo-audit/SKILL.md +0 -1
- package/.cursor/skills/sunset-review/SKILL.md +0 -1
- package/.cursor/skills/test/SKILL.md +12 -0
- package/.cursor/skills/ux-grill/SKILL.md +0 -1
- package/.cursor-plugin/plugin.json +1 -1
- package/.orchestrator/policy/blocked-commands.json +13 -4
- package/AGENTS.md +3 -2
- package/CHANGELOG.md +197 -0
- package/README.md +11 -9
- package/SECURITY.md +12 -0
- package/agents/dialectic-deriver.md +13 -10
- package/agents/eval-judge.md +67 -45
- package/agents/skill-applied-judge.md +34 -19
- package/commands/session.md +17 -3
- package/docs/baseline.md +12 -6
- package/docs/ci-setup.md +53 -0
- package/docs/codex-setup.md +15 -3
- package/docs/components.md +13 -6
- package/docs/events-schema.md +59 -9
- package/docs/install.md +16 -0
- package/docs/persona-panel.md +1 -1
- package/docs/pi-setup.md +1 -1
- package/docs/rule-authoring.md +135 -14
- package/docs/scope-collision-guard.md +2 -0
- package/docs/session-config-reference.md +106 -11
- package/docs/session-config-template.md +31 -2
- package/docs/telemetry.md +2 -0
- package/hooks/_lib/hook-import-set.json +125 -8
- package/hooks/_lib/subagent-paths.mjs +15 -0
- package/hooks/_lib/subagent-transcript.mjs +582 -31
- package/hooks/_lib/vcs-create-matcher.mjs +217 -62
- package/hooks/config-protection.mjs +11 -3
- package/hooks/cwd-change-restore.mjs +11 -3
- package/hooks/enforce-commands.mjs +70 -23
- package/hooks/enforce-scope.mjs +143 -33
- package/hooks/hooks-codex.json +1 -1
- package/hooks/hooks.json +1 -1
- package/hooks/loop-guard.mjs +11 -3
- package/hooks/on-session-end.mjs +72 -25
- package/hooks/on-session-start.mjs +48 -11
- package/hooks/on-stop.mjs +211 -23
- package/hooks/operator-steer.mjs +11 -3
- package/hooks/post-bash-issue-budget-refund.mjs +18 -8
- package/hooks/post-bash-write-verify.mjs +6 -2
- package/hooks/post-edit-import-probe.mjs +17 -9
- package/hooks/post-edit-validate.mjs +13 -5
- package/hooks/post-subagent-discovery-validator.mjs +98 -13
- package/hooks/post-tool-batch-wave-signal.mjs +200 -38
- package/hooks/post-tool-failure-corrective-context.mjs +11 -5
- package/hooks/post-tooluse-frontend-slop.mjs +10 -4
- package/hooks/pre-auq-clarity.mjs +18 -2
- package/hooks/pre-bash-destructive-guard.mjs +80 -9
- package/hooks/pre-bash-issue-budget.mjs +119 -28
- package/hooks/pre-bash-memory-propose-audit.mjs +86 -54
- package/hooks/pre-bash-sessions-ledger-guard.mjs +391 -20
- package/hooks/pre-bash-staging-fence.mjs +335 -31
- package/hooks/pre-bash-templates-first.mjs +19 -14
- package/hooks/pre-task-scope-disjoint.mjs +385 -5
- package/hooks/skill-invocation-telemetry.mjs +2 -1
- package/hooks/subagent-telemetry.mjs +15 -19
- package/hooks/wave-scope-commit-guard.mjs +197 -100
- package/monitors/monitors.json +1 -1
- package/output-styles/wave-summary.md +1 -1
- package/package.json +2 -1
- package/pi/prompts/autopilot.md +3 -3
- package/pi/prompts/bootstrap.md +3 -3
- package/pi/prompts/brainstorm.md +3 -3
- package/pi/prompts/close.md +2 -2
- package/pi/prompts/debug.md +3 -3
- package/pi/prompts/discovery.md +3 -3
- package/pi/prompts/dispatcher.md +3 -3
- package/pi/prompts/eli5.md +3 -3
- package/pi/prompts/eval.md +3 -3
- package/pi/prompts/evolve.md +3 -3
- package/pi/prompts/go.md +2 -2
- package/pi/prompts/grill.md +3 -3
- package/pi/prompts/harness-audit.md +2 -3
- package/pi/prompts/memory-cleanup.md +3 -3
- package/pi/prompts/persona-panel.md +3 -3
- package/pi/prompts/plan.md +3 -3
- package/pi/prompts/portfolio.md +2 -2
- package/pi/prompts/reconcile.md +3 -3
- package/pi/prompts/release.md +3 -3
- package/pi/prompts/repo-audit.md +3 -4
- package/pi/prompts/session.md +2 -2
- package/pi/prompts/spinout.md +3 -3
- package/pi/prompts/sunset-review.md +3 -3
- package/pi/prompts/templates-ack.md +1 -1
- package/pi/prompts/test.md +3 -3
- package/pi/prompts/ux-grill.md +3 -3
- package/rules/README.md +1 -1
- package/rules/opt-in-domain/prompt-caching.md +1 -1
- package/rules/opt-in-stack/backend-data.md +1 -1
- package/rules/opt-in-stack/backend.md +3 -3
- package/rules/opt-in-stack/frontend.md +1 -1
- package/rules/opt-in-stack/security-web.md +3 -3
- package/rules/opt-in-stack/swift.md +1 -1
- package/scripts/archive-closed-prds.mjs +2 -2
- package/scripts/auq-audit.mjs +2 -3
- package/scripts/autopilot.mjs +23 -2
- package/scripts/backfill-abandoned-sessions.mjs +171 -15
- package/scripts/backfill-evidence-digest.mjs +2 -1
- package/scripts/backfill-learnings-from-vault.mjs +2 -2
- package/scripts/check-package-manager.mjs +2 -2
- package/scripts/check-sessions-integrity.mjs +300 -0
- package/scripts/ci/assert-vitest-green.mjs +2 -1
- package/scripts/dialectic-deriver.mjs +50 -13
- package/scripts/emit-session.mjs +77 -32
- package/scripts/eval-session.mjs +65 -3
- package/scripts/export-hw-learnings.mjs +2 -1
- package/scripts/express-path.mjs +1 -1
- package/scripts/gc-stale-worktrees.mjs +2 -1
- package/scripts/generate-agents-skills.mjs +102 -29
- package/scripts/generate-codex-skills.mjs +48 -4
- package/scripts/generate-cursor-adapter.mjs +220 -11
- package/scripts/generate-hook-import-set.mjs +12 -27
- package/scripts/generate-pi-prompts.mjs +183 -13
- package/scripts/github-protection-audit.mjs +2 -3
- package/scripts/lib/agent-frontmatter.mjs +23 -1
- package/scripts/lib/agent-status.mjs +2 -31
- package/scripts/lib/auq/clarity.mjs +10 -2
- package/scripts/lib/auq/parse.mjs +12 -31
- package/scripts/lib/auq/schema.mjs +56 -41
- package/scripts/lib/auto-dialectic.mjs +304 -15
- package/scripts/lib/autopilot/flags.mjs +12 -1
- package/scripts/lib/autopilot/kill-switches.mjs +6 -3
- package/scripts/lib/autopilot/loop.mjs +14 -1
- package/scripts/lib/autopilot/stall-sampler.mjs +80 -23
- package/scripts/lib/ci-status-banner.mjs +376 -16
- package/scripts/lib/claude-md-budget-lint.mjs +2 -5
- package/scripts/lib/command-blocker.mjs +408 -33
- package/scripts/lib/config/dialectic.mjs +12 -3
- package/scripts/lib/config/drift-check.mjs +19 -0
- package/scripts/lib/config/gate.mjs +74 -0
- package/scripts/lib/config/reaper.mjs +162 -0
- package/scripts/lib/config.mjs +14 -0
- package/scripts/lib/convergence-monitor.mjs +76 -13
- package/scripts/lib/cursor-hook-bridge.mjs +2 -2
- package/scripts/lib/description-surface.mjs +2 -5
- package/scripts/lib/dispatcher/cli.mjs +2 -1
- package/scripts/lib/ecosystem-health.mjs +11 -0
- package/scripts/lib/ecosystem-wizard.mjs +2 -1
- package/scripts/lib/eval/engine.mjs +421 -53
- package/scripts/lib/eval/judge.mjs +463 -40
- package/scripts/lib/eval/schema.mjs +10 -1
- package/scripts/lib/events-rotation.mjs +221 -25
- package/scripts/lib/events-schema.mjs +114 -0
- package/scripts/lib/events.mjs +524 -5
- package/scripts/lib/fetch-baseline.mjs +3 -8
- package/scripts/lib/frontmatter-guard.mjs +21 -10
- package/scripts/lib/gates/gate-baseline.mjs +27 -2
- package/scripts/lib/gates/gate-full.mjs +28 -3
- package/scripts/lib/gates/gate-helpers.mjs +243 -21
- package/scripts/lib/gates/gate-incremental.mjs +28 -3
- package/scripts/lib/gates/gate-per-file.mjs +27 -2
- package/scripts/lib/gitlab-ops/stale-mr-sweep.mjs +2 -1
- package/scripts/lib/gitlab-portfolio/cli.mjs +2 -1
- package/scripts/lib/gitlab-portfolio/markdown-writer.mjs +6 -1
- package/scripts/lib/instruction-budget-guard.mjs +332 -50
- package/scripts/lib/io.mjs +42 -8
- package/scripts/lib/is-main-module.mjs +82 -0
- package/scripts/lib/issue-close-strip-labels.mjs +207 -49
- package/scripts/lib/js-mask.mjs +197 -0
- package/scripts/lib/learnings/evolve-telemetry.mjs +11 -7
- package/scripts/lib/locks/index.mjs +32 -25
- package/scripts/lib/maintenance-due-banner.mjs +122 -91
- package/scripts/lib/orphan-reaper.mjs +1588 -0
- package/scripts/lib/peer-cards/merger.mjs +48 -10
- package/scripts/lib/peer-cards/reader.mjs +78 -2
- package/scripts/lib/peer-discovery.mjs +2 -5
- package/scripts/lib/playwright-driver/runner.mjs +2 -1
- package/scripts/lib/process-group.mjs +899 -0
- package/scripts/lib/quality-gate.mjs +107 -28
- package/scripts/lib/reconcile/backlog.mjs +368 -0
- package/scripts/lib/reconcile/engine.mjs +55 -188
- package/scripts/lib/reconcile/rule-expiry-sweep.mjs +884 -0
- package/scripts/lib/reconcile/sanitize.mjs +69 -3
- package/scripts/lib/reconcile-nudge-banner.mjs +138 -45
- package/scripts/lib/resource-probe/parsers.mjs +31 -0
- package/scripts/lib/rule-loader.mjs +41 -12
- package/scripts/lib/rules-sync.mjs +2 -5
- package/scripts/lib/scope-echo.mjs +429 -7
- package/scripts/lib/scope-gate.mjs +605 -1
- package/scripts/lib/session-close-backfill.mjs +91 -12
- package/scripts/lib/session-id.mjs +9 -20
- package/scripts/lib/session-invocation.mjs +20 -0
- package/scripts/lib/session-schema/constants.mjs +30 -2
- package/scripts/lib/session-schema/normalizer.mjs +56 -4
- package/scripts/lib/session-schema.mjs +8 -3
- package/scripts/lib/session-start-probes.mjs +95 -10
- package/scripts/lib/sessions-canonical.mjs +23 -0
- package/scripts/lib/sessions-integrity-banner.mjs +7 -1
- package/scripts/lib/sessions-staleness-banner.mjs +193 -51
- package/scripts/lib/skill-evidence-window.mjs +891 -0
- package/scripts/lib/skill-evolution/candidate-intake.mjs +133 -12
- package/scripts/lib/skill-evolution/engine.mjs +18 -9
- package/scripts/lib/skill-judge.mjs +45 -3
- package/scripts/lib/state-md.mjs +84 -3
- package/scripts/lib/sunset/walker.mjs +31 -4
- package/scripts/lib/tail-window.mjs +56 -0
- package/scripts/lib/telemetry/schema.mjs +30 -0
- package/scripts/lib/telemetry/sync.mjs +61 -6
- package/scripts/lib/telemetry-flush-health-banner.mjs +4 -22
- package/scripts/lib/test-runner/issue-reconcile.mjs +48 -16
- package/scripts/lib/tests-src-ratio.mjs +2 -6
- package/scripts/lib/tmux-layout/telemetry-stats.mjs +74 -14
- package/scripts/lib/user-invocable-skills.mjs +205 -0
- package/scripts/lib/ux-grill/reconcile.mjs +48 -22
- package/scripts/lib/validate/check-agents-skills.mjs +26 -15
- package/scripts/lib/validate/check-banner-parity.mjs +2 -2
- package/scripts/lib/validate/check-cursor-adapter.mjs +3 -2
- package/scripts/lib/validate/check-dead-bridge.mjs +2 -2
- package/scripts/lib/validate/check-doc-cli-commands.mjs +2 -2
- package/scripts/lib/validate/check-entry-guard.mjs +329 -0
- package/scripts/lib/validate/check-guard-requires-parity.mjs +2 -2
- package/scripts/lib/validate/check-hook-entry-guards.mjs +636 -0
- package/scripts/lib/validate/check-hooks-emit-event-guard.mjs +2 -2
- package/scripts/lib/validate/check-learning-provenance.mjs +2 -2
- package/scripts/lib/validate/check-pi-prompts.mjs +1 -0
- package/scripts/lib/validate/check-rules.mjs +7 -5
- package/scripts/lib/validate/check-skill-links.mjs +35 -6
- package/scripts/lib/validate/check-skill-script-paths.mjs +241 -29
- package/scripts/lib/validate/check-test-git-config-target.mjs +26 -36
- package/scripts/lib/validate/check-unicode-safety.mjs +2 -2
- package/scripts/lib/validate/check-untracked-test-deps.mjs +9 -104
- package/scripts/lib/validate/check-unwired-features.mjs +220 -33
- package/scripts/lib/validate/check-validator-registration.mjs +36 -12
- package/scripts/lib/validate/check-vcs-repo-flag.mjs +2 -2
- package/scripts/lib/validate/confidential-names.mjs +10 -0
- package/scripts/lib/validate-vendored-rules.mjs +39 -12
- package/scripts/lib/vault-mirror/namespace.mjs +46 -8
- package/scripts/lib/vault-mirror/process.mjs +10 -3
- package/scripts/lib/vault-mirror/render-sessions.mjs +12 -2
- package/scripts/lib/vault-status/narrative-mirror.mjs +31 -7
- package/scripts/lib/vault-yaml.mjs +118 -0
- package/scripts/lib/wave-transcript-tail.mjs +2 -2
- package/scripts/lib/worktree/lifecycle.mjs +153 -1
- package/scripts/lock-reaper.mjs +2 -1
- package/scripts/materialize-wave-scope.mjs +87 -4
- package/scripts/migrate-sessions-jsonl.mjs +2 -1
- package/scripts/migrate-vault-paths.mjs +2 -3
- package/scripts/release-session-lock.mjs +305 -0
- package/scripts/release.mjs +109 -39
- package/scripts/relocate-vault-corpus.mjs +2 -3
- package/scripts/repair-invalid-sessions.mjs +2 -2
- package/scripts/resolve-session-invocation.mjs +59 -0
- package/scripts/run-quality-gate.mjs +156 -17
- package/scripts/session-shape.mjs +2 -2
- package/scripts/site-numbers.mjs +35 -11
- package/scripts/sweep-expired-rules.mjs +227 -0
- package/scripts/validate-plugin.mjs +21 -0
- package/scripts/validate-wave-scope.mjs +32 -105
- package/scripts/vault-consolidate.mjs +2 -2
- package/scripts/vault-mirror.mjs +11 -4
- package/scripts/wave-scope-binding.mjs +2 -3
- package/skills/_shared/bootstrap-gate.md +1 -1
- package/skills/_shared/monitor-patterns.md +1 -1
- package/skills/_shared/platform-tools.md +23 -11
- package/skills/_shared/research-evidence.md +53 -0
- package/skills/_shared/state-ownership.md +3 -0
- package/skills/autopilot/SKILL.md +80 -11
- package/skills/bootstrap/SKILL.md +51 -1
- package/skills/brainstorm/SKILL.md +16 -0
- package/skills/claude-md-drift-check/SKILL.md +1 -1
- package/skills/claude-md-drift-check/checker.mjs +49 -11
- package/{commands/close.md → skills/close/SKILL.md} +9 -3
- package/skills/convergence-monitoring/README.md +8 -1
- package/skills/convergence-monitoring/SIGNALS.md +50 -6
- package/skills/convergence-monitoring/SKILL.md +15 -6
- package/skills/debug/SKILL.md +10 -0
- package/skills/discovery/SKILL.md +24 -1
- package/skills/discovery/probes-session.md +2 -2
- package/skills/dispatcher/SKILL.md +38 -7
- package/skills/eli5/SKILL.md +11 -0
- package/skills/eval/SKILL.md +52 -23
- package/skills/eval/rubric-v1.md +1 -0
- package/skills/eval/rubric-v2.md +457 -0
- package/skills/evolve/SKILL.md +9 -2
- package/skills/evolve/references/evolve-dialectic-mode.md +46 -25
- package/skills/gitlab-ops/SKILL.md +3 -2
- package/{commands/go.md → skills/go/SKILL.md} +9 -1
- package/skills/grill/SKILL.md +19 -0
- package/{commands/harness-audit.md → skills/harness-audit/SKILL.md} +7 -2
- package/skills/hook-development/SKILL.md +46 -41
- package/skills/memory-cleanup/SKILL.md +7 -0
- package/skills/npm-publish/SKILL.md +2 -2
- package/skills/persona-panel/SKILL.md +56 -1
- package/skills/persona-panel/persona-format.md +1 -1
- package/skills/plan/SKILL.md +28 -1
- package/{commands/portfolio.md → skills/portfolio/SKILL.md} +8 -2
- package/skills/reconcile/SKILL.md +21 -0
- package/{commands/release.md → skills/release/SKILL.md} +16 -2
- package/skills/repo-audit/SKILL.md +7 -0
- package/skills/session-end/SKILL.md +13 -16
- package/skills/session-end/discovery-scan.md +1 -1
- package/skills/session-end/phase-3-6-tail.md +55 -9
- package/skills/session-end/plan-verification.md +2 -2
- package/skills/session-end/references/phase-5-issue-cleanup.md +9 -14
- package/skills/session-end/session-metrics-write.md +10 -0
- package/skills/session-plan/SKILL.md +18 -6
- package/skills/session-plan/references/session-plan-task-classification.md +2 -2
- package/skills/session-start/SKILL.md +5 -4
- package/skills/session-start/phase-8-5-express-path.md +6 -6
- package/skills/session-start/references/phase-1-5-session-continuity.md +1 -1
- package/skills/session-start/references/phase-2-7-portfolio-snapshot.md +1 -1
- package/skills/session-start/references/phase-4-ssot-environment-check.md +6 -4
- package/skills/spinout/SKILL.md +12 -1
- package/skills/sunset-review/SKILL.md +13 -0
- package/{commands/test.md → skills/test/SKILL.md} +10 -4
- package/skills/ux-grill/SKILL.md +20 -2
- package/skills/wave-executor/SKILL.md +14 -7
- package/skills/wave-executor/circuit-breaker.md +2 -0
- package/skills/wave-executor/references/wave-executor-state-init.md +18 -4
- package/skills/wave-executor/references/wave-loop-dispatch.md +5 -2
- package/skills/wave-executor/references/wave-loop-review.md +17 -1
- package/commands/autopilot.md +0 -80
- package/commands/bootstrap.md +0 -56
- package/commands/brainstorm.md +0 -48
- package/commands/debug.md +0 -36
- package/commands/discovery.md +0 -32
- package/commands/dispatcher.md +0 -59
- package/commands/eli5.md +0 -33
- package/commands/eval.md +0 -28
- package/commands/evolve.md +0 -10
- package/commands/grill.md +0 -45
- package/commands/memory-cleanup.md +0 -26
- package/commands/persona-panel.md +0 -121
- package/commands/plan.md +0 -15
- package/commands/reconcile.md +0 -23
- package/commands/repo-audit.md +0 -24
- package/commands/spinout.md +0 -15
- package/commands/sunset-review.md +0 -27
- package/commands/ux-grill.md +0 -51
|
@@ -20,19 +20,24 @@
|
|
|
20
20
|
* resolve to the wrong GitLab instance on a multi-host machine, turning
|
|
21
21
|
* this whole module into a silent no-op.
|
|
22
22
|
*
|
|
23
|
-
* Usage (
|
|
23
|
+
* Usage (session-end Phase 5 issue-close step) — ONE command strips, closes
|
|
24
|
+
* and verifies every resolved issue:
|
|
24
25
|
*
|
|
25
|
-
*
|
|
26
|
+
* node scripts/lib/issue-close-strip-labels.mjs --close --vcs gitlab 1388 1387
|
|
26
27
|
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
28
|
+
* It prints one JSON line per id and exits 1 when any id did not verify as
|
|
29
|
+
* closed. The mechanical call exists because the earlier prose-only step
|
|
30
|
+
* ("call stripStatusLabels, then close") was skipped often enough that 339
|
|
31
|
+
* closed issues still carried `status:in-progress` (measured 2026-09-19).
|
|
32
|
+
* `closeIssues()` is the same sequence as a library call; `stripStatusLabels()`
|
|
33
|
+
* stays exported for callers that only strip.
|
|
31
34
|
*
|
|
32
35
|
* Auto-created by `scripts/lib/issue-close-strip-labels.mjs` (#308).
|
|
33
36
|
*/
|
|
34
37
|
|
|
35
38
|
import { execFileSync } from 'node:child_process';
|
|
39
|
+
import { parseArgs } from 'node:util';
|
|
40
|
+
import { isMainModule } from './is-main-module.mjs';
|
|
36
41
|
import { resolveRepoSpec } from './vcs-repo-spec.mjs';
|
|
37
42
|
|
|
38
43
|
/** Regex that matches any `status:*` label name. */
|
|
@@ -43,11 +48,12 @@ const STATUS_LABEL_RE = /^status:/;
|
|
|
43
48
|
*
|
|
44
49
|
* @param {string} cmd
|
|
45
50
|
* @param {string[]} args
|
|
51
|
+
* @param {typeof execFileSync} [execFile] injectable executor (tests)
|
|
46
52
|
* @returns {{ ok: boolean, stdout: string, stderr: string }}
|
|
47
53
|
*/
|
|
48
|
-
function runCli(cmd, args) {
|
|
54
|
+
function runCli(cmd, args, execFile = execFileSync) {
|
|
49
55
|
try {
|
|
50
|
-
const stdout =
|
|
56
|
+
const stdout = execFile(cmd, args, {
|
|
51
57
|
encoding: 'utf8',
|
|
52
58
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
53
59
|
});
|
|
@@ -61,50 +67,50 @@ function runCli(cmd, args) {
|
|
|
61
67
|
}
|
|
62
68
|
|
|
63
69
|
/**
|
|
64
|
-
*
|
|
70
|
+
* Read an issue as JSON via `glab issue view --output json` (every field) or
|
|
71
|
+
* `gh issue view --json <ghFields>` (only the named fields).
|
|
65
72
|
*
|
|
66
|
-
* @param {{ issueId:
|
|
73
|
+
* @param {{ issueId: string, vcs: 'gitlab' | 'github', spec?: string,
|
|
74
|
+
* ghFields: string, execFile?: typeof execFileSync }} opts
|
|
67
75
|
* `spec` is the resolved `-R`/`--repo` host-pinning value (#839); omitted
|
|
68
76
|
* (undefined) means no `-R` is appended — never emit `-R undefined`.
|
|
69
|
-
* @returns {{ ok: boolean,
|
|
77
|
+
* @returns {{ ok: boolean, data: any, stderr: string }}
|
|
70
78
|
*/
|
|
71
|
-
function
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
const args = ['issue', 'view', id, '--json', 'labels'];
|
|
77
|
-
if (spec) args.push('-R', spec);
|
|
78
|
-
const res = runCli('gh', args);
|
|
79
|
-
if (!res.ok) return { ok: false, labels: [], stderr: res.stderr };
|
|
80
|
-
let parsed;
|
|
81
|
-
try {
|
|
82
|
-
parsed = JSON.parse(res.stdout);
|
|
83
|
-
} catch (e) {
|
|
84
|
-
return { ok: false, labels: [], stderr: `JSON parse failed: ${e && e.message ? e.message : String(e)}` };
|
|
85
|
-
}
|
|
86
|
-
const labels = Array.isArray(parsed?.labels)
|
|
87
|
-
? parsed.labels.map((l) => (typeof l?.name === 'string' ? l.name : String(l))).filter(Boolean)
|
|
88
|
-
: [];
|
|
89
|
-
return { ok: true, labels, stderr: '' };
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Default: gitlab via glab.
|
|
93
|
-
// `glab issue view <IID> --output json` returns an issue object with a `labels` array.
|
|
94
|
-
const args = ['issue', 'view', id, '--output', 'json'];
|
|
79
|
+
function viewIssueJson({ issueId, vcs, spec, ghFields, execFile }) {
|
|
80
|
+
const args =
|
|
81
|
+
vcs === 'github'
|
|
82
|
+
? ['issue', 'view', issueId, '--json', ghFields]
|
|
83
|
+
: ['issue', 'view', issueId, '--output', 'json'];
|
|
95
84
|
if (spec) args.push('-R', spec);
|
|
96
|
-
const res = runCli('glab', args);
|
|
97
|
-
if (!res.ok) return { ok: false,
|
|
98
|
-
let parsed;
|
|
85
|
+
const res = runCli(vcs === 'github' ? 'gh' : 'glab', args, execFile);
|
|
86
|
+
if (!res.ok) return { ok: false, data: null, stderr: res.stderr };
|
|
99
87
|
try {
|
|
100
|
-
|
|
88
|
+
return { ok: true, data: JSON.parse(res.stdout), stderr: '' };
|
|
101
89
|
} catch (e) {
|
|
102
|
-
return {
|
|
90
|
+
return {
|
|
91
|
+
ok: false,
|
|
92
|
+
data: null,
|
|
93
|
+
stderr: `JSON parse failed: ${e && e.message ? e.message : String(e)}`,
|
|
94
|
+
};
|
|
103
95
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Fetch the label names currently applied to an issue.
|
|
100
|
+
*
|
|
101
|
+
* GitHub shape: `{ labels: [{ name }] }`; GitLab shape: `{ labels: ["status:ready", ...] }`.
|
|
102
|
+
*
|
|
103
|
+
* @param {{ issueId: string, vcs: 'gitlab' | 'github', spec?: string, execFile?: typeof execFileSync }} opts
|
|
104
|
+
* @returns {{ ok: boolean, labels: string[], stderr: string }}
|
|
105
|
+
*/
|
|
106
|
+
function fetchLabels({ issueId, vcs, spec, execFile }) {
|
|
107
|
+
const { ok, data, stderr } = viewIssueJson({ issueId, vcs, spec, ghFields: 'labels', execFile });
|
|
108
|
+
if (!ok) return { ok: false, labels: [], stderr };
|
|
109
|
+
const toName =
|
|
110
|
+
vcs === 'github'
|
|
111
|
+
? (l) => (typeof l?.name === 'string' ? l.name : String(l))
|
|
112
|
+
: (l) => (typeof l === 'string' ? l : String(l));
|
|
113
|
+
const labels = Array.isArray(data?.labels) ? data.labels.map(toName).filter(Boolean) : [];
|
|
108
114
|
return { ok: true, labels, stderr: '' };
|
|
109
115
|
}
|
|
110
116
|
|
|
@@ -119,12 +125,14 @@ function fetchLabels({ issueId, vcs, spec }) {
|
|
|
119
125
|
* issueId: number | string,
|
|
120
126
|
* vcs?: 'gitlab' | 'github',
|
|
121
127
|
* repoRoot?: string,
|
|
122
|
-
* resolveRepoSpecFn?: (opts: { repoRoot: string, vcs: 'gitlab' | 'github' }) => string | undefined
|
|
128
|
+
* resolveRepoSpecFn?: (opts: { repoRoot: string, vcs: 'gitlab' | 'github' }) => string | undefined,
|
|
129
|
+
* execFile?: typeof execFileSync
|
|
123
130
|
* }} opts
|
|
124
131
|
* `repoRoot` defaults to `process.cwd()`. `resolveRepoSpecFn` is the
|
|
125
132
|
* injectable seam for the `-R`/`--repo` host-pinning resolution (#839) —
|
|
126
133
|
* defaults to the real `resolveRepoSpec` (shells out to `git remote
|
|
127
|
-
* get-url`); tests inject a stub instead of shelling out.
|
|
134
|
+
* get-url`); tests inject a stub instead of shelling out. `execFile`
|
|
135
|
+
* (default `execFileSync`) runs every glab/gh call.
|
|
128
136
|
* @returns {Promise<{ stripped: string[], error?: string }>}
|
|
129
137
|
*/
|
|
130
138
|
export async function stripStatusLabels({
|
|
@@ -132,6 +140,7 @@ export async function stripStatusLabels({
|
|
|
132
140
|
vcs = 'gitlab',
|
|
133
141
|
repoRoot = process.cwd(),
|
|
134
142
|
resolveRepoSpecFn = resolveRepoSpec,
|
|
143
|
+
execFile = execFileSync,
|
|
135
144
|
} = {}) {
|
|
136
145
|
try {
|
|
137
146
|
const id = String(issueId ?? '').trim();
|
|
@@ -146,7 +155,7 @@ export async function stripStatusLabels({
|
|
|
146
155
|
const spec = resolveRepoSpecFn({ repoRoot, vcs: vcsResolved });
|
|
147
156
|
|
|
148
157
|
// Step 1: fetch current labels.
|
|
149
|
-
const { ok, labels, stderr } = fetchLabels({ issueId: id, vcs: vcsResolved, spec });
|
|
158
|
+
const { ok, labels, stderr } = fetchLabels({ issueId: id, vcs: vcsResolved, spec, execFile });
|
|
150
159
|
if (!ok) {
|
|
151
160
|
return { stripped: [], error: `failed to fetch labels: ${stderr}` };
|
|
152
161
|
}
|
|
@@ -167,13 +176,13 @@ export async function stripStatusLabels({
|
|
|
167
176
|
args.push('--remove-label', label);
|
|
168
177
|
}
|
|
169
178
|
if (spec) args.push('-R', spec);
|
|
170
|
-
stripRes = runCli('gh', args);
|
|
179
|
+
stripRes = runCli('gh', args, execFile);
|
|
171
180
|
} else {
|
|
172
181
|
// `glab issue update <IID> --unlabel label1,label2,...`
|
|
173
182
|
// glab accepts comma-separated list in a single --unlabel flag value.
|
|
174
183
|
const args = ['issue', 'update', id, '--unlabel', toStrip.join(',')];
|
|
175
184
|
if (spec) args.push('-R', spec);
|
|
176
|
-
stripRes = runCli('glab', args);
|
|
185
|
+
stripRes = runCli('glab', args, execFile);
|
|
177
186
|
}
|
|
178
187
|
|
|
179
188
|
if (!stripRes.ok) {
|
|
@@ -189,3 +198,152 @@ export async function stripStatusLabels({
|
|
|
189
198
|
return { stripped: [], error: msg };
|
|
190
199
|
}
|
|
191
200
|
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Strip `status:*` labels, close, and VERIFY the close for each issue id — in
|
|
204
|
+
* that order, one id at a time.
|
|
205
|
+
*
|
|
206
|
+
* `closed` is true only when a re-read of the issue AFTER the close says
|
|
207
|
+
* `state: closed` (GitLab `closed`, GitHub `CLOSED`). The close command's own
|
|
208
|
+
* exit status is not trusted: a wrong project or a silent 404 can exit 0 while
|
|
209
|
+
* closing nothing (gitlab-ops skill, "Close verification"). The re-read runs
|
|
210
|
+
* even when the close command failed, so an issue that was already closed
|
|
211
|
+
* reports `closed: true` alongside the close `error`.
|
|
212
|
+
*
|
|
213
|
+
* A strip failure is non-fatal: it is reported as `stripError` and the close
|
|
214
|
+
* still runs. An id that is not a positive integer (an optional leading `#` is
|
|
215
|
+
* accepted) gets no CLI call at all — a value starting with `-` would
|
|
216
|
+
* otherwise reach glab/gh as a flag.
|
|
217
|
+
*
|
|
218
|
+
* @param {{
|
|
219
|
+
* ids: Array<number | string>,
|
|
220
|
+
* vcs?: 'gitlab' | 'github',
|
|
221
|
+
* repo?: string,
|
|
222
|
+
* repoRoot?: string,
|
|
223
|
+
* resolveRepoSpecFn?: (opts: { repoRoot: string, vcs: 'gitlab' | 'github' }) => string | undefined,
|
|
224
|
+
* execFile?: typeof execFileSync
|
|
225
|
+
* }} opts
|
|
226
|
+
* `repo` overrides the `-R`/`--repo` spec; otherwise it is resolved once via
|
|
227
|
+
* `resolveRepoSpecFn` exactly as `stripStatusLabels` does (#839).
|
|
228
|
+
* @returns {Promise<Array<{ id: string, stripped: string[], stripError?: string,
|
|
229
|
+
* closed: boolean, state: string | null, error?: string }>>}
|
|
230
|
+
*/
|
|
231
|
+
export async function closeIssues({
|
|
232
|
+
ids = [],
|
|
233
|
+
vcs = 'gitlab',
|
|
234
|
+
repo,
|
|
235
|
+
repoRoot = process.cwd(),
|
|
236
|
+
resolveRepoSpecFn = resolveRepoSpec,
|
|
237
|
+
execFile = execFileSync,
|
|
238
|
+
} = {}) {
|
|
239
|
+
const vcsResolved = vcs === 'github' ? 'github' : 'gitlab';
|
|
240
|
+
const spec = repo?.trim() || resolveRepoSpecFn({ repoRoot, vcs: vcsResolved });
|
|
241
|
+
const cli = vcsResolved === 'github' ? 'gh' : 'glab';
|
|
242
|
+
const results = [];
|
|
243
|
+
|
|
244
|
+
for (const rawId of ids) {
|
|
245
|
+
const id = String(rawId ?? '')
|
|
246
|
+
.trim()
|
|
247
|
+
.replace(/^#/, '');
|
|
248
|
+
if (!/^[1-9]\d*$/.test(id)) {
|
|
249
|
+
results.push({
|
|
250
|
+
id: String(rawId),
|
|
251
|
+
stripped: [],
|
|
252
|
+
closed: false,
|
|
253
|
+
state: null,
|
|
254
|
+
error: 'invalid issue id',
|
|
255
|
+
});
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
const result = { id, stripped: [], closed: false, state: null };
|
|
259
|
+
|
|
260
|
+
// 1. strip — non-fatal. The resolved spec is handed through so strip,
|
|
261
|
+
// close and verify all pin the same repo.
|
|
262
|
+
const strip = await stripStatusLabels({
|
|
263
|
+
issueId: id,
|
|
264
|
+
vcs: vcsResolved,
|
|
265
|
+
resolveRepoSpecFn: () => spec,
|
|
266
|
+
execFile,
|
|
267
|
+
});
|
|
268
|
+
result.stripped = strip.stripped;
|
|
269
|
+
if (strip.error) result.stripError = strip.error;
|
|
270
|
+
|
|
271
|
+
// 2. close
|
|
272
|
+
const closeArgs = ['issue', 'close', id];
|
|
273
|
+
if (spec) closeArgs.push('-R', spec);
|
|
274
|
+
const closeRes = runCli(cli, closeArgs, execFile);
|
|
275
|
+
const errors = closeRes.ok
|
|
276
|
+
? []
|
|
277
|
+
: [`close failed: ${closeRes.stderr.trim() || 'unknown error'}`];
|
|
278
|
+
|
|
279
|
+
// 3. verify — the platform's state is the only evidence of a close.
|
|
280
|
+
const view = viewIssueJson({
|
|
281
|
+
issueId: id,
|
|
282
|
+
vcs: vcsResolved,
|
|
283
|
+
spec,
|
|
284
|
+
ghFields: 'state',
|
|
285
|
+
execFile,
|
|
286
|
+
});
|
|
287
|
+
if (view.ok) {
|
|
288
|
+
result.state = typeof view.data?.state === 'string' ? view.data.state : null;
|
|
289
|
+
result.closed = result.state?.toLowerCase() === 'closed';
|
|
290
|
+
if (!result.closed) {
|
|
291
|
+
errors.push(`verify: issue state is ${result.state ?? 'unknown'}, not closed`);
|
|
292
|
+
}
|
|
293
|
+
} else {
|
|
294
|
+
errors.push(`verify failed: ${view.stderr.trim() || 'unknown error'}`);
|
|
295
|
+
}
|
|
296
|
+
if (errors.length) result.error = errors.join('; ');
|
|
297
|
+
results.push(result);
|
|
298
|
+
}
|
|
299
|
+
return results;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const USAGE =
|
|
303
|
+
'usage: issue-close-strip-labels.mjs --close [--vcs gitlab|github] [-R|--repo <spec>] <id>...';
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* CLI: `--close [--vcs gitlab|github] [-R <spec>] <id>...` — one JSON line per
|
|
307
|
+
* id on stdout. Exit 0 = every id verified closed, 1 = at least one did not,
|
|
308
|
+
* 2 = usage error (no GitLab/GitHub call made).
|
|
309
|
+
*
|
|
310
|
+
* @param {string[]} [argv]
|
|
311
|
+
* @returns {Promise<number>} exit code
|
|
312
|
+
*/
|
|
313
|
+
async function main(argv = process.argv.slice(2)) {
|
|
314
|
+
let parsed;
|
|
315
|
+
try {
|
|
316
|
+
parsed = parseArgs({
|
|
317
|
+
args: argv,
|
|
318
|
+
allowPositionals: true,
|
|
319
|
+
options: {
|
|
320
|
+
close: { type: 'boolean', default: false },
|
|
321
|
+
vcs: { type: 'string', default: 'gitlab' },
|
|
322
|
+
repo: { type: 'string', short: 'R' },
|
|
323
|
+
},
|
|
324
|
+
});
|
|
325
|
+
} catch (err) {
|
|
326
|
+
process.stderr.write(`${err?.message ?? err}\n${USAGE}\n`);
|
|
327
|
+
return 2;
|
|
328
|
+
}
|
|
329
|
+
const { values, positionals } = parsed;
|
|
330
|
+
if (!values.close || positionals.length === 0 || !['gitlab', 'github'].includes(values.vcs)) {
|
|
331
|
+
process.stderr.write(`${USAGE}\n`);
|
|
332
|
+
return 2;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
const results = await closeIssues({ ids: positionals, vcs: values.vcs, repo: values.repo });
|
|
336
|
+
for (const r of results) {
|
|
337
|
+
if (r.stripError) {
|
|
338
|
+
process.stderr.write(
|
|
339
|
+
`⚠ label strip failed for #${r.id}: ${r.stripError} — close attempted anyway\n`,
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
process.stdout.write(`${JSON.stringify(r)}\n`);
|
|
343
|
+
}
|
|
344
|
+
return results.every((r) => r.closed) ? 0 : 1;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
if (isMainModule(import.meta.url)) {
|
|
348
|
+
process.exitCode = await main();
|
|
349
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
// js-mask.mjs — ONE JavaScript lexer for every "blank the comments / separate
|
|
2
|
+
// code from data" scanner in this repo.
|
|
3
|
+
//
|
|
4
|
+
// WHY IT LIVES HERE. `maskSource` grew inside
|
|
5
|
+
// `scripts/lib/validate/check-untracked-test-deps.mjs`, where it is used to
|
|
6
|
+
// separate CODE from DATA. Three OTHER modules had hand-rolled
|
|
7
|
+
// `stripComments` copies with NO regex-literal branch, and each one was
|
|
8
|
+
// measurably wrong for the same input shape (`/\/*$/` — a regex whose body
|
|
9
|
+
// contains `/*`), measured 2026-09-18 @ 20a4cbff:
|
|
10
|
+
// - `check-validator-registration.mjs` — the regex's `/*` opened a block
|
|
11
|
+
// comment that swallowed the rest of the surface text → a FALSE
|
|
12
|
+
// "UNREGISTERED" finding.
|
|
13
|
+
// - `check-test-git-config-target.mjs` — same swallow inside a call tail →
|
|
14
|
+
// `wrapperHasCwd` returned false → a false alarm.
|
|
15
|
+
// - `auq/parse.mjs` — the swallowed region no longer contained
|
|
16
|
+
// `(Recommended)` → a silent FALSE NEGATIVE in the AUQ clarity measurement.
|
|
17
|
+
// One lexer, five consumers: the regex branch and its three named ceilings are
|
|
18
|
+
// maintained once.
|
|
19
|
+
//
|
|
20
|
+
// Import-safety: importing this module executes nothing.
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Keywords after which a `/` opens a REGEX LITERAL, never a division. The
|
|
24
|
+
* single-character `prev` below cannot tell `return /x/` from `n / x`, because
|
|
25
|
+
* the character it sees (`n`) is a word character in both. This set is the
|
|
26
|
+
* one-token lookback that closes the difference; it is deliberately the usual
|
|
27
|
+
* short list rather than a parser (BV-001.6/BV-004 — a full expression parser
|
|
28
|
+
* for a masker is the abstraction this file exists to avoid).
|
|
29
|
+
*
|
|
30
|
+
* Named ceiling (BV-004), in the other direction: a genuine DIVISION CHAIN after
|
|
31
|
+
* one of these words (`return a / b / c`) is now read as a regex and its middle
|
|
32
|
+
* blanked. Measured 2026-09-18 over `git ls-files '*.mjs'` (1245 files): 0
|
|
33
|
+
* occurrences — all 18 files whose masking this lookback changes carry a real
|
|
34
|
+
* `return /…/` literal. REVISIT TRIGGER: the first such division chain.
|
|
35
|
+
*/
|
|
36
|
+
const REGEX_PRECEDING_KEYWORDS = new Set([
|
|
37
|
+
'return', 'typeof', 'case', 'in', 'of', 'new', 'delete', 'void', 'yield',
|
|
38
|
+
'await', 'instanceof', 'do', 'else',
|
|
39
|
+
]);
|
|
40
|
+
|
|
41
|
+
/** Word characters, for the one-token lookback above. */
|
|
42
|
+
const WORD_CHAR_RE = /[A-Za-z0-9_$]/;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Blank out the INTERIOR of every string literal, template literal, comment and
|
|
46
|
+
* regex literal, preserving byte offsets and newlines. Delimiters are kept so
|
|
47
|
+
* paren/comma balance and identifier boundaries survive.
|
|
48
|
+
*
|
|
49
|
+
* This is what separates CODE from DATA. A test that embeds fixture source in a
|
|
50
|
+
* template literal (`check-untracked-test-deps.mjs`'s own test file does) must
|
|
51
|
+
* not be scanned as though that fixture were its own body — masking makes that
|
|
52
|
+
* structural instead of relying on a self-exemption marker.
|
|
53
|
+
*
|
|
54
|
+
* With `keepLiterals: true` only COMMENTS are blanked: string, template and
|
|
55
|
+
* regex literals are still recognised (so a `//` or `/*` inside one is never read
|
|
56
|
+
* as a comment, and a quote inside a regex never opens a string) but their
|
|
57
|
+
* contents stay intact. `check-entry-guard.mjs` needs exactly that — it must see
|
|
58
|
+
* `endsWith('x.mjs')` and `${process.argv[1]}` verbatim (#1383) — and it is the
|
|
59
|
+
* mode the three `stripComments` consumers delegate in (#1388).
|
|
60
|
+
*
|
|
61
|
+
* @param {string} text
|
|
62
|
+
* @param {{ keepLiterals?: boolean }} [options]
|
|
63
|
+
* @returns {string} same-length masked source
|
|
64
|
+
*/
|
|
65
|
+
export function maskSource(text, { keepLiterals = false } = {}) {
|
|
66
|
+
const out = text.split('');
|
|
67
|
+
const n = out.length;
|
|
68
|
+
let i = 0;
|
|
69
|
+
// Last significant (non-space) char before `i`, and its offset, used for the
|
|
70
|
+
// regex/division disambiguation below (the offset carries the one-token
|
|
71
|
+
// keyword lookback).
|
|
72
|
+
let prev = '';
|
|
73
|
+
let prevIdx = -1;
|
|
74
|
+
|
|
75
|
+
/** The whole word ending at `idx`, or '' when `idx` is not a word char. */
|
|
76
|
+
const wordEndingAt = (idx) => {
|
|
77
|
+
if (idx < 0 || !WORD_CHAR_RE.test(text[idx])) return '';
|
|
78
|
+
let k = idx;
|
|
79
|
+
while (k > 0 && WORD_CHAR_RE.test(text[k - 1])) k--;
|
|
80
|
+
return text.slice(k, idx + 1);
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const blank = (from, to) => {
|
|
84
|
+
for (let k = from; k < to && k < n; k++) if (out[k] !== '\n') out[k] = ' ';
|
|
85
|
+
};
|
|
86
|
+
// Literal interiors go through this one; comments always use `blank`.
|
|
87
|
+
const blankLiteral = keepLiterals ? () => {} : blank;
|
|
88
|
+
|
|
89
|
+
while (i < n) {
|
|
90
|
+
const c = text[i];
|
|
91
|
+
const next = text[i + 1];
|
|
92
|
+
|
|
93
|
+
// Line comment.
|
|
94
|
+
if (c === '/' && next === '/') {
|
|
95
|
+
let j = i;
|
|
96
|
+
while (j < n && text[j] !== '\n') j++;
|
|
97
|
+
blank(i, j);
|
|
98
|
+
i = j;
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
// Block comment — ONLY when it is actually closed.
|
|
102
|
+
//
|
|
103
|
+
// Named ceiling (BV-004), replacing an unbounded blank: an UNTERMINATED
|
|
104
|
+
// `/*` used to blank everything to EOF. In valid source that shape is a
|
|
105
|
+
// syntax error, so in practice it only ever arises from a lexer desync —
|
|
106
|
+
// a `/*` inside a regex literal the branch below failed to recognise
|
|
107
|
+
// (`return /\/*$/`). Blanking the rest of the file then hides every guard
|
|
108
|
+
// under it, which is a validator falling SILENT. The direction is therefore
|
|
109
|
+
// chosen fail-toward-REPORTING: an unclosed `/*` is not a comment at all,
|
|
110
|
+
// and the few bytes of a genuine one get scanned as code — at worst that
|
|
111
|
+
// produces a finding a human dismisses, never a silent pass.
|
|
112
|
+
// REVISIT TRIGGER: a tracked file that legitimately ends inside an
|
|
113
|
+
// unterminated block comment (i.e. the moment `node --check` accepts one).
|
|
114
|
+
if (c === '/' && next === '*') {
|
|
115
|
+
let j = i + 2;
|
|
116
|
+
while (j < n && !(text[j] === '*' && text[j + 1] === '/')) j++;
|
|
117
|
+
if (j < n) {
|
|
118
|
+
blank(i, j + 2);
|
|
119
|
+
i = j + 2;
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
// Unterminated — fall through and treat the `/` as ordinary source.
|
|
123
|
+
}
|
|
124
|
+
// Single/double-quoted string — keep the quotes, blank the interior.
|
|
125
|
+
if (c === "'" || c === '"') {
|
|
126
|
+
let j = i + 1;
|
|
127
|
+
while (j < n && text[j] !== c) {
|
|
128
|
+
if (text[j] === '\\') j++;
|
|
129
|
+
if (text[j] === '\n') break; // unterminated — bail at EOL
|
|
130
|
+
j++;
|
|
131
|
+
}
|
|
132
|
+
blankLiteral(i + 1, j);
|
|
133
|
+
i = Math.min(j + 1, n);
|
|
134
|
+
prev = c;
|
|
135
|
+
prevIdx = i - 1;
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
// Template literal — blank everything including `${…}` substitutions.
|
|
139
|
+
if (c === '`') {
|
|
140
|
+
let j = i + 1;
|
|
141
|
+
while (j < n && text[j] !== '`') {
|
|
142
|
+
if (text[j] === '\\') j++;
|
|
143
|
+
j++;
|
|
144
|
+
}
|
|
145
|
+
blankLiteral(i + 1, j);
|
|
146
|
+
i = Math.min(j + 1, n);
|
|
147
|
+
prev = c;
|
|
148
|
+
prevIdx = i - 1;
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
// Regex literal — only when the previous significant TOKEN cannot end an
|
|
152
|
+
// expression, AND a closing unescaped `/` exists on the SAME line. The
|
|
153
|
+
// same-line bound keeps a misread division from swallowing the file.
|
|
154
|
+
//
|
|
155
|
+
// The token is either the single char `prev`, or — when that char is a word
|
|
156
|
+
// character — the whole word ending at it, checked against
|
|
157
|
+
// REGEX_PRECEDING_KEYWORDS. Without that lookback `return /\/*$/` read as a
|
|
158
|
+
// division and its `/*` reached the block-comment branch above, which blanked
|
|
159
|
+
// the rest of the file: a validator silently passing (measured 2026-09-18).
|
|
160
|
+
//
|
|
161
|
+
// Named ceiling (BV-004): the lookback is exactly ONE token. A regex after
|
|
162
|
+
// any other non-expression-ending context — a `)` that closes `if (…)`, a
|
|
163
|
+
// statement label, `function` — is still read as division and its body
|
|
164
|
+
// scanned as code. That desync is now bounded on BOTH sides: a quote in it
|
|
165
|
+
// opens a string that bails at EOL, and a `/*` in it no longer blanks past
|
|
166
|
+
// the file (unterminated block comments are not comments — see above).
|
|
167
|
+
// REVISIT TRIGGER: a census finding that needs `)`-aware lookback, i.e. a
|
|
168
|
+
// regex used directly as the body of `if (…) /re/.test(x)`.
|
|
169
|
+
const startsRegex = c === '/' && (
|
|
170
|
+
prev === '' || '(,=:[!&|?{};+-*%~^<>'.includes(prev)
|
|
171
|
+
|| REGEX_PRECEDING_KEYWORDS.has(wordEndingAt(prevIdx))
|
|
172
|
+
);
|
|
173
|
+
if (startsRegex) {
|
|
174
|
+
let j = i + 1;
|
|
175
|
+
let inClass = false;
|
|
176
|
+
let closed = -1;
|
|
177
|
+
while (j < n && text[j] !== '\n') {
|
|
178
|
+
if (text[j] === '\\') { j += 2; continue; }
|
|
179
|
+
if (text[j] === '[') inClass = true;
|
|
180
|
+
else if (text[j] === ']') inClass = false;
|
|
181
|
+
else if (text[j] === '/' && !inClass) { closed = j; break; }
|
|
182
|
+
j++;
|
|
183
|
+
}
|
|
184
|
+
if (closed > i) {
|
|
185
|
+
blankLiteral(i + 1, closed);
|
|
186
|
+
i = closed + 1;
|
|
187
|
+
prev = '/';
|
|
188
|
+
prevIdx = closed;
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (!/\s/.test(c)) { prev = c; prevIdx = i; }
|
|
194
|
+
i++;
|
|
195
|
+
}
|
|
196
|
+
return out.join('');
|
|
197
|
+
}
|
|
@@ -11,13 +11,17 @@
|
|
|
11
11
|
* a CODE call site instead: `emitEvolveCompleted()` is invoked from
|
|
12
12
|
* `scripts/sweep-expired-learnings.mjs`'s `--prune` exit path (the ONE store
|
|
13
13
|
* write `/evolve analyze` already performs), and `recordDialecticRun()` is
|
|
14
|
-
* invoked from `scripts/dialectic-deriver.mjs::runDialecticDeriver()` for
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* throw-based abort classes (`unknown-model`,
|
|
18
|
-
* `
|
|
19
|
-
*
|
|
20
|
-
*
|
|
14
|
+
* invoked from `scripts/dialectic-deriver.mjs::runDialecticDeriver()` for
|
|
15
|
+
* every outcome that pipeline can determine on its own: the `ok`/abort
|
|
16
|
+
* returns (`empty-input`, `budget-exceeded`, `would-empty-card`, dry-run
|
|
17
|
+
* success) AND the two throw-based abort classes (`unknown-model`,
|
|
18
|
+
* `subagent-crash`), the latter via that module's `recordThrownAbort()`
|
|
19
|
+
* helper which records at the throw point before the original error is
|
|
20
|
+
* rethrown. Only APPLY-mode success still calls `recordDialecticRun()` from
|
|
21
|
+
* `skills/evolve/SKILL.md` prose (Step 6.4 of
|
|
22
|
+
* `skills/evolve/references/evolve-dialectic-mode.md`) — the merge
|
|
23
|
+
* (`mergePeerCard()`) happens one layer up, outside this pure pipeline, so the
|
|
24
|
+
* real merge-stats deltas are not knowable inside `runDialecticDeriver()`.
|
|
21
25
|
*
|
|
22
26
|
* Both emitters are best-effort and try/catch-wrapped — same posture as
|
|
23
27
|
* `emitReconcileCompleted` in `scripts/lib/reconcile/engine.mjs` — because
|
|
@@ -1,31 +1,38 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* locks/index.mjs — convenience barrel for the
|
|
3
|
-
* out of session-lock.mjs in #630 (A1 barrel-preserving split).
|
|
2
|
+
* locks/index.mjs — DEPRECATED convenience barrel for the lock protocols
|
|
3
|
+
* split out of session-lock.mjs in #630 (A1 barrel-preserving split).
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* the original
|
|
9
|
-
* importable directly.
|
|
5
|
+
* @deprecated since 5.2.0, removed in 6.0.0. Import directly from
|
|
6
|
+
* `./state-md-lock.mjs` / `./staging-fence-lock.mjs`, or from
|
|
7
|
+
* `scripts/lib/session-lock.mjs` for the canonical 22-symbol barrel that
|
|
8
|
+
* preserves the original import surface for all its importers.
|
|
10
9
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* This file shipped in 5.1.0 with zero in-repo importers and was deleted in
|
|
11
|
+
* dd05e0f8 (`check-unwired-features` S4: no hook, npm script, CI job or husky
|
|
12
|
+
* stage reached it, and it named symbols — not modules — so it did not qualify
|
|
13
|
+
* for the pure `export *` exemption that shape gets). Restored here as a
|
|
14
|
+
* one-cycle deprecation shim (`.claude/rules/development.md` § Package Lifecycle
|
|
15
|
+
* & Versioning) because `package.json` carries no `exports` map: every packed
|
|
16
|
+
* file under `scripts/lib/` is public, so a consumer that deep-imported this
|
|
17
|
+
* path before the deletion has no compile error to warn it, only a runtime
|
|
18
|
+
* "module not found" — a shim buys that consumer one minor cycle to migrate
|
|
19
|
+
* before 6.0.0 removes the path outright.
|
|
20
|
+
*
|
|
21
|
+
* Deliberately the `export *` form with ZERO named exports (matches the
|
|
22
|
+
* `scripts/lib/autopilot-telemetry.mjs` precedent): a named-export re-export
|
|
23
|
+
* barrel is exactly the shape `check-unwired-features.mjs` S4 flags as an
|
|
24
|
+
* unreachable library module (condition 4 in `collectUnreachableLibraryModules`
|
|
25
|
+
* requires named exports before a re-export shim over live code enters that
|
|
26
|
+
* census) — that flag is what got this file deleted the first time. A star
|
|
27
|
+
* re-export names no symbol, so the shim reads as `exports: []` and stays
|
|
28
|
+
* invisible to that census while its target modules stay reachable through it.
|
|
13
29
|
*/
|
|
14
30
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
releaseStateLock,
|
|
21
|
-
withStateMdLock,
|
|
22
|
-
} from './state-md-lock.mjs';
|
|
31
|
+
console.warn(
|
|
32
|
+
'[deprecated] scripts/lib/locks/index.mjs is deprecated since 5.2.0 and will be removed in 6.0.0 — ' +
|
|
33
|
+
"import from './state-md-lock.mjs' / './staging-fence-lock.mjs' directly, or from " +
|
|
34
|
+
'scripts/lib/session-lock.mjs for the canonical surface.',
|
|
35
|
+
);
|
|
23
36
|
|
|
24
|
-
export
|
|
25
|
-
|
|
26
|
-
DEFAULT_STAGING_FENCE_LOCK_TIMEOUT_MS,
|
|
27
|
-
STAGING_FENCE_LOCK_POLL_MS,
|
|
28
|
-
acquireStagingFenceLock,
|
|
29
|
-
releaseStagingFenceLock,
|
|
30
|
-
withStagingFenceLock,
|
|
31
|
-
} from './staging-fence-lock.mjs';
|
|
37
|
+
export * from './state-md-lock.mjs';
|
|
38
|
+
export * from './staging-fence-lock.mjs';
|