@cruxy/cli 1.11.1 → 1.11.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.
@@ -0,0 +1,107 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import { readFileSync } from "node:fs";
3
+ /** The token when the platform lookup failed: liveness falls back to pid-only. */
4
+ export const UNKNOWN_TOKEN = "unknown";
5
+ /** The start-time token for `pid`, or {@link UNKNOWN_TOKEN} when unobtainable. */
6
+ export function startToken(pid) {
7
+ try {
8
+ if (process.platform === "linux")
9
+ return linuxToken(pid);
10
+ if (process.platform === "darwin")
11
+ return darwinToken(pid);
12
+ if (process.platform === "win32")
13
+ return win32Token(pid);
14
+ }
15
+ catch {
16
+ // fall through — the platform said no; degrade to pid-only
17
+ }
18
+ return UNKNOWN_TOKEN;
19
+ }
20
+ /** This process's own stamp. Computed once — a process's identity never changes. */
21
+ export function selfStamp() {
22
+ if (!self) {
23
+ self = {
24
+ pid: process.pid,
25
+ token: startToken(process.pid),
26
+ startedAt: new Date(Date.now() - process.uptime() * 1000).toISOString(),
27
+ };
28
+ }
29
+ return self;
30
+ }
31
+ let self;
32
+ /** Whether a process with `pid` exists (EPERM counts: it exists, just not ours). */
33
+ export function pidAlive(pid) {
34
+ try {
35
+ process.kill(pid, 0);
36
+ return true;
37
+ }
38
+ catch (err) {
39
+ return err.code === "EPERM";
40
+ }
41
+ }
42
+ /**
43
+ * Classify a stamp against the live process table. Order matters: `self` is
44
+ * decided by pid AND token, so a stamp our own pid inherited from a crashed
45
+ * predecessor (pid recycled onto us) still reads as stale.
46
+ */
47
+ export function describeOwner(stamp) {
48
+ const me = selfStamp();
49
+ if (stamp.pid === me.pid) {
50
+ return stamp.token === me.token ? "self" : "stale";
51
+ }
52
+ if (!pidAlive(stamp.pid))
53
+ return "stale";
54
+ // Alive by pid. If both sides have a real token and they differ, the pid was
55
+ // recycled. An unknown token on either side cannot prove that, so the stamp
56
+ // is treated as live — the documented pid-only degradation.
57
+ if (stamp.token === UNKNOWN_TOKEN)
58
+ return "live";
59
+ const now = startToken(stamp.pid);
60
+ if (now === UNKNOWN_TOKEN)
61
+ return "live";
62
+ return now === stamp.token ? "live" : "stale";
63
+ }
64
+ // ── platform lookups ──────────────────────────────────────────────────────────
65
+ function linuxToken(pid) {
66
+ const stat = readFileSync(`/proc/${pid}/stat`, "utf8");
67
+ // The comm field is parenthesised and may itself contain spaces or parens;
68
+ // everything after the LAST `)` is the fixed-position numeric tail, in which
69
+ // starttime is the 20th entry (field 22 of the whole line).
70
+ const tail = stat
71
+ .slice(stat.lastIndexOf(")") + 2)
72
+ .trim()
73
+ .split(/\s+/);
74
+ const starttime = tail[19];
75
+ if (!starttime)
76
+ throw new Error("unexpected /proc stat shape");
77
+ let boot = "";
78
+ try {
79
+ boot = readFileSync("/proc/sys/kernel/random/boot_id", "utf8").trim();
80
+ }
81
+ catch {
82
+ // Older kernels / locked-down containers: the token is still per-boot in
83
+ // practice (ticks since boot), just not provably so across reboots.
84
+ }
85
+ return `linux:${boot}:${starttime}`;
86
+ }
87
+ function darwinToken(pid) {
88
+ const out = execFileSync("ps", ["-o", "lstart=", "-p", String(pid)], {
89
+ encoding: "utf8",
90
+ stdio: ["ignore", "pipe", "ignore"],
91
+ timeout: 2000,
92
+ }).trim();
93
+ if (out === "")
94
+ throw new Error("no such process");
95
+ return `darwin:${out.replace(/\s+/g, " ")}`;
96
+ }
97
+ function win32Token(pid) {
98
+ const out = execFileSync("powershell", [
99
+ "-NoProfile",
100
+ "-NonInteractive",
101
+ "-Command",
102
+ `(Get-Process -Id ${pid} -ErrorAction Stop).StartTime.ToString('o')`,
103
+ ], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], timeout: 5000 }).trim();
104
+ if (out === "")
105
+ throw new Error("no such process");
106
+ return `win32:${out}`;
107
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cruxy/cli",
3
- "version": "1.11.1",
3
+ "version": "1.11.2",
4
4
  "description": "an agentic coding CLI",
5
5
  "type": "module",
6
6
  "bin": {
@@ -32,8 +32,9 @@
32
32
  "commander": "^12.1.0",
33
33
  "fastembed": "^2.1.0",
34
34
  "picocolors": "^1.1.1",
35
+ "tar": "^7.5.22",
35
36
  "tinyglobby": "^0.2.10",
36
- "undici": "^6.21.0",
37
+ "undici": "^6.28.1",
37
38
  "zod": "^3.23.8",
38
39
  "zod-to-json-schema": "^3.23.5",
39
40
  "@cruxy/sdk": "0.8.0"