@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,1392 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import { existsSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
3
+ import * as nodePath from 'node:path';
4
+ import { archiveDevSession, buildAgentBrief, buildTaskPacket, computeDevNextAction, createDevSessionState, DevSessionPhase, DevSessionPlanStatus, diffDevSessions, getDevSessionDir, inspectSharkcraft, listDevCleanCandidates, listDevSessionsDetailed, parseDurationToMs, recordAppliedPlan, recordReportFile, recordValidation, recomputePhase, renderDevSessionFinalReport, renderDevSessionHtml, reviewSavedPlan, scanDevSession, setDevNextAction, setDevSessionBriefFile, setDevSessionPhase, upsertDevPlanEntry, writeDevSessionState, } from '@shrkcrft/inspector';
5
+ import { buildSavedPlan, generate, OverwriteStrategy, PLAN_SECRET_ENV, savePlanToFile, signPlan, } from '@shrkcrft/generator';
6
+ import { flagBool, flagList, flagString, flagVars, resolveCwd, } from "../command-registry.js";
7
+ import { asJson, header, kv } from "../output/format-output.js";
8
+ import { runValidationLoop } from "../validation/run-validation-loop.js";
9
+ const SUBCOMMANDS = new Set([
10
+ 'start',
11
+ 'plan',
12
+ 'status',
13
+ 'next',
14
+ 'continue',
15
+ 'validate',
16
+ 'report',
17
+ 'list',
18
+ 'mark-applied',
19
+ 'mark-validated',
20
+ 'diff',
21
+ 'archive',
22
+ 'clean',
23
+ 'open',
24
+ 'plans',
25
+ 'reports',
26
+ 'commands',
27
+ 'cycle',
28
+ ]);
29
+ function slugify(s) {
30
+ return s
31
+ .toLowerCase()
32
+ .replace(/[^a-z0-9]+/g, '-')
33
+ .replace(/^-+|-+$/g, '')
34
+ .slice(0, 40);
35
+ }
36
+ function loadSessionOrFail(args) {
37
+ const id = args.positional[0];
38
+ if (!id) {
39
+ process.stderr.write('Usage: shrk dev <subcommand> <sessionId>\n');
40
+ return 2;
41
+ }
42
+ const cwd = resolveCwd(args);
43
+ const load = scanDevSession(cwd, id);
44
+ if (!load) {
45
+ process.stderr.write(`No session "${id}".\n`);
46
+ return 1;
47
+ }
48
+ return { load, cwd };
49
+ }
50
+ async function startSession(args) {
51
+ const task = args.positional.join(' ').trim();
52
+ if (!task) {
53
+ process.stderr.write('Usage: shrk dev start "<task>"\n');
54
+ return 2;
55
+ }
56
+ const cwd = resolveCwd(args);
57
+ const inspection = await inspectSharkcraft({ cwd });
58
+ const packet = buildTaskPacket(inspection, task, { maxTokens: 3500 });
59
+ const stamp = new Date().toISOString().replace(/[:.]/g, '-');
60
+ const id = `${stamp}-${slugify(task)}`;
61
+ const dir = getDevSessionDir(cwd, id);
62
+ mkdirSync(dir, { recursive: true });
63
+ mkdirSync(nodePath.join(dir, 'plans'), { recursive: true });
64
+ mkdirSync(nodePath.join(dir, 'reports'), { recursive: true });
65
+ // Write all the deterministic artifacts the spec asks for.
66
+ writeFileSync(nodePath.join(dir, 'task.md'), `# ${task}\n`, 'utf8');
67
+ writeFileSync(nodePath.join(dir, 'task-packet.json'), JSON.stringify(packet, null, 2) + '\n', 'utf8');
68
+ writeFileSync(nodePath.join(dir, 'context.md'), `# Context for: ${task}\n\n${packet.context.body}\n`, 'utf8');
69
+ writeFileSync(nodePath.join(dir, 'action-hints.json'), JSON.stringify(packet.actionHints, null, 2) + '\n', 'utf8');
70
+ const pipelineInfo = {
71
+ selected: packet.recommendedPipelines[0] ?? null,
72
+ alternatives: packet.recommendedPipelines.slice(1),
73
+ humanReviewPoints: packet.humanReviewPoints,
74
+ };
75
+ writeFileSync(nodePath.join(dir, 'recommended-pipeline.json'), JSON.stringify(pipelineInfo, null, 2) + '\n', 'utf8');
76
+ // Commands script — preserved from `shrk session start` so the two
77
+ // workflows produce a comparable bundle.
78
+ const cmdLines = [
79
+ '#!/usr/bin/env bash',
80
+ '# Commands recommended by SharkCraft for this task.',
81
+ '# Review before running.',
82
+ ...packet.recommendedCliCommands,
83
+ '',
84
+ packet.suggestedGen?.dryRunCommand ?? '',
85
+ ].filter(Boolean);
86
+ writeFileSync(nodePath.join(dir, 'commands.sh'), cmdLines.join('\n') + '\n', 'utf8');
87
+ let state = createDevSessionState({ id, task, projectRoot: cwd, packet });
88
+ // --brief: write brief.md inside the session and record path on the state.
89
+ let briefFile;
90
+ if (flagBool(args, 'brief')) {
91
+ try {
92
+ const brief = await buildAgentBrief(inspection, { task });
93
+ const briefPath = nodePath.join(dir, 'brief.md');
94
+ writeFileSync(briefPath, brief.markdown, 'utf8');
95
+ briefFile = 'brief.md';
96
+ state = setDevSessionBriefFile(state, briefFile);
97
+ }
98
+ catch (e) {
99
+ state = { ...state, warnings: [...state.warnings, `brief: ${e.message}`] };
100
+ }
101
+ }
102
+ writeDevSessionState(cwd, state);
103
+ const nextSteps = buildNextStepsMarkdown(id, task, packet, state);
104
+ writeFileSync(nodePath.join(dir, 'next-steps.md'), nextSteps, 'utf8');
105
+ if (flagBool(args, 'json')) {
106
+ const files = [
107
+ 'task.md',
108
+ 'task-packet.json',
109
+ 'context.md',
110
+ 'action-hints.json',
111
+ 'recommended-pipeline.json',
112
+ 'next-steps.md',
113
+ 'commands.sh',
114
+ 'session.json',
115
+ ];
116
+ if (briefFile)
117
+ files.push(briefFile);
118
+ process.stdout.write(asJson({
119
+ id,
120
+ dir,
121
+ task,
122
+ phase: state.phase,
123
+ selectedPipeline: state.selectedPipeline,
124
+ selectedTemplates: state.selectedTemplates,
125
+ nextAction: state.nextAction,
126
+ briefFile: briefFile ?? null,
127
+ files,
128
+ }) + '\n');
129
+ return 0;
130
+ }
131
+ process.stdout.write(header(`Dev session started: ${id}`));
132
+ process.stdout.write(kv('task', task) + '\n');
133
+ process.stdout.write(kv('dir', dir) + '\n');
134
+ process.stdout.write(kv('pipeline', state.selectedPipeline ?? '(none)') + '\n');
135
+ if (state.selectedTemplates.length > 0) {
136
+ process.stdout.write(kv('top templates', state.selectedTemplates.slice(0, 3).join(', ')) + '\n');
137
+ }
138
+ if (packet.relevantRules.length > 0) {
139
+ process.stdout.write(kv('top rules', packet.relevantRules.slice(0, 3).map((r) => r.id).join(', ')) + '\n');
140
+ }
141
+ if (packet.verificationCommands.length > 0) {
142
+ process.stdout.write('\nVerification commands:\n');
143
+ for (const c of packet.verificationCommands.slice(0, 5)) {
144
+ process.stdout.write(` $ ${c}\n`);
145
+ }
146
+ }
147
+ if (packet.forbiddenActions.length > 0) {
148
+ process.stdout.write('\nForbidden actions:\n');
149
+ for (const a of packet.forbiddenActions.slice(0, 5)) {
150
+ process.stdout.write(` ✗ ${a}\n`);
151
+ }
152
+ }
153
+ process.stdout.write('\nFiles written:\n');
154
+ const filesWritten = [
155
+ 'task.md',
156
+ 'task-packet.json',
157
+ 'context.md',
158
+ 'action-hints.json',
159
+ 'recommended-pipeline.json',
160
+ 'next-steps.md',
161
+ 'commands.sh',
162
+ 'session.json',
163
+ ];
164
+ if (briefFile)
165
+ filesWritten.push(briefFile);
166
+ for (const f of filesWritten) {
167
+ process.stdout.write(` + ${f}\n`);
168
+ }
169
+ if (briefFile) {
170
+ process.stdout.write(`\nBrief: ${briefFile} (--brief was set)\n`);
171
+ }
172
+ else {
173
+ process.stdout.write(`\nTip: run \`shrk brief "${task}" --session ${id} --output .sharkcraft/sessions/${id}/brief.md\` to add a brief.\n`);
174
+ }
175
+ process.stdout.write(`\nNext: ${state.nextAction}\n`);
176
+ return 0;
177
+ }
178
+ function buildNextStepsMarkdown(id, task, packet, state) {
179
+ const lines = [];
180
+ lines.push(`# Next steps for: ${task}`);
181
+ lines.push('');
182
+ lines.push(`Session id: \`${id}\``);
183
+ lines.push(`Phase: \`${state.phase}\``);
184
+ lines.push('');
185
+ lines.push('## Recommended path');
186
+ lines.push('');
187
+ if (packet.suggestedGen) {
188
+ lines.push(`1. Generate plan(s) for template \`${packet.suggestedGen.templateId}\`:`);
189
+ lines.push(' ```');
190
+ lines.push(` shrk dev plan ${id} --template ${packet.suggestedGen.templateId} --name <name>` +
191
+ (packet.suggestedGen.requiredVariables.length > 0
192
+ ? ' ' + packet.suggestedGen.requiredVariables.map((v) => `--var ${v}=<${v}>`).join(' ')
193
+ : ''));
194
+ lines.push(' ```');
195
+ }
196
+ else {
197
+ lines.push(`1. No obvious generation template — keep reviewing context:`);
198
+ lines.push(' ```');
199
+ lines.push(` shrk dev continue ${id}`);
200
+ lines.push(' ```');
201
+ }
202
+ lines.push(`2. After plans are saved + reviewed, apply them (human approval required):`);
203
+ lines.push(' ```');
204
+ lines.push(` shrk apply .sharkcraft/sessions/${id}/plans/<plan>.json --verify-signature`);
205
+ lines.push(' ```');
206
+ lines.push(`3. Validate the changes:`);
207
+ lines.push(' ```');
208
+ lines.push(` shrk dev validate ${id}`);
209
+ lines.push(' ```');
210
+ lines.push(`4. Generate the audit-trail report:`);
211
+ lines.push(' ```');
212
+ lines.push(` shrk dev report ${id}`);
213
+ lines.push(' ```');
214
+ lines.push('');
215
+ if (packet.forbiddenActions.length > 0) {
216
+ lines.push('## Forbidden');
217
+ lines.push('');
218
+ for (const a of packet.forbiddenActions)
219
+ lines.push(`- ${a}`);
220
+ lines.push('');
221
+ }
222
+ return lines.join('\n') + '\n';
223
+ }
224
+ async function planSession(args) {
225
+ const loaded = loadSessionOrFail(args);
226
+ if (typeof loaded === 'number')
227
+ return loaded;
228
+ const { load, cwd } = loaded;
229
+ if (!load.packet) {
230
+ process.stderr.write(`Session ${load.id} has no task-packet.json — cannot plan. Re-run shrk dev start.\n`);
231
+ return 1;
232
+ }
233
+ if (!load.state) {
234
+ process.stderr.write(`Session ${load.id} has no session.json (legacy session). ` +
235
+ `Use shrk dev status / shrk session report for legacy sessions.\n`);
236
+ return 1;
237
+ }
238
+ const packet = load.packet;
239
+ let state = load.state;
240
+ const explicitTemplateId = flagString(args, 'template');
241
+ const explicitName = flagString(args, 'name');
242
+ const variables = flagVars(args);
243
+ const wantSign = flagBool(args, 'sign') || Boolean(process.env[PLAN_SECRET_ENV]);
244
+ const wantAll = flagBool(args, 'all');
245
+ const wantJson = flagBool(args, 'json');
246
+ // Decide which templates to plan. `planName` is the on-disk filename slug;
247
+ // `userName` is only set when the human actually passed --name (so the
248
+ // generator's auto-filled `name`/`className`/etc. don't mask missing-var
249
+ // intent generation).
250
+ const targets = [];
251
+ if (explicitTemplateId) {
252
+ const planName = explicitName ?? explicitTemplateId.replace(/[^a-z0-9]+/gi, '-');
253
+ const target = {
254
+ templateId: explicitTemplateId,
255
+ planName,
256
+ variables: { ...variables },
257
+ };
258
+ if (explicitName)
259
+ target.userName = explicitName;
260
+ targets.push(target);
261
+ }
262
+ else if (wantAll) {
263
+ for (const t of packet.relevantTemplates.slice(0, 3)) {
264
+ targets.push({
265
+ templateId: t.id,
266
+ planName: t.id.replace(/[^a-z0-9]+/gi, '-'),
267
+ variables: {},
268
+ });
269
+ }
270
+ }
271
+ else if (packet.suggestedGen) {
272
+ const g = packet.suggestedGen;
273
+ const target = {
274
+ templateId: g.templateId,
275
+ planName: explicitName ?? g.templateId.replace(/[^a-z0-9]+/gi, '-'),
276
+ variables: { ...variables },
277
+ };
278
+ if (explicitName)
279
+ target.userName = explicitName;
280
+ targets.push(target);
281
+ }
282
+ else {
283
+ process.stderr.write(`No template suggested for this task and --template was not provided.\n` +
284
+ `Try: shrk dev plan ${load.id} --template <id> --name <name>\n`);
285
+ return 1;
286
+ }
287
+ const inspection = await inspectSharkcraft({ cwd });
288
+ const plansDir = nodePath.join(load.dir, 'plans');
289
+ const reportsDir = nodePath.join(load.dir, 'reports');
290
+ mkdirSync(plansDir, { recursive: true });
291
+ mkdirSync(reportsDir, { recursive: true });
292
+ const results = [];
293
+ for (const target of targets) {
294
+ const template = inspection.templateRegistry.get(target.templateId);
295
+ if (!template) {
296
+ results.push({
297
+ templateId: target.templateId,
298
+ status: 'unknown-template',
299
+ message: `Template "${target.templateId}" is not registered in this project.`,
300
+ });
301
+ continue;
302
+ }
303
+ // Generate dry-run plan, save under plans/<planName>.json. We only pass
304
+ // `name` to the generator if the user explicitly supplied --name; otherwise
305
+ // the generator must report `name` as missing (so we write an intent file
306
+ // instead of silently auto-filling).
307
+ const genResult = generate(template, {
308
+ templateId: template.id,
309
+ ...(target.userName ? { name: target.userName } : {}),
310
+ variables: target.variables,
311
+ projectRoot: cwd,
312
+ overwriteStrategy: OverwriteStrategy.Never,
313
+ write: false,
314
+ });
315
+ if (!genResult.ok) {
316
+ results.push({
317
+ templateId: target.templateId,
318
+ status: 'generation-error',
319
+ message: genResult.error.message,
320
+ });
321
+ continue;
322
+ }
323
+ const { plan } = genResult.value;
324
+ // The generator's own validator reports missing-required-variable warnings —
325
+ // trust it (it already accounts for buildNameVariables auto-filling
326
+ // name/pascal/className/etc. from --name).
327
+ const missingFromWarnings = plan.warnings
328
+ .map((w) => /^(\w+):\s+Variable\s+'\w+'\s+is required/.exec(w)?.[1])
329
+ .filter((m) => typeof m === 'string');
330
+ if (missingFromWarnings.length > 0 || plan.changes.length === 0) {
331
+ const missing = missingFromWarnings.length > 0
332
+ ? missingFromWarnings
333
+ : (template.variables ?? []).filter((v) => v.required).map((v) => v.name);
334
+ const intentName = `${target.templateId.replace(/[^a-z0-9]+/gi, '-')}.intent.md`;
335
+ const intentBody = buildPlanIntentMarkdown(target, template, missing, load.id);
336
+ writeFileSync(nodePath.join(plansDir, intentName), intentBody, 'utf8');
337
+ state = upsertDevPlanEntry(state, {
338
+ name: intentName.replace(/\.intent\.md$/, ''),
339
+ templateId: target.templateId,
340
+ ...(target.planName ? { generatedName: target.planName } : {}),
341
+ variables: target.variables,
342
+ missingVariables: missing,
343
+ status: DevSessionPlanStatus.Intent,
344
+ file: intentName,
345
+ signed: false,
346
+ });
347
+ results.push({
348
+ templateId: target.templateId,
349
+ status: 'intent',
350
+ file: `plans/${intentName}`,
351
+ missingVariables: missing,
352
+ });
353
+ continue;
354
+ }
355
+ if (plan.hasConflicts) {
356
+ const conflicts = plan.changes
357
+ .filter((c) => String(c.type) === 'conflict')
358
+ .map((c) => c.relativePath);
359
+ results.push({
360
+ templateId: target.templateId,
361
+ status: 'conflicts',
362
+ conflicts,
363
+ });
364
+ continue;
365
+ }
366
+ let saved = buildSavedPlan({
367
+ templateId: template.id,
368
+ ...(target.planName ? { name: target.planName } : {}),
369
+ variables: target.variables,
370
+ projectRoot: cwd,
371
+ plan,
372
+ });
373
+ let signed = false;
374
+ if (wantSign) {
375
+ const r = signPlan(saved);
376
+ if (r.ok) {
377
+ saved = r.value;
378
+ signed = true;
379
+ }
380
+ else {
381
+ results.push({
382
+ templateId: target.templateId,
383
+ status: 'sign-error',
384
+ message: r.error.message,
385
+ });
386
+ continue;
387
+ }
388
+ }
389
+ const planFile = `${target.planName}.json`;
390
+ const planFullPath = nodePath.join(plansDir, planFile);
391
+ const saveResult = savePlanToFile(saved, planFullPath);
392
+ if (!saveResult.ok) {
393
+ results.push({
394
+ templateId: target.templateId,
395
+ status: 'save-error',
396
+ message: saveResult.error.message,
397
+ });
398
+ continue;
399
+ }
400
+ // Run plan review and store under reports/.
401
+ let reviewJsonName;
402
+ let reviewMdName;
403
+ try {
404
+ const review = reviewSavedPlan(inspection, planFullPath);
405
+ reviewJsonName = `plan-review-${target.planName}.json`;
406
+ writeFileSync(nodePath.join(reportsDir, reviewJsonName), JSON.stringify(review, null, 2) + '\n', 'utf8');
407
+ reviewMdName = `plan-review-${target.planName}.md`;
408
+ writeFileSync(nodePath.join(reportsDir, reviewMdName), renderReviewMarkdown(review), 'utf8');
409
+ state = recordReportFile(state, `reports/${reviewJsonName}`);
410
+ state = recordReportFile(state, `reports/${reviewMdName}`);
411
+ }
412
+ catch (e) {
413
+ results.push({
414
+ templateId: target.templateId,
415
+ status: 'review-error',
416
+ message: e.message,
417
+ });
418
+ // continue: the plan is still saved, just no review captured.
419
+ }
420
+ state = upsertDevPlanEntry(state, {
421
+ name: target.planName,
422
+ templateId: target.templateId,
423
+ ...(target.planName ? { generatedName: target.planName } : {}),
424
+ variables: target.variables,
425
+ missingVariables: [],
426
+ status: reviewJsonName ? DevSessionPlanStatus.Reviewed : DevSessionPlanStatus.Saved,
427
+ file: planFile,
428
+ signed,
429
+ ...(reviewJsonName ? { reviewReportFile: reviewJsonName } : {}),
430
+ ...(reviewMdName ? { reviewReportMarkdownFile: reviewMdName } : {}),
431
+ });
432
+ results.push({
433
+ templateId: target.templateId,
434
+ status: reviewJsonName ? 'reviewed' : 'saved',
435
+ file: `plans/${planFile}`,
436
+ signed,
437
+ ...(reviewJsonName ? { reviewReportFile: `reports/${reviewJsonName}` } : {}),
438
+ });
439
+ }
440
+ // Update phase + next action.
441
+ const scanAfter = scanDevSession(cwd, load.id);
442
+ const newPhase = recomputePhase(state, scanAfter);
443
+ state = setDevSessionPhase(state, newPhase);
444
+ const nextAction = computeDevNextAction({ ...scanAfter, state });
445
+ state = setDevNextAction(state, nextAction.command);
446
+ writeDevSessionState(cwd, state);
447
+ if (wantJson) {
448
+ process.stdout.write(asJson({ id: load.id, plans: results, nextAction: state.nextAction }) + '\n');
449
+ return 0;
450
+ }
451
+ process.stdout.write(header(`Dev plan: ${load.id}`));
452
+ for (const r of results) {
453
+ process.stdout.write(` ${String(r.status).padEnd(14)} ${r.file ?? r.templateId}\n`);
454
+ if (Array.isArray(r.missingVariables)) {
455
+ process.stdout.write(` missing: ${r.missingVariables.join(', ')}\n`);
456
+ }
457
+ if (r.message)
458
+ process.stdout.write(` note: ${r.message}\n`);
459
+ if (r.reviewReportFile)
460
+ process.stdout.write(` review: ${r.reviewReportFile}\n`);
461
+ }
462
+ process.stdout.write(`\nPhase: ${state.phase}\n`);
463
+ process.stdout.write(`Next: ${state.nextAction}\n`);
464
+ return 0;
465
+ }
466
+ function buildPlanIntentMarkdown(target, template, missing, sessionId) {
467
+ const lines = [];
468
+ lines.push(`# Plan intent: ${template.id}`);
469
+ lines.push('');
470
+ lines.push(`Template: ${template.name}`);
471
+ lines.push('');
472
+ lines.push('## Required variables');
473
+ lines.push('');
474
+ for (const m of missing) {
475
+ const def = (template.variables ?? []).find((v) => v.name === m);
476
+ lines.push(`- \`${m}\`${def?.description ? ` — ${def.description}` : ''}`);
477
+ }
478
+ lines.push('');
479
+ lines.push('## Why these are needed');
480
+ lines.push('');
481
+ lines.push(`SharkCraft will not hallucinate variable values. ` +
482
+ `Provide them explicitly so the saved plan is deterministic and signable.`);
483
+ lines.push('');
484
+ lines.push('## Example command');
485
+ lines.push('');
486
+ lines.push('```');
487
+ lines.push(`shrk dev plan ${sessionId} --template ${template.id} --name ${target.planName} ` +
488
+ missing.map((m) => `--var ${m}=<value>`).join(' '));
489
+ lines.push('```');
490
+ lines.push('');
491
+ lines.push('## Inspect the template');
492
+ lines.push('');
493
+ lines.push('```');
494
+ lines.push(`shrk templates vars ${template.id}`);
495
+ lines.push('```');
496
+ return lines.join('\n') + '\n';
497
+ }
498
+ function renderReviewMarkdown(report) {
499
+ const lines = [];
500
+ lines.push(`# Plan review`);
501
+ lines.push('');
502
+ lines.push(`Source: \`${report.source}\``);
503
+ if (report.templateId)
504
+ lines.push(`Template: \`${report.templateId}\``);
505
+ lines.push(`Signature: \`${report.signature}\`${report.signatureMessage ? ' — ' + report.signatureMessage : ''}`);
506
+ lines.push('');
507
+ lines.push('## Files');
508
+ lines.push('');
509
+ for (const f of report.files) {
510
+ lines.push(`- \`${f.type}\` \`${f.relativePath}\`${f.reason ? ' — ' + f.reason : ''}`);
511
+ }
512
+ lines.push('');
513
+ if (report.affectedPaths.length > 0) {
514
+ lines.push('## Affected path conventions');
515
+ lines.push('');
516
+ for (const p of report.affectedPaths)
517
+ lines.push(`- \`${p}\``);
518
+ lines.push('');
519
+ }
520
+ if (report.missingTestsHeuristic.length > 0) {
521
+ lines.push('## Missing tests (heuristic)');
522
+ lines.push('');
523
+ for (const m of report.missingTestsHeuristic)
524
+ lines.push(`- ${m}`);
525
+ lines.push('');
526
+ }
527
+ if (report.planIntroducedBoundaryConcerns.length > 0) {
528
+ lines.push('## Boundary concerns introduced by this plan');
529
+ lines.push('');
530
+ for (const c of report.planIntroducedBoundaryConcerns) {
531
+ lines.push(`- **${c.severity.toUpperCase()}** \`${c.file}:${c.line}\` imports \`${c.importSpecifier}\` (rule \`${c.ruleId}\`)`);
532
+ if (c.message)
533
+ lines.push(` - ${c.message}`);
534
+ }
535
+ lines.push('');
536
+ }
537
+ if (report.verificationCommands.length > 0) {
538
+ lines.push('## Verification commands');
539
+ lines.push('');
540
+ for (const c of report.verificationCommands)
541
+ lines.push(`- \`${c}\``);
542
+ lines.push('');
543
+ }
544
+ lines.push('---');
545
+ lines.push('');
546
+ lines.push(report.humanApprovalReminder);
547
+ return lines.join('\n') + '\n';
548
+ }
549
+ function statusSession(args) {
550
+ const loaded = loadSessionOrFail(args);
551
+ if (typeof loaded === 'number')
552
+ return loaded;
553
+ const { load } = loaded;
554
+ const state = load.state;
555
+ const next = computeDevNextAction(load);
556
+ if (flagBool(args, 'json')) {
557
+ const summary = {
558
+ id: load.id,
559
+ task: load.task,
560
+ legacy: load.legacy,
561
+ phase: state?.phase ?? null,
562
+ createdAt: state?.createdAt ?? null,
563
+ updatedAt: state?.updatedAt ?? null,
564
+ selectedPipeline: state?.selectedPipeline ?? null,
565
+ selectedTemplates: state?.selectedTemplates ?? [],
566
+ plans: state
567
+ ? state.plans
568
+ : load.plansOnDisk.concat(load.intentFiles).map((f) => ({ file: f, status: 'unknown' })),
569
+ reports: state?.reports ?? load.reportsOnDisk.map((f) => `reports/${f}`),
570
+ validations: state?.validations ?? [],
571
+ appliedPlans: state?.appliedPlans ?? [],
572
+ warnings: state?.warnings ?? [],
573
+ nextAction: next,
574
+ };
575
+ process.stdout.write(asJson(summary) + '\n');
576
+ return 0;
577
+ }
578
+ process.stdout.write(header(`Dev session: ${load.id}`));
579
+ process.stdout.write(kv('task', load.task || '(no task.md)') + '\n');
580
+ if (state) {
581
+ process.stdout.write(kv('phase', state.phase) + '\n');
582
+ process.stdout.write(kv('createdAt', state.createdAt) + '\n');
583
+ process.stdout.write(kv('updatedAt', state.updatedAt) + '\n');
584
+ process.stdout.write(kv('pipeline', state.selectedPipeline ?? '(none)') + '\n');
585
+ if (state.selectedTemplates.length > 0) {
586
+ process.stdout.write(kv('templates', state.selectedTemplates.join(', ')) + '\n');
587
+ }
588
+ }
589
+ else {
590
+ process.stdout.write(kv('phase', '(legacy — no session.json)') + '\n');
591
+ }
592
+ process.stdout.write('\nPlans:\n');
593
+ if (state && state.plans.length > 0) {
594
+ for (const p of state.plans) {
595
+ process.stdout.write(` • ${p.name} (${p.status}, template ${p.templateId})${p.signed ? ' [signed]' : ''}\n`);
596
+ if (p.missingVariables.length > 0) {
597
+ process.stdout.write(` missing: ${p.missingVariables.join(', ')}\n`);
598
+ }
599
+ if (p.reviewReportFile) {
600
+ process.stdout.write(` review: reports/${p.reviewReportFile}\n`);
601
+ }
602
+ }
603
+ }
604
+ else if (load.plansOnDisk.length > 0 || load.intentFiles.length > 0) {
605
+ for (const f of load.plansOnDisk)
606
+ process.stdout.write(` • plans/${f}\n`);
607
+ for (const f of load.intentFiles)
608
+ process.stdout.write(` • plans/${f} (intent)\n`);
609
+ }
610
+ else {
611
+ process.stdout.write(' (none)\n');
612
+ }
613
+ process.stdout.write('\nValidations:\n');
614
+ if (state && state.validations.length > 0) {
615
+ for (const v of state.validations) {
616
+ process.stdout.write(` • ${v.finishedAt}: ${v.passed ? 'passed' : 'FAILED'} (${v.commandsRun.length} cmd, ${v.boundaryViolations} boundary)\n`);
617
+ }
618
+ }
619
+ else {
620
+ process.stdout.write(' (not run)\n');
621
+ }
622
+ process.stdout.write('\nApplied plans:\n');
623
+ if (state && state.appliedPlans.length > 0) {
624
+ for (const a of state.appliedPlans) {
625
+ process.stdout.write(` • plans/${a.file} (applied ${a.appliedAt})\n`);
626
+ }
627
+ }
628
+ else {
629
+ process.stdout.write(' (none recorded — apply is the explicit human step)\n');
630
+ }
631
+ process.stdout.write('\nNext action:\n');
632
+ process.stdout.write(` ${next.action}\n`);
633
+ process.stdout.write(` $ ${next.command}\n`);
634
+ process.stdout.write(` reason: ${next.reason}\n`);
635
+ if (next.requiresHumanApproval) {
636
+ process.stdout.write(` ⚠ requires human approval before running\n`);
637
+ }
638
+ return 0;
639
+ }
640
+ function nextOrContinue(args) {
641
+ const loaded = loadSessionOrFail(args);
642
+ if (typeof loaded === 'number')
643
+ return loaded;
644
+ const { load, cwd } = loaded;
645
+ const next = computeDevNextAction(load);
646
+ // Persist nextAction in session.json if it changed (no other writes).
647
+ if (load.state && load.state.nextAction !== next.command) {
648
+ const updated = setDevNextAction(load.state, next.command);
649
+ writeDevSessionState(cwd, updated);
650
+ }
651
+ if (flagBool(args, 'json')) {
652
+ process.stdout.write(asJson(next) + '\n');
653
+ return 0;
654
+ }
655
+ process.stdout.write(header(`Next action: ${load.id}`));
656
+ process.stdout.write(` ${next.action}\n`);
657
+ process.stdout.write(` $ ${next.command}\n`);
658
+ process.stdout.write(` reason: ${next.reason}\n`);
659
+ if (next.requiresHumanApproval) {
660
+ process.stdout.write(` ⚠ requires human approval before running\n`);
661
+ }
662
+ return 0;
663
+ }
664
+ async function validateSession(args) {
665
+ const loaded = loadSessionOrFail(args);
666
+ if (typeof loaded === 'number')
667
+ return loaded;
668
+ const { load, cwd } = loaded;
669
+ const reportsDir = nodePath.join(load.dir, 'reports');
670
+ mkdirSync(reportsDir, { recursive: true });
671
+ const verificationIds = flagList(args, 'verification');
672
+ const allVerifications = flagBool(args, 'all-verifications');
673
+ const allowPackCommands = flagBool(args, 'allow-pack-commands');
674
+ const wantStrict = flagBool(args, 'strict');
675
+ const wantReport = flagBool(args, 'report') !== false; // default: write report
676
+ const wantJson = flagBool(args, 'json');
677
+ const startedAt = new Date().toISOString();
678
+ const reportFileName = `validate-${startedAt.replace(/[:.]/g, '-')}.json`;
679
+ const cmd = flagString(args, 'command');
680
+ if (!wantJson) {
681
+ process.stdout.write(header(`Dev validate: ${load.id}`));
682
+ if (cmd)
683
+ process.stdout.write(` command: ${cmd}\n`);
684
+ if (verificationIds.length > 0) {
685
+ process.stdout.write(` verifications: ${verificationIds.join(', ')}\n`);
686
+ }
687
+ else if (allVerifications) {
688
+ process.stdout.write(` verifications: (all configured)\n`);
689
+ }
690
+ if (!allowPackCommands) {
691
+ process.stdout.write(` pack commands: skipped (pass --allow-pack-commands to opt in)\n`);
692
+ }
693
+ process.stdout.write('\n');
694
+ }
695
+ const result = await runValidationLoop({
696
+ cwd,
697
+ ...(cmd ? { explicitCommand: cmd } : {}),
698
+ verificationIds,
699
+ allVerifications,
700
+ allowPackCommands,
701
+ reportDir: wantReport ? reportsDir : null,
702
+ reportFileName,
703
+ onCommandStart: (label) => {
704
+ if (!wantJson)
705
+ process.stdout.write(` → running: ${label}\n`);
706
+ },
707
+ });
708
+ const finishedAt = new Date().toISOString();
709
+ const passedFinal = result.passed && (!wantStrict || result.warnings === 0);
710
+ // Persist into session.json if we have a state object.
711
+ let stateAfter = load.state;
712
+ if (stateAfter) {
713
+ stateAfter = recordValidation(stateAfter, {
714
+ startedAt,
715
+ finishedAt,
716
+ reportFile: reportFileName,
717
+ passed: passedFinal,
718
+ warnings: result.warnings,
719
+ commandsRun: result.commandsRun.map((c) => {
720
+ const entry = {
721
+ command: c.command,
722
+ passed: c.passed,
723
+ };
724
+ if (c.note !== undefined)
725
+ entry.note = c.note;
726
+ return entry;
727
+ }),
728
+ boundaryViolations: result.boundaryViolations,
729
+ });
730
+ // If applied plans haven't been tracked explicitly, infer from session
731
+ // plans that the user must have applied something to get to validate.
732
+ if (stateAfter.appliedPlans.length === 0 && stateAfter.plans.length > 0) {
733
+ for (const p of stateAfter.plans.filter((p) => p.status !== DevSessionPlanStatus.Intent)) {
734
+ stateAfter = recordAppliedPlan(stateAfter, {
735
+ file: p.file,
736
+ appliedAt: finishedAt,
737
+ note: 'inferred from dev validate',
738
+ });
739
+ }
740
+ }
741
+ const scanAfter = scanDevSession(cwd, load.id);
742
+ const newPhase = passedFinal
743
+ ? DevSessionPhase.Validated
744
+ : recomputePhase(stateAfter, scanAfter);
745
+ stateAfter = setDevSessionPhase(stateAfter, newPhase);
746
+ const next = computeDevNextAction({ ...scanAfter, state: stateAfter });
747
+ stateAfter = setDevNextAction(stateAfter, next.command);
748
+ writeDevSessionState(cwd, stateAfter);
749
+ }
750
+ if (wantJson) {
751
+ process.stdout.write(asJson({
752
+ id: load.id,
753
+ passed: passedFinal,
754
+ warnings: result.warnings,
755
+ boundaryViolations: result.boundaryViolations,
756
+ commandsRun: result.commandsRun,
757
+ commandsFailed: result.commandsFailed,
758
+ reportPath: result.reportPath,
759
+ nextAction: stateAfter?.nextAction ?? null,
760
+ }) + '\n');
761
+ return passedFinal ? 0 : 1;
762
+ }
763
+ process.stdout.write(`\nValidation: ${result.commandsRun.length} command(s), ${result.commandsFailed.length} failed, ${result.warnings} warning(s)\n`);
764
+ for (const c of result.commandsRun) {
765
+ process.stdout.write(` ${c.passed ? 'OK ' : 'FAIL '} ${c.command}${c.note ? ' (' + c.note + ')' : ''}\n`);
766
+ }
767
+ if (result.boundaryViolations > 0) {
768
+ process.stdout.write(` WARN ${result.boundaryViolations} boundary violation(s)\n`);
769
+ }
770
+ if (result.reportPath)
771
+ process.stdout.write(` Report: ${result.reportPath}\n`);
772
+ process.stdout.write(`\nValidation: ${passedFinal ? 'OK ✓' : 'FAILED'}\n`);
773
+ return passedFinal ? 0 : 1;
774
+ }
775
+ function reportSession(args) {
776
+ const loaded = loadSessionOrFail(args);
777
+ if (typeof loaded === 'number')
778
+ return loaded;
779
+ const { load, cwd } = loaded;
780
+ const next = computeDevNextAction(load);
781
+ const md = renderDevSessionFinalReport(load, {
782
+ nextActionLine: `${next.action} — \`${next.command}\``,
783
+ });
784
+ const out = nodePath.join(load.dir, 'final-report.md');
785
+ writeFileSync(out, md, 'utf8');
786
+ let htmlOut;
787
+ if (flagBool(args, 'html')) {
788
+ const html = renderDevSessionHtml(load, {
789
+ nextActionLine: `${next.action} — ${next.command}`,
790
+ });
791
+ htmlOut = nodePath.join(load.dir, 'final-report.html');
792
+ writeFileSync(htmlOut, html, 'utf8');
793
+ }
794
+ if (load.state) {
795
+ let state = recordReportFile(load.state, 'final-report.md');
796
+ if (htmlOut)
797
+ state = recordReportFile(state, 'final-report.html');
798
+ state = setDevSessionPhase(state, DevSessionPhase.Completed);
799
+ state = setDevNextAction(state, `shrk session show ${load.id}`);
800
+ writeDevSessionState(cwd, state);
801
+ }
802
+ if (flagBool(args, 'json')) {
803
+ process.stdout.write(asJson({ id: load.id, path: out, ...(htmlOut ? { htmlPath: htmlOut } : {}) }) + '\n');
804
+ return 0;
805
+ }
806
+ process.stdout.write(`Wrote ${out}\n`);
807
+ if (htmlOut)
808
+ process.stdout.write(`Wrote ${htmlOut}\n`);
809
+ return 0;
810
+ }
811
+ function listSessionsCmd(args) {
812
+ const cwd = resolveCwd(args);
813
+ const items = listDevSessionsDetailed(cwd);
814
+ if (flagBool(args, 'json')) {
815
+ process.stdout.write(asJson(items) + '\n');
816
+ return 0;
817
+ }
818
+ process.stdout.write(header(`Dev sessions (${items.length})`));
819
+ for (const it of items.slice(0, 20)) {
820
+ const phase = it.phase ?? (it.legacy ? 'legacy' : 'unknown');
821
+ process.stdout.write(` • ${it.id} [${phase}] ${it.task || '(no task)'}\n`);
822
+ if (it.nextAction)
823
+ process.stdout.write(` next: ${it.nextAction}\n`);
824
+ }
825
+ if (items.length > 20)
826
+ process.stdout.write(` … (${items.length - 20} more)\n`);
827
+ return 0;
828
+ }
829
+ // ─── Part 3: dev mark-applied / mark-validated ─────────────────────────────
830
+ function markApplied(args) {
831
+ const id = args.positional[0];
832
+ const planArg = args.positional[1];
833
+ if (!id || !planArg) {
834
+ process.stderr.write('Usage: shrk dev mark-applied <sessionId> <planPath> [--note "..."]\n');
835
+ return 2;
836
+ }
837
+ const cwd = resolveCwd(args);
838
+ const load = scanDevSession(cwd, id);
839
+ if (!load) {
840
+ process.stderr.write(`No session "${id}".\n`);
841
+ return 1;
842
+ }
843
+ if (!load.state) {
844
+ process.stderr.write(`Session ${id} has no session.json (legacy). mark-applied requires a v1 session.\n`);
845
+ return 1;
846
+ }
847
+ // Resolve the plan to a path relative to plans/ within the session.
848
+ const planFile = resolveSessionPlanFile(load, planArg);
849
+ if (!planFile) {
850
+ process.stderr.write(`Plan "${planArg}" not found under .sharkcraft/sessions/${id}/plans/.\n`);
851
+ return 1;
852
+ }
853
+ const note = flagString(args, 'note');
854
+ let state = recordAppliedPlan(load.state, {
855
+ file: planFile,
856
+ appliedAt: new Date().toISOString(),
857
+ ...(note ? { note } : { note: 'recorded via shrk dev mark-applied' }),
858
+ });
859
+ // Promote plan entry status.
860
+ const planEntry = load.state.plans.find((p) => p.file === planFile);
861
+ if (planEntry) {
862
+ state = upsertDevPlanEntry(state, {
863
+ name: planEntry.name,
864
+ templateId: planEntry.templateId,
865
+ ...(planEntry.generatedName ? { generatedName: planEntry.generatedName } : {}),
866
+ variables: { ...planEntry.variables },
867
+ missingVariables: planEntry.missingVariables,
868
+ status: DevSessionPlanStatus.Applied,
869
+ file: planEntry.file,
870
+ signed: planEntry.signed,
871
+ ...(planEntry.reviewReportFile ? { reviewReportFile: planEntry.reviewReportFile } : {}),
872
+ ...(planEntry.reviewReportMarkdownFile
873
+ ? { reviewReportMarkdownFile: planEntry.reviewReportMarkdownFile }
874
+ : {}),
875
+ });
876
+ }
877
+ const scanAfter = scanDevSession(cwd, id);
878
+ state = setDevSessionPhase(state, recomputePhase(state, scanAfter));
879
+ const next = computeDevNextAction({ ...scanAfter, state });
880
+ state = setDevNextAction(state, next.command);
881
+ writeDevSessionState(cwd, state);
882
+ if (flagBool(args, 'json')) {
883
+ process.stdout.write(asJson({ id, planFile, phase: state.phase, nextAction: state.nextAction }) + '\n');
884
+ return 0;
885
+ }
886
+ process.stdout.write(`Marked plan applied: ${planFile}\n`);
887
+ process.stdout.write(`Phase: ${state.phase}\n`);
888
+ if (state.nextAction)
889
+ process.stdout.write(`Next: ${state.nextAction}\n`);
890
+ return 0;
891
+ }
892
+ function markValidated(args) {
893
+ const id = args.positional[0];
894
+ if (!id) {
895
+ process.stderr.write('Usage: shrk dev mark-validated <sessionId> [--report <path>] [--status passed|failed] [--note "..."]\n');
896
+ return 2;
897
+ }
898
+ const cwd = resolveCwd(args);
899
+ const load = scanDevSession(cwd, id);
900
+ if (!load) {
901
+ process.stderr.write(`No session "${id}".\n`);
902
+ return 1;
903
+ }
904
+ if (!load.state) {
905
+ process.stderr.write(`Session ${id} has no session.json (legacy). mark-validated requires a v1 session.\n`);
906
+ return 1;
907
+ }
908
+ const statusFlag = flagString(args, 'status') ?? 'passed';
909
+ const passed = statusFlag === 'passed';
910
+ if (statusFlag !== 'passed' && statusFlag !== 'failed') {
911
+ process.stderr.write(`Unknown --status "${statusFlag}". Use "passed" or "failed".\n`);
912
+ return 2;
913
+ }
914
+ const note = flagString(args, 'note');
915
+ const reportArg = flagString(args, 'report');
916
+ let reportFile = `mark-validated-${new Date().toISOString().replace(/[:.]/g, '-')}.json`;
917
+ if (reportArg) {
918
+ const reportAbs = nodePath.isAbsolute(reportArg)
919
+ ? reportArg
920
+ : nodePath.resolve(cwd, reportArg);
921
+ if (!existsSync(reportAbs)) {
922
+ process.stderr.write(`--report path not found: ${reportAbs}\n`);
923
+ return 1;
924
+ }
925
+ // Use the basename relative to the reports/ dir if it's already inside; otherwise
926
+ // record the absolute hint as a `note`.
927
+ const reportsDir = nodePath.join(load.dir, 'reports');
928
+ if (reportAbs.startsWith(reportsDir + nodePath.sep) || reportAbs === reportsDir) {
929
+ reportFile = nodePath.basename(reportAbs);
930
+ }
931
+ else {
932
+ reportFile = nodePath.basename(reportAbs);
933
+ }
934
+ }
935
+ const now = new Date().toISOString();
936
+ let state = recordValidation(load.state, {
937
+ startedAt: now,
938
+ finishedAt: now,
939
+ reportFile,
940
+ passed,
941
+ warnings: 0,
942
+ commandsRun: note ? [{ command: 'manual', passed, note }] : [],
943
+ boundaryViolations: 0,
944
+ });
945
+ if (reportArg)
946
+ state = recordReportFile(state, `reports/${reportFile}`);
947
+ const scanAfter = scanDevSession(cwd, id);
948
+ const newPhase = passed ? DevSessionPhase.Validated : DevSessionPhase.ValidationFailed;
949
+ state = setDevSessionPhase(state, newPhase);
950
+ const next = computeDevNextAction({ ...scanAfter, state });
951
+ state = setDevNextAction(state, next.command);
952
+ writeDevSessionState(cwd, state);
953
+ if (flagBool(args, 'json')) {
954
+ process.stdout.write(asJson({ id, status: statusFlag, reportFile, phase: state.phase, nextAction: state.nextAction }) +
955
+ '\n');
956
+ return 0;
957
+ }
958
+ process.stdout.write(`Marked session ${statusFlag}: ${id}\n`);
959
+ process.stdout.write(`Phase: ${state.phase}\n`);
960
+ if (state.nextAction)
961
+ process.stdout.write(`Next: ${state.nextAction}\n`);
962
+ return 0;
963
+ }
964
+ function resolveSessionPlanFile(load, planArg) {
965
+ const plansDir = nodePath.join(load.dir, 'plans');
966
+ // First, treat the arg as a basename within plans/.
967
+ const candidates = [planArg, nodePath.basename(planArg)];
968
+ for (const c of candidates) {
969
+ if (existsSync(nodePath.join(plansDir, c)))
970
+ return c;
971
+ }
972
+ // Else: if the arg is an absolute path inside this session's plans dir, accept.
973
+ const abs = nodePath.isAbsolute(planArg)
974
+ ? planArg
975
+ : nodePath.resolve(process.cwd(), planArg);
976
+ if (abs.startsWith(plansDir + nodePath.sep) && existsSync(abs)) {
977
+ return nodePath.relative(plansDir, abs);
978
+ }
979
+ return null;
980
+ }
981
+ // ─── Part 4: dev diff ──────────────────────────────────────────────────────
982
+ function diffCmd(args) {
983
+ const aId = args.positional[0];
984
+ const bId = args.positional[1];
985
+ if (!aId || !bId) {
986
+ process.stderr.write('Usage: shrk dev diff <sessionA> <sessionB> [--json]\n');
987
+ return 2;
988
+ }
989
+ const cwd = resolveCwd(args);
990
+ const a = scanDevSession(cwd, aId);
991
+ const b = scanDevSession(cwd, bId);
992
+ if (!a) {
993
+ process.stderr.write(`No session "${aId}".\n`);
994
+ return 1;
995
+ }
996
+ if (!b) {
997
+ process.stderr.write(`No session "${bId}".\n`);
998
+ return 1;
999
+ }
1000
+ const diff = diffDevSessions(a, b);
1001
+ if (flagBool(args, 'json')) {
1002
+ process.stdout.write(asJson(diff) + '\n');
1003
+ return 0;
1004
+ }
1005
+ process.stdout.write(header(`Dev diff: ${aId} ↔ ${bId}`));
1006
+ process.stdout.write(kv('A task', diff.a.task || '(none)') + '\n' + kv('B task', diff.b.task || '(none)') + '\n');
1007
+ process.stdout.write(kv('phase', diff.phase.changed ? `${diff.a.phase ?? '-'} → ${diff.b.phase ?? '-'}` : 'same') +
1008
+ '\n');
1009
+ process.stdout.write(kv('pipeline', diff.selectedPipeline.changed
1010
+ ? `${a.state?.selectedPipeline ?? '-'} → ${b.state?.selectedPipeline ?? '-'}`
1011
+ : 'same') + '\n');
1012
+ process.stdout.write(kv('validations', `A:${diff.validations.aCount} B:${diff.validations.bCount}`) + '\n');
1013
+ const groups = [
1014
+ { label: 'Templates (top from packet)', group: diff.topTemplates },
1015
+ { label: 'Rules (top from packet)', group: diff.topRules },
1016
+ { label: 'Selected templates', group: diff.selectedTemplates },
1017
+ { label: 'Plans', group: diff.plans },
1018
+ { label: 'Applied plans', group: diff.appliedPlans },
1019
+ { label: 'Reports', group: diff.reports },
1020
+ { label: 'Forbidden actions', group: diff.forbiddenActions },
1021
+ { label: 'Verification commands', group: diff.verificationCommands },
1022
+ { label: 'CLI commands', group: diff.cliCommands },
1023
+ { label: 'MCP tools', group: diff.mcpTools },
1024
+ ];
1025
+ for (const { label, group } of groups) {
1026
+ if (group.onlyA.length === 0 && group.onlyB.length === 0)
1027
+ continue;
1028
+ process.stdout.write(`\n${label}:\n`);
1029
+ for (const x of group.onlyA)
1030
+ process.stdout.write(` - only in A: ${x}\n`);
1031
+ for (const x of group.onlyB)
1032
+ process.stdout.write(` + only in B: ${x}\n`);
1033
+ }
1034
+ return 0;
1035
+ }
1036
+ // ─── Part 5: dev archive / clean ───────────────────────────────────────────
1037
+ function archiveCmd(args) {
1038
+ const id = args.positional[0];
1039
+ if (!id) {
1040
+ process.stderr.write('Usage: shrk dev archive <sessionId>\n');
1041
+ return 2;
1042
+ }
1043
+ const cwd = resolveCwd(args);
1044
+ const result = archiveDevSession(cwd, id);
1045
+ if (flagBool(args, 'json')) {
1046
+ process.stdout.write(asJson(result) + '\n');
1047
+ return result.archived ? 0 : 1;
1048
+ }
1049
+ if (result.archived) {
1050
+ process.stdout.write(`Archived ${id} → ${result.to}\n`);
1051
+ return 0;
1052
+ }
1053
+ process.stderr.write(`Could not archive ${id}: ${result.reason ?? 'unknown'}\n`);
1054
+ return 1;
1055
+ }
1056
+ function cleanCmd(args) {
1057
+ const cwd = resolveCwd(args);
1058
+ const olderThan = flagString(args, 'older-than');
1059
+ if (!olderThan) {
1060
+ process.stderr.write('Usage: shrk dev clean --older-than <duration> [--archive] [--write] [--include-active]\n' +
1061
+ ' duration accepts: 30m | 24h | 7d | 2w\n');
1062
+ return 2;
1063
+ }
1064
+ const olderThanMs = parseDurationToMs(olderThan);
1065
+ if (olderThanMs === null) {
1066
+ process.stderr.write(`Invalid --older-than value: "${olderThan}"\n`);
1067
+ return 2;
1068
+ }
1069
+ const includeActive = flagBool(args, 'include-active');
1070
+ const archive = flagBool(args, 'archive');
1071
+ const write = flagBool(args, 'write');
1072
+ const candidates = listDevCleanCandidates({
1073
+ cwd,
1074
+ olderThanMs,
1075
+ includeActive,
1076
+ });
1077
+ const eligible = candidates.filter((c) => c.reason === 'eligible' || c.reason === 'legacy session');
1078
+ const wantJson = flagBool(args, 'json');
1079
+ if (!write) {
1080
+ if (wantJson) {
1081
+ process.stdout.write(asJson({ dryRun: true, archive, candidates, eligible: eligible.map((c) => c.id) }) + '\n');
1082
+ return 0;
1083
+ }
1084
+ process.stdout.write(header('shrk dev clean (dry run)'));
1085
+ process.stdout.write(` olderThan=${olderThan} archive=${archive} includeActive=${includeActive}\n\n`);
1086
+ for (const c of candidates) {
1087
+ process.stdout.write(` ${c.reason === 'eligible' ? 'WILL ' : 'SKIP '} ${c.id} age=${Math.round(c.ageMs / 86_400_000)}d phase=${c.phase ?? '-'}${c.active ? ' (active)' : ''}\n`);
1088
+ }
1089
+ process.stdout.write(`\n${eligible.length} session(s) match. Pass --write to ${archive ? 'archive' : 'delete'} them.\n`);
1090
+ return 0;
1091
+ }
1092
+ // --write: actually perform the action.
1093
+ const results = [];
1094
+ for (const c of candidates) {
1095
+ if (c.reason !== 'eligible' && c.reason !== 'legacy session') {
1096
+ results.push({ id: c.id, action: 'skipped', reason: c.reason });
1097
+ continue;
1098
+ }
1099
+ if (archive) {
1100
+ const r = archiveDevSession(cwd, c.id);
1101
+ results.push(r.archived
1102
+ ? { id: c.id, action: 'archived' }
1103
+ : { id: c.id, action: 'skipped', reason: r.reason ?? 'archive failed' });
1104
+ continue;
1105
+ }
1106
+ // Delete.
1107
+ try {
1108
+ rmSync(getDevSessionDir(cwd, c.id), { recursive: true, force: true });
1109
+ results.push({ id: c.id, action: 'deleted' });
1110
+ }
1111
+ catch (e) {
1112
+ results.push({ id: c.id, action: 'skipped', reason: e.message });
1113
+ }
1114
+ }
1115
+ if (wantJson) {
1116
+ process.stdout.write(asJson({ results }) + '\n');
1117
+ return 0;
1118
+ }
1119
+ for (const r of results) {
1120
+ process.stdout.write(` ${r.action.padEnd(9)} ${r.id}${r.reason ? ' (' + r.reason + ')' : ''}\n`);
1121
+ }
1122
+ return 0;
1123
+ }
1124
+ // ─── Part 6: dev open / plans / reports / commands ─────────────────────────
1125
+ async function openCmd(args) {
1126
+ const id = args.positional[0];
1127
+ if (!id) {
1128
+ process.stderr.write('Usage: shrk dev open <sessionId> [--html] [--serve [--host <addr>] [--port <n>]]\n');
1129
+ return 2;
1130
+ }
1131
+ const cwd = resolveCwd(args);
1132
+ const load = scanDevSession(cwd, id);
1133
+ if (!load) {
1134
+ process.stderr.write(`No session "${id}".\n`);
1135
+ return 1;
1136
+ }
1137
+ // --serve: spin up a tiny local-only HTTP server. Default binds 127.0.0.1.
1138
+ if (flagBool(args, 'serve')) {
1139
+ return serveSessionHtml(args, load);
1140
+ }
1141
+ if (flagBool(args, 'html')) {
1142
+ const html = renderDevSessionHtml(load, {
1143
+ nextActionLine: load.state?.nextAction ?? undefined,
1144
+ });
1145
+ const out = nodePath.join(load.dir, 'final-report.html');
1146
+ writeFileSync(out, html, 'utf8');
1147
+ if (flagBool(args, 'json')) {
1148
+ process.stdout.write(asJson({ id, htmlPath: out }) + '\n');
1149
+ return 0;
1150
+ }
1151
+ process.stdout.write(`Wrote ${out}\n`);
1152
+ return 0;
1153
+ }
1154
+ if (flagBool(args, 'json')) {
1155
+ process.stdout.write(asJson({
1156
+ id,
1157
+ dir: load.dir,
1158
+ files: {
1159
+ task: 'task.md',
1160
+ packet: 'task-packet.json',
1161
+ state: 'session.json',
1162
+ plansDir: 'plans/',
1163
+ reportsDir: 'reports/',
1164
+ },
1165
+ }) + '\n');
1166
+ return 0;
1167
+ }
1168
+ process.stdout.write(header(`Dev session: ${id}`));
1169
+ process.stdout.write(` dir: ${load.dir}\n`);
1170
+ process.stdout.write(` task: ${nodePath.join(load.dir, 'task.md')}\n`);
1171
+ process.stdout.write(` packet: ${nodePath.join(load.dir, 'task-packet.json')}\n`);
1172
+ process.stdout.write(` state: ${nodePath.join(load.dir, 'session.json')}\n`);
1173
+ process.stdout.write(` plans/: ${nodePath.join(load.dir, 'plans')}\n`);
1174
+ process.stdout.write(` reports/: ${nodePath.join(load.dir, 'reports')}\n`);
1175
+ if (load.state?.nextAction) {
1176
+ process.stdout.write(`\n next: ${load.state.nextAction}\n`);
1177
+ }
1178
+ return 0;
1179
+ }
1180
+ async function serveSessionHtml(args, load) {
1181
+ const { startLiveSessionServer } = await import("../dashboard/live-session-server.js");
1182
+ const host = flagString(args, 'host') ?? '127.0.0.1';
1183
+ const port = Number(flagString(args, 'port') ?? '0');
1184
+ const live = flagBool(args, 'live');
1185
+ const handle = await startLiveSessionServer({
1186
+ cwd: resolveCwd(args),
1187
+ load,
1188
+ host,
1189
+ port,
1190
+ live,
1191
+ });
1192
+ process.stdout.write(`Serving session ${load.id} at ${handle.url}/${live ? ' (live)' : ''}\n` +
1193
+ `(local-only by default; press Ctrl+C to stop)\n`);
1194
+ if (flagBool(args, 'open') && process.platform === 'darwin') {
1195
+ try {
1196
+ spawnSync('open', [`${handle.url}/`]);
1197
+ }
1198
+ catch {
1199
+ /* ignore */
1200
+ }
1201
+ }
1202
+ return new Promise((resolve) => {
1203
+ const shutdown = () => {
1204
+ handle.close().finally(() => resolve(0));
1205
+ };
1206
+ process.on('SIGINT', shutdown);
1207
+ process.on('SIGTERM', shutdown);
1208
+ });
1209
+ }
1210
+ function plansCmd(args) {
1211
+ const id = args.positional[0];
1212
+ if (!id) {
1213
+ process.stderr.write('Usage: shrk dev plans <sessionId>\n');
1214
+ return 2;
1215
+ }
1216
+ const cwd = resolveCwd(args);
1217
+ const load = scanDevSession(cwd, id);
1218
+ if (!load) {
1219
+ process.stderr.write(`No session "${id}".\n`);
1220
+ return 1;
1221
+ }
1222
+ const plansDir = nodePath.join(load.dir, 'plans');
1223
+ const items = load.state?.plans ?? [];
1224
+ if (flagBool(args, 'json')) {
1225
+ process.stdout.write(asJson({
1226
+ id,
1227
+ plansDir,
1228
+ plans: items.map((p) => ({
1229
+ name: p.name,
1230
+ status: p.status,
1231
+ file: p.file,
1232
+ path: nodePath.join(plansDir, p.file),
1233
+ signed: p.signed,
1234
+ templateId: p.templateId,
1235
+ missingVariables: p.missingVariables,
1236
+ })),
1237
+ plansOnDisk: load.plansOnDisk,
1238
+ intentFiles: load.intentFiles,
1239
+ }) + '\n');
1240
+ return 0;
1241
+ }
1242
+ process.stdout.write(header(`Dev plans: ${id}`));
1243
+ process.stdout.write(` plansDir: ${plansDir}\n\n`);
1244
+ if (items.length === 0 && load.plansOnDisk.length === 0 && load.intentFiles.length === 0) {
1245
+ process.stdout.write(' (no plans)\n');
1246
+ return 0;
1247
+ }
1248
+ for (const p of items) {
1249
+ process.stdout.write(` • ${p.name.padEnd(28)} ${p.status.padEnd(10)} ${p.file}\n`);
1250
+ if (p.missingVariables.length > 0) {
1251
+ process.stdout.write(` missing: ${p.missingVariables.join(', ')}\n`);
1252
+ }
1253
+ }
1254
+ for (const f of load.plansOnDisk.filter((f) => !items.some((p) => p.file === f))) {
1255
+ process.stdout.write(` • ${f} (not tracked in session.json)\n`);
1256
+ }
1257
+ for (const f of load.intentFiles.filter((f) => !items.some((p) => p.file === f))) {
1258
+ process.stdout.write(` • ${f} (intent, not tracked)\n`);
1259
+ }
1260
+ return 0;
1261
+ }
1262
+ function reportsCmd(args) {
1263
+ const id = args.positional[0];
1264
+ if (!id) {
1265
+ process.stderr.write('Usage: shrk dev reports <sessionId>\n');
1266
+ return 2;
1267
+ }
1268
+ const cwd = resolveCwd(args);
1269
+ const load = scanDevSession(cwd, id);
1270
+ if (!load) {
1271
+ process.stderr.write(`No session "${id}".\n`);
1272
+ return 1;
1273
+ }
1274
+ const reportsDir = nodePath.join(load.dir, 'reports');
1275
+ if (flagBool(args, 'json')) {
1276
+ process.stdout.write(asJson({
1277
+ id,
1278
+ reportsDir,
1279
+ reportsOnDisk: load.reportsOnDisk,
1280
+ trackedReports: load.state?.reports ?? [],
1281
+ validations: load.state?.validations ?? [],
1282
+ }) + '\n');
1283
+ return 0;
1284
+ }
1285
+ process.stdout.write(header(`Dev reports: ${id}`));
1286
+ process.stdout.write(` reportsDir: ${reportsDir}\n\n`);
1287
+ if (load.reportsOnDisk.length === 0) {
1288
+ process.stdout.write(' (no reports)\n');
1289
+ return 0;
1290
+ }
1291
+ for (const r of load.reportsOnDisk)
1292
+ process.stdout.write(` • ${r}\n`);
1293
+ return 0;
1294
+ }
1295
+ function commandsCmd(args) {
1296
+ const id = args.positional[0];
1297
+ if (!id) {
1298
+ process.stderr.write('Usage: shrk dev commands <sessionId>\n');
1299
+ return 2;
1300
+ }
1301
+ const cwd = resolveCwd(args);
1302
+ const load = scanDevSession(cwd, id);
1303
+ if (!load) {
1304
+ process.stderr.write(`No session "${id}".\n`);
1305
+ return 1;
1306
+ }
1307
+ const plansRel = `.sharkcraft/sessions/${id}/plans`;
1308
+ const reportsRel = `.sharkcraft/sessions/${id}/reports`;
1309
+ const commands = {
1310
+ plan: `shrk dev plan ${id} --template <id> --name <name> [--var k=v ...]`,
1311
+ review: `shrk dev plan ${id} # (re-running plan auto-reviews)`,
1312
+ apply: `shrk apply ${plansRel}/<plan>.json --verify-signature`,
1313
+ applyWithSession: `shrk apply ${plansRel}/<plan>.json --session ${id} --verify-signature`,
1314
+ validate: `shrk dev validate ${id}`,
1315
+ validateWithReport: `shrk apply ${plansRel}/<plan>.json --validate --report`,
1316
+ report: `shrk dev report ${id}`,
1317
+ diff: `shrk dev diff <otherSessionId> ${id}`,
1318
+ open: `shrk dev open ${id}`,
1319
+ plans: `shrk dev plans ${id}`,
1320
+ reports: `shrk dev reports ${id}`,
1321
+ };
1322
+ if (flagBool(args, 'json')) {
1323
+ process.stdout.write(asJson({ id, commands, plansDir: plansRel, reportsDir: reportsRel }) + '\n');
1324
+ return 0;
1325
+ }
1326
+ process.stdout.write(header(`Dev commands: ${id}`));
1327
+ for (const [k, v] of Object.entries(commands)) {
1328
+ process.stdout.write(` # ${k}\n`);
1329
+ process.stdout.write(` $ ${v}\n\n`);
1330
+ }
1331
+ return 0;
1332
+ }
1333
+ export const devCommand = {
1334
+ name: 'dev',
1335
+ description: 'Safe AI-assisted development workflow: task → session → plan → review → apply (CLI) → validate → report. ' +
1336
+ 'Never auto-applies plans; never runs untrusted pack commands; never writes outside .sharkcraft/sessions/.',
1337
+ usage: 'shrk dev <start|plan|status|next|continue|validate|report|list|mark-applied|mark-validated|diff|archive|clean|open|plans|reports|commands> [args...] [--cwd <dir>] [--json]\n' +
1338
+ ' alias: shrk dev "<task>" → shrk dev start "<task>"',
1339
+ async run(args) {
1340
+ const first = args.positional[0];
1341
+ // If no first arg, print usage.
1342
+ if (!first) {
1343
+ process.stderr.write('Usage: shrk dev <start|plan|status|next|continue|validate|report|list|mark-applied|mark-validated|diff|archive|clean|open|plans|reports|commands> [args...]\n' +
1344
+ ' shrk dev "<task>" (alias for: shrk dev start "<task>")\n');
1345
+ return 2;
1346
+ }
1347
+ // Recognize known subcommands.
1348
+ if (SUBCOMMANDS.has(first)) {
1349
+ const sliced = { ...args, positional: args.positional.slice(1) };
1350
+ switch (first) {
1351
+ case 'start':
1352
+ return startSession(sliced);
1353
+ case 'plan':
1354
+ return planSession(sliced);
1355
+ case 'status':
1356
+ return statusSession(sliced);
1357
+ case 'next':
1358
+ case 'continue':
1359
+ return nextOrContinue(sliced);
1360
+ case 'validate':
1361
+ return validateSession(sliced);
1362
+ case 'report':
1363
+ return reportSession(sliced);
1364
+ case 'list':
1365
+ return listSessionsCmd(sliced);
1366
+ case 'mark-applied':
1367
+ return markApplied(sliced);
1368
+ case 'mark-validated':
1369
+ return markValidated(sliced);
1370
+ case 'diff':
1371
+ return diffCmd(sliced);
1372
+ case 'archive':
1373
+ return archiveCmd(sliced);
1374
+ case 'clean':
1375
+ return cleanCmd(sliced);
1376
+ case 'open':
1377
+ return openCmd(sliced);
1378
+ case 'plans':
1379
+ return plansCmd(sliced);
1380
+ case 'reports':
1381
+ return reportsCmd(sliced);
1382
+ case 'commands':
1383
+ return commandsCmd(sliced);
1384
+ // `dev cycle` removed (subsumed by `dev start`/`dev plan`).
1385
+ default:
1386
+ break;
1387
+ }
1388
+ }
1389
+ // Alias form: shrk dev "<task>" → shrk dev start "<task>".
1390
+ return startSession(args);
1391
+ },
1392
+ };