@kybernesis/create 0.14.8 → 0.14.9
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 +18 -1
- package/dist/cli.js +21 -1
- package/dist/deploy.d.ts +3 -0
- package/dist/deploy.js +6 -3
- package/dist/doctor.d.ts +2 -0
- package/dist/doctor.js +20 -0
- package/dist/init.d.ts +5 -0
- package/dist/init.js +16 -1
- package/dist/model-reach.d.ts +2 -0
- package/dist/model-reach.js +8 -4
- package/dist/self-version.d.ts +24 -0
- package/dist/self-version.js +56 -0
- package/dist/templates.d.ts +12 -0
- package/dist/templates.js +31 -0
- package/dist/upgrade.d.ts +18 -0
- package/dist/upgrade.js +196 -48
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -85,7 +85,7 @@ Run inside an agent project. Checks, with pass/warn/fail per line:
|
|
|
85
85
|
|
|
86
86
|
Exit code 1 on any failure — usable as a CI preflight.
|
|
87
87
|
|
|
88
|
-
## `kyb upgrade [--skip-eval] [--yes]`
|
|
88
|
+
## `kyb upgrade [--host[=<ssh-target>]] [--skip-eval] [--yes]`
|
|
89
89
|
|
|
90
90
|
Compares installed `@kybernesis/*` versions against npm, installs what's
|
|
91
91
|
behind, typechecks, then **runs the eval suite as the gate** — prints
|
|
@@ -100,6 +100,23 @@ runs fail closed unless `--yes` (or `-y`) is supplied. The warning is still prin
|
|
|
100
100
|
are migrated to `kyb-eval`; custom scripts are left untouched with a manual fix.
|
|
101
101
|
The wrapper counts corruption diagnostics beside the eval result and turns a
|
|
102
102
|
nominally green eve exit into a failure when condemned durable state was seen.
|
|
103
|
+
It also identifies failures from `judge.autoevals.*` assertions as judge
|
|
104
|
+
reachability or HTTP failures rather than implying that the agent model failed.
|
|
105
|
+
|
|
106
|
+
Immediately before a local gate, upgrade classifies the authored and compiled
|
|
107
|
+
model route the same way as `kyb doctor`, then checks host-only dependencies. A
|
|
108
|
+
Claude subscription agent must have its loopback proxy answering, and an
|
|
109
|
+
exe-backed agent or judge must be able to reach `EXE_LLM_URL` (or the internal
|
|
110
|
+
exe model catalog). If those routes are unavailable, the eval command is not
|
|
111
|
+
run and upgrade exits with status 2, prints that the gate can only run on the
|
|
112
|
+
host, and gives the exact ssh command. It does not print "Do NOT deploy" because
|
|
113
|
+
no eval exercised the code.
|
|
114
|
+
|
|
115
|
+
Use `kyb upgrade --host` to run the gate over ssh after the upgrade. The target
|
|
116
|
+
uses the same defaults as `kyb deploy`: `EVE_SSH_HOST`, then
|
|
117
|
+
`$EXE_VM_NAME.exe.xyz`; `--host=<ssh-target>` overrides them. The remote project
|
|
118
|
+
path is `~/<package-name>`, and the remote eval output streams directly to the
|
|
119
|
+
terminal. `--skip-eval` remains an explicit bypass and performs no preflight.
|
|
103
120
|
|
|
104
121
|
On self-hosted agents, upgrade also reconciles package-owned host artifacts. It
|
|
105
122
|
refreshes a stale `/etc/cron.daily/kyb-docker-prune` and an existing generated
|
package/dist/cli.js
CHANGED
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
* kyb deploy put this repo on its host and restart it, with proof
|
|
12
12
|
* kyb upgrade bump @kybernesis/* to latest, gated on the eval suite
|
|
13
13
|
* --skip-eval skip the eval gate (not for production changes)
|
|
14
|
+
* --host[=<target>] run the eval gate over ssh on the agent host
|
|
15
|
+
* --allow-stale proceed even when this kyb is behind npm
|
|
14
16
|
* --yes, -y confirm an eve upgrade noninteractively
|
|
15
17
|
*/
|
|
16
18
|
import { existsSync, readFileSync } from "node:fs";
|
|
@@ -52,6 +54,12 @@ function flag(rest, key) {
|
|
|
52
54
|
const hit = rest.find((a) => a.startsWith(`--${key}=`));
|
|
53
55
|
return hit ? hit.slice(key.length + 3) : undefined;
|
|
54
56
|
}
|
|
57
|
+
function optionalValueFlag(rest, key) {
|
|
58
|
+
if (rest.includes(`--${key}`))
|
|
59
|
+
return true;
|
|
60
|
+
const value = flag(rest, key);
|
|
61
|
+
return value === undefined ? undefined : value;
|
|
62
|
+
}
|
|
55
63
|
function initOptions(rest) {
|
|
56
64
|
const subs = flag(rest, 'subagents');
|
|
57
65
|
return {
|
|
@@ -75,7 +83,7 @@ const COMMANDS = {
|
|
|
75
83
|
credential: "Write the agent credential onto a host (--local to stay here).",
|
|
76
84
|
register: "Register this agent with the control plane (--name, --url).",
|
|
77
85
|
deploy: "Deploy this agent to its host (--no-env to leave the env file alone).",
|
|
78
|
-
upgrade: "Bring @kybernesis packages and eve to certified versions (--skip-eval, --yes).",
|
|
86
|
+
upgrade: "Bring @kybernesis packages and eve to certified versions (--host, --skip-eval, --allow-stale, --yes).",
|
|
79
87
|
tui: "Talk to your agents in the terminal.",
|
|
80
88
|
version: "Print the version of this tool.",
|
|
81
89
|
};
|
|
@@ -101,6 +109,14 @@ function usage(command) {
|
|
|
101
109
|
|
|
102
110
|
${dim("Factory env: KYB_MODEL_REACH=claude-sub (the CLI flag takes precedence).")}
|
|
103
111
|
${dim("Claude subscription reach uses the loopback OAuth proxy; it does not read EXE_MODEL.")}\n`);
|
|
112
|
+
}
|
|
113
|
+
else if (command === "upgrade") {
|
|
114
|
+
console.log(` ${bold("kyb upgrade")} [options]
|
|
115
|
+
--host[=<target>] ${dim("run the eval gate over ssh; defaults like kyb deploy")}
|
|
116
|
+
--skip-eval ${dim("skip the eval gate")}
|
|
117
|
+
--allow-stale ${dim("continue even when this kyb is behind the published version")}
|
|
118
|
+
--yes, -y ${dim("confirm an eve version change noninteractively")}
|
|
119
|
+
`);
|
|
104
120
|
}
|
|
105
121
|
return;
|
|
106
122
|
}
|
|
@@ -161,6 +177,8 @@ switch (command) {
|
|
|
161
177
|
break;
|
|
162
178
|
case "upgrade":
|
|
163
179
|
await upgrade({
|
|
180
|
+
allowStale: rest.includes("--allow-stale"),
|
|
181
|
+
host: optionalValueFlag(rest, "host"),
|
|
164
182
|
skipEval: rest.includes("--skip-eval"),
|
|
165
183
|
yes: rest.includes("--yes") || rest.includes("-y"),
|
|
166
184
|
});
|
|
@@ -228,7 +246,9 @@ ${dim(" npm i -g @kybernesis/create@latest")}
|
|
|
228
246
|
--host=<target> ${dim("ssh target; defaults to $EXE_VM_NAME.exe.xyz")}
|
|
229
247
|
--no-env ${dim("do not send .env.local (host manages its own secrets)")}
|
|
230
248
|
${bold("kyb upgrade")} bump @kybernesis/* packages, gated on evals
|
|
249
|
+
--host[=<target>] ${dim("run the eval gate over ssh; defaults to EVE_SSH_HOST or EXE_VM_NAME")}
|
|
231
250
|
--skip-eval ${dim("skip the eval gate")}
|
|
251
|
+
--allow-stale ${dim("continue even when this kyb is behind the published version")}
|
|
232
252
|
--yes, -y ${dim("confirm an eve version change noninteractively")}
|
|
233
253
|
|
|
234
254
|
Registry: https://registry.kybernesis.ai · Docs: the FDE playbook
|
package/dist/deploy.d.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
/** The ssh target: an explicit flag, then EVE_SSH_HOST, then the exe VM name. */
|
|
2
|
+
export declare function sshTarget(dir: string, explicit?: string): string | null;
|
|
3
|
+
export declare function remoteProjectPath(dir: string): string;
|
|
1
4
|
export declare function deploy(options: {
|
|
2
5
|
host?: string;
|
|
3
6
|
dir?: string;
|
package/dist/deploy.js
CHANGED
|
@@ -34,7 +34,7 @@ function hostOf(dir) {
|
|
|
34
34
|
return deps["@kybernesis/exe"] ? "exe" : "vercel";
|
|
35
35
|
}
|
|
36
36
|
/** The ssh target: an explicit flag, then EVE_SSH_HOST, then the exe VM name. */
|
|
37
|
-
function sshTarget(dir, explicit) {
|
|
37
|
+
export function sshTarget(dir, explicit) {
|
|
38
38
|
const e = env(dir);
|
|
39
39
|
if (explicit)
|
|
40
40
|
return explicit;
|
|
@@ -97,6 +97,10 @@ async function ensureModel(dir, target) {
|
|
|
97
97
|
upsertEnv(dir, { EXE_MODEL: chosen });
|
|
98
98
|
console.log(green(` ✓ EXE_MODEL="${chosen}" written to .env.local\n`));
|
|
99
99
|
}
|
|
100
|
+
export function remoteProjectPath(dir) {
|
|
101
|
+
const pkg = JSON.parse(readFileSync(join(dir, "package.json"), "utf8"));
|
|
102
|
+
return `~/${pkg.name ?? "agent"}`;
|
|
103
|
+
}
|
|
100
104
|
export async function deploy(options) {
|
|
101
105
|
const dir = options.dir ?? process.cwd();
|
|
102
106
|
if (!existsSync(join(dir, "agent"))) {
|
|
@@ -118,8 +122,7 @@ export async function deploy(options) {
|
|
|
118
122
|
process.exitCode = 1;
|
|
119
123
|
return;
|
|
120
124
|
}
|
|
121
|
-
const
|
|
122
|
-
const remote = `~/${name}`;
|
|
125
|
+
const remote = remoteProjectPath(dir);
|
|
123
126
|
console.log(dim(` host: ${target} path: ${remote}\n`));
|
|
124
127
|
await ensureModel(dir, target);
|
|
125
128
|
const run = (cmd, args) => {
|
package/dist/doctor.d.ts
CHANGED
|
@@ -6,6 +6,8 @@ export interface Check {
|
|
|
6
6
|
label: string;
|
|
7
7
|
detail?: string;
|
|
8
8
|
}
|
|
9
|
+
/** Report the opt-in GitHub capability only when its mount is present. */
|
|
10
|
+
export declare function githubToolsDoctorCheck(mountExists: boolean, env: Record<string, string | undefined>): Check | null;
|
|
9
11
|
/** The shape @kybernesis/exe's inspector returns; declared here so create keeps zero runtime deps. */
|
|
10
12
|
export interface DockerTemplateInspection {
|
|
11
13
|
status: "skipped" | "present" | "failed";
|
package/dist/doctor.js
CHANGED
|
@@ -6,11 +6,22 @@ import { bold, capture, dim, green, parseEnv, red, yellow } from "./util.js";
|
|
|
6
6
|
import { diagnoseManageRestart, findMatchingAgentServiceUnit } from "./systemd.js";
|
|
7
7
|
import { inspectEveAgent } from "./agent-limits.js";
|
|
8
8
|
import { classifyModelReach } from "./model-reach.js";
|
|
9
|
+
import { checkSelfVersion } from "./self-version.js";
|
|
9
10
|
const MARK = {
|
|
10
11
|
pass: green("✓"),
|
|
11
12
|
warn: yellow("!"),
|
|
12
13
|
fail: red("✗"),
|
|
13
14
|
};
|
|
15
|
+
/** Report the opt-in GitHub capability only when its mount is present. */
|
|
16
|
+
export function githubToolsDoctorCheck(mountExists, env) {
|
|
17
|
+
if (!mountExists || env.GITHUB_TOKEN)
|
|
18
|
+
return null;
|
|
19
|
+
return {
|
|
20
|
+
verdict: "warn",
|
|
21
|
+
label: "GitHub tools off (no GITHUB_TOKEN)",
|
|
22
|
+
detail: "set GITHUB_TOKEN in .env.local or the deployment environment, then rebuild and restart",
|
|
23
|
+
};
|
|
24
|
+
}
|
|
14
25
|
export function dockerTemplateDoctorChecks(result) {
|
|
15
26
|
if (result.status === "skipped")
|
|
16
27
|
return [];
|
|
@@ -40,6 +51,8 @@ export function modelReachDoctorCheck(authoredSource, compiledRouting) {
|
|
|
40
51
|
return { verdict: "pass", label: "Model reach: claude-sub (Claude subscription)" };
|
|
41
52
|
case "exe":
|
|
42
53
|
return { verdict: "pass", label: "Model reach: exe (host LLM integration)" };
|
|
54
|
+
case "grok-sub":
|
|
55
|
+
return { verdict: "pass", label: "Model reach: grok-sub (direct xAI subscription credential)" };
|
|
43
56
|
case "gateway":
|
|
44
57
|
return { verdict: "pass", label: "Model reach: gateway" };
|
|
45
58
|
case "direct-provider":
|
|
@@ -99,6 +112,10 @@ export async function doctor() {
|
|
|
99
112
|
const installedAgentService = findMatchingAgentServiceUnit(cwd);
|
|
100
113
|
const checks = [];
|
|
101
114
|
const add = (verdict, label, detail) => checks.push({ verdict, label, detail });
|
|
115
|
+
const selfVersion = checkSelfVersion();
|
|
116
|
+
if (selfVersion.kind === "stale") {
|
|
117
|
+
add("warn", selfVersion.message, selfVersion.fix);
|
|
118
|
+
}
|
|
102
119
|
// ── project shape ──────────────────────────────────────────────────────
|
|
103
120
|
if (!existsSync(join(cwd, "agent"))) {
|
|
104
121
|
console.error(red("Not an eve agent project (no agent/ directory). Run inside the agent repo."));
|
|
@@ -138,6 +155,9 @@ export async function doctor() {
|
|
|
138
155
|
};
|
|
139
156
|
if (!existsSync(envPath))
|
|
140
157
|
add("warn", ".env.local missing", "copy .env.example and fill it");
|
|
158
|
+
const githubCheck = githubToolsDoctorCheck(existsSync(join(cwd, "agent/extensions/github.ts")), env);
|
|
159
|
+
if (githubCheck)
|
|
160
|
+
add(githubCheck.verdict, githubCheck.label, githubCheck.detail);
|
|
141
161
|
// ── arcana keys: validate every key↔workspace pair read-only ───────────
|
|
142
162
|
const arcanaPairs = [];
|
|
143
163
|
if (env.ARCANA_API_KEY && env.ARCANA_COMPANY_WORKSPACE)
|
package/dist/init.d.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import { type ChannelKind, type HostKind } from "./templates.js";
|
|
2
|
+
/**
|
|
3
|
+
* Replace Eve's freshly installed registry mount with the Kybernesis-managed
|
|
4
|
+
* token-aware form. A failed registry add must not create a capability file.
|
|
5
|
+
*/
|
|
6
|
+
export declare function finalizeGithubToolsRegistryMount(cwd: string, registryAddSucceeded: boolean): boolean;
|
|
2
7
|
export interface InitOptions {
|
|
3
8
|
engineer?: boolean;
|
|
4
9
|
/**
|
package/dist/init.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { chmodSync, copyFileSync, cpSync, existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { join, resolve } from "node:path";
|
|
3
3
|
import { DEFAULT_ISSUER, EVE_VERSION, REGISTRY_URL, ask, bold, closePrompts, dim, green, run, slug, red, yellow, } from "./util.js";
|
|
4
|
-
import { CHANNEL_KINDS, channelPlan, engineerPlan, envExample, evalFileTs, exeEvalConfigTs, evalScript, hostAgentTs, hostSteps, identityMd, rootArcanaTs, subagentAgentTs, subagentArcanaTs, subagentInstructionsMd, } from "./templates.js";
|
|
4
|
+
import { CHANNEL_KINDS, channelPlan, engineerPlan, envExample, evalFileTs, exeEvalConfigTs, evalScript, hostAgentTs, hostSteps, githubToolsMountTs, identityMd, rootArcanaTs, subagentAgentTs, subagentArcanaTs, subagentInstructionsMd, } from "./templates.js";
|
|
5
5
|
import { suiteDir } from "./skills.js";
|
|
6
6
|
import { configureArcana } from "./arcana.js";
|
|
7
7
|
import { upsertEnv } from "./envfile.js";
|
|
@@ -19,6 +19,19 @@ const CORE_ITEMS = ["enterprise", "arcana", "evals"];
|
|
|
19
19
|
// self-hosted agent it cannot get an OIDC token and the agent fails to boot.
|
|
20
20
|
const ENGINEER_ITEMS_ALL = ["extension/agent-browser", "extension/github-tools"];
|
|
21
21
|
const ENGINEER_ITEMS_VERCEL = ["connection/vercel"];
|
|
22
|
+
/**
|
|
23
|
+
* Replace Eve's freshly installed registry mount with the Kybernesis-managed
|
|
24
|
+
* token-aware form. A failed registry add must not create a capability file.
|
|
25
|
+
*/
|
|
26
|
+
export function finalizeGithubToolsRegistryMount(cwd, registryAddSucceeded) {
|
|
27
|
+
if (!registryAddSucceeded)
|
|
28
|
+
return false;
|
|
29
|
+
const path = join(cwd, "agent/extensions/github.ts");
|
|
30
|
+
if (!existsSync(path))
|
|
31
|
+
return false;
|
|
32
|
+
writeFileSync(path, githubToolsMountTs());
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
22
35
|
export async function init(rawName, options = {}) {
|
|
23
36
|
const engineer = options.engineer === true;
|
|
24
37
|
const studio = options.studio === true;
|
|
@@ -165,6 +178,8 @@ export async function init(rawName, options = {}) {
|
|
|
165
178
|
const engItems = [...ENGINEER_ITEMS_ALL, ...(host === "vercel" ? ENGINEER_ITEMS_VERCEL : [])];
|
|
166
179
|
for (const item of engItems) {
|
|
167
180
|
const ok = run("npx", ["eve", "add", item, "--overwrite"], { cwd: dir, allowFail: true });
|
|
181
|
+
if (item === "extension/github-tools")
|
|
182
|
+
finalizeGithubToolsRegistryMount(dir, ok);
|
|
168
183
|
if (!ok)
|
|
169
184
|
console.log(yellow(` ! ${item} did not install cleanly — re-run: npx eve add ${item}`));
|
|
170
185
|
}
|
package/dist/model-reach.d.ts
CHANGED
package/dist/model-reach.js
CHANGED
|
@@ -35,12 +35,16 @@ export function classifyModelReach(authoredSource, compiledRouting) {
|
|
|
35
35
|
if (authoredSource !== null) {
|
|
36
36
|
const claudeSubscription = /\bclaudeSubscription\s*\(/.test(authoredSource);
|
|
37
37
|
const exeModel = /\bexeModel\s*\(/.test(authoredSource);
|
|
38
|
-
|
|
38
|
+
const grokSubscription = /\bgrokSubscription\s*\(/.test(authoredSource);
|
|
39
|
+
const authored = [claudeSubscription, exeModel, grokSubscription].filter(Boolean).length;
|
|
40
|
+
if (authored === 1 && claudeSubscription)
|
|
39
41
|
return { kind: "claude-sub" };
|
|
40
|
-
if (
|
|
42
|
+
if (authored === 1 && exeModel)
|
|
41
43
|
return { kind: "exe" };
|
|
42
|
-
if (
|
|
43
|
-
return { kind: "
|
|
44
|
+
if (authored === 1 && grokSubscription)
|
|
45
|
+
return { kind: "grok-sub" };
|
|
46
|
+
if (authored > 1) {
|
|
47
|
+
return { kind: "unresolved", reason: "root agent authors more than one model reach helper" };
|
|
44
48
|
}
|
|
45
49
|
}
|
|
46
50
|
if (compiledRouting.kind === "gateway")
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export declare const STALE_KYB_FIX = "npm install -g @kybernesis/create@latest";
|
|
2
|
+
export type SelfVersionResult = {
|
|
3
|
+
kind: "stale";
|
|
4
|
+
installed: string;
|
|
5
|
+
latest: string;
|
|
6
|
+
message: string;
|
|
7
|
+
fix: typeof STALE_KYB_FIX;
|
|
8
|
+
} | {
|
|
9
|
+
kind: "current";
|
|
10
|
+
installed: string;
|
|
11
|
+
latest: string;
|
|
12
|
+
} | {
|
|
13
|
+
kind: "ahead";
|
|
14
|
+
installed: string;
|
|
15
|
+
latest: string;
|
|
16
|
+
} | {
|
|
17
|
+
kind: "unknown";
|
|
18
|
+
installed?: string;
|
|
19
|
+
latest?: string;
|
|
20
|
+
};
|
|
21
|
+
/** Compare the three numeric version components exactly as upgrade historically has. */
|
|
22
|
+
export declare function versionLt(a: string, b: string): boolean;
|
|
23
|
+
/** Look up this CLI's published version. Unknown lookup state is deliberately non-blocking. */
|
|
24
|
+
export declare function checkSelfVersion(): SelfVersionResult;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
export const STALE_KYB_FIX = "npm install -g @kybernesis/create@latest";
|
|
4
|
+
function usableVersion(value) {
|
|
5
|
+
return Boolean(value && /^\d+\.\d+\.\d+$/.test(value));
|
|
6
|
+
}
|
|
7
|
+
/** Compare the three numeric version components exactly as upgrade historically has. */
|
|
8
|
+
export function versionLt(a, b) {
|
|
9
|
+
const pa = a.split(".").map(Number);
|
|
10
|
+
const pb = b.split(".").map(Number);
|
|
11
|
+
for (let i = 0; i < 3; i++) {
|
|
12
|
+
if ((pa[i] ?? 0) < (pb[i] ?? 0))
|
|
13
|
+
return true;
|
|
14
|
+
if ((pa[i] ?? 0) > (pb[i] ?? 0))
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
/** Look up this CLI's published version. Unknown lookup state is deliberately non-blocking. */
|
|
20
|
+
export function checkSelfVersion() {
|
|
21
|
+
let installed;
|
|
22
|
+
try {
|
|
23
|
+
installed = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8")).version;
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return { kind: "unknown" };
|
|
27
|
+
}
|
|
28
|
+
let latest;
|
|
29
|
+
try {
|
|
30
|
+
const result = spawnSync("npm", ["view", "@kybernesis/create", "version"], {
|
|
31
|
+
encoding: "utf8",
|
|
32
|
+
env: process.env,
|
|
33
|
+
});
|
|
34
|
+
if (result.status === 0)
|
|
35
|
+
latest = result.stdout.trim();
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return { kind: "unknown", installed };
|
|
39
|
+
}
|
|
40
|
+
if (!usableVersion(installed) || !usableVersion(latest)) {
|
|
41
|
+
return { kind: "unknown", ...(installed ? { installed } : {}), ...(latest ? { latest } : {}) };
|
|
42
|
+
}
|
|
43
|
+
if (installed === latest)
|
|
44
|
+
return { kind: "current", installed, latest };
|
|
45
|
+
if (versionLt(installed, latest)) {
|
|
46
|
+
return {
|
|
47
|
+
kind: "stale",
|
|
48
|
+
installed,
|
|
49
|
+
latest,
|
|
50
|
+
message: `kyb ${installed} is behind ${latest}. The certified eve version is ` +
|
|
51
|
+
"compiled into this tool, so an old kyb reports an old pin as current.",
|
|
52
|
+
fix: STALE_KYB_FIX,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
return { kind: "ahead", installed, latest };
|
|
56
|
+
}
|
package/dist/templates.d.ts
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
/** File templates written by `kyb init`. Kept in sync with the proven Kyber patterns. */
|
|
2
2
|
import type { ModelScaffoldConfig } from "./model-reach.js";
|
|
3
|
+
/** Exact output of Eve's legacy extension/github-tools registry item. */
|
|
4
|
+
export declare const LEGACY_GITHUB_TOOLS_MOUNT = "import githubTools from \"@github-tools/eve-extension\";\n\nexport default githubTools({});\n";
|
|
5
|
+
/**
|
|
6
|
+
* The managed GitHub extension mount written by init and recognized by upgrade.
|
|
7
|
+
*
|
|
8
|
+
* Eve discovers configured extensions from the direct imported-factory default
|
|
9
|
+
* call, so keep that syntax. An empty include list prevents the dynamic resolver
|
|
10
|
+
* from building any descriptors without a credential, while the lazy provider
|
|
11
|
+
* avoids eager missing-token validation. After GITHUB_TOKEN is added, a restart
|
|
12
|
+
* evaluates the module again and preserves the registry's original `{}` behavior.
|
|
13
|
+
*/
|
|
14
|
+
export declare function githubToolsMountTs(): string;
|
|
3
15
|
export declare const DEPT_DESCRIPTIONS: Record<string, string>;
|
|
4
16
|
export declare function deptDescription(dept: string): string;
|
|
5
17
|
export declare function identityMd(displayName: string, depts: string[]): string;
|
package/dist/templates.js
CHANGED
|
@@ -1,4 +1,35 @@
|
|
|
1
1
|
/** File templates written by `kyb init`. Kept in sync with the proven Kyber patterns. */
|
|
2
|
+
/** Exact output of Eve's legacy extension/github-tools registry item. */
|
|
3
|
+
export const LEGACY_GITHUB_TOOLS_MOUNT = `import githubTools from "@github-tools/eve-extension";
|
|
4
|
+
|
|
5
|
+
export default githubTools({});
|
|
6
|
+
`;
|
|
7
|
+
/**
|
|
8
|
+
* The managed GitHub extension mount written by init and recognized by upgrade.
|
|
9
|
+
*
|
|
10
|
+
* Eve discovers configured extensions from the direct imported-factory default
|
|
11
|
+
* call, so keep that syntax. An empty include list prevents the dynamic resolver
|
|
12
|
+
* from building any descriptors without a credential, while the lazy provider
|
|
13
|
+
* avoids eager missing-token validation. After GITHUB_TOKEN is added, a restart
|
|
14
|
+
* evaluates the module again and preserves the registry's original `{}` behavior.
|
|
15
|
+
*/
|
|
16
|
+
export function githubToolsMountTs() {
|
|
17
|
+
return `import githubTools from "@github-tools/eve-extension";
|
|
18
|
+
|
|
19
|
+
function githubToolsOptions(hasToken = Boolean(process.env.GITHUB_TOKEN)) {
|
|
20
|
+
return hasToken
|
|
21
|
+
? {}
|
|
22
|
+
: {
|
|
23
|
+
include: [],
|
|
24
|
+
token: async () => {
|
|
25
|
+
throw new Error("GITHUB_TOKEN is not set.");
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export default githubTools(githubToolsOptions());
|
|
31
|
+
`;
|
|
32
|
+
}
|
|
2
33
|
export const DEPT_DESCRIPTIONS = {
|
|
3
34
|
finance: "Finance specialist: financials, budgets, spend, revenue, invoices, runway, and financial reporting. Keeps the finance team's own memory workspace. Delegate any finance-shaped task, question, or reporting request here.",
|
|
4
35
|
marketing: "Marketing specialist: campaigns, content, positioning, brand, launches, social, and ads. Keeps the marketing team's own memory workspace. Delegate any marketing-shaped task or question here.",
|
package/dist/upgrade.d.ts
CHANGED
|
@@ -1,7 +1,25 @@
|
|
|
1
1
|
import { type AgentInputLimit } from "./agent-limits.js";
|
|
2
2
|
export declare function agentInputLimitUpgradeMessage(limit: AgentInputLimit): string;
|
|
3
|
+
export type GithubToolsMountRepair = {
|
|
4
|
+
kind: "missing" | "current" | "updated" | "customized";
|
|
5
|
+
} | {
|
|
6
|
+
kind: "error";
|
|
7
|
+
message: string;
|
|
8
|
+
};
|
|
9
|
+
/** Upgrade only the exact registry scaffold; authored GitHub policy is not ours. */
|
|
10
|
+
export declare function repairGithubToolsMount(cwd: string): GithubToolsMountRepair;
|
|
3
11
|
export interface UpgradeOptions {
|
|
12
|
+
allowStale?: boolean;
|
|
13
|
+
host?: true | string;
|
|
4
14
|
skipEval?: boolean;
|
|
5
15
|
yes?: boolean;
|
|
6
16
|
}
|
|
17
|
+
type EvalGatePreflight = {
|
|
18
|
+
kind: "ready";
|
|
19
|
+
} | {
|
|
20
|
+
kind: "unavailable";
|
|
21
|
+
reasons: string[];
|
|
22
|
+
};
|
|
23
|
+
export declare function preflightEvalGate(cwd: string): Promise<EvalGatePreflight>;
|
|
7
24
|
export declare function upgrade(options?: UpgradeOptions): Promise<void>;
|
|
25
|
+
export {};
|
package/dist/upgrade.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { chmodSync, copyFileSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
1
|
+
import { chmodSync, copyFileSync, existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { spawnSync } from "node:child_process";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
+
import { pathToFileURL } from "node:url";
|
|
4
5
|
import { upsertEnv } from "./envfile.js";
|
|
5
6
|
import { reconcileHostArtifact } from "./host-artifacts.js";
|
|
6
7
|
import { findMatchingAgentServiceUnit, repairManageRestart } from "./systemd.js";
|
|
@@ -8,43 +9,11 @@ import { repairTerminalSandboxCleanupHooks } from "./sandbox-cleanup.js";
|
|
|
8
9
|
import { repairRemovedDefaultTools as repairRemovedDefaultTools_ } from "./removed-default-tools.js";
|
|
9
10
|
import { EVE_VERSION, bold, capture, dim, green, parseEnv, red, run, yellow } from "./util.js";
|
|
10
11
|
import { inspectEveAgent } from "./agent-limits.js";
|
|
12
|
+
import { remoteProjectPath, sshTarget } from "./deploy.js";
|
|
13
|
+
import { classifyModelReach } from "./model-reach.js";
|
|
14
|
+
import { checkSelfVersion, versionLt } from "./self-version.js";
|
|
15
|
+
import { LEGACY_GITHUB_TOOLS_MOUNT, githubToolsMountTs } from "./templates.js";
|
|
11
16
|
import { confirmEveUpgrade, inspectBuzzSessions, inspectDurableRuns, reconcileEvalScript, } from "./upgrade-sessions.js";
|
|
12
|
-
function versionLt(a, b) {
|
|
13
|
-
const pa = a.split(".").map(Number);
|
|
14
|
-
const pb = b.split(".").map(Number);
|
|
15
|
-
for (let i = 0; i < 3; i++) {
|
|
16
|
-
if ((pa[i] ?? 0) < (pb[i] ?? 0))
|
|
17
|
-
return true;
|
|
18
|
-
if ((pa[i] ?? 0) > (pb[i] ?? 0))
|
|
19
|
-
return false;
|
|
20
|
-
}
|
|
21
|
-
return false;
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Warn when this CLI is itself out of date.
|
|
25
|
-
*
|
|
26
|
-
* @remarks
|
|
27
|
-
* The certified eve version is a constant compiled INTO this tool, so an old
|
|
28
|
-
* kyb reports an old pin as though it were current — and does it with total
|
|
29
|
-
* confidence, in the one command whose entire job is telling you what current
|
|
30
|
-
* means. That failure runs the wrong way round: it tells a healthy agent it is
|
|
31
|
-
* ahead of certified and in "unsupported territory", which invites someone to
|
|
32
|
-
* downgrade a fleet that was fine.
|
|
33
|
-
*
|
|
34
|
-
* Checked here rather than at install because this is the command where being
|
|
35
|
-
* stale changes the answer.
|
|
36
|
-
*/
|
|
37
|
-
function warnIfStale() {
|
|
38
|
-
const installed = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8")).version;
|
|
39
|
-
const latest = capture("npm", ["view", "@kybernesis/create", "version"])?.trim();
|
|
40
|
-
if (!latest || latest === installed)
|
|
41
|
-
return;
|
|
42
|
-
if (!versionLt(installed, latest))
|
|
43
|
-
return;
|
|
44
|
-
console.log(` ${yellow("!")} kyb ${installed} is behind ${latest}. The certified eve version is ` +
|
|
45
|
-
`compiled into this tool, so an old kyb reports an old pin as current.`);
|
|
46
|
-
console.log(` ${dim("npm install -g @kybernesis/create@latest")}\n`);
|
|
47
|
-
}
|
|
48
17
|
export function agentInputLimitUpgradeMessage(limit) {
|
|
49
18
|
switch (limit.kind) {
|
|
50
19
|
case "explicit-numeric":
|
|
@@ -223,6 +192,48 @@ function repairSandboxCleanupHooks(cwd, deps) {
|
|
|
223
192
|
console.log(` ${green("+")} installed terminal sandbox cleanup for ${added.length} agent scope(s) ` +
|
|
224
193
|
`${dim("(completed and failed sessions only)")}\n`);
|
|
225
194
|
}
|
|
195
|
+
/** Upgrade only the exact registry scaffold; authored GitHub policy is not ours. */
|
|
196
|
+
export function repairGithubToolsMount(cwd) {
|
|
197
|
+
const path = join(cwd, "agent/extensions/github.ts");
|
|
198
|
+
if (!existsSync(path))
|
|
199
|
+
return { kind: "missing" };
|
|
200
|
+
let current;
|
|
201
|
+
try {
|
|
202
|
+
current = readFileSync(path, "utf8");
|
|
203
|
+
}
|
|
204
|
+
catch (error) {
|
|
205
|
+
return { kind: "error", message: `could not read agent/extensions/github.ts: ${error.message}` };
|
|
206
|
+
}
|
|
207
|
+
const desired = githubToolsMountTs();
|
|
208
|
+
if (current === desired)
|
|
209
|
+
return { kind: "current" };
|
|
210
|
+
if (current !== LEGACY_GITHUB_TOOLS_MOUNT)
|
|
211
|
+
return { kind: "customized" };
|
|
212
|
+
const temp = `${path}.kyb-${process.pid}`;
|
|
213
|
+
try {
|
|
214
|
+
writeFileSync(temp, desired);
|
|
215
|
+
renameSync(temp, path);
|
|
216
|
+
return { kind: "updated" };
|
|
217
|
+
}
|
|
218
|
+
catch (error) {
|
|
219
|
+
rmSync(temp, { force: true });
|
|
220
|
+
return { kind: "error", message: `could not update agent/extensions/github.ts: ${error.message}` };
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
function reportGithubToolsMountRepair(cwd) {
|
|
224
|
+
const result = repairGithubToolsMount(cwd);
|
|
225
|
+
if (result.kind === "updated") {
|
|
226
|
+
console.log(` ${green("+")} updated agent/extensions/github.ts ` +
|
|
227
|
+
`${dim("(GitHub tools stay off until GITHUB_TOKEN is set)")}`);
|
|
228
|
+
}
|
|
229
|
+
else if (result.kind === "customized") {
|
|
230
|
+
console.log(` ${yellow("!")} agent/extensions/github.ts is customized, so it was left unchanged.\n` +
|
|
231
|
+
` To adopt the quiet no-token behavior, compare it with a new \`kyb init --engineer\` scaffold.`);
|
|
232
|
+
}
|
|
233
|
+
else if (result.kind === "error") {
|
|
234
|
+
console.log(` ${yellow("!")} ${result.message}; leaving the file unchanged.`);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
226
237
|
/**
|
|
227
238
|
* Keep package-owned host files synchronized with the package that installed them.
|
|
228
239
|
*
|
|
@@ -357,6 +368,141 @@ function repairEvalCommand(cwd) {
|
|
|
357
368
|
` Manual remediation: make this command invoke kyb-eval instead of eve eval, preserving its setup and arguments.\n` +
|
|
358
369
|
` Current scripts.eval: ${dim(JSON.stringify(current))}`);
|
|
359
370
|
}
|
|
371
|
+
const EVAL_GATE_UNAVAILABLE_EXIT = 2;
|
|
372
|
+
const DEFAULT_EXE_MODELS_URL = "https://llm.int.exe.xyz/models.json";
|
|
373
|
+
function evalGateEnvironment(cwd) {
|
|
374
|
+
const envPath = join(cwd, ".env.local");
|
|
375
|
+
return {
|
|
376
|
+
...(existsSync(envPath) ? parseEnv(readFileSync(envPath, "utf8")) : {}),
|
|
377
|
+
...process.env,
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
async function routeAnswers(url) {
|
|
381
|
+
try {
|
|
382
|
+
await fetch(url, { signal: AbortSignal.timeout(6000) });
|
|
383
|
+
return true;
|
|
384
|
+
}
|
|
385
|
+
catch {
|
|
386
|
+
return false;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
async function claudeSubscriptionProxyReady(cwd) {
|
|
390
|
+
const module = join(cwd, "node_modules/@kybernesis/exe/dist/claude.js");
|
|
391
|
+
if (!existsSync(module))
|
|
392
|
+
return false;
|
|
393
|
+
try {
|
|
394
|
+
const loaded = (await import(pathToFileURL(module).href));
|
|
395
|
+
if (typeof loaded.claudeProxyReady !== "function")
|
|
396
|
+
return false;
|
|
397
|
+
return (await loaded.claudeProxyReady()).ok;
|
|
398
|
+
}
|
|
399
|
+
catch {
|
|
400
|
+
return false;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
/** Resolve an exe-backed judge from the provider the authored config actually calls. */
|
|
404
|
+
function exeJudgeUrl(cwd, env) {
|
|
405
|
+
const paths = [join(cwd, "evals/evals.config.ts"), join(cwd, "evals.config.ts")];
|
|
406
|
+
const path = paths.find((candidate) => existsSync(candidate));
|
|
407
|
+
if (!path)
|
|
408
|
+
return null;
|
|
409
|
+
const source = readFileSync(path, "utf8");
|
|
410
|
+
const judgeProvider = /judge\s*:\s*\{[\s\S]*?model\s*:\s*([A-Za-z_$][\w$]*)\s*\(/.exec(source)?.[1];
|
|
411
|
+
if (!judgeProvider)
|
|
412
|
+
return null;
|
|
413
|
+
const escaped = judgeProvider.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
414
|
+
const providerBody = new RegExp(`(?:const|let)\\s+${escaped}\\s*=\\s*create[A-Za-z]+\\s*\\(\\s*\\{([\\s\\S]*?)\\}\\s*\\)`).exec(source)?.[1];
|
|
415
|
+
if (!providerBody)
|
|
416
|
+
return /EXE_LLM_URL|llm\.int\.exe\.xyz/.test(source) ? undefined : null;
|
|
417
|
+
if (/EXE_LLM_URL/.test(providerBody))
|
|
418
|
+
return env.EXE_LLM_URL || DEFAULT_EXE_MODELS_URL;
|
|
419
|
+
const baseUrl = /baseURL\s*:\s*["']([^"']+)["']/.exec(providerBody)?.[1];
|
|
420
|
+
if (baseUrl?.includes("llm.int.exe.xyz"))
|
|
421
|
+
return baseUrl;
|
|
422
|
+
return null;
|
|
423
|
+
}
|
|
424
|
+
export async function preflightEvalGate(cwd) {
|
|
425
|
+
const env = evalGateEnvironment(cwd);
|
|
426
|
+
const agentPath = join(cwd, "agent/agent.ts");
|
|
427
|
+
const authoredSource = existsSync(agentPath) ? readFileSync(agentPath, "utf8") : null;
|
|
428
|
+
const inspection = inspectEveAgent(cwd, env);
|
|
429
|
+
const reach = classifyModelReach(authoredSource, inspection?.modelRouting ?? {
|
|
430
|
+
kind: "unresolved",
|
|
431
|
+
reason: "eve info failed before compiled model routing could be inspected",
|
|
432
|
+
});
|
|
433
|
+
const reasons = [];
|
|
434
|
+
switch (reach.kind) {
|
|
435
|
+
case "claude-sub":
|
|
436
|
+
if (!(await claudeSubscriptionProxyReady(cwd)))
|
|
437
|
+
reasons.push("the agent model proxy is unreachable");
|
|
438
|
+
break;
|
|
439
|
+
case "exe":
|
|
440
|
+
if (!(await routeAnswers(env.EXE_LLM_URL || DEFAULT_EXE_MODELS_URL)))
|
|
441
|
+
reasons.push("the agent model route is unreachable");
|
|
442
|
+
break;
|
|
443
|
+
case "unresolved":
|
|
444
|
+
reasons.push(`the agent model route could not be resolved (${reach.reason})`);
|
|
445
|
+
break;
|
|
446
|
+
case "grok-sub":
|
|
447
|
+
case "gateway":
|
|
448
|
+
case "direct-provider":
|
|
449
|
+
break;
|
|
450
|
+
}
|
|
451
|
+
const judgeUrl = exeJudgeUrl(cwd, env);
|
|
452
|
+
if (judgeUrl === undefined)
|
|
453
|
+
reasons.push("the eve judge route could not be resolved");
|
|
454
|
+
else if (judgeUrl && !(await routeAnswers(judgeUrl)))
|
|
455
|
+
reasons.push("the eve judge is unreachable");
|
|
456
|
+
return reasons.length === 0 ? { kind: "ready" } : { kind: "unavailable", reasons };
|
|
457
|
+
}
|
|
458
|
+
function hostEvalCommand(cwd, target) {
|
|
459
|
+
const host = target ?? "<host>";
|
|
460
|
+
return `ssh ${host} ${shellQuote(`cd ${remoteProjectPath(cwd)} && npm run eval`)}`;
|
|
461
|
+
}
|
|
462
|
+
function reportEvalGateUnavailable(cwd, target, reasons) {
|
|
463
|
+
console.log(`\n${yellow("The eval gate for this agent can only run on its host (the model proxy and the eve judge are only reachable there).")}`);
|
|
464
|
+
for (const reason of reasons)
|
|
465
|
+
console.log(` ${dim(reason)}`);
|
|
466
|
+
console.log(`Run it there: ${bold(hostEvalCommand(cwd, target ?? undefined))}\n`);
|
|
467
|
+
process.exitCode = EVAL_GATE_UNAVAILABLE_EXIT;
|
|
468
|
+
}
|
|
469
|
+
async function runUpgradeEvalGate(cwd, host) {
|
|
470
|
+
if (host !== undefined) {
|
|
471
|
+
const target = sshTarget(cwd, typeof host === "string" && host.length > 0 ? host : undefined);
|
|
472
|
+
if (!target) {
|
|
473
|
+
reportEvalGateUnavailable(cwd, null, ["no ssh target is configured"]);
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
console.log(bold(`\nRunning the eval gate on ${target} (${remoteProjectPath(cwd)}) — deploy only on green …\n`));
|
|
477
|
+
const result = spawnSync("ssh", [target, `cd ${remoteProjectPath(cwd)} && npm run eval`], {
|
|
478
|
+
cwd,
|
|
479
|
+
env: process.env,
|
|
480
|
+
stdio: "inherit",
|
|
481
|
+
});
|
|
482
|
+
if (result.status === 0) {
|
|
483
|
+
console.log(`\n${green("✓ Upgrade green.")} Deploy with: ${bold("npx eve deploy")}\n`);
|
|
484
|
+
}
|
|
485
|
+
else {
|
|
486
|
+
console.log(`\n${red("✗ Evals failed after upgrade.")} Do NOT deploy — inspect .eve/evals/ artifacts on the host.\n`);
|
|
487
|
+
process.exitCode = 1;
|
|
488
|
+
}
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
const preflight = await preflightEvalGate(cwd);
|
|
492
|
+
if (preflight.kind === "unavailable") {
|
|
493
|
+
reportEvalGateUnavailable(cwd, sshTarget(cwd), preflight.reasons);
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
console.log(bold("\nRunning the eval gate (npm run eval) — deploy only on green …\n"));
|
|
497
|
+
const ok = run("npm", ["run", "eval"], { cwd, allowFail: true });
|
|
498
|
+
if (ok) {
|
|
499
|
+
console.log(`\n${green("✓ Upgrade green.")} Deploy with: ${bold("npx eve deploy")}\n`);
|
|
500
|
+
}
|
|
501
|
+
else {
|
|
502
|
+
console.log(`\n${red("✗ Evals failed after upgrade.")} Do NOT deploy — inspect .eve/evals/ artifacts.\n`);
|
|
503
|
+
process.exitCode = 1;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
360
506
|
function upgradeEnvironment(cwd) {
|
|
361
507
|
const envPath = join(cwd, ".env.local");
|
|
362
508
|
const env = {
|
|
@@ -507,6 +653,16 @@ function startStoppedBridge(cwd, unit) {
|
|
|
507
653
|
return false;
|
|
508
654
|
}
|
|
509
655
|
export async function upgrade(options = {}) {
|
|
656
|
+
console.log(bold("\nkyb upgrade — checking @kybernesis/* and eve against npm\n"));
|
|
657
|
+
const selfVersion = checkSelfVersion();
|
|
658
|
+
if (selfVersion.kind === "stale") {
|
|
659
|
+
console.log(` ${yellow("!")} ${selfVersion.message}`);
|
|
660
|
+
console.log(` ${dim(selfVersion.fix)}\n`);
|
|
661
|
+
if (!options.allowStale) {
|
|
662
|
+
process.exitCode = 1;
|
|
663
|
+
return;
|
|
664
|
+
}
|
|
665
|
+
}
|
|
510
666
|
const cwd = process.cwd();
|
|
511
667
|
const packagePath = join(cwd, "package.json");
|
|
512
668
|
const pkg = JSON.parse(readFileSync(packagePath, "utf8"));
|
|
@@ -514,8 +670,6 @@ export async function upgrade(options = {}) {
|
|
|
514
670
|
...(pkg.dependencies ?? {}),
|
|
515
671
|
...(pkg.devDependencies ?? {}),
|
|
516
672
|
};
|
|
517
|
-
console.log(bold("\nkyb upgrade — checking @kybernesis/* and eve against npm\n"));
|
|
518
|
-
warnIfStale();
|
|
519
673
|
reportAgentInputLimit(cwd);
|
|
520
674
|
const entries = dependencyEntries(pkg);
|
|
521
675
|
const installedVersions = new Map();
|
|
@@ -597,6 +751,7 @@ export async function upgrade(options = {}) {
|
|
|
597
751
|
repairBuzzSetup(cwd, deps);
|
|
598
752
|
repairRemovedDefaultTools(cwd);
|
|
599
753
|
repairSandboxCleanupHooks(cwd, deps);
|
|
754
|
+
reportGithubToolsMountRepair(cwd);
|
|
600
755
|
repairHostArtifacts(cwd, deps);
|
|
601
756
|
repairEvalCommand(cwd);
|
|
602
757
|
repairManageRestart(cwd, deps);
|
|
@@ -654,6 +809,7 @@ export async function upgrade(options = {}) {
|
|
|
654
809
|
repairBuzzSetup(cwd, deps);
|
|
655
810
|
repairRemovedDefaultTools(cwd);
|
|
656
811
|
repairSandboxCleanupHooks(cwd, deps);
|
|
812
|
+
reportGithubToolsMountRepair(cwd);
|
|
657
813
|
repairHostArtifacts(cwd, deps);
|
|
658
814
|
repairEvalCommand(cwd);
|
|
659
815
|
repairManageRestart(cwd, deps);
|
|
@@ -666,13 +822,5 @@ export async function upgrade(options = {}) {
|
|
|
666
822
|
console.log(yellow("\nEval gate SKIPPED (--skip-eval). Run `npm run eval` before deploying.\n"));
|
|
667
823
|
return;
|
|
668
824
|
}
|
|
669
|
-
|
|
670
|
-
const ok = run("npm", ["run", "eval"], { cwd, allowFail: true });
|
|
671
|
-
if (ok) {
|
|
672
|
-
console.log(`\n${green("✓ Upgrade green.")} Deploy with: ${bold("npx eve deploy")}\n`);
|
|
673
|
-
}
|
|
674
|
-
else {
|
|
675
|
-
console.log(`\n${red("✗ Evals failed after upgrade.")} Do NOT deploy — inspect .eve/evals/ artifacts.\n`);
|
|
676
|
-
process.exit(1);
|
|
677
|
-
}
|
|
825
|
+
await runUpgradeEvalGate(cwd, options.host);
|
|
678
826
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kybernesis/create",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.9",
|
|
4
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",
|