@fungi.computer/truffle 0.1.1 → 0.2.1

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 (174) hide show
  1. package/README.md +282 -34
  2. package/dist/auth-cli.d.ts +10 -0
  3. package/dist/auth-cli.js +36 -14
  4. package/dist/fungi-account-command.d.ts +1 -1
  5. package/dist/fungi-account-command.js +6 -3
  6. package/dist/index.d.ts +10 -2
  7. package/dist/index.js +8 -2
  8. package/dist/internal/image-fit-metafile.json +106 -0
  9. package/dist/internal/local-image-fit-worker.mjs +960 -0
  10. package/dist/internal/private-workerd-sandbox-worker.mjs +11 -12
  11. package/dist/internal/sandbox-metafile.json +7 -7
  12. package/dist/local-archive-handoff.d.ts +12 -0
  13. package/dist/local-archive-handoff.js +21 -0
  14. package/dist/local-extensions.d.ts +58 -12
  15. package/dist/local-extensions.js +195 -55
  16. package/dist/local-image-fit.d.ts +30 -0
  17. package/dist/local-image-fit.js +105 -0
  18. package/dist/local-models.d.ts +4 -2
  19. package/dist/local-models.js +11 -6
  20. package/dist/local-session-archives.d.ts +8 -0
  21. package/dist/local-session-archives.js +152 -0
  22. package/dist/local-skill-source.d.ts +18 -3
  23. package/dist/local-skill-source.js +216 -140
  24. package/dist/log-event.d.ts +7 -0
  25. package/dist/log-event.js +8 -4
  26. package/dist/private-bounded-response.d.ts +2 -0
  27. package/dist/private-bounded-response.js +41 -0
  28. package/dist/private-file-credential-store.d.ts +28 -3
  29. package/dist/private-file-credential-store.js +57 -9
  30. package/dist/private-files-patch.d.ts +2 -1
  31. package/dist/private-files-patch.js +21 -3
  32. package/dist/private-fungi-account.d.ts +40 -23
  33. package/dist/private-fungi-account.js +201 -21
  34. package/dist/private-fungi-mcp-connection.d.ts +4 -0
  35. package/dist/private-fungi-mcp-connection.js +25 -6
  36. package/dist/private-fungi-mcp-selection-schema.d.ts +7 -0
  37. package/dist/private-fungi-mcp-selection-schema.js +15 -0
  38. package/dist/private-fungi-mcp-selection.d.ts +6 -6
  39. package/dist/private-fungi-mcp-selection.js +29 -16
  40. package/dist/private-fungi-model-api.js +4 -4
  41. package/dist/private-fungi-model-catalog.d.ts +10 -0
  42. package/dist/private-fungi-model-catalog.js +10 -2
  43. package/dist/private-fungi-model-provider.d.ts +1 -1
  44. package/dist/private-fungi-model-provider.js +6 -1
  45. package/dist/private-fungi-pending-logouts.d.ts +1 -1
  46. package/dist/private-fungi-pending-logouts.js +1 -2
  47. package/dist/private-fungi-service-logout.d.ts +44 -0
  48. package/dist/private-fungi-service-logout.js +59 -0
  49. package/dist/private-invocation-computer.d.ts +24 -3
  50. package/dist/private-invocation-computer.js +101 -62
  51. package/dist/private-invocation-files.d.ts +16 -1
  52. package/dist/private-invocation-files.js +154 -83
  53. package/dist/private-local-acp-stdio.js +3 -0
  54. package/dist/private-local-admission-gate.d.ts +14 -0
  55. package/dist/private-local-admission-gate.js +52 -0
  56. package/dist/private-local-agent-control.d.ts +101 -0
  57. package/dist/private-local-agent-control.js +30 -0
  58. package/dist/private-local-agent-default-model.d.ts +12 -0
  59. package/dist/private-local-agent-default-model.js +31 -0
  60. package/dist/private-local-auth-rpc.d.ts +67 -7
  61. package/dist/private-local-auth-rpc.js +140 -17
  62. package/dist/private-local-bwrap.d.ts +13 -0
  63. package/dist/private-local-bwrap.js +70 -0
  64. package/dist/private-local-client-version.d.ts +5 -0
  65. package/dist/private-local-client-version.js +43 -0
  66. package/dist/private-local-computer-attach.d.ts +3 -3
  67. package/dist/private-local-computer-attach.js +17 -3
  68. package/dist/private-local-computer-processes.d.ts +6 -3
  69. package/dist/private-local-computer-processes.js +55 -31
  70. package/dist/private-local-config-root.d.ts +21 -0
  71. package/dist/private-local-config-root.js +19 -0
  72. package/dist/private-local-containment.d.ts +51 -0
  73. package/dist/private-local-containment.js +161 -0
  74. package/dist/private-local-delegation.d.ts +10 -3
  75. package/dist/private-local-delegation.js +70 -15
  76. package/dist/private-local-effective-model.d.ts +9 -1
  77. package/dist/private-local-effective-model.js +3 -0
  78. package/dist/private-local-exec-environment.d.ts +16 -0
  79. package/dist/private-local-exec-environment.js +11 -0
  80. package/dist/private-local-linux-sandbox.d.ts +8 -0
  81. package/dist/private-local-linux-sandbox.js +67 -0
  82. package/dist/private-local-mail.d.ts +4 -2
  83. package/dist/private-local-mail.js +41 -33
  84. package/dist/private-local-mesh-enrollment.d.ts +34 -0
  85. package/dist/private-local-mesh-enrollment.js +188 -0
  86. package/dist/private-local-mesh-links.d.ts +21 -0
  87. package/dist/private-local-mesh-links.js +229 -0
  88. package/dist/private-local-mesh-record.d.ts +120 -0
  89. package/dist/private-local-mesh-record.js +55 -0
  90. package/dist/private-local-process-identity.d.ts +20 -0
  91. package/dist/private-local-process-identity.js +40 -0
  92. package/dist/private-local-runtime-host.d.ts +64 -13
  93. package/dist/private-local-runtime-host.js +361 -172
  94. package/dist/private-local-sandbox-policy.d.ts +21 -0
  95. package/dist/private-local-sandbox-policy.js +121 -0
  96. package/dist/private-local-sandbox.d.ts +37 -0
  97. package/dist/private-local-sandbox.js +114 -0
  98. package/dist/private-local-seatbelt.d.ts +24 -0
  99. package/dist/private-local-seatbelt.js +68 -0
  100. package/dist/private-local-service-contract.d.ts +91 -11
  101. package/dist/private-local-service-discovery.d.ts +129 -13
  102. package/dist/private-local-service-discovery.js +148 -47
  103. package/dist/private-local-service-lease.d.ts +16 -0
  104. package/dist/private-local-service-lease.js +105 -0
  105. package/dist/private-local-service-listener.d.ts +9 -2
  106. package/dist/private-local-service-listener.js +260 -64
  107. package/dist/private-local-service-log.d.ts +128 -0
  108. package/dist/private-local-service-log.js +321 -0
  109. package/dist/private-local-service-owner.d.ts +87 -1519
  110. package/dist/private-local-service-owner.js +1069 -71
  111. package/dist/private-local-service-process.js +3 -1
  112. package/dist/private-local-service-termination.d.ts +7 -0
  113. package/dist/private-local-service-termination.js +67 -0
  114. package/dist/private-local-service.d.ts +31 -2
  115. package/dist/private-local-service.js +402 -126
  116. package/dist/private-local-session-discovery.d.ts +52 -5
  117. package/dist/private-local-session-discovery.js +132 -11
  118. package/dist/private-local-shiitake-host.js +2 -2
  119. package/dist/private-local-startup-model.d.ts +51 -0
  120. package/dist/private-local-startup-model.js +86 -0
  121. package/dist/private-local-stop-all.d.ts +27 -0
  122. package/dist/private-local-stop-all.js +26 -0
  123. package/dist/private-local-ui-attachment.d.ts +19 -0
  124. package/dist/private-local-ui-attachment.js +71 -0
  125. package/dist/private-local-worker-server.d.ts +1 -0
  126. package/dist/private-local-worker-server.js +13 -5
  127. package/dist/private-mcp-form-contract.d.ts +186 -0
  128. package/dist/private-mcp-form-contract.js +53 -0
  129. package/dist/private-mcp-form-elicitation.d.ts +18 -0
  130. package/dist/private-mcp-form-elicitation.js +97 -0
  131. package/dist/private-mcp-form-session.d.ts +172 -0
  132. package/dist/private-mcp-form-session.js +148 -0
  133. package/dist/private-openai-claims.d.ts +30 -0
  134. package/dist/private-openai-claims.js +69 -0
  135. package/dist/private-oyster-mcp-auth.d.ts +13 -0
  136. package/dist/private-oyster-mcp-auth.js +57 -0
  137. package/dist/private-provider-rejection.d.ts +15 -0
  138. package/dist/private-provider-rejection.js +24 -0
  139. package/dist/private-sqlite-owner.d.ts +34 -2
  140. package/dist/private-sqlite-owner.js +103 -37
  141. package/dist/private-team-computers.d.ts +4 -4
  142. package/dist/private-team-computers.js +11 -2
  143. package/dist/seatbelt/safe-base.sbpl +79 -0
  144. package/dist/subscription-activation.d.ts +9 -0
  145. package/dist/subscription-activation.js +62 -0
  146. package/dist/subscription-identity.d.ts +23 -0
  147. package/dist/subscription-identity.js +124 -0
  148. package/dist/subscription-turn.d.ts +17 -0
  149. package/dist/subscription-turn.js +143 -0
  150. package/dist/team-apps.d.ts +2 -2
  151. package/dist/team-apps.js +7 -2
  152. package/native/bin/LICENSE.bubblewrap +502 -0
  153. package/native/bin/LICENSE.libcap +112 -0
  154. package/native/bin/LICENSE.sandbox-runtime +201 -0
  155. package/native/bin/SOURCE.bubblewrap.tar.xz +0 -0
  156. package/native/bin/bwrap-build-source/Dockerfile +48 -0
  157. package/native/bin/bwrap-build-source/README.md +96 -0
  158. package/native/bin/bwrap-build-source/build.mjs +52 -0
  159. package/native/bin/bwrap-build-source/linux-arm64.ini +14 -0
  160. package/native/bin/bwrap-build-source/pin.mjs +21 -0
  161. package/native/bin/bwrap-build-source/record.mjs +74 -0
  162. package/native/bin/bwrap-build-source/vendor/LICENSE.sandbox-runtime +201 -0
  163. package/native/bin/bwrap-build-source/vendor/README.md +23 -0
  164. package/native/bin/bwrap-build-source/vendor/seccomp-unix-block.c +280 -0
  165. package/native/bin/bwrap-build.json +44 -0
  166. package/native/bin/fungi-bwrap +0 -0
  167. package/native/bin/fungi-bwrap.sha256 +1 -0
  168. package/native/bin/fungi-seccomp.bpf +0 -0
  169. package/native/bin/fungi-seccomp.bpf.sha256 +1 -0
  170. package/package.json +44 -31
  171. package/dist/private-local-model-settings.d.ts +0 -5
  172. package/dist/private-local-model-settings.js +0 -31
  173. package/dist/private-local-subagents.d.ts +0 -27
  174. package/dist/private-local-subagents.js +0 -77
@@ -0,0 +1,321 @@
1
+ import { Buffer } from "node:buffer";
2
+ import fs from "node:fs";
3
+ import { join } from "node:path";
4
+ import { localFailureMetadata, logEvent } from "./log-event.js";
5
+ import { z } from "zod";
6
+ export const serviceLogRecordBytes = 32 * 1024;
7
+ const serviceLogFileBytes = 1024 * 1024;
8
+ const serviceLogBackupFiles = 3;
9
+ export const serviceLogSampleIntervalMs = 5 * 60 * 1000;
10
+ export const serviceDiagnosticsStatusSchema = z.discriminatedUnion("state", [
11
+ z.strictObject({ state: z.literal("active") }),
12
+ z.strictObject({
13
+ state: z.literal("failed"),
14
+ code: z.enum([
15
+ "sink-open-failed",
16
+ "sink-write-failed",
17
+ "sink-close-failed",
18
+ ]),
19
+ since: z.iso.datetime(),
20
+ }),
21
+ z.strictObject({
22
+ state: z.literal("recovery-disabled"),
23
+ code: z.enum(["read-failed", "decode-failed"]),
24
+ since: z.iso.datetime(),
25
+ }),
26
+ ]);
27
+ function privateLogFileSize(file) {
28
+ if (!file.isFile() || (file.mode & 0o777) !== 0o600)
29
+ throw new Error("Diagnostic log is not a private regular file");
30
+ if (file.size > serviceLogFileBytes)
31
+ throw new Error("Diagnostic log exceeds its file byte bound");
32
+ return file.size;
33
+ }
34
+ function existingLogArchive(path) {
35
+ try {
36
+ return fs.statSync(path);
37
+ }
38
+ catch (cause) {
39
+ if (cause instanceof Error && "code" in cause && cause.code === "ENOENT")
40
+ return undefined;
41
+ throw cause;
42
+ }
43
+ }
44
+ /**
45
+ * Exactly four owned names, each at most 1 MiB. Rotation happens BEFORE append,
46
+ * oldest destination first; each rename either succeeds or throws to the
47
+ * resource's Option2 latch. Replacing .3 cannot add a fifth file or extra bytes.
48
+ * No retries, asynchronous work, chmod repair or second lifecycle owner.
49
+ */
50
+ function openNativeServiceLogWriter(directory) {
51
+ const path = join(directory, "service.jsonl");
52
+ for (let index = 1; index <= serviceLogBackupFiles; index++) {
53
+ const file = existingLogArchive(`${path}.${String(index)}`);
54
+ if (file !== undefined)
55
+ privateLogFileSize(file);
56
+ }
57
+ let descriptor;
58
+ const currentDescriptor = () => {
59
+ if (descriptor === undefined)
60
+ throw new Error("Diagnostic log is closed");
61
+ return descriptor;
62
+ };
63
+ const close = () => {
64
+ const fd = descriptor;
65
+ // Retire before calling the runtime: never close a reused descriptor.
66
+ descriptor = undefined;
67
+ if (fd !== undefined)
68
+ fs.closeSync(fd);
69
+ };
70
+ const open = () => {
71
+ descriptor = fs.openSync(path, "a", 0o600);
72
+ try {
73
+ privateLogFileSize(fs.fstatSync(descriptor));
74
+ }
75
+ catch (cause) {
76
+ try {
77
+ close();
78
+ }
79
+ catch (closeCause) {
80
+ logEvent("service-log.open-close", closeCause);
81
+ }
82
+ throw cause;
83
+ }
84
+ };
85
+ const rotate = () => {
86
+ close();
87
+ for (let index = serviceLogBackupFiles - 1; index >= 1; index--) {
88
+ const source = `${path}.${String(index)}`;
89
+ const file = existingLogArchive(source);
90
+ if (file === undefined)
91
+ continue; // only genuinely absent archive slots
92
+ privateLogFileSize(file);
93
+ fs.renameSync(source, `${path}.${String(index + 1)}`);
94
+ }
95
+ // Unlike optional archives, the active pathname MUST exist.
96
+ fs.renameSync(path, `${path}.1`);
97
+ open();
98
+ };
99
+ open();
100
+ return {
101
+ writeLine(line) {
102
+ const bytes = Buffer.byteLength(line, "utf8");
103
+ if (bytes > serviceLogRecordBytes)
104
+ throw new Error("Diagnostic record exceeds its byte bound");
105
+ const size = privateLogFileSize(fs.fstatSync(currentDescriptor()));
106
+ if (size + bytes > serviceLogFileBytes)
107
+ rotate();
108
+ const written = fs.writeSync(currentDescriptor(), line, null, "utf8");
109
+ if (written !== bytes)
110
+ throw new Error("Diagnostic log short write");
111
+ },
112
+ close,
113
+ };
114
+ }
115
+ /** A drain-timeout record names at most this many unfinished owners. */
116
+ const drainTimeoutOwnerLimit = 32;
117
+ function omissionSummary(counts) {
118
+ return {
119
+ status: "omitted-byte-bound",
120
+ typeCount: Object.keys(counts).length,
121
+ allocatedCells: Object.values(counts).reduce((sum, count) => sum + count, 0),
122
+ };
123
+ }
124
+ /**
125
+ * Preserve ALL maintained count entries, in their producer order, when they fit.
126
+ * If they do not, explicitly omit the maps as a whole. No ranking/top-N policy,
127
+ * count substitution, exception serialization or byte-sliced JSON.
128
+ */
129
+ export function encodeServiceLogRecord(record) {
130
+ const line = JSON.stringify(record) + "\n";
131
+ const encodedBytes = Buffer.byteLength(line, "utf8");
132
+ if (encodedBytes <= serviceLogRecordBytes)
133
+ return line;
134
+ if (record.event === "memory") {
135
+ const summary = JSON.stringify({
136
+ ...record,
137
+ heap: {
138
+ ...record.heap,
139
+ objectTypeCounts: omissionSummary(record.heap.objectTypeCounts),
140
+ protectedObjectTypeCounts: omissionSummary(record.heap.protectedObjectTypeCounts),
141
+ },
142
+ omittedRecordBytes: encodedBytes,
143
+ }) + "\n";
144
+ if (Buffer.byteLength(summary, "utf8") <= serviceLogRecordBytes)
145
+ return summary;
146
+ }
147
+ // Only fixed classification and numeric size survive an oversized record.
148
+ return (JSON.stringify({
149
+ source: "local-service",
150
+ timestamp: record.timestamp,
151
+ pid: record.pid,
152
+ event: "record-omitted",
153
+ recordEvent: record.event,
154
+ encodedBytes,
155
+ }) + "\n");
156
+ }
157
+ /**
158
+ * One timer per service lifetime. The listener must close it before disposing
159
+ * the writer, and dispose the writer before releasing its existing owner lease.
160
+ * Both entry paths use this same owned resource.
161
+ */
162
+ export function createServiceLogSampler(input) {
163
+ let timer;
164
+ let closed = false;
165
+ return {
166
+ start() {
167
+ if (closed)
168
+ throw new Error("Cannot restart a disposed service log sampler");
169
+ if (timer !== undefined)
170
+ return;
171
+ timer = setInterval(() => {
172
+ let memory;
173
+ try {
174
+ memory = input.readMemory();
175
+ }
176
+ catch (cause) {
177
+ logEvent("service-log.sample", cause);
178
+ input.emit({
179
+ event: "memory-unavailable",
180
+ failure: localFailureMetadata("service-log.sample", cause),
181
+ });
182
+ return;
183
+ }
184
+ // A sink failure must stay observable, not be mislabeled heap failure.
185
+ input.emit({ event: "memory", ...memory });
186
+ }, serviceLogSampleIntervalMs);
187
+ timer.unref();
188
+ },
189
+ close() {
190
+ closed = true;
191
+ if (timer !== undefined)
192
+ clearInterval(timer);
193
+ timer = undefined;
194
+ },
195
+ };
196
+ }
197
+ /**
198
+ * Diagnostics resources only: no service lock, signal handler or runtime drain.
199
+ * The existing listener remains the owner. Native file I/O stays in this module.
200
+ * Writer faults latch a typed live failure, stop sampling and close once.
201
+ * They never escape into a request, turn, signal handler or timer callback.
202
+ */
203
+ export function createServiceLogLifecycle(input) {
204
+ let ready = false;
205
+ let closed = false;
206
+ let reason;
207
+ let status = { state: "active" };
208
+ let recovery;
209
+ let writer;
210
+ let writerClosed = false;
211
+ const closeWriter = () => {
212
+ if (writerClosed)
213
+ return;
214
+ writerClosed = true;
215
+ try {
216
+ writer?.close();
217
+ }
218
+ catch (cause) {
219
+ if (status.state === "active")
220
+ status = {
221
+ state: "failed",
222
+ code: "sink-close-failed",
223
+ since: new Date().toISOString(),
224
+ };
225
+ logEvent("service-log.close", cause);
226
+ }
227
+ };
228
+ const fail = (code) => {
229
+ if (status.state === "failed")
230
+ return;
231
+ status = { state: "failed", code, since: new Date().toISOString() };
232
+ sampler.close();
233
+ closeWriter();
234
+ };
235
+ const emit = (event) => {
236
+ if (closed || status.state === "failed")
237
+ return;
238
+ try {
239
+ if (writer === undefined)
240
+ throw new Error("Diagnostic writer did not open");
241
+ writer.writeLine(encodeServiceLogRecord({
242
+ ...event,
243
+ source: "local-service",
244
+ timestamp: new Date().toISOString(),
245
+ pid: input.pid,
246
+ version: input.version,
247
+ }));
248
+ }
249
+ catch (cause) {
250
+ // Publish failure before disposal/reporting: even a reentrant status read
251
+ // sees the first code/time. No further writer call or retry is permitted.
252
+ fail("sink-write-failed");
253
+ logEvent("service-log.write", cause);
254
+ }
255
+ };
256
+ const sampler = createServiceLogSampler({
257
+ readMemory: input.readMemory,
258
+ emit,
259
+ });
260
+ try {
261
+ writer = (input.openWriter ?? openNativeServiceLogWriter)(input.directory);
262
+ }
263
+ catch (cause) {
264
+ fail("sink-open-failed");
265
+ logEvent("service-log.open", cause);
266
+ }
267
+ emit({ event: "starting" });
268
+ return {
269
+ // A sink failure still takes precedence: it means diagnostics cannot be
270
+ // persisted at all. Recovery disablement must not stop a working log sink.
271
+ getStatus: () => status.state === "failed" ? status : (recovery ?? status),
272
+ ready(serviceId) {
273
+ if (closed || ready)
274
+ return;
275
+ emit({ event: "ready", serviceId });
276
+ ready = true;
277
+ if (status.state === "active")
278
+ sampler.start();
279
+ },
280
+ stopping(observedReason) {
281
+ if (reason !== undefined)
282
+ return;
283
+ reason = observedReason;
284
+ sampler.close();
285
+ emit({ event: "stopping", reason });
286
+ },
287
+ failure(failure) {
288
+ emit({ event: "failure", failure });
289
+ },
290
+ recoveryDisabled(code) {
291
+ if (closed || recovery !== undefined)
292
+ return;
293
+ recovery = {
294
+ state: "recovery-disabled",
295
+ code,
296
+ since: new Date().toISOString(),
297
+ };
298
+ emit({ event: "recovery-persistence-disabled", code });
299
+ },
300
+ drainTimeout(drain) {
301
+ // Owner names only (Agent IDs or store keys), never exception or input
302
+ // text. The record encoder still enforces the per-record byte bound.
303
+ emit({
304
+ event: "drain-timeout",
305
+ deadlineMs: drain.deadlineMs,
306
+ phase: drain.phase,
307
+ unfinishedOwners: drain.unfinishedOwners.slice(0, drainTimeoutOwnerLimit),
308
+ unfinishedOwnerCount: drain.unfinishedOwners.length,
309
+ });
310
+ },
311
+ close() {
312
+ if (closed)
313
+ return;
314
+ sampler.close();
315
+ if (reason !== undefined)
316
+ emit({ event: "stopped", reason });
317
+ closeWriter();
318
+ closed = true;
319
+ },
320
+ };
321
+ }