@tyroneross/build-loop 0.30.3

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.
Files changed (389) hide show
  1. package/.agents/plugins/marketplace.json +10 -0
  2. package/.claude-plugin/marketplace.json +38 -0
  3. package/.claude-plugin/plugin.json +30 -0
  4. package/.codex-plugin/plugin.json +41 -0
  5. package/.cursor/rules/build-loop-surface.mdc +22 -0
  6. package/AGENTS.md +498 -0
  7. package/LICENSE +202 -0
  8. package/README.md +403 -0
  9. package/agents/alignment-checker.md +124 -0
  10. package/agents/api-assessor.md +136 -0
  11. package/agents/architecture-scout.md +185 -0
  12. package/agents/assessment-orchestrator.md +163 -0
  13. package/agents/build-orchestrator.md +198 -0
  14. package/agents/database-assessor.md +133 -0
  15. package/agents/design-contract-specialist.md +239 -0
  16. package/agents/fact-checker.md +69 -0
  17. package/agents/fix-critique.md +161 -0
  18. package/agents/frontend-assessor.md +136 -0
  19. package/agents/implementer.md +185 -0
  20. package/agents/independent-auditor.md +143 -0
  21. package/agents/mock-scanner.md +78 -0
  22. package/agents/optimize-runner.md +112 -0
  23. package/agents/overfitting-reviewer.md +96 -0
  24. package/agents/performance-assessor.md +159 -0
  25. package/agents/plan-critic.md +85 -0
  26. package/agents/promotion-reviewer.md +121 -0
  27. package/agents/recurring-pattern-detector.md +248 -0
  28. package/agents/retrospective-synthesizer.md +109 -0
  29. package/agents/root-cause-investigator.md +285 -0
  30. package/agents/scope-auditor.md +121 -0
  31. package/agents/security-reviewer.md +151 -0
  32. package/agents/self-improvement-architect.md +125 -0
  33. package/agents/synthesis-critic.md +99 -0
  34. package/agents/transcript-pattern-miner.md +165 -0
  35. package/agents/ui-validator.md +193 -0
  36. package/codex-skills/build-loop/SKILL.md +20 -0
  37. package/codex-skills/debug-loop/SKILL.md +18 -0
  38. package/codex-skills/handoff/SKILL.md +22 -0
  39. package/codex-skills/knowledge/SKILL.md +21 -0
  40. package/codex-skills/optimize/SKILL.md +18 -0
  41. package/codex-skills/research/SKILL.md +18 -0
  42. package/commands/agent-rally-point.md +301 -0
  43. package/commands/assess.md +41 -0
  44. package/commands/debug.md +20 -0
  45. package/commands/debugger-detail.md +34 -0
  46. package/commands/debugger-scan.md +15 -0
  47. package/commands/debugger-status.md +20 -0
  48. package/commands/debugger.md +32 -0
  49. package/commands/handoff.md +113 -0
  50. package/commands/knowledge-review.md +16 -0
  51. package/commands/optimize.md +31 -0
  52. package/commands/plan-verify.md +39 -0
  53. package/commands/promote-experiment.md +129 -0
  54. package/commands/research.md +22 -0
  55. package/commands/run.md +12 -0
  56. package/commands/self-review.md +51 -0
  57. package/commands/start-prd.md +57 -0
  58. package/commands/test.md +34 -0
  59. package/dist/src/assessment-orchestrator.d.ts +78 -0
  60. package/dist/src/assessment-orchestrator.d.ts.map +1 -0
  61. package/dist/src/assessment-orchestrator.js +304 -0
  62. package/dist/src/assessment-orchestrator.js.map +1 -0
  63. package/dist/src/audit-miner.d.ts +21 -0
  64. package/dist/src/audit-miner.d.ts.map +1 -0
  65. package/dist/src/audit-miner.js +421 -0
  66. package/dist/src/audit-miner.js.map +1 -0
  67. package/dist/src/batch-operations.d.ts +30 -0
  68. package/dist/src/batch-operations.d.ts.map +1 -0
  69. package/dist/src/batch-operations.js +339 -0
  70. package/dist/src/batch-operations.js.map +1 -0
  71. package/dist/src/config.d.ts +83 -0
  72. package/dist/src/config.d.ts.map +1 -0
  73. package/dist/src/config.js +176 -0
  74. package/dist/src/config.js.map +1 -0
  75. package/dist/src/context-engine.d.ts +45 -0
  76. package/dist/src/context-engine.d.ts.map +1 -0
  77. package/dist/src/context-engine.js +135 -0
  78. package/dist/src/context-engine.js.map +1 -0
  79. package/dist/src/debug-wrapper.d.ts +58 -0
  80. package/dist/src/debug-wrapper.d.ts.map +1 -0
  81. package/dist/src/debug-wrapper.js +285 -0
  82. package/dist/src/debug-wrapper.js.map +1 -0
  83. package/dist/src/index.d.ts +31 -0
  84. package/dist/src/index.d.ts.map +1 -0
  85. package/dist/src/index.js +149 -0
  86. package/dist/src/index.js.map +1 -0
  87. package/dist/src/interactive-verifier.d.ts +26 -0
  88. package/dist/src/interactive-verifier.d.ts.map +1 -0
  89. package/dist/src/interactive-verifier.js +435 -0
  90. package/dist/src/interactive-verifier.js.map +1 -0
  91. package/dist/src/lessons.d.ts +59 -0
  92. package/dist/src/lessons.d.ts.map +1 -0
  93. package/dist/src/lessons.js +172 -0
  94. package/dist/src/lessons.js.map +1 -0
  95. package/dist/src/log-reader.d.ts +39 -0
  96. package/dist/src/log-reader.d.ts.map +1 -0
  97. package/dist/src/log-reader.js +291 -0
  98. package/dist/src/log-reader.js.map +1 -0
  99. package/dist/src/logger.d.ts +59 -0
  100. package/dist/src/logger.d.ts.map +1 -0
  101. package/dist/src/logger.js +328 -0
  102. package/dist/src/logger.js.map +1 -0
  103. package/dist/src/parallel-retrieval.d.ts +52 -0
  104. package/dist/src/parallel-retrieval.d.ts.map +1 -0
  105. package/dist/src/parallel-retrieval.js +309 -0
  106. package/dist/src/parallel-retrieval.js.map +1 -0
  107. package/dist/src/pattern-extractor.d.ts +30 -0
  108. package/dist/src/pattern-extractor.d.ts.map +1 -0
  109. package/dist/src/pattern-extractor.js +386 -0
  110. package/dist/src/pattern-extractor.js.map +1 -0
  111. package/dist/src/result-aggregator.d.ts +44 -0
  112. package/dist/src/result-aggregator.d.ts.map +1 -0
  113. package/dist/src/result-aggregator.js +315 -0
  114. package/dist/src/result-aggregator.js.map +1 -0
  115. package/dist/src/retrieval.d.ts +139 -0
  116. package/dist/src/retrieval.d.ts.map +1 -0
  117. package/dist/src/retrieval.js +724 -0
  118. package/dist/src/retrieval.js.map +1 -0
  119. package/dist/src/setup/auto-setup.d.ts +15 -0
  120. package/dist/src/setup/auto-setup.d.ts.map +1 -0
  121. package/dist/src/setup/auto-setup.js +157 -0
  122. package/dist/src/setup/auto-setup.js.map +1 -0
  123. package/dist/src/setup/configure-hooks.d.ts +8 -0
  124. package/dist/src/setup/configure-hooks.d.ts.map +1 -0
  125. package/dist/src/setup/configure-hooks.js +16 -0
  126. package/dist/src/setup/configure-hooks.js.map +1 -0
  127. package/dist/src/setup/create-slash-commands.d.ts +8 -0
  128. package/dist/src/setup/create-slash-commands.d.ts.map +1 -0
  129. package/dist/src/setup/create-slash-commands.js +101 -0
  130. package/dist/src/setup/create-slash-commands.js.map +1 -0
  131. package/dist/src/setup/index.d.ts +8 -0
  132. package/dist/src/setup/index.d.ts.map +1 -0
  133. package/dist/src/setup/index.js +17 -0
  134. package/dist/src/setup/index.js.map +1 -0
  135. package/dist/src/setup/inject-claude-md.d.ts +10 -0
  136. package/dist/src/setup/inject-claude-md.d.ts.map +1 -0
  137. package/dist/src/setup/inject-claude-md.js +150 -0
  138. package/dist/src/setup/inject-claude-md.js.map +1 -0
  139. package/dist/src/setup/uninstall.d.ts +22 -0
  140. package/dist/src/setup/uninstall.d.ts.map +1 -0
  141. package/dist/src/setup/uninstall.js +235 -0
  142. package/dist/src/setup/uninstall.js.map +1 -0
  143. package/dist/src/storage.d.ts +192 -0
  144. package/dist/src/storage.d.ts.map +1 -0
  145. package/dist/src/storage.js +1037 -0
  146. package/dist/src/storage.js.map +1 -0
  147. package/dist/src/string-similarity.d.ts +8 -0
  148. package/dist/src/string-similarity.d.ts.map +1 -0
  149. package/dist/src/string-similarity.js +57 -0
  150. package/dist/src/string-similarity.js.map +1 -0
  151. package/dist/src/traces/adapters/browser.d.ts +69 -0
  152. package/dist/src/traces/adapters/browser.d.ts.map +1 -0
  153. package/dist/src/traces/adapters/browser.js +280 -0
  154. package/dist/src/traces/adapters/browser.js.map +1 -0
  155. package/dist/src/traces/adapters/index.d.ts +23 -0
  156. package/dist/src/traces/adapters/index.d.ts.map +1 -0
  157. package/dist/src/traces/adapters/index.js +67 -0
  158. package/dist/src/traces/adapters/index.js.map +1 -0
  159. package/dist/src/traces/adapters/langchain.d.ts +42 -0
  160. package/dist/src/traces/adapters/langchain.d.ts.map +1 -0
  161. package/dist/src/traces/adapters/langchain.js +151 -0
  162. package/dist/src/traces/adapters/langchain.js.map +1 -0
  163. package/dist/src/traces/adapters/opentelemetry.d.ts +46 -0
  164. package/dist/src/traces/adapters/opentelemetry.d.ts.map +1 -0
  165. package/dist/src/traces/adapters/opentelemetry.js +164 -0
  166. package/dist/src/traces/adapters/opentelemetry.js.map +1 -0
  167. package/dist/src/traces/adapters/sentry.d.ts +58 -0
  168. package/dist/src/traces/adapters/sentry.d.ts.map +1 -0
  169. package/dist/src/traces/adapters/sentry.js +212 -0
  170. package/dist/src/traces/adapters/sentry.js.map +1 -0
  171. package/dist/src/traces/index.d.ts +10 -0
  172. package/dist/src/traces/index.d.ts.map +1 -0
  173. package/dist/src/traces/index.js +45 -0
  174. package/dist/src/traces/index.js.map +1 -0
  175. package/dist/src/traces/storage.d.ts +78 -0
  176. package/dist/src/traces/storage.d.ts.map +1 -0
  177. package/dist/src/traces/storage.js +399 -0
  178. package/dist/src/traces/storage.js.map +1 -0
  179. package/dist/src/traces/summarizer.d.ts +83 -0
  180. package/dist/src/traces/summarizer.d.ts.map +1 -0
  181. package/dist/src/traces/summarizer.js +247 -0
  182. package/dist/src/traces/summarizer.js.map +1 -0
  183. package/dist/src/traces/types.d.ts +365 -0
  184. package/dist/src/traces/types.d.ts.map +1 -0
  185. package/dist/src/traces/types.js +14 -0
  186. package/dist/src/traces/types.js.map +1 -0
  187. package/dist/src/types.d.ts +495 -0
  188. package/dist/src/types.d.ts.map +1 -0
  189. package/dist/src/types.js +27 -0
  190. package/dist/src/types.js.map +1 -0
  191. package/docs/agent-surface-policy.md +45 -0
  192. package/docs/memory-setup.md +226 -0
  193. package/hooks/_arch_scan_bg.py +88 -0
  194. package/hooks/_plugin_drift_check_bg.py +85 -0
  195. package/hooks/_session_start_lib.sh +42 -0
  196. package/hooks/git/pre-push +141 -0
  197. package/hooks/hooks.json +126 -0
  198. package/hooks/post-commit +30 -0
  199. package/hooks/pre-commit +29 -0
  200. package/hooks/pre-edit-apppulse.sh +6 -0
  201. package/hooks/pre-edit-architecture.sh +106 -0
  202. package/hooks/pre-edit-rally-point.sh +92 -0
  203. package/hooks/session-start-apppulse.sh +6 -0
  204. package/hooks/session-start-architecture.sh +10 -0
  205. package/hooks/session-start-git-hooks.sh +12 -0
  206. package/hooks/session-start-plugin-drift.sh +27 -0
  207. package/hooks/session-start-rally-point.sh +44 -0
  208. package/hooks/session-start-retrieval.sh +24 -0
  209. package/hooks/session-start-worktree-gc.sh +105 -0
  210. package/hooks/test_apppulse_hooks.sh +6 -0
  211. package/hooks/test_rally_point_hooks.sh +388 -0
  212. package/hooks/test_sec008_hooks.sh +66 -0
  213. package/package.json +111 -0
  214. package/scripts/README.md +301 -0
  215. package/scripts/_db_url.py +61 -0
  216. package/scripts/_paths.py +445 -0
  217. package/scripts/blm.py +162 -0
  218. package/scripts/blm_api.py +263 -0
  219. package/scripts/check_cache_sync.py +490 -0
  220. package/scripts/embed_backend.py +475 -0
  221. package/scripts/install_memory.py +556 -0
  222. package/scripts/lessons_index/__init__.py +77 -0
  223. package/scripts/lessons_index/__main__.py +135 -0
  224. package/scripts/lessons_index/ingest.py +288 -0
  225. package/scripts/lessons_index/query.py +285 -0
  226. package/scripts/lessons_index/schema.py +114 -0
  227. package/scripts/memory_context/__init__.py +610 -0
  228. package/scripts/memory_graph/__init__.py +393 -0
  229. package/scripts/project_resolver.py +172 -0
  230. package/scripts/prune_codex_plugin_cache.py +23 -0
  231. package/scripts/prune_plugin_cache.py +359 -0
  232. package/scripts/semantic_index/__init__.py +482 -0
  233. package/scripts/semantic_index/_bench_hybrid.py +175 -0
  234. package/scripts/semantic_index/backfill.py +263 -0
  235. package/scripts/semantic_index/hybrid.py +174 -0
  236. package/scripts/semantic_index/test_backfill.py +292 -0
  237. package/scripts/semantic_index/test_hybrid.py +541 -0
  238. package/scripts/sync_navgator_lessons.py +666 -0
  239. package/scripts/sync_plugin_cache.py +388 -0
  240. package/skills/agent-rally-point/SKILL.md +165 -0
  241. package/skills/agent-rally-watcher/SKILL.md +83 -0
  242. package/skills/api-registry-bridge/SKILL.md +59 -0
  243. package/skills/architecture/dead/SKILL.md +56 -0
  244. package/skills/architecture/impact/SKILL.md +88 -0
  245. package/skills/architecture/review/SKILL.md +227 -0
  246. package/skills/architecture/rules/SKILL.md +72 -0
  247. package/skills/architecture/scan/SKILL.md +79 -0
  248. package/skills/architecture/trace/SKILL.md +65 -0
  249. package/skills/attribution-standard/SKILL.md +122 -0
  250. package/skills/authentication/SKILL.md +81 -0
  251. package/skills/authentication/references/better-auth-magic-link.md +135 -0
  252. package/skills/authentication/references/better-auth-setup.md +224 -0
  253. package/skills/authentication/references/google-calendar-sync.md +278 -0
  254. package/skills/authentication/references/google-cloud-console.md +159 -0
  255. package/skills/authentication/references/google-geocoding-directions.md +126 -0
  256. package/skills/authentication/references/google-lessons-example-web-app.md +177 -0
  257. package/skills/authentication/references/google-maps.md +162 -0
  258. package/skills/authentication/references/google-oauth-setup.md +343 -0
  259. package/skills/authentication/references/google-places.md +173 -0
  260. package/skills/authentication/references/lessons-example-web-app-better-auth.md +126 -0
  261. package/skills/authentication/references/resend-email.md +227 -0
  262. package/skills/authentication/references/resend-otp-magic-link.md +153 -0
  263. package/skills/authentication/references/supabase-auth.md +172 -0
  264. package/skills/auto-decision-capture/SKILL.md +419 -0
  265. package/skills/build-loop/SKILL.md +516 -0
  266. package/skills/build-loop/detect-plugins.mjs +82 -0
  267. package/skills/build-loop/eval-guide.md +65 -0
  268. package/skills/build-loop/fallbacks.md +549 -0
  269. package/skills/build-loop/phases/fact-check.md +42 -0
  270. package/skills/build-loop/phases/ui-validation.md +267 -0
  271. package/skills/build-loop/references/apple-native-planning.md +439 -0
  272. package/skills/build-loop/references/capability-routing.md +181 -0
  273. package/skills/build-loop/references/codex-subagents.md +98 -0
  274. package/skills/build-loop/references/coordination.md +161 -0
  275. package/skills/build-loop/references/correction-aware-capture.md +177 -0
  276. package/skills/build-loop/references/independent-auditor.md +72 -0
  277. package/skills/build-loop/references/intent-capability-pack.md +170 -0
  278. package/skills/build-loop/references/intent-exploration-prompts.md +96 -0
  279. package/skills/build-loop/references/leadership.md +72 -0
  280. package/skills/build-loop/references/memory.md +284 -0
  281. package/skills/build-loop/references/modular-systems-pack.md +96 -0
  282. package/skills/build-loop/references/output-style.md +129 -0
  283. package/skills/build-loop/references/pay-it-forward-arch.md +98 -0
  284. package/skills/build-loop/references/phase-1-assess.md +218 -0
  285. package/skills/build-loop/references/phase-2-plan.md +77 -0
  286. package/skills/build-loop/references/phase-3-execute.md +47 -0
  287. package/skills/build-loop/references/phase-4-review.md +310 -0
  288. package/skills/build-loop/references/phase-5-iterate.md +71 -0
  289. package/skills/build-loop/references/phase-6-learn.md +56 -0
  290. package/skills/build-loop/references/recent-design-structures.md +274 -0
  291. package/skills/build-loop/references/refactor-history/ASSESSMENT.md +85 -0
  292. package/skills/build-loop/references/refactor-history/STANDALONE_TEST_RUN.md +149 -0
  293. package/skills/build-loop/references/refactor-history/scenarios/01-simple-bugfix.md +32 -0
  294. package/skills/build-loop/references/refactor-history/scenarios/02-ui-build-with-iteration.md +48 -0
  295. package/skills/build-loop/references/refactor-history/scenarios/03-multi-failure-escalation.md +60 -0
  296. package/skills/build-loop/references/refactor-history/scenarios/04-ui-build-ibr-absent.md +51 -0
  297. package/skills/build-loop/references/refactor-history/scenarios/05-refactor-navgator-absent.md +71 -0
  298. package/skills/build-loop/references/refactor-history/scenarios/06-recurring-bug-debugger-absent.md +52 -0
  299. package/skills/build-loop/references/refactor-history/trace-comparison.md +202 -0
  300. package/skills/build-loop/references/self-recursive-dev.md +77 -0
  301. package/skills/build-loop/references/self-review.md +232 -0
  302. package/skills/build-loop/references/ui-io-contract.md +116 -0
  303. package/skills/build-loop/scanners/audit-design-rules.mjs +476 -0
  304. package/skills/build-loop/scanners/require-visual-evidence.mjs +239 -0
  305. package/skills/build-loop/templates/backlog-item.md +35 -0
  306. package/skills/build-loop/templates/codex-worker-prompt.md +89 -0
  307. package/skills/build-loop/templates/ui-subagent-prompt.md +179 -0
  308. package/skills/build-loop/templates/ux-fix-plan.md +40 -0
  309. package/skills/building-with-deepagents/SKILL.md +195 -0
  310. package/skills/building-with-deepagents/references/anti-patterns.md +141 -0
  311. package/skills/building-with-deepagents/references/api-quick-reference.md +184 -0
  312. package/skills/capabilities/SKILL.md +91 -0
  313. package/skills/debug-loop/SKILL.md +278 -0
  314. package/skills/debug-loop/references/convergence-rules.md +145 -0
  315. package/skills/debug-loop/references/swiftui-macos-clunky-ui-debugger.html +823 -0
  316. package/skills/debugging/assess/SKILL.md +111 -0
  317. package/skills/debugging/debug-loop/SKILL.md +231 -0
  318. package/skills/debugging/memory/SKILL.md +147 -0
  319. package/skills/debugging/store/SKILL.md +153 -0
  320. package/skills/debugging-memory/SKILL.md +440 -0
  321. package/skills/debugging-memory/examples/incident-example.json +67 -0
  322. package/skills/debugging-memory/references/incident-documentation.md +280 -0
  323. package/skills/debugging-memory/references/ios-notification-alarm-playbook.md +300 -0
  324. package/skills/debugging-memory/references/pattern-extraction.md +163 -0
  325. package/skills/debugging-memory/references/subagent-integration.md +312 -0
  326. package/skills/defenseclaw-bridge/SKILL.md +156 -0
  327. package/skills/defenseclaw-bridge/references/dc-config-mapping.md +162 -0
  328. package/skills/defenseclaw-bridge/references/output-format.md +108 -0
  329. package/skills/handoff/SKILL.md +94 -0
  330. package/skills/ibr-bridge/SKILL.md +68 -0
  331. package/skills/knowledge/SKILL.md +127 -0
  332. package/skills/knowledge/references/recall-integration.md +83 -0
  333. package/skills/knowledge/templates/madr-minimal.md +56 -0
  334. package/skills/knowledge-review/SKILL.md +112 -0
  335. package/skills/logging-tracer/SKILL.md +202 -0
  336. package/skills/logging-tracer/references/log-analysis.md +128 -0
  337. package/skills/logging-tracer/references/stack-templates.md +274 -0
  338. package/skills/logging-tracer-bridge/SKILL.md +70 -0
  339. package/skills/mcp-builder/SKILL.md +278 -0
  340. package/skills/mcp-builder/references/mcp-security.md +106 -0
  341. package/skills/model-tiering/SKILL.md +216 -0
  342. package/skills/native-ax-driver/SKILL.md +220 -0
  343. package/skills/native-ax-driver/scripts/layout_fill.py +222 -0
  344. package/skills/native-ax-driver/scripts/native_driver.py +495 -0
  345. package/skills/native-ax-driver/swift/bl-ax-driver/Package.swift +20 -0
  346. package/skills/native-ax-driver/swift/bl-ax-driver/Sources/main.swift +542 -0
  347. package/skills/optimize/SKILL.md +202 -0
  348. package/skills/optimize/profiles.md +61 -0
  349. package/skills/plan-verify/SKILL.md +115 -0
  350. package/skills/plan-verify/test-fixtures/example-app-v20-findings.json +27 -0
  351. package/skills/plan-verify/test-fixtures/example-app-v20.md +42 -0
  352. package/skills/plan-verify/test-fixtures/example-app-v22-findings.json +15 -0
  353. package/skills/plan-verify/test-fixtures/example-app-v22.md +1608 -0
  354. package/skills/plan-verify/test-fixtures/unrelated-good-plan-findings.json +15 -0
  355. package/skills/plan-verify/test-fixtures/unrelated-good-plan.md +55 -0
  356. package/skills/plugin-builder/SKILL.md +329 -0
  357. package/skills/plugin-builder/references/authoritative-sources.md +104 -0
  358. package/skills/plugin-builder/references/build-loop-phase-guidance.md +94 -0
  359. package/skills/plugin-builder/references/components-guide.md +221 -0
  360. package/skills/plugin-builder/references/distribution.md +317 -0
  361. package/skills/plugin-builder/references/dual-host-claude-codex.md +220 -0
  362. package/skills/plugin-builder/references/hooks-reference.md +210 -0
  363. package/skills/plugin-builder/references/manifest-schema.md +111 -0
  364. package/skills/plugin-builder/references/plugin-hygiene-lessons.md +307 -0
  365. package/skills/plugin-tests/SKILL.md +94 -0
  366. package/skills/prd-bridge/SKILL.md +135 -0
  367. package/skills/research/SKILL.md +80 -0
  368. package/skills/security-methodology/SKILL.md +105 -0
  369. package/skills/security-methodology/references/cross-source-matrix.md +77 -0
  370. package/skills/security-methodology/references/mitre-atlas-starter.md +83 -0
  371. package/skills/security-methodology/references/nist-600-1-mapping.md +119 -0
  372. package/skills/security-methodology/references/owasp-agentic-top-10.md +157 -0
  373. package/skills/security-methodology/references/owasp-llm-top-10.md +144 -0
  374. package/skills/security-methodology/references/owasp-web-top-10.md +65 -0
  375. package/skills/self-improve/SKILL.md +298 -0
  376. package/skills/spec-writing/SKILL.md +548 -0
  377. package/skills/spec-writing/scripts/check_checklist.py +478 -0
  378. package/skills/sync-skills/SKILL.md +132 -0
  379. package/skills/telemetry/SKILL.md +66 -0
  380. package/skills/ui-design/SKILL.md +75 -0
  381. package/skills/ui-design/references/design-patterns-multi.md +165 -0
  382. package/skills/ui-design/references/design-preferences-from-owned-apps.md +150 -0
  383. package/skills/ui-design/references/evidence-capture-policy.md +55 -0
  384. package/skills/ui-design/references/ui-guidance-sources.md +330 -0
  385. package/skills/ui-design/references/universal-design-principles.alt.md +182 -0
  386. package/skills/ui-design/references/universal-design-principles.md +419 -0
  387. package/templates/memory/MEMORY.md.template +55 -0
  388. package/templates/memory/constitution.md.template +64 -0
  389. package/templates/memory/manifest.json +47 -0
@@ -0,0 +1,388 @@
1
+ #!/usr/bin/env bash
2
+ # SPDX-FileCopyrightText: 2025-2026 Tyrone Ross, Jr <46267523+tyroneross@users.noreply.github.com>
3
+ # SPDX-License-Identifier: Apache-2.0
4
+ # Fixture-driven tests for the Rally Point hooks:
5
+ # - session-start-rally-point.sh : one-line restore only on delta,
6
+ # silent + exit 0 otherwise
7
+ # - pre-edit-rally-point.sh : cheap revision-stat hint, never blocks
8
+ # Any failure exits non-zero.
9
+
10
+ set -uo pipefail
11
+
12
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
13
+ REPO_ROOT="$(dirname "$SCRIPT_DIR")"
14
+ SS_HOOK="${SCRIPT_DIR}/session-start-rally-point.sh"
15
+ PE_HOOK="${SCRIPT_DIR}/pre-edit-rally-point.sh"
16
+ PKG="${REPO_ROOT}/scripts/rally_point"
17
+
18
+ PASS=0
19
+ FAIL=0
20
+ pass() { echo "PASS: $1"; PASS=$((PASS + 1)); }
21
+ fail() { echo "FAIL: $1 — $2"; FAIL=$((FAIL + 1)); }
22
+
23
+ # Build a temp git repo (so channel_paths.app_slug resolves) + isolated
24
+ # apps root.
25
+ REPO=$(mktemp -d)
26
+ APPS=$(mktemp -d)
27
+ ( cd "$REPO" && git init -q && git config user.email t@e.com \
28
+ && git config user.name t )
29
+ export BUILD_LOOP_APPS_ROOT="$APPS"
30
+ export BUILD_LOOP_BRIDGE_INTERNAL_ONLY=1
31
+ export BUILD_LOOP_RALLY_POINT_SKIP_WATCH=1
32
+
33
+ # ---- Case 1: no channel yet -> SessionStart silent, exit 0 -------------
34
+ OUT=$(CLAUDE_PROJECT_DIR="$REPO" bash "$SS_HOOK" </dev/null 2>/dev/null)
35
+ RC=$?
36
+ if [ "$RC" -eq 0 ] && [ -z "$OUT" ]; then
37
+ pass "SessionStart silent + exit 0 when no channel"
38
+ else
39
+ fail "SessionStart no-channel" "rc=$RC out='$OUT'"
40
+ fi
41
+
42
+ # ---- Case 2: pre-edit never blocks, exit 0, joins and prints when in a repo
43
+ # (the join fires immediately on first tool-use for a git repo with no prior
44
+ # channel — this is the "newly joined" path, not a "no channel = silence" path).
45
+ OUT=$(CLAUDE_PROJECT_DIR="$REPO" bash "$PE_HOOK" </dev/null 2>/dev/null)
46
+ RC=$?
47
+ if [ "$RC" -eq 0 ]; then
48
+ pass "pre-edit exit 0 when no prior channel (join fires or no-op)"
49
+ else
50
+ fail "pre-edit no-channel" "rc=$RC out='$OUT'"
51
+ fi
52
+
53
+ # ---- Seed a delta: write a change + bump revision via the modules -----
54
+ REPO="$REPO" APPS="$APPS" PKG="$PKG" python3 - <<'PYEOF'
55
+ import os, sys
56
+ sys.path.insert(0, os.environ["PKG"])
57
+ import channel_paths as ap, changes as ch, revision as rev, presence as pr
58
+ slug = ap.app_slug(cwd=os.environ["REPO"])
59
+ chan = ap.ensure_channel_dir(slug)
60
+ pr.write_presence(chan, session_id="peerX", tool="codex", model="m",
61
+ run_id="rp", app_slug=slug, phase="execute",
62
+ files_in_flight=["a.py"])
63
+ ch.append_change(chan, ch.make_record(
64
+ kind="dep-change", tool="codex", model="m", run_id="rp",
65
+ app_slug=slug, payload={"manifests": ["package.json"]}, revision=1))
66
+ rev.bump_revision(chan)
67
+ PYEOF
68
+
69
+ # ---- Case 3: pre-edit prints peer-ahead hint when revision advanced ----
70
+ # Throttle is 60s (default); the Case 2 join wrote a presence record moments
71
+ # ago so the join is throttled — only the hint fires.
72
+ OUT=$(CLAUDE_PROJECT_DIR="$REPO" bash "$PE_HOOK" </dev/null 2>/dev/null)
73
+ RC=$?
74
+ if [ "$RC" -eq 0 ] && echo "$OUT" | grep -q "peer ahead"; then
75
+ pass "pre-edit prints 'peer ahead' hint when revision advanced"
76
+ else
77
+ fail "pre-edit hint" "rc=$RC out='$OUT'"
78
+ fi
79
+
80
+ # ---- Case 4: SessionStart prints exactly one restore line on delta -----
81
+ OUT=$(CLAUDE_PROJECT_DIR="$REPO" bash "$SS_HOOK" </dev/null 2>/dev/null)
82
+ RC=$?
83
+ LINES=$(printf '%s' "$OUT" | grep -c . || true)
84
+ if [ "$RC" -eq 0 ] && [ "$LINES" -eq 1 ] \
85
+ && echo "$OUT" | grep -q "Rally Point:" \
86
+ && echo "$OUT" | grep -q "reinstall"; then
87
+ pass "SessionStart one-line restore on delta"
88
+ else
89
+ fail "SessionStart restore" "rc=$RC lines=$LINES out='$OUT'"
90
+ fi
91
+
92
+ # ---- Case 5: SessionStart silent on the SECOND call (cursor advanced) --
93
+ OUT=$(CLAUDE_PROJECT_DIR="$REPO" bash "$SS_HOOK" </dev/null 2>/dev/null)
94
+ RC=$?
95
+ if [ "$RC" -eq 0 ] && [ -z "$OUT" ]; then
96
+ pass "SessionStart silent after cursor advanced (delta-only)"
97
+ else
98
+ fail "SessionStart second-call" "rc=$RC out='$OUT'"
99
+ fi
100
+
101
+ # =========================================================================
102
+ # Codex-parity autojoin tests (2026-06-07)
103
+ # =========================================================================
104
+
105
+ # Per-repo isolation: ALL new cases write into their own APPS subdir so
106
+ # they cannot read state from the cases above. Use NONREPO + REPO_X.
107
+ NONREPO=$(mktemp -d)
108
+ REPO_X=$(mktemp -d)
109
+ ( cd "$REPO_X" && git init -q && git config user.email t@e.com \
110
+ && git config user.name t )
111
+ APPS2=$(mktemp -d)
112
+
113
+ # macOS realpath: /var/folders/... -> /private/var/folders/... — the
114
+ # operative-repo resolver runs `git rev-parse --show-toplevel` which
115
+ # returns the resolved form, so compare against that.
116
+ REPO_X_REAL=$(python3 -c "import os,sys; print(os.path.realpath(sys.argv[1]))" "$REPO_X")
117
+
118
+ # Force a short throttle window so the throttle test does not have to
119
+ # sleep for the full 60s default.
120
+ export BUILD_LOOP_RALLY_PRE_EDIT_THROTTLE_SECONDS=5
121
+
122
+ # ---- Case 6: SessionStart no-misregister when CLAUDE_PROJECT_DIR unset
123
+ # AND $PWD is not a repo (home-like scenario). The hook must exit 0 and
124
+ # write NOTHING under APPS2.
125
+ BUILD_LOOP_APPS_ROOT="$APPS2" \
126
+ bash -c "cd '$NONREPO' && unset CLAUDE_PROJECT_DIR && BUILD_LOOP_APPS_ROOT='$APPS2' BUILD_LOOP_BRIDGE_INTERNAL_ONLY=1 BUILD_LOOP_RALLY_POINT_SKIP_WATCH=1 bash '$SS_HOOK'" </dev/null >/tmp/_ss_nonrepo.out 2>/dev/null
127
+ RC=$?
128
+ WROTE=$(find "$APPS2" -type f 2>/dev/null | wc -l | tr -d ' ')
129
+ if [ "$RC" -eq 0 ] && [ "$WROTE" -eq 0 ]; then
130
+ pass "SessionStart no-misregister when launch cwd is not a repo"
131
+ else
132
+ fail "SessionStart no-misregister" "rc=$RC wrote=$WROTE out=$(cat /tmp/_ss_nonrepo.out 2>/dev/null)"
133
+ fi
134
+
135
+ # Reset APPS2 between cases (each new case starts clean).
136
+ rm -rf "$APPS2" && mkdir -p "$APPS2"
137
+
138
+ # ---- Case 7: pre-edit Edit/Write joins room of the OPERATIVE repo,
139
+ # not the launch dir. We invoke from NONREPO but the file_path lives
140
+ # inside REPO_X. Presence must land under REPO_X's slug.
141
+ EVENT_JSON=$(printf '{"tool_input":{"file_path":"%s/a.py"}}' "$REPO_X")
142
+ BUILD_LOOP_APPS_ROOT="$APPS2" BUILD_LOOP_BRIDGE_INTERNAL_ONLY=1 \
143
+ bash -c "cd '$NONREPO' && unset CLAUDE_PROJECT_DIR && \
144
+ printf '%s' '$EVENT_JSON' | \
145
+ BUILD_LOOP_APPS_ROOT='$APPS2' BUILD_LOOP_BRIDGE_INTERNAL_ONLY=1 \
146
+ BUILD_LOOP_RALLY_PRE_EDIT_THROTTLE_SECONDS=5 \
147
+ bash '$PE_HOOK'" >/tmp/_pe_edit.out 2>/dev/null
148
+ RC=$?
149
+ REPO_X_SLUG=$(basename "$REPO_X" | tr '[:upper:]' '[:lower:]')
150
+ PRESENCE_COUNT=$(find "$APPS2" -path "*/$REPO_X_SLUG/sessions/*.json" -type f 2>/dev/null | wc -l | tr -d ' ')
151
+ # Allow normalized slug variants (the slug normalizer maps unsafe chars).
152
+ ANY_PRESENCE=$(find "$APPS2" -path "*/sessions/*.json" -type f 2>/dev/null | wc -l | tr -d ' ')
153
+ if [ "$RC" -eq 0 ] && [ "$ANY_PRESENCE" -ge 1 ]; then
154
+ # Verify the presence record's cwd points into REPO_X, not NONREPO.
155
+ CWD_HIT=$(grep -l "\"cwd\":\"$REPO_X_REAL\"" "$APPS2"/*/sessions/*.json 2>/dev/null | head -1)
156
+ if [ -n "$CWD_HIT" ]; then
157
+ pass "pre-edit Edit joins operative repo room (not launch dir)"
158
+ else
159
+ fail "pre-edit Edit operative-repo cwd" "rc=$RC any_presence=$ANY_PRESENCE files=$(ls "$APPS2"/*/sessions/ 2>/dev/null)"
160
+ fi
161
+ else
162
+ fail "pre-edit Edit operative-repo" "rc=$RC any_presence=$ANY_PRESENCE out=$(cat /tmp/_pe_edit.out 2>/dev/null)"
163
+ fi
164
+
165
+ # Reset between cases.
166
+ rm -rf "$APPS2" && mkdir -p "$APPS2"
167
+
168
+ # ---- Case 8: pre-edit Bash with leading `cd <repoX>` resolves repoX
169
+ # from the command payload, even when the launch cwd is NONREPO.
170
+ EVENT_JSON=$(printf '{"tool_input":{"command":"cd %s && echo hi"}}' "$REPO_X")
171
+ bash -c "cd '$NONREPO' && unset CLAUDE_PROJECT_DIR && \
172
+ printf '%s' '$EVENT_JSON' | \
173
+ BUILD_LOOP_APPS_ROOT='$APPS2' BUILD_LOOP_BRIDGE_INTERNAL_ONLY=1 \
174
+ BUILD_LOOP_RALLY_PRE_EDIT_THROTTLE_SECONDS=5 \
175
+ bash '$PE_HOOK'" >/tmp/_pe_bash.out 2>/dev/null
176
+ RC=$?
177
+ ANY_PRESENCE=$(find "$APPS2" -path "*/sessions/*.json" -type f 2>/dev/null | wc -l | tr -d ' ')
178
+ if [ "$RC" -eq 0 ] && [ "$ANY_PRESENCE" -ge 1 ]; then
179
+ CWD_HIT=$(grep -l "\"cwd\":\"$REPO_X_REAL\"" "$APPS2"/*/sessions/*.json 2>/dev/null | head -1)
180
+ if [ -n "$CWD_HIT" ]; then
181
+ pass "pre-edit Bash 'cd <repoX>' resolves operative repo"
182
+ else
183
+ fail "pre-edit Bash cwd" "rc=$RC files=$(ls "$APPS2"/*/sessions/ 2>/dev/null)"
184
+ fi
185
+ else
186
+ fail "pre-edit Bash operative-repo" "rc=$RC any_presence=$ANY_PRESENCE out=$(cat /tmp/_pe_bash.out 2>/dev/null)"
187
+ fi
188
+
189
+ # DO NOT reset between Case 8 and Case 9 — Case 9 verifies the throttle
190
+ # blocks a SECOND write within the throttle window.
191
+
192
+ # ---- Case 9: Throttle: a second rapid tool-use in the same room within
193
+ # the throttle window must NOT write a fresh presence file AND must NOT
194
+ # create a new presence file (each tool-use spawns a fresh python3 PID;
195
+ # a PID-keyed session id would defeat the throttle).
196
+ COUNT_BEFORE=$(find "$APPS2" -path "*/sessions/*.json" -type f 2>/dev/null | wc -l | tr -d ' ')
197
+ PRESENCE_FILE=$(find "$APPS2" -path "*/sessions/*.json" -type f 2>/dev/null | head -1)
198
+ if [ -z "$PRESENCE_FILE" ]; then
199
+ fail "throttle setup" "no presence file from case 8"
200
+ else
201
+ MTIME_BEFORE=$(stat -f '%m' "$PRESENCE_FILE" 2>/dev/null || stat -c '%Y' "$PRESENCE_FILE" 2>/dev/null)
202
+ # Tiny sleep so any rewrite would change mtime (mtime resolution is 1s).
203
+ sleep 1
204
+ bash -c "cd '$NONREPO' && unset CLAUDE_PROJECT_DIR && \
205
+ printf '%s' '$EVENT_JSON' | \
206
+ BUILD_LOOP_APPS_ROOT='$APPS2' BUILD_LOOP_BRIDGE_INTERNAL_ONLY=1 \
207
+ BUILD_LOOP_RALLY_PRE_EDIT_THROTTLE_SECONDS=30 \
208
+ bash '$PE_HOOK'" </dev/null >/dev/null 2>&1
209
+ COUNT_AFTER=$(find "$APPS2" -path "*/sessions/*.json" -type f 2>/dev/null | wc -l | tr -d ' ')
210
+ MTIME_AFTER=$(stat -f '%m' "$PRESENCE_FILE" 2>/dev/null || stat -c '%Y' "$PRESENCE_FILE" 2>/dev/null)
211
+ if [ "$MTIME_BEFORE" = "$MTIME_AFTER" ] && [ "$COUNT_BEFORE" = "$COUNT_AFTER" ]; then
212
+ pass "pre-edit throttle: no double-write + no new file within window"
213
+ else
214
+ fail "pre-edit throttle" "mtime before=$MTIME_BEFORE after=$MTIME_AFTER; count before=$COUNT_BEFORE after=$COUNT_AFTER"
215
+ fi
216
+ fi
217
+
218
+ # Reset between cases.
219
+ rm -rf "$APPS2" && mkdir -p "$APPS2"
220
+
221
+ # ---- Case 10: Fail-open under env -i / minimal PATH. Each changed hook
222
+ # must exit 0 under the Claude Code minimal-PATH simulation, regardless of
223
+ # rally state.
224
+ for HOOK in "$SS_HOOK" "$PE_HOOK"; do
225
+ RC=$(env -i PATH=/usr/bin:/bin HOME=/tmp \
226
+ BUILD_LOOP_APPS_ROOT="$APPS2" \
227
+ BUILD_LOOP_BRIDGE_INTERNAL_ONLY=1 \
228
+ BUILD_LOOP_RALLY_POINT_SKIP_WATCH=1 \
229
+ bash "$HOOK" </dev/null >/dev/null 2>&1; echo $?)
230
+ if [ "$RC" -eq 0 ]; then
231
+ pass "env -i PATH=/usr/bin:/bin exit 0 ($(basename "$HOOK"))"
232
+ else
233
+ fail "minimal-PATH exit 0 ($(basename "$HOOK"))" "rc=$RC"
234
+ fi
235
+ done
236
+
237
+ # ---- Case 11: Fail-open when the rally_point package is missing. We
238
+ # point ``PKG`` (via shell-side directory absence check) at a stub root
239
+ # without scripts/rally_point — the hooks must still exit 0 cleanly.
240
+ STUB=$(mktemp -d)
241
+ mkdir -p "$STUB/hooks" "$STUB/scripts"
242
+ cp "$SS_HOOK" "$STUB/hooks/"
243
+ cp "$PE_HOOK" "$STUB/hooks/"
244
+ cp "$SCRIPT_DIR/_session_start_lib.sh" "$STUB/hooks/"
245
+ for HOOK_NAME in session-start-rally-point.sh pre-edit-rally-point.sh; do
246
+ RC=$(BUILD_LOOP_APPS_ROOT="$APPS2" BUILD_LOOP_RALLY_POINT_SKIP_WATCH=1 \
247
+ bash "$STUB/hooks/$HOOK_NAME" </dev/null >/dev/null 2>&1; echo $?)
248
+ if [ "$RC" -eq 0 ]; then
249
+ pass "fail-open exit 0 when rally_point package missing ($HOOK_NAME)"
250
+ else
251
+ fail "fail-open missing-package ($HOOK_NAME)" "rc=$RC"
252
+ fi
253
+ done
254
+
255
+ # =========================================================================
256
+ # New tests: status line, quiet flag, 64KB cap, socket hostname, cd guard
257
+ # =========================================================================
258
+
259
+ # ---- Case 12: visible status line "rally: joined <slug> room" prints on
260
+ # real join (throttle window set to 0 so the write always fires).
261
+ APPS3=$(mktemp -d)
262
+ REPO_Y=$(mktemp -d)
263
+ ( cd "$REPO_Y" && git init -q && git config user.email t@e.com && git config user.name t )
264
+ EVENT_JSON_Y=$(printf '{"tool_input":{"file_path":"%s/z.py"}}' "$REPO_Y")
265
+ OUT=$(printf '%s' "$EVENT_JSON_Y" | \
266
+ BUILD_LOOP_APPS_ROOT="$APPS3" \
267
+ BUILD_LOOP_BRIDGE_INTERNAL_ONLY=1 \
268
+ BUILD_LOOP_RALLY_PRE_EDIT_THROTTLE_SECONDS=0 \
269
+ CLAUDE_PROJECT_DIR="$REPO_Y" \
270
+ bash "$PE_HOOK" 2>/dev/null)
271
+ RC=$?
272
+ if [ "$RC" -eq 0 ] && echo "$OUT" | grep -q "rally: joined"; then
273
+ pass "visible status: 'rally: joined <slug> room' prints on real join"
274
+ else
275
+ fail "visible status: join line missing" "rc=$RC out='$OUT'"
276
+ fi
277
+
278
+ # ---- Case 13: status line is SILENT when throttled (write was skipped).
279
+ # Reuse APPS3 / REPO_Y from case 12; presence file is fresh, so the
280
+ # throttle (30s) blocks the write AND the status print.
281
+ OUT=$(printf '%s' "$EVENT_JSON_Y" | \
282
+ BUILD_LOOP_APPS_ROOT="$APPS3" \
283
+ BUILD_LOOP_BRIDGE_INTERNAL_ONLY=1 \
284
+ BUILD_LOOP_RALLY_PRE_EDIT_THROTTLE_SECONDS=30 \
285
+ CLAUDE_PROJECT_DIR="$REPO_Y" \
286
+ bash "$PE_HOOK" 2>/dev/null)
287
+ RC=$?
288
+ if [ "$RC" -eq 0 ] && ! echo "$OUT" | grep -q "rally: joined"; then
289
+ pass "visible status: silent when throttled (no double-print)"
290
+ else
291
+ fail "visible status: spurious join line when throttled" "rc=$RC out='$OUT'"
292
+ fi
293
+
294
+ # ---- Case 14: BUILD_LOOP_RALLY_QUIET=1 suppresses the status line even
295
+ # on a real join (throttle=0 so a write would fire without the quiet flag).
296
+ APPS4=$(mktemp -d)
297
+ REPO_Z=$(mktemp -d)
298
+ ( cd "$REPO_Z" && git init -q && git config user.email t@e.com && git config user.name t )
299
+ EVENT_JSON_Z=$(printf '{"tool_input":{"file_path":"%s/q.py"}}' "$REPO_Z")
300
+ OUT=$(printf '%s' "$EVENT_JSON_Z" | \
301
+ BUILD_LOOP_APPS_ROOT="$APPS4" \
302
+ BUILD_LOOP_BRIDGE_INTERNAL_ONLY=1 \
303
+ BUILD_LOOP_RALLY_PRE_EDIT_THROTTLE_SECONDS=0 \
304
+ BUILD_LOOP_RALLY_QUIET=1 \
305
+ CLAUDE_PROJECT_DIR="$REPO_Z" \
306
+ bash "$PE_HOOK" 2>/dev/null)
307
+ RC=$?
308
+ if [ "$RC" -eq 0 ] && [ -z "$OUT" ]; then
309
+ pass "BUILD_LOOP_RALLY_QUIET=1 suppresses join status line"
310
+ else
311
+ fail "QUIET flag did not suppress output" "rc=$RC out='$OUT'"
312
+ fi
313
+
314
+ # ---- Case 15: 64 KB stdin cap — a payload larger than 64 KB must not
315
+ # cause a failure; the hook must exit 0 cleanly.
316
+ APPS5=$(mktemp -d)
317
+ REPO_W=$(mktemp -d)
318
+ ( cd "$REPO_W" && git init -q && git config user.email t@e.com && git config user.name t )
319
+ # Build a ~100 KB JSON-ish blob (INVALID JSON so hooks.py falls through
320
+ # gracefully — the 64KB cap test is about not crashing, not about parsing).
321
+ BIG_PAYLOAD=$(python3 -c "print('{\"tool_input\":{\"file_path\":\"/tmp/x.py\",\"extra\":\"' + 'A'*102400 + '\"}}')")
322
+ RC=$(printf '%s' "$BIG_PAYLOAD" | \
323
+ BUILD_LOOP_APPS_ROOT="$APPS5" \
324
+ BUILD_LOOP_BRIDGE_INTERNAL_ONLY=1 \
325
+ BUILD_LOOP_RALLY_PRE_EDIT_THROTTLE_SECONDS=5 \
326
+ CLAUDE_PROJECT_DIR="$REPO_W" \
327
+ bash "$PE_HOOK" >/dev/null 2>/dev/null; echo $?)
328
+ if [ "$RC" -eq 0 ]; then
329
+ pass "64KB stdin cap: exit 0 on oversized payload"
330
+ else
331
+ fail "64KB stdin cap: hook errored on large stdin" "rc=$RC"
332
+ fi
333
+
334
+ # ---- Case 16: socket.gethostname() — session_id must NOT end in "-host"
335
+ # (which was the fallback when HOSTNAME env var was missing). Under env -i
336
+ # the real hostname is always available via the syscall.
337
+ APPS6=$(mktemp -d)
338
+ REPO_H=$(mktemp -d)
339
+ ( cd "$REPO_H" && git init -q && git config user.email t@e.com && git config user.name t )
340
+ EVENT_JSON_H=$(printf '{"tool_input":{"file_path":"%s/h.py"}}' "$REPO_H")
341
+ env -i PATH=/usr/bin:/bin HOME=/tmp \
342
+ BUILD_LOOP_APPS_ROOT="$APPS6" \
343
+ BUILD_LOOP_BRIDGE_INTERNAL_ONLY=1 \
344
+ BUILD_LOOP_RALLY_PRE_EDIT_THROTTLE_SECONDS=0 \
345
+ bash -c "printf '%s' '$EVENT_JSON_H' | CLAUDE_PROJECT_DIR='$REPO_H' bash '$PE_HOOK'" \
346
+ >/dev/null 2>/dev/null
347
+ PFILE=$(find "$APPS6" -path "*/sessions/*.json" -type f 2>/dev/null | head -1)
348
+ if [ -n "$PFILE" ]; then
349
+ SID=$(python3 -c "import json,sys; d=json.load(open(sys.argv[1])); print(d.get('session_id',''))" "$PFILE" 2>/dev/null || true)
350
+ if echo "$SID" | grep -qv "\-host$"; then
351
+ pass "socket.gethostname(): session_id does not end in '-host' under env -i"
352
+ else
353
+ fail "socket.gethostname(): session_id still ends in '-host'" "sid='$SID'"
354
+ fi
355
+ else
356
+ # No presence file written (env -i may lack python3 in /usr/bin path on this
357
+ # machine) — fall back to a direct Python unit check.
358
+ HOSTNAME_CHECK=$(env -i PATH=/usr/bin:/bin python3 -c "
359
+ import socket, sys
360
+ h = socket.gethostname()
361
+ sys.exit(0 if h and h != 'host' else 1)
362
+ " 2>/dev/null; echo $?)
363
+ if [ "$HOSTNAME_CHECK" = "0" ]; then
364
+ pass "socket.gethostname(): returns real hostname under env -i (direct check)"
365
+ else
366
+ fail "socket.gethostname(): returned empty or 'host' under env -i" ""
367
+ fi
368
+ fi
369
+
370
+ # ---- Case 17: non-first-line `cd` must resolve to None (not the evil path).
371
+ # _extract_cd_target should return None for "echo x\ncd /evil".
372
+ RESULT=$(python3 -c "
373
+ import sys
374
+ sys.path.insert(0, '${REPO_ROOT}/scripts')
375
+ from rally_point.hooks import _extract_cd_target
376
+ r = _extract_cd_target('echo x\ncd /evil')
377
+ # .match() anchors at start; the leading 'echo' line must prevent the match.
378
+ assert r is None, f'Expected None, got {r!r}'
379
+ print('ok')
380
+ " 2>/dev/null)
381
+ if [ "$RESULT" = "ok" ]; then
382
+ pass "_extract_cd_target: non-first-line cd resolves to None (re.MULTILINE removed)"
383
+ else
384
+ fail "_extract_cd_target: non-first-line cd wrongly matched" "result='$RESULT'"
385
+ fi
386
+
387
+ echo "Results: ${PASS} passed, ${FAIL} failed"
388
+ [ "$FAIL" -eq 0 ] || exit 1
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env bash
2
+ # SPDX-FileCopyrightText: 2025-2026 Tyrone Ross, Jr <46267523+tyroneross@users.noreply.github.com>
3
+ # SPDX-License-Identifier: Apache-2.0
4
+ # SEC-008 regression test for hooks/pre-commit and hooks/post-commit.
5
+ #
6
+ # Both hooks compute the repo toplevel via `git rev-parse --show-toplevel`.
7
+ # If that resolution fails, the old code produced an empty path, the
8
+ # `-f` file test silently failed, and the guard / capture was skipped —
9
+ # fail-open. The fix: `exit 2` when toplevel cannot be resolved.
10
+ #
11
+ # This test runs each hook from a directory that is NOT inside a git
12
+ # repo, so `git rev-parse --show-toplevel` yields nothing, and asserts
13
+ # the hook exits 2 instead of 0.
14
+ #
15
+ # Any failure exits non-zero.
16
+
17
+ set -uo pipefail
18
+
19
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
20
+ PRE_HOOK="${SCRIPT_DIR}/pre-commit"
21
+ POST_HOOK="${SCRIPT_DIR}/post-commit"
22
+
23
+ PASS=0
24
+ FAIL=0
25
+ pass() { echo "PASS: $1"; PASS=$((PASS + 1)); }
26
+ fail() { echo "FAIL: $1 — $2"; FAIL=$((FAIL + 1)); }
27
+
28
+ # A directory guaranteed not to be inside a git repo.
29
+ NOREPO=$(mktemp -d)
30
+ trap 'rm -rf "$NOREPO"' EXIT
31
+
32
+ # ---- Case 1: pre-commit exits 2 when toplevel cannot be resolved ------
33
+ ( cd "$NOREPO" && sh "$PRE_HOOK" </dev/null >/dev/null 2>&1 )
34
+ RC=$?
35
+ if [ "$RC" -eq 2 ]; then
36
+ pass "pre-commit fails closed (exit 2) with no resolvable toplevel"
37
+ else
38
+ fail "pre-commit no-toplevel" "expected exit 2, got $RC"
39
+ fi
40
+
41
+ # ---- Case 2: post-commit exits 2 when toplevel cannot be resolved ----
42
+ ( cd "$NOREPO" && sh "$POST_HOOK" </dev/null >/dev/null 2>&1 )
43
+ RC=$?
44
+ if [ "$RC" -eq 2 ]; then
45
+ pass "post-commit fails closed (exit 2) with no resolvable toplevel"
46
+ else
47
+ fail "post-commit no-toplevel" "expected exit 2, got $RC"
48
+ fi
49
+
50
+ # ---- Case 3: pre-commit exits 0 inside a repo with no guard script ---
51
+ # (the .private-slug-check.py is not installed, so the guard segment
52
+ # finds no file and the hook proceeds to its trailing `exit 0`).
53
+ REPO=$(mktemp -d)
54
+ ( cd "$REPO" && git init -q )
55
+ ( cd "$REPO" && sh "$PRE_HOOK" </dev/null >/dev/null 2>&1 )
56
+ RC=$?
57
+ rm -rf "$REPO"
58
+ if [ "$RC" -eq 0 ]; then
59
+ pass "pre-commit exits 0 inside a repo when guard script absent"
60
+ else
61
+ fail "pre-commit in-repo-no-guard" "expected exit 0, got $RC"
62
+ fi
63
+
64
+ echo "----"
65
+ echo "PASS=$PASS FAIL=$FAIL"
66
+ [ "$FAIL" -eq 0 ]
package/package.json ADDED
@@ -0,0 +1,111 @@
1
+ {
2
+ "name": "@tyroneross/build-loop",
3
+ "version": "0.30.3",
4
+ "publishConfig": {
5
+ "registry": "https://npm.pkg.github.com",
6
+ "access": "public"
7
+ },
8
+ "description": "Multi-phase build orchestration with integrated debugging: assess, plan, execute, review, iterate.",
9
+ "main": "dist/src/index.js",
10
+ "types": "dist/src/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/src/index.d.ts",
14
+ "require": "./dist/src/index.js",
15
+ "import": "./dist/src/index.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "codex-skills",
21
+ "commands",
22
+ "skills",
23
+ "scripts/_paths.py",
24
+ "scripts/_db_url.py",
25
+ "scripts/blm.py",
26
+ "scripts/blm_api.py",
27
+ "scripts/check_cache_sync.py",
28
+ "scripts/embed_backend.py",
29
+ "scripts/install_memory.py",
30
+ "scripts/lessons_index",
31
+ "scripts/memory_context",
32
+ "scripts/memory_graph",
33
+ "scripts/project_resolver.py",
34
+ "scripts/semantic_index",
35
+ "scripts/sync_navgator_lessons.py",
36
+ "scripts/sync_plugin_cache.py",
37
+ "scripts/prune_plugin_cache.py",
38
+ "scripts/prune_codex_plugin_cache.py",
39
+ "hooks",
40
+ "agents",
41
+ "docs/agent-surface-policy.md",
42
+ "docs/memory-setup.md",
43
+ "templates/memory",
44
+ ".cursor",
45
+ ".claude-plugin",
46
+ ".codex-plugin",
47
+ ".agents",
48
+ "README.md",
49
+ "AGENTS.md",
50
+ "LICENSE",
51
+ "!**/__pycache__",
52
+ "!**/__pycache__/**",
53
+ "!**/*.pyc"
54
+ ],
55
+ "scripts": {
56
+ "build": "tsc",
57
+ "watch": "tsc --watch",
58
+ "prepublishOnly": "npm run build",
59
+ "test": "python3 -m unittest scripts/test_commit_state_check.py scripts/test_bridge_preflight.py scripts/test_mcp_registration.py && bash scripts/hooks/test_hooks.sh",
60
+ "benchmark": "node benchmark-scoring.js",
61
+ "clean": "rm -rf dist",
62
+ "plugin:prune-cache": "python3 scripts/prune_plugin_cache.py --source .",
63
+ "plugin:prune-cache:apply": "python3 scripts/prune_plugin_cache.py --source . --apply",
64
+ "plugin:sync-cache": "python3 scripts/sync_plugin_cache.py --source . --host all",
65
+ "plugin:sync-cache:hooks": "python3 scripts/sync_plugin_cache.py --source . --host all --install-git-hooks",
66
+ "codex:prune-cache": "python3 scripts/prune_codex_plugin_cache.py --source .",
67
+ "codex:sync-cache": "python3 scripts/sync_plugin_cache.py --source . --host codex",
68
+ "codex:prune-cache:apply": "python3 scripts/prune_codex_plugin_cache.py --source . --apply",
69
+ "claude:prune-cache": "python3 scripts/prune_plugin_cache.py --source . --host claude",
70
+ "claude:sync-cache": "python3 scripts/sync_plugin_cache.py --source . --host claude",
71
+ "claude:prune-cache:apply": "python3 scripts/prune_plugin_cache.py --source . --host claude --apply"
72
+ },
73
+ "keywords": [
74
+ "build-loop",
75
+ "orchestration",
76
+ "codex",
77
+ "claude-code",
78
+ "plugin",
79
+ "agentic-development",
80
+ "spec-writing",
81
+ "evaluation"
82
+ ],
83
+ "author": "Tyrone Ross",
84
+ "license": "Apache-2.0",
85
+ "repository": {
86
+ "type": "git",
87
+ "url": "git+https://github.com/tyroneross/build-loop.git"
88
+ },
89
+ "bugs": {
90
+ "url": "https://github.com/tyroneross/build-loop/issues"
91
+ },
92
+ "homepage": "https://github.com/tyroneross/build-loop#readme",
93
+ "dependencies": {
94
+ "commander": "^14.0.3",
95
+ "prompts": "^2.4.2"
96
+ },
97
+ "devDependencies": {
98
+ "@types/node": "^20.0.0",
99
+ "@types/prompts": "^2.4.9",
100
+ "typescript": "^5.0.0"
101
+ },
102
+ "engines": {
103
+ "node": ">=18.0.0"
104
+ },
105
+ "packageManager": "npm@10.x",
106
+ "os": [
107
+ "darwin",
108
+ "linux",
109
+ "win32"
110
+ ]
111
+ }