@fungi.computer/truffle 0.0.0-stage → 0.2.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 (207) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +542 -2
  3. package/computerd-loopback.cjs +16 -0
  4. package/dist/auth-cli.d.ts +46 -0
  5. package/dist/auth-cli.js +373 -0
  6. package/dist/fungi-account-command.d.ts +18 -0
  7. package/dist/fungi-account-command.js +95 -0
  8. package/dist/index.d.ts +27 -0
  9. package/dist/index.js +23 -0
  10. package/dist/internal/image-fit-metafile.json +106 -0
  11. package/dist/internal/local-image-fit-worker.mjs +960 -0
  12. package/dist/internal/private-workerd-sandbox-worker.mjs +27487 -0
  13. package/dist/internal/sandbox-metafile.json +6726 -0
  14. package/dist/linear-auth.d.ts +4 -0
  15. package/dist/linear-auth.js +72 -0
  16. package/dist/local-archive-handoff.d.ts +12 -0
  17. package/dist/local-archive-handoff.js +21 -0
  18. package/dist/local-extensions.d.ts +143 -0
  19. package/dist/local-extensions.js +624 -0
  20. package/dist/local-image-fit.d.ts +30 -0
  21. package/dist/local-image-fit.js +105 -0
  22. package/dist/local-login.d.ts +55 -0
  23. package/dist/local-login.js +167 -0
  24. package/dist/local-models.d.ts +16 -0
  25. package/dist/local-models.js +82 -0
  26. package/dist/local-session-archives.d.ts +8 -0
  27. package/dist/local-session-archives.js +152 -0
  28. package/dist/local-skill-source.d.ts +21 -0
  29. package/dist/local-skill-source.js +433 -0
  30. package/dist/log-event.d.ts +9 -0
  31. package/dist/log-event.js +13 -0
  32. package/dist/private-bounded-response.d.ts +2 -0
  33. package/dist/private-bounded-response.js +41 -0
  34. package/dist/private-bun-shiitake-host.d.ts +11 -0
  35. package/dist/private-bun-shiitake-host.js +66 -0
  36. package/dist/private-file-credential-store.d.ts +58 -0
  37. package/dist/private-file-credential-store.js +331 -0
  38. package/dist/private-files-patch.d.ts +4 -0
  39. package/dist/private-files-patch.js +104 -0
  40. package/dist/private-fungi-account.d.ts +252 -0
  41. package/dist/private-fungi-account.js +1329 -0
  42. package/dist/private-fungi-auth-error.d.ts +5 -0
  43. package/dist/private-fungi-auth-error.js +7 -0
  44. package/dist/private-fungi-mcp-connection.d.ts +26 -0
  45. package/dist/private-fungi-mcp-connection.js +162 -0
  46. package/dist/private-fungi-mcp-endpoint.d.ts +2 -0
  47. package/dist/private-fungi-mcp-endpoint.js +15 -0
  48. package/dist/private-fungi-mcp-selection-schema.d.ts +7 -0
  49. package/dist/private-fungi-mcp-selection-schema.js +15 -0
  50. package/dist/private-fungi-mcp-selection.d.ts +14 -0
  51. package/dist/private-fungi-mcp-selection.js +49 -0
  52. package/dist/private-fungi-model-api.d.ts +6 -0
  53. package/dist/private-fungi-model-api.js +125 -0
  54. package/dist/private-fungi-model-catalog.d.ts +16 -0
  55. package/dist/private-fungi-model-catalog.js +86 -0
  56. package/dist/private-fungi-model-provider.d.ts +6 -0
  57. package/dist/private-fungi-model-provider.js +51 -0
  58. package/dist/private-fungi-pending-logouts.d.ts +34 -0
  59. package/dist/private-fungi-pending-logouts.js +135 -0
  60. package/dist/private-fungi-service-logout.d.ts +44 -0
  61. package/dist/private-fungi-service-logout.js +59 -0
  62. package/dist/private-invocation-computer.d.ts +58 -0
  63. package/dist/private-invocation-computer.js +498 -0
  64. package/dist/private-invocation-files.d.ts +30 -0
  65. package/dist/private-invocation-files.js +520 -0
  66. package/dist/private-local-acp-stdio.d.ts +17 -0
  67. package/dist/private-local-acp-stdio.js +145 -0
  68. package/dist/private-local-admission-gate.d.ts +14 -0
  69. package/dist/private-local-admission-gate.js +52 -0
  70. package/dist/private-local-agent-control.d.ts +101 -0
  71. package/dist/private-local-agent-control.js +30 -0
  72. package/dist/private-local-agent-default-model.d.ts +12 -0
  73. package/dist/private-local-agent-default-model.js +31 -0
  74. package/dist/private-local-auth-rpc.d.ts +129 -0
  75. package/dist/private-local-auth-rpc.js +396 -0
  76. package/dist/private-local-bwrap.d.ts +13 -0
  77. package/dist/private-local-bwrap.js +70 -0
  78. package/dist/private-local-client-version.d.ts +5 -0
  79. package/dist/private-local-client-version.js +43 -0
  80. package/dist/private-local-computer-attach.d.ts +49 -0
  81. package/dist/private-local-computer-attach.js +230 -0
  82. package/dist/private-local-computer-backend.d.ts +282 -0
  83. package/dist/private-local-computer-backend.js +402 -0
  84. package/dist/private-local-computer-processes.d.ts +202 -0
  85. package/dist/private-local-computer-processes.js +613 -0
  86. package/dist/private-local-config-root.d.ts +21 -0
  87. package/dist/private-local-config-root.js +19 -0
  88. package/dist/private-local-containment.d.ts +51 -0
  89. package/dist/private-local-containment.js +161 -0
  90. package/dist/private-local-default-model.d.ts +11 -0
  91. package/dist/private-local-default-model.js +45 -0
  92. package/dist/private-local-delegation.d.ts +36 -0
  93. package/dist/private-local-delegation.js +133 -0
  94. package/dist/private-local-effective-model.d.ts +27 -0
  95. package/dist/private-local-effective-model.js +17 -0
  96. package/dist/private-local-exec-environment.d.ts +16 -0
  97. package/dist/private-local-exec-environment.js +11 -0
  98. package/dist/private-local-exec-launch.d.ts +41 -0
  99. package/dist/private-local-exec-launch.js +51 -0
  100. package/dist/private-local-exec-path.d.ts +6 -0
  101. package/dist/private-local-exec-path.js +40 -0
  102. package/dist/private-local-git-exclude.d.ts +2 -0
  103. package/dist/private-local-git-exclude.js +33 -0
  104. package/dist/private-local-http-dispatch.d.ts +5 -0
  105. package/dist/private-local-http-dispatch.js +14 -0
  106. package/dist/private-local-linux-sandbox.d.ts +8 -0
  107. package/dist/private-local-linux-sandbox.js +67 -0
  108. package/dist/private-local-mail.d.ts +13 -0
  109. package/dist/private-local-mail.js +77 -0
  110. package/dist/private-local-mesh-enrollment.d.ts +34 -0
  111. package/dist/private-local-mesh-enrollment.js +188 -0
  112. package/dist/private-local-mesh-links.d.ts +21 -0
  113. package/dist/private-local-mesh-links.js +229 -0
  114. package/dist/private-local-mesh-record.d.ts +120 -0
  115. package/dist/private-local-mesh-record.js +55 -0
  116. package/dist/private-local-process-identity.d.ts +20 -0
  117. package/dist/private-local-process-identity.js +40 -0
  118. package/dist/private-local-runtime-host.d.ts +192 -0
  119. package/dist/private-local-runtime-host.js +1177 -0
  120. package/dist/private-local-sandbox-policy.d.ts +21 -0
  121. package/dist/private-local-sandbox-policy.js +121 -0
  122. package/dist/private-local-sandbox.d.ts +37 -0
  123. package/dist/private-local-sandbox.js +114 -0
  124. package/dist/private-local-seatbelt.d.ts +24 -0
  125. package/dist/private-local-seatbelt.js +68 -0
  126. package/dist/private-local-service-contract.d.ts +170 -0
  127. package/dist/private-local-service-contract.js +1 -0
  128. package/dist/private-local-service-discovery.d.ts +217 -0
  129. package/dist/private-local-service-discovery.js +322 -0
  130. package/dist/private-local-service-ids.d.ts +3 -0
  131. package/dist/private-local-service-ids.js +8 -0
  132. package/dist/private-local-service-lease.d.ts +16 -0
  133. package/dist/private-local-service-lease.js +105 -0
  134. package/dist/private-local-service-listener.d.ts +22 -0
  135. package/dist/private-local-service-listener.js +407 -0
  136. package/dist/private-local-service-log.d.ts +128 -0
  137. package/dist/private-local-service-log.js +321 -0
  138. package/dist/private-local-service-owner.d.ts +135 -0
  139. package/dist/private-local-service-owner.js +1369 -0
  140. package/dist/private-local-service-process.d.ts +1 -0
  141. package/dist/private-local-service-process.js +8 -0
  142. package/dist/private-local-service-termination.d.ts +7 -0
  143. package/dist/private-local-service-termination.js +67 -0
  144. package/dist/private-local-service.d.ts +46 -0
  145. package/dist/private-local-service.js +606 -0
  146. package/dist/private-local-session-discovery.d.ts +66 -0
  147. package/dist/private-local-session-discovery.js +278 -0
  148. package/dist/private-local-shiitake-host.d.ts +44 -0
  149. package/dist/private-local-shiitake-host.js +143 -0
  150. package/dist/private-local-startup-model.d.ts +51 -0
  151. package/dist/private-local-startup-model.js +86 -0
  152. package/dist/private-local-stop-all.d.ts +27 -0
  153. package/dist/private-local-stop-all.js +26 -0
  154. package/dist/private-local-ui-attachment.d.ts +19 -0
  155. package/dist/private-local-ui-attachment.js +71 -0
  156. package/dist/private-local-worker-server.d.ts +16 -0
  157. package/dist/private-local-worker-server.js +144 -0
  158. package/dist/private-mcp-form-contract.d.ts +186 -0
  159. package/dist/private-mcp-form-contract.js +53 -0
  160. package/dist/private-mcp-form-elicitation.d.ts +18 -0
  161. package/dist/private-mcp-form-elicitation.js +97 -0
  162. package/dist/private-mcp-form-session.d.ts +172 -0
  163. package/dist/private-mcp-form-session.js +148 -0
  164. package/dist/private-openai-claims.d.ts +30 -0
  165. package/dist/private-openai-claims.js +69 -0
  166. package/dist/private-oyster-mcp-auth.d.ts +13 -0
  167. package/dist/private-oyster-mcp-auth.js +57 -0
  168. package/dist/private-provider-rejection.d.ts +15 -0
  169. package/dist/private-provider-rejection.js +24 -0
  170. package/dist/private-sqlite-owner.d.ts +39 -0
  171. package/dist/private-sqlite-owner.js +169 -0
  172. package/dist/private-team-computers.d.ts +38 -0
  173. package/dist/private-team-computers.js +110 -0
  174. package/dist/private-workerd-sandbox.d.ts +3 -0
  175. package/dist/private-workerd-sandbox.js +347 -0
  176. package/dist/seatbelt/safe-base.sbpl +79 -0
  177. package/dist/subscription-activation.d.ts +9 -0
  178. package/dist/subscription-activation.js +62 -0
  179. package/dist/subscription-identity.d.ts +23 -0
  180. package/dist/subscription-identity.js +124 -0
  181. package/dist/subscription-turn.d.ts +17 -0
  182. package/dist/subscription-turn.js +143 -0
  183. package/dist/team-apps.d.ts +24 -0
  184. package/dist/team-apps.js +128 -0
  185. package/dist/tracker-git-credential.d.ts +15 -0
  186. package/dist/tracker-git-credential.js +87 -0
  187. package/native/bin/LICENSE.bubblewrap +502 -0
  188. package/native/bin/LICENSE.libcap +112 -0
  189. package/native/bin/LICENSE.sandbox-runtime +201 -0
  190. package/native/bin/SOURCE.bubblewrap.tar.xz +0 -0
  191. package/native/bin/build.json +4037 -0
  192. package/native/bin/bwrap-build-source/Dockerfile +48 -0
  193. package/native/bin/bwrap-build-source/README.md +96 -0
  194. package/native/bin/bwrap-build-source/build.mjs +52 -0
  195. package/native/bin/bwrap-build-source/linux-arm64.ini +14 -0
  196. package/native/bin/bwrap-build-source/pin.mjs +21 -0
  197. package/native/bin/bwrap-build-source/record.mjs +74 -0
  198. package/native/bin/bwrap-build-source/vendor/LICENSE.sandbox-runtime +201 -0
  199. package/native/bin/bwrap-build-source/vendor/README.md +23 -0
  200. package/native/bin/bwrap-build-source/vendor/seccomp-unix-block.c +280 -0
  201. package/native/bin/bwrap-build.json +44 -0
  202. package/native/bin/fungi-apply-patch +0 -0
  203. package/native/bin/fungi-bwrap +0 -0
  204. package/native/bin/fungi-bwrap.sha256 +1 -0
  205. package/native/bin/fungi-seccomp.bpf +0 -0
  206. package/native/bin/fungi-seccomp.bpf.sha256 +1 -0
  207. package/package.json +161 -3
@@ -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
+ }
@@ -0,0 +1,135 @@
1
+ import type { Accepted, CancelResult } from "@fungi.computer/shiitake";
2
+ import { type PrivateLocalConfigRoot } from "./private-local-config-root.js";
3
+ import type { ServiceLogLifecycle } from "./private-local-service-log.js";
4
+ import type { StopAllResult } from "./private-local-stop-all.js";
5
+ import { type LocalExtensions } from "./local-extensions.js";
6
+ import type { PrivateLocalServiceSelection, PrivateLocalSessionCreation } from "./private-local-service-contract.js";
7
+ import { openPrivateLocalRuntimeHost, type PrivateLocalRuntimeHost } from "./private-local-runtime-host.js";
8
+ import type { LocalUiAttachment } from "./private-local-ui-attachment.js";
9
+ export type LocalServiceRuntime = Pick<PrivateLocalRuntimeHost, "databasePath" | "agentId" | "name" | "getSession" | "effectiveModel" | "setModel" | "setArchived" | "setRequireSandbox" | "sandboxStatus" | "pendingDelegation" | "assertModelReady" | "listSessions" | "createSession" | "deleteSession" | "extensions" | "prepareReload" | "bindSessionPath" | "acceptMail" | "readSettlement" | "idle" | "close">;
10
+ export declare class LocalSessionPathConflict extends Error {
11
+ readonly name = "LocalSessionPathConflict";
12
+ constructor();
13
+ }
14
+ /**
15
+ * A folder holds several Agent stores and the request chose none of them.
16
+ * The service never picks one for the caller; --agent, --db or the
17
+ * landing screen does.
18
+ */
19
+ export declare class LocalAgentSelectionAmbiguous extends Error {
20
+ readonly name = "LocalAgentSelectionAmbiguous";
21
+ readonly agentIds: readonly string[];
22
+ constructor(agentIds: readonly string[]);
23
+ }
24
+ export type OpenLocalServiceRuntime = (
25
+ /** Selected by the service, never by a client selection or Agent Files root. */
26
+ options: Parameters<typeof openPrivateLocalRuntimeHost>[0] & Readonly<{
27
+ configRoot: PrivateLocalConfigRoot;
28
+ }>) => Promise<LocalServiceRuntime>;
29
+ /** One service owns each store, independently of how many clients select it. */
30
+ export declare function createLocalServiceOwners(openRuntime?: OpenLocalServiceRuntime, recoveryDirectory?: string,
31
+ /** The installed-extension owner that decides what each Agent holds. */
32
+ suppliedExtensions?: Pick<LocalExtensions, "assertHeldByAgent" | "enableAgent">,
33
+ /** How often idle Agents are checked; one is released on its second idle check. */
34
+ idleSweepMs?: number,
35
+ /** Read the recovery manifest; tests can hold this I/O independently of opens. */
36
+ readRecoveryManifest?: (path: string) => Promise<string>,
37
+ /** Report only the classification, never the manifest or exception text. */
38
+ onRecoveryDisabled?: ServiceLogLifecycle["recoveryDisabled"], configRoot?: PrivateLocalConfigRoot): {
39
+ refreshMesh: () => Promise<void>;
40
+ createSession: (creation: PrivateLocalSessionCreation) => Promise<{
41
+ agentId: string;
42
+ databasePath: string;
43
+ invocationRoot: string;
44
+ sessionId: string;
45
+ session: Readonly<{
46
+ address: string;
47
+ command: import("@fungi.computer/shiitake").SessionCommandHandler;
48
+ withdraw: (requestId: string) => Promise<import("@fungi.computer/shiitake/client").WithdrawResult>;
49
+ abort: () => Promise<void>;
50
+ send: (text: string, options?: import("@fungi.computer/shiitake").SendOptions) => Promise<Accepted>;
51
+ cancel: (input: Readonly<{
52
+ commandId: string;
53
+ onlyIfPending?: boolean;
54
+ }>) => Promise<CancelResult>;
55
+ latestPending: () => Promise<import("@fungi.computer/shiitake/client").SessionPendingPrompt | null>;
56
+ extension: (extensionId: string) => import("@fungi.computer/shiitake").SessionExtensionControls;
57
+ modelPreference: Readonly<{
58
+ read: () => Promise<import("@fungi.computer/shiitake").ModelPreference | null>;
59
+ set: (preference: import("@fungi.computer/shiitake").ModelPreference | null) => Promise<void>;
60
+ }>;
61
+ read: (input?: import("@fungi.computer/shiitake").ReadOptions) => Promise<import("@fungi.computer/shiitake").SessionSnapshot>;
62
+ subscribe: (input: import("@fungi.computer/shiitake").SubscribeOptions) => AsyncIterable<import("@fungi.computer/shiitake").SessionFrame>;
63
+ watch: (input?: import("@fungi.computer/shiitake").WatchOptions) => Promise<import("@fungi.computer/shiitake").SessionWatch>;
64
+ }>;
65
+ /** End this selection's use; the mounted route reopens the Agent later. */
66
+ release: () => void;
67
+ }>;
68
+ select: (selection: PrivateLocalServiceSelection, createRequestId?: string) => Promise<{
69
+ agentId: string;
70
+ databasePath: string;
71
+ invocationRoot: string;
72
+ sessionId: string;
73
+ session: Readonly<{
74
+ address: string;
75
+ command: import("@fungi.computer/shiitake").SessionCommandHandler;
76
+ withdraw: (requestId: string) => Promise<import("@fungi.computer/shiitake/client").WithdrawResult>;
77
+ abort: () => Promise<void>;
78
+ send: (text: string, options?: import("@fungi.computer/shiitake").SendOptions) => Promise<Accepted>;
79
+ cancel: (input: Readonly<{
80
+ commandId: string;
81
+ onlyIfPending?: boolean;
82
+ }>) => Promise<CancelResult>;
83
+ latestPending: () => Promise<import("@fungi.computer/shiitake/client").SessionPendingPrompt | null>;
84
+ extension: (extensionId: string) => import("@fungi.computer/shiitake").SessionExtensionControls;
85
+ modelPreference: Readonly<{
86
+ read: () => Promise<import("@fungi.computer/shiitake").ModelPreference | null>;
87
+ set: (preference: import("@fungi.computer/shiitake").ModelPreference | null) => Promise<void>;
88
+ }>;
89
+ read: (input?: import("@fungi.computer/shiitake").ReadOptions) => Promise<import("@fungi.computer/shiitake").SessionSnapshot>;
90
+ subscribe: (input: import("@fungi.computer/shiitake").SubscribeOptions) => AsyncIterable<import("@fungi.computer/shiitake").SessionFrame>;
91
+ watch: (input?: import("@fungi.computer/shiitake").WatchOptions) => Promise<import("@fungi.computer/shiitake").SessionWatch>;
92
+ }>;
93
+ /** End this selection's use; the mounted route reopens the Agent later. */
94
+ release: () => void;
95
+ }>;
96
+ serve: (selection: Pick<PrivateLocalServiceSelection, "invocationRoot" | "databasePath" | "fungiMcp">, request: Request, attachment?: LocalUiAttachment) => Promise<Response>;
97
+ effectiveModel: (selection: Pick<PrivateLocalServiceSelection, "invocationRoot" | "databasePath" | "fungiMcp">, sessionId: string, signal: AbortSignal) => Promise<{
98
+ agentName: "Shiitake";
99
+ providerId: string;
100
+ providerName: string;
101
+ modelId: string;
102
+ modelName: string;
103
+ credential: {
104
+ kind: "oauth" | "api_key" | "missing";
105
+ source: string;
106
+ };
107
+ label: string;
108
+ reasoning?: "minimal" | "low" | "medium" | "high" | "xhigh" | "max" | undefined;
109
+ }>;
110
+ sandboxStatus: (selection: Pick<PrivateLocalServiceSelection, "invocationRoot" | "databasePath" | "fungiMcp">, signal: AbortSignal) => Promise<{
111
+ state: "available";
112
+ requireSandbox: boolean;
113
+ } | {
114
+ state: "unavailable";
115
+ requireSandbox: boolean;
116
+ reason: {
117
+ kind: "missing" | "invalid-digest" | "digest-mismatch" | "not-executable" | "unsupported-platform" | "invalid-folder" | "backend-refused";
118
+ message: string;
119
+ };
120
+ }>;
121
+ sweepIdle: () => Promise<void>;
122
+ archive: (request: Readonly<{
123
+ invocationRoot: string;
124
+ agentId: string;
125
+ archived: boolean;
126
+ }>, signal: AbortSignal) => Promise<void>;
127
+ stopAll: (request: Readonly<{
128
+ invocationRoot: string;
129
+ agentId: string;
130
+ }>) => Promise<StopAllResult>;
131
+ restore: () => Promise<void>;
132
+ close: () => Promise<void>;
133
+ reload: (invocationRoot: string, clientPath: string) => Promise<void>;
134
+ unfinishedOwners: () => string[];
135
+ };