推进 INI 面板运行摘要状态

This commit is contained in:
2026-06-14 17:31:33 +08:00
parent 6242b415ff
commit f96329d67f
4 changed files with 199 additions and 0 deletions

View File

@@ -1028,3 +1028,70 @@ host_wasm_opfs_browser_smokes=ok
`programSource`、`snapshotLabel`、`workflow`、`programOpfsPath`、`programWasmPath`
供后续 SDK/API 或 UI panel 读取;先只做 UI/测试边界,不改变 interpreter、OPFS bridge
或 LinuxCNC-owned runtime semantics。
十四、2026-06-14 继续执行记录INI panel run summary state
本轮继续沿 OPFS/session/UI boundary 推进,把最近一次 `Run G-code` 的 session context
同步到可见 UI 状态字段和机器可读 run summary避免后续 UI/API 从日志文本反解析。
完成内容:
- 在 `wasm-port/runtime/ui/ini-panel/index.html` 增加最近一次 run 的可见状态字段:
- `Run Source`
- `Run Snapshot`
- `Run Workflow`
- `Run OPFS Path`
- `Run WASM Path`
- 在 `wasm-port/runtime/ui/ini-panel/app.js` 新增:
- `clearLastRunSummary()`
- `setLastRunSummary(program, snapshot)`
- 成功运行 G-code 后UI 写入 `window.linuxCncIniPanelLastRunSummary`,字段包括:
- `programSource`
- `snapshotLabel`
- `workflow`
- `programOpfsPath`
- `programWasmPath`
- fallback run 的 summary 明确为 `programSource: "default"`snapshot/workflow 为 `null`
- snapshot run 的 summary 明确为 `programSource: "snapshot"`,并包含
`ui-machine-session/ui-machine-session.json` 与 `save-session-snapshot`
- browser INI panel smoke 同时验证可见字段与 `window.linuxCncIniPanelLastRunSummary`
- 未改变日志格式以外的 runtime 行为、snapshot envelope、OPFS path model、G-code 文本、
interpreter run API、canonical-event 输出或 LinuxCNC-owned runtime semantics。
验证已通过:
```bash
git diff --check
SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_ini_panel_browser.sh
wasm-port/tests/opfs/node/verify_file_service.sh
wasm-port/tools/verify_vendor_sync.sh
wasm-port/tools/verify_no_standalone_cnc_semantics.sh
SKIP_INTERP_BUILD=1 wasm-port/tests/wasm/node/verify_interp_wasm.sh
SKIP_INTERP_BUILD=1 wasm-port/tests/wasm/node/verify_sim_configs_inventory_wasm.sh
SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_interp_browser.sh
wasm-port/tests/host/verify_host_smokes.sh
```
关键输出:
```text
browser_ini_opfs_smoke=ok
opfs_file_service_node_smoke=ok
vendor sync up to date
standalone CNC semantics guard complete
interp_wasm_node_smoke=ok
sim_configs_wasm_node_inventory_executed=28
sim_configs_wasm_node_inventory_passed=28
sim_configs_wasm_node_inventory_skipped=131
sim_configs_wasm_node_inventory_unexpected_fail=0
browser_interp_smoke=ok
host_wasm_opfs_browser_smokes=ok
```
下一步建议:
继续沿 OPFS/session/UI boundary 推进。优先把 `Run G-code` 的机器可读 summary 扩展为
包含轻量 runtime result 摘要,例如 `canonicalEventCount`、`motionSnapshotCount`、
`runStatus` 和 `iniWasmPath`,方便 UI/API 判断运行是否真的产生 LinuxCNC canonical output
仍只统计 LinuxCNC-owned runtime 输出,不解析或改写 G-code、tool、parameter、planner 等
CNC 语义。

View File

@@ -109,6 +109,11 @@ const fields = {
sessionGcode: document.getElementById("field-session-gcode"),
sessionSnapshot: document.getElementById("field-session-snapshot"),
runStatus: document.getElementById("field-run-status"),
runSource: document.getElementById("field-run-source"),
runSnapshot: document.getElementById("field-run-snapshot"),
runWorkflow: document.getElementById("field-run-workflow"),
runOpfsPath: document.getElementById("field-run-opfs-path"),
runWasmPath: document.getElementById("field-run-wasm-path"),
fiveaxisRemap: document.getElementById("field-fiveaxis-remap"),
};
@@ -350,6 +355,34 @@ function runSessionContextLogLines(program, snapshot = restoredSessionSnapshot)
];
}
function clearLastRunSummary() {
window.linuxCncIniPanelLastRunSummary = null;
setField("runSource", "-");
setField("runSnapshot", "-");
setField("runWorkflow", "-");
setField("runOpfsPath", "-");
setField("runWasmPath", "-");
}
function setLastRunSummary(program, snapshot = restoredSessionSnapshot) {
const snapshotLabel = snapshot ? sessionSnapshotLabel(snapshot.sessionId) : null;
const metadata = snapshot?.metadata ?? {};
const summary = {
programSource: program.source,
snapshotLabel,
workflow: metadata.workflow ?? null,
programOpfsPath: program.opfsPath,
programWasmPath: program.wasmPath,
};
window.linuxCncIniPanelLastRunSummary = summary;
setField("runSource", summary.programSource);
setField("runSnapshot", summary.snapshotLabel ?? "-");
setField("runWorkflow", summary.workflow ?? "-");
setField("runOpfsPath", summary.programOpfsPath);
setField("runWasmPath", summary.programWasmPath);
return summary;
}
async function loadSelectedGcodeProgram() {
const opfsPath = restoredSessionSnapshot?.payload?.files?.gcode;
let filename = UI_SESSION.defaultGcodeFilename;
@@ -627,11 +660,13 @@ document.getElementById("run-gcode").addEventListener("click", async () => {
interp.writeTextFile(program.wasmPath, program.text);
clearRunPlayback();
setField("runStatus", "running");
clearLastRunSummary();
setRunMonitor(5, "running", {}, "running");
await nextFrame();
const result = interp.runFileWithIni(program.wasmPath, loadedSession.ini.wasmPath);
setField("sessionGcode", program.opfsPath);
setField("runStatus", "ok");
setLastRunSummary(program);
setCanonicalEvents(result.trim());
playRunMotion(result.trim(), program.text);
setLog(
@@ -646,6 +681,7 @@ document.getElementById("run-gcode").addEventListener("click", async () => {
setField("runStatus", "failed");
setCanonicalEvents("");
clearRunPlayback();
clearLastRunSummary();
setRunMonitor(0, "failed", {}, "failed");
setLog(`G-code run failed: ${error.message}`, true);
}

View File

@@ -279,6 +279,16 @@
<dd id="field-session-snapshot">-</dd>
<dt>Run Status</dt>
<dd id="field-run-status">-</dd>
<dt>Run Source</dt>
<dd id="field-run-source">-</dd>
<dt>Run Snapshot</dt>
<dd id="field-run-snapshot">-</dd>
<dt>Run Workflow</dt>
<dd id="field-run-workflow">-</dd>
<dt>Run OPFS Path</dt>
<dd id="field-run-opfs-path">-</dd>
<dt>Run WASM Path</dt>
<dd id="field-run-wasm-path">-</dd>
<dt>5-Axis Remap</dt>
<dd id="field-fiveaxis-remap">-</dd>
</dl>

View File

@@ -411,6 +411,45 @@ TOOL_TABLE = browser-tool.tbl
) {
throw new Error(`UI fallback G-code run did not use default OPFS program path: ${fallbackRunLog}`);
}
assertEqual(
uiDocument.getElementById("field-run-source").textContent,
"default",
"UI fallback run source field",
);
assertEqual(
uiDocument.getElementById("field-run-snapshot").textContent,
"-",
"UI fallback run snapshot field",
);
assertEqual(
uiDocument.getElementById("field-run-workflow").textContent,
"-",
"UI fallback run workflow field",
);
assertEqual(
uiDocument.getElementById("field-run-opfs-path").textContent,
"linuxcnc/gcode/ui-session.ngc",
"UI fallback run OPFS field",
);
assertEqual(
uiDocument.getElementById("field-run-wasm-path").textContent,
"/work/ui-session.ngc",
"UI fallback run WASM field",
);
const fallbackRunSummary = uiDocument.defaultView.linuxCncIniPanelLastRunSummary;
assertEqual(fallbackRunSummary.programSource, "default", "UI fallback run summary source");
assertEqual(fallbackRunSummary.snapshotLabel, null, "UI fallback run summary snapshot");
assertEqual(fallbackRunSummary.workflow, null, "UI fallback run summary workflow");
assertEqual(
fallbackRunSummary.programOpfsPath,
"linuxcnc/gcode/ui-session.ngc",
"UI fallback run summary OPFS path",
);
assertEqual(
fallbackRunSummary.programWasmPath,
"/work/ui-session.ngc",
"UI fallback run summary WASM path",
);
uiDocument.getElementById("save-session-snapshot").click();
await waitFor(
() => uiDocument.getElementById("log")?.textContent.includes("Saved machine session snapshot"),
@@ -542,6 +581,53 @@ TOOL_TABLE = browser-tool.tbl
) {
throw new Error(`UI G-code run missing snapshot session context: ${runLog}`);
}
assertEqual(
uiDocument.getElementById("field-run-source").textContent,
"snapshot",
"UI snapshot run source field",
);
assertEqual(
uiDocument.getElementById("field-run-snapshot").textContent,
"ui-machine-session/ui-machine-session.json",
"UI snapshot run snapshot field",
);
assertEqual(
uiDocument.getElementById("field-run-workflow").textContent,
"save-session-snapshot",
"UI snapshot run workflow field",
);
assertEqual(
uiDocument.getElementById("field-run-opfs-path").textContent,
"linuxcnc/gcode/ui-session.ngc",
"UI snapshot run OPFS field",
);
assertEqual(
uiDocument.getElementById("field-run-wasm-path").textContent,
"/work/ui-session.ngc",
"UI snapshot run WASM field",
);
const snapshotRunSummary = uiDocument.defaultView.linuxCncIniPanelLastRunSummary;
assertEqual(snapshotRunSummary.programSource, "snapshot", "UI snapshot run summary source");
assertEqual(
snapshotRunSummary.snapshotLabel,
"ui-machine-session/ui-machine-session.json",
"UI snapshot run summary snapshot",
);
assertEqual(
snapshotRunSummary.workflow,
"save-session-snapshot",
"UI snapshot run summary workflow",
);
assertEqual(
snapshotRunSummary.programOpfsPath,
"linuxcnc/gcode/ui-session.ngc",
"UI snapshot run summary OPFS path",
);
assertEqual(
snapshotRunSummary.programWasmPath,
"/work/ui-session.ngc",
"UI snapshot run summary WASM path",
);
if (
!runLog.includes("canon_event=STRAIGHT_TRAVERSE") ||
!runLog.includes("canon_event=STRAIGHT_FEED")