@niujiajie/freespec 0.0.0-stage → 1.15.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 (308) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +58 -2
  3. package/bin/freespec.js +5 -0
  4. package/dist/cli/index.d.ts +25 -0
  5. package/dist/cli/index.js +359 -0
  6. package/dist/commands/shared-output.d.ts +18 -0
  7. package/dist/commands/shared-output.js +61 -0
  8. package/dist/commands/workflow/default-schema.d.ts +2 -0
  9. package/dist/commands/workflow/default-schema.js +4 -0
  10. package/dist/commands/workflow/index.d.ts +13 -0
  11. package/dist/commands/workflow/index.js +10 -0
  12. package/dist/commands/workflow/instructions.d.ts +39 -0
  13. package/dist/commands/workflow/instructions.js +565 -0
  14. package/dist/commands/workflow/new-change.d.ts +19 -0
  15. package/dist/commands/workflow/new-change.js +135 -0
  16. package/dist/commands/workflow/shared.d.ts +94 -0
  17. package/dist/commands/workflow/shared.js +169 -0
  18. package/dist/commands/workflow/status.d.ts +18 -0
  19. package/dist/commands/workflow/status.js +201 -0
  20. package/dist/core/artifact-graph/graph.d.ts +72 -0
  21. package/dist/core/artifact-graph/graph.js +165 -0
  22. package/dist/core/artifact-graph/index.d.ts +9 -0
  23. package/dist/core/artifact-graph/index.js +14 -0
  24. package/dist/core/artifact-graph/instruction-loader.d.ts +208 -0
  25. package/dist/core/artifact-graph/instruction-loader.js +268 -0
  26. package/dist/core/artifact-graph/outputs.d.ts +19 -0
  27. package/dist/core/artifact-graph/outputs.js +351 -0
  28. package/dist/core/artifact-graph/resolver.d.ts +89 -0
  29. package/dist/core/artifact-graph/resolver.js +342 -0
  30. package/dist/core/artifact-graph/schema.d.ts +27 -0
  31. package/dist/core/artifact-graph/schema.js +160 -0
  32. package/dist/core/artifact-graph/state.d.ts +12 -0
  33. package/dist/core/artifact-graph/state.js +31 -0
  34. package/dist/core/artifact-graph/types.d.ts +40 -0
  35. package/dist/core/artifact-graph/types.js +59 -0
  36. package/dist/core/available-tools.d.ts +18 -0
  37. package/dist/core/available-tools.js +49 -0
  38. package/dist/core/change-layout.d.ts +17 -0
  39. package/dist/core/change-layout.js +30 -0
  40. package/dist/core/change-metadata/index.d.ts +2 -0
  41. package/dist/core/change-metadata/index.js +2 -0
  42. package/dist/core/change-metadata/schema.d.ts +23 -0
  43. package/dist/core/change-metadata/schema.js +46 -0
  44. package/dist/core/change-status-policy.d.ts +49 -0
  45. package/dist/core/change-status-policy.js +50 -0
  46. package/dist/core/command-generation/adapters/amazon-q.d.ts +17 -0
  47. package/dist/core/command-generation/adapters/amazon-q.js +32 -0
  48. package/dist/core/command-generation/adapters/antigravity.d.ts +13 -0
  49. package/dist/core/command-generation/adapters/antigravity.js +27 -0
  50. package/dist/core/command-generation/adapters/atomcode.d.ts +24 -0
  51. package/dist/core/command-generation/adapters/atomcode.js +46 -0
  52. package/dist/core/command-generation/adapters/auggie.d.ts +13 -0
  53. package/dist/core/command-generation/adapters/auggie.js +28 -0
  54. package/dist/core/command-generation/adapters/bob.d.ts +18 -0
  55. package/dist/core/command-generation/adapters/bob.js +33 -0
  56. package/dist/core/command-generation/adapters/claude.d.ts +13 -0
  57. package/dist/core/command-generation/adapters/claude.js +32 -0
  58. package/dist/core/command-generation/adapters/cline.d.ts +14 -0
  59. package/dist/core/command-generation/adapters/cline.js +27 -0
  60. package/dist/core/command-generation/adapters/codeassistant.d.ts +15 -0
  61. package/dist/core/command-generation/adapters/codeassistant.js +29 -0
  62. package/dist/core/command-generation/adapters/codebuddy.d.ts +13 -0
  63. package/dist/core/command-generation/adapters/codebuddy.js +29 -0
  64. package/dist/core/command-generation/adapters/codestudio.d.ts +13 -0
  65. package/dist/core/command-generation/adapters/codestudio.js +27 -0
  66. package/dist/core/command-generation/adapters/command-code.d.ts +19 -0
  67. package/dist/core/command-generation/adapters/command-code.js +34 -0
  68. package/dist/core/command-generation/adapters/continue.d.ts +13 -0
  69. package/dist/core/command-generation/adapters/continue.js +33 -0
  70. package/dist/core/command-generation/adapters/costrict.d.ts +13 -0
  71. package/dist/core/command-generation/adapters/costrict.js +28 -0
  72. package/dist/core/command-generation/adapters/crush.d.ts +13 -0
  73. package/dist/core/command-generation/adapters/crush.js +30 -0
  74. package/dist/core/command-generation/adapters/cursor.d.ts +14 -0
  75. package/dist/core/command-generation/adapters/cursor.js +31 -0
  76. package/dist/core/command-generation/adapters/devin.d.ts +19 -0
  77. package/dist/core/command-generation/adapters/devin.js +36 -0
  78. package/dist/core/command-generation/adapters/easycode.d.ts +17 -0
  79. package/dist/core/command-generation/adapters/easycode.js +28 -0
  80. package/dist/core/command-generation/adapters/factory.d.ts +13 -0
  81. package/dist/core/command-generation/adapters/factory.js +28 -0
  82. package/dist/core/command-generation/adapters/gemini.d.ts +13 -0
  83. package/dist/core/command-generation/adapters/gemini.js +27 -0
  84. package/dist/core/command-generation/adapters/gigacode.d.ts +17 -0
  85. package/dist/core/command-generation/adapters/gigacode.js +31 -0
  86. package/dist/core/command-generation/adapters/github-copilot.d.ts +13 -0
  87. package/dist/core/command-generation/adapters/github-copilot.js +27 -0
  88. package/dist/core/command-generation/adapters/iflow.d.ts +13 -0
  89. package/dist/core/command-generation/adapters/iflow.js +30 -0
  90. package/dist/core/command-generation/adapters/index.d.ts +40 -0
  91. package/dist/core/command-generation/adapters/index.js +40 -0
  92. package/dist/core/command-generation/adapters/junie.d.ts +13 -0
  93. package/dist/core/command-generation/adapters/junie.js +27 -0
  94. package/dist/core/command-generation/adapters/kilocode.d.ts +14 -0
  95. package/dist/core/command-generation/adapters/kilocode.js +23 -0
  96. package/dist/core/command-generation/adapters/kiro.d.ts +13 -0
  97. package/dist/core/command-generation/adapters/kiro.js +27 -0
  98. package/dist/core/command-generation/adapters/lingma.d.ts +13 -0
  99. package/dist/core/command-generation/adapters/lingma.js +30 -0
  100. package/dist/core/command-generation/adapters/oh-my-pi.d.ts +21 -0
  101. package/dist/core/command-generation/adapters/oh-my-pi.js +42 -0
  102. package/dist/core/command-generation/adapters/opencode.d.ts +14 -0
  103. package/dist/core/command-generation/adapters/opencode.js +38 -0
  104. package/dist/core/command-generation/adapters/pi.d.ts +18 -0
  105. package/dist/core/command-generation/adapters/pi.js +39 -0
  106. package/dist/core/command-generation/adapters/qoder.d.ts +13 -0
  107. package/dist/core/command-generation/adapters/qoder.js +30 -0
  108. package/dist/core/command-generation/adapters/qwen.d.ts +17 -0
  109. package/dist/core/command-generation/adapters/qwen.js +31 -0
  110. package/dist/core/command-generation/adapters/roocode.d.ts +14 -0
  111. package/dist/core/command-generation/adapters/roocode.js +27 -0
  112. package/dist/core/command-generation/adapters/trae.d.ts +13 -0
  113. package/dist/core/command-generation/adapters/trae.js +28 -0
  114. package/dist/core/command-generation/adapters/zcode.d.ts +16 -0
  115. package/dist/core/command-generation/adapters/zcode.js +33 -0
  116. package/dist/core/command-generation/generator.d.ts +29 -0
  117. package/dist/core/command-generation/generator.js +43 -0
  118. package/dist/core/command-generation/index.d.ts +22 -0
  119. package/dist/core/command-generation/index.js +24 -0
  120. package/dist/core/command-generation/invocation.d.ts +73 -0
  121. package/dist/core/command-generation/invocation.js +77 -0
  122. package/dist/core/command-generation/registry.d.ts +36 -0
  123. package/dist/core/command-generation/registry.js +114 -0
  124. package/dist/core/command-generation/toml.d.ts +19 -0
  125. package/dist/core/command-generation/toml.js +39 -0
  126. package/dist/core/command-generation/types.d.ts +63 -0
  127. package/dist/core/command-generation/types.js +8 -0
  128. package/dist/core/command-generation/yaml.d.ts +36 -0
  129. package/dist/core/command-generation/yaml.js +48 -0
  130. package/dist/core/command-surface.d.ts +15 -0
  131. package/dist/core/command-surface.js +33 -0
  132. package/dist/core/config-prompts.d.ts +9 -0
  133. package/dist/core/config-prompts.js +56 -0
  134. package/dist/core/config-schema.d.ts +98 -0
  135. package/dist/core/config-schema.js +308 -0
  136. package/dist/core/config.d.ts +50 -0
  137. package/dist/core/config.js +122 -0
  138. package/dist/core/file-state.d.ts +36 -0
  139. package/dist/core/file-state.js +144 -0
  140. package/dist/core/file-view.d.ts +13 -0
  141. package/dist/core/file-view.js +14 -0
  142. package/dist/core/global-config.d.ts +101 -0
  143. package/dist/core/global-config.js +182 -0
  144. package/dist/core/id.d.ts +17 -0
  145. package/dist/core/id.js +30 -0
  146. package/dist/core/index.d.ts +6 -0
  147. package/dist/core/index.js +7 -0
  148. package/dist/core/init.d.ts +57 -0
  149. package/dist/core/init.js +836 -0
  150. package/dist/core/list.d.ts +11 -0
  151. package/dist/core/list.js +197 -0
  152. package/dist/core/migration.d.ts +121 -0
  153. package/dist/core/migration.js +540 -0
  154. package/dist/core/onboarding-commands.d.ts +30 -0
  155. package/dist/core/onboarding-commands.js +38 -0
  156. package/dist/core/openspec-root.d.ts +47 -0
  157. package/dist/core/openspec-root.js +196 -0
  158. package/dist/core/planning-home.d.ts +16 -0
  159. package/dist/core/planning-home.js +67 -0
  160. package/dist/core/profile-sync-drift.d.ts +31 -0
  161. package/dist/core/profile-sync-drift.js +201 -0
  162. package/dist/core/profiles.d.ts +19 -0
  163. package/dist/core/profiles.js +33 -0
  164. package/dist/core/project-config.d.ts +132 -0
  165. package/dist/core/project-config.js +519 -0
  166. package/dist/core/references.d.ts +10 -0
  167. package/dist/core/references.js +46 -0
  168. package/dist/core/root-selection.d.ts +59 -0
  169. package/dist/core/root-selection.js +132 -0
  170. package/dist/core/shared/allowed-tools.d.ts +12 -0
  171. package/dist/core/shared/allowed-tools.js +12 -0
  172. package/dist/core/shared/ide-restart.d.ts +26 -0
  173. package/dist/core/shared/ide-restart.js +42 -0
  174. package/dist/core/shared/index.d.ts +11 -0
  175. package/dist/core/shared/index.js +11 -0
  176. package/dist/core/shared/skill-content-equivalence.d.ts +7 -0
  177. package/dist/core/shared/skill-content-equivalence.js +45 -0
  178. package/dist/core/shared/skill-files.d.ts +7 -0
  179. package/dist/core/shared/skill-files.js +43 -0
  180. package/dist/core/shared/skill-generation.d.ts +49 -0
  181. package/dist/core/shared/skill-generation.js +125 -0
  182. package/dist/core/shared/skill-paths.d.ts +13 -0
  183. package/dist/core/shared/skill-paths.js +23 -0
  184. package/dist/core/shared/tool-detection.d.ts +99 -0
  185. package/dist/core/shared/tool-detection.js +318 -0
  186. package/dist/core/shared-skill-target.d.ts +51 -0
  187. package/dist/core/shared-skill-target.js +239 -0
  188. package/dist/core/store/errors.d.ts +20 -0
  189. package/dist/core/store/errors.js +22 -0
  190. package/dist/core/store/index.d.ts +2 -0
  191. package/dist/core/store/index.js +2 -0
  192. package/dist/core/styles/palette.d.ts +7 -0
  193. package/dist/core/styles/palette.js +8 -0
  194. package/dist/core/templates/optional-workflow.d.ts +69 -0
  195. package/dist/core/templates/optional-workflow.js +140 -0
  196. package/dist/core/templates/types.d.ts +19 -0
  197. package/dist/core/templates/types.js +5 -0
  198. package/dist/core/templates/workflows/personal.d.ts +22 -0
  199. package/dist/core/templates/workflows/personal.js +225 -0
  200. package/dist/core/update-plan.d.ts +127 -0
  201. package/dist/core/update-plan.js +390 -0
  202. package/dist/core/update.d.ts +154 -0
  203. package/dist/core/update.js +723 -0
  204. package/dist/core/version-check.d.ts +188 -0
  205. package/dist/core/version-check.js +906 -0
  206. package/dist/core/zod-issues.d.ts +4 -0
  207. package/dist/core/zod-issues.js +10 -0
  208. package/dist/index.d.ts +3 -0
  209. package/dist/index.js +3 -0
  210. package/dist/prompts/searchable-multi-select.d.ts +35 -0
  211. package/dist/prompts/searchable-multi-select.js +188 -0
  212. package/dist/telemetry/config.d.ts +37 -0
  213. package/dist/telemetry/config.js +148 -0
  214. package/dist/telemetry/index.d.ts +39 -0
  215. package/dist/telemetry/index.js +217 -0
  216. package/dist/telemetry/opt-out.d.ts +17 -0
  217. package/dist/telemetry/opt-out.js +27 -0
  218. package/dist/ui/ascii-patterns.d.ts +16 -0
  219. package/dist/ui/ascii-patterns.js +133 -0
  220. package/dist/ui/welcome-screen.d.ts +18 -0
  221. package/dist/ui/welcome-screen.js +199 -0
  222. package/dist/utils/change-metadata.d.ts +116 -0
  223. package/dist/utils/change-metadata.js +324 -0
  224. package/dist/utils/change-utils.d.ts +79 -0
  225. package/dist/utils/change-utils.js +121 -0
  226. package/dist/utils/ci.d.ts +12 -0
  227. package/dist/utils/ci.js +16 -0
  228. package/dist/utils/command-references.d.ts +104 -0
  229. package/dist/utils/command-references.js +190 -0
  230. package/dist/utils/date.d.ts +8 -0
  231. package/dist/utils/date.js +13 -0
  232. package/dist/utils/executable-path.d.ts +5 -0
  233. package/dist/utils/executable-path.js +44 -0
  234. package/dist/utils/file-system.d.ts +58 -0
  235. package/dist/utils/file-system.js +432 -0
  236. package/dist/utils/index.d.ts +6 -0
  237. package/dist/utils/index.js +9 -0
  238. package/dist/utils/interactive.d.ts +85 -0
  239. package/dist/utils/interactive.js +174 -0
  240. package/dist/utils/item-discovery.d.ts +15 -0
  241. package/dist/utils/item-discovery.js +33 -0
  242. package/dist/utils/line-endings.d.ts +34 -0
  243. package/dist/utils/line-endings.js +46 -0
  244. package/dist/utils/match.d.ts +3 -0
  245. package/dist/utils/match.js +22 -0
  246. package/dist/utils/nested-change.d.ts +35 -0
  247. package/dist/utils/nested-change.js +185 -0
  248. package/dist/utils/shell-detection.d.ts +20 -0
  249. package/dist/utils/shell-detection.js +94 -0
  250. package/dist/utils/task-progress.d.ts +67 -0
  251. package/dist/utils/task-progress.js +184 -0
  252. package/package.json +74 -4
  253. package/schemas//351/273/230/350/256/244/schema.yaml +68 -0
  254. package/schemas//351/273/230/350/256/244/templates//344/273/273/345/212/241/346/270/205/345/215/225.md +25 -0
  255. package/schemas//351/273/230/350/256/244/templates//346/265/213/350/257/225/347/224/250/344/276/213.md +34 -0
  256. package/schemas//351/273/230/350/256/244/templates//350/256/276/350/256/241/346/226/207/346/241/243.md +172 -0
  257. package/schemas//351/273/230/350/256/244/templates//351/234/200/346/261/202/346/226/207/346/241/243.md +19 -0
  258. package/skill-files//344/273/273/345/212/241/references//346/212/244/346/240/217.md +43 -0
  259. package/skill-files//344/273/273/345/212/241/references//347/262/222/345/272/246.md +23 -0
  260. package/skill-files//344/273/273/345/212/241/references//347/272/246/346/235/237.md +8 -0
  261. package/skill-files//344/273/273/345/212/241/scripts/check-tasks.mjs +83 -0
  262. package/skill-files//345/206/231Java/references/Java/350/247/204/350/214/203.md +25 -0
  263. package/skill-files//345/206/231Java/references//345/215/261/351/231/251/345/206/231/346/263/225.md +27 -0
  264. package/skill-files//345/206/231Java/references//345/256/214/346/210/220/345/257/271/347/205/247.md +15 -0
  265. package/skill-files//345/206/231Java/references//346/212/244/346/240/217.md +35 -0
  266. package/skill-files//345/206/231Java/references//347/272/246/346/235/237.md +8 -0
  267. package/skill-files//345/206/231Java/references//350/270/251/345/235/221.md +17 -0
  268. package/skill-files//345/256/241Java/references//346/212/244/346/240/217.md +19 -0
  269. package/skill-files//345/256/241Java/references//347/244/272/344/276/213.md +23 -0
  270. package/skill-files//345/256/241Java/references//347/272/246/346/235/237.md +7 -0
  271. package/skill-files//345/256/241Java/references//350/247/204/345/210/231.md +23 -0
  272. package/skill-files//345/256/241Java/references//351/242/206/345/237/237/346/243/200/351/241/271.md +58 -0
  273. package/skill-files//345/256/241/346/226/207/346/241/243/references//346/212/244/346/240/217.md +18 -0
  274. package/skill-files//345/256/241/346/226/207/346/241/243/references//347/272/246/346/235/237.md +8 -0
  275. package/skill-files//345/256/241/346/226/207/346/241/243/references//347/273/264/345/272/246.md +17 -0
  276. package/skill-files//345/256/241/346/226/207/346/241/243/references//350/270/251/345/235/221.md +11 -0
  277. package/skill-files//346/226/260/345/273/272/references//344/272/244/346/216/245.md +11 -0
  278. package/skill-files//346/226/260/345/273/272/references//346/212/244/346/240/217.md +14 -0
  279. package/skill-files//346/226/260/345/273/272/references//347/272/246/346/235/237.md +7 -0
  280. package/skill-files//346/267/261/346/200/235/config/prompts.yaml +114 -0
  281. package/skill-files//346/267/261/346/200/235/references//344/270/211/346/226/271/346/240/270/345/257/271.md +72 -0
  282. package/skill-files//346/267/261/346/200/235/references//344/276/213/345/255/220.md +39 -0
  283. package/skill-files//346/267/261/346/200/235/references//346/200/216/344/271/210/346/203/263.md +61 -0
  284. package/skill-files//346/267/261/346/200/235/references//346/212/244/346/240/217.md +26 -0
  285. package/skill-files//346/267/261/346/200/235/references//347/202/271/351/200/211/346/217/220/351/227/256.md +66 -0
  286. package/skill-files//346/267/261/346/200/235/references//347/231/273/350/256/260.md +45 -0
  287. package/skill-files//346/267/261/346/200/235/references//347/272/246/346/235/237.md +9 -0
  288. package/skill-files//347/224/250/344/276/213/references//346/200/216/344/271/210/345/206/231.md +13 -0
  289. package/skill-files//347/224/250/344/276/213/references//346/212/244/346/240/217.md +42 -0
  290. package/skill-files//347/224/250/344/276/213/references//347/272/246/346/235/237.md +5 -0
  291. package/skill-files//347/224/250/344/276/213/scripts/check-cases.mjs +70 -0
  292. package/skill-files//350/256/276/350/256/241/references//345/207/206/345/244/207.md +25 -0
  293. package/skill-files//350/256/276/350/256/241/references//346/212/244/346/240/217.md +134 -0
  294. package/skill-files//350/256/276/350/256/241/references//346/226/207/351/243/216.md +17 -0
  295. package/skill-files//350/256/276/350/256/241/references//347/225/214/351/235/242.md +18 -0
  296. package/skill-files//350/256/276/350/256/241/references//347/261/273/345/236/213.md +19 -0
  297. package/skill-files//350/256/276/350/256/241/references//347/272/246/346/235/237.md +25 -0
  298. package/skill-files//350/256/276/350/256/241/scripts/_smoke.mjs +72 -0
  299. package/skill-files//350/256/276/350/256/241/scripts/check-design.mjs +331 -0
  300. package/skill-files//351/234/200/346/261/202/references//346/212/244/346/240/217.md +26 -0
  301. package/skill-files//351/234/200/346/261/202/references//346/226/207/351/243/216.md +23 -0
  302. package/skill-files//351/234/200/346/261/202/references//346/267/261/346/200/235/346/221/204/345/205/245.md +21 -0
  303. package/skill-files//351/234/200/346/261/202/references//347/272/246/346/235/237.md +8 -0
  304. package/skill-files//351/234/200/346/261/202/references//351/234/200/346/261/202/345/276/205/345/256/232.md +13 -0
  305. package/skill-files//351/234/200/346/261/202/scripts/check-requirements.mjs +60 -0
  306. package/skill-files//351/252/214/346/224/266/references//346/212/244/346/240/217.md +27 -0
  307. package/skill-files//351/252/214/346/224/266/references//346/240/270/345/257/271.md +17 -0
  308. package/skill-files//351/252/214/346/224/266/references//347/272/246/346/235/237.md +7 -0
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Strings rendered into agent guidance. One line in, one line out: control
3
+ * characters and newlines must never let hostile content forge instruction lines.
4
+ */
5
+ export function sanitizeInline(value, maxLength = 300) {
6
+ const flattened = value
7
+ .replace(/[\u0000-\u001f\u007f-\u009f\u061c\u200e\u200f\u2028-\u202e\u2066-\u206f]+/g, ' ')
8
+ .trim();
9
+ return flattened.length > maxLength ? `${flattened.slice(0, maxLength)}…` : flattened;
10
+ }
11
+ /**
12
+ * The tags the instruction printer uses to frame its blocks. A block ends at
13
+ * its own closing tag and nowhere else, so this is the entire breakout
14
+ * surface: neutralize these and repo-supplied text cannot escape the element
15
+ * that marks it as data.
16
+ */
17
+ const ENVELOPE_TAGS = [
18
+ 'artifact',
19
+ 'dependencies',
20
+ 'dependency',
21
+ 'description',
22
+ 'instruction',
23
+ 'output',
24
+ 'path',
25
+ 'project_context',
26
+ 'rules',
27
+ 'success_criteria',
28
+ 'task',
29
+ 'template',
30
+ 'unlocks',
31
+ 'warning',
32
+ ];
33
+ const ENVELOPE_TAG = new RegExp(`<(/?)(${ENVELOPE_TAGS.join('|')})(\\s[^<>]*)?>`, 'gi');
34
+ /** Neutralize the envelope's own tags in repo-supplied text. */
35
+ export function escapeEnvelopeTags(value) {
36
+ return value.replace(ENVELOPE_TAG, (_match, slash, tag, attrs) => `&lt;${slash}${tag}${attrs ?? ''}&gt;`);
37
+ }
38
+ /** Escape attribute metacharacters so a quote cannot close the attribute. */
39
+ export function escapeEnvelopeAttribute(value) {
40
+ return value
41
+ .replace(/&/g, '&amp;')
42
+ .replace(/</g, '&lt;')
43
+ .replace(/>/g, '&gt;')
44
+ .replace(/"/g, '&quot;');
45
+ }
46
+ //# sourceMappingURL=references.js.map
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Resolves the local FreeSpec root for the supported commands.
3
+ *
4
+ * A root is the nearest ancestor whose `freespec/` directory is a planning
5
+ * directory (it contains a `<名称>变更` folder) or holds `config.yaml`.
6
+ * With neither, commands may treat the current directory as an implicit root.
7
+ */
8
+ import { type PlanningHome } from './planning-home.js';
9
+ export type FreeSpecRootSource = 'nearest' | 'implicit';
10
+ export interface StoreSelectorOptions {
11
+ store?: string;
12
+ storePath?: string;
13
+ }
14
+ export interface ResolveFreeSpecRootOptions extends StoreSelectorOptions {
15
+ startPath?: string;
16
+ allowImplicitRoot?: boolean;
17
+ globalDataDir?: string;
18
+ }
19
+ export interface ResolvedFreeSpecRoot {
20
+ path: string;
21
+ changesDir: string;
22
+ specsDir: string;
23
+ defaultSchema: string;
24
+ source: FreeSpecRootSource;
25
+ }
26
+ export interface RootSelectionDiagnostic {
27
+ severity: 'error';
28
+ code: string;
29
+ message: string;
30
+ target?: string;
31
+ fix?: string;
32
+ }
33
+ export declare class RootSelectionError extends Error {
34
+ readonly diagnostic: RootSelectionDiagnostic;
35
+ constructor(message: string, code: string, options?: {
36
+ target?: string;
37
+ fix?: string;
38
+ });
39
+ }
40
+ export declare function isRootSelectionError(error: unknown): error is RootSelectionError;
41
+ export declare function resolveFreeSpecRoot(options?: ResolveFreeSpecRootOptions): Promise<ResolvedFreeSpecRoot>;
42
+ export interface RootOutput {
43
+ path: string;
44
+ source: FreeSpecRootSource;
45
+ }
46
+ export declare function toRootOutput(root: ResolvedFreeSpecRoot): RootOutput;
47
+ export declare function toPlanningHome(root: ResolvedFreeSpecRoot): PlanningHome;
48
+ /**
49
+ * CLI adapter shared by the supported commands. In JSON mode a resolution
50
+ * failure is reported as a machine-readable payload on stdout with a
51
+ * non-zero exit code; the caller must return when this resolves to null.
52
+ */
53
+ export declare function resolveRootForCommand(selector: StoreSelectorOptions, output?: {
54
+ json?: boolean;
55
+ failurePayload?: Record<string, unknown>;
56
+ /** Commands that require an existing root set this to false. */
57
+ allowImplicitRoot?: boolean;
58
+ }): Promise<ResolvedFreeSpecRoot | null>;
59
+ //# sourceMappingURL=root-selection.d.ts.map
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Resolves the local FreeSpec root for the supported commands.
3
+ *
4
+ * A root is the nearest ancestor whose `freespec/` directory is a planning
5
+ * directory (it contains a `<名称>变更` folder) or holds `config.yaml`.
6
+ * With neither, commands may treat the current directory as an implicit root.
7
+ */
8
+ import * as fs from 'node:fs';
9
+ import * as path from 'node:path';
10
+ import { changeParentDir, DEFAULT_SCHEMA } from './change-layout.js';
11
+ import { findRepoPlanningRootSync } from './planning-home.js';
12
+ import { classifyFreeSpecDir } from './project-config.js';
13
+ import { FileSystemUtils } from '../utils/file-system.js';
14
+ export class RootSelectionError extends Error {
15
+ diagnostic;
16
+ constructor(message, code, options = {}) {
17
+ super(message);
18
+ this.name = 'RootSelectionError';
19
+ this.diagnostic = {
20
+ severity: 'error',
21
+ code,
22
+ message,
23
+ ...options,
24
+ };
25
+ }
26
+ }
27
+ export function isRootSelectionError(error) {
28
+ return error instanceof RootSelectionError;
29
+ }
30
+ function makeRoot(rootPath, source) {
31
+ return {
32
+ path: rootPath,
33
+ changesDir: changeParentDir(rootPath),
34
+ specsDir: path.join(rootPath, 'freespec', 'specs'),
35
+ defaultSchema: DEFAULT_SCHEMA,
36
+ source,
37
+ };
38
+ }
39
+ function canonicalDirectory(startPath) {
40
+ const resolved = path.resolve(startPath);
41
+ try {
42
+ const stats = fs.statSync(resolved);
43
+ const dir = stats.isDirectory() ? resolved : path.dirname(resolved);
44
+ return FileSystemUtils.canonicalizeExistingPath(dir);
45
+ }
46
+ catch {
47
+ return resolved;
48
+ }
49
+ }
50
+ /**
51
+ * An `freespec/` directory is a root when it holds a change folder or a
52
+ * config file. A bare directory is not enough: `~/freespec` would otherwise
53
+ * capture every command under the home tree.
54
+ */
55
+ function findQualifyingRootSync(startPath) {
56
+ let candidate = findRepoPlanningRootSync(startPath);
57
+ while (candidate) {
58
+ const { hasPlanningShape, pointer } = classifyFreeSpecDir(candidate);
59
+ if (hasPlanningShape || pointer.filePath) {
60
+ return candidate;
61
+ }
62
+ const parent = path.dirname(candidate);
63
+ if (parent === candidate) {
64
+ return null;
65
+ }
66
+ candidate = findRepoPlanningRootSync(parent);
67
+ }
68
+ return null;
69
+ }
70
+ function rejectStoreSelection() {
71
+ throw new RootSelectionError('This FreeSpec build uses the local freespec/ directory. Store selection is not available.', 'store_not_supported', {
72
+ target: 'freespec.root',
73
+ fix: 'Run freespec init in the project, then rerun the command there.',
74
+ });
75
+ }
76
+ export async function resolveFreeSpecRoot(options = {}) {
77
+ if (options.storePath !== undefined || options.store !== undefined) {
78
+ rejectStoreSelection();
79
+ }
80
+ const startPath = options.startPath ?? process.cwd();
81
+ const nearestRoot = findQualifyingRootSync(startPath);
82
+ if (nearestRoot) {
83
+ const { pointer } = classifyFreeSpecDir(nearestRoot);
84
+ if (pointer.value !== undefined && pointer.filePath) {
85
+ console.error(`Warning: ${pointer.filePath} declares store '${pointer.value}'. This build uses the local freespec/ directory and ignores that declaration.`);
86
+ }
87
+ return makeRoot(nearestRoot, 'nearest');
88
+ }
89
+ if (options.allowImplicitRoot === false) {
90
+ throw new RootSelectionError('No FreeSpec root found from the current directory.', 'no_freespec_root', { target: 'freespec.root', fix: 'Run freespec init to create a root here.' });
91
+ }
92
+ return makeRoot(canonicalDirectory(startPath), 'implicit');
93
+ }
94
+ export function toRootOutput(root) {
95
+ return {
96
+ path: root.path,
97
+ source: root.source,
98
+ };
99
+ }
100
+ export function toPlanningHome(root) {
101
+ return {
102
+ kind: 'repo',
103
+ root: root.path,
104
+ changesDir: root.changesDir,
105
+ defaultSchema: root.defaultSchema,
106
+ };
107
+ }
108
+ /**
109
+ * CLI adapter shared by the supported commands. In JSON mode a resolution
110
+ * failure is reported as a machine-readable payload on stdout with a
111
+ * non-zero exit code; the caller must return when this resolves to null.
112
+ */
113
+ export async function resolveRootForCommand(selector, output = {}) {
114
+ try {
115
+ return await resolveFreeSpecRoot({
116
+ ...(selector.store !== undefined ? { store: selector.store } : {}),
117
+ ...(selector.storePath !== undefined ? { storePath: selector.storePath } : {}),
118
+ ...(output.allowImplicitRoot !== undefined
119
+ ? { allowImplicitRoot: output.allowImplicitRoot }
120
+ : {}),
121
+ });
122
+ }
123
+ catch (error) {
124
+ if (output.json && isRootSelectionError(error)) {
125
+ console.log(JSON.stringify({ ...(output.failurePayload ?? {}), status: [error.diagnostic] }, null, 2));
126
+ process.exitCode = 1;
127
+ return null;
128
+ }
129
+ throw error;
130
+ }
131
+ }
132
+ //# sourceMappingURL=root-selection.js.map
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Pre-approved tools for generated skills and slash commands, emitted as the
3
+ * `allowed-tools` frontmatter field (Agent Skills standard for SKILL.md;
4
+ * same field for Claude Code slash commands). Scoped to the FreeSpec CLI so
5
+ * agents that honor it stop prompting on each `freespec` call; the field
6
+ * only pre-approves — it does not restrict — so any other tool a skill or
7
+ * command needs (Read, Write, arbitrary Bash for builds/tests) stays
8
+ * available under the user's normal permission settings. Tools that don't
9
+ * recognize the field ignore it.
10
+ */
11
+ export declare const OPENSPEC_CLI_ALLOWED_TOOLS = "Bash(freespec:*)";
12
+ //# sourceMappingURL=allowed-tools.d.ts.map
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Pre-approved tools for generated skills and slash commands, emitted as the
3
+ * `allowed-tools` frontmatter field (Agent Skills standard for SKILL.md;
4
+ * same field for Claude Code slash commands). Scoped to the FreeSpec CLI so
5
+ * agents that honor it stop prompting on each `freespec` call; the field
6
+ * only pre-approves — it does not restrict — so any other tool a skill or
7
+ * command needs (Read, Write, arbitrary Bash for builds/tests) stays
8
+ * available under the user's normal permission settings. Tools that don't
9
+ * recognize the field ignore it.
10
+ */
11
+ export const OPENSPEC_CLI_ALLOWED_TOOLS = 'Bash(freespec:*)';
12
+ //# sourceMappingURL=allowed-tools.js.map
@@ -0,0 +1,26 @@
1
+ /**
2
+ * IDE restart hint
3
+ *
4
+ * Shared restart guidance for tools successfully configured by init or update.
5
+ * The wording covers additions, updates, and removals, including an empty
6
+ * workflow selection that removes every generated file.
7
+ */
8
+ import type { Delivery } from '../global-config.js';
9
+ /** The surface a restart hint names. Absent when no hint is due. */
10
+ export type IdeRestartSurface = 'commands' | 'skills';
11
+ /**
12
+ * Both conditions stay coupled to the SAME tool: its surfaces are loaded by a
13
+ * long-running editor process (a CLI picks them up immediately, so a restart
14
+ * line would be wrong for it — see #1067), and it supports a generated surface
15
+ * under the active delivery. A CLI tool's commands must not determine the hint
16
+ * for an IDE tool that only supports skills. Commands take precedence when
17
+ * both surfaces are supported under the active delivery.
18
+ */
19
+ export declare function resolveIdeRestartSurface(toolIds: readonly string[], delivery: Delivery): IdeRestartSurface | null;
20
+ /**
21
+ * The restart line to print, or null when no restart is needed. Deliberately
22
+ * not "slash commands": Amazon Q's generated files are prompt-library entries
23
+ * invoked with `@`, so promising slash commands would be wrong for it.
24
+ */
25
+ export declare function formatIdeRestart(toolIds: readonly string[], delivery: Delivery): string | null;
26
+ //# sourceMappingURL=ide-restart.d.ts.map
@@ -0,0 +1,42 @@
1
+ /**
2
+ * IDE restart hint
3
+ *
4
+ * Shared restart guidance for tools successfully configured by init or update.
5
+ * The wording covers additions, updates, and removals, including an empty
6
+ * workflow selection that removes every generated file.
7
+ */
8
+ import { AI_TOOLS } from '../config.js';
9
+ import { shouldGenerateCommandsForTool, shouldGenerateSkillsForTool, } from '../command-surface.js';
10
+ function isIdeResident(toolId) {
11
+ return Boolean(AI_TOOLS.find((tool) => tool.value === toolId)?.requiresIdeRestart);
12
+ }
13
+ /**
14
+ * Both conditions stay coupled to the SAME tool: its surfaces are loaded by a
15
+ * long-running editor process (a CLI picks them up immediately, so a restart
16
+ * line would be wrong for it — see #1067), and it supports a generated surface
17
+ * under the active delivery. A CLI tool's commands must not determine the hint
18
+ * for an IDE tool that only supports skills. Commands take precedence when
19
+ * both surfaces are supported under the active delivery.
20
+ */
21
+ export function resolveIdeRestartSurface(toolIds, delivery) {
22
+ const ideTools = [...new Set(toolIds)].filter(isIdeResident);
23
+ if (ideTools.some((toolId) => shouldGenerateCommandsForTool(toolId, delivery))) {
24
+ return 'commands';
25
+ }
26
+ if (ideTools.some((toolId) => shouldGenerateSkillsForTool(toolId, delivery))) {
27
+ return 'skills';
28
+ }
29
+ return null;
30
+ }
31
+ /**
32
+ * The restart line to print, or null when no restart is needed. Deliberately
33
+ * not "slash commands": Amazon Q's generated files are prompt-library entries
34
+ * invoked with `@`, so promising slash commands would be wrong for it.
35
+ */
36
+ export function formatIdeRestart(toolIds, delivery) {
37
+ const surface = resolveIdeRestartSurface(toolIds, delivery);
38
+ return surface
39
+ ? `Restart your IDE to refresh ${surface}.`
40
+ : null;
41
+ }
42
+ //# sourceMappingURL=ide-restart.js.map
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Shared Utilities
3
+ *
4
+ * Common code shared between init and update commands.
5
+ */
6
+ export { SKILL_NAMES, type SkillName, COMMAND_IDS, type CommandId, type ToolSkillStatus, type ToolVersionStatus, getToolsWithSkillsDir, getToolSkillStatus, getToolStates, extractGeneratedByVersion, getToolVersionStatus, getConfiguredTools, getAllToolVersionStatus, } from './tool-detection.js';
7
+ export { type SkillTemplateEntry, type CommandTemplateEntry, getSkillTemplates, getCommandTemplates, getCommandContents, generateSkillContent, } from './skill-generation.js';
8
+ export { copySkillExtras, getSkillFilesRoot } from './skill-files.js';
9
+ export { type SkillCapableTool, toolSupportsSkills, getSkillCapableTools, hasGlobalSkillTarget, resolveToolSkillsDir, } from './skill-paths.js';
10
+ export { type IdeRestartSurface, resolveIdeRestartSurface, formatIdeRestart, } from './ide-restart.js';
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Shared Utilities
3
+ *
4
+ * Common code shared between init and update commands.
5
+ */
6
+ export { SKILL_NAMES, COMMAND_IDS, getToolsWithSkillsDir, getToolSkillStatus, getToolStates, extractGeneratedByVersion, getToolVersionStatus, getConfiguredTools, getAllToolVersionStatus, } from './tool-detection.js';
7
+ export { getSkillTemplates, getCommandTemplates, getCommandContents, generateSkillContent, } from './skill-generation.js';
8
+ export { copySkillExtras, getSkillFilesRoot } from './skill-files.js';
9
+ export { toolSupportsSkills, getSkillCapableTools, hasGlobalSkillTarget, resolveToolSkillsDir, } from './skill-paths.js';
10
+ export { resolveIdeRestartSurface, formatIdeRestart, } from './ide-restart.js';
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Returns whether a legacy Codex skill differs from the current canonical
3
+ * replacement only by generated version, checkout line endings/BOM, or the
4
+ * known Codex/generic dual-reference expansion.
5
+ */
6
+ export declare function isLegacyCodexSkillEquivalentToCurrent(legacyContent: string, currentContent: string): boolean;
7
+ //# sourceMappingURL=skill-content-equivalence.d.ts.map
@@ -0,0 +1,45 @@
1
+ import { OPENSPEC_SKILL_NAMES } from '../config.js';
2
+ const GENERATED_VERSION = /^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-(?:(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
3
+ const OPENSPEC_SKILL_NAME_SET = new Set(OPENSPEC_SKILL_NAMES);
4
+ /**
5
+ * Normalizes checkout line endings and a valid generated version inside the
6
+ * YAML frontmatter. Free-form `generatedBy` text in the instructions remains
7
+ * material.
8
+ */
9
+ function normalizeGeneratedSkill(content) {
10
+ const normalized = content.replace(/^\uFEFF/, '').replace(/\r\n/g, '\n');
11
+ const frontmatter = normalized.match(/^---\n[\s\S]*?\n---(?:\n|$)/)?.[0];
12
+ if (!frontmatter)
13
+ return normalized;
14
+ // `[ \t]` rather than `\s` so a leading/trailing whitespace run can never
15
+ // cross a newline: an `m`-anchored `\s*` re-scans from every line start,
16
+ // which is quadratic on a whitespace-heavy frontmatter. YAML indentation is
17
+ // spaces and tabs only, so matching is unchanged.
18
+ const versionLine = /^([ \t]*generatedBy:[ \t]*)(?:"([^"\n]+)"|'([^'\n]+)'|([^\s"'#]+))[ \t]*$/m;
19
+ const normalizedFrontmatter = frontmatter.replace(versionLine, (line, prefix, doubleQuoted, singleQuoted, bare) => {
20
+ const version = doubleQuoted ?? singleQuoted ?? bare;
21
+ return version && GENERATED_VERSION.test(version)
22
+ ? `${prefix}"<generated-version>"`
23
+ : line;
24
+ });
25
+ return normalizedFrontmatter + normalized.slice(frontmatter.length);
26
+ }
27
+ /**
28
+ * Converts only known generated dual references in current Codex content back
29
+ * to the direct syntax used by legacy `.codex` output.
30
+ */
31
+ function toLegacyCodexReferences(content) {
32
+ return content.replace(/\$(freespec-[a-z0-9-]+) \(Codex\) or \/\1 \(other agents\)/g, (match, skillName) => OPENSPEC_SKILL_NAME_SET.has(skillName) ? `$${skillName}` : match);
33
+ }
34
+ /**
35
+ * Returns whether a legacy Codex skill differs from the current canonical
36
+ * replacement only by generated version, checkout line endings/BOM, or the
37
+ * known Codex/generic dual-reference expansion.
38
+ */
39
+ export function isLegacyCodexSkillEquivalentToCurrent(legacyContent, currentContent) {
40
+ const normalizedLegacy = normalizeGeneratedSkill(legacyContent);
41
+ const normalizedCurrent = normalizeGeneratedSkill(currentContent);
42
+ return (normalizedLegacy === normalizedCurrent ||
43
+ normalizedLegacy === toLegacyCodexReferences(normalizedCurrent));
44
+ }
45
+ //# sourceMappingURL=skill-content-equivalence.js.map
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Package-root folder of skill extras. From dist/core/shared this is
3
+ * <package>/skill-files. Init and update copy it next to each SKILL.md.
4
+ */
5
+ export declare function getSkillFilesRoot(): string;
6
+ export declare function copySkillExtras(skillDir: string, workflowId: string): Promise<void>;
7
+ //# sourceMappingURL=skill-files.d.ts.map
@@ -0,0 +1,43 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ const EXTRA_DIRS = ['references', 'config', 'scripts'];
5
+ /**
6
+ * Package-root folder of skill extras. From dist/core/shared this is
7
+ * <package>/skill-files. Init and update copy it next to each SKILL.md.
8
+ */
9
+ export function getSkillFilesRoot() {
10
+ const currentFile = fileURLToPath(import.meta.url);
11
+ return path.join(path.dirname(currentFile), '..', '..', '..', 'skill-files');
12
+ }
13
+ async function copyTree(source, target) {
14
+ await fs.promises.mkdir(target, { recursive: true });
15
+ const entries = await fs.promises.readdir(source, { withFileTypes: true });
16
+ for (const entry of entries) {
17
+ const from = path.join(source, entry.name);
18
+ const to = path.join(target, entry.name);
19
+ if (entry.isDirectory()) {
20
+ await copyTree(from, to);
21
+ }
22
+ else if (entry.isFile()) {
23
+ await fs.promises.copyFile(from, to);
24
+ }
25
+ }
26
+ }
27
+ export async function copySkillExtras(skillDir, workflowId) {
28
+ if (!/^[\u4e00-\u9fffA-Za-z0-9]+$/u.test(workflowId)) {
29
+ throw new Error(`Refusing to copy skill files for ${workflowId}`);
30
+ }
31
+ const sourceRoot = path.join(getSkillFilesRoot(), workflowId);
32
+ if (!fs.existsSync(sourceRoot))
33
+ return;
34
+ for (const name of EXTRA_DIRS) {
35
+ const source = path.join(sourceRoot, name);
36
+ if (!fs.existsSync(source))
37
+ continue;
38
+ const target = path.join(skillDir, name);
39
+ await fs.promises.rm(target, { recursive: true, force: true });
40
+ await copyTree(source, target);
41
+ }
42
+ }
43
+ //# sourceMappingURL=skill-files.js.map
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Skill Generation Utilities
3
+ *
4
+ * Shared utilities for generating skill and command files.
5
+ */
6
+ import type { SkillTemplate, CommandTemplate } from '../templates/types.js';
7
+ import type { CommandContent } from '../command-generation/index.js';
8
+ /**
9
+ * Skill template with directory name and workflow ID mapping.
10
+ */
11
+ export interface SkillTemplateEntry {
12
+ template: SkillTemplate;
13
+ dirName: string;
14
+ workflowId: string;
15
+ }
16
+ /**
17
+ * Command template with ID mapping.
18
+ */
19
+ export interface CommandTemplateEntry {
20
+ template: CommandTemplate;
21
+ id: string;
22
+ }
23
+ /**
24
+ * Gets skill templates with their directory names, optionally filtered by workflow IDs.
25
+ *
26
+ * @param workflowFilter - If provided, only return templates whose workflowId is in this array
27
+ */
28
+ export declare function getSkillTemplates(workflowFilter?: readonly string[]): SkillTemplateEntry[];
29
+ /**
30
+ * Gets command templates with their IDs, optionally filtered by workflow IDs.
31
+ *
32
+ * @param workflowFilter - If provided, only return templates whose id is in this array
33
+ */
34
+ export declare function getCommandTemplates(workflowFilter?: readonly string[]): CommandTemplateEntry[];
35
+ /**
36
+ * Converts command templates to CommandContent array, optionally filtered by workflow IDs.
37
+ *
38
+ * @param workflowFilter - If provided, only return contents whose id is in this array
39
+ */
40
+ export declare function getCommandContents(workflowFilter?: readonly string[]): CommandContent[];
41
+ /**
42
+ * Generates skill file content with YAML frontmatter.
43
+ *
44
+ * @param template - The skill template
45
+ * @param generatedByVersion - The FreeSpec version to embed in the file
46
+ * @param transformInstructions - Optional callback to transform the instructions content
47
+ */
48
+ export declare function generateSkillContent(template: SkillTemplate, generatedByVersion: string, transformInstructions?: (instructions: string) => string): string;
49
+ //# sourceMappingURL=skill-generation.d.ts.map
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Skill Generation Utilities
3
+ *
4
+ * Shared utilities for generating skill and command files.
5
+ */
6
+ import { getAskCommandTemplate, getAskSkillTemplate, getCasesCommandTemplate, getCasesSkillTemplate, getCheckCommandTemplate, getCheckSkillTemplate, getDesignCommandTemplate, getDesignSkillTemplate, getJavaImplCommandTemplate, getJavaImplSkillTemplate, getJavaReviewCommandTemplate, getJavaReviewSkillTemplate, getNewCommandTemplate, getNewSkillTemplate, getRequirementsCommandTemplate, getRequirementsSkillTemplate, getReviewDocsCommandTemplate, getReviewDocsSkillTemplate, getTasksCommandTemplate, getTasksSkillTemplate, } from '../templates/workflows/personal.js';
7
+ import { assertWorkflowConditionalsResolved, resolveOptionalWorkflows, } from '../templates/optional-workflow.js';
8
+ import { ALL_WORKFLOWS } from '../profiles.js';
9
+ import { OPENSPEC_CLI_ALLOWED_TOOLS } from './allowed-tools.js';
10
+ /**
11
+ * The workflow set a template body is rendered against.
12
+ *
13
+ * `workflowFilter` is both the list of workflows to install and the set a
14
+ * template may refer to, so resolving optional-workflow conditionals here —
15
+ * the one place every generation path (init, update, migration, the skills.sh
16
+ * distribution) already funnels through — keeps a reference to an uninstalled
17
+ * workflow out of every generated file (#1734, umbrella #919).
18
+ *
19
+ * With no filter, every workflow is installed (that is what an unfiltered call
20
+ * means), so the installed branch is kept.
21
+ */
22
+ function resolveInstalledWorkflows(workflowFilter) {
23
+ return new Set(workflowFilter ?? ALL_WORKFLOWS);
24
+ }
25
+ /**
26
+ * Gets skill templates with their directory names, optionally filtered by workflow IDs.
27
+ *
28
+ * @param workflowFilter - If provided, only return templates whose workflowId is in this array
29
+ */
30
+ export function getSkillTemplates(workflowFilter) {
31
+ const all = [
32
+ { template: getNewSkillTemplate(), dirName: 'freespec-新建', workflowId: '新建' },
33
+ { template: getAskSkillTemplate(), dirName: 'freespec-深思', workflowId: '深思' },
34
+ { template: getRequirementsSkillTemplate(), dirName: 'freespec-需求', workflowId: '需求' },
35
+ { template: getDesignSkillTemplate(), dirName: 'freespec-设计', workflowId: '设计' },
36
+ { template: getTasksSkillTemplate(), dirName: 'freespec-任务', workflowId: '任务' },
37
+ { template: getReviewDocsSkillTemplate(), dirName: 'freespec-审文档', workflowId: '审文档' },
38
+ { template: getCasesSkillTemplate(), dirName: 'freespec-用例', workflowId: '用例' },
39
+ { template: getCheckSkillTemplate(), dirName: 'freespec-验收', workflowId: '验收' },
40
+ { template: getJavaImplSkillTemplate(), dirName: 'freespec-写Java', workflowId: '写Java' },
41
+ { template: getJavaReviewSkillTemplate(), dirName: 'freespec-审Java', workflowId: '审Java' },
42
+ ];
43
+ const installed = resolveInstalledWorkflows(workflowFilter);
44
+ const selected = workflowFilter ? all.filter(entry => installed.has(entry.workflowId)) : all;
45
+ return selected.map(entry => ({
46
+ ...entry,
47
+ template: {
48
+ ...entry.template,
49
+ instructions: resolveOptionalWorkflows(entry.template.instructions, installed),
50
+ },
51
+ }));
52
+ }
53
+ /**
54
+ * Gets command templates with their IDs, optionally filtered by workflow IDs.
55
+ *
56
+ * @param workflowFilter - If provided, only return templates whose id is in this array
57
+ */
58
+ export function getCommandTemplates(workflowFilter) {
59
+ const all = [
60
+ { template: getNewCommandTemplate(), id: '新建' },
61
+ { template: getAskCommandTemplate(), id: '深思' },
62
+ { template: getRequirementsCommandTemplate(), id: '需求' },
63
+ { template: getDesignCommandTemplate(), id: '设计' },
64
+ { template: getTasksCommandTemplate(), id: '任务' },
65
+ { template: getReviewDocsCommandTemplate(), id: '审文档' },
66
+ { template: getCasesCommandTemplate(), id: '用例' },
67
+ { template: getCheckCommandTemplate(), id: '验收' },
68
+ { template: getJavaImplCommandTemplate(), id: '写Java' },
69
+ { template: getJavaReviewCommandTemplate(), id: '审Java' },
70
+ ];
71
+ const installed = resolveInstalledWorkflows(workflowFilter);
72
+ const selected = workflowFilter ? all.filter(entry => installed.has(entry.id)) : all;
73
+ return selected.map(entry => ({
74
+ ...entry,
75
+ template: {
76
+ ...entry.template,
77
+ content: resolveOptionalWorkflows(entry.template.content, installed),
78
+ },
79
+ }));
80
+ }
81
+ /**
82
+ * Converts command templates to CommandContent array, optionally filtered by workflow IDs.
83
+ *
84
+ * @param workflowFilter - If provided, only return contents whose id is in this array
85
+ */
86
+ export function getCommandContents(workflowFilter) {
87
+ const commandTemplates = getCommandTemplates(workflowFilter);
88
+ return commandTemplates.map(({ template, id }) => ({
89
+ id,
90
+ name: template.name,
91
+ description: template.description,
92
+ category: template.category,
93
+ tags: template.tags,
94
+ body: template.content,
95
+ }));
96
+ }
97
+ /**
98
+ * Generates skill file content with YAML frontmatter.
99
+ *
100
+ * @param template - The skill template
101
+ * @param generatedByVersion - The FreeSpec version to embed in the file
102
+ * @param transformInstructions - Optional callback to transform the instructions content
103
+ */
104
+ export function generateSkillContent(template, generatedByVersion, transformInstructions) {
105
+ const instructions = transformInstructions
106
+ ? transformInstructions(template.instructions)
107
+ : template.instructions;
108
+ assertWorkflowConditionalsResolved(instructions, `Skill '${template.name}' was generated without resolving its optional-workflow blocks`);
109
+ return `---
110
+ name: ${template.name}
111
+ description: ${template.description}
112
+ disable-model-invocation: true
113
+ allowed-tools: ${OPENSPEC_CLI_ALLOWED_TOOLS}
114
+ license: ${template.license || 'MIT'}
115
+ compatibility: ${template.compatibility || 'Requires freespec CLI.'}
116
+ metadata:
117
+ author: ${template.metadata?.author || 'freespec'}
118
+ version: "${template.metadata?.version || '1.0'}"
119
+ generatedBy: "${generatedByVersion}"
120
+ ---
121
+
122
+ ${instructions}
123
+ `;
124
+ }
125
+ //# sourceMappingURL=skill-generation.js.map
@@ -0,0 +1,13 @@
1
+ import { type AIToolOption } from '../config.js';
2
+ export type SkillCapableTool = AIToolOption & ({
3
+ skillsDir: string;
4
+ } | {
5
+ globalSkillsDir: string;
6
+ });
7
+ export declare function toolSupportsSkills(tool: AIToolOption): tool is SkillCapableTool;
8
+ export declare function getSkillCapableTools(): SkillCapableTool[];
9
+ export declare function hasGlobalSkillTarget(tool: AIToolOption): boolean;
10
+ export declare function resolveToolSkillsDir(projectRoot: string, tool: SkillCapableTool, options?: {
11
+ homeDir?: string;
12
+ }): string;
13
+ //# sourceMappingURL=skill-paths.d.ts.map