@joshuafolkken/kit 1.1010.0 → 1.1050.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (350) hide show
  1. package/.claude/settings.json +1 -5
  2. package/.claude/skills/dependency-update/SKILL.md +6 -3
  3. package/.claude/skills/epic-commands/SKILL.md +46 -17
  4. package/.claude/skills/verify-ui/SKILL.md +1 -1
  5. package/.claude/skills/workflow-commands/SKILL.md +10 -25
  6. package/.claude/skills/workflow-commands/background-commands.md +1 -1
  7. package/.claude/skills/workflow-commands/backlogrun-child.md +6 -4
  8. package/.claude/skills/workflow-commands/backlogrun-lanes.md +1 -1
  9. package/.claude/skills/workflow-commands/backlogrun-park.md +6 -0
  10. package/.claude/skills/workflow-commands/backlogrun-progress.md +30 -36
  11. package/.claude/skills/workflow-commands/backlogrun-steps.md +16 -16
  12. package/.claude/skills/workflow-commands/backlogrun.md +3 -12
  13. package/.claude/skills/workflow-commands/chain-rule.md +2 -2
  14. package/.claude/skills/workflow-commands/followup-reference.md +2 -2
  15. package/.claude/skills/workflow-commands/fullrun-steps.md +4 -3
  16. package/.claude/skills/workflow-commands/fullrun.md +1 -1
  17. package/.claude/skills/workflow-commands/halfrun.md +2 -1
  18. package/.claude/skills/workflow-commands/into-target.md +1 -1
  19. package/.claude/skills/workflow-commands/issue-comments.md +1 -1
  20. package/.claude/skills/workflow-commands/observation-filing.md +80 -126
  21. package/.claude/skills/workflow-commands/pre-gate-cut.md +33 -36
  22. package/.claude/skills/workflow-commands/prerequisite.md +1 -1
  23. package/.claude/skills/workflow-commands/working-tree-hold.md +2 -2
  24. package/.codex/hooks.json +1 -5
  25. package/.github/workflows/auto-tag.yml +21 -0
  26. package/.github/workflows/publish.yml +9 -10
  27. package/.github/workflows/sonar-qube.yml +1 -1
  28. package/AGENTS.md +4 -25
  29. package/CLAUDE.md +24 -38
  30. package/GEMINI.md +4 -24
  31. package/README.md +22 -56
  32. package/dist/CLAUDE.md +24 -38
  33. package/dist/hooks/batch-guard.js +4 -4
  34. package/dist/hooks/{chunk-6PSTVOLH.js → chunk-5BK3K7V4.js} +114 -90
  35. package/dist/hooks/{chunk-PAXMLGSS.js → chunk-7VPDUBRN.js} +93 -175
  36. package/dist/hooks/{chunk-KPZN42RT.js → chunk-DMQN45FN.js} +3 -3
  37. package/dist/hooks/{chunk-WMIR5SNX.js → chunk-EJDX2TOB.js} +13 -3
  38. package/dist/hooks/{chunk-A2H5I2VD.js → chunk-GQ7KP45M.js} +2 -2
  39. package/dist/hooks/{chunk-4GDR2YTV.js → chunk-HJIISEAC.js} +4 -4
  40. package/dist/hooks/{chunk-AWTFKKFW.js → chunk-NAS4C7GP.js} +6 -33
  41. package/dist/hooks/{chunk-56LGMJJV.js → chunk-NJQOBE6L.js} +2 -2
  42. package/dist/hooks/{chunk-EZLHXKJ6.js → chunk-RLDX5SOC.js} +1222 -941
  43. package/dist/hooks/{chunk-GBJUERYK.js → chunk-WQ4OSBSS.js} +10 -3
  44. package/dist/hooks/codex-hook-adapter.js +10 -10
  45. package/dist/hooks/duplicate-read-guard.js +5 -5
  46. package/dist/hooks/format-edited.js +15 -34
  47. package/dist/hooks/investigation-guard.js +5 -5
  48. package/dist/hooks/pretool-guard.js +23 -16
  49. package/dist/hooks/stop-guard.js +21 -200
  50. package/dist/josh.js +42 -125
  51. package/dist/version/index.js +466 -42
  52. package/eslint/base.js +2 -11
  53. package/package.json +36 -10
  54. package/prompts/coding-standards.md +15 -290
  55. package/prompts/collaboration-workflow/cross-repo-epic.md +2 -51
  56. package/prompts/collaboration-workflow/epic-audit.md +2 -53
  57. package/prompts/collaboration-workflow/epic-bundle.md +2 -106
  58. package/prompts/collaboration-workflow/file-edits.md +6 -53
  59. package/prompts/collaboration-workflow/issue-template.md +4 -4
  60. package/prompts/collaboration-workflow/operating-rules.md +18 -75
  61. package/prompts/collaboration-workflow/principles.md +74 -0
  62. package/prompts/collaboration-workflow/residency.md +55 -15
  63. package/prompts/collaboration-workflow/rule-delivery.md +5 -46
  64. package/prompts/collaboration-workflow/shell-body.md +7 -9
  65. package/prompts/collaboration-workflow/turn-batching.md +21 -37
  66. package/prompts/collaboration-workflow/upstream-interrupt.md +1 -1
  67. package/prompts/collaboration-workflow/wip-cap.md +15 -18
  68. package/prompts/collaboration-workflow.md +22 -28
  69. package/prompts/sonar-hotspot-handling.md +1 -1
  70. package/scripts/adopt/adopt-logic.ts +2 -2
  71. package/scripts/adopt/adopt-toolkits.ts +3 -1
  72. package/scripts/adopt/adopt.ts +2 -2
  73. package/scripts/agent/agent-event.ts +2 -9
  74. package/scripts/agent/agent-exit-record.ts +2 -9
  75. package/scripts/auto-ok/auto-ok-cli.ts +9 -9
  76. package/scripts/backlog/backlog-budget-cli.ts +2 -6
  77. package/scripts/backlog/backlog-drive-cli.ts +20 -10
  78. package/scripts/backlog/backlog-drive.ts +50 -16
  79. package/scripts/backlog/backlog-next.ts +24 -8
  80. package/scripts/backlog/backlog-offer-cli.ts +6 -5
  81. package/scripts/backlog/backlog-plan-cli.ts +5 -1
  82. package/scripts/backlog/backlog-plan.ts +1 -1
  83. package/scripts/backlog/backlog-pool.ts +31 -11
  84. package/scripts/backlog/backlog-rank.ts +106 -0
  85. package/scripts/backlog/backlog-waves.ts +42 -29
  86. package/scripts/build/build-bin.ts +2 -1
  87. package/scripts/build/build-config-merge.ts +2 -1
  88. package/scripts/build/build-hooks.ts +31 -6
  89. package/scripts/build/build-managed-marker.ts +2 -1
  90. package/scripts/build/build-self-sync-guard.ts +2 -1
  91. package/scripts/build/build-version.ts +2 -1
  92. package/scripts/cases/cases-logic.ts +2 -6
  93. package/scripts/ci/pr-classification.ts +13 -11
  94. package/scripts/cost-runtime/cost-transcript.ts +4 -11
  95. package/scripts/delegation/delegation-policy.ts +11 -0
  96. package/scripts/doctor/doctor-consumer.ts +5 -12
  97. package/scripts/doctor/doctor-ports.ts +2 -2
  98. package/scripts/document/document-byte-budget.ts +13 -21
  99. package/scripts/document/document-section.ts +2 -6
  100. package/scripts/document/entry-read-budget.ts +6 -5
  101. package/scripts/{git/git-epic-add-body.ts → epic/epic-add-body.ts} +23 -23
  102. package/scripts/{git/git-epic-add-plan.ts → epic/epic-add-plan.ts} +23 -26
  103. package/scripts/{git/git-epic-add.ts → epic/epic-add.ts} +17 -17
  104. package/scripts/epic/epic-audit-cli.ts +4 -4
  105. package/scripts/epic/epic-audit-orphans.ts +2 -2
  106. package/scripts/epic/epic-audit-rationale.ts +1 -1
  107. package/scripts/epic/epic-audit.ts +1 -1
  108. package/scripts/{git/git-epic-body.ts → epic/epic-body.ts} +6 -6
  109. package/scripts/epic/epic-bundle-cli.ts +1 -1
  110. package/scripts/epic/epic-bundle.ts +2 -2
  111. package/scripts/epic/epic-candidate-confirm.ts +2 -1
  112. package/scripts/{git/git-epic-chains.ts → epic/epic-chains.ts} +4 -4
  113. package/{scripts-ai → scripts/epic}/epic-check.ts +5 -4
  114. package/{scripts-ai → scripts/epic}/epic-cli.ts +4 -4
  115. package/scripts/{git/git-epic-close-comment.ts → epic/epic-close-comment.ts} +9 -9
  116. package/scripts/{git/git-epic-close.ts → epic/epic-close.ts} +23 -19
  117. package/scripts/epic/epic-cross-repo.ts +21 -38
  118. package/scripts/{git/git-epic-decision.ts → epic/epic-decision.ts} +12 -14
  119. package/scripts/epic/epic-fetch.ts +3 -3
  120. package/scripts/epic/epic-graph.ts +3 -3
  121. package/scripts/epic/epic-index.ts +2 -2
  122. package/scripts/epic/epic-issue.ts +1 -1
  123. package/scripts/epic/epic-lane-offer.ts +11 -22
  124. package/scripts/epic/epic-next.ts +3 -3
  125. package/scripts/{git/git-epic-parse.ts → epic/epic-parse.ts} +3 -3
  126. package/scripts/{git/git-epic-promote.ts → epic/epic-promote.ts} +10 -10
  127. package/scripts/epic/epic-rank.ts +37 -0
  128. package/scripts/{git/git-epic-read.ts → epic/epic-read.ts} +9 -9
  129. package/scripts/{git/git-epic-reconcile.ts → epic/epic-reconcile.ts} +18 -20
  130. package/scripts/{git/git-epic-reference.ts → epic/epic-reference.ts} +4 -23
  131. package/scripts/epic/epic-relation-recheck.ts +4 -3
  132. package/scripts/{git/git-epic-relations.ts → epic/epic-relations.ts} +5 -5
  133. package/scripts/{git/git-epic-remove-plan.ts → epic/epic-remove-plan.ts} +17 -19
  134. package/scripts/{git/git-epic-remove.ts → epic/epic-remove.ts} +13 -13
  135. package/scripts/{git/git-epic-run.ts → epic/epic-run.ts} +27 -27
  136. package/scripts/{git/git-epic-sections.ts → epic/epic-sections.ts} +6 -6
  137. package/scripts/{git/git-epic-shape.ts → epic/epic-shape.ts} +7 -7
  138. package/scripts/epic/epic-solo.ts +29 -28
  139. package/scripts/{git/git-epic-validate.ts → epic/epic-validate.ts} +13 -13
  140. package/{scripts-ai → scripts/epic}/epic.ts +17 -16
  141. package/scripts/gh/fix-gh-packages.ts +2 -1
  142. package/scripts/gh/gh-spawn.ts +12 -10
  143. package/scripts/git/constants.ts +1 -1
  144. package/scripts/git/git-branch.ts +10 -1
  145. package/scripts/git/git-command.ts +2 -2
  146. package/scripts/git/git-error.ts +2 -5
  147. package/scripts/git/git-execa-error.ts +6 -1
  148. package/{scripts-ai → scripts/git}/git-followup-finish.ts +7 -7
  149. package/scripts/git/git-followup-flush.ts +74 -48
  150. package/scripts/git/git-followup-issue-close.ts +2 -2
  151. package/scripts/git/git-followup-label.ts +1 -1
  152. package/scripts/git/git-followup-pending.ts +1 -1
  153. package/{scripts-ai → scripts/git}/git-followup-workflow.ts +23 -11
  154. package/scripts/git/git-gh-exec.ts +85 -26
  155. package/scripts/git/git-gh-issue-read.ts +2 -2
  156. package/scripts/git/git-gh-issue-rest.ts +2 -2
  157. package/scripts/git/git-gh-issue-write.ts +6 -6
  158. package/scripts/git/git-gh-pr-read.ts +0 -21
  159. package/scripts/git/git-gh-pr.ts +2 -23
  160. package/scripts/git/git-next-issues.ts +34 -5
  161. package/scripts/git/git-pr-followup-wrapup.ts +2 -6
  162. package/scripts/git/git-preflight.ts +25 -10
  163. package/scripts/git/git-push-transport.ts +12 -69
  164. package/scripts/git/git-spawn.ts +79 -3
  165. package/scripts/git/git-ssh-keepalive.ts +74 -0
  166. package/scripts/git/git-staging.ts +21 -9
  167. package/{scripts-ai → scripts/git}/git-workflow.ts +11 -11
  168. package/scripts/git/github-issue-url.ts +1 -1
  169. package/scripts/git/gone-branch.ts +3 -2
  170. package/scripts/git/issue-labels.ts +13 -1
  171. package/scripts/git/issue-rank.ts +89 -0
  172. package/scripts/git/issue-reference.ts +19 -0
  173. package/scripts/git/main-merge.ts +2 -1
  174. package/scripts/git/main-sync.ts +3 -2
  175. package/scripts/git/schemas.ts +1 -1
  176. package/scripts/git/stash-pop-args.ts +7 -13
  177. package/scripts/git/stash-pop-cli.ts +2 -1
  178. package/{scripts-ai → scripts/git}/telegram-test-logic.ts +2 -2
  179. package/{scripts-ai → scripts/git}/telegram-test.ts +7 -7
  180. package/scripts/hooks/format-edited-cli.ts +15 -0
  181. package/scripts/hooks/format-edited-file.ts +2 -9
  182. package/scripts/hooks/format-rewrite-notice.ts +2 -8
  183. package/scripts/hooks/pretool-guard-cli.ts +21 -0
  184. package/scripts/hooks/pretool-guard.ts +14 -15
  185. package/scripts/init/init-ai-copy.ts +2 -5
  186. package/scripts/init/init.ts +8 -4
  187. package/scripts/init/start-exec.ts +7 -1
  188. package/scripts/init/start-plan.ts +18 -5
  189. package/scripts/init/start-setup-pr.ts +46 -19
  190. package/scripts/init/start-steps.ts +43 -10
  191. package/scripts/init/start.ts +42 -11
  192. package/scripts/issue/issue-cite.ts +19 -1
  193. package/scripts/issue/issue-comment-cli.ts +2 -1
  194. package/scripts/issue/issue-file-cli.ts +2 -1
  195. package/scripts/issue/issue-fold-cli.ts +9 -16
  196. package/scripts/issue/issue-scout-cli.ts +8 -13
  197. package/scripts/issue/measure-rerun-cli.ts +7 -6
  198. package/scripts/josh/josh-command-map.ts +0 -102
  199. package/scripts/josh/josh-commands-ai.ts +2 -2
  200. package/scripts/josh/josh-commands-backlog.ts +1 -1
  201. package/scripts/josh/josh-commands-development.ts +3 -3
  202. package/scripts/josh/josh-commands-project.ts +1 -1
  203. package/scripts/josh/josh-commands-workflow.ts +4 -4
  204. package/scripts/lane/lane-child-marker.ts +16 -2
  205. package/scripts/lane/lane-cli.ts +34 -15
  206. package/scripts/lane/lane-open.ts +3 -2
  207. package/scripts/lane/lane-registry.ts +3 -6
  208. package/scripts/lane/lane-report.ts +10 -4
  209. package/scripts/lib/cli-flags.ts +20 -2
  210. package/scripts/lib/error-message.ts +9 -0
  211. package/scripts/lib/read-file.ts +26 -2
  212. package/scripts/observations/observation-ledger-home.ts +98 -26
  213. package/scripts/observations/observation-ledger-migrate.ts +26 -21
  214. package/scripts/observations/observation-ledger-prepare.ts +10 -20
  215. package/scripts/observations/observation-ledger.ts +58 -25
  216. package/scripts/observations/observations-flush-cli.ts +6 -23
  217. package/scripts/observations/observations-flush-landing.ts +2 -1
  218. package/scripts/observations/observations-flush.ts +29 -20
  219. package/scripts/package/package-scout-cli.ts +8 -16
  220. package/scripts/ports/port-command.ts +2 -1
  221. package/scripts/propagate/propagate-plan.ts +185 -0
  222. package/scripts/propagate/propagate-publish.ts +6 -7
  223. package/scripts/propagate/propagate-run.ts +5 -1
  224. package/scripts/propagate/propagate-steps.ts +18 -2
  225. package/scripts/propagate/propagate-targets.ts +13 -2
  226. package/scripts/propagate/propagate.ts +63 -44
  227. package/scripts/refactor/import-graph.ts +2 -6
  228. package/scripts/registry-migration/migrate-logic.ts +1 -0
  229. package/scripts/registry-migration/migrate.ts +3 -2
  230. package/scripts/registry-migration/user-npmrc.ts +2 -2
  231. package/scripts/release/github-release.ts +1 -1
  232. package/scripts/release/release-cli.ts +2 -1
  233. package/scripts/repo/repo-setting.ts +10 -8
  234. package/scripts/review/review-attest.ts +44 -0
  235. package/scripts/review/review-brief-cli.ts +49 -2
  236. package/scripts/review/review-brief.ts +46 -1
  237. package/scripts/review/review-finding-ledger.ts +3 -3
  238. package/scripts/review/review-findings-cli.ts +4 -11
  239. package/scripts/review/review-record-cli.ts +14 -11
  240. package/scripts/review/review-record.ts +6 -16
  241. package/scripts/review/review-stamps.ts +7 -0
  242. package/scripts/rules/decision-oracle.ts +2 -2
  243. package/scripts/rules/implementation-cut.ts +1 -1
  244. package/scripts/rules/issue-fold.ts +1 -2
  245. package/scripts/rules/lane-carry-conflict.ts +1 -2
  246. package/scripts/rules/lane-park.ts +1 -2
  247. package/scripts/rules/pre-gate-cut.ts +2 -2
  248. package/scripts/rules/rule-body-guard.ts +2 -2
  249. package/scripts/rules/rule-value-cache.ts +99 -0
  250. package/scripts/rules/rule-value-cli.ts +10 -9
  251. package/scripts/rules/rule-value.ts +1 -1
  252. package/scripts/run/run-carry-args.ts +2 -6
  253. package/scripts/run/run-carry-cli.ts +5 -7
  254. package/scripts/run/run-cut-args.ts +7 -13
  255. package/scripts/run/run-ending-cli.ts +4 -7
  256. package/scripts/run/run-event-stream.ts +2 -5
  257. package/scripts/run/run-headless.ts +22 -6
  258. package/scripts/run/run-liveness-cli.ts +4 -7
  259. package/scripts/run/run-parent-cut-hook.ts +144 -0
  260. package/scripts/run/run-progress-args.ts +2 -6
  261. package/scripts/run/run-progress-cli.ts +2 -1
  262. package/scripts/run/run-progress-read.ts +2 -1
  263. package/scripts/run/run-progress.ts +21 -8
  264. package/scripts/run/run-ship-cli.ts +6 -74
  265. package/scripts/run/run-ship-preflight.ts +87 -0
  266. package/scripts/run/run-ship-review-steps.ts +5 -26
  267. package/scripts/run/run-ship-review.ts +9 -0
  268. package/scripts/run/run-ship-scoped.ts +44 -0
  269. package/scripts/run/run-ship-stage.ts +5 -1
  270. package/scripts/run/run-ship-steps.ts +105 -0
  271. package/scripts/run/run-ship.ts +2 -0
  272. package/scripts/run/run-tail-cli.ts +3 -3
  273. package/scripts/run/run-tidy-stashes.ts +7 -14
  274. package/scripts/run/run-wake-cli.ts +4 -8
  275. package/scripts/run/run-wake-describe.ts +19 -1
  276. package/scripts/run/run-wake-driver.ts +15 -2
  277. package/scripts/run/run-wake-session.ts +14 -4
  278. package/scripts/run/run-watcher-hook.ts +1 -1
  279. package/scripts/safe-chain/project-config.ts +3 -6
  280. package/scripts/security/security-audit-provision.ts +6 -7
  281. package/scripts/sonar/sonar-hotspots-cli.ts +2 -1
  282. package/scripts/sync/directory-copy-guard.ts +2 -1
  283. package/scripts/sync/sync-ai-files.ts +3 -3
  284. package/scripts/sync/template-source-logic.ts +3 -4
  285. package/scripts/test/e2e-retry-check.ts +3 -6
  286. package/scripts/time-runtime/time-bundle-call.ts +2 -2
  287. package/scripts/ui/ui-routes-cli.ts +3 -6
  288. package/scripts/version/bump-version.ts +2 -1
  289. package/scripts/version/npm-registry.ts +97 -0
  290. package/scripts/version/version-commands.ts +5 -4
  291. package/scripts/version/version-remote.ts +38 -33
  292. package/scripts/version/version-targets.ts +3 -3
  293. package/.claude/skills/workflow-commands/rule-residency.md +0 -267
  294. package/evals/scenarios/consult-not-execute.json +0 -20
  295. package/evals/scenarios/no-implicit-workflow.json +0 -26
  296. package/evals/scenarios/overrides-both-locations.json +0 -29
  297. package/evals/scenarios/upstream-interrupt.json +0 -23
  298. package/evals/scenarios/workflow-skill-loaded.json +0 -16
  299. package/prompts/agent-lint-protocol.json +0 -79
  300. package/prompts/agent-rules.md +0 -63
  301. package/prompts/collaboration-workflow/consultation-vs-execution.md +0 -8
  302. package/prompts/collaboration-workflow/distributed-docs.md +0 -7
  303. package/prompts/collaboration-workflow/durable-rules.md +0 -24
  304. package/prompts/collaboration-workflow/latest-first.md +0 -14
  305. package/prompts/collaboration-workflow/no-clones.md +0 -11
  306. package/prompts/collaboration-workflow/simplicity-first.md +0 -9
  307. package/prompts/collaboration-workflow/single-source-rules.md +0 -13
  308. package/scripts/build/shim-shell.ts +0 -25
  309. package/scripts/claude/skill-meta.ts +0 -37
  310. package/scripts/document/document-scan.ts +0 -108
  311. package/scripts/document/generate-catalog.ts +0 -69
  312. package/scripts/document/retired-phrases.ts +0 -143
  313. package/scripts/document/review-agent-type.ts +0 -46
  314. package/scripts/document/single-source.ts +0 -73
  315. package/scripts/git/git-fixture-workspace.ts +0 -88
  316. package/scripts/hooks/format-edited-file-fixtures.ts +0 -109
  317. package/scripts/hooks/prompt-hooks.ts +0 -38
  318. package/scripts/init/hook-command-bootstrap.ts +0 -83
  319. package/scripts/issue/issue-logic.ts +0 -50
  320. package/scripts/josh/__snapshots__/josh-command-map.test.ts.snap +0 -1227
  321. package/scripts/josh/josh-script-reader.ts +0 -11
  322. package/scripts/package/production-dependency-graph.ts +0 -68
  323. package/scripts/retrospective/retrospective-cli.ts +0 -97
  324. package/scripts/retrospective/retrospective.ts +0 -127
  325. package/scripts/rules/delivered-rules-harness.ts +0 -72
  326. package/scripts/rules/top-level-scripts-guard.ts +0 -47
  327. package/scripts/run/run-carry-flush.ts +0 -58
  328. package/scripts/run/run-transcript.golden.txt +0 -57
  329. package/scripts/run/run-wake-work.ts +0 -108
  330. package/scripts/sync/dependabot-pin-logic.ts +0 -135
  331. package/scripts/test/classify-isolation.ts +0 -149
  332. package/scripts/test/http-fault-injection.ts +0 -79
  333. package/scripts/test/josh-harness-environment.ts +0 -260
  334. package/scripts/test/josh-harness.ts +0 -96
  335. package/scripts/test/pilot-files.ts +0 -452
  336. package/scripts/test/pilot-measure.ts +0 -78
  337. package/scripts/test/test-network-guard.ts +0 -453
  338. package/scripts/test/test-repository-guard.ts +0 -317
  339. package/scripts/test/test-state-guard.ts +0 -85
  340. package/scripts/test/test-stdout-guard.ts +0 -54
  341. package/scripts/test/test-telegram-guard.ts +0 -90
  342. package/scripts/test/unit-guard-environment.ts +0 -12
  343. package/scripts/test/unit-projects.ts +0 -139
  344. package/scripts/test/vitest-include-globs.ts +0 -12
  345. package/scripts/time-runtime/time-batch-guard-fixtures.ts +0 -66
  346. package/scripts-ai/completion-gate.ts +0 -13
  347. package/scripts-ai/environment-loader.ts +0 -9
  348. /package/{scripts-ai → scripts/epic}/epic-cli-argv.ts +0 -0
  349. /package/{scripts-ai → scripts/epic}/epic-cli-remove.ts +0 -0
  350. /package/{scripts-ai → scripts/git}/followup-issue-number.ts +0 -0
@@ -2,7 +2,9 @@
2
2
 
3
3
  **単一ソースはこのファイルである。**
4
4
 
5
- **この規則は常駐していない — 引き金つき配送に移った**(joshuafolkken/kit#1524)。`pnpm josh rule:guard` が Issue を作成する `Bash` 呼び出し(`pnpm josh issue:file`。`gh issue create` や `…/issues` への `title` 付き POST による直接起票は `direct-filing` が毎回拒否する)を拒否し、そこで数え方・拒否・2 つの免除・免除を決める 3 条件を突きつける。起票が無いターンでは何も起きず、それは上限に触れる行為が無いということである。配送は**ラン 1 回につき 1 度**なので、数えたうえで同じ呼び出しをもう一度出せばよい。機構と列挙表は `rule-delivery.md`、配送文の実体は `scripts/rules/delivered-rules.ts` の `WIP_CAP_REASON` にあり、`scripts/backlog/backlog-manufacturing-rule.test.ts` がその中身を固定している。
5
+ **この規則は常駐していない — 引き金つき配送に移った**(joshuafolkken/kit#1524)。`pnpm josh rule:guard` が Issue を作成する `Bash` 呼び出し(`pnpm josh issue:file`。`gh issue create` や `…/issues` への `title` 付き POST による直接起票は `direct-filing` が毎回拒否する)を拒否し、そこで数え方・拒否・2 つの免除・免除を決める 3 条件を突きつける。起票が無いターンでは何も起きず、それは上限に触れる行為が無いということである。配送は**ラン 1 回につき 1 度**なので、数えたうえで同じ呼び出しをもう一度出せばよい。機構と列挙表は `rule-delivery.md`、配送文の実体は `scripts/rules/delivered-rules.ts` の `WIP_CAP_REASON` にある(固定するテストは `docs/maintainers/wip-cap-rationale.md` →「文言を固定しているテスト」)。
6
+
7
+ 背景・測定・経緯は保守者向けの `docs/maintainers/wip-cap-rationale.md` にあり、ラン中に読む必要はない。
6
8
 
7
9
  ## 規則
8
10
 
@@ -19,11 +21,11 @@ gh api "repos/{owner}/{repo}/issues?state=open&per_page=100" --paginate \
19
21
  - epic も子も含める。epic を除外すると、epic を作ることで上限を回避できてしまう。
20
22
  - **上限は 30。** 31 件目以降を作る前に 1 件閉じる。
21
23
  - **プルリクエストは数えない。** REST の `issues` エンドポイントは PR も返すため、`select(.pull_request == null)` で落とす。この 1 句を省くと、PR が開いているだけで上限に達する。
22
- - **`gh issue list` は使わない。** 配布ドキュメントの実行可能ブロックに置ける `gh` は REST のものだけで、`gh issue list` は GraphQL 経由のためクラウドセッションで 403 になる(`scripts/gh/gh-document-guard.test.ts`)。
24
+ - **`gh issue list` は使わない。** 配布ドキュメントの実行可能ブロックに置ける `gh` は REST のものだけで、`gh issue list` は GraphQL 経由のためクラウドセッションで 403 になる。
23
25
 
24
26
  ## なぜ上限が要るのか
25
27
 
26
- 2026-09-06 までの 7 日間で起票 257 件・クローズ 163 件、**1 日あたり +13.4 件**。直近 14 日は 14 日すべてで起票がクローズを上回った。一方 `fullrun` は PR 作成からマージまで中央値およそ 10 分で、**処理速度は問題ではなかった**。到着側が処理側を上回り続けていたのであり、オープン件数に上限が無いため、その増加は誰にも見えないまま蓄積した。
28
+ 測定は `docs/maintainers/wip-cap-rationale.md` →「なぜ上限が要るのか — 測定」。
27
29
 
28
30
  **上限は、増加を見えるようにするための強制装置である。** 数を減らすこと自体が目的ではない。30 を超えた状態で起票しようとしたときに「本当にこれは 1 件増やす価値があるか」を必ず 1 回考えさせる、そこだけが役割である。
29
31
 
@@ -45,15 +47,15 @@ gh api "repos/{owner}/{repo}/issues?state=open&per_page=100" --paginate \
45
47
 
46
48
  前提 Issue(`SKILL.md` → §2d)、別パッケージ起因の割り込み Issue、ユーザーが `new` と打った入口、`issue:scout` が重複無しと答えた新規作業、**そして分割判定が作る子 Issue と epic**。**これらは起票しないと実行が進まない。**
47
49
 
48
- - **上限を理由に止めない。** 止めれば、製造を減らす規則が実行を止めることになり、Issue が言うとおり「今より悪い状態」になる。
49
- - **分割の子がここに入る理由**: 分割を検出した `fullrun` / `halfrun` は「子と epic を起票して **STOP**」と定められている(`fullrun.md` / `halfrun.md`)。起票を止めて 1 Issue のまま実装へ進むのは、その停止規則を破って 1 Issue 分の承認を N 件分に広げることであり、上限が防ぐはずだったものより重い。**分割するかどうかを決めるのは分割判定の側**で、既定はもう「分割しない」に上がっている — 上限が二重に効く必要はない。
50
+ - **上限を理由に止めない。** 理由は `docs/maintainers/wip-cap-rationale.md` →「実行が詰まる起票を止めない理由」。
51
+ - **分割の子がここに入る理由**: 分割を検出した `fullrun` / `halfrun` は「子と epic を起票して **STOP**」と定められている(`fullrun.md` / `halfrun.md`)。**分割するかどうかを決めるのは分割判定の側**で、既定はもう「分割しない」に上がっている — 上限が二重に効く必要はない。
50
52
  - **超過した事実は完了報告に 1 行書く**(例: 「オープン 34 件で起票した」)。上限は可視化のための装置なので、超えたことが見えていれば役割は果たしている。
51
53
 
52
54
  ### 割り込み起票 — 上限が効かない側(3 条件で機械的に決める)
53
55
 
54
- **重大な欠陥の発見は、それが現在のランを止めていなくても捨ててはならない。** joshuafolkken/kit#1517 は並列実行を成立させない欠陥だったが、発見した実行単位のランをその瞬間ブロックしてはいなかったため裁量側に落ち、**別 Issue のコメント本文の中にだけ**残った。利用者が偶然そのコメントを読まなければ失われていた。上限の目的は増加を見えるようにすることであって、**発見を捨てることではない**(上の「なぜ上限が要るのか」)。
56
+ **重大な欠陥の発見は、それが現在のランを止めていなくても捨ててはならない。** 上限の目的は増加を見えるようにすることであって、**発見を捨てることではない**(上の「なぜ上限が要るのか」)。由来は `docs/maintainers/wip-cap-rationale.md` →「割り込み区分の由来 — joshuafolkken/kit#1517」。
55
57
 
56
- **別パッケージ起因の割り込みとは別の区分である。** あちらは上流リポジトリへ起票して停止する手順(`upstream-interrupt.md`、`route:tier-a`)で、実行が詰まる側に属する。ここで言う割り込みは、**このリポジトリの欠陥で、発見したランをブロックしていないもの**を指す。両者を同じものとして読んだことが joshuafolkken/kit#1517 を落とした経路そのものである。
58
+ **別パッケージ起因の割り込みとは別の区分である。** あちらは上流リポジトリへ起票して停止する手順(`upstream-interrupt.md`、`route:tier-a`)で、実行が詰まる側に属する。ここで言う割り込みは、**このリポジトリの欠陥で、発見したランをブロックしていないもの**を指す。
57
59
 
58
60
  #### 3 条件 — 該当するかは判断ではない
59
61
 
@@ -65,7 +67,7 @@ gh api "repos/{owner}/{repo}/issues?state=open&per_page=100" --paginate \
65
67
 
66
68
  **3 つのいずれにも当たらない発見は、従来どおり裁量側の出口を取る。** 改善案、設計上の好み、未検証の疑い、「あとで直したい」はここに入らない — レビュー指摘なら branch 3(PR 本文に 1 行残して落とす)であり、それは既定の出口であって上限に阻まれたときの代替ではない。
67
69
 
68
- **深刻さの自己申告は条件ではない。** 「重大だと思う」を条件に加えた瞬間、割り込みは誰でも通れる抜け道になり、上限そのものが無意味になる。3 条件は、当たるか当たらないかを **他人が同じ答えに到達できる**形で書いてあり、そこが唯一の役割である。
70
+ **深刻さの自己申告は条件ではない。** 理由は `docs/maintainers/wip-cap-rationale.md` →「深刻さの自己申告を条件にしない理由」。
69
71
 
70
72
  #### 該当したときの手順
71
73
 
@@ -76,14 +78,14 @@ gh api "repos/{owner}/{repo}/issues?state=open&per_page=100" --paginate \
76
78
  ```
77
79
 
78
80
  2. **超過している事実と、当たった条件の番号を本文に 1 行書く**(例:「オープン 37 件で起票。3 条件のうち 2(文書化された手順が完了できない)に該当」)。**どちらか一方では足りない** — 件数だけでは判定が再現できず、条件だけでは上限の可視化が効かない。
79
- 3. **次に実行されるものとして挿入する。** epic の下にあるなら `pnpm josh epic --add <E> <N>` で、**位置を指定せずに**追加する(`<E>` が epic、`<N>` が起票した割り込み)。**`--before` / `--after` を使ってはならない。** それらは `blocked-by` 関係を実際に書き込むため(`docs/josh-commands.md` →「`josh epic --add`」)、「発見したランをブロックしていない欠陥」という割り込みの定義と矛盾する**偽の依存関係**になり、`epic:next` が実装中の子を「割り込みにブロックされている」として出さなくなる。位置を指定しない追加は依存を一切宣言しない(joshuafolkken/kit#1253)ので、**順序は実行側が持つ** — 次に取り上げるのは実行側の選択であって、宣言された関係ではない(位置無し追加が依存を作らなくなったのは joshuafolkken/kit#1253 であり、`--after` の継ぎ足しなど残りの経路は joshuafolkken/kit#1080 で**まだ開いている** — 塞がった側を自分から迂回して、開いている側と同じ欠陥をここで作り直さないため)。**先に提示させたいときは `--order-before <M>` を使う**(joshuafolkken/kit#1738)— これはタスクリストの行だけを動かし、依存宣言も `blocked-by` も一切書かないので、上の禁止には当たらない。**禁止しているのは依存を書き込む `--before` / `--after` であって、順序そのものではない。** `epic:next` は runnable な子をタスクリスト順に提示する(joshuafolkken/kit#1583)ため、位置を指定しない追加は「末尾に提示される」を意味する — 割り込みを次に取り上げてほしいなら、行だけを前に出すこの指定がその手段である。**epic の下に無いなら挿入先そのものが無い**ので、この手順は飛ばして 4 だけを行う。
81
+ 3. **次に実行されるものとして挿入する。** epic の下にあるなら `pnpm josh epic --add <E> <N>` で、**位置を指定せずに**追加する(`<E>` が epic、`<N>` が起票した割り込み)。**`--before` / `--after` を使ってはならない。** それらは `blocked-by` 関係を実際に書き込むため(`docs/josh-commands.md` →「`josh epic --add`」)、「発見したランをブロックしていない欠陥」という割り込みの定義と矛盾する**偽の依存関係**になり、`epic:next` が実装中の子を「割り込みにブロックされている」として出さなくなる。位置を指定しない追加は依存を一切宣言しない(joshuafolkken/kit#1253)ので、**順序は実行側が持つ** — 次に取り上げるのは実行側の選択であって、宣言された関係ではない(経緯は `docs/maintainers/wip-cap-rationale.md` →「位置を指定しない追加の経緯」)。**先に提示させたいときは `--order-before <M>` を使う**(joshuafolkken/kit#1738)— これはタスクリストの行だけを動かし、依存宣言も `blocked-by` も一切書かないので、上の禁止には当たらない。**禁止しているのは依存を書き込む `--before` / `--after` であって、順序そのものではない。** `epic:next` は runnable な子をタスクリスト順に提示する(joshuafolkken/kit#1583)ため、位置を指定しない追加は「末尾に提示される」を意味する — 割り込みを次に取り上げてほしいなら、行だけを前に出すこの指定がその手段である。**epic の下に無いなら挿入先そのものが無い**ので、この手順は飛ばして 4 だけを行う。
80
82
  4. **着手は、既にある承認の内側でのみ、指示を待たずに行う。** `backlogrun` の中なら、打たれたキーワードがバッチを承認しているので、割り込みは次の子として着手してよい。**バッチの外では `CLAUDE.md` →「Explicit invocation required」が変わらず効く** — 起票と挿入まで済ませたうえで、利用者に打つべきコマンド(`fullrun #<N>`)を報告して止まる。**割り込みは上限の例外であって、明示起動規則の例外ではない。**
81
83
 
82
84
  **起票と、実行されるようにするところまでが 1 つのまとまりである。** epic の下にある割り込みを起票だけして追加しなければ、`epic:next` はそれを候補にすら出さない — Issue は残るが実行されないという、コメントに埋もれるのと大差ない状態になる。**epic の外にある割り込みでは、まとまりの後半は 4 の報告そのもの**であり、打つべきコマンドを利用者に渡すまでが 1 回の行為である。上の「ひとまとまりで判定する」がここにも効く。
83
85
 
84
86
  #### 実行のしかた — 検証経路そのものの欠陥は単独で走らせる
85
87
 
86
- **割り込みの対象が検証経路そのものの欠陥であるとき、その Issue は単独で実行し、バッチを再開するのはそれが `main` へマージされてからとする。** 「着地」はマージであって、PR を開いた時点でもレビューが収束した時点でもない — 壊れた検証の上でバッチを回せないというのがこの節の前提なので、**修正が効き始めるのはマージの瞬間**だからである。
88
+ **割り込みの対象が検証経路そのものの欠陥であるとき、その Issue は単独で実行し、バッチを再開するのはそれが `main` へマージされてからとする。** 「着地」はマージであって、PR を開いた時点でもレビューが収束した時点でもない。
87
89
 
88
90
  **該当するかは判断ではなく、影響先の列挙で決まる。** 欠陥が次のいずれかに影響するか:
89
91
 
@@ -92,14 +94,9 @@ gh api "repos/{owner}/{repo}/issues?state=open&per_page=100" --paginate \
92
94
  - **push 時のフック**
93
95
  - **マージ時のチェック**
94
96
 
95
- **いずれかに当たれば単独実行。** その Issue に `run:solo` を付け、強制はそれを読む `backlog:next` と `epic:next --lanes` が行う(joshuafolkken/kit#2776)。当たらなければ(機能追加、文書修正など)`run:lane` を付け、並列バッチの一員として走らせてよい。どちらもなければ `triage` が返り何も始まらない(joshuafolkken/kit#2779)ので、run が起票する Issue(割り込み・分割・前提)は起票時にどちらかを付ける。**「重大だと感じるか」は判定条件ではない** — 3 条件と同じ理由で、深刻さの自己申告を条件に加えた瞬間、この区分も抜け道になる。
96
-
97
- **理由は 2 つあり、どちらか一方だけでも単独実行の根拠として十分である。**
98
-
99
- 1. **壊れた検証の上でバッチを回すと、全員の結果が信用できない。** 6 レーンを並列で走らせれば、6 件分のゲートまたはレビューがまとめて無意味になる。直したあとに全部やり直すことになるので、単独実行は遅い選択ですらない。
100
- 2. **割り込み自身の検証が、その割り込みが直そうとしている欠陥の影響下にある。** joshuafolkken/kit#1515(テストが実ネットワークを叩いていた)と joshuafolkken/kit#1517(同時実行のスイートが一時ディレクトリを共有していた)はどちらもこの自己言及の罠を抱えており、両者とも単独実行で扱った。
97
+ **いずれかに当たれば単独実行。** その Issue に `run:solo` を付け、強制はそれを読む `backlog:next` と `epic:next --lanes` が行う(joshuafolkken/kit#2776)。当たらなければ(機能追加、文書修正など)`run:lane` を付け、並列バッチの一員として走らせてよい。どちらもなければ `triage` が返り何も始まらない(joshuafolkken/kit#2779)ので、run が起票する Issue(割り込み・分割・前提)は起票時にどちらかを付ける。**「重大だと感じるか」は判定条件ではない**(3 条件と同じ理由)。
101
98
 
102
- **判定が揺れた実例がこの節の由来である。** joshuafolkken/kit#1522(レーンで走る子のレビューが、レーンではなくセッションのチェックアウトを読む)は #1515 / #1517 と同じ形なのに、起票直後は並列バッチの一員として扱われ、利用者の指摘で単独に戻された。同じ判断者が同じ週に逆の答えを出しており、**列挙が無ければ一貫しない**ことがそこで示された。しかも #1522 は嘘の赤ではなく**嘘の緑**を返す側で、より危険である。
99
+ **理由は 2 つあり、どちらか一方だけでも単独実行の根拠として十分である。** その 2 つと、判定を列挙にした由来は `docs/maintainers/wip-cap-rationale.md` →「単独実行の理由と由来」。
103
100
 
104
101
  ## 上限そのものを変えるとき
105
102
 
@@ -109,7 +106,7 @@ gh api "repos/{owner}/{repo}/issues?state=open&per_page=100" --paginate \
109
106
 
110
107
  ## 3 つは一緒に動く
111
108
 
112
- 上限は単独では効かない。**製造側を止めないまま上限だけ入れると、製造は続いたまま実行だけが止まる。** だから joshuafolkken/kit#1469 は 3 つを 1 コミットで着地させた。
109
+ 上限は単独では効かない。**製造側を止めないまま上限だけ入れると、製造は続いたまま実行だけが止まる。** 経緯は `docs/maintainers/wip-cap-rationale.md` →「3 つを 1 コミットで着地させた経緯」。
113
110
 
114
111
  | 製造元 | 変更 | 単一ソース |
115
112
  | ------------------------- | ------------------------------------------------- | ----------------------------------------------------------------------- |
@@ -10,34 +10,28 @@
10
10
 
11
11
  **話題ごとにファイルが分かれている。** 以前はこの内容が 1 本の 169KB のファイルにあり、1 つの節を確かめるだけでも全体を読む必要があった。読んだものはそのセッションの残り全ターンで積み上がった前置きとして課金され続けるため、確認 1 回の費用が会話の長さに比例して効いていた(joshuafolkken/kit#965)。**必要な 1 本だけを開くこと。この索引を入口に、下の表から選ぶ。**
12
12
 
13
- | 話題 | ファイル |
14
- | ------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------- |
15
- | Overview | [`overview.md`](./collaboration-workflow/overview.md) |
16
- | Step 1: Issue 作成テンプレ | [`issue-template.md`](./collaboration-workflow/issue-template.md) |
17
- | Step 2: 提案依頼(AI 共通) | [`proposal-request.md`](./collaboration-workflow/proposal-request.md) |
18
- | Step 3: 計画コメントを記録して通知する | [`plan-comment.md`](./collaboration-workflow/plan-comment.md) |
19
- | 報告フォーマット(平易な概要 + 技術詳細) | [`report-format.md`](./collaboration-workflow/report-format.md) |
20
- | セッション向け出力で Issue はリンク+短い日本語要約で参照する | [`issue-citation.md`](./collaboration-workflow/issue-citation.md) |
21
- | 後から関連が判明した Issue を epic に束ねる | [`epic-bundle.md`](./collaboration-workflow/epic-bundle.md) |
22
- | オープン Issue の WIP 上限(30 件) | [`wip-cap.md`](./collaboration-workflow/wip-cap.md) |
23
- | リポジトリをまたぐ EPIC | [`cross-repo-epic.md`](./collaboration-workflow/cross-repo-epic.md) |
24
- | `josh epic:audit` — 子 Issue 群を横断して矛盾を検出する | [`epic-audit.md`](./collaboration-workflow/epic-audit.md) |
25
- | 別パッケージ起因の問題は割り込み Issue で対応する | [`upstream-interrupt.md`](./collaboration-workflow/upstream-interrupt.md) |
26
- | クローン禁止・単一ソース化(パッケージ境界を越えても) | [`no-clones.md`](./collaboration-workflow/no-clones.md) |
27
- | 設計はエレガント・シンプルを第一目標にする(仕組みを足す前に原因を問う) | [`simplicity-first.md`](./collaboration-workflow/simplicity-first.md) |
28
- | 相談と実行を区別する(議論中にファイルを編集しない) | [`consultation-vs-execution.md`](./collaboration-workflow/consultation-vs-execution.md) |
29
- | 配布ドキュメント・設定の変更は kit に上流化する | [`distributed-docs.md`](./collaboration-workflow/distributed-docs.md) |
30
- | エージェント規則の単一ソースは `CLAUDE.md`(`AGENTS.md` / `GEMINI.md` は導線) | [`single-source-rules.md`](./collaboration-workflow/single-source-rules.md) |
31
- | 最新優先・fix-forward(pin-back は最終手段) | [`latest-first.md`](./collaboration-workflow/latest-first.md) |
32
- | 恒久ルールは MEMORY ではなくプロンプト/ドキュメントに書く | [`durable-rules.md`](./collaboration-workflow/durable-rules.md) |
33
- | ファイル編集はコマンド本文に本文を載せない | [`file-edits.md`](./collaboration-workflow/file-edits.md) |
34
- | 本文をシェルの二重引用符に載せない | [`shell-body.md`](./collaboration-workflow/shell-body.md) |
35
- | 独立した呼び出しは同じターンに載せる | [`turn-batching.md`](./collaboration-workflow/turn-batching.md) |
36
- | `gh` は REST(`gh api`)で書く — 散文の指示も含む | [`gh-rest.md`](./collaboration-workflow/gh-rest.md) |
37
- | 常駐ドキュメントと skill の分担(何を常駐に残すか) | [`residency.md`](./collaboration-workflow/residency.md) |
38
- | 引き金つき配送 — 規則を効く瞬間に届ける | [`rule-delivery.md`](./collaboration-workflow/rule-delivery.md) |
39
- | コマンド出力が文脈へ持ち込む量の上限 | [`output-bounds.md`](./collaboration-workflow/output-bounds.md) |
40
- | 運用ルール | [`operating-rules.md`](./collaboration-workflow/operating-rules.md) |
13
+ | 話題 | ファイル |
14
+ | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- |
15
+ | Overview | [`overview.md`](./collaboration-workflow/overview.md) |
16
+ | Step 1: Issue 作成テンプレ | [`issue-template.md`](./collaboration-workflow/issue-template.md) |
17
+ | Step 2: 提案依頼(AI 共通) | [`proposal-request.md`](./collaboration-workflow/proposal-request.md) |
18
+ | Step 3: 計画コメントを記録して通知する | [`plan-comment.md`](./collaboration-workflow/plan-comment.md) |
19
+ | 報告フォーマット(平易な概要 + 技術詳細) | [`report-format.md`](./collaboration-workflow/report-format.md) |
20
+ | セッション向け出力で Issue はリンク+短い日本語要約で参照する | [`issue-citation.md`](./collaboration-workflow/issue-citation.md) |
21
+ | 後から関連が判明した Issue を epic に束ねる(本文は `epic-commands` skill) | [`epic-bundle.md`](./collaboration-workflow/epic-bundle.md) |
22
+ | オープン Issue の WIP 上限(30 件) | [`wip-cap.md`](./collaboration-workflow/wip-cap.md) |
23
+ | リポジトリをまたぐ EPIC(本文は `epic-commands` skill) | [`cross-repo-epic.md`](./collaboration-workflow/cross-repo-epic.md) |
24
+ | `josh epic:audit` — 子 Issue 群を横断して矛盾を検出する(本文は `epic-commands` skill) | [`epic-audit.md`](./collaboration-workflow/epic-audit.md) |
25
+ | 別パッケージ起因の問題は割り込み Issue で対応する | [`upstream-interrupt.md`](./collaboration-workflow/upstream-interrupt.md) |
26
+ | 原則 — クローン禁止・シンプル第一・相談と実行の区別・最新優先・恒久ルールと配布物と規則の置き場所 | [`principles.md`](./collaboration-workflow/principles.md) |
27
+ | ファイル編集はコマンド本文に本文を載せない | [`file-edits.md`](./collaboration-workflow/file-edits.md) |
28
+ | 本文をシェルの二重引用符に載せない | [`shell-body.md`](./collaboration-workflow/shell-body.md) |
29
+ | 独立した呼び出しは同じターンに載せる | [`turn-batching.md`](./collaboration-workflow/turn-batching.md) |
30
+ | `gh` は REST(`gh api`)で書く — 散文の指示も含む | [`gh-rest.md`](./collaboration-workflow/gh-rest.md) |
31
+ | 常駐ドキュメントと skill の分担(何を常駐に残すか) | [`residency.md`](./collaboration-workflow/residency.md) |
32
+ | 引き金つき配送 — 規則を効く瞬間に届ける | [`rule-delivery.md`](./collaboration-workflow/rule-delivery.md) |
33
+ | コマンド出力が文脈へ持ち込む量の上限 | [`output-bounds.md`](./collaboration-workflow/output-bounds.md) |
34
+ | 運用ルール | [`operating-rules.md`](./collaboration-workflow/operating-rules.md) |
41
35
 
42
36
  **どの 1 本を開けばよいかを決めるのに必要なのは、この索引だけである。** バイト数はここに書かない — 手で保守した数字は本文より先に古くなり、古い数字は無いより悪い。実サイズは `ls -l prompts/collaboration-workflow/` が答える。
43
37
 
@@ -42,7 +42,7 @@ per the table below, and do not let it silently block an unrelated change).
42
42
  ## Step A / Step B: fetch the hotspots and read each one's disposition
43
43
 
44
44
  ```bash
45
- pnpm josh sonar:hotspots <PR> # alias: josh shs
45
+ pnpm josh sonar:hotspots <PR>
46
46
  ```
47
47
 
48
48
  The command fetches the hotspots on the pull request from SonarCloud's public API (no auth), reading
@@ -12,7 +12,7 @@ const ADOPT_ORIGIN = 'Opened by `josh adopt` in this repository.'
12
12
  const INCOMPLETE_HEADLINE =
13
13
  'Refusing to adopt: these declared toolkits would fall out of the plan, and the run would sync the rest without them.'
14
14
  const INCOMPLETE_EFFECT =
15
- "The toolkits overlay files derived from kit's own (see docs/sync.md), so syncing kit without one rewrites that overlay back to kit's original — a wrong diff wearing kit's face."
15
+ "The toolkits overlay files derived from kit's own (see docs/maintainers/sync-rationale.md), so syncing kit without one rewrites that overlay back to kit's original — a wrong diff wearing kit's face."
16
16
  const MISPLACED_CAUSE =
17
17
  'declared under `dependencies`; the upgrade installs with `pnpm add -D` and would relocate it. Move it to `devDependencies`.'
18
18
  const ABSENT_CAUSE =
@@ -60,7 +60,7 @@ function name_causes(package_names: ReadonlyArray<string>, cause: string): Array
60
60
 
61
61
  // A declared toolkit that falls out of the plan is a refusal rather than a warning
62
62
  // (joshuafolkken/kit#1540). kit distributes the base files and every other toolkit overlays files
63
- // *derived* from them (`docs/sync.md` → two distribution tiers), so a run that syncs kit without the
63
+ // *derived* from them (`docs/maintainers/sync-rationale.md` → "The managed-workflow stamp"), so a run that syncs kit without the
64
64
  // overlay does not merely do less — it writes the overlay's paths back to kit's originals. That diff
65
65
  // then wears kit's own face in the pull request, which is exactly what a reviewer cannot spot.
66
66
  //
@@ -32,7 +32,7 @@ function is_toolkit_package(package_name: string): boolean {
32
32
 
33
33
  // kit is the base tier and every other toolkit distributes files *derived* from kit's, so the two
34
34
  // can manage the same path and whichever `sync` ran last decides its contents
35
- // (`docs/sync.md` → "two distribution tiers"). Ordering is therefore base-first: kit syncs, then the
35
+ // (`docs/maintainers/sync-rationale.md` → "The managed-workflow stamp"). Ordering is therefore base-first: kit syncs, then the
36
36
  // toolkits that overlay it. Sorting by name would put kit last and have it overwrite the overlay
37
37
  // with the original every single run.
38
38
  function toolkit_rank(package_name: string): number {
@@ -171,7 +171,9 @@ const adopt_toolkits = {
171
171
  declared_toolkits,
172
172
  misplaced_toolkits,
173
173
  pick_bin_name,
174
+ bin_name_of,
174
175
  read_bin_name,
176
+ all_declared_toolkits,
175
177
  is_unreachable_toolkit,
176
178
  resolve_toolkit,
177
179
  discover_toolkits,
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env tsx
2
2
  import { fileURLToPath } from 'node:url'
3
3
  import { PROJECT_ROOT } from '#scripts/init/init-paths'
4
- import { refuse_unknown_flags } from '#scripts/lib/cli-flags'
4
+ import { cli_flags } from '#scripts/lib/cli-flags'
5
5
  import { propagate_run, type TargetResult } from '#scripts/propagate/propagate-run'
6
6
  import { propagate_steps, type Release, type ReleasePlan } from '#scripts/propagate/propagate-steps'
7
7
  import type { PropagateTarget } from '#scripts/propagate/propagate-targets'
@@ -40,7 +40,7 @@ interface RunOptions {
40
40
 
41
41
  function parse_options(argv: ReadonlyArray<string>): RunOptions {
42
42
  const options: RunOptions = { is_dry_run: argv.includes(DRY_RUN_FLAG) }
43
- const usage = refuse_unknown_flags(argv, KNOWN_FLAGS, 'adopt')
43
+ const usage = cli_flags.refuse_unknown_flags(argv, KNOWN_FLAGS, 'adopt')
44
44
 
45
45
  return usage === undefined ? options : { ...options, usage }
46
46
  }
@@ -1,3 +1,4 @@
1
+ import { json_value } from '#scripts/lib/json-value'
1
2
  import { z } from 'zod'
2
3
  import type { AgentProvider } from './agent-role-profile'
3
4
  import { claude_result_event } from './claude-result-event'
@@ -53,14 +54,6 @@ const EMPTY_STATE: AgentEventState = {
53
54
  const LAUNCH_HEADER_PREFIX = '=== '
54
55
  const LAUNCH_HEADER_MARKER = ' · started by process '
55
56
 
56
- function parse_line(line: string): unknown {
57
- try {
58
- return JSON.parse(line)
59
- } catch {
60
- return undefined
61
- }
62
- }
63
-
64
57
  function usable_text(value: unknown): string | undefined {
65
58
  return typeof value === 'string' && value.trim() !== '' ? value : undefined
66
59
  }
@@ -149,7 +142,7 @@ function next_state(line: string, state: AgentEventState): AgentEventState {
149
142
  const is_header = line.startsWith(LAUNCH_HEADER_PREFIX) && line.includes(LAUNCH_HEADER_MARKER)
150
143
  if (is_header) return EMPTY_STATE
151
144
 
152
- return normalized(parse_line(line), state)
145
+ return normalized(json_value.parse_or_undefined(line), state)
153
146
  }
154
147
 
155
148
  function read(transcript: string): AgentEventState {
@@ -1,3 +1,4 @@
1
+ import { json_value } from '#scripts/lib/json-value'
1
2
  import { claude_result_event, type ClaudeResultEvent } from './claude-result-event'
2
3
 
3
4
  // The exit record of a dispatched lane child — the terminal `result` event a `claude -p` session
@@ -12,18 +13,10 @@ import { claude_result_event, type ClaudeResultEvent } from './claude-result-eve
12
13
  // over; a transcript with no result event at all reads as `undefined`, which the classifier treats as
13
14
  // an unreadable ending rather than guessing one.
14
15
 
15
- function parse_line(line: string): unknown {
16
- try {
17
- return JSON.parse(line)
18
- } catch {
19
- return undefined
20
- }
21
- }
22
-
23
16
  function read_exit_record(transcript: string): ClaudeResultEvent | undefined {
24
17
  return transcript
25
18
  .split('\n')
26
- .map((line) => claude_result_event.decode(parse_line(line)))
19
+ .map((line) => claude_result_event.decode(json_value.parse_or_undefined(line)))
27
20
  .findLast((record) => record !== undefined)
28
21
  }
29
22
 
@@ -310,9 +310,8 @@ async function fetch_tracking(count: number): Promise<TrackingRead> {
310
310
  }
311
311
  }
312
312
 
313
- // The pickup *order* is `git_next_issues.prioritize` itself, not a copy of it: newest first, with the
314
- // `epic` / `in-progress` / `needs-decision` exclusions. Its display cap does not reach this caller,
315
- // which reads only the first row.
313
+ // The pickup *order* is `git_next_issues.order` itself, not a copy of it: the ranking `prioritize`
314
+ // shows, with the `epic` / `in-progress` / `needs-decision` exclusions, before its display cap.
316
315
  //
317
316
  // The two are no longer the same *set*, and deliberately so: since joshuafolkken/kit#996 the pickup
318
317
  // also drops a candidate whose prerequisite is still open, while `🗒 Next issues` shows every open
@@ -323,9 +322,12 @@ async function fetch_tracking(count: number): Promise<TrackingRead> {
323
322
  // Membership of the label is the *query's* job, not this function's: `--label` is what makes the
324
323
  // listing the opted-in set, so re-testing it here would be a second definition of opting in.
325
324
  //
326
- // The exclusions are applied **before** `prioritize`, not after: it keeps only its first few rows,
327
- // so filtering its output would answer `none` whenever those rows happen to be blocked while a
328
- // runnable issue sits below them.
325
+ // The exclusions are applied to `git_next_issues.order`'s **uncapped** ranking, never to
326
+ // `prioritize`'s capped one, which would answer `none` whenever its first rows happen to be blocked
327
+ // while a runnable issue sits below them. They are applied **after** the ranking, not before it: the
328
+ // dependents key counts the issues waiting on a row, and a waiting issue is by definition blocked —
329
+ // filtered first, every row would count zero and the key would never decide anything
330
+ // (joshuafolkken/kit#2928).
329
331
  //
330
332
  // The `🗒 Next issues` display is deliberately *not* filtered this way; `git-next-issues.ts` records
331
333
  // why, and the short version is that a person can see a blocked issue and choose to start it anyway
@@ -354,9 +356,7 @@ function pick_next(
354
356
  tracked: ReadonlyMap<number, number> = new Map(),
355
357
  exclude: ReadonlyArray<number> = [],
356
358
  ): OpenIssueData | undefined {
357
- const runnable = issues.filter((issue) => is_runnable(issue, tracked, exclude))
358
-
359
- return git_next_issues.prioritize(runnable)[0]
359
+ return git_next_issues.order(issues).find((issue) => is_runnable(issue, tracked, exclude))
360
360
  }
361
361
 
362
362
  // Why there is nothing to run. "No open issue carries the label" and "every opted-in issue is
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env tsx
2
2
  import { fileURLToPath } from 'node:url'
3
- import { parseArgs } from 'node:util'
4
3
  import { path_decision } from '#scripts/josh/path-decision'
4
+ import { cli_flags } from '#scripts/lib/cli-flags'
5
5
  import { backlog_budget, type BacklogAnswer, type BudgetInput } from './backlog-budget'
6
6
 
7
7
  // The thin half of `josh backlog:budget` (joshuafolkken/kit#1632): read the loop's state off the
@@ -32,11 +32,7 @@ type ParsedValues = Partial<Record<OptionName, string | boolean>>
32
32
  // A misspelled flag is refused rather than defaulted, the contract `path_decision.has_unknown_flag`
33
33
  // states for the path-decided commands: an invocation nobody can read is never answered.
34
34
  function read_arguments(argv: ReadonlyArray<string>): ParsedValues | undefined {
35
- try {
36
- return parseArgs({ args: [...argv], options: OPTIONS, strict: true }).values
37
- } catch {
38
- return undefined
39
- }
35
+ return cli_flags.parse_or_undefined({ args: [...argv], options: OPTIONS, strict: true })?.values
40
36
  }
41
37
 
42
38
  function text_of(value: string | boolean | undefined): string | undefined {
@@ -1,13 +1,14 @@
1
1
  #!/usr/bin/env tsx
2
2
  import { setTimeout as sleep } from 'node:timers/promises'
3
3
  import { fileURLToPath } from 'node:url'
4
- import { parseArgs } from 'node:util'
5
4
  import { CONTEXT_CUT_THRESHOLD } from '#scripts/cost-runtime/context-cut-threshold'
6
5
  import { hook_decision } from '#scripts/josh/hook-decision'
7
6
  import { josh_command } from '#scripts/josh/josh-run'
8
7
  import { lane_await, type AwaitState } from '#scripts/lane/lane-await'
9
8
  import { lane_launch_cli } from '#scripts/lane/lane-launch-cli'
10
9
  import { lane_registry } from '#scripts/lane/lane-registry'
10
+ import { cli_flags } from '#scripts/lib/cli-flags'
11
+ import { error_text } from '#scripts/lib/error-message'
11
12
  import { run_carry, type RunCarry } from '#scripts/run/run-carry'
12
13
  import { run_event_stream_emit } from '#scripts/run/run-event-stream-emit'
13
14
  import { run_merge_cli } from '#scripts/run/run-merge-cli'
@@ -49,7 +50,7 @@ const LIST_SEPARATOR = ','
49
50
  const COUNT_PATTERN = /^\d+$/u
50
51
  const ISSUE_PATTERN = /^[1-9]\d*$/u
51
52
  const USAGE =
52
- 'Usage: josh backlog:drive --owner <pid> [--active <ISO-8601>] [--max <n>] [--idle <minutes>] [--only] [--exclude <n>[,<n>...]] [--await <n>[,<n>...]] [--window <minutes>]'
53
+ 'Usage: josh backlog:drive --owner <pid> [--active <ISO-8601>] [--max <n>] [--idle <minutes>] [--only] [--exclude <n>[,<n>...]] [--await <n>[,<n>...]] [--window <minutes>] [--stopped <n>]'
53
54
 
54
55
  const OPTIONS = {
55
56
  active: { type: 'string' },
@@ -59,6 +60,7 @@ const OPTIONS = {
59
60
  max: { type: 'string' },
60
61
  only: { type: 'boolean' },
61
62
  owner: { type: 'string' },
63
+ stopped: { type: 'string' },
62
64
  window: { type: 'string' },
63
65
  } as const
64
66
 
@@ -72,16 +74,14 @@ interface DriveContext {
72
74
  window_ms: number | undefined
73
75
  window: string | undefined
74
76
  is_only: boolean
77
+ // The child whose merge answered `stop` before the hand-back: the resumed run starts already stopping.
78
+ stopped: string | undefined
75
79
  }
76
80
 
77
81
  type Values = Partial<Record<Exclude<keyof typeof OPTIONS, 'only'>, string>> & { only?: boolean }
78
82
 
79
83
  function read_values(argv: ReadonlyArray<string>): Values | undefined {
80
- try {
81
- return parseArgs({ args: [...argv], options: OPTIONS, strict: true }).values
82
- } catch {
83
- return undefined
84
- }
84
+ return cli_flags.parse_or_undefined({ args: [...argv], options: OPTIONS, strict: true })?.values
85
85
  }
86
86
 
87
87
  // A comma list of issue numbers; one entry that is not an issue number refuses the whole list.
@@ -110,6 +110,12 @@ function is_valid_window(raw: string | undefined): boolean {
110
110
  return raw === undefined || COUNT_PATTERN.test(raw)
111
111
  }
112
112
 
113
+ function is_valid_single(values: Values): boolean {
114
+ const is_valid_stopped = values.stopped === undefined || ISSUE_PATTERN.test(values.stopped)
115
+
116
+ return is_valid_stopped && is_valid_window(values.window)
117
+ }
118
+
113
119
  function owner_of(values: Values | undefined): string | undefined {
114
120
  const owner = values?.owner
115
121
 
@@ -117,7 +123,7 @@ function owner_of(values: Values | undefined): string | undefined {
117
123
  }
118
124
 
119
125
  function to_context(values: Values, owner: string): DriveContext | undefined {
120
- if (!is_valid_window(values.window)) return undefined
126
+ if (!is_valid_single(values)) return undefined
121
127
 
122
128
  const forwarded = forwarded_of(values)
123
129
  const exclude = to_issues(values.exclude)
@@ -136,6 +142,7 @@ function to_context(values: Values, owner: string): DriveContext | undefined {
136
142
  window_ms,
137
143
  window: values.window,
138
144
  is_only: values.only === true,
145
+ stopped: values.stopped,
139
146
  }
140
147
  }
141
148
 
@@ -274,6 +281,7 @@ function resume_line(state: DriveState, context: DriveContext): string {
274
281
 
275
282
  if (exclude.length > 0) flags.push('--exclude', exclude.join(LIST_SEPARATOR))
276
283
  if (context.window !== undefined) flags.push('--window', context.window)
284
+ if (state.stopped_by !== undefined) flags.push('--stopped', state.stopped_by)
277
285
 
278
286
  return `resume: ${flags.join(' ')}`
279
287
  }
@@ -325,7 +333,9 @@ async function drive(context: DriveContext): Promise<number> {
325
333
  const seeded = await seeded_lanes(context)
326
334
 
327
335
  if (seeded === undefined) return FAILURE_EXIT_CODE
328
- const initial = backlog_drive.initial_state(seeded, context.active ?? new Date().toISOString())
336
+ const fresh = backlog_drive.initial_state(seeded, context.active ?? new Date().toISOString())
337
+ const initial =
338
+ context.stopped === undefined ? fresh : backlog_drive.merge_stopped(context.stopped, fresh)
329
339
  const last = { state: { ...initial, exclude: [...context.exclude] } }
330
340
  const config = { poll_ms: POLL_MS, offer_ms: OFFER_MS, window_ms: context.window_ms }
331
341
  const end = await backlog_drive.run_loop(last.state, config, ports_of(context, seeded, last))
@@ -340,7 +350,7 @@ async function run_safe(context: DriveContext): Promise<number> {
340
350
  try {
341
351
  return await drive(context)
342
352
  } catch (error) {
343
- console.info(`error ${error instanceof Error ? error.message : String(error)}`)
353
+ console.info(`error ${error_text.message_of(error)}`)
344
354
 
345
355
  return FAILURE_EXIT_CODE
346
356
  }
@@ -16,19 +16,22 @@
16
16
  // **Everything it touches is a port**, the pattern `run-wake-loop.ts` set, so the sequencing is pinned
17
17
  // without a process, a network or a clock.
18
18
 
19
- // The `run:merge` tokens that need the parent: a hand-off, a person's stop, a tripped guard, a foreign
20
- // owner, an unreadable state. `resumed` is not among them — the same lane is awaited again.
21
- const HANDOFF_TOKENS: ReadonlySet<string> = new Set([
19
+ const RUN_VERDICT = 'run'
20
+ const STOP_VERDICT = 'stop'
21
+ // The `run:merge` tokens that end the loop at once: a hand-off, a person's stop, the environment down,
22
+ // a foreign owner, an unreadable state. `resumed` is not among them — the same lane is awaited again.
23
+ const IMMEDIATE_TOKENS: ReadonlySet<string> = new Set([
22
24
  'over',
23
25
  'human-review',
24
- 'stop',
25
26
  'environment',
26
27
  'busy',
27
28
  'retry',
28
29
  ])
30
+ // Every token `run:merge` prints first even on a non-zero exit. `stop` — a parked backlog or the failure
31
+ // guard — is the offer's `stop` reached through a merge: the child is collected, nothing more starts,
32
+ // and the children still in flight are collected before the loop ends (joshuafolkken/kit#2881).
33
+ const HANDOFF_TOKENS: ReadonlySet<string> = new Set([...IMMEDIATE_TOKENS, STOP_VERDICT])
29
34
  const RESUMED_TOKEN = 'resumed'
30
- const RUN_VERDICT = 'run'
31
- const STOP_VERDICT = 'stop'
32
35
  const WATCH_VERDICT = 'watch'
33
36
  // The verdicts the loop acts on without the parent. Any other is handed back as it was printed.
34
37
  const KNOWN_VERDICTS: ReadonlySet<string> = new Set([
@@ -63,6 +66,8 @@ interface DriveState {
63
66
  is_stopping: boolean
64
67
  stop_reason?: string | undefined
65
68
  stop_is_finish?: boolean | undefined
69
+ // The child whose merge answered `stop`, carried on the resume line: no offer re-derives that stop.
70
+ stopped_by?: string | undefined
66
71
  }
67
72
 
68
73
  interface DriveEnd {
@@ -133,22 +138,43 @@ function initial_state(in_flight: ReadonlyArray<string>, active: string): DriveS
133
138
  }
134
139
  }
135
140
 
136
- // One finished child: collected, excluded, and — unless its cut was resumed in place — out of flight.
141
+ // The stop a merge reached: kept as the first stop's reason when an offer already stopped the run.
142
+ function merge_stopped(issue: string, state: DriveState): DriveState {
143
+ if (state.is_stopping) return state
144
+
145
+ return {
146
+ ...state,
147
+ is_stopping: true,
148
+ stop_reason: `run:merge #${issue} answered stop`,
149
+ stopped_by: issue,
150
+ }
151
+ }
152
+
153
+ // The child collected and excluded, and — unless its cut was resumed in place — out of flight.
154
+ function collected_state(
155
+ issue: string,
156
+ token: string,
157
+ state: DriveState,
158
+ active: string,
159
+ ): DriveState {
160
+ const in_flight =
161
+ token === RESUMED_TOKEN ? state.in_flight : state.in_flight.filter((item) => item !== issue)
162
+ const exclude = state.exclude.includes(issue) ? state.exclude : [...state.exclude, issue]
163
+
164
+ return { ...state, in_flight, exclude, active }
165
+ }
166
+
167
+ // One finished child: handed back on an immediate token, otherwise collected.
137
168
  async function collect(issue: string, state: DriveState, ports: DrivePorts): Promise<PassResult> {
138
169
  const token = await ports.merge(issue)
139
170
 
140
171
  // An empty first line is a `run:merge` that failed before printing one: never read as a collection.
141
172
  if (token === '') return ended('merge', state, undefined, issue)
142
- if (HANDOFF_TOKENS.has(token)) return ended('merge', state, token, issue)
173
+ if (IMMEDIATE_TOKENS.has(token)) return ended('merge', state, token, issue)
143
174
 
144
- const in_flight =
145
- token === RESUMED_TOKEN ? state.in_flight : state.in_flight.filter((item) => item !== issue)
146
- const exclude = state.exclude.includes(issue) ? state.exclude : [...state.exclude, issue]
175
+ const next = collected_state(issue, token, state, ports.now().toISOString())
147
176
 
148
- return {
149
- kind: 'continue',
150
- state: { ...state, in_flight, exclude, active: ports.now().toISOString() },
151
- }
177
+ return { kind: 'continue', state: token === STOP_VERDICT ? merge_stopped(issue, next) : next }
152
178
  }
153
179
 
154
180
  async function collect_finished(state: DriveState, ports: DrivePorts): Promise<PassResult> {
@@ -320,7 +346,15 @@ async function run_loop(
320
346
  return step.end
321
347
  }
322
348
 
323
- const backlog_drive = { HANDOFF_TOKENS, collect, initial_state, on_verdict, run_loop, run_pass }
349
+ const backlog_drive = {
350
+ HANDOFF_TOKENS,
351
+ collect,
352
+ initial_state,
353
+ merge_stopped,
354
+ on_verdict,
355
+ run_loop,
356
+ run_pass,
357
+ }
324
358
 
325
359
  export type { DriveEnd, DrivePorts, DriveState, LoopConfig, LoopPorts, OfferRead, PassResult }
326
360
  export { backlog_drive }