@cluesmith/codev 2.0.0-rc.69 → 2.0.0-rc.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.
- package/dashboard/dist/assets/{index-CG7nUttd.js → index-CDAINZKT.js} +21 -21
- package/dashboard/dist/assets/{index-CG7nUttd.js.map → index-CDAINZKT.js.map} +1 -1
- package/dashboard/dist/index.html +1 -1
- package/dist/agent-farm/cli.js +2 -2
- package/dist/agent-farm/cli.js.map +1 -1
- package/dist/agent-farm/commands/architect.d.ts +3 -3
- package/dist/agent-farm/commands/architect.d.ts.map +1 -1
- package/dist/agent-farm/commands/architect.js +20 -142
- package/dist/agent-farm/commands/architect.js.map +1 -1
- package/dist/agent-farm/commands/attach.d.ts.map +1 -1
- package/dist/agent-farm/commands/attach.js +13 -50
- package/dist/agent-farm/commands/attach.js.map +1 -1
- package/dist/agent-farm/commands/cleanup.d.ts.map +1 -1
- package/dist/agent-farm/commands/cleanup.js +1 -11
- package/dist/agent-farm/commands/cleanup.js.map +1 -1
- package/dist/agent-farm/commands/send.d.ts +1 -1
- package/dist/agent-farm/commands/send.d.ts.map +1 -1
- package/dist/agent-farm/commands/send.js +35 -92
- package/dist/agent-farm/commands/send.js.map +1 -1
- package/dist/agent-farm/commands/spawn.d.ts.map +1 -1
- package/dist/agent-farm/commands/spawn.js +26 -58
- package/dist/agent-farm/commands/spawn.js.map +1 -1
- package/dist/agent-farm/commands/status.js +1 -1
- package/dist/agent-farm/commands/status.js.map +1 -1
- package/dist/agent-farm/commands/stop.d.ts.map +1 -1
- package/dist/agent-farm/commands/stop.js +9 -44
- package/dist/agent-farm/commands/stop.js.map +1 -1
- package/dist/agent-farm/commands/tower-cloud.d.ts.map +1 -1
- package/dist/agent-farm/commands/tower-cloud.js +18 -1
- package/dist/agent-farm/commands/tower-cloud.js.map +1 -1
- package/dist/agent-farm/db/index.d.ts.map +1 -1
- package/dist/agent-farm/db/index.js +61 -0
- package/dist/agent-farm/db/index.js.map +1 -1
- package/dist/agent-farm/db/migrate.d.ts.map +1 -1
- package/dist/agent-farm/db/migrate.js +6 -9
- package/dist/agent-farm/db/migrate.js.map +1 -1
- package/dist/agent-farm/db/schema.d.ts +2 -2
- package/dist/agent-farm/db/schema.d.ts.map +1 -1
- package/dist/agent-farm/db/schema.js +3 -4
- package/dist/agent-farm/db/schema.js.map +1 -1
- package/dist/agent-farm/db/types.d.ts +0 -3
- package/dist/agent-farm/db/types.d.ts.map +1 -1
- package/dist/agent-farm/db/types.js +0 -3
- package/dist/agent-farm/db/types.js.map +1 -1
- package/dist/agent-farm/lib/tower-client.d.ts +4 -0
- package/dist/agent-farm/lib/tower-client.d.ts.map +1 -1
- package/dist/agent-farm/lib/tower-client.js +10 -0
- package/dist/agent-farm/lib/tower-client.js.map +1 -1
- package/dist/agent-farm/lib/tunnel-client.d.ts.map +1 -1
- package/dist/agent-farm/lib/tunnel-client.js +6 -13
- package/dist/agent-farm/lib/tunnel-client.js.map +1 -1
- package/dist/agent-farm/servers/tower-server.js +482 -494
- package/dist/agent-farm/servers/tower-server.js.map +1 -1
- package/dist/agent-farm/state.d.ts.map +1 -1
- package/dist/agent-farm/state.js +6 -10
- package/dist/agent-farm/state.js.map +1 -1
- package/dist/agent-farm/types.d.ts +0 -7
- package/dist/agent-farm/types.d.ts.map +1 -1
- package/dist/agent-farm/utils/deps.d.ts.map +1 -1
- package/dist/agent-farm/utils/deps.js +0 -16
- package/dist/agent-farm/utils/deps.js.map +1 -1
- package/dist/agent-farm/utils/gate-watcher.js +4 -4
- package/dist/agent-farm/utils/gate-watcher.js.map +1 -1
- package/dist/agent-farm/utils/session.d.ts +6 -6
- package/dist/agent-farm/utils/session.d.ts.map +1 -1
- package/dist/agent-farm/utils/session.js +4 -4
- package/dist/agent-farm/utils/session.js.map +1 -1
- package/dist/agent-farm/utils/shell.d.ts +4 -4
- package/dist/agent-farm/utils/shell.js +4 -4
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +2 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/consult/index.d.ts +1 -0
- package/dist/commands/consult/index.d.ts.map +1 -1
- package/dist/commands/consult/index.js +19 -5
- package/dist/commands/consult/index.js.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +0 -12
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/porch/next.d.ts.map +1 -1
- package/dist/commands/porch/next.js +90 -8
- package/dist/commands/porch/next.js.map +1 -1
- package/dist/commands/porch/prompts.d.ts.map +1 -1
- package/dist/commands/porch/prompts.js +26 -4
- package/dist/commands/porch/prompts.js.map +1 -1
- package/dist/commands/porch/verdict.d.ts +0 -8
- package/dist/commands/porch/verdict.d.ts.map +1 -1
- package/dist/commands/porch/verdict.js +0 -13
- package/dist/commands/porch/verdict.js.map +1 -1
- package/dist/terminal/pty-manager.d.ts +9 -0
- package/dist/terminal/pty-manager.d.ts.map +1 -1
- package/dist/terminal/pty-manager.js +45 -2
- package/dist/terminal/pty-manager.js.map +1 -1
- package/dist/terminal/pty-session.d.ts +27 -4
- package/dist/terminal/pty-session.d.ts.map +1 -1
- package/dist/terminal/pty-session.js +112 -4
- package/dist/terminal/pty-session.js.map +1 -1
- package/dist/terminal/ring-buffer.d.ts +10 -3
- package/dist/terminal/ring-buffer.d.ts.map +1 -1
- package/dist/terminal/ring-buffer.js +25 -5
- package/dist/terminal/ring-buffer.js.map +1 -1
- package/dist/terminal/session-manager.d.ts +115 -0
- package/dist/terminal/session-manager.d.ts.map +1 -0
- package/dist/terminal/session-manager.js +582 -0
- package/dist/terminal/session-manager.js.map +1 -0
- package/dist/terminal/shepherd-client.d.ts +58 -0
- package/dist/terminal/shepherd-client.d.ts.map +1 -0
- package/dist/terminal/shepherd-client.js +212 -0
- package/dist/terminal/shepherd-client.js.map +1 -0
- package/dist/terminal/shepherd-main.d.ts +19 -0
- package/dist/terminal/shepherd-main.d.ts.map +1 -0
- package/dist/terminal/shepherd-main.js +153 -0
- package/dist/terminal/shepherd-main.js.map +1 -0
- package/dist/terminal/shepherd-process.d.ts +75 -0
- package/dist/terminal/shepherd-process.d.ts.map +1 -0
- package/dist/terminal/shepherd-process.js +279 -0
- package/dist/terminal/shepherd-process.js.map +1 -0
- package/dist/terminal/shepherd-protocol.d.ts +115 -0
- package/dist/terminal/shepherd-protocol.d.ts.map +1 -0
- package/dist/terminal/shepherd-protocol.js +214 -0
- package/dist/terminal/shepherd-protocol.js.map +1 -0
- package/dist/terminal/shepherd-replay-buffer.d.ts +38 -0
- package/dist/terminal/shepherd-replay-buffer.d.ts.map +1 -0
- package/dist/terminal/shepherd-replay-buffer.js +94 -0
- package/dist/terminal/shepherd-replay-buffer.js.map +1 -0
- package/package.json +1 -1
- package/skeleton/.claude/skills/codev/SKILL.md +1 -1
- package/skeleton/DEPENDENCIES.md +2 -34
- package/skeleton/consult-types/impl-review.md +9 -9
- package/skeleton/consult-types/integration-review.md +1 -1
- package/skeleton/consult-types/plan-review.md +1 -1
- package/skeleton/consult-types/pr-ready.md +1 -1
- package/skeleton/consult-types/spec-review.md +1 -1
- package/skeleton/protocols/bugfix/prompts/pr.md +23 -4
- package/skeleton/protocols/maintain/protocol.md +3 -3
- package/skeleton/resources/commands/agent-farm.md +2 -3
- package/skeleton/resources/commands/codev.md +0 -2
- package/skeleton/roles/architect.md +1 -1
- package/skeleton/roles/consultant.md +6 -6
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Send command - send instructions to running builders via
|
|
2
|
+
* Send command - send instructions to running builders via Tower terminal API
|
|
3
3
|
*/
|
|
4
|
-
import { readFileSync
|
|
4
|
+
import { readFileSync } from 'node:fs';
|
|
5
5
|
import { existsSync } from 'node:fs';
|
|
6
|
-
import {
|
|
7
|
-
import { join, basename, dirname } from 'node:path';
|
|
8
|
-
import { randomUUID } from 'node:crypto';
|
|
6
|
+
import { dirname, join } from 'node:path';
|
|
9
7
|
import { logger, fatal } from '../utils/logger.js';
|
|
10
|
-
import { run } from '../utils/shell.js';
|
|
11
8
|
import { loadState, getArchitect } from '../state.js';
|
|
9
|
+
import { TowerClient } from '../lib/tower-client.js';
|
|
12
10
|
const MAX_FILE_SIZE = 48 * 1024; // 48KB limit per spec
|
|
13
11
|
/**
|
|
14
12
|
* Format message from architect to builder
|
|
@@ -45,7 +43,7 @@ ${content}
|
|
|
45
43
|
###############################`;
|
|
46
44
|
}
|
|
47
45
|
/**
|
|
48
|
-
* Send a message to a specific builder
|
|
46
|
+
* Send a message to a specific builder via Tower API
|
|
49
47
|
*/
|
|
50
48
|
async function sendToBuilder(builderId, message, options) {
|
|
51
49
|
const state = loadState();
|
|
@@ -53,20 +51,17 @@ async function sendToBuilder(builderId, message, options) {
|
|
|
53
51
|
if (!builder) {
|
|
54
52
|
throw new Error(`Builder ${builderId} not found. Use 'af status' to see active builders.`);
|
|
55
53
|
}
|
|
56
|
-
if (!builder.
|
|
57
|
-
throw new Error(`Builder ${builderId} has no
|
|
54
|
+
if (!builder.terminalId) {
|
|
55
|
+
throw new Error(`Builder ${builderId} has no terminal session.`);
|
|
58
56
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
catch {
|
|
64
|
-
throw new Error(`tmux session "${builder.tmuxSession}" not found (builder may have exited). Use 'af status' to check.`);
|
|
57
|
+
const client = new TowerClient();
|
|
58
|
+
const towerRunning = await client.isRunning();
|
|
59
|
+
if (!towerRunning) {
|
|
60
|
+
throw new Error('Tower is not running. Start it with: af tower start');
|
|
65
61
|
}
|
|
66
62
|
// Optional: Send Ctrl+C first to interrupt any running process
|
|
67
63
|
if (options.interrupt) {
|
|
68
|
-
await
|
|
69
|
-
// Brief pause for prompt to appear
|
|
64
|
+
await client.writeTerminal(builder.terminalId, '\x03'); // Ctrl+C
|
|
70
65
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
71
66
|
}
|
|
72
67
|
// Load file content if specified
|
|
@@ -83,33 +78,13 @@ async function sendToBuilder(builderId, message, options) {
|
|
|
83
78
|
}
|
|
84
79
|
// Format the message
|
|
85
80
|
const formattedMessage = formatArchitectMessage(message, fileContent, options.raw);
|
|
86
|
-
//
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
const bufferName = `architect-${builderId}`;
|
|
92
|
-
await run(`tmux load-buffer -b "${bufferName}" "${tempFile}"`);
|
|
93
|
-
await run(`tmux paste-buffer -b "${bufferName}" -t "${builder.tmuxSession}"`);
|
|
94
|
-
// Clean up tmux buffer
|
|
95
|
-
await run(`tmux delete-buffer -b "${bufferName}"`).catch(() => {
|
|
96
|
-
// Ignore delete-buffer errors (buffer may not exist)
|
|
97
|
-
});
|
|
98
|
-
// Send Enter to submit (unless --no-enter)
|
|
99
|
-
if (!options.noEnter) {
|
|
100
|
-
await run(`tmux send-keys -t "${builder.tmuxSession}" Enter`);
|
|
101
|
-
}
|
|
102
|
-
logger.debug(`Sent to ${builderId}: ${message.substring(0, 50)}...`);
|
|
103
|
-
}
|
|
104
|
-
finally {
|
|
105
|
-
// Clean up temp file
|
|
106
|
-
try {
|
|
107
|
-
unlinkSync(tempFile);
|
|
108
|
-
}
|
|
109
|
-
catch {
|
|
110
|
-
// Ignore cleanup errors
|
|
111
|
-
}
|
|
81
|
+
// Send via Tower API
|
|
82
|
+
await client.writeTerminal(builder.terminalId, formattedMessage);
|
|
83
|
+
// Send Enter to submit (unless --no-enter)
|
|
84
|
+
if (!options.noEnter) {
|
|
85
|
+
await client.writeTerminal(builder.terminalId, '\r');
|
|
112
86
|
}
|
|
87
|
+
logger.debug(`Sent to ${builderId}: ${message.substring(0, 50)}...`);
|
|
113
88
|
}
|
|
114
89
|
/**
|
|
115
90
|
* Detect project root from CWD by walking up to find .git or af-config.json.
|
|
@@ -133,32 +108,12 @@ function detectProjectRoot() {
|
|
|
133
108
|
return null;
|
|
134
109
|
}
|
|
135
110
|
/**
|
|
136
|
-
* Find the architect
|
|
137
|
-
* Checks state.db first (legacy), then falls back to Tower naming convention.
|
|
111
|
+
* Find the architect terminal ID from state or Tower.
|
|
138
112
|
*/
|
|
139
|
-
|
|
140
|
-
// Try legacy state.db first
|
|
113
|
+
function findArchitectTerminalId() {
|
|
141
114
|
const architect = getArchitect();
|
|
142
|
-
if (architect?.
|
|
143
|
-
|
|
144
|
-
await run(`tmux has-session -t "${architect.tmuxSession}" 2>/dev/null`);
|
|
145
|
-
return architect.tmuxSession;
|
|
146
|
-
}
|
|
147
|
-
catch {
|
|
148
|
-
// Session recorded but no longer exists — fall through
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
// Fallback: Tower creates architect sessions as "architect-<project-basename>"
|
|
152
|
-
const projectRoot = detectProjectRoot();
|
|
153
|
-
if (projectRoot) {
|
|
154
|
-
const candidateSession = `architect-${basename(projectRoot)}`;
|
|
155
|
-
try {
|
|
156
|
-
await run(`tmux has-session -t "${candidateSession}" 2>/dev/null`);
|
|
157
|
-
return candidateSession;
|
|
158
|
-
}
|
|
159
|
-
catch {
|
|
160
|
-
// Session doesn't exist
|
|
161
|
-
}
|
|
115
|
+
if (architect?.terminalId) {
|
|
116
|
+
return architect.terminalId;
|
|
162
117
|
}
|
|
163
118
|
throw new Error('Architect not running. Use "af status" to check.');
|
|
164
119
|
}
|
|
@@ -166,10 +121,15 @@ async function findArchitectTmuxSession() {
|
|
|
166
121
|
* Send a message to the architect (from a builder)
|
|
167
122
|
*/
|
|
168
123
|
async function sendToArchitect(fromBuilderId, message, options) {
|
|
169
|
-
const
|
|
124
|
+
const terminalId = findArchitectTerminalId();
|
|
125
|
+
const client = new TowerClient();
|
|
126
|
+
const towerRunning = await client.isRunning();
|
|
127
|
+
if (!towerRunning) {
|
|
128
|
+
throw new Error('Tower is not running. Start it with: af tower start');
|
|
129
|
+
}
|
|
170
130
|
// Optional: Send Ctrl+C first to interrupt any running process
|
|
171
131
|
if (options.interrupt) {
|
|
172
|
-
await
|
|
132
|
+
await client.writeTerminal(terminalId, '\x03'); // Ctrl+C
|
|
173
133
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
174
134
|
}
|
|
175
135
|
// Load file content if specified
|
|
@@ -186,30 +146,13 @@ async function sendToArchitect(fromBuilderId, message, options) {
|
|
|
186
146
|
}
|
|
187
147
|
// Format the message (from builder)
|
|
188
148
|
const formattedMessage = formatBuilderMessage(fromBuilderId, message, fileContent, options.raw);
|
|
189
|
-
//
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
const bufferName = `builder-${fromBuilderId}`;
|
|
195
|
-
await run(`tmux load-buffer -b "${bufferName}" "${tempFile}"`);
|
|
196
|
-
await run(`tmux paste-buffer -b "${bufferName}" -t "${tmuxSession}"`);
|
|
197
|
-
// Clean up tmux buffer
|
|
198
|
-
await run(`tmux delete-buffer -b "${bufferName}"`).catch(() => { });
|
|
199
|
-
// Send Enter to submit (unless --no-enter)
|
|
200
|
-
if (!options.noEnter) {
|
|
201
|
-
await run(`tmux send-keys -t "${tmuxSession}" Enter`);
|
|
202
|
-
}
|
|
203
|
-
logger.debug(`Sent to architect from ${fromBuilderId}: ${message.substring(0, 50)}...`);
|
|
204
|
-
}
|
|
205
|
-
finally {
|
|
206
|
-
try {
|
|
207
|
-
unlinkSync(tempFile);
|
|
208
|
-
}
|
|
209
|
-
catch {
|
|
210
|
-
// Ignore cleanup errors
|
|
211
|
-
}
|
|
149
|
+
// Send via Tower API
|
|
150
|
+
await client.writeTerminal(terminalId, formattedMessage);
|
|
151
|
+
// Send Enter to submit (unless --no-enter)
|
|
152
|
+
if (!options.noEnter) {
|
|
153
|
+
await client.writeTerminal(terminalId, '\r');
|
|
212
154
|
}
|
|
155
|
+
logger.debug(`Sent to architect from ${fromBuilderId}: ${message.substring(0, 50)}...`);
|
|
213
156
|
}
|
|
214
157
|
/**
|
|
215
158
|
* Send a message to all builders
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"send.js","sourceRoot":"","sources":["../../../src/agent-farm/commands/send.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,
|
|
1
|
+
{"version":3,"file":"send.js","sourceRoot":"","sources":["../../../src/agent-farm/commands/send.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spawn.d.ts","sourceRoot":"","sources":["../../../src/agent-farm/commands/spawn.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAoD,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"spawn.d.ts","sourceRoot":"","sources":["../../../src/agent-farm/commands/spawn.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAoD,MAAM,aAAa,CAAC;AAozClG;;GAEG;AACH,wBAAsB,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAwDhE"}
|
|
@@ -15,7 +15,6 @@ import { logger, fatal } from '../utils/logger.js';
|
|
|
15
15
|
import { run, commandExists } from '../utils/shell.js';
|
|
16
16
|
import { upsertBuilder } from '../state.js';
|
|
17
17
|
import { loadRolePrompt } from '../utils/roles.js';
|
|
18
|
-
import { getBuilderSessionName } from '../utils/session.js';
|
|
19
18
|
// Tower port — the single HTTP server since Spec 0090
|
|
20
19
|
const DEFAULT_TOWER_PORT = 4100;
|
|
21
20
|
/**
|
|
@@ -144,13 +143,6 @@ If porch reports "not found", run \`porch init\` to re-initialize.
|
|
|
144
143
|
* Generate a short 4-character base64-encoded ID
|
|
145
144
|
* Uses URL-safe base64 (a-z, A-Z, 0-9, -, _) for filesystem-safe IDs
|
|
146
145
|
*/
|
|
147
|
-
/**
|
|
148
|
-
* Get the project name from config (basename of projectRoot)
|
|
149
|
-
* Used to namespace tmux sessions and prevent cross-project collisions
|
|
150
|
-
*/
|
|
151
|
-
function getProjectName(config) {
|
|
152
|
-
return basename(config.projectRoot);
|
|
153
|
-
}
|
|
154
146
|
function generateShortId() {
|
|
155
147
|
// Generate random 24-bit number and base64 encode to 4 chars
|
|
156
148
|
const num = Math.floor(Math.random() * 0xFFFFFF);
|
|
@@ -455,14 +447,11 @@ async function createWorktree(config, branchName, worktreePath) {
|
|
|
455
447
|
* The Tower server must be running (port 4100).
|
|
456
448
|
*/
|
|
457
449
|
async function createPtySession(config, command, args, cwd, registration) {
|
|
458
|
-
const body = { command, args, cwd, cols: 200, rows: 50 };
|
|
450
|
+
const body = { command, args, cwd, cols: 200, rows: 50, persistent: true };
|
|
459
451
|
if (registration) {
|
|
460
452
|
body.projectPath = registration.projectPath;
|
|
461
453
|
body.type = registration.type;
|
|
462
454
|
body.roleId = registration.roleId;
|
|
463
|
-
if (registration.tmuxSession) {
|
|
464
|
-
body.tmuxSession = registration.tmuxSession;
|
|
465
|
-
}
|
|
466
455
|
}
|
|
467
456
|
const response = await fetch(`http://localhost:${DEFAULT_TOWER_PORT}/api/terminals`, {
|
|
468
457
|
method: 'POST',
|
|
@@ -474,14 +463,13 @@ async function createPtySession(config, command, args, cwd, registration) {
|
|
|
474
463
|
throw new Error(`Failed to create PTY session: ${response.status} ${text}`);
|
|
475
464
|
}
|
|
476
465
|
const result = await response.json();
|
|
477
|
-
return { terminalId: result.id
|
|
466
|
+
return { terminalId: result.id };
|
|
478
467
|
}
|
|
479
468
|
/**
|
|
480
469
|
* Start a terminal session for a builder
|
|
481
470
|
*/
|
|
482
471
|
async function startBuilderSession(config, builderId, worktreePath, baseCmd, prompt, roleContent, roleSource) {
|
|
483
|
-
|
|
484
|
-
logger.info('Creating tmux session...');
|
|
472
|
+
logger.info('Creating terminal session...');
|
|
485
473
|
// Write initial prompt to a file for reference
|
|
486
474
|
const promptFile = resolve(worktreePath, '.builder-prompt.txt');
|
|
487
475
|
writeFileSync(promptFile, prompt);
|
|
@@ -518,24 +506,21 @@ done
|
|
|
518
506
|
}
|
|
519
507
|
writeFileSync(scriptPath, scriptContent);
|
|
520
508
|
chmodSync(scriptPath, '755');
|
|
521
|
-
// Create PTY session via REST API (
|
|
509
|
+
// Create PTY session via Tower REST API (shepherd for persistence)
|
|
522
510
|
logger.info('Creating PTY terminal session...');
|
|
523
|
-
const { terminalId
|
|
524
|
-
logger.info(`Terminal session created: ${terminalId}
|
|
525
|
-
|
|
526
|
-
return { sessionName: actualTmux || sessionName, terminalId };
|
|
511
|
+
const { terminalId } = await createPtySession(config, '/bin/bash', [scriptPath], worktreePath, { projectPath: config.projectRoot, type: 'builder', roleId: builderId });
|
|
512
|
+
logger.info(`Terminal session created: ${terminalId}`);
|
|
513
|
+
return { terminalId };
|
|
527
514
|
}
|
|
528
515
|
/**
|
|
529
516
|
* Start a shell session (no worktree, just node-pty)
|
|
530
517
|
*/
|
|
531
518
|
async function startShellSession(config, shellId, baseCmd) {
|
|
532
|
-
|
|
533
|
-
const sessionName = tmuxName;
|
|
534
|
-
// Create PTY session via REST API (node-pty backend, tmux for persistence)
|
|
519
|
+
// Create PTY session via REST API
|
|
535
520
|
logger.info('Creating PTY terminal session for shell...');
|
|
536
|
-
const { terminalId
|
|
537
|
-
logger.info(`Shell terminal session created: ${terminalId}
|
|
538
|
-
return {
|
|
521
|
+
const { terminalId } = await createPtySession(config, '/bin/bash', ['-c', baseCmd], config.projectRoot, { projectPath: config.projectRoot, type: 'shell', roleId: shellId });
|
|
522
|
+
logger.info(`Shell terminal session created: ${terminalId}`);
|
|
523
|
+
return { terminalId };
|
|
539
524
|
}
|
|
540
525
|
/**
|
|
541
526
|
* Pre-initialize porch in a worktree so the builder doesn't need to self-correct.
|
|
@@ -631,7 +616,7 @@ ${initialPrompt}`;
|
|
|
631
616
|
// Load role
|
|
632
617
|
const role = options.noRole ? null : loadRolePrompt(config, 'builder');
|
|
633
618
|
const commands = getResolvedCommands();
|
|
634
|
-
const {
|
|
619
|
+
const { terminalId } = await startBuilderSession(config, builderId, worktreePath, commands.builder, builderPrompt, role?.content ?? null, role?.source ?? null);
|
|
635
620
|
const builder = {
|
|
636
621
|
id: builderId,
|
|
637
622
|
name: specName,
|
|
@@ -639,7 +624,6 @@ ${initialPrompt}`;
|
|
|
639
624
|
phase: 'init',
|
|
640
625
|
worktree: worktreePath,
|
|
641
626
|
branch: branchName,
|
|
642
|
-
tmuxSession: sessionName,
|
|
643
627
|
type: 'spec',
|
|
644
628
|
terminalId,
|
|
645
629
|
};
|
|
@@ -647,12 +631,7 @@ ${initialPrompt}`;
|
|
|
647
631
|
logger.blank();
|
|
648
632
|
logger.success(`Builder ${builderId} spawned!`);
|
|
649
633
|
logger.kv('Mode', mode === 'strict' ? 'Strict (porch-driven)' : 'Soft (protocol-guided)');
|
|
650
|
-
|
|
651
|
-
logger.kv('Terminal', `ws://localhost:${DEFAULT_TOWER_PORT}/ws/terminal/${terminalId}`);
|
|
652
|
-
}
|
|
653
|
-
else {
|
|
654
|
-
logger.kv('Terminal', 'tmux session: ' + sessionName);
|
|
655
|
-
}
|
|
634
|
+
logger.kv('Terminal', `ws://localhost:${DEFAULT_TOWER_PORT}/ws/terminal/${terminalId}`);
|
|
656
635
|
}
|
|
657
636
|
/**
|
|
658
637
|
* Spawn builder for an ad-hoc task
|
|
@@ -718,7 +697,7 @@ ${taskDescription}`;
|
|
|
718
697
|
// Load role
|
|
719
698
|
const role = options.noRole ? null : loadRolePrompt(config, 'builder');
|
|
720
699
|
const commands = getResolvedCommands();
|
|
721
|
-
const {
|
|
700
|
+
const { terminalId } = await startBuilderSession(config, builderId, worktreePath, commands.builder, builderPrompt, role?.content ?? null, role?.source ?? null);
|
|
722
701
|
const builder = {
|
|
723
702
|
id: builderId,
|
|
724
703
|
name: `Task: ${taskText.substring(0, 30)}${taskText.length > 30 ? '...' : ''}`,
|
|
@@ -726,7 +705,6 @@ ${taskDescription}`;
|
|
|
726
705
|
phase: 'init',
|
|
727
706
|
worktree: worktreePath,
|
|
728
707
|
branch: branchName,
|
|
729
|
-
tmuxSession: sessionName,
|
|
730
708
|
type: 'task',
|
|
731
709
|
taskText,
|
|
732
710
|
terminalId,
|
|
@@ -734,7 +712,7 @@ ${taskDescription}`;
|
|
|
734
712
|
upsertBuilder(builder);
|
|
735
713
|
logger.blank();
|
|
736
714
|
logger.success(`Builder ${builderId} spawned!`);
|
|
737
|
-
logger.kv('Terminal',
|
|
715
|
+
logger.kv('Terminal', `ws://localhost:${DEFAULT_TOWER_PORT}/ws/terminal/${terminalId}`);
|
|
738
716
|
}
|
|
739
717
|
/**
|
|
740
718
|
* Spawn builder to run a protocol
|
|
@@ -783,7 +761,7 @@ async function spawnProtocol(options, config) {
|
|
|
783
761
|
// Load protocol-specific role or fall back to builder role
|
|
784
762
|
const role = options.noRole ? null : loadProtocolRole(config, protocolName);
|
|
785
763
|
const commands = getResolvedCommands();
|
|
786
|
-
const {
|
|
764
|
+
const { terminalId } = await startBuilderSession(config, builderId, worktreePath, commands.builder, prompt, role?.content ?? null, role?.source ?? null);
|
|
787
765
|
const builder = {
|
|
788
766
|
id: builderId,
|
|
789
767
|
name: `Protocol: ${protocolName}`,
|
|
@@ -791,7 +769,6 @@ async function spawnProtocol(options, config) {
|
|
|
791
769
|
phase: 'init',
|
|
792
770
|
worktree: worktreePath,
|
|
793
771
|
branch: branchName,
|
|
794
|
-
tmuxSession: sessionName,
|
|
795
772
|
type: 'protocol',
|
|
796
773
|
protocolName,
|
|
797
774
|
terminalId,
|
|
@@ -799,7 +776,7 @@ async function spawnProtocol(options, config) {
|
|
|
799
776
|
upsertBuilder(builder);
|
|
800
777
|
logger.blank();
|
|
801
778
|
logger.success(`Builder ${builderId} spawned!`);
|
|
802
|
-
logger.kv('Terminal',
|
|
779
|
+
logger.kv('Terminal', `ws://localhost:${DEFAULT_TOWER_PORT}/ws/terminal/${terminalId}`);
|
|
803
780
|
}
|
|
804
781
|
/**
|
|
805
782
|
* Spawn a bare shell session (no worktree, no prompt)
|
|
@@ -811,7 +788,7 @@ async function spawnShell(options, config) {
|
|
|
811
788
|
await ensureDirectories(config);
|
|
812
789
|
await checkDependencies();
|
|
813
790
|
const commands = getResolvedCommands();
|
|
814
|
-
const {
|
|
791
|
+
const { terminalId } = await startShellSession(config, shortId, commands.builder);
|
|
815
792
|
// Shell sessions are tracked as builders with type 'shell'
|
|
816
793
|
// They don't have worktrees or branches
|
|
817
794
|
const builder = {
|
|
@@ -821,14 +798,13 @@ async function spawnShell(options, config) {
|
|
|
821
798
|
phase: 'interactive',
|
|
822
799
|
worktree: '',
|
|
823
800
|
branch: '',
|
|
824
|
-
tmuxSession: sessionName,
|
|
825
801
|
type: 'shell',
|
|
826
802
|
terminalId,
|
|
827
803
|
};
|
|
828
804
|
upsertBuilder(builder);
|
|
829
805
|
logger.blank();
|
|
830
806
|
logger.success(`Shell ${shellId} spawned!`);
|
|
831
|
-
logger.kv('Terminal',
|
|
807
|
+
logger.kv('Terminal', `ws://localhost:${DEFAULT_TOWER_PORT}/ws/terminal/${terminalId}`);
|
|
832
808
|
}
|
|
833
809
|
/**
|
|
834
810
|
* Spawn a worktree session (has worktree/branch, but no initial prompt)
|
|
@@ -860,8 +836,7 @@ async function spawnWorktree(options, config) {
|
|
|
860
836
|
const role = options.noRole ? null : loadRolePrompt(config, 'builder');
|
|
861
837
|
const commands = getResolvedCommands();
|
|
862
838
|
// Worktree mode: launch Claude with no prompt, but in the worktree directory
|
|
863
|
-
|
|
864
|
-
logger.info('Creating tmux session...');
|
|
839
|
+
logger.info('Creating terminal session...');
|
|
865
840
|
// Build launch script (with role if provided) to avoid shell escaping issues
|
|
866
841
|
const scriptPath = resolve(worktreePath, '.builder-start.sh');
|
|
867
842
|
let scriptContent;
|
|
@@ -893,10 +868,10 @@ done
|
|
|
893
868
|
`;
|
|
894
869
|
}
|
|
895
870
|
writeFileSync(scriptPath, scriptContent, { mode: 0o755 });
|
|
896
|
-
// Create PTY session via REST API
|
|
871
|
+
// Create PTY session via REST API
|
|
897
872
|
logger.info('Creating PTY terminal session for worktree...');
|
|
898
|
-
const { terminalId: worktreeTerminalId
|
|
899
|
-
logger.info(`Worktree terminal session created: ${worktreeTerminalId}
|
|
873
|
+
const { terminalId: worktreeTerminalId } = await createPtySession(config, '/bin/bash', [scriptPath], worktreePath, { projectPath: config.projectRoot, type: 'builder', roleId: builderId });
|
|
874
|
+
logger.info(`Worktree terminal session created: ${worktreeTerminalId}`);
|
|
900
875
|
const builder = {
|
|
901
876
|
id: builderId,
|
|
902
877
|
name: 'Worktree session',
|
|
@@ -904,14 +879,13 @@ done
|
|
|
904
879
|
phase: 'interactive',
|
|
905
880
|
worktree: worktreePath,
|
|
906
881
|
branch: branchName,
|
|
907
|
-
tmuxSession: actualTmux || sessionName,
|
|
908
882
|
type: 'worktree',
|
|
909
883
|
terminalId: worktreeTerminalId,
|
|
910
884
|
};
|
|
911
885
|
upsertBuilder(builder);
|
|
912
886
|
logger.blank();
|
|
913
887
|
logger.success(`Worktree ${builderId} spawned!`);
|
|
914
|
-
logger.kv('Terminal', `
|
|
888
|
+
logger.kv('Terminal', `ws://localhost:${DEFAULT_TOWER_PORT}/ws/terminal/${worktreeTerminalId}`);
|
|
915
889
|
}
|
|
916
890
|
/**
|
|
917
891
|
* Generate a slug from an issue title (max 30 chars, lowercase, alphanumeric + hyphens)
|
|
@@ -1066,7 +1040,7 @@ async function spawnBugfix(options, config) {
|
|
|
1066
1040
|
// Load role
|
|
1067
1041
|
const role = options.noRole ? null : loadRolePrompt(config, 'builder');
|
|
1068
1042
|
const commands = getResolvedCommands();
|
|
1069
|
-
const {
|
|
1043
|
+
const { terminalId } = await startBuilderSession(config, builderId, worktreePath, commands.builder, builderPrompt, role?.content ?? null, role?.source ?? null);
|
|
1070
1044
|
const builder = {
|
|
1071
1045
|
id: builderId,
|
|
1072
1046
|
name: `Bugfix #${issueNumber}: ${issue.title.substring(0, 40)}${issue.title.length > 40 ? '...' : ''}`,
|
|
@@ -1074,7 +1048,6 @@ async function spawnBugfix(options, config) {
|
|
|
1074
1048
|
phase: 'init',
|
|
1075
1049
|
worktree: worktreePath,
|
|
1076
1050
|
branch: branchName,
|
|
1077
|
-
tmuxSession: sessionName,
|
|
1078
1051
|
type: 'bugfix',
|
|
1079
1052
|
issueNumber,
|
|
1080
1053
|
terminalId,
|
|
@@ -1083,12 +1056,7 @@ async function spawnBugfix(options, config) {
|
|
|
1083
1056
|
logger.blank();
|
|
1084
1057
|
logger.success(`Bugfix builder for issue #${issueNumber} spawned!`);
|
|
1085
1058
|
logger.kv('Mode', mode === 'strict' ? 'Strict (porch-driven)' : 'Soft (protocol-guided)');
|
|
1086
|
-
|
|
1087
|
-
logger.kv('Terminal', `ws://localhost:${DEFAULT_TOWER_PORT}/ws/terminal/${terminalId}`);
|
|
1088
|
-
}
|
|
1089
|
-
else {
|
|
1090
|
-
logger.kv('Terminal', `tmux: ${sessionName}`);
|
|
1091
|
-
}
|
|
1059
|
+
logger.kv('Terminal', `ws://localhost:${DEFAULT_TOWER_PORT}/ws/terminal/${terminalId}`);
|
|
1092
1060
|
}
|
|
1093
1061
|
// =============================================================================
|
|
1094
1062
|
// Main entry point
|