Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions packages/coding-agent/src/changes.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
# changes

## Anchor compiled-binary detection to exact virtual-filesystem url shapes (2026-08-30)

### What changed

- `packages/coding-agent/src/config.ts`: `isBunBinary` now derives from `isCompiledBunBinaryUrl()`, which matches only the exact embedded-module url shapes (`file:///$bunfs/...`, `file:///<drive>:/~BUN/...` raw or percent-encoded) instead of unrestricted substring checks.

### Why

- A stock `bun run` from a disk path containing a marker segment (e.g. `/tmp/$bunfs/...`) previously classified as a compiled binary, misrouting theme/package-dir resolution and, via the new compiled-host signal, mislabeling the eval js runtime badge as `native`.

### Why an extension could not handle it

- `isBunBinary` is core bootstrap classification consumed by config path resolution and the bundled-extension loader.

### Expected merge conflict zones

- LOW: `isBunBinary` definition in `packages/coding-agent/src/config.ts`.

## Measure Cursor tool-result history at the wire representation (2026-08-29)

### What changed
Expand Down
15 changes: 11 additions & 4 deletions packages/coding-agent/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,18 @@ const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

/**
* Detect if we're running as a Bun compiled binary.
* Bun binaries have import.meta.url containing "$bunfs", "~BUN", or "%7EBUN" (Bun's virtual filesystem path)
* Exact module-url shape of a module embedded in a Bun compiled binary:
* posix `file:///$bunfs/...` or the windows virtual drive
* `file:///<drive>:/~BUN/...` (raw or percent-encoded). Marker-named disk
* paths (e.g. `file:///tmp/$bunfs/...`) never match. Shapes are mirrored by
* senpi-codemode's runtime-info.ts.
*/
export const isBunBinary =
import.meta.url.includes("$bunfs") || import.meta.url.includes("~BUN") || import.meta.url.includes("%7EBUN");
export function isCompiledBunBinaryUrl(moduleUrl: string): boolean {
return moduleUrl.startsWith("file:///$bunfs/") || /^file:\/\/\/[A-Za-z]:\/(?:~BUN|%7EBUN)\//.test(moduleUrl);
}

/** Detect if we're running as a Bun compiled binary. */
export const isBunBinary = isCompiledBunBinaryUrl(import.meta.url);

/** Detect if Bun is the runtime (compiled binary or bun run) */
export const isBunRuntime = !!process.versions.bun;
Expand Down
20 changes: 20 additions & 0 deletions packages/coding-agent/src/core/changes.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# changes

<<<<<<< HEAD
## 2026-08-30 - Experimental workflow eval-only policy

### What changed
Expand All @@ -18,6 +19,25 @@
### Expected merge conflict zones

- `agent-session.ts`: active-tool selection, tool registry refresh, reload, and system-prompt assembly.

## 2026-08-30 - Publish compiled-binary host signal for sidecar extensions

### What changed

- `packages/coding-agent/src/core/resource-loader.ts`: before loading a bundled extension through `resolveBinaryFactory` in a compiled binary, the loader publishes `Symbol.for("@earendil-works/pi-coding-agent:compiled-binary-host")` on `globalThis`.

### Why

- Compiled binaries load bundled extensions (codemode) from the physical sidecar, whose module urls carry no bunfs marker; codemode's eval runtime badge reads this host classification to label the self-hosted runtime `native`.

### Why an extension could not handle it

- Only the binary loader knows it is executing the compiled-host loading path; extension code loaded from the sidecar cannot observe `isBunBinary` itself.

### Expected merge conflict zones

- `packages/coding-agent/src/core/resource-loader.ts` (bundled builtin extension loading)

## 2026-08-29 - Bound Cursor serialized tool-result admissions

### What changed
Expand Down
9 changes: 9 additions & 0 deletions packages/coding-agent/src/core/resource-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,14 @@ const VENDORED_BUILTIN_EXTENSION_PACKAGES: ReadonlyArray<{ builtinId: string; pa
];
const moduleRequire = createRequire(import.meta.url);

/**
* Published before loading bundled extensions from the physical sidecar of a
* compiled binary: sidecar module urls carry no bunfs marker, so extensions
* (codemode's eval runtime badge) read this host classification instead.
* Key convention matches the interactive theme registry.
*/
const COMPILED_BINARY_HOST_KEY = Symbol.for("@earendil-works/pi-coding-agent:compiled-binary-host");

const bundledBuiltinExtensions: ReadonlyArray<{
id: string;
resolvePackage: () => string;
Expand Down Expand Up @@ -1389,6 +1397,7 @@ export class DefaultResourceLoader implements ResourceLoader {
}
try {
if (isBunBinary && bundledExtension.resolveBinaryFactory) {
Reflect.set(globalThis, COMPILED_BINARY_HOST_KEY, true);
const factory = await bundledExtension.resolveBinaryFactory();
const extensionPath = `<builtin:${bundledExtension.id}>`;
const extension = await loadExtensionFromFactory(
Expand Down
24 changes: 24 additions & 0 deletions packages/coding-agent/test/config-compiled-binary-url.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { describe, expect, it } from "vitest";
import { isCompiledBunBinaryUrl } from "../src/config.ts";

describe("isCompiledBunBinaryUrl", () => {
it("matches the posix virtual filesystem root of a compiled binary", () => {
expect(isCompiledBunBinaryUrl("file:///$bunfs/root/pi")).toBe(true);
});

it("matches the windows virtual drive, raw and percent-encoded, any drive letter", () => {
expect(isCompiledBunBinaryUrl("file:///B:/~BUN/root/pi")).toBe(true);
expect(isCompiledBunBinaryUrl("file:///b:/%7EBUN/root/pi")).toBe(true);
});

it("never matches stock bun disk paths that merely contain a marker segment", () => {
expect(isCompiledBunBinaryUrl("file:///private/tmp/$bunfs-stock-integration/probe.ts")).toBe(false);
expect(isCompiledBunBinaryUrl("file:///tmp/$bunfs/project/config.ts")).toBe(false);
expect(isCompiledBunBinaryUrl("file:///Users/dev/~BUN/root/config.ts")).toBe(false);
expect(isCompiledBunBinaryUrl("file:///Users/dev/%7EBUN/root/config.ts")).toBe(false);
});

it("never matches ordinary disk urls", () => {
expect(isCompiledBunBinaryUrl("file:///Users/dev/senpi/src/config.ts")).toBe(false);
});
});
4 changes: 4 additions & 0 deletions packages/senpi-codemode/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@

### Changed

- Eval header runtime badges for the js kernel now read `native` when a compiled
standalone binary hosts the kernel itself (an omo/pi native build), e.g.
`eval js (native 1.4.0, ~/.omo/…/omo)`; stock bun and node badges and the eval
prompt host line are unchanged.
- The eval prompt's dependency-graph section is now `<workflow>` and states its contract directly:
define the workflow spec in code, one node per logically distinct step, rather than hand-authoring
the graph as a single opaque call.
Expand Down
5 changes: 4 additions & 1 deletion packages/senpi-codemode/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ task-tool names are known.
`eval js (node 26.7.0, /opt/…/bin/node)` — with the same `runtime` info on
`EvalToolDetails` and its `cells` for RPC consumers; interpreter detection
resolves absolute executable paths, and the eval prompt host line names the
JS runtime (`node`/`bun`).
JS runtime (`node`/`bun`). When a compiled standalone binary hosts the JS
kernel itself (an omo/pi native build), the badge reads `native` instead of
`bun` — `eval js (native 1.4.0, ~/.omo/…/omo)` — while the prompt host line
stays `bun` for engine capability.
- JavaScript import rewriting for supported local modules and package imports
in the persistent Node.js worker.
- GPT models receive a terse `eval` prompt dialect that prioritizes composing
Expand Down
63 changes: 59 additions & 4 deletions packages/senpi-codemode/src/extension/runtime-info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,74 @@ export interface JsRuntimeVersions {
readonly bun?: string | undefined;
}

/** Identity of the in-process JS kernel host: bun when its marker exists, node otherwise. */
/**
* Global-registry key the coding-agent binary loader publishes before loading
* this package from the physical sidecar of a compiled binary. Compiled hosts
* load codemode from disk, so this module's own url carries no bunfs marker;
* the host's classification is the authoritative signal. Follows the
* Symbol.for registry convention of the interactive theme.
*/
const COMPILED_HOST_KEY = Symbol.for("@earendil-works/pi-coding-agent:compiled-binary-host");

/**
* Exact module-url shapes of Bun's virtual filesystem in compiled binaries:
* posix `file:///$bunfs/...` and the windows virtual drive
* `file:///<drive>:/~BUN/...` (raw or percent-encoded). Anchored so stock bun
* runs from disk paths that merely contain a marker segment never match.
*/
const POSIX_VIRTUAL_URL_PREFIX = "file:///$bunfs/";
const WINDOWS_VIRTUAL_URL_PATTERN = /^file:\/\/\/[A-Za-z]:\/(?:~BUN|%7EBUN)\//;

export interface NativeRuntimeSignals {
readonly bunVersion?: string | undefined;
readonly moduleUrl?: string | undefined;
readonly hostCompiledBinary?: boolean | undefined;
}

/**
* True when the bun runtime hosting this code is a compiled standalone binary
* (an omo/pi native build): the in-process JS kernel then runs inside the
* application binary itself rather than a stock bun install.
*/
export function isNativeSelfRuntime(signals: NativeRuntimeSignals = processNativeSignals()): boolean {
const bun = signals.bunVersion;
if (bun === undefined || bun.length === 0) return false;
if (signals.hostCompiledBinary === true) return true;
const moduleUrl = signals.moduleUrl ?? "";
return moduleUrl.startsWith(POSIX_VIRTUAL_URL_PREFIX) || WINDOWS_VIRTUAL_URL_PATTERN.test(moduleUrl);
}

function processNativeSignals(): NativeRuntimeSignals {
return {
bunVersion: process.versions.bun,
moduleUrl: import.meta.url,
hostCompiledBinary: Reflect.get(globalThis, COMPILED_HOST_KEY) === true,
};
}

/**
* Identity of the in-process JS kernel host: native when a compiled binary
* hosts the kernel itself, bun when its marker exists, node otherwise.
*/
export function jsRuntimeInfo(
versions: JsRuntimeVersions = process.versions,
execPath: string = process.execPath,
nativeSelf: boolean = isNativeSelfRuntime(),
): EvalRuntimeInfo {
const bun = versions.bun;
if (bun !== undefined && bun.length > 0) return { name: "bun", version: bun, path: execPath };
if (bun !== undefined && bun.length > 0) {
return { name: nativeSelf ? "native" : "bun", version: bun, path: execPath };
}
return { name: "node", version: versions.node, path: execPath };
}

/** Short host-line segment, e.g. "node 26.7.0" or "bun 1.4.0". */
/**
* Short host-line segment, e.g. "node 26.7.0" or "bun 1.4.0". Stays
* runtime-truthful for the eval prompt, so a native binary still reads "bun":
* the model needs the engine capability surface, not the install identity.
*/
export function jsRuntimeLabel(versions: JsRuntimeVersions = process.versions): string {
const info = jsRuntimeInfo(versions, "");
const info = jsRuntimeInfo(versions, "", false);
return `${info.name} ${info.version}`;
}

Expand Down
21 changes: 21 additions & 0 deletions packages/senpi-codemode/test/eval-render-runtime.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,27 @@ describe("eval renderer runtime badge", () => {
expect(rendered[0]).toBe("eval js (node 26.7.0) done");
});

it("labels the js runtime as native when the kernel runs inside the compiled binary", () => {
const details: EvalToolDetails = {
language: "js",
durationMs: 0,
toolCalls: [],
truncated: false,
runtime: { name: "native", version: "1.4.0" },
};

const rendered = renderLines(
renderEvalResult(
evalResult(details, "complete"),
{ expanded: false, isPartial: false },
undefined,
resultContext(undefined, false),
),
);

expect(rendered[0]).toBe("eval js (native 1.4.0) done");
});

it("renders headers without any badge when runtime is unknown", () => {
const rendered = renderLines(
renderEvalResult(
Expand Down
86 changes: 85 additions & 1 deletion packages/senpi-codemode/test/runtime-info.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { describe, expect, it } from "vitest";
import { jsRuntimeInfo, jsRuntimeLabel, runtimesFromAvailability } from "../src/extension/runtime-info.ts";
import {
isNativeSelfRuntime,
jsRuntimeInfo,
jsRuntimeLabel,
runtimesFromAvailability,
} from "../src/extension/runtime-info.ts";
import type { InterpreterAvailability, LanguageAvailability } from "../src/interpreters/detect.ts";

const unavailable: LanguageAvailability = { enabled: false, detected: { ok: false } };
Expand Down Expand Up @@ -30,6 +35,85 @@ describe("jsRuntimeInfo", () => {
path: "/usr/local/bin/node",
});
});

it("reports native when the bun runtime is the compiled binary itself", () => {
expect(jsRuntimeInfo({ node: "26.7.0", bun: "1.4.0" }, "/Users/dev/.omo/binary-runtime/omo", true)).toEqual({
name: "native",
version: "1.4.0",
path: "/Users/dev/.omo/binary-runtime/omo",
});
});

it("keeps the bun name when the runtime is a stock bun install", () => {
expect(jsRuntimeInfo({ node: "26.7.0", bun: "1.4.0" }, "/opt/bun/bin/bun", false)).toEqual({
name: "bun",
version: "1.4.0",
path: "/opt/bun/bin/bun",
});
});

it("never reports native without the bun marker", () => {
expect(jsRuntimeInfo({ node: "26.7.0" }, "/usr/local/bin/node", true)).toEqual({
name: "node",
version: "26.7.0",
path: "/usr/local/bin/node",
});
});
});

describe("isNativeSelfRuntime", () => {
it("trusts the compiled-host signal even when the module loads from a disk sidecar", () => {
expect(
isNativeSelfRuntime({
bunVersion: "1.4.0",
hostCompiledBinary: true,
moduleUrl: "file:///Users/dev/node_modules/@code-yeongyu/senpi-codemode/src/extension/runtime-info.ts",
}),
).toBe(true);
});

it("ignores the compiled-host signal without the bun marker", () => {
expect(
isNativeSelfRuntime({ bunVersion: undefined, hostCompiledBinary: true, moduleUrl: "file:///x/y.ts" }),
).toBe(false);
});

it("detects the bun virtual filesystem in the module url of a compiled binary", () => {
expect(isNativeSelfRuntime({ bunVersion: "1.4.0", moduleUrl: "file:///$bunfs/root/runtime-info.ts" })).toBe(true);
});

it("detects windows virtual filesystem markers, raw and url-encoded", () => {
expect(isNativeSelfRuntime({ bunVersion: "1.4.0", moduleUrl: "file:///B:/~BUN/root/runtime-info.ts" })).toBe(
true,
);
expect(isNativeSelfRuntime({ bunVersion: "1.4.0", moduleUrl: "file:///B:/%7EBUN/root/runtime-info.ts" })).toBe(
true,
);
});

it("stays false for stock bun runs loading modules from disk", () => {
expect(isNativeSelfRuntime({ bunVersion: "1.4.0", moduleUrl: "file:///Users/dev/src/runtime-info.ts" })).toBe(
false,
);
});

it("stays false when a stock bun disk path merely contains a marker segment", () => {
expect(
isNativeSelfRuntime({ bunVersion: "1.4.0", moduleUrl: "file:///tmp/$bunfs/project/runtime-info.ts" }),
).toBe(false);
expect(
isNativeSelfRuntime({ bunVersion: "1.4.0", moduleUrl: "file:///Users/dev/~BUN/root/runtime-info.ts" }),
).toBe(false);
expect(
isNativeSelfRuntime({ bunVersion: "1.4.0", moduleUrl: "file:///Users/dev/%7EBUN/root/runtime-info.ts" }),
).toBe(false);
});

it("stays false under node even when the module url carries a marker", () => {
expect(isNativeSelfRuntime({ bunVersion: undefined, moduleUrl: "file:///$bunfs/root/runtime-info.ts" })).toBe(
false,
);
});
});

describe("jsRuntimeLabel", () => {
Expand Down
6 changes: 6 additions & 0 deletions packages/senpi-codemode/test/runtime-label.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ describe("formatRuntimeBadge", () => {
).toBe("bun 1.4.0, /usr/local/bin/bun");
});

it("labels the native self-hosted runtime like any js runtime", () => {
expect(
formatRuntimeBadge("js", { name: "native", version: "1.4.0", path: "/Users/dev/.omo/bin/omo" }, "/Users/dev"),
).toBe("native 1.4.0, ~/.omo/bin/omo");
});

it("falls back to a version-only badge when no path is known", () => {
expect(formatRuntimeBadge("py", { name: "python", version: "3.12.4" }, "/Users/dev")).toBe("3.12.4");
});
Expand Down
Loading