universal-dev-standards 3.5.0-beta.4 → 3.5.0-beta.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "universal-dev-standards",
3
- "version": "3.5.0-beta.4",
3
+ "version": "3.5.0-beta.5",
4
4
  "description": "CLI tool for adopting Universal Development Standards",
5
5
  "keywords": [
6
6
  "documentation",
@@ -18,6 +18,11 @@ import {
18
18
  parseReferences,
19
19
  compareStandardsWithReferences
20
20
  } from '../utils/reference-sync.js';
21
+ import {
22
+ getToolFilePath,
23
+ getToolFormat,
24
+ extractMarkedContent
25
+ } from '../utils/integration-generator.js';
21
26
 
22
27
  /**
23
28
  * Check command - verify adoption status
@@ -211,6 +216,9 @@ export async function checkCommand(options = {}) {
211
216
  // Reference sync check
212
217
  checkReferenceSync(manifest, projectPath);
213
218
 
219
+ // Integration files check
220
+ checkIntegrationFiles(manifest, projectPath);
221
+
214
222
  // Skills status
215
223
  displaySkillsStatus(manifest, projectPath);
216
224
 
@@ -675,6 +683,132 @@ function displayCoverageReport(manifest) {
675
683
  console.log();
676
684
  }
677
685
 
686
+ /**
687
+ * Check AI tool integration files for standards coverage
688
+ */
689
+ function checkIntegrationFiles(manifest, projectPath) {
690
+ // Skip if no AI tools configured
691
+ if (!manifest.aiTools || manifest.aiTools.length === 0) {
692
+ return;
693
+ }
694
+
695
+ console.log(chalk.cyan('AI Tool Integration Status:'));
696
+
697
+ const standardsFiles = manifest.standards?.map(s => basename(s)) || [];
698
+ let hasIssues = false;
699
+ let checkedCount = 0;
700
+
701
+ // Standard filename to task mapping for coverage check
702
+ const STANDARD_TASK_MAPPING = {
703
+ 'anti-hallucination.md': 'AI collaboration',
704
+ 'commit-message.ai.yaml': 'Writing commits',
705
+ 'checkin-standards.md': 'Committing code',
706
+ 'logging-standards.md': 'Adding logging',
707
+ 'error-code-standards.md': 'Error handling',
708
+ 'testing.ai.yaml': 'Writing tests',
709
+ 'versioning.md': 'Version bumping',
710
+ 'changelog-standards.md': 'Updating changelog',
711
+ 'code-review-checklist.md': 'Code review',
712
+ 'spec-driven-development.md': 'Feature development',
713
+ 'test-completeness-dimensions.md': 'Test coverage',
714
+ 'git-workflow.ai.yaml': 'Git workflow'
715
+ };
716
+
717
+ for (const tool of manifest.aiTools) {
718
+ const toolFile = getToolFilePath(tool);
719
+ if (!toolFile) continue;
720
+
721
+ const fullPath = join(projectPath, toolFile);
722
+
723
+ // Check if file exists
724
+ if (!existsSync(fullPath)) {
725
+ console.log(chalk.red(` ✗ ${toolFile}: File not found`));
726
+ hasIssues = true;
727
+ continue;
728
+ }
729
+
730
+ checkedCount++;
731
+
732
+ // Read file content
733
+ let content;
734
+ try {
735
+ content = readFileSync(fullPath, 'utf-8');
736
+ } catch {
737
+ console.log(chalk.yellow(` ⚠ ${toolFile}: Could not read file`));
738
+ continue;
739
+ }
740
+
741
+ // Check for standards index marker
742
+ const format = getToolFormat(tool);
743
+ const { content: markedContent } = extractMarkedContent(content, format);
744
+ const hasStandardsIndex = markedContent.length > 0 ||
745
+ content.includes('Standards Index') ||
746
+ content.includes('Standards Compliance');
747
+
748
+ // Count referenced standards
749
+ const referencedStandards = [];
750
+ const missingStandards = [];
751
+
752
+ for (const stdFile of standardsFiles) {
753
+ // Check if standard is referenced in the file
754
+ const isReferenced = content.includes(stdFile) ||
755
+ content.includes(`.standards/${stdFile}`) ||
756
+ content.includes(`standards/${stdFile}`);
757
+
758
+ if (isReferenced) {
759
+ referencedStandards.push(stdFile);
760
+ } else if (STANDARD_TASK_MAPPING[stdFile]) {
761
+ // Only report as missing if it's a known trackable standard
762
+ missingStandards.push(stdFile);
763
+ }
764
+ }
765
+
766
+ // Report status
767
+ const totalTrackable = Object.keys(STANDARD_TASK_MAPPING).filter(s =>
768
+ standardsFiles.includes(s)
769
+ ).length;
770
+
771
+ if (hasStandardsIndex && missingStandards.length === 0) {
772
+ console.log(chalk.green(` ✓ ${toolFile}:`));
773
+ console.log(chalk.gray(' Standards index present'));
774
+ console.log(chalk.gray(` ${referencedStandards.length}/${totalTrackable || standardsFiles.length} standards referenced`));
775
+ } else if (hasStandardsIndex) {
776
+ console.log(chalk.yellow(` ⚠ ${toolFile}:`));
777
+ console.log(chalk.gray(' Standards index present'));
778
+ console.log(chalk.yellow(` ${referencedStandards.length}/${totalTrackable} standards referenced`));
779
+ if (missingStandards.length > 0 && missingStandards.length <= 5) {
780
+ console.log(chalk.yellow(` Missing: ${missingStandards.join(', ')}`));
781
+ } else if (missingStandards.length > 5) {
782
+ console.log(chalk.yellow(` Missing: ${missingStandards.slice(0, 5).join(', ')}...`));
783
+ }
784
+ hasIssues = true;
785
+ } else {
786
+ // No standards index - using minimal mode
787
+ console.log(chalk.gray(` ℹ ${toolFile}:`));
788
+ console.log(chalk.gray(' Using minimal mode (no standards index)'));
789
+ const coreRules = content.includes('Anti-Hallucination') ||
790
+ content.includes('Commit') ||
791
+ content.includes('Code Review');
792
+ if (coreRules) {
793
+ console.log(chalk.gray(' Core rules embedded'));
794
+ }
795
+ }
796
+ }
797
+
798
+ if (checkedCount === 0) {
799
+ console.log(chalk.gray(' No AI tool integration files configured.'));
800
+ }
801
+
802
+ if (hasIssues) {
803
+ console.log();
804
+ console.log(chalk.yellow(' To fix integration issues:'));
805
+ console.log(chalk.gray(' • Run `uds update` to sync all integration files'));
806
+ console.log(chalk.gray(' • Run `uds configure --type ai_tools` to manage AI tools'));
807
+ }
808
+
809
+ console.log();
810
+ }
811
+
678
812
  /**
679
813
  * Check reference sync status between manifest standards and integration files
680
814
  */
@@ -1,9 +1,13 @@
1
1
  import chalk from 'chalk';
2
2
  import ora from 'ora';
3
+ import { unlinkSync, existsSync } from 'fs';
4
+ import { join, basename } from 'path';
3
5
  import {
4
6
  getOptionSource,
5
7
  findOption,
6
- getAllStandards
8
+ getAllStandards,
9
+ getStandardsByLevel,
10
+ getStandardSource
7
11
  } from '../utils/registry.js';
8
12
  import {
9
13
  copyStandard,
@@ -17,8 +21,16 @@ import {
17
21
  promptMergeStrategy,
18
22
  promptCommitLanguage,
19
23
  promptTestLevels,
20
- promptConfirm
24
+ promptConfirm,
25
+ promptManageAITools,
26
+ promptAdoptionLevel,
27
+ promptContentModeChange,
28
+ handleAgentsMdSharing
21
29
  } from '../prompts/init.js';
30
+ import {
31
+ writeIntegrationFile,
32
+ getToolFilePath
33
+ } from '../utils/integration-generator.js';
22
34
 
23
35
  /**
24
36
  * Configure command - modify options for initialized project
@@ -47,7 +59,10 @@ export async function configureCommand(options) {
47
59
 
48
60
  console.log();
49
61
  console.log(chalk.cyan('Current Configuration:'));
62
+ console.log(chalk.gray(` Level: ${manifest.level || 2}`));
50
63
  console.log(chalk.gray(` Format: ${manifest.format || 'human'}`));
64
+ console.log(chalk.gray(` Content Mode: ${manifest.contentMode || 'minimal'}`));
65
+ console.log(chalk.gray(` AI Tools: ${manifest.aiTools?.length > 0 ? manifest.aiTools.join(', ') : 'none'}`));
51
66
  if (manifest.options) {
52
67
  if (manifest.options.workflow) {
53
68
  console.log(chalk.gray(` Git Workflow: ${manifest.options.workflow}`));
@@ -80,6 +95,11 @@ export async function configureCommand(options) {
80
95
  { name: 'Merge Strategy', value: 'merge_strategy' },
81
96
  { name: 'Commit Message Language', value: 'commit_language' },
82
97
  { name: 'Test Levels', value: 'test_levels' },
98
+ new inquirer.default.Separator(),
99
+ { name: `${chalk.cyan('AI Tools')} - Add/Remove AI integrations`, value: 'ai_tools' },
100
+ { name: `${chalk.cyan('Adoption Level')} - Change Level 1/2/3`, value: 'level' },
101
+ { name: `${chalk.cyan('Content Mode')} - Change full/index/minimal`, value: 'content_mode' },
102
+ new inquirer.default.Separator(),
83
103
  { name: 'All Options', value: 'all' }
84
104
  ]
85
105
  }
@@ -90,7 +110,60 @@ export async function configureCommand(options) {
90
110
  // Collect new options
91
111
  const newOptions = { ...manifest.options };
92
112
  let newFormat = manifest.format;
113
+ let newLevel = manifest.level || 2;
114
+ let newContentMode = manifest.contentMode || 'minimal';
115
+ let newAITools = [...(manifest.aiTools || [])];
116
+ let needsIntegrationRegeneration = false;
117
+
118
+ // Handle AI Tools configuration
119
+ if (configType === 'ai_tools') {
120
+ const result = await promptManageAITools(manifest.aiTools || []);
121
+
122
+ if (result.action === 'add' && result.tools.length > 0) {
123
+ // Handle AGENTS.md sharing
124
+ const toolsWithSharing = handleAgentsMdSharing(result.tools);
125
+ newAITools = [...new Set([...newAITools, ...toolsWithSharing])];
126
+ needsIntegrationRegeneration = true;
127
+ } else if (result.action === 'remove' && result.tools.length > 0) {
128
+ newAITools = newAITools.filter(t => !result.tools.includes(t));
129
+
130
+ // Remove integration files for removed tools
131
+ const spinner = ora('Removing integration files...').start();
132
+ for (const tool of result.tools) {
133
+ const filePath = join(projectPath, getToolFilePath(tool));
134
+ if (existsSync(filePath)) {
135
+ try {
136
+ unlinkSync(filePath);
137
+ console.log(chalk.gray(` Removed: ${getToolFilePath(tool)}`));
138
+ } catch (err) {
139
+ console.log(chalk.yellow(` Could not remove: ${getToolFilePath(tool)}`));
140
+ }
141
+ }
142
+ }
143
+ spinner.succeed('Integration files removed');
144
+ } else if (result.action === 'view' || result.action === 'cancel') {
145
+ console.log(chalk.gray('No changes made.'));
146
+ process.exit(0);
147
+ }
148
+ }
93
149
 
150
+ // Handle Level configuration
151
+ if (configType === 'level') {
152
+ newLevel = await promptAdoptionLevel(manifest.level || 2);
153
+ if (newLevel !== manifest.level) {
154
+ needsIntegrationRegeneration = true;
155
+ }
156
+ }
157
+
158
+ // Handle Content Mode configuration
159
+ if (configType === 'content_mode') {
160
+ newContentMode = await promptContentModeChange(manifest.contentMode || 'minimal');
161
+ if (newContentMode !== manifest.contentMode) {
162
+ needsIntegrationRegeneration = true;
163
+ }
164
+ }
165
+
166
+ // Handle traditional options
94
167
  if (configType === 'all' || configType === 'format') {
95
168
  newFormat = await promptFormat();
96
169
  }
@@ -114,7 +187,10 @@ export async function configureCommand(options) {
114
187
  // Show changes
115
188
  console.log();
116
189
  console.log(chalk.cyan('New Configuration:'));
190
+ console.log(chalk.gray(` Level: ${newLevel}`));
117
191
  console.log(chalk.gray(` Format: ${newFormat}`));
192
+ console.log(chalk.gray(` Content Mode: ${newContentMode}`));
193
+ console.log(chalk.gray(` AI Tools: ${newAITools.length > 0 ? newAITools.join(', ') : 'none'}`));
118
194
  if (newOptions.workflow) {
119
195
  console.log(chalk.gray(` Git Workflow: ${newOptions.workflow}`));
120
196
  }
@@ -133,7 +209,7 @@ export async function configureCommand(options) {
133
209
  const confirmed = await promptConfirm('Apply these changes?');
134
210
  if (!confirmed) {
135
211
  console.log(chalk.yellow('Configuration cancelled.'));
136
- return;
212
+ process.exit(0);
137
213
  }
138
214
 
139
215
  // Apply changes
@@ -141,6 +217,7 @@ export async function configureCommand(options) {
141
217
 
142
218
  const results = {
143
219
  copied: [],
220
+ generated: [],
144
221
  errors: []
145
222
  };
146
223
 
@@ -194,10 +271,78 @@ export async function configureCommand(options) {
194
271
  }
195
272
  }
196
273
 
274
+ // Handle level change - copy new standards if upgrading
275
+ if (newLevel > (manifest.level || 2)) {
276
+ const levelSpinner = ora('Adding new standards for higher level...').start();
277
+ const newStandards = getStandardsByLevel(newLevel);
278
+ const existingStandards = new Set(manifest.standards?.map(s => basename(s)) || []);
279
+
280
+ for (const std of newStandards) {
281
+ for (const targetFormat of formatsToUse) {
282
+ const sourcePath = getStandardSource(std, targetFormat);
283
+ const fileName = basename(sourcePath);
284
+ if (!existingStandards.has(fileName)) {
285
+ const result = await copyStandard(sourcePath, '.standards', projectPath);
286
+ if (result.success) {
287
+ results.copied.push(sourcePath);
288
+ }
289
+ }
290
+ }
291
+ }
292
+ levelSpinner.succeed('New standards added');
293
+ }
294
+
295
+ // Regenerate integration files if needed
296
+ if (needsIntegrationRegeneration && newAITools.length > 0) {
297
+ const intSpinner = ora('Regenerating integration files...').start();
298
+
299
+ // Build installed standards list
300
+ const installedStandardsList = manifest.standards?.map(s => basename(s)) || [];
301
+
302
+ // Determine language setting
303
+ let commonLanguage = 'en';
304
+ if (newOptions.commit_language === 'bilingual') {
305
+ commonLanguage = 'bilingual';
306
+ } else if (newOptions.commit_language === 'traditional-chinese') {
307
+ commonLanguage = 'zh-tw';
308
+ }
309
+
310
+ // Track generated files to handle AGENTS.md sharing
311
+ const generatedFiles = new Set();
312
+
313
+ for (const tool of newAITools) {
314
+ const targetFile = getToolFilePath(tool);
315
+ if (generatedFiles.has(targetFile)) {
316
+ continue; // Skip if already generated (AGENTS.md sharing)
317
+ }
318
+
319
+ const toolConfig = {
320
+ tool,
321
+ categories: ['anti-hallucination', 'commit-standards', 'code-review'],
322
+ language: commonLanguage,
323
+ installedStandards: installedStandardsList,
324
+ contentMode: newContentMode,
325
+ level: newLevel
326
+ };
327
+
328
+ const result = writeIntegrationFile(tool, toolConfig, projectPath);
329
+ if (result.success) {
330
+ results.generated.push(result.path);
331
+ generatedFiles.add(targetFile);
332
+ } else {
333
+ results.errors.push(`${tool}: ${result.error}`);
334
+ }
335
+ }
336
+ intSpinner.succeed(`Regenerated ${results.generated.length} integration files`);
337
+ }
338
+
197
339
  // Update manifest
198
340
  manifest.format = newFormat;
199
341
  manifest.options = newOptions;
200
- manifest.version = '2.0.0';
342
+ manifest.level = newLevel;
343
+ manifest.contentMode = newContentMode;
344
+ manifest.aiTools = newAITools;
345
+ manifest.version = '3.2.0';
201
346
  writeManifest(manifest, projectPath);
202
347
 
203
348
  spinner.succeed('Configuration updated');
@@ -206,7 +351,10 @@ export async function configureCommand(options) {
206
351
  console.log();
207
352
  console.log(chalk.green('✓ Configuration updated successfully!'));
208
353
  if (results.copied.length > 0) {
209
- console.log(chalk.gray(` ${results.copied.length} new option files copied`));
354
+ console.log(chalk.gray(` ${results.copied.length} new option/standard files copied`));
355
+ }
356
+ if (results.generated.length > 0) {
357
+ console.log(chalk.gray(` ${results.generated.length} integration files regenerated`));
210
358
  }
211
359
 
212
360
  if (results.errors.length > 0) {