@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.
Files changed (47) hide show
  1. package/CHANGELOG.md +139 -0
  2. package/README.md +90 -19
  3. package/dist/changelog.d.ts.map +1 -1
  4. package/dist/changelog.js +8 -1
  5. package/dist/changelog.js.map +1 -1
  6. package/dist/daemon-lock.d.ts +102 -0
  7. package/dist/daemon-lock.d.ts.map +1 -0
  8. package/dist/daemon-lock.js +321 -0
  9. package/dist/daemon-lock.js.map +1 -0
  10. package/dist/doctor.d.ts.map +1 -1
  11. package/dist/doctor.js +11 -0
  12. package/dist/doctor.js.map +1 -1
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +107 -21
  15. package/dist/index.js.map +1 -1
  16. package/dist/login.d.ts.map +1 -1
  17. package/dist/login.js +38 -5
  18. package/dist/login.js.map +1 -1
  19. package/dist/next-steps.d.ts +1 -5
  20. package/dist/next-steps.d.ts.map +1 -1
  21. package/dist/next-steps.js +9 -5
  22. package/dist/next-steps.js.map +1 -1
  23. package/dist/rename.d.ts +18 -0
  24. package/dist/rename.d.ts.map +1 -0
  25. package/dist/rename.js +252 -0
  26. package/dist/rename.js.map +1 -0
  27. package/dist/snapshot.js +24 -4
  28. package/dist/snapshot.js.map +1 -1
  29. package/dist/terminal.d.ts.map +1 -1
  30. package/dist/terminal.js +21 -0
  31. package/dist/terminal.js.map +1 -1
  32. package/dist/theme.d.ts +5 -3
  33. package/dist/theme.d.ts.map +1 -1
  34. package/dist/theme.js +7 -5
  35. package/dist/theme.js.map +1 -1
  36. package/package.json +3 -3
  37. package/plugin/.claude-plugin/plugin.json +1 -1
  38. package/plugin/README.md +13 -4
  39. package/plugin/commands/ask.md +65 -0
  40. package/plugin/commands/fork.md +4 -3
  41. package/plugin/commands/team.md +37 -64
  42. package/plugin/commands/tell.md +66 -0
  43. package/plugin/scripts/announce-roster.mjs +21 -7
  44. package/plugin/scripts/emit-event.mjs +17 -0
  45. package/plugin/scripts/ensure-daemon.mjs +41 -1
  46. package/plugin/scripts/roster.mjs +5 -0
  47. package/plugin/skills/popover/SKILL.md +34 -11
package/CHANGELOG.md CHANGED
@@ -15,6 +15,145 @@ already here:
15
15
  Every version that ships needs an entry — an update with nothing to print says nothing at
16
16
  all, which reads as though the update did not happen.
17
17
 
18
+ ## 0.8.1
19
+
20
+ ### Features
21
+
22
+ - Your agent offers a fork when the moment calls for one, instead of waiting to be asked. It
23
+ used to be told never to suggest one, on the reasoning that handing over a whole
24
+ conversation is a large enough disclosure to be the user's own idea. The effect was that the
25
+ most useful case never came up at all, because the moment for a fork is one you are usually
26
+ too deep in the work to notice: you are going off shift, or about to re-explain an hour of
27
+ debugging to a colleague by hand, or trading asks back and forth on what turns out never to
28
+ have been one question. Your agent now says so once, and says what the fork would include.
29
+ Making one is still yours alone — it cannot create a fork without you asking, "that would be
30
+ useful" is not read as a yes, and if you pass on the offer it does not raise it again.
31
+
32
+ ### Fixes
33
+
34
+ - Your agent is told who else is working in the repo again. The notice was supposed to appear
35
+ whenever the cast of teammate agents changed, and almost never did: it gave the daemon 250ms
36
+ to answer, and any answer more than five seconds old means fetching from the server, which
37
+ takes about 350ms. So it ran out of time and said nothing — and saying nothing looks exactly
38
+ like working alone, which is why it went unnoticed. It now waits long enough to get an
39
+ answer. If you are working alone it also stops checking every prompt, so you are not paying
40
+ for a lookup that has nothing to report.
41
+
42
+ - `popover fork revoke` no longer tells you a fork is destroyed when it is not. If the write
43
+ failed, it said "revoked" anyway — the one command whose whole job is undoing a mistake, and
44
+ the one place a false confirmation is worst, because you stop looking. It now says it could
45
+ not and asks you to try again. A code that was already gone still reports success, which is
46
+ deliberate: answering differently would let anyone holding a code learn whether a
47
+ conversation exists.
48
+
49
+ - Expired forks are actually deleted now. A fork's ciphertext is supposed to be destroyed 24
50
+ hours after it is made, but the cleanup only ever ran when somebody happened to create
51
+ another fork — so on a quiet team, conversations you had shared for a day stayed on the
52
+ server indefinitely. It now runs on a schedule of its own.
53
+
54
+ - A hiccup on our side no longer signs your machine out. Several of these reported a temporary
55
+ server problem as a permanent refusal: a failed lookup during `popover login` looked like an
56
+ invalid code and abandoned the login, and one during a routine daemon check looked like your
57
+ machine had been revoked — which is not something it retries. They now say the service is
58
+ briefly unavailable, and the daemon keeps its session.
59
+
60
+ - Opening a fork works on Windows when the folder it came from has a non-ASCII name. The
61
+ console reads a script in its own code page rather than UTF-8, so a path like
62
+ `C:\Users\Renée\work` arrived mangled, the `cd` quietly failed, and the fork opened anyway in
63
+ whatever directory the console started in — looking correct while every file path in the
64
+ conversation pointed somewhere else. It now switches the console to UTF-8 first, and stops
65
+ with a message rather than opening in the wrong place.
66
+
67
+ - Asks against a long conversation work now. Answering an agent used to run the question past
68
+ Haiku no matter what the agent itself was running, and Haiku holds 200K tokens — so on any
69
+ session bigger than that, Claude Code had to compress the whole conversation before it could
70
+ read it, which took longer than the 90 seconds the asker waits. You got "did not answer in
71
+ time", and the machine being asked had already spent the tokens. The answer now comes from
72
+ the same model the session is already running, which fits by definition: measured on a 3.9MB
73
+ conversation, 97.6s and no answer became 15s and an answer. It costs the answering machine
74
+ more per ask, and it is their call — set `POPOVER_FORK_MODEL` to pin a cheaper one.
75
+
76
+ ## 0.8.0
77
+
78
+ ### Features
79
+
80
+ - Asking and telling are their own commands. `/popover:ask B1 why did you rule out redis?` and
81
+ `/popover:tell B1 the migration is applied` replace `/popover:team ask …` and
82
+ `/popover:team tell …`, and `/popover:team` is now just the roster. The three cost completely
83
+ different things — the roster costs nothing, an ask spends the teammate's tokens on their
84
+ machine, a tell spends their attention and lands in their live session — and hiding all three
85
+ behind one first word made the cheapest and the most intrusive look like the same gesture.
86
+ The old forms still work and mention the new name once, so nothing you have already learned
87
+ breaks.
88
+ - Agents can have names. `popover rename B1 "auth work"` gives one of your agents a name, and
89
+ your teammates see it on their next roster while the dashboard picks it up live — so three
90
+ sessions in the same repo stop being three identical rows of `B1`, `B2`, `B3`. Run
91
+ `popover rename` on its own to pick from a list instead of looking a handle up first. A named
92
+ agent answers to either, so `/popover:ask B1` and `/popover:ask "auth work"` both
93
+ reach it. You can only name your own agents, the name goes when the session does, and
94
+ `popover rename B1 ""` takes it off again. Nothing changes for anyone who never uses it: a
95
+ roster with no named agents on it prints exactly as it did before.
96
+ - The documentation is public. popover.to/docs is the whole of how it works — the roster,
97
+ asking, telling, forking, which agents can see each other, and what leaves your machine —
98
+ and popover.to/changelog is this file, with a URL you can send someone. Neither needs an
99
+ account: until now the only thing a person could read before installing was the poster, so
100
+ deciding whether to run the install command meant asking somebody who already had.
101
+ - `popover changelog` points at popover.to/changelog when an install has no notes to read,
102
+ rather than at a repository that is private and answers a 404.
103
+
104
+ ### Fixes
105
+
106
+ - Everyone on your team needs this release. The way a repo is identified changed, and a popover
107
+ older than 0.8.0 cannot prove which repo it is in — so an out-of-date machine keeps working
108
+ and keeps its own agents up to date, but goes quiet for the rest of the team until it
109
+ updates. It says so on its own roster and in `popover doctor`, and your roster counts the
110
+ teammates it cannot show you rather than leaving you to wonder where everybody went.
111
+ - An unrecognised repo identity costs you the identity, not the update. A publish carries every
112
+ session on the machine in one write, so refusing that write over one field it did not like
113
+ took the whole machine off the air — no roster, no status, and its own agents frozen at
114
+ whatever they were last doing — while the connection itself looked perfectly healthy. A value
115
+ we cannot verify is now dropped and the update lands without it.
116
+ - Working in the same repo is now something popover checks rather than something it takes your
117
+ word for. A repo was identified by the name of its git remote, which anyone can type, so
118
+ anyone on your team could claim to be in a repo they had never cloned and see — and ask —
119
+ the agents working in it. Identity now comes from the repository's own history, which you
120
+ only have if you have actually cloned it, and what reaches the server is a hash of that
121
+ rather than the thing itself, so it cannot be read off one session and reused on another.
122
+ - Revoking a machine ends it. A revoked machine could quietly un-revoke itself and carry on,
123
+ which made the button on the dashboard a suggestion.
124
+ - The agent that answers you cannot rewrite what you asked it, and the agent you send a
125
+ message to cannot change who it came from. Both are what `/activity` and `popover log` show
126
+ you afterwards, so both are now fixed at the moment they are written.
127
+ - Nothing a teammate can type reaches your agent as an instruction. Names, titles and the
128
+ activity shown on the roster are text your agent reads, and a newline in the right place
129
+ could forge a line that looked like popover talking. That text is now bounded and stripped
130
+ of anything that can start a new line, hide itself, or reverse the one it is on.
131
+ - A laptop and a desktop no longer give two agents the same handle. Both machines numbered
132
+ their own agents from one, so `G1` could mean either, and asking for it reached neither.
133
+ Handles are now handed out where all of your machines can be seen at once.
134
+ - `popover daemon stop` stops popover and nothing else. It trusted a leftover file naming a
135
+ process id, which the operating system may since have given to something entirely
136
+ unrelated — and `popover update` runs it for you.
137
+ - `popover update` no longer risks leaving half an install behind on Windows, where a file
138
+ being replaced cannot be one a running program still holds open.
139
+ - A slow moment no longer takes your agents off your teammates' rosters. If popover could not
140
+ read the list of running sessions — a busy machine, a moment's hesitation — it concluded
141
+ every one of them had ended.
142
+ - `popover fork revoke` tells you the truth when it fails. It reported that a conversation had
143
+ been destroyed without checking, which is the one command whose word you would not think to
144
+ doubt.
145
+ - Agents belonging to teammates whose names are not written in the Latin alphabet can be
146
+ reached again. A teammate called 李明 is given the handle 李1, and asking for it matched every
147
+ agent whose handle ended in the same digit — so `/popover:team ask 李1` came back "did you
148
+ mean 李1 or 王1?" with no third thing you could type that would have worked. Their name now
149
+ finds them too, and so does the name of an agent renamed in any script.
150
+ - The roster lines up its columns for those agents rather than shearing them. Column widths
151
+ were counted in characters, and a character in Chinese, Japanese or Korean takes two columns
152
+ of a terminal, as does an emoji — so every such row drifted a column further left than the
153
+ one above it.
154
+ - Asking for something with no letters or digits in it — punctuation, or an emoji on its own —
155
+ says nothing matches, instead of matching every agent on the roster at once.
156
+
18
157
  ## 0.7.2
19
158
 
20
159
  ### Fixes
package/README.md CHANGED
@@ -1,11 +1,13 @@
1
1
  # popover
2
2
 
3
- See your teammates' active Claude Code agents, and ask them questions.
3
+ **Ask your teammates' agents, not your teammates.**
4
4
 
5
5
  When a teammate's agent has already worked out why the retry logic lives where it does, you
6
6
  should be able to ask it — without interrupting your teammate. popover shows you everyone's
7
- running agents in the same repo, and answers from a read-only fork of the agent's full
8
- context.
7
+ running Claude Code agents in the repo you are working in, and answers from a read-only fork
8
+ of the agent's full accumulated context.
9
+
10
+ Full documentation: **[popover.to/docs](https://www.popover.to/docs)**.
9
11
 
10
12
  ## Install
11
13
 
@@ -13,7 +15,8 @@ context.
13
15
  npm install -g @popoverinstall/cli && popover welcome
14
16
  ```
15
17
 
16
- Requires **Node.js 20+** and **Claude Code 2.1.229+**.
18
+ Requires **Node.js 20+** and **Claude Code 2.1.229+**. The same two commands on macOS, Linux
19
+ and Windows.
17
20
 
18
21
  `npm install -g` only places files. `popover welcome` is the rest of a first run: it registers
19
22
  the Claude Code plugin, records where the daemon lives, and offers to connect this machine. It
@@ -25,20 +28,71 @@ connection — and `welcome` is re-runnable, so it is also the way back if eithe
25
28
 
26
29
  ## Use
27
30
 
28
- Inside Claude Code, `/team` shows everyone's agents in the repo you are working in. From the
29
- shell:
31
+ Inside Claude Code, `/popover:team` prints the roster: every agent your team is running in the
32
+ repo you are in, and what each one is doing right now. Each gets a short handle.
33
+
34
+ ```
35
+ *You*
36
+ A1 ad pipeline idle 34m — Wiring Kling into the ad pipeline
37
+ A2 popover editing main.py — Team agent communication
38
+
39
+ *Bob Chen*
40
+ B1 api-server reading config.json — Fixing OAuth token refresh
41
+ B2 api-server creating plan.md — Postgres connection pooling
42
+ ```
43
+
44
+ Three things to do with one:
30
45
 
31
46
  ```
32
- popover team Print the team roster
33
- popover ask <who> <question> Ask a teammate's agent directly
47
+ /popover:ask B1 why did you rule out redis?
48
+ /popover:tell B1 the migration is applied on prod
49
+ /popover:fork create
50
+ ```
51
+
52
+ **Ask** is answered by a read-only fork of that agent, running on its owner's machine. Their
53
+ session is never interrupted and their source never leaves their laptop — only the answer
54
+ does. The fork has no tools, so a question about something the agent never looked at gets
55
+ "I don't know" rather than an investigation, and the answer is billed to their account.
56
+
57
+ **Tell** drops a heads-up into a running agent's context before its next prompt. No answer
58
+ comes back. It is for facts that would otherwise cause a collision, and it is the one thing
59
+ here that reaches a live session: the database caps a sender at ten messages an hour to any
60
+ one recipient, and the recipient's human is always notified.
61
+
62
+ **Fork** hands over the whole conversation. `/popover:fork create` returns a code that works
63
+ for 24 hours; whoever you send it to runs `popover fork open <code>` and carries on in their
64
+ own local chat. Opening one needs no popover account — `npx @popoverinstall/cli fork open
65
+ <code>` is enough.
66
+
67
+ Claude Code namespaces plugin commands, so it is `/popover:team`, not `/team`.
68
+
69
+ ## Who can see what
70
+
71
+ Agents are only visible to each other **inside the same repo**, so the directory you run from
72
+ is what scopes the roster. Repos are identified by their git remotes, so two clones match
73
+ however they were cloned; a directory with no shared remote is private to you. The boundary is
74
+ enforced by row-level security in Postgres, not by the client.
75
+
76
+ ## Commands
77
+
78
+ ```
79
+ popover welcome Set up and log in — the whole of a first run
80
+ popover login / logout Connect this machine, or forget its credentials
81
+ popover setup Re-register the Claude Code plugin
34
82
  popover status This machine's sessions and connection
35
- popover log Recent questions asked of your agents
36
- popover doctor Diagnose setup problems
83
+ popover team Print the roster for the repo you are in
84
+ popover fork <create|open|launch|list|revoke>
85
+ popover log Questions and messages your agents received
86
+ popover changelog [--all] What the last update changed
37
87
  popover update Upgrade and restart the daemon
88
+ popover doctor Diagnose setup problems
89
+ popover daemon <start|stop|restart|status|logs>
90
+ popover uninstall Stop the daemon, unhook Claude Code
38
91
  ```
39
92
 
40
- Agents are only visible to each other **inside the same repo**, so the directory you run from
41
- is what scopes the roster.
93
+ Asking and telling are not in that list on purpose: they live in the session, where the agent
94
+ doing them has the context to write a question worth answering and to do something with the
95
+ answer.
42
96
 
43
97
  ## How it works
44
98
 
@@ -47,11 +101,27 @@ Three pieces install together:
47
101
  - **the CLI** — the `popover` command
48
102
  - **the daemon** — a detached background process that publishes this machine's sessions and
49
103
  answers teammates' questions. It stores state in `~/.popover/`.
50
- - **the Claude Code plugin** — provides `/team` and the MCP tools agents use to reach each
51
- other. Registered automatically on first login.
104
+ - **the Claude Code plugin** — provides `/popover:team`, `/popover:fork`, and the MCP tools
105
+ agents use to reach each other. Registered by `popover setup`.
106
+
107
+ ## What leaves your machine
108
+
109
+ - An **ask** exports one answer. A teammate can learn whatever is already in that agent's
110
+ context, including the contents of files it read earlier in the session — that is what it
111
+ answers from. Every ask is logged with its cost.
112
+ - A **fork** exports the entire conversation: every message, every tool result, the contents
113
+ of every file read into it. It is sealed before it leaves, with a key derived from the code,
114
+ so the server holds something it cannot read — but anyone holding the code can open it.
115
+ Treat it the way you would treat pasting the transcript into a chat window.
116
+ - The device token is generated here and never transmitted; the server only ever sees its
117
+ SHA-256.
118
+
119
+ ## Troubleshooting
52
120
 
53
- Answers are produced by a read-only fork of the teammate's agent, billed to their account.
54
- Their session is never interrupted.
121
+ `popover doctor` diagnoses setup problems in root-cause order and is the right first move for
122
+ most things. `popover status` says whether this machine is connected; `popover daemon logs` is
123
+ the detail underneath. A teammate missing from the roster is usually running a version too old
124
+ to publish a repo identity — the roster counts them and says so.
55
125
 
56
126
  ## Uninstall
57
127
 
@@ -64,7 +134,8 @@ Credentials and logs are left in `~/.popover/`; delete the directory to remove t
64
134
 
65
135
  ## Links
66
136
 
67
- - [Source](https://github.com/many-ideations/popover)
68
- - [Issues](https://github.com/many-ideations/popover/issues)
137
+ - [Documentation](https://www.popover.to/docs)
138
+ - [Changelog](https://www.popover.to/changelog)
139
+ - [popover.to](https://www.popover.to) — dashboard, team and activity
69
140
 
70
- MIT
141
+ MIT · Quo Labs, Inc.
@@ -1 +1 @@
1
- {"version":3,"file":"changelog.d.ts","sourceRoot":"","sources":["../src/changelog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAiDH,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAmC/D"}
1
+ {"version":3,"file":"changelog.d.ts","sourceRoot":"","sources":["../src/changelog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAwDH,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAmC/D"}
package/dist/changelog.js CHANGED
@@ -19,7 +19,14 @@ import { parseChangelog, renderReleaseNotes } from "@popoverinstall/shared";
19
19
  import { keyReader, regionTextWidth, scrollRegion } from "./pager.js";
20
20
  import { box, glyph, style } from "./theme.js";
21
21
  import { bad, dim } from "./ui.js";
22
- const SOURCE_URL = "https://github.com/many-ideations/popover/blob/main/CHANGELOG.md";
22
+ /**
23
+ * Where to send someone whose install has no notes in it.
24
+ *
25
+ * The repository, which this used to name, is private — so the one line printed on the one
26
+ * path where the local copy has failed was a link to a 404. `/changelog` on the site renders
27
+ * the same file, is public, and needs no account.
28
+ */
29
+ const SOURCE_URL = "https://www.popover.to/changelog";
23
30
  /**
24
31
  * Where the notes live, in order of preference.
25
32
  *
@@ -1 +1 @@
1
- {"version":3,"file":"changelog.js","sourceRoot":"","sources":["../src/changelog.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"changelog.js","sourceRoot":"","sources":["../src/changelog.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,102 @@
1
+ /** The shape written by `writeLock()` in packages/daemon/src/index.ts. */
2
+ export interface DaemonLock {
3
+ pid: number;
4
+ /** Epoch ms. Absent in the legacy bare-pid format. */
5
+ startedAt?: number;
6
+ /** The daemon script. Absent in the legacy bare-pid format. */
7
+ entry?: string;
8
+ /** True when the file predates the richer format and holds nothing but a pid. */
9
+ legacy: boolean;
10
+ }
11
+ export type ProcessInfo = {
12
+ state: "running";
13
+ startedAt?: number;
14
+ commandLine?: string;
15
+ }
16
+ /** No process holds this pid. */
17
+ | {
18
+ state: "gone";
19
+ }
20
+ /** The probe itself could not run, so nothing is known either way. */
21
+ | {
22
+ state: "unknown";
23
+ };
24
+ export type LockVerdict = {
25
+ ok: true;
26
+ pid: number;
27
+ } | {
28
+ ok: false;
29
+ /**
30
+ * `gone` and `not-ours` mean the file is stale and should be cleaned; `unknown` means
31
+ * we could not tell, which is the one case where the file must be left exactly as it
32
+ * is — deleting a live daemon's lock would strand it.
33
+ */
34
+ reason: "bad-pid" | "gone" | "not-ours" | "unknown";
35
+ detail: string;
36
+ };
37
+ /**
38
+ * Parse the lock file, tolerating the format that predates it.
39
+ *
40
+ * A daemon installed before this change is still a daemon somebody may need to stop, and its
41
+ * lock holds a bare pid. It is accepted, flagged `legacy`, and verified against a weaker
42
+ * signal — see `verifyDaemonLock`.
43
+ */
44
+ export declare function readDaemonLock(file?: string): DaemonLock | null;
45
+ /**
46
+ * Whether the process named by the lock is still the daemon that wrote it.
47
+ *
48
+ * `expectedEntry` is the daemon build this CLI would start, used as the identity test for a
49
+ * legacy lock that records no entry of its own. It is a weaker test — it says "this pid is
50
+ * running the daemon" rather than "this pid is the one that wrote the file" — but combined
51
+ * with the pid still existing it is enough to rule out an unrelated process, which is the
52
+ * failure that matters.
53
+ */
54
+ export declare function verifyDaemonLock(lock: DaemonLock, opts?: {
55
+ expectedEntry?: string | null;
56
+ probe?: (pid: number) => ProcessInfo;
57
+ }): LockVerdict;
58
+ /**
59
+ * Ask the OS what a pid is, without ever throwing.
60
+ *
61
+ * Deliberately not `process.kill(pid, 0)`, which answers only "does something hold this
62
+ * number" — the exact question that led here. What is needed is identity, and identity means
63
+ * the start time and the command line, neither of which Node exposes for another process.
64
+ *
65
+ * Costs one subprocess. That is fine: this runs on the fallback path of `popover daemon
66
+ * stop`, after the pipe has already failed, and never on any hot path.
67
+ */
68
+ export declare function inspectProcess(pid: number): ProcessInfo;
69
+ /** Remove a lock that has been shown to name nothing of ours. Never throws. */
70
+ export declare function clearDaemonLock(file?: string): void;
71
+ /**
72
+ * Marker saying "an upgrade is replacing the install tree; do not start a daemon".
73
+ *
74
+ * `popover update` stops the daemon and then hands npm up to five minutes to replace the
75
+ * global package. The SessionStart hook runs in *every* Claude Code session, pings, finds
76
+ * nothing, and starts `node <entry>` pointing into the tree npm is halfway through replacing.
77
+ * On Windows the daemon it starts then holds those files open, npm's rename fails EPERM or
78
+ * EBUSY, and the update aborts with a half-replaced global install — a machine with no
79
+ * working `popover` at all.
80
+ *
81
+ * The deadline is what keeps this from being worse than the problem. A marker with no expiry
82
+ * that survives a crashed update would suppress the daemon forever, on a machine whose owner
83
+ * has no idea this file exists.
84
+ */
85
+ export declare function updateLockPath(): string;
86
+ export declare function beginUpdateLock(ttlMs: number): void;
87
+ export declare function clearUpdateLock(): void;
88
+ /**
89
+ * Whether an upgrade is in flight right now.
90
+ *
91
+ * Every branch fails towards starting the daemon. Only a marker that is present, readable and
92
+ * unexpired holds anything back; a torn or truncated one means the process that wrote it was
93
+ * interrupted, which is a dead update rather than a running one. Reading it the other way
94
+ * round would leave a machine permanently without a daemon over a file its owner has never
95
+ * heard of — worse than the race this guards against, and far harder to diagnose.
96
+ *
97
+ * `packages/plugin/scripts/ensure-daemon.mjs` duplicates this check, down to that choice. It
98
+ * must stay dependency-free — a hook that fails to resolve an import breaks every session on
99
+ * the machine — so it cannot import this. Change both together.
100
+ */
101
+ export declare function updateInProgress(): boolean;
102
+ //# sourceMappingURL=daemon-lock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daemon-lock.d.ts","sourceRoot":"","sources":["../src/daemon-lock.ts"],"names":[],"mappings":"AAkCA,0EAA0E;AAC1E,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+DAA+D;IAC/D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iFAAiF;IACjF,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,MAAM,WAAW,GACnB;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE;AAChE,iCAAiC;GAC/B;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE;AACnB,sEAAsE;GACpE;IAAE,KAAK,EAAE,SAAS,CAAA;CAAE,CAAC;AAEzB,MAAM,MAAM,WAAW,GACnB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GACzB;IACE,EAAE,EAAE,KAAK,CAAC;IACV;;;;OAIG;IACH,MAAM,EAAE,SAAS,GAAG,MAAM,GAAG,UAAU,GAAG,SAAS,CAAC;IACpD,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEN;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,IAAI,GAAE,MAAyB,GAAG,UAAU,GAAG,IAAI,CAgCjF;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,UAAU,EAChB,IAAI,GAAE;IAAE,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,WAAW,CAAA;CAAO,GACjF,WAAW,CAmEb;AAiBD;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,CAQvD;AAyED,+EAA+E;AAC/E,wBAAgB,eAAe,CAAC,IAAI,GAAE,MAAyB,GAAG,IAAI,CAMrE;AAMD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAYnD;AAED,wBAAgB,eAAe,IAAI,IAAI,CAMtC;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAS1C"}