@galaxy-foundry/gxwf-pi-harness 0.0.0 → 0.1.0

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/Dockerfile ADDED
@@ -0,0 +1,19 @@
1
+ ARG NODE_IMAGE=node:22.19.0-bookworm-slim
2
+ FROM ${NODE_IMAGE}
3
+
4
+ ARG PI_VERSION=0.84.4
5
+ ARG FOUNDRY_CLI_VERSION=0.1.0
6
+
7
+ RUN apt-get update \
8
+ && apt-get install -y --no-install-recommends bash ca-certificates git ripgrep \
9
+ && rm -rf /var/lib/apt/lists/*
10
+ RUN npm install -g --ignore-scripts \
11
+ "@earendil-works/pi-coding-agent@${PI_VERSION}" \
12
+ "@galaxy-foundry/gxwf-foundry@${FOUNDRY_CLI_VERSION}"
13
+
14
+ LABEL org.galaxyproject.foundry.pi-version="${PI_VERSION}" \
15
+ org.galaxyproject.foundry.cli-version="${FOUNDRY_CLI_VERSION}" \
16
+ org.galaxyproject.foundry.pi-rpc-version="1"
17
+
18
+ WORKDIR /workspace
19
+ ENTRYPOINT ["pi"]
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 Galaxy Project
3
+ Copyright (c) 2026 John Chilton
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,5 +1,43 @@
1
1
  # @galaxy-foundry/gxwf-pi-harness
2
2
 
3
- Reserved bootstrap package for the Galaxy Workflow Foundry Pi evaluation harness.
3
+ Pi-backed worker isolation for evaluating published Galaxy Workflow Foundry skills.
4
4
 
5
- The implementation will be published from [galaxyproject/foundry](https://github.com/galaxyproject/foundry) through npm trusted publishing.
5
+ The package has two surfaces:
6
+
7
+ - `runPiSkill()` starts one ephemeral Pi RPC worker with one explicitly loaded skill, a fresh configuration directory, staged declared inputs, and ambient resource discovery disabled.
8
+ - `@galaxy-foundry/gxwf-pi-harness/extension` registers the constrained `foundry_subagent` tool used by a top-level Pipeline skill.
9
+
10
+ The extension derives the worker's expected artifacts exclusively from the selected published cast's `_provenance.json`. The parent agent can choose the skill, task, and declared inputs, but cannot replace or suppress that artifact contract.
11
+
12
+ Local mode is process and context isolation, not a security boundary. The trace CLI defaults each local run to a unique directory under the operating system's temporary directory, and both local and container workers load a dereferenced staged copy of the selected skill rather than its checkout path. An explicit `--run-dir` still overrides that diagnostic default.
13
+
14
+ Container mode runs the whole Pi RPC worker inside a disposable Docker container. It mounts the staged skill bundle and copied declared inputs read-only, mounts only the run's output directory read-write, and uses tmpfs for Pi configuration and temporary files. The checkout itself is never mounted.
15
+
16
+ Build the default image from the repository root:
17
+
18
+ ```sh
19
+ npm run gxwf-pi-harness:container-build
20
+ ```
21
+
22
+ The image pins Pi 0.84.4 and the `@galaxy-foundry/gxwf-foundry` CLI 0.1.0 required by the pilot `summarize-nextflow` skill. It carries compatibility labels for both runtimes that are checked before every run. A caller may use `--sandbox-image <ref>` for another locally available image with the same labels. The runner resolves the ref to an immutable image ID before launch and records that ID, any repository digests, every mount, the network policy, and the names—not values—of forwarded credential variables.
23
+
24
+ Container provider access is explicit. Use `--sandbox-network bridge` and repeat `--credential-env <NAME>` for only the variables the provider needs. Use `--sandbox-network none` for credential-free probes. Run the Docker boundary test with `npm run gxwf-pi-harness:container-test`.
25
+
26
+ ## Extension configuration
27
+
28
+ - `FOUNDRY_SKILLS_DIR` — required path to the installed Foundry skills root.
29
+ - `FOUNDRY_RUNS_DIR` — directory for child run records; defaults to a temporary directory.
30
+ - `FOUNDRY_WORKER_TIMEOUT_MS` — child wall timeout; defaults to ten minutes.
31
+ - `FOUNDRY_SANDBOX` — `local` (default) or `container`.
32
+ - `FOUNDRY_SANDBOX_IMAGE` — optional compatible container image ref.
33
+ - `FOUNDRY_SANDBOX_NETWORK` — `bridge` (default) or `none`.
34
+ - `FOUNDRY_SANDBOX_CREDENTIAL_ENV` — comma-separated environment-variable allowlist.
35
+
36
+ The trace-mode CLI also accepts `--thinking <level>` when an evaluation should pin Pi's
37
+ reasoning level rather than use the model default.
38
+
39
+ The extension accepts skill names, never arbitrary skill paths. It resolves each name as one direct child of `FOUNDRY_SKILLS_DIR` and starts the child through the same runner used by trace-mode callers.
40
+
41
+ ## License
42
+
43
+ MIT.
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=container-rpc-entry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"container-rpc-entry.d.ts","sourceRoot":"","sources":["../src/container-rpc-entry.ts"],"names":[],"mappings":""}
@@ -0,0 +1,37 @@
1
+ import { spawn, spawnSync } from "node:child_process";
2
+ import process from "node:process";
3
+ import { buildDockerRunArgs } from "./container.js";
4
+ const encoded = process.env.FOUNDRY_CONTAINER_LAUNCH_CONFIG;
5
+ if (!encoded)
6
+ throw new Error("FOUNDRY_CONTAINER_LAUNCH_CONFIG is required");
7
+ const config = JSON.parse(encoded);
8
+ const args = buildDockerRunArgs(config, process.argv.slice(2));
9
+ const child = spawn(config.docker_bin, args, { stdio: ["pipe", "pipe", "pipe"] });
10
+ process.stdin.pipe(child.stdin);
11
+ child.stdout.pipe(process.stdout);
12
+ child.stderr.pipe(process.stderr);
13
+ let stopping = false;
14
+ function stop() {
15
+ if (stopping)
16
+ return;
17
+ stopping = true;
18
+ child.kill("SIGTERM");
19
+ spawnSync(config.docker_bin, ["container", "rm", "--force", config.container_name], {
20
+ stdio: "ignore",
21
+ timeout: 2_000,
22
+ });
23
+ }
24
+ process.once("SIGINT", stop);
25
+ process.once("SIGTERM", stop);
26
+ child.once("error", (error) => {
27
+ process.stderr.write(`Unable to start Docker worker: ${error.message}\n`);
28
+ process.stdin.unpipe(child.stdin);
29
+ process.stdin.pause();
30
+ process.exitCode = 1;
31
+ });
32
+ child.once("exit", (code, signal) => {
33
+ process.stdin.unpipe(child.stdin);
34
+ process.stdin.pause();
35
+ process.exitCode = code ?? (signal ? 1 : 0);
36
+ });
37
+ //# sourceMappingURL=container-rpc-entry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"container-rpc-entry.js","sourceRoot":"","sources":["../src/container-rpc-entry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,OAAO,MAAM,cAAc,CAAC;AAEnC,OAAO,EAAE,kBAAkB,EAA8B,MAAM,gBAAgB,CAAC;AAEhF,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAC;AAC5D,IAAI,CAAC,OAAO;IAAE,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;AAC7E,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAA0B,CAAC;AAC5D,MAAM,IAAI,GAAG,kBAAkB,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/D,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,UAAU,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;AAElF,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AAChC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;AAClC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;AAElC,IAAI,QAAQ,GAAG,KAAK,CAAC;AACrB,SAAS,IAAI;IACX,IAAI,QAAQ;QAAE,OAAO;IACrB,QAAQ,GAAG,IAAI,CAAC;IAChB,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACtB,SAAS,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,CAAC,cAAc,CAAC,EAAE;QAClF,KAAK,EAAE,QAAQ;QACf,OAAO,EAAE,KAAK;KACf,CAAC,CAAC;AACL,CAAC;AAED,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;AAC7B,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;AAC9B,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;IAC5B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,kCAAkC,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;IAC1E,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAClC,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACtB,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC,CAAC,CAAC;AACH,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE;IAClC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAClC,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACtB,OAAO,CAAC,QAAQ,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9C,CAAC,CAAC,CAAC"}
@@ -0,0 +1,33 @@
1
+ export declare const FOUNDRY_CLI_VERSION = "0.1.0";
2
+ export declare const DEFAULT_CONTAINER_IMAGE: string;
3
+ export declare const CONTAINER_PI_VERSION_LABEL = "org.galaxyproject.foundry.pi-version";
4
+ export declare const CONTAINER_FOUNDRY_VERSION_LABEL = "org.galaxyproject.foundry.cli-version";
5
+ export declare const CONTAINER_RPC_VERSION_LABEL = "org.galaxyproject.foundry.pi-rpc-version";
6
+ export declare const CONTAINER_RPC_VERSION = "1";
7
+ export type ContainerNetworkPolicy = "bridge" | "none";
8
+ export interface ContainerMount {
9
+ type: "bind" | "tmpfs";
10
+ source?: string;
11
+ target: string;
12
+ read_only: boolean;
13
+ purpose: "skill" | "inputs" | "output" | "agent-config" | "temporary-files";
14
+ }
15
+ export interface ContainerImageResolution {
16
+ requested: string;
17
+ resolved_id: string;
18
+ repo_digests: string[];
19
+ pi_version: string;
20
+ foundry_cli_version: string;
21
+ }
22
+ export interface ContainerLaunchConfig {
23
+ docker_bin: string;
24
+ container_name: string;
25
+ image_id: string;
26
+ network: ContainerNetworkPolicy;
27
+ credential_env: string[];
28
+ user?: string;
29
+ mounts: ContainerMount[];
30
+ }
31
+ export declare function inspectContainerImage(image: string, dockerBin?: string): ContainerImageResolution;
32
+ export declare function buildDockerRunArgs(config: ContainerLaunchConfig, piArgs: string[]): string[];
33
+ //# sourceMappingURL=container.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../src/container.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,mBAAmB,UAAU,CAAC;AAC3C,eAAO,MAAM,uBAAuB,QAAmF,CAAC;AACxH,eAAO,MAAM,0BAA0B,yCAAyC,CAAC;AACjF,eAAO,MAAM,+BAA+B,0CAA0C,CAAC;AACvF,eAAO,MAAM,2BAA2B,6CAA6C,CAAC;AACtF,eAAO,MAAM,qBAAqB,MAAM,CAAC;AAEzC,MAAM,MAAM,sBAAsB,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEvD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,cAAc,GAAG,iBAAiB,CAAC;CAC7E;AAED,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,sBAAsB,CAAC;IAChC,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,cAAc,EAAE,CAAC;CAC1B;AAgBD,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,MAAM,EACb,SAAS,SAAW,GACnB,wBAAwB,CAwC1B;AAoBD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,qBAAqB,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CA6B5F"}
@@ -0,0 +1,101 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import { VERSION as PI_VERSION } from "@earendil-works/pi-coding-agent";
3
+ export const FOUNDRY_CLI_VERSION = "0.1.0";
4
+ export const DEFAULT_CONTAINER_IMAGE = `galaxy-foundry/gxwf-pi-harness:pi-${PI_VERSION}-foundry-${FOUNDRY_CLI_VERSION}`;
5
+ export const CONTAINER_PI_VERSION_LABEL = "org.galaxyproject.foundry.pi-version";
6
+ export const CONTAINER_FOUNDRY_VERSION_LABEL = "org.galaxyproject.foundry.cli-version";
7
+ export const CONTAINER_RPC_VERSION_LABEL = "org.galaxyproject.foundry.pi-rpc-version";
8
+ export const CONTAINER_RPC_VERSION = "1";
9
+ function dockerFailure(command, stderr) {
10
+ const detail = stderr?.trim();
11
+ return new Error(`Docker ${command.join(" ")} failed${detail ? `: ${detail}` : ""}. ` +
12
+ `Build the default image with "npm run gxwf-pi-harness:container-build" or supply --sandbox-image.`);
13
+ }
14
+ export function inspectContainerImage(image, dockerBin = "docker") {
15
+ if (!image.trim())
16
+ throw new Error("container image must not be empty");
17
+ const command = ["image", "inspect", image];
18
+ const inspected = spawnSync(dockerBin, command, {
19
+ encoding: "utf8",
20
+ stdio: ["ignore", "pipe", "pipe"],
21
+ });
22
+ if (inspected.error)
23
+ throw inspected.error;
24
+ if (inspected.status !== 0)
25
+ throw dockerFailure(command, inspected.stderr);
26
+ const parsed = JSON.parse(inspected.stdout);
27
+ if (!Array.isArray(parsed) || parsed.length !== 1) {
28
+ throw new Error(`Docker returned an invalid image inspection for ${image}`);
29
+ }
30
+ const record = parsed[0];
31
+ if (typeof record.Id !== "string" || !record.Id.startsWith("sha256:")) {
32
+ throw new Error(`Docker image ${image} has no immutable sha256 image id`);
33
+ }
34
+ const labels = record.Config?.Labels ?? {};
35
+ const imagePiVersion = labels?.[CONTAINER_PI_VERSION_LABEL];
36
+ const foundryCliVersion = labels?.[CONTAINER_FOUNDRY_VERSION_LABEL];
37
+ const rpcVersion = labels?.[CONTAINER_RPC_VERSION_LABEL];
38
+ if (imagePiVersion !== PI_VERSION ||
39
+ foundryCliVersion !== FOUNDRY_CLI_VERSION ||
40
+ rpcVersion !== CONTAINER_RPC_VERSION) {
41
+ throw new Error(`Docker image ${image} is not a compatible Foundry Pi worker ` +
42
+ `(expected Pi ${PI_VERSION}, Foundry CLI ${FOUNDRY_CLI_VERSION}, and RPC contract ${CONTAINER_RPC_VERSION})`);
43
+ }
44
+ return {
45
+ requested: image,
46
+ resolved_id: record.Id,
47
+ repo_digests: Array.isArray(record.RepoDigests)
48
+ ? record.RepoDigests.filter((value) => typeof value === "string")
49
+ : [],
50
+ pi_version: imagePiVersion,
51
+ foundry_cli_version: foundryCliVersion,
52
+ };
53
+ }
54
+ function bindMountArgument(mount) {
55
+ if (!mount.source)
56
+ throw new Error(`bind mount ${mount.target} has no source`);
57
+ if (mount.source.includes(",")) {
58
+ throw new Error(`Docker bind mount source cannot contain a comma: ${mount.source}`);
59
+ }
60
+ return [
61
+ "type=bind",
62
+ `src=${mount.source}`,
63
+ `dst=${mount.target}`,
64
+ ...(mount.read_only ? ["readonly", "bind-recursive=disabled"] : []),
65
+ ].join(",");
66
+ }
67
+ function tmpfsArgument(mount) {
68
+ const size = mount.purpose === "agent-config" ? "64m" : "128m";
69
+ return `${mount.target}:rw,nosuid,nodev,size=${size},mode=1777`;
70
+ }
71
+ export function buildDockerRunArgs(config, piArgs) {
72
+ const args = [
73
+ "run",
74
+ "--rm",
75
+ "--interactive",
76
+ "--pull=never",
77
+ "--name",
78
+ config.container_name,
79
+ "--init",
80
+ "--read-only",
81
+ "--cap-drop=ALL",
82
+ "--security-opt=no-new-privileges",
83
+ "--pids-limit=256",
84
+ `--network=${config.network}`,
85
+ "--workdir=/workspace",
86
+ ];
87
+ if (config.user)
88
+ args.push(`--user=${config.user}`);
89
+ for (const mount of config.mounts) {
90
+ if (mount.type === "bind")
91
+ args.push("--mount", bindMountArgument(mount));
92
+ else
93
+ args.push("--tmpfs", tmpfsArgument(mount));
94
+ }
95
+ args.push("--env=HOME=/tmp", "--env=PI_CODING_AGENT_DIR=/pi-agent", "--env=PI_SKIP_VERSION_CHECK=1");
96
+ for (const name of config.credential_env)
97
+ args.push("--env", name);
98
+ args.push(config.image_id, ...piArgs);
99
+ return args;
100
+ }
101
+ //# sourceMappingURL=container.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"container.js","sourceRoot":"","sources":["../src/container.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { type ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
+ export default function foundryPiHarness(pi: ExtensionAPI): void;
3
+ //# sourceMappingURL=extension.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extension.d.ts","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":"AAMA,OAAO,EAAc,KAAK,YAAY,EAAE,MAAM,iCAAiC,CAAC;AA0HhF,MAAM,CAAC,OAAO,UAAU,gBAAgB,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CAE/D"}
@@ -0,0 +1,116 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { mkdirSync } from "node:fs";
3
+ import { tmpdir } from "node:os";
4
+ import path from "node:path";
5
+ import { Type } from "@earendil-works/pi-ai";
6
+ import { defineTool } from "@earendil-works/pi-coding-agent";
7
+ import { runPiSkill } from "./runner.js";
8
+ import { resolveDeclaredInput, resolveInstalledSkill } from "./skill-resolution.js";
9
+ const FoundrySubagentParams = Type.Object({
10
+ skill: Type.String({ description: "Published Foundry skill name" }),
11
+ task: Type.String({ description: "One phase-sized task for the selected skill" }),
12
+ inputs: Type.Optional(Type.Array(Type.String(), { description: "Declared input paths relative to the Pipeline run" })),
13
+ });
14
+ function sandboxConfiguration() {
15
+ const sandbox = process.env.FOUNDRY_SANDBOX ?? "local";
16
+ if (sandbox !== "local" && sandbox !== "container") {
17
+ throw new Error("FOUNDRY_SANDBOX must be local or container");
18
+ }
19
+ const sandboxNetwork = process.env.FOUNDRY_SANDBOX_NETWORK ?? "bridge";
20
+ if (sandboxNetwork !== "bridge" && sandboxNetwork !== "none") {
21
+ throw new Error("FOUNDRY_SANDBOX_NETWORK must be bridge or none");
22
+ }
23
+ const credentialEnv = (process.env.FOUNDRY_SANDBOX_CREDENTIAL_ENV ?? "")
24
+ .split(",")
25
+ .map((value) => value.trim())
26
+ .filter(Boolean);
27
+ return {
28
+ sandbox,
29
+ sandboxImage: process.env.FOUNDRY_SANDBOX_IMAGE,
30
+ sandboxNetwork,
31
+ credentialEnv,
32
+ };
33
+ }
34
+ const foundrySubagent = defineTool({
35
+ name: "foundry_subagent",
36
+ label: "Foundry subagent",
37
+ description: "Run exactly one named published Foundry skill in a fresh Pi worker. The caller chooses the skill and order.",
38
+ promptSnippet: "Run one named published Foundry skill in an isolated child session.",
39
+ executionMode: "sequential",
40
+ parameters: FoundrySubagentParams,
41
+ async execute(_toolCallId, params, signal, onUpdate, ctx) {
42
+ const skillsRoot = process.env.FOUNDRY_SKILLS_DIR;
43
+ if (!skillsRoot) {
44
+ return {
45
+ content: [{ type: "text", text: "FOUNDRY_SKILLS_DIR is not configured." }],
46
+ details: null,
47
+ };
48
+ }
49
+ try {
50
+ const sandbox = sandboxConfiguration();
51
+ const skillDir = resolveInstalledSkill(skillsRoot, params.skill);
52
+ const inputPaths = (params.inputs ?? []).map((input) => resolveDeclaredInput(ctx.cwd, input));
53
+ const runsRoot = path.resolve(process.env.FOUNDRY_RUNS_DIR ?? path.join(tmpdir(), "foundry-pi-runs"));
54
+ mkdirSync(runsRoot, { recursive: true });
55
+ const runDir = path.join(runsRoot, `${params.skill}-${randomUUID()}`);
56
+ const model = ctx.model;
57
+ if (!model)
58
+ throw new Error("the parent Pi session has no selected model");
59
+ let eventCount = 0;
60
+ const record = await runPiSkill({
61
+ skillDir,
62
+ prompt: params.task,
63
+ inputPaths,
64
+ runDir,
65
+ provider: model.provider,
66
+ model: model.id,
67
+ thinking: ctx.thinkingLevel,
68
+ timeoutMs: Number(process.env.FOUNDRY_WORKER_TIMEOUT_MS ?? 600_000),
69
+ ...sandbox,
70
+ signal,
71
+ onEvent: (event) => {
72
+ eventCount += 1;
73
+ onUpdate?.({
74
+ content: [
75
+ {
76
+ type: "text",
77
+ text: JSON.stringify({
78
+ skill: params.skill,
79
+ status: "running",
80
+ event_count: eventCount,
81
+ last_event: event.type,
82
+ }),
83
+ },
84
+ ],
85
+ details: { skill: params.skill, event_count: eventCount, last_event: event.type },
86
+ });
87
+ },
88
+ });
89
+ return {
90
+ content: [
91
+ {
92
+ type: "text",
93
+ text: JSON.stringify({
94
+ skill: params.skill,
95
+ status: record.status,
96
+ artifacts: record.artifacts,
97
+ run_record: path.join(runDir, "run.json"),
98
+ summary: record.final_output,
99
+ }),
100
+ },
101
+ ],
102
+ details: record,
103
+ };
104
+ }
105
+ catch (error) {
106
+ return {
107
+ content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }],
108
+ details: null,
109
+ };
110
+ }
111
+ },
112
+ });
113
+ export default function foundryPiHarness(pi) {
114
+ pi.registerTool(foundrySubagent);
115
+ }
116
+ //# sourceMappingURL=extension.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extension.js","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export { expectedArtifactsFromSkill, runPiSkill, sha256Path, type ArtifactResult, type ExpectedArtifact, type PiRunnerDependencies, type PiSkillRunRecord, type PiThinkingLevel, type RunPiSkillOptions, type RunStatus, type SandboxMode, type StagedInput, } from "./runner.js";
2
+ export { buildDockerRunArgs, CONTAINER_FOUNDRY_VERSION_LABEL, CONTAINER_PI_VERSION_LABEL, CONTAINER_RPC_VERSION, CONTAINER_RPC_VERSION_LABEL, DEFAULT_CONTAINER_IMAGE, FOUNDRY_CLI_VERSION, inspectContainerImage, type ContainerImageResolution, type ContainerLaunchConfig, type ContainerMount, type ContainerNetworkPolicy, } from "./container.js";
3
+ export { resolveDeclaredInput, resolveInstalledSkill } from "./skill-resolution.js";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,0BAA0B,EAC1B,UAAU,EACV,UAAU,EACV,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,KAAK,SAAS,EACd,KAAK,WAAW,EAChB,KAAK,WAAW,GACjB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,kBAAkB,EAClB,+BAA+B,EAC/B,0BAA0B,EAC1B,qBAAqB,EACrB,2BAA2B,EAC3B,uBAAuB,EACvB,mBAAmB,EACnB,qBAAqB,EACrB,KAAK,wBAAwB,EAC7B,KAAK,qBAAqB,EAC1B,KAAK,cAAc,EACnB,KAAK,sBAAsB,GAC5B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export { expectedArtifactsFromSkill, runPiSkill, sha256Path, } from "./runner.js";
2
+ export { buildDockerRunArgs, CONTAINER_FOUNDRY_VERSION_LABEL, CONTAINER_PI_VERSION_LABEL, CONTAINER_RPC_VERSION, CONTAINER_RPC_VERSION_LABEL, DEFAULT_CONTAINER_IMAGE, FOUNDRY_CLI_VERSION, inspectContainerImage, } from "./container.js";
3
+ export { resolveDeclaredInput, resolveInstalledSkill } from "./skill-resolution.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,0BAA0B,EAC1B,UAAU,EACV,UAAU,GAUX,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,kBAAkB,EAClB,+BAA+B,EAC/B,0BAA0B,EAC1B,qBAAqB,EACrB,2BAA2B,EAC3B,uBAAuB,EACvB,mBAAmB,EACnB,qBAAqB,GAKtB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,132 @@
1
+ import { type JsonAgentSessionEvent, type RpcClientOptions, type RpcSessionState, type SessionStats } from "@earendil-works/pi-coding-agent";
2
+ import { type ContainerImageResolution, type ContainerMount, type ContainerNetworkPolicy } from "./container.js";
3
+ export type SandboxMode = "local" | "container";
4
+ export type RunStatus = "passed" | "failed" | "error" | "timed_out" | "cancelled";
5
+ export type PiThinkingLevel = "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max";
6
+ export interface ExpectedArtifact {
7
+ id: string;
8
+ path: string;
9
+ }
10
+ export interface StagedInput {
11
+ source: string;
12
+ staged_path: string;
13
+ sha256: string;
14
+ }
15
+ export interface ArtifactResult {
16
+ id: string;
17
+ path: string;
18
+ status: "passed" | "present" | "missing" | "failed" | "error";
19
+ sha256?: string;
20
+ validator?: {
21
+ bin: string;
22
+ args: string[];
23
+ exit_code: number | null;
24
+ stdout_path: string;
25
+ stderr_path: string;
26
+ error?: string;
27
+ };
28
+ }
29
+ export interface PiSkillRunRecord {
30
+ run_schema_version: 1;
31
+ run_id: string;
32
+ status: RunStatus;
33
+ failure_kind?: "infrastructure" | "skill";
34
+ error?: string;
35
+ started_at: string;
36
+ finished_at: string;
37
+ duration_ms: number;
38
+ engine: {
39
+ name: "pi";
40
+ version: string;
41
+ provider: string;
42
+ requested_model: string;
43
+ requested_thinking?: PiThinkingLevel;
44
+ resolved_model?: string;
45
+ };
46
+ invocation: {
47
+ skill: string;
48
+ skill_path: string;
49
+ skill_sha256: string;
50
+ provenance_sha256?: string;
51
+ prompt_sha256: string;
52
+ explicit_activation: string;
53
+ tools: string[];
54
+ timeout_ms: number;
55
+ ambient_discovery_disabled: true;
56
+ };
57
+ sandbox: {
58
+ mode: "local";
59
+ security_boundary: false;
60
+ network_policy: "host";
61
+ credential_policy: "ambient-environment";
62
+ workdir: string;
63
+ agent_config_dir: string;
64
+ } | {
65
+ mode: "container";
66
+ security_boundary: true;
67
+ network_policy: ContainerNetworkPolicy;
68
+ credential_policy: "allowlisted-environment" | "none";
69
+ credential_env: string[];
70
+ workdir: "/workspace";
71
+ agent_config_dir: "/pi-agent";
72
+ image: ContainerImageResolution;
73
+ mounts: ContainerMount[];
74
+ container_name: string;
75
+ };
76
+ inputs: StagedInput[];
77
+ artifacts: ArtifactResult[];
78
+ usage?: {
79
+ input_tokens: number;
80
+ output_tokens: number;
81
+ cache_read_tokens: number;
82
+ cache_write_tokens: number;
83
+ total_tokens: number;
84
+ cost: number;
85
+ turns: number;
86
+ tool_calls: number;
87
+ };
88
+ final_output?: string;
89
+ trace_path: string;
90
+ stderr_path: string;
91
+ }
92
+ export interface RunPiSkillOptions {
93
+ skillDir: string;
94
+ prompt: string;
95
+ inputPaths?: string[];
96
+ expectedArtifacts?: ExpectedArtifact[];
97
+ runDir: string;
98
+ provider: string;
99
+ model: string;
100
+ thinking?: PiThinkingLevel;
101
+ timeoutMs?: number;
102
+ tools?: string[];
103
+ sandbox?: SandboxMode;
104
+ sandboxImage?: string;
105
+ sandboxNetwork?: ContainerNetworkPolicy;
106
+ credentialEnv?: string[];
107
+ dockerBin?: string;
108
+ signal?: AbortSignal;
109
+ onEvent?: (event: JsonAgentSessionEvent) => void;
110
+ }
111
+ interface PiClient {
112
+ start(): Promise<void>;
113
+ stop(): Promise<void>;
114
+ abort(): Promise<void>;
115
+ onEvent(listener: (event: JsonAgentSessionEvent) => void): () => void;
116
+ promptAndWait(message: string, images?: never, timeout?: number): Promise<JsonAgentSessionEvent[]>;
117
+ getStderr(): string;
118
+ getState(): Promise<RpcSessionState>;
119
+ getSessionStats(): Promise<SessionStats>;
120
+ getLastAssistantText(): Promise<string | null>;
121
+ }
122
+ export interface PiRunnerDependencies {
123
+ createClient?: (options: RpcClientOptions) => PiClient;
124
+ inspectContainerImage?: (image: string, dockerBin: string) => ContainerImageResolution;
125
+ now?: () => Date;
126
+ id?: () => string;
127
+ }
128
+ export declare function sha256Path(filePath: string): string;
129
+ export declare function expectedArtifactsFromSkill(skillDir: string): ExpectedArtifact[];
130
+ export declare function runPiSkill(options: RunPiSkillOptions, dependencies?: PiRunnerDependencies): Promise<PiSkillRunRecord>;
131
+ export {};
132
+ //# sourceMappingURL=runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"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"}
package/dist/runner.js ADDED
@@ -0,0 +1,494 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import { createHash, randomUUID } from "node:crypto";
3
+ import { chmodSync, cpSync, existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, realpathSync, writeFileSync, } from "node:fs";
4
+ import path from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+ import { RpcClient, VERSION as PI_VERSION, } from "@earendil-works/pi-coding-agent";
7
+ import { DEFAULT_CONTAINER_IMAGE, inspectContainerImage, } from "./container.js";
8
+ const DEFAULT_TOOLS = ["read", "write", "edit", "bash", "grep", "find", "ls"];
9
+ const SUPPORTED_TOOLS = new Set([...DEFAULT_TOOLS, "powershell"]);
10
+ const SKILL_NAME = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
11
+ const ARTIFACT_ID = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
12
+ function sha256Text(value) {
13
+ return createHash("sha256").update(value).digest("hex");
14
+ }
15
+ function relativeRecordPath(runDir, filePath) {
16
+ return path.relative(runDir, filePath).split(path.sep).join("/");
17
+ }
18
+ function listTree(root, current = root) {
19
+ const entries = readdirSync(current, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
20
+ const files = [];
21
+ for (const entry of entries) {
22
+ const fullPath = path.join(current, entry.name);
23
+ if (entry.isDirectory())
24
+ files.push(...listTree(root, fullPath));
25
+ else
26
+ files.push(path.relative(root, fullPath).split(path.sep).join("/"));
27
+ }
28
+ return files;
29
+ }
30
+ export function sha256Path(filePath) {
31
+ const resolved = realpathSync(filePath);
32
+ const stat = lstatSync(resolved);
33
+ if (stat.isFile())
34
+ return createHash("sha256").update(readFileSync(resolved)).digest("hex");
35
+ if (!stat.isDirectory())
36
+ throw new Error(`cannot hash unsupported path: ${filePath}`);
37
+ const hash = createHash("sha256");
38
+ for (const relative of listTree(resolved)) {
39
+ hash.update(relative);
40
+ hash.update("\0");
41
+ hash.update(readFileSync(path.join(resolved, relative)));
42
+ hash.update("\0");
43
+ }
44
+ return hash.digest("hex");
45
+ }
46
+ function readSkillName(skillDir) {
47
+ const skillPath = path.join(skillDir, "SKILL.md");
48
+ if (!existsSync(skillPath))
49
+ throw new Error(`${skillPath}: missing SKILL.md`);
50
+ const source = readFileSync(skillPath, "utf8");
51
+ const frontmatter = source.match(/^---\s*\n([\s\S]*?)\n---\s*\n/);
52
+ const name = frontmatter?.[1]?.match(/^name:\s*["']?([^\s"']+)["']?\s*$/m)?.[1];
53
+ if (!name || !SKILL_NAME.test(name))
54
+ throw new Error(`${skillPath}: invalid or missing skill name`);
55
+ return name;
56
+ }
57
+ function resolveWorkspacePath(workspace, relativePath) {
58
+ if (!relativePath || path.isAbsolute(relativePath)) {
59
+ throw new Error(`expected artifact path must be relative: ${relativePath}`);
60
+ }
61
+ const resolved = path.resolve(workspace, relativePath);
62
+ const relation = path.relative(workspace, resolved);
63
+ if (relation.startsWith("..") || path.isAbsolute(relation)) {
64
+ throw new Error(`path escapes worker directory: ${relativePath}`);
65
+ }
66
+ return resolved;
67
+ }
68
+ function makeReadOnly(filePath) {
69
+ const stat = lstatSync(filePath);
70
+ if (stat.isDirectory()) {
71
+ for (const entry of readdirSync(filePath))
72
+ makeReadOnly(path.join(filePath, entry));
73
+ chmodSync(filePath, 0o555);
74
+ }
75
+ else {
76
+ chmodSync(filePath, 0o444);
77
+ }
78
+ }
79
+ function stageInputs(inputPaths, inputsDir, stagedPrefix) {
80
+ if (inputPaths.length === 0)
81
+ return [];
82
+ mkdirSync(inputsDir);
83
+ const names = new Set();
84
+ return inputPaths.map((inputPath) => {
85
+ const source = realpathSync(inputPath);
86
+ const name = path.basename(source);
87
+ if (names.has(name))
88
+ throw new Error(`declared inputs share basename '${name}'`);
89
+ names.add(name);
90
+ const destination = path.join(inputsDir, name);
91
+ cpSync(source, destination, { recursive: true, dereference: true, force: false });
92
+ makeReadOnly(destination);
93
+ return {
94
+ source,
95
+ staged_path: `${stagedPrefix}/${name}`,
96
+ sha256: sha256Path(source),
97
+ };
98
+ });
99
+ }
100
+ function loadVerifyEntries(skillDir) {
101
+ const verifyPath = path.join(skillDir, "_verify.json");
102
+ if (!existsSync(verifyPath))
103
+ return new Map();
104
+ const manifest = JSON.parse(readFileSync(verifyPath, "utf8"));
105
+ if (manifest.verify_schema_version !== 1 || !Array.isArray(manifest.entries)) {
106
+ throw new Error(`${verifyPath}: invalid verify manifest`);
107
+ }
108
+ return new Map(manifest.entries.map((entry) => [entry.artifact_id, entry]));
109
+ }
110
+ function substituteArtifactPath(args, artifactPath) {
111
+ return args.length
112
+ ? args.map((arg) => arg.replaceAll("{artifact_path}", artifactPath))
113
+ : [artifactPath];
114
+ }
115
+ function validateArtifacts(expected, workspace, runDir, skillDir) {
116
+ const verify = loadVerifyEntries(skillDir);
117
+ const validationDir = path.join(runDir, "validation");
118
+ return expected.map((artifact) => {
119
+ if (!ARTIFACT_ID.test(artifact.id))
120
+ throw new Error(`invalid artifact id: ${artifact.id}`);
121
+ const artifactPath = resolveWorkspacePath(workspace, artifact.path);
122
+ const recordPath = path.relative(workspace, artifactPath).split(path.sep).join("/");
123
+ if (!existsSync(artifactPath))
124
+ return { id: artifact.id, path: recordPath, status: "missing" };
125
+ const result = {
126
+ id: artifact.id,
127
+ path: recordPath,
128
+ status: "present",
129
+ sha256: sha256Path(artifactPath),
130
+ };
131
+ const entry = verify.get(artifact.id);
132
+ if (!entry)
133
+ return result;
134
+ mkdirSync(validationDir, { recursive: true });
135
+ const executed = spawnSync(entry.validator_bin, substituteArtifactPath(entry.args, artifactPath), { cwd: workspace, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
136
+ const stdoutPath = path.join(validationDir, `${artifact.id}.stdout`);
137
+ const stderrPath = path.join(validationDir, `${artifact.id}.stderr`);
138
+ writeFileSync(stdoutPath, executed.stdout ?? "");
139
+ writeFileSync(stderrPath, executed.stderr ?? "");
140
+ result.status = executed.error ? "error" : executed.status === 0 ? "passed" : "failed";
141
+ result.validator = {
142
+ bin: entry.validator_bin,
143
+ args: substituteArtifactPath(entry.args, recordPath),
144
+ exit_code: typeof executed.status === "number" ? executed.status : null,
145
+ stdout_path: relativeRecordPath(runDir, stdoutPath),
146
+ stderr_path: relativeRecordPath(runDir, stderrPath),
147
+ error: executed.error?.message,
148
+ };
149
+ return result;
150
+ });
151
+ }
152
+ function isAgentFailure(events) {
153
+ return events.some((event) => {
154
+ if (event.type !== "message_end" || event.message.role !== "assistant")
155
+ return false;
156
+ return event.message.stopReason === "error" || event.message.stopReason === "aborted";
157
+ });
158
+ }
159
+ function invocationPrompt(skill, prompt, inputs) {
160
+ const inputNote = inputs.length
161
+ ? `\n\nDeclared inputs staged in this worker:\n${inputs.map((input) => `- ${input.staged_path}`).join("\n")}`
162
+ : "";
163
+ return `/skill:${skill}\n\n${prompt}${inputNote}`;
164
+ }
165
+ function prepareRunDirectory(runDir, sandbox) {
166
+ if (existsSync(runDir))
167
+ throw new Error(`run directory already exists: ${runDir}`);
168
+ mkdirSync(path.dirname(runDir), { recursive: true });
169
+ mkdirSync(runDir, { mode: 0o700 });
170
+ const workspace = path.join(runDir, "workspace");
171
+ mkdirSync(workspace);
172
+ const inputsDir = sandbox === "local" ? path.join(workspace, "inputs") : path.join(runDir, "inputs");
173
+ if (sandbox === "container")
174
+ return { workspace, inputsDir };
175
+ const agentDir = path.join(runDir, "pi-agent");
176
+ mkdirSync(agentDir);
177
+ return { workspace, agentDir, inputsDir };
178
+ }
179
+ function writeRecord(runDir, record) {
180
+ writeFileSync(path.join(runDir, "run.json"), `${JSON.stringify(record, null, 2)}\n`);
181
+ }
182
+ const ENVIRONMENT_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
183
+ function resolveCredentialEnv(names) {
184
+ const unique = [...new Set(names)];
185
+ for (const name of unique) {
186
+ if (!ENVIRONMENT_NAME.test(name))
187
+ throw new Error(`invalid credential environment name: ${name}`);
188
+ if (process.env[name] === undefined) {
189
+ throw new Error(`credential environment variable is not set: ${name}`);
190
+ }
191
+ }
192
+ return unique.sort();
193
+ }
194
+ function containerMounts(skillDir, inputsDir, workspace, hasInputs) {
195
+ return [
196
+ {
197
+ type: "bind",
198
+ source: skillDir,
199
+ target: "/skill",
200
+ read_only: true,
201
+ purpose: "skill",
202
+ },
203
+ ...(hasInputs
204
+ ? [
205
+ {
206
+ type: "bind",
207
+ source: inputsDir,
208
+ target: "/inputs",
209
+ read_only: true,
210
+ purpose: "inputs",
211
+ },
212
+ ]
213
+ : []),
214
+ {
215
+ type: "bind",
216
+ source: workspace,
217
+ target: "/workspace",
218
+ read_only: false,
219
+ purpose: "output",
220
+ },
221
+ {
222
+ type: "tmpfs",
223
+ target: "/pi-agent",
224
+ read_only: false,
225
+ purpose: "agent-config",
226
+ },
227
+ {
228
+ type: "tmpfs",
229
+ target: "/tmp",
230
+ read_only: false,
231
+ purpose: "temporary-files",
232
+ },
233
+ ];
234
+ }
235
+ export function expectedArtifactsFromSkill(skillDir) {
236
+ const provenancePath = path.join(skillDir, "_provenance.json");
237
+ if (!existsSync(provenancePath))
238
+ return [];
239
+ const provenance = JSON.parse(readFileSync(provenancePath, "utf8"));
240
+ const produces = provenance.artifacts?.produces ?? [];
241
+ return produces.flatMap((artifact) => typeof artifact.id === "string" && typeof artifact.default_filename === "string"
242
+ ? [{ id: artifact.id, path: artifact.default_filename }]
243
+ : []);
244
+ }
245
+ export async function runPiSkill(options, dependencies = {}) {
246
+ const now = dependencies.now ?? (() => new Date());
247
+ const runId = (dependencies.id ?? randomUUID)();
248
+ const started = now();
249
+ const runDir = path.resolve(options.runDir);
250
+ const skillDir = realpathSync(options.skillDir);
251
+ const sandbox = options.sandbox ?? "local";
252
+ const dockerBin = options.dockerBin ?? "docker";
253
+ const sandboxNetwork = options.sandboxNetwork ?? "bridge";
254
+ const timeoutMs = options.timeoutMs ?? 10 * 60 * 1000;
255
+ const tools = [...(options.tools ?? DEFAULT_TOOLS)];
256
+ if (sandbox !== "local" && sandbox !== "container") {
257
+ throw new Error(`unsupported sandbox mode: ${String(sandbox)}`);
258
+ }
259
+ if (sandboxNetwork !== "bridge" && sandboxNetwork !== "none") {
260
+ throw new Error(`unsupported container network policy: ${String(sandboxNetwork)}`);
261
+ }
262
+ if (sandbox === "local" && (options.sandboxImage || options.credentialEnv?.length)) {
263
+ throw new Error("container image and credential options require sandbox=container");
264
+ }
265
+ if (!options.provider.trim() || !options.model.trim()) {
266
+ throw new Error("provider and model are required");
267
+ }
268
+ if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
269
+ throw new Error("timeoutMs must be a positive finite number");
270
+ }
271
+ if (tools.length === 0 || tools.some((tool) => !SUPPORTED_TOOLS.has(tool))) {
272
+ throw new Error(`tools must be a non-empty subset of: ${[...SUPPORTED_TOOLS].join(", ")}`);
273
+ }
274
+ const credentialEnv = sandbox === "container" ? resolveCredentialEnv(options.credentialEnv ?? []) : [];
275
+ const image = sandbox === "container"
276
+ ? (dependencies.inspectContainerImage ?? inspectContainerImage)(options.sandboxImage ?? DEFAULT_CONTAINER_IMAGE, dockerBin)
277
+ : undefined;
278
+ const skill = readSkillName(skillDir);
279
+ const expectedArtifacts = options.expectedArtifacts ?? expectedArtifactsFromSkill(skillDir);
280
+ loadVerifyEntries(skillDir);
281
+ const { workspace, agentDir, inputsDir } = prepareRunDirectory(runDir, sandbox);
282
+ const workerSkillDir = path.join(runDir, "skill");
283
+ cpSync(skillDir, workerSkillDir, {
284
+ recursive: true,
285
+ dereference: true,
286
+ force: false,
287
+ });
288
+ makeReadOnly(workerSkillDir);
289
+ for (const artifact of expectedArtifacts) {
290
+ if (!ARTIFACT_ID.test(artifact.id))
291
+ throw new Error(`invalid artifact id: ${artifact.id}`);
292
+ resolveWorkspacePath(workspace, artifact.path);
293
+ }
294
+ const inputPaths = options.inputPaths ?? [];
295
+ const inputs = stageInputs(inputPaths, inputsDir, sandbox === "container" ? "/inputs" : "inputs");
296
+ const prompt = invocationPrompt(skill, options.prompt, inputs);
297
+ const tracePath = path.join(runDir, "trace.jsonl");
298
+ const stderrPath = path.join(runDir, "stderr.log");
299
+ writeFileSync(tracePath, "");
300
+ writeFileSync(stderrPath, "");
301
+ const provenancePath = path.join(skillDir, "_provenance.json");
302
+ const mounts = sandbox === "container"
303
+ ? containerMounts(workerSkillDir, inputsDir, workspace, inputPaths.length > 0)
304
+ : undefined;
305
+ const containerName = `foundry-pi-${runId.toLowerCase()}`;
306
+ const baseRecord = {
307
+ run_schema_version: 1,
308
+ run_id: runId,
309
+ started_at: started.toISOString(),
310
+ engine: {
311
+ name: "pi",
312
+ version: PI_VERSION,
313
+ provider: options.provider,
314
+ requested_model: options.model,
315
+ requested_thinking: options.thinking,
316
+ },
317
+ invocation: {
318
+ skill,
319
+ skill_path: skillDir,
320
+ skill_sha256: sha256Path(skillDir),
321
+ provenance_sha256: existsSync(provenancePath) ? sha256Path(provenancePath) : undefined,
322
+ prompt_sha256: sha256Text(prompt),
323
+ explicit_activation: `/skill:${skill}`,
324
+ tools,
325
+ timeout_ms: timeoutMs,
326
+ ambient_discovery_disabled: true,
327
+ },
328
+ sandbox: sandbox === "container"
329
+ ? {
330
+ mode: "container",
331
+ security_boundary: true,
332
+ network_policy: sandboxNetwork,
333
+ credential_policy: credentialEnv.length
334
+ ? "allowlisted-environment"
335
+ : "none",
336
+ credential_env: credentialEnv,
337
+ workdir: "/workspace",
338
+ agent_config_dir: "/pi-agent",
339
+ image: image,
340
+ mounts: mounts,
341
+ container_name: containerName,
342
+ }
343
+ : {
344
+ mode: "local",
345
+ security_boundary: false,
346
+ network_policy: "host",
347
+ credential_policy: "ambient-environment",
348
+ workdir: relativeRecordPath(runDir, workspace),
349
+ agent_config_dir: relativeRecordPath(runDir, agentDir),
350
+ },
351
+ inputs,
352
+ trace_path: relativeRecordPath(runDir, tracePath),
353
+ stderr_path: relativeRecordPath(runDir, stderrPath),
354
+ };
355
+ const cliPath = sandbox === "container"
356
+ ? fileURLToPath(new URL("./container-rpc-entry.js", import.meta.url))
357
+ : fileURLToPath(import.meta.resolve("@earendil-works/pi-coding-agent/rpc-entry"));
358
+ const launchConfig = sandbox === "container"
359
+ ? {
360
+ docker_bin: dockerBin,
361
+ container_name: containerName,
362
+ image_id: image.resolved_id,
363
+ network: sandboxNetwork,
364
+ credential_env: credentialEnv,
365
+ user: typeof process.getuid === "function" && typeof process.getgid === "function"
366
+ ? `${process.getuid()}:${process.getgid()}`
367
+ : undefined,
368
+ mounts: mounts,
369
+ }
370
+ : undefined;
371
+ const clientOptions = {
372
+ cliPath,
373
+ cwd: workspace,
374
+ env: sandbox === "container"
375
+ ? { FOUNDRY_CONTAINER_LAUNCH_CONFIG: JSON.stringify(launchConfig) }
376
+ : { PI_CODING_AGENT_DIR: agentDir },
377
+ provider: options.provider,
378
+ model: options.model,
379
+ args: [
380
+ "--no-session",
381
+ "--no-context-files",
382
+ "--no-extensions",
383
+ "--no-prompt-templates",
384
+ "--no-skills",
385
+ "--skill",
386
+ sandbox === "container" ? "/skill" : workerSkillDir,
387
+ "--tools",
388
+ tools.join(","),
389
+ ...(options.thinking ? ["--thinking", options.thinking] : []),
390
+ ],
391
+ };
392
+ const client = (dependencies.createClient ?? ((value) => new RpcClient(value)))(clientOptions);
393
+ const events = [];
394
+ let state;
395
+ let stats;
396
+ let finalOutput;
397
+ let status;
398
+ let failureKind;
399
+ let error;
400
+ let timedOut = false;
401
+ let cancelled = false;
402
+ const unsubscribe = client.onEvent((event) => {
403
+ events.push(event);
404
+ writeFileSync(tracePath, `${JSON.stringify(event)}\n`, { flag: "a" });
405
+ options.onEvent?.(event);
406
+ });
407
+ const abort = () => {
408
+ cancelled = !timedOut;
409
+ void client.abort().catch(() => undefined);
410
+ };
411
+ options.signal?.addEventListener("abort", abort, { once: true });
412
+ try {
413
+ await client.start();
414
+ let timer;
415
+ const timeout = new Promise((_, reject) => {
416
+ timer = setTimeout(() => {
417
+ timedOut = true;
418
+ void client.abort().catch(() => undefined);
419
+ reject(new Error(`Pi worker exceeded wall timeout of ${timeoutMs}ms`));
420
+ }, timeoutMs);
421
+ });
422
+ try {
423
+ await Promise.race([client.promptAndWait(prompt, undefined, timeoutMs), timeout]);
424
+ if (options.signal?.aborted)
425
+ throw new Error("Pi worker was cancelled");
426
+ }
427
+ finally {
428
+ if (timer)
429
+ clearTimeout(timer);
430
+ }
431
+ state = await client.getState();
432
+ stats = await client.getSessionStats();
433
+ finalOutput = (await client.getLastAssistantText()) ?? undefined;
434
+ const artifacts = validateArtifacts(expectedArtifacts, workspace, runDir, skillDir);
435
+ const artifactFailure = artifacts.some((artifact) => ["missing", "failed", "error"].includes(artifact.status));
436
+ const agentFailure = isAgentFailure(events);
437
+ status = artifactFailure || agentFailure ? "failed" : "passed";
438
+ if (status === "failed")
439
+ failureKind = "skill";
440
+ const finished = now();
441
+ const record = {
442
+ ...baseRecord,
443
+ status,
444
+ failure_kind: failureKind,
445
+ finished_at: finished.toISOString(),
446
+ duration_ms: finished.getTime() - started.getTime(),
447
+ engine: {
448
+ ...baseRecord.engine,
449
+ resolved_model: state?.model ? `${state.model.provider}/${state.model.id}` : undefined,
450
+ },
451
+ artifacts,
452
+ usage: stats
453
+ ? {
454
+ input_tokens: stats.tokens.input,
455
+ output_tokens: stats.tokens.output,
456
+ cache_read_tokens: stats.tokens.cacheRead,
457
+ cache_write_tokens: stats.tokens.cacheWrite,
458
+ total_tokens: stats.tokens.total,
459
+ cost: stats.cost,
460
+ turns: stats.assistantMessages,
461
+ tool_calls: stats.toolCalls,
462
+ }
463
+ : undefined,
464
+ final_output: finalOutput,
465
+ };
466
+ writeRecord(runDir, record);
467
+ return record;
468
+ }
469
+ catch (caught) {
470
+ error = caught instanceof Error ? caught.message : String(caught);
471
+ status = timedOut ? "timed_out" : cancelled || options.signal?.aborted ? "cancelled" : "error";
472
+ failureKind = status === "error" ? "infrastructure" : undefined;
473
+ const artifacts = validateArtifacts(expectedArtifacts, workspace, runDir, skillDir);
474
+ const finished = now();
475
+ const record = {
476
+ ...baseRecord,
477
+ status,
478
+ failure_kind: failureKind,
479
+ error,
480
+ finished_at: finished.toISOString(),
481
+ duration_ms: finished.getTime() - started.getTime(),
482
+ artifacts,
483
+ };
484
+ writeRecord(runDir, record);
485
+ return record;
486
+ }
487
+ finally {
488
+ options.signal?.removeEventListener("abort", abort);
489
+ unsubscribe();
490
+ await client.stop().catch(() => undefined);
491
+ writeFileSync(stderrPath, client.getStderr());
492
+ }
493
+ }
494
+ //# sourceMappingURL=runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare function resolveInstalledSkill(skillsRoot: string, skill: string): string;
2
+ export declare function resolveDeclaredInput(cwd: string, input: string): string;
3
+ //# sourceMappingURL=skill-resolution.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-resolution.d.ts","sourceRoot":"","sources":["../src/skill-resolution.ts"],"names":[],"mappings":"AAKA,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAQ/E;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAUvE"}
@@ -0,0 +1,25 @@
1
+ import { realpathSync } from "node:fs";
2
+ import path from "node:path";
3
+ const SKILL_NAME = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
4
+ export function resolveInstalledSkill(skillsRoot, skill) {
5
+ if (!SKILL_NAME.test(skill))
6
+ throw new Error(`invalid Foundry skill name: ${skill}`);
7
+ const root = realpathSync(skillsRoot);
8
+ const resolved = realpathSync(path.join(root, skill));
9
+ if (path.dirname(resolved) !== root) {
10
+ throw new Error(`Foundry skill resolves outside installed skill root: ${skill}`);
11
+ }
12
+ return resolved;
13
+ }
14
+ export function resolveDeclaredInput(cwd, input) {
15
+ if (path.isAbsolute(input))
16
+ throw new Error(`declared input must be relative to the run: ${input}`);
17
+ const root = realpathSync(cwd);
18
+ const resolved = realpathSync(path.resolve(root, input));
19
+ const relation = path.relative(root, resolved);
20
+ if (relation.startsWith("..") || path.isAbsolute(relation)) {
21
+ throw new Error(`declared input escapes the Pipeline run directory: ${input}`);
22
+ }
23
+ return resolved;
24
+ }
25
+ //# sourceMappingURL=skill-resolution.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-resolution.js","sourceRoot":"","sources":["../src/skill-resolution.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,MAAM,UAAU,GAAG,4BAA4B,CAAC;AAEhD,MAAM,UAAU,qBAAqB,CAAC,UAAkB,EAAE,KAAa;IACrE,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,KAAK,EAAE,CAAC,CAAC;IACrF,MAAM,IAAI,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC;IACtC,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;IACtD,IAAI,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,IAAI,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CAAC,wDAAwD,KAAK,EAAE,CAAC,CAAC;IACnF,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,GAAW,EAAE,KAAa;IAC7D,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,+CAA+C,KAAK,EAAE,CAAC,CAAC;IAC1E,MAAM,IAAI,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;IAC/B,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;IACzD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAC/C,IAAI,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC3D,MAAM,IAAI,KAAK,CAAC,sDAAsD,KAAK,EAAE,CAAC,CAAC;IACjF,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
package/package.json CHANGED
@@ -1,9 +1,21 @@
1
1
  {
2
2
  "name": "@galaxy-foundry/gxwf-pi-harness",
3
- "version": "0.0.0",
4
- "description": "Reserved bootstrap package for the Galaxy Workflow Foundry Pi evaluation harness.",
3
+ "version": "0.1.0",
4
+ "description": "Pi-backed isolated worker runner and extension for testing Galaxy Workflow Foundry skills.",
5
5
  "type": "module",
6
+ "exports": {
7
+ ".": {
8
+ "types": "./dist/index.d.ts",
9
+ "import": "./dist/index.js"
10
+ },
11
+ "./extension": {
12
+ "types": "./dist/extension.d.ts",
13
+ "import": "./dist/extension.js"
14
+ }
15
+ },
6
16
  "files": [
17
+ "dist",
18
+ "Dockerfile",
7
19
  "README.md",
8
20
  "LICENSE"
9
21
  ],
@@ -15,5 +27,37 @@
15
27
  "publishConfig": {
16
28
  "access": "public"
17
29
  },
18
- "license": "MIT"
19
- }
30
+ "keywords": [
31
+ "pi-package",
32
+ "galaxy",
33
+ "foundry",
34
+ "pi",
35
+ "agent",
36
+ "evaluation"
37
+ ],
38
+ "license": "MIT",
39
+ "dependencies": {
40
+ "@earendil-works/pi-ai": "0.84.4",
41
+ "@earendil-works/pi-coding-agent": "0.84.4"
42
+ },
43
+ "devDependencies": {
44
+ "@types/node": "^22.10.0",
45
+ "typescript": "^5.7.0",
46
+ "vitest": "^4.1.10"
47
+ },
48
+ "engines": {
49
+ "node": ">=22.19"
50
+ },
51
+ "pi": {
52
+ "extensions": [
53
+ "./dist/extension.js"
54
+ ]
55
+ },
56
+ "scripts": {
57
+ "build": "tsc",
58
+ "typecheck": "tsc --noEmit",
59
+ "test": "vitest run",
60
+ "test:container": "pnpm build && FOUNDRY_TEST_CONTAINER=1 vitest run test/container-docker.test.ts",
61
+ "test:watch": "vitest"
62
+ }
63
+ }