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
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env bash
2
- # smart-status.sh Workflow intelligence scoring engine
2
+ # smart-status.sh — Workflow intelligence scoring engine
3
3
  #
4
- # Reads issues via `bd list --json --limit 0`, computes a composite score
5
- # for each issue, and outputs them sorted by score descending.
4
+ # Reads issues via `forge issue list --json` (Forge Kernel), computes a composite
5
+ # score for each issue, and outputs them sorted by score descending.
6
6
  #
7
7
  # Composite score:
8
8
  # priority_weight * unblock_chain * type_weight * status_boost * epic_proximity * staleness_boost
@@ -11,20 +11,42 @@
11
11
  # smart-status.sh [--json]
12
12
  #
13
13
  # Environment:
14
- # BD_CMD — override the bd command (for testing with mocks)
15
- # GIT_CMD override the git command (for testing with mocks)
16
- # DEFAULT_BRANCH override the default branch name (default: auto-detect)
14
+ # FORGE_CMD— override the forge command (for testing with mocks)
15
+ # GIT_CMD — override the git command (for testing with mocks)
16
+ # DEFAULT_BRANCH — override the default branch name (default: auto-detect)
17
17
  #
18
18
  # Cross-platform: bash 3.2 compatible (no associative arrays, no mapfile).
19
19
  # OWASP A03: All variables quoted, sanitize() strips injection patterns.
20
20
 
21
21
  set -euo pipefail
22
22
 
23
- # ── Source cross-dev awareness scripts ────────────────────────────────
23
+ # ── Source cross-dev awareness scripts ────────────────────────────────
24
24
  # file-index.sh: file_index_read for reading file index entries
25
25
  # sync-utils.sh: get_session_identity for current developer identity
26
26
 
27
27
  _SMART_STATUS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
28
+ if [ -f "$_SMART_STATUS_DIR/bootstrap-windows-tools.sh" ]; then
29
+ source "$_SMART_STATUS_DIR/bootstrap-windows-tools.sh"
30
+ fi
31
+ NODE_CMD="${NODE_CMD:-node}"
32
+ JQ_CMD="${JQ_CMD:-jq}"
33
+
34
+ node_script_path() {
35
+ case "$1" in
36
+ /[A-Za-z]/*)
37
+ _drive="$(printf '%s' "${1:1:1}" | tr '[:lower:]' '[:upper:]')"
38
+ printf '%s:/%s\n' "$_drive" "${1:3}"
39
+ ;;
40
+ *)
41
+ if command -v cygpath >/dev/null 2>&1; then
42
+ cygpath -m "$1"
43
+ else
44
+ printf '%s\n' "$1"
45
+ fi
46
+ ;;
47
+ esac
48
+ }
49
+
28
50
  if [ -f "$_SMART_STATUS_DIR/lib/sanitize.sh" ]; then
29
51
  source "$_SMART_STATUS_DIR/lib/sanitize.sh"
30
52
  fi
@@ -35,7 +57,7 @@ if [ -f "$_SMART_STATUS_DIR/sync-utils.sh" ]; then
35
57
  source "$_SMART_STATUS_DIR/sync-utils.sh"
36
58
  fi
37
59
 
38
- # ── Helpers ──────────────────────────────────────────────────────────────
60
+ # ── Helpers ──────────────────────────────────────────────────────────────
39
61
 
40
62
  if ! declare -F sanitize >/dev/null; then
41
63
  # Sanitize a string: strip shell-injection patterns (OWASP A03)
@@ -56,9 +78,9 @@ sanitize() {
56
78
  }
57
79
  fi
58
80
 
59
- # ── Dependency check ────────────────────────────────────────────────────
81
+ # ── Dependency check ────────────────────────────────────────────────────
60
82
 
61
- if ! command -v jq &>/dev/null; then
83
+ if ! command -v "$JQ_CMD" &>/dev/null; then
62
84
  echo "Error: jq is required but not found." >&2
63
85
  echo "Install jq:" >&2
64
86
  echo " macOS: brew install jq" >&2
@@ -70,12 +92,12 @@ fi
70
92
  # Warn if jq < 1.6 (fromdateiso8601 and sub/2 require 1.6+)
71
93
  # Strip CR here as well because Windows jq.exe (or a CRLF-emitting wrapper in
72
94
  # tests) can affect the version probe before the jq() shim is defined below.
73
- _jq_version="$(command jq --version 2>/dev/null | tr -d '\r' | sed 's/jq-//')" || true
95
+ _jq_version="$(command "$JQ_CMD" --version 2>/dev/null | tr -d '\r' | sed 's/jq-//')" || true
74
96
  if [ -n "$_jq_version" ]; then
75
97
  _jq_major="${_jq_version%%.*}"
76
98
  _jq_minor="${_jq_version#*.}"; _jq_minor="${_jq_minor%%.*}"
77
99
  if [ "${_jq_major:-0}" -lt 1 ] || { [ "${_jq_major:-0}" -eq 1 ] && [ "${_jq_minor:-0}" -lt 6 ]; }; then
78
- echo "Warning: jq $_jq_version detected staleness features require jq 1.6+. Team Activity may not display." >&2
100
+ echo "Warning: jq $_jq_version detected - staleness features require jq 1.6+. Team Activity may not display." >&2
79
101
  fi
80
102
  fi
81
103
 
@@ -83,12 +105,12 @@ fi
83
105
  # numeric comparisons like `[ "$count" -gt 0 ]`. Strip trailing CRs from
84
106
  # all jq output after the dependency/version checks above.
85
107
  jq() {
86
- command jq "$@" | tr -d '\r'
108
+ command "$JQ_CMD" "$@" | tr -d '\r'
87
109
  }
88
110
 
89
- # ── Configuration ───────────────────────────────────────────────────────
111
+ # ── Configuration ───────────────────────────────────────────────────────
90
112
 
91
- BD="${BD_CMD:-bd}"
113
+ FORGE="${FORGE_CMD:-forge}"
92
114
  GIT="${GIT_CMD:-git}"
93
115
  JSON_MODE=0
94
116
 
@@ -103,7 +125,7 @@ else
103
125
  BASE_BRANCH="master"
104
126
  fi
105
127
 
106
- # Parse arguments (bash 3.2 compatible no associative arrays)
128
+ # Parse arguments (bash 3.2 compatible — no associative arrays)
107
129
  for arg in "$@"; do
108
130
  case "$arg" in
109
131
  --json) JSON_MODE=1 ;;
@@ -124,36 +146,18 @@ for arg in "$@"; do
124
146
  esac
125
147
  done
126
148
 
127
- # ── Fetch issues ────────────────────────────────────────────────────────
149
+ # ── Fetch issues ────────────────────────────────────────────────────────
128
150
 
129
- # Auto-recover beads database if Dolt server lost the database (e.g. branch
130
- # switch, fresh clone, server restart). Checks for the specific "database
131
- # not found" error, runs bd init --force + bd backup restore, then retries.
132
- # Capture stderr into variable (2>&1 redirects stderr to stdout for capture,
133
- # then >/dev/null discards original stdout so only errors remain).
134
- if ! command -v "$BD" >/dev/null 2>&1; then
135
- echo "Error: bd is required but not found." >&2
136
- exit 1
137
- fi
138
-
139
- _bd_list_err="$("$BD" list --json --limit 0 2>&1 >/dev/null || true)"
140
- if printf '%s' "$_bd_list_err" | grep -qi "database.*not found"; then
141
- # Derive prefix from repo root directory name (not pwd, which could be a subdirectory)
142
- _repo_root="$("$GIT" rev-parse --show-toplevel 2>/dev/null || pwd)"
143
- _bd_prefix="$(basename "$_repo_root" | tr '[:upper:]' '[:lower:]' | tr -cs '[:alnum:]-' '-' | sed 's/^-//;s/-$//')"
144
- echo "Beads database not found — attempting auto-recovery..." >&2
145
- if "$BD" init --force --prefix "$_bd_prefix" >/dev/null 2>&1; then
146
- if [ -d "$_repo_root/.beads/backup" ] && ls "$_repo_root/.beads/backup"/*.jsonl >/dev/null 2>&1; then
147
- "$BD" backup restore >/dev/null 2>&1 && echo "Beads: restored from backup." >&2 || echo "Beads: backup restore failed." >&2
148
- else
149
- echo "Beads: initialized fresh (no backup found)." >&2
150
- fi
151
- else
152
- echo "Beads: auto-recovery failed — run 'bd doctor' manually." >&2
153
- fi
154
- fi
155
-
156
- ISSUES_JSON="$("$BD" list --json --limit 0 2>/dev/null || echo '[]')"
151
+ # Fetch issues from the Forge Kernel and normalize the envelope into the bare
152
+ # array the scorer + grouping expect: extract .data.issues and drop terminal
153
+ # (done/cancelled) issues so completed work never pollutes the work queue. The
154
+ # kernel already supplies each issue's `dependents` (reverse-graph) and
155
+ # `dependencies` arrays, so no per-issue reshaping is needed. The kernel
156
+ # auto-migrates its single-machine SQLite store on read — nothing to recover.
157
+ ISSUES_JSON="$("$FORGE" issue list --json 2>/dev/null | jq '[
158
+ .data.issues[]
159
+ | select(.status != "done" and .status != "cancelled")
160
+ ]' 2>/dev/null || echo '[]')"
157
161
 
158
162
  # Bail early on empty
159
163
  if [ "$(printf '%s' "$ISSUES_JSON" | jq 'length')" = "0" ]; then
@@ -165,7 +169,7 @@ if [ "$(printf '%s' "$ISSUES_JSON" | jq 'length')" = "0" ]; then
165
169
  exit 0
166
170
  fi
167
171
 
168
- # ── Identify epics and fetch their children ─────────────────────────────
172
+ # ── Identify epics and fetch their children ─────────────────────────────
169
173
 
170
174
  # Extract epic IDs (type == "epic")
171
175
  EPIC_IDS="$(printf '%s' "$ISSUES_JSON" | jq -r '.[] | select(.type == "epic") | .id')"
@@ -173,104 +177,33 @@ EPIC_IDS="$(printf '%s' "$ISSUES_JSON" | jq -r '.[] | select(.type == "epic") |
173
177
  # Build a JSON object mapping epic_id -> { closed, total }
174
178
  EPIC_STATS="{}"
175
179
  if [ -n "$EPIC_IDS" ]; then
176
- # Process each epic (bash 3.2 compatible read line by line)
180
+ # Process each epic (bash 3.2 compatible — read line by line)
177
181
  while IFS= read -r epic_id; do
178
182
  [ -z "$epic_id" ] && continue
179
- CHILDREN_JSON="$("$BD" children "$epic_id" --json 2>/dev/null || echo '[]')"
180
- TOTAL="$(printf '%s' "$CHILDREN_JSON" | jq 'length')"
181
- CLOSED="$(printf '%s' "$CHILDREN_JSON" | jq '[.[] | select(.status == "closed")] | length')"
183
+ # Kernel `forge issue children` returns the rollup envelope; read total + the done
184
+ # count straight from the kernel-computed rollup (the kernel `done` status replaces
185
+ # the beads `closed` this math used to count). EPIC_STATS keeps its { total, closed }
186
+ # shape, so smart-status-score.js / scoring.js:getEpicProximity stay untouched.
187
+ CHILDREN_JSON="$("$FORGE" issue children "$epic_id" --json 2>/dev/null || echo '{}')"
188
+ [ -z "$CHILDREN_JSON" ] && CHILDREN_JSON='{}'
189
+ TOTAL="$(printf '%s' "$CHILDREN_JSON" | jq -r '(.data.rollup.total // 0)')"
190
+ CLOSED="$(printf '%s' "$CHILDREN_JSON" | jq -r '(.data.rollup.done // 0)')"
182
191
  EPIC_STATS="$(printf '%s' "$EPIC_STATS" | jq --arg id "$epic_id" --argjson total "$TOTAL" --argjson closed "$CLOSED" '. + {($id): {total: $total, closed: $closed}}')"
183
192
  done <<EOF
184
193
  $EPIC_IDS
185
194
  EOF
186
195
  fi
187
196
 
188
- # ── Score issues with jq ────────────────────────────────────────────────
189
-
190
- SCORED_JSON="$(printf '%s' "$ISSUES_JSON" | jq --argjson epic_stats "$EPIC_STATS" '
191
- # First pass: build reverse dependency map (who does each issue unblock?)
192
- # For each issue X, find all issues Y where Y.dependencies[].depends_on_id == X.id
193
- (reduce .[] as $dep_issue ({};
194
- reduce ($dep_issue.dependencies // [] | .[]) as $dep (.;
195
- .[$dep.depends_on_id] += [$dep_issue.id]
196
- )
197
- )) as $dependents_map |
198
-
199
- [.[] | . as $issue |
200
-
201
- # Priority weight: P0=5, P1=4, P2=3, P3=2, P4=1, default=1
202
- # Normalize priority to number (beads 0.62+ sends numbers, older sends strings)
203
- ((.priority // 2) | if type == "string" then
204
- (if . == "P0" then 0 elif . == "P1" then 1 elif . == "P2" then 2 elif . == "P3" then 3 elif . == "P4" then 4 else 5 end)
205
- else . end) as $pri_num |
206
- (if $pri_num == 0 then 5
207
- elif $pri_num == 1 then 4
208
- elif $pri_num == 2 then 3
209
- elif $pri_num == 3 then 2
210
- elif $pri_num == 4 then 1
211
- else 1 end) as $priority_weight |
212
-
213
- # Unblock chain: dependent_count + 1 (min 1).
214
- # NOTE: dependent_count is the authoritative server-side count. The "Unblocks:"
215
- # annotation (computed below from local response) may show fewer items when
216
- # bd list omits closed or filtered-out issues. This is an intentional trade-off.
217
- (((.dependent_count // 0) + 1) | if . < 1 then 1 else . end) as $unblock_chain |
218
-
219
- # Type weight: bug=1.2, feature=1.0, task=0.8, default=1.0
220
- # Handle null type from beads 0.62+
221
- (if (.type // "task") == "bug" then 1.2
222
- elif (.type // "task") == "feature" then 1.0
223
- elif (.type // "task") == "task" then 0.8
224
- else 1.0 end) as $type_weight |
225
-
226
- # Status boost: in_progress=1.5, open=1.0, default=1.0
227
- (if .status == "in_progress" then 1.5
228
- elif .status == "open" then 1.0
229
- else 1.0 end) as $status_boost |
230
-
231
- # Epic proximity: if issue has parent_id that is an epic, compute
232
- # 1.0 + (closed_siblings / total_siblings) * 0.5
233
- (if (.parent_id // "") != "" and ($epic_stats[.parent_id] // null) != null then
234
- $epic_stats[.parent_id] as $es |
235
- if $es.total > 0 then
236
- 1.0 + (($es.closed / $es.total) * 0.5)
237
- else 1.0 end
238
- else 1.0 end) as $epic_proximity |
239
-
240
- # Staleness boost based on updated_at
241
- # 0-7d=1.0, 7-14d=1.1, 14-30d=1.2, 30+d=1.5
242
- # Truncate to first 19 chars (YYYY-MM-DDTHH:MM:SS) + "Z" for fromdateiso8601.
243
- # Handles fractional seconds (.NNN), timezone offsets (+05:30), or both.
244
- (if .updated_at then
245
- ((.updated_at[:19] + "Z") | fromdateiso8601) as $ts |
246
- ((now - $ts) / 86400) as $days |
247
- if $days >= 30 then 1.5
248
- elif $days >= 14 then 1.2
249
- elif $days >= 7 then 1.1
250
- else 1.0 end
251
- else 1.0 end) as $staleness_boost |
252
-
253
- # Composite score
254
- ($priority_weight * $unblock_chain * $type_weight * $status_boost * $epic_proximity * $staleness_boost) as $score |
255
-
256
- # Compute dependents list (which issues does this one unblock?)
257
- ($dependents_map[$issue.id] // []) as $dependents_list |
258
-
259
- # Output scored issue
260
- $issue + {
261
- score: ($score * 100 | round / 100),
262
- priority_weight: $priority_weight,
263
- unblock_chain: $unblock_chain,
264
- type_weight: $type_weight,
265
- status_boost: $status_boost,
266
- epic_proximity: (($epic_proximity * 100 | round) / 100),
267
- staleness_boost: $staleness_boost,
268
- dependents: $dependents_list
269
- }
270
- ] | sort_by(-.score)
271
- ')"
272
-
273
- # ── Session detection ─────────────────────────────────────────────────
197
+ # ── Score issues via shared JS helper ──────────────────────────────────
198
+
199
+ if ! command -v "$NODE_CMD" >/dev/null 2>&1; then
200
+ echo "Error: node is required but not found." >&2
201
+ exit 1
202
+ fi
203
+
204
+ SCORED_JSON="$(printf '{"issues":%s,"epicStats":%s}' "$ISSUES_JSON" "$EPIC_STATS" | "$NODE_CMD" "$(node_script_path "$_SMART_STATUS_DIR/smart-status-score.js")")"
205
+
206
+ # ── Session detection ─────────────────────────────────────────────────
274
207
 
275
208
  # Parse git worktree list --porcelain to find active sessions
276
209
  # Format: blocks separated by blank lines, each block has:
@@ -280,198 +213,50 @@ SCORED_JSON="$(printf '%s' "$ISSUES_JSON" | jq --argjson epic_stats "$EPIC_STATS
280
213
 
281
214
  WORKTREE_PORCELAIN="$("$GIT" worktree list --porcelain 2>/dev/null || echo '')"
282
215
 
283
- # Collect non-default-branch worktree branches and paths
284
- # Stored as newline-delimited "branch<TAB>path" entries — safe for paths with |, spaces, etc.
285
- SESSION_ENTRIES=""
286
- SESSION_COUNT=0
287
-
288
- _wt_path=""
289
- _wt_branch=""
290
- while IFS= read -r line; do
291
- case "$line" in
292
- worktree\ *)
293
- _wt_path="${line#worktree }"
294
- ;;
295
- branch\ *)
296
- _wt_branch="${line#branch refs/heads/}"
297
- ;;
298
- "")
299
- # End of block — process if we have a branch that is not the default branch
300
- if [ -n "$_wt_branch" ] && [ "$_wt_branch" != "$BASE_BRANCH" ]; then
301
- SESSION_COUNT=$((SESSION_COUNT + 1))
302
- if [ -n "$SESSION_ENTRIES" ]; then
303
- SESSION_ENTRIES="${SESSION_ENTRIES}
304
- ${_wt_branch} ${_wt_path}"
305
- else
306
- SESSION_ENTRIES="${_wt_branch} ${_wt_path}"
307
- fi
308
- fi
309
- _wt_path=""
310
- _wt_branch=""
311
- ;;
312
- esac
313
- done <<EOF
314
- ${WORKTREE_PORCELAIN}
315
-
316
- EOF
317
216
 
318
- # Get in-progress issues for matching (only if we have sessions)
217
+ # Build session/conflict data with the shared JS helper so the shell layer
218
+ # only performs command execution and rendering.
319
219
  IN_PROGRESS_JSON="[]"
320
- if [ "$SESSION_COUNT" -gt 0 ]; then
321
- IN_PROGRESS_JSON="$("$BD" list --status in_progress --json --limit 0 2>/dev/null || echo '')"
322
- # Fallback: only if bd command failed (empty output), not if result is legitimately empty array
323
- if [ -z "$IN_PROGRESS_JSON" ] || ! printf '%s' "$IN_PROGRESS_JSON" | jq empty 2>/dev/null; then
324
- IN_PROGRESS_JSON="$(printf '%s' "$ISSUES_JSON" | jq '[.[] | select(.status == "in_progress")]')"
325
- fi
326
- fi
327
-
328
- # Build sessions data: for each branch, find matching in-progress issues
329
- # Match by: branch slug (after feat/, fix/, docs/) appears in issue title (case-insensitive, hyphen-to-space)
330
- SESSIONS_JSON="[]"
331
- if [ "$SESSION_COUNT" -gt 0 ]; then
332
- # Process each session (newline-delimited "branch<TAB>path" entries)
333
- while IFS=' ' read -r _branch _path; do
334
- [ -z "$_branch" ] && continue
335
-
336
- # Extract slug from branch name (strip any <prefix>/ convention)
337
- _slug="$_branch"
338
- case "$_slug" in
339
- */*) _slug="${_slug##*/}" ;;
340
- esac
341
-
342
- # Convert slug hyphens to spaces for title matching
343
- _slug_spaces="$(printf '%s' "$_slug" | tr '-' ' ')"
344
-
345
- # Find matching in-progress issues: title contains slug words (case-insensitive)
346
- _matched_ids="$(printf '%s' "$IN_PROGRESS_JSON" | jq -r --arg slug "$_slug_spaces" '
347
- [.[] | select(
348
- (.title | ascii_downcase | contains($slug | ascii_downcase))
349
- ) | .id] | join(",")
350
- ')"
351
-
352
- _issue_count=0
353
- if [ -n "$_matched_ids" ]; then
354
- # Count commas + 1
355
- _issue_count="$(printf '%s' "$_matched_ids" | tr -cd ',' | wc -c)"
356
- _issue_count=$((_issue_count + 1))
357
- fi
358
-
359
- # Build session JSON entry
360
- if [ -n "$_matched_ids" ]; then
361
- _ids_json="$(printf '%s' "$_matched_ids" | jq -R 'split(",")')"
362
- else
363
- _ids_json="[]"
364
- fi
365
-
366
- SESSIONS_JSON="$(printf '%s' "$SESSIONS_JSON" | jq \
367
- --arg branch "$_branch" \
368
- --arg path "$_path" \
369
- --argjson ids "$_ids_json" \
370
- --argjson count "$_issue_count" \
371
- '. + [{branch: $branch, path: $path, issue_ids: $ids, issue_count: $count}]'
372
- )"
373
-
374
- done <<SESSIONS_EOF
375
- $SESSION_ENTRIES
376
- SESSIONS_EOF
220
+ if [ -n "$WORKTREE_PORCELAIN" ]; then
221
+ # In-progress issues come straight from the already-fetched kernel list (it
222
+ # includes in_progress; only done/cancelled were dropped during the fetch).
223
+ IN_PROGRESS_JSON="$(printf '%s' "$ISSUES_JSON" | jq '[.[] | select(.status == "in_progress")]')"
377
224
  fi
378
225
 
379
- # ── File-level conflict detection ────────────────────────────────────────
380
- # For each active worktree branch, get changed files via:
381
- # git diff <base-branch>...<branch> --name-only --
382
- # Uses -- separator to prevent argument injection (OWASP A03)
226
+ SESSIONS_JSON="$(printf '{"baseBranch":%s,"worktreePorcelain":%s,"inProgressIssues":%s}' \
227
+ "$(printf '%s' "$BASE_BRANCH" | jq -R '.')" \
228
+ "$(printf '%s' "$WORKTREE_PORCELAIN" | jq -Rs '.')" \
229
+ "$IN_PROGRESS_JSON" | "$NODE_CMD" "$(node_script_path "$_SMART_STATUS_DIR/smart-status-sessions.js")")"
230
+ SESSION_COUNT="$(printf '%s' "$SESSIONS_JSON" | jq 'length')"
383
231
 
384
- # ALL_BRANCH_FILES: newline-delimited list of "branch<TAB>file1<TAB>file2..."
385
- ALL_BRANCH_FILES=""
386
232
  if [ "$SESSION_COUNT" -ge 2 ]; then
387
- # Read branches from SESSION_ENTRIES (newline-delimited "branch<TAB>path")
388
- while IFS=' ' read -r _branch _path; do
233
+ BRANCH_FILES_JSON="[]"
234
+ _session_branches="$(printf '%s' "$SESSIONS_JSON" | jq -r '.[].branch')"
235
+ while IFS= read -r _branch; do
389
236
  [ -z "$_branch" ] && continue
390
-
391
- # Get changed files for this branch vs BASE_BRANCH (-- prevents injection)
392
237
  _files="$("$GIT" diff "${BASE_BRANCH}...${_branch}" --name-only -- 2>/dev/null || echo '')"
393
- # Collapse to tab-delimited (tabs can't appear in filenames), strip empty lines
394
- _files_csv="$(printf '%s' "$_files" | tr '\n' '\t' | sed 's/\t$//' | sed 's/^\t//')"
395
-
396
- if [ -n "$ALL_BRANCH_FILES" ]; then
397
- ALL_BRANCH_FILES="${ALL_BRANCH_FILES}
398
- ${_branch}:${_files_csv}"
399
- else
400
- ALL_BRANCH_FILES="${_branch}:${_files_csv}"
401
- fi
402
- done <<CONFLICT_EOF
403
- $SESSION_ENTRIES
404
- CONFLICT_EOF
405
-
406
- # Build conflict map: find files that appear in multiple branches
407
- # and add changed_files + conflicts to SESSIONS_JSON
408
- while IFS= read -r _entry; do
409
- [ -z "$_entry" ] && continue
410
- _branch="${_entry%%:*}"
411
- _files_csv="${_entry#*:}"
412
-
413
- # Convert tab-delimited files to JSON array
414
- if [ -n "$_files_csv" ]; then
415
- _files_json="$(printf '%s' "$_files_csv" | jq -R 'split("\t")')"
416
- else
417
- _files_json="[]"
418
- fi
419
-
420
- # Find conflicts: files in this branch that also appear in other branches
421
- _conflicts_json="[]"
422
- while IFS= read -r _other_entry; do
423
- [ -z "$_other_entry" ] && continue
424
- _other_branch="${_other_entry%%:*}"
425
- _other_files="${_other_entry#*:}"
426
-
427
- # Skip self
428
- [ "$_other_branch" = "$_branch" ] && continue
429
- [ -z "$_other_files" ] && continue
430
-
431
- # Find intersection
432
- _other_json="$(printf '%s' "$_other_files" | jq -R 'split("\t")')"
433
- _overlap="$(jq -n --argjson a "$_files_json" --argjson b "$_other_json" \
434
- '[$a[] as $f | select($b | index($f))] | unique')"
435
- _overlap_len="$(printf '%s' "$_overlap" | jq 'length')"
436
- if [ "$_overlap_len" -gt 0 ]; then
437
- _conflicts_json="$(jq -n \
438
- --argjson existing "$_conflicts_json" \
439
- --arg other_branch "$_other_branch" \
440
- --argjson files "$_overlap" \
441
- '$existing + [{branch: $other_branch, files: $files}]')"
442
- fi
443
- done <<INNER_EOF
444
- $ALL_BRANCH_FILES
445
- INNER_EOF
446
-
447
- # Update SESSIONS_JSON: add changed_files and conflicts to matching branch entry
448
- SESSIONS_JSON="$(printf '%s' "$SESSIONS_JSON" | jq \
238
+ _files_json="$(printf '%s' "$_files" | jq -R -s 'split("\n") | map(select(length > 0))')"
239
+ BRANCH_FILES_JSON="$(printf '%s' "$BRANCH_FILES_JSON" | jq \
449
240
  --arg branch "$_branch" \
450
241
  --argjson files "$_files_json" \
451
- --argjson conflicts "$_conflicts_json" \
452
- '[.[] | if .branch == $branch then . + {changed_files: $files, conflicts: $conflicts} else . end]'
242
+ '. + [{branch: $branch, files: $files}]'
453
243
  )"
454
- done <<OUTER_EOF
455
- $ALL_BRANCH_FILES
456
- OUTER_EOF
457
- fi
244
+ done <<BRANCHEOF
245
+ $_session_branches
246
+ BRANCHEOF
458
247
 
459
- # ── Tier 2: git merge-tree conflict detection ──────────────────────────
460
- # If git >= 2.38 and there are file overlaps from Tier 1, run merge-tree
461
- # to detect actual merge conflicts vs mere file overlap.
248
+ SESSIONS_JSON="$(printf '{"sessions":%s,"branchFiles":%s}' "$SESSIONS_JSON" "$BRANCH_FILES_JSON" | "$NODE_CMD" "$(node_script_path "$_SMART_STATUS_DIR/smart-status-sessions.js")")"
249
+ fi
462
250
 
463
251
  TIER2_ENABLED=0
464
252
  if [ "$SESSION_COUNT" -ge 2 ]; then
465
- # Check git version >= 2.38 (merge-tree --write-tree requires it)
466
253
  _git_ver="$("$GIT" --version 2>/dev/null || echo '')"
467
254
  _git_major=0
468
255
  _git_minor=0
469
- # Parse "git version X.Y.Z..." -> extract major and minor
470
256
  _ver_nums="${_git_ver#git version }"
471
257
  _git_major="${_ver_nums%%.*}"
472
258
  _ver_rest="${_ver_nums#*.}"
473
259
  _git_minor="${_ver_rest%%.*}"
474
- # Validate they are numbers
475
260
  case "$_git_major" in ''|*[!0-9]*) _git_major=0 ;; esac
476
261
  case "$_git_minor" in ''|*[!0-9]*) _git_minor=0 ;; esac
477
262
 
@@ -480,79 +265,38 @@ if [ "$SESSION_COUNT" -ge 2 ]; then
480
265
  fi
481
266
  fi
482
267
 
483
- # For each pair of branches with file overlaps, run merge-tree
484
268
  if [ "$TIER2_ENABLED" = "1" ]; then
485
- # Collect all branch pairs that have conflicts in SESSIONS_JSON
486
269
  _conflict_pairs="$(printf '%s' "$SESSIONS_JSON" | jq -r '
487
270
  [.[] | select((.conflicts // []) | length > 0) |
488
271
  .branch as $b |
489
272
  .conflicts[] |
490
- [$b, .branch] | sort | join(" ")
273
+ [$b, .branch] | sort | join("\t")
491
274
  ] | unique | .[]
492
275
  ')"
493
276
 
494
277
  if [ -n "$_conflict_pairs" ]; then
495
- # Process each unique pair
496
- while IFS= read -r _pair; do
497
- [ -z "$_pair" ] && continue
498
- _b1="${_pair%% *}"
499
- _b2="${_pair#* }"
500
-
501
- # Run merge-tree; exit 1 = actual conflict, exit 0 = clean merge
278
+ MERGE_TREE_RESULTS_JSON="[]"
279
+ while IFS=' ' read -r _b1 _b2; do
280
+ [ -z "$_b1" ] && continue
281
+ [ -z "$_b2" ] && continue
502
282
  _mt_output=""
503
283
  _mt_exit=0
504
284
  _mt_output="$("$GIT" merge-tree --write-tree --name-only --no-messages -- "$_b1" "$_b2" 2>/dev/null)" || _mt_exit=$?
505
-
506
- if [ "$_mt_exit" -ne 0 ] && [ -n "$_mt_output" ]; then
507
- # Real conflict detected — parse conflicted file names
508
- # merge-tree outputs a tree SHA on first line, then filenames
509
- # With --name-only, conflicted files are listed after the SHA line
510
- _conflict_files=""
511
- _line_num=0
512
- while IFS= read -r _cf_line; do
513
- _line_num=$((_line_num + 1))
514
- # Skip the first line (tree SHA output from merge-tree)
515
- if [ "$_line_num" -eq 1 ]; then continue; fi
516
- # Skip empty lines
517
- if [ -z "$_cf_line" ]; then continue; fi
518
- if [ -n "$_conflict_files" ]; then
519
- _conflict_files="${_conflict_files} ${_cf_line}"
520
- else
521
- _conflict_files="${_cf_line}"
522
- fi
523
- done <<MTEOF
524
- $_mt_output
525
- MTEOF
526
-
527
- if [ -n "$_conflict_files" ]; then
528
- _cf_json="$(printf '%s' "$_conflict_files" | jq -R 'split("\t")')"
529
-
530
- # Add merge_conflicts to both branches in SESSIONS_JSON
531
- for _target_branch in "$_b1" "$_b2"; do
532
- _other_branch="$_b1"
533
- [ "$_target_branch" = "$_b1" ] && _other_branch="$_b2"
534
-
535
- SESSIONS_JSON="$(printf '%s' "$SESSIONS_JSON" | jq \
536
- --arg branch "$_target_branch" \
537
- --arg other "$_other_branch" \
538
- --argjson files "$_cf_json" \
539
- '[.[] | if .branch == $branch then
540
- . + {merge_conflicts: ((.merge_conflicts // []) + [{branch: $other, files: $files}])}
541
- else . end]'
542
- )"
543
- done
544
- fi
545
- fi
285
+ MERGE_TREE_RESULTS_JSON="$(printf '%s' "$MERGE_TREE_RESULTS_JSON" | jq \
286
+ --arg left "$_b1" \
287
+ --arg right "$_b2" \
288
+ --arg output "$_mt_output" \
289
+ --argjson exitCode "$_mt_exit" \
290
+ '. + [{left: $left, right: $right, exitCode: $exitCode, output: $output}]'
291
+ )"
546
292
  done <<PAIRSEOF
547
293
  $_conflict_pairs
548
294
  PAIRSEOF
295
+
296
+ SESSIONS_JSON="$(printf '{"sessions":%s,"mergeTreeResults":%s}' "$SESSIONS_JSON" "$MERGE_TREE_RESULTS_JSON" | "$NODE_CMD" "$(node_script_path "$_SMART_STATUS_DIR/smart-status-sessions.js")")"
549
297
  fi
550
298
  fi
551
299
 
552
- # ── Cross-developer team activity ────────────────────────────────────────
553
- # Read file index entries from all developers, identify OTHER developers'
554
- # in-progress work, compute module overlaps, and flag stale claims.
555
-
556
300
  TEAM_ACTIVITY_JSON="[]"
557
301
 
558
302
  # Only proceed if file_index_read and get_session_identity are available
@@ -620,7 +364,7 @@ if command -v file_index_read &>/dev/null && command -v get_session_identity &>/
620
364
  fi
621
365
  fi
622
366
 
623
- # ── Output ──────────────────────────────────────────────────────────────
367
+ # ── Output ──────────────────────────────────────────────────────────────
624
368
 
625
369
  if [ "$JSON_MODE" = "1" ]; then
626
370
  # Always output consistent shape: {sessions: [...], issues: [...], team_activity: [...]}
@@ -637,7 +381,7 @@ else
637
381
  C_RED=$'\033[31m' C_DIM=$'\033[2m' C_BOLD=$'\033[1m' C_CYAN=$'\033[36m'
638
382
  fi
639
383
 
640
- # ── Active Sessions (before grouped output) ──
384
+ # ── Active Sessions (before grouped output) ──
641
385
  if [ "$SESSION_COUNT" -gt 0 ]; then
642
386
  printf '%s%s=== ACTIVE SESSIONS ===%s\n' "$C_BOLD" "$C_CYAN" "$C_RESET"
643
387
  printf '%s' "$SESSIONS_JSON" | jq -r '.[] |
@@ -687,10 +431,10 @@ else
687
431
  printf '\n'
688
432
  fi
689
433
 
690
- # ── Team Activity (cross-developer visibility) ──
434
+ # ── Team Activity (cross-developer visibility) ──
691
435
  _ta_len="$(printf '%s' "$TEAM_ACTIVITY_JSON" | jq 'length')"
692
436
  if [ "$_ta_len" -gt 0 ]; then
693
- printf '%s%s── Team Activity ──────────────────────────────────────%s\n' "$C_BOLD" "$C_CYAN" "$C_RESET"
437
+ printf '%s%s--- Team Activity ----------------------------------------%s\n' "$C_BOLD" "$C_CYAN" "$C_RESET"
694
438
  printf '%s' "$TEAM_ACTIVITY_JSON" | jq -r '
695
439
  .[] |
696
440
  .developer as $dev |
@@ -707,7 +451,7 @@ else
707
451
  else
708
452
  " " + $iid + " (in_progress)" +
709
453
  (if ($mods | length) > 0 then
710
- " touching " + ($mods | join(", "))
454
+ " - touching " + ($mods | join(", "))
711
455
  else "" end)
712
456
  end),
713
457
  # Overlap or no-overlap line
@@ -733,14 +477,18 @@ else
733
477
  # Group assignment (priority order: RESUME > UNBLOCK_CHAINS > BLOCKED > BACKLOG > READY_WORK)
734
478
  # Note: in_progress issues with active blockers still show in RESUME (you started
735
479
  # the work, you need to see it) but get a "BLOCKED" annotation in the output.
480
+ # Counts come from the scorer output: dependents is the reverse-graph
481
+ # array it computes, dependencies is the normalized { depends_on_id }
482
+ # list. done/cancelled were dropped at fetch; the status guards below stay
483
+ # as defense-in-depth so a terminal issue can never land in BLOCKED.
736
484
  (if .status == "in_progress" then "RESUME"
737
- elif (.dependent_count // 0) >= 2 then "UNBLOCK_CHAINS"
738
- elif (.dependency_count // 0) > 0 and .status != "closed" then "BLOCKED"
485
+ elif ((.dependents // []) | length) >= 2 then "UNBLOCK_CHAINS"
486
+ elif ((.dependencies // []) | length) > 0 and .status != "done" and .status != "cancelled" then "BLOCKED"
739
487
  elif (.priority == "P4" or .priority == 4) then "BACKLOG"
740
488
  else "READY_WORK"
741
489
  end) as $group |
742
490
  # Flag in_progress issues that have active blockers
743
- (if .status == "in_progress" and (.dependency_count // 0) > 0 then true else false end) as $blocked_resume |
491
+ (if .status == "in_progress" and ((.dependencies // []) | length) > 0 then true else false end) as $blocked_resume |
744
492
  $item + { group: $group, days_ago: $days_ago, blocked_resume: $blocked_resume }
745
493
  ] |
746
494