@proletariat/cli 0.3.69 → 0.3.71
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/session/health.d.ts +11 -0
- package/dist/commands/session/health.js +1 -1
- package/dist/commands/session/health.js.map +1 -1
- package/dist/lib/execution/runners/cloud.d.ts +16 -0
- package/dist/lib/execution/runners/cloud.js +88 -0
- package/dist/lib/execution/runners/cloud.js.map +1 -0
- package/dist/lib/execution/runners/devcontainer-terminal.d.ts +13 -0
- package/dist/lib/execution/runners/devcontainer-terminal.js +184 -0
- package/dist/lib/execution/runners/devcontainer-terminal.js.map +1 -0
- package/dist/lib/execution/runners/devcontainer-tmux.d.ts +16 -0
- package/dist/lib/execution/runners/devcontainer-tmux.js +270 -0
- package/dist/lib/execution/runners/devcontainer-tmux.js.map +1 -0
- package/dist/lib/execution/runners/devcontainer.d.ts +19 -0
- package/dist/lib/execution/runners/devcontainer.js +261 -0
- package/dist/lib/execution/runners/devcontainer.js.map +1 -0
- package/dist/lib/execution/runners/docker-credentials.d.ts +51 -0
- package/dist/lib/execution/runners/docker-credentials.js +175 -0
- package/dist/lib/execution/runners/docker-credentials.js.map +1 -0
- package/dist/lib/execution/runners/docker-management.d.ts +49 -0
- package/dist/lib/execution/runners/docker-management.js +300 -0
- package/dist/lib/execution/runners/docker-management.js.map +1 -0
- package/dist/lib/execution/runners/docker.d.ts +13 -0
- package/dist/lib/execution/runners/docker.js +75 -0
- package/dist/lib/execution/runners/docker.js.map +1 -0
- package/dist/lib/execution/runners/executor.d.ts +41 -0
- package/dist/lib/execution/runners/executor.js +108 -0
- package/dist/lib/execution/runners/executor.js.map +1 -0
- package/dist/lib/execution/runners/host.d.ts +14 -0
- package/dist/lib/execution/runners/host.js +437 -0
- package/dist/lib/execution/runners/host.js.map +1 -0
- package/dist/lib/execution/runners/index.d.ts +29 -0
- package/dist/lib/execution/runners/index.js +79 -0
- package/dist/lib/execution/runners/index.js.map +1 -0
- package/dist/lib/execution/runners/orchestrator.d.ts +30 -0
- package/dist/lib/execution/runners/orchestrator.js +332 -0
- package/dist/lib/execution/runners/orchestrator.js.map +1 -0
- package/dist/lib/execution/runners/prompt-builder.d.ts +12 -0
- package/dist/lib/execution/runners/prompt-builder.js +337 -0
- package/dist/lib/execution/runners/prompt-builder.js.map +1 -0
- package/dist/lib/execution/runners/sandbox.d.ts +34 -0
- package/dist/lib/execution/runners/sandbox.js +108 -0
- package/dist/lib/execution/runners/sandbox.js.map +1 -0
- package/dist/lib/execution/runners/shared.d.ts +62 -0
- package/dist/lib/execution/runners/shared.js +141 -0
- package/dist/lib/execution/runners/shared.js.map +1 -0
- package/dist/lib/execution/runners.d.ts +12 -272
- package/dist/lib/execution/runners.js +12 -3200
- package/dist/lib/execution/runners.js.map +1 -1
- package/dist/lib/external-issues/outbound-sync.d.ts +15 -0
- package/dist/lib/external-issues/outbound-sync.js +11 -1
- package/dist/lib/external-issues/outbound-sync.js.map +1 -1
- package/dist/lib/telemetry/analytics.d.ts +2 -1
- package/dist/lib/telemetry/analytics.js +39 -9
- package/dist/lib/telemetry/analytics.js.map +1 -1
- package/oclif.manifest.json +3080 -3080
- 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;
|