specsmd 0.0.0-dev.9 → 0.0.0-dev.90
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/README.md +190 -224
- package/bin/cli.js +28 -1
- package/flows/aidlc/commands/construction-agent.md +5 -1
- package/flows/aidlc/commands/inception-agent.md +4 -0
- package/flows/aidlc/commands/master-agent.md +4 -0
- package/flows/aidlc/commands/operations-agent.md +4 -0
- package/flows/aidlc/memory-bank.yaml +2 -1
- package/{scripts/artifact-validator.js → flows/aidlc/scripts/artifact-validator.cjs} +3 -3
- package/{scripts/bolt-complete.js → flows/aidlc/scripts/bolt-complete.cjs} +36 -5
- package/{scripts/status-integrity.js → flows/aidlc/scripts/status-integrity.cjs} +5 -5
- package/flows/aidlc/skills/construction/bolt-list.md +1 -1
- package/flows/aidlc/skills/construction/bolt-start.md +3 -3
- package/flows/aidlc/skills/construction/bolt-status.md +1 -1
- package/flows/aidlc/skills/construction/prototype-apply.md +311 -0
- package/flows/aidlc/skills/inception/vibe-to-spec.md +410 -0
- package/flows/aidlc/skills/master/analyze-context.md +1 -1
- package/flows/aidlc/templates/construction/bolt-template.md +2 -2
- package/flows/aidlc/templates/construction/bolt-types/ddd-construction-bolt.md +73 -11
- package/flows/aidlc/templates/standards/decision-index-template.md +32 -0
- package/flows/fire/README.md +19 -0
- package/flows/fire/agents/builder/agent.md +260 -0
- package/flows/fire/agents/builder/skills/code-review/SKILL.md +257 -0
- package/flows/fire/agents/builder/skills/code-review/references/auto-fix-rules.md +218 -0
- package/flows/fire/agents/builder/skills/code-review/references/review-categories.md +154 -0
- package/flows/fire/agents/builder/skills/code-review/templates/review-report.md.hbs +120 -0
- package/flows/fire/agents/builder/skills/run-execute/SKILL.md +714 -0
- package/flows/fire/agents/builder/skills/run-execute/scripts/complete-run.cjs +800 -0
- package/flows/fire/agents/builder/skills/run-execute/scripts/init-run.cjs +500 -0
- package/flows/fire/agents/builder/skills/run-execute/scripts/update-checkpoint.cjs +254 -0
- package/flows/fire/agents/builder/skills/run-execute/scripts/update-phase.cjs +250 -0
- package/flows/fire/agents/builder/skills/run-execute/templates/plan.md.hbs +61 -0
- package/flows/fire/agents/builder/skills/run-execute/templates/test-report.md.hbs +81 -0
- package/flows/fire/agents/builder/skills/run-plan/SKILL.md +378 -0
- package/flows/fire/agents/builder/skills/run-status/SKILL.md +96 -0
- package/flows/fire/agents/builder/skills/walkthrough-generate/SKILL.md +267 -0
- package/flows/fire/agents/builder/skills/walkthrough-generate/templates/walkthrough.md.hbs +176 -0
- package/flows/fire/agents/orchestrator/agent.md +144 -0
- package/flows/fire/agents/orchestrator/skills/project-init/SKILL.md +226 -0
- package/flows/fire/agents/orchestrator/skills/project-init/templates/coding-standards.md.hbs +149 -0
- package/flows/fire/agents/orchestrator/skills/project-init/templates/constitution.md.hbs +43 -0
- package/flows/fire/agents/orchestrator/skills/project-init/templates/system-architecture.md.hbs +101 -0
- package/flows/fire/agents/orchestrator/skills/project-init/templates/tech-stack.md.hbs +136 -0
- package/flows/fire/agents/orchestrator/skills/project-init/templates/testing-standards.md.hbs +94 -0
- package/flows/fire/agents/orchestrator/skills/route/SKILL.md +146 -0
- package/flows/fire/agents/orchestrator/skills/status/SKILL.md +696 -0
- package/flows/fire/agents/planner/agent.md +143 -0
- package/flows/fire/agents/planner/skills/design-doc-generate/SKILL.md +156 -0
- package/flows/fire/agents/planner/skills/design-doc-generate/templates/design.md.hbs +124 -0
- package/flows/fire/agents/planner/skills/intent-capture/SKILL.md +125 -0
- package/flows/fire/agents/planner/skills/intent-capture/templates/brief.md.hbs +40 -0
- package/flows/fire/agents/planner/skills/work-item-decompose/SKILL.md +166 -0
- package/flows/fire/agents/planner/skills/work-item-decompose/templates/work-item.md.hbs +40 -0
- package/flows/fire/commands/fire-builder.md +56 -0
- package/flows/fire/commands/fire-planner.md +48 -0
- package/flows/fire/commands/fire.md +46 -0
- package/flows/fire/memory-bank.yaml +240 -0
- package/flows/fire/quick-start.md +146 -0
- package/flows/ideation/README.md +35 -0
- package/flows/ideation/agents/orchestrator/agent.md +103 -0
- package/flows/ideation/agents/orchestrator/skills/flame/SKILL.md +132 -0
- package/flows/ideation/agents/orchestrator/skills/flame/references/evaluation-criteria.md +81 -0
- package/flows/ideation/agents/orchestrator/skills/flame/references/six-hats-method.md +87 -0
- package/flows/ideation/agents/orchestrator/skills/flame/templates/flame-report.md.hbs +81 -0
- package/flows/ideation/agents/orchestrator/skills/forge/SKILL.md +153 -0
- package/flows/ideation/agents/orchestrator/skills/forge/references/disney-method.md +94 -0
- package/flows/ideation/agents/orchestrator/skills/forge/references/pitch-framework.md +87 -0
- package/flows/ideation/agents/orchestrator/skills/forge/templates/concept-brief.md.hbs +83 -0
- package/flows/ideation/agents/orchestrator/skills/spark/SKILL.md +152 -0
- package/flows/ideation/agents/orchestrator/skills/spark/references/anti-bias.md +43 -0
- package/flows/ideation/agents/orchestrator/skills/spark/references/techniques/analogy.md +60 -0
- package/flows/ideation/agents/orchestrator/skills/spark/references/techniques/first-principles.md +56 -0
- package/flows/ideation/agents/orchestrator/skills/spark/references/techniques/index.yaml +76 -0
- package/flows/ideation/agents/orchestrator/skills/spark/references/techniques/inversion.md +52 -0
- package/flows/ideation/agents/orchestrator/skills/spark/references/techniques/questorming.md +57 -0
- package/flows/ideation/agents/orchestrator/skills/spark/references/techniques/random-word.md +35 -0
- package/flows/ideation/agents/orchestrator/skills/spark/references/techniques/scamper.md +67 -0
- package/flows/ideation/agents/orchestrator/skills/spark/references/techniques/what-if.md +55 -0
- package/flows/ideation/agents/orchestrator/skills/spark/templates/spark-bank.md.hbs +72 -0
- package/flows/ideation/commands/flame.md +43 -0
- package/flows/ideation/commands/forge.md +43 -0
- package/flows/ideation/commands/ideation.md +51 -0
- package/flows/ideation/commands/spark.md +43 -0
- package/flows/ideation/memory-bank.yaml +177 -0
- package/flows/ideation/quick-start.md +84 -0
- package/flows/ideation/shared/protocols/anti-bias.md +79 -0
- package/flows/ideation/shared/protocols/deep-thinking.md +92 -0
- package/flows/ideation/shared/protocols/diverge-converge.md +72 -0
- package/flows/ideation/shared/protocols/interaction-adaptation.md +88 -0
- package/flows/simple/README.md +190 -0
- package/flows/simple/agents/agent.md +404 -0
- package/flows/simple/commands/agent.md +60 -0
- package/flows/simple/context-config.yaml +34 -0
- package/flows/simple/memory-bank.yaml +66 -0
- package/flows/simple/quick-start.md +231 -0
- package/flows/simple/skills/design.md +96 -0
- package/flows/simple/skills/execute.md +190 -0
- package/flows/simple/skills/requirements.md +94 -0
- package/flows/simple/skills/tasks.md +136 -0
- package/flows/simple/templates/design-template.md +138 -0
- package/flows/simple/templates/requirements-template.md +85 -0
- package/flows/simple/templates/tasks-template.md +104 -0
- package/lib/analytics/tracker.js +6 -2
- package/lib/constants.js +25 -8
- package/lib/dashboard/aidlc/parser.js +581 -0
- package/lib/dashboard/fire/model.js +382 -0
- package/lib/dashboard/fire/parser.js +470 -0
- package/lib/dashboard/flow-detect.js +86 -0
- package/lib/dashboard/git/changes.js +362 -0
- package/lib/dashboard/git/worktrees.js +248 -0
- package/lib/dashboard/index.js +709 -0
- package/lib/dashboard/runtime/watch-runtime.js +122 -0
- package/lib/dashboard/simple/parser.js +293 -0
- package/lib/dashboard/tui/app.js +1675 -0
- package/lib/dashboard/tui/components/error-banner.js +35 -0
- package/lib/dashboard/tui/components/header.js +60 -0
- package/lib/dashboard/tui/components/help-footer.js +15 -0
- package/lib/dashboard/tui/components/stats-strip.js +35 -0
- package/lib/dashboard/tui/file-entries.js +383 -0
- package/lib/dashboard/tui/flow-builders.js +991 -0
- package/lib/dashboard/tui/git-builders.js +218 -0
- package/lib/dashboard/tui/helpers.js +236 -0
- package/lib/dashboard/tui/overlays.js +242 -0
- package/lib/dashboard/tui/preview.js +220 -0
- package/lib/dashboard/tui/renderer.js +76 -0
- package/lib/dashboard/tui/row-builders.js +797 -0
- package/lib/dashboard/tui/sections.js +45 -0
- package/lib/dashboard/tui/store.js +44 -0
- package/lib/dashboard/tui/views/overview-view.js +61 -0
- package/lib/dashboard/tui/views/runs-view.js +93 -0
- package/lib/dashboard/tui/worktree-builders.js +229 -0
- package/lib/dashboard/web/extension-adapter.js +726 -0
- package/lib/dashboard/web/public/app.js +9 -0
- package/lib/dashboard/web/public/index.html +14 -0
- package/lib/dashboard/web/public/styles.css +36 -0
- package/lib/dashboard/web/public/webview-bundle.js +7596 -0
- package/lib/dashboard/web/server.js +376 -0
- package/lib/dashboard/web/snapshot.js +299 -0
- package/lib/installer.js +19 -15
- package/lib/installers/CodexInstaller.js +72 -1
- package/lib/installers/KiroInstaller.js +55 -0
- package/lib/installers/OpenCodeInstaller.js +9 -1
- package/lib/installers/ToolInstaller.js +4 -1
- package/lib/installers/WindsurfInstaller.js +0 -54
- package/package.json +15 -55
- package/scripts/check-webview-bundle-sync.cjs +38 -0
- package/scripts/sync-webview-bundle.cjs +19 -0
package/lib/installer.js
CHANGED
|
@@ -4,7 +4,7 @@ const prompts = require('prompts');
|
|
|
4
4
|
const yaml = require('js-yaml');
|
|
5
5
|
const CLIUtils = require('./cli-utils');
|
|
6
6
|
const InstallerFactory = require('./InstallerFactory');
|
|
7
|
-
const { FLOWS } = require('./constants');
|
|
7
|
+
const { FLOWS, LINKS } = require('./constants');
|
|
8
8
|
const analytics = require('./analytics');
|
|
9
9
|
|
|
10
10
|
// Use theme from CLIUtils for consistent styling
|
|
@@ -125,6 +125,7 @@ async function install() {
|
|
|
125
125
|
// Step 3: Select Flow
|
|
126
126
|
console.log('');
|
|
127
127
|
CLIUtils.displayStep(3, 4, 'Select SDLC flow');
|
|
128
|
+
console.log(theme.dim(` Learn more about flows: ${LINKS.flows}\n`));
|
|
128
129
|
const flowChoices = Object.entries(FLOWS).map(([key, flow]) => ({
|
|
129
130
|
title: `${flow.name} - ${flow.description}${flow.message || ''}`,
|
|
130
131
|
value: key,
|
|
@@ -171,6 +172,20 @@ async function install() {
|
|
|
171
172
|
`Open ${selectedToolNames.join(' or ')} and run /specsmd-master-agent`
|
|
172
173
|
];
|
|
173
174
|
CLIUtils.displayNextSteps(nextSteps);
|
|
175
|
+
|
|
176
|
+
// Display IDE extension info with brand colors
|
|
177
|
+
console.log('\n' + theme.primary('─'.repeat(72)));
|
|
178
|
+
console.log(CLIUtils.logoGradient(' ★ IDE Extension'));
|
|
179
|
+
console.log(theme.primary('─'.repeat(72)));
|
|
180
|
+
console.log('');
|
|
181
|
+
console.log(' ' + CLIUtils.logoGradient('Enhance your experience with the specsmd IDE extension!'));
|
|
182
|
+
console.log('');
|
|
183
|
+
console.log(` ${theme.primary('Learn more:')} ${LINKS.ideExtension}`);
|
|
184
|
+
console.log(` ${theme.primary('VS Code:')} ${LINKS.vscodeMarketplace}`);
|
|
185
|
+
console.log(` ${theme.primary('Cursor/Antigravity/Windsurf:')} ${LINKS.openVsx}`);
|
|
186
|
+
console.log('');
|
|
187
|
+
console.log(theme.primary('─'.repeat(72)) + '\n');
|
|
188
|
+
console.log('');
|
|
174
189
|
} catch (error) {
|
|
175
190
|
// Track installation failure
|
|
176
191
|
const errorCategory = categorizeError(error);
|
|
@@ -229,6 +244,9 @@ async function installFlow(flowKey, toolKeys) {
|
|
|
229
244
|
if (await fs.pathExists(path.join(flowPath, 'shared'))) {
|
|
230
245
|
await fs.copy(path.join(flowPath, 'shared'), path.join(targetFlowDir, 'shared'));
|
|
231
246
|
}
|
|
247
|
+
if (await fs.pathExists(path.join(flowPath, 'scripts'))) {
|
|
248
|
+
await fs.copy(path.join(flowPath, 'scripts'), path.join(targetFlowDir, 'scripts'));
|
|
249
|
+
}
|
|
232
250
|
|
|
233
251
|
// Copy config files
|
|
234
252
|
if (await fs.pathExists(path.join(flowPath, 'memory-bank.yaml'))) {
|
|
@@ -250,20 +268,6 @@ async function installFlow(flowKey, toolKeys) {
|
|
|
250
268
|
|
|
251
269
|
CLIUtils.displayStatus('', 'Installed flow resources', 'success');
|
|
252
270
|
|
|
253
|
-
// Step 2.5: Install local scripts for deterministic operations
|
|
254
|
-
// These scripts are version-matched to the installed specsmd version
|
|
255
|
-
const scriptsDir = path.join(specsmdDir, 'scripts');
|
|
256
|
-
await fs.ensureDir(scriptsDir);
|
|
257
|
-
|
|
258
|
-
const sourceScriptsDir = path.join(__dirname, '..', 'scripts');
|
|
259
|
-
if (await fs.pathExists(sourceScriptsDir)) {
|
|
260
|
-
await fs.copy(sourceScriptsDir, scriptsDir);
|
|
261
|
-
CLIUtils.displayStatus('', 'Installed local scripts', 'success');
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// Note: Scripts are invoked directly via relative path (e.g., node .specsmd/scripts/bolt-complete.js)
|
|
265
|
-
// No npm scripts added to package.json to avoid dependency on package.json for execution
|
|
266
|
-
|
|
267
271
|
// NOTE: memory-bank/ is NOT created during installation
|
|
268
272
|
// It will be created when user runs project-init
|
|
269
273
|
// This allows us to detect if project is initialized by checking for memory-bank/standards/
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
const ToolInstaller = require('./ToolInstaller');
|
|
2
|
+
const fs = require('fs-extra');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const CLIUtils = require('../cli-utils');
|
|
5
|
+
const { theme } = CLIUtils;
|
|
2
6
|
|
|
3
7
|
class CodexInstaller extends ToolInstaller {
|
|
4
8
|
get key() {
|
|
@@ -10,12 +14,79 @@ class CodexInstaller extends ToolInstaller {
|
|
|
10
14
|
}
|
|
11
15
|
|
|
12
16
|
get commandsDir() {
|
|
13
|
-
return '.codex';
|
|
17
|
+
return path.join('.codex', 'skills');
|
|
14
18
|
}
|
|
15
19
|
|
|
16
20
|
get detectPath() {
|
|
17
21
|
return '.codex';
|
|
18
22
|
}
|
|
23
|
+
|
|
24
|
+
async installCommands(flowPath, config) {
|
|
25
|
+
const targetSkillsDir = this.commandsDir;
|
|
26
|
+
console.log(theme.dim(` Installing skills to ${targetSkillsDir}/...`));
|
|
27
|
+
await fs.ensureDir(targetSkillsDir);
|
|
28
|
+
|
|
29
|
+
const commandsSourceDir = path.join(flowPath, 'commands');
|
|
30
|
+
if (!await fs.pathExists(commandsSourceDir)) {
|
|
31
|
+
console.log(theme.warning(` No commands folder found at ${commandsSourceDir}`));
|
|
32
|
+
return [];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const commandFiles = await fs.readdir(commandsSourceDir);
|
|
36
|
+
const installedFiles = [];
|
|
37
|
+
|
|
38
|
+
for (const cmdFile of commandFiles) {
|
|
39
|
+
if (!cmdFile.endsWith('.md')) continue;
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
const sourcePath = path.join(commandsSourceDir, cmdFile);
|
|
43
|
+
const content = await fs.readFile(sourcePath, 'utf8');
|
|
44
|
+
const commandName = cmdFile.replace('.md', '');
|
|
45
|
+
const prefix = (config && config.command && config.command.prefix) ? `${config.command.prefix}-` : '';
|
|
46
|
+
const skillName = `specsmd-${prefix}${commandName}`;
|
|
47
|
+
|
|
48
|
+
const { description, body } = this.parseFrontmatter(content);
|
|
49
|
+
|
|
50
|
+
// Build SKILL.md with Codex frontmatter
|
|
51
|
+
const skillContent = [
|
|
52
|
+
'---',
|
|
53
|
+
`name: ${skillName}`,
|
|
54
|
+
`description: "${description || 'specsmd agent'}"`,
|
|
55
|
+
'---',
|
|
56
|
+
'',
|
|
57
|
+
body
|
|
58
|
+
].join('\n');
|
|
59
|
+
|
|
60
|
+
// Write SKILL.md
|
|
61
|
+
const skillDir = path.join(targetSkillsDir, skillName);
|
|
62
|
+
await fs.ensureDir(skillDir);
|
|
63
|
+
await fs.writeFile(path.join(skillDir, 'SKILL.md'), skillContent, 'utf8');
|
|
64
|
+
|
|
65
|
+
installedFiles.push(skillName);
|
|
66
|
+
} catch (err) {
|
|
67
|
+
console.log(theme.warning(` Failed to install ${cmdFile}: ${err.message}`));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
CLIUtils.displayStatus('', `Installed ${installedFiles.length} skills for ${this.name}`, 'success');
|
|
72
|
+
return installedFiles;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Parse YAML frontmatter from a markdown file
|
|
77
|
+
*/
|
|
78
|
+
parseFrontmatter(content) {
|
|
79
|
+
const match = content.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
|
|
80
|
+
if (!match) return { description: '', body: content };
|
|
81
|
+
|
|
82
|
+
const frontmatter = match[1];
|
|
83
|
+
const body = match[2];
|
|
84
|
+
const descMatch = frontmatter.match(/description:\s*["']?(.+?)["']?\s*$/m);
|
|
85
|
+
return {
|
|
86
|
+
description: descMatch ? descMatch[1] : '',
|
|
87
|
+
body: body.trim()
|
|
88
|
+
};
|
|
89
|
+
}
|
|
19
90
|
}
|
|
20
91
|
|
|
21
92
|
module.exports = CodexInstaller;
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
const ToolInstaller = require('./ToolInstaller');
|
|
2
2
|
const path = require('path');
|
|
3
|
+
const fs = require('fs-extra');
|
|
4
|
+
const CLIUtils = require('../cli-utils');
|
|
5
|
+
const { theme } = CLIUtils;
|
|
3
6
|
|
|
4
7
|
class KiroInstaller extends ToolInstaller {
|
|
5
8
|
get key() {
|
|
@@ -17,6 +20,58 @@ class KiroInstaller extends ToolInstaller {
|
|
|
17
20
|
get detectPath() {
|
|
18
21
|
return '.kiro';
|
|
19
22
|
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Override to install commands and create specs symlink for simple flow
|
|
26
|
+
*/
|
|
27
|
+
async installCommands(flowPath, config) {
|
|
28
|
+
// Install commands (default behavior)
|
|
29
|
+
const installedCommands = await super.installCommands(flowPath, config);
|
|
30
|
+
|
|
31
|
+
// For simple flow, create symlink to make specs visible in Kiro
|
|
32
|
+
if (flowPath.includes('simple')) {
|
|
33
|
+
await this.createSpecsSymlink();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return installedCommands;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Create symlink from .kiro/specs to specs/ for Kiro specifications compatibility
|
|
41
|
+
*/
|
|
42
|
+
async createSpecsSymlink() {
|
|
43
|
+
const kiroSpecsPath = path.join('.kiro', 'specs');
|
|
44
|
+
const specsPath = 'specs';
|
|
45
|
+
|
|
46
|
+
// Check if .kiro/specs already exists
|
|
47
|
+
if (await fs.pathExists(kiroSpecsPath)) {
|
|
48
|
+
const stats = await fs.lstat(kiroSpecsPath);
|
|
49
|
+
if (stats.isSymbolicLink()) {
|
|
50
|
+
console.log(theme.dim(` .kiro/specs symlink already exists, skipping`));
|
|
51
|
+
} else {
|
|
52
|
+
console.log(theme.dim(` .kiro/specs already exists as folder, skipping symlink`));
|
|
53
|
+
}
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Ensure specs folder exists
|
|
58
|
+
await fs.ensureDir(specsPath);
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
// Create relative symlink from .kiro/specs -> ../specs
|
|
62
|
+
await fs.ensureSymlink(path.join('..', specsPath), kiroSpecsPath);
|
|
63
|
+
CLIUtils.displayStatus('', 'Created .kiro/specs symlink for Kiro compatibility', 'success');
|
|
64
|
+
} catch (err) {
|
|
65
|
+
// Handle specific error cases
|
|
66
|
+
if (err.code === 'EPERM' || err.code === 'EACCES') {
|
|
67
|
+
console.log(theme.warning(` Cannot create symlink (permission denied). On Windows, try running as Administrator.`));
|
|
68
|
+
} else if (err.code === 'EEXIST') {
|
|
69
|
+
console.log(theme.dim(` .kiro/specs already exists, skipping symlink`));
|
|
70
|
+
} else {
|
|
71
|
+
console.log(theme.warning(` Failed to create specs symlink: ${err.message}`));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
20
75
|
}
|
|
21
76
|
|
|
22
77
|
module.exports = KiroInstaller;
|
|
@@ -11,12 +11,20 @@ class OpenCodeInstaller extends ToolInstaller {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
get commandsDir() {
|
|
14
|
-
return path.join('.opencode', '
|
|
14
|
+
return path.join('.opencode', 'command');
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
get detectPath() {
|
|
18
18
|
return '.opencode';
|
|
19
19
|
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* OpenCode requires 'agent: build' in command frontmatter.
|
|
23
|
+
* This inserts the line before the closing '---' of existing frontmatter.
|
|
24
|
+
*/
|
|
25
|
+
transformContent(content) {
|
|
26
|
+
return content.replace(/^(---\n[\s\S]*?)(---)/, '$1agent: build\n$2');
|
|
27
|
+
}
|
|
20
28
|
}
|
|
21
29
|
|
|
22
30
|
module.exports = OpenCodeInstaller;
|
|
@@ -56,7 +56,10 @@ class ToolInstaller {
|
|
|
56
56
|
const targetFileName = `specsmd-${prefix}${cmdFile}`;
|
|
57
57
|
const targetPath = path.join(targetCommandsDir, targetFileName);
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
let content = await fs.readFile(sourcePath, 'utf8');
|
|
60
|
+
if (this.transformContent) {
|
|
61
|
+
content = this.transformContent(content);
|
|
62
|
+
}
|
|
60
63
|
await fs.outputFile(targetPath, content, 'utf8');
|
|
61
64
|
installedFiles.push(targetFileName);
|
|
62
65
|
} catch (err) {
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
const ToolInstaller = require('./ToolInstaller');
|
|
2
|
-
const fs = require('fs-extra');
|
|
3
2
|
const path = require('path');
|
|
4
|
-
const CLIUtils = require('../cli-utils');
|
|
5
|
-
const { theme } = CLIUtils;
|
|
6
3
|
|
|
7
4
|
class WindsurfInstaller extends ToolInstaller {
|
|
8
5
|
get key() {
|
|
@@ -20,57 +17,6 @@ class WindsurfInstaller extends ToolInstaller {
|
|
|
20
17
|
get detectPath() {
|
|
21
18
|
return '.windsurf';
|
|
22
19
|
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Override to add frontmatter for Windsurf workflows
|
|
26
|
-
*/
|
|
27
|
-
async installCommands(flowPath, config) {
|
|
28
|
-
const targetCommandsDir = this.commandsDir;
|
|
29
|
-
console.log(theme.dim(` Installing workflows to ${targetCommandsDir}/...`));
|
|
30
|
-
await fs.ensureDir(targetCommandsDir);
|
|
31
|
-
|
|
32
|
-
const commandsSourceDir = path.join(flowPath, 'commands');
|
|
33
|
-
|
|
34
|
-
if (!await fs.pathExists(commandsSourceDir)) {
|
|
35
|
-
console.log(theme.warning(` No commands folder found at ${commandsSourceDir}`));
|
|
36
|
-
return [];
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const commandFiles = await fs.readdir(commandsSourceDir);
|
|
40
|
-
const installedFiles = [];
|
|
41
|
-
|
|
42
|
-
for (const cmdFile of commandFiles) {
|
|
43
|
-
if (cmdFile.endsWith('.md')) {
|
|
44
|
-
const sourcePath = path.join(commandsSourceDir, cmdFile);
|
|
45
|
-
const prefix = (config && config.command && config.command.prefix) ? `${config.command.prefix}-` : '';
|
|
46
|
-
|
|
47
|
-
const targetFileName = `specsmd-${prefix}${cmdFile}`;
|
|
48
|
-
const targetPath = path.join(targetCommandsDir, targetFileName);
|
|
49
|
-
|
|
50
|
-
// Extract agent name from target filename (e.g., "specsmd-master-agent.md" -> "specsmd-master-agent")
|
|
51
|
-
const agentName = targetFileName.replace(/\.md$/, '');
|
|
52
|
-
|
|
53
|
-
// Read source content and add Windsurf frontmatter
|
|
54
|
-
let content = await fs.readFile(sourcePath, 'utf8');
|
|
55
|
-
|
|
56
|
-
// Add Windsurf-specific frontmatter if not present
|
|
57
|
-
if (!content.startsWith('---')) {
|
|
58
|
-
const frontmatter = `---
|
|
59
|
-
description: ${agentName}
|
|
60
|
-
---
|
|
61
|
-
|
|
62
|
-
`;
|
|
63
|
-
content = frontmatter + content;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
await fs.writeFile(targetPath, content);
|
|
67
|
-
installedFiles.push(targetFileName);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
CLIUtils.displayStatus('', `Installed ${installedFiles.length} workflows for ${this.name}`, 'success');
|
|
72
|
-
return installedFiles;
|
|
73
|
-
}
|
|
74
20
|
}
|
|
75
21
|
|
|
76
22
|
module.exports = WindsurfInstaller;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "specsmd",
|
|
3
|
-
"version": "0.0.0-dev.
|
|
3
|
+
"version": "0.0.0-dev.90",
|
|
4
4
|
"description": "Multi-agent orchestration system for AI-native software development. Delivers AI-DLC, Agile, and custom SDLC flows as markdown-based agent systems.",
|
|
5
5
|
"main": "lib/installer.js",
|
|
6
6
|
"bin": {
|
|
@@ -12,7 +12,10 @@
|
|
|
12
12
|
"test:schema": "vitest run __tests__/unit/schema-validation/",
|
|
13
13
|
"lint:md": "markdownlint 'flows/**/*.md' --config ../.markdownlint.yaml",
|
|
14
14
|
"lint:md:fix": "markdownlint 'flows/**/*.md' --config ../.markdownlint.yaml --fix",
|
|
15
|
-
"
|
|
15
|
+
"sync:webview-bundle": "node scripts/sync-webview-bundle.cjs",
|
|
16
|
+
"check:webview-bundle": "node scripts/check-webview-bundle-sync.cjs",
|
|
17
|
+
"prepack": "npm run check:webview-bundle",
|
|
18
|
+
"validate:all": "npm run test && npm run lint:md && npm run check:webview-bundle"
|
|
16
19
|
},
|
|
17
20
|
"keywords": [
|
|
18
21
|
"ai-dlc",
|
|
@@ -40,79 +43,36 @@
|
|
|
40
43
|
"README.md"
|
|
41
44
|
],
|
|
42
45
|
"dependencies": {
|
|
46
|
+
"@inkjs/ui": "^2.0.0",
|
|
43
47
|
"chalk": "^4.1.2",
|
|
48
|
+
"chokidar": "^4.0.3",
|
|
44
49
|
"commander": "^11.1.0",
|
|
45
50
|
"figlet": "^1.9.4",
|
|
46
51
|
"fs-extra": "^11.1.1",
|
|
47
52
|
"gradient-string": "^2.0.2",
|
|
53
|
+
"ink": "^5.2.1",
|
|
48
54
|
"js-yaml": "^4.1.0",
|
|
49
55
|
"mixpanel": "^0.18.0",
|
|
50
56
|
"oh-my-logo": "^0.4.0",
|
|
51
|
-
"prompts": "^2.4.2"
|
|
57
|
+
"prompts": "^2.4.2",
|
|
58
|
+
"react": "^18.3.1",
|
|
59
|
+
"slice-ansi": "^4.0.0",
|
|
60
|
+
"string-width": "^4.2.3"
|
|
52
61
|
},
|
|
53
62
|
"engines": {
|
|
54
|
-
"node": ">=
|
|
63
|
+
"node": ">=20.0.0"
|
|
55
64
|
},
|
|
56
65
|
"devDependencies": {
|
|
57
|
-
"@semantic-release/git": "^10.0.1",
|
|
58
66
|
"@types/js-yaml": "^4.0.9",
|
|
59
67
|
"@types/node": "^24.10.2",
|
|
60
68
|
"glob": "^13.0.0",
|
|
61
69
|
"markdownlint": "^0.40.0",
|
|
62
70
|
"markdownlint-cli": "^0.46.0",
|
|
63
71
|
"remark-parse": "^11.0.0",
|
|
64
|
-
"semantic-release": "^24.2.0",
|
|
65
72
|
"typescript": "^5.9.3",
|
|
66
73
|
"unified": "^11.0.5",
|
|
67
74
|
"unist-util-visit": "^5.0.0",
|
|
68
|
-
"vitest": "^4.0.15"
|
|
69
|
-
|
|
70
|
-
"release": {
|
|
71
|
-
"branches": [
|
|
72
|
-
"main"
|
|
73
|
-
],
|
|
74
|
-
"plugins": [
|
|
75
|
-
[
|
|
76
|
-
"@semantic-release/commit-analyzer",
|
|
77
|
-
{
|
|
78
|
-
"releaseRules": [
|
|
79
|
-
{
|
|
80
|
-
"breaking": true,
|
|
81
|
-
"release": "minor"
|
|
82
|
-
},
|
|
83
|
-
{
|
|
84
|
-
"type": "feat",
|
|
85
|
-
"release": "minor"
|
|
86
|
-
},
|
|
87
|
-
{
|
|
88
|
-
"type": "fix",
|
|
89
|
-
"release": "patch"
|
|
90
|
-
},
|
|
91
|
-
{
|
|
92
|
-
"type": "perf",
|
|
93
|
-
"release": "patch"
|
|
94
|
-
}
|
|
95
|
-
]
|
|
96
|
-
}
|
|
97
|
-
],
|
|
98
|
-
"@semantic-release/release-notes-generator",
|
|
99
|
-
"@semantic-release/npm",
|
|
100
|
-
[
|
|
101
|
-
"@semantic-release/github",
|
|
102
|
-
{
|
|
103
|
-
"successComment": false,
|
|
104
|
-
"failComment": false
|
|
105
|
-
}
|
|
106
|
-
],
|
|
107
|
-
[
|
|
108
|
-
"@semantic-release/git",
|
|
109
|
-
{
|
|
110
|
-
"assets": [
|
|
111
|
-
"package.json"
|
|
112
|
-
],
|
|
113
|
-
"message": "chore(release): ${nextRelease.version} [skip ci]"
|
|
114
|
-
}
|
|
115
|
-
]
|
|
116
|
-
]
|
|
75
|
+
"vitest": "^4.0.15",
|
|
76
|
+
"yaml": "^2.8.2"
|
|
117
77
|
}
|
|
118
78
|
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const crypto = require('crypto');
|
|
6
|
+
|
|
7
|
+
const packageRoot = path.resolve(__dirname, '..');
|
|
8
|
+
const repoRoot = path.resolve(packageRoot, '..');
|
|
9
|
+
const extensionBundle = path.join(repoRoot, 'vs-code-extension', 'dist', 'webview', 'bundle.js');
|
|
10
|
+
const packagedBundle = path.join(packageRoot, 'lib', 'dashboard', 'web', 'public', 'webview-bundle.js');
|
|
11
|
+
|
|
12
|
+
function hashFile(filePath) {
|
|
13
|
+
return crypto.createHash('sha256').update(fs.readFileSync(filePath)).digest('hex');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (!fs.existsSync(extensionBundle)) {
|
|
17
|
+
console.error(`Missing VS Code webview bundle: ${extensionBundle}`);
|
|
18
|
+
console.error('Run `npm run compile:webview` in vs-code-extension first.');
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (!fs.existsSync(packagedBundle)) {
|
|
23
|
+
console.error(`Missing packaged dashboard web bundle: ${packagedBundle}`);
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const extensionHash = hashFile(extensionBundle);
|
|
28
|
+
const packagedHash = hashFile(packagedBundle);
|
|
29
|
+
|
|
30
|
+
if (extensionHash !== packagedHash) {
|
|
31
|
+
console.error('Dashboard web bundle is out of sync with the VS Code webview bundle.');
|
|
32
|
+
console.error(`extension: ${extensionHash}`);
|
|
33
|
+
console.error(`packaged: ${packagedHash}`);
|
|
34
|
+
console.error('Run `npm run sync:webview-bundle` from src/.');
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
console.log('Dashboard web bundle is synced with the VS Code webview bundle.');
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
const packageRoot = path.resolve(__dirname, '..');
|
|
7
|
+
const repoRoot = path.resolve(packageRoot, '..');
|
|
8
|
+
const extensionBundle = path.join(repoRoot, 'vs-code-extension', 'dist', 'webview', 'bundle.js');
|
|
9
|
+
const packagedBundle = path.join(packageRoot, 'lib', 'dashboard', 'web', 'public', 'webview-bundle.js');
|
|
10
|
+
|
|
11
|
+
if (!fs.existsSync(extensionBundle)) {
|
|
12
|
+
console.error(`Missing VS Code webview bundle: ${extensionBundle}`);
|
|
13
|
+
console.error('Run `npm run compile:webview` in vs-code-extension first.');
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
fs.mkdirSync(path.dirname(packagedBundle), { recursive: true });
|
|
18
|
+
fs.copyFileSync(extensionBundle, packagedBundle);
|
|
19
|
+
console.log(`Synced ${path.relative(repoRoot, packagedBundle)} from ${path.relative(repoRoot, extensionBundle)}.`);
|