🚚 Name executable document grids <Grid> and <Pane> (#781) - #797
Conversation
`Terminal.Grid` and `<Terminal>` named a whole presentation after the terminal that one kind of pane happens to need. The authored syntax is now `<Grid>` and `<Pane>`, the provider-neutral domain ships as `@executablemd/grid`, and the tmux provider as `@executablemd/grid-tmux`. Core's adapters move to `packages/core/src/grid`.
Public symbols follow one rule: grid orchestration is `Grid*`, authored children and claims are `Pane*`, provider APIs are `GridProvider*`. `TERMINAL_GRIDS_API` becomes `GRIDS_API` under the stable name `Grids`, and `TERMINAL_PROVIDERS_API` becomes `GRID_PROVIDERS_API` under `GridProviders`.
Terminal stays where it names a real capability. `NO_TERMINAL`, `reserveTerminal`, `NativeLauncher`, `PaneTerminal`, `TerminalProcesses`, `TerminalSignal` and `TerminalLost` are unchanged, as are the tmux provider identity, the hidden `terminal-worker` verb, the durable event kind `terminal_grid_layout` and the durable identity `terminal_grid:${path}:layout`. Nothing a journal already holds is invalidated.
No compatibility package, re-export, alias, forwarding barrel or old implementation directory remains, and the generated publication workflow places grid after durable-streams, grid-tmux and core after grid, and CLI after all of them.
| // The launch runs in a scope of its own so that this owner can bring | ||
| // it down deliberately and watch how that goes. A cancelled launch — | ||
| // the reader closing a terminal grid is one — unwinds past every | ||
| // the reader closing a grid is one — unwinds past every |
There was a problem hiding this comment.
Redundant comment — restates what the code does.
| // the reader closing a grid is one — unwinds past every |
| // gets no machine sessions at all, which is the ordinary ACP behaviour. | ||
| sessions?: MachineSessionAssembly, | ||
| // What presents a terminal grid on this host. Deno and the compiled binary | ||
| // What presents a grid on this host. Deno and the compiled binary |
There was a problem hiding this comment.
Redundant comment — restates what the code does.
| // What presents a grid on this host. Deno and the compiled binary |
| export { useNormalizedOutput } from "./src/output/normalize.ts"; | ||
| export { useTerminalOutput } from "./src/output/terminal.ts"; | ||
| // The terminal domain is `@executablemd/terminal`'s, and a caller names it | ||
| // The terminal domain is `@executablemd/grid`'s, and a caller names it |
There was a problem hiding this comment.
Redundant comment — restates what the code does.
| // The terminal domain is `@executablemd/grid`'s, and a caller names it |
| if (segment.name === "Terminal.Grid") { | ||
| // No raise() here, like the branches above: expandTerminalGrid | ||
| if (segment.name === "Grid") { | ||
| // No raise() here, like the branches above: expandGrid |
There was a problem hiding this comment.
Redundant comment — restates what the code does.
| // No raise() here, like the branches above: expandGrid |
| const layout = gridLayout(columns.value, placed); | ||
| // The grid renders nothing into the document: what a pane shows belongs to | ||
| // that pane, and the sibling after `</Terminal.Grid>` renders to the root | ||
| // that pane, and the sibling after `</Grid>` renders to the root |
There was a problem hiding this comment.
Redundant comment — restates what the code does.
| // that pane, and the sibling after `</Grid>` renders to the root |
PR #797: 🚚 Name executable document grids
|
* 📝 Name interactive presentation as Grid and Pane (#781) * 🚚 Rename the interactive presentation domain to Grid and Pane (#781) `Terminal.Grid` and `<Terminal>` named a whole presentation after the terminal that one kind of pane happens to need. The authored syntax is now `<Grid>` and `<Pane>`, the provider-neutral domain ships as `@executablemd/grid`, and the tmux provider as `@executablemd/grid-tmux`. Core's adapters move to `packages/core/src/grid`. Public symbols follow one rule: grid orchestration is `Grid*`, authored children and claims are `Pane*`, provider APIs are `GridProvider*`. `TERMINAL_GRIDS_API` becomes `GRIDS_API` under the stable name `Grids`, and `TERMINAL_PROVIDERS_API` becomes `GRID_PROVIDERS_API` under `GridProviders`. Terminal stays where it names a real capability. `NO_TERMINAL`, `reserveTerminal`, `NativeLauncher`, `PaneTerminal`, `TerminalProcesses`, `TerminalSignal` and `TerminalLost` are unchanged, as are the tmux provider identity, the hidden `terminal-worker` verb, the durable event kind `terminal_grid_layout` and the durable identity `terminal_grid:${path}:layout`. Nothing a journal already holds is invalidated. No compatibility package, re-export, alias, forwarding barrel or old implementation directory remains, and the generated publication workflow places grid after durable-streams, grid-tmux and core after grid, and CLI after all of them.
* 📝 Name interactive presentation as Grid and Pane (#781) * 🚚 Rename the interactive presentation domain to Grid and Pane (#781) `Terminal.Grid` and `<Terminal>` named a whole presentation after the terminal that one kind of pane happens to need. The authored syntax is now `<Grid>` and `<Pane>`, the provider-neutral domain ships as `@executablemd/grid`, and the tmux provider as `@executablemd/grid-tmux`. Core's adapters move to `packages/core/src/grid`. Public symbols follow one rule: grid orchestration is `Grid*`, authored children and claims are `Pane*`, provider APIs are `GridProvider*`. `TERMINAL_GRIDS_API` becomes `GRIDS_API` under the stable name `Grids`, and `TERMINAL_PROVIDERS_API` becomes `GRID_PROVIDERS_API` under `GridProviders`. Terminal stays where it names a real capability. `NO_TERMINAL`, `reserveTerminal`, `NativeLauncher`, `PaneTerminal`, `TerminalProcesses`, `TerminalSignal` and `TerminalLost` are unchanged, as are the tmux provider identity, the hidden `terminal-worker` verb, the durable event kind `terminal_grid_layout` and the durable identity `terminal_grid:${path}:layout`. Nothing a journal already holds is invalidated. No compatibility package, re-export, alias, forwarding barrel or old implementation directory remains, and the generated publication workflow places grid after durable-streams, grid-tmux and core after grid, and CLI after all of them.
Closes #781. Stacked on #771 (
agent/issue-717-terminal-packages) — the #717quest, still unmerged. This PR carries two commits: the settled contract
(
cfe4d0ba, architecture and specifications) and the implementation(
860448b6).Why
Terminal.Gridand<Terminal>named a whole presentation after the terminalthat one kind of pane happens to need. A read-only Agent session view is pane
content without being a terminal, and a second multiplexer or a host-native
composite would have had to adopt terminal-specific vocabulary to implement the
same contract. The stack has not merged or shipped, so none of those names is a
compatibility surface — this is the last moment they are free to change.
What changes
Before:
<Terminal.Grid columns={2}> <Terminal title="Implementor">…</Terminal> <Terminal title="Shell" /> </Terminal.Grid>After:
Schemas, forms, direct-child rules, row-major layout, concurrency, replay,
failure containment, cancellation, leases and teardown are all unchanged.
<Grid>remains anxmd runprovider and is not added to Workflow execution.The packages move with the names:
packages/terminal/@executablemd/terminalpackages/grid/@executablemd/gridpackages/terminal-tmux/@executablemd/terminal-tmuxpackages/grid-tmux/@executablemd/grid-tmuxpackages/core/src/terminalpackages/core/src/gridxmd syntaxnow says "Open several panes in one view" for<Grid>, and<Pane>keeps "Expand Markdown or open a shell in a pane."How it works
One rule per role, applied everywhere:
So
TerminalGridRequest→GridRequest,TerminalPaneClaim→PaneClaim,TerminalProviderUnavailableError→GridProviderUnavailableError,createTerminalAuthority→createGridAuthority,openTerminalGrid→openGrid,TerminalTeardownFailed→GridTeardownFailed. The two contextualdescriptors keep their stable names in the spelling the architecture settled:
TERMINAL_GRIDS_API→GRIDS_API("Grids") andTERMINAL_PROVIDERS_API→GRID_PROVIDERS_API("GridProviders").Review guide
Start with:
packages/grid/tests/package-boundary.test.tsThen review:
packages/core/src/structural.tsandstructural-rules.ts— the authoredgrammar and its diagnostics.
packages/grid/mod.ts,lifecycle.ts,processes.ts,posix.ts,testing.ts— the five public roots.packages/core/src/grid/journal.ts— the durable identity, deliberatelyunchanged.
.github/workflows/publish-packages.yml— regenerated, not edited.Look carefully at:
Terminalinthis diff should describe a PTY, a lease, a signal or a process boundary.
What must stay true
terminal_grid_layoutand the identityterminal_grid:${path}:layoutkeeptheir exact spelling; enforced by
packages/core/src/grid/journal.tsandchecked by the TG17 replay rows in
packages/core/tests/grid.test.ts.tmuxand thehidden
terminal-workerverb are unchanged; checked bypackages/grid-tmux/tests/grid-tmux.test.tsTW12 andPANE_WORKER_COMMANDin TG21q's exact root.
NO_TERMINAL,reserveTerminal,NativeLauncher,PaneTerminal,TerminalProcesses,TerminalSignal,TerminalLost; checked by TG21r, which fails if the rename deleted thecapability instead of renaming the presentation.
forwarding barrel or reserved construct; checked by TG21e, TG21m, TG21n and
TG21o.
How to verify it
TG21oproves onlyGridandPaneare declared and neitherTerminal.GridnorTerminalis reserved, and fails if an alias is restored.TG21pis the discriminator for every absence row above: it plants eachrejected spelling into the exact scanner that must report it, so those rows
cannot pass because the scanner is blind.
TG21qpins all six public roots as exact sets rather than requirednames, so a symbol that reaches a root by being added to it is caught.
TG21rproves the technical terminal exports are still reachable while nofacet brings back a rejected presentation name — without it, deleting the
terminal capability outright would satisfy every other absence row.
TG21mreads the manifests, all three lockfiles and the generated publishworkflow by name, because a source that imports a deleted package fails
loudly while a manifest that still names one fails nothing until a release.
(
grid-structure,syntax-catalog,document-validation,syntax-cli);provider lifecycle and replay (
grid-provider,core/grid); pane-nativerouting (
native-launcher,terminal-processes,agent-session-launch,three
native-launchsuites,grid-native-launch); tmux and host teardown(
grid-tmux,grid-host,session-launch-cli); publication and discovery(
package-boundary, both publish-workflow suites,runtime-exclusions,test-file-discovery,jsr-consumer-documentation).deno task checkexits 0,deno task check:jsrendsSuccess Dry run complete, andpackage-boundary.test.tspasses under Node and Bun as wellas Deno.
Scope
Included
manifest, lockfile, generated workflow and test path that named them.
TG21boundary regression, moved topackages/grid/tests/.evidence — see Risks.
Intentionally unchanged
Terminalpresentation component (site/routes/index.tsx).It is technical UI and outside this contract.
and the
terminal-workercommand spelling.<Grid>is still not available to Workflow execution.core.terminal.pane, which carries aPaneTerminal.Generated or mechanical changes
.github/workflows/publish-packages.ymlcomes fromdeno task gen:publish-workflow. It now orders grid after durable-streams,grid-tmux and core after grid, and cli after all of them.
deno.lock,pnpm-lock.yamlandbun.lockwere regenerated in the orderAGENTS.md prescribes:
deno install --frozen=false,deno task setup,bun install.packages/grid*,packages/core/src/gridandpackages/grid/tests/package-boundary.test.tsis an identifier or pathrename with no intended behavior change.
Risks and limitations
deno task lintfails on this branch, and it already failed on the base.Twenty
local/require-scope-bound-event-registrationerrors sit inpackages/grid/src/posix-launcher.ts, fivegrid-tmuxsources,grid-tmux/tests/grid-tmux.test.tsandcli/src/grid-host.ts. The flaggedlines are byte-identical to
cfe4d0ba, and #757 — which installed that rule —is an ancestor of this base. The #717 stack was written before the rule landed
and was never rebased onto it. Repairing them is Effection listener-lifetime
work on #717 rather than naming, so this PR does not attempt it; it needs a
decision about where that work belongs.
Three further defects already on the base blocked the evidence matrix itself
and are repaired here, conservatively:
reapwas imported fromnative-launcher.ts; it is defined inposix-launcher.ts.syntax-cli.test.tscalledsyntaxCatalog/parseCatalog, which Add read-only XMD information requests toxmd plan#762 renamedto
syntaxSymbols/parseSymbols, andsyntax-catalog.test.tsTG3 assertedcatalog
version1 where every other row in the same file asserts 2.jsr-consumer-documentation.test.tsstaged itsMEMBERSwithout the neutraldomain package, so core's import of it could not resolve for a JSR consumer.
cli.tspassed a third argument to two-parameterresolveAuthorshipStack.The argument is dropped rather than threaded, which preserves today's
behavior:
xmd planinstalls no grid provider. Ifxmd planwas meant topresent grids, that is a separate product decision.
One judgment call inside the rename: the private context key
core.terminal.installationbecamecore.grid.installation. It carries aGridInstallation, is not exported, and is live-only rather than durable.Delivery gates not yet run: the full
deno task test,pnpm test:node,bun run test:bun,deno task build,deno task verify:clean, and theMeasure-test-weights dispatch.
Scope confirmation