@seanmars/tospec 0.19.0-beta.7 → 0.20.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 (429) hide show
  1. package/CHANGELOG.md +60 -231
  2. package/README.md +69 -82
  3. package/assets/dashboard/app.js +14 -3
  4. package/assets/dashboard/style.css +7 -0
  5. package/assets/rules/tospec/decision.md +3 -0
  6. package/dist/cli/index.d.ts.map +1 -1
  7. package/dist/cli/index.js +227 -86
  8. package/dist/cli/index.js.map +1 -1
  9. package/dist/commands/config.d.ts +9 -17
  10. package/dist/commands/config.d.ts.map +1 -1
  11. package/dist/commands/config.js +366 -107
  12. package/dist/commands/config.js.map +1 -1
  13. package/dist/commands/dashboard.d.ts +57 -99
  14. package/dist/commands/dashboard.d.ts.map +1 -1
  15. package/dist/commands/dashboard.js +224 -282
  16. package/dist/commands/dashboard.js.map +1 -1
  17. package/dist/commands/decision.d.ts +41 -19
  18. package/dist/commands/decision.d.ts.map +1 -1
  19. package/dist/commands/decision.js +385 -79
  20. package/dist/commands/decision.js.map +1 -1
  21. package/dist/commands/metrics.d.ts +28 -51
  22. package/dist/commands/metrics.d.ts.map +1 -1
  23. package/dist/commands/metrics.js +62 -93
  24. package/dist/commands/metrics.js.map +1 -1
  25. package/dist/commands/shared-output.d.ts +18 -21
  26. package/dist/commands/shared-output.d.ts.map +1 -1
  27. package/dist/commands/shared-output.js +49 -23
  28. package/dist/commands/shared-output.js.map +1 -1
  29. package/dist/commands/show.d.ts +7 -0
  30. package/dist/commands/show.d.ts.map +1 -1
  31. package/dist/commands/show.js +29 -7
  32. package/dist/commands/show.js.map +1 -1
  33. package/dist/commands/validate.d.ts +43 -45
  34. package/dist/commands/validate.d.ts.map +1 -1
  35. package/dist/commands/validate.js +262 -129
  36. package/dist/commands/validate.js.map +1 -1
  37. package/dist/commands/workflow/index.d.ts +6 -10
  38. package/dist/commands/workflow/index.d.ts.map +1 -1
  39. package/dist/commands/workflow/index.js +6 -10
  40. package/dist/commands/workflow/index.js.map +1 -1
  41. package/dist/commands/workflow/instructions.d.ts +21 -8
  42. package/dist/commands/workflow/instructions.d.ts.map +1 -1
  43. package/dist/commands/workflow/instructions.js +254 -95
  44. package/dist/commands/workflow/instructions.js.map +1 -1
  45. package/dist/commands/workflow/new-change.d.ts +4 -5
  46. package/dist/commands/workflow/new-change.d.ts.map +1 -1
  47. package/dist/commands/workflow/new-change.js +90 -25
  48. package/dist/commands/workflow/new-change.js.map +1 -1
  49. package/dist/commands/workflow/schemas.d.ts +3 -5
  50. package/dist/commands/workflow/schemas.d.ts.map +1 -1
  51. package/dist/commands/workflow/schemas.js +37 -11
  52. package/dist/commands/workflow/schemas.js.map +1 -1
  53. package/dist/commands/workflow/shared.d.ts +48 -21
  54. package/dist/commands/workflow/shared.d.ts.map +1 -1
  55. package/dist/commands/workflow/shared.js +36 -33
  56. package/dist/commands/workflow/shared.js.map +1 -1
  57. package/dist/commands/workflow/status.d.ts +10 -6
  58. package/dist/commands/workflow/status.d.ts.map +1 -1
  59. package/dist/commands/workflow/status.js +81 -42
  60. package/dist/commands/workflow/status.js.map +1 -1
  61. package/dist/commands/workflow/templates.d.ts +10 -3
  62. package/dist/commands/workflow/templates.d.ts.map +1 -1
  63. package/dist/commands/workflow/templates.js +39 -40
  64. package/dist/commands/workflow/templates.js.map +1 -1
  65. package/dist/core/archive.d.ts +26 -21
  66. package/dist/core/archive.d.ts.map +1 -1
  67. package/dist/core/archive.js +378 -235
  68. package/dist/core/archive.js.map +1 -1
  69. package/dist/core/artifact-graph/graph.d.ts +25 -42
  70. package/dist/core/artifact-graph/graph.d.ts.map +1 -1
  71. package/dist/core/artifact-graph/graph.js +45 -63
  72. package/dist/core/artifact-graph/graph.js.map +1 -1
  73. package/dist/core/artifact-graph/index.d.ts +1 -1
  74. package/dist/core/artifact-graph/index.d.ts.map +1 -1
  75. package/dist/core/artifact-graph/index.js +1 -1
  76. package/dist/core/artifact-graph/index.js.map +1 -1
  77. package/dist/core/artifact-graph/instruction-loader.d.ts +97 -103
  78. package/dist/core/artifact-graph/instruction-loader.d.ts.map +1 -1
  79. package/dist/core/artifact-graph/instruction-loader.js +146 -119
  80. package/dist/core/artifact-graph/instruction-loader.js.map +1 -1
  81. package/dist/core/artifact-graph/outputs.d.ts +9 -23
  82. package/dist/core/artifact-graph/outputs.d.ts.map +1 -1
  83. package/dist/core/artifact-graph/outputs.js +45 -38
  84. package/dist/core/artifact-graph/outputs.js.map +1 -1
  85. package/dist/core/artifact-graph/resolver.d.ts +44 -63
  86. package/dist/core/artifact-graph/resolver.d.ts.map +1 -1
  87. package/dist/core/artifact-graph/resolver.js +85 -86
  88. package/dist/core/artifact-graph/resolver.js.map +1 -1
  89. package/dist/core/artifact-graph/schema.d.ts +0 -6
  90. package/dist/core/artifact-graph/schema.d.ts.map +1 -1
  91. package/dist/core/artifact-graph/schema.js +7 -32
  92. package/dist/core/artifact-graph/schema.js.map +1 -1
  93. package/dist/core/artifact-graph/state.d.ts +1 -8
  94. package/dist/core/artifact-graph/state.d.ts.map +1 -1
  95. package/dist/core/artifact-graph/state.js +2 -17
  96. package/dist/core/artifact-graph/state.js.map +1 -1
  97. package/dist/core/artifact-graph/stub-detection.d.ts +12 -0
  98. package/dist/core/artifact-graph/stub-detection.d.ts.map +1 -0
  99. package/dist/core/artifact-graph/stub-detection.js +39 -0
  100. package/dist/core/artifact-graph/stub-detection.js.map +1 -0
  101. package/dist/core/artifact-graph/types.d.ts +4 -0
  102. package/dist/core/artifact-graph/types.d.ts.map +1 -1
  103. package/dist/core/artifact-graph/types.js +30 -10
  104. package/dist/core/artifact-graph/types.js.map +1 -1
  105. package/dist/core/available-tools.d.ts +3 -12
  106. package/dist/core/available-tools.d.ts.map +1 -1
  107. package/dist/core/available-tools.js +4 -13
  108. package/dist/core/available-tools.js.map +1 -1
  109. package/dist/core/change-metadata/schema.d.ts +1 -1
  110. package/dist/core/change-metadata/schema.d.ts.map +1 -1
  111. package/dist/core/change-metadata/schema.js +10 -7
  112. package/dist/core/change-metadata/schema.js.map +1 -1
  113. package/dist/core/change-presenter.d.ts +23 -18
  114. package/dist/core/change-presenter.d.ts.map +1 -1
  115. package/dist/core/change-presenter.js +102 -43
  116. package/dist/core/change-presenter.js.map +1 -1
  117. package/dist/core/change-status-policy.d.ts +8 -1
  118. package/dist/core/change-status-policy.d.ts.map +1 -1
  119. package/dist/core/change-status-policy.js +25 -1
  120. package/dist/core/change-status-policy.js.map +1 -1
  121. package/dist/core/codex-metrics.d.ts +25 -45
  122. package/dist/core/codex-metrics.d.ts.map +1 -1
  123. package/dist/core/codex-metrics.js +44 -88
  124. package/dist/core/codex-metrics.js.map +1 -1
  125. package/dist/core/codex-residue.d.ts +14 -15
  126. package/dist/core/codex-residue.d.ts.map +1 -1
  127. package/dist/core/codex-residue.js +18 -22
  128. package/dist/core/codex-residue.js.map +1 -1
  129. package/dist/core/command-generation/adapters/claude.d.ts +2 -9
  130. package/dist/core/command-generation/adapters/claude.d.ts.map +1 -1
  131. package/dist/core/command-generation/adapters/claude.js +2 -12
  132. package/dist/core/command-generation/adapters/claude.js.map +1 -1
  133. package/dist/core/command-generation/adapters/index.d.ts +1 -9
  134. package/dist/core/command-generation/adapters/index.d.ts.map +1 -1
  135. package/dist/core/command-generation/adapters/index.js +1 -9
  136. package/dist/core/command-generation/adapters/index.js.map +1 -1
  137. package/dist/core/command-generation/generator.d.ts +0 -17
  138. package/dist/core/command-generation/generator.d.ts.map +1 -1
  139. package/dist/core/command-generation/generator.js +0 -17
  140. package/dist/core/command-generation/generator.js.map +1 -1
  141. package/dist/core/command-generation/index.d.ts +2 -5
  142. package/dist/core/command-generation/index.d.ts.map +1 -1
  143. package/dist/core/command-generation/index.js +0 -9
  144. package/dist/core/command-generation/index.js.map +1 -1
  145. package/dist/core/command-generation/types.d.ts +10 -36
  146. package/dist/core/command-generation/types.d.ts.map +1 -1
  147. package/dist/core/command-generation/types.js +0 -6
  148. package/dist/core/command-generation/types.js.map +1 -1
  149. package/dist/core/command-generation/yaml.d.ts +3 -18
  150. package/dist/core/command-generation/yaml.d.ts.map +1 -1
  151. package/dist/core/command-generation/yaml.js +5 -23
  152. package/dist/core/command-generation/yaml.js.map +1 -1
  153. package/dist/core/config-prompts.d.ts +2 -4
  154. package/dist/core/config-prompts.d.ts.map +1 -1
  155. package/dist/core/config-prompts.js +2 -7
  156. package/dist/core/config-prompts.js.map +1 -1
  157. package/dist/core/config-schema.d.ts +8 -53
  158. package/dist/core/config-schema.d.ts.map +1 -1
  159. package/dist/core/config-schema.js +49 -62
  160. package/dist/core/config-schema.js.map +1 -1
  161. package/dist/core/config.d.ts +39 -26
  162. package/dist/core/config.d.ts.map +1 -1
  163. package/dist/core/config.js +36 -22
  164. package/dist/core/config.js.map +1 -1
  165. package/dist/core/dashboard-activity.d.ts +7 -9
  166. package/dist/core/dashboard-activity.d.ts.map +1 -1
  167. package/dist/core/dashboard-activity.js +26 -24
  168. package/dist/core/dashboard-activity.js.map +1 -1
  169. package/dist/core/dashboard-data.d.ts +40 -22
  170. package/dist/core/dashboard-data.d.ts.map +1 -1
  171. package/dist/core/dashboard-data.js +62 -70
  172. package/dist/core/dashboard-data.js.map +1 -1
  173. package/dist/core/global-config.d.ts +24 -53
  174. package/dist/core/global-config.d.ts.map +1 -1
  175. package/dist/core/global-config.js +38 -67
  176. package/dist/core/global-config.js.map +1 -1
  177. package/dist/core/init.d.ts +25 -19
  178. package/dist/core/init.d.ts.map +1 -1
  179. package/dist/core/init.js +168 -181
  180. package/dist/core/init.js.map +1 -1
  181. package/dist/core/list.d.ts +1 -1
  182. package/dist/core/list.d.ts.map +1 -1
  183. package/dist/core/list.js +121 -28
  184. package/dist/core/list.js.map +1 -1
  185. package/dist/core/local-server.d.ts +41 -83
  186. package/dist/core/local-server.d.ts.map +1 -1
  187. package/dist/core/local-server.js +53 -98
  188. package/dist/core/local-server.js.map +1 -1
  189. package/dist/core/markdown-render.d.ts +25 -0
  190. package/dist/core/markdown-render.d.ts.map +1 -0
  191. package/dist/core/markdown-render.js +94 -0
  192. package/dist/core/markdown-render.js.map +1 -0
  193. package/dist/core/migrate.d.ts +29 -14
  194. package/dist/core/migrate.d.ts.map +1 -1
  195. package/dist/core/migrate.js +184 -122
  196. package/dist/core/migrate.js.map +1 -1
  197. package/dist/core/parsers/change-parser.d.ts +7 -10
  198. package/dist/core/parsers/change-parser.d.ts.map +1 -1
  199. package/dist/core/parsers/change-parser.js +48 -56
  200. package/dist/core/parsers/change-parser.js.map +1 -1
  201. package/dist/core/parsers/markdown-parser.d.ts +8 -9
  202. package/dist/core/parsers/markdown-parser.d.ts.map +1 -1
  203. package/dist/core/parsers/markdown-parser.js +31 -22
  204. package/dist/core/parsers/markdown-parser.js.map +1 -1
  205. package/dist/core/parsers/requirement-blocks.d.ts +43 -15
  206. package/dist/core/parsers/requirement-blocks.d.ts.map +1 -1
  207. package/dist/core/parsers/requirement-blocks.js +142 -70
  208. package/dist/core/parsers/requirement-blocks.js.map +1 -1
  209. package/dist/core/parsers/requirement-text.d.ts +73 -79
  210. package/dist/core/parsers/requirement-text.d.ts.map +1 -1
  211. package/dist/core/parsers/requirement-text.js +137 -79
  212. package/dist/core/parsers/requirement-text.js.map +1 -1
  213. package/dist/core/parsers/spec-structure.d.ts.map +1 -1
  214. package/dist/core/parsers/spec-structure.js +10 -6
  215. package/dist/core/parsers/spec-structure.js.map +1 -1
  216. package/dist/core/profiles.d.ts +3 -10
  217. package/dist/core/profiles.d.ts.map +1 -1
  218. package/dist/core/profiles.js +5 -12
  219. package/dist/core/profiles.js.map +1 -1
  220. package/dist/core/project-config.d.ts +43 -44
  221. package/dist/core/project-config.d.ts.map +1 -1
  222. package/dist/core/project-config.js +107 -82
  223. package/dist/core/project-config.js.map +1 -1
  224. package/dist/core/project-layout.d.ts +9 -17
  225. package/dist/core/project-layout.d.ts.map +1 -1
  226. package/dist/core/project-layout.js +16 -26
  227. package/dist/core/project-layout.js.map +1 -1
  228. package/dist/core/root-selection.d.ts +11 -7
  229. package/dist/core/root-selection.d.ts.map +1 -1
  230. package/dist/core/root-selection.js +7 -8
  231. package/dist/core/root-selection.js.map +1 -1
  232. package/dist/core/rules.d.ts +6 -1
  233. package/dist/core/rules.d.ts.map +1 -1
  234. package/dist/core/rules.js +23 -2
  235. package/dist/core/rules.js.map +1 -1
  236. package/dist/core/schema-names.d.ts +16 -0
  237. package/dist/core/schema-names.d.ts.map +1 -0
  238. package/dist/core/schema-names.js +16 -0
  239. package/dist/core/schema-names.js.map +1 -0
  240. package/dist/core/schemas/base.schema.d.ts +3 -0
  241. package/dist/core/schemas/base.schema.d.ts.map +1 -1
  242. package/dist/core/schemas/base.schema.js +22 -6
  243. package/dist/core/schemas/base.schema.js.map +1 -1
  244. package/dist/core/schemas/change.schema.d.ts +16 -0
  245. package/dist/core/schemas/change.schema.d.ts.map +1 -1
  246. package/dist/core/schemas/change.schema.js +41 -10
  247. package/dist/core/schemas/change.schema.js.map +1 -1
  248. package/dist/core/schemas/spec.schema.d.ts +2 -0
  249. package/dist/core/schemas/spec.schema.d.ts.map +1 -1
  250. package/dist/core/shared/index.d.ts +3 -8
  251. package/dist/core/shared/index.d.ts.map +1 -1
  252. package/dist/core/shared/index.js +3 -8
  253. package/dist/core/shared/index.js.map +1 -1
  254. package/dist/core/shared/rules-generation.d.ts +19 -8
  255. package/dist/core/shared/rules-generation.d.ts.map +1 -1
  256. package/dist/core/shared/rules-generation.js +117 -50
  257. package/dist/core/shared/rules-generation.js.map +1 -1
  258. package/dist/core/shared/skill-generation.d.ts +28 -43
  259. package/dist/core/shared/skill-generation.d.ts.map +1 -1
  260. package/dist/core/shared/skill-generation.js +82 -51
  261. package/dist/core/shared/skill-generation.js.map +1 -1
  262. package/dist/core/shared/tool-detection.d.ts +39 -61
  263. package/dist/core/shared/tool-detection.d.ts.map +1 -1
  264. package/dist/core/shared/tool-detection.js +88 -80
  265. package/dist/core/shared/tool-detection.js.map +1 -1
  266. package/dist/core/skill-metrics.d.ts +36 -63
  267. package/dist/core/skill-metrics.d.ts.map +1 -1
  268. package/dist/core/skill-metrics.js +34 -73
  269. package/dist/core/skill-metrics.js.map +1 -1
  270. package/dist/core/spec-presenter.js +6 -6
  271. package/dist/core/spec-presenter.js.map +1 -1
  272. package/dist/core/specs-apply.d.ts +22 -23
  273. package/dist/core/specs-apply.d.ts.map +1 -1
  274. package/dist/core/specs-apply.js +166 -193
  275. package/dist/core/specs-apply.js.map +1 -1
  276. package/dist/core/templates/fragments/interview.d.ts +2 -6
  277. package/dist/core/templates/fragments/interview.d.ts.map +1 -1
  278. package/dist/core/templates/fragments/interview.js +2 -6
  279. package/dist/core/templates/fragments/interview.js.map +1 -1
  280. package/dist/core/templates/fragments/next-step.d.ts +4 -8
  281. package/dist/core/templates/fragments/next-step.d.ts.map +1 -1
  282. package/dist/core/templates/fragments/next-step.js +4 -8
  283. package/dist/core/templates/fragments/next-step.js.map +1 -1
  284. package/dist/core/templates/fragments/validate.d.ts +13 -0
  285. package/dist/core/templates/fragments/validate.d.ts.map +1 -0
  286. package/dist/core/templates/fragments/validate.js +13 -0
  287. package/dist/core/templates/fragments/validate.js.map +1 -0
  288. package/dist/core/templates/fragments/verify.d.ts +9 -12
  289. package/dist/core/templates/fragments/verify.d.ts.map +1 -1
  290. package/dist/core/templates/fragments/verify.js +9 -12
  291. package/dist/core/templates/fragments/verify.js.map +1 -1
  292. package/dist/core/templates/index.d.ts +0 -6
  293. package/dist/core/templates/index.d.ts.map +1 -1
  294. package/dist/core/templates/index.js +0 -7
  295. package/dist/core/templates/index.js.map +1 -1
  296. package/dist/core/templates/skill-templates.d.ts +1 -5
  297. package/dist/core/templates/skill-templates.d.ts.map +1 -1
  298. package/dist/core/templates/skill-templates.js +0 -5
  299. package/dist/core/templates/skill-templates.js.map +1 -1
  300. package/dist/core/templates/types.d.ts +3 -7
  301. package/dist/core/templates/types.d.ts.map +1 -1
  302. package/dist/core/templates/types.js +0 -3
  303. package/dist/core/templates/types.js.map +1 -1
  304. package/dist/core/templates/workflows/apply.d.ts +3 -9
  305. package/dist/core/templates/workflows/apply.d.ts.map +1 -1
  306. package/dist/core/templates/workflows/apply.js +11 -13
  307. package/dist/core/templates/workflows/apply.js.map +1 -1
  308. package/dist/core/templates/workflows/archive.d.ts +0 -6
  309. package/dist/core/templates/workflows/archive.d.ts.map +1 -1
  310. package/dist/core/templates/workflows/archive.js +19 -6
  311. package/dist/core/templates/workflows/archive.js.map +1 -1
  312. package/dist/core/templates/workflows/decision.js +4 -4
  313. package/dist/core/templates/workflows/decision.js.map +1 -1
  314. package/dist/core/templates/workflows/explore.js +1 -1
  315. package/dist/core/templates/workflows/grill.d.ts.map +1 -1
  316. package/dist/core/templates/workflows/grill.js +0 -2
  317. package/dist/core/templates/workflows/grill.js.map +1 -1
  318. package/dist/core/templates/workflows/issue.d.ts +0 -6
  319. package/dist/core/templates/workflows/issue.d.ts.map +1 -1
  320. package/dist/core/templates/workflows/issue.js +3 -2
  321. package/dist/core/templates/workflows/issue.js.map +1 -1
  322. package/dist/core/templates/workflows/propose.d.ts +0 -6
  323. package/dist/core/templates/workflows/propose.d.ts.map +1 -1
  324. package/dist/core/templates/workflows/propose.js +2 -2
  325. package/dist/core/templates/workflows/propose.js.map +1 -1
  326. package/dist/core/templates/workflows/sync.d.ts +2 -8
  327. package/dist/core/templates/workflows/sync.d.ts.map +1 -1
  328. package/dist/core/templates/workflows/sync.js +4 -3
  329. package/dist/core/templates/workflows/sync.js.map +1 -1
  330. package/dist/core/templates/workflows/update.d.ts +0 -6
  331. package/dist/core/templates/workflows/update.d.ts.map +1 -1
  332. package/dist/core/templates/workflows/update.js +9 -2
  333. package/dist/core/templates/workflows/update.js.map +1 -1
  334. package/dist/core/update.d.ts +23 -23
  335. package/dist/core/update.d.ts.map +1 -1
  336. package/dist/core/update.js +139 -118
  337. package/dist/core/update.js.map +1 -1
  338. package/dist/core/user-state-migration.d.ts +13 -15
  339. package/dist/core/user-state-migration.d.ts.map +1 -1
  340. package/dist/core/user-state-migration.js +16 -20
  341. package/dist/core/user-state-migration.js.map +1 -1
  342. package/dist/core/validation/constants.d.ts +4 -10
  343. package/dist/core/validation/constants.d.ts.map +1 -1
  344. package/dist/core/validation/constants.js +25 -20
  345. package/dist/core/validation/constants.js.map +1 -1
  346. package/dist/core/validation/prose-length.d.ts +15 -0
  347. package/dist/core/validation/prose-length.d.ts.map +1 -0
  348. package/dist/core/validation/prose-length.js +29 -0
  349. package/dist/core/validation/prose-length.js.map +1 -0
  350. package/dist/core/validation/purpose-placeholder.d.ts +9 -16
  351. package/dist/core/validation/purpose-placeholder.d.ts.map +1 -1
  352. package/dist/core/validation/purpose-placeholder.js +30 -44
  353. package/dist/core/validation/purpose-placeholder.js.map +1 -1
  354. package/dist/core/validation/section-validator.d.ts +4 -4
  355. package/dist/core/validation/section-validator.d.ts.map +1 -1
  356. package/dist/core/validation/section-validator.js +43 -7
  357. package/dist/core/validation/section-validator.js.map +1 -1
  358. package/dist/core/validation/task-numbering.d.ts +6 -3
  359. package/dist/core/validation/task-numbering.d.ts.map +1 -1
  360. package/dist/core/validation/task-numbering.js +23 -11
  361. package/dist/core/validation/task-numbering.js.map +1 -1
  362. package/dist/core/validation/types.d.ts +18 -0
  363. package/dist/core/validation/types.d.ts.map +1 -1
  364. package/dist/core/validation/types.js +12 -1
  365. package/dist/core/validation/types.js.map +1 -1
  366. package/dist/core/validation/validator.d.ts +43 -63
  367. package/dist/core/validation/validator.d.ts.map +1 -1
  368. package/dist/core/validation/validator.js +500 -267
  369. package/dist/core/validation/validator.js.map +1 -1
  370. package/dist/prompts/searchable-multi-select.d.ts +3 -8
  371. package/dist/prompts/searchable-multi-select.d.ts.map +1 -1
  372. package/dist/prompts/searchable-multi-select.js +16 -39
  373. package/dist/prompts/searchable-multi-select.js.map +1 -1
  374. package/dist/utils/change-metadata.d.ts +11 -50
  375. package/dist/utils/change-metadata.d.ts.map +1 -1
  376. package/dist/utils/change-metadata.js +48 -67
  377. package/dist/utils/change-metadata.js.map +1 -1
  378. package/dist/utils/change-utils.d.ts +30 -54
  379. package/dist/utils/change-utils.d.ts.map +1 -1
  380. package/dist/utils/change-utils.js +133 -91
  381. package/dist/utils/change-utils.js.map +1 -1
  382. package/dist/utils/file-lock.d.ts +39 -0
  383. package/dist/utils/file-lock.d.ts.map +1 -0
  384. package/dist/utils/file-lock.js +149 -0
  385. package/dist/utils/file-lock.js.map +1 -0
  386. package/dist/utils/file-system.d.ts +12 -32
  387. package/dist/utils/file-system.d.ts.map +1 -1
  388. package/dist/utils/file-system.js +16 -40
  389. package/dist/utils/file-system.js.map +1 -1
  390. package/dist/utils/frontmatter.d.ts +7 -11
  391. package/dist/utils/frontmatter.d.ts.map +1 -1
  392. package/dist/utils/frontmatter.js +11 -11
  393. package/dist/utils/frontmatter.js.map +1 -1
  394. package/dist/utils/interactive.d.ts +4 -9
  395. package/dist/utils/interactive.d.ts.map +1 -1
  396. package/dist/utils/interactive.js +2 -4
  397. package/dist/utils/interactive.js.map +1 -1
  398. package/dist/utils/item-discovery.d.ts +15 -10
  399. package/dist/utils/item-discovery.d.ts.map +1 -1
  400. package/dist/utils/item-discovery.js +42 -47
  401. package/dist/utils/item-discovery.js.map +1 -1
  402. package/dist/utils/link.d.ts +9 -18
  403. package/dist/utils/link.d.ts.map +1 -1
  404. package/dist/utils/link.js +9 -18
  405. package/dist/utils/link.js.map +1 -1
  406. package/dist/utils/requirement-diff.d.ts +13 -23
  407. package/dist/utils/requirement-diff.d.ts.map +1 -1
  408. package/dist/utils/requirement-diff.js +13 -23
  409. package/dist/utils/requirement-diff.js.map +1 -1
  410. package/dist/utils/spec-files.d.ts +7 -20
  411. package/dist/utils/spec-files.d.ts.map +1 -1
  412. package/dist/utils/spec-files.js +26 -51
  413. package/dist/utils/spec-files.js.map +1 -1
  414. package/dist/utils/task-progress.d.ts +11 -9
  415. package/dist/utils/task-progress.d.ts.map +1 -1
  416. package/dist/utils/task-progress.js +53 -32
  417. package/dist/utils/task-progress.js.map +1 -1
  418. package/dist/utils/timestamp.d.ts +5 -8
  419. package/dist/utils/timestamp.d.ts.map +1 -1
  420. package/dist/utils/timestamp.js +5 -8
  421. package/dist/utils/timestamp.js.map +1 -1
  422. package/package.json +2 -3
  423. package/schemas/decision/templates/decision.md +3 -1
  424. package/schemas/decision/templates/index.md +2 -2
  425. package/schemas/issue/schema.yaml +8 -1
  426. package/schemas/issue/templates/spec.md +27 -2
  427. package/schemas/sdd/schema.yaml +20 -1
  428. package/schemas/sdd/templates/spec.md +27 -2
  429. /package/assets/rules/tospec/{single-sourc-of-truth.md → single-source-of-truth.md} +0 -0
@@ -0,0 +1,149 @@
1
+ /**
2
+ * A cross-process advisory lock for read-compute-write sequences.
3
+ *
4
+ * `tospec archive` is one: it reads every target spec, merges in memory, then
5
+ * writes. Two overlapping archives both read the pre-merge text, so the second
6
+ * write erases the first one's requirement while both report success — measured
7
+ * at roughly one in five overlapping pairs.
8
+ *
9
+ * Advisory, not mandatory: it stops two of *our* merges from interleaving, not
10
+ * arbitrary writers.
11
+ */
12
+ import { promises as fs } from 'node:fs';
13
+ import * as os from 'node:os';
14
+ import * as path from 'node:path';
15
+ /**
16
+ * Two independent expiries. `timeoutMs` bounds how long *we* wait and is short,
17
+ * because waiting a minute on a few file reads means something is wrong, not
18
+ * busy. `staleMs` bounds how long a lock survives its holder and is long,
19
+ * because expiring it on an alive-but-slow holder hands the lock to a second
20
+ * writer — the exact failure being prevented.
21
+ */
22
+ const DEFAULT_TIMEOUT_MS = 30_000;
23
+ const DEFAULT_STALE_MS = 10 * 60_000;
24
+ const RETRY_INTERVAL_MS = 100;
25
+ /**
26
+ * How long an unreadable lock is left alone before it counts as abandoned.
27
+ *
28
+ * `open(…, 'wx')` creates the file before the record is written, so a held lock
29
+ * is briefly an *empty* file. Without this grace a waiter reads that emptiness
30
+ * as "no record", deletes the lock and takes it, and both processes hold it. The
31
+ * holder fills the file in microseconds, and a second is still short enough that
32
+ * a genuinely corrupt lock clears on the next run.
33
+ */
34
+ const UNREADABLE_GRACE_MS = 1_000;
35
+ export class LockTimeoutError extends Error {
36
+ holder;
37
+ constructor(message, holder) {
38
+ super(message);
39
+ this.holder = holder;
40
+ this.name = 'LockTimeoutError';
41
+ }
42
+ }
43
+ /** Whether a pid is a live process on this machine. */
44
+ function isAlive(pid) {
45
+ try {
46
+ // Signal 0 probes without delivering anything; EPERM means it exists and
47
+ // belongs to someone else, so still alive.
48
+ process.kill(pid, 0);
49
+ return true;
50
+ }
51
+ catch (err) {
52
+ return err.code === 'EPERM';
53
+ }
54
+ }
55
+ async function readRecord(lockPath) {
56
+ try {
57
+ return JSON.parse(await fs.readFile(lockPath, 'utf-8'));
58
+ }
59
+ catch {
60
+ // Unreadable, or read in the gap between the exclusive create and the
61
+ // record write, so the caller waits UNREADABLE_GRACE_MS before judging it.
62
+ return null;
63
+ }
64
+ }
65
+ /**
66
+ * True when the lock on disk should be taken over: older than `staleMs`, or its
67
+ * holder is gone. Pids are only meaningful locally, so a foreign host's lock is
68
+ * judged purely by age. An unreadable record is never stale on sight — the
69
+ * caller decides that, after UNREADABLE_GRACE_MS.
70
+ */
71
+ function isStale(record, staleMs) {
72
+ if (!record)
73
+ return false;
74
+ const age = Date.now() - Date.parse(record.startedAt);
75
+ if (Number.isFinite(age) && age > staleMs)
76
+ return true;
77
+ if (record.host !== os.hostname())
78
+ return false;
79
+ return !isAlive(record.pid);
80
+ }
81
+ /**
82
+ * Runs `fn` while holding an exclusive lock at `lockPath`. Released in a
83
+ * `finally`, so a throwing `fn` leaves nothing behind; a killed process is
84
+ * covered by the staleness rules above.
85
+ */
86
+ export async function withFileLock(lockPath, fn, options = {}) {
87
+ const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
88
+ const staleMs = options.staleMs ?? DEFAULT_STALE_MS;
89
+ const record = {
90
+ pid: process.pid,
91
+ host: os.hostname(),
92
+ startedAt: new Date().toISOString(),
93
+ operation: options.operation ?? 'operation',
94
+ };
95
+ await fs.mkdir(path.dirname(lockPath), { recursive: true });
96
+ const deadline = Date.now() + timeoutMs;
97
+ /** When the lock first read as unreadable, or null while it reads cleanly. */
98
+ let unreadableSince = null;
99
+ for (;;) {
100
+ try {
101
+ // 'wx' is the whole mechanism: create-or-EEXIST in one syscall, so two
102
+ // processes cannot both believe they created it.
103
+ const handle = await fs.open(lockPath, 'wx');
104
+ try {
105
+ await handle.writeFile(JSON.stringify(record), 'utf-8');
106
+ }
107
+ finally {
108
+ await handle.close();
109
+ }
110
+ break;
111
+ }
112
+ catch (err) {
113
+ if (err.code !== 'EEXIST')
114
+ throw err;
115
+ const holder = await readRecord(lockPath);
116
+ // Only a lock that stays unreadable past the grace period is abandoned
117
+ // rather than mid-creation.
118
+ if (holder === null)
119
+ unreadableSince ??= Date.now();
120
+ else
121
+ unreadableSince = null;
122
+ const graceExpired = unreadableSince !== null && Date.now() - unreadableSince >= UNREADABLE_GRACE_MS;
123
+ if (isStale(holder, staleMs) || graceExpired) {
124
+ // Unlink and loop rather than write over it: the create-exclusive retry
125
+ // decides the winner when two waiters both judge it stale.
126
+ await fs.rm(lockPath, { force: true });
127
+ unreadableSince = null;
128
+ continue;
129
+ }
130
+ // Before the sleep, so a `timeoutMs` shorter than the grace period is
131
+ // still honoured.
132
+ if (Date.now() >= deadline) {
133
+ const held = holder
134
+ ? `held by pid ${holder.pid} on ${holder.host} since ${holder.startedAt} (${holder.operation})`
135
+ : 'held by an unidentified process';
136
+ throw new LockTimeoutError(`Timed out after ${Math.round(timeoutMs / 1000)}s waiting for the lock at ${lockPath}, ${held}. ` +
137
+ 'Another tospec process is probably still running; if none is, delete that file and retry.', holder);
138
+ }
139
+ await new Promise((resolve) => setTimeout(resolve, RETRY_INTERVAL_MS));
140
+ }
141
+ }
142
+ try {
143
+ return await fn();
144
+ }
145
+ finally {
146
+ await fs.rm(lockPath, { force: true });
147
+ }
148
+ }
149
+ //# sourceMappingURL=file-lock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-lock.js","sourceRoot":"","sources":["../../src/utils/file-lock.ts"],"names":[],"mappings":"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"}
@@ -1,10 +1,7 @@
1
1
  /**
2
- * Most-recent mtime of any file under `dirPath` (recursive), falling back to
3
- * the directory's own mtime when it holds no files.
4
- *
5
- * Shared by `tospec list --sort recent` and the dashboard so both rank changes
6
- * by the same clock; they used to walk separately and could disagree.
7
- * ponytail: recursive walk; fine at repo scale (dozens of changes).
2
+ * Most-recent mtime of any file under `dirPath`, falling back to the directory's
3
+ * own mtime when it holds none. Shared by `tospec list --sort recent` and the
4
+ * dashboard so both rank changes by the same clock.
8
5
  */
9
6
  export declare function getLastModified(dirPath: string): Promise<Date>;
10
7
  /**
@@ -17,39 +14,22 @@ export declare function getLastModified(dirPath: string): Promise<Date>;
17
14
  export declare function extractNameFromPath(filePath: string): string;
18
15
  /**
19
16
  * Whether a failed read of a *targeted path* means it is not there, as opposed
20
- * to being there and unusable.
21
- *
22
- * `ENOENT` is the file itself; `ENOTDIR` is a parent component that is a file,
23
- * which makes the path unreachable for the same reason. Everything else —
24
- * `EACCES`, `EISDIR`, `EIO`, `EPERM` — describes a path that exists and could not
25
- * be read, and callers that treat those as absence state a conclusion the read
26
- * never reached.
27
- *
28
- * Use this when "there is nothing at this path yet" is a legitimate outcome for
29
- * a specific file. For enumerating a directory, use `isAbsentDirectoryError` —
30
- * the two differ on `ENOTDIR` and the difference is load-bearing.
17
+ * to being there and unusable. `ENOTDIR` counts because a parent component that
18
+ * is a file makes the path unreachable for the same reason;
19
+ * `EACCES`/`EISDIR`/`EIO` describe a path that exists. For enumerating a
20
+ * directory use `isAbsentDirectoryError`: the two differ on `ENOTDIR`.
31
21
  */
32
22
  export declare function isMissingPathError(error: unknown): boolean;
33
23
  /**
34
- * Whether a failed directory enumeration means the directory is not there.
35
- *
36
- * Deliberately narrower than `isMissingPathError`: `ENOTDIR` from a `readdir`
37
- * means something that is not a directory occupies the path, and answering
38
- * "empty" for that is how a broken layout comes to look like an absent one. For
39
- * a targeted read the same code means the parent is unreachable, which is
40
- * genuine absence — hence two predicates rather than one plus an exception.
24
+ * Narrower than `isMissingPathError`: `ENOTDIR` from a `readdir` means a
25
+ * non-directory occupies the path, and answering "empty" makes a broken layout
26
+ * look like an absent one.
41
27
  */
42
28
  export declare function isAbsentDirectoryError(error: unknown): boolean;
43
29
  export declare class FileSystemUtils {
44
- /**
45
- * Converts a path to use forward slashes (POSIX style).
46
- * Essential for cross-platform compatibility with glob libraries like fast-glob.
47
- */
30
+ /** fast-glob and friends only accept forward slashes. */
48
31
  static toPosixPath(p: string): string;
49
- /**
50
- * Returns a canonical absolute path when the target exists.
51
- * Falls back to path.resolve() so callers can still produce a stable absolute path.
52
- */
32
+ /** Falls back to path.resolve() when the target does not exist. */
53
33
  static canonicalizeExistingPath(targetPath: string): string;
54
34
  private static isWindowsBasePath;
55
35
  private static normalizeSegments;
@@ -1 +1 @@
1
- {"version":3,"file":"file-system.d.ts","sourceRoot":"","sources":["../../src/utils/file-system.ts"],"names":[],"mappings":"AAKA;;;;;;;GAOG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAsBpE;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAY5D;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAG1D;AAED;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAE9D;AAED,qBAAa,eAAe;IAC1B;;;OAGG;IACH,MAAM,CAAC,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEpC;IAED;;;OAGG;IACH,MAAM,CAAC,wBAAwB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAW1D;IAED,OAAO,CAAC,MAAM,CAAC,iBAAiB;IAIhC,OAAO,CAAC,MAAM,CAAC,iBAAiB;IAMhC,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAe/D;IAED,OAAa,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE3D;IAED,OAAa,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAU1D;IAED,OAAa,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAU9D;IAED,OAAa,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAIvE;IAED,OAAa,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAEvD;IAED,OAAa,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAqCrE;CACF"}
1
+ {"version":3,"file":"file-system.d.ts","sourceRoot":"","sources":["../../src/utils/file-system.ts"],"names":[],"mappings":"AAKA;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAsBpE;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAY5D;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAG1D;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAE9D;AAED,qBAAa,eAAe;IAC1B,yDAAyD;IACzD,MAAM,CAAC,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEpC;IAED,mEAAmE;IACnE,MAAM,CAAC,wBAAwB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAW1D;IAED,OAAO,CAAC,MAAM,CAAC,iBAAiB;IAIhC,OAAO,CAAC,MAAM,CAAC,iBAAiB;IAMhC,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAe/D;IAED,OAAa,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE3D;IAED,OAAa,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAU1D;IAED,OAAa,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAU9D;IAED,OAAa,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAIvE;IAED,OAAa,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAEvD;IAED,OAAa,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAiCrE;CACF"}
@@ -2,19 +2,16 @@ import * as nodeFs from 'fs';
2
2
  import path from 'path';
3
3
  const fs = nodeFs.promises;
4
4
  /**
5
- * Most-recent mtime of any file under `dirPath` (recursive), falling back to
6
- * the directory's own mtime when it holds no files.
7
- *
8
- * Shared by `tospec list --sort recent` and the dashboard so both rank changes
9
- * by the same clock; they used to walk separately and could disagree.
10
- * ponytail: recursive walk; fine at repo scale (dozens of changes).
5
+ * Most-recent mtime of any file under `dirPath`, falling back to the directory's
6
+ * own mtime when it holds none. Shared by `tospec list --sort recent` and the
7
+ * dashboard so both rank changes by the same clock.
11
8
  */
12
9
  export async function getLastModified(dirPath) {
13
10
  let latest = null;
14
11
  async function walk(dir) {
15
12
  const entries = await fs.readdir(dir, { withFileTypes: true });
16
13
  // Entries are independent and `latest` is an order-insensitive max, so the
17
- // stats fan out instead of running one await at a time.
14
+ // stats fan out rather than running one await at a time.
18
15
  await Promise.all(entries.map(async (entry) => {
19
16
  const full = path.join(dir, entry.name);
20
17
  if (entry.isDirectory()) {
@@ -49,49 +46,32 @@ export function extractNameFromPath(filePath) {
49
46
  }
50
47
  /**
51
48
  * Whether a failed read of a *targeted path* means it is not there, as opposed
52
- * to being there and unusable.
53
- *
54
- * `ENOENT` is the file itself; `ENOTDIR` is a parent component that is a file,
55
- * which makes the path unreachable for the same reason. Everything else —
56
- * `EACCES`, `EISDIR`, `EIO`, `EPERM` — describes a path that exists and could not
57
- * be read, and callers that treat those as absence state a conclusion the read
58
- * never reached.
59
- *
60
- * Use this when "there is nothing at this path yet" is a legitimate outcome for
61
- * a specific file. For enumerating a directory, use `isAbsentDirectoryError` —
62
- * the two differ on `ENOTDIR` and the difference is load-bearing.
49
+ * to being there and unusable. `ENOTDIR` counts because a parent component that
50
+ * is a file makes the path unreachable for the same reason;
51
+ * `EACCES`/`EISDIR`/`EIO` describe a path that exists. For enumerating a
52
+ * directory use `isAbsentDirectoryError`: the two differ on `ENOTDIR`.
63
53
  */
64
54
  export function isMissingPathError(error) {
65
55
  const code = error?.code;
66
56
  return code === 'ENOENT' || code === 'ENOTDIR';
67
57
  }
68
58
  /**
69
- * Whether a failed directory enumeration means the directory is not there.
70
- *
71
- * Deliberately narrower than `isMissingPathError`: `ENOTDIR` from a `readdir`
72
- * means something that is not a directory occupies the path, and answering
73
- * "empty" for that is how a broken layout comes to look like an absent one. For
74
- * a targeted read the same code means the parent is unreachable, which is
75
- * genuine absence — hence two predicates rather than one plus an exception.
59
+ * Narrower than `isMissingPathError`: `ENOTDIR` from a `readdir` means a
60
+ * non-directory occupies the path, and answering "empty" makes a broken layout
61
+ * look like an absent one.
76
62
  */
77
63
  export function isAbsentDirectoryError(error) {
78
64
  return error?.code === 'ENOENT';
79
65
  }
80
66
  export class FileSystemUtils {
81
- /**
82
- * Converts a path to use forward slashes (POSIX style).
83
- * Essential for cross-platform compatibility with glob libraries like fast-glob.
84
- */
67
+ /** fast-glob and friends only accept forward slashes. */
85
68
  static toPosixPath(p) {
86
69
  return p.replace(/\\/g, '/');
87
70
  }
88
- /**
89
- * Returns a canonical absolute path when the target exists.
90
- * Falls back to path.resolve() so callers can still produce a stable absolute path.
91
- */
71
+ /** Falls back to path.resolve() when the target does not exist. */
92
72
  static canonicalizeExistingPath(targetPath) {
93
73
  try {
94
- // Prefer the native resolver so Windows short-path aliases are expanded.
74
+ // The native resolver expands Windows short-path aliases.
95
75
  return nodeFs.realpathSync.native(targetPath);
96
76
  }
97
77
  catch {
@@ -161,7 +141,6 @@ export class FileSystemUtils {
161
141
  }
162
142
  static async ensureWritePermissions(dirPath) {
163
143
  try {
164
- // If directory doesn't exist, check parent directory permissions
165
144
  if (!await this.directoryExists(dirPath)) {
166
145
  const parentDir = path.dirname(dirPath);
167
146
  if (!await this.directoryExists(parentDir)) {
@@ -171,8 +150,7 @@ export class FileSystemUtils {
171
150
  }
172
151
  const testFile = path.join(dirPath, '.tospec-test-' + Date.now() + '-' + Math.random().toString(36).slice(2));
173
152
  await fs.writeFile(testFile, '');
174
- // On Windows, file may be temporarily locked by antivirus or indexing services.
175
- // Retry unlink with a small delay if it fails.
153
+ // On Windows the file may be briefly locked by antivirus or indexing.
176
154
  const maxRetries = 3;
177
155
  for (let attempt = 0; attempt < maxRetries; attempt++) {
178
156
  try {
@@ -181,12 +159,10 @@ export class FileSystemUtils {
181
159
  }
182
160
  catch (unlinkError) {
183
161
  if (attempt === maxRetries - 1) {
184
- // Last attempt failed, but we successfully wrote the file, so permissions are OK
185
- // Just log and continue - the temp file will be cleaned up eventually
162
+ // The write succeeded, so permissions are fine; only cleanup failed.
186
163
  console.debug(`Could not clean up test file ${testFile}: ${unlinkError.message}`);
187
164
  }
188
165
  else {
189
- // Wait briefly before retrying (Windows file lock release)
190
166
  await new Promise((resolve) => setTimeout(resolve, 50));
191
167
  }
192
168
  }
@@ -1 +1 @@
1
- {"version":3,"file":"file-system.js","sourceRoot":"","sources":["../../src/utils/file-system.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"file-system.js","sourceRoot":"","sources":["../../src/utils/file-system.ts"],"names":[],"mappings":"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"}
@@ -1,22 +1,18 @@
1
1
  /**
2
- * Splits `---`-delimited yaml frontmatter from the markdown body.
2
+ * The single reader for ticket/change frontmatter, so the dashboard,
3
+ * `tospec show` and archive agree on which ticket belongs to which change.
3
4
  *
4
- * The single reader for ticket/change frontmatter: the dashboard, `tospec show`
5
- * and archive must agree on which ticket belongs to which change, so the
6
- * delimiter scan lives in one place rather than once per caller.
7
- *
8
- * Malformed yaml *throws* — the dashboard reports it per ticket as a
9
- * `parseError` rather than silently showing a ticket with no metadata. Callers
10
- * that would rather degrade than fail should use `frontmatterString`.
5
+ * Malformed yaml *throws*, so the dashboard can report it per ticket as a
6
+ * `parseError` instead of showing a ticket with no metadata. Callers that would
7
+ * rather degrade than fail should use `frontmatterString`.
11
8
  */
12
9
  export declare function splitFrontmatter(content: string): {
13
10
  data: Record<string, unknown>;
14
11
  body: string;
15
12
  };
16
13
  /**
17
- * Reads a string field from a document's frontmatter, or null when the field is
18
- * absent, non-string, or the frontmatter does not parse. For display and
19
- * lookup paths, where a broken header should fall back rather than fail.
14
+ * Null when the field is absent, non-string, or the frontmatter does not parse —
15
+ * for display and lookup paths, where a broken header should degrade, not fail.
20
16
  */
21
17
  export declare function frontmatterString(content: string, field: string): string | null;
22
18
  //# sourceMappingURL=frontmatter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"frontmatter.d.ts","sourceRoot":"","sources":["../../src/utils/frontmatter.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG;IACjD,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,IAAI,EAAE,MAAM,CAAC;CACd,CAUA;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAO/E"}
1
+ {"version":3,"file":"frontmatter.d.ts","sourceRoot":"","sources":["../../src/utils/frontmatter.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG;IACjD,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,IAAI,EAAE,MAAM,CAAC;CACd,CAaA;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAO/E"}
@@ -1,16 +1,17 @@
1
1
  import { parse as parseYaml } from 'yaml';
2
+ import { stripBom } from '../core/parsers/requirement-text.js';
2
3
  /**
3
- * Splits `---`-delimited yaml frontmatter from the markdown body.
4
+ * The single reader for ticket/change frontmatter, so the dashboard,
5
+ * `tospec show` and archive agree on which ticket belongs to which change.
4
6
  *
5
- * The single reader for ticket/change frontmatter: the dashboard, `tospec show`
6
- * and archive must agree on which ticket belongs to which change, so the
7
- * delimiter scan lives in one place rather than once per caller.
8
- *
9
- * Malformed yaml *throws* — the dashboard reports it per ticket as a
10
- * `parseError` rather than silently showing a ticket with no metadata. Callers
11
- * that would rather degrade than fail should use `frontmatterString`.
7
+ * Malformed yaml *throws*, so the dashboard can report it per ticket as a
8
+ * `parseError` instead of showing a ticket with no metadata. Callers that would
9
+ * rather degrade than fail should use `frontmatterString`.
12
10
  */
13
11
  export function splitFrontmatter(content) {
12
+ // A leading BOM fails the `---` test below and hands back empty `data`, which
13
+ // reads as "this ticket has no frontmatter" with nothing reporting a problem.
14
+ content = stripBom(content);
14
15
  if (!content.startsWith('---'))
15
16
  return { data: {}, body: content };
16
17
  const end = content.indexOf('\n---', 3);
@@ -23,9 +24,8 @@ export function splitFrontmatter(content) {
23
24
  return { data, body };
24
25
  }
25
26
  /**
26
- * Reads a string field from a document's frontmatter, or null when the field is
27
- * absent, non-string, or the frontmatter does not parse. For display and
28
- * lookup paths, where a broken header should fall back rather than fail.
27
+ * Null when the field is absent, non-string, or the frontmatter does not parse —
28
+ * for display and lookup paths, where a broken header should degrade, not fail.
29
29
  */
30
30
  export function frontmatterString(content, field) {
31
31
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"frontmatter.js","sourceRoot":"","sources":["../../src/utils/frontmatter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAE1C;;;;;;;;;;GAUG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAe;IAI9C,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IACnE,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IACxC,IAAI,GAAG,KAAK,CAAC,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IAEnD,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;IAChD,MAAM,IAAI,GAAG,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAE,MAAkC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7F,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC;IAClD,MAAM,IAAI,GAAG,UAAU,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC;IACpE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AACxB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAe,EAAE,KAAa;IAC9D,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACpD,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;IAClD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"frontmatter.js","sourceRoot":"","sources":["../../src/utils/frontmatter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,qCAAqC,CAAC;AAE/D;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAe;IAI9C,8EAA8E;IAC9E,8EAA8E;IAC9E,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC5B,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IACnE,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IACxC,IAAI,GAAG,KAAK,CAAC,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IAEnD,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;IAChD,MAAM,IAAI,GAAG,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAE,MAAkC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7F,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC;IAClD,MAAM,IAAI,GAAG,UAAU,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC;IACpE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AACxB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAe,EAAE,KAAa;IAC9D,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACpD,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;IAClD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -1,17 +1,12 @@
1
1
  export type InteractiveOptions = {
2
- /**
3
- * Explicit "disable prompts" flag passed by internal callers.
4
- */
2
+ /** Explicit "disable prompts" flag passed by internal callers. */
5
3
  noInteractive?: boolean;
6
- /**
7
- * Commander-style negated option: `--no-interactive` sets this to false.
8
- */
4
+ /** Commander-style negated option: `--no-interactive` sets this to false. */
9
5
  interactive?: boolean;
10
6
  };
11
7
  /**
12
- * Resolves whether non-interactive mode is requested.
13
- * Handles both explicit `noInteractive: true` and Commander.js style `interactive: false`.
14
- * Use this helper instead of manually checking options.noInteractive to avoid bugs.
8
+ * The one reader of both spellings. Checking `options.noInteractive` by hand misses
9
+ * commander's `interactive: false`.
15
10
  */
16
11
  export declare function resolveNoInteractive(value?: boolean | InteractiveOptions): boolean;
17
12
  export declare function isInteractive(value?: boolean | InteractiveOptions): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"interactive.d.ts","sourceRoot":"","sources":["../../src/utils/interactive.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,kBAAkB,GAAG;IAC/B;;OAEG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;OAEG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,CAAC,EAAE,OAAO,GAAG,kBAAkB,GAAG,OAAO,CAGlF;AAED,wBAAgB,aAAa,CAAC,KAAK,CAAC,EAAE,OAAO,GAAG,kBAAkB,GAAG,OAAO,CAM3E"}
1
+ {"version":3,"file":"interactive.d.ts","sourceRoot":"","sources":["../../src/utils/interactive.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,kBAAkB,GAAG;IAC/B,kEAAkE;IAClE,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,6EAA6E;IAC7E,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,CAAC,EAAE,OAAO,GAAG,kBAAkB,GAAG,OAAO,CAGlF;AAED,wBAAgB,aAAa,CAAC,KAAK,CAAC,EAAE,OAAO,GAAG,kBAAkB,GAAG,OAAO,CAK3E"}
@@ -1,7 +1,6 @@
1
1
  /**
2
- * Resolves whether non-interactive mode is requested.
3
- * Handles both explicit `noInteractive: true` and Commander.js style `interactive: false`.
4
- * Use this helper instead of manually checking options.noInteractive to avoid bugs.
2
+ * The one reader of both spellings. Checking `options.noInteractive` by hand misses
3
+ * commander's `interactive: false`.
5
4
  */
6
5
  export function resolveNoInteractive(value) {
7
6
  if (typeof value === 'boolean')
@@ -13,7 +12,6 @@ export function isInteractive(value) {
13
12
  return false;
14
13
  if (process.env.OPEN_SPEC_INTERACTIVE === '0')
15
14
  return false;
16
- // Respect the standard CI environment variable (set by GitHub Actions, GitLab CI, Travis, etc.)
17
15
  if ('CI' in process.env)
18
16
  return false;
19
17
  return !!process.stdin.isTTY;
@@ -1 +1 @@
1
- {"version":3,"file":"interactive.js","sourceRoot":"","sources":["../../src/utils/interactive.ts"],"names":[],"mappings":"AAWA;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,KAAoC;IACvE,IAAI,OAAO,KAAK,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IAC7C,OAAO,KAAK,EAAE,aAAa,KAAK,IAAI,IAAI,KAAK,EAAE,WAAW,KAAK,KAAK,CAAC;AACvE,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAoC;IAChE,IAAI,oBAAoB,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC9C,IAAI,OAAO,CAAC,GAAG,CAAC,qBAAqB,KAAK,GAAG;QAAE,OAAO,KAAK,CAAC;IAC5D,gGAAgG;IAChG,IAAI,IAAI,IAAI,OAAO,CAAC,GAAG;QAAE,OAAO,KAAK,CAAC;IACtC,OAAO,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;AAC/B,CAAC"}
1
+ {"version":3,"file":"interactive.js","sourceRoot":"","sources":["../../src/utils/interactive.ts"],"names":[],"mappings":"AAOA;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,KAAoC;IACvE,IAAI,OAAO,KAAK,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IAC7C,OAAO,KAAK,EAAE,aAAa,KAAK,IAAI,IAAI,KAAK,EAAE,WAAW,KAAK,KAAK,CAAC;AACvE,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAoC;IAChE,IAAI,oBAAoB,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC9C,IAAI,OAAO,CAAC,GAAG,CAAC,qBAAqB,KAAK,GAAG;QAAE,OAAO,KAAK,CAAC;IAC5D,IAAI,IAAI,IAAI,OAAO,CAAC,GAAG;QAAE,OAAO,KAAK,CAAC;IACtC,OAAO,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;AAC/B,CAAC"}
@@ -1,21 +1,26 @@
1
1
  /**
2
- * Finds a change's ticket in the global `tospec/tickets/` index by matching the
3
- * ticket frontmatter's `change:` field. Scans only the active folder
4
- * (non-recursive), so archived tickets under `tickets/archive/` are excluded.
5
- * Returns the absolute path, or undefined if none matches.
2
+ * Every ticket in the active `tospec/tickets/` index whose frontmatter `change:`
3
+ * names this change, oldest first (the filename is the `yyyyMMdd_HHmmss` stamp).
4
+ * Non-recursive, so `tickets/archive/` is excluded.
6
5
  *
7
- * ponytail: linear scan of tickets/; fine at repo scale (one ticket per change).
8
- * Add an index if a project ever accumulates thousands of active changes.
6
+ * Plural because the index can hold more than one: `rm -rf` on a change leaves
7
+ * its ticket behind, and recreating the name adds a second. Callers that can
8
+ * report the ambiguity should; `findTicketPath` picks for the rest.
9
+ */
10
+ export declare function findTicketPaths(root: string, changeName: string): Promise<string[]>;
11
+ /**
12
+ * The newest wins: a second ticket exists because the change was recreated, so
13
+ * the later stamp describes the change on disk. Taking the first `readdir` entry
14
+ * files the run under the abandoned attempt's ticket.
9
15
  */
10
16
  export declare function findTicketPath(root: string, changeName: string): Promise<string | undefined>;
11
17
  /**
12
- * Active change directory names under `changesDir`, sorted, excluding `archive`
13
- * and dot-directories. The one rule for "which changes exist": list, archive
14
- * and status each filtered slightly differently, so a stray `.tmp/` showed up
15
- * in some listings and not others.
18
+ * The one rule for "which changes exist". Filtered separately per command, a
19
+ * stray `.tmp/` shows up in some listings and not others.
16
20
  */
17
21
  export declare function listActiveChangeDirs(changesDir: string): Promise<string[]>;
18
22
  export declare function getActiveChangeIds(root?: string): Promise<string[]>;
23
+ /** A capability directory counts as a spec only once it holds a `spec.md`. */
19
24
  export declare function getSpecIds(root?: string): Promise<string[]>;
20
25
  export declare function getArchivedChangeIds(root?: string): Promise<string[]>;
21
26
  //# sourceMappingURL=item-discovery.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"item-discovery.d.ts","sourceRoot":"","sources":["../../src/utils/item-discovery.ts"],"names":[],"mappings":"AAIA;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAmBlG;AAED;;;;;GAKG;AACH,wBAAsB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAUhF;AAED,wBAAsB,kBAAkB,CAAC,IAAI,GAAE,MAAsB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAExF;AAED,wBAAsB,UAAU,CAAC,IAAI,GAAE,MAAsB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAmBhF;AAED,wBAAsB,oBAAoB,CAAC,IAAI,GAAE,MAAsB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAW1F"}
1
+ {"version":3,"file":"item-discovery.d.ts","sourceRoot":"","sources":["../../src/utils/item-discovery.ts"],"names":[],"mappings":"AAIA;;;;;;;;GAQG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAoBzF;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAGlG;AAeD;;;GAGG;AACH,wBAAsB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAGhF;AAED,wBAAsB,kBAAkB,CAAC,IAAI,GAAE,MAAsB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAExF;AAED,8EAA8E;AAC9E,wBAAsB,UAAU,CAAC,IAAI,GAAE,MAAsB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAchF;AAED,wBAAsB,oBAAoB,CAAC,IAAI,GAAE,MAAsB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAE1F"}