scene-capability-engine 3.3.12 → 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.12",
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": {
@@ -136,6 +136,8 @@
136
136
 
137
137
  **复杂问题定位方法**: 优先使用 debug 日志与可观测信号定位(输入、输出、关键分支、异常栈、上下文参数),先还原执行路径再下结论
138
138
 
139
+ **修复后清理要求**: 问题修复并验证通过后,必须清理临时 debug 日志、临时埋点、一次性脚本和调试开关;需要长期保留的日志必须转为可配置观测项且默认关闭
140
+
139
141
  **允许的临时措施**: 仅在生产止血场景可临时绕行,但必须同时给出根因修复任务、回滚条件和截止时间
140
142
 
141
143
  **验收标准**: 必须有可复现用例、修复后回归通过、明确根因记录(不是仅现象描述)
@@ -155,4 +157,4 @@
155
157
 
156
158
  ---
157
159
 
158
- v15.0 | 2026-02-25 | 新增根因修复原则与 Ontology 四层一链分析原则
160
+ v16.0 | 2026-02-25 | 新增调试日志清理硬规则