@gigaflow/gmux 0.15.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 (229) hide show
  1. package/CHANGELOG.md +654 -0
  2. package/LICENSE +21 -0
  3. package/README.md +351 -0
  4. package/dist/adapters/claude-code.d.ts +52 -0
  5. package/dist/adapters/claude-code.js +315 -0
  6. package/dist/adapters/claude-code.js.map +1 -0
  7. package/dist/adapters/codex.d.ts +39 -0
  8. package/dist/adapters/codex.js +233 -0
  9. package/dist/adapters/codex.js.map +1 -0
  10. package/dist/adapters/jsonl.d.ts +40 -0
  11. package/dist/adapters/jsonl.js +92 -0
  12. package/dist/adapters/jsonl.js.map +1 -0
  13. package/dist/adapters/registry.d.ts +11 -0
  14. package/dist/adapters/registry.js +21 -0
  15. package/dist/adapters/registry.js.map +1 -0
  16. package/dist/adapters/types.d.ts +43 -0
  17. package/dist/adapters/types.js +2 -0
  18. package/dist/adapters/types.js.map +1 -0
  19. package/dist/cli/border-client.d.ts +8 -0
  20. package/dist/cli/border-client.js +11 -0
  21. package/dist/cli/border-client.js.map +1 -0
  22. package/dist/cli/commands/__ask-cancel.d.ts +35 -0
  23. package/dist/cli/commands/__ask-cancel.js +91 -0
  24. package/dist/cli/commands/__ask-cancel.js.map +1 -0
  25. package/dist/cli/commands/__ask-refresh.d.ts +40 -0
  26. package/dist/cli/commands/__ask-refresh.js +54 -0
  27. package/dist/cli/commands/__ask-refresh.js.map +1 -0
  28. package/dist/cli/commands/__ask-run.d.ts +43 -0
  29. package/dist/cli/commands/__ask-run.js +126 -0
  30. package/dist/cli/commands/__ask-run.js.map +1 -0
  31. package/dist/cli/commands/__ask-send.d.ts +50 -0
  32. package/dist/cli/commands/__ask-send.js +138 -0
  33. package/dist/cli/commands/__ask-send.js.map +1 -0
  34. package/dist/cli/commands/__preview-card.d.ts +31 -0
  35. package/dist/cli/commands/__preview-card.js +72 -0
  36. package/dist/cli/commands/__preview-card.js.map +1 -0
  37. package/dist/cli/commands/ask.d.ts +50 -0
  38. package/dist/cli/commands/ask.js +240 -0
  39. package/dist/cli/commands/ask.js.map +1 -0
  40. package/dist/cli/commands/auto.d.ts +12 -0
  41. package/dist/cli/commands/auto.js +28 -0
  42. package/dist/cli/commands/auto.js.map +1 -0
  43. package/dist/cli/commands/cockpit.d.ts +14 -0
  44. package/dist/cli/commands/cockpit.js +52 -0
  45. package/dist/cli/commands/cockpit.js.map +1 -0
  46. package/dist/cli/commands/daemon.d.ts +75 -0
  47. package/dist/cli/commands/daemon.js +258 -0
  48. package/dist/cli/commands/daemon.js.map +1 -0
  49. package/dist/cli/commands/doctor.d.ts +6 -0
  50. package/dist/cli/commands/doctor.js +159 -0
  51. package/dist/cli/commands/doctor.js.map +1 -0
  52. package/dist/cli/commands/grep.d.ts +2 -0
  53. package/dist/cli/commands/grep.js +52 -0
  54. package/dist/cli/commands/grep.js.map +1 -0
  55. package/dist/cli/commands/index-cmd.d.ts +2 -0
  56. package/dist/cli/commands/index-cmd.js +29 -0
  57. package/dist/cli/commands/index-cmd.js.map +1 -0
  58. package/dist/cli/commands/ls.d.ts +30 -0
  59. package/dist/cli/commands/ls.js +95 -0
  60. package/dist/cli/commands/ls.js.map +1 -0
  61. package/dist/cli/commands/overlay.d.ts +26 -0
  62. package/dist/cli/commands/overlay.js +216 -0
  63. package/dist/cli/commands/overlay.js.map +1 -0
  64. package/dist/cli/commands/pick.d.ts +59 -0
  65. package/dist/cli/commands/pick.js +254 -0
  66. package/dist/cli/commands/pick.js.map +1 -0
  67. package/dist/cli/commands/picker-rows.d.ts +17 -0
  68. package/dist/cli/commands/picker-rows.js +47 -0
  69. package/dist/cli/commands/picker-rows.js.map +1 -0
  70. package/dist/cli/commands/resume.d.ts +25 -0
  71. package/dist/cli/commands/resume.js +88 -0
  72. package/dist/cli/commands/resume.js.map +1 -0
  73. package/dist/cli/commands/run.d.ts +13 -0
  74. package/dist/cli/commands/run.js +78 -0
  75. package/dist/cli/commands/run.js.map +1 -0
  76. package/dist/cli/commands/setup.d.ts +37 -0
  77. package/dist/cli/commands/setup.js +200 -0
  78. package/dist/cli/commands/setup.js.map +1 -0
  79. package/dist/cli/commands/show.d.ts +2 -0
  80. package/dist/cli/commands/show.js +24 -0
  81. package/dist/cli/commands/show.js.map +1 -0
  82. package/dist/cli/commands/summarize.d.ts +2 -0
  83. package/dist/cli/commands/summarize.js +59 -0
  84. package/dist/cli/commands/summarize.js.map +1 -0
  85. package/dist/cli/commands/tmux.d.ts +11 -0
  86. package/dist/cli/commands/tmux.js +90 -0
  87. package/dist/cli/commands/tmux.js.map +1 -0
  88. package/dist/cli/commands/watch.d.ts +2 -0
  89. package/dist/cli/commands/watch.js +76 -0
  90. package/dist/cli/commands/watch.js.map +1 -0
  91. package/dist/cli/format.d.ts +74 -0
  92. package/dist/cli/format.js +242 -0
  93. package/dist/cli/format.js.map +1 -0
  94. package/dist/cli/gmux-render.d.ts +11 -0
  95. package/dist/cli/gmux-render.js +60 -0
  96. package/dist/cli/gmux-render.js.map +1 -0
  97. package/dist/cli/main.d.ts +8 -0
  98. package/dist/cli/main.js +145 -0
  99. package/dist/cli/main.js.map +1 -0
  100. package/dist/cli/overlay-ask.d.ts +13 -0
  101. package/dist/cli/overlay-ask.js +32 -0
  102. package/dist/cli/overlay-ask.js.map +1 -0
  103. package/dist/cli/overlay.d.ts +26 -0
  104. package/dist/cli/overlay.js +149 -0
  105. package/dist/cli/overlay.js.map +1 -0
  106. package/dist/cli/picker.d.ts +308 -0
  107. package/dist/cli/picker.js +642 -0
  108. package/dist/cli/picker.js.map +1 -0
  109. package/dist/cli/preview.d.ts +87 -0
  110. package/dist/cli/preview.js +292 -0
  111. package/dist/cli/preview.js.map +1 -0
  112. package/dist/cli/tmux-label.d.ts +50 -0
  113. package/dist/cli/tmux-label.js +146 -0
  114. package/dist/cli/tmux-label.js.map +1 -0
  115. package/dist/core/errors.d.ts +54 -0
  116. package/dist/core/errors.js +91 -0
  117. package/dist/core/errors.js.map +1 -0
  118. package/dist/core/fingerprint.d.ts +21 -0
  119. package/dist/core/fingerprint.js +59 -0
  120. package/dist/core/fingerprint.js.map +1 -0
  121. package/dist/core/gmux-types.d.ts +102 -0
  122. package/dist/core/gmux-types.js +13 -0
  123. package/dist/core/gmux-types.js.map +1 -0
  124. package/dist/core/pane-state.d.ts +5 -0
  125. package/dist/core/pane-state.js +15 -0
  126. package/dist/core/pane-state.js.map +1 -0
  127. package/dist/core/paths.d.ts +68 -0
  128. package/dist/core/paths.js +106 -0
  129. package/dist/core/paths.js.map +1 -0
  130. package/dist/core/proc-tree.d.ts +9 -0
  131. package/dist/core/proc-tree.js +33 -0
  132. package/dist/core/proc-tree.js.map +1 -0
  133. package/dist/core/text.d.ts +34 -0
  134. package/dist/core/text.js +126 -0
  135. package/dist/core/text.js.map +1 -0
  136. package/dist/core/types.d.ts +322 -0
  137. package/dist/core/types.js +10 -0
  138. package/dist/core/types.js.map +1 -0
  139. package/dist/services/ask-transcript.d.ts +256 -0
  140. package/dist/services/ask-transcript.js +544 -0
  141. package/dist/services/ask-transcript.js.map +1 -0
  142. package/dist/services/ask.d.ts +54 -0
  143. package/dist/services/ask.js +161 -0
  144. package/dist/services/ask.js.map +1 -0
  145. package/dist/services/auto-summarize.d.ts +188 -0
  146. package/dist/services/auto-summarize.js +415 -0
  147. package/dist/services/auto-summarize.js.map +1 -0
  148. package/dist/services/concurrency.d.ts +2 -0
  149. package/dist/services/concurrency.js +16 -0
  150. package/dist/services/concurrency.js.map +1 -0
  151. package/dist/services/config.d.ts +131 -0
  152. package/dist/services/config.js +325 -0
  153. package/dist/services/config.js.map +1 -0
  154. package/dist/services/daemon-client.d.ts +9 -0
  155. package/dist/services/daemon-client.js +34 -0
  156. package/dist/services/daemon-client.js.map +1 -0
  157. package/dist/services/daemon-socket.d.ts +30 -0
  158. package/dist/services/daemon-socket.js +76 -0
  159. package/dist/services/daemon-socket.js.map +1 -0
  160. package/dist/services/daemon.d.ts +43 -0
  161. package/dist/services/daemon.js +106 -0
  162. package/dist/services/daemon.js.map +1 -0
  163. package/dist/services/distill.d.ts +39 -0
  164. package/dist/services/distill.js +93 -0
  165. package/dist/services/distill.js.map +1 -0
  166. package/dist/services/guardian.d.ts +26 -0
  167. package/dist/services/guardian.js +71 -0
  168. package/dist/services/guardian.js.map +1 -0
  169. package/dist/services/index-store.d.ts +36 -0
  170. package/dist/services/index-store.js +125 -0
  171. package/dist/services/index-store.js.map +1 -0
  172. package/dist/services/log-rotation.d.ts +3 -0
  173. package/dist/services/log-rotation.js +28 -0
  174. package/dist/services/log-rotation.js.map +1 -0
  175. package/dist/services/pane-links.d.ts +10 -0
  176. package/dist/services/pane-links.js +47 -0
  177. package/dist/services/pane-links.js.map +1 -0
  178. package/dist/services/pane-process.d.ts +95 -0
  179. package/dist/services/pane-process.js +183 -0
  180. package/dist/services/pane-process.js.map +1 -0
  181. package/dist/services/pane-registry.d.ts +24 -0
  182. package/dist/services/pane-registry.js +40 -0
  183. package/dist/services/pane-registry.js.map +1 -0
  184. package/dist/services/provider-process.d.ts +37 -0
  185. package/dist/services/provider-process.js +105 -0
  186. package/dist/services/provider-process.js.map +1 -0
  187. package/dist/services/providers.d.ts +76 -0
  188. package/dist/services/providers.js +104 -0
  189. package/dist/services/providers.js.map +1 -0
  190. package/dist/services/resolve.d.ts +3 -0
  191. package/dist/services/resolve.js +18 -0
  192. package/dist/services/resolve.js.map +1 -0
  193. package/dist/services/resources.d.ts +17 -0
  194. package/dist/services/resources.js +113 -0
  195. package/dist/services/resources.js.map +1 -0
  196. package/dist/services/search.d.ts +29 -0
  197. package/dist/services/search.js +135 -0
  198. package/dist/services/search.js.map +1 -0
  199. package/dist/services/semantic-gate.d.ts +13 -0
  200. package/dist/services/semantic-gate.js +23 -0
  201. package/dist/services/semantic-gate.js.map +1 -0
  202. package/dist/services/semantic.d.ts +113 -0
  203. package/dist/services/semantic.js +216 -0
  204. package/dist/services/semantic.js.map +1 -0
  205. package/dist/services/sensors.d.ts +92 -0
  206. package/dist/services/sensors.js +246 -0
  207. package/dist/services/sensors.js.map +1 -0
  208. package/dist/services/summarize.d.ts +84 -0
  209. package/dist/services/summarize.js +230 -0
  210. package/dist/services/summarize.js.map +1 -0
  211. package/dist/services/tmux-gateway.d.ts +17 -0
  212. package/dist/services/tmux-gateway.js +10 -0
  213. package/dist/services/tmux-gateway.js.map +1 -0
  214. package/dist/services/tmux-resolve.d.ts +54 -0
  215. package/dist/services/tmux-resolve.js +0 -0
  216. package/dist/services/tmux-resolve.js.map +1 -0
  217. package/dist/services/tmux.d.ts +32 -0
  218. package/dist/services/tmux.js +107 -0
  219. package/dist/services/tmux.js.map +1 -0
  220. package/dist/services/views.d.ts +7 -0
  221. package/dist/services/views.js +18 -0
  222. package/dist/services/views.js.map +1 -0
  223. package/dist/services/watch.d.ts +36 -0
  224. package/dist/services/watch.js +98 -0
  225. package/dist/services/watch.js.map +1 -0
  226. package/dist/services/workspace.d.ts +19 -0
  227. package/dist/services/workspace.js +88 -0
  228. package/dist/services/workspace.js.map +1 -0
  229. package/package.json +64 -0
@@ -0,0 +1,254 @@
1
+ import { rm } from "node:fs/promises";
2
+ import { shellQuote } from "../../core/text.js";
3
+ import { askBrowseQueryPath, askLockPath, newAskTranscriptPath, readAskLock, sweepAskTranscripts, } from "../../services/ask-transcript.js";
4
+ import { inProgressIds, isLockStale, maybeAutoSummarize } from "../../services/auto-summarize.js";
5
+ import { loadViews } from "../../services/views.js";
6
+ import { listWidth, pickSession, selfCommandHere } from "../picker.js";
7
+ import { dim } from "../format.js";
8
+ import { ASK_CANCEL_COMMAND } from "./__ask-cancel.js";
9
+ import { ASK_SEND_COMMAND } from "./__ask-send.js";
10
+ import { askAboutSessions, askIsAvailable } from "./ask.js";
11
+ import { resumeInNewWindow, resumeSession } from "./resume.js";
12
+ import { autoSummarizeRequested, toFilters } from "./ls.js";
13
+ /** The hidden command fzf's ctrl-r binding runs. Not a thing a person runs. */
14
+ export const PICKER_ROWS_COMMAND = "__picker-rows";
15
+ /**
16
+ * The filter flags this picker was opened with, as argv.
17
+ *
18
+ * One copy, because every command the picker spawns must describe the *same*
19
+ * window. A filter that drifts in one of several copies is the silent
20
+ * wrong-window bug the `pickerAskArgs` comment below exists to warn about —
21
+ * nothing errors, the answers are just about other sessions.
22
+ *
23
+ * Values are NOT quoted here — the caller joins and quotes, because argv and a
24
+ * shell command string want different escaping.
25
+ */
26
+ export function filterArgs(options) {
27
+ const args = [];
28
+ if (options.harness)
29
+ args.push("--harness", options.harness);
30
+ if (options.project)
31
+ args.push("-p", options.project);
32
+ if (options.branch)
33
+ args.push("-b", options.branch);
34
+ if (options.since)
35
+ args.push("-s", options.since);
36
+ if (options.limit)
37
+ args.push("-n", options.limit);
38
+ if (options.includeSidechains === true)
39
+ args.push("--include-sidechains");
40
+ if (options.includeAutomated === true)
41
+ args.push("--include-automated");
42
+ return args;
43
+ }
44
+ /**
45
+ * The argv behind ctrl-o, reproducing this picker's filter set for `gmux ask`.
46
+ *
47
+ * Pure, and separate from `pickerReloadArgs` only because the two target
48
+ * different commands — they carry the same filters for the same reason.
49
+ *
50
+ * THE FILTERS ARE THE POINT. `gmux ask` builds its own window; left to its
51
+ * defaults it takes the 20 most recent sessions across every project, which for
52
+ * `gmux pick -p webshop` (or any pick past the 20th row) does not contain the
53
+ * session you are highlighting. `--focus` then finds nothing, resolves to null,
54
+ * and the chat answers about sessions you were not looking at — with no sign
55
+ * anything went wrong.
56
+ *
57
+ * `-n` is forwarded too: the window ask reasons over should be the list you are
58
+ * looking at, not a shorter one it chose for itself.
59
+ *
60
+ * `--focus {1}` is NOT added here. fzf substitutes that token, so it is appended
61
+ * unquoted by the picker; a shell-quoted `{1}` would arrive as a literal.
62
+ */
63
+ export function pickerAskArgs(options) {
64
+ return ["ask", ...filterArgs(options)];
65
+ }
66
+ /**
67
+ * The argv that reproduces this picker's filter set, for fzf's reload binding.
68
+ *
69
+ * Pure, so the thing a refresh actually runs is testable without spawning fzf.
70
+ *
71
+ * `--width` is passed explicitly: the reload child's stdout is a pipe, so it
72
+ * cannot measure the terminal and would fall back to a default width, reflowing
73
+ * every row on refresh. Only the parent, inside fzf, knows the real width.
74
+ */
75
+ export function pickerReloadArgs(options, width, autoSummarize = true) {
76
+ const args = [PICKER_ROWS_COMMAND, "--width", String(width), ...filterArgs(options)];
77
+ // The opt-out MUST cross the process boundary. ctrl-r forces a pass — it
78
+ // bypasses the cooldown — so a dropped flag here would spend tokens the user
79
+ // explicitly declined, with the one thing that might have throttled it
80
+ // removed. Commander reads a root option after the subcommand name fine.
81
+ if (!autoSummarize)
82
+ args.push("--no-auto-summarize");
83
+ return args;
84
+ }
85
+ /**
86
+ * The chat pane's shell commands, or undefined when it cannot be offered.
87
+ *
88
+ * **Built here and not in the picker**, which is the same call `askArgs` already
89
+ * makes: opaque strings in, shell commands out. `pick.ts` owns the provider
90
+ * question (`askIsAvailable`) and the transcript path, so it owns everything the
91
+ * picker would otherwise have to learn — and the picker's import list stays free
92
+ * of `node:fs`, of the lock's shape, and of a provider.
93
+ *
94
+ * **The path is allocated and NOTHING is created.** It has to exist as a string
95
+ * before fzf starts, because it is baked into the preview command; the first
96
+ * `__ask-send` creates the file as a side effect of opening it for append. A run
97
+ * where nobody presses ctrl-o therefore never touches the disk, and a missing
98
+ * file is exactly the empty state.
99
+ *
100
+ * `--port`, `--focus` and `--question` are NOT here: fzf substitutes `{1}` and
101
+ * expands `$FZF_PORT`/`$FZF_QUERY`, and `shellQuote`'s allowed class contains
102
+ * neither `$` nor `{`, so all three would arrive at the child as literal strings.
103
+ * The picker appends them unquoted, after these.
104
+ */
105
+ function pickerChatSpec(options, transcript) {
106
+ const self = selfCommandHere();
107
+ if (!self)
108
+ return undefined;
109
+ const command = (name, args) => `${self} ${[name, "--transcript", transcript, ...args].map(shellQuote).join(" ")}`;
110
+ return {
111
+ transcript,
112
+ // THE FILTERS ARE THE POINT, for the reason `pickerAskArgs` records: the
113
+ // worker builds its own window, and a window built from defaults does not
114
+ // contain the session you are pointing at — `--focus` then resolves to null
115
+ // and the chat answers about a list you never asked about, looking normal the
116
+ // whole time. Baked in at picker start, exactly as ctrl-r's are.
117
+ sendCmd: command(ASK_SEND_COMMAND, filterArgs(options)),
118
+ cancelCmd: command(ASK_CANCEL_COMMAND, []),
119
+ };
120
+ }
121
+ /**
122
+ * Everything the thread leaves on disk, gone when the picker is.
123
+ *
124
+ * **The group kill is here and not only in `__ask-cancel`** because accept and
125
+ * abort never run the esc binding: quit the picker mid-answer and `claude -p`
126
+ * would otherwise keep running, keep billing, and keep writing into a transcript
127
+ * nobody will ever read. Measured — `kill -TERM <worker>` leaves the provider
128
+ * orphaned and alive; only the group dies together.
129
+ *
130
+ * Never throws. A cleanup that fails must not become the way `gmux pick` reports
131
+ * that you picked a session.
132
+ */
133
+ function closeChatThread(transcript) {
134
+ return async () => {
135
+ try {
136
+ const lock = await readAskLock(transcript);
137
+ // Liveness ANDed with age, exactly as `isLockStale` already does — a stale
138
+ // lock's pid is either dead or recycled into some innocent process, and
139
+ // signalling a stranger's group is the worst thing on this path.
140
+ if (lock && lock.pid > 0 && !isLockStale(lock, new Date())) {
141
+ try {
142
+ process.kill(-lock.pid, "SIGTERM");
143
+ }
144
+ catch {
145
+ // ESRCH: it finished on its own. Nothing to reap.
146
+ }
147
+ }
148
+ await rm(transcript, { force: true });
149
+ await rm(askLockPath(transcript), { force: true });
150
+ await rm(askBrowseQueryPath(transcript), { force: true });
151
+ }
152
+ catch {
153
+ // An orphan is a few KB of disposable cache and the sweep will get it.
154
+ }
155
+ };
156
+ }
157
+ /**
158
+ * Load the list and start summaries for whatever needs them.
159
+ *
160
+ * Both the initial paint and a refresh go through here, so `r` in the numbered
161
+ * fallback does what ctrl-r does in fzf rather than only re-rendering stale
162
+ * rows. `force` is set for a refresh: a keypress is an explicit request.
163
+ */
164
+ async function refresh(options, enabled, force, notify) {
165
+ const views = await loadViews(toFilters(options, 50));
166
+ const started = await maybeAutoSummarize({
167
+ records: views.map((v) => v.record),
168
+ enabled,
169
+ force,
170
+ ...(notify ? { notify } : {}),
171
+ });
172
+ return { views, inProgress: new Set([...(await inProgressIds()), ...started.targetIds]) };
173
+ }
174
+ /**
175
+ * The bare `gmux` command: pick a recent session, then resume it.
176
+ * This is the whole point of the tool — everything else is in service of it.
177
+ *
178
+ * Registered as commander's *default* command rather than as options on the root
179
+ * program. Hanging `-n`/`-p` off the root would shadow the identically-named
180
+ * flags on `gmux ls`, so `gmux ls -n 8` would silently ignore the 8.
181
+ */
182
+ export function registerPick(program) {
183
+ program
184
+ .command("pick", { isDefault: true })
185
+ .description("pick a recent session and resume it (this is what bare `gmux` does)")
186
+ .option("--harness <id>", "only this harness")
187
+ .option("-p, --project <name>", "only sessions whose project matches")
188
+ .option("-b, --branch <name>", "only sessions whose git branch matches")
189
+ .option("-s, --since <when>", "only sessions newer than this (3d, 12h, 2w)")
190
+ .option("-n, --limit <count>", "how many sessions to offer", "50")
191
+ .option("--include-sidechains", "include subagent transcripts")
192
+ .option("--include-automated", "include non-interactive runs (claude -p, codex exec)")
193
+ .option("--resume-in-window", "resume the choice in a new tmux window (used by the tmux ctrl-shift-g binding)")
194
+ .action(async (options, command) => {
195
+ const enabled = autoSummarizeRequested(command);
196
+ // Kick the pass off over the sessions we are about to offer, exactly as
197
+ // `ls` does — the postAction hook cannot serve the picker, because our
198
+ // action ends in `resumeSession`, which waits on your harness. That hook
199
+ // fires when you quit Claude Code, not when the list is drawn.
200
+ //
201
+ // The notice goes to stderr, which fzf does not capture, so it prints
202
+ // before the picker paints rather than on top of it.
203
+ const opened = await refresh(options, enabled, false, (message) => process.stderr.write(`${dim(message)}\n`));
204
+ if (opened.views.length === 0) {
205
+ process.stdout.write(`${dim("No sessions found. If you expected some, run `gmux doctor`.")}\n`);
206
+ return;
207
+ }
208
+ // Ask is offered only when it would actually answer. Advertising ctrl-o to
209
+ // someone who chose "no model calls" — or who never installed what they
210
+ // chose — binds a key that opens a chat which dies instantly, and fzf
211
+ // repaints the list over the explanation before it can be read. That is
212
+ // the "key that does nothing" this file already refuses to offer.
213
+ const canAsk = await askIsAvailable();
214
+ // Reap transcripts left behind by pickers that were `kill -9`d. The
215
+ // parent's job, not the picker's, and it runs before we open so a live
216
+ // pane's file is never the one being read while we consider removing it.
217
+ await sweepAskTranscripts();
218
+ // Allocated whatever the fzf version is: only the `split` tier renders a
219
+ // chat, and it is the picker that knows which tier this is. A tier that
220
+ // ignores this never creates the file, so the cleanup below removes
221
+ // nothing and costs nothing.
222
+ const transcript = newAskTranscriptPath();
223
+ const chat = canAsk ? pickerChatSpec(options, transcript) : undefined;
224
+ const chosen = await pickSession(opened.views, {
225
+ inProgress: opened.inProgress,
226
+ reloadArgs: pickerReloadArgs(options, listWidth(), enabled),
227
+ ...(canAsk ? { askArgs: pickerAskArgs(options) } : {}),
228
+ ...(chat ? { chat, onClose: closeChatThread(transcript) } : {}),
229
+ // `a` in the numbered fallback. fzf's ctrl-o does NOT come through here:
230
+ // it runs its own `execute` binding against this build, so the chat gets
231
+ // a clean terminal instead of one fzf is painting.
232
+ ...(canAsk ? { ask: () => askAboutSessions(options) } : {}),
233
+ // `r` in the numbered fallback: forced, like the ctrl-r it stands in for.
234
+ reload: () => refresh(options, enabled, true),
235
+ // ctrl-r can surface a session that did not exist when we opened. Look
236
+ // it up the way `gmux resume <id>` does — naming a session explicitly
237
+ // means you want it, even if the list filters would now hide it.
238
+ resolve: async (id) => {
239
+ const fresh = await loadViews({ includeSidechains: true, includeAutomated: true });
240
+ return fresh.find((v) => v.record.sessionId === id) ?? null;
241
+ },
242
+ });
243
+ if (!chosen) {
244
+ process.stdout.write(`${dim("Nothing selected.")}\n`);
245
+ return;
246
+ }
247
+ if (options.resumeInWindow === true && process.env.TMUX) {
248
+ await resumeInNewWindow(chosen.record);
249
+ return;
250
+ }
251
+ await resumeSession(chosen.record);
252
+ });
253
+ }
254
+ //# sourceMappingURL=pick.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pick.js","sourceRoot":"","sources":["../../../src/cli/commands/pick.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { Command } from "commander";
2
+ /**
3
+ * The picker's ctrl-r target, re-entered as `gmux __picker-rows`.
4
+ *
5
+ * Hidden: like `__auto-summarize`, it is not a thing a person runs. fzf's
6
+ * `reload` binding replaces its item list with a command's stdout, so refresh
7
+ * is exactly "print the records again, having first kicked off summaries".
8
+ *
9
+ * Two rules, both because fzf owns the terminal while this runs:
10
+ *
11
+ * 1. NOTHING goes to stderr. `maybeAutoSummarize`'s notice would land on top of
12
+ * the picker and corrupt the display. The `◐` markers are the notice here.
13
+ * 2. Width comes from `--width`, not from measuring. Our stdout is a pipe, so
14
+ * `terminalWidth()` would report its default and every row would reflow to a
15
+ * different width than it had on open.
16
+ */
17
+ export declare function registerPickerRows(program: Command): void;
@@ -0,0 +1,47 @@
1
+ import { inProgressIds, maybeAutoSummarize } from "../../services/auto-summarize.js";
2
+ import { loadViews } from "../../services/views.js";
3
+ import { buildFzfRecords, fzfVersion, supportsMultiline } from "../picker.js";
4
+ import { PICKER_ROWS_COMMAND } from "./pick.js";
5
+ import { autoSummarizeRequested, toFilters } from "./ls.js";
6
+ /**
7
+ * The picker's ctrl-r target, re-entered as `gmux __picker-rows`.
8
+ *
9
+ * Hidden: like `__auto-summarize`, it is not a thing a person runs. fzf's
10
+ * `reload` binding replaces its item list with a command's stdout, so refresh
11
+ * is exactly "print the records again, having first kicked off summaries".
12
+ *
13
+ * Two rules, both because fzf owns the terminal while this runs:
14
+ *
15
+ * 1. NOTHING goes to stderr. `maybeAutoSummarize`'s notice would land on top of
16
+ * the picker and corrupt the display. The `◐` markers are the notice here.
17
+ * 2. Width comes from `--width`, not from measuring. Our stdout is a pipe, so
18
+ * `terminalWidth()` would report its default and every row would reflow to a
19
+ * different width than it had on open.
20
+ */
21
+ export function registerPickerRows(program) {
22
+ program
23
+ .command(PICKER_ROWS_COMMAND, { hidden: true })
24
+ .description("internal: print picker rows (run by the picker's ctrl-r binding)")
25
+ .option("--harness <id>", "only this harness")
26
+ .option("-p, --project <name>", "only sessions whose project matches")
27
+ .option("-b, --branch <name>", "only sessions whose git branch matches")
28
+ .option("-s, --since <when>", "only sessions newer than this")
29
+ .option("-n, --limit <count>", "how many sessions to offer", "50")
30
+ .option("--include-sidechains", "include subagent transcripts")
31
+ .option("--include-automated", "include non-interactive runs")
32
+ .option("--width <columns>", "list column width, measured by the parent")
33
+ .action(async (options, command) => {
34
+ const views = await loadViews(toFilters(options, 50));
35
+ // Forced: the user pressed a key. The lock still stops a stampede, and
36
+ // `--no-auto-summarize` — forwarded by pickerReloadArgs — still wins.
37
+ const started = await maybeAutoSummarize({
38
+ records: views.map((v) => v.record),
39
+ enabled: autoSummarizeRequested(command),
40
+ force: true,
41
+ });
42
+ const inProgress = new Set([...(await inProgressIds()), ...started.targetIds]);
43
+ const width = Number.parseInt(options.width ?? "", 10);
44
+ process.stdout.write(buildFzfRecords(views, supportsMultiline(fzfVersion()), Number.isFinite(width) && width > 0 ? width : undefined, new Date(), inProgress));
45
+ });
46
+ }
47
+ //# sourceMappingURL=picker-rows.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"picker-rows.js","sourceRoot":"","sources":["../../../src/cli/commands/picker-rows.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AACrF,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAC9E,OAAO,EAAE,mBAAmB,EAA0B,MAAM,WAAW,CAAC;AACxE,OAAO,EAAE,sBAAsB,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAE5D;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAgB;IACjD,OAAO;SACJ,OAAO,CAAC,mBAAmB,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;SAC9C,WAAW,CAAC,kEAAkE,CAAC;SAC/E,MAAM,CAAC,gBAAgB,EAAE,mBAAmB,CAAC;SAC7C,MAAM,CAAC,sBAAsB,EAAE,qCAAqC,CAAC;SACrE,MAAM,CAAC,qBAAqB,EAAE,wCAAwC,CAAC;SACvE,MAAM,CAAC,oBAAoB,EAAE,+BAA+B,CAAC;SAC7D,MAAM,CAAC,qBAAqB,EAAE,4BAA4B,EAAE,IAAI,CAAC;SACjE,MAAM,CAAC,sBAAsB,EAAE,8BAA8B,CAAC;SAC9D,MAAM,CAAC,qBAAqB,EAAE,8BAA8B,CAAC;SAC7D,MAAM,CAAC,mBAAmB,EAAE,2CAA2C,CAAC;SACxE,MAAM,CAAC,KAAK,EAAE,OAA0B,EAAE,OAAgB,EAAE,EAAE;QAC7D,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;QAEtD,uEAAuE;QACvE,sEAAsE;QACtE,MAAM,OAAO,GAAG,MAAM,kBAAkB,CAAC;YACvC,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;YACnC,OAAO,EAAE,sBAAsB,CAAC,OAAO,CAAC;YACxC,KAAK,EAAE,IAAI;SACZ,CAAC,CAAC;QAEH,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,aAAa,EAAE,CAAC,EAAE,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC;QAC/E,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;QAEvD,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,eAAe,CACb,KAAK,EACL,iBAAiB,CAAC,UAAU,EAAE,CAAC,EAC/B,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,EACvD,IAAI,IAAI,EAAE,EACV,UAAU,CACX,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,25 @@
1
+ import type { Command } from "commander";
2
+ import type { SessionRecord } from "../../core/types.js";
3
+ import type { ResumeCommand } from "../../adapters/types.js";
4
+ /**
5
+ * Hand control to the harness that owns this session.
6
+ *
7
+ * We replace this process rather than wrapping it: the user wants to be *in*
8
+ * Claude Code or Codex, not in a gmux shell that proxies keystrokes.
9
+ */
10
+ export declare function resumeSession(record: SessionRecord, dryRun?: boolean): Promise<never | void>;
11
+ /**
12
+ * The tmux argv that opens the resume command in a new window in the current
13
+ * session. Args are passed after `--` so nothing has to be shell-escaped — tmux
14
+ * runs the vector directly. Pure, so the shape is tested without spawning tmux.
15
+ */
16
+ export declare function newWindowArgv(resume: ResumeCommand): string[];
17
+ /**
18
+ * Resume a session in a NEW tmux window instead of replacing this process.
19
+ *
20
+ * Used only by the picker bridge (`gmux pick --resume-in-window`), which runs
21
+ * inside a `display-popup`: exec'ing the harness there would trap it in the
22
+ * ephemeral popup, gone the moment it exits. A new window is a persistent pane.
23
+ */
24
+ export declare function resumeInNewWindow(record: SessionRecord): Promise<void>;
25
+ export declare function registerResume(program: Command): void;
@@ -0,0 +1,88 @@
1
+ import { execFile, spawn } from "node:child_process";
2
+ import { existsSync } from "node:fs";
3
+ import { GmuxError } from "../../core/errors.js";
4
+ import { shellQuote } from "../../core/text.js";
5
+ import { adapterById } from "../../adapters/registry.js";
6
+ import { loadRecords } from "../../services/views.js";
7
+ import { resolveSession } from "../../services/resolve.js";
8
+ import { dim } from "../format.js";
9
+ /**
10
+ * Hand control to the harness that owns this session.
11
+ *
12
+ * We replace this process rather than wrapping it: the user wants to be *in*
13
+ * Claude Code or Codex, not in a gmux shell that proxies keystrokes.
14
+ */
15
+ export async function resumeSession(record, dryRun = false) {
16
+ const adapter = adapterById(record.harness);
17
+ if (!adapter) {
18
+ throw new GmuxError(`No adapter is registered for harness "${record.harness}".`, {
19
+ fix: "This session was indexed by a version of gmux that supported more harnesses. Run `gmux index --rebuild`.",
20
+ });
21
+ }
22
+ const { command, args, cwd } = adapter.resumeCommand(record);
23
+ if (!existsSync(cwd)) {
24
+ throw new GmuxError(`The session's directory no longer exists: ${cwd}`, {
25
+ fix: "The repo or worktree was moved or deleted. Recreate it, or resume manually from another directory.",
26
+ exitCode: 3,
27
+ });
28
+ }
29
+ if (dryRun) {
30
+ // Quote it: this line is meant to be pasted into a shell, and a repo path
31
+ // with a space in it would otherwise silently run in the wrong directory.
32
+ process.stdout.write(`cd ${shellQuote(cwd)} && ${command} ${args.map(shellQuote).join(" ")}\n`);
33
+ return;
34
+ }
35
+ process.stderr.write(`${dim(`→ ${command} ${args.join(" ")} (in ${cwd})`)}\n`);
36
+ const child = spawn(command, args, { cwd, stdio: "inherit" });
37
+ child.on("error", (error) => {
38
+ if (error.code === "ENOENT") {
39
+ process.stderr.write(`error "${command}" is not on your PATH, so this session cannot be resumed.\n` +
40
+ `fix Install ${adapter.displayName}, or run \`gmux resume ${record.sessionId.slice(0, 8)} --print\` to see the command.\n`);
41
+ process.exit(6);
42
+ }
43
+ process.stderr.write(`error ${error.message}\n`);
44
+ process.exit(1);
45
+ });
46
+ child.on("close", (code) => process.exit(code ?? 0));
47
+ }
48
+ /**
49
+ * The tmux argv that opens the resume command in a new window in the current
50
+ * session. Args are passed after `--` so nothing has to be shell-escaped — tmux
51
+ * runs the vector directly. Pure, so the shape is tested without spawning tmux.
52
+ */
53
+ export function newWindowArgv(resume) {
54
+ return ["new-window", "-c", resume.cwd, "--", resume.command, ...resume.args];
55
+ }
56
+ /**
57
+ * Resume a session in a NEW tmux window instead of replacing this process.
58
+ *
59
+ * Used only by the picker bridge (`gmux pick --resume-in-window`), which runs
60
+ * inside a `display-popup`: exec'ing the harness there would trap it in the
61
+ * ephemeral popup, gone the moment it exits. A new window is a persistent pane.
62
+ */
63
+ export async function resumeInNewWindow(record) {
64
+ const adapter = adapterById(record.harness);
65
+ if (!adapter) {
66
+ throw new GmuxError(`No adapter is registered for harness "${record.harness}".`, {
67
+ fix: "Run `gmux index --rebuild`.",
68
+ });
69
+ }
70
+ const argv = newWindowArgv(adapter.resumeCommand(record));
71
+ await new Promise((resolve, reject) => {
72
+ execFile("tmux", argv, (error) => (error ? reject(error) : resolve()));
73
+ });
74
+ }
75
+ export function registerResume(program) {
76
+ program
77
+ .command("resume <id>")
78
+ .description("resume a session in its original harness and directory")
79
+ .option("--print", "print the command instead of running it")
80
+ .action(async (id, options) => {
81
+ // As with `show`: naming a session explicitly means you want it, even if
82
+ // `gmux ls` would hide it by default.
83
+ const records = await loadRecords({ includeSidechains: true, includeAutomated: true });
84
+ const record = resolveSession(records, id);
85
+ await resumeSession(record, options.print === true);
86
+ });
87
+ }
88
+ //# sourceMappingURL=resume.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resume.js","sourceRoot":"","sources":["../../../src/cli/commands/resume.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { Command } from "commander";
2
+ import type { HarnessAdapter } from "../../adapters/types.js";
3
+ import type { SessionRef } from "../../core/types.js";
4
+ /** Match `gmux run <arg>` to a harness by id or by a process-name alias. */
5
+ export declare function resolveHarnessArg(arg: string): HarnessAdapter | null;
6
+ /**
7
+ * The session the harness just started or touched: newest among those whose id
8
+ * is either new (a fresh session) or whose mtime advanced since `before` (a
9
+ * resumed one — `gmux run codex resume`, `gmux run claude --resume <id>` write to
10
+ * an EXISTING session file, so no new id ever appears for those).
11
+ */
12
+ export declare function pickChangedSession(before: readonly SessionRef[], after: readonly SessionRef[]): SessionRef | null;
13
+ export declare function registerRun(program: Command): void;
@@ -0,0 +1,78 @@
1
+ import { spawn } from "node:child_process";
2
+ import { adapterById, allAdapters } from "../../adapters/registry.js";
3
+ import { writePaneLink } from "../../services/pane-links.js";
4
+ import { dim } from "../format.js";
5
+ /** How long to watch for the harness's freshly-written session file. */
6
+ const DETECT_WINDOW_MS = 8000;
7
+ const DETECT_POLL_MS = 500;
8
+ /** Match `gmux run <arg>` to a harness by id or by a process-name alias. */
9
+ export function resolveHarnessArg(arg) {
10
+ const needle = arg.trim().toLowerCase();
11
+ return (adapterById(needle) ??
12
+ allAdapters().find((a) => a.processNames.some((n) => n.toLowerCase() === needle)) ??
13
+ null);
14
+ }
15
+ /**
16
+ * The session the harness just started or touched: newest among those whose id
17
+ * is either new (a fresh session) or whose mtime advanced since `before` (a
18
+ * resumed one — `gmux run codex resume`, `gmux run claude --resume <id>` write to
19
+ * an EXISTING session file, so no new id ever appears for those).
20
+ */
21
+ export function pickChangedSession(before, after) {
22
+ const beforeMtimes = new Map(before.map((r) => [r.sessionId, r.mtimeMs]));
23
+ const changed = after.filter((r) => {
24
+ const priorMtime = beforeMtimes.get(r.sessionId);
25
+ return priorMtime === undefined || r.mtimeMs > priorMtime;
26
+ });
27
+ return [...changed].sort((a, b) => b.mtimeMs - a.mtimeMs)[0] ?? null;
28
+ }
29
+ async function captureLink(adapter, paneId, before) {
30
+ const deadline = Date.now() + DETECT_WINDOW_MS;
31
+ while (Date.now() < deadline) {
32
+ await new Promise((r) => setTimeout(r, DETECT_POLL_MS));
33
+ try {
34
+ const after = await adapter.listSessions();
35
+ const picked = pickChangedSession(before, after);
36
+ if (picked) {
37
+ await writePaneLink({ paneId, harness: adapter.id, sessionId: picked.sessionId });
38
+ return;
39
+ }
40
+ }
41
+ catch {
42
+ // The harness may not have written its dir yet; keep watching.
43
+ }
44
+ }
45
+ process.stderr.write(`${dim("gmux: could not link this pane automatically (the overlay will fall back to the cwd heuristic)")}\n`);
46
+ }
47
+ export function registerRun(program) {
48
+ program
49
+ .command("run <harness> [args...]")
50
+ .description("launch an agent and record which pane it runs in, for exact overlay mapping")
51
+ .allowUnknownOption(true)
52
+ .action(async (harness, args = []) => {
53
+ const adapter = resolveHarnessArg(harness);
54
+ if (!adapter) {
55
+ process.stderr.write(`error unknown harness "${harness}". Known: ${allAdapters().map((a) => a.id).join(", ")}\n`);
56
+ process.exit(2);
57
+ }
58
+ const paneId = process.env.TMUX_PANE;
59
+ const before = paneId ? await adapter.listSessions().catch(() => []) : [];
60
+ // The wrapper lingers only to capture the session id; stdio is inherited,
61
+ // so the pane is the agent for all interactive purposes.
62
+ const child = spawn(adapter.launchCommand, args, { stdio: "inherit" });
63
+ if (paneId) {
64
+ process.stderr.write(`${dim(`gmux: linking pane ${paneId} to this ${adapter.displayName} session`)}\n`);
65
+ void captureLink(adapter, paneId, before);
66
+ }
67
+ child.on("error", (error) => {
68
+ if (error.code === "ENOENT") {
69
+ process.stderr.write(`error "${adapter.launchCommand}" is not on your PATH.\n`);
70
+ process.exit(6);
71
+ }
72
+ process.stderr.write(`error ${error.message}\n`);
73
+ process.exit(1);
74
+ });
75
+ child.on("close", (code) => process.exit(code ?? 0));
76
+ });
77
+ }
78
+ //# sourceMappingURL=run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../../../src/cli/commands/run.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * `gmux setup` — choose the harness gmux calls for summaries and `gmux ask`.
3
+ *
4
+ * The wizard is the only place gmux asks a question. Everything it writes
5
+ * is a choice a human made, which is why it goes to the config dir rather than
6
+ * the cache — see core/paths.ts.
7
+ */
8
+ import { type Interface } from "node:readline/promises";
9
+ import type { Command } from "commander";
10
+ import { type GmConfig, type ProviderChoice } from "../../core/types.js";
11
+ /** One selectable answer to "which provider?". */
12
+ interface Option {
13
+ label: string;
14
+ detail: string;
15
+ /** null = make no model calls. */
16
+ choose: (rl: Interface) => Promise<ProviderChoice | null>;
17
+ }
18
+ /**
19
+ * The menu.
20
+ *
21
+ * Every catalog provider is listed, installed or not, and an uninstalled one is
22
+ * still selectable — you might be about to install it, and a wizard that hides
23
+ * the option you came for is a wizard that sends you to the docs. The line says
24
+ * what's missing and how to get it.
25
+ */
26
+ export declare function buildOptions(): Option[];
27
+ /**
28
+ * The wizard itself. Returns the config it wrote.
29
+ *
30
+ * Takes its own readline interface so the first-run caller and `gmux setup` share
31
+ * one implementation and one teardown.
32
+ */
33
+ export declare function runSetupWizard(options?: {
34
+ firstRun?: boolean;
35
+ }): Promise<GmConfig>;
36
+ export declare function registerSetup(program: Command): void;
37
+ export {};