@opencode/codemode 2.0.2 → 2.0.4

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 (71) hide show
  1. package/dist/codemode.d.ts +3 -0
  2. package/dist/codemode.js +12 -1
  3. package/dist/data.d.ts +14 -21
  4. package/dist/data.js +72 -140
  5. package/dist/extension.d.ts +11 -0
  6. package/dist/extension.js +9 -0
  7. package/dist/index.d.ts +1 -0
  8. package/dist/index.js +1 -0
  9. package/dist/interpreter/callback.d.ts +20 -0
  10. package/dist/interpreter/{runner.js → callback.js} +14 -14
  11. package/dist/interpreter/errors.d.ts +12 -5
  12. package/dist/interpreter/errors.js +66 -54
  13. package/dist/interpreter/execute.d.ts +2 -2
  14. package/dist/interpreter/execute.js +15 -15
  15. package/dist/interpreter/extensions.d.ts +8 -0
  16. package/dist/interpreter/extensions.js +155 -0
  17. package/dist/interpreter/generators.d.ts +2 -3
  18. package/dist/interpreter/generators.js +10 -10
  19. package/dist/interpreter/globals.d.ts +4 -12
  20. package/dist/interpreter/globals.js +56 -49
  21. package/dist/interpreter/interpreter.d.ts +34 -0
  22. package/dist/interpreter/{runtime.js → interpreter.js} +250 -215
  23. package/dist/interpreter/intrinsics.d.ts +5 -5
  24. package/dist/interpreter/intrinsics.js +16 -10
  25. package/dist/interpreter/limits.d.ts +10 -0
  26. package/dist/interpreter/limits.js +19 -0
  27. package/dist/interpreter/model.d.ts +27 -14
  28. package/dist/interpreter/model.js +22 -14
  29. package/dist/interpreter/native.d.ts +12 -13
  30. package/dist/interpreter/native.js +17 -16
  31. package/dist/interpreter/objects.d.ts +55 -48
  32. package/dist/interpreter/objects.js +64 -44
  33. package/dist/interpreter/promises.d.ts +13 -15
  34. package/dist/interpreter/promises.js +89 -85
  35. package/dist/interpreter/references.d.ts +1 -2
  36. package/dist/interpreter/references.js +18 -16
  37. package/dist/interpreter/scope.js +6 -6
  38. package/dist/openapi/types.d.ts +1 -1
  39. package/dist/stdlib/array.d.ts +3 -4
  40. package/dist/stdlib/array.js +115 -110
  41. package/dist/stdlib/bytes.d.ts +10 -0
  42. package/dist/stdlib/bytes.js +228 -0
  43. package/dist/stdlib/collections.d.ts +4 -4
  44. package/dist/stdlib/collections.js +89 -89
  45. package/dist/stdlib/console.d.ts +5 -3
  46. package/dist/stdlib/console.js +30 -37
  47. package/dist/stdlib/date.d.ts +2 -2
  48. package/dist/stdlib/date.js +35 -35
  49. package/dist/stdlib/json.d.ts +3 -3
  50. package/dist/stdlib/json.js +29 -67
  51. package/dist/stdlib/math.d.ts +3 -3
  52. package/dist/stdlib/math.js +17 -21
  53. package/dist/stdlib/number.d.ts +3 -3
  54. package/dist/stdlib/number.js +32 -36
  55. package/dist/stdlib/object.d.ts +5 -5
  56. package/dist/stdlib/object.js +59 -62
  57. package/dist/stdlib/regexp.d.ts +7 -8
  58. package/dist/stdlib/regexp.js +40 -48
  59. package/dist/stdlib/string.d.ts +2 -2
  60. package/dist/stdlib/string.js +110 -88
  61. package/dist/stdlib/url.d.ts +4 -6
  62. package/dist/stdlib/url.js +86 -90
  63. package/dist/stdlib/value.d.ts +3 -3
  64. package/dist/stdlib/value.js +26 -24
  65. package/dist/stdlib/web.d.ts +4 -4
  66. package/dist/stdlib/web.js +22 -8
  67. package/dist/tool-runtime.d.ts +12 -5
  68. package/dist/tool-runtime.js +25 -11
  69. package/package.json +1 -1
  70. package/dist/interpreter/runner.d.ts +0 -28
  71. 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";
@@ -59,12 +60,18 @@ export type SearchEntry = {
59
60
  /** Exact callable signature of the built-in `search` function, for host-owned instructions. */
60
61
  export declare const searchSignature: string;
61
62
  export declare const prepare: <R>(tools: Tools<R>) => Prepared<R>;
63
+ export declare class ToolRuntimeError extends Error {
64
+ readonly kind: Extract<DiagnosticKind, "UnknownTool" | "InvalidToolInput" | "InvalidToolOutput" | "ToolCallLimitExceeded">;
65
+ readonly suggestions: ReadonlyArray<string>;
66
+ constructor(kind: Extract<DiagnosticKind, "UnknownTool" | "InvalidToolInput" | "InvalidToolOutput" | "ToolCallLimitExceeded">, message: string, suggestions?: ReadonlyArray<string>);
67
+ }
68
+ /** The tool bridge of one execution. Arguments arrive and results leave as JSON; program values never enter. */
62
69
  export type ToolRuntime<R = never> = {
63
70
  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>;
71
+ readonly execute: (path: ReadonlyArray<string>, args: Array<Json | undefined>) => Effect.Effect<Json | undefined, unknown, R>;
72
+ readonly search: (args: Array<Json | undefined>) => Effect.Effect<Json | undefined, unknown, R>;
66
73
  readonly keys: (path: ReadonlyArray<string>) => ReadonlyArray<string>;
67
74
  };
68
75
  /** 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>;
76
+ export declare const make: <R>(prepared: Prepared<R>, maxToolCalls: number | undefined, hooks?: ToolCallHooks<R>) => ToolRuntime<R>;
70
77
  export * as ToolRuntime from "./tool-runtime.js";
@@ -1,5 +1,4 @@
1
1
  import { Cause, Effect, Exit, Formatter, Schema } from "effect";
2
- import { fromData, toData, ToolRuntimeError } from "./data.js";
3
2
  import { toolError } from "./tool-error.js";
4
3
  import { decodeInput as decodeToolInput, decodeOutput as decodeToolOutput, identifierSegment, inputProperties, inputTypeScript, isEmptyInput, outputTypeScript, } from "./tool-schema.js";
5
4
  import { isNamespace } from "./namespace.js";
@@ -183,8 +182,18 @@ const resolve = (root, path) => {
183
182
  }
184
183
  return node.tool;
185
184
  };
185
+ export class ToolRuntimeError extends Error {
186
+ kind;
187
+ suggestions;
188
+ constructor(kind, message, suggestions = []) {
189
+ super(message);
190
+ this.kind = kind;
191
+ this.suggestions = suggestions;
192
+ this.name = "ToolRuntimeError";
193
+ }
194
+ }
186
195
  /** Per-execution call state over tools prepared once for the runtime. */
187
- export const make = (prepared, prototypes, maxToolCalls, hooks) => {
196
+ export const make = (prepared, maxToolCalls, hooks) => {
188
197
  const calls = [];
189
198
  const root = prepared.root;
190
199
  const searchTool = makeSearchTool(prepared.searchIndex);
@@ -210,8 +219,8 @@ export const make = (prepared, prototypes, maxToolCalls, hooks) => {
210
219
  }
211
220
  calls.push(call);
212
221
  };
213
- const executeTool = (name, tool, externalArgs) => Effect.gen(function* () {
214
- const normalized = externalArgs.length === 0 ? [{}] : externalArgs;
222
+ const executeTool = (name, tool, args) => Effect.gen(function* () {
223
+ const normalized = args.length === 0 ? [{}] : args;
215
224
  if (normalized.length !== 1)
216
225
  throw new ToolRuntimeError("InvalidToolInput", `Tool '${name}' expects at most one input object.`);
217
226
  const input = yield* Effect.try({
@@ -233,8 +242,12 @@ export const make = (prepared, prototypes, maxToolCalls, hooks) => {
233
242
  .map((error) => (error.cause ? Formatter.format(error) : error.message || error.name))
234
243
  .join("\n")));
235
244
  }));
245
+ // The same round trip a tool result would take through text: exact JSON.stringify semantics.
236
246
  return yield* Effect.try({
237
- try: () => fromData(prototypes, decodeToolOutput(tool, raw), `Result from tool '${name}'`),
247
+ try: () => {
248
+ const text = JSON.stringify(decodeToolOutput(tool, raw));
249
+ return text === undefined ? undefined : JSON.parse(text);
250
+ },
238
251
  catch: (cause) => new ToolRuntimeError("InvalidToolOutput", `Invalid output from tool '${name}': ${cause}`),
239
252
  });
240
253
  }), call);
@@ -242,12 +255,13 @@ export const make = (prepared, prototypes, maxToolCalls, hooks) => {
242
255
  return {
243
256
  calls,
244
257
  keys: (path) => namespaceKeys(root, path),
245
- search: (args) => Effect.suspend(() => executeTool("search", searchTool, args.map((arg) => toData(arg, "Arguments for tool 'search'")))),
246
- execute: (path, args) => Effect.gen(function* () {
247
- const name = canonicalSegments(path).join(".");
248
- const externalArgs = args.map((arg) => toData(arg, `Arguments for tool '${name}'`));
249
- const tool = resolve(root, path);
250
- return yield* executeTool(name, tool, externalArgs);
258
+ search: (args) => Effect.suspend(() => executeTool("search", searchTool, args)),
259
+ execute: (path, args) => Effect.suspend(() => {
260
+ const segments = canonicalSegments(path);
261
+ // Models often write `tools.search(...)` for the bare `search(...)`; honor it unless a tool owns that path.
262
+ if (segments.length === 1 && segments[0] === "search" && lookup(root, segments) === undefined)
263
+ return executeTool("search", searchTool, args);
264
+ return executeTool(segments.join("."), resolve(root, path), args);
251
265
  }),
252
266
  };
253
267
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "@opencode/codemode",
4
- "version": "2.0.2",
4
+ "version": "2.0.4",
5
5
  "description": "Effect-native confined code execution over schema-described tools",
6
6
  "type": "module",
7
7
  "license": "MIT",