esoul-sdk 0.18.0 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/api-reference.md CHANGED
@@ -754,7 +754,7 @@ const PluginConnectionSchema: z.ZodEffects<z.ZodObject<{ key: z.ZodString; kind:
754
754
  The zod schema `plugin.json` must satisfy — the sync and `check_app` refuse a manifest that fails it, with the path.
755
755
 
756
756
  ```ts
757
- const PluginManifestSchema: z.ZodObject<{ manifestVersion: z.ZodLiteral<1>; id: z.ZodString; name: z.ZodString; version: z.ZodString; description: z.ZodString; applicationType: z.ZodString; entry: z.ZodString; icon: z.ZodOptional<z.ZodString>; author: z.ZodOptional<z.ZodObject<{ name: z.ZodString; email: z.ZodOptional<z.ZodString>; url: z.ZodOptional<z.ZodString>; }, "strip", z.ZodTypeAny, { name?: string; email?: string; url?: string; }, { name?: string; email?: string; url?: string; }>>; kickableTasks: z.ZodDefault<z.ZodOptional<z.ZodUnion<[z.ZodArray<z.ZodString, "many">, z.ZodRecord<z.ZodString, z.ZodObject<{ access: z.ZodDefault<z.ZodOptional<z.ZodUnion<[z.ZodEnum<["write", "read", "public", "token"]>, z.ZodArray<z.ZodString, "many">]>>>; requires: z.ZodOptional<z.ZodLiteral<"account">>; }, "strict", z.ZodTypeAny, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>>]>>>; webhooks: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>; ops: z.ZodDefault<z.ZodOptional<z.ZodUnion<[z.ZodArray<z.ZodString, "many">, z.ZodRecord<z.ZodString, z.ZodObject<{ access: z.ZodDefault<z.ZodOptional<z.ZodUnion<[z.ZodEnum<["write", "read", "public", "token"]>, z.ZodArray<z.ZodString, "many">]>>>; requires: z.ZodOptional<z.ZodLiteral<"account">>; }, "strict", z.ZodTypeAny, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>>]>>>; routes: z.ZodDefault<z.ZodOptional<z.ZodUnion<[z.ZodArray<z.ZodString, "many">, z.ZodRecord<z.ZodString, z.ZodObject<{ access: z.ZodDefault<z.ZodOptional<z.ZodUnion<[z.ZodEnum<["write", "read", "public", "token"]>, z.ZodArray<z.ZodString, "many">]>>>; requires: z.ZodOptional<z.ZodLiteral<"account">>; }, "strict", z.ZodTypeAny, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>>]>>>; pollTasks: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodObject<{ task: z.ZodString; everyMinutes: z.ZodNumber; }, "strip", z.ZodTypeAny, { task?: string; everyMinutes?: number; }, { task?: string; everyMinutes?: number; }>, "many">>>; platformApi: z.ZodOptional<z.ZodObject<{ min: z.ZodString; max: z.ZodOptional<z.ZodString>; }, "strip", z.ZodTypeAny, { min?: string; max?: string; }, { min?: string; max?: string; }>>; scopes: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>; roles: z.ZodOptional<z.ZodEffects<z.ZodObject<{ vocabulary: z.ZodArray<z.ZodString, "many">; default: z.ZodDefault<z.ZodOptional<z.ZodObject<{ owner: z.ZodOptional<z.ZodString>; "member-edit": z.ZodOptional<z.ZodString>; "member-readonly": z.ZodOptional<z.ZodString>; visitor: z.ZodOptional<z.ZodString>; anonymous: z.ZodOptional<z.ZodString>; agent: z.ZodOptional<z.ZodString>; }, "strict", z.ZodTypeAny, { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }, { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }>>>; describe: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>; attributes: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodEnum<["string", "int", "boolean"]>>>; custom: z.ZodOptional<z.ZodObject<{ attributes: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; models: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{ where: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; hide: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; update: z.ZodOptional<z.ZodObject<{ fields: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; transitions: z.ZodOptional<z.ZodString>; }, "strict", z.ZodTypeAny, { fields?: string[]; transitions?: string; }, { fields?: string[]; transitions?: string; }>>; }, "strict", z.ZodTypeAny, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>>>; ops: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; }, "strict", z.ZodTypeAny, { ops?: string[]; attributes?: string[]; models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; }, { ops?: string[]; attributes?: string[]; models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; }>>; }, "strict", z.ZodTypeAny, { default?: { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }; custom?: { ops?: string[]; attributes?: string[]; models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; }; vocabulary?: string[]; describe?: Record<string, string>; attributes?: Record<string, "string" | "boolean" | "int">; }, { default?: { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }; custom?: { ops?: string[]; attributes?: string[]; models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; }; vocabulary?: string[]; describe?: Record<string, string>; attributes?: Record<string, "string" | "boolean" | "int">; }>, { default?: { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }; custom?: { ops?: string[]; attributes?: string[]; models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; }; vocabulary?: string[]; describe?: Record<string, string>; attributes?: Record<string, "string" | "boolean" | "int">; }, { default?: { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }; custom?: { ops?: string[]; attributes?: string[]; models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; }; vocabulary?: string[]; describe?: Record<string, string>; attributes?: Record<string, "string" | "boolean" | "int">; }>>; workspaceTools: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>; device: z.ZodOptional<z.ZodEffects<z.ZodObject<{ commands: z.ZodRecord<z.ZodString, z.ZodObject<{ argv: z.ZodArray<z.ZodString, "many">; params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<[z.ZodEnum<["int", "number", "bool", "string"]>, z.ZodObject<{ type: z.ZodEnum<["int", "number"]>; min: z.ZodOptional<z.ZodNumber>; max: z.ZodOptional<z.ZodNumber>; describe: z.ZodOptional<z.ZodString>; }, "strict", z.ZodTypeAny, { type?: "number" | "int"; min?: number; max?: number; describe?: string; }, { type?: "number" | "int"; min?: number; max?: number; describe?: string; }>, z.ZodObject<{ type: z.ZodLiteral<"string">; pattern: z.ZodOptional<z.ZodString>; maxLength: z.ZodOptional<z.ZodNumber>; allowDash: z.ZodOptional<z.ZodBoolean>; describe: z.ZodOptional<z.ZodString>; }, "strict", z.ZodTypeAny, { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; }, { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; }>, z.ZodObject<{ type: z.ZodLiteral<"enum">; values: z.ZodArray<z.ZodString, "many">; describe: z.ZodOptional<z.ZodString>; }, "strict", z.ZodTypeAny, { values?: string[]; type?: "enum"; describe?: string; }, { values?: string[]; type?: "enum"; describe?: string; }>, z.ZodObject<{ type: z.ZodLiteral<"bool">; describe: z.ZodOptional<z.ZodString>; }, "strict", z.ZodTypeAny, { type?: "bool"; describe?: string; }, { type?: "bool"; describe?: string; }>]>>>; cwd: z.ZodOptional<z.ZodString>; env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>; config: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; timeoutSeconds: z.ZodOptional<z.ZodNumber>; onRestart: z.ZodOptional<z.ZodEnum<["report", "rerun"]>>; output: z.ZodOptional<z.ZodObject<{ mode: z.ZodOptional<z.ZodEnum<["live", "batched", "final"]>>; flushMs: z.ZodOptional<z.ZodNumber>; maxChunkKb: z.ZodOptional<z.ZodNumber>; keep: z.ZodOptional<z.ZodEnum<["head", "tail", "both"]>>; maxKb: z.ZodOptional<z.ZodNumber>; }, "strict", z.ZodTypeAny, { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }, { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }>>; result: z.ZodOptional<z.ZodEnum<["text", "json"]>>; describe: z.ZodOptional<z.ZodString>; }, "strict", z.ZodTypeAny, { params?: Record<string, "string" | "number" | "int" | "bool" | { type?: "number" | "int"; min?: number; max?: number; describe?: string; } | { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; } | { values?: string[]; type?: "enum"; describe?: string; } | { type?: "bool"; describe?: string; }>; describe?: string; argv?: string[]; cwd?: string; env?: Record<string, string>; config?: string[]; timeoutSeconds?: number; onRestart?: "report" | "rerun"; output?: { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }; result?: "text" | "json"; }, { params?: Record<string, "string" | "number" | "int" | "bool" | { type?: "number" | "int"; min?: number; max?: number; describe?: string; } | { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; } | { values?: string[]; type?: "enum"; describe?: string; } | { type?: "bool"; describe?: string; }>; describe?: string; argv?: string[]; cwd?: string; env?: Record<string, string>; config?: string[]; timeoutSeconds?: number; onRestart?: "report" | "rerun"; output?: { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }; result?: "text" | "json"; }>>; config: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{ secret: z.ZodOptional<z.ZodBoolean>; required: z.ZodOptional<z.ZodBoolean>; describe: z.ZodOptional<z.ZodString>; }, "strict", z.ZodTypeAny, { required?: boolean; describe?: string; secret?: boolean; }, { required?: boolean; describe?: string; secret?: boolean; }>>>; redact: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; onAppDeleted: z.ZodOptional<z.ZodEnum<["kill", "finish"]>>; }, "strict", z.ZodTypeAny, { commands?: Record<string, { params?: Record<string, "string" | "number" | "int" | "bool" | { type?: "number" | "int"; min?: number; max?: number; describe?: string; } | { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; } | { values?: string[]; type?: "enum"; describe?: string; } | { type?: "bool"; describe?: string; }>; describe?: string; argv?: string[]; cwd?: string; env?: Record<string, string>; config?: string[]; timeoutSeconds?: number; onRestart?: "report" | "rerun"; output?: { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }; result?: "text" | "json"; }>; config?: Record<string, { required?: boolean; describe?: string; secret?: boolean; }>; redact?: string[]; onAppDeleted?: "kill" | "finish"; }, { commands?: Record<string, { params?: Record<string, "string" | "number" | "int" | "bool" | { type?: "number" | "int"; min?: number; max?: number; describe?: string; } | { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; } | { values?: string[]; type?: "enum"; describe?: string; } | { type?: "bool"; describe?: string; }>; describe?: string; argv?: string[]; cwd?: string; env?: Record<string, string>; config?: string[]; timeoutSeconds?: number; onRestart?: "report" | "rerun"; output?: { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }; result?: "text" | "json"; }>; config?: Record<string, { required?: boolean; describe?: string; secret?: boolean; }>; redact?: string[]; onAppDeleted?: "kill" | "finish"; }>, { commands?: Record<string, { params?: Record<string, "string" | "number" | "int" | "bool" | { type?: "number" | "int"; min?: number; max?: number; describe?: string; } | { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; } | { values?: string[]; type?: "enum"; describe?: string; } | { type?: "bool"; describe?: string; }>; describe?: string; argv?: string[]; cwd?: string; env?: Record<string, string>; config?: string[]; timeoutSeconds?: number; onRestart?: "report" | "rerun"; output?: { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }; result?: "text" | "json"; }>; config?: Record<string, { required?: boolean; describe?: string; secret?: boolean; }>; redact?: string[]; onAppDeleted?: "kill" | "finish"; }, { commands?: Record<string, { params?: Record<string, "string" | "number" | "int" | "bool" | { type?: "number" | "int"; min?: number; max?: number; describe?: string; } | { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; } | { values?: string[]; type?: "enum"; describe?: string; } | { type?: "bool"; describe?: string; }>; describe?: string; argv?: string[]; cwd?: string; env?: Record<string, string>; config?: string[]; timeoutSeconds?: number; onRestart?: "report" | "rerun"; output?: { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }; result?: "text" | "json"; }>; config?: Record<string, { required?: boolean; describe?: string; secret?: boolean; }>; redact?: string[]; onAppDeleted?: "kill" | "finish"; }>>; connections: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodEffects<z.ZodObject<{ key: z.ZodString; kind: z.ZodEnum<["oauth2", "apiKey"]>; label: z.ZodString; description: z.ZodOptional<z.ZodString>; authorizeUrl: z.ZodOptional<z.ZodString>; tokenUrl: z.ZodOptional<z.ZodString>; oauthScopes: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; clientIdEnv: z.ZodOptional<z.ZodString>; clientSecretEnv: z.ZodOptional<z.ZodString>; headerNames: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; }, "strict", z.ZodTypeAny, { key?: string; kind?: "oauth2" | "apiKey"; label?: string; description?: string; authorizeUrl?: string; tokenUrl?: string; oauthScopes?: string[]; clientIdEnv?: string; clientSecretEnv?: string; headerNames?: string[]; }, { key?: string; kind?: "oauth2" | "apiKey"; label?: string; description?: string; authorizeUrl?: string; tokenUrl?: string; oauthScopes?: string[]; clientIdEnv?: string; clientSecretEnv?: string; headerNames?: string[]; }>, { key?: string; kind?: "oauth2" | "apiKey"; label?: string; description?: string; authorizeUrl?: string; tokenUrl?: string; oauthScopes?: string[]; clientIdEnv?: string; clientSecretEnv?: string; headerNames?: string[]; }, { key?: string; kind?: "oauth2" | "apiKey"; label?: string; description?: string; authorizeUrl?: string; tokenUrl?: string; oauthScopes?: string[]; clientIdEnv?: string; clientSecretEnv?: string; headerNames?: string[]; }>, "many">>>; fileSources: z.ZodOptional<z.ZodEffects<z.ZodObject<{ workspace: z.ZodOptional<z.ZodEnum<["read", "readwrite"]>>; providers: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>; write: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; }, "strict", z.ZodTypeAny, { write?: string[]; workspace?: "read" | "readwrite"; providers?: string[]; }, { write?: string[]; workspace?: "read" | "readwrite"; providers?: string[]; }>, { write?: string[]; workspace?: "read" | "readwrite"; providers?: string[]; }, { write?: string[]; workspace?: "read" | "readwrite"; providers?: string[]; }>>; fileProviders: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodObject<{ key: z.ZodString; connectionKey: z.ZodString; label: z.ZodString; }, "strict", z.ZodTypeAny, { key?: string; label?: string; connectionKey?: string; }, { key?: string; label?: string; connectionKey?: string; }>, "many">>>; uses: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{ contract: z.ZodString; label: z.ZodOptional<z.ZodString>; optional: z.ZodOptional<z.ZodBoolean>; }, "strict", z.ZodTypeAny, { label?: string; contract?: string; optional?: boolean; }, { label?: string; contract?: string; optional?: boolean; }>>>; provides: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{ tools: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; events: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; models: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; }, "strict", z.ZodTypeAny, { models?: string[]; tools?: string[]; events?: string[]; }, { models?: string[]; tools?: string[]; events?: string[]; }>>>; channel: z.ZodOptional<z.ZodObject<{ topics: z.ZodRecord<z.ZodString, z.ZodObject<{ audience: z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"all">, z.ZodLiteral<"viewer">, z.ZodString]>>; mayAddress: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; description: z.ZodOptional<z.ZodString>; }, "strict", z.ZodTypeAny, { description?: string; audience?: string; mayAddress?: string[]; }, { description?: string; audience?: string; mayAddress?: string[]; }>>; }, "strict", z.ZodTypeAny, { topics?: Record<string, { description?: string; audience?: string; mayAddress?: string[]; }>; }, { topics?: Record<string, { description?: string; audience?: string; mayAddress?: string[]; }>; }>>; db: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{ scope: z.ZodOptional<z.ZodEnum<["instance", "workspace", "user"]>>; owner: z.ZodOptional<z.ZodLiteral<"creator">>; fields: z.ZodRecord<z.ZodString, z.ZodString>; sealed: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; unique: z.ZodOptional<z.ZodArray<z.ZodArray<z.ZodString, "many">, "many">>; indexes: z.ZodOptional<z.ZodArray<z.ZodUnion<[z.ZodArray<z.ZodString, "many">, z.ZodObject<{ fields: z.ZodArray<z.ZodString, "many">; kind: z.ZodOptional<z.ZodEnum<["btree", "contains", "text"]>>; }, "strict", z.ZodTypeAny, { kind?: "text" | "btree" | "contains"; fields?: string[]; }, { kind?: "text" | "btree" | "contains"; fields?: string[]; }>]>, "many">>; rules: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>; }, "strict", z.ZodTypeAny, { owner?: "creator"; fields?: Record<string, string>; scope?: "workspace" | "instance" | "user"; sealed?: string[]; unique?: string[][]; indexes?: (string[] | { kind?: "text" | "btree" | "contains"; fields?: string[]; })[]; rules?: Record<string, unknown>; }, { owner?: "creator"; fields?: Record<string, string>; scope?: "workspace" | "instance" | "user"; sealed?: string[]; unique?: string[][]; indexes?: (string[] | { kind?: "text" | "btree" | "contains"; fields?: string[]; })[]; rules?: Record<string, unknown>; }>>>; }, "strict", z.ZodTypeAny, { roles?: { default?: { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }; custom?: { ops?: string[]; attributes?: string[]; models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; }; vocabulary?: string[]; describe?: Record<string, string>; attributes?: Record<string, "string" | "boolean" | "int">; }; description?: string; manifestVersion?: 1; id?: string; name?: string; version?: string; applicationType?: string; entry?: string; icon?: string; author?: { name?: string; email?: string; url?: string; }; kickableTasks?: string[] | Record<string, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>; webhooks?: string[]; ops?: string[] | Record<string, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>; routes?: string[] | Record<string, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>; pollTasks?: { task?: string; everyMinutes?: number; }[]; platformApi?: { min?: string; max?: string; }; scopes?: string[]; workspaceTools?: string[]; device?: { commands?: Record<string, { params?: Record<string, "string" | "number" | "int" | "bool" | { type?: "number" | "int"; min?: number; max?: number; describe?: string; } | { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; } | { values?: string[]; type?: "enum"; describe?: string; } | { type?: "bool"; describe?: string; }>; describe?: string; argv?: string[]; cwd?: string; env?: Record<string, string>; config?: string[]; timeoutSeconds?: number; onRestart?: "report" | "rerun"; output?: { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }; result?: "text" | "json"; }>; config?: Record<string, { required?: boolean; describe?: string; secret?: boolean; }>; redact?: string[]; onAppDeleted?: "kill" | "finish"; }; connections?: { key?: string; kind?: "oauth2" | "apiKey"; label?: string; description?: string; authorizeUrl?: string; tokenUrl?: string; oauthScopes?: string[]; clientIdEnv?: string; clientSecretEnv?: string; headerNames?: string[]; }[]; fileSources?: { write?: string[]; workspace?: "read" | "readwrite"; providers?: string[]; }; fileProviders?: { key?: string; label?: string; connectionKey?: string; }[]; uses?: Record<string, { label?: string; contract?: string; optional?: boolean; }>; provides?: Record<string, { models?: string[]; tools?: string[]; events?: string[]; }>; channel?: { topics?: Record<string, { description?: string; audience?: string; mayAddress?: string[]; }>; }; db?: Record<string, { owner?: "creator"; fields?: Record<string, string>; scope?: "workspace" | "instance" | "user"; sealed?: string[]; unique?: string[][]; indexes?: (string[] | { kind?: "text" | "btree" | "contains"; fields?: string[]; })[]; rules?: Record<string, unknown>; }>; }, { roles?: { default?: { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }; custom?: { ops?: string[]; attributes?: string[]; models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; }; vocabulary?: string[]; describe?: Record<string, string>; attributes?: Record<string, "string" | "boolean" | "int">; }; description?: string; manifestVersion?: 1; id?: string; name?: string; version?: string; applicationType?: string; entry?: string; icon?: string; author?: { name?: string; email?: string; url?: string; }; kickableTasks?: string[] | Record<string, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>; webhooks?: string[]; ops?: string[] | Record<string, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>; routes?: string[] | Record<string, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>; pollTasks?: { task?: string; everyMinutes?: number; }[]; platformApi?: { min?: string; max?: string; }; scopes?: string[]; workspaceTools?: string[]; device?: { commands?: Record<string, { params?: Record<string, "string" | "number" | "int" | "bool" | { type?: "number" | "int"; min?: number; max?: number; describe?: string; } | { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; } | { values?: string[]; type?: "enum"; describe?: string; } | { type?: "bool"; describe?: string; }>; describe?: string; argv?: string[]; cwd?: string; env?: Record<string, string>; config?: string[]; timeoutSeconds?: number; onRestart?: "report" | "rerun"; output?: { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }; result?: "text" | "json"; }>; config?: Record<string, { required?: boolean; describe?: string; secret?: boolean; }>; redact?: string[]; onAppDeleted?: "kill" | "finish"; }; connections?: { key?: string; kind?: "oauth2" | "apiKey"; label?: string; description?: string; authorizeUrl?: string; tokenUrl?: string; oauthScopes?: string[]; clientIdEnv?: string; clientSecretEnv?: string; headerNames?: string[]; }[]; fileSources?: { write?: string[]; workspace?: "read" | "readwrite"; providers?: string[]; }; fileProviders?: { key?: string; label?: string; connectionKey?: string; }[]; uses?: Record<string, { label?: string; contract?: string; optional?: boolean; }>; provides?: Record<string, { models?: string[]; tools?: string[]; events?: string[]; }>; channel?: { topics?: Record<string, { description?: string; audience?: string; mayAddress?: string[]; }>; }; db?: Record<string, { owner?: "creator"; fields?: Record<string, string>; scope?: "workspace" | "instance" | "user"; sealed?: string[]; unique?: string[][]; indexes?: (string[] | { kind?: "text" | "btree" | "contains"; fields?: string[]; })[]; rules?: Record<string, unknown>; }>; }>
757
+ const PluginManifestSchema: z.ZodObject<{ manifestVersion: z.ZodLiteral<1>; id: z.ZodString; name: z.ZodString; version: z.ZodString; description: z.ZodString; applicationType: z.ZodString; entry: z.ZodString; icon: z.ZodOptional<z.ZodString>; author: z.ZodOptional<z.ZodObject<{ name: z.ZodString; email: z.ZodOptional<z.ZodString>; url: z.ZodOptional<z.ZodString>; }, "strip", z.ZodTypeAny, { name?: string; email?: string; url?: string; }, { name?: string; email?: string; url?: string; }>>; kickableTasks: z.ZodDefault<z.ZodOptional<z.ZodUnion<[z.ZodArray<z.ZodString, "many">, z.ZodRecord<z.ZodString, z.ZodObject<{ access: z.ZodDefault<z.ZodOptional<z.ZodUnion<[z.ZodEnum<["write", "read", "public", "token"]>, z.ZodArray<z.ZodString, "many">]>>>; requires: z.ZodOptional<z.ZodLiteral<"account">>; }, "strict", z.ZodTypeAny, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>>]>>>; webhooks: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>; ops: z.ZodDefault<z.ZodOptional<z.ZodUnion<[z.ZodArray<z.ZodString, "many">, z.ZodRecord<z.ZodString, z.ZodObject<{ access: z.ZodDefault<z.ZodOptional<z.ZodUnion<[z.ZodEnum<["write", "read", "public", "token"]>, z.ZodArray<z.ZodString, "many">]>>>; requires: z.ZodOptional<z.ZodLiteral<"account">>; }, "strict", z.ZodTypeAny, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>>]>>>; routes: z.ZodDefault<z.ZodOptional<z.ZodUnion<[z.ZodArray<z.ZodString, "many">, z.ZodRecord<z.ZodString, z.ZodObject<{ access: z.ZodDefault<z.ZodOptional<z.ZodUnion<[z.ZodEnum<["write", "read", "public", "token"]>, z.ZodArray<z.ZodString, "many">]>>>; requires: z.ZodOptional<z.ZodLiteral<"account">>; }, "strict", z.ZodTypeAny, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>>]>>>; pollTasks: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodObject<{ task: z.ZodString; everyMinutes: z.ZodNumber; }, "strip", z.ZodTypeAny, { task?: string; everyMinutes?: number; }, { task?: string; everyMinutes?: number; }>, "many">>>; platformApi: z.ZodOptional<z.ZodObject<{ min: z.ZodString; max: z.ZodOptional<z.ZodString>; }, "strip", z.ZodTypeAny, { min?: string; max?: string; }, { min?: string; max?: string; }>>; scopes: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>; roles: z.ZodOptional<z.ZodEffects<z.ZodObject<{ vocabulary: z.ZodArray<z.ZodString, "many">; default: z.ZodDefault<z.ZodOptional<z.ZodObject<{ owner: z.ZodOptional<z.ZodString>; "member-edit": z.ZodOptional<z.ZodString>; "member-readonly": z.ZodOptional<z.ZodString>; visitor: z.ZodOptional<z.ZodString>; anonymous: z.ZodOptional<z.ZodString>; agent: z.ZodOptional<z.ZodString>; }, "strict", z.ZodTypeAny, { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }, { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }>>>; describe: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>; attributes: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodEnum<["string", "int", "boolean"]>>>; custom: z.ZodOptional<z.ZodObject<{ attributes: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; models: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{ where: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; hide: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; update: z.ZodOptional<z.ZodObject<{ fields: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; transitions: z.ZodOptional<z.ZodString>; }, "strict", z.ZodTypeAny, { fields?: string[]; transitions?: string; }, { fields?: string[]; transitions?: string; }>>; }, "strict", z.ZodTypeAny, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>>>; ops: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; }, "strict", z.ZodTypeAny, { ops?: string[]; attributes?: string[]; models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; }, { ops?: string[]; attributes?: string[]; models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; }>>; }, "strict", z.ZodTypeAny, { default?: { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }; custom?: { ops?: string[]; attributes?: string[]; models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; }; vocabulary?: string[]; describe?: Record<string, string>; attributes?: Record<string, "string" | "boolean" | "int">; }, { default?: { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }; custom?: { ops?: string[]; attributes?: string[]; models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; }; vocabulary?: string[]; describe?: Record<string, string>; attributes?: Record<string, "string" | "boolean" | "int">; }>, { default?: { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }; custom?: { ops?: string[]; attributes?: string[]; models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; }; vocabulary?: string[]; describe?: Record<string, string>; attributes?: Record<string, "string" | "boolean" | "int">; }, { default?: { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }; custom?: { ops?: string[]; attributes?: string[]; models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; }; vocabulary?: string[]; describe?: Record<string, string>; attributes?: Record<string, "string" | "boolean" | "int">; }>>; workspaceTools: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>; device: z.ZodOptional<z.ZodEffects<z.ZodObject<{ commands: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{ argv: z.ZodArray<z.ZodString, "many">; params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<[z.ZodEnum<["int", "number", "bool", "string"]>, z.ZodObject<{ type: z.ZodEnum<["int", "number"]>; min: z.ZodOptional<z.ZodNumber>; max: z.ZodOptional<z.ZodNumber>; describe: z.ZodOptional<z.ZodString>; }, "strict", z.ZodTypeAny, { type?: "number" | "int"; min?: number; max?: number; describe?: string; }, { type?: "number" | "int"; min?: number; max?: number; describe?: string; }>, z.ZodObject<{ type: z.ZodLiteral<"string">; pattern: z.ZodOptional<z.ZodString>; maxLength: z.ZodOptional<z.ZodNumber>; allowDash: z.ZodOptional<z.ZodBoolean>; describe: z.ZodOptional<z.ZodString>; }, "strict", z.ZodTypeAny, { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; }, { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; }>, z.ZodObject<{ type: z.ZodLiteral<"enum">; values: z.ZodArray<z.ZodString, "many">; describe: z.ZodOptional<z.ZodString>; }, "strict", z.ZodTypeAny, { values?: string[]; type?: "enum"; describe?: string; }, { values?: string[]; type?: "enum"; describe?: string; }>, z.ZodObject<{ type: z.ZodLiteral<"bool">; describe: z.ZodOptional<z.ZodString>; }, "strict", z.ZodTypeAny, { type?: "bool"; describe?: string; }, { type?: "bool"; describe?: string; }>]>>>; cwd: z.ZodOptional<z.ZodString>; env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>; config: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; timeoutSeconds: z.ZodOptional<z.ZodNumber>; onRestart: z.ZodOptional<z.ZodEnum<["report", "rerun"]>>; output: z.ZodOptional<z.ZodObject<{ mode: z.ZodOptional<z.ZodEnum<["live", "batched", "final"]>>; flushMs: z.ZodOptional<z.ZodNumber>; maxChunkKb: z.ZodOptional<z.ZodNumber>; keep: z.ZodOptional<z.ZodEnum<["head", "tail", "both"]>>; maxKb: z.ZodOptional<z.ZodNumber>; }, "strict", z.ZodTypeAny, { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }, { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }>>; result: z.ZodOptional<z.ZodEnum<["text", "json"]>>; describe: z.ZodOptional<z.ZodString>; }, "strict", z.ZodTypeAny, { params?: Record<string, "string" | "number" | "int" | "bool" | { type?: "number" | "int"; min?: number; max?: number; describe?: string; } | { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; } | { values?: string[]; type?: "enum"; describe?: string; } | { type?: "bool"; describe?: string; }>; describe?: string; argv?: string[]; cwd?: string; env?: Record<string, string>; config?: string[]; timeoutSeconds?: number; onRestart?: "report" | "rerun"; output?: { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }; result?: "text" | "json"; }, { params?: Record<string, "string" | "number" | "int" | "bool" | { type?: "number" | "int"; min?: number; max?: number; describe?: string; } | { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; } | { values?: string[]; type?: "enum"; describe?: string; } | { type?: "bool"; describe?: string; }>; describe?: string; argv?: string[]; cwd?: string; env?: Record<string, string>; config?: string[]; timeoutSeconds?: number; onRestart?: "report" | "rerun"; output?: { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }; result?: "text" | "json"; }>>>; program: z.ZodOptional<z.ZodObject<{ main: z.ZodString; resident: z.ZodOptional<z.ZodBoolean>; setup: z.ZodOptional<z.ZodArray<z.ZodObject<{ id: z.ZodString; describe: z.ZodString; run: z.ZodArray<z.ZodString, "many">; inputs: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; timeoutSeconds: z.ZodOptional<z.ZodNumber>; }, "strict", z.ZodTypeAny, { id?: string; describe?: string; timeoutSeconds?: number; run?: string[]; inputs?: string[]; }, { id?: string; describe?: string; timeoutSeconds?: number; run?: string[]; inputs?: string[]; }>, "many">>; selfTest: z.ZodOptional<z.ZodObject<{ run: z.ZodArray<z.ZodString, "many">; timeoutSeconds: z.ZodOptional<z.ZodNumber>; }, "strict", z.ZodTypeAny, { timeoutSeconds?: number; run?: string[]; }, { timeoutSeconds?: number; run?: string[]; }>>; }, "strict", z.ZodTypeAny, { main?: string; resident?: boolean; setup?: { id?: string; describe?: string; timeoutSeconds?: number; run?: string[]; inputs?: string[]; }[]; selfTest?: { timeoutSeconds?: number; run?: string[]; }; }, { main?: string; resident?: boolean; setup?: { id?: string; describe?: string; timeoutSeconds?: number; run?: string[]; inputs?: string[]; }[]; selfTest?: { timeoutSeconds?: number; run?: string[]; }; }>>; config: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{ secret: z.ZodOptional<z.ZodBoolean>; required: z.ZodOptional<z.ZodBoolean>; describe: z.ZodOptional<z.ZodString>; }, "strict", z.ZodTypeAny, { required?: boolean; describe?: string; secret?: boolean; }, { required?: boolean; describe?: string; secret?: boolean; }>>>; redact: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; onAppDeleted: z.ZodOptional<z.ZodEnum<["kill", "finish"]>>; }, "strict", z.ZodTypeAny, { config?: Record<string, { required?: boolean; describe?: string; secret?: boolean; }>; commands?: Record<string, { params?: Record<string, "string" | "number" | "int" | "bool" | { type?: "number" | "int"; min?: number; max?: number; describe?: string; } | { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; } | { values?: string[]; type?: "enum"; describe?: string; } | { type?: "bool"; describe?: string; }>; describe?: string; argv?: string[]; cwd?: string; env?: Record<string, string>; config?: string[]; timeoutSeconds?: number; onRestart?: "report" | "rerun"; output?: { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }; result?: "text" | "json"; }>; program?: { main?: string; resident?: boolean; setup?: { id?: string; describe?: string; timeoutSeconds?: number; run?: string[]; inputs?: string[]; }[]; selfTest?: { timeoutSeconds?: number; run?: string[]; }; }; redact?: string[]; onAppDeleted?: "kill" | "finish"; }, { config?: Record<string, { required?: boolean; describe?: string; secret?: boolean; }>; commands?: Record<string, { params?: Record<string, "string" | "number" | "int" | "bool" | { type?: "number" | "int"; min?: number; max?: number; describe?: string; } | { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; } | { values?: string[]; type?: "enum"; describe?: string; } | { type?: "bool"; describe?: string; }>; describe?: string; argv?: string[]; cwd?: string; env?: Record<string, string>; config?: string[]; timeoutSeconds?: number; onRestart?: "report" | "rerun"; output?: { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }; result?: "text" | "json"; }>; program?: { main?: string; resident?: boolean; setup?: { id?: string; describe?: string; timeoutSeconds?: number; run?: string[]; inputs?: string[]; }[]; selfTest?: { timeoutSeconds?: number; run?: string[]; }; }; redact?: string[]; onAppDeleted?: "kill" | "finish"; }>, { config?: Record<string, { required?: boolean; describe?: string; secret?: boolean; }>; commands?: Record<string, { params?: Record<string, "string" | "number" | "int" | "bool" | { type?: "number" | "int"; min?: number; max?: number; describe?: string; } | { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; } | { values?: string[]; type?: "enum"; describe?: string; } | { type?: "bool"; describe?: string; }>; describe?: string; argv?: string[]; cwd?: string; env?: Record<string, string>; config?: string[]; timeoutSeconds?: number; onRestart?: "report" | "rerun"; output?: { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }; result?: "text" | "json"; }>; program?: { main?: string; resident?: boolean; setup?: { id?: string; describe?: string; timeoutSeconds?: number; run?: string[]; inputs?: string[]; }[]; selfTest?: { timeoutSeconds?: number; run?: string[]; }; }; redact?: string[]; onAppDeleted?: "kill" | "finish"; }, { config?: Record<string, { required?: boolean; describe?: string; secret?: boolean; }>; commands?: Record<string, { params?: Record<string, "string" | "number" | "int" | "bool" | { type?: "number" | "int"; min?: number; max?: number; describe?: string; } | { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; } | { values?: string[]; type?: "enum"; describe?: string; } | { type?: "bool"; describe?: string; }>; describe?: string; argv?: string[]; cwd?: string; env?: Record<string, string>; config?: string[]; timeoutSeconds?: number; onRestart?: "report" | "rerun"; output?: { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }; result?: "text" | "json"; }>; program?: { main?: string; resident?: boolean; setup?: { id?: string; describe?: string; timeoutSeconds?: number; run?: string[]; inputs?: string[]; }[]; selfTest?: { timeoutSeconds?: number; run?: string[]; }; }; redact?: string[]; onAppDeleted?: "kill" | "finish"; }>>; connections: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodEffects<z.ZodObject<{ key: z.ZodString; kind: z.ZodEnum<["oauth2", "apiKey"]>; label: z.ZodString; description: z.ZodOptional<z.ZodString>; authorizeUrl: z.ZodOptional<z.ZodString>; tokenUrl: z.ZodOptional<z.ZodString>; oauthScopes: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; clientIdEnv: z.ZodOptional<z.ZodString>; clientSecretEnv: z.ZodOptional<z.ZodString>; headerNames: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; }, "strict", z.ZodTypeAny, { key?: string; kind?: "oauth2" | "apiKey"; label?: string; description?: string; authorizeUrl?: string; tokenUrl?: string; oauthScopes?: string[]; clientIdEnv?: string; clientSecretEnv?: string; headerNames?: string[]; }, { key?: string; kind?: "oauth2" | "apiKey"; label?: string; description?: string; authorizeUrl?: string; tokenUrl?: string; oauthScopes?: string[]; clientIdEnv?: string; clientSecretEnv?: string; headerNames?: string[]; }>, { key?: string; kind?: "oauth2" | "apiKey"; label?: string; description?: string; authorizeUrl?: string; tokenUrl?: string; oauthScopes?: string[]; clientIdEnv?: string; clientSecretEnv?: string; headerNames?: string[]; }, { key?: string; kind?: "oauth2" | "apiKey"; label?: string; description?: string; authorizeUrl?: string; tokenUrl?: string; oauthScopes?: string[]; clientIdEnv?: string; clientSecretEnv?: string; headerNames?: string[]; }>, "many">>>; fileSources: z.ZodOptional<z.ZodEffects<z.ZodObject<{ workspace: z.ZodOptional<z.ZodEnum<["read", "readwrite"]>>; providers: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>; write: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; }, "strict", z.ZodTypeAny, { write?: string[]; workspace?: "read" | "readwrite"; providers?: string[]; }, { write?: string[]; workspace?: "read" | "readwrite"; providers?: string[]; }>, { write?: string[]; workspace?: "read" | "readwrite"; providers?: string[]; }, { write?: string[]; workspace?: "read" | "readwrite"; providers?: string[]; }>>; fileProviders: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodObject<{ key: z.ZodString; connectionKey: z.ZodString; label: z.ZodString; }, "strict", z.ZodTypeAny, { key?: string; label?: string; connectionKey?: string; }, { key?: string; label?: string; connectionKey?: string; }>, "many">>>; uses: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{ contract: z.ZodString; label: z.ZodOptional<z.ZodString>; optional: z.ZodOptional<z.ZodBoolean>; }, "strict", z.ZodTypeAny, { label?: string; contract?: string; optional?: boolean; }, { label?: string; contract?: string; optional?: boolean; }>>>; provides: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{ tools: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; events: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; models: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; }, "strict", z.ZodTypeAny, { models?: string[]; tools?: string[]; events?: string[]; }, { models?: string[]; tools?: string[]; events?: string[]; }>>>; channel: z.ZodOptional<z.ZodObject<{ topics: z.ZodRecord<z.ZodString, z.ZodObject<{ audience: z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"all">, z.ZodLiteral<"viewer">, z.ZodString]>>; mayAddress: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; description: z.ZodOptional<z.ZodString>; }, "strict", z.ZodTypeAny, { description?: string; audience?: string; mayAddress?: string[]; }, { description?: string; audience?: string; mayAddress?: string[]; }>>; }, "strict", z.ZodTypeAny, { topics?: Record<string, { description?: string; audience?: string; mayAddress?: string[]; }>; }, { topics?: Record<string, { description?: string; audience?: string; mayAddress?: string[]; }>; }>>; db: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{ scope: z.ZodOptional<z.ZodEnum<["instance", "workspace", "user"]>>; owner: z.ZodOptional<z.ZodLiteral<"creator">>; fields: z.ZodRecord<z.ZodString, z.ZodString>; sealed: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; unique: z.ZodOptional<z.ZodArray<z.ZodArray<z.ZodString, "many">, "many">>; indexes: z.ZodOptional<z.ZodArray<z.ZodUnion<[z.ZodArray<z.ZodString, "many">, z.ZodObject<{ fields: z.ZodArray<z.ZodString, "many">; kind: z.ZodOptional<z.ZodEnum<["btree", "contains", "text"]>>; }, "strict", z.ZodTypeAny, { kind?: "text" | "btree" | "contains"; fields?: string[]; }, { kind?: "text" | "btree" | "contains"; fields?: string[]; }>]>, "many">>; rules: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>; }, "strict", z.ZodTypeAny, { owner?: "creator"; fields?: Record<string, string>; scope?: "workspace" | "instance" | "user"; sealed?: string[]; unique?: string[][]; indexes?: (string[] | { kind?: "text" | "btree" | "contains"; fields?: string[]; })[]; rules?: Record<string, unknown>; }, { owner?: "creator"; fields?: Record<string, string>; scope?: "workspace" | "instance" | "user"; sealed?: string[]; unique?: string[][]; indexes?: (string[] | { kind?: "text" | "btree" | "contains"; fields?: string[]; })[]; rules?: Record<string, unknown>; }>>>; }, "strict", z.ZodTypeAny, { roles?: { default?: { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }; custom?: { ops?: string[]; attributes?: string[]; models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; }; vocabulary?: string[]; describe?: Record<string, string>; attributes?: Record<string, "string" | "boolean" | "int">; }; description?: string; manifestVersion?: 1; id?: string; name?: string; version?: string; applicationType?: string; entry?: string; icon?: string; author?: { name?: string; email?: string; url?: string; }; kickableTasks?: string[] | Record<string, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>; webhooks?: string[]; ops?: string[] | Record<string, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>; routes?: string[] | Record<string, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>; pollTasks?: { task?: string; everyMinutes?: number; }[]; platformApi?: { min?: string; max?: string; }; scopes?: string[]; workspaceTools?: string[]; device?: { config?: Record<string, { required?: boolean; describe?: string; secret?: boolean; }>; commands?: Record<string, { params?: Record<string, "string" | "number" | "int" | "bool" | { type?: "number" | "int"; min?: number; max?: number; describe?: string; } | { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; } | { values?: string[]; type?: "enum"; describe?: string; } | { type?: "bool"; describe?: string; }>; describe?: string; argv?: string[]; cwd?: string; env?: Record<string, string>; config?: string[]; timeoutSeconds?: number; onRestart?: "report" | "rerun"; output?: { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }; result?: "text" | "json"; }>; program?: { main?: string; resident?: boolean; setup?: { id?: string; describe?: string; timeoutSeconds?: number; run?: string[]; inputs?: string[]; }[]; selfTest?: { timeoutSeconds?: number; run?: string[]; }; }; redact?: string[]; onAppDeleted?: "kill" | "finish"; }; connections?: { key?: string; kind?: "oauth2" | "apiKey"; label?: string; description?: string; authorizeUrl?: string; tokenUrl?: string; oauthScopes?: string[]; clientIdEnv?: string; clientSecretEnv?: string; headerNames?: string[]; }[]; fileSources?: { write?: string[]; workspace?: "read" | "readwrite"; providers?: string[]; }; fileProviders?: { key?: string; label?: string; connectionKey?: string; }[]; uses?: Record<string, { label?: string; contract?: string; optional?: boolean; }>; provides?: Record<string, { models?: string[]; tools?: string[]; events?: string[]; }>; channel?: { topics?: Record<string, { description?: string; audience?: string; mayAddress?: string[]; }>; }; db?: Record<string, { owner?: "creator"; fields?: Record<string, string>; scope?: "workspace" | "instance" | "user"; sealed?: string[]; unique?: string[][]; indexes?: (string[] | { kind?: "text" | "btree" | "contains"; fields?: string[]; })[]; rules?: Record<string, unknown>; }>; }, { roles?: { default?: { owner?: string; "member-edit"?: string; "member-readonly"?: string; visitor?: string; anonymous?: string; agent?: string; }; custom?: { ops?: string[]; attributes?: string[]; models?: Record<string, { where?: string[]; hide?: string[]; update?: { fields?: string[]; transitions?: string; }; }>; }; vocabulary?: string[]; describe?: Record<string, string>; attributes?: Record<string, "string" | "boolean" | "int">; }; description?: string; manifestVersion?: 1; id?: string; name?: string; version?: string; applicationType?: string; entry?: string; icon?: string; author?: { name?: string; email?: string; url?: string; }; kickableTasks?: string[] | Record<string, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>; webhooks?: string[]; ops?: string[] | Record<string, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>; routes?: string[] | Record<string, { access?: "write" | "read" | "public" | "token" | string[]; requires?: "account"; }>; pollTasks?: { task?: string; everyMinutes?: number; }[]; platformApi?: { min?: string; max?: string; }; scopes?: string[]; workspaceTools?: string[]; device?: { config?: Record<string, { required?: boolean; describe?: string; secret?: boolean; }>; commands?: Record<string, { params?: Record<string, "string" | "number" | "int" | "bool" | { type?: "number" | "int"; min?: number; max?: number; describe?: string; } | { type?: "string"; maxLength?: number; describe?: string; pattern?: string; allowDash?: boolean; } | { values?: string[]; type?: "enum"; describe?: string; } | { type?: "bool"; describe?: string; }>; describe?: string; argv?: string[]; cwd?: string; env?: Record<string, string>; config?: string[]; timeoutSeconds?: number; onRestart?: "report" | "rerun"; output?: { mode?: "live" | "batched" | "final"; flushMs?: number; maxChunkKb?: number; keep?: "head" | "tail" | "both"; maxKb?: number; }; result?: "text" | "json"; }>; program?: { main?: string; resident?: boolean; setup?: { id?: string; describe?: string; timeoutSeconds?: number; run?: string[]; inputs?: string[]; }[]; selfTest?: { timeoutSeconds?: number; run?: string[]; }; }; redact?: string[]; onAppDeleted?: "kill" | "finish"; }; connections?: { key?: string; kind?: "oauth2" | "apiKey"; label?: string; description?: string; authorizeUrl?: string; tokenUrl?: string; oauthScopes?: string[]; clientIdEnv?: string; clientSecretEnv?: string; headerNames?: string[]; }[]; fileSources?: { write?: string[]; workspace?: "read" | "readwrite"; providers?: string[]; }; fileProviders?: { key?: string; label?: string; connectionKey?: string; }[]; uses?: Record<string, { label?: string; contract?: string; optional?: boolean; }>; provides?: Record<string, { models?: string[]; tools?: string[]; events?: string[]; }>; channel?: { topics?: Record<string, { description?: string; audience?: string; mayAddress?: string[]; }>; }; db?: Record<string, { owner?: "creator"; fields?: Record<string, string>; scope?: "workspace" | "instance" | "user"; sealed?: string[]; unique?: string[][]; indexes?: (string[] | { kind?: "text" | "btree" | "contains"; fields?: string[]; })[]; rules?: Record<string, unknown>; }>; }>
758
758
  ```
759
759
 
760
760
  #### `PluginRolesSchema` — const · src/manifest.ts
@@ -1401,6 +1401,7 @@ interface DerivedTool extends ApplicationTools {
1401
1401
  ```ts
1402
1402
  interface DeviceBlock {
1403
1403
  commands: Record<string, CommandSpec>;
1404
+ program?: ProgramSpec;
1404
1405
  config?: Record<string, ConfigKeySpec>;
1405
1406
  redact?: string[];
1406
1407
  onAppDeleted?: "kill" | "finish";
@@ -1926,7 +1927,7 @@ interface UsesDecl {
1926
1927
  ```
1927
1928
 
1928
1929
  ==============================================================================
1929
- ## `esoul-sdk/server` — 77 exports
1930
+ ## `esoul-sdk/server` — 79 exports
1930
1931
 
1931
1932
  Server code only (server.ts, ops, routes, tasks): the viewer, the app's database, files, connections, machines, charts, route tokens.
1932
1933
 
@@ -2164,7 +2165,7 @@ WHO IS THIS, IN WORDS. The caller's own name and email, for an app with a reason
2164
2165
  function viewerProfile(_viewer: PluginViewer): Promise<ViewerProfile | null>
2165
2166
  ```
2166
2167
 
2167
- ### Types (48)
2168
+ ### Types (50)
2168
2169
 
2169
2170
  #### `AppRolePerson` — interface · src/server.ts
2170
2171
 
@@ -2417,8 +2418,6 @@ interface DeviceRunStarted {
2417
2418
 
2418
2419
  #### `DeviceRunStatus` — type · src/device.ts
2419
2420
 
2420
- Types for `devices(ctx)` — parts of an app that run on the person's own computer (plugin-device-arm.md §10–§11). The functions live in server.ts (host-only); the hooks and <ConnectComputer/> in react.ts.
2421
-
2422
2421
  ```ts
2423
2422
  type DeviceRunStatus = "queued" | "claimed" | "running" | "done" | "expired" | "cancelled" | "lost";
2424
2423
  ```
@@ -2464,6 +2463,10 @@ interface Devices {
2464
2463
  wait(commandId: string, opts?: { timeoutSeconds?: number }): Promise<DeviceRunView>;
2465
2464
  cancel(commandId: string): Promise<{ status: string }>;
2466
2465
  sh(line: string, opts: { agent: string; stdin?: string; linkId?: string; waitSeconds?: number }): Promise<ShellResult & { commandId: string; status: DeviceRunStatus }>;
2466
+ program(linkId: string): {
2467
+ send(topic: string, data?: unknown, opts?: { waitSeconds?: number }): Promise<{ commandId: string; status: DeviceRunStatus; ok: boolean; result: unknown; error: string | null }>;
2468
+ state(): Promise<ProgramState | null>;
2469
+ };
2467
2470
  }
2468
2471
  ```
2469
2472
 
@@ -2480,6 +2483,8 @@ interface DeviceSummary {
2480
2483
  pendingApproval: { added: string[]; changed: string[] };
2481
2484
  machine: { machineId: string; hostname: string; os: string; arch: string | null; runtimeVersion: string | null; lastSeenAt: number | null; online: boolean } | null;
2482
2485
  workspace?: WorkspaceGrant | null;
2486
+ program?: boolean;
2487
+ programState?: ProgramState | null;
2483
2488
  }
2484
2489
  ```
2485
2490
 
@@ -2720,7 +2725,8 @@ interface PluginViewer {
2720
2725
  attrs?: Record<string, AttrValue>;
2721
2726
  canWrite: boolean;
2722
2727
  shareId: string | null;
2723
- agent?: { runId?: string; onBehalfOf: Omit<PluginViewer, "agent"> };
2728
+ agent?: { runId?: string; onBehalfOf: Omit<PluginViewer, "agent"> };
2729
+ device?: { machineId: string; linkId: string; hostname: string };
2724
2730
  }
2725
2731
  ```
2726
2732
 
@@ -2761,6 +2767,38 @@ type PluginWebhookHandler = (
2761
2767
  ) => Promise<Response>;
2762
2768
  ```
2763
2769
 
2770
+ #### `ProgramState` — interface · src/machine/program-api.ts
2771
+
2772
+ Where an app's program stands on one computer — what the runtime reports and the app's Computers card renders. `phase` moves forward installing → setup → self-test → running (or ready, for a program started by its first message); `failed` and `refused` say why in `error`.
2773
+
2774
+ ```ts
2775
+ interface ProgramState {
2776
+ digest: string;
2777
+ phase: "installing" | "setup" | "self-test" | "ready" | "starting" | "running" | "stopped" | "failed" | "refused";
2778
+ steps: ProgramStepState[];
2779
+ status?: { text: string; progress?: number; ready?: boolean; at: number } | null;
2780
+ error?: string | null;
2781
+ logTail?: string[];
2782
+ restarts: number;
2783
+ updatedAt: number;
2784
+ }
2785
+ ```
2786
+
2787
+ #### `ProgramStepState` — interface · src/machine/program-api.ts
2788
+
2789
+ One setup step, as the Computers card shows it.
2790
+
2791
+ ```ts
2792
+ interface ProgramStepState {
2793
+ id: string;
2794
+ describe: string;
2795
+ state: "pending" | "running" | "done" | "cached" | "failed";
2796
+ startedAt?: number;
2797
+ endedAt?: number;
2798
+ detail?: string;
2799
+ }
2800
+ ```
2801
+
2764
2802
  #### `RouteTokenGrant` — interface · src/server.ts
2765
2803
 
2766
2804
  ```ts
@@ -3154,6 +3192,8 @@ interface DeviceSummary {
3154
3192
  pendingApproval: { added: string[]; changed: string[] };
3155
3193
  machine: { machineId: string; hostname: string; os: string; arch: string | null; runtimeVersion: string | null; lastSeenAt: number | null; online: boolean } | null;
3156
3194
  workspace?: WorkspaceGrant | null;
3195
+ program?: boolean;
3196
+ programState?: ProgramState | null;
3157
3197
  }
3158
3198
  ```
3159
3199
 
@@ -3737,11 +3777,11 @@ type ViewerKind = RuleViewer["kind"];
3737
3777
  ```
3738
3778
 
3739
3779
  ==============================================================================
3740
- ## `esoul-sdk/machine` — 82 exports
3780
+ ## `esoul-sdk/machine` — 102 exports
3741
3781
 
3742
3782
  The side of an app that runs on the person's computer: the signed door protocol, the declared-command rules, the runtime behind the `esoul-device` command. Node built-ins only.
3743
3783
 
3744
- ### Functions and values (51)
3784
+ ### Functions and values (62)
3745
3785
 
3746
3786
  #### `AGENT_NAME_RE` — const · src/machine/shell.ts
3747
3787
 
@@ -3775,12 +3815,20 @@ Apply a unified diff with context. Each hunk's old lines (context + removed) are
3775
3815
  function applyPatch(text: string, diff: string, opts: { partial?: boolean } = {}): { text: string; results: HunkResult[] }
3776
3816
  ```
3777
3817
 
3818
+ #### `approvedCommandNames` — function · src/machine/digest.ts
3819
+
3820
+ The command names an approval covers (without the program's entry).
3821
+
3822
+ ```ts
3823
+ function approvedCommandNames(approved: Record<string, string>): string[]
3824
+ ```
3825
+
3778
3826
  #### `builtInCapabilities` — function · src/machine/capabilities.ts
3779
3827
 
3780
3828
  The capabilities this runtime is built with, as one registry (the supervisor dispatches through it).
3781
3829
 
3782
3830
  ```ts
3783
- function builtInCapabilities(startRun: (job: Job, redact: string[], env: Record<string, string>) => Promise<void>): Map<string, Capability>
3831
+ function builtInCapabilities(startRun: (job: Job, redact: string[], env: Record<string, string>) => Promise<void>, programs: ProgramDelivery | null = null): Map<string, Capability>
3784
3832
  ```
3785
3833
 
3786
3834
  #### `canonical` — function · src/machine/protocol.ts
@@ -3809,7 +3857,7 @@ function commandDigest(spec: CommandSpec): string
3809
3857
 
3810
3858
  #### `commandDigests` — function · src/machine/digest.ts
3811
3859
 
3812
- Every declared command's digest, by name — what an approval records.
3860
+ Every declared command's digest, by name, and the program's under `@program` — what an approval records.
3813
3861
 
3814
3862
  ```ts
3815
3863
  function commandDigests(block: DeviceBlock): Record<string, string>
@@ -3847,6 +3895,14 @@ The short code both the machine and the connect page show, so the owner can see
3847
3895
  function connectCode(publicKey: string, offerId: string): string
3848
3896
  ```
3849
3897
 
3898
+ #### `createProgramManager` — function · src/machine/program-manager.ts
3899
+
3900
+ The runtime's keeper of app programs: `reconcile(links)` after each hello brings every approved program to its approved digest (download, verify, setup, self-test, start) and stops the rest; `deliver` hands a program the app's message and resolves with its answer.
3901
+
3902
+ ```ts
3903
+ function createProgramManager(opts: ProgramManagerOptions)
3904
+ ```
3905
+
3850
3906
  #### `DEFAULT_TIMEOUT_SECONDS` — const · src/machine/commands.ts
3851
3907
 
3852
3908
  A command's time limit when it declares none: one hour.
@@ -3855,6 +3911,14 @@ A command's time limit when it declares none: one hour.
3855
3911
  const DEFAULT_TIMEOUT_SECONDS: 3600
3856
3912
  ```
3857
3913
 
3914
+ #### `defineProgram` — function · src/machine/program-api.ts
3915
+
3916
+ Identity helper for a program written in plain JavaScript (TypeScript can use `satisfies Program`).
3917
+
3918
+ ```ts
3919
+ function defineProgram(program: Program): Program
3920
+ ```
3921
+
3858
3922
  #### `describeGrant` — function · src/machine/grant.ts
3859
3923
 
3860
3924
  A grant in words: "the folder /home/me/proj", "the whole computer", or "no workspace access".
@@ -4047,6 +4111,70 @@ The hunks of a unified diff (`@@ -a,b +c,d
4047
4111
  function parseUnifiedDiff(diff: string): Hunk[]
4048
4112
  ```
4049
4113
 
4114
+ #### `PROGRAM_KEY` — const · src/machine/digest.ts
4115
+
4116
+ Where an approval records the program's digest, beside the commands' (no command name can start with "@").
4117
+
4118
+ ```ts
4119
+ const PROGRAM_KEY: "@program"
4120
+ ```
4121
+
4122
+ #### `PROGRAM_MAX_BYTES` — const · src/machine/commands.ts
4123
+
4124
+ A program's files: at most this many bytes in all (setup steps download the heavy things).
4125
+
4126
+ ```ts
4127
+ const PROGRAM_MAX_BYTES: number
4128
+ ```
4129
+
4130
+ #### `PROGRAM_MAX_FILES` — const · src/machine/commands.ts
4131
+
4132
+ A program's files: at most this many.
4133
+
4134
+ ```ts
4135
+ const PROGRAM_MAX_FILES: 200
4136
+ ```
4137
+
4138
+ #### `programCapability` — function · src/machine/capabilities.ts
4139
+
4140
+ A message from the app to its program on this computer; the program's answer is the job's result.
4141
+
4142
+ ```ts
4143
+ function programCapability(programs: ProgramDelivery | null): Capability
4144
+ ```
4145
+
4146
+ #### `programDigest` — function · src/machine/digest.ts
4147
+
4148
+ The digest of a program: its spec (without the computed fields) and every file, sorted by path. Two builds of the same files give the same digest.
4149
+
4150
+ ```ts
4151
+ function programDigest(spec: Omit<ProgramSpec, "digest" | "size">, files: { path: string; content: Buffer | Uint8Array | string }[]): string
4152
+ ```
4153
+
4154
+ #### `programEnv` — function · src/machine/program-manager.ts
4155
+
4156
+ The environment an app's program and its setup steps get: scrubbed (the runtime's own settings never reach app code), the runtime's Node FIRST on PATH — on a computer whose only Node is the one the bootstrap brought (showrack), `node` in a setup step must be it — and HOME its own data folder, or the person's real home when the whole computer was granted (unconfined).
4157
+
4158
+ ```ts
4159
+ function programEnv(env: Record<string, string | undefined>, nodePath: string, dataDir: string, opts: { unconfined?: boolean } = {}): Record<string, string>
4160
+ ```
4161
+
4162
+ #### `programPaths` — function · src/machine/program-manager.ts
4163
+
4164
+ Where an app's program lives in the runtime's folder: its version folder, its own data folder, setup markers and logs.
4165
+
4166
+ ```ts
4167
+ function programPaths(home: string, linkId: string, digest?: string)
4168
+ ```
4169
+
4170
+ #### `programProblems` — function · src/machine/commands.ts
4171
+
4172
+ What is wrong with a program spec, in words (the platform's build adds `digest` and `size`).
4173
+
4174
+ ```ts
4175
+ function programProblems(p: unknown): string[]
4176
+ ```
4177
+
4050
4178
  #### `PROTOCOL` — const · src/machine/protocol.ts
4051
4179
 
4052
4180
  The protocol version, the first line of every signed request.
@@ -4151,7 +4279,7 @@ The shared command line, under grant ∩ ceiling, one working directory per name
4151
4279
  function workspaceCapability(): Capability
4152
4280
  ```
4153
4281
 
4154
- ### Types (31)
4282
+ ### Types (40)
4155
4283
 
4156
4284
  #### `CallTiming` — interface · src/machine/client.ts
4157
4285
 
@@ -4234,6 +4362,7 @@ interface ConnectResult {
4234
4362
  ```ts
4235
4363
  interface DeviceBlock {
4236
4364
  commands: Record<string, CommandSpec>;
4365
+ program?: ProgramSpec;
4237
4366
  config?: Record<string, ConfigKeySpec>;
4238
4367
  redact?: string[];
4239
4368
  onAppDeleted?: "kill" | "finish";
@@ -4406,6 +4535,119 @@ type ParamSpec =
4406
4535
  | { type: "bool"; describe?: string };
4407
4536
  ```
4408
4537
 
4538
+ #### `Program` — interface · src/machine/program-api.ts
4539
+
4540
+ An app's program: `start` is called once per process; `stop` before the process ends, when it ends cleanly.
4541
+
4542
+ ```ts
4543
+ interface Program {
4544
+ start(p: ProgramApi): void | Promise<void>;
4545
+ stop?(): void | Promise<void>;
4546
+ }
4547
+ ```
4548
+
4549
+ #### `ProgramApi` — interface · src/machine/program-api.ts
4550
+
4551
+ The program's handle on the computer and on its app.
4552
+
4553
+ ```ts
4554
+ interface ProgramApi {
4555
+ readonly computer: { readonly hostname: string; readonly platform: string; readonly arch: string; readonly cpus: number; readonly memoryGb: number };
4556
+ readonly appName: string | null;
4557
+ readonly programDir: string;
4558
+ readonly dataDir: string;
4559
+ readonly workspaceRoot: string | null;
4560
+ readonly config: Readonly<Record<string, string>>;
4561
+ status(text: string, extra?: { progress?: number; ready?: boolean }): void;
4562
+ op<T = unknown>(name: string, args?: unknown, opts?: { key?: string }): Promise<T>;
4563
+ on(topic: string, handler: (data: unknown) => unknown | Promise<unknown>): void;
4564
+ every(ms: number, fn: () => unknown | Promise<unknown>): () => void;
4565
+ log(...args: unknown[]): void;
4566
+ }
4567
+ ```
4568
+
4569
+ #### `ProgramDelivery` — interface · src/machine/capabilities.ts
4570
+
4571
+ The part of the program manager a message job needs (program-manager.ts).
4572
+
4573
+ ```ts
4574
+ interface ProgramDelivery {
4575
+ has(linkId: string): boolean;
4576
+ deliver(linkId: string, topic: string, data: unknown, signal?: AbortSignal): Promise<{ ok: boolean; result?: unknown; error?: string }>;
4577
+ }
4578
+ ```
4579
+
4580
+ #### `ProgramManager` — type · src/machine/program-manager.ts
4581
+
4582
+ The program manager's handle (see createProgramManager).
4583
+
4584
+ ```ts
4585
+ type ProgramManager = ReturnType<typeof createProgramManager>;
4586
+ ```
4587
+
4588
+ #### `ProgramManagerOptions` — interface · src/machine/program-manager.ts
4589
+
4590
+ What the program manager needs from the runtime.
4591
+
4592
+ ```ts
4593
+ interface ProgramManagerOptions {
4594
+ home: string;
4595
+ client: DoorClient;
4596
+ hostScript: string;
4597
+ nodePath?: string;
4598
+ log: (line: string) => void;
4599
+ ceiling: () => WorkspaceGrant | null;
4600
+ sandbox?: Sandbox;
4601
+ }
4602
+ ```
4603
+
4604
+ #### `ProgramSpec` — interface · src/machine/commands.ts
4605
+
4606
+ The app's own program on the computer (`computer-apps.md` §4.1): the files of `device/` shipped per app version, set up once, then started — at approval when `resident`, or when the app first sends it a message.
4607
+
4608
+ ```ts
4609
+ interface ProgramSpec {
4610
+ main: string;
4611
+ resident?: boolean;
4612
+ setup?: SetupStepSpec[];
4613
+ selfTest?: { run: string[]; timeoutSeconds?: number };
4614
+ digest?: string;
4615
+ size?: number;
4616
+ }
4617
+ ```
4618
+
4619
+ #### `ProgramState` — interface · src/machine/program-api.ts
4620
+
4621
+ Where an app's program stands on one computer — what the runtime reports and the app's Computers card renders. `phase` moves forward installing → setup → self-test → running (or ready, for a program started by its first message); `failed` and `refused` say why in `error`.
4622
+
4623
+ ```ts
4624
+ interface ProgramState {
4625
+ digest: string;
4626
+ phase: "installing" | "setup" | "self-test" | "ready" | "starting" | "running" | "stopped" | "failed" | "refused";
4627
+ steps: ProgramStepState[];
4628
+ status?: { text: string; progress?: number; ready?: boolean; at: number } | null;
4629
+ error?: string | null;
4630
+ logTail?: string[];
4631
+ restarts: number;
4632
+ updatedAt: number;
4633
+ }
4634
+ ```
4635
+
4636
+ #### `ProgramStepState` — interface · src/machine/program-api.ts
4637
+
4638
+ One setup step, as the Computers card shows it.
4639
+
4640
+ ```ts
4641
+ interface ProgramStepState {
4642
+ id: string;
4643
+ describe: string;
4644
+ state: "pending" | "running" | "done" | "cached" | "failed";
4645
+ startedAt?: number;
4646
+ endedAt?: number;
4647
+ detail?: string;
4648
+ }
4649
+ ```
4650
+
4409
4651
  #### `RenderedCommand` — interface · src/machine/commands.ts
4410
4652
 
4411
4653
  ```ts
@@ -4444,6 +4686,20 @@ type Sandbox = { kind: "none" } | { kind: "bwrap"; bin: string } | { kind: "seat
4444
4686
  type Scope = { kind: "folder"; root: string } | { kind: "computer" };
4445
4687
  ```
4446
4688
 
4689
+ #### `SetupStepSpec` — interface · src/machine/commands.ts
4690
+
4691
+ One setup step of a program: argv (never a shell line), run once per program digest and declared inputs.
4692
+
4693
+ ```ts
4694
+ interface SetupStepSpec {
4695
+ id: string;
4696
+ describe: string;
4697
+ run: string[];
4698
+ inputs?: string[];
4699
+ timeoutSeconds?: number;
4700
+ }
4701
+ ```
4702
+
4447
4703
  #### `ShellCall` — interface · src/machine/shell.ts
4448
4704
 
4449
4705
  ```ts