@opencode/codemode 0.0.0-reserved → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +184 -2
- package/dist/codemode.d.ts +145 -0
- package/dist/codemode.js +66 -0
- package/dist/data.d.ts +25 -0
- package/dist/data.js +153 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +7 -0
- package/dist/interpreter/errors.d.ts +7 -0
- package/dist/interpreter/errors.js +106 -0
- package/dist/interpreter/execute.d.ts +5 -0
- package/dist/interpreter/execute.js +171 -0
- package/dist/interpreter/globals.d.ts +13 -0
- package/dist/interpreter/globals.js +63 -0
- package/dist/interpreter/host.d.ts +41 -0
- package/dist/interpreter/host.js +44 -0
- package/dist/interpreter/methods.d.ts +4 -0
- package/dist/interpreter/methods.js +837 -0
- package/dist/interpreter/model.d.ts +82 -0
- package/dist/interpreter/model.js +86 -0
- package/dist/interpreter/objects.d.ts +37 -0
- package/dist/interpreter/objects.js +151 -0
- package/dist/interpreter/promises.d.ts +31 -0
- package/dist/interpreter/promises.js +271 -0
- package/dist/interpreter/references.d.ts +7 -0
- package/dist/interpreter/references.js +93 -0
- package/dist/interpreter/runner.d.ts +24 -0
- package/dist/interpreter/runner.js +45 -0
- package/dist/interpreter/runtime.d.ts +19 -0
- package/dist/interpreter/runtime.js +1940 -0
- package/dist/interpreter/scope.d.ts +15 -0
- package/dist/interpreter/scope.js +79 -0
- package/dist/interpreter/transpile.node.d.ts +5 -0
- package/dist/interpreter/transpile.node.js +19 -0
- package/dist/interpreter/transpile.workerd.d.ts +5 -0
- package/dist/interpreter/transpile.workerd.js +6 -0
- package/dist/namespace.d.ts +15 -0
- package/dist/namespace.js +7 -0
- package/dist/openapi/index.d.ts +7 -0
- package/dist/openapi/index.js +101 -0
- package/dist/openapi/runtime.d.ts +4 -0
- package/dist/openapi/runtime.js +283 -0
- package/dist/openapi/spec.d.ts +20 -0
- package/dist/openapi/spec.js +583 -0
- package/dist/openapi/types.d.ts +122 -0
- package/dist/openapi/types.js +2 -0
- package/dist/stdlib/array.d.ts +3 -0
- package/dist/stdlib/array.js +68 -0
- package/dist/stdlib/collections.d.ts +9 -0
- package/dist/stdlib/collections.js +173 -0
- package/dist/stdlib/console.d.ts +3 -0
- package/dist/stdlib/console.js +137 -0
- package/dist/stdlib/date.d.ts +8 -0
- package/dist/stdlib/date.js +208 -0
- package/dist/stdlib/json.d.ts +3 -0
- package/dist/stdlib/json.js +101 -0
- package/dist/stdlib/math.d.ts +8 -0
- package/dist/stdlib/math.js +89 -0
- package/dist/stdlib/number.d.ts +4 -0
- package/dist/stdlib/number.js +69 -0
- package/dist/stdlib/object.d.ts +7 -0
- package/dist/stdlib/object.js +106 -0
- package/dist/stdlib/regexp.d.ts +10 -0
- package/dist/stdlib/regexp.js +120 -0
- package/dist/stdlib/string.d.ts +2 -0
- package/dist/stdlib/string.js +51 -0
- package/dist/stdlib/url.d.ts +16 -0
- package/dist/stdlib/url.js +161 -0
- package/dist/stdlib/value.d.ts +13 -0
- package/dist/stdlib/value.js +120 -0
- package/dist/stdlib/web.d.ts +4 -0
- package/dist/stdlib/web.js +20 -0
- package/dist/tool-error.d.ts +11 -0
- package/dist/tool-error.js +9 -0
- package/dist/tool-runtime.d.ts +69 -0
- package/dist/tool-runtime.js +254 -0
- package/dist/tool-schema.d.ts +16 -0
- package/dist/tool-schema.js +263 -0
- package/dist/tool.d.ts +66 -0
- package/dist/tool.js +16 -0
- package/dist/tools.d.ts +5 -0
- package/dist/tools.js +1 -0
- package/dist/values.d.ts +37 -0
- package/dist/values.js +56 -0
- package/package.json +37 -6
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { sync, syncCall } from "../interpreter/host.js";
|
|
2
|
+
import { InterpreterRuntimeError } from "../interpreter/model.js";
|
|
3
|
+
import { ProgramArray, record, set } from "../interpreter/objects.js";
|
|
4
|
+
import { Values } from "../values.js";
|
|
5
|
+
import { coerceToNumber, coerceToString } from "./value.js";
|
|
6
|
+
export const regexpMethods = new Set(["test", "exec", "toString"]);
|
|
7
|
+
export const regexpProperties = new Set([
|
|
8
|
+
"source",
|
|
9
|
+
"flags",
|
|
10
|
+
"lastIndex",
|
|
11
|
+
"hasIndices",
|
|
12
|
+
"global",
|
|
13
|
+
"ignoreCase",
|
|
14
|
+
"multiline",
|
|
15
|
+
"sticky",
|
|
16
|
+
"unicode",
|
|
17
|
+
"unicodeSets",
|
|
18
|
+
"dotAll",
|
|
19
|
+
]);
|
|
20
|
+
const regexFailureReason = (error) => (error instanceof Error ? error.message : String(error)).replace(/^Invalid regular expression:\s*/i, "");
|
|
21
|
+
const escapeRegexHint = 'To match special characters like ( ) [ ] { } + * ? . literally, escape them with a backslash (e.g. "\\\\(") or test for them with String.includes instead.';
|
|
22
|
+
export const toHostRegex = (arg, method, node, extraFlags = "") => {
|
|
23
|
+
// Native parity: an undefined pattern behaves as an empty pattern.
|
|
24
|
+
if (arg === undefined)
|
|
25
|
+
return new RegExp("", extraFlags);
|
|
26
|
+
if (arg instanceof Values.RegExp)
|
|
27
|
+
return arg.regex;
|
|
28
|
+
if (typeof arg === "string") {
|
|
29
|
+
try {
|
|
30
|
+
return new RegExp(arg, extraFlags);
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
throw new InterpreterRuntimeError(`String.${method} received the string ${JSON.stringify(arg)}, which is not a valid regular expression pattern (${regexFailureReason(error)}). ${escapeRegexHint}`, node).as("SyntaxError");
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
throw new InterpreterRuntimeError(`String.${method} expects a regular expression (a /pattern/flags literal or new RegExp(...)) or a string pattern, not ${arg === null ? "null" : typeof arg}.`, node);
|
|
37
|
+
};
|
|
38
|
+
export const matchToValue = (match) => {
|
|
39
|
+
const result = new ProgramArray(Array.from(match, (group) => group));
|
|
40
|
+
if (match.index !== undefined)
|
|
41
|
+
set(result, "index", match.index);
|
|
42
|
+
if (match.input !== undefined)
|
|
43
|
+
set(result, "input", match.input);
|
|
44
|
+
if (match.groups)
|
|
45
|
+
set(result, "groups", record(match.groups));
|
|
46
|
+
if (match.indices)
|
|
47
|
+
set(result, "indices", indicesToValue(match.indices));
|
|
48
|
+
return result;
|
|
49
|
+
};
|
|
50
|
+
export const constructRegExp = (args, node) => {
|
|
51
|
+
const first = args[0];
|
|
52
|
+
const pattern = first instanceof Values.RegExp ? first.regex.source : first === undefined ? "" : coerceToString(first);
|
|
53
|
+
const flagsArg = args[1];
|
|
54
|
+
if (flagsArg !== undefined && typeof flagsArg !== "string") {
|
|
55
|
+
throw new InterpreterRuntimeError(`RegExp flags must be a string of flag characters (e.g. "g", "gi"), not ${flagsArg === null ? "null" : typeof flagsArg}.`, node).as("SyntaxError");
|
|
56
|
+
}
|
|
57
|
+
const flags = flagsArg ?? (first instanceof Values.RegExp ? first.regex.flags : "");
|
|
58
|
+
try {
|
|
59
|
+
return new Values.RegExp(pattern, flags);
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
const reason = regexFailureReason(error);
|
|
63
|
+
throw new InterpreterRuntimeError(/flag/i.test(reason)
|
|
64
|
+
? `new RegExp(...) received invalid flags ${JSON.stringify(flags)} (${reason}). Valid flags are d, g, i, m, s, u, v, and y.`
|
|
65
|
+
: `new RegExp(...) received ${JSON.stringify(pattern)}, which is not a valid regular expression pattern (${reason}). ${escapeRegexHint}`, node).as("SyntaxError");
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
// RegExp constructs identically with or without new, like JS.
|
|
69
|
+
export const regexpGlobal = sync("RegExp", constructRegExp, {
|
|
70
|
+
construct: syncCall(constructRegExp),
|
|
71
|
+
instanceOf: (value) => value instanceof Values.RegExp,
|
|
72
|
+
members: {
|
|
73
|
+
escape: sync("RegExp.escape", (args, node) => {
|
|
74
|
+
if (typeof args[0] !== "string") {
|
|
75
|
+
throw new InterpreterRuntimeError("RegExp.escape expects a string.", node).as("TypeError");
|
|
76
|
+
}
|
|
77
|
+
return RegExp.escape(args[0]);
|
|
78
|
+
}),
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
export const invokeRegExpMethod = (value, name, args, node) => {
|
|
82
|
+
switch (name) {
|
|
83
|
+
case "test":
|
|
84
|
+
case "exec": {
|
|
85
|
+
const input = coerceToString(args[0]);
|
|
86
|
+
const lastIndex = value.lastIndex;
|
|
87
|
+
const stateful = value.regex.global || value.regex.sticky;
|
|
88
|
+
value.regex.lastIndex = toLength(lastIndex);
|
|
89
|
+
if (name === "test") {
|
|
90
|
+
const matched = value.regex.test(input);
|
|
91
|
+
if (!stateful)
|
|
92
|
+
value.lastIndex = lastIndex;
|
|
93
|
+
return matched;
|
|
94
|
+
}
|
|
95
|
+
const matched = value.regex.exec(input);
|
|
96
|
+
if (!stateful)
|
|
97
|
+
value.lastIndex = lastIndex;
|
|
98
|
+
return matched === null ? null : matchToValue(matched);
|
|
99
|
+
}
|
|
100
|
+
case "toString":
|
|
101
|
+
return coerceToString(value);
|
|
102
|
+
default:
|
|
103
|
+
throw new InterpreterRuntimeError(`RegExp method '${name}' is not available.`, node);
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
const toLength = (value) => {
|
|
107
|
+
const number = coerceToNumber(value);
|
|
108
|
+
if (Number.isNaN(number) || number <= 0)
|
|
109
|
+
return 0;
|
|
110
|
+
return Math.min(Math.floor(number), Number.MAX_SAFE_INTEGER);
|
|
111
|
+
};
|
|
112
|
+
const indicesToValue = (indices) => {
|
|
113
|
+
const range = (pair) => (pair === undefined ? undefined : new ProgramArray([...pair]));
|
|
114
|
+
const result = new ProgramArray(Array.from(indices, range));
|
|
115
|
+
const groups = indices.groups;
|
|
116
|
+
set(result, "groups", groups === undefined
|
|
117
|
+
? undefined
|
|
118
|
+
: record(Object.fromEntries(Object.entries(groups).map(([key, pair]) => [key, range(pair)]))));
|
|
119
|
+
return result;
|
|
120
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { sync } from "../interpreter/host.js";
|
|
2
|
+
import { InterpreterRuntimeError } from "../interpreter/model.js";
|
|
3
|
+
import { coercion } from "./value.js";
|
|
4
|
+
export const stringMethods = new Set([
|
|
5
|
+
"toLowerCase",
|
|
6
|
+
"toUpperCase",
|
|
7
|
+
"trim",
|
|
8
|
+
"trimStart",
|
|
9
|
+
"trimEnd",
|
|
10
|
+
"trimLeft",
|
|
11
|
+
"trimRight",
|
|
12
|
+
"split",
|
|
13
|
+
"slice",
|
|
14
|
+
"substring",
|
|
15
|
+
"substr",
|
|
16
|
+
"includes",
|
|
17
|
+
"startsWith",
|
|
18
|
+
"endsWith",
|
|
19
|
+
"indexOf",
|
|
20
|
+
"lastIndexOf",
|
|
21
|
+
"replace",
|
|
22
|
+
"replaceAll",
|
|
23
|
+
"repeat",
|
|
24
|
+
"padStart",
|
|
25
|
+
"padEnd",
|
|
26
|
+
"charAt",
|
|
27
|
+
"charCodeAt",
|
|
28
|
+
"codePointAt",
|
|
29
|
+
"at",
|
|
30
|
+
"concat",
|
|
31
|
+
"toString",
|
|
32
|
+
"match",
|
|
33
|
+
"matchAll",
|
|
34
|
+
"search",
|
|
35
|
+
"localeCompare",
|
|
36
|
+
"normalize",
|
|
37
|
+
"isWellFormed",
|
|
38
|
+
"toWellFormed",
|
|
39
|
+
]);
|
|
40
|
+
const codeUnits = (name, op) => sync(`String.${name}`, (args, node) => op(...args.map((arg) => {
|
|
41
|
+
if (typeof arg !== "number")
|
|
42
|
+
throw new InterpreterRuntimeError(`String.${name} expects number arguments.`, node);
|
|
43
|
+
return arg;
|
|
44
|
+
})));
|
|
45
|
+
export const stringGlobal = coercion("String", {
|
|
46
|
+
instanceOf: () => false,
|
|
47
|
+
members: {
|
|
48
|
+
fromCharCode: codeUnits("fromCharCode", String.fromCharCode),
|
|
49
|
+
fromCodePoint: codeUnits("fromCodePoint", String.fromCodePoint),
|
|
50
|
+
},
|
|
51
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { HostFunction } from "../interpreter/host.js";
|
|
2
|
+
import { type AstNode } from "../interpreter/model.js";
|
|
3
|
+
import { type Runner } from "../interpreter/runner.js";
|
|
4
|
+
import { Values } from "../values.js";
|
|
5
|
+
export declare const urlProperties: Set<string>;
|
|
6
|
+
export declare const urlWritableProperties: Set<string>;
|
|
7
|
+
export declare const urlMethods: Set<string>;
|
|
8
|
+
export declare const urlSearchParamsMethods: Set<string>;
|
|
9
|
+
export declare const uriArgument: (value: unknown, label: string) => string;
|
|
10
|
+
type UriFunction = "encodeURI" | "encodeURIComponent" | "decodeURI" | "decodeURIComponent";
|
|
11
|
+
export declare const uriGlobal: (name: UriFunction) => HostFunction<never>;
|
|
12
|
+
export declare const urlArgument: (value: unknown, label: string) => string;
|
|
13
|
+
export declare const urlGlobal: HostFunction<never>;
|
|
14
|
+
export declare const urlSearchParamsGlobal: <R>(runner: Runner<R>) => HostFunction<R>;
|
|
15
|
+
export declare const invokeURLMethod: (value: Values.URL, name: string, node: AstNode) => string;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { toProgram } from "../data.js";
|
|
3
|
+
import { HostFunction, requiresNew, sync, syncCall } from "../interpreter/host.js";
|
|
4
|
+
import { InterpreterRuntimeError } from "../interpreter/model.js";
|
|
5
|
+
import { ownEntries, ProgramObject } from "../interpreter/objects.js";
|
|
6
|
+
import { isRuntimeReference } from "../interpreter/references.js";
|
|
7
|
+
import { preserveConsumerError } from "../interpreter/runner.js";
|
|
8
|
+
import { Values } from "../values.js";
|
|
9
|
+
import { coerceToString } from "./value.js";
|
|
10
|
+
export const urlProperties = new Set([
|
|
11
|
+
"href",
|
|
12
|
+
"origin",
|
|
13
|
+
"protocol",
|
|
14
|
+
"username",
|
|
15
|
+
"password",
|
|
16
|
+
"host",
|
|
17
|
+
"hostname",
|
|
18
|
+
"port",
|
|
19
|
+
"pathname",
|
|
20
|
+
"search",
|
|
21
|
+
"hash",
|
|
22
|
+
]);
|
|
23
|
+
export const urlWritableProperties = new Set([
|
|
24
|
+
"href",
|
|
25
|
+
"protocol",
|
|
26
|
+
"username",
|
|
27
|
+
"password",
|
|
28
|
+
"host",
|
|
29
|
+
"hostname",
|
|
30
|
+
"port",
|
|
31
|
+
"pathname",
|
|
32
|
+
"search",
|
|
33
|
+
"hash",
|
|
34
|
+
]);
|
|
35
|
+
export const urlMethods = new Set(["toString", "toJSON"]);
|
|
36
|
+
export const urlSearchParamsMethods = new Set([
|
|
37
|
+
"append",
|
|
38
|
+
"delete",
|
|
39
|
+
"get",
|
|
40
|
+
"getAll",
|
|
41
|
+
"has",
|
|
42
|
+
"set",
|
|
43
|
+
"sort",
|
|
44
|
+
"forEach",
|
|
45
|
+
"keys",
|
|
46
|
+
"values",
|
|
47
|
+
"entries",
|
|
48
|
+
"toString",
|
|
49
|
+
]);
|
|
50
|
+
export const uriArgument = (value, label) => coerceToString(toProgram(value, label));
|
|
51
|
+
const uriFunctions = {
|
|
52
|
+
encodeURI,
|
|
53
|
+
encodeURIComponent,
|
|
54
|
+
decodeURI,
|
|
55
|
+
decodeURIComponent,
|
|
56
|
+
};
|
|
57
|
+
export const uriGlobal = (name) => sync(name, (args, node) => {
|
|
58
|
+
const value = uriArgument(args[0], `${name} input`);
|
|
59
|
+
try {
|
|
60
|
+
return uriFunctions[name](value);
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
throw new InterpreterRuntimeError(`${name} received malformed URI data: ${error instanceof Error ? error.message : String(error)}`, node).as("URIError");
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
export const urlArgument = (value, label) => value instanceof Values.URL ? value.url.href : uriArgument(value, label);
|
|
67
|
+
const urlStatic = (name) => sync(`URL.${name}`, (args, node) => {
|
|
68
|
+
if (args.length === 0) {
|
|
69
|
+
throw new InterpreterRuntimeError(`URL.${name} requires a URL argument.`, node).as("TypeError");
|
|
70
|
+
}
|
|
71
|
+
const input = urlArgument(args[0], `URL.${name} input`);
|
|
72
|
+
const base = args[1] === undefined ? undefined : urlArgument(args[1], `URL.${name} base`);
|
|
73
|
+
try {
|
|
74
|
+
const url = new URL(input, base);
|
|
75
|
+
return name === "canParse" ? true : new Values.URL(url);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return name === "canParse" ? false : null;
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
const constructURL = (args, node) => {
|
|
82
|
+
if (args.length === 0) {
|
|
83
|
+
throw new InterpreterRuntimeError("new URL(...) requires a URL string and an optional base URL.", node).as("TypeError");
|
|
84
|
+
}
|
|
85
|
+
const input = urlArgument(args[0], "new URL input");
|
|
86
|
+
const base = args[1] === undefined ? undefined : urlArgument(args[1], "new URL base");
|
|
87
|
+
try {
|
|
88
|
+
return new Values.URL(new URL(input, base));
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
throw new InterpreterRuntimeError(`new URL(...) received an invalid URL${base === undefined ? "" : " or base URL"}.`, node).as("TypeError");
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
export const urlGlobal = new HostFunction({
|
|
95
|
+
name: "URL",
|
|
96
|
+
call: requiresNew("URL"),
|
|
97
|
+
construct: syncCall(constructURL),
|
|
98
|
+
instanceOf: (value) => value instanceof Values.URL,
|
|
99
|
+
members: { canParse: urlStatic("canParse"), parse: urlStatic("parse") },
|
|
100
|
+
});
|
|
101
|
+
const readURLSearchParamsPair = (runner, value, node) => Effect.gen(function* () {
|
|
102
|
+
const cursor = yield* runner.syncIterator(value, node);
|
|
103
|
+
if (cursor === undefined) {
|
|
104
|
+
throw new InterpreterRuntimeError("new URLSearchParams(...) expects iterable [name, value] pairs.", node).as("TypeError");
|
|
105
|
+
}
|
|
106
|
+
const items = [];
|
|
107
|
+
while (true) {
|
|
108
|
+
const step = yield* cursor.next;
|
|
109
|
+
if (step.done)
|
|
110
|
+
return items;
|
|
111
|
+
items.push(yield* preserveConsumerError(cursor, Effect.sync(() => uriArgument(step.value, "URLSearchParams pair value"))));
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
const constructURLSearchParams = (runner, init, node) => {
|
|
115
|
+
if (init === undefined)
|
|
116
|
+
return Effect.succeed(new Values.URLSearchParams(new URLSearchParams()));
|
|
117
|
+
if (init instanceof Values.URLSearchParams) {
|
|
118
|
+
return Effect.succeed(new Values.URLSearchParams(new URLSearchParams(init.params)));
|
|
119
|
+
}
|
|
120
|
+
if (typeof init === "string")
|
|
121
|
+
return Effect.succeed(new Values.URLSearchParams(new URLSearchParams(init)));
|
|
122
|
+
if (init === null || typeof init === "number" || typeof init === "boolean") {
|
|
123
|
+
return Effect.succeed(new Values.URLSearchParams(new URLSearchParams(coerceToString(init))));
|
|
124
|
+
}
|
|
125
|
+
return Effect.gen(function* () {
|
|
126
|
+
const cursor = yield* runner.syncIterator(init, node);
|
|
127
|
+
if (cursor !== undefined) {
|
|
128
|
+
const entries = [];
|
|
129
|
+
while (true) {
|
|
130
|
+
const step = yield* cursor.next;
|
|
131
|
+
if (step.done) {
|
|
132
|
+
if (entries.some((entry) => entry.length !== 2)) {
|
|
133
|
+
throw new InterpreterRuntimeError("new URLSearchParams(...) expects iterable [name, value] pairs.", node).as("TypeError");
|
|
134
|
+
}
|
|
135
|
+
return new Values.URLSearchParams(new URLSearchParams(entries.map((entry) => [entry[0] ?? "", entry[1] ?? ""])));
|
|
136
|
+
}
|
|
137
|
+
entries.push(yield* preserveConsumerError(cursor, readURLSearchParamsPair(runner, step.value, node)));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (isRuntimeReference(init)) {
|
|
141
|
+
throw new InterpreterRuntimeError("new URLSearchParams(...) expects a query string, data object, or synchronous iterable pairs.", node).as("TypeError");
|
|
142
|
+
}
|
|
143
|
+
if (Values.isValue(init))
|
|
144
|
+
return new Values.URLSearchParams(new URLSearchParams());
|
|
145
|
+
if (!(init instanceof ProgramObject)) {
|
|
146
|
+
throw new InterpreterRuntimeError("new URLSearchParams(...) expects a query string, data object, iterable pairs, or URLSearchParams.", node).as("TypeError");
|
|
147
|
+
}
|
|
148
|
+
return new Values.URLSearchParams(new URLSearchParams(Object.fromEntries(ownEntries(init).map(([key, value]) => [key, coerceToString(value)]))));
|
|
149
|
+
});
|
|
150
|
+
};
|
|
151
|
+
export const urlSearchParamsGlobal = (runner) => new HostFunction({
|
|
152
|
+
name: "URLSearchParams",
|
|
153
|
+
call: requiresNew("URLSearchParams"),
|
|
154
|
+
construct: (args, node) => constructURLSearchParams(runner, args[0], node),
|
|
155
|
+
instanceOf: (value) => value instanceof Values.URLSearchParams,
|
|
156
|
+
});
|
|
157
|
+
export const invokeURLMethod = (value, name, node) => {
|
|
158
|
+
if (name === "toString" || name === "toJSON")
|
|
159
|
+
return value.url.href;
|
|
160
|
+
throw new InterpreterRuntimeError(`URL method '${name}' is not available.`, node);
|
|
161
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type HostFunction, type SyncOptions } from "../interpreter/host.js";
|
|
2
|
+
import { ProgramError } from "../interpreter/objects.js";
|
|
3
|
+
export declare const errorConstructors: Set<string>;
|
|
4
|
+
export declare const compoundOperators: Set<string>;
|
|
5
|
+
export declare const createErrorValue: (name: string, message: string) => ProgramError;
|
|
6
|
+
export declare const createAggregateErrorValue: (errors: Array<unknown>, message: string) => ProgramError;
|
|
7
|
+
export declare const errorBrandName: (value: unknown) => string | undefined;
|
|
8
|
+
export declare const coerceToString: (value: unknown) => string;
|
|
9
|
+
export declare const coerceToNumber: (value: unknown) => number;
|
|
10
|
+
type Coercion = "Number" | "String" | "Boolean" | "parseInt" | "parseFloat" | "isFinite" | "isNaN";
|
|
11
|
+
/** A global coercion function such as `Number` or `parseInt`. */
|
|
12
|
+
export declare const coercion: (name: Coercion, options?: SyncOptions) => HostFunction;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { sync } from "../interpreter/host.js";
|
|
2
|
+
import { InterpreterRuntimeError } from "../interpreter/model.js";
|
|
3
|
+
import { toProgram } from "../data.js";
|
|
4
|
+
import { get, ProgramArray, ProgramError, set } from "../interpreter/objects.js";
|
|
5
|
+
import { Values } from "../values.js";
|
|
6
|
+
export const errorConstructors = new Set([
|
|
7
|
+
"Error",
|
|
8
|
+
"TypeError",
|
|
9
|
+
"RangeError",
|
|
10
|
+
"SyntaxError",
|
|
11
|
+
"ReferenceError",
|
|
12
|
+
"EvalError",
|
|
13
|
+
"URIError",
|
|
14
|
+
"AggregateError",
|
|
15
|
+
]);
|
|
16
|
+
export const compoundOperators = new Set(["+=", "-=", "*=", "/=", "%=", "**=", "&=", "|=", "^=", "<<=", ">>=", ">>>="]);
|
|
17
|
+
export const createErrorValue = (name, message) => {
|
|
18
|
+
const value = new ProgramError(name);
|
|
19
|
+
set(value, "name", name);
|
|
20
|
+
set(value, "message", message);
|
|
21
|
+
return value;
|
|
22
|
+
};
|
|
23
|
+
export const createAggregateErrorValue = (errors, message) => {
|
|
24
|
+
const value = createErrorValue("AggregateError", message);
|
|
25
|
+
set(value, "errors", new ProgramArray(errors));
|
|
26
|
+
return value;
|
|
27
|
+
};
|
|
28
|
+
export const errorBrandName = (value) => value instanceof ProgramError ? value.errorName : undefined;
|
|
29
|
+
export const coerceToString = (value) => {
|
|
30
|
+
if (value === null)
|
|
31
|
+
return "null";
|
|
32
|
+
if (value === undefined)
|
|
33
|
+
return "undefined";
|
|
34
|
+
if (value instanceof Values.Date)
|
|
35
|
+
return Number.isFinite(value.time) ? new Date(value.time).toISOString() : "Invalid Date";
|
|
36
|
+
if (value instanceof Values.RegExp)
|
|
37
|
+
return `/${value.regex.source}/${value.regex.flags}`;
|
|
38
|
+
if (value instanceof Values.Map)
|
|
39
|
+
return "[object Map]";
|
|
40
|
+
if (value instanceof Values.Set)
|
|
41
|
+
return "[object Set]";
|
|
42
|
+
if (value instanceof Values.URL)
|
|
43
|
+
return value.url.href;
|
|
44
|
+
if (value instanceof Values.URLSearchParams)
|
|
45
|
+
return value.params.toString();
|
|
46
|
+
if (value instanceof ProgramError) {
|
|
47
|
+
// Match Error.prototype.toString: "name: message", or just one when the other is empty.
|
|
48
|
+
const name = get(value, "name");
|
|
49
|
+
const message = get(value, "message");
|
|
50
|
+
const shownName = typeof name === "string" ? name : "Error";
|
|
51
|
+
const shownMessage = typeof message === "string" ? message : "";
|
|
52
|
+
if (shownMessage === "")
|
|
53
|
+
return shownName;
|
|
54
|
+
if (shownName === "")
|
|
55
|
+
return shownMessage;
|
|
56
|
+
return `${shownName}: ${shownMessage}`;
|
|
57
|
+
}
|
|
58
|
+
if (value instanceof ProgramArray) {
|
|
59
|
+
return value.items.map((item) => (item === null || item === undefined ? "" : coerceToString(item))).join(",");
|
|
60
|
+
}
|
|
61
|
+
if (typeof value === "object")
|
|
62
|
+
return "[object Object]";
|
|
63
|
+
return String(value);
|
|
64
|
+
};
|
|
65
|
+
export const coerceToNumber = (value) => {
|
|
66
|
+
if (value instanceof Values.Date)
|
|
67
|
+
return value.time;
|
|
68
|
+
if (Values.isValue(value))
|
|
69
|
+
return Number.NaN;
|
|
70
|
+
if (value instanceof ProgramArray)
|
|
71
|
+
return Number(coerceToString(value));
|
|
72
|
+
return value !== null && typeof value === "object" ? Number.NaN : Number(value);
|
|
73
|
+
};
|
|
74
|
+
const coerce = (name, args, node) => {
|
|
75
|
+
// Native: Number() is 0 and String() is "", unlike their undefined-argument forms; the
|
|
76
|
+
// other coercers match native through the undefined-argument path below.
|
|
77
|
+
if (args.length === 0) {
|
|
78
|
+
if (name === "Number")
|
|
79
|
+
return 0;
|
|
80
|
+
if (name === "String")
|
|
81
|
+
return "";
|
|
82
|
+
}
|
|
83
|
+
const raw = args[0];
|
|
84
|
+
if (Values.isValue(raw)) {
|
|
85
|
+
if (name === "Boolean")
|
|
86
|
+
return true;
|
|
87
|
+
if (name === "Number")
|
|
88
|
+
return coerceToNumber(raw);
|
|
89
|
+
if (name === "String")
|
|
90
|
+
return coerceToString(raw);
|
|
91
|
+
if (name === "isFinite")
|
|
92
|
+
return Number.isFinite(coerceToNumber(raw));
|
|
93
|
+
if (name === "isNaN")
|
|
94
|
+
return Number.isNaN(coerceToNumber(raw));
|
|
95
|
+
if (name === "parseInt")
|
|
96
|
+
return parseInt(coerceToString(raw));
|
|
97
|
+
return parseFloat(coerceToString(raw));
|
|
98
|
+
}
|
|
99
|
+
const value = toProgram(raw, `${name} input`);
|
|
100
|
+
if (name === "Number")
|
|
101
|
+
return coerceToNumber(value);
|
|
102
|
+
if (name === "Boolean")
|
|
103
|
+
return Boolean(value);
|
|
104
|
+
if (name === "isFinite")
|
|
105
|
+
return Number.isFinite(coerceToNumber(value));
|
|
106
|
+
if (name === "isNaN")
|
|
107
|
+
return Number.isNaN(coerceToNumber(value));
|
|
108
|
+
if (name === "parseInt") {
|
|
109
|
+
const radix = args[1];
|
|
110
|
+
if (radix !== undefined && typeof radix !== "number") {
|
|
111
|
+
throw new InterpreterRuntimeError("parseInt expects a numeric radix.", node);
|
|
112
|
+
}
|
|
113
|
+
return parseInt(coerceToString(value), radix);
|
|
114
|
+
}
|
|
115
|
+
if (name === "parseFloat")
|
|
116
|
+
return parseFloat(coerceToString(value));
|
|
117
|
+
return coerceToString(value);
|
|
118
|
+
};
|
|
119
|
+
/** A global coercion function such as `Number` or `parseInt`. */
|
|
120
|
+
export const coercion = (name, options = {}) => sync(name, (args, node) => toProgram(coerce(name, args, node), `${name} result`), options);
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { HostNamespace } from "../interpreter/host.js";
|
|
2
|
+
export declare const atobGlobal: import("../interpreter/host.js").HostFunction<never>;
|
|
3
|
+
export declare const btoaGlobal: import("../interpreter/host.js").HostFunction<never>;
|
|
4
|
+
export declare const cryptoGlobal: HostNamespace;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { HostNamespace, sync } from "../interpreter/host.js";
|
|
2
|
+
import { InterpreterRuntimeError } from "../interpreter/model.js";
|
|
3
|
+
import { coerceToString } from "./value.js";
|
|
4
|
+
// WebIDL DOMString conversion: a missing argument is a TypeError, anything else stringifies.
|
|
5
|
+
const base64 = (name) => sync(name, (args, node) => {
|
|
6
|
+
if (args.length === 0)
|
|
7
|
+
throw new InterpreterRuntimeError(`${name} requires 1 argument (a string)`, node).as("TypeError");
|
|
8
|
+
const input = coerceToString(args[0]);
|
|
9
|
+
try {
|
|
10
|
+
return name === "atob" ? atob(input) : btoa(input);
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
throw new InterpreterRuntimeError("The string contains invalid characters.", node).as("InvalidCharacterError");
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
export const atobGlobal = base64("atob");
|
|
17
|
+
export const btoaGlobal = base64("btoa");
|
|
18
|
+
export const cryptoGlobal = new HostNamespace("crypto", {
|
|
19
|
+
randomUUID: sync("crypto.randomUUID", () => crypto.randomUUID()),
|
|
20
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
declare const ToolError_base: Schema.Class<ToolError, Schema.TaggedStruct<"ToolError", {
|
|
3
|
+
readonly message: Schema.String;
|
|
4
|
+
readonly cause: Schema.optionalKey<Schema.Defect>;
|
|
5
|
+
}>, import("effect/Cause").YieldableError>;
|
|
6
|
+
/** Tool failure reported as `ToolFailure`. */
|
|
7
|
+
export declare class ToolError extends ToolError_base {
|
|
8
|
+
}
|
|
9
|
+
/** Creates a tool failure with an optional underlying cause. */
|
|
10
|
+
export declare const toolError: (message: string, cause?: unknown) => ToolError;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
/** Tool failure reported as `ToolFailure`. */
|
|
3
|
+
export class ToolError extends Schema.TaggedError()("ToolError", {
|
|
4
|
+
message: Schema.String,
|
|
5
|
+
cause: Schema.optionalKey(Schema.Defect()),
|
|
6
|
+
}) {
|
|
7
|
+
}
|
|
8
|
+
/** Creates a tool failure with an optional underlying cause. */
|
|
9
|
+
export const toolError = (message, cause) => new ToolError({ message, ...(cause === undefined ? {} : { cause }) });
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { type Namespace } from "./namespace.js";
|
|
3
|
+
import { type Tool } from "./tool.js";
|
|
4
|
+
import type { Tools } from "./tools.js";
|
|
5
|
+
export declare const compareText: (left: string, right: string) => 1 | -1 | 0;
|
|
6
|
+
export type Services<T> = ServicesOf<T, []>;
|
|
7
|
+
type ServicesOf<T, Depth extends ReadonlyArray<unknown>> = Depth["length"] extends 8 ? never : T extends {
|
|
8
|
+
readonly _tag: "CodeModeTool";
|
|
9
|
+
readonly execute: (input: unknown) => Effect.Effect<unknown, unknown, infer R>;
|
|
10
|
+
} ? R : T extends object ? string extends keyof T ? ServicesOf<T[string], [...Depth, unknown]> : ServicesOf<T[keyof T], [...Depth, unknown]> : never;
|
|
11
|
+
export type ToolCall = {
|
|
12
|
+
readonly name: string;
|
|
13
|
+
};
|
|
14
|
+
export type ToolCallStarted = {
|
|
15
|
+
readonly index: number;
|
|
16
|
+
readonly name: string;
|
|
17
|
+
readonly input: unknown;
|
|
18
|
+
};
|
|
19
|
+
export type ToolCallEnded = {
|
|
20
|
+
readonly index: number;
|
|
21
|
+
readonly name: string;
|
|
22
|
+
readonly input: unknown;
|
|
23
|
+
readonly durationMs: number;
|
|
24
|
+
readonly outcome: "success" | "failure" | "interrupted";
|
|
25
|
+
readonly message?: string;
|
|
26
|
+
};
|
|
27
|
+
export type ToolCallHooks<R = never> = {
|
|
28
|
+
/** Observes decoded tool input immediately before tool execution. */
|
|
29
|
+
readonly onToolCallStart?: ((call: ToolCallStarted) => Effect.Effect<void, never, R>) | undefined;
|
|
30
|
+
/** Observes each admitted tool call as it succeeds, fails, or is interrupted. */
|
|
31
|
+
readonly onToolCallEnd?: ((call: ToolCallEnded) => Effect.Effect<void, never, R>) | undefined;
|
|
32
|
+
};
|
|
33
|
+
export type ToolDescription = {
|
|
34
|
+
readonly path: string;
|
|
35
|
+
readonly description: string;
|
|
36
|
+
readonly signature: string;
|
|
37
|
+
};
|
|
38
|
+
export declare const toolExpression: (path: string) => string;
|
|
39
|
+
export declare class ToolReference {
|
|
40
|
+
readonly path: ReadonlyArray<string>;
|
|
41
|
+
constructor(path: ReadonlyArray<string>);
|
|
42
|
+
}
|
|
43
|
+
type ToolNode<R> = {
|
|
44
|
+
tool?: Tool<R>;
|
|
45
|
+
namespace?: Namespace<R>;
|
|
46
|
+
readonly children: Map<string, ToolNode<R>>;
|
|
47
|
+
};
|
|
48
|
+
/** Tools indexed once per runtime: the lookup trie plus the model-facing catalog and search index. */
|
|
49
|
+
export type Prepared<R = never> = {
|
|
50
|
+
readonly root: ToolNode<R>;
|
|
51
|
+
readonly catalog: ReadonlyArray<ToolDescription>;
|
|
52
|
+
readonly searchIndex: ReadonlyArray<SearchEntry>;
|
|
53
|
+
};
|
|
54
|
+
export type SearchEntry = {
|
|
55
|
+
readonly description: ToolDescription;
|
|
56
|
+
readonly searchText: string;
|
|
57
|
+
};
|
|
58
|
+
/** Exact callable signature of the built-in `search` function, for host-owned instructions. */
|
|
59
|
+
export declare const searchSignature: string;
|
|
60
|
+
export declare const prepare: <R>(tools: Tools<R>) => Prepared<R>;
|
|
61
|
+
export type ToolRuntime<R = never> = {
|
|
62
|
+
readonly calls: Array<ToolCall>;
|
|
63
|
+
readonly execute: (path: ReadonlyArray<string>, args: Array<unknown>) => Effect.Effect<unknown, unknown, R>;
|
|
64
|
+
readonly search: (args: Array<unknown>) => Effect.Effect<unknown, unknown, R>;
|
|
65
|
+
readonly keys: (path: ReadonlyArray<string>) => ReadonlyArray<string>;
|
|
66
|
+
};
|
|
67
|
+
/** Per-execution call state over tools prepared once for the runtime. */
|
|
68
|
+
export declare const make: <R>(prepared: Prepared<R>, maxToolCalls: number | undefined, hooks?: ToolCallHooks<R>) => ToolRuntime<R>;
|
|
69
|
+
export * as ToolRuntime from "./tool-runtime.js";
|