From 03db34485e2ea99bd1dba17b09df5f31aa8a8651 Mon Sep 17 00:00:00 2001 From: wangdequan Date: Tue, 16 Jun 2026 06:36:45 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8E=A5=E5=85=A5=20INI=20panel=20session=20re?= =?UTF-8?q?adiness=20workflow?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PROJECT_COMPLETION_TRACKER.md | 4 +- text14.txt | 72 ++++++++ wasm-port/docs/panel-entry.md | 8 + wasm-port/runtime/ui/ini-panel/app.js | 30 +++- .../runtime/ui/ini-panel/session-workflow.js | 57 ++++++ wasm-port/runtime/ui/ini-panel/ui-shell.js | 10 ++ .../ui/node/verify_ini_panel_entry_docs.mjs | 19 ++ .../verify_ini_panel_session_workflow.mjs | 167 ++++++++++++++++++ 8 files changed, 363 insertions(+), 4 deletions(-) diff --git a/PROJECT_COMPLETION_TRACKER.md b/PROJECT_COMPLETION_TRACKER.md index e05139c..79f2288 100644 --- a/PROJECT_COMPLETION_TRACKER.md +++ b/PROJECT_COMPLETION_TRACKER.md @@ -9,7 +9,7 @@ turn-by-turn continuation notes and next-batch execution records. ## Current Status - Active continuation file: `text14.txt` -- Latest completed batch: project release gate wrapper +- Latest completed batch: INI panel session readiness workflow - Latest relevant commit: use `git log -1 --oneline` after each committed batch - Working tree at tracker creation: clean - Required policy: LinuxCNC remains the only CNC semantic source @@ -44,7 +44,7 @@ The project is complete for the current scope when all of the following are true | Native sim configs baseline | Stable | Last recorded Layer 2: `total 159`, `pass 151`, `expected_fail 8`, `unexpected_fail 0`. | | OPFS/session persistence | Stable for current scope | Browser smoke passes, SDK re-exports OPFS/session helpers including `readMachineSessionReadiness()`, and `docs/opfs-session-persistence.md` defines the project-level release gate. | | SDK/API surface | Stable for current scope | SDK re-exports core, OPFS/session readiness/load helpers, sim-config staging, and INI panel shell/workflow overview helpers with a Node surface smoke. | -| Browser/UI workflow | Stable for current scope | Workflow overview embedding mount DOM closure is complete and documented for external shells. | +| Browser/UI workflow | Stable for current scope | Workflow overview embedding mount DOM closure is complete, and INI panel session workflows expose OPFS/session readiness before loading WASM session state. | | Workflow overview embedding | Stable for current scope | Report/display/render, DOM contract/readiness/renderer, mount result/display/render, mount DOM contract/readiness/renderer/wrapper exist. | | Host/runtime boundary proof | Stable blocked state | Host smoke passes; runtime families remain blocked and `docs/host-runtime-boundary-handoff.md` records host readiness, promotion blockers, dispatch, and evidence gates. | | Documentation/release gate | Stable for current scope | `docs/project-release-handoff.md` links README, panel entry, SDK, OPFS/session, sim-config, host/runtime, source reuse, drift, and tracker acceptance paths. | diff --git a/text14.txt b/text14.txt index 77e062f..db5dcc4 100644 --- a/text14.txt +++ b/text14.txt @@ -1704,3 +1704,75 @@ opfs_session_docs_node_smoke=ok 继续以实质能力推进为主。下一批建议把 `readMachineSessionReadiness()` 接入 INI panel/session workflow 或 external shell handoff view-model,让 UI 在加载 session 前显示结构化 ready/blocked 原因;仍保持只读,不新增控制按钮,不解析 G-code,不扩大 LinuxCNC 语义边界。 + +二十一、2026-06-16 继续执行记录:INI panel session readiness workflow + +本轮继续以功能实质性推进为主,把上一批新增的 `readMachineSessionReadiness()` 接入 INI panel/session +workflow 层。现在 UI/session workflow 和外部 shell 入口可以在加载 machine session 到 WASM 前获取 +结构化 ready/blocked 原因。 + +完成内容: + +- `wasm-port/runtime/ui/ini-panel/session-workflow.js` 新增: + - `createMachineSessionReadinessFieldState()`; + - `machineSessionReadinessLogLines()`; + - `readMachineSessionReadinessWorkflow()`; +- `restoreMachineSessionSnapshotWorkflow()` 支持可选 `readReadiness`; +- restore snapshot workflow 会把 readiness report 合并进: + - `readiness`; + - `fields.sessionReadinessPhase`; + - `fields.sessionReadinessReady`; + - `fields.sessionReadinessMissing`; + - `logLines`; +- restore+load workflow 会在 load session 前保留 readiness log 与字段; +- `wasm-port/runtime/ui/ini-panel/app.js` 接入 `readMachineSessionReadiness()`: + - restore session snapshot 时读取 readiness; + - load session 时先读取 readiness 再加载 WASM session; + - restore+load session 时读取 readiness; + - panel state 中保存 `sessionReadiness`; +- `wasm-port/runtime/ui/ini-panel/ui-shell.js` re-export session readiness workflow helpers; +- `wasm-port/docs/panel-entry.md` 记录 external shell 可用的 session readiness workflow helper; +- `wasm-port/tests/ui/node/verify_ini_panel_session_workflow.mjs` 覆盖 ready/blocked readiness、 + restore readiness、restore+load readiness; +- `wasm-port/tests/ui/node/verify_ini_panel_entry_docs.mjs` 覆盖 ui-shell export 与 docs drift; +- `PROJECT_COMPLETION_TRACKER.md` 同步 latest completed batch 与 Browser/UI workflow 状态; +- 未新增控制按钮; +- 未执行 action-plan; +- 未解析 G-code; +- 未解释 canonical events; +- 未新增 JS CNC 语义; +- 未运行 opt-in runtime probes; +- 未 promotion blocked runtime family; +- 未改变 LinuxCNC interpreter、tool、parameter、planner、kinematics、remap 或 LinuxCNC-owned + runtime semantics。 + +验证已通过: + +```bash +git diff --check +wasm-port/tests/ui/node/verify_ini_panel_session_workflow.sh +wasm-port/tests/ui/node/verify_ini_panel_entry_docs.sh +wasm-port/tests/ui/node/verify_ini_panel_ui_shell.sh +wasm-port/tests/ui/node/verify_ui_node_smokes.sh +SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_ini_panel_browser.sh +``` + +关键输出: + +```text +ini_panel_session_workflow_node_smoke=ok +ini_panel_entry_docs_node_smoke=ok +ini_panel_ui_shell_node_smoke=ok +ui_node_smokes=ok +browser_ini_opfs_smoke=ok +browser_ini_control_page_smoke=ok +browser_ini_launch_smoke=ok +browser_ini_workflow_overview_smoke=ok +browser_ini_shell_integration_workflow_smoke=ok +``` + +下一步工作计划: + +继续做实质能力推进。下一批建议把 session readiness report 纳入 read-only control page status 或 +shell handoff package/display view-model,让外部 shell 不进入 editor 页面也能读取 session +ready/blocked 原因;仍保持只读,不新增控制按钮,不解析 G-code,不扩大 LinuxCNC 语义边界。 diff --git a/wasm-port/docs/panel-entry.md b/wasm-port/docs/panel-entry.md index 96c0276..6f7b419 100644 --- a/wasm-port/docs/panel-entry.md +++ b/wasm-port/docs/panel-entry.md @@ -77,6 +77,9 @@ import { createMachineSessionControlPageController, createMachineSessionReadonlyStatus, createMachineSessionReadonlyStatusApiManifest, + createMachineSessionReadinessFieldState, + machineSessionReadinessLogLines, + readMachineSessionReadinessWorkflow, readMachineSessionReadonlyStatus, loadMachineSessionForControlPageWorkflow, createControlPageSessionLoadState, @@ -127,6 +130,11 @@ outer shell needs one stable read of `stateBundle`, `workflowStatus`, Use `createMachineSessionReadonlyStatusApiManifest()` or `controlPage.readonlyStatusApiManifest` when you only need the API shape and method names. +Use `readMachineSessionReadinessWorkflow()` when an outer shell or panel flow +needs a read-only `ready`/`blocked` readiness report before loading a machine +session into WASM. `createMachineSessionReadinessFieldState()` and +`machineSessionReadinessLogLines()` turn that report into stable fields and +status text without parsing G-code or executing LinuxCNC behavior. Use `createIniPanelShellControlPageContract()` or `controlPage.contract` when an outer shell needs a fast contract check for `createController`, `loadSessionState`, `readStatus`, `refresh`, `renderView`, the readonly status diff --git a/wasm-port/runtime/ui/ini-panel/app.js b/wasm-port/runtime/ui/ini-panel/app.js index 559bdfc..062b547 100644 --- a/wasm-port/runtime/ui/ini-panel/app.js +++ b/wasm-port/runtime/ui/ini-panel/app.js @@ -18,6 +18,9 @@ import { import { loadMachineSessionFromOpfs, } from "../../opfs/linuxcnc-machine-session-bridge.js"; +import { + readMachineSessionReadiness, +} from "../../opfs/machine-session-readiness.js"; import { loadMachineSessionSnapshot, saveMachineSessionSnapshot, @@ -37,6 +40,7 @@ import { } from "./run-workflow.js"; import { loadMachineSessionIntoWasmWorkflow, + readMachineSessionReadinessWorkflow, restoreMachineSessionSnapshotWorkflow, saveMachineSessionSnapshotWorkflow, } from "./session-workflow.js"; @@ -486,6 +490,14 @@ async function loadMachineSessionIntoWasm() { return loadedSession; } +function readCurrentMachineSessionReadiness() { + return readMachineSessionReadiness(MACHINE_ID, { + sessionId: UI_SESSION.snapshotId, + snapshotFilename: UI_SESSION.snapshotFilename, + gcodeFilename: UI_SESSION.defaultGcodeFilename, + }); +} + async function loadSample() { setLog(`Fetching ${SAMPLE_PATH}`); const response = await fetch(SAMPLE_PATH); @@ -674,6 +686,7 @@ document.getElementById("restore-session-snapshot").addEventListener("click", as snapshotLabel: sessionSnapshotLabel(UI_SESSION), loadMachineSessionSnapshot, loadMachineTextFiles, + readReadiness: readCurrentMachineSessionReadiness, }); editor.value = workflow.editorIniText; setField("sessionIni", workflow.fields.sessionIni); @@ -684,6 +697,7 @@ document.getElementById("restore-session-snapshot").addEventListener("click", as restoredSessionSnapshot = workflow.snapshot; updatePanelMachineSessionState({ sessionSnapshot: workflow.summary, + sessionReadiness: workflow.readiness, sessionLoad: null, selectedProgram: null, fields: workflow.fields, @@ -707,17 +721,27 @@ document.getElementById("restore-session-snapshot").addEventListener("click", as document.getElementById("load-session").addEventListener("click", async () => { try { + const readinessWorkflow = await readMachineSessionReadinessWorkflow({ + readReadiness: readCurrentMachineSessionReadiness, + }); const workflow = await loadMachineSessionIntoWasmWorkflow({ loadSession: () => loadMachineSessionIntoWasm(), }); loadedSession = workflow.loadedSession; updatePanelMachineSessionState({ + sessionReadiness: readinessWorkflow.readiness, sessionLoad: workflow.loadSummary, - fields: workflow.fields, + fields: { + ...readinessWorkflow.fields, + ...workflow.fields, + }, lastAction: "load-session", error: null, }); - setLog(workflow.logLines.join("\n")); + setLog([ + ...readinessWorkflow.logLines, + ...workflow.logLines, + ].join("\n")); } catch (error) { updatePanelMachineSessionState({ lastAction: "load-session", @@ -736,6 +760,7 @@ document.getElementById("restore-load-session").addEventListener("click", async snapshotLabel: sessionSnapshotLabel(UI_SESSION), loadMachineSessionSnapshot, loadMachineTextFiles, + readReadiness: readCurrentMachineSessionReadiness, loadSession: () => loadMachineSessionIntoWasm(), }); editor.value = workflow.editorIniText; @@ -750,6 +775,7 @@ document.getElementById("restore-load-session").addEventListener("click", async } updatePanelMachineSessionState({ sessionSnapshot: workflow.summary, + sessionReadiness: workflow.readiness, sessionLoad: workflow.loadSummary, selectedProgram: null, fields: workflow.fields, diff --git a/wasm-port/runtime/ui/ini-panel/session-workflow.js b/wasm-port/runtime/ui/ini-panel/session-workflow.js index 4c15bc4..1d17e97 100644 --- a/wasm-port/runtime/ui/ini-panel/session-workflow.js +++ b/wasm-port/runtime/ui/ini-panel/session-workflow.js @@ -52,6 +52,47 @@ export function machineSessionLoadWorkflowLogLines(summary) { ]; } +export function createMachineSessionReadinessFieldState(readiness) { + return { + sessionReadinessPhase: readiness.phase, + sessionReadinessReady: readiness.ready ? "ready" : "blocked", + sessionReadinessMissing: readiness.missing.length === 0 ? "none" : readiness.missing.join(", "), + }; +} + +export function machineSessionReadinessLogLines(readiness) { + const checks = Array.isArray(readiness.checks) ? readiness.checks : []; + return [ + `Session readiness: ${readiness.ready ? "ready" : "blocked"}`, + ...checks.map((check) => { + const status = check.ok ? "ok" : `blocked (${check.error})`; + return `${check.name}: ${check.path} -> ${status}`; + }), + ...(readiness.snapshotCheck + ? [ + `snapshot: ${readiness.snapshotCheck.path} -> ${ + readiness.snapshotCheck.ok ? "ok" : `blocked (${readiness.snapshotCheck.error})` + }`, + ] + : []), + ]; +} + +export async function readMachineSessionReadinessWorkflow({ + readiness, + readReadiness, +} = {}) { + const sessionReadiness = readiness ?? await readReadiness?.(); + if (!sessionReadiness) { + throw new Error("A machine session readiness reader is required."); + } + return { + readiness: sessionReadiness, + fields: createMachineSessionReadinessFieldState(sessionReadiness), + logLines: machineSessionReadinessLogLines(sessionReadiness), + }; +} + export async function loadMachineSessionIntoWasmWorkflow({ loadSession }) { if (typeof loadSession !== "function") { throw new Error("A machine session loader is required."); @@ -114,6 +155,7 @@ export async function restoreMachineSessionSnapshotWorkflow({ snapshotLabel, loadMachineSessionSnapshot, loadMachineTextFiles, + readReadiness = null, loadSession = null, }) { const snapshot = await loadMachineSessionSnapshot( @@ -129,21 +171,36 @@ export async function restoreMachineSessionSnapshotWorkflow({ editorIniText: files.ini, summary, fields, + readiness: null, loadSummary: null, loadedSession: null, logLines: sessionSnapshotRestoreLogLines(summary), }; + if (readReadiness) { + const readinessWorkflow = await readMachineSessionReadinessWorkflow({ readReadiness }); + result.readiness = readinessWorkflow.readiness; + result.fields = { + ...result.fields, + ...readinessWorkflow.fields, + }; + result.logLines = [ + ...result.logLines, + ...readinessWorkflow.logLines, + ]; + } if (loadSession) { const loadWorkflow = await loadMachineSessionIntoWasmWorkflow({ loadSession }); result.loadedSession = loadWorkflow.loadedSession; result.loadSummary = loadWorkflow.loadSummary; result.fields = { ...fields, + ...(result.readiness ? createMachineSessionReadinessFieldState(result.readiness) : {}), ...loadWorkflow.fields, sessionGcode: summary.gcodeOpfsPath, }; result.logLines = [ ...sessionSnapshotSummaryLogLines(summary), + ...(result.readiness ? machineSessionReadinessLogLines(result.readiness) : []), ...loadWorkflow.logLines, `G-code: ${summary.gcodeOpfsPath ?? "-"}`, ]; diff --git a/wasm-port/runtime/ui/ini-panel/ui-shell.js b/wasm-port/runtime/ui/ini-panel/ui-shell.js index b233665..62f861f 100644 --- a/wasm-port/runtime/ui/ini-panel/ui-shell.js +++ b/wasm-port/runtime/ui/ini-panel/ui-shell.js @@ -18,6 +18,11 @@ import { createControlPageSessionLoadState, loadMachineSessionForControlPageWorkflow, } from "./control-page-session-workflow.js"; +import { + createMachineSessionReadinessFieldState, + machineSessionReadinessLogLines, + readMachineSessionReadinessWorkflow, +} from "./session-workflow.js"; import { createMachineSessionReadonlyStatus, createMachineSessionReadonlyStatusApiManifest, @@ -32,6 +37,11 @@ export { createControlPageSessionLoadState, loadMachineSessionForControlPageWorkflow, } from "./control-page-session-workflow.js"; +export { + createMachineSessionReadinessFieldState, + machineSessionReadinessLogLines, + readMachineSessionReadinessWorkflow, +} from "./session-workflow.js"; export { createMachineSessionReadonlyStatus, createMachineSessionReadonlyStatusApiManifest, diff --git a/wasm-port/tests/ui/node/verify_ini_panel_entry_docs.mjs b/wasm-port/tests/ui/node/verify_ini_panel_entry_docs.mjs index c7b6c96..b6e3d15 100644 --- a/wasm-port/tests/ui/node/verify_ini_panel_entry_docs.mjs +++ b/wasm-port/tests/ui/node/verify_ini_panel_entry_docs.mjs @@ -66,6 +66,9 @@ import { createIniPanelShellViewModel, createMachineSessionReadonlyStatus, createMachineSessionReadonlyStatusApiManifest, + createMachineSessionReadinessFieldState, + machineSessionReadinessLogLines, + readMachineSessionReadinessWorkflow, loadMachineSessionForControlPageWorkflow, readMachineSessionReadonlyStatus, refreshMachineSessionControlPage, @@ -96,6 +99,10 @@ const sessionWorkflowText = readFileSync( resolve(root, "runtime/ui/ini-panel/control-page-session-workflow.js"), "utf8", ); +const iniPanelSessionWorkflowText = readFileSync( + resolve(root, "runtime/ui/ini-panel/session-workflow.js"), + "utf8", +); const requiredShellExports = [ "INI_PANEL_ENTRIES", @@ -168,6 +175,9 @@ const requiredShellExports = [ "createMachineSessionControlPageController", "createMachineSessionReadonlyStatus", "createMachineSessionReadonlyStatusApiManifest", + "createMachineSessionReadinessFieldState", + "machineSessionReadinessLogLines", + "readMachineSessionReadinessWorkflow", "loadMachineSessionForControlPageWorkflow", "readMachineSessionReadonlyStatus", "refreshMachineSessionControlPage", @@ -196,6 +206,15 @@ for (const exportName of [ assert.match(docText, new RegExp(`\\b${exportName}\\b`)); } +for (const exportName of [ + "createMachineSessionReadinessFieldState", + "machineSessionReadinessLogLines", + "readMachineSessionReadinessWorkflow", +]) { + assert.match(iniPanelSessionWorkflowText, new RegExp(`\\bexport (?:async )?function ${exportName}\\b`)); + assert.match(docText, new RegExp(`\\b${exportName}\\b`)); +} + const requiredPages = [ ["Launch", "runtime/ui/ini-panel/launch.html"], ["Edit and run", "runtime/ui/ini-panel/index.html"], diff --git a/wasm-port/tests/ui/node/verify_ini_panel_session_workflow.mjs b/wasm-port/tests/ui/node/verify_ini_panel_session_workflow.mjs index 2617da8..2f42924 100644 --- a/wasm-port/tests/ui/node/verify_ini_panel_session_workflow.mjs +++ b/wasm-port/tests/ui/node/verify_ini_panel_session_workflow.mjs @@ -1,9 +1,12 @@ import assert from "node:assert/strict"; import { + createMachineSessionReadinessFieldState, createMachineSessionLoadFieldState, loadMachineSessionIntoWasmWorkflow, machineSessionLoadWorkflowLogLines, + machineSessionReadinessLogLines, + readMachineSessionReadinessWorkflow, restoreMachineSessionSnapshotWorkflow, saveMachineSessionSnapshotWorkflow, } from "../../../runtime/ui/ini-panel/session-workflow.js"; @@ -63,6 +66,101 @@ await assert.rejects( /machine session loader/, ); +const readySessionReadiness = { + ready: true, + phase: "ready", + missing: [], + checks: [ + { + name: "ini", + path: "linuxcnc/machines/xyzab-tdr/machine.ini", + ok: true, + error: null, + }, + { + name: "parameters", + path: "linuxcnc/machines/xyzab-tdr/linuxcnc.var", + ok: true, + error: null, + }, + { + name: "toolTable", + path: "linuxcnc/machines/xyzab-tdr/tool.tbl", + ok: true, + error: null, + }, + ], + snapshotCheck: { + name: "snapshot", + path: "linuxcnc/sessions/ui-machine-session/ui-machine-session.json", + ok: true, + error: null, + }, +}; + +const readinessWorkflowCalls = []; +const readinessWorkflow = await readMachineSessionReadinessWorkflow({ + readReadiness: async () => { + readinessWorkflowCalls.push(["readReadiness"]); + return readySessionReadiness; + }, +}); +assert.deepEqual(readinessWorkflowCalls, [["readReadiness"]]); +assert.equal(readinessWorkflow.readiness, readySessionReadiness); +assert.deepEqual(createMachineSessionReadinessFieldState(readySessionReadiness), { + sessionReadinessPhase: "ready", + sessionReadinessReady: "ready", + sessionReadinessMissing: "none", +}); +assert.deepEqual(readinessWorkflow.fields, { + sessionReadinessPhase: "ready", + sessionReadinessReady: "ready", + sessionReadinessMissing: "none", +}); +assert.deepEqual(machineSessionReadinessLogLines(readySessionReadiness), [ + "Session readiness: ready", + "ini: linuxcnc/machines/xyzab-tdr/machine.ini -> ok", + "parameters: linuxcnc/machines/xyzab-tdr/linuxcnc.var -> ok", + "toolTable: linuxcnc/machines/xyzab-tdr/tool.tbl -> ok", + "snapshot: linuxcnc/sessions/ui-machine-session/ui-machine-session.json -> ok", +]); +assert.deepEqual(readinessWorkflow.logLines, machineSessionReadinessLogLines(readySessionReadiness)); +await assert.rejects( + () => readMachineSessionReadinessWorkflow({}), + /machine session readiness reader/, +); + +const blockedSessionReadiness = { + ready: false, + phase: "blocked", + missing: ["parameters", "toolTable"], + checks: [ + { + name: "parameters", + path: "linuxcnc/machines/missing/linuxcnc.var", + ok: false, + error: "missing file", + }, + { + name: "toolTable", + path: "linuxcnc/machines/missing/tool.tbl", + ok: false, + error: "missing file", + }, + ], + snapshotCheck: null, +}; +assert.deepEqual(createMachineSessionReadinessFieldState(blockedSessionReadiness), { + sessionReadinessPhase: "blocked", + sessionReadinessReady: "blocked", + sessionReadinessMissing: "parameters, toolTable", +}); +assert.deepEqual(machineSessionReadinessLogLines(blockedSessionReadiness), [ + "Session readiness: blocked", + "parameters: linuxcnc/machines/missing/linuxcnc.var -> blocked (missing file)", + "toolTable: linuxcnc/machines/missing/tool.tbl -> blocked (missing file)", +]); + const calls = []; const saveWorkflow = await saveMachineSessionSnapshotWorkflow({ machineId: "xyzab-tdr", @@ -224,6 +322,75 @@ assert.deepEqual(restoreWorkflow.logLines, [ "G-code: linuxcnc/gcode/ui-session.ngc", ]); +const restoreReadinessCalls = []; +const restoreReadinessWorkflow = await restoreMachineSessionSnapshotWorkflow({ + machineId: "xyzab-tdr", + snapshotId: "ui-machine-session", + snapshotFilename: "ui-machine-session.json", + snapshotLabel: "ui-machine-session/ui-machine-session.json", + loadMachineSessionSnapshot: async (snapshotId, machineId, options) => { + restoreReadinessCalls.push(["loadMachineSessionSnapshot", snapshotId, machineId, options]); + return { + sessionId: snapshotId, + metadata: { + workflow: "save-session-snapshot", + snapshotLabel: "ui-machine-session/ui-machine-session.json", + defaultGcodeOpfsPath: "linuxcnc/gcode/ui-session.ngc", + }, + payload: { + files: { + ini: "linuxcnc/machines/xyzab-tdr/machine.ini", + parameters: "linuxcnc/machines/xyzab-tdr/linuxcnc.var", + toolTable: "linuxcnc/machines/xyzab-tdr/tool.tbl", + gcode: "linuxcnc/gcode/ui-session.ngc", + }, + }, + }; + }, + loadMachineTextFiles: async (machineId) => { + restoreReadinessCalls.push(["loadMachineTextFiles", machineId]); + return { + ini: "[EMC]\nMACHINE = xyzab-tdr\n", + }; + }, + readReadiness: async () => { + restoreReadinessCalls.push(["readReadiness"]); + return readySessionReadiness; + }, +}); + +assert.deepEqual(restoreReadinessCalls, [ + [ + "loadMachineSessionSnapshot", + "ui-machine-session", + "xyzab-tdr", + { filename: "ui-machine-session.json" }, + ], + ["loadMachineTextFiles", "xyzab-tdr"], + ["readReadiness"], +]); +assert.equal(restoreReadinessWorkflow.readiness, readySessionReadiness); +assert.deepEqual(restoreReadinessWorkflow.fields, { + sessionIni: "linuxcnc/machines/xyzab-tdr/machine.ini", + sessionParameters: "linuxcnc/machines/xyzab-tdr/linuxcnc.var", + sessionToolTable: "linuxcnc/machines/xyzab-tdr/tool.tbl", + sessionGcode: "linuxcnc/gcode/ui-session.ngc", + sessionSnapshot: "ui-machine-session/ui-machine-session.json", + sessionReadinessPhase: "ready", + sessionReadinessReady: "ready", + sessionReadinessMissing: "none", +}); +assert.deepEqual(restoreReadinessWorkflow.logLines, [ + "Snapshot: ui-machine-session/ui-machine-session.json", + "Workflow: save-session-snapshot", + "Default G-code: linuxcnc/gcode/ui-session.ngc", + "INI: linuxcnc/machines/xyzab-tdr/machine.ini", + "Parameter file: linuxcnc/machines/xyzab-tdr/linuxcnc.var", + "Tool table file: linuxcnc/machines/xyzab-tdr/tool.tbl", + "G-code: linuxcnc/gcode/ui-session.ngc", + ...machineSessionReadinessLogLines(readySessionReadiness), +]); + const restoreLoadCalls = []; const restoreLoadWorkflow = await restoreMachineSessionSnapshotWorkflow({ machineId: "xyzab-tdr",