@seanmars/tospec 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (402) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +114 -0
  3. package/assets/dashboard/app.js +1032 -0
  4. package/assets/dashboard/chart.umd.js +14 -0
  5. package/assets/dashboard/index.html +30 -0
  6. package/assets/dashboard/style.css +675 -0
  7. package/bin/tospec.js +5 -0
  8. package/dist/cli/index.d.ts +5 -0
  9. package/dist/cli/index.d.ts.map +1 -0
  10. package/dist/cli/index.js +330 -0
  11. package/dist/cli/index.js.map +1 -0
  12. package/dist/commands/config.d.ts +36 -0
  13. package/dist/commands/config.d.ts.map +1 -0
  14. package/dist/commands/config.js +486 -0
  15. package/dist/commands/config.js.map +1 -0
  16. package/dist/commands/dashboard.d.ts +40 -0
  17. package/dist/commands/dashboard.d.ts.map +1 -0
  18. package/dist/commands/dashboard.js +385 -0
  19. package/dist/commands/dashboard.js.map +1 -0
  20. package/dist/commands/shared-output.d.ts +24 -0
  21. package/dist/commands/shared-output.d.ts.map +1 -0
  22. package/dist/commands/shared-output.js +51 -0
  23. package/dist/commands/shared-output.js.map +1 -0
  24. package/dist/commands/show.d.ts +17 -0
  25. package/dist/commands/show.d.ts.map +1 -0
  26. package/dist/commands/show.js +164 -0
  27. package/dist/commands/show.js.map +1 -0
  28. package/dist/commands/validate.d.ts +51 -0
  29. package/dist/commands/validate.d.ts.map +1 -0
  30. package/dist/commands/validate.js +416 -0
  31. package/dist/commands/validate.js.map +1 -0
  32. package/dist/commands/workflow/index.d.ts +17 -0
  33. package/dist/commands/workflow/index.d.ts.map +1 -0
  34. package/dist/commands/workflow/index.js +12 -0
  35. package/dist/commands/workflow/index.js.map +1 -0
  36. package/dist/commands/workflow/instructions.d.ts +35 -0
  37. package/dist/commands/workflow/instructions.d.ts.map +1 -0
  38. package/dist/commands/workflow/instructions.js +359 -0
  39. package/dist/commands/workflow/instructions.js.map +1 -0
  40. package/dist/commands/workflow/new-change.d.ts +17 -0
  41. package/dist/commands/workflow/new-change.d.ts.map +1 -0
  42. package/dist/commands/workflow/new-change.js +97 -0
  43. package/dist/commands/workflow/new-change.js.map +1 -0
  44. package/dist/commands/workflow/schemas.d.ts +10 -0
  45. package/dist/commands/workflow/schemas.d.ts.map +1 -0
  46. package/dist/commands/workflow/schemas.js +33 -0
  47. package/dist/commands/workflow/schemas.js.map +1 -0
  48. package/dist/commands/workflow/shared.d.ts +63 -0
  49. package/dist/commands/workflow/shared.d.ts.map +1 -0
  50. package/dist/commands/workflow/shared.js +111 -0
  51. package/dist/commands/workflow/shared.js.map +1 -0
  52. package/dist/commands/workflow/status.d.ts +14 -0
  53. package/dist/commands/workflow/status.d.ts.map +1 -0
  54. package/dist/commands/workflow/status.js +77 -0
  55. package/dist/commands/workflow/status.js.map +1 -0
  56. package/dist/commands/workflow/templates.d.ts +16 -0
  57. package/dist/commands/workflow/templates.d.ts.map +1 -0
  58. package/dist/commands/workflow/templates.js +60 -0
  59. package/dist/commands/workflow/templates.js.map +1 -0
  60. package/dist/core/archive.d.ts +33 -0
  61. package/dist/core/archive.d.ts.map +1 -0
  62. package/dist/core/archive.js +585 -0
  63. package/dist/core/archive.js.map +1 -0
  64. package/dist/core/artifact-graph/graph.d.ts +56 -0
  65. package/dist/core/artifact-graph/graph.d.ts.map +1 -0
  66. package/dist/core/artifact-graph/graph.js +141 -0
  67. package/dist/core/artifact-graph/graph.js.map +1 -0
  68. package/dist/core/artifact-graph/index.d.ts +9 -0
  69. package/dist/core/artifact-graph/index.d.ts.map +1 -0
  70. package/dist/core/artifact-graph/index.js +14 -0
  71. package/dist/core/artifact-graph/index.js.map +1 -0
  72. package/dist/core/artifact-graph/instruction-loader.d.ts +188 -0
  73. package/dist/core/artifact-graph/instruction-loader.d.ts.map +1 -0
  74. package/dist/core/artifact-graph/instruction-loader.js +243 -0
  75. package/dist/core/artifact-graph/instruction-loader.js.map +1 -0
  76. package/dist/core/artifact-graph/outputs.d.ts +14 -0
  77. package/dist/core/artifact-graph/outputs.d.ts.map +1 -0
  78. package/dist/core/artifact-graph/outputs.js +39 -0
  79. package/dist/core/artifact-graph/outputs.js.map +1 -0
  80. package/dist/core/artifact-graph/resolver.d.ts +81 -0
  81. package/dist/core/artifact-graph/resolver.d.ts.map +1 -0
  82. package/dist/core/artifact-graph/resolver.js +257 -0
  83. package/dist/core/artifact-graph/resolver.js.map +1 -0
  84. package/dist/core/artifact-graph/schema.d.ts +13 -0
  85. package/dist/core/artifact-graph/schema.d.ts.map +1 -0
  86. package/dist/core/artifact-graph/schema.js +108 -0
  87. package/dist/core/artifact-graph/schema.js.map +1 -0
  88. package/dist/core/artifact-graph/state.d.ts +12 -0
  89. package/dist/core/artifact-graph/state.d.ts.map +1 -0
  90. package/dist/core/artifact-graph/state.js +31 -0
  91. package/dist/core/artifact-graph/state.js.map +1 -0
  92. package/dist/core/artifact-graph/types.d.ts +55 -0
  93. package/dist/core/artifact-graph/types.d.ts.map +1 -0
  94. package/dist/core/artifact-graph/types.js +38 -0
  95. package/dist/core/artifact-graph/types.js.map +1 -0
  96. package/dist/core/available-tools.d.ts +17 -0
  97. package/dist/core/available-tools.d.ts.map +1 -0
  98. package/dist/core/available-tools.js +43 -0
  99. package/dist/core/available-tools.js.map +1 -0
  100. package/dist/core/change-metadata/index.d.ts +2 -0
  101. package/dist/core/change-metadata/index.d.ts.map +1 -0
  102. package/dist/core/change-metadata/index.js +2 -0
  103. package/dist/core/change-metadata/index.js.map +1 -0
  104. package/dist/core/change-metadata/schema.d.ts +12 -0
  105. package/dist/core/change-metadata/schema.d.ts.map +1 -0
  106. package/dist/core/change-metadata/schema.js +15 -0
  107. package/dist/core/change-metadata/schema.js.map +1 -0
  108. package/dist/core/change-presenter.d.ts +24 -0
  109. package/dist/core/change-presenter.d.ts.map +1 -0
  110. package/dist/core/change-presenter.js +135 -0
  111. package/dist/core/change-presenter.js.map +1 -0
  112. package/dist/core/change-status-policy.d.ts +35 -0
  113. package/dist/core/change-status-policy.d.ts.map +1 -0
  114. package/dist/core/change-status-policy.js +34 -0
  115. package/dist/core/change-status-policy.js.map +1 -0
  116. package/dist/core/command-generation/adapters/claude.d.ts +14 -0
  117. package/dist/core/command-generation/adapters/claude.d.ts.map +1 -0
  118. package/dist/core/command-generation/adapters/claude.js +38 -0
  119. package/dist/core/command-generation/adapters/claude.js.map +1 -0
  120. package/dist/core/command-generation/adapters/cursor.d.ts +14 -0
  121. package/dist/core/command-generation/adapters/cursor.d.ts.map +1 -0
  122. package/dist/core/command-generation/adapters/cursor.js +31 -0
  123. package/dist/core/command-generation/adapters/cursor.js.map +1 -0
  124. package/dist/core/command-generation/adapters/index.d.ts +8 -0
  125. package/dist/core/command-generation/adapters/index.d.ts.map +1 -0
  126. package/dist/core/command-generation/adapters/index.js +8 -0
  127. package/dist/core/command-generation/adapters/index.js.map +1 -0
  128. package/dist/core/command-generation/generator.d.ts +21 -0
  129. package/dist/core/command-generation/generator.d.ts.map +1 -0
  130. package/dist/core/command-generation/generator.js +27 -0
  131. package/dist/core/command-generation/generator.js.map +1 -0
  132. package/dist/core/command-generation/index.d.ts +22 -0
  133. package/dist/core/command-generation/index.d.ts.map +1 -0
  134. package/dist/core/command-generation/index.js +24 -0
  135. package/dist/core/command-generation/index.js.map +1 -0
  136. package/dist/core/command-generation/registry.d.ts +24 -0
  137. package/dist/core/command-generation/registry.d.ts.map +1 -0
  138. package/dist/core/command-generation/registry.js +38 -0
  139. package/dist/core/command-generation/registry.js.map +1 -0
  140. package/dist/core/command-generation/types.d.ts +56 -0
  141. package/dist/core/command-generation/types.d.ts.map +1 -0
  142. package/dist/core/command-generation/types.js +8 -0
  143. package/dist/core/command-generation/types.js.map +1 -0
  144. package/dist/core/command-generation/yaml.d.ts +22 -0
  145. package/dist/core/command-generation/yaml.d.ts.map +1 -0
  146. package/dist/core/command-generation/yaml.js +38 -0
  147. package/dist/core/command-generation/yaml.js.map +1 -0
  148. package/dist/core/config-prompts.d.ts +9 -0
  149. package/dist/core/config-prompts.d.ts.map +1 -0
  150. package/dist/core/config-prompts.js +34 -0
  151. package/dist/core/config-prompts.js.map +1 -0
  152. package/dist/core/config-schema.d.ts +87 -0
  153. package/dist/core/config-schema.d.ts.map +1 -0
  154. package/dist/core/config-schema.js +239 -0
  155. package/dist/core/config-schema.js.map +1 -0
  156. package/dist/core/config.d.ts +19 -0
  157. package/dist/core/config.d.ts.map +1 -0
  158. package/dist/core/config.js +14 -0
  159. package/dist/core/config.js.map +1 -0
  160. package/dist/core/converters/json-converter.d.ts +6 -0
  161. package/dist/core/converters/json-converter.d.ts.map +1 -0
  162. package/dist/core/converters/json-converter.js +51 -0
  163. package/dist/core/converters/json-converter.js.map +1 -0
  164. package/dist/core/dashboard-activity.d.ts +50 -0
  165. package/dist/core/dashboard-activity.d.ts.map +1 -0
  166. package/dist/core/dashboard-activity.js +147 -0
  167. package/dist/core/dashboard-activity.js.map +1 -0
  168. package/dist/core/dashboard-data.d.ts +100 -0
  169. package/dist/core/dashboard-data.d.ts.map +1 -0
  170. package/dist/core/dashboard-data.js +368 -0
  171. package/dist/core/dashboard-data.js.map +1 -0
  172. package/dist/core/global-config.d.ts +51 -0
  173. package/dist/core/global-config.d.ts.map +1 -0
  174. package/dist/core/global-config.js +124 -0
  175. package/dist/core/global-config.js.map +1 -0
  176. package/dist/core/id.d.ts +17 -0
  177. package/dist/core/id.d.ts.map +1 -0
  178. package/dist/core/id.js +30 -0
  179. package/dist/core/id.js.map +1 -0
  180. package/dist/core/init.d.ts +34 -0
  181. package/dist/core/init.d.ts.map +1 -0
  182. package/dist/core/init.js +495 -0
  183. package/dist/core/init.js.map +1 -0
  184. package/dist/core/list.d.ts +12 -0
  185. package/dist/core/list.d.ts.map +1 -0
  186. package/dist/core/list.js +192 -0
  187. package/dist/core/list.js.map +1 -0
  188. package/dist/core/migrate.d.ts +52 -0
  189. package/dist/core/migrate.d.ts.map +1 -0
  190. package/dist/core/migrate.js +300 -0
  191. package/dist/core/migrate.js.map +1 -0
  192. package/dist/core/parsers/change-parser.d.ts +19 -0
  193. package/dist/core/parsers/change-parser.d.ts.map +1 -0
  194. package/dist/core/parsers/change-parser.js +204 -0
  195. package/dist/core/parsers/change-parser.js.map +1 -0
  196. package/dist/core/parsers/markdown-parser.d.ts +29 -0
  197. package/dist/core/parsers/markdown-parser.d.ts.map +1 -0
  198. package/dist/core/parsers/markdown-parser.js +181 -0
  199. package/dist/core/parsers/markdown-parser.js.map +1 -0
  200. package/dist/core/parsers/requirement-blocks.d.ts +37 -0
  201. package/dist/core/parsers/requirement-blocks.d.ts.map +1 -0
  202. package/dist/core/parsers/requirement-blocks.js +201 -0
  203. package/dist/core/parsers/requirement-blocks.js.map +1 -0
  204. package/dist/core/parsers/requirement-text.d.ts +55 -0
  205. package/dist/core/parsers/requirement-text.d.ts.map +1 -0
  206. package/dist/core/parsers/requirement-text.js +136 -0
  207. package/dist/core/parsers/requirement-text.js.map +1 -0
  208. package/dist/core/parsers/spec-structure.d.ts +9 -0
  209. package/dist/core/parsers/spec-structure.d.ts.map +1 -0
  210. package/dist/core/parsers/spec-structure.js +88 -0
  211. package/dist/core/parsers/spec-structure.js.map +1 -0
  212. package/dist/core/planning-home.d.ts +16 -0
  213. package/dist/core/planning-home.d.ts.map +1 -0
  214. package/dist/core/planning-home.js +67 -0
  215. package/dist/core/planning-home.js.map +1 -0
  216. package/dist/core/profiles.d.ts +24 -0
  217. package/dist/core/profiles.d.ts.map +1 -0
  218. package/dist/core/profiles.js +27 -0
  219. package/dist/core/profiles.js.map +1 -0
  220. package/dist/core/project-config.d.ts +100 -0
  221. package/dist/core/project-config.d.ts.map +1 -0
  222. package/dist/core/project-config.js +389 -0
  223. package/dist/core/project-config.js.map +1 -0
  224. package/dist/core/references.d.ts +40 -0
  225. package/dist/core/references.d.ts.map +1 -0
  226. package/dist/core/references.js +11 -0
  227. package/dist/core/references.js.map +1 -0
  228. package/dist/core/root-selection.d.ts +57 -0
  229. package/dist/core/root-selection.d.ts.map +1 -0
  230. package/dist/core/root-selection.js +98 -0
  231. package/dist/core/root-selection.js.map +1 -0
  232. package/dist/core/schemas/base.schema.d.ts +13 -0
  233. package/dist/core/schemas/base.schema.d.ts.map +1 -0
  234. package/dist/core/schemas/base.schema.js +18 -0
  235. package/dist/core/schemas/base.schema.js.map +1 -0
  236. package/dist/core/schemas/change.schema.d.ts +73 -0
  237. package/dist/core/schemas/change.schema.d.ts.map +1 -0
  238. package/dist/core/schemas/change.schema.js +31 -0
  239. package/dist/core/schemas/change.schema.js.map +1 -0
  240. package/dist/core/schemas/index.d.ts +4 -0
  241. package/dist/core/schemas/index.d.ts.map +1 -0
  242. package/dist/core/schemas/index.js +4 -0
  243. package/dist/core/schemas/index.js.map +1 -0
  244. package/dist/core/schemas/spec.schema.d.ts +18 -0
  245. package/dist/core/schemas/spec.schema.d.ts.map +1 -0
  246. package/dist/core/schemas/spec.schema.js +15 -0
  247. package/dist/core/schemas/spec.schema.js.map +1 -0
  248. package/dist/core/shared/index.d.ts +8 -0
  249. package/dist/core/shared/index.d.ts.map +1 -0
  250. package/dist/core/shared/index.js +8 -0
  251. package/dist/core/shared/index.js.map +1 -0
  252. package/dist/core/shared/skill-generation.d.ts +63 -0
  253. package/dist/core/shared/skill-generation.d.ts.map +1 -0
  254. package/dist/core/shared/skill-generation.js +125 -0
  255. package/dist/core/shared/skill-generation.js.map +1 -0
  256. package/dist/core/shared/tool-detection.d.ts +96 -0
  257. package/dist/core/shared/tool-detection.d.ts.map +1 -0
  258. package/dist/core/shared/tool-detection.js +207 -0
  259. package/dist/core/shared/tool-detection.js.map +1 -0
  260. package/dist/core/spec-presenter.d.ts +17 -0
  261. package/dist/core/spec-presenter.d.ts.map +1 -0
  262. package/dist/core/spec-presenter.js +98 -0
  263. package/dist/core/spec-presenter.js.map +1 -0
  264. package/dist/core/specs-apply.d.ts +78 -0
  265. package/dist/core/specs-apply.d.ts.map +1 -0
  266. package/dist/core/specs-apply.js +429 -0
  267. package/dist/core/specs-apply.js.map +1 -0
  268. package/dist/core/templates/index.d.ts +8 -0
  269. package/dist/core/templates/index.d.ts.map +1 -0
  270. package/dist/core/templates/index.js +9 -0
  271. package/dist/core/templates/index.js.map +1 -0
  272. package/dist/core/templates/skill-templates.d.ts +14 -0
  273. package/dist/core/templates/skill-templates.d.ts.map +1 -0
  274. package/dist/core/templates/skill-templates.js +13 -0
  275. package/dist/core/templates/skill-templates.js.map +1 -0
  276. package/dist/core/templates/types.d.ts +20 -0
  277. package/dist/core/templates/types.d.ts.map +1 -0
  278. package/dist/core/templates/types.js +5 -0
  279. package/dist/core/templates/types.js.map +1 -0
  280. package/dist/core/templates/workflows/apply.d.ts +10 -0
  281. package/dist/core/templates/workflows/apply.d.ts.map +1 -0
  282. package/dist/core/templates/workflows/apply.js +81 -0
  283. package/dist/core/templates/workflows/apply.js.map +1 -0
  284. package/dist/core/templates/workflows/archive.d.ts +10 -0
  285. package/dist/core/templates/workflows/archive.d.ts.map +1 -0
  286. package/dist/core/templates/workflows/archive.js +75 -0
  287. package/dist/core/templates/workflows/archive.js.map +1 -0
  288. package/dist/core/templates/workflows/explore.d.ts +10 -0
  289. package/dist/core/templates/workflows/explore.d.ts.map +1 -0
  290. package/dist/core/templates/workflows/explore.js +75 -0
  291. package/dist/core/templates/workflows/explore.js.map +1 -0
  292. package/dist/core/templates/workflows/issue.d.ts +10 -0
  293. package/dist/core/templates/workflows/issue.d.ts.map +1 -0
  294. package/dist/core/templates/workflows/issue.js +89 -0
  295. package/dist/core/templates/workflows/issue.js.map +1 -0
  296. package/dist/core/templates/workflows/propose.d.ts +10 -0
  297. package/dist/core/templates/workflows/propose.d.ts.map +1 -0
  298. package/dist/core/templates/workflows/propose.js +77 -0
  299. package/dist/core/templates/workflows/propose.js.map +1 -0
  300. package/dist/core/templates/workflows/sync.d.ts +14 -0
  301. package/dist/core/templates/workflows/sync.d.ts.map +1 -0
  302. package/dist/core/templates/workflows/sync.js +86 -0
  303. package/dist/core/templates/workflows/sync.js.map +1 -0
  304. package/dist/core/templates/workflows/update.d.ts +10 -0
  305. package/dist/core/templates/workflows/update.d.ts.map +1 -0
  306. package/dist/core/templates/workflows/update.js +99 -0
  307. package/dist/core/templates/workflows/update.js.map +1 -0
  308. package/dist/core/templates/workflows/verify.d.ts +9 -0
  309. package/dist/core/templates/workflows/verify.d.ts.map +1 -0
  310. package/dist/core/templates/workflows/verify.js +44 -0
  311. package/dist/core/templates/workflows/verify.js.map +1 -0
  312. package/dist/core/update.d.ts +46 -0
  313. package/dist/core/update.d.ts.map +1 -0
  314. package/dist/core/update.js +296 -0
  315. package/dist/core/update.js.map +1 -0
  316. package/dist/core/validation/constants.d.ts +34 -0
  317. package/dist/core/validation/constants.d.ts.map +1 -0
  318. package/dist/core/validation/constants.js +40 -0
  319. package/dist/core/validation/constants.js.map +1 -0
  320. package/dist/core/validation/section-validator.d.ts +19 -0
  321. package/dist/core/validation/section-validator.d.ts.map +1 -0
  322. package/dist/core/validation/section-validator.js +59 -0
  323. package/dist/core/validation/section-validator.js.map +1 -0
  324. package/dist/core/validation/types.d.ts +18 -0
  325. package/dist/core/validation/types.d.ts.map +1 -0
  326. package/dist/core/validation/types.js +2 -0
  327. package/dist/core/validation/types.js.map +1 -0
  328. package/dist/core/validation/validator.d.ts +51 -0
  329. package/dist/core/validation/validator.d.ts.map +1 -0
  330. package/dist/core/validation/validator.js +469 -0
  331. package/dist/core/validation/validator.js.map +1 -0
  332. package/dist/index.d.ts +2 -0
  333. package/dist/index.d.ts.map +1 -0
  334. package/dist/index.js +2 -0
  335. package/dist/index.js.map +1 -0
  336. package/dist/prompts/searchable-multi-select.d.ts +28 -0
  337. package/dist/prompts/searchable-multi-select.d.ts.map +1 -0
  338. package/dist/prompts/searchable-multi-select.js +158 -0
  339. package/dist/prompts/searchable-multi-select.js.map +1 -0
  340. package/dist/ui/welcome-screen.d.ts +5 -0
  341. package/dist/ui/welcome-screen.d.ts.map +1 -0
  342. package/dist/ui/welcome-screen.js +22 -0
  343. package/dist/ui/welcome-screen.js.map +1 -0
  344. package/dist/utils/change-metadata.d.ts +55 -0
  345. package/dist/utils/change-metadata.d.ts.map +1 -0
  346. package/dist/utils/change-metadata.js +141 -0
  347. package/dist/utils/change-metadata.js.map +1 -0
  348. package/dist/utils/change-utils.d.ts +73 -0
  349. package/dist/utils/change-utils.d.ts.map +1 -0
  350. package/dist/utils/change-utils.js +194 -0
  351. package/dist/utils/change-utils.js.map +1 -0
  352. package/dist/utils/command-references.d.ts +18 -0
  353. package/dist/utils/command-references.d.ts.map +1 -0
  354. package/dist/utils/command-references.js +20 -0
  355. package/dist/utils/command-references.js.map +1 -0
  356. package/dist/utils/file-system.d.ts +41 -0
  357. package/dist/utils/file-system.d.ts.map +1 -0
  358. package/dist/utils/file-system.js +320 -0
  359. package/dist/utils/file-system.js.map +1 -0
  360. package/dist/utils/index.d.ts +6 -0
  361. package/dist/utils/index.d.ts.map +1 -0
  362. package/dist/utils/index.js +9 -0
  363. package/dist/utils/index.js.map +1 -0
  364. package/dist/utils/interactive.d.ts +18 -0
  365. package/dist/utils/interactive.d.ts.map +1 -0
  366. package/dist/utils/interactive.js +21 -0
  367. package/dist/utils/interactive.js.map +1 -0
  368. package/dist/utils/item-discovery.d.ts +14 -0
  369. package/dist/utils/item-discovery.d.ts.map +1 -0
  370. package/dist/utils/item-discovery.js +104 -0
  371. package/dist/utils/item-discovery.js.map +1 -0
  372. package/dist/utils/link.d.ts +22 -0
  373. package/dist/utils/link.d.ts.map +1 -0
  374. package/dist/utils/link.js +85 -0
  375. package/dist/utils/link.js.map +1 -0
  376. package/dist/utils/match.d.ts +3 -0
  377. package/dist/utils/match.d.ts.map +1 -0
  378. package/dist/utils/match.js +22 -0
  379. package/dist/utils/match.js.map +1 -0
  380. package/dist/utils/shell-detection.d.ts +20 -0
  381. package/dist/utils/shell-detection.d.ts.map +1 -0
  382. package/dist/utils/shell-detection.js +41 -0
  383. package/dist/utils/shell-detection.js.map +1 -0
  384. package/dist/utils/task-progress.d.ts +32 -0
  385. package/dist/utils/task-progress.d.ts.map +1 -0
  386. package/dist/utils/task-progress.js +129 -0
  387. package/dist/utils/task-progress.js.map +1 -0
  388. package/dist/utils/timestamp.d.ts +9 -0
  389. package/dist/utils/timestamp.d.ts.map +1 -0
  390. package/dist/utils/timestamp.js +18 -0
  391. package/dist/utils/timestamp.js.map +1 -0
  392. package/package.json +55 -0
  393. package/schemas/issue/schema.yaml +34 -0
  394. package/schemas/issue/templates/spec.md +13 -0
  395. package/schemas/issue/templates/task.md +21 -0
  396. package/schemas/issue/templates/ticket.md +2 -0
  397. package/schemas/sdd/schema.yaml +55 -0
  398. package/schemas/sdd/templates/design.md +15 -0
  399. package/schemas/sdd/templates/proposal.md +15 -0
  400. package/schemas/sdd/templates/spec.md +13 -0
  401. package/schemas/sdd/templates/tasks.md +11 -0
  402. package/schemas/sdd/templates/ticket.md +2 -0
@@ -0,0 +1,87 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Zod schema for global Tospec configuration.
4
+ * Uses passthrough() to preserve unknown fields for forward compatibility.
5
+ */
6
+ export declare const GlobalConfigSchema: z.ZodObject<{
7
+ featureFlags: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodBoolean>>>;
8
+ profile: z.ZodDefault<z.ZodOptional<z.ZodEnum<{
9
+ core: "core";
10
+ custom: "custom";
11
+ }>>>;
12
+ delivery: z.ZodDefault<z.ZodOptional<z.ZodEnum<{
13
+ skills: "skills";
14
+ commands: "commands";
15
+ both: "both";
16
+ }>>>;
17
+ workflows: z.ZodOptional<z.ZodArray<z.ZodString>>;
18
+ }, z.core.$loose>;
19
+ export type GlobalConfigType = z.infer<typeof GlobalConfigSchema>;
20
+ /**
21
+ * Default configuration values.
22
+ */
23
+ export declare const DEFAULT_CONFIG: GlobalConfigType;
24
+ /**
25
+ * Validate a config key path for CLI set operations.
26
+ * Unknown top-level keys are rejected unless explicitly allowed by the caller.
27
+ */
28
+ export declare function validateConfigKeyPath(path: string): {
29
+ valid: boolean;
30
+ reason?: string;
31
+ };
32
+ /**
33
+ * Get a nested value from an object using dot notation.
34
+ *
35
+ * @param obj - The object to access
36
+ * @param path - Dot-separated path (e.g., "featureFlags.someFlag")
37
+ * @returns The value at the path, or undefined if not found
38
+ */
39
+ export declare function getNestedValue(obj: Record<string, unknown>, path: string): unknown;
40
+ /**
41
+ * Set a nested value in an object using dot notation.
42
+ * Creates intermediate objects as needed.
43
+ *
44
+ * @param obj - The object to modify (mutated in place)
45
+ * @param path - Dot-separated path (e.g., "featureFlags.someFlag")
46
+ * @param value - The value to set
47
+ */
48
+ export declare function setNestedValue(obj: Record<string, unknown>, path: string, value: unknown): void;
49
+ /**
50
+ * Delete a nested value from an object using dot notation.
51
+ *
52
+ * @param obj - The object to modify (mutated in place)
53
+ * @param path - Dot-separated path (e.g., "featureFlags.someFlag")
54
+ * @returns true if the key existed and was deleted, false otherwise
55
+ */
56
+ export declare function deleteNestedValue(obj: Record<string, unknown>, path: string): boolean;
57
+ /**
58
+ * Coerce a string value to its appropriate type.
59
+ * - "true" / "false" -> boolean
60
+ * - Numeric strings -> number
61
+ * - JSON arrays/objects -> parsed containers
62
+ * - Everything else -> string
63
+ *
64
+ * @param value - The string value to coerce
65
+ * @param forceString - If true, always return the value as a string
66
+ * @returns The coerced value
67
+ */
68
+ export declare function coerceValue(value: string, forceString?: boolean): string | number | boolean | unknown[] | Record<string, unknown>;
69
+ /**
70
+ * Format a value for YAML-like display.
71
+ *
72
+ * @param value - The value to format
73
+ * @param indent - Current indentation level
74
+ * @returns Formatted string
75
+ */
76
+ export declare function formatValueYaml(value: unknown, indent?: number): string;
77
+ /**
78
+ * Validate a configuration object against the schema.
79
+ *
80
+ * @param config - The configuration to validate
81
+ * @returns Validation result with success status and optional error message
82
+ */
83
+ export declare function validateConfig(config: unknown): {
84
+ success: boolean;
85
+ error?: string;
86
+ };
87
+ //# sourceMappingURL=config-schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-schema.d.ts","sourceRoot":"","sources":["../../src/core/config-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;GAGG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;iBAkBf,CAAC;AAEjB,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAElE;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,gBAI5B,CAAC;AAIF;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAwBvF;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAelF;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAc/F;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAkBrF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,MAAM,EACb,WAAW,GAAE,OAAe,GAC3B,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAyBjE;AA2BD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,GAAE,MAAU,GAAG,MAAM,CAuC1E;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,OAAO,GAAG;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAYpF"}
@@ -0,0 +1,239 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Zod schema for global Tospec configuration.
4
+ * Uses passthrough() to preserve unknown fields for forward compatibility.
5
+ */
6
+ export const GlobalConfigSchema = z
7
+ .object({
8
+ featureFlags: z
9
+ .record(z.string(), z.boolean())
10
+ .optional()
11
+ .default({}),
12
+ profile: z
13
+ .enum(['core', 'custom'])
14
+ .optional()
15
+ .default('core'),
16
+ delivery: z
17
+ .enum(['both', 'skills', 'commands'])
18
+ .optional()
19
+ .default('skills'),
20
+ workflows: z
21
+ .array(z.string())
22
+ .optional(),
23
+ })
24
+ .passthrough();
25
+ /**
26
+ * Default configuration values.
27
+ */
28
+ export const DEFAULT_CONFIG = {
29
+ featureFlags: {},
30
+ profile: 'core',
31
+ delivery: 'skills',
32
+ };
33
+ const KNOWN_TOP_LEVEL_KEYS = new Set([...Object.keys(DEFAULT_CONFIG), 'workflows']);
34
+ /**
35
+ * Validate a config key path for CLI set operations.
36
+ * Unknown top-level keys are rejected unless explicitly allowed by the caller.
37
+ */
38
+ export function validateConfigKeyPath(path) {
39
+ const rawKeys = path.split('.');
40
+ if (rawKeys.length === 0 || rawKeys.some((key) => key.trim() === '')) {
41
+ return { valid: false, reason: 'Key path must not be empty' };
42
+ }
43
+ const rootKey = rawKeys[0];
44
+ if (!KNOWN_TOP_LEVEL_KEYS.has(rootKey)) {
45
+ return { valid: false, reason: `Unknown top-level key "${rootKey}"` };
46
+ }
47
+ if (rootKey === 'featureFlags') {
48
+ if (rawKeys.length > 2) {
49
+ return { valid: false, reason: 'featureFlags values are booleans and do not support nested keys' };
50
+ }
51
+ return { valid: true };
52
+ }
53
+ if (rawKeys.length > 1) {
54
+ return { valid: false, reason: `"${rootKey}" does not support nested keys` };
55
+ }
56
+ return { valid: true };
57
+ }
58
+ /**
59
+ * Get a nested value from an object using dot notation.
60
+ *
61
+ * @param obj - The object to access
62
+ * @param path - Dot-separated path (e.g., "featureFlags.someFlag")
63
+ * @returns The value at the path, or undefined if not found
64
+ */
65
+ export function getNestedValue(obj, path) {
66
+ const keys = path.split('.');
67
+ let current = obj;
68
+ for (const key of keys) {
69
+ if (current === null || current === undefined) {
70
+ return undefined;
71
+ }
72
+ if (typeof current !== 'object') {
73
+ return undefined;
74
+ }
75
+ current = current[key];
76
+ }
77
+ return current;
78
+ }
79
+ /**
80
+ * Set a nested value in an object using dot notation.
81
+ * Creates intermediate objects as needed.
82
+ *
83
+ * @param obj - The object to modify (mutated in place)
84
+ * @param path - Dot-separated path (e.g., "featureFlags.someFlag")
85
+ * @param value - The value to set
86
+ */
87
+ export function setNestedValue(obj, path, value) {
88
+ const keys = path.split('.');
89
+ let current = obj;
90
+ for (let i = 0; i < keys.length - 1; i++) {
91
+ const key = keys[i];
92
+ if (current[key] === undefined || current[key] === null || typeof current[key] !== 'object') {
93
+ current[key] = {};
94
+ }
95
+ current = current[key];
96
+ }
97
+ const lastKey = keys[keys.length - 1];
98
+ current[lastKey] = value;
99
+ }
100
+ /**
101
+ * Delete a nested value from an object using dot notation.
102
+ *
103
+ * @param obj - The object to modify (mutated in place)
104
+ * @param path - Dot-separated path (e.g., "featureFlags.someFlag")
105
+ * @returns true if the key existed and was deleted, false otherwise
106
+ */
107
+ export function deleteNestedValue(obj, path) {
108
+ const keys = path.split('.');
109
+ let current = obj;
110
+ for (let i = 0; i < keys.length - 1; i++) {
111
+ const key = keys[i];
112
+ if (current[key] === undefined || current[key] === null || typeof current[key] !== 'object') {
113
+ return false;
114
+ }
115
+ current = current[key];
116
+ }
117
+ const lastKey = keys[keys.length - 1];
118
+ if (lastKey in current) {
119
+ delete current[lastKey];
120
+ return true;
121
+ }
122
+ return false;
123
+ }
124
+ /**
125
+ * Coerce a string value to its appropriate type.
126
+ * - "true" / "false" -> boolean
127
+ * - Numeric strings -> number
128
+ * - JSON arrays/objects -> parsed containers
129
+ * - Everything else -> string
130
+ *
131
+ * @param value - The string value to coerce
132
+ * @param forceString - If true, always return the value as a string
133
+ * @returns The coerced value
134
+ */
135
+ export function coerceValue(value, forceString = false) {
136
+ if (forceString) {
137
+ return value;
138
+ }
139
+ // Boolean coercion
140
+ if (value === 'true') {
141
+ return true;
142
+ }
143
+ if (value === 'false') {
144
+ return false;
145
+ }
146
+ // Number coercion - must be a valid finite number
147
+ const num = Number(value);
148
+ if (!isNaN(num) && isFinite(num) && value.trim() !== '') {
149
+ return num;
150
+ }
151
+ const jsonContainer = parseJsonContainer(value);
152
+ if (jsonContainer !== undefined) {
153
+ return jsonContainer;
154
+ }
155
+ return value;
156
+ }
157
+ function parseJsonContainer(value) {
158
+ const trimmed = value.trim();
159
+ const looksLikeContainer = (trimmed.startsWith('[') && trimmed.endsWith(']')) ||
160
+ (trimmed.startsWith('{') && trimmed.endsWith('}'));
161
+ if (!looksLikeContainer) {
162
+ return undefined;
163
+ }
164
+ try {
165
+ const parsed = JSON.parse(trimmed);
166
+ if (Array.isArray(parsed)) {
167
+ return parsed;
168
+ }
169
+ if (parsed !== null && typeof parsed === 'object') {
170
+ return parsed;
171
+ }
172
+ }
173
+ catch {
174
+ return undefined;
175
+ }
176
+ return undefined;
177
+ }
178
+ /**
179
+ * Format a value for YAML-like display.
180
+ *
181
+ * @param value - The value to format
182
+ * @param indent - Current indentation level
183
+ * @returns Formatted string
184
+ */
185
+ export function formatValueYaml(value, indent = 0) {
186
+ const indentStr = ' '.repeat(indent);
187
+ if (value === null || value === undefined) {
188
+ return 'null';
189
+ }
190
+ if (typeof value === 'boolean' || typeof value === 'number') {
191
+ return String(value);
192
+ }
193
+ if (typeof value === 'string') {
194
+ return value;
195
+ }
196
+ if (Array.isArray(value)) {
197
+ if (value.length === 0) {
198
+ return '[]';
199
+ }
200
+ return value.map((item) => `${indentStr}- ${formatValueYaml(item, indent + 1)}`).join('\n');
201
+ }
202
+ if (typeof value === 'object') {
203
+ const entries = Object.entries(value);
204
+ if (entries.length === 0) {
205
+ return '{}';
206
+ }
207
+ return entries
208
+ .map(([key, val]) => {
209
+ const formattedVal = formatValueYaml(val, indent + 1);
210
+ if (typeof val === 'object' && val !== null && Object.keys(val).length > 0) {
211
+ return `${indentStr}${key}:\n${formattedVal}`;
212
+ }
213
+ return `${indentStr}${key}: ${formattedVal}`;
214
+ })
215
+ .join('\n');
216
+ }
217
+ return String(value);
218
+ }
219
+ /**
220
+ * Validate a configuration object against the schema.
221
+ *
222
+ * @param config - The configuration to validate
223
+ * @returns Validation result with success status and optional error message
224
+ */
225
+ export function validateConfig(config) {
226
+ try {
227
+ GlobalConfigSchema.parse(config);
228
+ return { success: true };
229
+ }
230
+ catch (error) {
231
+ if (error instanceof z.ZodError) {
232
+ const zodError = error;
233
+ const messages = zodError.issues.map((e) => `${e.path.join('.')}: ${e.message}`);
234
+ return { success: false, error: messages.join('; ') };
235
+ }
236
+ return { success: false, error: 'Unknown validation error' };
237
+ }
238
+ }
239
+ //# sourceMappingURL=config-schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-schema.js","sourceRoot":"","sources":["../../src/core/config-schema.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ export declare const TOSPEC_DIR_NAME = "tospec";
2
+ export declare const TOSPEC_MARKERS: {
3
+ start: string;
4
+ end: string;
5
+ };
6
+ export interface TospecConfig {
7
+ aiTools: string[];
8
+ }
9
+ export interface AIToolOption {
10
+ name: string;
11
+ value: string;
12
+ available: boolean;
13
+ successLabel?: string;
14
+ skillsDir?: string;
15
+ detectionPaths?: string[];
16
+ }
17
+ export declare const AI_TOOLS: AIToolOption[];
18
+ export declare const HARD_LINK_TOOLS: readonly string[];
19
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,eAAe,WAAW,CAAC;AAExC,eAAO,MAAM,cAAc;;;CAG1B,CAAC;AAEF,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED,eAAO,MAAM,QAAQ,EAAE,YAAY,EAGlC,CAAC;AAKF,eAAO,MAAM,eAAe,EAAE,SAAS,MAAM,EAAe,CAAC"}
@@ -0,0 +1,14 @@
1
+ export const TOSPEC_DIR_NAME = 'tospec';
2
+ export const TOSPEC_MARKERS = {
3
+ start: '<!-- TOSPEC:START -->',
4
+ end: '<!-- TOSPEC:END -->'
5
+ };
6
+ export const AI_TOOLS = [
7
+ { name: 'Claude Code', value: 'claude', available: true, successLabel: 'Claude Code', skillsDir: '.claude' },
8
+ { name: 'Codex', value: 'codex', available: true, successLabel: 'Codex', skillsDir: '.codex' }
9
+ ];
10
+ // Tools (by tool.value) that get hard-linked skill files; anything not listed
11
+ // lands as a plain recursive copy instead. Claude Code reads hard-linked skill
12
+ // files; other agents (e.g. codex) are fine with ordinary files.
13
+ export const HARD_LINK_TOOLS = ['claude'];
14
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG,QAAQ,CAAC;AAExC,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,KAAK,EAAE,uBAAuB;IAC9B,GAAG,EAAE,qBAAqB;CAC3B,CAAC;AAeF,MAAM,CAAC,MAAM,QAAQ,GAAmB;IACtC,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE;IAC5G,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE;CAC/F,CAAC;AAEF,8EAA8E;AAC9E,+EAA+E;AAC/E,iEAAiE;AACjE,MAAM,CAAC,MAAM,eAAe,GAAsB,CAAC,QAAQ,CAAC,CAAC"}
@@ -0,0 +1,6 @@
1
+ export declare class JsonConverter {
2
+ convertSpecToJson(filePath: string): string;
3
+ convertChangeToJson(filePath: string): Promise<string>;
4
+ private extractNameFromPath;
5
+ }
6
+ //# sourceMappingURL=json-converter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-converter.d.ts","sourceRoot":"","sources":["../../../src/core/converters/json-converter.ts"],"names":[],"mappings":"AAOA,qBAAa,aAAa;IACxB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAkBrC,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAmB5D,OAAO,CAAC,mBAAmB;CAgB5B"}
@@ -0,0 +1,51 @@
1
+ import { readFileSync } from 'fs';
2
+ import path from 'path';
3
+ import { MarkdownParser } from '../parsers/markdown-parser.js';
4
+ import { ChangeParser } from '../parsers/change-parser.js';
5
+ import { FileSystemUtils } from '../../utils/file-system.js';
6
+ export class JsonConverter {
7
+ convertSpecToJson(filePath) {
8
+ const content = readFileSync(filePath, 'utf-8');
9
+ const parser = new MarkdownParser(content);
10
+ const specName = this.extractNameFromPath(filePath);
11
+ const spec = parser.parseSpec(specName);
12
+ const jsonSpec = {
13
+ ...spec,
14
+ metadata: {
15
+ ...spec.metadata,
16
+ sourcePath: filePath,
17
+ },
18
+ };
19
+ return JSON.stringify(jsonSpec, null, 2);
20
+ }
21
+ async convertChangeToJson(filePath) {
22
+ const content = readFileSync(filePath, 'utf-8');
23
+ const changeName = this.extractNameFromPath(filePath);
24
+ const changeDir = path.dirname(filePath);
25
+ const parser = new ChangeParser(content, changeDir);
26
+ const change = await parser.parseChangeWithDeltas(changeName);
27
+ const jsonChange = {
28
+ ...change,
29
+ metadata: {
30
+ ...change.metadata,
31
+ sourcePath: filePath,
32
+ },
33
+ };
34
+ return JSON.stringify(jsonChange, null, 2);
35
+ }
36
+ extractNameFromPath(filePath) {
37
+ const normalizedPath = FileSystemUtils.toPosixPath(filePath);
38
+ const parts = normalizedPath.split('/');
39
+ for (let i = parts.length - 1; i >= 0; i--) {
40
+ if (parts[i] === 'specs' || parts[i] === 'changes') {
41
+ if (i < parts.length - 1) {
42
+ return parts[i + 1];
43
+ }
44
+ }
45
+ }
46
+ const fileName = parts[parts.length - 1] ?? '';
47
+ const dotIndex = fileName.lastIndexOf('.');
48
+ return dotIndex > 0 ? fileName.slice(0, dotIndex) : fileName;
49
+ }
50
+ }
51
+ //# sourceMappingURL=json-converter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-converter.js","sourceRoot":"","sources":["../../../src/core/converters/json-converter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAE3D,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAE7D,MAAM,OAAO,aAAa;IACxB,iBAAiB,CAAC,QAAgB;QAChC,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAChD,MAAM,MAAM,GAAG,IAAI,cAAc,CAAC,OAAO,CAAC,CAAC;QAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,mBAAmB,CAAC,QAAQ,CAAC,CAAC;QAEpD,MAAM,IAAI,GAAG,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QAExC,MAAM,QAAQ,GAAG;YACf,GAAG,IAAI;YACP,QAAQ,EAAE;gBACR,GAAG,IAAI,CAAC,QAAQ;gBAChB,UAAU,EAAE,QAAQ;aACrB;SACF,CAAC;QAEF,OAAO,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAC3C,CAAC;IAED,KAAK,CAAC,mBAAmB,CAAC,QAAgB;QACxC,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAChD,MAAM,UAAU,GAAG,IAAI,CAAC,mBAAmB,CAAC,QAAQ,CAAC,CAAC;QACtD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACzC,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QAEpD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,qBAAqB,CAAC,UAAU,CAAC,CAAC;QAE9D,MAAM,UAAU,GAAG;YACjB,GAAG,MAAM;YACT,QAAQ,EAAE;gBACR,GAAG,MAAM,CAAC,QAAQ;gBAClB,UAAU,EAAE,QAAQ;aACrB;SACF,CAAC;QAEF,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAC7C,CAAC;IAEO,mBAAmB,CAAC,QAAgB;QAC1C,MAAM,cAAc,GAAG,eAAe,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;QAC7D,MAAM,KAAK,GAAG,cAAc,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAExC,KAAK,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3C,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,OAAO,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS,EAAE,CAAC;gBACnD,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACzB,OAAO,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;gBACtB,CAAC;YACH,CAAC;QACH,CAAC;QAED,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;QAC/C,MAAM,QAAQ,GAAG,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QAC3C,OAAO,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC/D,CAAC;CACF"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Dashboard git activity + health signals (ADR 001, D4-D7, D12, D16).
3
+ *
4
+ * Two `git log` runs produce a 30-day daily series: commits repo-wide vs
5
+ * commits touching `tospec/`. The gap between the two is the spec-drift
6
+ * signal. Pure aggregation is split from the git-spawning wrapper so vitest
7
+ * can exercise it without a repo.
8
+ */
9
+ export declare const DEFAULT_STALE_DAYS = 14;
10
+ /** Series window: trailing day count, or 'all' for the full git history. */
11
+ export type ActivityWindow = number | 'all';
12
+ export interface ActivityDay {
13
+ date: string;
14
+ repo: number;
15
+ tospec: number;
16
+ }
17
+ export interface DashboardActivity {
18
+ available: boolean;
19
+ reason?: string;
20
+ days: ActivityDay[];
21
+ specDrift: boolean;
22
+ staleDays: number;
23
+ }
24
+ /**
25
+ * Buckets two lists of commit dates (yyyy-mm-dd, from `git log --date=short`)
26
+ * into a zero-filled daily series covering the last `days` days ending `today`.
27
+ */
28
+ export declare function aggregateDaily(repoDates: string[], tospecDates: string[], days?: number, today?: Date): ActivityDay[];
29
+ /**
30
+ * Spec drift (D12): >=1 repo commit in the last `windowDays`, zero commits
31
+ * touching tospec/ in the same window, and at least one active change.
32
+ */
33
+ export declare function computeSpecDrift(days: ActivityDay[], activeChangeCount: number, windowDays?: number): boolean;
34
+ /**
35
+ * Days needed to cover every date in both series ending today (inclusive),
36
+ * never less than `minDays`. Dates are yyyy-mm-dd, so lexicographic min is
37
+ * the earliest.
38
+ */
39
+ export declare function historySpanDays(repoDates: string[], tospecDates: string[], minDays?: number, today?: Date): number;
40
+ /** Stale-change threshold from tospec/config.yaml, defaulting to 14 days. */
41
+ export declare function resolveStaleDays(projectRoot: string): number;
42
+ /**
43
+ * Collects the activity payload. `changeName` narrows the tospec series to
44
+ * that change's directory (detail view); the repo series stays repo-wide.
45
+ * `window` is the trailing day count (default 30) or 'all' for full history.
46
+ * Git being unavailable degrades to `{available: false}` (D6) — staleDays is
47
+ * config, not git, so it is always populated.
48
+ */
49
+ export declare function collectActivity(projectRoot: string, changeName?: string, window?: ActivityWindow): Promise<DashboardActivity>;
50
+ //# sourceMappingURL=dashboard-activity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard-activity.d.ts","sourceRoot":"","sources":["../../src/core/dashboard-activity.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AASH,eAAO,MAAM,kBAAkB,KAAK,CAAC;AAIrC,4EAA4E;AAC5E,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,KAAK,CAAC;AAE5C,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,WAAW,EAAE,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAcD;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,EAAE,EACnB,WAAW,EAAE,MAAM,EAAE,EACrB,IAAI,GAAE,MAAsB,EAC5B,KAAK,GAAE,IAAiB,GACvB,WAAW,EAAE,CAaf;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,WAAW,EAAE,EACnB,iBAAiB,EAAE,MAAM,EACzB,UAAU,GAAE,MAA0B,GACrC,OAAO,CAMT;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,MAAM,EAAE,EACnB,WAAW,EAAE,MAAM,EAAE,EACrB,OAAO,GAAE,MAAsB,EAC/B,KAAK,GAAE,IAAiB,GACvB,MAAM,CAWR;AAED,6EAA6E;AAC7E,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAM5D;AA8BD;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,EACnB,UAAU,CAAC,EAAE,MAAM,EACnB,MAAM,GAAE,cAA8B,GACrC,OAAO,CAAC,iBAAiB,CAAC,CAgC5B"}
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Dashboard git activity + health signals (ADR 001, D4-D7, D12, D16).
3
+ *
4
+ * Two `git log` runs produce a 30-day daily series: commits repo-wide vs
5
+ * commits touching `tospec/`. The gap between the two is the spec-drift
6
+ * signal. Pure aggregation is split from the git-spawning wrapper so vitest
7
+ * can exercise it without a repo.
8
+ */
9
+ import { execFile } from 'node:child_process';
10
+ import { promisify } from 'node:util';
11
+ import { readProjectConfig } from './project-config.js';
12
+ import { getActiveChangeIds } from '../utils/item-discovery.js';
13
+ const execFileAsync = promisify(execFile);
14
+ export const DEFAULT_STALE_DAYS = 14;
15
+ const ACTIVITY_DAYS = 30;
16
+ const DRIFT_WINDOW_DAYS = 7;
17
+ // -----------------------------------------------------------------------------
18
+ // Pure aggregation (unit-testable)
19
+ // -----------------------------------------------------------------------------
20
+ /** yyyy-mm-dd in local time. */
21
+ function isoDay(d) {
22
+ const y = d.getFullYear();
23
+ const m = String(d.getMonth() + 1).padStart(2, '0');
24
+ const day = String(d.getDate()).padStart(2, '0');
25
+ return `${y}-${m}-${day}`;
26
+ }
27
+ /**
28
+ * Buckets two lists of commit dates (yyyy-mm-dd, from `git log --date=short`)
29
+ * into a zero-filled daily series covering the last `days` days ending `today`.
30
+ */
31
+ export function aggregateDaily(repoDates, tospecDates, days = ACTIVITY_DAYS, today = new Date()) {
32
+ const repoCounts = new Map();
33
+ for (const d of repoDates)
34
+ repoCounts.set(d, (repoCounts.get(d) ?? 0) + 1);
35
+ const tospecCounts = new Map();
36
+ for (const d of tospecDates)
37
+ tospecCounts.set(d, (tospecCounts.get(d) ?? 0) + 1);
38
+ const out = [];
39
+ for (let i = days - 1; i >= 0; i--) {
40
+ const d = new Date(today.getFullYear(), today.getMonth(), today.getDate() - i);
41
+ const key = isoDay(d);
42
+ out.push({ date: key, repo: repoCounts.get(key) ?? 0, tospec: tospecCounts.get(key) ?? 0 });
43
+ }
44
+ return out;
45
+ }
46
+ /**
47
+ * Spec drift (D12): >=1 repo commit in the last `windowDays`, zero commits
48
+ * touching tospec/ in the same window, and at least one active change.
49
+ */
50
+ export function computeSpecDrift(days, activeChangeCount, windowDays = DRIFT_WINDOW_DAYS) {
51
+ if (activeChangeCount === 0)
52
+ return false;
53
+ const recent = days.slice(-windowDays);
54
+ const repoCommits = recent.reduce((sum, d) => sum + d.repo, 0);
55
+ const tospecCommits = recent.reduce((sum, d) => sum + d.tospec, 0);
56
+ return repoCommits > 0 && tospecCommits === 0;
57
+ }
58
+ /**
59
+ * Days needed to cover every date in both series ending today (inclusive),
60
+ * never less than `minDays`. Dates are yyyy-mm-dd, so lexicographic min is
61
+ * the earliest.
62
+ */
63
+ export function historySpanDays(repoDates, tospecDates, minDays = ACTIVITY_DAYS, today = new Date()) {
64
+ let earliest = '';
65
+ for (const d of [...repoDates, ...tospecDates]) {
66
+ if (!earliest || d < earliest)
67
+ earliest = d;
68
+ }
69
+ if (!earliest)
70
+ return minDays;
71
+ const [y, m, day] = earliest.split('-').map(Number);
72
+ const start = new Date(y, m - 1, day);
73
+ const end = new Date(today.getFullYear(), today.getMonth(), today.getDate());
74
+ const span = Math.round((end.getTime() - start.getTime()) / 86400000) + 1;
75
+ return Math.max(span, minDays);
76
+ }
77
+ /** Stale-change threshold from tospec/config.yaml, defaulting to 14 days. */
78
+ export function resolveStaleDays(projectRoot) {
79
+ try {
80
+ return readProjectConfig(projectRoot)?.dashboard?.staleDays ?? DEFAULT_STALE_DAYS;
81
+ }
82
+ catch {
83
+ return DEFAULT_STALE_DAYS;
84
+ }
85
+ }
86
+ // -----------------------------------------------------------------------------
87
+ // Git wrapper
88
+ // -----------------------------------------------------------------------------
89
+ /** Commit dates (yyyy-mm-dd, one per commit), newest first. */
90
+ async function gitLogDates(projectRoot, window, pathFilters) {
91
+ const args = ['log', '--format=%cd', '--date=short'];
92
+ if (window !== 'all')
93
+ args.splice(1, 0, `--since=${window} days ago`);
94
+ if (pathFilters)
95
+ args.push('--', ...pathFilters);
96
+ const { stdout } = await execFileAsync('git', args, { cwd: projectRoot });
97
+ return stdout.split(/\r?\n/).filter((line) => /^\d{4}-\d{2}-\d{2}$/.test(line));
98
+ }
99
+ /** null when git is usable, otherwise the reason string for the API payload. */
100
+ async function gitUnavailableReason(projectRoot) {
101
+ try {
102
+ await execFileAsync('git', ['rev-parse', '--is-inside-work-tree'], { cwd: projectRoot });
103
+ return null;
104
+ }
105
+ catch (err) {
106
+ const code = err.code;
107
+ return code === 'ENOENT' ? 'git not found' : 'not a git repository';
108
+ }
109
+ }
110
+ /**
111
+ * Collects the activity payload. `changeName` narrows the tospec series to
112
+ * that change's directory (detail view); the repo series stays repo-wide.
113
+ * `window` is the trailing day count (default 30) or 'all' for full history.
114
+ * Git being unavailable degrades to `{available: false}` (D6) — staleDays is
115
+ * config, not git, so it is always populated.
116
+ */
117
+ export async function collectActivity(projectRoot, changeName, window = ACTIVITY_DAYS) {
118
+ const staleDays = resolveStaleDays(projectRoot);
119
+ const reason = await gitUnavailableReason(projectRoot);
120
+ if (reason !== null) {
121
+ return { available: false, reason, days: [], specDrift: false, staleDays };
122
+ }
123
+ // `tospec migrate` copies openspec/ into tospec/, so commit history for
124
+ // migrated changes lives under openspec/ paths. A pathspec that matches
125
+ // nothing is harmless, so always include the legacy prefix.
126
+ // ponytail: only covers the default `openspec` source dir; record custom
127
+ // migrate source dirs in config if anyone needs them counted.
128
+ const pathFilters = changeName
129
+ ? [`tospec/changes/${changeName}/`, `openspec/changes/${changeName}/`]
130
+ : ['tospec/', 'openspec/'];
131
+ const [repoDates, tospecDates] = await Promise.all([
132
+ gitLogDates(projectRoot, window),
133
+ gitLogDates(projectRoot, window, pathFilters),
134
+ ]);
135
+ // ponytail: 'all' zero-fills one entry per day since the first commit; a
136
+ // decade-old repo means a few thousand points, coarser buckets if that hurts.
137
+ const spanDays = window === 'all' ? historySpanDays(repoDates, tospecDates) : window;
138
+ const days = aggregateDaily(repoDates, tospecDates, spanDays);
139
+ // Drift only makes sense repo-wide, not for a single change's series.
140
+ let specDrift = false;
141
+ if (!changeName) {
142
+ const activeChanges = await getActiveChangeIds(projectRoot);
143
+ specDrift = computeSpecDrift(days, activeChanges.length);
144
+ }
145
+ return { available: true, days, specDrift, staleDays };
146
+ }
147
+ //# sourceMappingURL=dashboard-activity.js.map