@opencode/codemode 2.0.3 → 2.0.5

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 (72) hide show
  1. package/README.md +5 -2
  2. package/dist/codemode.d.ts +7 -2
  3. package/dist/codemode.js +15 -2
  4. package/dist/data.d.ts +14 -21
  5. package/dist/data.js +72 -140
  6. package/dist/extension.d.ts +11 -0
  7. package/dist/extension.js +9 -0
  8. package/dist/index.d.ts +1 -0
  9. package/dist/index.js +1 -0
  10. package/dist/interpreter/callback.d.ts +20 -0
  11. package/dist/interpreter/{runner.js → callback.js} +14 -14
  12. package/dist/interpreter/errors.d.ts +12 -5
  13. package/dist/interpreter/errors.js +66 -54
  14. package/dist/interpreter/execute.d.ts +2 -2
  15. package/dist/interpreter/execute.js +15 -15
  16. package/dist/interpreter/extensions.d.ts +8 -0
  17. package/dist/interpreter/extensions.js +160 -0
  18. package/dist/interpreter/generators.d.ts +2 -3
  19. package/dist/interpreter/generators.js +10 -10
  20. package/dist/interpreter/globals.d.ts +4 -12
  21. package/dist/interpreter/globals.js +56 -49
  22. package/dist/interpreter/interpreter.d.ts +34 -0
  23. package/dist/interpreter/{runtime.js → interpreter.js} +250 -215
  24. package/dist/interpreter/intrinsics.d.ts +5 -5
  25. package/dist/interpreter/intrinsics.js +16 -10
  26. package/dist/interpreter/limits.d.ts +10 -0
  27. package/dist/interpreter/limits.js +19 -0
  28. package/dist/interpreter/model.d.ts +27 -14
  29. package/dist/interpreter/model.js +22 -14
  30. package/dist/interpreter/native.d.ts +12 -13
  31. package/dist/interpreter/native.js +17 -16
  32. package/dist/interpreter/objects.d.ts +55 -48
  33. package/dist/interpreter/objects.js +64 -44
  34. package/dist/interpreter/promises.d.ts +13 -15
  35. package/dist/interpreter/promises.js +89 -85
  36. package/dist/interpreter/references.d.ts +1 -2
  37. package/dist/interpreter/references.js +18 -16
  38. package/dist/interpreter/scope.js +6 -6
  39. package/dist/openapi/types.d.ts +1 -1
  40. package/dist/stdlib/array.d.ts +3 -4
  41. package/dist/stdlib/array.js +115 -110
  42. package/dist/stdlib/bytes.d.ts +10 -0
  43. package/dist/stdlib/bytes.js +228 -0
  44. package/dist/stdlib/collections.d.ts +4 -4
  45. package/dist/stdlib/collections.js +89 -89
  46. package/dist/stdlib/console.d.ts +5 -3
  47. package/dist/stdlib/console.js +30 -37
  48. package/dist/stdlib/date.d.ts +2 -2
  49. package/dist/stdlib/date.js +35 -35
  50. package/dist/stdlib/json.d.ts +3 -3
  51. package/dist/stdlib/json.js +29 -67
  52. package/dist/stdlib/math.d.ts +3 -3
  53. package/dist/stdlib/math.js +17 -21
  54. package/dist/stdlib/number.d.ts +3 -3
  55. package/dist/stdlib/number.js +32 -36
  56. package/dist/stdlib/object.d.ts +5 -5
  57. package/dist/stdlib/object.js +59 -62
  58. package/dist/stdlib/regexp.d.ts +7 -8
  59. package/dist/stdlib/regexp.js +40 -48
  60. package/dist/stdlib/string.d.ts +2 -2
  61. package/dist/stdlib/string.js +110 -88
  62. package/dist/stdlib/url.d.ts +4 -6
  63. package/dist/stdlib/url.js +86 -90
  64. package/dist/stdlib/value.d.ts +3 -3
  65. package/dist/stdlib/value.js +26 -24
  66. package/dist/stdlib/web.d.ts +4 -4
  67. package/dist/stdlib/web.js +22 -8
  68. package/dist/tool-runtime.d.ts +38 -19
  69. package/dist/tool-runtime.js +70 -48
  70. package/package.json +1 -1
  71. package/dist/interpreter/runner.d.ts +0 -28
  72. package/dist/interpreter/runtime.d.ts +0 -19
@@ -1,10 +1,9 @@
1
1
  import { Effect } from "effect";
2
- import { toProgram, ToolRuntimeError } from "../data.js";
3
2
  import { constructor, fn, methods, prototypeFrom, receiver, requiresNew } from "../interpreter/native.js";
4
- import { InterpreterRuntimeError, uriError } from "../interpreter/model.js";
5
- import { defineAccessor, entries, isWrapper, ProgramArray, ProgramObject, ProgramURL, ProgramURLSearchParams, } from "../interpreter/objects.js";
3
+ import { PendingThrow, typeError, uriError } from "../interpreter/model.js";
4
+ import { defineAccessor, entries, isWrapper, Arr, Obj, URLObj, URLSearchParamsObj } from "../interpreter/objects.js";
6
5
  import { isRuntimeReference } from "../interpreter/references.js";
7
- import { applyCollectionCallback, preserveConsumerError } from "../interpreter/runner.js";
6
+ import { applyCollectionCallback, preserveConsumerError } from "../interpreter/callback.js";
8
7
  import { coerceToString } from "./value.js";
9
8
  const urlProperties = [
10
9
  "href",
@@ -19,64 +18,63 @@ const urlProperties = [
19
18
  "search",
20
19
  "hash",
21
20
  ];
22
- export const uriArgument = (protos, value, label) => coerceToString(toProgram(protos, value, label));
23
21
  const uriFunctions = {
24
22
  encodeURI,
25
23
  encodeURIComponent,
26
24
  decodeURI,
27
25
  decodeURIComponent,
28
26
  };
29
- export const uriGlobal = (runner, name) => fn(runner.prototypes, name, 1, (_, args, node) => {
30
- const value = uriArgument(runner.prototypes, args[0], `${name} input`);
27
+ export const uriGlobal = (ctx, name) => fn(ctx.builtins, name, 1, (_, args) => {
28
+ const value = coerceToString(args[0]);
31
29
  try {
32
30
  return uriFunctions[name](value);
33
31
  }
34
32
  catch (error) {
35
- throw uriError(`${name} received malformed URI data: ${error instanceof Error ? error.message : String(error)}`, node);
33
+ throw uriError(`${name} received malformed URI data: ${error instanceof Error ? error.message : String(error)}`);
36
34
  }
37
35
  });
38
- const urlArgument = (protos, value, label) => value instanceof ProgramURL ? value.url.href : uriArgument(protos, value, label);
39
- export const urlGlobal = (runner) => {
40
- const protos = runner.prototypes;
41
- const proto = protos.URL;
42
- const construct = (args, into, node) => {
36
+ const urlArgument = (value) => (value instanceof URLObj ? value.url.href : coerceToString(value));
37
+ export const urlGlobal = (ctx) => {
38
+ const builtins = ctx.builtins;
39
+ const proto = builtins.URL;
40
+ const construct = (args, into) => {
43
41
  if (args.length === 0) {
44
- throw new InterpreterRuntimeError("new URL(...) requires a URL string and an optional base URL.", node);
42
+ throw typeError("new URL(...) requires a URL string and an optional base URL.");
45
43
  }
46
- const input = urlArgument(protos, args[0], "new URL input");
47
- const base = args[1] === undefined ? undefined : urlArgument(protos, args[1], "new URL base");
44
+ const input = urlArgument(args[0]);
45
+ const base = args[1] === undefined ? undefined : urlArgument(args[1]);
48
46
  try {
49
- return new ProgramURL(into, protos.URLSearchParams, new URL(input, base));
47
+ return new URLObj(into, builtins.URLSearchParams, new URL(input, base));
50
48
  }
51
49
  catch {
52
- throw new InterpreterRuntimeError(`new URL(...) received an invalid URL${base === undefined ? "" : " or base URL"}.`, node);
50
+ throw typeError(`new URL(...) received an invalid URL${base === undefined ? "" : " or base URL"}.`);
53
51
  }
54
52
  };
55
- const url = constructor(protos, proto, {
53
+ const url = constructor(builtins, proto, {
56
54
  name: "URL",
57
55
  length: 1,
58
56
  call: requiresNew("URL"),
59
- construct: (args, newTarget, node) => Effect.sync(() => construct(args, prototypeFrom(newTarget, proto), node)),
57
+ construct: (args, newTarget) => Effect.sync(() => construct(args, prototypeFrom(newTarget, proto))),
60
58
  });
61
59
  const parse = (name) => [
62
60
  name,
63
61
  1,
64
- (_, args, node) => {
62
+ (_, args) => {
65
63
  if (args.length === 0)
66
- throw new InterpreterRuntimeError(`URL.${name} requires a URL argument.`, node);
67
- const input = urlArgument(protos, args[0], `URL.${name} input`);
68
- const base = args[1] === undefined ? undefined : urlArgument(protos, args[1], `URL.${name} base`);
64
+ throw typeError(`URL.${name} requires a URL argument.`);
65
+ const input = urlArgument(args[0]);
66
+ const base = args[1] === undefined ? undefined : urlArgument(args[1]);
69
67
  try {
70
68
  const parsed = new URL(input, base);
71
- return name === "canParse" ? true : new ProgramURL(proto, protos.URLSearchParams, parsed);
69
+ return name === "canParse" ? true : new URLObj(proto, builtins.URLSearchParams, parsed);
72
70
  }
73
71
  catch {
74
72
  return name === "canParse" ? false : null;
75
73
  }
76
74
  },
77
75
  ];
78
- methods(protos, url, [parse("canParse"), parse("parse")]);
79
- const self = (thisValue, name, node) => receiver(ProgramURL, thisValue, `URL.prototype.${name}`, node);
76
+ methods(builtins, url, [parse("canParse"), parse("parse")]);
77
+ const self = (thisValue, name) => receiver(URLObj, thisValue, `URL.prototype.${name}`);
80
78
  for (const name of urlProperties) {
81
79
  defineAccessor(proto, name, (thisValue) => self(thisValue, name).url[name], name === "origin"
82
80
  ? undefined
@@ -84,40 +82,40 @@ export const urlGlobal = (runner) => {
84
82
  const target = self(thisValue, name);
85
83
  try {
86
84
  ;
87
- target.url[name] = uriArgument(protos, value, `URL.${name} value`);
85
+ target.url[name] = coerceToString(value);
88
86
  }
89
87
  catch (error) {
90
- if (error instanceof InterpreterRuntimeError || error instanceof ToolRuntimeError)
88
+ if (error instanceof PendingThrow)
91
89
  throw error;
92
- throw new InterpreterRuntimeError(`URL.${name} received an invalid value.`);
90
+ throw typeError(`URL.${name} received an invalid value.`);
93
91
  }
94
92
  });
95
93
  }
96
94
  defineAccessor(proto, "searchParams", (thisValue) => self(thisValue, "searchParams").searchParams);
97
- methods(protos, proto, [
98
- ["toString", 0, (thisValue, _, node) => self(thisValue, "toString", node).url.href],
99
- ["toJSON", 0, (thisValue, _, node) => self(thisValue, "toJSON", node).url.href],
95
+ methods(builtins, proto, [
96
+ ["toString", 0, (thisValue) => self(thisValue, "toString").url.href],
97
+ ["toJSON", 0, (thisValue) => self(thisValue, "toJSON").url.href],
100
98
  ]);
101
99
  return url;
102
100
  };
103
- const readPair = (runner, value, node) => Effect.gen(function* () {
104
- const cursor = yield* runner.syncIterator(value, node);
101
+ const readPair = (ctx, value) => Effect.gen(function* () {
102
+ const cursor = yield* ctx.iterate(value);
105
103
  if (cursor === undefined) {
106
- throw new InterpreterRuntimeError("new URLSearchParams(...) expects iterable [name, value] pairs.", node);
104
+ throw typeError("new URLSearchParams(...) expects iterable [name, value] pairs.");
107
105
  }
108
106
  const items = [];
109
107
  while (true) {
110
108
  const step = yield* cursor.next;
111
109
  if (step.done)
112
110
  return items;
113
- items.push(yield* preserveConsumerError(cursor, Effect.sync(() => uriArgument(runner.prototypes, step.value, "URLSearchParams pair value"))));
111
+ items.push(yield* preserveConsumerError(cursor, Effect.sync(() => coerceToString(step.value))));
114
112
  }
115
113
  });
116
- const constructURLSearchParams = (runner, init, proto, node) => {
117
- const wrap = (params) => new ProgramURLSearchParams(proto, params);
114
+ const constructURLSearchParams = (ctx, init, proto) => {
115
+ const wrap = (params) => new URLSearchParamsObj(proto, params);
118
116
  if (init === undefined)
119
117
  return Effect.succeed(wrap(new URLSearchParams()));
120
- if (init instanceof ProgramURLSearchParams)
118
+ if (init instanceof URLSearchParamsObj)
121
119
  return Effect.succeed(wrap(new URLSearchParams(init.params)));
122
120
  if (typeof init === "string")
123
121
  return Effect.succeed(wrap(new URLSearchParams(init)));
@@ -125,130 +123,128 @@ const constructURLSearchParams = (runner, init, proto, node) => {
125
123
  return Effect.succeed(wrap(new URLSearchParams(coerceToString(init))));
126
124
  }
127
125
  return Effect.gen(function* () {
128
- const cursor = yield* runner.syncIterator(init, node);
126
+ const cursor = yield* ctx.iterate(init);
129
127
  if (cursor !== undefined) {
130
128
  const pairs = [];
131
129
  while (true) {
132
130
  const step = yield* cursor.next;
133
131
  if (step.done) {
134
132
  if (pairs.some((entry) => entry.length !== 2)) {
135
- throw new InterpreterRuntimeError("new URLSearchParams(...) expects iterable [name, value] pairs.", node);
133
+ throw typeError("new URLSearchParams(...) expects iterable [name, value] pairs.");
136
134
  }
137
135
  return wrap(new URLSearchParams(pairs.map((entry) => [entry[0] ?? "", entry[1] ?? ""])));
138
136
  }
139
- pairs.push(yield* preserveConsumerError(cursor, readPair(runner, step.value, node)));
137
+ pairs.push(yield* preserveConsumerError(cursor, readPair(ctx, step.value)));
140
138
  }
141
139
  }
142
140
  if (isRuntimeReference(init)) {
143
- throw new InterpreterRuntimeError("new URLSearchParams(...) expects a query string, data object, or synchronous iterable pairs.", node);
141
+ throw typeError("new URLSearchParams(...) expects a query string, data object, or synchronous iterable pairs.");
144
142
  }
145
143
  if (isWrapper(init))
146
144
  return wrap(new URLSearchParams());
147
- if (!(init instanceof ProgramObject)) {
148
- throw new InterpreterRuntimeError("new URLSearchParams(...) expects a query string, data object, iterable pairs, or URLSearchParams.", node);
145
+ if (!(init instanceof Obj)) {
146
+ throw typeError("new URLSearchParams(...) expects a query string, data object, iterable pairs, or URLSearchParams.");
149
147
  }
150
148
  return wrap(new URLSearchParams(Object.fromEntries(entries(init).map(([key, value]) => [key, coerceToString(value)]))));
151
149
  });
152
150
  };
153
- export const urlSearchParamsGlobal = (runner) => {
154
- const protos = runner.prototypes;
155
- const proto = protos.URLSearchParams;
156
- const searchParams = constructor(protos, proto, {
151
+ export const urlSearchParamsGlobal = (ctx) => {
152
+ const builtins = ctx.builtins;
153
+ const proto = builtins.URLSearchParams;
154
+ const searchParams = constructor(builtins, proto, {
157
155
  name: "URLSearchParams",
158
156
  call: requiresNew("URLSearchParams"),
159
- construct: (args, newTarget, node) => constructURLSearchParams(runner, args[0], prototypeFrom(newTarget, proto), node),
157
+ construct: (args, newTarget) => constructURLSearchParams(ctx, args[0], prototypeFrom(newTarget, proto)),
160
158
  });
161
- const self = (thisValue, name, node) => receiver(ProgramURLSearchParams, thisValue, `URLSearchParams.prototype.${name}`, node);
162
- const wrap = (items) => new ProgramArray(protos.Array, items);
163
- const arg = (name, args, index) => uriArgument(protos, args[index], `URLSearchParams.${name} argument ${index + 1}`);
164
- const requireArgs = (name, args, count, node) => {
159
+ const self = (thisValue, name) => receiver(URLSearchParamsObj, thisValue, `URLSearchParams.prototype.${name}`);
160
+ const wrap = (items) => new Arr(builtins.Array, items);
161
+ const arg = (args, index) => coerceToString(args[index]);
162
+ const requireArgs = (name, args, count) => {
165
163
  if (args.length < count) {
166
- throw new InterpreterRuntimeError(`URLSearchParams.${name} requires ${count} argument${count === 1 ? "" : "s"}.`, node);
164
+ throw typeError(`URLSearchParams.${name} requires ${count} argument${count === 1 ? "" : "s"}.`);
167
165
  }
168
166
  };
169
167
  defineAccessor(proto, "size", (thisValue) => self(thisValue, "size").params.size);
170
- methods(protos, proto, [
168
+ methods(builtins, proto, [
171
169
  [
172
170
  "append",
173
171
  2,
174
- (thisValue, args, node) => {
175
- requireArgs("append", args, 2, node);
176
- self(thisValue, "append", node).params.append(arg("append", args, 0), arg("append", args, 1));
172
+ (thisValue, args) => {
173
+ requireArgs("append", args, 2);
174
+ self(thisValue, "append").params.append(arg(args, 0), arg(args, 1));
177
175
  return undefined;
178
176
  },
179
177
  ],
180
178
  [
181
179
  "delete",
182
180
  1,
183
- (thisValue, args, node) => {
184
- requireArgs("delete", args, 1, node);
185
- const params = self(thisValue, "delete", node).params;
181
+ (thisValue, args) => {
182
+ requireArgs("delete", args, 1);
183
+ const params = self(thisValue, "delete").params;
186
184
  if (args[1] !== undefined)
187
- params.delete(arg("delete", args, 0), arg("delete", args, 1));
185
+ params.delete(arg(args, 0), arg(args, 1));
188
186
  else
189
- params.delete(arg("delete", args, 0));
187
+ params.delete(arg(args, 0));
190
188
  return undefined;
191
189
  },
192
190
  ],
193
191
  [
194
192
  "get",
195
193
  1,
196
- (thisValue, args, node) => {
197
- requireArgs("get", args, 1, node);
198
- return self(thisValue, "get", node).params.get(arg("get", args, 0));
194
+ (thisValue, args) => {
195
+ requireArgs("get", args, 1);
196
+ return self(thisValue, "get").params.get(arg(args, 0));
199
197
  },
200
198
  ],
201
199
  [
202
200
  "getAll",
203
201
  1,
204
- (thisValue, args, node) => {
205
- requireArgs("getAll", args, 1, node);
206
- return wrap(self(thisValue, "getAll", node).params.getAll(arg("getAll", args, 0)));
202
+ (thisValue, args) => {
203
+ requireArgs("getAll", args, 1);
204
+ return wrap(self(thisValue, "getAll").params.getAll(arg(args, 0)));
207
205
  },
208
206
  ],
209
207
  [
210
208
  "has",
211
209
  1,
212
- (thisValue, args, node) => {
213
- requireArgs("has", args, 1, node);
214
- const params = self(thisValue, "has", node).params;
215
- return args[1] !== undefined
216
- ? params.has(arg("has", args, 0), arg("has", args, 1))
217
- : params.has(arg("has", args, 0));
210
+ (thisValue, args) => {
211
+ requireArgs("has", args, 1);
212
+ const params = self(thisValue, "has").params;
213
+ return args[1] !== undefined ? params.has(arg(args, 0), arg(args, 1)) : params.has(arg(args, 0));
218
214
  },
219
215
  ],
220
216
  [
221
217
  "set",
222
218
  2,
223
- (thisValue, args, node) => {
224
- requireArgs("set", args, 2, node);
225
- self(thisValue, "set", node).params.set(arg("set", args, 0), arg("set", args, 1));
219
+ (thisValue, args) => {
220
+ requireArgs("set", args, 2);
221
+ self(thisValue, "set").params.set(arg(args, 0), arg(args, 1));
226
222
  return undefined;
227
223
  },
228
224
  ],
229
225
  [
230
226
  "sort",
231
227
  0,
232
- (thisValue, _, node) => {
233
- self(thisValue, "sort", node).params.sort();
228
+ (thisValue) => {
229
+ self(thisValue, "sort").params.sort();
234
230
  return undefined;
235
231
  },
236
232
  ],
237
- ["keys", 0, (thisValue, _, node) => wrap(Array.from(self(thisValue, "keys", node).params.keys()))],
238
- ["values", 0, (thisValue, _, node) => wrap(Array.from(self(thisValue, "values", node).params.values()))],
233
+ ["keys", 0, (thisValue) => wrap(Array.from(self(thisValue, "keys").params.keys()))],
234
+ ["values", 0, (thisValue) => wrap(Array.from(self(thisValue, "values").params.values()))],
239
235
  [
240
236
  "entries",
241
237
  0,
242
- (thisValue, _, node) => wrap(Array.from(self(thisValue, "entries", node).params.entries(), ([key, value]) => wrap([key, value]))),
238
+ (thisValue) => wrap(Array.from(self(thisValue, "entries").params.entries(), ([key, value]) => wrap([key, value]))),
243
239
  ],
244
- ["toString", 0, (thisValue, _, node) => self(thisValue, "toString", node).params.toString()],
240
+ ["toString", 0, (thisValue) => self(thisValue, "toString").params.toString()],
245
241
  [
246
242
  "forEach",
247
243
  1,
248
- (thisValue, args, node) => {
249
- requireArgs("forEach", args, 1, node);
250
- const target = self(thisValue, "forEach", node);
251
- const apply = applyCollectionCallback(runner, args[0], "URLSearchParams.forEach", node);
244
+ (thisValue, args) => {
245
+ requireArgs("forEach", args, 1);
246
+ const target = self(thisValue, "forEach");
247
+ const apply = applyCollectionCallback(ctx, args[0], "URLSearchParams.forEach");
252
248
  return Effect.gen(function* () {
253
249
  for (const [key, value] of Array.from(target.params.entries()))
254
250
  yield* apply([value, key, target]);
@@ -1,9 +1,9 @@
1
- import { type NativeFunction } from "../interpreter/objects.js";
2
- import type { Runner } from "../interpreter/runner.js";
1
+ import { type Native } from "../interpreter/objects.js";
2
+ import type { Interpreter } from "../interpreter/interpreter.js";
3
3
  export declare const compoundOperators: Set<string>;
4
4
  /** The built-in string form of a value, without consulting program-defined `toString` methods. */
5
5
  export declare const coerceToString: (value: unknown) => string;
6
6
  export declare const coerceToNumber: (value: unknown) => number;
7
7
  export type Coercion = "Number" | "String" | "Boolean" | "parseInt" | "parseFloat" | "isFinite" | "isNaN";
8
8
  /** A global coercion function such as `Number` or `parseInt`. */
9
- export declare const coercion: <R>(runner: Runner<R>, name: Coercion, length?: number) => NativeFunction<R>;
9
+ export declare const coercion: <R>(ctx: Interpreter<R>, name: Coercion, length?: number) => Native<R>;
@@ -1,7 +1,6 @@
1
- import { toProgram } from "../data.js";
2
1
  import { fn } from "../interpreter/native.js";
3
- import { InterpreterRuntimeError } from "../interpreter/model.js";
4
- import { get, isWrapper, ProgramArray, ProgramDate, ProgramError, ProgramMap, ProgramRegExp, ProgramSet, ProgramURL, ProgramURLSearchParams, } from "../interpreter/objects.js";
2
+ import { typeError } from "../interpreter/model.js";
3
+ import { get, isWrapper, Arr, Bytes, DateObj, ErrorObj, MapObj, RegExpObj, SetObj, URLObj, URLSearchParamsObj, } from "../interpreter/objects.js";
5
4
  export const compoundOperators = new Set(["+=", "-=", "*=", "/=", "%=", "**=", "&=", "|=", "^=", "<<=", ">>=", ">>>="]);
6
5
  /** The built-in string form of a value, without consulting program-defined `toString` methods. */
7
6
  export const coerceToString = (value) => {
@@ -9,19 +8,21 @@ export const coerceToString = (value) => {
9
8
  return "null";
10
9
  if (value === undefined)
11
10
  return "undefined";
12
- if (value instanceof ProgramDate)
11
+ if (value instanceof DateObj)
13
12
  return Number.isFinite(value.time) ? new Date(value.time).toISOString() : "Invalid Date";
14
- if (value instanceof ProgramRegExp)
13
+ if (value instanceof RegExpObj)
15
14
  return `/${value.regex.source}/${value.regex.flags}`;
16
- if (value instanceof ProgramMap)
15
+ if (value instanceof MapObj)
17
16
  return "[object Map]";
18
- if (value instanceof ProgramSet)
17
+ if (value instanceof SetObj)
19
18
  return "[object Set]";
20
- if (value instanceof ProgramURL)
19
+ if (value instanceof URLObj)
21
20
  return value.url.href;
22
- if (value instanceof ProgramURLSearchParams)
21
+ if (value instanceof URLSearchParamsObj)
23
22
  return value.params.toString();
24
- if (value instanceof ProgramError) {
23
+ if (value instanceof Bytes)
24
+ return value.bytes.join(",");
25
+ if (value instanceof ErrorObj) {
25
26
  // Match Error.prototype.toString: "name: message", or just one when the other is empty.
26
27
  const name = get(value, "name");
27
28
  const message = get(value, "message");
@@ -33,7 +34,7 @@ export const coerceToString = (value) => {
33
34
  return shownMessage;
34
35
  return `${shownName}: ${shownMessage}`;
35
36
  }
36
- if (value instanceof ProgramArray) {
37
+ if (value instanceof Arr) {
37
38
  return value.items.map((item) => (item === null || item === undefined ? "" : coerceToString(item))).join(",");
38
39
  }
39
40
  if (typeof value === "object")
@@ -41,15 +42,17 @@ export const coerceToString = (value) => {
41
42
  return String(value);
42
43
  };
43
44
  export const coerceToNumber = (value) => {
44
- if (value instanceof ProgramDate)
45
+ if (value instanceof DateObj)
45
46
  return value.time;
47
+ if (value instanceof Bytes)
48
+ return Number(coerceToString(value));
46
49
  if (isWrapper(value))
47
50
  return Number.NaN;
48
- if (value instanceof ProgramArray)
51
+ if (value instanceof Arr)
49
52
  return Number(coerceToString(value));
50
53
  return value !== null && typeof value === "object" ? Number.NaN : Number(value);
51
54
  };
52
- const coerce = (runner, name, args, node) => {
55
+ const coerce = (ctx, name, args) => {
53
56
  // Native: Number() is 0 and String() is "", unlike their undefined-argument forms; the
54
57
  // other coercers match native through the undefined-argument path below.
55
58
  if (args.length === 0) {
@@ -74,25 +77,24 @@ const coerce = (runner, name, args, node) => {
74
77
  return parseInt(coerceToString(raw));
75
78
  return parseFloat(coerceToString(raw));
76
79
  }
77
- const value = toProgram(runner.prototypes, raw, `${name} input`);
78
80
  if (name === "Number")
79
- return coerceToNumber(value);
81
+ return coerceToNumber(raw);
80
82
  if (name === "Boolean")
81
- return Boolean(value);
83
+ return Boolean(raw);
82
84
  if (name === "isFinite")
83
- return Number.isFinite(coerceToNumber(value));
85
+ return Number.isFinite(coerceToNumber(raw));
84
86
  if (name === "isNaN")
85
- return Number.isNaN(coerceToNumber(value));
87
+ return Number.isNaN(coerceToNumber(raw));
86
88
  if (name === "parseInt") {
87
89
  const radix = args[1];
88
90
  if (radix !== undefined && typeof radix !== "number") {
89
- throw new InterpreterRuntimeError("parseInt expects a numeric radix.", node);
91
+ throw typeError("parseInt expects a numeric radix.");
90
92
  }
91
- return parseInt(coerceToString(value), radix);
93
+ return parseInt(coerceToString(raw), radix);
92
94
  }
93
95
  if (name === "parseFloat")
94
- return parseFloat(coerceToString(value));
95
- return coerceToString(value);
96
+ return parseFloat(coerceToString(raw));
97
+ return coerceToString(raw);
96
98
  };
97
99
  /** A global coercion function such as `Number` or `parseInt`. */
98
- export const coercion = (runner, name, length = 1) => fn(runner.prototypes, name, length, (_, args, node) => toProgram(runner.prototypes, coerce(runner, name, args, node), `${name} result`));
100
+ export const coercion = (ctx, name, length = 1) => fn(ctx.builtins, name, length, (_, args) => coerce(ctx, name, args));
@@ -1,4 +1,4 @@
1
- import { ProgramObject } from "../interpreter/objects.js";
2
- import type { Runner } from "../interpreter/runner.js";
3
- export declare const base64Global: <R>(runner: Runner<R>, name: "atob" | "btoa") => import("../interpreter/objects.js").NativeFunction<R>;
4
- export declare const cryptoGlobal: <R>(runner: Runner<R>) => ProgramObject;
1
+ import { Obj } from "../interpreter/objects.js";
2
+ import type { Interpreter } from "../interpreter/interpreter.js";
3
+ export declare const base64Global: <R>(ctx: Interpreter<R>, name: "atob" | "btoa") => import("../interpreter/objects.js").Native<R>;
4
+ export declare const cryptoGlobal: <R>(ctx: Interpreter<R>) => Obj;
@@ -1,22 +1,36 @@
1
1
  import { fn, methods } from "../interpreter/native.js";
2
- import { InterpreterRuntimeError } from "../interpreter/model.js";
3
- import { ProgramObject } from "../interpreter/objects.js";
2
+ import { typeError } from "../interpreter/model.js";
3
+ import { Bytes, Obj } from "../interpreter/objects.js";
4
+ import { describeValue } from "../interpreter/references.js";
4
5
  import { coerceToString } from "./value.js";
5
6
  // WebIDL DOMString conversion: a missing argument is a TypeError, anything else stringifies. Invalid input is a
6
7
  // TypeError as well; browsers throw a DOMException named InvalidCharacterError, which CodeMode does not have.
7
- export const base64Global = (runner, name) => fn(runner.prototypes, name, 1, (_, args, node) => {
8
+ export const base64Global = (ctx, name) => fn(ctx.builtins, name, 1, (_, args) => {
8
9
  if (args.length === 0)
9
- throw new InterpreterRuntimeError(`${name} requires 1 argument (a string)`, node);
10
+ throw typeError(`${name} requires 1 argument (a string)`);
10
11
  const input = coerceToString(args[0]);
11
12
  try {
12
13
  return name === "atob" ? atob(input) : btoa(input);
13
14
  }
14
15
  catch {
15
- throw new InterpreterRuntimeError("The string contains invalid characters.", node);
16
+ throw typeError("The string contains invalid characters.");
16
17
  }
17
18
  });
18
- export const cryptoGlobal = (runner) => {
19
- const object = new ProgramObject(runner.prototypes.Object);
20
- methods(runner.prototypes, object, [["randomUUID", 0, () => crypto.randomUUID()]]);
19
+ export const cryptoGlobal = (ctx) => {
20
+ const object = new Obj(ctx.builtins.Object);
21
+ methods(ctx.builtins, object, [
22
+ ["randomUUID", 0, () => crypto.randomUUID()],
23
+ [
24
+ "getRandomValues",
25
+ 1,
26
+ (_, args) => {
27
+ if (!(args[0] instanceof Bytes)) {
28
+ throw typeError(`crypto.getRandomValues expects a Uint8Array, received ${describeValue(args[0])}.`);
29
+ }
30
+ crypto.getRandomValues(args[0].bytes);
31
+ return args[0];
32
+ },
33
+ ],
34
+ ]);
21
35
  return object;
22
36
  };
@@ -1,9 +1,10 @@
1
1
  import { Effect } from "effect";
2
- import type { Prototypes } from "./interpreter/intrinsics.js";
2
+ import type { Json } from "./data.js";
3
+ import type { DiagnosticKind } from "./codemode.js";
3
4
  import { type Namespace } from "./namespace.js";
4
5
  import { type Tool } from "./tool.js";
5
6
  import type { Tools } from "./tools.js";
6
- export declare const compareText: (left: string, right: string) => 1 | -1 | 0;
7
+ export declare const compareText: (left: string, right: string) => 0 | 1 | -1;
7
8
  export type Services<T> = ServicesOf<T, []>;
8
9
  type ServicesOf<T, Depth extends ReadonlyArray<unknown>> = Depth["length"] extends 8 ? never : T extends {
9
10
  readonly _tag: "CodeModeTool";
@@ -12,25 +13,36 @@ type ServicesOf<T, Depth extends ReadonlyArray<unknown>> = Depth["length"] exten
12
13
  export type ToolCall = {
13
14
  readonly name: string;
14
15
  };
15
- export type ToolCallStarted = {
16
- readonly index: number;
16
+ /** A tool call the program is making, with its decoded input. */
17
+ export type ToolInvocation = {
17
18
  readonly name: string;
18
19
  readonly input: unknown;
19
20
  };
20
- export type ToolCallEnded = {
21
- readonly index: number;
21
+ /** A call the program is making to an extension global, with its arguments. */
22
+ export type ExtensionInvocation = {
23
+ readonly extension: string;
22
24
  readonly name: string;
23
- readonly input: unknown;
24
- readonly durationMs: number;
25
- readonly outcome: "success" | "failure" | "interrupted";
26
- readonly message?: string;
25
+ readonly args: ReadonlyArray<unknown>;
26
+ };
27
+ /** How a call ended; `after` hooks observe it and cannot change it. */
28
+ export type CallResult = {
29
+ readonly status: "success";
30
+ readonly value: unknown;
31
+ } | {
32
+ readonly status: "failure";
33
+ readonly error: unknown;
34
+ } | {
35
+ readonly status: "interrupted";
27
36
  };
28
- export type ToolCallHooks<R = never> = {
29
- /** Observes decoded tool input immediately before tool execution. */
30
- readonly onToolCallStart?: ((call: ToolCallStarted) => Effect.Effect<void, never, R>) | undefined;
31
- /** Observes each admitted tool call as it succeeds, fails, or is interrupted. */
32
- readonly onToolCallEnd?: ((call: ToolCallEnded) => Effect.Effect<void, never, R>) | undefined;
37
+ /** Hooks around every call the program makes into the host. A failing `before` denies the call. */
38
+ export type Hooks<R = never> = {
39
+ readonly "tool.before"?: ((call: ToolInvocation) => Effect.Effect<void, unknown, R>) | undefined;
40
+ readonly "tool.after"?: ((call: ToolInvocation, result: CallResult) => Effect.Effect<void, never, R>) | undefined;
41
+ readonly "extension.before"?: ((call: ExtensionInvocation) => Effect.Effect<void, unknown, R>) | undefined;
42
+ readonly "extension.after"?: ((call: ExtensionInvocation, result: CallResult) => Effect.Effect<void, never, R>) | undefined;
33
43
  };
44
+ /** Runs `before`, then `run`, then `after` with how it ended, including when interrupted. */
45
+ export declare const hooked: <Call, A, R>(call: Call, before: ((call: Call) => Effect.Effect<void, unknown, R>) | undefined, after: ((call: Call, result: CallResult) => Effect.Effect<void, never, R>) | undefined, run: Effect.Effect<A, unknown, R>) => Effect.Effect<A, unknown, R>;
34
46
  export type ToolDescription = {
35
47
  readonly path: string;
36
48
  readonly description: string;
@@ -46,7 +58,7 @@ type ToolNode<R> = {
46
58
  namespace?: Namespace<R>;
47
59
  readonly children: Map<string, ToolNode<R>>;
48
60
  };
49
- /** Tools indexed once per runtime: the lookup trie plus the model-facing catalog and search index. */
61
+ /** Tools indexed once per runtime, with discovery materialized on demand. */
50
62
  export type Prepared<R = never> = {
51
63
  readonly root: ToolNode<R>;
52
64
  readonly catalog: ReadonlyArray<ToolDescription>;
@@ -59,12 +71,19 @@ export type SearchEntry = {
59
71
  /** Exact callable signature of the built-in `search` function, for host-owned instructions. */
60
72
  export declare const searchSignature: string;
61
73
  export declare const prepare: <R>(tools: Tools<R>) => Prepared<R>;
74
+ export declare class ToolRuntimeError extends Error {
75
+ readonly kind: Extract<DiagnosticKind, "UnknownTool" | "InvalidToolInput" | "InvalidToolOutput" | "ToolCallLimitExceeded">;
76
+ readonly suggestions: ReadonlyArray<string>;
77
+ constructor(kind: Extract<DiagnosticKind, "UnknownTool" | "InvalidToolInput" | "InvalidToolOutput" | "ToolCallLimitExceeded">, message: string, suggestions?: ReadonlyArray<string>);
78
+ }
79
+ /** The tool bridge of one execution. Arguments arrive and results leave as JSON; program values never enter. */
62
80
  export type ToolRuntime<R = never> = {
63
81
  readonly calls: Array<ToolCall>;
64
- readonly execute: (path: ReadonlyArray<string>, args: Array<unknown>) => Effect.Effect<unknown, unknown, R>;
65
- readonly search: (args: Array<unknown>) => Effect.Effect<unknown, unknown, R>;
82
+ readonly hooks: Hooks<R>;
83
+ readonly execute: (path: ReadonlyArray<string>, args: Array<Json | undefined>) => Effect.Effect<Json | undefined, unknown, R>;
84
+ readonly search: (args: Array<Json | undefined>) => Effect.Effect<Json | undefined, unknown, R>;
66
85
  readonly keys: (path: ReadonlyArray<string>) => ReadonlyArray<string>;
67
86
  };
68
87
  /** Per-execution call state over tools prepared once for the runtime. */
69
- export declare const make: <R>(prepared: Prepared<R>, prototypes: Prototypes, maxToolCalls: number | undefined, hooks?: ToolCallHooks<R>) => ToolRuntime<R>;
88
+ export declare const make: <R>(prepared: Prepared<R>, maxToolCalls: number | undefined, hooks?: Hooks<R>) => ToolRuntime<R>;
70
89
  export * as ToolRuntime from "./tool-runtime.js";