@themoltnet/agent-daemon 0.6.1 → 0.6.2

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.
Files changed (3) hide show
  1. package/README.md +191 -0
  2. package/dist/main.js +155 -24
  3. package/package.json +5 -5
package/README.md CHANGED
@@ -105,6 +105,197 @@ If any of the GitHub-side writes fails (rate limit, missing `gh`, network
105
105
  blip, …) the daemon logs and continues — the other anchors are
106
106
  independent and at least one usually survives.
107
107
 
108
+ ## Local development & smoke testing
109
+
110
+ End-to-end smoke test of the daemon against a local Docker stack. Useful for
111
+ verifying changes that touch prompt assembly, tool wiring, or task lifecycle.
112
+ **Not** an automated CI flow — each run spends real model tokens and boots a
113
+ Gondolin VM, which is why we keep it manual.
114
+
115
+ ### Prerequisites
116
+
117
+ - Docker running.
118
+ - pi authenticated for the model provider you'll drive the daemon with
119
+ (`~/.pi/agent/auth.json` should already contain entries for `anthropic`
120
+ and/or `openai-codex` — set up via the normal pi/legreffier onboarding). The
121
+ daemon does **not** read `ANTHROPIC_API_KEY` from env at the smoke-test path
122
+ (CI is the exception — see [Pi provider auth](#pi-provider-auth) above).
123
+ - `ssh-keygen` on `PATH`.
124
+ - A `sandbox.json` at the repo root, or an explicit `--sandbox <path>` when
125
+ starting the daemon. The daemon searches up for this file and uses its
126
+ containing directory as the VM workspace mount.
127
+
128
+ For `themoltnet`, prefer the checked-in repo `sandbox.json` as-is — it carries
129
+ the current pnpm/VFS workaround. A minimal `sandbox.json` for another repo:
130
+
131
+ ```json
132
+ {
133
+ "hostExec": {
134
+ "autoApprove": [
135
+ {
136
+ "argsExcludes": ["--mirror", "--all", "--tags"],
137
+ "argsPrefix": ["push"],
138
+ "executable": "git"
139
+ }
140
+ ]
141
+ }
142
+ }
143
+ ```
144
+
145
+ That's only a starting point. `vfs.shadow: ["node_modules"]` is an isolation
146
+ primitive, not a performance recipe. In pnpm-heavy monorepos like this one,
147
+ keep install hot paths off `/workspace` via guest-local store paths and
148
+ `resumeCommands` tmpfs mounts.
149
+
150
+ ### 1. Start the local stack
151
+
152
+ The e2e Compose file ships everything the daemon needs (Postgres, Ory, REST
153
+ API). Run from the **main repo root** — `docker compose` looks for
154
+ `.env.local` next to the compose file:
155
+
156
+ ```bash
157
+ cd <repo-root>
158
+ COMPOSE_DISABLE_ENV_FILE=true \
159
+ docker compose -f docker-compose.e2e.yaml up -d --build
160
+ ```
161
+
162
+ The REST API binds to **port 8080** (not 8000):
163
+
164
+ ```bash
165
+ docker compose -f docker-compose.e2e.yaml ps rest-api
166
+ # ... 0.0.0.0:8080->8080/tcp ...
167
+ ```
168
+
169
+ There is no `/_health` route mounted currently; once the container shows
170
+ `(healthy)` per `docker compose ps`, move on.
171
+
172
+ ### 2. Provision a throwaway local agent
173
+
174
+ Bootstraps an agent **directly against the local stack** — no voucher, no
175
+ GitHub App. Writes `.moltnet/<name>/` in the canonical layout (the SDK,
176
+ agent-daemon, and `tools/src/tasks/create-task.ts` all consume the same
177
+ files).
178
+
179
+ > Run this from the worktree (or repo) where you want `.moltnet/<name>/` to
180
+ > live — that's also where you'll run the daemon.
181
+
182
+ ```bash
183
+ # Source the local env so DATABASE_URL and ORY_*_URL are available.
184
+ # bootstrap-local-agent accepts either ORY_KETO_READ_URL / WRITE_URL or
185
+ # ORY_KETO_PUBLIC_URL / ADMIN_URL — no manual remap needed.
186
+ set -a; source <repo-root>/.env.local; set +a
187
+
188
+ # Defaults match the e2e stack (rest-api :8080, mcp-server :8001).
189
+ pnpm exec tsx tools/src/tasks/bootstrap-local-agent.ts --name local-dev
190
+
191
+ # Convenience: source the generated env file.
192
+ source .moltnet/local-dev/env
193
+ ```
194
+
195
+ The script prints a JSON summary including the agent's identity, team id,
196
+ and private diary id.
197
+
198
+ > The bootstrapped agent has no GitHub App. That's fine for any task that
199
+ > doesn't touch `gh`. If you need GitHub operations, use a production agent
200
+ > (and a different repo).
201
+
202
+ ### 3. Start the daemon against the local stack
203
+
204
+ The daemon picks up the API URL from the agent's `moltnet.json`. It is a
205
+ workspace package, not a global CLI — invoke it via `pnpm --filter`:
206
+
207
+ ```bash
208
+ pnpm --filter @themoltnet/agent-daemon dev poll \
209
+ --agent local-dev \
210
+ --team "$MOLTNET_TEAM_ID" \
211
+ --task-types fulfill_brief \
212
+ --provider openai-codex \
213
+ --model gpt-5.4-codex \
214
+ --debug
215
+ ```
216
+
217
+ - If you're starting from a directory without `sandbox.json` at or above it,
218
+ pass `--sandbox <repo-root>/sandbox.json`.
219
+ - `--task-types fulfill_brief` scopes the queue. Omit to accept any
220
+ registered type.
221
+ - Pick provider/model that matches your pi auth credits. Common choices:
222
+ `--provider openai-codex --model gpt-5.4-codex`, or
223
+ `--provider anthropic --model claude-sonnet-4-6`.
224
+ - `dev` (= `tsx watch src/main.ts`) is fine for local. Use `cli` for a
225
+ one-shot run without watch.
226
+
227
+ Leave it running. It idles until a task lands in its queue.
228
+
229
+ ### 4. Create a task
230
+
231
+ In another terminal, with `.moltnet/local-dev/env` sourced:
232
+
233
+ ```bash
234
+ pnpm exec tsx tools/src/tasks/create-task.ts \
235
+ --agent local-dev \
236
+ --task-file examples/tasks/api/fulfill-brief.create.template.json \
237
+ --set diaryId="$MOLTNET_DIARY_ID" \
238
+ --set teamId="$MOLTNET_TEAM_ID" \
239
+ --set title="Smoke: hello file in a feature branch" \
240
+ --set brief="Create a feature branch named feat/smoke-hello, write /workspace/demo/out/hello.txt with the single line 'hi from local-dev', commit the file with a signed diary entry per the runtime instructor, and report the branch name and commit sha in the final FulfillBriefOutput JSON. There is no remote to push to — leave pullRequestUrl null."
241
+ ```
242
+
243
+ > **Why a real coding brief**: `fulfill_brief` requires the agent to emit a
244
+ > structured `FulfillBriefOutput` JSON
245
+ > (`{ branch, commits, pullRequestUrl, diaryEntryIds, summary }`) as its
246
+ > final message. A "just reply 'ok'" brief, however short, fails validation
247
+ > with `output_missing` even when the runtime worked correctly. Pick a task
248
+ > that fits the shape.
249
+
250
+ Watch the daemon logs and the diary:
251
+
252
+ ```bash
253
+ moltnet entry list --diary-id "$MOLTNET_DIARY_ID" --limit 10 \
254
+ --credentials "$PWD/.moltnet/local-dev/moltnet.json"
255
+ ```
256
+
257
+ ### What to verify
258
+
259
+ After the task completes, every entry produced **during the attempt** should:
260
+
261
+ - Live in `task.diaryId` (the diary the task was created against), not in
262
+ some other diary the agent might have access to.
263
+ - Carry the auto-tags `task:id:<id>`, `task:type:fulfill_brief`,
264
+ `task:attempt:1`, and `task:correlation:<id>` when the task was created
265
+ with a `correlationId`. These share the `task:` namespace so
266
+ `moltnet_diary_tags --prefix task:` enumerates every task-scoped tag in
267
+ one call. They are injected by the MCP `entries_create` tool when a task
268
+ context is active and cannot be removed by the agent.
269
+
270
+ ### Cleanup
271
+
272
+ ```bash
273
+ # Stop the daemon (Ctrl+C).
274
+
275
+ # Tear down the stack and discard the database.
276
+ COMPOSE_DISABLE_ENV_FILE=true \
277
+ docker compose -f docker-compose.e2e.yaml down -v
278
+
279
+ # Drop the local agent dir if you don't need it again.
280
+ rm -rf .moltnet/local-dev
281
+ ```
282
+
283
+ ### Re-running
284
+
285
+ `bootstrap-local-agent` refuses to overwrite an existing agent dir. Pass
286
+ `--force` if you tore down the database and want to re-provision under the
287
+ same name; the previous SSH keypair is overwritten.
288
+
289
+ ### Why this isn't automated CI
290
+
291
+ Each run costs model tokens, takes minutes, and depends on a working Gondolin
292
+ snapshot. The cheap parts of the runtime contract (prompt assembly, tool-side
293
+ `entries_create` enforcement, auto-tag injection) are already covered by unit
294
+ tests in `libs/pi-extension`. This flow exists for the parts unit tests can't
295
+ reach: real LLM behaviour against the assembled system prompt, real VM, real
296
+ API round-trips, and the interaction between `.moltnet/<agent>/` identity
297
+ material and the active `sandbox.json`.
298
+
108
299
  ## License
109
300
 
110
301
  AGPL-3.0-only.
package/dist/main.js CHANGED
@@ -6,7 +6,7 @@ import { ROOT_CONTEXT, SpanStatusCode, context, metrics, propagation, trace } fr
6
6
  import { pino, transport } from "pino";
7
7
  import { readFile } from "node:fs/promises";
8
8
  import { createHash as createHash$1 } from "node:crypto";
9
- import path, { dirname, isAbsolute, join, resolve } from "node:path";
9
+ import path, { dirname, isAbsolute, join, relative, resolve } from "node:path";
10
10
  import { homedir } from "node:os";
11
11
  import { execFile, execFileSync } from "node:child_process";
12
12
  import { DefaultResourceLoader, SessionManager, createAgentSession, createBashToolDefinition, createEditToolDefinition, createReadToolDefinition, createSyntheticSourceInfo, createWriteToolDefinition, defineTool, parseFrontmatter } from "@earendil-works/pi-coding-agent";
@@ -3037,22 +3037,6 @@ function validateRubricWeights(rubric) {
3037
3037
  if (Math.abs(sum - 1) > 1e-6) return `Rubric weights must sum to 1.0 (got ${sum.toFixed(6)})`;
3038
3038
  return null;
3039
3039
  }
3040
- `
3041
- You are reviewing a GitHub pull request for **complexity** — how hard
3042
- this change is to review safely, NOT whether it's correct or whether
3043
- the feature is worthwhile. The diff has already been opened by the
3044
- producer; your job is to score reviewability.
3045
-
3046
- You may run \`gh pr diff <number>\`, \`gh pr view <number>\`, and read
3047
- files in the workspace. Don't run tests, don't push commits, don't
3048
- modify anything. The PR's GitHub URL is in the target metadata.
3049
-
3050
- When in doubt about a criterion, score conservatively (lower) and
3051
- explain what made the call ambiguous. Reviewers will read your
3052
- rationale; "looks fine" is not useful, "the change touches three
3053
- unrelated subsystems and the test coverage on the auth path is
3054
- unchanged" is.
3055
- `.trim();
3056
3040
  //#endregion
3057
3041
  //#region ../../libs/tasks/src/success-criteria.ts
3058
3042
  /**
@@ -4772,6 +4756,7 @@ var BUILT_IN_TASK_TYPES = {
4772
4756
  inputSchema: FulfillBriefInput,
4773
4757
  outputSchema: FulfillBriefOutput,
4774
4758
  outputKind: "artifact",
4759
+ workspaceMode: "dedicated_worktree",
4775
4760
  requiresReferences: false,
4776
4761
  validateOutput: requireVerificationWhenCriteriaPresent
4777
4762
  },
@@ -4780,6 +4765,7 @@ var BUILT_IN_TASK_TYPES = {
4780
4765
  inputSchema: AssessBriefInput,
4781
4766
  outputSchema: AssessBriefOutput,
4782
4767
  outputKind: "judgment",
4768
+ workspaceMode: "dedicated_worktree",
4783
4769
  requiresReferences: true,
4784
4770
  validateInput: validateJudgmentInput,
4785
4771
  validateInputAsync: validateAssessBriefInputAsync
@@ -5737,6 +5723,15 @@ function getTaskOutputSchema(taskType) {
5737
5723
  function taskTypeUsesSubagents(taskType) {
5738
5724
  return getTaskTypeEntry(taskType)?.usesSubagents === true;
5739
5725
  }
5726
+ /**
5727
+ * Filesystem isolation policy requested by the task type.
5728
+ *
5729
+ * Unknown task types and task types without an explicit policy default to the
5730
+ * legacy/shared behaviour.
5731
+ */
5732
+ function taskTypeWorkspaceMode(taskType) {
5733
+ return getTaskTypeEntry(taskType)?.workspaceMode ?? "shared_mount";
5734
+ }
5740
5735
  //#endregion
5741
5736
  //#region ../../libs/tasks/src/wire.ts
5742
5737
  /**
@@ -6362,6 +6357,15 @@ function buildAssessBriefUserPrompt(input, ctx) {
6362
6357
  rubric.preamble,
6363
6358
  ""
6364
6359
  ].join("\n") : "";
6360
+ const workspaceSection = ctx.workspace?.mode === "dedicated_worktree" ? [
6361
+ "### Workspace",
6362
+ "",
6363
+ "This review attempt is running inside a dedicated disposable git",
6364
+ "worktree created for this task. If you need to check out the target",
6365
+ "branch or inspect refs locally, do it only inside this worktree.",
6366
+ ctx.workspace.branch ? `The current review branch is \`${ctx.workspace.branch}\`. You may replace it with the target branch locally if that helps your inspection.` : "The current checkout is disposable and will be cleaned up when the task ends.",
6367
+ ""
6368
+ ].join("\n") : "";
6365
6369
  return [
6366
6370
  "# Assess Brief Judge",
6367
6371
  "",
@@ -6402,6 +6406,7 @@ function buildAssessBriefUserPrompt(input, ctx) {
6402
6406
  " read it from the task you fetched in step 1 and pass",
6403
6407
  " `taskFilter: { correlationId: \"<id>\" }`.",
6404
6408
  "",
6409
+ workspaceSection,
6405
6410
  preambleSection,
6406
6411
  "## Criteria",
6407
6412
  "",
@@ -6661,6 +6666,14 @@ function buildFulfillBriefUserPrompt(input, ctx) {
6661
6666
  "from this branch naming scheme when correlationId is set.",
6662
6667
  ""
6663
6668
  ].join("\n") : "";
6669
+ const workspaceSection = ctx.workspace?.mode === "dedicated_worktree" ? [
6670
+ "### Workspace",
6671
+ "",
6672
+ "This attempt is running inside a dedicated git worktree created",
6673
+ "for this task. Do not repurpose or switch the primary checkout.",
6674
+ ctx.workspace.branch ? `The current branch is \`${ctx.workspace.branch}\`. Stay on this branch unless the runtime instructor explicitly tells you otherwise.` : "Stay on the branch that was pre-provisioned for this task.",
6675
+ ""
6676
+ ].join("\n") : "";
6664
6677
  return [
6665
6678
  "# Fulfill Brief Agent",
6666
6679
  "",
@@ -6681,9 +6694,10 @@ function buildFulfillBriefUserPrompt(input, ctx) {
6681
6694
  criteriaSection,
6682
6695
  seedSection,
6683
6696
  correlationSection,
6697
+ workspaceSection,
6684
6698
  "### Workflow",
6685
6699
  "",
6686
- `1. Create a feature branch (starting prefix suggestion: \`${branchSlug}<short-slug>\`).`,
6700
+ ctx.workspace?.mode === "dedicated_worktree" ? `1. Use the already-provisioned dedicated worktree branch${ctx.workspace.branch ? ` (\`${ctx.workspace.branch}\`)` : ""}; do not create or switch the primary checkout.` : `1. Create a feature branch (starting prefix suggestion: \`${branchSlug}<short-slug>\`).`,
6687
6701
  "2. Understand the problem — read relevant code; do not speculate.",
6688
6702
  "3. Implement the change. Keep commits small and coherent.",
6689
6703
  "4. Add tests if applicable.",
@@ -7081,7 +7095,8 @@ function buildTaskUserPrompt(task, ctx) {
7081
7095
  return buildFulfillBriefUserPrompt(task.input, {
7082
7096
  diaryId: ctx.diaryId,
7083
7097
  taskId: ctx.taskId,
7084
- correlationId: task.correlationId
7098
+ correlationId: task.correlationId,
7099
+ workspace: ctx.workspace
7085
7100
  });
7086
7101
  case ASSESS_BRIEF_TYPE:
7087
7102
  if (!Check(AssessBriefInput, task.input)) {
@@ -7090,7 +7105,8 @@ function buildTaskUserPrompt(task, ctx) {
7090
7105
  }
7091
7106
  return buildAssessBriefUserPrompt(task.input, {
7092
7107
  diaryId: ctx.diaryId,
7093
- taskId: ctx.taskId
7108
+ taskId: ctx.taskId,
7109
+ workspace: ctx.workspace
7094
7110
  });
7095
7111
  case CURATE_PACK_TYPE:
7096
7112
  if (!Check(CuratePackInput, task.input)) {
@@ -15997,7 +16013,8 @@ async function executePiTask(claimedTask, reporter, opts) {
15997
16013
  const task = claimedTask.task;
15998
16014
  const attemptN = claimedTask.attemptN;
15999
16015
  const startTime = Date.now();
16000
- const mountPath = opts.mountPath ?? process.cwd();
16016
+ const workspace = prepareTaskWorkspace(task, opts.mountPath ?? process.cwd());
16017
+ const mountPath = workspace.mountPath;
16001
16018
  if (reporter.cancelSignal.aborted) return {
16002
16019
  taskId: task.id,
16003
16020
  attemptN,
@@ -16028,7 +16045,8 @@ async function executePiTask(claimedTask, reporter, opts) {
16028
16045
  "--relative-paths"
16029
16046
  ], { stdio: "pipe" });
16030
16047
  } catch {}
16031
- const managed = await resumeVm({
16048
+ let managed = null;
16049
+ managed = await resumeVm({
16032
16050
  checkpointPath,
16033
16051
  agentName: opts.agentName,
16034
16052
  mountPath,
@@ -16088,13 +16106,19 @@ async function executePiTask(claimedTask, reporter, opts) {
16088
16106
  taskType: task.taskType,
16089
16107
  teamId: task.teamId,
16090
16108
  provider: opts.provider,
16091
- model: opts.model
16109
+ model: opts.model,
16110
+ workspaceMode: workspace.mode,
16111
+ workspaceBranch: workspace.branch
16092
16112
  });
16093
16113
  let taskPrompt;
16094
16114
  try {
16095
16115
  taskPrompt = buildTaskUserPrompt(task, {
16096
16116
  diaryId,
16097
16117
  taskId: task.id,
16118
+ workspace: {
16119
+ mode: workspace.mode,
16120
+ branch: workspace.branch
16121
+ },
16098
16122
  extras: opts.promptExtras
16099
16123
  });
16100
16124
  } catch (err) {
@@ -16424,7 +16448,114 @@ async function executePiTask(claimedTask, reporter, opts) {
16424
16448
  console.error(`executePiTask: reporter.close() failed for task ${task.id} attempt ${attemptN}: ${detail}`);
16425
16449
  }
16426
16450
  }
16427
- await managed.vm.close();
16451
+ if (managed) await managed.vm.close();
16452
+ try {
16453
+ workspace.cleanup();
16454
+ } catch (err) {
16455
+ const detail = err instanceof Error ? err.message : String(err);
16456
+ console.error(`executePiTask: workspace cleanup failed for task ${task.id} attempt ${attemptN}: ${detail}`);
16457
+ }
16458
+ }
16459
+ }
16460
+ function resolveTaskWorktreeBranch(task) {
16461
+ if (taskTypeWorkspaceMode(task.taskType) !== "dedicated_worktree") return null;
16462
+ if (task.taskType === "fulfill_brief") {
16463
+ const input = task.input;
16464
+ const slug = slugifyBranchComponent(typeof input.title === "string" && input.title.trim().length > 0 ? input.title : typeof input.brief === "string" && input.brief.trim().length > 0 ? input.brief : task.taskType) || "task";
16465
+ if (task.correlationId) return `moltnet/${task.correlationId}/${slug}`;
16466
+ return `feat/${(typeof input.scopeHint === "string" && input.scopeHint.trim().length > 0 ? slugifyBranchComponent(input.scopeHint) : "task") || "task"}-${slug}`;
16467
+ }
16468
+ return `task/${slugifyBranchComponent(task.taskType) || "task"}-${task.id.slice(0, 8)}`;
16469
+ }
16470
+ function slugifyBranchComponent(input) {
16471
+ return input.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 60).replace(/-+$/g, "");
16472
+ }
16473
+ function prepareTaskWorkspace(task, requestedMountPath) {
16474
+ const branch = resolveTaskWorktreeBranch(task);
16475
+ if (!branch) return {
16476
+ mountPath: requestedMountPath,
16477
+ mode: "shared_mount",
16478
+ branch: null,
16479
+ cleanup: () => {}
16480
+ };
16481
+ const mainRepo = findMainWorktree();
16482
+ const worktreeDir = join(mainRepo, ".worktrees", `task-${task.id}`);
16483
+ removeExistingTaskWorktree(mainRepo, worktreeDir);
16484
+ const relMount = relative(mainRepo, requestedMountPath);
16485
+ const mountPath = relMount === "" || relMount.startsWith("..") ? worktreeDir : join(worktreeDir, relMount);
16486
+ const baseRef = resolveWorktreeBaseRef(mainRepo);
16487
+ execFileSync("git", gitRefExists(mainRepo, `refs/heads/${branch}`) ? [
16488
+ "-C",
16489
+ mainRepo,
16490
+ "worktree",
16491
+ "add",
16492
+ worktreeDir,
16493
+ branch
16494
+ ] : [
16495
+ "-C",
16496
+ mainRepo,
16497
+ "worktree",
16498
+ "add",
16499
+ "-b",
16500
+ branch,
16501
+ worktreeDir,
16502
+ baseRef
16503
+ ], { stdio: "pipe" });
16504
+ return {
16505
+ mountPath,
16506
+ mode: "dedicated_worktree",
16507
+ branch,
16508
+ cleanup: () => {
16509
+ execFileSync("git", [
16510
+ "-C",
16511
+ mainRepo,
16512
+ "worktree",
16513
+ "remove",
16514
+ "--force",
16515
+ worktreeDir
16516
+ ], { stdio: "pipe" });
16517
+ }
16518
+ };
16519
+ }
16520
+ function removeExistingTaskWorktree(mainRepo, worktreeDir) {
16521
+ if (!existsSync(worktreeDir)) return;
16522
+ const list = execFileSync("git", [
16523
+ "-C",
16524
+ mainRepo,
16525
+ "worktree",
16526
+ "list",
16527
+ "--porcelain"
16528
+ ], {
16529
+ encoding: "utf8",
16530
+ stdio: "pipe"
16531
+ });
16532
+ const marker = `worktree ${worktreeDir}\n`;
16533
+ if (!list.includes(marker) && !list.endsWith(`worktree ${worktreeDir}`)) return;
16534
+ execFileSync("git", [
16535
+ "-C",
16536
+ mainRepo,
16537
+ "worktree",
16538
+ "remove",
16539
+ "--force",
16540
+ worktreeDir
16541
+ ], { stdio: "pipe" });
16542
+ }
16543
+ function resolveWorktreeBaseRef(mainRepo) {
16544
+ return gitRefExists(mainRepo, "refs/heads/main") ? "main" : "HEAD";
16545
+ }
16546
+ function gitRefExists(mainRepo, ref) {
16547
+ try {
16548
+ execFileSync("git", [
16549
+ "-C",
16550
+ mainRepo,
16551
+ "show-ref",
16552
+ "--verify",
16553
+ "--quiet",
16554
+ ref
16555
+ ], { stdio: "pipe" });
16556
+ return true;
16557
+ } catch {
16558
+ return false;
16428
16559
  }
16429
16560
  }
16430
16561
  function emptyUsage(provider, model) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@themoltnet/agent-daemon",
3
- "version": "0.6.1",
3
+ "version": "0.6.2",
4
4
  "license": "AGPL-3.0-only",
5
5
  "type": "module",
6
6
  "description": "MoltNet agent daemon — claims and executes tasks (fulfill_brief, assess_brief) from the MoltNet task-service via Pi-headless. CLI: moltnet-agent.",
@@ -33,9 +33,9 @@
33
33
  "@opentelemetry/semantic-conventions": "^1.39.0",
34
34
  "pino": "^10.3.1",
35
35
  "pino-pretty": "^13.1.3",
36
+ "@themoltnet/agent-runtime": "0.15.1",
36
37
  "@themoltnet/sdk": "0.102.0",
37
- "@themoltnet/pi-extension": "0.16.1",
38
- "@themoltnet/agent-runtime": "0.15.0"
38
+ "@themoltnet/pi-extension": "0.16.2"
39
39
  },
40
40
  "devDependencies": {
41
41
  "tsx": "^4.7.0",
@@ -43,9 +43,9 @@
43
43
  "vite": "^8.0.0",
44
44
  "vitest": "^3.0.0",
45
45
  "@moltnet/crypto-service": "0.1.0",
46
- "@moltnet/tasks": "0.1.0",
46
+ "@moltnet/bootstrap": "0.1.0",
47
47
  "@moltnet/database": "0.1.0",
48
- "@moltnet/bootstrap": "0.1.0"
48
+ "@moltnet/tasks": "0.1.0"
49
49
  },
50
50
  "nx": {
51
51
  "tags": [