scene-capability-engine 3.6.39 → 3.6.45

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.
Files changed (49) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/bin/scene-capability-engine.js +78 -4
  3. package/docs/command-reference.md +5 -0
  4. package/docs/developer-guide.md +1 -1
  5. package/docs/releases/README.md +6 -0
  6. package/docs/releases/v3.6.40.md +19 -0
  7. package/docs/releases/v3.6.41.md +20 -0
  8. package/docs/releases/v3.6.42.md +19 -0
  9. package/docs/releases/v3.6.43.md +17 -0
  10. package/docs/releases/v3.6.44.md +17 -0
  11. package/docs/releases/v3.6.45.md +18 -0
  12. package/docs/spec-collaboration-guide.md +1 -1
  13. package/docs/zh/releases/README.md +6 -0
  14. package/docs/zh/releases/v3.6.40.md +19 -0
  15. package/docs/zh/releases/v3.6.41.md +20 -0
  16. package/docs/zh/releases/v3.6.42.md +19 -0
  17. package/docs/zh/releases/v3.6.43.md +17 -0
  18. package/docs/zh/releases/v3.6.44.md +17 -0
  19. package/docs/zh/releases/v3.6.45.md +18 -0
  20. package/lib/adoption/adoption-logger.js +1 -1
  21. package/lib/adoption/adoption-strategy.js +29 -29
  22. package/lib/adoption/detection-engine.js +16 -13
  23. package/lib/adoption/smart-orchestrator.js +3 -3
  24. package/lib/adoption/strategy-selector.js +19 -15
  25. package/lib/adoption/template-sync.js +3 -3
  26. package/lib/auto/autonomous-engine.js +5 -5
  27. package/lib/auto/handoff-release-gate-history-loaders-service.js +24 -4
  28. package/lib/auto/handoff-run-service.js +37 -0
  29. package/lib/backup/backup-system.js +10 -10
  30. package/lib/collab/collab-manager.js +8 -5
  31. package/lib/collab/dependency-manager.js +1 -1
  32. package/lib/commands/adopt.js +2 -2
  33. package/lib/commands/auto.js +239 -97
  34. package/lib/commands/collab.js +10 -4
  35. package/lib/commands/status.js +3 -3
  36. package/lib/commands/studio.js +8 -0
  37. package/lib/repo/config-manager.js +2 -2
  38. package/lib/spec/bootstrap/context-collector.js +5 -4
  39. package/lib/spec-gate/rules/default-rules.js +8 -8
  40. package/lib/upgrade/migration-engine.js +5 -5
  41. package/lib/upgrade/migrations/1.0.0-to-1.1.0.js +3 -3
  42. package/lib/utils/tool-detector.js +4 -4
  43. package/lib/utils/validation.js +6 -6
  44. package/lib/workspace/collab-governance-audit.js +575 -0
  45. package/lib/workspace/multi/workspace-context-resolver.js +3 -3
  46. package/lib/workspace/multi/workspace-registry.js +3 -3
  47. package/lib/workspace/multi/workspace-state-manager.js +3 -3
  48. package/lib/workspace/spec-delivery-audit.js +553 -0
  49. package/package.json +1 -1
@@ -31,8 +31,8 @@ class DetectionEngine {
31
31
  */
32
32
  async analyze(projectPath) {
33
33
  try {
34
- const kiroPath = path.join(projectPath, this.sceDir);
35
- const hasKiroDir = await pathExists(kiroPath);
34
+ const scePath = path.join(projectPath, this.sceDir);
35
+ const hasSceDir = await pathExists(scePath);
36
36
 
37
37
  let hasVersionFile = false;
38
38
  let hasSpecs = false;
@@ -41,9 +41,9 @@ class DetectionEngine {
41
41
  let existingVersion = null;
42
42
  let steeringDetection = null;
43
43
 
44
- if (hasKiroDir) {
44
+ if (hasSceDir) {
45
45
  // Check for version.json
46
- const versionPath = path.join(kiroPath, this.versionFile);
46
+ const versionPath = path.join(scePath, this.versionFile);
47
47
  hasVersionFile = await pathExists(versionPath);
48
48
 
49
49
  if (hasVersionFile) {
@@ -57,7 +57,7 @@ class DetectionEngine {
57
57
  }
58
58
 
59
59
  // Check for specs/
60
- const specsPath = path.join(kiroPath, this.specsDir);
60
+ const specsPath = path.join(scePath, this.specsDir);
61
61
  hasSpecs = await pathExists(specsPath);
62
62
 
63
63
  // Check for steering/ using SteeringManager
@@ -65,7 +65,7 @@ class DetectionEngine {
65
65
  hasSteering = steeringDetection.hasExistingSteering;
66
66
 
67
67
  // Check for tools/
68
- const toolsPath = path.join(kiroPath, this.toolsDir);
68
+ const toolsPath = path.join(scePath, this.toolsDir);
69
69
  hasTools = await pathExists(toolsPath);
70
70
  }
71
71
 
@@ -73,10 +73,11 @@ class DetectionEngine {
73
73
  const projectType = await this.detectProjectType(projectPath);
74
74
 
75
75
  // Detect conflicts (only if we're going to add template files)
76
- const conflicts = hasKiroDir ? await this.detectConflicts(projectPath) : [];
76
+ const conflicts = hasSceDir ? await this.detectConflicts(projectPath) : [];
77
77
 
78
78
  return {
79
- hasKiroDir,
79
+ hasSceDir,
80
+ hasKiroDir: hasSceDir,
80
81
  hasVersionFile,
81
82
  hasSpecs,
82
83
  hasSteering,
@@ -98,8 +99,9 @@ class DetectionEngine {
98
99
  * @returns {AdoptionMode} - 'fresh', 'partial', or 'full'
99
100
  */
100
101
  determineStrategy(result) {
102
+ const hasSceDir = result && result.hasSceDir !== undefined ? result.hasSceDir : result.hasKiroDir;
101
103
  // Fresh adoption: no .sce/ directory
102
- if (!result.hasKiroDir) {
104
+ if (!hasSceDir) {
103
105
  return 'fresh';
104
106
  }
105
107
 
@@ -152,7 +154,7 @@ class DetectionEngine {
152
154
  const conflicts = [];
153
155
 
154
156
  try {
155
- const kiroPath = path.join(projectPath, this.sceDir);
157
+ const scePath = path.join(projectPath, this.sceDir);
156
158
 
157
159
  // Define template files that might conflict
158
160
  const templateFiles = [
@@ -177,7 +179,7 @@ class DetectionEngine {
177
179
  ];
178
180
 
179
181
  for (const templateFile of templateFiles) {
180
- const filePath = path.join(kiroPath, templateFile);
182
+ const filePath = path.join(scePath, templateFile);
181
183
  const exists = await pathExists(filePath);
182
184
 
183
185
  if (exists) {
@@ -249,12 +251,13 @@ class DetectionEngine {
249
251
  */
250
252
  getSummary(result) {
251
253
  const lines = [];
254
+ const hasSceDir = result && result.hasSceDir !== undefined ? result.hasSceDir : result.hasKiroDir;
252
255
 
253
256
  lines.push('Project Analysis:');
254
257
  lines.push(` Project Type: ${result.projectType}`);
255
- lines.push(` .sce/ Directory: ${result.hasKiroDir ? 'Yes' : 'No'}`);
258
+ lines.push(` .sce/ Directory: ${hasSceDir ? 'Yes' : 'No'}`);
256
259
 
257
- if (result.hasKiroDir) {
260
+ if (hasSceDir) {
258
261
  lines.push(` version.json: ${result.hasVersionFile ? 'Yes' : 'No'}`);
259
262
  if (result.existingVersion) {
260
263
  lines.push(` Current Version: ${result.existingVersion}`);
@@ -317,10 +317,10 @@ class SmartOrchestrator {
317
317
 
318
318
  } else if (mode === 'smart-adopt' || mode === 'smart-update') {
319
319
  // Check which template files exist and differ
320
- const kiroPath = path.join(projectPath, '.sce');
320
+ const scePath = path.join(projectPath, '.sce');
321
321
 
322
322
  for (const templateFile of templateFiles) {
323
- const filePath = path.join(kiroPath, templateFile);
323
+ const filePath = path.join(scePath, templateFile);
324
324
  const fs = require('fs-extra');
325
325
 
326
326
  if (await fs.pathExists(filePath)) {
@@ -340,7 +340,7 @@ class SmartOrchestrator {
340
340
  }
341
341
 
342
342
  // Always preserve CURRENT_CONTEXT.md if it exists
343
- const currentContextPath = path.join(kiroPath, 'steering/CURRENT_CONTEXT.md');
343
+ const currentContextPath = path.join(scePath, 'steering/CURRENT_CONTEXT.md');
344
344
  const fs = require('fs-extra');
345
345
  if (await fs.pathExists(currentContextPath)) {
346
346
  plan.filesToPreserve.push('steering/CURRENT_CONTEXT.md');
@@ -31,7 +31,11 @@ const AdoptionMode = {
31
31
  */
32
32
  class ProjectState {
33
33
  constructor(data = {}) {
34
- this.hasKiroDir = data.hasKiroDir !== undefined ? data.hasKiroDir : false;
34
+ this.hasSceDir = data.hasSceDir !== undefined
35
+ ? data.hasSceDir
36
+ : (data.hasKiroDir !== undefined ? data.hasKiroDir : false);
37
+ // Backward-compatible alias for older callers/tests.
38
+ this.hasKiroDir = this.hasSceDir;
35
39
  this.hasVersionFile = data.hasVersionFile !== undefined ? data.hasVersionFile : false;
36
40
  this.currentVersion = data.currentVersion !== undefined ? data.currentVersion : null;
37
41
  this.targetVersion = data.targetVersion !== undefined ? data.targetVersion : null;
@@ -61,22 +65,22 @@ class StrategySelector {
61
65
  * @returns {Promise<ProjectState>} - Comprehensive project state
62
66
  */
63
67
  async detectProjectState(projectPath) {
64
- const kiroPath = path.join(projectPath, '.sce');
65
- const versionPath = path.join(kiroPath, 'version.json');
66
- const specsPath = path.join(kiroPath, 'specs');
67
- const steeringPath = path.join(kiroPath, 'steering');
68
- const toolsPath = path.join(kiroPath, 'tools');
68
+ const scePath = path.join(projectPath, '.sce');
69
+ const versionPath = path.join(scePath, 'version.json');
70
+ const specsPath = path.join(scePath, 'specs');
71
+ const steeringPath = path.join(scePath, 'steering');
72
+ const toolsPath = path.join(scePath, 'tools');
69
73
 
70
74
  // Get target version from package.json
71
75
  const packageJson = require('../../package.json');
72
76
  const targetVersion = packageJson.version;
73
77
 
74
78
  // Check directory existence
75
- const hasKiroDir = await this.fs.pathExists(kiroPath);
76
- const hasVersionFile = hasKiroDir && await this.fs.pathExists(versionPath);
77
- const hasSpecs = hasKiroDir && await this.fs.pathExists(specsPath);
78
- const hasSteering = hasKiroDir && await this.fs.pathExists(steeringPath);
79
- const hasTools = hasKiroDir && await this.fs.pathExists(toolsPath);
79
+ const hasSceDir = await this.fs.pathExists(scePath);
80
+ const hasVersionFile = hasSceDir && await this.fs.pathExists(versionPath);
81
+ const hasSpecs = hasSceDir && await this.fs.pathExists(specsPath);
82
+ const hasSteering = hasSceDir && await this.fs.pathExists(steeringPath);
83
+ const hasTools = hasSceDir && await this.fs.pathExists(toolsPath);
80
84
 
81
85
  // Read current version if available
82
86
  let currentVersion = null;
@@ -103,7 +107,7 @@ class StrategySelector {
103
107
 
104
108
  // Detect potential conflicts (files that exist and might be overwritten)
105
109
  const conflicts = [];
106
- if (hasKiroDir) {
110
+ if (hasSceDir) {
107
111
  const templateFiles = [
108
112
  'steering/CORE_PRINCIPLES.md',
109
113
  'steering/ENVIRONMENT.md',
@@ -116,7 +120,7 @@ class StrategySelector {
116
120
  ];
117
121
 
118
122
  for (const templateFile of templateFiles) {
119
- const filePath = path.join(kiroPath, templateFile);
123
+ const filePath = path.join(scePath, templateFile);
120
124
  if (await this.fs.pathExists(filePath)) {
121
125
  conflicts.push(templateFile);
122
126
  }
@@ -124,7 +128,7 @@ class StrategySelector {
124
128
  }
125
129
 
126
130
  return new ProjectState({
127
- hasKiroDir,
131
+ hasSceDir,
128
132
  hasVersionFile,
129
133
  currentVersion,
130
134
  targetVersion,
@@ -144,7 +148,7 @@ class StrategySelector {
144
148
  */
145
149
  selectMode(state) {
146
150
  // No .sce/ directory - fresh adoption
147
- if (!state.hasKiroDir) {
151
+ if (!state.hasSceDir) {
148
152
  return AdoptionMode.FRESH;
149
153
  }
150
154
 
@@ -59,7 +59,7 @@ class TemplateSync {
59
59
  errors: [] // Files that couldn't be compared
60
60
  };
61
61
 
62
- const kiroPath = path.join(projectPath, '.sce');
62
+ const scePath = path.join(projectPath, '.sce');
63
63
 
64
64
  for (const templateFile of this.templateFiles) {
65
65
  try {
@@ -72,7 +72,7 @@ class TemplateSync {
72
72
  continue;
73
73
  }
74
74
 
75
- const projectFilePath = path.join(kiroPath, templateFile);
75
+ const projectFilePath = path.join(scePath, templateFile);
76
76
  const templateFilePath = path.join(templatePath, templateFile);
77
77
 
78
78
  // Check if template file exists
@@ -323,7 +323,7 @@ class TemplateSync {
323
323
 
324
324
  const synced = [];
325
325
  const errors = [];
326
- const kiroPath = path.join(projectPath, '.sce');
326
+ const scePath = path.join(projectPath, '.sce');
327
327
 
328
328
  // Sync missing files
329
329
  for (const missing of report.differences.missing) {
@@ -69,25 +69,25 @@ class AutonomousEngine {
69
69
  const fs = require('fs-extra');
70
70
 
71
71
  // Check for .sce directory (接管标志)
72
- const kiroDir = path.join(process.cwd(), '.sce');
73
- if (!await fs.pathExists(kiroDir)) {
72
+ const sceDir = path.join(process.cwd(), '.sce');
73
+ if (!await fs.pathExists(sceDir)) {
74
74
  throw new Error('CORE_PRINCIPLES violation: .sce directory not found. Project not adopted by sce.');
75
75
  }
76
76
 
77
77
  // Check for version.json
78
- const versionFile = path.join(kiroDir, 'version.json');
78
+ const versionFile = path.join(sceDir, 'version.json');
79
79
  if (!await fs.pathExists(versionFile)) {
80
80
  console.warn('Warning: version.json not found. Consider running sce adoption.');
81
81
  }
82
82
 
83
83
  // Check for specs directory
84
- const specsDir = path.join(kiroDir, 'specs');
84
+ const specsDir = path.join(sceDir, 'specs');
85
85
  if (!await fs.pathExists(specsDir)) {
86
86
  await fs.ensureDir(specsDir);
87
87
  }
88
88
 
89
89
  // Check for steering directory
90
- const steeringDir = path.join(kiroDir, 'steering');
90
+ const steeringDir = path.join(sceDir, 'steering');
91
91
  if (!await fs.pathExists(steeringDir)) {
92
92
  console.warn('Warning: steering directory not found.');
93
93
  }
@@ -426,7 +426,19 @@ async function loadAutoHandoffReleaseGateReports(projectPath, dirCandidate = nul
426
426
  warnings.push(`skip invalid release gate payload: ${reportFile}`);
427
427
  continue;
428
428
  }
429
- entries.push(buildAutoHandoffReleaseGateHistoryEntry(payload, { projectPath, file: reportFile, tag: parseAutoHandoffReleaseGateTag(path.basename(reportFile)) }, dependencies));
429
+ try {
430
+ entries.push(buildAutoHandoffReleaseGateHistoryEntry(
431
+ payload,
432
+ {
433
+ projectPath,
434
+ file: reportFile,
435
+ tag: parseAutoHandoffReleaseGateTag(path.basename(reportFile))
436
+ },
437
+ dependencies
438
+ ));
439
+ } catch (error) {
440
+ warnings.push(`skip invalid release gate report entry: ${reportFile} (${error.message})`);
441
+ }
430
442
  }
431
443
 
432
444
  return {
@@ -459,13 +471,21 @@ async function loadAutoHandoffReleaseGateHistorySeed(projectPath, fileCandidate
459
471
  };
460
472
  }
461
473
  const list = Array.isArray(payload && payload.entries) ? payload.entries : [];
462
- const entries = list
474
+ const warnings = [];
475
+ const entries = [];
476
+ list
463
477
  .filter(item => item && typeof item === 'object' && !Array.isArray(item))
464
- .map(item => buildAutoHandoffReleaseGateHistoryEntry(item, { projectPath }, dependencies));
478
+ .forEach((item, index) => {
479
+ try {
480
+ entries.push(buildAutoHandoffReleaseGateHistoryEntry(item, { projectPath }, dependencies));
481
+ } catch (error) {
482
+ warnings.push(`skip invalid gate history entry #${index + 1}: ${error.message}`);
483
+ }
484
+ });
465
485
  return {
466
486
  file: filePath,
467
487
  entries,
468
- warnings: []
488
+ warnings
469
489
  };
470
490
  }
471
491
 
@@ -13,6 +13,8 @@ async function runAutoHandoff(projectPath, options = {}, dependencies = {}) {
13
13
  loadGovernanceReleaseGateSignals,
14
14
  completeAutoHandoffRunPhase,
15
15
  evaluateAutoHandoffOntologyGateReasons,
16
+ auditSpecDeliverySync,
17
+ evaluateAutoHandoffSpecDeliveryGateReasons,
16
18
  evaluateAutoHandoffReleaseGatePreflightGateReasons,
17
19
  failAutoHandoffRunPhase,
18
20
  buildAutoHandoffMoquiBaselineSnapshot,
@@ -63,6 +65,7 @@ async function runAutoHandoff(projectPath, options = {}, dependencies = {}) {
63
65
  observability_snapshot: null,
64
66
  spec_status: null,
65
67
  ontology_validation: null,
68
+ spec_delivery_sync: null,
66
69
  moqui_baseline: null,
67
70
  scene_package_batch: null,
68
71
  moqui_capability_coverage: null,
@@ -92,6 +95,9 @@ async function runAutoHandoff(projectPath, options = {}, dependencies = {}) {
92
95
  result.ontology_validation = evaluateHandoffOntologyValidation(
93
96
  plan && plan.handoff ? plan.handoff.ontology_validation : null
94
97
  );
98
+ result.spec_delivery_sync = await auditSpecDeliverySync(projectPath, {
99
+ requireManifest: false
100
+ });
95
101
  result.template_diff = await buildAutoHandoffTemplateDiff(projectPath, { manifest: options.manifest });
96
102
  result.release_gate_preflight = buildAutoHandoffReleaseGatePreflight(
97
103
  await loadGovernanceReleaseGateSignals(projectPath)
@@ -110,6 +116,15 @@ async function runAutoHandoff(projectPath, options = {}, dependencies = {}) {
110
116
  completeAutoHandoffRunPhase(precheckPhase, {
111
117
  validation: plan.validation,
112
118
  phase_count: Array.isArray(plan.phases) ? plan.phases.length : 0,
119
+ spec_delivery_sync: result.spec_delivery_sync
120
+ ? {
121
+ manifest_count: result.spec_delivery_sync.summary
122
+ ? result.spec_delivery_sync.summary.manifest_count
123
+ : 0,
124
+ passed: result.spec_delivery_sync.passed === true,
125
+ reason: result.spec_delivery_sync.reason || null
126
+ }
127
+ : null,
113
128
  template_compatibility: result.template_diff.compatibility,
114
129
  release_gate_preflight: {
115
130
  available: result.release_gate_preflight.available,
@@ -139,6 +154,28 @@ async function runAutoHandoff(projectPath, options = {}, dependencies = {}) {
139
154
  if (ontologyGateReasons.length > 0) {
140
155
  throw new Error(`handoff ontology validation gate failed: ${ontologyGateReasons.join('; ')}`);
141
156
  }
157
+ const specDeliveryGateReasons = evaluateAutoHandoffSpecDeliveryGateReasons(
158
+ result.policy,
159
+ result.spec_delivery_sync
160
+ );
161
+ if (specDeliveryGateReasons.length > 0) {
162
+ throw new Error(`handoff spec delivery sync gate failed: ${specDeliveryGateReasons.join('; ')}`);
163
+ }
164
+ if (
165
+ result.policy.require_spec_delivery_sync !== true &&
166
+ result.spec_delivery_sync &&
167
+ result.spec_delivery_sync.reason !== 'no-manifests' &&
168
+ result.spec_delivery_sync.passed !== true
169
+ ) {
170
+ const advisoryReasons = Array.isArray(result.spec_delivery_sync.violations)
171
+ ? result.spec_delivery_sync.violations
172
+ : [];
173
+ if (advisoryReasons.length > 0) {
174
+ result.warnings.push(
175
+ `spec delivery sync advisory: ${advisoryReasons.join('; ')}`
176
+ );
177
+ }
178
+ }
142
179
  const releaseGatePreflightReasons = evaluateAutoHandoffReleaseGatePreflightGateReasons(
143
180
  result.policy,
144
181
  result.release_gate_preflight
@@ -40,7 +40,7 @@ class BackupSystem {
40
40
  * @param {string} projectPath - Absolute path to project root
41
41
  * @returns {string} - Absolute path to .sce directory
42
42
  */
43
- getKiroDir(projectPath) {
43
+ getSceDir(projectPath) {
44
44
  return path.join(projectPath, '.sce');
45
45
  }
46
46
 
@@ -74,11 +74,11 @@ class BackupSystem {
74
74
  const { type = 'manual' } = options;
75
75
 
76
76
  try {
77
- const kiroDir = this.getKiroDir(projectPath);
77
+ const sceDir = this.getSceDir(projectPath);
78
78
 
79
79
  // Check if .sce/ exists
80
- const kiroExists = await pathExists(kiroDir);
81
- if (!kiroExists) {
80
+ const sceExists = await pathExists(sceDir);
81
+ if (!sceExists) {
82
82
  throw new Error('.sce/ directory does not exist');
83
83
  }
84
84
 
@@ -100,7 +100,7 @@ class BackupSystem {
100
100
  await ensureDirectory(backupPath);
101
101
 
102
102
  // Copy .sce/ contents to backup (excluding backups/ itself)
103
- const items = await listFiles(kiroDir);
103
+ const items = await listFiles(sceDir);
104
104
 
105
105
  for (const item of items) {
106
106
  // Skip the backups directory itself
@@ -108,7 +108,7 @@ class BackupSystem {
108
108
  continue;
109
109
  }
110
110
 
111
- const sourcePath = path.join(kiroDir, item);
111
+ const sourcePath = path.join(sceDir, item);
112
112
  const destPath = path.join(backupPath, item);
113
113
 
114
114
  await copyDirectory(sourcePath, destPath, { overwrite: false });
@@ -243,20 +243,20 @@ class BackupSystem {
243
243
  throw new Error(`Backup validation failed: ${backupId}`);
244
244
  }
245
245
 
246
- const kiroDir = this.getKiroDir(projectPath);
246
+ const sceDir = this.getSceDir(projectPath);
247
247
 
248
248
  // Get list of items to restore (excluding metadata.json)
249
249
  const items = await listFiles(backupPath);
250
250
  const itemsToRestore = items.filter(item => item !== 'metadata.json');
251
251
 
252
252
  // Remove existing .sce/ contents (except backups/)
253
- const existingItems = await listFiles(kiroDir);
253
+ const existingItems = await listFiles(sceDir);
254
254
  for (const item of existingItems) {
255
255
  if (item === this.backupDirName) {
256
256
  continue;
257
257
  }
258
258
 
259
- const itemPath = path.join(kiroDir, item);
259
+ const itemPath = path.join(sceDir, item);
260
260
  await remove(itemPath);
261
261
  }
262
262
 
@@ -264,7 +264,7 @@ class BackupSystem {
264
264
  const restoredFiles = [];
265
265
  for (const item of itemsToRestore) {
266
266
  const sourcePath = path.join(backupPath, item);
267
- const destPath = path.join(kiroDir, item);
267
+ const destPath = path.join(sceDir, item);
268
268
 
269
269
  await copyDirectory(sourcePath, destPath, { overwrite: true });
270
270
  restoredFiles.push(item);
@@ -125,10 +125,10 @@ class CollaborationManager {
125
125
  /**
126
126
  * Assign a spec to a SCE instance
127
127
  * @param {string} specName - Name of the spec
128
- * @param {string} kiroInstance - SCE instance identifier
128
+ * @param {string} sceInstance - SCE instance identifier
129
129
  * @returns {Promise<Object>} Assignment result
130
130
  */
131
- async assignSpec(specName, kiroInstance) {
131
+ async assignSpec(specName, sceInstance) {
132
132
  const metadata = await this.metadataManager.readMetadata(specName);
133
133
 
134
134
  if (!metadata) {
@@ -149,17 +149,20 @@ class CollaborationManager {
149
149
  // Update assignment
150
150
  const updated = await this.metadataManager.atomicUpdate(specName, (meta) => {
151
151
  meta.assignment = {
152
- kiroInstance,
152
+ sceInstance,
153
153
  assignedAt: new Date().toISOString()
154
154
  };
155
+ if (meta.assignment && Object.prototype.hasOwnProperty.call(meta.assignment, 'kiroInstance')) {
156
+ delete meta.assignment.kiroInstance;
157
+ }
155
158
  return meta;
156
159
  });
157
160
 
158
161
  return {
159
162
  success: true,
160
163
  spec: specName,
161
- kiroInstance,
162
- message: `Assigned '${specName}' to '${kiroInstance}'`
164
+ sceInstance,
165
+ message: `Assigned '${specName}' to '${sceInstance}'`
163
166
  };
164
167
  }
165
168
 
@@ -25,7 +25,7 @@ class DependencyManager {
25
25
  nodes.push({
26
26
  id: name,
27
27
  status: metadata.status?.current || 'not-started',
28
- kiroInstance: metadata.assignment?.sceInstance || null,
28
+ sceInstance: metadata.assignment?.sceInstance || metadata.assignment?.kiroInstance || null,
29
29
  type: metadata.type
30
30
  });
31
31
 
@@ -220,7 +220,7 @@ async function adoptInteractive(projectPath, options) {
220
220
  console.log(' - Preserve existing specs/ and steering/');
221
221
  console.log(' - Add missing components');
222
222
  console.log(' - Create/update version.json');
223
- if (detection.hasKiroDir) {
223
+ if (detection.hasSceDir) {
224
224
  console.log(' - Create backup before changes');
225
225
  }
226
226
  } else if (strategy === 'full') {
@@ -487,7 +487,7 @@ async function adoptInteractive(projectPath, options) {
487
487
 
488
488
  // 9. Create backup if needed (for non-conflict scenarios)
489
489
  let backupId = null;
490
- if (detection.hasKiroDir && (strategy === 'partial' || strategy === 'full')) {
490
+ if (detection.hasSceDir && (strategy === 'partial' || strategy === 'full')) {
491
491
  console.log(chalk.blue('📦 Creating backup...'));
492
492
  const backupSystem = new BackupSystem();
493
493