@proletariat/cli 0.3.34 → 0.3.36
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/auth.d.ts +15 -3
- package/dist/commands/agent/auth.js +136 -15
- package/dist/commands/agent/index.js +11 -2
- package/dist/commands/agent/list.js +16 -7
- package/dist/commands/agent/staff/add.d.ts +1 -0
- package/dist/commands/agent/staff/add.js +1 -0
- package/dist/commands/agent/staff/index.d.ts +15 -0
- package/dist/commands/agent/staff/index.js +83 -0
- package/dist/commands/agent/staff/list.d.ts +1 -0
- package/dist/commands/agent/staff/list.js +1 -0
- package/dist/commands/agent/staff/remove.d.ts +1 -0
- package/dist/commands/agent/staff/remove.js +1 -0
- package/dist/commands/agent/status.js +32 -4
- package/dist/commands/agent/themes/add-names.d.ts +1 -0
- package/dist/commands/agent/themes/add-names.js +1 -0
- package/dist/commands/agent/themes/create.d.ts +1 -0
- package/dist/commands/agent/themes/create.js +1 -0
- package/dist/commands/agent/themes/index.d.ts +10 -0
- package/dist/commands/agent/themes/index.js +144 -0
- package/dist/commands/agent/themes/list.d.ts +1 -0
- package/dist/commands/agent/themes/list.js +1 -0
- package/dist/commands/agent/themes/set.d.ts +1 -0
- package/dist/commands/agent/themes/set.js +1 -0
- package/dist/commands/agents/themes/add-names.d.ts +1 -0
- package/dist/commands/agents/themes/add-names.js +1 -0
- package/dist/commands/agents/themes/create.d.ts +1 -0
- package/dist/commands/agents/themes/create.js +1 -0
- package/dist/commands/agents/themes/list.d.ts +1 -0
- package/dist/commands/agents/themes/list.js +1 -0
- package/dist/commands/board/watch.js +6 -0
- package/dist/commands/branch/list.d.ts +1 -0
- package/dist/commands/branch/list.js +43 -12
- package/dist/commands/branch/where.js +3 -2
- package/dist/commands/category/list.d.ts +2 -1
- package/dist/commands/category/list.js +38 -13
- package/dist/commands/{claude.d.ts → claude/index.d.ts} +1 -1
- package/dist/commands/{claude.js → claude/index.js} +12 -12
- package/dist/commands/claude/open.d.ts +13 -0
- package/dist/commands/claude/open.js +175 -0
- package/dist/commands/diet.js +18 -2
- package/dist/commands/docker/logs.js +7 -3
- package/dist/commands/docker/shell.js +6 -0
- package/dist/commands/docker/start.js +20 -4
- package/dist/commands/docker/sync.d.ts +4 -0
- package/dist/commands/docker/sync.js +30 -2
- package/dist/commands/epic/show.d.ts +13 -0
- package/dist/commands/epic/show.js +16 -0
- package/dist/commands/epic/view.js +27 -0
- package/dist/commands/execution/config.d.ts +0 -4
- package/dist/commands/execution/config.js +10 -32
- package/dist/commands/execution/index.js +2 -1
- package/dist/commands/execution/logs.js +1 -1
- package/dist/commands/execution/stop.js +2 -1
- package/dist/commands/execution/view.js +22 -26
- package/dist/commands/init.js +2 -19
- package/dist/commands/label/create.d.ts +20 -0
- package/dist/commands/label/create.js +57 -0
- package/dist/commands/label/delete.d.ts +17 -0
- package/dist/commands/label/delete.js +32 -0
- package/dist/commands/label/group/create.d.ts +20 -0
- package/dist/commands/label/group/create.js +55 -0
- package/dist/commands/label/group/list.d.ts +14 -0
- package/dist/commands/label/group/list.js +52 -0
- package/dist/commands/label/index.d.ts +15 -0
- package/dist/commands/label/index.js +58 -0
- package/dist/commands/label/list.d.ts +16 -0
- package/dist/commands/label/list.js +83 -0
- package/dist/commands/link/list.js +3 -2
- package/dist/commands/mcp-server.js +27 -1
- package/dist/commands/phase/template/apply.d.ts +26 -0
- package/dist/commands/phase/template/apply.js +14 -0
- package/dist/commands/phase/template/create.d.ts +23 -0
- package/dist/commands/phase/template/create.js +14 -0
- package/dist/commands/phase/template/delete.d.ts +18 -0
- package/dist/commands/phase/template/delete.js +61 -0
- package/dist/commands/phase/template/list.d.ts +17 -0
- package/dist/commands/phase/template/list.js +89 -0
- package/dist/commands/phase/template/update.d.ts +1 -0
- package/dist/commands/phase/template/update.js +1 -0
- package/dist/commands/priority/add.js +1 -1
- package/dist/commands/project/create.js +3 -4
- package/dist/commands/project/update.js +5 -8
- package/dist/commands/pull.js +24 -0
- package/dist/commands/roadmap/generate.js +1 -2
- package/dist/commands/session/create.d.ts +19 -0
- package/dist/commands/session/create.js +102 -0
- package/dist/commands/session/health.js +2 -21
- package/dist/commands/session/index.js +14 -1
- package/dist/commands/session/list.js +26 -7
- package/dist/commands/session/peek.d.ts +38 -0
- package/dist/commands/session/peek.js +316 -0
- package/dist/commands/session/poke.d.ts +27 -0
- package/dist/commands/session/poke.js +219 -0
- package/dist/commands/spec/link/depends.d.ts +18 -0
- package/dist/commands/spec/link/depends.js +86 -0
- package/dist/commands/spec/link/index.d.ts +17 -0
- package/dist/commands/spec/link/index.js +92 -0
- package/dist/commands/spec/link/remove.d.ts +18 -0
- package/dist/commands/spec/link/remove.js +90 -0
- package/dist/commands/spec/view.js +29 -0
- package/dist/commands/support/logs.js +2 -2
- package/dist/commands/template/apply.js +5 -4
- package/dist/commands/template/create.js +1 -1
- package/dist/commands/template/list.js +2 -1
- package/dist/commands/theme/add-names.d.ts +4 -0
- package/dist/commands/theme/add-names.js +11 -1
- package/dist/commands/theme/create.d.ts +2 -0
- package/dist/commands/theme/create.js +8 -0
- package/dist/commands/ticket/bulk.js +2 -2
- package/dist/commands/ticket/complete.js +2 -2
- package/dist/commands/ticket/create.js +21 -0
- package/dist/commands/ticket/delete.js +8 -0
- package/dist/commands/ticket/edit.js +25 -0
- package/dist/commands/ticket/index.js +2 -2
- package/dist/commands/ticket/link/block.d.ts +15 -0
- package/dist/commands/ticket/link/block.js +95 -0
- package/dist/commands/ticket/link/index.d.ts +14 -0
- package/dist/commands/ticket/link/index.js +96 -0
- package/dist/commands/ticket/list.d.ts +1 -0
- package/dist/commands/ticket/list.js +6 -0
- package/dist/commands/ticket/move.js +25 -2
- package/dist/commands/ticket/resolve.js +4 -5
- package/dist/commands/ticket/show.d.ts +13 -0
- package/dist/commands/ticket/show.js +16 -0
- package/dist/commands/ticket/template/apply.d.ts +26 -0
- package/dist/commands/ticket/template/apply.js +14 -0
- package/dist/commands/ticket/template/delete.d.ts +18 -0
- package/dist/commands/ticket/template/delete.js +61 -0
- package/dist/commands/ticket/template/list.d.ts +17 -0
- package/dist/commands/ticket/template/list.js +78 -0
- package/dist/commands/ticket/template/save.d.ts +17 -0
- package/dist/commands/ticket/template/save.js +97 -0
- package/dist/commands/ticket/view.js +30 -0
- package/dist/commands/work/index.js +4 -0
- package/dist/commands/work/ready.js +17 -0
- package/dist/commands/work/resolve.js +1 -1
- package/dist/commands/work/spawn.js +4 -4
- package/dist/commands/work/start.d.ts +1 -0
- package/dist/commands/work/start.js +203 -93
- package/dist/commands/work/status.d.ts +14 -0
- package/dist/commands/work/status.js +60 -0
- package/dist/commands/workflow/index.js +2 -1
- package/dist/commands/workflow/show.d.ts +13 -0
- package/dist/commands/workflow/show.js +16 -0
- package/dist/commands/workspace/add.js +15 -0
- package/dist/commands/workspace/list.js +2 -1
- package/dist/commands/workspace/prune.js +5 -5
- package/dist/lib/branch/index.d.ts +1 -0
- package/dist/lib/database/index.d.ts +1 -1
- package/dist/lib/database/index.js +20 -0
- package/dist/lib/execution/config.d.ts +15 -1
- package/dist/lib/execution/config.js +28 -0
- package/dist/lib/execution/devcontainer.js +3 -1
- package/dist/lib/execution/runners.d.ts +18 -2
- package/dist/lib/execution/runners.js +71 -29
- package/dist/lib/execution/session-utils.d.ts +11 -1
- package/dist/lib/execution/session-utils.js +26 -1
- package/dist/lib/execution/storage.d.ts +5 -0
- package/dist/lib/execution/storage.js +18 -3
- package/dist/lib/execution/types.d.ts +3 -0
- package/dist/lib/flags/resolver.js +1 -0
- package/dist/lib/mcp/helpers.d.ts +1 -2
- package/dist/lib/mcp/tools/board.js +4 -6
- package/dist/lib/mcp/tools/cli-passthrough.js +25 -6
- package/dist/lib/mcp/tools/diet.js +1 -0
- package/dist/lib/mcp/tools/epic.js +8 -3
- package/dist/lib/mcp/tools/index.d.ts +1 -0
- package/dist/lib/mcp/tools/index.js +1 -0
- package/dist/lib/mcp/tools/label.d.ts +6 -0
- package/dist/lib/mcp/tools/label.js +338 -0
- package/dist/lib/mcp/tools/spec.js +1 -1
- package/dist/lib/mcp/tools/ticket.js +57 -19
- package/dist/lib/mcp/tools/work.js +96 -6
- package/dist/lib/mcp/types.d.ts +10 -0
- package/dist/lib/multiline-input.js +8 -19
- package/dist/lib/pmo/base-command.d.ts +0 -1
- package/dist/lib/pmo/base-command.js +4 -5
- package/dist/lib/pmo/schema.d.ts +6 -0
- package/dist/lib/pmo/schema.js +44 -0
- package/dist/lib/pmo/storage/actions.js +1 -1
- package/dist/lib/pmo/storage/base.d.ts +6 -0
- package/dist/lib/pmo/storage/base.js +311 -52
- package/dist/lib/pmo/storage/index.d.ts +23 -1
- package/dist/lib/pmo/storage/index.js +59 -1
- package/dist/lib/pmo/storage/labels.d.ts +55 -0
- package/dist/lib/pmo/storage/labels.js +346 -0
- package/dist/lib/pmo/storage/tickets.js +17 -0
- package/dist/lib/pmo/storage/types.d.ts +25 -0
- package/dist/lib/pmo/types.d.ts +44 -0
- package/dist/lib/pmo/utils.js +1 -1
- package/dist/lib/prompt-command.d.ts +20 -0
- package/dist/lib/prompt-command.js +38 -2
- package/dist/lib/prompt-json.d.ts +36 -4
- package/dist/lib/prompt-json.js +129 -7
- package/dist/lib/styles.d.ts +37 -0
- package/dist/lib/styles.js +73 -0
- package/oclif.manifest.json +6399 -3799
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export default class Auth extends
|
|
1
|
+
import { PromptCommand } from '../../lib/prompt-command.js';
|
|
2
|
+
export default class Auth extends PromptCommand {
|
|
3
3
|
static description: string;
|
|
4
4
|
static examples: string[];
|
|
5
5
|
static flags: {
|
|
@@ -7,7 +7,13 @@ export default class Auth extends Command {
|
|
|
7
7
|
machine: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
8
8
|
check: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
9
9
|
force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
10
|
+
'api-key': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
10
11
|
};
|
|
12
|
+
/**
|
|
13
|
+
* Try to open the workspace database for saving auth preferences.
|
|
14
|
+
* Returns null if not in an HQ directory (auth still works, just won't save preference).
|
|
15
|
+
*/
|
|
16
|
+
private tryOpenDb;
|
|
11
17
|
/**
|
|
12
18
|
* Check if the claude-credentials volume exists
|
|
13
19
|
*/
|
|
@@ -17,7 +23,9 @@ export default class Auth extends Command {
|
|
|
17
23
|
*/
|
|
18
24
|
private createVolume;
|
|
19
25
|
/**
|
|
20
|
-
* Check if valid credentials exist in the volume
|
|
26
|
+
* Check if valid credentials exist in the volume.
|
|
27
|
+
* Don't check expiration - access tokens are short-lived but Claude Code
|
|
28
|
+
* handles token refresh internally using stored refresh tokens.
|
|
21
29
|
*/
|
|
22
30
|
private credentialsExist;
|
|
23
31
|
/**
|
|
@@ -28,5 +36,9 @@ export default class Auth extends Command {
|
|
|
28
36
|
* Run the interactive login flow in a temporary container
|
|
29
37
|
*/
|
|
30
38
|
private runLoginFlow;
|
|
39
|
+
/**
|
|
40
|
+
* Handle API key authentication flow
|
|
41
|
+
*/
|
|
42
|
+
private handleApiKey;
|
|
31
43
|
run(): Promise<void>;
|
|
32
44
|
}
|
|
@@ -1,16 +1,22 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Flags } from '@oclif/core';
|
|
2
2
|
import { execSync, spawnSync } from 'node:child_process';
|
|
3
|
+
import { PromptCommand } from '../../lib/prompt-command.js';
|
|
3
4
|
import { colors } from '../../lib/colors.js';
|
|
4
5
|
import { machineOutputFlags } from '../../lib/pmo/index.js';
|
|
5
6
|
import { isDockerRunning } from '../../lib/execution/runners.js';
|
|
6
7
|
import { shouldOutputJson, outputSuccessAsJson, outputErrorAsJson, createMetadata, } from '../../lib/prompt-json.js';
|
|
8
|
+
import { findHQRoot } from '../../lib/workspace.js';
|
|
9
|
+
import { getWorkspaceDbPath } from '../../lib/workspace.js';
|
|
10
|
+
import { saveAuthMethod } from '../../lib/execution/config.js';
|
|
11
|
+
import Database from 'better-sqlite3';
|
|
7
12
|
const CLAUDE_CREDENTIALS_VOLUME = 'claude-credentials';
|
|
8
|
-
export default class Auth extends
|
|
13
|
+
export default class Auth extends PromptCommand {
|
|
9
14
|
static description = 'Set up Claude Code authentication for Docker containers (one-time setup)';
|
|
10
15
|
static examples = [
|
|
11
16
|
'<%= config.bin %> <%= command.id %>',
|
|
12
17
|
'<%= config.bin %> <%= command.id %> --check',
|
|
13
18
|
'<%= config.bin %> <%= command.id %> --force',
|
|
19
|
+
'<%= config.bin %> <%= command.id %> --api-key',
|
|
14
20
|
];
|
|
15
21
|
static flags = {
|
|
16
22
|
check: Flags.boolean({
|
|
@@ -21,8 +27,30 @@ export default class Auth extends Command {
|
|
|
21
27
|
description: 'Force re-authentication even if credentials exist',
|
|
22
28
|
default: false,
|
|
23
29
|
}),
|
|
30
|
+
'api-key': Flags.boolean({
|
|
31
|
+
description: 'Use ANTHROPIC_API_KEY instead of OAuth (saves preference)',
|
|
32
|
+
default: false,
|
|
33
|
+
}),
|
|
24
34
|
...machineOutputFlags,
|
|
25
35
|
};
|
|
36
|
+
/**
|
|
37
|
+
* Try to open the workspace database for saving auth preferences.
|
|
38
|
+
* Returns null if not in an HQ directory (auth still works, just won't save preference).
|
|
39
|
+
*/
|
|
40
|
+
tryOpenDb() {
|
|
41
|
+
try {
|
|
42
|
+
const hqPath = findHQRoot();
|
|
43
|
+
if (!hqPath)
|
|
44
|
+
return null;
|
|
45
|
+
const dbPath = getWorkspaceDbPath(hqPath);
|
|
46
|
+
const db = new Database(dbPath);
|
|
47
|
+
db.pragma('foreign_keys = ON');
|
|
48
|
+
return db;
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
26
54
|
/**
|
|
27
55
|
* Check if the claude-credentials volume exists
|
|
28
56
|
*/
|
|
@@ -47,19 +75,16 @@ export default class Auth extends Command {
|
|
|
47
75
|
}
|
|
48
76
|
}
|
|
49
77
|
/**
|
|
50
|
-
* Check if valid credentials exist in the volume
|
|
78
|
+
* Check if valid credentials exist in the volume.
|
|
79
|
+
* Don't check expiration - access tokens are short-lived but Claude Code
|
|
80
|
+
* handles token refresh internally using stored refresh tokens.
|
|
51
81
|
*/
|
|
52
82
|
credentialsExist() {
|
|
53
83
|
try {
|
|
54
84
|
const result = execSync(`docker run --rm -v ${CLAUDE_CREDENTIALS_VOLUME}:/data alpine cat /data/.credentials.json 2>/dev/null`, { stdio: 'pipe', encoding: 'utf-8' });
|
|
55
|
-
// Parse and validate the credentials
|
|
56
85
|
const creds = JSON.parse(result);
|
|
57
|
-
if (creds.claudeAiOauth?.accessToken
|
|
58
|
-
|
|
59
|
-
const expiresAt = creds.claudeAiOauth.expiresAt;
|
|
60
|
-
if (expiresAt > Date.now()) {
|
|
61
|
-
return true;
|
|
62
|
-
}
|
|
86
|
+
if (creds.claudeAiOauth?.accessToken) {
|
|
87
|
+
return true;
|
|
63
88
|
}
|
|
64
89
|
return false;
|
|
65
90
|
}
|
|
@@ -93,8 +118,7 @@ export default class Auth extends Command {
|
|
|
93
118
|
this.log(colors.primary('🔐 Starting Claude Code authentication...'));
|
|
94
119
|
this.log('');
|
|
95
120
|
this.log(colors.text('A temporary container will start with Claude Code.'));
|
|
96
|
-
this.log(colors.text('
|
|
97
|
-
this.log(colors.text('Then complete the browser authentication.'));
|
|
121
|
+
this.log(colors.text('Complete the browser authentication when prompted.'));
|
|
98
122
|
this.log('');
|
|
99
123
|
this.log(colors.textSecondary('Press Ctrl+C to cancel.'));
|
|
100
124
|
this.log('');
|
|
@@ -108,7 +132,8 @@ export default class Auth extends Command {
|
|
|
108
132
|
'node:20',
|
|
109
133
|
'bash', '-c',
|
|
110
134
|
// Install as root, then run claude as node user (so credentials have correct ownership)
|
|
111
|
-
|
|
135
|
+
// Pass "/login" as initial prompt so user doesn't have to type it manually
|
|
136
|
+
'npm install -g @anthropic-ai/claude-code@latest --silent 2>/dev/null && chown -R node:node /home/node/.claude && su -s /bin/bash -c "HOME=/home/node CLAUDE_CONFIG_DIR=/home/node/.claude claude \\"/login\\"" node'
|
|
112
137
|
], { stdio: 'inherit' });
|
|
113
138
|
return result.status === 0;
|
|
114
139
|
}
|
|
@@ -117,12 +142,74 @@ export default class Auth extends Command {
|
|
|
117
142
|
return false;
|
|
118
143
|
}
|
|
119
144
|
}
|
|
145
|
+
/**
|
|
146
|
+
* Handle API key authentication flow
|
|
147
|
+
*/
|
|
148
|
+
handleApiKey(jsonMode, flags) {
|
|
149
|
+
const apiKey = process.env.ANTHROPIC_API_KEY;
|
|
150
|
+
if (!apiKey) {
|
|
151
|
+
if (jsonMode) {
|
|
152
|
+
outputErrorAsJson('API_KEY_NOT_SET', 'ANTHROPIC_API_KEY is not set in your environment. Export it and try again.', createMetadata('agent auth', flags));
|
|
153
|
+
}
|
|
154
|
+
this.error('ANTHROPIC_API_KEY is not set in your environment.\nExport it with: export ANTHROPIC_API_KEY=sk-ant-...');
|
|
155
|
+
}
|
|
156
|
+
// Save preference to config if in an HQ
|
|
157
|
+
const db = this.tryOpenDb();
|
|
158
|
+
if (db) {
|
|
159
|
+
try {
|
|
160
|
+
saveAuthMethod(db, 'apikey');
|
|
161
|
+
}
|
|
162
|
+
finally {
|
|
163
|
+
db.close();
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
if (jsonMode) {
|
|
167
|
+
outputSuccessAsJson({
|
|
168
|
+
authenticated: true,
|
|
169
|
+
method: 'apikey',
|
|
170
|
+
message: 'ANTHROPIC_API_KEY is set. Auth method saved as default.',
|
|
171
|
+
}, createMetadata('agent auth', flags));
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
this.log(colors.success('✓ ANTHROPIC_API_KEY is set'));
|
|
175
|
+
this.log(colors.textSecondary(' Auth method saved as default: apikey'));
|
|
176
|
+
this.log(colors.textSecondary(' Containers will use your API key for authentication.'));
|
|
177
|
+
this.log('');
|
|
178
|
+
this.log(colors.warning(' Note: This uses API credits, not your Max subscription.'));
|
|
179
|
+
this.log(colors.textSecondary(` Run "${this.config.bin} agent auth" (without --api-key) to switch to OAuth.`));
|
|
180
|
+
}
|
|
120
181
|
async run() {
|
|
121
182
|
const { flags } = await this.parse(Auth);
|
|
122
183
|
// Check if JSON output mode is active
|
|
123
184
|
const jsonMode = shouldOutputJson(flags);
|
|
124
|
-
|
|
185
|
+
const jsonModeConfig = jsonMode ? { flags, commandName: 'agent auth' } : null;
|
|
186
|
+
// Handle --api-key shortcut: validate key and save preference
|
|
187
|
+
if (flags['api-key']) {
|
|
188
|
+
this.handleApiKey(jsonMode, flags);
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
// Check Docker is running (needed for OAuth flow)
|
|
125
192
|
if (!isDockerRunning()) {
|
|
193
|
+
// If Docker isn't running, offer API key as alternative
|
|
194
|
+
const hasApiKey = !!process.env.ANTHROPIC_API_KEY;
|
|
195
|
+
if (hasApiKey && !flags.check) {
|
|
196
|
+
this.log(colors.warning('Docker is not running.'));
|
|
197
|
+
this.log('');
|
|
198
|
+
const { authChoice } = await this.prompt([{
|
|
199
|
+
type: 'list',
|
|
200
|
+
name: 'authChoice',
|
|
201
|
+
message: 'Docker is required for OAuth. Use API key instead?',
|
|
202
|
+
choices: [
|
|
203
|
+
{ name: 'Use ANTHROPIC_API_KEY instead (API credits)', value: 'apikey', command: `${this.config.bin} agent auth --api-key --json` },
|
|
204
|
+
{ name: 'Cancel (start Docker first for OAuth)', value: 'cancel' },
|
|
205
|
+
],
|
|
206
|
+
default: 'apikey',
|
|
207
|
+
}], jsonModeConfig);
|
|
208
|
+
if (authChoice === 'apikey') {
|
|
209
|
+
this.handleApiKey(jsonMode, flags);
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
126
213
|
if (jsonMode) {
|
|
127
214
|
outputErrorAsJson('DOCKER_NOT_RUNNING', 'Docker is not running. Please start Docker Desktop and try again.', createMetadata('agent auth', flags));
|
|
128
215
|
}
|
|
@@ -144,6 +231,7 @@ export default class Auth extends Command {
|
|
|
144
231
|
if (jsonMode) {
|
|
145
232
|
outputSuccessAsJson({
|
|
146
233
|
authenticated: true,
|
|
234
|
+
method: 'oauth',
|
|
147
235
|
subscriptionType: info?.subscriptionType || 'unknown',
|
|
148
236
|
expiresAt: info?.expiresAt.toISOString(),
|
|
149
237
|
}, createMetadata('agent auth', flags));
|
|
@@ -169,6 +257,7 @@ export default class Auth extends Command {
|
|
|
169
257
|
if (jsonMode) {
|
|
170
258
|
outputSuccessAsJson({
|
|
171
259
|
authenticated: true,
|
|
260
|
+
method: 'oauth',
|
|
172
261
|
subscriptionType: info?.subscriptionType || 'unknown',
|
|
173
262
|
expiresAt: info?.expiresAt.toISOString(),
|
|
174
263
|
message: 'Credentials already configured. Use --force to re-authenticate.',
|
|
@@ -184,17 +273,49 @@ export default class Auth extends Command {
|
|
|
184
273
|
this.log(colors.text('Use --force to re-authenticate.'));
|
|
185
274
|
return;
|
|
186
275
|
}
|
|
276
|
+
// Prompt for auth method choice (OAuth or API key)
|
|
277
|
+
const hasApiKey = !!process.env.ANTHROPIC_API_KEY;
|
|
278
|
+
// Only prompt if there's a real choice (API key is available)
|
|
279
|
+
let selectedMethod = 'oauth';
|
|
280
|
+
if (hasApiKey) {
|
|
281
|
+
const { selectedMethod: chosen } = await this.prompt([{
|
|
282
|
+
type: 'list',
|
|
283
|
+
name: 'selectedMethod',
|
|
284
|
+
message: 'Which authentication method would you like to use?',
|
|
285
|
+
choices: [
|
|
286
|
+
{ name: 'OAuth (recommended — uses Max subscription)', value: 'oauth', command: `${this.config.bin} agent auth --force --json` },
|
|
287
|
+
{ name: 'API key (uses API credits, not Max subscription)', value: 'apikey', command: `${this.config.bin} agent auth --api-key --json` },
|
|
288
|
+
],
|
|
289
|
+
default: 'oauth',
|
|
290
|
+
}], jsonModeConfig);
|
|
291
|
+
selectedMethod = chosen;
|
|
292
|
+
}
|
|
293
|
+
if (selectedMethod === 'apikey') {
|
|
294
|
+
this.handleApiKey(jsonMode, flags);
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
187
297
|
// JSON mode cannot handle interactive login flow
|
|
188
298
|
if (jsonMode) {
|
|
189
299
|
outputErrorAsJson('INTERACTIVE_REQUIRED', 'Authentication requires interactive login. Run without --json flag to authenticate.', createMetadata('agent auth', flags));
|
|
190
300
|
}
|
|
191
|
-
// Run the login flow
|
|
301
|
+
// Run the OAuth login flow
|
|
192
302
|
const success = this.runLoginFlow();
|
|
193
303
|
if (success && this.credentialsExist()) {
|
|
304
|
+
// Save OAuth as auth method preference
|
|
305
|
+
const db = this.tryOpenDb();
|
|
306
|
+
if (db) {
|
|
307
|
+
try {
|
|
308
|
+
saveAuthMethod(db, 'oauth');
|
|
309
|
+
}
|
|
310
|
+
finally {
|
|
311
|
+
db.close();
|
|
312
|
+
}
|
|
313
|
+
}
|
|
194
314
|
this.log('');
|
|
195
315
|
this.log(colors.success('✓ Authentication successful!'));
|
|
196
316
|
this.log(colors.textSecondary(' Credentials saved to Docker volume: ' + CLAUDE_CREDENTIALS_VOLUME));
|
|
197
317
|
this.log(colors.textSecondary(' All agent containers will share these credentials.'));
|
|
318
|
+
this.log(colors.textSecondary(' Auth method saved as default: oauth'));
|
|
198
319
|
}
|
|
199
320
|
else {
|
|
200
321
|
this.log('');
|
|
@@ -45,6 +45,7 @@ export default class Agent extends PMOCommand {
|
|
|
45
45
|
{ name: '🗑️ Remove agent', value: 'remove', command: 'prlt agent remove --machine' },
|
|
46
46
|
// Management group
|
|
47
47
|
{ name: '👔 Manage staff agents', value: 'staff', command: 'prlt agent staff --machine' },
|
|
48
|
+
{ name: '⏱️ Manage temp agents', value: 'temp', command: 'prlt agent temp --machine' },
|
|
48
49
|
{ name: '🧹 Cleanup agents', value: 'cleanup', command: 'prlt agent cleanup --machine' },
|
|
49
50
|
{ name: '🎨 Manage themes', value: 'themes', command: 'prlt agent themes --machine' },
|
|
50
51
|
// Operations group
|
|
@@ -89,11 +90,19 @@ export default class Agent extends PMOCommand {
|
|
|
89
90
|
break;
|
|
90
91
|
}
|
|
91
92
|
case 'staff': {
|
|
92
|
-
const { default: StaffCommand } = await import('
|
|
93
|
+
const { default: StaffCommand } = await import('./staff/index.js');
|
|
93
94
|
const cmd = new StaffCommand([], this.config);
|
|
94
95
|
await cmd.run();
|
|
95
96
|
break;
|
|
96
97
|
}
|
|
98
|
+
case 'temp': {
|
|
99
|
+
// @ts-expect-error -- temp subcommand not yet implemented
|
|
100
|
+
// eslint-disable-next-line import/no-unresolved -- temp subcommand not yet implemented
|
|
101
|
+
const { default: TempCommand } = await import('./temp/index.js');
|
|
102
|
+
const cmd = new TempCommand([], this.config);
|
|
103
|
+
await cmd.run();
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
97
106
|
case 'cleanup': {
|
|
98
107
|
const { default: CleanupCommand } = await import('./cleanup.js');
|
|
99
108
|
const cmd = new CleanupCommand([], this.config);
|
|
@@ -101,7 +110,7 @@ export default class Agent extends PMOCommand {
|
|
|
101
110
|
break;
|
|
102
111
|
}
|
|
103
112
|
case 'themes': {
|
|
104
|
-
const { default: ThemeCommand } = await import('
|
|
113
|
+
const { default: ThemeCommand } = await import('./themes/index.js');
|
|
105
114
|
const cmd = new ThemeCommand([], this.config);
|
|
106
115
|
await cmd.run();
|
|
107
116
|
break;
|
|
@@ -35,8 +35,8 @@ export default class List extends PMOCommand {
|
|
|
35
35
|
const activeAgents = workspaceInfo.agents.filter(a => a.status === 'active');
|
|
36
36
|
// Determine type filter - prompt if not provided (but not in JSON mode)
|
|
37
37
|
let typeFilter = flags.type;
|
|
38
|
-
// In JSON mode
|
|
39
|
-
if (jsonMode
|
|
38
|
+
// In JSON mode, output agents as JSON respecting the type filter
|
|
39
|
+
if (jsonMode) {
|
|
40
40
|
const staffAgents = activeAgents.filter(a => a.type === 'persistent');
|
|
41
41
|
const tempAgents = activeAgents.filter(a => a.type === 'ephemeral');
|
|
42
42
|
const agentsStatus = getAllAgentsStatus(workspaceInfo);
|
|
@@ -56,11 +56,20 @@ export default class List extends PMOCommand {
|
|
|
56
56
|
};
|
|
57
57
|
});
|
|
58
58
|
};
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
59
|
+
let output;
|
|
60
|
+
if (typeFilter === 'staff') {
|
|
61
|
+
output = { staff: formatAgentJson(staffAgents) };
|
|
62
|
+
}
|
|
63
|
+
else if (typeFilter === 'temp') {
|
|
64
|
+
output = { temp: formatAgentJson(tempAgents) };
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
// No filter or 'all' - return both groups without redundant combined array
|
|
68
|
+
output = {
|
|
69
|
+
staff: formatAgentJson(staffAgents),
|
|
70
|
+
temp: formatAgentJson(tempAgents),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
64
73
|
this.log(JSON.stringify(output, null, 2));
|
|
65
74
|
return;
|
|
66
75
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '../../staff/add.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '../../staff/add.js';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { PMOCommand } from '../../../lib/pmo/index.js';
|
|
2
|
+
export default class AgentStaff extends PMOCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
'no-interactive': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
7
|
+
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
8
|
+
machine: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
9
|
+
project: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
};
|
|
11
|
+
protected getPMOOptions(): {
|
|
12
|
+
promptIfMultiple: boolean;
|
|
13
|
+
};
|
|
14
|
+
execute(): Promise<void>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { Flags } from '@oclif/core';
|
|
2
|
+
import inquirer from 'inquirer';
|
|
3
|
+
import { colors } from '../../../lib/colors.js';
|
|
4
|
+
import { PMOCommand, pmoBaseFlags } from '../../../lib/pmo/index.js';
|
|
5
|
+
import { shouldOutputJson, outputPromptAsJson, createMetadata, buildPromptConfig, } from '../../../lib/prompt-json.js';
|
|
6
|
+
export default class AgentStaff extends PMOCommand {
|
|
7
|
+
static description = 'Manage staff (persistent) agents';
|
|
8
|
+
static examples = [
|
|
9
|
+
'<%= config.bin %> <%= command.id %> list',
|
|
10
|
+
'<%= config.bin %> <%= command.id %> add',
|
|
11
|
+
'<%= config.bin %> <%= command.id %> remove camry',
|
|
12
|
+
];
|
|
13
|
+
static flags = {
|
|
14
|
+
...pmoBaseFlags,
|
|
15
|
+
'no-interactive': Flags.boolean({
|
|
16
|
+
description: 'Alias for --json flag',
|
|
17
|
+
default: false,
|
|
18
|
+
}),
|
|
19
|
+
};
|
|
20
|
+
getPMOOptions() {
|
|
21
|
+
return { promptIfMultiple: false };
|
|
22
|
+
}
|
|
23
|
+
async execute() {
|
|
24
|
+
const { flags } = await this.parse(AgentStaff);
|
|
25
|
+
const jsonMode = shouldOutputJson(flags);
|
|
26
|
+
const menuChoices = [
|
|
27
|
+
{ name: 'List staff agents', value: 'list', command: 'prlt agent staff list --machine' },
|
|
28
|
+
{ name: 'Add staff agent', value: 'add', command: 'prlt agent staff add --machine' },
|
|
29
|
+
{ name: 'Remove staff agent', value: 'remove', command: 'prlt agent staff remove --machine' },
|
|
30
|
+
{ name: 'Cancel', value: 'cancel', command: '' },
|
|
31
|
+
];
|
|
32
|
+
const message = 'What would you like to do?';
|
|
33
|
+
if (jsonMode) {
|
|
34
|
+
outputPromptAsJson(buildPromptConfig('list', 'action', message, menuChoices), createMetadata('agent staff', flags));
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
this.log(colors.primary('Staff Agents'));
|
|
38
|
+
this.log(colors.textMuted('Persistent agents with dedicated worktrees.\n'));
|
|
39
|
+
const { action } = await this.prompt([{
|
|
40
|
+
type: 'list',
|
|
41
|
+
name: 'action',
|
|
42
|
+
message,
|
|
43
|
+
choices: [
|
|
44
|
+
{ name: '📋 ' + menuChoices[0].name, value: menuChoices[0].value },
|
|
45
|
+
{ name: '➕ ' + menuChoices[1].name, value: menuChoices[1].value },
|
|
46
|
+
{ name: '🗑️ ' + menuChoices[2].name, value: menuChoices[2].value },
|
|
47
|
+
new inquirer.Separator(),
|
|
48
|
+
{ name: '❌ ' + menuChoices[3].name, value: menuChoices[3].value },
|
|
49
|
+
]
|
|
50
|
+
}], null);
|
|
51
|
+
if (action === 'cancel') {
|
|
52
|
+
this.log(colors.textMuted('Operation cancelled.'));
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
try {
|
|
56
|
+
switch (action) {
|
|
57
|
+
case 'list': {
|
|
58
|
+
const { default: ListCommand } = await import('./list.js');
|
|
59
|
+
const cmd = new ListCommand([], this.config);
|
|
60
|
+
await cmd.run();
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
case 'add': {
|
|
64
|
+
const { default: AddCommand } = await import('./add.js');
|
|
65
|
+
const cmd = new AddCommand([], this.config);
|
|
66
|
+
await cmd.run();
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
case 'remove': {
|
|
70
|
+
const { default: RemoveCommand } = await import('./remove.js');
|
|
71
|
+
const cmd = new RemoveCommand([], this.config);
|
|
72
|
+
await cmd.run();
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
default:
|
|
76
|
+
this.error(`Unknown action: ${action}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
this.error(`Failed to execute staff ${action}: ${error instanceof Error ? error.message : String(error)}`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '../../staff/list.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '../../staff/list.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '../../staff/remove.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '../../staff/remove.js';
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Args } from '@oclif/core';
|
|
2
2
|
import { colors, format } from '../../lib/colors.js';
|
|
3
|
-
import { getWorkspaceInfo, getAgentStatus, formatAgentList } from '../../lib/agents/commands.js';
|
|
3
|
+
import { getWorkspaceInfo, getAgentStatus, getAllAgentsStatus, formatAgentList } from '../../lib/agents/commands.js';
|
|
4
4
|
import { PMOCommand, pmoBaseFlags } from '../../lib/pmo/index.js';
|
|
5
|
-
import { shouldOutputJson, outputErrorAsJson, createMetadata, } from '../../lib/prompt-json.js';
|
|
5
|
+
import { shouldOutputJson, outputErrorAsJson, outputSuccessAsJson, createMetadata, } from '../../lib/prompt-json.js';
|
|
6
6
|
export default class Status extends PMOCommand {
|
|
7
7
|
static description = 'Show detailed status for a specific agent';
|
|
8
8
|
static examples = [
|
|
@@ -36,6 +36,13 @@ export default class Status extends PMOCommand {
|
|
|
36
36
|
return;
|
|
37
37
|
}
|
|
38
38
|
let agentName = args.name;
|
|
39
|
+
// In JSON mode with no agent specified, return all agent statuses
|
|
40
|
+
if (jsonMode && !agentName) {
|
|
41
|
+
const allStatuses = getAllAgentsStatus(workspaceInfo);
|
|
42
|
+
outputSuccessAsJson({
|
|
43
|
+
agents: allStatuses,
|
|
44
|
+
}, createMetadata('agent status', flags));
|
|
45
|
+
}
|
|
39
46
|
// Agent mode config for prompts
|
|
40
47
|
const agentConfig = jsonMode ? { flags, commandName: 'agent status' } : null;
|
|
41
48
|
// Interactive mode if no agent specified
|
|
@@ -59,15 +66,36 @@ export default class Status extends PMOCommand {
|
|
|
59
66
|
}], agentConfig);
|
|
60
67
|
agentName = selected;
|
|
61
68
|
}
|
|
62
|
-
await this.showDetailedStatus(workspaceInfo, agentName);
|
|
69
|
+
await this.showDetailedStatus(workspaceInfo, agentName, jsonMode);
|
|
63
70
|
}
|
|
64
|
-
async showDetailedStatus(workspaceInfo, agentName) {
|
|
71
|
+
async showDetailedStatus(workspaceInfo, agentName, jsonMode = false) {
|
|
65
72
|
// Validate agent exists
|
|
66
73
|
const agent = workspaceInfo.agents.find((a) => a.name === agentName);
|
|
67
74
|
if (!agent) {
|
|
68
75
|
this.error(`Agent "${agentName}" not found. Available: ${formatAgentList(workspaceInfo.agents)}`);
|
|
69
76
|
}
|
|
70
77
|
const agentStatus = getAgentStatus(workspaceInfo, agentName);
|
|
78
|
+
// JSON output mode
|
|
79
|
+
if (jsonMode) {
|
|
80
|
+
this.log(JSON.stringify({
|
|
81
|
+
success: true,
|
|
82
|
+
agent: {
|
|
83
|
+
name: agentName,
|
|
84
|
+
type: agent.type,
|
|
85
|
+
exists: agentStatus.exists,
|
|
86
|
+
path: `${workspaceInfo.agentsPath}/${agentName}`,
|
|
87
|
+
branch: agentStatus.branch,
|
|
88
|
+
repositories: agentStatus.repositories.map(r => ({
|
|
89
|
+
name: r.name,
|
|
90
|
+
status: r.status,
|
|
91
|
+
commitsAhead: r.commitsAhead,
|
|
92
|
+
})),
|
|
93
|
+
assignedTickets: agentStatus.assignedTickets,
|
|
94
|
+
completedTickets: agentStatus.completedTickets,
|
|
95
|
+
},
|
|
96
|
+
}, null, 2));
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
71
99
|
this.log(format.title(`🤖 Agent: ${agentName}`));
|
|
72
100
|
// Basic status
|
|
73
101
|
const statusIcon = agentStatus.exists ? '🟢' : '🔴';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '../../theme/add-names.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '../../theme/add-names.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '../../theme/create.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '../../theme/create.js';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { PromptCommand } from '../../../lib/prompt-command.js';
|
|
2
|
+
export default class AgentThemes extends PromptCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
7
|
+
machine: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
8
|
+
};
|
|
9
|
+
run(): Promise<void>;
|
|
10
|
+
}
|