@code-yeongyu/senpi-codemode 2026.10.9 → 2026.10.10-11
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/CHANGELOG.md +190 -0
- package/README.md +161 -11
- package/package.json +6 -5
- package/src/bridge/memory-protocol.ts +8 -1
- package/src/bridge/protocol.ts +9 -4
- package/src/bridge/reserved.ts +2 -0
- package/src/bridges/eval-environment-schemas.ts +52 -0
- package/src/bridges/eval-virtual-schemas.ts +11 -4
- package/src/bridges/reserved-dispatch.ts +13 -1
- package/src/config/executable-settings.json +5 -0
- package/src/config/project-trust.ts +51 -0
- package/src/config/settings-overrides.ts +2 -0
- package/src/environments/editable-check.ts +1 -1
- package/src/environments/js-environments.ts +208 -0
- package/src/environments/js-installer.ts +268 -0
- package/src/environments/js-revision-files.ts +91 -0
- package/src/environments/no-links.ts +132 -0
- package/src/environments/packages-install.ts +98 -0
- package/src/environments/project-resolves.ts +54 -0
- package/src/environments/py-environment.ts +7 -3
- package/src/environments/py-installer.ts +5 -1
- package/src/environments/python-environments.ts +1 -1
- package/src/environments/revision-store.ts +20 -4
- package/src/extension/bridge-tool-call.ts +5 -1
- package/src/extension/eval-notifier.ts +13 -2
- package/src/extension/kernel-registration.ts +7 -2
- package/src/extension/runtime-factory.ts +51 -13
- package/src/extension/runtime-info.ts +6 -2
- package/src/extension/session-cwd.ts +25 -9
- package/src/extension/session-manager-contract.ts +3 -0
- package/src/extension/session-manager.ts +20 -6
- package/src/index.ts +3 -2
- package/src/interpreters/detect.ts +34 -1
- package/src/kernels/AGENTS.md +2 -0
- package/src/kernels/jl/runner.jl +11 -22
- package/src/kernels/js/cell-dispatch.ts +44 -0
- package/src/kernels/js/cell-ownership.js +268 -0
- package/src/kernels/js/cell-run-context.js +89 -0
- package/src/kernels/js/context-manager.ts +46 -51
- package/src/kernels/js/control-frames.ts +24 -0
- package/src/kernels/js/group-signal-notice.js +117 -0
- package/src/kernels/js/host-entries.ts +62 -0
- package/src/kernels/js/inline-worker.ts +2 -0
- package/src/kernels/js/kernel-contract.ts +16 -1
- package/src/kernels/js/kernel-memory-bridge.ts +1 -1
- package/src/kernels/js/kernel-memory.ts +79 -0
- package/src/kernels/js/kernel-tools-registry.js +1 -0
- package/src/kernels/js/local-module-loader.ts +25 -6
- package/src/kernels/js/process-drain-scan.d.ts +8 -0
- package/src/kernels/js/process-drain-scan.js +28 -0
- package/src/kernels/js/process-entry.js +466 -0
- package/src/kernels/js/process-memory-host.ts +83 -0
- package/src/kernels/js/process-tree-host.ts +4 -8
- package/src/kernels/js/process-tree.d.ts +11 -0
- package/src/kernels/js/process-tree.js +55 -10
- package/src/kernels/js/process-worker.ts +298 -0
- package/src/kernels/js/rejection-reports.js +61 -0
- package/src/kernels/js/run-queue.ts +7 -0
- package/src/kernels/js/windows-tree-kill-host.ts +117 -0
- package/src/kernels/js/windows-tree-kill.d.ts +19 -0
- package/src/kernels/js/windows-tree-kill.js +100 -0
- package/src/kernels/js/worker-core.js +53 -8
- package/src/kernels/js/worker-cwd.js +46 -12
- package/src/kernels/js/worker-host.ts +9 -2
- package/src/kernels/js/worker-indirect-eval.js +37 -13
- package/src/kernels/js/worker-package-resolve.js +153 -0
- package/src/kernels/js/worker-require.d.ts +19 -0
- package/src/kernels/js/worker-require.js +52 -0
- package/src/kernels/js/worker-runtime.js +66 -13
- package/src/kernels/js/worker-shadow-guard.js +2 -6
- package/src/kernels/js/worker-shell-capture.js +9 -0
- package/src/kernels/js/worker-slot.ts +8 -0
- package/src/kernels/js/worker-startup.ts +49 -1
- package/src/kernels/js/worker-webview.js +15 -1
- package/src/kernels/py/host-cell.ts +8 -31
- package/src/kernels/py/prelude.py +69 -27
- package/src/kernels/py/process.ts +4 -0
- package/src/kernels/py/transport.ts +4 -0
- package/src/kernels/rb/runner.rb +9 -19
- package/src/kernels/sandbox/sandbox-cell.ts +141 -0
- package/src/kernels/sandbox/vendor/pi-codemode/VENDORED.md +1 -0
- package/src/kernels/sandbox/vendor/pi-codemode/runtime/host.ts +2 -2
- package/src/kernels/sandbox/vendor/pi-codemode/runtime/prelude-source.ts +14 -1
- package/src/kernels/sandbox/vendor/pi-codemode/runtime/worker.ts +4 -1
- package/src/kernels/sandbox/vendor/pi-codemode/types.ts +2 -0
- package/src/kernels/shared/bun-ffi.ts +24 -0
- package/src/kernels/shared/host-cell.ts +57 -0
- package/src/kernels/shared/kernel-memory-host.ts +30 -7
- package/src/kernels/shared/process-cpu.ts +7 -3
- package/src/kernels/shared/process-group-cpu.ts +6 -3
- package/src/kernels/shared/subprocess-kernel.ts +29 -3
- package/src/kernels/shared/subprocess-memory-globals.ts +101 -0
- package/src/kernels/shared/subprocess-process.ts +24 -2
- package/src/kernels/shared/subprocess-queue.ts +1 -0
- package/src/prompt/eval-prompt.ts +8 -1
- package/src/tool/AGENTS.md +1 -0
- package/src/tool/cell-handler.ts +12 -11
- package/src/tool/cell-reserved-dispatch.ts +1 -0
- package/src/tool/cell-runtime.ts +4 -2
- package/src/tool/detached-cell-contract.ts +3 -0
- package/src/tool/detached-cell-manager.ts +4 -8
- package/src/tool/detached-cell-notification.ts +11 -63
- package/src/tool/detached-cell-snapshot.ts +17 -0
- package/src/tool/detached-eval-result.ts +13 -7
- package/src/tool/detached-notification-queue.ts +1 -2
- package/src/tool/eval-request.ts +23 -1
- package/src/tool/eval-tool-options.ts +3 -0
- package/src/tool/eval-tool.ts +19 -5
- package/src/tool/interrupt-note.ts +4 -5
- package/src/tool/live-headline.ts +60 -0
- package/src/tool/load-cell.ts +18 -3
- package/src/tool/magic-cell-host.ts +60 -2
- package/src/tool/magic-cells.ts +12 -2
- package/src/tool/managed-cell.ts +0 -4
- package/src/tool/render-agent.ts +110 -0
- package/src/tool/render-blocks.ts +252 -0
- package/src/tool/render-call.ts +130 -0
- package/src/tool/render-cell.ts +165 -0
- package/src/tool/render-detail.ts +152 -0
- package/src/tool/render-live.ts +288 -0
- package/src/tool/render-result.ts +202 -0
- package/src/tool/render-status.ts +166 -0
- package/src/tool/render-tail.ts +139 -0
- package/src/tool/render.ts +3 -1069
- package/src/tool/run-eval-cell.ts +53 -16
- package/src/tool/runtime-label.ts +2 -1
- package/src/tool/types.ts +34 -3
|
@@ -7,12 +7,12 @@ import {
|
|
|
7
7
|
kernelToolsStorage,
|
|
8
8
|
} from "@code-yeongyu/senpi";
|
|
9
9
|
import type { KernelToHostMessage } from "../bridge/protocol.ts";
|
|
10
|
+
import { resolveSandbox } from "../config/feature-settings.ts";
|
|
10
11
|
import { DEFAULT_FOREGROUND_WINDOW_SECONDS, defaultCodemodeSettings } from "../config/settings.ts";
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
} from "../kernels/js/kernel-tools-types.ts";
|
|
12
|
+
import type { JsEnvironments } from "../environments/js-environments.ts";
|
|
13
|
+
import type { PackagesInstallEnvironments } from "../environments/packages-install.ts";
|
|
14
|
+
import { KERNEL_TOOLS_CAPABILITIES, type KernelToolsCapability } from "../kernels/js/kernel-tools-types.ts";
|
|
15
|
+
import { sandboxCellExecutor, sandboxRuntimeInfo } from "../kernels/sandbox/sandbox-cell.ts";
|
|
16
16
|
import { TIMEOUT_PAUSE_OP, TIMEOUT_RESUME_OP } from "../timeouts/bridge-timeout.ts";
|
|
17
17
|
import { abortError, CellExecution, defaultTimeoutFactory } from "./cell-execution.ts";
|
|
18
18
|
import { CellHandler, type CellState } from "./cell-handler.ts";
|
|
@@ -42,7 +42,8 @@ export async function runEvalCell(
|
|
|
42
42
|
const bridgeAbortController = new AbortController();
|
|
43
43
|
const cellSignal = AbortSignal.any([invocation.signal, bridgeAbortController.signal]);
|
|
44
44
|
const bridgeContext: ExtensionContext = { ...invocation.ctx, signal: cellSignal };
|
|
45
|
-
const runtime =
|
|
45
|
+
const runtime =
|
|
46
|
+
invocation.input.isolate === true ? sandboxRuntimeInfo() : options.runtimes?.[invocation.input.language];
|
|
46
47
|
const state: CellState = {
|
|
47
48
|
input: invocation.input,
|
|
48
49
|
...(runtime === undefined ? {} : { runtime }),
|
|
@@ -238,6 +239,7 @@ async function executeCell(
|
|
|
238
239
|
...(kernelTools === undefined ? {} : { kernelTools }),
|
|
239
240
|
...(options.handles === undefined ? {} : { handles: options.handles }),
|
|
240
241
|
hardDeadlineMs: cell.startedAtMs + cell.hardLimitSeconds * 1_000,
|
|
242
|
+
...cellEnvironments(invocation.input.language, options),
|
|
241
243
|
});
|
|
242
244
|
handler = activeHandler;
|
|
243
245
|
cellManager.bindKernel(
|
|
@@ -261,25 +263,50 @@ async function executeCell(
|
|
|
261
263
|
}
|
|
262
264
|
if (invocation.input.reset) await execution.wait(kernel.reset());
|
|
263
265
|
execution.setKernel(kernel);
|
|
264
|
-
const magic = planMagicCell(
|
|
266
|
+
const magic = planMagicCell(
|
|
267
|
+
invocation.input.language,
|
|
268
|
+
invocation.input.code,
|
|
269
|
+
options.pythonEnvironments,
|
|
270
|
+
options.jsEnvironments,
|
|
271
|
+
);
|
|
265
272
|
// Resolved when the cell's turn comes in the kernel's queue: a %load reads the file the cells ahead of it
|
|
266
273
|
// wrote, and a refusal settles in queue order like any cell.
|
|
267
274
|
const loadOptions = { cwd: invocation.ctx.cwd, artifactsDir: options.artifactsDir };
|
|
268
|
-
|
|
269
|
-
|
|
275
|
+
// An isolated cell never runs a file outside its sandbox: %load there is refused.
|
|
276
|
+
const isolatedLoad = invocation.input.isolate === true && magic.kind === "load";
|
|
277
|
+
const resolveAtStart = isolatedLoad
|
|
278
|
+
? () => ({
|
|
279
|
+
ok: false as const,
|
|
280
|
+
message:
|
|
281
|
+
"isolate: true cannot run a %load cell: an isolated cell sees no host files, and loading one would break that isolation. Run %load in a normal cell, or paste the code into the isolated cell.",
|
|
282
|
+
})
|
|
283
|
+
: magic.kind === "load"
|
|
270
284
|
? () => loadCell(magic.target, loadOptions)
|
|
271
285
|
: magic.kind === "refused"
|
|
272
286
|
? () => ({ ok: false as const, message: magic.message })
|
|
273
287
|
: undefined;
|
|
288
|
+
const isolated =
|
|
289
|
+
invocation.input.isolate === true && resolveAtStart === undefined
|
|
290
|
+
? sandboxCellExecutor(invocation.input.code, {
|
|
291
|
+
sandbox: resolveSandbox(options.settings ?? {}),
|
|
292
|
+
executeTool: options.executeTool,
|
|
293
|
+
toolNames: () => (options.listTools?.() ?? []).map((tool) => tool.name),
|
|
294
|
+
describeTool: (name) => options.listTools?.().find((tool) => tool.name === name)?.description,
|
|
295
|
+
})
|
|
296
|
+
: undefined;
|
|
274
297
|
const environments = invocation.input.language === "py" ? options.pythonEnvironments : undefined;
|
|
275
298
|
const envRoot = environments === undefined ? undefined : () => environments.activeRoot ?? "";
|
|
299
|
+
const jsEnvironments = invocation.input.language === "js" ? options.jsEnvironments : undefined;
|
|
300
|
+
const packageRoot = jsEnvironments === undefined ? undefined : () => jsEnvironments.packageRoot;
|
|
276
301
|
const result = await execution.wait(
|
|
277
302
|
kernel.run({
|
|
278
303
|
cellId: invocation.cellId,
|
|
279
304
|
code: invocation.input.code,
|
|
280
305
|
...(resolveAtStart === undefined ? {} : { resolveAtStart }),
|
|
281
306
|
...(magic.kind === "host" ? { host: magic.executor } : {}),
|
|
307
|
+
...(isolated === undefined ? {} : { host: isolated }),
|
|
282
308
|
...(envRoot === undefined ? {} : { envRoot }),
|
|
309
|
+
...(packageRoot === undefined ? {} : { packageRoot }),
|
|
283
310
|
...(bridgeCellToken === undefined ? {} : { bridgeCellToken }),
|
|
284
311
|
kernelPreludes: options.kernelPreludes?.(),
|
|
285
312
|
onMessage,
|
|
@@ -325,14 +352,24 @@ async function executeCell(
|
|
|
325
352
|
}
|
|
326
353
|
|
|
327
354
|
function kernelToolsFor(kernel: EvalKernel): KernelToolsCapability | undefined {
|
|
328
|
-
if (
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
};
|
|
355
|
+
if (typeof kernel.describeKernelTools !== "function" || typeof kernel.invokeKernelTool !== "function")
|
|
356
|
+
return undefined;
|
|
357
|
+
const describeKernelTools = kernel.describeKernelTools.bind(kernel);
|
|
358
|
+
const invokeKernelTool = kernel.invokeKernelTool.bind(kernel);
|
|
333
359
|
return {
|
|
334
360
|
capabilities: KERNEL_TOOLS_CAPABILITIES,
|
|
335
|
-
describe:
|
|
336
|
-
invoke:
|
|
361
|
+
describe: describeKernelTools,
|
|
362
|
+
invoke: invokeKernelTool,
|
|
337
363
|
} satisfies ExtensionKernelTools;
|
|
338
364
|
}
|
|
365
|
+
|
|
366
|
+
// Only JS cells call tools in-process; a Python cell reaches packages.install() over the bridge, whose session manager
|
|
367
|
+
// holds the same Python environment its magics use.
|
|
368
|
+
function cellEnvironments(
|
|
369
|
+
language: string,
|
|
370
|
+
options: { readonly jsEnvironments?: JsEnvironments },
|
|
371
|
+
): { readonly environments?: PackagesInstallEnvironments } {
|
|
372
|
+
if (language === "js" && options.jsEnvironments !== undefined)
|
|
373
|
+
return { environments: { js: options.jsEnvironments } };
|
|
374
|
+
return {};
|
|
375
|
+
}
|
|
@@ -10,7 +10,8 @@ const ELLIPSIS = "\u2026";
|
|
|
10
10
|
* runtime name because node and bun are otherwise indistinguishable.
|
|
11
11
|
*/
|
|
12
12
|
export function formatRuntimeBadge(language: EvalLanguage, runtime: EvalRuntimeInfo, home: string = homedir()): string {
|
|
13
|
-
const
|
|
13
|
+
const base = language === "js" ? `${runtime.name} ${runtime.version}` : runtime.version;
|
|
14
|
+
const label = runtime.isolation === undefined ? base : `${base}, ${runtime.isolation}`;
|
|
14
15
|
if (runtime.path === undefined || runtime.path.length === 0) return label;
|
|
15
16
|
return `${label}, ${minifyPath(runtime.path, home)}`;
|
|
16
17
|
}
|
package/src/tool/types.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
AgentToolResult,
|
|
3
|
+
AgentToolUpdateCallback,
|
|
4
|
+
ExtensionKernelTools,
|
|
5
|
+
KernelPreludeContribution,
|
|
6
|
+
} from "@code-yeongyu/senpi";
|
|
2
7
|
import { type TSchema, type TUnsafe, Type } from "typebox";
|
|
3
8
|
import type { KernelMemoryReport } from "../bridge/memory-protocol.ts";
|
|
4
9
|
import type { HostToKernelMessage, KernelToHostMessage } from "../bridge/protocol.ts";
|
|
@@ -8,7 +13,7 @@ import {
|
|
|
8
13
|
DEFAULT_RUN_BUDGET_SECONDS,
|
|
9
14
|
defaultCodemodeSettings,
|
|
10
15
|
} from "../config/settings.ts";
|
|
11
|
-
import type { KernelToolsCapability } from "../kernels/js/kernel-tools-types.ts";
|
|
16
|
+
import type { KernelToolsCapability, KernelToolsDescribeResult } from "../kernels/js/kernel-tools-types.ts";
|
|
12
17
|
import type { TruncationMeta } from "../output/output-meta.ts";
|
|
13
18
|
|
|
14
19
|
export const evalLanguageOrder = ["js", "py", "rb", "jl"] as const;
|
|
@@ -52,6 +57,8 @@ export interface EvalToolInput {
|
|
|
52
57
|
readonly timeout?: number;
|
|
53
58
|
readonly on_timeout?: "detach" | "error";
|
|
54
59
|
readonly reset?: boolean;
|
|
60
|
+
/** Run in a fresh sandbox VM instead of the persistent kernel; accepted only while `sandbox.enabled` is on. */
|
|
61
|
+
readonly isolate?: boolean;
|
|
55
62
|
}
|
|
56
63
|
|
|
57
64
|
export interface EvalListInput {
|
|
@@ -117,14 +124,26 @@ const fullEvalInputSchema = Type.Object(
|
|
|
117
124
|
/** Runtime accepts a discriminated run/control union. */
|
|
118
125
|
export type EvalInputSchema = TUnsafe<EvalToolRequest> & Pick<typeof fullEvalInputSchema, "properties">;
|
|
119
126
|
|
|
127
|
+
const ISOLATE_FIELD_DESCRIPTION =
|
|
128
|
+
"js only. Fresh sandbox per call: no persistence, no fs/net/process/timers; only tool.* plus print/display.";
|
|
129
|
+
|
|
120
130
|
export function createEvalInputSchema(
|
|
121
131
|
enabled: EnabledEvalLanguages,
|
|
122
132
|
deadlines: EvalDeadlineSeconds = defaultEvalDeadlineSeconds,
|
|
133
|
+
options: { readonly sandbox?: boolean } = {},
|
|
123
134
|
): EvalInputSchema {
|
|
124
135
|
const languages = enabledLanguageList(enabled);
|
|
125
136
|
if (languages.length === 0) throw new Error("eval requires at least one enabled language");
|
|
126
137
|
const languageSchema = evalLanguageUnion(languages);
|
|
127
|
-
|
|
138
|
+
// The sandbox field exists in the schema only while sandbox cells are turned on, so the default schema
|
|
139
|
+
// (and the prompt built from it) stays exactly what it was.
|
|
140
|
+
const properties =
|
|
141
|
+
options.sandbox === true && languages.includes("js")
|
|
142
|
+
? {
|
|
143
|
+
...evalInputProperties(languageSchema, deadlines),
|
|
144
|
+
isolate: Type.Optional(Type.Boolean({ description: ISOLATE_FIELD_DESCRIPTION })),
|
|
145
|
+
}
|
|
146
|
+
: evalInputProperties(languageSchema, deadlines);
|
|
128
147
|
return Type.Unsafe<EvalToolRequest>(
|
|
129
148
|
Type.Object(properties, {
|
|
130
149
|
// Keep branches self-contained for Mistral-hosted GLM (#2240).
|
|
@@ -175,6 +194,12 @@ export interface EvalKernelRunInput {
|
|
|
175
194
|
readonly envRoot?: () => string;
|
|
176
195
|
/** The file a `%load` cell runs: tracebacks name it and its relative imports resolve from its directory. */
|
|
177
196
|
readonly sourceFile?: string;
|
|
197
|
+
/**
|
|
198
|
+
* JavaScript only: the session's managed package revision; bare imports that do not resolve from cwd fall back to
|
|
199
|
+
* it. Read when the cell starts running (not when it was queued), so a cell queued behind `%bun add` resolves the
|
|
200
|
+
* revision that install published.
|
|
201
|
+
*/
|
|
202
|
+
readonly packageRoot?: () => string | undefined;
|
|
178
203
|
/**
|
|
179
204
|
* Called when the cell's turn comes in the kernel's queue, never earlier: what to run instead of `code` (a `%load`
|
|
180
205
|
* cell's file), or a refusal that settles the cell as failed in queue order.
|
|
@@ -218,6 +243,10 @@ export interface EvalKernel {
|
|
|
218
243
|
isAlive?(): boolean;
|
|
219
244
|
/** Hands over, and forgets, every queued cell of a dead kernel that never started. */
|
|
220
245
|
drainPending?(): readonly PendingCell[];
|
|
246
|
+
/** Describes this kernel's registered kernel tools; only an in-process JS kernel has them. */
|
|
247
|
+
describeKernelTools?(names: readonly string[]): Promise<KernelToolsDescribeResult>;
|
|
248
|
+
/** Invokes one of this kernel's kernel tools; present exactly when `describeKernelTools` is. */
|
|
249
|
+
invokeKernelTool?: ExtensionKernelTools["invoke"];
|
|
221
250
|
}
|
|
222
251
|
|
|
223
252
|
export interface EvalKernelManager {
|
|
@@ -259,6 +288,8 @@ export interface EvalRuntimeInfo {
|
|
|
259
288
|
readonly name: string;
|
|
260
289
|
readonly version: string;
|
|
261
290
|
readonly path?: string;
|
|
291
|
+
/** JS only: the kernel runs in a child process (`process`), or the cell ran in an isolated QuickJS VM (`sandbox`). */
|
|
292
|
+
readonly isolation?: "process" | "sandbox";
|
|
262
293
|
}
|
|
263
294
|
|
|
264
295
|
export type EvalRuntimes = Readonly<Partial<Record<EvalLanguage, EvalRuntimeInfo>>>;
|