@kybernesis/create 0.15.1 → 0.15.2

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.
@@ -80,3 +80,19 @@ export declare function arcanaMemorySlotTs(options: {
80
80
  * registry item, so the three can never disagree about what the file says.
81
81
  */
82
82
  export declare function notifyMountTs(): string;
83
+ /**
84
+ * The sandbox source for a reasoning-only specialist. One source for the
85
+ * `kyb upgrade` repair and any future scaffold, so they cannot disagree.
86
+ *
87
+ * Every eve agent has exactly one sandbox, and a declared subagent that
88
+ * authors none gets the framework default — on a self-hosted host, a Docker
89
+ * container from an 840MB image. A specialist that reasons and remembers with
90
+ * its file tools disabled never touches a filesystem, yet still booted a
91
+ * container per call; on a small host those boots blow eve's command-hook
92
+ * wait, which reads as the specialist being unavailable. `justbash` is eve's
93
+ * pure-JS bash: a virtual filesystem, no daemon, no VM, no container, no
94
+ * image, available instantly.
95
+ */
96
+ export declare function reasoningSandboxLibTs(): string;
97
+ /** What each reasoning-only subagent's `sandbox.ts` re-exports. */
98
+ export declare function reasoningSandboxReexportTs(): string;
package/dist/templates.js CHANGED
@@ -733,3 +733,34 @@ export function notifyMountTs() {
733
733
  export { default } from "@kybernesis/notify/extension";
734
734
  `;
735
735
  }
736
+ /**
737
+ * The sandbox source for a reasoning-only specialist. One source for the
738
+ * `kyb upgrade` repair and any future scaffold, so they cannot disagree.
739
+ *
740
+ * Every eve agent has exactly one sandbox, and a declared subagent that
741
+ * authors none gets the framework default — on a self-hosted host, a Docker
742
+ * container from an 840MB image. A specialist that reasons and remembers with
743
+ * its file tools disabled never touches a filesystem, yet still booted a
744
+ * container per call; on a small host those boots blow eve's command-hook
745
+ * wait, which reads as the specialist being unavailable. `justbash` is eve's
746
+ * pure-JS bash: a virtual filesystem, no daemon, no VM, no container, no
747
+ * image, available instantly.
748
+ */
749
+ export function reasoningSandboxLibTs() {
750
+ return `import { defineSandbox } from "eve/sandbox";
751
+ import { justbash } from "eve/sandbox/just-bash";
752
+
753
+ // The sandbox for a reasoning-only specialist: an instant virtual filesystem,
754
+ // no Docker container. See agent/subagents/<id>/sandbox.ts, which re-export
755
+ // this. Only subagents that do real build/git/network work keep a docker()
756
+ // sandbox of their own.
757
+ export default defineSandbox({ backend: justbash() });
758
+ `;
759
+ }
760
+ /** What each reasoning-only subagent's `sandbox.ts` re-exports. */
761
+ export function reasoningSandboxReexportTs() {
762
+ return `// Reasoning-only specialist: no real filesystem, so no Docker container.
763
+ // See agent/lib/reasoning-sandbox for why this exists and what it replaces.
764
+ export { default } from "../../lib/reasoning-sandbox";
765
+ `;
766
+ }
package/dist/upgrade.d.ts CHANGED
@@ -15,6 +15,10 @@ export declare function agentInputLimitUpgradeMessage(limit: AgentInputLimit): s
15
15
  export declare function needsNotify(deps: Record<string, string>): boolean;
16
16
  /** Write the notify mount if it is missing. Never touches a file that exists. */
17
17
  export declare function repairNotifyMount(cwd: string): "mounted" | "present";
18
+ /** Reasoning-only subagents (disable all file tools) that have no sandbox of their own. */
19
+ export declare function reasoningSubagentsNeedingSandbox(cwd: string): string[];
20
+ /** Write the shared lib source and each specialist's re-export. Never touches a file that exists. */
21
+ export declare function writeReasoningSandboxes(cwd: string, subagents: string[]): string[];
18
22
  export type GithubToolsMountRepair = {
19
23
  kind: "missing" | "current" | "updated" | "customized";
20
24
  } | {
package/dist/upgrade.js CHANGED
@@ -1,4 +1,4 @@
1
- import { chmodSync, copyFileSync, existsSync, mkdirSync, mkdtempSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
1
+ import { chmodSync, copyFileSync, existsSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
2
2
  import { spawnSync } from "node:child_process";
3
3
  import { tmpdir } from "node:os";
4
4
  import { join } from "node:path";
@@ -15,7 +15,7 @@ import { inspectEveAgent } from "./agent-limits.js";
15
15
  import { remoteProjectPath, sshTarget } from "./deploy.js";
16
16
  import { classifyModelReach } from "./model-reach.js";
17
17
  import { checkSelfVersion, versionLt } from "./self-version.js";
18
- import { LEGACY_GITHUB_TOOLS_MOUNT, githubToolsMountTs, notifyMountTs } from "./templates.js";
18
+ import { LEGACY_GITHUB_TOOLS_MOUNT, githubToolsMountTs, notifyMountTs, reasoningSandboxLibTs, reasoningSandboxReexportTs } from "./templates.js";
19
19
  import { confirmEveUpgrade, inspectBuzzSessions, inspectDurableRuns, reconcileEvalScript, } from "./upgrade-sessions.js";
20
20
  export function agentInputLimitUpgradeMessage(limit) {
21
21
  switch (limit.kind) {
@@ -210,6 +210,109 @@ function repairNotifySetup(cwd, deps) {
210
210
  console.log(` ${dim("Takes effect after the next build and restart.")}\n`);
211
211
  }
212
212
  }
213
+ /**
214
+ * A reasoning-only specialist that still boots a Docker container.
215
+ *
216
+ * Every eve agent has exactly one sandbox, and a declared subagent that
217
+ * authors none gets the framework default — on a self-hosted host, a Docker
218
+ * container from an 840MB image. A specialist whose `bash`, `read_file`, and
219
+ * `write_file` tools are all disabled reasons and remembers and never touches
220
+ * a filesystem, yet each still booted its own container per call. On a small
221
+ * host those boots contend and blow eve's ~120s command-hook wait, which reads
222
+ * as "the specialist is unavailable" and, under a scheduled fan-out, thrashes
223
+ * the host. Disabling the file tools never stopped the sandbox: it is a slot
224
+ * eve always fills, not a consequence of the tools.
225
+ *
226
+ * The signal is deliberately narrow and static: a subagent that disables all
227
+ * three file tools has declared it does no filesystem work, so `just-bash` —
228
+ * eve's containerless virtual filesystem — is safe and correct for it. A
229
+ * subagent that leaves those tools enabled is left alone; whether it needs a
230
+ * real sandbox is a judgment only a person can make.
231
+ */
232
+ function disablesAllFileTools(dir) {
233
+ const tools = join(dir, "tools");
234
+ if (!existsSync(tools))
235
+ return false;
236
+ return ["bash", "read_file", "write_file"].every((name) => {
237
+ const file = join(tools, `${name}.ts`);
238
+ if (!existsSync(file))
239
+ return false;
240
+ try {
241
+ return /disableTool\s*\(/.test(readFileSync(file, "utf8"));
242
+ }
243
+ catch {
244
+ return false;
245
+ }
246
+ });
247
+ }
248
+ function hasAuthoredSandbox(dir) {
249
+ return existsSync(join(dir, "sandbox.ts")) || existsSync(join(dir, "sandbox"));
250
+ }
251
+ /** Reasoning-only subagents (disable all file tools) that have no sandbox of their own. */
252
+ export function reasoningSubagentsNeedingSandbox(cwd) {
253
+ const root = join(cwd, "agent/subagents");
254
+ if (!existsSync(root))
255
+ return [];
256
+ const found = [];
257
+ for (const entry of readdirSync(root)) {
258
+ const dir = join(root, entry);
259
+ try {
260
+ if (!statSync(dir).isDirectory())
261
+ continue;
262
+ }
263
+ catch {
264
+ continue;
265
+ }
266
+ if (!existsSync(join(dir, "agent.ts")))
267
+ continue;
268
+ if (hasAuthoredSandbox(dir))
269
+ continue;
270
+ if (disablesAllFileTools(dir))
271
+ found.push(entry);
272
+ }
273
+ return found.sort();
274
+ }
275
+ /** Write the shared lib source and each specialist's re-export. Never touches a file that exists. */
276
+ export function writeReasoningSandboxes(cwd, subagents) {
277
+ const wrote = [];
278
+ const lib = join(cwd, "agent/lib/reasoning-sandbox.ts");
279
+ if (!existsSync(lib)) {
280
+ mkdirSync(join(cwd, "agent/lib"), { recursive: true });
281
+ writeFileSync(lib, reasoningSandboxLibTs());
282
+ wrote.push("agent/lib/reasoning-sandbox.ts");
283
+ }
284
+ for (const name of subagents) {
285
+ const file = join(cwd, "agent/subagents", name, "sandbox.ts");
286
+ if (existsSync(file))
287
+ continue;
288
+ writeFileSync(file, reasoningSandboxReexportTs());
289
+ wrote.push(`agent/subagents/${name}/sandbox.ts`);
290
+ }
291
+ return wrote;
292
+ }
293
+ function repairReasoningSandboxes(cwd, deps) {
294
+ const needing = reasoningSubagentsNeedingSandbox(cwd);
295
+ if (needing.length === 0)
296
+ return;
297
+ const done = [];
298
+ if (!deps["just-bash"]) {
299
+ const ok = run("npm", ["install", "just-bash@^3.1.0", "--no-audit", "--no-fund"], { cwd, allowFail: true, quiet: true });
300
+ if (!ok) {
301
+ console.log(` ${yellow("!")} ${needing.length} reasoning specialist(s) still boot a Docker container per call, but just-bash could not be installed.\n` +
302
+ ` Run: npm install just-bash@^3.1.0 && npx kyb upgrade`);
303
+ return;
304
+ }
305
+ deps["just-bash"] = "^3.1.0";
306
+ done.push("installed just-bash");
307
+ }
308
+ const wrote = writeReasoningSandboxes(cwd, needing);
309
+ if (wrote.length > 0)
310
+ done.push(`gave ${needing.join(", ")} an instant sandbox (${wrote.length} file${wrote.length === 1 ? "" : "s"})`);
311
+ if (done.length > 0) {
312
+ console.log(` ${green("+")} Sandboxes: ${done.join("; ")} ${dim("— reasoning specialists no longer boot a Docker container")}`);
313
+ console.log(` ${dim("Takes effect after the next build and restart.")}\n`);
314
+ }
315
+ }
213
316
  /** Quote one argument for the manual shell commands printed after a failed repair. */
214
317
  function shellQuote(value) {
215
318
  return `'${value.replaceAll("'", `'"'"'`)}'`;
@@ -846,6 +949,7 @@ export async function upgrade(options = {}) {
846
949
  repairHostArtifacts(cwd, deps);
847
950
  repairEvalCommand(cwd);
848
951
  repairNotifySetup(cwd, deps);
952
+ repairReasoningSandboxes(cwd, deps);
849
953
  repairManageRestart(cwd, deps);
850
954
  return;
851
955
  }
@@ -918,6 +1022,7 @@ export async function upgrade(options = {}) {
918
1022
  repairHostArtifacts(cwd, deps);
919
1023
  repairEvalCommand(cwd);
920
1024
  repairNotifySetup(cwd, deps);
1025
+ repairReasoningSandboxes(cwd, deps);
921
1026
  repairManageRestart(cwd, deps);
922
1027
  run("npm", ["run", "typecheck"], { cwd });
923
1028
  if (eveChanged) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@kybernesis/create",
3
- "version": "0.15.1",
4
- "description": "The Kybernesis agent scaffolder and FDE toolkit: one command to a governed, remembering, multiplayer, self-testing eve agent \u2014 plus doctor and upgrade.",
3
+ "version": "0.15.2",
4
+ "description": "The Kybernesis agent scaffolder and FDE toolkit: one command to a governed, remembering, multiplayer, self-testing eve agent — plus doctor and upgrade.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
7
7
  "homepage": "https://kybernesis.ai",