@themoltnet/agent-daemon 0.34.2 → 0.36.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 +106 -41
- package/package.json +8 -8
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, modify a checkout, 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. Use the registered task-artifact tools for artifact access; never use shell or CLI wrappers to fetch artifacts, paginate, or discover them speculatively.\n- If the effective runtime exposes a local calculator or shell, use it only inside scratch for coverage accounting, budget arithmetic, and JSON validation. The runtime capability section and policy are authoritative; do not assume a static executable list.\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- Write and upload exactly the requested versioned plan artifact, then reference its returned metadata 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.",
|
|
@@ -278,11 +283,15 @@ var RUNTIME_PROFILE_CONTEXT_CATALOGUE = {
|
|
|
278
283
|
},
|
|
279
284
|
"verification-and-artifacts-v1": {
|
|
280
285
|
binding: "prompt_prefix",
|
|
281
|
-
content: "# Verification and artifacts\n\n- Run relevant verification before submitting. When task facts include `successCriteria`, assess them honestly in the generated verification contract; a fail or skip with evidence is better than a fabricated pass.\n- The registered submit-output tool owns the exact agent submission schema and validation recovery. Use that schema; do not invent a JSON shape in prose.\n- Upload
|
|
286
|
+
content: "# Verification and artifacts\n\n- Run relevant verification before submitting. When task facts include `successCriteria`, assess them honestly in the generated verification contract; a fail or skip with evidence is better than a fabricated pass.\n- The registered submit-output tool owns the exact agent submission schema and validation recovery. Use that schema; do not invent a JSON shape in prose.\n- Upload only task-relevant artifacts, and inspect each before uploading. Never upload secrets, credentials, API keys, auth tokens or headers, .env files, or personal or customer data; redact sensitive values, and prefer minimal, sanitized excerpts over whole logs, bundles, or datasets. Include artifact metadata only where the typed submit contract permits it.\n- If the task depends on prior artifacts, list and download the exact referenced artifact before judging or continuing that work.",
|
|
282
287
|
slug: "verification-and-artifacts-v1"
|
|
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"]
|
|
@@ -1721,7 +1730,7 @@ var VerificationResult = Type.Object({
|
|
|
1721
1730
|
var VerificationRecord = Type.Object({
|
|
1722
1731
|
inputCid: Type.String({ minLength: 1 }),
|
|
1723
1732
|
results: Type.Array(VerificationResult),
|
|
1724
|
-
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\"." })
|
|
1725
1734
|
}, {
|
|
1726
1735
|
$id: "VerificationRecord",
|
|
1727
1736
|
additionalProperties: false
|
|
@@ -2529,11 +2538,14 @@ var CuratePackOutput = Type.Object({
|
|
|
2529
2538
|
//#endregion
|
|
2530
2539
|
//#region ../../libs/tasks/src/task-types/freeform.ts
|
|
2531
2540
|
var FREEFORM_TYPE = "freeform";
|
|
2532
|
-
var FreeformExecutionOptions = Type.Object({
|
|
2533
|
-
Type.
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2541
|
+
var FreeformExecutionOptions = Type.Object({
|
|
2542
|
+
workspace: Type.Optional(Type.Union([
|
|
2543
|
+
Type.Literal("none"),
|
|
2544
|
+
Type.Literal("shared_mount"),
|
|
2545
|
+
Type.Literal("dedicated_worktree")
|
|
2546
|
+
])),
|
|
2547
|
+
revision: Type.Optional(Type.String({ pattern: "^[0-9a-fA-F]{40}$" }))
|
|
2548
|
+
}, {
|
|
2537
2549
|
$id: "FreeformExecutionOptions",
|
|
2538
2550
|
additionalProperties: false
|
|
2539
2551
|
});
|
|
@@ -2619,6 +2631,12 @@ var FreeformOutput = Type.Object({
|
|
|
2619
2631
|
* are sequential preconditions, later ones presume earlier ones hold.
|
|
2620
2632
|
*/
|
|
2621
2633
|
async function validateFreeformInputAsync(input, ctx) {
|
|
2634
|
+
const execution = input.execution;
|
|
2635
|
+
if (execution?.revision && execution.workspace === "none") return [{
|
|
2636
|
+
field: "input/execution/revision",
|
|
2637
|
+
message: "execution.revision requires a repository workspace; use shared_mount or dedicated_worktree",
|
|
2638
|
+
code: "freeform.executionRevisionRequiresRepository"
|
|
2639
|
+
}];
|
|
2622
2640
|
const cf = input.continueFrom;
|
|
2623
2641
|
if (!cf) return [];
|
|
2624
2642
|
const source = await ctx.resolveTask(cf.taskId);
|
|
@@ -2632,11 +2650,16 @@ async function validateFreeformInputAsync(input, ctx) {
|
|
|
2632
2650
|
message: `Source task type '${source.taskType}' is not continuable; only freeform → freeform is supported in v1`,
|
|
2633
2651
|
code: "freeform.sourceTaskTypeNotSupported"
|
|
2634
2652
|
}];
|
|
2635
|
-
if (
|
|
2653
|
+
if (execution?.workspace) return [{
|
|
2636
2654
|
field: "input/execution/workspace",
|
|
2637
2655
|
message: "execution.workspace is derived from parent runtime context when continueFrom is set; omit it",
|
|
2638
2656
|
code: "freeform.executionWorkspaceNotInheritable"
|
|
2639
2657
|
}];
|
|
2658
|
+
if (execution?.revision) return [{
|
|
2659
|
+
field: "input/execution/revision",
|
|
2660
|
+
message: "execution.revision is derived from parent runtime context when continueFrom is set; omit it",
|
|
2661
|
+
code: "freeform.executionRevisionNotInheritable"
|
|
2662
|
+
}];
|
|
2640
2663
|
if (ctx.deferReadinessChecks) return [];
|
|
2641
2664
|
const attempt = (await ctx.listAttempts(cf.taskId)).find((a) => a.attemptN === cf.attemptN);
|
|
2642
2665
|
if (!attempt || attempt.status !== "completed") return [{
|
|
@@ -4235,8 +4258,9 @@ function buildDaemonTaskExecutionPlan(task, stateDirs, identity, warmSessionTtlS
|
|
|
4235
4258
|
const slotKey = warmSessionTtlSec > 0 && descriptor.sessionKey ? buildRuntimeSlotKey(descriptor.sessionKey, identity.runtimeInstanceId) : null;
|
|
4236
4259
|
const workspaceScope = slotKey !== null ? descriptor.policy.workspaceScope : "attempt";
|
|
4237
4260
|
const slotId = slotKey ? buildDaemonSlotId(identity, slotKey) : null;
|
|
4238
|
-
const sessionDir = slotId ? `${stateDirs.piSessionsDir}/${
|
|
4261
|
+
const sessionDir = slotId ? `${stateDirs.piSessionsDir}/${boundedKeyDirComponent(slotId)}` : null;
|
|
4239
4262
|
const worktreeBranch = resolveTaskWorktreeBranch(task, workspaceMode);
|
|
4263
|
+
const workspaceRevision = resolveTaskWorkspaceRevision(task.input);
|
|
4240
4264
|
const workspaceId = workspaceMode !== "shared_mount" ? resolveTaskWorkspaceId(task, {
|
|
4241
4265
|
sessionKey: slotId,
|
|
4242
4266
|
workspaceScope,
|
|
@@ -4252,9 +4276,14 @@ function buildDaemonTaskExecutionPlan(task, stateDirs, identity, warmSessionTtlS
|
|
|
4252
4276
|
workspaceScope,
|
|
4253
4277
|
sessionPersistence: sessionDir ? { sessionDir } : null,
|
|
4254
4278
|
workspaceId,
|
|
4255
|
-
worktreeBranch
|
|
4279
|
+
worktreeBranch,
|
|
4280
|
+
workspaceRevision
|
|
4256
4281
|
};
|
|
4257
4282
|
}
|
|
4283
|
+
function resolveTaskWorkspaceRevision(input) {
|
|
4284
|
+
const value = input?.execution?.revision;
|
|
4285
|
+
return typeof value === "string" && /^[0-9a-fA-F]{40}$/.test(value) ? value.toLowerCase() : null;
|
|
4286
|
+
}
|
|
4258
4287
|
function buildDaemonSlotId(identity, slotKey) {
|
|
4259
4288
|
return [
|
|
4260
4289
|
"agent",
|
|
@@ -4280,6 +4309,7 @@ function slugSlotIdentityComponent(input) {
|
|
|
4280
4309
|
}
|
|
4281
4310
|
function resolveTaskWorktreeBranch(task, workspaceMode) {
|
|
4282
4311
|
if (workspaceMode !== "dedicated_worktree") return null;
|
|
4312
|
+
if (typeof task.input.execution?.revision === "string") return null;
|
|
4283
4313
|
if (task.taskType === "fulfill_brief") {
|
|
4284
4314
|
const input = task.input;
|
|
4285
4315
|
const slug = slugifyAsciiLower(typeof task.title === "string" && task.title.trim().length > 0 ? task.title : typeof input.brief === "string" && input.brief.trim().length > 0 ? input.brief : task.taskType, 60) || "task";
|
|
@@ -4323,8 +4353,27 @@ function isRuntimeProfileWorkspaceMode(value) {
|
|
|
4323
4353
|
function toDaemonWorkspaceMode(mode) {
|
|
4324
4354
|
return mode === "none" ? "scratch_mount" : mode;
|
|
4325
4355
|
}
|
|
4356
|
+
/**
|
|
4357
|
+
* URL-encode a slot/session key for use as a single filesystem directory
|
|
4358
|
+
* component, bounded to stay under the 255-byte per-component filename limit.
|
|
4359
|
+
* A long key (e.g. `run_eval`'s custom key, which embeds the variant label +
|
|
4360
|
+
* agent name + worker id) otherwise crashes `mkdir` with `ENAMETOOLONG`.
|
|
4361
|
+
*
|
|
4362
|
+
* Additive by design: keys short enough today keep their exact encoded form (so
|
|
4363
|
+
* existing warm dirs are byte-identical), and only over-long keys get a readable
|
|
4364
|
+
* prefix + a collision-resistant sha256 suffix. The component is never decoded
|
|
4365
|
+
* back to the key anywhere, so hashing the tail is safe. Used for BOTH the
|
|
4366
|
+
* pi-sessions dir and the session workspace dir so the two names derive
|
|
4367
|
+
* consistently from the same slot id.
|
|
4368
|
+
*/
|
|
4369
|
+
function boundedKeyDirComponent(key) {
|
|
4370
|
+
const encoded = encodeURIComponent(key);
|
|
4371
|
+
if (encoded.length <= 200) return encoded;
|
|
4372
|
+
const hash = createHash("sha256").update(key).digest("hex").slice(0, 16);
|
|
4373
|
+
return `${encoded.slice(0, 180)}-${hash}`;
|
|
4374
|
+
}
|
|
4326
4375
|
function resolveTaskWorkspaceId(task, executionPlan) {
|
|
4327
|
-
if (executionPlan.workspaceScope === "session" && executionPlan.sessionKey !== null) return `session-${
|
|
4376
|
+
if (executionPlan.workspaceScope === "session" && executionPlan.sessionKey !== null) return `session-${boundedKeyDirComponent(executionPlan.sessionKey)}`;
|
|
4328
4377
|
return executionPlan.attemptN ? `daemon-task-${task.id}-attempt-${executionPlan.attemptN}` : `task-${task.id}`;
|
|
4329
4378
|
}
|
|
4330
4379
|
//#endregion
|
|
@@ -4355,9 +4404,14 @@ function createExecutionPlanCache(args) {
|
|
|
4355
4404
|
};
|
|
4356
4405
|
}
|
|
4357
4406
|
function createNullSourceAttemptResolver() {
|
|
4358
|
-
return {
|
|
4359
|
-
|
|
4360
|
-
|
|
4407
|
+
return {
|
|
4408
|
+
findOutputBranch() {
|
|
4409
|
+
return Promise.resolve(null);
|
|
4410
|
+
},
|
|
4411
|
+
findInputRevision() {
|
|
4412
|
+
return Promise.resolve(null);
|
|
4413
|
+
}
|
|
4414
|
+
};
|
|
4361
4415
|
}
|
|
4362
4416
|
function createNullRuntimeSessionStore() {
|
|
4363
4417
|
return {
|
|
@@ -4381,7 +4435,7 @@ function assertPlanAllowedByWorkspacePolicy(plan, policy) {
|
|
|
4381
4435
|
}
|
|
4382
4436
|
function planToRuntimeProfileWorkspaceMode(plan) {
|
|
4383
4437
|
if (plan.workspaceMode === "scratch_mount") return "none";
|
|
4384
|
-
if (plan.workspaceMode === "dedicated_worktree" && !plan.worktreeBranch) return "shared_mount";
|
|
4438
|
+
if (plan.workspaceMode === "dedicated_worktree" && !plan.worktreeBranch && !plan.workspaceRevision) return "shared_mount";
|
|
4385
4439
|
return plan.workspaceMode;
|
|
4386
4440
|
}
|
|
4387
4441
|
function buildClaimedTaskKey(task) {
|
|
@@ -4427,16 +4481,20 @@ async function maybeAttachWarmSlotContext(claimedTask, basePlan, stateDirs, slot
|
|
|
4427
4481
|
attemptN: continueFrom.attemptN,
|
|
4428
4482
|
taskId: continueFrom.taskId
|
|
4429
4483
|
});
|
|
4484
|
+
const recoveredRevision = recoveredBranch ? null : await sourceAttemptResolver.findInputRevision({
|
|
4485
|
+
attemptN: continueFrom.attemptN,
|
|
4486
|
+
taskId: continueFrom.taskId
|
|
4487
|
+
});
|
|
4430
4488
|
if (continueFrom.mode === "fork") {
|
|
4431
|
-
if (recoveredBranch) {
|
|
4489
|
+
if (recoveredBranch || recoveredRevision) {
|
|
4432
4490
|
const forkWorkspaceId = `fork-${claimedTask.task.id}-attempt-${claimedTask.attemptN}`;
|
|
4433
|
-
const forkBranch = buildForkBranch(recoveredBranch, claimedTask.task.id, claimedTask.attemptN);
|
|
4491
|
+
const forkBranch = buildForkBranch(recoveredBranch ?? `detached-${continueFrom.taskId.slice(0, 8)}`, claimedTask.task.id, claimedTask.attemptN);
|
|
4434
4492
|
return {
|
|
4435
4493
|
...basePlan,
|
|
4436
4494
|
workspaceMode: "dedicated_worktree",
|
|
4437
4495
|
workspaceId: forkWorkspaceId,
|
|
4438
4496
|
worktreeBranch: forkBranch,
|
|
4439
|
-
worktreeBaseRef: recoveredBranch,
|
|
4497
|
+
worktreeBaseRef: recoveredBranch ?? recoveredRevision,
|
|
4440
4498
|
workspaceKind: "fork",
|
|
4441
4499
|
sessionPersistence: {
|
|
4442
4500
|
sessionDir,
|
|
@@ -4446,11 +4504,13 @@ async function maybeAttachWarmSlotContext(claimedTask, basePlan, stateDirs, slot
|
|
|
4446
4504
|
}
|
|
4447
4505
|
throw new ProducerContextResolutionError(`Cannot fork continuation of ${continueFrom.taskId}/${continueFrom.attemptN}: durable runtime session is available but the source attempt output did not report a branch`);
|
|
4448
4506
|
}
|
|
4507
|
+
const hasDedicatedWorkspace = Boolean(recoveredBranch || recoveredRevision);
|
|
4449
4508
|
return {
|
|
4450
4509
|
...basePlan,
|
|
4451
|
-
workspaceMode: "dedicated_worktree",
|
|
4452
|
-
workspaceId:
|
|
4510
|
+
workspaceMode: hasDedicatedWorkspace ? "dedicated_worktree" : "shared_mount",
|
|
4511
|
+
workspaceId: hasDedicatedWorkspace ? buildAttemptWorkspaceId(claimedTask) : null,
|
|
4453
4512
|
worktreeBranch: recoveredBranch,
|
|
4513
|
+
workspaceRevision: recoveredRevision,
|
|
4454
4514
|
sessionPersistence: {
|
|
4455
4515
|
sessionDir,
|
|
4456
4516
|
forkFromSessionPath: resolution.sessionPath
|
|
@@ -4458,16 +4518,20 @@ async function maybeAttachWarmSlotContext(claimedTask, basePlan, stateDirs, slot
|
|
|
4458
4518
|
};
|
|
4459
4519
|
}
|
|
4460
4520
|
const parentBranch = resolution.producerSlot.workspace?.worktreeBranch ?? null;
|
|
4521
|
+
const parentRevision = parentBranch ? null : await sourceAttemptResolver.findInputRevision({
|
|
4522
|
+
attemptN: continueFrom.attemptN,
|
|
4523
|
+
taskId: continueFrom.taskId
|
|
4524
|
+
});
|
|
4461
4525
|
if (continueFrom.mode === "fork") {
|
|
4462
|
-
if (!parentBranch) throw new ProducerContextResolutionError(`Cannot fork continuation of ${continueFrom.taskId}/${continueFrom.attemptN}: producer slot has no worktree branch to fork from`);
|
|
4526
|
+
if (!parentBranch && !parentRevision) throw new ProducerContextResolutionError(`Cannot fork continuation of ${continueFrom.taskId}/${continueFrom.attemptN}: producer slot has no worktree branch or immutable revision to fork from`);
|
|
4463
4527
|
const forkWorkspaceId = `fork-${claimedTask.task.id}-attempt-${claimedTask.attemptN}`;
|
|
4464
|
-
const forkBranch = buildForkBranch(parentBranch, claimedTask.task.id, claimedTask.attemptN);
|
|
4528
|
+
const forkBranch = buildForkBranch(parentBranch ?? `detached-${continueFrom.taskId.slice(0, 8)}`, claimedTask.task.id, claimedTask.attemptN);
|
|
4465
4529
|
return {
|
|
4466
4530
|
...basePlan,
|
|
4467
4531
|
workspaceMode: "dedicated_worktree",
|
|
4468
4532
|
workspaceId: forkWorkspaceId,
|
|
4469
4533
|
worktreeBranch: forkBranch,
|
|
4470
|
-
worktreeBaseRef: parentBranch,
|
|
4534
|
+
worktreeBaseRef: parentBranch ?? parentRevision,
|
|
4471
4535
|
workspaceKind: "fork",
|
|
4472
4536
|
sessionPersistence: {
|
|
4473
4537
|
sessionDir,
|
|
@@ -4475,11 +4539,13 @@ async function maybeAttachWarmSlotContext(claimedTask, basePlan, stateDirs, slot
|
|
|
4475
4539
|
}
|
|
4476
4540
|
};
|
|
4477
4541
|
}
|
|
4542
|
+
const hasDedicatedWorkspace = Boolean(parentBranch || parentRevision);
|
|
4478
4543
|
return {
|
|
4479
4544
|
...basePlan,
|
|
4480
|
-
workspaceMode: "dedicated_worktree",
|
|
4481
|
-
workspaceId:
|
|
4545
|
+
workspaceMode: hasDedicatedWorkspace ? "dedicated_worktree" : "shared_mount",
|
|
4546
|
+
workspaceId: hasDedicatedWorkspace ? buildAttemptWorkspaceId(claimedTask) : null,
|
|
4482
4547
|
worktreeBranch: parentBranch,
|
|
4548
|
+
workspaceRevision: parentRevision,
|
|
4483
4549
|
sessionPersistence: {
|
|
4484
4550
|
sessionDir,
|
|
4485
4551
|
forkFromSessionPath: resolution.sessionPath
|
|
@@ -5403,15 +5469,11 @@ async function listRegisteredWorktrees(mainWorktree) {
|
|
|
5403
5469
|
}
|
|
5404
5470
|
function isRealPathInsideRoot(path, root) {
|
|
5405
5471
|
try {
|
|
5406
|
-
return isResolvedPathInsideRoot
|
|
5472
|
+
return isResolvedPathInsideRoot(realpathSync(path), realpathSync(root));
|
|
5407
5473
|
} catch {
|
|
5408
5474
|
return false;
|
|
5409
5475
|
}
|
|
5410
5476
|
}
|
|
5411
|
-
function isResolvedPathInsideRoot$1(path, root) {
|
|
5412
|
-
const rel = relative(root, path);
|
|
5413
|
-
return rel === "" || !rel.startsWith("..") && !isAbsolute(rel);
|
|
5414
|
-
}
|
|
5415
5477
|
function canonicalPath(path) {
|
|
5416
5478
|
try {
|
|
5417
5479
|
return realpathSync(path);
|
|
@@ -5678,11 +5740,18 @@ function signalExitCode(signal) {
|
|
|
5678
5740
|
//#region src/lib/source-attempts.ts
|
|
5679
5741
|
function createApiSourceAttemptResolver(args) {
|
|
5680
5742
|
const { agent } = args;
|
|
5681
|
-
return {
|
|
5682
|
-
|
|
5683
|
-
|
|
5684
|
-
|
|
5685
|
-
|
|
5743
|
+
return {
|
|
5744
|
+
async findOutputBranch(input) {
|
|
5745
|
+
const attempt = (await agent.tasks.listAttempts(input.taskId)).find((candidate) => candidate.attemptN === input.attemptN);
|
|
5746
|
+
if (!attempt || attempt.status !== "completed") return null;
|
|
5747
|
+
return resolveOutputBranch(attempt.output);
|
|
5748
|
+
},
|
|
5749
|
+
async findInputRevision(input) {
|
|
5750
|
+
const task = await agent.tasks.get(input.taskId);
|
|
5751
|
+
if (task.status !== "completed" || task.acceptedAttemptN !== input.attemptN) return null;
|
|
5752
|
+
return resolveTaskWorkspaceRevision(task.input);
|
|
5753
|
+
}
|
|
5754
|
+
};
|
|
5686
5755
|
}
|
|
5687
5756
|
function resolveOutputBranch(output) {
|
|
5688
5757
|
if (!output || typeof output !== "object") return null;
|
|
@@ -6782,10 +6851,6 @@ async function isPathInsideRoot(path, root) {
|
|
|
6782
6851
|
}
|
|
6783
6852
|
return isResolvedPathInsideRoot(realResolvedPath, realResolvedRoot);
|
|
6784
6853
|
}
|
|
6785
|
-
function isResolvedPathInsideRoot(path, root) {
|
|
6786
|
-
const rel = relative(root, path);
|
|
6787
|
-
return rel === "" || !rel.startsWith("..") && !isAbsolute(rel);
|
|
6788
|
-
}
|
|
6789
6854
|
async function computeCompressedSessionFingerprint(path) {
|
|
6790
6855
|
const hash = createHash("sha256");
|
|
6791
6856
|
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.36.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,9 +62,9 @@
|
|
|
62
62
|
"pino": "^10.3.1",
|
|
63
63
|
"pino-pretty": "^13.1.3",
|
|
64
64
|
"typebox": "^1.2.8",
|
|
65
|
-
"@themoltnet/pi-runtime": "0.
|
|
66
|
-
"@themoltnet/
|
|
67
|
-
"@themoltnet/
|
|
65
|
+
"@themoltnet/pi-runtime": "0.6.0",
|
|
66
|
+
"@themoltnet/agent-runtime": "0.40.0",
|
|
67
|
+
"@themoltnet/sdk": "0.128.0"
|
|
68
68
|
},
|
|
69
69
|
"devDependencies": {
|
|
70
70
|
"tsx": "^4.7.0",
|
|
@@ -72,10 +72,10 @@
|
|
|
72
72
|
"vite": "^8.0.0",
|
|
73
73
|
"vite-plugin-dts": "^4.5.4",
|
|
74
74
|
"vitest": "^3.0.0",
|
|
75
|
-
"@moltnet/crypto-service": "0.1.0",
|
|
76
75
|
"@moltnet/bootstrap": "0.1.0",
|
|
77
|
-
"@moltnet/
|
|
78
|
-
"@moltnet/tasks": "0.1.0"
|
|
76
|
+
"@moltnet/crypto-service": "0.1.0",
|
|
77
|
+
"@moltnet/tasks": "0.1.0",
|
|
78
|
+
"@moltnet/observability": "0.1.0"
|
|
79
79
|
},
|
|
80
80
|
"nx": {
|
|
81
81
|
"projectType": "application",
|