@tyroneross/build-loop 0.36.0 → 0.43.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/plugins/marketplace.json +2 -2
- package/.claude-plugin/marketplace.json +3 -3
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.cursor/rules/build-loop-surface.mdc +12 -11
- package/.cursor/rules/skill-index.mdc +33 -0
- package/AGENTS.md +213 -34
- package/README.md +99 -31
- package/agents/advisor.md +4 -4
- package/agents/alignment-checker.md +2 -2
- package/agents/architecture-scout.md +4 -4
- package/agents/build-orchestrator.md +38 -36
- package/agents/database-assessor.md +11 -5
- package/agents/design-contract-specialist.md +8 -8
- package/agents/fact-checker.md +13 -3
- package/agents/fix-critique.md +2 -2
- package/agents/independent-auditor.md +60 -7
- package/agents/leak-scanner.md +82 -0
- package/agents/overfitting-reviewer.md +2 -2
- package/agents/plan-critic.md +1 -1
- package/agents/promotion-reviewer.md +5 -5
- package/agents/retrospective-synthesizer.md +138 -35
- package/agents/scope-auditor.md +82 -11
- package/agents/security-reviewer.md +56 -2
- package/agents/self-improvement-architect.md +17 -3
- package/agents/transcript-pattern-miner.md +5 -5
- package/agents/ui-validator.md +1 -1
- package/bin/build-loop-debugger.js +143 -0
- package/bin/build-loop-install.js +1 -4
- package/bin/build-loop-load-probe.js +345 -0
- package/codex-skills/build-loop/SKILL.md +28 -6
- package/commands/feedback.md +37 -0
- package/dist/src/interactive-verifier.d.ts +1 -14
- package/dist/src/interactive-verifier.d.ts.map +1 -1
- package/dist/src/interactive-verifier.js +6 -113
- package/dist/src/interactive-verifier.js.map +1 -1
- package/dist/src/quality.d.ts +5 -0
- package/dist/src/quality.d.ts.map +1 -0
- package/dist/src/quality.js +81 -0
- package/dist/src/quality.js.map +1 -0
- package/dist/src/storage.d.ts.map +1 -1
- package/dist/src/storage.js +37 -3
- package/dist/src/storage.js.map +1 -1
- package/docs/agent-surface-policy.md +35 -31
- package/docs/memory-setup.md +19 -0
- package/hooks/git/pre-push +65 -4
- package/hooks/hooks.json +95 -38
- package/hooks/pre-commit +20 -1
- package/hooks/pre-edit-rally-point.sh +10 -3
- package/hooks/session-start-codex-hook-trust.sh +30 -0
- package/hooks/session-start-git-hooks.sh +3 -1
- package/hooks/session-start-rally-point.sh +52 -4
- package/hooks/session-start-worktree-gc.sh +47 -94
- package/hooks/stop-transcript-sweep.sh +173 -0
- package/hooks/test_closeout.sh +14 -2
- package/package.json +8 -7
- package/scripts/README.md +1 -1
- package/scripts/_paths.py +65 -0
- package/scripts/groundwork_exchange.py +1012 -0
- package/scripts/install_memory.py +33 -1
- package/scripts/lessons_index/ingest.py +13 -2
- package/scripts/lessons_index/query.py +36 -13
- package/scripts/memory_context/__init__.py +108 -14
- package/scripts/memory_graph/__init__.py +5 -1
- package/scripts/project_resolver.py +42 -36
- package/scripts/sync_plugin_cache.py +37 -2
- package/skills/agent-rally-point/SKILL.md +46 -0
- package/skills/api-registry-bridge/SKILL.md +1 -1
- package/skills/architecture/dead/SKILL.md +1 -1
- package/skills/architecture/impact/SKILL.md +1 -1
- package/skills/architecture/review/SKILL.md +1 -1
- package/skills/architecture/rules/SKILL.md +3 -3
- package/skills/architecture/scan/SKILL.md +1 -1
- package/skills/architecture/trace/SKILL.md +1 -1
- package/skills/attribution-standard/SKILL.md +6 -6
- package/skills/auto-decision-capture/SKILL.md +31 -2
- package/skills/auto-finding-capture/SKILL.md +28 -1
- package/skills/build-loop/SKILL.md +131 -23
- package/skills/build-loop/fallbacks.md +16 -21
- package/skills/build-loop/phases/ui-validation.md +2 -2
- package/skills/build-loop/references/advisor-dispatch-ladder.md +1 -1
- package/skills/build-loop/references/apple-native-planning.md +1 -1
- package/skills/build-loop/references/autonomous-and-per-commit-modes.md +11 -5
- package/skills/build-loop/references/autonomy-dashboard.md +115 -0
- package/skills/build-loop/references/capability-routing.md +24 -2
- package/skills/build-loop/references/coordination.md +24 -6
- package/skills/build-loop/references/experiment-results-template.md +15 -3
- package/skills/build-loop/references/leadership.md +1 -1
- package/skills/build-loop/references/memory.md +14 -3
- package/skills/build-loop/references/modular-systems-pack.md +8 -0
- package/skills/build-loop/references/output-style.md +86 -0
- package/skills/build-loop/references/phase-1-assess.md +102 -2
- package/skills/build-loop/references/phase-2-plan.md +9 -1
- package/skills/build-loop/references/phase-3-execute.md +5 -2
- package/skills/build-loop/references/phase-4-review.md +85 -8
- package/skills/build-loop/references/phase-5-iterate.md +76 -8
- package/skills/build-loop/references/phase-6-learn.md +10 -17
- package/skills/build-loop/references/privileged-request-broker.md +254 -0
- package/skills/build-loop/references/resource-aware-execution.md +183 -0
- package/skills/build-loop/references/self-recursive-dev.md +2 -2
- package/skills/build-loop/references/status-output-format.md +207 -0
- package/skills/build-loop/references/verify-dispatch.md +56 -2
- package/skills/building-with-deepagents/SKILL.md +1 -1
- package/skills/claim-scope/SKILL.md +185 -0
- package/skills/color-engine/SKILL.md +103 -0
- package/skills/color-engine/_core.py +464 -0
- package/skills/color-engine/color_engine.py +175 -0
- package/skills/cost-rca/SKILL.md +61 -0
- package/skills/data-plane-worktrees/SKILL.md +139 -0
- package/skills/data-plane-worktrees/agents/openai.yaml +4 -0
- package/skills/database-practice/SKILL.md +200 -0
- package/skills/database-practice/references/diagnostic-queries.sql +126 -0
- package/skills/database-practice/references/vector-and-graph-tuning.md +208 -0
- package/skills/database-practice/scripts/db_table_map.py +1244 -0
- package/skills/database-practice/scripts/test_db_table_map.py +514 -0
- package/skills/debug-loop/SKILL.md +36 -6
- package/skills/debugging-memory/SKILL.md +32 -430
- package/skills/debugging-memory/references/pattern-extraction.md +4 -4
- package/skills/debugging-memory/references/search.md +32 -120
- package/skills/debugging-memory/references/store.md +32 -126
- package/skills/debugging-memory/references/subagent-integration.md +1 -1
- package/skills/decision-queue/SKILL.md +251 -0
- package/skills/decision-queue/assets/template.html +1242 -0
- package/skills/decision-queue/references/example-large-queue-batching.md +164 -0
- package/skills/decision-queue/scripts/regen_template_constants.py +160 -0
- package/skills/defenseclaw-bridge/SKILL.md +2 -2
- package/skills/defenseclaw-bridge/references/dc-config-mapping.md +2 -9
- package/skills/drain-proposals/SKILL.md +53 -0
- package/skills/focused-loop-builder/SKILL.md +31 -0
- package/skills/focused-loop-builder/references/spec-format.md +27 -0
- package/skills/handoff/SKILL.md +169 -8
- package/skills/ibr-bridge/SKILL.md +4 -1
- package/skills/knowledge/SKILL.md +26 -14
- package/skills/knowledge/references/review-mode.md +2 -3
- package/skills/knowledge/templates/madr-minimal.md +1 -1
- package/skills/mcp-builder/SKILL.md +1 -1
- package/skills/model-bakeoff/SKILL.md +48 -10
- package/skills/model-tiering/SKILL.md +92 -31
- package/skills/native-ax-driver/SKILL.md +38 -5
- package/skills/native-ax-driver/scripts/native_driver.py +278 -22
- package/skills/native-ax-driver/scripts/test_native_driver.py +227 -0
- package/skills/optimize/SKILL.md +1 -1
- package/skills/plugin-builder/SKILL.md +48 -1
- package/skills/plugin-builder/references/build-loop-phase-guidance.md +3 -4
- package/skills/plugin-builder/references/distribution.md +13 -2
- package/skills/plugin-builder/references/plugin-hygiene-lessons.md +2 -2
- package/skills/plugin-tests/SKILL.md +2 -2
- package/skills/recursive-retrospective/SKILL.md +1 -1
- package/skills/repo-closeout/SKILL.md +17 -0
- package/skills/repo-closeout/agents/openai.yaml +4 -0
- package/skills/repo-maintenance/SKILL.md +179 -0
- package/skills/repo-maintenance/agents/openai.yaml +4 -0
- package/skills/repo-maintenance/references/pre-public-hygiene.md +134 -0
- package/skills/repo-maintenance/references/repository-taxonomy.md +161 -0
- package/skills/repo-maintenance/references/safety-protocol.md +106 -0
- package/skills/repo-maintenance/references/stack-profiles.md +138 -0
- package/skills/repo-maintenance/scripts/audit_repo_maintenance.py +1198 -0
- package/skills/repo-maintenance/scripts/test_audit_repo_maintenance.py +506 -0
- package/skills/repository-intelligence/SKILL.md +189 -0
- package/skills/repository-intelligence/agents/openai.yaml +4 -0
- package/skills/repository-intelligence/references/assessment-rubric.md +88 -0
- package/skills/repository-intelligence/scripts/repository_inventory.py +347 -0
- package/skills/research/SKILL.md +12 -2
- package/skills/root-cause-analysis/SKILL.md +1 -1
- package/skills/runtime-parity-verification/SKILL.md +36 -1
- package/skills/security-methodology/SKILL.md +23 -10
- package/skills/security-methodology/references/agentic-handoff-templates.md +220 -0
- package/skills/security-methodology/references/cross-source-matrix.md +1 -1
- package/skills/security-methodology/references/owasp-agentic-top-10.md +1 -1
- package/skills/security-scan/SKILL.md +55 -15
- package/skills/self-improve/SKILL.md +70 -50
- package/skills/silent-assumptions/SKILL.md +341 -0
- package/skills/silent-assumptions/references/elicitation-detectors.md +342 -0
- package/skills/spec-writing/SKILL.md +128 -24
- package/skills/spec-writing/scripts/check_checklist.py +114 -15
- package/skills/ui-design/SKILL.md +6 -4
- package/skills/ui-design/references/color-engine.md +132 -0
- package/skills/ui-design/references/design-preferences-from-owned-apps.md +8 -8
- package/skills/ui-design/references/ui-guidance-sources.md +1 -1
- package/skills/ui-design/references/universal-design-principles.alt.md +2 -2
- package/plugin-artifacts/codex/.codex-plugin/plugin.json +0 -41
- package/plugin-artifacts/codex/AGENTS.md +0 -560
- package/plugin-artifacts/codex/BUILD-ARTIFACT.md +0 -5
- package/plugin-artifacts/codex/LICENSE +0 -202
- package/plugin-artifacts/codex/README.md +0 -313
- package/plugin-artifacts/codex/assets/build-loop-plugin-icon.png +0 -0
- package/plugin-artifacts/codex/docs/agent-surface-policy.md +0 -63
- package/plugin-artifacts/codex/references/advisor-dispatch-ladder.md +0 -62
- package/plugin-artifacts/codex/references/agent-role-taxonomy.md +0 -135
- package/plugin-artifacts/codex/references/autonomous-and-per-commit-modes.md +0 -161
- package/plugin-artifacts/codex/references/autonomy-config.md +0 -231
- package/plugin-artifacts/codex/references/backlog-system.md +0 -285
- package/plugin-artifacts/codex/references/capability-routing.md +0 -231
- package/plugin-artifacts/codex/references/codex-subagents.md +0 -106
- package/plugin-artifacts/codex/references/coordination-file-template.md +0 -181
- package/plugin-artifacts/codex/references/coordination-rules.md +0 -552
- package/plugin-artifacts/codex/references/dogfood-reload-checkpoint.md +0 -112
- package/plugin-artifacts/codex/references/halt-and-ask-protocol.md +0 -102
- package/plugin-artifacts/codex/references/implementer-envelope-schema.md +0 -302
- package/plugin-artifacts/codex/references/intent-capability-pack.md +0 -257
- package/plugin-artifacts/codex/references/intent-exploration-prompts.md +0 -96
- package/plugin-artifacts/codex/references/leadership.md +0 -72
- package/plugin-artifacts/codex/references/memory-systems.md +0 -261
- package/plugin-artifacts/codex/references/memory.md +0 -313
- package/plugin-artifacts/codex/references/model-tier-mapping.md +0 -296
- package/plugin-artifacts/codex/references/modular-systems-pack.md +0 -96
- package/plugin-artifacts/codex/references/phase-1-assess.md +0 -249
- package/plugin-artifacts/codex/references/phase-2-plan.md +0 -86
- package/plugin-artifacts/codex/references/phase-3-execute.md +0 -49
- package/plugin-artifacts/codex/references/phase-4-review.md +0 -341
- package/plugin-artifacts/codex/references/phase-5-iterate.md +0 -72
- package/plugin-artifacts/codex/references/phase-6-learn.md +0 -58
- package/plugin-artifacts/codex/references/recent-design-structures.md +0 -274
- package/plugin-artifacts/codex/references/research-trigger-policy.md +0 -140
- package/plugin-artifacts/codex/references/runtime-smoke-triggers.md +0 -42
- package/plugin-artifacts/codex/references/self-review.md +0 -234
- package/plugin-artifacts/codex/references/single-writer-commit-protocol.md +0 -90
- package/plugin-artifacts/codex/references/task-capture-policy.md +0 -68
- package/plugin-artifacts/codex/references/ui-io-contract.md +0 -116
- package/plugin-artifacts/codex/references/ui-spotcheck-protocol.md +0 -65
- package/plugin-artifacts/codex/references/verify-dispatch.md +0 -85
- package/plugin-artifacts/codex/skills/build-loop/SKILL.md +0 -381
- package/plugin-artifacts/codex/skills/build-loop/detect-plugins.mjs +0 -82
- package/plugin-artifacts/codex/skills/build-loop/eval-guide.md +0 -65
- package/plugin-artifacts/codex/skills/build-loop/fallbacks.md +0 -549
- package/plugin-artifacts/codex/skills/build-loop/phases/fact-check.md +0 -42
- package/plugin-artifacts/codex/skills/build-loop/phases/ui-validation.md +0 -267
- package/plugin-artifacts/codex/skills/build-loop/references/advisor-dispatch-ladder.md +0 -62
- package/plugin-artifacts/codex/skills/build-loop/references/apple-native-planning.md +0 -439
- package/plugin-artifacts/codex/skills/build-loop/references/autonomous-and-per-commit-modes.md +0 -161
- package/plugin-artifacts/codex/skills/build-loop/references/capability-routing.md +0 -231
- package/plugin-artifacts/codex/skills/build-loop/references/codex-subagents.md +0 -106
- package/plugin-artifacts/codex/skills/build-loop/references/coordination.md +0 -161
- package/plugin-artifacts/codex/skills/build-loop/references/correction-aware-capture.md +0 -177
- package/plugin-artifacts/codex/skills/build-loop/references/experiment-results-template.md +0 -101
- package/plugin-artifacts/codex/skills/build-loop/references/independent-auditor.md +0 -72
- package/plugin-artifacts/codex/skills/build-loop/references/intent-capability-pack.md +0 -257
- package/plugin-artifacts/codex/skills/build-loop/references/intent-exploration-prompts.md +0 -96
- package/plugin-artifacts/codex/skills/build-loop/references/leadership.md +0 -72
- package/plugin-artifacts/codex/skills/build-loop/references/memory.md +0 -313
- package/plugin-artifacts/codex/skills/build-loop/references/modular-systems-pack.md +0 -96
- package/plugin-artifacts/codex/skills/build-loop/references/output-style.md +0 -222
- package/plugin-artifacts/codex/skills/build-loop/references/pay-it-forward-arch.md +0 -98
- package/plugin-artifacts/codex/skills/build-loop/references/phase-1-assess.md +0 -249
- package/plugin-artifacts/codex/skills/build-loop/references/phase-2-plan.md +0 -86
- package/plugin-artifacts/codex/skills/build-loop/references/phase-3-execute.md +0 -49
- package/plugin-artifacts/codex/skills/build-loop/references/phase-4-review.md +0 -341
- package/plugin-artifacts/codex/skills/build-loop/references/phase-5-iterate.md +0 -72
- package/plugin-artifacts/codex/skills/build-loop/references/phase-6-learn.md +0 -58
- package/plugin-artifacts/codex/skills/build-loop/references/recent-design-structures.md +0 -274
- package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/ASSESSMENT.md +0 -85
- package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/STANDALONE_TEST_RUN.md +0 -149
- package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/01-simple-bugfix.md +0 -32
- package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/02-ui-build-with-iteration.md +0 -48
- package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/03-multi-failure-escalation.md +0 -60
- package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/04-ui-build-ibr-absent.md +0 -51
- package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/05-refactor-navgator-absent.md +0 -71
- package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/06-recurring-bug-debugger-absent.md +0 -52
- package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/trace-comparison.md +0 -202
- package/plugin-artifacts/codex/skills/build-loop/references/self-recursive-dev.md +0 -77
- package/plugin-artifacts/codex/skills/build-loop/references/self-review.md +0 -234
- package/plugin-artifacts/codex/skills/build-loop/references/ui-io-contract.md +0 -116
- package/plugin-artifacts/codex/skills/build-loop/references/verify-dispatch.md +0 -85
- package/plugin-artifacts/codex/skills/build-loop/scanners/audit-design-rules.mjs +0 -476
- package/plugin-artifacts/codex/skills/build-loop/scanners/require-visual-evidence.mjs +0 -239
- package/plugin-artifacts/codex/skills/build-loop/templates/backlog-item.md +0 -35
- package/plugin-artifacts/codex/skills/build-loop/templates/codex-worker-prompt.md +0 -100
- package/plugin-artifacts/codex/skills/build-loop/templates/ui-subagent-prompt.md +0 -179
- package/plugin-artifacts/codex/skills/build-loop/templates/ux-fix-plan.md +0 -40
- package/scripts/build_codex_plugin_artifact.py +0 -321
package/hooks/hooks.json
CHANGED
|
@@ -7,57 +7,66 @@
|
|
|
7
7
|
{
|
|
8
8
|
"type": "command",
|
|
9
9
|
"command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/session-start-architecture.sh\" </dev/null >/dev/null 2>&1; exit 0",
|
|
10
|
-
"timeout":
|
|
10
|
+
"timeout": 2
|
|
11
11
|
},
|
|
12
12
|
{
|
|
13
13
|
"type": "command",
|
|
14
14
|
"command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/session-start-retrieval.sh\" </dev/null >/dev/null 2>&1; exit 0",
|
|
15
|
-
"timeout":
|
|
15
|
+
"timeout": 2
|
|
16
16
|
},
|
|
17
17
|
{
|
|
18
18
|
"type": "command",
|
|
19
|
-
"command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/session-start-rally-point.sh\"
|
|
20
|
-
"timeout":
|
|
19
|
+
"command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/session-start-rally-point.sh\" 2>/dev/null; exit 0",
|
|
20
|
+
"timeout": 2
|
|
21
21
|
},
|
|
22
22
|
{
|
|
23
23
|
"type": "command",
|
|
24
24
|
"command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/session-start-worktree-gc.sh\" </dev/null >/dev/null 2>&1; exit 0",
|
|
25
|
-
"timeout":
|
|
25
|
+
"timeout": 2
|
|
26
26
|
},
|
|
27
27
|
{
|
|
28
28
|
"type": "command",
|
|
29
29
|
"command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/session-start-git-hooks.sh\" </dev/null >/dev/null 2>&1; exit 0",
|
|
30
|
-
"timeout":
|
|
30
|
+
"timeout": 2
|
|
31
31
|
},
|
|
32
32
|
{
|
|
33
33
|
"type": "command",
|
|
34
34
|
"command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/session-start-plugin-drift.sh\" </dev/null >/dev/null 2>&1; exit 0",
|
|
35
|
-
"timeout":
|
|
35
|
+
"timeout": 2
|
|
36
36
|
},
|
|
37
37
|
{
|
|
38
38
|
"type": "command",
|
|
39
39
|
"command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/session-start-plugin-heal.sh\" </dev/null >/dev/null 2>&1; exit 0",
|
|
40
|
-
"timeout":
|
|
40
|
+
"timeout": 2
|
|
41
41
|
},
|
|
42
42
|
{
|
|
43
43
|
"type": "command",
|
|
44
44
|
"command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/session-start-memory.sh\" </dev/null >/dev/null 2>&1; exit 0",
|
|
45
|
-
"timeout":
|
|
45
|
+
"timeout": 6
|
|
46
46
|
},
|
|
47
47
|
{
|
|
48
48
|
"type": "command",
|
|
49
49
|
"command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/session-start-closeout.sh\" </dev/null >/dev/null 2>&1; exit 0",
|
|
50
|
-
"timeout":
|
|
50
|
+
"timeout": 3
|
|
51
51
|
},
|
|
52
52
|
{
|
|
53
53
|
"type": "command",
|
|
54
54
|
"command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/closeout.sh\" session-start </dev/null 2>/dev/null; exit 0",
|
|
55
|
-
"timeout":
|
|
55
|
+
"timeout": 3
|
|
56
56
|
},
|
|
57
57
|
{
|
|
58
58
|
"type": "command",
|
|
59
59
|
"command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/session-start-extensions.sh\" </dev/null 2>/dev/null; exit 0",
|
|
60
|
-
"timeout":
|
|
60
|
+
"timeout": 2
|
|
61
|
+
}
|
|
62
|
+
]
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"hooks": [
|
|
66
|
+
{
|
|
67
|
+
"type": "command",
|
|
68
|
+
"command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/session-start-codex-hook-trust.sh\" </dev/null 2>/dev/null || printf '{}'",
|
|
69
|
+
"timeout": 5
|
|
61
70
|
}
|
|
62
71
|
]
|
|
63
72
|
}
|
|
@@ -69,7 +78,7 @@
|
|
|
69
78
|
{
|
|
70
79
|
"type": "command",
|
|
71
80
|
"command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/route-guard.sh\" prompt-submit 2>/dev/null || printf '{}'",
|
|
72
|
-
"timeout":
|
|
81
|
+
"timeout": 3
|
|
73
82
|
}
|
|
74
83
|
]
|
|
75
84
|
}
|
|
@@ -81,7 +90,7 @@
|
|
|
81
90
|
{
|
|
82
91
|
"type": "command",
|
|
83
92
|
"command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/route-guard.sh\" pre-skill 2>/dev/null || printf '{}'",
|
|
84
|
-
"timeout":
|
|
93
|
+
"timeout": 3
|
|
85
94
|
}
|
|
86
95
|
]
|
|
87
96
|
},
|
|
@@ -91,12 +100,12 @@
|
|
|
91
100
|
{
|
|
92
101
|
"type": "command",
|
|
93
102
|
"command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/pre-edit-architecture.sh\" >/dev/null 2>&1; exit 0",
|
|
94
|
-
"timeout":
|
|
103
|
+
"timeout": 2
|
|
95
104
|
},
|
|
96
105
|
{
|
|
97
106
|
"type": "command",
|
|
98
107
|
"command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/pre-edit-rally-point.sh\"; exit 0",
|
|
99
|
-
"timeout":
|
|
108
|
+
"timeout": 2
|
|
100
109
|
}
|
|
101
110
|
]
|
|
102
111
|
},
|
|
@@ -106,12 +115,22 @@
|
|
|
106
115
|
{
|
|
107
116
|
"type": "command",
|
|
108
117
|
"command": "root=\"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}\"; hook=\"$root/scripts/hooks/pre_bash_dispatch.sh\"; if [ -x \"$hook\" ]; then \"$hook\"; else printf '{}'; fi",
|
|
109
|
-
"timeout":
|
|
118
|
+
"timeout": 9
|
|
110
119
|
},
|
|
111
120
|
{
|
|
112
121
|
"type": "command",
|
|
113
122
|
"command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/pre-edit-rally-point.sh\"; exit 0",
|
|
114
|
-
"timeout":
|
|
123
|
+
"timeout": 2
|
|
124
|
+
}
|
|
125
|
+
]
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"matcher": "",
|
|
129
|
+
"hooks": [
|
|
130
|
+
{
|
|
131
|
+
"type": "command",
|
|
132
|
+
"command": "python3 \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/scripts/tool_trace.py\" --workdir \"$CLAUDE_PROJECT_DIR\" hook --phase start >/dev/null 2>&1 || true",
|
|
133
|
+
"timeout": 1
|
|
115
134
|
}
|
|
116
135
|
]
|
|
117
136
|
}
|
|
@@ -123,12 +142,22 @@
|
|
|
123
142
|
{
|
|
124
143
|
"type": "command",
|
|
125
144
|
"command": "[ -f .build-loop/state.json ] || exit 0; python3 -c \"import json,sys; s=json.load(open('.build-loop/state.json')); p7=s.get('phases',{}).get('fact_check',{}).get('completed',False); active=s.get('active',False); sys.exit(0 if (not active or p7) else 1)\" 2>/dev/null && exit 0; echo \"$TOOL_INPUT\" | grep -qE '\\b(git\\s+push|npm\\s+publish|vercel\\s+deploy|gh\\s+release)\\b' && echo 'Build loop Phase 7 (fact-check) has not completed. Run fact-check before deploying.'; exit 0",
|
|
126
|
-
"timeout":
|
|
145
|
+
"timeout": 3
|
|
127
146
|
},
|
|
128
147
|
{
|
|
129
148
|
"type": "command",
|
|
130
149
|
"command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/post-push-closeout.sh\" </dev/null >/dev/null 2>&1; exit 0",
|
|
131
|
-
"timeout":
|
|
150
|
+
"timeout": 2
|
|
151
|
+
}
|
|
152
|
+
]
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
"matcher": "",
|
|
156
|
+
"hooks": [
|
|
157
|
+
{
|
|
158
|
+
"type": "command",
|
|
159
|
+
"command": "python3 \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/scripts/tool_trace.py\" --workdir \"$CLAUDE_PROJECT_DIR\" hook --phase end >/dev/null 2>&1 || true",
|
|
160
|
+
"timeout": 1
|
|
132
161
|
}
|
|
133
162
|
]
|
|
134
163
|
}
|
|
@@ -139,43 +168,71 @@
|
|
|
139
168
|
"hooks": [
|
|
140
169
|
{
|
|
141
170
|
"type": "command",
|
|
142
|
-
"command": "
|
|
143
|
-
"timeout":
|
|
171
|
+
"command": "python3 \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/scripts/state_finalize.py\" --workdir \"$CLAUDE_PROJECT_DIR\" --mark-incomplete-as-crashed </dev/null >/dev/null 2>&1; printf '{}'",
|
|
172
|
+
"timeout": 2
|
|
144
173
|
},
|
|
145
174
|
{
|
|
146
175
|
"type": "command",
|
|
147
|
-
"command": "
|
|
148
|
-
"timeout":
|
|
176
|
+
"command": "root=\"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}\"; hook=\"$root/scripts/hooks/stop_finalize.sh\"; if [ -x \"$hook\" ]; then \"$hook\"; else printf '{}'; fi",
|
|
177
|
+
"timeout": 30
|
|
149
178
|
},
|
|
150
179
|
{
|
|
151
180
|
"type": "command",
|
|
152
|
-
"command": "
|
|
153
|
-
"timeout":
|
|
154
|
-
}
|
|
181
|
+
"command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/closeout.sh\" stop 2>/dev/null; exit 0",
|
|
182
|
+
"timeout": 6
|
|
183
|
+
}
|
|
184
|
+
]
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
"matcher": "",
|
|
188
|
+
"hooks": [
|
|
155
189
|
{
|
|
156
190
|
"type": "command",
|
|
157
|
-
"command": "python3 \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/scripts/
|
|
158
|
-
"timeout":
|
|
159
|
-
}
|
|
191
|
+
"command": "if [ -f \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/scripts/commit_state_check.py\" ]; then python3 \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/scripts/commit_state_check.py\" --workdir \"${CLAUDE_PROJECT_DIR}\" --hook; else printf '{}'; fi",
|
|
192
|
+
"timeout": 5
|
|
193
|
+
}
|
|
194
|
+
]
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
"matcher": "",
|
|
198
|
+
"hooks": [
|
|
160
199
|
{
|
|
161
200
|
"type": "command",
|
|
162
|
-
"command": "
|
|
163
|
-
"timeout":
|
|
164
|
-
}
|
|
201
|
+
"command": "python3 \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/scripts/tool_trace.py\" --workdir \"$CLAUDE_PROJECT_DIR\" ingest >/dev/null 2>&1 || true; printf '{}'",
|
|
202
|
+
"timeout": 5
|
|
203
|
+
}
|
|
204
|
+
]
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
"hooks": [
|
|
165
208
|
{
|
|
166
209
|
"type": "command",
|
|
167
|
-
"command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/
|
|
168
|
-
"timeout":
|
|
210
|
+
"command": "bash \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/hooks/stop-transcript-sweep.sh\" all 2>/dev/null || printf '{}'",
|
|
211
|
+
"timeout": 5
|
|
169
212
|
}
|
|
170
213
|
]
|
|
171
|
-
}
|
|
214
|
+
}
|
|
215
|
+
],
|
|
216
|
+
"SessionEnd": [
|
|
172
217
|
{
|
|
173
218
|
"matcher": "",
|
|
174
219
|
"hooks": [
|
|
175
220
|
{
|
|
176
221
|
"type": "command",
|
|
177
|
-
"command": "
|
|
178
|
-
"timeout":
|
|
222
|
+
"command": "root=\"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}\"; s=\"$root/scripts/hooks/session_end_retro_sweep.py\"; tp=$(python3 -c 'import sys,json;print(json.load(sys.stdin).get(\"transcript_path\",\"\"))' 2>/dev/null); if [ -n \"$tp\" ] && [ -f \"$s\" ]; then nohup python3 \"$s\" \"$tp\" </dev/null >/dev/null 2>&1 & fi; exit 0",
|
|
223
|
+
"timeout": 5
|
|
224
|
+
}
|
|
225
|
+
]
|
|
226
|
+
}
|
|
227
|
+
],
|
|
228
|
+
"PostToolUseFailure": [
|
|
229
|
+
{
|
|
230
|
+
"matcher": "",
|
|
231
|
+
"hooks": [
|
|
232
|
+
{
|
|
233
|
+
"type": "command",
|
|
234
|
+
"command": "python3 \"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/scripts/tool_trace.py\" --workdir \"$CLAUDE_PROJECT_DIR\" hook --phase error >/dev/null 2>&1 || true",
|
|
235
|
+
"timeout": 1
|
|
179
236
|
}
|
|
180
237
|
]
|
|
181
238
|
}
|
package/hooks/pre-commit
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/bin/sh
|
|
2
|
-
# Public-repo hygiene pre-commit hook.
|
|
2
|
+
# Public-repo hygiene and independent-audit pre-commit hook.
|
|
3
3
|
#
|
|
4
4
|
# build-loop is open source. This hook blocks a commit that stages a
|
|
5
5
|
# private app slug (see scripts/check_private_slugs.py for the editable
|
|
@@ -26,4 +26,23 @@ if [ -f "$RUNTIME_MEMORY_GUARD" ]; then
|
|
|
26
26
|
fi
|
|
27
27
|
# --- END private-slug-guard pre-commit ---
|
|
28
28
|
|
|
29
|
+
# --- BEGIN portability-guard pre-commit ---
|
|
30
|
+
# Blocks a commit that ships a maintainer-machine path to installed users.
|
|
31
|
+
# Runs from the repo (no secret config needed, unlike the slug guard), so
|
|
32
|
+
# there is no .git/hooks copy to desync. See scripts/check_portability.py.
|
|
33
|
+
PORTABILITY_GUARD="$RALLY_POINT_TOPLEVEL/scripts/check_portability.py"
|
|
34
|
+
if [ -f "$PORTABILITY_GUARD" ]; then
|
|
35
|
+
python3 "$PORTABILITY_GUARD" || exit 1
|
|
36
|
+
fi
|
|
37
|
+
# --- END portability-guard pre-commit ---
|
|
38
|
+
|
|
39
|
+
# --- BEGIN independent-audit pre-commit ---
|
|
40
|
+
# Covers manual, Codex, IDE, and other commit paths. The auditor blocks only
|
|
41
|
+
# deterministic integrity failures; its advisory packet remains visible.
|
|
42
|
+
INDEPENDENT_AUDIT="$RALLY_POINT_TOPLEVEL/scripts/audit_before_commit.py"
|
|
43
|
+
if [ -f "$INDEPENDENT_AUDIT" ]; then
|
|
44
|
+
python3 "$INDEPENDENT_AUDIT" || exit $?
|
|
45
|
+
fi
|
|
46
|
+
# --- END independent-audit pre-commit ---
|
|
47
|
+
|
|
29
48
|
exit 0
|
|
@@ -34,8 +34,7 @@ PKG="$SCRIPT_DIR/../scripts/rally_point"
|
|
|
34
34
|
# the payload is forwarded to Python via the environment.
|
|
35
35
|
STDIN_JSON=""
|
|
36
36
|
if [ ! -t 0 ]; then
|
|
37
|
-
STDIN_JSON=$(
|
|
38
|
-
STDIN_JSON=$(printf '%s' "$STDIN_JSON" | head -c 65536)
|
|
37
|
+
STDIN_JSON=$(head -c 65536 2>/dev/null || true)
|
|
39
38
|
fi
|
|
40
39
|
|
|
41
40
|
# Extract file_path (Edit/Write) and command (Bash) from the event JSON.
|
|
@@ -44,6 +43,7 @@ fi
|
|
|
44
43
|
# with NUL handling across portable awk/read.
|
|
45
44
|
FILE_PATH=""
|
|
46
45
|
TOOL_CMD=""
|
|
46
|
+
EVENT_SESSION_ID=""
|
|
47
47
|
if [ -n "$STDIN_JSON" ]; then
|
|
48
48
|
EXTRACTED=$(STDIN_JSON="$STDIN_JSON" python3 - <<'PYEOF' 2>/dev/null
|
|
49
49
|
import json, os, sys
|
|
@@ -55,22 +55,27 @@ except (ValueError, TypeError):
|
|
|
55
55
|
ti = (d.get("tool_input") or {}) if isinstance(d.get("tool_input"), dict) else {}
|
|
56
56
|
fp = ti.get("file_path") or ti.get("path") or ti.get("filename") or ""
|
|
57
57
|
cmd = ti.get("command") or ""
|
|
58
|
+
session_id = d.get("session_id") or ""
|
|
58
59
|
# Emit fp as base64 (single line, no newlines), then cmd as base64. The
|
|
59
60
|
# bash side decodes; this avoids embedded-newline parsing entirely.
|
|
60
61
|
import base64
|
|
61
62
|
b64 = lambda s: base64.b64encode(s.encode("utf-8", "replace")).decode("ascii") if s else ""
|
|
62
|
-
sys.stdout.write(b64(fp) + "\n" + b64(cmd) + "\n")
|
|
63
|
+
sys.stdout.write(b64(fp) + "\n" + b64(cmd) + "\n" + b64(session_id) + "\n")
|
|
63
64
|
PYEOF
|
|
64
65
|
)
|
|
65
66
|
if [ -n "$EXTRACTED" ]; then
|
|
66
67
|
FILE_PATH_B64=$(printf '%s\n' "$EXTRACTED" | sed -n '1p')
|
|
67
68
|
TOOL_CMD_B64=$(printf '%s\n' "$EXTRACTED" | sed -n '2p')
|
|
69
|
+
EVENT_SESSION_ID_B64=$(printf '%s\n' "$EXTRACTED" | sed -n '3p')
|
|
68
70
|
if [ -n "$FILE_PATH_B64" ]; then
|
|
69
71
|
FILE_PATH=$(printf '%s' "$FILE_PATH_B64" | base64 --decode 2>/dev/null || true)
|
|
70
72
|
fi
|
|
71
73
|
if [ -n "$TOOL_CMD_B64" ]; then
|
|
72
74
|
TOOL_CMD=$(printf '%s' "$TOOL_CMD_B64" | base64 --decode 2>/dev/null || true)
|
|
73
75
|
fi
|
|
76
|
+
if [ -n "$EVENT_SESSION_ID_B64" ]; then
|
|
77
|
+
EVENT_SESSION_ID=$(printf '%s' "$EVENT_SESSION_ID_B64" | base64 --decode 2>/dev/null || true)
|
|
78
|
+
fi
|
|
74
79
|
fi
|
|
75
80
|
fi
|
|
76
81
|
|
|
@@ -83,9 +88,11 @@ fi
|
|
|
83
88
|
# without polluting the terminal by default.
|
|
84
89
|
if [ "${BUILD_LOOP_RALLY_DEBUG:-0}" = "1" ]; then
|
|
85
90
|
python3 "$PKG/hooks.py" pre-edit --workdir "$WORKDIR" --tool claude_code \
|
|
91
|
+
--session-id "$EVENT_SESSION_ID" \
|
|
86
92
|
--file-path "$FILE_PATH" --command "$TOOL_CMD" || exit 0
|
|
87
93
|
else
|
|
88
94
|
python3 "$PKG/hooks.py" pre-edit --workdir "$WORKDIR" --tool claude_code \
|
|
95
|
+
--session-id "$EVENT_SESSION_ID" \
|
|
89
96
|
--file-path "$FILE_PATH" --command "$TOOL_CMD" 2>/dev/null || exit 0
|
|
90
97
|
fi
|
|
91
98
|
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
# Report Codex hooks that are registered but never trusted, so they cannot
|
|
4
|
+
# silently never run. Advisory: emits context only when there IS a gap, and
|
|
5
|
+
# always exits 0.
|
|
6
|
+
#
|
|
7
|
+
# WHY: Codex records hook trust in ~/.codex/config.toml keyed by ORDINAL
|
|
8
|
+
# POSITION. Nothing compared it to .codex/hooks.json, so on 2026-08-23 a sweep
|
|
9
|
+
# found 28 of 46 registered hooks across 10 repos had never been trusted --
|
|
10
|
+
# including one that had shipped in git 9 days earlier.
|
|
11
|
+
set +e
|
|
12
|
+
PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-${CLAUDE_PROJECT_DIR:-$PWD}}"
|
|
13
|
+
WORKDIR="${CLAUDE_PROJECT_DIR:-$PWD}"
|
|
14
|
+
CHECK="${PLUGIN_ROOT}/scripts/codex_hook_trust_check.py"
|
|
15
|
+
|
|
16
|
+
[ -f "$CHECK" ] || { printf '{}'; exit 0; }
|
|
17
|
+
[ -f "${WORKDIR}/.codex/hooks.json" ] || { printf '{}'; exit 0; }
|
|
18
|
+
command -v python3 >/dev/null 2>&1 || { printf '{}'; exit 0; }
|
|
19
|
+
|
|
20
|
+
REPORT="$(python3 "$CHECK" --workdir "$WORKDIR" 2>/dev/null)"
|
|
21
|
+
[ -n "$REPORT" ] || { printf '{}'; exit 0; }
|
|
22
|
+
|
|
23
|
+
REPORT="$REPORT" python3 -c '
|
|
24
|
+
import json, os
|
|
25
|
+
print(json.dumps({"hookSpecificOutput": {
|
|
26
|
+
"hookEventName": "SessionStart",
|
|
27
|
+
"additionalContext": os.environ.get("REPORT", ""),
|
|
28
|
+
}}))
|
|
29
|
+
' 2>/dev/null || printf '{}'
|
|
30
|
+
exit 0
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
# in one hook body — the test gate added per the 2026-06-29 RCA so new sessions get
|
|
6
6
|
# the prevent-before-merge control automatically) + the artifact-guard pre-commit segment
|
|
7
7
|
# (regenerate-and-restage checked-in artifacts; block undeclared third-party
|
|
8
|
-
# imports — chained so it coexists with the
|
|
8
|
+
# imports — chained so it coexists with the Rally Point hygiene and independent
|
|
9
|
+
# commit-audit segment).
|
|
9
10
|
# Skips silently when: not inside a git repo, Python unavailable, hook
|
|
10
11
|
# source not found, or a foreign (non-build-loop) pre-push is already
|
|
11
12
|
# installed (requires --force to overwrite; we never force on auto-install).
|
|
@@ -14,4 +15,5 @@ cd "${CLAUDE_PROJECT_DIR:-$PWD}" 2>/dev/null || exit 0
|
|
|
14
15
|
git rev-parse --git-dir >/dev/null 2>&1 || exit 0
|
|
15
16
|
python3 "${PLUGIN_ROOT}/scripts/install_git_hooks.py" --install >/dev/null 2>&1 || true
|
|
16
17
|
python3 "${PLUGIN_ROOT}/scripts/artifact_guard.py" --install-hook >/dev/null 2>&1 || true
|
|
18
|
+
python3 "${PLUGIN_ROOT}/scripts/rally_point/install_git_hook.py" --repo "$PWD" >/dev/null 2>&1 || true
|
|
17
19
|
exit 0
|
|
@@ -15,6 +15,36 @@ W="${CLAUDE_PROJECT_DIR:-$PWD}"
|
|
|
15
15
|
PKG="$(dirname "$D")/scripts/rally_point"
|
|
16
16
|
[ -d "$PKG" ] || exit 0
|
|
17
17
|
|
|
18
|
+
# Claude's hook event is the authoritative session identity. Do not depend on
|
|
19
|
+
# CLAUDE_SESSION_ID being exported: plugin hooks receive the same session_id on
|
|
20
|
+
# stdin at SessionStart, PreToolUse, and Stop. The shared Python resolver keeps
|
|
21
|
+
# explicit/event, environment, and process fallbacks identical for every path.
|
|
22
|
+
STDIN_JSON=""
|
|
23
|
+
if [ ! -t 0 ]; then
|
|
24
|
+
STDIN_JSON=$(head -c 65536 2>/dev/null || true)
|
|
25
|
+
fi
|
|
26
|
+
EVENT_SESSION_ID=""
|
|
27
|
+
if [ -n "$STDIN_JSON" ]; then
|
|
28
|
+
EVENT_SESSION_ID=$(STDIN_JSON="$STDIN_JSON" python3 - <<'PYEOF' 2>/dev/null
|
|
29
|
+
import json, os
|
|
30
|
+
try:
|
|
31
|
+
event = json.loads(os.environ.get("STDIN_JSON") or "{}")
|
|
32
|
+
except (TypeError, ValueError):
|
|
33
|
+
event = {}
|
|
34
|
+
value = event.get("session_id") if isinstance(event, dict) else ""
|
|
35
|
+
print(str(value or "").replace("\n", " ").replace("\t", " "), end="")
|
|
36
|
+
PYEOF
|
|
37
|
+
) || EVENT_SESSION_ID=""
|
|
38
|
+
fi
|
|
39
|
+
RALLY_HOOK_SESSION_ID=""
|
|
40
|
+
if [ -f "$PKG/actor_identity.py" ]; then
|
|
41
|
+
RALLY_HOOK_SESSION_ID=$(RALLY_OBSERVER_PID="${PPID:-0}" \
|
|
42
|
+
python3 "$PKG/actor_identity.py" --tool claude_code \
|
|
43
|
+
--session-id "$EVENT_SESSION_ID" --field session-id 2>/dev/null || true)
|
|
44
|
+
fi
|
|
45
|
+
[ -n "$RALLY_HOOK_SESSION_ID" ] || \
|
|
46
|
+
RALLY_HOOK_SESSION_ID="${EVENT_SESSION_ID:-${BUILD_LOOP_RALLY_SESSION_ID:-${CLAUDE_SESSION_ID:-${RALLY_AGENT_ID:-${RALLY_SESSION_ID:-claude-${PPID}}}}}}"
|
|
47
|
+
|
|
18
48
|
# Guard: if CLAUDE_PROJECT_DIR is unset and $PWD is not a git repo, the
|
|
19
49
|
# launch cwd is not a rally room — defer the join to pre-edit (operative
|
|
20
50
|
# repo resolution from the first Edit/Write/Bash). This is the no-op path.
|
|
@@ -27,15 +57,19 @@ fi
|
|
|
27
57
|
# Step 1: checkpoint_read restore line (verbose: surface delta if any).
|
|
28
58
|
# ``session-start-safe`` no-ops cleanly when the resolved workdir is not a
|
|
29
59
|
# git repo (belt-and-braces — the shell guard above already filters).
|
|
30
|
-
python3 "$PKG/hooks.py" session-start-safe --workdir "$W" --verbose
|
|
60
|
+
python3 "$PKG/hooks.py" session-start-safe --workdir "$W" --verbose \
|
|
61
|
+
--tool claude_code --session-id "$RALLY_HOOK_SESSION_ID" 2>/dev/null || true
|
|
31
62
|
|
|
32
63
|
# Step 2: probe announce + listen (fully detached watcher).
|
|
33
64
|
if [ "${BUILD_LOOP_RALLY_POINT_SKIP_WATCH:-}" = "1" ]; then
|
|
34
65
|
[ -f "$PKG/session_probe.py" ] && WORKDIR="$W" python3 "$PKG/session_probe.py" \
|
|
35
|
-
--workdir "$W" --tool claude_code --
|
|
66
|
+
--workdir "$W" --tool claude_code --session-id "$RALLY_HOOK_SESSION_ID" \
|
|
67
|
+
--mode hook >/dev/null 2>&1 || true
|
|
36
68
|
else
|
|
37
69
|
[ -f "$PKG/session_probe.py" ] && WORKDIR="$W" python3 "$PKG/session_probe.py" \
|
|
38
|
-
--workdir "$W" --tool claude_code --
|
|
70
|
+
--workdir "$W" --tool claude_code --session-id "$RALLY_HOOK_SESSION_ID" \
|
|
71
|
+
--mode hook --start-watch \
|
|
72
|
+
--watch-parent-pid "${PPID}" >/dev/null 2>&1 || true
|
|
39
73
|
fi
|
|
40
74
|
|
|
41
75
|
# Step 3: opportunistic reaper sweep — physical cleanup of over-TTL presence/claims/lead.
|
|
@@ -43,7 +77,8 @@ fi
|
|
|
43
77
|
[ -f "$PKG/reaper.py" ] && python3 "$PKG/reaper.py" --workdir "$W" --apply >/dev/null 2>&1 || true
|
|
44
78
|
|
|
45
79
|
# Step 4: advance cursor past probe's own writes (silent; same script, no VERBOSE).
|
|
46
|
-
python3 "$PKG/hooks.py" session-start-advance --workdir "$W"
|
|
80
|
+
python3 "$PKG/hooks.py" session-start-advance --workdir "$W" \
|
|
81
|
+
--tool claude_code --session-id "$RALLY_HOOK_SESSION_ID" 2>/dev/null || true
|
|
47
82
|
|
|
48
83
|
# Step 5: on-PATH-vs-pin rally version staleness guard (lane E-a). This is
|
|
49
84
|
# the control that would have caught the rally version-mismatch incident:
|
|
@@ -63,4 +98,17 @@ if command -v rally >/dev/null 2>&1; then
|
|
|
63
98
|
fi
|
|
64
99
|
fi
|
|
65
100
|
|
|
101
|
+
# Step 6: peer-on-same-workdir commit-collision WARN (lane EC-03 rca). Advisory +
|
|
102
|
+
# fail-open: warns (never blocks) when a peer session is active on THIS workdir —
|
|
103
|
+
# the precondition for the concurrent-write race (two writers on one checkout race
|
|
104
|
+
# on HEAD/index; commits land on the wrong branch). On any error this silently
|
|
105
|
+
# no-ops and NEVER affects the hook's exit code.
|
|
106
|
+
[ -f "$PKG/peer_collision.py" ] && python3 "$PKG/peer_collision.py" --workdir "$W" 1>/dev/null || true
|
|
107
|
+
|
|
108
|
+
# Step 7: orphan/stale-session NOTICE (lane EC-04 coord — notify half). Advisory +
|
|
109
|
+
# fail-open + READ-ONLY: a dry-run count of over-TTL sessions surfaced as a WARN.
|
|
110
|
+
# It never reaps (Step 3 already does that capability-gated); it only tells the
|
|
111
|
+
# human cleanup is pending. Prints only to stderr; exit 0 preserved.
|
|
112
|
+
[ -f "$PKG/orphan_notice.py" ] && python3 "$PKG/orphan_notice.py" --workdir "$W" 1>/dev/null || true
|
|
113
|
+
|
|
66
114
|
exit 0
|
|
@@ -1,105 +1,58 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
|
|
8
|
-
git rev-parse --git-dir >/dev/null 2>&1 || exit 0
|
|
9
|
-
R=".build-loop/worktree-gc-last.txt"
|
|
10
|
-
mkdir -p "$(dirname "$R")"
|
|
11
|
-
_bundle_done=0
|
|
3
|
+
# SessionStart worktree report. This hook never mutates Git.
|
|
4
|
+
#
|
|
5
|
+
# Destructive finalization requires a direct collapse_run/reaper invocation with
|
|
6
|
+
# explicit owner release. BUILDLOOP_GC_ACT is intentionally ignored: Stop is a
|
|
7
|
+
# turn boundary, and SessionStart cannot prove the prior terminal process exited.
|
|
12
8
|
|
|
13
|
-
|
|
14
|
-
# `rally sessions --json` returns a list of live sessions, collect their
|
|
15
|
-
# `cwd` paths so we can skip any worktree owned by an active session in
|
|
16
|
-
# addition to the path-prefix guard below. Rally owns its own worktree
|
|
17
|
-
# lifecycle; build-loop's GC must never reap a rally-owned worktree (force-
|
|
18
|
-
# removing it deletes the cwd of a live agent process and every subsequent
|
|
19
|
-
# hook fails with posix_spawn ENOENT). The path-prefix exclusion is the
|
|
20
|
-
# PRIMARY guard and works even when `rally` is not installed.
|
|
21
|
-
_rally_cwds=""
|
|
22
|
-
if command -v rally >/dev/null 2>&1; then
|
|
23
|
-
_rally_cwds=$(rally sessions --json 2>/dev/null \
|
|
24
|
-
| awk 'match($0, /"cwd"[[:space:]]*:[[:space:]]*"[^"]+"/){
|
|
25
|
-
s=substr($0,RSTART,RLENGTH);
|
|
26
|
-
sub(/^"cwd"[[:space:]]*:[[:space:]]*"/,"",s);
|
|
27
|
-
sub(/"$/,"",s);
|
|
28
|
-
print s
|
|
29
|
-
}' 2>/dev/null || true)
|
|
30
|
-
fi
|
|
9
|
+
set -u
|
|
31
10
|
|
|
32
|
-
{
|
|
33
|
-
|
|
11
|
+
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$PWD}"
|
|
12
|
+
cd "$PROJECT_DIR" 2>/dev/null || exit 0
|
|
13
|
+
git rev-parse --git-dir >/dev/null 2>&1 || exit 0
|
|
34
14
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
| awk '/^worktree /{p=$2} /^branch /{b=$2; sub("refs/heads/","",b); if(p && b){print p" "b}; p=""; b=""}' \
|
|
39
|
-
| while read -r path branch; do
|
|
40
|
-
[ "$branch" = main ] && continue
|
|
41
|
-
# Rally-owned worktrees are NEVER touched by build-loop's GC.
|
|
42
|
-
# Primary guard: path-prefix exclusion (works without rally on PATH).
|
|
43
|
-
case "$path" in
|
|
44
|
-
*/.rally/worktrees/*)
|
|
45
|
-
echo " SKIP:rally-owned $path branch=$branch"
|
|
46
|
-
continue
|
|
47
|
-
;;
|
|
48
|
-
esac
|
|
49
|
-
# Defense-in-depth: live rally session cwd cross-check.
|
|
50
|
-
if [ -n "$_rally_cwds" ]; then
|
|
51
|
-
_skip=0
|
|
52
|
-
while IFS= read -r _cwd; do
|
|
53
|
-
[ -z "$_cwd" ] && continue
|
|
54
|
-
if [ "$_cwd" = "$path" ]; then
|
|
55
|
-
_skip=1
|
|
56
|
-
break
|
|
57
|
-
fi
|
|
58
|
-
done <<EOF
|
|
59
|
-
$_rally_cwds
|
|
60
|
-
EOF
|
|
61
|
-
if [ "$_skip" = "1" ]; then
|
|
62
|
-
echo " SKIP:rally-live-session $path branch=$branch"
|
|
63
|
-
continue
|
|
64
|
-
fi
|
|
65
|
-
fi
|
|
66
|
-
git merge-base --is-ancestor "$branch" main 2>/dev/null || continue
|
|
67
|
-
dirty=$(git -C "$path" status --porcelain 2>/dev/null | wc -l | tr -d ' ')
|
|
68
|
-
locked=unlocked
|
|
69
|
-
[ -f "$path/.git" ] && grep -q locked "$path/.git" 2>/dev/null && locked=locked
|
|
70
|
-
echo " $path branch=$branch merged=yes dirty=$dirty $locked"
|
|
15
|
+
REPORT=".build-loop/worktree-gc-last.txt"
|
|
16
|
+
REPORT_DIR=".build-loop/worktree-gc"
|
|
17
|
+
mkdir -p "$(dirname "$REPORT")" "$REPORT_DIR"
|
|
71
18
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
git branch -D "$branch" >/dev/null 2>&1
|
|
81
|
-
echo " ACT:removed $path branch=$branch"
|
|
82
|
-
fi
|
|
83
|
-
done
|
|
19
|
+
HOOK_DIR="$(cd "$(dirname "$0")" 2>/dev/null && pwd)"
|
|
20
|
+
PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-$(cd "$HOOK_DIR/.." 2>/dev/null && pwd)}"
|
|
21
|
+
REAPER="$PLUGIN_ROOT/scripts/worktree_reaper/__main__.py"
|
|
22
|
+
_py=""
|
|
23
|
+
if [ -f "$HOOK_DIR/_resolve_python.sh" ]; then
|
|
24
|
+
# shellcheck source=hooks/_resolve_python.sh
|
|
25
|
+
. "$HOOK_DIR/_resolve_python.sh"
|
|
26
|
+
fi
|
|
84
27
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
28
|
+
stamp="$(date -u +%Y%m%dT%H%M%SZ)"
|
|
29
|
+
tmp="${REPORT}.tmp.$$"
|
|
30
|
+
json_tmp="${REPORT_DIR}/${stamp}-$$.json"
|
|
31
|
+
err_tmp="${REPORT_DIR}/${stamp}-$$.stderr"
|
|
88
32
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
if (!printed_hdr) { removed=removed "\n## Auto-removed (merged, bundled)\n"; printed_hdr=1 }
|
|
97
|
-
removed=removed $0 "\n"
|
|
98
|
-
next
|
|
99
|
-
}
|
|
100
|
-
{ print }
|
|
101
|
-
END { printf "%s", removed }
|
|
102
|
-
' "$R" > "$tmp" && mv "$tmp" "$R"
|
|
33
|
+
if [ -n "$_py" ] && [ -f "$REAPER" ]; then
|
|
34
|
+
"$_py" "$REAPER" --workdir "$PWD" --dry-run --json >"$json_tmp" 2>"$err_tmp"
|
|
35
|
+
rc=$?
|
|
36
|
+
else
|
|
37
|
+
rc=127
|
|
38
|
+
: >"$json_tmp"
|
|
39
|
+
printf '%s\n' "worktree reporter unavailable (python or reaper missing)" >"$err_tmp"
|
|
103
40
|
fi
|
|
104
41
|
|
|
42
|
+
{
|
|
43
|
+
printf '# Worktree report — %s\n\n' "$(date -u +%FT%TZ)"
|
|
44
|
+
printf 'Mode: REPORT-ONLY (SessionStart never owns terminal release)\n'
|
|
45
|
+
if [ "${BUILDLOOP_GC_ACT:-0}" = "1" ]; then
|
|
46
|
+
printf 'Notice: BUILDLOOP_GC_ACT=1 ignored; use an explicit owner-released finalizer call.\n'
|
|
47
|
+
fi
|
|
48
|
+
printf 'Exit: %s\n\n' "$rc"
|
|
49
|
+
printf '## Summary\n\n'
|
|
50
|
+
cat "$err_tmp"
|
|
51
|
+
printf '\n## JSON\n\n```json\n'
|
|
52
|
+
cat "$json_tmp"
|
|
53
|
+
printf '\n```\n'
|
|
54
|
+
} >"$tmp" 2>/dev/null
|
|
55
|
+
|
|
56
|
+
mv "$tmp" "$REPORT" 2>/dev/null || true
|
|
57
|
+
rm -f "$err_tmp"
|
|
105
58
|
exit 0
|