@opencode/codemode 2.0.11 → 2.0.12

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.
@@ -14,6 +14,8 @@ export declare const preserveConsumerError: <A, R>(cursor: IteratorCursor<R>, ef
14
14
  * default hint as "string", like their `Symbol.toPrimitive`.
15
15
  */
16
16
  export declare const toPrimitive: <R>(ctx: Interpreter<R>, value: unknown, hint: "number" | "string" | "default") => Effect.Effect<unknown, unknown, R>;
17
+ /** Invoke(value, name): calls the method the value would find through its prototype. */
18
+ export declare const invoke: <R>(ctx: Interpreter<R>, value: unknown, name: string, label: string) => Effect.Effect<unknown, unknown, R>;
17
19
  export declare const toPrimitiveString: <R>(ctx: Interpreter<R>, value: unknown) => Effect.Effect<string, unknown, R>;
18
20
  export declare const toPrimitiveNumber: <R>(ctx: Interpreter<R>, value: unknown) => Effect.Effect<number, unknown, R>;
19
21
  export declare const isSupportedCallback: (value: unknown) => value is Callable;
@@ -1,5 +1,6 @@
1
1
  import { Effect, Exit } from "effect";
2
2
  import { coerceToNumber, coerceToString } from "../stdlib/value.js";
3
+ import { primitivePrototype } from "./intrinsics.js";
3
4
  import { typeError } from "./model.js";
4
5
  import { Callable, get, Native, DateObj, Obj } from "./objects.js";
5
6
  import { typeofValue } from "./references.js";
@@ -27,6 +28,13 @@ export const toPrimitive = (ctx, value, hint) => {
27
28
  throw typeError("Cannot convert object to primitive value.");
28
29
  });
29
30
  };
31
+ /** Invoke(value, name): calls the method the value would find through its prototype. */
32
+ export const invoke = (ctx, value, name, label) => {
33
+ const target = value instanceof Obj ? value : primitivePrototype(ctx.builtins, value);
34
+ if (target === undefined)
35
+ throw typeError(`${label} called on null or undefined.`);
36
+ return ctx.call(get(target, name), value, []);
37
+ };
30
38
  export const toPrimitiveString = (ctx, value) => Effect.map(toPrimitive(ctx, value, "string"), coerceToString);
31
39
  export const toPrimitiveNumber = (ctx, value) => Effect.map(toPrimitive(ctx, value, "number"), coerceToNumber);
32
40
  // The single acceptance list for callbacks: collections, sort, string replacers,
@@ -150,6 +150,7 @@ export const errorGlobal = (type, ctx) => {
150
150
  methods(builtins, prototype, [
151
151
  ["toString", 0, (thisValue) => errorToString(receiver(Obj, thisValue, "Error.prototype.toString"))],
152
152
  ]);
153
+ methods(builtins, ctor, [["isError", 1, (_, args) => args[0] instanceof ErrorObj]]);
153
154
  }
154
155
  return ctor;
155
156
  };
@@ -2,7 +2,7 @@ import type { Program } from "acorn";
2
2
  import { Effect } from "effect";
3
3
  import { type Json } from "../data.js";
4
4
  import { type ToolRuntime } from "../tool-runtime.js";
5
- import type { Builtins } from "./intrinsics.js";
5
+ import { type Builtins } from "./intrinsics.js";
6
6
  import { PromiseObj } from "./objects.js";
7
7
  import { Pending } from "./promises.js";
8
8
  /** One program execution: the tool bridge, promise scheduler, captured logs, and the global scope built once. */
@@ -4,6 +4,7 @@ import { ToolReference } from "../tool-runtime.js";
4
4
  import { AsyncIteratorSymbol, CallSite, GeneratorReturn, IteratorSymbol, OptionalShortCircuit, invalidData, Throw, rangeError, typeError, unsupportedSyntax, } from "./model.js";
5
5
  import { checkStringLength } from "./limits.js";
6
6
  import { locate, materialize } from "./errors.js";
7
+ import { primitivePrototype } from "./intrinsics.js";
7
8
  import { globals } from "./globals.js";
8
9
  import { assign, Callable, define, get, has, hasPrototype, keys, Native, parseArrayIndex, Arr, Bytes, DateObj, Fn, GeneratorObj, IteratorObj, MapObj, Obj, PromiseObj, SetObj, URLSearchParamsObj, HeadersObj, record, remove, set, } from "./objects.js";
9
10
  import { preserveConsumerError } from "./callback.js";
@@ -27,21 +28,27 @@ const loopExit = (result, labels) => {
27
28
  return result;
28
29
  return undefined;
29
30
  };
30
- const calleeDescription = (callee) => {
31
- if (callee?.type === "Identifier")
32
- return callee.name;
33
- if (callee?.type === "MemberExpression") {
34
- const object = callee.object;
35
- const property = callee.property;
36
- const key = !callee.computed && property.type === "Identifier"
37
- ? property.name
38
- : property.type === "Literal" && typeof property.value === "string"
39
- ? property.value
40
- : undefined;
41
- if (object.type === "Identifier" && key !== undefined)
42
- return `${object.name}.${key}`;
43
- }
44
- return "The called value";
31
+ // Native engines name the callee (`search(...).catch is not a function`), including call chains. Returns
32
+ // undefined when a link cannot be named, so a chain is either named completely or not at all.
33
+ const calleeDescription = (node) => {
34
+ if (node?.type === "Identifier")
35
+ return node.name;
36
+ if (node?.type === "CallExpression") {
37
+ const target = calleeDescription(node.callee);
38
+ return target === undefined ? undefined : `${target}(...)`;
39
+ }
40
+ if (node?.type !== "MemberExpression")
41
+ return undefined;
42
+ const property = node.property;
43
+ const key = !node.computed && property.type === "Identifier"
44
+ ? property.name
45
+ : property.type === "Literal" && typeof property.value === "string"
46
+ ? property.value
47
+ : undefined;
48
+ if (key === undefined)
49
+ return undefined;
50
+ const object = calleeDescription(node.object);
51
+ return object === undefined ? undefined : `${object}.${key}`;
45
52
  };
46
53
  // OrdinaryHasInstance: walk the left operand's chain looking for the constructor's `prototype`.
47
54
  const instanceofValue = (lhs, rhs, node) => {
@@ -1025,7 +1032,7 @@ class Frame {
1025
1032
  // `new` itself is supported, so a non-constructible callee is a TypeError like JS rather than
1026
1033
  // unsupported syntax. Built-ins like Number are real constructors in JS, so do not claim
1027
1034
  // otherwise; say `new` is unsupported for them and point at the plain call.
1028
- const name = calleeDescription(node.callee);
1035
+ const name = calleeDescription(node.callee) ?? "The called value";
1029
1036
  const message = callee instanceof Fn
1030
1037
  ? `${name} cannot be constructed: user-defined constructors and classes are not supported. Call it as a function that returns a plain object instead.`
1031
1038
  : callee instanceof Native
@@ -1312,7 +1319,7 @@ class Frame {
1312
1319
  if (callable instanceof Native) {
1313
1320
  return yield* self.native(() => callable.call(thisValue, args), node);
1314
1321
  }
1315
- throw typeError(`${calleeDescription(callee)} is not a function.`, callee ?? node);
1322
+ throw typeError(`${calleeDescription(callee) ?? "The called value"} is not a function.`, callee ?? node);
1316
1323
  });
1317
1324
  }
1318
1325
  // Built-ins throw without a location, synchronously or inside their Effect; the call site supplies it.
@@ -1712,20 +1719,17 @@ class Frame {
1712
1719
  }
1713
1720
  if (objectValue instanceof Obj)
1714
1721
  return { target: objectValue, key, receiver: objectValue };
1715
- // Primitives read through their wrapper prototype without being boxed; strings own length and indexes.
1716
- const builtins = self.ctx.builtins;
1722
+ // Strings own length and indexes; every other primitive property reads through the wrapper prototype.
1717
1723
  if (typeof objectValue === "string") {
1718
1724
  if (key === "length")
1719
1725
  return { value: objectValue.length };
1720
1726
  const index = typeof key === "symbol" ? undefined : parseArrayIndex(key);
1721
1727
  if (index !== undefined)
1722
1728
  return { value: objectValue[index] };
1723
- return { target: builtins.String, key, receiver: objectValue };
1724
1729
  }
1725
- if (typeof objectValue === "number")
1726
- return { target: builtins.Number, key, receiver: objectValue };
1727
- if (typeof objectValue === "boolean")
1728
- return { target: builtins.Boolean, key, receiver: objectValue };
1730
+ const proto = primitivePrototype(self.ctx.builtins, objectValue);
1731
+ if (proto !== undefined)
1732
+ return { target: proto, key, receiver: objectValue };
1729
1733
  if (objectValue === null || objectValue === undefined) {
1730
1734
  throw typeError(`Cannot read properties of ${objectValue} (reading '${String(key)}').`, objectNode);
1731
1735
  }
@@ -9,5 +9,7 @@ declare const builtins: readonly ["Object", "Function", "Array", "String", "Numb
9
9
  */
10
10
  export type Builtins = Readonly<Record<(typeof builtins)[number] | ErrorType, Obj>>;
11
11
  export declare const createErrorValue: (prototype: Obj, message: string | undefined) => ErrorObj;
12
+ /** The prototype a primitive reads its methods from without being boxed; none for null, undefined, and symbols. */
13
+ export declare const primitivePrototype: (builtins: Builtins, value: unknown) => Obj | undefined;
12
14
  export declare const createBuiltins: () => Builtins;
13
15
  export {};
@@ -40,6 +40,16 @@ export const createErrorValue = (prototype, message) => {
40
40
  define(value, "message", message, hidden);
41
41
  return value;
42
42
  };
43
+ /** The prototype a primitive reads its methods from without being boxed; none for null, undefined, and symbols. */
44
+ export const primitivePrototype = (builtins, value) => {
45
+ if (typeof value === "string")
46
+ return builtins.String;
47
+ if (typeof value === "number")
48
+ return builtins.Number;
49
+ if (typeof value === "boolean")
50
+ return builtins.Boolean;
51
+ return undefined;
52
+ };
43
53
  export const createBuiltins = () => {
44
54
  const object = new Obj(null);
45
55
  // Function.prototype is itself callable and returns undefined.
@@ -52,9 +52,10 @@ export const uriError = failure("URIError");
52
52
  export const supportedSyntaxMessage = "This is a restricted JavaScript-like language. Supported: plain and async functions, data literals, destructuring, standard control flow, await and Promise, and built-ins such as Array, Object, Math, JSON, Date, RegExp, Map, Set, and URL. Unsupported: classes, this, getters/setters, tagged templates, BigInt, and custom Symbols. Use plain functions and data objects instead.";
53
53
  export const unsupportedSyntax = (kind, node) => new PendingThrow("SyntaxError", `Syntax '${kind}' is not supported. ${supportedSyntaxMessage}`, node, "UnsupportedSyntax", [supportedSyntaxMessage]);
54
54
  export const isRecord = (value) => typeof value === "object" && value !== null;
55
+ // Acorn lines are 1-based and its columns are 0-based. Diagnostics use 1-based columns of the submitted source.
55
56
  export const sourceLocation = (node) => ({
56
- line: Math.max(1, (node.loc?.start.line ?? 2) - 1),
57
- column: Math.max(1, (node.loc?.start.column ?? 4) - 3),
57
+ line: node.loc?.start.line ?? 1,
58
+ column: (node.loc?.start.column ?? 0) + 1,
58
59
  });
59
60
  export const formatLocation = (node) => {
60
61
  if (!node?.loc)
@@ -4,7 +4,7 @@ import { checkArrayLength, checkStringLength, MAX_ARRAY_LENGTH } from "../interp
4
4
  import { invalidData, IteratorSymbol, rangeError, typeError } from "../interpreter/model.js";
5
5
  import { define, get, hidden, Arr, GeneratorObj, IteratorObj, Obj } from "../interpreter/objects.js";
6
6
  import { describeValue, rejectCircularInsertion } from "../interpreter/references.js";
7
- import { applyCollectionCallback, preserveConsumerError } from "../interpreter/callback.js";
7
+ import { applyCollectionCallback, invoke, preserveConsumerError } from "../interpreter/callback.js";
8
8
  import { compareText } from "../tool-runtime.js";
9
9
  import { coerceToNumber, coerceToString } from "./value.js";
10
10
  const arrayLikeSource = (source) => {
@@ -317,6 +317,13 @@ export const arrayGlobal = (ctx) => {
317
317
  return target;
318
318
  },
319
319
  ],
320
+ [
321
+ "toLocaleString",
322
+ 0,
323
+ (thisValue) => Effect.map(Effect.forEach(self(thisValue, "toLocaleString").items, (item) => item === null || item === undefined
324
+ ? Effect.succeed("")
325
+ : Effect.map(invoke(ctx, item, "toLocaleString", "Array.prototype.toLocaleString"), coerceToString)), (parts) => parts.join(",")),
326
+ ],
320
327
  ["keys", 0, (thisValue) => new IteratorObj(builtins.Iterator, self(thisValue, "keys").items.keys())],
321
328
  ["values", 0, (thisValue) => new IteratorObj(builtins.Iterator, self(thisValue, "values").items.values())],
322
329
  [
@@ -123,6 +123,31 @@ export const mapGlobal = (ctx) => {
123
123
  return target;
124
124
  },
125
125
  ],
126
+ [
127
+ "getOrInsert",
128
+ 2,
129
+ (thisValue, args) => {
130
+ const target = self(thisValue, "getOrInsert").map;
131
+ if (!target.has(args[0]))
132
+ target.set(args[0], args[1]);
133
+ return target.get(args[0]);
134
+ },
135
+ ],
136
+ [
137
+ "getOrInsertComputed",
138
+ 2,
139
+ (thisValue, args) => {
140
+ const target = self(thisValue, "getOrInsertComputed").map;
141
+ const apply = applyCollectionCallback(ctx, args[1], "Map.getOrInsertComputed");
142
+ if (target.has(args[0]))
143
+ return target.get(args[0]);
144
+ // The callback sees the stored key (-0 is +0) and its result wins over anything it inserted itself.
145
+ return Effect.map(apply([args[0] === 0 ? 0 : args[0]]), (value) => {
146
+ target.set(args[0], value);
147
+ return value;
148
+ });
149
+ },
150
+ ],
126
151
  ["delete", 1, (thisValue, args) => self(thisValue, "delete").map.delete(args[0])],
127
152
  [
128
153
  "clear",
@@ -92,6 +92,11 @@ export const dateGlobal = (ctx) => {
92
92
  ["toTimeString", 0, (thisValue) => new Date(self(thisValue, "toTimeString").time).toTimeString()],
93
93
  ["toUTCString", 0, (thisValue) => new Date(self(thisValue, "toUTCString").time).toUTCString()],
94
94
  ["toGMTString", 0, (thisValue) => new Date(self(thisValue, "toGMTString").time).toUTCString()],
95
+ ...["toLocaleString", "toLocaleDateString", "toLocaleTimeString"].map((name) => [
96
+ name,
97
+ 0,
98
+ (thisValue) => new Date(self(thisValue, name).time)[name]("en-US", { timeZone: "UTC" }),
99
+ ]),
95
100
  ...getters.map((name) => [name, 0, (thisValue) => new Date(self(thisValue, name).time)[name]()]),
96
101
  ...setters.map(([name, length]) => [
97
102
  name,
@@ -50,6 +50,7 @@ export const numberGlobal = (ctx) => {
50
50
  };
51
51
  methods(builtins, builtins.Number, [
52
52
  ["toFixed", 1, (thisValue, args) => self(thisValue, "toFixed").toFixed(optNum("toFixed", args[0]))],
53
+ ["toLocaleString", 0, (thisValue) => self(thisValue, "toLocaleString").toLocaleString("en-US")],
53
54
  [
54
55
  "toExponential",
55
56
  1,
@@ -3,7 +3,7 @@ import { constructor, methods, receiver } from "../interpreter/native.js";
3
3
  import { AsyncIteratorSymbol, invalidData, IteratorSymbol, rangeError, typeError, } from "../interpreter/model.js";
4
4
  import { Callable, define, entries, enumerableKeys, getOwn, hasOwn, hasPrototype, hidden, keys, own, Arr, Bytes, DateObj, ErrorObj, Obj, PromiseObj, RegExpObj, set, } from "../interpreter/objects.js";
5
5
  import { containsOpaqueReference, describeValue, rejectCircularInsertion } from "../interpreter/references.js";
6
- import { preserveConsumerError } from "../interpreter/callback.js";
6
+ import { invoke, preserveConsumerError } from "../interpreter/callback.js";
7
7
  import { ToolReference } from "../tool-runtime.js";
8
8
  import { groupBy } from "./collections.js";
9
9
  import { coerceToString } from "./value.js";
@@ -161,7 +161,7 @@ export const objectGlobal = (ctx) => {
161
161
  true,
162
162
  ],
163
163
  ["toString", 0, (thisValue) => `[object ${classTag(thisValue)}]`],
164
- ["toLocaleString", 0, (thisValue) => `[object ${classTag(thisValue)}]`],
164
+ ["toLocaleString", 0, (thisValue) => invoke(ctx, thisValue, "toString", "Object.prototype.toLocaleString")],
165
165
  [
166
166
  "valueOf",
167
167
  0,
@@ -130,6 +130,8 @@ export const stringGlobal = (ctx) => {
130
130
  simple("valueOf", 0, (value) => value),
131
131
  simple("toLowerCase", 0, (value) => value.toLowerCase()),
132
132
  simple("toUpperCase", 0, (value) => value.toUpperCase()),
133
+ simple("toLocaleLowerCase", 0, (value) => value.toLowerCase()),
134
+ simple("toLocaleUpperCase", 0, (value) => value.toUpperCase()),
133
135
  simple("trim", 0, (value) => value.trim()),
134
136
  simple("trimStart", 0, (value) => value.trimStart()),
135
137
  simple("trimLeft", 0, (value) => value.trimStart()),
@@ -66,6 +66,8 @@ export type Prepared<R = never> = {
66
66
  };
67
67
  export type SearchEntry = {
68
68
  readonly description: ToolDescription;
69
+ /** The path split into words, so `zones` matches `get_zones` as a word rather than as a substring of `timezones`. */
70
+ readonly pathWords: ReadonlyArray<string>;
69
71
  readonly searchText: string;
70
72
  };
71
73
  /** Exact callable signature of the built-in `search` function, for host-owned instructions. */
@@ -136,6 +136,7 @@ const makeSearchTool = (searchIndex) => ({
136
136
  const description = entry.description.description.toLowerCase();
137
137
  const score = terms.reduce((total, forms) => total +
138
138
  (forms.some((form) => path === form || path.endsWith(`.${form}`)) ? 20 : 0) +
139
+ (forms.some((form) => entry.pathWords.includes(form)) ? 12 : 0) +
139
140
  (forms.some((form) => path.includes(form)) ? 8 : 0) +
140
141
  (forms.some((form) => description.includes(form)) ? 4 : 0) +
141
142
  (forms.some((form) => entry.searchText.includes(form)) ? 2 : 0), 0);
@@ -163,6 +164,7 @@ export const searchSignature = (() => {
163
164
  })();
164
165
  const toSearchEntry = (visible) => ({
165
166
  description: describeTool(visible),
167
+ pathWords: tokenize(visible.path),
166
168
  searchText: [
167
169
  visible.path,
168
170
  visible.tool.description,
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.11",
4
+ "version": "2.0.12",
5
5
  "description": "Effect-native confined code execution over schema-described tools",
6
6
  "type": "module",
7
7
  "license": "MIT",