@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,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SkillsCommand = void 0;
|
|
4
|
+
const services_1 = require("../services");
|
|
5
|
+
const subcommandHelp_1 = require("../utils/subcommandHelp");
|
|
6
|
+
const BaseCommand_1 = require("./BaseCommand");
|
|
7
|
+
class SkillsCommand extends BaseCommand_1.BaseCommand {
|
|
8
|
+
async execute(action = 'status', projectPath) {
|
|
9
|
+
try {
|
|
10
|
+
if ((0, subcommandHelp_1.isHelpAction)(action)) {
|
|
11
|
+
this.info((0, subcommandHelp_1.getSkillsHelpText)());
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
const targetPath = projectPath || process.cwd();
|
|
15
|
+
switch (action) {
|
|
16
|
+
case 'status': {
|
|
17
|
+
const skills = await services_1.services.projectService.getSkillsStatus(targetPath);
|
|
18
|
+
console.log('\nSkills Status');
|
|
19
|
+
console.log('=============\n');
|
|
20
|
+
console.log(`Skill files: ${skills.existing}/${skills.totalSkillFiles}`);
|
|
21
|
+
console.log(`Index: ${skills.skillIndex.exists ? 'present' : 'missing'}`);
|
|
22
|
+
console.log(`Index needs rebuild: ${skills.skillIndex.needsRebuild ? 'yes' : 'no'}`);
|
|
23
|
+
if (skills.skillIndex.updatedAt) {
|
|
24
|
+
console.log(`Index updated: ${skills.skillIndex.updatedAt}`);
|
|
25
|
+
}
|
|
26
|
+
if (skills.skillIndex.latestSourceUpdatedAt) {
|
|
27
|
+
console.log(`Latest skill update: ${skills.skillIndex.latestSourceUpdatedAt}`);
|
|
28
|
+
}
|
|
29
|
+
if (skills.skillIndex.stats) {
|
|
30
|
+
console.log(`Index stats: ${skills.skillIndex.stats.totalFiles} files, ${skills.skillIndex.stats.totalModules} modules, ${skills.skillIndex.stats.totalSections} sections`);
|
|
31
|
+
}
|
|
32
|
+
if (skills.skillIndex.reasons.length > 0) {
|
|
33
|
+
console.log('Index rebuild reasons:');
|
|
34
|
+
for (const reason of skills.skillIndex.reasons) {
|
|
35
|
+
console.log(` - ${reason}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
console.log('\nRoot skills:');
|
|
39
|
+
for (const skill of skills.rootSkills) {
|
|
40
|
+
console.log(` ${skill.exists ? '✓' : '✗'} ${skill.path}`);
|
|
41
|
+
}
|
|
42
|
+
if (skills.moduleSkills.length > 0) {
|
|
43
|
+
console.log('\nModule skills:');
|
|
44
|
+
for (const skill of skills.moduleSkills) {
|
|
45
|
+
console.log(` ${skill.exists ? '✓' : '✗'} ${skill.path}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (skills.missingRecommended.length > 0) {
|
|
49
|
+
console.log('\nMissing recommended skills:');
|
|
50
|
+
for (const item of skills.missingRecommended) {
|
|
51
|
+
console.log(` - ${item}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
console.log('');
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
default:
|
|
58
|
+
this.info((0, subcommandHelp_1.getSkillsHelpText)());
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
this.error(`Skills command failed: ${error}`);
|
|
63
|
+
throw error;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
exports.SkillsCommand = SkillsCommand;
|
|
68
|
+
//# sourceMappingURL=SkillsCommand.js.map
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StatusCommand = void 0;
|
|
4
|
+
const services_1 = require("../services");
|
|
5
|
+
const BaseCommand_1 = require("./BaseCommand");
|
|
6
|
+
class StatusCommand extends BaseCommand_1.BaseCommand {
|
|
7
|
+
async execute(projectPath) {
|
|
8
|
+
try {
|
|
9
|
+
const targetPath = projectPath || process.cwd();
|
|
10
|
+
this.logger.info(`Getting status for ${targetPath}`);
|
|
11
|
+
const [structure, summary, docs, skills, execution, changes, queuedChanges, runReport] = await Promise.all([
|
|
12
|
+
services_1.services.projectService.detectProjectStructure(targetPath),
|
|
13
|
+
services_1.services.projectService.getProjectSummary(targetPath),
|
|
14
|
+
services_1.services.projectService.getDocsStatus(targetPath),
|
|
15
|
+
services_1.services.projectService.getSkillsStatus(targetPath),
|
|
16
|
+
services_1.services.projectService.getExecutionStatus(targetPath),
|
|
17
|
+
services_1.services.projectService.getActiveChangeStatusReport(targetPath),
|
|
18
|
+
services_1.services.queueService.getQueuedChanges(targetPath),
|
|
19
|
+
services_1.services.runService.getStatusReport(targetPath),
|
|
20
|
+
]);
|
|
21
|
+
console.log('\nProject Status');
|
|
22
|
+
console.log('==============\n');
|
|
23
|
+
console.log(`Name: ${summary.name}`);
|
|
24
|
+
console.log(`Path: ${summary.path}`);
|
|
25
|
+
console.log(`Mode: ${summary.mode ?? 'uninitialized'}`);
|
|
26
|
+
console.log(`Initialized: ${summary.initialized ? 'yes' : 'no'}`);
|
|
27
|
+
console.log(`Structure Level: ${summary.structureLevel}`);
|
|
28
|
+
console.log(`Active Changes: ${summary.activeChangeCount}`);
|
|
29
|
+
console.log(`Queued Changes: ${queuedChanges.length}`);
|
|
30
|
+
console.log('\nStructure');
|
|
31
|
+
console.log('---------');
|
|
32
|
+
console.log(`Missing required: ${structure.missingRequired.length}`);
|
|
33
|
+
if (structure.missingRequired.length > 0) {
|
|
34
|
+
for (const item of structure.missingRequired) {
|
|
35
|
+
console.log(` - ${item}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
console.log(`Missing recommended: ${structure.missingRecommended.length}`);
|
|
39
|
+
if (structure.missingRecommended.length > 0) {
|
|
40
|
+
for (const item of structure.missingRecommended.slice(0, 10)) {
|
|
41
|
+
console.log(` - ${item}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
console.log('\nUpgrade suggestions:');
|
|
45
|
+
for (const suggestion of structure.upgradeSuggestions) {
|
|
46
|
+
console.log(` - ${suggestion.title}: ${suggestion.description}`);
|
|
47
|
+
for (const item of suggestion.paths.slice(0, 5)) {
|
|
48
|
+
console.log(` ${item}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
console.log('\nDocs');
|
|
52
|
+
console.log('----');
|
|
53
|
+
console.log(`Coverage: ${docs.coverage}% (${docs.existing}/${docs.total})`);
|
|
54
|
+
console.log(`Missing required docs: ${docs.missingRequired.length}`);
|
|
55
|
+
console.log('\nSkills');
|
|
56
|
+
console.log('------');
|
|
57
|
+
console.log(`Skill files: ${skills.existing}/${skills.totalSkillFiles}`);
|
|
58
|
+
console.log(`Skill index: ${skills.skillIndex.exists ? 'present' : 'missing'}`);
|
|
59
|
+
if (skills.skillIndex.stats) {
|
|
60
|
+
console.log(`Index stats: ${skills.skillIndex.stats.totalFiles} files, ${skills.skillIndex.stats.totalSections} sections`);
|
|
61
|
+
}
|
|
62
|
+
console.log('\nExecution');
|
|
63
|
+
console.log('---------');
|
|
64
|
+
console.log(`Active changes: ${execution.totalActiveChanges}`);
|
|
65
|
+
console.log(`Queued changes: ${queuedChanges.length}`);
|
|
66
|
+
for (const [status, count] of Object.entries(execution.byStatus)) {
|
|
67
|
+
console.log(` ${status}: ${count}`);
|
|
68
|
+
}
|
|
69
|
+
console.log(`Protocol summary: PASS ${changes.totals.pass} | WARN ${changes.totals.warn} | FAIL ${changes.totals.fail}`);
|
|
70
|
+
if (execution.activeChanges.length > 0) {
|
|
71
|
+
console.log('\nCurrent changes:');
|
|
72
|
+
for (const change of execution.activeChanges) {
|
|
73
|
+
console.log(` - ${change.name} [${change.status}] ${change.progress}%`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (queuedChanges.length > 0) {
|
|
77
|
+
console.log('\nQueued changes:');
|
|
78
|
+
for (const change of queuedChanges) {
|
|
79
|
+
console.log(` - ${change.name} [${change.status}]`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (runReport.currentRun) {
|
|
83
|
+
console.log('\nQueue Run');
|
|
84
|
+
console.log('---------');
|
|
85
|
+
console.log(`Status: ${runReport.currentRun.status}`);
|
|
86
|
+
console.log(`Profile: ${runReport.currentRun.profileId}`);
|
|
87
|
+
console.log(`Stage: ${runReport.stage ?? 'unknown'}`);
|
|
88
|
+
if (runReport.nextInstruction) {
|
|
89
|
+
console.log(`Next: ${runReport.nextInstruction}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
console.log('\nRecommended Next Step');
|
|
93
|
+
console.log('---------------------');
|
|
94
|
+
for (const step of this.getRecommendedNextSteps(targetPath, structure, docs, execution, queuedChanges, runReport)) {
|
|
95
|
+
console.log(` - ${step}`);
|
|
96
|
+
}
|
|
97
|
+
console.log('');
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
this.error(`Failed to get status: ${error}`);
|
|
101
|
+
throw error;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
getRecommendedNextSteps(projectPath, structure, docs, execution, queuedChanges, runReport) {
|
|
105
|
+
if (!structure.initialized) {
|
|
106
|
+
return [
|
|
107
|
+
`Run "ospec init ${projectPath}" to initialize the OSpec protocol shell.`,
|
|
108
|
+
];
|
|
109
|
+
}
|
|
110
|
+
if (docs.missingRequired.length > 0 || docs.coverage < 100) {
|
|
111
|
+
return [
|
|
112
|
+
'The OSpec protocol shell is ready, but the project knowledge layer is still incomplete.',
|
|
113
|
+
`Run "ospec docs generate ${projectPath}" to backfill the default project knowledge layer. This still will not apply business scaffold or generate docs/project/bootstrap-summary.md.`,
|
|
114
|
+
];
|
|
115
|
+
}
|
|
116
|
+
if (execution.totalActiveChanges === 0 && queuedChanges.length === 0) {
|
|
117
|
+
return [
|
|
118
|
+
`Or run "ospec new <change-name> ${projectPath}" if you want to create the first change from CLI.`,
|
|
119
|
+
];
|
|
120
|
+
}
|
|
121
|
+
if (execution.totalActiveChanges === 0 && queuedChanges.length > 0) {
|
|
122
|
+
return [
|
|
123
|
+
`There is no active change right now, but ${queuedChanges.length} queued change(s) are waiting.`,
|
|
124
|
+
`Run "ospec queue next ${projectPath}" if you want to activate the next queued change manually.`,
|
|
125
|
+
`Or run "ospec run start ${projectPath}" to begin explicit queue tracking.`,
|
|
126
|
+
];
|
|
127
|
+
}
|
|
128
|
+
const currentChange = execution.activeChanges[0];
|
|
129
|
+
const nextSteps = [
|
|
130
|
+
`Continue the active change "${currentChange.name}" with "ospec progress ${projectPath}/changes/active/${currentChange.name}".`,
|
|
131
|
+
`Run "ospec verify ${projectPath}/changes/active/${currentChange.name}" before trying to archive it.`,
|
|
132
|
+
];
|
|
133
|
+
if (queuedChanges.length > 0) {
|
|
134
|
+
nextSteps.push(`There are ${queuedChanges.length} queued change(s) waiting behind the active one. Use "ospec run ${runReport.currentRun ? 'step' : 'start'} ${projectPath}" when you want explicit queue progression.`);
|
|
135
|
+
}
|
|
136
|
+
return nextSteps;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
exports.StatusCommand = StatusCommand;
|
|
140
|
+
//# sourceMappingURL=StatusCommand.js.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { BaseCommand } from './BaseCommand';
|
|
2
|
+
export declare class UpdateCommand extends BaseCommand {
|
|
3
|
+
execute(rootDir?: string): Promise<void>;
|
|
4
|
+
private syncProjectTooling;
|
|
5
|
+
private syncInstalledSkills;
|
|
6
|
+
private shouldSyncClaudeSkills;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=UpdateCommand.d.ts.map
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.UpdateCommand = void 0;
|
|
4
|
+
const os_1 = require("os");
|
|
5
|
+
const path_1 = require("path");
|
|
6
|
+
const services_1 = require("../services");
|
|
7
|
+
const BaseCommand_1 = require("./BaseCommand");
|
|
8
|
+
const PluginsCommand_1 = require("./PluginsCommand");
|
|
9
|
+
const SkillCommand_1 = require("./SkillCommand");
|
|
10
|
+
class UpdateCommand extends BaseCommand_1.BaseCommand {
|
|
11
|
+
async execute(rootDir) {
|
|
12
|
+
const targetPath = rootDir ? (0, path_1.resolve)(rootDir) : process.cwd();
|
|
13
|
+
const structure = await services_1.services.projectService.detectProjectStructure(targetPath);
|
|
14
|
+
if (!structure.initialized) {
|
|
15
|
+
throw new Error('Project is not initialized. Run "ospec init" first.');
|
|
16
|
+
}
|
|
17
|
+
this.info(`Updating OSpec project at ${targetPath}`);
|
|
18
|
+
const protocolResult = await services_1.services.projectService.syncProtocolGuidance(targetPath);
|
|
19
|
+
const toolingResult = await this.syncProjectTooling(targetPath, protocolResult.documentLanguage);
|
|
20
|
+
const pluginResult = await this.syncEnabledPluginAssets(targetPath);
|
|
21
|
+
const skillResult = await this.syncInstalledSkills();
|
|
22
|
+
const refreshedFiles = [...protocolResult.refreshedFiles, ...toolingResult.refreshedFiles, ...pluginResult.refreshedFiles];
|
|
23
|
+
const createdFiles = [...protocolResult.createdFiles, ...toolingResult.createdFiles, ...pluginResult.createdFiles];
|
|
24
|
+
const skippedFiles = [...protocolResult.skippedFiles, ...toolingResult.skippedFiles, ...pluginResult.skippedFiles];
|
|
25
|
+
this.success(`Updated OSpec assets for ${protocolResult.projectName}`);
|
|
26
|
+
this.info(` document language: ${protocolResult.documentLanguage}`);
|
|
27
|
+
this.info(` created: ${createdFiles.length}`);
|
|
28
|
+
this.info(` refreshed: ${refreshedFiles.length}`);
|
|
29
|
+
this.info(` skipped: ${skippedFiles.length}`);
|
|
30
|
+
if (toolingResult.hookInstalledFiles.length > 0) {
|
|
31
|
+
this.info(` git hooks refreshed: ${toolingResult.hookInstalledFiles.join(', ')}`);
|
|
32
|
+
}
|
|
33
|
+
this.info(` codex skill: ${skillResult.codex.targetDir}`);
|
|
34
|
+
if (skillResult.claude) {
|
|
35
|
+
this.info(` claude skill: ${skillResult.claude.targetDir}`);
|
|
36
|
+
}
|
|
37
|
+
if (pluginResult.enabledPlugins.length > 0) {
|
|
38
|
+
this.info(` plugin assets refreshed: ${pluginResult.enabledPlugins.join(', ')}`);
|
|
39
|
+
}
|
|
40
|
+
if (pluginResult.configSaved) {
|
|
41
|
+
this.info(' plugin config normalized: .skillrc');
|
|
42
|
+
}
|
|
43
|
+
this.info(' note: update refreshes protocol docs, tooling, hooks, managed skills, and managed assets for already-enabled plugins');
|
|
44
|
+
this.info(' note: it does not enable, disable, or migrate existing changes automatically');
|
|
45
|
+
}
|
|
46
|
+
async syncProjectTooling(rootDir, documentLanguage) {
|
|
47
|
+
const toolingPaths = [
|
|
48
|
+
'build-index-auto.cjs',
|
|
49
|
+
'.ospec/templates/hooks/pre-commit',
|
|
50
|
+
'.ospec/templates/hooks/post-merge',
|
|
51
|
+
];
|
|
52
|
+
const directCopyResult = await services_1.services.projectAssetService.syncDirectCopyAssets(rootDir, documentLanguage, {
|
|
53
|
+
targetRelativePaths: toolingPaths,
|
|
54
|
+
});
|
|
55
|
+
const config = await services_1.services.configManager.loadConfig(rootDir);
|
|
56
|
+
const hookInstallResult = await services_1.services.projectAssetService.installGitHooks(rootDir, config.hooks);
|
|
57
|
+
return {
|
|
58
|
+
createdFiles: [...directCopyResult.created],
|
|
59
|
+
refreshedFiles: [...directCopyResult.refreshed],
|
|
60
|
+
skippedFiles: [...directCopyResult.skipped],
|
|
61
|
+
hookInstalledFiles: [...hookInstallResult.installed],
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
async syncEnabledPluginAssets(rootDir) {
|
|
65
|
+
const rawConfig = await services_1.services.fileService.readJSON((0, path_1.join)(rootDir, '.skillrc'));
|
|
66
|
+
const config = await services_1.services.configManager.loadConfig(rootDir);
|
|
67
|
+
const nextConfig = JSON.parse(JSON.stringify(config));
|
|
68
|
+
const pluginsCommand = new PluginsCommand_1.PluginsCommand();
|
|
69
|
+
const createdFiles = [];
|
|
70
|
+
const refreshedFiles = [];
|
|
71
|
+
const skippedFiles = [];
|
|
72
|
+
const enabledPlugins = [];
|
|
73
|
+
let configChanged = false;
|
|
74
|
+
const hasLegacyPluginKeys = Boolean(rawConfig?.plugins?.['stitch-gemini'] || rawConfig?.plugins?.['stitch-codex']);
|
|
75
|
+
if (nextConfig.plugins?.stitch?.enabled) {
|
|
76
|
+
enabledPlugins.push('stitch');
|
|
77
|
+
configChanged = this.normalizeEnabledStitchPlugin(nextConfig.plugins.stitch, pluginsCommand) || configChanged;
|
|
78
|
+
const stitchAssets = await this.ensureManagedPluginAssets(rootDir, [
|
|
79
|
+
'.ospec/plugins/stitch/project.json',
|
|
80
|
+
'.ospec/plugins/stitch/README.md',
|
|
81
|
+
'.ospec/plugins/stitch/exports/.gitkeep',
|
|
82
|
+
'.ospec/plugins/stitch/baselines/.gitkeep',
|
|
83
|
+
'.ospec/plugins/stitch/cache/.gitkeep',
|
|
84
|
+
], async () => {
|
|
85
|
+
await pluginsCommand.ensureStitchWorkspaceScaffold(rootDir, nextConfig.plugins.stitch);
|
|
86
|
+
});
|
|
87
|
+
createdFiles.push(...stitchAssets.createdFiles);
|
|
88
|
+
skippedFiles.push(...stitchAssets.skippedFiles);
|
|
89
|
+
}
|
|
90
|
+
if (nextConfig.plugins?.checkpoint?.enabled) {
|
|
91
|
+
enabledPlugins.push('checkpoint');
|
|
92
|
+
configChanged = this.normalizeEnabledCheckpointPlugin(nextConfig.plugins.checkpoint, pluginsCommand) || configChanged;
|
|
93
|
+
const checkpointAssets = await this.ensureManagedPluginAssets(rootDir, [
|
|
94
|
+
'.ospec/plugins/checkpoint/routes.yaml',
|
|
95
|
+
'.ospec/plugins/checkpoint/flows.yaml',
|
|
96
|
+
'.ospec/plugins/checkpoint/README.md',
|
|
97
|
+
'.ospec/plugins/checkpoint/baselines/.gitkeep',
|
|
98
|
+
'.ospec/plugins/checkpoint/auth/.gitkeep',
|
|
99
|
+
'.ospec/plugins/checkpoint/auth/README.md',
|
|
100
|
+
'.ospec/plugins/checkpoint/auth/login.example.js',
|
|
101
|
+
'.ospec/plugins/checkpoint/cache/.gitkeep',
|
|
102
|
+
], async () => {
|
|
103
|
+
await pluginsCommand.ensureCheckpointWorkspaceScaffold(rootDir, nextConfig.plugins.checkpoint);
|
|
104
|
+
});
|
|
105
|
+
createdFiles.push(...checkpointAssets.createdFiles);
|
|
106
|
+
skippedFiles.push(...checkpointAssets.skippedFiles);
|
|
107
|
+
}
|
|
108
|
+
if (enabledPlugins.length > 0 && (hasLegacyPluginKeys || configChanged)) {
|
|
109
|
+
await services_1.services.configManager.saveConfig(rootDir, nextConfig);
|
|
110
|
+
refreshedFiles.push('.skillrc');
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
createdFiles,
|
|
114
|
+
refreshedFiles,
|
|
115
|
+
skippedFiles,
|
|
116
|
+
enabledPlugins,
|
|
117
|
+
configSaved: refreshedFiles.includes('.skillrc'),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
normalizeEnabledStitchPlugin(stitchConfig, pluginsCommand) {
|
|
121
|
+
const before = JSON.stringify(stitchConfig);
|
|
122
|
+
stitchConfig.runner = stitchConfig.runner || pluginsCommand.createDefaultStitchPluginConfig().runner;
|
|
123
|
+
stitchConfig.gemini = stitchConfig.gemini || {
|
|
124
|
+
model: 'gemini-3-flash-preview',
|
|
125
|
+
auto_switch_on_limit: true,
|
|
126
|
+
save_on_fallback: true,
|
|
127
|
+
};
|
|
128
|
+
stitchConfig.codex = stitchConfig.codex || {
|
|
129
|
+
model: '',
|
|
130
|
+
mcp_server: 'stitch',
|
|
131
|
+
};
|
|
132
|
+
if (!stitchConfig.provider) {
|
|
133
|
+
stitchConfig.provider = 'gemini';
|
|
134
|
+
}
|
|
135
|
+
const provider = pluginsCommand.getStitchProvider(stitchConfig);
|
|
136
|
+
if (!stitchConfig.runner.command) {
|
|
137
|
+
stitchConfig.runner.command = 'node';
|
|
138
|
+
}
|
|
139
|
+
if (!Array.isArray(stitchConfig.runner.args) ||
|
|
140
|
+
stitchConfig.runner.args.length === 0 ||
|
|
141
|
+
pluginsCommand.isBuiltInGeminiRunner(stitchConfig.runner) ||
|
|
142
|
+
pluginsCommand.isBuiltInCodexRunner(stitchConfig.runner)) {
|
|
143
|
+
stitchConfig.runner.args = pluginsCommand.getDefaultRunnerArgs(provider);
|
|
144
|
+
}
|
|
145
|
+
if (!stitchConfig.runner.cwd) {
|
|
146
|
+
stitchConfig.runner.cwd = '${project_path}';
|
|
147
|
+
}
|
|
148
|
+
if (typeof stitchConfig.runner.token_env !== 'string' ||
|
|
149
|
+
(provider === 'gemini' &&
|
|
150
|
+
pluginsCommand.isBuiltInGeminiRunner(stitchConfig.runner) &&
|
|
151
|
+
stitchConfig.runner.token_env.trim() === 'STITCH_API_TOKEN')) {
|
|
152
|
+
stitchConfig.runner.token_env = '';
|
|
153
|
+
}
|
|
154
|
+
stitchConfig.capabilities = stitchConfig.capabilities || {};
|
|
155
|
+
stitchConfig.capabilities.page_design_review = stitchConfig.capabilities.page_design_review || {
|
|
156
|
+
enabled: false,
|
|
157
|
+
step: 'stitch_design_review',
|
|
158
|
+
activate_when_flags: ['ui_change', 'page_design', 'landing_page'],
|
|
159
|
+
};
|
|
160
|
+
return before !== JSON.stringify(stitchConfig);
|
|
161
|
+
}
|
|
162
|
+
normalizeEnabledCheckpointPlugin(checkpointConfig, pluginsCommand) {
|
|
163
|
+
const before = JSON.stringify(checkpointConfig);
|
|
164
|
+
const defaultConfig = pluginsCommand.createDefaultCheckpointPluginConfig();
|
|
165
|
+
checkpointConfig.runtime = checkpointConfig.runtime || defaultConfig.runtime;
|
|
166
|
+
checkpointConfig.runner = checkpointConfig.runner || defaultConfig.runner;
|
|
167
|
+
checkpointConfig.capabilities = checkpointConfig.capabilities || {};
|
|
168
|
+
checkpointConfig.capabilities.ui_review = checkpointConfig.capabilities.ui_review || {
|
|
169
|
+
enabled: false,
|
|
170
|
+
step: 'checkpoint_ui_review',
|
|
171
|
+
activate_when_flags: ['ui_change', 'page_design', 'landing_page'],
|
|
172
|
+
};
|
|
173
|
+
checkpointConfig.capabilities.flow_check = checkpointConfig.capabilities.flow_check || {
|
|
174
|
+
enabled: false,
|
|
175
|
+
step: 'checkpoint_flow_check',
|
|
176
|
+
activate_when_flags: ['feature_flow', 'api_change', 'backend_change', 'integration_change'],
|
|
177
|
+
};
|
|
178
|
+
checkpointConfig.stitch_integration = checkpointConfig.stitch_integration || {
|
|
179
|
+
enabled: true,
|
|
180
|
+
auto_pass_stitch_review: true,
|
|
181
|
+
};
|
|
182
|
+
checkpointConfig.runtime.startup = checkpointConfig.runtime.startup || defaultConfig.runtime.startup;
|
|
183
|
+
checkpointConfig.runtime.readiness = checkpointConfig.runtime.readiness || defaultConfig.runtime.readiness;
|
|
184
|
+
checkpointConfig.runtime.auth = checkpointConfig.runtime.auth || defaultConfig.runtime.auth;
|
|
185
|
+
checkpointConfig.runtime.shutdown = checkpointConfig.runtime.shutdown || defaultConfig.runtime.shutdown;
|
|
186
|
+
if (!checkpointConfig.runner.command) {
|
|
187
|
+
checkpointConfig.runner.command = 'node';
|
|
188
|
+
}
|
|
189
|
+
if (!Array.isArray(checkpointConfig.runner.args) ||
|
|
190
|
+
checkpointConfig.runner.args.length === 0 ||
|
|
191
|
+
pluginsCommand.isBuiltInCheckpointRunner(checkpointConfig.runner)) {
|
|
192
|
+
checkpointConfig.runner.args = pluginsCommand.getDefaultCheckpointRunnerArgs();
|
|
193
|
+
}
|
|
194
|
+
if (!checkpointConfig.runner.cwd) {
|
|
195
|
+
checkpointConfig.runner.cwd = '${project_path}';
|
|
196
|
+
}
|
|
197
|
+
if (typeof checkpointConfig.runner.token_env !== 'string') {
|
|
198
|
+
checkpointConfig.runner.token_env = '';
|
|
199
|
+
}
|
|
200
|
+
return before !== JSON.stringify(checkpointConfig);
|
|
201
|
+
}
|
|
202
|
+
async ensureManagedPluginAssets(rootDir, relativePaths, ensureAssets) {
|
|
203
|
+
const uniqueRelativePaths = Array.from(new Set(relativePaths.map(item => item.replace(/\\/g, '/'))));
|
|
204
|
+
const beforeMap = {};
|
|
205
|
+
for (const relativePath of uniqueRelativePaths) {
|
|
206
|
+
beforeMap[relativePath] = await services_1.services.fileService.exists((0, path_1.join)(rootDir, ...relativePath.split('/')));
|
|
207
|
+
}
|
|
208
|
+
await ensureAssets();
|
|
209
|
+
const createdFiles = [];
|
|
210
|
+
const skippedFiles = [];
|
|
211
|
+
for (const relativePath of uniqueRelativePaths) {
|
|
212
|
+
const exists = await services_1.services.fileService.exists((0, path_1.join)(rootDir, ...relativePath.split('/')));
|
|
213
|
+
if (!exists) {
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
if (beforeMap[relativePath]) {
|
|
217
|
+
skippedFiles.push(relativePath);
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
createdFiles.push(relativePath);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return { createdFiles, skippedFiles };
|
|
224
|
+
}
|
|
225
|
+
async syncInstalledSkills() {
|
|
226
|
+
const skillCommand = new SkillCommand_1.SkillCommand();
|
|
227
|
+
const codex = await skillCommand.installSkill('codex', 'ospec-change');
|
|
228
|
+
const claude = (await this.shouldSyncClaudeSkills()) ? await skillCommand.installSkill('claude', 'ospec-change') : null;
|
|
229
|
+
return { codex, claude };
|
|
230
|
+
}
|
|
231
|
+
resolveProviderHome(provider) {
|
|
232
|
+
const envHome = provider === 'claude'
|
|
233
|
+
? String(process.env.CLAUDE_HOME || '').trim()
|
|
234
|
+
: String(process.env.CODEX_HOME || '').trim();
|
|
235
|
+
if (envHome) {
|
|
236
|
+
return (0, path_1.resolve)(envHome);
|
|
237
|
+
}
|
|
238
|
+
return provider === 'claude'
|
|
239
|
+
? (0, path_1.join)((0, os_1.homedir)(), '.claude')
|
|
240
|
+
: (0, path_1.join)((0, os_1.homedir)(), '.codex');
|
|
241
|
+
}
|
|
242
|
+
async shouldSyncClaudeSkills() {
|
|
243
|
+
const claudeHome = this.resolveProviderHome('claude');
|
|
244
|
+
if (String(process.env.CLAUDE_HOME || '').trim()) {
|
|
245
|
+
return true;
|
|
246
|
+
}
|
|
247
|
+
return services_1.services.fileService.exists(claudeHome);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
exports.UpdateCommand = UpdateCommand;
|
|
251
|
+
//# sourceMappingURL=UpdateCommand.js.map
|