@fungi.computer/oyster 0.0.1 → 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 (195) hide show
  1. package/README.md +228 -176
  2. package/dist/agent-avatars.d.ts +103 -0
  3. package/dist/agent-avatars.js +66 -0
  4. package/dist/agents.d.ts +12 -2
  5. package/dist/agents.js +39 -2
  6. package/dist/app-builds.d.ts +76 -17
  7. package/dist/app-builds.js +207 -63
  8. package/dist/app-sources.d.ts +7 -22
  9. package/dist/app-sources.js +49 -14
  10. package/dist/apps/gate.d.ts +7 -7
  11. package/dist/apps/gate.js +6 -6
  12. package/dist/apps/installation.d.ts +35 -35
  13. package/dist/apps/installation.js +20 -19
  14. package/dist/build/artifact-writer.d.ts +40 -0
  15. package/dist/build/artifact-writer.js +181 -0
  16. package/dist/build/build-jobs.js +7 -1
  17. package/dist/build/build-policy.d.ts +10 -0
  18. package/dist/build/build-policy.js +10 -0
  19. package/dist/build/build-step.d.ts +12 -1
  20. package/dist/build/build-step.js +9 -1
  21. package/dist/build/candidate-builder.d.ts +68 -0
  22. package/dist/build/candidate-builder.js +91 -0
  23. package/dist/build/candidate-cli.d.ts +1 -0
  24. package/dist/build/candidate-cli.js +119 -0
  25. package/dist/build/candidate-cli.mjs +28220 -0
  26. package/dist/build/content-objects.d.ts +37 -0
  27. package/dist/build/content-objects.js +53 -0
  28. package/dist/build/effect.d.ts +18 -0
  29. package/dist/build/effect.js +52 -12
  30. package/dist/build/git-environment.d.ts +3 -0
  31. package/dist/build/git-environment.js +21 -9
  32. package/dist/build/local-build.d.ts +13 -3
  33. package/dist/build/local-build.js +149 -99
  34. package/dist/build/snapshot-package-store.d.ts +10 -0
  35. package/dist/build/snapshot-package-store.js +15 -0
  36. package/dist/build/snapshot-program-scripts.js +1 -1
  37. package/dist/build/snapshot-programs/snapshot-path.d.ts +2 -0
  38. package/dist/build/snapshot-programs/snapshot-path.js +6 -0
  39. package/dist/build/submission-contract.d.ts +461 -17
  40. package/dist/build/submission-contract.js +136 -26
  41. package/dist/build/workspace-build.d.ts +7 -2
  42. package/dist/build/workspace-build.js +55 -11
  43. package/dist/build-contract.d.ts +3 -0
  44. package/dist/build-contract.js +3 -0
  45. package/dist/build-egress.d.ts +62 -0
  46. package/dist/build-egress.js +148 -0
  47. package/dist/build.d.ts +1 -0
  48. package/dist/build.js +1 -0
  49. package/dist/cloudflare.js +4 -4
  50. package/dist/frame-binding-wire-script.js +1 -1
  51. package/dist/frame-binding-wire.d.ts +1 -1
  52. package/dist/frame-binding-wire.js +1 -1
  53. package/dist/git-journal.js +4 -4
  54. package/dist/index.d.ts +1 -0
  55. package/dist/index.js +1 -0
  56. package/dist/installation-consent.d.ts +3 -1
  57. package/dist/installation-consent.js +2 -0
  58. package/dist/mcp-owner.js +20 -8
  59. package/dist/pack.d.ts +6 -3
  60. package/dist/pack.js +28 -11
  61. package/dist/page/gill-observation.d.ts +4 -0
  62. package/dist/page/gill-observation.js +31 -0
  63. package/dist/page/mount.d.ts +4 -8
  64. package/dist/page/window-launch.d.ts +18 -0
  65. package/dist/page/window-launch.js +11 -0
  66. package/dist/page-script.js +4 -4
  67. package/dist/release.d.ts +11 -0
  68. package/dist/release.js +4 -1
  69. package/dist/shell/app-directory.d.ts +50 -45
  70. package/dist/shell/app-directory.js +19 -18
  71. package/dist/shell/shell-module.d.ts +26 -2
  72. package/dist/shell/shell-module.js +51 -2
  73. package/dist/shell/window-manager.d.ts +5 -1
  74. package/dist/shell/window-manager.js +21 -2
  75. package/dist/shell/workbench-directory.d.ts +332 -0
  76. package/dist/shell/workbench-directory.js +35 -0
  77. package/dist/shell/workbench-host-types.d.ts +1 -1
  78. package/dist/shell/workbench-host.js +5 -0
  79. package/dist/shell/workbench-model.d.ts +3 -1
  80. package/dist/source/index.d.ts +6 -7
  81. package/dist/source/index.js +6 -7
  82. package/dist/source/template-push.d.ts +33 -0
  83. package/dist/source/template-push.js +223 -0
  84. package/dist/source/template-repository.d.ts +2 -0
  85. package/dist/source/template-repository.js +13 -0
  86. package/dist/source/{template-write.d.ts → template-seed.d.ts} +19 -20
  87. package/dist/source/template-seed.js +80 -0
  88. package/dist/standalone/agent-directory.d.ts +4 -0
  89. package/dist/standalone/agent-directory.js +4 -0
  90. package/dist/standalone/agents.d.ts +227 -0
  91. package/dist/standalone/agents.js +834 -0
  92. package/dist/standalone/app-builds-binding.d.ts +36 -0
  93. package/dist/standalone/app-builds-binding.js +119 -0
  94. package/dist/standalone/app-set.d.ts +91 -0
  95. package/dist/standalone/app-set.js +395 -0
  96. package/dist/standalone/app-source.d.ts +41 -0
  97. package/dist/standalone/app-source.js +59 -0
  98. package/dist/standalone/builds.d.ts +18 -0
  99. package/dist/standalone/builds.js +101 -0
  100. package/dist/standalone/computer-egress.d.ts +37 -0
  101. package/dist/standalone/computer-egress.js +111 -0
  102. package/dist/standalone/computer.d.ts +122 -0
  103. package/dist/standalone/computer.js +714 -0
  104. package/dist/standalone/install-apps-cli.d.ts +2 -0
  105. package/dist/standalone/install-apps-cli.js +126 -0
  106. package/dist/standalone/instance.d.ts +35 -0
  107. package/dist/standalone/instance.js +74 -0
  108. package/dist/standalone/media.d.ts +76 -0
  109. package/dist/standalone/media.js +227 -0
  110. package/dist/standalone/preview.d.ts +51 -0
  111. package/dist/standalone/preview.js +167 -0
  112. package/dist/standalone/registry.d.ts +102 -0
  113. package/dist/standalone/registry.js +193 -0
  114. package/dist/standalone/tenancy.d.ts +42 -0
  115. package/dist/standalone/tenancy.js +241 -0
  116. package/dist/standalone/worker.d.ts +55 -0
  117. package/dist/standalone/worker.js +147 -0
  118. package/dist/standalone/workflow-authority-readers.d.ts +16 -0
  119. package/dist/standalone/workflow-authority-readers.js +35 -0
  120. package/dist/standalone/workflow-binding.d.ts +216 -0
  121. package/dist/standalone/workflow-binding.js +217 -0
  122. package/dist/standalone/workflow-events.d.ts +46 -0
  123. package/dist/standalone/workflow-events.js +39 -0
  124. package/dist/standalone/workflow-git-capture.d.ts +7 -0
  125. package/dist/standalone/workflow-git-capture.js +62 -0
  126. package/dist/standalone/workflow-host.d.ts +955 -0
  127. package/dist/standalone/workflow-host.js +778 -0
  128. package/dist/standalone/workflow-node-capture.d.ts +13 -0
  129. package/dist/standalone/workflow-node-capture.js +72 -0
  130. package/dist/standalone/workflow-root-authority.d.ts +27 -0
  131. package/dist/standalone/workflow-root-authority.js +87 -0
  132. package/dist/standalone/workflow-schedules.d.ts +52 -0
  133. package/dist/standalone/workflow-schedules.js +40 -0
  134. package/dist/standalone/workflow-trigger-host.d.ts +1716 -0
  135. package/dist/standalone/workflow-trigger-host.js +52 -0
  136. package/dist/standalone/workflows.d.ts +713 -0
  137. package/dist/standalone/workflows.js +554 -0
  138. package/dist/tenancy/auth0.d.ts +64 -0
  139. package/dist/tenancy/auth0.js +198 -0
  140. package/dist/tenancy/cloudflare/rate-limit.d.ts +8 -0
  141. package/dist/tenancy/cloudflare/rate-limit.js +19 -0
  142. package/dist/tenancy/cloudflare/registry.d.ts +50 -0
  143. package/dist/tenancy/cloudflare/registry.js +301 -0
  144. package/dist/tenancy/cloudflare.d.ts +2 -0
  145. package/dist/tenancy/cloudflare.js +2 -0
  146. package/dist/tenancy/cold-directory.d.ts +13 -0
  147. package/dist/tenancy/cold-directory.js +43 -0
  148. package/dist/tenancy/contracts.d.ts +195 -0
  149. package/dist/tenancy/contracts.js +1 -0
  150. package/dist/tenancy/index.d.ts +19 -0
  151. package/dist/tenancy/index.js +156 -0
  152. package/dist/tenancy/owner-key.d.ts +26 -0
  153. package/dist/tenancy/owner-key.js +63 -0
  154. package/dist/tenancy/oyster.d.ts +4 -0
  155. package/dist/tenancy/oyster.js +25 -0
  156. package/dist/tenancy/registry-record.d.ts +7 -0
  157. package/dist/tenancy/registry-record.js +44 -0
  158. package/dist/tenancy/registry.d.ts +27 -0
  159. package/dist/tenancy/registry.js +138 -0
  160. package/dist/tenancy/resolve.d.ts +7 -0
  161. package/dist/tenancy/resolve.js +64 -0
  162. package/dist/workers-git.js +1 -4
  163. package/dist/workers.d.ts +2 -2
  164. package/dist/workers.js +3 -1
  165. package/docs/api/build-contract.md +829 -32
  166. package/docs/api/build.md +253 -17
  167. package/docs/api/modules.md +40 -32
  168. package/docs/api/pack.md +6 -3
  169. package/docs/api/shell/app-directory.md +267 -0
  170. package/docs/api/shell/shell-module.md +64 -3
  171. package/docs/api/shell/workbench-directory.md +119 -0
  172. package/docs/api/shell/workbench.md +19 -0
  173. package/docs/api/shell.md +127 -0
  174. package/docs/api/tenancy/auth0.md +110 -0
  175. package/docs/api/tenancy/cloudflare.md +221 -0
  176. package/docs/api/tenancy/cold-directory.md +46 -0
  177. package/docs/api/tenancy/owner-key.md +63 -0
  178. package/docs/api/tenancy/registry.md +77 -0
  179. package/docs/api/tenancy/resolve.md +69 -0
  180. package/docs/api/tenancy.md +430 -0
  181. package/docs/api/workers-git.md +140 -21
  182. package/docs/api/workers.md +15 -2
  183. package/docs/site/agent-quickstart.mdx +52 -55
  184. package/examples/standalone/worker.ts +7 -14
  185. package/examples/standalone/wrangler.jsonc +67 -6
  186. package/package.json +78 -25
  187. package/dist/build/r2-artifact-writer.d.ts +0 -31
  188. package/dist/build/r2-artifact-writer.js +0 -179
  189. package/dist/source/template-write.js +0 -344
  190. package/docs/media/architecture.mmd +0 -32
  191. package/docs/media/architecture.png +0 -0
  192. package/docs/media/bonsai-network.png +0 -0
  193. package/docs/media/bonsai-repository.png +0 -0
  194. package/examples/git/worker.ts +0 -39
  195. package/examples/git/wrangler.jsonc +0 -32
@@ -1,344 +0,0 @@
1
- var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
2
- if (value !== null && value !== void 0) {
3
- if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
4
- var dispose, inner;
5
- if (async) {
6
- if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
7
- dispose = value[Symbol.asyncDispose];
8
- }
9
- if (dispose === void 0) {
10
- if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
11
- dispose = value[Symbol.dispose];
12
- if (async) inner = dispose;
13
- }
14
- if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
15
- if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
16
- env.stack.push({ value: value, dispose: dispose, async: async });
17
- }
18
- else if (async) {
19
- env.stack.push({ async: true });
20
- }
21
- return value;
22
- };
23
- var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
24
- return function (env) {
25
- function fail(e) {
26
- env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
27
- env.hasError = true;
28
- }
29
- var r, s = 0;
30
- function next() {
31
- while (r = env.stack.pop()) {
32
- try {
33
- if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
34
- if (r.dispose) {
35
- var result = r.dispose.call(r.value);
36
- if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
37
- }
38
- else s |= 1;
39
- }
40
- catch (e) {
41
- fail(e);
42
- }
43
- }
44
- if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
45
- if (env.hasError) throw env.error;
46
- }
47
- return next();
48
- };
49
- })(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
50
- var e = new Error(message);
51
- return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
52
- });
53
- import { memfs } from "memfs";
54
- import { dirname, join } from "node:path";
55
- import * as git from "isomorphic-git";
56
- import * as Schema from "effect/Schema";
57
- import { parseAppId, parseSourceRevision } from "@fungi.computer/puffball";
58
- import { appIdSchema, sha256DigestSchema, sourceRevisionSchema, } from "@fungi.computer/puffball/effect";
59
- import { capturedPinnedRecipeSchema, digestPinnedRecipe, } from "../build-contract.js";
60
- import { templateRepositoryForApp } from "./template-repository.js";
61
- function logEvent(operation, cause) {
62
- console.error(JSON.stringify({
63
- source: "app-publisher",
64
- operation,
65
- failureKind: cause instanceof Error ? "Error" : "NonErrorThrown",
66
- }));
67
- }
68
- class TemplateRequestTooLarge extends Error {
69
- }
70
- /** A bounded operator source upload; decoding happens only at the Publisher boundary. */
71
- export const TEMPLATE_WRITE_MAX_REQUEST_BYTES = 24 * 1024 * 1024;
72
- const templatePathSchema = Schema.String.pipe(Schema.check(Schema.makeFilter((path) => path.length > 0 &&
73
- path.length <= 4096 &&
74
- !path.includes("\\") &&
75
- !path.includes("\0") &&
76
- path
77
- .split("/")
78
- .every((part) => part !== "" &&
79
- part !== "." &&
80
- part !== ".." &&
81
- part.toLowerCase() !== ".git"))));
82
- export const templateWriteInputSchema = Schema.Struct({
83
- appId: appIdSchema,
84
- sourceRevision: sourceRevisionSchema,
85
- sourceTreeDigest: sha256DigestSchema,
86
- recipe: capturedPinnedRecipeSchema,
87
- files: Schema.Array(Schema.Struct({
88
- path: templatePathSchema,
89
- contents: Schema.Uint8ArrayFromBase64,
90
- })).pipe(Schema.check(Schema.makeFilter((files) => files.length > 0 && files.length <= 10_000))),
91
- });
92
- /** Isomorphic Git owns the protocol; the existing Artifacts owner owns every
93
- * credential and revokes it when the response stream closes. */
94
- function templateHttp(transport, repository, signal) {
95
- const readers = new Set();
96
- const close = async (reader) => {
97
- if (!readers.delete(reader))
98
- return;
99
- try {
100
- await reader.cancel();
101
- }
102
- finally {
103
- reader.releaseLock();
104
- }
105
- };
106
- return {
107
- async [Symbol.asyncDispose]() {
108
- const results = await Promise.allSettled([...readers].map(close));
109
- if (results.some((result) => result.status === "rejected"))
110
- throw new Error("Template Git response cleanup failed");
111
- },
112
- async request(input) {
113
- signal.throwIfAborted();
114
- const chunks = input.body;
115
- const iterator = chunks === undefined
116
- ? undefined
117
- : (async function* () {
118
- yield* chunks;
119
- })();
120
- const body = iterator === undefined
121
- ? null
122
- : new ReadableStream({
123
- async pull(controller) {
124
- const item = await iterator.next();
125
- if (item.done)
126
- controller.close();
127
- else
128
- controller.enqueue(item.value);
129
- },
130
- async cancel() {
131
- await iterator.return(undefined);
132
- },
133
- });
134
- const init = {
135
- method: input.method ?? "GET",
136
- headers: new Headers(input.headers),
137
- body,
138
- signal,
139
- };
140
- if (body !== null)
141
- Object.assign(init, { duplex: "half" });
142
- const response = await transport.exchangeTemplateGit(repository, new Request(input.url, init));
143
- // Own the reader before handing the iterable to Git, including when the
144
- // client never starts iteration or abandons it without calling return().
145
- const reader = response.body?.getReader();
146
- if (reader !== undefined)
147
- readers.add(reader);
148
- async function* responseChunks() {
149
- if (reader === undefined)
150
- return;
151
- try {
152
- for (;;) {
153
- signal.throwIfAborted();
154
- const item = await reader.read();
155
- if (item.done)
156
- return;
157
- yield item.value;
158
- }
159
- }
160
- finally {
161
- await close(reader);
162
- }
163
- }
164
- return {
165
- url: input.url,
166
- method: input.method,
167
- statusCode: response.status,
168
- statusMessage: response.statusText,
169
- headers: Object.fromEntries(response.headers),
170
- body: responseChunks(),
171
- };
172
- },
173
- };
174
- }
175
- /** Each request owns an in-memory Git working tree. Uploaded source never
176
- * executes here and callers supply no provider token; the maintained Git client
177
- * writes and compares trees. */
178
- async function writeTemplate(transport, input, repository, signal) {
179
- const env_1 = { stack: [], error: void 0, hasError: false };
180
- try {
181
- const { fs } = memfs();
182
- const dir = "/template";
183
- await git.init({ fs, dir, defaultBranch: "main" });
184
- const paths = new Set();
185
- for (const file of input.files) {
186
- signal.throwIfAborted();
187
- if (paths.has(file.path))
188
- throw new Error("Duplicate template source path");
189
- paths.add(file.path);
190
- const target = join(dir, file.path);
191
- await fs.promises.mkdir(dirname(target), { recursive: true });
192
- await fs.promises.writeFile(target, file.contents);
193
- }
194
- await git.add({ fs, dir, filepath: [...paths], force: true });
195
- const oid = await git.commit({
196
- fs,
197
- dir,
198
- author: {
199
- name: "Botanical App Source",
200
- email: "app-source@botanical.invalid",
201
- timestamp: 0,
202
- timezoneOffset: 0,
203
- },
204
- message: `Seed ${input.appId} from ${input.sourceRevision}`,
205
- });
206
- const http = __addDisposableResource(env_1, templateHttp(transport, repository, signal), true);
207
- const url = `https://git.team.internal/${repository}.git`;
208
- await git.addRemote({ fs, dir, remote: "origin", url });
209
- const refs = await git.listServerRefs({
210
- http,
211
- url,
212
- prefix: "refs/heads/main",
213
- });
214
- const main = refs.find((ref) => ref.ref === "refs/heads/main");
215
- if (main !== undefined) {
216
- await git.fetch({
217
- fs,
218
- http,
219
- dir,
220
- url,
221
- ref: "main",
222
- singleBranch: true,
223
- depth: 1,
224
- tags: false,
225
- });
226
- const expected = await git.readCommit({ fs, dir, oid });
227
- const actual = await git.readCommit({ fs, dir, oid: main.oid });
228
- if (expected.commit.tree !== actual.commit.tree)
229
- return null;
230
- }
231
- if (main === undefined) {
232
- // isomorphic-git's pack writer sends whole objects, preserving Artifacts
233
- // native forks' requirement that seed packs contain no delta objects.
234
- const pushed = await git.push({
235
- fs,
236
- http,
237
- dir,
238
- url,
239
- ref: "main",
240
- remoteRef: "main",
241
- signal,
242
- });
243
- if (!pushed.ok)
244
- throw new Error("Template Git push refused");
245
- }
246
- // A successful push or matching fetched tree is not sufficient: retain the
247
- // former Publisher receipt check that main still names this exact commit.
248
- const expectedHead = main?.oid ?? oid;
249
- const confirmed = await git.listServerRefs({
250
- http,
251
- url,
252
- prefix: "refs/heads/main",
253
- });
254
- return confirmed.find((ref) => ref.ref === "refs/heads/main")?.oid ===
255
- expectedHead
256
- ? expectedHead
257
- : null;
258
- }
259
- catch (e_1) {
260
- env_1.error = e_1;
261
- env_1.hasError = true;
262
- }
263
- finally {
264
- const result_1 = __disposeResources(env_1);
265
- if (result_1)
266
- await result_1;
267
- }
268
- }
269
- /** The only operator template-write result contains provenance, never custody. */
270
- export async function seedPublisherTemplate(receipts, transport, rawAppId, request) {
271
- try {
272
- const appId = parseAppId(rawAppId);
273
- const length = Number(request.headers.get("content-length") ?? "0");
274
- if (!Number.isSafeInteger(length) ||
275
- length < 0 ||
276
- length > TEMPLATE_WRITE_MAX_REQUEST_BYTES)
277
- return { kind: "too-large" };
278
- const signal = AbortSignal.any([
279
- request.signal,
280
- AbortSignal.timeout(240_000),
281
- ]);
282
- let bytes = 0;
283
- const bounded = request.body?.pipeThrough(new TransformStream({
284
- transform(chunk, controller) {
285
- bytes += chunk.byteLength;
286
- if (bytes > TEMPLATE_WRITE_MAX_REQUEST_BYTES)
287
- throw new TemplateRequestTooLarge();
288
- controller.enqueue(chunk);
289
- },
290
- }), { signal });
291
- let input;
292
- try {
293
- const body = await new Response(bounded).json();
294
- input = Schema.decodeUnknownSync(templateWriteInputSchema, {
295
- onExcessProperty: "error",
296
- })(body);
297
- }
298
- catch (cause) {
299
- logEvent("operator.template.decode", cause);
300
- return {
301
- kind: cause instanceof TemplateRequestTooLarge ? "too-large" : "invalid",
302
- };
303
- }
304
- if (input.appId !== appId)
305
- return { kind: "conflict" };
306
- const repository = templateRepositoryForApp(appId);
307
- await transport.ensureRepository(repository);
308
- const oid = await writeTemplate(transport, input, repository, signal);
309
- if (oid === null)
310
- return { kind: "conflict" };
311
- const seedRevision = parseSourceRevision(`git:${oid}`);
312
- const receipt = {
313
- appId,
314
- sourceRevision: input.sourceRevision,
315
- sourceTreeDigest: input.sourceTreeDigest,
316
- seedRevision,
317
- recipe: input.recipe,
318
- buildRecipeDigest: digestPinnedRecipe(input.recipe),
319
- };
320
- const existing = await receipts.read(appId, seedRevision);
321
- if (existing !== null &&
322
- (existing.sourceRevision !== receipt.sourceRevision ||
323
- existing.sourceTreeDigest !== receipt.sourceTreeDigest ||
324
- existing.buildRecipeDigest !== receipt.buildRecipeDigest))
325
- return { kind: "conflict" };
326
- // Recording still uses the write-once, digest-checked Publisher receipt owner.
327
- await receipts.record(receipt);
328
- return {
329
- kind: existing === null ? "recorded" : "existing",
330
- receipt: {
331
- appId,
332
- repository,
333
- sourceRevision: receipt.sourceRevision,
334
- sourceTreeDigest: receipt.sourceTreeDigest,
335
- seedRevision,
336
- buildRecipeDigest: receipt.buildRecipeDigest,
337
- },
338
- };
339
- }
340
- catch (cause) {
341
- logEvent("operator.template.write", cause);
342
- return { kind: "unavailable" };
343
- }
344
- }
@@ -1,32 +0,0 @@
1
- flowchart LR
2
- people["Browsers<br/>git clients<br/>MCP agents"]
3
-
4
- subgraph oyster["Oyster Worker · Cloudflare Workers or celld"]
5
- direction TB
6
- router["Router<br/>/apps · /api · /git · /mcp"]
7
- home["Tourtois home<br/>launcher · windows · settings"]
8
- registry[("OysterRegistry DO<br/>installations")]
9
- instance["App Instance DO<br/>one per installation"]
10
- facet["App backend<br/>Worker Loader facet<br/>with its own SQLite"]
11
- door["git door<br/>per-agent keys"]
12
- router --> home
13
- router --> registry
14
- router --> instance --> facet
15
- router --> door
16
- end
17
-
18
- apps["Apps as immutable Releases<br/>Bonsai · Workflows · Shed<br/>Inkcap · Grove · Prints"]
19
-
20
- subgraph services["Bindings the host provides"]
21
- direction TB
22
- r2[("R2<br/>Release artifacts")]
23
- artifacts[("Artifacts<br/>git repositories")]
24
- platform["Braid Workflows · Computers<br/>Agents · Workers AI"]
25
- end
26
-
27
- people --> router
28
- home -. "UI in sandboxed frames" .-> apps
29
- registry -- "Release refs" --> r2
30
- door --> artifacts
31
- facet -- "declared only" --> platform
32
- facet -- "GIT binding" --> artifacts
Binary file
Binary file
Binary file
@@ -1,39 +0,0 @@
1
- // Add Git to an Oyster Worker. `host.git` is the whole seam: `createOyster`
2
- // mounts the git door at `/git/<installation>/<repo>.git`, and every clone,
3
- // fetch and push passes host authentication, live installation admission and
4
- // the App's own push policy before Artifacts sees a byte.
5
- //
6
- // One root composes every tenant host. HTTP, MCP and background wakes all reach
7
- // it through `root.hostFor`, so they share one auth, one workspace and one
8
- // capability set.
9
- import type { TenantScope } from "@fungi.computer/oyster/tenant";
10
- import {
11
- createOysterGitMcpOwner,
12
- createOysterGitWorker,
13
- OysterGitInstance,
14
- oysterGitRoot,
15
- ownerOrKeyTenancy,
16
- type OysterGitWorkerEnv,
17
- } from "@fungi.computer/oyster/workers-git";
18
-
19
- export { OysterRegistry } from "@fungi.computer/oyster/workers";
20
- // The one binding entrypoint, whose table also hands Apps `env.GIT` and `env.EVENTS`.
21
- export {
22
- OysterBinding,
23
- OysterKeys,
24
- OysterWebhooks,
25
- } from "@fungi.computer/oyster/workers-git";
26
-
27
- // The owner key, or a named key minted at POST /api/keys, signs `git` in.
28
- const root = oysterGitRoot<OysterGitWorkerEnv>({ tenancy: ownerOrKeyTenancy });
29
-
30
- export class OysterMcp extends createOysterGitMcpOwner(root) {}
31
-
32
- /** Instances that hand Apps `env.GIT` and `env.EVENTS`; wakes use the root's host. */
33
- export class OysterInstance extends OysterGitInstance {
34
- protected hostFor(scope: TenantScope) {
35
- return root.hostFor(this.env, scope);
36
- }
37
- }
38
-
39
- export default createOysterGitWorker(root);
@@ -1,32 +0,0 @@
1
- {
2
- "$schema": "../../../../node_modules/wrangler/config-schema.json",
3
- "name": "oyster-git",
4
- "main": "worker.ts",
5
- "compatibility_date": "2026-09-04",
6
- "compatibility_flags": ["nodejs_compat"],
7
- "vars": { "OYSTER_ORIGIN": "https://oyster.example" },
8
- "worker_loaders": [{ "binding": "LOADER" }],
9
- "r2_buckets": [{ "binding": "RELEASES", "bucket_name": "oyster-releases" }],
10
- "artifacts": [{ "binding": "ARTIFACTS", "namespace": "oyster" }],
11
- "durable_objects": {
12
- "bindings": [
13
- { "name": "MCP", "class_name": "OysterMcp" },
14
- { "name": "REGISTRY", "class_name": "OysterRegistry" },
15
- { "name": "INSTANCES", "class_name": "OysterInstance" },
16
- { "name": "KEYS", "class_name": "OysterKeys" },
17
- { "name": "WEBHOOKS", "class_name": "OysterWebhooks" },
18
- ],
19
- },
20
- "migrations": [
21
- {
22
- "tag": "v1",
23
- "new_sqlite_classes": [
24
- "OysterMcp",
25
- "OysterRegistry",
26
- "OysterInstance",
27
- "OysterKeys",
28
- "OysterWebhooks",
29
- ],
30
- },
31
- ],
32
- }