specky-sdd 3.11.1 → 3.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (392) hide show
  1. package/.apm/hooks/scripts/specky-contract-context.mjs +188 -172
  2. package/CHANGELOG.md +30 -0
  3. package/README.md +20 -13
  4. package/apm.lock.yaml +1 -1
  5. package/apm.yml +3 -3
  6. package/config.yml +1 -1
  7. package/dist/cli/commands/apm.d.ts +11 -0
  8. package/dist/cli/commands/apm.d.ts.map +1 -1
  9. package/dist/cli/commands/apm.js +4 -4
  10. package/dist/cli/commands/apm.js.map +1 -1
  11. package/dist/cli/commands/compile.d.ts.map +1 -1
  12. package/dist/cli/commands/compile.js +33 -10
  13. package/dist/cli/commands/compile.js.map +1 -1
  14. package/dist/cli/commands/doctor.d.ts.map +1 -1
  15. package/dist/cli/commands/doctor.js +18 -9
  16. package/dist/cli/commands/doctor.js.map +1 -1
  17. package/dist/cli/commands/hooks.d.ts.map +1 -1
  18. package/dist/cli/commands/hooks.js +3 -1
  19. package/dist/cli/commands/hooks.js.map +1 -1
  20. package/dist/cli/commands/init.d.ts.map +1 -1
  21. package/dist/cli/commands/init.js +13 -12
  22. package/dist/cli/commands/init.js.map +1 -1
  23. package/dist/cli/commands/migrate-contracts.d.ts.map +1 -1
  24. package/dist/cli/commands/migrate-contracts.js +12 -6
  25. package/dist/cli/commands/migrate-contracts.js.map +1 -1
  26. package/dist/cli/commands/status.d.ts.map +1 -1
  27. package/dist/cli/commands/status.js +5 -4
  28. package/dist/cli/commands/status.js.map +1 -1
  29. package/dist/cli/index.js +23 -6
  30. package/dist/cli/index.js.map +1 -1
  31. package/dist/cli/lib/apm/lock.d.ts.map +1 -1
  32. package/dist/cli/lib/apm/lock.js +1 -1
  33. package/dist/cli/lib/apm/lock.js.map +1 -1
  34. package/dist/cli/lib/apm/manifest.d.ts.map +1 -1
  35. package/dist/cli/lib/apm/manifest.js +1 -1
  36. package/dist/cli/lib/apm/manifest.js.map +1 -1
  37. package/dist/cli/lib/apm/policy.d.ts.map +1 -1
  38. package/dist/cli/lib/apm/policy.js +2 -2
  39. package/dist/cli/lib/apm/policy.js.map +1 -1
  40. package/dist/cli/lib/asset-copier.d.ts.map +1 -1
  41. package/dist/cli/lib/asset-copier.js +25 -10
  42. package/dist/cli/lib/asset-copier.js.map +1 -1
  43. package/dist/cli/lib/cursor-plugin-writer.d.ts.map +1 -1
  44. package/dist/cli/lib/cursor-plugin-writer.js +4 -2
  45. package/dist/cli/lib/cursor-plugin-writer.js.map +1 -1
  46. package/dist/cli/lib/gitignore-writer.d.ts.map +1 -1
  47. package/dist/cli/lib/gitignore-writer.js.map +1 -1
  48. package/dist/cli/lib/harness/compilers/agent-skills.js.map +1 -1
  49. package/dist/cli/lib/harness/compilers/claude.d.ts.map +1 -1
  50. package/dist/cli/lib/harness/compilers/claude.js +2 -4
  51. package/dist/cli/lib/harness/compilers/claude.js.map +1 -1
  52. package/dist/cli/lib/harness/compilers/common.d.ts.map +1 -1
  53. package/dist/cli/lib/harness/compilers/common.js +2 -6
  54. package/dist/cli/lib/harness/compilers/common.js.map +1 -1
  55. package/dist/cli/lib/harness/compilers/copilot.js.map +1 -1
  56. package/dist/cli/lib/harness/compilers/cursor.d.ts.map +1 -1
  57. package/dist/cli/lib/harness/compilers/cursor.js +2 -4
  58. package/dist/cli/lib/harness/compilers/cursor.js.map +1 -1
  59. package/dist/cli/lib/harness/compilers/opencode.d.ts.map +1 -1
  60. package/dist/cli/lib/harness/compilers/opencode.js +1 -3
  61. package/dist/cli/lib/harness/compilers/opencode.js.map +1 -1
  62. package/dist/cli/lib/harness/index.d.ts +1 -1
  63. package/dist/cli/lib/harness/index.d.ts.map +1 -1
  64. package/dist/cli/lib/harness/index.js +3 -3
  65. package/dist/cli/lib/harness/index.js.map +1 -1
  66. package/dist/cli/lib/harness/tool-map.d.ts.map +1 -1
  67. package/dist/cli/lib/harness/tool-map.js +1 -2
  68. package/dist/cli/lib/harness/tool-map.js.map +1 -1
  69. package/dist/cli/lib/harness/types.d.ts.map +1 -1
  70. package/dist/cli/lib/ide-detect.d.ts.map +1 -1
  71. package/dist/cli/lib/ide-detect.js +1 -5
  72. package/dist/cli/lib/ide-detect.js.map +1 -1
  73. package/dist/cli/lib/paths.d.ts +10 -0
  74. package/dist/cli/lib/paths.d.ts.map +1 -1
  75. package/dist/cli/lib/paths.js +1 -1
  76. package/dist/cli/lib/paths.js.map +1 -1
  77. package/dist/cli/lib/settings-merger.d.ts.map +1 -1
  78. package/dist/cli/lib/settings-merger.js +2 -3
  79. package/dist/cli/lib/settings-merger.js.map +1 -1
  80. package/dist/cli/lib/update-check.js +5 -2
  81. package/dist/cli/lib/update-check.js.map +1 -1
  82. package/dist/cli/lib/vscode-settings-writer.d.ts.map +1 -1
  83. package/dist/cli/lib/vscode-settings-writer.js +1 -1
  84. package/dist/cli/lib/vscode-settings-writer.js.map +1 -1
  85. package/dist/config.d.ts +13 -0
  86. package/dist/config.d.ts.map +1 -1
  87. package/dist/config.js +75 -22
  88. package/dist/config.js.map +1 -1
  89. package/dist/constants.d.ts.map +1 -1
  90. package/dist/constants.js +6 -1
  91. package/dist/constants.js.map +1 -1
  92. package/dist/contracts/pipeline-profiles.d.ts.map +1 -1
  93. package/dist/contracts/pipeline-profiles.js +24 -12
  94. package/dist/contracts/pipeline-profiles.js.map +1 -1
  95. package/dist/contracts/tool-contracts.d.ts.map +1 -1
  96. package/dist/contracts/tool-contracts.js +431 -58
  97. package/dist/contracts/tool-contracts.js.map +1 -1
  98. package/dist/contracts/use-case.d.ts +1 -1
  99. package/dist/contracts/use-case.d.ts.map +1 -1
  100. package/dist/contracts/use-case.js +253 -72
  101. package/dist/contracts/use-case.js.map +1 -1
  102. package/dist/index.d.ts.map +1 -1
  103. package/dist/index.js +51 -48
  104. package/dist/index.js.map +1 -1
  105. package/dist/schemas/common.d.ts.map +1 -1
  106. package/dist/schemas/common.js +1 -3
  107. package/dist/schemas/common.js.map +1 -1
  108. package/dist/schemas/context.d.ts.map +1 -1
  109. package/dist/schemas/context.js +6 -3
  110. package/dist/schemas/context.js.map +1 -1
  111. package/dist/schemas/environment.d.ts.map +1 -1
  112. package/dist/schemas/environment.js +16 -7
  113. package/dist/schemas/environment.js.map +1 -1
  114. package/dist/schemas/feature-content.d.ts.map +1 -1
  115. package/dist/schemas/feature-content.js +44 -17
  116. package/dist/schemas/feature-content.js.map +1 -1
  117. package/dist/schemas/infrastructure.d.ts.map +1 -1
  118. package/dist/schemas/infrastructure.js +16 -7
  119. package/dist/schemas/infrastructure.js.map +1 -1
  120. package/dist/schemas/input.d.ts.map +1 -1
  121. package/dist/schemas/input.js +17 -11
  122. package/dist/schemas/input.js.map +1 -1
  123. package/dist/schemas/integration.d.ts.map +1 -1
  124. package/dist/schemas/integration.js +27 -21
  125. package/dist/schemas/integration.js.map +1 -1
  126. package/dist/schemas/metrics.d.ts.map +1 -1
  127. package/dist/schemas/metrics.js +6 -3
  128. package/dist/schemas/metrics.js.map +1 -1
  129. package/dist/schemas/pbt.d.ts.map +1 -1
  130. package/dist/schemas/pbt.js +6 -3
  131. package/dist/schemas/pbt.js.map +1 -1
  132. package/dist/schemas/pipeline.d.ts.map +1 -1
  133. package/dist/schemas/pipeline.js +71 -58
  134. package/dist/schemas/pipeline.js.map +1 -1
  135. package/dist/schemas/quality.d.ts.map +1 -1
  136. package/dist/schemas/quality.js +35 -12
  137. package/dist/schemas/quality.js.map +1 -1
  138. package/dist/schemas/routing.d.ts.map +1 -1
  139. package/dist/schemas/routing.js +5 -2
  140. package/dist/schemas/routing.js.map +1 -1
  141. package/dist/schemas/testing.d.ts.map +1 -1
  142. package/dist/schemas/testing.js +11 -5
  143. package/dist/schemas/testing.js.map +1 -1
  144. package/dist/schemas/transcript.d.ts.map +1 -1
  145. package/dist/schemas/transcript.js +22 -18
  146. package/dist/schemas/transcript.js.map +1 -1
  147. package/dist/schemas/utility.d.ts.map +1 -1
  148. package/dist/schemas/utility.js +39 -56
  149. package/dist/schemas/utility.js.map +1 -1
  150. package/dist/schemas/visualization.d.ts +12 -4
  151. package/dist/schemas/visualization.d.ts.map +1 -1
  152. package/dist/schemas/visualization.js +137 -33
  153. package/dist/schemas/visualization.js.map +1 -1
  154. package/dist/services/analysis-engine.d.ts.map +1 -1
  155. package/dist/services/analysis-engine.js +7 -3
  156. package/dist/services/analysis-engine.js.map +1 -1
  157. package/dist/services/audit-logger.d.ts +18 -0
  158. package/dist/services/audit-logger.d.ts.map +1 -1
  159. package/dist/services/audit-logger.js +75 -37
  160. package/dist/services/audit-logger.js.map +1 -1
  161. package/dist/services/codebase-scanner.d.ts.map +1 -1
  162. package/dist/services/codebase-scanner.js +1 -4
  163. package/dist/services/codebase-scanner.js.map +1 -1
  164. package/dist/services/cognitive-debt-engine.d.ts.map +1 -1
  165. package/dist/services/cognitive-debt-engine.js +1 -1
  166. package/dist/services/cognitive-debt-engine.js.map +1 -1
  167. package/dist/services/compliance-engine.d.ts +1 -1
  168. package/dist/services/compliance-engine.d.ts.map +1 -1
  169. package/dist/services/compliance-engine.js +210 -30
  170. package/dist/services/compliance-engine.js.map +1 -1
  171. package/dist/services/content-diagram-generator.d.ts +96 -0
  172. package/dist/services/content-diagram-generator.d.ts.map +1 -0
  173. package/dist/services/content-diagram-generator.js +372 -0
  174. package/dist/services/content-diagram-generator.js.map +1 -0
  175. package/dist/services/context-tiering-engine.d.ts +1 -1
  176. package/dist/services/context-tiering-engine.d.ts.map +1 -1
  177. package/dist/services/context-tiering-engine.js +2 -4
  178. package/dist/services/context-tiering-engine.js.map +1 -1
  179. package/dist/services/cross-analyzer.d.ts +1 -3
  180. package/dist/services/cross-analyzer.d.ts.map +1 -1
  181. package/dist/services/cross-analyzer.js +28 -28
  182. package/dist/services/cross-analyzer.js.map +1 -1
  183. package/dist/services/dependency-graph.d.ts.map +1 -1
  184. package/dist/services/dependency-graph.js +148 -28
  185. package/dist/services/dependency-graph.js.map +1 -1
  186. package/dist/services/design-completeness.d.ts +19 -0
  187. package/dist/services/design-completeness.d.ts.map +1 -0
  188. package/dist/services/design-completeness.js +58 -0
  189. package/dist/services/design-completeness.js.map +1 -0
  190. package/dist/services/diagram-generator.d.ts.map +1 -1
  191. package/dist/services/diagram-generator.js.map +1 -1
  192. package/dist/services/doc-generator.d.ts.map +1 -1
  193. package/dist/services/doc-generator.js +43 -12
  194. package/dist/services/doc-generator.js.map +1 -1
  195. package/dist/services/document-converter.d.ts +1 -1
  196. package/dist/services/document-converter.d.ts.map +1 -1
  197. package/dist/services/document-converter.js +35 -21
  198. package/dist/services/document-converter.js.map +1 -1
  199. package/dist/services/ears-validator.d.ts +1 -1
  200. package/dist/services/ears-validator.d.ts.map +1 -1
  201. package/dist/services/ears-validator.js +36 -11
  202. package/dist/services/ears-validator.js.map +1 -1
  203. package/dist/services/execution-context.d.ts +16 -3
  204. package/dist/services/execution-context.d.ts.map +1 -1
  205. package/dist/services/execution-context.js +42 -2
  206. package/dist/services/execution-context.js.map +1 -1
  207. package/dist/services/feature-package-generator.d.ts.map +1 -1
  208. package/dist/services/feature-package-generator.js +43 -15
  209. package/dist/services/feature-package-generator.js.map +1 -1
  210. package/dist/services/file-manager.d.ts.map +1 -1
  211. package/dist/services/file-manager.js +20 -6
  212. package/dist/services/file-manager.js.map +1 -1
  213. package/dist/services/git-manager.d.ts +1 -1
  214. package/dist/services/git-manager.d.ts.map +1 -1
  215. package/dist/services/git-manager.js +18 -7
  216. package/dist/services/git-manager.js.map +1 -1
  217. package/dist/services/iac-generator.d.ts +48 -1
  218. package/dist/services/iac-generator.d.ts.map +1 -1
  219. package/dist/services/iac-generator.js +655 -77
  220. package/dist/services/iac-generator.js.map +1 -1
  221. package/dist/services/intent-drift-engine.d.ts.map +1 -1
  222. package/dist/services/intent-drift-engine.js +19 -2
  223. package/dist/services/intent-drift-engine.js.map +1 -1
  224. package/dist/services/methodology.d.ts.map +1 -1
  225. package/dist/services/methodology.js +85 -21
  226. package/dist/services/methodology.js.map +1 -1
  227. package/dist/services/metrics-generator.d.ts +0 -1
  228. package/dist/services/metrics-generator.d.ts.map +1 -1
  229. package/dist/services/metrics-generator.js +28 -19
  230. package/dist/services/metrics-generator.js.map +1 -1
  231. package/dist/services/model-routing-engine.d.ts +4 -4
  232. package/dist/services/model-routing-engine.d.ts.map +1 -1
  233. package/dist/services/model-routing-engine.js +73 -72
  234. package/dist/services/model-routing-engine.js.map +1 -1
  235. package/dist/services/pbt-generator.d.ts.map +1 -1
  236. package/dist/services/pbt-generator.js +3 -2
  237. package/dist/services/pbt-generator.js.map +1 -1
  238. package/dist/services/rate-limiter.d.ts +8 -0
  239. package/dist/services/rate-limiter.d.ts.map +1 -1
  240. package/dist/services/rate-limiter.js +18 -0
  241. package/dist/services/rate-limiter.js.map +1 -1
  242. package/dist/services/rbac-engine.d.ts.map +1 -1
  243. package/dist/services/rbac-engine.js +1 -3
  244. package/dist/services/rbac-engine.js.map +1 -1
  245. package/dist/services/state-machine.d.ts +17 -2
  246. package/dist/services/state-machine.d.ts.map +1 -1
  247. package/dist/services/state-machine.js +110 -75
  248. package/dist/services/state-machine.js.map +1 -1
  249. package/dist/services/template-engine.d.ts +2 -2
  250. package/dist/services/template-engine.d.ts.map +1 -1
  251. package/dist/services/template-engine.js +6 -5
  252. package/dist/services/template-engine.js.map +1 -1
  253. package/dist/services/test-generator.d.ts +0 -2
  254. package/dist/services/test-generator.d.ts.map +1 -1
  255. package/dist/services/test-generator.js +61 -42
  256. package/dist/services/test-generator.js.map +1 -1
  257. package/dist/services/test-result-parser.d.ts.map +1 -1
  258. package/dist/services/test-result-parser.js +5 -4
  259. package/dist/services/test-result-parser.js.map +1 -1
  260. package/dist/services/test-traceability-mapper.d.ts.map +1 -1
  261. package/dist/services/test-traceability-mapper.js +16 -4
  262. package/dist/services/test-traceability-mapper.js.map +1 -1
  263. package/dist/services/transcript-parser.d.ts +1 -1
  264. package/dist/services/transcript-parser.d.ts.map +1 -1
  265. package/dist/services/transcript-parser.js +61 -27
  266. package/dist/services/transcript-parser.js.map +1 -1
  267. package/dist/services/work-item-exporter.d.ts +1 -1
  268. package/dist/services/work-item-exporter.d.ts.map +1 -1
  269. package/dist/services/work-item-exporter.js +14 -2
  270. package/dist/services/work-item-exporter.js.map +1 -1
  271. package/dist/tools/analysis.d.ts +1 -1
  272. package/dist/tools/analysis.d.ts.map +1 -1
  273. package/dist/tools/analysis.js +22 -17
  274. package/dist/tools/analysis.js.map +1 -1
  275. package/dist/tools/audit.d.ts.map +1 -1
  276. package/dist/tools/audit.js +4 -2
  277. package/dist/tools/audit.js.map +1 -1
  278. package/dist/tools/checkpoint.d.ts.map +1 -1
  279. package/dist/tools/checkpoint.js +46 -32
  280. package/dist/tools/checkpoint.js.map +1 -1
  281. package/dist/tools/context.d.ts +1 -1
  282. package/dist/tools/context.d.ts.map +1 -1
  283. package/dist/tools/context.js +4 -9
  284. package/dist/tools/context.js.map +1 -1
  285. package/dist/tools/documentation.d.ts.map +1 -1
  286. package/dist/tools/documentation.js +60 -23
  287. package/dist/tools/documentation.js.map +1 -1
  288. package/dist/tools/environment.d.ts +2 -2
  289. package/dist/tools/environment.d.ts.map +1 -1
  290. package/dist/tools/environment.js +27 -26
  291. package/dist/tools/environment.js.map +1 -1
  292. package/dist/tools/infrastructure.d.ts +1 -1
  293. package/dist/tools/infrastructure.d.ts.map +1 -1
  294. package/dist/tools/infrastructure.js +24 -25
  295. package/dist/tools/infrastructure.js.map +1 -1
  296. package/dist/tools/input.d.ts +1 -1
  297. package/dist/tools/input.d.ts.map +1 -1
  298. package/dist/tools/input.js +31 -29
  299. package/dist/tools/input.js.map +1 -1
  300. package/dist/tools/integration.d.ts +1 -1
  301. package/dist/tools/integration.d.ts.map +1 -1
  302. package/dist/tools/integration.js +33 -44
  303. package/dist/tools/integration.js.map +1 -1
  304. package/dist/tools/metrics.d.ts +4 -4
  305. package/dist/tools/metrics.d.ts.map +1 -1
  306. package/dist/tools/metrics.js +5 -15
  307. package/dist/tools/metrics.js.map +1 -1
  308. package/dist/tools/pbt.d.ts +1 -1
  309. package/dist/tools/pbt.d.ts.map +1 -1
  310. package/dist/tools/pbt.js +6 -16
  311. package/dist/tools/pbt.js.map +1 -1
  312. package/dist/tools/pipeline-writers.d.ts +193 -0
  313. package/dist/tools/pipeline-writers.d.ts.map +1 -0
  314. package/dist/tools/pipeline-writers.js +203 -0
  315. package/dist/tools/pipeline-writers.js.map +1 -0
  316. package/dist/tools/pipeline.d.ts +1 -1
  317. package/dist/tools/pipeline.d.ts.map +1 -1
  318. package/dist/tools/pipeline.js +151 -203
  319. package/dist/tools/pipeline.js.map +1 -1
  320. package/dist/tools/quality.d.ts +3 -3
  321. package/dist/tools/quality.d.ts.map +1 -1
  322. package/dist/tools/quality.js +354 -95
  323. package/dist/tools/quality.js.map +1 -1
  324. package/dist/tools/rbac.d.ts.map +1 -1
  325. package/dist/tools/rbac.js +7 -4
  326. package/dist/tools/rbac.js.map +1 -1
  327. package/dist/tools/response-builder.d.ts +1 -1
  328. package/dist/tools/response-builder.d.ts.map +1 -1
  329. package/dist/tools/response-builder.js +5 -8
  330. package/dist/tools/response-builder.js.map +1 -1
  331. package/dist/tools/routing.d.ts.map +1 -1
  332. package/dist/tools/routing.js +3 -9
  333. package/dist/tools/routing.js.map +1 -1
  334. package/dist/tools/testing.d.ts.map +1 -1
  335. package/dist/tools/testing.js +36 -32
  336. package/dist/tools/testing.js.map +1 -1
  337. package/dist/tools/tool-enforcement.d.ts +2 -2
  338. package/dist/tools/tool-enforcement.d.ts.map +1 -1
  339. package/dist/tools/tool-enforcement.js +2 -1
  340. package/dist/tools/tool-enforcement.js.map +1 -1
  341. package/dist/tools/tool-result.d.ts +1 -0
  342. package/dist/tools/tool-result.d.ts.map +1 -1
  343. package/dist/tools/tool-result.js.map +1 -1
  344. package/dist/tools/transcript.d.ts +1 -1
  345. package/dist/tools/transcript.d.ts.map +1 -1
  346. package/dist/tools/transcript.js +161 -240
  347. package/dist/tools/transcript.js.map +1 -1
  348. package/dist/tools/turnkey.d.ts.map +1 -1
  349. package/dist/tools/turnkey.js +41 -17
  350. package/dist/tools/turnkey.js.map +1 -1
  351. package/dist/tools/utility.d.ts +2 -2
  352. package/dist/tools/utility.d.ts.map +1 -1
  353. package/dist/tools/utility.js +49 -38
  354. package/dist/tools/utility.js.map +1 -1
  355. package/dist/tools/visualization.d.ts.map +1 -1
  356. package/dist/tools/visualization.js +156 -58
  357. package/dist/tools/visualization.js.map +1 -1
  358. package/dist/types.d.ts +18 -2
  359. package/dist/types.d.ts.map +1 -1
  360. package/dist/utils/artifact-metadata.d.ts.map +1 -1
  361. package/dist/utils/artifact-metadata.js.map +1 -1
  362. package/dist/utils/context-helper.d.ts +1 -1
  363. package/dist/utils/context-helper.d.ts.map +1 -1
  364. package/dist/utils/context-helper.js.map +1 -1
  365. package/dist/utils/http-auth.d.ts.map +1 -1
  366. package/dist/utils/http-auth.js +1 -1
  367. package/dist/utils/http-auth.js.map +1 -1
  368. package/dist/utils/id-contracts.d.ts +21 -0
  369. package/dist/utils/id-contracts.d.ts.map +1 -1
  370. package/dist/utils/id-contracts.js +60 -1
  371. package/dist/utils/id-contracts.js.map +1 -1
  372. package/dist/utils/requirement-partition.d.ts.map +1 -1
  373. package/dist/utils/requirement-partition.js.map +1 -1
  374. package/dist/utils/routing-helper.d.ts +1 -1
  375. package/dist/utils/routing-helper.d.ts.map +1 -1
  376. package/dist/utils/routing-helper.js.map +1 -1
  377. package/dist/utils/safe-read.d.ts +10 -0
  378. package/dist/utils/safe-read.d.ts.map +1 -0
  379. package/dist/utils/safe-read.js +10 -0
  380. package/dist/utils/safe-read.js.map +1 -0
  381. package/dist/utils/task-parser.d.ts.map +1 -1
  382. package/dist/utils/task-parser.js +1 -1
  383. package/dist/utils/task-parser.js.map +1 -1
  384. package/dist/utils/test-quality.d.ts +10 -0
  385. package/dist/utils/test-quality.d.ts.map +1 -0
  386. package/dist/utils/test-quality.js +10 -0
  387. package/dist/utils/test-quality.js.map +1 -0
  388. package/dist/utils/token-table.d.ts +20 -0
  389. package/dist/utils/token-table.d.ts.map +1 -1
  390. package/dist/utils/token-table.js +2 -2
  391. package/dist/utils/token-table.js.map +1 -1
  392. package/package.json +6 -2
@@ -1,219 +1,235 @@
1
1
  #!/usr/bin/env node
2
2
  import { createHash, createHmac, timingSafeEqual } from "node:crypto";
3
- import { existsSync, readFileSync, readdirSync } from "node:fs";
3
+ import { existsSync, readdirSync, readFileSync } from "node:fs";
4
4
  import { relative, resolve, sep } from "node:path";
5
5
 
6
6
  function fail(message) {
7
- console.error(`[specky-contract-context] ${message}`);
8
- process.exit(2);
7
+ console.error(`[specky-contract-context] ${message}`);
8
+ process.exit(2);
9
9
  }
10
10
 
11
11
  function readHookInput() {
12
- const fromEnvironment = process.env.SDD_HOOK_INPUT;
13
- if (fromEnvironment?.trim()) return fromEnvironment;
14
- if (process.stdin.isTTY) return "";
15
- try {
16
- return readFileSync(0, "utf8");
17
- } catch {
18
- return "";
19
- }
12
+ const fromEnvironment = process.env.SDD_HOOK_INPUT;
13
+ if (fromEnvironment?.trim()) return fromEnvironment;
14
+ if (process.stdin.isTTY) return "";
15
+ try {
16
+ return readFileSync(0, "utf8");
17
+ } catch {
18
+ return "";
19
+ }
20
20
  }
21
21
 
22
22
  function parseInput(raw) {
23
- if (!raw.trim()) return {};
24
- try {
25
- return JSON.parse(raw);
26
- } catch {
27
- return {};
28
- }
23
+ if (!raw.trim()) return {};
24
+ try {
25
+ return JSON.parse(raw);
26
+ } catch {
27
+ return {};
28
+ }
29
29
  }
30
30
 
31
31
  function objects(value) {
32
- if (typeof value !== "object" || value === null || Array.isArray(value)) return [];
33
- const record = value;
34
- return [
35
- record,
36
- record.tool_input,
37
- record.toolInput,
38
- record.arguments,
39
- record.input,
40
- record.params,
41
- record.params?.arguments,
42
- record.request?.params?.arguments,
43
- ].filter((candidate) => typeof candidate === "object" && candidate !== null && !Array.isArray(candidate));
32
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return [];
33
+ const record = value;
34
+ return [
35
+ record,
36
+ record.tool_input,
37
+ record.toolInput,
38
+ record.arguments,
39
+ record.input,
40
+ record.params,
41
+ record.params?.arguments,
42
+ record.request?.params?.arguments,
43
+ ].filter(
44
+ (candidate) => typeof candidate === "object" && candidate !== null && !Array.isArray(candidate),
45
+ );
44
46
  }
45
47
 
46
48
  function findString(input, keys) {
47
- for (const candidate of objects(input)) {
48
- for (const key of keys) {
49
- const value = candidate[key];
50
- if (typeof value === "string" && value.trim()) return value.trim();
51
- }
49
+ for (const candidate of objects(input)) {
50
+ for (const key of keys) {
51
+ const value = candidate[key];
52
+ if (typeof value === "string" && value.trim()) return value.trim();
52
53
  }
53
- return undefined;
54
+ }
55
+ return undefined;
54
56
  }
55
57
 
56
58
  function safeRelativePath(value, label) {
57
- if (!value || value.startsWith("/") || value.startsWith("\\") || /^[A-Za-z]:/.test(value)) {
58
- fail(`${label} must be a workspace-relative path.`);
59
- }
60
- const segments = value.split(/[\\/]/);
61
- if (segments.includes("..") || value.includes("\0")) fail(`${label} contains unsafe traversal.`);
62
- return segments.filter((segment) => segment && segment !== ".").join("/");
59
+ if (!value || value.startsWith("/") || value.startsWith("\\") || /^[A-Za-z]:/.test(value)) {
60
+ fail(`${label} must be a workspace-relative path.`);
61
+ }
62
+ const segments = value.split(/[\\/]/);
63
+ if (segments.includes("..") || value.includes("\0")) fail(`${label} contains unsafe traversal.`);
64
+ return segments.filter((segment) => segment && segment !== ".").join("/");
63
65
  }
64
66
 
65
67
  function canonicalize(value) {
66
- if (Array.isArray(value)) return value.map(canonicalize);
67
- if (typeof value !== "object" || value === null) return value;
68
- return Object.keys(value)
69
- .sort((left, right) => left.localeCompare(right))
70
- .reduce((result, key) => {
71
- result[key] = canonicalize(value[key]);
72
- return result;
73
- }, {});
68
+ if (Array.isArray(value)) return value.map(canonicalize);
69
+ if (typeof value !== "object" || value === null) return value;
70
+ return Object.keys(value)
71
+ .sort((left, right) => left.localeCompare(right))
72
+ .reduce((result, key) => {
73
+ result[key] = canonicalize(value[key]);
74
+ return result;
75
+ }, {});
74
76
  }
75
77
 
76
78
  function fingerprintContract(contract) {
77
- const { fingerprint: _fingerprint, ...snapshot } = contract;
78
- return createHash("sha256").update(JSON.stringify(canonicalize(snapshot))).digest("hex");
79
+ const { fingerprint: _fingerprint, ...snapshot } = contract;
80
+ return createHash("sha256")
81
+ .update(JSON.stringify(canonicalize(snapshot)))
82
+ .digest("hex");
79
83
  }
80
84
 
81
85
  function safeEqualHex(left, right) {
82
- if (!/^[a-f0-9]{64}$/.test(left) || !/^[a-f0-9]{64}$/.test(right)) return false;
83
- return timingSafeEqual(Buffer.from(left, "hex"), Buffer.from(right, "hex"));
86
+ if (!/^[a-f0-9]{64}$/.test(left) || !/^[a-f0-9]{64}$/.test(right)) return false;
87
+ return timingSafeEqual(Buffer.from(left, "hex"), Buffer.from(right, "hex"));
84
88
  }
85
89
 
86
90
  function shellQuote(value) {
87
- return `'${String(value).replaceAll("'", `'"'"'`)}'`;
91
+ return `'${String(value).replaceAll("'", `'"'"'`)}'`;
88
92
  }
89
93
 
90
94
  function resolveContext() {
91
- const workspace = resolve(process.env.SPECKY_HOOK_WORKSPACE ?? process.cwd());
92
- const input = parseInput(readHookInput());
93
- const requestedSpecDir = process.env.SDD_SPEC_DIR ?? findString(input, ["spec_dir", "specDir"]);
94
- const requestedFeatureNumber = process.env.SDD_FEATURE_NUMBER
95
- ?? findString(input, ["feature_number", "featureNumber"]);
96
-
97
- if (!requestedSpecDir || !requestedFeatureNumber) {
98
- return { active: false, reason: "missing explicit SDD_SPEC_DIR/SDD_FEATURE_NUMBER context" };
99
- }
100
- const specDir = safeRelativePath(requestedSpecDir, "spec_dir");
101
- if (!/^\d{3}$/.test(requestedFeatureNumber)) fail("feature_number must be exactly three digits.");
102
-
103
- const specRoot = resolve(workspace, specDir);
104
- if (!existsSync(specRoot)) fail(`spec root does not exist: ${specDir}`);
105
- const matches = readdirSync(specRoot, { withFileTypes: true })
106
- .filter((entry) => entry.isDirectory() && entry.name.startsWith(`${requestedFeatureNumber}-`));
107
- if (matches.length !== 1) {
108
- fail(`feature ${requestedFeatureNumber} must resolve to exactly one directory in ${specDir}; found ${matches.length}.`);
109
- }
110
-
111
- const featureName = matches[0].name.slice(4);
112
- const featureDirectory = `${specDir}/${matches[0].name}`;
113
- const statePath = resolve(workspace, featureDirectory, ".sdd-state.json");
114
- const signaturePath = `${statePath}.sig`;
115
- if (!existsSync(statePath) || !existsSync(signaturePath)) {
116
- fail(`feature ${requestedFeatureNumber} requires signed v5 state at ${featureDirectory}/.sdd-state.json.`);
117
- }
118
-
119
- const raw = readFileSync(statePath, "utf8");
120
- let state;
121
- try {
122
- state = JSON.parse(raw);
123
- } catch {
124
- fail(`state is not valid JSON: ${relative(workspace, statePath)}`);
125
- }
126
- if (state.version !== "5.0.0") fail(`state version ${String(state.version)} requires migration.`);
127
-
128
- const key = process.env.SDD_STATE_KEY
129
- ?? createHash("sha256").update(`specky-state-v1:${workspace}`).digest("hex");
130
- const expectedSignature = createHmac("sha256", key).update(raw).digest("hex");
131
- const storedSignature = readFileSync(signaturePath, "utf8").trim();
132
- if (!safeEqualHex(storedSignature, expectedSignature)) fail("feature state signature verification failed.");
133
-
134
- if (
135
- state.feature?.number !== requestedFeatureNumber ||
136
- state.feature?.name !== featureName ||
137
- state.feature?.directory !== featureDirectory
138
- ) {
139
- fail(`feature state identity does not match ${featureDirectory}.`);
140
- }
141
- if (!state.contract || fingerprintContract(state.contract) !== state.contract.fingerprint) {
142
- fail("feature contract fingerprint verification failed.");
143
- }
144
- if (!Array.isArray(state.contract.phases) || !state.contract.phases.includes(state.current_phase)) {
145
- fail(`current phase ${String(state.current_phase)} is not enabled by the feature contract.`);
146
- }
147
-
148
- const capabilities = Array.isArray(state.contract.capabilities) ? state.contract.capabilities : [];
149
- const capabilityConfig = state.contract.capability_config ?? {};
150
- const configuredCapabilities = Object.keys(capabilityConfig).sort();
151
- const declaredCapabilities = [...new Set(capabilities)].sort();
152
- if (JSON.stringify(configuredCapabilities) !== JSON.stringify(declaredCapabilities)) {
153
- fail("capabilities and capability_config keys do not match.");
154
- }
155
-
156
- return {
157
- active: true,
158
- workspace,
159
- specDir,
160
- featureNumber: requestedFeatureNumber,
161
- featureName,
162
- featureDirectory,
163
- statePath: relative(workspace, statePath).split(sep).join("/"),
164
- phase: state.current_phase,
165
- contract: state.contract,
166
- gateDecision: state.gate_decision?.decision ?? "",
167
- };
95
+ const workspace = resolve(process.env.SPECKY_HOOK_WORKSPACE ?? process.cwd());
96
+ const input = parseInput(readHookInput());
97
+ const requestedSpecDir = process.env.SDD_SPEC_DIR ?? findString(input, ["spec_dir", "specDir"]);
98
+ const requestedFeatureNumber =
99
+ process.env.SDD_FEATURE_NUMBER ?? findString(input, ["feature_number", "featureNumber"]);
100
+
101
+ if (!requestedSpecDir || !requestedFeatureNumber) {
102
+ return { active: false, reason: "missing explicit SDD_SPEC_DIR/SDD_FEATURE_NUMBER context" };
103
+ }
104
+ const specDir = safeRelativePath(requestedSpecDir, "spec_dir");
105
+ if (!/^\d{3}$/.test(requestedFeatureNumber)) fail("feature_number must be exactly three digits.");
106
+
107
+ const specRoot = resolve(workspace, specDir);
108
+ if (!existsSync(specRoot)) fail(`spec root does not exist: ${specDir}`);
109
+ const matches = readdirSync(specRoot, { withFileTypes: true }).filter(
110
+ (entry) => entry.isDirectory() && entry.name.startsWith(`${requestedFeatureNumber}-`),
111
+ );
112
+ if (matches.length !== 1) {
113
+ fail(
114
+ `feature ${requestedFeatureNumber} must resolve to exactly one directory in ${specDir}; found ${matches.length}.`,
115
+ );
116
+ }
117
+
118
+ const featureName = matches[0].name.slice(4);
119
+ const featureDirectory = `${specDir}/${matches[0].name}`;
120
+ const statePath = resolve(workspace, featureDirectory, ".sdd-state.json");
121
+ const signaturePath = `${statePath}.sig`;
122
+ if (!existsSync(statePath) || !existsSync(signaturePath)) {
123
+ fail(
124
+ `feature ${requestedFeatureNumber} requires signed v5 state at ${featureDirectory}/.sdd-state.json.`,
125
+ );
126
+ }
127
+
128
+ const raw = readFileSync(statePath, "utf8");
129
+ let state;
130
+ try {
131
+ state = JSON.parse(raw);
132
+ } catch {
133
+ fail(`state is not valid JSON: ${relative(workspace, statePath)}`);
134
+ }
135
+ if (state.version !== "5.0.0") fail(`state version ${String(state.version)} requires migration.`);
136
+
137
+ const key =
138
+ process.env.SDD_STATE_KEY ??
139
+ createHash("sha256").update(`specky-state-v1:${workspace}`).digest("hex");
140
+ const expectedSignature = createHmac("sha256", key).update(raw).digest("hex");
141
+ const storedSignature = readFileSync(signaturePath, "utf8").trim();
142
+ if (!safeEqualHex(storedSignature, expectedSignature))
143
+ fail("feature state signature verification failed.");
144
+
145
+ if (
146
+ state.feature?.number !== requestedFeatureNumber ||
147
+ state.feature?.name !== featureName ||
148
+ state.feature?.directory !== featureDirectory
149
+ ) {
150
+ fail(`feature state identity does not match ${featureDirectory}.`);
151
+ }
152
+ if (!state.contract || fingerprintContract(state.contract) !== state.contract.fingerprint) {
153
+ fail("feature contract fingerprint verification failed.");
154
+ }
155
+ if (
156
+ !Array.isArray(state.contract.phases) ||
157
+ !state.contract.phases.includes(state.current_phase)
158
+ ) {
159
+ fail(`current phase ${String(state.current_phase)} is not enabled by the feature contract.`);
160
+ }
161
+
162
+ const capabilities = Array.isArray(state.contract.capabilities)
163
+ ? state.contract.capabilities
164
+ : [];
165
+ const capabilityConfig = state.contract.capability_config ?? {};
166
+ const configuredCapabilities = Object.keys(capabilityConfig).sort();
167
+ const declaredCapabilities = [...new Set(capabilities)].sort();
168
+ if (JSON.stringify(configuredCapabilities) !== JSON.stringify(declaredCapabilities)) {
169
+ fail("capabilities and capability_config keys do not match.");
170
+ }
171
+
172
+ return {
173
+ active: true,
174
+ workspace,
175
+ specDir,
176
+ featureNumber: requestedFeatureNumber,
177
+ featureName,
178
+ featureDirectory,
179
+ statePath: relative(workspace, statePath).split(sep).join("/"),
180
+ phase: state.current_phase,
181
+ contract: state.contract,
182
+ gateDecision: state.gate_decision?.decision ?? "",
183
+ };
168
184
  }
169
185
 
170
186
  function printShell(context) {
171
- const contract = context.contract ?? {};
172
- const capabilities = Array.isArray(contract.capabilities) ? contract.capabilities : [];
173
- const release = contract.capability_config?.release;
174
- const tdd = contract.capability_config?.tdd;
175
- const compliance = contract.capability_config?.compliance;
176
- const development = contract.capability_config?.["dev-environment"];
177
- const iac = contract.capability_config?.iac;
178
- const values = {
179
- SPECKY_CONTEXT_ACTIVE: context.active ? "1" : "0",
180
- SPECKY_CONTEXT_REASON: context.reason ?? "",
181
- SPECKY_SPEC_DIR: context.specDir ?? "",
182
- SPECKY_FEATURE_NUMBER: context.featureNumber ?? "",
183
- SPECKY_FEATURE_NAME: context.featureName ?? "",
184
- SPECKY_FEATURE_DIR: context.featureDirectory ?? "",
185
- SPECKY_STATE_FILE: context.statePath ?? "",
186
- SPECKY_PHASE: context.phase ?? "",
187
- SPECKY_CONTRACT_ID: contract.id ?? "",
188
- SPECKY_CONTRACT_FINGERPRINT: contract.fingerprint ?? "",
189
- SPECKY_LIFECYCLE: contract.lifecycle ?? "",
190
- SPECKY_WORKLOAD: contract.workload ?? "",
191
- SPECKY_EXECUTION_MODE: contract.execution_mode ?? "",
192
- SPECKY_CAPABILITIES: capabilities.join(","),
193
- SPECKY_GATE_DECISION: context.gateDecision ?? "",
194
- SPECKY_RELEASE_ENABLED: release ? "1" : "0",
195
- SPECKY_BRANCH_PREFIX: release?.branch_prefix ?? "",
196
- SPECKY_BASE_BRANCH: release?.base_branch ?? "",
197
- SPECKY_CHECKPOINTS_REQUIRED: release?.checkpoints ? "1" : "0",
198
- SPECKY_TDD_ENABLED: tdd ? "1" : "0",
199
- SPECKY_TDD_THRESHOLD: tdd ? String(tdd.coverage_threshold) : "",
200
- SPECKY_COMPLIANCE_ENABLED: compliance ? "1" : "0",
201
- SPECKY_COMPLIANCE_FRAMEWORKS: compliance?.frameworks?.join(",") ?? "",
202
- SPECKY_DEV_ENV_ENABLED: development ? "1" : "0",
203
- SPECKY_DEV_LANGUAGE: development?.language ?? "",
204
- SPECKY_IAC_ENABLED: iac ? "1" : "0",
205
- SPECKY_IAC_PROVIDER: iac?.provider ?? "",
206
- SPECKY_IAC_CLOUD: iac?.cloud ?? "",
207
- };
208
- for (const [key, value] of Object.entries(values)) console.log(`${key}=${shellQuote(value)}`);
187
+ const contract = context.contract ?? {};
188
+ const capabilities = Array.isArray(contract.capabilities) ? contract.capabilities : [];
189
+ const release = contract.capability_config?.release;
190
+ const tdd = contract.capability_config?.tdd;
191
+ const compliance = contract.capability_config?.compliance;
192
+ const development = contract.capability_config?.["dev-environment"];
193
+ const iac = contract.capability_config?.iac;
194
+ const values = {
195
+ SPECKY_CONTEXT_ACTIVE: context.active ? "1" : "0",
196
+ SPECKY_CONTEXT_REASON: context.reason ?? "",
197
+ SPECKY_SPEC_DIR: context.specDir ?? "",
198
+ SPECKY_FEATURE_NUMBER: context.featureNumber ?? "",
199
+ SPECKY_FEATURE_NAME: context.featureName ?? "",
200
+ SPECKY_FEATURE_DIR: context.featureDirectory ?? "",
201
+ SPECKY_STATE_FILE: context.statePath ?? "",
202
+ SPECKY_PHASE: context.phase ?? "",
203
+ SPECKY_CONTRACT_ID: contract.id ?? "",
204
+ SPECKY_CONTRACT_FINGERPRINT: contract.fingerprint ?? "",
205
+ SPECKY_LIFECYCLE: contract.lifecycle ?? "",
206
+ SPECKY_WORKLOAD: contract.workload ?? "",
207
+ SPECKY_EXECUTION_MODE: contract.execution_mode ?? "",
208
+ SPECKY_CAPABILITIES: capabilities.join(","),
209
+ SPECKY_GATE_DECISION: context.gateDecision ?? "",
210
+ SPECKY_RELEASE_ENABLED: release ? "1" : "0",
211
+ SPECKY_BRANCH_PREFIX: release?.branch_prefix ?? "",
212
+ SPECKY_BASE_BRANCH: release?.base_branch ?? "",
213
+ SPECKY_CHECKPOINTS_REQUIRED: release?.checkpoints ? "1" : "0",
214
+ SPECKY_TDD_ENABLED: tdd ? "1" : "0",
215
+ SPECKY_TDD_THRESHOLD: tdd ? String(tdd.coverage_threshold) : "",
216
+ SPECKY_COMPLIANCE_ENABLED: compliance ? "1" : "0",
217
+ SPECKY_COMPLIANCE_FRAMEWORKS: compliance?.frameworks?.join(",") ?? "",
218
+ SPECKY_DEV_ENV_ENABLED: development ? "1" : "0",
219
+ SPECKY_DEV_LANGUAGE: development?.language ?? "",
220
+ SPECKY_IAC_ENABLED: iac ? "1" : "0",
221
+ SPECKY_IAC_PROVIDER: iac?.provider ?? "",
222
+ SPECKY_IAC_CLOUD: iac?.cloud ?? "",
223
+ };
224
+ for (const [key, value] of Object.entries(values)) console.log(`${key}=${shellQuote(value)}`);
209
225
  }
210
226
 
211
227
  const command = process.argv[2] ?? "shell";
212
228
  const context = resolveContext();
213
229
  if (command === "json") {
214
- console.log(JSON.stringify(context));
230
+ console.log(JSON.stringify(context));
215
231
  } else if (command === "shell") {
216
- printShell(context);
232
+ printShell(context);
217
233
  } else {
218
- fail(`unknown command ${command}`);
234
+ fail(`unknown command ${command}`);
219
235
  }
package/CHANGELOG.md CHANGED
@@ -7,6 +7,36 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [3.12.0] - 2026-07-20
11
+
12
+ ### Added
13
+
14
+ - Backward-compatible `mode: "explicit" | "auto"` inputs for `sdd_generate_diagram` and `sdd_generate_all_diagrams`; explicit remains the default.
15
+ - Evidence-grounded automatic Mermaid generation for C4 context, sequence, ER, and deployment diagrams from `SPECIFICATION.md` and `DESIGN.md`.
16
+ - Source evidence tracking for derived actors, requirements, exchanges, use cases, components, entities, and deployment nodes.
17
+ - Biome lint and format integration with `biome.json` and npm scripts (`lint`, `lint:fix`, `format`).
18
+ - Unit tests for previously uncovered modules: `slug`, `routing-helper`, `audit-tools`, `transcript-tools`, `cli-commands`, `vscode-settings-writer`, and `agent-skills`.
19
+ - `.specs/001-biome-lint-integration/` spec package for dogfooding the SDD pipeline on Specky itself.
20
+
21
+ ### Changed
22
+
23
+ - Terraform resource discovery now uses canonical `module:service` keys derived from the relevant `DESIGN.md` sections, with clause-scoped handling for exclusions such as `without`, `avoid`, and `not use`.
24
+ - Diagram-set auto mode synthesizes and validates the complete contracted set in memory before atomically writing `DIAGRAMS.md`.
25
+ - Coverage thresholds ratcheted to 89% statements, 77% branches, 95% functions, and 90% lines.
26
+ - Test suite expanded from 663 to 1019 tests across 99 files.
27
+
28
+ ### Fixed
29
+
30
+ - Unsupported Terraform resource types now fail preflight with an actionable error instead of emitting placeholder comments.
31
+ - `specky compile` now validates and reads instruction primitives through a single file descriptor, eliminating the CodeQL-reported filesystem race.
32
+ - Feature directory identifiers use stable forward-slash separators in user-facing MCP errors on Windows.
33
+ - Integration test and hook timeouts allow subprocess-heavy tests to complete under full-suite CPU contention.
34
+ - Biome warnings for unused imports, unused variables, optional chains, and static-only classes.
35
+ - `useOptionalChain` violations in `settings-merger`, `audit-logger`, `http-auth`, and `token-table`.
36
+ - `noUnusedVariables` violations in `pipeline.ts`, `cross-analyzer.ts`, and `vscode-settings-writer.ts`.
37
+ - `noUnusedFunctionParameters` violations in `metrics.ts` and `turnkey.ts`.
38
+ - `noStaticOnlyClass` suppressions documented for `DependencyGraph` and `MethodologyGuide`.
39
+
10
40
  ## [3.11.1] - 2026-07-16
11
41
 
12
42
  ### Added
package/README.md CHANGED
@@ -60,7 +60,7 @@
60
60
  | **Enterprise** | [Compliance Frameworks](#compliance-frameworks) | HIPAA, SOC2, GDPR, PCI-DSS, ISO 27001 |
61
61
  | | [Enterprise Ready](#enterprise-ready) | Security, audit trail, quality gates |
62
62
  | **Platform** | [The SDD Platform](#the-spec-driven-development-platform) | Built on Spec-Kit, everything included |
63
- | | [Roadmap](#roadmap) | v3.11.1 current, future capabilities planned |
63
+ | | [Roadmap](#roadmap) | v3.12.0 current, future capabilities planned |
64
64
 
65
65
  ## What is Specky?
66
66
 
@@ -106,7 +106,7 @@ specky install --target=opencode # OpenCode
106
106
  specky install --target=agent-skills # Skills-only shared .agents/skills bundle
107
107
  ```
108
108
 
109
- > **Important:** Prefer `--target=...`. The legacy `--ide` flag still works for `copilot`, `claude`, `both`, and `auto`, but it is deprecated in favor of APM-style targets. If Copilot is installed in a workspace, Specky strips Claude hooks from `.claude/settings.json` to prevent Copilot cross-read blocks. See [docs/INSTALL.md](docs/INSTALL.md) for details.
109
+ > **Important:** Prefer `--target=...`. The legacy `--ide` flag still works for `copilot`, `claude`, `both`, and `auto`, but it is deprecated in favor of APM-style targets. Copilot + Claude in the same workspace is supported (`--target=both` or `all`); Specky strips Claude hooks from `.claude/settings.json` so Copilot cannot cross-read them. Prefer a **single** target if you need Claude lifecycle hooks. See [docs/INSTALL.md](docs/INSTALL.md) for details.
110
110
 
111
111
  Or per-project (for teams — pins version in `package.json`, run via `npx`):
112
112
 
@@ -215,8 +215,8 @@ Specky adds a **deterministic engine** between your intent and your code:
215
215
  | EARS validation (programmatic, not AI guessing) | 6 patterns enforced at schema level |
216
216
  | Enforced pipeline (not suggestions) | Contract-specific phases, central analysis gate, optional configured LGTM blocking |
217
217
  | Pre/post hooks on every phase | specky-artifact-validator, specky-branch-validator, specky-phase-gate, specky-lgtm-gate |
218
- | Workload-specific diagrams | Exact required manifest, explicit Mermaid/FigJam payloads, source evidence references |
219
- | Infrastructure as Code | Terraform from persisted cloud/resources; DESIGN.md evidence required |
218
+ | Workload-specific diagrams | Explicit evidence validation or deterministic auto-generation from specification/design content |
219
+ | Infrastructure as Code | DESIGN.md-driven Terraform with exact resource templates and fail-fast preflight |
220
220
  | Work item export | GitHub Issues, Azure Boards, Jira via MCP-to-MCP routing |
221
221
  | 5 compliance frameworks | HIPAA, SOC2, GDPR, PCI-DSS, ISO 27001 with explicit control-ID evidence |
222
222
  | Cross-artifact traceability | Requirement to design to task to test to code |
@@ -566,7 +566,7 @@ The AI calls:
566
566
 
567
567
  - `sdd_run_analysis` → completeness audit, orphaned criteria detection
568
568
  - `sdd_compliance_check` → evaluates the persisted SOC2 pack using evidence keyed by control ID
569
- - `sdd_generate_all_diagrams` → validates exactly the workload-required Mermaid payloads against source evidence
569
+ - `sdd_generate_all_diagrams` → validates explicit Mermaid payloads or uses `mode: "auto"` to derive the complete supported set from source evidence before an atomic write
570
570
 
571
571
  ### Step 6: Generate infrastructure and tests
572
572
 
@@ -576,7 +576,7 @@ The AI calls:
576
576
 
577
577
  The AI calls:
578
578
 
579
- - `sdd_generate_iac` → Terraform for the exact cloud/resources stored in the feature contract
579
+ - `sdd_generate_iac` → Terraform for the exact cloud/resources grounded in the relevant `DESIGN.md` sections; excluded or unsupported resources fail before files are written
580
580
  - `sdd_generate_dockerfile` → Dockerfile/compose from the persisted development stack
581
581
  - `sdd_generate_tests` → executable tests from fingerprinted requirement bindings
582
582
 
@@ -839,16 +839,18 @@ All artifacts are saved in [`.specs/NNN-feature/`](#where-specifications-live).
839
839
 
840
840
  | Tool | Description |
841
841
  |------|-------------|
842
- | `sdd_generate_diagram` | Single Mermaid diagram validated against the workload contract's required set |
843
- | `sdd_generate_all_diagrams` | The exact diagram set the feature contract requires, written atomically |
842
+ | `sdd_generate_diagram` | Explicit Mermaid validation by default, or evidence-grounded auto-generation for supported types |
843
+ | `sdd_generate_all_diagrams` | Explicit validation or atomic auto-generation of the complete supported contracted set |
844
844
  | `sdd_generate_user_stories` | User stories with flow diagrams (web-application workload) |
845
845
  | `sdd_figma_diagram` | FigJam-ready diagram via Figma MCP |
846
846
 
847
+ `mode: "explicit"` remains the compatibility default and requires caller-supplied Mermaid plus evidence references. `mode: "auto"` derives C4 context, sequence, ER, and deployment diagrams from `SPECIFICATION.md` and `DESIGN.md`; unsupported contracted types fail before any file is written.
848
+
847
849
  ### Infrastructure as Code (3)
848
850
 
849
851
  | Tool | Description |
850
852
  |------|-------------|
851
- | `sdd_generate_iac` | Terraform/Bicep from architecture design |
853
+ | `sdd_generate_iac` | Terraform from canonical `module:service` resources grounded in relevant `DESIGN.md` sections; unsupported templates fail preflight |
852
854
  | `sdd_validate_iac` | Validation via Terraform MCP + Azure MCP |
853
855
  | `sdd_generate_dockerfile` | Dockerfile + docker-compose from tech stack |
854
856
 
@@ -1248,6 +1250,10 @@ npm test
1248
1250
  # Run tests with coverage report
1249
1251
  npm run test:coverage
1250
1252
 
1253
+ # Lint and format with Biome
1254
+ npm run lint
1255
+ npm run format
1256
+
1251
1257
  # Development mode (auto-reload on file changes)
1252
1258
  npm run dev
1253
1259
 
@@ -1255,9 +1261,9 @@ npm run dev
1255
1261
  echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}' | node dist/index.js 2>/dev/null
1256
1262
 
1257
1263
  # Run the published image from GHCR (multi-arch: linux/amd64 + linux/arm64)
1258
- docker pull ghcr.io/paulasilvatech/specky:latest # or pin a release: :3.11.1
1264
+ docker pull ghcr.io/paulasilvatech/specky:latest # or pin a release: :3.12.0
1259
1265
  docker run --rm -p 3200:3200 ghcr.io/paulasilvatech/specky:latest
1260
- curl http://localhost:3200/health # -> {"status":"ok","version":"3.11.1"}
1266
+ curl http://localhost:3200/health # -> {"status":"ok","version":"3.12.0"}
1261
1267
 
1262
1268
  # Or build and run locally from source
1263
1269
  docker build -t specky-sdd:dev .
@@ -1272,7 +1278,7 @@ deployments (enterprise profile, token auth, TLS proxy, private packages) see
1272
1278
 
1273
1279
  ## Roadmap
1274
1280
 
1275
- ### v3.11.1 (current)
1281
+ ### v3.12.0 (current)
1276
1282
 
1277
1283
  | Capability | Status |
1278
1284
  |------------|--------|
@@ -1281,7 +1287,8 @@ deployments (enterprise profile, token auth, TLS proxy, private packages) see
1281
1287
  | Target-specific install: `--target=copilot`, `claude`, `cursor`, `opencode`, or `agent-skills` | Stable |
1282
1288
  | Copilot-safe hook manifests (no lifecycle event cross-read) | Stable |
1283
1289
  | Phase validation on every tool with gate enforcement | Stable |
1284
- | Workload-contracted diagram sets (C4, sequence, ER, DFD, deployment, network) | Stable |
1290
+ | Evidence-grounded diagram generation with explicit and auto modes | Stable |
1291
+ | DESIGN.md-driven Terraform with unsupported-resource preflight | Stable |
1285
1292
  | 12-section system design template (C4 model, security, infrastructure) | Stable |
1286
1293
  | Enriched interactive responses on all tools (progress, handoff, education) | Stable |
1287
1294
  | Parallel documentation generation (5 types via Promise.all) | Stable |
package/apm.lock.yaml CHANGED
@@ -2,7 +2,7 @@
2
2
  schemaVersion: 1
3
3
  package:
4
4
  name: specky-sdd
5
- version: 3.11.1
5
+ version: 3.12.0
6
6
  primitives:
7
7
  .apm/agents/specky-design-architect.agent.md: sha256:54c69e392e21cbc1097fce8dd9d53d457d2a80d442390c6072c7d8dc5429c47f
8
8
  .apm/agents/specky-implementer.agent.md: sha256:4bad0b5238d185e25011cc01de90a146d2e719ad2621c814989c5e2986f13772
package/apm.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  name: specky-sdd
2
- version: 3.11.1
2
+ version: 3.12.0
3
3
  description: "Agentic Spec-Driven Development — 10-phase pipeline with 58 MCP tools, 13 agents, 22 prompts, 14 skills, 16 hooks, EARS notation, model routing, and enterprise security"
4
4
  author: Paula Silva
5
5
  license: MIT
@@ -32,7 +32,7 @@ mcp:
32
32
  registry: false
33
33
  transport: stdio
34
34
  command: npx
35
- args: ["-y", "specky-sdd@3.11.1", "serve"]
35
+ args: ["-y", "specky-sdd@3.12.0", "serve"]
36
36
  tools: ["sdd_*"]
37
37
 
38
38
  dependencies:
@@ -41,7 +41,7 @@ dependencies:
41
41
  registry: false
42
42
  transport: stdio
43
43
  command: npx
44
- args: ["-y", "specky-sdd@3.11.1"]
44
+ args: ["-y", "specky-sdd@3.12.0"]
45
45
  tools: ["*"]
46
46
 
47
47
  scripts:
package/config.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  kind: "specky-package-catalog"
2
- version: "3.11.1"
2
+ version: "3.12.0"
3
3
  runtime_config:
4
4
  path: ".specky/config.yml"
5
5
  required: true
@@ -1,2 +1,13 @@
1
+ /**
2
+ * commands/apm.ts — `specky apm <subcommand>` governance surface.
3
+ *
4
+ * Subcommands:
5
+ * validate Validate apm.yml against on-disk primitives + package.json.
6
+ * lock Write apm.lock.yaml with a sha256 for every primitive.
7
+ * verify-lock Recompute hashes and diff against apm.lock.yaml.
8
+ * policy Enforce apm-policy.yml (MCP allowlist, hooks, tool isolation).
9
+ * audit Run the primitive frontmatter audit.
10
+ * sbom Emit a CycloneDX SBOM of the packaged primitives.
11
+ */
1
12
  export declare function apmCommand(argv: string[]): number;
2
13
  //# sourceMappingURL=apm.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"apm.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/apm.ts"],"names":[],"mappings":"AAgHA,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CAwCjD"}
1
+ {"version":3,"file":"apm.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/apm.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAoGH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CAwCjD"}