scene-capability-engine 3.3.13 → 3.3.14

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.
@@ -6,6 +6,7 @@
6
6
 
7
7
  const fs = require('fs-extra');
8
8
  const path = require('path');
9
+ const semver = require('semver');
9
10
  const { ValidationError } = require('./template-error');
10
11
 
11
12
  class TemplateValidator {
@@ -14,7 +15,8 @@ class TemplateValidator {
14
15
  this.requiredFrontmatterFields = [
15
16
  'name', 'category', 'description', 'difficulty',
16
17
  'tags', 'applicable_scenarios', 'author',
17
- 'created_at', 'updated_at', 'version'
18
+ 'created_at', 'updated_at', 'version',
19
+ 'template_type', 'min_sce_version'
18
20
  ];
19
21
  }
20
22
 
@@ -251,6 +253,27 @@ class TemplateValidator {
251
253
  result.errors.push(`${filename}: Invalid difficulty "${metadata.difficulty}"`);
252
254
  }
253
255
 
256
+ // Validate template type
257
+ const validTemplateTypes = ['spec-scaffold', 'capability-template', 'runtime-playbook'];
258
+ if (metadata.template_type && !validTemplateTypes.includes(metadata.template_type)) {
259
+ result.errors.push(`${filename}: Invalid template_type "${metadata.template_type}"`);
260
+ }
261
+
262
+ // Validate SCE compatibility semver
263
+ if (metadata.min_sce_version && !semver.valid(metadata.min_sce_version)) {
264
+ result.errors.push(`${filename}: Invalid min_sce_version "${metadata.min_sce_version}"`);
265
+ }
266
+
267
+ if (metadata.max_sce_version && !semver.valid(metadata.max_sce_version)) {
268
+ result.errors.push(`${filename}: Invalid max_sce_version "${metadata.max_sce_version}"`);
269
+ }
270
+
271
+ if (metadata.min_sce_version && metadata.max_sce_version &&
272
+ semver.valid(metadata.min_sce_version) && semver.valid(metadata.max_sce_version) &&
273
+ semver.gt(metadata.min_sce_version, metadata.max_sce_version)) {
274
+ result.errors.push(`${filename}: min_sce_version must be <= max_sce_version`);
275
+ }
276
+
254
277
  return result;
255
278
  }
256
279
 
@@ -26,7 +26,7 @@ class GlobalConfig {
26
26
  /**
27
27
  * Get the default configuration file path
28
28
  *
29
- * @returns {string} Path to ~/.kse/workspace-state.json
29
+ * @returns {string} Path to ~/.sce/workspace-state.json
30
30
  * @deprecated Use WorkspaceStateManager.getDefaultStatePath() instead
31
31
  */
32
32
  getDefaultConfigPath() {
@@ -84,16 +84,16 @@ class PathUtils {
84
84
  /**
85
85
  * Get the default sce configuration directory
86
86
  *
87
- * @returns {string} Path to ~/.kse directory
87
+ * @returns {string} Path to ~/.sce directory
88
88
  */
89
89
  static getConfigDir() {
90
- return path.join(os.homedir(), '.kse');
90
+ return path.join(os.homedir(), '.sce');
91
91
  }
92
92
 
93
93
  /**
94
94
  * Get the default workspace state file path
95
95
  *
96
- * @returns {string} Path to ~/.kse/workspace-state.json
96
+ * @returns {string} Path to ~/.sce/workspace-state.json
97
97
  */
98
98
  static getWorkspaceStatePath() {
99
99
  return path.join(this.getConfigDir(), 'workspace-state.json');
@@ -26,7 +26,7 @@ class WorkspaceRegistry {
26
26
  /**
27
27
  * Get the default configuration file path
28
28
  *
29
- * @returns {string} Path to ~/.kse/workspace-state.json
29
+ * @returns {string} Path to ~/.sce/workspace-state.json
30
30
  * @deprecated Use WorkspaceStateManager.getDefaultStatePath() instead
31
31
  */
32
32
  getDefaultConfigPath() {
@@ -10,7 +10,7 @@ const Workspace = require('./workspace');
10
10
  * data in a single configuration file. This ensures atomic updates and
11
11
  * eliminates data inconsistency risks.
12
12
  *
13
- * Architecture: Single file (~/.kse/workspace-state.json) contains:
13
+ * Architecture: Single file (~/.sce/workspace-state.json) contains:
14
14
  * - All workspace entries
15
15
  * - Active workspace selection
16
16
  * - User preferences
@@ -41,13 +41,34 @@ class WorkspaceStateManager {
41
41
  /**
42
42
  * Get the default state file path
43
43
  *
44
- * @returns {string} Path to ~/.kse/workspace-state.json
44
+ * @returns {string} Path to ~/.sce/workspace-state.json
45
45
  */
46
46
  getDefaultStatePath() {
47
+ const homeDir = os.homedir();
48
+ return path.join(homeDir, '.sce', 'workspace-state.json');
49
+ }
50
+
51
+ /**
52
+ * Get the legacy state file path used by prior versions
53
+ *
54
+ * @returns {string} Path to ~/.kse/workspace-state.json
55
+ */
56
+ getLegacyStatePath() {
47
57
  const homeDir = os.homedir();
48
58
  return path.join(homeDir, '.kse', 'workspace-state.json');
49
59
  }
50
60
 
61
+ /**
62
+ * Whether state manager is operating on the default state path.
63
+ *
64
+ * Automatic legacy migration should only run in this mode.
65
+ *
66
+ * @returns {boolean}
67
+ */
68
+ isDefaultStatePath() {
69
+ return path.resolve(this.statePath) === path.resolve(this.getDefaultStatePath());
70
+ }
71
+
51
72
  /**
52
73
  * Load workspace state from disk
53
74
  *
@@ -66,6 +87,15 @@ class WorkspaceStateManager {
66
87
  return true;
67
88
  }
68
89
 
90
+ // Migrate legacy single-file state from ~/.kse/workspace-state.json
91
+ if (await this.hasLegacyStateFile()) {
92
+ console.log('Migrating workspace state to new .sce directory...');
93
+ await this.migrateFromLegacyStateFile();
94
+ await this.loadNewFormat();
95
+ this.loaded = true;
96
+ return true;
97
+ }
98
+
69
99
  // Check for legacy format and migrate
70
100
  if (await this.hasLegacyFiles()) {
71
101
  console.log('Migrating workspace configuration to new format...');
@@ -137,6 +167,10 @@ class WorkspaceStateManager {
137
167
  * @returns {Promise<boolean>}
138
168
  */
139
169
  async hasLegacyFiles() {
170
+ if (!this.isDefaultStatePath()) {
171
+ return false;
172
+ }
173
+
140
174
  const homeDir = os.homedir();
141
175
  const legacyWorkspacesPath = path.join(homeDir, '.kse', 'workspaces.json');
142
176
  const legacyConfigPath = path.join(homeDir, '.kse', 'config.json');
@@ -147,6 +181,34 @@ class WorkspaceStateManager {
147
181
  return workspacesExists || configExists;
148
182
  }
149
183
 
184
+ /**
185
+ * Check whether legacy single-file state exists
186
+ *
187
+ * @private
188
+ * @returns {Promise<boolean>}
189
+ */
190
+ async hasLegacyStateFile() {
191
+ if (!this.isDefaultStatePath()) {
192
+ return false;
193
+ }
194
+
195
+ const legacyStatePath = this.getLegacyStatePath();
196
+ return fs.pathExists(legacyStatePath);
197
+ }
198
+
199
+ /**
200
+ * Copy legacy single-file state into the new default location.
201
+ *
202
+ * @private
203
+ * @returns {Promise<void>}
204
+ */
205
+ async migrateFromLegacyStateFile() {
206
+ const legacyStatePath = this.getLegacyStatePath();
207
+ const stateDir = path.dirname(this.statePath);
208
+ await fs.ensureDir(stateDir);
209
+ await fs.copy(legacyStatePath, this.statePath);
210
+ }
211
+
150
212
  /**
151
213
  * Migrate from legacy format (workspaces.json + config.json)
152
214
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scene-capability-engine",
3
- "version": "3.3.13",
3
+ "version": "3.3.14",
4
4
  "description": "SCE (Scene Capability Engine) - A CLI tool and npm package for spec-driven development with AI coding assistants.",
5
5
  "main": "index.js",
6
6
  "bin": {