@proletariat/cli 0.3.35 → 0.3.40
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/README.md +37 -2
- package/bin/dev.js +0 -0
- package/dist/commands/agent/auth.d.ts +12 -2
- package/dist/commands/agent/auth.js +128 -4
- package/dist/commands/agent/list.js +16 -7
- package/dist/commands/agent/status.js +32 -4
- 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 +9 -19
- 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/ticket.js +7 -24
- package/dist/commands/epic/view.js +27 -0
- package/dist/commands/execution/config.d.ts +0 -4
- package/dist/commands/execution/config.js +14 -46
- package/dist/commands/execution/index.js +2 -1
- package/dist/commands/execution/logs.js +7 -1
- package/dist/commands/execution/stop.js +2 -1
- package/dist/commands/execution/view.js +30 -26
- package/dist/commands/init.js +2 -19
- package/dist/commands/label/create.js +2 -1
- package/dist/commands/label/delete.js +2 -1
- package/dist/commands/label/group/create.js +2 -1
- package/dist/commands/label/group/list.js +2 -1
- package/dist/commands/label/list.js +2 -1
- package/dist/commands/mcp-server.js +27 -1
- package/dist/commands/phase/template/list.js +2 -1
- package/dist/commands/pmo/init.js +12 -40
- package/dist/commands/project/create.js +3 -4
- package/dist/commands/project/update.js +5 -6
- package/dist/commands/pull.js +24 -0
- package/dist/commands/qa/index.d.ts +54 -0
- package/dist/commands/qa/index.js +762 -0
- package/dist/commands/repo/view.js +2 -8
- package/dist/commands/session/attach.js +4 -4
- package/dist/commands/session/create.d.ts +19 -0
- package/dist/commands/session/create.js +102 -0
- package/dist/commands/session/health.js +4 -23
- package/dist/commands/session/index.js +14 -1
- package/dist/commands/session/list.js +9 -8
- 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/view.js +29 -0
- 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/epic.js +17 -43
- package/dist/commands/ticket/index.js +2 -2
- package/dist/commands/ticket/move.js +25 -2
- package/dist/commands/ticket/resolve.js +3 -4
- package/dist/commands/ticket/show.d.ts +13 -0
- package/dist/commands/ticket/show.js +16 -0
- package/dist/commands/ticket/template/list.js +2 -1
- package/dist/commands/ticket/view.d.ts +0 -1
- package/dist/commands/ticket/view.js +30 -1
- package/dist/commands/work/index.js +4 -0
- package/dist/commands/work/spawn-all.js +1 -1
- package/dist/commands/work/spawn.js +15 -4
- package/dist/commands/work/start.js +186 -103
- package/dist/commands/work/status.d.ts +14 -0
- package/dist/commands/work/status.js +60 -0
- package/dist/commands/work/watch.js +1 -1
- 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 +7 -7
- package/dist/hooks/init.js +10 -2
- package/dist/lib/agents/commands.d.ts +5 -0
- package/dist/lib/agents/commands.js +143 -97
- package/dist/lib/branch/index.d.ts +1 -0
- package/dist/lib/database/drizzle-schema.d.ts +465 -0
- package/dist/lib/database/drizzle-schema.js +53 -0
- package/dist/lib/database/index.d.ts +47 -1
- package/dist/lib/database/index.js +138 -20
- package/dist/lib/execution/config.d.ts +15 -1
- package/dist/lib/execution/config.js +28 -0
- package/dist/lib/execution/runners.d.ts +45 -0
- package/dist/lib/execution/runners.js +187 -26
- package/dist/lib/execution/session-utils.d.ts +16 -1
- package/dist/lib/execution/session-utils.js +71 -4
- package/dist/lib/execution/spawner.js +15 -2
- package/dist/lib/execution/storage.d.ts +6 -1
- package/dist/lib/execution/storage.js +35 -5
- package/dist/lib/execution/types.d.ts +3 -0
- package/dist/lib/mcp/tools/board.js +4 -6
- package/dist/lib/mcp/tools/cli-passthrough.js +25 -6
- 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/spec.js +1 -1
- package/dist/lib/mcp/tools/ticket.js +11 -9
- package/dist/lib/mcp/tools/tmux.d.ts +16 -0
- package/dist/lib/mcp/tools/tmux.js +182 -0
- package/dist/lib/mcp/tools/work.js +148 -6
- package/dist/lib/mcp/types.d.ts +10 -0
- package/dist/lib/multiline-input.js +2 -1
- package/dist/lib/pmo/base-command.js +4 -4
- package/dist/lib/pmo/schema.d.ts +1 -1
- package/dist/lib/pmo/schema.js +1 -0
- package/dist/lib/pmo/storage/actions.js +1 -1
- package/dist/lib/pmo/storage/base.js +402 -50
- package/dist/lib/pmo/storage/dependencies.d.ts +1 -0
- package/dist/lib/pmo/storage/dependencies.js +11 -3
- package/dist/lib/pmo/storage/epics.js +1 -1
- package/dist/lib/pmo/storage/helpers.d.ts +4 -4
- package/dist/lib/pmo/storage/helpers.js +36 -26
- package/dist/lib/pmo/storage/projects.d.ts +2 -0
- package/dist/lib/pmo/storage/projects.js +207 -119
- package/dist/lib/pmo/storage/specs.d.ts +2 -0
- package/dist/lib/pmo/storage/specs.js +274 -188
- package/dist/lib/pmo/storage/tickets.d.ts +2 -0
- package/dist/lib/pmo/storage/tickets.js +350 -290
- package/dist/lib/pmo/storage/types.d.ts +1 -0
- package/dist/lib/pmo/storage/views.d.ts +2 -0
- package/dist/lib/pmo/storage/views.js +183 -130
- package/dist/lib/prompt-command.d.ts +20 -0
- package/dist/lib/prompt-command.js +38 -2
- package/dist/lib/prompt-json.d.ts +41 -4
- package/dist/lib/prompt-json.js +138 -7
- package/dist/lib/styles.d.ts +37 -0
- package/dist/lib/styles.js +73 -0
- package/oclif.manifest.json +4046 -3385
- package/package.json +11 -6
- package/LICENSE +0 -190
|
@@ -2,7 +2,7 @@ import { Args } from '@oclif/core';
|
|
|
2
2
|
import { PMOCommand, pmoBaseFlags } from '../../lib/pmo/index.js';
|
|
3
3
|
import { colors, format } from '../../lib/colors.js';
|
|
4
4
|
import { findHQRoot, getWorkspaceRepoInfo, } from '../../lib/repos/index.js';
|
|
5
|
-
import {
|
|
5
|
+
import { getWorktreesForRepo } from '../../lib/database/index.js';
|
|
6
6
|
import { shouldOutputJson, outputErrorAsJson, createMetadata, } from '../../lib/prompt-json.js';
|
|
7
7
|
import { visualPadEnd } from '../../lib/string-utils.js';
|
|
8
8
|
export default class View extends PMOCommand {
|
|
@@ -102,13 +102,7 @@ export default class View extends PMOCommand {
|
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
104
|
// Get agent worktree info
|
|
105
|
-
const
|
|
106
|
-
const worktrees = db.prepare(`
|
|
107
|
-
SELECT agent_name, is_clean, commits_ahead, branch
|
|
108
|
-
FROM agent_worktrees
|
|
109
|
-
WHERE repo_name = ?
|
|
110
|
-
`).all(repoName);
|
|
111
|
-
db.close();
|
|
105
|
+
const worktrees = getWorktreesForRepo(hqPath, repoName);
|
|
112
106
|
if (worktrees.length > 0) {
|
|
113
107
|
this.log(format.subtitle('\n👥 Agent Worktrees:'));
|
|
114
108
|
for (const wt of worktrees) {
|
|
@@ -7,7 +7,7 @@ import Database from 'better-sqlite3';
|
|
|
7
7
|
import { styles } from '../../lib/styles.js';
|
|
8
8
|
import { getWorkspaceInfo } from '../../lib/agents/commands.js';
|
|
9
9
|
import { ExecutionStorage } from '../../lib/execution/index.js';
|
|
10
|
-
import { parseSessionName, getHostTmuxSessionNames, getContainerTmuxSessionMap, flattenContainerSessions, findSessionForExecution, } from '../../lib/execution/session-utils.js';
|
|
10
|
+
import { parseSessionName, getHostTmuxSessionNames, getContainerTmuxSessionMap, flattenContainerSessions, findContainerSessionsByPrefix, findSessionForExecution, } from '../../lib/execution/session-utils.js';
|
|
11
11
|
import { PMOCommand, pmoBaseFlags } from '../../lib/pmo/index.js';
|
|
12
12
|
import { shouldOutputJson, outputErrorAsJson, createMetadata, } from '../../lib/prompt-json.js';
|
|
13
13
|
export default class SessionAttach extends PMOCommand {
|
|
@@ -154,7 +154,7 @@ export default class SessionAttach extends PMOCommand {
|
|
|
154
154
|
// If sessionId is NULL, try to find session by naming convention
|
|
155
155
|
if (!exec.sessionId) {
|
|
156
156
|
if (isContainer && exec.containerId) {
|
|
157
|
-
const containerSessions = containerTmuxSessions
|
|
157
|
+
const containerSessions = findContainerSessionsByPrefix(containerTmuxSessions, exec.containerId);
|
|
158
158
|
const match = findSessionForExecution(exec.ticketId, exec.agentName, containerSessions);
|
|
159
159
|
if (match) {
|
|
160
160
|
actualSessionId = match;
|
|
@@ -177,8 +177,8 @@ export default class SessionAttach extends PMOCommand {
|
|
|
177
177
|
else {
|
|
178
178
|
// sessionId is set, verify it exists
|
|
179
179
|
if (isContainer && exec.containerId) {
|
|
180
|
-
const containerSessions = containerTmuxSessions
|
|
181
|
-
exists = containerSessions
|
|
180
|
+
const containerSessions = findContainerSessionsByPrefix(containerTmuxSessions, exec.containerId);
|
|
181
|
+
exists = containerSessions.includes(exec.sessionId);
|
|
182
182
|
containerId = exec.containerId;
|
|
183
183
|
}
|
|
184
184
|
else {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { PMOCommand } from '../../lib/pmo/index.js';
|
|
2
|
+
export default class SessionCreate extends PMOCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static args: {
|
|
6
|
+
name: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
7
|
+
};
|
|
8
|
+
static flags: {
|
|
9
|
+
command: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
detach: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
11
|
+
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
12
|
+
machine: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
13
|
+
project: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
|
+
};
|
|
15
|
+
protected getPMOOptions(): {
|
|
16
|
+
promptIfMultiple: boolean;
|
|
17
|
+
};
|
|
18
|
+
execute(): Promise<void>;
|
|
19
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { Args, Flags } from '@oclif/core';
|
|
2
|
+
import { execSync } from 'node:child_process';
|
|
3
|
+
import { styles } from '../../lib/styles.js';
|
|
4
|
+
import { PMOCommand, pmoBaseFlags } from '../../lib/pmo/index.js';
|
|
5
|
+
import { shouldOutputJson, outputSuccessAsJson, outputErrorAsJson, createMetadata, } from '../../lib/prompt-json.js';
|
|
6
|
+
export default class SessionCreate extends PMOCommand {
|
|
7
|
+
static description = 'Create a new tmux session';
|
|
8
|
+
static examples = [
|
|
9
|
+
'<%= config.bin %> <%= command.id %> my-session',
|
|
10
|
+
'<%= config.bin %> <%= command.id %> my-session --command "npm run dev"',
|
|
11
|
+
'<%= config.bin %> <%= command.id %> my-session --detach',
|
|
12
|
+
];
|
|
13
|
+
static args = {
|
|
14
|
+
name: Args.string({
|
|
15
|
+
description: 'Name for the new tmux session',
|
|
16
|
+
required: true,
|
|
17
|
+
}),
|
|
18
|
+
};
|
|
19
|
+
static flags = {
|
|
20
|
+
...pmoBaseFlags,
|
|
21
|
+
command: Flags.string({
|
|
22
|
+
char: 'c',
|
|
23
|
+
description: 'Initial command to run in the session',
|
|
24
|
+
}),
|
|
25
|
+
detach: Flags.boolean({
|
|
26
|
+
char: 'd',
|
|
27
|
+
description: 'Create session in detached mode (do not attach)',
|
|
28
|
+
default: false,
|
|
29
|
+
}),
|
|
30
|
+
};
|
|
31
|
+
getPMOOptions() {
|
|
32
|
+
return { promptIfMultiple: false };
|
|
33
|
+
}
|
|
34
|
+
async execute() {
|
|
35
|
+
const { args, flags } = await this.parse(SessionCreate);
|
|
36
|
+
const jsonMode = shouldOutputJson(flags);
|
|
37
|
+
const sessionName = args.name;
|
|
38
|
+
// Check if tmux is available
|
|
39
|
+
try {
|
|
40
|
+
execSync('which tmux', { stdio: 'pipe' });
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
if (jsonMode) {
|
|
44
|
+
outputErrorAsJson('TMUX_NOT_FOUND', 'tmux is not installed or not in PATH.', createMetadata('session create', flags));
|
|
45
|
+
}
|
|
46
|
+
this.error('tmux is not installed or not in PATH.');
|
|
47
|
+
}
|
|
48
|
+
// Check if a session with this name already exists
|
|
49
|
+
try {
|
|
50
|
+
execSync(`tmux has-session -t "${sessionName}" 2>/dev/null`, { stdio: 'pipe' });
|
|
51
|
+
// If we get here, session exists
|
|
52
|
+
if (jsonMode) {
|
|
53
|
+
outputErrorAsJson('SESSION_EXISTS', `A tmux session named "${sessionName}" already exists.`, createMetadata('session create', flags));
|
|
54
|
+
}
|
|
55
|
+
this.error(`A tmux session named "${sessionName}" already exists.`);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
// Session doesn't exist, good to proceed
|
|
59
|
+
}
|
|
60
|
+
// Build the tmux new-session command
|
|
61
|
+
const tmuxArgs = ['tmux', 'new-session'];
|
|
62
|
+
// Always use detached mode for creation, then attach if needed
|
|
63
|
+
tmuxArgs.push('-d');
|
|
64
|
+
tmuxArgs.push('-s', `"${sessionName}"`);
|
|
65
|
+
if (flags.command) {
|
|
66
|
+
tmuxArgs.push(`"${flags.command}"`);
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
execSync(tmuxArgs.join(' '), { stdio: 'pipe' });
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
const message = `Failed to create tmux session "${sessionName}": ${error instanceof Error ? error.message : error}`;
|
|
73
|
+
if (jsonMode) {
|
|
74
|
+
outputErrorAsJson('CREATE_FAILED', message, createMetadata('session create', flags));
|
|
75
|
+
}
|
|
76
|
+
this.error(message);
|
|
77
|
+
}
|
|
78
|
+
if (jsonMode) {
|
|
79
|
+
outputSuccessAsJson({
|
|
80
|
+
sessionName,
|
|
81
|
+
detached: flags.detach,
|
|
82
|
+
command: flags.command || null,
|
|
83
|
+
}, createMetadata('session create', flags));
|
|
84
|
+
}
|
|
85
|
+
this.log('');
|
|
86
|
+
this.log(styles.success(`Created tmux session: ${sessionName}`));
|
|
87
|
+
if (!flags.detach) {
|
|
88
|
+
this.log(styles.info(`Attaching to session: ${sessionName}`));
|
|
89
|
+
try {
|
|
90
|
+
execSync(`tmux attach -t "${sessionName}"`, { stdio: 'inherit' });
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
this.log(styles.muted(`Session "${sessionName}" is running in detached mode.`));
|
|
94
|
+
this.log(styles.muted(`Attach with: tmux attach -t "${sessionName}"`));
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
this.log(styles.muted(`Attach with: prlt session attach ${sessionName}`));
|
|
99
|
+
}
|
|
100
|
+
this.log('');
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -5,32 +5,13 @@ import Database from 'better-sqlite3';
|
|
|
5
5
|
import { styles } from '../../lib/styles.js';
|
|
6
6
|
import { getWorkspaceInfo } from '../../lib/agents/commands.js';
|
|
7
7
|
import { ExecutionStorage } from '../../lib/execution/index.js';
|
|
8
|
-
import { parseSessionName, getHostTmuxSessionNames, getContainerTmuxSessionMap, flattenContainerSessions, findSessionForExecution, } from '../../lib/execution/session-utils.js';
|
|
8
|
+
import { parseSessionName, getHostTmuxSessionNames, getContainerTmuxSessionMap, flattenContainerSessions, findContainerSessionsByPrefix, findSessionForExecution, captureTmuxPane, } from '../../lib/execution/session-utils.js';
|
|
9
9
|
import { PMOCommand, pmoBaseFlags } from '../../lib/pmo/index.js';
|
|
10
10
|
import { visualPadEnd } from '../../lib/string-utils.js';
|
|
11
11
|
import { shouldOutputJson, outputSuccessAsJson, outputErrorAsJson, createMetadata, } from '../../lib/prompt-json.js';
|
|
12
12
|
// =============================================================================
|
|
13
13
|
// Detection Logic
|
|
14
14
|
// =============================================================================
|
|
15
|
-
/**
|
|
16
|
-
* Capture the last N lines from a tmux pane.
|
|
17
|
-
*/
|
|
18
|
-
function captureTmuxPane(sessionId, lines, containerId) {
|
|
19
|
-
try {
|
|
20
|
-
const captureCmd = `tmux capture-pane -t "${sessionId}" -p -S -${lines}`;
|
|
21
|
-
if (containerId) {
|
|
22
|
-
return execSync(`docker exec ${containerId} bash -c '${captureCmd}'`, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], timeout: 10000 }).trim();
|
|
23
|
-
}
|
|
24
|
-
return execSync(captureCmd, {
|
|
25
|
-
encoding: 'utf-8',
|
|
26
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
27
|
-
timeout: 5000,
|
|
28
|
-
}).trim();
|
|
29
|
-
}
|
|
30
|
-
catch {
|
|
31
|
-
return null;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
15
|
/**
|
|
35
16
|
* Detect agent health state from tmux pane content.
|
|
36
17
|
*
|
|
@@ -187,7 +168,7 @@ export default class SessionHealth extends PMOCommand {
|
|
|
187
168
|
// Try to find session if sessionId is NULL
|
|
188
169
|
if (!exec.sessionId) {
|
|
189
170
|
if (isContainer && exec.containerId) {
|
|
190
|
-
const containerSessions = containerTmuxSessions
|
|
171
|
+
const containerSessions = findContainerSessionsByPrefix(containerTmuxSessions, exec.containerId);
|
|
191
172
|
const match = findSessionForExecution(exec.ticketId, exec.agentName, containerSessions);
|
|
192
173
|
if (match) {
|
|
193
174
|
actualSessionId = match;
|
|
@@ -207,8 +188,8 @@ export default class SessionHealth extends PMOCommand {
|
|
|
207
188
|
}
|
|
208
189
|
else {
|
|
209
190
|
if (isContainer && exec.containerId) {
|
|
210
|
-
const containerSessions = containerTmuxSessions
|
|
211
|
-
exists = containerSessions
|
|
191
|
+
const containerSessions = findContainerSessionsByPrefix(containerTmuxSessions, exec.containerId);
|
|
192
|
+
exists = containerSessions.includes(exec.sessionId);
|
|
212
193
|
containerId = exec.containerId;
|
|
213
194
|
}
|
|
214
195
|
else {
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { PMOCommand, pmoBaseFlags } from '../../lib/pmo/index.js';
|
|
2
2
|
import { shouldOutputJson } from '../../lib/prompt-json.js';
|
|
3
3
|
export default class Session extends PMOCommand {
|
|
4
|
-
static description = 'Manage agent tmux sessions (list, attach, detach)';
|
|
4
|
+
static description = 'Manage agent tmux sessions (list, attach, create, detach)';
|
|
5
5
|
static examples = [
|
|
6
6
|
'<%= config.bin %> <%= command.id %>',
|
|
7
7
|
'<%= config.bin %> <%= command.id %> list',
|
|
8
8
|
'<%= config.bin %> <%= command.id %> attach TKT-347-implement',
|
|
9
|
+
'<%= config.bin %> <%= command.id %> create my-session',
|
|
9
10
|
];
|
|
10
11
|
static flags = {
|
|
11
12
|
...pmoBaseFlags,
|
|
@@ -22,8 +23,11 @@ export default class Session extends PMOCommand {
|
|
|
22
23
|
message: 'Session Management - What would you like to do?',
|
|
23
24
|
choices: [
|
|
24
25
|
{ name: 'List active sessions', value: 'list', command: 'prlt session list --json' },
|
|
26
|
+
{ name: 'Create a new session', value: 'create', command: 'prlt session create --json' },
|
|
25
27
|
{ name: 'Attach to a session', value: 'attach', command: 'prlt session attach --json' },
|
|
28
|
+
{ name: 'Peek at agent output', value: 'peek', command: 'prlt session peek --json' },
|
|
26
29
|
{ name: 'Check agent health', value: 'health', command: 'prlt session health --json' },
|
|
30
|
+
{ name: 'Poke a running agent', value: 'poke', command: 'prlt session poke --json' },
|
|
27
31
|
{ name: 'Cancel', value: 'cancel' },
|
|
28
32
|
],
|
|
29
33
|
}], jsonModeConfig);
|
|
@@ -35,12 +39,21 @@ export default class Session extends PMOCommand {
|
|
|
35
39
|
case 'list':
|
|
36
40
|
await this.config.runCommand('session:list', []);
|
|
37
41
|
break;
|
|
42
|
+
case 'create':
|
|
43
|
+
await this.config.runCommand('session:create', []);
|
|
44
|
+
break;
|
|
38
45
|
case 'attach':
|
|
39
46
|
await this.config.runCommand('session:attach', []);
|
|
40
47
|
break;
|
|
48
|
+
case 'peek':
|
|
49
|
+
await this.config.runCommand('session:peek', []);
|
|
50
|
+
break;
|
|
41
51
|
case 'health':
|
|
42
52
|
await this.config.runCommand('session:health', []);
|
|
43
53
|
break;
|
|
54
|
+
case 'poke':
|
|
55
|
+
await this.config.runCommand('session:poke', []);
|
|
56
|
+
break;
|
|
44
57
|
}
|
|
45
58
|
}
|
|
46
59
|
}
|
|
@@ -4,7 +4,7 @@ import Database from 'better-sqlite3';
|
|
|
4
4
|
import { styles } from '../../lib/styles.js';
|
|
5
5
|
import { getWorkspaceInfo } from '../../lib/agents/commands.js';
|
|
6
6
|
import { ExecutionStorage } from '../../lib/execution/index.js';
|
|
7
|
-
import { parseSessionName, getHostTmuxSessionNames, getContainerTmuxSessionMap, flattenContainerSessions, findSessionForExecution, } from '../../lib/execution/session-utils.js';
|
|
7
|
+
import { parseSessionName, getHostTmuxSessionNames, getContainerTmuxSessionMap, flattenContainerSessions, findContainerSessionsByPrefix, findSessionForExecution, } from '../../lib/execution/session-utils.js';
|
|
8
8
|
import { PMOCommand, pmoBaseFlags } from '../../lib/pmo/index.js';
|
|
9
9
|
import { shouldOutputJson } from '../../lib/prompt-json.js';
|
|
10
10
|
import { visualPadEnd } from '../../lib/string-utils.js';
|
|
@@ -65,7 +65,7 @@ export default class SessionList extends PMOCommand {
|
|
|
65
65
|
// If sessionId is NULL, try to find session by naming convention
|
|
66
66
|
if (!exec.sessionId) {
|
|
67
67
|
if (isContainer && exec.containerId) {
|
|
68
|
-
const containerSessions = containerTmuxSessions
|
|
68
|
+
const containerSessions = findContainerSessionsByPrefix(containerTmuxSessions, exec.containerId);
|
|
69
69
|
const match = findSessionForExecution(exec.ticketId, exec.agentName, containerSessions);
|
|
70
70
|
if (match) {
|
|
71
71
|
actualSessionId = match;
|
|
@@ -88,8 +88,8 @@ export default class SessionList extends PMOCommand {
|
|
|
88
88
|
else {
|
|
89
89
|
// sessionId is set, verify it exists
|
|
90
90
|
if (isContainer && exec.containerId) {
|
|
91
|
-
const containerSessions = containerTmuxSessions
|
|
92
|
-
exists = containerSessions
|
|
91
|
+
const containerSessions = findContainerSessionsByPrefix(containerTmuxSessions, exec.containerId);
|
|
92
|
+
exists = containerSessions.includes(exec.sessionId);
|
|
93
93
|
containerId = exec.containerId;
|
|
94
94
|
}
|
|
95
95
|
else {
|
|
@@ -105,14 +105,15 @@ export default class SessionList extends PMOCommand {
|
|
|
105
105
|
matchedHostSessions.add(actualSessionId);
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
|
-
//
|
|
109
|
-
//
|
|
110
|
-
|
|
108
|
+
// Always include sessions from DB that have a sessionId.
|
|
109
|
+
// When tmux verification fails (e.g., Docker/tmux not accessible from MCP context),
|
|
110
|
+
// show the session with the DB status instead of silently dropping it.
|
|
111
|
+
if (actualSessionId) {
|
|
111
112
|
sessions.push({
|
|
112
113
|
sessionId: actualSessionId,
|
|
113
114
|
ticketId: exec.ticketId,
|
|
114
115
|
agentName: exec.agentName,
|
|
115
|
-
status: exists ? exec.status : 'stale',
|
|
116
|
+
status: exists ? exec.status : (flags.all ? 'stale' : exec.status),
|
|
116
117
|
environment: isContainer ? 'container' : 'host',
|
|
117
118
|
containerId,
|
|
118
119
|
exists,
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { PMOCommand } from '../../lib/pmo/index.js';
|
|
2
|
+
export default class SessionPeek extends PMOCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static args: {
|
|
6
|
+
target: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
7
|
+
};
|
|
8
|
+
static flags: {
|
|
9
|
+
lines: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
11
|
+
machine: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
12
|
+
project: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
|
+
};
|
|
14
|
+
protected getPMOOptions(): {
|
|
15
|
+
promptIfMultiple: boolean;
|
|
16
|
+
};
|
|
17
|
+
execute(): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* Resolve a target identifier to matching sessions.
|
|
20
|
+
* Supports: agent name, ticket ID (TKT-XXX), execution ID (WORK-XXX), or session ID.
|
|
21
|
+
*/
|
|
22
|
+
private resolveTarget;
|
|
23
|
+
/**
|
|
24
|
+
* Resolve an execution ID (WORK-XXX) to matching sessions.
|
|
25
|
+
*/
|
|
26
|
+
private resolveFromExecution;
|
|
27
|
+
/**
|
|
28
|
+
* Output peek content for a session.
|
|
29
|
+
* In raw mode: outputs plain text to stdout.
|
|
30
|
+
* In JSON mode: outputs structured JSON.
|
|
31
|
+
*/
|
|
32
|
+
private outputPeek;
|
|
33
|
+
/**
|
|
34
|
+
* Get verified sessions from DB that have actual tmux processes.
|
|
35
|
+
* Same discovery pattern as attach.ts and list.ts.
|
|
36
|
+
*/
|
|
37
|
+
private getVerifiedSessions;
|
|
38
|
+
}
|