@kybernesis/create 0.25.0 → 0.26.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/README.md CHANGED
@@ -14,6 +14,10 @@ npx @kybernesis/create init acme-atlas
14
14
 
15
15
  `kyb init --host=exe` always installs the agent's computer (`@kybernesis/computer`: a persistent desktop with Chrome a person can watch and take over) and its vault (`@kybernesis/vault`: per-agent, per-person logins and cards it fills on that computer without seeing them). They are not options. A Vercel host gets neither, because a function cannot keep a desktop alive, and init says so.
16
16
 
17
+ ## Core on every Studio agent
18
+
19
+ `kyb init --studio` (every agent the provisioner builds) also installs what a person sees beyond words in KYBER Studio and on the phone: cards under replies (`@kybernesis/cards` and the `show` tool from the `cards` registry item), artifacts (`@kybernesis/artifacts`: pages the agent makes and keeps, served by manage) and magic (`@kybernesis/magic`: proactive heads-ups, off until each person turns them on). On a Linq agent, magic delivers into the iMessage thread the person last used. `kyb upgrade` adds whichever of the three an agent with `@kybernesis/manage` is missing, lists them in `--check` so the owner's Update button shows, and holds the result to the eval gate even when no other package moved.
20
+
17
21
  ## `kyb init [name]`
18
22
 
19
23
  Scaffolds the full Kybernesis stack:
package/dist/doctor.js CHANGED
@@ -11,6 +11,7 @@ import { describeStaleSidecar, newestPackageChange, staleSidecars } from "./stal
11
11
  import { checkSelfVersion } from "./self-version.js";
12
12
  import { envUrlProblems } from "./env-urls.js";
13
13
  import { migrateManifest, migrateSources } from "./line-hop.js";
14
+ import { missingStudioCore } from "./studio-core.js";
14
15
  const MARK = {
15
16
  pass: green("✓"),
16
17
  warn: yellow("!"),
@@ -230,6 +231,10 @@ export async function doctor() {
230
231
  else
231
232
  add("warn", `${p} not installed`, `eve add @kybernesis/${p.split("/")[1]}`);
232
233
  }
234
+ // Core on every agent Studio manages; kyb upgrade adds whichever is missing.
235
+ for (const core of missingStudioCore(deps)) {
236
+ add("warn", `${core.pkg} not installed (${core.what})`, `npx kyb upgrade adds it, or npx eve add @kybernesis/${core.item}`);
237
+ }
233
238
  /**
234
239
  * multiplayer is conversation mechanics for a SHARED channel — threads with
235
240
  * per-speaker identity, the public/DM split. An agent reached only through
package/dist/init.js CHANGED
@@ -9,6 +9,7 @@ import { upsertEnv } from "./envfile.js";
9
9
  import { systemdRestartCommand } from "./systemd.js";
10
10
  import { sandboxCleanupScaffoldFiles } from "./sandbox-cleanup.js";
11
11
  import { MODEL_REACH_ENV, resolveModelScaffold } from "./model-reach.js";
12
+ import { STUDIO_CORE, ignoreMagicState, wireMagicLinq } from "./studio-core.js";
12
13
  /**
13
14
  * The always-installed core. Everything else — channels, subagents, engineer,
14
15
  * host bindings — is opt-in, because assuming them means the FDE deletes files
@@ -151,7 +152,7 @@ export async function init(rawName, options = {}) {
151
152
  // client change THIS AGENT — its dependencies and its source; `notify`
152
153
  // lets it reach the person's phone. Different blast radius, so an agent
153
154
  // can have one without the others.
154
- console.log(bold("\n2b2 KYBER Studio: local execution + management routes + phone notifications …"));
155
+ console.log(bold("\n2b2 KYBER Studio: local execution + management routes + phone notifications + cards, artifacts, heads-ups …"));
155
156
  const studioFailures = [];
156
157
  for (const item of ["local", "manage", "notify"]) {
157
158
  // The @kybernesis/ prefix is load-bearing: a bare name resolves against
@@ -168,6 +169,20 @@ export async function init(rawName, options = {}) {
168
169
  console.log(yellow(` ! ${item} did not install — re-run: npx eve add @kybernesis/${item}`));
169
170
  }
170
171
  }
172
+ // What a person sees beyond words, on every agent Studio reaches: cards
173
+ // under replies, artifacts, and magic (off until each person opts in).
174
+ // After manage and notify on purpose: artifacts are served by manage's
175
+ // routes, and magic delivers into its conversation and rings the phone.
176
+ for (const core of STUDIO_CORE) {
177
+ const ok = run("npx", ["eve", "add", `@kybernesis/${core.item}`, "--overwrite"], { cwd: dir, allowFail: true });
178
+ if (!ok) {
179
+ studioFailures.push(core.item);
180
+ console.log(yellow(` ! ${core.item} did not install — re-run: npx eve add @kybernesis/${core.item}`));
181
+ }
182
+ else if (core.item === "magic") {
183
+ ignoreMagicState(dir);
184
+ }
185
+ }
171
186
  // Said again, loudly, at the end. A warning printed sixty lines before a
172
187
  // green summary is a warning nobody reads — and the agent that results
173
188
  // looks correctly scaffolded right up until KYBER Studio refuses it.
@@ -351,6 +366,9 @@ export async function init(rawName, options = {}) {
351
366
  else {
352
367
  console.log(bold(`\n4/6 Channel: ${channel} (no channel file) …`));
353
368
  }
369
+ // A person who last texted the agent gets their heads-ups in that thread.
370
+ if (studio && wireMagicLinq(dir))
371
+ console.log(dim(" agent/lib/magic-surfaces.ts — heads-ups also land in iMessage threads"));
354
372
  if (depts.length) {
355
373
  console.log(bold(`\n4b Generating ${depts.length} department subagent(s) …`));
356
374
  const skillsSource = join(dir, "node_modules/@kybernesis/arcana/dist/extension/skills");
@@ -403,6 +421,7 @@ export async function init(rawName, options = {}) {
403
421
  host === "exe" ? "exe.dev host" : null,
404
422
  model.reach === "claude-sub" ? "Claude subscription reach" : null,
405
423
  studio ? "KYBER Studio (local execution + management routes)" : null,
424
+ studio ? "cards, artifacts and heads-ups (each person opts in)" : null,
406
425
  engineer ? "engineer subagent (workshop + vision loop)" : null,
407
426
  compPlan ? "its own computer (desktop + Chrome, watch and take over)" : null,
408
427
  compPlan ? "its own vault (logins and cards it fills without seeing)" : null,
@@ -0,0 +1,68 @@
1
+ /**
2
+ * What a person gets from an agent in KYBER Studio and on the phone beyond
3
+ * words: cards under a reply (the `show` tool), pages the agent makes and
4
+ * keeps (artifacts), and heads-ups it sends on its own (magic, off for each
5
+ * person until they turn it on). Core on every agent since 2026-10-23 (Ian:
6
+ * "they ship with every single agent").
7
+ *
8
+ * Keyed on @kybernesis/manage, like notify: manage serves the artifact pages
9
+ * and owns the conversation magic delivers into, so without it neither has
10
+ * anywhere to land. Every agent the provisioner builds has it (--studio).
11
+ *
12
+ * Each one's marker is its own package. An agent that already has it, added
13
+ * by hand or customised (Sid's own delivery map), is never touched.
14
+ */
15
+ export declare const STUDIO_CORE: readonly [{
16
+ readonly item: "cards";
17
+ readonly pkg: "@kybernesis/cards";
18
+ readonly what: "cards under its replies";
19
+ }, {
20
+ readonly item: "artifacts";
21
+ readonly pkg: "@kybernesis/artifacts";
22
+ readonly what: "pages it makes and keeps";
23
+ }, {
24
+ readonly item: "magic";
25
+ readonly pkg: "@kybernesis/magic";
26
+ readonly what: "heads-ups, off until each person turns them on";
27
+ }];
28
+ export type StudioCoreItem = (typeof STUDIO_CORE)[number];
29
+ /** The core items this agent is missing, in install order. None without manage. */
30
+ export declare function missingStudioCore(deps: Record<string, string>): StudioCoreItem[];
31
+ /**
32
+ * The additions an upgrade would make, for `kyb upgrade --check`.
33
+ *
34
+ * Without them the Update button stays hidden on an agent whose packages are
35
+ * all current, which is exactly the agent these were built after. `resolve`
36
+ * names the build that would install; one that resolves to nothing is left
37
+ * out, because nothing published runs on this eve.
38
+ */
39
+ export declare function planStudioCore(deps: Record<string, string>, resolve: (pkg: string) => string | undefined): Array<{
40
+ name: string;
41
+ from: string;
42
+ to: string;
43
+ }>;
44
+ /**
45
+ * Where magic delivers on an agent that also answers on iMessage through Linq.
46
+ *
47
+ * The registry's map sends every heads-up into the conversation Studio and the
48
+ * phone share. A person who last texted the agent should get it in that same
49
+ * thread instead (Linq thread ids start with "linq:").
50
+ */
51
+ export declare function magicSurfacesLinqTs(): string;
52
+ /**
53
+ * Point magic at Linq when this agent has a Linq channel. Only ever called
54
+ * right after the registry wrote its default map, so nothing hand-made is lost.
55
+ */
56
+ export declare function wireMagicLinq(cwd: string): boolean;
57
+ /**
58
+ * Keep magic's per-person state out of git. `.kyb/magic/people/<id>/` holds
59
+ * what each person turned on and what they were told; it belongs to the host.
60
+ */
61
+ export declare function ignoreMagicState(cwd: string): boolean;
62
+ /**
63
+ * Install each missing core item from the agent's own @kybernesis registry,
64
+ * the same way `eve add` would by hand: its package and its files. Returns
65
+ * what was added; a failure is said and skipped, and the eval gate after it
66
+ * judges the agent as it stands.
67
+ */
68
+ export declare function repairStudioCore(cwd: string, deps: Record<string, string>): StudioCoreItem[];
@@ -0,0 +1,124 @@
1
+ import { appendFileSync, existsSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { dim, green, run, yellow } from "./util.js";
4
+ /**
5
+ * What a person gets from an agent in KYBER Studio and on the phone beyond
6
+ * words: cards under a reply (the `show` tool), pages the agent makes and
7
+ * keeps (artifacts), and heads-ups it sends on its own (magic, off for each
8
+ * person until they turn it on). Core on every agent since 2026-10-23 (Ian:
9
+ * "they ship with every single agent").
10
+ *
11
+ * Keyed on @kybernesis/manage, like notify: manage serves the artifact pages
12
+ * and owns the conversation magic delivers into, so without it neither has
13
+ * anywhere to land. Every agent the provisioner builds has it (--studio).
14
+ *
15
+ * Each one's marker is its own package. An agent that already has it, added
16
+ * by hand or customised (Sid's own delivery map), is never touched.
17
+ */
18
+ export const STUDIO_CORE = [
19
+ { item: "cards", pkg: "@kybernesis/cards", what: "cards under its replies" },
20
+ { item: "artifacts", pkg: "@kybernesis/artifacts", what: "pages it makes and keeps" },
21
+ { item: "magic", pkg: "@kybernesis/magic", what: "heads-ups, off until each person turns them on" },
22
+ ];
23
+ /** The core items this agent is missing, in install order. None without manage. */
24
+ export function missingStudioCore(deps) {
25
+ if (!deps["@kybernesis/manage"])
26
+ return [];
27
+ return STUDIO_CORE.filter((core) => !deps[core.pkg]);
28
+ }
29
+ /**
30
+ * The additions an upgrade would make, for `kyb upgrade --check`.
31
+ *
32
+ * Without them the Update button stays hidden on an agent whose packages are
33
+ * all current, which is exactly the agent these were built after. `resolve`
34
+ * names the build that would install; one that resolves to nothing is left
35
+ * out, because nothing published runs on this eve.
36
+ */
37
+ export function planStudioCore(deps, resolve) {
38
+ return missingStudioCore(deps).flatMap((core) => {
39
+ const version = resolve(core.pkg);
40
+ return version ? [{ name: core.pkg, from: "none", to: version }] : [];
41
+ });
42
+ }
43
+ /**
44
+ * Where magic delivers on an agent that also answers on iMessage through Linq.
45
+ *
46
+ * The registry's map sends every heads-up into the conversation Studio and the
47
+ * phone share. A person who last texted the agent should get it in that same
48
+ * thread instead (Linq thread ids start with "linq:").
49
+ */
50
+ export function magicSurfacesLinqTs() {
51
+ return `import type { MagicDispatch } from "@kybernesis/magic";
52
+ import type { ScheduleToFn } from "eve/schedules";
53
+ import kyb from "../channels/kyb.js";
54
+ import linq from "../channels/linq.js";
55
+
56
+ /**
57
+ * Where a heads-up is delivered: the conversation the person last used.
58
+ *
59
+ * A person who last texted this agent gets it in that same iMessage thread
60
+ * (Linq thread ids start with "linq:"). Everyone else gets it in the
61
+ * conversation Studio and the phone app share, which rings their phone.
62
+ */
63
+ export function deliver(to: ScheduleToFn, dispatch: MagicDispatch) {
64
+ const { surface, packet } = dispatch;
65
+ if (surface.token?.startsWith("linq:")) {
66
+ return to(linq, { threadId: surface.token }).send(packet, { auth: surface.auth });
67
+ }
68
+ return to(kyb, { routine: "magic" }).send(packet, { auth: surface.auth });
69
+ }
70
+ `;
71
+ }
72
+ /**
73
+ * Point magic at Linq when this agent has a Linq channel. Only ever called
74
+ * right after the registry wrote its default map, so nothing hand-made is lost.
75
+ */
76
+ export function wireMagicLinq(cwd) {
77
+ if (!existsSync(join(cwd, "agent/channels/linq.ts")))
78
+ return false;
79
+ const surfaces = join(cwd, "agent/lib/magic-surfaces.ts");
80
+ if (!existsSync(surfaces))
81
+ return false;
82
+ writeFileSync(surfaces, magicSurfacesLinqTs());
83
+ return true;
84
+ }
85
+ /**
86
+ * Keep magic's per-person state out of git. `.kyb/magic/people/<id>/` holds
87
+ * what each person turned on and what they were told; it belongs to the host.
88
+ */
89
+ export function ignoreMagicState(cwd) {
90
+ const path = join(cwd, ".gitignore");
91
+ const current = existsSync(path) ? readFileSync(path, "utf8") : "";
92
+ if (current.split("\n").some((line) => /^\/?\.kyb\/?$/.test(line.trim())))
93
+ return false;
94
+ appendFileSync(path, `${current && !current.endsWith("\n") ? "\n" : ""}.kyb\n`);
95
+ return true;
96
+ }
97
+ /**
98
+ * Install each missing core item from the agent's own @kybernesis registry,
99
+ * the same way `eve add` would by hand: its package and its files. Returns
100
+ * what was added; a failure is said and skipped, and the eval gate after it
101
+ * judges the agent as it stands.
102
+ */
103
+ export function repairStudioCore(cwd, deps) {
104
+ const added = [];
105
+ for (const core of missingStudioCore(deps)) {
106
+ const ok = run("npx", ["eve", "add", `@kybernesis/${core.item}`, "--yes"], { cwd, allowFail: true, quiet: true });
107
+ if (!ok) {
108
+ console.log(` ${yellow("!")} could not add ${core.pkg} (${core.what}). Run: npx eve add @kybernesis/${core.item}`);
109
+ continue;
110
+ }
111
+ deps[core.pkg] = "latest";
112
+ added.push(core);
113
+ if (core.item === "magic") {
114
+ ignoreMagicState(cwd);
115
+ if (wireMagicLinq(cwd))
116
+ console.log(` ${dim("magic delivers into iMessage threads too (agent/lib/magic-surfaces.ts)")}`);
117
+ }
118
+ }
119
+ if (added.length > 0) {
120
+ console.log(` ${green("+")} Added ${added.map((core) => `${core.pkg} ${dim(`(${core.what})`)}`).join(", ")}`);
121
+ console.log(` ${dim("Takes effect after the next build and restart.")}\n`);
122
+ }
123
+ return added;
124
+ }
package/dist/upgrade.js CHANGED
@@ -12,6 +12,7 @@ import { newestOnLine } from "./on-line-version.js";
12
12
  import { findMatchingAgentServiceUnit, repairManageRestart } from "./systemd.js";
13
13
  import { repairTerminalSandboxCleanupHooks } from "./sandbox-cleanup.js";
14
14
  import { repairExeClaudeRoute } from "./exe-claude-route.js";
15
+ import { planStudioCore, repairStudioCore } from "./studio-core.js";
15
16
  import { repairOptInTools, repairRemovedDefaultTools as repairRemovedDefaultTools_ } from "./removed-default-tools.js";
16
17
  import { EVE_VERSION, REGISTRY_URL, bold, capture, dim, green, parseEnv, red, run, yellow } from "./util.js";
17
18
  import { backUpWorkflowStore, clearStaleEveCaches, migrateManifest, migrateSources, restoreWorkflowStore, workflowStoreBackup, } from "./line-hop.js";
@@ -1098,6 +1099,9 @@ export async function upgrade(options = {}) {
1098
1099
  .filter((target) => changed.includes(`${target.name}@${target.targetVersion}`))
1099
1100
  .map((target) => [target.name, { name: target.name, from: target.installedVersion, to: target.targetVersion }])).values(),
1100
1101
  ...manifest.moves.map((move) => ({ name: move.name, from: move.from, to: move.to ?? "removed" })),
1102
+ // Packages every agent now ships with that this one predates: an
1103
+ // upgrade adds them, so the Update button has to show them.
1104
+ ...planStudioCore(deps, (name) => newestBuildForEve(name, EVE_VERSION)),
1101
1105
  ],
1102
1106
  resetsConversations: eveChanged,
1103
1107
  });
@@ -1135,10 +1139,20 @@ export async function upgrade(options = {}) {
1135
1139
  repairHostArtifacts(cwd, deps);
1136
1140
  repairEvalCommand(cwd);
1137
1141
  repairNotifySetup(cwd, deps);
1142
+ const added = repairStudioCore(cwd, deps);
1138
1143
  repairReasoningSandboxes(cwd, deps);
1139
1144
  repairManageRestart(cwd, deps);
1140
1145
  repairExeClaudeRoutes(cwd, deps);
1141
1146
  reportSourceMigration(cwd);
1147
+ if (added.length === 0)
1148
+ return;
1149
+ // New tools and a schedule on a live agent: the same gate as any upgrade.
1150
+ run("npm", ["run", "typecheck"], { cwd });
1151
+ if (options.skipEval) {
1152
+ console.log(yellow("\nEval gate SKIPPED (--skip-eval). Run `npm run eval` before deploying.\n"));
1153
+ return;
1154
+ }
1155
+ await runUpgradeEvalGate(cwd, options.host);
1142
1156
  return;
1143
1157
  }
1144
1158
  console.log(bold(`\nInstalling: ${changed.join(", ")}\n`));
@@ -1225,6 +1239,7 @@ export async function upgrade(options = {}) {
1225
1239
  repairHostArtifacts(cwd, deps);
1226
1240
  repairEvalCommand(cwd);
1227
1241
  repairNotifySetup(cwd, deps);
1242
+ repairStudioCore(cwd, deps);
1228
1243
  repairReasoningSandboxes(cwd, deps);
1229
1244
  repairManageRestart(cwd, deps);
1230
1245
  repairExeClaudeRoutes(cwd, deps);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kybernesis/create",
3
- "version": "0.25.0",
3
+ "version": "0.26.0",
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",
@@ -46,8 +46,7 @@
46
46
  "node": ">=20"
47
47
  },
48
48
  "publishConfig": {
49
- "access": "public",
50
- "tag": "eve-0.81"
49
+ "access": "public"
51
50
  },
52
51
  "peerDependencies": {}
53
52
  }