Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 94 additions & 19 deletions architecture.md

Large diffs are not rendered by default.

8 changes: 5 additions & 3 deletions packages/cli/src/documents/Plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ props:
returns:
type: string
description: >-
Create an XMD program from a Prompt. `<Plan as="program">Ask for the user's
age.</Plan>` expands its content normally to form the complete Prompt.
as: Required. The exact approved Plan source after teardown and structural admission.
Create an XMD program from a prompt. `<Plan>Ask for the user's age.</Plan>`
expands the approved plan.
as: >-
Optional. It captures the exact approved Plan source, after teardown and
structural admission, without expanding any of it.
context: The complete Prompt, expanded once before authorship.
---

Expand Down
20 changes: 20 additions & 0 deletions packages/cli/src/plan-component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,24 @@ export const PLAN_COMPONENT = "Plan";
*/
export const PLAN_IDENTITY = "<plan>";

/**
* What this host says the Component's return is.
*
* `<Plan>` produces approved XMD program source rather than ordinary text, so a
* site that captures nothing has somewhere for that return to go: canonical
* core expands those exact bytes where the author wrote the element, under the
* identity above. A site that writes `as` binds the same bytes and runs none of
* them.
*
* It travels with the declaration and nowhere else. No frontmatter field names
* it, so a repository `Plan.md`, a workflow bundle member and a registration
* cannot ask for it, and neither can the Plan a run approves.
*/
const PLAN_DISPOSITION = {
kind: "executable-source",
sourceIdentity: PLAN_IDENTITY,
} as const;

/** Which surface reached the Component. Sealed: it is never a public prop. */
export type PlanSurface = "command" | "component";

Expand Down Expand Up @@ -236,6 +254,7 @@ export function* planComponentDeclaration(
// empty rendering rather than on the spelling, which is the same answer for
// a body that rendered to nothing.
forms: ["paired"],
returnDisposition: PLAN_DISPOSITION,
privates: [
planInputs(assembly),
planAuthorship(assembly),
Expand Down Expand Up @@ -270,6 +289,7 @@ export function* planComponentDescription(): Operation<DeclaredMarkdownComponent
source,
digest: sourceDigest(source),
forms: ["paired"],
returnDisposition: PLAN_DISPOSITION,
// The private names travel too, even though none of them is ever described.
// Selection refuses a name a declaration keeps to itself, and it has to
// refuse the same names here as it does in a run — otherwise a repository
Expand Down
8 changes: 8 additions & 0 deletions packages/cli/src/syntax.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,14 @@ function renderReturns(entry: CompleteComponentSyntaxEntry): string[] {
fence("json", stringify(entry.returns)),
];
}
if (entry.returnDisposition?.kind === "executable-source") {
return [
"**Returns:** executable source — written without `as`, it expands where you wrote it, " +
`under the identity ${code(entry.returnDisposition.sourceIdentity)}. Written with ` +
"`as`, it binds that source and expands none of it.",
fence("json", stringify(entry.returns)),
];
}
return [
"**Returns:** a value — it renders nothing, and `as` binds what it returns.",
fence("json", stringify(entry.returns)),
Expand Down
Loading
Loading