abmux 0.0.4 → 0.0.5
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/dist/cli/index.js +181 -184
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -178,15 +178,6 @@ var PANE_KIND = {
|
|
|
178
178
|
busy: "busy"
|
|
179
179
|
};
|
|
180
180
|
|
|
181
|
-
// src/utils/PathUtils.ts
|
|
182
|
-
var formatCwd = (cwd) => {
|
|
183
|
-
const home = process.env["HOME"] ?? "";
|
|
184
|
-
if (home && cwd.startsWith(home)) {
|
|
185
|
-
return `~${cwd.slice(home.length)}`;
|
|
186
|
-
}
|
|
187
|
-
return cwd;
|
|
188
|
-
};
|
|
189
|
-
|
|
190
181
|
// src/services/session-detection-service.ts
|
|
191
182
|
var BUSY_TITLES = /* @__PURE__ */ new Set([
|
|
192
183
|
"nvim",
|
|
@@ -252,66 +243,44 @@ var toUnifiedPane = (pane) => {
|
|
|
252
243
|
var createSessionDetectionService = () => ({
|
|
253
244
|
groupBySession: ({ panes }) => {
|
|
254
245
|
const windowKey = (pane) => `${pane.sessionName}:${String(pane.windowIndex)}`;
|
|
255
|
-
const
|
|
256
|
-
|
|
257
|
-
const
|
|
258
|
-
const
|
|
259
|
-
|
|
260
|
-
if (
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
activePaneTitle: pane.isActive ? pane.title : "",
|
|
272
|
-
panes: [unified]
|
|
273
|
-
});
|
|
246
|
+
const panesByWindow = Map.groupBy(panes, windowKey);
|
|
247
|
+
const sortPanes = (items) => items.toSorted((a, b) => {
|
|
248
|
+
const kindOrder = { claude: 0, available: 1, busy: 2 };
|
|
249
|
+
const kindDiff = kindOrder[a.kind] - kindOrder[b.kind];
|
|
250
|
+
if (kindDiff !== 0) return kindDiff;
|
|
251
|
+
if (a.kind === "claude" && b.kind === "claude") {
|
|
252
|
+
const statusOrder = {
|
|
253
|
+
"waiting-confirm": 0,
|
|
254
|
+
"waiting-input": 1,
|
|
255
|
+
thinking: 2,
|
|
256
|
+
"tool-running": 3,
|
|
257
|
+
idle: 4
|
|
258
|
+
};
|
|
259
|
+
const sa = statusOrder[a.claudeStatus ?? "idle"] ?? 4;
|
|
260
|
+
const sb = statusOrder[b.claudeStatus ?? "idle"] ?? 4;
|
|
261
|
+
if (sa !== sb) return sa - sb;
|
|
274
262
|
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
}
|
|
296
|
-
return a.pane.paneIndex - b.pane.paneIndex;
|
|
297
|
-
})
|
|
263
|
+
return a.pane.paneIndex - b.pane.paneIndex;
|
|
264
|
+
});
|
|
265
|
+
const windowGroups = [...panesByWindow.entries()].toSorted(([a], [b]) => a.localeCompare(b)).map(([, group]) => {
|
|
266
|
+
const first = group[0];
|
|
267
|
+
const activePaneTitle = group.find((p) => p.isActive)?.title ?? "";
|
|
268
|
+
return {
|
|
269
|
+
windowIndex: first.windowIndex,
|
|
270
|
+
windowName: first.windowName || activePaneTitle || `Window ${String(first.windowIndex)}`,
|
|
271
|
+
sessionName: first.sessionName,
|
|
272
|
+
panes: sortPanes(group.map(toUnifiedPane))
|
|
273
|
+
};
|
|
274
|
+
});
|
|
275
|
+
const sessionGroups = Map.groupBy(windowGroups, (win) => win.sessionName);
|
|
276
|
+
return [...sessionGroups.entries()].map(([sessionName, wins]) => ({
|
|
277
|
+
sessionName,
|
|
278
|
+
tabs: wins.map(({ windowIndex, windowName, panes: p }) => ({
|
|
279
|
+
windowIndex,
|
|
280
|
+
windowName,
|
|
281
|
+
panes: p
|
|
282
|
+
}))
|
|
298
283
|
}));
|
|
299
|
-
const sessionMap = /* @__PURE__ */ new Map();
|
|
300
|
-
for (const win of windowGroups) {
|
|
301
|
-
const existing = sessionMap.get(win.sessionName);
|
|
302
|
-
if (existing) {
|
|
303
|
-
existing.push({
|
|
304
|
-
windowIndex: win.windowIndex,
|
|
305
|
-
windowName: win.windowName,
|
|
306
|
-
panes: win.panes
|
|
307
|
-
});
|
|
308
|
-
} else {
|
|
309
|
-
sessionMap.set(win.sessionName, [
|
|
310
|
-
{ windowIndex: win.windowIndex, windowName: win.windowName, panes: win.panes }
|
|
311
|
-
]);
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
return [...sessionMap.entries()].map(([sessionName, tabs]) => ({ sessionName, tabs }));
|
|
315
284
|
},
|
|
316
285
|
detectStatusFromText
|
|
317
286
|
});
|
|
@@ -396,24 +365,15 @@ var findProjects = async (dir, depth) => {
|
|
|
396
365
|
const dirs = entries.filter(
|
|
397
366
|
(e) => e.isDirectory() && !e.name.startsWith(".") && !SKIP_DIRS.has(e.name)
|
|
398
367
|
);
|
|
399
|
-
const
|
|
400
|
-
const childScans = [];
|
|
401
|
-
for (const entry of dirs) {
|
|
368
|
+
const childScans = dirs.map((entry) => {
|
|
402
369
|
const fullPath = join2(dir, entry.name);
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
);
|
|
409
|
-
}
|
|
370
|
+
return exists(join2(fullPath, ".git")).then(async (isProject) => {
|
|
371
|
+
if (isProject) return [fullPath];
|
|
372
|
+
return await findProjects(fullPath, depth + 1);
|
|
373
|
+
});
|
|
374
|
+
});
|
|
410
375
|
const nested = await Promise.all(childScans);
|
|
411
|
-
|
|
412
|
-
for (const p of paths) {
|
|
413
|
-
results.push(p);
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
return results;
|
|
376
|
+
return nested.flat();
|
|
417
377
|
} catch {
|
|
418
378
|
return [];
|
|
419
379
|
}
|
|
@@ -507,7 +467,7 @@ var createUsecases = (context) => ({
|
|
|
507
467
|
// package.json
|
|
508
468
|
var package_default = {
|
|
509
469
|
name: "abmux",
|
|
510
|
-
version: "0.0.
|
|
470
|
+
version: "0.0.5",
|
|
511
471
|
repository: {
|
|
512
472
|
type: "git",
|
|
513
473
|
url: "https://github.com/cut0/abmux.git"
|
|
@@ -618,17 +578,29 @@ var useScroll = (cursor, totalItems, availableRows) => {
|
|
|
618
578
|
}, [cursor, totalItems, availableRows]);
|
|
619
579
|
};
|
|
620
580
|
|
|
581
|
+
// src/utils/PathUtils.ts
|
|
582
|
+
var formatCwd = (cwd) => {
|
|
583
|
+
const home = process.env["HOME"] ?? "";
|
|
584
|
+
if (home && cwd.startsWith(home)) {
|
|
585
|
+
return `~${cwd.slice(home.length)}`;
|
|
586
|
+
}
|
|
587
|
+
return cwd;
|
|
588
|
+
};
|
|
589
|
+
var findMatchingDirectory = (path, directories) => directories.filter((dir) => path === dir || path.startsWith(dir + "/")).reduce(
|
|
590
|
+
(best, dir) => !best || dir.length > best.length ? dir : best,
|
|
591
|
+
void 0
|
|
592
|
+
);
|
|
593
|
+
|
|
621
594
|
// src/components/shared/DirectorySelect.tsx
|
|
622
595
|
import { jsx as jsx3, jsxs } from "react/jsx-runtime";
|
|
623
|
-
var
|
|
624
|
-
const current =
|
|
625
|
-
const rest =
|
|
596
|
+
var sortSessions = (sessions, currentSession) => {
|
|
597
|
+
const current = sessions.filter((s) => s.name === currentSession);
|
|
598
|
+
const rest = sessions.filter((s) => s.name !== currentSession);
|
|
626
599
|
return [...current, ...rest];
|
|
627
600
|
};
|
|
628
601
|
var SessionListPanel = ({
|
|
629
|
-
|
|
602
|
+
sessions,
|
|
630
603
|
currentSession,
|
|
631
|
-
sessionPathMap,
|
|
632
604
|
isFocused,
|
|
633
605
|
availableRows,
|
|
634
606
|
onSelect,
|
|
@@ -638,30 +610,30 @@ var SessionListPanel = ({
|
|
|
638
610
|
}) => {
|
|
639
611
|
const { exit } = useApp();
|
|
640
612
|
const [cursor, setCursor] = useState(0);
|
|
641
|
-
const
|
|
642
|
-
() =>
|
|
643
|
-
[
|
|
613
|
+
const sortedSessions = useMemo2(
|
|
614
|
+
() => sortSessions(sessions, currentSession),
|
|
615
|
+
[sessions, currentSession]
|
|
644
616
|
);
|
|
645
|
-
const
|
|
646
|
-
const clampedCursor = cursor >=
|
|
617
|
+
const names = useMemo2(() => sortedSessions.map((s) => s.name), [sortedSessions]);
|
|
618
|
+
const clampedCursor = cursor >= names.length ? Math.max(0, names.length - 1) : cursor;
|
|
647
619
|
if (clampedCursor !== cursor) {
|
|
648
620
|
setCursor(clampedCursor);
|
|
649
621
|
}
|
|
650
622
|
const reservedLines = 1;
|
|
651
623
|
const { scrollOffset, visibleCount } = useScroll(
|
|
652
624
|
clampedCursor,
|
|
653
|
-
|
|
625
|
+
names.length,
|
|
654
626
|
availableRows - reservedLines
|
|
655
627
|
);
|
|
656
|
-
const visibleSessions =
|
|
628
|
+
const visibleSessions = sortedSessions.slice(scrollOffset, scrollOffset + visibleCount);
|
|
657
629
|
const moveCursor = useCallback(
|
|
658
630
|
(next) => {
|
|
659
|
-
const clamped = Math.max(0, Math.min(
|
|
631
|
+
const clamped = Math.max(0, Math.min(names.length - 1, next));
|
|
660
632
|
setCursor(clamped);
|
|
661
|
-
const name =
|
|
633
|
+
const name = names[clamped];
|
|
662
634
|
if (name) onCursorChange(name);
|
|
663
635
|
},
|
|
664
|
-
[
|
|
636
|
+
[names, onCursorChange]
|
|
665
637
|
);
|
|
666
638
|
useInput(
|
|
667
639
|
(input, key) => {
|
|
@@ -678,12 +650,12 @@ var SessionListPanel = ({
|
|
|
678
650
|
return;
|
|
679
651
|
}
|
|
680
652
|
if (key.return || key.rightArrow) {
|
|
681
|
-
const name =
|
|
653
|
+
const name = names[clampedCursor];
|
|
682
654
|
if (name) onSelect(name);
|
|
683
655
|
return;
|
|
684
656
|
}
|
|
685
657
|
if (input === "d" && onDeleteSession) {
|
|
686
|
-
const name =
|
|
658
|
+
const name = names[clampedCursor];
|
|
687
659
|
if (name) onDeleteSession(name);
|
|
688
660
|
return;
|
|
689
661
|
}
|
|
@@ -701,20 +673,19 @@ var SessionListPanel = ({
|
|
|
701
673
|
"(",
|
|
702
674
|
clampedCursor + 1,
|
|
703
675
|
"/",
|
|
704
|
-
|
|
676
|
+
names.length,
|
|
705
677
|
")"
|
|
706
678
|
] })
|
|
707
679
|
] }),
|
|
708
|
-
/* @__PURE__ */ jsx3(Box3, { flexDirection: "column", flexGrow: 1, overflow: "hidden", children: visibleSessions.map((
|
|
680
|
+
/* @__PURE__ */ jsx3(Box3, { flexDirection: "column", flexGrow: 1, overflow: "hidden", children: visibleSessions.map((session, i) => {
|
|
709
681
|
const globalIndex = scrollOffset + i;
|
|
710
682
|
const isHighlighted = globalIndex === clampedCursor;
|
|
711
|
-
const isCurrent = name === currentSession;
|
|
712
|
-
const path = sessionPathMap.get(name);
|
|
683
|
+
const isCurrent = session.name === currentSession;
|
|
713
684
|
return /* @__PURE__ */ jsxs(Box3, { paddingLeft: 1, gap: 1, children: [
|
|
714
685
|
/* @__PURE__ */ jsx3(Text3, { color: isHighlighted ? "green" : void 0, children: isHighlighted ? "\u25B6" : " " }),
|
|
715
|
-
/* @__PURE__ */ jsx3(Text3, { color: isHighlighted ? "green" : "cyan", bold: isHighlighted, wrap: "truncate", children: path ? formatCwd(path) : name }),
|
|
686
|
+
/* @__PURE__ */ jsx3(Text3, { color: isHighlighted ? "green" : "cyan", bold: isHighlighted, wrap: "truncate", children: session.path ? formatCwd(session.path) : session.name }),
|
|
716
687
|
isCurrent && /* @__PURE__ */ jsx3(Text3, { color: "yellow", children: "(cwd)" })
|
|
717
|
-
] }, name);
|
|
688
|
+
] }, session.name);
|
|
718
689
|
}) })
|
|
719
690
|
] });
|
|
720
691
|
};
|
|
@@ -1122,14 +1093,16 @@ var POLL_INTERVAL = 3e3;
|
|
|
1122
1093
|
var ManagerView = ({
|
|
1123
1094
|
actions,
|
|
1124
1095
|
currentSession,
|
|
1125
|
-
currentCwd,
|
|
1126
1096
|
directories,
|
|
1127
|
-
sessionCwdMap,
|
|
1128
1097
|
restoredPrompt,
|
|
1129
|
-
restoredSession
|
|
1098
|
+
restoredSession,
|
|
1099
|
+
restoredCwd
|
|
1130
1100
|
}) => {
|
|
1131
1101
|
const { rows, columns } = useTerminalSize();
|
|
1132
|
-
const [
|
|
1102
|
+
const [sessionsState, setSessionsState] = useState5({
|
|
1103
|
+
sessions: [],
|
|
1104
|
+
isLoading: true
|
|
1105
|
+
});
|
|
1133
1106
|
const [mode, setMode] = useState5(restoredPrompt ? MODE.confirm : MODE.split);
|
|
1134
1107
|
const [focus, setFocus] = useState5(FOCUS.left);
|
|
1135
1108
|
const [selectedSession, setSelectedSession] = useState5(restoredSession);
|
|
@@ -1137,17 +1110,16 @@ var ManagerView = ({
|
|
|
1137
1110
|
const [pendingDeleteSession, setPendingDeleteSession] = useState5(void 0);
|
|
1138
1111
|
const refresh = useCallback3(async () => {
|
|
1139
1112
|
try {
|
|
1140
|
-
const
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
}
|
|
1147
|
-
}
|
|
1148
|
-
setFetchState({ data: [...missing, ...groups], isLoading: false });
|
|
1113
|
+
const fetched = await actions.fetchSessions();
|
|
1114
|
+
setSessionsState((prev) => {
|
|
1115
|
+
const fetchedNames = new Set(fetched.map((s) => s.name));
|
|
1116
|
+
const userOnly = prev.sessions.filter(
|
|
1117
|
+
(s) => !fetchedNames.has(s.name) && s.groups.length === 0
|
|
1118
|
+
);
|
|
1119
|
+
return { sessions: [...userOnly, ...fetched], isLoading: false };
|
|
1120
|
+
});
|
|
1149
1121
|
} catch {
|
|
1150
|
-
|
|
1122
|
+
setSessionsState((prev) => ({ ...prev, isLoading: false }));
|
|
1151
1123
|
}
|
|
1152
1124
|
}, [actions]);
|
|
1153
1125
|
useEffect2(() => {
|
|
@@ -1159,40 +1131,34 @@ var ManagerView = ({
|
|
|
1159
1131
|
clearInterval(timer);
|
|
1160
1132
|
};
|
|
1161
1133
|
}, [refresh]);
|
|
1162
|
-
const resolvedSession = selectedSession ??
|
|
1163
|
-
const
|
|
1164
|
-
() =>
|
|
1165
|
-
[
|
|
1134
|
+
const resolvedSession = selectedSession ?? sessionsState.sessions[0]?.name;
|
|
1135
|
+
const selectedManagedSession = useMemo5(
|
|
1136
|
+
() => sessionsState.sessions.find((s) => s.name === resolvedSession),
|
|
1137
|
+
[sessionsState.sessions, resolvedSession]
|
|
1166
1138
|
);
|
|
1167
|
-
const
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
}
|
|
1175
|
-
return map;
|
|
1176
|
-
}, [fetchState.data]);
|
|
1139
|
+
const selectedGroup = useMemo5(() => {
|
|
1140
|
+
if (!selectedManagedSession) return void 0;
|
|
1141
|
+
return {
|
|
1142
|
+
sessionName: selectedManagedSession.name,
|
|
1143
|
+
tabs: selectedManagedSession.groups.flatMap((g) => g.tabs)
|
|
1144
|
+
};
|
|
1145
|
+
}, [selectedManagedSession]);
|
|
1177
1146
|
const handleOpenAddSession = useCallback3(() => {
|
|
1178
1147
|
setMode(MODE.addSession);
|
|
1179
1148
|
}, []);
|
|
1180
|
-
const handleAddSessionSelect = useCallback3(
|
|
1181
|
-
(path)
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
},
|
|
1194
|
-
[fetchState.data]
|
|
1195
|
-
);
|
|
1149
|
+
const handleAddSessionSelect = useCallback3((path) => {
|
|
1150
|
+
const name = basename2(path);
|
|
1151
|
+
setSessionsState((prev) => {
|
|
1152
|
+
const exists2 = prev.sessions.some((s) => s.name === name);
|
|
1153
|
+
if (exists2) return prev;
|
|
1154
|
+
return {
|
|
1155
|
+
...prev,
|
|
1156
|
+
sessions: [{ name, path, groups: [] }, ...prev.sessions]
|
|
1157
|
+
};
|
|
1158
|
+
});
|
|
1159
|
+
setSelectedSession(name);
|
|
1160
|
+
setMode(MODE.split);
|
|
1161
|
+
}, []);
|
|
1196
1162
|
const handleCancelAddSession = useCallback3(() => {
|
|
1197
1163
|
setMode(MODE.split);
|
|
1198
1164
|
}, []);
|
|
@@ -1202,32 +1168,43 @@ var ManagerView = ({
|
|
|
1202
1168
|
}, []);
|
|
1203
1169
|
const handleConfirmDelete = useCallback3(() => {
|
|
1204
1170
|
if (!pendingDeleteSession) return;
|
|
1205
|
-
|
|
1171
|
+
const session = sessionsState.sessions.find((s) => s.name === pendingDeleteSession);
|
|
1172
|
+
setSessionsState((prev) => ({
|
|
1173
|
+
...prev,
|
|
1174
|
+
sessions: prev.sessions.filter((s) => s.name !== pendingDeleteSession)
|
|
1175
|
+
}));
|
|
1206
1176
|
if (resolvedSession === pendingDeleteSession) {
|
|
1207
1177
|
setSelectedSession(void 0);
|
|
1208
1178
|
}
|
|
1209
|
-
|
|
1179
|
+
if (session) {
|
|
1180
|
+
const killAll = Promise.all(
|
|
1181
|
+
session.groups.map((g) => swallow(() => actions.killSession(g.sessionName)))
|
|
1182
|
+
);
|
|
1183
|
+
void killAll.then(() => void refresh());
|
|
1184
|
+
}
|
|
1210
1185
|
setPendingDeleteSession(void 0);
|
|
1211
1186
|
setMode(MODE.split);
|
|
1212
|
-
}, [pendingDeleteSession, resolvedSession, actions, refresh]);
|
|
1187
|
+
}, [pendingDeleteSession, resolvedSession, sessionsState.sessions, actions, refresh]);
|
|
1213
1188
|
const handleCancelDelete = useCallback3(() => {
|
|
1214
1189
|
setPendingDeleteSession(void 0);
|
|
1215
1190
|
setMode(MODE.split);
|
|
1216
1191
|
}, []);
|
|
1217
1192
|
const handleNewSession = useCallback3(
|
|
1218
1193
|
(sessionName) => {
|
|
1219
|
-
|
|
1194
|
+
const cwd = selectedManagedSession?.path;
|
|
1195
|
+
if (!cwd) return;
|
|
1196
|
+
actions.openEditor(sessionName, cwd);
|
|
1220
1197
|
},
|
|
1221
|
-
[actions]
|
|
1198
|
+
[actions, selectedManagedSession]
|
|
1222
1199
|
);
|
|
1223
1200
|
const handleConfirmNew = useCallback3(() => {
|
|
1224
1201
|
if (!resolvedSession) return;
|
|
1225
|
-
const
|
|
1226
|
-
|
|
1202
|
+
const cwd = restoredCwd ?? selectedManagedSession?.path;
|
|
1203
|
+
if (!cwd) return;
|
|
1227
1204
|
void actions.createSession(resolvedSession, cwd, pendingPrompt).then(() => void refresh());
|
|
1228
1205
|
setPendingPrompt("");
|
|
1229
1206
|
setMode(MODE.split);
|
|
1230
|
-
}, [resolvedSession,
|
|
1207
|
+
}, [resolvedSession, restoredCwd, selectedManagedSession, pendingPrompt, actions, refresh]);
|
|
1231
1208
|
const handleCancelConfirm = useCallback3(() => {
|
|
1232
1209
|
setPendingPrompt("");
|
|
1233
1210
|
setMode(MODE.split);
|
|
@@ -1267,7 +1244,7 @@ var ManagerView = ({
|
|
|
1267
1244
|
},
|
|
1268
1245
|
[actions]
|
|
1269
1246
|
);
|
|
1270
|
-
if (
|
|
1247
|
+
if (sessionsState.isLoading) {
|
|
1271
1248
|
return /* @__PURE__ */ jsxs7(Box10, { flexDirection: "column", height: rows, children: [
|
|
1272
1249
|
/* @__PURE__ */ jsx10(Header, { title: `${APP_TITLE} v${APP_VERSION}` }),
|
|
1273
1250
|
/* @__PURE__ */ jsx10(StatusBar, { message: "Loading...", type: "info" })
|
|
@@ -1284,8 +1261,11 @@ var ManagerView = ({
|
|
|
1284
1261
|
);
|
|
1285
1262
|
}
|
|
1286
1263
|
if (mode === MODE.deleteSession && pendingDeleteSession) {
|
|
1287
|
-
const
|
|
1288
|
-
const paneCount =
|
|
1264
|
+
const deleteSession = sessionsState.sessions.find((s) => s.name === pendingDeleteSession);
|
|
1265
|
+
const paneCount = deleteSession?.groups.reduce(
|
|
1266
|
+
(sum, g) => sum + g.tabs.reduce((s, t) => s + t.panes.length, 0),
|
|
1267
|
+
0
|
|
1268
|
+
) ?? 0;
|
|
1289
1269
|
return /* @__PURE__ */ jsx10(
|
|
1290
1270
|
DeleteSessionView,
|
|
1291
1271
|
{
|
|
@@ -1323,9 +1303,8 @@ var ManagerView = ({
|
|
|
1323
1303
|
children: /* @__PURE__ */ jsx10(
|
|
1324
1304
|
SessionListPanel,
|
|
1325
1305
|
{
|
|
1326
|
-
|
|
1306
|
+
sessions: sessionsState.sessions,
|
|
1327
1307
|
currentSession,
|
|
1328
|
-
sessionPathMap,
|
|
1329
1308
|
isFocused: focus === FOCUS.left,
|
|
1330
1309
|
availableRows: panelHeight,
|
|
1331
1310
|
onSelect: handleSessionSelect,
|
|
@@ -1368,25 +1347,38 @@ var ManagerView = ({
|
|
|
1368
1347
|
// src/cli/tui-command.ts
|
|
1369
1348
|
var createTuiCommand = ({ usecases, services, infra }) => async () => {
|
|
1370
1349
|
const directories = await services.directoryScan.scan();
|
|
1371
|
-
const sessionCwdMap = /* @__PURE__ */ new Map();
|
|
1372
1350
|
let instance;
|
|
1373
1351
|
let pendingPrompt;
|
|
1374
1352
|
let pendingSession;
|
|
1353
|
+
let pendingCwd;
|
|
1375
1354
|
const actions = {
|
|
1376
1355
|
fetchSessions: async () => {
|
|
1377
1356
|
const result = await usecases.manager.list();
|
|
1378
|
-
|
|
1379
|
-
result.sessionGroups.map(async (group) =>
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1357
|
+
const resolved = await Promise.all(
|
|
1358
|
+
result.sessionGroups.map(async (group) => {
|
|
1359
|
+
const enrichedGroup = {
|
|
1360
|
+
sessionName: group.sessionName,
|
|
1361
|
+
tabs: await Promise.all(
|
|
1362
|
+
group.tabs.map(async (tab) => ({
|
|
1363
|
+
windowIndex: tab.windowIndex,
|
|
1364
|
+
windowName: tab.windowName,
|
|
1365
|
+
panes: await Promise.all(
|
|
1366
|
+
tab.panes.map((up) => usecases.manager.enrichStatus(up))
|
|
1367
|
+
)
|
|
1368
|
+
}))
|
|
1369
|
+
)
|
|
1370
|
+
};
|
|
1371
|
+
const paneCwd = group.tabs[0]?.panes[0]?.pane.cwd ?? "";
|
|
1372
|
+
const path = findMatchingDirectory(paneCwd, directories) ?? paneCwd;
|
|
1373
|
+
return { path, group: enrichedGroup };
|
|
1374
|
+
})
|
|
1389
1375
|
);
|
|
1376
|
+
const grouped = Map.groupBy(resolved, (item) => item.path || item.group.sessionName);
|
|
1377
|
+
return [...grouped.entries()].map(([key, items]) => ({
|
|
1378
|
+
name: basename3(key) || items[0].group.sessionName,
|
|
1379
|
+
path: items[0].path,
|
|
1380
|
+
groups: items.map((item) => item.group)
|
|
1381
|
+
}));
|
|
1390
1382
|
},
|
|
1391
1383
|
createSession: async (sessionName, cwd, prompt) => {
|
|
1392
1384
|
await usecases.manager.createSession({ sessionName, cwd, prompt });
|
|
@@ -1403,11 +1395,12 @@ var createTuiCommand = ({ usecases, services, infra }) => async () => {
|
|
|
1403
1395
|
unhighlightWindow: async (up) => {
|
|
1404
1396
|
await usecases.manager.unhighlightWindow(up);
|
|
1405
1397
|
},
|
|
1406
|
-
openEditor: (sessionName) => {
|
|
1398
|
+
openEditor: (sessionName, cwd) => {
|
|
1407
1399
|
instance.unmount();
|
|
1408
1400
|
const prompt = infra.editor.open();
|
|
1409
1401
|
pendingPrompt = prompt;
|
|
1410
1402
|
pendingSession = sessionName;
|
|
1403
|
+
pendingCwd = cwd;
|
|
1411
1404
|
instance = renderApp();
|
|
1412
1405
|
return prompt;
|
|
1413
1406
|
},
|
|
@@ -1423,17 +1416,20 @@ var createTuiCommand = ({ usecases, services, infra }) => async () => {
|
|
|
1423
1416
|
const renderApp = () => {
|
|
1424
1417
|
const prompt = pendingPrompt;
|
|
1425
1418
|
const session = pendingSession;
|
|
1419
|
+
const cwd = pendingCwd;
|
|
1426
1420
|
pendingPrompt = void 0;
|
|
1427
1421
|
pendingSession = void 0;
|
|
1422
|
+
pendingCwd = void 0;
|
|
1423
|
+
const rawCwd = process.cwd();
|
|
1424
|
+
const currentSession = basename3(findMatchingDirectory(rawCwd, directories) ?? rawCwd);
|
|
1428
1425
|
return render(
|
|
1429
1426
|
createElement(ManagerView, {
|
|
1430
1427
|
actions,
|
|
1431
|
-
currentSession
|
|
1432
|
-
currentCwd: process.cwd(),
|
|
1428
|
+
currentSession,
|
|
1433
1429
|
directories,
|
|
1434
|
-
sessionCwdMap,
|
|
1435
1430
|
restoredPrompt: prompt,
|
|
1436
|
-
restoredSession: session
|
|
1431
|
+
restoredSession: session,
|
|
1432
|
+
restoredCwd: cwd
|
|
1437
1433
|
}),
|
|
1438
1434
|
{ concurrent: true }
|
|
1439
1435
|
);
|
|
@@ -1491,10 +1487,11 @@ var createListCommand = ({ usecases }) => async () => {
|
|
|
1491
1487
|
console.log("No sessions found.");
|
|
1492
1488
|
return;
|
|
1493
1489
|
}
|
|
1494
|
-
|
|
1490
|
+
const lines = result.sessionGroups.map((group) => {
|
|
1495
1491
|
const paneCount = group.tabs.reduce((sum, t) => sum + t.panes.length, 0);
|
|
1496
|
-
|
|
1497
|
-
}
|
|
1492
|
+
return `${group.sessionName} (${String(paneCount)} panes)`;
|
|
1493
|
+
});
|
|
1494
|
+
console.log(lines.join("\n"));
|
|
1498
1495
|
};
|
|
1499
1496
|
|
|
1500
1497
|
// src/cli/index.ts
|