intent-planner 0.13.1

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 (334) hide show
  1. package/LICENSE +21 -0
  2. package/README.en.md +225 -0
  3. package/README.md +225 -0
  4. package/bin/cli.mjs +289 -0
  5. package/package.json +46 -0
  6. package/src/install.mjs +527 -0
  7. package/templates/en/agents/claude/CLAUDE.md +62 -0
  8. package/templates/en/agents/codex/AGENTS.md +62 -0
  9. package/templates/en/agents/gemini/GEMINI.md +62 -0
  10. package/templates/en/claude/skills/CONTRACT.md +86 -0
  11. package/templates/en/claude/skills/intent-compass/SKILL.md +55 -0
  12. package/templates/en/claude/skills/intent-compass/rules/algo-qoc.md +62 -0
  13. package/templates/en/claude/skills/intent-compass/rules/constraint-surfacing.md +41 -0
  14. package/templates/en/claude/skills/intent-discover/SKILL.md +63 -0
  15. package/templates/en/claude/skills/intent-discover/rules/algo-drift-analysis.md +34 -0
  16. package/templates/en/claude/skills/intent-discover/rules/algo-gore-lite.md +35 -0
  17. package/templates/en/claude/skills/intent-discover/rules/algo-impact-analysis.md +37 -0
  18. package/templates/en/claude/skills/intent-discover/rules/algo-intent-recovery.md +39 -0
  19. package/templates/en/claude/skills/intent-discover/rules/designer-questions.md +78 -0
  20. package/templates/en/claude/skills/intent-discover/rules/drift-terrain.md +105 -0
  21. package/templates/en/claude/skills/intent-discover/rules/mode-selection.md +31 -0
  22. package/templates/en/claude/skills/intent-export-cc-sdd/SKILL.md +88 -0
  23. package/templates/en/claude/skills/intent-export-cc-sdd/rules/drift-export-check.md +75 -0
  24. package/templates/en/claude/skills/intent-export-cc-sdd/rules/export-questions.md +23 -0
  25. package/templates/en/claude/skills/intent-export-cc-sdd/rules/map-cc-sdd.md +62 -0
  26. package/templates/en/claude/skills/intent-export-openspec/SKILL.md +90 -0
  27. package/templates/en/claude/skills/intent-export-openspec/rules/drift-export-check.md +50 -0
  28. package/templates/en/claude/skills/intent-export-openspec/rules/export-questions.md +23 -0
  29. package/templates/en/claude/skills/intent-export-openspec/rules/map-openspec.md +75 -0
  30. package/templates/en/claude/skills/intent-from-spec/SKILL.md +60 -0
  31. package/templates/en/claude/skills/intent-from-spec/rules/extract-intent.md +56 -0
  32. package/templates/en/claude/skills/intent-from-spec/rules/gap-readout.md +54 -0
  33. package/templates/en/claude/skills/intent-from-spec/rules/load-bearing.md +48 -0
  34. package/templates/en/claude/skills/intent-from-spec/rules/omission-recap.md +42 -0
  35. package/templates/en/claude/skills/intent-improve/SKILL.md +70 -0
  36. package/templates/en/claude/skills/intent-improve/rules/improve-axes.md +121 -0
  37. package/templates/en/claude/skills/intent-overview/SKILL.md +63 -0
  38. package/templates/en/claude/skills/intent-overview/rules/aggregate-sources.md +61 -0
  39. package/templates/en/claude/skills/intent-overview/rules/gap-readout.md +54 -0
  40. package/templates/en/claude/skills/intent-overview/rules/mermaid-tree.md +78 -0
  41. package/templates/en/claude/skills/intent-overview/rules/progress-readout.md +119 -0
  42. package/templates/en/claude/skills/intent-packets/SKILL.md +97 -0
  43. package/templates/en/claude/skills/intent-packets/rules/algo-additive-slicing.md +55 -0
  44. package/templates/en/claude/skills/intent-packets/rules/algo-characterization-test.md +40 -0
  45. package/templates/en/claude/skills/intent-packets/rules/algo-example-mapping.md +47 -0
  46. package/templates/en/claude/skills/intent-packets/rules/algo-migration-slicing.md +47 -0
  47. package/templates/en/claude/skills/intent-packets/rules/decision-slots.md +88 -0
  48. package/templates/en/claude/skills/intent-packets/rules/export-route.md +54 -0
  49. package/templates/en/claude/skills/intent-packets/rules/first-packet.md +35 -0
  50. package/templates/en/claude/skills/intent-packets/rules/packet-format.md +207 -0
  51. package/templates/en/claude/skills/intent-packets/rules/walking-skeleton.md +35 -0
  52. package/templates/en/claude/skills/intent-release-note/SKILL.md +58 -0
  53. package/templates/en/claude/skills/intent-release-note/rules/format-changelog.md +40 -0
  54. package/templates/en/claude/skills/intent-release-note/rules/format-github-releases.md +41 -0
  55. package/templates/en/claude/skills/intent-release-note/rules/format-select.md +32 -0
  56. package/templates/en/claude/skills/intent-release-note/rules/source-scope.md +42 -0
  57. package/templates/en/claude/skills/intent-status/SKILL.md +171 -0
  58. package/templates/en/claude/skills/intent-status/rules/decision-table.md +47 -0
  59. package/templates/en/claude/skills/intent-to-spec/SKILL.md +68 -0
  60. package/templates/en/claude/skills/intent-to-spec/rules/fabrication-guard.md +41 -0
  61. package/templates/en/claude/skills/intent-to-spec/rules/format-integrated.md +42 -0
  62. package/templates/en/claude/skills/intent-to-spec/rules/format-nonprogram.md +45 -0
  63. package/templates/en/claude/skills/intent-to-spec/rules/format-upstream.md +41 -0
  64. package/templates/en/claude/skills/intent-to-spec/rules/source-scope.md +50 -0
  65. package/templates/en/claude/skills/intent-validate/SKILL.md +80 -0
  66. package/templates/en/claude/skills/intent-validate/rules/validate-checks.md +121 -0
  67. package/templates/en/claude/skills/intent-writeback/SKILL.md +71 -0
  68. package/templates/en/claude/skills/intent-writeback/rules/writeback-protocol.md +139 -0
  69. package/templates/en/codex/skills/CONTRACT.md +77 -0
  70. package/templates/en/codex/skills/intent-compass/SKILL.md +52 -0
  71. package/templates/en/codex/skills/intent-compass/rules/algo-qoc.md +62 -0
  72. package/templates/en/codex/skills/intent-compass/rules/constraint-surfacing.md +41 -0
  73. package/templates/en/codex/skills/intent-discover/SKILL.md +60 -0
  74. package/templates/en/codex/skills/intent-discover/rules/algo-drift-analysis.md +34 -0
  75. package/templates/en/codex/skills/intent-discover/rules/algo-gore-lite.md +35 -0
  76. package/templates/en/codex/skills/intent-discover/rules/algo-impact-analysis.md +37 -0
  77. package/templates/en/codex/skills/intent-discover/rules/algo-intent-recovery.md +39 -0
  78. package/templates/en/codex/skills/intent-discover/rules/designer-questions.md +78 -0
  79. package/templates/en/codex/skills/intent-discover/rules/drift-terrain.md +105 -0
  80. package/templates/en/codex/skills/intent-discover/rules/mode-selection.md +31 -0
  81. package/templates/en/codex/skills/intent-export-cc-sdd/SKILL.md +85 -0
  82. package/templates/en/codex/skills/intent-export-cc-sdd/rules/drift-export-check.md +75 -0
  83. package/templates/en/codex/skills/intent-export-cc-sdd/rules/export-questions.md +23 -0
  84. package/templates/en/codex/skills/intent-export-cc-sdd/rules/map-cc-sdd.md +62 -0
  85. package/templates/en/codex/skills/intent-export-openspec/SKILL.md +87 -0
  86. package/templates/en/codex/skills/intent-export-openspec/rules/drift-export-check.md +50 -0
  87. package/templates/en/codex/skills/intent-export-openspec/rules/export-questions.md +23 -0
  88. package/templates/en/codex/skills/intent-export-openspec/rules/map-openspec.md +75 -0
  89. package/templates/en/codex/skills/intent-from-spec/SKILL.md +58 -0
  90. package/templates/en/codex/skills/intent-from-spec/rules/extract-intent.md +56 -0
  91. package/templates/en/codex/skills/intent-from-spec/rules/gap-readout.md +54 -0
  92. package/templates/en/codex/skills/intent-from-spec/rules/load-bearing.md +48 -0
  93. package/templates/en/codex/skills/intent-from-spec/rules/omission-recap.md +42 -0
  94. package/templates/en/codex/skills/intent-improve/SKILL.md +67 -0
  95. package/templates/en/codex/skills/intent-improve/rules/improve-axes.md +121 -0
  96. package/templates/en/codex/skills/intent-overview/SKILL.md +61 -0
  97. package/templates/en/codex/skills/intent-overview/rules/aggregate-sources.md +61 -0
  98. package/templates/en/codex/skills/intent-overview/rules/gap-readout.md +54 -0
  99. package/templates/en/codex/skills/intent-overview/rules/mermaid-tree.md +78 -0
  100. package/templates/en/codex/skills/intent-overview/rules/progress-readout.md +119 -0
  101. package/templates/en/codex/skills/intent-packets/SKILL.md +94 -0
  102. package/templates/en/codex/skills/intent-packets/rules/algo-additive-slicing.md +55 -0
  103. package/templates/en/codex/skills/intent-packets/rules/algo-characterization-test.md +40 -0
  104. package/templates/en/codex/skills/intent-packets/rules/algo-example-mapping.md +47 -0
  105. package/templates/en/codex/skills/intent-packets/rules/algo-migration-slicing.md +47 -0
  106. package/templates/en/codex/skills/intent-packets/rules/decision-slots.md +88 -0
  107. package/templates/en/codex/skills/intent-packets/rules/export-route.md +54 -0
  108. package/templates/en/codex/skills/intent-packets/rules/first-packet.md +35 -0
  109. package/templates/en/codex/skills/intent-packets/rules/packet-format.md +207 -0
  110. package/templates/en/codex/skills/intent-packets/rules/walking-skeleton.md +35 -0
  111. package/templates/en/codex/skills/intent-release-note/SKILL.md +56 -0
  112. package/templates/en/codex/skills/intent-release-note/rules/format-changelog.md +40 -0
  113. package/templates/en/codex/skills/intent-release-note/rules/format-github-releases.md +41 -0
  114. package/templates/en/codex/skills/intent-release-note/rules/format-select.md +32 -0
  115. package/templates/en/codex/skills/intent-release-note/rules/source-scope.md +42 -0
  116. package/templates/en/codex/skills/intent-status/SKILL.md +169 -0
  117. package/templates/en/codex/skills/intent-status/rules/decision-table.md +47 -0
  118. package/templates/en/codex/skills/intent-to-spec/SKILL.md +66 -0
  119. package/templates/en/codex/skills/intent-to-spec/rules/fabrication-guard.md +41 -0
  120. package/templates/en/codex/skills/intent-to-spec/rules/format-integrated.md +42 -0
  121. package/templates/en/codex/skills/intent-to-spec/rules/format-nonprogram.md +45 -0
  122. package/templates/en/codex/skills/intent-to-spec/rules/format-upstream.md +41 -0
  123. package/templates/en/codex/skills/intent-to-spec/rules/source-scope.md +50 -0
  124. package/templates/en/codex/skills/intent-validate/SKILL.md +78 -0
  125. package/templates/en/codex/skills/intent-validate/rules/validate-checks.md +121 -0
  126. package/templates/en/codex/skills/intent-writeback/SKILL.md +68 -0
  127. package/templates/en/codex/skills/intent-writeback/rules/writeback-protocol.md +139 -0
  128. package/templates/en/intent/README.md +118 -0
  129. package/templates/en/intent/cc-sdd/README.md +28 -0
  130. package/templates/en/intent/compass-archive/README.md +9 -0
  131. package/templates/en/intent/compass-archive/archive/.gitkeep +0 -0
  132. package/templates/en/intent/compass-archive.md +7 -0
  133. package/templates/en/intent/constraint-library.md +32 -0
  134. package/templates/en/intent/constraint-starters.md +58 -0
  135. package/templates/en/intent/context-cost-cues.md +55 -0
  136. package/templates/en/intent/deltas/README.md +11 -0
  137. package/templates/en/intent/deltas/archive/.gitkeep +0 -0
  138. package/templates/en/intent/deltas.md +34 -0
  139. package/templates/en/intent/drift-log/README.md +11 -0
  140. package/templates/en/intent/drift-log/archive/.gitkeep +0 -0
  141. package/templates/en/intent/drift-log.md +41 -0
  142. package/templates/en/intent/drift-patterns.md +68 -0
  143. package/templates/en/intent/export-log/README.md +12 -0
  144. package/templates/en/intent/export-log/archive/.gitkeep +0 -0
  145. package/templates/en/intent/export-log.md +6 -0
  146. package/templates/en/intent/glossary.md +23 -0
  147. package/templates/en/intent/intent-compass.md +55 -0
  148. package/templates/en/intent/intent-tree.md +59 -0
  149. package/templates/en/intent/milestones/README.md +10 -0
  150. package/templates/en/intent/milestones/archive/.gitkeep +0 -0
  151. package/templates/en/intent/milestones.md +22 -0
  152. package/templates/en/intent/mode.local.md +23 -0
  153. package/templates/en/intent/mode.md +32 -0
  154. package/templates/en/intent/modes/README.md +28 -0
  155. package/templates/en/intent/modes/behavior-unknown.md +57 -0
  156. package/templates/en/intent/modes/feature-growth.md +57 -0
  157. package/templates/en/intent/modes/non-code.md +46 -0
  158. package/templates/en/intent/modes/refactor.md +56 -0
  159. package/templates/en/intent/modes/standard.md +50 -0
  160. package/templates/en/intent/nl-spec/README.md +18 -0
  161. package/templates/en/intent/openspec/proposal.md +15 -0
  162. package/templates/en/intent/openspec/spec-delta.md +25 -0
  163. package/templates/en/intent/overview/README.md +18 -0
  164. package/templates/en/intent/packets/README.md +29 -0
  165. package/templates/en/intent/packets/index.md +6 -0
  166. package/templates/en/intent/packets/plan.md +23 -0
  167. package/templates/en/intent/release-note/README.md +18 -0
  168. package/templates/en/intent/scripts/intent-check.mjs +786 -0
  169. package/templates/en/intent/scripts/pre-push +27 -0
  170. package/templates/en/intent/spec-ingest/README.md +18 -0
  171. package/templates/ja/agents/claude/CLAUDE.md +62 -0
  172. package/templates/ja/agents/codex/AGENTS.md +62 -0
  173. package/templates/ja/agents/gemini/GEMINI.md +62 -0
  174. package/templates/ja/claude/skills/CONTRACT.md +90 -0
  175. package/templates/ja/claude/skills/intent-compass/SKILL.md +55 -0
  176. package/templates/ja/claude/skills/intent-compass/rules/algo-qoc.md +62 -0
  177. package/templates/ja/claude/skills/intent-compass/rules/constraint-surfacing.md +41 -0
  178. package/templates/ja/claude/skills/intent-discover/SKILL.md +63 -0
  179. package/templates/ja/claude/skills/intent-discover/rules/algo-drift-analysis.md +34 -0
  180. package/templates/ja/claude/skills/intent-discover/rules/algo-gore-lite.md +35 -0
  181. package/templates/ja/claude/skills/intent-discover/rules/algo-impact-analysis.md +37 -0
  182. package/templates/ja/claude/skills/intent-discover/rules/algo-intent-recovery.md +39 -0
  183. package/templates/ja/claude/skills/intent-discover/rules/designer-questions.md +78 -0
  184. package/templates/ja/claude/skills/intent-discover/rules/drift-terrain.md +105 -0
  185. package/templates/ja/claude/skills/intent-discover/rules/mode-selection.md +31 -0
  186. package/templates/ja/claude/skills/intent-export-cc-sdd/SKILL.md +88 -0
  187. package/templates/ja/claude/skills/intent-export-cc-sdd/rules/drift-export-check.md +75 -0
  188. package/templates/ja/claude/skills/intent-export-cc-sdd/rules/export-questions.md +23 -0
  189. package/templates/ja/claude/skills/intent-export-cc-sdd/rules/map-cc-sdd.md +62 -0
  190. package/templates/ja/claude/skills/intent-export-openspec/SKILL.md +90 -0
  191. package/templates/ja/claude/skills/intent-export-openspec/rules/drift-export-check.md +50 -0
  192. package/templates/ja/claude/skills/intent-export-openspec/rules/export-questions.md +23 -0
  193. package/templates/ja/claude/skills/intent-export-openspec/rules/map-openspec.md +75 -0
  194. package/templates/ja/claude/skills/intent-from-spec/SKILL.md +60 -0
  195. package/templates/ja/claude/skills/intent-from-spec/rules/extract-intent.md +56 -0
  196. package/templates/ja/claude/skills/intent-from-spec/rules/gap-readout.md +54 -0
  197. package/templates/ja/claude/skills/intent-from-spec/rules/load-bearing.md +48 -0
  198. package/templates/ja/claude/skills/intent-from-spec/rules/omission-recap.md +42 -0
  199. package/templates/ja/claude/skills/intent-improve/SKILL.md +70 -0
  200. package/templates/ja/claude/skills/intent-improve/rules/improve-axes.md +121 -0
  201. package/templates/ja/claude/skills/intent-overview/SKILL.md +63 -0
  202. package/templates/ja/claude/skills/intent-overview/rules/aggregate-sources.md +61 -0
  203. package/templates/ja/claude/skills/intent-overview/rules/gap-readout.md +54 -0
  204. package/templates/ja/claude/skills/intent-overview/rules/mermaid-tree.md +78 -0
  205. package/templates/ja/claude/skills/intent-overview/rules/progress-readout.md +119 -0
  206. package/templates/ja/claude/skills/intent-packets/SKILL.md +97 -0
  207. package/templates/ja/claude/skills/intent-packets/rules/algo-additive-slicing.md +55 -0
  208. package/templates/ja/claude/skills/intent-packets/rules/algo-characterization-test.md +40 -0
  209. package/templates/ja/claude/skills/intent-packets/rules/algo-example-mapping.md +47 -0
  210. package/templates/ja/claude/skills/intent-packets/rules/algo-migration-slicing.md +47 -0
  211. package/templates/ja/claude/skills/intent-packets/rules/decision-slots.md +88 -0
  212. package/templates/ja/claude/skills/intent-packets/rules/export-route.md +54 -0
  213. package/templates/ja/claude/skills/intent-packets/rules/first-packet.md +35 -0
  214. package/templates/ja/claude/skills/intent-packets/rules/packet-format.md +207 -0
  215. package/templates/ja/claude/skills/intent-packets/rules/walking-skeleton.md +35 -0
  216. package/templates/ja/claude/skills/intent-release-note/SKILL.md +58 -0
  217. package/templates/ja/claude/skills/intent-release-note/rules/format-changelog.md +40 -0
  218. package/templates/ja/claude/skills/intent-release-note/rules/format-github-releases.md +41 -0
  219. package/templates/ja/claude/skills/intent-release-note/rules/format-select.md +32 -0
  220. package/templates/ja/claude/skills/intent-release-note/rules/source-scope.md +42 -0
  221. package/templates/ja/claude/skills/intent-status/SKILL.md +171 -0
  222. package/templates/ja/claude/skills/intent-status/rules/decision-table.md +47 -0
  223. package/templates/ja/claude/skills/intent-to-spec/SKILL.md +68 -0
  224. package/templates/ja/claude/skills/intent-to-spec/rules/fabrication-guard.md +41 -0
  225. package/templates/ja/claude/skills/intent-to-spec/rules/format-integrated.md +42 -0
  226. package/templates/ja/claude/skills/intent-to-spec/rules/format-nonprogram.md +45 -0
  227. package/templates/ja/claude/skills/intent-to-spec/rules/format-upstream.md +41 -0
  228. package/templates/ja/claude/skills/intent-to-spec/rules/source-scope.md +50 -0
  229. package/templates/ja/claude/skills/intent-validate/SKILL.md +80 -0
  230. package/templates/ja/claude/skills/intent-validate/rules/validate-checks.md +121 -0
  231. package/templates/ja/claude/skills/intent-writeback/SKILL.md +71 -0
  232. package/templates/ja/claude/skills/intent-writeback/rules/writeback-protocol.md +139 -0
  233. package/templates/ja/codex/skills/CONTRACT.md +81 -0
  234. package/templates/ja/codex/skills/intent-compass/SKILL.md +52 -0
  235. package/templates/ja/codex/skills/intent-compass/rules/algo-qoc.md +62 -0
  236. package/templates/ja/codex/skills/intent-compass/rules/constraint-surfacing.md +41 -0
  237. package/templates/ja/codex/skills/intent-discover/SKILL.md +60 -0
  238. package/templates/ja/codex/skills/intent-discover/rules/algo-drift-analysis.md +34 -0
  239. package/templates/ja/codex/skills/intent-discover/rules/algo-gore-lite.md +35 -0
  240. package/templates/ja/codex/skills/intent-discover/rules/algo-impact-analysis.md +37 -0
  241. package/templates/ja/codex/skills/intent-discover/rules/algo-intent-recovery.md +39 -0
  242. package/templates/ja/codex/skills/intent-discover/rules/designer-questions.md +78 -0
  243. package/templates/ja/codex/skills/intent-discover/rules/drift-terrain.md +105 -0
  244. package/templates/ja/codex/skills/intent-discover/rules/mode-selection.md +31 -0
  245. package/templates/ja/codex/skills/intent-export-cc-sdd/SKILL.md +85 -0
  246. package/templates/ja/codex/skills/intent-export-cc-sdd/rules/drift-export-check.md +75 -0
  247. package/templates/ja/codex/skills/intent-export-cc-sdd/rules/export-questions.md +23 -0
  248. package/templates/ja/codex/skills/intent-export-cc-sdd/rules/map-cc-sdd.md +62 -0
  249. package/templates/ja/codex/skills/intent-export-openspec/SKILL.md +87 -0
  250. package/templates/ja/codex/skills/intent-export-openspec/rules/drift-export-check.md +50 -0
  251. package/templates/ja/codex/skills/intent-export-openspec/rules/export-questions.md +23 -0
  252. package/templates/ja/codex/skills/intent-export-openspec/rules/map-openspec.md +75 -0
  253. package/templates/ja/codex/skills/intent-from-spec/SKILL.md +58 -0
  254. package/templates/ja/codex/skills/intent-from-spec/rules/extract-intent.md +56 -0
  255. package/templates/ja/codex/skills/intent-from-spec/rules/gap-readout.md +54 -0
  256. package/templates/ja/codex/skills/intent-from-spec/rules/load-bearing.md +48 -0
  257. package/templates/ja/codex/skills/intent-from-spec/rules/omission-recap.md +42 -0
  258. package/templates/ja/codex/skills/intent-improve/SKILL.md +67 -0
  259. package/templates/ja/codex/skills/intent-improve/rules/improve-axes.md +121 -0
  260. package/templates/ja/codex/skills/intent-overview/SKILL.md +61 -0
  261. package/templates/ja/codex/skills/intent-overview/rules/aggregate-sources.md +61 -0
  262. package/templates/ja/codex/skills/intent-overview/rules/gap-readout.md +54 -0
  263. package/templates/ja/codex/skills/intent-overview/rules/mermaid-tree.md +78 -0
  264. package/templates/ja/codex/skills/intent-overview/rules/progress-readout.md +119 -0
  265. package/templates/ja/codex/skills/intent-packets/SKILL.md +94 -0
  266. package/templates/ja/codex/skills/intent-packets/rules/algo-additive-slicing.md +55 -0
  267. package/templates/ja/codex/skills/intent-packets/rules/algo-characterization-test.md +40 -0
  268. package/templates/ja/codex/skills/intent-packets/rules/algo-example-mapping.md +47 -0
  269. package/templates/ja/codex/skills/intent-packets/rules/algo-migration-slicing.md +47 -0
  270. package/templates/ja/codex/skills/intent-packets/rules/decision-slots.md +88 -0
  271. package/templates/ja/codex/skills/intent-packets/rules/export-route.md +54 -0
  272. package/templates/ja/codex/skills/intent-packets/rules/first-packet.md +35 -0
  273. package/templates/ja/codex/skills/intent-packets/rules/packet-format.md +207 -0
  274. package/templates/ja/codex/skills/intent-packets/rules/walking-skeleton.md +35 -0
  275. package/templates/ja/codex/skills/intent-release-note/SKILL.md +56 -0
  276. package/templates/ja/codex/skills/intent-release-note/rules/format-changelog.md +40 -0
  277. package/templates/ja/codex/skills/intent-release-note/rules/format-github-releases.md +41 -0
  278. package/templates/ja/codex/skills/intent-release-note/rules/format-select.md +32 -0
  279. package/templates/ja/codex/skills/intent-release-note/rules/source-scope.md +42 -0
  280. package/templates/ja/codex/skills/intent-status/SKILL.md +169 -0
  281. package/templates/ja/codex/skills/intent-status/rules/decision-table.md +47 -0
  282. package/templates/ja/codex/skills/intent-to-spec/SKILL.md +66 -0
  283. package/templates/ja/codex/skills/intent-to-spec/rules/fabrication-guard.md +41 -0
  284. package/templates/ja/codex/skills/intent-to-spec/rules/format-integrated.md +42 -0
  285. package/templates/ja/codex/skills/intent-to-spec/rules/format-nonprogram.md +45 -0
  286. package/templates/ja/codex/skills/intent-to-spec/rules/format-upstream.md +41 -0
  287. package/templates/ja/codex/skills/intent-to-spec/rules/source-scope.md +50 -0
  288. package/templates/ja/codex/skills/intent-validate/SKILL.md +78 -0
  289. package/templates/ja/codex/skills/intent-validate/rules/validate-checks.md +121 -0
  290. package/templates/ja/codex/skills/intent-writeback/SKILL.md +68 -0
  291. package/templates/ja/codex/skills/intent-writeback/rules/writeback-protocol.md +139 -0
  292. package/templates/ja/intent/README.md +118 -0
  293. package/templates/ja/intent/cc-sdd/README.md +28 -0
  294. package/templates/ja/intent/compass-archive/README.md +9 -0
  295. package/templates/ja/intent/compass-archive/archive/.gitkeep +0 -0
  296. package/templates/ja/intent/compass-archive.md +7 -0
  297. package/templates/ja/intent/constraint-library.md +32 -0
  298. package/templates/ja/intent/constraint-starters.md +58 -0
  299. package/templates/ja/intent/context-cost-cues.md +55 -0
  300. package/templates/ja/intent/deltas/README.md +11 -0
  301. package/templates/ja/intent/deltas/archive/.gitkeep +0 -0
  302. package/templates/ja/intent/deltas.md +34 -0
  303. package/templates/ja/intent/drift-log/README.md +11 -0
  304. package/templates/ja/intent/drift-log/archive/.gitkeep +0 -0
  305. package/templates/ja/intent/drift-log.md +41 -0
  306. package/templates/ja/intent/drift-patterns.md +68 -0
  307. package/templates/ja/intent/export-log/README.md +12 -0
  308. package/templates/ja/intent/export-log/archive/.gitkeep +0 -0
  309. package/templates/ja/intent/export-log.md +6 -0
  310. package/templates/ja/intent/glossary.md +23 -0
  311. package/templates/ja/intent/intent-compass.md +55 -0
  312. package/templates/ja/intent/intent-tree.md +59 -0
  313. package/templates/ja/intent/milestones/README.md +10 -0
  314. package/templates/ja/intent/milestones/archive/.gitkeep +0 -0
  315. package/templates/ja/intent/milestones.md +22 -0
  316. package/templates/ja/intent/mode.local.md +23 -0
  317. package/templates/ja/intent/mode.md +32 -0
  318. package/templates/ja/intent/modes/README.md +28 -0
  319. package/templates/ja/intent/modes/behavior-unknown.md +57 -0
  320. package/templates/ja/intent/modes/feature-growth.md +57 -0
  321. package/templates/ja/intent/modes/non-code.md +46 -0
  322. package/templates/ja/intent/modes/refactor.md +56 -0
  323. package/templates/ja/intent/modes/standard.md +50 -0
  324. package/templates/ja/intent/nl-spec/README.md +18 -0
  325. package/templates/ja/intent/openspec/proposal.md +15 -0
  326. package/templates/ja/intent/openspec/spec-delta.md +25 -0
  327. package/templates/ja/intent/overview/README.md +18 -0
  328. package/templates/ja/intent/packets/README.md +29 -0
  329. package/templates/ja/intent/packets/index.md +6 -0
  330. package/templates/ja/intent/packets/plan.md +23 -0
  331. package/templates/ja/intent/release-note/README.md +18 -0
  332. package/templates/ja/intent/scripts/intent-check.mjs +786 -0
  333. package/templates/ja/intent/scripts/pre-push +27 -0
  334. package/templates/ja/intent/spec-ingest/README.md +18 -0
@@ -0,0 +1,786 @@
1
+ #!/usr/bin/env node
2
+ // intent-check — writeback enforcement の判定スクリプト
3
+ //
4
+ // 使い方: node .intent/scripts/intent-check.mjs(引数なし。cwd = プロジェクトルート)
5
+ // stdout 1行目(機械可読の判定行・キー順固定):
6
+ // intent-check: result=<ok|stale|not-applicable> enforcement=<off|remind|gate>
7
+ // commits=<N|-> threshold=<M> grace=<in-implementation|-> pending=<K> block=<yes|no>
8
+ // 2行目以降は人間可読の根拠(基準点・grace 判定根拠・欠落 packet・pending packet 名・案内)。
9
+ // 終了コード: 0 = 通過(ok / not-applicable / off / remind の警告含む)
10
+ // 1 = ブロック(enforcement=gate かつ (stale または pending>0) のときのみ)
11
+ // 2 = 内部エラー(想定外例外。stderr に原因。呼び出し側は通過扱い = fail-open)
12
+ //
13
+ // 動作要件: Node.js >= 18.17。node: プレフィックスの標準モジュールのみを使う
14
+ // 単一ファイル実装(外部依存なし)。templates/ja と templates/en に同一バイトで
15
+ // 配布される言語非依存の共通実装(このため出力メッセージは英語に固定する)。
16
+ //
17
+ // 設計上の約束:
18
+ // - 状態ファイルを持たない。入力は .intent/ 配下の既存成果物(mode.md / deltas.md /
19
+ // export-log.md)・`.kiro/specs/`(存在時、読み取りのみ)と git 履歴(spawnSync の
20
+ // 引数配列で実行。シェル文字列を組み立てない)のみ。ファイル書き込みはゼロ。
21
+ // - fail-open: 設定の未記載・不正値・ファイル不在はすべて既定値
22
+ // (enforcement=off / threshold=5 / 除外なし)へ静かにフォールバックし、停止しない。
23
+ // 不正値があったことは invalidFields で呼び出し側へ伝え、人間可読部の注記に使う。
24
+ // git の失敗(CLI 不在・非リポジトリ・ハッシュ不存在)も例外にせず縮退する。
25
+
26
+ import { spawnSync } from "node:child_process";
27
+ import fs from "node:fs";
28
+ import path from "node:path";
29
+ import { pathToFileURL } from "node:url";
30
+
31
+ // ---------------------------------------------------------------------------
32
+ // 既定値(mode.md の Enforcement セクションが欠けているときの解釈)
33
+ // ---------------------------------------------------------------------------
34
+
35
+ const DEFAULT_ENFORCEMENT = "off";
36
+ const DEFAULT_THRESHOLD = 5;
37
+ // .intent/ は設定によらず常に staleness 計数から暗黙除外する。
38
+ // parseEnforcementConfig の返り値 exclude に必ず先頭で含めることで規約を一元化する。
39
+ const IMPLICIT_EXCLUDE = ".intent/";
40
+
41
+ const VALID_ENFORCEMENT = new Set(["off", "remind", "gate"]);
42
+
43
+ /**
44
+ * mode.md の Enforcement セクションのパース結果。
45
+ *
46
+ * @typedef {object} EnforcementConfig
47
+ * @property {"off"|"remind"|"gate"} enforcement 強制の強度(既定 off)
48
+ * @property {number} threshold staleness 閾値コミット数(正の整数、既定 5)
49
+ * @property {string[]} exclude 計数から除く相対パス接頭辞。先頭に必ず ".intent/"(暗黙除外)を含む
50
+ * @property {string[]} invalidFields 不正値のため既定へフォールバックしたフィールド名
51
+ * ("enforcement" | "enforcement-threshold"。判定行の invalid 注記に使う)
52
+ */
53
+
54
+ /**
55
+ * export-log.md の1行(1 export)。
56
+ *
57
+ * @typedef {object} ExportLogEntry
58
+ * @property {string} packet packet 名(packet ファイルの frontmatter `name` との照合キー)
59
+ * @property {string} exportedAt export 日時(ISO 8601。記録された文字列のまま)
60
+ * @property {string|null} commit export 時点の短縮コミットハッシュ。記録 `-`(取得不可)は null
61
+ */
62
+
63
+ /**
64
+ * computeStaleness の結果(後続層が threshold / pending と合成して CheckResult を作る)。
65
+ *
66
+ * @typedef {object} StalenessResult
67
+ * @property {number|null} commits 基準点以降に非除外パスへ触れたコミット数。
68
+ * 基準点なし・git 利用不可(baseline.kind === "none")のとき null
69
+ * @property {{ kind: "export-hash"|"delta-date"|"none", value: string|null }} baseline
70
+ * 採用された基準点。export-hash は短縮ハッシュ、delta-date は日付(YYYY-MM-DD)、
71
+ * none(not-applicable 相当)は value=null
72
+ * @property {boolean} gitAvailable git CLI が実行でき、かつ cwd が git 作業ツリー内か
73
+ */
74
+
75
+ // ---------------------------------------------------------------------------
76
+ // 共通ヘルパ
77
+ // ---------------------------------------------------------------------------
78
+
79
+ /**
80
+ * ファイルを UTF-8 で読み、不在なら null を返す(fail-open の入口)。
81
+ * 不在以外の I/O エラーは隠さず投げる(呼び出し側で exit 2 = 内部エラー扱いにする)。
82
+ *
83
+ * @param {string} filePath 読み取るファイルの絶対パス
84
+ * @returns {string|null} ファイル内容。不在(ENOENT / ENOTDIR)なら null
85
+ */
86
+ export function readTextIfExists(filePath) {
87
+ try {
88
+ return fs.readFileSync(filePath, "utf8");
89
+ } catch (err) {
90
+ if (err && (err.code === "ENOENT" || err.code === "ENOTDIR")) return null;
91
+ throw err;
92
+ }
93
+ }
94
+
95
+ // 値が ISO 8601 の日付(任意で時刻つき)として実在するか。
96
+ // 形(YYYY-MM-DD 始まり)+ Date.parse の実パース + 日付部の round-trip の3点を要求し、
97
+ // プレースホルダ(`<ISO 8601 日付>`)・月範囲外(2026-13-45)に加えて、Date.parse が
98
+ // 03-03 へ繰り上げて受理してしまう暦に無い日付(2026-02-31)も弾く。
99
+ function isIsoDate(value) {
100
+ const match = /^(\d{4}-\d{2}-\d{2})([T ].+)?$/.exec(value);
101
+ if (!match) return false;
102
+ if (Number.isNaN(Date.parse(value))) return false;
103
+ const parsed = new Date(`${match[1]}T00:00:00Z`);
104
+ return !Number.isNaN(parsed.getTime()) && parsed.toISOString().slice(0, 10) === match[1];
105
+ }
106
+
107
+ // ---------------------------------------------------------------------------
108
+ // mode.md — Enforcement セクションの寛容パース
109
+ // ---------------------------------------------------------------------------
110
+
111
+ // 設定行の形: `- **enforcement**: off`(太字マーカーは省略可: `- enforcement: off`)。
112
+ // scaffold に同居する説明行(`- **enforcement** — ...`)はコロン区切りでないため一致しない。
113
+ // 長いキーを先に置く(enforcement が enforcement-threshold の接頭辞のため)。
114
+ const CONFIG_LINE_RE =
115
+ /^\s*-\s*(?:\*\*)?(enforcement-threshold|enforcement-exclude|enforcement)(?:\*\*)?\s*:\s*(.*)$/;
116
+
117
+ /**
118
+ * mode.md の内容から enforcement 設定を寛容にパースする。
119
+ *
120
+ * 解釈規則(R1.3, R1.4, R2.5):
121
+ * - mode.md 不在(content = null)・フィールド未記載・空値 → 既定値(off / 5 / 除外なし)。
122
+ * invalid 扱いしない。
123
+ * - 不正値(enforcement の値域外・threshold が正の整数でない)→ 既定値へフォールバックし、
124
+ * invalidFields にフィールド名を積む(判定行で「invalid value ignored」と注記するため)。
125
+ * - `: ` と `:` は同一視する(値の前後空白は trim)。各フィールドは最初の設定行が勝つ。
126
+ * - exclude はカンマ区切りで trim し空要素は捨てる。`.intent/` は常に暗黙除外として
127
+ * 返り値 exclude の先頭に含める。
128
+ *
129
+ * @param {string|null|undefined} content mode.md の内容。不在なら null
130
+ * @returns {EnforcementConfig} パース結果(常に完全な既定値つき)
131
+ */
132
+ export function parseEnforcementConfig(content) {
133
+ /** @type {EnforcementConfig} */
134
+ const config = {
135
+ enforcement: DEFAULT_ENFORCEMENT,
136
+ threshold: DEFAULT_THRESHOLD,
137
+ exclude: [IMPLICIT_EXCLUDE],
138
+ invalidFields: [],
139
+ };
140
+ if (typeof content !== "string" || content === "") return config;
141
+
142
+ /** @type {Record<string, string>} */
143
+ const raw = {};
144
+ for (const line of content.split(/\r?\n/)) {
145
+ const match = CONFIG_LINE_RE.exec(line);
146
+ if (!match) continue;
147
+ const [, key, value] = match;
148
+ if (key in raw) continue; // 最初の設定行が勝つ
149
+ raw[key] = value.trim();
150
+ }
151
+
152
+ // enforcement: 値域 off | remind | gate(大文字小文字は許容)。空値は未記載と同じ。
153
+ if (raw.enforcement) {
154
+ const value = raw.enforcement.toLowerCase();
155
+ if (VALID_ENFORCEMENT.has(value)) {
156
+ config.enforcement = /** @type {"off"|"remind"|"gate"} */ (value);
157
+ } else {
158
+ config.invalidFields.push("enforcement");
159
+ }
160
+ }
161
+
162
+ // enforcement-threshold: 正の整数のみ有効。空値は未記載と同じ。
163
+ if (raw["enforcement-threshold"]) {
164
+ const value = raw["enforcement-threshold"];
165
+ if (/^\d+$/.test(value) && Number.parseInt(value, 10) >= 1) {
166
+ config.threshold = Number.parseInt(value, 10);
167
+ } else {
168
+ config.invalidFields.push("enforcement-threshold");
169
+ }
170
+ }
171
+
172
+ // enforcement-exclude: カンマ区切り・trim・空要素除去。暗黙除外との重複は捨てる。
173
+ if (raw["enforcement-exclude"]) {
174
+ for (const entry of raw["enforcement-exclude"].split(",")) {
175
+ const trimmed = entry.trim();
176
+ if (trimmed === "" || trimmed === IMPLICIT_EXCLUDE) continue;
177
+ config.exclude.push(trimmed);
178
+ }
179
+ }
180
+
181
+ return config;
182
+ }
183
+
184
+ // ---------------------------------------------------------------------------
185
+ // deltas.md — pending エントリの厳格パース
186
+ // ---------------------------------------------------------------------------
187
+
188
+ // エントリヘッダの形: `## Delta: <名前> — <日付>`(区切りは em-dash)。
189
+ const DELTA_HEADER_RE = /^##\s*Delta:\s*(.+?)\s*—\s*(.+?)\s*$/;
190
+ // Status 行の形: `- Status: <値>`。値の判定は接頭辞除去 + trim 後のリテラル等価のみ。
191
+ const STATUS_LINE_RE = /^\s*-\s*Status:\s*(.*)$/;
192
+
193
+ /**
194
+ * deltas.md の内容から pending 状態の delta を厳格パースで数え、packet 名を抽出する。
195
+ *
196
+ * 厳格条件(両方を満たすエントリのみ計数。substring 一致・緩い正規表現は使わない):
197
+ * - ヘッダ `## Delta: <名前> — <日付>` の日付が ISO 8601 として実パース可能
198
+ * (プレースホルダ `<ISO 8601 日付>` は不可)
199
+ * - エントリ内の最初の Status 行の値(`- Status:` 接頭辞除去 + trim 後)が
200
+ * リテラル等価で `pending`(雛形の `pending | promoted (...)` や
201
+ * `promoted (2026-06-11)` 注記は構造的に除外)
202
+ *
203
+ * この規則により、配布直後の未記入 scaffold では必ず pending=0 になる。
204
+ *
205
+ * @param {string|null|undefined} content deltas.md の内容。不在なら null
206
+ * @returns {string[]} pending な delta の packet 名(記載順)。件数 = pending 数
207
+ */
208
+ export function parsePendingDeltas(content) {
209
+ if (typeof content !== "string" || content === "") return [];
210
+
211
+ /** @type {string[]} */
212
+ const pending = [];
213
+ /** @type {{ name: string, date: string, status: string|null } | null} */
214
+ let entry = null;
215
+
216
+ const finalize = () => {
217
+ if (entry && entry.status === "pending" && isIsoDate(entry.date)) {
218
+ pending.push(entry.name);
219
+ }
220
+ entry = null;
221
+ };
222
+
223
+ for (const line of content.split(/\r?\n/)) {
224
+ const header = DELTA_HEADER_RE.exec(line);
225
+ if (header) {
226
+ finalize();
227
+ entry = { name: header[1], date: header[2], status: null };
228
+ continue;
229
+ }
230
+ if (/^##(?!#)/.test(line)) {
231
+ // Delta 以外のレベル2見出し(### 学び 等のレベル3はエントリ内に留まる)
232
+ finalize();
233
+ continue;
234
+ }
235
+ if (entry && entry.status === null) {
236
+ const status = STATUS_LINE_RE.exec(line);
237
+ if (status) entry.status = status[1].trim();
238
+ }
239
+ }
240
+ finalize();
241
+
242
+ return pending;
243
+ }
244
+
245
+ /**
246
+ * deltas.md の内容から全 delta エントリのヘッダ日付を記載順に抽出する。
247
+ *
248
+ * Status は問わない(promoted / closed も含める): delta エントリの存在自体が
249
+ * 「その日付に writeback が行われた」証拠であり、staleness の基準点(フォールバック
250
+ * 連鎖の第2候補)として有効なため。ヘッダ日付が ISO 8601 として実在しない行
251
+ * (プレースホルダ `<ISO 8601 日付>` 等)は捨てる。
252
+ *
253
+ * @param {string|null|undefined} content deltas.md の内容。不在なら null
254
+ * @returns {string[]} 有効な日付文字列(記載順・記録された文字列のまま)
255
+ */
256
+ export function parseDeltaDates(content) {
257
+ if (typeof content !== "string" || content === "") return [];
258
+
259
+ /** @type {string[]} */
260
+ const dates = [];
261
+ for (const line of content.split(/\r?\n/)) {
262
+ const header = DELTA_HEADER_RE.exec(line);
263
+ if (header && isIsoDate(header[2])) dates.push(header[2]);
264
+ }
265
+ return dates;
266
+ }
267
+
268
+ /**
269
+ * deltas.md の内容から全 delta エントリの名前(packet 名)を記載順に抽出する。
270
+ *
271
+ * Status は問わない: delta エントリの存在自体が「その packet について writeback が
272
+ * 行われた」証拠であり、多重 export の grace 抑止判定(先行 export 行に対応する
273
+ * writeback があるか)に使うため。parseDeltaDates と同じく、ヘッダ日付が ISO 8601
274
+ * として実在しない行(プレースホルダ雛形等)は捨てる。
275
+ *
276
+ * @param {string|null|undefined} content deltas.md の内容。不在なら null
277
+ * @returns {string[]} delta エントリの名前(記載順・記録された文字列のまま)
278
+ */
279
+ export function parseDeltaNames(content) {
280
+ if (typeof content !== "string" || content === "") return [];
281
+
282
+ /** @type {string[]} */
283
+ const names = [];
284
+ for (const line of content.split(/\r?\n/)) {
285
+ const header = DELTA_HEADER_RE.exec(line);
286
+ if (header && isIsoDate(header[2])) names.push(header[1]);
287
+ }
288
+ return names;
289
+ }
290
+
291
+ // ---------------------------------------------------------------------------
292
+ // export-log.md — テーブル行の読み取り
293
+ // ---------------------------------------------------------------------------
294
+
295
+ /**
296
+ * export-log.md の内容からデータ行(packet / exported_at / commit)を記載順に読み取る。
297
+ * 見出し・引用(>)・テーブルヘッダ・区切り行(|---|)は読み飛ばす。
298
+ * ヘッダのみの未記入 scaffold では空配列を返す。
299
+ *
300
+ * @param {string|null|undefined} content export-log.md の内容。不在なら null
301
+ * @returns {ExportLogEntry[]} export 履歴(ファイル記載順)
302
+ */
303
+ export function parseExportLog(content) {
304
+ if (typeof content !== "string" || content === "") return [];
305
+
306
+ /** @type {ExportLogEntry[]} */
307
+ const entries = [];
308
+ for (const line of content.split(/\r?\n/)) {
309
+ const trimmed = line.trim();
310
+ if (!trimmed.startsWith("|")) continue; // テーブル行以外(見出し・引用・空行)
311
+
312
+ const cells = trimmed
313
+ .split("|")
314
+ .slice(1, trimmed.endsWith("|") ? -1 : undefined)
315
+ .map((cell) => cell.trim());
316
+ if (cells.length < 3) continue;
317
+ if (cells.every((cell) => /^:?-+:?$/.test(cell))) continue; // 区切り行 |---|---|---|
318
+ if (cells[0] === "packet") continue; // ヘッダ行
319
+
320
+ entries.push({
321
+ packet: cells[0],
322
+ exportedAt: cells[1],
323
+ commit: cells[2] === "-" ? null : cells[2],
324
+ });
325
+ }
326
+ return entries;
327
+ }
328
+
329
+ /**
330
+ * export 履歴を読む(append-log-discipline-add task 3.2)。
331
+ * 分割形(`export-log/<packet-slug>.md` 群)が存在すればそれを正本として読み、各ファイルの
332
+ * テーブル行を集めて `exportedAt` 昇順に整列して返す(分割では append 順=ファイル位置が失われるため
333
+ * 時刻で順序を再構成する。computeStaleness は末尾を最新行・applyGrace は slice(0,-1) で前段を読む)。
334
+ * 分割ディレクトリが無ければ旧単一 `export-log.md`(add では生成 active ミラー)を読む(後方互換)。
335
+ *
336
+ * @param {string} intentDir `.intent` のパス
337
+ * @returns {ExportLogEntry[]} export 履歴(exportedAt 昇順 = 末尾が最新)
338
+ */
339
+ export function readExportLogEntries(intentDir) {
340
+ const splitDir = path.join(intentDir, "export-log");
341
+ let split = [];
342
+ try {
343
+ if (fs.statSync(splitDir).isDirectory()) {
344
+ for (const name of fs.readdirSync(splitDir)) {
345
+ if (!name.endsWith(".md")) continue;
346
+ split.push(...parseExportLog(readTextIfExists(path.join(splitDir, name))));
347
+ }
348
+ }
349
+ } catch {
350
+ split = [];
351
+ }
352
+ if (split.length > 0) {
353
+ return split.sort((a, b) =>
354
+ a.exportedAt < b.exportedAt ? -1 : a.exportedAt > b.exportedAt ? 1 : 0,
355
+ );
356
+ }
357
+ // フォールバック: 旧単一ファイル(生成ミラー)。記載順をそのまま用いる。
358
+ return parseExportLog(readTextIfExists(path.join(intentDir, "export-log.md")));
359
+ }
360
+
361
+ // ---------------------------------------------------------------------------
362
+ // staleness — git 履歴からの導出(基準点フォールバック連鎖)
363
+ // ---------------------------------------------------------------------------
364
+
365
+ /**
366
+ * git を同期実行し、成功時のみ stdout を返す。失敗(非ゼロ終了・CLI 不在 ENOENT)は
367
+ * 例外にせず null を返す(フォールバック連鎖の入口)。シェルを介さず引数配列で渡す。
368
+ *
369
+ * @param {string} gitCmd git コマンド名(テスト用注入点。通常 "git")
370
+ * @param {string[]} args git 引数の配列
371
+ * @param {string} cwd 実行ディレクトリ
372
+ * @returns {string|null} stdout。失敗なら null
373
+ */
374
+ function runGit(gitCmd, args, cwd) {
375
+ const result = spawnSync(gitCmd, args, { cwd, encoding: "utf8", windowsHide: true });
376
+ if (result.error || result.status !== 0) return null;
377
+ return typeof result.stdout === "string" ? result.stdout : "";
378
+ }
379
+
380
+ // export-log の commit セルとして基準点に使ってよい形: 短縮〜完全長の hex ハッシュのみ。
381
+ // `HEAD` / `main` 等の revision 式は git 上は解決できてしまうが「export 時点の固定点」では
382
+ // ないため、ハッシュ形状でなければ記録なし扱いにしてフォールバック連鎖へ進める。
383
+ const HEX_HASH_RE = /^[0-9a-f]{4,40}$/i;
384
+
385
+ // 有効な ISO 日付のうち日付部(YYYY-MM-DD)が最新のものを返す。無ければ null。
386
+ // 比較は日付部の語彙比較(ゼロ埋め固定長なので辞書順 = 時系列順)。Date.parse 比較だと
387
+ // 日付のみ(UTC 解釈)とタイムゾーン付き時刻の混在で日付部の古い方が勝つことがある。
388
+ // 基準点として使うのは日付部だけなので、同日付内の時刻差は順位に影響させない(先勝ち)。
389
+ function latestIsoDate(dates) {
390
+ let latest = null;
391
+ for (const date of dates) {
392
+ if (typeof date !== "string" || !isIsoDate(date)) continue;
393
+ if (latest === null || date.slice(0, 10) > latest.slice(0, 10)) latest = date;
394
+ }
395
+ return latest;
396
+ }
397
+
398
+ // 翌日 00:00(ローカル時刻・タイムゾーン表記なし)の --since 値を作る。
399
+ // 同日コミットを数えない(false positive 回避の安全側。設計が許容する盲点)ための境界。
400
+ // Date コンストラクタが月末・年末の繰り上がりを正規化する。
401
+ function nextDayMidnight(isoDateOnly) {
402
+ const [y, m, d] = isoDateOnly.split("-").map(Number);
403
+ const next = new Date(y, m - 1, d + 1);
404
+ const pad = (n) => String(n).padStart(2, "0");
405
+ return `${next.getFullYear()}-${pad(next.getMonth() + 1)}-${pad(next.getDate())}T00:00:00`;
406
+ }
407
+
408
+ // 計数用 pathspec: `.` 全体から .intent/(暗黙除外)と設定除外パスを除く。
409
+ // EnforcementConfig.exclude は先頭に .intent/ を含むため重複は捨てる。
410
+ function buildCountPathspec(excludePaths) {
411
+ const spec = [".", `:(exclude)${IMPLICIT_EXCLUDE}`];
412
+ const seen = new Set([IMPLICIT_EXCLUDE]);
413
+ for (const exclude of excludePaths) {
414
+ if (typeof exclude !== "string" || exclude === "" || seen.has(exclude)) continue;
415
+ seen.add(exclude);
416
+ spec.push(`:(exclude)${exclude}`);
417
+ }
418
+ return spec;
419
+ }
420
+
421
+ /**
422
+ * staleness(基準点以降に `.intent/` と除外パス以外へ触れたコミット数)を git から導出する。
423
+ *
424
+ * 基準点のフォールバック連鎖(R2.1, R2.4 / design "IntentCheckScript"):
425
+ * 1. export-log 最新行のコミットハッシュ。`git cat-file -e <hash>^{commit}` で存在確認
426
+ * してから `git rev-list --count <hash>..HEAD -- <pathspec>` で数える。ハッシュ不存在
427
+ * (rebase / amend / shallow clone)や rev-list 失敗は例外にせず 2. へ。
428
+ * 2. delta エントリ日付(最新のもの)。`git rev-list --count HEAD --since=<翌日 00:00>` で
429
+ * 日付より後のコミットのみ数える(同日コミットは数えない安全側)。ただし最新 export
430
+ * より新しい delta 日付がある場合(= export 後に writeback 済みで、ハッシュ基準点は
431
+ * もう古い)は 1. より先に試す。
432
+ * 3. どちらの基準点も使えなければ kind: "none"(not-applicable 相当、commits: null)。
433
+ *
434
+ * 非 git ディレクトリ・git CLI 不在は gitAvailable: false で即 kind: "none" を返し、
435
+ * 例外を投げない(fail-open)。書き込みは一切行わず、同一入力に対して決定的。
436
+ *
437
+ * @param {object} options
438
+ * @param {string} options.cwd 判定対象のプロジェクトルート(git 実行ディレクトリ)
439
+ * @param {ExportLogEntry[]} [options.exportLog] parseExportLog の結果(記載順)
440
+ * @param {string[]} [options.deltaDates] parseDeltaDates の結果(delta エントリの日付)
441
+ * @param {string[]} [options.excludePaths] 計数から除く相対パス接頭辞
442
+ * (EnforcementConfig.exclude。`.intent/` は含まれていなくても常に暗黙除外する)
443
+ * @param {string} [options.gitCmd] git コマンド名(テスト用の注入点。既定 "git")
444
+ * @returns {StalenessResult}
445
+ */
446
+ export function computeStaleness({
447
+ cwd,
448
+ exportLog = [],
449
+ deltaDates = [],
450
+ excludePaths = [],
451
+ gitCmd = "git",
452
+ }) {
453
+ /** @type {(gitAvailable: boolean) => StalenessResult} */
454
+ const none = (gitAvailable) => ({
455
+ commits: null,
456
+ baseline: { kind: "none", value: null },
457
+ gitAvailable,
458
+ });
459
+
460
+ const insideWorkTree = runGit(gitCmd, ["rev-parse", "--is-inside-work-tree"], cwd);
461
+ if (insideWorkTree === null || insideWorkTree.trim() !== "true") return none(false);
462
+
463
+ const pathspec = buildCountPathspec(excludePaths);
464
+ const countCommits = (revArgs) => {
465
+ const out = runGit(gitCmd, ["rev-list", "--count", ...revArgs, "--", ...pathspec], cwd);
466
+ if (out === null) return null;
467
+ const count = Number.parseInt(out.trim(), 10);
468
+ return Number.isInteger(count) && count >= 0 ? count : null;
469
+ };
470
+
471
+ const latestExport = exportLog.length > 0 ? exportLog[exportLog.length - 1] : null;
472
+ // hex 形状でない commit セル(`HEAD` 等)は記録なし扱い(フォールバック連鎖へ)
473
+ const exportHash =
474
+ latestExport && latestExport.commit && HEX_HASH_RE.test(latestExport.commit)
475
+ ? latestExport.commit
476
+ : null;
477
+ const latestDelta = latestIsoDate(deltaDates);
478
+
479
+ /** @type {Array<{ kind: "export-hash"|"delta-date", value: string, count: () => number|null }>} */
480
+ const candidates = [];
481
+ if (exportHash !== null) {
482
+ candidates.push({
483
+ kind: "export-hash",
484
+ value: exportHash,
485
+ count: () => {
486
+ if (runGit(gitCmd, ["cat-file", "-e", `${exportHash}^{commit}`], cwd) === null) return null;
487
+ return countCommits([`${exportHash}..HEAD`]);
488
+ },
489
+ });
490
+ }
491
+ if (latestDelta !== null) {
492
+ const dateOnly = latestDelta.slice(0, 10);
493
+ candidates.push({
494
+ kind: "delta-date",
495
+ value: dateOnly,
496
+ count: () => countCommits(["HEAD", `--since=${nextDayMidnight(dateOnly)}`]),
497
+ });
498
+ }
499
+ // 最新 export より delta 日付が厳密に新しい(export 後の writeback がある)ときだけ
500
+ // delta-date を先頭へ。export 日時が不正で比較できない場合はハッシュ優先のまま。
501
+ if (
502
+ candidates.length === 2 &&
503
+ latestExport !== null &&
504
+ latestDelta !== null &&
505
+ Date.parse(latestDelta) > Date.parse(latestExport.exportedAt)
506
+ ) {
507
+ candidates.reverse();
508
+ }
509
+
510
+ for (const candidate of candidates) {
511
+ const commits = candidate.count();
512
+ if (commits !== null) {
513
+ return {
514
+ commits,
515
+ baseline: { kind: candidate.kind, value: candidate.value },
516
+ gitAvailable: true,
517
+ };
518
+ }
519
+ }
520
+ return none(true);
521
+ }
522
+
523
+ // ---------------------------------------------------------------------------
524
+ // in-implementation grace — .kiro/specs/ との照合(読み取りのみ・任意依存)
525
+ // ---------------------------------------------------------------------------
526
+
527
+ // 未チェックタスク行(`- [ ]`)。1つでも残っていれば spec は進行中とみなす。
528
+ const UNCHECKED_TASK_RE = /^\s*-\s*\[ \]/m;
529
+
530
+ /**
531
+ * packet 名に対応する進行中 spec を `.kiro/specs/` から探す。
532
+ *
533
+ * 照合規則(単純・決定的): spec ディレクトリ名 または その tasks.md 本文が
534
+ * packet 名(trim 済み)を含むこと(テキスト包含・大文字小文字非区別)。かつ
535
+ * tasks.md に未チェックタスク `- [ ]` が1つ以上残っていること(= 実装進行中)。
536
+ * 候補が複数あるときは名前順で最初の進行中 spec を返す(決定性の確保)。
537
+ *
538
+ * `.kiro/specs/` 不在・tasks.md 不在・照合不可はすべて null(grace なし)に縮退する。
539
+ *
540
+ * @param {string} cwd プロジェクトルート
541
+ * @param {string} packetName export-log 最新行の packet 名(trim 済み・非空)
542
+ * @returns {string|null} 進行中 spec のディレクトリ名。対応なしなら null
543
+ */
544
+ function findInProgressSpecForPacket(cwd, packetName) {
545
+ const specsDir = path.join(cwd, ".kiro", "specs");
546
+ let entries;
547
+ try {
548
+ entries = fs.readdirSync(specsDir, { withFileTypes: true });
549
+ } catch (err) {
550
+ if (err && (err.code === "ENOENT" || err.code === "ENOTDIR")) return null;
551
+ throw err;
552
+ }
553
+
554
+ const needle = packetName.toLowerCase();
555
+ const dirNames = entries
556
+ .filter((entry) => entry.isDirectory())
557
+ .map((entry) => entry.name)
558
+ .sort();
559
+ for (const dirName of dirNames) {
560
+ const tasks = readTextIfExists(path.join(specsDir, dirName, "tasks.md"));
561
+ if (tasks === null) continue;
562
+ const matches =
563
+ dirName.toLowerCase().includes(needle) || tasks.toLowerCase().includes(needle);
564
+ if (matches && UNCHECKED_TASK_RE.test(tasks)) return dirName;
565
+ }
566
+ return null;
567
+ }
568
+
569
+ // ---------------------------------------------------------------------------
570
+ // runCheck — 判定の合成(CheckResult)と出力契約
571
+ // ---------------------------------------------------------------------------
572
+
573
+ /**
574
+ * runCheck の合成結果(design "Service Interface" の CheckResult)。
575
+ * design 定義の8フィールドに、人間可読の根拠行を組み立てるための3フィールド
576
+ * (graceSpec / graceBlockedBy / invalidFields)を追加している。
577
+ *
578
+ * 不変条件:
579
+ * - result === "stale" ⇒ commits > threshold
580
+ * - shouldBlock ⇒ enforcement === "gate"
581
+ * - grace === "in-implementation" ⇒ result === "ok"
582
+ *
583
+ * @typedef {object} CheckResult
584
+ * @property {"ok"|"stale"|"not-applicable"} result staleness 判定。
585
+ * enforcement=off では導出自体をスキップし "ok"(commits=null)と報告する
586
+ * (off では警告もブロックも発生せず判定値は消費されないため。人間可読部に明記)
587
+ * @property {"off"|"remind"|"gate"} enforcement 適用された強制の強度
588
+ * @property {number|null} commits 基準点以降の非除外コミット数(未導出・導出不能は null)
589
+ * @property {number} threshold 適用された staleness 閾値
590
+ * @property {{ kind: "export-hash"|"delta-date"|"none", value: string|null }} baseline 採用基準点
591
+ * @property {"in-implementation"|null} grace 進行中 spec 検出により staleness を抑止した印
592
+ * @property {string|null} graceSpec grace の根拠になった spec ディレクトリ名
593
+ * @property {string[]} graceBlockedBy grace を抑止した欠落 packet 名(先行 export 行のうち
594
+ * 対応する delta エントリが deltas.md に無いもの。多重 export の保護)
595
+ * @property {string[]} pendingDeltas pending 状態の delta の packet 名(厳格パース)
596
+ * @property {string[]} invalidFields 既定値へフォールバックした不正設定フィールド名
597
+ * @property {boolean} shouldBlock enforcement==="gate" && (stale || pending>0)
598
+ */
599
+
600
+ /**
601
+ * pending / staleness / grace を合成して最終判定を作る(書き込みゼロ・決定的)。
602
+ *
603
+ * 判定の流れ:
604
+ * 1. `.intent/` 不在 → not-applicable(前提条件。git も読まない)
605
+ * 2. enforcement=off → staleness 導出をスキップして ok(pending の計数だけは行う)
606
+ * 3. remind|gate → computeStaleness。基準点なしは not-applicable、
607
+ * commits > threshold なら stale。ただし in-implementation grace
608
+ * (export-log 最新 packet ↔ 進行中 spec の照合。先行 export 行の delta 欠落が
609
+ * あれば適用せず graceBlockedBy に欠落名)で ok へ抑止しうる
610
+ * 4. shouldBlock = gate かつ (stale または pending>0)。staleness が not-applicable
611
+ * でも pending だけでブロックは成立する(R4.5)。pending 検査は grace 中も常に有効
612
+ *
613
+ * @param {string} cwd 判定対象のプロジェクトルート
614
+ * @param {object} [opts]
615
+ * @param {string} [opts.gitCmd] git コマンド名(テスト用の注入点。既定 "git")
616
+ * @returns {CheckResult}
617
+ */
618
+ export function runCheck(cwd, { gitCmd = "git" } = {}) {
619
+ const intentDir = path.join(cwd, ".intent");
620
+ const config = parseEnforcementConfig(readTextIfExists(path.join(intentDir, "mode.md")));
621
+ const deltasContent = readTextIfExists(path.join(intentDir, "deltas.md"));
622
+ const pendingDeltas = parsePendingDeltas(deltasContent);
623
+ const exportLog = readExportLogEntries(intentDir);
624
+
625
+ /** @type {CheckResult} */
626
+ const check = {
627
+ result: "not-applicable",
628
+ enforcement: config.enforcement,
629
+ commits: null,
630
+ threshold: config.threshold,
631
+ baseline: { kind: "none", value: null },
632
+ grace: null,
633
+ graceSpec: null,
634
+ graceBlockedBy: [],
635
+ pendingDeltas,
636
+ invalidFields: config.invalidFields,
637
+ shouldBlock: false,
638
+ };
639
+
640
+ if (fs.existsSync(intentDir)) {
641
+ if (config.enforcement === "off") {
642
+ // off は強制を発動しないため staleness 導出(git 実行)を省略する。
643
+ // result=ok / commits=null は「検査せず通過」の意(人間可読部に明記される)。
644
+ check.result = "ok";
645
+ } else {
646
+ const staleness = computeStaleness({
647
+ cwd,
648
+ exportLog,
649
+ deltaDates: parseDeltaDates(deltasContent),
650
+ excludePaths: config.exclude,
651
+ gitCmd,
652
+ });
653
+ check.commits = staleness.commits;
654
+ check.baseline = staleness.baseline;
655
+ if (staleness.baseline.kind === "none") {
656
+ check.result = "not-applicable"; // pending のみで判定継続(R4.5)
657
+ } else if (staleness.commits > config.threshold) {
658
+ applyGrace(check, cwd, exportLog, deltasContent);
659
+ } else {
660
+ check.result = "ok";
661
+ }
662
+ }
663
+ }
664
+
665
+ check.shouldBlock =
666
+ check.enforcement === "gate" && (check.result === "stale" || pendingDeltas.length > 0);
667
+ return check;
668
+ }
669
+
670
+ /**
671
+ * 閾値超過時の in-implementation grace 判定。check の result / grace / graceSpec /
672
+ * graceBlockedBy を更新する(grace 不成立なら result="stale" のまま)。
673
+ *
674
+ * 適用条件(design "IntentCheckScript" の grace 段落):
675
+ * - export-log 最新行の packet が `.kiro/specs/` の進行中 spec に対応すること
676
+ * - かつ最新行より前の全 export 行に、packet 名が一致する delta エントリ
677
+ * (status 不問 = writeback の証拠)が deltas.md に存在すること。
678
+ * 欠落があれば grace を適用せず、欠落 packet 名を graceBlockedBy に積む
679
+ *
680
+ * @param {CheckResult} check 更新対象(result は呼び出し時点で stale 相当)
681
+ * @param {string} cwd プロジェクトルート
682
+ * @param {ExportLogEntry[]} exportLog export 履歴(記載順)
683
+ * @param {string|null} deltasContent deltas.md の内容
684
+ */
685
+ function applyGrace(check, cwd, exportLog, deltasContent) {
686
+ check.result = "stale";
687
+ const latest = exportLog.length > 0 ? exportLog[exportLog.length - 1] : null;
688
+ const packet = latest ? latest.packet.trim() : "";
689
+ if (packet === "") return; // 照合キーなし → grace なし
690
+
691
+ const specName = findInProgressSpecForPacket(cwd, packet);
692
+ if (specName === null) return; // 進行中 spec に対応しない → grace なし
693
+
694
+ // 多重 export の保護: 先行 export 行の writeback 漏れがあるなら grace を抑止する
695
+ const deltaNames = new Set(
696
+ parseDeltaNames(deltasContent).map((name) => name.trim().toLowerCase()),
697
+ );
698
+ /** @type {string[]} */
699
+ const missing = [];
700
+ for (const row of exportLog.slice(0, -1)) {
701
+ const name = row.packet.trim();
702
+ if (name === "" || deltaNames.has(name.toLowerCase()) || missing.includes(name)) continue;
703
+ missing.push(name);
704
+ }
705
+ if (missing.length > 0) {
706
+ check.graceBlockedBy = missing;
707
+ return;
708
+ }
709
+
710
+ check.result = "ok";
711
+ check.grace = "in-implementation";
712
+ check.graceSpec = specName;
713
+ }
714
+
715
+ /**
716
+ * CheckResult を出力契約(design "Batch / Job Contract")に整形する。
717
+ * 1行目は機械可読の判定行(キー順固定・注記等で形式を崩さない)、2行目以降は
718
+ * 人間可読の根拠。ja/en 同一バイト配布のためメッセージは英語に固定する。
719
+ *
720
+ * @param {CheckResult} check runCheck の結果
721
+ * @returns {string[]} 出力行(先頭が判定行。常に2行以上)
722
+ */
723
+ export function formatCheckOutput(check) {
724
+ const commits = check.commits === null ? "-" : String(check.commits);
725
+ const grace = check.grace === null ? "-" : check.grace;
726
+ const block = check.shouldBlock ? "yes" : "no";
727
+ const lines = [
728
+ `intent-check: result=${check.result} enforcement=${check.enforcement} commits=${commits} threshold=${check.threshold} grace=${grace} pending=${check.pendingDeltas.length} block=${block}`,
729
+ ];
730
+
731
+ if (check.invalidFields.length > 0) {
732
+ lines.push(
733
+ `- config: ${check.invalidFields.join(", ")} (invalid value ignored; defaults applied)`,
734
+ );
735
+ }
736
+ if (check.enforcement === "off") {
737
+ lines.push("- enforcement=off: staleness check skipped (nothing is blocked; commits=-)");
738
+ } else if (check.baseline.kind === "none") {
739
+ lines.push("- baseline: none (no usable reference point or no git history; staleness not applicable)");
740
+ } else {
741
+ lines.push(`- baseline: ${check.baseline.kind} ${check.baseline.value}`);
742
+ }
743
+ if (check.grace === "in-implementation") {
744
+ lines.push(
745
+ `- grace: latest export packet matches in-progress spec ".kiro/specs/${check.graceSpec}/" (unchecked tasks remain); staleness suppressed`,
746
+ );
747
+ }
748
+ if (check.graceBlockedBy.length > 0) {
749
+ lines.push(
750
+ `- grace suppressed: earlier export packet(s) without a writeback delta: ${check.graceBlockedBy.join(", ")}`,
751
+ );
752
+ }
753
+ if (check.result === "stale") {
754
+ lines.push(`- stale: ${check.commits} commits since baseline exceed threshold ${check.threshold}`);
755
+ }
756
+ if (check.pendingDeltas.length > 0) {
757
+ lines.push(`- pending delta(s): ${check.pendingDeltas.join(", ")}`);
758
+ }
759
+ if (check.result === "stale" || check.pendingDeltas.length > 0) {
760
+ lines.push("- next: run /intent-writeback to record learnings before moving on");
761
+ }
762
+ return lines;
763
+ }
764
+
765
+ // ---------------------------------------------------------------------------
766
+ // main guard — CLI 本体(import 時は副作用ゼロ)
767
+ // ---------------------------------------------------------------------------
768
+
769
+ // 直接実行(node .intent/scripts/intent-check.mjs)の判定。
770
+ const isMain =
771
+ typeof process.argv[1] === "string" &&
772
+ import.meta.url === pathToFileURL(process.argv[1]).href;
773
+
774
+ if (isMain) {
775
+ try {
776
+ const check = runCheck(process.cwd());
777
+ process.stdout.write(`${formatCheckOutput(check).join("\n")}\n`);
778
+ process.exitCode = check.shouldBlock ? 1 : 0;
779
+ } catch (err) {
780
+ // 想定外の内部エラーのみここに来る(git 失敗やファイル不在は各層で縮退済み)。
781
+ // 呼び出し側(スキル・pre-push フック)は exit 2 を通過扱いにする(fail-open)。
782
+ const detail = err && err.stack ? err.stack : String(err);
783
+ process.stderr.write(`intent-check: internal error\n${detail}\n`);
784
+ process.exitCode = 2;
785
+ }
786
+ }