@themoltnet/pi-extension 0.24.0 → 0.25.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.d.ts +6 -0
- package/dist/index.js +85 -31
- package/package.json +6 -6
package/dist/index.d.ts
CHANGED
|
@@ -505,6 +505,12 @@ export declare interface PiTaskExecutionPlan {
|
|
|
505
505
|
* worktree is required.
|
|
506
506
|
*/
|
|
507
507
|
worktreeBranch: string | null;
|
|
508
|
+
/**
|
|
509
|
+
* Base ref a NEW `worktreeBranch` is cut from. Used by `fork` continuations
|
|
510
|
+
* to branch from the parent's tip instead of the default (main/HEAD). Ignored
|
|
511
|
+
* when `worktreeBranch` already exists.
|
|
512
|
+
*/
|
|
513
|
+
worktreeBaseRef?: string | null;
|
|
508
514
|
/**
|
|
509
515
|
* Lifetime of the task workspace from the daemon's point of view.
|
|
510
516
|
* `attempt` = disposable; `session` = keep stable for the reuse key.
|
package/dist/index.js
CHANGED
|
@@ -8824,8 +8824,7 @@ async function resumeVm(config) {
|
|
|
8824
8824
|
signal: config.signal
|
|
8825
8825
|
});
|
|
8826
8826
|
if (creds.gitconfig) {
|
|
8827
|
-
const
|
|
8828
|
-
const vmGitconfig = creds.gitconfig.replace(/signingKey\s*=\s*.+/g, `signingKey = ${vmSigningKey}`);
|
|
8827
|
+
const vmGitconfig = rewriteGitconfigPaths(creds.gitconfig, vmSshDir, vmAgentDir);
|
|
8829
8828
|
await vm.fs.writeFile(`${vmAgentDir}/gitconfig`, vmGitconfig, {
|
|
8830
8829
|
mode: 420,
|
|
8831
8830
|
signal: config.signal
|
|
@@ -8848,17 +8847,6 @@ async function resumeVm(config) {
|
|
|
8848
8847
|
signal: config.signal
|
|
8849
8848
|
});
|
|
8850
8849
|
await vm.exec("chown -R agent:agent /home/agent/.pi /home/agent/.moltnet", { signal: config.signal });
|
|
8851
|
-
const gitCredHelperPath = `${vmSshDir}/git-credential-moltnet`;
|
|
8852
|
-
const credHelperScript = `#!/bin/sh
|
|
8853
|
-
echo "username=x-access-token"
|
|
8854
|
-
echo "password=$(moltnet github token --credentials ${vmSshDir}/moltnet.json)"
|
|
8855
|
-
`;
|
|
8856
|
-
await vm.fs.writeFile(gitCredHelperPath, credHelperScript, {
|
|
8857
|
-
mode: 493,
|
|
8858
|
-
signal: config.signal
|
|
8859
|
-
});
|
|
8860
|
-
await vmRun(vm, "git credential helper", `git config --global credential.helper ${gitCredHelperPath} && \
|
|
8861
|
-
git config --global url."https://github.com/".insteadOf "git@github.com:"`, config.signal);
|
|
8862
8850
|
return {
|
|
8863
8851
|
vm,
|
|
8864
8852
|
credentials: creds,
|
|
@@ -8877,6 +8865,30 @@ echo "password=$(moltnet github token --credentials ${vmSshDir}/moltnet.json)"
|
|
|
8877
8865
|
}
|
|
8878
8866
|
}
|
|
8879
8867
|
/**
|
|
8868
|
+
* Rewrite host-absolute paths inside an agent gitconfig to VM-local
|
|
8869
|
+
* equivalents before injecting it into the guest.
|
|
8870
|
+
*
|
|
8871
|
+
* Two rewrites:
|
|
8872
|
+
* - `signingKey = <host path>` → `<vmSshDir>/id_ed25519`
|
|
8873
|
+
* - `... credential-helper --credentials <host moltnet.json>`
|
|
8874
|
+
* → `<vmAgentDir>/moltnet.json`
|
|
8875
|
+
*
|
|
8876
|
+
* The credential-helper line is generated host-side by `moltnet github setup`
|
|
8877
|
+
* with a host-absolute `--credentials` path; inside the guest that path is
|
|
8878
|
+
* invalid, so it must point at the VM-side moltnet.json. The `insteadOf`
|
|
8879
|
+
* rewrite rule and every other line are workspace-independent and pass through
|
|
8880
|
+
* unchanged. A gitconfig without a credential helper is rewritten only for
|
|
8881
|
+
* `signingKey`.
|
|
8882
|
+
*
|
|
8883
|
+
* This is the single source of truth for git push auth in the guest: the
|
|
8884
|
+
* injected gitconfig carries the tokenless mint-on-demand helper, so the VM
|
|
8885
|
+
* no longer hand-rolls a credential-helper script or runs an imperative
|
|
8886
|
+
* `git config --global ... insteadOf` against the guest $HOME.
|
|
8887
|
+
*/
|
|
8888
|
+
function rewriteGitconfigPaths(gitconfig, vmSshDir, vmAgentDir) {
|
|
8889
|
+
return gitconfig.replace(/signingKey\s*=\s*.+/g, `signingKey = ${vmSshDir}/id_ed25519`).replace(/(moltnet github credential-helper --credentials )\S+/g, `$1${vmAgentDir}/moltnet.json`);
|
|
8890
|
+
}
|
|
8891
|
+
/**
|
|
8880
8892
|
* Rewrite host-absolute paths inside moltnet.json to VM-local equivalents.
|
|
8881
8893
|
*
|
|
8882
8894
|
* Fields rewritten:
|
|
@@ -13470,6 +13482,54 @@ function validateRubricWeights(rubric) {
|
|
|
13470
13482
|
return null;
|
|
13471
13483
|
}
|
|
13472
13484
|
//#endregion
|
|
13485
|
+
//#region ../tasks/src/runtime-models.ts
|
|
13486
|
+
/**
|
|
13487
|
+
* Runtime model catalog: a list of supported provider/model couples that
|
|
13488
|
+
* MoltNet daemons can target. Backed by the `runtime_models` table.
|
|
13489
|
+
*
|
|
13490
|
+
* Scope is intrinsic to the row:
|
|
13491
|
+
* - `teamId == null` => global entry (MoltNet-seeded, read-only to most callers)
|
|
13492
|
+
* - `teamId != null` => team-owned custom entry
|
|
13493
|
+
*
|
|
13494
|
+
* The REST API exposes a single shape regardless of scope; the team header
|
|
13495
|
+
* gates which rows are returned.
|
|
13496
|
+
*/
|
|
13497
|
+
var RuntimeModelProvider = String$1({
|
|
13498
|
+
minLength: 1,
|
|
13499
|
+
maxLength: 100,
|
|
13500
|
+
pattern: "^[a-zA-Z0-9][a-zA-Z0-9._-]{0,99}$"
|
|
13501
|
+
});
|
|
13502
|
+
var RuntimeModelName = String$1({
|
|
13503
|
+
minLength: 1,
|
|
13504
|
+
maxLength: 200,
|
|
13505
|
+
pattern: "^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,199}$"
|
|
13506
|
+
});
|
|
13507
|
+
var RuntimeModelCapabilities = Record(String$1({
|
|
13508
|
+
minLength: 1,
|
|
13509
|
+
maxLength: 64
|
|
13510
|
+
}), Union([
|
|
13511
|
+
Boolean$1(),
|
|
13512
|
+
Number$1(),
|
|
13513
|
+
String$1({ maxLength: 256 })
|
|
13514
|
+
]));
|
|
13515
|
+
_Object_({
|
|
13516
|
+
id: String$1({ format: "uuid" }),
|
|
13517
|
+
teamId: Union([String$1({ format: "uuid" }), Null()]),
|
|
13518
|
+
provider: RuntimeModelProvider,
|
|
13519
|
+
model: RuntimeModelName,
|
|
13520
|
+
displayName: Union([String$1({ maxLength: 200 }), Null()]),
|
|
13521
|
+
description: Union([String$1({ maxLength: 4096 }), Null()]),
|
|
13522
|
+
capabilities: RuntimeModelCapabilities,
|
|
13523
|
+
isActive: Boolean$1(),
|
|
13524
|
+
createdByAgentId: Union([String$1({ format: "uuid" }), Null()]),
|
|
13525
|
+
createdByHumanId: Union([String$1({ format: "uuid" }), Null()]),
|
|
13526
|
+
createdAt: String$1({ format: "date-time" }),
|
|
13527
|
+
updatedAt: String$1({ format: "date-time" })
|
|
13528
|
+
}, {
|
|
13529
|
+
$id: "RuntimeModel",
|
|
13530
|
+
additionalProperties: false
|
|
13531
|
+
});
|
|
13532
|
+
//#endregion
|
|
13473
13533
|
//#region ../tasks/src/runtime-profiles.ts
|
|
13474
13534
|
var RuntimeProfileName = String$1({
|
|
13475
13535
|
minLength: 1,
|
|
@@ -14010,20 +14070,17 @@ var FreeformOutput = _Object_({
|
|
|
14010
14070
|
* 3. `freeform.sourceAttemptNotCompleted` — named attempt is missing
|
|
14011
14071
|
* or not in `completed` state; warm continuation only makes sense
|
|
14012
14072
|
* once the parent has produced a terminal output.
|
|
14013
|
-
* 4. `freeform.
|
|
14014
|
-
* surface for copy-on-write continuation tracked in #1293; v1
|
|
14015
|
-
* rejects it server-side so daemons never have to branch.
|
|
14016
|
-
* 5. `freeform.executionWorkspaceNotInheritable` — caller set
|
|
14073
|
+
* 4. `freeform.executionWorkspaceNotInheritable` — caller set
|
|
14017
14074
|
* `execution.workspace` together with `continueFrom`. Workspace
|
|
14018
14075
|
* mode for a continuation is inherited from the parent slot
|
|
14019
14076
|
* (`maybeAttachWarmSlotContext` forces `dedicated_worktree` +
|
|
14020
14077
|
* the parent's worktreeBranch), so any caller-supplied override
|
|
14021
14078
|
* is silently dropped at the daemon plan stage. Reject explicitly
|
|
14022
14079
|
* so misconfiguration surfaces at create time.
|
|
14023
|
-
*
|
|
14080
|
+
* 5. `freeform.sourceNotResumeEligible` — `daemonState` is null or
|
|
14024
14081
|
* `slotResumableUntil` is null. Older completions (pre-#1287) and
|
|
14025
14082
|
* daemons that opt out fall here.
|
|
14026
|
-
*
|
|
14083
|
+
* 6. `freeform.sourceResumeExpired` — `slotResumableUntil` is in the
|
|
14027
14084
|
* past; the warm slot's TTL has elapsed and no daemon is
|
|
14028
14085
|
* guaranteed to still hold it.
|
|
14029
14086
|
*
|
|
@@ -14044,11 +14101,6 @@ async function validateFreeformInputAsync(input, ctx) {
|
|
|
14044
14101
|
message: `Source task type '${source.taskType}' is not continuable; only freeform → freeform is supported in v1`,
|
|
14045
14102
|
code: "freeform.sourceTaskTypeNotSupported"
|
|
14046
14103
|
}];
|
|
14047
|
-
if (cf.mode === "fork") return [{
|
|
14048
|
-
field: "input/continueFrom/mode",
|
|
14049
|
-
message: "fork mode not yet implemented; see https://github.com/getlarge/themoltnet/issues/1293",
|
|
14050
|
-
code: "freeform.forkModeNotImplemented"
|
|
14051
|
-
}];
|
|
14052
14104
|
if (input.execution?.workspace) return [{
|
|
14053
14105
|
field: "input/execution/workspace",
|
|
14054
14106
|
message: "execution.workspace is inherited from the parent slot when continueFrom is set; omit it",
|
|
@@ -23203,10 +23255,11 @@ function prepareTaskWorkspace(task, requestedMountPath, executionPlan) {
|
|
|
23203
23255
|
const relMount = relative(mainRepo, requestedMountPath);
|
|
23204
23256
|
const cwdPath = relMount === "" || relMount.startsWith("..") ? worktreeDir : join(worktreeDir, relMount);
|
|
23205
23257
|
const keepWorkspace = executionPlan?.workspaceScope === "session" && executionPlan.sessionKey !== null;
|
|
23206
|
-
|
|
23258
|
+
const baseRefOverride = executionPlan?.worktreeBaseRef ?? null;
|
|
23259
|
+
if (keepWorkspace) ensureReusableTaskWorktree(mainRepo, worktreeDir, branch, baseRefOverride);
|
|
23207
23260
|
else {
|
|
23208
23261
|
removeExistingTaskWorktree(mainRepo, worktreeDir);
|
|
23209
|
-
addTaskWorktree(mainRepo, worktreeDir, branch);
|
|
23262
|
+
addTaskWorktree(mainRepo, worktreeDir, branch, baseRefOverride);
|
|
23210
23263
|
}
|
|
23211
23264
|
return {
|
|
23212
23265
|
mountPath: mainRepo,
|
|
@@ -23231,14 +23284,15 @@ function resolveTaskWorktreePath(mainRepo, workspaceId) {
|
|
|
23231
23284
|
function resolveTaskScratchPath(mainRepo, workspaceId) {
|
|
23232
23285
|
return join(mainRepo, ".moltnet", "d", "task-workspaces", workspaceId);
|
|
23233
23286
|
}
|
|
23234
|
-
function ensureReusableTaskWorktree(mainRepo, worktreeDir, branch) {
|
|
23287
|
+
function ensureReusableTaskWorktree(mainRepo, worktreeDir, branch, baseRefOverride = null) {
|
|
23235
23288
|
if (isRegisteredWorktree(mainRepo, worktreeDir)) return;
|
|
23236
23289
|
if (existsSync(worktreeDir)) throw new Error(`Expected reusable worktree ${worktreeDir} to be git-managed, but it exists outside git worktree metadata.`);
|
|
23237
|
-
addTaskWorktree(mainRepo, worktreeDir, branch);
|
|
23290
|
+
addTaskWorktree(mainRepo, worktreeDir, branch, baseRefOverride);
|
|
23238
23291
|
}
|
|
23239
|
-
function addTaskWorktree(mainRepo, worktreeDir, branch) {
|
|
23240
|
-
const
|
|
23241
|
-
|
|
23292
|
+
function addTaskWorktree(mainRepo, worktreeDir, branch, baseRefOverride = null) {
|
|
23293
|
+
const branchExists = gitRefExists(mainRepo, `refs/heads/${branch}`);
|
|
23294
|
+
const baseRef = baseRefOverride ?? resolveWorktreeBaseRef(mainRepo);
|
|
23295
|
+
execFileSync("git", branchExists ? [
|
|
23242
23296
|
"-C",
|
|
23243
23297
|
mainRepo,
|
|
23244
23298
|
"worktree",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@themoltnet/pi-extension",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.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": [
|
|
@@ -36,8 +36,8 @@
|
|
|
36
36
|
"@earendil-works/gondolin": "^0.9.1",
|
|
37
37
|
"@opentelemetry/api": "^1.9.0",
|
|
38
38
|
"typebox": "^1.2.8",
|
|
39
|
-
"@themoltnet/
|
|
40
|
-
"@themoltnet/
|
|
39
|
+
"@themoltnet/sdk": "0.108.0",
|
|
40
|
+
"@themoltnet/agent-runtime": "0.25.0"
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
43
43
|
"@earendil-works/pi-coding-agent": ">=0.74.0",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
55
|
"@earendil-works/pi-ai": "^0.74.0",
|
|
56
|
-
"@earendil-works/pi-coding-agent": "^0.
|
|
56
|
+
"@earendil-works/pi-coding-agent": "^0.79.4",
|
|
57
57
|
"@opentelemetry/sdk-metrics": "^2.5.1",
|
|
58
58
|
"@opentelemetry/sdk-trace-base": "^2.5.1",
|
|
59
59
|
"@types/node": "^22.19.0",
|
|
@@ -61,8 +61,8 @@
|
|
|
61
61
|
"vite": "^8.0.0",
|
|
62
62
|
"vite-plugin-dts": "^4.5.4",
|
|
63
63
|
"vitest": "^3.0.0",
|
|
64
|
-
"@moltnet/
|
|
65
|
-
"@moltnet/
|
|
64
|
+
"@moltnet/tasks": "0.1.0",
|
|
65
|
+
"@moltnet/crypto-service": "0.1.0"
|
|
66
66
|
},
|
|
67
67
|
"engines": {
|
|
68
68
|
"node": ">=22"
|