musubi-sdd 6.2.1 → 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/bin/musubi-dashboard.js +1 -1
- package/bin/musubi-upgrade.js +395 -0
- package/bin/musubi.js +15 -0
- package/package.json +3 -2
- package/src/constitutional/ci-reporter.js +8 -6
- package/src/constitutional/phase-minus-one.js +2 -2
- package/src/constitutional/steering-sync.js +1 -1
- package/src/dashboard/sprint-reporter.js +1 -1
- package/src/dashboard/workflow-dashboard.js +1 -1
- package/src/enterprise/experiment-report.js +1 -1
- package/src/traceability/extractor.js +1 -1
package/bin/musubi-dashboard.js
CHANGED
|
@@ -21,7 +21,7 @@ const { DashboardCLI } = require('../src/cli/dashboard-cli');
|
|
|
21
21
|
const args = process.argv.slice(2);
|
|
22
22
|
const command = args[0];
|
|
23
23
|
const subcommand = args[1];
|
|
24
|
-
const
|
|
24
|
+
const _feature = args[2] || args[1];
|
|
25
25
|
|
|
26
26
|
// Parse options
|
|
27
27
|
const options = {};
|
|
@@ -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",
|
|
@@ -218,11 +218,13 @@ class CIReporter {
|
|
|
218
218
|
}
|
|
219
219
|
}
|
|
220
220
|
|
|
221
|
-
// Set output
|
|
221
|
+
// Set output using Environment Files (GITHUB_OUTPUT)
|
|
222
|
+
// Note: In GitHub Actions, these would be written to $GITHUB_OUTPUT file
|
|
223
|
+
// Format: echo "name=value" >> $GITHUB_OUTPUT
|
|
222
224
|
lines.push('');
|
|
223
|
-
lines.push(
|
|
224
|
-
lines.push(
|
|
225
|
-
lines.push(
|
|
225
|
+
lines.push(`violations=${results.summary.totalViolations}`);
|
|
226
|
+
lines.push(`blocked=${blockDecision.shouldBlock}`);
|
|
227
|
+
lines.push(`phase_minus_one=${blockDecision.requiresPhaseMinusOne}`);
|
|
226
228
|
|
|
227
229
|
return lines.join('\n');
|
|
228
230
|
}
|
|
@@ -230,10 +232,10 @@ class CIReporter {
|
|
|
230
232
|
/**
|
|
231
233
|
* Format as JUnit XML
|
|
232
234
|
* @param {Object} results - Check results
|
|
233
|
-
* @param {Object}
|
|
235
|
+
* @param {Object} _blockDecision - Block decision (unused, for interface compatibility)
|
|
234
236
|
* @returns {string} JUnit XML
|
|
235
237
|
*/
|
|
236
|
-
formatJUnit(results,
|
|
238
|
+
formatJUnit(results, _blockDecision) {
|
|
237
239
|
const lines = [];
|
|
238
240
|
|
|
239
241
|
lines.push('<?xml version="1.0" encoding="UTF-8"?>');
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
const fs = require('fs').promises;
|
|
11
11
|
const path = require('path');
|
|
12
|
-
const { ConstitutionalChecker
|
|
12
|
+
const { ConstitutionalChecker } = require('./checker');
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* Default configuration
|
|
@@ -51,7 +51,7 @@ class PhaseMinusOneGate {
|
|
|
51
51
|
* @returns {Promise<Object>} Gate record
|
|
52
52
|
*/
|
|
53
53
|
async trigger(options) {
|
|
54
|
-
const gateId = `GATE-${Date.now()}`;
|
|
54
|
+
const gateId = `GATE-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
55
55
|
|
|
56
56
|
const gate = {
|
|
57
57
|
id: gateId,
|
|
@@ -102,7 +102,7 @@ class SteeringSync {
|
|
|
102
102
|
// Check for orphaned references
|
|
103
103
|
if (structure) {
|
|
104
104
|
// Check if directories mentioned in structure.md exist
|
|
105
|
-
const dirPattern = /`([a-z
|
|
105
|
+
const dirPattern = /`([a-z-]+\/)`/g;
|
|
106
106
|
let match;
|
|
107
107
|
while ((match = dirPattern.exec(structure)) !== null) {
|
|
108
108
|
const dirName = match[1].replace('/', '');
|
|
@@ -37,7 +37,7 @@ class SprintReporter {
|
|
|
37
37
|
*/
|
|
38
38
|
async generateReport(sprint) {
|
|
39
39
|
const report = {
|
|
40
|
-
id: `RPT-${sprint.id}-${Date.now()}`,
|
|
40
|
+
id: `RPT-${sprint.id}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
|
|
41
41
|
sprintId: sprint.id,
|
|
42
42
|
sprintName: sprint.name,
|
|
43
43
|
featureId: sprint.featureId,
|
|
@@ -230,7 +230,7 @@ class WorkflowDashboard {
|
|
|
230
230
|
|
|
231
231
|
const actions = [];
|
|
232
232
|
const currentStage = workflow.currentStage;
|
|
233
|
-
const
|
|
233
|
+
const _stageData = workflow.stages[currentStage];
|
|
234
234
|
|
|
235
235
|
// Check for blockers
|
|
236
236
|
const unresolvedBlockers = workflow.blockers.filter(b => !b.resolvedAt);
|
|
@@ -393,7 +393,7 @@ class ExperimentReportGenerator {
|
|
|
393
393
|
* @returns {string} HTML content
|
|
394
394
|
*/
|
|
395
395
|
formatHTML(report) {
|
|
396
|
-
const { metadata, summary, testResults,
|
|
396
|
+
const { metadata, summary, testResults, observations, conclusions } = report;
|
|
397
397
|
|
|
398
398
|
return `<!DOCTYPE html>
|
|
399
399
|
<html lang="en">
|
|
@@ -120,7 +120,7 @@ class TraceabilityExtractor {
|
|
|
120
120
|
const lines = stdout.trim().split('\n').filter(l => l.length > 0);
|
|
121
121
|
|
|
122
122
|
for (const line of lines) {
|
|
123
|
-
const [hash, message
|
|
123
|
+
const [hash, message] = line.split('|');
|
|
124
124
|
|
|
125
125
|
for (const pattern of REQ_PATTERNS) {
|
|
126
126
|
pattern.lastIndex = 0;
|