@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,242 @@
1
+ /**
2
+ * Rendering.
3
+ *
4
+ * Colour is applied only when stdout is a TTY and NO_COLOR is unset, so piping
5
+ * `gmux ls` into another program — or into an agent — yields clean text.
6
+ */
7
+ import { cell, relativeAge, truncate, wrapText } from "../core/text.js";
8
+ /** Colour is off unless the user leaves it on — a `NO_COLOR`/`dumb` opt-out we honour everywhere. */
9
+ const colorEnabled = () => !process.env.NO_COLOR && process.env.TERM !== "dumb";
10
+ const useColor = () => process.stdout.isTTY === true && colorEnabled();
11
+ const wrap = (code) => (text) => (useColor() ? `[${code}m${text}` : text);
12
+ export const dim = wrap("2");
13
+ export const bold = wrap("1");
14
+ export const cyan = wrap("36");
15
+ export const yellow = wrap("33");
16
+ export const red = wrap("31");
17
+ export const green = wrap("32");
18
+ /**
19
+ * Colour forced on for output we KNOW an ANSI renderer consumes, even off a TTY.
20
+ *
21
+ * The picker's preview command writes to a pipe, so `process.stdout.isTTY` is
22
+ * false and `useColor()` above is too — yet fzf renders that pipe with `--ansi`.
23
+ * These variants drop only the TTY test, so the pane can carry colour while
24
+ * `NO_COLOR` and `TERM=dumb` still turn it off. Used solely by `preview.ts`; the
25
+ * card and `gmux ls`/`gmux show` keep the gated `dim`/`cyan`/`bold` and stay clean
26
+ * when piped into another program.
27
+ */
28
+ const wrapForced = (code) => (text) => colorEnabled() ? `[${code}m${text}` : text;
29
+ export const paneCyan = wrapForced("36");
30
+ export const paneBold = wrapForced("1");
31
+ export const paneDim = wrapForced("2");
32
+ /** Marks a session that stopped mid-task — usually the one you want to resume. */
33
+ const MID_TASK = "⚠";
34
+ /**
35
+ * Marks a row whose summary has not been written yet.
36
+ *
37
+ * One column, so a row that gains a summary does not shift the layout. It used
38
+ * to be a dim `~`, which was invisible next to the yellow `⚠` — and now that
39
+ * these rows are actively being summarized in the background, "pending" is a
40
+ * state worth seeing.
41
+ */
42
+ const NO_SUMMARY = "○";
43
+ /** Marks a row whose summary is being written right now, by the background worker. */
44
+ const IN_PROGRESS = "◐";
45
+ const MARKERS = [
46
+ {
47
+ icon: MID_TASK,
48
+ color: yellow,
49
+ label: "ended mid-task",
50
+ matches: (view) => view.record.endedMidTask === true,
51
+ counted: false,
52
+ },
53
+ {
54
+ icon: IN_PROGRESS,
55
+ color: green,
56
+ label: "summarizing now",
57
+ matches: (view, inProgress) => !view.summary && inProgress.has(view.record.sessionId),
58
+ counted: true,
59
+ },
60
+ {
61
+ icon: NO_SUMMARY,
62
+ color: cyan,
63
+ label: "no summary yet",
64
+ matches: (view, inProgress) => !view.summary && !inProgress.has(view.record.sessionId),
65
+ counted: true,
66
+ },
67
+ ];
68
+ /** Wide enough to read as separate entries, narrow enough to hold one line. */
69
+ const KEY_GAP = " ";
70
+ const keyEntry = (marker, label) => `${marker.color(marker.icon)} ${dim(label)}`;
71
+ /** "repo/branch", or just "repo" when the branch adds nothing. */
72
+ export function sessionLabel(record) {
73
+ const project = record.project ?? "?";
74
+ return record.gitBranch ? `${project}/${record.gitBranch}` : project;
75
+ }
76
+ const WHERE_WIDTH = 28;
77
+ /** Never squeeze the description below this, however narrow the terminal. */
78
+ const MIN_TEXT_WIDTH = 24;
79
+ /** The description shown for a session: summary first, and never blank. */
80
+ function rowText(view) {
81
+ const { record, summary } = view;
82
+ return summary?.headline ?? record.title ?? record.lastUserPrompt ?? "(no content)";
83
+ }
84
+ const NONE = new Set();
85
+ /** The fixed-width columns before the description, coloured and plain. */
86
+ function rowPrefix(view, now, inProgress = NONE) {
87
+ const { record, summary } = view;
88
+ const id = record.sessionId.slice(0, 8);
89
+ const age = cell(relativeAge(record.updatedAt, now), 4);
90
+ const where = cell(sessionLabel(record), WHERE_WIDTH);
91
+ const flag = record.endedMidTask ? yellow(MID_TASK) : " ";
92
+ const mark = summary
93
+ ? " "
94
+ : inProgress.has(record.sessionId)
95
+ ? green(IN_PROGRESS)
96
+ : cyan(NO_SUMMARY);
97
+ return {
98
+ colored: `${dim(id)} ${dim(age)} ${flag}${mark} ${cyan(where)} `,
99
+ // Measured from the plain text: colour codes take no screen columns.
100
+ width: id.length + 1 + age.length + 1 + 2 + 1 + where.length + 1,
101
+ };
102
+ }
103
+ /**
104
+ * One row, on exactly one line.
105
+ *
106
+ * Used by the picker, where a session must occupy a single line — fzf maps lines
107
+ * back to session ids, so a wrapped row would break selection.
108
+ */
109
+ export function formatRow(view, now = new Date(), inProgress = NONE) {
110
+ return `${rowPrefix(view, now, inProgress).colored}${truncate(rowText(view), 72)}`;
111
+ }
112
+ /**
113
+ * One row of `gmux ls`, wrapped to the terminal so the whole description is
114
+ * readable rather than chopped off at the right edge. Continuation lines are
115
+ * indented to sit under the description column.
116
+ *
117
+ * Pass `width: Infinity` when the output is not a terminal: piped output should
118
+ * be one line per session, so `gmux ls | grep` behaves.
119
+ */
120
+ export function formatRowLines(view, now = new Date(), width = terminalWidth(), inProgress = NONE) {
121
+ const prefix = rowPrefix(view, now, inProgress);
122
+ const text = rowText(view);
123
+ if (!Number.isFinite(width)) {
124
+ return [`${prefix.colored}${text}`]; // Piped: one line, nothing lost.
125
+ }
126
+ const available = width - prefix.width;
127
+ // On a terminal too narrow to hold the columns AND a readable description,
128
+ // giving the description a sliver of a column would just overflow anyway.
129
+ // Drop it onto its own indented lines instead.
130
+ if (available < MIN_TEXT_WIDTH) {
131
+ const indent = " ";
132
+ return [
133
+ prefix.colored.trimEnd(),
134
+ ...wrapText(text, Math.max(MIN_TEXT_WIDTH, width - indent.length)).map((line) => `${indent}${line}`),
135
+ ];
136
+ }
137
+ const [first = "", ...rest] = wrapText(text, available);
138
+ const indent = " ".repeat(prefix.width);
139
+ return [`${prefix.colored}${first}`, ...rest.map((line) => `${indent}${dim(line)}`)];
140
+ }
141
+ /**
142
+ * The key under the list. Only mentions markers that actually appear, so a fully
143
+ * summarized list carries no footer at all.
144
+ */
145
+ export function formatLegend(views, inProgress = NONE) {
146
+ return MARKERS.flatMap((marker) => {
147
+ const on = views.filter((view) => marker.matches(view, inProgress)).length;
148
+ if (on === 0)
149
+ return [];
150
+ return [keyEntry(marker, marker.counted ? `${marker.label} (${on})` : marker.label)];
151
+ }).join(KEY_GAP);
152
+ }
153
+ /**
154
+ * The key for a LIVE list: every marker, always, and never a count.
155
+ *
156
+ * The picker renders the same markers `gmux ls` does, so it needs the same
157
+ * explanation — but not `formatLegend`. fzf sets `--header` once, at spawn:
158
+ * `ctrl-r` reloads the item list and leaves the header untouched. Counts baked
159
+ * in there freeze at open and are wrong after the first refresh, and a key
160
+ * listing "only the markers present" goes stale the moment a refresh brings in
161
+ * one that wasn't. ctrl-r is precisely when both change.
162
+ *
163
+ * So: nothing here depends on the list. A stale key is worse than a fixed one —
164
+ * absent an explanation you go looking, given a wrong one you don't. The cost is
165
+ * one line naming `○` on a list that has none.
166
+ */
167
+ export function formatMarkerKey() {
168
+ return MARKERS.map((marker) => keyEntry(marker, marker.label)).join(KEY_GAP);
169
+ }
170
+ /** Terminal width, or a sane default when we cannot tell. */
171
+ export function terminalWidth() {
172
+ return process.stdout.columns && process.stdout.columns > 0 ? process.stdout.columns : 100;
173
+ }
174
+ /** The detail card shown by `gmux show` and in the picker's preview pane. */
175
+ export function formatCard(view, now = new Date()) {
176
+ const { record, summary } = view;
177
+ const lines = [];
178
+ lines.push(bold(sessionLabel(record)), dim(`${record.harness} · ${record.sessionId} · ${relativeAge(record.updatedAt, now)} ago`));
179
+ lines.push("");
180
+ if (summary) {
181
+ // Widening zoom: the headline names the work, the overview frames it, the
182
+ // summary reorients you. `headline` is the one field parsing guarantees, so
183
+ // it stands in for the overview when that is empty.
184
+ lines.push(bold("HEADLINE"), indent(summary.headline), "");
185
+ if (summary.overview)
186
+ lines.push(bold("OVERVIEW"), indent(summary.overview), "");
187
+ if (summary.summary)
188
+ lines.push(bold("SUMMARY"), indent(summary.summary), "");
189
+ if (summary.landed)
190
+ lines.push(bold("RECENT WORK"), indent(summary.landed), "");
191
+ if (summary.open)
192
+ lines.push(bold("STILL OPEN"), indent(summary.open), "");
193
+ if (summary.nextStep)
194
+ lines.push(bold("NEXT STEP"), indent(green(summary.nextStep)), "");
195
+ }
196
+ else {
197
+ lines.push(dim("No summary yet."), dim(`Run: gmux summarize ${record.sessionId.slice(0, 8)}`), "");
198
+ if (record.title)
199
+ lines.push(bold("TITLE (recorded at session start)"), indent(record.title), "");
200
+ }
201
+ if (record.lastUserPrompt) {
202
+ lines.push(bold("LAST THING YOU SAID"), indent(`"${truncate(record.lastUserPrompt, 240)}"`), "");
203
+ }
204
+ if (record.filesTouched.length > 0) {
205
+ const shown = record.filesTouched.slice(0, 6);
206
+ const extra = record.filesTouched.length - shown.length;
207
+ lines.push(bold("FILES TOUCHED"), ...shown.map((f) => ` ${f}`), ...(extra > 0 ? [dim(` … and ${extra} more`)] : []), "");
208
+ }
209
+ if (record.prLinks.length > 0) {
210
+ const shown = record.prLinks.slice(0, 8);
211
+ const extra = record.prLinks.length - shown.length;
212
+ lines.push(bold("PULL REQUESTS"), ...shown.map((pr) => ` #${pr.number} ${pr.url}`), ...(extra > 0 ? [dim(` … and ${extra} more`)] : []), "");
213
+ }
214
+ const facts = [`${record.messageCount} messages`, `${record.userPromptCount} prompts`];
215
+ if (record.endedMidTask)
216
+ facts.push(yellow("ended mid-task"));
217
+ if (record.lastToolFailure)
218
+ facts.push(red("last command failed"));
219
+ lines.push(dim(facts.join(" · ")));
220
+ if (record.cwd)
221
+ lines.push(dim(record.cwd));
222
+ return lines.join("\n");
223
+ }
224
+ /**
225
+ * Two spaces under a heading — the card's only body indent.
226
+ *
227
+ * Exported for the preview's chat half, whose speaker bodies sit under `you` and
228
+ * `gmux` exactly as the card's text sits under `WHERE IT LANDED`. Both halves share
229
+ * one pane, so a second indent idiom would show up as two columns that almost
230
+ * line up.
231
+ */
232
+ export function indent(text) {
233
+ return text
234
+ .split("\n")
235
+ .map((line) => ` ${line}`)
236
+ .join("\n");
237
+ }
238
+ /** Stable JSON envelope. Everything machine-readable goes through here. */
239
+ export function jsonEnvelope(schemaVersion, data) {
240
+ return JSON.stringify({ schemaVersion, data }, null, 2);
241
+ }
242
+ //# sourceMappingURL=format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/cli/format.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { HostPressure, WorkspaceSnapshot } from "../core/gmux-types.js";
2
+ export declare function formatBytes(n: number): string;
3
+ export declare function relativeTime(ts: number, now: number): string;
4
+ export declare function unattributedLine(host: HostPressure | null): string | null;
5
+ export interface RenderCockpitOptions {
6
+ width?: number;
7
+ stale?: {
8
+ ageMs: number;
9
+ } | null;
10
+ }
11
+ export declare function renderCockpit(snapshot: WorkspaceSnapshot, now: number, widthOrOpts?: number | RenderCockpitOptions): string[];
@@ -0,0 +1,60 @@
1
+ import { basename } from "node:path";
2
+ import { stateGlyph } from "./tmux-label.js";
3
+ export function formatBytes(n) {
4
+ const gb = n / (1024 ** 3);
5
+ if (gb >= 1)
6
+ return `${gb.toFixed(1)} GB`;
7
+ const mb = n / (1024 ** 2);
8
+ return `${mb.toFixed(0)} MB`;
9
+ }
10
+ export function relativeTime(ts, now) {
11
+ const s = Math.max(0, Math.round((now - ts) / 1000));
12
+ if (s < 60)
13
+ return `${s}s ago`;
14
+ const m = Math.round(s / 60);
15
+ if (m < 60)
16
+ return `${m}m ago`;
17
+ return `${Math.round(m / 60)}h ago`;
18
+ }
19
+ function paneRow(e, now) {
20
+ const name = e.identity.cwd ? basename(e.identity.cwd) : e.identity.command;
21
+ const label = e.semantics?.label ?? e.state;
22
+ const mem = e.resources ? formatBytes(e.resources.perPaneRss) : "—";
23
+ const activity = e.lastActivityTs ? relativeTime(e.lastActivityTs, now) : "—";
24
+ return `${stateGlyph(e.state)} ${name} ${label} [${mem}] ${activity}`;
25
+ }
26
+ export function unattributedLine(host) {
27
+ if (!host || host.unattributed <= 0)
28
+ return null;
29
+ return ` unattributed: ${formatBytes(host.unattributed)} (source outside tracked panes)`;
30
+ }
31
+ /** Normalizes the legacy positional `width` arg and the newer options object into one shape. */
32
+ function normalizeCockpitOptions(widthOrOpts) {
33
+ if (typeof widthOrOpts === "number")
34
+ return { width: widthOrOpts, stale: null };
35
+ return { width: widthOrOpts?.width ?? 120, stale: widthOrOpts?.stale ?? null };
36
+ }
37
+ export function renderCockpit(snapshot, now, widthOrOpts) {
38
+ const { stale } = normalizeCockpitOptions(widthOrOpts);
39
+ const lines = [];
40
+ if (stale)
41
+ lines.push(`⚠ daemon not connected — snapshot ${relativeTime(now - stale.ageMs, now)}`);
42
+ for (const g of snapshot.guardianLog.slice(-3))
43
+ lines.push(`⚠ ${g.message}`);
44
+ if (snapshot.guardianLog.length > 0)
45
+ lines.push("");
46
+ lines.push(`gmux — ${snapshot.panes.length} panes`);
47
+ // Sort panes by memory descending if any have resources
48
+ const hasResources = snapshot.panes.some((p) => p.resources);
49
+ const sortedPanes = hasResources
50
+ ? [...snapshot.panes].sort((a, b) => (b.resources?.perPaneRss ?? 0) - (a.resources?.perPaneRss ?? 0))
51
+ : snapshot.panes;
52
+ for (const e of sortedPanes)
53
+ lines.push(paneRow(e, now));
54
+ // Add unattributed line if present
55
+ const unattr = unattributedLine(snapshot.hostPressure);
56
+ if (unattr)
57
+ lines.push(unattr);
58
+ return lines;
59
+ }
60
+ //# sourceMappingURL=gmux-render.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gmux-render.js","sourceRoot":"","sources":["../../src/cli/gmux-render.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * gmux — browse, search and resume agent coding sessions.
4
+ *
5
+ * Every read command supports `--json`. That is deliberate: gmux is a tool
6
+ * for agents as much as for people, and an agent can only use what it can parse.
7
+ */
8
+ export {};
@@ -0,0 +1,145 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * gmux — browse, search and resume agent coding sessions.
4
+ *
5
+ * Every read command supports `--json`. That is deliberate: gmux is a tool
6
+ * for agents as much as for people, and an agent can only use what it can parse.
7
+ */
8
+ import { createRequire } from "node:module";
9
+ import { Command } from "commander";
10
+ import { GmuxError } from "../core/errors.js";
11
+ import { maybeAutoSummarize } from "../services/auto-summarize.js";
12
+ import { configExists, shouldRunSetupWizard } from "../services/config.js";
13
+ import { registerAsk } from "./commands/ask.js";
14
+ import { registerAskCancel } from "./commands/__ask-cancel.js";
15
+ import { registerAskRun } from "./commands/__ask-run.js";
16
+ import { registerAskSend } from "./commands/__ask-send.js";
17
+ import { registerAutoSummarizeWorker } from "./commands/auto.js";
18
+ import { registerCockpit } from "./commands/cockpit.js";
19
+ import { registerDaemon } from "./commands/daemon.js";
20
+ import { registerDoctor } from "./commands/doctor.js";
21
+ import { registerSetup, runSetupWizard } from "./commands/setup.js";
22
+ import { registerGrep } from "./commands/grep.js";
23
+ import { registerIndex } from "./commands/index-cmd.js";
24
+ import { registerLs } from "./commands/ls.js";
25
+ import { registerOverlay } from "./commands/overlay.js";
26
+ import { registerWatch } from "./commands/watch.js";
27
+ import { registerPick } from "./commands/pick.js";
28
+ import { registerPickerRows } from "./commands/picker-rows.js";
29
+ import { registerPreviewCard } from "./commands/__preview-card.js";
30
+ import { registerResume } from "./commands/resume.js";
31
+ import { registerRun } from "./commands/run.js";
32
+ import { registerShow } from "./commands/show.js";
33
+ import { registerSummarize } from "./commands/summarize.js";
34
+ import { registerTmux } from "./commands/tmux.js";
35
+ import { red, dim } from "./format.js";
36
+ /**
37
+ * Read the version from package.json rather than hardcoding it.
38
+ *
39
+ * A hardcoded string silently drifts on every release — v0.1.1 shipped
40
+ * reporting `0.1.0`. Resolves to the package root from both `dist/cli/` (built)
41
+ * and `src/cli/` (via tsx).
42
+ */
43
+ const { version } = createRequire(import.meta.url)("../../package.json");
44
+ const program = new Command();
45
+ program
46
+ .name("gmux")
47
+ .description("Browse, search and resume your AI coding agent sessions.")
48
+ .version(version)
49
+ .option("--no-color", "disable coloured output")
50
+ .option("--no-auto-summarize", "do not summarize recent sessions in the background")
51
+ .hook("preAction", async (thisCommand, actionCommand) => {
52
+ if (thisCommand.opts()["color"] === false)
53
+ process.env.NO_COLOR = "1";
54
+ /**
55
+ * First run: ask who to call, before spending anything on calling them.
56
+ *
57
+ * Every gate here is load-bearing. `gmux ls --json` is an interface agents
58
+ * call, and a version of it that can block on a human prompt is a broken
59
+ * interface whatever it prints — so no TTY, or `--json`, or a `__`-prefixed
60
+ * internal command means we say nothing and behave exactly as gmux did before
61
+ * config existed: autodetect and carry on.
62
+ */
63
+ const gate = {
64
+ hasConfig: await configExists(),
65
+ isTty: process.stdin.isTTY === true && process.stdout.isTTY === true,
66
+ isJson: actionCommand.opts()["json"] === true,
67
+ commandName: actionCommand.name(),
68
+ };
69
+ if (shouldRunSetupWizard(gate))
70
+ await runSetupWizard({ firstRun: true });
71
+ })
72
+ /**
73
+ * Keep the ten most recent sessions summarized — in the background, always.
74
+ *
75
+ * This runs in `postAction`, after the command has already written its output,
76
+ * so `gmux ls` still returns in ~60ms. The work itself is handed to a detached
77
+ * child that outlives us (see services/auto-summarize.ts); we only decide, and
78
+ * we tell the user on STDERR so `gmux ls --json` stays machine-readable.
79
+ *
80
+ * The worker command is exempt, or it would spawn a copy of itself forever.
81
+ */
82
+ .hook("postAction", async (thisCommand, actionCommand) => {
83
+ /**
84
+ * `__`-prefixed commands are the internals gmux spawns at itself, and none of
85
+ * them may decide anything here — by prefix, not by a list that the next
86
+ * hidden command has to remember to join. `__auto-summarize` would fork a
87
+ * copy of itself; `__picker-rows` runs its own pass first; `__ask-send`
88
+ * inherits fzf's env, so GMUX_CHILD is unset and every question typed
89
+ * into the chat pane would fork a summarize decision from inside fzf —
90
+ * whose `notify` writes to the stderr fzf is painting. Same convention
91
+ * `shouldRunSetupWizard` already uses.
92
+ */
93
+ if (actionCommand.name().startsWith("__"))
94
+ return;
95
+ // `ls` and `pick` run the pass themselves, BEFORE rendering, so they can
96
+ // mark the rows they just kicked off with ◐. Running it again here would be
97
+ // a wasted decision — and for `pick` a badly timed one: its action ends in
98
+ // `resumeSession`, which waits on your harness, so this hook would not fire
99
+ // until you quit Claude Code.
100
+ if (actionCommand.name() === "ls" || actionCommand.name() === "pick")
101
+ return;
102
+ await maybeAutoSummarize({
103
+ enabled: thisCommand.opts()["autoSummarize"] !== false,
104
+ notify: (message) => process.stderr.write(`${dim(message)}\n`),
105
+ });
106
+ });
107
+ registerLs(program);
108
+ registerShow(program);
109
+ registerGrep(program);
110
+ registerAsk(program);
111
+ registerResume(program);
112
+ registerSummarize(program);
113
+ registerSetup(program);
114
+ registerIndex(program);
115
+ registerDoctor(program);
116
+ registerAutoSummarizeWorker(program);
117
+ registerPickerRows(program);
118
+ registerPreviewCard(program);
119
+ registerAskSend(program);
120
+ registerAskRun(program);
121
+ registerAskCancel(program);
122
+ registerPick(program); // Also the default action when `gmux` is run bare.
123
+ registerOverlay(program);
124
+ registerCockpit(program);
125
+ registerTmux(program);
126
+ registerRun(program);
127
+ registerWatch(program);
128
+ registerDaemon(program);
129
+ async function main() {
130
+ try {
131
+ await program.parseAsync(process.argv);
132
+ }
133
+ catch (error) {
134
+ if (error instanceof GmuxError) {
135
+ process.stderr.write(`${red("error")} ${error.message}\n`);
136
+ if (error.fix)
137
+ process.stderr.write(`${dim("fix")} ${error.fix}\n`);
138
+ process.exit(error.exitCode);
139
+ }
140
+ process.stderr.write(`${red("error")} ${error.message}\n`);
141
+ process.exit(1);
142
+ }
143
+ }
144
+ void main();
145
+ //# sourceMappingURL=main.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * The ask box that sits at the bottom of the ctrl-g overlay. Pure string
3
+ * layout — the command positions it on the popup and drives the keystrokes.
4
+ */
5
+ /** Rows the ask box occupies at the bottom of the overlay. */
6
+ export declare const ASK_BOX_HEIGHT = 3;
7
+ /**
8
+ * The three lines of the ask box (top border, the input line, bottom border),
9
+ * each clipped to `width`. A long input scrolls so its tail stays visible.
10
+ */
11
+ export declare function askBoxLines(input: string, width: number): string[];
12
+ /** The cursor's column (1-based) inside the input line, clamped to the field. */
13
+ export declare function askCursorColumn(input: string, width: number): number;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * The ask box that sits at the bottom of the ctrl-g overlay. Pure string
3
+ * layout — the command positions it on the popup and drives the keystrokes.
4
+ */
5
+ /** Rows the ask box occupies at the bottom of the overlay. */
6
+ export const ASK_BOX_HEIGHT = 3;
7
+ const LABEL = "ask · Enter send · ^R refresh · ^G/Esc close";
8
+ /**
9
+ * The three lines of the ask box (top border, the input line, bottom border),
10
+ * each clipped to `width`. A long input scrolls so its tail stays visible.
11
+ */
12
+ export function askBoxLines(input, width) {
13
+ const w = Math.max(12, Math.floor(width));
14
+ const inner = w - 2; // between the │ │ borders
15
+ const dashes = Math.max(0, inner - LABEL.length - 3);
16
+ const top = `╭─ ${LABEL} ${"─".repeat(dashes)}╮`.slice(0, w);
17
+ const field = inner - 2; // inside "│ … │"
18
+ const prompt = `> ${input}`;
19
+ const shown = prompt.length > field ? prompt.slice(prompt.length - field) : prompt;
20
+ const mid = `│ ${shown.padEnd(field, " ")} │`.slice(0, w);
21
+ const bottom = `╰${"─".repeat(inner)}╯`.slice(0, w);
22
+ return [top, mid, bottom];
23
+ }
24
+ /** The cursor's column (1-based) inside the input line, clamped to the field. */
25
+ export function askCursorColumn(input, width) {
26
+ const inner = Math.max(12, Math.floor(width)) - 2;
27
+ const field = inner - 2;
28
+ const prompt = `> ${input}`;
29
+ const offset = Math.min(prompt.length, field);
30
+ return 3 + offset; // "│ " is 2 cols, field starts at col 3
31
+ }
32
+ //# sourceMappingURL=overlay-ask.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overlay-ask.js","sourceRoot":"","sources":["../../src/cli/overlay-ask.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,8DAA8D;AAC9D,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC;AAEhC,MAAM,KAAK,GAAG,8CAA8C,CAAC;AAE7D;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,KAAa,EAAE,KAAa;IACtD,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;IAC1C,MAAM,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,0BAA0B;IAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACrD,MAAM,GAAG,GAAG,MAAM,KAAK,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAE7D,MAAM,KAAK,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,iBAAiB;IAC1C,MAAM,MAAM,GAAG,KAAK,KAAK,EAAE,CAAC;IAC5B,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IACnF,MAAM,GAAG,GAAG,KAAK,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAE1D,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACpD,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;AAC5B,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,eAAe,CAAC,KAAa,EAAE,KAAa;IAC1D,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC;IAClD,MAAM,KAAK,GAAG,KAAK,GAAG,CAAC,CAAC;IACxB,MAAM,MAAM,GAAG,KAAK,KAAK,EAAE,CAAC;IAC5B,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAC9C,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC,wCAAwC;AAC7D,CAAC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Draw every pane's summary card in place. Pure: given resolved cells and the
3
+ * clock, produce one string of ANSI cursor moves that paints a full-screen
4
+ * overlay. The command layer supplies the cells and the terminal; nothing here
5
+ * reads tmux, stdin, or the clock on its own.
6
+ *
7
+ * A compact sibling of `formatCard`: same summary fields and section names,
8
+ * sized to a rectangle with a degradation ladder — full card, then title +
9
+ * what-landed, then just the title, then a muted placeholder for a pane with no
10
+ * agent. Monochrome: the structure is carried by layout, so it survives a pane
11
+ * that cannot render colour.
12
+ */
13
+ import type { SessionView, TmuxPane } from "../core/types.js";
14
+ export interface OverlayCell {
15
+ pane: TmuxPane;
16
+ /** null when the pane runs no resolvable agent. */
17
+ view: SessionView | null;
18
+ /** True while a background refresh for this session is in flight. */
19
+ refreshing: boolean;
20
+ /** A broadcast question is being answered for this pane's session right now. */
21
+ asking?: boolean;
22
+ /** This pane's own answer to the current broadcast question, if it has landed. */
23
+ answer?: string | null;
24
+ }
25
+ export declare function cellLines(cell: OverlayCell, width: number, height: number, now: Date): string[];
26
+ export declare function renderOverlay(cells: readonly OverlayCell[], now?: Date): string;