/** * The `execute-action` wire contract. * * `execute-action` is the channel a rendered artifact uses to reach an * integration, and it used to accept arbitrary code — the same surface as * `execute`. That was wider than anything the shell could produce: artifact code * is purely declarative `tools.*`, and the shell's proxy serializes every call * into exactly one shape. * * Wider than necessary is also wider than safe. A hostile or confused iframe * could post arbitrary source down the app channel even though no affordance in * the shell ever writes any. So the server parses `execute-action` against the * one grammar the proxy emits: * * return await tools.<ident>("<role>")?(.<ident>)*(<JSON>) * * One awaited tool call, one JSON-literal argument, nothing else — no * statements, no loops, no composition. `execute` (the model-facing codemode * tool) is untouched; this constraint is only for the app-originated channel. * * The leading identifier is an INTEGRATION, not a connection: artifact paths * carry no tier and no connection name (see `artifact-bindings.ts`). The * optional string call right after it is the integration ROLE, which is how an * artifact using two accounts of one integration says which it means. Both are * resolved to a full address server-side, against the bindings stored on the * artifact row — so what arrives here is never an address the iframe chose. * * The producing half is `toolCallCode` in * `@executor-js/mcp-apps-shell/shell/proxy`, and `tool-call-grammar.pin.test.ts` * in that package pins the two together so neither can drift. */ import { Option, Schema } from "effect"; const TOOL_CALL_CODE = /^return await tools\.([A-Za-z_$][\w$]*)(?:\((("(?:[^"\\]|\\.)*"))\))?((?:\.[A-Za-z_$][\w$]*)*)\((.*)\);?$/s; /** The proxy's argument is always `JSON.stringify` output, so anything that * does not decode is, by construction, not something the proxy emitted. */const decodeArgs = Schema.decodeUnknownOption(Schema.fromJsonString(Schema.Unknown));const decodeRole = Schema.decodeUnknownOption(Schema.fromJsonString(Schema.String)); export type ParsedToolCall = { /** The dotted path segments under `tools`, e.g. `["github", "issues", "create"]`. * The head is an integration slug (or a system-tool root); it is never a * tier or a connection name. */ readonly path: readonly string[]; /** The integration role, when the call was tagged with one. Absent means the * artifact uses a single account of that integration, whose role is the * integration slug itself. */ readonly role?: string; /** The single call argument, already JSON-decoded. */ readonly args: unknown;}; /** The message handed back to the iframe when its code is not a tool call. */export const TOOL_CALL_CONTRACT_MESSAGE = [ "execute-action accepts a single tool call, not arbitrary code.", 'The only accepted form is `return await tools.<integration>("<role>")?.<path>(<json>)` —', "exactly what the shell's `tools.*` proxy emits.", "Interactive UI reaches integrations declaratively:", "`tools.<integration>.<tool>.queryOptions(...)` / `.infiniteQueryOptions(...)` for reads,", "`.mutationOptions(...)` for writes.",].join(" "); /** * `null` when `code` is not the proxy's emission, otherwise the call it * describes. Callers only need the null check; the parsed value is returned * because it is free here and useful to log. */export const parseToolCallCode = (code: string): ParsedToolCall | null => { const match = TOOL_CALL_CODE.exec(code.trim()); if (!match) return null; const [, root, serializedRole, , dottedRest, serializedArgs] = match; if (root === undefined || dottedRest === undefined || serializedArgs === undefined) return null; const args = decodeArgs(serializedArgs); if (Option.isNone(args)) return null; const rest = dottedRest.length > 0 ? dottedRest.slice(1).split(".") : []; const path = [root, ...rest]; if (serializedRole === undefined) return { path, args: args.value }; // The role is a JSON string literal for the same reason the args are a JSON // literal: it decodes or it was not the proxy's emission. const role = decodeRole(serializedRole); if (Option.isNone(role) || role.value.length === 0) return null; return { path, role: role.value, args: args.value };}; const TOOL_PATH_SEGMENT = /^[A-Za-z_$][\w$]*$/; /** * Build the codemode call for a RESOLVED address — the full * `tools.<integration>.<tier>.<connection>.<tool>` path, after bindings have * been applied. * * The app channel never executes the string the iframe sent. It parses that * string into a path, rewrites the path through the artifact's bindings, and * re-emits it here. So this is the only code `execute-action` ever runs, and it * is built from segments the server itself chose. * * Deliberately not shared with the shell's `toolCallCode`: that one produces the * unresolved short form for the wire, this one produces the resolved address for * the engine, and they sit on opposite sides of the trust boundary. The shell * package depends on this one, never the reverse. */export const formatToolCallCode = (path: readonly string[], args: unknown): string => { for (const segment of path) { if (!TOOL_PATH_SEGMENT.test(segment)) { // oxlint-disable-next-line executor/no-try-catch-or-throw, executor/no-error-constructor -- boundary: unreachable by construction (every segment came from a parsed path or a stored binding); a defect here must not become a malformed emission throw new Error("Invalid resolved tool path."); } } return `return await tools.${path.join(".")}(${JSON.stringify(args ?? {})})`;};
/**
* The `execute-action` wire contract.
*
* `execute-action` is the channel a rendered artifact uses to reach an
* integration, and it used to accept arbitrary code — the same surface as
* `execute`. That was wider than anything the shell could produce: artifact code
* is purely declarative `tools.*`, and the shell's proxy serializes every call
* into exactly one shape.
*
* Wider than necessary is also wider than safe. A hostile or confused iframe
* could post arbitrary source down the app channel even though no affordance in
* the shell ever writes any. So the server parses `execute-action` against the
* one grammar the proxy emits:
*
* return await tools.<ident>("<role>")?(.<ident>)*(<JSON>)
*
* One awaited tool call, one JSON-literal argument, nothing else — no
* statements, no loops, no composition. `execute` (the model-facing codemode
* tool) is untouched; this constraint is only for the app-originated channel.
*
* The leading identifier is an INTEGRATION, not a connection: artifact paths
* carry no tier and no connection name (see `artifact-bindings.ts`). The
* optional string call right after it is the integration ROLE, which is how an
* artifact using two accounts of one integration says which it means. Both are
* resolved to a full address server-side, against the bindings stored on the
* artifact row — so what arrives here is never an address the iframe chose.
*
* The producing half is `toolCallCode` in
* `@executor-js/mcp-apps-shell/shell/proxy`, and `tool-call-grammar.pin.test.ts`
* in that package pins the two together so neither can drift.
*/
import { Option, Schema } from "effect";
const TOOL_CALL_CODE =
/^return await tools\.([A-Za-z_$][\w$]*)(?:\((("(?:[^"\\]|\\.)*"))\))?((?:\.[A-Za-z_$][\w$]*)*)\((.*)\);?$/s;
/** The proxy's argument is always `JSON.stringify` output, so anything that
* does not decode is, by construction, not something the proxy emitted. */
const decodeArgs = Schema.decodeUnknownOption(Schema.fromJsonString(Schema.Unknown));
const decodeRole = Schema.decodeUnknownOption(Schema.fromJsonString(Schema.String));
export type ParsedToolCall = {
/** The dotted path segments under `tools`, e.g. `["github", "issues", "create"]`.
* The head is an integration slug (or a system-tool root); it is never a
* tier or a connection name. */
readonly path: readonly string[];
/** The integration role, when the call was tagged with one. Absent means the
* artifact uses a single account of that integration, whose role is the
* integration slug itself. */
readonly role?: string;
/** The single call argument, already JSON-decoded. */
readonly args: unknown;
};
/** The message handed back to the iframe when its code is not a tool call. */
export const TOOL_CALL_CONTRACT_MESSAGE = [
"execute-action accepts a single tool call, not arbitrary code.",
'The only accepted form is `return await tools.<integration>("<role>")?.<path>(<json>)` —',
"exactly what the shell's `tools.*` proxy emits.",
"Interactive UI reaches integrations declaratively:",
"`tools.<integration>.<tool>.queryOptions(...)` / `.infiniteQueryOptions(...)` for reads,",
"`.mutationOptions(...)` for writes.",
].join(" ");
/**
* `null` when `code` is not the proxy's emission, otherwise the call it
* describes. Callers only need the null check; the parsed value is returned
* because it is free here and useful to log.
*/
export const parseToolCallCode = (code: string): ParsedToolCall | null => {
const match = TOOL_CALL_CODE.exec(code.trim());
if (!match) return null;
const [, root, serializedRole, , dottedRest, serializedArgs] = match;
if (root === undefined || dottedRest === undefined || serializedArgs === undefined) return null;
const args = decodeArgs(serializedArgs);
if (Option.isNone(args)) return null;
const rest = dottedRest.length > 0 ? dottedRest.slice(1).split(".") : [];
const path = [root, ...rest];
if (serializedRole === undefined) return { path, args: args.value };
// The role is a JSON string literal for the same reason the args are a JSON
// literal: it decodes or it was not the proxy's emission.
const role = decodeRole(serializedRole);
if (Option.isNone(role) || role.value.length === 0) return null;
return { path, role: role.value, args: args.value };
};
const TOOL_PATH_SEGMENT = /^[A-Za-z_$][\w$]*$/;
/**
* Build the codemode call for a RESOLVED address — the full
* `tools.<integration>.<tier>.<connection>.<tool>` path, after bindings have
* been applied.
*
* The app channel never executes the string the iframe sent. It parses that
* string into a path, rewrites the path through the artifact's bindings, and
* re-emits it here. So this is the only code `execute-action` ever runs, and it
* is built from segments the server itself chose.
*
* Deliberately not shared with the shell's `toolCallCode`: that one produces the
* unresolved short form for the wire, this one produces the resolved address for
* the engine, and they sit on opposite sides of the trust boundary. The shell
* package depends on this one, never the reverse.
*/
export const formatToolCallCode = (path: readonly string[], args: unknown): string => {
for (const segment of path) {
if (!TOOL_PATH_SEGMENT.test(segment)) {
// oxlint-disable-next-line executor/no-try-catch-or-throw, executor/no-error-constructor -- boundary: unreachable by construction (every segment came from a parsed path or a stored binding); a defect here must not become a malformed emission
throw new Error("Invalid resolved tool path.");
}
}
return `return await tools.${path.join(".")}(${JSON.stringify(args ?? {})})`;
};