Add EveTui plugin fallback projections
This commit is contained in:
parent
88068c35ae
commit
e1c635d033
12 changed files with 319 additions and 49 deletions
|
|
@ -393,8 +393,8 @@ Recently cut:
|
|||
`runtimePluginProjectionCoverage[]` records. Runtime-owner smokes assert
|
||||
Unity UI Toolkit support for `sai.vn`, `norn.graph`, and `tex.math`, Unity
|
||||
scene support for the same three plugin capabilities, and Electron shell
|
||||
support for the same sidecar plugin projection shells without importing
|
||||
plugin semantics.
|
||||
and TUI support for the same sidecar plugin projection shells without
|
||||
importing plugin semantics.
|
||||
- Provider/runtime/plugin projection coverage is now exported as
|
||||
`providerRuntimePluginProjectionCoverage[]`. The runtime-owner smoke proves
|
||||
the Sai VN provider surface lowers fully in web, lowers in Unity UI Toolkit
|
||||
|
|
@ -404,7 +404,7 @@ Recently cut:
|
|||
projection.
|
||||
- Runtime/plugin projection gaps are now exported as
|
||||
`runtimePluginProjectionGaps[]`. The runtime-owner smoke asserts remaining
|
||||
device-edge and TUI plugin gaps as typed records, so missing Sai, Norn, or TeX
|
||||
device-edge plugin gaps as typed records, so missing Sai, Norn, or TeX
|
||||
projection support is owned by the runtime split target and does not imply
|
||||
those plugin semantics should move into Eve core or Aetheria product code.
|
||||
- Split target blockers are now exported as `splitTargetBlockers[]` and as
|
||||
|
|
@ -501,23 +501,25 @@ Recently cut:
|
|||
- EveTui now has a pending split target and handoff at
|
||||
`runtimes/incubating/eve-tui/evetui-split-handoff.json`. It claims the
|
||||
advertised `tui` world-surface lowering target as a lossy terminal-grid
|
||||
command surface. The handoff draws the line between the provider-agnostic
|
||||
terminal/grid lowerer and provider-owned TUI surfaces, and the split-target
|
||||
consumer smoke keeps runtime graduation and transcript/cell-grid capture
|
||||
visible as blockers.
|
||||
command surface and carries compact Sai, Norn, and TeX sidecar plugin
|
||||
fallback shells. The handoff draws the line between the provider-agnostic
|
||||
terminal/grid lowerer, plugin-owned semantics, and provider-owned TUI
|
||||
surfaces, while the split-target consumer smoke keeps runtime graduation and
|
||||
transcript/cell-grid capture ownership visible as blockers.
|
||||
- EveTui now has a direct split handoff smoke at
|
||||
`scripts/run-evetui-split-handoff-smoke.ps1`, a pending runtime capability
|
||||
manifest at `runtimes/incubating/eve-tui/eve-runtime-capability.json`, and a
|
||||
lifecycle smoke at `scripts/run-evetui-lifecycle-smoke.ps1`. The manifest
|
||||
declares provider advertisement consumption, command transport, terminal-grid
|
||||
summary, terminal-grid lowering, and the `tui` world/editor lowering claim;
|
||||
it now carries an executable terminal capture request contract through
|
||||
summary, terminal-grid lowering, sidecar plugin fallback projection, and the
|
||||
`tui` world/editor lowering claim; it now carries an executable terminal
|
||||
capture request contract through
|
||||
`tools/evetui/evetui-capture-contract.mjs` and
|
||||
`scripts/run-evetui-capture-contract-smoke.ps1`, plus a deterministic
|
||||
`gamecult.eve.tui_grid.v1` JSON capture artifact through
|
||||
`tools/evetui/evetui-capture-artifact.mjs` and
|
||||
`scripts/run-evetui-capture-smoke.ps1`. Plugin projection, terminal package
|
||||
release, and owner-repo production of the capture path remain pending.
|
||||
`scripts/run-evetui-capture-smoke.ps1`. Terminal package release and
|
||||
owner-repo production of the capture path remain pending.
|
||||
- EveTui release lifecycle now carries a structured pending release request
|
||||
contract. The runtime capability manifest reads version truth from
|
||||
`runtimes/incubating/eve-tui/package.json`, names the
|
||||
|
|
@ -866,11 +868,11 @@ Recently cut:
|
|||
- The parity harness now emits an `EveConformance`-shaped export under
|
||||
`artifacts/conformance/latest`, with a top-level index and per-pack JSON
|
||||
files for core, plugin, provider, and runtime consumers.
|
||||
- Unity and Electron plugin projection capability gaps are now explicitly
|
||||
demoted. UI Toolkit, Unity scene, and Electron runtimes own generic projection
|
||||
and command requests, while Sai, Norn, and TeX semantics remain sidecar-plugin
|
||||
responsibilities. Runtimes only add projection shells for capabilities a
|
||||
plugin advertises through Eve.
|
||||
- Unity, Electron, and TUI plugin projection capability gaps are now explicitly
|
||||
demoted. UI Toolkit, Unity scene, Electron, and compact TUI runtimes own
|
||||
generic projection and command requests, while Sai, Norn, and TeX semantics
|
||||
remain sidecar-plugin responsibilities. Runtimes only add projection shells or
|
||||
lossy terminal fallbacks for capabilities a plugin advertises through Eve.
|
||||
- Flutter and Unity now have runtime command-transport smoke evidence in the
|
||||
parity report. Flutter emits `gamecult.eve.command.v1` intents from lowered
|
||||
controls, and Unity command requests now carry the same command schema.
|
||||
|
|
|
|||
|
|
@ -18,23 +18,41 @@
|
|||
"commandTransport",
|
||||
"terminalGridSummary",
|
||||
"terminalGridLowering",
|
||||
"embeddedDocuments"
|
||||
"embeddedDocuments",
|
||||
"pluginProjection"
|
||||
],
|
||||
"supportedPlugins": [],
|
||||
"unsupportedPlugins": [
|
||||
"supportedPlugins": [
|
||||
{
|
||||
"pluginId": "sai.vn",
|
||||
"reason": "TUI provider-shell skeleton exists, but no terminal adapter exists for Sai sidecar-advertised VN projection in this runtime."
|
||||
"capabilities": [
|
||||
"vn.stage",
|
||||
"story.choose",
|
||||
"story.continue",
|
||||
"story.jump"
|
||||
],
|
||||
"projectionAdapter": "EveTuiShell.buildPluginProjection",
|
||||
"lossiness": "terminal-summary"
|
||||
},
|
||||
{
|
||||
"pluginId": "norn.graph",
|
||||
"reason": "TUI provider-shell skeleton exists, but no terminal fallback exists for Norn sidecar-advertised graph projection in this runtime."
|
||||
"capabilities": [
|
||||
"embed.norn"
|
||||
],
|
||||
"projectionAdapter": "EveTuiShell.buildPluginProjection",
|
||||
"lossiness": "terminal-outline"
|
||||
},
|
||||
{
|
||||
"pluginId": "tex.math",
|
||||
"reason": "TUI provider-shell skeleton exists, but no terminal fallback exists for TeX sidecar-advertised math projection in this runtime."
|
||||
"capabilities": [
|
||||
"embed.tex",
|
||||
"tex.inline",
|
||||
"tex.block"
|
||||
],
|
||||
"projectionAdapter": "EveTuiShell.buildPluginProjection",
|
||||
"lossiness": "source-text"
|
||||
}
|
||||
],
|
||||
"unsupportedPlugins": [],
|
||||
"worldSurfaceLowering": [
|
||||
{
|
||||
"targetId": "tui",
|
||||
|
|
@ -46,6 +64,7 @@
|
|||
"evidencePaths": [
|
||||
"runtimes/incubating/eve-tui/src/eve-tui-shell.mjs",
|
||||
"runtimes/incubating/eve-tui/test/eve-tui-shell.test.mjs",
|
||||
"web/fixtures/sai-vn-surface.json",
|
||||
"web/fixtures/aetheria.provider-advertisement.json"
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,8 @@
|
|||
"currentPaths": [
|
||||
"runtimes/incubating/eve-tui/package.json",
|
||||
"runtimes/incubating/eve-tui/src/eve-tui-shell.mjs",
|
||||
"runtimes/incubating/eve-tui/test/eve-tui-shell.test.mjs"
|
||||
"runtimes/incubating/eve-tui/test/eve-tui-shell.test.mjs",
|
||||
"web/fixtures/sai-vn-surface.json"
|
||||
],
|
||||
"destinationOwner": "EveTui",
|
||||
"replacementProof": "EveTui hosts a provider-agnostic TUI lowerer that consumes provider advertisements and Eve surface documents without importing provider internals."
|
||||
|
|
@ -41,6 +42,18 @@
|
|||
"destinationOwner": "EveTui",
|
||||
"replacementProof": "TUI actions emit gamecult.eve.command.v1 intents through provider-advertised command boundaries and render provider receipts instead of mutating local state."
|
||||
},
|
||||
{
|
||||
"id": "tui-plugin-projection",
|
||||
"stage": "plugin-projection",
|
||||
"currentPaths": [
|
||||
"runtimes/incubating/eve-tui/src/eve-tui-shell.mjs",
|
||||
"runtimes/incubating/eve-tui/test/eve-tui-shell.test.mjs",
|
||||
"runtimes/incubating/eve-tui/eve-runtime-capability.json",
|
||||
"web/fixtures/sai-vn-surface.json"
|
||||
],
|
||||
"destinationOwner": "EveTui",
|
||||
"replacementProof": "EveTui owns lossy terminal fallback shells for Sai, Norn, and TeX sidecar-advertised components; Sai keeps story state, Norn keeps graph layout/state, and EvePlugins keeps TeX rendering semantics."
|
||||
},
|
||||
{
|
||||
"id": "tui-capture-lifecycle",
|
||||
"stage": "capture",
|
||||
|
|
@ -68,12 +81,15 @@
|
|||
"provider internals as TUI runtime authority",
|
||||
"renderer-local product state as provider truth",
|
||||
"terminal-only command routes that bypass gamecult.eve.command.v1",
|
||||
"plugin semantic internals",
|
||||
"Sai story state, VN/Ink semantics, or story command interpretation as TUI runtime authority",
|
||||
"Norn graph layout, graph state, or command semantics as TUI runtime authority",
|
||||
"TeX parsing, typesetting, baseline metrics, or render-cache semantics as TUI runtime authority",
|
||||
"lossy text summaries pretending to be provider state"
|
||||
],
|
||||
"requiredExternalProofs": [
|
||||
"EveTui publishes a runtime capability manifest with terminal/grid capabilities.",
|
||||
"EveTui owns a provider-shell contract skeleton that selects advertised provider surfaces, lowers Eve surface trees, emits gamecult.eve.command.v1 intents, and produces an explicitly lossy terminal grid.",
|
||||
"EveTui projects Sai, Norn, and TeX sidecar plugin fallback shells without importing plugin semantic internals.",
|
||||
"EveTui owns the provider-agnostic terminal grid lowerer outside Eve incubation.",
|
||||
"EveTui consumes at least one non-Aetheria provider advertisement.",
|
||||
"EveTui consumes Aetheria's agent-facing TUI surface through provider advertisements without importing Aetheria internals.",
|
||||
|
|
|
|||
|
|
@ -82,6 +82,7 @@ export class EveTuiShell {
|
|||
width: this.width,
|
||||
lines,
|
||||
embeddedDocumentSlots: collectEmbeddedDocumentSlots(document.root),
|
||||
pluginProjections: collectPluginProjections(document.root),
|
||||
lossiness: "terminal-grid-command-surface; summarizes provider-authored world surface without owning provider state",
|
||||
};
|
||||
}
|
||||
|
|
@ -154,7 +155,11 @@ function buildComponentLines(component, width, depth = 0) {
|
|||
const props = objectValue(source.props);
|
||||
const label = firstString(props.label, props.title, props.text, props.bind, props.command, props.fieldId);
|
||||
const indent = " ".repeat(Math.min(depth, 6));
|
||||
const ownLine = fitLine(`${indent}${terminalElementKind(kind)} ${id}${label ? ` ${label}` : ""}`, width);
|
||||
const pluginProjection = buildPluginProjection(kind, source);
|
||||
const pluginSuffix = pluginProjection
|
||||
? ` [${pluginProjection.pluginId}:${pluginProjection.semanticOwner}]`
|
||||
: "";
|
||||
const ownLine = fitLine(`${indent}${terminalElementKind(kind)} ${id}${label ? ` ${label}` : ""}${pluginSuffix}`, width);
|
||||
const children = Array.isArray(source.children) ? source.children : [];
|
||||
const embeddedDocuments = normalizeEmbeddedDocuments(source.embeddedDocuments);
|
||||
return [
|
||||
|
|
@ -176,6 +181,21 @@ function collectEmbeddedDocumentSlots(component, slots = []) {
|
|||
return slots;
|
||||
}
|
||||
|
||||
function collectPluginProjections(component, projections = []) {
|
||||
const source = objectValue(component);
|
||||
const projection = buildPluginProjection(firstString(source.kind), source);
|
||||
if (projection) {
|
||||
projections.push({
|
||||
ownerId: firstString(source.id),
|
||||
...projection,
|
||||
});
|
||||
}
|
||||
for (const child of Array.isArray(source.children) ? source.children : []) {
|
||||
collectPluginProjections(child, projections);
|
||||
}
|
||||
return projections;
|
||||
}
|
||||
|
||||
function normalizeEmbeddedDocuments(value) {
|
||||
return Array.isArray(value)
|
||||
? value
|
||||
|
|
@ -192,6 +212,9 @@ function normalizeEmbeddedDocuments(value) {
|
|||
|
||||
function terminalElementKind(componentKind) {
|
||||
if (!componentKind) return "empty";
|
||||
if (componentKind === "vn.stage") return "sai-vn";
|
||||
if (componentKind === "embed.norn") return "norn";
|
||||
if (componentKind === "embed.tex") return "tex";
|
||||
if (componentKind.startsWith("control.")) return "command";
|
||||
if (componentKind.startsWith("embed.")) return "plugin";
|
||||
if (componentKind === "surface.slot") return "slot";
|
||||
|
|
@ -201,6 +224,57 @@ function terminalElementKind(componentKind) {
|
|||
return componentKind;
|
||||
}
|
||||
|
||||
function buildPluginProjection(componentKind, component) {
|
||||
const props = objectValue(component.props);
|
||||
if (componentKind === "vn.stage") {
|
||||
return {
|
||||
pluginId: "sai.vn",
|
||||
projectionKind: "sai-vn-terminal-stage-summary",
|
||||
abiSchema: "gamecult.eve.plugin_abi.v1",
|
||||
commandBoundary: "sidecar-advertised-plugin-abi",
|
||||
capabilities: ["vn.stage", "story.choose", "story.continue", "story.jump"],
|
||||
documentId: firstString(props.storyId, component.id),
|
||||
semanticOwner: "Sai",
|
||||
fallbackKind: "terminal-summary",
|
||||
};
|
||||
}
|
||||
|
||||
if (componentKind === "embed.norn") {
|
||||
return {
|
||||
pluginId: "norn.graph",
|
||||
projectionKind: "norn-graph-terminal-outline",
|
||||
abiSchema: "gamecult.eve.plugin_abi.v1",
|
||||
commandBoundary: "sidecar-advertised-plugin-abi",
|
||||
capabilities: ["embed.norn"],
|
||||
documentId: firstString(props.sourceUri, props.documentId, component.id),
|
||||
semanticOwner: "Norn",
|
||||
fallbackKind: "terminal-outline",
|
||||
};
|
||||
}
|
||||
|
||||
if (componentKind === "embed.tex") {
|
||||
return {
|
||||
pluginId: "tex.math",
|
||||
projectionKind: texProjectionKind(props),
|
||||
abiSchema: "gamecult.eve.plugin_abi.v1",
|
||||
commandBoundary: "sidecar-advertised-plugin-abi",
|
||||
capabilities: ["embed.tex", "tex.inline", "tex.block"],
|
||||
documentId: firstString(props.sourceUri, props.source, component.id),
|
||||
semanticOwner: "EvePlugins",
|
||||
fallbackKind: "source-text",
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function texProjectionKind(props) {
|
||||
const display = firstString(props.display, "inline");
|
||||
if (display === "block") return "tex-math-terminal-block-source";
|
||||
if (display === "page") return "tex-math-terminal-page-source";
|
||||
return "tex-math-terminal-inline-source";
|
||||
}
|
||||
|
||||
function fitLine(value, width) {
|
||||
const text = String(value || "");
|
||||
if (text.length <= width) return text;
|
||||
|
|
|
|||
|
|
@ -74,8 +74,21 @@ test("lowers provider surface trees into a terminal grid", () => {
|
|||
assert.ok(grid.lines.every(line => line.length <= 44));
|
||||
assert.ok(grid.lines.some(line => line.includes("world aetheria.daemon.game.gravity")));
|
||||
assert.ok(grid.lines.some(line => line.includes("command aetheria.daemon.game.focus")));
|
||||
assert.ok(grid.lines.some(line => line.includes("plugin aetheria.daemon.game.norn")));
|
||||
assert.ok(grid.lines.some(line => line.includes("norn aetheria.daemon.game.norn")));
|
||||
assert.ok(grid.lines.some(line => line.includes("slot norn.map")));
|
||||
assert.deepEqual(grid.pluginProjections, [
|
||||
{
|
||||
ownerId: "aetheria.daemon.game.norn",
|
||||
pluginId: "norn.graph",
|
||||
projectionKind: "norn-graph-terminal-outline",
|
||||
abiSchema: "gamecult.eve.plugin_abi.v1",
|
||||
commandBoundary: "sidecar-advertised-plugin-abi",
|
||||
capabilities: ["embed.norn"],
|
||||
documentId: "aetheria.daemon.game.norn",
|
||||
semanticOwner: "Norn",
|
||||
fallbackKind: "terminal-outline",
|
||||
},
|
||||
]);
|
||||
assert.deepEqual(grid.embeddedDocumentSlots, [
|
||||
{
|
||||
ownerId: "aetheria.daemon.game.norn",
|
||||
|
|
@ -95,6 +108,36 @@ test("rejects surface documents that do not match the advertised TUI target", ()
|
|||
);
|
||||
});
|
||||
|
||||
test("lowers Sai, Norn, and TeX plugin surfaces into compact terminal fallbacks", () => {
|
||||
const shell = new EveTuiShell({ width: 72 });
|
||||
const saiSurface = JSON.parse(readFileSync(path.join(repoRoot, "web/fixtures/sai-vn-surface.json"), "utf8"));
|
||||
const grid = shell.lowerSurface(saiSurface, saiAdvertisement(), "sai.visual_novel.surface");
|
||||
|
||||
assert.deepEqual(validateSchemaSubset(tuiGridSchema, grid), []);
|
||||
assert.equal(grid.providerId, "gamecult.home.vn");
|
||||
assert.equal(grid.surfaceId, "sai.visual_novel.surface");
|
||||
assert.ok(grid.lines.every(line => line.length <= 72));
|
||||
assert.ok(grid.lines.some(line => line.includes("sai-vn sai.root")));
|
||||
assert.ok(grid.lines.some(line => line.includes("norn sai.graph")));
|
||||
assert.ok(grid.lines.some(line => line.includes("tex sai.tex.log-power")));
|
||||
|
||||
const byPlugin = new Map(grid.pluginProjections.map(projection => [projection.pluginId, projection]));
|
||||
assert.equal(byPlugin.get("sai.vn").semanticOwner, "Sai");
|
||||
assert.equal(byPlugin.get("sai.vn").projectionKind, "sai-vn-terminal-stage-summary");
|
||||
assert.deepEqual(byPlugin.get("sai.vn").capabilities, [
|
||||
"vn.stage",
|
||||
"story.choose",
|
||||
"story.continue",
|
||||
"story.jump",
|
||||
]);
|
||||
assert.equal(byPlugin.get("norn.graph").semanticOwner, "Norn");
|
||||
assert.equal(byPlugin.get("norn.graph").fallbackKind, "terminal-outline");
|
||||
assert.equal(byPlugin.get("tex.math").semanticOwner, "EvePlugins");
|
||||
assert.equal(byPlugin.get("tex.math").projectionKind, "tex-math-terminal-block-source");
|
||||
assert.equal(byPlugin.get("tex.math").fallbackKind, "source-text");
|
||||
assert.equal(byPlugin.get("tex.math").documentId, "\\\\mathrm{votes}(p)=1+\\\\lfloor\\\\log_b(1+p)\\\\rfloor");
|
||||
});
|
||||
|
||||
function advertisement() {
|
||||
return {
|
||||
schema: "gamecult.eve.provider_advertisement.v1",
|
||||
|
|
@ -127,6 +170,27 @@ function advertisement() {
|
|||
};
|
||||
}
|
||||
|
||||
function saiAdvertisement() {
|
||||
return {
|
||||
schema: "gamecult.eve.provider_advertisement.v1",
|
||||
providerId: "gamecult.home.vn",
|
||||
title: "GameCult Compound VN",
|
||||
surfaces: [
|
||||
{
|
||||
surfaceId: "sai.visual_novel.surface",
|
||||
transport: "local-json",
|
||||
url: "web/fixtures/sai-vn-surface.json",
|
||||
worldInteraction: {
|
||||
projectionKind: "provider-authored-world-surface",
|
||||
commandBoundary: "sai.vn.plugin.commands",
|
||||
receiptSchema: "gamecult.eve.command_receipt.v1",
|
||||
ownership: "provider-owns-story-state-plugin-sidecars-own-nested-semantics",
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
function surfaceDocument(surfaceId = "aetheria.daemon.game") {
|
||||
return {
|
||||
type: "surface-state",
|
||||
|
|
|
|||
|
|
@ -81,6 +81,57 @@
|
|||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"pluginProjections": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ownerId",
|
||||
"pluginId",
|
||||
"projectionKind",
|
||||
"semanticOwner",
|
||||
"fallbackKind"
|
||||
],
|
||||
"properties": {
|
||||
"ownerId": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"pluginId": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"projectionKind": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"abiSchema": {
|
||||
"type": "string"
|
||||
},
|
||||
"commandBoundary": {
|
||||
"type": "string"
|
||||
},
|
||||
"capabilities": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"documentId": {
|
||||
"type": "string"
|
||||
},
|
||||
"semanticOwner": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"fallbackKind": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"lossiness": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
|
|
|
|||
|
|
@ -36,13 +36,30 @@ if ($manifest.incubation.splitTarget -ne "EveTui") {
|
|||
throw "Unexpected EveTui split target: $($manifest.incubation.splitTarget)"
|
||||
}
|
||||
|
||||
foreach ($feature in @("providerAdvertisements", "commandTransport", "terminalGridSummary", "terminalGridLowering", "embeddedDocuments")) {
|
||||
foreach ($feature in @("providerAdvertisements", "commandTransport", "terminalGridSummary", "terminalGridLowering", "embeddedDocuments", "pluginProjection")) {
|
||||
if (-not (@($manifest.supportedFeatures) -contains $feature)) {
|
||||
throw "EveTui manifest missing provider-shell feature: $feature"
|
||||
}
|
||||
}
|
||||
if (@($manifest.supportedPlugins).Count -ne 0) {
|
||||
throw "EveTui must not claim plugin projection before terminal projection adapters for sidecar-advertised capabilities exist"
|
||||
|
||||
$expectedPlugins = @{
|
||||
"sai.vn" = @("vn.stage", "story.choose", "story.continue", "story.jump")
|
||||
"norn.graph" = @("embed.norn")
|
||||
"tex.math" = @("embed.tex", "tex.inline", "tex.block")
|
||||
}
|
||||
foreach ($pluginId in $expectedPlugins.Keys) {
|
||||
$supported = @($manifest.supportedPlugins) | Where-Object { $_.pluginId -eq $pluginId } | Select-Object -First 1
|
||||
if (-not $supported) {
|
||||
throw "EveTui manifest missing supported plugin declaration: $pluginId"
|
||||
}
|
||||
foreach ($capability in $expectedPlugins[$pluginId]) {
|
||||
if (-not (@($supported.capabilities) -contains $capability)) {
|
||||
throw "EveTui supported plugin $pluginId missing capability: $capability"
|
||||
}
|
||||
}
|
||||
if ($supported.projectionAdapter -ne "EveTuiShell.buildPluginProjection") {
|
||||
throw "EveTui supported plugin $pluginId has unexpected projection adapter: $($supported.projectionAdapter)"
|
||||
}
|
||||
}
|
||||
|
||||
$worldSurfaceLoweringClaims = @()
|
||||
|
|
@ -69,10 +86,10 @@ foreach ($evidencePath in @($worldSurfaceLoweringClaim.evidencePaths)) {
|
|||
}
|
||||
}
|
||||
|
||||
foreach ($pluginId in @("sai.vn", "norn.graph", "tex.math")) {
|
||||
foreach ($pluginId in $expectedPlugins.Keys) {
|
||||
$unsupported = @($manifest.unsupportedPlugins) | Where-Object { $_.pluginId -eq $pluginId } | Select-Object -First 1
|
||||
if (-not $unsupported) {
|
||||
throw "EveTui manifest missing unsupported plugin declaration: $pluginId"
|
||||
if ($unsupported) {
|
||||
throw "EveTui manifest must not report $pluginId unsupported while terminal fallback projection is declared"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,12 +24,19 @@ if ($manifest.lifecycle.test.status -ne "provider-shell-contract-skeleton") {
|
|||
throw "Unexpected EveTui provider shell status: $($manifest.lifecycle.test.status)"
|
||||
}
|
||||
|
||||
foreach ($feature in @("providerAdvertisements", "commandTransport", "terminalGridSummary", "terminalGridLowering")) {
|
||||
foreach ($feature in @("providerAdvertisements", "commandTransport", "terminalGridSummary", "terminalGridLowering", "pluginProjection")) {
|
||||
if (-not (@($manifest.supportedFeatures) -contains $feature)) {
|
||||
throw "EveTui provider shell missing supported feature: $feature"
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($pluginId in @("sai.vn", "norn.graph", "tex.math")) {
|
||||
$supported = @($manifest.supportedPlugins) | Where-Object { $_.pluginId -eq $pluginId } | Select-Object -First 1
|
||||
if (-not $supported) {
|
||||
throw "EveTui provider shell missing supported plugin projection: $pluginId"
|
||||
}
|
||||
}
|
||||
|
||||
$worldSurfaceLoweringClaims = @()
|
||||
if ($null -ne $manifest.worldSurfaceLowering) {
|
||||
$worldSurfaceLoweringClaims = @($manifest.worldSurfaceLowering)
|
||||
|
|
@ -78,14 +85,14 @@ foreach ($relativePath in $expectedFiles) {
|
|||
}
|
||||
|
||||
$shellSource = Get-Content -LiteralPath (Join-Path $projectRoot "runtimes\incubating\eve-tui\src\eve-tui-shell.mjs") -Raw
|
||||
foreach ($symbol in @("EveTuiShell", "selectSurface", "lowerSurface", "normalizeSurfaceDocument", "buildComponentLines", "terminalElementKind", "createCommandIntent", "renderSummary", "gamecult.eve.tui_grid.v1", "commandBoundary", "receiptSchema")) {
|
||||
foreach ($symbol in @("EveTuiShell", "selectSurface", "lowerSurface", "normalizeSurfaceDocument", "buildComponentLines", "buildPluginProjection", "collectPluginProjections", "terminalElementKind", "sai.vn", "norn.graph", "tex.math", "sidecar-advertised-plugin-abi", "createCommandIntent", "renderSummary", "gamecult.eve.tui_grid.v1", "commandBoundary", "receiptSchema")) {
|
||||
if (-not $shellSource.Contains($symbol)) {
|
||||
throw "EveTui provider shell source missing symbol: $symbol"
|
||||
}
|
||||
}
|
||||
|
||||
$testSource = Get-Content -LiteralPath (Join-Path $projectRoot "runtimes\incubating\eve-tui\test\eve-tui-shell.test.mjs") -Raw
|
||||
foreach ($symbol in @("selects advertised provider surfaces", "command intents carry provider-advertised boundaries", "summary grid is explicitly lossy", "lowers provider surface trees into a terminal grid", "rejects surface documents that do not match the advertised TUI target", "aetheria.daemon.commands")) {
|
||||
foreach ($symbol in @("selects advertised provider surfaces", "command intents carry provider-advertised boundaries", "summary grid is explicitly lossy", "lowers provider surface trees into a terminal grid", "lowers Sai, Norn, and TeX plugin surfaces into compact terminal fallbacks", "pluginProjections", "sai-vn-terminal-stage-summary", "norn-graph-terminal-outline", "tex-math-terminal-block-source", "rejects surface documents that do not match the advertised TUI target", "aetheria.daemon.commands")) {
|
||||
if (-not $testSource.Contains($symbol)) {
|
||||
throw "EveTui provider shell test missing symbol: $symbol"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ $expectedMoveSets = @{
|
|||
"tui-runtime-body" = "runtime-body"
|
||||
"tui-world-surface-lowering" = "world-surface-lowering"
|
||||
"tui-command-transport" = "command"
|
||||
"tui-plugin-projection" = "plugin-projection"
|
||||
"tui-capture-lifecycle" = "capture"
|
||||
}
|
||||
$moveSets = @($handoff.moveSets)
|
||||
|
|
@ -61,7 +62,7 @@ foreach ($id in $expectedMoveSets.Keys) {
|
|||
}
|
||||
$currentPaths = if ($null -eq $moveSet.currentPaths) { @() } else { @($moveSet.currentPaths) }
|
||||
$observedProviderPaths = if ($null -eq $moveSet.observedProviderPaths) { @() } else { @($moveSet.observedProviderPaths) }
|
||||
if ($id -in @("tui-runtime-body", "tui-world-surface-lowering", "tui-command-transport", "tui-capture-lifecycle")) {
|
||||
if ($id -in @("tui-runtime-body", "tui-world-surface-lowering", "tui-command-transport", "tui-plugin-projection", "tui-capture-lifecycle")) {
|
||||
if ($currentPaths.Count -eq 0) {
|
||||
throw "EveTui split handoff move set $id must name provider-shell skeleton paths"
|
||||
}
|
||||
|
|
@ -94,7 +95,9 @@ foreach ($forbiddenImport in @(
|
|||
"provider internals as TUI runtime authority",
|
||||
"renderer-local product state as provider truth",
|
||||
"terminal-only command routes that bypass gamecult.eve.command.v1",
|
||||
"plugin semantic internals",
|
||||
"Sai story state, VN/Ink semantics, or story command interpretation as TUI runtime authority",
|
||||
"Norn graph layout, graph state, or command semantics as TUI runtime authority",
|
||||
"TeX parsing, typesetting, baseline metrics, or render-cache semantics as TUI runtime authority",
|
||||
"lossy text summaries pretending to be provider state"
|
||||
)) {
|
||||
if (-not (@($handoff.forbiddenImports) -contains $forbiddenImport)) {
|
||||
|
|
@ -102,6 +105,17 @@ foreach ($forbiddenImport in @(
|
|||
}
|
||||
}
|
||||
|
||||
$pluginMoveSet = $moveSets | Where-Object { $_.id -eq "tui-plugin-projection" } | Select-Object -First 1
|
||||
foreach ($relativePath in @(
|
||||
"runtimes/incubating/eve-tui/src/eve-tui-shell.mjs",
|
||||
"runtimes/incubating/eve-tui/test/eve-tui-shell.test.mjs",
|
||||
"web/fixtures/sai-vn-surface.json"
|
||||
)) {
|
||||
if (-not (@($pluginMoveSet.currentPaths) -contains $relativePath)) {
|
||||
throw "EveTui plugin projection move set missing current path: $relativePath"
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($proof in @($handoff.requiredExternalProofs)) {
|
||||
if (-not $proof) {
|
||||
throw "EveTui split handoff contains an empty required external proof"
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ node $consumerScript $consumerExport `
|
|||
--expect-runtime-feature tui:terminalGridSummary `
|
||||
--expect-runtime-feature tui:terminalGridLowering `
|
||||
--expect-runtime-feature tui:embeddedDocuments `
|
||||
--expect-runtime-feature tui:pluginProjection `
|
||||
--expect-runtime-feature direct2d:embeddedDocuments `
|
||||
--expect-runtime-world-target web:web-reference `
|
||||
--expect-runtime-world-field web:web-reference:supportLevel:reference-dom-canvas-command-boundary `
|
||||
|
|
@ -99,6 +100,9 @@ node $consumerScript $consumerExport `
|
|||
--expect-runtime-plugin-projection electron-shell:sai.vn:supported:EveElectron `
|
||||
--expect-runtime-plugin-projection electron-shell:norn.graph:supported:EveElectron `
|
||||
--expect-runtime-plugin-projection electron-shell:tex.math:supported:EveElectron `
|
||||
--expect-runtime-plugin-projection tui:sai.vn:supported:EveTui `
|
||||
--expect-runtime-plugin-projection tui:norn.graph:supported:EveTui `
|
||||
--expect-runtime-plugin-projection tui:tex.math:supported:EveTui `
|
||||
--expect-provider-runtime-plugin-projection gamecult.home.vn:sai.visual_novel.surface:web:sai.vn:supported:Eve `
|
||||
--expect-provider-runtime-plugin-projection gamecult.home.vn:sai.visual_novel.surface:web:tex.math:optional-supported:Eve `
|
||||
--expect-provider-runtime-plugin-projection gamecult.home.vn:sai.visual_novel.surface:unity-uitoolkit:sai.vn:supported:EveUnity `
|
||||
|
|
@ -110,11 +114,11 @@ node $consumerScript $consumerExport `
|
|||
--expect-provider-runtime-plugin-projection gamecult.home.vn:sai.visual_novel.surface:electron-shell:sai.vn:supported:EveElectron `
|
||||
--expect-provider-runtime-plugin-projection gamecult.home.vn:sai.visual_novel.surface:electron-shell:norn.graph:optional-supported:EveElectron `
|
||||
--expect-provider-runtime-plugin-projection gamecult.home.vn:sai.visual_novel.surface:electron-shell:tex.math:optional-supported:EveElectron `
|
||||
--expect-provider-runtime-plugin-projection gamecult.home.vn:sai.visual_novel.surface:tui:sai.vn:supported:EveTui `
|
||||
--expect-provider-runtime-plugin-projection gamecult.home.vn:sai.visual_novel.surface:tui:norn.graph:optional-supported:EveTui `
|
||||
--expect-provider-runtime-plugin-projection gamecult.home.vn:sai.visual_novel.surface:tui:tex.math:optional-supported:EveTui `
|
||||
--expect-provider-runtime-plugin-projection gamecult.home.vn:sai.visual_novel.surface:ios-uikit:sai.vn:unsupported-runtime-projection:EveIOS `
|
||||
--expect-provider-runtime-plugin-projection gamecult.home.vn:sai.visual_novel.surface:ios-uikit:norn.graph:optional-unsupported-runtime-projection:EveIOS `
|
||||
--expect-runtime-plugin-gap tui:sai.vn:EveTui `
|
||||
--expect-runtime-plugin-gap tui:norn.graph:EveTui `
|
||||
--expect-runtime-plugin-gap tui:tex.math:EveTui `
|
||||
--expect-runtime-handoff unity-uitoolkit `
|
||||
--expect-runtime-command-schema web:gamecult.eve.command.v1 `
|
||||
--expect-runtime-command-schema windows-flutter:gamecult.eve.command.v1 `
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ try {
|
|||
--expect-split-handoff-move EveTui:tui:tui-runtime-body:current:exists:eve-tui-shell.mjs `
|
||||
--expect-split-handoff-move EveTui:tui:tui-world-surface-lowering:current:exists:eve-tui-shell.mjs `
|
||||
--expect-split-handoff-move EveTui:tui:tui-command-transport:current:exists:eve-tui-shell.mjs `
|
||||
--expect-split-handoff-move EveTui:tui:tui-plugin-projection:current:exists:sai-vn-surface.json `
|
||||
--expect-split-handoff-move EveTui:tui:tui-capture-lifecycle:current:exists:evetui-capture-contract.mjs `
|
||||
--expect-split-target-blocker "EveTui:TUI runtime body graduates to EveTui outside provider product code"
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
|
|
|
|||
|
|
@ -830,23 +830,23 @@
|
|||
},
|
||||
"splitHandoffPath": "runtimes/incubating/eve-tui/evetui-split-handoff.json",
|
||||
"requiredFixtures": ["embedded-surface", "aetheria-world"],
|
||||
"pluginFixtures": [],
|
||||
"supportedFeatures": ["providerAdvertisements", "commandTransport", "terminalGridSummary", "terminalGridLowering", "embeddedDocuments"],
|
||||
"supportedPlugins": [],
|
||||
"unsupportedPlugins": [
|
||||
"pluginFixtures": ["sai-vn"],
|
||||
"supportedFeatures": ["providerAdvertisements", "commandTransport", "terminalGridSummary", "terminalGridLowering", "embeddedDocuments", "pluginProjection"],
|
||||
"supportedPlugins": [
|
||||
{
|
||||
"pluginId": "sai.vn",
|
||||
"reason": "TUI provider-shell skeleton exists, but no terminal adapter exists for Sai sidecar-advertised VN projection in this runtime."
|
||||
"capabilities": ["vn.stage", "story.choose", "story.continue", "story.jump"]
|
||||
},
|
||||
{
|
||||
"pluginId": "norn.graph",
|
||||
"reason": "TUI provider-shell skeleton exists, but no terminal fallback exists for Norn sidecar-advertised graph projection in this runtime."
|
||||
"capabilities": ["embed.norn"]
|
||||
},
|
||||
{
|
||||
"pluginId": "tex.math",
|
||||
"reason": "TUI provider-shell skeleton exists, but no terminal fallback exists for TeX sidecar-advertised math projection in this runtime."
|
||||
"capabilities": ["embed.tex", "tex.inline", "tex.block"]
|
||||
}
|
||||
],
|
||||
"unsupportedPlugins": [],
|
||||
"worldSurfaceLowering": [
|
||||
{
|
||||
"targetId": "tui",
|
||||
|
|
@ -858,6 +858,7 @@
|
|||
"evidencePaths": [
|
||||
"runtimes/incubating/eve-tui/src/eve-tui-shell.mjs",
|
||||
"runtimes/incubating/eve-tui/test/eve-tui-shell.test.mjs",
|
||||
"web/fixtures/sai-vn-surface.json",
|
||||
"web/fixtures/aetheria.provider-advertisement.json"
|
||||
]
|
||||
}
|
||||
|
|
@ -884,11 +885,11 @@
|
|||
"expectedSourceSymbols": [
|
||||
{
|
||||
"path": "runtimes/incubating/eve-tui/src/eve-tui-shell.mjs",
|
||||
"contains": ["EveTuiShell", "selectSurface", "lowerSurface", "normalizeSurfaceDocument", "buildComponentLines", "collectEmbeddedDocumentSlots", "normalizeEmbeddedDocuments", "embeddedDocumentSlots", "terminalElementKind", "createCommandIntent", "renderSummary", "gamecult.eve.tui_grid.v1", "commandBoundary", "receiptSchema"]
|
||||
"contains": ["EveTuiShell", "selectSurface", "lowerSurface", "normalizeSurfaceDocument", "buildComponentLines", "buildPluginProjection", "collectPluginProjections", "collectEmbeddedDocumentSlots", "normalizeEmbeddedDocuments", "embeddedDocumentSlots", "pluginProjections", "terminalElementKind", "sai.vn", "norn.graph", "tex.math", "sidecar-advertised-plugin-abi", "createCommandIntent", "renderSummary", "gamecult.eve.tui_grid.v1", "commandBoundary", "receiptSchema"]
|
||||
},
|
||||
{
|
||||
"path": "runtimes/incubating/eve-tui/test/eve-tui-shell.test.mjs",
|
||||
"contains": ["selects advertised provider surfaces", "command intents carry provider-advertised boundaries", "summary grid is explicitly lossy", "lowers provider surface trees into a terminal grid", "embeddedDocumentSlots", "norn.map", "rejects surface documents that do not match the advertised TUI target", "aetheria.daemon.commands"]
|
||||
"contains": ["selects advertised provider surfaces", "command intents carry provider-advertised boundaries", "summary grid is explicitly lossy", "lowers provider surface trees into a terminal grid", "lowers Sai, Norn, and TeX plugin surfaces into compact terminal fallbacks", "embeddedDocumentSlots", "pluginProjections", "norn.map", "sai-vn-terminal-stage-summary", "norn-graph-terminal-outline", "tex-math-terminal-block-source", "rejects surface documents that do not match the advertised TUI target", "aetheria.daemon.commands"]
|
||||
},
|
||||
{
|
||||
"path": "tools/evetui/evetui-capture-contract.mjs",
|
||||
|
|
|
|||
Loading…
Reference in a new issue