@hwip/cli 0.0.1 → 0.1.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/LICENSE +190 -0
- package/NOTICE +11 -0
- package/README.md +1983 -0
- package/dist/agent-list.d.ts +76 -0
- package/dist/agent-list.js +102 -0
- package/dist/agent-read.d.ts +105 -0
- package/dist/agent-read.js +309 -0
- package/dist/agent-rules-fetch.d.ts +51 -0
- package/dist/agent-rules-fetch.js +275 -0
- package/dist/agent-rules.default.d.ts +30 -0
- package/dist/agent-rules.default.js +305 -0
- package/dist/agent-session.d.ts +23 -0
- package/dist/agent-session.js +44 -0
- package/dist/agent-state.d.ts +84 -0
- package/dist/agent-state.js +188 -0
- package/dist/agent-target.d.ts +60 -0
- package/dist/agent-target.js +81 -0
- package/dist/agents.d.ts +31 -0
- package/dist/agents.js +75 -0
- package/dist/api.d.ts +28 -0
- package/dist/api.js +76 -0
- package/dist/args.d.ts +74 -0
- package/dist/args.js +254 -0
- package/dist/ask-context-attach.d.ts +73 -0
- package/dist/ask-context-attach.js +151 -0
- package/dist/ask-context-screen.d.ts +21 -0
- package/dist/ask-context-screen.js +49 -0
- package/dist/ask-context-switch.d.ts +31 -0
- package/dist/ask-context-switch.js +74 -0
- package/dist/ask-context.d.ts +84 -0
- package/dist/ask-context.js +172 -0
- package/dist/ask-pending.d.ts +47 -0
- package/dist/ask-pending.js +221 -0
- package/dist/ask-seal.d.ts +120 -0
- package/dist/ask-seal.js +179 -0
- package/dist/ask.d.ts +107 -0
- package/dist/ask.js +551 -0
- package/dist/blocked-prompt-seal.d.ts +39 -0
- package/dist/blocked-prompt-seal.js +92 -0
- package/dist/blocked-prompt.d.ts +62 -0
- package/dist/blocked-prompt.js +518 -0
- package/dist/channel.d.ts +67 -0
- package/dist/channel.js +136 -0
- package/dist/check-update.d.ts +28 -0
- package/dist/check-update.js +153 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +813 -0
- package/dist/codex-config.d.ts +24 -0
- package/dist/codex-config.js +169 -0
- package/dist/codex-transcript.d.ts +59 -0
- package/dist/codex-transcript.js +373 -0
- package/dist/command-refusal.d.ts +56 -0
- package/dist/command-refusal.js +127 -0
- package/dist/command-scan.d.ts +46 -0
- package/dist/command-scan.js +154 -0
- package/dist/command-seal.d.ts +57 -0
- package/dist/command-seal.js +88 -0
- package/dist/command-seq.d.ts +30 -0
- package/dist/command-seq.js +150 -0
- package/dist/config.d.ts +156 -0
- package/dist/config.js +392 -0
- package/dist/core-sections.d.ts +18 -0
- package/dist/core-sections.js +28 -0
- package/dist/crypto.d.ts +278 -0
- package/dist/crypto.js +698 -0
- package/dist/desktop-notify.d.ts +33 -0
- package/dist/desktop-notify.js +49 -0
- package/dist/device-directory.d.ts +36 -0
- package/dist/device-directory.js +97 -0
- package/dist/device-presence.d.ts +17 -0
- package/dist/device-presence.js +62 -0
- package/dist/downloads.d.ts +29 -0
- package/dist/downloads.js +106 -0
- package/dist/errors.d.ts +12 -0
- package/dist/errors.js +28 -0
- package/dist/file-crypto.d.ts +94 -0
- package/dist/file-crypto.js +278 -0
- package/dist/file-view-budget.d.ts +15 -0
- package/dist/file-view-budget.js +34 -0
- package/dist/file-view-switch.d.ts +28 -0
- package/dist/file-view-switch.js +122 -0
- package/dist/file-view.d.ts +108 -0
- package/dist/file-view.js +327 -0
- package/dist/gate.d.ts +141 -0
- package/dist/gate.js +336 -0
- package/dist/gemini-transcript.d.ts +32 -0
- package/dist/gemini-transcript.js +189 -0
- package/dist/http-failure.d.ts +98 -0
- package/dist/http-failure.js +349 -0
- package/dist/hwip-core.generated.d.ts +7 -0
- package/dist/hwip-core.generated.js +14 -0
- package/dist/hwip-hook.d.ts +77 -0
- package/dist/hwip-hook.js +340 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +14 -0
- package/dist/input-sequencer.d.ts +65 -0
- package/dist/input-sequencer.js +142 -0
- package/dist/insecure-url.d.ts +16 -0
- package/dist/insecure-url.js +76 -0
- package/dist/installer.d.ts +96 -0
- package/dist/installer.js +850 -0
- package/dist/inventory-offload.d.ts +49 -0
- package/dist/inventory-offload.js +209 -0
- package/dist/inventory-worker.d.ts +2 -0
- package/dist/inventory-worker.js +27 -0
- package/dist/jsonc-doc.d.ts +106 -0
- package/dist/jsonc-doc.js +354 -0
- package/dist/keep-awake.d.ts +32 -0
- package/dist/keep-awake.js +46 -0
- package/dist/key-changes.d.ts +48 -0
- package/dist/key-changes.js +140 -0
- package/dist/lan-auth.d.ts +140 -0
- package/dist/lan-auth.js +217 -0
- package/dist/lan-endpoint.d.ts +41 -0
- package/dist/lan-endpoint.js +115 -0
- package/dist/lan-receiver.d.ts +122 -0
- package/dist/lan-receiver.js +510 -0
- package/dist/lan-sender.d.ts +76 -0
- package/dist/lan-sender.js +184 -0
- package/dist/lan-transfer.d.ts +36 -0
- package/dist/lan-transfer.js +54 -0
- package/dist/listener-device-id.d.ts +20 -0
- package/dist/listener-device-id.js +133 -0
- package/dist/listener-log.d.ts +4 -0
- package/dist/listener-log.js +23 -0
- package/dist/listener-process.d.ts +200 -0
- package/dist/listener-process.js +470 -0
- package/dist/listener-service.d.ts +225 -0
- package/dist/listener-service.js +682 -0
- package/dist/listener-worktree-cleanup.d.ts +27 -0
- package/dist/listener-worktree-cleanup.js +62 -0
- package/dist/listener.d.ts +1325 -0
- package/dist/listener.js +5681 -0
- package/dist/login-address.d.ts +25 -0
- package/dist/login-address.js +97 -0
- package/dist/login-page.d.ts +29 -0
- package/dist/login-page.js +93 -0
- package/dist/login.d.ts +98 -0
- package/dist/login.js +388 -0
- package/dist/mcp-command.d.ts +45 -0
- package/dist/mcp-command.js +50 -0
- package/dist/mcp.d.ts +19 -0
- package/dist/mcp.js +29 -0
- package/dist/node-support.d.ts +19 -0
- package/dist/node-support.js +38 -0
- package/dist/notify-failure.d.ts +57 -0
- package/dist/notify-failure.js +150 -0
- package/dist/opencode-transcript.d.ts +139 -0
- package/dist/opencode-transcript.js +390 -0
- package/dist/optional-features.d.ts +6 -0
- package/dist/optional-features.js +19 -0
- package/dist/pane-fit.d.ts +40 -0
- package/dist/pane-fit.js +119 -0
- package/dist/peer-key.d.ts +33 -0
- package/dist/peer-key.js +34 -0
- package/dist/pi-transcript.d.ts +26 -0
- package/dist/pi-transcript.js +255 -0
- package/dist/presence.d.ts +14 -0
- package/dist/presence.js +124 -0
- package/dist/private-files.d.ts +51 -0
- package/dist/private-files.js +218 -0
- package/dist/project-switch.d.ts +19 -0
- package/dist/project-switch.js +60 -0
- package/dist/redact.d.ts +10 -0
- package/dist/redact.js +21 -0
- package/dist/remote-agents.d.ts +410 -0
- package/dist/remote-agents.js +1218 -0
- package/dist/remote-hook.d.ts +12 -0
- package/dist/remote-hook.js +196 -0
- package/dist/replace-file.d.ts +50 -0
- package/dist/replace-file.js +328 -0
- package/dist/schedule-command.d.ts +35 -0
- package/dist/schedule-command.js +260 -0
- package/dist/schedule-launch.d.ts +15 -0
- package/dist/schedule-launch.js +24 -0
- package/dist/schedule-ready.d.ts +44 -0
- package/dist/schedule-ready.js +71 -0
- package/dist/schedule-remote.d.ts +77 -0
- package/dist/schedule-remote.js +167 -0
- package/dist/schedule-runner.d.ts +89 -0
- package/dist/schedule-runner.js +452 -0
- package/dist/schedule.d.ts +149 -0
- package/dist/schedule.js +428 -0
- package/dist/secret-mask.d.ts +29 -0
- package/dist/secret-mask.js +245 -0
- package/dist/self-register.d.ts +45 -0
- package/dist/self-register.js +67 -0
- package/dist/send.d.ts +56 -0
- package/dist/send.js +104 -0
- package/dist/session-diff.d.ts +161 -0
- package/dist/session-diff.js +445 -0
- package/dist/session-registry.d.ts +143 -0
- package/dist/session-registry.js +216 -0
- package/dist/sessions-report.d.ts +59 -0
- package/dist/sessions-report.js +99 -0
- package/dist/shell-audit.d.ts +34 -0
- package/dist/shell-audit.js +47 -0
- package/dist/subagent-transcripts.d.ts +167 -0
- package/dist/subagent-transcripts.js +437 -0
- package/dist/subscriber-trust.d.ts +128 -0
- package/dist/subscriber-trust.js +397 -0
- package/dist/templates.d.ts +105 -0
- package/dist/templates.js +871 -0
- package/dist/tmux-install.d.ts +44 -0
- package/dist/tmux-install.js +65 -0
- package/dist/tmux-liveness.d.ts +45 -0
- package/dist/tmux-liveness.js +71 -0
- package/dist/tmux-pane.d.ts +55 -0
- package/dist/tmux-pane.js +126 -0
- package/dist/tmux-socket.d.ts +20 -0
- package/dist/tmux-socket.js +292 -0
- package/dist/todo-fold.d.ts +31 -0
- package/dist/todo-fold.js +102 -0
- package/dist/transcript-tail.d.ts +312 -0
- package/dist/transcript-tail.js +718 -0
- package/dist/trust-command.d.ts +49 -0
- package/dist/trust-command.js +200 -0
- package/dist/trust-lock.d.ts +26 -0
- package/dist/trust-lock.js +94 -0
- package/dist/trust-pins.d.ts +37 -0
- package/dist/trust-pins.js +82 -0
- package/dist/turn-recorder-wire.d.ts +70 -0
- package/dist/turn-recorder-wire.js +165 -0
- package/dist/turn-recorder.d.ts +190 -0
- package/dist/turn-recorder.js +695 -0
- package/dist/turn-ring.d.ts +93 -0
- package/dist/turn-ring.js +418 -0
- package/dist/turn-watch.d.ts +177 -0
- package/dist/turn-watch.js +630 -0
- package/dist/types.d.ts +63 -0
- package/dist/types.js +2 -0
- package/dist/uninstall.d.ts +55 -0
- package/dist/uninstall.js +507 -0
- package/dist/usage.d.ts +17 -0
- package/dist/usage.js +421 -0
- package/dist/verify.d.ts +47 -0
- package/dist/verify.js +396 -0
- package/dist/worktree.d.ts +144 -0
- package/dist/worktree.js +310 -0
- package/dist/wrapper.d.ts +254 -0
- package/dist/wrapper.js +704 -0
- package/dist/ws-url.d.ts +109 -0
- package/dist/ws-url.js +202 -0
- package/package.json +78 -10
- 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
|