@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.
- package/CHANGELOG.md +654 -0
- package/LICENSE +21 -0
- package/README.md +351 -0
- package/dist/adapters/claude-code.d.ts +52 -0
- package/dist/adapters/claude-code.js +315 -0
- package/dist/adapters/claude-code.js.map +1 -0
- package/dist/adapters/codex.d.ts +39 -0
- package/dist/adapters/codex.js +233 -0
- package/dist/adapters/codex.js.map +1 -0
- package/dist/adapters/jsonl.d.ts +40 -0
- package/dist/adapters/jsonl.js +92 -0
- package/dist/adapters/jsonl.js.map +1 -0
- package/dist/adapters/registry.d.ts +11 -0
- package/dist/adapters/registry.js +21 -0
- package/dist/adapters/registry.js.map +1 -0
- package/dist/adapters/types.d.ts +43 -0
- package/dist/adapters/types.js +2 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/cli/border-client.d.ts +8 -0
- package/dist/cli/border-client.js +11 -0
- package/dist/cli/border-client.js.map +1 -0
- package/dist/cli/commands/__ask-cancel.d.ts +35 -0
- package/dist/cli/commands/__ask-cancel.js +91 -0
- package/dist/cli/commands/__ask-cancel.js.map +1 -0
- package/dist/cli/commands/__ask-refresh.d.ts +40 -0
- package/dist/cli/commands/__ask-refresh.js +54 -0
- package/dist/cli/commands/__ask-refresh.js.map +1 -0
- package/dist/cli/commands/__ask-run.d.ts +43 -0
- package/dist/cli/commands/__ask-run.js +126 -0
- package/dist/cli/commands/__ask-run.js.map +1 -0
- package/dist/cli/commands/__ask-send.d.ts +50 -0
- package/dist/cli/commands/__ask-send.js +138 -0
- package/dist/cli/commands/__ask-send.js.map +1 -0
- package/dist/cli/commands/__preview-card.d.ts +31 -0
- package/dist/cli/commands/__preview-card.js +72 -0
- package/dist/cli/commands/__preview-card.js.map +1 -0
- package/dist/cli/commands/ask.d.ts +50 -0
- package/dist/cli/commands/ask.js +240 -0
- package/dist/cli/commands/ask.js.map +1 -0
- package/dist/cli/commands/auto.d.ts +12 -0
- package/dist/cli/commands/auto.js +28 -0
- package/dist/cli/commands/auto.js.map +1 -0
- package/dist/cli/commands/cockpit.d.ts +14 -0
- package/dist/cli/commands/cockpit.js +52 -0
- package/dist/cli/commands/cockpit.js.map +1 -0
- package/dist/cli/commands/daemon.d.ts +75 -0
- package/dist/cli/commands/daemon.js +258 -0
- package/dist/cli/commands/daemon.js.map +1 -0
- package/dist/cli/commands/doctor.d.ts +6 -0
- package/dist/cli/commands/doctor.js +159 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/grep.d.ts +2 -0
- package/dist/cli/commands/grep.js +52 -0
- package/dist/cli/commands/grep.js.map +1 -0
- package/dist/cli/commands/index-cmd.d.ts +2 -0
- package/dist/cli/commands/index-cmd.js +29 -0
- package/dist/cli/commands/index-cmd.js.map +1 -0
- package/dist/cli/commands/ls.d.ts +30 -0
- package/dist/cli/commands/ls.js +95 -0
- package/dist/cli/commands/ls.js.map +1 -0
- package/dist/cli/commands/overlay.d.ts +26 -0
- package/dist/cli/commands/overlay.js +216 -0
- package/dist/cli/commands/overlay.js.map +1 -0
- package/dist/cli/commands/pick.d.ts +59 -0
- package/dist/cli/commands/pick.js +254 -0
- package/dist/cli/commands/pick.js.map +1 -0
- package/dist/cli/commands/picker-rows.d.ts +17 -0
- package/dist/cli/commands/picker-rows.js +47 -0
- package/dist/cli/commands/picker-rows.js.map +1 -0
- package/dist/cli/commands/resume.d.ts +25 -0
- package/dist/cli/commands/resume.js +88 -0
- package/dist/cli/commands/resume.js.map +1 -0
- package/dist/cli/commands/run.d.ts +13 -0
- package/dist/cli/commands/run.js +78 -0
- package/dist/cli/commands/run.js.map +1 -0
- package/dist/cli/commands/setup.d.ts +37 -0
- package/dist/cli/commands/setup.js +200 -0
- package/dist/cli/commands/setup.js.map +1 -0
- package/dist/cli/commands/show.d.ts +2 -0
- package/dist/cli/commands/show.js +24 -0
- package/dist/cli/commands/show.js.map +1 -0
- package/dist/cli/commands/summarize.d.ts +2 -0
- package/dist/cli/commands/summarize.js +59 -0
- package/dist/cli/commands/summarize.js.map +1 -0
- package/dist/cli/commands/tmux.d.ts +11 -0
- package/dist/cli/commands/tmux.js +90 -0
- package/dist/cli/commands/tmux.js.map +1 -0
- package/dist/cli/commands/watch.d.ts +2 -0
- package/dist/cli/commands/watch.js +76 -0
- package/dist/cli/commands/watch.js.map +1 -0
- package/dist/cli/format.d.ts +74 -0
- package/dist/cli/format.js +242 -0
- package/dist/cli/format.js.map +1 -0
- package/dist/cli/gmux-render.d.ts +11 -0
- package/dist/cli/gmux-render.js +60 -0
- package/dist/cli/gmux-render.js.map +1 -0
- package/dist/cli/main.d.ts +8 -0
- package/dist/cli/main.js +145 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/overlay-ask.d.ts +13 -0
- package/dist/cli/overlay-ask.js +32 -0
- package/dist/cli/overlay-ask.js.map +1 -0
- package/dist/cli/overlay.d.ts +26 -0
- package/dist/cli/overlay.js +149 -0
- package/dist/cli/overlay.js.map +1 -0
- package/dist/cli/picker.d.ts +308 -0
- package/dist/cli/picker.js +642 -0
- package/dist/cli/picker.js.map +1 -0
- package/dist/cli/preview.d.ts +87 -0
- package/dist/cli/preview.js +292 -0
- package/dist/cli/preview.js.map +1 -0
- package/dist/cli/tmux-label.d.ts +50 -0
- package/dist/cli/tmux-label.js +146 -0
- package/dist/cli/tmux-label.js.map +1 -0
- package/dist/core/errors.d.ts +54 -0
- package/dist/core/errors.js +91 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/fingerprint.d.ts +21 -0
- package/dist/core/fingerprint.js +59 -0
- package/dist/core/fingerprint.js.map +1 -0
- package/dist/core/gmux-types.d.ts +102 -0
- package/dist/core/gmux-types.js +13 -0
- package/dist/core/gmux-types.js.map +1 -0
- package/dist/core/pane-state.d.ts +5 -0
- package/dist/core/pane-state.js +15 -0
- package/dist/core/pane-state.js.map +1 -0
- package/dist/core/paths.d.ts +68 -0
- package/dist/core/paths.js +106 -0
- package/dist/core/paths.js.map +1 -0
- package/dist/core/proc-tree.d.ts +9 -0
- package/dist/core/proc-tree.js +33 -0
- package/dist/core/proc-tree.js.map +1 -0
- package/dist/core/text.d.ts +34 -0
- package/dist/core/text.js +126 -0
- package/dist/core/text.js.map +1 -0
- package/dist/core/types.d.ts +322 -0
- package/dist/core/types.js +10 -0
- package/dist/core/types.js.map +1 -0
- package/dist/services/ask-transcript.d.ts +256 -0
- package/dist/services/ask-transcript.js +544 -0
- package/dist/services/ask-transcript.js.map +1 -0
- package/dist/services/ask.d.ts +54 -0
- package/dist/services/ask.js +161 -0
- package/dist/services/ask.js.map +1 -0
- package/dist/services/auto-summarize.d.ts +188 -0
- package/dist/services/auto-summarize.js +415 -0
- package/dist/services/auto-summarize.js.map +1 -0
- package/dist/services/concurrency.d.ts +2 -0
- package/dist/services/concurrency.js +16 -0
- package/dist/services/concurrency.js.map +1 -0
- package/dist/services/config.d.ts +131 -0
- package/dist/services/config.js +325 -0
- package/dist/services/config.js.map +1 -0
- package/dist/services/daemon-client.d.ts +9 -0
- package/dist/services/daemon-client.js +34 -0
- package/dist/services/daemon-client.js.map +1 -0
- package/dist/services/daemon-socket.d.ts +30 -0
- package/dist/services/daemon-socket.js +76 -0
- package/dist/services/daemon-socket.js.map +1 -0
- package/dist/services/daemon.d.ts +43 -0
- package/dist/services/daemon.js +106 -0
- package/dist/services/daemon.js.map +1 -0
- package/dist/services/distill.d.ts +39 -0
- package/dist/services/distill.js +93 -0
- package/dist/services/distill.js.map +1 -0
- package/dist/services/guardian.d.ts +26 -0
- package/dist/services/guardian.js +71 -0
- package/dist/services/guardian.js.map +1 -0
- package/dist/services/index-store.d.ts +36 -0
- package/dist/services/index-store.js +125 -0
- package/dist/services/index-store.js.map +1 -0
- package/dist/services/log-rotation.d.ts +3 -0
- package/dist/services/log-rotation.js +28 -0
- package/dist/services/log-rotation.js.map +1 -0
- package/dist/services/pane-links.d.ts +10 -0
- package/dist/services/pane-links.js +47 -0
- package/dist/services/pane-links.js.map +1 -0
- package/dist/services/pane-process.d.ts +95 -0
- package/dist/services/pane-process.js +183 -0
- package/dist/services/pane-process.js.map +1 -0
- package/dist/services/pane-registry.d.ts +24 -0
- package/dist/services/pane-registry.js +40 -0
- package/dist/services/pane-registry.js.map +1 -0
- package/dist/services/provider-process.d.ts +37 -0
- package/dist/services/provider-process.js +105 -0
- package/dist/services/provider-process.js.map +1 -0
- package/dist/services/providers.d.ts +76 -0
- package/dist/services/providers.js +104 -0
- package/dist/services/providers.js.map +1 -0
- package/dist/services/resolve.d.ts +3 -0
- package/dist/services/resolve.js +18 -0
- package/dist/services/resolve.js.map +1 -0
- package/dist/services/resources.d.ts +17 -0
- package/dist/services/resources.js +113 -0
- package/dist/services/resources.js.map +1 -0
- package/dist/services/search.d.ts +29 -0
- package/dist/services/search.js +135 -0
- package/dist/services/search.js.map +1 -0
- package/dist/services/semantic-gate.d.ts +13 -0
- package/dist/services/semantic-gate.js +23 -0
- package/dist/services/semantic-gate.js.map +1 -0
- package/dist/services/semantic.d.ts +113 -0
- package/dist/services/semantic.js +216 -0
- package/dist/services/semantic.js.map +1 -0
- package/dist/services/sensors.d.ts +92 -0
- package/dist/services/sensors.js +246 -0
- package/dist/services/sensors.js.map +1 -0
- package/dist/services/summarize.d.ts +84 -0
- package/dist/services/summarize.js +230 -0
- package/dist/services/summarize.js.map +1 -0
- package/dist/services/tmux-gateway.d.ts +17 -0
- package/dist/services/tmux-gateway.js +10 -0
- package/dist/services/tmux-gateway.js.map +1 -0
- package/dist/services/tmux-resolve.d.ts +54 -0
- package/dist/services/tmux-resolve.js +0 -0
- package/dist/services/tmux-resolve.js.map +1 -0
- package/dist/services/tmux.d.ts +32 -0
- package/dist/services/tmux.js +107 -0
- package/dist/services/tmux.js.map +1 -0
- package/dist/services/views.d.ts +7 -0
- package/dist/services/views.js +18 -0
- package/dist/services/views.js.map +1 -0
- package/dist/services/watch.d.ts +36 -0
- package/dist/services/watch.js +98 -0
- package/dist/services/watch.js.map +1 -0
- package/dist/services/workspace.d.ts +19 -0
- package/dist/services/workspace.js +88 -0
- package/dist/services/workspace.js.map +1 -0
- package/package.json +64 -0
|
@@ -0,0 +1,200 @@
|
|
|
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 { createInterface } from "node:readline/promises";
|
|
9
|
+
import { GmuxError } from "../../core/errors.js";
|
|
10
|
+
import { DEFAULT_GMUX_CONFIG } from "../../core/gmux-types.js";
|
|
11
|
+
import { configPath } from "../../core/paths.js";
|
|
12
|
+
import { CONFIG_VERSION } from "../../core/types.js";
|
|
13
|
+
import { CUSTOM_PROVIDER_ID, PROVIDERS, onPath, toChoice, } from "../../services/providers.js";
|
|
14
|
+
import { parseCommand, readConfig, writeConfig } from "../../services/config.js";
|
|
15
|
+
import { bold, cyan, dim, green, yellow } from "../format.js";
|
|
16
|
+
function providerOption(spec) {
|
|
17
|
+
const installed = onPath(spec.binary);
|
|
18
|
+
return {
|
|
19
|
+
label: spec.displayName,
|
|
20
|
+
detail: installed ? `${spec.summaryArgv.join(" ")}` : `not installed — ${spec.install}`,
|
|
21
|
+
choose: async () => toChoice(spec),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The menu.
|
|
26
|
+
*
|
|
27
|
+
* Every catalog provider is listed, installed or not, and an uninstalled one is
|
|
28
|
+
* still selectable — you might be about to install it, and a wizard that hides
|
|
29
|
+
* the option you came for is a wizard that sends you to the docs. The line says
|
|
30
|
+
* what's missing and how to get it.
|
|
31
|
+
*/
|
|
32
|
+
export function buildOptions() {
|
|
33
|
+
const options = PROVIDERS.map(providerOption);
|
|
34
|
+
options.push({
|
|
35
|
+
label: "Something else",
|
|
36
|
+
detail: "any command that reads a prompt on stdin and writes text",
|
|
37
|
+
choose: async (rl) => {
|
|
38
|
+
for (;;) {
|
|
39
|
+
const raw = (await rl.question(`\n command (e.g. ${dim("gemini -p")}): `)).trim();
|
|
40
|
+
const command = parseCommand(raw);
|
|
41
|
+
if (command.length > 0)
|
|
42
|
+
return { id: CUSTOM_PROVIDER_ID, command };
|
|
43
|
+
process.stdout.write(` ${yellow("A command is required.")}\n`);
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
options.push({
|
|
48
|
+
label: "Nothing — make no model calls",
|
|
49
|
+
detail: "no summaries, no `gmux ask`. `gmux ls` still works on hard facts alone",
|
|
50
|
+
choose: async () => null,
|
|
51
|
+
});
|
|
52
|
+
return options;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* The wizard is a conversation, and it needs a terminal to have one.
|
|
56
|
+
*
|
|
57
|
+
* Not politeness — correctness. `readline/promises` drops lines that arrive
|
|
58
|
+
* while no `question()` is pending, which is every gap between our questions.
|
|
59
|
+
* Piped input therefore loses answers and then blocks on a line that will never
|
|
60
|
+
* come, and the process exits 0 having written nothing: the worst possible
|
|
61
|
+
* failure, because it looks like success.
|
|
62
|
+
*
|
|
63
|
+
* A TTY has no such gap — a human types *after* the prompt. So we require one,
|
|
64
|
+
* and point anyone scripting this at the two things that do work headlessly.
|
|
65
|
+
*/
|
|
66
|
+
function requireTty() {
|
|
67
|
+
if (process.stdin.isTTY === true && process.stdout.isTTY === true)
|
|
68
|
+
return;
|
|
69
|
+
throw new GmuxError("`gmux setup` needs an interactive terminal.", {
|
|
70
|
+
fix: `Run it in a terminal. To configure without one, set GMUX_SUMMARY_CMD='claude -p', or write ${configPath()} directly.`,
|
|
71
|
+
exitCode: 3,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
/** Read a 1-based menu choice, re-asking until it is valid. */
|
|
75
|
+
async function askChoice(rl, options, fallback) {
|
|
76
|
+
for (;;) {
|
|
77
|
+
const raw = (await rl.question(`\nwhich? [1-${options.length}, default ${fallback}] `)).trim();
|
|
78
|
+
if (raw === "")
|
|
79
|
+
return fallback;
|
|
80
|
+
const n = Number.parseInt(raw, 10);
|
|
81
|
+
if (Number.isFinite(n) && n >= 1 && n <= options.length)
|
|
82
|
+
return n;
|
|
83
|
+
process.stdout.write(` ${yellow(`Enter a number between 1 and ${options.length}.`)}\n`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
async function askYesNo(rl, question, fallback) {
|
|
87
|
+
const hint = fallback ? "Y/n" : "y/N";
|
|
88
|
+
for (;;) {
|
|
89
|
+
const raw = (await rl.question(`${question} [${hint}] `)).trim().toLowerCase();
|
|
90
|
+
if (raw === "")
|
|
91
|
+
return fallback;
|
|
92
|
+
if (["y", "yes"].includes(raw))
|
|
93
|
+
return true;
|
|
94
|
+
if (["n", "no"].includes(raw))
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* The one place gmux discloses that gmux can act on its own.
|
|
100
|
+
*
|
|
101
|
+
* Every other config choice here is passive — which harness to call, whether
|
|
102
|
+
* to summarize in the background. This is the one that reaches into a pane
|
|
103
|
+
* and types something, so it gets its own prominent prompt rather than
|
|
104
|
+
* riding along inside another question, and an explicit default rather than
|
|
105
|
+
* a silent one: pressing enter is still a choice, just the one most people
|
|
106
|
+
* want (see DEFAULT_GMUX_CONFIG.guardianPolicy).
|
|
107
|
+
*/
|
|
108
|
+
async function askGuardianPolicy(rl) {
|
|
109
|
+
process.stdout.write(`\n${bold("The gmux memory guardian")}\n${dim('It can type a "checkpoint and pause" message INTO your agent panes when host memory\n' +
|
|
110
|
+
"runs critically low. This is the one action gmux takes on your behalf.")}\n\n`);
|
|
111
|
+
process.stdout.write(` 1. ${bold("auto")} ${dim("broadcast the checkpoint message automatically (default)")}\n`);
|
|
112
|
+
process.stdout.write(` 2. ${bold("notify")} ${dim("tell me, do not type anything")}\n`);
|
|
113
|
+
process.stdout.write(` 3. ${bold("off")} ${dim("never act")}\n`);
|
|
114
|
+
for (;;) {
|
|
115
|
+
const raw = (await rl.question(`\nwhich? [1-3, default 1] `)).trim();
|
|
116
|
+
if (raw === "" || raw === "1")
|
|
117
|
+
return "auto";
|
|
118
|
+
if (raw === "2")
|
|
119
|
+
return "notify";
|
|
120
|
+
if (raw === "3")
|
|
121
|
+
return "off";
|
|
122
|
+
process.stdout.write(` ${yellow("Enter 1, 2, or 3.")}\n`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* The wizard itself. Returns the config it wrote.
|
|
127
|
+
*
|
|
128
|
+
* Takes its own readline interface so the first-run caller and `gmux setup` share
|
|
129
|
+
* one implementation and one teardown.
|
|
130
|
+
*/
|
|
131
|
+
export async function runSetupWizard(options = {}) {
|
|
132
|
+
requireTty();
|
|
133
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
134
|
+
try {
|
|
135
|
+
const existing = await readConfig();
|
|
136
|
+
if (options.firstRun) {
|
|
137
|
+
process.stdout.write(`\n${bold("Welcome to gmux.")}\n${dim("One question before we start: summaries cost model calls, so gmux won't make any until you say who to call.")}\n`);
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
process.stdout.write(`\n${bold("gmux setup")}\n`);
|
|
141
|
+
}
|
|
142
|
+
if (existing) {
|
|
143
|
+
const current = existing.provider
|
|
144
|
+
? existing.provider.command.join(" ")
|
|
145
|
+
: "nothing — no model calls";
|
|
146
|
+
process.stdout.write(`${dim(`currently: ${current}`)}\n`);
|
|
147
|
+
}
|
|
148
|
+
process.stdout.write(`\n${bold("Which harness should gmux use for model calls?")}\n`);
|
|
149
|
+
process.stdout.write(`${dim("Used to summarize where your sessions landed, and to answer `gmux ask`.")}\n\n`);
|
|
150
|
+
const menu = buildOptions();
|
|
151
|
+
// Default to the first installed provider — the answer most people want,
|
|
152
|
+
// and the one that reproduces gmux's behavior before config existed.
|
|
153
|
+
const firstInstalled = menu.findIndex((_, i) => {
|
|
154
|
+
const spec = PROVIDERS[i];
|
|
155
|
+
return spec ? onPath(spec.binary) : false;
|
|
156
|
+
});
|
|
157
|
+
const fallback = firstInstalled === -1 ? menu.length : firstInstalled + 1;
|
|
158
|
+
for (const [i, option] of menu.entries()) {
|
|
159
|
+
const spec = PROVIDERS[i];
|
|
160
|
+
const installed = spec ? onPath(spec.binary) : true;
|
|
161
|
+
const mark = spec ? (installed ? green("✓") : dim("○")) : dim(" ");
|
|
162
|
+
process.stdout.write(` ${mark} ${String(i + 1)}. ${bold(option.label)} ${dim(option.detail)}\n`);
|
|
163
|
+
}
|
|
164
|
+
const picked = menu[(await askChoice(rl, menu, fallback)) - 1];
|
|
165
|
+
const provider = await picked.choose(rl);
|
|
166
|
+
if (existing?.gmux) {
|
|
167
|
+
process.stdout.write(`${dim(`guardian currently: ${existing.gmux.guardianPolicy}`)}\n`);
|
|
168
|
+
}
|
|
169
|
+
const guardianPolicy = await askGuardianPolicy(rl);
|
|
170
|
+
// Only worth asking when there is something to call. "None" already answered it.
|
|
171
|
+
const autoSummarize = provider
|
|
172
|
+
? await askYesNo(rl, `\n${bold("Keep your 20 most recent sessions summarized in the background?")}\n${dim("This spends tokens as you work. gmux ls stays instant either way.")}\n`, true)
|
|
173
|
+
: false;
|
|
174
|
+
const config = {
|
|
175
|
+
version: CONFIG_VERSION,
|
|
176
|
+
provider,
|
|
177
|
+
autoSummarize,
|
|
178
|
+
gmux: { ...DEFAULT_GMUX_CONFIG, guardianPolicy },
|
|
179
|
+
};
|
|
180
|
+
await writeConfig(config);
|
|
181
|
+
process.stdout.write(`\n${green("✓")} ${dim(`saved to ${configPath()}`)}\n`);
|
|
182
|
+
process.stdout.write(provider
|
|
183
|
+
? `${dim("gmux will call")} ${cyan(provider.command.join(" "))}${dim(". Change it any time with `gmux setup`.")}\n\n`
|
|
184
|
+
: `${dim("gmux will make no model calls. Run `gmux setup` if you change your mind.")}\n\n`);
|
|
185
|
+
process.stdout.write(`${dim(`guardian: ${guardianPolicy}. Change it any time with \`gmux setup\`.`)}\n\n`);
|
|
186
|
+
return config;
|
|
187
|
+
}
|
|
188
|
+
finally {
|
|
189
|
+
rl.close();
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
export function registerSetup(program) {
|
|
193
|
+
program
|
|
194
|
+
.command("setup")
|
|
195
|
+
.description("choose the harness gmux uses for model calls (summaries and `gmux ask`)")
|
|
196
|
+
.action(async () => {
|
|
197
|
+
await runSetupWizard();
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
//# sourceMappingURL=setup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../../../src/cli/commands/setup.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { SCHEMA_VERSION } from "../../core/types.js";
|
|
2
|
+
import { loadRecords } from "../../services/views.js";
|
|
3
|
+
import { resolveSession } from "../../services/resolve.js";
|
|
4
|
+
import { readSummary } from "../../services/summarize.js";
|
|
5
|
+
import { formatCard, jsonEnvelope } from "../format.js";
|
|
6
|
+
export function registerShow(program) {
|
|
7
|
+
program
|
|
8
|
+
.command("show <id>")
|
|
9
|
+
.description("show the full context card for one session (id or unique prefix)")
|
|
10
|
+
.option("--json", "emit JSON for scripts and agents")
|
|
11
|
+
.action(async (id, options) => {
|
|
12
|
+
// Naming a session explicitly means you want it, whatever kind it is —
|
|
13
|
+
// including the ones `gmux ls` hides by default.
|
|
14
|
+
const records = await loadRecords({ includeSidechains: true, includeAutomated: true });
|
|
15
|
+
const record = resolveSession(records, id);
|
|
16
|
+
const summary = await readSummary(record);
|
|
17
|
+
if (options.json) {
|
|
18
|
+
process.stdout.write(`${jsonEnvelope(SCHEMA_VERSION, { record, summary })}\n`);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
process.stdout.write(`${formatCard({ record, summary })}\n`);
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=show.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"show.js","sourceRoot":"","sources":["../../../src/cli/commands/show.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAExD,MAAM,UAAU,YAAY,CAAC,OAAgB;IAC3C,OAAO;SACJ,OAAO,CAAC,WAAW,CAAC;SACpB,WAAW,CAAC,kEAAkE,CAAC;SAC/E,MAAM,CAAC,QAAQ,EAAE,kCAAkC,CAAC;SACpD,MAAM,CAAC,KAAK,EAAE,EAAU,EAAE,OAA2B,EAAE,EAAE;QACxD,uEAAuE;QACvE,iDAAiD;QACjD,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,EAAE,iBAAiB,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,CAAC,CAAC;QACvF,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAC3C,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,MAAM,CAAC,CAAC;QAE1C,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,YAAY,CAAC,cAAc,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC;YAC/E,OAAO;QACT,CAAC;QACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,UAAU,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { GmuxError, NoProviderError } from "../../core/errors.js";
|
|
2
|
+
import { loadRecords } from "../../services/views.js";
|
|
3
|
+
import { resolveSession } from "../../services/resolve.js";
|
|
4
|
+
import { defaultSummaryProvider, summarizeBatch } from "../../services/summarize.js";
|
|
5
|
+
import { bold, dim, green, yellow } from "../format.js";
|
|
6
|
+
export function registerSummarize(program) {
|
|
7
|
+
program
|
|
8
|
+
.command("summarize [id]")
|
|
9
|
+
.description("write summaries of where sessions landed (cached; only regenerates when a session changed)")
|
|
10
|
+
.option("-r, --recent <count>", "summarize the N most recent sessions", "20")
|
|
11
|
+
.option("--all", "summarize every session (can be expensive — you have a lot)")
|
|
12
|
+
.option("--force", "regenerate even if a cached summary is still current")
|
|
13
|
+
.option("--harness <id>", "only this harness")
|
|
14
|
+
.option("-p, --project <name>", "only sessions whose project matches")
|
|
15
|
+
.action(async (id, options) => {
|
|
16
|
+
// Two different "no", and they need two different answers: "you chose
|
|
17
|
+
// none" is a decision to revisit, "it isn't installed" is a thing to fix.
|
|
18
|
+
const provider = await defaultSummaryProvider();
|
|
19
|
+
if (!provider)
|
|
20
|
+
throw new NoProviderError("`gmux summarize`");
|
|
21
|
+
if (!(await provider.isAvailable())) {
|
|
22
|
+
throw new GmuxError(`Summary provider "${provider.name}" is not on your PATH.`, {
|
|
23
|
+
fix: "Run `gmux setup` to choose a provider that is installed.",
|
|
24
|
+
exitCode: 6,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
const all = await loadRecords({
|
|
28
|
+
...(options.harness ? { harness: options.harness } : {}),
|
|
29
|
+
...(options.project ? { project: options.project } : {}),
|
|
30
|
+
});
|
|
31
|
+
const targets = id
|
|
32
|
+
? [resolveSession(all, id)]
|
|
33
|
+
: options.all
|
|
34
|
+
? all
|
|
35
|
+
: all.slice(0, Number.parseInt(options.recent ?? "20", 10));
|
|
36
|
+
if (targets.length === 0) {
|
|
37
|
+
process.stdout.write(`${dim("Nothing to summarize.")}\n`);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
process.stdout.write(`${dim(`Summarizing ${targets.length} session${targets.length === 1 ? "" : "s"} with ${provider.name}…`)}\n`);
|
|
41
|
+
const result = await summarizeBatch(targets, provider, {
|
|
42
|
+
force: options.force === true,
|
|
43
|
+
onProgress: (done, total) => {
|
|
44
|
+
if (process.stdout.isTTY)
|
|
45
|
+
process.stdout.write(`\r${dim(` ${done}/${total}`)}`);
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
if (process.stdout.isTTY)
|
|
49
|
+
process.stdout.write("\r\x1b[K");
|
|
50
|
+
process.stdout.write(`${green(`✓ ${result.generated} written`)} ${dim(`${result.skipped} already current`)}\n`);
|
|
51
|
+
if (result.failed.length > 0) {
|
|
52
|
+
process.stdout.write(`${yellow(`${result.failed.length} failed:`)}\n`);
|
|
53
|
+
for (const failure of result.failed.slice(0, 5)) {
|
|
54
|
+
process.stdout.write(` ${bold(failure.sessionId.slice(0, 8))} ${dim(failure.reason)}\n`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=summarize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"summarize.js","sourceRoot":"","sources":["../../../src/cli/commands/summarize.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,sBAAsB,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AACrF,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAExD,MAAM,UAAU,iBAAiB,CAAC,OAAgB;IAChD,OAAO;SACJ,OAAO,CAAC,gBAAgB,CAAC;SACzB,WAAW,CAAC,4FAA4F,CAAC;SACzG,MAAM,CAAC,sBAAsB,EAAE,sCAAsC,EAAE,IAAI,CAAC;SAC5E,MAAM,CAAC,OAAO,EAAE,6DAA6D,CAAC;SAC9E,MAAM,CAAC,SAAS,EAAE,sDAAsD,CAAC;SACzE,MAAM,CAAC,gBAAgB,EAAE,mBAAmB,CAAC;SAC7C,MAAM,CAAC,sBAAsB,EAAE,qCAAqC,CAAC;SACrE,MAAM,CACL,KAAK,EACH,EAAsB,EACtB,OAAgG,EAChG,EAAE;QACF,sEAAsE;QACtE,0EAA0E;QAC1E,MAAM,QAAQ,GAAG,MAAM,sBAAsB,EAAE,CAAC;QAChD,IAAI,CAAC,QAAQ;YAAE,MAAM,IAAI,eAAe,CAAC,kBAAkB,CAAC,CAAC;QAC7D,IAAI,CAAC,CAAC,MAAM,QAAQ,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;YACpC,MAAM,IAAI,SAAS,CAAC,qBAAqB,QAAQ,CAAC,IAAI,wBAAwB,EAAE;gBAC9E,GAAG,EAAE,0DAA0D;gBAC/D,QAAQ,EAAE,CAAC;aACZ,CAAC,CAAC;QACL,CAAC;QAED,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC;YAC5B,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACxD,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACzD,CAAC,CAAC;QAEH,MAAM,OAAO,GAAG,EAAE;YAChB,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YAC3B,CAAC,CAAC,OAAO,CAAC,GAAG;gBACX,CAAC,CAAC,GAAG;gBACL,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,IAAI,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;QAEhE,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,uBAAuB,CAAC,IAAI,CAAC,CAAC;YAC1D,OAAO;QACT,CAAC;QAED,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,GAAG,GAAG,CAAC,eAAe,OAAO,CAAC,MAAM,WAAW,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,SAAS,QAAQ,CAAC,IAAI,GAAG,CAAC,IAAI,CAC7G,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,OAAO,EAAE,QAAQ,EAAE;YACrD,KAAK,EAAE,OAAO,CAAC,KAAK,KAAK,IAAI;YAC7B,UAAU,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;gBAC1B,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK;oBAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,KAAK,IAAI,IAAI,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;YACnF,CAAC;SACF,CAAC,CAAC;QAEH,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK;YAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAE3D,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,GAAG,KAAK,CAAC,KAAK,MAAM,CAAC,SAAS,UAAU,CAAC,KAAK,GAAG,CAAC,GAAG,MAAM,CAAC,OAAO,kBAAkB,CAAC,IAAI,CAC3F,CAAC;QAEF,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;YACvE,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;gBAChD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAC5F,CAAC;QACH,CAAC;IACH,CAAC,CACF,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Command } from "commander";
|
|
2
|
+
export declare const BLOCK_START = "# >>> gmux >>>";
|
|
3
|
+
export declare const BLOCK_END = "# <<< gmux <<<";
|
|
4
|
+
/**
|
|
5
|
+
* The bindings gmux manages. `ctrl+g` pulls up the whole-workspace cockpit;
|
|
6
|
+
* `ctrl+shift+g` opens the history picker, whose Enter resumes into a new window.
|
|
7
|
+
*/
|
|
8
|
+
export declare function bindingsBlock(): string;
|
|
9
|
+
export declare function upsertBlock(existing: string, block: string): string;
|
|
10
|
+
export declare function removeBlock(existing: string): string;
|
|
11
|
+
export declare function registerTmux(program: Command): void;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { dim, green } from "../format.js";
|
|
5
|
+
import { toggleWatch } from "../tmux-label.js";
|
|
6
|
+
export const BLOCK_START = "# >>> gmux >>>";
|
|
7
|
+
export const BLOCK_END = "# <<< gmux <<<";
|
|
8
|
+
/**
|
|
9
|
+
* The bindings gmux manages. `ctrl+g` pulls up the whole-workspace cockpit;
|
|
10
|
+
* `ctrl+shift+g` opens the history picker, whose Enter resumes into a new window.
|
|
11
|
+
*/
|
|
12
|
+
export function bindingsBlock() {
|
|
13
|
+
return [
|
|
14
|
+
BLOCK_START,
|
|
15
|
+
"# Pull up the whole-workspace cockpit; any close key dismisses.",
|
|
16
|
+
// Whole-workspace, so — unlike the overlay it replaced — this needs no
|
|
17
|
+
// window id resolved in-shell.
|
|
18
|
+
"bind -n C-g display-popup -w 100% -h 100% -x 0 -y 0 -B -E 'gmux cockpit'",
|
|
19
|
+
"# Toggle a headline label on every pane's border (leaves your panes visible).",
|
|
20
|
+
`bind -n M-g run-shell 'gmux tmux label "$(tmux display -p "#{window_id}")"'`,
|
|
21
|
+
"# Browse session history; Enter resumes into a new window.",
|
|
22
|
+
"bind -n C-S-g display-popup -w 80% -h 80% -E 'gmux pick --resume-in-window'",
|
|
23
|
+
BLOCK_END,
|
|
24
|
+
].join("\n");
|
|
25
|
+
}
|
|
26
|
+
function blockRegion(text) {
|
|
27
|
+
const start = text.indexOf(BLOCK_START);
|
|
28
|
+
if (start === -1)
|
|
29
|
+
return null;
|
|
30
|
+
const endMarker = text.indexOf(BLOCK_END, start);
|
|
31
|
+
if (endMarker === -1)
|
|
32
|
+
return null;
|
|
33
|
+
return { start, end: endMarker + BLOCK_END.length };
|
|
34
|
+
}
|
|
35
|
+
export function upsertBlock(existing, block) {
|
|
36
|
+
const region = blockRegion(existing);
|
|
37
|
+
if (!region) {
|
|
38
|
+
const sep = existing.length === 0 || existing.endsWith("\n") ? "" : "\n";
|
|
39
|
+
return `${existing}${sep}${block}\n`;
|
|
40
|
+
}
|
|
41
|
+
return existing.slice(0, region.start) + block + existing.slice(region.end);
|
|
42
|
+
}
|
|
43
|
+
export function removeBlock(existing) {
|
|
44
|
+
const region = blockRegion(existing);
|
|
45
|
+
if (!region)
|
|
46
|
+
return existing;
|
|
47
|
+
let before = existing.slice(0, region.start);
|
|
48
|
+
let after = existing.slice(region.end);
|
|
49
|
+
if (before.endsWith("\n"))
|
|
50
|
+
before = before.slice(0, -1);
|
|
51
|
+
if (after.startsWith("\n"))
|
|
52
|
+
after = after.slice(1);
|
|
53
|
+
return before + (before && after ? "\n" : "") + after;
|
|
54
|
+
}
|
|
55
|
+
function confPath() {
|
|
56
|
+
return join(homedir(), ".tmux.conf");
|
|
57
|
+
}
|
|
58
|
+
async function readConf() {
|
|
59
|
+
try {
|
|
60
|
+
return await readFile(confPath(), "utf8");
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return "";
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
export function registerTmux(program) {
|
|
67
|
+
const tmux = program.command("tmux").description("manage gmux's tmux key bindings");
|
|
68
|
+
tmux
|
|
69
|
+
.command("install")
|
|
70
|
+
.description("add the gmux cockpit/picker key bindings to ~/.tmux.conf")
|
|
71
|
+
.action(async () => {
|
|
72
|
+
await writeFile(confPath(), upsertBlock(await readConf(), bindingsBlock()), "utf8");
|
|
73
|
+
process.stdout.write(`${green("installed")} bindings in ${confPath()}\n`);
|
|
74
|
+
process.stdout.write(`${dim("reload with `tmux source-file ~/.tmux.conf`; then ctrl-g pulls up the cockpit, ctrl-shift-g browses")}\n`);
|
|
75
|
+
});
|
|
76
|
+
tmux
|
|
77
|
+
.command("uninstall")
|
|
78
|
+
.description("remove the gmux block from ~/.tmux.conf")
|
|
79
|
+
.action(async () => {
|
|
80
|
+
await writeFile(confPath(), removeBlock(await readConf()), "utf8");
|
|
81
|
+
process.stdout.write(`${green("removed")} the gmux block from ${confPath()}\n`);
|
|
82
|
+
});
|
|
83
|
+
tmux
|
|
84
|
+
.command("label <window>")
|
|
85
|
+
.description("toggle the live pane-border label agent (used by the M-g binding)")
|
|
86
|
+
.action(async (windowId) => {
|
|
87
|
+
await toggleWatch(windowId);
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=tmux.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tmux.js","sourceRoot":"","sources":["../../../src/cli/commands/tmux.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { maybeAutoSummarize } from "../../services/auto-summarize.js";
|
|
2
|
+
import { listAllPanes } from "../../services/tmux.js";
|
|
3
|
+
import { WATCH_INTERVAL_MS, WATCH_WORKER_COMMAND, clearWatchPid, readWatchPid, startWatch, stopWatch, } from "../../services/watch.js";
|
|
4
|
+
import { disableBorder, enableBorder, labelPanes } from "../tmux-label.js";
|
|
5
|
+
import { dim, green } from "../format.js";
|
|
6
|
+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
7
|
+
/**
|
|
8
|
+
* The background agent's loop, running in the detached worker.
|
|
9
|
+
*
|
|
10
|
+
* Each tick: label every pane across every window from cache (cheap), then hand
|
|
11
|
+
* the on-screen sessions to the summariser — WITHOUT `force`, so the existing
|
|
12
|
+
* cooldown throttles how often divergence turns into a model call while the
|
|
13
|
+
* labels stay live. `shouldRefresh` (the SimHash gate) decides what's worth it.
|
|
14
|
+
*
|
|
15
|
+
* It exits cleanly when tmux is gone (`listAllPanes` throws), when its PID file
|
|
16
|
+
* is removed or replaced (the toggle's stop path), or on a terminating signal.
|
|
17
|
+
* A transient per-tick error never kills the loop.
|
|
18
|
+
*/
|
|
19
|
+
async function runWatch() {
|
|
20
|
+
const me = process.pid;
|
|
21
|
+
let running = true;
|
|
22
|
+
// Exit promptly on stop rather than waiting out the current sleep. The toggle's
|
|
23
|
+
// stop path has already cleared the pid file; a signal-kill without it leaves a
|
|
24
|
+
// stale pid the next start reclaims.
|
|
25
|
+
const stop = () => {
|
|
26
|
+
running = false;
|
|
27
|
+
process.exit(0);
|
|
28
|
+
};
|
|
29
|
+
process.on("SIGTERM", stop);
|
|
30
|
+
process.on("SIGINT", stop);
|
|
31
|
+
while (running) {
|
|
32
|
+
const record = await readWatchPid();
|
|
33
|
+
if (!record || record.pid !== me)
|
|
34
|
+
break; // toggled off, or superseded
|
|
35
|
+
let panes;
|
|
36
|
+
try {
|
|
37
|
+
panes = await listAllPanes();
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
break; // tmux server is gone
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
const records = await labelPanes(panes);
|
|
44
|
+
await maybeAutoSummarize({ records });
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// A transient read/tmux hiccup — skip this tick, keep watching.
|
|
48
|
+
}
|
|
49
|
+
await sleep(WATCH_INTERVAL_MS);
|
|
50
|
+
}
|
|
51
|
+
await clearWatchPid();
|
|
52
|
+
}
|
|
53
|
+
export function registerWatch(program) {
|
|
54
|
+
program
|
|
55
|
+
.command("watch")
|
|
56
|
+
.description("run gmux's background agent: keep pane labels and summaries current")
|
|
57
|
+
.option("--stop", "stop the running watcher")
|
|
58
|
+
.action(async (options) => {
|
|
59
|
+
if (options.stop) {
|
|
60
|
+
const was = await stopWatch();
|
|
61
|
+
await disableBorder();
|
|
62
|
+
process.stdout.write(`${was ? green("stopped") : dim("nothing was running")}\n`);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const result = await startWatch();
|
|
66
|
+
if (result !== "failed")
|
|
67
|
+
await enableBorder();
|
|
68
|
+
process.stdout.write(`${dim(`watch ${result}`)}\n`);
|
|
69
|
+
});
|
|
70
|
+
// The detached loop. Hidden (`__`-prefixed), so the postAction summarize hook
|
|
71
|
+
// and the setup wizard both skip it.
|
|
72
|
+
program.command(WATCH_WORKER_COMMAND, { hidden: true }).action(async () => {
|
|
73
|
+
await runWatch();
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=watch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watch.js","sourceRoot":"","sources":["../../../src/cli/commands/watch.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AACtE,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,aAAa,EACb,YAAY,EACZ,UAAU,EACV,SAAS,GACV,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC3E,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAE1C,MAAM,KAAK,GAAG,CAAC,EAAU,EAAiB,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAE/F;;;;;;;;;;;GAWG;AACH,KAAK,UAAU,QAAQ;IACrB,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC;IACvB,IAAI,OAAO,GAAG,IAAI,CAAC;IACnB,gFAAgF;IAChF,gFAAgF;IAChF,qCAAqC;IACrC,MAAM,IAAI,GAAG,GAAS,EAAE;QACtB,OAAO,GAAG,KAAK,CAAC;QAChB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IACF,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAC5B,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAE3B,OAAO,OAAO,EAAE,CAAC;QACf,MAAM,MAAM,GAAG,MAAM,YAAY,EAAE,CAAC;QACpC,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,GAAG,KAAK,EAAE;YAAE,MAAM,CAAC,6BAA6B;QAEtE,IAAI,KAAK,CAAC;QACV,IAAI,CAAC;YACH,KAAK,GAAG,MAAM,YAAY,EAAE,CAAC;QAC/B,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,CAAC,sBAAsB;QAC/B,CAAC;QAED,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,KAAK,CAAC,CAAC;YACxC,MAAM,kBAAkB,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;QACxC,CAAC;QAAC,MAAM,CAAC;YACP,gEAAgE;QAClE,CAAC;QAED,MAAM,KAAK,CAAC,iBAAiB,CAAC,CAAC;IACjC,CAAC;IAED,MAAM,aAAa,EAAE,CAAC;AACxB,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,OAAgB;IAC5C,OAAO;SACJ,OAAO,CAAC,OAAO,CAAC;SAChB,WAAW,CAAC,qEAAqE,CAAC;SAClF,MAAM,CAAC,QAAQ,EAAE,0BAA0B,CAAC;SAC5C,MAAM,CAAC,KAAK,EAAE,OAA2B,EAAE,EAAE;QAC5C,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YACjB,MAAM,GAAG,GAAG,MAAM,SAAS,EAAE,CAAC;YAC9B,MAAM,aAAa,EAAE,CAAC;YACtB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC;YACjF,OAAO;QACT,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;QAClC,IAAI,MAAM,KAAK,QAAQ;YAAE,MAAM,YAAY,EAAE,CAAC;QAC9C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,SAAS,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEL,8EAA8E;IAC9E,qCAAqC;IACrC,OAAO,CAAC,OAAO,CAAC,oBAAoB,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE;QACxE,MAAM,QAAQ,EAAE,CAAC;IACnB,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,74 @@
|
|
|
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 type { SessionRecord, SessionView } from "../core/types.js";
|
|
8
|
+
export declare const dim: (text: string) => string;
|
|
9
|
+
export declare const bold: (text: string) => string;
|
|
10
|
+
export declare const cyan: (text: string) => string;
|
|
11
|
+
export declare const yellow: (text: string) => string;
|
|
12
|
+
export declare const red: (text: string) => string;
|
|
13
|
+
export declare const green: (text: string) => string;
|
|
14
|
+
export declare const paneCyan: (text: string) => string;
|
|
15
|
+
export declare const paneBold: (text: string) => string;
|
|
16
|
+
export declare const paneDim: (text: string) => string;
|
|
17
|
+
/** "repo/branch", or just "repo" when the branch adds nothing. */
|
|
18
|
+
export declare function sessionLabel(record: SessionRecord): string;
|
|
19
|
+
/**
|
|
20
|
+
* Rows whose summary the background worker is writing at this moment.
|
|
21
|
+
* Empty set = nothing in flight.
|
|
22
|
+
*/
|
|
23
|
+
export type InProgress = ReadonlySet<string>;
|
|
24
|
+
/**
|
|
25
|
+
* One row, on exactly one line.
|
|
26
|
+
*
|
|
27
|
+
* Used by the picker, where a session must occupy a single line — fzf maps lines
|
|
28
|
+
* back to session ids, so a wrapped row would break selection.
|
|
29
|
+
*/
|
|
30
|
+
export declare function formatRow(view: SessionView, now?: Date, inProgress?: InProgress): string;
|
|
31
|
+
/**
|
|
32
|
+
* One row of `gmux ls`, wrapped to the terminal so the whole description is
|
|
33
|
+
* readable rather than chopped off at the right edge. Continuation lines are
|
|
34
|
+
* indented to sit under the description column.
|
|
35
|
+
*
|
|
36
|
+
* Pass `width: Infinity` when the output is not a terminal: piped output should
|
|
37
|
+
* be one line per session, so `gmux ls | grep` behaves.
|
|
38
|
+
*/
|
|
39
|
+
export declare function formatRowLines(view: SessionView, now?: Date, width?: number, inProgress?: InProgress): string[];
|
|
40
|
+
/**
|
|
41
|
+
* The key under the list. Only mentions markers that actually appear, so a fully
|
|
42
|
+
* summarized list carries no footer at all.
|
|
43
|
+
*/
|
|
44
|
+
export declare function formatLegend(views: readonly SessionView[], inProgress?: InProgress): string;
|
|
45
|
+
/**
|
|
46
|
+
* The key for a LIVE list: every marker, always, and never a count.
|
|
47
|
+
*
|
|
48
|
+
* The picker renders the same markers `gmux ls` does, so it needs the same
|
|
49
|
+
* explanation — but not `formatLegend`. fzf sets `--header` once, at spawn:
|
|
50
|
+
* `ctrl-r` reloads the item list and leaves the header untouched. Counts baked
|
|
51
|
+
* in there freeze at open and are wrong after the first refresh, and a key
|
|
52
|
+
* listing "only the markers present" goes stale the moment a refresh brings in
|
|
53
|
+
* one that wasn't. ctrl-r is precisely when both change.
|
|
54
|
+
*
|
|
55
|
+
* So: nothing here depends on the list. A stale key is worse than a fixed one —
|
|
56
|
+
* absent an explanation you go looking, given a wrong one you don't. The cost is
|
|
57
|
+
* one line naming `○` on a list that has none.
|
|
58
|
+
*/
|
|
59
|
+
export declare function formatMarkerKey(): string;
|
|
60
|
+
/** Terminal width, or a sane default when we cannot tell. */
|
|
61
|
+
export declare function terminalWidth(): number;
|
|
62
|
+
/** The detail card shown by `gmux show` and in the picker's preview pane. */
|
|
63
|
+
export declare function formatCard(view: SessionView, now?: Date): string;
|
|
64
|
+
/**
|
|
65
|
+
* Two spaces under a heading — the card's only body indent.
|
|
66
|
+
*
|
|
67
|
+
* Exported for the preview's chat half, whose speaker bodies sit under `you` and
|
|
68
|
+
* `gmux` exactly as the card's text sits under `WHERE IT LANDED`. Both halves share
|
|
69
|
+
* one pane, so a second indent idiom would show up as two columns that almost
|
|
70
|
+
* line up.
|
|
71
|
+
*/
|
|
72
|
+
export declare function indent(text: string): string;
|
|
73
|
+
/** Stable JSON envelope. Everything machine-readable goes through here. */
|
|
74
|
+
export declare function jsonEnvelope<T>(schemaVersion: number, data: T): string;
|