@opencode/codemode 2.0.3 → 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.
- package/dist/codemode.d.ts +3 -0
- package/dist/codemode.js +12 -1
- package/dist/data.d.ts +14 -21
- package/dist/data.js +72 -140
- package/dist/extension.d.ts +11 -0
- package/dist/extension.js +9 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/interpreter/callback.d.ts +20 -0
- package/dist/interpreter/{runner.js → callback.js} +14 -14
- package/dist/interpreter/errors.d.ts +12 -5
- package/dist/interpreter/errors.js +66 -54
- package/dist/interpreter/execute.d.ts +2 -2
- package/dist/interpreter/execute.js +15 -15
- package/dist/interpreter/extensions.d.ts +8 -0
- package/dist/interpreter/extensions.js +155 -0
- package/dist/interpreter/generators.d.ts +2 -3
- package/dist/interpreter/generators.js +10 -10
- package/dist/interpreter/globals.d.ts +4 -12
- package/dist/interpreter/globals.js +56 -49
- package/dist/interpreter/interpreter.d.ts +34 -0
- package/dist/interpreter/{runtime.js → interpreter.js} +250 -215
- package/dist/interpreter/intrinsics.d.ts +5 -5
- package/dist/interpreter/intrinsics.js +16 -10
- package/dist/interpreter/limits.d.ts +10 -0
- package/dist/interpreter/limits.js +19 -0
- package/dist/interpreter/model.d.ts +27 -14
- package/dist/interpreter/model.js +22 -14
- package/dist/interpreter/native.d.ts +12 -13
- package/dist/interpreter/native.js +17 -16
- package/dist/interpreter/objects.d.ts +55 -48
- package/dist/interpreter/objects.js +64 -44
- package/dist/interpreter/promises.d.ts +13 -15
- package/dist/interpreter/promises.js +89 -85
- package/dist/interpreter/references.d.ts +1 -2
- package/dist/interpreter/references.js +18 -16
- package/dist/interpreter/scope.js +6 -6
- package/dist/openapi/types.d.ts +1 -1
- package/dist/stdlib/array.d.ts +3 -4
- package/dist/stdlib/array.js +115 -110
- package/dist/stdlib/bytes.d.ts +10 -0
- package/dist/stdlib/bytes.js +228 -0
- package/dist/stdlib/collections.d.ts +4 -4
- package/dist/stdlib/collections.js +89 -89
- package/dist/stdlib/console.d.ts +5 -3
- package/dist/stdlib/console.js +30 -37
- package/dist/stdlib/date.d.ts +2 -2
- package/dist/stdlib/date.js +35 -35
- package/dist/stdlib/json.d.ts +3 -3
- package/dist/stdlib/json.js +29 -67
- package/dist/stdlib/math.d.ts +3 -3
- package/dist/stdlib/math.js +17 -21
- package/dist/stdlib/number.d.ts +3 -3
- package/dist/stdlib/number.js +32 -36
- package/dist/stdlib/object.d.ts +5 -5
- package/dist/stdlib/object.js +59 -62
- package/dist/stdlib/regexp.d.ts +7 -8
- package/dist/stdlib/regexp.js +40 -48
- package/dist/stdlib/string.d.ts +2 -2
- package/dist/stdlib/string.js +110 -88
- package/dist/stdlib/url.d.ts +4 -6
- package/dist/stdlib/url.js +86 -90
- package/dist/stdlib/value.d.ts +3 -3
- package/dist/stdlib/value.js +26 -24
- package/dist/stdlib/web.d.ts +4 -4
- package/dist/stdlib/web.js +22 -8
- package/dist/tool-runtime.d.ts +12 -5
- package/dist/tool-runtime.js +25 -11
- package/package.json +1 -1
- package/dist/interpreter/runner.d.ts +0 -28
- package/dist/interpreter/runtime.d.ts +0 -19
package/dist/stdlib/url.js
CHANGED
|
@@ -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 {
|
|
5
|
-
import { defineAccessor, entries, isWrapper,
|
|
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/
|
|
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 = (
|
|
30
|
-
const value =
|
|
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)}
|
|
33
|
+
throw uriError(`${name} received malformed URI data: ${error instanceof Error ? error.message : String(error)}`);
|
|
36
34
|
}
|
|
37
35
|
});
|
|
38
|
-
const urlArgument = (
|
|
39
|
-
export const urlGlobal = (
|
|
40
|
-
const
|
|
41
|
-
const proto =
|
|
42
|
-
const construct = (args, into
|
|
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
|
|
42
|
+
throw typeError("new URL(...) requires a URL string and an optional base URL.");
|
|
45
43
|
}
|
|
46
|
-
const input = urlArgument(
|
|
47
|
-
const base = args[1] === undefined ? undefined : urlArgument(
|
|
44
|
+
const input = urlArgument(args[0]);
|
|
45
|
+
const base = args[1] === undefined ? undefined : urlArgument(args[1]);
|
|
48
46
|
try {
|
|
49
|
-
return new
|
|
47
|
+
return new URLObj(into, builtins.URLSearchParams, new URL(input, base));
|
|
50
48
|
}
|
|
51
49
|
catch {
|
|
52
|
-
throw
|
|
50
|
+
throw typeError(`new URL(...) received an invalid URL${base === undefined ? "" : " or base URL"}.`);
|
|
53
51
|
}
|
|
54
52
|
};
|
|
55
|
-
const url = constructor(
|
|
53
|
+
const url = constructor(builtins, proto, {
|
|
56
54
|
name: "URL",
|
|
57
55
|
length: 1,
|
|
58
56
|
call: requiresNew("URL"),
|
|
59
|
-
construct: (args, newTarget
|
|
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
|
|
62
|
+
(_, args) => {
|
|
65
63
|
if (args.length === 0)
|
|
66
|
-
throw
|
|
67
|
-
const input = urlArgument(
|
|
68
|
-
const base = args[1] === undefined ? undefined : urlArgument(
|
|
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
|
|
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(
|
|
79
|
-
const self = (thisValue, name
|
|
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] =
|
|
85
|
+
target.url[name] = coerceToString(value);
|
|
88
86
|
}
|
|
89
87
|
catch (error) {
|
|
90
|
-
if (error instanceof
|
|
88
|
+
if (error instanceof PendingThrow)
|
|
91
89
|
throw error;
|
|
92
|
-
throw
|
|
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(
|
|
98
|
-
["toString", 0, (thisValue
|
|
99
|
-
["toJSON", 0, (thisValue
|
|
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 = (
|
|
104
|
-
const cursor = yield*
|
|
101
|
+
const readPair = (ctx, value) => Effect.gen(function* () {
|
|
102
|
+
const cursor = yield* ctx.iterate(value);
|
|
105
103
|
if (cursor === undefined) {
|
|
106
|
-
throw
|
|
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(() =>
|
|
111
|
+
items.push(yield* preserveConsumerError(cursor, Effect.sync(() => coerceToString(step.value))));
|
|
114
112
|
}
|
|
115
113
|
});
|
|
116
|
-
const constructURLSearchParams = (
|
|
117
|
-
const wrap = (params) => new
|
|
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
|
|
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*
|
|
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
|
|
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(
|
|
137
|
+
pairs.push(yield* preserveConsumerError(cursor, readPair(ctx, step.value)));
|
|
140
138
|
}
|
|
141
139
|
}
|
|
142
140
|
if (isRuntimeReference(init)) {
|
|
143
|
-
throw
|
|
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
|
|
148
|
-
throw
|
|
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 = (
|
|
154
|
-
const
|
|
155
|
-
const proto =
|
|
156
|
-
const searchParams = constructor(
|
|
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
|
|
157
|
+
construct: (args, newTarget) => constructURLSearchParams(ctx, args[0], prototypeFrom(newTarget, proto)),
|
|
160
158
|
});
|
|
161
|
-
const self = (thisValue, name
|
|
162
|
-
const wrap = (items) => new
|
|
163
|
-
const arg = (
|
|
164
|
-
const requireArgs = (name, args, count
|
|
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
|
|
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(
|
|
168
|
+
methods(builtins, proto, [
|
|
171
169
|
[
|
|
172
170
|
"append",
|
|
173
171
|
2,
|
|
174
|
-
(thisValue, args
|
|
175
|
-
requireArgs("append", args, 2
|
|
176
|
-
self(thisValue, "append"
|
|
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
|
|
184
|
-
requireArgs("delete", args, 1
|
|
185
|
-
const params = self(thisValue, "delete"
|
|
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(
|
|
185
|
+
params.delete(arg(args, 0), arg(args, 1));
|
|
188
186
|
else
|
|
189
|
-
params.delete(arg(
|
|
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
|
|
197
|
-
requireArgs("get", args, 1
|
|
198
|
-
return self(thisValue, "get"
|
|
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
|
|
205
|
-
requireArgs("getAll", args, 1
|
|
206
|
-
return wrap(self(thisValue, "getAll"
|
|
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
|
|
213
|
-
requireArgs("has", args, 1
|
|
214
|
-
const params = self(thisValue, "has"
|
|
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
|
|
224
|
-
requireArgs("set", args, 2
|
|
225
|
-
self(thisValue, "set"
|
|
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
|
|
233
|
-
self(thisValue, "sort"
|
|
228
|
+
(thisValue) => {
|
|
229
|
+
self(thisValue, "sort").params.sort();
|
|
234
230
|
return undefined;
|
|
235
231
|
},
|
|
236
232
|
],
|
|
237
|
-
["keys", 0, (thisValue
|
|
238
|
-
["values", 0, (thisValue
|
|
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
|
|
238
|
+
(thisValue) => wrap(Array.from(self(thisValue, "entries").params.entries(), ([key, value]) => wrap([key, value]))),
|
|
243
239
|
],
|
|
244
|
-
["toString", 0, (thisValue
|
|
240
|
+
["toString", 0, (thisValue) => self(thisValue, "toString").params.toString()],
|
|
245
241
|
[
|
|
246
242
|
"forEach",
|
|
247
243
|
1,
|
|
248
|
-
(thisValue, args
|
|
249
|
-
requireArgs("forEach", args, 1
|
|
250
|
-
const target = self(thisValue, "forEach"
|
|
251
|
-
const apply = applyCollectionCallback(
|
|
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]);
|
package/dist/stdlib/value.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
import type {
|
|
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>(
|
|
9
|
+
export declare const coercion: <R>(ctx: Interpreter<R>, name: Coercion, length?: number) => Native<R>;
|
package/dist/stdlib/value.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { toProgram } from "../data.js";
|
|
2
1
|
import { fn } from "../interpreter/native.js";
|
|
3
|
-
import {
|
|
4
|
-
import { get, isWrapper,
|
|
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
|
|
11
|
+
if (value instanceof DateObj)
|
|
13
12
|
return Number.isFinite(value.time) ? new Date(value.time).toISOString() : "Invalid Date";
|
|
14
|
-
if (value instanceof
|
|
13
|
+
if (value instanceof RegExpObj)
|
|
15
14
|
return `/${value.regex.source}/${value.regex.flags}`;
|
|
16
|
-
if (value instanceof
|
|
15
|
+
if (value instanceof MapObj)
|
|
17
16
|
return "[object Map]";
|
|
18
|
-
if (value instanceof
|
|
17
|
+
if (value instanceof SetObj)
|
|
19
18
|
return "[object Set]";
|
|
20
|
-
if (value instanceof
|
|
19
|
+
if (value instanceof URLObj)
|
|
21
20
|
return value.url.href;
|
|
22
|
-
if (value instanceof
|
|
21
|
+
if (value instanceof URLSearchParamsObj)
|
|
23
22
|
return value.params.toString();
|
|
24
|
-
if (value instanceof
|
|
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
|
|
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
|
|
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
|
|
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 = (
|
|
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(
|
|
81
|
+
return coerceToNumber(raw);
|
|
80
82
|
if (name === "Boolean")
|
|
81
|
-
return Boolean(
|
|
83
|
+
return Boolean(raw);
|
|
82
84
|
if (name === "isFinite")
|
|
83
|
-
return Number.isFinite(coerceToNumber(
|
|
85
|
+
return Number.isFinite(coerceToNumber(raw));
|
|
84
86
|
if (name === "isNaN")
|
|
85
|
-
return Number.isNaN(coerceToNumber(
|
|
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
|
|
91
|
+
throw typeError("parseInt expects a numeric radix.");
|
|
90
92
|
}
|
|
91
|
-
return parseInt(coerceToString(
|
|
93
|
+
return parseInt(coerceToString(raw), radix);
|
|
92
94
|
}
|
|
93
95
|
if (name === "parseFloat")
|
|
94
|
-
return parseFloat(coerceToString(
|
|
95
|
-
return coerceToString(
|
|
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 = (
|
|
100
|
+
export const coercion = (ctx, name, length = 1) => fn(ctx.builtins, name, length, (_, args) => coerce(ctx, name, args));
|
package/dist/stdlib/web.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type {
|
|
3
|
-
export declare const base64Global: <R>(
|
|
4
|
-
export declare const cryptoGlobal: <R>(
|
|
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;
|
package/dist/stdlib/web.js
CHANGED
|
@@ -1,22 +1,36 @@
|
|
|
1
1
|
import { fn, methods } from "../interpreter/native.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
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 = (
|
|
8
|
+
export const base64Global = (ctx, name) => fn(ctx.builtins, name, 1, (_, args) => {
|
|
8
9
|
if (args.length === 0)
|
|
9
|
-
throw
|
|
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
|
|
16
|
+
throw typeError("The string contains invalid characters.");
|
|
16
17
|
}
|
|
17
18
|
});
|
|
18
|
-
export const cryptoGlobal = (
|
|
19
|
-
const object = new
|
|
20
|
-
methods(
|
|
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
|
};
|
package/dist/tool-runtime.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
|
-
import type {
|
|
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) =>
|
|
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<
|
|
65
|
-
readonly search: (args: Array<
|
|
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>,
|
|
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";
|
package/dist/tool-runtime.js
CHANGED
|
@@ -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,
|
|
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,
|
|
214
|
-
const normalized =
|
|
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: () =>
|
|
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
|
|
246
|
-
execute: (path, args) => Effect.
|
|
247
|
-
const
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
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