推进 INI 面板 shell handoff action plan

This commit is contained in:
2026-06-15 10:00:40 +08:00
parent b1f23e6641
commit 2a7485c14d
10 changed files with 392 additions and 5 deletions

View File

@@ -80,6 +80,7 @@
!launchApi?.getShellSessionHandoffDisplayViewModel ||
!launchApi?.getShellSessionHandoffSnapshot ||
!launchApi?.getShellSessionHandoffRenderState ||
!launchApi?.getShellSessionHandoffActionPlan ||
!launchApi?.getLauncherLinks ||
!launchApi?.getControlPageApiMethods
) {
@@ -119,7 +120,7 @@
);
assertEqual(
launchApiManifest.methods.join(","),
"isSupportedLaunchApiManifest,getLaunchApiSchema,getLaunchApiManifest,getShellIntegrationSchema,getShellIntegrationManifest,getShellIntegrationReadiness,getShellSessionHandoffSummarySchema,getShellSessionHandoffSummary,isSupportedShellSessionHandoffSummary,getShellSessionHandoffCompatibilityReport,getShellSessionHandoffDisplayViewModel,getShellSessionHandoffSnapshot,getShellSessionHandoffRenderState,getLauncherLinks,getControlPageApiMethods",
"isSupportedLaunchApiManifest,getLaunchApiSchema,getLaunchApiManifest,getShellIntegrationSchema,getShellIntegrationManifest,getShellIntegrationReadiness,getShellSessionHandoffSummarySchema,getShellSessionHandoffSummary,isSupportedShellSessionHandoffSummary,getShellSessionHandoffCompatibilityReport,getShellSessionHandoffDisplayViewModel,getShellSessionHandoffSnapshot,getShellSessionHandoffRenderState,getShellSessionHandoffActionPlan,getLauncherLinks,getControlPageApiMethods",
"launch API manifest methods",
);
const shellIntegrationSchema = launchApi.getShellIntegrationSchema();
@@ -131,6 +132,7 @@
const shellSessionHandoffDisplayViewModel = launchApi.getShellSessionHandoffDisplayViewModel();
const shellSessionHandoffSnapshot = launchApi.getShellSessionHandoffSnapshot();
const shellSessionHandoffRenderState = launchApi.getShellSessionHandoffRenderState();
const shellSessionHandoffActionPlan = launchApi.getShellSessionHandoffActionPlan();
assertEqual(
shellIntegrationSchema.manifestVersion,
1,
@@ -241,6 +243,26 @@
"Ready: No blocking reasons",
"shell session handoff render-state status",
);
assertEqual(
shellSessionHandoffActionPlan.planVersion,
1,
"shell session handoff action-plan version",
);
assertEqual(
shellSessionHandoffActionPlan.ready,
true,
"shell session handoff action-plan readiness",
);
assertEqual(
shellSessionHandoffActionPlan.nextSteps.map(({ id }) => id).join(","),
"open-control-page,read-readonly-status",
"shell session handoff action-plan next steps",
);
assertEqual(
shellSessionHandoffActionPlan.requiredMethods.readStatus,
"readControlPageStatus",
"shell session handoff action-plan read method",
);
assertEqual(
JSON.stringify(shellSessionHandoffSnapshot.readiness),
JSON.stringify(shellIntegrationReadiness),
@@ -261,6 +283,11 @@
JSON.stringify(shellSessionHandoffDisplayViewModel.rows),
"shell session handoff render-state rows",
);
assertEqual(
JSON.stringify(shellSessionHandoffActionPlan.displayRows),
JSON.stringify(shellSessionHandoffRenderState.rows),
"shell session handoff action-plan rows",
);
assertEqual(
launchDoc.querySelector("[data-handoff-status]").textContent,
"Ready: No blocking reasons",

View File

@@ -70,7 +70,8 @@ TOOL_TABLE = browser-shell-tool.tbl
!launchApi?.getShellSessionHandoffCompatibilityReport ||
!launchApi?.getShellSessionHandoffDisplayViewModel ||
!launchApi?.getShellSessionHandoffSnapshot ||
!launchApi?.getShellSessionHandoffRenderState
!launchApi?.getShellSessionHandoffRenderState ||
!launchApi?.getShellSessionHandoffActionPlan
) {
throw new Error("launch API namespace did not expose shell integration helpers");
}
@@ -83,6 +84,7 @@ TOOL_TABLE = browser-shell-tool.tbl
const handoffDisplay = launchApi.getShellSessionHandoffDisplayViewModel();
const handoffSnapshot = launchApi.getShellSessionHandoffSnapshot();
const handoffRenderState = launchApi.getShellSessionHandoffRenderState();
const handoffActionPlan = launchApi.getShellSessionHandoffActionPlan();
assertEqual(handoffSummarySchema.summaryVersion, 1, "shell handoff summary schema version");
assertEqual(
launchApi.isSupportedShellSessionHandoffSummary(handoffSummary),
@@ -99,6 +101,13 @@ TOOL_TABLE = browser-shell-tool.tbl
assertEqual(handoffRenderState.ready, true, "shell handoff render-state readiness");
assertEqual(handoffRenderState.statusLine, "Ready: No blocking reasons", "shell handoff render-state status");
assertEqual(handoffRenderState.rows.length, handoffDisplay.rows.length, "shell handoff render-state rows");
assertEqual(handoffActionPlan.ready, true, "shell handoff action-plan readiness");
assertEqual(handoffActionPlan.targetPage.href, "./control-page.html", "shell handoff action-plan target");
assertEqual(
handoffActionPlan.nextSteps.map(({ id }) => id).join(","),
"open-control-page,read-readonly-status",
"shell handoff action-plan next steps",
);
assertEqual(readiness.phase, "ready", "shell integration readiness phase");
assertEqual(readiness.ready, true, "shell integration readiness");
assertEqual(readiness.missing.join(","), "", "shell integration readiness missing checks");

View File

@@ -18,6 +18,7 @@ import {
createIniPanelShellIntegrationReadiness,
createIniPanelShellIntegrationSchema,
createIniPanelShellIntegrationWorkflowPlan,
createIniPanelShellSessionHandoffActionPlan,
createIniPanelShellSessionHandoffCompatibilityReport,
createIniPanelShellSessionHandoffDisplayViewModel,
createIniPanelShellSessionHandoffRenderState,
@@ -72,6 +73,7 @@ const requiredShellExports = [
"createIniPanelShellIntegrationReadiness",
"createIniPanelShellIntegrationSchema",
"createIniPanelShellIntegrationWorkflowPlan",
"createIniPanelShellSessionHandoffActionPlan",
"createIniPanelShellSessionHandoffCompatibilityReport",
"createIniPanelShellSessionHandoffDisplayViewModel",
"createIniPanelShellSessionHandoffRenderState",
@@ -190,6 +192,13 @@ assert.deepEqual(
createIniPanelShellViewModel().shellSessionHandoffRenderState,
createIniPanelShellSessionHandoffRenderState(createIniPanelShellViewModel().shellSessionHandoffSnapshot),
);
assert.deepEqual(
createIniPanelShellViewModel().shellSessionHandoffActionPlan,
createIniPanelShellSessionHandoffActionPlan({
snapshot: createIniPanelShellViewModel().shellSessionHandoffSnapshot,
renderState: createIniPanelShellViewModel().shellSessionHandoffRenderState,
}),
);
assert.equal(isSupportedIniPanelShellIntegrationManifest(createIniPanelShellViewModel().shellIntegrationManifest), true);
assert.deepEqual(createIniPanelShellViewModel().launchApiSchema, createIniPanelLaunchApiSchema());
assert.deepEqual(createIniPanelShellViewModel().launchApiManifest, createIniPanelLaunchApiManifest());
@@ -244,6 +253,7 @@ assert.match(shellText, /\bexport function createIniPanelShellIntegrationSchema\
assert.match(shellText, /\bexport function createIniPanelShellIntegrationManifest\b/);
assert.match(shellText, /\bexport function createIniPanelShellIntegrationReadiness\b/);
assert.match(shellText, /\bexport function createIniPanelShellIntegrationWorkflowPlan\b/);
assert.match(shellText, /\bexport function createIniPanelShellSessionHandoffActionPlan\b/);
assert.match(shellText, /\bexport function createIniPanelShellSessionHandoffCompatibilityReport\b/);
assert.match(shellText, /\bexport function createIniPanelShellSessionHandoffDisplayViewModel\b/);
assert.match(shellText, /\bexport function createIniPanelShellSessionHandoffRenderState\b/);
@@ -272,6 +282,7 @@ assert.match(launchText, /\bgetShellSessionHandoffCompatibilityReport\b/);
assert.match(launchText, /\bgetShellSessionHandoffDisplayViewModel\b/);
assert.match(launchText, /\bgetShellSessionHandoffSnapshot\b/);
assert.match(launchText, /\bgetShellSessionHandoffRenderState\b/);
assert.match(launchText, /\bgetShellSessionHandoffActionPlan\b/);
assert.match(launchText, /\bdata-handoff-shell\b/);
assert.match(launchText, /\bdata-handoff-status\b/);
assert.match(launchText, /\bdata-handoff-rows\b/);
@@ -293,6 +304,7 @@ assert.match(docText, /\bcreateIniPanelShellIntegrationManifest\b/);
assert.match(docText, /\bcreateIniPanelShellIntegrationReadiness\b/);
assert.match(docText, /\bcreateIniPanelShellIntegrationSchema\b/);
assert.match(docText, /\bcreateIniPanelShellIntegrationWorkflowPlan\b/);
assert.match(docText, /\bcreateIniPanelShellSessionHandoffActionPlan\b/);
assert.match(docText, /\bcreateIniPanelShellSessionHandoffCompatibilityReport\b/);
assert.match(docText, /\bcreateIniPanelShellSessionHandoffDisplayViewModel\b/);
assert.match(docText, /\bcreateIniPanelShellSessionHandoffRenderState\b/);
@@ -316,6 +328,7 @@ assert.match(docText, /\blinuxCncIniPanelLaunchApi\.getShellSessionHandoffCompat
assert.match(docText, /\blinuxCncIniPanelLaunchApi\.getShellSessionHandoffDisplayViewModel\b/);
assert.match(docText, /\blinuxCncIniPanelLaunchApi\.getShellSessionHandoffSnapshot\b/);
assert.match(docText, /\blinuxCncIniPanelLaunchApi\.getShellSessionHandoffRenderState\b/);
assert.match(docText, /\blinuxCncIniPanelLaunchApi\.getShellSessionHandoffActionPlan\b/);
assert.match(docText, /\bdata-handoff-shell\b/);
assert.match(docText, /\bdata-handoff-status\b/);
assert.match(docText, /\bdata-handoff-rows\b/);
@@ -329,6 +342,7 @@ assert.match(shellIntegrationWorkflowSmokeText, /\bgetShellSessionHandoffCompati
assert.match(shellIntegrationWorkflowSmokeText, /\bgetShellSessionHandoffDisplayViewModel\b/);
assert.match(shellIntegrationWorkflowSmokeText, /\bgetShellSessionHandoffSnapshot\b/);
assert.match(shellIntegrationWorkflowSmokeText, /\bgetShellSessionHandoffRenderState\b/);
assert.match(shellIntegrationWorkflowSmokeText, /\bgetShellSessionHandoffActionPlan\b/);
assert.match(shellIntegrationWorkflowSmokeText, /\bhandoffSummary\.handoffMethods\.readStatus\b/);
assert.match(shellIntegrationWorkflowSmokeText, /\breadControlPageStatus\b/);
assert.match(shellIntegrationWorkflowSmokeText, /\bbrowser_ini_shell_integration_workflow_smoke=ok\b/);

View File

@@ -53,6 +53,7 @@ assert.deepEqual(manifest, {
"getShellSessionHandoffDisplayViewModel",
"getShellSessionHandoffSnapshot",
"getShellSessionHandoffRenderState",
"getShellSessionHandoffActionPlan",
"getLauncherLinks",
"getControlPageApiMethods",
],
@@ -160,6 +161,7 @@ assert.match(launchText, /\bgetShellSessionHandoffCompatibilityReport\b/);
assert.match(launchText, /\bgetShellSessionHandoffDisplayViewModel\b/);
assert.match(launchText, /\bgetShellSessionHandoffSnapshot\b/);
assert.match(launchText, /\bgetShellSessionHandoffRenderState\b/);
assert.match(launchText, /\bgetShellSessionHandoffActionPlan\b/);
assert.match(launchText, /\blinuxCncIniPanelLaunchApi\b/);
console.log("ini_panel_launch_api_manifest_node_smoke=ok");

View File

@@ -14,6 +14,7 @@ import {
createIniPanelShellIntegrationReadiness,
createIniPanelShellIntegrationSchema,
createIniPanelShellIntegrationWorkflowPlan,
createIniPanelShellSessionHandoffActionPlan,
createIniPanelShellSessionHandoffCompatibilityReport,
createIniPanelShellSessionHandoffDisplayViewModel,
createIniPanelShellSessionHandoffRenderState,
@@ -46,6 +47,10 @@ const handoffSnapshot = createIniPanelShellSessionHandoffSnapshot({
displayViewModel: handoffDisplayViewModel,
});
const handoffRenderState = createIniPanelShellSessionHandoffRenderState(handoffSnapshot);
const handoffActionPlan = createIniPanelShellSessionHandoffActionPlan({
snapshot: handoffSnapshot,
renderState: handoffRenderState,
});
assert.deepEqual(schema, {
apiName: "ini-panel-shell-integration",
@@ -101,7 +106,7 @@ assert.deepEqual(readiness, {
counts: {
pages: 2,
launcherLinks: 2,
launchMethods: 15,
launchMethods: 16,
controlPageMethods: 11,
persistenceCapabilities: 3,
},
@@ -163,7 +168,7 @@ assert.deepEqual(handoffSummary, {
counts: {
pages: 2,
launcherLinks: 2,
launchMethods: 15,
launchMethods: 16,
controlPageMethods: 11,
persistenceCapabilities: 3,
},
@@ -327,8 +332,44 @@ assert.deepEqual(handoffRenderState, {
handoffReady: "true",
},
});
assert.deepEqual(handoffActionPlan, {
apiName: "ini-panel-shell-session-handoff-action-plan",
planVersion: 1,
phase: "ready",
ready: true,
statusLine: "Ready: No blocking reasons",
targetPage: {
entryId: "control-view",
href: "./control-page.html",
},
requiredMethods: {
loadSessionState: "loadControlPageSessionState",
readStatus: "readControlPageStatus",
},
blockingReasons: [],
displayRows: handoffRenderState.rows,
nextSteps: [
{
id: "open-control-page",
label: "Open control page target",
targetPage: {
entryId: "control-view",
href: "./control-page.html",
},
},
{
id: "read-readonly-status",
label: "Read readonly status",
methods: {
loadSessionState: "loadControlPageSessionState",
readStatus: "readControlPageStatus",
},
},
],
});
assert.equal(createIniPanelShellSessionHandoffSnapshot().displayViewModel.rows.length, 5);
assert.equal(createIniPanelShellSessionHandoffRenderState().statusLine, "Ready: No blocking reasons");
assert.equal(createIniPanelShellSessionHandoffActionPlan().nextSteps.length, 2);
assert.deepEqual(
createIniPanelShellSessionHandoffDisplayViewModel(
createIniPanelShellSessionHandoffCompatibilityReport({ ...handoffSummary, summaryVersion: 2 }),
@@ -415,6 +456,60 @@ assert.deepEqual(
},
},
);
assert.deepEqual(
createIniPanelShellSessionHandoffActionPlan({
snapshot: createIniPanelShellSessionHandoffSnapshot({
summary: {
...handoffSummary,
summaryVersion: 2,
},
compatibilityReport: createIniPanelShellSessionHandoffCompatibilityReport({
...handoffSummary,
summaryVersion: 2,
}),
}),
renderState: createIniPanelShellSessionHandoffRenderState(createIniPanelShellSessionHandoffSnapshot({
compatibilityReport: createIniPanelShellSessionHandoffCompatibilityReport({
...handoffSummary,
summaryVersion: 2,
}),
})),
}).nextSteps,
[
{
id: "resolve-blockers",
label: "Resolve handoff blockers",
blockingReasons: [],
displayRows: [
{
id: "summary-supported",
label: "Summary schema",
value: "blocked",
},
{
id: "handoff-ready",
label: "Handoff readiness",
value: "blocked",
},
{
id: "missing-fields",
label: "Missing fields",
value: "none",
},
{
id: "mismatch-fields",
label: "Mismatched fields",
value: "summaryVersion",
},
{
id: "blocking-reasons",
label: "Blocking reasons",
value: "none",
},
],
},
],
);
const blockedManifest = {
...createIniPanelShellIntegrationManifest(),
compatibility: {
@@ -436,7 +531,7 @@ assert.deepEqual(createIniPanelShellIntegrationReadiness(blockedManifest), {
counts: {
pages: 2,
launcherLinks: 2,
launchMethods: 15,
launchMethods: 16,
controlPageMethods: 11,
persistenceCapabilities: 3,
},
@@ -481,6 +576,23 @@ assert.equal(
})).compatible,
false,
);
assert.deepEqual(
createIniPanelShellSessionHandoffActionPlan({
snapshot: createIniPanelShellSessionHandoffSnapshot({
summary: createIniPanelShellSessionHandoffSummary({
manifest: blockedManifest,
readiness: createIniPanelShellIntegrationReadiness(blockedManifest),
workflowPlan: blockedWorkflowPlan,
}),
compatibilityReport: createIniPanelShellSessionHandoffCompatibilityReport(createIniPanelShellSessionHandoffSummary({
manifest: blockedManifest,
readiness: createIniPanelShellIntegrationReadiness(blockedManifest),
workflowPlan: blockedWorkflowPlan,
})),
}),
}).blockingReasons,
["launchCompatibility"],
);
const missingTargetPlan = createIniPanelShellIntegrationWorkflowPlan({
manifest,
controlEntryId: "missing-entry",
@@ -579,6 +691,7 @@ assert.match(shellText, /\bexport function createIniPanelShellIntegrationSchema\
assert.match(shellText, /\bexport function createIniPanelShellIntegrationManifest\b/);
assert.match(shellText, /\bexport function createIniPanelShellIntegrationReadiness\b/);
assert.match(shellText, /\bexport function createIniPanelShellIntegrationWorkflowPlan\b/);
assert.match(shellText, /\bexport function createIniPanelShellSessionHandoffActionPlan\b/);
assert.match(shellText, /\bexport function createIniPanelShellSessionHandoffCompatibilityReport\b/);
assert.match(shellText, /\bexport function createIniPanelShellSessionHandoffDisplayViewModel\b/);
assert.match(shellText, /\bexport function createIniPanelShellSessionHandoffRenderState\b/);
@@ -593,6 +706,7 @@ assert.match(launchText, /\bgetShellIntegrationReadiness\b/);
assert.match(docText, /\bcreateIniPanelShellIntegrationManifest\b/);
assert.match(docText, /\bcreateIniPanelShellIntegrationReadiness\b/);
assert.match(docText, /\bcreateIniPanelShellIntegrationWorkflowPlan\b/);
assert.match(docText, /\bcreateIniPanelShellSessionHandoffActionPlan\b/);
assert.match(docText, /\bcreateIniPanelShellSessionHandoffCompatibilityReport\b/);
assert.match(docText, /\bcreateIniPanelShellSessionHandoffDisplayViewModel\b/);
assert.match(docText, /\bcreateIniPanelShellSessionHandoffRenderState\b/);

View File

@@ -14,6 +14,7 @@ import {
createIniPanelShellIntegrationReadiness,
createIniPanelShellIntegrationSchema,
createIniPanelShellIntegrationWorkflowPlan,
createIniPanelShellSessionHandoffActionPlan,
createIniPanelShellSessionHandoffCompatibilityReport,
createIniPanelShellSessionHandoffDisplayViewModel,
createIniPanelShellSessionHandoffRenderState,
@@ -73,6 +74,7 @@ assert.equal(typeof createIniPanelShellIntegrationManifest, "function");
assert.equal(typeof createIniPanelShellIntegrationReadiness, "function");
assert.equal(typeof createIniPanelShellIntegrationSchema, "function");
assert.equal(typeof createIniPanelShellIntegrationWorkflowPlan, "function");
assert.equal(typeof createIniPanelShellSessionHandoffActionPlan, "function");
assert.equal(typeof createIniPanelShellSessionHandoffCompatibilityReport, "function");
assert.equal(typeof createIniPanelShellSessionHandoffDisplayViewModel, "function");
assert.equal(typeof createIniPanelShellSessionHandoffRenderState, "function");
@@ -167,6 +169,13 @@ assert.deepEqual(
shellViewModel.shellSessionHandoffRenderState,
createIniPanelShellSessionHandoffRenderState(shellViewModel.shellSessionHandoffSnapshot),
);
assert.deepEqual(
shellViewModel.shellSessionHandoffActionPlan,
createIniPanelShellSessionHandoffActionPlan({
snapshot: shellViewModel.shellSessionHandoffSnapshot,
renderState: shellViewModel.shellSessionHandoffRenderState,
}),
);
assert.deepEqual(shellViewModel.shellSessionHandoffDisplayViewModel, {
phase: "ready",
title: "Shell handoff compatibility",
@@ -215,6 +224,41 @@ assert.deepEqual(shellViewModel.shellSessionHandoffRenderState, {
handoffReady: "true",
},
});
assert.deepEqual(shellViewModel.shellSessionHandoffActionPlan, {
apiName: "ini-panel-shell-session-handoff-action-plan",
planVersion: 1,
phase: "ready",
ready: true,
statusLine: "Ready: No blocking reasons",
targetPage: {
entryId: "control-view",
href: "./control-page.html",
},
requiredMethods: {
loadSessionState: "loadControlPageSessionState",
readStatus: "readControlPageStatus",
},
blockingReasons: [],
displayRows: shellViewModel.shellSessionHandoffRenderState.rows,
nextSteps: [
{
id: "open-control-page",
label: "Open control page target",
targetPage: {
entryId: "control-view",
href: "./control-page.html",
},
},
{
id: "read-readonly-status",
label: "Read readonly status",
methods: {
loadSessionState: "loadControlPageSessionState",
readStatus: "readControlPageStatus",
},
},
],
});
assert.equal(
isSupportedIniPanelShellIntegrationManifest(shellViewModel.shellIntegrationManifest),
true,
@@ -260,6 +304,7 @@ assert.equal(
);
assert.equal(shellViewModel.createShellSessionHandoffSnapshot, createIniPanelShellSessionHandoffSnapshot);
assert.equal(shellViewModel.createShellSessionHandoffRenderState, createIniPanelShellSessionHandoffRenderState);
assert.equal(shellViewModel.createShellSessionHandoffActionPlan, createIniPanelShellSessionHandoffActionPlan);
assert.deepEqual(shellViewModel.controlPage.contract, createIniPanelShellControlPageContract());
assert.equal(shellViewModel.controlPage.isSupportedBrowserApiManifest, isSupportedIniPanelControlPageApiManifest);
assert.equal(shellViewModel.controlPage.loadSessionState, loadMachineSessionForControlPageWorkflow);