@proletariat/cli 0.3.110 → 0.3.112
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/commands/gateway/connect.d.ts +33 -0
- package/dist/commands/gateway/connect.js +130 -0
- package/dist/commands/gateway/connect.js.map +1 -0
- package/dist/commands/gateway/disconnect.d.ts +21 -0
- package/dist/commands/gateway/disconnect.js +69 -0
- package/dist/commands/gateway/disconnect.js.map +1 -0
- package/dist/commands/gateway/start.d.ts +23 -0
- package/dist/commands/gateway/start.js +133 -0
- package/dist/commands/gateway/start.js.map +1 -0
- package/dist/commands/gateway/status.d.ts +16 -0
- package/dist/commands/gateway/status.js +76 -0
- package/dist/commands/gateway/status.js.map +1 -0
- package/dist/commands/gateway/test.d.ts +22 -0
- package/dist/commands/gateway/test.js +83 -0
- package/dist/commands/gateway/test.js.map +1 -0
- package/dist/commands/orchestrator/attach.d.ts +2 -0
- package/dist/commands/orchestrator/attach.js +80 -118
- package/dist/commands/orchestrator/attach.js.map +1 -1
- package/dist/commands/orchestrator/start.js +21 -0
- package/dist/commands/orchestrator/start.js.map +1 -1
- package/dist/commands/orchestrator/status.d.ts +3 -0
- package/dist/commands/orchestrator/status.js +104 -130
- package/dist/commands/orchestrator/status.js.map +1 -1
- package/dist/commands/orchestrator/stop.d.ts +2 -0
- package/dist/commands/orchestrator/stop.js +105 -107
- package/dist/commands/orchestrator/stop.js.map +1 -1
- package/dist/commands/reconcile.d.ts +29 -0
- package/dist/commands/reconcile.js +140 -0
- package/dist/commands/reconcile.js.map +1 -0
- package/dist/commands/session/attach.d.ts +2 -6
- package/dist/commands/session/attach.js +68 -97
- package/dist/commands/session/attach.js.map +1 -1
- package/dist/commands/session/list.d.ts +4 -1
- package/dist/commands/session/list.js +160 -326
- package/dist/commands/session/list.js.map +1 -1
- package/dist/commands/work/ship.js +131 -61
- package/dist/commands/work/ship.js.map +1 -1
- package/dist/commands/work/start.js +104 -49
- package/dist/commands/work/start.js.map +1 -1
- package/dist/lib/execution/session-utils.d.ts +4 -1
- package/dist/lib/execution/session-utils.js +3 -0
- package/dist/lib/execution/session-utils.js.map +1 -1
- package/dist/lib/gateway/channel-factory.d.ts +13 -0
- package/dist/lib/gateway/channel-factory.js +37 -0
- package/dist/lib/gateway/channel-factory.js.map +1 -0
- package/dist/lib/gateway/channels/telegram.d.ts +115 -0
- package/dist/lib/gateway/channels/telegram.js +215 -0
- package/dist/lib/gateway/channels/telegram.js.map +1 -0
- package/dist/lib/gateway/router.d.ts +84 -0
- package/dist/lib/gateway/router.js +140 -0
- package/dist/lib/gateway/router.js.map +1 -0
- package/dist/lib/gateway/session-poker.d.ts +35 -0
- package/dist/lib/gateway/session-poker.js +85 -0
- package/dist/lib/gateway/session-poker.js.map +1 -0
- package/dist/lib/gateway/types.d.ts +124 -0
- package/dist/lib/gateway/types.js +17 -0
- package/dist/lib/gateway/types.js.map +1 -0
- package/dist/lib/machine-db-mirror.d.ts +64 -0
- package/dist/lib/machine-db-mirror.js +82 -0
- package/dist/lib/machine-db-mirror.js.map +1 -0
- package/dist/lib/machine-db.d.ts +98 -0
- package/dist/lib/machine-db.js +152 -0
- package/dist/lib/machine-db.js.map +1 -1
- package/dist/lib/orchestrate/prompt-chain.d.ts +19 -4
- package/dist/lib/orchestrate/prompt-chain.js +19 -4
- package/dist/lib/orchestrate/prompt-chain.js.map +1 -1
- package/dist/lib/pr/index.d.ts +34 -2
- package/dist/lib/pr/index.js +95 -4
- package/dist/lib/pr/index.js.map +1 -1
- package/dist/lib/reconcile/core.d.ts +62 -0
- package/dist/lib/reconcile/core.js +137 -0
- package/dist/lib/reconcile/core.js.map +1 -0
- package/dist/lib/reconcile/index.d.ts +54 -0
- package/dist/lib/reconcile/index.js +377 -0
- package/dist/lib/reconcile/index.js.map +1 -0
- package/dist/lib/reconcile/types.d.ts +133 -0
- package/dist/lib/reconcile/types.js +16 -0
- package/dist/lib/reconcile/types.js.map +1 -0
- package/dist/lib/session/renderer.d.ts +121 -0
- package/dist/lib/session/renderer.js +547 -0
- package/dist/lib/session/renderer.js.map +1 -0
- package/dist/lib/update-check.d.ts +64 -7
- package/dist/lib/update-check.js +164 -20
- package/dist/lib/update-check.js.map +1 -1
- package/oclif.manifest.json +1203 -750
- package/package.json +1 -1
|
@@ -0,0 +1,547 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Renderer (PRLT-1272)
|
|
3
|
+
*
|
|
4
|
+
* Unified machine-wide session collection and grouped rendering.
|
|
5
|
+
*
|
|
6
|
+
* The principle: `prlt session list`, `prlt orchestrator status`, and related
|
|
7
|
+
* commands should ALWAYS query machine-wide for all sessions, regardless of
|
|
8
|
+
* whether the user is inside an HQ. Sessions are then visually grouped by
|
|
9
|
+
* their originating HQ — the current HQ bubbles to the top, other locations
|
|
10
|
+
* are still visible but de-emphasized.
|
|
11
|
+
*
|
|
12
|
+
* Sources collected:
|
|
13
|
+
* 1. machine.db `executions` table — cross-repo ticketless and ticketed work
|
|
14
|
+
* 2. Each registered HQ's workspace.db `agent_work` table — per-HQ workers
|
|
15
|
+
* 3. Discovered tmux/Docker orchestrator sessions — detected by name prefix
|
|
16
|
+
*
|
|
17
|
+
* Each entry is annotated with its hqPath/hqName/role so the renderer can
|
|
18
|
+
* group them.
|
|
19
|
+
*/
|
|
20
|
+
import * as fs from 'node:fs';
|
|
21
|
+
import * as os from 'node:os';
|
|
22
|
+
import * as path from 'node:path';
|
|
23
|
+
import { execSync } from 'node:child_process';
|
|
24
|
+
import { ExecutionStorage } from '../execution/storage.js';
|
|
25
|
+
import { openWorkspaceDatabase } from '../database/index.js';
|
|
26
|
+
import { MachineDB } from '../machine-db.js';
|
|
27
|
+
import { getRegisteredHeadquarters, getHeadquartersNameFromPath, normalizePath, } from '../machine-config.js';
|
|
28
|
+
import { checkContainerLiveness, discoverSessionId, findContainerSessionsByPrefix, getContainerTmuxSessionMap, getHostTmuxSessionNames, isContainerEnvironment, isSessionAlive, } from '../execution/session-utils.js';
|
|
29
|
+
import { findHQRoot } from '../workspace.js';
|
|
30
|
+
function captureRuntimeSnapshot() {
|
|
31
|
+
return {
|
|
32
|
+
hostTmuxSessions: getHostTmuxSessionNames(),
|
|
33
|
+
containerTmuxSessions: getContainerTmuxSessionMap(),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function findRunningOrchestratorContainers() {
|
|
37
|
+
try {
|
|
38
|
+
const output = execSync('docker ps --filter "name=prlt-orchestrator-" --format "{{.Names}}\t{{.ID}}"', { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }).trim();
|
|
39
|
+
if (!output)
|
|
40
|
+
return [];
|
|
41
|
+
return output
|
|
42
|
+
.split('\n')
|
|
43
|
+
.filter(Boolean)
|
|
44
|
+
.map(line => {
|
|
45
|
+
const [name, id] = line.split('\t');
|
|
46
|
+
return { name, containerId: id };
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// =============================================================================
|
|
54
|
+
// HQ resolution helpers
|
|
55
|
+
// =============================================================================
|
|
56
|
+
/**
|
|
57
|
+
* Sanitize a name segment for use in tmux session names.
|
|
58
|
+
* Mirror of orchestrator/start.ts sanitizeName() — duplicated here to avoid
|
|
59
|
+
* importing a command file from a lib helper (cycle risk).
|
|
60
|
+
*/
|
|
61
|
+
function sanitizeName(name) {
|
|
62
|
+
return name
|
|
63
|
+
.replace(/[^a-zA-Z0-9._-]/g, '-')
|
|
64
|
+
.replace(/-+/g, '-')
|
|
65
|
+
.replace(/^-|-$/g, '');
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Build the orchestrator session prefix used by `prlt orchestrator start`.
|
|
69
|
+
* Format: `prlt-orchestrator-{sanitizedHqName}-`
|
|
70
|
+
*/
|
|
71
|
+
function orchestratorPrefixForHq(hqName) {
|
|
72
|
+
return `prlt-orchestrator-${sanitizeName(hqName) || 'default'}-`;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Try to attribute an orchestrator session/container name to one of the
|
|
76
|
+
* registered HQs. Returns the matching HQ entry, or null if no match.
|
|
77
|
+
*/
|
|
78
|
+
function attributeOrchestratorToHq(sessionName, registered) {
|
|
79
|
+
for (const hq of registered) {
|
|
80
|
+
const hqName = getHeadquartersNameFromPath(hq.path);
|
|
81
|
+
const prefix = orchestratorPrefixForHq(hqName);
|
|
82
|
+
if (sessionName.startsWith(prefix)) {
|
|
83
|
+
return {
|
|
84
|
+
hqPath: hq.path,
|
|
85
|
+
hqName,
|
|
86
|
+
orchestratorName: sessionName.slice(prefix.length),
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Replace the user's home directory in a path with `~` for display.
|
|
94
|
+
*/
|
|
95
|
+
export function tildifyPath(p) {
|
|
96
|
+
if (!p)
|
|
97
|
+
return p;
|
|
98
|
+
const home = process.env.HOME || os.homedir();
|
|
99
|
+
if (p === home)
|
|
100
|
+
return '~';
|
|
101
|
+
if (p.startsWith(home + path.sep))
|
|
102
|
+
return '~' + p.slice(home.length);
|
|
103
|
+
return p;
|
|
104
|
+
}
|
|
105
|
+
// =============================================================================
|
|
106
|
+
// Workspace.db (per-HQ) collection
|
|
107
|
+
// =============================================================================
|
|
108
|
+
function collectFromWorkspaceDb(hqPath, hqName, snapshot, includeAll) {
|
|
109
|
+
const sessions = [];
|
|
110
|
+
let db = null;
|
|
111
|
+
try {
|
|
112
|
+
db = openWorkspaceDatabase(hqPath);
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
return sessions;
|
|
116
|
+
}
|
|
117
|
+
try {
|
|
118
|
+
const storage = new ExecutionStorage(db);
|
|
119
|
+
// Active executions (running + starting)
|
|
120
|
+
const active = [
|
|
121
|
+
...storage.listExecutions({ status: 'running' }),
|
|
122
|
+
...storage.listExecutions({ status: 'starting' }),
|
|
123
|
+
];
|
|
124
|
+
// Self-healing: also check stopped records that may have a live tmux session
|
|
125
|
+
if (includeAll) {
|
|
126
|
+
active.push(...storage.listExecutions({ status: 'stopped' }));
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
// Promote any stopped executions whose tmux sessions are still alive.
|
|
130
|
+
const stopped = storage.listExecutions({ status: 'stopped' });
|
|
131
|
+
for (const exec of stopped) {
|
|
132
|
+
if (isSessionAlive(exec)) {
|
|
133
|
+
active.push(exec);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
for (const exec of active) {
|
|
138
|
+
const isContainer = isContainerEnvironment(exec.environment);
|
|
139
|
+
let exists = false;
|
|
140
|
+
let actualSessionId = discoverSessionId(exec, snapshot.hostTmuxSessions, snapshot.containerTmuxSessions) ||
|
|
141
|
+
exec.sessionId;
|
|
142
|
+
if (isContainer && exec.containerId) {
|
|
143
|
+
const containerStatus = checkContainerLiveness(exec.containerId);
|
|
144
|
+
if (containerStatus === 'running') {
|
|
145
|
+
if (actualSessionId) {
|
|
146
|
+
const containerSessions = findContainerSessionsByPrefix(snapshot.containerTmuxSessions, exec.containerId);
|
|
147
|
+
exists = containerSessions.includes(actualSessionId);
|
|
148
|
+
}
|
|
149
|
+
if (!exists) {
|
|
150
|
+
// Container running but no tmux session — still counts as alive.
|
|
151
|
+
exists = true;
|
|
152
|
+
actualSessionId =
|
|
153
|
+
actualSessionId || `container:${exec.containerId.substring(0, 12)}`;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
else if (actualSessionId) {
|
|
158
|
+
exists = snapshot.hostTmuxSessions.includes(actualSessionId);
|
|
159
|
+
}
|
|
160
|
+
if (!actualSessionId)
|
|
161
|
+
continue;
|
|
162
|
+
if (!exists && !includeAll)
|
|
163
|
+
continue;
|
|
164
|
+
// Determine role: agentName 'orchestrator-*' or ticketId 'ORCH'
|
|
165
|
+
let role = 'worker';
|
|
166
|
+
if (exec.agentName.startsWith('orchestrator') ||
|
|
167
|
+
exec.ticketId === 'ORCH' ||
|
|
168
|
+
exec.ticketId === 'orchestrator') {
|
|
169
|
+
role = 'orchestrator';
|
|
170
|
+
}
|
|
171
|
+
sessions.push({
|
|
172
|
+
id: exec.id,
|
|
173
|
+
sessionId: actualSessionId,
|
|
174
|
+
ticketId: exec.ticketId,
|
|
175
|
+
agentName: exec.agentName,
|
|
176
|
+
status: deriveStatus(exec.status, exists, exec.lifecycleState),
|
|
177
|
+
role,
|
|
178
|
+
environment: isContainer ? 'container' : 'host',
|
|
179
|
+
containerId: exec.containerId,
|
|
180
|
+
exists,
|
|
181
|
+
source: 'db',
|
|
182
|
+
startedAt: exec.startedAt,
|
|
183
|
+
lastHeartbeat: exec.lastHeartbeat,
|
|
184
|
+
lifecycleState: exec.lifecycleState,
|
|
185
|
+
hqPath,
|
|
186
|
+
hqName,
|
|
187
|
+
repoPath: hqPath,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
finally {
|
|
192
|
+
db.close();
|
|
193
|
+
}
|
|
194
|
+
return sessions;
|
|
195
|
+
}
|
|
196
|
+
function deriveStatus(rawStatus, exists, lifecycleState) {
|
|
197
|
+
if (lifecycleState === 'died')
|
|
198
|
+
return 'died';
|
|
199
|
+
if (lifecycleState === 'idle')
|
|
200
|
+
return 'idle';
|
|
201
|
+
if (!exists)
|
|
202
|
+
return 'stale';
|
|
203
|
+
return rawStatus || 'running';
|
|
204
|
+
}
|
|
205
|
+
// =============================================================================
|
|
206
|
+
// machine.db collection
|
|
207
|
+
// =============================================================================
|
|
208
|
+
function collectFromMachineDb(snapshot, registered, alreadySeenSessionIds, includeAll) {
|
|
209
|
+
const sessions = [];
|
|
210
|
+
let db = null;
|
|
211
|
+
try {
|
|
212
|
+
db = new MachineDB();
|
|
213
|
+
}
|
|
214
|
+
catch {
|
|
215
|
+
return sessions;
|
|
216
|
+
}
|
|
217
|
+
try {
|
|
218
|
+
const machineExecs = includeAll
|
|
219
|
+
? db.listExecutions()
|
|
220
|
+
: db.getActiveExecutions();
|
|
221
|
+
for (const exec of machineExecs) {
|
|
222
|
+
// Skip duplicates already collected from a workspace.db.
|
|
223
|
+
if (exec.sessionId && alreadySeenSessionIds.has(exec.sessionId))
|
|
224
|
+
continue;
|
|
225
|
+
const isContainer = exec.environment === 'docker' || exec.environment === 'devcontainer';
|
|
226
|
+
let exists = false;
|
|
227
|
+
let actualSessionId = exec.sessionId;
|
|
228
|
+
if (isContainer && exec.containerId) {
|
|
229
|
+
const status = checkContainerLiveness(exec.containerId);
|
|
230
|
+
if (status === 'running') {
|
|
231
|
+
if (exec.sessionId) {
|
|
232
|
+
const containerSessions = findContainerSessionsByPrefix(snapshot.containerTmuxSessions, exec.containerId);
|
|
233
|
+
exists = containerSessions.includes(exec.sessionId);
|
|
234
|
+
}
|
|
235
|
+
if (!exists) {
|
|
236
|
+
exists = true;
|
|
237
|
+
actualSessionId =
|
|
238
|
+
actualSessionId || `container:${exec.containerId.substring(0, 12)}`;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
else if (exec.sessionId) {
|
|
243
|
+
exists = snapshot.hostTmuxSessions.includes(exec.sessionId);
|
|
244
|
+
}
|
|
245
|
+
if (!actualSessionId)
|
|
246
|
+
continue;
|
|
247
|
+
if (!exists && !includeAll)
|
|
248
|
+
continue;
|
|
249
|
+
// Attribute repoPath to a registered HQ if possible.
|
|
250
|
+
const matchedHq = matchRepoToHq(exec.repoPath, registered);
|
|
251
|
+
// Detect role
|
|
252
|
+
let role = exec.ticketId ? 'worker' : 'headless';
|
|
253
|
+
if (exec.agentName.startsWith('orchestrator') ||
|
|
254
|
+
exec.ticketId === 'ORCH' ||
|
|
255
|
+
exec.ticketId === 'orchestrator') {
|
|
256
|
+
role = 'orchestrator';
|
|
257
|
+
}
|
|
258
|
+
sessions.push({
|
|
259
|
+
id: exec.id,
|
|
260
|
+
sessionId: actualSessionId,
|
|
261
|
+
ticketId: exec.ticketId || exec.id,
|
|
262
|
+
agentName: exec.agentName,
|
|
263
|
+
status: deriveStatus(exec.status, exists),
|
|
264
|
+
role,
|
|
265
|
+
environment: isContainer ? 'container' : 'host',
|
|
266
|
+
containerId: exec.containerId,
|
|
267
|
+
exists,
|
|
268
|
+
source: 'db',
|
|
269
|
+
startedAt: exec.startedAt,
|
|
270
|
+
hqPath: matchedHq?.hqPath,
|
|
271
|
+
hqName: matchedHq?.hqName,
|
|
272
|
+
repoPath: exec.repoPath,
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
finally {
|
|
277
|
+
db.close();
|
|
278
|
+
}
|
|
279
|
+
return sessions;
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Match a repo path to one of the registered HQs.
|
|
283
|
+
* A repo is considered to belong to an HQ if it lives inside the HQ tree
|
|
284
|
+
* (e.g. an agent worktree under `<hqPath>/agents/...`).
|
|
285
|
+
*/
|
|
286
|
+
function matchRepoToHq(repoPath, registered) {
|
|
287
|
+
if (!repoPath)
|
|
288
|
+
return null;
|
|
289
|
+
let normalized;
|
|
290
|
+
try {
|
|
291
|
+
normalized = normalizePath(repoPath);
|
|
292
|
+
}
|
|
293
|
+
catch {
|
|
294
|
+
normalized = repoPath;
|
|
295
|
+
}
|
|
296
|
+
for (const hq of registered) {
|
|
297
|
+
let hqNormalized;
|
|
298
|
+
try {
|
|
299
|
+
hqNormalized = normalizePath(hq.path);
|
|
300
|
+
}
|
|
301
|
+
catch {
|
|
302
|
+
hqNormalized = hq.path;
|
|
303
|
+
}
|
|
304
|
+
if (normalized === hqNormalized || normalized.startsWith(hqNormalized + path.sep)) {
|
|
305
|
+
return { hqPath: hq.path, hqName: getHeadquartersNameFromPath(hq.path) };
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
return null;
|
|
309
|
+
}
|
|
310
|
+
// =============================================================================
|
|
311
|
+
// Orchestrator discovery (tmux + Docker)
|
|
312
|
+
// =============================================================================
|
|
313
|
+
function collectOrchestrators(snapshot, registered, alreadySeenSessionIds) {
|
|
314
|
+
const sessions = [];
|
|
315
|
+
// Host tmux orchestrator sessions
|
|
316
|
+
for (const sessionName of snapshot.hostTmuxSessions) {
|
|
317
|
+
if (!sessionName.startsWith('prlt-orchestrator-'))
|
|
318
|
+
continue;
|
|
319
|
+
if (alreadySeenSessionIds.has(sessionName))
|
|
320
|
+
continue;
|
|
321
|
+
const attribution = attributeOrchestratorToHq(sessionName, registered);
|
|
322
|
+
sessions.push({
|
|
323
|
+
id: sessionName,
|
|
324
|
+
sessionId: sessionName,
|
|
325
|
+
ticketId: 'orchestrator',
|
|
326
|
+
agentName: attribution?.orchestratorName || sessionName,
|
|
327
|
+
status: 'running',
|
|
328
|
+
role: 'orchestrator',
|
|
329
|
+
environment: 'host',
|
|
330
|
+
exists: true,
|
|
331
|
+
source: 'discovered',
|
|
332
|
+
hqPath: attribution?.hqPath,
|
|
333
|
+
hqName: attribution?.hqName,
|
|
334
|
+
repoPath: attribution?.hqPath,
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
// Docker orchestrator containers
|
|
338
|
+
const dockerOrchestrators = findRunningOrchestratorContainers();
|
|
339
|
+
for (const { name, containerId } of dockerOrchestrators) {
|
|
340
|
+
if (alreadySeenSessionIds.has(name))
|
|
341
|
+
continue;
|
|
342
|
+
const attribution = attributeOrchestratorToHq(name, registered);
|
|
343
|
+
sessions.push({
|
|
344
|
+
id: name,
|
|
345
|
+
sessionId: name,
|
|
346
|
+
ticketId: 'orchestrator',
|
|
347
|
+
agentName: attribution?.orchestratorName || name,
|
|
348
|
+
status: 'running',
|
|
349
|
+
role: 'orchestrator',
|
|
350
|
+
environment: 'container',
|
|
351
|
+
containerId,
|
|
352
|
+
exists: true,
|
|
353
|
+
source: 'discovered',
|
|
354
|
+
hqPath: attribution?.hqPath,
|
|
355
|
+
hqName: attribution?.hqName,
|
|
356
|
+
repoPath: attribution?.hqPath,
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
return sessions;
|
|
360
|
+
}
|
|
361
|
+
// =============================================================================
|
|
362
|
+
// Public API: collect + group
|
|
363
|
+
// =============================================================================
|
|
364
|
+
/**
|
|
365
|
+
* Collect all sessions on the machine, regardless of cwd.
|
|
366
|
+
*
|
|
367
|
+
* Queries:
|
|
368
|
+
* 1. machine.db (cross-repo executions, source of truth for ticketless work)
|
|
369
|
+
* 2. Every registered HQ's workspace.db (workers per HQ)
|
|
370
|
+
* 3. tmux/Docker (orchestrators by name prefix)
|
|
371
|
+
*
|
|
372
|
+
* Filters are applied at the end so the underlying machine query path is
|
|
373
|
+
* the same in every command.
|
|
374
|
+
*/
|
|
375
|
+
export function collectAllSessions(options = {}) {
|
|
376
|
+
const snapshot = captureRuntimeSnapshot();
|
|
377
|
+
const registered = getRegisteredHeadquarters().filter(hq => fs.existsSync(hq.path));
|
|
378
|
+
// Include the current cwd HQ even when it isn't in the machine registry
|
|
379
|
+
// (e.g. e2e tests that set up a throwaway HQ without registering it).
|
|
380
|
+
const cwdHq = findHQRoot(process.cwd());
|
|
381
|
+
const hqsToQuery = [...registered];
|
|
382
|
+
if (cwdHq) {
|
|
383
|
+
let cwdNormalized;
|
|
384
|
+
try {
|
|
385
|
+
cwdNormalized = normalizePath(cwdHq);
|
|
386
|
+
}
|
|
387
|
+
catch {
|
|
388
|
+
cwdNormalized = cwdHq;
|
|
389
|
+
}
|
|
390
|
+
const alreadyRegistered = registered.some(hq => {
|
|
391
|
+
try {
|
|
392
|
+
return normalizePath(hq.path) === cwdNormalized;
|
|
393
|
+
}
|
|
394
|
+
catch {
|
|
395
|
+
return hq.path === cwdNormalized;
|
|
396
|
+
}
|
|
397
|
+
});
|
|
398
|
+
if (!alreadyRegistered) {
|
|
399
|
+
hqsToQuery.push({
|
|
400
|
+
name: getHeadquartersNameFromPath(cwdHq),
|
|
401
|
+
path: cwdHq,
|
|
402
|
+
registeredAt: new Date().toISOString(),
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
const seenSessionIds = new Set();
|
|
407
|
+
const all = [];
|
|
408
|
+
// 1) Per-HQ workspace databases (workers + locally tracked orchestrators).
|
|
409
|
+
for (const hq of hqsToQuery) {
|
|
410
|
+
const hqName = getHeadquartersNameFromPath(hq.path);
|
|
411
|
+
const fromHq = collectFromWorkspaceDb(hq.path, hqName, snapshot, options.includeAll === true);
|
|
412
|
+
for (const s of fromHq) {
|
|
413
|
+
if (s.sessionId)
|
|
414
|
+
seenSessionIds.add(s.sessionId);
|
|
415
|
+
all.push(s);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
// 2) machine.db ticketless / cross-repo executions
|
|
419
|
+
const fromMachine = collectFromMachineDb(snapshot, hqsToQuery, seenSessionIds, options.includeAll === true);
|
|
420
|
+
for (const s of fromMachine) {
|
|
421
|
+
if (s.sessionId)
|
|
422
|
+
seenSessionIds.add(s.sessionId);
|
|
423
|
+
all.push(s);
|
|
424
|
+
}
|
|
425
|
+
// 3) Discovered orchestrator tmux/Docker sessions not yet covered by a DB
|
|
426
|
+
const discoveredOrchestrators = collectOrchestrators(snapshot, hqsToQuery, seenSessionIds);
|
|
427
|
+
for (const s of discoveredOrchestrators) {
|
|
428
|
+
if (s.sessionId)
|
|
429
|
+
seenSessionIds.add(s.sessionId);
|
|
430
|
+
all.push(s);
|
|
431
|
+
}
|
|
432
|
+
// Apply filters
|
|
433
|
+
let filtered = all;
|
|
434
|
+
if (options.hqPathFilter) {
|
|
435
|
+
let normalized;
|
|
436
|
+
try {
|
|
437
|
+
normalized = normalizePath(options.hqPathFilter);
|
|
438
|
+
}
|
|
439
|
+
catch {
|
|
440
|
+
normalized = options.hqPathFilter;
|
|
441
|
+
}
|
|
442
|
+
filtered = filtered.filter(s => {
|
|
443
|
+
if (!s.hqPath)
|
|
444
|
+
return false;
|
|
445
|
+
try {
|
|
446
|
+
return normalizePath(s.hqPath) === normalized;
|
|
447
|
+
}
|
|
448
|
+
catch {
|
|
449
|
+
return s.hqPath === normalized;
|
|
450
|
+
}
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
if (options.roleFilter) {
|
|
454
|
+
filtered = filtered.filter(s => s.role === options.roleFilter);
|
|
455
|
+
}
|
|
456
|
+
return filtered;
|
|
457
|
+
}
|
|
458
|
+
/**
|
|
459
|
+
* Group sessions into "current HQ" vs "other locations" buckets.
|
|
460
|
+
*
|
|
461
|
+
* The current HQ is resolved from `process.cwd()` (or an explicit override).
|
|
462
|
+
* Sessions whose hqPath matches the current HQ go into `here`; everything
|
|
463
|
+
* else goes into `elsewhere`.
|
|
464
|
+
*/
|
|
465
|
+
export function groupSessionsByHQ(sessions, currentHqOverride) {
|
|
466
|
+
const currentHq = currentHqOverride === null
|
|
467
|
+
? undefined
|
|
468
|
+
: currentHqOverride ?? findHQRoot(process.cwd()) ?? undefined;
|
|
469
|
+
let normalizedCurrent;
|
|
470
|
+
if (currentHq) {
|
|
471
|
+
try {
|
|
472
|
+
normalizedCurrent = normalizePath(currentHq);
|
|
473
|
+
}
|
|
474
|
+
catch {
|
|
475
|
+
normalizedCurrent = currentHq;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
const here = [];
|
|
479
|
+
const elsewhere = [];
|
|
480
|
+
for (const s of sessions) {
|
|
481
|
+
if (!normalizedCurrent || !s.hqPath) {
|
|
482
|
+
elsewhere.push(s);
|
|
483
|
+
continue;
|
|
484
|
+
}
|
|
485
|
+
let normalizedSession;
|
|
486
|
+
try {
|
|
487
|
+
normalizedSession = normalizePath(s.hqPath);
|
|
488
|
+
}
|
|
489
|
+
catch {
|
|
490
|
+
normalizedSession = s.hqPath;
|
|
491
|
+
}
|
|
492
|
+
if (normalizedSession === normalizedCurrent) {
|
|
493
|
+
here.push(s);
|
|
494
|
+
}
|
|
495
|
+
else {
|
|
496
|
+
elsewhere.push(s);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
return {
|
|
500
|
+
currentHq,
|
|
501
|
+
currentHqName: currentHq ? getHeadquartersNameFromPath(currentHq) : undefined,
|
|
502
|
+
here,
|
|
503
|
+
elsewhere,
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
// =============================================================================
|
|
507
|
+
// Pretty rendering helpers (text)
|
|
508
|
+
// =============================================================================
|
|
509
|
+
/** Format a Date into a compact relative duration like "~15m", "~3h", "~2d". */
|
|
510
|
+
export function formatRelativeAge(start, now = new Date()) {
|
|
511
|
+
if (!start)
|
|
512
|
+
return '';
|
|
513
|
+
const diffMs = Math.max(0, now.getTime() - start.getTime());
|
|
514
|
+
const sec = Math.floor(diffMs / 1000);
|
|
515
|
+
if (sec < 60)
|
|
516
|
+
return `~${sec}s`;
|
|
517
|
+
const min = Math.floor(sec / 60);
|
|
518
|
+
if (min < 60)
|
|
519
|
+
return `~${min}m`;
|
|
520
|
+
const hr = Math.floor(min / 60);
|
|
521
|
+
if (hr < 48)
|
|
522
|
+
return `~${hr}h`;
|
|
523
|
+
const day = Math.floor(hr / 24);
|
|
524
|
+
return `~${day}d`;
|
|
525
|
+
}
|
|
526
|
+
/**
|
|
527
|
+
* Group elsewhere sessions by hqPath/hqName for nicer rendering.
|
|
528
|
+
* Sessions without an hqPath are bucketed under "(no HQ)".
|
|
529
|
+
*/
|
|
530
|
+
export function bucketElsewhereByHq(elsewhere) {
|
|
531
|
+
const buckets = new Map();
|
|
532
|
+
for (const s of elsewhere) {
|
|
533
|
+
const key = s.hqPath ?? '__none__';
|
|
534
|
+
let bucket = buckets.get(key);
|
|
535
|
+
if (!bucket) {
|
|
536
|
+
bucket = {
|
|
537
|
+
hqPath: s.hqPath ?? null,
|
|
538
|
+
hqName: s.hqName ?? '(no HQ)',
|
|
539
|
+
sessions: [],
|
|
540
|
+
};
|
|
541
|
+
buckets.set(key, bucket);
|
|
542
|
+
}
|
|
543
|
+
bucket.sessions.push(s);
|
|
544
|
+
}
|
|
545
|
+
return Array.from(buckets.values());
|
|
546
|
+
}
|
|
547
|
+
//# sourceMappingURL=renderer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"renderer.js","sourceRoot":"","sources":["../../../src/lib/session/renderer.ts"],"names":[],"mappings":"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"}
|
|
@@ -84,23 +84,79 @@ export declare function isNewerVersion(current: string, latest: string): boolean
|
|
|
84
84
|
/**
|
|
85
85
|
* Get the npm global node_modules directory.
|
|
86
86
|
* Returns null if it cannot be determined.
|
|
87
|
+
*
|
|
88
|
+
* Honours the `PRLT_NPM_MODULES_DIR_OVERRIDE` env var for tests so the
|
|
89
|
+
* backup/restore logic in {@link runNpmInstallWithRetry} can be exercised
|
|
90
|
+
* against a temp directory instead of the user's real npm prefix.
|
|
87
91
|
*/
|
|
88
92
|
export declare function getNpmGlobalModulesDir(): string | null;
|
|
89
93
|
/**
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
|
|
94
|
+
* Captured state of a bin symlink — used so we can restore the symlink
|
|
95
|
+
* if npm removed it during a failed retry install (PRLT-1276).
|
|
96
|
+
*/
|
|
97
|
+
interface BinSymlinkRecord {
|
|
98
|
+
/** Absolute path to the bin entry (e.g. `<prefix>/bin/prlt`) */
|
|
99
|
+
path: string;
|
|
100
|
+
/** Original link target, as returned by `readlink` (may be relative) */
|
|
101
|
+
target: string;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* State captured before we disturb the current @proletariat/cli install,
|
|
105
|
+
* so it can be restored if the retry install fails.
|
|
106
|
+
*/
|
|
107
|
+
export interface NpmPackageBackup {
|
|
108
|
+
/** Absolute path to the original package directory */
|
|
109
|
+
originalPath: string;
|
|
110
|
+
/**
|
|
111
|
+
* Absolute path to the backup (rename-aside) location.
|
|
112
|
+
* Empty string when there was nothing to back up (package dir did not exist).
|
|
113
|
+
*/
|
|
114
|
+
backupPath: string;
|
|
115
|
+
/** Bin symlinks that existed before the backup was taken */
|
|
116
|
+
binSymlinks: BinSymlinkRecord[];
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Back up the existing @proletariat/cli package directory via atomic rename
|
|
120
|
+
* so an install retry can run against a clean slate while preserving the
|
|
121
|
+
* ability to restore the previous installation if the retry fails.
|
|
93
122
|
*
|
|
94
|
-
*
|
|
123
|
+
* The backup is placed adjacent to the original in the same directory, so
|
|
124
|
+
* the rename is guaranteed to be atomic. Returns null if the rename fails
|
|
125
|
+
* (e.g. permission error) — in that case the caller must not proceed,
|
|
126
|
+
* because destroying the package dir without a backup is exactly the
|
|
127
|
+
* PRLT-1276 regression we are trying to avoid.
|
|
128
|
+
*
|
|
129
|
+
* When there is no existing package dir to back up, this still returns a
|
|
130
|
+
* valid `NpmPackageBackup` with an empty `backupPath` — the bin symlink
|
|
131
|
+
* records are still captured so they can be restored on failure.
|
|
132
|
+
*/
|
|
133
|
+
export declare function backupNpmPackageDir(): NpmPackageBackup | null;
|
|
134
|
+
/**
|
|
135
|
+
* Restore the backup created by {@link backupNpmPackageDir} after a failed
|
|
136
|
+
* retry. Removes any partially-installed content at the original path,
|
|
137
|
+
* renames the backup back into place, and re-creates bin symlinks that npm
|
|
138
|
+
* may have removed during the failed install.
|
|
95
139
|
*/
|
|
96
|
-
export declare function
|
|
140
|
+
export declare function restoreNpmPackageBackup(info: NpmPackageBackup): boolean;
|
|
141
|
+
/**
|
|
142
|
+
* Remove the backup created by {@link backupNpmPackageDir} after a
|
|
143
|
+
* successful retry. Best-effort — failures are not fatal.
|
|
144
|
+
*/
|
|
145
|
+
export declare function discardNpmPackageBackup(info: NpmPackageBackup): void;
|
|
97
146
|
/**
|
|
98
147
|
* Run an npm global install command with automatic ENOTEMPTY retry.
|
|
99
148
|
*
|
|
100
149
|
* npm global installs frequently fail with ENOTEMPTY when renaming the
|
|
101
150
|
* old package directory (a known npm bug). When this error is detected
|
|
102
|
-
* in stderr, the
|
|
103
|
-
* retried
|
|
151
|
+
* in stderr, the existing @proletariat/cli directory is moved aside via
|
|
152
|
+
* an atomic rename, the install is retried against a clean slate, and
|
|
153
|
+
* the backup is either discarded (on success) or restored (on failure).
|
|
154
|
+
*
|
|
155
|
+
* PRLT-1276: this is the restore-on-failure path that fixes the "prlt
|
|
156
|
+
* intermittently disappears from PATH" bug. Previously we `rm -rf`'d the
|
|
157
|
+
* package directory before retrying, so a retry that failed for any reason
|
|
158
|
+
* (network glitch, timeout, nvm mid-switch) left the user with a deleted
|
|
159
|
+
* package and a dangling `bin/prlt` symlink.
|
|
104
160
|
*
|
|
105
161
|
* Throws on failure (both non-ENOTEMPTY errors and failed retries).
|
|
106
162
|
*/
|
|
@@ -152,3 +208,4 @@ export declare function dismissVersion(version: string): void;
|
|
|
152
208
|
* This is the default "Skip" behavior — just don't persist anything.
|
|
153
209
|
*/
|
|
154
210
|
export declare function dismissSession(): void;
|
|
211
|
+
export {};
|