@fungi.computer/computer 0.2.2 → 0.3.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/dist/apply-patch/build.mjs +2 -0
- package/dist/apply-patch/cache.mjs +3 -3
- package/dist/apply-patch/compile.mjs +6 -1
- package/dist/apply-patch/main.rs +14 -0
- package/dist/apply-patch/toolchain.mjs +23 -3
- package/dist/fleet/wire.d.ts +6 -6
- package/dist/index.d.ts +10 -6
- package/package.json +9 -5
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
// container behind. Any other host builds its own target natively through
|
|
11
11
|
// rustup. One immutable artifact per pin, wrapper and target is cached under
|
|
12
12
|
// ${XDG_CACHE_HOME:-~/.cache}/fungi/native-patch and restored on later calls.
|
|
13
|
+
// Turbo's strict environment lends only tool homes, so under Turbo the cache
|
|
14
|
+
// follows HOME; a caller that wants a private cache sets a private HOME.
|
|
13
15
|
import { spawn } from "node:child_process";
|
|
14
16
|
import { homedir } from "node:os";
|
|
15
17
|
import { resolve } from "node:path";
|
|
@@ -50,7 +50,7 @@ async function digest(path) {
|
|
|
50
50
|
.digest("hex");
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
/** One immutable artifact per Codex pin/target, shared by every checkout and updater. */
|
|
53
|
+
/** One immutable artifact per Codex pin/target/wrapper, shared by every checkout and updater. */
|
|
54
54
|
export async function ensureNativePatchArtifact({
|
|
55
55
|
cacheRoot,
|
|
56
56
|
pin: inputPin,
|
|
@@ -62,7 +62,7 @@ export async function ensureNativePatchArtifact({
|
|
|
62
62
|
const pin = pinSchema.parse(inputPin);
|
|
63
63
|
const target = targetSchema.parse(inputTarget);
|
|
64
64
|
const wrapperSha256 = await digest(wrapper);
|
|
65
|
-
const key = join(cacheRoot, pin.version, target);
|
|
65
|
+
const key = join(cacheRoot, pin.version, target, wrapperSha256);
|
|
66
66
|
const artifact = join(key, "artifact");
|
|
67
67
|
await mkdir(key, { recursive: true, mode: 0o700 });
|
|
68
68
|
async function published() {
|
|
@@ -82,7 +82,7 @@ export async function ensureNativePatchArtifact({
|
|
|
82
82
|
receipt.wrapperSha256 !== wrapperSha256
|
|
83
83
|
)
|
|
84
84
|
throw new Error(
|
|
85
|
-
`Cached patch artifact does not match this pin or wrapper: ${artifact}.
|
|
85
|
+
`Cached patch artifact does not match this pin or wrapper: ${artifact}. The artifact was not used or rebuilt.`,
|
|
86
86
|
);
|
|
87
87
|
if (
|
|
88
88
|
(await digest(join(artifact, "fungi-apply-patch"))) !==
|
|
@@ -114,7 +114,11 @@ const nativePathFlags = [
|
|
|
114
114
|
.map((flag) => JSON.stringify(flag))
|
|
115
115
|
.join(" ");
|
|
116
116
|
ensureNativeHostToolchain({ toolchain: codexPatchPin.rustToolchain });
|
|
117
|
-
const {
|
|
117
|
+
const {
|
|
118
|
+
command: cargoCommand,
|
|
119
|
+
args: cargoArgs,
|
|
120
|
+
env: cargoEnv,
|
|
121
|
+
} = selectCargoInvocation({
|
|
118
122
|
toolchain: codexPatchPin.rustToolchain,
|
|
119
123
|
cargoArgs: [
|
|
120
124
|
crossMac ? "zigbuild" : "build",
|
|
@@ -139,6 +143,7 @@ const cargo = spawnSync(cargoCommand, cargoArgs, {
|
|
|
139
143
|
maxBuffer: 64 * 1024 * 1024,
|
|
140
144
|
env: {
|
|
141
145
|
...process.env,
|
|
146
|
+
...cargoEnv,
|
|
142
147
|
CARGO_TARGET_DIR: resolve(scratch, "target"),
|
|
143
148
|
CARGO_ENCODED_RUSTFLAGS: [
|
|
144
149
|
`--remap-path-prefix=${scratch}=/build`,
|
package/dist/apply-patch/main.rs
CHANGED
|
@@ -242,6 +242,20 @@ async fn run() -> Result<(), Box<dyn std::error::Error>> {
|
|
|
242
242
|
}
|
|
243
243
|
}
|
|
244
244
|
}
|
|
245
|
+
// Inspection uses the same upstream parser and admission as application.
|
|
246
|
+
// The host uses these NUL-delimited paths to enforce protected mounts
|
|
247
|
+
// before offering an approval and again immediately before dispatch.
|
|
248
|
+
if std::env::args().nth(1).as_deref() == Some("--inspect") {
|
|
249
|
+
use std::io::Write;
|
|
250
|
+
let mut output = io::stdout().lock();
|
|
251
|
+
let mut paths: Vec<_> = paths.into_iter().collect();
|
|
252
|
+
paths.sort();
|
|
253
|
+
for path in paths {
|
|
254
|
+
output.write_all(path.as_os_str().as_encoded_bytes())?;
|
|
255
|
+
output.write_all(&[0])?;
|
|
256
|
+
}
|
|
257
|
+
return Ok(());
|
|
258
|
+
}
|
|
245
259
|
let cwd = PathUri::from_abs_path(&AbsolutePathBuf::try_from(PathBuf::from(&root))?);
|
|
246
260
|
let mode = ApplyPatchFileUpdateMode::PreserveLineEndings;
|
|
247
261
|
let diagnostic_hunks = parsed.hunks.clone();
|
|
@@ -4,16 +4,36 @@
|
|
|
4
4
|
// image's builder stage) installs Rust through rustup. A non-rustup `cargo`
|
|
5
5
|
// earlier on `PATH` (for example Homebrew's) rejects the `+toolchain`
|
|
6
6
|
// directive, so the build asks rustup's ordinary interface for the pinned
|
|
7
|
-
// toolchain's `cargo` explicitly.
|
|
7
|
+
// toolchain's `cargo` explicitly. Cargo itself still resolves `rustc` from
|
|
8
|
+
// `PATH`, so a Homebrew `rustc` listed first would compile with the wrong
|
|
9
|
+
// compiler; the invocation pins `RUSTC` to the toolchain's own compiler too.
|
|
8
10
|
import { spawnSync } from "node:child_process";
|
|
9
11
|
|
|
10
12
|
/**
|
|
11
|
-
* Builds the `{ command, args }` cargo invocation for the pinned
|
|
13
|
+
* Builds the `{ command, args, env }` cargo invocation for the pinned
|
|
14
|
+
* toolchain. `env` carries `RUSTC` and must be merged into the child's
|
|
15
|
+
* environment.
|
|
12
16
|
*
|
|
13
17
|
* @param {{ toolchain: string, cargoArgs: string[] }} options
|
|
14
18
|
*/
|
|
15
19
|
export function selectCargoInvocation({ toolchain, cargoArgs }) {
|
|
16
|
-
|
|
20
|
+
const which = spawnSync(
|
|
21
|
+
"rustup",
|
|
22
|
+
["which", "--toolchain", toolchain, "rustc"],
|
|
23
|
+
{
|
|
24
|
+
encoding: "utf8",
|
|
25
|
+
},
|
|
26
|
+
);
|
|
27
|
+
if (which.error) throw which.error;
|
|
28
|
+
if (which.status !== 0)
|
|
29
|
+
throw new Error(
|
|
30
|
+
`rustup could not locate the Rust ${toolchain} toolchain's rustc: ${which.stderr.trim()}`,
|
|
31
|
+
);
|
|
32
|
+
return {
|
|
33
|
+
command: "rustup",
|
|
34
|
+
args: ["run", toolchain, "cargo", ...cargoArgs],
|
|
35
|
+
env: { RUSTC: which.stdout.trim() },
|
|
36
|
+
};
|
|
17
37
|
}
|
|
18
38
|
|
|
19
39
|
/**
|
package/dist/fleet/wire.d.ts
CHANGED
|
@@ -8,9 +8,6 @@ export declare const computerActionSchema: z.ZodEnum<{
|
|
|
8
8
|
mkdir: "mkdir";
|
|
9
9
|
backing: "backing";
|
|
10
10
|
bash: "bash";
|
|
11
|
-
exposePort: "exposePort";
|
|
12
|
-
listPorts: "listPorts";
|
|
13
|
-
unexposePort: "unexposePort";
|
|
14
11
|
"files.read": "files.read";
|
|
15
12
|
"files.readBytes": "files.readBytes";
|
|
16
13
|
"files.write": "files.write";
|
|
@@ -25,6 +22,9 @@ export declare const computerActionSchema: z.ZodEnum<{
|
|
|
25
22
|
processStart: "processStart";
|
|
26
23
|
processList: "processList";
|
|
27
24
|
processKill: "processKill";
|
|
25
|
+
exposePort: "exposePort";
|
|
26
|
+
unexposePort: "unexposePort";
|
|
27
|
+
listPorts: "listPorts";
|
|
28
28
|
}>;
|
|
29
29
|
export type ComputerAction = z.output<typeof computerActionSchema>;
|
|
30
30
|
/** Opaque host identities; the fleet does not derive authority from their text. */
|
|
@@ -43,9 +43,6 @@ export declare const computerGrantSchema: z.ZodObject<{
|
|
|
43
43
|
mkdir: "mkdir";
|
|
44
44
|
backing: "backing";
|
|
45
45
|
bash: "bash";
|
|
46
|
-
exposePort: "exposePort";
|
|
47
|
-
listPorts: "listPorts";
|
|
48
|
-
unexposePort: "unexposePort";
|
|
49
46
|
"files.read": "files.read";
|
|
50
47
|
"files.readBytes": "files.readBytes";
|
|
51
48
|
"files.write": "files.write";
|
|
@@ -60,6 +57,9 @@ export declare const computerGrantSchema: z.ZodObject<{
|
|
|
60
57
|
processStart: "processStart";
|
|
61
58
|
processList: "processList";
|
|
62
59
|
processKill: "processKill";
|
|
60
|
+
exposePort: "exposePort";
|
|
61
|
+
unexposePort: "unexposePort";
|
|
62
|
+
listPorts: "listPorts";
|
|
63
63
|
}>>>;
|
|
64
64
|
expiresAt: z.ZodNumber;
|
|
65
65
|
egress: z.ZodOptional<z.ZodJSONSchema>;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { createLocalBackendReplayStore } from "./local-backend-replay.js";
|
|
2
|
-
import { Workspace, WorkspaceProxy, WorkspaceServiceProxy, type
|
|
2
|
+
import { Workspace, WorkspaceProxy, WorkspaceServiceProxy, type WorkspaceStub } from "@fungi.computer/cloudflare-computer";
|
|
3
3
|
import { type WorkerShellBackendOptions } from "@fungi.computer/cloudflare-computer/backends/worker-shell";
|
|
4
4
|
import { type IWorkspaceContainerAPI } from "@fungi.computer/cloudflare-computer/backends/container";
|
|
5
5
|
import { DurableObject } from "cloudflare:workers";
|
|
@@ -10,8 +10,13 @@ import { createWorkspaceFilesPort } from "./files.js";
|
|
|
10
10
|
import { OnBoxVmContainerHost, type OnBoxVmEnv, type OnBoxVmPlacement } from "./on-box-vm.js";
|
|
11
11
|
import { type AttachedBackend, type AttachedBackendView, type BackendNeed, type BackendRoute, type ContainerRuntimeStart, type HostedBacking } from "./computer-backends.js";
|
|
12
12
|
import { LocalBackendConnections } from "./local-backend.js";
|
|
13
|
+
/** Files needs only the native Workspace lease and its atomic replacement door. */
|
|
14
|
+
export type ComputerFilesRpc = Readonly<{
|
|
15
|
+
__getWorkspaceStub(): Promise<WorkspaceStub>;
|
|
16
|
+
replaceFileIfUnchanged(input: ComputerFileReplacement): Promise<ComputerFileReplacementResult>;
|
|
17
|
+
}>;
|
|
13
18
|
/** The exact RPC surface of one Computer Durable Object. */
|
|
14
|
-
export type ComputerRpc =
|
|
19
|
+
export type ComputerRpc = ComputerFilesRpc & Readonly<{
|
|
15
20
|
getCapabilities: ComputerDO["getCapabilities"];
|
|
16
21
|
call: (capabilityId: ComputerValue, input: ComputerValue) => Promise<ComputerValue>;
|
|
17
22
|
readFile: (input: ComputerFileReadInput) => Promise<ReadableStream<Uint8Array>>;
|
|
@@ -31,7 +36,6 @@ export type ComputerRpc = WorkspaceStubHost & Readonly<{
|
|
|
31
36
|
port: number;
|
|
32
37
|
removed: boolean;
|
|
33
38
|
}>;
|
|
34
|
-
replaceFileIfUnchanged: (input: ComputerFileReplacement) => Promise<ComputerFileReplacementResult>;
|
|
35
39
|
}>;
|
|
36
40
|
/** The Cloudflare binding projection needed to select one named Computer. */
|
|
37
41
|
export type ComputerNamespace = Readonly<{
|
|
@@ -120,7 +124,7 @@ declare class ContainerComputer extends ContainerComputerBase {
|
|
|
120
124
|
*/
|
|
121
125
|
protected readyWorkspace(): Promise<Workspace>;
|
|
122
126
|
/** `getWorkspace(stub)` reaches the current generation through this door. */
|
|
123
|
-
__getWorkspaceStub(): Promise<
|
|
127
|
+
__getWorkspaceStub(): Promise<WorkspaceStub>;
|
|
124
128
|
/**
|
|
125
129
|
* Backend doors. An attached machine dials in on its public connect path.
|
|
126
130
|
* A container backend's `/ws` upgrade and egress: the platform container's
|
|
@@ -130,7 +134,7 @@ declare class ContainerComputer extends ContainerComputerBase {
|
|
|
130
134
|
fetch(request: Request): Promise<Response>;
|
|
131
135
|
}
|
|
132
136
|
/** One upstream Cloudflare Workspace that advertises and runs its capabilities. */
|
|
133
|
-
export declare class ComputerDO extends ContainerComputer {
|
|
137
|
+
export declare class ComputerDO extends ContainerComputer implements ComputerFilesRpc {
|
|
134
138
|
#private;
|
|
135
139
|
constructor(ctx: DurableObjectState, env: ComputerEnv);
|
|
136
140
|
/** Host-admitted settings write; egress reads the current durable value. */
|
|
@@ -294,7 +298,7 @@ export { computerContainerSleepAfterMs } from "./container-policy.js";
|
|
|
294
298
|
export * from "./computer-backends.js";
|
|
295
299
|
export { LocalBackendOfflineError, localBackendAudience, localBackendDialPath, verifyLocalBackendDial, } from "./local-backend.js";
|
|
296
300
|
/** Keep each native Workspace lease inside the operation that uses it. */
|
|
297
|
-
export declare function createComputerFilesPort(computer:
|
|
301
|
+
export declare function createComputerFilesPort(computer: ComputerFilesRpc | Rpc.Provider<ComputerFilesRpc>): FilesPort;
|
|
298
302
|
export { createWorkspaceFilesPort, type WorkspaceFilesOwner } from "./files.js";
|
|
299
303
|
export { ComputerOperationConflictError, ComputerOperationLimitError, ComputerRequestInvalidError, } from "./operation-record.js";
|
|
300
304
|
export type { ContainerComputer };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fungi.computer/computer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"author": "Levi <levi@technomancy.dev>",
|
|
5
5
|
"description": "Cloudflare Computer host for one durable Fungi Computer",
|
|
6
6
|
"type": "module",
|
|
@@ -35,6 +35,10 @@
|
|
|
35
35
|
"types": "./dist/fleet/wire.d.ts",
|
|
36
36
|
"import": "./dist/fleet/wire.js"
|
|
37
37
|
},
|
|
38
|
+
"./fleet/inventory-wire": {
|
|
39
|
+
"types": "./dist/fleet/inventory-wire.d.ts",
|
|
40
|
+
"import": "./dist/fleet/inventory-wire.js"
|
|
41
|
+
},
|
|
38
42
|
"./fleet": {
|
|
39
43
|
"types": "./dist/fleet/index.d.ts",
|
|
40
44
|
"import": "./dist/fleet/index.js"
|
|
@@ -55,11 +59,11 @@
|
|
|
55
59
|
"@fungi.computer/cairn": "0.1.0",
|
|
56
60
|
"@fungi.computer/capnweb": "0.12.0",
|
|
57
61
|
"@fungi.computer/cloudflare-computer": "0.2.1-fungi.2",
|
|
58
|
-
"@fungi.computer/cordyceps": "0.
|
|
59
|
-
"@fungi.computer/knapsack": "0.
|
|
60
|
-
"@fungi.computer/seam": "0.
|
|
62
|
+
"@fungi.computer/cordyceps": "0.4.0",
|
|
63
|
+
"@fungi.computer/knapsack": "0.3.0",
|
|
64
|
+
"@fungi.computer/seam": "0.2.0",
|
|
61
65
|
"@fungi.computer/watchdog": "0.1.0",
|
|
62
|
-
"@fungi.computer/computer-contract": "0.0.
|
|
66
|
+
"@fungi.computer/computer-contract": "0.0.3",
|
|
63
67
|
"effect": "4.0.2",
|
|
64
68
|
"just-bash": "3.4.2",
|
|
65
69
|
"zod": "4.4.3"
|