@synqa/cli 1.1.0 → 1.2.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/update.js ADDED
@@ -0,0 +1,71 @@
1
+ // Update check and /update. The check is one short, silent GET to the npm registry; the update
2
+ // runs npm itself (no shell string on POSIX; npm.cmd through a shell on Windows).
3
+ import { spawn } from "node:child_process";
4
+ import { homedir } from "node:os";
5
+
6
+
7
+ export const REGISTRY_URL = "https://registry.npmjs.org/@synqa/cli/latest";
8
+ export const PACKAGE_SPEC = "@synqa/cli@latest";
9
+
10
+ // "1.2.0" -> [1, 2, 0]; anything that is not a plain x.y.z (with an optional -pre part) is undefined.
11
+ export function parseVersion(v ) {
12
+ const m = /^v?(\d+)\.(\d+)\.(\d+)(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.exec(v.trim());
13
+ return m ? [Number(m[1]), Number(m[2]), Number(m[3])] : undefined;
14
+ }
15
+
16
+ // Numeric, not textual: 1.10.0 is newer than 1.9.0. Returns <0, 0 or >0; undefined if either is unparseable.
17
+ export function compareVersions(a , b ) {
18
+ const x = parseVersion(a);
19
+ const y = parseVersion(b);
20
+ if (!x || !y) return undefined;
21
+ for (let i = 0; i < 3; i++) {
22
+ const d = (x[i] ) - (y[i] );
23
+ if (d !== 0) return d;
24
+ }
25
+ return 0;
26
+ }
27
+
28
+ export const isNewer = (latest , current ) => (compareVersions(latest, current) ?? 0) > 0;
29
+
30
+ // The latest published version if it is newer than `current`, else undefined. Every failure
31
+ // (offline, slow, odd answer) is silent.
32
+ export async function checkForUpdate(current , fetchFn = fetch, timeoutMs = 1500) {
33
+ const ac = new AbortController();
34
+ const timer = setTimeout(() => ac.abort(), timeoutMs);
35
+ (timer ).unref?.();
36
+ try {
37
+ const res = await fetchFn(REGISTRY_URL, { headers: { accept: "application/json" }, signal: ac.signal });
38
+ if (!res.ok) return undefined;
39
+ const body = (await res.json()) ;
40
+ const latest = typeof body.version === "string" ? body.version : "";
41
+ return isNewer(latest, current) ? latest : undefined;
42
+ } catch {
43
+ return undefined;
44
+ } finally {
45
+ clearTimeout(timer);
46
+ }
47
+ }
48
+
49
+ // How /update runs npm. POSIX: spawn("npm", [...]) with no shell. Windows: npm is npm.cmd, which
50
+ // Node can only start through a shell.
51
+ export function updateCommand(platform = process.platform) {
52
+ return { file: platform === "win32" ? "npm.cmd" : "npm", args: ["install", "-g", PACKAGE_SPEC], shell: platform === "win32" };
53
+ }
54
+
55
+ export function runUpdate(platform = process.platform, spawnFn = spawn) {
56
+ const c = updateCommand(platform);
57
+ return new Promise((resolve) => {
58
+ try {
59
+ const child = spawnFn(c.file, c.args, {
60
+ stdio: "inherit", shell: c.shell,
61
+ // Never the workspace: npm must not pick up a project's .npmrc or a planted npm.cmd.
62
+ cwd: homedir(),
63
+ ...(platform === "win32" ? { env: { ...process.env, NoDefaultCurrentDirectoryInExePath: "1" } } : {}),
64
+ });
65
+ child.on("error", () => resolve(1));
66
+ child.on("close", (code ) => resolve(code ?? 1));
67
+ } catch {
68
+ resolve(1);
69
+ }
70
+ });
71
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@synqa/cli",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Synqa terminal coding agent",
5
5
  "type": "module",
6
6
  "bin": {