@neta-art/cohub-cli 3.8.0 → 3.8.2

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/bin/cohub.js CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- import "../dist/index.js";
2
+ import "../dist/bootstrap.js";
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env node
2
+ import { relaunchCli } from "./launcher.js";
3
+ import { ensureCliSelfUpdated } from "./self-update.js";
4
+ const argv = process.argv.slice(2);
5
+ const isVersionRequest = argv.some((arg) => arg === "-v" || arg === "--version");
6
+ let shouldRelaunch = false;
7
+ try {
8
+ if (!isVersionRequest) {
9
+ shouldRelaunch = await ensureCliSelfUpdated() !== "current";
10
+ }
11
+ }
12
+ catch (error) {
13
+ const message = error instanceof Error ? error.message : String(error);
14
+ process.stderr.write(`cohub self-update failed: ${message}\n`);
15
+ process.stderr.write("run with --version to skip self-update\n");
16
+ process.exit(1);
17
+ }
18
+ if (shouldRelaunch) {
19
+ const entrypoint = process.argv[1];
20
+ if (!entrypoint) {
21
+ process.stderr.write("cohub failed to locate its updated entrypoint\n");
22
+ process.exit(1);
23
+ }
24
+ try {
25
+ process.exitCode = await relaunchCli(entrypoint, argv);
26
+ }
27
+ catch (error) {
28
+ const message = error instanceof Error ? error.message : String(error);
29
+ process.stderr.write(`cohub failed to launch the updated CLI: ${message}\n`);
30
+ process.exitCode = 1;
31
+ }
32
+ }
33
+ else {
34
+ await import("./index.js");
35
+ }
package/dist/index.js CHANGED
@@ -20,7 +20,6 @@ import { registerSandbox } from "./commands/sandbox.js";
20
20
  import { registerTasks } from "./commands/tasks.js";
21
21
  import { registerUi } from "./commands/ui.js";
22
22
  import { registerWorks } from "./commands/works.js";
23
- import { ensureCliSelfUpdated } from "./self-update.js";
24
23
  const VERSION = (() => {
25
24
  try {
26
25
  const pkg = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf-8"));
@@ -84,20 +83,8 @@ registerTasks(program);
84
83
  registerCronJobs(program);
85
84
  registerWorks(program);
86
85
  registerUi(program);
87
- const isVersionRequest = (argv) => argv.some((arg) => arg === "-v" || arg === "--version");
88
- try {
89
- const argv = process.argv.slice(2);
90
- if (await maybeHandleRunCommand(argv)) {
91
- process.exit();
92
- }
93
- if (!isVersionRequest(argv)) {
94
- await ensureCliSelfUpdated();
95
- }
96
- }
97
- catch (error) {
98
- const message = error instanceof Error ? error.message : String(error);
99
- process.stderr.write(`cohub self-update failed: ${message}\n`);
100
- process.stderr.write("run with --version to skip self-update\n");
101
- process.exit(1);
86
+ const argv = process.argv.slice(2);
87
+ if (await maybeHandleRunCommand(argv)) {
88
+ process.exit();
102
89
  }
103
90
  program.parse();
@@ -0,0 +1,2 @@
1
+ export declare function exitCodeForChild(code: number | null, signal: NodeJS.Signals | null): number;
2
+ export declare function relaunchCli(entrypoint: string, argv: string[]): Promise<number>;
@@ -0,0 +1,38 @@
1
+ import { spawn } from "node:child_process";
2
+ import { constants } from "node:os";
3
+ const FORWARDED_SIGNALS = ["SIGINT", "SIGTERM", "SIGHUP"];
4
+ export function exitCodeForChild(code, signal) {
5
+ if (code !== null)
6
+ return code;
7
+ if (!signal)
8
+ return 1;
9
+ return 128 + (constants.signals[signal] ?? 1);
10
+ }
11
+ export function relaunchCli(entrypoint, argv) {
12
+ return new Promise((resolve, reject) => {
13
+ const child = spawn(process.execPath, [entrypoint, ...argv], {
14
+ env: process.env,
15
+ stdio: "inherit",
16
+ });
17
+ const signalHandlers = FORWARDED_SIGNALS.map((signal) => {
18
+ const forward = () => {
19
+ if (child.exitCode === null && child.signalCode === null)
20
+ child.kill(signal);
21
+ };
22
+ process.on(signal, forward);
23
+ return [signal, forward];
24
+ });
25
+ const cleanup = () => {
26
+ for (const [signal, forward] of signalHandlers)
27
+ process.off(signal, forward);
28
+ };
29
+ child.once("error", (error) => {
30
+ cleanup();
31
+ reject(error);
32
+ });
33
+ child.once("close", (code, signal) => {
34
+ cleanup();
35
+ resolve(exitCodeForChild(code, signal));
36
+ });
37
+ });
38
+ }
@@ -1 +1,3 @@
1
- export declare function ensureCliSelfUpdated(): Promise<void>;
1
+ export type CliSelfUpdateResult = "current" | "updated" | "updated-by-peer";
2
+ export declare function resolveSelfUpdateResult(beforeVersion: string | undefined, afterVersion: string | undefined, updatedByPeer: boolean): CliSelfUpdateResult;
3
+ export declare function ensureCliSelfUpdated(): Promise<CliSelfUpdateResult>;
@@ -8,6 +8,7 @@ const DEFAULT_TIMEOUT_MS = 60_000;
8
8
  const LOCK_STALE_MS = 5 * 60 * 1000;
9
9
  const STATE_PATH = join(homedir(), ".cache", "cohub-cli", "self-update.json");
10
10
  const LOCK_PATH = join(homedir(), ".cache", "cohub-cli", "self-update.lock");
11
+ const PACKAGE_PATH = new URL("../package.json", import.meta.url);
11
12
  const parsePositiveIntEnv = (name, fallback) => {
12
13
  const raw = process.env[name]?.trim();
13
14
  if (!raw)
@@ -40,6 +41,20 @@ const writeState = () => {
40
41
  mkdirSync(dirname(STATE_PATH), { recursive: true });
41
42
  writeFileSync(STATE_PATH, `${JSON.stringify({ lastUpdatedAt: new Date().toISOString() }, null, 2)}\n`);
42
43
  };
44
+ const readInstalledVersion = () => {
45
+ try {
46
+ const pkg = JSON.parse(readFileSync(PACKAGE_PATH, "utf-8"));
47
+ return typeof pkg.version === "string" ? pkg.version : undefined;
48
+ }
49
+ catch {
50
+ return undefined;
51
+ }
52
+ };
53
+ export function resolveSelfUpdateResult(beforeVersion, afterVersion, updatedByPeer) {
54
+ if (beforeVersion !== undefined && beforeVersion === afterVersion)
55
+ return "current";
56
+ return updatedByPeer ? "updated-by-peer" : "updated";
57
+ }
43
58
  const isDue = () => {
44
59
  const state = readState();
45
60
  if (!state.lastUpdatedAt)
@@ -114,9 +129,10 @@ const runNpmUpdate = (timeoutMs) => {
114
129
  };
115
130
  export async function ensureCliSelfUpdated() {
116
131
  if (process.env.COHUB_CLI_AUTO_UPDATE === "0")
117
- return;
132
+ return "current";
118
133
  if (!isDue())
119
- return;
134
+ return "current";
135
+ const beforeVersion = readInstalledVersion();
120
136
  const timeoutMs = getTimeoutMs();
121
137
  const locked = await acquireLock(timeoutMs);
122
138
  if (!locked) {
@@ -125,10 +141,12 @@ export async function ensureCliSelfUpdated() {
125
141
  try {
126
142
  // Another process may have completed the update while this process was
127
143
  // waiting for the lock.
128
- if (!isDue())
129
- return;
144
+ if (!isDue()) {
145
+ return resolveSelfUpdateResult(beforeVersion, readInstalledVersion(), true);
146
+ }
130
147
  await runNpmUpdate(timeoutMs);
131
148
  writeState();
149
+ return resolveSelfUpdateResult(beforeVersion, readInstalledVersion(), false);
132
150
  }
133
151
  finally {
134
152
  releaseLock();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neta-art/cohub-cli",
3
- "version": "3.8.0",
3
+ "version": "3.8.2",
4
4
  "description": "CLI for Cohub — spaces, sessions, and agent collaboration.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -19,7 +19,7 @@
19
19
  "commander": "^15.0.0",
20
20
  "pixi.js": "^8.19.0",
21
21
  "sharp": "^0.35.3",
22
- "@neta-art/cohub": "5.3.0"
22
+ "@neta-art/cohub": "5.3.2"
23
23
  },
24
24
  "publishConfig": {
25
25
  "access": "public"