musubi-sdd 6.2.0 ā 6.2.2
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.ja.md +60 -1
- package/README.md +60 -1
- package/bin/musubi-dashboard.js +340 -0
- package/bin/musubi-upgrade.js +395 -0
- package/bin/musubi.js +15 -0
- package/package.json +5 -3
- package/src/cli/dashboard-cli.js +536 -0
- package/src/constitutional/checker.js +633 -0
- package/src/constitutional/ci-reporter.js +338 -0
- package/src/constitutional/index.js +22 -0
- package/src/constitutional/phase-minus-one.js +404 -0
- package/src/constitutional/steering-sync.js +473 -0
- package/src/dashboard/index.js +20 -0
- package/src/dashboard/sprint-planner.js +361 -0
- package/src/dashboard/sprint-reporter.js +378 -0
- package/src/dashboard/transition-recorder.js +209 -0
- package/src/dashboard/workflow-dashboard.js +434 -0
- package/src/enterprise/error-recovery.js +524 -0
- package/src/enterprise/experiment-report.js +573 -0
- package/src/enterprise/index.js +57 -4
- package/src/enterprise/rollback-manager.js +584 -0
- package/src/enterprise/tech-article.js +509 -0
- package/src/traceability/extractor.js +294 -0
- package/src/traceability/gap-detector.js +230 -0
- package/src/traceability/index.js +15 -0
- package/src/traceability/matrix-storage.js +368 -0
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* MUSUBI Upgrade Script
|
|
5
|
+
*
|
|
6
|
+
* Upgrades existing MUSUBI projects to newer versions:
|
|
7
|
+
* - Updates steering files
|
|
8
|
+
* - Adds new prompts/skills
|
|
9
|
+
* - Migrates configuration
|
|
10
|
+
* - Preserves user customizations
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const fs = require('fs-extra');
|
|
14
|
+
const path = require('path');
|
|
15
|
+
const chalk = require('chalk');
|
|
16
|
+
const { Command } = require('commander');
|
|
17
|
+
|
|
18
|
+
const program = new Command();
|
|
19
|
+
const packageJson = require('../package.json');
|
|
20
|
+
|
|
21
|
+
// Version migration definitions
|
|
22
|
+
const MIGRATIONS = {
|
|
23
|
+
'6.2.0': {
|
|
24
|
+
description: 'Review Gate Engine, Dashboard, Traceability',
|
|
25
|
+
changes: [
|
|
26
|
+
'Add Review Gate prompts to AGENTS.md',
|
|
27
|
+
'Create storage/reviews/, storage/dashboard/, storage/traceability/ directories',
|
|
28
|
+
'Update steering/project.yml with reviewGate settings',
|
|
29
|
+
],
|
|
30
|
+
migrate: migrateToV620,
|
|
31
|
+
},
|
|
32
|
+
'6.2.1': {
|
|
33
|
+
description: 'Bug fixes and improvements',
|
|
34
|
+
changes: ['Minor fixes'],
|
|
35
|
+
migrate: migrateToV621,
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// ============================================================================
|
|
40
|
+
// Migration Functions
|
|
41
|
+
// ============================================================================
|
|
42
|
+
|
|
43
|
+
async function migrateToV620(projectDir, _options) {
|
|
44
|
+
const results = { success: [], failed: [], skipped: [] };
|
|
45
|
+
|
|
46
|
+
// 1. Create new storage directories
|
|
47
|
+
const newDirs = [
|
|
48
|
+
'storage/reviews',
|
|
49
|
+
'storage/dashboard',
|
|
50
|
+
'storage/traceability',
|
|
51
|
+
'storage/transitions',
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
for (const dir of newDirs) {
|
|
55
|
+
const dirPath = path.join(projectDir, dir);
|
|
56
|
+
try {
|
|
57
|
+
if (!fs.existsSync(dirPath)) {
|
|
58
|
+
await fs.ensureDir(dirPath);
|
|
59
|
+
await fs.writeFile(path.join(dirPath, '.gitkeep'), '');
|
|
60
|
+
results.success.push(`Created ${dir}/`);
|
|
61
|
+
} else {
|
|
62
|
+
results.skipped.push(`${dir}/ already exists`);
|
|
63
|
+
}
|
|
64
|
+
} catch (err) {
|
|
65
|
+
results.failed.push(`Failed to create ${dir}/: ${err.message}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// 2. Update AGENTS.md with new review prompts
|
|
70
|
+
const agentsPath = path.join(projectDir, 'AGENTS.md');
|
|
71
|
+
if (fs.existsSync(agentsPath)) {
|
|
72
|
+
try {
|
|
73
|
+
let content = await fs.readFile(agentsPath, 'utf8');
|
|
74
|
+
|
|
75
|
+
const reviewPrompts = `
|
|
76
|
+
### Review Gate Prompts (v6.2.0)
|
|
77
|
+
|
|
78
|
+
- \`#sdd-review-requirements <feature>\` - Review requirements (EARS, stakeholders, acceptance criteria)
|
|
79
|
+
- \`#sdd-review-design <feature>\` - Review design (C4, ADR, Constitutional Articles)
|
|
80
|
+
- \`#sdd-review-implementation <feature>\` - Review implementation (coverage, lint, traceability)
|
|
81
|
+
- \`#sdd-review-all <feature>\` - Full review cycle for all phases
|
|
82
|
+
`;
|
|
83
|
+
|
|
84
|
+
if (!content.includes('#sdd-review-requirements')) {
|
|
85
|
+
// Find a good insertion point (after existing prompts section)
|
|
86
|
+
const promptsIndex = content.indexOf('### Prompts');
|
|
87
|
+
if (promptsIndex !== -1) {
|
|
88
|
+
const nextSectionIndex = content.indexOf('###', promptsIndex + 10);
|
|
89
|
+
if (nextSectionIndex !== -1) {
|
|
90
|
+
content =
|
|
91
|
+
content.slice(0, nextSectionIndex) + reviewPrompts + '\n' + content.slice(nextSectionIndex);
|
|
92
|
+
} else {
|
|
93
|
+
content += '\n' + reviewPrompts;
|
|
94
|
+
}
|
|
95
|
+
} else {
|
|
96
|
+
content += '\n' + reviewPrompts;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
await fs.writeFile(agentsPath, content);
|
|
100
|
+
results.success.push('Added Review Gate prompts to AGENTS.md');
|
|
101
|
+
} else {
|
|
102
|
+
results.skipped.push('Review Gate prompts already in AGENTS.md');
|
|
103
|
+
}
|
|
104
|
+
} catch (err) {
|
|
105
|
+
results.failed.push(`Failed to update AGENTS.md: ${err.message}`);
|
|
106
|
+
}
|
|
107
|
+
} else {
|
|
108
|
+
results.skipped.push('AGENTS.md not found (not a MUSUBI project?)');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// 3. Update steering/project.yml with reviewGate settings
|
|
112
|
+
const projectYmlPath = path.join(projectDir, 'steering', 'project.yml');
|
|
113
|
+
if (fs.existsSync(projectYmlPath)) {
|
|
114
|
+
try {
|
|
115
|
+
let content = await fs.readFile(projectYmlPath, 'utf8');
|
|
116
|
+
|
|
117
|
+
const reviewGateConfig = `
|
|
118
|
+
# Review Gate Settings (v6.2.0)
|
|
119
|
+
reviewGate:
|
|
120
|
+
requirements:
|
|
121
|
+
earsCheck: true
|
|
122
|
+
stakeholderCoverage: true
|
|
123
|
+
acceptanceCriteriaRequired: true
|
|
124
|
+
design:
|
|
125
|
+
c4Required: ['context', 'container', 'component']
|
|
126
|
+
adrRequired: true
|
|
127
|
+
constitutionalArticles: [1, 2, 7, 8]
|
|
128
|
+
implementation:
|
|
129
|
+
minCoverage: 80
|
|
130
|
+
coverageType: 'line'
|
|
131
|
+
lintStrict: true
|
|
132
|
+
|
|
133
|
+
# Traceability Settings (v6.2.0)
|
|
134
|
+
traceability:
|
|
135
|
+
patterns:
|
|
136
|
+
- 'REQ-[A-Z0-9]+-\\\\d{3}'
|
|
137
|
+
- 'IMP-\\\\d+\\\\.\\\\d+-\\\\d{3}(?:-\\\\d{2})?'
|
|
138
|
+
extractFrom:
|
|
139
|
+
- 'src/**/*.{ts,js}'
|
|
140
|
+
- 'tests/**/*.test.{ts,js}'
|
|
141
|
+
outputPath: 'storage/traceability/matrix.yml'
|
|
142
|
+
`;
|
|
143
|
+
|
|
144
|
+
if (!content.includes('reviewGate:')) {
|
|
145
|
+
content += '\n' + reviewGateConfig;
|
|
146
|
+
await fs.writeFile(projectYmlPath, content);
|
|
147
|
+
results.success.push('Added reviewGate settings to steering/project.yml');
|
|
148
|
+
} else {
|
|
149
|
+
results.skipped.push('reviewGate settings already in steering/project.yml');
|
|
150
|
+
}
|
|
151
|
+
} catch (err) {
|
|
152
|
+
results.failed.push(`Failed to update steering/project.yml: ${err.message}`);
|
|
153
|
+
}
|
|
154
|
+
} else {
|
|
155
|
+
results.skipped.push('steering/project.yml not found');
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// 4. Create version marker
|
|
159
|
+
const versionPath = path.join(projectDir, 'steering', '.musubi-version');
|
|
160
|
+
try {
|
|
161
|
+
await fs.writeFile(versionPath, '6.2.0\n');
|
|
162
|
+
results.success.push('Created version marker');
|
|
163
|
+
} catch (err) {
|
|
164
|
+
results.failed.push(`Failed to create version marker: ${err.message}`);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return results;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
async function migrateToV621(projectDir, _options) {
|
|
171
|
+
const results = { success: [], failed: [], skipped: [] };
|
|
172
|
+
|
|
173
|
+
// v6.2.1 is mainly bug fixes, just update version marker
|
|
174
|
+
const versionPath = path.join(projectDir, 'steering', '.musubi-version');
|
|
175
|
+
try {
|
|
176
|
+
await fs.writeFile(versionPath, '6.2.1\n');
|
|
177
|
+
results.success.push('Updated version marker to 6.2.1');
|
|
178
|
+
} catch (err) {
|
|
179
|
+
results.failed.push(`Failed to update version marker: ${err.message}`);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return results;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// ============================================================================
|
|
186
|
+
// Utility Functions
|
|
187
|
+
// ============================================================================
|
|
188
|
+
|
|
189
|
+
function getCurrentVersion(projectDir) {
|
|
190
|
+
const versionPath = path.join(projectDir, 'steering', '.musubi-version');
|
|
191
|
+
if (fs.existsSync(versionPath)) {
|
|
192
|
+
return fs.readFileSync(versionPath, 'utf8').trim();
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Fallback: check if MUSUBI is initialized
|
|
196
|
+
const steeringDir = path.join(projectDir, 'steering');
|
|
197
|
+
if (fs.existsSync(steeringDir)) {
|
|
198
|
+
return '6.0.0'; // Assume pre-version-tracking
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function compareVersions(v1, v2) {
|
|
205
|
+
const parts1 = v1.split('.').map(Number);
|
|
206
|
+
const parts2 = v2.split('.').map(Number);
|
|
207
|
+
|
|
208
|
+
for (let i = 0; i < 3; i++) {
|
|
209
|
+
if (parts1[i] > parts2[i]) return 1;
|
|
210
|
+
if (parts1[i] < parts2[i]) return -1;
|
|
211
|
+
}
|
|
212
|
+
return 0;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function getMigrationPath(fromVersion, toVersion) {
|
|
216
|
+
const versions = Object.keys(MIGRATIONS).sort(compareVersions);
|
|
217
|
+
const path = [];
|
|
218
|
+
|
|
219
|
+
for (const version of versions) {
|
|
220
|
+
if (compareVersions(version, fromVersion) > 0 && compareVersions(version, toVersion) <= 0) {
|
|
221
|
+
path.push(version);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return path;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// ============================================================================
|
|
229
|
+
// CLI Commands
|
|
230
|
+
// ============================================================================
|
|
231
|
+
|
|
232
|
+
program
|
|
233
|
+
.name('musubi-upgrade')
|
|
234
|
+
.description('Upgrade MUSUBI project to a newer version')
|
|
235
|
+
.version(packageJson.version)
|
|
236
|
+
.option('--to <version>', 'Target version to upgrade to', 'latest')
|
|
237
|
+
.option('--dry-run', 'Preview changes without applying')
|
|
238
|
+
.option('--force', 'Force upgrade even if already at target version')
|
|
239
|
+
.action(async options => {
|
|
240
|
+
const projectDir = process.cwd();
|
|
241
|
+
|
|
242
|
+
console.log(chalk.blue.bold('\nš MUSUBI Upgrade\n'));
|
|
243
|
+
|
|
244
|
+
// Check if MUSUBI is initialized
|
|
245
|
+
const currentVersion = getCurrentVersion(projectDir);
|
|
246
|
+
if (!currentVersion) {
|
|
247
|
+
console.log(chalk.red('ā MUSUBI is not initialized in this directory.'));
|
|
248
|
+
console.log(chalk.gray('\nRun: npx musubi-sdd init\n'));
|
|
249
|
+
process.exit(1);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Determine target version
|
|
253
|
+
let targetVersion = options.to;
|
|
254
|
+
if (targetVersion === 'latest') {
|
|
255
|
+
targetVersion = packageJson.version;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Validate target version
|
|
259
|
+
const availableVersions = Object.keys(MIGRATIONS);
|
|
260
|
+
if (!availableVersions.includes(targetVersion) && targetVersion !== packageJson.version) {
|
|
261
|
+
console.log(chalk.red(`ā Unknown target version: ${targetVersion}`));
|
|
262
|
+
console.log(chalk.gray(`\nAvailable versions: ${availableVersions.join(', ')}\n`));
|
|
263
|
+
process.exit(1);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
console.log(chalk.white(`Current version: ${chalk.yellow(currentVersion)}`));
|
|
267
|
+
console.log(chalk.white(`Target version: ${chalk.green(targetVersion)}`));
|
|
268
|
+
|
|
269
|
+
// Check if upgrade is needed
|
|
270
|
+
const comparison = compareVersions(currentVersion, targetVersion);
|
|
271
|
+
if (comparison >= 0 && !options.force) {
|
|
272
|
+
console.log(chalk.green('\nā
Already at target version or newer.\n'));
|
|
273
|
+
console.log(chalk.gray('Use --force to re-run migrations.\n'));
|
|
274
|
+
process.exit(0);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Get migration path
|
|
278
|
+
const migrationPath = getMigrationPath(currentVersion, targetVersion);
|
|
279
|
+
|
|
280
|
+
if (migrationPath.length === 0) {
|
|
281
|
+
console.log(chalk.yellow('\nā ļø No migrations needed.\n'));
|
|
282
|
+
process.exit(0);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
console.log(chalk.white(`\nMigrations to apply: ${migrationPath.join(' ā ')}\n`));
|
|
286
|
+
|
|
287
|
+
// Show migration details
|
|
288
|
+
for (const version of migrationPath) {
|
|
289
|
+
const migration = MIGRATIONS[version];
|
|
290
|
+
console.log(chalk.cyan(`š¦ v${version}: ${migration.description}`));
|
|
291
|
+
for (const change of migration.changes) {
|
|
292
|
+
console.log(chalk.gray(` - ${change}`));
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
if (options.dryRun) {
|
|
297
|
+
console.log(chalk.yellow('\nš Dry run mode - no changes applied.\n'));
|
|
298
|
+
process.exit(0);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Confirm upgrade
|
|
302
|
+
console.log('');
|
|
303
|
+
|
|
304
|
+
// Apply migrations
|
|
305
|
+
let totalSuccess = 0;
|
|
306
|
+
let totalFailed = 0;
|
|
307
|
+
let totalSkipped = 0;
|
|
308
|
+
|
|
309
|
+
for (const version of migrationPath) {
|
|
310
|
+
console.log(chalk.blue(`\nš¦ Applying migration to v${version}...\n`));
|
|
311
|
+
|
|
312
|
+
const migration = MIGRATIONS[version];
|
|
313
|
+
const results = await migration.migrate(projectDir, options);
|
|
314
|
+
|
|
315
|
+
for (const msg of results.success) {
|
|
316
|
+
console.log(chalk.green(` ā
${msg}`));
|
|
317
|
+
totalSuccess++;
|
|
318
|
+
}
|
|
319
|
+
for (const msg of results.skipped) {
|
|
320
|
+
console.log(chalk.yellow(` āļø ${msg}`));
|
|
321
|
+
totalSkipped++;
|
|
322
|
+
}
|
|
323
|
+
for (const msg of results.failed) {
|
|
324
|
+
console.log(chalk.red(` ā ${msg}`));
|
|
325
|
+
totalFailed++;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Summary
|
|
330
|
+
console.log(chalk.blue.bold('\nš Upgrade Summary\n'));
|
|
331
|
+
console.log(chalk.green(` ā
Success: ${totalSuccess}`));
|
|
332
|
+
console.log(chalk.yellow(` āļø Skipped: ${totalSkipped}`));
|
|
333
|
+
console.log(chalk.red(` ā Failed: ${totalFailed}`));
|
|
334
|
+
|
|
335
|
+
if (totalFailed > 0) {
|
|
336
|
+
console.log(chalk.red('\nā ļø Some migrations failed. Please check the errors above.\n'));
|
|
337
|
+
process.exit(1);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
console.log(chalk.green(`\nā
Successfully upgraded to v${targetVersion}!\n`));
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
// List available migrations
|
|
344
|
+
program
|
|
345
|
+
.command('list')
|
|
346
|
+
.description('List available migrations')
|
|
347
|
+
.action(() => {
|
|
348
|
+
console.log(chalk.blue.bold('\nš Available MUSUBI Migrations\n'));
|
|
349
|
+
|
|
350
|
+
const versions = Object.keys(MIGRATIONS).sort(compareVersions);
|
|
351
|
+
for (const version of versions) {
|
|
352
|
+
const migration = MIGRATIONS[version];
|
|
353
|
+
console.log(chalk.cyan(`v${version}: ${migration.description}`));
|
|
354
|
+
for (const change of migration.changes) {
|
|
355
|
+
console.log(chalk.gray(` - ${change}`));
|
|
356
|
+
}
|
|
357
|
+
console.log('');
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
console.log(chalk.white(`Current package version: ${packageJson.version}\n`));
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
// Check current version
|
|
364
|
+
program
|
|
365
|
+
.command('check')
|
|
366
|
+
.description('Check current project version')
|
|
367
|
+
.action(() => {
|
|
368
|
+
const projectDir = process.cwd();
|
|
369
|
+
const currentVersion = getCurrentVersion(projectDir);
|
|
370
|
+
|
|
371
|
+
console.log(chalk.blue.bold('\nš MUSUBI Version Check\n'));
|
|
372
|
+
|
|
373
|
+
if (!currentVersion) {
|
|
374
|
+
console.log(chalk.red('ā MUSUBI is not initialized in this directory.\n'));
|
|
375
|
+
process.exit(1);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
console.log(chalk.white(`Project version: ${chalk.yellow(currentVersion)}`));
|
|
379
|
+
console.log(chalk.white(`Package version: ${chalk.green(packageJson.version)}`));
|
|
380
|
+
|
|
381
|
+
const comparison = compareVersions(currentVersion, packageJson.version);
|
|
382
|
+
if (comparison < 0) {
|
|
383
|
+
console.log(chalk.yellow(`\nā ļø Upgrade available: ${currentVersion} ā ${packageJson.version}`));
|
|
384
|
+
console.log(chalk.gray('\nRun: npx musubi-sdd upgrade\n'));
|
|
385
|
+
} else {
|
|
386
|
+
console.log(chalk.green('\nā
Project is up to date.\n'));
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
program.parse(process.argv);
|
|
391
|
+
|
|
392
|
+
// Show help if no arguments
|
|
393
|
+
if (!process.argv.slice(2).length) {
|
|
394
|
+
program.outputHelp();
|
|
395
|
+
}
|
package/bin/musubi.js
CHANGED
|
@@ -392,6 +392,21 @@ program
|
|
|
392
392
|
}
|
|
393
393
|
});
|
|
394
394
|
|
|
395
|
+
// ============================================================================
|
|
396
|
+
// Command: upgrade
|
|
397
|
+
// ============================================================================
|
|
398
|
+
program
|
|
399
|
+
.command('upgrade')
|
|
400
|
+
.description('Upgrade MUSUBI project to a newer version')
|
|
401
|
+
.option('--to <version>', 'Target version to upgrade to', 'latest')
|
|
402
|
+
.option('--dry-run', 'Preview changes without applying')
|
|
403
|
+
.option('--force', 'Force upgrade even if already at target version')
|
|
404
|
+
.action(async _options => {
|
|
405
|
+
// Delegate to musubi-upgrade.js
|
|
406
|
+
process.argv = ['node', 'musubi-upgrade', ...process.argv.slice(3)];
|
|
407
|
+
require('./musubi-upgrade.js');
|
|
408
|
+
});
|
|
409
|
+
|
|
395
410
|
// ============================================================================
|
|
396
411
|
// Command: info
|
|
397
412
|
// ============================================================================
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "musubi-sdd",
|
|
3
|
-
"version": "6.2.
|
|
3
|
+
"version": "6.2.2",
|
|
4
4
|
"description": "Ultimate Specification Driven Development Tool with 27 Agents for 7 AI Coding Platforms + MCP Integration (Claude Code, GitHub Copilot, Cursor, Gemini CLI, Windsurf, Codex, Qwen Code)",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -26,7 +26,8 @@
|
|
|
26
26
|
"musubi-gui": "bin/musubi-gui.js",
|
|
27
27
|
"musubi-orchestrate": "bin/musubi-orchestrate.js",
|
|
28
28
|
"musubi-release": "bin/musubi-release.js",
|
|
29
|
-
"musubi-config": "bin/musubi-config.js"
|
|
29
|
+
"musubi-config": "bin/musubi-config.js",
|
|
30
|
+
"musubi-upgrade": "bin/musubi-upgrade.js"
|
|
30
31
|
},
|
|
31
32
|
"scripts": {
|
|
32
33
|
"test": "jest",
|
|
@@ -73,7 +74,8 @@
|
|
|
73
74
|
"js-yaml": "^4.1.0",
|
|
74
75
|
"open": "^10.1.0",
|
|
75
76
|
"playwright": "^1.40.0",
|
|
76
|
-
"ws": "^8.14.2"
|
|
77
|
+
"ws": "^8.14.2",
|
|
78
|
+
"yaml": "^2.8.2"
|
|
77
79
|
},
|
|
78
80
|
"devDependencies": {
|
|
79
81
|
"eslint": "^8.50.0",
|