musubi-sdd 5.9.2 → 5.9.3

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.
@@ -15,10 +15,7 @@ const chalk = require('chalk');
15
15
 
16
16
  const program = new Command();
17
17
 
18
- program
19
- .name('musubi-config')
20
- .description('MUSUBI Project Configuration Manager')
21
- .version('1.0.0');
18
+ program.name('musubi-config').description('MUSUBI Project Configuration Manager').version('1.0.0');
22
19
 
23
20
  program
24
21
  .command('validate')
@@ -57,7 +54,8 @@ program
57
54
  console.log(chalk.green('\nāœ… Configuration is valid'));
58
55
  }
59
56
 
60
- const exitCode = result.errors.length > 0 || (options.strict && result.warnings.length > 0) ? 1 : 0;
57
+ const exitCode =
58
+ result.errors.length > 0 || (options.strict && result.warnings.length > 0) ? 1 : 0;
61
59
  process.exit(exitCode);
62
60
  } catch (error) {
63
61
  console.error(chalk.red(`Error: ${error.message}`));
@@ -56,7 +56,7 @@ async function getCurrentVersion() {
56
56
  */
57
57
  function bumpVersion(version, type) {
58
58
  const parts = version.split('.').map(Number);
59
-
59
+
60
60
  switch (type) {
61
61
  case 'major':
62
62
  return `${parts[0] + 1}.0.0`;
@@ -78,19 +78,19 @@ function bumpVersion(version, type) {
78
78
  */
79
79
  async function preReleaseChecks(options) {
80
80
  const checks = [];
81
-
81
+
82
82
  // Check for uncommitted changes
83
83
  if (!options.skipGitCheck) {
84
84
  try {
85
- const status = execSync('git status --porcelain', {
86
- cwd: projectRoot,
87
- encoding: 'utf8'
85
+ const status = execSync('git status --porcelain', {
86
+ cwd: projectRoot,
87
+ encoding: 'utf8',
88
88
  });
89
89
  if (status.trim()) {
90
- checks.push({
91
- name: 'Uncommitted changes',
92
- passed: false,
93
- message: 'You have uncommitted changes'
90
+ checks.push({
91
+ name: 'Uncommitted changes',
92
+ passed: false,
93
+ message: 'You have uncommitted changes',
94
94
  });
95
95
  } else {
96
96
  checks.push({ name: 'Git status', passed: true });
@@ -99,7 +99,7 @@ async function preReleaseChecks(options) {
99
99
  checks.push({ name: 'Git status', passed: false, message: 'Git not available' });
100
100
  }
101
101
  }
102
-
102
+
103
103
  // Run tests
104
104
  if (!options.skipTests) {
105
105
  try {
@@ -110,7 +110,7 @@ async function preReleaseChecks(options) {
110
110
  checks.push({ name: 'Tests', passed: false, message: 'Tests failed' });
111
111
  }
112
112
  }
113
-
113
+
114
114
  // Check coverage (if available)
115
115
  if (!options.skipCoverage) {
116
116
  try {
@@ -119,18 +119,18 @@ async function preReleaseChecks(options) {
119
119
  const coverage = JSON.parse(await fs.readFile(coveragePath, 'utf8'));
120
120
  const totalCoverage = coverage.total?.lines?.pct || 0;
121
121
  const threshold = options.coverageThreshold || 70;
122
-
122
+
123
123
  if (totalCoverage >= threshold) {
124
- checks.push({
125
- name: 'Coverage',
126
- passed: true,
127
- message: `${totalCoverage}% >= ${threshold}%`
124
+ checks.push({
125
+ name: 'Coverage',
126
+ passed: true,
127
+ message: `${totalCoverage}% >= ${threshold}%`,
128
128
  });
129
129
  } else {
130
- checks.push({
131
- name: 'Coverage',
132
- passed: false,
133
- message: `${totalCoverage}% < ${threshold}%`
130
+ checks.push({
131
+ name: 'Coverage',
132
+ passed: false,
133
+ message: `${totalCoverage}% < ${threshold}%`,
134
134
  });
135
135
  }
136
136
  }
@@ -138,7 +138,7 @@ async function preReleaseChecks(options) {
138
138
  // Coverage check optional
139
139
  }
140
140
  }
141
-
141
+
142
142
  return checks;
143
143
  }
144
144
 
@@ -147,9 +147,9 @@ async function preReleaseChecks(options) {
147
147
  */
148
148
  function createGitTag(version, message) {
149
149
  try {
150
- execSync(`git tag -a v${version} -m "${message}"`, {
151
- cwd: projectRoot,
152
- encoding: 'utf8'
150
+ execSync(`git tag -a v${version} -m "${message}"`, {
151
+ cwd: projectRoot,
152
+ encoding: 'utf8',
153
153
  });
154
154
  return true;
155
155
  } catch (error) {
@@ -184,7 +184,7 @@ function publishToNpm(options = {}) {
184
184
  if (options.access) cmd += ` --access ${options.access}`;
185
185
  if (options.tag) cmd += ` --tag ${options.tag}`;
186
186
  if (options.dryRun) cmd += ' --dry-run';
187
-
187
+
188
188
  execSync(cmd, { cwd: projectRoot, stdio: 'inherit' });
189
189
  return true;
190
190
  } catch (error) {
@@ -212,41 +212,43 @@ program
212
212
  .action(async (type, options) => {
213
213
  try {
214
214
  console.log(chalk.bold('\nšŸš€ MUSUBI Release Manager\n'));
215
-
215
+
216
216
  // Get current version
217
217
  const currentVersion = await getCurrentVersion();
218
218
  const newVersion = bumpVersion(currentVersion, type);
219
-
219
+
220
220
  console.log(chalk.white(` Current version: ${chalk.gray(currentVersion)}`));
221
221
  console.log(chalk.white(` New version: ${chalk.cyan(newVersion)}`));
222
222
  console.log();
223
-
223
+
224
224
  // Pre-release checks
225
225
  console.log(chalk.bold('šŸ“‹ Pre-release checks:\n'));
226
226
  const checks = await preReleaseChecks(options);
227
-
227
+
228
228
  let allPassed = true;
229
229
  for (const check of checks) {
230
230
  if (check.passed) {
231
- console.log(chalk.green(` āœ… ${check.name}${check.message ? `: ${check.message}` : ''}`));
231
+ console.log(
232
+ chalk.green(` āœ… ${check.name}${check.message ? `: ${check.message}` : ''}`)
233
+ );
232
234
  } else {
233
235
  console.log(chalk.red(` āŒ ${check.name}: ${check.message}`));
234
236
  allPassed = false;
235
237
  }
236
238
  }
237
-
239
+
238
240
  if (!allPassed && !options.dryRun) {
239
241
  console.log(chalk.red('\nāŒ Pre-release checks failed. Use --skip-* options to bypass.'));
240
242
  process.exit(1);
241
243
  }
242
-
244
+
243
245
  if (options.dryRun) {
244
246
  console.log(chalk.yellow('\nšŸ” Dry run - no changes made'));
245
247
  return;
246
248
  }
247
-
249
+
248
250
  console.log();
249
-
251
+
250
252
  // Update package.json
251
253
  console.log(chalk.white(' šŸ“¦ Updating package.json...'));
252
254
  const pkg = await readPackageJson();
@@ -255,7 +257,7 @@ program
255
257
  await writePackageJson(pkg);
256
258
  console.log(chalk.green(' Done'));
257
259
  }
258
-
260
+
259
261
  // Update CHANGELOG
260
262
  if (!options.skipChangelog) {
261
263
  console.log(chalk.white(' šŸ“ Updating CHANGELOG...'));
@@ -263,7 +265,7 @@ program
263
265
  const result = await generator.update(newVersion);
264
266
  console.log(chalk.green(` Added ${result.commitCount} commits`));
265
267
  }
266
-
268
+
267
269
  // Git commit
268
270
  console.log(chalk.white(' šŸ’¾ Committing changes...'));
269
271
  execSync(`git add -A && git commit -m "chore(release): v${newVersion}"`, {
@@ -271,23 +273,22 @@ program
271
273
  encoding: 'utf8',
272
274
  });
273
275
  console.log(chalk.green(' Done'));
274
-
276
+
275
277
  // Create tag
276
278
  if (options.tag !== false) {
277
279
  console.log(chalk.white(' šŸ·ļø Creating git tag...'));
278
280
  createGitTag(newVersion, `Release v${newVersion}`);
279
281
  console.log(chalk.green(' Done'));
280
282
  }
281
-
283
+
282
284
  // Push
283
285
  if (options.push !== false) {
284
286
  console.log(chalk.white(' ā¬†ļø Pushing to remote...'));
285
287
  pushToRemote(options.tag !== false);
286
288
  console.log(chalk.green(' Done'));
287
289
  }
288
-
290
+
289
291
  console.log(chalk.green(`\nāœ… Released v${newVersion}!\n`));
290
-
291
292
  } catch (error) {
292
293
  console.error(chalk.red(`\nāŒ Error: ${error.message}`));
293
294
  process.exit(1);
@@ -300,9 +301,9 @@ program
300
301
  .option('--access <access>', 'Package access level (public/restricted)')
301
302
  .option('--tag <tag>', 'npm dist-tag')
302
303
  .option('--dry-run', 'Run npm publish --dry-run')
303
- .action(async (options) => {
304
+ .action(async options => {
304
305
  console.log(chalk.bold('\nšŸ“¦ Publishing to npm...\n'));
305
-
306
+
306
307
  const success = publishToNpm(options);
307
308
  if (success) {
308
309
  console.log(chalk.green('\nāœ… Published successfully!'));
@@ -316,25 +317,25 @@ program
316
317
  .description('Generate or update CHANGELOG')
317
318
  .option('-v, --version <version>', 'Version for the changelog entry')
318
319
  .option('-f, --from <tag>', 'Starting tag for commit range')
319
- .action(async (options) => {
320
+ .action(async options => {
320
321
  try {
321
322
  console.log(chalk.bold('\nšŸ“ Generating CHANGELOG...\n'));
322
-
323
+
323
324
  const generator = new ChangelogGenerator(projectRoot);
324
325
  const version = options.version || (await getCurrentVersion());
325
326
  const result = await generator.update(version, options.from);
326
-
327
+
327
328
  console.log(chalk.white(` Version: ${result.version}`));
328
329
  console.log(chalk.white(` Commits: ${result.commitCount}`));
329
330
  console.log();
330
-
331
+
331
332
  // Show category breakdown
332
333
  for (const [category, commits] of Object.entries(result.categories)) {
333
334
  if (commits.length > 0) {
334
335
  console.log(chalk.gray(` ${category}: ${commits.length}`));
335
336
  }
336
337
  }
337
-
338
+
338
339
  console.log(chalk.green('\nāœ… CHANGELOG updated!'));
339
340
  } catch (error) {
340
341
  console.error(chalk.red(`\nāŒ Error: ${error.message}`));
@@ -348,12 +349,12 @@ program
348
349
  .option('-v, --version <version>', 'Version for the release notes')
349
350
  .option('-f, --from <tag>', 'Starting tag for commit range')
350
351
  .option('-o, --output <file>', 'Output file (default: stdout)')
351
- .action(async (options) => {
352
+ .action(async options => {
352
353
  try {
353
354
  const generator = new ChangelogGenerator(projectRoot);
354
355
  const version = options.version || (await getCurrentVersion());
355
356
  const notes = generator.generateReleaseNotes(version, options.from);
356
-
357
+
357
358
  if (options.output) {
358
359
  await fs.writeFile(options.output, notes, 'utf8');
359
360
  console.log(chalk.green(`āœ… Release notes written to ${options.output}`));
@@ -372,10 +373,10 @@ program
372
373
  .action(async () => {
373
374
  try {
374
375
  console.log(chalk.bold('\nšŸ“Š Release Status\n'));
375
-
376
+
376
377
  const currentVersion = await getCurrentVersion();
377
378
  console.log(chalk.white(` Current version: ${chalk.cyan(currentVersion)}`));
378
-
379
+
379
380
  // Get last tag
380
381
  try {
381
382
  const lastTag = execSync('git describe --tags --abbrev=0', {
@@ -383,7 +384,7 @@ program
383
384
  encoding: 'utf8',
384
385
  }).trim();
385
386
  console.log(chalk.white(` Last tag: ${chalk.gray(lastTag)}`));
386
-
387
+
387
388
  // Count commits since last tag
388
389
  const commitCount = execSync(`git rev-list ${lastTag}..HEAD --count`, {
389
390
  cwd: projectRoot,
@@ -393,7 +394,7 @@ program
393
394
  } catch {
394
395
  console.log(chalk.gray(' No tags found'));
395
396
  }
396
-
397
+
397
398
  // Check for uncommitted changes
398
399
  const status = execSync('git status --porcelain', {
399
400
  cwd: projectRoot,
@@ -404,7 +405,7 @@ program
404
405
  } else {
405
406
  console.log(chalk.green(' Uncommitted changes: No'));
406
407
  }
407
-
408
+
408
409
  console.log();
409
410
  } catch (error) {
410
411
  console.error(chalk.red(`\nāŒ Error: ${error.message}`));
@@ -58,10 +58,14 @@ async function showStatus() {
58
58
 
59
59
  console.log(chalk.bold('\nšŸ“Š Workflow Status\n'));
60
60
  console.log(chalk.white(`Feature: ${chalk.cyan(state.feature)}`));
61
- console.log(chalk.white(`Mode: ${chalk.magenta(state.mode || 'default')} (${getModeDescription(state.mode || 'medium')})`));
61
+ console.log(
62
+ chalk.white(
63
+ `Mode: ${chalk.magenta(state.mode || 'default')} (${getModeDescription(state.mode || 'medium')})`
64
+ )
65
+ );
62
66
  console.log(chalk.white(`Current Stage: ${formatStage(state.currentStage)}`));
63
67
  console.log(chalk.white(`Started: ${new Date(state.startedAt).toLocaleString()}`));
64
-
68
+
65
69
  // Show mode config
66
70
  if (state.config) {
67
71
  console.log(chalk.bold('\nāš™ļø Mode Configuration:'));
@@ -83,7 +87,7 @@ async function showStatus() {
83
87
  } else {
84
88
  stagesToShow = Object.keys(WORKFLOW_STAGES);
85
89
  }
86
-
90
+
87
91
  const currentIndex = stagesToShow.indexOf(state.currentStage);
88
92
 
89
93
  stagesToShow.forEach((stage, index) => {
@@ -200,19 +204,22 @@ program
200
204
  .command('init <feature>')
201
205
  .description('Initialize a new workflow for a feature')
202
206
  .option('-s, --stage <stage>', 'Starting stage (auto-detected based on mode)')
203
- .option('-m, --mode <mode>', 'Workflow mode: small, medium, or large (auto-detected from feature name)')
207
+ .option(
208
+ '-m, --mode <mode>',
209
+ 'Workflow mode: small, medium, or large (auto-detected from feature name)'
210
+ )
204
211
  .action(async (feature, options) => {
205
212
  try {
206
213
  const initOptions = {};
207
214
  if (options.stage) initOptions.startStage = options.stage;
208
215
  if (options.mode) initOptions.mode = options.mode;
209
-
216
+
210
217
  const state = await engine.initWorkflow(feature, initOptions);
211
218
  console.log(chalk.green(`\nāœ… Workflow initialized for "${feature}"`));
212
219
  console.log(chalk.cyan(` Mode: ${state.mode} (${getModeDescription(state.mode)})`));
213
220
  console.log(chalk.cyan(` Starting: ${formatStage(state.currentStage)}`));
214
221
  console.log(chalk.gray(` Coverage: ${state.config.coverageThreshold}%`));
215
-
222
+
216
223
  // Show stages for this mode
217
224
  const modeManager = engine.getModeManager();
218
225
  const stages = await modeManager.getStages(state.mode);
@@ -235,9 +242,9 @@ program
235
242
  .action(async () => {
236
243
  const modeManager = engine.getModeManager();
237
244
  const modes = await modeManager.compareModes();
238
-
245
+
239
246
  console.log(chalk.bold('\nšŸ“Š Available Workflow Modes\n'));
240
-
247
+
241
248
  modes.forEach(mode => {
242
249
  console.log(chalk.bold.cyan(` ${mode.name.toUpperCase()}`));
243
250
  console.log(chalk.white(` ${mode.description}`));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "musubi-sdd",
3
- "version": "5.9.2",
3
+ "version": "5.9.3",
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": {
@@ -270,10 +270,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
270
270
  const existingContent = await this.readChangelog();
271
271
 
272
272
  // Find insertion point (after header, before first version)
273
- const headerEndMatch = existingContent.match(
274
- /# Changelog[\s\S]*?(?=\n## \[|$)/
275
- );
276
-
273
+ const headerEndMatch = existingContent.match(/# Changelog[\s\S]*?(?=\n## \[|$)/);
274
+
277
275
  let newContent;
278
276
  if (headerEndMatch) {
279
277
  const headerEnd = headerEndMatch[0].length;
package/src/index.js CHANGED
@@ -61,7 +61,11 @@ const { ConstitutionalValidator } = require('./validators/constitutional-validat
61
61
  const { Constitution } = require('./validators/constitution');
62
62
  const { DeltaFormatValidator } = require('./validators/delta-format');
63
63
  const { TraceabilityValidator } = require('./validators/traceability-validator');
64
- const { ConstitutionLevelManager, EnforcementLevel, ArticleId } = require('./validators/constitution-level-manager');
64
+ const {
65
+ ConstitutionLevelManager,
66
+ EnforcementLevel,
67
+ ArticleId,
68
+ } = require('./validators/constitution-level-manager');
65
69
  const { ProjectValidator, DEFAULT_PROJECT_CONFIG } = require('./validators/project-validator');
66
70
 
67
71
  // Orchestration
@@ -78,7 +82,11 @@ const { DeltaSpecManager } = require('./managers/delta-spec');
78
82
  const { MemoryCondenser } = require('./managers/memory-condenser');
79
83
  const { SkillLoader } = require('./managers/skill-loader');
80
84
  const { WorkflowModeManager, DEFAULT_MODES } = require('./managers/workflow-mode-manager');
81
- const { PackageManager, PackageType, DEFAULT_COVERAGE_TARGETS } = require('./managers/package-manager');
85
+ const {
86
+ PackageManager,
87
+ PackageType,
88
+ DEFAULT_COVERAGE_TARGETS,
89
+ } = require('./managers/package-manager');
82
90
 
83
91
  // Monitoring
84
92
  const { CostTracker } = require('./monitoring/cost-tracker');
@@ -8,7 +8,7 @@
8
8
  const fs = require('fs-extra');
9
9
  const path = require('path');
10
10
  const yaml = require('js-yaml');
11
- const { execSync } = require('child_process');
11
+ const { execSync: _execSync } = require('child_process');
12
12
 
13
13
  /**
14
14
  * Package types
@@ -195,7 +195,7 @@ class PackageManager {
195
195
  if (this._packages) return this._packages;
196
196
 
197
197
  const config = await this.loadConfig();
198
-
198
+
199
199
  if (config.packages && config.packages.length > 0) {
200
200
  this._packages = config.packages;
201
201
  } else {
@@ -283,9 +283,7 @@ class PackageManager {
283
283
  // Add edges for internal dependencies
284
284
  const deps = [
285
285
  ...(pkg.dependencies || []),
286
- ...(config.dependency_graph?.ignore_dev_dependencies
287
- ? []
288
- : (pkg.devDependencies || [])),
286
+ ...(config.dependency_graph?.ignore_dev_dependencies ? [] : pkg.devDependencies || []),
289
287
  ];
290
288
 
291
289
  for (const dep of deps) {
@@ -131,13 +131,13 @@ class WorkflowEngine {
131
131
  // Normalize stage name (handle aliases)
132
132
  const normalizedTarget = STAGE_ALIASES[targetStage] || targetStage;
133
133
  const currentStage = state.currentStage;
134
-
134
+
135
135
  // Get valid transitions based on mode
136
136
  let validTransitions;
137
137
  if (state.mode) {
138
138
  validTransitions = await this.modeManager.getValidTransitions(state.mode, currentStage);
139
139
  }
140
-
140
+
141
141
  // Fall back to full transitions if mode-specific not available
142
142
  if (!validTransitions || validTransitions.length === 0) {
143
143
  validTransitions = WORKFLOW_STAGES[currentStage]?.next || [];
@@ -400,7 +400,7 @@ class WorkflowEngine {
400
400
  async getValidTransitions() {
401
401
  const state = await this.getState();
402
402
  if (!state) return [];
403
-
403
+
404
404
  // Use mode-specific transitions if available
405
405
  if (state.mode) {
406
406
  const modeTransitions = await this.modeManager.getValidTransitions(
@@ -411,7 +411,7 @@ class WorkflowEngine {
411
411
  return modeTransitions;
412
412
  }
413
413
  }
414
-
414
+
415
415
  return WORKFLOW_STAGES[state.currentStage]?.next || [];
416
416
  }
417
417
 
@@ -66,7 +66,12 @@ const workflowModeSkill = {
66
66
  inputs: [
67
67
  { name: 'action', type: 'string', description: 'get|detect|compare', required: true },
68
68
  { name: 'mode', type: 'string', description: 'small|medium|large', required: false },
69
- { name: 'featureName', type: 'string', description: 'Feature name for auto-detection', required: false },
69
+ {
70
+ name: 'featureName',
71
+ type: 'string',
72
+ description: 'Feature name for auto-detection',
73
+ required: false,
74
+ },
70
75
  { name: 'projectPath', type: 'string', description: 'Project root path', required: false },
71
76
  ],
72
77
  outputs: [
@@ -113,7 +118,12 @@ const packageManagerSkill = {
113
118
  tags: ['package', 'monorepo', 'dependency', 'coverage', 'graph'],
114
119
  inputs: [
115
120
  { name: 'action', type: 'string', description: 'list|graph|validate|coverage', required: true },
116
- { name: 'packageName', type: 'string', description: 'Package name for coverage lookup', required: false },
121
+ {
122
+ name: 'packageName',
123
+ type: 'string',
124
+ description: 'Package name for coverage lookup',
125
+ required: false,
126
+ },
117
127
  { name: 'projectPath', type: 'string', description: 'Project root path', required: false },
118
128
  ],
119
129
  outputs: [
@@ -163,8 +173,18 @@ const constitutionLevelSkill = {
163
173
  tags: ['constitution', 'governance', 'critical', 'advisory', 'flexible', 'articles'],
164
174
  inputs: [
165
175
  { name: 'action', type: 'string', description: 'summary|level|validate', required: true },
166
- { name: 'articleId', type: 'string', description: 'Article ID (e.g., CONST-001)', required: false },
167
- { name: 'validation', type: 'object', description: 'Validation results object', required: false },
176
+ {
177
+ name: 'articleId',
178
+ type: 'string',
179
+ description: 'Article ID (e.g., CONST-001)',
180
+ required: false,
181
+ },
182
+ {
183
+ name: 'validation',
184
+ type: 'object',
185
+ description: 'Validation results object',
186
+ required: false,
187
+ },
168
188
  { name: 'projectPath', type: 'string', description: 'Project root path', required: false },
169
189
  ],
170
190
  outputs: [
@@ -240,7 +260,12 @@ const projectConfigSkill = {
240
260
  if (!input.dryRun && result.migrated) {
241
261
  await validator.saveConfig(result.config);
242
262
  }
243
- return { success: true, migrated: result.migrated, config: result.config, dryRun: input.dryRun };
263
+ return {
264
+ success: true,
265
+ migrated: result.migrated,
266
+ config: result.config,
267
+ dryRun: input.dryRun,
268
+ };
244
269
  }
245
270
  case 'show': {
246
271
  const report = await validator.generateReport();
@@ -107,9 +107,9 @@ const SkillCategory = {
107
107
  VALIDATION: 'validation',
108
108
  INTEGRATION: 'integration',
109
109
  MONITORING: 'monitoring',
110
- RELEASE: 'release', // Added for release management
110
+ RELEASE: 'release', // Added for release management
111
111
  CONFIGURATION: 'configuration', // Added for project configuration
112
- WORKFLOW: 'workflow', // Added for workflow management
112
+ WORKFLOW: 'workflow', // Added for workflow management
113
113
  GENERAL: 'general',
114
114
  };
115
115
 
@@ -39,7 +39,20 @@
39
39
  "description": "Programming languages used",
40
40
  "items": {
41
41
  "type": "string",
42
- "enum": ["javascript", "typescript", "python", "rust", "go", "java", "ruby", "markdown", "yaml", "json", "cobol", "shell"]
42
+ "enum": [
43
+ "javascript",
44
+ "typescript",
45
+ "python",
46
+ "rust",
47
+ "go",
48
+ "java",
49
+ "ruby",
50
+ "markdown",
51
+ "yaml",
52
+ "json",
53
+ "cobol",
54
+ "shell"
55
+ ]
43
56
  }
44
57
  },
45
58
  "frameworks": {
@@ -73,7 +86,10 @@
73
86
  "naming_conventions": {
74
87
  "type": "object",
75
88
  "properties": {
76
- "files": { "type": "string", "enum": ["kebab-case", "camelCase", "PascalCase", "snake_case"] },
89
+ "files": {
90
+ "type": "string",
91
+ "enum": ["kebab-case", "camelCase", "PascalCase", "snake_case"]
92
+ },
77
93
  "classes": { "type": "string", "enum": ["PascalCase", "camelCase"] },
78
94
  "functions": { "type": "string", "enum": ["camelCase", "snake_case"] },
79
95
  "constants": { "type": "string", "enum": ["UPPER_SNAKE_CASE", "camelCase"] }
@@ -183,7 +199,10 @@
183
199
  "format": { "type": "string", "enum": ["keep-a-changelog", "conventional"] },
184
200
  "include_types": {
185
201
  "type": "array",
186
- "items": { "type": "string", "enum": ["feat", "fix", "docs", "style", "refactor", "test", "chore"] }
202
+ "items": {
203
+ "type": "string",
204
+ "enum": ["feat", "fix", "docs", "style", "refactor", "test", "chore"]
205
+ }
187
206
  }
188
207
  }
189
208
  },
@@ -208,10 +227,7 @@
208
227
  "properties": {
209
228
  "coverage_threshold": { "type": "integer", "minimum": 50, "maximum": 100 },
210
229
  "mock_allowed": {
211
- "oneOf": [
212
- { "type": "boolean" },
213
- { "type": "array", "items": { "type": "string" } }
214
- ]
230
+ "oneOf": [{ "type": "boolean" }, { "type": "array", "items": { "type": "string" } }]
215
231
  },
216
232
  "ears_required": { "type": "boolean" },
217
233
  "adr_required": { "type": "boolean" }
@@ -13,8 +13,8 @@ const yaml = require('js-yaml');
13
13
  * Enforcement levels
14
14
  */
15
15
  const EnforcementLevel = {
16
- BLOCK: 'block', // Violations block progress
17
- WARN: 'warn', // Violations show warnings
16
+ BLOCK: 'block', // Violations block progress
17
+ WARN: 'warn', // Violations show warnings
18
18
  CONFIGURE: 'configurable', // Can be overridden per project
19
19
  };
20
20
 
@@ -15,7 +15,7 @@ const glob = require('glob');
15
15
  const {
16
16
  ConstitutionLevelManager,
17
17
  ArticleId,
18
- EnforcementLevel,
18
+ EnforcementLevel: _EnforcementLevel,
19
19
  } = require('./constitution-level-manager');
20
20
 
21
21
  class ConstitutionalValidator {
@@ -165,10 +165,8 @@ class ConstitutionalValidator {
165
165
  for (const lib of subDirs) {
166
166
  // Check multiple possible test directory names
167
167
  const testDirs = ['tests', 'test', '__tests__'];
168
- const hasTestDir = testDirs.some(dir =>
169
- fs.existsSync(path.join(libPath, lib, dir))
170
- );
171
-
168
+ const hasTestDir = testDirs.some(dir => fs.existsSync(path.join(libPath, lib, dir)));
169
+
172
170
  // Check for test files in the library root or test subdirectories
173
171
  const testFile = glob.sync(path.join(libPath, lib, '**/*.test.{js,ts}'));
174
172
  const specFile = glob.sync(path.join(libPath, lib, '**/*.spec.{js,ts}'));
@@ -427,13 +425,7 @@ class ConstitutionalValidator {
427
425
  `Create steering/${file}`
428
426
  );
429
427
  } else {
430
- this._recordFinding(
431
- articleId,
432
- articleName,
433
- true,
434
- `Found steering/${file}`,
435
- null
436
- );
428
+ this._recordFinding(articleId, articleName, true, `Found steering/${file}`, null);
437
429
  }
438
430
  }
439
431
  }
@@ -565,7 +557,8 @@ class ConstitutionalValidator {
565
557
 
566
558
  for (const file of testFiles) {
567
559
  const content = fs.readFileSync(file, 'utf-8');
568
- const mockMatches = content.match(/\b(jest\.mock|sinon\.stub|vi\.mock|mock\()\s*\(['"]([^'"]+)['"]\)/g) || [];
560
+ const mockMatches =
561
+ content.match(/\b(jest\.mock|sinon\.stub|vi\.mock|mock\()\s*\(['"]([^'"]+)['"]\)/g) || [];
569
562
 
570
563
  for (const match of mockMatches) {
571
564
  const isAllowed = allowedMockPatterns.some(pattern =>
@@ -667,7 +660,9 @@ class ConstitutionalValidator {
667
660
  console.log(
668
661
  `Passes: ${report.summary.passes} | Warnings: ${report.summary.warnings} | Violations: ${report.summary.violations}`
669
662
  );
670
- console.log(`Critical: ${criticalViolations.length} | Advisory: ${nonBlockingViolations.length}`);
663
+ console.log(
664
+ `Critical: ${criticalViolations.length} | Advisory: ${nonBlockingViolations.length}`
665
+ );
671
666
 
672
667
  if (criticalViolations.length > 0) {
673
668
  console.log('\n🚫 CRITICAL VIOLATIONS (blocking):');