@proletariat/cli 0.3.109 → 0.3.111
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/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/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/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/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 +11 -0
- package/dist/lib/machine-db.js +17 -0
- package/dist/lib/machine-db.js.map +1 -1
- package/dist/lib/orchestrate/actions.d.ts +8 -0
- package/dist/lib/orchestrate/actions.js +166 -94
- package/dist/lib/orchestrate/actions.js.map +1 -1
- package/dist/lib/orchestrate/prompt-chain.d.ts +181 -0
- package/dist/lib/orchestrate/prompt-chain.js +323 -0
- package/dist/lib/orchestrate/prompt-chain.js.map +1 -0
- package/dist/lib/prompt-command.d.ts +61 -1
- package/dist/lib/prompt-command.js +167 -1
- package/dist/lib/prompt-command.js.map +1 -1
- package/dist/lib/prompt-json.d.ts +129 -2
- package/dist/lib/prompt-json.js +157 -0
- package/dist/lib/prompt-json.js.map +1 -1
- package/dist/lib/runtime-command.d.ts +3 -1
- package/dist/lib/runtime-command.js +4 -2
- package/dist/lib/runtime-command.js.map +1 -1
- 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 +1173 -1062
- package/package.json +1 -1
|
@@ -3,15 +3,16 @@ import { PromptCommand } from '../../lib/prompt-command.js';
|
|
|
3
3
|
import { machineOutputFlags } from '../../lib/pmo/index.js';
|
|
4
4
|
import { shouldOutputJson, outputSuccessAsJson, createMetadata, } from '../../lib/prompt-json.js';
|
|
5
5
|
import { styles } from '../../lib/styles.js';
|
|
6
|
-
import {
|
|
7
|
-
import { findHQRoot } from '../../lib/workspace.js';
|
|
8
|
-
import { getHeadquartersNameFromPath } from '../../lib/machine-config.js';
|
|
6
|
+
import { captureTmuxPane } from '../../lib/execution/session-utils.js';
|
|
9
7
|
import { execSync } from 'node:child_process';
|
|
10
|
-
import {
|
|
8
|
+
import { collectAllSessions, groupSessionsByHQ, bucketElsewhereByHq, tildifyPath, } from '../../lib/session/renderer.js';
|
|
9
|
+
import { findHQRoot } from '../../lib/workspace.js';
|
|
11
10
|
export default class OrchestratorStatus extends PromptCommand {
|
|
12
|
-
static description = 'Check
|
|
11
|
+
static description = 'Check orchestrator sessions across the entire machine, grouped by HQ.';
|
|
13
12
|
static examples = [
|
|
14
13
|
'<%= config.bin %> <%= command.id %>',
|
|
14
|
+
'<%= config.bin %> <%= command.id %> --here',
|
|
15
|
+
'<%= config.bin %> <%= command.id %> --hq ~/Projects/backend-hq',
|
|
15
16
|
'<%= config.bin %> <%= command.id %> --peek',
|
|
16
17
|
'<%= config.bin %> <%= command.id %> --peek --lines 50',
|
|
17
18
|
];
|
|
@@ -19,10 +20,19 @@ export default class OrchestratorStatus extends PromptCommand {
|
|
|
19
20
|
...machineOutputFlags,
|
|
20
21
|
name: Flags.string({
|
|
21
22
|
char: 'n',
|
|
22
|
-
description: '
|
|
23
|
+
description: 'Filter to a single orchestrator by name (matches agentName)',
|
|
24
|
+
}),
|
|
25
|
+
here: Flags.boolean({
|
|
26
|
+
description: 'Filter to orchestrators in the current HQ only',
|
|
27
|
+
default: false,
|
|
28
|
+
exclusive: ['hq'],
|
|
29
|
+
}),
|
|
30
|
+
hq: Flags.string({
|
|
31
|
+
description: 'Filter to orchestrators in a specific HQ path',
|
|
32
|
+
exclusive: ['here'],
|
|
23
33
|
}),
|
|
24
34
|
peek: Flags.boolean({
|
|
25
|
-
description: 'Show recent output from
|
|
35
|
+
description: 'Show recent output from each orchestrator',
|
|
26
36
|
default: false,
|
|
27
37
|
}),
|
|
28
38
|
lines: Flags.integer({
|
|
@@ -44,142 +54,106 @@ export default class OrchestratorStatus extends PromptCommand {
|
|
|
44
54
|
async run() {
|
|
45
55
|
const { flags } = await this.parse(OrchestratorStatus);
|
|
46
56
|
const jsonMode = shouldOutputJson(flags);
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
// Explicit --name: check that specific orchestrator (host tmux + Docker)
|
|
54
|
-
const sessionName = buildOrchestratorSessionName(hqName, flags.name);
|
|
55
|
-
const isHostRunning = hostSessions.includes(sessionName);
|
|
56
|
-
const containerName = buildOrchestratorContainerName(hqName, flags.name);
|
|
57
|
-
const dockerContainerId = getOrchestratorContainerId(containerName);
|
|
58
|
-
const isDockerRunning = !!dockerContainerId;
|
|
59
|
-
const isRunning = isHostRunning || isDockerRunning;
|
|
60
|
-
const environment = isDockerRunning ? 'docker' : 'host';
|
|
61
|
-
let recentOutput = null;
|
|
62
|
-
if (isRunning && flags.peek) {
|
|
63
|
-
if (isDockerRunning && dockerContainerId) {
|
|
64
|
-
recentOutput = this.captureDockerTmuxPane(dockerContainerId, containerName, flags.lines);
|
|
65
|
-
}
|
|
66
|
-
else {
|
|
67
|
-
recentOutput = captureTmuxPane(sessionName, flags.lines);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
if (jsonMode) {
|
|
71
|
-
outputSuccessAsJson({
|
|
72
|
-
running: isRunning,
|
|
73
|
-
sessionId: isRunning ? (isDockerRunning ? containerName : sessionName) : null,
|
|
74
|
-
containerId: dockerContainerId || null,
|
|
75
|
-
environment,
|
|
76
|
-
name: flags.name,
|
|
77
|
-
...(recentOutput !== null && { recentOutput }),
|
|
78
|
-
}, createMetadata('orchestrator status', flags));
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
this.log('');
|
|
82
|
-
if (isRunning) {
|
|
83
|
-
this.log(styles.success(`Orchestrator "${flags.name}" is running${isDockerRunning ? ' (Docker)' : ''}`));
|
|
84
|
-
this.log(styles.muted(` Session: ${isDockerRunning ? containerName : sessionName}`));
|
|
85
|
-
if (dockerContainerId) {
|
|
86
|
-
this.log(styles.muted(` Container: ${dockerContainerId}`));
|
|
87
|
-
}
|
|
88
|
-
this.log(styles.muted(` Attach: prlt orchestrator attach --name ${flags.name}`));
|
|
89
|
-
if (recentOutput) {
|
|
90
|
-
this.log('');
|
|
91
|
-
this.log(styles.header('Recent output:'));
|
|
92
|
-
this.log(styles.muted('─'.repeat(60)));
|
|
93
|
-
this.log(recentOutput);
|
|
94
|
-
this.log(styles.muted('─'.repeat(60)));
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
else {
|
|
98
|
-
this.log(styles.muted(`Orchestrator "${flags.name}" is not running.`));
|
|
99
|
-
this.log(styles.muted('Start it with: prlt orchestrator start'));
|
|
100
|
-
}
|
|
101
|
-
this.log('');
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
// No --name: show status for ALL orchestrators in this HQ (host + Docker)
|
|
105
|
-
const hqSessions = findHQOrchestratorSessions(hostSessions, hqName);
|
|
106
|
-
const hqContainers = findHQOrchestratorContainers(hqName);
|
|
107
|
-
const allSessions = [
|
|
108
|
-
...hqSessions.map(s => ({ sessionId: s, name: extractOrchestratorNameFromSession(s, hqName) || s, environment: 'host', containerId: null })),
|
|
109
|
-
...hqContainers.map(c => ({ sessionId: c, name: extractOrchestratorNameFromSession(c, hqName) || c, environment: 'docker', containerId: getOrchestratorContainerId(c) })),
|
|
110
|
-
];
|
|
111
|
-
if (jsonMode) {
|
|
112
|
-
outputSuccessAsJson({
|
|
113
|
-
running: allSessions.length > 0,
|
|
114
|
-
sessions: allSessions,
|
|
115
|
-
}, createMetadata('orchestrator status', flags));
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
this.log('');
|
|
119
|
-
if (allSessions.length === 0) {
|
|
120
|
-
this.log(styles.muted('No orchestrator sessions running.'));
|
|
121
|
-
this.log(styles.muted('Start one with: prlt orchestrator start'));
|
|
122
|
-
}
|
|
123
|
-
else {
|
|
124
|
-
this.log(styles.success(`${allSessions.length} orchestrator session(s) running:`));
|
|
125
|
-
for (const s of allSessions) {
|
|
126
|
-
const envLabel = s.environment === 'docker' ? ' (Docker)' : '';
|
|
127
|
-
this.log(styles.muted(` ${s.name}${envLabel} (${s.sessionId})`));
|
|
128
|
-
this.log(styles.muted(` Attach: prlt orchestrator attach --name ${s.name}`));
|
|
129
|
-
if (flags.peek) {
|
|
130
|
-
let output = null;
|
|
131
|
-
if (s.environment === 'docker' && s.containerId) {
|
|
132
|
-
output = this.captureDockerTmuxPane(s.containerId, s.sessionId, flags.lines);
|
|
133
|
-
}
|
|
134
|
-
else {
|
|
135
|
-
output = captureTmuxPane(s.sessionId, flags.lines);
|
|
136
|
-
}
|
|
137
|
-
if (output) {
|
|
138
|
-
this.log(styles.muted('─'.repeat(60)));
|
|
139
|
-
this.log(output);
|
|
140
|
-
this.log(styles.muted('─'.repeat(60)));
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
this.log('');
|
|
146
|
-
return;
|
|
57
|
+
// Resolve HQ filter
|
|
58
|
+
let hqPathFilter;
|
|
59
|
+
if (flags.here) {
|
|
60
|
+
const cwdHq = findHQRoot(process.cwd());
|
|
61
|
+
if (cwdHq)
|
|
62
|
+
hqPathFilter = cwdHq;
|
|
147
63
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
64
|
+
else if (flags.hq) {
|
|
65
|
+
hqPathFilter = flags.hq;
|
|
66
|
+
}
|
|
67
|
+
// Always query machine-wide for orchestrator role.
|
|
68
|
+
let orchestrators = collectAllSessions({
|
|
69
|
+
hqPathFilter,
|
|
70
|
+
roleFilter: 'orchestrator',
|
|
71
|
+
includeAll: false,
|
|
72
|
+
});
|
|
73
|
+
// Optional --name filter (substring match against agentName/sessionId)
|
|
74
|
+
if (flags.name) {
|
|
75
|
+
const needle = flags.name.toLowerCase();
|
|
76
|
+
orchestrators = orchestrators.filter(s => s.agentName.toLowerCase().includes(needle) ||
|
|
77
|
+
s.sessionId.toLowerCase().includes(needle));
|
|
78
|
+
}
|
|
79
|
+
const grouped = groupSessionsByHQ(orchestrators);
|
|
155
80
|
if (jsonMode) {
|
|
156
81
|
outputSuccessAsJson({
|
|
157
|
-
running:
|
|
158
|
-
sessions:
|
|
82
|
+
running: orchestrators.length > 0,
|
|
83
|
+
sessions: orchestrators.map(toJsonOrchestrator),
|
|
84
|
+
grouped: {
|
|
85
|
+
current_hq: grouped.currentHq ? tildifyPath(grouped.currentHq) : null,
|
|
86
|
+
here: grouped.here.map(toJsonOrchestrator),
|
|
87
|
+
elsewhere: grouped.elsewhere.map(toJsonOrchestrator),
|
|
88
|
+
},
|
|
159
89
|
}, createMetadata('orchestrator status', flags));
|
|
160
90
|
return;
|
|
161
91
|
}
|
|
162
92
|
this.log('');
|
|
163
|
-
if (
|
|
93
|
+
if (orchestrators.length === 0) {
|
|
164
94
|
this.log(styles.muted('No orchestrator sessions running.'));
|
|
165
95
|
this.log(styles.muted('Start one with: prlt orchestrator start'));
|
|
96
|
+
this.log('');
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
// Render current HQ
|
|
100
|
+
if (grouped.currentHq) {
|
|
101
|
+
this.log(styles.header(`Current HQ: ${tildifyPath(grouped.currentHq)} (${grouped.here.length} orchestrator${grouped.here.length === 1 ? '' : 's'})`));
|
|
102
|
+
if (grouped.here.length === 0) {
|
|
103
|
+
this.log(styles.muted(' (none)'));
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
this.renderOrchestratorRows(grouped.here, flags.peek, flags.lines, /* dim */ false);
|
|
107
|
+
}
|
|
108
|
+
this.log('');
|
|
166
109
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
110
|
+
// Render elsewhere
|
|
111
|
+
if (grouped.elsewhere.length > 0) {
|
|
112
|
+
this.log(styles.muted(`Other locations (${grouped.elsewhere.length} orchestrator${grouped.elsewhere.length === 1 ? '' : 's'})`));
|
|
113
|
+
const buckets = bucketElsewhereByHq(grouped.elsewhere);
|
|
114
|
+
for (const bucket of buckets) {
|
|
115
|
+
const hqLabel = bucket.hqPath ? tildifyPath(bucket.hqPath) : '(no HQ)';
|
|
116
|
+
this.log(styles.muted(` ${bucket.hqName} — ${hqLabel}`));
|
|
117
|
+
this.renderOrchestratorRows(bucket.sessions, flags.peek, flags.lines, /* dim */ true);
|
|
118
|
+
}
|
|
119
|
+
this.log('');
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
renderOrchestratorRows(sessions, peek, lines, dim) {
|
|
123
|
+
for (const s of sessions) {
|
|
124
|
+
const envLabel = s.environment === 'container' ? ' (Docker)' : '';
|
|
125
|
+
const line = ` ${s.agentName}${envLabel} (${s.sessionId})`;
|
|
126
|
+
this.log(dim ? styles.muted(line) : styles.muted(line));
|
|
127
|
+
const attachCmd = s.agentName === 'main'
|
|
128
|
+
? ' Attach: prlt orchestrator attach'
|
|
129
|
+
: ` Attach: prlt orchestrator attach --name ${s.agentName}`;
|
|
130
|
+
this.log(styles.muted(attachCmd));
|
|
131
|
+
if (peek) {
|
|
132
|
+
let output = null;
|
|
133
|
+
if (s.environment === 'container' && s.containerId) {
|
|
134
|
+
output = this.captureDockerTmuxPane(s.containerId, s.sessionId, lines);
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
output = captureTmuxPane(s.sessionId, lines);
|
|
138
|
+
}
|
|
139
|
+
if (output) {
|
|
140
|
+
this.log(styles.muted('─'.repeat(60)));
|
|
141
|
+
this.log(output);
|
|
142
|
+
this.log(styles.muted('─'.repeat(60)));
|
|
179
143
|
}
|
|
180
144
|
}
|
|
181
145
|
}
|
|
182
|
-
this.log('');
|
|
183
146
|
}
|
|
184
147
|
}
|
|
148
|
+
function toJsonOrchestrator(s) {
|
|
149
|
+
return {
|
|
150
|
+
sessionId: s.sessionId,
|
|
151
|
+
name: s.agentName,
|
|
152
|
+
environment: s.environment === 'container' ? 'docker' : 'host',
|
|
153
|
+
containerId: s.containerId ?? null,
|
|
154
|
+
hqPath: s.hqPath ?? null,
|
|
155
|
+
hqName: s.hqName ?? null,
|
|
156
|
+
status: s.status,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
185
159
|
//# sourceMappingURL=status.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../../src/commands/orchestrator/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAC3D,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,cAAc,GACf,MAAM,0BAA0B,CAAA;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAC5C,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../../src/commands/orchestrator/status.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,6 +4,8 @@ export default class OrchestratorStop extends PromptCommand {
|
|
|
4
4
|
static examples: string[];
|
|
5
5
|
static flags: {
|
|
6
6
|
name: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
here: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
8
|
+
hq: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
9
|
force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
8
10
|
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
9
11
|
machine: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
@@ -6,10 +6,9 @@ import { machineOutputFlags } from '../../lib/pmo/index.js';
|
|
|
6
6
|
import { findHQRoot } from '../../lib/workspace.js';
|
|
7
7
|
import { shouldOutputJson, outputErrorAsJson, outputSuccessAsJson, outputPromptAsJson, buildPromptConfig, createMetadata, } from '../../lib/prompt-json.js';
|
|
8
8
|
import { styles } from '../../lib/styles.js';
|
|
9
|
-
import { getHostTmuxSessionNames } from '../../lib/execution/session-utils.js';
|
|
10
9
|
import { ExecutionStorage } from '../../lib/execution/storage.js';
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
10
|
+
import { MachineDB } from '../../lib/machine-db.js';
|
|
11
|
+
import { collectAllSessions, groupSessionsByHQ, tildifyPath, } from '../../lib/session/renderer.js';
|
|
13
12
|
export default class OrchestratorStop extends PromptCommand {
|
|
14
13
|
static description = 'Stop the running orchestrator';
|
|
15
14
|
static examples = [
|
|
@@ -20,7 +19,16 @@ export default class OrchestratorStop extends PromptCommand {
|
|
|
20
19
|
...machineOutputFlags,
|
|
21
20
|
name: Flags.string({
|
|
22
21
|
char: 'n',
|
|
23
|
-
description: 'Name of the orchestrator
|
|
22
|
+
description: 'Name of the orchestrator to stop (matches agentName)',
|
|
23
|
+
}),
|
|
24
|
+
here: Flags.boolean({
|
|
25
|
+
description: 'Filter to orchestrators in the current HQ only',
|
|
26
|
+
default: false,
|
|
27
|
+
exclusive: ['hq'],
|
|
28
|
+
}),
|
|
29
|
+
hq: Flags.string({
|
|
30
|
+
description: 'Filter to orchestrators in a specific HQ path',
|
|
31
|
+
exclusive: ['here'],
|
|
24
32
|
}),
|
|
25
33
|
force: Flags.boolean({
|
|
26
34
|
char: 'f',
|
|
@@ -31,118 +39,84 @@ export default class OrchestratorStop extends PromptCommand {
|
|
|
31
39
|
async run() {
|
|
32
40
|
const { flags } = await this.parse(OrchestratorStop);
|
|
33
41
|
const jsonMode = shouldOutputJson(flags);
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if (
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
// No --name: discover ALL orchestrators in this HQ (host + Docker)
|
|
62
|
-
const hqSessions = findHQOrchestratorSessions(hostSessions, hqName);
|
|
63
|
-
const hqContainers = findHQOrchestratorContainers(hqName);
|
|
64
|
-
const allSessions = [
|
|
65
|
-
...hqSessions.map(s => ({ name: extractOrchestratorNameFromSession(s, hqName) || s, value: s, isDocker: false })),
|
|
66
|
-
...hqContainers.map(c => ({ name: extractOrchestratorNameFromSession(c, hqName) || c, value: c, isDocker: true })),
|
|
67
|
-
];
|
|
68
|
-
if (allSessions.length === 1) {
|
|
69
|
-
sessionName = allSessions[0].value;
|
|
70
|
-
orchestratorName = allSessions[0].name;
|
|
71
|
-
isDockerSession = allSessions[0].isDocker;
|
|
72
|
-
}
|
|
73
|
-
else if (allSessions.length > 1) {
|
|
74
|
-
const sessionChoices = allSessions.map(s => ({
|
|
75
|
-
name: `${s.name}${s.isDocker ? ' (Docker)' : ''}`,
|
|
76
|
-
value: s.value,
|
|
77
|
-
command: `prlt orchestrator stop --name "${s.name}" --force --json`,
|
|
78
|
-
}));
|
|
79
|
-
const selectMessage = 'Multiple orchestrator sessions found. Select one to stop:';
|
|
80
|
-
if (jsonMode) {
|
|
81
|
-
outputPromptAsJson(buildPromptConfig('list', 'session', selectMessage, sessionChoices), createMetadata('orchestrator stop', flags));
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
const { session } = await this.prompt([{
|
|
85
|
-
type: 'list',
|
|
86
|
-
name: 'session',
|
|
87
|
-
message: selectMessage,
|
|
88
|
-
choices: sessionChoices,
|
|
89
|
-
}]);
|
|
90
|
-
sessionName = session;
|
|
91
|
-
const matched = allSessions.find(s => s.value === session);
|
|
92
|
-
orchestratorName = matched?.name;
|
|
93
|
-
isDockerSession = matched?.isDocker || false;
|
|
94
|
-
}
|
|
95
|
-
// If 0 found, fall through to global discovery below
|
|
42
|
+
// Resolve HQ filter
|
|
43
|
+
let hqPathFilter;
|
|
44
|
+
if (flags.here) {
|
|
45
|
+
const cwdHq = findHQRoot(process.cwd());
|
|
46
|
+
if (cwdHq)
|
|
47
|
+
hqPathFilter = cwdHq;
|
|
48
|
+
}
|
|
49
|
+
else if (flags.hq) {
|
|
50
|
+
hqPathFilter = flags.hq;
|
|
51
|
+
}
|
|
52
|
+
// Always query machine-wide for orchestrators.
|
|
53
|
+
let orchestrators = collectAllSessions({
|
|
54
|
+
hqPathFilter,
|
|
55
|
+
roleFilter: 'orchestrator',
|
|
56
|
+
includeAll: false,
|
|
57
|
+
});
|
|
58
|
+
// Optional --name filter
|
|
59
|
+
if (flags.name) {
|
|
60
|
+
const needle = flags.name.toLowerCase();
|
|
61
|
+
orchestrators = orchestrators.filter(s => s.agentName.toLowerCase() === needle ||
|
|
62
|
+
s.agentName.toLowerCase().includes(needle) ||
|
|
63
|
+
s.sessionId.toLowerCase().includes(needle));
|
|
64
|
+
}
|
|
65
|
+
if (orchestrators.length === 0) {
|
|
66
|
+
if (jsonMode) {
|
|
67
|
+
outputErrorAsJson('NOT_RUNNING', 'Orchestrator is not running.', createMetadata('orchestrator stop', flags));
|
|
68
|
+
return;
|
|
96
69
|
}
|
|
70
|
+
this.log('');
|
|
71
|
+
this.log(styles.muted('Orchestrator is not running.'));
|
|
72
|
+
this.log('');
|
|
73
|
+
return;
|
|
97
74
|
}
|
|
98
|
-
//
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
];
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
75
|
+
// Pick a single orchestrator. Prefer current-HQ when multiple exist.
|
|
76
|
+
let picked;
|
|
77
|
+
if (orchestrators.length === 1) {
|
|
78
|
+
picked = orchestrators[0];
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
const grouped = groupSessionsByHQ(orchestrators);
|
|
82
|
+
const ordered = [...grouped.here, ...grouped.elsewhere];
|
|
83
|
+
const selectMessage = 'Multiple orchestrator sessions found. Select one to stop:';
|
|
84
|
+
const sessionChoices = ordered.map(s => {
|
|
85
|
+
const hqLabel = s.hqPath ? tildifyPath(s.hqPath) : '(no HQ)';
|
|
86
|
+
const tag = s.environment === 'container' ? ' (Docker)' : '';
|
|
87
|
+
return {
|
|
88
|
+
name: `${s.agentName}${tag} — ${hqLabel}`,
|
|
89
|
+
value: s.sessionId,
|
|
90
|
+
command: `prlt orchestrator stop --name "${s.agentName}" --force --json`,
|
|
91
|
+
};
|
|
92
|
+
});
|
|
93
|
+
if (jsonMode) {
|
|
94
|
+
outputPromptAsJson(buildPromptConfig('list', 'session', selectMessage, sessionChoices), createMetadata('orchestrator stop', flags));
|
|
114
95
|
return;
|
|
115
96
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
97
|
+
// Print a grouped preview banner above the picker.
|
|
98
|
+
if (grouped.currentHq) {
|
|
99
|
+
this.log('');
|
|
100
|
+
this.log(styles.header(`Current HQ: ${tildifyPath(grouped.currentHq)} (${grouped.here.length} orchestrator${grouped.here.length === 1 ? '' : 's'})`));
|
|
119
101
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
const sessionChoices = allSessions.map(s => ({
|
|
123
|
-
name: s.name,
|
|
124
|
-
value: s.value,
|
|
125
|
-
command: `prlt orchestrator stop --name "${s.value}" --force --json`,
|
|
126
|
-
}));
|
|
127
|
-
const selectMessage = 'Multiple orchestrator sessions found. Select one to stop:';
|
|
128
|
-
if (jsonMode) {
|
|
129
|
-
outputPromptAsJson(buildPromptConfig('list', 'session', selectMessage, sessionChoices), createMetadata('orchestrator stop', flags));
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
|
-
const { session } = await this.prompt([{
|
|
133
|
-
type: 'list',
|
|
134
|
-
name: 'session',
|
|
135
|
-
message: selectMessage,
|
|
136
|
-
choices: sessionChoices,
|
|
137
|
-
}]);
|
|
138
|
-
sessionName = session;
|
|
139
|
-
const matched = allSessions.find(s => s.value === session);
|
|
140
|
-
isDockerSession = matched?.isDocker || false;
|
|
102
|
+
if (grouped.elsewhere.length > 0) {
|
|
103
|
+
this.log(styles.muted(`Other locations: ${grouped.elsewhere.length} orchestrator${grouped.elsewhere.length === 1 ? '' : 's'}`));
|
|
141
104
|
}
|
|
105
|
+
const { session } = await this.prompt([{
|
|
106
|
+
type: 'list',
|
|
107
|
+
name: 'session',
|
|
108
|
+
message: selectMessage,
|
|
109
|
+
choices: sessionChoices,
|
|
110
|
+
}]);
|
|
111
|
+
picked = ordered.find(s => s.sessionId === session);
|
|
142
112
|
}
|
|
143
|
-
if (!
|
|
113
|
+
if (!picked) {
|
|
144
114
|
return;
|
|
145
115
|
}
|
|
116
|
+
const sessionName = picked.sessionId;
|
|
117
|
+
const isDockerSession = picked.environment === 'container';
|
|
118
|
+
const orchestratorName = picked.agentName;
|
|
119
|
+
const hqPath = picked.hqPath ?? findHQRoot(process.cwd());
|
|
146
120
|
// Confirm unless --force
|
|
147
121
|
if (!flags.force && !jsonMode) {
|
|
148
122
|
const { confirmed } = await this.prompt([{
|
|
@@ -203,6 +177,30 @@ export default class OrchestratorStop extends PromptCommand {
|
|
|
203
177
|
db?.close();
|
|
204
178
|
}
|
|
205
179
|
}
|
|
180
|
+
// PRLT-1275: Update the machine.db mirror row so cross-HQ consumers
|
|
181
|
+
// (e.g. prlt session list from /tmp, the renderer) see the orchestrator
|
|
182
|
+
// as stopped. Non-fatal — machine.db is secondary.
|
|
183
|
+
try {
|
|
184
|
+
const machineDb = new MachineDB();
|
|
185
|
+
try {
|
|
186
|
+
const match = machineDb.findBySessionId(sessionName);
|
|
187
|
+
if (match) {
|
|
188
|
+
machineDb.updateStatus(match.id, 'stopped');
|
|
189
|
+
}
|
|
190
|
+
else if (orchestratorName) {
|
|
191
|
+
const rows = machineDb.getActiveByAgentPrefix(`orchestrator-${orchestratorName}`);
|
|
192
|
+
for (const row of rows) {
|
|
193
|
+
machineDb.updateStatus(row.id, 'stopped');
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
finally {
|
|
198
|
+
machineDb.close();
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
catch {
|
|
202
|
+
// Non-fatal
|
|
203
|
+
}
|
|
206
204
|
if (jsonMode) {
|
|
207
205
|
outputSuccessAsJson({
|
|
208
206
|
sessionId: sessionName,
|