@themoltnet/pi-extension 0.37.2 → 0.38.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/dist/index.js +88 -17
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
2
|
import { execFileSync } from "node:child_process";
|
|
3
3
|
import { createReadStream, createWriteStream, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync } from "node:fs";
|
|
4
|
-
import path, { join } from "node:path";
|
|
4
|
+
import path, { isAbsolute, join, relative } from "node:path";
|
|
5
5
|
import { DEFAULT_MAX_BYTES, createBashTool, createEditTool, createFindTool, createGrepTool, createLsTool, createReadTool, createWriteTool, defineTool, formatSize, truncateHead, truncateLine } from "@earendil-works/pi-coding-agent";
|
|
6
|
-
import { readFile, realpath, stat } from "node:fs/promises";
|
|
6
|
+
import { mkdir, readFile, realpath, stat } from "node:fs/promises";
|
|
7
7
|
import { pipeline } from "node:stream/promises";
|
|
8
8
|
import { Type } from "@earendil-works/pi-ai";
|
|
9
|
-
import { homedir } from "node:os";
|
|
10
9
|
import crypto, { createHash } from "crypto";
|
|
11
10
|
import { createHash as createHash$1 } from "node:crypto";
|
|
11
|
+
import { homedir } from "node:os";
|
|
12
12
|
import { Readable } from "node:stream";
|
|
13
13
|
import { MemoryProvider, RealFSProvider, ShadowProvider, VM, VmCheckpoint, createHttpHooks, createShadowPathPredicate, ensureImageSelector, isWriteFlag, loadGuestAssets } from "@earendil-works/gondolin";
|
|
14
14
|
import { parseEnv } from "node:util";
|
|
@@ -41,6 +41,20 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
41
41
|
var __toCommonJS = (mod) => __hasOwnProp.call(mod, "module.exports") ? mod["module.exports"] : __copyProps(__defProp$1({}, "__esModule", { value: true }), mod);
|
|
42
42
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
43
43
|
//#endregion
|
|
44
|
+
//#region ../pi-runtime/src/path-containment.ts
|
|
45
|
+
/**
|
|
46
|
+
* Check containment for already-resolved lexical or real paths.
|
|
47
|
+
*
|
|
48
|
+
* Callers that accept untrusted paths must resolve/realpath at their I/O
|
|
49
|
+
* boundary first; keeping the platform-specific relative-path rule here avoids
|
|
50
|
+
* subtly different `..` and absolute-path handling across runtime cleanup,
|
|
51
|
+
* session sync, and artifact staging.
|
|
52
|
+
*/
|
|
53
|
+
function isResolvedPathInsideRoot(path, root) {
|
|
54
|
+
const rel = relative(root, path);
|
|
55
|
+
return rel === "" || !rel.startsWith("..") && !isAbsolute(rel);
|
|
56
|
+
}
|
|
57
|
+
//#endregion
|
|
44
58
|
//#region ../pi-runtime/src/moltnet/render-phase6.ts
|
|
45
59
|
function slugToTitle(value) {
|
|
46
60
|
return value.split(/[:/_-]+/).filter(Boolean).map((part) => part[0]?.toUpperCase() + part.slice(1)).join(" ");
|
|
@@ -232,11 +246,32 @@ async function openWorkspaceArtifactInput(config, cwd, filePath) {
|
|
|
232
246
|
}
|
|
233
247
|
async function resolveWorkspaceOutputPath(cwd, filePath) {
|
|
234
248
|
const resolved = path.isAbsolute(filePath) ? path.resolve(filePath) : path.resolve(cwd, filePath);
|
|
235
|
-
const
|
|
236
|
-
const
|
|
237
|
-
if (
|
|
249
|
+
const workspaceRoot = path.resolve(cwd);
|
|
250
|
+
const lexicalRel = path.relative(workspaceRoot, resolved);
|
|
251
|
+
if (lexicalRel === "" || lexicalRel.startsWith("..") || path.isAbsolute(lexicalRel)) throw new Error(`task artifact output path escapes workspace: ${filePath}`);
|
|
252
|
+
const realCwd = await realpath(cwd);
|
|
253
|
+
const parent = path.dirname(resolved);
|
|
254
|
+
assertPathInsideWorkspace(realCwd, await findExistingAncestor(parent), filePath);
|
|
255
|
+
await mkdir(parent, { recursive: true });
|
|
256
|
+
assertPathInsideWorkspace(realCwd, await realpath(parent), filePath);
|
|
238
257
|
return resolved;
|
|
239
258
|
}
|
|
259
|
+
async function findExistingAncestor(candidate) {
|
|
260
|
+
let current = candidate;
|
|
261
|
+
for (;;) {
|
|
262
|
+
try {
|
|
263
|
+
return await realpath(current);
|
|
264
|
+
} catch (err) {
|
|
265
|
+
if (!err || typeof err !== "object" || !("code" in err) || err.code !== "ENOENT") throw err;
|
|
266
|
+
}
|
|
267
|
+
const parent = path.dirname(current);
|
|
268
|
+
if (parent === current) throw new Error(`task artifact output has no existing ancestor: ${candidate}`);
|
|
269
|
+
current = parent;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
function assertPathInsideWorkspace(realCwd, realPath, displayPath) {
|
|
273
|
+
if (!isResolvedPathInsideRoot(realPath, realCwd)) throw new Error(`task artifact output path escapes workspace: ${displayPath}`);
|
|
274
|
+
}
|
|
240
275
|
/**
|
|
241
276
|
* Expand the `taskFilter` shorthand on the diary list/search tools into
|
|
242
277
|
* the matching `task:*` provenance tags emitted by `moltnet_create_entry`
|
|
@@ -9948,6 +9983,11 @@ var RuntimeModel = _Object_({
|
|
|
9948
9983
|
var RUNTIME_PROFILE_CONTEXT_CATALOGUE = {
|
|
9949
9984
|
version: 1,
|
|
9950
9985
|
fragments: {
|
|
9986
|
+
"artifact-planner-v1": {
|
|
9987
|
+
binding: "prompt_prefix",
|
|
9988
|
+
content: "# Bounded artifact planner\n\n- The typed task facts, embedded bounded manifest, exact bound artifact references, registered tools, and runtime capability section are the complete contract. Do not search diaries, inspect a mounted repository, enumerate unrelated tasks or artifacts, use shell commands, modify files, commit, branch, push, or contact GitHub.\n- Read only the exact artifact CIDs named by the task, and only when the embedded manifest does not provide enough evidence. Never paginate or discover artifacts speculatively.\n- Perform semantic classification and planning from supplied content and producer/consumer evidence. Do not substitute filename, directory, language, ecosystem, or repository-specific exclusion rules for evidence.\n- Return exactly the requested versioned structured plan through the registered submit-output tool. Do not emit a second prose or JSON representation.",
|
|
9989
|
+
slug: "artifact-planner-v1"
|
|
9990
|
+
},
|
|
9951
9991
|
"accountable-delivery-v1": {
|
|
9952
9992
|
binding: "prompt_prefix",
|
|
9953
9993
|
content: "# Accountable delivery\n\n- Pair every commit made during this task with a signed diary entry created by the `moltnet_create_entry` custom tool. Put the returned id in a `MoltNet-Diary: <id>` commit trailer.\n- Keep commit signing enabled; do not bypass the agent git configuration.\n- Push a branch and open or update a pull request only when the task asks for it. For GitHub mutations, use the credential-bound `GH_TOKEN` command form required by the runtime kernel.\n- Keep changes, commits, and any requested pull request coherent enough to review independently.",
|
|
@@ -9980,6 +10020,10 @@ var RUNTIME_PROFILE_CONTEXT_CATALOGUE = {
|
|
|
9980
10020
|
}
|
|
9981
10021
|
},
|
|
9982
10022
|
recipes: {
|
|
10023
|
+
"artifact-planner@v1": {
|
|
10024
|
+
description: "Minimal artifact-only context for bounded semantic classification and planning.",
|
|
10025
|
+
fragments: ["artifact-planner-v1"]
|
|
10026
|
+
},
|
|
9983
10027
|
"run-eval-direct@v1": {
|
|
9984
10028
|
description: "Minimal direct context for a short, isolated evaluation run.",
|
|
9985
10029
|
fragments: ["run-eval-direct-v1"]
|
|
@@ -11467,7 +11511,7 @@ var VerificationResult = _Object_({
|
|
|
11467
11511
|
var VerificationRecord = _Object_({
|
|
11468
11512
|
inputCid: String$1({ minLength: 1 }),
|
|
11469
11513
|
results: _Array_(VerificationResult),
|
|
11470
|
-
passed: Boolean$1()
|
|
11514
|
+
passed: Boolean$1({ description: "True iff every verification result has status \"pass\" or \"skip\"; false when any result has status \"fail\"." })
|
|
11471
11515
|
}, {
|
|
11472
11516
|
$id: "VerificationRecord",
|
|
11473
11517
|
additionalProperties: false
|
|
@@ -15161,6 +15205,16 @@ function checkVerificationInputCid(value, runtime) {
|
|
|
15161
15205
|
}];
|
|
15162
15206
|
return [];
|
|
15163
15207
|
}
|
|
15208
|
+
function checkVerificationPassedConsistency(value) {
|
|
15209
|
+
const verification = value !== null && typeof value === "object" ? value.verification : void 0;
|
|
15210
|
+
if (verification === void 0 || !Array.isArray(verification.results) || typeof verification.passed !== "boolean") return [];
|
|
15211
|
+
const expectedPassed = verification.results.every((result) => result.status !== "fail");
|
|
15212
|
+
if (verification.passed !== expectedPassed) return [{
|
|
15213
|
+
field: "output/verification/passed",
|
|
15214
|
+
message: "must be true iff no verification result has status \"fail\""
|
|
15215
|
+
}];
|
|
15216
|
+
return [];
|
|
15217
|
+
}
|
|
15164
15218
|
function validateTaskResult(taskType, value, input, runtime, submission = false) {
|
|
15165
15219
|
const entry = getTaskTypeEntry(taskType);
|
|
15166
15220
|
if (!entry) return [{
|
|
@@ -15176,7 +15230,7 @@ function validateTaskResult(taskType, value, input, runtime, submission = false)
|
|
|
15176
15230
|
message: validationError
|
|
15177
15231
|
}];
|
|
15178
15232
|
}
|
|
15179
|
-
return checkVerificationInputCid(value, runtime);
|
|
15233
|
+
return [...checkVerificationInputCid(value, runtime), ...checkVerificationPassedConsistency(value)];
|
|
15180
15234
|
}
|
|
15181
15235
|
function validateTaskOutput(taskType, output, input, runtime) {
|
|
15182
15236
|
return validateTaskResult(taskType, output, input, runtime);
|
|
@@ -17572,7 +17626,7 @@ var require_transport = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
17572
17626
|
var { createRequire: createRequire$1 } = __require("module");
|
|
17573
17627
|
var { existsSync: existsSync$1 } = __require("node:fs");
|
|
17574
17628
|
var getCallers = require_caller();
|
|
17575
|
-
var { join: join$1, isAbsolute, sep } = __require("node:path");
|
|
17629
|
+
var { join: join$1, isAbsolute: isAbsolute$1, sep } = __require("node:path");
|
|
17576
17630
|
var { fileURLToPath } = __require("node:url");
|
|
17577
17631
|
var sleep = require_atomic_sleep();
|
|
17578
17632
|
var onExit = require_on_exit_leak_free();
|
|
@@ -17633,7 +17687,7 @@ var require_transport = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
17633
17687
|
} catch {
|
|
17634
17688
|
return false;
|
|
17635
17689
|
}
|
|
17636
|
-
return isAbsolute(path) && !existsSync$1(path);
|
|
17690
|
+
return isAbsolute$1(path) && !existsSync$1(path);
|
|
17637
17691
|
}
|
|
17638
17692
|
function stripQuotes(value) {
|
|
17639
17693
|
const first = value[0];
|
|
@@ -17736,7 +17790,7 @@ var require_transport = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
17736
17790
|
return buildStream(fixTarget(target), options, worker, sync, name);
|
|
17737
17791
|
function fixTarget(origin) {
|
|
17738
17792
|
origin = bundlerOverrides[origin] || origin;
|
|
17739
|
-
if (isAbsolute(origin) || origin.indexOf("file://") === 0) return origin;
|
|
17793
|
+
if (isAbsolute$1(origin) || origin.indexOf("file://") === 0) return origin;
|
|
17740
17794
|
if (origin === "pino/file") return join$1(__dirname, "..", "file.js");
|
|
17741
17795
|
let fixTarget;
|
|
17742
17796
|
for (const filePath of callers) try {
|
|
@@ -28545,6 +28599,12 @@ var WRAPPERS = new Map([
|
|
|
28545
28599
|
["builtin", spec(0)]
|
|
28546
28600
|
]);
|
|
28547
28601
|
//#endregion
|
|
28602
|
+
//#region ../pi-runtime/src/config.ts
|
|
28603
|
+
/** Resolve Pi's host-side auth/config directory from process configuration. */
|
|
28604
|
+
function resolvePiCodingAgentDir() {
|
|
28605
|
+
return process.env["PI_CODING_AGENT_DIR"] ?? path.join(homedir(), ".pi", "agent");
|
|
28606
|
+
}
|
|
28607
|
+
//#endregion
|
|
28548
28608
|
//#region ../pi-runtime/src/snapshot.ts
|
|
28549
28609
|
/**
|
|
28550
28610
|
* Snapshot builder with auto-build and caching.
|
|
@@ -28834,6 +28894,17 @@ async function delay(ms, signal, label) {
|
|
|
28834
28894
|
* investigation and the alternatives we rejected.
|
|
28835
28895
|
*/
|
|
28836
28896
|
var GUEST_TASK_CONTEXT_MOUNT = "/moltnet-task-context";
|
|
28897
|
+
function resolveVfsShadowConfig(config) {
|
|
28898
|
+
const patterns = config?.vfs?.shadow ?? [];
|
|
28899
|
+
if (patterns.length === 0) return {
|
|
28900
|
+
mode: "none",
|
|
28901
|
+
patterns: []
|
|
28902
|
+
};
|
|
28903
|
+
return {
|
|
28904
|
+
mode: config?.vfs?.shadowMode ?? "tmpfs",
|
|
28905
|
+
patterns
|
|
28906
|
+
};
|
|
28907
|
+
}
|
|
28837
28908
|
function shouldRunResumeCommand(entry, ctx) {
|
|
28838
28909
|
if (typeof entry === "string") return true;
|
|
28839
28910
|
const workspaceModes = entry.when?.workspaceMode;
|
|
@@ -28906,7 +28977,7 @@ function resolveVmAgentDir(config) {
|
|
|
28906
28977
|
function loadCredentials(agentDir) {
|
|
28907
28978
|
const moltnetJson = readFileSync(path.join(agentDir, "moltnet.json"), "utf8");
|
|
28908
28979
|
const agentEnvRaw = readFileSync(path.join(agentDir, "env"), "utf8");
|
|
28909
|
-
const piAgentDir =
|
|
28980
|
+
const piAgentDir = resolvePiCodingAgentDir();
|
|
28910
28981
|
const piAuthPath = path.join(piAgentDir, "auth.json");
|
|
28911
28982
|
const piAuthJson = existsSync(piAuthPath) ? readFileSync(piAuthPath, "utf8") : null;
|
|
28912
28983
|
const gitconfigPath = path.join(agentDir, "gitconfig");
|
|
@@ -29061,7 +29132,7 @@ async function resumeVm(config) {
|
|
|
29061
29132
|
else vmAgentEnv[k] = v;
|
|
29062
29133
|
}
|
|
29063
29134
|
vmAgentEnv.MOLTNET_CREDENTIALS_PATH = `${vmAgentDir}/moltnet.json`;
|
|
29064
|
-
const vfsConfig = config.sandboxConfig
|
|
29135
|
+
const vfsConfig = resolveVfsShadowConfig(config.sandboxConfig);
|
|
29065
29136
|
let workspaceProvider = new RealFSProvider(config.mountPath);
|
|
29066
29137
|
workspaceProvider = new ShadowProvider(workspaceProvider, {
|
|
29067
29138
|
shouldShadow: ({ path: shadowPath }) => shouldShadowNodeModulesPath(shadowPath),
|
|
@@ -29069,11 +29140,11 @@ async function resumeVm(config) {
|
|
|
29069
29140
|
tmpfs: new AutoParentMemoryProvider(),
|
|
29070
29141
|
writeMode: "tmpfs"
|
|
29071
29142
|
});
|
|
29072
|
-
if (vfsConfig
|
|
29073
|
-
const predicate = createShadowPathPredicate(vfsConfig.
|
|
29143
|
+
if (vfsConfig.mode !== "none") {
|
|
29144
|
+
const predicate = createShadowPathPredicate(vfsConfig.patterns);
|
|
29074
29145
|
workspaceProvider = new ShadowProvider(workspaceProvider, {
|
|
29075
29146
|
shouldShadow: predicate,
|
|
29076
|
-
writeMode: vfsConfig.
|
|
29147
|
+
writeMode: vfsConfig.mode
|
|
29077
29148
|
});
|
|
29078
29149
|
}
|
|
29079
29150
|
const forwardedEnv = {};
|
|
@@ -29533,7 +29604,7 @@ async function executeGondolinGrep(vm, localCwd, guestWorkspace, params, signal)
|
|
|
29533
29604
|
const onAbort = () => ac.abort();
|
|
29534
29605
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
29535
29606
|
try {
|
|
29536
|
-
const proc = vm.exec(["
|
|
29607
|
+
const proc = vm.exec(["rg", ...args], {
|
|
29537
29608
|
signal: ac.signal,
|
|
29538
29609
|
stdout: "pipe",
|
|
29539
29610
|
stderr: "pipe"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@themoltnet/pi-extension",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.38.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "MoltNet pi extension — sandboxed tool execution in Gondolin VMs with MoltNet identity and persistent memory",
|
|
6
6
|
"keywords": [
|
|
@@ -34,11 +34,11 @@
|
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@earendil-works/gondolin": "^0.9.1",
|
|
37
|
-
"@themoltnet/pi-runtime": "0.
|
|
37
|
+
"@themoltnet/pi-runtime": "0.5.0",
|
|
38
38
|
"@themoltnet/sdk": "0.128.0"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
|
-
"@earendil-works/pi-ai": "0.
|
|
41
|
+
"@earendil-works/pi-ai": "0.79.4",
|
|
42
42
|
"@earendil-works/pi-coding-agent": "0.79.4"
|
|
43
43
|
},
|
|
44
44
|
"peerDependenciesMeta": {
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
}
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
|
-
"@earendil-works/pi-ai": "0.
|
|
53
|
+
"@earendil-works/pi-ai": "0.79.4",
|
|
54
54
|
"@earendil-works/pi-coding-agent": "0.79.4",
|
|
55
55
|
"@types/node": "^22.19.0",
|
|
56
56
|
"typescript": "~5.9.2",
|