@proletariat/cli 0.3.48 → 0.3.49
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/claude/index.js +21 -21
- package/dist/commands/claude/open.js +1 -1
- package/dist/commands/config/index.js +2 -2
- package/dist/commands/execution/config.d.ts +2 -2
- package/dist/commands/execution/config.js +18 -18
- package/dist/commands/execution/list.js +2 -2
- package/dist/commands/execution/view.js +2 -2
- package/dist/commands/orchestrator/start.d.ts +1 -1
- package/dist/commands/orchestrator/start.js +19 -19
- package/dist/commands/qa/index.js +12 -12
- package/dist/commands/staff/add.js +1 -1
- package/dist/commands/work/linear.js +28 -5
- package/dist/commands/work/revise.js +8 -8
- package/dist/commands/work/spawn.js +1 -1
- package/dist/commands/work/start.js +12 -12
- package/dist/commands/work/watch.js +3 -3
- package/dist/lib/agents/index.js +2 -2
- package/dist/lib/database/drizzle-schema.d.ts +7 -7
- package/dist/lib/database/drizzle-schema.js +1 -1
- package/dist/lib/execution/config.d.ts +6 -6
- package/dist/lib/execution/config.js +17 -10
- package/dist/lib/execution/devcontainer.d.ts +3 -3
- package/dist/lib/execution/devcontainer.js +3 -3
- package/dist/lib/execution/runners.d.ts +2 -2
- package/dist/lib/execution/runners.js +23 -24
- package/dist/lib/execution/spawner.js +3 -3
- package/dist/lib/execution/storage.d.ts +2 -2
- package/dist/lib/execution/storage.js +3 -3
- package/dist/lib/execution/types.d.ts +2 -2
- package/dist/lib/execution/types.js +1 -1
- package/dist/lib/external-issues/linear.d.ts +6 -0
- package/dist/lib/external-issues/linear.js +63 -0
- package/dist/lib/pmo/schema.d.ts +1 -1
- package/dist/lib/pmo/schema.js +1 -1
- package/dist/lib/pmo/storage/base.js +31 -0
- package/dist/lib/repos/index.js +1 -1
- package/oclif.manifest.json +4318 -4313
- package/package.json +1 -1
|
@@ -143,8 +143,8 @@ export default class Claude extends PromptCommand {
|
|
|
143
143
|
else {
|
|
144
144
|
// Build devcontainer label
|
|
145
145
|
const devcontainerLabel = hasProjectDevcontainer
|
|
146
|
-
? '🐳 devcontainer (uses project config,
|
|
147
|
-
: '🐳 devcontainer (uses catch-all container,
|
|
146
|
+
? '🐳 devcontainer (uses project config, isolated)'
|
|
147
|
+
: '🐳 devcontainer (uses catch-all container, isolated)';
|
|
148
148
|
// In JSON mode, output environment prompt and exit
|
|
149
149
|
if (jsonMode) {
|
|
150
150
|
await this.prompt([
|
|
@@ -267,15 +267,15 @@ export default class Claude extends PromptCommand {
|
|
|
267
267
|
displayMode = selectedDisplay;
|
|
268
268
|
}
|
|
269
269
|
// Prompt for permission mode
|
|
270
|
-
let
|
|
270
|
+
let permissionMode = 'safe';
|
|
271
271
|
if (flags['permission-mode']) {
|
|
272
|
-
|
|
272
|
+
permissionMode = (flags['permission-mode'] || 'safe');
|
|
273
273
|
}
|
|
274
274
|
else {
|
|
275
|
-
const {
|
|
275
|
+
const { selectedMode } = await this.prompt([
|
|
276
276
|
{
|
|
277
277
|
type: 'list',
|
|
278
|
-
name: '
|
|
278
|
+
name: 'selectedMode',
|
|
279
279
|
message: 'Permission mode:',
|
|
280
280
|
choices: [
|
|
281
281
|
{ name: '⚠️ danger - Skip permission checks (faster)', value: 'danger', command: `prlt claude --slug "${slug}" --environment ${environment} --display-mode ${displayMode} --permission-mode danger --json` },
|
|
@@ -286,10 +286,10 @@ export default class Claude extends PromptCommand {
|
|
|
286
286
|
], jsonModeConfig);
|
|
287
287
|
if (jsonMode)
|
|
288
288
|
return;
|
|
289
|
-
|
|
289
|
+
permissionMode = selectedMode;
|
|
290
290
|
}
|
|
291
291
|
// Warn about uncommitted changes in danger mode
|
|
292
|
-
if (
|
|
292
|
+
if (permissionMode === 'danger' && isGitRepo(workDir) && hasUncommittedChanges(workDir)) {
|
|
293
293
|
this.log('');
|
|
294
294
|
this.warn('Running in danger mode with uncommitted changes!');
|
|
295
295
|
this.log(styles.muted(' Consider committing or stashing changes first.'));
|
|
@@ -347,7 +347,7 @@ export default class Claude extends PromptCommand {
|
|
|
347
347
|
};
|
|
348
348
|
// Load execution config (use defaults for yolo mode)
|
|
349
349
|
const executionConfig = { ...DEFAULT_EXECUTION_CONFIG };
|
|
350
|
-
executionConfig.
|
|
350
|
+
executionConfig.permissionMode = permissionMode;
|
|
351
351
|
executionConfig.outputMode = 'interactive';
|
|
352
352
|
// For terminal mode, prompt for terminal preference
|
|
353
353
|
if (displayMode === 'terminal' && !jsonMode) {
|
|
@@ -384,7 +384,7 @@ export default class Claude extends PromptCommand {
|
|
|
384
384
|
this.log(styles.muted(` Directory: ${workDir}`));
|
|
385
385
|
this.log(styles.muted(` Environment: ${environment === 'devcontainer' ? '🐳' : '💻'} ${environment}`));
|
|
386
386
|
this.log(styles.muted(` Display: ${displayMode}`));
|
|
387
|
-
this.log(styles.muted(` Permissions: ${
|
|
387
|
+
this.log(styles.muted(` Permissions: ${permissionMode === 'safe' ? '🔒 safe' : '⚠️ danger'}`));
|
|
388
388
|
if (flags.prompt) {
|
|
389
389
|
this.log(styles.muted(` Initial prompt: "${flags.prompt.substring(0, 50)}${flags.prompt.length > 50 ? '...' : ''}"`));
|
|
390
390
|
}
|
|
@@ -537,8 +537,8 @@ export default class Claude extends PromptCommand {
|
|
|
537
537
|
const hasProjectDevcontainer = hasDevcontainerConfig(workDir);
|
|
538
538
|
// Build devcontainer label
|
|
539
539
|
const devcontainerLabel = hasProjectDevcontainer
|
|
540
|
-
? '🐳 devcontainer (uses project config,
|
|
541
|
-
: '🐳 devcontainer (uses catch-all container,
|
|
540
|
+
? '🐳 devcontainer (uses project config, isolated)'
|
|
541
|
+
: '🐳 devcontainer (uses catch-all container, isolated)';
|
|
542
542
|
let environment = 'host';
|
|
543
543
|
if (flags.environment) {
|
|
544
544
|
environment = flags.environment;
|
|
@@ -670,16 +670,16 @@ export default class Claude extends PromptCommand {
|
|
|
670
670
|
displayMode = selectedDisplay;
|
|
671
671
|
}
|
|
672
672
|
// Prompt for permission mode
|
|
673
|
-
let
|
|
673
|
+
let permissionMode = 'safe';
|
|
674
674
|
if (flags['permission-mode']) {
|
|
675
|
-
|
|
675
|
+
permissionMode = (flags['permission-mode'] || 'safe');
|
|
676
676
|
}
|
|
677
677
|
else {
|
|
678
678
|
const containerNote = environment === 'devcontainer' ? ' (container provides additional isolation)' : '';
|
|
679
|
-
const {
|
|
679
|
+
const { selectedMode } = await this.prompt([
|
|
680
680
|
{
|
|
681
681
|
type: 'list',
|
|
682
|
-
name: '
|
|
682
|
+
name: 'selectedMode',
|
|
683
683
|
message: `Permission mode${containerNote}:`,
|
|
684
684
|
choices: [
|
|
685
685
|
{ name: '⚠️ danger - Skip permission checks (faster)', value: 'danger', command: `prlt claude --project ${projectId} --title "${ticketTitle}" --environment ${environment} --display-mode ${displayMode} --permission-mode danger --json` },
|
|
@@ -692,10 +692,10 @@ export default class Claude extends PromptCommand {
|
|
|
692
692
|
db.close();
|
|
693
693
|
return;
|
|
694
694
|
}
|
|
695
|
-
|
|
695
|
+
permissionMode = selectedMode;
|
|
696
696
|
}
|
|
697
697
|
// Warn about uncommitted changes in danger mode
|
|
698
|
-
if (
|
|
698
|
+
if (permissionMode === 'danger' && isGitRepo(workDir) && hasUncommittedChanges(workDir)) {
|
|
699
699
|
this.log('');
|
|
700
700
|
this.warn('Running in danger mode with uncommitted changes!');
|
|
701
701
|
this.log(styles.muted(' Consider committing or stashing changes first.'));
|
|
@@ -777,14 +777,14 @@ export default class Claude extends PromptCommand {
|
|
|
777
777
|
executor: 'claude-code',
|
|
778
778
|
environment,
|
|
779
779
|
displayMode,
|
|
780
|
-
|
|
780
|
+
permissionMode,
|
|
781
781
|
branch: 'main',
|
|
782
782
|
});
|
|
783
783
|
// Update ticket assignee
|
|
784
784
|
await storage.updateTicket(ticket.id, { assignee: agentName });
|
|
785
785
|
// Load execution config
|
|
786
786
|
const executionConfig = loadExecutionConfig(db);
|
|
787
|
-
executionConfig.
|
|
787
|
+
executionConfig.permissionMode = permissionMode;
|
|
788
788
|
executionConfig.outputMode = 'interactive';
|
|
789
789
|
// For terminal mode, ensure terminal preference is set
|
|
790
790
|
if (displayMode === 'terminal' && !jsonMode) {
|
|
@@ -808,7 +808,7 @@ export default class Claude extends PromptCommand {
|
|
|
808
808
|
this.log(styles.muted(` Work ID: ${execution.id}`));
|
|
809
809
|
this.log(styles.muted(` Environment: ${environment === 'devcontainer' ? '🐳' : '💻'} ${environment}`));
|
|
810
810
|
this.log(styles.muted(` Display: ${displayMode}`));
|
|
811
|
-
this.log(styles.muted(` Permissions: ${
|
|
811
|
+
this.log(styles.muted(` Permissions: ${permissionMode === 'safe' ? '🔒 safe' : '⚠️ danger'}`));
|
|
812
812
|
if (flags.prompt) {
|
|
813
813
|
this.log(styles.muted(` Initial prompt: "${flags.prompt.substring(0, 50)}${flags.prompt.length > 50 ? '...' : ''}"`));
|
|
814
814
|
}
|
|
@@ -102,7 +102,7 @@ export default class Open extends PromptCommand {
|
|
|
102
102
|
// Load execution config
|
|
103
103
|
const executionConfig = { ...DEFAULT_EXECUTION_CONFIG };
|
|
104
104
|
executionConfig.outputMode = 'interactive';
|
|
105
|
-
executionConfig.
|
|
105
|
+
executionConfig.permissionMode = 'danger'; // Default to danger mode for quick open
|
|
106
106
|
// Try to load saved preferences from workspace DB or home dir
|
|
107
107
|
const dbPath = hqPath
|
|
108
108
|
? path.join(hqPath, '.proletariat', 'workspace.db')
|
|
@@ -92,7 +92,7 @@ export default class Config extends PromptCommand {
|
|
|
92
92
|
defaultExecutor: config.defaultExecutor,
|
|
93
93
|
defaultEnvironment: config.defaultEnvironment,
|
|
94
94
|
outputMode: config.outputMode,
|
|
95
|
-
|
|
95
|
+
permissionMode: config.permissionMode,
|
|
96
96
|
createPrDefault: config.createPrDefault ?? null,
|
|
97
97
|
firewall: {
|
|
98
98
|
allowlistDomains: config.firewall.allowlistDomains,
|
|
@@ -118,7 +118,7 @@ export default class Config extends PromptCommand {
|
|
|
118
118
|
this.log(` defaultExecutor: ${config.defaultExecutor}`);
|
|
119
119
|
this.log(` defaultEnvironment: ${config.defaultEnvironment}`);
|
|
120
120
|
this.log(` outputMode: ${config.outputMode}`);
|
|
121
|
-
this.log(`
|
|
121
|
+
this.log(` permissionMode: ${config.permissionMode}`);
|
|
122
122
|
this.log(` createPrDefault: ${config.createPrDefault ?? 'not set (will prompt)'}`);
|
|
123
123
|
this.log(` firewall.allowlistDomains: ${config.firewall.allowlistDomains.join(', ') || '(none)'}`);
|
|
124
124
|
this.log('');
|
|
@@ -24,7 +24,7 @@ export default class ExecutionConfig extends PMOCommand {
|
|
|
24
24
|
*/
|
|
25
25
|
private setOutputMode;
|
|
26
26
|
/**
|
|
27
|
-
* Save
|
|
27
|
+
* Save permission mode preference to workspace settings
|
|
28
28
|
*/
|
|
29
|
-
private
|
|
29
|
+
private setPermissionMode;
|
|
30
30
|
}
|
|
@@ -14,7 +14,7 @@ export default class ExecutionConfig extends PMOCommand {
|
|
|
14
14
|
'<%= config.bin %> execution config --list # Show all settings',
|
|
15
15
|
'<%= config.bin %> execution config --set defaultEnvironment host',
|
|
16
16
|
'<%= config.bin %> execution config --set outputMode interactive',
|
|
17
|
-
'<%= config.bin %> execution config --set
|
|
17
|
+
'<%= config.bin %> execution config --set permissionMode safe',
|
|
18
18
|
'<%= config.bin %> execution config --setting outputMode --json # Show output mode choices',
|
|
19
19
|
];
|
|
20
20
|
static flags = {
|
|
@@ -91,7 +91,7 @@ export default class ExecutionConfig extends PMOCommand {
|
|
|
91
91
|
defaultEnvironment: config.defaultEnvironment,
|
|
92
92
|
defaultExecutor: config.defaultExecutor,
|
|
93
93
|
outputMode: config.outputMode,
|
|
94
|
-
|
|
94
|
+
permissionMode: config.permissionMode,
|
|
95
95
|
}, createMetadata('execution config', flags));
|
|
96
96
|
}
|
|
97
97
|
else {
|
|
@@ -105,7 +105,7 @@ export default class ExecutionConfig extends PMOCommand {
|
|
|
105
105
|
this.log('');
|
|
106
106
|
this.log(styles.emphasis('Output'));
|
|
107
107
|
this.log(` outputMode: ${config.outputMode}`);
|
|
108
|
-
this.log(`
|
|
108
|
+
this.log(` permissionMode: ${config.permissionMode}`);
|
|
109
109
|
this.log('');
|
|
110
110
|
this.log(styles.emphasis('Terminal'));
|
|
111
111
|
this.log(` app: ${config.terminal.app}`);
|
|
@@ -131,7 +131,7 @@ export default class ExecutionConfig extends PMOCommand {
|
|
|
131
131
|
const settingChoices = [
|
|
132
132
|
{ name: `Default Environment: ${config.defaultEnvironment}`, value: 'defaultEnvironment', command: 'prlt execution config --setting defaultEnvironment --json' },
|
|
133
133
|
{ name: `Output Mode: ${config.outputMode}`, value: 'outputMode', command: 'prlt execution config --setting outputMode --json' },
|
|
134
|
-
{ name: `Permission Mode: ${config.
|
|
134
|
+
{ name: `Permission Mode: ${config.permissionMode}`, value: 'permissionMode', command: 'prlt execution config --setting permissionMode --json' },
|
|
135
135
|
{ name: `Terminal App: ${config.terminal.app}`, value: 'terminal.app', command: 'prlt execution config --setting terminal.app --json' },
|
|
136
136
|
{ name: `Open Tabs in Background: ${config.terminal.openInBackground}`, value: 'terminal.openInBackground', command: 'prlt execution config --setting terminal.openInBackground --json' },
|
|
137
137
|
{ name: `Shell: ${config.shell}`, value: 'shell', command: 'prlt execution config --setting shell --json' },
|
|
@@ -177,7 +177,7 @@ export default class ExecutionConfig extends PMOCommand {
|
|
|
177
177
|
case 'defaultEnvironment': {
|
|
178
178
|
const envChoices = [
|
|
179
179
|
{ name: 'host - Run directly on host machine', value: 'host', command: 'prlt execution config --set "defaultEnvironment host" --json' },
|
|
180
|
-
{ name: 'devcontainer - Run in a devcontainer (
|
|
180
|
+
{ name: 'devcontainer - Run in a devcontainer (isolated)', value: 'devcontainer', command: 'prlt execution config --set "defaultEnvironment devcontainer" --json' },
|
|
181
181
|
{ name: 'docker - Run in a Docker container', value: 'docker', command: 'prlt execution config --set "defaultEnvironment docker" --json' },
|
|
182
182
|
{ name: 'vm - Run on a remote VM', value: 'vm', command: 'prlt execution config --set "defaultEnvironment vm" --json' },
|
|
183
183
|
];
|
|
@@ -212,10 +212,10 @@ export default class ExecutionConfig extends PMOCommand {
|
|
|
212
212
|
this.log(styles.success(`Output mode set to: ${newOutput}`));
|
|
213
213
|
break;
|
|
214
214
|
}
|
|
215
|
-
case '
|
|
215
|
+
case 'permissionMode': {
|
|
216
216
|
const permChoices = [
|
|
217
|
-
{ name: 'safe
|
|
218
|
-
{ name: 'danger - Skip permission checks (--dangerously-skip-permissions)', value: '
|
|
217
|
+
{ name: '🔒 safe - Requires approval for dangerous operations (recommended)', value: 'safe', command: 'prlt execution config --set "permissionMode safe" --json' },
|
|
218
|
+
{ name: '⚠️ danger - Skip permission checks (--dangerously-skip-permissions)', value: 'danger', command: 'prlt execution config --set "permissionMode danger" --json' },
|
|
219
219
|
];
|
|
220
220
|
const { newPerm } = await this.prompt([
|
|
221
221
|
{
|
|
@@ -223,11 +223,11 @@ export default class ExecutionConfig extends PMOCommand {
|
|
|
223
223
|
name: 'newPerm',
|
|
224
224
|
message: 'Select permission mode:',
|
|
225
225
|
choices: permChoices,
|
|
226
|
-
default:
|
|
226
|
+
default: config.permissionMode,
|
|
227
227
|
},
|
|
228
228
|
], jsonModeConfig);
|
|
229
|
-
this.setConfigValue(db, '
|
|
230
|
-
this.log(styles.success(`Permission mode set to: ${newPerm
|
|
229
|
+
this.setConfigValue(db, 'permissionMode', newPerm, false);
|
|
230
|
+
this.log(styles.success(`Permission mode set to: ${newPerm}`));
|
|
231
231
|
break;
|
|
232
232
|
}
|
|
233
233
|
case 'terminal.app': {
|
|
@@ -324,7 +324,7 @@ export default class ExecutionConfig extends PMOCommand {
|
|
|
324
324
|
const VALID_VALUES = {
|
|
325
325
|
defaultenvironment: ['host', 'devcontainer', 'docker', 'vm'],
|
|
326
326
|
outputmode: ['interactive', 'print'],
|
|
327
|
-
|
|
327
|
+
permissionmode: ['safe', 'danger'],
|
|
328
328
|
'terminal.app': ['Terminal', 'iTerm', 'Alacritty', 'Ghostty', 'Kitty', 'tmux', 'Warp', 'WezTerm'],
|
|
329
329
|
'terminal.openinbackground': ['true', 'false'],
|
|
330
330
|
shell: ['bash', 'zsh', 'fish'],
|
|
@@ -350,9 +350,9 @@ export default class ExecutionConfig extends PMOCommand {
|
|
|
350
350
|
// Store output mode - need to add this to the config storage
|
|
351
351
|
this.setOutputMode(db, value);
|
|
352
352
|
break;
|
|
353
|
-
case '
|
|
354
|
-
// Store
|
|
355
|
-
this.
|
|
353
|
+
case 'permissionmode':
|
|
354
|
+
// Store permission mode preference
|
|
355
|
+
this.setPermissionMode(db, value);
|
|
356
356
|
break;
|
|
357
357
|
case 'terminal.app':
|
|
358
358
|
saveTerminalApp(db, value);
|
|
@@ -389,9 +389,9 @@ export default class ExecutionConfig extends PMOCommand {
|
|
|
389
389
|
saveExecutionSetting(db, 'outputMode', mode);
|
|
390
390
|
}
|
|
391
391
|
/**
|
|
392
|
-
* Save
|
|
392
|
+
* Save permission mode preference to workspace settings
|
|
393
393
|
*/
|
|
394
|
-
|
|
395
|
-
saveExecutionSetting(db, '
|
|
394
|
+
setPermissionMode(db, mode) {
|
|
395
|
+
saveExecutionSetting(db, 'permissionMode', mode);
|
|
396
396
|
}
|
|
397
397
|
}
|
|
@@ -88,8 +88,8 @@ export default class ExecutionList extends PMOCommand {
|
|
|
88
88
|
const timeAgo = formatTimeAgo(exec.startedAt);
|
|
89
89
|
const envIcon = exec.environment === 'devcontainer' ? '🐳' : (exec.environment === 'host' ? '💻' : '📦');
|
|
90
90
|
const envStr = `${envIcon} ${exec.environment}`;
|
|
91
|
-
const permsStr = exec.
|
|
92
|
-
const permsColor = exec.
|
|
91
|
+
const permsStr = exec.permissionMode;
|
|
92
|
+
const permsColor = exec.permissionMode === 'safe' ? styles.success : styles.warning;
|
|
93
93
|
this.log(visualPadEnd(exec.id, 14) +
|
|
94
94
|
visualPadEnd(exec.ticketId, 9) +
|
|
95
95
|
visualPadEnd(exec.agentName, 10) +
|
|
@@ -93,7 +93,7 @@ export default class ExecutionView extends PMOCommand {
|
|
|
93
93
|
executor: execution.executor,
|
|
94
94
|
environment: execution.environment,
|
|
95
95
|
displayMode: execution.displayMode,
|
|
96
|
-
|
|
96
|
+
permissionMode: execution.permissionMode,
|
|
97
97
|
status: execution.status,
|
|
98
98
|
branch: execution.branch || null,
|
|
99
99
|
pid: execution.pid || null,
|
|
@@ -124,7 +124,7 @@ export default class ExecutionView extends PMOCommand {
|
|
|
124
124
|
const envIcon = getEnvironmentIcon(execution.environment);
|
|
125
125
|
this.log(`${styles.muted('Type:')} ${envIcon} ${execution.environment}`);
|
|
126
126
|
this.log(`${styles.muted('Display:')} ${execution.displayMode}`);
|
|
127
|
-
this.log(`${styles.muted('Permissions:')} ${execution.
|
|
127
|
+
this.log(`${styles.muted('Permissions:')} ${execution.permissionMode === 'safe' ? styles.success('safe') : styles.warning('danger')}`);
|
|
128
128
|
if (execution.branch) {
|
|
129
129
|
this.log(`${styles.muted('Branch:')} ${execution.branch}`);
|
|
130
130
|
}
|
|
@@ -18,7 +18,7 @@ export default class OrchestratorStart extends PromptCommand {
|
|
|
18
18
|
action: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
19
19
|
executor: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
20
20
|
'skip-permissions': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
21
|
-
|
|
21
|
+
'permission-mode': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
22
22
|
name: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
23
23
|
background: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
24
24
|
foreground: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
@@ -44,7 +44,7 @@ export default class OrchestratorStart extends PromptCommand {
|
|
|
44
44
|
static examples = [
|
|
45
45
|
'<%= config.bin %> <%= command.id %>',
|
|
46
46
|
'<%= config.bin %> <%= command.id %> --executor codex',
|
|
47
|
-
'<%= config.bin %> <%= command.id %> --
|
|
47
|
+
'<%= config.bin %> <%= command.id %> --permission-mode danger',
|
|
48
48
|
'<%= config.bin %> <%= command.id %> --prompt "coordinate all agents on TKT-100"',
|
|
49
49
|
'<%= config.bin %> <%= command.id %> --background',
|
|
50
50
|
];
|
|
@@ -64,13 +64,13 @@ export default class OrchestratorStart extends PromptCommand {
|
|
|
64
64
|
options: ['claude-code', 'codex', 'aider', 'custom'],
|
|
65
65
|
}),
|
|
66
66
|
'skip-permissions': Flags.boolean({
|
|
67
|
-
description: '
|
|
67
|
+
description: 'Skip permission checks (shorthand for --permission-mode danger)',
|
|
68
68
|
default: false,
|
|
69
|
-
exclusive: ['
|
|
69
|
+
exclusive: ['permission-mode'],
|
|
70
70
|
}),
|
|
71
|
-
|
|
72
|
-
description: '
|
|
73
|
-
|
|
71
|
+
'permission-mode': Flags.string({
|
|
72
|
+
description: 'Permission mode for the orchestrator (danger=skip checks, safe=require approval)',
|
|
73
|
+
options: ['danger', 'safe'],
|
|
74
74
|
exclusive: ['skip-permissions'],
|
|
75
75
|
}),
|
|
76
76
|
name: Flags.string({
|
|
@@ -157,30 +157,30 @@ export default class OrchestratorStart extends PromptCommand {
|
|
|
157
157
|
selectedExecutor = executor;
|
|
158
158
|
}
|
|
159
159
|
// Permission mode selection
|
|
160
|
-
let
|
|
160
|
+
let permissionMode;
|
|
161
161
|
if (flags['skip-permissions']) {
|
|
162
|
-
|
|
162
|
+
permissionMode = 'danger';
|
|
163
163
|
}
|
|
164
|
-
else if (flags
|
|
165
|
-
|
|
164
|
+
else if (flags['permission-mode']) {
|
|
165
|
+
permissionMode = flags['permission-mode'];
|
|
166
166
|
}
|
|
167
167
|
else {
|
|
168
168
|
const permissionChoices = [
|
|
169
|
-
{ name: '
|
|
170
|
-
{ name: '
|
|
169
|
+
{ name: '⚠️ danger - Skip permission checks (faster)', value: 'danger', command: 'prlt orchestrator start --permission-mode danger --json' },
|
|
170
|
+
{ name: '🔒 safe - Requires approval for dangerous operations', value: 'safe', command: 'prlt orchestrator start --permission-mode safe --json' },
|
|
171
171
|
];
|
|
172
|
-
const permissionMessage = '
|
|
172
|
+
const permissionMessage = 'Permission mode:';
|
|
173
173
|
if (jsonMode) {
|
|
174
174
|
outputPromptAsJson(buildPromptConfig('list', 'permissionMode', permissionMessage, permissionChoices), createMetadata('orchestrator start', flags));
|
|
175
175
|
return;
|
|
176
176
|
}
|
|
177
|
-
const { permissionMode } = await this.prompt([{
|
|
177
|
+
const { permissionMode: selectedMode } = await this.prompt([{
|
|
178
178
|
type: 'list',
|
|
179
179
|
name: 'permissionMode',
|
|
180
180
|
message: permissionMessage,
|
|
181
181
|
choices: permissionChoices,
|
|
182
182
|
}]);
|
|
183
|
-
|
|
183
|
+
permissionMode = selectedMode;
|
|
184
184
|
}
|
|
185
185
|
// Resolve action prompt
|
|
186
186
|
let actionPrompt = flags.prompt;
|
|
@@ -228,7 +228,7 @@ export default class OrchestratorStart extends PromptCommand {
|
|
|
228
228
|
// Build execution config
|
|
229
229
|
const executionConfig = { ...DEFAULT_EXECUTION_CONFIG };
|
|
230
230
|
executionConfig.outputMode = 'interactive';
|
|
231
|
-
executionConfig.
|
|
231
|
+
executionConfig.permissionMode = permissionMode;
|
|
232
232
|
// Load saved preferences from workspace DB
|
|
233
233
|
const dbPath = path.join(hqPath, '.proletariat', 'workspace.db');
|
|
234
234
|
let db = null;
|
|
@@ -299,7 +299,7 @@ export default class OrchestratorStart extends PromptCommand {
|
|
|
299
299
|
this.log('');
|
|
300
300
|
this.log(styles.muted(` Starting orchestrator...`));
|
|
301
301
|
this.log(styles.muted(` Executor: ${selectedExecutor}`));
|
|
302
|
-
this.log(styles.muted(` Permission mode: ${
|
|
302
|
+
this.log(styles.muted(` Permission mode: ${permissionMode}`));
|
|
303
303
|
this.log(styles.muted(` Display mode: ${displayMode}`));
|
|
304
304
|
this.log(styles.muted(` Directory: ${hqPath}`));
|
|
305
305
|
if (orchestratorName !== 'main') {
|
|
@@ -325,7 +325,7 @@ export default class OrchestratorStart extends PromptCommand {
|
|
|
325
325
|
executor: selectedExecutor,
|
|
326
326
|
environment: 'host',
|
|
327
327
|
displayMode,
|
|
328
|
-
|
|
328
|
+
permissionMode,
|
|
329
329
|
sessionId: result.sessionId || sessionName,
|
|
330
330
|
});
|
|
331
331
|
}
|
|
@@ -337,7 +337,7 @@ export default class OrchestratorStart extends PromptCommand {
|
|
|
337
337
|
outputSuccessAsJson({
|
|
338
338
|
sessionId: result.sessionId || sessionName,
|
|
339
339
|
executor: selectedExecutor,
|
|
340
|
-
|
|
340
|
+
permissionMode,
|
|
341
341
|
displayMode,
|
|
342
342
|
directory: hqPath,
|
|
343
343
|
name: orchestratorName,
|
|
@@ -295,7 +295,7 @@ Clean up your tmux session when done.`,
|
|
|
295
295
|
}
|
|
296
296
|
}
|
|
297
297
|
// Resolve permission mode (default to danger for QA since it's in a container)
|
|
298
|
-
const
|
|
298
|
+
const permissionMode = await this.resolvePermissionMode(flags, jsonMode, jsonModeConfig, environment, displayMode);
|
|
299
299
|
if (jsonMode && !flags['permission-mode']) {
|
|
300
300
|
db.close();
|
|
301
301
|
return;
|
|
@@ -359,14 +359,14 @@ Clean up your tmux session when done.`,
|
|
|
359
359
|
executor: 'claude-code',
|
|
360
360
|
environment,
|
|
361
361
|
displayMode,
|
|
362
|
-
|
|
362
|
+
permissionMode,
|
|
363
363
|
branch: 'main',
|
|
364
364
|
});
|
|
365
365
|
// Update ticket assignee
|
|
366
366
|
await storage.updateTicket(ticket.id, { assignee: agentName });
|
|
367
367
|
// Load execution config
|
|
368
368
|
const executionConfig = loadExecutionConfig(db);
|
|
369
|
-
executionConfig.
|
|
369
|
+
executionConfig.permissionMode = permissionMode;
|
|
370
370
|
executionConfig.outputMode = 'interactive';
|
|
371
371
|
// For terminal mode, ensure terminal preference is set
|
|
372
372
|
if (displayMode === 'terminal' && !jsonMode) {
|
|
@@ -390,7 +390,7 @@ Clean up your tmux session when done.`,
|
|
|
390
390
|
this.log(styles.muted(` Work ID: ${execution.id}`));
|
|
391
391
|
this.log(styles.muted(` Environment: ${environment === 'devcontainer' ? '🐳' : '💻'} ${environment}`));
|
|
392
392
|
this.log(styles.muted(` Display: ${displayMode}${flags.watch ? ' (watch mode)' : ''}`));
|
|
393
|
-
this.log(styles.muted(` Permissions: ${
|
|
393
|
+
this.log(styles.muted(` Permissions: ${permissionMode === 'safe' ? '🔒 safe' : '⚠️ danger'}`));
|
|
394
394
|
this.log('');
|
|
395
395
|
// Run execution
|
|
396
396
|
this.log(styles.muted('Starting QA agent...'));
|
|
@@ -457,7 +457,7 @@ Clean up your tmux session when done.`,
|
|
|
457
457
|
return;
|
|
458
458
|
}
|
|
459
459
|
// Resolve permission mode
|
|
460
|
-
const
|
|
460
|
+
const permissionMode = await this.resolvePermissionMode(flags, jsonMode, jsonModeConfig, environment, displayMode);
|
|
461
461
|
if (jsonMode && !flags['permission-mode'])
|
|
462
462
|
return;
|
|
463
463
|
const sessionName = `qa-explore-${Date.now().toString(36)}`;
|
|
@@ -501,7 +501,7 @@ Clean up your tmux session when done.`,
|
|
|
501
501
|
};
|
|
502
502
|
// Load execution config
|
|
503
503
|
const executionConfig = { ...DEFAULT_EXECUTION_CONFIG };
|
|
504
|
-
executionConfig.
|
|
504
|
+
executionConfig.permissionMode = permissionMode;
|
|
505
505
|
executionConfig.outputMode = 'interactive';
|
|
506
506
|
// For terminal mode, prompt for terminal preference
|
|
507
507
|
if (displayMode === 'terminal' && !jsonMode) {
|
|
@@ -535,7 +535,7 @@ Clean up your tmux session when done.`,
|
|
|
535
535
|
this.log(styles.muted(` Directory: ${workDir}`));
|
|
536
536
|
this.log(styles.muted(` Environment: ${environment === 'devcontainer' ? '🐳' : '💻'} ${environment}`));
|
|
537
537
|
this.log(styles.muted(` Display: ${displayMode}${flags.watch ? ' (watch mode)' : ''}`));
|
|
538
|
-
this.log(styles.muted(` Permissions: ${
|
|
538
|
+
this.log(styles.muted(` Permissions: ${permissionMode === 'safe' ? '🔒 safe' : '⚠️ danger'}`));
|
|
539
539
|
this.log('');
|
|
540
540
|
// Run execution
|
|
541
541
|
this.log(styles.muted('Starting QA agent...'));
|
|
@@ -575,8 +575,8 @@ Clean up your tmux session when done.`,
|
|
|
575
575
|
}
|
|
576
576
|
const hasProjectDevcontainer = hasDevcontainerConfig(workDir);
|
|
577
577
|
const devcontainerLabel = hasProjectDevcontainer
|
|
578
|
-
? '🐳 devcontainer (uses project config,
|
|
579
|
-
: '🐳 devcontainer (uses catch-all container,
|
|
578
|
+
? '🐳 devcontainer (uses project config, isolated)'
|
|
579
|
+
: '🐳 devcontainer (uses catch-all container, isolated)';
|
|
580
580
|
if (jsonMode) {
|
|
581
581
|
await this.prompt([
|
|
582
582
|
{
|
|
@@ -680,7 +680,7 @@ Clean up your tmux session when done.`,
|
|
|
680
680
|
*/
|
|
681
681
|
async resolvePermissionMode(flags, jsonMode, jsonModeConfig, environment, displayMode) {
|
|
682
682
|
if (flags['permission-mode']) {
|
|
683
|
-
return flags['permission-mode']
|
|
683
|
+
return (flags['permission-mode'] || 'safe');
|
|
684
684
|
}
|
|
685
685
|
const containerNote = environment === 'devcontainer' ? ' (container provides isolation)' : '';
|
|
686
686
|
const { permissionMode } = await this.prompt([
|
|
@@ -696,8 +696,8 @@ Clean up your tmux session when done.`,
|
|
|
696
696
|
},
|
|
697
697
|
], jsonModeConfig);
|
|
698
698
|
if (jsonMode)
|
|
699
|
-
return
|
|
700
|
-
return permissionMode
|
|
699
|
+
return 'safe'; // unreachable
|
|
700
|
+
return permissionMode;
|
|
701
701
|
}
|
|
702
702
|
/**
|
|
703
703
|
* Set up catch-all devcontainer for directories without one.
|
|
@@ -264,7 +264,7 @@ export default class Add extends PromptCommand {
|
|
|
264
264
|
this.log(chalk.blue(` From theme: ${theme?.display_name || themeId}`));
|
|
265
265
|
}
|
|
266
266
|
if (!flags['no-container']) {
|
|
267
|
-
this.log(chalk.blue(' Devcontainer config created for
|
|
267
|
+
this.log(chalk.blue(' Devcontainer config created for isolated execution'));
|
|
268
268
|
}
|
|
269
269
|
}
|
|
270
270
|
catch (error) {
|
|
@@ -2,7 +2,8 @@ import { Flags } from '@oclif/core';
|
|
|
2
2
|
import { PMOCommand, pmoBaseFlags, autoExportToBoard, } from '../../lib/pmo/index.js';
|
|
3
3
|
import { shouldOutputJson, } from '../../lib/prompt-json.js';
|
|
4
4
|
import { ExternalIssueAdapterError, } from '../../lib/external-issues/types.js';
|
|
5
|
-
import { listLinearIssues, buildLinearIssueChoiceCommand, buildLinearTicketDescription, buildLinearMetadata, buildLinearSpawnContextMessage, } from '../../lib/external-issues/linear.js';
|
|
5
|
+
import { listLinearIssues, getLinearIssueByIdentifier, buildLinearIssueChoiceCommand, buildLinearTicketDescription, buildLinearMetadata, buildLinearSpawnContextMessage, } from '../../lib/external-issues/linear.js';
|
|
6
|
+
import { getLinearApiKey, loadLinearConfig } from '../../lib/linear/index.js';
|
|
6
7
|
function buildWorkStartArgs(options) {
|
|
7
8
|
const args = [options.ticketId, '--project', options.projectId, '--ephemeral'];
|
|
8
9
|
if (options.executor)
|
|
@@ -125,6 +126,8 @@ export default class WorkLinear extends PMOCommand {
|
|
|
125
126
|
async execute() {
|
|
126
127
|
const { flags } = await this.parse(WorkLinear);
|
|
127
128
|
const jsonMode = shouldOutputJson(flags);
|
|
129
|
+
const db = this.storage.getDatabase();
|
|
130
|
+
const linearConfig = loadLinearConfig(db);
|
|
128
131
|
const projectId = await this.requireProject({
|
|
129
132
|
jsonMode: {
|
|
130
133
|
flags,
|
|
@@ -132,10 +135,12 @@ export default class WorkLinear extends PMOCommand {
|
|
|
132
135
|
baseCommand: 'prlt work linear',
|
|
133
136
|
},
|
|
134
137
|
});
|
|
135
|
-
const
|
|
138
|
+
const apiKey = getLinearApiKey(db) || undefined;
|
|
139
|
+
const team = flags.team || linearConfig?.defaultTeamKey || process.env.PRLT_LINEAR_TEAM;
|
|
136
140
|
let issues;
|
|
137
141
|
try {
|
|
138
142
|
issues = await listLinearIssues({
|
|
143
|
+
apiKey,
|
|
139
144
|
team,
|
|
140
145
|
}, { limit: flags.limit });
|
|
141
146
|
}
|
|
@@ -150,10 +155,25 @@ export default class WorkLinear extends PMOCommand {
|
|
|
150
155
|
return this.handleError('NO_LINEAR_ISSUES', 'No active Linear issues found for the configured team.', { jsonMode, commandName: 'work linear', flags });
|
|
151
156
|
}
|
|
152
157
|
let selectedIssue = issues.find(issue => issue.source.externalKey === flags.issue);
|
|
153
|
-
if (!selectedIssue) {
|
|
154
|
-
|
|
158
|
+
if (!selectedIssue && flags.issue) {
|
|
159
|
+
try {
|
|
160
|
+
selectedIssue = await getLinearIssueByIdentifier({
|
|
161
|
+
apiKey,
|
|
162
|
+
team,
|
|
163
|
+
}, flags.issue) ?? undefined;
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
if (error instanceof ExternalIssueAdapterError) {
|
|
167
|
+
return this.handleError(error.code, error.message, { jsonMode, commandName: 'work linear', flags });
|
|
168
|
+
}
|
|
169
|
+
const msg = error instanceof Error ? error.message : 'Failed to fetch Linear issue.';
|
|
170
|
+
return this.handleError('LINEAR_REQUEST_FAILED', msg, { jsonMode, commandName: 'work linear', flags });
|
|
171
|
+
}
|
|
172
|
+
if (!selectedIssue) {
|
|
155
173
|
return this.handleError('LINEAR_ISSUE_NOT_FOUND', `Linear issue "${flags.issue}" was not found.`, { jsonMode, commandName: 'work linear', flags });
|
|
156
174
|
}
|
|
175
|
+
}
|
|
176
|
+
if (!selectedIssue) {
|
|
157
177
|
const selectedKey = await this.selectFromList({
|
|
158
178
|
message: 'Select Linear issue to spawn:',
|
|
159
179
|
items: issues,
|
|
@@ -162,7 +182,10 @@ export default class WorkLinear extends PMOCommand {
|
|
|
162
182
|
return `[${priority}] ${issue.source.externalKey} - ${issue.title}`;
|
|
163
183
|
},
|
|
164
184
|
getValue: issue => issue.source.externalKey,
|
|
165
|
-
getCommand: issue =>
|
|
185
|
+
getCommand: issue => {
|
|
186
|
+
const base = buildLinearIssueChoiceCommand(issue.source.externalKey, projectId);
|
|
187
|
+
return team ? `${base} --team ${team}` : base;
|
|
188
|
+
},
|
|
166
189
|
jsonMode: jsonMode ? { flags, commandName: 'work linear' } : null,
|
|
167
190
|
});
|
|
168
191
|
if (!selectedKey) {
|