@creativeintelligence/abbie 0.1.6 → 0.1.8

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 (141) hide show
  1. package/bin/dev.js +1 -49
  2. package/bin/run.js +42 -49
  3. package/dist/cli/commands/project/add.d.ts +0 -1
  4. package/dist/cli/commands/project/add.js +16 -52
  5. package/dist/cli/commands/project/list.js +13 -93
  6. package/dist/cli/commands/project/remove.d.ts +0 -2
  7. package/dist/cli/commands/project/remove.js +11 -28
  8. package/dist/cli/commands/session/list.js +3 -12
  9. package/dist/cli/commands/session/mark-done.js +1 -7
  10. package/dist/cli/commands/session/start.d.ts +0 -1
  11. package/dist/cli/commands/session/start.js +5 -7
  12. package/dist/lib/active-sessions.d.ts +0 -12
  13. package/dist/lib/active-sessions.js +6 -175
  14. package/dist/lib/project-path.d.ts +6 -0
  15. package/dist/lib/project-path.js +21 -0
  16. package/dist/lib.d.ts +1 -2
  17. package/dist/lib.js +2 -4
  18. package/oclif.manifest.json +2569 -6368
  19. package/package.json +21 -10
  20. package/dist/cli/commands/backlog/add.d.ts +0 -22
  21. package/dist/cli/commands/backlog/add.js +0 -65
  22. package/dist/cli/commands/backlog/claim.d.ts +0 -19
  23. package/dist/cli/commands/backlog/claim.js +0 -45
  24. package/dist/cli/commands/backlog/complete.d.ts +0 -18
  25. package/dist/cli/commands/backlog/complete.js +0 -42
  26. package/dist/cli/commands/backlog/list.d.ts +0 -20
  27. package/dist/cli/commands/backlog/list.js +0 -91
  28. package/dist/cli/commands/backlog/pick.d.ts +0 -18
  29. package/dist/cli/commands/backlog/pick.js +0 -42
  30. package/dist/cli/commands/backlog/sync.d.ts +0 -24
  31. package/dist/cli/commands/backlog/sync.js +0 -109
  32. package/dist/cli/commands/daemon.d.ts +0 -56
  33. package/dist/cli/commands/daemon.js +0 -1465
  34. package/dist/cli/commands/docs/lint.d.ts +0 -18
  35. package/dist/cli/commands/docs/lint.js +0 -82
  36. package/dist/cli/commands/docs/sync.d.ts +0 -19
  37. package/dist/cli/commands/docs/sync.js +0 -76
  38. package/dist/cli/commands/gc.d.ts +0 -29
  39. package/dist/cli/commands/gc.js +0 -211
  40. package/dist/cli/commands/index.d.ts +0 -36
  41. package/dist/cli/commands/index.js +0 -228
  42. package/dist/cli/commands/panes/broker.d.ts +0 -17
  43. package/dist/cli/commands/panes/broker.js +0 -57
  44. package/dist/cli/commands/panes/pipe-sink.d.ts +0 -17
  45. package/dist/cli/commands/panes/pipe-sink.js +0 -90
  46. package/dist/cli/commands/panes/snapshot.d.ts +0 -20
  47. package/dist/cli/commands/panes/snapshot.js +0 -125
  48. package/dist/cli/commands/preview/init.d.ts +0 -25
  49. package/dist/cli/commands/preview/init.js +0 -159
  50. package/dist/cli/commands/preview/sync.d.ts +0 -23
  51. package/dist/cli/commands/preview/sync.js +0 -144
  52. package/dist/cli/commands/preview/watch.d.ts +0 -24
  53. package/dist/cli/commands/preview/watch.js +0 -153
  54. package/dist/cli/commands/resource/acquire.d.ts +0 -21
  55. package/dist/cli/commands/resource/acquire.js +0 -90
  56. package/dist/cli/commands/resource/list.d.ts +0 -15
  57. package/dist/cli/commands/resource/list.js +0 -61
  58. package/dist/cli/commands/resource/release.d.ts +0 -18
  59. package/dist/cli/commands/resource/release.js +0 -50
  60. package/dist/cli/commands/resource/wait.d.ts +0 -21
  61. package/dist/cli/commands/resource/wait.js +0 -73
  62. package/dist/cli/commands/session/view.d.ts +0 -24
  63. package/dist/cli/commands/session/view.js +0 -145
  64. package/dist/cli/commands/start.d.ts +0 -37
  65. package/dist/cli/commands/start.js +0 -234
  66. package/dist/cli/commands/triage/claim.d.ts +0 -23
  67. package/dist/cli/commands/triage/claim.js +0 -186
  68. package/dist/cli/commands/triage/list.d.ts +0 -22
  69. package/dist/cli/commands/triage/list.js +0 -112
  70. package/dist/cli/commands/triage/next.d.ts +0 -18
  71. package/dist/cli/commands/triage/next.js +0 -63
  72. package/dist/cli/commands/triage/pull.d.ts +0 -19
  73. package/dist/cli/commands/triage/pull.js +0 -82
  74. package/dist/cli/commands/triage/stats.d.ts +0 -16
  75. package/dist/cli/commands/triage/stats.js +0 -69
  76. package/dist/cli/commands/tunnel/list.d.ts +0 -16
  77. package/dist/cli/commands/tunnel/list.js +0 -98
  78. package/dist/cli/commands/tunnel/start.d.ts +0 -24
  79. package/dist/cli/commands/tunnel/start.js +0 -107
  80. package/dist/cli/commands/tunnel/stop.d.ts +0 -20
  81. package/dist/cli/commands/tunnel/stop.js +0 -90
  82. package/dist/cli/commands/tunnel/url.d.ts +0 -21
  83. package/dist/cli/commands/tunnel/url.js +0 -70
  84. package/dist/cli/commands/windows/context.d.ts +0 -18
  85. package/dist/cli/commands/windows/context.js +0 -326
  86. package/dist/cli/commands/windows/focus.d.ts +0 -17
  87. package/dist/cli/commands/windows/focus.js +0 -103
  88. package/dist/cli/commands/windows/list.d.ts +0 -21
  89. package/dist/cli/commands/windows/list.js +0 -172
  90. package/dist/cli/commands/windows/map.d.ts +0 -17
  91. package/dist/cli/commands/windows/map.js +0 -168
  92. package/dist/cli/commands/windows/read.d.ts +0 -21
  93. package/dist/cli/commands/windows/read.js +0 -241
  94. package/dist/cli/commands/windows/search.d.ts +0 -24
  95. package/dist/cli/commands/windows/search.js +0 -171
  96. package/dist/cli/commands/windows/show.d.ts +0 -19
  97. package/dist/cli/commands/windows/show.js +0 -165
  98. package/dist/cli/commands/windows/watch.d.ts +0 -19
  99. package/dist/cli/commands/windows/watch.js +0 -241
  100. package/dist/lib/managed-session.d.ts +0 -27
  101. package/dist/lib/managed-session.js +0 -105
  102. package/dist/lib/panes/broker.d.ts +0 -130
  103. package/dist/lib/panes/broker.js +0 -97
  104. package/dist/lib/panes/index.d.ts +0 -2
  105. package/dist/lib/panes/index.js +0 -1
  106. package/dist/lib/panes/server.d.ts +0 -17
  107. package/dist/lib/panes/server.js +0 -308
  108. package/dist/lib/preview/manager.d.ts +0 -77
  109. package/dist/lib/preview/manager.js +0 -369
  110. package/dist/lib/preview/schema.d.ts +0 -2
  111. package/dist/lib/preview/schema.js +0 -32
  112. package/dist/lib/preview/sprite.d.ts +0 -85
  113. package/dist/lib/preview/sprite.js +0 -321
  114. package/dist/lib/preview/watcher.d.ts +0 -63
  115. package/dist/lib/preview/watcher.js +0 -185
  116. package/dist/lib/project-identity.d.ts +0 -16
  117. package/dist/lib/project-identity.js +0 -75
  118. package/dist/lib/tmux/bridge.d.ts +0 -133
  119. package/dist/lib/tmux/bridge.js +0 -315
  120. package/dist/lib/tmux/context.d.ts +0 -82
  121. package/dist/lib/tmux/context.js +0 -239
  122. package/dist/lib/tmux/index.d.ts +0 -8
  123. package/dist/lib/tmux/index.js +0 -11
  124. package/dist/lib/tmux/map.d.ts +0 -57
  125. package/dist/lib/tmux/map.js +0 -198
  126. package/dist/lib/tmux/panes.d.ts +0 -27
  127. package/dist/lib/tmux/panes.js +0 -151
  128. package/dist/lib/tmux/redaction.d.ts +0 -57
  129. package/dist/lib/tmux/redaction.js +0 -152
  130. package/dist/lib/web/analytics.d.ts +0 -63
  131. package/dist/lib/web/analytics.js +0 -168
  132. package/dist/lib/web/server.d.ts +0 -26
  133. package/dist/lib/web/server.js +0 -697
  134. package/dist/lib/web/tmux-bridge.d.ts +0 -7
  135. package/dist/lib/web/tmux-bridge.js +0 -7
  136. package/dist/lib/windows/index.d.ts +0 -3
  137. package/dist/lib/windows/index.js +0 -2
  138. package/dist/lib/windows/inventory.d.ts +0 -21
  139. package/dist/lib/windows/inventory.js +0 -263
  140. package/dist/lib/windows/types.d.ts +0 -46
  141. package/dist/lib/windows/types.js +0 -1
@@ -1,165 +0,0 @@
1
- import { Args, Flags } from "@oclif/core";
2
- import { getCurrentBufferInfo } from "../../../lib/nvim/remote.js";
3
- import { isRunning } from "../../../lib/tmux/index.js";
4
- import * as windows from "../../../lib/windows/index.js";
5
- import { BaseCommand } from "../../base-command.js";
6
- function abbreviateHome(path) {
7
- const home = process.env.HOME;
8
- if (!home)
9
- return path;
10
- if (path === home)
11
- return "~";
12
- if (path.startsWith(`${home}/`))
13
- return `~/${path.slice(home.length + 1)}`;
14
- return path;
15
- }
16
- function paneRef(window) {
17
- return `${window.session}:${window.window}.${window.pane}`;
18
- }
19
- function formatPathForDisplay(path, cwd) {
20
- if (!path)
21
- return path;
22
- const normalizedCwd = cwd.endsWith("/") ? cwd : `${cwd}/`;
23
- if (path.startsWith(normalizedCwd)) {
24
- return path.slice(normalizedCwd.length);
25
- }
26
- return abbreviateHome(path);
27
- }
28
- function toBufferInfo(buf) {
29
- if (!buf)
30
- return null;
31
- return {
32
- name: buf.name,
33
- path: buf.name,
34
- modified: buf.modified,
35
- filetype: buf.filetype,
36
- lineCount: 0,
37
- cursor: buf.cursor,
38
- };
39
- }
40
- export default class WindowsShowCommand extends BaseCommand {
41
- static summary = "Show detailed window state";
42
- static hidden = false;
43
- static examples = [
44
- "$ abbie windows show",
45
- "$ abbie windows show %3",
46
- "$ abbie windows show work:0.0",
47
- "$ abbie windows show --with-buffers",
48
- "$ abbie windows show --json",
49
- ];
50
- static args = {
51
- ref: Args.string({
52
- description: "Pane ID (e.g. %3) or session:window.pane (e.g. work:0.0)",
53
- required: false,
54
- }),
55
- };
56
- static flags = {
57
- ...BaseCommand.baseFlags,
58
- "with-buffers": Flags.boolean({
59
- description: "Include all buffers (expensive)",
60
- default: false,
61
- }),
62
- };
63
- async execute() {
64
- const { args, flags } = await this.parse(WindowsShowCommand);
65
- this.parsedFlags = flags;
66
- const tmuxRunning = await isRunning();
67
- if (!tmuxRunning) {
68
- const result = { tmuxRunning: false, window: null };
69
- if (!this.jsonEnabled?.()) {
70
- this.log("tmux is not running");
71
- }
72
- return result;
73
- }
74
- const state = args.ref
75
- ? await windows.getWindowState(args.ref, {
76
- includeNvim: true,
77
- includeAgent: true,
78
- includeBuffers: flags["with-buffers"],
79
- })
80
- : await windows.getFocusedWindow({
81
- includeNvim: true,
82
- includeAgent: true,
83
- includeBuffers: flags["with-buffers"],
84
- });
85
- let enriched = state;
86
- if (enriched?.nvim?.available && enriched.nvim.serverAddr && !enriched.nvim.currentBuffer) {
87
- const buf = await getCurrentBufferInfo(enriched.nvim.serverAddr);
88
- const converted = toBufferInfo(buf);
89
- if (converted) {
90
- enriched = {
91
- ...enriched,
92
- nvim: {
93
- ...enriched.nvim,
94
- currentBuffer: converted,
95
- },
96
- };
97
- }
98
- }
99
- const result = { tmuxRunning: true, window: enriched };
100
- if (!this.jsonEnabled?.()) {
101
- this.printText(result, flags);
102
- }
103
- return result;
104
- }
105
- printText(result, flags) {
106
- const state = result.window;
107
- if (!state) {
108
- this.log("Window not found");
109
- return;
110
- }
111
- const id = state.window.paneId || paneRef(state.window);
112
- const ref = paneRef(state.window);
113
- this.log(`WINDOW ${id} (${ref})`);
114
- this.log(`Session: ${state.window.session}`);
115
- this.log(`Window: ${state.window.window} (${state.window.windowName})`);
116
- this.log(`Pane: ${state.window.pane} (${state.window.active ? "active" : "inactive"})`);
117
- this.log(`CWD: ${abbreviateHome(state.window.cwd)}`);
118
- this.log(`CMD: ${state.window.title}`);
119
- this.log(`Size: ${state.window.size.cols}x${state.window.size.rows}`);
120
- this.log("");
121
- this.log("NVIM");
122
- if (state.nvim?.available) {
123
- this.log(`PID: ${state.nvim.pid ?? "-"}`);
124
- this.log(`Server: ${state.nvim.serverAddr ?? "-"}${state.nvim.discoveryMethod ? ` (${state.nvim.discoveryMethod})` : ""}`);
125
- const buf = state.nvim.currentBuffer;
126
- if (buf) {
127
- const cursor = buf.cursor ? `${buf.cursor.line}:${buf.cursor.col}` : "-";
128
- const displayPath = formatPathForDisplay(buf.path, state.window.cwd);
129
- const mod = buf.modified ? " [modified]" : "";
130
- this.log(`Buffer: ${displayPath} (${buf.filetype || "unknown"})${mod}`);
131
- this.log(`Cursor: ${cursor}`);
132
- }
133
- else {
134
- this.log("Buffer: -");
135
- }
136
- if (flags["with-buffers"] && state.buffers.length > 0) {
137
- this.log("");
138
- this.log("BUFFERS");
139
- for (const b of state.buffers) {
140
- const displayPath = formatPathForDisplay(b.path, state.window.cwd);
141
- const mod = b.modified ? " [modified]" : "";
142
- this.log(`- ${displayPath} (${b.filetype || "unknown"})${mod}`);
143
- }
144
- }
145
- }
146
- else {
147
- this.log("Not available");
148
- }
149
- this.log("");
150
- this.log("AGENT");
151
- if (state.agent) {
152
- this.log(`Type: ${state.agent.type}`);
153
- this.log(`PID: ${state.agent.pid}`);
154
- if (state.agent.sessionId) {
155
- this.log(`Session: ${state.agent.sessionId}`);
156
- }
157
- if (state.agent.issue) {
158
- this.log(`Issue: ${state.agent.issue}`);
159
- }
160
- }
161
- else {
162
- this.log("None");
163
- }
164
- }
165
- }
@@ -1,19 +0,0 @@
1
- import { BaseCommand } from "../../base-command.js";
2
- export default class WindowsWatchCommand extends BaseCommand {
3
- static summary: string;
4
- static hidden: boolean;
5
- static examples: string[];
6
- static flags: {
7
- session: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
8
- active: import("@oclif/core/interfaces").BooleanFlag<boolean>;
9
- "with-nvim": import("@oclif/core/interfaces").BooleanFlag<boolean>;
10
- "with-agent": import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
- "debounce-ms": import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
12
- format: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
- quiet: import("@oclif/core/interfaces").BooleanFlag<boolean>;
14
- "json-errors": import("@oclif/core/interfaces").BooleanFlag<boolean>;
15
- ndjson: import("@oclif/core/interfaces").BooleanFlag<boolean>;
16
- };
17
- execute(): Promise<unknown>;
18
- }
19
- //# sourceMappingURL=watch.d.ts.map
@@ -1,241 +0,0 @@
1
- import { spawn } from "node:child_process";
2
- import { createHash } from "node:crypto";
3
- import { Flags } from "@oclif/core";
4
- import { isRunning } from "../../../lib/tmux/index.js";
5
- import * as windows from "../../../lib/windows/index.js";
6
- import { BaseCommand } from "../../base-command.js";
7
- function paneRef(window) {
8
- return `${window.session}:${window.window}.${window.pane}`;
9
- }
10
- function stableWindowId(state) {
11
- return state.window.paneId || paneRef(state.window);
12
- }
13
- function sortWindows(states) {
14
- return [...states].sort((a, b) => {
15
- if (a.window.session !== b.window.session)
16
- return a.window.session.localeCompare(b.window.session);
17
- if (a.window.window !== b.window.window)
18
- return a.window.window - b.window.window;
19
- return a.window.pane - b.window.pane;
20
- });
21
- }
22
- function hashWindows(states) {
23
- const stable = states.map((s) => ({
24
- id: stableWindowId(s),
25
- session: s.window.session,
26
- window: s.window.window,
27
- windowName: s.window.windowName,
28
- pane: s.window.pane,
29
- cwd: s.window.cwd,
30
- title: s.window.title,
31
- active: s.window.active,
32
- cols: s.window.size.cols,
33
- rows: s.window.size.rows,
34
- hasNvim: s.nvim?.available ?? false,
35
- nvimPid: s.nvim?.pid ?? null,
36
- agentType: s.agent?.type ?? null,
37
- agentPid: s.agent?.pid ?? null,
38
- }));
39
- return createHash("sha1").update(JSON.stringify(stable)).digest("hex");
40
- }
41
- function isControlModeNotification(line) {
42
- if (!line.startsWith("%"))
43
- return false;
44
- if (line.startsWith("%begin"))
45
- return false;
46
- if (line.startsWith("%end"))
47
- return false;
48
- if (line.startsWith("%error"))
49
- return false;
50
- return true;
51
- }
52
- export default class WindowsWatchCommand extends BaseCommand {
53
- static summary = "Watch workspace windows (tmux panes) and stream updates";
54
- static hidden = false;
55
- static examples = [
56
- "$ abbie windows watch --ndjson --quiet",
57
- "$ abbie windows watch --ndjson --quiet --debounce-ms 100",
58
- "$ abbie windows watch --ndjson --quiet --no-with-nvim",
59
- ];
60
- static flags = {
61
- ...BaseCommand.baseFlags,
62
- session: Flags.string({
63
- char: "s",
64
- description: "Filter to specific tmux session",
65
- }),
66
- active: Flags.boolean({
67
- description: "Only show active panes",
68
- default: false,
69
- }),
70
- "with-nvim": Flags.boolean({
71
- description: "Include nvim state",
72
- default: true,
73
- allowNo: true,
74
- }),
75
- "with-agent": Flags.boolean({
76
- description: "Include agent detection",
77
- default: true,
78
- allowNo: true,
79
- }),
80
- "debounce-ms": Flags.integer({
81
- description: "Debounce inventory refresh triggered by tmux notifications (ms)",
82
- default: 75,
83
- }),
84
- };
85
- async execute() {
86
- const { flags } = await this.parse(WindowsWatchCommand);
87
- this.parsedFlags = flags;
88
- if (!this.ndjsonEnabled()) {
89
- this.error("windows watch is a streaming command; run with --ndjson (and usually --quiet)");
90
- }
91
- const tmuxRunning = await isRunning();
92
- if (!tmuxRunning) {
93
- const evt = {
94
- type: "windows.status",
95
- at: new Date().toISOString(),
96
- reason: "initial",
97
- tmuxRunning: false,
98
- message: "tmux is not running",
99
- };
100
- this.outputNdjson([evt]);
101
- return evt;
102
- }
103
- const includeNvim = flags["with-nvim"];
104
- const includeAgent = flags["with-agent"];
105
- const onlyActive = flags.active;
106
- const debounceMs = Math.max(0, flags["debounce-ms"]);
107
- let lastHash = null;
108
- let pendingTimer = null;
109
- let lastReason = "tmux";
110
- let stopped = false;
111
- const emitInventory = async (reason) => {
112
- if (stopped)
113
- return;
114
- const states = await windows.inventory({
115
- session: flags.session,
116
- includeNvim,
117
- includeAgent,
118
- includeBuffers: false,
119
- });
120
- const filtered = onlyActive ? states.filter((s) => s.window.active) : states;
121
- const sorted = sortWindows(filtered);
122
- const hash = hashWindows(sorted);
123
- if (reason !== "initial" && lastHash === hash)
124
- return;
125
- lastHash = hash;
126
- const evt = {
127
- type: "windows.update",
128
- at: new Date().toISOString(),
129
- reason,
130
- tmuxRunning: true,
131
- windows: sorted,
132
- hash,
133
- };
134
- this.outputNdjson([evt]);
135
- };
136
- const scheduleInventory = (reason) => {
137
- lastReason = reason;
138
- if (pendingTimer)
139
- return;
140
- pendingTimer = setTimeout(async () => {
141
- pendingTimer = null;
142
- try {
143
- await emitInventory(lastReason);
144
- }
145
- catch (err) {
146
- // Streaming command: emit a status event rather than crashing the process.
147
- const message = err instanceof Error ? err.message : String(err);
148
- const evt = {
149
- type: "windows.status",
150
- at: new Date().toISOString(),
151
- reason: "tmux",
152
- tmuxRunning: true,
153
- message,
154
- };
155
- this.outputNdjson([evt]);
156
- }
157
- }, debounceMs);
158
- };
159
- // Initial inventory
160
- await emitInventory("initial");
161
- // tmux control-mode client: uses notifications to trigger refresh without polling.
162
- const tmux = spawn("tmux", ["-C"], { stdio: ["pipe", "pipe", "pipe"] });
163
- // Kick control-mode to ensure it's alive; output is ignored by our notification filter.
164
- try {
165
- tmux.stdin.write("refresh-client -S\n");
166
- }
167
- catch {
168
- // ignore
169
- }
170
- const stop = (reason) => {
171
- if (stopped)
172
- return;
173
- stopped = true;
174
- if (pendingTimer) {
175
- clearTimeout(pendingTimer);
176
- pendingTimer = null;
177
- }
178
- try {
179
- tmux.kill("SIGTERM");
180
- }
181
- catch {
182
- // ignore
183
- }
184
- const evt = {
185
- type: "windows.status",
186
- at: new Date().toISOString(),
187
- reason,
188
- tmuxRunning: false,
189
- message: "stopped",
190
- };
191
- this.outputNdjson([evt]);
192
- };
193
- const onSigint = () => stop("tmux-exit");
194
- const onSigterm = () => stop("tmux-exit");
195
- process.on("SIGINT", onSigint);
196
- process.on("SIGTERM", onSigterm);
197
- return await new Promise((resolve) => {
198
- let buffer = "";
199
- tmux.stdout.on("data", (data) => {
200
- buffer += data.toString();
201
- for (;;) {
202
- const idx = buffer.indexOf("\n");
203
- if (idx === -1)
204
- break;
205
- const line = buffer.slice(0, idx).trimEnd();
206
- buffer = buffer.slice(idx + 1);
207
- if (!line)
208
- continue;
209
- if (isControlModeNotification(line)) {
210
- scheduleInventory("tmux");
211
- }
212
- }
213
- });
214
- tmux.stderr.on("data", (data) => {
215
- const message = data.toString().trim();
216
- if (!message)
217
- return;
218
- const evt = {
219
- type: "windows.status",
220
- at: new Date().toISOString(),
221
- reason: "tmux",
222
- tmuxRunning: true,
223
- message,
224
- };
225
- this.outputNdjson([evt]);
226
- });
227
- tmux.on("exit", () => {
228
- stop("tmux-exit");
229
- process.off("SIGINT", onSigint);
230
- process.off("SIGTERM", onSigterm);
231
- resolve({
232
- type: "windows.status",
233
- at: new Date().toISOString(),
234
- reason: "tmux-exit",
235
- tmuxRunning: false,
236
- message: "tmux exited",
237
- });
238
- });
239
- });
240
- }
241
- }
@@ -1,27 +0,0 @@
1
- /**
2
- * Managed abbie tmux session utilities.
3
- *
4
- * Abbie owns a dedicated tmux session where it manages project windows.
5
- * This module provides the shared primitives for creating, querying,
6
- * and managing that session.
7
- */
8
- /**
9
- * Get the managed session name (from env or default).
10
- */
11
- export declare function getManagedSessionName(): string;
12
- /**
13
- * Ensure the managed abbie tmux session exists.
14
- * Creates it (detached) if it doesn't exist yet.
15
- * Returns the session name.
16
- */
17
- export declare function ensureManagedSession(): Promise<string>;
18
- /**
19
- * List windows in the managed session.
20
- * Returns empty array if session doesn't exist.
21
- */
22
- export declare function listManagedWindows(): Promise<import("./tmux/bridge.js").TmuxWindow[]>;
23
- /**
24
- * Check if a project window already exists in the managed session.
25
- */
26
- export declare function hasProjectWindow(name: string): Promise<boolean>;
27
- //# sourceMappingURL=managed-session.d.ts.map
@@ -1,105 +0,0 @@
1
- /**
2
- * Managed abbie tmux session utilities.
3
- *
4
- * Abbie owns a dedicated tmux session where it manages project windows.
5
- * This module provides the shared primitives for creating, querying,
6
- * and managing that session.
7
- */
8
- import { spawn as spawnCmd } from "node:child_process";
9
- import { homedir } from "node:os";
10
- const DEFAULT_SESSION_NAME = "abbie";
11
- const INTERNAL_WINDOW_NAME = "_abbie";
12
- const LEGACY_SHELL_WINDOWS = new Set(["zsh", "bash", "fish", "sh"]);
13
- /**
14
- * Get the managed session name (from env or default).
15
- */
16
- export function getManagedSessionName() {
17
- return process.env.ABBIE_TMUX_SESSION ?? DEFAULT_SESSION_NAME;
18
- }
19
- /**
20
- * Ensure the managed abbie tmux session exists.
21
- * Creates it (detached) if it doesn't exist yet.
22
- * Returns the session name.
23
- */
24
- export async function ensureManagedSession() {
25
- const { isRunning, listSessions, listWindows } = await import("./tmux/bridge.js");
26
- const session = getManagedSessionName();
27
- const running = await isRunning();
28
- if (!running) {
29
- // No tmux server at all — create session (this also starts the server)
30
- await createDetachedSession(session);
31
- return session;
32
- }
33
- const sessions = await listSessions();
34
- const exists = sessions.some((s) => s.name === session);
35
- if (!exists) {
36
- await createDetachedSession(session);
37
- return session;
38
- }
39
- // Normalize legacy bootstrap windows created by older versions (e.g. `zsh` window at index 0)
40
- // so users don’t see a confusing "zsh" project when attaching to the managed session.
41
- try {
42
- const windows = await listWindows(session);
43
- const hasInternal = windows.some((w) => w.name === INTERNAL_WINDOW_NAME);
44
- const legacyBootstrap = windows.find((w) => w.index === 0 && LEGACY_SHELL_WINDOWS.has(w.name));
45
- if (!hasInternal && legacyBootstrap) {
46
- await renameWindow(session, legacyBootstrap.index, INTERNAL_WINDOW_NAME);
47
- }
48
- }
49
- catch {
50
- // Best-effort only
51
- }
52
- return session;
53
- }
54
- /**
55
- * List windows in the managed session.
56
- * Returns empty array if session doesn't exist.
57
- */
58
- export async function listManagedWindows() {
59
- const { isRunning, listSessions, listWindows } = await import("./tmux/bridge.js");
60
- const session = getManagedSessionName();
61
- if (!(await isRunning()))
62
- return [];
63
- const sessions = await listSessions();
64
- if (!sessions.some((s) => s.name === session))
65
- return [];
66
- return listWindows(session);
67
- }
68
- /**
69
- * Check if a project window already exists in the managed session.
70
- */
71
- export async function hasProjectWindow(name) {
72
- const windows = await listManagedWindows();
73
- return windows.some((w) => w.name === name);
74
- }
75
- /**
76
- * Create a detached tmux session.
77
- */
78
- async function createDetachedSession(name) {
79
- return new Promise((resolve, reject) => {
80
- const proc = spawnCmd("tmux", ["new-session", "-d", "-s", name, "-n", INTERNAL_WINDOW_NAME, "-c", homedir()], {
81
- stdio: ["ignore", "ignore", "ignore"],
82
- });
83
- proc.on("close", (code) => {
84
- if (code === 0)
85
- resolve();
86
- else
87
- reject(new Error(`Failed to create tmux session: ${name}`));
88
- });
89
- proc.on("error", reject);
90
- });
91
- }
92
- async function renameWindow(session, index, name) {
93
- await new Promise((resolve, reject) => {
94
- const proc = spawnCmd("tmux", ["rename-window", "-t", `${session}:${index}`, name], {
95
- stdio: ["ignore", "ignore", "ignore"],
96
- });
97
- proc.on("close", (code) => {
98
- if (code === 0)
99
- resolve();
100
- else
101
- reject(new Error(`Failed to rename window ${session}:${index} → ${name}`));
102
- });
103
- proc.on("error", reject);
104
- });
105
- }
@@ -1,130 +0,0 @@
1
- import { type Socket } from "node:net";
2
- /**
3
- * Panes broker protocol (local fanout).
4
- *
5
- * Transport: Unix domain socket (newline-delimited JSON).
6
- * - Client → server: control messages (subscribe/unsubscribe, ping)
7
- * - Server → client: pane snapshots + deltas + status
8
- *
9
- * Goal: enable multiple clients (TUI + tools) to subscribe without each
10
- * attaching to tmux / mutating pane state.
11
- *
12
- * This file defines the protocol + a minimal client helper. The daemon/broker
13
- * implementation lives elsewhere and can be integrated later.
14
- */
15
- export type PanesBrokerRedactionMode = "raw" | "default";
16
- export type PanesBrokerContentEncoding = "text" | "ansi";
17
- export type PanesBrokerPaneTarget = {
18
- paneId: string;
19
- ref?: string;
20
- } | {
21
- ref: string;
22
- paneId?: string;
23
- };
24
- export type PanesBrokerSubscribeOptions = {
25
- requestId?: string;
26
- target: PanesBrokerPaneTarget;
27
- redaction?: PanesBrokerRedactionMode;
28
- encoding?: PanesBrokerContentEncoding;
29
- history?: {
30
- lines: number;
31
- };
32
- follow?: boolean;
33
- };
34
- export type PanesBrokerClientHello = {
35
- type: "client.hello";
36
- at: string;
37
- clientId: string;
38
- version: 1;
39
- pid: number;
40
- };
41
- export type PanesBrokerSubscribe = {
42
- type: "panes.subscribe";
43
- at: string;
44
- requestId: string;
45
- target: PanesBrokerPaneTarget;
46
- redaction: PanesBrokerRedactionMode;
47
- encoding: PanesBrokerContentEncoding;
48
- history?: {
49
- lines: number;
50
- };
51
- follow: boolean;
52
- };
53
- export type PanesBrokerUnsubscribe = {
54
- type: "panes.unsubscribe";
55
- at: string;
56
- requestId: string;
57
- };
58
- export type PanesBrokerPing = {
59
- type: "client.ping";
60
- at: string;
61
- nonce: string;
62
- };
63
- export type PanesBrokerClientMessage = PanesBrokerClientHello | PanesBrokerSubscribe | PanesBrokerUnsubscribe | PanesBrokerPing;
64
- export type PanesBrokerServerHello = {
65
- type: "broker.hello";
66
- at: string;
67
- version: 1;
68
- pid: number;
69
- };
70
- export type PanesBrokerPong = {
71
- type: "broker.pong";
72
- at: string;
73
- nonce: string;
74
- };
75
- export type PanesBrokerPanesSnapshot = {
76
- type: "panes.snapshot";
77
- at: string;
78
- requestId: string;
79
- paneId: string;
80
- ref?: string;
81
- encoding: PanesBrokerContentEncoding;
82
- redaction: PanesBrokerRedactionMode;
83
- cols?: number;
84
- rows?: number;
85
- truncated?: boolean;
86
- content: string;
87
- };
88
- export type PanesBrokerPanesDelta = {
89
- type: "panes.delta";
90
- at: string;
91
- requestId: string;
92
- paneId: string;
93
- ref?: string;
94
- encoding: PanesBrokerContentEncoding;
95
- redaction: PanesBrokerRedactionMode;
96
- chunk: string;
97
- };
98
- export type PanesBrokerPanesStatus = {
99
- type: "panes.status";
100
- at: string;
101
- requestId?: string;
102
- paneId?: string;
103
- level: "info" | "warn" | "error";
104
- message: string;
105
- };
106
- export type PanesBrokerServerMessage = PanesBrokerServerHello | PanesBrokerPong | PanesBrokerPanesSnapshot | PanesBrokerPanesDelta | PanesBrokerPanesStatus;
107
- export type PanesBrokerConnectOptions = {
108
- socketPath?: string;
109
- };
110
- export declare function getDefaultPanesBrokerSocketPath(): string;
111
- export type LineParser<T> = {
112
- pushChunk: (chunk: Buffer | string) => void;
113
- onMessage: (fn: (msg: T) => void) => void;
114
- onError: (fn: (err: Error) => void) => void;
115
- };
116
- export declare function createNdjsonLineParser<T>(): LineParser<T>;
117
- export type PanesBrokerClient = {
118
- socket: Socket;
119
- clientId: string;
120
- send: (msg: PanesBrokerClientMessage) => void;
121
- subscribe: (opts: PanesBrokerSubscribeOptions) => string;
122
- unsubscribe: (requestId: string) => void;
123
- ping: () => string;
124
- };
125
- export declare function connectPanesBroker(opts?: PanesBrokerConnectOptions, handlers?: {
126
- onMessage?: (msg: PanesBrokerServerMessage) => void;
127
- onError?: (err: Error) => void;
128
- onClose?: () => void;
129
- }): PanesBrokerClient;
130
- //# sourceMappingURL=broker.d.ts.map