@kybernesis/create 0.15.0 → 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.
- package/dist/templates.d.ts +16 -0
- package/dist/templates.js +31 -0
- package/dist/upgrade.d.ts +4 -0
- package/dist/upgrade.js +140 -11
- package/package.json +2 -2
package/dist/templates.d.ts
CHANGED
|
@@ -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("'", `'"'"'`)}'`;
|
|
@@ -721,15 +824,6 @@ function startStoppedBridge(cwd, unit) {
|
|
|
721
824
|
}
|
|
722
825
|
export async function upgrade(options = {}) {
|
|
723
826
|
console.log(bold("\nkyb upgrade — checking @kybernesis/* and eve against npm\n"));
|
|
724
|
-
const selfVersion = checkSelfVersion();
|
|
725
|
-
if (selfVersion.kind === "stale") {
|
|
726
|
-
console.log(` ${yellow("!")} ${selfVersion.message}`);
|
|
727
|
-
console.log(` ${dim(selfVersion.fix)}\n`);
|
|
728
|
-
if (!options.allowStale) {
|
|
729
|
-
process.exitCode = 1;
|
|
730
|
-
return;
|
|
731
|
-
}
|
|
732
|
-
}
|
|
733
827
|
const cwd = process.cwd();
|
|
734
828
|
const packagePath = join(cwd, "package.json");
|
|
735
829
|
const pkg = JSON.parse(readFileSync(packagePath, "utf8"));
|
|
@@ -737,6 +831,39 @@ export async function upgrade(options = {}) {
|
|
|
737
831
|
...(pkg.dependencies ?? {}),
|
|
738
832
|
...(pkg.devDependencies ?? {}),
|
|
739
833
|
};
|
|
834
|
+
const selfVersion = checkSelfVersion();
|
|
835
|
+
if (selfVersion.kind === "stale" && !options.allowStale) {
|
|
836
|
+
/**
|
|
837
|
+
* A stale kyb that is the PROJECT's own dependency renews itself.
|
|
838
|
+
*
|
|
839
|
+
* On every self-hosted agent, kyb is in package.json and `npx kyb` runs
|
|
840
|
+
* that copy; a global install — the printed fix until now — changes
|
|
841
|
+
* nothing there, and the person who followed it was back at the same
|
|
842
|
+
* message. So when the project owns kyb, install the latest into the
|
|
843
|
+
* project and run the upgrade again from that copy. The re-run is marked
|
|
844
|
+
* so that a registry that has not caught up cannot make this loop.
|
|
845
|
+
*/
|
|
846
|
+
if (deps["@kybernesis/create"] && process.env.KYB_UPGRADE_RENEWED !== "1") {
|
|
847
|
+
console.log(` ${yellow("↑")} kyb ${selfVersion.installed} → ${selfVersion.latest} ${dim("(this project's own copy; renewing it first)")}`);
|
|
848
|
+
const renewed = run("npm", ["install", `@kybernesis/create@${selfVersion.latest}`, "--no-audit", "--no-fund"], { cwd, allowFail: true, quiet: true });
|
|
849
|
+
const cli = join(cwd, "node_modules/@kybernesis/create/dist/cli.js");
|
|
850
|
+
if (renewed && existsSync(cli)) {
|
|
851
|
+
const again = spawnSync(process.execPath, [cli, "upgrade", ...process.argv.slice(3)], {
|
|
852
|
+
cwd, stdio: "inherit", env: { ...process.env, KYB_UPGRADE_RENEWED: "1" },
|
|
853
|
+
});
|
|
854
|
+
process.exitCode = again.status ?? 1;
|
|
855
|
+
return;
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
console.log(` ${yellow("!")} ${selfVersion.message}`);
|
|
859
|
+
console.log(` ${dim(deps["@kybernesis/create"] ? `npm install @kybernesis/create@latest && npx kyb upgrade` : selfVersion.fix)}\n`);
|
|
860
|
+
process.exitCode = 1;
|
|
861
|
+
return;
|
|
862
|
+
}
|
|
863
|
+
if (selfVersion.kind === "stale") {
|
|
864
|
+
console.log(` ${yellow("!")} ${selfVersion.message}`);
|
|
865
|
+
console.log(` ${dim(selfVersion.fix)} ${dim("(continuing: --allow-stale)")}\n`);
|
|
866
|
+
}
|
|
740
867
|
reportAgentInputLimit(cwd);
|
|
741
868
|
const entries = dependencyEntries(pkg);
|
|
742
869
|
const installedVersions = new Map();
|
|
@@ -822,6 +949,7 @@ export async function upgrade(options = {}) {
|
|
|
822
949
|
repairHostArtifacts(cwd, deps);
|
|
823
950
|
repairEvalCommand(cwd);
|
|
824
951
|
repairNotifySetup(cwd, deps);
|
|
952
|
+
repairReasoningSandboxes(cwd, deps);
|
|
825
953
|
repairManageRestart(cwd, deps);
|
|
826
954
|
return;
|
|
827
955
|
}
|
|
@@ -894,6 +1022,7 @@ export async function upgrade(options = {}) {
|
|
|
894
1022
|
repairHostArtifacts(cwd, deps);
|
|
895
1023
|
repairEvalCommand(cwd);
|
|
896
1024
|
repairNotifySetup(cwd, deps);
|
|
1025
|
+
repairReasoningSandboxes(cwd, deps);
|
|
897
1026
|
repairManageRestart(cwd, deps);
|
|
898
1027
|
run("npm", ["run", "typecheck"], { cwd });
|
|
899
1028
|
if (eveChanged) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kybernesis/create",
|
|
3
|
-
"version": "0.15.
|
|
4
|
-
"description": "The Kybernesis agent scaffolder and FDE toolkit: one command to a governed, remembering, multiplayer, self-testing eve agent
|
|
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",
|