@themoltnet/agent-daemon 0.34.1 → 0.35.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/cli.js +43 -15
- package/package.json +6 -6
package/dist/cli.js
CHANGED
|
@@ -5,10 +5,10 @@ import * as Format from "typebox/format";
|
|
|
5
5
|
import { Type } from "typebox";
|
|
6
6
|
import crypto from "crypto";
|
|
7
7
|
import { Value } from "typebox/value";
|
|
8
|
-
import { dirname,
|
|
8
|
+
import { dirname, join, resolve } from "node:path";
|
|
9
9
|
import { parseArgs, promisify } from "node:util";
|
|
10
10
|
import { AgentRuntime, ApiTaskReporter, ApiTaskSource, PollingApiTaskSource } from "@themoltnet/agent-runtime";
|
|
11
|
-
import { createPiRetryTriage, findMainWorktree, normalizeRetryTriageResult, redactRetryTriageSecrets } from "@themoltnet/pi-runtime";
|
|
11
|
+
import { createPiRetryTriage, findMainWorktree, isResolvedPathInsideRoot, normalizeRetryTriageResult, redactRetryTriageSecrets } from "@themoltnet/pi-runtime";
|
|
12
12
|
import { execFile, execFileSync } from "node:child_process";
|
|
13
13
|
import { createReadStream, createWriteStream, existsSync, mkdirSync, readdirSync, realpathSync, rmSync } from "node:fs";
|
|
14
14
|
import { AuthenticationError, MoltNetError, connect } from "@themoltnet/sdk";
|
|
@@ -251,6 +251,11 @@ Type.Object({
|
|
|
251
251
|
var RUNTIME_PROFILE_CONTEXT_CATALOGUE = {
|
|
252
252
|
version: 1,
|
|
253
253
|
fragments: {
|
|
254
|
+
"artifact-planner-v1": {
|
|
255
|
+
binding: "prompt_prefix",
|
|
256
|
+
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.",
|
|
257
|
+
slug: "artifact-planner-v1"
|
|
258
|
+
},
|
|
254
259
|
"accountable-delivery-v1": {
|
|
255
260
|
binding: "prompt_prefix",
|
|
256
261
|
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.",
|
|
@@ -283,6 +288,10 @@ var RUNTIME_PROFILE_CONTEXT_CATALOGUE = {
|
|
|
283
288
|
}
|
|
284
289
|
},
|
|
285
290
|
recipes: {
|
|
291
|
+
"artifact-planner@v1": {
|
|
292
|
+
description: "Minimal artifact-only context for bounded semantic classification and planning.",
|
|
293
|
+
fragments: ["artifact-planner-v1"]
|
|
294
|
+
},
|
|
286
295
|
"run-eval-direct@v1": {
|
|
287
296
|
description: "Minimal direct context for a short, isolated evaluation run.",
|
|
288
297
|
fragments: ["run-eval-direct-v1"]
|
|
@@ -889,7 +898,11 @@ var ProblemDetailsSchema = Type.Object({
|
|
|
889
898
|
}),
|
|
890
899
|
code: ProblemCodeSchema,
|
|
891
900
|
detail: Type.Optional(Type.String()),
|
|
892
|
-
instance: Type.Optional(Type.String())
|
|
901
|
+
instance: Type.Optional(Type.String()),
|
|
902
|
+
retryAfter: Type.Optional(Type.Integer({
|
|
903
|
+
minimum: 0,
|
|
904
|
+
description: "Non-negative delay in seconds before retrying, matching the Retry-After response header when present."
|
|
905
|
+
}))
|
|
893
906
|
}, {
|
|
894
907
|
$id: "ProblemDetails",
|
|
895
908
|
additionalProperties: true
|
|
@@ -1717,7 +1730,7 @@ var VerificationResult = Type.Object({
|
|
|
1717
1730
|
var VerificationRecord = Type.Object({
|
|
1718
1731
|
inputCid: Type.String({ minLength: 1 }),
|
|
1719
1732
|
results: Type.Array(VerificationResult),
|
|
1720
|
-
passed: Type.Boolean()
|
|
1733
|
+
passed: Type.Boolean({ description: "True iff every verification result has status \"pass\" or \"skip\"; false when any result has status \"fail\"." })
|
|
1721
1734
|
}, {
|
|
1722
1735
|
$id: "VerificationRecord",
|
|
1723
1736
|
additionalProperties: false
|
|
@@ -3692,6 +3705,10 @@ Type.Object({
|
|
|
3692
3705
|
taskId: Uuid,
|
|
3693
3706
|
attemptN: Type.Number({ minimum: 1 }),
|
|
3694
3707
|
claimedByAgentId: Uuid,
|
|
3708
|
+
leaseId: Type.Union([Uuid, Type.Null()]),
|
|
3709
|
+
runtimeProfileId: Type.Union([Uuid, Type.Null()]),
|
|
3710
|
+
runtimeProfileRevision: Type.Union([Type.Integer({ minimum: 1 }), Type.Null()]),
|
|
3711
|
+
policySnapshotHash: Type.Union([Type.String({ pattern: "^sha256:[0-9a-f]{64}$" }), Type.Null()]),
|
|
3695
3712
|
runtimeId: Type.Union([Uuid, Type.Null()]),
|
|
3696
3713
|
claimedAt: IsoTimestamp,
|
|
3697
3714
|
startedAt: Type.Union([IsoTimestamp, Type.Null()]),
|
|
@@ -4227,7 +4244,7 @@ function buildDaemonTaskExecutionPlan(task, stateDirs, identity, warmSessionTtlS
|
|
|
4227
4244
|
const slotKey = warmSessionTtlSec > 0 && descriptor.sessionKey ? buildRuntimeSlotKey(descriptor.sessionKey, identity.runtimeInstanceId) : null;
|
|
4228
4245
|
const workspaceScope = slotKey !== null ? descriptor.policy.workspaceScope : "attempt";
|
|
4229
4246
|
const slotId = slotKey ? buildDaemonSlotId(identity, slotKey) : null;
|
|
4230
|
-
const sessionDir = slotId ? `${stateDirs.piSessionsDir}/${
|
|
4247
|
+
const sessionDir = slotId ? `${stateDirs.piSessionsDir}/${boundedKeyDirComponent(slotId)}` : null;
|
|
4231
4248
|
const worktreeBranch = resolveTaskWorktreeBranch(task, workspaceMode);
|
|
4232
4249
|
const workspaceId = workspaceMode !== "shared_mount" ? resolveTaskWorkspaceId(task, {
|
|
4233
4250
|
sessionKey: slotId,
|
|
@@ -4315,8 +4332,27 @@ function isRuntimeProfileWorkspaceMode(value) {
|
|
|
4315
4332
|
function toDaemonWorkspaceMode(mode) {
|
|
4316
4333
|
return mode === "none" ? "scratch_mount" : mode;
|
|
4317
4334
|
}
|
|
4335
|
+
/**
|
|
4336
|
+
* URL-encode a slot/session key for use as a single filesystem directory
|
|
4337
|
+
* component, bounded to stay under the 255-byte per-component filename limit.
|
|
4338
|
+
* A long key (e.g. `run_eval`'s custom key, which embeds the variant label +
|
|
4339
|
+
* agent name + worker id) otherwise crashes `mkdir` with `ENAMETOOLONG`.
|
|
4340
|
+
*
|
|
4341
|
+
* Additive by design: keys short enough today keep their exact encoded form (so
|
|
4342
|
+
* existing warm dirs are byte-identical), and only over-long keys get a readable
|
|
4343
|
+
* prefix + a collision-resistant sha256 suffix. The component is never decoded
|
|
4344
|
+
* back to the key anywhere, so hashing the tail is safe. Used for BOTH the
|
|
4345
|
+
* pi-sessions dir and the session workspace dir so the two names derive
|
|
4346
|
+
* consistently from the same slot id.
|
|
4347
|
+
*/
|
|
4348
|
+
function boundedKeyDirComponent(key) {
|
|
4349
|
+
const encoded = encodeURIComponent(key);
|
|
4350
|
+
if (encoded.length <= 200) return encoded;
|
|
4351
|
+
const hash = createHash("sha256").update(key).digest("hex").slice(0, 16);
|
|
4352
|
+
return `${encoded.slice(0, 180)}-${hash}`;
|
|
4353
|
+
}
|
|
4318
4354
|
function resolveTaskWorkspaceId(task, executionPlan) {
|
|
4319
|
-
if (executionPlan.workspaceScope === "session" && executionPlan.sessionKey !== null) return `session-${
|
|
4355
|
+
if (executionPlan.workspaceScope === "session" && executionPlan.sessionKey !== null) return `session-${boundedKeyDirComponent(executionPlan.sessionKey)}`;
|
|
4320
4356
|
return executionPlan.attemptN ? `daemon-task-${task.id}-attempt-${executionPlan.attemptN}` : `task-${task.id}`;
|
|
4321
4357
|
}
|
|
4322
4358
|
//#endregion
|
|
@@ -5395,15 +5431,11 @@ async function listRegisteredWorktrees(mainWorktree) {
|
|
|
5395
5431
|
}
|
|
5396
5432
|
function isRealPathInsideRoot(path, root) {
|
|
5397
5433
|
try {
|
|
5398
|
-
return isResolvedPathInsideRoot
|
|
5434
|
+
return isResolvedPathInsideRoot(realpathSync(path), realpathSync(root));
|
|
5399
5435
|
} catch {
|
|
5400
5436
|
return false;
|
|
5401
5437
|
}
|
|
5402
5438
|
}
|
|
5403
|
-
function isResolvedPathInsideRoot$1(path, root) {
|
|
5404
|
-
const rel = relative(root, path);
|
|
5405
|
-
return rel === "" || !rel.startsWith("..") && !isAbsolute(rel);
|
|
5406
|
-
}
|
|
5407
5439
|
function canonicalPath(path) {
|
|
5408
5440
|
try {
|
|
5409
5441
|
return realpathSync(path);
|
|
@@ -6774,10 +6806,6 @@ async function isPathInsideRoot(path, root) {
|
|
|
6774
6806
|
}
|
|
6775
6807
|
return isResolvedPathInsideRoot(realResolvedPath, realResolvedRoot);
|
|
6776
6808
|
}
|
|
6777
|
-
function isResolvedPathInsideRoot(path, root) {
|
|
6778
|
-
const rel = relative(root, path);
|
|
6779
|
-
return rel === "" || !rel.startsWith("..") && !isAbsolute(rel);
|
|
6780
|
-
}
|
|
6781
6809
|
async function computeCompressedSessionFingerprint(path) {
|
|
6782
6810
|
const hash = createHash("sha256");
|
|
6783
6811
|
let bytes = 0;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@themoltnet/agent-daemon",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.35.0",
|
|
4
4
|
"license": "AGPL-3.0-only",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Universal MoltNet agent daemon host with a built-in Pi/Gondolin runtime and support for trusted operator-owned runtime modules. CLI: moltnet-agent.",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"@earendil-works/gondolin": "^0.9.1",
|
|
47
|
-
"@earendil-works/pi-ai": "0.
|
|
47
|
+
"@earendil-works/pi-ai": "0.79.4",
|
|
48
48
|
"@earendil-works/pi-coding-agent": "0.79.4",
|
|
49
49
|
"@opentelemetry/api": "^1.9.0",
|
|
50
50
|
"@opentelemetry/exporter-trace-otlp-proto": "^0.212.0",
|
|
@@ -62,8 +62,8 @@
|
|
|
62
62
|
"pino": "^10.3.1",
|
|
63
63
|
"pino-pretty": "^13.1.3",
|
|
64
64
|
"typebox": "^1.2.8",
|
|
65
|
-
"@themoltnet/agent-runtime": "0.
|
|
66
|
-
"@themoltnet/pi-runtime": "0.
|
|
65
|
+
"@themoltnet/agent-runtime": "0.39.1",
|
|
66
|
+
"@themoltnet/pi-runtime": "0.5.0",
|
|
67
67
|
"@themoltnet/sdk": "0.128.0"
|
|
68
68
|
},
|
|
69
69
|
"devDependencies": {
|
|
@@ -73,9 +73,9 @@
|
|
|
73
73
|
"vite-plugin-dts": "^4.5.4",
|
|
74
74
|
"vitest": "^3.0.0",
|
|
75
75
|
"@moltnet/bootstrap": "0.1.0",
|
|
76
|
-
"@moltnet/tasks": "0.1.0",
|
|
77
76
|
"@moltnet/crypto-service": "0.1.0",
|
|
78
|
-
"@moltnet/observability": "0.1.0"
|
|
77
|
+
"@moltnet/observability": "0.1.0",
|
|
78
|
+
"@moltnet/tasks": "0.1.0"
|
|
79
79
|
},
|
|
80
80
|
"nx": {
|
|
81
81
|
"projectType": "application",
|