@kybernesis/create 0.14.11 → 0.15.1

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/init.js CHANGED
@@ -142,13 +142,14 @@ export async function init(rawName, options = {}) {
142
142
  run("npx", ["eve", "add", item, "--overwrite"], { cwd: dir, allowFail: true });
143
143
  }
144
144
  if (studio) {
145
- // Two separate items on purpose: `local` lets the agent act on the USER'S
145
+ // Three separate items on purpose: `local` lets the agent act on the USER'S
146
146
  // machine (consent per effect, granted on the desktop); `manage` lets a
147
- // client change THIS AGENT — its dependencies and its source. Different
148
- // blast radius, so an agent can have one without the other.
149
- console.log(bold("\n2b2 KYBER Studio: local execution + management routes …"));
147
+ // client change THIS AGENT — its dependencies and its source; `notify`
148
+ // lets it reach the person's phone. Different blast radius, so an agent
149
+ // can have one without the others.
150
+ console.log(bold("\n2b2 KYBER Studio: local execution + management routes + phone notifications …"));
150
151
  const studioFailures = [];
151
- for (const item of ["local", "manage"]) {
152
+ for (const item of ["local", "manage", "notify"]) {
152
153
  // The @kybernesis/ prefix is load-bearing: a bare name resolves against
153
154
  // eve OWN registry, which has no such item, so both installs failed with
154
155
  // "not found" — and allowFail swallowed it. --studio therefore did
@@ -75,3 +75,8 @@ export declare function exeEvalConfigTs(): string;
75
75
  export declare function arcanaMemorySlotTs(options: {
76
76
  extensionMounted: boolean;
77
77
  }): string;
78
+ /**
79
+ * The notify mount. One source for `kyb init --studio`, `kyb upgrade` and the
80
+ * registry item, so the three can never disagree about what the file says.
81
+ */
82
+ export declare function notifyMountTs(): string;
package/dist/templates.js CHANGED
@@ -722,3 +722,14 @@ export default defineMemory({
722
722
  });
723
723
  `;
724
724
  }
725
+ /**
726
+ * The notify mount. One source for `kyb init --studio`, `kyb upgrade` and the
727
+ * registry item, so the three can never disagree about what the file says.
728
+ */
729
+ export function notifyMountTs() {
730
+ return `// Tell the person's phone when this agent parks on a question or finishes a
731
+ // reply while they are away. The person is the verified session principal;
732
+ // the control plane does the ringing. See @kybernesis/notify.
733
+ export { default } from "@kybernesis/notify/extension";
734
+ `;
735
+ }
package/dist/upgrade.d.ts CHANGED
@@ -1,5 +1,20 @@
1
1
  import { type AgentInputLimit } from "./agent-limits.js";
2
2
  export declare function agentInputLimitUpgradeMessage(limit: AgentInputLimit): string;
3
+ /**
4
+ * A Studio agent that cannot ring the person's phone.
5
+ *
6
+ * `@kybernesis/notify` arrived after most agents were made, and an upgrade
7
+ * only ever moved packages an agent already had — so every existing agent
8
+ * would have stayed silent on the phone, and the first sign would have been
9
+ * a person waiting for a notification that never came. The agents that need
10
+ * it are the ones a desktop can manage: anything with `@kybernesis/manage`.
11
+ *
12
+ * The pure part — is it needed, is the mount there — is separate from the
13
+ * npm call so it can be tested without a network.
14
+ */
15
+ export declare function needsNotify(deps: Record<string, string>): boolean;
16
+ /** Write the notify mount if it is missing. Never touches a file that exists. */
17
+ export declare function repairNotifyMount(cwd: string): "mounted" | "present";
3
18
  export type GithubToolsMountRepair = {
4
19
  kind: "missing" | "current" | "updated" | "customized";
5
20
  } | {
package/dist/upgrade.js CHANGED
@@ -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 } from "./templates.js";
18
+ import { LEGACY_GITHUB_TOOLS_MOUNT, githubToolsMountTs, notifyMountTs } 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) {
@@ -165,6 +165,51 @@ function repairBuzzSetup(cwd, deps) {
165
165
  console.log(` ${dim("Takes effect after the next build and restart.")}\n`);
166
166
  }
167
167
  }
168
+ /**
169
+ * A Studio agent that cannot ring the person's phone.
170
+ *
171
+ * `@kybernesis/notify` arrived after most agents were made, and an upgrade
172
+ * only ever moved packages an agent already had — so every existing agent
173
+ * would have stayed silent on the phone, and the first sign would have been
174
+ * a person waiting for a notification that never came. The agents that need
175
+ * it are the ones a desktop can manage: anything with `@kybernesis/manage`.
176
+ *
177
+ * The pure part — is it needed, is the mount there — is separate from the
178
+ * npm call so it can be tested without a network.
179
+ */
180
+ export function needsNotify(deps) {
181
+ return Boolean(deps["@kybernesis/manage"]) && !deps["@kybernesis/notify"];
182
+ }
183
+ /** Write the notify mount if it is missing. Never touches a file that exists. */
184
+ export function repairNotifyMount(cwd) {
185
+ const mount = join(cwd, "agent/extensions/notify.ts");
186
+ if (existsSync(mount))
187
+ return "present";
188
+ mkdirSync(join(cwd, "agent/extensions"), { recursive: true });
189
+ writeFileSync(mount, notifyMountTs());
190
+ return "mounted";
191
+ }
192
+ function repairNotifySetup(cwd, deps) {
193
+ if (!deps["@kybernesis/manage"])
194
+ return;
195
+ const done = [];
196
+ if (needsNotify(deps)) {
197
+ const ok = run("npm", ["install", "@kybernesis/notify@latest", "--no-audit", "--no-fund"], { cwd, allowFail: true, quiet: true });
198
+ if (!ok) {
199
+ console.log(` ${yellow("!")} could not install @kybernesis/notify, so this agent cannot reach the person's phone.\n` +
200
+ ` Run: npm install @kybernesis/notify@latest && npx kyb upgrade`);
201
+ return;
202
+ }
203
+ deps["@kybernesis/notify"] = "latest";
204
+ done.push("installed @kybernesis/notify");
205
+ }
206
+ if (repairNotifyMount(cwd) === "mounted")
207
+ done.push("mounted it (agent/extensions/notify.ts)");
208
+ if (done.length > 0) {
209
+ console.log(` ${green("+")} Notify: ${done.join("; ")} ${dim("— the person's phone hears when this agent needs them")}`);
210
+ console.log(` ${dim("Takes effect after the next build and restart.")}\n`);
211
+ }
212
+ }
168
213
  /** Quote one argument for the manual shell commands printed after a failed repair. */
169
214
  function shellQuote(value) {
170
215
  return `'${value.replaceAll("'", `'"'"'`)}'`;
@@ -676,15 +721,6 @@ function startStoppedBridge(cwd, unit) {
676
721
  }
677
722
  export async function upgrade(options = {}) {
678
723
  console.log(bold("\nkyb upgrade — checking @kybernesis/* and eve against npm\n"));
679
- const selfVersion = checkSelfVersion();
680
- if (selfVersion.kind === "stale") {
681
- console.log(` ${yellow("!")} ${selfVersion.message}`);
682
- console.log(` ${dim(selfVersion.fix)}\n`);
683
- if (!options.allowStale) {
684
- process.exitCode = 1;
685
- return;
686
- }
687
- }
688
724
  const cwd = process.cwd();
689
725
  const packagePath = join(cwd, "package.json");
690
726
  const pkg = JSON.parse(readFileSync(packagePath, "utf8"));
@@ -692,6 +728,39 @@ export async function upgrade(options = {}) {
692
728
  ...(pkg.dependencies ?? {}),
693
729
  ...(pkg.devDependencies ?? {}),
694
730
  };
731
+ const selfVersion = checkSelfVersion();
732
+ if (selfVersion.kind === "stale" && !options.allowStale) {
733
+ /**
734
+ * A stale kyb that is the PROJECT's own dependency renews itself.
735
+ *
736
+ * On every self-hosted agent, kyb is in package.json and `npx kyb` runs
737
+ * that copy; a global install — the printed fix until now — changes
738
+ * nothing there, and the person who followed it was back at the same
739
+ * message. So when the project owns kyb, install the latest into the
740
+ * project and run the upgrade again from that copy. The re-run is marked
741
+ * so that a registry that has not caught up cannot make this loop.
742
+ */
743
+ if (deps["@kybernesis/create"] && process.env.KYB_UPGRADE_RENEWED !== "1") {
744
+ console.log(` ${yellow("↑")} kyb ${selfVersion.installed} → ${selfVersion.latest} ${dim("(this project's own copy; renewing it first)")}`);
745
+ const renewed = run("npm", ["install", `@kybernesis/create@${selfVersion.latest}`, "--no-audit", "--no-fund"], { cwd, allowFail: true, quiet: true });
746
+ const cli = join(cwd, "node_modules/@kybernesis/create/dist/cli.js");
747
+ if (renewed && existsSync(cli)) {
748
+ const again = spawnSync(process.execPath, [cli, "upgrade", ...process.argv.slice(3)], {
749
+ cwd, stdio: "inherit", env: { ...process.env, KYB_UPGRADE_RENEWED: "1" },
750
+ });
751
+ process.exitCode = again.status ?? 1;
752
+ return;
753
+ }
754
+ }
755
+ console.log(` ${yellow("!")} ${selfVersion.message}`);
756
+ console.log(` ${dim(deps["@kybernesis/create"] ? `npm install @kybernesis/create@latest && npx kyb upgrade` : selfVersion.fix)}\n`);
757
+ process.exitCode = 1;
758
+ return;
759
+ }
760
+ if (selfVersion.kind === "stale") {
761
+ console.log(` ${yellow("!")} ${selfVersion.message}`);
762
+ console.log(` ${dim(selfVersion.fix)} ${dim("(continuing: --allow-stale)")}\n`);
763
+ }
695
764
  reportAgentInputLimit(cwd);
696
765
  const entries = dependencyEntries(pkg);
697
766
  const installedVersions = new Map();
@@ -776,6 +845,7 @@ export async function upgrade(options = {}) {
776
845
  reportGithubToolsMountRepair(cwd);
777
846
  repairHostArtifacts(cwd, deps);
778
847
  repairEvalCommand(cwd);
848
+ repairNotifySetup(cwd, deps);
779
849
  repairManageRestart(cwd, deps);
780
850
  return;
781
851
  }
@@ -847,6 +917,7 @@ export async function upgrade(options = {}) {
847
917
  reportGithubToolsMountRepair(cwd);
848
918
  repairHostArtifacts(cwd, deps);
849
919
  repairEvalCommand(cwd);
920
+ repairNotifySetup(cwd, deps);
850
921
  repairManageRestart(cwd, deps);
851
922
  run("npm", ["run", "typecheck"], { cwd });
852
923
  if (eveChanged) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@kybernesis/create",
3
- "version": "0.14.11",
4
- "description": "The Kybernesis agent scaffolder and FDE toolkit: one command to a governed, remembering, multiplayer, self-testing eve agent — plus doctor and upgrade.",
3
+ "version": "0.15.1",
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",
7
7
  "homepage": "https://kybernesis.ai",