ftown-bridge 0.3.14 → 0.3.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/bin/ftown-sessions +5 -0
  2. package/dist/agent-commands.d.ts +17 -0
  3. package/dist/agent-commands.js +41 -0
  4. package/dist/agent-commands.js.map +1 -0
  5. package/dist/claude-runner.js +5 -1
  6. package/dist/claude-runner.js.map +1 -1
  7. package/dist/create-ftown-session.d.ts +33 -0
  8. package/dist/create-ftown-session.js +81 -0
  9. package/dist/create-ftown-session.js.map +1 -0
  10. package/dist/cursor-hook-installer.d.ts +3 -0
  11. package/dist/cursor-hook-installer.js +22 -6
  12. package/dist/cursor-hook-installer.js.map +1 -1
  13. package/dist/ftown-sessions-cli.d.ts +2 -0
  14. package/dist/ftown-sessions-cli.js +223 -0
  15. package/dist/ftown-sessions-cli.js.map +1 -0
  16. package/dist/harness-cli.d.ts +2 -0
  17. package/dist/harness-cli.js +432 -0
  18. package/dist/harness-cli.js.map +1 -0
  19. package/dist/harness-format.d.ts +3 -0
  20. package/dist/harness-format.js +14 -0
  21. package/dist/harness-format.js.map +1 -0
  22. package/dist/harness-installer.d.ts +16 -0
  23. package/dist/harness-installer.js +108 -0
  24. package/dist/harness-installer.js.map +1 -0
  25. package/dist/hook-installer.js +2 -2
  26. package/dist/hook-installer.js.map +1 -1
  27. package/dist/index.js +59 -27
  28. package/dist/index.js.map +1 -1
  29. package/dist/install-ftown-cli.d.ts +3 -0
  30. package/dist/install-ftown-cli.js +20 -0
  31. package/dist/install-ftown-cli.js.map +1 -0
  32. package/dist/install-ftown-skill.d.ts +4 -0
  33. package/dist/install-ftown-skill.js +50 -0
  34. package/dist/install-ftown-skill.js.map +1 -0
  35. package/dist/install-notify-script.d.ts +6 -0
  36. package/dist/install-notify-script.js +23 -0
  37. package/dist/install-notify-script.js.map +1 -0
  38. package/dist/local-api-server.d.ts +3 -0
  39. package/dist/local-api-server.js +56 -3
  40. package/dist/local-api-server.js.map +1 -1
  41. package/dist/session-registry.d.ts +4 -0
  42. package/dist/session-registry.js +72 -0
  43. package/dist/session-registry.js.map +1 -0
  44. package/dist/terminal-manager.d.ts +3 -1
  45. package/dist/terminal-manager.js +15 -6
  46. package/dist/terminal-manager.js.map +1 -1
  47. package/dist/types.d.ts +1 -0
  48. package/dist/xterm-theme.d.ts +30 -0
  49. package/dist/xterm-theme.js +38 -0
  50. package/dist/xterm-theme.js.map +1 -0
  51. package/hooks/notify.sh +36 -4
  52. package/package.json +9 -4
  53. package/skills/bridge-harness/SKILL.md +43 -0
  54. package/skills/ftown-sessions/SKILL.md +101 -0
  55. package/skills/ftown-sessions/scripts/ftown-sessions +4 -0
@@ -0,0 +1,72 @@
1
+ import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { homedir } from 'node:os';
4
+ import { resolve } from 'node:path';
5
+ const REGISTRY_PATH = join(homedir(), '.ftown', 'session-registry.json');
6
+ function loadRegistry() {
7
+ try {
8
+ if (!existsSync(REGISTRY_PATH)) {
9
+ return { byWorkspace: {}, byConversation: {} };
10
+ }
11
+ const parsed = JSON.parse(readFileSync(REGISTRY_PATH, 'utf8'));
12
+ return {
13
+ byWorkspace: parsed.byWorkspace ?? {},
14
+ byConversation: parsed.byConversation ?? {},
15
+ };
16
+ }
17
+ catch {
18
+ return { byWorkspace: {}, byConversation: {} };
19
+ }
20
+ }
21
+ function saveRegistry(data) {
22
+ mkdirSync(join(homedir(), '.ftown'), { recursive: true, mode: 0o700 });
23
+ const tmp = `${REGISTRY_PATH}.tmp`;
24
+ writeFileSync(tmp, JSON.stringify(data, null, 2) + '\n', { mode: 0o600 });
25
+ renameSync(tmp, REGISTRY_PATH);
26
+ }
27
+ export function registerSessionWorkspace(sessionId, workingDir) {
28
+ if (!workingDir?.trim())
29
+ return;
30
+ const data = loadRegistry();
31
+ data.byWorkspace[resolve(workingDir.trim())] = sessionId;
32
+ saveRegistry(data);
33
+ }
34
+ export function registerSessionConversation(sessionId, conversationId) {
35
+ if (!conversationId)
36
+ return;
37
+ const data = loadRegistry();
38
+ data.byConversation[conversationId] = sessionId;
39
+ saveRegistry(data);
40
+ }
41
+ export function unregisterSession(sessionId) {
42
+ const data = loadRegistry();
43
+ for (const [path, id] of Object.entries(data.byWorkspace)) {
44
+ if (id === sessionId)
45
+ delete data.byWorkspace[path];
46
+ }
47
+ for (const [conv, id] of Object.entries(data.byConversation)) {
48
+ if (id === sessionId)
49
+ delete data.byConversation[conv];
50
+ }
51
+ saveRegistry(data);
52
+ }
53
+ export function resolveSessionIdFromHookPayload(payload) {
54
+ const ftownId = payload.ftown_session_id;
55
+ if (typeof ftownId === 'string' && ftownId)
56
+ return ftownId;
57
+ const data = loadRegistry();
58
+ const conversationId = payload.conversation_id;
59
+ if (typeof conversationId === 'string' && conversationId) {
60
+ const byConv = data.byConversation[conversationId];
61
+ if (byConv)
62
+ return byConv;
63
+ }
64
+ const roots = payload.workspace_roots;
65
+ if (Array.isArray(roots) && typeof roots[0] === 'string' && roots[0]) {
66
+ const byWs = data.byWorkspace[resolve(roots[0])];
67
+ if (byWs)
68
+ return byWs;
69
+ }
70
+ return undefined;
71
+ }
72
+ //# sourceMappingURL=session-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-registry.js","sourceRoot":"","sources":["../src/session-registry.ts"],"names":[],"mappings":"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"}
@@ -7,6 +7,8 @@ export interface ScreenData {
7
7
  export interface GrepMatch {
8
8
  lineNumber: number;
9
9
  text: string;
10
+ before?: string[];
11
+ after?: string[];
10
12
  }
11
13
  export interface GrepResult {
12
14
  matches: GrepMatch[];
@@ -25,7 +27,7 @@ export declare class TerminalManager {
25
27
  getRawBuffer(sessionId: string): string;
26
28
  serialize(sessionId: string, scrollback?: number): string;
27
29
  getScreen(sessionId: string, offset?: number, limit?: number): ScreenData;
28
- grep(sessionId: string, pattern: string, offset?: number, limit?: number): GrepResult;
30
+ grep(sessionId: string, pattern: string, offset?: number, limit?: number, contextLines?: number): GrepResult;
29
31
  replay(sessionId: string, rawLog: string): void;
30
32
  resize(sessionId: string, cols: number, rows: number): void;
31
33
  destroy(sessionId: string): void;
@@ -1,5 +1,6 @@
1
1
  import xtermHeadless from '@xterm/headless';
2
2
  import serializeAddon from '@xterm/addon-serialize';
3
+ import { FTOWN_XTERM_THEME } from './xterm-theme.js';
3
4
  const { Terminal } = xtermHeadless;
4
5
  const { SerializeAddon } = serializeAddon;
5
6
  export class TerminalManager {
@@ -18,6 +19,7 @@ export class TerminalManager {
18
19
  rows: 40,
19
20
  scrollback: this.scrollback,
20
21
  allowProposedApi: true,
22
+ theme: FTOWN_XTERM_THEME,
21
23
  });
22
24
  const serializer = new SerializeAddon();
23
25
  terminal.loadAddon(serializer);
@@ -67,7 +69,7 @@ export class TerminalManager {
67
69
  const lines = allLines.slice(offset, offset + limit);
68
70
  return { lines, totalLines, offset, limit };
69
71
  }
70
- grep(sessionId, pattern, offset = 0, limit = 1000) {
72
+ grep(sessionId, pattern, offset = 0, limit = 1000, contextLines = 0) {
71
73
  const managed = this.terminals.get(sessionId);
72
74
  if (!managed) {
73
75
  return { matches: [], totalMatches: 0, offset, limit };
@@ -80,14 +82,21 @@ export class TerminalManager {
80
82
  return { matches: [], totalMatches: 0, offset, limit };
81
83
  }
82
84
  const totalLines = managed.terminal.buffer.active.length;
83
- const matches = [];
85
+ const lineTexts = [];
84
86
  for (let i = 0; i < totalLines; i++) {
85
87
  const line = managed.terminal.buffer.active.getLine(i);
86
- if (line) {
87
- const text = line.translateToString(true);
88
- if (regex.test(text)) {
89
- matches.push({ lineNumber: i + 1, text });
88
+ lineTexts.push(line ? line.translateToString(true) : '');
89
+ }
90
+ const matches = [];
91
+ const ctx = Math.max(0, Math.min(10, contextLines));
92
+ for (let i = 0; i < lineTexts.length; i++) {
93
+ if (regex.test(lineTexts[i])) {
94
+ const entry = { lineNumber: i + 1, text: lineTexts[i] };
95
+ if (ctx > 0) {
96
+ entry.before = lineTexts.slice(Math.max(0, i - ctx), i);
97
+ entry.after = lineTexts.slice(i + 1, Math.min(lineTexts.length, i + 1 + ctx));
90
98
  }
99
+ matches.push(entry);
91
100
  }
92
101
  }
93
102
  const totalMatches = matches.length;
@@ -1 +1 @@
1
- {"version":3,"file":"terminal-manager.js","sourceRoot":"","sources":["../src/terminal-manager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"terminal-manager.js","sourceRoot":"","sources":["../src/terminal-manager.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -34,6 +34,7 @@ export interface Command {
34
34
  export type CommandType = 'create_session' | 'stop_session' | 'list_sessions' | 'get_history' | 'retry_session' | 'send_message' | 'rename_session' | 'remove_session' | 'bridge_exec' | 'clear_terminal' | 'update_session_parent';
35
35
  export interface CreateSessionPayload {
36
36
  command: string;
37
+ prompt?: string;
37
38
  name?: string;
38
39
  workingDir?: string;
39
40
  bridgeId?: string;
@@ -0,0 +1,30 @@
1
+ /** Match ui/src/components/Terminal.tsx so serialize/replay preserves agent colors. */
2
+ export declare const FTOWN_XTERM_THEME: {
3
+ readonly background: "#07070a";
4
+ readonly foreground: "#e8e8f0";
5
+ readonly cursor: "#00ff88";
6
+ readonly cursorAccent: "#07070a";
7
+ readonly selectionBackground: "rgba(0, 255, 136, 0.15)";
8
+ readonly black: "#0a0a0d";
9
+ readonly red: "#ff4466";
10
+ readonly green: "#00ff88";
11
+ readonly yellow: "#ffaa00";
12
+ readonly blue: "#44aaff";
13
+ readonly magenta: "#cc66ff";
14
+ readonly cyan: "#00ddff";
15
+ readonly white: "#c8c8d8";
16
+ readonly brightBlack: "#44444f";
17
+ readonly brightRed: "#ff6680";
18
+ readonly brightGreen: "#33ffaa";
19
+ readonly brightYellow: "#ffcc44";
20
+ readonly brightBlue: "#66bbff";
21
+ readonly brightMagenta: "#dd88ff";
22
+ readonly brightCyan: "#44eeff";
23
+ readonly brightWhite: "#e8e8f0";
24
+ };
25
+ /**
26
+ * Ink-based CLIs (Cursor Agent) emit no ANSI colors unless truecolor is advertised.
27
+ * The bridge process often inherits NO_COLOR=1 from Cursor IDE — strip it for PTY children
28
+ * unless the user explicitly opts out via session env (NO_COLOR=1 or FTOWN_NO_COLOR=1).
29
+ */
30
+ export declare function applyTerminalColorEnv(env: Record<string, string>): void;
@@ -0,0 +1,38 @@
1
+ /** Match ui/src/components/Terminal.tsx so serialize/replay preserves agent colors. */
2
+ export const FTOWN_XTERM_THEME = {
3
+ background: '#07070a',
4
+ foreground: '#e8e8f0',
5
+ cursor: '#00ff88',
6
+ cursorAccent: '#07070a',
7
+ selectionBackground: 'rgba(0, 255, 136, 0.15)',
8
+ black: '#0a0a0d',
9
+ red: '#ff4466',
10
+ green: '#00ff88',
11
+ yellow: '#ffaa00',
12
+ blue: '#44aaff',
13
+ magenta: '#cc66ff',
14
+ cyan: '#00ddff',
15
+ white: '#c8c8d8',
16
+ brightBlack: '#44444f',
17
+ brightRed: '#ff6680',
18
+ brightGreen: '#33ffaa',
19
+ brightYellow: '#ffcc44',
20
+ brightBlue: '#66bbff',
21
+ brightMagenta: '#dd88ff',
22
+ brightCyan: '#44eeff',
23
+ brightWhite: '#e8e8f0',
24
+ };
25
+ /**
26
+ * Ink-based CLIs (Cursor Agent) emit no ANSI colors unless truecolor is advertised.
27
+ * The bridge process often inherits NO_COLOR=1 from Cursor IDE — strip it for PTY children
28
+ * unless the user explicitly opts out via session env (NO_COLOR=1 or FTOWN_NO_COLOR=1).
29
+ */
30
+ export function applyTerminalColorEnv(env) {
31
+ env.TERM = env.TERM || 'xterm-256color';
32
+ if (env.FTOWN_NO_COLOR === '1' || env.NO_COLOR === '1' || env.NO_COLOR === 'true') {
33
+ return;
34
+ }
35
+ env.COLORTERM = 'truecolor';
36
+ env.FORCE_COLOR = '3';
37
+ }
38
+ //# sourceMappingURL=xterm-theme.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xterm-theme.js","sourceRoot":"","sources":["../src/xterm-theme.ts"],"names":[],"mappings":"AAAA,uFAAuF;AACvF,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,UAAU,EAAE,SAAS;IACrB,UAAU,EAAE,SAAS;IACrB,MAAM,EAAE,SAAS;IACjB,YAAY,EAAE,SAAS;IACvB,mBAAmB,EAAE,yBAAyB;IAC9C,KAAK,EAAE,SAAS;IAChB,GAAG,EAAE,SAAS;IACd,KAAK,EAAE,SAAS;IAChB,MAAM,EAAE,SAAS;IACjB,IAAI,EAAE,SAAS;IACf,OAAO,EAAE,SAAS;IAClB,IAAI,EAAE,SAAS;IACf,KAAK,EAAE,SAAS;IAChB,WAAW,EAAE,SAAS;IACtB,SAAS,EAAE,SAAS;IACpB,WAAW,EAAE,SAAS;IACtB,YAAY,EAAE,SAAS;IACvB,UAAU,EAAE,SAAS;IACrB,aAAa,EAAE,SAAS;IACxB,UAAU,EAAE,SAAS;IACrB,WAAW,EAAE,SAAS;CACd,CAAC;AAEX;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAC,GAA2B;IAC/D,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,IAAI,gBAAgB,CAAC;IAExC,IAAI,GAAG,CAAC,cAAc,KAAK,GAAG,IAAI,GAAG,CAAC,QAAQ,KAAK,GAAG,IAAI,GAAG,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;QAClF,OAAO;IACT,CAAC;IAED,GAAG,CAAC,SAAS,GAAG,WAAW,CAAC;IAC5B,GAAG,CAAC,WAAW,GAAG,GAAG,CAAC;AACxB,CAAC"}
package/hooks/notify.sh CHANGED
@@ -1,16 +1,48 @@
1
1
  #!/bin/bash
2
2
  INPUT=$(cat)
3
- PORT="${FTOWN_HOOK_PORT}"
4
- SESSION_ID="${FTOWN_SESSION_ID}"
5
- TOKEN="${FTOWN_HOOK_TOKEN}"
3
+
4
+ PORT="${FTOWN_HOOK_PORT:-}"
5
+ SESSION_ID="${FTOWN_SESSION_ID:-}"
6
+ TOKEN="${FTOWN_HOOK_TOKEN:-}"
7
+
8
+ BRIDGE_JSON="${HOME}/.ftown/bridge.json"
9
+ REGISTRY="${HOME}/.ftown/session-registry.json"
10
+
11
+ if [ -z "$PORT" ] && [ -f "$BRIDGE_JSON" ]; then
12
+ PORT=$(jq -r '.port // empty' "$BRIDGE_JSON" 2>/dev/null)
13
+ if [ -z "$TOKEN" ]; then
14
+ TOKEN=$(jq -r '.token // empty' "$BRIDGE_JSON" 2>/dev/null)
15
+ fi
16
+ fi
17
+
18
+ if [ -z "$SESSION_ID" ] && [ -n "$INPUT" ]; then
19
+ CONV=$(echo "$INPUT" | jq -r '.conversation_id // empty' 2>/dev/null)
20
+ WS=$(echo "$INPUT" | jq -r '.workspace_roots[0] // empty' 2>/dev/null)
21
+ if [ -f "$REGISTRY" ]; then
22
+ if [ -n "$CONV" ]; then
23
+ SESSION_ID=$(jq -r --arg c "$CONV" '.byConversation[$c] // empty' "$REGISTRY" 2>/dev/null)
24
+ fi
25
+ if [ -z "$SESSION_ID" ] && [ -n "$WS" ]; then
26
+ SESSION_ID=$(jq -r --arg w "$WS" '.byWorkspace[$w] // empty' "$REGISTRY" 2>/dev/null)
27
+ fi
28
+ fi
29
+ fi
30
+
6
31
  if [ -z "$PORT" ] || [ -z "$SESSION_ID" ]; then
7
32
  exit 0
8
33
  fi
9
- PAYLOAD=$(echo "$INPUT" | jq -c --arg sid "$SESSION_ID" '. + {ftown_session_id: $sid}')
34
+
35
+ PAYLOAD=$(echo "$INPUT" | jq -c --arg sid "$SESSION_ID" '. + {ftown_session_id: $sid}' 2>/dev/null)
36
+ if [ -z "$PAYLOAD" ]; then
37
+ PAYLOAD=$(jq -nc --arg sid "$SESSION_ID" --arg ev "${HOOK_EVENT_NAME:-hook}" \
38
+ '{ftown_session_id: $sid, hook_event_name: $ev}')
39
+ fi
40
+
10
41
  AUTH_ARGS=()
11
42
  if [ -n "$TOKEN" ]; then
12
43
  AUTH_ARGS+=(-H "Authorization: Bearer ${TOKEN}")
13
44
  fi
45
+
14
46
  curl -s -X POST "http://localhost:${PORT}/hook" \
15
47
  -H "Content-Type: application/json" \
16
48
  "${AUTH_ARGS[@]}" \
package/package.json CHANGED
@@ -1,21 +1,26 @@
1
1
  {
2
2
  "name": "ftown-bridge",
3
- "version": "0.3.14",
3
+ "version": "0.3.16",
4
4
  "description": "CLI bridge for ftown — generic PTY-over-Centrifugo relay",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "bin": {
8
- "ftown-bridge": "dist/index.js"
8
+ "ftown-bridge": "dist/index.js",
9
+ "ftown-harness": "dist/harness-cli.js",
10
+ "ftown-sessions": "bin/ftown-sessions"
9
11
  },
10
12
  "files": [
11
13
  "dist",
12
- "hooks"
14
+ "bin",
15
+ "hooks",
16
+ "skills"
13
17
  ],
14
18
  "scripts": {
15
19
  "build": "tsc",
16
20
  "prepublishOnly": "npm run build",
17
21
  "start": "tsx src/index.ts",
18
- "dev": "tsx watch src/index.ts"
22
+ "dev": "tsx watch src/index.ts",
23
+ "harness": "tsx src/harness-cli.ts"
19
24
  },
20
25
  "engines": {
21
26
  "node": ">=22"
@@ -0,0 +1,43 @@
1
+ ---
2
+ name: bridge-harness
3
+ description: Control local ftown-bridge sessions via auto-deployed ~/.ftown/bin/ftown-harness. Triggers on bridge harness, /bridge-harness, bridge sessions.
4
+ ---
5
+
6
+ # bridge-harness
7
+
8
+ ## Entry (auto-deployed)
9
+
10
+ ```bash
11
+ ~/.ftown/bin/ftown-harness <cmd>
12
+ ```
13
+
14
+ Read `~/.ftown/harness-agent.md` on each bridge start. Never curl/lsof the local bridge API.
15
+
16
+ ## Playbook
17
+
18
+ ```bash
19
+ ftown-harness status
20
+ ftown-harness here -n 25 # tails log even if process dead (status=error)
21
+ ftown-harness ls --tail 3 # log=N on each row; previews dead sessions with logs
22
+ ftown-harness grep ftown "error|FAIL" -C 2
23
+ ```
24
+
25
+ ## Commands
26
+
27
+ | Cmd | Notes |
28
+ |-----|-------|
29
+ | `here -n N` | Workspace walk-up; **tails when dead** if log exists |
30
+ | `ls --tail N` | Shows `log=lines`; preview any session with logs |
31
+ | `tail` / `grep` | ANSI+OSC stripped; `grep -C 2` context |
32
+ | `send` | `--dry-run` first; `-s` submit; only when user asks |
33
+ | `--json` | `ftown-harness --json ls` etc. |
34
+
35
+ Lookup: exact name → substring → id prefix.
36
+
37
+ ## Dead vs error
38
+
39
+ `status=error` + `alive=false` does **not** mean no logs. Use `here`/`tail` — they read persisted terminal logs.
40
+
41
+ ## context-mode
42
+
43
+ Use `ftown-harness` in Bash only. No curl/wget to 127.0.0.1.
@@ -0,0 +1,101 @@
1
+ ---
2
+ name: ftown-sessions
3
+ description: >-
4
+ Observe and control other ftown CLI agent sessions on the same machine. Use the
5
+ ftown-sessions CLI (~/.ftown/ftown-sessions) to list, create, read, and drive
6
+ sibling sessions while running inside a ftown-managed Claude Code or Cursor Agent
7
+ session.
8
+ ---
9
+
10
+ # ftown cross-session CLI
11
+
12
+ **Prefer the CLI** — installed to `~/.ftown/ftown-sessions` whenever `ftown-bridge` is running. It reads `~/.ftown/bridge.json` automatically.
13
+
14
+ ```bash
15
+ ~/.ftown/ftown-sessions --help
16
+ ```
17
+
18
+ Skill copy (same binary via wrapper): `scripts/ftown-sessions` in this skill directory.
19
+
20
+ **Trust model:** anyone who can read `bridge.json` can control **every** ftown session on that bridge.
21
+
22
+ ## Commands
23
+
24
+ ```bash
25
+ # List sessions (JSON)
26
+ ~/.ftown/ftown-sessions list
27
+
28
+ # Spawn a child agent (uses FTOWN_SESSION_ID for --parent)
29
+ ~/.ftown/ftown-sessions create \
30
+ --shell cursor \
31
+ --prompt "Review the auth module and summarize" \
32
+ --workdir /path/to/repo \
33
+ --name auth-review \
34
+ --parent
35
+
36
+ # Metadata
37
+ ~/.ftown/ftown-sessions get <session-id>
38
+
39
+ # Terminal output (plain lines; add --json for structured)
40
+ ~/.ftown/ftown-sessions screen <session-id> --limit 200
41
+
42
+ # Search output
43
+ ~/.ftown/ftown-sessions grep <session-id> --pattern 'error|failed'
44
+
45
+ # Type into another running session
46
+ ~/.ftown/ftown-sessions keys <session-id> 'y'
47
+
48
+ # Liveness
49
+ ~/.ftown/ftown-sessions running <session-id>
50
+ ```
51
+
52
+ ### Create options
53
+
54
+ | Flag | Description |
55
+ |------|-------------|
56
+ | `--shell` | `cursor`, `claude`, `shell`, `opencode`, … (default `claude`) |
57
+ | `--prompt` | Initial message sent after spawn |
58
+ | `--workdir` | Working directory |
59
+ | `--name` | Dashboard label |
60
+ | `--command` | Full command override (skips `--shell` builder) |
61
+ | `--parent` | Set parent to `$FTOWN_SESSION_ID` |
62
+ | `--parent-id` | Explicit parent session UUID |
63
+ | `--model` | Cursor model name |
64
+
65
+ Returns JSON with the new `session.id` — use that id for `screen` / `grep` / `keys`.
66
+
67
+ ## Typical workflow
68
+
69
+ ```bash
70
+ CLI=~/.ftown/ftown-sessions
71
+
72
+ $CLI list
73
+ $CLI create --shell cursor --prompt "Run tests and report" --workdir "$PWD" --parent
74
+ # -> note session.id from JSON
75
+
76
+ $CLI screen <child-id> --limit 100
77
+ $CLI grep <child-id> --pattern 'FAIL|Error'
78
+ ```
79
+
80
+ ## Environment
81
+
82
+ Spawned ftown sessions receive:
83
+
84
+ - `FTOWN_SESSION_ID` — this session (use with `--parent`)
85
+ - `FTOWN_HOOK_PORT` / `FTOWN_HOOK_TOKEN` — hook forwarding (not for cross-session control)
86
+
87
+ ## HTTP API (optional)
88
+
89
+ The CLI wraps the loopback API. Raw access if needed:
90
+
91
+ | Method | Path | Purpose |
92
+ |--------|------|---------|
93
+ | GET | `/api/sessions` | List |
94
+ | POST | `/api/sessions` | Create |
95
+ | GET | `/api/sessions/:id/screen` | Terminal lines |
96
+ | POST | `/api/sessions/:id/grep` | Search |
97
+ | POST | `/api/sessions/:id/keys` | Send keys |
98
+
99
+ ## If the CLI is missing
100
+
101
+ Start or restart **ftown-bridge** on this machine. It installs `~/.ftown/ftown-sessions`, `~/.ftown/notify.sh`, and updates this skill under `~/.agents/skills/ftown-sessions/`.
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env bash
2
+ # Delegates to the bridge-installed CLI (~/.ftown/ftown-sessions).
3
+ set -euo pipefail
4
+ exec "${HOME}/.ftown/ftown-sessions" "$@"