@kybernesis/create 0.10.0 → 0.12.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/doctor.js +25 -0
- package/dist/init.js +39 -0
- package/dist/upgrade.js +33 -1
- package/package.json +1 -1
- package/skills/fde-engagement/references/playbook.md +47 -0
package/dist/doctor.js
CHANGED
|
@@ -250,6 +250,31 @@ export async function doctor() {
|
|
|
250
250
|
add("warn", "self-hosted: export .env.local into the server process", "eve start does NOT read it; use the supervision script from @kybernesis/exe (scripts/eve-server.sh)");
|
|
251
251
|
add("warn", "self-hosted: start via `npx eve start`, not `node .output/server/index.mjs`", "sandbox templates are prewarmed by the CLI; starting the server directly skips prewarm and every sandbox tool fails with SandboxTemplateNotProvisionedError");
|
|
252
252
|
}
|
|
253
|
+
/**
|
|
254
|
+
* A self-hosted agent answering everything twice.
|
|
255
|
+
*
|
|
256
|
+
* The local queue delivers a turn by POSTing it to this same server and
|
|
257
|
+
* holds that connection open for the whole turn, but its client gives up
|
|
258
|
+
* after 30 seconds by default. Every turn slower than that is redelivered,
|
|
259
|
+
* and the workflow re-executes steps that already ran — so the person gets
|
|
260
|
+
* two differently-worded answers to one question, and the log says only
|
|
261
|
+
* that a retry recovered. It is reported as the model being odd, which
|
|
262
|
+
* sends the search nowhere near the transport.
|
|
263
|
+
*
|
|
264
|
+
* Hosted agents never see it; real queue infrastructure runs there. This is
|
|
265
|
+
* a cost of self-hosting that nothing in the environment announces.
|
|
266
|
+
*/
|
|
267
|
+
const QUEUE_TIMEOUT_FLOOR_MS = 120_000;
|
|
268
|
+
const shortQueueTimeouts = [
|
|
269
|
+
"WORKFLOW_LOCAL_HEADERS_TIMEOUT_MS",
|
|
270
|
+
"WORKFLOW_LOCAL_BODY_TIMEOUT_MS",
|
|
271
|
+
].filter((name) => Number(env[name] ?? 30_000) < QUEUE_TIMEOUT_FLOOR_MS);
|
|
272
|
+
if (shortQueueTimeouts.length === 0) {
|
|
273
|
+
add("pass", "local queue delivery survives turns longer than 30s");
|
|
274
|
+
}
|
|
275
|
+
else {
|
|
276
|
+
add("fail", `self-hosted: ${shortQueueTimeouts.join(" and ")} left at the 30s default`, "one queue delivery holds a connection open for the entire turn, so any turn slower than the timeout is redelivered and its steps re-run — the agent answers the same question twice, with two different answers, and nothing reports an error. Set both to 900000 in .env.local and restart the server");
|
|
277
|
+
}
|
|
253
278
|
// The exe VM sandbox backend needs a credential that cannot be scoped.
|
|
254
279
|
// Surface the blast radius here, where it is still cheap to change course.
|
|
255
280
|
const sandboxFile = join(cwd, "agent/sandbox/sandbox.ts");
|
package/dist/init.js
CHANGED
|
@@ -166,6 +166,21 @@ export async function init(rawName, options = {}) {
|
|
|
166
166
|
* curl https://llm.int.exe.xyz/models.json
|
|
167
167
|
*/
|
|
168
168
|
known.EXE_MODEL = "";
|
|
169
|
+
/**
|
|
170
|
+
* Longer than any turn, because the alternative is answering twice.
|
|
171
|
+
*
|
|
172
|
+
* The local queue delivers a turn by POSTing it to this same server and
|
|
173
|
+
* holds the connection open until the turn finishes, but its client gives
|
|
174
|
+
* up after 30 seconds by default. Any turn slower than that is redelivered
|
|
175
|
+
* and its steps re-run, so the person gets two differently-worded answers
|
|
176
|
+
* to one question with nothing in any log that looks like a fault.
|
|
177
|
+
*
|
|
178
|
+
* Written at scaffold rather than documented: it only affects self-hosted
|
|
179
|
+
* agents, it has one sensible value, and the failure it prevents is one
|
|
180
|
+
* nobody recognises in time.
|
|
181
|
+
*/
|
|
182
|
+
known.WORKFLOW_LOCAL_HEADERS_TIMEOUT_MS = "900000";
|
|
183
|
+
known.WORKFLOW_LOCAL_BODY_TIMEOUT_MS = "900000";
|
|
169
184
|
}
|
|
170
185
|
upsertEnv(dir, known);
|
|
171
186
|
if (!options.yes)
|
|
@@ -194,6 +209,30 @@ export async function init(rawName, options = {}) {
|
|
|
194
209
|
catch {
|
|
195
210
|
console.log(yellow(" ! could not install scripts/eve-server.sh — copy it from node_modules/@kybernesis/exe/scripts/"));
|
|
196
211
|
}
|
|
212
|
+
/**
|
|
213
|
+
* The Claude subscription, as a script rather than a procedure.
|
|
214
|
+
*
|
|
215
|
+
* Same reasoning as the restart script above, and the same history: the
|
|
216
|
+
* provider (`claudeSubscription()`) was generalised into @kybernesis/exe
|
|
217
|
+
* after the first agent used it, but STANDING THE PROXY UP stayed a thing
|
|
218
|
+
* someone did by hand on one VM. So the capability was in every agent's
|
|
219
|
+
* packages while the only written procedure was a patch README telling the
|
|
220
|
+
* next person to clone a third-party repository — which is how a client
|
|
221
|
+
* ends up being walked through a git checkout by their consultant.
|
|
222
|
+
*
|
|
223
|
+
* Installed unconditionally for an exe host: it costs one file, and the
|
|
224
|
+
* alternative is rediscovering the procedure per deployment.
|
|
225
|
+
*/
|
|
226
|
+
try {
|
|
227
|
+
const proxySource = join(dir, "node_modules/@kybernesis/exe/scripts/claude-subscription.sh");
|
|
228
|
+
const proxyTarget = join(dir, "scripts/claude-subscription.sh");
|
|
229
|
+
copyFileSync(proxySource, proxyTarget);
|
|
230
|
+
chmodSync(proxyTarget, 0o755);
|
|
231
|
+
console.log(dim(" scripts/claude-subscription.sh — put this agent on a Claude subscription, no API key"));
|
|
232
|
+
}
|
|
233
|
+
catch {
|
|
234
|
+
console.log(yellow(" ! could not install scripts/claude-subscription.sh — copy it from node_modules/@kybernesis/exe/scripts/"));
|
|
235
|
+
}
|
|
197
236
|
/**
|
|
198
237
|
* Point the management routes at that script.
|
|
199
238
|
*
|
package/dist/upgrade.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
+
import { upsertEnv } from "./envfile.js";
|
|
3
4
|
import { EVE_VERSION, bold, capture, dim, green, red, run, yellow } from "./util.js";
|
|
4
5
|
/**
|
|
5
6
|
* Which packages to upgrade: every `@kybernesis/*` this agent depends on.
|
|
@@ -56,12 +57,43 @@ function warnIfStale() {
|
|
|
56
57
|
`compiled into this tool, so an old kyb reports an old pin as current.`);
|
|
57
58
|
console.log(` ${dim("npm install -g @kybernesis/create@latest")}\n`);
|
|
58
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* Raise the local queue's delivery timeouts on an agent that already exists.
|
|
62
|
+
*
|
|
63
|
+
* @remarks
|
|
64
|
+
* Written as a repair rather than a warning because of what the bug looks like
|
|
65
|
+
* from outside: the agent answers the same question twice, in two different
|
|
66
|
+
* wordings, and no error appears in any log. Nobody reports that as a transport
|
|
67
|
+
* problem, so a warning would be read past — and the correct value is not a
|
|
68
|
+
* judgement call, it is "longer than a turn".
|
|
69
|
+
*
|
|
70
|
+
* Only for self-hosted agents. Hosted ones use real queue infrastructure and
|
|
71
|
+
* never touch this transport, so the variables would be noise in their
|
|
72
|
+
* environment.
|
|
73
|
+
*/
|
|
74
|
+
function repairLocalQueueTimeouts(cwd, deps) {
|
|
75
|
+
if (!deps["@kybernesis/exe"])
|
|
76
|
+
return;
|
|
77
|
+
const path = join(cwd, ".env.local");
|
|
78
|
+
if (!existsSync(path))
|
|
79
|
+
return;
|
|
80
|
+
const text = readFileSync(path, "utf8");
|
|
81
|
+
const missing = ["WORKFLOW_LOCAL_HEADERS_TIMEOUT_MS", "WORKFLOW_LOCAL_BODY_TIMEOUT_MS"].filter((name) => !new RegExp(`^${name}=`, "m").test(text));
|
|
82
|
+
if (missing.length === 0)
|
|
83
|
+
return;
|
|
84
|
+
upsertEnv(cwd, Object.fromEntries(missing.map((name) => [name, "900000"])));
|
|
85
|
+
console.log(` ${green("+")} raised the local queue delivery timeout in .env.local ${dim("(was 30s)")}\n` +
|
|
86
|
+
` ${dim("A delivery holds one connection open for the whole turn. Below this, any turn")}\n` +
|
|
87
|
+
` ${dim("slower than 30s was redelivered and its steps re-run — the agent answered twice.")}\n` +
|
|
88
|
+
` ${dim("Takes effect on the next server restart.")}\n`);
|
|
89
|
+
}
|
|
59
90
|
export async function upgrade(skipEval) {
|
|
60
91
|
const cwd = process.cwd();
|
|
61
92
|
const pkg = JSON.parse(readFileSync(join(cwd, "package.json"), "utf8"));
|
|
62
93
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
63
94
|
console.log(bold("\nkyb upgrade — checking @kybernesis/* and eve against npm\n"));
|
|
64
95
|
warnIfStale();
|
|
96
|
+
repairLocalQueueTimeouts(cwd, deps);
|
|
65
97
|
const toUpgrade = [];
|
|
66
98
|
const unresolved = [];
|
|
67
99
|
for (const name of kybernesisPackages(deps)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kybernesis/create",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
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",
|
|
@@ -1968,6 +1968,53 @@ nowhere in its context. Verify from the host — the configured model id and the
|
|
|
1968
1968
|
credential in use — never by asking the agent. Expect a client to ask it in a
|
|
1969
1969
|
demo, and have the real answer ready.
|
|
1970
1970
|
|
|
1971
|
+
**Claude, on a Claude Max / Pro / Claude Code subscription.** The one that is
|
|
1972
|
+
a process rather than a file. Anthropic's billing validator accepts an OAuth
|
|
1973
|
+
bearer *instead of* an API key, and that bearer expires — so something has to
|
|
1974
|
+
own the refresh. A small proxy holds Claude Code's own credentials, refreshes
|
|
1975
|
+
them, and swaps them in; the agent speaks ordinary Anthropic API to loopback and
|
|
1976
|
+
never holds a long-lived secret.
|
|
1977
|
+
|
|
1978
|
+
```bash
|
|
1979
|
+
# on the host, installed by kyb init for an exe host
|
|
1980
|
+
bash scripts/claude-subscription.sh up
|
|
1981
|
+
bash scripts/claude-subscription.sh login # "Sign in with Claude", never an API key
|
|
1982
|
+
bash scripts/claude-subscription.sh status # signed in? bound to loopback?
|
|
1983
|
+
```
|
|
1984
|
+
|
|
1985
|
+
```ts title="agent/agent.ts"
|
|
1986
|
+
import { createAnthropic } from "@ai-sdk/anthropic";
|
|
1987
|
+
import { claudeSubscription, CLAUDE_SUBSCRIPTION_CONTEXT_WINDOW } from "@kybernesis/exe";
|
|
1988
|
+
|
|
1989
|
+
export default defineAgent({
|
|
1990
|
+
model: claudeSubscription({ model: "claude-opus-5", createAnthropic }),
|
|
1991
|
+
modelContextWindowTokens: CLAUDE_SUBSCRIPTION_CONTEXT_WINDOW,
|
|
1992
|
+
});
|
|
1993
|
+
```
|
|
1994
|
+
|
|
1995
|
+
Four things to know before you promise it:
|
|
1996
|
+
|
|
1997
|
+
- **The exe LLM integration also serves `anthropic/*` ids, and that is NOT this.**
|
|
1998
|
+
It reaches Anthropic through a gateway, which bills metered usage. Same model,
|
|
1999
|
+
entirely different invoice. If the point is that the client pays nothing
|
|
2000
|
+
incremental, it has to be the proxy.
|
|
2001
|
+
- **If the agent searches the web, build the patched image** —
|
|
2002
|
+
`scripts/claude-subscription.sh build-patched`. The published proxy renames
|
|
2003
|
+
provider-defined tools, which Anthropic validates by name, and the failure
|
|
2004
|
+
(`tools.N.web_search_20250305.name: Input should be 'web_search'`) reads like
|
|
2005
|
+
a bug in the agent's own tool definitions.
|
|
2006
|
+
- **The sign-in is per host and interactive** — a browser step, once, in the
|
|
2007
|
+
container. It survives restarts because it lives in a named volume, but a new
|
|
2008
|
+
VM needs its own.
|
|
2009
|
+
- **It is a process to keep alive.** If the container stops, every turn fails
|
|
2010
|
+
with a connection error from inside the model SDK, which reads like the model
|
|
2011
|
+
being down. `hostPreflight({ claudeProxyUrl })` asks about it at boot; the
|
|
2012
|
+
restart policy keeps it up.
|
|
2013
|
+
|
|
2014
|
+
Scope it honestly with the client: this is their own subscription, on their own
|
|
2015
|
+
infrastructure, for their own agent. It is not a shared gateway or a resale of
|
|
2016
|
+
Anthropic access, and it should not be built as one.
|
|
2017
|
+
|
|
1971
2018
|
### 11.5 Third-party APIs: broker the credential, pin the version
|
|
1972
2019
|
|
|
1973
2020
|
Do not put a client's API token on the agent host. Put it in an exe.dev
|