@hwip/cli 0.0.1 → 0.1.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.
Files changed (245) hide show
  1. package/LICENSE +190 -0
  2. package/NOTICE +11 -0
  3. package/README.md +1979 -0
  4. package/dist/agent-list.d.ts +76 -0
  5. package/dist/agent-list.js +102 -0
  6. package/dist/agent-read.d.ts +105 -0
  7. package/dist/agent-read.js +309 -0
  8. package/dist/agent-rules-fetch.d.ts +51 -0
  9. package/dist/agent-rules-fetch.js +275 -0
  10. package/dist/agent-rules.default.d.ts +30 -0
  11. package/dist/agent-rules.default.js +292 -0
  12. package/dist/agent-session.d.ts +23 -0
  13. package/dist/agent-session.js +44 -0
  14. package/dist/agent-state.d.ts +84 -0
  15. package/dist/agent-state.js +188 -0
  16. package/dist/agent-target.d.ts +60 -0
  17. package/dist/agent-target.js +81 -0
  18. package/dist/agents.d.ts +31 -0
  19. package/dist/agents.js +75 -0
  20. package/dist/api.d.ts +28 -0
  21. package/dist/api.js +76 -0
  22. package/dist/args.d.ts +74 -0
  23. package/dist/args.js +254 -0
  24. package/dist/ask-context-attach.d.ts +73 -0
  25. package/dist/ask-context-attach.js +151 -0
  26. package/dist/ask-context-screen.d.ts +21 -0
  27. package/dist/ask-context-screen.js +49 -0
  28. package/dist/ask-context-switch.d.ts +31 -0
  29. package/dist/ask-context-switch.js +74 -0
  30. package/dist/ask-context.d.ts +84 -0
  31. package/dist/ask-context.js +172 -0
  32. package/dist/ask-pending.d.ts +47 -0
  33. package/dist/ask-pending.js +221 -0
  34. package/dist/ask-seal.d.ts +120 -0
  35. package/dist/ask-seal.js +179 -0
  36. package/dist/ask.d.ts +107 -0
  37. package/dist/ask.js +551 -0
  38. package/dist/blocked-prompt-seal.d.ts +35 -0
  39. package/dist/blocked-prompt-seal.js +89 -0
  40. package/dist/blocked-prompt.d.ts +57 -0
  41. package/dist/blocked-prompt.js +181 -0
  42. package/dist/channel.d.ts +67 -0
  43. package/dist/channel.js +136 -0
  44. package/dist/check-update.d.ts +28 -0
  45. package/dist/check-update.js +153 -0
  46. package/dist/cli.d.ts +3 -0
  47. package/dist/cli.js +813 -0
  48. package/dist/codex-config.d.ts +24 -0
  49. package/dist/codex-config.js +169 -0
  50. package/dist/codex-transcript.d.ts +59 -0
  51. package/dist/codex-transcript.js +373 -0
  52. package/dist/command-refusal.d.ts +56 -0
  53. package/dist/command-refusal.js +127 -0
  54. package/dist/command-scan.d.ts +46 -0
  55. package/dist/command-scan.js +154 -0
  56. package/dist/command-seal.d.ts +57 -0
  57. package/dist/command-seal.js +88 -0
  58. package/dist/command-seq.d.ts +30 -0
  59. package/dist/command-seq.js +150 -0
  60. package/dist/config.d.ts +156 -0
  61. package/dist/config.js +392 -0
  62. package/dist/core-sections.d.ts +18 -0
  63. package/dist/core-sections.js +28 -0
  64. package/dist/crypto.d.ts +278 -0
  65. package/dist/crypto.js +698 -0
  66. package/dist/desktop-notify.d.ts +33 -0
  67. package/dist/desktop-notify.js +49 -0
  68. package/dist/device-directory.d.ts +36 -0
  69. package/dist/device-directory.js +97 -0
  70. package/dist/device-presence.d.ts +17 -0
  71. package/dist/device-presence.js +62 -0
  72. package/dist/downloads.d.ts +29 -0
  73. package/dist/downloads.js +106 -0
  74. package/dist/errors.d.ts +12 -0
  75. package/dist/errors.js +28 -0
  76. package/dist/file-crypto.d.ts +94 -0
  77. package/dist/file-crypto.js +272 -0
  78. package/dist/file-view-budget.d.ts +15 -0
  79. package/dist/file-view-budget.js +34 -0
  80. package/dist/file-view-switch.d.ts +28 -0
  81. package/dist/file-view-switch.js +122 -0
  82. package/dist/file-view.d.ts +108 -0
  83. package/dist/file-view.js +327 -0
  84. package/dist/gate.d.ts +141 -0
  85. package/dist/gate.js +336 -0
  86. package/dist/gemini-transcript.d.ts +32 -0
  87. package/dist/gemini-transcript.js +189 -0
  88. package/dist/http-failure.d.ts +98 -0
  89. package/dist/http-failure.js +349 -0
  90. package/dist/hwip-core.generated.d.ts +7 -0
  91. package/dist/hwip-core.generated.js +14 -0
  92. package/dist/hwip-hook.d.ts +77 -0
  93. package/dist/hwip-hook.js +340 -0
  94. package/dist/index.d.ts +7 -0
  95. package/dist/index.js +14 -0
  96. package/dist/input-sequencer.d.ts +65 -0
  97. package/dist/input-sequencer.js +142 -0
  98. package/dist/insecure-url.d.ts +16 -0
  99. package/dist/insecure-url.js +76 -0
  100. package/dist/installer.d.ts +96 -0
  101. package/dist/installer.js +850 -0
  102. package/dist/inventory-offload.d.ts +49 -0
  103. package/dist/inventory-offload.js +209 -0
  104. package/dist/inventory-worker.d.ts +2 -0
  105. package/dist/inventory-worker.js +27 -0
  106. package/dist/jsonc-doc.d.ts +106 -0
  107. package/dist/jsonc-doc.js +354 -0
  108. package/dist/keep-awake.d.ts +32 -0
  109. package/dist/keep-awake.js +46 -0
  110. package/dist/key-changes.d.ts +48 -0
  111. package/dist/key-changes.js +140 -0
  112. package/dist/lan-auth.d.ts +140 -0
  113. package/dist/lan-auth.js +217 -0
  114. package/dist/lan-endpoint.d.ts +41 -0
  115. package/dist/lan-endpoint.js +115 -0
  116. package/dist/lan-receiver.d.ts +122 -0
  117. package/dist/lan-receiver.js +510 -0
  118. package/dist/lan-sender.d.ts +76 -0
  119. package/dist/lan-sender.js +184 -0
  120. package/dist/lan-transfer.d.ts +36 -0
  121. package/dist/lan-transfer.js +54 -0
  122. package/dist/listener-device-id.d.ts +20 -0
  123. package/dist/listener-device-id.js +133 -0
  124. package/dist/listener-log.d.ts +4 -0
  125. package/dist/listener-log.js +23 -0
  126. package/dist/listener-process.d.ts +200 -0
  127. package/dist/listener-process.js +470 -0
  128. package/dist/listener-service.d.ts +225 -0
  129. package/dist/listener-service.js +682 -0
  130. package/dist/listener-worktree-cleanup.d.ts +27 -0
  131. package/dist/listener-worktree-cleanup.js +62 -0
  132. package/dist/listener.d.ts +1325 -0
  133. package/dist/listener.js +5680 -0
  134. package/dist/login-address.d.ts +25 -0
  135. package/dist/login-address.js +97 -0
  136. package/dist/login-page.d.ts +29 -0
  137. package/dist/login-page.js +93 -0
  138. package/dist/login.d.ts +98 -0
  139. package/dist/login.js +388 -0
  140. package/dist/mcp-command.d.ts +45 -0
  141. package/dist/mcp-command.js +50 -0
  142. package/dist/mcp.d.ts +19 -0
  143. package/dist/mcp.js +29 -0
  144. package/dist/node-support.d.ts +19 -0
  145. package/dist/node-support.js +38 -0
  146. package/dist/notify-failure.d.ts +57 -0
  147. package/dist/notify-failure.js +150 -0
  148. package/dist/opencode-transcript.d.ts +139 -0
  149. package/dist/opencode-transcript.js +390 -0
  150. package/dist/optional-features.d.ts +6 -0
  151. package/dist/optional-features.js +19 -0
  152. package/dist/pane-fit.d.ts +40 -0
  153. package/dist/pane-fit.js +119 -0
  154. package/dist/peer-key.d.ts +33 -0
  155. package/dist/peer-key.js +34 -0
  156. package/dist/pi-transcript.d.ts +26 -0
  157. package/dist/pi-transcript.js +255 -0
  158. package/dist/presence.d.ts +14 -0
  159. package/dist/presence.js +124 -0
  160. package/dist/private-files.d.ts +51 -0
  161. package/dist/private-files.js +218 -0
  162. package/dist/project-switch.d.ts +19 -0
  163. package/dist/project-switch.js +60 -0
  164. package/dist/redact.d.ts +10 -0
  165. package/dist/redact.js +21 -0
  166. package/dist/remote-agents.d.ts +410 -0
  167. package/dist/remote-agents.js +1218 -0
  168. package/dist/remote-hook.d.ts +12 -0
  169. package/dist/remote-hook.js +196 -0
  170. package/dist/replace-file.d.ts +50 -0
  171. package/dist/replace-file.js +328 -0
  172. package/dist/schedule-command.d.ts +35 -0
  173. package/dist/schedule-command.js +260 -0
  174. package/dist/schedule-launch.d.ts +15 -0
  175. package/dist/schedule-launch.js +24 -0
  176. package/dist/schedule-ready.d.ts +44 -0
  177. package/dist/schedule-ready.js +71 -0
  178. package/dist/schedule-remote.d.ts +77 -0
  179. package/dist/schedule-remote.js +167 -0
  180. package/dist/schedule-runner.d.ts +89 -0
  181. package/dist/schedule-runner.js +452 -0
  182. package/dist/schedule.d.ts +149 -0
  183. package/dist/schedule.js +428 -0
  184. package/dist/secret-mask.d.ts +29 -0
  185. package/dist/secret-mask.js +245 -0
  186. package/dist/self-register.d.ts +45 -0
  187. package/dist/self-register.js +67 -0
  188. package/dist/send.d.ts +56 -0
  189. package/dist/send.js +104 -0
  190. package/dist/session-diff.d.ts +161 -0
  191. package/dist/session-diff.js +445 -0
  192. package/dist/session-registry.d.ts +143 -0
  193. package/dist/session-registry.js +216 -0
  194. package/dist/sessions-report.d.ts +59 -0
  195. package/dist/sessions-report.js +99 -0
  196. package/dist/shell-audit.d.ts +34 -0
  197. package/dist/shell-audit.js +47 -0
  198. package/dist/subagent-transcripts.d.ts +167 -0
  199. package/dist/subagent-transcripts.js +437 -0
  200. package/dist/subscriber-trust.d.ts +128 -0
  201. package/dist/subscriber-trust.js +397 -0
  202. package/dist/templates.d.ts +105 -0
  203. package/dist/templates.js +871 -0
  204. package/dist/tmux-install.d.ts +44 -0
  205. package/dist/tmux-install.js +65 -0
  206. package/dist/tmux-liveness.d.ts +45 -0
  207. package/dist/tmux-liveness.js +71 -0
  208. package/dist/tmux-pane.d.ts +55 -0
  209. package/dist/tmux-pane.js +126 -0
  210. package/dist/tmux-socket.d.ts +20 -0
  211. package/dist/tmux-socket.js +292 -0
  212. package/dist/todo-fold.d.ts +31 -0
  213. package/dist/todo-fold.js +102 -0
  214. package/dist/transcript-tail.d.ts +312 -0
  215. package/dist/transcript-tail.js +718 -0
  216. package/dist/trust-command.d.ts +49 -0
  217. package/dist/trust-command.js +200 -0
  218. package/dist/trust-lock.d.ts +26 -0
  219. package/dist/trust-lock.js +94 -0
  220. package/dist/trust-pins.d.ts +37 -0
  221. package/dist/trust-pins.js +82 -0
  222. package/dist/turn-recorder-wire.d.ts +70 -0
  223. package/dist/turn-recorder-wire.js +165 -0
  224. package/dist/turn-recorder.d.ts +190 -0
  225. package/dist/turn-recorder.js +695 -0
  226. package/dist/turn-ring.d.ts +93 -0
  227. package/dist/turn-ring.js +418 -0
  228. package/dist/turn-watch.d.ts +177 -0
  229. package/dist/turn-watch.js +630 -0
  230. package/dist/types.d.ts +63 -0
  231. package/dist/types.js +2 -0
  232. package/dist/uninstall.d.ts +55 -0
  233. package/dist/uninstall.js +507 -0
  234. package/dist/usage.d.ts +17 -0
  235. package/dist/usage.js +421 -0
  236. package/dist/verify.d.ts +47 -0
  237. package/dist/verify.js +396 -0
  238. package/dist/worktree.d.ts +144 -0
  239. package/dist/worktree.js +310 -0
  240. package/dist/wrapper.d.ts +254 -0
  241. package/dist/wrapper.js +704 -0
  242. package/dist/ws-url.d.ts +109 -0
  243. package/dist/ws-url.js +202 -0
  244. package/package.json +78 -10
  245. package/bin/hwip.js +0 -3
@@ -0,0 +1,410 @@
1
+ import { spawnSync } from 'child_process';
2
+ import { type TranscriptProjector, type TranscriptReader } from './transcript-tail.js';
3
+ export interface RemoteAgent {
4
+ /** Wire value for AgentSession.agentKind (server/phone contract). */
5
+ kind: string;
6
+ /** Human name for --help text. */
7
+ displayName: string;
8
+ /** Binary launched in the tmux pane; also the primary pane-match token. */
9
+ binary: string;
10
+ /** `hwip <subcommand>` aliases that launch this agent. */
11
+ subcommands: readonly string[];
12
+ /**
13
+ * What this agent is typed to make it quit, if it has such a command.
14
+ *
15
+ * Signals are not enough on their own: Claude Code holds its prompt
16
+ * through both `C-c` and `C-d`, so a remote "end this session" built only
17
+ * out of key presses reports failure against the agent people actually
18
+ * run. Omitted where the command has not been verified against the real
19
+ * binary — sending a guess into a live pane types it at whatever prompt
20
+ * is there.
21
+ */
22
+ quitCommand?: string;
23
+ /** Extra pane_command basenames accepted as this agent (beyond binary). */
24
+ paneMatchAliases?: readonly string[];
25
+ /**
26
+ * Resolve the agent's own session id from the pane's cwd (+ pane pid
27
+ * when the caller knows it — enables exact process-tree matching).
28
+ * EXTENSION POINT: carried by Claude Code and OpenCode. Every other row
29
+ * omits it until that agent's session-file format is confirmed — the
30
+ * listener then reports agentSessionId: null.
31
+ */
32
+ resolveSessionId?: (paneCwd: string, panePid?: number) => string | null;
33
+ /**
34
+ * Resolve the name the agent calls this session by — what the user sees in
35
+ * their own terminal, which the phone shows instead of the computed
36
+ * `<project> · <Agent> #N` label.
37
+ *
38
+ * Same shape as `resolveSessionId` and the same EXTENSION POINT rule: a row
39
+ * carries this only once that agent's name store is confirmed. Cursor and
40
+ * Gemini never will — their state files hold ids, cwds and timestamps and no
41
+ * name at all, so there is nothing to read and the computed label stands.
42
+ */
43
+ resolveSessionName?: (paneCwd: string, panePid?: number) => string | null;
44
+ /**
45
+ * Resolve the file this agent is writing its session transcript to, for the
46
+ * live chat timeline (`turn-watch`).
47
+ *
48
+ * Same shape and the same EXTENSION POINT rule as the two above: a row
49
+ * carries this only once that agent's transcript format is confirmed, and a
50
+ * pane whose agent omits it answers `no_transcript` rather than guessing.
51
+ * That is the seam a second agent hangs off — the reader that parses the
52
+ * file is `projectTranscript` below.
53
+ */
54
+ resolveTranscript?: (paneCwd: string, panePid?: number) => string | null;
55
+ /**
56
+ * Read this agent's transcript lines into the events the timeline draws.
57
+ *
58
+ * Set with `resolveTranscript` or not at all — `remote-agents.test.ts`
59
+ * enforces the pair over the whole table. Half a pair is the one failure
60
+ * mode worth a test here: a path nothing can parse reaches the phone as an
61
+ * empty timeline, which reads as a hung agent, where the missing row would
62
+ * have said "no live timeline" and been true.
63
+ */
64
+ projectTranscript?: TranscriptProjector;
65
+ /**
66
+ * How to read what `resolveTranscript` returned, for an agent whose
67
+ * transcript is not an append-only file. Omitted by every row whose is —
68
+ * those are tailed by `readTranscriptDelta`. opencode is the one that sets
69
+ * it: its "path" names a session in its SQLite store (`opencode-transcript.ts`).
70
+ */
71
+ readTranscript?: TranscriptReader;
72
+ }
73
+ /**
74
+ * The directory name Claude Code gives a cwd under `~/.claude/projects/`.
75
+ * Copied from the Claude Code 2.1.287 binary (`k` / `Jx`): every character
76
+ * outside `[a-zA-Z0-9]` becomes `-`, so `.`, `_`, spaces, `@` and Hangul all
77
+ * collapse, one `-` per UTF-16 unit. Names past 200 characters are cut and
78
+ * suffixed with `-` plus the base-36 of a Java-style string hash of the cwd.
79
+ * mcp-server/src/config.ts carries the same rule and test vectors — keep the
80
+ * two in step.
81
+ */
82
+ export declare const claudeProjectDirName: (cwd: string) => string;
83
+ /**
84
+ * Locate the most recent Claude Code session UUID for the working
85
+ * directory of a tmux pane. Mirrors `mcp-server/config.ts`'s
86
+ * detectClaudeSessionId: CC writes per-session jsonl files at
87
+ * `~/.claude/projects/<claudeProjectDirName(cwd)>/<UUID>.jsonl`.
88
+ * Cached for 60s — see
89
+ * claudeSessionCache.
90
+ */
91
+ export declare const detectClaudeSessionId: (cwd: string) => string | null;
92
+ export interface PidSessionRecord {
93
+ pid: number;
94
+ sessionId: string;
95
+ cwd: string;
96
+ /**
97
+ * What Claude Code calls this session (`hwipit-95` when derived from the
98
+ * cwd, free text once named). Optional: an older CC writes the record
99
+ * without it, and a record without a name is still a valid id match.
100
+ */
101
+ name?: string;
102
+ }
103
+ export interface ProcTable {
104
+ /** ppid → its direct children, for walking a pane's process tree. */
105
+ children: Map<number, number[]>;
106
+ /** pid → process start time in epoch ms. Only pids whose `lstart` parsed. */
107
+ startTimes: Map<number, number>;
108
+ /** pid → its process group id. Absent when the row carried no pgid. */
109
+ pgidOf: Map<number, number>;
110
+ /** pid → the foreground process group of its controlling tty. A pane
111
+ * shell whose tpgid equals its own pgid IS the foreground — a plain
112
+ * prompt; anything else is running a foreground command. */
113
+ tpgidOf: Map<number, number>;
114
+ /** pid → its command name (`comm`), last column because it may contain
115
+ * spaces (`tmux: client`). Basename-matched against the agent registry. */
116
+ commOf: Map<number, string>;
117
+ }
118
+ /**
119
+ * Parse `ps -axo pid=,ppid=,lstart=`. A row is `<pid> <ppid> [<lstart>]`, e.g.
120
+ * ` 1 0 Fri Aug 7 11:12:59 2026 ` — note the two spaces before a
121
+ * single-digit day and the trailing padding.
122
+ *
123
+ * The third field is OPTIONAL in the pattern, and that is load-bearing rather
124
+ * than defensive. Requiring it would mean that on any machine whose `ps` prints
125
+ * a different `lstart` shape, EVERY row fails to match, `children` comes back
126
+ * empty, `collectDescendantPids` answers `{rootPid}`, and
127
+ * `detectClaudeSessionByPid` finds nothing — dropping Claude Code back to the
128
+ * mtime heuristic and its identity theft (see CLAUDE_SESSIONS_DIR above). The
129
+ * parent links must survive an unreadable timestamp; only the start time is
130
+ * allowed to go missing, and every consumer of `startTimes` treats an absent
131
+ * entry as "no match" rather than guessing.
132
+ */
133
+ /**
134
+ * Parse `ps -axo pid=,ppid=,pgid=,tpgid=,lstart=,comm=`. A row is
135
+ * `<pid> <ppid> <pgid> <tpgid> [<lstart>] [<comm>]`, e.g.
136
+ * ` 902 1 902 902 Fri Aug 7 11:12:59 2026 zsh` — note the two spaces
137
+ * before a single-digit day and the trailing padding.
138
+ *
139
+ * Token positions, not one regex: `lstart` is a fixed 5 tokens when present
140
+ * and `comm` is LAST because it may contain spaces. A row with fewer tokens
141
+ * simply contributes fewer maps — the shape is load-bearing rather than
142
+ * defensive: parent links must survive an unreadable timestamp (the reason
143
+ * `lstart` is optional), and the pgid/tpgid/comm columns are absent only when
144
+ * a caller fed the old narrower argv, which nothing in production does.
145
+ */
146
+ export declare const parseProcTable: (table: string) => ProcTable;
147
+ /**
148
+ * The process table, or null when `ps` failed. Exported with its spawn as a
149
+ * seam so the bounds are testable without a real `ps`.
150
+ */
151
+ export declare const readProcTable: (run?: typeof spawnSync) => ProcTable | null;
152
+ /**
153
+ * The agent running in the FOREGROUND process group of the tty owned by a
154
+ * pane shell, or null. This is what separates a subagent pane from a plain
155
+ * prompt: the subagent pane reports `pane_current_command=bash` (a script
156
+ * execs pi), so the pane-level command identifies nothing — but the tty's
157
+ * foreground group is pi's, and `comm` names it. A pane sitting at its login
158
+ * shell has the shell's own group in the foreground (tpgid === pgid) and is
159
+ * not a subagent, no matter what the registry would match.
160
+ */
161
+ export declare const foregroundAgentFor: (panePid: number, table?: ProcTable | null) => RegisteredRemoteAgent | null;
162
+ /** Start times for this cycle's snapshot. Empty when `ps` is unavailable. */
163
+ export declare const psStartTimes: () => Map<number, number>;
164
+ /** pid set of `rootPid` + all descendants, from one `ps` snapshot. */
165
+ export declare const collectDescendantPids: (rootPid: number) => Set<number>;
166
+ /** Test seam for the pid-based resolver. */
167
+ export interface PidResolveDeps {
168
+ records?: PidSessionRecord[];
169
+ descendants?: Set<number>;
170
+ }
171
+ /**
172
+ * Whether this machine's Claude Code writes `~/.claude/sessions` records at all.
173
+ *
174
+ * The difference between "no records anywhere" (an older CC — the mtime
175
+ * heuristic is the only option) and "records exist, none match this pane" (the
176
+ * pane is not a Claude session) is the difference between a useful fallback and
177
+ * a wrong answer, so callers that care ask it explicitly.
178
+ */
179
+ export declare const pidSessionRecordsExist: () => boolean;
180
+ /**
181
+ * Exact resolution: the session record whose pid lives in the pane's
182
+ * process tree AND whose cwd matches (guards against OS pid reuse
183
+ * leaving a stale record pointing elsewhere). Null → caller falls back
184
+ * to the mtime heuristic.
185
+ *
186
+ * Returns the whole record so the id and the name come from one lookup — they
187
+ * describe the same session, and reading the directory twice per cycle to get
188
+ * them separately is what the cache above exists to avoid.
189
+ */
190
+ export declare const detectClaudeSessionByPid: (panePid: number, paneCwd: string | null, deps?: PidResolveDeps) => PidSessionRecord | null;
191
+ export declare const detectClaudeSessionIdByPid: (panePid: number, paneCwd: string | null, deps?: PidResolveDeps) => string | null;
192
+ /**
193
+ * The name of the session running in this pane. No mtime fallback exists here:
194
+ * the transcript filenames the heuristic walks carry a UUID and nothing else,
195
+ * so an older CC without `~/.claude/sessions` yields no name and the phone
196
+ * keeps the computed label.
197
+ */
198
+ export declare const detectClaudeSessionNameByPid: (panePid: number, paneCwd: string | null, deps?: PidResolveDeps) => string | null;
199
+ /**
200
+ * The transcript file for the Claude Code session running in a tmux pane.
201
+ *
202
+ * Pid first, cwd only as a fallback, and the order is the whole point: the cwd
203
+ * heuristic picks the newest `*.jsonl` in the directory, so a second `claude`
204
+ * started in the same repo steals the first one's transcript (the comment above
205
+ * `detectClaudeSessionIdByPid` records that failure). Live-timeline viewers are
206
+ * per tmux session, so two sessions in one directory must resolve to two files
207
+ * or each phone reads the other's work.
208
+ *
209
+ * Returns null when this pane is not running Claude Code at all — a Codex or
210
+ * Gemini pane has no transcript here, and that is an answer, not a failure.
211
+ */
212
+ export declare const claudeTranscriptPath: (paneCwd: string | null, panePid?: number) => string | null;
213
+ /**
214
+ * The transcript a pi pane is writing, or null when there is none to follow.
215
+ *
216
+ * Newest-by-mtime within the directory. pi keeps no pid→session record the way
217
+ * Claude Code does, so `panePid` cannot pick between two pi panes sharing a
218
+ * directory — both resolve to the newer session's file. That is the known limit
219
+ * of this resolver, and it is the same shape as Claude's mtime fallback.
220
+ *
221
+ * `panePid` still matters, as the cache key: a restart in the same directory
222
+ * writes a new file, and a cwd-only key would keep answering with the old one
223
+ * until the TTL ran out.
224
+ */
225
+ export declare const piTranscriptPath: (paneCwd: string | null, panePid?: number) => string | null;
226
+ /**
227
+ * The row whose timestamp is closest to when one of the pane's processes started,
228
+ * within {@link PROC_MATCH_TOLERANCE_MS}. Null when nothing qualifies — including
229
+ * when no pid in the tree has a known start time, which is why the start times
230
+ * are collected before any row is compared rather than defaulted to zero.
231
+ */
232
+ export declare const pickRowByProcStart: <T>(rows: readonly T[], tsMsOf: (row: T) => number | null, startTimes: Map<number, number>, pids: Set<number>) => T | null;
233
+ /**
234
+ * Read rows from a SQLite file as JSON. Null on every failure — no `sqlite3` on
235
+ * PATH, a locked or corrupt database, a schema that moved — because a missing
236
+ * name costs the computed label and nothing else.
237
+ *
238
+ * The query carries no parameters BY DESIGN: SQL passed to the `sqlite3` binary
239
+ * as an argv string has nowhere to bind `?` to, so interpolating a cwd would
240
+ * make this file the place that has to know SQLite quoting rules. Callers select
241
+ * the columns they need and filter in JS instead; the stores hold tens of rows,
242
+ * not millions. The `timeout` keeps a locked database from holding up a report
243
+ * cycle that runs every five seconds.
244
+ */
245
+ export declare const sqliteJson: (dbPath: string, sql: string, run?: typeof spawnSync) => unknown[] | null;
246
+ /** Test seam for the store-backed resolvers. `rows: null` = the read failed. */
247
+ export interface StoreResolveDeps {
248
+ rows?: unknown[] | null;
249
+ startTimes?: Map<number, number>;
250
+ descendants?: Set<number>;
251
+ }
252
+ export declare const detectHermesSessionName: (paneCwd: string, panePid?: number, deps?: StoreResolveDeps) => string | null;
253
+ /**
254
+ * The highest-numbered match, numerically. Codex versions its state file
255
+ * (`state_5.sqlite` today) and moves to the next number on a schema migration,
256
+ * so hard-coding a name would silently stop reading after an upgrade. Sorting
257
+ * the strings would break at `state_10` vs `state_9`.
258
+ */
259
+ export declare const newestVersionedDb: (entries: readonly string[], pattern: RegExp) => string | null;
260
+ /**
261
+ * No `source` filter, unlike the Hermes reader's `source = 'cli'`. The column
262
+ * exists here too (alongside `thread_source`), but Codex is unauthenticated on
263
+ * every machine measured so far and its `threads` table is empty, so which
264
+ * values mark a terminal session is unknown — and a wrong guess filters out
265
+ * every row, which fails as "no name ever" rather than loudly. A thread from a
266
+ * non-terminal frontend is therefore eligible to match, and it lands in the same
267
+ * accepted misjoin as two terminals in the same directory: it needs the same cwd
268
+ * AND a creation time within the tolerance of a process in this pane. Add the
269
+ * filter once the values can be observed.
270
+ */
271
+ export declare const detectCodexSessionName: (paneCwd: string, panePid?: number, deps?: StoreResolveDeps) => string | null;
272
+ export declare const codexTranscriptPath: (paneCwd: string | null, panePid?: number) => string | null;
273
+ /**
274
+ * The transcript a Gemini pane is writing, or null when there is none to follow.
275
+ *
276
+ * Newest-by-mtime within the project's `chats` directory, which also follows a
277
+ * resumed session: Gemini keeps appending to the original file. Like pi's,
278
+ * Gemini keeps no pid → session record, so two Gemini panes in one directory
279
+ * both resolve to the newer file — the known limit — and `panePid` is only the
280
+ * cache key that lets a restart be noticed.
281
+ *
282
+ * The cwd is resolved as given; if a pane's cwd and the path Gemini registered
283
+ * ever differ by a symlink (`/tmp` ↔ `/private/tmp`) this answers null, and
284
+ * realpath is the fix to reach for then.
285
+ */
286
+ export declare const geminiTranscriptPath: (paneCwd: string | null, panePid?: number) => string | null;
287
+ /**
288
+ * The opencode session running in this pane: the one in the pane's directory
289
+ * written to most recently since the pane's process started. Started-since is
290
+ * what keeps a pane that has not sent its first prompt — no session row yet —
291
+ * from being handed yesterday's session in the same directory. Two opencode
292
+ * panes in one directory both answer the busier one: the store says nothing
293
+ * about which process wrote what, the limit pi and Gemini already have.
294
+ */
295
+ export declare const detectOpencodeSession: (paneCwd: string, panePid?: number, deps?: StoreResolveDeps) => {
296
+ id: string;
297
+ title: string | null;
298
+ } | null;
299
+ export declare const opencodeTranscriptPath: (paneCwd: string | null, panePid?: number) => string | null;
300
+ declare const REMOTE_AGENT_TABLE: readonly [{
301
+ readonly kind: "claude";
302
+ readonly displayName: "Claude Code";
303
+ readonly binary: "claude";
304
+ readonly subcommands: readonly ["cc", "claude"];
305
+ readonly quitCommand: "/exit";
306
+ readonly resolveSessionId: (paneCwd: string, panePid: number | undefined) => string | null;
307
+ readonly resolveSessionName: (paneCwd: string, panePid: number | undefined) => string | null;
308
+ readonly resolveTranscript: (paneCwd: string, panePid: number | undefined) => string | null;
309
+ readonly projectTranscript: TranscriptProjector;
310
+ }, {
311
+ readonly kind: "codex";
312
+ readonly displayName: "Codex CLI";
313
+ readonly binary: "codex";
314
+ readonly subcommands: readonly ["codex"];
315
+ readonly resolveSessionName: (paneCwd: string, panePid?: number, deps?: StoreResolveDeps) => string | null;
316
+ readonly resolveTranscript: (paneCwd: string, panePid: number | undefined) => string | null;
317
+ readonly projectTranscript: TranscriptProjector;
318
+ }, {
319
+ readonly kind: "cursor";
320
+ readonly displayName: "Cursor CLI";
321
+ readonly binary: "cursor-agent";
322
+ readonly subcommands: readonly ["cursor", "cursor-agent"];
323
+ }, {
324
+ readonly kind: "gemini";
325
+ readonly displayName: "Gemini CLI";
326
+ readonly binary: "gemini";
327
+ readonly subcommands: readonly ["gemini"];
328
+ readonly resolveTranscript: (paneCwd: string, panePid: number | undefined) => string | null;
329
+ readonly projectTranscript: TranscriptProjector;
330
+ }, {
331
+ readonly kind: "hermes";
332
+ readonly displayName: "Hermes";
333
+ readonly binary: "hermes";
334
+ readonly subcommands: readonly ["hermes"];
335
+ readonly resolveSessionName: (paneCwd: string, panePid?: number, deps?: StoreResolveDeps) => string | null;
336
+ }, {
337
+ readonly kind: "pi";
338
+ readonly displayName: "Pi";
339
+ readonly binary: "pi";
340
+ readonly subcommands: readonly ["pi"];
341
+ readonly resolveTranscript: (paneCwd: string, panePid: number | undefined) => string | null;
342
+ readonly projectTranscript: TranscriptProjector;
343
+ }, {
344
+ readonly kind: "opencode";
345
+ readonly displayName: "OpenCode";
346
+ readonly binary: "opencode";
347
+ readonly subcommands: readonly ["opencode"];
348
+ readonly quitCommand: "/exit";
349
+ readonly resolveSessionId: (paneCwd: string, panePid: number | undefined) => string | null;
350
+ readonly resolveSessionName: (paneCwd: string, panePid: number | undefined) => string | null;
351
+ readonly resolveTranscript: (paneCwd: string, panePid: number | undefined) => string | null;
352
+ readonly projectTranscript: TranscriptProjector;
353
+ readonly readTranscript: (path: string, prev: import("./transcript-tail.js").TailState | null) => import("./transcript-tail.js").TailRead | null;
354
+ }, {
355
+ readonly kind: "kimi";
356
+ readonly displayName: "Kimi Code";
357
+ readonly binary: "kimi";
358
+ readonly subcommands: readonly ["kimi"];
359
+ }, {
360
+ readonly kind: "grok";
361
+ readonly displayName: "Grok Build";
362
+ readonly binary: "grok";
363
+ readonly subcommands: readonly ["grok"];
364
+ }, {
365
+ readonly kind: "antigravity";
366
+ readonly displayName: "Antigravity";
367
+ readonly binary: "agy";
368
+ readonly subcommands: readonly ["agy", "antigravity"];
369
+ }, {
370
+ readonly kind: "qwen";
371
+ readonly displayName: "Qwen Code";
372
+ readonly binary: "qwen";
373
+ readonly subcommands: readonly ["qwen"];
374
+ }, {
375
+ readonly kind: "auggie";
376
+ readonly displayName: "Auggie";
377
+ readonly binary: "auggie";
378
+ readonly subcommands: readonly ["auggie"];
379
+ }, {
380
+ readonly kind: "kilo";
381
+ readonly displayName: "Kilo";
382
+ readonly binary: "kilo";
383
+ readonly subcommands: readonly ["kilo"];
384
+ }, {
385
+ readonly kind: "copilot";
386
+ readonly displayName: "Copilot CLI";
387
+ readonly binary: "copilot";
388
+ readonly subcommands: readonly ["copilot"];
389
+ }, {
390
+ readonly kind: "kiro";
391
+ readonly displayName: "Kiro";
392
+ readonly binary: "kiro-cli";
393
+ readonly subcommands: readonly ["kiro-cli", "kiro"];
394
+ }, {
395
+ readonly kind: "droid";
396
+ readonly displayName: "Factory Droid";
397
+ readonly binary: "droid";
398
+ readonly subcommands: readonly ["droid"];
399
+ }];
400
+ /** Closed union of remote-controllable agent kinds, derived from the table above. */
401
+ export type AgentKind = (typeof REMOTE_AGENT_TABLE)[number]['kind'];
402
+ /** A registry row: the uniform RemoteAgent shape with `kind` narrowed to the closed union. */
403
+ export type RegisteredRemoteAgent = RemoteAgent & {
404
+ kind: AgentKind;
405
+ };
406
+ export declare const REMOTE_AGENTS: readonly RegisteredRemoteAgent[];
407
+ export declare const findAgentBySubcommand: (cmd: string) => RegisteredRemoteAgent | undefined;
408
+ export declare const matchAgentByPaneCommand: (base: string) => RegisteredRemoteAgent | undefined;
409
+ export {};
410
+ //# sourceMappingURL=remote-agents.d.ts.map