@opencode/codemode 0.0.0-dev-19436 → 0.0.0-dev-19437

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.
@@ -136,7 +136,7 @@ export declare const Result: Schema.Union<readonly [Schema.Struct<{
136
136
  export type Result = typeof Result.Type;
137
137
  /** Reusable confined runtime over explicit tools. */
138
138
  export type Runtime<R = never> = {
139
- readonly catalog: () => ReadonlyArray<ToolDescription>;
139
+ readonly catalog: ReadonlyArray<ToolDescription>;
140
140
  readonly execute: (code: string) => Effect.Effect<Result, never, R>;
141
141
  };
142
142
  /** Executes one Effect-native CodeMode program without constructing a reusable runtime. */
package/dist/codemode.js CHANGED
@@ -60,7 +60,7 @@ export const make = (options = {}) => {
60
60
  const prepared = ToolRuntime.prepare((options.tools ?? {}));
61
61
  const limits = resolveExecutionLimits(options.limits);
62
62
  return {
63
- catalog: () => prepared.catalog,
63
+ catalog: prepared.catalog,
64
64
  execute: (code) => executeProgram(code, prepared, limits, options),
65
65
  };
66
66
  };
@@ -12,6 +12,9 @@ export declare class PromiseRuntime<R> {
12
12
  private readonly failures;
13
13
  private nextID;
14
14
  constructor(scope: Scope.Scope);
15
+ createWithSelf(body: (self: {
16
+ promise?: Values.Promise;
17
+ }) => Effect.Effect<unknown, unknown, R>): Effect.Effect<Values.Promise, never, R>;
15
18
  create(effect: Effect.Effect<unknown, unknown, R>): Effect.Effect<Values.Promise, never, R>;
16
19
  markObserved(promise: Values.Promise): void;
17
20
  await(promise: Values.Promise): Effect.Effect<Exit.Exit<unknown, unknown>>;
@@ -22,6 +22,14 @@ export class PromiseRuntime {
22
22
  constructor(scope) {
23
23
  this.scope = scope;
24
24
  }
25
+ // Resolution bodies need the promise's own identity to reject `resolve(promise)` self-resolution.
26
+ createWithSelf(body) {
27
+ const self = {};
28
+ return Effect.map(this.create(body(self)), (promise) => {
29
+ self.promise = promise;
30
+ return promise;
31
+ });
32
+ }
25
33
  create(effect) {
26
34
  return Effect.suspend(() => {
27
35
  // Allocate before forking so reruns get distinct IDs and diagnostics retain creation order.
@@ -103,11 +111,7 @@ export const resolvePromiseValue = (runner, value, node, own) => {
103
111
  export const resolvePromise = (runner, promises, value, node) => {
104
112
  if (value instanceof Values.Promise)
105
113
  return Effect.succeed(value);
106
- const box = {};
107
- return Effect.map(promises.create(resolvePromiseValue(runner, value, node, box)), (promise) => {
108
- box.promise = promise;
109
- return promise;
110
- });
114
+ return promises.createWithSelf((self) => resolvePromiseValue(runner, value, node, self));
111
115
  };
112
116
  const promiseStatics = ["all", "allSettled", "race", "any", "resolve", "reject"];
113
117
  const invokePromiseMethod = (runner, promises, name, args, node) => {
@@ -184,9 +188,7 @@ const constructPromise = (runner, promises, executor, node) => {
184
188
  }
185
189
  return Effect.gen(function* () {
186
190
  const deferred = Deferred.makeUnsafe();
187
- const box = {};
188
- const promise = yield* promises.create(Effect.flatMap(Deferred.await(deferred), (value) => resolvePromiseValue(runner, value, node, box)));
189
- box.promise = promise;
191
+ const promise = yield* promises.createWithSelf((self) => Effect.flatMap(Deferred.await(deferred), (value) => resolvePromiseValue(runner, value, node, self)));
190
192
  const resolve = capability("resolve", (value) => Deferred.doneUnsafe(deferred, Exit.succeed(value)));
191
193
  const reject = capability("reject", (value) => Deferred.doneUnsafe(deferred, Exit.fail(new ProgramThrow(value))));
192
194
  const executed = yield* Effect.exit(runner.invokeFunction(executor, [resolve, reject]));
@@ -223,20 +225,15 @@ const reactionExit = (promises, source) => Effect.gen(function* () {
223
225
  return exit;
224
226
  });
225
227
  const chainReaction = (runner, promises, source, onFulfilled, onRejected, method, node) => {
226
- const box = {};
227
- const body = Effect.gen(function* () {
228
+ return promises.createWithSelf((self) => Effect.gen(function* () {
228
229
  const exit = yield* reactionExit(promises, source);
229
230
  const handler = Exit.isSuccess(exit) ? onFulfilled : onRejected;
230
231
  if (handler === undefined)
231
232
  return yield* exit;
232
233
  const input = Exit.isSuccess(exit) ? exit.value : caughtErrorValue(Cause.squash(exit.cause));
233
234
  const result = yield* applyCollectionCallback(runner, handler, method, node)([input]);
234
- return yield* resolvePromiseValue(runner, result, node, box);
235
- });
236
- return Effect.map(promises.create(body), (derived) => {
237
- box.promise = derived;
238
- return derived;
239
- });
235
+ return yield* resolvePromiseValue(runner, result, node, self);
236
+ }));
240
237
  };
241
238
  const chainFinally = (runner, promises, source, cleanup, method, node) => promises.create(Effect.gen(function* () {
242
239
  const exit = yield* reactionExit(promises, source);
@@ -19,6 +19,20 @@ import { uriArgument, urlMethods, urlProperties, urlSearchParamsMethods, urlWrit
19
19
  import { enumerableSource } from "../stdlib/object.js";
20
20
  import { coerceToNumber, coerceToString, compoundOperators, errorBrandName } from "../stdlib/value.js";
21
21
  import { Values } from "../values.js";
22
+ // What a loop does with its body's result: exit with a StatementResult, or undefined to keep iterating.
23
+ // Unlabelled break ends this loop; a label the loop does not carry propagates outward.
24
+ const loopExit = (result, labels) => {
25
+ if (result.kind === "return")
26
+ return result;
27
+ if (result.kind === "break") {
28
+ if (result.label !== undefined && !labels?.has(result.label))
29
+ return result;
30
+ return { kind: "none" };
31
+ }
32
+ if (result.kind === "continue" && result.label !== undefined && !labels?.has(result.label))
33
+ return result;
34
+ return undefined;
35
+ };
22
36
  const calleeDescription = (callee) => {
23
37
  if (callee?.type === "Identifier")
24
38
  return callee.name;
@@ -352,20 +366,9 @@ class Frame {
352
366
  const self = this;
353
367
  return Effect.gen(function* () {
354
368
  while (yield* self.evaluateExpression(node.test)) {
355
- const result = yield* self.evaluateStatement(node.body);
356
- if (result.kind === "continue") {
357
- if (result.label !== undefined && !labels?.has(result.label))
358
- return result;
359
- continue;
360
- }
361
- if (result.kind === "break") {
362
- if (result.label !== undefined && !labels?.has(result.label))
363
- return result;
364
- return { kind: "none" };
365
- }
366
- if (result.kind === "return") {
367
- return result;
368
- }
369
+ const exit = loopExit(yield* self.evaluateStatement(node.body), labels);
370
+ if (exit !== undefined)
371
+ return exit;
369
372
  }
370
373
  return { kind: "none" };
371
374
  });
@@ -374,20 +377,9 @@ class Frame {
374
377
  const self = this;
375
378
  return Effect.gen(function* () {
376
379
  do {
377
- const result = yield* self.evaluateStatement(node.body);
378
- if (result.kind === "continue") {
379
- if (result.label !== undefined && !labels?.has(result.label))
380
- return result;
381
- continue;
382
- }
383
- if (result.kind === "break") {
384
- if (result.label !== undefined && !labels?.has(result.label))
385
- return result;
386
- return { kind: "none" };
387
- }
388
- if (result.kind === "return") {
389
- return result;
390
- }
380
+ const exit = loopExit(yield* self.evaluateStatement(node.body), labels);
381
+ if (exit !== undefined)
382
+ return exit;
391
383
  } while (yield* self.evaluateExpression(node.test));
392
384
  return { kind: "none" };
393
385
  });
@@ -422,24 +414,13 @@ class Frame {
422
414
  };
423
415
  nextIteration();
424
416
  while (testNode ? yield* self.evaluateExpression(testNode) : true) {
425
- const result = yield* self.evaluateStatement(node.body);
426
- if (result.kind === "return") {
427
- return result;
428
- }
429
- if (result.kind === "break") {
430
- if (result.label !== undefined && !labels?.has(result.label))
431
- return result;
432
- return { kind: "none" };
433
- }
434
- if (result.kind === "continue" && result.label !== undefined && !labels?.has(result.label))
435
- return result;
417
+ const exit = loopExit(yield* self.evaluateStatement(node.body), labels);
418
+ if (exit !== undefined)
419
+ return exit;
436
420
  nextIteration();
437
421
  if (updateNode) {
438
422
  yield* self.evaluateExpression(updateNode);
439
423
  }
440
- if (result.kind === "continue") {
441
- continue;
442
- }
443
424
  }
444
425
  return { kind: "none" };
445
426
  }).pipe(Effect.ensuring(Effect.sync(() => self.scopes.pop())));
@@ -499,20 +480,10 @@ class Frame {
499
480
  }
500
481
  return yield* Effect.failCause(bodyExit.cause);
501
482
  }
502
- const result = bodyExit.value;
503
- if (result.kind === "return") {
504
- yield* close();
505
- return result;
506
- }
507
- if (result.kind === "break") {
508
- yield* close();
509
- if (result.label !== undefined && !labels?.has(result.label))
510
- return result;
511
- return { kind: "none" };
512
- }
513
- if (result.kind === "continue" && result.label !== undefined && !labels?.has(result.label)) {
483
+ const exit = loopExit(bodyExit.value, labels);
484
+ if (exit !== undefined) {
514
485
  yield* close();
515
- return result;
486
+ return exit;
516
487
  }
517
488
  }
518
489
  }).pipe(Effect.ensuring(Effect.sync(() => {
@@ -705,19 +676,9 @@ class Frame {
705
676
  if (declared)
706
677
  self.scopes.pop();
707
678
  })));
708
- if (result.kind === "return") {
709
- return result;
710
- }
711
- if (result.kind === "break") {
712
- if (result.label !== undefined && !labels?.has(result.label))
713
- return result;
714
- return { kind: "none" };
715
- }
716
- if (result.kind === "continue") {
717
- if (result.label !== undefined && !labels?.has(result.label))
718
- return result;
719
- continue;
720
- }
679
+ const exit = loopExit(result, labels);
680
+ if (exit !== undefined)
681
+ return exit;
721
682
  }
722
683
  return { kind: "none" };
723
684
  }).pipe(Effect.ensuring(Effect.sync(() => {
@@ -97,13 +97,6 @@ const constructObject = (args, node) => {
97
97
  return first;
98
98
  throw new InterpreterRuntimeError(`Object(${typeof first}) wrapper objects are not supported; use the primitive value directly.`, node);
99
99
  };
100
- // Tool references are not data; only Object.keys(tools) reads them, for tool names.
101
- const rejectTools = (name, args, node) => {
102
- if (!(args[0] instanceof ToolReference))
103
- return;
104
- throw new InterpreterRuntimeError(`Object.${name}(...) cannot read tool references: they are not plain data. Use Object.keys(tools) for names, or search({ query }) for signatures.`, node, "InvalidDataValue");
105
- };
106
- const objectStatic = (name, impl) => sync(`Object.${name}`, impl);
107
100
  // Object constructs identically with or without new, like JS. Only `keys` copies its result into the
108
101
  // program; `values`, `entries`, `assign`, and `fromEntries` hand back the program's own values.
109
102
  export const objectGlobal = (runner, toolKeys) => new HostFunction({
@@ -115,22 +108,19 @@ export const objectGlobal = (runner, toolKeys) => new HostFunction({
115
108
  keys: sync("Object.keys", (args, node) => toProgram(args[0] instanceof ToolReference
116
109
  ? [...toolKeys(args[0].path)]
117
110
  : Object.keys(enumerableSource("Object.keys(...)", args[0], node)), "Object.keys result")),
118
- values: objectStatic("values", (args, node) => Object.values(enumerableSource("Object.values(...)", args[0], node))),
119
- entries: objectStatic("entries", (args, node) => Object.entries(enumerableSource("Object.entries(...)", args[0], node)).map(([key, item]) => [key, item])),
120
- hasOwn: objectStatic("hasOwn", (args, node) => Object.hasOwn(enumerableSource("Object.hasOwn(...)", args[0], node), args[1] === AsyncIteratorSymbol || args[1] === IteratorSymbol ? args[1] : String(args[1]))),
121
- is: objectStatic("is", (args, node) => {
111
+ values: sync("Object.values", (args, node) => Object.values(enumerableSource("Object.values(...)", args[0], node))),
112
+ entries: sync("Object.entries", (args, node) => Object.entries(enumerableSource("Object.entries(...)", args[0], node)).map(([key, item]) => [key, item])),
113
+ hasOwn: sync("Object.hasOwn", (args, node) => Object.hasOwn(enumerableSource("Object.hasOwn(...)", args[0], node), args[1] === AsyncIteratorSymbol || args[1] === IteratorSymbol ? args[1] : String(args[1]))),
114
+ is: sync("Object.is", (args, node) => {
122
115
  if (containsOpaqueReference(args[0]) || containsOpaqueReference(args[1])) {
123
116
  throw new InterpreterRuntimeError("Object.is requires data values.", node, "InvalidDataValue");
124
117
  }
125
118
  return Object.is(args[0], args[1]);
126
119
  }),
127
- assign: objectStatic("assign", objectAssign),
120
+ assign: sync("Object.assign", objectAssign),
128
121
  fromEntries: new HostFunction({
129
122
  name: "Object.fromEntries",
130
- call: (args, node) => Effect.suspend(() => {
131
- rejectTools("fromEntries", args, node);
132
- return objectFromEntries(runner, args[0], node);
133
- }),
123
+ call: (args, node) => Effect.suspend(() => objectFromEntries(runner, args[0], node)),
134
124
  }),
135
125
  groupBy: groupBy(runner, "Object"),
136
126
  },
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": "0.0.0-dev-19436",
4
+ "version": "0.0.0-dev-19437",
5
5
  "description": "Effect-native confined code execution over schema-described tools",
6
6
  "type": "module",
7
7
  "license": "MIT",