@proletariat/cli 0.3.43 → 0.3.44

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.
@@ -0,0 +1,104 @@
1
+ import { Flags } from '@oclif/core';
2
+ import { execSync } from 'node:child_process';
3
+ import * as path from 'node:path';
4
+ import * as fs from 'node:fs';
5
+ import Database from 'better-sqlite3';
6
+ import { PromptCommand } from '../../lib/prompt-command.js';
7
+ import { machineOutputFlags } from '../../lib/pmo/index.js';
8
+ import { findHQRoot } from '../../lib/workspace.js';
9
+ import { shouldOutputJson, outputErrorAsJson, outputSuccessAsJson, createMetadata, } from '../../lib/prompt-json.js';
10
+ import { styles } from '../../lib/styles.js';
11
+ import { getHostTmuxSessionNames } from '../../lib/execution/session-utils.js';
12
+ import { ExecutionStorage } from '../../lib/execution/storage.js';
13
+ import { ORCHESTRATOR_SESSION_NAME } from './start.js';
14
+ export default class OrchestratorStop extends PromptCommand {
15
+ static description = 'Stop the running orchestrator';
16
+ static examples = [
17
+ '<%= config.bin %> <%= command.id %>',
18
+ '<%= config.bin %> <%= command.id %> --force',
19
+ ];
20
+ static flags = {
21
+ ...machineOutputFlags,
22
+ force: Flags.boolean({
23
+ char: 'f',
24
+ description: 'Skip confirmation',
25
+ default: false,
26
+ }),
27
+ };
28
+ async run() {
29
+ const { flags } = await this.parse(OrchestratorStop);
30
+ const jsonMode = shouldOutputJson(flags);
31
+ // Check if orchestrator session exists
32
+ const hostSessions = getHostTmuxSessionNames();
33
+ if (!hostSessions.includes(ORCHESTRATOR_SESSION_NAME)) {
34
+ if (jsonMode) {
35
+ outputErrorAsJson('NOT_RUNNING', 'Orchestrator is not running.', createMetadata('orchestrator stop', flags));
36
+ return;
37
+ }
38
+ this.log('');
39
+ this.log(styles.muted('Orchestrator is not running.'));
40
+ this.log('');
41
+ return;
42
+ }
43
+ // Confirm unless --force
44
+ if (!flags.force && !jsonMode) {
45
+ const { confirmed } = await this.prompt([{
46
+ type: 'list',
47
+ name: 'confirmed',
48
+ message: 'Stop the orchestrator?',
49
+ choices: [
50
+ { name: 'Yes', value: true },
51
+ { name: 'No', value: false },
52
+ ],
53
+ }]);
54
+ if (!confirmed) {
55
+ this.log(styles.muted('Cancelled.'));
56
+ return;
57
+ }
58
+ }
59
+ // Kill the tmux session
60
+ try {
61
+ execSync(`tmux kill-session -t "${ORCHESTRATOR_SESSION_NAME}"`, { stdio: 'pipe' });
62
+ }
63
+ catch (error) {
64
+ if (jsonMode) {
65
+ outputErrorAsJson('KILL_FAILED', `Failed to stop orchestrator: ${error instanceof Error ? error.message : error}`, createMetadata('orchestrator stop', flags));
66
+ return;
67
+ }
68
+ this.error(`Failed to stop orchestrator: ${error instanceof Error ? error.message : error}`);
69
+ }
70
+ // Update execution record to stopped
71
+ const hqPath = findHQRoot(process.cwd());
72
+ if (hqPath) {
73
+ const dbPath = path.join(hqPath, '.proletariat', 'workspace.db');
74
+ if (fs.existsSync(dbPath)) {
75
+ let db = null;
76
+ try {
77
+ db = new Database(dbPath);
78
+ const executionStorage = new ExecutionStorage(db);
79
+ const running = executionStorage.listExecutions({ agentName: 'orchestrator', status: 'running' });
80
+ const starting = executionStorage.listExecutions({ agentName: 'orchestrator', status: 'starting' });
81
+ for (const exec of [...running, ...starting]) {
82
+ executionStorage.updateStatus(exec.id, 'stopped');
83
+ }
84
+ }
85
+ catch {
86
+ // Non-fatal
87
+ }
88
+ finally {
89
+ db?.close();
90
+ }
91
+ }
92
+ }
93
+ if (jsonMode) {
94
+ outputSuccessAsJson({
95
+ sessionId: ORCHESTRATOR_SESSION_NAME,
96
+ status: 'stopped',
97
+ }, createMetadata('orchestrator stop', flags));
98
+ return;
99
+ }
100
+ this.log('');
101
+ this.log(styles.success('Orchestrator stopped.'));
102
+ this.log('');
103
+ }
104
+ }