session-orchestrator 3.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +29 -0
- package/.claude-plugin/plugin.json +18 -0
- package/.codex-plugin/agents/explorer.toml +14 -0
- package/.codex-plugin/agents/session-reviewer.toml +23 -0
- package/.codex-plugin/agents/wave-worker.toml +15 -0
- package/.codex-plugin/config.toml +20 -0
- package/.codex-plugin/plugin.json +37 -0
- package/.cursor/rules/000-session-orchestrator.mdc +73 -0
- package/.cursor/rules/010-session-workflow.mdc +170 -0
- package/.cursor/rules/020-quality-gates.mdc +128 -0
- package/.cursor/rules/030-wave-execution.mdc +216 -0
- package/.cursor/rules/040-discovery.mdc +242 -0
- package/.cursor/rules/050-plan.mdc +235 -0
- package/.cursor/rules/060-evolve.mdc +232 -0
- package/.cursor/rules/070-gitlab-ops.mdc +246 -0
- package/.cursor/rules/080-ecosystem-health.mdc +145 -0
- package/.mcp.json +8 -0
- package/CHANGELOG.md +1544 -0
- package/LICENSE +21 -0
- package/NOTICE +64 -0
- package/README.md +242 -0
- package/SECURITY.md +90 -0
- package/agents/AGENTS.md +136 -0
- package/agents/analyst.md +99 -0
- package/agents/architect-reviewer.md +93 -0
- package/agents/code-implementer.md +106 -0
- package/agents/db-specialist.md +104 -0
- package/agents/dialectic-deriver.md +139 -0
- package/agents/docs-writer.md +113 -0
- package/agents/eval-judge.md +146 -0
- package/agents/memory-proposal-collector.md +297 -0
- package/agents/qa-strategist.md +102 -0
- package/agents/schemas/analyst.schema.json +46 -0
- package/agents/schemas/architect-reviewer.schema.json +50 -0
- package/agents/schemas/code-implementer.schema.json +61 -0
- package/agents/schemas/db-specialist.schema.json +80 -0
- package/agents/schemas/docs-writer.schema.json +56 -0
- package/agents/schemas/persona-panel-sidecar.schema.json +245 -0
- package/agents/schemas/qa-strategist.schema.json +46 -0
- package/agents/schemas/security-reviewer.schema.json +86 -0
- package/agents/schemas/session-reviewer.schema.json +69 -0
- package/agents/schemas/test-writer.schema.json +69 -0
- package/agents/schemas/ui-developer.schema.json +90 -0
- package/agents/schemas/ux-evaluator.schema.json +51 -0
- package/agents/security-reviewer.md +236 -0
- package/agents/session-reviewer.md +201 -0
- package/agents/skill-applied-judge.md +122 -0
- package/agents/test-writer.md +123 -0
- package/agents/ui-developer.md +109 -0
- package/agents/ux-evaluator.md +161 -0
- package/assets/icon.svg +11 -0
- package/assets/og-card.png +0 -0
- package/assets/og-card.svg +47 -0
- package/commands/autopilot-multi.md +74 -0
- package/commands/autopilot.md +80 -0
- package/commands/bootstrap.md +56 -0
- package/commands/brainstorm.md +48 -0
- package/commands/close.md +24 -0
- package/commands/debug.md +36 -0
- package/commands/discovery.md +32 -0
- package/commands/dispatcher.md +59 -0
- package/commands/eval.md +28 -0
- package/commands/evolve.md +10 -0
- package/commands/go.md +41 -0
- package/commands/grill.md +45 -0
- package/commands/harness-audit.md +26 -0
- package/commands/memory-cleanup.md +25 -0
- package/commands/persona-panel.md +121 -0
- package/commands/plan.md +15 -0
- package/commands/portfolio.md +97 -0
- package/commands/reconcile.md +23 -0
- package/commands/repo-audit.md +24 -0
- package/commands/session.md +30 -0
- package/commands/spinout.md +15 -0
- package/commands/sunset-review.md +27 -0
- package/commands/templates-ack.md +96 -0
- package/commands/test.md +97 -0
- package/docs/README.md +105 -0
- package/docs/USER-GUIDE.md +1403 -0
- package/docs/ci-setup.md +81 -0
- package/docs/codex-setup.md +142 -0
- package/docs/components.md +74 -0
- package/docs/cursor-setup.md +104 -0
- package/docs/events-schema.md +81 -0
- package/docs/migration-v3.md +148 -0
- package/docs/owner-config-schema.md +154 -0
- package/docs/persona-panel.md +433 -0
- package/docs/pi-setup.md +115 -0
- package/docs/plugin-architecture-v3.md +296 -0
- package/docs/pm-skills-marketplace.md +114 -0
- package/docs/policy-cache-validation-2026-04-28.md +118 -0
- package/docs/rule-authoring.md +316 -0
- package/docs/session-config-reference.md +1439 -0
- package/docs/session-config-template.md +961 -0
- package/docs/vault-docs-architecture.md +297 -0
- package/hooks/_lib/lock-bootstrap.mjs +272 -0
- package/hooks/_lib/lock-reconcile.mjs +93 -0
- package/hooks/_lib/profile-gate.mjs +95 -0
- package/hooks/_lib/transcript-history.mjs +211 -0
- package/hooks/agent-teams-h3-test.sh +362 -0
- package/hooks/config-protection.mjs +0 -0
- package/hooks/cwd-change-restore.mjs +131 -0
- package/hooks/enforce-commands.mjs +179 -0
- package/hooks/enforce-scope.mjs +273 -0
- package/hooks/hooks-codex.json +60 -0
- package/hooks/hooks-cursor.json +15 -0
- package/hooks/hooks-pi.json +115 -0
- package/hooks/hooks.json +215 -0
- package/hooks/loop-guard.mjs +260 -0
- package/hooks/on-session-end.mjs +217 -0
- package/hooks/on-session-start.mjs +660 -0
- package/hooks/on-stop.mjs +294 -0
- package/hooks/operator-steer.mjs +64 -0
- package/hooks/post-edit-validate.mjs +225 -0
- package/hooks/post-subagent-discovery-validator.mjs +398 -0
- package/hooks/post-tool-batch-wave-signal.mjs +328 -0
- package/hooks/post-tool-failure-corrective-context.mjs +248 -0
- package/hooks/post-tooluse-frontend-slop.mjs +184 -0
- package/hooks/pre-bash-destructive-guard.mjs +515 -0
- package/hooks/pre-bash-memory-propose-audit.mjs +206 -0
- package/hooks/pre-bash-staging-fence.mjs +223 -0
- package/hooks/pre-bash-templates-first.mjs +404 -0
- package/hooks/run-node.sh +72 -0
- package/hooks/skill-invocation-telemetry.mjs +99 -0
- package/hooks/subagent-telemetry.mjs +249 -0
- package/hooks/wave-scope-commit-guard.mjs +191 -0
- package/monitors/monitors.json +14 -0
- package/output-styles/finding-report.md +48 -0
- package/output-styles/session-report.md +53 -0
- package/output-styles/wave-summary.md +38 -0
- package/package.json +94 -0
- package/pi/extensions/session-orchestrator.ts +25 -0
- package/pi/prompts/autopilot-multi.md +12 -0
- package/pi/prompts/autopilot.md +12 -0
- package/pi/prompts/bootstrap.md +12 -0
- package/pi/prompts/brainstorm.md +12 -0
- package/pi/prompts/close.md +11 -0
- package/pi/prompts/debug.md +12 -0
- package/pi/prompts/discovery.md +12 -0
- package/pi/prompts/dispatcher.md +12 -0
- package/pi/prompts/eval.md +12 -0
- package/pi/prompts/evolve.md +12 -0
- package/pi/prompts/go.md +12 -0
- package/pi/prompts/grill.md +12 -0
- package/pi/prompts/harness-audit.md +12 -0
- package/pi/prompts/memory-cleanup.md +12 -0
- package/pi/prompts/persona-panel.md +12 -0
- package/pi/prompts/plan.md +12 -0
- package/pi/prompts/portfolio.md +12 -0
- package/pi/prompts/reconcile.md +12 -0
- package/pi/prompts/repo-audit.md +12 -0
- package/pi/prompts/session.md +12 -0
- package/pi/prompts/spinout.md +12 -0
- package/pi/prompts/sunset-review.md +12 -0
- package/pi/prompts/templates-ack.md +12 -0
- package/pi/prompts/test.md +12 -0
- package/rules/_index.md +51 -0
- package/rules/always-on/commit-discipline.md +26 -0
- package/rules/always-on/npm-quality-gates.md +26 -0
- package/rules/always-on/parallel-sessions.md +43 -0
- package/rules/opt-in-domain/prompt-caching.md +270 -0
- package/rules/opt-in-stack/backend-data.md +188 -0
- package/rules/opt-in-stack/backend.md +390 -0
- package/rules/opt-in-stack/frontend.md +98 -0
- package/rules/opt-in-stack/security-web.md +194 -0
- package/rules/opt-in-stack/swift.md +65 -0
- package/scripts/archive-closed-prds.mjs +416 -0
- package/scripts/autopilot-multi.mjs +802 -0
- package/scripts/autopilot.mjs +383 -0
- package/scripts/backfill-abandoned-sessions.mjs +265 -0
- package/scripts/backfill-learnings-expires.mjs +196 -0
- package/scripts/backfill-learnings.mjs +203 -0
- package/scripts/backfill-sessions.mjs +282 -0
- package/scripts/check-doc-consistency.sh +279 -0
- package/scripts/check-package-manager.mjs +445 -0
- package/scripts/ci/assert-vitest-green.mjs +267 -0
- package/scripts/codex-install.mjs +435 -0
- package/scripts/compute-grounding-injection.sh +186 -0
- package/scripts/cursor-install.mjs +113 -0
- package/scripts/dialectic-deriver.mjs +573 -0
- package/scripts/emit-event.mjs +160 -0
- package/scripts/emit-session.mjs +212 -0
- package/scripts/eval-session.mjs +262 -0
- package/scripts/export-hw-learnings.mjs +437 -0
- package/scripts/gc-stale-worktrees.mjs +666 -0
- package/scripts/generate-pi-prompts.mjs +127 -0
- package/scripts/harness-audit.mjs +287 -0
- package/scripts/lib/agent-frontmatter.mjs +266 -0
- package/scripts/lib/agent-output-schema.mjs +166 -0
- package/scripts/lib/agent-status.mjs +303 -0
- package/scripts/lib/ajv-loader.mjs +34 -0
- package/scripts/lib/auto-dialectic.mjs +382 -0
- package/scripts/lib/auto-dream.mjs +471 -0
- package/scripts/lib/autonomy/suitability.mjs +212 -0
- package/scripts/lib/autopilot/dep-graph.mjs +417 -0
- package/scripts/lib/autopilot/durable-telemetry.mjs +121 -0
- package/scripts/lib/autopilot/flags.mjs +104 -0
- package/scripts/lib/autopilot/kill-switches.mjs +174 -0
- package/scripts/lib/autopilot/loop.mjs +320 -0
- package/scripts/lib/autopilot/mr-draft.mjs +520 -0
- package/scripts/lib/autopilot/multi-killswitch.mjs +184 -0
- package/scripts/lib/autopilot/recent-runs.mjs +106 -0
- package/scripts/lib/autopilot/stall-sampler.mjs +97 -0
- package/scripts/lib/autopilot/telemetry.mjs +224 -0
- package/scripts/lib/autopilot/worktree-pipeline.mjs +605 -0
- package/scripts/lib/autopilot-telemetry.mjs +11 -0
- package/scripts/lib/autopilot.mjs +39 -0
- package/scripts/lib/backlog-scan.mjs +179 -0
- package/scripts/lib/bootstrap-lock-freshness.mjs +260 -0
- package/scripts/lib/bootstrap-lock-refresh.mjs +186 -0
- package/scripts/lib/build-live-signals.mjs +150 -0
- package/scripts/lib/ci-status-banner.mjs +425 -0
- package/scripts/lib/claude-md-budget-lint.mjs +246 -0
- package/scripts/lib/cli-flags.mjs +158 -0
- package/scripts/lib/codex/plugin-contract.mjs +610 -0
- package/scripts/lib/cold-start-detector.mjs +240 -0
- package/scripts/lib/command-blocker.mjs +458 -0
- package/scripts/lib/common.mjs +333 -0
- package/scripts/lib/config/auto-dream.mjs +77 -0
- package/scripts/lib/config/block-header.mjs +94 -0
- package/scripts/lib/config/broken-window.mjs +114 -0
- package/scripts/lib/config/coercers.mjs +248 -0
- package/scripts/lib/config/cold-start.mjs +92 -0
- package/scripts/lib/config/config-protection.mjs +120 -0
- package/scripts/lib/config/cross-repo.mjs +104 -0
- package/scripts/lib/config/custom-phases.mjs +213 -0
- package/scripts/lib/config/dialectic.mjs +92 -0
- package/scripts/lib/config/discovery-validator.mjs +75 -0
- package/scripts/lib/config/dispatcher-autonomy-capture.mjs +240 -0
- package/scripts/lib/config/dispatcher-autonomy.mjs +152 -0
- package/scripts/lib/config/docs-orchestrator.mjs +90 -0
- package/scripts/lib/config/docs-staleness.mjs +96 -0
- package/scripts/lib/config/drift-check.mjs +155 -0
- package/scripts/lib/config/eval.mjs +130 -0
- package/scripts/lib/config/events-rotation.mjs +74 -0
- package/scripts/lib/config/evolve.mjs +308 -0
- package/scripts/lib/config/frontend-slop-hook.mjs +104 -0
- package/scripts/lib/config/gitlab-portfolio.mjs +150 -0
- package/scripts/lib/config/handover-gate.mjs +106 -0
- package/scripts/lib/config/host-paths.mjs +76 -0
- package/scripts/lib/config/io.mjs +54 -0
- package/scripts/lib/config/loop-guard.mjs +117 -0
- package/scripts/lib/config/memory.mjs +150 -0
- package/scripts/lib/config/persona-gate-wave.mjs +258 -0
- package/scripts/lib/config/reconcile.mjs +205 -0
- package/scripts/lib/config/section-extractor.mjs +100 -0
- package/scripts/lib/config/skill-evolution.mjs +112 -0
- package/scripts/lib/config/slopcheck.mjs +99 -0
- package/scripts/lib/config/state-md-lock.mjs +83 -0
- package/scripts/lib/config/templates-first.mjs +94 -0
- package/scripts/lib/config/test.mjs +113 -0
- package/scripts/lib/config/vault-integration.mjs +201 -0
- package/scripts/lib/config/vault-mirror-quality.mjs +99 -0
- package/scripts/lib/config/vault-staleness.mjs +84 -0
- package/scripts/lib/config/vault-sync.mjs +96 -0
- package/scripts/lib/config/verification-auto-fix.mjs +84 -0
- package/scripts/lib/config/wave-reviewers.mjs +133 -0
- package/scripts/lib/config-schema.mjs +345 -0
- package/scripts/lib/config.mjs +474 -0
- package/scripts/lib/convergence-monitor.mjs +389 -0
- package/scripts/lib/coordinator-snapshot.mjs +371 -0
- package/scripts/lib/crypto-digest-utils.mjs +91 -0
- package/scripts/lib/discovery/helpers.mjs +127 -0
- package/scripts/lib/discovery/triage-state.mjs +279 -0
- package/scripts/lib/dispatcher/cli.mjs +257 -0
- package/scripts/lib/dispatcher/enumerate.mjs +243 -0
- package/scripts/lib/dispatcher/rank.mjs +363 -0
- package/scripts/lib/ecosystem-health.mjs +224 -0
- package/scripts/lib/ecosystem-wizard/ci-detector.mjs +18 -0
- package/scripts/lib/ecosystem-wizard/config-parser.mjs +54 -0
- package/scripts/lib/ecosystem-wizard/config-writer.mjs +287 -0
- package/scripts/lib/ecosystem-wizard/package-manager-detector.mjs +42 -0
- package/scripts/lib/ecosystem-wizard/wizard-prompt.mjs +246 -0
- package/scripts/lib/ecosystem-wizard.mjs +48 -0
- package/scripts/lib/env-check.mjs +89 -0
- package/scripts/lib/eval/engine.mjs +605 -0
- package/scripts/lib/eval/judge.mjs +433 -0
- package/scripts/lib/eval/report.mjs +367 -0
- package/scripts/lib/eval/schema.mjs +618 -0
- package/scripts/lib/eval/session-resolve.mjs +137 -0
- package/scripts/lib/eval/sink.mjs +77 -0
- package/scripts/lib/events-rotation.mjs +86 -0
- package/scripts/lib/events-schema.mjs +81 -0
- package/scripts/lib/events.mjs +80 -0
- package/scripts/lib/evolve/autonomy-verdict.mjs +461 -0
- package/scripts/lib/evolve/autopilot-effectiveness.mjs +293 -0
- package/scripts/lib/exclusivity-matrix.mjs +68 -0
- package/scripts/lib/fetch-baseline.mjs +311 -0
- package/scripts/lib/file-lock.mjs +512 -0
- package/scripts/lib/frontend-detect/detect.mjs +138 -0
- package/scripts/lib/frontend-detect/rules.mjs +295 -0
- package/scripts/lib/frontmatter-guard.mjs +241 -0
- package/scripts/lib/gates/echo-stub-detect.mjs +39 -0
- package/scripts/lib/gates/gate-baseline.mjs +42 -0
- package/scripts/lib/gates/gate-full.mjs +85 -0
- package/scripts/lib/gates/gate-helpers.mjs +231 -0
- package/scripts/lib/gates/gate-incremental.mjs +76 -0
- package/scripts/lib/gates/gate-per-file.mjs +55 -0
- package/scripts/lib/gitlab-ops/stale-mr-sweep.mjs +447 -0
- package/scripts/lib/gitlab-portfolio/aggregator.mjs +383 -0
- package/scripts/lib/gitlab-portfolio/cli.mjs +428 -0
- package/scripts/lib/gitlab-portfolio/markdown-writer.mjs +289 -0
- package/scripts/lib/gitlab-portfolio/vcs-detect.mjs +182 -0
- package/scripts/lib/handover-gate.mjs +222 -0
- package/scripts/lib/hardening.mjs +43 -0
- package/scripts/lib/hardware-pattern-detector.mjs +238 -0
- package/scripts/lib/harness-audit/categories/category1.mjs +123 -0
- package/scripts/lib/harness-audit/categories/category2.mjs +145 -0
- package/scripts/lib/harness-audit/categories/category3.mjs +143 -0
- package/scripts/lib/harness-audit/categories/category4.mjs +202 -0
- package/scripts/lib/harness-audit/categories/category5.mjs +152 -0
- package/scripts/lib/harness-audit/categories/category6.mjs +211 -0
- package/scripts/lib/harness-audit/categories/category7.mjs +125 -0
- package/scripts/lib/harness-audit/categories/category8.mjs +328 -0
- package/scripts/lib/harness-audit/categories/category9.mjs +294 -0
- package/scripts/lib/harness-audit/categories/helpers.mjs +165 -0
- package/scripts/lib/harness-audit/categories.mjs +19 -0
- package/scripts/lib/historical-guard.mjs +15 -0
- package/scripts/lib/host-identity.mjs +262 -0
- package/scripts/lib/instruction-budget-guard.mjs +332 -0
- package/scripts/lib/io.mjs +304 -0
- package/scripts/lib/issue-close-strip-labels.mjs +161 -0
- package/scripts/lib/language-mappers/README.md +57 -0
- package/scripts/lib/language-mappers/index.mjs +165 -0
- package/scripts/lib/language-mappers/markdown.mjs +149 -0
- package/scripts/lib/language-mappers/python.mjs +249 -0
- package/scripts/lib/language-mappers/swift.mjs +201 -0
- package/scripts/lib/language-mappers/typescript.mjs +433 -0
- package/scripts/lib/learnings/expiry-sweep.mjs +164 -0
- package/scripts/lib/learnings/filters.mjs +43 -0
- package/scripts/lib/learnings/io.mjs +255 -0
- package/scripts/lib/learnings/schema.mjs +518 -0
- package/scripts/lib/learnings/surface.mjs +207 -0
- package/scripts/lib/learnings.mjs +42 -0
- package/scripts/lib/lock-reaper.mjs +648 -0
- package/scripts/lib/locks/index.mjs +31 -0
- package/scripts/lib/locks/lock-body.mjs +62 -0
- package/scripts/lib/locks/staging-fence-lock.mjs +267 -0
- package/scripts/lib/locks/state-md-lock.mjs +351 -0
- package/scripts/lib/loop-readiness-banner.mjs +144 -0
- package/scripts/lib/memory-banner.mjs +478 -0
- package/scripts/lib/memory-cleanup/worktree-sweep.mjs +108 -0
- package/scripts/lib/memory-cleanup-stamp.mjs +56 -0
- package/scripts/lib/memory-paths.mjs +31 -0
- package/scripts/lib/memory-proposals/collector.mjs +334 -0
- package/scripts/lib/memory-proposals/schema.mjs +289 -0
- package/scripts/lib/memory-proposals/sink.mjs +507 -0
- package/scripts/lib/memory-proposals/store.mjs +441 -0
- package/scripts/lib/mission-status-schema.mjs +114 -0
- package/scripts/lib/mode-selector/alternatives.mjs +64 -0
- package/scripts/lib/mode-selector/constants.mjs +29 -0
- package/scripts/lib/mode-selector/context-pressure.mjs +157 -0
- package/scripts/lib/mode-selector/rationale.mjs +55 -0
- package/scripts/lib/mode-selector/scoring.mjs +221 -0
- package/scripts/lib/mode-selector-accuracy.mjs +121 -0
- package/scripts/lib/mode-selector.mjs +160 -0
- package/scripts/lib/multi-provider-build/providers.mjs +64 -0
- package/scripts/lib/multi-provider-build/templating.mjs +130 -0
- package/scripts/lib/named-baseline-resolver.mjs +233 -0
- package/scripts/lib/named-vault-resolver.mjs +433 -0
- package/scripts/lib/owner-config/coerce.mjs +29 -0
- package/scripts/lib/owner-config/constants.mjs +21 -0
- package/scripts/lib/owner-config/defaults.mjs +50 -0
- package/scripts/lib/owner-config/error.mjs +19 -0
- package/scripts/lib/owner-config/index.mjs +13 -0
- package/scripts/lib/owner-config/merge.mjs +52 -0
- package/scripts/lib/owner-config/validate.mjs +259 -0
- package/scripts/lib/owner-config-banner.mjs +126 -0
- package/scripts/lib/owner-config-loader.mjs +159 -0
- package/scripts/lib/owner-config.example.yaml +72 -0
- package/scripts/lib/owner-config.mjs +28 -0
- package/scripts/lib/owner-interview.mjs +243 -0
- package/scripts/lib/owner-yaml.mjs +571 -0
- package/scripts/lib/package-manager.mjs +160 -0
- package/scripts/lib/path-utils.mjs +217 -0
- package/scripts/lib/peer-cards/merger.mjs +310 -0
- package/scripts/lib/peer-cards/reader.mjs +125 -0
- package/scripts/lib/peer-cards/schema.mjs +230 -0
- package/scripts/lib/peer-cards/staleness-banner.mjs +86 -0
- package/scripts/lib/peer-cards/writer.mjs +138 -0
- package/scripts/lib/peer-discovery.mjs +200 -0
- package/scripts/lib/persona-panel/catalog-loader.mjs +577 -0
- package/scripts/lib/persona-panel/consolidator.mjs +370 -0
- package/scripts/lib/persona-panel/persona-runner.mjs +375 -0
- package/scripts/lib/persona-panel/threshold.mjs +130 -0
- package/scripts/lib/pi-hook-bridge.mjs +328 -0
- package/scripts/lib/platform.mjs +266 -0
- package/scripts/lib/playwright-driver/runner.mjs +297 -0
- package/scripts/lib/plugin-root.mjs +210 -0
- package/scripts/lib/pre-dispatch-check.mjs +126 -0
- package/scripts/lib/product-repo-detect.mjs +121 -0
- package/scripts/lib/profiles/registry.mjs +176 -0
- package/scripts/lib/profiles/schema.mjs +209 -0
- package/scripts/lib/qg-command-drift-banner.mjs +88 -0
- package/scripts/lib/quality-gate/diagnostics.mjs +92 -0
- package/scripts/lib/quality-gate.mjs +536 -0
- package/scripts/lib/quality-gates-cache.mjs +228 -0
- package/scripts/lib/quality-gates-policy.mjs +95 -0
- package/scripts/lib/recommendations-v0.mjs +156 -0
- package/scripts/lib/reconcile/eligibility.mjs +203 -0
- package/scripts/lib/reconcile/emitter.mjs +244 -0
- package/scripts/lib/reconcile/engine.mjs +412 -0
- package/scripts/lib/reconcile/idempotency.mjs +239 -0
- package/scripts/lib/reconcile/renderer.mjs +211 -0
- package/scripts/lib/reconcile/writer.mjs +293 -0
- package/scripts/lib/reconcile-nudge-banner.mjs +284 -0
- package/scripts/lib/resource-probe/evaluate.mjs +190 -0
- package/scripts/lib/resource-probe/parsers.mjs +181 -0
- package/scripts/lib/resource-probe/probe-platform.mjs +300 -0
- package/scripts/lib/resource-probe.mjs +95 -0
- package/scripts/lib/rule-loader.mjs +552 -0
- package/scripts/lib/rules-sync.mjs +439 -0
- package/scripts/lib/scope-gate.mjs +496 -0
- package/scripts/lib/session-close-backfill.mjs +539 -0
- package/scripts/lib/session-discovery.mjs +256 -0
- package/scripts/lib/session-end/phase-skip.mjs +357 -0
- package/scripts/lib/session-end/worktree-cleanup.mjs +112 -0
- package/scripts/lib/session-id.mjs +362 -0
- package/scripts/lib/session-lock.mjs +703 -0
- package/scripts/lib/session-registry.mjs +355 -0
- package/scripts/lib/session-schema/aliases.mjs +71 -0
- package/scripts/lib/session-schema/constants.mjs +115 -0
- package/scripts/lib/session-schema/normalizer.mjs +66 -0
- package/scripts/lib/session-schema/timestamps.mjs +64 -0
- package/scripts/lib/session-schema/validator.mjs +453 -0
- package/scripts/lib/session-schema.mjs +71 -0
- package/scripts/lib/session-token-rollup.mjs +137 -0
- package/scripts/lib/sessions-staleness-banner.mjs +247 -0
- package/scripts/lib/skill-evolution/blast-radius-classifier.mjs +114 -0
- package/scripts/lib/skill-evolution/candidate-intake.mjs +270 -0
- package/scripts/lib/skill-evolution/config-validation-gate.mjs +279 -0
- package/scripts/lib/skill-evolution/engine.mjs +719 -0
- package/scripts/lib/skill-evolution/idempotency.mjs +279 -0
- package/scripts/lib/skill-evolution/mr-opener.mjs +507 -0
- package/scripts/lib/skill-health/join.mjs +181 -0
- package/scripts/lib/skill-health/score.mjs +123 -0
- package/scripts/lib/skill-invocations-schema.mjs +214 -0
- package/scripts/lib/skill-judge.mjs +348 -0
- package/scripts/lib/skill-judgments-schema.mjs +264 -0
- package/scripts/lib/slopcheck.mjs +501 -0
- package/scripts/lib/soul-resolve.mjs +118 -0
- package/scripts/lib/spiral-carryover.mjs +495 -0
- package/scripts/lib/state-md/body-sections.mjs +851 -0
- package/scripts/lib/state-md/frontmatter-mutators.mjs +453 -0
- package/scripts/lib/state-md/mission-status.mjs +247 -0
- package/scripts/lib/state-md/recommendations.mjs +57 -0
- package/scripts/lib/state-md/yaml-parser.mjs +234 -0
- package/scripts/lib/state-md-peer-guard.mjs +232 -0
- package/scripts/lib/state-md.mjs +53 -0
- package/scripts/lib/subagents-schema.mjs +309 -0
- package/scripts/lib/sunset/walker.mjs +1192 -0
- package/scripts/lib/test-runner/artifact-paths.mjs +94 -0
- package/scripts/lib/test-runner/fingerprint.mjs +33 -0
- package/scripts/lib/test-runner/issue-reconcile.mjs +770 -0
- package/scripts/lib/tmux-layout/layouts.mjs +224 -0
- package/scripts/lib/tmux-layout/telemetry-stats.mjs +100 -0
- package/scripts/lib/tmux-layout/telemetry.mjs +88 -0
- package/scripts/lib/tmux-layout/tmux-shell.mjs +82 -0
- package/scripts/lib/tmux-layout/vcs-detector.mjs +88 -0
- package/scripts/lib/validate/check-agents.mjs +457 -0
- package/scripts/lib/validate/check-codex-plugin.mjs +37 -0
- package/scripts/lib/validate/check-commands.mjs +148 -0
- package/scripts/lib/validate/check-component-paths.mjs +112 -0
- package/scripts/lib/validate/check-dead-bridge.mjs +180 -0
- package/scripts/lib/validate/check-hooks-symmetry.mjs +258 -0
- package/scripts/lib/validate/check-json-files.mjs +116 -0
- package/scripts/lib/validate/check-owner-leakage.mjs +1011 -0
- package/scripts/lib/validate/check-path-utils-canary.mjs +175 -0
- package/scripts/lib/validate/check-peekaboo-driver-canary.mjs +201 -0
- package/scripts/lib/validate/check-pi-package.mjs +110 -0
- package/scripts/lib/validate/check-pi-prompts.mjs +43 -0
- package/scripts/lib/validate/check-playwright-mcp-canary.mjs +154 -0
- package/scripts/lib/validate/check-plugin-json.mjs +96 -0
- package/scripts/lib/validate/check-plugin-monitors.mjs +206 -0
- package/scripts/lib/validate/check-plugin-schema.mjs +137 -0
- package/scripts/lib/validate/check-rules.mjs +143 -0
- package/scripts/lib/validate/check-session-plan-routing.mjs +154 -0
- package/scripts/lib/validate/check-test-fixture-shapes.mjs +280 -0
- package/scripts/lib/validate/check-unicode-safety.mjs +533 -0
- package/scripts/lib/validate/confidential-names.mjs +169 -0
- package/scripts/lib/validate/dead-bridge-corpus.mjs +141 -0
- package/scripts/lib/validate/dead-bridge-detectors.mjs +568 -0
- package/scripts/lib/validate/tier-inference.mjs +100 -0
- package/scripts/lib/validate-vendored-rules.mjs +519 -0
- package/scripts/lib/vault-archive.mjs +404 -0
- package/scripts/lib/vault-backfill/glab.mjs +164 -0
- package/scripts/lib/vault-backfill/manifest.mjs +75 -0
- package/scripts/lib/vault-backfill/template.mjs +130 -0
- package/scripts/lib/vault-consolidate-fs.mjs +331 -0
- package/scripts/lib/vault-migration-rules.mjs +155 -0
- package/scripts/lib/vault-mirror/auto-commit.mjs +203 -0
- package/scripts/lib/vault-mirror/namespace.mjs +152 -0
- package/scripts/lib/vault-mirror/process.mjs +567 -0
- package/scripts/lib/vault-mirror/pseudonym-map.mjs +164 -0
- package/scripts/lib/vault-mirror/render-learnings.mjs +201 -0
- package/scripts/lib/vault-mirror/render-sessions.mjs +367 -0
- package/scripts/lib/vault-mirror/render.mjs +8 -0
- package/scripts/lib/vault-mirror/utils.mjs +217 -0
- package/scripts/lib/vault-relocation-rules.mjs +555 -0
- package/scripts/lib/vault-repo-backfill.mjs +235 -0
- package/scripts/lib/vault-staleness-banner.mjs +142 -0
- package/scripts/lib/vault-status/board-writer.mjs +769 -0
- package/scripts/lib/vault-status/narrative-mirror.mjs +544 -0
- package/scripts/lib/vault-sync-baseline.mjs +152 -0
- package/scripts/lib/wave-context.mjs +29 -0
- package/scripts/lib/wave-executor/pool.mjs +248 -0
- package/scripts/lib/wave-resource-gate.mjs +204 -0
- package/scripts/lib/wave-sizing.mjs +75 -0
- package/scripts/lib/webhook-url.mjs +105 -0
- package/scripts/lib/workspace.mjs +198 -0
- package/scripts/lib/worktree/constants.mjs +35 -0
- package/scripts/lib/worktree/index.mjs +17 -0
- package/scripts/lib/worktree/lifecycle.mjs +287 -0
- package/scripts/lib/worktree/listing.mjs +118 -0
- package/scripts/lib/worktree/meta.mjs +64 -0
- package/scripts/lib/worktree-freshness.mjs +313 -0
- package/scripts/lib/worktree.mjs +15 -0
- package/scripts/lifecycle-sim-v6.mjs +347 -0
- package/scripts/lock-reaper.mjs +185 -0
- package/scripts/mcp-server.sh +241 -0
- package/scripts/measure-policy-cache-effectiveness.mjs +427 -0
- package/scripts/memory-propose.mjs +464 -0
- package/scripts/migrate-cold-start-seed.mjs +404 -0
- package/scripts/migrate-learnings-jsonl.mjs +189 -0
- package/scripts/migrate-legacy-learnings.sh +61 -0
- package/scripts/migrate-sessions-jsonl.mjs +448 -0
- package/scripts/migrate-subagents-jsonl.mjs +196 -0
- package/scripts/migrate-vault-paths.mjs +796 -0
- package/scripts/parse-config.mjs +149 -0
- package/scripts/pi-install.mjs +117 -0
- package/scripts/print-applicable-rules.mjs +247 -0
- package/scripts/promote-vault-strict.mjs +496 -0
- package/scripts/relocate-vault-corpus.mjs +1178 -0
- package/scripts/run-migrate-v2-cross-repo.mjs +385 -0
- package/scripts/run-quality-gate.mjs +216 -0
- package/scripts/spikes/h3-agent-teams/preflight.sh +53 -0
- package/scripts/spikes/h3-agent-teams/run-h3.sh +112 -0
- package/scripts/spikes/h3-agent-teams/setup.sh +137 -0
- package/scripts/spikes/h3-agent-teams/toggle.sh +38 -0
- package/scripts/sweep-expired-learnings.mjs +135 -0
- package/scripts/sync-vault-schema.mjs +376 -0
- package/scripts/tests/fixtures/fetch-baseline/sample-rule.md +8 -0
- package/scripts/tmux-layout.mjs +245 -0
- package/scripts/token-audit.sh +191 -0
- package/scripts/typecheck.mjs +42 -0
- package/scripts/upload-social-preview.mjs +316 -0
- package/scripts/validate-config.mjs +46 -0
- package/scripts/validate-plugin-manifests.mjs +163 -0
- package/scripts/validate-plugin.mjs +264 -0
- package/scripts/validate-wave-scope.mjs +289 -0
- package/scripts/vault-backfill.mjs +404 -0
- package/scripts/vault-consolidate.mjs +596 -0
- package/scripts/vault-integration-watcher.mjs +394 -0
- package/scripts/vault-mirror.mjs +430 -0
- package/skills/_shared/bootstrap-gate.md +111 -0
- package/skills/_shared/config-reading.md +226 -0
- package/skills/_shared/instruction-file-resolution.md +79 -0
- package/skills/_shared/model-selection.md +64 -0
- package/skills/_shared/monitor-patterns.md +300 -0
- package/skills/_shared/parallel-aware-auq.md +121 -0
- package/skills/_shared/parallel-aware-preamble.md +185 -0
- package/skills/_shared/platform-tools.md +96 -0
- package/skills/_shared/state-ownership.md +221 -0
- package/skills/architecture/DEEPENING.md +37 -0
- package/skills/architecture/INTERFACE-DESIGN.md +44 -0
- package/skills/architecture/LANGUAGE.md +53 -0
- package/skills/architecture/SKILL.md +92 -0
- package/skills/autopilot/SKILL.md +419 -0
- package/skills/bootstrap/SKILL.md +592 -0
- package/skills/bootstrap/STATE.md.template +24 -0
- package/skills/bootstrap/_shared-template.md +243 -0
- package/skills/bootstrap/deep-template.md +659 -0
- package/skills/bootstrap/fast-template.md +251 -0
- package/skills/bootstrap/intensity-heuristic.md +80 -0
- package/skills/bootstrap/public-fallback.md +342 -0
- package/skills/bootstrap/standard-template.md +736 -0
- package/skills/bootstrap/templates/agents/project-code-review.md +18 -0
- package/skills/bootstrap/templates/agents/project-discovery.md +18 -0
- package/skills/bootstrap/templates/agents/project-quality-gate.md +18 -0
- package/skills/brainstorm/SKILL.md +268 -0
- package/skills/brainstorm/soul.md +49 -0
- package/skills/claude-md-drift-check/SKILL.md +186 -0
- package/skills/claude-md-drift-check/checker.mjs +1380 -0
- package/skills/claude-md-drift-check/checker.sh +37 -0
- package/skills/claude-md-drift-check/package.json +16 -0
- package/skills/convergence-monitoring/README.md +39 -0
- package/skills/convergence-monitoring/SIGNALS.md +246 -0
- package/skills/convergence-monitoring/SKILL.md +285 -0
- package/skills/daily/SKILL.md +222 -0
- package/skills/daily/generate.sh +92 -0
- package/skills/daily/templates/daily.md.tpl +36 -0
- package/skills/debug/SKILL.md +188 -0
- package/skills/debug/soul.md +35 -0
- package/skills/discovery/SKILL.md +567 -0
- package/skills/discovery/issue-templates.md +237 -0
- package/skills/discovery/probes/docs-staleness.mjs +195 -0
- package/skills/discovery/probes/frontend-slop.mjs +186 -0
- package/skills/discovery/probes/ssot-code-diff.mjs +310 -0
- package/skills/discovery/probes/supply-chain-slopcheck.mjs +440 -0
- package/skills/discovery/probes/vault-narrative-staleness.mjs +355 -0
- package/skills/discovery/probes/vault-staleness.mjs +272 -0
- package/skills/discovery/probes-arch.md +252 -0
- package/skills/discovery/probes-audit.md +95 -0
- package/skills/discovery/probes-code.md +329 -0
- package/skills/discovery/probes-docs.md +76 -0
- package/skills/discovery/probes-feature.md +150 -0
- package/skills/discovery/probes-infra.md +138 -0
- package/skills/discovery/probes-intro.md +25 -0
- package/skills/discovery/probes-session.md +495 -0
- package/skills/discovery/probes-supply-chain.md +94 -0
- package/skills/discovery/probes-ui.md +147 -0
- package/skills/discovery/probes-vault.md +64 -0
- package/skills/discovery/slop-patterns.md +115 -0
- package/skills/dispatcher/SKILL.md +173 -0
- package/skills/docs-orchestrator/SKILL.md +362 -0
- package/skills/docs-orchestrator/audience-mapping.md +140 -0
- package/skills/domain-model/ADR-FORMAT.md +47 -0
- package/skills/domain-model/CONTEXT-FORMAT.md +77 -0
- package/skills/domain-model/SKILL.md +85 -0
- package/skills/ecosystem-health/SKILL.md +119 -0
- package/skills/ecosystem-health/wizard.md +193 -0
- package/skills/eval/SKILL.md +293 -0
- package/skills/eval/rubric-v1.md +218 -0
- package/skills/evolve/SKILL.md +546 -0
- package/skills/frontmatter-guard/SKILL.md +126 -0
- package/skills/gitlab-ops/SKILL.md +368 -0
- package/skills/gitlab-portfolio/SKILL.md +196 -0
- package/skills/grill/SKILL.md +185 -0
- package/skills/grill/soul.md +55 -0
- package/skills/hook-development/SKILL.md +413 -0
- package/skills/mcp-builder/SKILL.md +260 -0
- package/skills/memory-cleanup/SKILL.md +310 -0
- package/skills/mode-selector/SKILL.md +226 -0
- package/skills/peekaboo-driver/SKILL.md +237 -0
- package/skills/peekaboo-driver/soul.md +32 -0
- package/skills/persona-panel/SKILL.md +365 -0
- package/skills/persona-panel/persona-format.md +205 -0
- package/skills/persona-panel/presets/designer-lens.md +87 -0
- package/skills/persona-panel/presets/engineer-lens.md +88 -0
- package/skills/persona-panel/presets/pm-lens.md +86 -0
- package/skills/plan/SKILL.md +496 -0
- package/skills/plan/mode-feature.md +141 -0
- package/skills/plan/mode-new.md +297 -0
- package/skills/plan/mode-retro.md +271 -0
- package/skills/plan/prd-feature-template.md +132 -0
- package/skills/plan/prd-full-template.md +151 -0
- package/skills/plan/prd-reviewer-prompt.md +103 -0
- package/skills/plan/retro-template.md +75 -0
- package/skills/plan/soul.md +62 -0
- package/skills/playwright-driver/SKILL.md +226 -0
- package/skills/playwright-driver/soul.md +30 -0
- package/skills/quality-gates/SKILL.md +212 -0
- package/skills/reconcile/SKILL.md +324 -0
- package/skills/repo-audit/SKILL.md +272 -0
- package/skills/session-end/SKILL.md +1044 -0
- package/skills/session-end/discovery-scan.md +37 -0
- package/skills/session-end/drift-operations.md +97 -0
- package/skills/session-end/learning-patterns.md +78 -0
- package/skills/session-end/metrics-collection.md +175 -0
- package/skills/session-end/phase-3-2-docs-verification.md +148 -0
- package/skills/session-end/phase-3-6-tail.md +344 -0
- package/skills/session-end/phase-3-7a-recommendations.md +86 -0
- package/skills/session-end/plan-verification.md +288 -0
- package/skills/session-end/session-metrics-write.md +223 -0
- package/skills/session-end/vault-operations.md +50 -0
- package/skills/session-end/verification-checklist.md +20 -0
- package/skills/session-plan/SKILL.md +554 -0
- package/skills/session-plan/wave-template.md +37 -0
- package/skills/session-start/SKILL.md +1043 -0
- package/skills/session-start/phase-2-5-docs-planning.md +119 -0
- package/skills/session-start/phase-4-5-resource-health.md +49 -0
- package/skills/session-start/phase-7-1-premise-check.md +47 -0
- package/skills/session-start/phase-7-5-mode-selector.md +237 -0
- package/skills/session-start/phase-8-5-express-path.md +61 -0
- package/skills/session-start/presentation-format.md +81 -0
- package/skills/session-start/soul.md +57 -0
- package/skills/skill-creator/SKILL.md +168 -0
- package/skills/spinout/SKILL.md +76 -0
- package/skills/sunset-review/SKILL.md +96 -0
- package/skills/test-runner/SKILL.md +362 -0
- package/skills/test-runner/rubric-v1.md +388 -0
- package/skills/test-runner/soul.md +46 -0
- package/skills/tmux-layout/SKILL.md +104 -0
- package/skills/ubiquitous-language/SKILL.md +97 -0
- package/skills/using-orchestrator/SKILL.md +144 -0
- package/skills/vault-mirror/SKILL.md +234 -0
- package/skills/vault-sync/SKILL.md +319 -0
- package/skills/vault-sync/package-lock.json +40 -0
- package/skills/vault-sync/package.json +11 -0
- package/skills/vault-sync/tests/fixtures/archive-test-vault/90-archive/bad-archived.md +8 -0
- package/skills/vault-sync/tests/fixtures/archive-test-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/archive-test-vault/live-note.md +8 -0
- package/skills/vault-sync/tests/fixtures/broken-frontmatter-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/broken-frontmatter-vault/bad-type.md +8 -0
- package/skills/vault-sync/tests/fixtures/broken-frontmatter-vault/good-note.md +8 -0
- package/skills/vault-sync/tests/fixtures/clean-vault/.obsidian/config.md +8 -0
- package/skills/vault-sync/tests/fixtures/clean-vault/01-projects/foo/projects-baseline.md +10 -0
- package/skills/vault-sync/tests/fixtures/clean-vault/03-daily/daily-2026-04-13.md +8 -0
- package/skills/vault-sync/tests/fixtures/clean-vault/README.md +3 -0
- package/skills/vault-sync/tests/fixtures/clean-vault/hello-world.md +11 -0
- package/skills/vault-sync/tests/fixtures/dangling-link-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/dangling-link-vault/has-dangling.md +9 -0
- package/skills/vault-sync/tests/fixtures/dangling-link-vault/real-target.md +8 -0
- package/skills/vault-sync/tests/fixtures/empty-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/missing-field-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/missing-field-vault/missing-id.md +7 -0
- package/skills/vault-sync/tests/fixtures/nested-tag-vault/03-daily/daily-2026-04-13.md +9 -0
- package/skills/vault-sync/tests/fixtures/nested-tag-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/nested-tag-vault/nested-tags-note.md +11 -0
- package/skills/vault-sync/tests/fixtures/no-frontmatter-vault/README.md +3 -0
- package/skills/vault-sync/tests/fixtures/no-frontmatter-vault/_MOC.md +3 -0
- package/skills/vault-sync/tests/fixtures/no-frontmatter-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/with-moc-vault/_MOC.md +11 -0
- package/skills/vault-sync/tests/fixtures/with-moc-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/with-moc-vault/hello-world.md +11 -0
- package/skills/vault-sync/tests/schema-drift.test.mjs +133 -0
- package/skills/vault-sync/validator.mjs +658 -0
- package/skills/vault-sync/validator.sh +55 -0
- package/skills/wave-executor/SKILL.md +496 -0
- package/skills/wave-executor/circuit-breaker.md +169 -0
- package/skills/wave-executor/wave-loop.md +1043 -0
- package/skills/write-executable-plan/SKILL.md +237 -0
- package/skills/write-executable-plan/plan-template.md +154 -0
- package/templates/_minimal/CLAUDE.md.tmpl +41 -0
- package/templates/_minimal/README.md.tmpl +15 -0
- package/templates/_minimal/gitignore.tmpl +47 -0
- package/templates/_shared/harte-regeln.md +16 -0
- package/templates/_shared/loop.md +90 -0
- package/templates/_shared/rules/parallel-sessions.md +77 -0
- package/templates/nextjs-minimal/README.md +30 -0
- package/templates/nextjs-minimal/app/layout.tsx +18 -0
- package/templates/nextjs-minimal/app/page.tsx +7 -0
- package/templates/nextjs-minimal/eslint.config.mjs +16 -0
- package/templates/nextjs-minimal/next.config.mjs +4 -0
- package/templates/nextjs-minimal/package.json +27 -0
- package/templates/nextjs-minimal/tsconfig.json +23 -0
- package/templates/node-minimal/README.md +33 -0
- package/templates/node-minimal/eslint.config.mjs +10 -0
- package/templates/node-minimal/package.json +21 -0
- package/templates/node-minimal/src/index.ts +1 -0
- package/templates/node-minimal/tests/sanity.test.ts +5 -0
- package/templates/node-minimal/tsconfig.json +17 -0
- package/templates/personas/README.md +150 -0
- package/templates/personas/accounting-compliance.v1.md +120 -0
- package/templates/personas/accounting-tax-advisor.v1.md +116 -0
- package/templates/personas/buyer-p1-cto.v1.md +125 -0
- package/templates/personas/buyer-p2-kanzlei.v1.md +134 -0
- package/templates/personas/buyer-p3-build.v1.md +130 -0
- package/templates/personas/buyer-p4-tech-veto.v1.md +130 -0
- package/templates/personas/buyer-p5-solo.v1.md +132 -0
- package/templates/personas/buyer-p6-ld.v1.md +130 -0
- package/templates/personas/klima-ai-expert.v1.md +114 -0
- package/templates/personas/klima-physicist.v1.md +117 -0
- package/templates/python-uv/README.md +28 -0
- package/templates/python-uv/pyproject.toml +32 -0
- package/templates/python-uv/src/__PROJECT_NAME__/__init__.py +0 -0
- package/templates/python-uv/src/__PROJECT_NAME__/main.py +6 -0
- package/templates/python-uv/tests/test_sanity.py +2 -0
- package/templates/static-html/README.md +19 -0
- package/templates/static-html/index.html +15 -0
- package/templates/static-html/script.js +1 -0
- package/templates/static-html/styles.css +26 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* profile-gate.mjs — runtime hook control via SO_HOOK_PROFILE + SO_DISABLED_HOOKS.
|
|
3
|
+
*
|
|
4
|
+
* Issue #211. Allows operators to disable hook handlers at runtime without editing
|
|
5
|
+
* hooks.json or settings files.
|
|
6
|
+
*
|
|
7
|
+
* Env vars:
|
|
8
|
+
* SO_HOOK_PROFILE "full" | "minimal" | "off" (default: "full")
|
|
9
|
+
* SO_DISABLED_HOOKS comma-separated hook names to disable individually
|
|
10
|
+
*
|
|
11
|
+
* Profile mapping:
|
|
12
|
+
* full — all hooks enabled (default, preserves existing behaviour)
|
|
13
|
+
* minimal — only on-session-start + pre-bash-destructive-guard enabled
|
|
14
|
+
* off — no hooks enabled
|
|
15
|
+
*
|
|
16
|
+
* SO_DISABLED_HOOKS overrides the profile for the listed names.
|
|
17
|
+
* Unknown profiles default to "full" and emit a single stderr warning.
|
|
18
|
+
*
|
|
19
|
+
* Usage in each hook handler (at the very top, before any other logic):
|
|
20
|
+
* import { shouldRunHook } from './_lib/profile-gate.mjs';
|
|
21
|
+
* if (!shouldRunHook('on-session-start')) process.exit(0);
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/** Hook names enabled in the "minimal" profile. */
|
|
25
|
+
const MINIMAL_HOOKS = new Set([
|
|
26
|
+
'on-session-start',
|
|
27
|
+
'pre-bash-destructive-guard',
|
|
28
|
+
]);
|
|
29
|
+
|
|
30
|
+
/** Valid profile names. */
|
|
31
|
+
const VALID_PROFILES = new Set(['full', 'minimal', 'off']);
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Warn once per process (hook subprocess is single-use, so this is effectively
|
|
35
|
+
* warn-once per invocation).
|
|
36
|
+
*/
|
|
37
|
+
let _unknownProfileWarned = false;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Resolve the active profile from SO_HOOK_PROFILE.
|
|
41
|
+
* Unknown values → "full" + single stderr warning.
|
|
42
|
+
*
|
|
43
|
+
* @returns {"full"|"minimal"|"off"}
|
|
44
|
+
*/
|
|
45
|
+
function resolveProfile() {
|
|
46
|
+
const raw = (process.env.SO_HOOK_PROFILE ?? '').trim().toLowerCase();
|
|
47
|
+
if (!raw || raw === 'full') return 'full';
|
|
48
|
+
if (VALID_PROFILES.has(raw)) return /** @type {"full"|"minimal"|"off"} */ (raw);
|
|
49
|
+
|
|
50
|
+
// Unknown profile — warn once, fall back to full
|
|
51
|
+
if (!_unknownProfileWarned) {
|
|
52
|
+
process.stderr.write(
|
|
53
|
+
`⚠ SO_HOOK_PROFILE="${process.env.SO_HOOK_PROFILE}" is unknown — defaulting to "full". ` +
|
|
54
|
+
`Valid values: full | minimal | off\n`
|
|
55
|
+
);
|
|
56
|
+
_unknownProfileWarned = true;
|
|
57
|
+
}
|
|
58
|
+
return 'full';
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Parse SO_DISABLED_HOOKS into a Set of lowercase hook names.
|
|
63
|
+
*
|
|
64
|
+
* @returns {Set<string>}
|
|
65
|
+
*/
|
|
66
|
+
function resolveDisabledHooks() {
|
|
67
|
+
const raw = process.env.SO_DISABLED_HOOKS ?? '';
|
|
68
|
+
if (!raw.trim()) return new Set();
|
|
69
|
+
return new Set(
|
|
70
|
+
raw.split(',').map((s) => s.trim().toLowerCase()).filter(Boolean)
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Determine whether a named hook should run given the current env configuration.
|
|
76
|
+
*
|
|
77
|
+
* @param {string} hookName - canonical hook file stem (e.g. "on-session-start")
|
|
78
|
+
* @param {boolean} [defaultEnabled=true] - fallback when no profile/disable-list applies
|
|
79
|
+
* @returns {boolean} true = run the hook; false = skip (exit 0)
|
|
80
|
+
*/
|
|
81
|
+
export function shouldRunHook(hookName, defaultEnabled = true) {
|
|
82
|
+
const name = hookName.trim().toLowerCase();
|
|
83
|
+
|
|
84
|
+
// SO_DISABLED_HOOKS takes precedence over profile for listed names.
|
|
85
|
+
const disabled = resolveDisabledHooks();
|
|
86
|
+
if (disabled.has(name)) return false;
|
|
87
|
+
|
|
88
|
+
const profile = resolveProfile();
|
|
89
|
+
|
|
90
|
+
if (profile === 'off') return false;
|
|
91
|
+
if (profile === 'minimal') return MINIMAL_HOOKS.has(name);
|
|
92
|
+
|
|
93
|
+
// profile === 'full' — use defaultEnabled (always true in practice)
|
|
94
|
+
return defaultEnabled;
|
|
95
|
+
}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* transcript-history.mjs — Read-only inspection of the Claude Code transcript JSONL.
|
|
3
|
+
*
|
|
4
|
+
* Part of issue #519 ("gsd Pattern Adoption Quick-Wins", archived in the
|
|
5
|
+
* private Meta-Vault, Pattern 3: gh-templates-first PreToolUse hook). Other
|
|
6
|
+
* hooks call into this helper to answer "did the coordinator already Read a
|
|
7
|
+
* matching template path during this session?".
|
|
8
|
+
*
|
|
9
|
+
* Schema reference (Claude Code hook contract): each PreToolUse stdin payload
|
|
10
|
+
* carries a `transcript_path` field pointing at a JSONL file. Each line is one
|
|
11
|
+
* record; assistant tool calls appear as:
|
|
12
|
+
*
|
|
13
|
+
* { type: "assistant",
|
|
14
|
+
* message: { content: [ { type: "tool_use", name: "Read",
|
|
15
|
+
* input: { file_path: "<abs path>" } }, ... ] } }
|
|
16
|
+
*
|
|
17
|
+
* We only ever read, never write. Failure (missing file, malformed JSON, no
|
|
18
|
+
* permission) returns false — the caller is responsible for deciding whether
|
|
19
|
+
* "no evidence of prior Read" should block or pass. The default-deny semantics
|
|
20
|
+
* for the templates-first hook live in the caller, not here.
|
|
21
|
+
*
|
|
22
|
+
* No external dependencies — Node 20+ stdlib only.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import { readFile } from 'node:fs/promises';
|
|
26
|
+
import { existsSync } from 'node:fs';
|
|
27
|
+
import path from 'node:path';
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Cap on transcript bytes read. A long session can grow to several MB; we
|
|
31
|
+
* cap at 16 MiB to keep the hook hot-path bounded. Records older than this
|
|
32
|
+
* cap will simply not be inspected — acceptable trade-off because a Read
|
|
33
|
+
* relevant to the current `gh/glab create` is almost certainly recent.
|
|
34
|
+
*/
|
|
35
|
+
const MAX_TRANSCRIPT_BYTES = 16 * 1024 * 1024;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Cap on simultaneous match attempts per pattern. Patterns are matched as
|
|
39
|
+
* substrings, and the caller passes a small fixed list — but if a pathological
|
|
40
|
+
* caller passed thousands of patterns we still keep work bounded.
|
|
41
|
+
*/
|
|
42
|
+
const MAX_PATTERNS = 64;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Check whether the absolute path `filePath` appears to match the
|
|
46
|
+
* pattern. Patterns are interpreted as substrings of the file path, with
|
|
47
|
+
* one carve-out: a trailing slash means "directory match" — any path that
|
|
48
|
+
* contains the pattern (sans trailing slash) followed by a path separator
|
|
49
|
+
* counts as a hit, but the bare pattern alone does not.
|
|
50
|
+
*
|
|
51
|
+
* Examples:
|
|
52
|
+
* matchPathPattern("/repo/.github/PULL_REQUEST_TEMPLATE.md",
|
|
53
|
+
* ".github/PULL_REQUEST_TEMPLATE.md") -> true
|
|
54
|
+
* matchPathPattern("/repo/.github/ISSUE_TEMPLATE/bug.md",
|
|
55
|
+
* ".github/ISSUE_TEMPLATE/") -> true
|
|
56
|
+
* matchPathPattern("/repo/.github/ISSUE_TEMPLATE",
|
|
57
|
+
* ".github/ISSUE_TEMPLATE/") -> false (no child)
|
|
58
|
+
* matchPathPattern("/repo/.github/ISSUE_TEMPLATE",
|
|
59
|
+
* ".github/ISSUE_TEMPLATE") -> true (substring fallback)
|
|
60
|
+
*
|
|
61
|
+
* @param {string} filePath Absolute or relative path observed in transcript
|
|
62
|
+
* @param {string} pattern Pattern from policy template_paths[]
|
|
63
|
+
* @returns {boolean}
|
|
64
|
+
*/
|
|
65
|
+
export function matchPathPattern(filePath, pattern) {
|
|
66
|
+
if (typeof filePath !== 'string' || typeof pattern !== 'string') return false;
|
|
67
|
+
if (filePath.length === 0 || pattern.length === 0) return false;
|
|
68
|
+
|
|
69
|
+
// Normalise both sides to POSIX-style separators for substring matching.
|
|
70
|
+
// We don't resolve symlinks or canonicalise — fuzzy substring match is
|
|
71
|
+
// intentional so that the policy file stays portable.
|
|
72
|
+
const norm = (s) => s.replace(/\\/g, '/');
|
|
73
|
+
const haystack = norm(filePath);
|
|
74
|
+
const needle = norm(pattern);
|
|
75
|
+
|
|
76
|
+
// Directory-style pattern (trailing slash): require pattern (sans slash)
|
|
77
|
+
// followed by a separator somewhere in the path.
|
|
78
|
+
if (needle.endsWith('/')) {
|
|
79
|
+
const stem = needle.slice(0, -1);
|
|
80
|
+
// Must appear with a path-separator before AND after, OR at start of path.
|
|
81
|
+
const idx = haystack.indexOf(stem + '/');
|
|
82
|
+
return idx !== -1;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Plain substring match.
|
|
86
|
+
return haystack.includes(needle);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Extract every file_path value from `Read` tool_use entries in a single
|
|
91
|
+
* transcript record (parsed JSON object). Returns an empty array when the
|
|
92
|
+
* record contains no Read tool_use.
|
|
93
|
+
*
|
|
94
|
+
* @param {object} record Parsed JSON object from one JSONL line
|
|
95
|
+
* @returns {string[]}
|
|
96
|
+
*/
|
|
97
|
+
export function extractReadFilePaths(record) {
|
|
98
|
+
if (!record || typeof record !== 'object') return [];
|
|
99
|
+
// Only assistant records carry tool_use entries we care about.
|
|
100
|
+
if (record.type !== 'assistant') return [];
|
|
101
|
+
const msg = record.message;
|
|
102
|
+
if (!msg || typeof msg !== 'object') return [];
|
|
103
|
+
const content = msg.content;
|
|
104
|
+
if (!Array.isArray(content)) return [];
|
|
105
|
+
|
|
106
|
+
const paths = [];
|
|
107
|
+
for (const block of content) {
|
|
108
|
+
if (!block || typeof block !== 'object') continue;
|
|
109
|
+
if (block.type !== 'tool_use') continue;
|
|
110
|
+
if (block.name !== 'Read') continue;
|
|
111
|
+
const fp = block.input?.file_path;
|
|
112
|
+
if (typeof fp === 'string' && fp.length > 0) paths.push(fp);
|
|
113
|
+
}
|
|
114
|
+
return paths;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Read the transcript JSONL file and return true when at least one prior
|
|
119
|
+
* `Read` tool call's `file_path` matches any of `pathPatterns`.
|
|
120
|
+
*
|
|
121
|
+
* Fail-safe semantics: on any error (missing transcript, unreadable file,
|
|
122
|
+
* malformed JSON line, etc.) the function returns false. The caller's hook
|
|
123
|
+
* then treats absence-of-evidence as the default-deny path. This is the
|
|
124
|
+
* correct safety posture for templates-first: when we cannot prove the
|
|
125
|
+
* coordinator has read a template, we should not let an unguarded
|
|
126
|
+
* `gh/glab create` through.
|
|
127
|
+
*
|
|
128
|
+
* @param {string[]} pathPatterns Patterns from templates-policy.json
|
|
129
|
+
* @param {string} transcriptPath Absolute path to the session JSONL
|
|
130
|
+
* @returns {Promise<{ matched: boolean, matchedPath: string|null }>}
|
|
131
|
+
*/
|
|
132
|
+
export async function hasReadInSession(pathPatterns, transcriptPath) {
|
|
133
|
+
if (!Array.isArray(pathPatterns) || pathPatterns.length === 0) {
|
|
134
|
+
return { matched: false, matchedPath: null };
|
|
135
|
+
}
|
|
136
|
+
if (typeof transcriptPath !== 'string' || transcriptPath.length === 0) {
|
|
137
|
+
return { matched: false, matchedPath: null };
|
|
138
|
+
}
|
|
139
|
+
if (!existsSync(transcriptPath)) {
|
|
140
|
+
return { matched: false, matchedPath: null };
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Cap pattern list defensively.
|
|
144
|
+
const patterns = pathPatterns.slice(0, MAX_PATTERNS).filter(
|
|
145
|
+
(p) => typeof p === 'string' && p.length > 0,
|
|
146
|
+
);
|
|
147
|
+
if (patterns.length === 0) {
|
|
148
|
+
return { matched: false, matchedPath: null };
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
let raw;
|
|
152
|
+
try {
|
|
153
|
+
raw = await readFile(transcriptPath, 'utf8');
|
|
154
|
+
} catch {
|
|
155
|
+
return { matched: false, matchedPath: null };
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (raw.length > MAX_TRANSCRIPT_BYTES) {
|
|
159
|
+
// Inspect only the trailing slice — the most recent records are the
|
|
160
|
+
// ones a templates-Read is likely to live in. Splitting at the next
|
|
161
|
+
// newline ensures we don't start mid-record.
|
|
162
|
+
const sliced = raw.slice(raw.length - MAX_TRANSCRIPT_BYTES);
|
|
163
|
+
const nlIdx = sliced.indexOf('\n');
|
|
164
|
+
raw = nlIdx === -1 ? sliced : sliced.slice(nlIdx + 1);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Iterate line-by-line. Use split rather than readline streaming because
|
|
168
|
+
// 16 MiB is small enough to hold in memory comfortably and avoids
|
|
169
|
+
// dangling-handle issues on hook subprocess teardown.
|
|
170
|
+
const lines = raw.split(/\r?\n/);
|
|
171
|
+
for (const line of lines) {
|
|
172
|
+
if (!line) continue;
|
|
173
|
+
let record;
|
|
174
|
+
try {
|
|
175
|
+
record = JSON.parse(line);
|
|
176
|
+
} catch {
|
|
177
|
+
// Skip malformed lines — partial writes from in-flight tool calls.
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
const filePaths = extractReadFilePaths(record);
|
|
181
|
+
if (filePaths.length === 0) continue;
|
|
182
|
+
|
|
183
|
+
for (const fp of filePaths) {
|
|
184
|
+
for (const pat of patterns) {
|
|
185
|
+
if (matchPathPattern(fp, pat)) {
|
|
186
|
+
return { matched: true, matchedPath: fp };
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return { matched: false, matchedPath: null };
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Convenience: return only the boolean. Useful for hot-path callers that
|
|
197
|
+
* do not need the matched path. Falls through to hasReadInSession().
|
|
198
|
+
*
|
|
199
|
+
* @param {string[]} pathPatterns
|
|
200
|
+
* @param {string} transcriptPath
|
|
201
|
+
* @returns {Promise<boolean>}
|
|
202
|
+
*/
|
|
203
|
+
export async function hasReadInSessionBool(pathPatterns, transcriptPath) {
|
|
204
|
+
const { matched } = await hasReadInSession(pathPatterns, transcriptPath);
|
|
205
|
+
return matched;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Re-export the path module's join so test fixtures can build platform-
|
|
209
|
+
// safe paths without re-importing 'node:path'. Not part of the public API
|
|
210
|
+
// contract — purely a convenience.
|
|
211
|
+
export const _join = path.join;
|
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# hooks/agent-teams-h3-test.sh — Empirical H3 hook-seam test harness for Agent Teams Adapter
|
|
3
|
+
#
|
|
4
|
+
# Per ADR 0002 (issue #484): verify that a TaskCompleted exit-2 hook reliably blocks
|
|
5
|
+
# task completion + feeds back to the teammate across 3 repeat runs (lagging-task-status race).
|
|
6
|
+
#
|
|
7
|
+
# This is a DRY-RUN harness. Live Agent Teams execution is interactive and cannot be
|
|
8
|
+
# fully automated from bash. The script:
|
|
9
|
+
# 1. Verifies preconditions (claude-code version, experimental flag availability)
|
|
10
|
+
# 2. Sets up the test team scaffold at ~/.claude/teams/h3-test-deep3/
|
|
11
|
+
# 3. Prints the manual 3-run procedure for the operator to execute
|
|
12
|
+
# 4. Generates a JSONL log template for capturing results
|
|
13
|
+
#
|
|
14
|
+
# Exit codes:
|
|
15
|
+
# 0 — preconditions met, scaffold created, ready for manual 3-run
|
|
16
|
+
# 1 — preconditions failed (version too low, flag unrecognized, etc.)
|
|
17
|
+
# 2 — scaffold creation failed (permission/path issue)
|
|
18
|
+
|
|
19
|
+
set -euo pipefail
|
|
20
|
+
|
|
21
|
+
TEAM_NAME="h3-test-deep3"
|
|
22
|
+
TEAM_DIR="${HOME}/.claude/teams/${TEAM_NAME}"
|
|
23
|
+
LOG_TEMPLATE_PATH=".orchestrator/research/h3-hook-seam-test-template.jsonl"
|
|
24
|
+
MIN_CLAUDE_VERSION="2.1.32"
|
|
25
|
+
|
|
26
|
+
# ---------------------------------------------------------------------------
|
|
27
|
+
# Helpers
|
|
28
|
+
# ---------------------------------------------------------------------------
|
|
29
|
+
|
|
30
|
+
print_header() {
|
|
31
|
+
echo ""
|
|
32
|
+
echo "============================================================"
|
|
33
|
+
echo " H3 Hook-Seam Test Harness — Agent Teams Adapter (ADR 0002)"
|
|
34
|
+
echo "============================================================"
|
|
35
|
+
echo ""
|
|
36
|
+
echo "Purpose: Verify that a TaskCompleted exit-2 hook reliably blocks"
|
|
37
|
+
echo " task completion and delivers feedback to the teammate,"
|
|
38
|
+
echo " across 3 repeat runs (lagging-task-status race check)."
|
|
39
|
+
echo ""
|
|
40
|
+
echo "This is a DRY-RUN setup harness. Live execution is interactive."
|
|
41
|
+
echo ""
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
version_gte() {
|
|
45
|
+
# Returns 0 if $1 >= $2 (semver comparison, major.minor.patch)
|
|
46
|
+
local actual="$1"
|
|
47
|
+
local required="$2"
|
|
48
|
+
# Use sort -V to compare; if the required version comes first (or is equal),
|
|
49
|
+
# the actual version is sufficient.
|
|
50
|
+
local lowest
|
|
51
|
+
lowest="$(printf '%s\n%s\n' "$actual" "$required" | sort -V | head -n1)"
|
|
52
|
+
[ "$lowest" = "$required" ]
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
# ---------------------------------------------------------------------------
|
|
56
|
+
# Step 1: Precondition check
|
|
57
|
+
# ---------------------------------------------------------------------------
|
|
58
|
+
|
|
59
|
+
precondition_check() {
|
|
60
|
+
echo "=== Step 1: Precondition Check ==="
|
|
61
|
+
echo ""
|
|
62
|
+
|
|
63
|
+
local failed=0
|
|
64
|
+
|
|
65
|
+
# 1a. claude-code binary present
|
|
66
|
+
if ! command -v claude >/dev/null 2>&1; then
|
|
67
|
+
echo "[FAIL] 'claude' binary not found on PATH."
|
|
68
|
+
echo " Install Claude Code >= ${MIN_CLAUDE_VERSION} and ensure it is on your PATH."
|
|
69
|
+
failed=1
|
|
70
|
+
else
|
|
71
|
+
# 1b. Version check
|
|
72
|
+
local raw_version
|
|
73
|
+
raw_version="$(claude --version 2>/dev/null | head -n1)" || true
|
|
74
|
+
# Extract the semver portion (e.g. "2.1.144" from "2.1.144 (Claude Code)")
|
|
75
|
+
local actual_version
|
|
76
|
+
actual_version="$(echo "${raw_version}" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -n1)" || true
|
|
77
|
+
|
|
78
|
+
if [ -z "${actual_version}" ]; then
|
|
79
|
+
echo "[FAIL] Could not parse version from: '${raw_version}'"
|
|
80
|
+
echo " Expected format: '2.1.144 (Claude Code)'"
|
|
81
|
+
failed=1
|
|
82
|
+
elif version_gte "${actual_version}" "${MIN_CLAUDE_VERSION}"; then
|
|
83
|
+
echo "[PASS] claude version: ${actual_version} >= ${MIN_CLAUDE_VERSION} (minimum required)"
|
|
84
|
+
else
|
|
85
|
+
echo "[FAIL] claude version: ${actual_version} < ${MIN_CLAUDE_VERSION} (minimum required)"
|
|
86
|
+
echo " Please upgrade Claude Code before running the H3 test."
|
|
87
|
+
failed=1
|
|
88
|
+
fi
|
|
89
|
+
fi
|
|
90
|
+
|
|
91
|
+
# 1c. CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS recognized in binary
|
|
92
|
+
# We check via 'strings' (available on macOS/Linux) rather than actually
|
|
93
|
+
# setting the env-var, since setting it alone has no side effects but
|
|
94
|
+
# we want to confirm the flag is compiled in — not just accepted silently.
|
|
95
|
+
echo ""
|
|
96
|
+
echo "Checking CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS flag recognition..."
|
|
97
|
+
local claude_bin
|
|
98
|
+
claude_bin="$(command -v claude 2>/dev/null)" || true
|
|
99
|
+
|
|
100
|
+
if [ -n "${claude_bin}" ] && command -v strings >/dev/null 2>&1; then
|
|
101
|
+
local flag_hits
|
|
102
|
+
flag_hits="$(strings "${claude_bin}" 2>/dev/null | grep -c 'CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS' || true)"
|
|
103
|
+
if [ "${flag_hits}" -ge 1 ]; then
|
|
104
|
+
echo "[PASS] CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS is compiled into the binary (${flag_hits} occurrences)"
|
|
105
|
+
else
|
|
106
|
+
echo "[WARN] Could not confirm flag in binary via 'strings'. This may be a macOS SIP or binary format issue."
|
|
107
|
+
echo " Proceeding; flag may still be recognized at runtime."
|
|
108
|
+
fi
|
|
109
|
+
else
|
|
110
|
+
echo "[INFO] 'strings' not available or claude binary not found — skipping binary flag scan."
|
|
111
|
+
echo " Flag recognition was confirmed empirically at W1 D2 (session 2026-05-19-deep-2)."
|
|
112
|
+
fi
|
|
113
|
+
|
|
114
|
+
# 1d. No existing ~/.claude/teams/ team with this name (avoid clobber)
|
|
115
|
+
echo ""
|
|
116
|
+
if [ -d "${TEAM_DIR}" ]; then
|
|
117
|
+
echo "[WARN] ${TEAM_DIR} already exists. Scaffold step will skip overwriting existing files."
|
|
118
|
+
else
|
|
119
|
+
echo "[INFO] ${TEAM_DIR} does not exist — scaffold will create it fresh."
|
|
120
|
+
fi
|
|
121
|
+
|
|
122
|
+
echo ""
|
|
123
|
+
if [ "${failed}" -eq 1 ]; then
|
|
124
|
+
echo "[FAIL] One or more preconditions not met. Resolve issues above before proceeding."
|
|
125
|
+
return 1
|
|
126
|
+
fi
|
|
127
|
+
|
|
128
|
+
echo "[PASS] All preconditions met."
|
|
129
|
+
return 0
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
# ---------------------------------------------------------------------------
|
|
133
|
+
# Step 2: Scaffold the test team directory
|
|
134
|
+
# ---------------------------------------------------------------------------
|
|
135
|
+
|
|
136
|
+
scaffold_team_dir() {
|
|
137
|
+
echo "=== Step 2: Team Scaffold ==="
|
|
138
|
+
echo ""
|
|
139
|
+
echo "Creating team scaffold at: ${TEAM_DIR}"
|
|
140
|
+
echo ""
|
|
141
|
+
|
|
142
|
+
# Use a subshell so set -e applies; any failure returns 2 to caller via trap
|
|
143
|
+
if ! mkdir -p "${TEAM_DIR}"; then
|
|
144
|
+
echo "[FAIL] Could not create ${TEAM_DIR} — check permissions."
|
|
145
|
+
return 2
|
|
146
|
+
fi
|
|
147
|
+
|
|
148
|
+
# Write the hooks config that will exercise the H3 seam.
|
|
149
|
+
# NOTE: This is the INTENDED config shape; the operator must verify that
|
|
150
|
+
# the actual Agent Teams schema in their claude-code version matches this
|
|
151
|
+
# before live execution. The machine-owned config.json is NOT created here
|
|
152
|
+
# (that is generated by claude-code on first team spawn).
|
|
153
|
+
local hooks_file="${TEAM_DIR}/hooks.json"
|
|
154
|
+
if [ ! -f "${hooks_file}" ]; then
|
|
155
|
+
cat >"${hooks_file}" <<'HOOKS_JSON'
|
|
156
|
+
{
|
|
157
|
+
"_comment": "H3 test hook config — NOT machine-owned config.json. Verify schema with your claude-code version.",
|
|
158
|
+
"_warning": "config.json for Agent Teams is machine-owned; do not hand-edit it. This hooks.json is reference only.",
|
|
159
|
+
"teamHooks": {
|
|
160
|
+
"TaskCompleted": [
|
|
161
|
+
{
|
|
162
|
+
"hooks": [
|
|
163
|
+
{
|
|
164
|
+
"type": "command",
|
|
165
|
+
"command": "npm run typecheck",
|
|
166
|
+
"_rationale": "Exit-2 on typecheck failure blocks task completion + feeds back to teammate. H3 test seam."
|
|
167
|
+
}
|
|
168
|
+
]
|
|
169
|
+
}
|
|
170
|
+
],
|
|
171
|
+
"TeammateIdle": [
|
|
172
|
+
{
|
|
173
|
+
"hooks": [
|
|
174
|
+
{
|
|
175
|
+
"type": "command",
|
|
176
|
+
"command": "echo '[H3] TeammateIdle hook fired — teammate is idle'",
|
|
177
|
+
"_rationale": "Witness hook to confirm TeammateIdle seam fires. No blocking behavior for H3."
|
|
178
|
+
}
|
|
179
|
+
]
|
|
180
|
+
}
|
|
181
|
+
]
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
HOOKS_JSON
|
|
185
|
+
echo "[DONE] Created ${hooks_file} (reference hook config — NOT the machine-owned config.json)"
|
|
186
|
+
else
|
|
187
|
+
echo "[SKIP] ${hooks_file} already exists — not overwritten."
|
|
188
|
+
fi
|
|
189
|
+
|
|
190
|
+
# Write the test task definition (reference only)
|
|
191
|
+
local task_file="${TEAM_DIR}/h3-test-task.json"
|
|
192
|
+
if [ ! -f "${task_file}" ]; then
|
|
193
|
+
cat >"${task_file}" <<'TASK_JSON'
|
|
194
|
+
{
|
|
195
|
+
"_comment": "Reference task definition for H3 manual test run. Adapt to your team lead's task-creation flow.",
|
|
196
|
+
"id": "h3-ts-error-task",
|
|
197
|
+
"subject": "Introduce a deliberate TypeScript error in a scratch file, then confirm typecheck blocks completion",
|
|
198
|
+
"description": "Add 'const x: number = \"not-a-number\";' to src/scratch/h3-test.ts. This guarantees a typecheck failure. The TaskCompleted hook (npm run typecheck) must exit 2, blocking the teammate and delivering the error message as feedback. Verify the teammate sees the block, reads the feedback, corrects the file, and retries.",
|
|
199
|
+
"expectedOutcome": {
|
|
200
|
+
"hookFires": true,
|
|
201
|
+
"exitCode": 2,
|
|
202
|
+
"taskBlocked": true,
|
|
203
|
+
"feedbackDelivered": true,
|
|
204
|
+
"teammateRetries": true
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
TASK_JSON
|
|
208
|
+
echo "[DONE] Created ${task_file} (reference task definition)"
|
|
209
|
+
else
|
|
210
|
+
echo "[SKIP] ${task_file} already exists — not overwritten."
|
|
211
|
+
fi
|
|
212
|
+
|
|
213
|
+
echo ""
|
|
214
|
+
echo "[PASS] Scaffold complete: ${TEAM_DIR}"
|
|
215
|
+
return 0
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
# ---------------------------------------------------------------------------
|
|
219
|
+
# Step 3: Generate JSONL log template
|
|
220
|
+
# ---------------------------------------------------------------------------
|
|
221
|
+
|
|
222
|
+
generate_log_template() {
|
|
223
|
+
echo "=== Step 3: JSONL Log Template ==="
|
|
224
|
+
echo ""
|
|
225
|
+
|
|
226
|
+
local log_dir
|
|
227
|
+
log_dir="$(dirname "${LOG_TEMPLATE_PATH}")"
|
|
228
|
+
|
|
229
|
+
if [ ! -d "${log_dir}" ]; then
|
|
230
|
+
echo "[INFO] Creating directory: ${log_dir}"
|
|
231
|
+
if ! mkdir -p "${log_dir}"; then
|
|
232
|
+
echo "[WARN] Could not create ${log_dir} — skipping log template generation."
|
|
233
|
+
return 0
|
|
234
|
+
fi
|
|
235
|
+
fi
|
|
236
|
+
|
|
237
|
+
if [ -f "${LOG_TEMPLATE_PATH}" ]; then
|
|
238
|
+
echo "[SKIP] ${LOG_TEMPLATE_PATH} already exists — not overwritten."
|
|
239
|
+
return 0
|
|
240
|
+
fi
|
|
241
|
+
|
|
242
|
+
cat >"${LOG_TEMPLATE_PATH}" <<'JSONL_TEMPLATE'
|
|
243
|
+
{"timestamp":"YYYY-MM-DDTHH:MM:SSZ","run_n":1,"hook_exit_code":null,"task_status":null,"blocked":null,"feedback_delivered":null,"teammate_retried":null,"notes":"Run 1 — PENDING. Fill after manual execution."}
|
|
244
|
+
{"timestamp":"YYYY-MM-DDTHH:MM:SSZ","run_n":2,"hook_exit_code":null,"task_status":null,"blocked":null,"feedback_delivered":null,"teammate_retried":null,"notes":"Run 2 — PENDING. Fill after manual execution."}
|
|
245
|
+
{"timestamp":"YYYY-MM-DDTHH:MM:SSZ","run_n":3,"hook_exit_code":null,"task_status":null,"blocked":null,"feedback_delivered":null,"teammate_retried":null,"notes":"Run 3 — PENDING. Fill after manual execution."}
|
|
246
|
+
JSONL_TEMPLATE
|
|
247
|
+
|
|
248
|
+
echo "[DONE] Created log template: ${LOG_TEMPLATE_PATH}"
|
|
249
|
+
echo ""
|
|
250
|
+
echo "Schema per row:"
|
|
251
|
+
echo " timestamp — ISO-8601 UTC timestamp of the run"
|
|
252
|
+
echo " run_n — 1, 2, or 3"
|
|
253
|
+
echo " hook_exit_code — observed exit code from the TaskCompleted hook (expect 2 on TS error)"
|
|
254
|
+
echo " task_status — 'blocked' | 'completed' | 'error'"
|
|
255
|
+
echo " blocked — true if teammate saw the task blocked; false otherwise"
|
|
256
|
+
echo " feedback_delivered — true if teammate received the typecheck error message; false otherwise"
|
|
257
|
+
echo " teammate_retried — true if teammate corrected the error and retried; false otherwise"
|
|
258
|
+
echo " notes — free-text observations (race condition signs, UI behaviour, etc.)"
|
|
259
|
+
return 0
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
# ---------------------------------------------------------------------------
|
|
263
|
+
# Step 4: Print manual 3-run procedure
|
|
264
|
+
# ---------------------------------------------------------------------------
|
|
265
|
+
|
|
266
|
+
print_manual_procedure() {
|
|
267
|
+
echo ""
|
|
268
|
+
echo "=== Step 4: Manual 3-Run Procedure ==="
|
|
269
|
+
echo ""
|
|
270
|
+
echo "Complete the following steps manually in a terminal with an interactive Claude Code session."
|
|
271
|
+
echo "Run the full procedure 3 times, logging results to: ${LOG_TEMPLATE_PATH}"
|
|
272
|
+
echo ""
|
|
273
|
+
echo "--- Pre-run setup (once) ---"
|
|
274
|
+
echo ""
|
|
275
|
+
echo " 1. Export the Agent Teams flag:"
|
|
276
|
+
echo " export CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1"
|
|
277
|
+
echo ""
|
|
278
|
+
echo " 2. Create the scratch TypeScript file for the test task:"
|
|
279
|
+
echo " mkdir -p src/scratch"
|
|
280
|
+
echo " echo 'const x: number = \"not-a-number\";' > src/scratch/h3-test.ts"
|
|
281
|
+
echo ""
|
|
282
|
+
echo "--- Per-run procedure (repeat 3 times) ---"
|
|
283
|
+
echo ""
|
|
284
|
+
echo " Run N (replace N with 1, 2, 3):"
|
|
285
|
+
echo ""
|
|
286
|
+
echo " Step 1. Launch Claude Code in team lead mode:"
|
|
287
|
+
echo " claude (with CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 in env)"
|
|
288
|
+
echo ""
|
|
289
|
+
echo " Step 2. In the Claude Code session, use /team to configure the team:"
|
|
290
|
+
echo " - Team name: ${TEAM_NAME}"
|
|
291
|
+
echo " - Spawn 1 teammate (e.g., named 'impl-agent')"
|
|
292
|
+
echo " - Attach the TaskCompleted hook: 'npm run typecheck' (exit-2 blocks)"
|
|
293
|
+
echo " Reference hooks config: ${TEAM_DIR}/hooks.json"
|
|
294
|
+
echo ""
|
|
295
|
+
echo " Step 3. Assign the teammate the H3 test task:"
|
|
296
|
+
echo " 'Implement src/scratch/h3-test.ts — it currently has a TypeScript error."
|
|
297
|
+
echo " The task is complete when typecheck passes. Task ID: h3-ts-error-task.'"
|
|
298
|
+
echo " Reference task definition: ${TEAM_DIR}/h3-test-task.json"
|
|
299
|
+
echo ""
|
|
300
|
+
echo " Step 4. Observe TaskCompleted hook behavior:"
|
|
301
|
+
echo " - Hook fires 'npm run typecheck'"
|
|
302
|
+
echo " - Does the hook exit 2? (typecheck should fail on the deliberate error)"
|
|
303
|
+
echo " - Is the task marked 'blocked' (not 'completed') in the task list?"
|
|
304
|
+
echo " - Does the teammate receive the typecheck error output as feedback?"
|
|
305
|
+
echo ""
|
|
306
|
+
echo " Step 5. Observe teammate correction:"
|
|
307
|
+
echo " - Does the teammate read the feedback and correct src/scratch/h3-test.ts?"
|
|
308
|
+
echo " - Does the teammate retry task completion after correction?"
|
|
309
|
+
echo " - Does the hook exit 0 on the corrected file?"
|
|
310
|
+
echo " - Is the task marked 'completed'?"
|
|
311
|
+
echo ""
|
|
312
|
+
echo " Step 6. Log results:"
|
|
313
|
+
echo " Edit ${LOG_TEMPLATE_PATH} and fill in row N with observed values."
|
|
314
|
+
echo ""
|
|
315
|
+
echo "--- Promotion criteria (from ADR 0002) ---"
|
|
316
|
+
echo ""
|
|
317
|
+
echo " PASS: All 3 runs show hook_exit_code=2, blocked=true, feedback_delivered=true"
|
|
318
|
+
echo " → H3 PASS → Agent Teams backend spike proceeds (#484)"
|
|
319
|
+
echo ""
|
|
320
|
+
echo " FAIL: Any run shows blocked=false OR feedback_delivered=false"
|
|
321
|
+
echo " → H3 FAIL → Spike closed won't-do, ADR 0002 collapses to Stay"
|
|
322
|
+
echo ""
|
|
323
|
+
echo " After recording results, update \"Agent Teams H3 Hook-Seam Test — Empirical Research Note\""
|
|
324
|
+
echo " (#484; archived in the private Meta-Vault)"
|
|
325
|
+
echo " § Results and § Status with the outcome."
|
|
326
|
+
echo ""
|
|
327
|
+
echo "--- Cleanup ---"
|
|
328
|
+
echo ""
|
|
329
|
+
echo " After all 3 runs:"
|
|
330
|
+
echo " rm -f src/scratch/h3-test.ts"
|
|
331
|
+
echo " # Team dir ${TEAM_DIR} can be left for H4 config-overwrite test"
|
|
332
|
+
echo ""
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
# ---------------------------------------------------------------------------
|
|
336
|
+
# Main
|
|
337
|
+
# ---------------------------------------------------------------------------
|
|
338
|
+
|
|
339
|
+
main() {
|
|
340
|
+
print_header
|
|
341
|
+
|
|
342
|
+
precondition_check || exit 1
|
|
343
|
+
echo ""
|
|
344
|
+
|
|
345
|
+
scaffold_team_dir || exit 2
|
|
346
|
+
echo ""
|
|
347
|
+
|
|
348
|
+
generate_log_template
|
|
349
|
+
echo ""
|
|
350
|
+
|
|
351
|
+
print_manual_procedure
|
|
352
|
+
|
|
353
|
+
echo "============================================================"
|
|
354
|
+
echo " Harness setup complete — ready for manual 3-run execution"
|
|
355
|
+
echo " Log template: ${LOG_TEMPLATE_PATH}"
|
|
356
|
+
echo " Team scaffold: ${TEAM_DIR}"
|
|
357
|
+
echo "============================================================"
|
|
358
|
+
echo ""
|
|
359
|
+
exit 0
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
main "$@"
|
|
Binary file
|