forge-workflow 0.0.10 → 0.1.0-beta.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 (468) 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 +82 -5
  5. package/.forge/hooks/forge-native-hook.js +431 -0
  6. package/.forge/protected-paths.yaml +157 -0
  7. package/AGENTS.md +151 -61
  8. package/CHANGELOG.md +709 -0
  9. package/CLAUDE.md +9 -118
  10. package/QUICKSTART.md +175 -0
  11. package/README.md +275 -365
  12. package/bin/forge-cmd.js +120 -9
  13. package/bin/forge-preflight.js +26 -5
  14. package/bin/forge.js +532 -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/forge/TOOLCHAIN.md +670 -0
  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 +121 -0
  29. package/docs/guides/SUPPORT.md +190 -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 +214 -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/{TOOLCHAIN.md → reference/TOOLCHAIN.md} +62 -47
  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 +155 -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/activation/ensure-forge-home.js +135 -0
  67. package/lib/adapter-cli.js +307 -0
  68. package/lib/adapters/beads-issue-adapter.js +127 -0
  69. package/lib/adapters/beads-kernel-compat.js +1109 -0
  70. package/lib/adapters/greptile-review-adapter.js +141 -0
  71. package/lib/adapters/kernel-issue-adapter.js +101 -0
  72. package/lib/adapters/pr-state-adapter.js +484 -0
  73. package/lib/adoption-profiles.js +139 -0
  74. package/lib/agents/README.md +2 -6
  75. package/lib/agents/claude.plugin.json +3 -8
  76. package/lib/agents/codex.plugin.json +9 -1
  77. package/lib/agents/cursor.plugin.json +2 -6
  78. package/lib/agents/hermes.plugin.json +22 -0
  79. package/lib/agents-config.js +39 -1236
  80. package/lib/audit-evidence.js +282 -0
  81. package/lib/beads-detect.js +60 -0
  82. package/lib/beads-nudge.js +91 -0
  83. package/lib/beads-setup.js +121 -0
  84. package/lib/beads-sync-scaffold.js +25 -101
  85. package/lib/codex-skills.js +51 -1
  86. package/lib/commands/_aliases.js +248 -0
  87. package/lib/commands/_issue.js +780 -77
  88. package/lib/commands/_manifest.js +93 -0
  89. package/lib/commands/_registry.js +99 -34
  90. package/lib/commands/_resolve-command-opts.js +230 -0
  91. package/lib/commands/_serve-security.js +270 -0
  92. package/lib/commands/adapter.js +12 -0
  93. package/lib/commands/add.js +118 -0
  94. package/lib/commands/audit.js +70 -0
  95. package/lib/commands/blocked.js +5 -0
  96. package/lib/commands/board.js +64 -0
  97. package/lib/commands/claim.js +21 -2
  98. package/lib/commands/claims.js +7 -0
  99. package/lib/commands/clean.js +485 -75
  100. package/lib/commands/close.js +2 -2
  101. package/lib/commands/comment.js +5 -0
  102. package/lib/commands/control.js +148 -0
  103. package/lib/commands/create.js +2 -2
  104. package/lib/commands/dev.js +185 -7
  105. package/lib/commands/doc-gate.js +336 -0
  106. package/lib/commands/doctor.js +156 -0
  107. package/lib/commands/explain.js +15 -0
  108. package/lib/commands/export.js +237 -0
  109. package/lib/commands/gate.js +209 -0
  110. package/lib/commands/hooks.js +377 -0
  111. package/lib/commands/inbox.js +118 -0
  112. package/lib/commands/init.js +604 -0
  113. package/lib/commands/insights.js +79 -0
  114. package/lib/commands/issue.js +12 -1
  115. package/lib/commands/issues.js +17 -0
  116. package/lib/commands/lint.js +5 -0
  117. package/lib/commands/list.js +2 -2
  118. package/lib/commands/memory.js +81 -0
  119. package/lib/commands/merge.js +312 -0
  120. package/lib/commands/migrate.js +362 -0
  121. package/lib/commands/new.js +12 -0
  122. package/lib/commands/options.js +241 -0
  123. package/lib/commands/orient.js +13 -0
  124. package/lib/commands/orphans.js +5 -0
  125. package/lib/commands/patch.js +67 -0
  126. package/lib/commands/plan.js +481 -29
  127. package/lib/commands/pr.js +88 -0
  128. package/lib/commands/preflight.js +211 -0
  129. package/lib/commands/prime.js +13 -0
  130. package/lib/commands/push.js +135 -2
  131. package/lib/commands/ready.js +2 -2
  132. package/lib/commands/recall.js +171 -0
  133. package/lib/commands/recap.js +75 -0
  134. package/lib/commands/recommend.js +0 -1
  135. package/lib/commands/release.js +104 -0
  136. package/lib/commands/remember.js +140 -0
  137. package/lib/commands/role.js +99 -0
  138. package/lib/commands/serve.js +581 -0
  139. package/lib/commands/setup.js +900 -971
  140. package/lib/commands/shepherd.js +501 -0
  141. package/lib/commands/ship.js +59 -1
  142. package/lib/commands/show.js +2 -2
  143. package/lib/commands/stage.js +192 -0
  144. package/lib/commands/stale.js +5 -0
  145. package/lib/commands/status.js +158 -21
  146. package/lib/commands/sync.js +34 -46
  147. package/lib/commands/team.js +4 -1
  148. package/lib/commands/test.js +43 -27
  149. package/lib/commands/update.js +2 -2
  150. package/lib/commands/upgrade.js +47 -0
  151. package/lib/commands/validate.js +43 -18
  152. package/lib/commands/worktree.js +362 -99
  153. package/lib/config-writer.js +202 -0
  154. package/lib/control-plane.js +236 -0
  155. package/lib/core/runtime-graph.js +977 -0
  156. package/lib/dep-guard/keyword-ripple.js +2 -2
  157. package/lib/deprecated-sync-cleanup.js +362 -0
  158. package/lib/detect-agent.js +2 -28
  159. package/lib/detect-worktree.js +35 -9
  160. package/lib/doc-gate/declaration.js +177 -0
  161. package/lib/doc-gate/detect.js +289 -0
  162. package/lib/doc-gate/gate.js +375 -0
  163. package/lib/doc-gate/okf-config.js +128 -0
  164. package/lib/doc-gate/okf.js +429 -0
  165. package/lib/docs-command.js +1161 -6
  166. package/lib/forge-issues.js +382 -11
  167. package/lib/forge-lock.js +262 -0
  168. package/lib/gate-events.js +192 -0
  169. package/lib/global-flags.js +104 -0
  170. package/lib/greptile-match.js +7 -63
  171. package/lib/grounding/context-events.js +230 -0
  172. package/lib/grounding/read-first.js +112 -0
  173. package/lib/harness-capability-matrix.js +380 -0
  174. package/lib/hook-global-installer.js +347 -0
  175. package/lib/hook-renderer.js +541 -0
  176. package/lib/inbox.js +391 -0
  177. package/lib/insights.js +397 -0
  178. package/lib/issue-adapter.js +156 -0
  179. package/lib/issue-backend.js +145 -0
  180. package/lib/issue-render.js +220 -0
  181. package/lib/kernel/backing-issue.js +311 -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/owned-kernel.js +43 -0
  192. package/lib/kernel/planning-buckets-schema.js +109 -0
  193. package/lib/kernel/projection-jsonl-writer.js +450 -0
  194. package/lib/kernel/readiness-model.js +329 -0
  195. package/lib/kernel/schema.js +356 -0
  196. package/lib/kernel/sqlite-driver.js +2540 -0
  197. package/lib/kernel/taxonomy-validator.js +394 -0
  198. package/lib/lefthook-check.js +3 -2
  199. package/lib/lefthook-wiring.js +413 -0
  200. package/lib/mcp-config-renderer.js +288 -0
  201. package/lib/memory/graphiti-mcp.js +106 -0
  202. package/lib/memory/router.js +387 -0
  203. package/lib/memory/typed-api.js +102 -0
  204. package/lib/memory-digest.js +195 -0
  205. package/lib/merge-rules.js +395 -0
  206. package/lib/migrate-dry-run.js +466 -0
  207. package/lib/orientation.js +863 -0
  208. package/lib/package-manager-remediation.js +103 -0
  209. package/lib/package-root.js +381 -0
  210. package/lib/patch-intent.js +890 -0
  211. package/lib/plugin-catalog.js +3 -4
  212. package/lib/plugin-manager.js +0 -5
  213. package/lib/pr-bundle.js +186 -0
  214. package/lib/pr-monitor/auto-actions.js +175 -0
  215. package/lib/pr-monitor/differ.js +195 -0
  216. package/lib/pr-monitor/digest.js +206 -0
  217. package/lib/pr-monitor/events.js +0 -0
  218. package/lib/pr-monitor/gather.js +124 -0
  219. package/lib/pr-monitor/journal.js +299 -0
  220. package/lib/pr-monitor/monitor.js +146 -0
  221. package/lib/pr-monitor/render-sticky.js +192 -0
  222. package/lib/pr-monitor/upsert-sticky.js +169 -0
  223. package/lib/pr-monitor/watch-lifecycle.js +95 -0
  224. package/lib/pr-monitor/watch.js +247 -0
  225. package/lib/pr-pull.js +1314 -0
  226. package/lib/pr-shepherd.js +494 -0
  227. package/lib/pr-state-validator.js +59 -0
  228. package/lib/preflight/gates.js +237 -0
  229. package/lib/preflight/runner.js +116 -0
  230. package/lib/project-discovery.js +0 -53
  231. package/lib/project-memory.js +99 -497
  232. package/lib/protected-path-manifest.js +281 -0
  233. package/lib/protected-state-surfaces.js +387 -0
  234. package/lib/release-readiness.js +2105 -0
  235. package/lib/reset.js +59 -45
  236. package/lib/review-adapter.js +68 -0
  237. package/lib/rules-sync.js +260 -0
  238. package/lib/runtime-health.js +241 -20
  239. package/lib/safety-config-renderer.js +268 -0
  240. package/lib/setup-action-log.js +1 -7
  241. package/lib/setup.js +27 -65
  242. package/lib/shell-utils.js +76 -6
  243. package/lib/skills-sync.js +330 -0
  244. package/lib/smart-status/scoring.js +17 -3
  245. package/lib/status/beads-snapshot.js +45 -2
  246. package/lib/status/presenter.js +169 -18
  247. package/lib/status/snapshot.js +186 -0
  248. package/lib/sync-backend.js +202 -0
  249. package/lib/untrusted-content.js +52 -0
  250. package/lib/upgrade-safety.js +251 -0
  251. package/lib/workflow/enforce-stage.js +351 -45
  252. package/lib/workflow/stage-transition.js +115 -0
  253. package/lib/workflow/stages.js +30 -6
  254. package/lib/workflow/state-manager.js +11 -22
  255. package/lib/workflow/state.js +23 -1
  256. package/lib/workflow-profiles.js +17 -5
  257. package/package.json +37 -35
  258. package/rules/documentation.md +19 -0
  259. package/rules/kernel-tracking.md +26 -0
  260. package/rules/security.md +22 -0
  261. package/rules/tdd.md +20 -0
  262. package/rules/workflow.md +27 -0
  263. package/scripts/auto-backing-issue.js +47 -0
  264. package/scripts/beads-context.sh +81 -57
  265. package/scripts/beads-upgrade-smoke.sh +24 -3
  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.sh +22 -3
  272. package/scripts/file-index.sh +3 -0
  273. package/scripts/forge-team/lib/claim.sh +34 -18
  274. package/scripts/forge-team/lib/dashboard.sh +61 -86
  275. package/scripts/forge-team/lib/epic.sh +99 -263
  276. package/scripts/forge-team/lib/hooks.sh +26 -28
  277. package/scripts/forge-team/lib/identity.sh +4 -4
  278. package/scripts/forge-team/lib/sync-github.sh +49 -84
  279. package/scripts/forge-team/lib/verify.sh +93 -83
  280. package/scripts/forge-team/lib/workload.sh +41 -65
  281. package/scripts/forge-team/tests/claim.test.sh +25 -19
  282. package/scripts/forge-team/tests/dashboard.test.sh +31 -46
  283. package/scripts/forge-team/tests/epic.test.sh +52 -71
  284. package/scripts/forge-team/tests/hooks.test.sh +38 -50
  285. package/scripts/forge-team/tests/identity.test.sh +3 -3
  286. package/scripts/forge-team/tests/integration.test.sh +44 -66
  287. package/scripts/forge-team/tests/sync-github.test.sh +50 -83
  288. package/scripts/forge-team/tests/verify.test.sh +37 -46
  289. package/scripts/forge-team/tests/workflow-integration.test.sh +4 -4
  290. package/scripts/forge-team/tests/workload.test.sh +32 -66
  291. package/scripts/gen-command-manifest.js +153 -0
  292. package/scripts/gen-embedded-assets.mjs +129 -0
  293. package/scripts/install.ps1 +139 -0
  294. package/scripts/install.sh +268 -0
  295. package/scripts/lib/release-asset.mjs +84 -0
  296. package/scripts/parity-check.mjs +145 -0
  297. package/scripts/parity-check.test.mjs +58 -0
  298. package/scripts/pin-agentic-workflow-images.js +112 -0
  299. package/scripts/pr-auto-actions.js +93 -0
  300. package/scripts/pr-coordinator.sh +3 -0
  301. package/scripts/pr-verdict-label.js +50 -0
  302. package/scripts/preflight-sonar.eslint.config.mjs +44 -0
  303. package/scripts/preflight.sh +21 -94
  304. package/scripts/protected-state-check.js +104 -0
  305. package/scripts/smart-status.sh +60 -57
  306. package/scripts/spikes/config-race-bench.js +111 -0
  307. package/scripts/spikes/harness-capability-matrix.js +13 -0
  308. package/scripts/spikes/patch-anchor-stability-bench.js +125 -0
  309. package/scripts/spikes/protected-path-manifest.js +20 -0
  310. package/scripts/spikes/skill-auto-invoke-parity.js +292 -0
  311. package/scripts/sync-agent-skills.js +62 -0
  312. package/scripts/sync-utils.sh +3 -0
  313. package/scripts/test-ci-shard.js +13 -6
  314. package/scripts/test.js +95 -12
  315. package/skills/claim-safety/SKILL.md +102 -0
  316. package/skills/claim-safety/evals/evals.json +46 -0
  317. package/{.github/prompts/dev.prompt.md → skills/dev/SKILL.md} +44 -50
  318. package/skills/dev/evals/evals.json +50 -0
  319. package/skills/hermes-forge/SKILL.md +185 -0
  320. package/skills/hermes-forge/evals/evals.json +46 -0
  321. package/skills/issue-basics/SKILL.md +111 -0
  322. package/skills/issue-basics/evals/evals.json +46 -0
  323. package/skills/kernel/SKILL.md +166 -0
  324. package/skills/kernel/evals/evals.json +50 -0
  325. package/skills/memory/SKILL.md +102 -0
  326. package/skills/parallel-deep-research/SKILL.md +14 -11
  327. package/skills/parallel-deep-research/evals/evals.json +11 -27
  328. package/{.github/prompts/plan.prompt.md → skills/plan/SKILL.md} +132 -157
  329. package/skills/plan/evals/evals.json +42 -0
  330. package/skills/research/SKILL.md +195 -0
  331. package/skills/research/evals/evals.json +42 -0
  332. package/{.github/prompts/review.prompt.md → skills/review/SKILL.md} +98 -62
  333. package/skills/review/evals/evals.json +42 -0
  334. package/skills/rollback/SKILL.md +110 -0
  335. package/skills/rollback/evals/evals.json +46 -0
  336. package/skills/rollback/references/methods.md +204 -0
  337. package/{.cursor/commands/rollback.md → skills/rollback/references/workflow-integration.md} +10 -284
  338. package/skills/shepherd/SKILL.md +66 -0
  339. package/skills/shepherd/evals/evals.json +42 -0
  340. package/{.github/prompts/ship.prompt.md → skills/ship/SKILL.md} +81 -45
  341. package/skills/ship/evals/evals.json +42 -0
  342. package/skills/smith/SKILL.md +142 -0
  343. package/skills/smith/evals/evals.json +46 -0
  344. package/skills/smith/references/autonomy-and-gates.md +94 -0
  345. package/{.github/prompts/sonarcloud.prompt.md → skills/sonarcloud/SKILL.md} +14 -3
  346. package/skills/sonarcloud/evals/evals.json +46 -0
  347. package/skills/sonarcloud-analysis/SKILL.md +18 -13
  348. package/skills/sonarcloud-analysis/evals/evals.json +11 -15
  349. package/{.github/prompts/status.prompt.md → skills/status/SKILL.md} +20 -10
  350. package/skills/status/evals/evals.json +50 -0
  351. package/skills/triage-ready/SKILL.md +121 -0
  352. package/skills/triage-ready/evals/evals.json +42 -0
  353. package/{.github/prompts/validate.prompt.md → skills/validate/SKILL.md} +52 -29
  354. package/skills/validate/evals/evals.json +42 -0
  355. package/skills/verify/SKILL.md +299 -0
  356. package/skills/verify/evals/evals.json +50 -0
  357. package/.claude/commands/dev.md +0 -345
  358. package/.claude/commands/plan.md +0 -566
  359. package/.claude/commands/premerge.md +0 -186
  360. package/.claude/commands/research.md +0 -42
  361. package/.claude/commands/review.md +0 -451
  362. package/.claude/commands/rollback.md +0 -721
  363. package/.claude/commands/ship.md +0 -213
  364. package/.claude/commands/sonarcloud.md +0 -152
  365. package/.claude/commands/status.md +0 -90
  366. package/.claude/commands/validate.md +0 -288
  367. package/.claude/commands/verify.md +0 -269
  368. package/.claude/rules/workflow.md +0 -121
  369. package/.cline/workflows/dev.md +0 -342
  370. package/.cline/workflows/plan.md +0 -563
  371. package/.cline/workflows/premerge.md +0 -183
  372. package/.cline/workflows/research.md +0 -39
  373. package/.cline/workflows/review.md +0 -448
  374. package/.cline/workflows/rollback.md +0 -718
  375. package/.cline/workflows/ship.md +0 -210
  376. package/.cline/workflows/sonarcloud.md +0 -146
  377. package/.cline/workflows/status.md +0 -87
  378. package/.cline/workflows/validate.md +0 -285
  379. package/.cline/workflows/verify.md +0 -266
  380. package/.codex/config.toml +0 -11
  381. package/.codex/skills/dev/SKILL.md +0 -345
  382. package/.codex/skills/plan/SKILL.md +0 -566
  383. package/.codex/skills/premerge/SKILL.md +0 -186
  384. package/.codex/skills/research/SKILL.md +0 -42
  385. package/.codex/skills/review/SKILL.md +0 -451
  386. package/.codex/skills/rollback/SKILL.md +0 -721
  387. package/.codex/skills/ship/SKILL.md +0 -213
  388. package/.codex/skills/sonarcloud/SKILL.md +0 -149
  389. package/.codex/skills/status/SKILL.md +0 -90
  390. package/.codex/skills/validate/SKILL.md +0 -288
  391. package/.codex/skills/verify/SKILL.md +0 -269
  392. package/.cursor/commands/dev.md +0 -342
  393. package/.cursor/commands/plan.md +0 -563
  394. package/.cursor/commands/premerge.md +0 -183
  395. package/.cursor/commands/research.md +0 -39
  396. package/.cursor/commands/review.md +0 -448
  397. package/.cursor/commands/ship.md +0 -210
  398. package/.cursor/commands/sonarcloud.md +0 -146
  399. package/.cursor/commands/status.md +0 -87
  400. package/.cursor/commands/validate.md +0 -285
  401. package/.cursor/commands/verify.md +0 -266
  402. package/.cursorrules +0 -149
  403. package/.github/prompts/premerge.prompt.md +0 -188
  404. package/.github/prompts/research.prompt.md +0 -44
  405. package/.github/prompts/rollback.prompt.md +0 -723
  406. package/.github/prompts/verify.prompt.md +0 -271
  407. package/.github/workflows/beads-to-github.yml +0 -89
  408. package/.github/workflows/github-to-beads.yml +0 -100
  409. package/.kilocode/workflows/dev.md +0 -346
  410. package/.kilocode/workflows/plan.md +0 -567
  411. package/.kilocode/workflows/premerge.md +0 -187
  412. package/.kilocode/workflows/research.md +0 -43
  413. package/.kilocode/workflows/review.md +0 -452
  414. package/.kilocode/workflows/rollback.md +0 -722
  415. package/.kilocode/workflows/ship.md +0 -214
  416. package/.kilocode/workflows/sonarcloud.md +0 -150
  417. package/.kilocode/workflows/status.md +0 -91
  418. package/.kilocode/workflows/validate.md +0 -289
  419. package/.kilocode/workflows/verify.md +0 -270
  420. package/.opencode/commands/dev.md +0 -345
  421. package/.opencode/commands/plan.md +0 -566
  422. package/.opencode/commands/premerge.md +0 -186
  423. package/.opencode/commands/research.md +0 -42
  424. package/.opencode/commands/review.md +0 -451
  425. package/.opencode/commands/rollback.md +0 -721
  426. package/.opencode/commands/ship.md +0 -213
  427. package/.opencode/commands/sonarcloud.md +0 -149
  428. package/.opencode/commands/status.md +0 -90
  429. package/.opencode/commands/validate.md +0 -288
  430. package/.opencode/commands/verify.md +0 -269
  431. package/.roo/commands/dev.md +0 -346
  432. package/.roo/commands/plan.md +0 -567
  433. package/.roo/commands/premerge.md +0 -187
  434. package/.roo/commands/research.md +0 -43
  435. package/.roo/commands/review.md +0 -452
  436. package/.roo/commands/rollback.md +0 -722
  437. package/.roo/commands/ship.md +0 -214
  438. package/.roo/commands/sonarcloud.md +0 -150
  439. package/.roo/commands/status.md +0 -91
  440. package/.roo/commands/validate.md +0 -289
  441. package/.roo/commands/verify.md +0 -270
  442. package/docs/BEADS_GITHUB_SYNC.md +0 -281
  443. package/docs/GREPTILE_SETUP.md +0 -400
  444. package/docs/MANUAL_REVIEW_GUIDE.md +0 -106
  445. package/docs/SETUP.md +0 -663
  446. package/docs/VALIDATION.md +0 -363
  447. package/lib/agents/cline.plugin.json +0 -29
  448. package/lib/agents/copilot.plugin.json +0 -24
  449. package/lib/agents/kilocode.plugin.json +0 -22
  450. package/lib/agents/opencode.plugin.json +0 -23
  451. package/lib/agents/roo.plugin.json +0 -30
  452. package/lib/beads-bootstrap.js +0 -225
  453. package/lib/beads-health-check.js +0 -188
  454. package/lib/commands/commands-reset.js +0 -147
  455. package/opencode.json +0 -67
  456. package/scripts/beads-context.test.js +0 -584
  457. package/scripts/github-beads-sync/comment.mjs +0 -64
  458. package/scripts/github-beads-sync/config.mjs +0 -148
  459. package/scripts/github-beads-sync/github-api.mjs +0 -131
  460. package/scripts/github-beads-sync/index.mjs +0 -356
  461. package/scripts/github-beads-sync/label-mapper.mjs +0 -54
  462. package/scripts/github-beads-sync/mapping.mjs +0 -132
  463. package/scripts/github-beads-sync/reverse-sync-cli.mjs +0 -31
  464. package/scripts/github-beads-sync/reverse-sync.mjs +0 -162
  465. package/scripts/github-beads-sync/run-bd.mjs +0 -161
  466. package/scripts/github-beads-sync/sanitize.mjs +0 -121
  467. package/scripts/github-beads-sync.config.json +0 -26
  468. package/scripts/sync-commands.js +0 -600
@@ -7,7 +7,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
7
7
  TEST_TMP="$(mktemp -d)"
8
8
  trap 'rm -rf "$TEST_TMP"' EXIT
9
9
 
10
- # Override TEAM_MAP_ROOT so tests don't touch real .beads/
10
+ # Override TEAM_MAP_ROOT so tests don't touch real .forge/
11
11
  export TEAM_MAP_ROOT="$TEST_TMP"
12
12
 
13
13
  # Fix "now" so stale detection is deterministic
@@ -27,75 +27,41 @@ esac
27
27
  MOCK
28
28
  chmod +x "$mock_dir/gh"
29
29
 
30
- # ── Create mock bd ───────────────────────────────────────────────────────
31
- cat > "$mock_dir/bd" << 'MOCK'
30
+ # ── Create mock forge ─────────────────────────────────────────────────────
31
+ # Emits Kernel-shaped JSON ({"data":{"issues":[...]}}) for `issue list`.
32
+ cat > "$mock_dir/forge" << 'MOCK'
32
33
  #!/usr/bin/env bash
33
- case "$1 $2" in
34
- "list --status=open,in_progress")
35
- exit 1
36
- ;;
37
- "list --status=open")
38
- echo "forge-bbb · Feature B"
39
- ;;
40
- "list --status=in_progress")
41
- echo "◐ forge-aaa · Feature A"
42
- echo "forge-ccc · Feature C"
43
- echo "◐ forge-m1n8.6 · Sub-feature X (dotted ID)"
44
- ;;
45
- "show forge-aaa")
46
- echo " forge-aaa · Feature A [● P2 · IN_PROGRESS]"
47
- echo "Owner: devone"
48
- echo "Updated: 2026-03-27T10:00:00Z"
49
- ;;
50
- "show forge-bbb")
51
- echo "○ forge-bbb · Feature B [● P2 · OPEN]"
52
- echo "Owner: devtwo"
53
- echo "Updated: 2026-03-25T10:00:00Z"
54
- ;;
55
- "show forge-ccc")
56
- echo "◐ forge-ccc · Feature C [● P1 · IN_PROGRESS]"
57
- echo "Owner: devone"
58
- echo "Updated: 2026-03-27T09:00:00Z"
59
- echo ""
60
- echo "DEPENDS ON"
61
- echo " → forge-aaa: Feature A"
62
- ;;
63
- "show forge-m1n8.6")
64
- # Dotted sub-ID — bd show must receive the full ID including .6
65
- echo "◐ forge-m1n8.6 · Sub-feature X [● P2 · IN_PROGRESS]"
66
- echo "Owner: devthree"
67
- echo "Updated: 2026-03-27T08:00:00Z"
68
- ;;
69
- "show forge-m1n8")
70
- # Parent epic — if a buggy parser truncates forge-m1n8.6 to forge-m1n8,
71
- # the workload would get this WRONG owner and trigger the guard below.
72
- echo "◐ forge-m1n8 · PARENT EPIC (WRONG — dotted ID was truncated)"
73
- echo "Owner: WRONG_OWNER_DO_NOT_USE"
74
- echo "Updated: 2026-03-20T10:00:00Z"
75
- ;;
76
- esac
34
+ args="$*"
35
+ emit() { printf '{"data":{"issues":%s}}\n' "$1"; }
36
+
37
+ # forge-aaa BLOCKS forge-ccc (kernel: the blocker carries the dependency edge),
38
+ # so forge-ccc is the blocked one — blocked_by resolves to forge-aaa by reverse scan.
39
+ aaa='{"id":"forge-aaa","title":"Feature A","status":"in_progress","assignee":"devone","updated_at":"2026-03-27T10:00:00Z","dependencies":["forge-ccc"]}'
40
+ bbb='{"id":"forge-bbb","title":"Feature B","status":"open","assignee":"devtwo","updated_at":"2026-03-25T10:00:00Z","dependencies":[]}'
41
+ ccc='{"id":"forge-ccc","title":"Feature C","status":"in_progress","assignee":"devone","updated_at":"2026-03-27T09:00:00Z","dependencies":[]}'
42
+ # Dotted sub-ID: the id flows through verbatim from JSON, never truncated.
43
+ m1n8='{"id":"forge-m1n8.6","title":"Sub-feature X (dotted ID)","status":"in_progress","assignee":"devthree","updated_at":"2026-03-27T08:00:00Z","dependencies":[]}'
44
+
45
+ if [[ "$args" == *"issue list"* ]]; then
46
+ if [[ "$args" == *"--status=open"* ]]; then emit "[$bbb]"
47
+ elif [[ "$args" == *"--status=in_progress"* ]]; then emit "[$aaa,$ccc,$m1n8]"
48
+ else emit "[]"; fi
49
+ exit 0
50
+ fi
51
+ exit 0
77
52
  MOCK
78
- chmod +x "$mock_dir/bd"
53
+ chmod +x "$mock_dir/forge"
79
54
 
80
- # ── Create mock bd with no issues ────────────────────────────────────────
81
- cat > "$mock_dir/bd-empty" << 'MOCK'
55
+ # ── Create mock forge with no issues ──────────────────────────────────────
56
+ cat > "$mock_dir/forge-empty" << 'MOCK'
82
57
  #!/usr/bin/env bash
83
- case "$1 $2" in
84
- "list --status=open,in_progress")
85
- echo ""
86
- ;;
87
- "list --status=open")
88
- echo "○ forge-should-not-appear · Open fallback sentinel"
89
- ;;
90
- "list --status=in_progress")
91
- echo "◐ forge-should-not-appear-2 · In-progress fallback sentinel"
92
- ;;
93
- esac
58
+ printf '{"data":{"issues":[]}}\n'
59
+ exit 0
94
60
  MOCK
95
- chmod +x "$mock_dir/bd-empty"
61
+ chmod +x "$mock_dir/forge-empty"
96
62
 
97
63
  export GH_CMD="$mock_dir/gh"
98
- export BD_CMD="$mock_dir/bd"
64
+ export FORGE_CMD="$mock_dir/forge"
99
65
 
100
66
  # Source the library under test
101
67
  source "$SCRIPT_DIR/lib/workload.sh"
@@ -183,13 +149,13 @@ assert_not_contains "excludes devtwo" "Developer: devtwo" "$output"
183
149
  echo ""
184
150
  echo "── Test 4: No issues → No active work ──"
185
151
  unset _GITHUB_USER_CACHE
186
- export BD_CMD="$mock_dir/bd-empty"
152
+ export FORGE_CMD="$mock_dir/forge-empty"
187
153
  rc=0
188
154
  output="$(cmd_workload 2>/dev/null)" || rc=$?
189
155
  assert_exit "exits 0" 0 "$rc"
190
156
  assert_contains "shows no active work message" "No active work" "$output"
191
- assert_not_contains "does not fall back when combined query succeeds with no issues" "forge-should-not-appear" "$output"
192
- export BD_CMD="$mock_dir/bd"
157
+ assert_not_contains "empty issue lists yield no issue entries" "forge-" "$output"
158
+ export FORGE_CMD="$mock_dir/forge"
193
159
 
194
160
  # ── Test 5: Stale assignment flagged (>48h) ──────────────────────────────
195
161
  echo ""
@@ -0,0 +1,153 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * Generate the static command manifest — scripts/gen-command-manifest.js
6
+ *
7
+ * Static bundlers (`bun build --compile`) need a static require graph, but the
8
+ * command registry discovers commands at runtime via `fs.readdirSync` +
9
+ * `require(filePath)`. This generator walks `lib/commands/*.js` and emits
10
+ * `lib/commands/_manifest.js`, a checked-in module that `require`s every command
11
+ * module by a *static* relative path. The registry loads the manifest as its
12
+ * fast, bundleable path and keeps readdir auto-discovery as a dev/extension
13
+ * fallback (see lib/commands/_registry.js).
14
+ *
15
+ * The output is deterministic (sorted by filename) and timestamp-free, and the
16
+ * file is only rewritten when its content actually changes, so no-op
17
+ * regeneration never dirties the working tree.
18
+ *
19
+ * Usage:
20
+ * node scripts/gen-command-manifest.js # write if changed
21
+ * node scripts/gen-command-manifest.js --check # exit 1 if out of date
22
+ *
23
+ * @module scripts/gen-command-manifest
24
+ */
25
+
26
+ const fs = require('node:fs');
27
+ const path = require('node:path');
28
+
29
+ const COMMANDS_DIR = path.resolve(__dirname, '..', 'lib', 'commands');
30
+ const MANIFEST_PATH = path.join(COMMANDS_DIR, '_manifest.js');
31
+
32
+ /**
33
+ * List the command module filenames the manifest should enumerate.
34
+ *
35
+ * Mirrors the registry's own filter: `.js` files that do not start with `_`
36
+ * (underscore-prefixed files are registry internals, not commands), sorted for
37
+ * deterministic output.
38
+ *
39
+ * @param {string} [commandsDir] - Directory to scan (defaults to lib/commands)
40
+ * @returns {string[]} Sorted command filenames (e.g. `['add.js', 'audit.js']`)
41
+ */
42
+ function listCommandFiles(commandsDir = COMMANDS_DIR) {
43
+ return fs
44
+ .readdirSync(commandsDir)
45
+ .filter(f => f.endsWith('.js') && !f.startsWith('_'))
46
+ .sort();
47
+ }
48
+
49
+ /**
50
+ * Render the manifest source from a list of command filenames.
51
+ *
52
+ * @param {string[]} files - Sorted command filenames
53
+ * @returns {string} Full source text for lib/commands/_manifest.js
54
+ */
55
+ function renderManifest(files) {
56
+ const header = [
57
+ '/**',
58
+ ' * Static Command Manifest — GENERATED FILE, DO NOT EDIT.',
59
+ ' *',
60
+ ' * Regenerate with: node scripts/gen-command-manifest.js',
61
+ ' * Drift is enforced by test/structural/command-manifest-drift.test.js.',
62
+ ' *',
63
+ ' * This module `require`s every command by a static relative path so',
64
+ ' * `bun build --compile` can statically bundle the command graph. The registry',
65
+ ' * (lib/commands/_registry.js) consumes `commands` as its fast, bundleable path',
66
+ ' * and falls back to `fs.readdirSync` auto-discovery for dev/extension commands.',
67
+ ' *',
68
+ ' * @module commands/_manifest',
69
+ ' */',
70
+ '',
71
+ "'use strict';",
72
+ '',
73
+ '/**',
74
+ ' * @typedef {Object} ManifestEntry',
75
+ ' * @property {string} file - Command filename (e.g. `status.js`)',
76
+ ' * @property {import("./_registry").CommandModule} module - The required command module',
77
+ ' */',
78
+ '',
79
+ '/** @type {ManifestEntry[]} */',
80
+ 'const commands = [',
81
+ ];
82
+
83
+ const entries = files.map(file => {
84
+ const modPath = `./${file.replace(/\.js$/, '')}`;
85
+ return ` { file: ${JSON.stringify(file)}, module: require(${JSON.stringify(modPath)}) },`;
86
+ });
87
+
88
+ const footer = [
89
+ '];',
90
+ '',
91
+ 'module.exports = {',
92
+ ' // Absolute path of the canonical commands directory this manifest describes.',
93
+ ' // The registry applies the manifest only when asked to load this exact dir.',
94
+ ' dir: __dirname,',
95
+ ' commands,',
96
+ '};',
97
+ '',
98
+ ];
99
+
100
+ return [...header, ...entries, ...footer].join('\n');
101
+ }
102
+
103
+ /**
104
+ * Generate (or check) the manifest.
105
+ *
106
+ * @param {{ check?: boolean, commandsDir?: string, manifestPath?: string }} [opts]
107
+ * @returns {{ changed: boolean, files: string[], path: string }}
108
+ */
109
+ function generate(opts = {}) {
110
+ const commandsDir = opts.commandsDir ?? COMMANDS_DIR;
111
+ const manifestPath = opts.manifestPath ?? MANIFEST_PATH;
112
+ const files = listCommandFiles(commandsDir);
113
+ const next = renderManifest(files);
114
+
115
+ const current = fs.existsSync(manifestPath)
116
+ ? fs.readFileSync(manifestPath, 'utf8')
117
+ : null;
118
+
119
+ const changed = current !== next;
120
+
121
+ if (changed && !opts.check) {
122
+ fs.writeFileSync(manifestPath, next, 'utf8');
123
+ }
124
+
125
+ return { changed, files, path: manifestPath };
126
+ }
127
+
128
+ module.exports = { listCommandFiles, renderManifest, generate, COMMANDS_DIR, MANIFEST_PATH };
129
+
130
+ // CLI entry point
131
+ if (require.main === module) {
132
+ const check = process.argv.includes('--check');
133
+ const result = generate({ check });
134
+
135
+ if (check && result.changed) {
136
+ console.error(
137
+ '[gen-command-manifest] lib/commands/_manifest.js is out of date.\n' +
138
+ 'Run: node scripts/gen-command-manifest.js'
139
+ );
140
+ process.exit(1);
141
+ }
142
+
143
+ if (result.changed) {
144
+ console.log(
145
+ `[gen-command-manifest] wrote ${path.relative(process.cwd(), result.path)} ` +
146
+ `(${result.files.length} commands)`
147
+ );
148
+ } else {
149
+ console.log(
150
+ `[gen-command-manifest] up to date (${result.files.length} commands)`
151
+ );
152
+ }
153
+ }
@@ -0,0 +1,129 @@
1
+ // Generate lib/embedded-assets.generated.mjs — a Bun-embeddable manifest that
2
+ // statically imports every runtime asset (with { type: "file" }) and maps its
3
+ // real relative POSIX path to the embedded-file path Bun resolves at compile time.
4
+ //
5
+ // WHY a generated per-file map instead of `bun build --compile ... skills/**`:
6
+ // Bun's `embeddedFiles` exposes only a HASHED, directory-less `blob.name`
7
+ // (e.g. `SKILL-a1b2c3.md`), so every skill's `SKILL.md` would collide and the
8
+ // tree could not be reconstructed. A generated map keyed by the true relative
9
+ // path preserves the directory structure exactly; each value is that specific
10
+ // file's `/$bunfs/…` path, so `Bun.file(value)` / `fs` reads the right bytes.
11
+ //
12
+ // The output is gitignored and regenerated by the `build:binary` script right
13
+ // before `bun build --compile`, so it can never drift from the source tree. The
14
+ // completeness test (test/embedded-assets-drift.test.js) walks the same roots and
15
+ // asserts the embed set == the on-disk asset set, both ways.
16
+
17
+ import fs from 'node:fs';
18
+ import path from 'node:path';
19
+ import crypto from 'node:crypto';
20
+ import { fileURLToPath } from 'node:url';
21
+ import pkgRoot from '../lib/package-root.js';
22
+
23
+ const { ASSET_ROOTS } = pkgRoot;
24
+
25
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
26
+ const REPO_ROOT = path.resolve(__dirname, '..');
27
+ const OUT_FILE = path.join(REPO_ROOT, 'lib', 'embedded-assets.generated.mjs');
28
+
29
+ // Deterministic, locale-INDEPENDENT codepoint comparator. Locale-default sort would
30
+ // diverge by machine locale and produce different embed bytes across the step-3
31
+ // cross-compile targets, so sorting is pinned to codepoint order everywhere.
32
+ const byteCompare = (a, b) => (a < b ? -1 : a > b ? 1 : 0);
33
+
34
+ /** True when the asset needs the executable bit restored on extraction (files-only embedding drops mode). */
35
+ export function isExecutableAsset(relPosixPath) {
36
+ return relPosixPath.endsWith('.sh') || relPosixPath.startsWith('.forge/hooks/');
37
+ }
38
+
39
+ /** Recursively list files under an absolute path, returning repo-relative posix paths. Symlinks are skipped (materialize content, never embed links). */
40
+ function walk(absPath, relPath, out) {
41
+ const stat = fs.lstatSync(absPath);
42
+ if (stat.isSymbolicLink()) return;
43
+ if (stat.isDirectory()) {
44
+ for (const entry of fs.readdirSync(absPath).sort(byteCompare)) {
45
+ walk(path.join(absPath, entry), `${relPath}/${entry}`, out);
46
+ }
47
+ } else if (stat.isFile()) {
48
+ out.push(relPath);
49
+ }
50
+ }
51
+
52
+ /** Collect every embeddable asset as a sorted list of repo-relative posix paths. */
53
+ export function collectAssetFiles(repoRoot = REPO_ROOT, roots = ASSET_ROOTS) {
54
+ const files = [];
55
+ for (const root of roots) {
56
+ const abs = path.join(repoRoot, root);
57
+ if (!fs.existsSync(abs)) {
58
+ // Fail CLOSED: a configured asset root that is absent would silently ship an
59
+ // incomplete manifest. Error instead so the build stops loudly.
60
+ throw new Error(
61
+ `Configured ASSET_ROOT does not exist: ${root} (looked in ${abs}). ` +
62
+ 'Fix ASSET_ROOTS in lib/package-root.js or restore the missing path.'
63
+ );
64
+ }
65
+ walk(abs, root.split(path.sep).join('/'), files);
66
+ }
67
+ return [...new Set(files)].sort(byteCompare);
68
+ }
69
+
70
+ /**
71
+ * Content fingerprint over the asset SET: sha256 of each relpath + its bytes, in
72
+ * sorted order. Emitted into the manifest so the runtime cache dir identity
73
+ * changes whenever any asset content or the set changes (invalidates stale
74
+ * same-version extractions). Deterministic across machines.
75
+ */
76
+ export function assetFingerprint(repoRoot = REPO_ROOT, files = collectAssetFiles(repoRoot)) {
77
+ const h = crypto.createHash('sha256');
78
+ for (const rel of files) {
79
+ h.update(rel);
80
+ h.update('\0');
81
+ h.update(fs.readFileSync(path.join(repoRoot, ...rel.split('/'))));
82
+ }
83
+ return h.digest('hex');
84
+ }
85
+
86
+ function render(files, fingerprint) {
87
+ const imports = [];
88
+ const entries = [];
89
+ const execEntries = [];
90
+ files.forEach((rel, i) => {
91
+ const ident = `a${i}`;
92
+ // Specifier is relative to lib/embedded-assets.generated.mjs → prefix `../`.
93
+ const specifier = JSON.stringify(`../${rel}`);
94
+ imports.push(`import ${ident} from ${specifier} with { type: "file" };`);
95
+ entries.push(` ${JSON.stringify(rel)}: ${ident},`);
96
+ if (isExecutableAsset(rel)) execEntries.push(` ${JSON.stringify(rel)},`);
97
+ });
98
+ return [
99
+ '// AUTO-GENERATED by scripts/gen-embedded-assets.mjs — DO NOT EDIT.',
100
+ '// Gitignored; regenerated before every `bun build --compile`.',
101
+ ...imports,
102
+ '',
103
+ 'export const EMBEDDED_ASSETS = {',
104
+ ...entries,
105
+ '};',
106
+ '',
107
+ 'export const EXECUTABLE_ASSETS = [',
108
+ ...execEntries,
109
+ '];',
110
+ '',
111
+ `export const ASSET_FINGERPRINT = ${JSON.stringify(fingerprint)};`,
112
+ '',
113
+ ].join('\n');
114
+ }
115
+
116
+ function main() {
117
+ const files = collectAssetFiles();
118
+ const fingerprint = assetFingerprint(REPO_ROOT, files);
119
+ fs.mkdirSync(path.dirname(OUT_FILE), { recursive: true });
120
+ fs.writeFileSync(OUT_FILE, render(files, fingerprint), 'utf8');
121
+ const execCount = files.filter(isExecutableAsset).length;
122
+ console.log(
123
+ `Embedded ${files.length} asset file(s) (${execCount} executable), fingerprint ${fingerprint.slice(0, 16)} → ${path.relative(REPO_ROOT, OUT_FILE)}`
124
+ );
125
+ }
126
+
127
+ if (import.meta.main || process.argv[1] === fileURLToPath(import.meta.url)) {
128
+ main();
129
+ }
@@ -0,0 +1,139 @@
1
+ <#
2
+ .SYNOPSIS
3
+ Forge single-binary installer for Windows (x64).
4
+
5
+ .DESCRIPTION
6
+ Downloads the forge-windows-x64.exe binary from the GitHub Release, installs it
7
+ to %LOCALAPPDATA%\Programs\forge\forge.exe, and prints a PATH note plus the next
8
+ step. The binary bundles Forge's JavaScript but NOT its external prerequisites:
9
+ git, gh (GitHub CLI) and Git Bash must still be installed separately.
10
+
11
+ .PARAMETER Version
12
+ Release tag to install (default: latest), e.g. v1.2.3.
13
+
14
+ .PARAMETER Dir
15
+ Install directory (default: $env:LOCALAPPDATA\Programs\forge).
16
+
17
+ .PARAMETER PrintAsset
18
+ Print the resolved asset name and exit (used for verification/testing).
19
+
20
+ .EXAMPLE
21
+ irm https://raw.githubusercontent.com/harshanandak/forge/master/scripts/install.ps1 | iex
22
+
23
+ .EXAMPLE
24
+ # Pin a version (download the script, then run it with an argument):
25
+ $s = irm https://raw.githubusercontent.com/harshanandak/forge/master/scripts/install.ps1
26
+ & ([scriptblock]::Create($s)) -Version v1.2.3
27
+ #>
28
+ [CmdletBinding()]
29
+ param(
30
+ [string]$Version = 'latest',
31
+ [string]$Dir = (Join-Path $env:LOCALAPPDATA 'Programs\forge'),
32
+ [switch]$PrintAsset,
33
+ [switch]$SkipChecksum
34
+ )
35
+
36
+ $ErrorActionPreference = 'Stop'
37
+ Set-StrictMode -Version Latest
38
+
39
+ $Repo = if ($env:FORGE_REPO) { $env:FORGE_REPO } else { 'harshanandak/forge' }
40
+ if ($Version -eq 'latest' -and $env:FORGE_VERSION) { $Version = $env:FORGE_VERSION }
41
+
42
+ # Canonical asset-name mapping for Windows - the only target this script installs.
43
+ # Mirrors scripts/lib/release-asset.mjs (forge-<os>-<arch>[.exe]).
44
+ $Arch = if ($env:FORGE_ARCH) { $env:FORGE_ARCH } else { 'x64' }
45
+ if ($Arch -ne 'x64') {
46
+ throw "forge-install: unsupported architecture '$Arch'. Only windows-x64 is published."
47
+ }
48
+ $Asset = "forge-windows-$Arch.exe"
49
+
50
+ if ($PrintAsset) {
51
+ Write-Output $Asset
52
+ return
53
+ }
54
+
55
+ # Resolve version + URL. The /releases/latest/download/<asset> path redirects to
56
+ # the newest release, so no JSON API call is needed to download.
57
+ if ($Version -eq 'latest') {
58
+ $Url = "https://github.com/$Repo/releases/latest/download/$Asset"
59
+ try {
60
+ $rel = Invoke-RestMethod -Uri "https://api.github.com/repos/$Repo/releases/latest" `
61
+ -Headers @{ 'User-Agent' = 'forge-install' }
62
+ $ResolvedVersion = $rel.tag_name
63
+ } catch {
64
+ $ResolvedVersion = 'latest'
65
+ }
66
+ } else {
67
+ $Url = "https://github.com/$Repo/releases/download/$Version/$Asset"
68
+ $ResolvedVersion = $Version
69
+ }
70
+
71
+ Write-Host "forge-install: platform windows / $Arch -> asset $Asset"
72
+ Write-Host "forge-install: downloading $Asset ($ResolvedVersion)"
73
+
74
+ New-Item -ItemType Directory -Force -Path $Dir | Out-Null
75
+ $Dest = Join-Path $Dir 'forge.exe'
76
+ $Tmp = Join-Path ([System.IO.Path]::GetTempPath()) ("forge-install-" + [System.Guid]::NewGuid().ToString('N') + ".exe")
77
+
78
+ try {
79
+ Invoke-WebRequest -Uri $Url -OutFile $Tmp -UseBasicParsing -TimeoutSec 300
80
+ } catch {
81
+ throw "forge-install: download failed from $Url - is the release published for windows-x64? ($_)"
82
+ }
83
+ if (-not (Test-Path $Tmp) -or (Get-Item $Tmp).Length -eq 0) {
84
+ throw "forge-install: downloaded file is empty - asset '$Asset' may not exist in release '$ResolvedVersion'."
85
+ }
86
+
87
+ # Integrity verification (SHA-256) BEFORE installing. A mismatch is fatal
88
+ # (corrupted or substituted download). If the manifest cannot be fetched we warn
89
+ # and continue; pass -SkipChecksum or set FORGE_SKIP_CHECKSUM=1 to bypass.
90
+ if ($SkipChecksum -or $env:FORGE_SKIP_CHECKSUM -eq '1') {
91
+ Write-Host "forge-install: skipping integrity check (requested)."
92
+ } else {
93
+ $SumsUrl = $Url.Substring(0, $Url.LastIndexOf('/') + 1) + 'checksums.txt'
94
+ $SumsTmp = Join-Path ([System.IO.Path]::GetTempPath()) ("forge-install-" + [System.Guid]::NewGuid().ToString('N') + ".txt")
95
+ $expected = $null
96
+ $manifestFetched = $false
97
+ try {
98
+ Invoke-WebRequest -Uri $SumsUrl -OutFile $SumsTmp -UseBasicParsing -TimeoutSec 30
99
+ $manifestFetched = $true
100
+ foreach ($line in (Get-Content $SumsTmp)) {
101
+ # Lines are "<hash> <name>" (text) or "<hash> *<name>" (binary).
102
+ if ($line -match '^\s*([0-9a-fA-F]{64})\s+\*?(.+?)\s*$' -and $Matches[2] -eq $Asset) {
103
+ $expected = $Matches[1].ToLower()
104
+ break
105
+ }
106
+ }
107
+ } catch {
108
+ Write-Host "forge-install: could not download checksums.txt - skipping integrity check."
109
+ } finally {
110
+ if (Test-Path $SumsTmp) { Remove-Item -Force $SumsTmp }
111
+ }
112
+ if ($expected) {
113
+ $actual = (Get-FileHash -Algorithm SHA256 -Path $Tmp).Hash.ToLower()
114
+ if ($actual -ne $expected) {
115
+ Remove-Item -Force $Tmp
116
+ throw "forge-install: checksum mismatch for $Asset`n expected: $expected`n actual: $actual`nThe download may be corrupted or tampered with - aborting."
117
+ }
118
+ Write-Host "forge-install: checksum verified (sha256)."
119
+ } elseif ($manifestFetched) {
120
+ Write-Host "forge-install: $Asset not listed in checksums.txt - skipping integrity check."
121
+ }
122
+ }
123
+
124
+ Move-Item -Force -Path $Tmp -Destination $Dest
125
+
126
+ Write-Host ""
127
+ Write-Host "forge-install: installed forge $ResolvedVersion -> $Dest"
128
+
129
+ # PATH note: check the user PATH, not just the current process.
130
+ $userPath = [Environment]::GetEnvironmentVariable('Path', 'User')
131
+ if (-not ($userPath -and ($userPath -split ';' | Where-Object { $_ -eq $Dir }))) {
132
+ Write-Host ""
133
+ Write-Host "$Dir is not on your PATH. Add it (new terminals will pick it up):"
134
+ Write-Host " [Environment]::SetEnvironmentVariable('Path', `"$Dir;`$([Environment]::GetEnvironmentVariable('Path','User'))`", 'User')"
135
+ }
136
+
137
+ Write-Host ""
138
+ Write-Host "Next: run 'forge setup' in a git repo to wire up Forge."
139
+ Write-Host "Note: git, gh (GitHub CLI) and Git Bash must be installed separately - the binary bundles Forge, not those tools."