@clawplays/ospec-cli 0.1.1

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 (191) hide show
  1. package/.ospec/templates/hooks/post-merge +8 -0
  2. package/.ospec/templates/hooks/pre-commit +8 -0
  3. package/LICENSE +21 -0
  4. package/README.md +549 -0
  5. package/README.zh-CN.md +549 -0
  6. package/assets/for-ai/en-US/ai-guide.md +98 -0
  7. package/assets/for-ai/en-US/execution-protocol.md +64 -0
  8. package/assets/for-ai/zh-CN/ai-guide.md +102 -0
  9. package/assets/for-ai/zh-CN/execution-protocol.md +68 -0
  10. package/assets/git-hooks/post-merge +12 -0
  11. package/assets/git-hooks/pre-commit +12 -0
  12. package/assets/global-skills/claude/ospec-change/SKILL.md +116 -0
  13. package/assets/global-skills/codex/ospec-change/SKILL.md +117 -0
  14. package/assets/global-skills/codex/ospec-change/agents/openai.yaml +7 -0
  15. package/assets/global-skills/codex/ospec-change/skill.yaml +19 -0
  16. package/assets/project-conventions/en-US/development-guide.md +32 -0
  17. package/assets/project-conventions/en-US/naming-conventions.md +51 -0
  18. package/assets/project-conventions/en-US/skill-conventions.md +40 -0
  19. package/assets/project-conventions/en-US/workflow-conventions.md +70 -0
  20. package/assets/project-conventions/zh-CN/development-guide.md +32 -0
  21. package/assets/project-conventions/zh-CN/naming-conventions.md +51 -0
  22. package/assets/project-conventions/zh-CN/skill-conventions.md +40 -0
  23. package/assets/project-conventions/zh-CN/workflow-conventions.md +74 -0
  24. package/dist/adapters/codex-stitch-adapter.js +420 -0
  25. package/dist/adapters/gemini-stitch-adapter.js +408 -0
  26. package/dist/adapters/playwright-checkpoint-adapter.js +2260 -0
  27. package/dist/advanced/BatchOperations.d.ts +36 -0
  28. package/dist/advanced/BatchOperations.js +159 -0
  29. package/dist/advanced/CachingLayer.d.ts +66 -0
  30. package/dist/advanced/CachingLayer.js +136 -0
  31. package/dist/advanced/FeatureUpdater.d.ts +46 -0
  32. package/dist/advanced/FeatureUpdater.js +151 -0
  33. package/dist/advanced/PerformanceMonitor.d.ts +52 -0
  34. package/dist/advanced/PerformanceMonitor.js +129 -0
  35. package/dist/advanced/StatePersistence.d.ts +61 -0
  36. package/dist/advanced/StatePersistence.js +168 -0
  37. package/dist/advanced/index.d.ts +14 -0
  38. package/dist/advanced/index.js +22 -0
  39. package/dist/cli/commands/config.d.ts +5 -0
  40. package/dist/cli/commands/config.js +6 -0
  41. package/dist/cli/commands/feature.d.ts +5 -0
  42. package/dist/cli/commands/feature.js +6 -0
  43. package/dist/cli/commands/index.d.ts +5 -0
  44. package/dist/cli/commands/index.js +6 -0
  45. package/dist/cli/commands/project.d.ts +5 -0
  46. package/dist/cli/commands/project.js +6 -0
  47. package/dist/cli/commands/validate.d.ts +5 -0
  48. package/dist/cli/commands/validate.js +6 -0
  49. package/dist/cli/index.d.ts +5 -0
  50. package/dist/cli/index.js +6 -0
  51. package/dist/cli.d.ts +3 -0
  52. package/dist/cli.js +1007 -0
  53. package/dist/commands/ArchiveCommand.d.ts +14 -0
  54. package/dist/commands/ArchiveCommand.js +241 -0
  55. package/dist/commands/BaseCommand.d.ts +33 -0
  56. package/dist/commands/BaseCommand.js +46 -0
  57. package/dist/commands/BatchCommand.d.ts +5 -0
  58. package/dist/commands/BatchCommand.js +42 -0
  59. package/dist/commands/ChangesCommand.d.ts +3 -0
  60. package/dist/commands/ChangesCommand.js +71 -0
  61. package/dist/commands/DocsCommand.d.ts +5 -0
  62. package/dist/commands/DocsCommand.js +118 -0
  63. package/dist/commands/FinalizeCommand.d.ts +3 -0
  64. package/dist/commands/FinalizeCommand.js +24 -0
  65. package/dist/commands/IndexCommand.d.ts +5 -0
  66. package/dist/commands/IndexCommand.js +57 -0
  67. package/dist/commands/InitCommand.d.ts +5 -0
  68. package/dist/commands/InitCommand.js +65 -0
  69. package/dist/commands/NewCommand.d.ts +11 -0
  70. package/dist/commands/NewCommand.js +262 -0
  71. package/dist/commands/PluginsCommand.d.ts +58 -0
  72. package/dist/commands/PluginsCommand.js +2491 -0
  73. package/dist/commands/ProgressCommand.d.ts +5 -0
  74. package/dist/commands/ProgressCommand.js +103 -0
  75. package/dist/commands/QueueCommand.d.ts +10 -0
  76. package/dist/commands/QueueCommand.js +147 -0
  77. package/dist/commands/RunCommand.d.ts +13 -0
  78. package/dist/commands/RunCommand.js +200 -0
  79. package/dist/commands/SkillCommand.d.ts +31 -0
  80. package/dist/commands/SkillCommand.js +1216 -0
  81. package/dist/commands/SkillsCommand.d.ts +5 -0
  82. package/dist/commands/SkillsCommand.js +68 -0
  83. package/dist/commands/StatusCommand.d.ts +6 -0
  84. package/dist/commands/StatusCommand.js +140 -0
  85. package/dist/commands/UpdateCommand.d.ts +8 -0
  86. package/dist/commands/UpdateCommand.js +251 -0
  87. package/dist/commands/VerifyCommand.d.ts +5 -0
  88. package/dist/commands/VerifyCommand.js +278 -0
  89. package/dist/commands/WorkflowCommand.d.ts +12 -0
  90. package/dist/commands/WorkflowCommand.js +150 -0
  91. package/dist/commands/index.d.ts +43 -0
  92. package/dist/commands/index.js +85 -0
  93. package/dist/core/constants.d.ts +41 -0
  94. package/dist/core/constants.js +73 -0
  95. package/dist/core/errors.d.ts +36 -0
  96. package/dist/core/errors.js +72 -0
  97. package/dist/core/index.d.ts +7 -0
  98. package/dist/core/index.js +23 -0
  99. package/dist/core/types.d.ts +369 -0
  100. package/dist/core/types.js +3 -0
  101. package/dist/index.d.ts +11 -0
  102. package/dist/index.js +27 -0
  103. package/dist/presets/ProjectPresets.d.ts +41 -0
  104. package/dist/presets/ProjectPresets.js +190 -0
  105. package/dist/scaffolds/ProjectScaffoldPresets.d.ts +20 -0
  106. package/dist/scaffolds/ProjectScaffoldPresets.js +151 -0
  107. package/dist/services/ConfigManager.d.ts +14 -0
  108. package/dist/services/ConfigManager.js +386 -0
  109. package/dist/services/FeatureManager.d.ts +5 -0
  110. package/dist/services/FeatureManager.js +6 -0
  111. package/dist/services/FileService.d.ts +21 -0
  112. package/dist/services/FileService.js +152 -0
  113. package/dist/services/IndexBuilder.d.ts +12 -0
  114. package/dist/services/IndexBuilder.js +130 -0
  115. package/dist/services/Logger.d.ts +20 -0
  116. package/dist/services/Logger.js +48 -0
  117. package/dist/services/ProjectAssetRegistry.d.ts +12 -0
  118. package/dist/services/ProjectAssetRegistry.js +96 -0
  119. package/dist/services/ProjectAssetService.d.ts +49 -0
  120. package/dist/services/ProjectAssetService.js +223 -0
  121. package/dist/services/ProjectScaffoldCommandService.d.ts +73 -0
  122. package/dist/services/ProjectScaffoldCommandService.js +159 -0
  123. package/dist/services/ProjectScaffoldService.d.ts +44 -0
  124. package/dist/services/ProjectScaffoldService.js +507 -0
  125. package/dist/services/ProjectService.d.ts +209 -0
  126. package/dist/services/ProjectService.js +13239 -0
  127. package/dist/services/QueueService.d.ts +17 -0
  128. package/dist/services/QueueService.js +142 -0
  129. package/dist/services/RunService.d.ts +40 -0
  130. package/dist/services/RunService.js +420 -0
  131. package/dist/services/SkillParser.d.ts +30 -0
  132. package/dist/services/SkillParser.js +88 -0
  133. package/dist/services/StateManager.d.ts +16 -0
  134. package/dist/services/StateManager.js +127 -0
  135. package/dist/services/TemplateEngine.d.ts +43 -0
  136. package/dist/services/TemplateEngine.js +119 -0
  137. package/dist/services/TemplateGenerator.d.ts +40 -0
  138. package/dist/services/TemplateGenerator.js +273 -0
  139. package/dist/services/ValidationService.d.ts +19 -0
  140. package/dist/services/ValidationService.js +44 -0
  141. package/dist/services/Validator.d.ts +5 -0
  142. package/dist/services/Validator.js +6 -0
  143. package/dist/services/index.d.ts +52 -0
  144. package/dist/services/index.js +91 -0
  145. package/dist/services/templates/ExecutionTemplateBuilder.d.ts +12 -0
  146. package/dist/services/templates/ExecutionTemplateBuilder.js +300 -0
  147. package/dist/services/templates/ProjectTemplateBuilder.d.ts +38 -0
  148. package/dist/services/templates/ProjectTemplateBuilder.js +1897 -0
  149. package/dist/services/templates/TemplateBuilderBase.d.ts +19 -0
  150. package/dist/services/templates/TemplateBuilderBase.js +60 -0
  151. package/dist/services/templates/TemplateInputFactory.d.ts +16 -0
  152. package/dist/services/templates/TemplateInputFactory.js +298 -0
  153. package/dist/services/templates/templateTypes.d.ts +90 -0
  154. package/dist/services/templates/templateTypes.js +3 -0
  155. package/dist/tools/build-index.js +632 -0
  156. package/dist/utils/DateUtils.d.ts +18 -0
  157. package/dist/utils/DateUtils.js +40 -0
  158. package/dist/utils/PathUtils.d.ts +9 -0
  159. package/dist/utils/PathUtils.js +66 -0
  160. package/dist/utils/StringUtils.d.ts +26 -0
  161. package/dist/utils/StringUtils.js +47 -0
  162. package/dist/utils/helpers.d.ts +5 -0
  163. package/dist/utils/helpers.js +6 -0
  164. package/dist/utils/index.d.ts +7 -0
  165. package/dist/utils/index.js +23 -0
  166. package/dist/utils/logger.d.ts +5 -0
  167. package/dist/utils/logger.js +6 -0
  168. package/dist/utils/path.d.ts +5 -0
  169. package/dist/utils/path.js +6 -0
  170. package/dist/utils/subcommandHelp.d.ts +11 -0
  171. package/dist/utils/subcommandHelp.js +119 -0
  172. package/dist/workflow/ArchiveGate.d.ts +30 -0
  173. package/dist/workflow/ArchiveGate.js +93 -0
  174. package/dist/workflow/ConfigurableWorkflow.d.ts +89 -0
  175. package/dist/workflow/ConfigurableWorkflow.js +186 -0
  176. package/dist/workflow/HookSystem.d.ts +38 -0
  177. package/dist/workflow/HookSystem.js +66 -0
  178. package/dist/workflow/IndexRegenerator.d.ts +49 -0
  179. package/dist/workflow/IndexRegenerator.js +147 -0
  180. package/dist/workflow/PluginWorkflowComposer.d.ts +138 -0
  181. package/dist/workflow/PluginWorkflowComposer.js +239 -0
  182. package/dist/workflow/SkillUpdateEngine.d.ts +26 -0
  183. package/dist/workflow/SkillUpdateEngine.js +113 -0
  184. package/dist/workflow/VerificationSystem.d.ts +24 -0
  185. package/dist/workflow/VerificationSystem.js +116 -0
  186. package/dist/workflow/WorkflowEngine.d.ts +15 -0
  187. package/dist/workflow/WorkflowEngine.js +57 -0
  188. package/dist/workflow/index.d.ts +19 -0
  189. package/dist/workflow/index.js +32 -0
  190. package/package.json +78 -0
  191. package/scripts/postinstall.js +43 -0
@@ -0,0 +1,1216 @@
1
+ "use strict";
2
+
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+
5
+ return (mod && mod.__esModule) ? mod : { "default": mod };
6
+
7
+ };
8
+
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+
11
+ exports.SkillCommand = void 0;
12
+
13
+ const os_1 = __importDefault(require("os"));
14
+
15
+ const path_1 = __importDefault(require("path"));
16
+
17
+ const services_1 = require("../services");
18
+
19
+ const subcommandHelp_1 = require("../utils/subcommandHelp");
20
+
21
+ const BaseCommand_1 = require("./BaseCommand");
22
+
23
+ const ACTION_SKILLS = [
24
+
25
+ {
26
+
27
+ name: 'ospec-init',
28
+
29
+ title: 'OSpec Init',
30
+
31
+ description: 'Initialize the OSpec protocol shell for a directory without assuming stack templates or creating the first change.',
32
+
33
+ shortDescription: 'Initialize OSpec protocol shell',
34
+
35
+ defaultPrompt: 'Use $ospec-init to inspect the target directory, run ospec status first, initialize the protocol shell with ospec init when needed, and verify the protocol-shell files on disk. Do not create docs backfill, business scaffold, or the first change automatically.',
36
+
37
+ markdown: `# OSpec Init
38
+
39
+
40
+
41
+ Use this action when the user intent is initialization.
42
+
43
+
44
+
45
+ ## Guardrails
46
+
47
+
48
+
49
+ - run \`ospec status [path]\` first
50
+
51
+ - use \`ospec init [path]\` for plain initialization
52
+
53
+ - verify \`.skillrc\`, \`.ospec/\`, \`changes/\`, \`SKILL.md\`, \`SKILL.index.json\`, \`build-index-auto.cjs\`, and \`for-ai/\` files on disk
54
+
55
+ - do not assume a web template when the project type is unclear
56
+
57
+ - do not backfill docs or create the first change unless explicitly requested
58
+
59
+
60
+
61
+ ## Commands
62
+
63
+
64
+
65
+ \`\`\`bash
66
+
67
+ ospec status [path]
68
+
69
+ ospec init [path]
70
+
71
+ \`\`\`
72
+
73
+ `,
74
+
75
+ },
76
+
77
+ {
78
+
79
+ name: 'ospec-inspect',
80
+
81
+ title: 'OSpec Inspect',
82
+
83
+ description: 'Inspect an existing repository to determine OSpec initialization level, docs coverage, skills coverage, and active change posture.',
84
+
85
+ shortDescription: 'Inspect OSpec project state',
86
+
87
+ defaultPrompt: 'Use $ospec-inspect to inspect the current repository state with ospec status, ospec docs status, ospec skills status, and ospec changes status. Prefer diagnosis before mutation.',
88
+
89
+ markdown: `# OSpec Inspect
90
+
91
+
92
+
93
+ Use this action when the user wants to understand current project posture before changing anything.
94
+
95
+
96
+
97
+ ## Commands
98
+
99
+
100
+
101
+ \`\`\`bash
102
+
103
+ ospec status [path]
104
+
105
+ ospec docs status [path]
106
+
107
+ ospec skills status [path]
108
+
109
+ ospec changes status [path]
110
+
111
+ \`\`\`
112
+
113
+
114
+
115
+ ## Rules
116
+
117
+
118
+
119
+ - prefer inspection before initialization or backfill
120
+
121
+ - call out whether the repo is initialized and whether project knowledge docs are complete
122
+
123
+ `,
124
+
125
+ },
126
+
127
+ {
128
+
129
+ name: 'ospec-backfill',
130
+
131
+ title: 'OSpec Backfill',
132
+
133
+ description: 'Backfill the project knowledge layer after protocol-shell init without applying business scaffold or creating a change.',
134
+
135
+ shortDescription: 'Backfill project knowledge layer',
136
+
137
+ defaultPrompt: 'Use $ospec-backfill to backfill the project knowledge layer after protocol-shell init. Prefer ospec docs generate, keep scaffold explicit, and do not create the first change automatically.',
138
+
139
+ markdown: `# OSpec Backfill
140
+
141
+
142
+
143
+ Use this action after the protocol shell already exists and the repository still lacks project knowledge.
144
+
145
+
146
+
147
+ ## Guardrails
148
+
149
+
150
+
151
+ - require the protocol shell first
152
+
153
+ - prefer \`ospec docs generate [path]\`
154
+
155
+ - do not apply business scaffold during docs backfill
156
+
157
+ - do not generate \`docs/project/bootstrap-summary.md\`
158
+
159
+ - do not create a change unless explicitly requested
160
+
161
+
162
+
163
+ ## Commands
164
+
165
+
166
+
167
+ \`\`\`bash
168
+
169
+ ospec docs status [path]
170
+
171
+ ospec docs generate [path]
172
+
173
+ ospec skills status [path]
174
+
175
+ ospec index check [path]
176
+
177
+ \`\`\`
178
+
179
+ `,
180
+
181
+ },
182
+
183
+ {
184
+
185
+ name: 'ospec-change',
186
+
187
+ title: 'OSpec Change',
188
+
189
+ description: 'Create or advance an active change inside an OSpec project while respecting workflow files and optional-step activation.',
190
+
191
+ shortDescription: 'Create or advance a change',
192
+
193
+ defaultPrompt: 'Use $ospec-change to handle a requirement through the full OSpec change lifecycle. Inspect project state first, read the project-adopted for-ai guidance before writing, preserve the project document language already established in for-ai and existing change files, and work inside changes/active/<change>. Default to one active change and do not enter queue mode unless the user explicitly asks to split work into multiple changes, create a queue, or execute a queue. When queue behavior is explicitly requested, derive an ordered kebab-case list of change names, use ospec queue add to create queued changes, and use ospec run manual-safe only when the user explicitly asks to run the queue. Use verify, archive-check, or finalize for closeout. If Stitch installation, provider switching, doctor remediation, MCP setup, or auth setup is involved, read the repo-local Stitch plugin spec first and use its documented config snippet instead of inventing a replacement. If that spec is missing, use these built-in baselines: Gemini uses %USERPROFILE%/.gemini/settings.json with mcpServers.stitch.httpUrl and headers.X-Goog-Api-Key; Codex uses %USERPROFILE%/.codex/config.toml with [mcp_servers.stitch], type="http", url="https://stitch.googleapis.com/mcp", and X-Goog-Api-Key in headers or [mcp_servers.stitch.http_headers].',
194
+
195
+ markdown: `# OSpec Change
196
+
197
+
198
+
199
+ Use this skill when the user says things like "use ospec change to do a requirement".
200
+
201
+
202
+
203
+ ## Scope
204
+
205
+
206
+
207
+ This skill is the single entry for the full change lifecycle inside an initialized OSpec project:
208
+
209
+ - requirement intake
210
+
211
+ - change naming or matching
212
+
213
+ - proposal and task refinement
214
+
215
+ - implementation guidance
216
+
217
+ - progress tracking
218
+
219
+ - verification
220
+
221
+ - archive readiness check
222
+
223
+ - finalize closeout
224
+
225
+
226
+
227
+ ## Read Order
228
+
229
+
230
+
231
+ 1. \`.skillrc\`
232
+
233
+ 2. \`SKILL.index.json\`
234
+
235
+ 3. \`for-ai/ai-guide.md\`
236
+
237
+ 4. \`for-ai/execution-protocol.md\`
238
+
239
+ 5. \`changes/active/<change>/proposal.md\`
240
+
241
+ 6. \`changes/active/<change>/tasks.md\`
242
+
243
+ 7. \`changes/active/<change>/state.json\`
244
+
245
+ 8. \`changes/active/<change>/verification.md\`
246
+
247
+ 9. \`changes/active/<change>/review.md\`
248
+
249
+
250
+
251
+ ## Language
252
+
253
+
254
+
255
+ - Follow the project-adopted document language from \`for-ai/\` and existing change docs.
256
+
257
+ - Keep Chinese projects in Chinese unless the repo explicitly adopts English.
258
+
259
+
260
+
261
+ ## Required Logic
262
+
263
+
264
+
265
+ 1. Inspect repository state first when posture is unclear.
266
+
267
+ 2. If the repo is not initialized, stop at initialization guidance instead of forcing a change.
268
+
269
+ 3. If the request is a new requirement, derive a concise kebab-case change name and create it.
270
+
271
+ 4. If the matching active change already exists, continue it instead of duplicating it.
272
+
273
+ 5. Treat \`changes/active/<change>/\` as the execution container.
274
+
275
+ 6. Keep \`proposal.md\`, \`tasks.md\`, \`state.json\`, \`verification.md\`, and \`review.md\` aligned with actual execution and with the project's established document language.
276
+
277
+ 7. Use OSpec closeout commands instead of inventing a parallel process.
278
+
279
+
280
+
281
+ ## Commands
282
+
283
+
284
+
285
+ \`\`\`bash
286
+
287
+ ospec status [path]
288
+
289
+ ospec new <change-name> [path]
290
+
291
+ ospec changes status [path]
292
+
293
+ ospec progress [changes/active/<change>]
294
+
295
+ ospec verify [changes/active/<change>]
296
+
297
+ ospec archive [changes/active/<change>] --check
298
+
299
+ ospec finalize [changes/active/<change>]
300
+
301
+ \`\`\`
302
+
303
+
304
+
305
+ ## Guardrails
306
+
307
+
308
+
309
+ - Do not assume dashboard workflows exist.
310
+
311
+ - Do not refer to \`basic\` or \`full\` structure levels.
312
+
313
+ - Do not confuse repository initialization with change execution.
314
+
315
+ - Do not claim completion until implementation, verification notes, and closeout status are aligned.
316
+
317
+ - If real project tests exist, run or recommend them separately from \`ospec verify\`.
318
+
319
+ `,
320
+
321
+ },
322
+
323
+ {
324
+
325
+ name: 'ospec-verify',
326
+
327
+ title: 'OSpec Verify',
328
+
329
+ description: 'Verify a OSpec change and inspect aggregated PASS/WARN/FAIL status across all active changes before commit or archive.',
330
+
331
+ shortDescription: 'Verify changes and summaries',
332
+
333
+ defaultPrompt: 'Use $ospec-verify to verify change protocol completeness with ospec verify and ospec changes status. Highlight PASS, WARN, and FAIL items before archive or commit.',
334
+
335
+ markdown: `# OSpec Verify
336
+
337
+
338
+
339
+ Use this action when validating delivery readiness.
340
+
341
+
342
+
343
+ ## Commands
344
+
345
+
346
+
347
+ \`\`\`bash
348
+
349
+ ospec verify [changes/active/<change>]
350
+
351
+ ospec changes status [path]
352
+
353
+ ospec index check [path]
354
+
355
+ \`\`\`
356
+
357
+
358
+
359
+ ## Rules
360
+
361
+
362
+
363
+ - show PASS, WARN, and FAIL clearly
364
+
365
+ - incomplete checklists are warnings
366
+
367
+ - missing protocol files or optional-step coverage are failures
368
+
369
+ `,
370
+
371
+ },
372
+
373
+ {
374
+
375
+ name: 'ospec-archive',
376
+
377
+ title: 'OSpec Archive',
378
+
379
+ description: 'Archive a completed OSpec change after checking workflow gates, and support an explicit check-only mode when needed.',
380
+
381
+ shortDescription: 'Archive a completed change',
382
+
383
+ defaultPrompt: 'Use $ospec-archive to archive a completed OSpec change. Check readiness first, then run ospec archive on the active change path. If you only need a dry check, use ospec archive --check.',
384
+
385
+ markdown: `# OSpec Archive
386
+
387
+
388
+
389
+ Use this action when a change is complete and should be archived before commit.
390
+
391
+
392
+
393
+ ## Commands
394
+
395
+
396
+
397
+ \`\`\`bash
398
+
399
+ ospec archive [changes/active/<change>]
400
+
401
+ ospec archive [changes/active/<change>] --check
402
+
403
+ ospec verify [changes/active/<change>]
404
+
405
+ ospec changes status [path]
406
+
407
+ \`\`\`
408
+
409
+
410
+
411
+ ## Rules
412
+
413
+
414
+
415
+ - state.json.status must be \`ready_to_archive\`
416
+
417
+ - verification and optional-step coverage must already be complete
418
+
419
+ - archive before commit; do not expect commit to archive automatically
420
+
421
+ - use \`--check\` only when you want readiness output without executing archive
422
+
423
+ `,
424
+
425
+ },
426
+
427
+ {
428
+
429
+ name: 'ospec-finalize',
430
+
431
+ title: 'OSpec Finalize',
432
+
433
+ description: 'Run the standard change closeout flow, verify protocol completeness, refresh the index, and archive the completed change before commit.',
434
+
435
+ shortDescription: 'Finalize a completed change',
436
+
437
+ defaultPrompt: 'Use $ospec-finalize to close a completed OSpec change. Run the preflight verification, rebuild the index, move the change through archive, and leave the repository ready for manual commit.',
438
+
439
+ markdown: `# OSpec Finalize
440
+
441
+
442
+
443
+ Use this action when implementation is complete and the change should be closed before commit.
444
+
445
+
446
+
447
+ ## Commands
448
+
449
+
450
+
451
+ \`\`\`bash
452
+
453
+ ospec finalize [changes/active/<change>]
454
+
455
+ ospec changes status [path]
456
+
457
+ \`\`\`
458
+
459
+
460
+
461
+ ## Rules
462
+
463
+
464
+
465
+ - finalize is the default closeout path for a completed change
466
+
467
+ - it should verify protocol completeness before archive
468
+
469
+ - it should archive before commit
470
+
471
+ - Git commit remains manual unless the project explicitly adds optional automation
472
+
473
+ `,
474
+
475
+ },
476
+
477
+ ];
478
+
479
+ class SkillCommand extends BaseCommand_1.BaseCommand {
480
+
481
+ async execute(action = 'status', skillNameOrTargetDir, targetDir) {
482
+
483
+ try {
484
+
485
+ if ((0, subcommandHelp_1.isHelpAction)(action)) {
486
+
487
+ this.info((0, subcommandHelp_1.getSkillHelpText)());
488
+
489
+ return;
490
+
491
+ }
492
+
493
+ const { provider, verb } = this.resolveAction(action);
494
+ const selection = this.resolveSkillSelection(skillNameOrTargetDir, targetDir);
495
+
496
+ switch (verb) {
497
+
498
+ case 'install': {
499
+
500
+ const result = await this.installSkill(provider, selection.skillName, selection.targetDir);
501
+
502
+ this.success(`Installed ospec ${result.providerLabel} skill: ${result.skillName}`);
503
+ this.info(` target: ${result.targetDir}`);
504
+
505
+ break;
506
+
507
+ }
508
+
509
+ case 'status': {
510
+
511
+ const result = await this.getInstalledSkillStatus(provider, selection.skillName, selection.targetDir);
512
+
513
+ console.log(`\n${result.providerLabel} Skill Status`);
514
+
515
+ console.log(`${'='.repeat(`${result.providerLabel} Skill Status`.length)}\n`);
516
+
517
+ console.log(`Skill: ${result.skillName}`);
518
+ console.log(`Target: ${result.targetDir}`);
519
+ console.log(`In sync: ${result.inSync ? 'yes' : 'no'}`);
520
+
521
+ for (const asset of result.assets) {
522
+
523
+ console.log(` ${asset.relativePath}: ${asset.exists ? 'present' : 'missing'}`);
524
+
525
+ }
526
+
527
+ if (result.missingFiles.length > 0) {
528
+
529
+ console.log('\nMissing files:');
530
+
531
+ for (const item of result.missingFiles) {
532
+
533
+ console.log(` - ${item}`);
534
+
535
+ }
536
+
537
+ }
538
+
539
+ if (result.driftedFiles.length > 0) {
540
+
541
+ console.log('\nOut-of-sync files:');
542
+
543
+ for (const item of result.driftedFiles) {
544
+
545
+ console.log(` - ${item}`);
546
+
547
+ }
548
+
549
+ }
550
+
551
+ if (!result.inSync) {
552
+
553
+ console.log(`\nRecommendation: run "ospec skill ${this.getInstallAction(provider)} ${result.skillName}${selection.targetDir ? ` ${selection.targetDir}` : ''}" to sync this skill.`);
554
+
555
+ }
556
+
557
+ console.log('');
558
+
559
+ break;
560
+
561
+ }
562
+
563
+ }
564
+
565
+ }
566
+
567
+ catch (error) {
568
+
569
+ this.error(`Skill command failed: ${error}`);
570
+
571
+ throw error;
572
+
573
+ }
574
+
575
+ }
576
+
577
+ resolveAction(action) {
578
+
579
+ switch (action) {
580
+
581
+ case 'install':
582
+
583
+ return { provider: 'codex', verb: 'install' };
584
+
585
+ case 'status':
586
+
587
+ return { provider: 'codex', verb: 'status' };
588
+
589
+ case 'install-claude':
590
+
591
+ return { provider: 'claude', verb: 'install' };
592
+
593
+ case 'status-claude':
594
+
595
+ return { provider: 'claude', verb: 'status' };
596
+
597
+ default:
598
+
599
+ throw new Error(`Unknown skill action: ${action}`);
600
+
601
+ }
602
+
603
+ }
604
+
605
+ getInstallAction(provider) {
606
+
607
+ return provider === 'claude' ? 'install-claude' : 'install';
608
+
609
+ }
610
+
611
+ resolveSkillSelection(skillNameOrTargetDir, targetDir) {
612
+
613
+ const first = String(skillNameOrTargetDir || '').trim();
614
+ const second = String(targetDir || '').trim();
615
+
616
+ if (second && !this.isKnownSkillName(first)) {
617
+
618
+ throw new Error(`Unknown skill name: ${first}`);
619
+
620
+ }
621
+
622
+ if (first && this.isKnownSkillName(first)) {
623
+
624
+ return {
625
+
626
+ skillName: first,
627
+
628
+ targetDir: second || undefined,
629
+
630
+ };
631
+
632
+ }
633
+
634
+ if (first && !second && first.startsWith('ospec')) {
635
+
636
+ throw new Error(`Unknown skill name: ${first}`);
637
+
638
+ }
639
+
640
+ return {
641
+
642
+ skillName: 'ospec-change',
643
+
644
+ targetDir: first || undefined,
645
+
646
+ };
647
+
648
+ }
649
+
650
+ isKnownSkillName(skillName) {
651
+
652
+ return this.getAvailableSkillNames().includes(skillName);
653
+
654
+ }
655
+
656
+ getAvailableSkillNames() {
657
+
658
+ return ['ospec', ...ACTION_SKILLS.map(skill => skill.name), 'ospec-cli'];
659
+
660
+ }
661
+
662
+ async installSkill(provider, skillName, targetDir) {
663
+
664
+ const skillPackage = await this.buildSkillPackage(provider, skillName, targetDir);
665
+
666
+ await this.syncSkillFiles(skillPackage.assets, skillPackage.targetDir);
667
+
668
+ return this.getInstalledSkillStatus(provider, skillName, targetDir);
669
+
670
+ }
671
+
672
+ async getInstalledSkillStatus(provider, skillName, targetDir) {
673
+
674
+ const skillPackage = await this.buildSkillPackage(provider, skillName, targetDir);
675
+
676
+ const assets = await Promise.all(skillPackage.assets.map(async (asset) => {
677
+
678
+ const absolutePath = path_1.default.join(skillPackage.targetDir, asset.relativePath);
679
+
680
+ const exists = await services_1.services.fileService.exists(absolutePath);
681
+
682
+ const inSync = exists && (await services_1.services.fileService.readFile(absolutePath)) === asset.content;
683
+
684
+ return {
685
+
686
+ relativePath: asset.relativePath,
687
+
688
+ absolutePath,
689
+
690
+ exists,
691
+
692
+ inSync,
693
+
694
+ };
695
+
696
+ }));
697
+
698
+ return {
699
+
700
+ provider,
701
+
702
+ providerLabel: provider === 'claude' ? 'Claude Code' : 'Codex',
703
+
704
+ skillName,
705
+
706
+ targetDir: skillPackage.targetDir,
707
+
708
+ assets,
709
+
710
+ inSync: assets.every(asset => asset.inSync),
711
+
712
+ missingFiles: assets.filter(asset => !asset.exists).map(asset => asset.absolutePath),
713
+
714
+ driftedFiles: assets.filter(asset => asset.exists && !asset.inSync).map(asset => asset.absolutePath),
715
+
716
+ };
717
+
718
+ }
719
+
720
+ async buildSkillPackage(provider, skillName, targetDir) {
721
+
722
+ const resolvedTargetDir = this.resolveTargetDir(provider, skillName, targetDir);
723
+
724
+ if (skillName === 'ospec-cli') {
725
+
726
+ const compatibilityFiles = await this.buildLegacyAliasPackage(provider, resolvedTargetDir);
727
+
728
+ return {
729
+
730
+ name: 'ospec-cli',
731
+
732
+ targetDir: resolvedTargetDir,
733
+
734
+ assets: compatibilityFiles.assets,
735
+
736
+ };
737
+
738
+ }
739
+
740
+ const definition = await this.getSkillDefinition(skillName);
741
+
742
+ return {
743
+
744
+ name: definition.name,
745
+
746
+ targetDir: resolvedTargetDir,
747
+
748
+ assets: await this.buildPackageAssets(provider, definition),
749
+
750
+ };
751
+
752
+ }
753
+
754
+ async getSkillDefinition(skillName) {
755
+
756
+ if (skillName === 'ospec') {
757
+
758
+ return this.buildPrimarySkillDefinition();
759
+
760
+ }
761
+
762
+ const definition = ACTION_SKILLS.find(skill => skill.name === skillName);
763
+
764
+ if (!definition) {
765
+
766
+ throw new Error(`Unknown skill name: ${skillName}`);
767
+
768
+ }
769
+
770
+ return definition;
771
+
772
+ }
773
+
774
+ async buildPrimarySkillDefinition() {
775
+
776
+ const sourceFiles = this.resolvePrimarySourceFiles();
777
+
778
+ const sourceSkillMd = await services_1.services.fileService.readFile(sourceFiles.skillMdPath);
779
+
780
+ const sourceSkillYaml = await services_1.services.fileService.readFile(sourceFiles.skillYamlPath);
781
+
782
+ const sourceOpenaiYaml = await services_1.services.fileService.readFile(sourceFiles.openaiYamlPath);
783
+
784
+ return {
785
+
786
+ name: 'ospec',
787
+
788
+ title: 'OSpec',
789
+
790
+ description: 'Protocol-shell-first OSpec workflow for initialization, project knowledge backfill, change execution, verification, and archive readiness.',
791
+
792
+ shortDescription: 'Inspect, initialize, and operate OSpec projects',
793
+
794
+ defaultPrompt: this.extractInterfaceDefaultPrompt(sourceSkillYaml, sourceOpenaiYaml),
795
+
796
+ markdown: sourceSkillMd,
797
+
798
+ skillYaml: sourceSkillYaml,
799
+
800
+ openaiYaml: sourceOpenaiYaml,
801
+
802
+ };
803
+
804
+ }
805
+
806
+ async buildPackageAssets(provider, definition) {
807
+
808
+ if (provider === 'claude') {
809
+
810
+ return [
811
+
812
+ {
813
+
814
+ relativePath: 'SKILL.md',
815
+
816
+ content: this.withClaudeFrontmatter(definition.name, definition.description, this.stripFrontmatter(this.buildSkillMarkdown(definition))),
817
+
818
+ },
819
+
820
+ ];
821
+
822
+ }
823
+
824
+ return [
825
+
826
+ {
827
+
828
+ relativePath: 'SKILL.md',
829
+
830
+ content: this.buildSkillMarkdown(definition),
831
+
832
+ },
833
+
834
+ {
835
+
836
+ relativePath: 'skill.yaml',
837
+
838
+ content: definition.skillYaml || this.buildCodexSkillYaml(definition),
839
+
840
+ },
841
+
842
+ {
843
+
844
+ relativePath: 'agents/openai.yaml',
845
+
846
+ content: definition.openaiYaml || this.buildOpenAiYaml(definition),
847
+
848
+ },
849
+
850
+ ];
851
+
852
+ }
853
+
854
+ async buildLegacyAliasPackage(provider, targetDir) {
855
+
856
+ if (provider === 'claude') {
857
+
858
+ return {
859
+
860
+ targetDir,
861
+
862
+ assets: [
863
+
864
+ {
865
+
866
+ relativePath: 'SKILL.md',
867
+
868
+ content: this.withClaudeFrontmatter('ospec-cli', 'Legacy compatibility alias for the OSpec skill in Claude Code. Use when existing prompts, automation, or habits still refer to ospec-cli.', this.stripFrontmatter(this.buildCodexLegacyAliasFiles().skillMd)),
869
+
870
+ },
871
+
872
+ ],
873
+
874
+ };
875
+
876
+ }
877
+
878
+ const compatibilityFiles = this.buildCodexLegacyAliasFiles();
879
+
880
+ return {
881
+
882
+ targetDir,
883
+
884
+ assets: [
885
+
886
+ { relativePath: 'SKILL.md', content: compatibilityFiles.skillMd },
887
+
888
+ { relativePath: 'skill.yaml', content: compatibilityFiles.skillYaml },
889
+
890
+ { relativePath: 'agents/openai.yaml', content: compatibilityFiles.openaiYaml },
891
+
892
+ ],
893
+
894
+ };
895
+
896
+ }
897
+
898
+ async syncSkillFiles(assets, targetDir) {
899
+
900
+ await services_1.services.fileService.ensureDir(targetDir);
901
+
902
+ for (const asset of assets) {
903
+
904
+ const absolutePath = path_1.default.join(targetDir, asset.relativePath);
905
+
906
+ await services_1.services.fileService.ensureDir(path_1.default.dirname(absolutePath));
907
+
908
+ await services_1.services.fileService.writeFile(absolutePath, asset.content);
909
+
910
+ }
911
+
912
+ }
913
+
914
+ async isPackageInSync(assets, targetDir) {
915
+
916
+ for (const asset of assets) {
917
+
918
+ const absolutePath = path_1.default.join(targetDir, asset.relativePath);
919
+
920
+ if (!(await services_1.services.fileService.exists(absolutePath))) {
921
+
922
+ return false;
923
+
924
+ }
925
+
926
+ if ((await services_1.services.fileService.readFile(absolutePath)) !== asset.content) {
927
+
928
+ return false;
929
+
930
+ }
931
+
932
+ }
933
+
934
+ return true;
935
+
936
+ }
937
+
938
+ buildCodexSkillYaml(definition) {
939
+
940
+ return `name: ${definition.name}
941
+
942
+ title: ${definition.title}
943
+
944
+ description: ${definition.description}
945
+
946
+ version: 5.1.0
947
+
948
+ author: OSpec Team
949
+
950
+ license: MIT
951
+
952
+
953
+
954
+ interface:
955
+
956
+ display_name: "${definition.title}"
957
+
958
+ short_description: "${definition.shortDescription}"
959
+
960
+ default_prompt: "${this.escapeYaml(definition.defaultPrompt)}"
961
+
962
+ `;
963
+
964
+ }
965
+
966
+ buildOpenAiYaml(definition) {
967
+
968
+ return `interface:
969
+
970
+ display_name: "${definition.title}"
971
+
972
+ short_description: "${definition.shortDescription}"
973
+
974
+ default_prompt: "${this.escapeYaml(definition.defaultPrompt)}"
975
+
976
+ `;
977
+
978
+ }
979
+
980
+ resolvePackageRoot() {
981
+
982
+ return path_1.default.resolve(__dirname, '..', '..');
983
+
984
+ }
985
+
986
+ resolvePrimarySourceFiles() {
987
+
988
+ const packageRoot = this.resolvePackageRoot();
989
+
990
+ return {
991
+
992
+ skillMdPath: path_1.default.join(packageRoot, 'SKILL.md'),
993
+
994
+ skillYamlPath: path_1.default.join(packageRoot, 'skill.yaml'),
995
+
996
+ openaiYamlPath: path_1.default.join(packageRoot, 'agents', 'openai.yaml'),
997
+
998
+ };
999
+
1000
+ }
1001
+
1002
+ withClaudeFrontmatter(name, description, markdownBody) {
1003
+
1004
+ return `---
1005
+
1006
+ name: ${name}
1007
+
1008
+ description: ${description}
1009
+
1010
+ ---
1011
+
1012
+
1013
+
1014
+ ${markdownBody.trimStart()}`;
1015
+
1016
+ }
1017
+
1018
+ stripFrontmatter(markdown) {
1019
+
1020
+ return markdown.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/, '');
1021
+
1022
+ }
1023
+
1024
+ buildSkillMarkdown(definition) {
1025
+
1026
+ if (/^---\r?\n/.test(definition.markdown)) {
1027
+
1028
+ return definition.markdown;
1029
+
1030
+ }
1031
+
1032
+ return `---
1033
+
1034
+ name: ${definition.name}
1035
+
1036
+ description: ${definition.description}
1037
+
1038
+ tags: [ospec, cli, workflow]
1039
+
1040
+ ---
1041
+
1042
+
1043
+
1044
+ ${definition.markdown.trimStart()}`;
1045
+
1046
+ }
1047
+
1048
+ escapeYaml(value) {
1049
+
1050
+ return value.replace(/"/g, '\\"');
1051
+
1052
+ }
1053
+
1054
+ extractInterfaceDefaultPrompt(skillYaml, openaiYaml) {
1055
+
1056
+ const match = skillYaml.match(/default_prompt:\s*"([\s\S]*?)"/) ||
1057
+
1058
+ openaiYaml.match(/default_prompt:\s*"([\s\S]*?)"/);
1059
+
1060
+ return match?.[1]?.replace(/\\"/g, '"') || 'Use $ospec to operate this OSpec project.';
1061
+
1062
+ }
1063
+
1064
+ buildCodexLegacyAliasFiles() {
1065
+
1066
+ return {
1067
+
1068
+ skillMd: `---
1069
+
1070
+ name: ospec-cli
1071
+
1072
+ description: Legacy compatibility alias for the OSpec skill. Use when existing prompts, automation, or habits still refer to ospec-cli; follow the same OSpec workflow, but prefer the newer $ospec skill name in fresh prompts.
1073
+
1074
+ ---
1075
+
1076
+
1077
+
1078
+ # OSpec CLI Legacy Alias
1079
+
1080
+
1081
+
1082
+ This skill is a compatibility wrapper for the main \`ospec\` skill.
1083
+
1084
+
1085
+
1086
+ Prefer this prompt style for new work:
1087
+
1088
+
1089
+
1090
+ 1. \`Use ospec to initialize this directory\`
1091
+
1092
+ 2. \`Use ospec to inspect this repository\`
1093
+
1094
+ 3. \`Use ospec to backfill the project knowledge layer\`
1095
+
1096
+ 4. \`Use ospec to create and advance a change for this requirement\`
1097
+
1098
+
1099
+
1100
+ Always keep these guardrails:
1101
+
1102
+
1103
+
1104
+ - protocol shell first
1105
+
1106
+ - no assumed web template when the project type is unclear
1107
+
1108
+ - no business scaffold during plain init
1109
+
1110
+ - no automatic first change
1111
+
1112
+
1113
+
1114
+ Use the same command surface:
1115
+
1116
+
1117
+
1118
+ \`\`\`bash
1119
+
1120
+ ospec status [path]
1121
+
1122
+ ospec init [path]
1123
+
1124
+ ospec docs generate [path]
1125
+
1126
+ ospec changes status [path]
1127
+
1128
+ ospec skill status
1129
+
1130
+ ospec skill install
1131
+
1132
+ ospec skill status-claude
1133
+
1134
+ ospec skill install-claude
1135
+
1136
+ \`\`\`
1137
+
1138
+ `,
1139
+
1140
+ skillYaml: `name: ospec-cli
1141
+
1142
+ title: OSpec CLI (Legacy Alias)
1143
+
1144
+ description: Legacy compatibility alias that redirects ospec-cli skill usage to the newer ospec skill name.
1145
+
1146
+ version: 5.1.0
1147
+
1148
+ author: OSpec Team
1149
+
1150
+ license: MIT
1151
+
1152
+
1153
+
1154
+ interface:
1155
+
1156
+ display_name: "OSpec CLI"
1157
+
1158
+ short_description: "Legacy alias for the OSpec skill"
1159
+
1160
+ default_prompt: "Use $ospec to inspect and initialize this directory according to OSpec rules: protocol shell first, explicit knowledge backfill, no assumed web template when the project type is unclear, and no automatic first change."
1161
+
1162
+ `,
1163
+
1164
+ openaiYaml: `interface:
1165
+
1166
+ display_name: "OSpec CLI"
1167
+
1168
+ short_description: "Legacy alias for the OSpec skill"
1169
+
1170
+ default_prompt: "Use $ospec to inspect and initialize this directory according to OSpec rules: protocol shell first, explicit knowledge backfill, no assumed web template when the project type is unclear, and no automatic first change."
1171
+
1172
+ `,
1173
+
1174
+ };
1175
+
1176
+ }
1177
+
1178
+ resolveTargetDir(provider, skillName, targetDir) {
1179
+
1180
+ if (targetDir) {
1181
+
1182
+ return targetDir;
1183
+
1184
+ }
1185
+
1186
+ return path_1.default.join(this.resolveProviderHome(provider), 'skills', skillName);
1187
+
1188
+ }
1189
+
1190
+ resolveProviderHome(provider) {
1191
+
1192
+ const envHome = provider === 'claude'
1193
+
1194
+ ? String(process.env.CLAUDE_HOME || '').trim()
1195
+
1196
+ : String(process.env.CODEX_HOME || '').trim();
1197
+
1198
+ if (envHome) {
1199
+
1200
+ return path_1.default.resolve(envHome);
1201
+
1202
+ }
1203
+
1204
+ return provider === 'claude'
1205
+
1206
+ ? path_1.default.join(os_1.default.homedir(), '.claude')
1207
+
1208
+ : path_1.default.join(os_1.default.homedir(), '.codex');
1209
+
1210
+ }
1211
+
1212
+ }
1213
+
1214
+ exports.SkillCommand = SkillCommand;
1215
+
1216
+ //# sourceMappingURL=SkillCommand.js.map