@shrkcrft/cli 0.1.0-alpha.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 (450) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +15 -0
  3. package/dist/asset-preview/apply-action-hint-stub.d.ts +28 -0
  4. package/dist/asset-preview/apply-action-hint-stub.d.ts.map +1 -0
  5. package/dist/asset-preview/apply-action-hint-stub.js +170 -0
  6. package/dist/asset-preview/apply-asset-preview.d.ts +31 -0
  7. package/dist/asset-preview/apply-asset-preview.d.ts.map +1 -0
  8. package/dist/asset-preview/apply-asset-preview.js +210 -0
  9. package/dist/asset-preview/apply-knowledge-stale-fix.d.ts +37 -0
  10. package/dist/asset-preview/apply-knowledge-stale-fix.d.ts.map +1 -0
  11. package/dist/asset-preview/apply-knowledge-stale-fix.js +344 -0
  12. package/dist/asset-preview/apply-missing-barrel.d.ts +15 -0
  13. package/dist/asset-preview/apply-missing-barrel.d.ts.map +1 -0
  14. package/dist/asset-preview/apply-missing-barrel.js +65 -0
  15. package/dist/asset-preview/apply-template-drift-fix.d.ts +21 -0
  16. package/dist/asset-preview/apply-template-drift-fix.d.ts.map +1 -0
  17. package/dist/asset-preview/apply-template-drift-fix.js +125 -0
  18. package/dist/asset-preview/apply-template-update.d.ts +43 -0
  19. package/dist/asset-preview/apply-template-update.d.ts.map +1 -0
  20. package/dist/asset-preview/apply-template-update.js +257 -0
  21. package/dist/asset-preview/entry-mutator.d.ts +106 -0
  22. package/dist/asset-preview/entry-mutator.d.ts.map +1 -0
  23. package/dist/asset-preview/entry-mutator.js +428 -0
  24. package/dist/authoring/authoring-kit.d.ts +36 -0
  25. package/dist/authoring/authoring-kit.d.ts.map +1 -0
  26. package/dist/authoring/authoring-kit.js +106 -0
  27. package/dist/command-registry.d.ts +158 -0
  28. package/dist/command-registry.d.ts.map +1 -0
  29. package/dist/command-registry.js +348 -0
  30. package/dist/commands/apply.command.d.ts +3 -0
  31. package/dist/commands/apply.command.d.ts.map +1 -0
  32. package/dist/commands/apply.command.js +879 -0
  33. package/dist/commands/architecture.command.d.ts +5 -0
  34. package/dist/commands/architecture.command.d.ts.map +1 -0
  35. package/dist/commands/architecture.command.js +141 -0
  36. package/dist/commands/ask.command.d.ts +3 -0
  37. package/dist/commands/ask.command.d.ts.map +1 -0
  38. package/dist/commands/ask.command.js +58 -0
  39. package/dist/commands/audit.command.d.ts +3 -0
  40. package/dist/commands/audit.command.d.ts.map +1 -0
  41. package/dist/commands/audit.command.js +141 -0
  42. package/dist/commands/biome.command.d.ts +7 -0
  43. package/dist/commands/biome.command.d.ts.map +1 -0
  44. package/dist/commands/biome.command.js +350 -0
  45. package/dist/commands/boundaries.command.d.ts +9 -0
  46. package/dist/commands/boundaries.command.d.ts.map +1 -0
  47. package/dist/commands/boundaries.command.js +314 -0
  48. package/dist/commands/brief.command.d.ts +3 -0
  49. package/dist/commands/brief.command.d.ts.map +1 -0
  50. package/dist/commands/brief.command.js +206 -0
  51. package/dist/commands/bundle.command.d.ts +3 -0
  52. package/dist/commands/bundle.command.d.ts.map +1 -0
  53. package/dist/commands/bundle.command.js +1183 -0
  54. package/dist/commands/changes.command.d.ts +3 -0
  55. package/dist/commands/changes.command.d.ts.map +1 -0
  56. package/dist/commands/changes.command.js +155 -0
  57. package/dist/commands/check.command.d.ts +3 -0
  58. package/dist/commands/check.command.d.ts.map +1 -0
  59. package/dist/commands/check.command.js +553 -0
  60. package/dist/commands/checks.command.d.ts +29 -0
  61. package/dist/commands/checks.command.d.ts.map +1 -0
  62. package/dist/commands/checks.command.js +521 -0
  63. package/dist/commands/ci.command.d.ts +3 -0
  64. package/dist/commands/ci.command.d.ts.map +1 -0
  65. package/dist/commands/ci.command.js +680 -0
  66. package/dist/commands/codemod.command.d.ts +3 -0
  67. package/dist/commands/codemod.command.d.ts.map +1 -0
  68. package/dist/commands/codemod.command.js +130 -0
  69. package/dist/commands/command-catalog.d.ts +265 -0
  70. package/dist/commands/command-catalog.d.ts.map +1 -0
  71. package/dist/commands/command-catalog.js +3242 -0
  72. package/dist/commands/commands.command.d.ts +92 -0
  73. package/dist/commands/commands.command.d.ts.map +1 -0
  74. package/dist/commands/commands.command.js +1208 -0
  75. package/dist/commands/constructs.command.d.ts +15 -0
  76. package/dist/commands/constructs.command.d.ts.map +1 -0
  77. package/dist/commands/constructs.command.js +669 -0
  78. package/dist/commands/context.command.d.ts +3 -0
  79. package/dist/commands/context.command.d.ts.map +1 -0
  80. package/dist/commands/context.command.js +120 -0
  81. package/dist/commands/contract-gate.command.d.ts +5 -0
  82. package/dist/commands/contract-gate.command.d.ts.map +1 -0
  83. package/dist/commands/contract-gate.command.js +208 -0
  84. package/dist/commands/contract-templates.command.d.ts +8 -0
  85. package/dist/commands/contract-templates.command.d.ts.map +1 -0
  86. package/dist/commands/contract-templates.command.js +151 -0
  87. package/dist/commands/contract.command.d.ts +3 -0
  88. package/dist/commands/contract.command.d.ts.map +1 -0
  89. package/dist/commands/contract.command.js +105 -0
  90. package/dist/commands/conventions.command.d.ts +8 -0
  91. package/dist/commands/conventions.command.d.ts.map +1 -0
  92. package/dist/commands/conventions.command.js +169 -0
  93. package/dist/commands/coverage.command.d.ts +3 -0
  94. package/dist/commands/coverage.command.d.ts.map +1 -0
  95. package/dist/commands/coverage.command.js +56 -0
  96. package/dist/commands/daily.commands.d.ts +5 -0
  97. package/dist/commands/daily.commands.d.ts.map +1 -0
  98. package/dist/commands/daily.commands.js +224 -0
  99. package/dist/commands/dashboard-export.command.d.ts +4 -0
  100. package/dist/commands/dashboard-export.command.d.ts.map +1 -0
  101. package/dist/commands/dashboard-export.command.js +86 -0
  102. package/dist/commands/dashboard.command.d.ts +3 -0
  103. package/dist/commands/dashboard.command.d.ts.map +1 -0
  104. package/dist/commands/dashboard.command.js +106 -0
  105. package/dist/commands/dev.command.d.ts +3 -0
  106. package/dist/commands/dev.command.d.ts.map +1 -0
  107. package/dist/commands/dev.command.js +1392 -0
  108. package/dist/commands/diagnostics.command.d.ts +5 -0
  109. package/dist/commands/diagnostics.command.d.ts.map +1 -0
  110. package/dist/commands/diagnostics.command.js +97 -0
  111. package/dist/commands/docs.command.d.ts +4 -0
  112. package/dist/commands/docs.command.d.ts.map +1 -0
  113. package/dist/commands/docs.command.js +34 -0
  114. package/dist/commands/doctor.command.d.ts +7 -0
  115. package/dist/commands/doctor.command.d.ts.map +1 -0
  116. package/dist/commands/doctor.command.js +681 -0
  117. package/dist/commands/drift.command.d.ts +3 -0
  118. package/dist/commands/drift.command.d.ts.map +1 -0
  119. package/dist/commands/drift.command.js +124 -0
  120. package/dist/commands/eslint.command.d.ts +7 -0
  121. package/dist/commands/eslint.command.d.ts.map +1 -0
  122. package/dist/commands/eslint.command.js +423 -0
  123. package/dist/commands/explore.command.d.ts +3 -0
  124. package/dist/commands/explore.command.d.ts.map +1 -0
  125. package/dist/commands/explore.command.js +65 -0
  126. package/dist/commands/export-bundle.command.d.ts +6 -0
  127. package/dist/commands/export-bundle.command.d.ts.map +1 -0
  128. package/dist/commands/export-bundle.command.js +96 -0
  129. package/dist/commands/export.command.d.ts +3 -0
  130. package/dist/commands/export.command.d.ts.map +1 -0
  131. package/dist/commands/export.command.js +83 -0
  132. package/dist/commands/feedback-dispatch.command.d.ts +12 -0
  133. package/dist/commands/feedback-dispatch.command.d.ts.map +1 -0
  134. package/dist/commands/feedback-dispatch.command.js +63 -0
  135. package/dist/commands/feedback.command.d.ts +11 -0
  136. package/dist/commands/feedback.command.d.ts.map +1 -0
  137. package/dist/commands/feedback.command.js +336 -0
  138. package/dist/commands/fix.command.d.ts +3 -0
  139. package/dist/commands/fix.command.d.ts.map +1 -0
  140. package/dist/commands/fix.command.js +776 -0
  141. package/dist/commands/gen.command.d.ts +3 -0
  142. package/dist/commands/gen.command.d.ts.map +1 -0
  143. package/dist/commands/gen.command.js +136 -0
  144. package/dist/commands/git.command.d.ts +6 -0
  145. package/dist/commands/git.command.d.ts.map +1 -0
  146. package/dist/commands/git.command.js +81 -0
  147. package/dist/commands/graph.command.d.ts +3 -0
  148. package/dist/commands/graph.command.d.ts.map +1 -0
  149. package/dist/commands/graph.command.js +287 -0
  150. package/dist/commands/grounding.command.d.ts +7 -0
  151. package/dist/commands/grounding.command.d.ts.map +1 -0
  152. package/dist/commands/grounding.command.js +54 -0
  153. package/dist/commands/help.command.d.ts +20 -0
  154. package/dist/commands/help.command.d.ts.map +1 -0
  155. package/dist/commands/help.command.js +127 -0
  156. package/dist/commands/helper.command.d.ts +6 -0
  157. package/dist/commands/helper.command.d.ts.map +1 -0
  158. package/dist/commands/helper.command.js +170 -0
  159. package/dist/commands/ide.command.d.ts +6 -0
  160. package/dist/commands/ide.command.d.ts.map +1 -0
  161. package/dist/commands/ide.command.js +340 -0
  162. package/dist/commands/impact.command.d.ts +3 -0
  163. package/dist/commands/impact.command.d.ts.map +1 -0
  164. package/dist/commands/impact.command.js +819 -0
  165. package/dist/commands/import.command.d.ts +3 -0
  166. package/dist/commands/import.command.d.ts.map +1 -0
  167. package/dist/commands/import.command.js +115 -0
  168. package/dist/commands/infer.command.d.ts +3 -0
  169. package/dist/commands/infer.command.d.ts.map +1 -0
  170. package/dist/commands/infer.command.js +227 -0
  171. package/dist/commands/ingest.command.d.ts +6 -0
  172. package/dist/commands/ingest.command.d.ts.map +1 -0
  173. package/dist/commands/ingest.command.js +532 -0
  174. package/dist/commands/init.command.d.ts +3 -0
  175. package/dist/commands/init.command.d.ts.map +1 -0
  176. package/dist/commands/init.command.js +301 -0
  177. package/dist/commands/inspect.command.d.ts +3 -0
  178. package/dist/commands/inspect.command.d.ts.map +1 -0
  179. package/dist/commands/inspect.command.js +122 -0
  180. package/dist/commands/knowledge-author.command.d.ts +22 -0
  181. package/dist/commands/knowledge-author.command.d.ts.map +1 -0
  182. package/dist/commands/knowledge-author.command.js +366 -0
  183. package/dist/commands/knowledge-propose.command.d.ts +3 -0
  184. package/dist/commands/knowledge-propose.command.d.ts.map +1 -0
  185. package/dist/commands/knowledge-propose.command.js +125 -0
  186. package/dist/commands/knowledge.command.d.ts +18 -0
  187. package/dist/commands/knowledge.command.d.ts.map +1 -0
  188. package/dist/commands/knowledge.command.js +538 -0
  189. package/dist/commands/languages.command.d.ts +3 -0
  190. package/dist/commands/languages.command.d.ts.map +1 -0
  191. package/dist/commands/languages.command.js +300 -0
  192. package/dist/commands/lint.command.d.ts +15 -0
  193. package/dist/commands/lint.command.d.ts.map +1 -0
  194. package/dist/commands/lint.command.js +194 -0
  195. package/dist/commands/mcp.command.d.ts +3 -0
  196. package/dist/commands/mcp.command.d.ts.map +1 -0
  197. package/dist/commands/mcp.command.js +74 -0
  198. package/dist/commands/memory.command.d.ts +11 -0
  199. package/dist/commands/memory.command.d.ts.map +1 -0
  200. package/dist/commands/memory.command.js +264 -0
  201. package/dist/commands/onboard.command.d.ts +3 -0
  202. package/dist/commands/onboard.command.d.ts.map +1 -0
  203. package/dist/commands/onboard.command.js +650 -0
  204. package/dist/commands/orchestrate.command.d.ts +3 -0
  205. package/dist/commands/orchestrate.command.d.ts.map +1 -0
  206. package/dist/commands/orchestrate.command.js +49 -0
  207. package/dist/commands/owners.command.d.ts +5 -0
  208. package/dist/commands/owners.command.d.ts.map +1 -0
  209. package/dist/commands/owners.command.js +113 -0
  210. package/dist/commands/ownership.command.d.ts +5 -0
  211. package/dist/commands/ownership.command.d.ts.map +1 -0
  212. package/dist/commands/ownership.command.js +117 -0
  213. package/dist/commands/pack-author.command.d.ts +30 -0
  214. package/dist/commands/pack-author.command.d.ts.map +1 -0
  215. package/dist/commands/pack-author.command.js +242 -0
  216. package/dist/commands/packs-new.d.ts +27 -0
  217. package/dist/commands/packs-new.d.ts.map +1 -0
  218. package/dist/commands/packs-new.js +805 -0
  219. package/dist/commands/packs.command.d.ts +15 -0
  220. package/dist/commands/packs.command.d.ts.map +1 -0
  221. package/dist/commands/packs.command.js +958 -0
  222. package/dist/commands/paths.command.d.ts +6 -0
  223. package/dist/commands/paths.command.d.ts.map +1 -0
  224. package/dist/commands/paths.command.js +97 -0
  225. package/dist/commands/pipelines.command.d.ts +9 -0
  226. package/dist/commands/pipelines.command.d.ts.map +1 -0
  227. package/dist/commands/pipelines.command.js +308 -0
  228. package/dist/commands/plan-check.command.d.ts +27 -0
  229. package/dist/commands/plan-check.command.d.ts.map +1 -0
  230. package/dist/commands/plan-check.command.js +150 -0
  231. package/dist/commands/plan-simulate.command.d.ts +3 -0
  232. package/dist/commands/plan-simulate.command.d.ts.map +1 -0
  233. package/dist/commands/plan-simulate.command.js +60 -0
  234. package/dist/commands/plan.command.d.ts +8 -0
  235. package/dist/commands/plan.command.d.ts.map +1 -0
  236. package/dist/commands/plan.command.js +139 -0
  237. package/dist/commands/playbooks.command.d.ts +10 -0
  238. package/dist/commands/playbooks.command.d.ts.map +1 -0
  239. package/dist/commands/playbooks.command.js +296 -0
  240. package/dist/commands/plugin.command.d.ts +11 -0
  241. package/dist/commands/plugin.command.d.ts.map +1 -0
  242. package/dist/commands/plugin.command.js +394 -0
  243. package/dist/commands/policy.command.d.ts +8 -0
  244. package/dist/commands/policy.command.d.ts.map +1 -0
  245. package/dist/commands/policy.command.js +451 -0
  246. package/dist/commands/pr.command.d.ts +3 -0
  247. package/dist/commands/pr.command.d.ts.map +1 -0
  248. package/dist/commands/pr.command.js +132 -0
  249. package/dist/commands/preflight.command.d.ts +3 -0
  250. package/dist/commands/preflight.command.d.ts.map +1 -0
  251. package/dist/commands/preflight.command.js +102 -0
  252. package/dist/commands/presets.command.d.ts +17 -0
  253. package/dist/commands/presets.command.d.ts.map +1 -0
  254. package/dist/commands/presets.command.js +647 -0
  255. package/dist/commands/profiles.command.d.ts +7 -0
  256. package/dist/commands/profiles.command.d.ts.map +1 -0
  257. package/dist/commands/profiles.command.js +151 -0
  258. package/dist/commands/provenance.command.d.ts +26 -0
  259. package/dist/commands/provenance.command.d.ts.map +1 -0
  260. package/dist/commands/provenance.command.js +237 -0
  261. package/dist/commands/quality.command.d.ts +5 -0
  262. package/dist/commands/quality.command.d.ts.map +1 -0
  263. package/dist/commands/quality.command.js +69 -0
  264. package/dist/commands/recommend.command.d.ts +4 -0
  265. package/dist/commands/recommend.command.d.ts.map +1 -0
  266. package/dist/commands/recommend.command.js +270 -0
  267. package/dist/commands/registrations.command.d.ts +3 -0
  268. package/dist/commands/registrations.command.d.ts.map +1 -0
  269. package/dist/commands/registrations.command.js +300 -0
  270. package/dist/commands/registry.command.d.ts +4 -0
  271. package/dist/commands/registry.command.d.ts.map +1 -0
  272. package/dist/commands/registry.command.js +37 -0
  273. package/dist/commands/release.command.d.ts +4 -0
  274. package/dist/commands/release.command.d.ts.map +1 -0
  275. package/dist/commands/release.command.js +639 -0
  276. package/dist/commands/repo.command.d.ts +3 -0
  277. package/dist/commands/repo.command.d.ts.map +1 -0
  278. package/dist/commands/repo.command.js +24 -0
  279. package/dist/commands/report.command.d.ts +3 -0
  280. package/dist/commands/report.command.d.ts.map +1 -0
  281. package/dist/commands/report.command.js +511 -0
  282. package/dist/commands/reposet.command.d.ts +6 -0
  283. package/dist/commands/reposet.command.d.ts.map +1 -0
  284. package/dist/commands/reposet.command.js +120 -0
  285. package/dist/commands/review.command.d.ts +3 -0
  286. package/dist/commands/review.command.d.ts.map +1 -0
  287. package/dist/commands/review.command.js +354 -0
  288. package/dist/commands/risk.command.d.ts +3 -0
  289. package/dist/commands/risk.command.d.ts.map +1 -0
  290. package/dist/commands/risk.command.js +56 -0
  291. package/dist/commands/rounds.command.d.ts +8 -0
  292. package/dist/commands/rounds.command.d.ts.map +1 -0
  293. package/dist/commands/rounds.command.js +180 -0
  294. package/dist/commands/rules.command.d.ts +49 -0
  295. package/dist/commands/rules.command.d.ts.map +1 -0
  296. package/dist/commands/rules.command.js +435 -0
  297. package/dist/commands/runtime.command.d.ts +3 -0
  298. package/dist/commands/runtime.command.d.ts.map +1 -0
  299. package/dist/commands/runtime.command.js +56 -0
  300. package/dist/commands/safety.command.d.ts +3 -0
  301. package/dist/commands/safety.command.d.ts.map +1 -0
  302. package/dist/commands/safety.command.js +117 -0
  303. package/dist/commands/scaffolds.command.d.ts +5 -0
  304. package/dist/commands/scaffolds.command.d.ts.map +1 -0
  305. package/dist/commands/scaffolds.command.js +122 -0
  306. package/dist/commands/schemas.command.d.ts +21 -0
  307. package/dist/commands/schemas.command.d.ts.map +1 -0
  308. package/dist/commands/schemas.command.js +296 -0
  309. package/dist/commands/search.command.d.ts +12 -0
  310. package/dist/commands/search.command.d.ts.map +1 -0
  311. package/dist/commands/search.command.js +275 -0
  312. package/dist/commands/self-config.command.d.ts +7 -0
  313. package/dist/commands/self-config.command.d.ts.map +1 -0
  314. package/dist/commands/self-config.command.js +156 -0
  315. package/dist/commands/self.command.d.ts +3 -0
  316. package/dist/commands/self.command.d.ts.map +1 -0
  317. package/dist/commands/self.command.js +117 -0
  318. package/dist/commands/simulate.command.d.ts +3 -0
  319. package/dist/commands/simulate.command.d.ts.map +1 -0
  320. package/dist/commands/simulate.command.js +54 -0
  321. package/dist/commands/spec.command.d.ts +29 -0
  322. package/dist/commands/spec.command.d.ts.map +1 -0
  323. package/dist/commands/spec.command.js +985 -0
  324. package/dist/commands/start-here.command.d.ts +3 -0
  325. package/dist/commands/start-here.command.d.ts.map +1 -0
  326. package/dist/commands/start-here.command.js +35 -0
  327. package/dist/commands/stats.command.d.ts +3 -0
  328. package/dist/commands/stats.command.d.ts.map +1 -0
  329. package/dist/commands/stats.command.js +88 -0
  330. package/dist/commands/surface.command.d.ts +15 -0
  331. package/dist/commands/surface.command.d.ts.map +1 -0
  332. package/dist/commands/surface.command.js +328 -0
  333. package/dist/commands/task-context.command.d.ts +7 -0
  334. package/dist/commands/task-context.command.d.ts.map +1 -0
  335. package/dist/commands/task-context.command.js +646 -0
  336. package/dist/commands/task.command.d.ts +3 -0
  337. package/dist/commands/task.command.d.ts.map +1 -0
  338. package/dist/commands/task.command.js +301 -0
  339. package/dist/commands/template-quality.command.d.ts +5 -0
  340. package/dist/commands/template-quality.command.d.ts.map +1 -0
  341. package/dist/commands/template-quality.command.js +128 -0
  342. package/dist/commands/templates.command.d.ts +26 -0
  343. package/dist/commands/templates.command.d.ts.map +1 -0
  344. package/dist/commands/templates.command.js +964 -0
  345. package/dist/commands/test.command.d.ts +3 -0
  346. package/dist/commands/test.command.d.ts.map +1 -0
  347. package/dist/commands/test.command.js +262 -0
  348. package/dist/commands/tests.command.d.ts +5 -0
  349. package/dist/commands/tests.command.d.ts.map +1 -0
  350. package/dist/commands/tests.command.js +97 -0
  351. package/dist/commands/trace.command.d.ts +3 -0
  352. package/dist/commands/trace.command.d.ts.map +1 -0
  353. package/dist/commands/trace.command.js +121 -0
  354. package/dist/commands/upgrade.command.d.ts +4 -0
  355. package/dist/commands/upgrade.command.d.ts.map +1 -0
  356. package/dist/commands/upgrade.command.js +43 -0
  357. package/dist/commands/version.command.d.ts +3 -0
  358. package/dist/commands/version.command.d.ts.map +1 -0
  359. package/dist/commands/version.command.js +10 -0
  360. package/dist/commands/why.command.d.ts +24 -0
  361. package/dist/commands/why.command.d.ts.map +1 -0
  362. package/dist/commands/why.command.js +119 -0
  363. package/dist/dashboard/dashboard-api-server.d.ts +21 -0
  364. package/dist/dashboard/dashboard-api-server.d.ts.map +1 -0
  365. package/dist/dashboard/dashboard-api-server.js +410 -0
  366. package/dist/dashboard/live-session-server.d.ts +18 -0
  367. package/dist/dashboard/live-session-server.d.ts.map +1 -0
  368. package/dist/dashboard/live-session-server.js +133 -0
  369. package/dist/diff/collect-changed-paths.d.ts +27 -0
  370. package/dist/diff/collect-changed-paths.d.ts.map +1 -0
  371. package/dist/diff/collect-changed-paths.js +68 -0
  372. package/dist/doctor/doctor-tags.d.ts +63 -0
  373. package/dist/doctor/doctor-tags.d.ts.map +1 -0
  374. package/dist/doctor/doctor-tags.js +146 -0
  375. package/dist/export/export-formats.d.ts +22 -0
  376. package/dist/export/export-formats.d.ts.map +1 -0
  377. package/dist/export/export-formats.js +135 -0
  378. package/dist/index.d.ts +22 -0
  379. package/dist/index.d.ts.map +1 -0
  380. package/dist/index.js +21 -0
  381. package/dist/init/detected-block.d.ts +57 -0
  382. package/dist/init/detected-block.d.ts.map +1 -0
  383. package/dist/init/detected-block.js +197 -0
  384. package/dist/init/gitignore.d.ts +30 -0
  385. package/dist/init/gitignore.d.ts.map +1 -0
  386. package/dist/init/gitignore.js +110 -0
  387. package/dist/init/init-templates.d.ts +6 -0
  388. package/dist/init/init-templates.d.ts.map +1 -0
  389. package/dist/init/init-templates.js +413 -0
  390. package/dist/main.d.ts +18 -0
  391. package/dist/main.d.ts.map +1 -0
  392. package/dist/main.js +699 -0
  393. package/dist/output/failure-hints.d.ts +55 -0
  394. package/dist/output/failure-hints.d.ts.map +1 -0
  395. package/dist/output/failure-hints.js +159 -0
  396. package/dist/output/format-output.d.ts +9 -0
  397. package/dist/output/format-output.d.ts.map +1 -0
  398. package/dist/output/format-output.js +26 -0
  399. package/dist/output/print-error.d.ts +3 -0
  400. package/dist/output/print-error.d.ts.map +1 -0
  401. package/dist/output/print-error.js +14 -0
  402. package/dist/output/watch-loop.d.ts +37 -0
  403. package/dist/output/watch-loop.d.ts.map +1 -0
  404. package/dist/output/watch-loop.js +115 -0
  405. package/dist/schemas/json-schemas.d.ts +1630 -0
  406. package/dist/schemas/json-schemas.d.ts.map +1 -0
  407. package/dist/schemas/json-schemas.js +811 -0
  408. package/dist/surface/about.d.ts +10 -0
  409. package/dist/surface/about.d.ts.map +1 -0
  410. package/dist/surface/about.js +53 -0
  411. package/dist/surface/load-surface-context.d.ts +34 -0
  412. package/dist/surface/load-surface-context.d.ts.map +1 -0
  413. package/dist/surface/load-surface-context.js +100 -0
  414. package/dist/surface/no-args-landing.d.ts +7 -0
  415. package/dist/surface/no-args-landing.d.ts.map +1 -0
  416. package/dist/surface/no-args-landing.js +36 -0
  417. package/dist/surface/not-enabled-error.d.ts +24 -0
  418. package/dist/surface/not-enabled-error.d.ts.map +1 -0
  419. package/dist/surface/not-enabled-error.js +36 -0
  420. package/dist/surface/profiles.d.ts +37 -0
  421. package/dist/surface/profiles.d.ts.map +1 -0
  422. package/dist/surface/profiles.js +151 -0
  423. package/dist/surface/shape-defaults.d.ts +21 -0
  424. package/dist/surface/shape-defaults.d.ts.map +1 -0
  425. package/dist/surface/shape-defaults.js +50 -0
  426. package/dist/surface/spine-extractor.d.ts +38 -0
  427. package/dist/surface/spine-extractor.d.ts.map +1 -0
  428. package/dist/surface/spine-extractor.js +100 -0
  429. package/dist/surface/surface-config-writer.d.ts +59 -0
  430. package/dist/surface/surface-config-writer.d.ts.map +1 -0
  431. package/dist/surface/surface-config-writer.js +135 -0
  432. package/dist/surface/surface-summary.d.ts +66 -0
  433. package/dist/surface/surface-summary.d.ts.map +1 -0
  434. package/dist/surface/surface-summary.js +162 -0
  435. package/dist/surface/tier.d.ts +100 -0
  436. package/dist/surface/tier.d.ts.map +1 -0
  437. package/dist/surface/tier.js +172 -0
  438. package/dist/task-next/apply-batch-runner.d.ts +42 -0
  439. package/dist/task-next/apply-batch-runner.d.ts.map +1 -0
  440. package/dist/task-next/apply-batch-runner.js +192 -0
  441. package/dist/task-next/task-next-ranker.d.ts +75 -0
  442. package/dist/task-next/task-next-ranker.d.ts.map +1 -0
  443. package/dist/task-next/task-next-ranker.js +179 -0
  444. package/dist/usage/usage-log.d.ts +54 -0
  445. package/dist/usage/usage-log.d.ts.map +1 -0
  446. package/dist/usage/usage-log.js +105 -0
  447. package/dist/validation/run-validation-loop.d.ts +38 -0
  448. package/dist/validation/run-validation-loop.d.ts.map +1 -0
  449. package/dist/validation/run-validation-loop.js +100 -0
  450. package/package.json +73 -0
@@ -0,0 +1,985 @@
1
+ /**
2
+ * `shrk spec` surface.
3
+ *
4
+ * - `spec create "<title>"` — ground a new spec under .sharkcraft/specs/.
5
+ * - `spec review <id>` — structural + cross-registry validation.
6
+ * - `spec implement <id>` — compose proposedTemplates into a signed plan.
7
+ * - `spec verify <id>` — run trusted verification commands + checks.
8
+ * - `spec list` — list every spec.
9
+ * - `spec show <id>` — print spec contents.
10
+ * - `spec status <id>` — read/transition status.
11
+ * - `spec lint <id>` — fast structural-only lint.
12
+ *
13
+ * Preview-first everywhere. `--write` / `--apply` opt-in.
14
+ */
15
+ import { execSync } from 'node:child_process';
16
+ import { createHash } from 'node:crypto';
17
+ import { existsSync, readFileSync, writeFileSync } from 'node:fs';
18
+ import * as nodePath from 'node:path';
19
+ import { appendSpecEvent, buildSavedPlan, buildSpecId, canonicalJson, deriveSpecJson, FileChangeType, generate, listSpecIds, loadSpec, OverwriteStrategy, persistSpecArtifacts, PLAN_SECRET_ENV, readSpecEvents, renderSpecMd, savePlanToFile, signPlan, specDir, specMdPath, specPlanPath, specVerificationPath, splitSpecMd, SPEC_SCHEMA_V1, SpecStatus, validateSpecStructural, verifyPlan, writeSpecJson, writeSpecMd, } from '@shrkcrft/generator';
20
+ import { AssetProvenanceOperation, AssetProvenanceSource, buildSpecList, buildSpecReview, buildTaskPacket, inspectSharkcraft, recordProvenance, SPEC_LIST_SCHEMA, } from '@shrkcrft/inspector';
21
+ import { flagBool, flagList, flagString, resolveCwd, } from "../command-registry.js";
22
+ import { collectChangedPaths } from "../diff/collect-changed-paths.js";
23
+ import { asJson, header } from "../output/format-output.js";
24
+ // Bonus DX item — `spec implement --apply` now dispatches into
25
+ // applyCommand instead of asking the user to run apply separately.
26
+ import { applyCommand } from "./apply.command.js";
27
+ const DEFAULT_RELATED_LIMIT = 5;
28
+ export const SPEC_IMPLEMENT_SCHEMA = 'sharkcraft.spec-implement/v1';
29
+ export const SPEC_VERIFICATION_SCHEMA = 'sharkcraft.spec-verification/v1';
30
+ export const specCreateCommand = {
31
+ name: 'create',
32
+ description: "Scaffold a grounded spec under .sharkcraft/specs/<id>/. Preview-only by default; pass --write to land. The engine fills the grounding fields (relevantRules / Knowledge / Paths / Templates / VerificationCommands); the human or agent fills the intent / motivation / acceptance.",
33
+ usage: 'shrk spec create "<title>" [--slug <slug>] [--write] [--issue <url>] [--related-knowledge <id,..>] [--related-rule <id,..>] [--related-path <id,..>] [--template <id,..>] [--limit 5] [--force] [--json]',
34
+ async run(args) {
35
+ const title = args.positional[0];
36
+ if (!title || title.trim().length === 0) {
37
+ process.stderr.write('Usage: shrk spec create "<title>" [--write]\n');
38
+ return 2;
39
+ }
40
+ const cwd = resolveCwd(args);
41
+ const inspection = await inspectSharkcraft({ cwd });
42
+ const slugOverride = flagString(args, 'slug');
43
+ const existing = listSpecIds(cwd);
44
+ const built = buildSpecId({
45
+ title,
46
+ ...(slugOverride !== undefined ? { slug: slugOverride } : {}),
47
+ existingIds: existing,
48
+ });
49
+ const limit = parseLimit(flagString(args, 'limit')) ?? DEFAULT_RELATED_LIMIT;
50
+ const force = flagBool(args, 'force');
51
+ const cliRelatedKnowledge = flagList(args, 'related-knowledge');
52
+ const cliRelatedRules = flagList(args, 'related-rule');
53
+ const cliRelatedPaths = flagList(args, 'related-path');
54
+ const cliTemplates = flagList(args, 'template');
55
+ let relatedRules = cliRelatedRules;
56
+ let relatedKnowledge = cliRelatedKnowledge;
57
+ let relatedPaths = cliRelatedPaths;
58
+ let proposedTemplates = [];
59
+ if (relatedRules.length === 0 || relatedKnowledge.length === 0 || relatedPaths.length === 0 || cliTemplates.length === 0) {
60
+ const packet = buildTaskPacket(inspection, title, { maxTokens: 1500 });
61
+ if (relatedRules.length === 0) {
62
+ relatedRules = packet.relevantRules.slice(0, limit).map((r) => r.id);
63
+ }
64
+ if (relatedKnowledge.length === 0) {
65
+ // Pull top-N knowledge ids from the same packet ranker.
66
+ relatedKnowledge = inspection.knowledgeEntries
67
+ .slice(0, limit)
68
+ .map((k) => k.id);
69
+ }
70
+ if (relatedPaths.length === 0) {
71
+ relatedPaths = packet.relevantPaths.slice(0, limit).map((p) => p.id);
72
+ }
73
+ if (cliTemplates.length === 0) {
74
+ proposedTemplates = packet.relevantTemplates.slice(0, 1).map((t) => ({
75
+ templateId: t.id,
76
+ variables: {},
77
+ }));
78
+ }
79
+ }
80
+ if (cliTemplates.length > 0) {
81
+ proposedTemplates = cliTemplates.map((id) => ({ templateId: id, variables: {} }));
82
+ }
83
+ // Unknown id refusal (any explicit flag must resolve).
84
+ const ruleIds = new Set(inspection.ruleService.list().map((r) => r.id));
85
+ const pathIds = new Set(inspection.pathService.list().map((p) => p.id));
86
+ const knowledgeIds = new Set(inspection.knowledgeEntries.map((k) => k.id));
87
+ const templateIds = new Set(inspection.templates.map((t) => t.id));
88
+ for (const id of cliRelatedRules) {
89
+ if (!ruleIds.has(id))
90
+ return reject(`unknown rule id "${id}"`);
91
+ }
92
+ for (const id of cliRelatedKnowledge) {
93
+ if (!knowledgeIds.has(id))
94
+ return reject(`unknown knowledge id "${id}"`);
95
+ }
96
+ for (const id of cliRelatedPaths) {
97
+ if (!pathIds.has(id))
98
+ return reject(`unknown path id "${id}"`);
99
+ }
100
+ for (const id of cliTemplates) {
101
+ if (!templateIds.has(id))
102
+ return reject(`unknown template id "${id}"`);
103
+ }
104
+ const verificationCommandIds = (inspection.config?.verificationCommands ?? [])
105
+ .filter((c) => c.trusted !== false)
106
+ .map((c) => c.id);
107
+ const issue = flagString(args, 'issue') ?? null;
108
+ const now = new Date().toISOString();
109
+ const md = renderSpecMd({
110
+ id: built.id,
111
+ slug: built.slug,
112
+ title,
113
+ createdAt: now,
114
+ updatedAt: now,
115
+ issue,
116
+ relevantRules: relatedRules,
117
+ relevantKnowledge: relatedKnowledge,
118
+ relevantPaths: relatedPaths,
119
+ affectedPackages: [],
120
+ proposedTemplates,
121
+ verificationCommandIds,
122
+ });
123
+ const split = splitSpecMd(md);
124
+ if (!split.ok) {
125
+ process.stderr.write(`Internal error: scaffolded spec did not parse: ${split.error.message}\n`);
126
+ return 1;
127
+ }
128
+ const derived = deriveSpecJson(split.value);
129
+ if (!derived.ok) {
130
+ process.stderr.write(`Internal error: scaffolded spec did not derive: ${derived.error.message}\n`);
131
+ return 1;
132
+ }
133
+ const wantWrite = flagBool(args, 'write');
134
+ const targetDir = specDir(cwd, built.id);
135
+ if (wantWrite && existsSync(targetDir) && !force) {
136
+ process.stderr.write(`Spec ${built.id} already exists at ${targetDir}. Re-run with --force to overwrite, or ` +
137
+ `pick a different slug.\n`);
138
+ return 1;
139
+ }
140
+ let written = false;
141
+ if (wantWrite) {
142
+ const res = persistSpecArtifacts({ projectRoot: cwd, id: built.id, md, json: derived.value });
143
+ if (!res.ok) {
144
+ process.stderr.write(`Failed to write spec: ${res.error.message}\n`);
145
+ return 1;
146
+ }
147
+ written = true;
148
+ appendSpecEvent(cwd, built.id, {
149
+ operation: 'create',
150
+ details: { title, slug: built.slug },
151
+ });
152
+ recordProvenance({
153
+ projectRoot: cwd,
154
+ entry: {
155
+ operation: AssetProvenanceOperation.Add,
156
+ assetKind: 'spec',
157
+ assetId: built.id,
158
+ source: AssetProvenanceSource.Cli,
159
+ reason: 'shrk spec create',
160
+ ...(issue !== null ? { extra: { issue } } : {}),
161
+ },
162
+ });
163
+ }
164
+ const result = {
165
+ schema: SPEC_SCHEMA_V1,
166
+ preview: true,
167
+ id: built.id,
168
+ path: specMdPath(cwd, built.id),
169
+ md,
170
+ spec: derived.value,
171
+ written,
172
+ };
173
+ if (flagBool(args, 'json')) {
174
+ process.stdout.write(asJson(result) + '\n');
175
+ return 0;
176
+ }
177
+ process.stdout.write(header(`Spec ${written ? 'created' : 'preview'}: ${built.id}`));
178
+ process.stdout.write(` path: ${result.path}\n`);
179
+ process.stdout.write(` written: ${written ? 'yes' : 'no (pass --write to land)'}\n`);
180
+ process.stdout.write('\n--- spec.md ---\n');
181
+ process.stdout.write(md);
182
+ process.stdout.write('\n--- next ---\n');
183
+ if (!written) {
184
+ process.stdout.write(` $ shrk spec create "${title}" --write\n`);
185
+ }
186
+ else {
187
+ process.stdout.write(` edit ${result.path}\n`);
188
+ process.stdout.write(` $ shrk spec review ${built.id}\n`);
189
+ }
190
+ return 0;
191
+ },
192
+ };
193
+ function parseLimit(v) {
194
+ if (v === undefined)
195
+ return undefined;
196
+ const n = Number.parseInt(v, 10);
197
+ if (!Number.isFinite(n) || n <= 0)
198
+ return undefined;
199
+ return n;
200
+ }
201
+ function reject(message) {
202
+ process.stderr.write(`Refusing: ${message}\n`);
203
+ return 1;
204
+ }
205
+ export const specReviewCommand = {
206
+ name: 'review',
207
+ description: 'Read-only structural + cross-registry validation of a spec. Returns sharkcraft.spec-review/v1.',
208
+ usage: 'shrk spec review <id|path> [--json] [--strict] [--write]',
209
+ async run(args) {
210
+ const ref = args.positional[0];
211
+ if (!ref) {
212
+ process.stderr.write('Usage: shrk spec review <id|path>\n');
213
+ return 2;
214
+ }
215
+ const cwd = resolveCwd(args);
216
+ const resolved = resolveSpecRef(cwd, ref);
217
+ if (!resolved) {
218
+ process.stderr.write(`Spec not found: ${ref}\n`);
219
+ return 1;
220
+ }
221
+ const inspection = await inspectSharkcraft({ cwd });
222
+ const loaded = loadSpec(cwd, resolved.id);
223
+ if (!loaded.ok) {
224
+ process.stderr.write(`Failed to load spec ${resolved.id}: ${loaded.error.message}\n`);
225
+ return 1;
226
+ }
227
+ const review = buildSpecReview({
228
+ spec: loaded.value.spec,
229
+ specPath: specMdPath(cwd, resolved.id),
230
+ body: loaded.value.body,
231
+ inspection,
232
+ });
233
+ appendSpecEvent(cwd, resolved.id, {
234
+ operation: 'review',
235
+ verdict: review.verdict,
236
+ details: {
237
+ errors: review.errors.length,
238
+ warnings: review.warnings.length,
239
+ },
240
+ });
241
+ if (flagBool(args, 'write')) {
242
+ // Cache the latest spec.json view + maybe transition status.
243
+ writeSpecJson(cwd, resolved.id, loaded.value.spec);
244
+ if ((review.verdict === 'pass' || review.verdict === 'warn') &&
245
+ loaded.value.spec.status === SpecStatus.Draft) {
246
+ const md = readFileSync(specMdPath(cwd, resolved.id), 'utf8');
247
+ const updated = md
248
+ .replace(/^status:\s*draft$/m, `status: ${SpecStatus.Review}`)
249
+ .replace(/^updatedAt:\s*.+$/m, `updatedAt: ${new Date().toISOString()}`);
250
+ writeSpecMd(cwd, resolved.id, updated);
251
+ }
252
+ }
253
+ if (flagBool(args, 'json')) {
254
+ process.stdout.write(asJson(review) + '\n');
255
+ }
256
+ else {
257
+ renderReview(review);
258
+ }
259
+ const strict = flagBool(args, 'strict');
260
+ if (review.verdict === 'fail')
261
+ return 1;
262
+ if (review.verdict === 'warn' && strict)
263
+ return 1;
264
+ return 0;
265
+ },
266
+ };
267
+ function renderReview(review) {
268
+ process.stdout.write(header(`Spec review: ${review.specId}`));
269
+ process.stdout.write(` verdict: ${review.verdict.toUpperCase()}\n`);
270
+ process.stdout.write(` errors: ${review.errors.length}\n`);
271
+ process.stdout.write(` warnings: ${review.warnings.length}\n`);
272
+ if (review.errors.length > 0) {
273
+ process.stdout.write('\nErrors:\n');
274
+ for (const e of review.errors) {
275
+ process.stdout.write(` [${e.code}] ${e.field}: ${e.message}\n`);
276
+ }
277
+ }
278
+ if (review.warnings.length > 0) {
279
+ process.stdout.write('\nWarnings:\n');
280
+ for (const w of review.warnings) {
281
+ process.stdout.write(` [${w.code}] ${w.field}: ${w.message}\n`);
282
+ }
283
+ }
284
+ }
285
+ export const specLintCommand = {
286
+ name: 'lint',
287
+ description: 'Fast structural-only lint of a spec. Same as `spec review` but skips cross-registry resolution. Read-only.',
288
+ usage: 'shrk spec lint <id|path> [--json]',
289
+ async run(args) {
290
+ const ref = args.positional[0];
291
+ if (!ref) {
292
+ process.stderr.write('Usage: shrk spec lint <id|path>\n');
293
+ return 2;
294
+ }
295
+ const cwd = resolveCwd(args);
296
+ const resolved = resolveSpecRef(cwd, ref);
297
+ if (!resolved) {
298
+ process.stderr.write(`Spec not found: ${ref}\n`);
299
+ return 1;
300
+ }
301
+ const loaded = loadSpec(cwd, resolved.id);
302
+ if (!loaded.ok) {
303
+ process.stderr.write(`Failed to load spec ${resolved.id}: ${loaded.error.message}\n`);
304
+ return 1;
305
+ }
306
+ const result = validateSpecStructural(loaded.value.spec, loaded.value.body);
307
+ const verdict = result.errors.length > 0 ? 'fail' : result.warnings.length > 0 ? 'warn' : 'pass';
308
+ if (flagBool(args, 'json')) {
309
+ process.stdout.write(asJson({ schema: 'sharkcraft.spec-lint/v1', id: resolved.id, verdict, ...result }) + '\n');
310
+ }
311
+ else {
312
+ process.stdout.write(header(`Spec lint: ${resolved.id}`));
313
+ process.stdout.write(` verdict: ${verdict.toUpperCase()}\n`);
314
+ for (const e of result.errors)
315
+ process.stdout.write(` ERR ${e.field}: ${e.message}\n`);
316
+ for (const w of result.warnings)
317
+ process.stdout.write(` WARN ${w.field}: ${w.message}\n`);
318
+ }
319
+ return verdict === 'fail' ? 1 : 0;
320
+ },
321
+ };
322
+ export const specListCommand = {
323
+ name: 'list',
324
+ description: 'List every spec in .sharkcraft/specs/. Read-only.',
325
+ usage: 'shrk spec list [--status <s>] [--json]',
326
+ async run(args) {
327
+ const cwd = resolveCwd(args);
328
+ const report = buildSpecList(cwd);
329
+ const statusFilter = flagString(args, 'status');
330
+ const filtered = statusFilter
331
+ ? {
332
+ ...report,
333
+ entries: report.entries.filter((e) => e.status === statusFilter),
334
+ }
335
+ : report;
336
+ if (flagBool(args, 'json')) {
337
+ process.stdout.write(asJson(filtered) + '\n');
338
+ return 0;
339
+ }
340
+ process.stdout.write(header(`Specs (${filtered.entries.length})`));
341
+ for (const e of filtered.entries) {
342
+ const flags = [e.hasPlan ? 'P' : '-', e.hasVerification ? 'V' : '-'].join('');
343
+ process.stdout.write(` ${e.id.padEnd(36)} ${String(e.status).padEnd(13)} ${flags} ${e.title}\n`);
344
+ }
345
+ if (filtered.entries.length === 0) {
346
+ process.stdout.write('\n(no specs yet — try `shrk spec create "<title>" --write`)\n');
347
+ }
348
+ return 0;
349
+ },
350
+ };
351
+ export const specShowCommand = {
352
+ name: 'show',
353
+ description: 'Print a spec contents. Read-only.',
354
+ usage: 'shrk spec show <id> [--include-body] [--json]',
355
+ async run(args) {
356
+ const ref = args.positional[0];
357
+ if (!ref) {
358
+ process.stderr.write('Usage: shrk spec show <id>\n');
359
+ return 2;
360
+ }
361
+ const cwd = resolveCwd(args);
362
+ const resolved = resolveSpecRef(cwd, ref);
363
+ if (!resolved) {
364
+ process.stderr.write(`Spec not found: ${ref}\n`);
365
+ return 1;
366
+ }
367
+ const loaded = loadSpec(cwd, resolved.id);
368
+ if (!loaded.ok) {
369
+ process.stderr.write(`Failed to load spec ${resolved.id}: ${loaded.error.message}\n`);
370
+ return 1;
371
+ }
372
+ const includeBody = flagBool(args, 'include-body');
373
+ if (flagBool(args, 'json')) {
374
+ const payload = includeBody
375
+ ? { ...loaded.value.spec, body: loaded.value.body }
376
+ : loaded.value.spec;
377
+ process.stdout.write(asJson(payload) + '\n');
378
+ return 0;
379
+ }
380
+ process.stdout.write(header(`Spec: ${loaded.value.spec.id}`));
381
+ process.stdout.write(` title: ${loaded.value.spec.title}\n`);
382
+ process.stdout.write(` status: ${loaded.value.spec.status}\n`);
383
+ process.stdout.write(` created: ${loaded.value.spec.createdAt}\n`);
384
+ process.stdout.write(` updated: ${loaded.value.spec.updatedAt}\n`);
385
+ process.stdout.write(` intent: ${loaded.value.spec.intent.slice(0, 200)}\n`);
386
+ process.stdout.write(` acceptance: ${loaded.value.spec.acceptanceCriteria.length} criterion(s)\n`);
387
+ if (includeBody) {
388
+ process.stdout.write('\n--- body ---\n');
389
+ process.stdout.write(loaded.value.body);
390
+ process.stdout.write('\n');
391
+ }
392
+ return 0;
393
+ },
394
+ };
395
+ export const specStatusCommand = {
396
+ name: 'status',
397
+ description: 'Read the current spec status, or transition it. Manual transitions allowed only to `abandoned` (with --reason). Other transitions happen automatically via `spec review` / `spec implement` / `spec verify`.',
398
+ usage: 'shrk spec status <id> [--set <state>] [--reason <text>] [--write] [--json]',
399
+ async run(args) {
400
+ const ref = args.positional[0];
401
+ if (!ref) {
402
+ process.stderr.write('Usage: shrk spec status <id> [--set abandoned --reason <text> --write]\n');
403
+ return 2;
404
+ }
405
+ const cwd = resolveCwd(args);
406
+ const resolved = resolveSpecRef(cwd, ref);
407
+ if (!resolved) {
408
+ process.stderr.write(`Spec not found: ${ref}\n`);
409
+ return 1;
410
+ }
411
+ const loaded = loadSpec(cwd, resolved.id);
412
+ if (!loaded.ok) {
413
+ process.stderr.write(`Failed to load spec ${resolved.id}: ${loaded.error.message}\n`);
414
+ return 1;
415
+ }
416
+ const set = flagString(args, 'set');
417
+ if (!set) {
418
+ const payload = { id: resolved.id, status: loaded.value.spec.status };
419
+ if (flagBool(args, 'json')) {
420
+ process.stdout.write(asJson(payload) + '\n');
421
+ }
422
+ else {
423
+ process.stdout.write(`${resolved.id}: ${loaded.value.spec.status}\n`);
424
+ }
425
+ return 0;
426
+ }
427
+ if (set !== SpecStatus.Abandoned) {
428
+ process.stderr.write(`Refusing: manual transitions are only allowed to "${SpecStatus.Abandoned}". ` +
429
+ `Other transitions happen via spec review / implement / verify.\n`);
430
+ return 1;
431
+ }
432
+ const reason = flagString(args, 'reason');
433
+ if (!reason || reason.trim().length === 0) {
434
+ process.stderr.write('Refusing: spec status --set abandoned requires --reason "<text>".\n');
435
+ return 1;
436
+ }
437
+ const wantWrite = flagBool(args, 'write');
438
+ if (!wantWrite) {
439
+ process.stdout.write(`Preview: would transition ${resolved.id} → ${SpecStatus.Abandoned} (reason: ${reason}).\n` +
440
+ `Re-run with --write to apply.\n`);
441
+ return 0;
442
+ }
443
+ const md = readFileSync(specMdPath(cwd, resolved.id), 'utf8');
444
+ const updated = md
445
+ .replace(/^status:\s*\S+$/m, `status: ${SpecStatus.Abandoned}`)
446
+ .replace(/^updatedAt:\s*.+$/m, `updatedAt: ${new Date().toISOString()}`);
447
+ writeSpecMd(cwd, resolved.id, updated);
448
+ appendSpecEvent(cwd, resolved.id, {
449
+ operation: 'status',
450
+ verdict: SpecStatus.Abandoned,
451
+ details: { reason },
452
+ });
453
+ process.stdout.write(`${resolved.id}: abandoned (reason: ${reason})\n`);
454
+ return 0;
455
+ },
456
+ };
457
+ export const specImplementCommand = {
458
+ name: 'implement',
459
+ description: 'Compose the spec\'s proposedTemplates into a signed combined plan. Default dry-run; pass --write-plan to land plan.json under the spec dir; --apply to ship the change.',
460
+ usage: 'shrk spec implement <id> [--dry-run] [--write-plan] [--apply] [--allow-divergent] [--skip-review] [--json]',
461
+ async run(args) {
462
+ const ref = args.positional[0];
463
+ if (!ref) {
464
+ process.stderr.write('Usage: shrk spec implement <id>\n');
465
+ return 2;
466
+ }
467
+ const cwd = resolveCwd(args);
468
+ const resolved = resolveSpecRef(cwd, ref);
469
+ if (!resolved) {
470
+ process.stderr.write(`Spec not found: ${ref}\n`);
471
+ return 1;
472
+ }
473
+ const loaded = loadSpec(cwd, resolved.id);
474
+ if (!loaded.ok) {
475
+ process.stderr.write(`Failed to load spec ${resolved.id}: ${loaded.error.message}\n`);
476
+ return 1;
477
+ }
478
+ const spec = loaded.value.spec;
479
+ if (spec.status === SpecStatus.Abandoned) {
480
+ process.stderr.write(`Refusing: spec ${spec.id} is abandoned.\n`);
481
+ return 1;
482
+ }
483
+ if (spec.proposedTemplates.length === 0) {
484
+ process.stderr.write(`Refusing: spec ${spec.id} has no proposedTemplates.\n`);
485
+ return 1;
486
+ }
487
+ const reviewOk = flagBool(args, 'skip-review') || hasReviewEventOk(cwd, spec.id);
488
+ if (!reviewOk) {
489
+ process.stderr.write(`Refusing: spec has not been reviewed. Run \`shrk spec review ${spec.id}\` first, or pass --skip-review.\n`);
490
+ return 1;
491
+ }
492
+ const inspection = await inspectSharkcraft({ cwd });
493
+ const perTemplate = [];
494
+ const combinedChanges = [];
495
+ const refusals = [];
496
+ const collectedFileChanges = [];
497
+ for (const t of spec.proposedTemplates) {
498
+ const template = inspection.templateRegistry.get(t.templateId);
499
+ if (!template) {
500
+ refusals.push({ templateId: t.templateId, reason: 'template not found in registry' });
501
+ continue;
502
+ }
503
+ const result = generate(template, {
504
+ templateId: t.templateId,
505
+ variables: t.variables,
506
+ projectRoot: cwd,
507
+ overwriteStrategy: OverwriteStrategy.Never,
508
+ write: false,
509
+ });
510
+ if (!result.ok) {
511
+ refusals.push({ templateId: t.templateId, reason: result.error.message });
512
+ continue;
513
+ }
514
+ const plan = result.value.plan;
515
+ perTemplate.push({
516
+ templateId: t.templateId,
517
+ totalFiles: plan.totalFiles,
518
+ hasConflicts: plan.hasConflicts,
519
+ changes: plan.changes.map((c) => ({
520
+ type: String(c.type),
521
+ relativePath: c.relativePath,
522
+ sizeBytes: c.sizeBytes,
523
+ ...(c.operation !== undefined ? { operation: c.operation } : {}),
524
+ })),
525
+ });
526
+ if (plan.hasConflicts) {
527
+ refusals.push({ templateId: t.templateId, reason: 'plan has conflicts' });
528
+ continue;
529
+ }
530
+ for (const ch of plan.changes) {
531
+ const dup = combinedChanges.find((e) => e.relativePath === ch.relativePath &&
532
+ e.type === String(ch.type) &&
533
+ e.type === String(FileChangeType.Create));
534
+ if (dup) {
535
+ refusals.push({
536
+ templateId: t.templateId,
537
+ reason: `combined-plan conflict on ${ch.relativePath} (also written by another template)`,
538
+ });
539
+ continue;
540
+ }
541
+ const entry = {
542
+ type: String(ch.type),
543
+ relativePath: ch.relativePath,
544
+ sizeBytes: ch.sizeBytes,
545
+ ...(ch.operation !== undefined ? { operation: ch.operation } : {}),
546
+ };
547
+ combinedChanges.push(entry);
548
+ collectedFileChanges.push(entry);
549
+ }
550
+ }
551
+ const syntheticPlan = {
552
+ templateId: `sharkcraft.spec/${spec.id}`,
553
+ templateName: `spec ${spec.id}`,
554
+ changes: collectedFileChanges.map((c) => ({
555
+ type: c.type,
556
+ relativePath: c.relativePath,
557
+ absolutePath: nodePath.join(cwd, c.relativePath),
558
+ sizeBytes: c.sizeBytes,
559
+ contents: '',
560
+ reason: `spec=${spec.id}`,
561
+ ...(c.operation !== undefined ? { operation: c.operation } : {}),
562
+ })),
563
+ totalFiles: collectedFileChanges.length,
564
+ hasConflicts: false,
565
+ warnings: [],
566
+ postGenerationNotes: [],
567
+ };
568
+ const built = buildSavedPlan({
569
+ templateId: `sharkcraft.spec/${spec.id}`,
570
+ variables: flattenVariables(spec.proposedTemplates),
571
+ projectRoot: cwd,
572
+ plan: syntheticPlan,
573
+ note: `spec=${spec.id}; frontmatter=${spec.frontmatterHash}`,
574
+ });
575
+ let signedPlan = built;
576
+ let signatureStatus = 'unsigned';
577
+ if (process.env[PLAN_SECRET_ENV]) {
578
+ const signed = signPlan(built);
579
+ if (signed.ok) {
580
+ signedPlan = signed.value;
581
+ signatureStatus = 'signed';
582
+ }
583
+ else {
584
+ signatureStatus = 'missing-secret';
585
+ }
586
+ }
587
+ else {
588
+ signatureStatus = 'missing-secret';
589
+ }
590
+ const wantWritePlan = flagBool(args, 'write-plan');
591
+ const wantApply = flagBool(args, 'apply');
592
+ let savedPlanPath = null;
593
+ let applied = false;
594
+ if (refusals.length > 0 && !flagBool(args, 'allow-divergent')) {
595
+ const report = {
596
+ schema: SPEC_IMPLEMENT_SCHEMA,
597
+ specId: spec.id,
598
+ frontmatterHash: spec.frontmatterHash,
599
+ perTemplatePlans: perTemplate,
600
+ combined: {
601
+ savedPlanPath,
602
+ totalFiles: combinedChanges.length,
603
+ signatureStatus,
604
+ applied,
605
+ },
606
+ refusals,
607
+ };
608
+ if (flagBool(args, 'json'))
609
+ process.stdout.write(asJson(report) + '\n');
610
+ else {
611
+ process.stdout.write(header(`Spec implement REFUSED: ${spec.id}`));
612
+ for (const r of refusals) {
613
+ process.stdout.write(` ${r.templateId}: ${r.reason}\n`);
614
+ }
615
+ }
616
+ return 1;
617
+ }
618
+ if (wantWritePlan) {
619
+ savedPlanPath = specPlanPath(cwd, spec.id);
620
+ const writeRes = savePlanToFile(signedPlan, savedPlanPath);
621
+ if (!writeRes.ok) {
622
+ process.stderr.write(`Failed to write plan: ${writeRes.error.message}\n`);
623
+ return 1;
624
+ }
625
+ // Update spec.md plan block + transition status.
626
+ const md = readFileSync(specMdPath(cwd, spec.id), 'utf8');
627
+ const planRefLines = [
628
+ 'plan:',
629
+ ` planPath: ${nodePath.relative(specDir(cwd, spec.id), savedPlanPath)}`,
630
+ ` planHash: ${shortHash(canonicalJson(signedPlan))}`,
631
+ ` signedAt: ${signedPlan.signature?.signedAt ?? ''}`,
632
+ ];
633
+ const updated = upsertPlanBlock(md, planRefLines.join('\n'))
634
+ .replace(/^status:\s*\S+$/m, `status: ${SpecStatus.Implementing}`)
635
+ .replace(/^updatedAt:\s*.+$/m, `updatedAt: ${new Date().toISOString()}`);
636
+ writeSpecMd(cwd, spec.id, updated);
637
+ // Re-derive spec.json so it stays consistent.
638
+ const reparsed = splitSpecMd(updated);
639
+ if (reparsed.ok) {
640
+ const rederived = deriveSpecJson(reparsed.value);
641
+ if (rederived.ok)
642
+ writeSpecJson(cwd, spec.id, rederived.value);
643
+ }
644
+ appendSpecEvent(cwd, spec.id, {
645
+ operation: 'implement',
646
+ verdict: 'plan-written',
647
+ details: { planPath: savedPlanPath, signatureStatus },
648
+ });
649
+ }
650
+ if (wantApply) {
651
+ // Close the spec→apply loop. `spec implement --apply` dispatches
652
+ // into applyCommand directly with the signed plan path. The
653
+ // signed plan was written above if --write-plan was passed; if
654
+ // not, we still have the in-memory signed plan in `signedPlan`
655
+ // — write it to a transient location under the spec dir so apply
656
+ // has a file to consume.
657
+ if (!savedPlanPath) {
658
+ // Materialize the plan if --apply was passed without --write-plan.
659
+ savedPlanPath = specPlanPath(cwd, spec.id);
660
+ const writeRes = savePlanToFile(signedPlan, savedPlanPath);
661
+ if (!writeRes.ok) {
662
+ process.stderr.write(`Failed to write plan for apply: ${writeRes.error.message}\n`);
663
+ return 1;
664
+ }
665
+ }
666
+ // Dispatch into applyCommand. Forward --allow-divergent and
667
+ // --verify-signature (defaults to true since we signed the plan
668
+ // when a SHARKCRAFT_PLAN_SECRET was available).
669
+ const applyFlags = new Map();
670
+ if (flagBool(args, 'allow-divergent'))
671
+ applyFlags.set('allow-divergent', true);
672
+ if (signatureStatus === 'signed')
673
+ applyFlags.set('verify-signature', true);
674
+ if (flagBool(args, 'json'))
675
+ applyFlags.set('json', true);
676
+ const applyArgs = {
677
+ positional: [savedPlanPath],
678
+ flags: applyFlags,
679
+ multiFlags: new Map(),
680
+ ...(args.globalCwd !== undefined ? { globalCwd: args.globalCwd } : {}),
681
+ };
682
+ const applyRc = await applyCommand.run(applyArgs);
683
+ applied = applyRc === 0;
684
+ appendSpecEvent(cwd, spec.id, {
685
+ operation: 'apply',
686
+ verdict: applied ? 'applied' : 'apply-failed',
687
+ details: { planPath: nodePath.relative(cwd, savedPlanPath), rc: applyRc },
688
+ });
689
+ if (!applied) {
690
+ process.stderr.write(`Apply returned non-zero (${applyRc}); inspect the apply output above for details.\n`);
691
+ }
692
+ }
693
+ const report = {
694
+ schema: SPEC_IMPLEMENT_SCHEMA,
695
+ specId: spec.id,
696
+ frontmatterHash: spec.frontmatterHash,
697
+ perTemplatePlans: perTemplate,
698
+ combined: {
699
+ savedPlanPath,
700
+ totalFiles: combinedChanges.length,
701
+ signatureStatus,
702
+ applied,
703
+ },
704
+ refusals,
705
+ };
706
+ if (flagBool(args, 'json')) {
707
+ process.stdout.write(asJson(report) + '\n');
708
+ }
709
+ else {
710
+ process.stdout.write(header(`Spec implement: ${spec.id}`));
711
+ process.stdout.write(` per-template plans: ${perTemplate.length}\n`);
712
+ for (const p of perTemplate) {
713
+ process.stdout.write(` ${p.templateId.padEnd(28)} files=${p.totalFiles}\n`);
714
+ }
715
+ process.stdout.write(` combined files: ${combinedChanges.length}\n`);
716
+ process.stdout.write(` signature: ${signatureStatus}\n`);
717
+ if (savedPlanPath)
718
+ process.stdout.write(` plan: ${savedPlanPath}\n`);
719
+ if (refusals.length > 0) {
720
+ process.stdout.write('\nRefusals:\n');
721
+ for (const r of refusals)
722
+ process.stdout.write(` ${r.templateId}: ${r.reason}\n`);
723
+ }
724
+ }
725
+ return 0;
726
+ },
727
+ };
728
+ function hasReviewEventOk(projectRoot, id) {
729
+ const events = readSpecEvents(projectRoot, id);
730
+ return events.some((e) => e.operation === 'review' && e.verdict !== 'fail');
731
+ }
732
+ function flattenVariables(templates) {
733
+ const out = {};
734
+ for (const t of templates) {
735
+ for (const [k, v] of Object.entries(t.variables)) {
736
+ out[`${t.templateId}.${k}`] = v;
737
+ }
738
+ }
739
+ return out;
740
+ }
741
+ function upsertPlanBlock(md, planBlock) {
742
+ const lines = md.split('\n');
743
+ // Find frontmatter range.
744
+ if (lines[0] !== '---')
745
+ return md;
746
+ let close = -1;
747
+ for (let i = 1; i < lines.length; i++) {
748
+ if (lines[i] === '---') {
749
+ close = i;
750
+ break;
751
+ }
752
+ }
753
+ if (close === -1)
754
+ return md;
755
+ // Strip any existing `plan:` block (top-level, until next top-level key).
756
+ const fm = [];
757
+ let inPlan = false;
758
+ for (let i = 1; i < close; i++) {
759
+ const line = lines[i];
760
+ if (line.startsWith('plan:')) {
761
+ inPlan = true;
762
+ continue;
763
+ }
764
+ if (inPlan) {
765
+ // End of plan block iff next top-level key (non-whitespace start).
766
+ if (line.length > 0 && line[0] !== ' ' && line[0] !== '\t') {
767
+ inPlan = false;
768
+ fm.push(line);
769
+ }
770
+ continue;
771
+ }
772
+ fm.push(line);
773
+ }
774
+ return ['---', ...fm, planBlock, '---', ...lines.slice(close + 1)].join('\n');
775
+ }
776
+ function shortHash(text) {
777
+ return createHash('sha256').update(text, 'utf8').digest('hex');
778
+ }
779
+ export const specVerifyCommand = {
780
+ name: 'verify',
781
+ description: 'Run the spec\'s trusted verification commands, check acceptance-criteria coverage, run diff-aware boundary + drift checks. Returns sharkcraft.spec-verification/v1.',
782
+ usage: 'shrk spec verify <id> [--since <ref>] [--strict] [--skip-verification-commands] [--json] [--write]',
783
+ async run(args) {
784
+ const ref = args.positional[0];
785
+ if (!ref) {
786
+ process.stderr.write('Usage: shrk spec verify <id>\n');
787
+ return 2;
788
+ }
789
+ const cwd = resolveCwd(args);
790
+ const resolved = resolveSpecRef(cwd, ref);
791
+ if (!resolved) {
792
+ process.stderr.write(`Spec not found: ${ref}\n`);
793
+ return 1;
794
+ }
795
+ const loaded = loadSpec(cwd, resolved.id);
796
+ if (!loaded.ok) {
797
+ process.stderr.write(`Failed to load spec ${resolved.id}: ${loaded.error.message}\n`);
798
+ return 1;
799
+ }
800
+ const spec = loaded.value.spec;
801
+ if (spec.status !== SpecStatus.Implementing &&
802
+ spec.status !== SpecStatus.Implemented &&
803
+ spec.status !== SpecStatus.Verified) {
804
+ process.stderr.write(`Refusing: spec ${spec.id} is in status "${spec.status}". Implement first via \`shrk spec implement ${spec.id} --write-plan\`.\n`);
805
+ return 1;
806
+ }
807
+ const inspection = await inspectSharkcraft({ cwd });
808
+ const trusted = new Map((inspection.config?.verificationCommands ?? [])
809
+ .filter((c) => c.trusted !== false)
810
+ .map((c) => [c.id, c]));
811
+ const known = new Map((inspection.config?.verificationCommands ?? []).map((c) => [c.id, c]));
812
+ const skipCommands = flagBool(args, 'skip-verification-commands');
813
+ const commandResults = [];
814
+ let commandFailed = false;
815
+ if (!skipCommands) {
816
+ for (const v of spec.verificationCommands) {
817
+ const cmd = trusted.get(v.id);
818
+ if (!cmd) {
819
+ if (!known.has(v.id)) {
820
+ commandResults.push({ id: v.id, status: 'unknown' });
821
+ commandFailed = true;
822
+ continue;
823
+ }
824
+ commandResults.push({ id: v.id, status: 'skipped' });
825
+ continue;
826
+ }
827
+ const start = Date.now();
828
+ try {
829
+ execSync(cmd.command, { cwd, stdio: 'pipe' });
830
+ commandResults.push({
831
+ id: v.id,
832
+ status: 'pass',
833
+ exitCode: 0,
834
+ durationMs: Date.now() - start,
835
+ });
836
+ }
837
+ catch (e) {
838
+ const errAny = e;
839
+ commandResults.push({
840
+ id: v.id,
841
+ status: 'fail',
842
+ exitCode: errAny.status ?? 1,
843
+ durationMs: Date.now() - start,
844
+ stderrTail: typeof errAny.stderr === 'string'
845
+ ? errAny.stderr.split('\n').slice(-5).join('\n')
846
+ : errAny.stderr?.toString('utf8').split('\n').slice(-5).join('\n'),
847
+ });
848
+ commandFailed = true;
849
+ }
850
+ }
851
+ }
852
+ const sinceRef = flagString(args, 'since');
853
+ const changed = collectChangedPaths({ cwd, ...(sinceRef ? { ref: sinceRef } : {}) });
854
+ const declaredScope = new Set([
855
+ ...spec.affectedAreas.files,
856
+ ...spec.affectedAreas.packages,
857
+ ]);
858
+ const scopeDrift = [];
859
+ if (changed.isAvailable) {
860
+ for (const p of changed.changed) {
861
+ const inScope = [...declaredScope].some((s) => p === s || p.startsWith(s.endsWith('/') ? s : `${s}/`));
862
+ if (!inScope && declaredScope.size > 0) {
863
+ scopeDrift.push({ path: p, reason: 'changed file outside affectedAreas' });
864
+ }
865
+ }
866
+ }
867
+ let planIntegrity;
868
+ const planPath = specPlanPath(cwd, spec.id);
869
+ if (!existsSync(planPath)) {
870
+ planIntegrity = 'no-plan';
871
+ }
872
+ else {
873
+ try {
874
+ const planRaw = JSON.parse(readFileSync(planPath, 'utf8'));
875
+ const verify = verifyPlan(planRaw);
876
+ if (verify.ok)
877
+ planIntegrity = 'verified';
878
+ else if (verify.status === 'missing-signature')
879
+ planIntegrity = 'missing-signature';
880
+ else if (verify.status === 'missing-secret')
881
+ planIntegrity = 'missing-signature';
882
+ else
883
+ planIntegrity = 'invalid-signature';
884
+ }
885
+ catch {
886
+ planIntegrity = 'invalid-signature';
887
+ }
888
+ }
889
+ const acceptanceResults = spec.acceptanceCriteria.map((ac) => ({
890
+ id: ac.id,
891
+ status: ac.verifiedBy.includes('manual')
892
+ ? 'manual'
893
+ : commandFailed
894
+ ? 'fail'
895
+ : 'pass',
896
+ evidence: [],
897
+ }));
898
+ const verdict = commandFailed
899
+ ? 'fail'
900
+ : scopeDrift.length > 0 || planIntegrity === 'missing-signature'
901
+ ? 'warn'
902
+ : 'pass';
903
+ const report = {
904
+ schema: SPEC_VERIFICATION_SCHEMA,
905
+ specId: spec.id,
906
+ frontmatterHash: spec.frontmatterHash,
907
+ ranAt: new Date().toISOString(),
908
+ verdict,
909
+ acceptanceCriteria: acceptanceResults,
910
+ verificationCommands: commandResults,
911
+ boundaries: { since: changed.ref, violations: [] },
912
+ scopeDrift: { outsideScope: scopeDrift },
913
+ planIntegrity: { status: planIntegrity },
914
+ };
915
+ if (flagBool(args, 'write') || flagBool(args, 'apply')) {
916
+ writeFileSync(specVerificationPath(cwd, spec.id), JSON.stringify(report, null, 2) + '\n', 'utf8');
917
+ if (verdict === 'pass' && spec.status !== SpecStatus.Verified) {
918
+ const md = readFileSync(specMdPath(cwd, spec.id), 'utf8');
919
+ const updated = md
920
+ .replace(/^status:\s*\S+$/m, `status: ${SpecStatus.Verified}`)
921
+ .replace(/^updatedAt:\s*.+$/m, `updatedAt: ${new Date().toISOString()}`);
922
+ writeSpecMd(cwd, spec.id, updated);
923
+ }
924
+ }
925
+ appendSpecEvent(cwd, spec.id, { operation: 'verify', verdict });
926
+ if (flagBool(args, 'json')) {
927
+ process.stdout.write(asJson(report) + '\n');
928
+ }
929
+ else {
930
+ process.stdout.write(header(`Spec verify: ${spec.id}`));
931
+ process.stdout.write(` verdict: ${verdict.toUpperCase()}\n`);
932
+ process.stdout.write(` verification commands: ${commandResults.length} (${commandResults.filter((r) => r.status === 'pass').length} pass)\n`);
933
+ for (const r of commandResults) {
934
+ process.stdout.write(` ${r.status.padEnd(7)} ${r.id}${r.durationMs ? ` (${r.durationMs}ms)` : ''}\n`);
935
+ }
936
+ process.stdout.write(` scope drift: ${scopeDrift.length}\n`);
937
+ process.stdout.write(` plan integrity: ${planIntegrity}\n`);
938
+ }
939
+ if (verdict === 'fail')
940
+ return 1;
941
+ if (verdict === 'warn' && flagBool(args, 'strict'))
942
+ return 1;
943
+ return 0;
944
+ },
945
+ };
946
+ export const specParentCommand = {
947
+ name: 'spec',
948
+ description: 'Spec-driven development. Subcommand required: create | review | implement | verify | list | show | status | lint.',
949
+ usage: 'shrk spec <create|review|implement|verify|list|show|status|lint> [...]',
950
+ async run(args) {
951
+ const sub = args.positional[0];
952
+ const handlerMap = {
953
+ create: specCreateCommand,
954
+ review: specReviewCommand,
955
+ implement: specImplementCommand,
956
+ verify: specVerifyCommand,
957
+ list: specListCommand,
958
+ show: specShowCommand,
959
+ status: specStatusCommand,
960
+ lint: specLintCommand,
961
+ };
962
+ if (!sub || !handlerMap[sub]) {
963
+ process.stderr.write('Usage: shrk spec <create|review|implement|verify|list|show|status|lint>\n');
964
+ return 2;
965
+ }
966
+ return await handlerMap[sub].run({
967
+ ...args,
968
+ positional: args.positional.slice(1),
969
+ });
970
+ },
971
+ };
972
+ function resolveSpecRef(projectRoot, ref) {
973
+ // Direct id.
974
+ if (existsSync(specMdPath(projectRoot, ref)))
975
+ return { id: ref };
976
+ // Path to a spec.md.
977
+ if (ref.endsWith('spec.md') && existsSync(ref)) {
978
+ const id = nodePath.basename(nodePath.dirname(ref));
979
+ if (existsSync(specMdPath(projectRoot, id)))
980
+ return { id };
981
+ }
982
+ return null;
983
+ }
984
+ // Re-export schema constant for surface visibility.
985
+ export { SPEC_LIST_SCHEMA };