scene-capability-engine 3.6.61 → 3.6.63

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,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [3.6.63] - 2026-03-21
11
+
12
+ ### Fixed
13
+ - Relaxed `audit:steering` so a clean-room checkout no longer hard-fails release validation just because the gitignored personal file `.sce/steering/CURRENT_CONTEXT.md` is absent.
14
+
15
+ ## [3.6.62] - 2026-03-21
16
+
17
+ ### Removed
18
+ - Removed the OpenHands-specific `sce studio events --openhands-events <path>` bridge so current SCE no longer exposes a vendor-specific event-ingestion path in the active CLI surface.
19
+
10
20
  ## [3.6.61] - 2026-03-20
11
21
 
12
22
  ### Added
package/README.md CHANGED
@@ -155,7 +155,7 @@ SCE is opinionated by default.
155
155
  For IDEs, AI shells, or custom frontends, the most important SCE surfaces are:
156
156
 
157
157
  - `sce studio plan|generate|apply|verify|release`
158
- - `sce studio events --openhands-events <path>`
158
+ - `sce studio events`
159
159
  - `sce task ref|show|rerun`
160
160
  - `sce timeline save|list|show|restore`
161
161
  - `sce capability inventory`
@@ -230,5 +230,5 @@ MIT. See [LICENSE](LICENSE).
230
230
 
231
231
  ---
232
232
 
233
- **Version**: 3.6.61
234
- **Last Updated**: 2026-03-20
233
+ **Version**: 3.6.63
234
+ **Last Updated**: 2026-03-21
package/README.zh.md CHANGED
@@ -160,7 +160,7 @@ SCE 默认是强治理的。
160
160
  如果你要对接 IDE、AI 助手或前端,优先关注这些接口面:
161
161
 
162
162
  - `sce studio plan|generate|apply|verify|release`
163
- - `sce studio events --openhands-events <path>`
163
+ - `sce studio events`
164
164
  - `sce task ref|show|rerun`
165
165
  - `sce timeline save|list|show|restore`
166
166
  - `sce capability inventory`
@@ -235,5 +235,5 @@ MIT,见 [LICENSE](LICENSE)。
235
235
 
236
236
  ---
237
237
 
238
- **版本**:3.6.61
239
- **最后更新**:2026-03-20
238
+ **版本**:3.6.63
239
+ **最后更新**:2026-03-21
@@ -744,8 +744,6 @@ sce studio resume --job <job-id> --json
744
744
 
745
745
  # Inspect recent stage events
746
746
  sce studio events --job <job-id> --limit 50 --json
747
- # Map OpenHands raw events into the same task-stream contract
748
- sce studio events --job <job-id> --openhands-events ./openhands-events.json --json
749
747
 
750
748
  # Rollback a job after apply/release
751
749
  sce studio rollback --job <job-id> --reason "manual-check-failed" --json
@@ -779,7 +777,6 @@ Studio JSON output now includes a stable UI-oriented task stream contract (in ad
779
777
  - `task.evidence[]`: structured evidence references
780
778
  - `task.feedback_model`: human-facing task feedback (`problem`, `execution`, `diagnosis`, `evidence`, `next_step`, `mb_status`)
781
779
  - `event[]`: raw audit event stream (`studio events` also keeps legacy `events[]` for compatibility)
782
- - `studio events --openhands-events <path>` switches `source_stream=openhands` and maps OpenHands raw events to the same task contract fields.
783
780
  - hierarchical task reference lookup/rerun:
784
781
  - `sce task show --ref <SS.PP.TT> --json`
785
782
  - `sce task rerun --ref <SS.PP.TT> [--dry-run] --json`
@@ -117,7 +117,6 @@ SCE 现在在时间线命令中增加:
117
117
  ## 4. 最小接口清单
118
118
 
119
119
  - `sce studio events --job <job-id> --json`
120
- - `sce studio events --job <job-id> --openhands-events <path> --json`
121
120
  - `sce timeline list --limit 20 --json`
122
121
  - `sce timeline show <snapshot-id> --json`
123
122
 
@@ -9,6 +9,8 @@ This directory stores release-facing documents:
9
9
  ## Archived Versions
10
10
 
11
11
  - [Release checklist](../release-checklist.md)
12
+ - [v3.6.63 release notes](./v3.6.63.md)
13
+ - [v3.6.62 release notes](./v3.6.62.md)
12
14
  - [v3.6.61 release notes](./v3.6.61.md)
13
15
  - [v3.6.60 release notes](./v3.6.60.md)
14
16
  - [v3.6.59 release notes](./v3.6.59.md)
@@ -0,0 +1,32 @@
1
+ # v3.6.62 Release Notes
2
+
3
+ Release date: 2026-03-21
4
+
5
+ ## Highlights
6
+
7
+ - Removed the OpenHands-specific `sce studio events --openhands-events <path>` bridge from the tracked CLI surface so SCE no longer publishes a vendor-specific event-ingestion path as a first-class runtime contract.
8
+ - Removed the corresponding OpenHands mapping test coverage and cleaned the main command reference plus README surfaces to keep shipped documentation aligned with the active product boundary.
9
+ - Kept the broader external-runtime direction vendor-neutral so future IDE embedding can focus on Codex CLI, Claude Code, and similar in-process tool endpoints without carrying a stale OpenHands-first entry point.
10
+
11
+ ## Validation
12
+
13
+ - `npx jest tests/unit/commands/studio.test.js --runInBand`
14
+ - `npm run test:release`
15
+ - `npm run audit:release-docs`
16
+ - `npm run audit:steering`
17
+ - `npm run test:skip-audit`
18
+ - `npm run test:sce-tracking`
19
+ - `npm run gate:npm-runtime-assets`
20
+ - `npm run test:brand-consistency`
21
+ - `npm run audit:clarification-first`
22
+ - `npm run audit:magicball-engineering-contract`
23
+ - `npm run audit:magicball-project-contract`
24
+ - `npm run gate:collab-governance`
25
+ - `npm run gate:errorbook-registry-health`
26
+ - `npm run gate:errorbook-release`
27
+ - `npm pack --dry-run`
28
+
29
+ ## Release Notes
30
+
31
+ - Use `v3.6.62` when you need the published SCE package to exclude the old OpenHands-specific `studio events` bridge from the active CLI and doc surface.
32
+ - This patch intentionally does not rewrite user-local draft Specs; it only cleans the tracked engine, tests, and release-facing documentation.
@@ -0,0 +1,34 @@
1
+ # v3.6.63 Release Notes
2
+
3
+ Release date: 2026-03-21
4
+
5
+ ## Highlights
6
+
7
+ - Fixed a clean-room release blocker in `audit:steering`: the gitignored personal file `.sce/steering/CURRENT_CONTEXT.md` is now treated as optional when absent in a fresh checkout.
8
+ - Added unit coverage so steering governance still enforces stable layers while no longer requiring a local-only context file to exist in Git-tracked release environments.
9
+ - Kept the `v3.6.62` OpenHands cleanup intact; this patch only repairs the release path uncovered while publishing that cleanup.
10
+
11
+ ## Validation
12
+
13
+ - `npx jest tests/unit/scripts/steering-content-audit.test.js --runInBand`
14
+ - `npx jest tests/unit/commands/studio.test.js --runInBand`
15
+ - `npm run test:release`
16
+ - `npm run audit:release-docs`
17
+ - `npm run audit:steering`
18
+ - `npm run test:skip-audit`
19
+ - `npm run test:sce-tracking`
20
+ - `npm run gate:npm-runtime-assets`
21
+ - `npm run test:brand-consistency`
22
+ - `npm run audit:clarification-first`
23
+ - `npm run audit:magicball-engineering-contract`
24
+ - `npm run audit:magicball-project-contract`
25
+ - `npm run gate:collab-governance`
26
+ - `npm run gate:errorbook-registry-health`
27
+ - `npm run gate:errorbook-release`
28
+ - `npm run report:interactive-governance -- --fail-on-alert`
29
+ - `npm pack --dry-run`
30
+
31
+ ## Release Notes
32
+
33
+ - Use `v3.6.63` if you need the OpenHands cleanup from `v3.6.62` plus a clean-room-safe steering audit during publish.
34
+ - This fix preserves the co-work rule that `CURRENT_CONTEXT.md` remains local/personal state and should not be force-committed just to satisfy release automation.
@@ -9,6 +9,8 @@
9
9
  ## 历史版本归档
10
10
 
11
11
  - [发布检查清单](../release-checklist.md)
12
+ - [v3.6.63 发布说明](./v3.6.63.md)
13
+ - [v3.6.62 发布说明](./v3.6.62.md)
12
14
  - [v3.6.61 发布说明](./v3.6.61.md)
13
15
  - [v3.6.60 发布说明](./v3.6.60.md)
14
16
  - [v3.6.59 发布说明](./v3.6.59.md)
@@ -0,0 +1,32 @@
1
+ # v3.6.62 发布说明
2
+
3
+ 发布日期:2026-03-21
4
+
5
+ ## 重点变化
6
+
7
+ - 从已跟踪 CLI 正式接口面移除了 OpenHands 专有的 `sce studio events --openhands-events <path>` 桥接入口,避免 SCE 继续把某个供应商专有事件摄取路径作为一等运行时契约发布。
8
+ - 同步移除了对应的 OpenHands 映射测试,并清理了主命令参考与 README 中的相关说明,保证随包发布的文档与当前正式产品边界一致。
9
+ - 外部 runtime 方向继续保持 vendor-neutral,为后续 IDE 内嵌 Codex CLI、Claude Code 等执行端预留稳定空间,而不是继续背着过时的 OpenHands-first 入口。
10
+
11
+ ## 验证
12
+
13
+ - `npx jest tests/unit/commands/studio.test.js --runInBand`
14
+ - `npm run test:release`
15
+ - `npm run audit:release-docs`
16
+ - `npm run audit:steering`
17
+ - `npm run test:skip-audit`
18
+ - `npm run test:sce-tracking`
19
+ - `npm run gate:npm-runtime-assets`
20
+ - `npm run test:brand-consistency`
21
+ - `npm run audit:clarification-first`
22
+ - `npm run audit:magicball-engineering-contract`
23
+ - `npm run audit:magicball-project-contract`
24
+ - `npm run gate:collab-governance`
25
+ - `npm run gate:errorbook-registry-health`
26
+ - `npm run gate:errorbook-release`
27
+ - `npm pack --dry-run`
28
+
29
+ ## 发布说明
30
+
31
+ - 当你需要已发布的 SCE 包不再暴露旧的 OpenHands 专有 `studio events` 桥接入口时,请使用 `v3.6.62`。
32
+ - 本次补丁刻意不去重写用户本地未纳管的草稿 spec,只清理已跟踪的 engine、测试与发布文档面。
@@ -0,0 +1,34 @@
1
+ # v3.6.63 发布说明
2
+
3
+ 发布日期:2026-03-21
4
+
5
+ ## 重点变化
6
+
7
+ - 修复了 `audit:steering` 的 clean-room 发布阻断问题:在全新克隆中,如果被 `.gitignore` 排除的个人态文件 `.sce/steering/CURRENT_CONTEXT.md` 不存在,不再直接把发布校验打成失败。
8
+ - 增加了对应单测,确保 steering 治理仍然会继续严格检查稳定层文件,但不再强迫 Git 跟踪环境必须带着本地个人上下文文件。
9
+ - `v3.6.62` 的 OpenHands 清理内容保持不变;本补丁只修复发布那条线在真实发布过程中暴露出的流程缺陷。
10
+
11
+ ## 验证
12
+
13
+ - `npx jest tests/unit/scripts/steering-content-audit.test.js --runInBand`
14
+ - `npx jest tests/unit/commands/studio.test.js --runInBand`
15
+ - `npm run test:release`
16
+ - `npm run audit:release-docs`
17
+ - `npm run audit:steering`
18
+ - `npm run test:skip-audit`
19
+ - `npm run test:sce-tracking`
20
+ - `npm run gate:npm-runtime-assets`
21
+ - `npm run test:brand-consistency`
22
+ - `npm run audit:clarification-first`
23
+ - `npm run audit:magicball-engineering-contract`
24
+ - `npm run audit:magicball-project-contract`
25
+ - `npm run gate:collab-governance`
26
+ - `npm run gate:errorbook-registry-health`
27
+ - `npm run gate:errorbook-release`
28
+ - `npm run report:interactive-governance -- --fail-on-alert`
29
+ - `npm pack --dry-run`
30
+
31
+ ## 发布说明
32
+
33
+ - 如果你既需要 `v3.6.62` 的 OpenHands 清理,又需要 clean-room 发布环境下可通过的 steering 审计,请使用 `v3.6.63`。
34
+ - 该修复保持 co-work 规则不变:`CURRENT_CONTEXT.md` 依然属于本地个人态文件,不应为了过发布门禁而被强制提交到 Git。
@@ -921,273 +921,6 @@ function extractEventArrayFromPayload(payload) {
921
921
  return [payload];
922
922
  }
923
923
 
924
- async function readOpenHandsEventsFile(openhandsEventsPath, fileSystem = fs) {
925
- const normalizedPath = normalizeString(openhandsEventsPath);
926
- if (!normalizedPath) {
927
- return [];
928
- }
929
- const exists = await fileSystem.pathExists(normalizedPath);
930
- if (!exists) {
931
- throw new Error(`OpenHands events file not found: ${normalizedPath}`);
932
- }
933
-
934
- const content = await fileSystem.readFile(normalizedPath, 'utf8');
935
- const trimmed = `${content || ''}`.trim();
936
- if (!trimmed) {
937
- return [];
938
- }
939
-
940
- try {
941
- const parsed = JSON.parse(trimmed);
942
- return extractEventArrayFromPayload(parsed);
943
- } catch (_error) {
944
- const lines = trimmed
945
- .split(/\r?\n/)
946
- .map((line) => line.trim())
947
- .filter(Boolean);
948
- const parsedLines = [];
949
- for (const line of lines) {
950
- try {
951
- parsedLines.push(JSON.parse(line));
952
- } catch (_innerError) {
953
- // Skip malformed JSONL lines to keep ingestion robust.
954
- }
955
- }
956
- return parsedLines;
957
- }
958
- }
959
-
960
- function normalizeOpenHandsEventRecord(rawEvent, index, jobId) {
961
- const raw = rawEvent && typeof rawEvent === 'object'
962
- ? rawEvent
963
- : { value: rawEvent };
964
- const eventId = pickFirstString([
965
- raw.event_id,
966
- raw.eventId,
967
- raw.id,
968
- raw.uuid
969
- ]) || `oh-evt-${index + 1}`;
970
- const eventType = pickFirstString([
971
- raw.event_type,
972
- raw.eventType,
973
- raw.type,
974
- raw.kind,
975
- raw.action
976
- ]) || 'unknown';
977
- const timestamp = pickFirstString([
978
- raw.timestamp,
979
- raw.time,
980
- raw.created_at,
981
- raw.createdAt,
982
- raw.ts
983
- ]) || nowIso();
984
- return {
985
- api_version: STUDIO_EVENT_API_VERSION,
986
- event_id: eventId,
987
- job_id: jobId,
988
- event_type: `openhands.${eventType}`,
989
- timestamp,
990
- metadata: {
991
- source: 'openhands',
992
- raw
993
- }
994
- };
995
- }
996
-
997
- function tryParseJsonText(value) {
998
- if (typeof value !== 'string') {
999
- return null;
1000
- }
1001
- const trimmed = value.trim();
1002
- if (!trimmed) {
1003
- return null;
1004
- }
1005
- if (!(trimmed.startsWith('{') || trimmed.startsWith('['))) {
1006
- return null;
1007
- }
1008
- try {
1009
- return JSON.parse(trimmed);
1010
- } catch (_error) {
1011
- return null;
1012
- }
1013
- }
1014
-
1015
- function stringifyCompact(value) {
1016
- if (value == null) {
1017
- return '';
1018
- }
1019
- if (typeof value === 'string') {
1020
- return value;
1021
- }
1022
- try {
1023
- return JSON.stringify(value);
1024
- } catch (_error) {
1025
- return `${value}`;
1026
- }
1027
- }
1028
-
1029
- function extractOpenHandsCommandCandidates(raw = {}) {
1030
- const command = pickFirstString([
1031
- raw.command,
1032
- raw.cmd,
1033
- raw.input && raw.input.command,
1034
- raw.action && raw.action.command,
1035
- raw.observation && raw.observation.command,
1036
- raw.tool_input && raw.tool_input.command
1037
- ]);
1038
-
1039
- const toolName = pickFirstString([
1040
- raw.tool_name,
1041
- raw.toolName,
1042
- raw.tool && raw.tool.name,
1043
- raw.name
1044
- ]);
1045
- const toolArgs = raw.arguments || raw.tool_input || raw.input || null;
1046
-
1047
- const cmd = command || (toolName
1048
- ? `tool:${toolName}${toolArgs ? ` ${stringifyCompact(toolArgs)}` : ''}`
1049
- : '');
1050
-
1051
- return {
1052
- cmd,
1053
- exit_code: pickFirstNumber([
1054
- raw.exit_code,
1055
- raw.exitCode,
1056
- raw.result && (raw.result.exit_code ?? raw.result.exitCode)
1057
- ]),
1058
- stdout: pickFirstString([
1059
- raw.stdout,
1060
- raw.output,
1061
- raw.result && raw.result.stdout,
1062
- raw.observation && raw.observation.stdout
1063
- ]),
1064
- stderr: pickFirstString([
1065
- raw.stderr,
1066
- raw.result && raw.result.stderr,
1067
- raw.error && raw.error.message,
1068
- typeof raw.error === 'string' ? raw.error : ''
1069
- ]),
1070
- log_path: pickFirstString([
1071
- raw.log_path,
1072
- raw.logPath,
1073
- raw.log && raw.log.path
1074
- ])
1075
- };
1076
- }
1077
-
1078
- function collectOpenHandsFileChangesFromRaw(raw = {}) {
1079
- const changes = [];
1080
- const addPath = (pathValue, lineValue, diffRefValue = '') => {
1081
- const pathRef = normalizeString(pathValue);
1082
- if (!pathRef) {
1083
- return;
1084
- }
1085
- const line = Number.parseInt(`${lineValue != null ? lineValue : 1}`, 10);
1086
- const normalizedLine = Number.isFinite(line) && line > 0 ? line : 1;
1087
- const diffRef = normalizeString(diffRefValue) || `${pathRef}:${normalizedLine}`;
1088
- changes.push({
1089
- path: pathRef,
1090
- line: normalizedLine,
1091
- diffRef
1092
- });
1093
- };
1094
-
1095
- if (typeof raw.path === 'string') {
1096
- addPath(raw.path, raw.line || raw.line_number, raw.diff_ref);
1097
- }
1098
- if (raw.file && typeof raw.file === 'object') {
1099
- addPath(raw.file.path || raw.file.name, raw.file.line || raw.file.line_number, raw.file.diffRef || raw.file.diff_ref);
1100
- }
1101
-
1102
- const arrayKeys = ['files', 'changed_files', 'modified_files', 'created_files', 'deleted_files'];
1103
- for (const key of arrayKeys) {
1104
- const values = Array.isArray(raw[key]) ? raw[key] : [];
1105
- for (const value of values) {
1106
- if (typeof value === 'string') {
1107
- addPath(value, 1);
1108
- } else if (value && typeof value === 'object') {
1109
- addPath(value.path || value.file || value.name, value.line || value.line_number, value.diffRef || value.diff_ref);
1110
- }
1111
- }
1112
- }
1113
-
1114
- const patchText = pickFirstString([raw.patch, raw.diff]);
1115
- if (patchText) {
1116
- const parsedJson = tryParseJsonText(patchText);
1117
- if (parsedJson && typeof parsedJson === 'object') {
1118
- const nested = collectOpenHandsFileChangesFromRaw(parsedJson);
1119
- changes.push(...nested);
1120
- } else {
1121
- const lines = patchText.split(/\r?\n/);
1122
- for (const line of lines) {
1123
- const match = line.match(/^\+\+\+\s+b\/(.+)$/);
1124
- if (match && match[1]) {
1125
- addPath(match[1], 1);
1126
- }
1127
- }
1128
- }
1129
- }
1130
-
1131
- return changes;
1132
- }
1133
-
1134
- function mapOpenHandsEventsToTaskSignals(openhandsEvents = [], context = {}) {
1135
- const normalizedEvents = openhandsEvents.map((item, index) =>
1136
- normalizeOpenHandsEventRecord(item, index, context.jobId)
1137
- );
1138
-
1139
- const commands = [];
1140
- const fileChanges = [];
1141
- const errors = [];
1142
- const evidence = [];
1143
-
1144
- for (const event of normalizedEvents) {
1145
- const raw = event && event.metadata ? event.metadata.raw || {} : {};
1146
- const commandCandidate = extractOpenHandsCommandCandidates(raw);
1147
- if (commandCandidate.cmd || commandCandidate.stdout || commandCandidate.stderr || commandCandidate.exit_code != null) {
1148
- commands.push(commandCandidate);
1149
- }
1150
-
1151
- fileChanges.push(...collectOpenHandsFileChangesFromRaw(raw));
1152
-
1153
- const eventType = normalizeString(event.event_type).toLowerCase();
1154
- const failedByType = eventType.includes('error') || eventType.includes('fail');
1155
- const failedByExit = commandCandidate.exit_code != null && Number(commandCandidate.exit_code) !== 0;
1156
- const failedByStderr = commandCandidate.stderr.length > 0 && !commandCandidate.stdout;
1157
- if (failedByType || failedByExit || failedByStderr) {
1158
- const message = pickFirstString([
1159
- raw.message,
1160
- raw.error && raw.error.message,
1161
- typeof raw.error === 'string' ? raw.error : '',
1162
- failedByExit ? `OpenHands command failed (exit ${commandCandidate.exit_code})` : '',
1163
- 'OpenHands event indicates failure'
1164
- ]);
1165
- errors.push({
1166
- message,
1167
- step_id: event.event_type,
1168
- cmd: commandCandidate.cmd,
1169
- exit_code: commandCandidate.exit_code,
1170
- stderr: commandCandidate.stderr,
1171
- stdout: commandCandidate.stdout
1172
- });
1173
- }
1174
-
1175
- evidence.push({
1176
- type: 'openhands-event',
1177
- ref: event.event_id,
1178
- detail: event.event_type
1179
- });
1180
- }
1181
-
1182
- return {
1183
- event: normalizedEvents,
1184
- commands: normalizeTaskCommands(commands),
1185
- file_changes: normalizeTaskFileChanges(fileChanges),
1186
- errors: normalizeTaskErrors(errors),
1187
- evidence: normalizeTaskEvidence(evidence)
1188
- };
1189
- }
1190
-
1191
924
  function extractCommandsFromStageMetadata(stageMetadata = {}) {
1192
925
  const gateSteps = Array.isArray(stageMetadata && stageMetadata.gate_steps)
1193
926
  ? stageMetadata.gate_steps
@@ -2919,21 +2652,7 @@ async function runStudioEventsCommand(options = {}, dependencies = {}) {
2919
2652
 
2920
2653
  const limit = normalizePositiveInteger(options.limit, 50);
2921
2654
  const job = await loadJob(paths, jobId, fileSystem);
2922
- const openhandsEventsPath = normalizeString(options.openhandsEvents);
2923
- let sourceStream = 'studio';
2924
2655
  let events = await readStudioEvents(paths, jobId, { limit }, fileSystem);
2925
- let openhandsSignals = null;
2926
- if (openhandsEventsPath) {
2927
- const absoluteOpenhandsPath = path.isAbsolute(openhandsEventsPath)
2928
- ? openhandsEventsPath
2929
- : path.join(projectPath, openhandsEventsPath);
2930
- const rawOpenhandsEvents = await readOpenHandsEventsFile(absoluteOpenhandsPath, fileSystem);
2931
- openhandsSignals = mapOpenHandsEventsToTaskSignals(rawOpenhandsEvents, {
2932
- jobId: job.job_id
2933
- });
2934
- events = openhandsSignals.event;
2935
- sourceStream = 'openhands';
2936
- }
2937
2656
 
2938
2657
  const payload = await buildCommandPayload('studio-events', job, {
2939
2658
  events,
@@ -2941,47 +2660,11 @@ async function runStudioEventsCommand(options = {}, dependencies = {}) {
2941
2660
  fileSystem
2942
2661
  });
2943
2662
  payload.limit = limit;
2944
- payload.source_stream = sourceStream;
2945
- if (sourceStream === 'openhands') {
2946
- payload.openhands_events_file = path.relative(projectPath, path.isAbsolute(openhandsEventsPath)
2947
- ? openhandsEventsPath
2948
- : path.join(projectPath, openhandsEventsPath)).replace(/\\/g, '/');
2949
- payload.task = {
2950
- ...payload.task,
2951
- summary: [
2952
- `OpenHands events: ${events.length} | commands: ${openhandsSignals.commands.length} | errors: ${openhandsSignals.errors.length}`,
2953
- `File changes: ${openhandsSignals.file_changes.length} | source: ${payload.openhands_events_file}`,
2954
- `Next: ${payload.task.next_action}`
2955
- ],
2956
- handoff: {
2957
- ...(payload.task.handoff || {}),
2958
- source_stream: 'openhands',
2959
- openhands_event_count: events.length,
2960
- openhands_command_count: openhandsSignals.commands.length,
2961
- openhands_error_count: openhandsSignals.errors.length
2962
- },
2963
- commands: openhandsSignals.commands,
2964
- file_changes: openhandsSignals.file_changes,
2965
- errors: openhandsSignals.errors,
2966
- evidence: normalizeTaskEvidence([
2967
- ...(Array.isArray(payload.task.evidence) ? payload.task.evidence : []),
2968
- ...openhandsSignals.evidence,
2969
- {
2970
- type: 'openhands-event-file',
2971
- ref: payload.openhands_events_file,
2972
- detail: 'mapped'
2973
- }
2974
- ])
2975
- };
2976
- payload.eventId = events.length > 0
2977
- ? events[events.length - 1].event_id
2978
- : null;
2979
- }
2663
+ payload.source_stream = 'studio';
2980
2664
  payload.events = events;
2981
2665
  const normalizedPayload = attachTaskFeedbackModel(payload);
2982
2666
  printStudioEventsPayload(normalizedPayload, options);
2983
2667
  return normalizedPayload;
2984
- return payload;
2985
2668
  }
2986
2669
 
2987
2670
  function printStudioIntakePayload(payload, options = {}) {
@@ -3267,7 +2950,6 @@ function registerStudioCommands(program) {
3267
2950
  .description('Show studio job event stream')
3268
2951
  .option('--job <job-id>', 'Studio job id (defaults to latest)')
3269
2952
  .option('--limit <number>', 'Maximum number of recent events to return', '50')
3270
- .option('--openhands-events <path>', 'Optional OpenHands raw events file (.json/.jsonl) mapped to task stream')
3271
2953
  .option('--json', 'Print machine-readable JSON output')
3272
2954
  .action(async (options) => runStudioCommand(runStudioEventsCommand, options, 'events'));
3273
2955
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scene-capability-engine",
3
- "version": "3.6.61",
3
+ "version": "3.6.63",
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": {
@@ -186,6 +186,10 @@ function pushViolation(violations, severity, file, rule, message, suggestion) {
186
186
  });
187
187
  }
188
188
 
189
+ function isOptionalCurrentContextFile(fileName) {
190
+ return fileName === 'CURRENT_CONTEXT.md';
191
+ }
192
+
189
193
  function auditSteeringContent(options = {}) {
190
194
  const projectPath = path.resolve(options.projectPath || process.cwd());
191
195
  const packageJsonPath = path.join(projectPath, 'package.json');
@@ -206,6 +210,17 @@ function auditSteeringContent(options = {}) {
206
210
  for (const fileName of fileNames) {
207
211
  const absolutePath = path.join(steeringDir, fileName);
208
212
  if (!fs.existsSync(absolutePath)) {
213
+ if (isOptionalCurrentContextFile(fileName)) {
214
+ pushViolation(
215
+ violations,
216
+ 'warning',
217
+ fileName,
218
+ 'missing_optional_context',
219
+ `${fileName} is absent in this checkout; clean-room repositories may omit personal current context until active local work begins.`,
220
+ 'Create CURRENT_CONTEXT.md locally when active work starts, but keep it out of Git-tracked release state.'
221
+ );
222
+ continue;
223
+ }
209
224
  pushViolation(
210
225
  violations,
211
226
  'error',
@@ -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.61
247
- **Last Updated**: 2026-03-20
246
+ **sce Version**: 3.6.63
247
+ **Last Updated**: 2026-03-21
248
248
  **Purpose**: Guide AI tools to work effectively with this project