@fungi.computer/bonsai 0.1.0 → 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.
package/package.json CHANGED
@@ -1,16 +1,17 @@
1
1
  {
2
2
  "name": "@fungi.computer/bonsai",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "author": "Levi <levi@technomancy.dev>",
5
5
  "type": "module",
6
6
  "description": "Bonsai: a git platform for many agents working at once, on Workers and Artifacts",
7
7
  "dependencies": {
8
- "@fungi.computer/agar": "0.2.0",
9
- "@fungi.computer/caps": "0.1.0",
10
- "@fungi.computer/issues": "0.0.1",
11
- "@fungi.computer/oyster": "0.2.0",
12
- "@fungi.computer/puffball": "0.1.0",
13
- "@fungi.computer/stipe": "0.0.1",
8
+ "@fungi.computer/agar": "0.3.0",
9
+ "@fungi.computer/caps": "0.2.0",
10
+ "@fungi.computer/issues": "0.1.0",
11
+ "@fungi.computer/oyster": "0.3.0",
12
+ "@fungi.computer/puffball": "0.2.0",
13
+ "@fungi.computer/sigils": "0.2.0",
14
+ "@fungi.computer/stipe": "0.1.0",
14
15
  "@pierre/diffs": "1.3.6",
15
16
  "@pierre/trees": "1.0.0-beta.6",
16
17
  "@tanstack/react-query": "5.102.8",
@@ -22,12 +23,16 @@
22
23
  "react": "18.3.1",
23
24
  "react-dom": "18.3.1",
24
25
  "zod": "4.4.3",
25
- "@fungi.computer/watchdog": "0.0.1",
26
+ "@fungi.computer/watchdog": "0.1.0",
26
27
  "effect": "4.0.2",
27
- "@fungi.computer/cairn": "0.0.1",
28
- "@fungi.computer/maosaico": "0.0.1",
28
+ "@fungi.computer/cairn": "0.1.0",
29
+ "@fungi.computer/maosaico": "0.1.0",
29
30
  "@visx/hierarchy": "3.12.0",
30
- "@fungi.computer/gills": "0.1.0"
31
+ "@fungi.computer/gills": "0.2.0",
32
+ "@fungi.computer/nacre": "0.0.1",
33
+ "@fungi.computer/trellis": "0.2.0",
34
+ "@fungi.computer/braid": "0.2.0",
35
+ "@fungi.computer/workflows-wire": "0.2.0"
31
36
  },
32
37
  "devDependencies": {
33
38
  "playwright": "1.62.1",
@@ -43,12 +48,11 @@
43
48
  "vitest": "4.1.11",
44
49
  "wrangler": "4.135.0",
45
50
  "tsx": "4.23.12",
46
- "@fungi.computer/braid": "0.1.0",
47
- "@fungi.computer/gills": "0.1.0",
51
+ "@fungi.computer/gills": "0.2.0",
48
52
  "eslint": "10.9.1",
49
53
  "oxlint": "1.78.0",
50
54
  "jsdom": "29.0.1",
51
- "@fungi.computer/computer": "0.1.0"
55
+ "@fungi.computer/computer-contract": "0.0.1"
52
56
  },
53
57
  "botanical": {
54
58
  "role": "app",
@@ -89,7 +93,9 @@
89
93
  "git.repository",
90
94
  "apps.open",
91
95
  "app.events.emit",
92
- "computer.execute"
96
+ "computer.execute",
97
+ "workflow.run",
98
+ "workflow.publish"
93
99
  ],
94
100
  "receives": [
95
101
  "git.push"
@@ -117,9 +123,21 @@
117
123
  {
118
124
  "name": "APPS",
119
125
  "operations": [
126
+ "register",
127
+ "fork",
120
128
  "build",
121
129
  "buildStatus",
122
- "select"
130
+ "select",
131
+ "repository"
132
+ ]
133
+ },
134
+ {
135
+ "name": "WORKFLOWS",
136
+ "operations": [
137
+ "catalog",
138
+ "runGraph",
139
+ "graphStatus",
140
+ "runs"
123
141
  ]
124
142
  }
125
143
  ]
@@ -132,7 +150,25 @@
132
150
  ],
133
151
  "stylesheets": [
134
152
  "web/bonsai.css"
135
- ]
153
+ ],
154
+ "entry": "web/index.html",
155
+ "maxOutputBytes": 67108864,
156
+ "backend": {
157
+ "entry": "backend/index.ts",
158
+ "exportName": "BonsaiApp",
159
+ "compatibilityDate": "2026-09-04",
160
+ "runtime": {
161
+ "kind": "durable-facet",
162
+ "stateSchema": 1
163
+ }
164
+ },
165
+ "assetBase": "./",
166
+ "assets": {
167
+ "maxManifestBytes": 1048576,
168
+ "maxObjects": 1024,
169
+ "maxObjectBytes": 16777216,
170
+ "maxTotalBytes": 67108864
171
+ }
136
172
  }
137
173
  },
138
174
  "scripts": {
@@ -140,7 +176,7 @@
140
176
  "typecheck": "tsc -p tsconfig.json --noEmit",
141
177
  "lint": "eslint backend web shared test --max-warnings=0 && oxlint --config ../../oxlint.config.ts --deny-warnings backend web shared test",
142
178
  "test": "pnpm run test:unit && pnpm run test:merge",
143
- "test:unit": "vitest run && node --import tsx --test test/seed-resume.test.mjs test/insight-layout.test.mjs test/checks-workflow-template.test.mjs test/merge-template-build.test.mjs test/storyboard-save-template.test.mjs",
179
+ "test:unit": "vitest run && node --import tsx --test test/seed-resume.test.mjs test/insight-layout.test.mjs test/checks-workflow-template.test.mjs test/merge-template-build.test.mjs test/storyboard-save-template.test.mjs test/favicon.test.mjs",
144
180
  "test:merge": "node --import tsx test/git-push.native.mjs",
145
181
  "format:check": "node ../../tooling/repository/scripts/format-package-check.mjs",
146
182
  "lint:anti-slop": "node ../../tooling/repository/scripts/lint-package-anti-slop.mjs",
@@ -9,6 +9,10 @@ import process from "node:process";
9
9
  import { log } from "node:console";
10
10
  import { installRelease, packRelease } from "@fungi.computer/oyster/pack";
11
11
  import { standaloneAppSet } from "@fungi.computer/oyster/standalone/app-set";
12
+ import {
13
+ appBuildRecipe,
14
+ readBuildManifest,
15
+ } from "@fungi.computer/oyster/build";
12
16
 
13
17
  const root = fileURLToPath(new URL("../", import.meta.url));
14
18
  const repository = fileURLToPath(new URL("../../../", import.meta.url));
@@ -22,6 +26,13 @@ const revision = execFileSync("git", ["rev-parse", "HEAD"], {
22
26
  }).trim();
23
27
  const bonsai = standaloneAppSet.find((app) => app.installationId === "bonsai");
24
28
  if (!bonsai) throw new Error("The standalone App set must include Bonsai");
29
+ const manifest = readBuildManifest(
30
+ execFileSync(
31
+ "git",
32
+ ["show", revision + ":" + bonsai.directory + "/package.json"],
33
+ { cwd: repository, encoding: "utf8" },
34
+ ),
35
+ );
25
36
  const stamp = Date.now().toString(36);
26
37
  const outDirectory = `${root}.botanical/release`;
27
38
 
@@ -34,7 +45,7 @@ await packRelease({
34
45
  cwd: repository,
35
46
  encoding: "utf8",
36
47
  }).trim(),
37
- recipe: bonsai.recipe,
48
+ recipe: appBuildRecipe(manifest, bonsai.directory),
38
49
  outDirectory,
39
50
  });
40
51
 
@@ -20,7 +20,7 @@ import * as z from "zod";
20
20
  import { installRelease } from "@fungi.computer/oyster/pack";
21
21
  import { parseSourceRevision } from "@fungi.computer/puffball";
22
22
  import { releaseSchema } from "@fungi.computer/puffball/effect";
23
- import { workbenchDirectorySchema } from "@fungi.computer/oyster/shell/workbench-directory";
23
+ import { workbenchDirectorySchema } from "@fungi.computer/nacre/workbench-directory";
24
24
 
25
25
  const [packedDirectory, expectedRevision, tourtoisDirectory, tourtoisRevision] =
26
26
  z
@@ -227,11 +227,13 @@ try {
227
227
  "The unchanged Shed backend runs a native command",
228
228
  );
229
229
  const result = await command.json();
230
- assert.equal(result.status, "succeeded");
231
- assert.equal(result.output.status, "completed");
232
- assert.equal(result.output.stdout, "standalone-shed-terminal");
233
- assert.equal(result.output.stderr, "");
234
- assert.equal(result.output.exitCode, 0);
230
+ assert.deepEqual(result, {
231
+ stdout: "standalone-shed-terminal",
232
+ stderr: "",
233
+ exitCode: 0,
234
+ stdoutTruncated: false,
235
+ stderrTruncated: false,
236
+ });
235
237
 
236
238
  const directoryResponse = await globalThis.fetch(
237
239
  `${origin}/api/workbench/directory`,
@@ -568,8 +570,8 @@ try {
568
570
  // Tourtois window chrome, not Shed's own light/full prompt, so they
569
571
  // work the same escalated or not.
570
572
  // Port 8099, not 8080: 8080 is computerDaemonPort, computerd's own
571
- // reserved control-plane port (packages/computer/src/
572
- // operation-contract.ts); starting a demo process there throws
573
+ // reserved control-plane port (packages/computer-contract/src/
574
+ // index.ts); starting a demo process there throws
573
575
  // ComputerPortReservedError, confirmed against the real VM.
574
576
  //
575
577
  // Not python3 -m http.server: packages/computer/Dockerfile only
@@ -12,6 +12,15 @@ import { commit } from "@fungi.computer/agar/roles/files";
12
12
 
13
13
  export const productName = "Bonsai";
14
14
 
15
+ /** An explicit owner action starts the same published build/install Workflow. */
16
+ export const appBuildWorkflowInput = z.strictObject({
17
+ repo: repoName,
18
+ sourceRevision: z.string().min(1).max(256),
19
+ installationId: z.string().min(1).max(256),
20
+ requestId: z.string().min(1).max(256),
21
+ });
22
+ export type AppBuildWorkflowInput = z.infer<typeof appBuildWorkflowInput>;
23
+
15
24
  /** Any JSON value: App method inputs and results travel as JSON. */
16
25
  export const jsonValue = z.json();
17
26
  export type JsonValue = z.infer<typeof jsonValue>;
@@ -389,6 +398,22 @@ export const issueFiles = z.strictObject({
389
398
  export type IssueFiles = z.infer<typeof issueFiles>;
390
399
  export const repoPage = z.strictObject({ repos: z.array(repoSummary) });
391
400
 
401
+ /** The host's install decision on this build, not a consent request. */
402
+ const appBuildInstallation = z.discriminatedUnion("kind", [
403
+ z.strictObject({ kind: z.literal("pending"), installationId: z.string() }),
404
+ z.strictObject({ kind: z.literal("installed"), installationId: z.string() }),
405
+ z.strictObject({
406
+ kind: z.literal("needs_consent"),
407
+ installationId: z.string(),
408
+ }),
409
+ z.strictObject({
410
+ kind: z.literal("failed"),
411
+ installationId: z.string(),
412
+ detail: z.string(),
413
+ }),
414
+ ]);
415
+ export type AppBuildInstallation = z.infer<typeof appBuildInstallation>;
416
+
392
417
  /** One App build job as its owner sees it; a settled success carries its Release. */
393
418
  export const appBuildView = z.strictObject({
394
419
  jobId: z.string().min(1).max(256),
@@ -399,6 +424,22 @@ export const appBuildView = z.strictObject({
399
424
  detail: z.string().max(65_536).nullable(),
400
425
  /** The recorded Release, parsed by its owner where it is installed. */
401
426
  release: z.unknown(),
427
+ installation: appBuildInstallation.nullable(),
428
+ });
429
+
430
+ /** Register the calling installation's repository, never a caller-supplied recipe. */
431
+ export const appRegistrationInput = z.strictObject({ repo: repoName });
432
+
433
+ /** Workflows wait for one job; Settings discovers its repository's latest job. */
434
+ export const appBuildStatusInput = z.union([
435
+ z.strictObject({ jobId: z.string().min(1).max(256) }),
436
+ appRegistrationInput,
437
+ ]);
438
+
439
+ /** The host's App identity and exact main commit whose metadata it registered. */
440
+ export const appRegistration = appBuildView.pick({
441
+ appId: true,
442
+ sourceRevision: true,
402
443
  });
403
444
 
404
445
  export const errorBody = z.strictObject({ error: z.string() });