@openscout/scout 0.2.69 → 0.2.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/dist/client/assets/{addon-fit-DtSNdpy5.js → addon-fit-BNV7JPhj.js} +1 -1
- package/dist/client/assets/{addon-webgl-YYNKPQUg.js → addon-webgl-B-_Y5L3F.js} +1 -1
- package/dist/client/assets/index-BJri_z5a.css +1 -0
- package/dist/client/assets/index-Ccjo5BZz.js +199 -0
- package/dist/client/assets/{xterm-fBtFsYpq.js → xterm-Cx1oABPt.js} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/main.mjs +13252 -12118
- package/dist/openscout-terminal-relay.mjs +17 -94
- package/dist/pair-supervisor.mjs +600 -19
- package/dist/runtime/broker-daemon.mjs +1075 -153
- package/dist/scout-control-plane-web.mjs +988 -187
- package/dist/scout-web-server.mjs +988 -187
- package/package.json +1 -1
- package/dist/client/assets/index-5-XOQrKH.js +0 -186
- package/dist/client/assets/index-BnA2HAbt.css +0 -1
|
@@ -7,9 +7,9 @@ import { createRequire as createRequire2 } from "node:module";
|
|
|
7
7
|
|
|
8
8
|
// packages/web/server/terminal-relay-session.ts
|
|
9
9
|
import { createRequire } from "module";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
10
|
+
import { execSync } from "child_process";
|
|
11
|
+
import { existsSync, mkdirSync, writeFileSync } from "fs";
|
|
12
|
+
import { join, dirname as pathDirname } from "path";
|
|
13
13
|
var require2 = createRequire(import.meta.url);
|
|
14
14
|
var pty = require2("node-pty");
|
|
15
15
|
var DEFAULT_ORPHAN_TTL_MS = 30 * 60 * 1000;
|
|
@@ -56,9 +56,6 @@ function resizeSession(session, cols, rows) {
|
|
|
56
56
|
return false;
|
|
57
57
|
try {
|
|
58
58
|
session.pty.resize(cols, rows);
|
|
59
|
-
if (session.backend === "tmux" && session.tmuxSession) {
|
|
60
|
-
resizeTmuxWindow(session.tmuxSession, cols, rows);
|
|
61
|
-
}
|
|
62
59
|
session.cols = cols;
|
|
63
60
|
session.rows = rows;
|
|
64
61
|
return true;
|
|
@@ -93,78 +90,17 @@ function findBin(name, envOverride) {
|
|
|
93
90
|
return null;
|
|
94
91
|
}
|
|
95
92
|
}
|
|
96
|
-
function expandHomePath(value) {
|
|
97
|
-
const home = process.env.HOME || "/tmp";
|
|
98
|
-
if (value === "~")
|
|
99
|
-
return home;
|
|
100
|
-
if (value.startsWith("~/"))
|
|
101
|
-
return join(home, value.slice(2));
|
|
102
|
-
return value;
|
|
103
|
-
}
|
|
104
|
-
function isExecutablePath(candidate) {
|
|
105
|
-
if (!candidate)
|
|
106
|
-
return false;
|
|
107
|
-
try {
|
|
108
|
-
accessSync(candidate, constants.X_OK);
|
|
109
|
-
return true;
|
|
110
|
-
} catch {
|
|
111
|
-
return false;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
function findExecutableInDirectories(name, directories) {
|
|
115
|
-
const seen = new Set;
|
|
116
|
-
for (const directory of directories) {
|
|
117
|
-
if (!directory)
|
|
118
|
-
continue;
|
|
119
|
-
const normalizedDirectory = pathResolve(expandHomePath(directory));
|
|
120
|
-
if (seen.has(normalizedDirectory))
|
|
121
|
-
continue;
|
|
122
|
-
seen.add(normalizedDirectory);
|
|
123
|
-
const candidate = join(normalizedDirectory, name);
|
|
124
|
-
if (isExecutablePath(candidate))
|
|
125
|
-
return candidate;
|
|
126
|
-
}
|
|
127
|
-
return null;
|
|
128
|
-
}
|
|
129
|
-
function findExecutableOnPath(name) {
|
|
130
|
-
return findExecutableInDirectories(name, (process.env.PATH || "").split(pathDelimiter));
|
|
131
|
-
}
|
|
132
93
|
function findClaudeBin() {
|
|
133
|
-
|
|
134
|
-
const explicit = process.env[envKey]?.trim();
|
|
135
|
-
if (!explicit)
|
|
136
|
-
continue;
|
|
137
|
-
const expanded = expandHomePath(explicit);
|
|
138
|
-
if (isExecutablePath(expanded))
|
|
139
|
-
return pathResolve(expanded);
|
|
140
|
-
const foundOnPath = findExecutableOnPath(explicit);
|
|
141
|
-
if (foundOnPath)
|
|
142
|
-
return foundOnPath;
|
|
143
|
-
}
|
|
144
|
-
const home = process.env.HOME || "/tmp";
|
|
145
|
-
return findExecutableInDirectories("claude", [
|
|
146
|
-
join(home, ".local", "bin"),
|
|
147
|
-
join(home, ".claude", "local"),
|
|
148
|
-
"/opt/homebrew/bin",
|
|
149
|
-
"/usr/local/bin",
|
|
150
|
-
join(home, ".bun", "bin")
|
|
151
|
-
]) ?? findExecutableOnPath("claude");
|
|
94
|
+
return findBin("claude", "CLAUDE_BIN");
|
|
152
95
|
}
|
|
153
96
|
function findPiBin() {
|
|
154
97
|
return findBin("pi", "PI_BIN");
|
|
155
98
|
}
|
|
156
99
|
function findShellBin() {
|
|
157
|
-
const
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
"/bin/sh"
|
|
162
|
-
].filter((candidate) => Boolean(candidate));
|
|
163
|
-
for (const candidate of candidates) {
|
|
164
|
-
if (existsSync(candidate))
|
|
165
|
-
return candidate;
|
|
166
|
-
}
|
|
167
|
-
return null;
|
|
100
|
+
const configured = process.env.SHELL;
|
|
101
|
+
if (configured && existsSync(configured))
|
|
102
|
+
return configured;
|
|
103
|
+
return findBin("zsh") ?? findBin("bash") ?? findBin("sh") ?? (existsSync("/bin/sh") ? "/bin/sh" : null);
|
|
168
104
|
}
|
|
169
105
|
function normalizePiProviderForCli(provider) {
|
|
170
106
|
if (!provider)
|
|
@@ -181,22 +117,6 @@ function tmuxSessionExists(name) {
|
|
|
181
117
|
return false;
|
|
182
118
|
}
|
|
183
119
|
}
|
|
184
|
-
function resizeTmuxWindow(name, cols, rows) {
|
|
185
|
-
try {
|
|
186
|
-
execFileSync("tmux", [
|
|
187
|
-
"resize-window",
|
|
188
|
-
"-t",
|
|
189
|
-
name,
|
|
190
|
-
"-x",
|
|
191
|
-
String(cols),
|
|
192
|
-
"-y",
|
|
193
|
-
String(rows)
|
|
194
|
-
], { stdio: "ignore" });
|
|
195
|
-
return true;
|
|
196
|
-
} catch {
|
|
197
|
-
return false;
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
120
|
function bootstrapFiles(cwd, files, sessionId) {
|
|
201
121
|
for (const [relPath, content] of Object.entries(files)) {
|
|
202
122
|
const absPath = join(cwd, relPath);
|
|
@@ -213,14 +133,16 @@ function bootstrapFiles(cwd, files, sessionId) {
|
|
|
213
133
|
}
|
|
214
134
|
}
|
|
215
135
|
}
|
|
216
|
-
function spawnTmuxSession(tmuxName, cols, rows, cwd,
|
|
136
|
+
function spawnTmuxSession(tmuxName, cols, rows, cwd, commandBin, commandArgs, env) {
|
|
217
137
|
const exists = tmuxSessionExists(tmuxName);
|
|
218
138
|
if (!exists) {
|
|
219
|
-
const shellCmd = [
|
|
139
|
+
const shellCmd = [commandBin, ...commandArgs].map((a) => a.includes(" ") ? `'${a}'` : a).join(" ");
|
|
220
140
|
execSync(`tmux new-session -d -s ${tmuxName} -x ${cols} -y ${rows} -c '${cwd}' '${shellCmd}'`, { env });
|
|
221
141
|
console.log(`[relay] Created tmux session: ${tmuxName}`);
|
|
222
142
|
} else {
|
|
223
|
-
|
|
143
|
+
try {
|
|
144
|
+
execSync(`tmux resize-window -t ${tmuxName} -x ${cols} -y ${rows} 2>/dev/null`);
|
|
145
|
+
} catch {}
|
|
224
146
|
console.log(`[relay] Attaching to existing tmux session: ${tmuxName}`);
|
|
225
147
|
}
|
|
226
148
|
return pty.spawn("tmux", ["attach", "-t", tmuxName], {
|
|
@@ -242,7 +164,7 @@ function createSession(ws, msg) {
|
|
|
242
164
|
if (agent === "shell") {
|
|
243
165
|
agentBin = findShellBin();
|
|
244
166
|
if (!agentBin) {
|
|
245
|
-
const reason = "
|
|
167
|
+
const reason = "No login shell found. Set SHELL or install zsh, bash, or sh.";
|
|
246
168
|
console.error(`[relay] Session ${id} failed: ${reason}`);
|
|
247
169
|
send(ws, { type: "session:error", error: reason });
|
|
248
170
|
return null;
|
|
@@ -258,7 +180,7 @@ function createSession(ws, msg) {
|
|
|
258
180
|
} else {
|
|
259
181
|
agentBin = findClaudeBin();
|
|
260
182
|
if (!agentBin) {
|
|
261
|
-
const reason = "Claude CLI not found. Install it with:
|
|
183
|
+
const reason = "Claude CLI not found. Install it with: npm install -g @anthropic-ai/claude-code";
|
|
262
184
|
console.error(`[relay] Session ${id} failed: ${reason}`);
|
|
263
185
|
send(ws, { type: "session:error", error: reason });
|
|
264
186
|
return null;
|
|
@@ -282,7 +204,8 @@ function createSession(ws, msg) {
|
|
|
282
204
|
}
|
|
283
205
|
let agentArgs;
|
|
284
206
|
if (agent === "shell") {
|
|
285
|
-
|
|
207
|
+
const shellName = agentBin.split("/").pop() ?? "";
|
|
208
|
+
agentArgs = shellName === "sh" ? [] : ["-l"];
|
|
286
209
|
} else if (agent === "pi") {
|
|
287
210
|
agentArgs = ["--verbose"];
|
|
288
211
|
const provider = normalizePiProviderForCli(msg.provider);
|