@opencode/codemode 0.0.0-dev-19567 → 0.0.0-dev-19570
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.
|
@@ -5,7 +5,11 @@ import type { DiagnosticKind } from "../codemode.js";
|
|
|
5
5
|
import type { ProgramError } from "./objects.js";
|
|
6
6
|
/** Any parsed node; the interpreter narrows on `type` and reads `loc` for diagnostics. */
|
|
7
7
|
export type AstNode = Node;
|
|
8
|
-
|
|
8
|
+
/** The program call a built-in is running under: where to locate failures born inside it, and how deep the stack is there. */
|
|
9
|
+
export declare const CallSite: Context.Reference<{
|
|
10
|
+
readonly node?: AstNode;
|
|
11
|
+
readonly depth: number;
|
|
12
|
+
}>;
|
|
9
13
|
export type Binding = {
|
|
10
14
|
mutable: boolean;
|
|
11
15
|
value: unknown;
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { Context } from "effect";
|
|
2
|
-
|
|
2
|
+
/** The program call a built-in is running under: where to locate failures born inside it, and how deep the stack is there. */
|
|
3
|
+
export const CallSite = Context.Reference("codemode/CallSite", {
|
|
4
|
+
defaultValue: () => ({ depth: 0 }),
|
|
5
|
+
});
|
|
3
6
|
export const AsyncIteratorSymbol = Symbol("codemode.async-iterator");
|
|
4
7
|
export const IteratorSymbol = Symbol("codemode.iterator");
|
|
5
8
|
export const IteratorSymbols = [AsyncIteratorSymbol, IteratorSymbol];
|
|
@@ -35,7 +35,7 @@ export class PromiseRuntime {
|
|
|
35
35
|
return Effect.flatMap(CallSite, (site) => {
|
|
36
36
|
// Allocate before forking so reruns get distinct IDs and diagnostics retain creation order.
|
|
37
37
|
const id = this.nextID++;
|
|
38
|
-
const body = Effect.catchDefect(effect, (defect) => Effect.die(locate(defect, site)));
|
|
38
|
+
const body = Effect.catchDefect(effect, (defect) => Effect.die(locate(defect, site.node)));
|
|
39
39
|
return Effect.map(Effect.forkIn(body, this.scope, { startImmediately: true }), (fiber) => {
|
|
40
40
|
const promise = new ProgramPromise(this.proto, fiber);
|
|
41
41
|
this.active.add(promise);
|
|
@@ -175,15 +175,20 @@ export class Runtime {
|
|
|
175
175
|
return this.root.run(program);
|
|
176
176
|
}
|
|
177
177
|
}
|
|
178
|
+
const MAX_CALL_DEPTH = 10_000;
|
|
178
179
|
/** One activation: the top-level program or a single function call, evaluating against its own scope chain. */
|
|
179
180
|
class Frame {
|
|
180
181
|
runtime;
|
|
181
182
|
scopes;
|
|
183
|
+
depth;
|
|
182
184
|
generatorState;
|
|
183
185
|
generatorAsync = false;
|
|
184
|
-
constructor(runtime, scopes
|
|
186
|
+
constructor(runtime, scopes,
|
|
187
|
+
/** Nested call depth; resets when an await resumes, since the continuation runs from the job queue. */
|
|
188
|
+
depth = 0) {
|
|
185
189
|
this.runtime = runtime;
|
|
186
190
|
this.scopes = scopes;
|
|
191
|
+
this.depth = depth;
|
|
187
192
|
}
|
|
188
193
|
run(program) {
|
|
189
194
|
const self = this;
|
|
@@ -523,7 +528,7 @@ class Frame {
|
|
|
523
528
|
})));
|
|
524
529
|
}
|
|
525
530
|
awaitValue(value) {
|
|
526
|
-
return Effect.flatMap(resolvePromise(this.runtime.runner, this.runtime.promises, value), (promise) => this.settlePromise(promise));
|
|
531
|
+
return Effect.flatMap(resolvePromise(this.runtime.runner, this.runtime.promises, value), (promise) => Effect.ensuring(this.settlePromise(promise), Effect.sync(() => (this.depth = 0))));
|
|
527
532
|
}
|
|
528
533
|
awaitAsyncFromSyncValue(iterator, value, node, closeOnRejection) {
|
|
529
534
|
const self = this;
|
|
@@ -1280,7 +1285,7 @@ class Frame {
|
|
|
1280
1285
|
return yield* self.createToolCallPromise(callable.path, args);
|
|
1281
1286
|
}
|
|
1282
1287
|
if (callable instanceof ProgramFunction)
|
|
1283
|
-
return yield* self.invokeFunction(callable, args);
|
|
1288
|
+
return yield* self.invokeFunction(callable, args, node);
|
|
1284
1289
|
if (callable instanceof NativeFunction) {
|
|
1285
1290
|
return yield* self.native(() => callable.call(thisValue, args), node);
|
|
1286
1291
|
}
|
|
@@ -1289,7 +1294,7 @@ class Frame {
|
|
|
1289
1294
|
}
|
|
1290
1295
|
// Built-ins throw without a location, synchronously or inside their Effect; the call site supplies it.
|
|
1291
1296
|
native(body, node) {
|
|
1292
|
-
return Effect.provideService(Effect.catchDefect(Effect.suspend(body), (defect) => Effect.die(locate(defect, node))), CallSite, node);
|
|
1297
|
+
return Effect.provideService(Effect.catchDefect(Effect.suspend(body), (defect) => Effect.die(locate(defect, node))), CallSite, { node, depth: this.depth });
|
|
1293
1298
|
}
|
|
1294
1299
|
evaluateCallArguments(argNodes) {
|
|
1295
1300
|
const self = this;
|
|
@@ -1315,37 +1320,43 @@ class Frame {
|
|
|
1315
1320
|
return args;
|
|
1316
1321
|
});
|
|
1317
1322
|
}
|
|
1318
|
-
|
|
1323
|
+
// A callback invoked by a built-in runs below the call that invoked the built-in, so the deeper of the two counts.
|
|
1324
|
+
invokeFunction(fn, args, node) {
|
|
1319
1325
|
const self = this;
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1326
|
+
return Effect.flatMap(CallSite, (site) => {
|
|
1327
|
+
const depth = Math.max(self.depth, site.depth) + 1;
|
|
1328
|
+
if (depth > MAX_CALL_DEPTH)
|
|
1329
|
+
throw rangeError("Maximum call stack size exceeded", node);
|
|
1330
|
+
const invocation = new Frame(this.runtime, new ScopeStack([...fn.capturedScopes, new Map()]), depth);
|
|
1331
|
+
const run = Effect.gen(function* () {
|
|
1332
|
+
// Seed all parameters first so defaults cannot fall through to same-named outer bindings.
|
|
1333
|
+
const paramScope = invocation.scopes.current();
|
|
1334
|
+
for (const parameter of fn.parameters) {
|
|
1335
|
+
for (const name of collectPatternNames(parameter)) {
|
|
1336
|
+
paramScope.set(name, { mutable: true, value: undefined, initialized: false });
|
|
1337
|
+
}
|
|
1327
1338
|
}
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1339
|
+
for (const [index, parameter] of fn.parameters.entries()) {
|
|
1340
|
+
if (parameter.type === "RestElement") {
|
|
1341
|
+
yield* invocation.declarePattern(parameter.argument, new ProgramArray(self.runtime.prototypes.Array, args.slice(index)), true, parameter, true);
|
|
1342
|
+
break;
|
|
1343
|
+
}
|
|
1344
|
+
yield* invocation.declarePattern(parameter, args[index], true, parameter, true);
|
|
1333
1345
|
}
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
return
|
|
1341
|
-
}
|
|
1342
|
-
|
|
1346
|
+
if (fn.body.type === "BlockStatement") {
|
|
1347
|
+
invocation.scopes.push();
|
|
1348
|
+
invocation.hoistVars(fn.body.body, paramScope);
|
|
1349
|
+
const result = yield* invocation.evaluateStatement(fn.body);
|
|
1350
|
+
return result.kind === "return" ? result.value : undefined;
|
|
1351
|
+
}
|
|
1352
|
+
return yield* invocation.evaluateExpression(fn.body);
|
|
1353
|
+
});
|
|
1354
|
+
if (fn.generator)
|
|
1355
|
+
return Effect.succeed(this.createGenerator(invocation, run, fn.async));
|
|
1356
|
+
if (!fn.async)
|
|
1357
|
+
return run;
|
|
1358
|
+
return this.runtime.promises.createWithSelf((self) => Effect.flatMap(run, (value) => resolvePromiseValue(invocation.runtime.runner, value, self)));
|
|
1343
1359
|
});
|
|
1344
|
-
if (fn.generator)
|
|
1345
|
-
return Effect.succeed(this.createGenerator(invocation, run, fn.async));
|
|
1346
|
-
if (!fn.async)
|
|
1347
|
-
return run;
|
|
1348
|
-
return this.runtime.promises.createWithSelf((self) => Effect.flatMap(run, (value) => resolvePromiseValue(invocation.runtime.runner, value, self)));
|
|
1349
1360
|
}
|
|
1350
1361
|
createGenerator(invocation, run, asynchronous) {
|
|
1351
1362
|
const state = { started: false, completed: false, draining: false, pending: [], pendingIndex: 0 };
|
package/dist/tool-runtime.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { Prototypes } from "./interpreter/intrinsics.js";
|
|
|
3
3
|
import { type Namespace } from "./namespace.js";
|
|
4
4
|
import { type Tool } from "./tool.js";
|
|
5
5
|
import type { Tools } from "./tools.js";
|
|
6
|
-
export declare const compareText: (left: string, right: string) =>
|
|
6
|
+
export declare const compareText: (left: string, right: string) => 0 | 1 | -1;
|
|
7
7
|
export type Services<T> = ServicesOf<T, []>;
|
|
8
8
|
type ServicesOf<T, Depth extends ReadonlyArray<unknown>> = Depth["length"] extends 8 ? never : T extends {
|
|
9
9
|
readonly _tag: "CodeModeTool";
|
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-
|
|
4
|
+
"version": "0.0.0-dev-19570",
|
|
5
5
|
"description": "Effect-native confined code execution over schema-described tools",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"license": "MIT",
|