forge-workflow 0.0.9 → 0.1.0-beta.2

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 (479) hide show
  1. package/.claude/rules/{greptile-review-process.md → review-process.md} +56 -41
  2. package/.claude/scripts/{greptile-resolve.sh → review-resolve.sh} +13 -3
  3. package/.cursor/rules/permissions-guidance.mdc +2 -2
  4. package/.forge/hooks/check-tdd.js +3 -0
  5. package/.forge/hooks/forge-native-hook.js +245 -0
  6. package/.forge/protected-paths.yaml +157 -0
  7. package/AGENTS.md +151 -61
  8. package/CHANGELOG.md +681 -0
  9. package/CLAUDE.md +9 -106
  10. package/QUICKSTART.md +171 -0
  11. package/README.md +271 -363
  12. package/bin/forge-cmd.js +120 -9
  13. package/bin/forge-preflight.js +26 -5
  14. package/bin/forge.js +466 -489
  15. package/docs/INDEX.md +93 -0
  16. package/docs/PROJECT_DESIGN.md +685 -0
  17. package/docs/architecture/index.md +66 -0
  18. package/docs/architecture/notes/README.md +35 -0
  19. package/docs/architecture/subsystems/README.md +46 -0
  20. package/docs/{TOOLCHAIN.md → forge/TOOLCHAIN.md} +56 -47
  21. package/docs/forge/VALIDATION.md +82 -0
  22. package/docs/{AGENT_INSTALL_PROMPT.md → guides/AGENT_INSTALL_PROMPT.md} +3 -3
  23. package/docs/guides/BEADS_GITHUB_SYNC.md +32 -0
  24. package/docs/{ENHANCED_ONBOARDING.md → guides/ENHANCED_ONBOARDING.md} +16 -12
  25. package/docs/guides/GREPTILE_SETUP.md +46 -0
  26. package/docs/guides/MANUAL_REVIEW_GUIDE.md +58 -0
  27. package/docs/guides/MIGRATION.md +56 -0
  28. package/docs/guides/SETUP.md +118 -0
  29. package/docs/guides/SUPPORT.md +185 -0
  30. package/docs/guides/WORKFLOW_TEMPLATES.md +74 -0
  31. package/docs/guides/memory-backends.md +183 -0
  32. package/docs/reference/ADAPTERS.md +128 -0
  33. package/docs/reference/AGENT_SKILL_PARITY.md +175 -0
  34. package/docs/reference/COMMANDS.md +205 -0
  35. package/docs/reference/DECISION_DRIFT_GUARDS.md +97 -0
  36. package/docs/{EXAMPLES.md → reference/EXAMPLES.md} +7 -5
  37. package/docs/reference/FORGE_KERNEL_STORAGE_MODEL.md +135 -0
  38. package/docs/reference/HERMES_INTEGRATION.md +118 -0
  39. package/docs/reference/INSIGHTS_RECAP.md +63 -0
  40. package/docs/reference/INSTALL.md +164 -0
  41. package/docs/reference/KERNEL_TAXONOMY_VALIDATION.md +161 -0
  42. package/docs/reference/PROTECTED_PATH_MANIFEST.md +25 -0
  43. package/docs/reference/RELEASE.md +68 -0
  44. package/docs/reference/RESEARCH_TEMPLATE.md +292 -0
  45. package/docs/{ROADMAP.md → reference/ROADMAP.md} +12 -9
  46. package/docs/reference/SKILLS.md +35 -0
  47. package/docs/reference/STATUS_BOARD.md +80 -0
  48. package/docs/reference/TEMPLATES.md +106 -0
  49. package/docs/reference/TOOLCHAIN.md +658 -0
  50. package/docs/reference/VALIDATION.md +82 -0
  51. package/docs/reference/agent-permissions.md +169 -0
  52. package/docs/reference/beads-to-kernel-migration-ux.md +61 -0
  53. package/docs/reference/control-plane-guarantees.md +125 -0
  54. package/docs/reference/dependency-chain.md +331 -0
  55. package/docs/reference/forge-kernel-issue-command-contract.md +161 -0
  56. package/docs/reference/forge-kernel-schema.md +72 -0
  57. package/docs/reference/kernel-conflict-evaluators.md +27 -0
  58. package/docs/reference/patch-md-format.md +77 -0
  59. package/docs/reference/protected-state-surfaces.md +59 -0
  60. package/docs/reference/shepherd.md +115 -0
  61. package/docs/reference/superpowers-analysis.md +320 -0
  62. package/docs/reference/superpowers-integration-options.md +404 -0
  63. package/docs/reference/test-environment.md +519 -0
  64. package/docs/reference/upgrade-safety.md +59 -0
  65. package/lefthook.yml +18 -0
  66. package/lib/adapter-cli.js +307 -0
  67. package/lib/adapters/beads-issue-adapter.js +127 -0
  68. package/lib/adapters/beads-kernel-compat.js +1042 -0
  69. package/lib/adapters/greptile-review-adapter.js +141 -0
  70. package/lib/adapters/kernel-issue-adapter.js +101 -0
  71. package/lib/adapters/pr-state-adapter.js +484 -0
  72. package/lib/adoption-profiles.js +126 -0
  73. package/lib/agents/README.md +2 -6
  74. package/lib/agents/claude.plugin.json +3 -8
  75. package/lib/agents/codex.plugin.json +9 -1
  76. package/lib/agents/cursor.plugin.json +2 -6
  77. package/lib/agents/hermes.plugin.json +22 -0
  78. package/lib/agents-config.js +39 -1236
  79. package/lib/audit-evidence.js +282 -0
  80. package/lib/beads-setup.js +225 -28
  81. package/lib/beads-sync-scaffold.js +36 -107
  82. package/lib/codex-skills.js +51 -1
  83. package/lib/commands/_issue.js +744 -70
  84. package/lib/commands/_manifest.js +91 -0
  85. package/lib/commands/_registry.js +85 -34
  86. package/lib/commands/_resolve-command-opts.js +261 -0
  87. package/lib/commands/_serve-security.js +270 -0
  88. package/lib/commands/adapter.js +12 -0
  89. package/lib/commands/add.js +118 -0
  90. package/lib/commands/audit.js +70 -0
  91. package/lib/commands/blocked.js +5 -0
  92. package/lib/commands/board.js +64 -0
  93. package/lib/commands/claim.js +21 -2
  94. package/lib/commands/claims.js +7 -0
  95. package/lib/commands/clean.js +485 -75
  96. package/lib/commands/close.js +2 -2
  97. package/lib/commands/comment.js +5 -0
  98. package/lib/commands/control.js +148 -0
  99. package/lib/commands/create.js +2 -2
  100. package/lib/commands/dev.js +185 -7
  101. package/lib/commands/doc-gate.js +336 -0
  102. package/lib/commands/doctor.js +156 -0
  103. package/lib/commands/explain.js +15 -0
  104. package/lib/commands/export.js +237 -0
  105. package/lib/commands/gate.js +192 -0
  106. package/lib/commands/hooks.js +242 -0
  107. package/lib/commands/inbox.js +118 -0
  108. package/lib/commands/init.js +598 -0
  109. package/lib/commands/insights.js +79 -0
  110. package/lib/commands/issue.js +12 -1
  111. package/lib/commands/issues.js +66 -0
  112. package/lib/commands/lint.js +5 -0
  113. package/lib/commands/list.js +2 -2
  114. package/lib/commands/merge.js +312 -0
  115. package/lib/commands/migrate.js +523 -0
  116. package/lib/commands/new.js +12 -0
  117. package/lib/commands/options.js +241 -0
  118. package/lib/commands/orient.js +13 -0
  119. package/lib/commands/orphans.js +5 -0
  120. package/lib/commands/patch.js +67 -0
  121. package/lib/commands/plan.js +436 -24
  122. package/lib/commands/preflight.js +211 -0
  123. package/lib/commands/prime.js +13 -0
  124. package/lib/commands/push.js +69 -2
  125. package/lib/commands/ready.js +2 -2
  126. package/lib/commands/recall.js +116 -0
  127. package/lib/commands/recap.js +61 -0
  128. package/lib/commands/recommend.js +22 -2
  129. package/lib/commands/release.js +91 -0
  130. package/lib/commands/remember.js +74 -0
  131. package/lib/commands/role.js +99 -0
  132. package/lib/commands/serve.js +581 -0
  133. package/lib/commands/setup.js +851 -979
  134. package/lib/commands/shepherd.js +436 -0
  135. package/lib/commands/ship.js +23 -1
  136. package/lib/commands/show.js +2 -2
  137. package/lib/commands/stage.js +192 -0
  138. package/lib/commands/stale.js +5 -0
  139. package/lib/commands/status.js +329 -11
  140. package/lib/commands/sync.js +34 -46
  141. package/lib/commands/team.js +15 -2
  142. package/lib/commands/test.js +58 -7
  143. package/lib/commands/update.js +2 -2
  144. package/lib/commands/upgrade.js +47 -0
  145. package/lib/commands/validate.js +56 -25
  146. package/lib/commands/worktree.js +308 -128
  147. package/lib/config-writer.js +202 -0
  148. package/lib/control-plane.js +236 -0
  149. package/lib/core/runtime-graph.js +946 -0
  150. package/lib/dep-guard/keyword-ripple.js +184 -0
  151. package/lib/deprecated-sync-cleanup.js +362 -0
  152. package/lib/detect-agent.js +2 -28
  153. package/lib/detect-worktree.js +42 -17
  154. package/lib/doc-gate/declaration.js +177 -0
  155. package/lib/doc-gate/detect.js +289 -0
  156. package/lib/doc-gate/gate.js +375 -0
  157. package/lib/doc-gate/okf-config.js +128 -0
  158. package/lib/doc-gate/okf.js +429 -0
  159. package/lib/docs-command.js +1161 -6
  160. package/lib/forge-issues.js +697 -0
  161. package/lib/forge-lock.js +262 -0
  162. package/lib/gate-events.js +193 -0
  163. package/lib/global-flags.js +74 -0
  164. package/lib/greptile-match.js +7 -63
  165. package/lib/harness-capability-matrix.js +380 -0
  166. package/lib/hook-global-installer.js +347 -0
  167. package/lib/hook-renderer.js +451 -0
  168. package/lib/inbox.js +391 -0
  169. package/lib/insights.js +397 -0
  170. package/lib/issue-adapter.js +156 -0
  171. package/lib/issue-backend.js +145 -0
  172. package/lib/issue-render.js +220 -0
  173. package/lib/issue-sync/authority.js +100 -0
  174. package/lib/issue-sync/github-pull.js +184 -0
  175. package/lib/issue-sync/import-primitives.js +98 -0
  176. package/lib/issue-sync/legacy-link-bridge.js +436 -0
  177. package/lib/issue-sync/link-store.js +292 -0
  178. package/lib/issue-sync/project-github.js +123 -0
  179. package/lib/issue-sync/reconcile.js +195 -0
  180. package/lib/issue-sync/schema.js +126 -0
  181. package/lib/kernel/backing-issue.js +305 -0
  182. package/lib/kernel/broker.js +1218 -0
  183. package/lib/kernel/cli-broker-factory.js +130 -0
  184. package/lib/kernel/conflict-signal.js +82 -0
  185. package/lib/kernel/evaluators.js +195 -0
  186. package/lib/kernel/fs-class.js +495 -0
  187. package/lib/kernel/issue-command-contract.js +559 -0
  188. package/lib/kernel/issue-id-resolver.js +186 -0
  189. package/lib/kernel/lease-enforcer.js +158 -0
  190. package/lib/kernel/migrations.js +333 -0
  191. package/lib/kernel/planning-buckets-schema.js +109 -0
  192. package/lib/kernel/projection-jsonl-writer.js +450 -0
  193. package/lib/kernel/readiness-model.js +329 -0
  194. package/lib/kernel/schema.js +356 -0
  195. package/lib/kernel/sqlite-driver.js +2504 -0
  196. package/lib/kernel/taxonomy-validator.js +394 -0
  197. package/lib/lefthook-check.js +8 -4
  198. package/lib/lefthook-wiring.js +413 -0
  199. package/lib/mcp-config-renderer.js +288 -0
  200. package/lib/memory/graphiti-mcp.js +106 -0
  201. package/lib/memory/router.js +387 -0
  202. package/lib/memory/typed-api.js +102 -0
  203. package/lib/memory-digest.js +195 -0
  204. package/lib/merge-rules.js +395 -0
  205. package/lib/migrate-dry-run.js +466 -0
  206. package/lib/orientation.js +863 -0
  207. package/lib/package-manager-remediation.js +103 -0
  208. package/lib/package-root.js +381 -0
  209. package/lib/patch-intent.js +890 -0
  210. package/lib/plugin-catalog.js +3 -4
  211. package/lib/plugin-manager.js +0 -5
  212. package/lib/pr-bundle.js +186 -0
  213. package/lib/pr-monitor/differ.js +195 -0
  214. package/lib/pr-monitor/events.js +0 -0
  215. package/lib/pr-monitor/gather.js +124 -0
  216. package/lib/pr-monitor/journal.js +299 -0
  217. package/lib/pr-monitor/monitor.js +146 -0
  218. package/lib/pr-monitor/render-sticky.js +157 -0
  219. package/lib/pr-monitor/watch-lifecycle.js +95 -0
  220. package/lib/pr-monitor/watch.js +247 -0
  221. package/lib/pr-pull.js +1273 -0
  222. package/lib/pr-shepherd.js +494 -0
  223. package/lib/pr-state-validator.js +59 -0
  224. package/lib/preflight/gates.js +237 -0
  225. package/lib/preflight/runner.js +116 -0
  226. package/lib/project-discovery.js +0 -53
  227. package/lib/project-memory.js +166 -0
  228. package/lib/protected-path-manifest.js +281 -0
  229. package/lib/protected-state-surfaces.js +387 -0
  230. package/lib/release-readiness.js +2089 -0
  231. package/lib/reset.js +59 -45
  232. package/lib/review-adapter.js +68 -0
  233. package/lib/rules-sync.js +260 -0
  234. package/lib/runtime-health.js +332 -23
  235. package/lib/safety-config-renderer.js +268 -0
  236. package/lib/setup-action-log.js +1 -7
  237. package/lib/setup.js +27 -65
  238. package/lib/shell-utils.js +76 -6
  239. package/lib/skills-sync.js +330 -0
  240. package/lib/smart-status/conflicts.js +205 -0
  241. package/lib/smart-status/scoring.js +191 -0
  242. package/lib/status/beads-snapshot.js +145 -0
  243. package/lib/status/presenter.js +216 -0
  244. package/lib/status/snapshot.js +186 -0
  245. package/lib/sync-backend.js +202 -0
  246. package/lib/untrusted-content.js +52 -0
  247. package/lib/upgrade-safety.js +199 -0
  248. package/lib/workflow/enforce-stage.js +298 -47
  249. package/lib/workflow/stage-transition.js +115 -0
  250. package/lib/workflow/stages.js +30 -6
  251. package/lib/workflow/state-manager.js +159 -14
  252. package/lib/workflow/state.js +23 -1
  253. package/lib/workflow-profiles.js +17 -5
  254. package/package.json +46 -36
  255. package/rules/documentation.md +19 -0
  256. package/rules/kernel-tracking.md +26 -0
  257. package/rules/security.md +22 -0
  258. package/rules/tdd.md +20 -0
  259. package/rules/workflow.md +27 -0
  260. package/scripts/auto-backing-issue.js +47 -0
  261. package/scripts/beads-context.sh +165 -22
  262. package/scripts/beads-migrate-to-dolt.sh +7 -0
  263. package/scripts/beads-upgrade-smoke.sh +284 -0
  264. package/scripts/behavioral-judge.sh +115 -11
  265. package/scripts/benchmark.js +349 -63
  266. package/scripts/bootstrap-windows-tools.sh +78 -0
  267. package/scripts/branch-protection.js +2 -3
  268. package/scripts/check-agents.js +34 -137
  269. package/scripts/commitlint.js +3 -1
  270. package/scripts/conflict-detect.sh +3 -0
  271. package/scripts/dep-guard-analyze.js +52 -17
  272. package/scripts/dep-guard-keyword-ripple.js +29 -0
  273. package/scripts/dep-guard-render-review.js +86 -0
  274. package/scripts/dep-guard.sh +64 -232
  275. package/scripts/file-index.sh +3 -0
  276. package/scripts/forge-team/lib/claim.sh +34 -18
  277. package/scripts/forge-team/lib/dashboard.sh +61 -86
  278. package/scripts/forge-team/lib/epic.sh +99 -263
  279. package/scripts/forge-team/lib/hooks.sh +26 -28
  280. package/scripts/forge-team/lib/identity.sh +4 -4
  281. package/scripts/forge-team/lib/sync-github.sh +144 -47
  282. package/scripts/forge-team/lib/verify.sh +93 -83
  283. package/scripts/forge-team/lib/workload.sh +41 -65
  284. package/scripts/forge-team/tests/claim.test.sh +25 -19
  285. package/scripts/forge-team/tests/dashboard.test.sh +31 -46
  286. package/scripts/forge-team/tests/epic.test.sh +52 -71
  287. package/scripts/forge-team/tests/hooks.test.sh +38 -50
  288. package/scripts/forge-team/tests/identity.test.sh +3 -3
  289. package/scripts/forge-team/tests/integration.test.sh +44 -66
  290. package/scripts/forge-team/tests/sync-github.test.sh +183 -79
  291. package/scripts/forge-team/tests/verify.test.sh +37 -46
  292. package/scripts/forge-team/tests/workflow-integration.test.sh +4 -4
  293. package/scripts/forge-team/tests/workload.test.sh +32 -66
  294. package/scripts/gen-command-manifest.js +153 -0
  295. package/scripts/gen-embedded-assets.mjs +129 -0
  296. package/scripts/install.ps1 +139 -0
  297. package/scripts/install.sh +268 -0
  298. package/scripts/lib/beads-migrate-to-dolt.mjs +503 -0
  299. package/scripts/lib/release-asset.mjs +84 -0
  300. package/scripts/parity-check.mjs +145 -0
  301. package/scripts/parity-check.test.mjs +58 -0
  302. package/scripts/pin-agentic-workflow-images.js +112 -0
  303. package/scripts/pr-coordinator.sh +3 -0
  304. package/scripts/preflight-sonar.eslint.config.mjs +44 -0
  305. package/scripts/preflight.sh +108 -0
  306. package/scripts/protected-state-check.js +104 -0
  307. package/scripts/smart-status-score.js +31 -0
  308. package/scripts/smart-status-sessions.js +51 -0
  309. package/scripts/smart-status.sh +117 -369
  310. package/scripts/spikes/config-race-bench.js +111 -0
  311. package/scripts/spikes/harness-capability-matrix.js +13 -0
  312. package/scripts/spikes/patch-anchor-stability-bench.js +125 -0
  313. package/scripts/spikes/protected-path-manifest.js +20 -0
  314. package/scripts/spikes/skill-auto-invoke-parity.js +292 -0
  315. package/scripts/sync-agent-skills.js +62 -0
  316. package/scripts/sync-agentic-workflow.js +48 -0
  317. package/scripts/sync-utils.sh +3 -0
  318. package/scripts/test-ci-shard.js +251 -0
  319. package/scripts/test-dashboard.js +188 -52
  320. package/scripts/test-full-suite.js +186 -0
  321. package/scripts/test-profile.js +278 -0
  322. package/scripts/test.js +302 -28
  323. package/scripts/validate.js +143 -0
  324. package/scripts/validate.sh +18 -1
  325. package/skills/claim-safety/SKILL.md +102 -0
  326. package/skills/claim-safety/evals/evals.json +46 -0
  327. package/{.github/prompts/dev.prompt.md → skills/dev/SKILL.md} +46 -52
  328. package/skills/dev/evals/evals.json +50 -0
  329. package/skills/hermes-forge/SKILL.md +185 -0
  330. package/skills/hermes-forge/evals/evals.json +46 -0
  331. package/skills/issue-basics/SKILL.md +111 -0
  332. package/skills/issue-basics/evals/evals.json +46 -0
  333. package/skills/kernel/SKILL.md +166 -0
  334. package/skills/kernel/evals/evals.json +50 -0
  335. package/skills/memory/SKILL.md +102 -0
  336. package/skills/parallel-deep-research/SKILL.md +14 -11
  337. package/skills/parallel-deep-research/evals/evals.json +11 -27
  338. package/{.github/prompts/plan.prompt.md → skills/plan/SKILL.md} +134 -159
  339. package/skills/plan/evals/evals.json +42 -0
  340. package/skills/research/SKILL.md +195 -0
  341. package/skills/research/evals/evals.json +42 -0
  342. package/{.github/prompts/review.prompt.md → skills/review/SKILL.md} +98 -62
  343. package/skills/review/evals/evals.json +42 -0
  344. package/skills/rollback/SKILL.md +110 -0
  345. package/skills/rollback/evals/evals.json +46 -0
  346. package/skills/rollback/references/methods.md +204 -0
  347. package/{.cursor/commands/rollback.md → skills/rollback/references/workflow-integration.md} +10 -284
  348. package/skills/shepherd/SKILL.md +66 -0
  349. package/skills/shepherd/evals/evals.json +42 -0
  350. package/skills/ship/SKILL.md +251 -0
  351. package/skills/ship/evals/evals.json +42 -0
  352. package/skills/smith/SKILL.md +142 -0
  353. package/skills/smith/evals/evals.json +46 -0
  354. package/skills/smith/references/autonomy-and-gates.md +94 -0
  355. package/{.github/prompts/sonarcloud.prompt.md → skills/sonarcloud/SKILL.md} +14 -3
  356. package/skills/sonarcloud/evals/evals.json +46 -0
  357. package/skills/sonarcloud-analysis/SKILL.md +18 -13
  358. package/skills/sonarcloud-analysis/evals/evals.json +11 -15
  359. package/skills/status/SKILL.md +102 -0
  360. package/skills/status/evals/evals.json +50 -0
  361. package/skills/triage-ready/SKILL.md +121 -0
  362. package/skills/triage-ready/evals/evals.json +42 -0
  363. package/{.github/prompts/validate.prompt.md → skills/validate/SKILL.md} +52 -29
  364. package/skills/validate/evals/evals.json +42 -0
  365. package/skills/verify/SKILL.md +299 -0
  366. package/skills/verify/evals/evals.json +50 -0
  367. package/.claude/commands/dev.md +0 -345
  368. package/.claude/commands/plan.md +0 -566
  369. package/.claude/commands/premerge.md +0 -186
  370. package/.claude/commands/research.md +0 -42
  371. package/.claude/commands/review.md +0 -451
  372. package/.claude/commands/rollback.md +0 -721
  373. package/.claude/commands/ship.md +0 -213
  374. package/.claude/commands/sonarcloud.md +0 -152
  375. package/.claude/commands/status.md +0 -90
  376. package/.claude/commands/validate.md +0 -288
  377. package/.claude/commands/verify.md +0 -269
  378. package/.claude/rules/workflow.md +0 -121
  379. package/.cline/workflows/dev.md +0 -342
  380. package/.cline/workflows/plan.md +0 -563
  381. package/.cline/workflows/premerge.md +0 -183
  382. package/.cline/workflows/research.md +0 -39
  383. package/.cline/workflows/review.md +0 -448
  384. package/.cline/workflows/rollback.md +0 -718
  385. package/.cline/workflows/ship.md +0 -210
  386. package/.cline/workflows/sonarcloud.md +0 -146
  387. package/.cline/workflows/status.md +0 -87
  388. package/.cline/workflows/validate.md +0 -285
  389. package/.cline/workflows/verify.md +0 -266
  390. package/.codex/config.toml +0 -11
  391. package/.codex/skills/dev/SKILL.md +0 -345
  392. package/.codex/skills/plan/SKILL.md +0 -566
  393. package/.codex/skills/premerge/SKILL.md +0 -186
  394. package/.codex/skills/research/SKILL.md +0 -42
  395. package/.codex/skills/review/SKILL.md +0 -451
  396. package/.codex/skills/rollback/SKILL.md +0 -721
  397. package/.codex/skills/ship/SKILL.md +0 -213
  398. package/.codex/skills/sonarcloud/SKILL.md +0 -149
  399. package/.codex/skills/status/SKILL.md +0 -90
  400. package/.codex/skills/validate/SKILL.md +0 -288
  401. package/.codex/skills/verify/SKILL.md +0 -269
  402. package/.cursor/commands/dev.md +0 -342
  403. package/.cursor/commands/plan.md +0 -563
  404. package/.cursor/commands/premerge.md +0 -183
  405. package/.cursor/commands/research.md +0 -39
  406. package/.cursor/commands/review.md +0 -448
  407. package/.cursor/commands/ship.md +0 -210
  408. package/.cursor/commands/sonarcloud.md +0 -146
  409. package/.cursor/commands/status.md +0 -87
  410. package/.cursor/commands/validate.md +0 -285
  411. package/.cursor/commands/verify.md +0 -266
  412. package/.cursorrules +0 -149
  413. package/.github/prompts/premerge.prompt.md +0 -188
  414. package/.github/prompts/research.prompt.md +0 -44
  415. package/.github/prompts/rollback.prompt.md +0 -723
  416. package/.github/prompts/ship.prompt.md +0 -215
  417. package/.github/prompts/status.prompt.md +0 -92
  418. package/.github/prompts/verify.prompt.md +0 -271
  419. package/.github/workflows/beads-to-github.yml +0 -56
  420. package/.github/workflows/github-to-beads.yml +0 -97
  421. package/.kilocode/workflows/dev.md +0 -346
  422. package/.kilocode/workflows/plan.md +0 -567
  423. package/.kilocode/workflows/premerge.md +0 -187
  424. package/.kilocode/workflows/research.md +0 -43
  425. package/.kilocode/workflows/review.md +0 -452
  426. package/.kilocode/workflows/rollback.md +0 -722
  427. package/.kilocode/workflows/ship.md +0 -214
  428. package/.kilocode/workflows/sonarcloud.md +0 -150
  429. package/.kilocode/workflows/status.md +0 -91
  430. package/.kilocode/workflows/validate.md +0 -289
  431. package/.kilocode/workflows/verify.md +0 -270
  432. package/.opencode/commands/dev.md +0 -345
  433. package/.opencode/commands/plan.md +0 -566
  434. package/.opencode/commands/premerge.md +0 -186
  435. package/.opencode/commands/research.md +0 -42
  436. package/.opencode/commands/review.md +0 -451
  437. package/.opencode/commands/rollback.md +0 -721
  438. package/.opencode/commands/ship.md +0 -213
  439. package/.opencode/commands/sonarcloud.md +0 -149
  440. package/.opencode/commands/status.md +0 -90
  441. package/.opencode/commands/validate.md +0 -288
  442. package/.opencode/commands/verify.md +0 -269
  443. package/.roo/commands/dev.md +0 -346
  444. package/.roo/commands/plan.md +0 -567
  445. package/.roo/commands/premerge.md +0 -187
  446. package/.roo/commands/research.md +0 -43
  447. package/.roo/commands/review.md +0 -452
  448. package/.roo/commands/rollback.md +0 -722
  449. package/.roo/commands/ship.md +0 -214
  450. package/.roo/commands/sonarcloud.md +0 -150
  451. package/.roo/commands/status.md +0 -91
  452. package/.roo/commands/validate.md +0 -289
  453. package/.roo/commands/verify.md +0 -270
  454. package/docs/BEADS_GITHUB_SYNC.md +0 -255
  455. package/docs/GREPTILE_SETUP.md +0 -400
  456. package/docs/MANUAL_REVIEW_GUIDE.md +0 -106
  457. package/docs/SETUP.md +0 -663
  458. package/docs/VALIDATION.md +0 -363
  459. package/lib/agents/cline.plugin.json +0 -29
  460. package/lib/agents/copilot.plugin.json +0 -24
  461. package/lib/agents/kilocode.plugin.json +0 -22
  462. package/lib/agents/opencode.plugin.json +0 -23
  463. package/lib/agents/roo.plugin.json +0 -30
  464. package/lib/beads-health-check.js +0 -143
  465. package/lib/commands/commands-reset.js +0 -147
  466. package/opencode.json +0 -67
  467. package/scripts/beads-context.test.js +0 -567
  468. package/scripts/github-beads-sync/comment.mjs +0 -64
  469. package/scripts/github-beads-sync/config.mjs +0 -148
  470. package/scripts/github-beads-sync/github-api.mjs +0 -131
  471. package/scripts/github-beads-sync/index.mjs +0 -332
  472. package/scripts/github-beads-sync/label-mapper.mjs +0 -54
  473. package/scripts/github-beads-sync/mapping.mjs +0 -78
  474. package/scripts/github-beads-sync/reverse-sync-cli.mjs +0 -31
  475. package/scripts/github-beads-sync/reverse-sync.mjs +0 -138
  476. package/scripts/github-beads-sync/run-bd.mjs +0 -161
  477. package/scripts/github-beads-sync/sanitize.mjs +0 -121
  478. package/scripts/github-beads-sync.config.json +0 -26
  479. package/scripts/sync-commands.js +0 -600
@@ -0,0 +1,111 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const { performance } = require('node:perf_hooks');
5
+
6
+ function readNumberFlag(args, name, fallback) {
7
+ const index = args.indexOf(name);
8
+ if (index === -1) return fallback;
9
+ const value = Number(args[index + 1]);
10
+ if (!Number.isFinite(value) || value < 0) {
11
+ throw new Error(`${name} must be a non-negative number`);
12
+ }
13
+ return value;
14
+ }
15
+
16
+ function assertPositiveInteger(name, value) {
17
+ if (!Number.isInteger(value) || value <= 0) {
18
+ throw new Error(`${name} must be a positive integer`);
19
+ }
20
+ }
21
+
22
+ function machinePatch(trial, machine) {
23
+ const sharedValue = trial % 10 === 0 ? `shared-${trial}` : undefined;
24
+ const conflictingValue = trial === 37 ? `${machine}-conflict-${trial}` : undefined;
25
+ return {
26
+ machine,
27
+ global: {
28
+ ...(sharedValue ? { 'stage.review.timeout': sharedValue } : {}),
29
+ ...(conflictingValue ? { 'stage.dev.parallelism': conflictingValue } : {}),
30
+ },
31
+ machineLocal: {
32
+ [`${machine}.shell`]: machine === 'machine-a' ? 'git-bash' : 'pwsh',
33
+ [`${machine}.workspace`]: `.forge/machines/${machine}`,
34
+ },
35
+ };
36
+ }
37
+
38
+ function mergeTrial(trial) {
39
+ const left = machinePatch(trial, 'machine-a');
40
+ const right = machinePatch(trial, 'machine-b');
41
+ const merged = { global: {}, machineLocal: {} };
42
+ const conflicts = [];
43
+
44
+ for (const patch of [left, right]) {
45
+ Object.assign(merged.machineLocal, patch.machineLocal);
46
+ }
47
+
48
+ const globalKeys = new Set([...Object.keys(left.global), ...Object.keys(right.global)]);
49
+ for (const key of globalKeys) {
50
+ const leftHas = Object.prototype.hasOwnProperty.call(left.global, key);
51
+ const rightHas = Object.prototype.hasOwnProperty.call(right.global, key);
52
+ if (leftHas && rightHas && left.global[key] !== right.global[key]) {
53
+ conflicts.push(key);
54
+ continue;
55
+ }
56
+ merged.global[key] = leftHas ? left.global[key] : right.global[key];
57
+ }
58
+
59
+ return {
60
+ trial,
61
+ manualResolve: conflicts.length > 0,
62
+ conflicts,
63
+ mergedKeyCount: Object.keys(merged.global).length + Object.keys(merged.machineLocal).length,
64
+ };
65
+ }
66
+
67
+ function runBench(options = {}) {
68
+ const trials = options.trials ?? 50;
69
+ const threshold = options.threshold ?? 0.05;
70
+ assertPositiveInteger('trials', trials);
71
+
72
+ const start = performance.now();
73
+ const results = Array.from({ length: trials }, (_, index) => mergeTrial(index + 1));
74
+ const manualResolves = results.filter((result) => result.manualResolve);
75
+ const manualResolveRate = manualResolves.length / trials;
76
+ const elapsedMs = performance.now() - start;
77
+
78
+ return {
79
+ spike: 'cross-machine-config-race',
80
+ trials,
81
+ manualResolves: manualResolves.length,
82
+ manualResolveRate,
83
+ threshold,
84
+ passed: manualResolveRate < threshold,
85
+ elapsedMs: Number(elapsedMs.toFixed(3)),
86
+ complexity: 'O(trials * changed keys); machine-local files avoid shared-file git conflicts',
87
+ conflictTrials: manualResolves.map((result) => ({
88
+ trial: result.trial,
89
+ conflicts: result.conflicts,
90
+ })),
91
+ };
92
+ }
93
+
94
+ function main() {
95
+ const args = process.argv.slice(2);
96
+ const result = runBench({
97
+ trials: readNumberFlag(args, '--trials', 50),
98
+ threshold: readNumberFlag(args, '--threshold', 0.05),
99
+ });
100
+
101
+ console.log(JSON.stringify(result, null, args.includes('--json') ? 0 : 2));
102
+ if (!result.passed) {
103
+ process.exitCode = 1;
104
+ }
105
+ }
106
+
107
+ if (require.main === module) {
108
+ main();
109
+ }
110
+
111
+ module.exports = { runBench, mergeTrial };
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const { buildHarnessCapabilityEvidence } = require('../../lib/harness-capability-matrix');
5
+
6
+ function main() {
7
+ const evidence = buildHarnessCapabilityEvidence();
8
+ console.log(JSON.stringify(evidence, null, 2));
9
+ }
10
+
11
+ if (require.main === module) {
12
+ main();
13
+ }
@@ -0,0 +1,125 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const { performance } = require('node:perf_hooks');
5
+
6
+ function readNumberFlag(args, name, fallback) {
7
+ const index = args.indexOf(name);
8
+ if (index === -1) return fallback;
9
+ const value = Number(args[index + 1]);
10
+ if (!Number.isFinite(value) || value < 0) {
11
+ throw new Error(`${name} must be a non-negative number`);
12
+ }
13
+ return value;
14
+ }
15
+
16
+ function assertPositiveInteger(name, value) {
17
+ if (!Number.isInteger(value) || value <= 0) {
18
+ throw new Error(`${name} must be a positive integer`);
19
+ }
20
+ }
21
+
22
+ function assertNonNegativeInteger(name, value) {
23
+ if (!Number.isInteger(value) || value < 0) {
24
+ throw new Error(`${name} must be a non-negative integer`);
25
+ }
26
+ }
27
+
28
+ function runBench(options = {}) {
29
+ const anchorCount = options.anchorCount ?? 500;
30
+ const patchCount = options.patchCount ?? 50;
31
+ const renameCount = options.renameCount ?? patchCount;
32
+ const unmappedCount = options.unmappedCount ?? 2;
33
+ const threshold = options.threshold ?? 0.10;
34
+
35
+ assertPositiveInteger('anchorCount', anchorCount);
36
+ assertPositiveInteger('patchCount', patchCount);
37
+ assertNonNegativeInteger('renameCount', renameCount);
38
+ assertNonNegativeInteger('unmappedCount', unmappedCount);
39
+ if (patchCount > anchorCount) {
40
+ throw new Error('patchCount must be <= anchorCount');
41
+ }
42
+ if (renameCount > patchCount) {
43
+ throw new Error('renameCount must be <= patchCount');
44
+ }
45
+ if (unmappedCount > renameCount) {
46
+ throw new Error('unmappedCount must be <= renameCount');
47
+ }
48
+
49
+ const start = performance.now();
50
+ const oldAnchors = Array.from({ length: anchorCount }, (_, i) => `stage.${i}.body`);
51
+ const patches = oldAnchors.slice(0, patchCount).map((anchor, i) => ({
52
+ id: `patch-${String(i + 1).padStart(3, '0')}`,
53
+ anchor,
54
+ }));
55
+
56
+ const currentAnchors = new Set(oldAnchors);
57
+ const aliases = new Map();
58
+ for (let i = 0; i < renameCount; i += 1) {
59
+ const oldAnchor = oldAnchors[i];
60
+ const newAnchor = `${oldAnchor}.v2`;
61
+ currentAnchors.delete(oldAnchor);
62
+ currentAnchors.add(newAnchor);
63
+ if (i >= unmappedCount) {
64
+ aliases.set(oldAnchor, newAnchor);
65
+ }
66
+ }
67
+
68
+ let resolved = 0;
69
+ let orphaned = 0;
70
+ const orphanIds = [];
71
+ for (const patch of patches) {
72
+ if (currentAnchors.has(patch.anchor)) {
73
+ resolved += 1;
74
+ continue;
75
+ }
76
+ const alias = aliases.get(patch.anchor);
77
+ if (alias && currentAnchors.has(alias)) {
78
+ resolved += 1;
79
+ continue;
80
+ }
81
+ orphaned += 1;
82
+ orphanIds.push(patch.id);
83
+ }
84
+
85
+ const elapsedMs = performance.now() - start;
86
+ const orphanRate = orphaned / patchCount;
87
+ return {
88
+ spike: 'patch-anchor-stability',
89
+ patchCount,
90
+ anchorCount,
91
+ renamedAnchors: renameCount,
92
+ aliasEntries: aliases.size,
93
+ orphaned,
94
+ resolved,
95
+ orphanRate,
96
+ threshold,
97
+ passed: orphanRate < threshold,
98
+ elapsedMs: Number(elapsedMs.toFixed(3)),
99
+ complexity: 'O(patches + anchors + aliases) with Map/Set lookups',
100
+ orphanIds,
101
+ };
102
+ }
103
+
104
+ function main() {
105
+ const args = process.argv.slice(2);
106
+ const patchCount = readNumberFlag(args, '--patches', 50);
107
+ const result = runBench({
108
+ anchorCount: readNumberFlag(args, '--anchors', 500),
109
+ patchCount,
110
+ renameCount: readNumberFlag(args, '--renames', patchCount),
111
+ unmappedCount: readNumberFlag(args, '--unmapped', 2),
112
+ threshold: readNumberFlag(args, '--threshold', 0.10),
113
+ });
114
+
115
+ console.log(JSON.stringify(result, null, args.includes('--json') ? 0 : 2));
116
+ if (!result.passed) {
117
+ process.exitCode = 1;
118
+ }
119
+ }
120
+
121
+ if (require.main === module) {
122
+ main();
123
+ }
124
+
125
+ module.exports = { runBench };
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const path = require('node:path');
5
+ const {
6
+ buildProtectedPathManifestEvidence,
7
+ loadProtectedPathManifest,
8
+ } = require('../../lib/protected-path-manifest');
9
+
10
+ const root = path.resolve(__dirname, '..', '..');
11
+ const manifestPath = path.join(root, '.forge', 'protected-paths.yaml');
12
+
13
+ try {
14
+ const manifest = loadProtectedPathManifest(manifestPath);
15
+ process.stdout.write(`${JSON.stringify(buildProtectedPathManifestEvidence(manifest), null, 2)}\n`);
16
+ } catch (error) {
17
+ const message = error instanceof Error ? error.message : String(error);
18
+ process.stderr.write(`Failed to build protected path manifest evidence from ${manifestPath}: ${message}\n`);
19
+ process.exit(1);
20
+ }
@@ -0,0 +1,292 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const fs = require('node:fs');
5
+ const os = require('node:os');
6
+ const path = require('node:path');
7
+ const YAML = require('yaml');
8
+
9
+ const CANONICAL_SKILL = {
10
+ name: 'guard-rails-audit',
11
+ description: 'Use when asked to inspect Forge L1 rail enforcement, audit events, or protected path policy.',
12
+ body: [
13
+ '# Guard Rails Audit',
14
+ '',
15
+ 'Check Forge L1 rails, audit-event coverage, and protected path policy before recommending changes.',
16
+ ].join('\n'),
17
+ };
18
+
19
+ const MATCHING_PROMPT = 'Inspect Forge L1 rail enforcement and audit events for protected path policy.';
20
+ const NON_MATCHING_PROMPT = 'Draft release notes for a minor README copy edit.';
21
+ const FIXTURE_FILE = 'src/index.js';
22
+
23
+ const SOURCES = [
24
+ {
25
+ label: 'S1',
26
+ harness: 'claude-code',
27
+ url: 'https://code.claude.com/docs/en/skills',
28
+ summary: 'Claude Code project skills live under .claude/skills/<skill>/SKILL.md and use description metadata for automatic invocation.',
29
+ },
30
+ {
31
+ label: 'S2',
32
+ harness: 'cursor',
33
+ url: 'https://docs.cursor.com/en/context',
34
+ summary: 'Cursor Project Rules live under .cursor/rules as .mdc files; Agent Requested rules are description-driven.',
35
+ },
36
+ {
37
+ label: 'S3',
38
+ harness: 'codex-cli',
39
+ url: 'https://github.com/openai/codex/blob/main/codex-rs/skills/src/assets/samples/skill-creator/SKILL.md',
40
+ summary: 'Codex skills use SKILL.md frontmatter name and description to determine when the skill gets used.',
41
+ },
42
+ {
43
+ label: 'S4',
44
+ harness: 'forge',
45
+ url: 'lib/codex-skills.js',
46
+ summary: 'Forge packages repository Codex skills from .codex/skills for installation into $CODEX_HOME/skills.',
47
+ },
48
+ ];
49
+
50
+ const HARNESS_TARGETS = [
51
+ {
52
+ harness: 'claude-code',
53
+ target: '.claude/skills/guard-rails-audit/SKILL.md',
54
+ explicitInvocation: '/guard-rails-audit',
55
+ sourceLabel: 'S1',
56
+ source: 'Claude Code skill directory target',
57
+ buildFrontmatter: () => ({
58
+ name: CANONICAL_SKILL.name,
59
+ description: CANONICAL_SKILL.description,
60
+ }),
61
+ },
62
+ {
63
+ harness: 'cursor',
64
+ target: '.cursor/rules/guard-rails-audit.mdc',
65
+ explicitInvocation: '/guard-rails-audit',
66
+ sourceLabel: 'S2',
67
+ source: 'Cursor project rule with documented description/globs/alwaysApply metadata',
68
+ buildFrontmatter: () => ({
69
+ description: CANONICAL_SKILL.description,
70
+ globs: null,
71
+ alwaysApply: false,
72
+ }),
73
+ },
74
+ {
75
+ harness: 'codex-cli',
76
+ target: '.codex/skills/guard-rails-audit/SKILL.md',
77
+ explicitInvocation: '/guard-rails-audit',
78
+ sourceLabel: 'S4',
79
+ source: 'Forge repository Codex skills package surface; custom slash prompt files are intentionally not used',
80
+ buildFrontmatter: () => ({
81
+ name: CANONICAL_SKILL.name,
82
+ description: CANONICAL_SKILL.description,
83
+ }),
84
+ },
85
+ ];
86
+
87
+ function buildMarkdown(frontmatter, body) {
88
+ return `---\n${YAML.stringify(frontmatter, {
89
+ lineWidth: 0,
90
+ defaultKeyType: 'PLAIN',
91
+ defaultStringType: 'PLAIN',
92
+ }).trimEnd()}\n---\n\n${body}\n`;
93
+ }
94
+
95
+ function parseFrontmatter(content) {
96
+ const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?/);
97
+ if (!match) return {};
98
+ const parsed = YAML.parse(match[1]);
99
+ return parsed && typeof parsed === 'object' ? parsed : {};
100
+ }
101
+
102
+ function writeFile(root, relativePath, content) {
103
+ const absolutePath = path.join(root, relativePath);
104
+ fs.mkdirSync(path.dirname(absolutePath), { recursive: true });
105
+ fs.writeFileSync(absolutePath, content);
106
+ }
107
+
108
+ function isDirectoryEmpty(directory) {
109
+ return !fs.existsSync(directory) || fs.readdirSync(directory).length === 0;
110
+ }
111
+
112
+ function materializeFixture(root) {
113
+ if (!isDirectoryEmpty(root)) {
114
+ throw new Error(`fixture directory must be empty: ${root}`);
115
+ }
116
+
117
+ fs.mkdirSync(root, { recursive: true });
118
+ writeFile(root, FIXTURE_FILE, 'export function fixture() { return true; }\n');
119
+
120
+ for (const target of HARNESS_TARGETS) {
121
+ writeFile(
122
+ root,
123
+ target.target,
124
+ buildMarkdown(target.buildFrontmatter(), CANONICAL_SKILL.body),
125
+ );
126
+ }
127
+
128
+ return { root, skill: CANONICAL_SKILL, targets: HARNESS_TARGETS };
129
+ }
130
+
131
+ function tokens(value) {
132
+ return String(value)
133
+ .toLowerCase()
134
+ .match(/[a-z0-9]+/g)
135
+ ?.filter((token) => token.length >= 4) || [];
136
+ }
137
+
138
+ function descriptionMatches(description, prompt) {
139
+ const promptTokens = new Set(tokens(prompt));
140
+ const triggerTokens = tokens(description)
141
+ .filter((token) => !['when', 'asked', 'inspect'].includes(token));
142
+
143
+ return triggerTokens.some((token) => promptTokens.has(token));
144
+ }
145
+
146
+ function cursorGlobMatches(globs, filePath) {
147
+ void filePath;
148
+ if (!Array.isArray(globs) || globs.length === 0) return true;
149
+ return globs.includes('**/*') || globs.includes(filePath);
150
+ }
151
+
152
+ function validateHarness(root, target) {
153
+ const absolutePath = path.join(root, target.target);
154
+ const failures = [];
155
+
156
+ if (!fs.existsSync(absolutePath)) {
157
+ failures.push(`missing ${target.target}`);
158
+ return { ...target, passed: false, failures };
159
+ }
160
+
161
+ const frontmatter = parseFrontmatter(fs.readFileSync(absolutePath, 'utf8'));
162
+ const description = frontmatter.description;
163
+ const positiveMatch = descriptionMatches(description, MATCHING_PROMPT);
164
+ const negativeMatch = descriptionMatches(description, NON_MATCHING_PROMPT);
165
+
166
+ if (description !== CANONICAL_SKILL.description) {
167
+ failures.push('description does not match canonical skill description');
168
+ }
169
+ if (!positiveMatch) {
170
+ failures.push('matching prompt did not select the skill by description');
171
+ }
172
+ if (negativeMatch) {
173
+ failures.push('unrelated prompt selected the skill');
174
+ }
175
+ if (target.explicitInvocation !== `/${CANONICAL_SKILL.name}`) {
176
+ failures.push('explicit slash invocation does not match canonical skill name');
177
+ }
178
+
179
+ if (target.harness === 'claude-code') {
180
+ if (frontmatter.name !== CANONICAL_SKILL.name) failures.push('Claude skill name is missing or incorrect');
181
+ }
182
+
183
+ if (target.harness === 'cursor') {
184
+ if (frontmatter.alwaysApply !== false) failures.push('Cursor rule must keep alwaysApply: false for request-time selection');
185
+ if (!cursorGlobMatches(frontmatter.globs, FIXTURE_FILE)) failures.push(`Cursor globs do not include ${FIXTURE_FILE}`);
186
+ }
187
+
188
+ if (target.harness === 'codex-cli') {
189
+ if (!target.target.startsWith('.codex/skills/') || target.target.includes('/prompts/')) {
190
+ failures.push('Codex target must use .codex/skills, not undocumented prompt/slash files');
191
+ }
192
+ }
193
+
194
+ return {
195
+ ...target,
196
+ passed: failures.length === 0,
197
+ descriptionMatched: positiveMatch,
198
+ negativePromptIgnored: !negativeMatch,
199
+ frontmatter,
200
+ failures,
201
+ };
202
+ }
203
+
204
+ function runParity(options = {}) {
205
+ const root = options.fixtureDir || fs.mkdtempSync(path.join(os.tmpdir(), 'forge-w0-harness-parity-'));
206
+ const cleanup = options.fixtureDir ? false : options.cleanup !== false;
207
+
208
+ try {
209
+ materializeFixture(root);
210
+ const harnesses = HARNESS_TARGETS.map((target) => validateHarness(root, target));
211
+ const passed = harnesses.every((result) => result.passed);
212
+ const feasibleCount = harnesses.filter((result) => result.passed).length;
213
+ const knownIssues = passed ? [] : [{
214
+ issue: 'Cross-harness skill render parity did not pass for all three target harnesses.',
215
+ d38: 'D38 kills v3 if two of Claude/Cursor/Codex cannot render a single skill correctly by the W3 checkpoint.',
216
+ feasibleCount,
217
+ }];
218
+
219
+ return {
220
+ fixture: 'w0-skill-auto-invoke-parity',
221
+ fixtureRoot: root,
222
+ matchingPrompt: MATCHING_PROMPT,
223
+ nonMatchingPrompt: NON_MATCHING_PROMPT,
224
+ canonicalSkill: CANONICAL_SKILL,
225
+ harnesses,
226
+ sources: SOURCES,
227
+ proofBoundary: {
228
+ level: 'metadata-surface',
229
+ liveAgentInvocation: 'not-run',
230
+ codexRuntimeDiscovery: 'not-run',
231
+ reason: 'closed-source harness model invocation is outside this deterministic fixture; .codex/skills is the Forge repository packaging surface, not proof of direct Codex runtime discovery',
232
+ },
233
+ passed,
234
+ knownIssues,
235
+ };
236
+ } finally {
237
+ if (cleanup) fs.rmSync(root, { recursive: true, force: true });
238
+ }
239
+ }
240
+
241
+ function printText(result) {
242
+ console.log(`W0 skill auto-invoke parity: ${result.passed ? 'PASS' : 'FAIL'}`);
243
+ for (const harness of result.harnesses) {
244
+ const status = harness.passed ? 'PASS' : 'FAIL';
245
+ console.log(`${status} ${harness.harness} ${harness.target}`);
246
+ for (const failure of harness.failures) {
247
+ console.log(` - ${failure}`);
248
+ }
249
+ }
250
+ if (result.knownIssues.length > 0) {
251
+ for (const issue of result.knownIssues) {
252
+ console.log(`Known issue: ${issue.issue} ${issue.d38}`);
253
+ }
254
+ }
255
+ }
256
+
257
+ function readStringFlag(args, name) {
258
+ const index = args.indexOf(name);
259
+ if (index === -1) return undefined;
260
+ const value = args[index + 1];
261
+ if (!value || value.startsWith('-')) return undefined;
262
+ return value;
263
+ }
264
+
265
+ function main() {
266
+ const args = process.argv.slice(2);
267
+ const result = runParity({ fixtureDir: readStringFlag(args, '--fixture-dir') });
268
+
269
+ if (args.includes('--json')) {
270
+ console.log(JSON.stringify(result));
271
+ } else {
272
+ printText(result);
273
+ }
274
+
275
+ if (!result.passed) process.exitCode = 1;
276
+ }
277
+
278
+ if (require.main === module) {
279
+ main();
280
+ }
281
+
282
+ module.exports = {
283
+ CANONICAL_SKILL,
284
+ HARNESS_TARGETS,
285
+ MATCHING_PROMPT,
286
+ NON_MATCHING_PROMPT,
287
+ SOURCES,
288
+ descriptionMatches,
289
+ materializeFixture,
290
+ parseFrontmatter,
291
+ runParity,
292
+ };
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * Pre-commit auto-sync for the committed `.agents/skills` mirror.
6
+ *
7
+ * `.agents/skills` is Codex's repo-local discovery path and the ONE skill mirror
8
+ * committed to the repo (so a teammate who clones WITHOUT running `forge setup`
9
+ * still gets Forge skills/stages auto-discovered). It must stay byte-identical to
10
+ * the canonical `skills/` source, which the structural drift gate enforces.
11
+ *
12
+ * This hook removes the regen friction: whenever `skills/**` is staged, it
13
+ * regenerates `.agents/skills` from `skills/` (reusing the same
14
+ * `populateCodexRepoSkills` / `populateAgentSkills` sync the drift gate checks
15
+ * against) and re-stages it, so the committed mirror never drifts from canonical.
16
+ *
17
+ * It is intentionally scoped to `skills/**` via lefthook's `glob`, so it only runs
18
+ * when the canonical source actually changes.
19
+ */
20
+
21
+ const path = require('node:path');
22
+ const { execFileSync } = require('node:child_process');
23
+ const { populateCodexRepoSkills, resolveCodexRepoSkillsDir } = require('../lib/codex-skills');
24
+
25
+ function repoRoot() {
26
+ try {
27
+ return execFileSync('git', ['rev-parse', '--show-toplevel'], {
28
+ encoding: 'utf8',
29
+ stdio: ['ignore', 'pipe', 'ignore'],
30
+ }).trim();
31
+ } catch {
32
+ return path.resolve(__dirname, '..');
33
+ }
34
+ }
35
+
36
+ function main() {
37
+ const root = repoRoot();
38
+ let written = [];
39
+ try {
40
+ // clean: true so skills removed from canonical are dropped from the mirror too.
41
+ ({ written } = populateCodexRepoSkills({ sourceRoot: root, projectRoot: root, clean: true }));
42
+ } catch (error) {
43
+ console.error(`sync-agent-skills: failed to regenerate .agents/skills — ${error.message}`);
44
+ process.exit(1);
45
+ }
46
+
47
+ const mirror = resolveCodexRepoSkillsDir(root);
48
+ try {
49
+ // Stage the regenerated mirror (and any deletions within it).
50
+ execFileSync('git', ['add', '--all', '--', mirror], {
51
+ cwd: root,
52
+ stdio: ['ignore', 'ignore', 'inherit'],
53
+ });
54
+ } catch (error) {
55
+ console.error(`sync-agent-skills: failed to stage .agents/skills — ${error.message}`);
56
+ process.exit(1);
57
+ }
58
+
59
+ console.log(`sync-agent-skills: .agents/skills in sync with skills/ (${written.length} skills)`);
60
+ }
61
+
62
+ main();
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require('node:fs');
4
+ const path = require('node:path');
5
+
6
+ const rootDir = path.join(__dirname, '..');
7
+ const sourceDir = path.join(rootDir, '.github', 'agentic-workflows');
8
+ const targetDir = path.join(rootDir, '.github', 'workflows');
9
+
10
+ function syncFile(fileName, checkOnly) {
11
+ const sourcePath = path.join(sourceDir, fileName);
12
+ const targetPath = path.join(targetDir, fileName);
13
+ const source = fs.readFileSync(sourcePath, 'utf8');
14
+ const target = fs.existsSync(targetPath) ? fs.readFileSync(targetPath, 'utf8') : null;
15
+
16
+ if (source === target) {
17
+ return { changed: false, fileName };
18
+ }
19
+
20
+ if (checkOnly) {
21
+ return { changed: true, fileName };
22
+ }
23
+
24
+ fs.mkdirSync(path.dirname(targetPath), { recursive: true });
25
+ fs.writeFileSync(targetPath, source);
26
+ return { changed: true, fileName };
27
+ }
28
+
29
+ function main() {
30
+ const checkOnly = process.argv.includes('--check');
31
+ const fileNames = fs.readdirSync(sourceDir).filter((file) => file === 'behavioral-test.md' || file === 'behavioral-test.lock.yml');
32
+ const results = fileNames.map((fileName) => syncFile(fileName, checkOnly));
33
+ const changed = results.filter((result) => result.changed);
34
+
35
+ if (checkOnly && changed.length > 0) {
36
+ console.error(`Agentic workflow files out of sync: ${changed.map((result) => result.fileName).join(', ')}`);
37
+ process.exit(1);
38
+ }
39
+
40
+ if (changed.length === 0) {
41
+ console.log('Agentic workflow files already in sync');
42
+ return;
43
+ }
44
+
45
+ console.log(`Synced agentic workflow files: ${changed.map((result) => result.fileName).join(', ')}`);
46
+ }
47
+
48
+ main();
@@ -13,6 +13,9 @@ fi
13
13
 
14
14
  # Source shared sanitize library
15
15
  _SU_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
16
+ if [[ -f "$_SU_SCRIPT_DIR/bootstrap-windows-tools.sh" ]]; then
17
+ source "$_SU_SCRIPT_DIR/bootstrap-windows-tools.sh"
18
+ fi
16
19
  source "$_SU_SCRIPT_DIR/lib/sanitize.sh"
17
20
 
18
21
  # ── Session Identity ───────────────────────────────────────────────────