@fungi.computer/truffle 0.5.0 → 0.6.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.
Files changed (34) hide show
  1. package/README.md +27 -4
  2. package/dist/internal/private-workerd-sandbox-worker.mjs +243 -273
  3. package/dist/internal/sandbox-metafile.json +35 -30
  4. package/dist/local-extensions.d.ts +2 -2
  5. package/dist/local-extensions.js +43 -19
  6. package/dist/private-fungi-mcp-connection.js +6 -1
  7. package/dist/private-invocation-computer.d.ts +6 -2
  8. package/dist/private-invocation-computer.js +20 -13
  9. package/dist/private-local-computer-processes.d.ts +7 -2
  10. package/dist/private-local-computer-processes.js +47 -23
  11. package/dist/private-local-delegation.js +15 -11
  12. package/dist/private-local-exec-environment.d.ts +5 -2
  13. package/dist/private-local-exec-environment.js +35 -1
  14. package/dist/private-local-exec-review.js +14 -7
  15. package/dist/private-local-exec-rules.d.ts +7 -0
  16. package/dist/private-local-exec-rules.js +23 -6
  17. package/dist/private-local-extension-records.d.ts +1 -1
  18. package/dist/private-local-runtime-host.js +2 -2
  19. package/dist/private-local-sandbox-policy.js +4 -0
  20. package/dist/private-local-sandbox.d.ts +3 -1
  21. package/dist/private-local-sandbox.js +2 -2
  22. package/dist/private-local-schedule-client.d.ts +12 -0
  23. package/dist/private-local-schedule-client.js +41 -0
  24. package/dist/private-local-schedules.d.ts +84 -0
  25. package/dist/private-local-schedules.js +65 -0
  26. package/dist/private-local-service-contract.d.ts +3 -0
  27. package/dist/private-local-service-discovery.d.ts +3 -3
  28. package/dist/private-local-service-discovery.js +1 -1
  29. package/dist/private-local-service-listener.js +9 -0
  30. package/dist/private-local-service-owner.d.ts +130 -0
  31. package/dist/private-local-service-owner.js +29 -0
  32. package/dist/private-local-service.d.ts +3 -0
  33. package/dist/private-local-service.js +2 -0
  34. package/package.json +17 -13
@@ -3,10 +3,12 @@ import { type PrivateLocalConfigRoot } from "./private-local-config-root.js";
3
3
  import type { ServiceLogLifecycle } from "./private-local-service-log.js";
4
4
  import type { StopAllResult } from "./private-local-stop-all.js";
5
5
  import { type LocalExtensions } from "./local-extensions.js";
6
+ import { z } from "zod";
6
7
  import type { PrivateLocalServiceSelection, PrivateLocalSessionCreation } from "./private-local-service-contract.js";
7
8
  import { openPrivateLocalRuntimeHost, type PrivateLocalRuntimeHost } from "./private-local-runtime-host.js";
8
9
  import type { LocalUiAttachment } from "./private-local-ui-attachment.js";
9
10
  import { createLocalMeshLinks } from "./private-local-mesh-links.js";
11
+ import { localScheduleControlInputSchema, localScheduleListInputSchema } from "./private-local-schedules.js";
10
12
  export type LocalServiceRuntime = Pick<PrivateLocalRuntimeHost, "databasePath" | "agentId" | "name" | "getSession" | "effectiveModel" | "setModel" | "setArchived" | "setMode" | "sandboxStatus" | "pendingDelegation" | "assertModelReady" | "listSessions" | "createSession" | "deleteSession" | "extensions" | "prepareReload" | "bindSessionPath" | "acceptMail" | "readSettlement" | "idle" | "close">;
11
13
  export declare class LocalSessionPathConflict extends Error {
12
14
  readonly name = "LocalSessionPathConflict";
@@ -127,6 +129,134 @@ serviceNative?: () => NonNullable<Parameters<typeof openPrivateLocalRuntimeHost>
127
129
  } | undefined;
128
130
  }>;
129
131
  sweepIdle: () => Promise<void>;
132
+ schedules: (request: z.input<typeof localScheduleListInputSchema>, signal: AbortSignal) => Promise<{
133
+ readonly items: readonly ({
134
+ readonly agentId: string;
135
+ readonly kind: "almanac";
136
+ readonly schedule: {
137
+ readonly id: string;
138
+ readonly sessionId: string;
139
+ readonly prompt: string;
140
+ readonly cron: {
141
+ readonly expression: string;
142
+ readonly timeZone: string;
143
+ } | null;
144
+ readonly nextDueAt: number;
145
+ readonly state: "cancelled" | "active" | "paused" | "finished";
146
+ readonly lastCommandId: string | null;
147
+ readonly lastError: string | null;
148
+ readonly attempt: number;
149
+ };
150
+ } | {
151
+ readonly agentId: string;
152
+ readonly kind: "loop";
153
+ readonly schedule: {
154
+ readonly sessionId: string;
155
+ readonly loopId: string;
156
+ readonly origin: "human" | "model";
157
+ readonly expiresAt: number | null;
158
+ readonly prompt: string;
159
+ readonly mode: "self_paced" | "fixed_interval";
160
+ readonly cron: {
161
+ readonly expression: string;
162
+ readonly timeZone: string;
163
+ } | null;
164
+ readonly state: "cancelled" | "active" | "failed" | "paused" | "finished";
165
+ readonly commandId: string;
166
+ readonly reason: string | null;
167
+ readonly nextDueAt: number | null;
168
+ readonly lastError: string | null;
169
+ readonly consecutiveFailures: number;
170
+ };
171
+ })[];
172
+ readonly unavailable: readonly {
173
+ readonly agentId: string;
174
+ readonly reason: "owner_unavailable";
175
+ }[];
176
+ readonly next: {
177
+ readonly agentId: string;
178
+ readonly kind: "almanac" | "loop";
179
+ readonly after?: string;
180
+ } | null;
181
+ }>;
182
+ pauseSchedule: (request: z.input<typeof localScheduleControlInputSchema>, signal: AbortSignal) => Promise<{
183
+ readonly agentId: string;
184
+ readonly kind: "almanac";
185
+ readonly schedule: {
186
+ readonly id: string;
187
+ readonly sessionId: string;
188
+ readonly prompt: string;
189
+ readonly cron: {
190
+ readonly expression: string;
191
+ readonly timeZone: string;
192
+ } | null;
193
+ readonly nextDueAt: number;
194
+ readonly state: "cancelled" | "active" | "paused" | "finished";
195
+ readonly lastCommandId: string | null;
196
+ readonly lastError: string | null;
197
+ readonly attempt: number;
198
+ };
199
+ } | {
200
+ readonly agentId: string;
201
+ readonly kind: "loop";
202
+ readonly schedule: {
203
+ readonly sessionId: string;
204
+ readonly loopId: string;
205
+ readonly origin: "human" | "model";
206
+ readonly expiresAt: number | null;
207
+ readonly prompt: string;
208
+ readonly mode: "self_paced" | "fixed_interval";
209
+ readonly cron: {
210
+ readonly expression: string;
211
+ readonly timeZone: string;
212
+ } | null;
213
+ readonly state: "cancelled" | "active" | "failed" | "paused" | "finished";
214
+ readonly commandId: string;
215
+ readonly reason: string | null;
216
+ readonly nextDueAt: number | null;
217
+ readonly lastError: string | null;
218
+ readonly consecutiveFailures: number;
219
+ };
220
+ }>;
221
+ deleteSchedule: (request: z.input<typeof localScheduleControlInputSchema>, signal: AbortSignal) => Promise<{
222
+ readonly agentId: string;
223
+ readonly kind: "almanac";
224
+ readonly schedule: {
225
+ readonly id: string;
226
+ readonly sessionId: string;
227
+ readonly prompt: string;
228
+ readonly cron: {
229
+ readonly expression: string;
230
+ readonly timeZone: string;
231
+ } | null;
232
+ readonly nextDueAt: number;
233
+ readonly state: "cancelled" | "active" | "paused" | "finished";
234
+ readonly lastCommandId: string | null;
235
+ readonly lastError: string | null;
236
+ readonly attempt: number;
237
+ };
238
+ } | {
239
+ readonly agentId: string;
240
+ readonly kind: "loop";
241
+ readonly schedule: {
242
+ readonly sessionId: string;
243
+ readonly loopId: string;
244
+ readonly origin: "human" | "model";
245
+ readonly expiresAt: number | null;
246
+ readonly prompt: string;
247
+ readonly mode: "self_paced" | "fixed_interval";
248
+ readonly cron: {
249
+ readonly expression: string;
250
+ readonly timeZone: string;
251
+ } | null;
252
+ readonly state: "cancelled" | "active" | "failed" | "paused" | "finished";
253
+ readonly commandId: string;
254
+ readonly reason: string | null;
255
+ readonly nextDueAt: number | null;
256
+ readonly lastError: string | null;
257
+ readonly consecutiveFailures: number;
258
+ };
259
+ }>;
130
260
  archive: (request: Readonly<{
131
261
  invocationRoot: string;
132
262
  agentId: string;
@@ -25,6 +25,8 @@ import { createLocalMeshLinks, localMeshLinkKey, } from "./private-local-mesh-li
25
25
  import { agentMailAddressSchema, machineAgentRequestSchema, machineDirectorySchema, } from "@fungi.computer/seam/machine-link-protocol";
26
26
  import { commandSettlementSchema, settlementReadableBy, } from "@fungi.computer/shiitake/fleet";
27
27
  import { BirdDogMailSchema } from "@fungi.computer/bird-dog/effect";
28
+ import { controlAgentScheduleWithContent } from "@fungi.computer/shiitake-extensions/schedules";
29
+ import { localScheduleControlInputSchema, localScheduleListInputSchema, readLocalSchedulePage, } from "./private-local-schedules.js";
28
30
  export class LocalSessionPathConflict extends Error {
29
31
  name = "LocalSessionPathConflict";
30
32
  constructor() {
@@ -1034,6 +1036,7 @@ serviceNative, onExecApprovalDecision = () => undefined) {
1034
1036
  }
1035
1037
  }
1036
1038
  return {
1039
+ targets,
1037
1040
  owner: admittedOwner,
1038
1041
  answer: answerAsSender,
1039
1042
  escalate: escalateAsSender,
@@ -1366,6 +1369,29 @@ serviceNative, onExecApprovalDecision = () => undefined) {
1366
1369
  scheduleWakes();
1367
1370
  await saveRecovery();
1368
1371
  }
1372
+ /** Private person-only schedule discovery, never the Agent or mesh directory. */
1373
+ async function schedules(request, signal) {
1374
+ ensureRunning();
1375
+ signal.throwIfAborted();
1376
+ const input = localScheduleListInputSchema.parse(request);
1377
+ const root = await realpath(input.invocationRoot);
1378
+ const control = directory(root);
1379
+ const agents = [...(await control.targets(signal, "all")).keys()];
1380
+ return readLocalSchedulePage(agents, (agentId, requestSignal) => control.owner(agentId, requestSignal, true), input, signal);
1381
+ }
1382
+ async function controlSchedule(request, action, signal) {
1383
+ ensureRunning();
1384
+ signal.throwIfAborted();
1385
+ const input = localScheduleControlInputSchema.parse(request);
1386
+ const root = await realpath(input.invocationRoot);
1387
+ const { owner, release } = await directory(root).owner(input.target.agentId, signal, true);
1388
+ try {
1389
+ return await controlAgentScheduleWithContent(owner, input.target, action);
1390
+ }
1391
+ finally {
1392
+ release();
1393
+ }
1394
+ }
1369
1395
  /** A person archives or restores any Agent of one project folder. */
1370
1396
  async function archive(request, signal) {
1371
1397
  const control = directory(await realpath(request.invocationRoot));
@@ -1521,6 +1547,9 @@ serviceNative, onExecApprovalDecision = () => undefined) {
1521
1547
  effectiveModel,
1522
1548
  sandboxStatus,
1523
1549
  sweepIdle,
1550
+ schedules,
1551
+ pauseSchedule: (request, signal) => controlSchedule(request, "pause", signal),
1552
+ deleteSchedule: (request, signal) => controlSchedule(request, "delete", signal),
1524
1553
  archive,
1525
1554
  stopAll,
1526
1555
  restore,
@@ -1,3 +1,6 @@
1
+ export type { PrivateLocalScheduleCapability } from "./private-local-schedule-client.js";
2
+ export type { AgentScheduleRow, AgentScheduleTarget, } from "@fungi.computer/shiitake-extensions/schedules";
3
+ export type { LocalSchedulePage } from "./private-local-schedules.js";
1
4
  export { LocalSandboxUnavailable } from "./private-local-containment.js";
2
5
  export type { StopAllResult } from "./private-local-stop-all.js";
3
6
  export { LocalAgentSelectionAmbiguous, LocalSessionPathConflict, } from "./private-local-service-owner.js";
@@ -1,5 +1,6 @@
1
1
  import { FungiMcpSelectionConflict } from "./private-fungi-mcp-selection.js";
2
2
  import { logEvent } from "./log-event.js";
3
+ import { createPrivateLocalScheduleCapability } from "./private-local-schedule-client.js";
3
4
  import { readBoundedResponse } from "./private-bounded-response.js";
4
5
  import { LocalSandboxUnavailable, sandboxUnavailableReasonSchema, } from "./private-local-containment.js";
5
6
  export { LocalSandboxUnavailable } from "./private-local-containment.js";
@@ -513,6 +514,7 @@ export function createPrivateLocalServiceManager(options = {}) {
513
514
  snapshot: z.unknown(),
514
515
  });
515
516
  return {
517
+ schedules: (invocationRoot) => createPrivateLocalScheduleCapability(invocationRoot, start),
516
518
  status,
517
519
  start,
518
520
  createSession: (creation, request) => openConnection("sessions", creation, request),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fungi.computer/truffle",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "private": false,
5
5
  "description": "Truffle: Fungi's local Agent runtime, bundled into the fungi command",
6
6
  "type": "module",
@@ -77,26 +77,26 @@
77
77
  "@cf-wasm/photon": "0.4.0",
78
78
  "@earendil-works/pi-ai": "1.3.0",
79
79
  "@effect/platform-node": "4.0.2",
80
- "@fungi.computer/agar": "0.5.0",
80
+ "@fungi.computer/agar": "0.6.0",
81
81
  "@fungi.computer/approvals": "0.2.0",
82
- "@fungi.computer/bird-dog": "0.3.0",
82
+ "@fungi.computer/bird-dog": "0.3.1",
83
83
  "@fungi.computer/cairn": "0.1.0",
84
84
  "@fungi.computer/capnweb": "0.12.0",
85
85
  "@fungi.computer/carrier": "0.2.0",
86
86
  "@fungi.computer/cordyceps": "0.4.0",
87
87
  "@fungi.computer/gills": "0.2.0",
88
- "@fungi.computer/graft": "0.1.4",
89
- "@fungi.computer/knapsack": "0.4.0",
88
+ "@fungi.computer/graft": "0.1.5",
89
+ "@fungi.computer/knapsack": "0.4.1",
90
90
  "@fungi.computer/lantern": "0.3.1",
91
- "@fungi.computer/mycelium": "0.2.3",
92
- "@fungi.computer/nacre": "0.1.0",
91
+ "@fungi.computer/mycelium": "0.3.0",
92
+ "@fungi.computer/nacre": "0.1.1",
93
93
  "@fungi.computer/seam": "0.2.0",
94
- "@fungi.computer/shiitake": "0.6.0",
95
- "@fungi.computer/shiitake-extensions": "0.4.0",
94
+ "@fungi.computer/shiitake": "0.7.0",
95
+ "@fungi.computer/shiitake-extensions": "0.5.0",
96
96
  "@fungi.computer/veil": "0.2.1",
97
97
  "@fungi.computer/watchdog": "0.1.0",
98
98
  "@fungi.computer/whistle": "0.3.0",
99
- "@fungi.computer/zookeeper": "0.0.5",
99
+ "@fungi.computer/zookeeper": "0.0.6",
100
100
  "@jellybrick/dbus-next": "0.11.4",
101
101
  "@modelcontextprotocol/client": "2.0.0",
102
102
  "@napi-rs/keyring": "2.1.2",
@@ -107,6 +107,7 @@
107
107
  "image-size": "2.0.4",
108
108
  "jose": "6.2.11",
109
109
  "miniflare": "5.20260828.0-alpha",
110
+ "npm-package-arg": "14.0.0",
110
111
  "proper-lockfile": "4.1.2",
111
112
  "re2js": "1.3.3",
112
113
  "semver": "7.8.5",
@@ -120,10 +121,11 @@
120
121
  "@fungi.computer/mule": "0.2.1",
121
122
  "@modelcontextprotocol/server": "2.0.0",
122
123
  "@types/node": "24.13.3",
124
+ "@types/npm-package-arg": "6.1.4",
123
125
  "@types/proper-lockfile": "4.1.4",
124
126
  "@types/semver": "7.8.0",
125
127
  "@types/write-file-atomic": "4.0.3",
126
- "bun": "1.4.2",
128
+ "bun": "1.4.4",
127
129
  "bun-types": "1.4.1",
128
130
  "esbuild": "0.28.2",
129
131
  "typescript": "5.9.3",
@@ -165,12 +167,14 @@
165
167
  "clean": "node --input-type=module --eval \"import { rm } from 'node:fs/promises'; await rm('dist', { recursive: true, force: true });\"",
166
168
  "test": "pnpm run test:node && pnpm run test:merge && pnpm run test:stop-all",
167
169
  "soak:memory": "bun scripts/service-memory-soak.mjs",
170
+ "soak:sqlite-open-close": "bun scripts/sqlite-open-close-repro.mjs",
168
171
  "test:stop-all": "bun test ./test/private-local-stop-all.bun.test.ts",
169
172
  "test:full": "pnpm run test && pnpm run test:bun",
170
173
  "test:node": "../../node_modules/.bin/vitest run",
174
+ "test:sandbox:native": "../../node_modules/.bin/vitest run --config vitest.native.config.ts",
171
175
  "test:bun": "pnpm run test:mesh-link && pnpm run test:bun:batch && bun test ./test/private-workerd-deadline.bun.test.ts",
172
176
  "test:mesh-link": "bun test ./test/private-local-mesh-links.bun.test.ts",
173
- "test:bun:batch": "bun test ./test/private-sqlite-approval-driver.bun.test.ts ./test/mcp-form-service.bun.test.ts ./test/private-local-service-discovery.bun.test.ts ./test/private-local-service-listener.bun.test.ts ./test/private-local-service-manager.bun.test.ts ./test/private-local-service-rebind.bun.test.ts ./test/private-local-service-stop.bun.test.ts ./test/private-local-service-ensure.bun.test.ts ./test/private-local-service-identity.bun.test.ts ./test/private-local-service-kill-resume.bun.test.ts ./test/private-local-service-idle-owners.bun.test.ts ./test/private-local-service-idle-delegation.bun.test.ts ./test/private-local-mail-retry.bun.test.ts ./test/private-local-service-log-native.bun.test.ts ./test/private-local-service-log.bun.test.ts ./test/private-local-sqlite-lifetime.bun.test.ts ./test/private-sqlite-driver.bun.test.ts ./test/private-local-reload.bun.test.ts ./test/private-local-auth-rpc.bun.test.ts ./test/private-workerd-forage.bun.test.ts ./test/local-extensions.bun.test.ts ./test/local-extension-archive.bun.test.ts ./test/local-zookeeper-slot.bun.test.ts ./test/local-extension-skills.bun.test.ts ./test/private-local-sandbox-service.bun.test.ts ./test/private-local-native-service.bun.test.ts",
177
+ "test:bun:batch": "bun test ./test/private-sqlite-approval-driver.bun.test.ts ./test/mcp-form-service.bun.test.ts ./test/private-local-service-discovery.bun.test.ts ./test/private-local-service-listener.bun.test.ts ./test/private-local-schedules.bun.test.ts ./test/private-local-service-manager.bun.test.ts ./test/private-local-service-rebind.bun.test.ts ./test/private-local-service-stop.bun.test.ts ./test/private-local-service-ensure.bun.test.ts ./test/private-local-service-identity.bun.test.ts ./test/private-local-service-kill-resume.bun.test.ts ./test/private-local-service-idle-owners.bun.test.ts ./test/private-local-service-idle-delegation.bun.test.ts ./test/private-local-mail-retry.bun.test.ts ./test/private-local-service-log-native.bun.test.ts ./test/private-local-service-log.bun.test.ts ./test/private-local-sqlite-lifetime.bun.test.ts ./test/private-sqlite-driver.bun.test.ts ./test/private-local-reload.bun.test.ts ./test/private-local-auth-rpc.bun.test.ts ./test/private-workerd-forage.bun.test.ts ./test/local-extensions.bun.test.ts ./test/local-extension-archive.bun.test.ts ./test/local-zookeeper-slot.bun.test.ts ./test/local-extension-skills.bun.test.ts ./test/private-local-sandbox-service.bun.test.ts ./test/private-local-native-service.bun.test.ts",
174
178
  "build:native": "fungi-apply-patch-build --out native/bin && node scripts/build-bwrap.mjs --out native/bin && node scripts/generate-native-digests.mjs",
175
179
  "test:patch": "node --test --test-timeout=30000 test/apply-patch.native.mjs",
176
180
  "test:sandbox:linux": "node --import tsx test/fixtures/local-sandbox-proof.mts",
@@ -178,7 +182,7 @@
178
182
  "format:check": "node ../../tooling/repository/scripts/format-package-check.mjs",
179
183
  "lint:anti-slop": "node ../../tooling/repository/scripts/lint-package-anti-slop.mjs",
180
184
  "test:unit": "node ../../tooling/repository/scripts/test-file-pool.mjs pnpm run test:node && pnpm run test:mesh-link && pnpm run test:bun:batch && pnpm run test:stop-all",
181
- "test:merge": "pnpm run test:patch && case \"$(uname -s)\" in Darwin) pnpm run test:sandbox:macos ;; *) pnpm run test:sandbox:linux ;; esac",
185
+ "test:merge": "pnpm run test:sandbox:native && pnpm run test:patch && case \"$(uname -s)\" in Darwin) pnpm run test:sandbox:macos ;; *) pnpm run test:sandbox:linux ;; esac",
182
186
  "proof:goal-loop-sol": "bun scripts/goal-loop-model-proof.mjs",
183
187
  "proof:unpatched-login": "node scripts/prove-unpatched-login.mjs",
184
188
  "proof:sqlite-close": "bun test ./test/private-local-sqlite-close.bun.test.ts"