flow-agent-bridge 0.2.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.
@@ -0,0 +1,177 @@
1
+ // Runtime exec: spawn a coding-agent CLI headlessly per conversation turn.
2
+ //
3
+ // Claude runtime (primary): `claude -p --output-format stream-json --verbose`
4
+ // with `--session-id <uuid>` on the first turn and `--resume <uuid>` after.
5
+ // Tool calls stream by as stream-json events → surfaced as thinking steps.
6
+ // Codex runtime: STUB — baseline "prompt in, stdout out" contract, no session
7
+ // resume, no thinking steps. Untested; see AGENTS.md.
8
+ import { spawn } from 'node:child_process';
9
+ import path from 'node:path';
10
+ /** One line per tool call, latest step shown: "Bash: pnpm test". */
11
+ export function formatToolStep(name, input) {
12
+ const i = (input ?? {});
13
+ const short = (v, max = 80) => {
14
+ const s = String(v ?? '').replace(/\s+/g, ' ').trim();
15
+ return s.length > max ? `${s.slice(0, max - 1)}…` : s;
16
+ };
17
+ if (name.startsWith('mcp__flow__'))
18
+ return `Flow: ${name.slice('mcp__flow__'.length)}`;
19
+ if (name.startsWith('mcp__'))
20
+ return name.replace(/^mcp__/, '').replace('__', ': ');
21
+ switch (name) {
22
+ case 'Bash':
23
+ return `Bash: ${short(i.command)}`;
24
+ case 'Read':
25
+ case 'Write':
26
+ case 'Edit':
27
+ case 'NotebookEdit':
28
+ return `${name}: ${short(path.basename(String(i.file_path ?? i.notebook_path ?? '')))}`;
29
+ case 'Glob':
30
+ case 'Grep':
31
+ return `${name}: ${short(i.pattern)}`;
32
+ case 'WebSearch':
33
+ return `WebSearch: ${short(i.query)}`;
34
+ case 'WebFetch':
35
+ return `WebFetch: ${short(i.url)}`;
36
+ case 'Task':
37
+ case 'Agent':
38
+ return `Agent: ${short(i.description ?? i.prompt)}`;
39
+ case 'TodoWrite':
40
+ return 'updating plan';
41
+ default:
42
+ return name;
43
+ }
44
+ }
45
+ /**
46
+ * Feed stream-json stdout lines; emits tool steps and captures the final
47
+ * result. Tolerant of non-JSON noise on stdout.
48
+ */
49
+ export class StreamJsonParser {
50
+ onToolStep;
51
+ buf = '';
52
+ finalText = '';
53
+ isError = false;
54
+ sawResult = false;
55
+ constructor(onToolStep) {
56
+ this.onToolStep = onToolStep;
57
+ }
58
+ feed(chunk) {
59
+ this.buf += chunk;
60
+ let idx;
61
+ while ((idx = this.buf.indexOf('\n')) >= 0) {
62
+ const line = this.buf.slice(0, idx).trim();
63
+ this.buf = this.buf.slice(idx + 1);
64
+ if (!line)
65
+ continue;
66
+ this.handleLine(line);
67
+ }
68
+ }
69
+ handleLine(line) {
70
+ let ev;
71
+ try {
72
+ ev = JSON.parse(line);
73
+ }
74
+ catch {
75
+ return; // non-JSON noise
76
+ }
77
+ if (ev.type === 'assistant') {
78
+ for (const block of ev.message?.content ?? []) {
79
+ if (block.type === 'tool_use' && block.name)
80
+ this.onToolStep(formatToolStep(block.name, block.input));
81
+ }
82
+ }
83
+ else if (ev.type === 'result') {
84
+ this.sawResult = true;
85
+ this.isError = ev.is_error === true || (ev.subtype !== undefined && ev.subtype !== 'success');
86
+ this.finalText = ev.result ?? '';
87
+ }
88
+ }
89
+ }
90
+ function buildClaudeArgs(cfg, opts) {
91
+ const args = ['-p', '--output-format', 'stream-json', '--verbose'];
92
+ args.push(opts.resume ? '--resume' : '--session-id', opts.sessionId);
93
+ args.push('--append-system-prompt', opts.systemPrompt);
94
+ args.push('--max-turns', String(cfg.maxTurns));
95
+ if (cfg.permissionMode)
96
+ args.push('--permission-mode', cfg.permissionMode);
97
+ const allowed = [...cfg.allowedTools];
98
+ if (opts.mcpConfigPath) {
99
+ // = form: --mcp-config and --allowedTools are variadic in the claude CLI
100
+ // and would otherwise swallow the trailing positional prompt
101
+ args.push(`--mcp-config=${opts.mcpConfigPath}`);
102
+ allowed.push('mcp__flow'); // pre-grant the flow tools — headless runs can't prompt
103
+ }
104
+ if (allowed.length)
105
+ args.push(`--allowedTools=${allowed.join(',')}`);
106
+ args.push(...cfg.extraArgs);
107
+ args.push(opts.prompt);
108
+ return args;
109
+ }
110
+ function buildCodexArgs(cfg, opts) {
111
+ // STUB: baseline contract only (stdout = reply). No session resume.
112
+ return ['exec', '--skip-git-repo-check', ...cfg.extraArgs, opts.prompt];
113
+ }
114
+ /** Demo mode: static canned reply, no CLI spawn. */
115
+ export const DEMO_REPLY = 'Your message was received';
116
+ export async function runRuntime(cfg, opts) {
117
+ if (cfg.kind === 'demo') {
118
+ // Brief pause so the typing indicator is visible in clients.
119
+ await new Promise((r) => setTimeout(r, 500));
120
+ return { ok: true, text: DEMO_REPLY };
121
+ }
122
+ const args = cfg.kind === 'claude' ? buildClaudeArgs(cfg, opts) : buildCodexArgs(cfg, opts);
123
+ return new Promise((resolve) => {
124
+ const child = spawn(cfg.command, args, {
125
+ cwd: cfg.cwd,
126
+ stdio: ['ignore', 'pipe', 'pipe'],
127
+ env: { ...process.env },
128
+ });
129
+ const parser = new StreamJsonParser(opts.onToolStep);
130
+ let stdout = '';
131
+ let stderr = '';
132
+ let settled = false;
133
+ const timer = setTimeout(() => {
134
+ if (settled)
135
+ return;
136
+ settled = true;
137
+ child.kill('SIGKILL');
138
+ resolve({ ok: false, text: '', error: `timed out after ${cfg.timeoutSec}s` });
139
+ }, cfg.timeoutSec * 1000);
140
+ child.stdout.on('data', (d) => {
141
+ const s = d.toString('utf8');
142
+ stdout += s;
143
+ if (cfg.kind === 'claude')
144
+ parser.feed(s);
145
+ });
146
+ child.stderr.on('data', (d) => {
147
+ stderr += d.toString('utf8');
148
+ });
149
+ child.on('error', (err) => {
150
+ if (settled)
151
+ return;
152
+ settled = true;
153
+ clearTimeout(timer);
154
+ resolve({ ok: false, text: '', error: `could not spawn ${cfg.command}: ${err.message}` });
155
+ });
156
+ child.on('close', (code) => {
157
+ if (settled)
158
+ return;
159
+ settled = true;
160
+ clearTimeout(timer);
161
+ parser.feed('\n'); // flush a trailing unterminated line
162
+ if (cfg.kind === 'claude') {
163
+ if (parser.sawResult && !parser.isError)
164
+ return resolve({ ok: true, text: parser.finalText });
165
+ const error = parser.sawResult
166
+ ? `runtime reported an error${parser.finalText ? `: ${parser.finalText.slice(0, 300)}` : ''}`
167
+ : `runtime exited ${code} without a result${stderr ? `: ${stderr.slice(-300)}` : ''}`;
168
+ return resolve({ ok: false, text: parser.finalText, error });
169
+ }
170
+ // baseline contract: stdout is the reply
171
+ if (code === 0)
172
+ return resolve({ ok: true, text: stdout.trim() });
173
+ return resolve({ ok: false, text: '', error: `runtime exited ${code}${stderr ? `: ${stderr.slice(-300)}` : ''}` });
174
+ });
175
+ });
176
+ }
177
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare function runSetup(configPath: string): Promise<string>;
package/dist/setup.js ADDED
@@ -0,0 +1,86 @@
1
+ // Interactive first-run setup: prompt for the invite key, exchange it for an
2
+ // agent token, ask the handful of questions that matter, save agent.json, and
3
+ // hand back the path so the caller can start the daemon immediately.
4
+ // Advanced knobs (permissionMode, allowedTools, eventScope, …) are edited in
5
+ // the saved file — see AGENTS.md.
6
+ import fs from 'node:fs';
7
+ import path from 'node:path';
8
+ import readline from 'node:readline/promises';
9
+ import { FlowApi, registerAgent } from './api.js';
10
+ import { expandHome } from './config.js';
11
+ async function ask(rl, q, def) {
12
+ const suffix = def ? ` [${def}]` : '';
13
+ const answer = (await rl.question(`${q}${suffix}: `)).trim();
14
+ return answer || def || '';
15
+ }
16
+ export async function runSetup(configPath) {
17
+ if (!process.stdin.isTTY) {
18
+ throw new Error(`no config at ${configPath} and stdin is not a TTY — run interactively or pass a config path`);
19
+ }
20
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
21
+ try {
22
+ console.log('No config found — setting up a new agent.\n');
23
+ const serverUrl = (await ask(rl, 'Flow server URL', process.env.FLOW_SERVER_URL ?? 'https://app.flowtoo.org')).replace(/\/+$/, '');
24
+ let key = '';
25
+ while (!key.startsWith('flow-agent-')) {
26
+ key = await ask(rl, 'Invite key (flow-agent-…) — or an agent token (flow-agent-token-…, from "Regenerate token") to reuse an existing agent');
27
+ if (!key.startsWith('flow-agent-'))
28
+ console.log(' that does not look like a flow-agent-… key or token');
29
+ }
30
+ let agentToken;
31
+ if (key.startsWith('flow-agent-token-')) {
32
+ // Existing agent: validate the token and skip registration.
33
+ console.log('\nAgent token detected — verifying…');
34
+ const me = await new FlowApi(serverUrl, key).me();
35
+ console.log(`connecting as existing agent ${me.displayName} <@${me.id}>\n`);
36
+ agentToken = key;
37
+ }
38
+ else {
39
+ const name = await ask(rl, 'Agent name (blank = use the invite’s name hint)');
40
+ const description = await ask(rl, 'Description (optional)');
41
+ console.log('\nRegistering…');
42
+ const res = await registerAgent(serverUrl, {
43
+ inviteKey: key,
44
+ ...(name ? { name } : {}),
45
+ ...(description ? { description } : {}),
46
+ });
47
+ console.log(`registered ${res.user.displayName} <@${res.user.id}> in workspace "${res.workspace.name}"\n`);
48
+ agentToken = res.agentToken;
49
+ }
50
+ let kind = '';
51
+ while (!['claude', 'codex', 'demo'].includes(kind)) {
52
+ kind = (await ask(rl, 'Runtime — claude, codex, or demo', 'claude')).toLowerCase();
53
+ }
54
+ const config = {
55
+ serverUrl,
56
+ agentToken,
57
+ runtime: { kind },
58
+ };
59
+ if (kind !== 'demo') {
60
+ let cwd = '';
61
+ while (!cwd) {
62
+ const answer = await ask(rl, 'Working directory the agent runs in (its identity — e.g. a repo checkout)', '.');
63
+ const resolved = path.resolve(expandHome(answer));
64
+ if (fs.existsSync(resolved))
65
+ cwd = resolved;
66
+ else
67
+ console.log(` ${resolved} does not exist — try again`);
68
+ }
69
+ config.runtime.cwd = cwd;
70
+ if (kind === 'claude') {
71
+ // Sane read-only default so a fresh agent can answer questions without
72
+ // being able to mutate anything; widen in the config file deliberately.
73
+ config.runtime.allowedTools = ['Read', 'Grep', 'Glob'];
74
+ }
75
+ }
76
+ const abs = path.resolve(configPath);
77
+ fs.writeFileSync(abs, JSON.stringify(config, null, 2) + '\n', { mode: 0o600 });
78
+ console.log(`\nSaved ${abs} (contains the agent token — keep it private).`);
79
+ console.log('Edit it any time for permissions, event scope, progress mode, etc. (see AGENTS.md).\n');
80
+ return abs;
81
+ }
82
+ finally {
83
+ rl.close();
84
+ }
85
+ }
86
+ //# sourceMappingURL=setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.js","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "flow-agent-bridge",
3
+ "version": "0.2.0",
4
+ "type": "module",
5
+ "description": "Flow agent bridge: joins a Flow workspace as a first-class AI agent and execs a coding-agent CLI (Claude Code, Codex) headlessly per conversation",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/scottpersinger/flow.git",
10
+ "directory": "packages/agent-bridge"
11
+ },
12
+ "keywords": [
13
+ "flow",
14
+ "agent",
15
+ "claude",
16
+ "claude-code",
17
+ "chat-bot",
18
+ "bridge"
19
+ ],
20
+ "engines": {
21
+ "node": ">=20"
22
+ },
23
+ "bin": {
24
+ "flow-agent-bridge": "dist/index.js"
25
+ },
26
+ "files": [
27
+ "dist",
28
+ "README.md"
29
+ ],
30
+ "scripts": {
31
+ "build": "tsc -p tsconfig.json",
32
+ "dev": "tsx src/index.ts",
33
+ "test": "vitest run",
34
+ "prepack": "pnpm build",
35
+ "pack:tarball": "pnpm pack"
36
+ },
37
+ "dependencies": {
38
+ "ws": "^8.18.0"
39
+ },
40
+ "devDependencies": {
41
+ "@flow/shared": "workspace:*",
42
+ "@types/node": "^22.10.0",
43
+ "@types/ws": "^8.5.13",
44
+ "tsx": "^4.19.2",
45
+ "typescript": "^5.6.0",
46
+ "vitest": "^2.1.8"
47
+ }
48
+ }