@kybernesis/create 0.24.1 → 0.24.3

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.
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Give every `exeModel({ …, createOpenAI })` call in an agent the Anthropic
3
+ * factory too.
4
+ *
5
+ * @remarks
6
+ * Claude on the exe gateway is served on its Messages API, not the OpenAI one.
7
+ * Older scaffolds wrote subagents such as the builder with only `createOpenAI`
8
+ * and a Claude default (`anthropic/claude-sonnet-5`). That never had a working
9
+ * route, and since exe 0.17 `exeModel` refuses it at load, so the agent's whole
10
+ * eval suite stops before the first case and an update is rolled back for a
11
+ * file nobody touched. Passing `createAnthropic` as well is harmless for a
12
+ * non-Claude id (exeModel only uses it for `anthropic/…`), so the repair is
13
+ * unconditional for any call that lacks it.
14
+ *
15
+ * Returns the agent-relative paths it changed.
16
+ */
17
+ export declare function repairExeClaudeRoute(cwd: string): string[];
18
+ /** The source with `createAnthropic` passed to each exeModel call that has only `createOpenAI`, and imported. */
19
+ export declare function withAnthropicFactory(source: string): string;
@@ -0,0 +1,69 @@
1
+ import { existsSync, readdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
2
+ import { join, relative } from "node:path";
3
+ /**
4
+ * Give every `exeModel({ …, createOpenAI })` call in an agent the Anthropic
5
+ * factory too.
6
+ *
7
+ * @remarks
8
+ * Claude on the exe gateway is served on its Messages API, not the OpenAI one.
9
+ * Older scaffolds wrote subagents such as the builder with only `createOpenAI`
10
+ * and a Claude default (`anthropic/claude-sonnet-5`). That never had a working
11
+ * route, and since exe 0.17 `exeModel` refuses it at load, so the agent's whole
12
+ * eval suite stops before the first case and an update is rolled back for a
13
+ * file nobody touched. Passing `createAnthropic` as well is harmless for a
14
+ * non-Claude id (exeModel only uses it for `anthropic/…`), so the repair is
15
+ * unconditional for any call that lacks it.
16
+ *
17
+ * Returns the agent-relative paths it changed.
18
+ */
19
+ export function repairExeClaudeRoute(cwd) {
20
+ const root = join(cwd, "agent");
21
+ if (!existsSync(root))
22
+ return [];
23
+ const changed = [];
24
+ for (const file of sourceFiles(root)) {
25
+ const source = readFileSync(file, "utf8");
26
+ const next = withAnthropicFactory(source);
27
+ if (next === source)
28
+ continue;
29
+ writeFileSync(file, next);
30
+ changed.push(relative(cwd, file));
31
+ }
32
+ return changed;
33
+ }
34
+ /** The source with `createAnthropic` passed to each exeModel call that has only `createOpenAI`, and imported. */
35
+ export function withAnthropicFactory(source) {
36
+ if (!/\bexeModel\s*\(/.test(source))
37
+ return source;
38
+ let touched = false;
39
+ const next = source.replace(/\bexeModel\s*\(\s*\{([^{}]*)\}\s*\)/g, (call, body) => {
40
+ if (!/\bcreateOpenAI\b/.test(body) || /\bcreateAnthropic\b/.test(body))
41
+ return call;
42
+ touched = true;
43
+ return call.replace(/\bcreateOpenAI\b/, "createOpenAI, createAnthropic");
44
+ });
45
+ if (!touched)
46
+ return source;
47
+ if (/\bimport\s*\{[^}]*\bcreateAnthropic\b[^}]*\}\s*from\s*["']@ai-sdk\/anthropic["']/.test(next))
48
+ return next;
49
+ const openaiImport = /^import\s*\{[^}]*\bcreateOpenAI\b[^}]*\}\s*from\s*["']@ai-sdk\/openai["'];?[^\n]*\n/m.exec(next);
50
+ const line = 'import { createAnthropic } from "@ai-sdk/anthropic";\n';
51
+ if (openaiImport) {
52
+ const at = openaiImport.index + openaiImport[0].length;
53
+ return next.slice(0, at) + line + next.slice(at);
54
+ }
55
+ return line + next;
56
+ }
57
+ function sourceFiles(dir) {
58
+ const out = [];
59
+ for (const entry of readdirSync(dir)) {
60
+ if (entry === "node_modules" || entry.startsWith("."))
61
+ continue;
62
+ const full = join(dir, entry);
63
+ if (statSync(full).isDirectory())
64
+ out.push(...sourceFiles(full));
65
+ else if (/\.(ts|mts|js|mjs)$/.test(entry))
66
+ out.push(full);
67
+ }
68
+ return out;
69
+ }
package/dist/upgrade.js CHANGED
@@ -11,6 +11,7 @@ import { dockerPruneCronArtifact } from "./docker-prune-cron.js";
11
11
  import { newestOnLine } from "./on-line-version.js";
12
12
  import { findMatchingAgentServiceUnit, repairManageRestart } from "./systemd.js";
13
13
  import { repairTerminalSandboxCleanupHooks } from "./sandbox-cleanup.js";
14
+ import { repairExeClaudeRoute } from "./exe-claude-route.js";
14
15
  import { repairOptInTools, repairRemovedDefaultTools as repairRemovedDefaultTools_ } from "./removed-default-tools.js";
15
16
  import { EVE_VERSION, bold, capture, dim, green, parseEnv, red, run, yellow } from "./util.js";
16
17
  import { inspectEveAgent } from "./agent-limits.js";
@@ -75,6 +76,25 @@ function repairLocalQueueTimeouts(cwd, deps) {
75
76
  ` ${dim("slower than 30s was redelivered and its steps re-run — the agent answered twice.")}\n` +
76
77
  ` ${dim("Takes effect on the next server restart.")}\n`);
77
78
  }
79
+ /** Route Claude ids through the gateway's Messages API wherever an agent builds an exe model (see exe-claude-route.ts). */
80
+ function repairExeClaudeRoutes(cwd, deps) {
81
+ if (!deps["@kybernesis/exe"])
82
+ return;
83
+ const changed = repairExeClaudeRoute(cwd);
84
+ if (changed.length === 0)
85
+ return;
86
+ if (!deps["@ai-sdk/anthropic"]) {
87
+ const added = commandResult("npm", ["install", "@ai-sdk/anthropic"], cwd);
88
+ if (added.status !== 0) {
89
+ console.log(red(` ✗ could not install @ai-sdk/anthropic for the Claude route:\n${added.stderr.trim()}`));
90
+ process.exitCode = 1;
91
+ return;
92
+ }
93
+ }
94
+ console.log(` ${green("+")} passed createAnthropic to exeModel in ${changed.join(", ")}\n` +
95
+ ` ${dim("Claude on the exe gateway is served on its Messages API; with only createOpenAI")}\n` +
96
+ ` ${dim("a Claude id has no route, and exe 0.17+ refuses it when the agent loads.")}\n`);
97
+ }
78
98
  /**
79
99
  * Finish a Buzz install that a version bump alone leaves half-done.
80
100
  *
@@ -582,7 +602,10 @@ function exeJudgeUrl(cwd, env) {
582
602
  if (!judgeProvider)
583
603
  return null;
584
604
  const escaped = judgeProvider.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
585
- const providerBody = new RegExp(`(?:const|let)\\s+${escaped}\\s*=\\s*create[A-Za-z]+\\s*\\(\\s*\\{([\\s\\S]*?)\\}\\s*\\)`).exec(source)?.[1];
605
+ // The provider may be made inline (`model: createAnthropic({ … }).evaluationModel(…)`)
606
+ // as well as bound to a name first; both carry the base URL in the same object.
607
+ const inline = /judge\s*:\s*\{[\s\S]*?model\s*:\s*create[A-Za-z]+\s*\(\s*\{([\s\S]*?)\}\s*\)/.exec(source)?.[1];
608
+ const providerBody = inline ?? new RegExp(`(?:const|let)\\s+${escaped}\\s*=\\s*create[A-Za-z]+\\s*\\(\\s*\\{([\\s\\S]*?)\\}\\s*\\)`).exec(source)?.[1];
586
609
  if (!providerBody)
587
610
  return /EXE_LLM_URL|llm\.int\.exe\.xyz/.test(source) ? undefined : null;
588
611
  if (/EXE_LLM_URL/.test(providerBody))
@@ -785,6 +808,12 @@ function newestBuildForEve(name, eve) {
785
808
  const candidates = [];
786
809
  for (const version of ordered) {
787
810
  const peer = targetEvePeer(name, version);
811
+ // A package whose newest build declares no eve peer at all (this CLI,
812
+ // @kybernesis/create) is not built per eve line: its newest is the answer.
813
+ // Without this, every agent that keeps kyb in its own package.json could
814
+ // never plan an upgrade (`kyb upgrade --check` reported it unresolved).
815
+ if (!peer && candidates.length === 0)
816
+ return version;
788
817
  candidates.push({ version, ...(peer ? { peer } : {}) });
789
818
  const hit = newestOnLine(candidates, eve);
790
819
  if (hit)
@@ -1032,6 +1061,7 @@ export async function upgrade(options = {}) {
1032
1061
  repairNotifySetup(cwd, deps);
1033
1062
  repairReasoningSandboxes(cwd, deps);
1034
1063
  repairManageRestart(cwd, deps);
1064
+ repairExeClaudeRoutes(cwd, deps);
1035
1065
  return;
1036
1066
  }
1037
1067
  console.log(bold(`\nInstalling: ${changed.join(", ")}\n`));
@@ -1123,6 +1153,7 @@ export async function upgrade(options = {}) {
1123
1153
  repairNotifySetup(cwd, deps);
1124
1154
  repairReasoningSandboxes(cwd, deps);
1125
1155
  repairManageRestart(cwd, deps);
1156
+ repairExeClaudeRoutes(cwd, deps);
1126
1157
  run("npm", ["run", "typecheck"], { cwd });
1127
1158
  if (eveChanged) {
1128
1159
  const infoOk = run("npx", ["eve", "info"], { cwd, allowFail: true, quiet: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kybernesis/create",
3
- "version": "0.24.1",
3
+ "version": "0.24.3",
4
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.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",