scene-capability-engine 3.6.36 → 3.6.38
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/CHANGELOG.md +37 -12
- package/bin/scene-capability-engine.js +1 -1
- package/docs/331-poc-adaptation-roadmap.md +3 -3
- package/docs/command-reference.md +5 -5
- package/docs/faq.md +1 -1
- package/docs/interactive-customization/331-poc-sce-integration-checklist.md +3 -3
- package/docs/interactive-customization/moqui-interactive-template-playbook.md +4 -4
- package/docs/interactive-customization/phase-acceptance-evidence.md +2 -2
- package/docs/moqui-standard-rebuild-guide.md +6 -6
- package/docs/moqui-template-core-library-playbook.md +1 -1
- package/docs/release-checklist.md +50 -27
- package/docs/releases/README.md +2 -0
- package/docs/releases/v3.6.37.md +22 -0
- package/docs/releases/v3.6.38.md +19 -0
- package/docs/steering-governance.md +112 -0
- package/docs/steering-strategy-guide.md +7 -7
- package/docs/troubleshooting.md +1 -1
- package/docs/zh/release-checklist.md +40 -17
- package/docs/zh/releases/README.md +2 -0
- package/docs/zh/releases/v3.6.37.md +22 -0
- package/docs/zh/releases/v3.6.38.md +19 -0
- package/lib/auto/governance-summary.js +2 -2
- package/lib/commands/adopt.js +4 -4
- package/lib/commands/auto.js +3 -3
- package/lib/spec/bootstrap/context-collector.js +1 -1
- package/lib/steering/adoption-config.js +2 -2
- package/lib/steering/compliance-cache.js +2 -2
- package/lib/steering/steering-manager.js +4 -4
- package/lib/task/task-claimer.js +1 -2
- package/lib/workspace/multi/workspace-context-resolver.js +3 -3
- package/lib/workspace/multi/workspace-state-manager.js +0 -164
- package/lib/workspace/sce-tracking-audit.js +1 -1
- package/lib/workspace/takeover-baseline.js +1 -1
- package/package.json +4 -2
- package/template/.sce/README.md +1 -1
- package/template/.sce/steering/CORE_PRINCIPLES.md +21 -211
- package/template/.sce/steering/CURRENT_CONTEXT.md +9 -27
- package/template/.sce/steering/ENVIRONMENT.md +18 -32
- package/template/.sce/steering/RULES_GUIDE.md +16 -44
- package/template/.sce/steering/manifest.yaml +50 -0
- package/bin/kse.js +0 -3
|
@@ -100,28 +100,35 @@ node scripts/git-managed-gate.js --fail-on-violation --json
|
|
|
100
100
|
|
|
101
101
|
确认:
|
|
102
102
|
|
|
103
|
+
- 发布自动化是基于 tag,而不是普通 commit:
|
|
104
|
+
- `.github/workflows/release.yml` 只在 `push.tags: v*` 时触发
|
|
105
|
+
- 普通 `git push` 只会跑常规 CI,不会发布 npm 包,也不会创建 GitHub Release
|
|
106
|
+
- GitHub Actions 发版前置条件已配置:
|
|
107
|
+
- 仓库 Secret `NPM_TOKEN` 必须存在且有效,workflow 会用它执行 `npm publish --access public`
|
|
108
|
+
- workflow 的 release 资产/回读步骤依赖 `GITHUB_TOKEN`
|
|
103
109
|
- `package.json` 版本号正确;
|
|
110
|
+
- `package.json` 版本号必须大于 npm 当前已发布版本;
|
|
104
111
|
- `CHANGELOG.md` 已记录发布相关变化;
|
|
105
112
|
- 发布说明草稿已就绪(如 `docs/releases/vX.Y.Z.md`)。
|
|
106
113
|
- 可选:通过仓库变量配置 release evidence 门禁(`Settings -> Secrets and variables -> Actions -> Variables`):
|
|
107
|
-
- `
|
|
108
|
-
- `
|
|
109
|
-
- `
|
|
110
|
-
- `
|
|
111
|
-
- `
|
|
112
|
-
- `
|
|
113
|
-
- `
|
|
114
|
-
- `
|
|
115
|
-
- `
|
|
114
|
+
- `SCE_RELEASE_GATE_ENFORCE`:`true|false`(默认 advisory,不阻断发布)
|
|
115
|
+
- `SCE_RELEASE_GATE_REQUIRE_EVIDENCE`:是否要求存在 `handoff-runs.json` 摘要
|
|
116
|
+
- `SCE_RELEASE_GATE_REQUIRE_GATE_PASS`:是否要求 evidence gate `passed=true`(有 evidence 时默认要求)
|
|
117
|
+
- `SCE_RELEASE_GATE_MIN_SPEC_SUCCESS_RATE`:最小允许成功率(百分比)
|
|
118
|
+
- `SCE_RELEASE_GATE_MAX_RISK_LEVEL`:`low|medium|high|unknown`(默认 `unknown`)
|
|
119
|
+
- `SCE_RELEASE_GATE_MAX_UNMAPPED_RULES`:ontology 业务规则未映射最大允许值
|
|
120
|
+
- `SCE_RELEASE_GATE_MAX_UNDECIDED_DECISIONS`:ontology 决策未定最大允许值
|
|
121
|
+
- `SCE_RELEASE_GATE_REQUIRE_SCENE_BATCH_PASS`:是否要求 scene package publish-batch gate 必须通过(`true|false`,默认 `true`)
|
|
122
|
+
- `SCE_RELEASE_GATE_MAX_SCENE_BATCH_FAILURES`:scene package batch 失败数量最大允许值(默认 `0`)
|
|
116
123
|
- 可选:通过仓库变量调节 Release Notes 中的漂移告警阈值:
|
|
117
124
|
- CI 中漂移评估由 `scripts/release-drift-evaluate.js` 执行(历史读取、告警计算、gate 报告写回、enforce 退出码)。
|
|
118
|
-
- `
|
|
119
|
-
- `
|
|
120
|
-
- `
|
|
121
|
-
- `
|
|
122
|
-
- `
|
|
123
|
-
- `
|
|
124
|
-
- `
|
|
125
|
+
- `SCE_RELEASE_DRIFT_ENFORCE`:`true|false`(默认 `false`),触发 drift alert 时阻断发布
|
|
126
|
+
- `SCE_RELEASE_DRIFT_FAIL_STREAK_MIN`:触发告警的最小连续失败次数(默认 `2`)
|
|
127
|
+
- `SCE_RELEASE_DRIFT_HIGH_RISK_SHARE_MIN_PERCENT`:近 5 版 high 风险占比告警阈值(默认 `60`)
|
|
128
|
+
- `SCE_RELEASE_DRIFT_HIGH_RISK_SHARE_DELTA_MIN_PERCENT`:短期相对长期 high 风险占比增量阈值(默认 `25`)
|
|
129
|
+
- `SCE_RELEASE_DRIFT_PREFLIGHT_BLOCK_RATE_MIN_PERCENT`:近 5 版(有 preflight 信号)blocked 占比告警阈值(默认 `40`)
|
|
130
|
+
- `SCE_RELEASE_DRIFT_HARD_GATE_BLOCK_STREAK_MIN`:hard-gate preflight 连续 blocked 告警阈值(最近窗口,默认 `2`)
|
|
131
|
+
- `SCE_RELEASE_DRIFT_PREFLIGHT_UNAVAILABLE_STREAK_MIN`:release preflight 连续 unavailable 告警阈值(最近窗口,默认 `2`)
|
|
125
132
|
- 可选:发布资产 0 字节防护(workflow 默认开启)
|
|
126
133
|
- `scripts/release-asset-nonempty-normalize.js` 会在上传 GitHub Release 资产前,为可选 `.lines` / `.jsonl` 资产自动补齐占位内容,避免 422。
|
|
127
134
|
- 本地 dry-run 示例:
|
|
@@ -131,4 +138,20 @@ node scripts/git-managed-gate.js --fail-on-violation --json
|
|
|
131
138
|
- 可选本地预演 release gate 历史索引产物:
|
|
132
139
|
- `sce auto handoff gate-index --dir .sce/reports/release-evidence --out .sce/reports/release-evidence/release-gate-history.json --json`
|
|
133
140
|
|
|
134
|
-
|
|
141
|
+
然后再执行正式发布流程:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
# 1. 先升级版本并提交
|
|
145
|
+
# 2. 先 push 分支代码
|
|
146
|
+
git push origin main
|
|
147
|
+
|
|
148
|
+
# 3. 再创建并 push 发版 tag
|
|
149
|
+
git tag vX.Y.Z
|
|
150
|
+
git push origin vX.Y.Z
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
预期:
|
|
154
|
+
|
|
155
|
+
- `git push origin main` 只跑常规 CI;
|
|
156
|
+
- `git push origin vX.Y.Z` 才会触发 GitHub Actions `Release` workflow;
|
|
157
|
+
- 只有 release workflow 全部门禁通过后,才会自动发布 npm 包并创建 GitHub Release。
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
## 历史版本归档
|
|
10
10
|
|
|
11
11
|
- [发布检查清单](../release-checklist.md)
|
|
12
|
+
- [v3.6.38 发布说明](./v3.6.38.md)
|
|
13
|
+
- [v3.6.37 发布说明](./v3.6.37.md)
|
|
12
14
|
- [v1.46.2 发布说明](./v1.46.2.md)(历史归档)
|
|
13
15
|
- [v1.46.2 验证报告](./v1.46.2-validation.md)(历史归档)
|
|
14
16
|
- [GitHub Releases](https://github.com/heguangyong/scene-capability-engine/releases)(最新)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# v3.6.37 发布说明
|
|
2
|
+
|
|
3
|
+
发布日期:2026-03-12
|
|
4
|
+
|
|
5
|
+
## 重点变化
|
|
6
|
+
|
|
7
|
+
- 彻底移除了运行路径、模板、夹具和对外文档中的旧 `kse` 命令与内容,不再保留兼容桥接。
|
|
8
|
+
- 将 scene package / template 元数据与 fixture 路径统一到 `sce` 命名,避免新产物继续泄漏旧 `kse` 标识。
|
|
9
|
+
- 修复了 Windows 下 `scripts/git-managed-gate.js` 的 git 可执行文件解析问题,新增 `git.cmd` / `git.exe` 回退,避免发布前置门禁误判。
|
|
10
|
+
- 明确记录了真实发布方式:只有 `v*` tag push 才会触发 GitHub Actions 发版,且 workflow 发布依赖仓库 Secret `NPM_TOKEN`。
|
|
11
|
+
|
|
12
|
+
## 验证
|
|
13
|
+
|
|
14
|
+
- `npx jest tests/unit/workspace/workspace-context-resolver.test.js tests/unit/workspace/workspace-state-manager.test.js tests/unit/steering/compliance-cache.test.js tests/unit/scripts/moqui-lexicon-audit.test.js tests/unit/scripts/moqui-standard-rebuild.test.js tests/unit/scripts/moqui-metadata-extract.test.js tests/unit/task/task-claimer.test.js tests/unit/commands/auto.test.js tests/integration/auto-close-loop-cli.integration.test.js --runInBand`
|
|
15
|
+
- `node scripts/check-branding-consistency.js`
|
|
16
|
+
- `npx jest tests/unit/scripts/git-managed-gate.test.js --runInBand`
|
|
17
|
+
|
|
18
|
+
## 发布说明
|
|
19
|
+
|
|
20
|
+
- 普通 `git push` 不会发布本项目。
|
|
21
|
+
- 只有 `git push origin vX.Y.Z` 触发 `.github/workflows/release.yml` 后,才会进入自动发布流程。
|
|
22
|
+
- GitHub Actions 发版依赖仓库 Secret `NPM_TOKEN`。
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# v3.6.38 发布说明
|
|
2
|
+
|
|
3
|
+
发布日期:2026-03-12
|
|
4
|
+
|
|
5
|
+
## 重点变化
|
|
6
|
+
|
|
7
|
+
- 新增 steering 自治理审计,检查内容预算、历史堆积、checklist 泄漏、稳定层 Spec 泄漏,以及非规范治理别名。
|
|
8
|
+
- 重构了当前 steering 基线和模板 steering,使其长期保持精简、分层明确、便于刷新。
|
|
9
|
+
- 将 steering 卫生检查接入常规 CI、`prepublishOnly` 和每周 GitHub Actions 定时任务。
|
|
10
|
+
|
|
11
|
+
## 验证
|
|
12
|
+
|
|
13
|
+
- `npm run audit:steering`
|
|
14
|
+
- `npx jest tests/unit/steering/steering-compliance-checker.test.js tests/unit/scripts/steering-content-audit.test.js tests/unit/scripts/git-managed-gate.test.js --runInBand`
|
|
15
|
+
|
|
16
|
+
## 发布说明
|
|
17
|
+
|
|
18
|
+
- steering 现在通过周期审计持续自我净化,而不是靠人工想起来时再清理。
|
|
19
|
+
- 稳定层应保持“原则长期有效、内容尽量精简”的状态,避免再回到大而杂的历史堆积。
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
const { parseAutoHandoffGateBoolean, normalizeHandoffText } = require('./governance-signals');
|
|
2
2
|
const { buildMoquiRegressionRecoverySequenceLines } = require('./moqui-recovery-sequence');
|
|
3
3
|
|
|
4
4
|
function deriveGovernanceRiskLevel(summary) {
|
|
@@ -575,7 +575,7 @@ function buildGovernanceRecommendations(summary) {
|
|
|
575
575
|
}
|
|
576
576
|
if (Number.isFinite(weeklyOpsConfigWarningsTotal) && weeklyOpsConfigWarningsTotal > 0) {
|
|
577
577
|
recommendations.push(
|
|
578
|
-
'Fix invalid weekly ops threshold variables (`
|
|
578
|
+
'Fix invalid weekly ops threshold variables (`SCE_RELEASE_WEEKLY_OPS_*`) and rerun release gates ' +
|
|
579
579
|
'to clear config warnings.'
|
|
580
580
|
);
|
|
581
581
|
}
|
package/lib/commands/adopt.js
CHANGED
|
@@ -449,7 +449,7 @@ async function adoptInteractive(projectPath, options) {
|
|
|
449
449
|
// Prompt for strategy
|
|
450
450
|
steeringStrategy = await steeringManager.promptStrategy(detection.steeringDetection);
|
|
451
451
|
|
|
452
|
-
if (steeringStrategy === 'use-
|
|
452
|
+
if (steeringStrategy === 'use-sce') {
|
|
453
453
|
// Backup existing steering files
|
|
454
454
|
console.log(chalk.blue('📦 Backing up existing steering files...'));
|
|
455
455
|
const backupResult = await steeringManager.backupSteering(projectPath);
|
|
@@ -460,7 +460,7 @@ async function adoptInteractive(projectPath, options) {
|
|
|
460
460
|
|
|
461
461
|
// Install sce steering files
|
|
462
462
|
console.log(chalk.blue('📝 Installing sce steering files...'));
|
|
463
|
-
const installResult = await steeringManager.
|
|
463
|
+
const installResult = await steeringManager.installSceSteering(projectPath);
|
|
464
464
|
|
|
465
465
|
if (installResult.success) {
|
|
466
466
|
console.log(chalk.green(`✅ Installed ${installResult.filesInstalled} sce steering file(s)`));
|
|
@@ -711,7 +711,7 @@ async function adoptInteractive(projectPath, options) {
|
|
|
711
711
|
*
|
|
712
712
|
* @param {string} projectPath - Project root path
|
|
713
713
|
*/
|
|
714
|
-
async function
|
|
714
|
+
async function setupSceMcpConfig(projectPath) {
|
|
715
715
|
const mcpConfigPath = path.join(projectPath, '.sce', 'settings', 'mcp.json');
|
|
716
716
|
|
|
717
717
|
// Don't overwrite existing config
|
|
@@ -767,7 +767,7 @@ async function offerAutomationSetup(projectPath) {
|
|
|
767
767
|
|
|
768
768
|
// If AI IDE detected, create default MCP settings
|
|
769
769
|
if (toolDetection.primaryTool === 'SCE') {
|
|
770
|
-
await
|
|
770
|
+
await setupSceMcpConfig(projectPath);
|
|
771
771
|
}
|
|
772
772
|
} catch (toolError) {
|
|
773
773
|
// Tool detection is optional, don't fail adoption if it errors
|
package/lib/commands/auto.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
2
|
* Autonomous Control CLI Commands
|
|
3
3
|
*/
|
|
4
4
|
|
|
@@ -8615,7 +8615,7 @@ function buildAutoHandoffRunRecommendations(projectPath, result) {
|
|
|
8615
8615
|
observabilityWeeklyOps.config_warning_positive_sessions > 0
|
|
8616
8616
|
) {
|
|
8617
8617
|
push(
|
|
8618
|
-
'Fix invalid weekly ops threshold variables (`
|
|
8618
|
+
'Fix invalid weekly ops threshold variables (`SCE_RELEASE_WEEKLY_OPS_*`) and rerun release gates ' +
|
|
8619
8619
|
'to clear config warnings.'
|
|
8620
8620
|
);
|
|
8621
8621
|
}
|
|
@@ -13073,7 +13073,7 @@ function buildGovernanceCloseLoopRecommendations(finalAssessment, stopReason, st
|
|
|
13073
13073
|
}
|
|
13074
13074
|
if (reasons.some(item => `${item}`.includes('weekly-ops-config-warnings'))) {
|
|
13075
13075
|
base.push(
|
|
13076
|
-
'Fix invalid weekly ops threshold variables (`
|
|
13076
|
+
'Fix invalid weekly ops threshold variables (`SCE_RELEASE_WEEKLY_OPS_*`) and rerun release gates ' +
|
|
13077
13077
|
'to clear config warnings.'
|
|
13078
13078
|
);
|
|
13079
13079
|
}
|
|
@@ -35,7 +35,7 @@ class ContextCollector {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
_detectLanguagePreference() {
|
|
38
|
-
const lang = `${process.env.
|
|
38
|
+
const lang = `${process.env.SCE_LANG || process.env.LANG || ''}`.toLowerCase();
|
|
39
39
|
if (lang.includes('zh')) {
|
|
40
40
|
return 'zh';
|
|
41
41
|
}
|
|
@@ -60,7 +60,7 @@ class AdoptionConfig {
|
|
|
60
60
|
/**
|
|
61
61
|
* 更新 steering 策略配置
|
|
62
62
|
*
|
|
63
|
-
* @param {string} strategy - 策略 ('use-
|
|
63
|
+
* @param {string} strategy - 策略 ('use-sce' | 'use-project')
|
|
64
64
|
* @param {string|null} backupId - 备份 ID(如果有)
|
|
65
65
|
* @returns {Promise<boolean>} 是否成功
|
|
66
66
|
*/
|
|
@@ -152,7 +152,7 @@ class AdoptionConfig {
|
|
|
152
152
|
const config = {
|
|
153
153
|
version: '1.0.0',
|
|
154
154
|
adoptedAt: new Date().toISOString(),
|
|
155
|
-
steeringStrategy: options.steeringStrategy || 'use-
|
|
155
|
+
steeringStrategy: options.steeringStrategy || 'use-sce',
|
|
156
156
|
multiUserMode: options.multiUserMode || false,
|
|
157
157
|
...options
|
|
158
158
|
};
|
|
@@ -21,11 +21,11 @@ class ComplianceCache {
|
|
|
21
21
|
/**
|
|
22
22
|
* Get the default cache file path
|
|
23
23
|
*
|
|
24
|
-
* @returns {string} Path to ~/.
|
|
24
|
+
* @returns {string} Path to ~/.sce/steering-check-cache.json
|
|
25
25
|
*/
|
|
26
26
|
getDefaultCachePath() {
|
|
27
27
|
const homeDir = os.homedir();
|
|
28
|
-
return path.join(homeDir, '.
|
|
28
|
+
return path.join(homeDir, '.sce', 'steering-check-cache.json');
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
/**
|
|
@@ -65,12 +65,12 @@ class SteeringManager {
|
|
|
65
65
|
* 提示用户选择 steering 策略
|
|
66
66
|
*
|
|
67
67
|
* @param {Object} detection - detectSteering 的返回结果
|
|
68
|
-
* @returns {Promise<string>} 选择的策略 ('use-
|
|
68
|
+
* @returns {Promise<string>} 选择的策略 ('use-sce' | 'use-project')
|
|
69
69
|
*/
|
|
70
70
|
async promptStrategy(detection) {
|
|
71
71
|
if (!detection.hasExistingSteering) {
|
|
72
72
|
// 没有现有 steering 文件,默认使用 sce
|
|
73
|
-
return 'use-
|
|
73
|
+
return 'use-sce';
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
console.log('\n⚠️ Steering Conflict Detected');
|
|
@@ -94,7 +94,7 @@ class SteeringManager {
|
|
|
94
94
|
choices: [
|
|
95
95
|
{
|
|
96
96
|
name: 'Use sce steering (backup existing files) - Recommended for new sce users',
|
|
97
|
-
value: 'use-
|
|
97
|
+
value: 'use-sce'
|
|
98
98
|
},
|
|
99
99
|
{
|
|
100
100
|
name: 'Keep existing steering (skip sce steering) - For projects with custom steering rules',
|
|
@@ -167,7 +167,7 @@ class SteeringManager {
|
|
|
167
167
|
* @param {string} projectPath - 项目根目录路径
|
|
168
168
|
* @returns {Promise<Object>} 安装结果
|
|
169
169
|
*/
|
|
170
|
-
async
|
|
170
|
+
async installSceSteering(projectPath) {
|
|
171
171
|
const steeringPath = path.join(projectPath, this.steeringDir);
|
|
172
172
|
const templatePath = path.join(__dirname, '../../template/.sce/steering');
|
|
173
173
|
|
package/lib/task/task-claimer.js
CHANGED
|
@@ -97,8 +97,7 @@ class TaskClaimer {
|
|
|
97
97
|
return [];
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
|
|
101
|
-
const markerHeaderRegex = /^\s*##\s+(?:(?:sce|kse)\s+)?Status\s+Markers\s*$/i;
|
|
100
|
+
const markerHeaderRegex = /^\s*##\s+(?:sce\s+)?Status\s+Markers\s*$/i;
|
|
102
101
|
const sectionHeaderRegex = /^\s*##\s+/;
|
|
103
102
|
|
|
104
103
|
const markerLine = lines.findIndex((line) => markerHeaderRegex.test(String(line || '')));
|
|
@@ -92,7 +92,7 @@ class WorkspaceContextResolver {
|
|
|
92
92
|
* @param {string} dirPath - Directory path to check
|
|
93
93
|
* @returns {Promise<boolean>} True if directory contains .sce/ structure
|
|
94
94
|
*/
|
|
95
|
-
async
|
|
95
|
+
async isValidSceDirectory(dirPath) {
|
|
96
96
|
try {
|
|
97
97
|
const kiroPath = path.join(dirPath, '.sce');
|
|
98
98
|
const exists = await fs.pathExists(kiroPath);
|
|
@@ -184,7 +184,7 @@ class WorkspaceContextResolver {
|
|
|
184
184
|
const targetDir = currentDir || process.cwd();
|
|
185
185
|
|
|
186
186
|
// Check if it's a valid sce directory
|
|
187
|
-
const isValid = await this.
|
|
187
|
+
const isValid = await this.isValidSceDirectory(targetDir);
|
|
188
188
|
if (!isValid) {
|
|
189
189
|
return false;
|
|
190
190
|
}
|
|
@@ -210,7 +210,7 @@ class WorkspaceContextResolver {
|
|
|
210
210
|
|
|
211
211
|
if (!workspace) {
|
|
212
212
|
const targetDir = currentDir || process.cwd();
|
|
213
|
-
const isValid = await this.
|
|
213
|
+
const isValid = await this.isValidSceDirectory(targetDir);
|
|
214
214
|
|
|
215
215
|
if (isValid) {
|
|
216
216
|
throw new Error(
|
|
@@ -48,62 +48,20 @@ class WorkspaceStateManager {
|
|
|
48
48
|
return path.join(homeDir, '.sce', 'workspace-state.json');
|
|
49
49
|
}
|
|
50
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() {
|
|
57
|
-
const homeDir = os.homedir();
|
|
58
|
-
return path.join(homeDir, '.kse', 'workspace-state.json');
|
|
59
|
-
}
|
|
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
|
-
|
|
72
51
|
/**
|
|
73
52
|
* Load workspace state from disk
|
|
74
53
|
*
|
|
75
|
-
* Supports automatic migration from legacy format (workspaces.json + config.json)
|
|
76
|
-
*
|
|
77
54
|
* @returns {Promise<boolean>} True if loaded successfully
|
|
78
55
|
*/
|
|
79
56
|
async load() {
|
|
80
57
|
try {
|
|
81
|
-
// Try loading new format
|
|
82
58
|
const exists = await fs.pathExists(this.statePath);
|
|
83
|
-
|
|
84
59
|
if (exists) {
|
|
85
60
|
await this.loadNewFormat();
|
|
86
61
|
this.loaded = true;
|
|
87
62
|
return true;
|
|
88
63
|
}
|
|
89
64
|
|
|
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
|
-
|
|
99
|
-
// Check for legacy format and migrate
|
|
100
|
-
if (await this.hasLegacyFiles()) {
|
|
101
|
-
console.log('Migrating workspace configuration to new format...');
|
|
102
|
-
await this.migrateFromLegacy();
|
|
103
|
-
this.loaded = true;
|
|
104
|
-
return true;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
65
|
// Initialize empty state
|
|
108
66
|
this.state = {
|
|
109
67
|
version: '1.0',
|
|
@@ -160,128 +118,6 @@ class WorkspaceStateManager {
|
|
|
160
118
|
};
|
|
161
119
|
}
|
|
162
120
|
|
|
163
|
-
/**
|
|
164
|
-
* Check if legacy configuration files exist
|
|
165
|
-
*
|
|
166
|
-
* @private
|
|
167
|
-
* @returns {Promise<boolean>}
|
|
168
|
-
*/
|
|
169
|
-
async hasLegacyFiles() {
|
|
170
|
-
if (!this.isDefaultStatePath()) {
|
|
171
|
-
return false;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
const homeDir = os.homedir();
|
|
175
|
-
const legacyWorkspacesPath = path.join(homeDir, '.kse', 'workspaces.json');
|
|
176
|
-
const legacyConfigPath = path.join(homeDir, '.kse', 'config.json');
|
|
177
|
-
|
|
178
|
-
const workspacesExists = await fs.pathExists(legacyWorkspacesPath);
|
|
179
|
-
const configExists = await fs.pathExists(legacyConfigPath);
|
|
180
|
-
|
|
181
|
-
return workspacesExists || configExists;
|
|
182
|
-
}
|
|
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
|
-
|
|
212
|
-
/**
|
|
213
|
-
* Migrate from legacy format (workspaces.json + config.json)
|
|
214
|
-
*
|
|
215
|
-
* @private
|
|
216
|
-
*/
|
|
217
|
-
async migrateFromLegacy() {
|
|
218
|
-
const homeDir = os.homedir();
|
|
219
|
-
const legacyWorkspacesPath = path.join(homeDir, '.kse', 'workspaces.json');
|
|
220
|
-
const legacyConfigPath = path.join(homeDir, '.kse', 'config.json');
|
|
221
|
-
|
|
222
|
-
// Load legacy workspaces
|
|
223
|
-
let legacyWorkspaces = [];
|
|
224
|
-
if (await fs.pathExists(legacyWorkspacesPath)) {
|
|
225
|
-
const content = await fs.readFile(legacyWorkspacesPath, 'utf8');
|
|
226
|
-
const data = JSON.parse(content);
|
|
227
|
-
legacyWorkspaces = data.workspaces || [];
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
// Load legacy config
|
|
231
|
-
let legacyActiveWorkspace = null;
|
|
232
|
-
let legacyPreferences = {};
|
|
233
|
-
if (await fs.pathExists(legacyConfigPath)) {
|
|
234
|
-
const content = await fs.readFile(legacyConfigPath, 'utf8');
|
|
235
|
-
const data = JSON.parse(content);
|
|
236
|
-
legacyActiveWorkspace = data.active_workspace || null;
|
|
237
|
-
legacyPreferences = data.preferences || {};
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// Merge into new format
|
|
241
|
-
this.state.activeWorkspace = legacyActiveWorkspace;
|
|
242
|
-
this.state.workspaces = new Map();
|
|
243
|
-
|
|
244
|
-
for (const workspaceData of legacyWorkspaces) {
|
|
245
|
-
const workspace = Workspace.fromDict(workspaceData);
|
|
246
|
-
this.state.workspaces.set(workspace.name, workspace);
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
this.state.preferences = {
|
|
250
|
-
autoDetectWorkspace: legacyPreferences.auto_detect_workspace ?? true,
|
|
251
|
-
confirmDestructiveOperations: legacyPreferences.confirm_destructive_operations ?? true
|
|
252
|
-
};
|
|
253
|
-
|
|
254
|
-
// Save to new format
|
|
255
|
-
await this.save();
|
|
256
|
-
|
|
257
|
-
// Backup legacy files
|
|
258
|
-
await this.backupLegacyFiles();
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
/**
|
|
262
|
-
* Backup legacy configuration files
|
|
263
|
-
*
|
|
264
|
-
* @private
|
|
265
|
-
*/
|
|
266
|
-
async backupLegacyFiles() {
|
|
267
|
-
const homeDir = os.homedir();
|
|
268
|
-
const legacyWorkspacesPath = path.join(homeDir, '.kse', 'workspaces.json');
|
|
269
|
-
const legacyConfigPath = path.join(homeDir, '.kse', 'config.json');
|
|
270
|
-
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
271
|
-
|
|
272
|
-
if (await fs.pathExists(legacyWorkspacesPath)) {
|
|
273
|
-
const backupPath = path.join(homeDir, '.kse', `workspaces.json.backup-${timestamp}`);
|
|
274
|
-
await fs.copy(legacyWorkspacesPath, backupPath);
|
|
275
|
-
await fs.remove(legacyWorkspacesPath);
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
if (await fs.pathExists(legacyConfigPath)) {
|
|
279
|
-
const backupPath = path.join(homeDir, '.kse', `config.json.backup-${timestamp}`);
|
|
280
|
-
await fs.copy(legacyConfigPath, backupPath);
|
|
281
|
-
await fs.remove(legacyConfigPath);
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
|
|
285
121
|
/**
|
|
286
122
|
* Save workspace state to disk (atomic operation)
|
|
287
123
|
*
|
|
@@ -4,7 +4,7 @@ const FIXTURE_ROOT = 'tests/fixtures/moqui-core-regression/workspace/.sce';
|
|
|
4
4
|
const REQUIRED_TRACKED_FILES = [
|
|
5
5
|
`${FIXTURE_ROOT}/specs/60-10-moqui-core-order-query/custom/scene-package.json`,
|
|
6
6
|
`${FIXTURE_ROOT}/specs/60-10-moqui-core-order-query/custom/scene.yaml`,
|
|
7
|
-
`${FIXTURE_ROOT}/templates/scene-packages/
|
|
7
|
+
`${FIXTURE_ROOT}/templates/scene-packages/sce.scene--erp-order-query-read--0.1.0/scene-package.json`,
|
|
8
8
|
];
|
|
9
9
|
const DISALLOWED_TRACKED_PREFIXES = [
|
|
10
10
|
`${FIXTURE_ROOT}/reports/`,
|
|
@@ -303,7 +303,7 @@ function _buildAdoptionConfig(existing, nowIso, sceVersion) {
|
|
|
303
303
|
adoptedAt,
|
|
304
304
|
steeringStrategy: typeof base.steeringStrategy === 'string' && base.steeringStrategy.trim()
|
|
305
305
|
? base.steeringStrategy
|
|
306
|
-
: 'use-
|
|
306
|
+
: 'use-sce',
|
|
307
307
|
multiUserMode: base.multiUserMode === true,
|
|
308
308
|
runtimePolicy: {
|
|
309
309
|
agent_parity_permissions: true,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "scene-capability-engine",
|
|
3
|
-
"version": "3.6.
|
|
3
|
+
"version": "3.6.38",
|
|
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": {
|
|
@@ -38,6 +38,8 @@
|
|
|
38
38
|
"test:skip-audit": "node scripts/check-skip-allowlist.js",
|
|
39
39
|
"test:sce-tracking": "node scripts/check-sce-tracking.js",
|
|
40
40
|
"test:brand-consistency": "node scripts/check-branding-consistency.js",
|
|
41
|
+
"audit:steering": "node scripts/steering-content-audit.js --fail-on-error",
|
|
42
|
+
"report:steering-audit": "node scripts/steering-content-audit.js --json",
|
|
41
43
|
"test:watch": "npx jest --watch",
|
|
42
44
|
"coverage": "npx jest --coverage",
|
|
43
45
|
"report:moqui-metadata": "node scripts/moqui-metadata-extract.js --json",
|
|
@@ -76,7 +78,7 @@
|
|
|
76
78
|
"gate:release-asset-integrity": "node scripts/release-asset-integrity-check.js",
|
|
77
79
|
"report:release-risk-remediation": "node scripts/release-risk-remediation-bundle.js --json",
|
|
78
80
|
"report:moqui-core-regression": "node scripts/moqui-core-regression-suite.js --json",
|
|
79
|
-
"prepublishOnly": "npm run test:release && npm run test:skip-audit && npm run test:sce-tracking && npm run test:brand-consistency && npm run gate:git-managed && npm run gate:errorbook-registry-health && npm run gate:errorbook-release && npm run report:interactive-governance -- --fail-on-alert",
|
|
81
|
+
"prepublishOnly": "npm run test:release && npm run test:skip-audit && npm run test:sce-tracking && npm run test:brand-consistency && npm run audit:steering && npm run gate:git-managed && npm run gate:errorbook-registry-health && npm run gate:errorbook-release && npm run report:interactive-governance -- --fail-on-alert",
|
|
80
82
|
"publish:manual": "npm publish --access public",
|
|
81
83
|
"install-global": "npm install -g .",
|
|
82
84
|
"uninstall-global": "npm uninstall -g scene-capability-engine"
|
package/template/.sce/README.md
CHANGED
|
@@ -45,7 +45,7 @@ This project uses **Spec-driven development** - a structured approach where:
|
|
|
45
45
|
|
|
46
46
|
### Workspace Management
|
|
47
47
|
- `sce workspace create/list/switch/info/remove` — Manage multiple sce projects
|
|
48
|
-
- Global state: `~/.
|
|
48
|
+
- Global state: `~/.sce/workspace-state.json`
|
|
49
49
|
|
|
50
50
|
### Environment Configuration
|
|
51
51
|
- `sce env list/switch/info/register/unregister/rollback/verify/run` — Multi-environment management
|