ftown-bridge 0.3.15 → 0.4.0
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/bin/ftown-sessions +5 -0
- package/dist/agent-commands.d.ts +17 -0
- package/dist/agent-commands.js +41 -0
- package/dist/agent-commands.js.map +1 -0
- package/dist/claude-runner.d.ts +27 -0
- package/dist/claude-runner.js +234 -44
- package/dist/claude-runner.js.map +1 -1
- package/dist/create-ftown-session.d.ts +49 -0
- package/dist/create-ftown-session.js +147 -0
- package/dist/create-ftown-session.js.map +1 -0
- package/dist/cursor-hook-installer.js +2 -2
- package/dist/cursor-hook-installer.js.map +1 -1
- package/dist/ftown-sessions-cli.d.ts +2 -0
- package/dist/ftown-sessions-cli.js +304 -0
- package/dist/ftown-sessions-cli.js.map +1 -0
- package/dist/harness-cli.d.ts +2 -0
- package/dist/harness-cli.js +432 -0
- package/dist/harness-cli.js.map +1 -0
- package/dist/harness-format.d.ts +3 -0
- package/dist/harness-format.js +14 -0
- package/dist/harness-format.js.map +1 -0
- package/dist/harness-installer.d.ts +16 -0
- package/dist/harness-installer.js +108 -0
- package/dist/harness-installer.js.map +1 -0
- package/dist/hook-installer.js +2 -2
- package/dist/hook-installer.js.map +1 -1
- package/dist/index.js +265 -61
- package/dist/index.js.map +1 -1
- package/dist/install-ftown-cli.d.ts +3 -0
- package/dist/install-ftown-cli.js +20 -0
- package/dist/install-ftown-cli.js.map +1 -0
- package/dist/install-ftown-skill.d.ts +4 -0
- package/dist/install-ftown-skill.js +50 -0
- package/dist/install-ftown-skill.js.map +1 -0
- package/dist/install-notify-script.d.ts +6 -0
- package/dist/install-notify-script.js +23 -0
- package/dist/install-notify-script.js.map +1 -0
- package/dist/local-api-server.d.ts +5 -0
- package/dist/local-api-server.js +137 -6
- package/dist/local-api-server.js.map +1 -1
- package/dist/session-registry.d.ts +11 -1
- package/dist/session-registry.js +3 -3
- package/dist/session-registry.js.map +1 -1
- package/dist/terminal-manager.d.ts +3 -1
- package/dist/terminal-manager.js +13 -6
- package/dist/terminal-manager.js.map +1 -1
- package/dist/tmux.d.ts +24 -0
- package/dist/tmux.js +149 -0
- package/dist/tmux.js.map +1 -0
- package/dist/types.d.ts +4 -0
- package/hooks/notify.sh +34 -12
- package/package.json +9 -4
- package/skills/ftown-sessions/SKILL.md +136 -0
- package/skills/ftown-sessions/scripts/ftown-sessions +4 -0
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Local bridge harness — talks to ftown-bridge LocalApiServer via ~/.ftown/bridge.json
|
|
4
|
+
*/
|
|
5
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
6
|
+
import { homedir } from 'node:os';
|
|
7
|
+
import { join, resolve } from 'node:path';
|
|
8
|
+
import { Command } from 'commander';
|
|
9
|
+
import { cleanTerminalLine, formatLogLines, isDisplayableLine } from './harness-format.js';
|
|
10
|
+
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
11
|
+
const BRIDGE_JSON = join(homedir(), '.ftown', 'bridge.json');
|
|
12
|
+
const REGISTRY_JSON = join(homedir(), '.ftown', 'session-registry.json');
|
|
13
|
+
function loadPointer() {
|
|
14
|
+
if (!existsSync(BRIDGE_JSON)) {
|
|
15
|
+
const wrapper = join(homedir(), '.ftown', 'bin', 'ftown-harness');
|
|
16
|
+
throw new Error(`Bridge not running (no ${BRIDGE_JSON}). Start ftown-bridge from the UI CLI token, then use ${wrapper}`);
|
|
17
|
+
}
|
|
18
|
+
const parsed = JSON.parse(readFileSync(BRIDGE_JSON, 'utf8'));
|
|
19
|
+
if (!parsed.port || !parsed.token) {
|
|
20
|
+
throw new Error(`Invalid ${BRIDGE_JSON} — missing port or token`);
|
|
21
|
+
}
|
|
22
|
+
return parsed;
|
|
23
|
+
}
|
|
24
|
+
function loadRegistry() {
|
|
25
|
+
if (!existsSync(REGISTRY_JSON)) {
|
|
26
|
+
return { byWorkspace: {}, byConversation: {} };
|
|
27
|
+
}
|
|
28
|
+
const parsed = JSON.parse(readFileSync(REGISTRY_JSON, 'utf8'));
|
|
29
|
+
return {
|
|
30
|
+
byWorkspace: parsed.byWorkspace ?? {},
|
|
31
|
+
byConversation: parsed.byConversation ?? {},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function emit(json, data, text) {
|
|
35
|
+
if (json)
|
|
36
|
+
console.log(JSON.stringify(data, null, 2));
|
|
37
|
+
else
|
|
38
|
+
console.log(text);
|
|
39
|
+
}
|
|
40
|
+
async function api(pointer, method, path, body) {
|
|
41
|
+
const url = `http://127.0.0.1:${pointer.port}${path}`;
|
|
42
|
+
const res = await fetch(url, {
|
|
43
|
+
method,
|
|
44
|
+
headers: {
|
|
45
|
+
Authorization: `Bearer ${pointer.token}`,
|
|
46
|
+
...(body !== undefined ? { 'Content-Type': 'application/json' } : {}),
|
|
47
|
+
},
|
|
48
|
+
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
49
|
+
});
|
|
50
|
+
const data = (await res.json());
|
|
51
|
+
if (!res.ok) {
|
|
52
|
+
throw new Error(data.error ?? `HTTP ${res.status} ${path}`);
|
|
53
|
+
}
|
|
54
|
+
return data;
|
|
55
|
+
}
|
|
56
|
+
async function listSessions(pointer) {
|
|
57
|
+
const { sessions } = await api(pointer, 'GET', '/api/sessions');
|
|
58
|
+
return sessions;
|
|
59
|
+
}
|
|
60
|
+
async function getSession(pointer, id) {
|
|
61
|
+
const { session } = await api(pointer, 'GET', `/api/sessions/${id}`);
|
|
62
|
+
return session;
|
|
63
|
+
}
|
|
64
|
+
async function getLogLineCount(pointer, id) {
|
|
65
|
+
const meta = await api(pointer, 'GET', `/api/sessions/${id}/screen?limit=1`);
|
|
66
|
+
return meta.totalLines;
|
|
67
|
+
}
|
|
68
|
+
async function isAlive(pointer, id) {
|
|
69
|
+
const { running } = await api(pointer, 'GET', `/api/sessions/${id}/running`);
|
|
70
|
+
return running;
|
|
71
|
+
}
|
|
72
|
+
function resolveSessionId(sessions, query) {
|
|
73
|
+
if (UUID_RE.test(query) || query.length >= 8) {
|
|
74
|
+
const byPrefix = sessions.filter((s) => s.id === query || s.id.startsWith(query));
|
|
75
|
+
if (byPrefix.length === 1)
|
|
76
|
+
return byPrefix[0].id;
|
|
77
|
+
if (byPrefix.length > 1) {
|
|
78
|
+
throw new Error(`Ambiguous id prefix "${query}": ${byPrefix.map((s) => `${s.name} (${s.id.slice(0, 8)}…)`).join(', ')}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
const exact = sessions.filter((s) => s.name === query);
|
|
82
|
+
if (exact.length === 1)
|
|
83
|
+
return exact[0].id;
|
|
84
|
+
const fuzzy = sessions.filter((s) => s.name.toLowerCase().includes(query.toLowerCase()));
|
|
85
|
+
if (fuzzy.length === 1)
|
|
86
|
+
return fuzzy[0].id;
|
|
87
|
+
if (fuzzy.length > 1) {
|
|
88
|
+
throw new Error(`Ambiguous name "${query}": ${fuzzy.map((s) => s.name).join(', ')} — use full name or id prefix`);
|
|
89
|
+
}
|
|
90
|
+
throw new Error(`No session matching "${query}"`);
|
|
91
|
+
}
|
|
92
|
+
function resolveWorkspaceSessionId(cwd) {
|
|
93
|
+
const reg = loadRegistry();
|
|
94
|
+
let dir = resolve(cwd);
|
|
95
|
+
const root = resolve('/');
|
|
96
|
+
while (dir.startsWith(root)) {
|
|
97
|
+
const id = reg.byWorkspace[dir];
|
|
98
|
+
if (id)
|
|
99
|
+
return { id, workspace: dir };
|
|
100
|
+
const parent = resolve(dir, '..');
|
|
101
|
+
if (parent === dir)
|
|
102
|
+
break;
|
|
103
|
+
dir = parent;
|
|
104
|
+
}
|
|
105
|
+
return undefined;
|
|
106
|
+
}
|
|
107
|
+
function submitSuffix(shellType) {
|
|
108
|
+
switch (shellType) {
|
|
109
|
+
case 'claude':
|
|
110
|
+
case 'cursor':
|
|
111
|
+
return '\x1b\r';
|
|
112
|
+
default:
|
|
113
|
+
return '\r';
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
async function fetchTail(pointer, id, n) {
|
|
117
|
+
const totalLines = await getLogLineCount(pointer, id);
|
|
118
|
+
if (totalLines === 0)
|
|
119
|
+
return [];
|
|
120
|
+
const start = Math.max(0, totalLines - n);
|
|
121
|
+
const scr = await api(pointer, 'GET', `/api/sessions/${id}/screen?offset=${start}&limit=${n}`);
|
|
122
|
+
return formatLogLines(scr.lines);
|
|
123
|
+
}
|
|
124
|
+
async function printTail(pointer, id, n, opts) {
|
|
125
|
+
const lines = await fetchTail(pointer, id, n);
|
|
126
|
+
if (opts.json) {
|
|
127
|
+
emit(true, { sessionId: id, lines }, '');
|
|
128
|
+
return lines;
|
|
129
|
+
}
|
|
130
|
+
if (opts.header)
|
|
131
|
+
console.log(opts.header);
|
|
132
|
+
for (const line of lines)
|
|
133
|
+
console.log(line);
|
|
134
|
+
return lines;
|
|
135
|
+
}
|
|
136
|
+
async function cmdStatus(pointer, json) {
|
|
137
|
+
let alive = false;
|
|
138
|
+
try {
|
|
139
|
+
await api(pointer, 'GET', '/api/sessions');
|
|
140
|
+
alive = true;
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
alive = false;
|
|
144
|
+
}
|
|
145
|
+
const data = {
|
|
146
|
+
bridge: alive ? 'up' : 'down',
|
|
147
|
+
url: `http://127.0.0.1:${pointer.port}`,
|
|
148
|
+
auth: BRIDGE_JSON,
|
|
149
|
+
cli: pointer.harness ?? join(homedir(), '.ftown', 'bin', 'ftown-harness'),
|
|
150
|
+
pid: pointer.pid,
|
|
151
|
+
bridgeId: pointer.bridgeId,
|
|
152
|
+
since: pointer.startedAt,
|
|
153
|
+
};
|
|
154
|
+
if (json)
|
|
155
|
+
emit(true, data, '');
|
|
156
|
+
else {
|
|
157
|
+
console.log(`bridge: ${data.bridge}`);
|
|
158
|
+
console.log(`url: ${data.url}`);
|
|
159
|
+
console.log(`auth: ${data.auth}`);
|
|
160
|
+
console.log(`cli: ${data.cli}`);
|
|
161
|
+
if (data.pid)
|
|
162
|
+
console.log(`pid: ${data.pid}`);
|
|
163
|
+
if (data.bridgeId)
|
|
164
|
+
console.log(`id: ${data.bridgeId}`);
|
|
165
|
+
if (data.since)
|
|
166
|
+
console.log(`since: ${data.since}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
async function cmdLs(pointer, opts) {
|
|
170
|
+
const sessions = await listSessions(pointer);
|
|
171
|
+
if (sessions.length === 0) {
|
|
172
|
+
emit(opts.json, { sessions: [] }, '(no sessions)');
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
const cwd = resolve(process.cwd());
|
|
176
|
+
const hereResolved = resolveWorkspaceSessionId(cwd);
|
|
177
|
+
const hereId = hereResolved?.id;
|
|
178
|
+
const rows = [];
|
|
179
|
+
for (const s of sessions.sort((a, b) => (a.name ?? '').localeCompare(b.name ?? ''))) {
|
|
180
|
+
const logLines = await getLogLineCount(pointer, s.id);
|
|
181
|
+
const alive = s.status === 'running' ? await isAlive(pointer, s.id) : false;
|
|
182
|
+
const hasLog = logLines > 0;
|
|
183
|
+
const mark = s.id === hereId;
|
|
184
|
+
const row = {
|
|
185
|
+
mark,
|
|
186
|
+
name: s.name,
|
|
187
|
+
id: s.id,
|
|
188
|
+
status: s.status,
|
|
189
|
+
alive,
|
|
190
|
+
shellType: s.shellType,
|
|
191
|
+
workingDir: s.workingDir,
|
|
192
|
+
logLines,
|
|
193
|
+
hasLog,
|
|
194
|
+
};
|
|
195
|
+
rows.push(row);
|
|
196
|
+
if (!opts.json) {
|
|
197
|
+
const wd = s.workingDir ? `…${s.workingDir.slice(-30)}` : '';
|
|
198
|
+
const logLabel = hasLog ? `log=${logLines}` : 'no log';
|
|
199
|
+
const proc = alive ? 'alive' : 'dead ';
|
|
200
|
+
console.log(`${mark ? '*' : ' '} ${s.name.padEnd(14)} ${s.id.slice(0, 8)}… ${s.status.padEnd(9)} ${proc} ${logLabel.padEnd(12)} ${(s.shellType ?? '?').padEnd(7)} ${wd}`);
|
|
201
|
+
if (opts.tail > 0 && hasLog) {
|
|
202
|
+
const lines = await fetchTail(pointer, s.id, opts.tail);
|
|
203
|
+
for (const line of lines)
|
|
204
|
+
console.log(` ${line.slice(0, 120)}`);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
if (opts.json) {
|
|
209
|
+
emit(true, { sessions: rows, hereWorkspace: hereResolved?.workspace }, '');
|
|
210
|
+
}
|
|
211
|
+
else if (hereId) {
|
|
212
|
+
console.log('\n* = session for current working directory');
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
async function cmdHere(pointer, opts) {
|
|
216
|
+
const cwd = resolve(opts.cwd ?? process.cwd());
|
|
217
|
+
const resolved = resolveWorkspaceSessionId(cwd);
|
|
218
|
+
if (!resolved) {
|
|
219
|
+
emit(opts.json, { error: 'no_registry', cwd }, `No registry entry for workspace tree from: ${cwd}`);
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
const { id, workspace } = resolved;
|
|
223
|
+
const session = await getSession(pointer, id);
|
|
224
|
+
const alive = await isAlive(pointer, id);
|
|
225
|
+
const logLines = await getLogLineCount(pointer, id);
|
|
226
|
+
const meta = {
|
|
227
|
+
session,
|
|
228
|
+
registryWorkspace: workspace,
|
|
229
|
+
alive,
|
|
230
|
+
logLines,
|
|
231
|
+
hasLog: logLines > 0,
|
|
232
|
+
};
|
|
233
|
+
if (opts.json) {
|
|
234
|
+
const out = { ...meta };
|
|
235
|
+
if (opts.lines > 0 && logLines > 0) {
|
|
236
|
+
out.tail = await fetchTail(pointer, id, opts.lines);
|
|
237
|
+
}
|
|
238
|
+
emit(true, out, '');
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
console.log(`${session.name} (${id})`);
|
|
242
|
+
console.log(`registry=${workspace}`);
|
|
243
|
+
console.log(`status=${session.status} alive=${alive} shell=${session.shellType ?? '?'} log=${logLines}`);
|
|
244
|
+
if (session.workingDir)
|
|
245
|
+
console.log(`cwd=${session.workingDir}`);
|
|
246
|
+
if (opts.lines <= 0)
|
|
247
|
+
return;
|
|
248
|
+
if (logLines === 0) {
|
|
249
|
+
console.log('---');
|
|
250
|
+
console.log('(no terminal log yet)');
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
if (!alive) {
|
|
254
|
+
console.log(`---`);
|
|
255
|
+
console.log(`# process not running — showing last ${opts.lines} log lines (status=${session.status})`);
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
console.log('---');
|
|
259
|
+
}
|
|
260
|
+
await printTail(pointer, id, opts.lines, {});
|
|
261
|
+
}
|
|
262
|
+
async function cmdTail(pointer, query, opts) {
|
|
263
|
+
const sessions = await listSessions(pointer);
|
|
264
|
+
const id = resolveSessionId(sessions, query);
|
|
265
|
+
const session = await getSession(pointer, id);
|
|
266
|
+
const logLines = await getLogLineCount(pointer, id);
|
|
267
|
+
if (opts.json) {
|
|
268
|
+
emit(true, { session, logLines, lines: await fetchTail(pointer, id, opts.lines) }, '');
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
console.log(`# ${session.name} (${id}) log=${logLines}`);
|
|
272
|
+
await printTail(pointer, id, opts.lines, {});
|
|
273
|
+
}
|
|
274
|
+
function printGrepMatch(m, context) {
|
|
275
|
+
if (context > 0 && m.before?.length) {
|
|
276
|
+
const startLine = m.lineNumber - m.before.length;
|
|
277
|
+
for (let i = 0; i < m.before.length; i++) {
|
|
278
|
+
const t = cleanTerminalLine(m.before[i]);
|
|
279
|
+
if (isDisplayableLine(t))
|
|
280
|
+
console.log(` ${startLine + i}- ${t.slice(0, 200)}`);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
const hit = cleanTerminalLine(m.text);
|
|
284
|
+
if (isDisplayableLine(hit))
|
|
285
|
+
console.log(`${m.lineNumber}: ${hit.slice(0, 200)}`);
|
|
286
|
+
if (context > 0 && m.after?.length) {
|
|
287
|
+
for (let j = 0; j < m.after.length; j++) {
|
|
288
|
+
const t = cleanTerminalLine(m.after[j]);
|
|
289
|
+
if (isDisplayableLine(t))
|
|
290
|
+
console.log(` ${m.lineNumber + j + 1}- ${t.slice(0, 200)}`);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
async function cmdGrep(pointer, query, pattern, opts) {
|
|
295
|
+
const sessions = await listSessions(pointer);
|
|
296
|
+
const id = resolveSessionId(sessions, query);
|
|
297
|
+
const result = await api(pointer, 'POST', `/api/sessions/${id}/grep`, {
|
|
298
|
+
pattern,
|
|
299
|
+
offset: opts.offset,
|
|
300
|
+
limit: opts.limit,
|
|
301
|
+
...(opts.context > 0 ? { context: opts.context } : {}),
|
|
302
|
+
});
|
|
303
|
+
if (opts.json) {
|
|
304
|
+
const cleaned = result.matches.map((m) => ({
|
|
305
|
+
lineNumber: m.lineNumber,
|
|
306
|
+
text: cleanTerminalLine(m.text),
|
|
307
|
+
before: m.before?.map(cleanTerminalLine).filter(isDisplayableLine),
|
|
308
|
+
after: m.after?.map(cleanTerminalLine).filter(isDisplayableLine),
|
|
309
|
+
}));
|
|
310
|
+
emit(true, { totalMatches: result.totalMatches, matches: cleaned }, '');
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
console.log(`# matches ${result.totalMatches} (showing ${result.matches.length})`);
|
|
314
|
+
for (const m of result.matches) {
|
|
315
|
+
if (opts.context > 0)
|
|
316
|
+
printGrepMatch(m, opts.context);
|
|
317
|
+
else {
|
|
318
|
+
const hit = cleanTerminalLine(m.text);
|
|
319
|
+
if (isDisplayableLine(hit))
|
|
320
|
+
console.log(`${m.lineNumber}: ${hit.slice(0, 200)}`);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
async function cmdSend(pointer, query, text, opts) {
|
|
325
|
+
const sessions = await listSessions(pointer);
|
|
326
|
+
const id = resolveSessionId(sessions, query);
|
|
327
|
+
const session = await getSession(pointer, id);
|
|
328
|
+
let keys = text;
|
|
329
|
+
if (opts.submit)
|
|
330
|
+
keys += submitSuffix(session.shellType);
|
|
331
|
+
const plan = {
|
|
332
|
+
sessionId: id,
|
|
333
|
+
name: session.name,
|
|
334
|
+
shellType: session.shellType,
|
|
335
|
+
submit: opts.submit,
|
|
336
|
+
bytes: keys.length,
|
|
337
|
+
dryRun: opts.dryRun,
|
|
338
|
+
};
|
|
339
|
+
if (opts.dryRun) {
|
|
340
|
+
emit(opts.json, plan, `dry-run: would send ${keys.length} bytes to ${session.name} (submit=${opts.submit})`);
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
await api(pointer, 'POST', `/api/sessions/${id}/keys`, { keys });
|
|
344
|
+
emit(opts.json, { ...plan, sent: true }, `sent ${keys.length} bytes to ${session.name} (submit=${opts.submit})`);
|
|
345
|
+
}
|
|
346
|
+
const program = new Command();
|
|
347
|
+
program
|
|
348
|
+
.name('ftown-harness')
|
|
349
|
+
.description('CLI for ftown bridge local API (~/.ftown/bridge.json)')
|
|
350
|
+
.option('--json', 'Machine-readable JSON output');
|
|
351
|
+
program
|
|
352
|
+
.command('status')
|
|
353
|
+
.description('Bridge pointer and health')
|
|
354
|
+
.action(async (_opts, cmd) => {
|
|
355
|
+
const pointer = loadPointer();
|
|
356
|
+
await cmdStatus(pointer, !!cmd.parent?.opts().json);
|
|
357
|
+
});
|
|
358
|
+
program
|
|
359
|
+
.command('ls')
|
|
360
|
+
.description('List sessions (* = cwd workspace)')
|
|
361
|
+
.option('-n, --tail <n>', 'Preview last N log lines per session (incl. dead)', '0')
|
|
362
|
+
.action(async (opts, cmd) => {
|
|
363
|
+
const pointer = loadPointer();
|
|
364
|
+
await cmdLs(pointer, {
|
|
365
|
+
tail: parseInt(opts.tail, 10) || 0,
|
|
366
|
+
json: !!cmd.parent?.opts().json,
|
|
367
|
+
});
|
|
368
|
+
});
|
|
369
|
+
program
|
|
370
|
+
.command('here')
|
|
371
|
+
.description('Session for current workspace (from registry)')
|
|
372
|
+
.option('-n, --lines <n>', 'Tail lines (works for dead sessions with logs)', '15')
|
|
373
|
+
.option('--cwd <path>', 'Workspace path (default: process.cwd())')
|
|
374
|
+
.action(async (opts, cmd) => {
|
|
375
|
+
const pointer = loadPointer();
|
|
376
|
+
await cmdHere(pointer, {
|
|
377
|
+
lines: parseInt(opts.lines, 10) || 15,
|
|
378
|
+
cwd: opts.cwd,
|
|
379
|
+
json: !!cmd.parent?.opts().json,
|
|
380
|
+
});
|
|
381
|
+
});
|
|
382
|
+
program
|
|
383
|
+
.command('tail <session>')
|
|
384
|
+
.description('Last N lines of terminal (ANSI/OSC stripped)')
|
|
385
|
+
.option('-n, --lines <n>', 'Line count', '40')
|
|
386
|
+
.action(async (session, opts, cmd) => {
|
|
387
|
+
const pointer = loadPointer();
|
|
388
|
+
await cmdTail(pointer, session, {
|
|
389
|
+
lines: parseInt(opts.lines, 10) || 40,
|
|
390
|
+
json: !!cmd.parent?.opts().json,
|
|
391
|
+
});
|
|
392
|
+
});
|
|
393
|
+
program
|
|
394
|
+
.command('grep <session> <pattern>')
|
|
395
|
+
.description('Search terminal log (regex)')
|
|
396
|
+
.option('-n, --limit <n>', 'Max matches', '30')
|
|
397
|
+
.option('--offset <n>', 'Match offset', '0')
|
|
398
|
+
.option('-C, --context <n>', 'Lines of context before/after each match', '0')
|
|
399
|
+
.action(async (session, pattern, opts, cmd) => {
|
|
400
|
+
const pointer = loadPointer();
|
|
401
|
+
await cmdGrep(pointer, session, pattern, {
|
|
402
|
+
limit: parseInt(opts.limit, 10) || 30,
|
|
403
|
+
offset: parseInt(opts.offset, 10) || 0,
|
|
404
|
+
context: parseInt(opts.context, 10) || 0,
|
|
405
|
+
json: !!cmd.parent?.opts().json,
|
|
406
|
+
});
|
|
407
|
+
});
|
|
408
|
+
program
|
|
409
|
+
.command('send <session> <text...>')
|
|
410
|
+
.description('Send keystrokes (--submit adds Enter for shell type)')
|
|
411
|
+
.option('-s, --submit', 'Append submit sequence after text')
|
|
412
|
+
.option('-l, --literal', 'Do not interpret escape sequences in text')
|
|
413
|
+
.option('--dry-run', 'Print what would be sent without writing to PTY')
|
|
414
|
+
.action(async (session, textParts, opts, cmd) => {
|
|
415
|
+
const pointer = loadPointer();
|
|
416
|
+
let text = textParts.join(' ');
|
|
417
|
+
if (!opts.literal) {
|
|
418
|
+
text = text.replace(/\\r/g, '\r').replace(/\\n/g, '\n').replace(/\\t/g, '\t').replace(/\\x1b/g, '\x1b');
|
|
419
|
+
}
|
|
420
|
+
await cmdSend(pointer, session, text, {
|
|
421
|
+
submit: !!opts.submit,
|
|
422
|
+
literal: !!opts.literal,
|
|
423
|
+
dryRun: !!opts.dryRun,
|
|
424
|
+
json: !!cmd.parent?.opts().json,
|
|
425
|
+
});
|
|
426
|
+
});
|
|
427
|
+
program.parseAsync(process.argv).catch((err) => {
|
|
428
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
429
|
+
console.error(`ftown-harness: ${msg}`);
|
|
430
|
+
process.exit(1);
|
|
431
|
+
});
|
|
432
|
+
//# sourceMappingURL=harness-cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"harness-cli.js","sourceRoot":"","sources":["../src/harness-cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** Strip ANSI CSI/SGR and OSC sequences; drop non-printable controls. */
|
|
2
|
+
const ANSI_RE = /\x1b\[[0-9;?]*[a-zA-Z]/g;
|
|
3
|
+
const OSC_RE = /\x1b\][^\x07]*(?:\x07|\x1b\\)/g;
|
|
4
|
+
const CONTROL_RE = /[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g;
|
|
5
|
+
export function cleanTerminalLine(text) {
|
|
6
|
+
return text.replace(OSC_RE, '').replace(ANSI_RE, '').replace(CONTROL_RE, '').trimEnd();
|
|
7
|
+
}
|
|
8
|
+
export function isDisplayableLine(text) {
|
|
9
|
+
return cleanTerminalLine(text).trim().length > 0;
|
|
10
|
+
}
|
|
11
|
+
export function formatLogLines(rawLines) {
|
|
12
|
+
return rawLines.map(cleanTerminalLine).filter(isDisplayableLine);
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=harness-format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"harness-format.js","sourceRoot":"","sources":["../src/harness-format.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,MAAM,OAAO,GAAG,yBAAyB,CAAC;AAC1C,MAAM,MAAM,GAAG,gCAAgC,CAAC;AAChD,MAAM,UAAU,GAAG,mCAAmC,CAAC;AAEvD,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;AACzF,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,OAAO,iBAAiB,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,QAAkB;IAC/C,OAAO,QAAQ,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC;AACnE,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface HarnessInstallResult {
|
|
2
|
+
wrapperPath: string;
|
|
3
|
+
cliPath: string;
|
|
4
|
+
binDir: string;
|
|
5
|
+
}
|
|
6
|
+
/** Deploy ftown-harness wrapper under ~/.ftown/bin (idempotent). */
|
|
7
|
+
export declare function installHarness(harnessCliPath: string): HarnessInstallResult;
|
|
8
|
+
export declare function harnessOnPath(): boolean;
|
|
9
|
+
export declare function pathHint(): string;
|
|
10
|
+
/** Agent-facing cheat sheet — rewritten on every bridge start. */
|
|
11
|
+
export declare function writeHarnessAgentGuide(opts: {
|
|
12
|
+
wrapperPath: string;
|
|
13
|
+
port: number;
|
|
14
|
+
bridgeId?: string;
|
|
15
|
+
}): void;
|
|
16
|
+
export declare function agentGuidePath(): string;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
const FTOWN_DIR = join(homedir(), '.ftown');
|
|
5
|
+
const BIN_DIR = join(FTOWN_DIR, 'bin');
|
|
6
|
+
const HARNESS_WRAPPER = join(BIN_DIR, 'ftown-harness');
|
|
7
|
+
const HARNESS_CLI_PATH_FILE = join(FTOWN_DIR, 'harness-cli.path');
|
|
8
|
+
const WRAPPER_SCRIPT = `#!/usr/bin/env bash
|
|
9
|
+
# Auto-deployed by ftown-bridge — do not edit
|
|
10
|
+
set -euo pipefail
|
|
11
|
+
CLI_PATH_FILE="${HARNESS_CLI_PATH_FILE.replace(/\\/g, '\\\\')}"
|
|
12
|
+
if [[ ! -f "$CLI_PATH_FILE" ]]; then
|
|
13
|
+
echo "ftown-harness: bridge not running (missing $CLI_PATH_FILE)" >&2
|
|
14
|
+
exit 1
|
|
15
|
+
fi
|
|
16
|
+
CLI="$(cat "$CLI_PATH_FILE")"
|
|
17
|
+
if [[ ! -f "$CLI" ]]; then
|
|
18
|
+
echo "ftown-harness: harness CLI missing at $CLI — restart ftown-bridge" >&2
|
|
19
|
+
exit 1
|
|
20
|
+
fi
|
|
21
|
+
exec node "$CLI" "$@"
|
|
22
|
+
`;
|
|
23
|
+
/** Deploy ftown-harness wrapper under ~/.ftown/bin (idempotent). */
|
|
24
|
+
export function installHarness(harnessCliPath) {
|
|
25
|
+
const cliPath = harnessCliPath;
|
|
26
|
+
mkdirSync(BIN_DIR, { recursive: true, mode: 0o700 });
|
|
27
|
+
writeFileSync(HARNESS_CLI_PATH_FILE, cliPath + '\n', { mode: 0o600 });
|
|
28
|
+
writeFileSync(HARNESS_WRAPPER, WRAPPER_SCRIPT, { mode: 0o755 });
|
|
29
|
+
return {
|
|
30
|
+
wrapperPath: HARNESS_WRAPPER,
|
|
31
|
+
cliPath,
|
|
32
|
+
binDir: BIN_DIR,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export function harnessOnPath() {
|
|
36
|
+
const pathEnv = process.env.PATH ?? '';
|
|
37
|
+
return pathEnv.split(':').some((p) => p === BIN_DIR || p === join(FTOWN_DIR, 'bin'));
|
|
38
|
+
}
|
|
39
|
+
export function pathHint() {
|
|
40
|
+
return existsSync(HARNESS_WRAPPER)
|
|
41
|
+
? `Add to PATH: export PATH="${BIN_DIR}:$PATH"`
|
|
42
|
+
: '';
|
|
43
|
+
}
|
|
44
|
+
const AGENT_GUIDE = join(FTOWN_DIR, 'harness-agent.md');
|
|
45
|
+
/** Agent-facing cheat sheet — rewritten on every bridge start. */
|
|
46
|
+
export function writeHarnessAgentGuide(opts) {
|
|
47
|
+
const h = opts.wrapperPath;
|
|
48
|
+
const body = `# ftown bridge harness (auto-generated)
|
|
49
|
+
|
|
50
|
+
Bridge is running. Use the harness CLI — **do not** use curl, lsof, or raw HTTP for the local bridge API.
|
|
51
|
+
|
|
52
|
+
## Command
|
|
53
|
+
|
|
54
|
+
\`\`\`bash
|
|
55
|
+
${h} <subcommand>
|
|
56
|
+
\`\`\`
|
|
57
|
+
|
|
58
|
+
Wrapper path is stable; bridge port/token live in \`~/.ftown/bridge.json\` (current port: ${opts.port}).
|
|
59
|
+
|
|
60
|
+
## Default workflow (run in order)
|
|
61
|
+
|
|
62
|
+
\`\`\`bash
|
|
63
|
+
${h} status # bridge up?
|
|
64
|
+
${h} here -n 25 # workspace session + tail (works when process dead if log exists)
|
|
65
|
+
${h} ls --tail 3 # all sessions; log=N lines; preview dead sessions too
|
|
66
|
+
${h} grep <name> "error|FAIL" -C 2
|
|
67
|
+
\`\`\`
|
|
68
|
+
|
|
69
|
+
## Subcommands
|
|
70
|
+
|
|
71
|
+
| Subcommand | Example |
|
|
72
|
+
|------------|---------|
|
|
73
|
+
| \`status\` | \`${h} status\` |
|
|
74
|
+
| \`ls\` | \`${h} ls --tail 3\` |
|
|
75
|
+
| \`here\` | \`${h} here -n 30\` — walks up from cwd to find workspace |
|
|
76
|
+
| \`tail\` | \`${h} tail ftown -n 40\` |
|
|
77
|
+
| \`grep\` | \`${h} grep legbi "pattern" -C 2\` |
|
|
78
|
+
| \`send\` | \`${h} send ftown "text" -s --dry-run\` first; **only if user asked** |
|
|
79
|
+
| \`--json\` | \`${h} --json ls\` — machine-readable output |
|
|
80
|
+
|
|
81
|
+
## Session names
|
|
82
|
+
|
|
83
|
+
Resolve by exact name → unique substring → id prefix. Ambiguous names print choices.
|
|
84
|
+
|
|
85
|
+
## Submit keys (\`-s\`)
|
|
86
|
+
|
|
87
|
+
- \`cursor\` / \`claude\`: Escape+Enter (\`\\x1b\\r\`)
|
|
88
|
+
- \`shell\`: Enter (\`\\r\`)
|
|
89
|
+
|
|
90
|
+
## Registry
|
|
91
|
+
|
|
92
|
+
\`~/.ftown/session-registry.json\` maps workspace roots → session id. \`here\` uses it.
|
|
93
|
+
|
|
94
|
+
## When bridge is down
|
|
95
|
+
|
|
96
|
+
\`${h}\` exits with a clear error. Start bridge from ftown UI → CLI Token → \`npx ftown-bridge --token ... --api-url ...\`
|
|
97
|
+
|
|
98
|
+
## context-mode
|
|
99
|
+
|
|
100
|
+
Allowed Bash: \`${h}\` subcommands (short output). Do not use curl/wget/fetch to \`127.0.0.1\` for bridge API.
|
|
101
|
+
`;
|
|
102
|
+
mkdirSync(FTOWN_DIR, { recursive: true, mode: 0o700 });
|
|
103
|
+
writeFileSync(AGENT_GUIDE, body, { mode: 0o600 });
|
|
104
|
+
}
|
|
105
|
+
export function agentGuidePath() {
|
|
106
|
+
return AGENT_GUIDE;
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=harness-installer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"harness-installer.js","sourceRoot":"","sources":["../src/harness-installer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAElC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAC;AAC5C,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;AACvC,MAAM,eAAe,GAAG,IAAI,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;AACvD,MAAM,qBAAqB,GAAG,IAAI,CAAC,SAAS,EAAE,kBAAkB,CAAC,CAAC;AAElE,MAAM,cAAc,GAAG;;;iBAGN,qBAAqB,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC;;;;;;;;;;;CAW5D,CAAC;AAQF,oEAAoE;AACpE,MAAM,UAAU,cAAc,CAAC,cAAsB;IACnD,MAAM,OAAO,GAAG,cAAc,CAAC;IAE/B,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACrD,aAAa,CAAC,qBAAqB,EAAE,OAAO,GAAG,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACtE,aAAa,CAAC,eAAe,EAAE,cAAc,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAEhE,OAAO;QACL,WAAW,EAAE,eAAe;QAC5B,OAAO;QACP,MAAM,EAAE,OAAO;KAChB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;IACvC,OAAO,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,OAAO,IAAI,CAAC,KAAK,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC;AACvF,CAAC;AAED,MAAM,UAAU,QAAQ;IACtB,OAAO,UAAU,CAAC,eAAe,CAAC;QAChC,CAAC,CAAC,6BAA6B,OAAO,SAAS;QAC/C,CAAC,CAAC,EAAE,CAAC;AACT,CAAC;AAED,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,EAAE,kBAAkB,CAAC,CAAC;AAExD,kEAAkE;AAClE,MAAM,UAAU,sBAAsB,CAAC,IAItC;IACC,MAAM,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC;IAC3B,MAAM,IAAI,GAAG;;;;;;;EAOb,CAAC;;;4FAGyF,IAAI,CAAC,IAAI;;;;;EAKnG,CAAC;EACD,CAAC;EACD,CAAC;EACD,CAAC;;;;;;;mBAOgB,CAAC;eACL,CAAC;iBACC,CAAC;iBACD,CAAC;iBACD,CAAC;iBACD,CAAC;mBACC,CAAC;;;;;;;;;;;;;;;;;IAiBhB,CAAC;;;;kBAIa,CAAC;CAClB,CAAC;IACA,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACvD,aAAa,CAAC,WAAW,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,OAAO,WAAW,CAAC;AACrB,CAAC"}
|
package/dist/hook-installer.js
CHANGED
|
@@ -2,7 +2,7 @@ import { existsSync, readFileSync, renameSync, writeFileSync, mkdirSync } from '
|
|
|
2
2
|
import { join, dirname } from 'node:path';
|
|
3
3
|
import { homedir } from 'node:os';
|
|
4
4
|
const HOOK_EVENTS = ['Notification', 'Stop', 'PreToolUse', 'PostToolUse', 'UserPromptSubmit'];
|
|
5
|
-
|
|
5
|
+
import { isFtownNotifyCommand } from './install-notify-script.js';
|
|
6
6
|
function isObject(value) {
|
|
7
7
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
8
8
|
}
|
|
@@ -60,7 +60,7 @@ export function installClaudeHooks(notifyScriptPath) {
|
|
|
60
60
|
continue;
|
|
61
61
|
for (let j = 0; j < inner.length; j++) {
|
|
62
62
|
const h = inner[j];
|
|
63
|
-
if (isObject(h) && typeof h.command === 'string' && h.command
|
|
63
|
+
if (isObject(h) && typeof h.command === 'string' && isFtownNotifyCommand(h.command)) {
|
|
64
64
|
foundIndex = i;
|
|
65
65
|
foundHookIndex = j;
|
|
66
66
|
break;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hook-installer.js","sourceRoot":"","sources":["../src/hook-installer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACzF,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAElC,MAAM,WAAW,GAAG,CAAC,cAAc,EAAE,MAAM,EAAE,YAAY,EAAE,aAAa,EAAE,kBAAkB,CAAU,CAAC;AAEvG,
|
|
1
|
+
{"version":3,"file":"hook-installer.js","sourceRoot":"","sources":["../src/hook-installer.ts"],"names":[],"mappings":"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"}
|