@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 @@
|
|
|
1
|
+
{"version":3,"file":"auto.js","sourceRoot":"","sources":["../../../src/cli/commands/auto.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,sBAAsB,EACtB,WAAW,EACX,gBAAgB,GACjB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAErE;;;;;;;;;GASG;AACH,MAAM,UAAU,2BAA2B,CAAC,OAAgB;IAC1D,OAAO;SACJ,OAAO,CAAC,sBAAsB,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;SACjD,WAAW,CAAC,6EAA6E,CAAC;SAC1F,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,mEAAmE;QACnE,6DAA6D;QAC7D,MAAM,QAAQ,GAAG,MAAM,sBAAsB,EAAE,CAAC;QAChD,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAC,MAAM,QAAQ,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;YACjD,MAAM,WAAW,EAAE,CAAC;YACpB,OAAO;QACT,CAAC;QACD,MAAM,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Command } from "commander";
|
|
2
|
+
import type { WorkspaceSnapshot } from "../../core/gmux-types.js";
|
|
3
|
+
import { type RenderCockpitOptions } from "../gmux-render.js";
|
|
4
|
+
/** Clear screen + home, then the cockpit grid — CRLF-joined for raw-mode stdout. */
|
|
5
|
+
export declare function buildFrame(snapshot: WorkspaceSnapshot, now: number, opts?: RenderCockpitOptions): string;
|
|
6
|
+
/**
|
|
7
|
+
* The whole-workspace cockpit: paint the last known snapshot immediately (if
|
|
8
|
+
* one is on disk), then stay live off the daemon socket until a close key is
|
|
9
|
+
* pressed. If the socket errors — daemon not running, or it dies mid-session —
|
|
10
|
+
* we stay defensive: fall back to re-reading the snapshot file so the header
|
|
11
|
+
* can show a "daemon not connected — snapshot Ns ago" banner instead of
|
|
12
|
+
* silently going quiet.
|
|
13
|
+
*/
|
|
14
|
+
export declare function registerCockpit(program: Command): void;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { readSnapshotFile, subscribe } from "../../services/daemon-client.js";
|
|
2
|
+
import { renderCockpit } from "../gmux-render.js";
|
|
3
|
+
import { isCloseKey } from "./overlay.js";
|
|
4
|
+
/** Clear screen + home, then the cockpit grid — CRLF-joined for raw-mode stdout. */
|
|
5
|
+
export function buildFrame(snapshot, now, opts) {
|
|
6
|
+
return "\x1b[2J\x1b[H" + renderCockpit(snapshot, now, opts).join("\r\n");
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* The whole-workspace cockpit: paint the last known snapshot immediately (if
|
|
10
|
+
* one is on disk), then stay live off the daemon socket until a close key is
|
|
11
|
+
* pressed. If the socket errors — daemon not running, or it dies mid-session —
|
|
12
|
+
* we stay defensive: fall back to re-reading the snapshot file so the header
|
|
13
|
+
* can show a "daemon not connected — snapshot Ns ago" banner instead of
|
|
14
|
+
* silently going quiet.
|
|
15
|
+
*/
|
|
16
|
+
export function registerCockpit(program) {
|
|
17
|
+
program
|
|
18
|
+
.command("cockpit")
|
|
19
|
+
.description("pull up the gmux workspace cockpit (used by the tmux ctrl-g binding)")
|
|
20
|
+
.action(async () => {
|
|
21
|
+
const initial = await readSnapshotFile();
|
|
22
|
+
const paint = (s) => {
|
|
23
|
+
process.stdout.write(buildFrame(s, Date.now()));
|
|
24
|
+
};
|
|
25
|
+
if (initial)
|
|
26
|
+
paint(initial.snapshot);
|
|
27
|
+
const paintStale = () => {
|
|
28
|
+
readSnapshotFile()
|
|
29
|
+
.then((current) => {
|
|
30
|
+
if (current)
|
|
31
|
+
process.stdout.write(buildFrame(current.snapshot, Date.now(), { stale: { ageMs: current.ageMs } }));
|
|
32
|
+
})
|
|
33
|
+
.catch(() => { });
|
|
34
|
+
};
|
|
35
|
+
const stop = subscribe(paint, { onError: paintStale });
|
|
36
|
+
const stdin = process.stdin;
|
|
37
|
+
if (stdin.isTTY)
|
|
38
|
+
stdin.setRawMode?.(true);
|
|
39
|
+
stdin.resume();
|
|
40
|
+
await new Promise((done) => {
|
|
41
|
+
stdin.on("data", (buf) => {
|
|
42
|
+
if (isCloseKey(buf.toString()))
|
|
43
|
+
done();
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
stop();
|
|
47
|
+
if (stdin.isTTY)
|
|
48
|
+
stdin.setRawMode?.(false);
|
|
49
|
+
process.exit(0);
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=cockpit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cockpit.js","sourceRoot":"","sources":["../../../src/cli/commands/cockpit.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AAC9E,OAAO,EAAE,aAAa,EAA6B,MAAM,mBAAmB,CAAC;AAC7E,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,oFAAoF;AACpF,MAAM,UAAU,UAAU,CAAC,QAA2B,EAAE,GAAW,EAAE,IAA2B;IAC9F,OAAO,eAAe,GAAG,aAAa,CAAC,QAAQ,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC3E,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAAC,OAAgB;IAC9C,OAAO;SACJ,OAAO,CAAC,SAAS,CAAC;SAClB,WAAW,CAAC,sEAAsE,CAAC;SACnF,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,MAAM,OAAO,GAAG,MAAM,gBAAgB,EAAE,CAAC;QACzC,MAAM,KAAK,GAAG,CAAC,CAAoB,EAAQ,EAAE;YAC3C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QAClD,CAAC,CAAC;QACF,IAAI,OAAO;YAAE,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAErC,MAAM,UAAU,GAAG,GAAS,EAAE;YAC5B,gBAAgB,EAAE;iBACf,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE;gBAChB,IAAI,OAAO;oBAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC;YACnH,CAAC,CAAC;iBACD,KAAK,CAAC,GAAG,EAAE,GAAwC,CAAC,CAAC,CAAC;QAC3D,CAAC,CAAC;QAEF,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC,CAAC;QAEvD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC5B,IAAI,KAAK,CAAC,KAAK;YAAE,KAAK,CAAC,UAAU,EAAE,CAAC,IAAI,CAAC,CAAC;QAC1C,KAAK,CAAC,MAAM,EAAE,CAAC;QAEf,MAAM,IAAI,OAAO,CAAO,CAAC,IAAI,EAAE,EAAE;YAC/B,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,GAAW,EAAE,EAAE;gBAC/B,IAAI,UAAU,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;oBAAE,IAAI,EAAE,CAAC;YACzC,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,IAAI,EAAE,CAAC;QACP,IAAI,KAAK,CAAC,KAAK;YAAE,KAAK,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC;QAC3C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `gmux daemon` — the gmux workspace daemon.
|
|
3
|
+
*
|
|
4
|
+
* `run` starts the interval loop (tmux registry diff → sensors → classify →
|
|
5
|
+
* write to the model) plus the `ModelServer` socket, foreground, supervised by
|
|
6
|
+
* a PID lockfile so a second `gmux daemon run` refuses to double-start. `status`
|
|
7
|
+
* and `stop` read that same lock to report on / signal the running process.
|
|
8
|
+
*
|
|
9
|
+
* The lock is a small mirror of `services/auto-summarize.ts`'s lock: same
|
|
10
|
+
* shape (`{ pid, startedAt }`), same staleness rule (owner dead, or too old).
|
|
11
|
+
* It lives under `gmuxDir()` rather than `cacheDir()` directly because it is
|
|
12
|
+
* gmux-specific ephemeral state, not shared with the rest of gmux.
|
|
13
|
+
*/
|
|
14
|
+
import type { Command } from "commander";
|
|
15
|
+
import type { GmuxConfig } from "../../core/gmux-types.js";
|
|
16
|
+
import { type DaemonDeps } from "../../services/daemon.js";
|
|
17
|
+
import { type LabelProvider } from "../../services/semantic.js";
|
|
18
|
+
import { type TmuxGateway } from "../../services/tmux-gateway.js";
|
|
19
|
+
import { WorkspaceModel } from "../../services/workspace.js";
|
|
20
|
+
export interface LoopOpts {
|
|
21
|
+
tickMs: number;
|
|
22
|
+
signal: AbortSignal;
|
|
23
|
+
onTick?: () => void;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The testable core: tick the daemon on an interval until `signal` aborts.
|
|
27
|
+
*
|
|
28
|
+
* A tick failure never kills the loop — `tickOnce` already swallows per-sensor
|
|
29
|
+
* errors, but this catch is belt-and-suspenders against anything else (e.g. a
|
|
30
|
+
* gateway that throws) so the daemon degrades to "nothing observed this tick"
|
|
31
|
+
* rather than exiting.
|
|
32
|
+
*
|
|
33
|
+
* Exactly ONE `abort` listener is attached, before the loop starts, and it
|
|
34
|
+
* lives for the whole call. Attaching a fresh `{ once: true }` listener inside
|
|
35
|
+
* each iteration's wait looks harmless — `once` removes it once *abort*
|
|
36
|
+
* fires — but on the far more common path (the timeout just elapses) nothing
|
|
37
|
+
* ever removes it, so listeners pile up on the long-lived signal and Node
|
|
38
|
+
* emits `MaxListenersExceededWarning` after ~10 ticks. `wake` is the current
|
|
39
|
+
* iteration's resolver; the single listener just calls whichever one is live.
|
|
40
|
+
*/
|
|
41
|
+
export declare function runDaemonLoop(deps: DaemonDeps, opts: LoopOpts): Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* Assemble the full `DaemonDeps` for a production `gmux daemon run` — all four
|
|
44
|
+
* phases wired: the base tick loop (gateway/model/clock), the LLM semantic
|
|
45
|
+
* worker (Phase 1), and the resource monitor + memory guardian (Phase 2).
|
|
46
|
+
*
|
|
47
|
+
* Pure and synchronous so it can be unit-tested without a socket or real
|
|
48
|
+
* processes: the caller resolves the (async) label provider once and passes
|
|
49
|
+
* it in. The `SemanticWorker`'s own try/catch tolerates a provider that
|
|
50
|
+
* throws, so wiring it unconditionally is safe even when no provider is
|
|
51
|
+
* configured. `resolveAgents` is deliberately left unset — the guardian's
|
|
52
|
+
* real broadcast targeting (harness && sessionId, in `Daemon.tickOnce`) is
|
|
53
|
+
* the production path; that override is a test-only seam.
|
|
54
|
+
*/
|
|
55
|
+
export declare function buildDaemonDeps(gateway: TmuxGateway, model: WorkspaceModel, gmuxCfg: GmuxConfig, provider: LabelProvider): DaemonDeps;
|
|
56
|
+
/** A lock older than this belongs to a process that died without cleaning up. */
|
|
57
|
+
export declare const DAEMON_LOCK_STALE_MS: number;
|
|
58
|
+
export interface DaemonLock {
|
|
59
|
+
pid: number;
|
|
60
|
+
startedAt: string;
|
|
61
|
+
}
|
|
62
|
+
export declare function daemonLockPath(): string;
|
|
63
|
+
/** A lock is stale when its owner is gone, or when it is simply too old. */
|
|
64
|
+
export declare function isDaemonLockStale(lock: DaemonLock, now?: Date, staleMs?: number): boolean;
|
|
65
|
+
/** Corrupt or missing lock reads as "not running" — never throws. */
|
|
66
|
+
export declare function readDaemonLock(): Promise<DaemonLock | null>;
|
|
67
|
+
export declare function releaseDaemonLock(): Promise<void>;
|
|
68
|
+
/**
|
|
69
|
+
* Take the lock for this process, refusing if a live one already exists.
|
|
70
|
+
*
|
|
71
|
+
* Returns false — never throws — when another daemon is already running, so
|
|
72
|
+
* callers can print a clear message and exit rather than crash.
|
|
73
|
+
*/
|
|
74
|
+
export declare function acquireDaemonLock(now?: Date): Promise<boolean>;
|
|
75
|
+
export declare function registerDaemon(program: Command): void;
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `gmux daemon` — the gmux workspace daemon.
|
|
3
|
+
*
|
|
4
|
+
* `run` starts the interval loop (tmux registry diff → sensors → classify →
|
|
5
|
+
* write to the model) plus the `ModelServer` socket, foreground, supervised by
|
|
6
|
+
* a PID lockfile so a second `gmux daemon run` refuses to double-start. `status`
|
|
7
|
+
* and `stop` read that same lock to report on / signal the running process.
|
|
8
|
+
*
|
|
9
|
+
* The lock is a small mirror of `services/auto-summarize.ts`'s lock: same
|
|
10
|
+
* shape (`{ pid, startedAt }`), same staleness rule (owner dead, or too old).
|
|
11
|
+
* It lives under `gmuxDir()` rather than `cacheDir()` directly because it is
|
|
12
|
+
* gmux-specific ephemeral state, not shared with the rest of gmux.
|
|
13
|
+
*/
|
|
14
|
+
import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
15
|
+
import { join } from "node:path";
|
|
16
|
+
import { gmuxDir } from "../../core/paths.js";
|
|
17
|
+
import { readConfig, resolveGmuxConfig } from "../../services/config.js";
|
|
18
|
+
import { Daemon } from "../../services/daemon.js";
|
|
19
|
+
import { readSnapshotFile } from "../../services/daemon-client.js";
|
|
20
|
+
import { ModelServer } from "../../services/daemon-socket.js";
|
|
21
|
+
import { Guardian } from "../../services/guardian.js";
|
|
22
|
+
import { ResourceMonitor } from "../../services/resources.js";
|
|
23
|
+
import { defaultLabelProvider, SemanticWorker } from "../../services/semantic.js";
|
|
24
|
+
import { SemanticGate } from "../../services/semantic-gate.js";
|
|
25
|
+
import { RealTmuxGateway } from "../../services/tmux-gateway.js";
|
|
26
|
+
import { WorkspaceModel } from "../../services/workspace.js";
|
|
27
|
+
import { paintFromSnapshot } from "../border-client.js";
|
|
28
|
+
import { dim, green, red, yellow } from "../format.js";
|
|
29
|
+
import { enableBorder } from "../tmux-label.js";
|
|
30
|
+
/**
|
|
31
|
+
* The testable core: tick the daemon on an interval until `signal` aborts.
|
|
32
|
+
*
|
|
33
|
+
* A tick failure never kills the loop — `tickOnce` already swallows per-sensor
|
|
34
|
+
* errors, but this catch is belt-and-suspenders against anything else (e.g. a
|
|
35
|
+
* gateway that throws) so the daemon degrades to "nothing observed this tick"
|
|
36
|
+
* rather than exiting.
|
|
37
|
+
*
|
|
38
|
+
* Exactly ONE `abort` listener is attached, before the loop starts, and it
|
|
39
|
+
* lives for the whole call. Attaching a fresh `{ once: true }` listener inside
|
|
40
|
+
* each iteration's wait looks harmless — `once` removes it once *abort*
|
|
41
|
+
* fires — but on the far more common path (the timeout just elapses) nothing
|
|
42
|
+
* ever removes it, so listeners pile up on the long-lived signal and Node
|
|
43
|
+
* emits `MaxListenersExceededWarning` after ~10 ticks. `wake` is the current
|
|
44
|
+
* iteration's resolver; the single listener just calls whichever one is live.
|
|
45
|
+
*/
|
|
46
|
+
export async function runDaemonLoop(deps, opts) {
|
|
47
|
+
const daemon = new Daemon(deps);
|
|
48
|
+
let wake;
|
|
49
|
+
const onAbort = () => wake?.();
|
|
50
|
+
opts.signal.addEventListener("abort", onAbort, { once: true });
|
|
51
|
+
try {
|
|
52
|
+
while (!opts.signal.aborted) {
|
|
53
|
+
await daemon.tickOnce().catch(() => {
|
|
54
|
+
/* keep the loop alive */
|
|
55
|
+
});
|
|
56
|
+
opts.onTick?.();
|
|
57
|
+
if (opts.signal.aborted)
|
|
58
|
+
break;
|
|
59
|
+
await new Promise((resolve) => {
|
|
60
|
+
const t = setTimeout(() => {
|
|
61
|
+
wake = undefined;
|
|
62
|
+
resolve();
|
|
63
|
+
}, opts.tickMs);
|
|
64
|
+
wake = () => {
|
|
65
|
+
clearTimeout(t);
|
|
66
|
+
resolve();
|
|
67
|
+
};
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
finally {
|
|
72
|
+
// Already gone if `abort` fired (the `once` removed it); harmless no-op
|
|
73
|
+
// either way. Guarantees no timer or listener outlives the call.
|
|
74
|
+
opts.signal.removeEventListener("abort", onAbort);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Assemble the full `DaemonDeps` for a production `gmux daemon run` — all four
|
|
79
|
+
* phases wired: the base tick loop (gateway/model/clock), the LLM semantic
|
|
80
|
+
* worker (Phase 1), and the resource monitor + memory guardian (Phase 2).
|
|
81
|
+
*
|
|
82
|
+
* Pure and synchronous so it can be unit-tested without a socket or real
|
|
83
|
+
* processes: the caller resolves the (async) label provider once and passes
|
|
84
|
+
* it in. The `SemanticWorker`'s own try/catch tolerates a provider that
|
|
85
|
+
* throws, so wiring it unconditionally is safe even when no provider is
|
|
86
|
+
* configured. `resolveAgents` is deliberately left unset — the guardian's
|
|
87
|
+
* real broadcast targeting (harness && sessionId, in `Daemon.tickOnce`) is
|
|
88
|
+
* the production path; that override is a test-only seam.
|
|
89
|
+
*/
|
|
90
|
+
export function buildDaemonDeps(gateway, model, gmuxCfg, provider) {
|
|
91
|
+
const semantic = new SemanticWorker(model, provider, new SemanticGate());
|
|
92
|
+
const resources = new ResourceMonitor();
|
|
93
|
+
const guardian = new Guardian({
|
|
94
|
+
policy: gmuxCfg.guardianPolicy,
|
|
95
|
+
threshold: gmuxCfg.memoryThreshold,
|
|
96
|
+
cooldownSeconds: gmuxCfg.cooldownSeconds,
|
|
97
|
+
});
|
|
98
|
+
return { gateway, model, now: () => Date.now(), semantic, resources, guardian };
|
|
99
|
+
}
|
|
100
|
+
// --- Lock -------------------------------------------------------------
|
|
101
|
+
/** A lock older than this belongs to a process that died without cleaning up. */
|
|
102
|
+
export const DAEMON_LOCK_STALE_MS = 10 * 60_000;
|
|
103
|
+
export function daemonLockPath() {
|
|
104
|
+
return join(gmuxDir(), "daemon.lock");
|
|
105
|
+
}
|
|
106
|
+
function processAlive(pid) {
|
|
107
|
+
if (pid <= 0)
|
|
108
|
+
return false;
|
|
109
|
+
try {
|
|
110
|
+
process.kill(pid, 0);
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
// EPERM means the process exists but belongs to someone else — still alive.
|
|
115
|
+
return error.code === "EPERM";
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/** A lock is stale when its owner is gone, or when it is simply too old. */
|
|
119
|
+
export function isDaemonLockStale(lock, now = new Date(), staleMs = DAEMON_LOCK_STALE_MS) {
|
|
120
|
+
const started = Date.parse(lock.startedAt);
|
|
121
|
+
if (Number.isNaN(started))
|
|
122
|
+
return true;
|
|
123
|
+
if (now.getTime() - started > staleMs)
|
|
124
|
+
return true;
|
|
125
|
+
return !processAlive(lock.pid);
|
|
126
|
+
}
|
|
127
|
+
/** Corrupt or missing lock reads as "not running" — never throws. */
|
|
128
|
+
export async function readDaemonLock() {
|
|
129
|
+
try {
|
|
130
|
+
const parsed = JSON.parse(await readFile(daemonLockPath(), "utf8"));
|
|
131
|
+
if (typeof parsed?.startedAt !== "string")
|
|
132
|
+
return null;
|
|
133
|
+
const pid = Number(parsed.pid);
|
|
134
|
+
if (!Number.isFinite(pid))
|
|
135
|
+
return null;
|
|
136
|
+
return { pid, startedAt: parsed.startedAt };
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
async function writeDaemonLock(lock) {
|
|
143
|
+
await mkdir(gmuxDir(), { recursive: true });
|
|
144
|
+
await writeFile(daemonLockPath(), JSON.stringify(lock), "utf8");
|
|
145
|
+
}
|
|
146
|
+
export async function releaseDaemonLock() {
|
|
147
|
+
await rm(daemonLockPath(), { force: true });
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Take the lock for this process, refusing if a live one already exists.
|
|
151
|
+
*
|
|
152
|
+
* Returns false — never throws — when another daemon is already running, so
|
|
153
|
+
* callers can print a clear message and exit rather than crash.
|
|
154
|
+
*/
|
|
155
|
+
export async function acquireDaemonLock(now = new Date()) {
|
|
156
|
+
const existing = await readDaemonLock();
|
|
157
|
+
if (existing && !isDaemonLockStale(existing, now))
|
|
158
|
+
return false;
|
|
159
|
+
await writeDaemonLock({ pid: process.pid, startedAt: now.toISOString() });
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
// --- Command ------------------------------------------------------------
|
|
163
|
+
export function registerDaemon(program) {
|
|
164
|
+
const cmd = program.command("daemon").description("run and manage the gmux workspace daemon");
|
|
165
|
+
cmd
|
|
166
|
+
.command("run", { isDefault: true })
|
|
167
|
+
.description("run the daemon loop in the foreground")
|
|
168
|
+
.action(async () => {
|
|
169
|
+
if (!(await acquireDaemonLock())) {
|
|
170
|
+
const existing = await readDaemonLock();
|
|
171
|
+
process.stderr.write(`${red("error")} a daemon is already running (pid ${existing?.pid ?? "?"})\n`);
|
|
172
|
+
process.exitCode = 1;
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
// From here on the lock is held, so EVERYTHING — server construction,
|
|
176
|
+
// `start()`, the loop — must run inside this `try`. `server.start()`
|
|
177
|
+
// can throw (e.g. the socket path is unwritable, or a stale socket
|
|
178
|
+
// file is somehow un-removable); if it does outside a `try/finally`
|
|
179
|
+
// the lock file is leaked forever and every future `gmux daemon run`
|
|
180
|
+
// refuses to start until someone manually deletes it.
|
|
181
|
+
const config = await readConfig();
|
|
182
|
+
const gmuxCfg = resolveGmuxConfig(config);
|
|
183
|
+
const provider = await defaultLabelProvider();
|
|
184
|
+
const gateway = new RealTmuxGateway();
|
|
185
|
+
const model = new WorkspaceModel();
|
|
186
|
+
const deps = buildDaemonDeps(gateway, model, gmuxCfg, provider);
|
|
187
|
+
const server = new ModelServer(model);
|
|
188
|
+
const ac = new AbortController();
|
|
189
|
+
const stop = () => ac.abort();
|
|
190
|
+
// Repaints every pane's `@gm_label` on each model change — state only,
|
|
191
|
+
// zero sensing. Never lets a paint failure (e.g. a pane that vanished
|
|
192
|
+
// mid-write) propagate into the model's "change" emitter and take down
|
|
193
|
+
// the daemon loop.
|
|
194
|
+
const onChange = () => {
|
|
195
|
+
paintFromSnapshot(model.snapshot(), (id, text) => gateway.setOption(id, "@gm_label", text)).catch(() => { });
|
|
196
|
+
};
|
|
197
|
+
try {
|
|
198
|
+
await server.start();
|
|
199
|
+
process.on("SIGINT", stop);
|
|
200
|
+
process.on("SIGTERM", stop);
|
|
201
|
+
process.stdout.write(`${green("gmux daemon started")} (pid ${process.pid})\n`);
|
|
202
|
+
await enableBorder();
|
|
203
|
+
model.on("change", onChange);
|
|
204
|
+
await runDaemonLoop(deps, { tickMs: gmuxCfg.tickMs, signal: ac.signal });
|
|
205
|
+
}
|
|
206
|
+
finally {
|
|
207
|
+
model.off("change", onChange);
|
|
208
|
+
process.off("SIGINT", stop);
|
|
209
|
+
process.off("SIGTERM", stop);
|
|
210
|
+
// Safe even when `start()` itself threw: `stop()` no-ops when the
|
|
211
|
+
// server was never assigned, and force-removes the socket path
|
|
212
|
+
// either way. Never let a cleanup failure hide the original error
|
|
213
|
+
// or, worse, skip releasing the lock below.
|
|
214
|
+
await server.stop().catch(() => { });
|
|
215
|
+
await releaseDaemonLock();
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
cmd
|
|
219
|
+
.command("status")
|
|
220
|
+
.description("show whether the daemon is running")
|
|
221
|
+
.action(async () => {
|
|
222
|
+
const lock = await readDaemonLock();
|
|
223
|
+
if (!lock) {
|
|
224
|
+
process.stdout.write(`${dim("stopped")} — no daemon lock\n`);
|
|
225
|
+
}
|
|
226
|
+
else if (isDaemonLockStale(lock)) {
|
|
227
|
+
process.stdout.write(`${yellow("stale")} — lock left by pid ${lock.pid} (${lock.startedAt})\n`);
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
process.stdout.write(`${green("running")} (pid ${lock.pid}, started ${lock.startedAt})\n`);
|
|
231
|
+
}
|
|
232
|
+
const snap = await readSnapshotFile();
|
|
233
|
+
if (snap) {
|
|
234
|
+
process.stdout.write(`${dim(`snapshot: ${snap.snapshot.panes.length} pane(s), ${Math.round(snap.ageMs / 1000)}s old`)}\n`);
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
process.stdout.write(`${dim("snapshot: none yet")}\n`);
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
cmd
|
|
241
|
+
.command("stop")
|
|
242
|
+
.description("stop the running daemon")
|
|
243
|
+
.action(async () => {
|
|
244
|
+
const lock = await readDaemonLock();
|
|
245
|
+
if (!lock || isDaemonLockStale(lock)) {
|
|
246
|
+
process.stdout.write(`${dim("nothing was running")}\n`);
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
try {
|
|
250
|
+
process.kill(lock.pid, "SIGTERM");
|
|
251
|
+
process.stdout.write(`${green("stopped")} (sent SIGTERM to pid ${lock.pid})\n`);
|
|
252
|
+
}
|
|
253
|
+
catch {
|
|
254
|
+
process.stdout.write(`${dim("nothing was running")}\n`);
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
//# sourceMappingURL=daemon.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon.js","sourceRoot":"","sources":["../../../src/cli/commands/daemon.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Command } from "commander";
|
|
2
|
+
/**
|
|
3
|
+
* Report what is present, what is missing, and — for anything missing — the
|
|
4
|
+
* exact command that fixes it. No diagnostic should ever leave you guessing.
|
|
5
|
+
*/
|
|
6
|
+
export declare function registerDoctor(program: Command): void;
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { SCHEMA_VERSION } from "../../core/types.js";
|
|
2
|
+
import { cacheDir, configPath } from "../../core/paths.js";
|
|
3
|
+
import { allAdapters } from "../../adapters/registry.js";
|
|
4
|
+
import { AUTO_SUMMARIZE_LIMIT, autoSummarizeEnabled, lastAutoSummarizeError, } from "../../services/auto-summarize.js";
|
|
5
|
+
import { configExists, isChildProcess, readConfig } from "../../services/config.js";
|
|
6
|
+
import { onPath } from "../../services/providers.js";
|
|
7
|
+
import { defaultSummaryProvider } from "../../services/summarize.js";
|
|
8
|
+
import { discover } from "../../services/index-store.js";
|
|
9
|
+
import { supportsDisplayPopup, tmuxVersion } from "../../services/tmux.js";
|
|
10
|
+
import { dim, green, jsonEnvelope, red, yellow } from "../format.js";
|
|
11
|
+
/**
|
|
12
|
+
* Report what is present, what is missing, and — for anything missing — the
|
|
13
|
+
* exact command that fixes it. No diagnostic should ever leave you guessing.
|
|
14
|
+
*/
|
|
15
|
+
export function registerDoctor(program) {
|
|
16
|
+
program
|
|
17
|
+
.command("doctor")
|
|
18
|
+
.description("check what gmux can see, and what's missing")
|
|
19
|
+
.option("--json", "emit JSON for scripts and agents")
|
|
20
|
+
.action(async (options) => {
|
|
21
|
+
const checks = [];
|
|
22
|
+
for (const adapter of allAdapters()) {
|
|
23
|
+
const available = await adapter.isAvailable();
|
|
24
|
+
const sessions = available ? (await adapter.listSessions()).length : 0;
|
|
25
|
+
checks.push({
|
|
26
|
+
name: `harness: ${adapter.displayName}`,
|
|
27
|
+
ok: available,
|
|
28
|
+
optional: true,
|
|
29
|
+
detail: available ? `${sessions} sessions found` : "no session directory on this machine",
|
|
30
|
+
...(available ? {} : { fix: `Nothing to do unless you use ${adapter.displayName}.` }),
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
const rg = onPath("rg");
|
|
34
|
+
checks.push({
|
|
35
|
+
name: "ripgrep (search)",
|
|
36
|
+
ok: rg,
|
|
37
|
+
detail: rg ? "on PATH" : "missing — `gmux grep` will not work",
|
|
38
|
+
...(rg ? {} : { fix: "brew install ripgrep" }),
|
|
39
|
+
});
|
|
40
|
+
const fzf = onPath("fzf");
|
|
41
|
+
checks.push({
|
|
42
|
+
name: "fzf (fuzzy picker)",
|
|
43
|
+
ok: fzf,
|
|
44
|
+
optional: true,
|
|
45
|
+
detail: fzf ? "on PATH" : "missing — the picker falls back to a numbered list",
|
|
46
|
+
...(fzf ? {} : { fix: "brew install fzf" }),
|
|
47
|
+
});
|
|
48
|
+
const tmuxV = await tmuxVersion();
|
|
49
|
+
const tmuxOk = supportsDisplayPopup(tmuxV);
|
|
50
|
+
checks.push({
|
|
51
|
+
name: "tmux (peek overlay)",
|
|
52
|
+
ok: tmuxOk,
|
|
53
|
+
optional: true,
|
|
54
|
+
detail: tmuxV
|
|
55
|
+
? tmuxOk
|
|
56
|
+
? `${tmuxV.raw} — \`ctrl+g\` overlay available`
|
|
57
|
+
: `${tmuxV.raw} — too old; the overlay needs tmux >= 3.2`
|
|
58
|
+
: "not found — the tmux overlay (`gmux tmux install`) is unavailable",
|
|
59
|
+
...(tmuxOk
|
|
60
|
+
? {}
|
|
61
|
+
: { fix: tmuxV ? "Upgrade tmux to 3.2 or newer." : "brew install tmux, then `gmux tmux install`." }),
|
|
62
|
+
});
|
|
63
|
+
// Config first: it explains every provider answer below it.
|
|
64
|
+
const config = await readConfig();
|
|
65
|
+
const hasConfigFile = await configExists();
|
|
66
|
+
checks.push({
|
|
67
|
+
name: "config",
|
|
68
|
+
// Absent config is fine — gmux autodetects. A file we couldn't parse is not.
|
|
69
|
+
ok: !hasConfigFile || config !== null,
|
|
70
|
+
optional: true,
|
|
71
|
+
detail: !hasConfigFile
|
|
72
|
+
? "none yet — gmux autodetects a provider. `gmux setup` makes the choice explicit"
|
|
73
|
+
: config === null
|
|
74
|
+
? "unreadable — ignoring it and autodetecting instead"
|
|
75
|
+
: `${configPath()}`,
|
|
76
|
+
...(hasConfigFile && config === null ? { fix: "Run `gmux setup` to rewrite it." } : {}),
|
|
77
|
+
});
|
|
78
|
+
const provider = await defaultSummaryProvider();
|
|
79
|
+
const providerOk = provider !== null && (await provider.isAvailable());
|
|
80
|
+
checks.push({
|
|
81
|
+
name: provider ? `model provider (${provider.name})` : "model provider",
|
|
82
|
+
ok: providerOk,
|
|
83
|
+
optional: true,
|
|
84
|
+
detail: !provider
|
|
85
|
+
? "none — this machine is configured to make no model calls"
|
|
86
|
+
: providerOk
|
|
87
|
+
? "on PATH"
|
|
88
|
+
: "missing — `gmux summarize` and `gmux ask` will not work",
|
|
89
|
+
...(providerOk ? {} : { fix: "Run `gmux setup` to choose a provider." }),
|
|
90
|
+
});
|
|
91
|
+
// Background model calls spend tokens, so make it visible that they happen
|
|
92
|
+
// — and say, right here, exactly which of the three "no"s is in effect.
|
|
93
|
+
const envOn = autoSummarizeEnabled();
|
|
94
|
+
const configOn = config ? config.autoSummarize : true;
|
|
95
|
+
const nested = isChildProcess();
|
|
96
|
+
const autoOn = envOn && configOn && !nested;
|
|
97
|
+
const offReason = !envOn
|
|
98
|
+
? "off (GMUX_AUTO_SUMMARIZE=0)"
|
|
99
|
+
: !configOn
|
|
100
|
+
? "off (you declined it in `gmux setup`)"
|
|
101
|
+
: nested
|
|
102
|
+
? "off (this gmux was spawned by gmux's own provider)"
|
|
103
|
+
: "";
|
|
104
|
+
checks.push({
|
|
105
|
+
name: "auto-summarize (background)",
|
|
106
|
+
ok: autoOn && providerOk,
|
|
107
|
+
optional: true,
|
|
108
|
+
detail: !autoOn
|
|
109
|
+
? offReason
|
|
110
|
+
: providerOk
|
|
111
|
+
? `on — the ${AUTO_SUMMARIZE_LIMIT} most recent sessions are summarized in the background`
|
|
112
|
+
: "on, but idle — no model provider available",
|
|
113
|
+
...(autoOn && providerOk
|
|
114
|
+
? {}
|
|
115
|
+
: {
|
|
116
|
+
fix: !envOn
|
|
117
|
+
? "Unset GMUX_AUTO_SUMMARIZE to let gmux keep recent sessions summarized."
|
|
118
|
+
: !configOn
|
|
119
|
+
? "Run `gmux setup` to turn it back on."
|
|
120
|
+
: nested
|
|
121
|
+
? "Nothing to do — this is the guard that stops gmux summarizing its own summarizer."
|
|
122
|
+
: "Run `gmux setup` to choose a provider, or `gmux --no-auto-summarize` to silence this.",
|
|
123
|
+
}),
|
|
124
|
+
});
|
|
125
|
+
// The worker's stdio is ignored, so a broken provider is otherwise silent:
|
|
126
|
+
// summaries simply never appear and there is nothing to look at.
|
|
127
|
+
const lastError = await lastAutoSummarizeError();
|
|
128
|
+
if (lastError) {
|
|
129
|
+
checks.push({
|
|
130
|
+
name: "last background summarize",
|
|
131
|
+
ok: false,
|
|
132
|
+
optional: true,
|
|
133
|
+
detail: lastError,
|
|
134
|
+
fix: "Check the summary provider works standalone: `echo hi | claude -p`.",
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
const total = (await discover()).length;
|
|
138
|
+
checks.push({
|
|
139
|
+
name: "sessions visible",
|
|
140
|
+
ok: total > 0,
|
|
141
|
+
detail: `${total} total`,
|
|
142
|
+
...(total > 0 ? {} : { fix: "Run an agent session first, or check GMUX_HOME." }),
|
|
143
|
+
});
|
|
144
|
+
if (options.json) {
|
|
145
|
+
process.stdout.write(`${jsonEnvelope(SCHEMA_VERSION, { checks, cacheDir: cacheDir() })}\n`);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
for (const check of checks) {
|
|
149
|
+
const mark = check.ok ? green("✓") : check.optional ? yellow("○") : red("✗");
|
|
150
|
+
process.stdout.write(`${mark} ${check.name} ${dim(check.detail)}\n`);
|
|
151
|
+
if (!check.ok && check.fix)
|
|
152
|
+
process.stdout.write(` ${dim(`fix: ${check.fix}`)}\n`);
|
|
153
|
+
}
|
|
154
|
+
process.stdout.write(`\n${dim(`cache: ${cacheDir()}`)}\n`);
|
|
155
|
+
if (checks.some((c) => !c.ok && !c.optional))
|
|
156
|
+
process.exitCode = 1;
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../../src/cli/commands/doctor.ts"],"names":[],"mappings":"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"}
|