zdev 0.2.3 → 0.2.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/index.js +37 -3
- package/package.json +1 -1
- package/src/commands/list.ts +58 -5
package/dist/index.js
CHANGED
|
@@ -2764,6 +2764,20 @@ Run 'zdev list' to see active features`);
|
|
|
2764
2764
|
|
|
2765
2765
|
// src/commands/list.ts
|
|
2766
2766
|
import { existsSync as existsSync6 } from "fs";
|
|
2767
|
+
function getTmuxSessions(pattern) {
|
|
2768
|
+
const socketDir = process.env.CLAWDBOT_TMUX_SOCKET_DIR || "/tmp/clawdbot-tmux-sockets";
|
|
2769
|
+
const socket = `${socketDir}/clawdbot.sock`;
|
|
2770
|
+
let result = run("tmux", ["-S", socket, "list-sessions", "-F", "#{session_name}"]);
|
|
2771
|
+
if (!result.success) {
|
|
2772
|
+
result = run("tmux", ["list-sessions", "-F", "#{session_name}"]);
|
|
2773
|
+
}
|
|
2774
|
+
if (!result.success)
|
|
2775
|
+
return [];
|
|
2776
|
+
const sessions = result.stdout.split(`
|
|
2777
|
+
`).filter(Boolean);
|
|
2778
|
+
const patternWords = pattern.split("-").filter((w) => w.length > 2);
|
|
2779
|
+
return sessions.filter((name) => patternWords.some((word) => name.toLowerCase().includes(word.toLowerCase())));
|
|
2780
|
+
}
|
|
2767
2781
|
async function list(options = {}) {
|
|
2768
2782
|
const config = loadConfig();
|
|
2769
2783
|
const allocations = Object.entries(config.allocations);
|
|
@@ -2798,7 +2812,20 @@ No active features.
|
|
|
2798
2812
|
const worktreeExists = existsSync6(worktreePath);
|
|
2799
2813
|
const frontendRunning = alloc.pids.frontend ? isProcessRunning(alloc.pids.frontend) : false;
|
|
2800
2814
|
const convexRunning = alloc.pids.convex ? isProcessRunning(alloc.pids.convex) : false;
|
|
2801
|
-
const
|
|
2815
|
+
const featureSlug = name.toLowerCase().replace(/[^a-z0-9]/g, "-");
|
|
2816
|
+
const projectSlug = alloc.project.toLowerCase().replace(/[^a-z0-9]/g, "-");
|
|
2817
|
+
const featureOnly = alloc.branch.replace("feature/", "").toLowerCase().replace(/[^a-z0-9]/g, "-");
|
|
2818
|
+
let tmuxSessions = getTmuxSessions(featureSlug);
|
|
2819
|
+
if (tmuxSessions.length === 0) {
|
|
2820
|
+
tmuxSessions = getTmuxSessions(projectSlug);
|
|
2821
|
+
}
|
|
2822
|
+
if (tmuxSessions.length === 0 && featureOnly !== projectSlug) {
|
|
2823
|
+
tmuxSessions = getTmuxSessions(featureOnly);
|
|
2824
|
+
}
|
|
2825
|
+
const hasTmux = tmuxSessions.length > 0;
|
|
2826
|
+
const isRunning = frontendRunning || convexRunning || hasTmux;
|
|
2827
|
+
const isFullyRunning = frontendRunning && convexRunning || hasTmux && tmuxSessions.length >= 2;
|
|
2828
|
+
const statusEmoji = isFullyRunning ? "\uD83D\uDFE2" : isRunning ? "\uD83D\uDFE1" : "\uD83D\uDD34";
|
|
2802
2829
|
console.log(`${statusEmoji} ${name}`);
|
|
2803
2830
|
console.log(` Project: ${alloc.project}`);
|
|
2804
2831
|
console.log(` Branch: ${alloc.branch}`);
|
|
@@ -2807,8 +2834,15 @@ No active features.
|
|
|
2807
2834
|
if (alloc.funnelPath && traefikStatus.devDomain) {
|
|
2808
2835
|
console.log(` Public: https://${alloc.funnelPath}.${traefikStatus.devDomain}`);
|
|
2809
2836
|
}
|
|
2810
|
-
|
|
2811
|
-
|
|
2837
|
+
if (alloc.pids.frontend || alloc.pids.convex) {
|
|
2838
|
+
console.log(` Frontend: ${frontendRunning ? `running (PID: ${alloc.pids.frontend})` : "stopped"}`);
|
|
2839
|
+
console.log(` Convex: ${convexRunning ? `running (PID: ${alloc.pids.convex})` : "stopped"}`);
|
|
2840
|
+
}
|
|
2841
|
+
if (hasTmux) {
|
|
2842
|
+
console.log(` Tmux: ${tmuxSessions.join(", ")}`);
|
|
2843
|
+
} else if (!frontendRunning && !convexRunning) {
|
|
2844
|
+
console.log(` Servers: stopped`);
|
|
2845
|
+
}
|
|
2812
2846
|
console.log(` Started: ${new Date(alloc.started).toLocaleString()}`);
|
|
2813
2847
|
console.log();
|
|
2814
2848
|
}
|
package/package.json
CHANGED
package/src/commands/list.ts
CHANGED
|
@@ -5,7 +5,32 @@ import {
|
|
|
5
5
|
ZEBU_HOME,
|
|
6
6
|
WORKTREES_DIR,
|
|
7
7
|
} from "../config.js";
|
|
8
|
-
import { isProcessRunning, getTraefikStatus } from "../utils.js";
|
|
8
|
+
import { isProcessRunning, getTraefikStatus, run } from "../utils.js";
|
|
9
|
+
|
|
10
|
+
// Get tmux sessions matching a pattern
|
|
11
|
+
function getTmuxSessions(pattern: string): string[] {
|
|
12
|
+
const socketDir = process.env.CLAWDBOT_TMUX_SOCKET_DIR || "/tmp/clawdbot-tmux-sockets";
|
|
13
|
+
const socket = `${socketDir}/clawdbot.sock`;
|
|
14
|
+
|
|
15
|
+
// Try clawdbot socket first
|
|
16
|
+
let result = run("tmux", ["-S", socket, "list-sessions", "-F", "#{session_name}"]);
|
|
17
|
+
|
|
18
|
+
if (!result.success) {
|
|
19
|
+
// Fall back to default tmux socket
|
|
20
|
+
result = run("tmux", ["list-sessions", "-F", "#{session_name}"]);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (!result.success) return [];
|
|
24
|
+
|
|
25
|
+
const sessions = result.stdout.split("\n").filter(Boolean);
|
|
26
|
+
|
|
27
|
+
// Match if session name contains any word from the pattern
|
|
28
|
+
const patternWords = pattern.split("-").filter(w => w.length > 2);
|
|
29
|
+
|
|
30
|
+
return sessions.filter(name =>
|
|
31
|
+
patternWords.some(word => name.toLowerCase().includes(word.toLowerCase()))
|
|
32
|
+
);
|
|
33
|
+
}
|
|
9
34
|
|
|
10
35
|
export interface ListOptions {
|
|
11
36
|
json?: boolean;
|
|
@@ -52,8 +77,25 @@ export async function list(options: ListOptions = {}): Promise<void> {
|
|
|
52
77
|
? isProcessRunning(alloc.pids.convex)
|
|
53
78
|
: false;
|
|
54
79
|
|
|
55
|
-
|
|
56
|
-
|
|
80
|
+
// Check for tmux sessions related to this feature
|
|
81
|
+
// Try multiple patterns: full name, project name, feature name
|
|
82
|
+
const featureSlug = name.toLowerCase().replace(/[^a-z0-9]/g, "-");
|
|
83
|
+
const projectSlug = alloc.project.toLowerCase().replace(/[^a-z0-9]/g, "-");
|
|
84
|
+
const featureOnly = alloc.branch.replace("feature/", "").toLowerCase().replace(/[^a-z0-9]/g, "-");
|
|
85
|
+
|
|
86
|
+
let tmuxSessions = getTmuxSessions(featureSlug);
|
|
87
|
+
if (tmuxSessions.length === 0) {
|
|
88
|
+
tmuxSessions = getTmuxSessions(projectSlug);
|
|
89
|
+
}
|
|
90
|
+
if (tmuxSessions.length === 0 && featureOnly !== projectSlug) {
|
|
91
|
+
tmuxSessions = getTmuxSessions(featureOnly);
|
|
92
|
+
}
|
|
93
|
+
const hasTmux = tmuxSessions.length > 0;
|
|
94
|
+
|
|
95
|
+
const isRunning = frontendRunning || convexRunning || hasTmux;
|
|
96
|
+
const isFullyRunning = (frontendRunning && convexRunning) || (hasTmux && tmuxSessions.length >= 2);
|
|
97
|
+
|
|
98
|
+
const statusEmoji = isFullyRunning ? "🟢" : isRunning ? "🟡" : "🔴";
|
|
57
99
|
|
|
58
100
|
console.log(`${statusEmoji} ${name}`);
|
|
59
101
|
console.log(` Project: ${alloc.project}`);
|
|
@@ -65,8 +107,19 @@ export async function list(options: ListOptions = {}): Promise<void> {
|
|
|
65
107
|
console.log(` Public: https://${alloc.funnelPath}.${traefikStatus.devDomain}`);
|
|
66
108
|
}
|
|
67
109
|
|
|
68
|
-
|
|
69
|
-
|
|
110
|
+
// Show PID-based status
|
|
111
|
+
if (alloc.pids.frontend || alloc.pids.convex) {
|
|
112
|
+
console.log(` Frontend: ${frontendRunning ? `running (PID: ${alloc.pids.frontend})` : "stopped"}`);
|
|
113
|
+
console.log(` Convex: ${convexRunning ? `running (PID: ${alloc.pids.convex})` : "stopped"}`);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Show tmux sessions if any
|
|
117
|
+
if (hasTmux) {
|
|
118
|
+
console.log(` Tmux: ${tmuxSessions.join(", ")}`);
|
|
119
|
+
} else if (!frontendRunning && !convexRunning) {
|
|
120
|
+
console.log(` Servers: stopped`);
|
|
121
|
+
}
|
|
122
|
+
|
|
70
123
|
console.log(` Started: ${new Date(alloc.started).toLocaleString()}`);
|
|
71
124
|
console.log();
|
|
72
125
|
}
|