scene-capability-engine 3.6.50 → 3.6.52
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 +11 -0
- package/README.md +3 -3
- package/README.zh.md +3 -3
- package/docs/command-reference.md +4 -3
- package/docs/magicball-adaptation-task-checklist-v1.md +18 -1
- package/docs/magicball-cli-invocation-examples.md +7 -0
- package/docs/magicball-integration-issue-tracker.md +2 -2
- package/docs/magicball-sce-adaptation-guide.md +2 -2
- package/docs/magicball-write-auth-adaptation-guide.md +7 -0
- package/docs/multi-agent-coordination-guide.md +2 -2
- package/docs/releases/v3.6.51.md +18 -0
- package/docs/releases/v3.6.52.md +20 -0
- package/docs/zh/releases/v3.6.51.md +18 -0
- package/docs/zh/releases/v3.6.52.md +20 -0
- package/lib/commands/app.js +144 -17
- package/lib/commands/mode.js +40 -10
- package/lib/workspace/collab-governance-audit.js +168 -0
- package/lib/workspace/takeover-baseline.js +57 -6
- package/package.json +1 -1
- package/template/.sce/README.md +2 -2
- package/template/.sce/steering/CORE_PRINCIPLES.md +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [3.6.52] - 2026-03-16
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- Added `sce app runtime uninstall` with active-release protection, explicit installed-vs-active runtime projection fields, and MagicBall-facing runtime uninstall/auth documentation.
|
|
14
|
+
- Extended co-work governance auditing so shared `errorbook` registry baseline and managed `errorbook_convergence` defaults are now checked alongside multi-agent/runtime-state drift.
|
|
15
|
+
|
|
16
|
+
## [3.6.51] - 2026-03-15
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
- Added a new core steering baseline rule requiring rewrite-style changes to remove obsolete code, dead branches, abandoned adapters, and stale references in the same change unless an explicit temporary compatibility plan exists.
|
|
20
|
+
|
|
10
21
|
## [3.6.50] - 2026-03-14
|
|
11
22
|
|
|
12
23
|
### Changed
|
package/README.md
CHANGED
|
@@ -165,7 +165,7 @@ MagicBall-specific integration surfaces now also include:
|
|
|
165
165
|
|
|
166
166
|
- `sce app bundle list|show|register`
|
|
167
167
|
- `sce app registry status|configure|sync*`
|
|
168
|
-
- `sce app runtime show|releases|install|activate`
|
|
168
|
+
- `sce app runtime show|releases|install|activate|uninstall`
|
|
169
169
|
- `sce app engineering show|attach|hydrate|activate`
|
|
170
170
|
- `sce mode application|ontology|engineering home`
|
|
171
171
|
- `sce pm requirement|tracking|planning|change|issue ... --json`
|
|
@@ -218,5 +218,5 @@ MIT. See [LICENSE](LICENSE).
|
|
|
218
218
|
|
|
219
219
|
---
|
|
220
220
|
|
|
221
|
-
**Version**: 3.6.
|
|
222
|
-
**Last Updated**: 2026-03-
|
|
221
|
+
**Version**: 3.6.52
|
|
222
|
+
**Last Updated**: 2026-03-16
|
package/README.zh.md
CHANGED
|
@@ -170,7 +170,7 @@ SCE 默认是强治理的。
|
|
|
170
170
|
|
|
171
171
|
- `sce app bundle list|show|register`
|
|
172
172
|
- `sce app registry status|configure|sync*`
|
|
173
|
-
- `sce app runtime show|releases|install|activate`
|
|
173
|
+
- `sce app runtime show|releases|install|activate|uninstall`
|
|
174
174
|
- `sce app engineering show|attach|hydrate|activate`
|
|
175
175
|
- `sce mode application|ontology|engineering home`
|
|
176
176
|
- `sce pm requirement|tracking|planning|change|issue ... --json`
|
|
@@ -223,5 +223,5 @@ MIT,见 [LICENSE](LICENSE)。
|
|
|
223
223
|
|
|
224
224
|
---
|
|
225
225
|
|
|
226
|
-
**版本**:3.6.
|
|
227
|
-
**最后更新**:2026-03-
|
|
226
|
+
**版本**:3.6.52
|
|
227
|
+
**最后更新**:2026-03-16
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
> Quick reference for all `sce` commands
|
|
4
4
|
|
|
5
|
-
**Version**: 3.6.
|
|
6
|
-
**Last Updated**: 2026-03-
|
|
5
|
+
**Version**: 3.6.52
|
|
6
|
+
**Last Updated**: 2026-03-16
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
@@ -135,7 +135,7 @@ Timeline policy:
|
|
|
135
135
|
- default enabled with local retention under `.sce/timeline/snapshots/`
|
|
136
136
|
- stage/key-event checkpoints are automatically captured for `studio` and `session` commands
|
|
137
137
|
- interval auto-checkpoints are integrated in the same flow via timeline checkpoint capture
|
|
138
|
-
- `timeline push` now blocks before snapshot/push when collaboration governance drifts, so tracked runtime state, missing co-work ignore rules,
|
|
138
|
+
- `timeline push` now blocks before snapshot/push when collaboration governance drifts, so tracked runtime state, missing co-work ignore rules, missing shared `errorbook` registry baseline, invalid multi-agent config, legacy `.kiro*` references, or steering boundary drift cannot pass through managed push flow
|
|
139
139
|
|
|
140
140
|
### Value Metrics
|
|
141
141
|
|
|
@@ -393,6 +393,7 @@ sce app runtime show --app customer-order-demo --json
|
|
|
393
393
|
sce app runtime releases --app customer-order-demo --json
|
|
394
394
|
sce app runtime install --app customer-order-demo --release <release-id> --json
|
|
395
395
|
sce app runtime activate --app customer-order-demo --release <release-id> --json
|
|
396
|
+
sce app runtime uninstall --app customer-order-demo --release <release-id> --json
|
|
396
397
|
|
|
397
398
|
# Engineering projection
|
|
398
399
|
sce app engineering show --app customer-order-demo --json
|
|
@@ -70,6 +70,8 @@ Important fields:
|
|
|
70
70
|
- `summary.app_name`
|
|
71
71
|
- `summary.runtime_version`
|
|
72
72
|
- `summary.install_status`
|
|
73
|
+
- `summary.installed_release_id`
|
|
74
|
+
- `summary.active_release_id`
|
|
73
75
|
- `summary.release_count`
|
|
74
76
|
- `view_model.current_release`
|
|
75
77
|
- `view_model.entrypoint`
|
|
@@ -84,6 +86,7 @@ sce app runtime releases --app customer-order-demo --json
|
|
|
84
86
|
Expected UI:
|
|
85
87
|
- release table/list
|
|
86
88
|
- active/default release marker
|
|
89
|
+
- installed marker
|
|
87
90
|
- runtime version
|
|
88
91
|
- release status
|
|
89
92
|
- entrypoint
|
|
@@ -113,6 +116,19 @@ Done when:
|
|
|
113
116
|
- active release changes in UI
|
|
114
117
|
- `mode application home` reflects the new active release after refresh
|
|
115
118
|
|
|
119
|
+
### Task 2.5
|
|
120
|
+
Wire uninstall action for installed-but-not-active release.
|
|
121
|
+
|
|
122
|
+
Command:
|
|
123
|
+
```bash
|
|
124
|
+
sce app runtime uninstall --app customer-order-demo --release <release-id> --json
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Done when:
|
|
128
|
+
- uninstall button is shown only for installed and non-active release
|
|
129
|
+
- uninstall removes local installed state after refresh
|
|
130
|
+
- the same release can be installed again through existing install flow
|
|
131
|
+
|
|
116
132
|
## Phase 3: Ontology Mode
|
|
117
133
|
|
|
118
134
|
### Task 3.1
|
|
@@ -288,6 +304,7 @@ Commands that matter now:
|
|
|
288
304
|
- `sce app engineering activate`
|
|
289
305
|
- `sce app runtime install`
|
|
290
306
|
- `sce app runtime activate`
|
|
307
|
+
- `sce app runtime uninstall`
|
|
291
308
|
- `sce pm * upsert`
|
|
292
309
|
- `sce ontology * upsert`
|
|
293
310
|
|
|
@@ -371,7 +388,7 @@ MagicBall can be considered adapted to the current SCE version when:
|
|
|
371
388
|
4. Ontology Mode reads `sce ontology *`
|
|
372
389
|
5. Assurance tabs read `sce assurance *`
|
|
373
390
|
6. write actions pass `--auth-lease`
|
|
374
|
-
7. install / activate / attach / hydrate actions work from the UI
|
|
391
|
+
7. install / activate / uninstall / attach / hydrate actions work from the UI
|
|
375
392
|
|
|
376
393
|
## Practical Conclusion
|
|
377
394
|
|
|
@@ -55,6 +55,8 @@ Typical fields MagicBall cares about:
|
|
|
55
55
|
- `summary.app_name`
|
|
56
56
|
- `summary.runtime_version`
|
|
57
57
|
- `summary.install_status`
|
|
58
|
+
- `summary.installed_release_id`
|
|
59
|
+
- `summary.active_release_id`
|
|
58
60
|
- `summary.release_count`
|
|
59
61
|
- `view_model.current_release`
|
|
60
62
|
|
|
@@ -73,6 +75,11 @@ sce app runtime install --app customer-order-demo --release rel-2026-03 --json
|
|
|
73
75
|
sce app runtime activate --app customer-order-demo --release rel-2026-03 --json
|
|
74
76
|
```
|
|
75
77
|
|
|
78
|
+
### 2.5 Uninstall a non-active installed release
|
|
79
|
+
```bash
|
|
80
|
+
sce app runtime uninstall --app customer-order-demo --release rel-2026-03 --json
|
|
81
|
+
```
|
|
82
|
+
|
|
76
83
|
## 3. Ontology Mode Examples
|
|
77
84
|
|
|
78
85
|
### 3.1 Read ontology home
|
|
@@ -22,7 +22,7 @@ SCE changes completed and now available for MagicBall:
|
|
|
22
22
|
- `mode ontology home --app ... --json`
|
|
23
23
|
- `mode engineering home --app ... --json`
|
|
24
24
|
- `app registry status/configure/sync*`
|
|
25
|
-
- `app runtime show/releases/install/activate`
|
|
25
|
+
- `app runtime show/releases/install/activate/uninstall`
|
|
26
26
|
- `app engineering show/attach/hydrate/activate`
|
|
27
27
|
- `pm requirement/tracking/planning/change/issue` data plane
|
|
28
28
|
- `ontology er/br/dl` + `ontology triad summary`
|
|
@@ -33,7 +33,7 @@ SCE changes completed and now available for MagicBall:
|
|
|
33
33
|
### Current recommended MagicBall consumption order
|
|
34
34
|
1. consume `mode * home` as the top-level source for the three modes
|
|
35
35
|
2. consume `pm`, `ontology`, and `assurance` table payloads
|
|
36
|
-
3. wire runtime install/activate and engineering attach/hydrate/activate actions
|
|
36
|
+
3. wire runtime install/activate/uninstall and engineering attach/hydrate/activate actions
|
|
37
37
|
4. use demo app: `customer-order-demo`
|
|
38
38
|
|
|
39
39
|
### Related SCE docs
|
|
@@ -25,7 +25,7 @@ Use these documents together:
|
|
|
25
25
|
SCE currently provides MagicBall-facing support for:
|
|
26
26
|
1. `app bundle registry`
|
|
27
27
|
2. `application / ontology / engineering home projections`
|
|
28
|
-
3. `app runtime install / activate`
|
|
28
|
+
3. `app runtime install / activate / uninstall`
|
|
29
29
|
4. `app engineering attach / hydrate / activate`
|
|
30
30
|
5. `pm` delivery data plane
|
|
31
31
|
6. `ontology` triad data plane
|
|
@@ -100,7 +100,7 @@ Use `docs/magicball-cli-invocation-examples.md` for copy-ready commands.
|
|
|
100
100
|
- `sce app engineering show`
|
|
101
101
|
|
|
102
102
|
### Runtime and engineering control
|
|
103
|
-
- `sce app runtime show/releases/install/activate`
|
|
103
|
+
- `sce app runtime show/releases/install/activate/uninstall`
|
|
104
104
|
- `sce app engineering show/attach/hydrate/activate`
|
|
105
105
|
- `sce app registry status/configure/sync*`
|
|
106
106
|
|
|
@@ -67,6 +67,7 @@ Current implemented write flows in SCE imply these practical action families:
|
|
|
67
67
|
- `app:engineering:activate`
|
|
68
68
|
- `app:runtime:install`
|
|
69
69
|
- `app:runtime:activate`
|
|
70
|
+
- `app:runtime:uninstall`
|
|
70
71
|
|
|
71
72
|
### Engineering mode PM data plane
|
|
72
73
|
- `pm:requirement:upsert`
|
|
@@ -176,6 +177,7 @@ Recommended UI steps:
|
|
|
176
177
|
| Activate engineering workspace | `sce app engineering activate` | `app:engineering:activate` |
|
|
177
178
|
| Install runtime release | `sce app runtime install` | `app:runtime:install` |
|
|
178
179
|
| Activate runtime release | `sce app runtime activate` | `app:runtime:activate` |
|
|
180
|
+
| Uninstall runtime release | `sce app runtime uninstall` | `app:runtime:uninstall` |
|
|
179
181
|
| Save requirement | `sce pm requirement upsert` | `pm:requirement:upsert` |
|
|
180
182
|
| Save tracking item | `sce pm tracking upsert` | `pm:tracking:upsert` |
|
|
181
183
|
| Save plan | `sce pm planning upsert` | `pm:planning:upsert` |
|
|
@@ -196,6 +198,11 @@ Recommended UI steps:
|
|
|
196
198
|
sce auth grant --scope app:runtime:activate --reason "activate selected runtime release" --json
|
|
197
199
|
```
|
|
198
200
|
|
|
201
|
+
### Runtime uninstall lease
|
|
202
|
+
```bash
|
|
203
|
+
sce auth grant --scope app:runtime:uninstall --reason "remove non-active installed runtime release" --json
|
|
204
|
+
```
|
|
205
|
+
|
|
199
206
|
### Multiple scopes if one workflow batches mutations
|
|
200
207
|
```bash
|
|
201
208
|
sce auth grant --scope app:engineering:attach,app:engineering:hydrate,app:engineering:activate --reason "initialize engineering workspace" --json
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# v3.6.51 Release Notes
|
|
2
|
+
|
|
3
|
+
Release date: 2026-03-15
|
|
4
|
+
|
|
5
|
+
## Highlights
|
|
6
|
+
|
|
7
|
+
- Added a new SCE core principle that requires rewrite-style feature, UI, and module changes to remove obsolete implementations in the same change instead of leaving dead code behind.
|
|
8
|
+
- Extended takeover baseline repair so adopted projects automatically regain this obsolete-code-cleanup principle if their steering baseline drifts.
|
|
9
|
+
- Synced package and documentation version metadata for the new release, including runtime/template README footers and current-version guide headers.
|
|
10
|
+
|
|
11
|
+
## Validation
|
|
12
|
+
|
|
13
|
+
- `npx jest tests/unit/workspace/takeover-baseline.test.js --runInBand`
|
|
14
|
+
|
|
15
|
+
## Release Notes
|
|
16
|
+
|
|
17
|
+
- This patch tightens SCE's default governance against AI-generated garbage code by making dead-code cleanup an explicit baseline requirement rather than an optional style preference.
|
|
18
|
+
- The rule applies across all SCE-managed projects and clarifies that temporary retention is allowed only when compatibility or rollback constraints are documented with a concrete cleanup plan.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# v3.6.52 Release Notes
|
|
2
|
+
|
|
3
|
+
Release date: 2026-03-16
|
|
4
|
+
|
|
5
|
+
## Highlights
|
|
6
|
+
|
|
7
|
+
- Added `sce app runtime uninstall` so MagicBall and CLI users can remove a non-active installed runtime release without editing local SCE state by hand.
|
|
8
|
+
- Split runtime projection semantics so installed release and active release are exposed separately in runtime/app-home payloads.
|
|
9
|
+
- Extended co-work governance auditing to enforce shared `errorbook` registry availability and managed `errorbook_convergence` defaults as part of the default collaboration baseline.
|
|
10
|
+
|
|
11
|
+
## Validation
|
|
12
|
+
|
|
13
|
+
- `npx jest tests/unit/commands/app-mode.test.js --runInBand`
|
|
14
|
+
- `npx jest tests/unit/workspace/collab-governance-audit.test.js tests/unit/scripts/collab-governance-gate.test.js --runInBand`
|
|
15
|
+
- `node scripts/collab-governance-gate.js --json`
|
|
16
|
+
|
|
17
|
+
## Release Notes
|
|
18
|
+
|
|
19
|
+
- This patch closes two integration gaps: MagicBall can now offer uninstall/reinstall flows cleanly, and co-work governance now treats shared failure-learning resources as a real default baseline instead of a merely available optional capability.
|
|
20
|
+
- The runtime model is still a single-installation-slot design; multiple release selection is supported, but multiple local installed runtime versions per app are not introduced in this patch.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# v3.6.51 发布说明
|
|
2
|
+
|
|
3
|
+
发布日期:2026-03-15
|
|
4
|
+
|
|
5
|
+
## 重点变化
|
|
6
|
+
|
|
7
|
+
- 新增一条 SCE 核心原则:功能、UI 或模块发生重写/替换时,失效旧实现必须在同一轮变更中清理,不能继续把废弃代码留在仓库里。
|
|
8
|
+
- 扩展 takeover baseline 修复逻辑;接管项目若缺失这条“清理废弃代码”原则,SCE 会自动补齐基线。
|
|
9
|
+
- 同步更新本次版本的包信息和文档版本元数据,包括运行时/模板 README 尾注以及当前版本说明文档。
|
|
10
|
+
|
|
11
|
+
## 验证
|
|
12
|
+
|
|
13
|
+
- `npx jest tests/unit/workspace/takeover-baseline.test.js --runInBand`
|
|
14
|
+
|
|
15
|
+
## 发布说明
|
|
16
|
+
|
|
17
|
+
- 这个补丁版把“禁止 AI 制造垃圾代码并把旧实现遗留在仓库里”提升为 SCE 的默认治理要求,而不再只是编码习惯建议。
|
|
18
|
+
- 若确实因为兼容、灰度或回滚需要临时保留旧实现,也必须明确说明保留理由、适用边界、退出条件和后续清理计划。
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# v3.6.52 发布说明
|
|
2
|
+
|
|
3
|
+
发布日期:2026-03-16
|
|
4
|
+
|
|
5
|
+
## 重点变化
|
|
6
|
+
|
|
7
|
+
- 新增 `sce app runtime uninstall`,MagicBall 和 CLI 现在都可以在不手改本地状态的前提下卸载“已安装但未激活”的运行时版本。
|
|
8
|
+
- 运行时投影语义已拆分为“已安装版本”和“当前激活版本”,前端不再需要自行猜测 installed / active 状态。
|
|
9
|
+
- co-work 治理审计已扩展为默认检查共享 `errorbook` registry 是否可用,以及 managed 项目的 `errorbook_convergence` 基线是否漂移。
|
|
10
|
+
|
|
11
|
+
## 验证
|
|
12
|
+
|
|
13
|
+
- `npx jest tests/unit/commands/app-mode.test.js --runInBand`
|
|
14
|
+
- `npx jest tests/unit/workspace/collab-governance-audit.test.js tests/unit/scripts/collab-governance-gate.test.js --runInBand`
|
|
15
|
+
- `node scripts/collab-governance-gate.js --json`
|
|
16
|
+
|
|
17
|
+
## 发布说明
|
|
18
|
+
|
|
19
|
+
- 这个补丁版补上了两个真实缺口:一是 MagicBall 运行时版本管理终于具备卸载/重装闭环,二是 co-work 默认协作基线开始真正把共享错题经验资源视为必备能力,而不是“仓库里有这个功能就算支持”。
|
|
20
|
+
- 当前运行时仍然是“单安装槽位”模型;本次支持多版本选择,但不引入同一 app 多个本地安装版本并存。
|
package/lib/commands/app.js
CHANGED
|
@@ -89,17 +89,77 @@ function buildBundleSummary(graph = {}) {
|
|
|
89
89
|
};
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
function
|
|
92
|
+
function getRuntimeProjectionState(graph = {}) {
|
|
93
93
|
const bundle = graph.bundle || {};
|
|
94
94
|
const runtimeRelease = graph.runtime_release || {};
|
|
95
95
|
const metadata = bundle.metadata && typeof bundle.metadata === 'object' ? bundle.metadata : {};
|
|
96
96
|
const installation = metadata.runtime_installation && typeof metadata.runtime_installation === 'object'
|
|
97
97
|
? metadata.runtime_installation
|
|
98
98
|
: {};
|
|
99
|
+
const runtimeActivation = metadata.runtime_activation && typeof metadata.runtime_activation === 'object'
|
|
100
|
+
? metadata.runtime_activation
|
|
101
|
+
: {};
|
|
99
102
|
const serviceCatalog = metadata.service_catalog && typeof metadata.service_catalog === 'object'
|
|
100
103
|
? metadata.service_catalog
|
|
101
104
|
: {};
|
|
102
105
|
const releases = Array.isArray(serviceCatalog.releases) ? serviceCatalog.releases : [];
|
|
106
|
+
const installStatus = normalizeString(installation.status) || 'not-installed';
|
|
107
|
+
const installedReleaseId = installStatus === 'installed'
|
|
108
|
+
? (normalizeString(installation.release_id) || null)
|
|
109
|
+
: null;
|
|
110
|
+
const activeReleaseId = normalizeString(
|
|
111
|
+
bundle.runtime_release_id
|
|
112
|
+
|| runtimeRelease.release_id
|
|
113
|
+
|| runtimeActivation.active_release_id
|
|
114
|
+
) || null;
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
metadata,
|
|
118
|
+
installation,
|
|
119
|
+
runtimeActivation,
|
|
120
|
+
serviceCatalog,
|
|
121
|
+
releases,
|
|
122
|
+
installStatus,
|
|
123
|
+
installedReleaseId,
|
|
124
|
+
activeReleaseId
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function buildRuntimeReleaseItems(graph = {}) {
|
|
129
|
+
const state = getRuntimeProjectionState(graph);
|
|
130
|
+
return state.releases.map((item) => {
|
|
131
|
+
const releaseId = normalizeString(item && item.release_id) || null;
|
|
132
|
+
const installed = Boolean(releaseId && state.installedReleaseId && releaseId === state.installedReleaseId);
|
|
133
|
+
const active = Boolean(releaseId && state.activeReleaseId && releaseId === state.activeReleaseId);
|
|
134
|
+
const availableActions = [];
|
|
135
|
+
|
|
136
|
+
if (!installed) {
|
|
137
|
+
availableActions.push('install');
|
|
138
|
+
}
|
|
139
|
+
if (!active) {
|
|
140
|
+
availableActions.push('activate');
|
|
141
|
+
}
|
|
142
|
+
if (installed && !active) {
|
|
143
|
+
availableActions.push('uninstall');
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return {
|
|
147
|
+
...item,
|
|
148
|
+
installed,
|
|
149
|
+
active,
|
|
150
|
+
installation_status: installed ? state.installStatus : 'not-installed',
|
|
151
|
+
can_install: !installed,
|
|
152
|
+
can_activate: !active,
|
|
153
|
+
can_uninstall: installed && !active,
|
|
154
|
+
available_actions: availableActions
|
|
155
|
+
};
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function buildRuntimeSummary(graph = {}) {
|
|
160
|
+
const bundle = graph.bundle || {};
|
|
161
|
+
const runtimeRelease = graph.runtime_release || {};
|
|
162
|
+
const state = getRuntimeProjectionState(graph);
|
|
103
163
|
return {
|
|
104
164
|
app_id: bundle.app_id || null,
|
|
105
165
|
app_name: bundle.app_name || null,
|
|
@@ -107,10 +167,11 @@ function buildRuntimeSummary(graph = {}) {
|
|
|
107
167
|
runtime_version: runtimeRelease.runtime_version || null,
|
|
108
168
|
release_status: runtimeRelease.release_status || null,
|
|
109
169
|
runtime_status: runtimeRelease.runtime_status || null,
|
|
110
|
-
install_status:
|
|
111
|
-
install_root: installation.install_root || null,
|
|
112
|
-
release_count: releases.length,
|
|
113
|
-
|
|
170
|
+
install_status: state.installStatus,
|
|
171
|
+
install_root: state.installation.install_root || null,
|
|
172
|
+
release_count: state.releases.length,
|
|
173
|
+
installed_release_id: state.installedReleaseId,
|
|
174
|
+
active_release_id: state.activeReleaseId
|
|
114
175
|
};
|
|
115
176
|
}
|
|
116
177
|
|
|
@@ -564,8 +625,7 @@ async function runAppRuntimeShowCommand(options = {}, dependencies = {}) {
|
|
|
564
625
|
throw new Error('--app is required');
|
|
565
626
|
}
|
|
566
627
|
const { graph } = await requireAppGraph(appRef, dependencies);
|
|
567
|
-
const
|
|
568
|
-
const serviceCatalog = metadata.service_catalog && typeof metadata.service_catalog === 'object' ? metadata.service_catalog : {};
|
|
628
|
+
const state = getRuntimeProjectionState(graph);
|
|
569
629
|
const payload = {
|
|
570
630
|
mode: 'app-runtime-show',
|
|
571
631
|
generated_at: new Date().toISOString(),
|
|
@@ -575,12 +635,14 @@ async function runAppRuntimeShowCommand(options = {}, dependencies = {}) {
|
|
|
575
635
|
summary: buildRuntimeSummary(graph),
|
|
576
636
|
bundle: graph.bundle,
|
|
577
637
|
runtime_release: graph.runtime_release,
|
|
578
|
-
runtime_installation:
|
|
638
|
+
runtime_installation: Object.keys(state.installation).length > 0 ? state.installation : null,
|
|
639
|
+
runtime_activation: Object.keys(state.runtimeActivation).length > 0 ? state.runtimeActivation : null,
|
|
579
640
|
service_catalog: {
|
|
580
|
-
default_release_id: serviceCatalog.default_release_id || null,
|
|
581
|
-
release_count:
|
|
582
|
-
source: serviceCatalog.source || null
|
|
583
|
-
}
|
|
641
|
+
default_release_id: state.serviceCatalog.default_release_id || null,
|
|
642
|
+
release_count: state.releases.length,
|
|
643
|
+
source: state.serviceCatalog.source || null
|
|
644
|
+
},
|
|
645
|
+
releases: buildRuntimeReleaseItems(graph)
|
|
584
646
|
};
|
|
585
647
|
printPayload(payload, options, 'App Runtime Show');
|
|
586
648
|
return payload;
|
|
@@ -592,9 +654,8 @@ async function runAppRuntimeReleasesCommand(options = {}, dependencies = {}) {
|
|
|
592
654
|
throw new Error('--app is required');
|
|
593
655
|
}
|
|
594
656
|
const { graph } = await requireAppGraph(appRef, dependencies);
|
|
595
|
-
const
|
|
596
|
-
const
|
|
597
|
-
const releases = Array.isArray(serviceCatalog.releases) ? serviceCatalog.releases : [];
|
|
657
|
+
const state = getRuntimeProjectionState(graph);
|
|
658
|
+
const releases = buildRuntimeReleaseItems(graph);
|
|
598
659
|
const payload = {
|
|
599
660
|
mode: 'app-runtime-releases',
|
|
600
661
|
generated_at: new Date().toISOString(),
|
|
@@ -603,12 +664,14 @@ async function runAppRuntimeReleasesCommand(options = {}, dependencies = {}) {
|
|
|
603
664
|
},
|
|
604
665
|
summary: {
|
|
605
666
|
total: releases.length,
|
|
606
|
-
default_release_id: serviceCatalog.default_release_id || null
|
|
667
|
+
default_release_id: state.serviceCatalog.default_release_id || null,
|
|
668
|
+
installed_release_id: state.installedReleaseId,
|
|
669
|
+
active_release_id: state.activeReleaseId
|
|
607
670
|
},
|
|
608
671
|
items: releases,
|
|
609
672
|
view_model: {
|
|
610
673
|
type: 'table',
|
|
611
|
-
columns: ['release_id', 'runtime_version', 'release_channel', 'release_status', 'runtime_status', 'published_at']
|
|
674
|
+
columns: ['release_id', 'runtime_version', 'release_channel', 'release_status', 'runtime_status', 'installed', 'active', 'published_at']
|
|
612
675
|
},
|
|
613
676
|
mb_status: graph.runtime_release && graph.runtime_release.runtime_status ? graph.runtime_release.runtime_status : (graph.bundle && graph.bundle.status ? graph.bundle.status : 'unknown')
|
|
614
677
|
};
|
|
@@ -704,6 +767,58 @@ async function runAppRuntimeActivateCommand(options = {}, dependencies = {}) {
|
|
|
704
767
|
return payload;
|
|
705
768
|
}
|
|
706
769
|
|
|
770
|
+
async function runAppRuntimeUninstallCommand(options = {}, dependencies = {}) {
|
|
771
|
+
const appRef = normalizeString(options.app);
|
|
772
|
+
if (!appRef) {
|
|
773
|
+
throw new Error('--app is required');
|
|
774
|
+
}
|
|
775
|
+
await ensureAuthorized('app:runtime:uninstall', options, dependencies);
|
|
776
|
+
const fileSystem = dependencies.fileSystem || fs;
|
|
777
|
+
const { store, graph } = await requireAppGraph(appRef, dependencies);
|
|
778
|
+
const nextPayload = graphToRegisterPayload(graph);
|
|
779
|
+
const state = getRuntimeProjectionState(graph);
|
|
780
|
+
const installedReleaseId = state.installedReleaseId;
|
|
781
|
+
const targetReleaseId = normalizeString(options.release) || installedReleaseId;
|
|
782
|
+
|
|
783
|
+
if (!installedReleaseId) {
|
|
784
|
+
throw new Error('no installed runtime release found for this app');
|
|
785
|
+
}
|
|
786
|
+
if (!targetReleaseId || targetReleaseId !== installedReleaseId) {
|
|
787
|
+
throw new Error(`runtime release is not installed: ${targetReleaseId || '<unknown>'}`);
|
|
788
|
+
}
|
|
789
|
+
if (state.activeReleaseId && targetReleaseId === state.activeReleaseId) {
|
|
790
|
+
throw new Error(`cannot uninstall active runtime release ${targetReleaseId}; activate another release first`);
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
const installRoot = normalizeString(state.installation.install_root);
|
|
794
|
+
if (installRoot) {
|
|
795
|
+
await fileSystem.remove(installRoot);
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
nextPayload.metadata = nextPayload.metadata || {};
|
|
799
|
+
nextPayload.metadata.runtime_installation = {
|
|
800
|
+
status: 'not-installed',
|
|
801
|
+
release_id: null,
|
|
802
|
+
install_root: null,
|
|
803
|
+
uninstalled_at: new Date().toISOString(),
|
|
804
|
+
source: 'sce app runtime uninstall',
|
|
805
|
+
previous_release_id: targetReleaseId
|
|
806
|
+
};
|
|
807
|
+
|
|
808
|
+
const updated = await store.registerAppBundle(nextPayload);
|
|
809
|
+
const updatedState = getRuntimeProjectionState(updated);
|
|
810
|
+
const payload = {
|
|
811
|
+
mode: 'app-runtime-uninstall',
|
|
812
|
+
success: true,
|
|
813
|
+
summary: buildRuntimeSummary(updated),
|
|
814
|
+
uninstalled_release_id: targetReleaseId,
|
|
815
|
+
removed_install_root: installRoot || null,
|
|
816
|
+
runtime_installation: updatedState.installation
|
|
817
|
+
};
|
|
818
|
+
printPayload(payload, options, 'App Runtime Uninstall');
|
|
819
|
+
return payload;
|
|
820
|
+
}
|
|
821
|
+
|
|
707
822
|
function safeRun(handler, options = {}, context = 'app command') {
|
|
708
823
|
Promise.resolve(handler(options))
|
|
709
824
|
.catch((error) => {
|
|
@@ -839,6 +954,17 @@ function registerAppCommands(program) {
|
|
|
839
954
|
.option('--json', 'Print machine-readable JSON output')
|
|
840
955
|
.action((options) => safeRun(runAppRuntimeActivateCommand, options, 'app runtime activate'));
|
|
841
956
|
|
|
957
|
+
runtime
|
|
958
|
+
.command('uninstall')
|
|
959
|
+
.description('Uninstall runtime release for one app bundle')
|
|
960
|
+
.requiredOption('--app <app-id-or-key>', 'App id or app key')
|
|
961
|
+
.option('--release <release-id>', 'Installed runtime release id')
|
|
962
|
+
.option('--auth-lease <lease-id>', 'Write authorization lease id')
|
|
963
|
+
.option('--auth-password <password>', 'Inline auth password if policy allows')
|
|
964
|
+
.option('--actor <actor>', 'Audit actor override')
|
|
965
|
+
.option('--json', 'Print machine-readable JSON output')
|
|
966
|
+
.action((options) => safeRun(runAppRuntimeUninstallCommand, options, 'app runtime uninstall'));
|
|
967
|
+
|
|
842
968
|
const engineering = app
|
|
843
969
|
.command('engineering')
|
|
844
970
|
.description('Manage engineering project projection for one app bundle');
|
|
@@ -903,6 +1029,7 @@ module.exports = {
|
|
|
903
1029
|
runAppRuntimeReleasesCommand,
|
|
904
1030
|
runAppRuntimeInstallCommand,
|
|
905
1031
|
runAppRuntimeActivateCommand,
|
|
1032
|
+
runAppRuntimeUninstallCommand,
|
|
906
1033
|
runAppEngineeringShowCommand,
|
|
907
1034
|
runAppEngineeringAttachCommand,
|
|
908
1035
|
runAppEngineeringHydrateCommand,
|
package/lib/commands/mode.js
CHANGED
|
@@ -37,18 +37,44 @@ function isFreshProjectionCache(cacheRecord, ttlSeconds) {
|
|
|
37
37
|
return (Date.now() - generatedAt) <= maxAgeMs;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
function getRuntimeProjectionState(graph = {}) {
|
|
41
41
|
const bundle = graph.bundle || {};
|
|
42
42
|
const runtimeRelease = graph.runtime_release || {};
|
|
43
|
-
const sceneBindings = Array.isArray(graph.scene_bindings) ? graph.scene_bindings : [];
|
|
44
43
|
const metadata = bundle.metadata && typeof bundle.metadata === 'object' ? bundle.metadata : {};
|
|
45
44
|
const installation = metadata.runtime_installation && typeof metadata.runtime_installation === 'object'
|
|
46
45
|
? metadata.runtime_installation
|
|
47
46
|
: {};
|
|
47
|
+
const runtimeActivation = metadata.runtime_activation && typeof metadata.runtime_activation === 'object'
|
|
48
|
+
? metadata.runtime_activation
|
|
49
|
+
: {};
|
|
48
50
|
const serviceCatalog = metadata.service_catalog && typeof metadata.service_catalog === 'object'
|
|
49
51
|
? metadata.service_catalog
|
|
50
52
|
: {};
|
|
51
53
|
const releases = Array.isArray(serviceCatalog.releases) ? serviceCatalog.releases : [];
|
|
54
|
+
const installStatus = normalizeString(installation.status) || 'not-installed';
|
|
55
|
+
const installedReleaseId = installStatus === 'installed'
|
|
56
|
+
? (normalizeString(installation.release_id) || null)
|
|
57
|
+
: null;
|
|
58
|
+
const activeReleaseId = normalizeString(
|
|
59
|
+
bundle.runtime_release_id
|
|
60
|
+
|| runtimeRelease.release_id
|
|
61
|
+
|| runtimeActivation.active_release_id
|
|
62
|
+
) || null;
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
installation,
|
|
66
|
+
releases,
|
|
67
|
+
installStatus,
|
|
68
|
+
installedReleaseId,
|
|
69
|
+
activeReleaseId
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async function buildApplicationHome(graph = {}, dependencies = {}) {
|
|
74
|
+
const bundle = graph.bundle || {};
|
|
75
|
+
const runtimeRelease = graph.runtime_release || {};
|
|
76
|
+
const sceneBindings = Array.isArray(graph.scene_bindings) ? graph.scene_bindings : [];
|
|
77
|
+
const state = getRuntimeProjectionState(graph);
|
|
52
78
|
return {
|
|
53
79
|
mode: 'application-home',
|
|
54
80
|
query: {
|
|
@@ -60,8 +86,10 @@ async function buildApplicationHome(graph = {}, dependencies = {}) {
|
|
|
60
86
|
environment: bundle.environment || null,
|
|
61
87
|
release_status: runtimeRelease.release_status || null,
|
|
62
88
|
runtime_status: runtimeRelease.runtime_status || null,
|
|
63
|
-
install_status:
|
|
64
|
-
|
|
89
|
+
install_status: state.installStatus,
|
|
90
|
+
installed_release_id: state.installedReleaseId,
|
|
91
|
+
active_release_id: state.activeReleaseId,
|
|
92
|
+
release_count: state.releases.length
|
|
65
93
|
},
|
|
66
94
|
relations: {
|
|
67
95
|
runtime_release_id: bundle.runtime_release_id || null,
|
|
@@ -69,20 +97,22 @@ async function buildApplicationHome(graph = {}, dependencies = {}) {
|
|
|
69
97
|
engineering_project_id: bundle.engineering_project_id || null,
|
|
70
98
|
default_scene_id: bundle.default_scene_id || null
|
|
71
99
|
},
|
|
72
|
-
items: releases,
|
|
100
|
+
items: state.releases,
|
|
73
101
|
view_model: {
|
|
74
102
|
projection: 'application',
|
|
75
103
|
app_id: bundle.app_id || null,
|
|
76
104
|
app_key: bundle.app_key || null,
|
|
77
105
|
app_name: bundle.app_name || null,
|
|
78
106
|
entrypoint: runtimeRelease.entrypoint || null,
|
|
79
|
-
current_release:
|
|
80
|
-
|
|
81
|
-
|
|
107
|
+
current_release: state.activeReleaseId,
|
|
108
|
+
installed_release_id: state.installedReleaseId,
|
|
109
|
+
active_release_id: state.activeReleaseId,
|
|
110
|
+
current_environment: bundle.environment || state.installation.current_environment || null,
|
|
111
|
+
install_root: state.installation.install_root || null,
|
|
82
112
|
scene_binding_count: sceneBindings.length,
|
|
83
|
-
release_count: releases.length
|
|
113
|
+
release_count: state.releases.length
|
|
84
114
|
},
|
|
85
|
-
mb_status: runtimeRelease.runtime_status ||
|
|
115
|
+
mb_status: runtimeRelease.runtime_status || state.installStatus || bundle.status || 'unknown'
|
|
86
116
|
};
|
|
87
117
|
}
|
|
88
118
|
|
|
@@ -50,6 +50,8 @@ const ACTIVE_TEXT_SCAN_EXCLUDES = Object.freeze([
|
|
|
50
50
|
|
|
51
51
|
const LEGACY_REFERENCE_REGEX = /\.kiro(?:[\\/]|-workspaces\b)/;
|
|
52
52
|
const MULTI_AGENT_CONFIG_REFERENCE = '.sce/config/multi-agent.json';
|
|
53
|
+
const ERRORBOOK_REGISTRY_CONFIG_PATH = '.sce/config/errorbook-registry.json';
|
|
54
|
+
const ADOPTION_CONFIG_PATH = '.sce/adoption-config.json';
|
|
53
55
|
|
|
54
56
|
const REQUIRED_GITIGNORE_RULES = Object.freeze([
|
|
55
57
|
{ rule: '.sce/steering/CURRENT_CONTEXT.md', sample: '.sce/steering/CURRENT_CONTEXT.md' },
|
|
@@ -377,6 +379,159 @@ function validateMultiAgentConfig(payload) {
|
|
|
377
379
|
return violations;
|
|
378
380
|
}
|
|
379
381
|
|
|
382
|
+
function validateErrorbookRegistryConfig(payload) {
|
|
383
|
+
const violations = [];
|
|
384
|
+
if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
|
|
385
|
+
violations.push('errorbook registry config must be a JSON object');
|
|
386
|
+
return violations;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
if (typeof payload.enabled !== 'boolean') {
|
|
390
|
+
violations.push('errorbook registry config must declare boolean field "enabled"');
|
|
391
|
+
} else if (payload.enabled !== true) {
|
|
392
|
+
violations.push('errorbook registry config must keep "enabled" set to true under co-work baseline');
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
if (typeof payload.cache_file !== 'string' || !payload.cache_file.trim()) {
|
|
396
|
+
violations.push('errorbook registry config must declare non-empty field "cache_file"');
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
const sources = Array.isArray(payload.sources) ? payload.sources : [];
|
|
400
|
+
if (sources.length === 0) {
|
|
401
|
+
violations.push('errorbook registry config must declare at least one registry source');
|
|
402
|
+
return violations;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
const enabledSources = sources.filter((item) => {
|
|
406
|
+
if (!item || typeof item !== 'object' || Array.isArray(item)) {
|
|
407
|
+
return false;
|
|
408
|
+
}
|
|
409
|
+
const enabled = item.enabled !== false;
|
|
410
|
+
const url = typeof item.url === 'string' ? item.url.trim() : '';
|
|
411
|
+
return enabled && Boolean(url);
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
if (enabledSources.length === 0) {
|
|
415
|
+
violations.push('errorbook registry config must keep at least one enabled source with a non-empty "url"');
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
return violations;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
async function inspectErrorbookRegistry(projectRoot, options = {}, dependencies = {}) {
|
|
422
|
+
const fileSystem = dependencies.fileSystem || fs;
|
|
423
|
+
const configPath = path.join(projectRoot, '.sce', 'config', 'errorbook-registry.json');
|
|
424
|
+
const exists = await fileSystem.pathExists(configPath);
|
|
425
|
+
const report = {
|
|
426
|
+
file: ERRORBOOK_REGISTRY_CONFIG_PATH,
|
|
427
|
+
exists,
|
|
428
|
+
valid: false,
|
|
429
|
+
enabled: null,
|
|
430
|
+
enabled_source_count: 0,
|
|
431
|
+
warnings: [],
|
|
432
|
+
violations: [],
|
|
433
|
+
passed: true,
|
|
434
|
+
reason: 'passed'
|
|
435
|
+
};
|
|
436
|
+
|
|
437
|
+
if (!exists) {
|
|
438
|
+
report.passed = false;
|
|
439
|
+
report.reason = 'missing-config';
|
|
440
|
+
report.violations.push('shared errorbook registry config is missing');
|
|
441
|
+
return report;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
let payload;
|
|
445
|
+
try {
|
|
446
|
+
payload = await fileSystem.readJson(configPath);
|
|
447
|
+
} catch (error) {
|
|
448
|
+
report.passed = false;
|
|
449
|
+
report.reason = 'invalid-json';
|
|
450
|
+
report.violations.push(`invalid errorbook registry config: ${error.message}`);
|
|
451
|
+
return report;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
const validationErrors = validateErrorbookRegistryConfig(payload);
|
|
455
|
+
report.valid = validationErrors.length === 0;
|
|
456
|
+
report.enabled = typeof payload.enabled === 'boolean' ? payload.enabled : null;
|
|
457
|
+
report.enabled_source_count = Array.isArray(payload.sources)
|
|
458
|
+
? payload.sources.filter((item) => item && typeof item === 'object' && item.enabled !== false && typeof item.url === 'string' && item.url.trim()).length
|
|
459
|
+
: 0;
|
|
460
|
+
|
|
461
|
+
if (validationErrors.length > 0) {
|
|
462
|
+
report.passed = false;
|
|
463
|
+
report.reason = 'invalid-config';
|
|
464
|
+
report.violations.push(...validationErrors);
|
|
465
|
+
return report;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
return report;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
async function inspectErrorbookConvergence(projectRoot, options = {}, dependencies = {}) {
|
|
472
|
+
const fileSystem = dependencies.fileSystem || fs;
|
|
473
|
+
const configPath = path.join(projectRoot, '.sce', 'adoption-config.json');
|
|
474
|
+
const exists = await fileSystem.pathExists(configPath);
|
|
475
|
+
const report = {
|
|
476
|
+
file: ADOPTION_CONFIG_PATH,
|
|
477
|
+
exists,
|
|
478
|
+
managed_project: exists,
|
|
479
|
+
warnings: [],
|
|
480
|
+
violations: [],
|
|
481
|
+
passed: true,
|
|
482
|
+
reason: exists ? 'passed' : 'not-managed'
|
|
483
|
+
};
|
|
484
|
+
|
|
485
|
+
if (!exists) {
|
|
486
|
+
return report;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
let payload;
|
|
490
|
+
try {
|
|
491
|
+
payload = await fileSystem.readJson(configPath);
|
|
492
|
+
} catch (error) {
|
|
493
|
+
report.passed = false;
|
|
494
|
+
report.reason = 'invalid-json';
|
|
495
|
+
report.violations.push(`invalid adoption config: ${error.message}`);
|
|
496
|
+
return report;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
const convergence = payload
|
|
500
|
+
&& payload.defaults
|
|
501
|
+
&& payload.defaults.errorbook_convergence
|
|
502
|
+
&& typeof payload.defaults.errorbook_convergence === 'object'
|
|
503
|
+
&& !Array.isArray(payload.defaults.errorbook_convergence)
|
|
504
|
+
? payload.defaults.errorbook_convergence
|
|
505
|
+
: null;
|
|
506
|
+
|
|
507
|
+
if (!convergence) {
|
|
508
|
+
report.passed = false;
|
|
509
|
+
report.reason = 'missing-convergence';
|
|
510
|
+
report.violations.push('managed adoption baseline is missing defaults.errorbook_convergence');
|
|
511
|
+
return report;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
if (convergence.enabled !== true) {
|
|
515
|
+
report.violations.push('managed adoption baseline must keep errorbook_convergence.enabled=true');
|
|
516
|
+
}
|
|
517
|
+
if (convergence.canonical_mechanism !== 'errorbook') {
|
|
518
|
+
report.violations.push('managed adoption baseline must keep errorbook_convergence.canonical_mechanism=errorbook');
|
|
519
|
+
}
|
|
520
|
+
if (convergence.disallow_parallel_mechanisms !== true) {
|
|
521
|
+
report.violations.push('managed adoption baseline must keep errorbook_convergence.disallow_parallel_mechanisms=true');
|
|
522
|
+
}
|
|
523
|
+
if (convergence.strategy !== 'absorb_into_sce_errorbook') {
|
|
524
|
+
report.violations.push('managed adoption baseline must keep errorbook_convergence.strategy=absorb_into_sce_errorbook');
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
if (report.violations.length > 0) {
|
|
528
|
+
report.passed = false;
|
|
529
|
+
report.reason = 'convergence-drift';
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
return report;
|
|
533
|
+
}
|
|
534
|
+
|
|
380
535
|
async function inspectMultiAgentConfig(projectRoot, scanResult, options = {}, dependencies = {}) {
|
|
381
536
|
const fileSystem = dependencies.fileSystem || fs;
|
|
382
537
|
const configPath = path.join(projectRoot, '.sce', 'config', 'multi-agent.json');
|
|
@@ -497,6 +652,8 @@ async function auditCollabGovernance(projectRoot = process.cwd(), options = {},
|
|
|
497
652
|
const runtimeTracking = inspectRuntimeTracking(gitSnapshot);
|
|
498
653
|
const scanResult = await scanActiveTextReferences(projectRoot, gitSnapshot.tracked_files, options, dependencies);
|
|
499
654
|
const multiAgent = await inspectMultiAgentConfig(projectRoot, scanResult, options, dependencies);
|
|
655
|
+
const errorbookRegistry = await inspectErrorbookRegistry(projectRoot, options, dependencies);
|
|
656
|
+
const errorbookConvergence = await inspectErrorbookConvergence(projectRoot, options, dependencies);
|
|
500
657
|
const steeringBoundary = inspectSteeringBoundary(projectRoot);
|
|
501
658
|
|
|
502
659
|
const legacyReferences = {
|
|
@@ -521,6 +678,8 @@ async function auditCollabGovernance(projectRoot = process.cwd(), options = {},
|
|
|
521
678
|
gitignore,
|
|
522
679
|
runtime_tracking: runtimeTracking,
|
|
523
680
|
multi_agent: multiAgent,
|
|
681
|
+
errorbook_registry: errorbookRegistry,
|
|
682
|
+
errorbook_convergence: errorbookConvergence,
|
|
524
683
|
legacy_references: legacyReferences,
|
|
525
684
|
steering_boundary: steeringBoundary,
|
|
526
685
|
summary: {
|
|
@@ -528,6 +687,8 @@ async function auditCollabGovernance(projectRoot = process.cwd(), options = {},
|
|
|
528
687
|
tracked_runtime_files: runtimeTracking.tracked_runtime_files.length,
|
|
529
688
|
multi_agent_warnings: multiAgent.warnings.length,
|
|
530
689
|
multi_agent_violations: multiAgent.violations.length,
|
|
690
|
+
errorbook_registry_violations: errorbookRegistry.violations.length,
|
|
691
|
+
errorbook_convergence_violations: errorbookConvergence.violations.length,
|
|
531
692
|
legacy_reference_count: legacyReferences.matches.length,
|
|
532
693
|
steering_boundary_violations: steeringBoundary.violations.length
|
|
533
694
|
},
|
|
@@ -541,12 +702,16 @@ async function auditCollabGovernance(projectRoot = process.cwd(), options = {},
|
|
|
541
702
|
report.warnings.push(...(gitSnapshot.available === true ? gitSnapshot.warnings : []));
|
|
542
703
|
report.warnings.push(...runtimeTracking.warnings);
|
|
543
704
|
report.warnings.push(...multiAgent.warnings);
|
|
705
|
+
report.warnings.push(...errorbookRegistry.warnings);
|
|
706
|
+
report.warnings.push(...errorbookConvergence.warnings);
|
|
544
707
|
report.warnings.push(...legacyReferences.warnings);
|
|
545
708
|
report.warnings.push(...steeringBoundary.warnings);
|
|
546
709
|
|
|
547
710
|
report.violations.push(...gitignore.violations);
|
|
548
711
|
report.violations.push(...runtimeTracking.violations);
|
|
549
712
|
report.violations.push(...multiAgent.violations);
|
|
713
|
+
report.violations.push(...errorbookRegistry.violations);
|
|
714
|
+
report.violations.push(...errorbookConvergence.violations);
|
|
550
715
|
report.violations.push(...legacyReferences.violations);
|
|
551
716
|
report.violations.push(
|
|
552
717
|
...steeringBoundary.violations.map((item) => `steering boundary violation: ${item.path || item.name}`)
|
|
@@ -568,8 +733,11 @@ module.exports = {
|
|
|
568
733
|
RUNTIME_TRACKED_PATTERNS,
|
|
569
734
|
auditCollabGovernance,
|
|
570
735
|
inspectGitignore,
|
|
736
|
+
inspectErrorbookConvergence,
|
|
737
|
+
inspectErrorbookRegistry,
|
|
571
738
|
inspectMultiAgentConfig,
|
|
572
739
|
inspectRuntimeTracking,
|
|
573
740
|
scanActiveTextReferences,
|
|
741
|
+
validateErrorbookRegistryConfig,
|
|
574
742
|
validateMultiAgentConfig
|
|
575
743
|
};
|
|
@@ -48,6 +48,18 @@ const BACKEND_API_PRECEDENCE_CORE_PRINCIPLE_SECTION = [
|
|
|
48
48
|
'- 除非明确要求新建接口或修改后端接口,否则禁止为了迁就前端错误调用去随意改后端实现或契约。',
|
|
49
49
|
'- 默认优先修正前端请求、映射、类型和兼容处理,使其与后端接口保持一致;若怀疑后端契约错误,应先确认再改。'
|
|
50
50
|
].join('\n');
|
|
51
|
+
const DELIVERY_SYNC_CORE_PRINCIPLE_HEADING = '## 6. 测试、文档、代码必须同步闭环';
|
|
52
|
+
const DELIVERY_SYNC_REQUIRED_LINES = Object.freeze([
|
|
53
|
+
'- 代码变更必须跑相关验证;发布前不得忽略失败。',
|
|
54
|
+
'- 重要功能、命令、配置变化必须同步更新 README、用户文档或发布说明。',
|
|
55
|
+
'- 功能修改、UI 重写、模块替换时,已失效的旧实现、旧样式、死分支、失效适配层和无效引用必须在同一轮变更中清理,不得继续留作“保险”。',
|
|
56
|
+
'- 若因兼容、灰度或回滚必须暂时保留旧实现,必须明确保留理由、适用边界、退出条件和后续清理计划。'
|
|
57
|
+
]);
|
|
58
|
+
const DELIVERY_SYNC_CORE_PRINCIPLE_SECTION = [
|
|
59
|
+
DELIVERY_SYNC_CORE_PRINCIPLE_HEADING,
|
|
60
|
+
'',
|
|
61
|
+
...DELIVERY_SYNC_REQUIRED_LINES
|
|
62
|
+
].join('\n');
|
|
51
63
|
const LARGE_FILE_REFACTOR_CORE_PRINCIPLE_HEADING = '## 15. 单文件规模过大必须触发重构评估,禁止无限堆积';
|
|
52
64
|
const LARGE_FILE_REFACTOR_CORE_PRINCIPLE_SECTION = [
|
|
53
65
|
LARGE_FILE_REFACTOR_CORE_PRINCIPLE_HEADING,
|
|
@@ -59,6 +71,10 @@ const LARGE_FILE_REFACTOR_CORE_PRINCIPLE_SECTION = [
|
|
|
59
71
|
'- 行数阈值只是强触发信号,不代表低于阈值就可以忽略耦合、职责混杂、测试失控和理解成本问题;若复杂度已明显失控,应提前启动重构。'
|
|
60
72
|
].join('\n');
|
|
61
73
|
const REQUIRED_CORE_PRINCIPLE_SECTIONS = Object.freeze([
|
|
74
|
+
{
|
|
75
|
+
heading: DELIVERY_SYNC_CORE_PRINCIPLE_HEADING,
|
|
76
|
+
section: DELIVERY_SYNC_CORE_PRINCIPLE_SECTION
|
|
77
|
+
},
|
|
62
78
|
{
|
|
63
79
|
heading: CLARIFICATION_FIRST_CORE_PRINCIPLE_HEADING,
|
|
64
80
|
section: CLARIFICATION_FIRST_CORE_PRINCIPLE_SECTION
|
|
@@ -658,22 +674,54 @@ async function _reconcileSteeringContract(projectPath, options = {}) {
|
|
|
658
674
|
};
|
|
659
675
|
}
|
|
660
676
|
|
|
677
|
+
function _appendLinesToSection(content, heading, lines) {
|
|
678
|
+
if (!content || !heading || !Array.isArray(lines) || lines.length === 0) {
|
|
679
|
+
return content;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
const startIndex = content.indexOf(heading);
|
|
683
|
+
if (startIndex === -1) {
|
|
684
|
+
return content;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
const sectionBodyStart = startIndex + heading.length;
|
|
688
|
+
const nextHeadingIndex = content.indexOf('\n## ', sectionBodyStart);
|
|
689
|
+
const sectionEnd = nextHeadingIndex === -1 ? content.length : nextHeadingIndex;
|
|
690
|
+
const section = content.slice(startIndex, sectionEnd).trimEnd();
|
|
691
|
+
const missingLines = lines.filter((line) => !section.includes(line));
|
|
692
|
+
|
|
693
|
+
if (missingLines.length === 0) {
|
|
694
|
+
return content;
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
const updatedSection = `${section}\n${missingLines.join('\n')}`;
|
|
698
|
+
return `${content.slice(0, startIndex)}${updatedSection}${content.slice(sectionEnd)}`;
|
|
699
|
+
}
|
|
700
|
+
|
|
661
701
|
async function _reconcileCorePrinciplesBaseline(projectPath, options = {}) {
|
|
662
702
|
const { apply, fileSystem } = options;
|
|
663
703
|
const corePrinciplesPath = path.join(projectPath, SCE_STEERING_DIR, DEFAULT_LAYER_FILES.core_principles);
|
|
664
704
|
const exists = await fileSystem.pathExists(corePrinciplesPath);
|
|
665
705
|
const existingContent = exists ? await fileSystem.readFile(corePrinciplesPath, 'utf8') : '';
|
|
666
706
|
const missingSections = REQUIRED_CORE_PRINCIPLE_SECTIONS.filter(({ heading }) => !existingContent.includes(heading));
|
|
667
|
-
const
|
|
707
|
+
const missingDeliverySyncLines = existingContent.includes(DELIVERY_SYNC_CORE_PRINCIPLE_HEADING)
|
|
708
|
+
? DELIVERY_SYNC_REQUIRED_LINES.filter((line) => !existingContent.includes(line))
|
|
709
|
+
: [];
|
|
710
|
+
const changed = missingSections.length > 0 || missingDeliverySyncLines.length > 0;
|
|
668
711
|
|
|
669
712
|
if (apply && changed) {
|
|
670
|
-
|
|
713
|
+
let nextContent = `${existingContent || ''}`.trimEnd();
|
|
671
714
|
const appendedSections = missingSections.map((item) => item.section).join('\n\n');
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
715
|
+
if (appendedSections) {
|
|
716
|
+
nextContent = nextContent
|
|
717
|
+
? `${nextContent}\n\n${appendedSections}`
|
|
718
|
+
: appendedSections;
|
|
719
|
+
}
|
|
720
|
+
if (missingDeliverySyncLines.length > 0) {
|
|
721
|
+
nextContent = _appendLinesToSection(nextContent, DELIVERY_SYNC_CORE_PRINCIPLE_HEADING, missingDeliverySyncLines);
|
|
722
|
+
}
|
|
675
723
|
await fileSystem.ensureDir(path.dirname(corePrinciplesPath));
|
|
676
|
-
await fileSystem.writeFile(corePrinciplesPath, nextContent
|
|
724
|
+
await fileSystem.writeFile(corePrinciplesPath, `${nextContent}\n`, 'utf8');
|
|
677
725
|
}
|
|
678
726
|
|
|
679
727
|
return {
|
|
@@ -684,6 +732,7 @@ async function _reconcileCorePrinciplesBaseline(projectPath, options = {}) {
|
|
|
684
732
|
managed_by: 'takeover-baseline',
|
|
685
733
|
details: {
|
|
686
734
|
missing_required_headings_before: missingSections.map((item) => item.heading),
|
|
735
|
+
missing_delivery_sync_lines_before: missingDeliverySyncLines,
|
|
687
736
|
required_headings: REQUIRED_CORE_PRINCIPLE_SECTIONS.map((item) => item.heading)
|
|
688
737
|
}
|
|
689
738
|
};
|
|
@@ -923,6 +972,8 @@ module.exports = {
|
|
|
923
972
|
STEERING_CHANGE_EVALUATION_CORE_PRINCIPLE_SECTION,
|
|
924
973
|
BACKEND_API_PRECEDENCE_CORE_PRINCIPLE_HEADING,
|
|
925
974
|
BACKEND_API_PRECEDENCE_CORE_PRINCIPLE_SECTION,
|
|
975
|
+
DELIVERY_SYNC_CORE_PRINCIPLE_HEADING,
|
|
976
|
+
DELIVERY_SYNC_REQUIRED_LINES,
|
|
926
977
|
LARGE_FILE_REFACTOR_CORE_PRINCIPLE_HEADING,
|
|
927
978
|
LARGE_FILE_REFACTOR_CORE_PRINCIPLE_SECTION,
|
|
928
979
|
REQUIRED_CORE_PRINCIPLE_SECTIONS,
|
package/package.json
CHANGED
package/template/.sce/README.md
CHANGED
|
@@ -243,6 +243,6 @@ A Spec is a complete feature definition with three parts:
|
|
|
243
243
|
---
|
|
244
244
|
|
|
245
245
|
**Project Type**: Spec-driven development
|
|
246
|
-
**sce Version**: 3.6.
|
|
247
|
-
**Last Updated**: 2026-03-
|
|
246
|
+
**sce Version**: 3.6.52
|
|
247
|
+
**Last Updated**: 2026-03-16
|
|
248
248
|
**Purpose**: Guide AI tools to work effectively with this project
|