scene-capability-engine 3.6.25 → 3.6.27
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 +14 -1
- package/README.md +1 -1
- package/README.zh.md +1 -1
- package/docs/agent-runtime/capability-iteration-ui.schema.json +72 -2
- package/docs/command-reference.md +2 -1
- package/docs/magicball-capability-iteration-api.md +2 -0
- package/docs/magicball-capability-iteration-ui.md +13 -0
- package/docs/magicball-task-feedback-timeline-guide.md +123 -0
- package/lib/commands/capability.js +108 -3
- package/lib/commands/studio.js +94 -3
- package/lib/commands/timeline.js +84 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [3.6.27] - 2026-03-06
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- Studio task payloads now expose `task.feedback_model` for human-facing task cards.
|
|
14
|
+
- Timeline list/show payloads now expose `view_model` for Magicball timeline panels.
|
|
15
|
+
- Added `docs/magicball-task-feedback-timeline-guide.md`.
|
|
16
|
+
|
|
17
|
+
## [3.6.26] - 2026-03-06
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
- Capability inventory now exposes scene-level advice fields, homepage summary recommendations, and quick filters for Magicball dashboards.
|
|
21
|
+
- Capability iteration schema and Magicball docs now define the homepage recommendation contract.
|
|
22
|
+
|
|
10
23
|
## [3.6.25] - 2026-03-06
|
|
11
24
|
|
|
12
25
|
### Added
|
|
@@ -16,7 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
16
29
|
## [3.6.24] - 2026-03-06
|
|
17
30
|
|
|
18
31
|
### Added
|
|
19
|
-
- Capability inventory payload now exposes fixed homepage query metadata (`query`), summary stats (`summary_stats`), and sorting metadata (`sort`).
|
|
32
|
+
- Capability inventory payload now exposes fixed homepage query metadata (`query`), summary stats (`summary_stats`), summary recommendations, quick filters, and sorting metadata (`sort`).
|
|
20
33
|
- Capability iteration schema and Magicball docs now define the fixed homepage inventory protocol.
|
|
21
34
|
|
|
22
35
|
## [3.6.23] - 2026-03-06
|
package/README.md
CHANGED
package/README.zh.md
CHANGED
|
@@ -668,7 +668,9 @@
|
|
|
668
668
|
"scene_count",
|
|
669
669
|
"sort",
|
|
670
670
|
"scenes",
|
|
671
|
-
"summary_stats"
|
|
671
|
+
"summary_stats",
|
|
672
|
+
"summary_recommendations",
|
|
673
|
+
"quick_filters"
|
|
672
674
|
],
|
|
673
675
|
"properties": {
|
|
674
676
|
"mode": {
|
|
@@ -769,7 +771,12 @@
|
|
|
769
771
|
"ontology_core_ui",
|
|
770
772
|
"release_readiness",
|
|
771
773
|
"release_readiness_ui",
|
|
772
|
-
"score_preview"
|
|
774
|
+
"score_preview",
|
|
775
|
+
"attention_level",
|
|
776
|
+
"recommended_action",
|
|
777
|
+
"blocking_summary",
|
|
778
|
+
"next_action",
|
|
779
|
+
"next_command"
|
|
773
780
|
],
|
|
774
781
|
"properties": {
|
|
775
782
|
"scene_id": {
|
|
@@ -798,6 +805,21 @@
|
|
|
798
805
|
},
|
|
799
806
|
"score_preview": {
|
|
800
807
|
"type": "object"
|
|
808
|
+
},
|
|
809
|
+
"attention_level": {
|
|
810
|
+
"type": "string"
|
|
811
|
+
},
|
|
812
|
+
"recommended_action": {
|
|
813
|
+
"type": "string"
|
|
814
|
+
},
|
|
815
|
+
"blocking_summary": {
|
|
816
|
+
"type": "string"
|
|
817
|
+
},
|
|
818
|
+
"next_action": {
|
|
819
|
+
"type": "string"
|
|
820
|
+
},
|
|
821
|
+
"next_command": {
|
|
822
|
+
"type": "string"
|
|
801
823
|
}
|
|
802
824
|
},
|
|
803
825
|
"additionalProperties": false
|
|
@@ -844,6 +866,54 @@
|
|
|
844
866
|
}
|
|
845
867
|
},
|
|
846
868
|
"additionalProperties": false
|
|
869
|
+
},
|
|
870
|
+
"summary_recommendations": {
|
|
871
|
+
"type": "array",
|
|
872
|
+
"items": {
|
|
873
|
+
"type": "string"
|
|
874
|
+
}
|
|
875
|
+
},
|
|
876
|
+
"quick_filters": {
|
|
877
|
+
"type": "array",
|
|
878
|
+
"items": {
|
|
879
|
+
"type": "object",
|
|
880
|
+
"required": [
|
|
881
|
+
"id",
|
|
882
|
+
"label",
|
|
883
|
+
"query"
|
|
884
|
+
],
|
|
885
|
+
"properties": {
|
|
886
|
+
"id": {
|
|
887
|
+
"type": "string"
|
|
888
|
+
},
|
|
889
|
+
"label": {
|
|
890
|
+
"type": "string"
|
|
891
|
+
},
|
|
892
|
+
"query": {
|
|
893
|
+
"type": "object",
|
|
894
|
+
"required": [
|
|
895
|
+
"release_ready",
|
|
896
|
+
"missing_triad"
|
|
897
|
+
],
|
|
898
|
+
"properties": {
|
|
899
|
+
"release_ready": {
|
|
900
|
+
"type": [
|
|
901
|
+
"boolean",
|
|
902
|
+
"null"
|
|
903
|
+
]
|
|
904
|
+
},
|
|
905
|
+
"missing_triad": {
|
|
906
|
+
"type": [
|
|
907
|
+
"string",
|
|
908
|
+
"null"
|
|
909
|
+
]
|
|
910
|
+
}
|
|
911
|
+
},
|
|
912
|
+
"additionalProperties": false
|
|
913
|
+
}
|
|
914
|
+
},
|
|
915
|
+
"additionalProperties": false
|
|
916
|
+
}
|
|
847
917
|
}
|
|
848
918
|
},
|
|
849
919
|
"additionalProperties": false
|
|
@@ -627,6 +627,7 @@ Studio JSON output now includes a stable UI-oriented task stream contract (in ad
|
|
|
627
627
|
- `task.commands[]`: `cmd`, `exit_code`, `stdout`, `stderr`, `log_path`
|
|
628
628
|
- `task.errors[]`: `message`, `error_bundle` (copy-ready diagnostic bundle)
|
|
629
629
|
- `task.evidence[]`: structured evidence references
|
|
630
|
+
- `task.feedback_model`: human-facing task feedback (`problem`, `execution`, `diagnosis`, `evidence`, `next_step`)
|
|
630
631
|
- `event[]`: raw audit event stream (`studio events` also keeps legacy `events[]` for compatibility)
|
|
631
632
|
- `studio events --openhands-events <path>` switches `source_stream=openhands` and maps OpenHands raw events to the same task contract fields.
|
|
632
633
|
- hierarchical task reference lookup/rerun:
|
|
@@ -1875,7 +1876,7 @@ sce capability inventory --json
|
|
|
1875
1876
|
sce capability inventory --release-ready false --missing-triad decision_strategy --json
|
|
1876
1877
|
```
|
|
1877
1878
|
|
|
1878
|
-
`capability inventory` returns fixed homepage query metadata in `query`, summary cards in `summary_stats`, and sorting metadata in `sort`.
|
|
1879
|
+
`capability inventory` returns fixed homepage query metadata in `query`, summary cards in `summary_stats`, top recommendations in `summary_recommendations`, quick filters in `quick_filters`, and sorting metadata in `sort`.
|
|
1879
1880
|
|
|
1880
1881
|
|
|
1881
1882
|
Capability candidates are now evaluated against the ontology core triad by default:
|
|
@@ -188,5 +188,7 @@ sce capability register --input <template_file> --risk-level <level> --difficult
|
|
|
188
188
|
- `query.filters.missing_triad`:triad 缺口过滤
|
|
189
189
|
- `summary_stats.publish_ready_count` / `summary_stats.blocked_count`:顶部统计卡
|
|
190
190
|
- `summary_stats.missing_triads.*`:triad 缺口计数卡
|
|
191
|
+
- `summary_recommendations[]`:首页总览建议
|
|
192
|
+
- `quick_filters[]`:首页快捷筛选配置
|
|
191
193
|
- `sort.strategy`:默认排序策略说明
|
|
192
194
|
- `sort.triad_priority`:triad 优先级数组
|
|
@@ -214,3 +214,16 @@ sce capability register --input <template.json> --json
|
|
|
214
214
|
- `summary_stats.missing_triads.decision_strategy`:缺决策策略数量
|
|
215
215
|
- `summary_stats.missing_triads.business_rules`:缺业务规则数量
|
|
216
216
|
- `summary_stats.missing_triads.entity_relation`:缺实体关系数量
|
|
217
|
+
|
|
218
|
+
## 13. Scene 卡片建议字段
|
|
219
|
+
|
|
220
|
+
- `attention_level`:critical/high/medium/low
|
|
221
|
+
- `recommended_action`:卡片主建议
|
|
222
|
+
- `blocking_summary`:一行摘要
|
|
223
|
+
- `next_action`:前端动作 key
|
|
224
|
+
- `next_command`:默认 CLI 建议
|
|
225
|
+
|
|
226
|
+
## 14. 首页总览建议字段
|
|
227
|
+
|
|
228
|
+
- `summary_recommendations[]`:顶部全局建议
|
|
229
|
+
- `quick_filters[]`:推荐快捷筛选
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# Magicball Task Feedback + Timeline Integration Guide
|
|
2
|
+
|
|
3
|
+
> 目标:让 Magicball 在不直接消费底层事件流/快照原始结构的情况下,使用 SCE 的稳定任务反馈模型与时间线视图模型。
|
|
4
|
+
|
|
5
|
+
## 1. 任务反馈模型(来源:`sce studio events --json`)
|
|
6
|
+
|
|
7
|
+
SCE 现在在 `task` 下增加:
|
|
8
|
+
- `feedback_model.version`
|
|
9
|
+
- `feedback_model.problem`
|
|
10
|
+
- `feedback_model.execution`
|
|
11
|
+
- `feedback_model.diagnosis`
|
|
12
|
+
- `feedback_model.evidence`
|
|
13
|
+
- `feedback_model.next_step`
|
|
14
|
+
|
|
15
|
+
### 1.1 字段说明
|
|
16
|
+
|
|
17
|
+
- `problem.component`:当前问题所属组件/scene
|
|
18
|
+
- `problem.action`:当前动作或阶段
|
|
19
|
+
- `problem.expected`:期望结果
|
|
20
|
+
- `problem.actual`:实际结果
|
|
21
|
+
|
|
22
|
+
- `execution.stage`:当前阶段(plan/generate/apply/verify/release/rollback/events)
|
|
23
|
+
- `execution.status`:当前状态
|
|
24
|
+
- `execution.summary[]`:3 行以内摘要
|
|
25
|
+
- `execution.blocking_summary`:阻断摘要
|
|
26
|
+
|
|
27
|
+
- `diagnosis.hypothesis`:当前根因假设/错误摘要
|
|
28
|
+
- `diagnosis.chain_checkpoint`:定位链路检查点
|
|
29
|
+
- `diagnosis.root_cause_confidence`:根因判断置信度(low/medium/high)
|
|
30
|
+
|
|
31
|
+
- `evidence.file_count` / `evidence.file_paths[]`
|
|
32
|
+
- `evidence.command_count` / `evidence.error_count`
|
|
33
|
+
- `evidence.verification_result`
|
|
34
|
+
- `evidence.regression_scope[]`
|
|
35
|
+
|
|
36
|
+
- `next_step.recommended_action`:面向人的下一步建议
|
|
37
|
+
- `next_step.next_action`:动作 key
|
|
38
|
+
- `next_step.next_command`:推荐命令
|
|
39
|
+
|
|
40
|
+
### 1.2 Magicball UI 建议
|
|
41
|
+
|
|
42
|
+
任务卡默认显示:
|
|
43
|
+
1. `problem.expected / actual`
|
|
44
|
+
2. `execution.summary`
|
|
45
|
+
3. `execution.blocking_summary`
|
|
46
|
+
4. `next_step.recommended_action`
|
|
47
|
+
5. `evidence.file_paths`(最多前 3-5 个)
|
|
48
|
+
|
|
49
|
+
事件流 `event[]` 保留为“展开查看”,不再作为主视图。
|
|
50
|
+
|
|
51
|
+
## 2. 时间线视图模型(来源:`sce timeline list/show --json`)
|
|
52
|
+
|
|
53
|
+
SCE 现在在时间线命令中增加:
|
|
54
|
+
- `view_model.summary`
|
|
55
|
+
- `view_model.entries[]`(list)
|
|
56
|
+
- `view_model.snapshot`(show)
|
|
57
|
+
- `view_model.files_preview[]`(show)
|
|
58
|
+
|
|
59
|
+
### 2.1 timeline list
|
|
60
|
+
|
|
61
|
+
关键字段:
|
|
62
|
+
- `view_model.summary.total`
|
|
63
|
+
- `view_model.summary.latest_snapshot_id`
|
|
64
|
+
- `view_model.summary.latest_created_at`
|
|
65
|
+
- `view_model.summary.dirty_snapshot_count`
|
|
66
|
+
- `view_model.summary.scene_count`
|
|
67
|
+
- `view_model.summary.trigger_counts`
|
|
68
|
+
- `view_model.entries[]`
|
|
69
|
+
|
|
70
|
+
每个 entry:
|
|
71
|
+
- `snapshot_id`
|
|
72
|
+
- `title`
|
|
73
|
+
- `subtitle`
|
|
74
|
+
- `created_at`
|
|
75
|
+
- `scene_id`
|
|
76
|
+
- `file_count`
|
|
77
|
+
- `attention_level`
|
|
78
|
+
- `show_command`
|
|
79
|
+
- `restore_command`
|
|
80
|
+
|
|
81
|
+
### 2.2 timeline show
|
|
82
|
+
|
|
83
|
+
关键字段:
|
|
84
|
+
- `view_model.snapshot`
|
|
85
|
+
- `view_model.files_preview[]`
|
|
86
|
+
- `view_model.file_total`
|
|
87
|
+
- `view_model.restore_command`
|
|
88
|
+
|
|
89
|
+
### 2.3 Magicball UI 建议
|
|
90
|
+
|
|
91
|
+
时间线面板建议两层:
|
|
92
|
+
- 列表层:使用 `view_model.entries[]` 渲染时间线卡片
|
|
93
|
+
- 详情层:使用 `view_model.snapshot + files_preview` 渲染快照详情
|
|
94
|
+
|
|
95
|
+
默认展示:
|
|
96
|
+
- 快照标题
|
|
97
|
+
- 创建时间
|
|
98
|
+
- 关联 scene
|
|
99
|
+
- 文件数
|
|
100
|
+
- attention level
|
|
101
|
+
- “查看详情 / 恢复” 按钮
|
|
102
|
+
|
|
103
|
+
## 3. 推荐对接顺序
|
|
104
|
+
|
|
105
|
+
1. 任务面板先接 `task.feedback_model`
|
|
106
|
+
2. 再把 `event[]` 放到“高级模式”
|
|
107
|
+
3. 时间线首页接 `timeline list.view_model`
|
|
108
|
+
4. 时间线详情页接 `timeline show.view_model`
|
|
109
|
+
|
|
110
|
+
## 4. 最小接口清单
|
|
111
|
+
|
|
112
|
+
- `sce studio events --job <job-id> --json`
|
|
113
|
+
- `sce studio events --job <job-id> --openhands-events <path> --json`
|
|
114
|
+
- `sce timeline list --limit 20 --json`
|
|
115
|
+
- `sce timeline show <snapshot-id> --json`
|
|
116
|
+
|
|
117
|
+
## 5. 设计原则
|
|
118
|
+
|
|
119
|
+
- 主视图优先展示“人可判断信息”,不是原始事件流
|
|
120
|
+
- 事件流保留为审计层,不作为第一视图
|
|
121
|
+
- 时间线优先展示“可恢复、可比较、可追踪”的节点信息
|
|
122
|
+
- 所有字段都以 SCE 输出为准,Magicball 不自行推断
|
|
123
|
+
|
|
@@ -836,6 +836,60 @@ function resolveCapabilityTriadPriority(entry) {
|
|
|
836
836
|
return 3;
|
|
837
837
|
}
|
|
838
838
|
|
|
839
|
+
function buildCapabilityInventorySceneAdvice(entry) {
|
|
840
|
+
const sceneId = String(entry && entry.scene_id || 'scene.unknown');
|
|
841
|
+
const releaseUi = entry && entry.release_readiness_ui ? entry.release_readiness_ui : { publish_ready: true, blocking_missing: [] };
|
|
842
|
+
const missing = Array.isArray(releaseUi.blocking_missing) ? releaseUi.blocking_missing : [];
|
|
843
|
+
const valueScore = Number(entry && entry.score_preview && entry.score_preview.value_score || 0);
|
|
844
|
+
|
|
845
|
+
let attentionLevel = 'low';
|
|
846
|
+
let recommendedAction = '可直接发布';
|
|
847
|
+
let blockingSummary = '已满足发布前置条件';
|
|
848
|
+
let nextAction = 'publish';
|
|
849
|
+
|
|
850
|
+
if (!releaseUi.publish_ready) {
|
|
851
|
+
if (missing.includes('decision_strategy')) {
|
|
852
|
+
attentionLevel = 'critical';
|
|
853
|
+
recommendedAction = '补齐决策策略';
|
|
854
|
+
blockingSummary = '缺决策策略,暂不可发布';
|
|
855
|
+
nextAction = 'fill_decision_strategy';
|
|
856
|
+
} else if (missing.includes('business_rules')) {
|
|
857
|
+
attentionLevel = 'high';
|
|
858
|
+
recommendedAction = '补齐业务规则';
|
|
859
|
+
blockingSummary = '缺业务规则,暂不可发布';
|
|
860
|
+
nextAction = 'fill_business_rules';
|
|
861
|
+
} else if (missing.includes('entity_relation')) {
|
|
862
|
+
attentionLevel = 'medium';
|
|
863
|
+
recommendedAction = '补齐实体关系';
|
|
864
|
+
blockingSummary = '缺实体关系,暂不可发布';
|
|
865
|
+
nextAction = 'fill_entity_relation';
|
|
866
|
+
} else {
|
|
867
|
+
attentionLevel = 'medium';
|
|
868
|
+
recommendedAction = '补齐本体能力';
|
|
869
|
+
blockingSummary = '本体能力不完整,暂不可发布';
|
|
870
|
+
nextAction = 'repair_ontology_core';
|
|
871
|
+
}
|
|
872
|
+
} else if (valueScore >= 70) {
|
|
873
|
+
attentionLevel = 'low';
|
|
874
|
+
recommendedAction = '进入模板构建';
|
|
875
|
+
blockingSummary = '能力成熟度较高,可进入模板构建/发布';
|
|
876
|
+
nextAction = 'build_template';
|
|
877
|
+
} else {
|
|
878
|
+
attentionLevel = 'medium';
|
|
879
|
+
recommendedAction = '继续补充任务证据';
|
|
880
|
+
blockingSummary = '已可发布,但建议先补强任务与验证证据';
|
|
881
|
+
nextAction = 'strengthen_evidence';
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
return {
|
|
885
|
+
attention_level: attentionLevel,
|
|
886
|
+
recommended_action: recommendedAction,
|
|
887
|
+
blocking_summary: blockingSummary,
|
|
888
|
+
next_action: nextAction,
|
|
889
|
+
next_command: 'sce capability extract --scene ' + sceneId + ' --json'
|
|
890
|
+
};
|
|
891
|
+
}
|
|
892
|
+
|
|
839
893
|
function buildCapabilityInventorySummaryStats(entries) {
|
|
840
894
|
const items = Array.isArray(entries) ? entries : [];
|
|
841
895
|
const summary = {
|
|
@@ -869,6 +923,47 @@ function buildCapabilityInventorySummaryStats(entries) {
|
|
|
869
923
|
return summary;
|
|
870
924
|
}
|
|
871
925
|
|
|
926
|
+
function buildCapabilityInventorySummaryRecommendations(entries) {
|
|
927
|
+
const items = Array.isArray(entries) ? entries : [];
|
|
928
|
+
const recommendations = [];
|
|
929
|
+
const blocked = items.filter((item) => !(item && item.release_readiness_ui && item.release_readiness_ui.publish_ready));
|
|
930
|
+
const missingDecision = blocked.filter((item) => Array.isArray(item.release_readiness_ui && item.release_readiness_ui.blocking_missing) && item.release_readiness_ui.blocking_missing.includes('decision_strategy'));
|
|
931
|
+
const missingRules = blocked.filter((item) => Array.isArray(item.release_readiness_ui && item.release_readiness_ui.blocking_missing) && item.release_readiness_ui.blocking_missing.includes('business_rules'));
|
|
932
|
+
const readyScenes = items.filter((item) => item && item.release_readiness_ui && item.release_readiness_ui.publish_ready);
|
|
933
|
+
|
|
934
|
+
if (missingDecision.length > 0) {
|
|
935
|
+
recommendations.push('优先处理缺决策策略的 scene(' + missingDecision.length + ')');
|
|
936
|
+
}
|
|
937
|
+
if (missingRules.length > 0) {
|
|
938
|
+
recommendations.push('其次处理缺业务规则的 scene(' + missingRules.length + ')');
|
|
939
|
+
}
|
|
940
|
+
if (readyScenes.length > 0) {
|
|
941
|
+
recommendations.push('可优先推进可发布 scene 进入模板构建(' + readyScenes.length + ')');
|
|
942
|
+
}
|
|
943
|
+
if (blocked.length === 0 && readyScenes.length === 0 && items.length > 0) {
|
|
944
|
+
recommendations.push('当前 scene 已基本稳定,可继续补强验证证据');
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
return recommendations;
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
function buildCapabilityInventoryQuickFilters(summaryStats) {
|
|
951
|
+
const stats = summaryStats || { blocked_count: 0, missing_triads: {} };
|
|
952
|
+
const filters = [];
|
|
953
|
+
if (Number(stats.blocked_count || 0) > 0) {
|
|
954
|
+
filters.push({ id: 'blocked', label: '不可发布', query: { release_ready: false, missing_triad: null } });
|
|
955
|
+
}
|
|
956
|
+
for (const triad of ['decision_strategy', 'business_rules', 'entity_relation']) {
|
|
957
|
+
if (Number(stats.missing_triads && stats.missing_triads[triad] || 0) > 0) {
|
|
958
|
+
filters.push({ id: 'missing_' + triad, label: '缺' + triad, query: { release_ready: false, missing_triad: triad } });
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
if (Number(stats.publish_ready_count || 0) > 0) {
|
|
962
|
+
filters.push({ id: 'ready', label: '可发布', query: { release_ready: true, missing_triad: null } });
|
|
963
|
+
}
|
|
964
|
+
return filters;
|
|
965
|
+
}
|
|
966
|
+
|
|
872
967
|
function sortCapabilityInventoryEntries(entries) {
|
|
873
968
|
return [...(Array.isArray(entries) ? entries : [])].sort((left, right) => {
|
|
874
969
|
const leftReady = Boolean(left && left.release_readiness_ui && left.release_readiness_ui.publish_ready);
|
|
@@ -933,7 +1028,7 @@ async function runCapabilityInventoryCommand(options = {}, dependencies = {}) {
|
|
|
933
1028
|
ontology_scope: candidate.ontology_scope,
|
|
934
1029
|
ontology_core: candidate.ontology_core
|
|
935
1030
|
});
|
|
936
|
-
|
|
1031
|
+
const sceneEntry = {
|
|
937
1032
|
scene_id: sceneId,
|
|
938
1033
|
summary: candidate.summary,
|
|
939
1034
|
source: candidate.source,
|
|
@@ -943,10 +1038,15 @@ async function runCapabilityInventoryCommand(options = {}, dependencies = {}) {
|
|
|
943
1038
|
release_readiness: releaseReadiness,
|
|
944
1039
|
release_readiness_ui: buildCapabilityReleaseReadinessUi(releaseReadiness),
|
|
945
1040
|
score_preview: score
|
|
1041
|
+
};
|
|
1042
|
+
scenes.push({
|
|
1043
|
+
...sceneEntry,
|
|
1044
|
+
...buildCapabilityInventorySceneAdvice(sceneEntry)
|
|
946
1045
|
});
|
|
947
1046
|
}
|
|
948
1047
|
|
|
949
1048
|
const filteredScenes = sortCapabilityInventoryEntries(filterCapabilityInventoryEntries(scenes, options));
|
|
1049
|
+
const summaryStats = buildCapabilityInventorySummaryStats(filteredScenes);
|
|
950
1050
|
const releaseReadyFilterRaw = normalizeText(options.releaseReady || options.release_ready).toLowerCase();
|
|
951
1051
|
const payload = {
|
|
952
1052
|
mode: 'capability-inventory',
|
|
@@ -963,7 +1063,9 @@ async function runCapabilityInventoryCommand(options = {}, dependencies = {}) {
|
|
|
963
1063
|
},
|
|
964
1064
|
scene_total: scenes.length,
|
|
965
1065
|
scene_count: filteredScenes.length,
|
|
966
|
-
summary_stats:
|
|
1066
|
+
summary_stats: summaryStats,
|
|
1067
|
+
summary_recommendations: buildCapabilityInventorySummaryRecommendations(filteredScenes),
|
|
1068
|
+
quick_filters: buildCapabilityInventoryQuickFilters(summaryStats),
|
|
967
1069
|
sort: {
|
|
968
1070
|
strategy: 'publish_ready -> missing_triad_priority -> value_score_desc -> scene_id',
|
|
969
1071
|
triad_priority: ['decision_strategy', 'business_rules', 'entity_relation']
|
|
@@ -1752,5 +1854,8 @@ module.exports = {
|
|
|
1752
1854
|
filterCapabilityCatalogEntries,
|
|
1753
1855
|
filterCapabilityInventoryEntries,
|
|
1754
1856
|
sortCapabilityInventoryEntries,
|
|
1755
|
-
|
|
1857
|
+
buildCapabilityInventorySceneAdvice,
|
|
1858
|
+
buildCapabilityInventorySummaryStats,
|
|
1859
|
+
buildCapabilityInventorySummaryRecommendations,
|
|
1860
|
+
buildCapabilityInventoryQuickFilters
|
|
1756
1861
|
};
|
package/lib/commands/studio.js
CHANGED
|
@@ -1460,6 +1460,95 @@ function buildTaskAcceptanceCriteria(stageName = '', job = {}, nextAction = '')
|
|
|
1460
1460
|
];
|
|
1461
1461
|
}
|
|
1462
1462
|
|
|
1463
|
+
function buildTaskFeedbackModel(payload = {}) {
|
|
1464
|
+
const task = payload && payload.task && typeof payload.task === 'object' ? payload.task : {};
|
|
1465
|
+
const handoff = task && typeof task.handoff === 'object' ? task.handoff : {};
|
|
1466
|
+
const errors = Array.isArray(task.errors) ? task.errors : [];
|
|
1467
|
+
const commands = Array.isArray(task.commands) ? task.commands : [];
|
|
1468
|
+
const fileChanges = Array.isArray(task.file_changes) ? task.file_changes : [];
|
|
1469
|
+
const evidence = Array.isArray(task.evidence) ? task.evidence : [];
|
|
1470
|
+
const acceptance = Array.isArray(task.acceptance_criteria) ? task.acceptance_criteria : [];
|
|
1471
|
+
const firstError = errors[0] || {};
|
|
1472
|
+
const stage = normalizeString(handoff.stage) || 'task';
|
|
1473
|
+
const status = normalizeString(task.status) || 'unknown';
|
|
1474
|
+
const problemComponent = normalizeString(handoff.component) || normalizeString(payload.sceneId) || null;
|
|
1475
|
+
const expected = normalizeString(acceptance[0]) || ('Complete ' + stage + ' stage successfully');
|
|
1476
|
+
const actual = normalizeString(firstError.message) || ('Current status: ' + status);
|
|
1477
|
+
|
|
1478
|
+
let chainCheckpoint = 'task-envelope';
|
|
1479
|
+
if (errors.length > 0 && commands.length > 0) {
|
|
1480
|
+
chainCheckpoint = 'command-execution';
|
|
1481
|
+
} else if (errors.length > 0) {
|
|
1482
|
+
chainCheckpoint = 'stage-gate';
|
|
1483
|
+
} else if (fileChanges.length > 0) {
|
|
1484
|
+
chainCheckpoint = 'patch-applied';
|
|
1485
|
+
} else if (evidence.length > 0) {
|
|
1486
|
+
chainCheckpoint = 'evidence-collected';
|
|
1487
|
+
}
|
|
1488
|
+
|
|
1489
|
+
let confidence = 'low';
|
|
1490
|
+
if (errors.length > 0) {
|
|
1491
|
+
confidence = 'medium';
|
|
1492
|
+
} else if (status === 'completed') {
|
|
1493
|
+
confidence = 'high';
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
let recommendedAction = '继续当前阶段';
|
|
1497
|
+
if (errors.length > 0) {
|
|
1498
|
+
recommendedAction = '处理阻断后重试';
|
|
1499
|
+
} else if (status === 'completed' && normalizeString(task.next_action) && normalizeString(task.next_action) !== 'complete') {
|
|
1500
|
+
recommendedAction = '执行下一阶段';
|
|
1501
|
+
} else if (status === 'completed') {
|
|
1502
|
+
recommendedAction = '任务完成';
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1505
|
+
return {
|
|
1506
|
+
version: '1.0',
|
|
1507
|
+
problem: {
|
|
1508
|
+
component: problemComponent,
|
|
1509
|
+
action: normalizeString(handoff.action) || stage,
|
|
1510
|
+
expected,
|
|
1511
|
+
actual
|
|
1512
|
+
},
|
|
1513
|
+
execution: {
|
|
1514
|
+
stage,
|
|
1515
|
+
status,
|
|
1516
|
+
summary: Array.isArray(task.summary) ? task.summary.slice(0, 3) : [],
|
|
1517
|
+
blocking_summary: normalizeString(handoff.blocking_summary) || normalizeString(firstError.message) || null
|
|
1518
|
+
},
|
|
1519
|
+
diagnosis: {
|
|
1520
|
+
hypothesis: normalizeString(firstError.error_bundle) || normalizeString(firstError.message) || normalizeString(handoff.reason) || null,
|
|
1521
|
+
chain_checkpoint: chainCheckpoint,
|
|
1522
|
+
root_cause_confidence: confidence
|
|
1523
|
+
},
|
|
1524
|
+
evidence: {
|
|
1525
|
+
file_count: fileChanges.length,
|
|
1526
|
+
file_paths: fileChanges.slice(0, 5).map((item) => normalizeString(item && item.path)).filter(Boolean),
|
|
1527
|
+
command_count: commands.length,
|
|
1528
|
+
error_count: errors.length,
|
|
1529
|
+
verification_result: status === 'completed' ? 'passed-or-advanced' : (errors.length > 0 ? 'blocked' : 'in-progress'),
|
|
1530
|
+
regression_scope: Array.isArray(handoff.regression_scope) ? handoff.regression_scope : []
|
|
1531
|
+
},
|
|
1532
|
+
next_step: {
|
|
1533
|
+
recommended_action: recommendedAction,
|
|
1534
|
+
next_action: normalizeString(task.next_action) || null,
|
|
1535
|
+
next_command: normalizeString(task.next_action) || null
|
|
1536
|
+
}
|
|
1537
|
+
};
|
|
1538
|
+
}
|
|
1539
|
+
|
|
1540
|
+
function attachTaskFeedbackModel(payload = {}) {
|
|
1541
|
+
if (!payload || typeof payload !== 'object' || !payload.task || typeof payload.task !== 'object') {
|
|
1542
|
+
return payload;
|
|
1543
|
+
}
|
|
1544
|
+
return {
|
|
1545
|
+
...payload,
|
|
1546
|
+
task: {
|
|
1547
|
+
...payload.task,
|
|
1548
|
+
feedback_model: buildTaskFeedbackModel(payload)
|
|
1549
|
+
}
|
|
1550
|
+
};
|
|
1551
|
+
}
|
|
1463
1552
|
function buildTaskEnvelope(mode, job, options = {}) {
|
|
1464
1553
|
const stageName = resolveTaskStage(mode, job, options.stageName);
|
|
1465
1554
|
const stageState = stageName && job && job.stages && job.stages[stageName]
|
|
@@ -2039,13 +2128,13 @@ async function buildCommandPayload(mode, job, options = {}) {
|
|
|
2039
2128
|
next_action: resolveNextAction(job),
|
|
2040
2129
|
artifacts: { ...job.artifacts }
|
|
2041
2130
|
};
|
|
2042
|
-
return {
|
|
2131
|
+
return attachTaskFeedbackModel({
|
|
2043
2132
|
...base,
|
|
2044
2133
|
...buildTaskEnvelope(mode, job, {
|
|
2045
2134
|
...options,
|
|
2046
2135
|
taskRef
|
|
2047
2136
|
})
|
|
2048
|
-
};
|
|
2137
|
+
});
|
|
2049
2138
|
}
|
|
2050
2139
|
|
|
2051
2140
|
function buildJobDomainChainMetadata(job = {}) {
|
|
@@ -3308,7 +3397,9 @@ async function runStudioEventsCommand(options = {}, dependencies = {}) {
|
|
|
3308
3397
|
: null;
|
|
3309
3398
|
}
|
|
3310
3399
|
payload.events = events;
|
|
3311
|
-
|
|
3400
|
+
const normalizedPayload = attachTaskFeedbackModel(payload);
|
|
3401
|
+
printStudioEventsPayload(normalizedPayload, options);
|
|
3402
|
+
return normalizedPayload;
|
|
3312
3403
|
return payload;
|
|
3313
3404
|
}
|
|
3314
3405
|
|
package/lib/commands/timeline.js
CHANGED
|
@@ -44,6 +44,88 @@ function createStore(dependencies = {}) {
|
|
|
44
44
|
return dependencies.timelineStore || new ProjectTimelineStore(projectPath, fileSystem);
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
function summarizeTimelineAttention(entry = {}) {
|
|
48
|
+
const trigger = normalizeText(entry.trigger).toLowerCase();
|
|
49
|
+
const git = entry && typeof entry.git === 'object' ? entry.git : {};
|
|
50
|
+
if (trigger === 'restore') {
|
|
51
|
+
return 'high';
|
|
52
|
+
}
|
|
53
|
+
if (trigger === 'push') {
|
|
54
|
+
return 'medium';
|
|
55
|
+
}
|
|
56
|
+
if (Number(git.dirty_count || 0) > 0) {
|
|
57
|
+
return 'medium';
|
|
58
|
+
}
|
|
59
|
+
return 'low';
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function buildTimelineEntryViewModel(entry = {}) {
|
|
63
|
+
const title = normalizeText(entry.summary) || ((normalizeText(entry.trigger) || 'timeline') + ' checkpoint');
|
|
64
|
+
const subtitleParts = [
|
|
65
|
+
normalizeText(entry.event),
|
|
66
|
+
entry.scene_id ? ('scene=' + entry.scene_id) : '',
|
|
67
|
+
Number.isFinite(Number(entry.file_count)) ? ('files=' + Number(entry.file_count)) : ''
|
|
68
|
+
].filter(Boolean);
|
|
69
|
+
return {
|
|
70
|
+
snapshot_id: normalizeText(entry.snapshot_id) || null,
|
|
71
|
+
title,
|
|
72
|
+
subtitle: subtitleParts.join(' | '),
|
|
73
|
+
trigger: normalizeText(entry.trigger) || null,
|
|
74
|
+
event: normalizeText(entry.event) || null,
|
|
75
|
+
created_at: normalizeText(entry.created_at) || null,
|
|
76
|
+
scene_id: normalizeText(entry.scene_id) || null,
|
|
77
|
+
session_id: normalizeText(entry.session_id) || null,
|
|
78
|
+
file_count: Number.isFinite(Number(entry.file_count)) ? Number(entry.file_count) : 0,
|
|
79
|
+
branch: entry && entry.git ? normalizeText(entry.git.branch) || null : null,
|
|
80
|
+
head: entry && entry.git ? normalizeText(entry.git.head) || null : null,
|
|
81
|
+
dirty_count: entry && entry.git && Number.isFinite(Number(entry.git.dirty_count)) ? Number(entry.git.dirty_count) : 0,
|
|
82
|
+
attention_level: summarizeTimelineAttention(entry),
|
|
83
|
+
show_command: normalizeText(entry.snapshot_id) ? ('sce timeline show ' + entry.snapshot_id + ' --json') : null,
|
|
84
|
+
restore_command: normalizeText(entry.snapshot_id) ? ('sce timeline restore ' + entry.snapshot_id + ' --json') : null
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function buildTimelineListViewModel(payload = {}) {
|
|
89
|
+
const snapshots = Array.isArray(payload.snapshots) ? payload.snapshots : [];
|
|
90
|
+
const trigger_counts = {};
|
|
91
|
+
let dirty_snapshot_count = 0;
|
|
92
|
+
const sceneIds = new Set();
|
|
93
|
+
for (const item of snapshots) {
|
|
94
|
+
const trigger = normalizeText(item.trigger) || 'unknown';
|
|
95
|
+
trigger_counts[trigger] = Number(trigger_counts[trigger] || 0) + 1;
|
|
96
|
+
if (item.scene_id) {
|
|
97
|
+
sceneIds.add(item.scene_id);
|
|
98
|
+
}
|
|
99
|
+
if (item.git && item.git.dirty) {
|
|
100
|
+
dirty_snapshot_count += 1;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
summary: {
|
|
105
|
+
total: Number(payload.total || snapshots.length || 0),
|
|
106
|
+
latest_snapshot_id: snapshots[0] ? normalizeText(snapshots[0].snapshot_id) || null : null,
|
|
107
|
+
latest_created_at: snapshots[0] ? normalizeText(snapshots[0].created_at) || null : null,
|
|
108
|
+
dirty_snapshot_count,
|
|
109
|
+
scene_count: sceneIds.size,
|
|
110
|
+
trigger_counts
|
|
111
|
+
},
|
|
112
|
+
entries: snapshots.map((item) => buildTimelineEntryViewModel(item))
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function buildTimelineShowViewModel(payload = {}) {
|
|
117
|
+
const snapshot = payload.snapshot && typeof payload.snapshot === 'object' ? payload.snapshot : {};
|
|
118
|
+
const filesPayload = payload.files && typeof payload.files === 'object' ? payload.files : {};
|
|
119
|
+
const files = Array.isArray(filesPayload.files) ? filesPayload.files : [];
|
|
120
|
+
return {
|
|
121
|
+
snapshot: buildTimelineEntryViewModel(snapshot),
|
|
122
|
+
files_preview: files.slice(0, 20),
|
|
123
|
+
file_preview_count: Math.min(files.length, 20),
|
|
124
|
+
file_total: Number(filesPayload.file_count || files.length || 0),
|
|
125
|
+
restore_command: snapshot.snapshot_id ? ('sce timeline restore ' + snapshot.snapshot_id + ' --json') : null
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
47
129
|
function printPayload(payload, asJson = false, title = 'Timeline') {
|
|
48
130
|
if (asJson) {
|
|
49
131
|
console.log(JSON.stringify(payload, null, 2));
|
|
@@ -112,6 +194,7 @@ async function runTimelineListCommand(options = {}, dependencies = {}) {
|
|
|
112
194
|
limit: normalizePositiveInteger(options.limit, 20, 2000),
|
|
113
195
|
trigger: normalizeText(options.trigger)
|
|
114
196
|
});
|
|
197
|
+
payload.view_model = buildTimelineListViewModel(payload);
|
|
115
198
|
printPayload(payload, options.json, 'Timeline List');
|
|
116
199
|
return payload;
|
|
117
200
|
}
|
|
@@ -119,6 +202,7 @@ async function runTimelineListCommand(options = {}, dependencies = {}) {
|
|
|
119
202
|
async function runTimelineShowCommand(snapshotId, options = {}, dependencies = {}) {
|
|
120
203
|
const store = createStore(dependencies);
|
|
121
204
|
const payload = await store.getSnapshot(snapshotId);
|
|
205
|
+
payload.view_model = buildTimelineShowViewModel(payload);
|
|
122
206
|
printPayload(payload, options.json, 'Timeline Show');
|
|
123
207
|
return payload;
|
|
124
208
|
}
|
package/package.json
CHANGED