flow-agent-bridge 0.6.0 → 0.8.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/README.md +28 -8
- package/dist/api.d.ts +7 -11
- package/dist/api.js +11 -30
- package/dist/api.js.map +1 -1
- package/dist/index.js +71 -63
- package/dist/index.js.map +1 -1
- package/dist/setup.d.ts +12 -1
- package/dist/setup.js +78 -63
- package/dist/setup.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,16 +14,36 @@ Flow WS ──> flow-agent-bridge daemon ──spawn──> claude -p --resume <
|
|
|
14
14
|
## Install & run
|
|
15
15
|
|
|
16
16
|
```sh
|
|
17
|
-
|
|
18
|
-
flow-agent-bridge # interactive setup on first run, daemon after
|
|
17
|
+
npx flow-agent-bridge <invite-code> # no install; setup on first run, daemon after
|
|
19
18
|
```
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
`
|
|
20
|
+
Get the `<invite-code>` from Flow: click **Invite your Agent** at the bottom of
|
|
21
|
+
the sidebar and copy the one-time `npx flow-agent-bridge flow-K7P2-9QMR` command it
|
|
22
|
+
shows. The first run asks only **agent name, handle, harness** (claude / codex /
|
|
23
|
+
demo), then redeems the code and joins the workspace **immediately** — no
|
|
24
|
+
approval step. The code is exchanged for a permanent agent token, the config is
|
|
25
|
+
saved to `agent.json` (chmod 600) next to where you ran it, and the daemon
|
|
26
|
+
starts. The agent gets a random avatar the sponsor can change inside Flow.
|
|
27
|
+
Subsequent runs just start the daemon.
|
|
28
|
+
|
|
29
|
+
Every prompt can be pre-answered with a flag, so the whole thing runs
|
|
30
|
+
unattended:
|
|
31
|
+
|
|
32
|
+
```sh
|
|
33
|
+
npx flow-agent-bridge --invite flow-K7P2-9QMR --name RepoBot --handle repobot --harness claude
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
| Flag | Default | Meaning |
|
|
37
|
+
|---|---|---|
|
|
38
|
+
| `--invite` | prompted (or the positional `<invite-code>`) | the one-time invite code |
|
|
39
|
+
| `--name` / `--handle` / `--harness` | prompted | agent name, @handle, runtime |
|
|
40
|
+
| `--server` (or `--host`) | `https://app.flowtoo.org` | Flow server URL |
|
|
41
|
+
| `--token` | — | reuse an existing `flow-agent-token-…` (skips onboarding) |
|
|
42
|
+
| `--description` | none | one-line agent description |
|
|
43
|
+
| `--cwd` | current directory | working directory the agent runs in (its identity) |
|
|
44
|
+
|
|
45
|
+
Already have an agent? `--token flow-agent-token-…` reconnects as it and skips
|
|
46
|
+
onboarding.
|
|
27
47
|
|
|
28
48
|
## What you get
|
|
29
49
|
|
package/dist/api.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AgentLoginResponse,
|
|
1
|
+
import type { AgentLoginResponse, AgentRedeemResponse, ArtifactDTO, ChannelDTO, FileDTO, MessageDTO, MessagePage, UserDTO, WorkspaceDTO, WorkspaceMemberDTO } from '@flow/shared';
|
|
2
2
|
export declare class FlowApiError extends Error {
|
|
3
3
|
readonly status: number;
|
|
4
4
|
readonly code: string;
|
|
@@ -45,22 +45,18 @@ export declare class FlowApi {
|
|
|
45
45
|
}
|
|
46
46
|
/** A fresh agent secret key (the agent's password-equivalent, shown/stored once). */
|
|
47
47
|
export declare function newAgentKey(): string;
|
|
48
|
-
export interface
|
|
48
|
+
export interface RedeemInput {
|
|
49
|
+
code: string;
|
|
49
50
|
username: string;
|
|
50
51
|
key: string;
|
|
51
52
|
name: string;
|
|
52
|
-
sponsorEmail: string;
|
|
53
53
|
description?: string;
|
|
54
|
-
avatarUrl?: string;
|
|
55
54
|
}
|
|
56
|
-
/** Unauthenticated: open a pairing request → pairing code + poll credentials. */
|
|
57
|
-
export declare function startAgentRegistration(serverUrl: string, input: RegisterInput): Promise<AgentRegisterStartResponse>;
|
|
58
|
-
export declare function pollAgentRegistration(serverUrl: string, requestId: string, pollSecret: string): Promise<AgentRegisterPollResponse>;
|
|
59
55
|
/**
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
56
|
+
* Redeem a one-time invite code (the code IS the auth). Returns the agent token
|
|
57
|
+
* synchronously — don't lose it (recovery: `flow-agent-bridge login` with the
|
|
58
|
+
* username + key).
|
|
63
59
|
*/
|
|
64
|
-
export declare function
|
|
60
|
+
export declare function redeemAgentInvite(serverUrl: string, input: RedeemInput): Promise<AgentRedeemResponse>;
|
|
65
61
|
/** Unauthenticated: username + key → fresh agent token (revokes prior tokens). */
|
|
66
62
|
export declare function agentLogin(serverUrl: string, username: string, key: string): Promise<AgentLoginResponse>;
|
package/dist/api.js
CHANGED
|
@@ -147,17 +147,21 @@ export class FlowApi {
|
|
|
147
147
|
return (await res.json());
|
|
148
148
|
}
|
|
149
149
|
}
|
|
150
|
-
// ----
|
|
151
|
-
//
|
|
152
|
-
//
|
|
153
|
-
//
|
|
150
|
+
// ---- Invite-code onboarding (AGENT_MEMBERS.md) ------------------
|
|
151
|
+
// A human member generates a one-time invite code inside Flow; the agent
|
|
152
|
+
// redeems it with its durable credentials (username + secret key) and joins
|
|
153
|
+
// immediately — no sponsor approval. The code carries the sponsor + workspace.
|
|
154
154
|
/** A fresh agent secret key (the agent's password-equivalent, shown/stored once). */
|
|
155
155
|
export function newAgentKey() {
|
|
156
156
|
return `flow-agent-key-${randomBytes(24).toString('base64url')}`;
|
|
157
157
|
}
|
|
158
|
-
/**
|
|
159
|
-
|
|
160
|
-
|
|
158
|
+
/**
|
|
159
|
+
* Redeem a one-time invite code (the code IS the auth). Returns the agent token
|
|
160
|
+
* synchronously — don't lose it (recovery: `flow-agent-bridge login` with the
|
|
161
|
+
* username + key).
|
|
162
|
+
*/
|
|
163
|
+
export async function redeemAgentInvite(serverUrl, input) {
|
|
164
|
+
const res = await fetch(`${serverUrl.replace(/\/+$/, '')}/v1/agents/redeem`, {
|
|
161
165
|
method: 'POST',
|
|
162
166
|
headers: { 'content-type': 'application/json' },
|
|
163
167
|
body: JSON.stringify(input),
|
|
@@ -166,29 +170,6 @@ export async function startAgentRegistration(serverUrl, input) {
|
|
|
166
170
|
await parseError(res);
|
|
167
171
|
return (await res.json());
|
|
168
172
|
}
|
|
169
|
-
export async function pollAgentRegistration(serverUrl, requestId, pollSecret) {
|
|
170
|
-
const res = await fetch(`${serverUrl.replace(/\/+$/, '')}/v1/agents/register/${requestId}`, {
|
|
171
|
-
headers: { authorization: `Bearer ${pollSecret}` },
|
|
172
|
-
});
|
|
173
|
-
if (!res.ok)
|
|
174
|
-
await parseError(res);
|
|
175
|
-
return (await res.json());
|
|
176
|
-
}
|
|
177
|
-
/**
|
|
178
|
-
* Poll until the sponsor resolves the request (approve/deny) or it expires.
|
|
179
|
-
* The approved response carries the agent token exactly once — don't lose it
|
|
180
|
-
* (recovery: `flow-agent-bridge login` with the username + key).
|
|
181
|
-
*/
|
|
182
|
-
export async function waitForApproval(serverUrl, start) {
|
|
183
|
-
for (;;) {
|
|
184
|
-
const res = await pollAgentRegistration(serverUrl, start.requestId, start.pollSecret);
|
|
185
|
-
if (res.status !== 'pending')
|
|
186
|
-
return res;
|
|
187
|
-
if (Date.now() > Date.parse(start.expiresAt))
|
|
188
|
-
return { status: 'expired' };
|
|
189
|
-
await new Promise((r) => setTimeout(r, 2000));
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
173
|
/** Unauthenticated: username + key → fresh agent token (revokes prior tokens). */
|
|
193
174
|
export async function agentLogin(serverUrl, username, key) {
|
|
194
175
|
const res = await fetch(`${serverUrl.replace(/\/+$/, '')}/v1/agents/login`, {
|
package/dist/api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// flow-agent-bridge CLI:
|
|
3
|
-
// flow-agent-bridge
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
3
|
+
// flow-agent-bridge <invite-code> the one command: redeem a one-time
|
|
4
|
+
// invite code (generated in Flow →
|
|
5
|
+
// “Invite your Agent”). Streamlined
|
|
6
|
+
// setup asks name, handle, harness →
|
|
7
|
+
// joins immediately → save, then runs
|
|
8
|
+
// the daemon. Default config: ./agent.json
|
|
9
|
+
// flow-agent-bridge [config.json] if the config exists, run the daemon;
|
|
10
|
+
// if not, run setup (prompts for the
|
|
11
|
+
// invite code) then run.
|
|
12
|
+
// Skip any prompt with a flag:
|
|
13
|
+
// --invite --name --handle --harness
|
|
14
|
+
// --server --token --description --cwd
|
|
8
15
|
// flow-agent-bridge run <config.json> start the daemon (no setup)
|
|
9
|
-
// flow-agent-bridge register --server <url> --sponsor <email> --username <handle>
|
|
10
|
-
// --name <name> [--key <secret>] [--description <text>] [--avatar <url>]
|
|
11
|
-
// (prints a pairing code and blocks until the sponsor approves inside Flow;
|
|
12
|
-
// --key omitted → a fresh key is generated and printed)
|
|
13
16
|
// flow-agent-bridge login --server <url> --username <handle> --key <secret>
|
|
14
17
|
// (mints a fresh agent token, revoking the old one — the lost-agent.json path)
|
|
15
18
|
// flow-agent-bridge mcp-init [config.json]
|
|
@@ -18,16 +21,19 @@
|
|
|
18
21
|
import fs from 'node:fs';
|
|
19
22
|
import { loadConfig } from './config.js';
|
|
20
23
|
import { AgentBridge } from './bridge.js';
|
|
21
|
-
import { agentLogin
|
|
24
|
+
import { agentLogin } from './api.js';
|
|
22
25
|
import { runMcpServer } from './mcp-server.js';
|
|
23
26
|
import { runMcpInit } from './mcp-init.js';
|
|
24
27
|
import { runSetup } from './setup.js';
|
|
28
|
+
/** An invite code positional (`flow-XXXX-XXXX`), told apart from a config path. */
|
|
29
|
+
const INVITE_CODE_RE = /^flow-[A-HJ-NP-Z2-9]{4}-[A-HJ-NP-Z2-9]{4}$/;
|
|
25
30
|
function usage() {
|
|
26
31
|
console.error('usage:\n' +
|
|
32
|
+
' flow-agent-bridge <invite-code> redeem an invite (from Flow) + run — default ./agent.json\n' +
|
|
27
33
|
' flow-agent-bridge [config.json] setup (if missing) + run — default ./agent.json\n' +
|
|
34
|
+
' setup flags (skip a prompt): --invite --name --handle --harness\n' +
|
|
35
|
+
' --server --token --description --cwd\n' +
|
|
28
36
|
' flow-agent-bridge run <config.json>\n' +
|
|
29
|
-
' flow-agent-bridge register --server <url> --sponsor <email> --username <handle> --name <name>\n' +
|
|
30
|
-
' [--key <secret>] [--description <text>] [--avatar <url>]\n' +
|
|
31
37
|
' flow-agent-bridge login --server <url> --username <handle> --key <secret>\n' +
|
|
32
38
|
' flow-agent-bridge mcp-init [config.json] write ./.mcp.json for MCP clients (claude CLI)\n');
|
|
33
39
|
process.exit(2);
|
|
@@ -36,47 +42,47 @@ function flag(args, name) {
|
|
|
36
42
|
const i = args.indexOf(`--${name}`);
|
|
37
43
|
return i >= 0 ? args[i + 1] : undefined;
|
|
38
44
|
}
|
|
45
|
+
/** Non-flag tokens (flags all take a value, so skip `--x val` pairs). */
|
|
46
|
+
function allPositionals(args) {
|
|
47
|
+
const out = [];
|
|
48
|
+
for (let i = 0; i < args.length; i++) {
|
|
49
|
+
const a = args[i];
|
|
50
|
+
if (a.startsWith('--'))
|
|
51
|
+
i++; // skip the flag's value too
|
|
52
|
+
else
|
|
53
|
+
out.push(a);
|
|
54
|
+
}
|
|
55
|
+
return out;
|
|
56
|
+
}
|
|
57
|
+
function parseSetupOptions(args, invite) {
|
|
58
|
+
return {
|
|
59
|
+
serverUrl: flag(args, 'server') ?? flag(args, 'host'),
|
|
60
|
+
token: flag(args, 'token'),
|
|
61
|
+
invite: invite ?? flag(args, 'invite'),
|
|
62
|
+
name: flag(args, 'name'),
|
|
63
|
+
username: flag(args, 'username') ?? flag(args, 'handle'),
|
|
64
|
+
harness: flag(args, 'harness') ?? flag(args, 'runtime'),
|
|
65
|
+
description: flag(args, 'description'),
|
|
66
|
+
cwd: flag(args, 'cwd'),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
async function startDaemon(configPath) {
|
|
70
|
+
const cfg = loadConfig(configPath);
|
|
71
|
+
const bridge = new AgentBridge(cfg);
|
|
72
|
+
await bridge.start();
|
|
73
|
+
const shutdown = () => {
|
|
74
|
+
bridge.stop();
|
|
75
|
+
setTimeout(() => process.exit(0), 200);
|
|
76
|
+
};
|
|
77
|
+
process.on('SIGINT', shutdown);
|
|
78
|
+
process.on('SIGTERM', shutdown);
|
|
79
|
+
}
|
|
39
80
|
async function main() {
|
|
40
81
|
const [cmd, ...rest] = process.argv.slice(2);
|
|
41
82
|
if (cmd === 'mcp')
|
|
42
83
|
return runMcpServer();
|
|
43
84
|
if (cmd === 'mcp-init')
|
|
44
85
|
return runMcpInit(rest[0] ?? 'agent.json');
|
|
45
|
-
if (cmd === 'register') {
|
|
46
|
-
const server = flag(rest, 'server');
|
|
47
|
-
const sponsor = flag(rest, 'sponsor');
|
|
48
|
-
const username = flag(rest, 'username');
|
|
49
|
-
const name = flag(rest, 'name');
|
|
50
|
-
if (!server || !sponsor || !username || !name)
|
|
51
|
-
usage();
|
|
52
|
-
const key = flag(rest, 'key') ?? newAgentKey();
|
|
53
|
-
const generatedKey = !flag(rest, 'key');
|
|
54
|
-
const start = await startAgentRegistration(server, {
|
|
55
|
-
username,
|
|
56
|
-
key,
|
|
57
|
-
name,
|
|
58
|
-
sponsorEmail: sponsor,
|
|
59
|
-
...(flag(rest, 'description') ? { description: flag(rest, 'description') } : {}),
|
|
60
|
-
...(flag(rest, 'avatar') ? { avatarUrl: flag(rest, 'avatar') } : {}),
|
|
61
|
-
});
|
|
62
|
-
console.log(`pairing code: ${start.code}`);
|
|
63
|
-
console.log(`waiting for ${sponsor} to approve inside Flow (they must see the SAME code)…`);
|
|
64
|
-
const res = await waitForApproval(server, start);
|
|
65
|
-
if (res.status !== 'approved' || !res.agentToken) {
|
|
66
|
-
throw new Error(res.status === 'denied' ? 'the sponsor denied the request' : 'the request expired — re-run register');
|
|
67
|
-
}
|
|
68
|
-
console.log(`registered ${res.user.displayName} <@${res.user.id}> in workspace "${res.workspace.name}"`);
|
|
69
|
-
console.log('');
|
|
70
|
-
console.log('agent token (put it in your bridge config as "agentToken"):');
|
|
71
|
-
console.log(` ${res.agentToken}`);
|
|
72
|
-
if (generatedKey) {
|
|
73
|
-
console.log('');
|
|
74
|
-
console.log('agent key (shown ONCE — with the username, this recovers a lost token via `login`):');
|
|
75
|
-
console.log(` username: ${username}`);
|
|
76
|
-
console.log(` key: ${key}`);
|
|
77
|
-
}
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
86
|
if (cmd === 'login') {
|
|
81
87
|
const server = flag(rest, 'server');
|
|
82
88
|
const username = flag(rest, 'username');
|
|
@@ -91,22 +97,24 @@ async function main() {
|
|
|
91
97
|
}
|
|
92
98
|
if (cmd === 'help' || cmd === '--help' || cmd === '-h')
|
|
93
99
|
usage();
|
|
94
|
-
// `run <config>`
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
100
|
+
// `run <config>` starts the daemon on an existing config — no setup.
|
|
101
|
+
if (cmd === 'run') {
|
|
102
|
+
const configPath = rest[0];
|
|
103
|
+
if (!configPath)
|
|
104
|
+
usage();
|
|
105
|
+
return startDaemon(configPath);
|
|
106
|
+
}
|
|
107
|
+
// Default path: setup (if the config is missing) + run. A positional that
|
|
108
|
+
// looks like an invite code (`flow-XXXX-XXXX`) is the invite; any other
|
|
109
|
+
// positional is the config path (default ./agent.json). Everything else is a
|
|
110
|
+
// setup flag, so `npx flow-agent-bridge flow-K7P2-9QMR --harness codex` works bare.
|
|
111
|
+
const args = cmd === undefined ? [] : [cmd, ...rest];
|
|
112
|
+
const positionals = allPositionals(args);
|
|
113
|
+
const invite = positionals.find((p) => INVITE_CODE_RE.test(p));
|
|
114
|
+
const configPath = positionals.find((p) => p !== invite) ?? 'agent.json';
|
|
115
|
+
if (!fs.existsSync(configPath))
|
|
116
|
+
await runSetup(configPath, parseSetupOptions(args, invite));
|
|
117
|
+
return startDaemon(configPath);
|
|
110
118
|
}
|
|
111
119
|
main().catch((err) => {
|
|
112
120
|
console.error(`fatal: ${err.message}`);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,yBAAyB;AACzB
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/setup.d.ts
CHANGED
|
@@ -1 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
/** Optional values that skip their prompt when supplied as CLI flags. */
|
|
2
|
+
export interface SetupOptions {
|
|
3
|
+
serverUrl?: string | undefined;
|
|
4
|
+
token?: string | undefined;
|
|
5
|
+
invite?: string | undefined;
|
|
6
|
+
name?: string | undefined;
|
|
7
|
+
username?: string | undefined;
|
|
8
|
+
harness?: string | undefined;
|
|
9
|
+
description?: string | undefined;
|
|
10
|
+
cwd?: string | undefined;
|
|
11
|
+
}
|
|
12
|
+
export declare function runSetup(configPath: string, opts?: SetupOptions): Promise<string>;
|
package/dist/setup.js
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
|
-
// Interactive first-run setup (AGENT_MEMBERS.md):
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
1
|
+
// Interactive first-run setup (AGENT_MEMBERS.md): onboard the agent with a
|
|
2
|
+
// one-time invite code and hand back a ready-to-run agent.json. The streamlined
|
|
3
|
+
// flow (phase 15) asks only what a person must decide — the invite code (usually
|
|
4
|
+
// passed as the positional arg), then agent name, handle, harness — and redeems
|
|
5
|
+
// the code to join immediately (no sponsor approval; the code carries the
|
|
6
|
+
// sponsor + workspace). Everything else (server URL, an existing token to
|
|
7
|
+
// reuse, a description, the working directory) has a sensible default and is
|
|
8
|
+
// overridable with a CLI flag. Advanced knobs (permissionMode, allowedTools,
|
|
9
|
+
// eventScope, …) are edited in the saved file.
|
|
7
10
|
import fs from 'node:fs';
|
|
8
11
|
import path from 'node:path';
|
|
9
12
|
import readline from 'node:readline/promises';
|
|
10
|
-
import { FlowApi, newAgentKey,
|
|
13
|
+
import { FlowApi, newAgentKey, redeemAgentInvite } from './api.js';
|
|
11
14
|
import { expandHome } from './config.js';
|
|
15
|
+
const HARNESSES = ['claude', 'codex', 'demo'];
|
|
16
|
+
const INVITE_CODE_RE = /^flow-[A-HJ-NP-Z2-9]{4}-[A-HJ-NP-Z2-9]{4}$/;
|
|
12
17
|
async function ask(rl, q, def) {
|
|
13
18
|
const suffix = def ? ` [${def}]` : '';
|
|
14
19
|
const answer = (await rl.question(`${q}${suffix}: `)).trim();
|
|
@@ -22,65 +27,79 @@ function slugify(name) {
|
|
|
22
27
|
.replace(/^[-._]+|[-._]+$/g, '')
|
|
23
28
|
.slice(0, 32);
|
|
24
29
|
}
|
|
25
|
-
export async function runSetup(configPath) {
|
|
26
|
-
|
|
27
|
-
|
|
30
|
+
export async function runSetup(configPath, opts = {}) {
|
|
31
|
+
const serverUrl = (opts.serverUrl ?? process.env.FLOW_SERVER_URL ?? 'https://app.flowtoo.org').replace(/\/+$/, '');
|
|
32
|
+
const rl = process.stdin.isTTY ? readline.createInterface({ input: process.stdin, output: process.stdout }) : null;
|
|
33
|
+
// A required value: take the flag if given (validated), otherwise prompt.
|
|
34
|
+
// Without a TTY and without the flag there is no way to obtain it.
|
|
35
|
+
async function required(provided, label, opt = {}) {
|
|
36
|
+
const norm = opt.normalize ?? ((s) => s);
|
|
37
|
+
if (provided !== undefined) {
|
|
38
|
+
const v = norm(provided);
|
|
39
|
+
if (opt.validate && !opt.validate(v))
|
|
40
|
+
throw new Error(`invalid value for ${label}: "${provided}"`);
|
|
41
|
+
return v;
|
|
42
|
+
}
|
|
43
|
+
if (!rl)
|
|
44
|
+
throw new Error(`no config at ${configPath} and stdin is not a TTY — pass the setup flags or run interactively`);
|
|
45
|
+
let v = '';
|
|
46
|
+
do {
|
|
47
|
+
v = norm(await ask(rl, label, opt.def));
|
|
48
|
+
} while (!v || (opt.validate ? !opt.validate(v) : false));
|
|
49
|
+
return v;
|
|
28
50
|
}
|
|
29
|
-
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
30
51
|
try {
|
|
31
|
-
console.log('
|
|
32
|
-
const serverUrl = (await ask(rl, 'Flow server URL', process.env.FLOW_SERVER_URL ?? 'https://app.flowtoo.org')).replace(/\/+$/, '');
|
|
33
|
-
const existing = await ask(rl, 'Existing agent token (flow-agent-token-…) to reuse — or press enter to register');
|
|
52
|
+
console.log('Setting up your Flow agent.\n');
|
|
34
53
|
let agentToken;
|
|
35
54
|
let agentUsername;
|
|
36
55
|
let agentKey;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
56
|
+
let kind;
|
|
57
|
+
if (opts.token) {
|
|
58
|
+
// Reuse an existing agent: validate the token and skip registration.
|
|
59
|
+
console.log('Verifying the agent token…');
|
|
60
|
+
const me = await new FlowApi(serverUrl, opts.token).me();
|
|
61
|
+
console.log(`Reconnecting as existing agent ${me.displayName} <@${me.id}>.\n`);
|
|
62
|
+
agentToken = opts.token;
|
|
63
|
+
kind = await required(opts.harness, 'Agent harness — claude, codex, or demo', {
|
|
64
|
+
def: 'claude',
|
|
65
|
+
normalize: (s) => s.toLowerCase(),
|
|
66
|
+
validate: (s) => HARNESSES.includes(s),
|
|
67
|
+
});
|
|
43
68
|
}
|
|
44
69
|
else {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
70
|
+
// Redeem a one-time invite code (phase 15). The code (usually the
|
|
71
|
+
// positional arg) carries the sponsor + workspace; ask only name, handle,
|
|
72
|
+
// and harness, then join immediately — no approval.
|
|
73
|
+
const code = await required(opts.invite, 'Invite code (generate one in Flow → “Invite your Agent”)', {
|
|
74
|
+
normalize: (s) => s.trim(),
|
|
75
|
+
validate: (s) => INVITE_CODE_RE.test(s),
|
|
76
|
+
});
|
|
77
|
+
const name = await required(opts.name, 'Agent name (shown in Flow, e.g. RepoBot)');
|
|
78
|
+
const username = await required(opts.username, 'Handle (the agent’s @username — its durable login)', {
|
|
79
|
+
def: slugify(name),
|
|
80
|
+
normalize: (s) => s.toLowerCase(),
|
|
81
|
+
validate: (s) => /^[a-z0-9][a-z0-9._-]{2,31}$/.test(s),
|
|
82
|
+
});
|
|
83
|
+
kind = await required(opts.harness, 'Agent harness — claude, codex, or demo', {
|
|
84
|
+
def: 'claude',
|
|
85
|
+
normalize: (s) => s.toLowerCase(),
|
|
86
|
+
validate: (s) => HARNESSES.includes(s),
|
|
87
|
+
});
|
|
88
|
+
const description = opts.description ?? '';
|
|
57
89
|
const key = newAgentKey();
|
|
58
|
-
console.log('\
|
|
59
|
-
const
|
|
90
|
+
console.log('\nJoining the workspace…');
|
|
91
|
+
const res = await redeemAgentInvite(serverUrl, {
|
|
92
|
+
code,
|
|
60
93
|
username,
|
|
61
94
|
key,
|
|
62
95
|
name,
|
|
63
|
-
sponsorEmail,
|
|
64
96
|
...(description ? { description } : {}),
|
|
65
97
|
});
|
|
66
|
-
console.log(
|
|
67
|
-
console.log(` pairing code: ${start.code}`);
|
|
68
|
-
console.log('');
|
|
69
|
-
console.log(`Now approve this request inside Flow (as ${sponsorEmail}) — a prompt is waiting there.`);
|
|
70
|
-
console.log('Only approve if it shows the SAME code. Waiting (expires in 10 minutes)…');
|
|
71
|
-
const res = await waitForApproval(serverUrl, start);
|
|
72
|
-
if (res.status !== 'approved' || !res.agentToken) {
|
|
73
|
-
throw new Error(res.status === 'denied' ? 'the sponsor denied the request' : 'the request expired — run setup again');
|
|
74
|
-
}
|
|
75
|
-
console.log(`\napproved! registered ${res.user.displayName} <@${res.user.id}> in workspace "${res.workspace.name}"\n`);
|
|
98
|
+
console.log(`\njoined as ${res.user.displayName} <@${res.user.id}> in workspace "${res.workspace.name}"\n`);
|
|
76
99
|
agentToken = res.agentToken;
|
|
77
100
|
agentUsername = username;
|
|
78
101
|
agentKey = key;
|
|
79
102
|
}
|
|
80
|
-
let kind = '';
|
|
81
|
-
while (!['claude', 'codex', 'demo'].includes(kind)) {
|
|
82
|
-
kind = (await ask(rl, 'Runtime — claude, codex, or demo', 'claude')).toLowerCase();
|
|
83
|
-
}
|
|
84
103
|
const config = {
|
|
85
104
|
serverUrl,
|
|
86
105
|
agentToken,
|
|
@@ -91,28 +110,24 @@ export async function runSetup(configPath) {
|
|
|
91
110
|
runtime: { kind },
|
|
92
111
|
};
|
|
93
112
|
if (kind !== 'demo') {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
cwd = resolved;
|
|
100
|
-
else
|
|
101
|
-
console.log(` ${resolved} does not exist — try again`);
|
|
102
|
-
}
|
|
113
|
+
// Optional; defaults to where `npx flow-agent-bridge` was run (usually the
|
|
114
|
+
// repo checkout that IS the agent's identity). --cwd overrides.
|
|
115
|
+
const cwd = path.resolve(expandHome(opts.cwd ?? '.'));
|
|
116
|
+
if (!fs.existsSync(cwd))
|
|
117
|
+
throw new Error(`working directory does not exist: ${cwd} (pass --cwd)`);
|
|
103
118
|
config.runtime.cwd = cwd;
|
|
104
119
|
// No allowedTools written: the default is full permissions in the cwd
|
|
105
|
-
// (operator ruling) — add allowedTools/permissionMode to the saved
|
|
106
|
-
//
|
|
120
|
+
// (operator ruling) — add allowedTools/permissionMode to the saved config
|
|
121
|
+
// to scope the agent down.
|
|
107
122
|
}
|
|
108
123
|
const abs = path.resolve(configPath);
|
|
109
124
|
fs.writeFileSync(abs, JSON.stringify(config, null, 2) + '\n', { mode: 0o600 });
|
|
110
|
-
console.log(
|
|
111
|
-
console.log('
|
|
125
|
+
console.log(`Saved ${abs} (contains the agent token and key — keep it private).`);
|
|
126
|
+
console.log('Starting the agent — edit the config any time for permissions, scope, etc. (see AGENT_MEMBERS.md).\n');
|
|
112
127
|
return abs;
|
|
113
128
|
}
|
|
114
129
|
finally {
|
|
115
|
-
rl
|
|
130
|
+
rl?.close();
|
|
116
131
|
}
|
|
117
132
|
}
|
|
118
133
|
//# sourceMappingURL=setup.js.map
|
package/dist/setup.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "flow-agent-bridge",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"type": "module",
|
|
5
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
6
|
"license": "MIT",
|