scene-capability-engine 3.6.51 → 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 CHANGED
@@ -7,6 +7,12 @@ 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
+
10
16
  ## [3.6.51] - 2026-03-15
11
17
 
12
18
  ### 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.51
222
- **Last Updated**: 2026-03-15
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.51
227
- **最后更新**:2026-03-15
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.51
6
- **Last Updated**: 2026-03-15
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, legacy `.kiro*` references, invalid multi-agent config, or steering boundary drift cannot pass through managed push flow
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
@@ -2,8 +2,8 @@
2
2
 
3
3
  > Enable multiple AI agents to work on the same sce project simultaneously without conflicts.
4
4
 
5
- **Version**: 3.6.51
6
- **Last Updated**: 2026-03-15
5
+ **Version**: 3.6.52
6
+ **Last Updated**: 2026-03-16
7
7
 
8
8
  ---
9
9
 
@@ -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,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 多个本地安装版本并存。
@@ -89,17 +89,77 @@ function buildBundleSummary(graph = {}) {
89
89
  };
90
90
  }
91
91
 
92
- function buildRuntimeSummary(graph = {}) {
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: installation.status || 'not-installed',
111
- install_root: installation.install_root || null,
112
- release_count: releases.length,
113
- active_release_id: installation.release_id || bundle.runtime_release_id || runtimeRelease.release_id || null
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 metadata = graph.bundle && graph.bundle.metadata && typeof graph.bundle.metadata === 'object' ? graph.bundle.metadata : {};
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: metadata.runtime_installation || null,
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: Array.isArray(serviceCatalog.releases) ? serviceCatalog.releases.length : 0,
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 metadata = graph.bundle && graph.bundle.metadata && typeof graph.bundle.metadata === 'object' ? graph.bundle.metadata : {};
596
- const serviceCatalog = metadata.service_catalog && typeof metadata.service_catalog === 'object' ? metadata.service_catalog : {};
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,
@@ -37,18 +37,44 @@ function isFreshProjectionCache(cacheRecord, ttlSeconds) {
37
37
  return (Date.now() - generatedAt) <= maxAgeMs;
38
38
  }
39
39
 
40
- async function buildApplicationHome(graph = {}, dependencies = {}) {
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: installation.status || 'not-installed',
64
- release_count: releases.length
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: installation.release_id || runtimeRelease.release_id || null,
80
- current_environment: bundle.environment || installation.current_environment || null,
81
- install_root: installation.install_root || null,
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 || installation.status || bundle.status || 'unknown'
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
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scene-capability-engine",
3
- "version": "3.6.51",
3
+ "version": "3.6.52",
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": {
@@ -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.51
247
- **Last Updated**: 2026-03-15
246
+ **sce Version**: 3.6.52
247
+ **Last Updated**: 2026-03-16
248
248
  **Purpose**: Guide AI tools to work effectively with this project