@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.
Files changed (148) hide show
  1. package/README.md +37 -2
  2. package/bin/dev.js +0 -0
  3. package/dist/commands/agent/auth.d.ts +12 -2
  4. package/dist/commands/agent/auth.js +128 -4
  5. package/dist/commands/agent/list.js +16 -7
  6. package/dist/commands/agent/status.js +32 -4
  7. package/dist/commands/board/watch.js +6 -0
  8. package/dist/commands/branch/list.d.ts +1 -0
  9. package/dist/commands/branch/list.js +43 -12
  10. package/dist/commands/branch/where.js +9 -19
  11. package/dist/commands/category/list.d.ts +2 -1
  12. package/dist/commands/category/list.js +38 -13
  13. package/dist/commands/{claude.d.ts → claude/index.d.ts} +1 -1
  14. package/dist/commands/{claude.js → claude/index.js} +12 -12
  15. package/dist/commands/claude/open.d.ts +13 -0
  16. package/dist/commands/claude/open.js +175 -0
  17. package/dist/commands/diet.js +18 -2
  18. package/dist/commands/docker/logs.js +7 -3
  19. package/dist/commands/docker/shell.js +6 -0
  20. package/dist/commands/docker/start.js +20 -4
  21. package/dist/commands/docker/sync.d.ts +4 -0
  22. package/dist/commands/docker/sync.js +30 -2
  23. package/dist/commands/epic/show.d.ts +13 -0
  24. package/dist/commands/epic/show.js +16 -0
  25. package/dist/commands/epic/ticket.js +7 -24
  26. package/dist/commands/epic/view.js +27 -0
  27. package/dist/commands/execution/config.d.ts +0 -4
  28. package/dist/commands/execution/config.js +14 -46
  29. package/dist/commands/execution/index.js +2 -1
  30. package/dist/commands/execution/logs.js +7 -1
  31. package/dist/commands/execution/stop.js +2 -1
  32. package/dist/commands/execution/view.js +30 -26
  33. package/dist/commands/init.js +2 -19
  34. package/dist/commands/label/create.js +2 -1
  35. package/dist/commands/label/delete.js +2 -1
  36. package/dist/commands/label/group/create.js +2 -1
  37. package/dist/commands/label/group/list.js +2 -1
  38. package/dist/commands/label/list.js +2 -1
  39. package/dist/commands/mcp-server.js +27 -1
  40. package/dist/commands/phase/template/list.js +2 -1
  41. package/dist/commands/pmo/init.js +12 -40
  42. package/dist/commands/project/create.js +3 -4
  43. package/dist/commands/project/update.js +5 -6
  44. package/dist/commands/pull.js +24 -0
  45. package/dist/commands/qa/index.d.ts +54 -0
  46. package/dist/commands/qa/index.js +762 -0
  47. package/dist/commands/repo/view.js +2 -8
  48. package/dist/commands/session/attach.js +4 -4
  49. package/dist/commands/session/create.d.ts +19 -0
  50. package/dist/commands/session/create.js +102 -0
  51. package/dist/commands/session/health.js +4 -23
  52. package/dist/commands/session/index.js +14 -1
  53. package/dist/commands/session/list.js +9 -8
  54. package/dist/commands/session/peek.d.ts +38 -0
  55. package/dist/commands/session/peek.js +316 -0
  56. package/dist/commands/session/poke.d.ts +27 -0
  57. package/dist/commands/session/poke.js +219 -0
  58. package/dist/commands/spec/view.js +29 -0
  59. package/dist/commands/template/list.js +2 -1
  60. package/dist/commands/theme/add-names.d.ts +4 -0
  61. package/dist/commands/theme/add-names.js +11 -1
  62. package/dist/commands/theme/create.d.ts +2 -0
  63. package/dist/commands/theme/create.js +8 -0
  64. package/dist/commands/ticket/bulk.js +2 -2
  65. package/dist/commands/ticket/complete.js +2 -2
  66. package/dist/commands/ticket/create.js +21 -0
  67. package/dist/commands/ticket/delete.js +8 -0
  68. package/dist/commands/ticket/edit.js +25 -0
  69. package/dist/commands/ticket/epic.js +17 -43
  70. package/dist/commands/ticket/index.js +2 -2
  71. package/dist/commands/ticket/move.js +25 -2
  72. package/dist/commands/ticket/resolve.js +3 -4
  73. package/dist/commands/ticket/show.d.ts +13 -0
  74. package/dist/commands/ticket/show.js +16 -0
  75. package/dist/commands/ticket/template/list.js +2 -1
  76. package/dist/commands/ticket/view.d.ts +0 -1
  77. package/dist/commands/ticket/view.js +30 -1
  78. package/dist/commands/work/index.js +4 -0
  79. package/dist/commands/work/spawn-all.js +1 -1
  80. package/dist/commands/work/spawn.js +15 -4
  81. package/dist/commands/work/start.js +186 -103
  82. package/dist/commands/work/status.d.ts +14 -0
  83. package/dist/commands/work/status.js +60 -0
  84. package/dist/commands/work/watch.js +1 -1
  85. package/dist/commands/workflow/index.js +2 -1
  86. package/dist/commands/workflow/show.d.ts +13 -0
  87. package/dist/commands/workflow/show.js +16 -0
  88. package/dist/commands/workspace/add.js +15 -0
  89. package/dist/commands/workspace/list.js +2 -1
  90. package/dist/commands/workspace/prune.js +7 -7
  91. package/dist/hooks/init.js +10 -2
  92. package/dist/lib/agents/commands.d.ts +5 -0
  93. package/dist/lib/agents/commands.js +143 -97
  94. package/dist/lib/branch/index.d.ts +1 -0
  95. package/dist/lib/database/drizzle-schema.d.ts +465 -0
  96. package/dist/lib/database/drizzle-schema.js +53 -0
  97. package/dist/lib/database/index.d.ts +47 -1
  98. package/dist/lib/database/index.js +138 -20
  99. package/dist/lib/execution/config.d.ts +15 -1
  100. package/dist/lib/execution/config.js +28 -0
  101. package/dist/lib/execution/runners.d.ts +45 -0
  102. package/dist/lib/execution/runners.js +187 -26
  103. package/dist/lib/execution/session-utils.d.ts +16 -1
  104. package/dist/lib/execution/session-utils.js +71 -4
  105. package/dist/lib/execution/spawner.js +15 -2
  106. package/dist/lib/execution/storage.d.ts +6 -1
  107. package/dist/lib/execution/storage.js +35 -5
  108. package/dist/lib/execution/types.d.ts +3 -0
  109. package/dist/lib/mcp/tools/board.js +4 -6
  110. package/dist/lib/mcp/tools/cli-passthrough.js +25 -6
  111. package/dist/lib/mcp/tools/epic.js +8 -3
  112. package/dist/lib/mcp/tools/index.d.ts +1 -0
  113. package/dist/lib/mcp/tools/index.js +1 -0
  114. package/dist/lib/mcp/tools/spec.js +1 -1
  115. package/dist/lib/mcp/tools/ticket.js +11 -9
  116. package/dist/lib/mcp/tools/tmux.d.ts +16 -0
  117. package/dist/lib/mcp/tools/tmux.js +182 -0
  118. package/dist/lib/mcp/tools/work.js +148 -6
  119. package/dist/lib/mcp/types.d.ts +10 -0
  120. package/dist/lib/multiline-input.js +2 -1
  121. package/dist/lib/pmo/base-command.js +4 -4
  122. package/dist/lib/pmo/schema.d.ts +1 -1
  123. package/dist/lib/pmo/schema.js +1 -0
  124. package/dist/lib/pmo/storage/actions.js +1 -1
  125. package/dist/lib/pmo/storage/base.js +402 -50
  126. package/dist/lib/pmo/storage/dependencies.d.ts +1 -0
  127. package/dist/lib/pmo/storage/dependencies.js +11 -3
  128. package/dist/lib/pmo/storage/epics.js +1 -1
  129. package/dist/lib/pmo/storage/helpers.d.ts +4 -4
  130. package/dist/lib/pmo/storage/helpers.js +36 -26
  131. package/dist/lib/pmo/storage/projects.d.ts +2 -0
  132. package/dist/lib/pmo/storage/projects.js +207 -119
  133. package/dist/lib/pmo/storage/specs.d.ts +2 -0
  134. package/dist/lib/pmo/storage/specs.js +274 -188
  135. package/dist/lib/pmo/storage/tickets.d.ts +2 -0
  136. package/dist/lib/pmo/storage/tickets.js +350 -290
  137. package/dist/lib/pmo/storage/types.d.ts +1 -0
  138. package/dist/lib/pmo/storage/views.d.ts +2 -0
  139. package/dist/lib/pmo/storage/views.js +183 -130
  140. package/dist/lib/prompt-command.d.ts +20 -0
  141. package/dist/lib/prompt-command.js +38 -2
  142. package/dist/lib/prompt-json.d.ts +41 -4
  143. package/dist/lib/prompt-json.js +138 -7
  144. package/dist/lib/styles.d.ts +37 -0
  145. package/dist/lib/styles.js +73 -0
  146. package/oclif.manifest.json +4046 -3385
  147. package/package.json +11 -6
  148. 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 { openWorkspaceDatabase } from '../../lib/database/index.js';
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 db = openWorkspaceDatabase(hqPath);
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.get(exec.containerId) || [];
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.get(exec.containerId);
181
- exists = containerSessions?.includes(exec.sessionId) ?? false;
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.get(exec.containerId) || [];
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.get(exec.containerId);
211
- exists = containerSessions?.includes(exec.sessionId) ?? false;
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.get(exec.containerId) || [];
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.get(exec.containerId);
92
- exists = containerSessions?.includes(exec.sessionId) ?? false;
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
- // Only include if session exists, unless --all flag
109
- // Note: actualSessionId is guaranteed non-null here due to continue above
110
- if ((exists || flags.all) && actualSessionId) {
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
+ }