@procedures/compiler 0.0.0-stage → 0.2.3

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.
Files changed (174) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +254 -2
  3. package/dist/.tsbuildinfo +1 -0
  4. package/dist/checks.d.ts +24 -0
  5. package/dist/checks.d.ts.map +1 -0
  6. package/dist/checks.js +123 -0
  7. package/dist/checks.js.map +1 -0
  8. package/dist/codegen-closure.d.ts +19 -0
  9. package/dist/codegen-closure.d.ts.map +1 -0
  10. package/dist/codegen-closure.js +200 -0
  11. package/dist/codegen-closure.js.map +1 -0
  12. package/dist/codegen-text.d.ts +44 -0
  13. package/dist/codegen-text.d.ts.map +1 -0
  14. package/dist/codegen-text.js +360 -0
  15. package/dist/codegen-text.js.map +1 -0
  16. package/dist/diagnostics.d.ts +67 -0
  17. package/dist/diagnostics.d.ts.map +1 -0
  18. package/dist/diagnostics.js +38 -0
  19. package/dist/diagnostics.js.map +1 -0
  20. package/dist/effects.d.ts +63 -0
  21. package/dist/effects.d.ts.map +1 -0
  22. package/dist/effects.js +185 -0
  23. package/dist/effects.js.map +1 -0
  24. package/dist/explain.d.ts +58 -0
  25. package/dist/explain.d.ts.map +1 -0
  26. package/dist/explain.js +144 -0
  27. package/dist/explain.js.map +1 -0
  28. package/dist/facts.d.ts +66 -0
  29. package/dist/facts.d.ts.map +1 -0
  30. package/dist/facts.js +102 -0
  31. package/dist/facts.js.map +1 -0
  32. package/dist/fold.d.ts +27 -0
  33. package/dist/fold.d.ts.map +1 -0
  34. package/dist/fold.js +128 -0
  35. package/dist/fold.js.map +1 -0
  36. package/dist/index.d.ts +35 -0
  37. package/dist/index.d.ts.map +1 -0
  38. package/dist/index.js +22 -0
  39. package/dist/index.js.map +1 -0
  40. package/dist/interceptor.d.ts +51 -0
  41. package/dist/interceptor.d.ts.map +1 -0
  42. package/dist/interceptor.js +116 -0
  43. package/dist/interceptor.js.map +1 -0
  44. package/dist/ir.d.ts +240 -0
  45. package/dist/ir.d.ts.map +1 -0
  46. package/dist/ir.js +74 -0
  47. package/dist/ir.js.map +1 -0
  48. package/dist/mermaid.d.ts +53 -0
  49. package/dist/mermaid.d.ts.map +1 -0
  50. package/dist/mermaid.js +423 -0
  51. package/dist/mermaid.js.map +1 -0
  52. package/dist/module.d.ts +20 -0
  53. package/dist/module.d.ts.map +1 -0
  54. package/dist/module.js +124 -0
  55. package/dist/module.js.map +1 -0
  56. package/dist/normalize.d.ts +43 -0
  57. package/dist/normalize.d.ts.map +1 -0
  58. package/dist/normalize.js +529 -0
  59. package/dist/normalize.js.map +1 -0
  60. package/dist/openrpc.d.ts +63 -0
  61. package/dist/openrpc.d.ts.map +1 -0
  62. package/dist/openrpc.js +57 -0
  63. package/dist/openrpc.js.map +1 -0
  64. package/dist/print.d.ts +8 -0
  65. package/dist/print.d.ts.map +1 -0
  66. package/dist/print.js +148 -0
  67. package/dist/print.js.map +1 -0
  68. package/dist/procedures/program/check.d.ts +14 -0
  69. package/dist/procedures/program/check.d.ts.map +1 -0
  70. package/dist/procedures/program/check.js +30 -0
  71. package/dist/procedures/program/check.js.map +1 -0
  72. package/dist/procedures/program/compile.d.ts +14 -0
  73. package/dist/procedures/program/compile.d.ts.map +1 -0
  74. package/dist/procedures/program/compile.js +35 -0
  75. package/dist/procedures/program/compile.js.map +1 -0
  76. package/dist/procedures/program/diagram.d.ts +14 -0
  77. package/dist/procedures/program/diagram.d.ts.map +1 -0
  78. package/dist/procedures/program/diagram.js +23 -0
  79. package/dist/procedures/program/diagram.js.map +1 -0
  80. package/dist/procedures/program/effects-output.d.ts +8 -0
  81. package/dist/procedures/program/effects-output.d.ts.map +1 -0
  82. package/dist/procedures/program/effects-output.js +13 -0
  83. package/dist/procedures/program/effects-output.js.map +1 -0
  84. package/dist/procedures/program/explain.d.ts +14 -0
  85. package/dist/procedures/program/explain.d.ts.map +1 -0
  86. package/dist/procedures/program/explain.js +43 -0
  87. package/dist/procedures/program/explain.js.map +1 -0
  88. package/dist/procedures/program/index.d.ts +5 -0
  89. package/dist/procedures/program/index.d.ts.map +1 -0
  90. package/dist/procedures/program/index.js +5 -0
  91. package/dist/procedures/program/index.js.map +1 -0
  92. package/dist/procedures/sdk/index.d.ts +3 -0
  93. package/dist/procedures/sdk/index.d.ts.map +1 -0
  94. package/dist/procedures/sdk/index.js +3 -0
  95. package/dist/procedures/sdk/index.js.map +1 -0
  96. package/dist/procedures/sdk/manifest.d.ts +11 -0
  97. package/dist/procedures/sdk/manifest.d.ts.map +1 -0
  98. package/dist/procedures/sdk/manifest.js +15 -0
  99. package/dist/procedures/sdk/manifest.js.map +1 -0
  100. package/dist/procedures/sdk/openrpc.d.ts +11 -0
  101. package/dist/procedures/sdk/openrpc.d.ts.map +1 -0
  102. package/dist/procedures/sdk/openrpc.js +13 -0
  103. package/dist/procedures/sdk/openrpc.js.map +1 -0
  104. package/dist/procedures/sdk/typescript.d.ts +11 -0
  105. package/dist/procedures/sdk/typescript.d.ts.map +1 -0
  106. package/dist/procedures/sdk/typescript.js +14 -0
  107. package/dist/procedures/sdk/typescript.js.map +1 -0
  108. package/dist/program.d.ts +84 -0
  109. package/dist/program.d.ts.map +1 -0
  110. package/dist/program.js +108 -0
  111. package/dist/program.js.map +1 -0
  112. package/dist/refs.d.ts +9 -0
  113. package/dist/refs.d.ts.map +1 -0
  114. package/dist/refs.js +9 -0
  115. package/dist/refs.js.map +1 -0
  116. package/dist/register.d.ts +6 -0
  117. package/dist/register.d.ts.map +1 -0
  118. package/dist/register.js +8 -0
  119. package/dist/register.js.map +1 -0
  120. package/dist/runtime.d.ts +68 -0
  121. package/dist/runtime.d.ts.map +1 -0
  122. package/dist/runtime.js +138 -0
  123. package/dist/runtime.js.map +1 -0
  124. package/dist/schema.d.ts +41 -0
  125. package/dist/schema.d.ts.map +1 -0
  126. package/dist/schema.js +325 -0
  127. package/dist/schema.js.map +1 -0
  128. package/dist/scopes.d.ts +25 -0
  129. package/dist/scopes.d.ts.map +1 -0
  130. package/dist/scopes.js +202 -0
  131. package/dist/scopes.js.map +1 -0
  132. package/dist/types.d.ts +129 -0
  133. package/dist/types.d.ts.map +1 -0
  134. package/dist/types.js +157 -0
  135. package/dist/types.js.map +1 -0
  136. package/dist/typescript-sdk.d.ts +34 -0
  137. package/dist/typescript-sdk.d.ts.map +1 -0
  138. package/dist/typescript-sdk.js +231 -0
  139. package/dist/typescript-sdk.js.map +1 -0
  140. package/package.json +83 -3
  141. package/src/checks.ts +128 -0
  142. package/src/codegen-closure.ts +224 -0
  143. package/src/codegen-text.ts +396 -0
  144. package/src/diagnostics.ts +98 -0
  145. package/src/effects.ts +231 -0
  146. package/src/explain.ts +194 -0
  147. package/src/facts.ts +161 -0
  148. package/src/fold.ts +136 -0
  149. package/src/index.ts +35 -0
  150. package/src/interceptor.ts +149 -0
  151. package/src/ir.ts +330 -0
  152. package/src/mermaid.ts +460 -0
  153. package/src/module.ts +171 -0
  154. package/src/normalize.ts +694 -0
  155. package/src/openrpc.ts +104 -0
  156. package/src/print.ts +143 -0
  157. package/src/procedures/program/check.ts +31 -0
  158. package/src/procedures/program/compile.ts +36 -0
  159. package/src/procedures/program/diagram.ts +25 -0
  160. package/src/procedures/program/effects-output.ts +16 -0
  161. package/src/procedures/program/explain.ts +46 -0
  162. package/src/procedures/program/index.ts +4 -0
  163. package/src/procedures/sdk/index.ts +2 -0
  164. package/src/procedures/sdk/manifest.ts +17 -0
  165. package/src/procedures/sdk/openrpc.ts +16 -0
  166. package/src/procedures/sdk/typescript.ts +17 -0
  167. package/src/program.ts +181 -0
  168. package/src/refs.ts +9 -0
  169. package/src/register.ts +10 -0
  170. package/src/runtime.ts +188 -0
  171. package/src/schema.ts +318 -0
  172. package/src/scopes.ts +196 -0
  173. package/src/types.ts +318 -0
  174. package/src/typescript-sdk.ts +282 -0
package/src/scopes.ts ADDED
@@ -0,0 +1,196 @@
1
+ /**
2
+ * The scopes pass: each `$ref` gets the binding that the interpreter reads.
3
+ *
4
+ * The pass follows `lookupOutputRef()` of the client. The innermost frame with the name gives the
5
+ * value. `$last` is the last result of the innermost frame that has one. A chain frame gets a
6
+ * name after its step: a step reads only the names of the steps before it. A name that no frame
7
+ * has is an error (`Unknown $ref name`). In the input of a deferred call, the runner can give the
8
+ * name later, so there the name stays.
9
+ */
10
+
11
+ import { isPlainObject } from "@procedures/client/browser";
12
+ import { isOutputRef } from "./refs.js";
13
+ import { childPointer, type Binding, type IRNode, type ItemsSpec, type Pointer, type ProgramIR, type ReferenceNode, type ScopeFrame, type ScopeSnapshot } from "./ir.js";
14
+ import type { Diagnostic } from "./diagnostics.js";
15
+
16
+ /** A frame while the pass walks: the names grow as the steps of a chain pass. */
17
+ interface Frame {
18
+ readonly names: Map<string, Binding>;
19
+ last: Binding | undefined;
20
+ /** The names of this step and the later steps of a chain, to find a use before the definition. */
21
+ later: ReadonlySet<string>;
22
+ }
23
+
24
+ type Env = readonly Frame[] | undefined;
25
+
26
+ /** This function resolves the references of the IR and gives the diagnostics of the names. */
27
+ export function resolveScopes(ir: ProgramIR): Diagnostic[] {
28
+ const diagnostics: Diagnostic[] = [];
29
+ const root: Env = ir.input ? [frameOf([["input", ir.input]])] : undefined;
30
+ visit(ir.root, root, diagnostics);
31
+ return diagnostics;
32
+ }
33
+
34
+ function frameOf(names: ReadonlyArray<readonly [string, Binding]>): Frame {
35
+ return { names: new Map(names), last: undefined, later: new Set() };
36
+ }
37
+
38
+ /** The static scope at a point: a copy of the frames, as `withScope()` gives them to a raw input. */
39
+ export function snapshot(env: Env): ScopeSnapshot {
40
+ if (!env) return undefined;
41
+ return env.map((frame): ScopeFrame => ({ names: [...frame.names.entries()], last: frame.last }));
42
+ }
43
+
44
+ /** `lookupOutputRef()`: the binding of a name, or undefined. */
45
+ function lookup(env: Env, name: string): Binding | undefined {
46
+ if (!env) return undefined;
47
+ for (let index = env.length - 1; index >= 0; index--) {
48
+ const frame = env[index]!;
49
+ if (name === "$last") {
50
+ if (frame.last) return frame.last;
51
+ } else {
52
+ const binding = frame.names.get(name);
53
+ if (binding) return binding;
54
+ }
55
+ }
56
+ return undefined;
57
+ }
58
+
59
+ function resolve(node: ReferenceNode, env: Env, diagnostics: Diagnostic[]): void {
60
+ if (node.synthetic) return;
61
+ node.binding = lookup(env, node.name);
62
+ if (node.binding) return;
63
+ if (node.deferred) {
64
+ diagnostics.push({
65
+ severity: "info",
66
+ code: "unknown-name",
67
+ message: `No scope has the name "${node.name}" here. In the input of a deferred call, the $ref stays data for the runner.`,
68
+ pointer: node.pointer,
69
+ });
70
+ return;
71
+ }
72
+ const later = env?.some((frame) => frame.later.has(node.name)) ?? false;
73
+ const names = [...new Set((env ?? []).flatMap((frame) => [...frame.names.keys(), ...(frame.last ? ["$last"] : [])]))];
74
+ const known = names.length > 0 ? ` The names here: ${names.join(", ")}.` : " No name is in the scope here.";
75
+ diagnostics.push(
76
+ later
77
+ ? {
78
+ severity: "error",
79
+ code: "use-before-definition",
80
+ message: `The $ref "${node.text}" reads "${node.name}" before the step that makes it: a step reads only the names of the steps before it.`,
81
+ pointer: node.pointer,
82
+ }
83
+ : {
84
+ severity: "error",
85
+ code: "unknown-name",
86
+ message: `Unknown $ref name "${node.name}" in "${node.text}".${known}${node.name === "$last" ? " The first step of a chain has no $last." : ""}`,
87
+ pointer: node.pointer,
88
+ },
89
+ );
90
+ }
91
+
92
+ function visitItems(items: ItemsSpec, env: Env, diagnostics: Diagnostic[]): void {
93
+ if (items.kind === "list") for (const item of items.items) visit(item, env, diagnostics);
94
+ else visit(items.value, env, diagnostics);
95
+ }
96
+
97
+ function visit(node: IRNode, env: Env, diagnostics: Diagnostic[]): void {
98
+ switch (node.kind) {
99
+ case "literal":
100
+ case "fail":
101
+ return;
102
+ case "reference":
103
+ resolve(node, env, diagnostics);
104
+ return;
105
+ case "object":
106
+ for (const entry of node.entries) visit(entry.value, env, diagnostics);
107
+ return;
108
+ case "array":
109
+ for (const item of node.items) visit(item, env, diagnostics);
110
+ return;
111
+ case "call":
112
+ case "deferred":
113
+ visit(node.input, env, diagnostics);
114
+ return;
115
+ case "dynamic":
116
+ node.scope = snapshot(env);
117
+ visit(node.input, env, diagnostics);
118
+ if (node.model) visit(node.model, env, diagnostics);
119
+ // The body of procedure.define has its own scope (`input`): the program checks it as a body
120
+ else if (node.reason === "runs-refs" && node.key !== "procedure.define") scanRaw(node.input, env, diagnostics);
121
+ return;
122
+ case "chain": {
123
+ const names = node.steps.map((step) => step.result.name);
124
+ const frame: Frame = { names: new Map(), last: undefined, later: new Set() };
125
+ const inner: Env = [...(env ?? []), frame];
126
+ if (node.initialInput) visit(node.initialInput, inner, diagnostics);
127
+ node.steps.forEach((step, index) => {
128
+ frame.later = new Set(names.slice(index).filter((name): name is string => name !== undefined));
129
+ visit(step.node, inner, diagnostics);
130
+ if (step.result.name !== undefined) frame.names.set(step.result.name, step.result);
131
+ frame.last = step.result;
132
+ });
133
+ frame.later = new Set();
134
+ return;
135
+ }
136
+ case "parallel":
137
+ for (const task of node.tasks) visit(task, env, diagnostics);
138
+ return;
139
+ case "conditional":
140
+ visit(node.condition, env, diagnostics);
141
+ if (node.then) visit(node.then, env, diagnostics);
142
+ if (node.else) visit(node.else, env, diagnostics);
143
+ return;
144
+ case "try":
145
+ visit(node.try, env, diagnostics);
146
+ visit(node.catch, [...(env ?? []), frameOf([["error", node.error]])], diagnostics);
147
+ return;
148
+ case "and":
149
+ case "or":
150
+ for (const value of node.values) visit(value, env, diagnostics);
151
+ return;
152
+ case "map": {
153
+ visitItems(node.items, env, diagnostics);
154
+ // scopeWith({ [as]: item, index }): with `as: "index"`, the index replaces the item
155
+ if (node.fn) visit(node.fn, [...(env ?? []), frameOf([[node.item.name!, node.item], ["index", node.index]])], diagnostics);
156
+ return;
157
+ }
158
+ case "reduce": {
159
+ if (node.items) visitItems(node.items, env, diagnostics);
160
+ visit(node.initial, env, diagnostics);
161
+ if (node.fn) {
162
+ visit(node.fn, [...(env ?? []), frameOf([["acc", node.acc], ["item", node.item], ["index", node.index]])], diagnostics);
163
+ }
164
+ return;
165
+ }
166
+ }
167
+ }
168
+
169
+ /**
170
+ * This function examines the raw input of a procedure that runs refs (`dag.traverse`, `core.catch`).
171
+ * Its `$ref` values read the scope of the caller, or a name that the runner gives. An unknown
172
+ * name is a warning.
173
+ */
174
+ function scanRaw(node: IRNode, env: Env, diagnostics: Diagnostic[]): void {
175
+ if (node.kind !== "literal") return;
176
+ const seen = new Set<object>();
177
+ const walk = (value: unknown, pointer: Pointer): void => {
178
+ if (value === null || typeof value !== "object" || seen.has(value)) return;
179
+ seen.add(value);
180
+ if (isOutputRef(value)) {
181
+ const name = value.$ref.split(".")[0] ?? "";
182
+ if (env && !lookup(env, name)) {
183
+ diagnostics.push({
184
+ severity: "warning",
185
+ code: "unknown-name",
186
+ message: `No scope has the name "${name}" here. The procedure that runs this input can give the name, or the $ref fails.`,
187
+ pointer,
188
+ });
189
+ }
190
+ return;
191
+ }
192
+ if (Array.isArray(value)) value.forEach((item, index) => walk(item, childPointer(pointer, index)));
193
+ else if (isPlainObject(value)) for (const [key, item] of Object.entries(value)) walk(item, childPointer(pointer, key));
194
+ };
195
+ walk(node.value, node.pointer);
196
+ }
package/src/types.ts ADDED
@@ -0,0 +1,318 @@
1
+ /**
2
+ * The types and schemas of the procedures of this package: `program.check`, `program.compile`,
3
+ * `program.diagram`, `program.explain`, `sdk.openrpc` and `sdk.typescript`.
4
+ *
5
+ * mark procedure new adds the types of each new procedure here.
6
+ */
7
+
8
+ import { z } from "zod";
9
+ import type { Capability, PermittedEffects } from "@procedures/client/browser";
10
+ import type { Diagnostic } from "./diagnostics.js";
11
+
12
+ // =============================================================================
13
+ // Shared parts
14
+ // =============================================================================
15
+
16
+ /** The JSON form of a capability: the effects that the run can have. */
17
+ export interface CapabilityInput {
18
+ clearance?: unknown;
19
+ effects?:
20
+ | {
21
+ reads?: string[] | "any" | undefined;
22
+ writes?: string[] | "any" | undefined;
23
+ destructive?: boolean | undefined;
24
+ }
25
+ | undefined;
26
+ deadline?: number | undefined;
27
+ }
28
+
29
+ const PermitSchema = z.union([z.array(z.string()), z.literal("any")]);
30
+
31
+ /** The schema of a capability in the input of the procedures. */
32
+ export const CapabilityInputSchema: z.ZodType<CapabilityInput> = z
33
+ .object({
34
+ clearance: z.unknown().optional().describe("The clearance of the run"),
35
+ effects: z
36
+ .object({
37
+ reads: PermitSchema.optional().describe('The resources that a call can read: names, or "any"'),
38
+ writes: PermitSchema.optional().describe('The resources that a call can change: names, or "any". An empty list: no change.'),
39
+ destructive: z.boolean().optional().describe("False: a call cannot start a destructive procedure"),
40
+ })
41
+ .optional()
42
+ .describe("The effects that the calls can have. Absent: all effects."),
43
+ deadline: z.number().optional().describe("The deadline (the static check does not use it)"),
44
+ })
45
+ .describe("The capability of the run. Absent: the capability of the caller.") as z.ZodType<CapabilityInput>;
46
+
47
+ /** This function makes a capability from its JSON form. */
48
+ export function toCapability(input: CapabilityInput): Capability<unknown> {
49
+ const effects: { reads?: readonly string[] | "any"; writes?: readonly string[] | "any"; destructive?: boolean } = {};
50
+ if (input.effects?.reads !== undefined) effects.reads = input.effects.reads;
51
+ if (input.effects?.writes !== undefined) effects.writes = input.effects.writes;
52
+ if (input.effects?.destructive !== undefined) effects.destructive = input.effects.destructive;
53
+ return {
54
+ ...(input.clearance !== undefined ? { clearance: input.clearance } : {}),
55
+ ...(input.effects ? { effects: effects as PermittedEffects } : {}),
56
+ ...(input.deadline !== undefined ? { deadline: input.deadline } : {}),
57
+ };
58
+ }
59
+
60
+ /** The effects of a program, in the output of the procedures. */
61
+ export interface EffectsOutput {
62
+ reads?: string[] | undefined;
63
+ writes?: string[] | undefined;
64
+ destructive?: boolean | undefined;
65
+ idempotent?: boolean | undefined;
66
+ }
67
+
68
+ const EffectsOutputSchema = z
69
+ .object({
70
+ reads: z.array(z.string()).optional().describe("The resources that a run can read. Absent: not known."),
71
+ writes: z.array(z.string()).optional().describe("The resources that a run can change. Absent: not known."),
72
+ destructive: z.boolean().optional().describe("True: a call can delete or overwrite data"),
73
+ idempotent: z.boolean().optional().describe("True: each call that changes data is idempotent"),
74
+ })
75
+ .describe("The effects that a run can have (the upper bound)");
76
+
77
+ const MustEffectsSchema = z
78
+ .object({
79
+ reads: z.array(z.string()).describe("The resources that each run reads"),
80
+ writes: z.array(z.string()).describe("The resources that each run changes"),
81
+ })
82
+ .describe("The effects of each run in which no call fails (the lower bound)");
83
+
84
+ const DiagnosticSchema = z.object({
85
+ severity: z.enum(["error", "warning", "info"]).describe("An error stops the program"),
86
+ code: z.string().describe("The code of the problem, for example unknown-name"),
87
+ message: z.string().describe("The text of the problem"),
88
+ pointer: z.string().describe("The JSON pointer of the part of the program"),
89
+ });
90
+
91
+ const ProgramField = z.unknown().describe("The program: a call ({ $proc, input }). The procedure reads it as data: nothing in it starts.");
92
+ const ModeField = z
93
+ .enum(["exec", "body"])
94
+ .optional()
95
+ .describe("exec (the default): the program runs as client.exec runs it. body: as the body of a defined procedure, with input in scope.");
96
+
97
+ // =============================================================================
98
+ // program.check Types - Check a program before it runs
99
+ // =============================================================================
100
+
101
+ /** The input of `program.check`. */
102
+ export interface ProgramCheckInput {
103
+ program: unknown;
104
+ capability?: CapabilityInput | undefined;
105
+ mode?: "exec" | "body" | undefined;
106
+ }
107
+
108
+ export const ProgramCheckInputSchema: z.ZodType<ProgramCheckInput> = z.object({
109
+ program: ProgramField,
110
+ capability: CapabilityInputSchema.optional(),
111
+ mode: ModeField,
112
+ }) as z.ZodType<ProgramCheckInput>;
113
+
114
+ /** The output of `program.check`. */
115
+ export interface ProgramCheckOutput {
116
+ ok: boolean;
117
+ effects: EffectsOutput;
118
+ mustEffects: { reads: string[]; writes: string[] };
119
+ diagnostics: Diagnostic[];
120
+ registryHash: string;
121
+ }
122
+
123
+ const checkOutputFields = {
124
+ ok: z.boolean().describe("True when no diagnostic is an error: then the host can start the program"),
125
+ effects: EffectsOutputSchema,
126
+ mustEffects: MustEffectsSchema,
127
+ diagnostics: z.array(DiagnosticSchema).describe("The problems, in the order of the program"),
128
+ registryHash: z.string().describe("The hash of the manifest that the check used"),
129
+ };
130
+
131
+ export const ProgramCheckOutputSchema: z.ZodType<ProgramCheckOutput> = z.object(checkOutputFields) as z.ZodType<ProgramCheckOutput>;
132
+
133
+ // =============================================================================
134
+ // program.compile Types - Compile a program to a JavaScript function
135
+ // =============================================================================
136
+
137
+ /** The input of `program.compile`. */
138
+ export interface ProgramCompileInput extends ProgramCheckInput {
139
+ fold?: boolean | undefined;
140
+ language?: "js" | "ts" | undefined;
141
+ }
142
+
143
+ export const ProgramCompileInputSchema: z.ZodType<ProgramCompileInput> = z.object({
144
+ program: ProgramField,
145
+ capability: CapabilityInputSchema.optional(),
146
+ mode: ModeField,
147
+ fold: z.boolean().optional().describe("True: compute the pure core calls with literal inputs now"),
148
+ language: z.enum(["js", "ts"]).optional().describe("The language of the code: js (the default) or ts"),
149
+ }) as z.ZodType<ProgramCompileInput>;
150
+
151
+ /** The output of `program.compile`. */
152
+ export interface ProgramCompileOutput extends ProgramCheckOutput {
153
+ code: string;
154
+ sourceMap: Array<{ line: number; pointer: string }>;
155
+ folded: string[];
156
+ }
157
+
158
+ export const ProgramCompileOutputSchema: z.ZodType<ProgramCompileOutput> = z.object({
159
+ ...checkOutputFields,
160
+ code: z.string().describe("The ES module: its default export is async (ctx, input) => output"),
161
+ sourceMap: z
162
+ .array(z.object({ line: z.number().describe("The line of the code, from 1"), pointer: z.string().describe("The JSON pointer of the part of the program") }))
163
+ .describe("The lines of the code that start a part of the program"),
164
+ folded: z.array(z.string()).describe("The pointers of the calls that the fold pass computed"),
165
+ }) as z.ZodType<ProgramCompileOutput>;
166
+
167
+ // =============================================================================
168
+ // program.diagram Types - Draw a program as a Mermaid flowchart
169
+ // =============================================================================
170
+
171
+ /** The input of `program.diagram`. */
172
+ export interface ProgramDiagramInput {
173
+ program: unknown;
174
+ mode?: "exec" | "body" | undefined;
175
+ direction?: "TD" | "LR" | undefined;
176
+ }
177
+
178
+ export const ProgramDiagramInputSchema: z.ZodType<ProgramDiagramInput> = z.object({
179
+ program: ProgramField,
180
+ mode: ModeField,
181
+ direction: z.enum(["TD", "LR"]).optional().describe("The direction of the flowchart: TD (from the top down, the default) or LR (from left to right)"),
182
+ }) as z.ZodType<ProgramDiagramInput>;
183
+
184
+ /** The output of `program.diagram`. */
185
+ export interface ProgramDiagramOutput {
186
+ mermaid: string;
187
+ diagnostics: Diagnostic[];
188
+ }
189
+
190
+ export const ProgramDiagramOutputSchema: z.ZodType<ProgramDiagramOutput> = z.object({
191
+ mermaid: z.string().describe("The Mermaid flowchart of the program. A node with an error has the class error."),
192
+ diagnostics: z.array(DiagnosticSchema).describe("The problems that the check found, in the order of the program"),
193
+ }) as z.ZodType<ProgramDiagramOutput>;
194
+
195
+ // =============================================================================
196
+ // program.explain Types - Explain a program: its effects, each call and its refusal under the capability
197
+ // =============================================================================
198
+
199
+ /** The input of `program.explain`. */
200
+ export type ProgramExplainInput = ProgramCheckInput;
201
+
202
+ export const ProgramExplainInputSchema: z.ZodType<ProgramExplainInput> = z.object({
203
+ program: ProgramField,
204
+ capability: CapabilityInputSchema.optional(),
205
+ mode: ModeField,
206
+ }) as z.ZodType<ProgramExplainInput>;
207
+
208
+ /** The explanation of one call, in the output of `program.explain`. */
209
+ export interface CallExplanationOutput {
210
+ key: string;
211
+ path: string[];
212
+ pointer: string;
213
+ kind: "call" | "control" | "dynamic";
214
+ effects?: EffectsOutput | undefined;
215
+ known: boolean;
216
+ exposed: boolean;
217
+ permitted: boolean;
218
+ reason?: "effects-undeclared" | "effects-exceeded" | "clearance" | "deadline" | "not-found" | undefined;
219
+ message: string;
220
+ }
221
+
222
+ const DeclaredEffectsSchema = z
223
+ .object({
224
+ reads: z.array(z.string()).optional().describe("The resources that the procedure can read. Absent: not declared."),
225
+ writes: z.array(z.string()).optional().describe("The resources that the procedure can change. Absent: not declared."),
226
+ destructive: z.boolean().optional().describe("True: the procedure can delete or overwrite data"),
227
+ idempotent: z.boolean().optional().describe("True: a second call with the same input changes nothing more"),
228
+ })
229
+ .describe("The effects that the procedure declares. Absent: the procedure declares none.");
230
+
231
+ const CallExplanationSchema = z.object({
232
+ key: z.string().describe("The key of the procedure: its path with dots"),
233
+ path: z.array(z.string()).describe("The path of the procedure"),
234
+ pointer: z.string().describe("The JSON pointer of the call in the program"),
235
+ kind: z.enum(["call", "control", "dynamic"]).describe("call, a control-flow call, or a dynamic call whose input is a program"),
236
+ effects: DeclaredEffectsSchema.optional(),
237
+ known: z.boolean().describe("True when the host has a procedure at the path"),
238
+ exposed: z.boolean().describe("True when the host has the procedure and lets a program call it"),
239
+ permitted: z.boolean().describe("True when the capability permits the call"),
240
+ reason: z
241
+ .enum(["effects-undeclared", "effects-exceeded", "clearance", "deadline", "not-found"])
242
+ .optional()
243
+ .describe("The reason of a refusal, or not-found for a path without a procedure"),
244
+ message: z.string().describe("The answer of the capability in words"),
245
+ });
246
+
247
+ /** The output of `program.explain`. */
248
+ export interface ProgramExplainOutput extends ProgramCheckOutput {
249
+ calls: CallExplanationOutput[];
250
+ summary: string;
251
+ }
252
+
253
+ export const ProgramExplainOutputSchema: z.ZodType<ProgramExplainOutput> = z.object({
254
+ ...checkOutputFields,
255
+ calls: z.array(CallExplanationSchema).describe("The calls of the program, in the order of the tree: a call comes before the calls of its input"),
256
+ summary: z.string().describe("The explanation in short sentences"),
257
+ }) as z.ZodType<ProgramExplainOutput>;
258
+
259
+ // =============================================================================
260
+ // sdk.openrpc Types - Describe the procedures of the registry as an OpenRPC document
261
+ // =============================================================================
262
+
263
+ /** The input of `sdk.openrpc` and `sdk.typescript`. */
264
+ export interface SdkInput {
265
+ namespace?: string | undefined;
266
+ }
267
+
268
+ const SdkInputSchema: z.ZodType<SdkInput> = z.object({
269
+ namespace: z.string().optional().describe("Only the procedures under this first path segment"),
270
+ }) as z.ZodType<SdkInput>;
271
+
272
+ /** The input of `sdk.openrpc`. */
273
+ export type SdkOpenrpcInput = SdkInput;
274
+
275
+ export const SdkOpenrpcInputSchema: z.ZodType<SdkOpenrpcInput> = SdkInputSchema;
276
+
277
+ /** The output of `sdk.openrpc`: an OpenRPC 1.3 document. */
278
+ export interface SdkOpenrpcOutput {
279
+ openrpc: string;
280
+ info: { title: string; version: string; description?: string | undefined };
281
+ methods: Array<Record<string, unknown>>;
282
+ }
283
+
284
+ export const SdkOpenrpcOutputSchema: z.ZodType<SdkOpenrpcOutput> = z.object({
285
+ openrpc: z.string().describe("The version of the OpenRPC specification"),
286
+ info: z
287
+ .object({
288
+ title: z.string().describe("The title of the document"),
289
+ version: z.string().describe("The version of the document: the hash of the manifest"),
290
+ description: z.string().optional().describe("The description of the document"),
291
+ })
292
+ .describe("The information about the document"),
293
+ methods: z
294
+ .array(z.record(z.string(), z.unknown()))
295
+ .describe("One method for each procedure, in the order of the names: params, result, x-path and x-effects"),
296
+ }) as z.ZodType<SdkOpenrpcOutput>;
297
+
298
+ // =============================================================================
299
+ // sdk.typescript Types - Write a typed TypeScript SDK for the procedures of the registry
300
+ // =============================================================================
301
+
302
+ /** The input of `sdk.typescript`. */
303
+ export type SdkTypescriptInput = SdkInput;
304
+
305
+ export const SdkTypescriptInputSchema: z.ZodType<SdkTypescriptInput> = SdkInputSchema;
306
+
307
+ /** The output of `sdk.typescript`. */
308
+ export interface SdkTypescriptOutput {
309
+ code: string;
310
+ procedures: number;
311
+ registryHash: string;
312
+ }
313
+
314
+ export const SdkTypescriptOutputSchema: z.ZodType<SdkTypescriptOutput> = z.object({
315
+ code: z.string().describe("The source of the TypeScript module: the types, the interface Sdk and the function createSdk"),
316
+ procedures: z.number().describe("The number of procedures in the SDK"),
317
+ registryHash: z.string().describe("The hash of the manifest that the SDK comes from"),
318
+ }) as z.ZodType<SdkTypescriptOutput>;