@popoverinstall/cli 0.7.2 → 0.8.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/CHANGELOG.md +139 -0
- package/README.md +90 -19
- package/dist/changelog.d.ts.map +1 -1
- package/dist/changelog.js +8 -1
- package/dist/changelog.js.map +1 -1
- package/dist/daemon-lock.d.ts +102 -0
- package/dist/daemon-lock.d.ts.map +1 -0
- package/dist/daemon-lock.js +321 -0
- package/dist/daemon-lock.js.map +1 -0
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +11 -0
- package/dist/doctor.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +107 -21
- package/dist/index.js.map +1 -1
- package/dist/login.d.ts.map +1 -1
- package/dist/login.js +38 -5
- package/dist/login.js.map +1 -1
- package/dist/next-steps.d.ts +1 -5
- package/dist/next-steps.d.ts.map +1 -1
- package/dist/next-steps.js +9 -5
- package/dist/next-steps.js.map +1 -1
- package/dist/rename.d.ts +18 -0
- package/dist/rename.d.ts.map +1 -0
- package/dist/rename.js +252 -0
- package/dist/rename.js.map +1 -0
- package/dist/snapshot.js +24 -4
- package/dist/snapshot.js.map +1 -1
- package/dist/terminal.d.ts.map +1 -1
- package/dist/terminal.js +21 -0
- package/dist/terminal.js.map +1 -1
- package/dist/theme.d.ts +5 -3
- package/dist/theme.d.ts.map +1 -1
- package/dist/theme.js +7 -5
- package/dist/theme.js.map +1 -1
- package/package.json +3 -3
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/README.md +13 -4
- package/plugin/commands/ask.md +65 -0
- package/plugin/commands/fork.md +4 -3
- package/plugin/commands/team.md +37 -64
- package/plugin/commands/tell.md +66 -0
- package/plugin/scripts/announce-roster.mjs +21 -7
- package/plugin/scripts/emit-event.mjs +17 -0
- package/plugin/scripts/ensure-daemon.mjs +41 -1
- package/plugin/scripts/roster.mjs +5 -0
- package/plugin/skills/popover/SKILL.md +34 -11
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { daemonLockPath, popoverHome } from "@popoverinstall/shared";
|
|
5
|
+
/**
|
|
6
|
+
* Reading the daemon's lock file, and refusing to act on it when it is stale.
|
|
7
|
+
*
|
|
8
|
+
* The lock is advisory. A daemon is running if and only if it answers on the pipe; the file
|
|
9
|
+
* exists so that a daemon which has stopped answering can still be signalled. That makes
|
|
10
|
+
* every use of it an act of trust in a number written by a process that may be long gone,
|
|
11
|
+
* and this module exists to make that trust conditional.
|
|
12
|
+
*
|
|
13
|
+
* Two ways it used to be misplaced, both reproduced:
|
|
14
|
+
*
|
|
15
|
+
* 1. **A recycled pid.** A daemon killed without its graceful path — `taskkill /F`, Task
|
|
16
|
+
* Manager, a power cut — leaves the file behind, and Windows reissues pids aggressively.
|
|
17
|
+
* `popover daemon stop` then sent SIGTERM to whatever now holds that number, and
|
|
18
|
+
* `popover update` runs the same path, so this was not a rare route into someone else's
|
|
19
|
+
* process.
|
|
20
|
+
* 2. **A zero-byte lock.** A crash mid-write, or a full disk, leaves an empty file.
|
|
21
|
+
* `Number("")` is `0` and `Number.isFinite(0)` is `true`, so the pid check passed and
|
|
22
|
+
* `process.kill(0, "SIGTERM")` went out — which on macOS and Linux signals the *caller's
|
|
23
|
+
* entire process group*, killing the user's shell.
|
|
24
|
+
*
|
|
25
|
+
* So: the pid must be a positive integer, and the process wearing it must still look like the
|
|
26
|
+
* one that wrote the file — same start time, running the same script. When that cannot be
|
|
27
|
+
* established, nothing is signalled. Refusing to act is always recoverable; signalling the
|
|
28
|
+
* wrong process is not.
|
|
29
|
+
*/
|
|
30
|
+
/** How far the OS-reported start time may differ from the recorded one. */
|
|
31
|
+
const START_TIME_TOLERANCE_MS = 5_000;
|
|
32
|
+
/**
|
|
33
|
+
* Parse the lock file, tolerating the format that predates it.
|
|
34
|
+
*
|
|
35
|
+
* A daemon installed before this change is still a daemon somebody may need to stop, and its
|
|
36
|
+
* lock holds a bare pid. It is accepted, flagged `legacy`, and verified against a weaker
|
|
37
|
+
* signal — see `verifyDaemonLock`.
|
|
38
|
+
*/
|
|
39
|
+
export function readDaemonLock(file = daemonLockPath()) {
|
|
40
|
+
let raw;
|
|
41
|
+
try {
|
|
42
|
+
raw = readFileSync(file, "utf8").trim();
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
// Includes the zero-byte case, which is the whole reason this returns null rather than
|
|
48
|
+
// letting `Number("")` become a pid of 0.
|
|
49
|
+
if (!raw)
|
|
50
|
+
return null;
|
|
51
|
+
if (raw.startsWith("{")) {
|
|
52
|
+
try {
|
|
53
|
+
const parsed = JSON.parse(raw);
|
|
54
|
+
const pid = Number(parsed.pid);
|
|
55
|
+
if (!Number.isInteger(pid))
|
|
56
|
+
return null;
|
|
57
|
+
return {
|
|
58
|
+
pid,
|
|
59
|
+
...(Number.isFinite(Number(parsed.startedAt)) && Number(parsed.startedAt) > 0
|
|
60
|
+
? { startedAt: Number(parsed.startedAt) }
|
|
61
|
+
: {}),
|
|
62
|
+
...(parsed.entry ? { entry: String(parsed.entry) } : {}),
|
|
63
|
+
legacy: false,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const pid = Number(raw);
|
|
71
|
+
if (!Number.isInteger(pid))
|
|
72
|
+
return null;
|
|
73
|
+
return { pid, legacy: true };
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Whether the process named by the lock is still the daemon that wrote it.
|
|
77
|
+
*
|
|
78
|
+
* `expectedEntry` is the daemon build this CLI would start, used as the identity test for a
|
|
79
|
+
* legacy lock that records no entry of its own. It is a weaker test — it says "this pid is
|
|
80
|
+
* running the daemon" rather than "this pid is the one that wrote the file" — but combined
|
|
81
|
+
* with the pid still existing it is enough to rule out an unrelated process, which is the
|
|
82
|
+
* failure that matters.
|
|
83
|
+
*/
|
|
84
|
+
export function verifyDaemonLock(lock, opts = {}) {
|
|
85
|
+
// `pid > 0` rather than `Number.isFinite`: 0 is a real, finite number and a catastrophic
|
|
86
|
+
// signal target, and a negative pid signals a process group on POSIX.
|
|
87
|
+
if (!Number.isInteger(lock.pid) || lock.pid <= 0) {
|
|
88
|
+
return { ok: false, reason: "bad-pid", detail: `the lock names pid ${lock.pid}` };
|
|
89
|
+
}
|
|
90
|
+
const probe = opts.probe ?? inspectProcess;
|
|
91
|
+
const info = probe(lock.pid);
|
|
92
|
+
if (info.state === "gone") {
|
|
93
|
+
return { ok: false, reason: "gone", detail: `no process is running as pid ${lock.pid}` };
|
|
94
|
+
}
|
|
95
|
+
if (info.state === "unknown") {
|
|
96
|
+
return {
|
|
97
|
+
ok: false,
|
|
98
|
+
reason: "unknown",
|
|
99
|
+
detail: `this machine would not say what pid ${lock.pid} is`,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
// The start time is the strongest available evidence against a recycled pid: a reissued
|
|
103
|
+
// number belongs to a process that started later, by definition.
|
|
104
|
+
if (lock.startedAt !== undefined) {
|
|
105
|
+
if (info.startedAt === undefined) {
|
|
106
|
+
return {
|
|
107
|
+
ok: false,
|
|
108
|
+
reason: "unknown",
|
|
109
|
+
detail: `could not read the start time of pid ${lock.pid}`,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
if (Math.abs(info.startedAt - lock.startedAt) > START_TIME_TOLERANCE_MS) {
|
|
113
|
+
return {
|
|
114
|
+
ok: false,
|
|
115
|
+
reason: "not-ours",
|
|
116
|
+
detail: `pid ${lock.pid} started at a different time than the daemon that wrote the lock`,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
const wanted = lock.entry ?? opts.expectedEntry ?? null;
|
|
121
|
+
if (wanted) {
|
|
122
|
+
if (info.commandLine === undefined) {
|
|
123
|
+
return {
|
|
124
|
+
ok: false,
|
|
125
|
+
reason: "unknown",
|
|
126
|
+
detail: `could not read the command line of pid ${lock.pid}`,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
if (!commandLineNames(info.commandLine, wanted)) {
|
|
130
|
+
return {
|
|
131
|
+
ok: false,
|
|
132
|
+
reason: "not-ours",
|
|
133
|
+
detail: `pid ${lock.pid} is not running the popover daemon`,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
else if (lock.legacy) {
|
|
138
|
+
// Nothing recorded and nothing to compare against. A legacy lock plus no known daemon
|
|
139
|
+
// build is exactly the situation this module exists to refuse.
|
|
140
|
+
return {
|
|
141
|
+
ok: false,
|
|
142
|
+
reason: "unknown",
|
|
143
|
+
detail: "the lock predates this version and there is no daemon build to check it against",
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
return { ok: true, pid: lock.pid };
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Whether a command line is running a given script.
|
|
150
|
+
*
|
|
151
|
+
* Compared on the path as text rather than by resolving it: the daemon recorded
|
|
152
|
+
* `process.argv[1]` and the OS reports the same string back, so an exact substring match is
|
|
153
|
+
* both sufficient and free of filesystem calls that could themselves fail. Windows gets a
|
|
154
|
+
* case-insensitive comparison with separators normalised, because a path can come back with
|
|
155
|
+
* either slash and either case and still be the same file.
|
|
156
|
+
*/
|
|
157
|
+
function commandLineNames(commandLine, entry) {
|
|
158
|
+
if (process.platform !== "win32")
|
|
159
|
+
return commandLine.includes(entry);
|
|
160
|
+
const norm = (s) => s.replace(/\\/g, "/").toLowerCase();
|
|
161
|
+
return norm(commandLine).includes(norm(entry));
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Ask the OS what a pid is, without ever throwing.
|
|
165
|
+
*
|
|
166
|
+
* Deliberately not `process.kill(pid, 0)`, which answers only "does something hold this
|
|
167
|
+
* number" — the exact question that led here. What is needed is identity, and identity means
|
|
168
|
+
* the start time and the command line, neither of which Node exposes for another process.
|
|
169
|
+
*
|
|
170
|
+
* Costs one subprocess. That is fine: this runs on the fallback path of `popover daemon
|
|
171
|
+
* stop`, after the pipe has already failed, and never on any hot path.
|
|
172
|
+
*/
|
|
173
|
+
export function inspectProcess(pid) {
|
|
174
|
+
try {
|
|
175
|
+
return process.platform === "win32" ? inspectWindows(pid) : inspectPosix(pid);
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
// A probe that could not run tells us nothing, and "nothing" must not read as "gone" —
|
|
179
|
+
// that would send us on to clean the lock of a daemon that is alive and well.
|
|
180
|
+
return { state: "unknown" };
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
function inspectPosix(pid) {
|
|
184
|
+
let out;
|
|
185
|
+
try {
|
|
186
|
+
out = execFileSync("ps", ["-o", "lstart=,args=", "-p", String(pid)], {
|
|
187
|
+
encoding: "utf8",
|
|
188
|
+
timeout: 8_000,
|
|
189
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
catch (err) {
|
|
193
|
+
// `ps` exits non-zero with no output when the pid does not exist, which is an answer.
|
|
194
|
+
// Anything else — no `ps`, a timeout — is not.
|
|
195
|
+
const status = err.status;
|
|
196
|
+
if (status === 1)
|
|
197
|
+
return { state: "gone" };
|
|
198
|
+
return { state: "unknown" };
|
|
199
|
+
}
|
|
200
|
+
const line = out.split("\n").find((l) => l.trim().length > 0);
|
|
201
|
+
if (!line)
|
|
202
|
+
return { state: "gone" };
|
|
203
|
+
// `lstart` is `%a %b %e %H:%M:%S %Y`, space-padded to a fixed width, so the date and the
|
|
204
|
+
// command are separable without knowing anything about the command.
|
|
205
|
+
const m = /^\s*(\w{3}\s+\w{3}\s+[\d ]?\d\s+\d{2}:\d{2}:\d{2}\s+\d{4})\s+(.*)$/.exec(line);
|
|
206
|
+
if (!m)
|
|
207
|
+
return { state: "running", commandLine: line.trim() };
|
|
208
|
+
const at = Date.parse(m[1].replace(/\s+/g, " "));
|
|
209
|
+
return {
|
|
210
|
+
state: "running",
|
|
211
|
+
...(Number.isFinite(at) ? { startedAt: at } : {}),
|
|
212
|
+
commandLine: m[2].trim(),
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
function inspectWindows(pid) {
|
|
216
|
+
// One CIM query, because `Get-Process` reports a start time but not a command line and the
|
|
217
|
+
// command line is what identifies the script. Emitted as JSON so nothing has to be parsed
|
|
218
|
+
// out of a localised table.
|
|
219
|
+
const script = `$ErrorActionPreference='Stop';` +
|
|
220
|
+
`$p = Get-CimInstance Win32_Process -Filter "ProcessId=${pid}";` +
|
|
221
|
+
`if ($null -eq $p) { exit 3 };` +
|
|
222
|
+
`$o = [ordered]@{ ` +
|
|
223
|
+
`start = [int64]([DateTimeOffset]$p.CreationDate).ToUnixTimeMilliseconds(); ` +
|
|
224
|
+
`cmd = [string]$p.CommandLine };` +
|
|
225
|
+
`[Console]::Out.Write(($o | ConvertTo-Json -Compress))`;
|
|
226
|
+
let out;
|
|
227
|
+
try {
|
|
228
|
+
out = execFileSync("powershell.exe", ["-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-Command", script], { encoding: "utf8", timeout: 8_000, stdio: ["ignore", "pipe", "ignore"], windowsHide: true });
|
|
229
|
+
}
|
|
230
|
+
catch (err) {
|
|
231
|
+
// Exit 3 is our own "no such process"; every other failure is the probe, not the answer.
|
|
232
|
+
if (err.status === 3)
|
|
233
|
+
return { state: "gone" };
|
|
234
|
+
return { state: "unknown" };
|
|
235
|
+
}
|
|
236
|
+
try {
|
|
237
|
+
const parsed = JSON.parse(out.trim());
|
|
238
|
+
const at = Number(parsed.start);
|
|
239
|
+
return {
|
|
240
|
+
state: "running",
|
|
241
|
+
...(Number.isFinite(at) && at > 0 ? { startedAt: at } : {}),
|
|
242
|
+
...(parsed.cmd ? { commandLine: String(parsed.cmd) } : {}),
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
catch {
|
|
246
|
+
return { state: "unknown" };
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
/** Remove a lock that has been shown to name nothing of ours. Never throws. */
|
|
250
|
+
export function clearDaemonLock(file = daemonLockPath()) {
|
|
251
|
+
try {
|
|
252
|
+
rmSync(file, { force: true });
|
|
253
|
+
}
|
|
254
|
+
catch {
|
|
255
|
+
/* the next start overwrites it anyway */
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
// ---------------------------------------------------------------------------
|
|
259
|
+
// The update interlock
|
|
260
|
+
// ---------------------------------------------------------------------------
|
|
261
|
+
/**
|
|
262
|
+
* Marker saying "an upgrade is replacing the install tree; do not start a daemon".
|
|
263
|
+
*
|
|
264
|
+
* `popover update` stops the daemon and then hands npm up to five minutes to replace the
|
|
265
|
+
* global package. The SessionStart hook runs in *every* Claude Code session, pings, finds
|
|
266
|
+
* nothing, and starts `node <entry>` pointing into the tree npm is halfway through replacing.
|
|
267
|
+
* On Windows the daemon it starts then holds those files open, npm's rename fails EPERM or
|
|
268
|
+
* EBUSY, and the update aborts with a half-replaced global install — a machine with no
|
|
269
|
+
* working `popover` at all.
|
|
270
|
+
*
|
|
271
|
+
* The deadline is what keeps this from being worse than the problem. A marker with no expiry
|
|
272
|
+
* that survives a crashed update would suppress the daemon forever, on a machine whose owner
|
|
273
|
+
* has no idea this file exists.
|
|
274
|
+
*/
|
|
275
|
+
export function updateLockPath() {
|
|
276
|
+
return path.join(popoverHome(), "update.lock");
|
|
277
|
+
}
|
|
278
|
+
export function beginUpdateLock(ttlMs) {
|
|
279
|
+
try {
|
|
280
|
+
mkdirSync(popoverHome(), { recursive: true });
|
|
281
|
+
writeFileSync(updateLockPath(), `${JSON.stringify({ v: 1, pid: process.pid, deadline: Date.now() + ttlMs })}\n`, "utf8");
|
|
282
|
+
}
|
|
283
|
+
catch {
|
|
284
|
+
// Best effort. Failing to write it makes the race possible again, which is where we
|
|
285
|
+
// started; failing the update over it would be worse.
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
export function clearUpdateLock() {
|
|
289
|
+
try {
|
|
290
|
+
rmSync(updateLockPath(), { force: true });
|
|
291
|
+
}
|
|
292
|
+
catch {
|
|
293
|
+
/* a stale marker expires on its own */
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Whether an upgrade is in flight right now.
|
|
298
|
+
*
|
|
299
|
+
* Every branch fails towards starting the daemon. Only a marker that is present, readable and
|
|
300
|
+
* unexpired holds anything back; a torn or truncated one means the process that wrote it was
|
|
301
|
+
* interrupted, which is a dead update rather than a running one. Reading it the other way
|
|
302
|
+
* round would leave a machine permanently without a daemon over a file its owner has never
|
|
303
|
+
* heard of — worse than the race this guards against, and far harder to diagnose.
|
|
304
|
+
*
|
|
305
|
+
* `packages/plugin/scripts/ensure-daemon.mjs` duplicates this check, down to that choice. It
|
|
306
|
+
* must stay dependency-free — a hook that fails to resolve an import breaks every session on
|
|
307
|
+
* the machine — so it cannot import this. Change both together.
|
|
308
|
+
*/
|
|
309
|
+
export function updateInProgress() {
|
|
310
|
+
try {
|
|
311
|
+
const file = updateLockPath();
|
|
312
|
+
if (!existsSync(file))
|
|
313
|
+
return false;
|
|
314
|
+
const deadline = Number(JSON.parse(readFileSync(file, "utf8")).deadline);
|
|
315
|
+
return Number.isFinite(deadline) && Date.now() < deadline;
|
|
316
|
+
}
|
|
317
|
+
catch {
|
|
318
|
+
return false;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
//# sourceMappingURL=daemon-lock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon-lock.js","sourceRoot":"","sources":["../src/daemon-lock.ts"],"names":[],"mappings":"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"}
|
package/dist/doctor.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"AAWA,6HAA6H;AAC7H,eAAO,MAAM,kBAAkB,sBAAuB,CAAC;AAEvD;;;;;GAKG;AACH,wBAAsB,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"AAWA,6HAA6H;AAC7H,eAAO,MAAM,kBAAkB,sBAAuB,CAAC;AAEvD;;;;;GAKG;AACH,wBAAsB,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,CAuI9C;AAED,wBAAsB,aAAa,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAQ5D;AAcD,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAS/F"}
|
package/dist/doctor.js
CHANGED
|
@@ -61,6 +61,17 @@ export async function doctor() {
|
|
|
61
61
|
if (!pong.authenticated) {
|
|
62
62
|
fail("daemon is running but not authenticated", "Its token exchange failed. Check the backend, then `popover daemon restart`.");
|
|
63
63
|
}
|
|
64
|
+
// A blocked client is a failure, not a suggestion: the backend is refusing its writes,
|
|
65
|
+
// so this machine's agents are invisible to the team no matter how healthy everything
|
|
66
|
+
// else here looks. Reported before the roster check below, which would otherwise show
|
|
67
|
+
// an empty team and read as "nobody is around".
|
|
68
|
+
if (pong.update?.blocked) {
|
|
69
|
+
fail("this build is too old to publish to your team", `The backend refuses its writes, so your agents are invisible to teammates. Run \`${pong.update.command}\`.`);
|
|
70
|
+
}
|
|
71
|
+
else if (pong.update) {
|
|
72
|
+
warn(`a newer release is available (${pong.update.current} → ${pong.update.latest})`);
|
|
73
|
+
dim(`Run \`${pong.update.command}\`.`);
|
|
74
|
+
}
|
|
64
75
|
}
|
|
65
76
|
// 5. Backend round trip — the check that actually exercises the JWT path.
|
|
66
77
|
if (creds) {
|
package/dist/doctor.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAsCA;;;;;;GAMG;AACH,eAAO,MAAM,OAAO,EAAE,MAEb,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -5,11 +5,13 @@ import os from "node:os";
|
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import { PACKAGE_NAME, clearCredentials, daemonEntryPointerPath, daemonLogPath, defaultApiUrl, installCommand, loadCredentials, parseChangelog, popoverHome, releasesInstalled, renderReleaseNotes, } from "@popoverinstall/shared";
|
|
7
7
|
import { changelog } from "./changelog.js";
|
|
8
|
+
import { beginUpdateLock, clearDaemonLock, clearUpdateLock, readDaemonLock, updateInProgress, verifyDaemonLock, } from "./daemon-lock.js";
|
|
8
9
|
import { resolveDaemonEntry } from "./daemon-entry.js";
|
|
9
10
|
import { doctor } from "./doctor.js";
|
|
10
11
|
import { execTool } from "./exec.js";
|
|
11
12
|
import { askDaemon, daemonIsRunning } from "./ipc-client.js";
|
|
12
13
|
import { login } from "./login.js";
|
|
14
|
+
import { rename } from "./rename.js";
|
|
13
15
|
import { setup } from "./setup.js";
|
|
14
16
|
import { forkCommand } from "./snapshot.js";
|
|
15
17
|
import { bad, c, dim, info, ok, warn } from "./ui.js";
|
|
@@ -36,7 +38,9 @@ async function main() {
|
|
|
36
38
|
return welcome({ apiUrl: flag(rest, "--api") ?? defaultApiUrl() });
|
|
37
39
|
case "logout":
|
|
38
40
|
clearCredentials();
|
|
39
|
-
|
|
41
|
+
// No longer "after it restarts": a running daemon re-reads this file on every publish
|
|
42
|
+
// tick and drops its connection when it goes, so signing out takes effect in seconds.
|
|
43
|
+
ok("Signed out. The daemon stops publishing within a few seconds.");
|
|
40
44
|
dim("Revoke the machine at the dashboard to cut off access immediately.");
|
|
41
45
|
return 0;
|
|
42
46
|
case "update":
|
|
@@ -49,6 +53,8 @@ async function main() {
|
|
|
49
53
|
return doctor();
|
|
50
54
|
case "team":
|
|
51
55
|
return team();
|
|
56
|
+
case "rename":
|
|
57
|
+
return rename(rest);
|
|
52
58
|
case "daemon":
|
|
53
59
|
return daemonCommand(rest[0] ?? "status");
|
|
54
60
|
case "fork":
|
|
@@ -71,7 +77,7 @@ async function main() {
|
|
|
71
77
|
case "ask":
|
|
72
78
|
case "tell":
|
|
73
79
|
bad(`\`popover ${command}\` has moved into the session.`);
|
|
74
|
-
dim(`Run /popover
|
|
80
|
+
dim(`Run /popover:${command} <agent> <${command === "ask" ? "question" : "message"}> in Claude Code instead.`);
|
|
75
81
|
dim("An agent there has the context to write a question worth answering — and to");
|
|
76
82
|
dim("do something with the answer.");
|
|
77
83
|
return 1;
|
|
@@ -135,7 +141,7 @@ function usage() {
|
|
|
135
141
|
${c.bold("popover")} — connect this machine, and see what your team's agents are doing
|
|
136
142
|
${next ? `\n${next}` : ""}
|
|
137
143
|
Asking and telling happen inside a session, where the agent doing them has the
|
|
138
|
-
context to be worth reading: ${c.bold("/popover:
|
|
144
|
+
context to be worth reading: ${c.bold("/popover:ask B1 …")} and ${c.bold("/popover:tell B1 …")}
|
|
139
145
|
|
|
140
146
|
${c.bold("popover login")} [--api URL] Connect this machine to your team
|
|
141
147
|
${c.bold("popover logout")} Forget this machine's credentials
|
|
@@ -145,6 +151,7 @@ ${next ? `\n${next}` : ""}
|
|
|
145
151
|
${c.bold("popover changelog")} [--all] What the last update changed
|
|
146
152
|
${c.bold("popover status")} Show this machine's sessions and connection
|
|
147
153
|
${c.bold("popover team")} Print the team roster
|
|
154
|
+
${c.bold("popover rename")} [handle] Name an agent, so your team can tell them apart
|
|
148
155
|
${c.bold("popover fork")} <create|open|launch|list|revoke>
|
|
149
156
|
${c.bold("popover doctor")} Diagnose setup problems
|
|
150
157
|
${c.bold("popover daemon")} <start|stop|restart|status|logs>
|
|
@@ -177,15 +184,51 @@ ${next ? `\n${next}` : ""}
|
|
|
177
184
|
* `setup()` has to run afterwards. Claude Code caches plugins by version, so without
|
|
178
185
|
* re-registering, the user keeps running the previous plugin against the new daemon — a
|
|
179
186
|
* version skew that produces no error, just quietly stale behaviour.
|
|
187
|
+
*
|
|
188
|
+
* 3. **Something else will try to start the daemon while npm is mid-install.** Stopping the
|
|
189
|
+
* daemon is necessary but not sufficient: the plugin's SessionStart hook runs in every
|
|
190
|
+
* Claude Code session on the machine, and all it knows is that no daemon is answering. It
|
|
191
|
+
* would then spawn one out of the tree npm is replacing, whose open file handles make
|
|
192
|
+
* npm's rename fail EPERM/EBUSY on Windows and abort the update half-done. The marker
|
|
193
|
+
* written below is the interlock; `updateInProgress()` is what the hook and `daemon start`
|
|
194
|
+
* both check.
|
|
195
|
+
*
|
|
196
|
+
* Its scope is exactly the window it guards — from before the stop, because the race opens
|
|
197
|
+
* the instant the daemon stops answering, to the moment npm is done with the tree. It is
|
|
198
|
+
* released before anything restarts the daemon, or the interlock would suppress our own
|
|
199
|
+
* restart, and it is released in a `finally` with a deadline on top, so neither a thrown
|
|
200
|
+
* npm, a Ctrl-C, nor a power cut can leave a machine that refuses to start its daemon.
|
|
180
201
|
*/
|
|
202
|
+
const UPDATE_LOCK_TTL_MS = 360_000; // the npm timeout below, with room to spare
|
|
181
203
|
async function update() {
|
|
182
204
|
// Asked before stopping it, because the daemon is the only thing that knows which
|
|
183
205
|
// version the backend publishes.
|
|
184
206
|
const pong = await askDaemon({ t: "ping", id: "update" }, 2_000);
|
|
185
207
|
const expected = pong?.t === "pong" ? pong.update?.latest : undefined;
|
|
186
208
|
info(`Updating ${PACKAGE_NAME} (${VERSION} → ${expected ?? "latest"})`);
|
|
187
|
-
|
|
209
|
+
let failure;
|
|
210
|
+
beginUpdateLock(UPDATE_LOCK_TTL_MS);
|
|
188
211
|
try {
|
|
212
|
+
const stopped = await daemonCommand("stop").catch(() => 1);
|
|
213
|
+
// A refused stop is not a stopped daemon. `daemon stop` deliberately signals nothing
|
|
214
|
+
// when it cannot verify the lock's pid is ours — which includes any case where the
|
|
215
|
+
// process probe itself is unavailable or slow, and on Windows that is a real
|
|
216
|
+
// possibility (no PowerShell on PATH, constrained language mode, a timed-out probe).
|
|
217
|
+
// Carrying on hands npm an install tree the daemon is still holding open, and npm's
|
|
218
|
+
// rename fails EPERM/EBUSY partway through, leaving a half-replaced global install —
|
|
219
|
+
// the precise failure the update interlock exists to prevent, arrived at from the one
|
|
220
|
+
// direction the interlock does not cover.
|
|
221
|
+
//
|
|
222
|
+
// Liveness is the real test, not the exit code: if nothing answers a ping then the
|
|
223
|
+
// daemon is gone whatever the lock file claimed, and the update is safe to run.
|
|
224
|
+
if (stopped !== 0) {
|
|
225
|
+
const stillAlive = await askDaemon({ t: "ping", id: "update" }, 1_500);
|
|
226
|
+
if (stillAlive?.t === "pong") {
|
|
227
|
+
bad("The daemon is still running and could not be stopped, so nothing was installed.");
|
|
228
|
+
dim("Stop it by hand or reboot, then run `popover update` again.");
|
|
229
|
+
return 1;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
189
232
|
// `execTool`, not `execFile`: on Windows `npm` is a `.cmd` that Node will not spawn
|
|
190
233
|
// directly, and the update used to die on `spawn npm ENOENT` before reaching the
|
|
191
234
|
// registry. See packages/cli/src/exec.ts.
|
|
@@ -197,6 +240,15 @@ async function update() {
|
|
|
197
240
|
process.stdout.write(stdout);
|
|
198
241
|
}
|
|
199
242
|
catch (err) {
|
|
243
|
+
failure = err;
|
|
244
|
+
}
|
|
245
|
+
finally {
|
|
246
|
+
// npm is finished with the install tree either way, so nothing is gained by holding the
|
|
247
|
+
// interlock over the restart below — and holding it would block that restart.
|
|
248
|
+
clearUpdateLock();
|
|
249
|
+
}
|
|
250
|
+
if (failure) {
|
|
251
|
+
const err = failure;
|
|
200
252
|
process.stdout.write(err.stdout ?? "");
|
|
201
253
|
const output = `${err.stdout ?? ""}${err.stderr ?? ""}`;
|
|
202
254
|
// A release that the registry will not serve yet: publishing is a separate step from the
|
|
@@ -383,6 +435,13 @@ async function daemonCommand(sub) {
|
|
|
383
435
|
ok("Daemon is already running.");
|
|
384
436
|
return 0;
|
|
385
437
|
}
|
|
438
|
+
// An upgrade is replacing the tree the daemon runs out of. Starting one now would hold
|
|
439
|
+
// those files open and make npm's rename fail — see `update()`. `popover update` clears
|
|
440
|
+
// this before its own restart, so this can never suppress that.
|
|
441
|
+
if (updateInProgress()) {
|
|
442
|
+
warn("An update is in progress; not starting the daemon until it finishes.");
|
|
443
|
+
return 0;
|
|
444
|
+
}
|
|
386
445
|
const entry = resolveDaemonEntry();
|
|
387
446
|
if (!entry) {
|
|
388
447
|
bad("Could not find the daemon build.");
|
|
@@ -424,30 +483,57 @@ async function daemonCommand(sub) {
|
|
|
424
483
|
warn("The daemon accepted the stop but is still running; signalling it.");
|
|
425
484
|
}
|
|
426
485
|
// Fallback: a daemon too old to know this request, or one that is wedged.
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
486
|
+
//
|
|
487
|
+
// Everything below treats the lock file as a claim to be checked rather than an
|
|
488
|
+
// instruction to be followed. It is written by a process that may have died without
|
|
489
|
+
// removing it, and pids are reused — so a lock that cannot be tied to a running popover
|
|
490
|
+
// daemon is reported and cleaned, never signalled. See packages/cli/src/daemon-lock.ts.
|
|
491
|
+
const lock = readDaemonLock();
|
|
492
|
+
if (!lock) {
|
|
493
|
+
warn("No readable daemon lock file; it may not be running.");
|
|
494
|
+
clearDaemonLock();
|
|
430
495
|
return 0;
|
|
431
496
|
}
|
|
432
|
-
const
|
|
433
|
-
if (
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
497
|
+
const verdict = verifyDaemonLock(lock, { expectedEntry: resolveDaemonEntry() });
|
|
498
|
+
if (verdict.ok) {
|
|
499
|
+
try {
|
|
500
|
+
process.kill(verdict.pid, "SIGTERM");
|
|
501
|
+
ok(`Signalled daemon (pid ${verdict.pid}).`);
|
|
502
|
+
return 0;
|
|
503
|
+
}
|
|
504
|
+
catch {
|
|
505
|
+
// It exited between the check and the signal, which is a stop by any other name.
|
|
506
|
+
warn("Daemon was not running.");
|
|
507
|
+
clearDaemonLock();
|
|
508
|
+
return 0;
|
|
509
|
+
}
|
|
441
510
|
}
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
511
|
+
if (verdict.reason === "unknown") {
|
|
512
|
+
// The one case where doing nothing is the answer: we could not establish what that
|
|
513
|
+
// pid is, and a wrong guess signals a process that has nothing to do with popover.
|
|
514
|
+
// The lock is left alone too — it may belong to a daemon that is perfectly alive.
|
|
515
|
+
bad(`Could not confirm that pid ${lock.pid} is the popover daemon (${verdict.detail}).`);
|
|
516
|
+
dim("Nothing was signalled. Stop it by hand if you are sure, or reboot.");
|
|
517
|
+
return 1;
|
|
445
518
|
}
|
|
519
|
+
warn(`Ignoring a stale daemon lock — ${verdict.detail}.`);
|
|
520
|
+
clearDaemonLock();
|
|
521
|
+
return 0;
|
|
446
522
|
}
|
|
447
|
-
case "restart":
|
|
448
|
-
await daemonCommand("stop");
|
|
523
|
+
case "restart": {
|
|
524
|
+
const stopped = await daemonCommand("stop");
|
|
449
525
|
await sleep(1200);
|
|
526
|
+
// Starting unconditionally after a refused stop is how you end up with two daemons
|
|
527
|
+
// racing for one socket. `stop` refuses when it cannot confirm the locked pid is
|
|
528
|
+
// ours, so check whether anything is actually still answering before starting
|
|
529
|
+
// another — the ping is the truth, the lock is only a hint.
|
|
530
|
+
if (stopped !== 0 && (await daemonIsRunning())) {
|
|
531
|
+
bad("The daemon is still running and could not be stopped, so it was not restarted.");
|
|
532
|
+
dim("Stop it by hand or reboot, then run `popover daemon start`.");
|
|
533
|
+
return 1;
|
|
534
|
+
}
|
|
450
535
|
return daemonCommand("start");
|
|
536
|
+
}
|
|
451
537
|
case "status":
|
|
452
538
|
if (await daemonIsRunning()) {
|
|
453
539
|
ok("Daemon is running.");
|