@proletariat/cli 0.3.19 → 0.3.21
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/agent/login.js +2 -2
- package/dist/commands/agent/remove.d.ts +1 -0
- package/dist/commands/agent/remove.js +36 -28
- package/dist/commands/agent/shell.js +2 -2
- package/dist/commands/agent/staff/remove.d.ts +1 -0
- package/dist/commands/agent/staff/remove.js +36 -28
- package/dist/commands/agent/status.js +2 -2
- package/dist/commands/agent/temp/cleanup.js +10 -17
- package/dist/commands/agent/themes/add-names.d.ts +1 -0
- package/dist/commands/agent/themes/add-names.js +5 -1
- package/dist/commands/agent/visit.js +2 -2
- package/dist/commands/board/view.d.ts +15 -0
- package/dist/commands/board/view.js +136 -0
- package/dist/commands/config/index.js +6 -3
- package/dist/commands/epic/link/index.js +17 -0
- package/dist/commands/execution/config.d.ts +34 -0
- package/dist/commands/execution/config.js +433 -0
- package/dist/commands/execution/index.js +6 -1
- package/dist/commands/execution/kill.d.ts +12 -0
- package/dist/commands/execution/kill.js +17 -0
- package/dist/commands/execution/list.js +5 -4
- package/dist/commands/execution/logs.js +1 -0
- package/dist/commands/execution/view.d.ts +17 -0
- package/dist/commands/execution/view.js +288 -0
- package/dist/commands/phase/move.js +8 -0
- package/dist/commands/phase/template/apply.js +2 -2
- package/dist/commands/phase/template/create.js +67 -20
- package/dist/commands/phase/template/list.js +1 -1
- package/dist/commands/pr/index.js +6 -2
- package/dist/commands/pr/list.d.ts +17 -0
- package/dist/commands/pr/list.js +163 -0
- package/dist/commands/project/update.d.ts +19 -0
- package/dist/commands/project/update.js +163 -0
- package/dist/commands/roadmap/create.js +5 -0
- package/dist/commands/spec/delete.d.ts +18 -0
- package/dist/commands/spec/delete.js +111 -0
- package/dist/commands/spec/edit.d.ts +23 -0
- package/dist/commands/spec/edit.js +232 -0
- package/dist/commands/spec/index.js +5 -0
- package/dist/commands/status/create.js +38 -34
- package/dist/commands/status/list.js +5 -3
- package/dist/commands/template/phase/create.d.ts +1 -0
- package/dist/commands/template/phase/create.js +10 -1
- package/dist/commands/template/phase/index.js +4 -4
- package/dist/commands/template/ticket/create.d.ts +20 -0
- package/dist/commands/template/ticket/create.js +87 -0
- package/dist/commands/template/ticket/delete.d.ts +1 -1
- package/dist/commands/template/ticket/delete.js +4 -2
- package/dist/commands/template/ticket/save.d.ts +2 -0
- package/dist/commands/template/ticket/save.js +11 -0
- package/dist/commands/ticket/create.js +8 -1
- package/dist/commands/ticket/edit.js +1 -1
- package/dist/commands/ticket/list.d.ts +2 -0
- package/dist/commands/ticket/list.js +39 -2
- package/dist/commands/ticket/template/create.d.ts +9 -1
- package/dist/commands/ticket/template/create.js +224 -52
- package/dist/commands/ticket/template/save.d.ts +2 -1
- package/dist/commands/ticket/template/save.js +58 -7
- package/dist/commands/ticket/update.js +2 -2
- package/dist/commands/work/ready.js +8 -8
- package/dist/commands/work/spawn.js +32 -8
- package/dist/commands/work/watch.js +2 -0
- package/dist/lib/agents/commands.d.ts +7 -0
- package/dist/lib/agents/commands.js +11 -0
- package/dist/lib/agents/index.js +14 -4
- package/dist/lib/branch/index.js +24 -0
- package/dist/lib/execution/config.d.ts +2 -0
- package/dist/lib/execution/config.js +12 -0
- package/dist/lib/execution/runners.js +1 -2
- package/dist/lib/pmo/storage/epics.js +20 -10
- package/dist/lib/pmo/storage/helpers.d.ts +10 -0
- package/dist/lib/pmo/storage/helpers.js +59 -1
- package/dist/lib/pmo/storage/projects.js +20 -8
- package/dist/lib/pmo/storage/specs.js +23 -13
- package/dist/lib/pmo/storage/statuses.js +39 -18
- package/dist/lib/pmo/storage/subtasks.js +19 -8
- package/dist/lib/pmo/storage/tickets.js +27 -15
- package/dist/lib/pmo/utils.d.ts +4 -2
- package/dist/lib/pmo/utils.js +4 -2
- package/oclif.manifest.json +4037 -3234
- package/package.json +2 -4
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
import { Flags } from '@oclif/core';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
import Database from 'better-sqlite3';
|
|
4
|
+
import inquirer from 'inquirer';
|
|
5
|
+
import { PMOCommand, pmoBaseFlags } from '../../lib/pmo/index.js';
|
|
6
|
+
import { styles } from '../../lib/styles.js';
|
|
7
|
+
import { getWorkspaceInfo } from '../../lib/agents/commands.js';
|
|
8
|
+
import { loadExecutionConfig, saveTerminalApp, saveTerminalOpenInBackground, saveTmuxControlMode, saveShell, saveExecutionSetting, } from '../../lib/execution/config.js';
|
|
9
|
+
import { shouldOutputJson, isAgentMode, outputPromptAsJson, outputSuccessAsJson, outputErrorAsJson, createMetadata, normalizeChoices, } from '../../lib/prompt-json.js';
|
|
10
|
+
export default class ExecutionConfig extends PMOCommand {
|
|
11
|
+
static description = 'View and update execution preferences';
|
|
12
|
+
static examples = [
|
|
13
|
+
'<%= config.bin %> execution config # Interactive menu',
|
|
14
|
+
'<%= config.bin %> execution config --json # Output current config as JSON',
|
|
15
|
+
'<%= config.bin %> execution config --list # Show all settings',
|
|
16
|
+
'<%= config.bin %> execution config --set defaultEnvironment host',
|
|
17
|
+
'<%= config.bin %> execution config --set outputMode interactive',
|
|
18
|
+
'<%= config.bin %> execution config --set sandboxed true',
|
|
19
|
+
'<%= config.bin %> execution config --setting outputMode --json # Show output mode choices',
|
|
20
|
+
];
|
|
21
|
+
static flags = {
|
|
22
|
+
...pmoBaseFlags,
|
|
23
|
+
json: Flags.boolean({
|
|
24
|
+
description: 'Output configuration as JSON (for AI agents/scripts)',
|
|
25
|
+
default: false,
|
|
26
|
+
}),
|
|
27
|
+
set: Flags.string({
|
|
28
|
+
char: 's',
|
|
29
|
+
description: 'Set a config value (format: key value)',
|
|
30
|
+
multiple: true,
|
|
31
|
+
}),
|
|
32
|
+
list: Flags.boolean({
|
|
33
|
+
char: 'l',
|
|
34
|
+
description: 'List all configuration values',
|
|
35
|
+
default: false,
|
|
36
|
+
}),
|
|
37
|
+
setting: Flags.string({
|
|
38
|
+
description: 'Navigate to a specific setting prompt (for agent navigation)',
|
|
39
|
+
}),
|
|
40
|
+
};
|
|
41
|
+
getPMOOptions() {
|
|
42
|
+
return { promptIfMultiple: false };
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Prompt wrapper - drop-in replacement for inquirer.prompt
|
|
46
|
+
*/
|
|
47
|
+
async promptUser(questions, jsonModeConfig) {
|
|
48
|
+
if (jsonModeConfig && isAgentMode(jsonModeConfig.flags)) {
|
|
49
|
+
const firstQuestion = questions[0];
|
|
50
|
+
if (firstQuestion) {
|
|
51
|
+
const choices = firstQuestion.choices
|
|
52
|
+
? normalizeChoices(firstQuestion.choices)
|
|
53
|
+
: undefined;
|
|
54
|
+
outputPromptAsJson({
|
|
55
|
+
type: firstQuestion.type,
|
|
56
|
+
name: firstQuestion.name,
|
|
57
|
+
message: firstQuestion.message,
|
|
58
|
+
choices,
|
|
59
|
+
default: firstQuestion.default,
|
|
60
|
+
}, createMetadata(jsonModeConfig.commandName, jsonModeConfig.flags));
|
|
61
|
+
}
|
|
62
|
+
return {};
|
|
63
|
+
}
|
|
64
|
+
return inquirer.prompt(questions);
|
|
65
|
+
}
|
|
66
|
+
async execute() {
|
|
67
|
+
const { flags } = await this.parse(ExecutionConfig);
|
|
68
|
+
const jsonMode = shouldOutputJson(flags);
|
|
69
|
+
const jsonModeConfig = jsonMode ? { flags, commandName: 'execution config' } : null;
|
|
70
|
+
// Get workspace info
|
|
71
|
+
let workspaceInfo;
|
|
72
|
+
try {
|
|
73
|
+
workspaceInfo = getWorkspaceInfo();
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
if (jsonMode) {
|
|
77
|
+
outputErrorAsJson('NOT_IN_WORKSPACE', 'Not in a workspace. Run "prlt init" first.', createMetadata('execution config', flags));
|
|
78
|
+
this.exit(1);
|
|
79
|
+
}
|
|
80
|
+
this.error('Not in a workspace. Run "prlt init" first.');
|
|
81
|
+
}
|
|
82
|
+
// Open database
|
|
83
|
+
const dbPath = path.join(workspaceInfo.path, '.proletariat', 'workspace.db');
|
|
84
|
+
const db = new Database(dbPath);
|
|
85
|
+
try {
|
|
86
|
+
// Load current config
|
|
87
|
+
const config = loadExecutionConfig(db);
|
|
88
|
+
// Handle --set flag
|
|
89
|
+
if (flags.set && flags.set.length > 0) {
|
|
90
|
+
for (const setValue of flags.set) {
|
|
91
|
+
const [key, ...valueParts] = setValue.split(' ');
|
|
92
|
+
const value = valueParts.join(' ');
|
|
93
|
+
if (!key || !value) {
|
|
94
|
+
if (jsonMode) {
|
|
95
|
+
outputErrorAsJson('INVALID_SET_FORMAT', `Invalid format: "${setValue}". Use: --set "key value"`, createMetadata('execution config', flags));
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
this.error(`Invalid format: "${setValue}". Use: --set "key value"`);
|
|
99
|
+
}
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
this.setConfigValue(db, key, value, jsonMode);
|
|
103
|
+
}
|
|
104
|
+
db.close();
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
// Handle --list or --json flag without --setting (just show config)
|
|
108
|
+
if ((flags.list || flags.json) && !flags.setting) {
|
|
109
|
+
if (jsonMode) {
|
|
110
|
+
outputSuccessAsJson({
|
|
111
|
+
terminal: {
|
|
112
|
+
app: config.terminal.app,
|
|
113
|
+
openInBackground: config.terminal.openInBackground,
|
|
114
|
+
},
|
|
115
|
+
shell: config.shell,
|
|
116
|
+
tmux: {
|
|
117
|
+
controlMode: config.tmux.controlMode,
|
|
118
|
+
},
|
|
119
|
+
defaultEnvironment: config.defaultEnvironment,
|
|
120
|
+
defaultExecutor: config.defaultExecutor,
|
|
121
|
+
outputMode: config.outputMode,
|
|
122
|
+
sandboxed: config.sandboxed,
|
|
123
|
+
}, createMetadata('execution config', flags));
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
this.log('');
|
|
127
|
+
this.log(styles.header('Execution Configuration'));
|
|
128
|
+
this.log('═'.repeat(50));
|
|
129
|
+
this.log('');
|
|
130
|
+
this.log(styles.emphasis('Environment'));
|
|
131
|
+
this.log(` defaultEnvironment: ${config.defaultEnvironment}`);
|
|
132
|
+
this.log(` defaultExecutor: ${config.defaultExecutor}`);
|
|
133
|
+
this.log('');
|
|
134
|
+
this.log(styles.emphasis('Output'));
|
|
135
|
+
this.log(` outputMode: ${config.outputMode}`);
|
|
136
|
+
this.log(` sandboxed: ${config.sandboxed}`);
|
|
137
|
+
this.log('');
|
|
138
|
+
this.log(styles.emphasis('Terminal'));
|
|
139
|
+
this.log(` app: ${config.terminal.app}`);
|
|
140
|
+
this.log(` openInBackground: ${config.terminal.openInBackground}`);
|
|
141
|
+
this.log('');
|
|
142
|
+
this.log(styles.emphasis('Shell'));
|
|
143
|
+
this.log(` shell: ${config.shell}`);
|
|
144
|
+
this.log('');
|
|
145
|
+
this.log(styles.emphasis('Tmux'));
|
|
146
|
+
this.log(` controlMode: ${config.tmux.controlMode}`);
|
|
147
|
+
this.log('');
|
|
148
|
+
}
|
|
149
|
+
db.close();
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
// Handle --setting flag (navigate directly to a sub-prompt)
|
|
153
|
+
if (flags.setting) {
|
|
154
|
+
await this.handleSettingPrompt(db, config, flags.setting, jsonModeConfig);
|
|
155
|
+
db.close();
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
// Interactive menu
|
|
159
|
+
const settingChoices = [
|
|
160
|
+
{ name: `Default Environment: ${config.defaultEnvironment}`, value: 'defaultEnvironment', command: 'prlt execution config --setting defaultEnvironment --json' },
|
|
161
|
+
{ name: `Output Mode: ${config.outputMode}`, value: 'outputMode', command: 'prlt execution config --setting outputMode --json' },
|
|
162
|
+
{ name: `Permission Mode: ${config.sandboxed ? 'safe' : 'danger'}`, value: 'sandboxed', command: 'prlt execution config --setting sandboxed --json' },
|
|
163
|
+
{ name: `Terminal App: ${config.terminal.app}`, value: 'terminal.app', command: 'prlt execution config --setting terminal.app --json' },
|
|
164
|
+
{ name: `Open Tabs in Background: ${config.terminal.openInBackground}`, value: 'terminal.openInBackground', command: 'prlt execution config --setting terminal.openInBackground --json' },
|
|
165
|
+
{ name: `Shell: ${config.shell}`, value: 'shell', command: 'prlt execution config --setting shell --json' },
|
|
166
|
+
{ name: `Tmux Control Mode: ${config.tmux.controlMode}`, value: 'tmux.controlMode', command: 'prlt execution config --setting tmux.controlMode --json' },
|
|
167
|
+
];
|
|
168
|
+
const { setting } = await this.promptUser([
|
|
169
|
+
{
|
|
170
|
+
type: 'list',
|
|
171
|
+
name: 'setting',
|
|
172
|
+
message: 'Select setting to configure:',
|
|
173
|
+
choices: [
|
|
174
|
+
new inquirer.Separator('── Execution ──'),
|
|
175
|
+
...settingChoices.slice(0, 3),
|
|
176
|
+
new inquirer.Separator('── Terminal ──'),
|
|
177
|
+
...settingChoices.slice(3, 5),
|
|
178
|
+
new inquirer.Separator('── Shell ──'),
|
|
179
|
+
settingChoices[5],
|
|
180
|
+
new inquirer.Separator('── Tmux ──'),
|
|
181
|
+
settingChoices[6],
|
|
182
|
+
new inquirer.Separator(),
|
|
183
|
+
{ name: 'Exit', value: '__exit__' },
|
|
184
|
+
],
|
|
185
|
+
},
|
|
186
|
+
], jsonModeConfig);
|
|
187
|
+
if (setting === '__exit__') {
|
|
188
|
+
db.close();
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
// Handle the selected setting
|
|
192
|
+
await this.handleSettingPrompt(db, config, setting, jsonModeConfig);
|
|
193
|
+
db.close();
|
|
194
|
+
}
|
|
195
|
+
catch (error) {
|
|
196
|
+
db.close();
|
|
197
|
+
throw error;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Handle a specific setting's sub-prompt
|
|
202
|
+
*/
|
|
203
|
+
async handleSettingPrompt(db, config, setting, jsonModeConfig) {
|
|
204
|
+
switch (setting) {
|
|
205
|
+
case 'defaultEnvironment': {
|
|
206
|
+
const envChoices = [
|
|
207
|
+
{ name: 'host - Run directly on host machine', value: 'host', command: 'prlt execution config --set "defaultEnvironment host" --json' },
|
|
208
|
+
{ name: 'devcontainer - Run in a devcontainer (sandboxed)', value: 'devcontainer', command: 'prlt execution config --set "defaultEnvironment devcontainer" --json' },
|
|
209
|
+
{ name: 'docker - Run in a Docker container', value: 'docker', command: 'prlt execution config --set "defaultEnvironment docker" --json' },
|
|
210
|
+
{ name: 'vm - Run on a remote VM', value: 'vm', command: 'prlt execution config --set "defaultEnvironment vm" --json' },
|
|
211
|
+
];
|
|
212
|
+
const { newEnv } = await this.promptUser([
|
|
213
|
+
{
|
|
214
|
+
type: 'list',
|
|
215
|
+
name: 'newEnv',
|
|
216
|
+
message: 'Select default execution environment:',
|
|
217
|
+
choices: envChoices,
|
|
218
|
+
default: config.defaultEnvironment,
|
|
219
|
+
},
|
|
220
|
+
], jsonModeConfig);
|
|
221
|
+
saveExecutionSetting(db, 'defaultMode', newEnv);
|
|
222
|
+
this.log(styles.success(`Default environment set to: ${newEnv}`));
|
|
223
|
+
break;
|
|
224
|
+
}
|
|
225
|
+
case 'outputMode': {
|
|
226
|
+
const outputChoices = [
|
|
227
|
+
{ name: 'interactive - Watch Claude work in real-time (streaming UI)', value: 'interactive', command: 'prlt execution config --set "outputMode interactive" --json' },
|
|
228
|
+
{ name: 'print - Show final result only (better for logs)', value: 'print', command: 'prlt execution config --set "outputMode print" --json' },
|
|
229
|
+
];
|
|
230
|
+
const { newOutput } = await this.promptUser([
|
|
231
|
+
{
|
|
232
|
+
type: 'list',
|
|
233
|
+
name: 'newOutput',
|
|
234
|
+
message: 'Select output mode:',
|
|
235
|
+
choices: outputChoices,
|
|
236
|
+
default: config.outputMode,
|
|
237
|
+
},
|
|
238
|
+
], jsonModeConfig);
|
|
239
|
+
this.setConfigValue(db, 'outputMode', newOutput, false);
|
|
240
|
+
this.log(styles.success(`Output mode set to: ${newOutput}`));
|
|
241
|
+
break;
|
|
242
|
+
}
|
|
243
|
+
case 'sandboxed': {
|
|
244
|
+
const permChoices = [
|
|
245
|
+
{ name: 'safe - Requires approval for dangerous operations (recommended)', value: 'true', command: 'prlt execution config --set "sandboxed true" --json' },
|
|
246
|
+
{ name: 'danger - Skip permission checks (--dangerously-skip-permissions)', value: 'false', command: 'prlt execution config --set "sandboxed false" --json' },
|
|
247
|
+
];
|
|
248
|
+
const { newPerm } = await this.promptUser([
|
|
249
|
+
{
|
|
250
|
+
type: 'list',
|
|
251
|
+
name: 'newPerm',
|
|
252
|
+
message: 'Select permission mode:',
|
|
253
|
+
choices: permChoices,
|
|
254
|
+
default: String(config.sandboxed),
|
|
255
|
+
},
|
|
256
|
+
], jsonModeConfig);
|
|
257
|
+
this.setConfigValue(db, 'sandboxed', newPerm, false);
|
|
258
|
+
this.log(styles.success(`Permission mode set to: ${newPerm === 'true' ? 'safe' : 'danger'}`));
|
|
259
|
+
break;
|
|
260
|
+
}
|
|
261
|
+
case 'terminal.app': {
|
|
262
|
+
const appChoices = [
|
|
263
|
+
{ name: 'iTerm', value: 'iTerm', command: 'prlt execution config --set "terminal.app iTerm" --json' },
|
|
264
|
+
{ name: 'Terminal.app (macOS default)', value: 'Terminal', command: 'prlt execution config --set "terminal.app Terminal" --json' },
|
|
265
|
+
{ name: 'Ghostty', value: 'Ghostty', command: 'prlt execution config --set "terminal.app Ghostty" --json' },
|
|
266
|
+
{ name: 'Alacritty', value: 'Alacritty', command: 'prlt execution config --set "terminal.app Alacritty" --json' },
|
|
267
|
+
{ name: 'Kitty', value: 'Kitty', command: 'prlt execution config --set "terminal.app Kitty" --json' },
|
|
268
|
+
{ name: 'WezTerm', value: 'WezTerm', command: 'prlt execution config --set "terminal.app WezTerm" --json' },
|
|
269
|
+
{ name: 'Warp', value: 'Warp', command: 'prlt execution config --set "terminal.app Warp" --json' },
|
|
270
|
+
{ name: 'tmux', value: 'tmux', command: 'prlt execution config --set "terminal.app tmux" --json' },
|
|
271
|
+
];
|
|
272
|
+
const { newApp } = await this.promptUser([
|
|
273
|
+
{
|
|
274
|
+
type: 'list',
|
|
275
|
+
name: 'newApp',
|
|
276
|
+
message: 'Select terminal app:',
|
|
277
|
+
choices: appChoices,
|
|
278
|
+
default: config.terminal.app,
|
|
279
|
+
},
|
|
280
|
+
], jsonModeConfig);
|
|
281
|
+
saveTerminalApp(db, newApp);
|
|
282
|
+
this.log(styles.success(`Terminal app set to: ${newApp}`));
|
|
283
|
+
break;
|
|
284
|
+
}
|
|
285
|
+
case 'terminal.openInBackground': {
|
|
286
|
+
const bgChoices = [
|
|
287
|
+
{ name: 'Yes - Open tabs in background (don\'t steal focus)', value: 'true', command: 'prlt execution config --set "terminal.openInBackground true" --json' },
|
|
288
|
+
{ name: 'No - Bring terminal to foreground when opening tabs', value: 'false', command: 'prlt execution config --set "terminal.openInBackground false" --json' },
|
|
289
|
+
];
|
|
290
|
+
const { openInBg } = await this.promptUser([
|
|
291
|
+
{
|
|
292
|
+
type: 'list',
|
|
293
|
+
name: 'openInBg',
|
|
294
|
+
message: 'Open terminal tabs in background?',
|
|
295
|
+
choices: bgChoices,
|
|
296
|
+
default: String(config.terminal.openInBackground),
|
|
297
|
+
},
|
|
298
|
+
], jsonModeConfig);
|
|
299
|
+
saveTerminalOpenInBackground(db, openInBg === 'true');
|
|
300
|
+
this.log(styles.success(`Open in background set to: ${openInBg}`));
|
|
301
|
+
break;
|
|
302
|
+
}
|
|
303
|
+
case 'shell': {
|
|
304
|
+
const shellChoices = [
|
|
305
|
+
{ name: 'zsh (macOS default)', value: 'zsh', command: 'prlt execution config --set "shell zsh" --json' },
|
|
306
|
+
{ name: 'bash', value: 'bash', command: 'prlt execution config --set "shell bash" --json' },
|
|
307
|
+
{ name: 'fish', value: 'fish', command: 'prlt execution config --set "shell fish" --json' },
|
|
308
|
+
];
|
|
309
|
+
const { newShell } = await this.promptUser([
|
|
310
|
+
{
|
|
311
|
+
type: 'list',
|
|
312
|
+
name: 'newShell',
|
|
313
|
+
message: 'Select shell:',
|
|
314
|
+
choices: shellChoices,
|
|
315
|
+
default: config.shell,
|
|
316
|
+
},
|
|
317
|
+
], jsonModeConfig);
|
|
318
|
+
saveShell(db, newShell);
|
|
319
|
+
this.log(styles.success(`Shell set to: ${newShell}`));
|
|
320
|
+
break;
|
|
321
|
+
}
|
|
322
|
+
case 'tmux.controlMode': {
|
|
323
|
+
const ccChoices = [
|
|
324
|
+
{ name: 'Yes - Use tmux -CC for native iTerm integration', value: 'true', command: 'prlt execution config --set "tmux.controlMode true" --json' },
|
|
325
|
+
{ name: 'No - Standard tmux interface', value: 'false', command: 'prlt execution config --set "tmux.controlMode false" --json' },
|
|
326
|
+
];
|
|
327
|
+
const { controlMode } = await this.promptUser([
|
|
328
|
+
{
|
|
329
|
+
type: 'list',
|
|
330
|
+
name: 'controlMode',
|
|
331
|
+
message: 'Enable tmux control mode (-CC)?',
|
|
332
|
+
choices: ccChoices,
|
|
333
|
+
default: String(config.tmux.controlMode),
|
|
334
|
+
},
|
|
335
|
+
], jsonModeConfig);
|
|
336
|
+
saveTmuxControlMode(db, controlMode === 'true');
|
|
337
|
+
this.log(styles.success(`Tmux control mode set to: ${controlMode}`));
|
|
338
|
+
break;
|
|
339
|
+
}
|
|
340
|
+
default: {
|
|
341
|
+
const jsonMode = shouldOutputJson(jsonModeConfig?.flags ?? {});
|
|
342
|
+
if (jsonMode) {
|
|
343
|
+
outputErrorAsJson('UNKNOWN_SETTING', `Unknown setting: ${setting}`, createMetadata('execution config', jsonModeConfig?.flags ?? {}));
|
|
344
|
+
}
|
|
345
|
+
this.error(`Unknown setting: ${setting}`);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
setConfigValue(db, key, value, jsonMode) {
|
|
350
|
+
const normalizedKey = key.toLowerCase();
|
|
351
|
+
// Define valid values for each config key
|
|
352
|
+
const VALID_VALUES = {
|
|
353
|
+
defaultenvironment: ['host', 'devcontainer', 'docker', 'vm'],
|
|
354
|
+
outputmode: ['interactive', 'print'],
|
|
355
|
+
sandboxed: ['true', 'false'],
|
|
356
|
+
'terminal.app': ['Terminal', 'iTerm', 'Alacritty', 'Ghostty', 'Kitty', 'tmux', 'Warp', 'WezTerm'],
|
|
357
|
+
'terminal.openinbackground': ['true', 'false'],
|
|
358
|
+
shell: ['bash', 'zsh', 'fish'],
|
|
359
|
+
'tmux.controlmode': ['true', 'false'],
|
|
360
|
+
};
|
|
361
|
+
// Validate value against allowed options
|
|
362
|
+
const validValues = VALID_VALUES[normalizedKey];
|
|
363
|
+
if (validValues && !validValues.includes(value)) {
|
|
364
|
+
const errorMsg = `Invalid value "${value}" for ${key}. Valid options: ${validValues.join(', ')}`;
|
|
365
|
+
if (jsonMode) {
|
|
366
|
+
outputErrorAsJson('INVALID_VALUE', errorMsg, createMetadata('execution config', {}));
|
|
367
|
+
}
|
|
368
|
+
else {
|
|
369
|
+
this.error(errorMsg);
|
|
370
|
+
}
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
switch (normalizedKey) {
|
|
374
|
+
case 'defaultenvironment':
|
|
375
|
+
saveExecutionSetting(db, 'defaultMode', value);
|
|
376
|
+
break;
|
|
377
|
+
case 'outputmode':
|
|
378
|
+
// Store output mode - need to add this to the config storage
|
|
379
|
+
this.setOutputMode(db, value);
|
|
380
|
+
break;
|
|
381
|
+
case 'sandboxed':
|
|
382
|
+
// Store sandboxed preference
|
|
383
|
+
this.setSandboxed(db, value.toLowerCase() === 'true');
|
|
384
|
+
break;
|
|
385
|
+
case 'terminal.app':
|
|
386
|
+
saveTerminalApp(db, value);
|
|
387
|
+
break;
|
|
388
|
+
case 'terminal.openinbackground':
|
|
389
|
+
saveTerminalOpenInBackground(db, value.toLowerCase() === 'true');
|
|
390
|
+
break;
|
|
391
|
+
case 'shell':
|
|
392
|
+
saveShell(db, value);
|
|
393
|
+
break;
|
|
394
|
+
case 'tmux.controlmode':
|
|
395
|
+
saveTmuxControlMode(db, value.toLowerCase() === 'true');
|
|
396
|
+
break;
|
|
397
|
+
default:
|
|
398
|
+
if (jsonMode) {
|
|
399
|
+
outputErrorAsJson('UNKNOWN_KEY', `Unknown config key: ${key}`, createMetadata('execution config', {}));
|
|
400
|
+
}
|
|
401
|
+
else {
|
|
402
|
+
this.warn(`Unknown config key: ${key}`);
|
|
403
|
+
}
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
if (jsonMode) {
|
|
407
|
+
outputSuccessAsJson({ key, value }, createMetadata('execution config', {}));
|
|
408
|
+
}
|
|
409
|
+
else {
|
|
410
|
+
this.log(styles.success(`Set ${key} = ${value}`));
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Save output mode to workspace settings
|
|
415
|
+
*/
|
|
416
|
+
setOutputMode(db, mode) {
|
|
417
|
+
db.prepare(`
|
|
418
|
+
INSERT INTO workspace_settings (key, value)
|
|
419
|
+
VALUES (?, ?)
|
|
420
|
+
ON CONFLICT(key) DO UPDATE SET value = excluded.value
|
|
421
|
+
`).run('execution.output_mode', mode);
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Save sandboxed preference to workspace settings
|
|
425
|
+
*/
|
|
426
|
+
setSandboxed(db, sandboxed) {
|
|
427
|
+
db.prepare(`
|
|
428
|
+
INSERT INTO workspace_settings (key, value)
|
|
429
|
+
VALUES (?, ?)
|
|
430
|
+
ON CONFLICT(key) DO UPDATE SET value = excluded.value
|
|
431
|
+
`).run('execution.sandboxed', sandboxed.toString());
|
|
432
|
+
}
|
|
433
|
+
}
|
|
@@ -2,9 +2,10 @@ import { Flags } from '@oclif/core';
|
|
|
2
2
|
import inquirer from 'inquirer';
|
|
3
3
|
import { PMOCommand, pmoBaseFlags } from '../../lib/pmo/index.js';
|
|
4
4
|
export default class Execution extends PMOCommand {
|
|
5
|
-
static description = 'Single execution operations (logs, stop)';
|
|
5
|
+
static description = 'Single execution operations (view, logs, stop)';
|
|
6
6
|
static examples = [
|
|
7
7
|
'<%= config.bin %> <%= command.id %>',
|
|
8
|
+
'<%= config.bin %> <%= command.id %> view WORK-001',
|
|
8
9
|
'<%= config.bin %> <%= command.id %> logs WORK-001',
|
|
9
10
|
'<%= config.bin %> <%= command.id %> stop WORK-001',
|
|
10
11
|
];
|
|
@@ -28,9 +29,11 @@ export default class Execution extends PMOCommand {
|
|
|
28
29
|
message: 'What would you like to do?',
|
|
29
30
|
choices: [
|
|
30
31
|
{ name: '📋 List all executions', value: 'list', command: 'prlt execution list --json' },
|
|
32
|
+
{ name: '🔍 View execution details', value: 'view', command: 'prlt execution view --json' },
|
|
31
33
|
{ name: '📜 View logs for an execution', value: 'logs', command: 'prlt execution logs --json' },
|
|
32
34
|
{ name: '🛑 Stop an execution', value: 'stop', command: 'prlt execution stop --json' },
|
|
33
35
|
{ name: '🛑 Stop all running', value: 'stop-all', command: 'prlt execution stop --all --json' },
|
|
36
|
+
{ name: '⚙️ Configure execution preferences', value: 'config', command: 'prlt execution config --json' },
|
|
34
37
|
new inquirer.Separator(),
|
|
35
38
|
{ name: '❌ Cancel', value: 'cancel', command: '' },
|
|
36
39
|
],
|
|
@@ -42,9 +45,11 @@ export default class Execution extends PMOCommand {
|
|
|
42
45
|
// Run the selected subcommand
|
|
43
46
|
const commands = {
|
|
44
47
|
list: { cmd: 'execution:list', args: [] },
|
|
48
|
+
view: { cmd: 'execution:view', args: [] },
|
|
45
49
|
logs: { cmd: 'execution:logs', args: [] },
|
|
46
50
|
stop: { cmd: 'execution:stop', args: [] },
|
|
47
51
|
'stop-all': { cmd: 'execution:stop', args: ['--all'] },
|
|
52
|
+
config: { cmd: 'execution:config', args: [] },
|
|
48
53
|
};
|
|
49
54
|
const command = commands[action];
|
|
50
55
|
if (command) {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import ExecutionStop from './stop.js';
|
|
2
|
+
/**
|
|
3
|
+
* Alias for 'execution stop' command.
|
|
4
|
+
* Users intuitively try 'execution kill' so this provides a familiar interface.
|
|
5
|
+
*/
|
|
6
|
+
export default class ExecutionKill extends ExecutionStop {
|
|
7
|
+
static description: string;
|
|
8
|
+
static args: {
|
|
9
|
+
id: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
10
|
+
};
|
|
11
|
+
static examples: string[];
|
|
12
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import ExecutionStop from './stop.js';
|
|
2
|
+
/**
|
|
3
|
+
* Alias for 'execution stop' command.
|
|
4
|
+
* Users intuitively try 'execution kill' so this provides a familiar interface.
|
|
5
|
+
*/
|
|
6
|
+
export default class ExecutionKill extends ExecutionStop {
|
|
7
|
+
static description = 'Stop running execution(s) (alias for "execution stop")';
|
|
8
|
+
static args = ExecutionStop.args;
|
|
9
|
+
static examples = [
|
|
10
|
+
'<%= config.bin %> <%= command.id %> WORK-001',
|
|
11
|
+
'<%= config.bin %> <%= command.id %> WORK-001 --force',
|
|
12
|
+
'<%= config.bin %> <%= command.id %> # Interactive mode',
|
|
13
|
+
'<%= config.bin %> <%= command.id %> --all',
|
|
14
|
+
'<%= config.bin %> <%= command.id %> --all --force',
|
|
15
|
+
'<%= config.bin %> <%= command.id %> --agent altman',
|
|
16
|
+
];
|
|
17
|
+
}
|
|
@@ -28,6 +28,7 @@ export default class ExecutionList extends PMOCommand {
|
|
|
28
28
|
char: 'l',
|
|
29
29
|
description: 'Number of results',
|
|
30
30
|
default: 20,
|
|
31
|
+
min: 1,
|
|
31
32
|
}),
|
|
32
33
|
};
|
|
33
34
|
getPMOOptions() {
|
|
@@ -61,10 +62,10 @@ export default class ExecutionList extends PMOCommand {
|
|
|
61
62
|
this.log('');
|
|
62
63
|
this.log(styles.header('🚀 Agent Work'));
|
|
63
64
|
this.log('═'.repeat(100));
|
|
64
|
-
this.log(styles.muted(padEnd('ID',
|
|
65
|
+
this.log(styles.muted(padEnd('ID', 14) +
|
|
65
66
|
padEnd('Ticket', 9) +
|
|
66
67
|
padEnd('Agent', 10) +
|
|
67
|
-
padEnd('Env',
|
|
68
|
+
padEnd('Env', 13) +
|
|
68
69
|
padEnd('Display', 11) +
|
|
69
70
|
padEnd('Perms', 8) +
|
|
70
71
|
padEnd('Status', 10) +
|
|
@@ -78,10 +79,10 @@ export default class ExecutionList extends PMOCommand {
|
|
|
78
79
|
const envStr = `${envIcon} ${exec.environment}`;
|
|
79
80
|
const permsStr = exec.sandboxed ? 'safe' : 'danger';
|
|
80
81
|
const permsColor = exec.sandboxed ? styles.success : styles.warning;
|
|
81
|
-
this.log(padEnd(exec.id,
|
|
82
|
+
this.log(padEnd(exec.id, 14) +
|
|
82
83
|
padEnd(exec.ticketId, 9) +
|
|
83
84
|
padEnd(exec.agentName, 10) +
|
|
84
|
-
padEnd(envStr,
|
|
85
|
+
padEnd(envStr, 13) +
|
|
85
86
|
padEnd(exec.displayMode, 11) +
|
|
86
87
|
permsColor(padEnd(permsStr, 8)) +
|
|
87
88
|
statusColor(padEnd(exec.status, 10)) +
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { PMOCommand } from '../../lib/pmo/index.js';
|
|
2
|
+
export default class ExecutionView extends PMOCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static args: {
|
|
6
|
+
id: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
7
|
+
};
|
|
8
|
+
static flags: {
|
|
9
|
+
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
10
|
+
machine: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
11
|
+
project: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
};
|
|
13
|
+
protected getPMOOptions(): {
|
|
14
|
+
promptIfMultiple: boolean;
|
|
15
|
+
};
|
|
16
|
+
execute(): Promise<void>;
|
|
17
|
+
}
|