@proletariat/cli 0.3.68 → 0.3.70

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 (53) hide show
  1. package/dist/commands/session/health.d.ts +11 -0
  2. package/dist/commands/session/health.js +1 -1
  3. package/dist/commands/session/health.js.map +1 -1
  4. package/dist/lib/execution/runners/cloud.d.ts +16 -0
  5. package/dist/lib/execution/runners/cloud.js +88 -0
  6. package/dist/lib/execution/runners/cloud.js.map +1 -0
  7. package/dist/lib/execution/runners/devcontainer-terminal.d.ts +13 -0
  8. package/dist/lib/execution/runners/devcontainer-terminal.js +184 -0
  9. package/dist/lib/execution/runners/devcontainer-terminal.js.map +1 -0
  10. package/dist/lib/execution/runners/devcontainer-tmux.d.ts +16 -0
  11. package/dist/lib/execution/runners/devcontainer-tmux.js +270 -0
  12. package/dist/lib/execution/runners/devcontainer-tmux.js.map +1 -0
  13. package/dist/lib/execution/runners/devcontainer.d.ts +19 -0
  14. package/dist/lib/execution/runners/devcontainer.js +261 -0
  15. package/dist/lib/execution/runners/devcontainer.js.map +1 -0
  16. package/dist/lib/execution/runners/docker-credentials.d.ts +51 -0
  17. package/dist/lib/execution/runners/docker-credentials.js +175 -0
  18. package/dist/lib/execution/runners/docker-credentials.js.map +1 -0
  19. package/dist/lib/execution/runners/docker-management.d.ts +49 -0
  20. package/dist/lib/execution/runners/docker-management.js +300 -0
  21. package/dist/lib/execution/runners/docker-management.js.map +1 -0
  22. package/dist/lib/execution/runners/docker.d.ts +13 -0
  23. package/dist/lib/execution/runners/docker.js +75 -0
  24. package/dist/lib/execution/runners/docker.js.map +1 -0
  25. package/dist/lib/execution/runners/executor.d.ts +41 -0
  26. package/dist/lib/execution/runners/executor.js +108 -0
  27. package/dist/lib/execution/runners/executor.js.map +1 -0
  28. package/dist/lib/execution/runners/host.d.ts +14 -0
  29. package/dist/lib/execution/runners/host.js +437 -0
  30. package/dist/lib/execution/runners/host.js.map +1 -0
  31. package/dist/lib/execution/runners/index.d.ts +29 -0
  32. package/dist/lib/execution/runners/index.js +79 -0
  33. package/dist/lib/execution/runners/index.js.map +1 -0
  34. package/dist/lib/execution/runners/orchestrator.d.ts +30 -0
  35. package/dist/lib/execution/runners/orchestrator.js +332 -0
  36. package/dist/lib/execution/runners/orchestrator.js.map +1 -0
  37. package/dist/lib/execution/runners/prompt-builder.d.ts +12 -0
  38. package/dist/lib/execution/runners/prompt-builder.js +337 -0
  39. package/dist/lib/execution/runners/prompt-builder.js.map +1 -0
  40. package/dist/lib/execution/runners/sandbox.d.ts +34 -0
  41. package/dist/lib/execution/runners/sandbox.js +108 -0
  42. package/dist/lib/execution/runners/sandbox.js.map +1 -0
  43. package/dist/lib/execution/runners/shared.d.ts +62 -0
  44. package/dist/lib/execution/runners/shared.js +141 -0
  45. package/dist/lib/execution/runners/shared.js.map +1 -0
  46. package/dist/lib/execution/runners.d.ts +12 -272
  47. package/dist/lib/execution/runners.js +12 -3200
  48. package/dist/lib/execution/runners.js.map +1 -1
  49. package/dist/lib/external-issues/outbound-sync.d.ts +15 -0
  50. package/dist/lib/external-issues/outbound-sync.js +11 -1
  51. package/dist/lib/external-issues/outbound-sync.js.map +1 -1
  52. package/oclif.manifest.json +2334 -2334
  53. package/package.json +1 -1
@@ -0,0 +1,270 @@
1
+ /**
2
+ * Devcontainer Tmux Display Handler
3
+ *
4
+ * Runs devcontainer commands in tmux sessions inside Docker containers.
5
+ * Handles session creation, terminal tab opening, and attachment.
6
+ */
7
+ import { execSync, fs, path, os, getSetTitleCommands, } from './shared.js';
8
+ import { buildTmuxWindowName, buildWindowTitle, shouldUseControlMode, buildTmuxMouseOption, buildTmuxAttachCommand, configureITermTmuxWindowMode, } from './shared.js';
9
+ /**
10
+ * Run devcontainer command in tmux session INSIDE the container.
11
+ *
12
+ * Architecture: Container tmux only (simple, no nesting)
13
+ * 1. Start tmux session INSIDE the container (detached) - runs claude
14
+ * 2. Open terminal tab that attaches directly to the container's tmux
15
+ */
16
+ export async function runDevcontainerInTmux(context, devcontainerCmd, config, displayMode = 'terminal', containerId, promptContainerPath) {
17
+ const sessionName = buildTmuxWindowName(context);
18
+ const windowTitle = buildWindowTitle(context);
19
+ const terminalApp = config.terminal.app;
20
+ const useControlMode = shouldUseControlMode(terminalApp, config.tmux.controlMode);
21
+ try {
22
+ let actualContainerId = containerId;
23
+ if (!actualContainerId) {
24
+ const containerIdMatch = devcontainerCmd.match(/docker exec\s+(?:-it\s+)?(\S+)/);
25
+ if (containerIdMatch) {
26
+ actualContainerId = containerIdMatch[1];
27
+ }
28
+ }
29
+ if (!actualContainerId) {
30
+ return { success: false, error: 'Could not determine container ID for tmux session' };
31
+ }
32
+ // Check if tmux is available inside the container
33
+ try {
34
+ execSync(`docker exec ${actualContainerId} which tmux`, { stdio: 'pipe' });
35
+ }
36
+ catch {
37
+ return {
38
+ success: false,
39
+ error: `tmux is not installed in the devcontainer. Add 'tmux' to your devcontainer's Dockerfile or use the default prlt devcontainer template.`,
40
+ };
41
+ }
42
+ // Extract the claude command from the devcontainer command
43
+ const cmdMatch = devcontainerCmd.match(/bash -c '(.+)'$/);
44
+ const claudeCmd = cmdMatch ? cmdMatch[1] : devcontainerCmd;
45
+ const containerPostExec = context.isEphemeral
46
+ ? `echo ""\necho "✅ Ephemeral agent work complete. Session will auto-close in 5s..."\nsleep 5\nexit 0`
47
+ : `echo ""\necho "✅ Agent work complete. Press Enter to close or run more commands."\nexec bash`;
48
+ const promptWaitBlock = promptContainerPath
49
+ ? `# TKT-099: Wait for prompt file to sync from host into container
50
+ PROMPT_WAIT=0
51
+ while [ ! -s "${promptContainerPath}" ] && [ $PROMPT_WAIT -lt 30 ]; do
52
+ sleep 0.5
53
+ PROMPT_WAIT=$((PROMPT_WAIT + 1))
54
+ done
55
+ if [ ! -s "${promptContainerPath}" ]; then
56
+ echo "⚠️ Warning: Prompt file not available after 15s: ${promptContainerPath}"
57
+ fi
58
+ `
59
+ : '';
60
+ const tmuxScript = `#!/bin/bash
61
+ export TERM=xterm-256color
62
+ export COLORTERM=truecolor
63
+ unset CI
64
+ unset CLAUDECODE
65
+ echo "🚀 Starting: ${sessionName}"
66
+ echo ""
67
+ ${promptWaitBlock}${claudeCmd}
68
+ ${containerPostExec}
69
+ `;
70
+ const scriptPath = `/tmp/prlt-${sessionName}.sh`;
71
+ const mouseOption = buildTmuxMouseOption(useControlMode);
72
+ // Write script to container
73
+ try {
74
+ execSync(`docker exec -i ${actualContainerId} bash -c 'cat > ${scriptPath} && chmod +x ${scriptPath}'`, {
75
+ input: tmuxScript,
76
+ stdio: ['pipe', 'pipe', 'pipe'],
77
+ });
78
+ }
79
+ catch (error) {
80
+ return { success: false, error: `Failed to write script to container: ${error instanceof Error ? error.message : error}` };
81
+ }
82
+ // Kill existing session with same name if reusing container (TKT-1028)
83
+ try {
84
+ execSync(`docker exec ${actualContainerId} tmux has-session -t "${sessionName}" 2>&1`, { stdio: 'pipe' });
85
+ console.debug(`[runners:tmux] Killing existing tmux session "${sessionName}" in container`);
86
+ try {
87
+ execSync(`docker exec ${actualContainerId} tmux kill-session -t "${sessionName}"`, { stdio: 'pipe' });
88
+ }
89
+ catch { /* Ignore */ }
90
+ }
91
+ catch { /* Session doesn't exist */ }
92
+ // Create tmux session
93
+ const createSessionCmd = `tmux new-session -d -s "${sessionName}" -n "${sessionName}" "bash ${scriptPath}"${mouseOption} \\; set-option -g set-titles on \\; set-option -g set-titles-string "#{window_name}"`;
94
+ try {
95
+ execSync(`docker exec ${actualContainerId} bash -c '${createSessionCmd}'`, { stdio: 'pipe' });
96
+ }
97
+ catch (error) {
98
+ return { success: false, error: `Failed to create tmux session inside container: ${error instanceof Error ? error.message : error}` };
99
+ }
100
+ // Background mode: return after session creation
101
+ if (displayMode === 'background') {
102
+ await new Promise(resolve => setTimeout(resolve, 500));
103
+ try {
104
+ execSync(`docker exec ${actualContainerId} tmux has-session -t "${sessionName}" 2>&1`, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] });
105
+ }
106
+ catch {
107
+ return { success: false, error: `Failed to verify tmux session "${sessionName}" inside container.` };
108
+ }
109
+ return { success: true, containerId: actualContainerId, sessionId: sessionName };
110
+ }
111
+ // Foreground mode: attach in current terminal
112
+ if (displayMode === 'foreground') {
113
+ try {
114
+ const fgTmuxAttach = buildTmuxAttachCommand(false, true);
115
+ execSync(`clear && docker exec -it ${actualContainerId} ${fgTmuxAttach} -t "${sessionName}"`, { stdio: 'inherit' });
116
+ return { success: true, containerId: actualContainerId, sessionId: sessionName };
117
+ }
118
+ catch (error) {
119
+ return { success: false, error: `Failed to attach to container tmux session: ${error instanceof Error ? error.message : error}` };
120
+ }
121
+ }
122
+ // Terminal mode: open new tab
123
+ const tmuxAttach = buildTmuxAttachCommand(useControlMode, true);
124
+ const attachCmd = `docker exec -it ${actualContainerId} ${tmuxAttach} -t "${sessionName}"`;
125
+ // iTerm control mode: direct -CC attach
126
+ if (terminalApp === 'iTerm' && useControlMode) {
127
+ configureITermTmuxWindowMode(config.tmux.windowMode);
128
+ const openInBackground = config.terminal.openInBackground ?? true;
129
+ if (openInBackground) {
130
+ execSync(`osascript -e '
131
+ set frontApp to path to frontmost application as text
132
+ tell application "iTerm"
133
+ tell current window
134
+ set newTab to (create tab with default profile)
135
+ tell current session of newTab
136
+ write text "docker exec -it ${actualContainerId} tmux -u -CC attach -d -t \\"${sessionName}\\""
137
+ end tell
138
+ end tell
139
+ end tell
140
+ tell application frontApp to activate
141
+ '`);
142
+ }
143
+ else {
144
+ execSync(`osascript -e '
145
+ tell application "iTerm"
146
+ activate
147
+ tell current window
148
+ set newTab to (create tab with default profile)
149
+ tell current session of newTab
150
+ write text "docker exec -it ${actualContainerId} tmux -u -CC attach -d -t \\"${sessionName}\\""
151
+ end tell
152
+ end tell
153
+ end tell
154
+ '`);
155
+ }
156
+ return { success: true, containerId: actualContainerId, sessionId: sessionName };
157
+ }
158
+ // Other terminals: create script file and open tab
159
+ const baseDir = context.hqPath
160
+ ? path.join(context.hqPath, '.proletariat', 'scripts')
161
+ : path.join(os.homedir(), '.proletariat', 'scripts');
162
+ fs.mkdirSync(baseDir, { recursive: true });
163
+ const hostScriptPath = path.join(baseDir, `attach-${sessionName}-${Date.now()}.sh`);
164
+ const setTitleCmds = getSetTitleCommands(windowTitle);
165
+ const hostScript = `#!/bin/bash
166
+ ${setTitleCmds}
167
+ # Attach to container tmux session
168
+ ${attachCmd}
169
+ rm -f "${hostScriptPath}"
170
+ exec $SHELL
171
+ `;
172
+ fs.writeFileSync(hostScriptPath, hostScript, { mode: 0o755 });
173
+ const openInBackground = config.terminal.openInBackground ?? true;
174
+ switch (terminalApp) {
175
+ case 'iTerm':
176
+ if (openInBackground) {
177
+ execSync(`osascript -e '
178
+ tell application "System Events"
179
+ set frontApp to name of first application process whose frontmost is true
180
+ set frontAppBundle to bundle identifier of first application process whose frontmost is true
181
+ end tell
182
+ tell application "iTerm"
183
+ if (count of windows) = 0 then
184
+ create window with default profile
185
+ tell current session of current window
186
+ set name to "${windowTitle}"
187
+ write text "${hostScriptPath}"
188
+ end tell
189
+ else
190
+ tell current window
191
+ create tab with default profile
192
+ tell current session
193
+ set name to "${windowTitle}"
194
+ write text "${hostScriptPath}"
195
+ end tell
196
+ end tell
197
+ end if
198
+ end tell
199
+ delay 0.2
200
+ tell application "System Events"
201
+ set frontmost of process frontApp to true
202
+ end tell
203
+ delay 0.1
204
+ do shell script "open -b " & quoted form of frontAppBundle
205
+ '`);
206
+ }
207
+ else {
208
+ execSync(`osascript -e '
209
+ tell application "iTerm"
210
+ activate
211
+ if (count of windows) = 0 then
212
+ create window with default profile
213
+ tell current session of current window
214
+ set name to "${windowTitle}"
215
+ write text "${hostScriptPath}"
216
+ end tell
217
+ else
218
+ tell current window
219
+ create tab with default profile
220
+ tell current session
221
+ set name to "${windowTitle}"
222
+ write text "${hostScriptPath}"
223
+ end tell
224
+ end tell
225
+ end if
226
+ end tell
227
+ '`);
228
+ }
229
+ break;
230
+ case 'Ghostty':
231
+ execSync(`osascript -e '
232
+ tell application "Ghostty" to activate
233
+ tell application "System Events"
234
+ tell process "Ghostty"
235
+ keystroke "t" using command down
236
+ delay 0.3
237
+ keystroke "${hostScriptPath}"
238
+ keystroke return
239
+ end tell
240
+ end tell
241
+ '`);
242
+ break;
243
+ case 'Terminal':
244
+ default:
245
+ if (openInBackground) {
246
+ execSync(`osascript -e 'tell application "Terminal" to do script "${hostScriptPath}"'`);
247
+ }
248
+ else {
249
+ execSync(`osascript -e '
250
+ tell application "Terminal"
251
+ activate
252
+ tell application "System Events"
253
+ tell process "Terminal"
254
+ keystroke "t" using command down
255
+ end tell
256
+ end tell
257
+ delay 0.3
258
+ do script "${hostScriptPath}" in front window
259
+ end tell
260
+ '`);
261
+ }
262
+ break;
263
+ }
264
+ return { success: true, containerId: actualContainerId, sessionId: sessionName };
265
+ }
266
+ catch (error) {
267
+ return { success: false, error: error instanceof Error ? error.message : 'Failed to start tmux session in container' };
268
+ }
269
+ }
270
+ //# sourceMappingURL=devcontainer-tmux.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"devcontainer-tmux.js","sourceRoot":"","sources":["../../../../src/lib/execution/runners/devcontainer-tmux.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Devcontainer Runner (uses raw Docker)
3
+ *
4
+ * Runs commands inside Docker containers with filesystem isolation.
5
+ * Delegates display mode handling to devcontainer-terminal.ts and devcontainer-tmux.ts.
6
+ */
7
+ import { DisplayMode, OutputMode, PermissionMode, SessionManager, ExecutorType, ExecutionContext, ExecutionConfig } from './shared.js';
8
+ import { RunnerResult } from './shared.js';
9
+ /**
10
+ * Build the command to run Claude inside the container.
11
+ * Uses docker exec for direct container access.
12
+ * Uses a prompt file to avoid shell escaping issues.
13
+ */
14
+ export declare function buildDevcontainerCommand(context: ExecutionContext, executor: ExecutorType, promptFile: string, containerId?: string, outputMode?: OutputMode, permissionMode?: PermissionMode, displayMode?: DisplayMode, mcpConfigFile?: string): string;
15
+ /**
16
+ * Run command inside a Docker container.
17
+ * Uses raw Docker commands for filesystem isolation - no devcontainer CLI required.
18
+ */
19
+ export declare function runDevcontainer(context: ExecutionContext, executor: ExecutorType, config: ExecutionConfig, displayMode?: DisplayMode, sessionManager?: SessionManager): Promise<RunnerResult>;
@@ -0,0 +1,261 @@
1
+ /**
2
+ * Devcontainer Runner (uses raw Docker)
3
+ *
4
+ * Runs commands inside Docker containers with filesystem isolation.
5
+ * Delegates display mode handling to devcontainer-terminal.ts and devcontainer-tmux.ts.
6
+ */
7
+ import { spawn, execSync, fs, path, os, resolveCodexExecutionContext, validateCodexMode, getCodexCommand, resolveToolsForSpawn, } from './shared.js';
8
+ import { buildSessionName, buildPrompt, getExecutorCommand, isClaudeExecutor, checkDockerDaemon, ensureDockerContainer, copyClaudeCredentials, } from './shared.js';
9
+ import { runDevcontainerInTmux } from './devcontainer-tmux.js';
10
+ import { runDevcontainerInTerminal } from './devcontainer-terminal.js';
11
+ // =============================================================================
12
+ // Prompt File Management
13
+ // =============================================================================
14
+ /**
15
+ * Clean up old prompt files from the worktree.
16
+ * This is called before writing a new prompt file to prevent accumulation
17
+ * of stale prompt files from failed or interrupted executions.
18
+ */
19
+ function cleanupOldPromptFiles(worktreePath, ticketId) {
20
+ try {
21
+ const files = fs.readdirSync(worktreePath);
22
+ const pattern = ticketId
23
+ ? new RegExp(`^\\.prlt-prompt-${ticketId}-\\d+\\.txt$`)
24
+ : /^\.prlt-prompt-.*\.txt$/;
25
+ for (const file of files) {
26
+ if (pattern.test(file)) {
27
+ try {
28
+ fs.unlinkSync(path.join(worktreePath, file));
29
+ }
30
+ catch (err) {
31
+ console.debug(`[runners:cleanup] Failed to delete ${file}:`, err);
32
+ }
33
+ }
34
+ }
35
+ }
36
+ catch (err) {
37
+ console.debug(`[runners:cleanup] Failed to read directory ${worktreePath}:`, err);
38
+ }
39
+ }
40
+ /**
41
+ * Write prompt to a file inside the worktree so the container can access it.
42
+ * Returns the path to the prompt file (relative to worktree for container access).
43
+ * Cleans up old prompt files for the same ticket before writing.
44
+ */
45
+ function writePromptFile(context) {
46
+ // Clean up old prompt files for this ticket before creating a new one
47
+ cleanupOldPromptFiles(context.worktreePath, context.ticketId);
48
+ const prompt = buildPrompt(context);
49
+ const filename = `.prlt-prompt-${context.ticketId}-${Date.now()}.txt`;
50
+ const hostPath = path.join(context.worktreePath, filename);
51
+ fs.writeFileSync(hostPath, prompt, { mode: 0o644 });
52
+ // Container mounts agentDir at /workspace
53
+ // If worktreePath is a subdirectory of agentDir, we need the relative path
54
+ const relativePath = path.relative(context.agentDir, context.worktreePath);
55
+ const containerPath = relativePath
56
+ ? `/workspace/${relativePath}/${filename}`
57
+ : `/workspace/${filename}`;
58
+ return { hostPath, containerPath };
59
+ }
60
+ // =============================================================================
61
+ // Devcontainer Command Builder
62
+ // =============================================================================
63
+ /**
64
+ * Build the command to run Claude inside the container.
65
+ * Uses docker exec for direct container access.
66
+ * Uses a prompt file to avoid shell escaping issues.
67
+ */
68
+ export function buildDevcontainerCommand(context, executor, promptFile, containerId, outputMode = 'interactive', permissionMode = 'safe', displayMode = 'terminal', mcpConfigFile) {
69
+ // Calculate the relative path from agentDir to worktreePath for cd
70
+ const relativePath = path.relative(context.agentDir, context.worktreePath);
71
+ const cdCmd = relativePath ? `cd /workspace/${relativePath} && ` : '';
72
+ // Build executor command using the centralized getExecutorCommand()
73
+ let executorCmd;
74
+ const skipPermissions = permissionMode === 'danger';
75
+ if (isClaudeExecutor(executor)) {
76
+ const printFlag = outputMode === 'print' ? '-p ' : '';
77
+ const bypassTrustFlag = '--permission-mode bypassPermissions ';
78
+ const permissionsFlag = skipPermissions ? '--dangerously-skip-permissions ' : '';
79
+ const effortFlag = '--effort high ';
80
+ // TKT-053: Disable plan mode for background agents — prevents silent stalls
81
+ const disallowPlanFlag = displayMode === 'background' ? '--disallowedTools EnterPlanMode ' : '';
82
+ // Tool registry (TKT-083): pass MCP config to Claude Code via --mcp-config flag
83
+ const mcpConfigFlag = mcpConfigFile ? `--mcp-config ${mcpConfigFile} ` : '';
84
+ // PRLT-950: Use -- to separate flags from positional prompt argument.
85
+ executorCmd = `claude ${bypassTrustFlag}${permissionsFlag}${effortFlag}${printFlag}${disallowPlanFlag}${mcpConfigFlag}-- "$(cat ${promptFile})"`;
86
+ }
87
+ else if (executor === 'codex') {
88
+ const codexPermission = permissionMode;
89
+ const codexContext = resolveCodexExecutionContext(displayMode, outputMode);
90
+ const modeError = validateCodexMode(codexPermission, codexContext);
91
+ if (modeError) {
92
+ throw modeError;
93
+ }
94
+ const codexResult = getCodexCommand('PLACEHOLDER', codexPermission, codexContext);
95
+ const argsStr = codexResult.args.map(a => a === 'PLACEHOLDER' ? `"$(cat ${promptFile})"` : a).join(' ');
96
+ executorCmd = `${codexResult.cmd} ${argsStr}`;
97
+ }
98
+ else {
99
+ const { cmd, args } = getExecutorCommand(executor, `PLACEHOLDER`, skipPermissions);
100
+ const argsStr = args.map(a => a === 'PLACEHOLDER' ? `"$(cat ${promptFile})"` : a).join(' ');
101
+ executorCmd = `${cmd} ${argsStr}`;
102
+ }
103
+ const fullCmd = `${cdCmd}${executorCmd} && rm -f ${promptFile}`;
104
+ const ttyFlags = displayMode === 'background' ? '' : '-it ';
105
+ return `docker exec ${ttyFlags}${containerId} bash -c '${fullCmd}'`;
106
+ }
107
+ // =============================================================================
108
+ // Devcontainer Runner
109
+ // =============================================================================
110
+ /**
111
+ * Run command inside a Docker container.
112
+ * Uses raw Docker commands for filesystem isolation - no devcontainer CLI required.
113
+ */
114
+ export async function runDevcontainer(context, executor, config, displayMode = 'terminal', sessionManager = 'tmux') {
115
+ const devcontainerPath = path.join(context.agentDir, '.devcontainer');
116
+ const dockerfile = path.join(devcontainerPath, 'Dockerfile');
117
+ if (!fs.existsSync(dockerfile)) {
118
+ return {
119
+ success: false,
120
+ error: `No Dockerfile found at ${devcontainerPath}. Run 'prlt agent add' to set up the agent with Docker config.`,
121
+ };
122
+ }
123
+ try {
124
+ // Check if Docker is running (TKT-081: fast detection with diagnostic info)
125
+ const dockerStatus = checkDockerDaemon();
126
+ if (!dockerStatus.available) {
127
+ return {
128
+ success: false,
129
+ error: `Docker daemon is not available. ${dockerStatus.message}`,
130
+ };
131
+ }
132
+ // Ensure GitHub token is available for git push operations
133
+ if (!process.env.GITHUB_TOKEN && !process.env.GH_TOKEN) {
134
+ try {
135
+ const token = execSync('gh auth token', { encoding: 'utf-8', stdio: 'pipe' }).trim();
136
+ if (token) {
137
+ process.env.GITHUB_TOKEN = token;
138
+ process.env.GH_TOKEN = token;
139
+ }
140
+ }
141
+ catch (err) {
142
+ console.debug('[runners:docker] gh auth token failed:', err);
143
+ }
144
+ }
145
+ // Copy Claude credentials into agent directory so container can access them
146
+ if (isClaudeExecutor(executor)) {
147
+ copyClaudeCredentials(context.agentDir);
148
+ }
149
+ // Start or reuse container using raw Docker commands
150
+ const containerId = ensureDockerContainer(context, config, executor);
151
+ if (!containerId) {
152
+ return {
153
+ success: false,
154
+ error: 'Failed to start Docker container. Check Docker logs for details.',
155
+ };
156
+ }
157
+ // Write prompt to file in worktree (accessible by container)
158
+ const { hostPath: promptHostPath, containerPath: promptFile } = writePromptFile(context);
159
+ // Tool registry (TKT-083): generate MCP config file for container
160
+ let mcpConfigContainerPath;
161
+ if (context.hqPath && isClaudeExecutor(executor)) {
162
+ const toolsResult = resolveToolsForSpawn(context.hqPath, context.toolPolicy, context.worktreePath);
163
+ if (toolsResult.mcpConfigPath) {
164
+ const relativeMcp = path.relative(context.agentDir, toolsResult.mcpConfigPath);
165
+ mcpConfigContainerPath = `/workspace/${relativeMcp}`;
166
+ }
167
+ }
168
+ // Inject fresh GitHub token into container (containers may be reused with stale/empty tokens)
169
+ const githubToken = process.env.GITHUB_TOKEN || process.env.GH_TOKEN;
170
+ if (containerId && githubToken) {
171
+ try {
172
+ execSync(`docker exec ${containerId} bash -c 'echo "${githubToken}" > /home/node/.github-token && chmod 600 /home/node/.github-token && git config --global credential.helper "!f() { echo \\"username=x-access-token\\"; echo \\"password=\\$(cat /home/node/.github-token)\\"; }; f" && git config --global url."https://github.com/".insteadOf "git@github.com:"'`, {
173
+ stdio: 'pipe',
174
+ });
175
+ }
176
+ catch {
177
+ // Non-fatal - token injection failed but execution can continue
178
+ }
179
+ }
180
+ // Build the docker exec command
181
+ const devcontainerCmd = buildDevcontainerCommand(context, executor, promptFile, containerId, config.outputMode, config.permissionMode, displayMode, mcpConfigContainerPath);
182
+ // Execute based on display mode
183
+ let result;
184
+ if (sessionManager === 'tmux') {
185
+ result = await runDevcontainerInTmux(context, devcontainerCmd, config, displayMode, containerId || undefined, promptFile);
186
+ }
187
+ else {
188
+ switch (displayMode) {
189
+ case 'background':
190
+ result = await runDevcontainerInBackground(context, devcontainerCmd);
191
+ break;
192
+ case 'terminal':
193
+ default:
194
+ result = await runDevcontainerInTerminal(context, devcontainerCmd, config);
195
+ break;
196
+ }
197
+ }
198
+ // Clean up prompt file if execution failed to start
199
+ if (!result.success && fs.existsSync(promptHostPath)) {
200
+ try {
201
+ fs.unlinkSync(promptHostPath);
202
+ }
203
+ catch (err) {
204
+ console.debug('[runners:devcontainer] Failed to cleanup prompt file:', err);
205
+ }
206
+ }
207
+ // Override containerId with the real Docker container ID
208
+ if (result.success && containerId) {
209
+ result.containerId = containerId;
210
+ }
211
+ // Set sessionId when using tmux inside the container
212
+ if (result.success && sessionManager === 'tmux') {
213
+ const sessionId = buildSessionName(context);
214
+ result.sessionId = sessionId;
215
+ // For terminal display mode, verify the tmux session was actually created
216
+ if (displayMode === 'terminal' && containerId) {
217
+ await new Promise(resolve => setTimeout(resolve, 3000));
218
+ try {
219
+ execSync(`docker exec ${containerId} tmux has-session -t "${sessionId}" 2>&1`, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] });
220
+ }
221
+ catch (err) {
222
+ console.debug(`[runners:devcontainer] tmux session ${sessionId} not found in container:`, err);
223
+ result.success = false;
224
+ result.error = `Failed to create tmux session "${sessionId}" inside container. Check terminal for errors.`;
225
+ }
226
+ }
227
+ }
228
+ return result;
229
+ }
230
+ catch (error) {
231
+ cleanupOldPromptFiles(context.worktreePath, context.ticketId);
232
+ return {
233
+ success: false,
234
+ error: error instanceof Error ? error.message : 'Failed to run in devcontainer',
235
+ };
236
+ }
237
+ }
238
+ // =============================================================================
239
+ // Background Display Handler
240
+ // =============================================================================
241
+ /**
242
+ * Run devcontainer command in background, logging to file
243
+ */
244
+ async function runDevcontainerInBackground(context, devcontainerCmd) {
245
+ const logsDir = path.join(os.homedir(), '.proletariat', 'logs');
246
+ fs.mkdirSync(logsDir, { recursive: true });
247
+ const logPath = path.join(logsDir, `work-${context.ticketId}-${Date.now()}.log`);
248
+ const logStream = fs.openSync(logPath, 'w');
249
+ const child = spawn('sh', ['-c', devcontainerCmd], {
250
+ detached: true,
251
+ stdio: ['ignore', logStream, logStream],
252
+ });
253
+ child.unref();
254
+ return {
255
+ success: true,
256
+ pid: child.pid?.toString(),
257
+ containerId: `devcontainer-${context.agentName}`,
258
+ logPath,
259
+ };
260
+ }
261
+ //# sourceMappingURL=devcontainer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"devcontainer.js","sourceRoot":"","sources":["../../../../src/lib/execution/runners/devcontainer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Docker Credential Helpers
3
+ *
4
+ * Functions for checking and managing Claude Code credentials
5
+ * in Docker volumes, host filesystem, and macOS keychain.
6
+ * Also includes tmux server keychain access management.
7
+ */
8
+ export declare const CLAUDE_CREDENTIALS_VOLUME = "claude-credentials";
9
+ /**
10
+ * Check if the claude-credentials Docker volume exists.
11
+ */
12
+ export declare function credentialsVolumeExists(): boolean;
13
+ /**
14
+ * Check if valid Claude OAuth credentials exist in the Docker volume.
15
+ * Returns true if OAuth credentials are stored (even if access token is expired,
16
+ * since Claude Code handles refresh internally using stored refresh tokens).
17
+ *
18
+ * NOTE: This intentionally does NOT check for ANTHROPIC_API_KEY. If the user
19
+ * has an API key but no OAuth credentials, we want to prompt them to set up
20
+ * OAuth (which uses their Max subscription) rather than silently burning API credits.
21
+ */
22
+ export declare function dockerCredentialsExist(): boolean;
23
+ /**
24
+ * Get Docker credential info for display.
25
+ * Returns expiration date and subscription type if available.
26
+ */
27
+ export declare function getDockerCredentialInfo(): {
28
+ expiresAt: Date;
29
+ subscriptionType?: string;
30
+ } | null;
31
+ /**
32
+ * Check if Claude Code authentication is available on the host system.
33
+ * Returns true if any of:
34
+ * 1. ANTHROPIC_API_KEY environment variable is set
35
+ * 2. OAuth credentials exist in ~/.claude/.credentials.json (Claude Code 1.x)
36
+ * 3. OAuth credentials exist in macOS keychain (Claude Code 2.x)
37
+ */
38
+ export declare function hostCredentialsExist(): boolean;
39
+ /**
40
+ * Ensure tmux server has keychain access for Claude Code OAuth.
41
+ *
42
+ * On macOS, tmux sessions can lose access to the keychain if the tmux server
43
+ * was started in a context without keychain access. This function tests and
44
+ * restarts the tmux server if needed.
45
+ */
46
+ export declare function ensureTmuxServerHasKeychainAccess(): Promise<void>;
47
+ /**
48
+ * Copy Claude Code credentials (~/.claude.json) into the agent directory.
49
+ * This makes the subscription credentials available inside the devcontainer.
50
+ */
51
+ export declare function copyClaudeCredentials(agentDir: string): void;