@fungi.computer/mycelium 0.2.3 → 0.3.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.
- package/README.md +17 -12
- package/dist/effect.d.ts +1 -0
- package/dist/effect.js +1 -0
- package/dist/execute-tool.d.ts +2 -0
- package/dist/execute-tool.js +4 -1
- package/dist/index.d.ts +3 -3
- package/dist/internal/execution-lifecycle.js +3 -2
- package/dist/output-collector.js +89 -27
- package/dist/runtime.js +11 -7
- package/dist/sandbox-admission.js +1 -1
- package/docs/api/effect.md +11 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -10,9 +10,10 @@ when the run ends. You can also execute a known operation without a model.
|
|
|
10
10
|
npm install @fungi.computer/mycelium
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
The package ships ESM only
|
|
14
|
-
[Cairn](../cairn/README.md),
|
|
15
|
-
[
|
|
13
|
+
The package ships ESM only. Runtime dependencies include Zod, Effect, `acorn`,
|
|
14
|
+
Cloudflare Code Mode, the MCP server SDK, [Cairn](../cairn/README.md),
|
|
15
|
+
[Forage](../forage/README.md), [Mule](../mule/README.md) and
|
|
16
|
+
[Puffball](../puffball/README.md), all installed automatically. The root
|
|
16
17
|
entrypoint is the Promise host facade. `@fungi.computer/mycelium/effect`
|
|
17
18
|
supplies the scoped Effect API. Both produce an Effect-native Mule tool. The
|
|
18
19
|
`./sandbox-guest`, `./sandbox-wire`, `./sandbox-failure`, `./sandbox-boundary`,
|
|
@@ -223,17 +224,21 @@ Preserve that evidence without sending host diagnostics to the guest.
|
|
|
223
224
|
### Sandbox admission
|
|
224
225
|
|
|
225
226
|
The host-only `execution` options accept `sandboxCapacity` (a positive safe
|
|
226
|
-
integer) and `admissionWaitMs` (an integer from 1 to 900,000 milliseconds
|
|
227
|
-
default
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
227
|
+
integer) and `admissionWaitMs` (an integer from 1 to 900,000 milliseconds). By
|
|
228
|
+
default, admission waits for the invocation's `timeoutMs` budget (180,000
|
|
229
|
+
milliseconds when omitted), rather than failing after five seconds. An explicit
|
|
230
|
+
host wait remains bounded by the original invocation deadline. Guests still
|
|
231
|
+
submit only `code`. An omitted capacity derives from available cores, clamped to
|
|
232
|
+
2..32; hosts without a portable core observation use 2. Node captures its
|
|
233
|
+
affinity-aware core count once per runtime through
|
|
234
|
+
`node:os.availableParallelism()`, behind a platform-conditional module outside
|
|
235
|
+
the Workers import graph. Explicit valid capacity overrides bypass observation
|
|
236
|
+
and are not clamped, including values above 32.
|
|
233
237
|
|
|
234
238
|
`normalizeSandboxAdmissionPolicy(options, availableCores?)` validates and
|
|
235
|
-
resolves these host facts
|
|
236
|
-
|
|
239
|
+
resolves these host facts, using 180,000 milliseconds when no wait is supplied.
|
|
240
|
+
It does not reserve a slot or start a sandbox. Both public runtime facades
|
|
241
|
+
validate and capture the policy when the runtime opens.
|
|
237
242
|
|
|
238
243
|
Admission belongs to the existing runtime-wide backing-work tracker, not each
|
|
239
244
|
lease, group, or revision. A full pool waits until a slot opens or the earlier
|
package/dist/effect.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ import type { CapabilitySession, CapabilitySource, ModuleRegistration, Sandbox a
|
|
|
10
10
|
import type { AccessOptions, LabelledTool } from "./access.js";
|
|
11
11
|
export type { CapabilitySession, CapabilitySource, ModuleRegistration, SandboxBinding, SandboxRequest, };
|
|
12
12
|
export type { ExecutionOptions } from "./execute-tool.js";
|
|
13
|
+
export { forageDiscoveryInstructions } from "./execute-tool.js";
|
|
13
14
|
export type { Access, AccessContext, AccessLabel, AccessOptions, AccessRefusal, AccessRefusalReason, ConfirmRequest, Grant, Grants, LabelledTool, ToolPolicy, } from "./access.js";
|
|
14
15
|
/**
|
|
15
16
|
* Effect-native host seam for sandbox execution.
|
package/dist/effect.js
CHANGED
|
@@ -3,6 +3,7 @@ import * as Effect from "effect/Effect";
|
|
|
3
3
|
import * as Scope from "effect/Scope";
|
|
4
4
|
import {} from "./sandbox-failure.js";
|
|
5
5
|
import { openCoreRuntime } from "./runtime.js";
|
|
6
|
+
export { forageDiscoveryInstructions } from "./execute-tool.js";
|
|
6
7
|
/**
|
|
7
8
|
* Adapt a Promise-shaped sandbox to the Effect seam. This is Mycelium's one
|
|
8
9
|
* Promise sandbox conversion: interruption waits for the host Promise to
|
package/dist/execute-tool.d.ts
CHANGED
|
@@ -7,6 +7,8 @@ import { type BackingWorkGroup, type SerializedSandboxValue } from "./internal/e
|
|
|
7
7
|
import { type MyceliumError } from "./errors.js";
|
|
8
8
|
import type { EffectSandbox } from "./runtime.js";
|
|
9
9
|
import type { SandboxAdmissionOptions } from "./sandbox-admission.js";
|
|
10
|
+
/** Shared discovery scope for hosts offering Mycelium's execute tool. */
|
|
11
|
+
export declare const forageDiscoveryInstructions = "Inside execute, call forage.search, forage.list or forage.describe to discover operations and inspect their inputs. forage is available only there, not as a separate tool.";
|
|
10
12
|
/** Host execution limits plus the reserved, host-only admission contract. */
|
|
11
13
|
export type ExecutionOptions = Readonly<{
|
|
12
14
|
/** Total execution deadline in milliseconds. */
|
package/dist/execute-tool.js
CHANGED
|
@@ -14,7 +14,10 @@ import { OutputCollector } from "./output-collector.js";
|
|
|
14
14
|
import { InvalidOperationInput } from "./errors.js";
|
|
15
15
|
/** The one outer Mule input authority for the Mycelium execute door. */
|
|
16
16
|
const ExecuteInputSchema = Schema.Struct({ code: Schema.String });
|
|
17
|
-
|
|
17
|
+
/** Shared discovery scope for hosts offering Mycelium's execute tool. */
|
|
18
|
+
export const forageDiscoveryInstructions = "Inside execute, call forage.search, forage.list or forage.describe to discover operations and inspect their inputs. forage is available only there, not as a separate tool.";
|
|
19
|
+
const executeDescription = `${forageDiscoveryInstructions} ` +
|
|
20
|
+
'Run async JavaScript in the sandbox. Each call is a fresh sandbox, not a REPL: nothing survives between calls, so redefine helpers or persist state to a file. Never shadow injected module names with local bindings. Find operations with await forage.search({ query }) using one short keyword such as read or shell, or page them all with forage.list({limit:50}), optionally by namespace, until nextCursor is null. Inspect input with await forage.describe({ path }) before calling; describe known paths directly. Call an operation as await env.<path>({ ... }) with the exact dotted path, for example await env.computers.local.exec({ command: "pwd" }); a bare computers.local.exec is not defined. Put multiline shell commands in a template literal. Code is JavaScript first, so double each backslash the shell needs (`\\\\(` passes `\\(`; `\\(` becomes `(`). For file edits, prefer Files operations when available. Explicitly return the final value. Before treating a shell or process result as success, check status, exitCode and stderr.';
|
|
18
21
|
/** One bound operation: its labels are checked against the host's grants first. */
|
|
19
22
|
function guardedInvoke(entry, context, access, sessionId) {
|
|
20
23
|
const label = {
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ export { sandboxFailure, isSandboxFailure, sandboxOperatorValue, } from "./sandb
|
|
|
2
2
|
import type { ForageCatalog } from "@fungi.computer/forage";
|
|
3
3
|
export { normalizeSandboxAdmissionPolicy, type SandboxAdmissionOptions, type SandboxAdmissionPolicy, } from "./sandbox-admission.js";
|
|
4
4
|
import type { MuleTool } from "@fungi.computer/mule/effect";
|
|
5
|
-
import type { Sandbox
|
|
5
|
+
import type { Sandbox } from "./sandbox.js";
|
|
6
6
|
export type { MyceliumJsonValue, SandboxValue, SandboxBinding, SandboxRequest, Sandbox, } from "./sandbox.js";
|
|
7
7
|
import type * as Schema from "effect/Schema";
|
|
8
8
|
import type { OperationSchema } from "./operation-schema.js";
|
|
@@ -143,13 +143,13 @@ export type MyceliumApi = Readonly<{
|
|
|
143
143
|
/**
|
|
144
144
|
* Declare one schema-described operation behind the execute door. An Effect
|
|
145
145
|
* output schema encodes the result to JSON; otherwise the result must
|
|
146
|
-
* already be a JSON value.
|
|
146
|
+
* already be a JSON value, which may be readonly.
|
|
147
147
|
*/
|
|
148
148
|
operation: {
|
|
149
149
|
<I, O>(definition: OperationDefinition<I, O> & {
|
|
150
150
|
readonly output: Schema.Codec<O, unknown>;
|
|
151
151
|
}): OperationRegistration<I, O>;
|
|
152
|
-
<I, O extends
|
|
152
|
+
<I, O extends Schema.Json>(definition: OperationDefinition<I, O>): OperationRegistration<I, O>;
|
|
153
153
|
};
|
|
154
154
|
/** Open the Promise-shaped facade over Mycelium's Effect runtime. */
|
|
155
155
|
make: (options: MyceliumOptions) => Promise<Runtime>;
|
|
@@ -32,12 +32,13 @@ export function normalizeExecutionPolicy(value) {
|
|
|
32
32
|
if (!parsed.success) {
|
|
33
33
|
throw new MyceliumDefinitionError("Execution policy is invalid");
|
|
34
34
|
}
|
|
35
|
+
const timeoutMs = parsed.data?.timeoutMs ?? 180_000;
|
|
35
36
|
return Object.freeze({
|
|
36
|
-
timeoutMs
|
|
37
|
+
timeoutMs,
|
|
37
38
|
abortGraceMs: parsed.data?.abortGraceMs ?? 5_000,
|
|
38
39
|
...normalizeSandboxAdmissionPolicy({
|
|
39
40
|
sandboxCapacity: parsed.data?.sandboxCapacity,
|
|
40
|
-
admissionWaitMs: parsed.data?.admissionWaitMs,
|
|
41
|
+
admissionWaitMs: parsed.data?.admissionWaitMs ?? timeoutMs,
|
|
41
42
|
}, parsed.data?.sandboxCapacity === undefined
|
|
42
43
|
? availableHostCores()
|
|
43
44
|
: undefined),
|
package/dist/output-collector.js
CHANGED
|
@@ -2,6 +2,8 @@ import * as Effect from "effect/Effect";
|
|
|
2
2
|
import * as Queue from "effect/Queue";
|
|
3
3
|
import * as Stream from "effect/Stream";
|
|
4
4
|
const capacity = 8192;
|
|
5
|
+
// Bound temporary decoded text and raw context even for a single huge write.
|
|
6
|
+
const decodeCapacity = capacity * 4;
|
|
5
7
|
const encoder = new TextEncoder();
|
|
6
8
|
// fatal: false is the existing default; Cloudflare's type requires the field.
|
|
7
9
|
const decoder = () => new TextDecoder("utf-8", { ignoreBOM: true, fatal: false });
|
|
@@ -9,11 +11,11 @@ const decoder = () => new TextDecoder("utf-8", { ignoreBOM: true, fatal: false }
|
|
|
9
11
|
export class OutputCollector {
|
|
10
12
|
wake;
|
|
11
13
|
#producers = {
|
|
12
|
-
stdout: { decoder: decoder(),
|
|
13
|
-
stderr: { decoder: decoder(),
|
|
14
|
+
stdout: { decoder: decoder(), pending: new Uint8Array(0) },
|
|
15
|
+
stderr: { decoder: decoder(), pending: new Uint8Array(0) },
|
|
14
16
|
};
|
|
15
17
|
#probe = decoder();
|
|
16
|
-
// One bounded ring of
|
|
18
|
+
// One bounded ring of decoded chunks. TextDecoder owns every UTF-8 boundary.
|
|
17
19
|
#parts = Array.from({ length: capacity }, () => undefined);
|
|
18
20
|
#head = 0;
|
|
19
21
|
#size = 0;
|
|
@@ -35,28 +37,34 @@ export class OutputCollector {
|
|
|
35
37
|
return;
|
|
36
38
|
const producer = this.#producers[stream];
|
|
37
39
|
this.#totalBytes += bytes.length;
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
const
|
|
42
|
-
producer.
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
// buffering the current byte as the start of the next scalar. Ask the
|
|
48
|
-
// maintained decoder, rather than duplicating UTF-8 byte grammar.
|
|
49
|
-
const pending = producer.pendingBytes > 1 &&
|
|
50
|
-
this.#probe.decode(byte, { stream: true }).length === 0
|
|
51
|
-
? 1
|
|
52
|
-
: 0;
|
|
53
|
-
this.#probe.decode();
|
|
54
|
-
this.#append(text, producer.pendingBytes - pending);
|
|
55
|
-
producer.pendingBytes = pending;
|
|
40
|
+
for (let offset = 0; offset < bytes.length; offset += decodeCapacity) {
|
|
41
|
+
const chunk = bytes.subarray(offset, offset + decodeCapacity);
|
|
42
|
+
const text = producer.decoder.decode(chunk, { stream: true });
|
|
43
|
+
const raw = new Uint8Array(producer.pending.length + chunk.length);
|
|
44
|
+
raw.set(producer.pending);
|
|
45
|
+
raw.set(chunk, producer.pending.length);
|
|
46
|
+
const pending = this.#pendingLength(raw);
|
|
47
|
+
producer.pending = raw.slice(raw.length - pending);
|
|
48
|
+
this.#append(text, raw.length - pending, raw);
|
|
56
49
|
}
|
|
57
50
|
this.#dirty = true;
|
|
58
51
|
Queue.offerUnsafe(this.wake, undefined);
|
|
59
52
|
}
|
|
53
|
+
#decodePrefix(raw, length) {
|
|
54
|
+
const text = this.#probe.decode(raw.subarray(0, length), { stream: true });
|
|
55
|
+
this.#probe.decode();
|
|
56
|
+
return text;
|
|
57
|
+
}
|
|
58
|
+
#pendingLength(raw) {
|
|
59
|
+
// UTF-8 has at most three incomplete bytes. Ask the maintained decoder
|
|
60
|
+
// which suffix is still incomplete; do not inspect UTF-8 byte patterns.
|
|
61
|
+
for (let length = 1; length <= Math.min(3, raw.length); length++) {
|
|
62
|
+
const suffix = raw.subarray(raw.length - length);
|
|
63
|
+
if (this.#decodePrefix(suffix, suffix.length).length === 0)
|
|
64
|
+
return length;
|
|
65
|
+
}
|
|
66
|
+
return 0;
|
|
67
|
+
}
|
|
60
68
|
#evict() {
|
|
61
69
|
const part = this.#parts[this.#head];
|
|
62
70
|
if (part === undefined)
|
|
@@ -68,11 +76,56 @@ export class OutputCollector {
|
|
|
68
76
|
this.#newlines -= part.newlines;
|
|
69
77
|
this.#droppedBytes += part.rawBytes;
|
|
70
78
|
}
|
|
71
|
-
#
|
|
79
|
+
#trimHead(part, textBytes, newlines) {
|
|
80
|
+
const raw = part.raw;
|
|
81
|
+
if (raw === null) {
|
|
82
|
+
this.#evict();
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
// Find the first decoder emission that pays both clipping debts. A native
|
|
86
|
+
// decode can emit replacement + ASCII together, or emit a replacement
|
|
87
|
+
// while buffering the next scalar. Keep those same emission boundaries.
|
|
88
|
+
const enough = (length) => {
|
|
89
|
+
const prefix = this.#decodePrefix(raw, length);
|
|
90
|
+
return (encoder.encode(prefix).length >= textBytes &&
|
|
91
|
+
prefix.split("\n").length - 1 >= newlines);
|
|
92
|
+
};
|
|
93
|
+
let high = Math.min(raw.length, Math.max(4, textBytes));
|
|
94
|
+
while (high < raw.length && !enough(high))
|
|
95
|
+
high = Math.min(raw.length, high * 2);
|
|
96
|
+
let low = 0;
|
|
97
|
+
while (low < high) {
|
|
98
|
+
const middle = Math.floor((low + high) / 2);
|
|
99
|
+
if (enough(middle))
|
|
100
|
+
high = middle;
|
|
101
|
+
else
|
|
102
|
+
low = middle + 1;
|
|
103
|
+
}
|
|
104
|
+
const prefix = this.#decodePrefix(raw, low);
|
|
105
|
+
if (prefix.length === part.text.length) {
|
|
106
|
+
this.#evict();
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const cut = low - this.#pendingLength(raw.subarray(0, low));
|
|
110
|
+
const removedBytes = encoder.encode(prefix).length;
|
|
111
|
+
const removedLines = prefix.split("\n").length - 1;
|
|
112
|
+
part.raw = raw.slice(cut);
|
|
113
|
+
// Decode the bounded remainder anew so a sliced string cannot retain the
|
|
114
|
+
// larger temporary chunk. raw.slice also releases its original buffer.
|
|
115
|
+
part.text = this.#decodePrefix(part.raw, part.raw.length);
|
|
116
|
+
part.rawBytes -= cut;
|
|
117
|
+
part.textBytes -= removedBytes;
|
|
118
|
+
part.newlines -= removedLines;
|
|
119
|
+
this.#textBytes -= removedBytes;
|
|
120
|
+
this.#newlines -= removedLines;
|
|
121
|
+
this.#droppedBytes += cut;
|
|
122
|
+
}
|
|
123
|
+
#append(text, rawBytes, raw) {
|
|
72
124
|
if (text.length === 0)
|
|
73
125
|
return;
|
|
74
126
|
const part = {
|
|
75
127
|
text,
|
|
128
|
+
raw,
|
|
76
129
|
rawBytes,
|
|
77
130
|
textBytes: encoder.encode(text).length,
|
|
78
131
|
newlines: text.split("\n").length - 1,
|
|
@@ -83,8 +136,17 @@ export class OutputCollector {
|
|
|
83
136
|
this.#size++;
|
|
84
137
|
this.#textBytes += part.textBytes;
|
|
85
138
|
this.#newlines += part.newlines;
|
|
86
|
-
while (this.#textBytes > capacity || this.#newlines >= 200)
|
|
87
|
-
this.#
|
|
139
|
+
while (this.#textBytes > capacity || this.#newlines >= 200) {
|
|
140
|
+
const head = this.#parts[this.#head];
|
|
141
|
+
if (head === undefined)
|
|
142
|
+
throw new Error("Missing output ring entry");
|
|
143
|
+
const bytesToDrop = Math.max(0, this.#textBytes - capacity);
|
|
144
|
+
const linesToDrop = Math.max(0, this.#newlines - 199);
|
|
145
|
+
if (head.textBytes <= bytesToDrop || head.newlines < linesToDrop)
|
|
146
|
+
this.#evict();
|
|
147
|
+
else
|
|
148
|
+
this.#trimHead(head, bytesToDrop, linesToDrop);
|
|
149
|
+
}
|
|
88
150
|
}
|
|
89
151
|
snapshot() {
|
|
90
152
|
let tail = "";
|
|
@@ -121,8 +183,8 @@ export class OutputCollector {
|
|
|
121
183
|
this.#closed = true;
|
|
122
184
|
for (const producer of [this.#producers.stdout, this.#producers.stderr]) {
|
|
123
185
|
const text = producer.decoder.decode();
|
|
124
|
-
this.#append(text, producer.
|
|
125
|
-
producer.
|
|
186
|
+
this.#append(text, producer.pending.length, null);
|
|
187
|
+
producer.pending = new Uint8Array(0);
|
|
126
188
|
if (text.length > 0)
|
|
127
189
|
this.#dirty = true;
|
|
128
190
|
}
|
|
@@ -139,7 +201,7 @@ export class OutputCollector {
|
|
|
139
201
|
this.#dirty = false;
|
|
140
202
|
for (const producer of [this.#producers.stdout, this.#producers.stderr]) {
|
|
141
203
|
producer.decoder.decode();
|
|
142
|
-
producer.
|
|
204
|
+
producer.pending = new Uint8Array(0);
|
|
143
205
|
}
|
|
144
206
|
}
|
|
145
207
|
}
|
package/dist/runtime.js
CHANGED
|
@@ -50,12 +50,16 @@ export function openCoreRuntime(options) {
|
|
|
50
50
|
onFailure: options.onSandboxFailure,
|
|
51
51
|
execution,
|
|
52
52
|
});
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
53
|
+
// A source-only runtime has no static definitions to validate. Its empty
|
|
54
|
+
// surface would be discarded; acquisition compiles the captured modules.
|
|
55
|
+
const staticSurface = options.modules.length === 0 && options.sources.length > 0
|
|
56
|
+
? undefined
|
|
57
|
+
: yield* Effect.try({
|
|
58
|
+
try: () => compileSurface(options.modules),
|
|
59
|
+
catch: (cause) => cause instanceof MyceliumDefinitionError
|
|
60
|
+
? cause
|
|
61
|
+
: new MyceliumDefinitionError("Capability compilation failed"),
|
|
62
|
+
});
|
|
59
63
|
const tools = yield* Effect.try({
|
|
60
64
|
try: () => Object.freeze(options.tools.map((tool) => guardTool(tool, options.access, {
|
|
61
65
|
sessionId: options.session?.sessionId ?? null,
|
|
@@ -67,7 +71,7 @@ export function openCoreRuntime(options) {
|
|
|
67
71
|
let installed;
|
|
68
72
|
const liveRevisions = new Set();
|
|
69
73
|
let closed = false;
|
|
70
|
-
if (options.sources.length === 0) {
|
|
74
|
+
if (options.sources.length === 0 && staticSurface !== undefined) {
|
|
71
75
|
const candidate = yield* acquireSourceCandidate({
|
|
72
76
|
...options,
|
|
73
77
|
sandbox,
|
|
@@ -16,6 +16,6 @@ export function normalizeSandboxAdmissionPolicy(options, availableCores) {
|
|
|
16
16
|
}
|
|
17
17
|
return Object.freeze({
|
|
18
18
|
capacity: parsed.data.sandboxCapacity ?? Math.min(32, Math.max(2, cores.data)),
|
|
19
|
-
waitMs: parsed.data.admissionWaitMs ??
|
|
19
|
+
waitMs: parsed.data.admissionWaitMs ?? 180_000,
|
|
20
20
|
});
|
|
21
21
|
}
|
package/docs/api/effect.md
CHANGED
|
@@ -77,6 +77,17 @@ type Runtime = Readonly<{
|
|
|
77
77
|
|
|
78
78
|
Warm Effect lifecycle for acquiring scope-owned run leases.
|
|
79
79
|
|
|
80
|
+
## Variables
|
|
81
|
+
|
|
82
|
+
### forageDiscoveryInstructions
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
const forageDiscoveryInstructions: "Inside execute, call forage.search, forage.list or forage.describe to discover operations and inspect their inputs. forage is available only there, not as a separate tool." =
|
|
86
|
+
"Inside execute, call forage.search, forage.list or forage.describe to discover operations and inspect their inputs. forage is available only there, not as a separate tool.";
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Shared discovery scope for hosts offering Mycelium's execute tool.
|
|
90
|
+
|
|
80
91
|
## Functions
|
|
81
92
|
|
|
82
93
|
### fromTypedSandbox()
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fungi.computer/mycelium",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"author": "Levi <levi@technomancy.dev>",
|
|
5
5
|
"description": "Effect-native scoped capability lifecycle with a Zod-authored execute door",
|
|
6
6
|
"type": "module",
|
|
@@ -79,9 +79,9 @@
|
|
|
79
79
|
],
|
|
80
80
|
"dependencies": {
|
|
81
81
|
"@fungi.computer/cairn": "0.1.0",
|
|
82
|
-
"@fungi.computer/forage": "0.2.
|
|
82
|
+
"@fungi.computer/forage": "0.2.2",
|
|
83
83
|
"@fungi.computer/mule": "0.2.1",
|
|
84
|
-
"@fungi.computer/puffball": "0.
|
|
84
|
+
"@fungi.computer/puffball": "0.4.0",
|
|
85
85
|
"effect": "4.0.2",
|
|
86
86
|
"zod": "4.4.3",
|
|
87
87
|
"acorn": "8.18.0",
|