@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.
- package/.ospec/templates/hooks/post-merge +8 -0
- package/.ospec/templates/hooks/pre-commit +8 -0
- package/LICENSE +21 -0
- package/README.md +549 -0
- package/README.zh-CN.md +549 -0
- package/assets/for-ai/en-US/ai-guide.md +98 -0
- package/assets/for-ai/en-US/execution-protocol.md +64 -0
- package/assets/for-ai/zh-CN/ai-guide.md +102 -0
- package/assets/for-ai/zh-CN/execution-protocol.md +68 -0
- package/assets/git-hooks/post-merge +12 -0
- package/assets/git-hooks/pre-commit +12 -0
- package/assets/global-skills/claude/ospec-change/SKILL.md +116 -0
- package/assets/global-skills/codex/ospec-change/SKILL.md +117 -0
- package/assets/global-skills/codex/ospec-change/agents/openai.yaml +7 -0
- package/assets/global-skills/codex/ospec-change/skill.yaml +19 -0
- package/assets/project-conventions/en-US/development-guide.md +32 -0
- package/assets/project-conventions/en-US/naming-conventions.md +51 -0
- package/assets/project-conventions/en-US/skill-conventions.md +40 -0
- package/assets/project-conventions/en-US/workflow-conventions.md +70 -0
- package/assets/project-conventions/zh-CN/development-guide.md +32 -0
- package/assets/project-conventions/zh-CN/naming-conventions.md +51 -0
- package/assets/project-conventions/zh-CN/skill-conventions.md +40 -0
- package/assets/project-conventions/zh-CN/workflow-conventions.md +74 -0
- package/dist/adapters/codex-stitch-adapter.js +420 -0
- package/dist/adapters/gemini-stitch-adapter.js +408 -0
- package/dist/adapters/playwright-checkpoint-adapter.js +2260 -0
- package/dist/advanced/BatchOperations.d.ts +36 -0
- package/dist/advanced/BatchOperations.js +159 -0
- package/dist/advanced/CachingLayer.d.ts +66 -0
- package/dist/advanced/CachingLayer.js +136 -0
- package/dist/advanced/FeatureUpdater.d.ts +46 -0
- package/dist/advanced/FeatureUpdater.js +151 -0
- package/dist/advanced/PerformanceMonitor.d.ts +52 -0
- package/dist/advanced/PerformanceMonitor.js +129 -0
- package/dist/advanced/StatePersistence.d.ts +61 -0
- package/dist/advanced/StatePersistence.js +168 -0
- package/dist/advanced/index.d.ts +14 -0
- package/dist/advanced/index.js +22 -0
- package/dist/cli/commands/config.d.ts +5 -0
- package/dist/cli/commands/config.js +6 -0
- package/dist/cli/commands/feature.d.ts +5 -0
- package/dist/cli/commands/feature.js +6 -0
- package/dist/cli/commands/index.d.ts +5 -0
- package/dist/cli/commands/index.js +6 -0
- package/dist/cli/commands/project.d.ts +5 -0
- package/dist/cli/commands/project.js +6 -0
- package/dist/cli/commands/validate.d.ts +5 -0
- package/dist/cli/commands/validate.js +6 -0
- package/dist/cli/index.d.ts +5 -0
- package/dist/cli/index.js +6 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +1007 -0
- package/dist/commands/ArchiveCommand.d.ts +14 -0
- package/dist/commands/ArchiveCommand.js +241 -0
- package/dist/commands/BaseCommand.d.ts +33 -0
- package/dist/commands/BaseCommand.js +46 -0
- package/dist/commands/BatchCommand.d.ts +5 -0
- package/dist/commands/BatchCommand.js +42 -0
- package/dist/commands/ChangesCommand.d.ts +3 -0
- package/dist/commands/ChangesCommand.js +71 -0
- package/dist/commands/DocsCommand.d.ts +5 -0
- package/dist/commands/DocsCommand.js +118 -0
- package/dist/commands/FinalizeCommand.d.ts +3 -0
- package/dist/commands/FinalizeCommand.js +24 -0
- package/dist/commands/IndexCommand.d.ts +5 -0
- package/dist/commands/IndexCommand.js +57 -0
- package/dist/commands/InitCommand.d.ts +5 -0
- package/dist/commands/InitCommand.js +65 -0
- package/dist/commands/NewCommand.d.ts +11 -0
- package/dist/commands/NewCommand.js +262 -0
- package/dist/commands/PluginsCommand.d.ts +58 -0
- package/dist/commands/PluginsCommand.js +2491 -0
- package/dist/commands/ProgressCommand.d.ts +5 -0
- package/dist/commands/ProgressCommand.js +103 -0
- package/dist/commands/QueueCommand.d.ts +10 -0
- package/dist/commands/QueueCommand.js +147 -0
- package/dist/commands/RunCommand.d.ts +13 -0
- package/dist/commands/RunCommand.js +200 -0
- package/dist/commands/SkillCommand.d.ts +31 -0
- package/dist/commands/SkillCommand.js +1216 -0
- package/dist/commands/SkillsCommand.d.ts +5 -0
- package/dist/commands/SkillsCommand.js +68 -0
- package/dist/commands/StatusCommand.d.ts +6 -0
- package/dist/commands/StatusCommand.js +140 -0
- package/dist/commands/UpdateCommand.d.ts +8 -0
- package/dist/commands/UpdateCommand.js +251 -0
- package/dist/commands/VerifyCommand.d.ts +5 -0
- package/dist/commands/VerifyCommand.js +278 -0
- package/dist/commands/WorkflowCommand.d.ts +12 -0
- package/dist/commands/WorkflowCommand.js +150 -0
- package/dist/commands/index.d.ts +43 -0
- package/dist/commands/index.js +85 -0
- package/dist/core/constants.d.ts +41 -0
- package/dist/core/constants.js +73 -0
- package/dist/core/errors.d.ts +36 -0
- package/dist/core/errors.js +72 -0
- package/dist/core/index.d.ts +7 -0
- package/dist/core/index.js +23 -0
- package/dist/core/types.d.ts +369 -0
- package/dist/core/types.js +3 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +27 -0
- package/dist/presets/ProjectPresets.d.ts +41 -0
- package/dist/presets/ProjectPresets.js +190 -0
- package/dist/scaffolds/ProjectScaffoldPresets.d.ts +20 -0
- package/dist/scaffolds/ProjectScaffoldPresets.js +151 -0
- package/dist/services/ConfigManager.d.ts +14 -0
- package/dist/services/ConfigManager.js +386 -0
- package/dist/services/FeatureManager.d.ts +5 -0
- package/dist/services/FeatureManager.js +6 -0
- package/dist/services/FileService.d.ts +21 -0
- package/dist/services/FileService.js +152 -0
- package/dist/services/IndexBuilder.d.ts +12 -0
- package/dist/services/IndexBuilder.js +130 -0
- package/dist/services/Logger.d.ts +20 -0
- package/dist/services/Logger.js +48 -0
- package/dist/services/ProjectAssetRegistry.d.ts +12 -0
- package/dist/services/ProjectAssetRegistry.js +96 -0
- package/dist/services/ProjectAssetService.d.ts +49 -0
- package/dist/services/ProjectAssetService.js +223 -0
- package/dist/services/ProjectScaffoldCommandService.d.ts +73 -0
- package/dist/services/ProjectScaffoldCommandService.js +159 -0
- package/dist/services/ProjectScaffoldService.d.ts +44 -0
- package/dist/services/ProjectScaffoldService.js +507 -0
- package/dist/services/ProjectService.d.ts +209 -0
- package/dist/services/ProjectService.js +13239 -0
- package/dist/services/QueueService.d.ts +17 -0
- package/dist/services/QueueService.js +142 -0
- package/dist/services/RunService.d.ts +40 -0
- package/dist/services/RunService.js +420 -0
- package/dist/services/SkillParser.d.ts +30 -0
- package/dist/services/SkillParser.js +88 -0
- package/dist/services/StateManager.d.ts +16 -0
- package/dist/services/StateManager.js +127 -0
- package/dist/services/TemplateEngine.d.ts +43 -0
- package/dist/services/TemplateEngine.js +119 -0
- package/dist/services/TemplateGenerator.d.ts +40 -0
- package/dist/services/TemplateGenerator.js +273 -0
- package/dist/services/ValidationService.d.ts +19 -0
- package/dist/services/ValidationService.js +44 -0
- package/dist/services/Validator.d.ts +5 -0
- package/dist/services/Validator.js +6 -0
- package/dist/services/index.d.ts +52 -0
- package/dist/services/index.js +91 -0
- package/dist/services/templates/ExecutionTemplateBuilder.d.ts +12 -0
- package/dist/services/templates/ExecutionTemplateBuilder.js +300 -0
- package/dist/services/templates/ProjectTemplateBuilder.d.ts +38 -0
- package/dist/services/templates/ProjectTemplateBuilder.js +1897 -0
- package/dist/services/templates/TemplateBuilderBase.d.ts +19 -0
- package/dist/services/templates/TemplateBuilderBase.js +60 -0
- package/dist/services/templates/TemplateInputFactory.d.ts +16 -0
- package/dist/services/templates/TemplateInputFactory.js +298 -0
- package/dist/services/templates/templateTypes.d.ts +90 -0
- package/dist/services/templates/templateTypes.js +3 -0
- package/dist/tools/build-index.js +632 -0
- package/dist/utils/DateUtils.d.ts +18 -0
- package/dist/utils/DateUtils.js +40 -0
- package/dist/utils/PathUtils.d.ts +9 -0
- package/dist/utils/PathUtils.js +66 -0
- package/dist/utils/StringUtils.d.ts +26 -0
- package/dist/utils/StringUtils.js +47 -0
- package/dist/utils/helpers.d.ts +5 -0
- package/dist/utils/helpers.js +6 -0
- package/dist/utils/index.d.ts +7 -0
- package/dist/utils/index.js +23 -0
- package/dist/utils/logger.d.ts +5 -0
- package/dist/utils/logger.js +6 -0
- package/dist/utils/path.d.ts +5 -0
- package/dist/utils/path.js +6 -0
- package/dist/utils/subcommandHelp.d.ts +11 -0
- package/dist/utils/subcommandHelp.js +119 -0
- package/dist/workflow/ArchiveGate.d.ts +30 -0
- package/dist/workflow/ArchiveGate.js +93 -0
- package/dist/workflow/ConfigurableWorkflow.d.ts +89 -0
- package/dist/workflow/ConfigurableWorkflow.js +186 -0
- package/dist/workflow/HookSystem.d.ts +38 -0
- package/dist/workflow/HookSystem.js +66 -0
- package/dist/workflow/IndexRegenerator.d.ts +49 -0
- package/dist/workflow/IndexRegenerator.js +147 -0
- package/dist/workflow/PluginWorkflowComposer.d.ts +138 -0
- package/dist/workflow/PluginWorkflowComposer.js +239 -0
- package/dist/workflow/SkillUpdateEngine.d.ts +26 -0
- package/dist/workflow/SkillUpdateEngine.js +113 -0
- package/dist/workflow/VerificationSystem.d.ts +24 -0
- package/dist/workflow/VerificationSystem.js +116 -0
- package/dist/workflow/WorkflowEngine.d.ts +15 -0
- package/dist/workflow/WorkflowEngine.js +57 -0
- package/dist/workflow/index.d.ts +19 -0
- package/dist/workflow/index.js +32 -0
- package/package.json +78 -0
- 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
|