@vercel/board 0.23.0 → 0.24.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 +14 -19
- package/dist/{a2-NMEbIKNZ.mjs → a2-BxfKZFvJ.mjs} +1 -1
- package/dist/{backend-CWmd4UH-.d.mts → backend-D0GDYiFr.d.mts} +1 -1
- package/dist/backend-a2.d.mts +1 -1
- package/dist/backend-a2.mjs +1 -1
- package/dist/{backend-http-BfWQfvqB.d.mts → backend-http-Dvq2p__1.d.mts} +1 -1
- package/dist/{backend-http-DQUsVgML.mjs → backend-http-rfiG-AKP.mjs} +1 -1
- package/dist/{backend-http-D_rjJVmW.mjs → backend-http-tGUo0e8j.mjs} +3 -3
- package/dist/backend-http.d.mts +1 -1
- package/dist/backend-http.mjs +1 -1
- package/dist/backend-http.node.d.mts +2 -2
- package/dist/backend-http.node.mjs +1 -1
- package/dist/{backend-vercel-CYOqtLPc.d.mts → backend-vercel-01QKDobk.d.mts} +1 -1
- package/dist/{backend-vercel-BSuIfOyF.mjs → backend-vercel-C3zuxmcD.mjs} +2 -2
- package/dist/{backend-vercel-BWVAihZC.mjs → backend-vercel-DM5PyMc2.mjs} +2 -2
- package/dist/backend-vercel.d.mts +1 -1
- package/dist/backend-vercel.mjs +1 -1
- package/dist/backend-vercel.node.d.mts +1 -1
- package/dist/backend-vercel.node.mjs +1 -1
- package/dist/cli-commands.mjs +1 -1
- package/dist/cli-embedded.d.mts +4 -4
- package/dist/cli-embedded.mjs +3 -3
- package/dist/cli.mjs +43 -36
- package/dist/{commands-D_ODblQY.mjs → commands-BtL4jFq8.mjs} +0 -30
- package/dist/conformance.d.mts +1 -1
- package/dist/{exports-ggfE9jNv.d.mts → exports-87_yESpp.d.mts} +1 -1
- package/dist/{exports-DAVHon9y.mjs → exports-Bw81oDDl.mjs} +1 -1
- package/dist/{index-DsMPCv_K.d.mts → index-B_hWanKF.d.mts} +3 -3
- package/dist/index.d.mts +2 -2
- package/dist/{index.default-TBybqjGV.mjs → index.default-B6oPlvEa.mjs} +1 -1
- package/dist/index.mjs +2 -2
- package/dist/index.node.d.mts +2 -2
- package/dist/index.node.mjs +1 -1
- package/dist/inspect/app.js +1 -1
- package/dist/{main-B5BCEQ0l.mjs → main-CzWvRy91.mjs} +21 -62
- package/dist/{node-BeKPcokJ.mjs → node-CirFYqw0.mjs} +7 -30
- package/dist/{serve-BC218-NQ.mjs → serve-DHyA-6FR.mjs} +3 -3
- package/dist/{server-BxUruJxv.mjs → server-Cp2oIQOj.mjs} +3 -3
- package/dist/{watchers-hash-DYu8WWXj.mjs → watchers-hash-C_1jGA53.mjs} +2 -2
- package/docs/01-board/01-mounting.md +4 -5
- package/docs/01-quickstart.md +8 -8
- package/docs/03-guides/01-coding-agents.md +17 -20
- package/docs/03-guides/02-inspector.md +1 -1
- package/docs/04-reference/01-cli.md +17 -39
- package/docs/04-reference/02-board.md +2 -4
- package/docs/index.md +2 -3
- package/package.json +1 -1
|
@@ -10,15 +10,6 @@ import { decodeJwt } from "jose";
|
|
|
10
10
|
import { exchangeVercelOidcToken, getVercelOidcToken, getVercelToken } from "@vercel/oidc";
|
|
11
11
|
//#region src/client/node.ts
|
|
12
12
|
const configDir = () => join(process.env.XDG_CONFIG_HOME || join(homedir(), ".config"), "board");
|
|
13
|
-
/** The board saved by `board use <url>`. */
|
|
14
|
-
function savedUrl() {
|
|
15
|
-
try {
|
|
16
|
-
const { url } = JSON.parse(readFileSync(join(configDir(), "config.json"), "utf8"));
|
|
17
|
-
return url;
|
|
18
|
-
} catch {
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
13
|
/**
|
|
23
14
|
* A Git checkout's root: `.git` is a directory with a `HEAD`, or a worktree's
|
|
24
15
|
* `gitdir:` file. A stray empty `.git` (say, in `~` or `/tmp`) isn't one.
|
|
@@ -32,10 +23,11 @@ function isCheckout(directory) {
|
|
|
32
23
|
return false;
|
|
33
24
|
}
|
|
34
25
|
}
|
|
26
|
+
/** The project `cwd` is in: its Git checkout's root, or `cwd` outside one. */
|
|
35
27
|
function projectDir(cwd = process.cwd()) {
|
|
36
28
|
let directory = resolve(cwd);
|
|
37
29
|
while (true) {
|
|
38
|
-
if (
|
|
30
|
+
if (isCheckout(directory)) return directory;
|
|
39
31
|
const parent = dirname(directory);
|
|
40
32
|
if (parent === directory) return resolve(cwd);
|
|
41
33
|
directory = parent;
|
|
@@ -43,7 +35,7 @@ function projectDir(cwd = process.cwd()) {
|
|
|
43
35
|
}
|
|
44
36
|
/**
|
|
45
37
|
* The nearest Vercel project link (`.vercel/project.json`), searching up from the current
|
|
46
|
-
* directory to a Git checkout's root
|
|
38
|
+
* directory to a Git checkout's root. Null when there's none.
|
|
47
39
|
*/
|
|
48
40
|
function vercelProjectFile(cwd = process.cwd()) {
|
|
49
41
|
let directory = resolve(cwd);
|
|
@@ -55,21 +47,6 @@ function vercelProjectFile(cwd = process.cwd()) {
|
|
|
55
47
|
directory = parent;
|
|
56
48
|
}
|
|
57
49
|
}
|
|
58
|
-
function projectUrl() {
|
|
59
|
-
const path = join(projectDir(), ".board", "config.json");
|
|
60
|
-
let contents;
|
|
61
|
-
try {
|
|
62
|
-
contents = readFileSync(path, "utf8");
|
|
63
|
-
} catch (error) {
|
|
64
|
-
if (error.code === "ENOENT") return void 0;
|
|
65
|
-
throw error;
|
|
66
|
-
}
|
|
67
|
-
try {
|
|
68
|
-
const { url } = JSON.parse(contents);
|
|
69
|
-
if (typeof url === "string" && ["http:", "https:"].includes(new URL(url).protocol)) return url;
|
|
70
|
-
} catch {}
|
|
71
|
-
throw new BoardError("invalid_config", `invalid board link at ${path}: expected an http(s) url`, 0);
|
|
72
|
-
}
|
|
73
50
|
const LOOPBACK = /* @__PURE__ */ new Set([
|
|
74
51
|
"127.0.0.1",
|
|
75
52
|
"localhost",
|
|
@@ -278,10 +255,10 @@ async function githubActionsToken(audience) {
|
|
|
278
255
|
if (!response.ok) throw new BoardError("no_token", `GitHub Actions refused an OIDC token (${response.status}): does the job have \`permissions: id-token: write\`?`, 0);
|
|
279
256
|
return (await response.json()).value;
|
|
280
257
|
}
|
|
281
|
-
/** The board the environment points at: `BOARD_URL
|
|
258
|
+
/** The board the environment points at: `BOARD_URL`. */
|
|
282
259
|
function boardUrl() {
|
|
283
|
-
const url =
|
|
284
|
-
if (!url) throw new BoardError("no_board", "no board URL:
|
|
260
|
+
const url = process.env.BOARD_URL?.replace(/\/+$/, "");
|
|
261
|
+
if (!url) throw new BoardError("no_board", "no board URL: set BOARD_URL", 0);
|
|
285
262
|
return url;
|
|
286
263
|
}
|
|
287
264
|
/**
|
|
@@ -623,4 +600,4 @@ const vercelCliApi = async (method, path) => {
|
|
|
623
600
|
}
|
|
624
601
|
};
|
|
625
602
|
//#endregion
|
|
626
|
-
export {
|
|
603
|
+
export { projectDir as a, localTokenFile as i, connect as n, vercelLogin as o, environmentProfile as r, vercelProjectFile as s, boardUrl as t };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as board } from "./server-
|
|
1
|
+
import { i as localTokenFile } from "./node-CirFYqw0.mjs";
|
|
2
|
+
import { t as board } from "./server-Cp2oIQOj.mjs";
|
|
3
3
|
import { t as oidcTokens } from "./tokens-DUXaXwOj.mjs";
|
|
4
|
-
import { n as fsBlob, t as a2 } from "./a2-
|
|
4
|
+
import { n as fsBlob, t as a2 } from "./a2-BxfKZFvJ.mjs";
|
|
5
5
|
import { t as localScheduler } from "./local-DhkrAqPP.mjs";
|
|
6
6
|
import { mkdir, rm, writeFile } from "node:fs/promises";
|
|
7
7
|
import { userInfo } from "node:os";
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { t as createBoard } from "./exports-
|
|
2
|
-
import { t as http } from "./backend-http-
|
|
1
|
+
import { t as createBoard } from "./exports-Bw81oDDl.mjs";
|
|
2
|
+
import { t as http } from "./backend-http-tGUo0e8j.mjs";
|
|
3
3
|
//#region src/server/index.ts
|
|
4
4
|
/**
|
|
5
5
|
* The handle on a board. With a `backend`, the board lives there: `a2()` keeps it in this
|
|
6
6
|
* deployment, `http(url)` uses another. Without one, it's `http()` to the board the environment
|
|
7
|
-
* points at: `BOARD_URL
|
|
7
|
+
* points at: `BOARD_URL`.
|
|
8
8
|
*/
|
|
9
9
|
function board(options = {}) {
|
|
10
10
|
return createBoard(options, {
|
|
@@ -2,7 +2,7 @@ import { n as DIRECT_UPLOAD_BYTES_MAX, t as ATTACHMENT_BYTES_MAX } from "./files
|
|
|
2
2
|
import { S as storable, a as AttachmentId, c as ChannelPath, d as LabelKey, g as MessageText, l as Emoji, m as MESSAGE_TEXT_MAX, n as ActorId, p as Labels, x as platformAvatar } from "./schemas-Be08nyfW.mjs";
|
|
3
3
|
import { a as Link, i as ExternalTarget, n as ExternalEvent, o as Origin, t as ExternalAuthor } from "./external-BV_cUncs.mjs";
|
|
4
4
|
import { r as badRequest, t as HttpError } from "./errors-CQ-fwxM3.mjs";
|
|
5
|
-
import { o as options } from "./commands-
|
|
5
|
+
import { o as options } from "./commands-BtL4jFq8.mjs";
|
|
6
6
|
import { z } from "zod";
|
|
7
7
|
//#region src/api/routes.ts
|
|
8
8
|
/**
|
|
@@ -662,7 +662,7 @@ const routes = {
|
|
|
662
662
|
const SYNC = "@sync";
|
|
663
663
|
//#endregion
|
|
664
664
|
//#region src/version.ts
|
|
665
|
-
const VERSION = "0.
|
|
665
|
+
const VERSION = "0.24.0";
|
|
666
666
|
//#endregion
|
|
667
667
|
//#region src/server/routing.ts
|
|
668
668
|
/** board()'s own routes: the files it serves, and sync's, which run where board() does. */
|
|
@@ -19,7 +19,7 @@ export const GET = team.fetch, POST = team.fetch
|
|
|
19
19
|
```
|
|
20
20
|
|
|
21
21
|
That's a board. It answers at `/api/board`, and the CLI points at it with
|
|
22
|
-
`BOARD_URL` or
|
|
22
|
+
`BOARD_URL` or `--url`. `fetch` is its one handler; Next.js wants it under
|
|
23
23
|
each method's name. `a2()` keeps the board in the store you give it, or in
|
|
24
24
|
SQLite at `.a2/dev.db` without one, which a serverless function can't write:
|
|
25
25
|
see [Without a store](#without-a-store). Call `board()` once, at module scope.
|
|
@@ -63,7 +63,7 @@ A board on `http()` keeps nothing:
|
|
|
63
63
|
- **It answers only wake-ups and webhooks,** and the sign-in routes of the
|
|
64
64
|
sync it runs. Anything else, discovery included, answers 404 `<its URL>
|
|
65
65
|
answers only wake-ups and webhooks`, and verifies nothing. People and the
|
|
66
|
-
CLI use the other board
|
|
66
|
+
CLI use the other board, by its URL. With an
|
|
67
67
|
`access` of its own, it serves its callers too, as a gateway: see
|
|
68
68
|
[A board on `http()`](./09-access.md#a-board-on-http).
|
|
69
69
|
- **Its handle writes there as this deployment:**
|
|
@@ -125,7 +125,7 @@ with credentials it recognizes:
|
|
|
125
125
|
| `fetch` | How requests reach it, credentials included. In Node it defaults to what `vb` uses: a token whose audience is the other board's URL, from `BOARD_TOKEN`, `vb serve`'s, GitHub Actions, the Vercel runtime (a deployment's OIDC token), then `vercel login`, through Deployment Protection, with your handle (`BOARD_HANDLE`, then your Vercel username). In a browser it's `fetch`, sending the page's own session |
|
|
126
126
|
|
|
127
127
|
In Node, `http()` without a `url` uses the board the environment points at:
|
|
128
|
-
`BOARD_URL
|
|
128
|
+
`BOARD_URL`.
|
|
129
129
|
|
|
130
130
|
Set `url` when the board sits behind a proxy or rewrite that changes the
|
|
131
131
|
origin it sees, so the audience it checks matches the one clients mint for.
|
|
@@ -335,8 +335,7 @@ const team = board()
|
|
|
335
335
|
await team.post('deploys', 'www@a1b2c3 is live')
|
|
336
336
|
```
|
|
337
337
|
|
|
338
|
-
In Node it finds that board
|
|
339
|
-
link (`vb link`, `vb serve`), then `vb use`'s. It acts as whoever its `fetch`'s
|
|
338
|
+
In Node it finds that board in `BOARD_URL`, as `vb` does. It acts as whoever its `fetch`'s
|
|
340
339
|
credentials say, and the default one sends a token from `BOARD_TOKEN`, a local
|
|
341
340
|
board's token file (`vb serve`), GitHub Actions OIDC, Vercel OIDC, then your
|
|
342
341
|
`vercel login`. Its profile is `BOARD_AS`, or the coding agent it runs in,
|
package/docs/01-quickstart.md
CHANGED
|
@@ -49,11 +49,10 @@ it is from `.vercel/project.json`, which `vercel link` writes. See
|
|
|
49
49
|
npm run dev
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
-
Then, in another terminal,
|
|
53
|
-
are:
|
|
52
|
+
Then, in another terminal, point the CLI at the board and check who you are:
|
|
54
53
|
|
|
55
54
|
```bash
|
|
56
|
-
|
|
55
|
+
export BOARD_URL=http://localhost:3000/api/board
|
|
57
56
|
npx vb whoami
|
|
58
57
|
```
|
|
59
58
|
|
|
@@ -64,8 +63,9 @@ source vercel login
|
|
|
64
63
|
token expires in 11h 59m
|
|
65
64
|
```
|
|
66
65
|
|
|
67
|
-
|
|
68
|
-
|
|
66
|
+
`BOARD_URL` (or `--url` on one command) says which board; without either,
|
|
67
|
+
in a Vercel project, the CLI talks to your team's board in Vercel's API
|
|
68
|
+
instead. There's no login command: the CLI mints a token from your Vercel
|
|
69
69
|
CLI login, for this board only.
|
|
70
70
|
|
|
71
71
|
> [!NOTE]
|
|
@@ -178,11 +178,11 @@ psql "$DATABASE_URL" -f node_modules/@vercel/board/sql/postgres/schema.sql
|
|
|
178
178
|
|
|
179
179
|
[Database](./01-board/02-database.md#postgres) shows how to apply it on every
|
|
180
180
|
build instead, and how to keep the board on [Redis](./01-board/02-database.md#redis),
|
|
181
|
-
which needs nothing applied. Deploy, then
|
|
181
|
+
which needs nothing applied. Deploy, then point the CLI at the deployed board instead:
|
|
182
182
|
|
|
183
183
|
```bash
|
|
184
184
|
vercel deploy --prod
|
|
185
|
-
|
|
185
|
+
export BOARD_URL=https://your-app.vercel.app/api/board
|
|
186
186
|
```
|
|
187
187
|
|
|
188
188
|
[Mounting](./01-board/01-mounting.md#production-checklist) covers the rest of
|
|
@@ -193,4 +193,4 @@ messages send, a blob store for attachments, and Vercel Deployment Protection.
|
|
|
193
193
|
|
|
194
194
|
- [Sync a Slack channel](./02-sync/01-overview.md) so a thread reaches the people who live there.
|
|
195
195
|
- [Run a watcher](./01-board/06-watchers.md) to triage new threads on the board itself.
|
|
196
|
-
- [
|
|
196
|
+
- [Set up your coding agents](./03-guides/01-coding-agents.md) so they post what they did.
|
|
@@ -1,42 +1,39 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Coding agents
|
|
3
|
-
description:
|
|
3
|
+
description: Point the CLI at your team's board, give your agents the skill, and have them share what they did after every turn.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
##
|
|
6
|
+
## Point it at your board
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
# in a terminal, anywhere in the repo:
|
|
10
|
-
npx @vercel/board link https://team.example/api/board
|
|
11
|
-
```
|
|
8
|
+
Set `BOARD_URL` where you and your agents run, in your shell's profile, say:
|
|
12
9
|
|
|
13
|
-
```
|
|
14
|
-
|
|
10
|
+
```bash
|
|
11
|
+
export BOARD_URL=https://team.example/api/board
|
|
15
12
|
```
|
|
16
13
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
Or pass `--url <url>` to one command. In a Vercel project with neither, the
|
|
15
|
+
CLI talks to your team's board in Vercel's API: `vercel link` already says
|
|
16
|
+
which team.
|
|
20
17
|
|
|
21
|
-
- **The
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
- **The repo never picks a host.** A checkout you clone can't send your token
|
|
19
|
+
anywhere: a project's `.vercel/project.json` names only its team, in
|
|
20
|
+
Vercel's API.
|
|
21
|
+
- **Credentials stay with you.** You sign in with your own `vercel login`,
|
|
24
22
|
and tokens are cached per user. Access to the board is access to its Vercel
|
|
25
23
|
project: an account without it gets
|
|
26
24
|
`error: your Vercel account can't access this board's project: ask for access to it`.
|
|
27
|
-
- **The
|
|
25
|
+
- **The URL picks a board, not a channel.** Agents choose channels per task.
|
|
28
26
|
|
|
29
27
|
Every command finds the board in this order, and the first match wins:
|
|
30
28
|
|
|
31
29
|
| Where | Set with |
|
|
32
30
|
| --- | --- |
|
|
33
31
|
| An explicit URL | `--url <url>` |
|
|
32
|
+
| A team's board | `--scope <team>` |
|
|
34
33
|
| The environment | `BOARD_URL` |
|
|
35
|
-
| The project
|
|
36
|
-
| Your default board | `vb use <url>` (saved in `~/.config/board/config.json`) |
|
|
34
|
+
| The Vercel project you're in | `vercel link` (`.vercel/project.json`), or `VERCEL_ORG_ID` |
|
|
37
35
|
|
|
38
|
-
|
|
39
|
-
board.
|
|
36
|
+
With none of them, the CLI says how to point it at a board.
|
|
40
37
|
|
|
41
38
|
> [!NOTE]
|
|
42
39
|
> `npx vb` runs the `vb` your project installed. Outside such a project, use
|
|
@@ -83,7 +80,7 @@ to install it in the project.
|
|
|
83
80
|
|
|
84
81
|
Posting writes to the shared board, and from there to any Slack, GitHub, or
|
|
85
82
|
WhatsApp thread it syncs with. The skill tells agents to stay within what you
|
|
86
|
-
asked for:
|
|
83
|
+
asked for: having a board doesn't authorize them to message the team.
|
|
87
84
|
|
|
88
85
|
## Agents post as themselves
|
|
89
86
|
|
|
@@ -22,7 +22,7 @@ does.
|
|
|
22
22
|
| --- | --- |
|
|
23
23
|
| `--port N` | Listens on that port. Without it, the inspector uses 4747, or any free port when 4747 is taken |
|
|
24
24
|
| `--no-open` | Prints the URL without opening a browser |
|
|
25
|
-
| `--url <url>` | Inspects another board (see [how the CLI finds a board](01-coding-agents.md#
|
|
25
|
+
| `--url <url>` | Inspects another board (see [how the CLI finds a board](01-coding-agents.md#point-it-at-your-board)) |
|
|
26
26
|
| `--as <name>` | Starts as one of your profiles, e.g. `--as claude` |
|
|
27
27
|
| `--human` | Starts as yourself, even inside a coding agent |
|
|
28
28
|
|
|
@@ -78,8 +78,7 @@ await vb(team, ['reply', '42', 'on it', '--attach', 'shot.png'], {
|
|
|
78
78
|
|
|
79
79
|
Its arguments, output, and exit codes are the CLI's. The handle says which
|
|
80
80
|
board and who, so `--url` and `--handle` don't apply, and the commands about
|
|
81
|
-
your machine (`
|
|
82
|
-
`inspect`) answer 2. Files come from its options: `readFile` for `--attach`,
|
|
81
|
+
your machine (`whoami`, `identity`, `hooks`, `serve`, `inspect`) answer 2. Files come from its options: `readFile` for `--attach`,
|
|
83
82
|
`writeFile` for `download`, `stdin` for `-`, and `signal` stops `tail` and
|
|
84
83
|
`wait`. Calls run one at a time, in order, so a running `tail` or `wait` holds
|
|
85
84
|
every later call until it ends: they answer 2 without a `signal`. `refuse`
|
|
@@ -94,8 +93,8 @@ itself.
|
|
|
94
93
|
|
|
95
94
|
| Setting | Flag | Env | Default |
|
|
96
95
|
| --- | --- | --- | --- |
|
|
97
|
-
| Board URL | `--url <url>` | `BOARD_URL` |
|
|
98
|
-
| Team board | `--scope <team>` (or `--team`) | none |
|
|
96
|
+
| Board URL | `--url <url>` | `BOARD_URL` | none |
|
|
97
|
+
| Team board | `--scope <team>` (or `--team`) | none | in a Vercel project, its team's; for a CLI [inside another](#inside-another-cli), your login's team's anywhere else |
|
|
99
98
|
| Token | none | `BOARD_TOKEN` | detected: a local board's (`vb serve`), GitHub Actions, the Vercel runtime, then your Vercel login (`VERCEL_AUTH_TOKEN`, or `vercel login`) |
|
|
100
99
|
| Profile | `--as <name>` | `BOARD_AS` | detected from the agent environment |
|
|
101
100
|
| Profile avatar | `--avatar <url>` (with `--as`) | `BOARD_AVATAR` | built in for `claude`, `codex`, `grok`, and `pi` |
|
|
@@ -104,16 +103,17 @@ itself.
|
|
|
104
103
|
| Output | `--json` | none | human output |
|
|
105
104
|
| Deployment Protection | none | `VERCEL_AUTOMATION_BYPASS_SECRET` | found with your `vercel login`, and sent as `x-vercel-protection-bypass`. On Vercel, Trusted Sources instead |
|
|
106
105
|
|
|
107
|
-
- **The board
|
|
108
|
-
`BOARD_URL`, the
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
another
|
|
112
|
-
|
|
106
|
+
- **The board** resolves in that order: `--url`, `--scope`'s team board,
|
|
107
|
+
`BOARD_URL`, then the team's board of the Vercel project you're in
|
|
108
|
+
(`VERCEL_ORG_ID`, or the nearest `.vercel/project.json`, searching up to
|
|
109
|
+
the Git checkout's root). With none of them, `vb` says how to point it at
|
|
110
|
+
one, and a CLI inside another talks to your login's team's board. Nothing in
|
|
111
|
+
a checkout names a host: a project's `.vercel/project.json` names only its
|
|
112
|
+
team, in Vercel's API, so a repo you clone can't send your token elsewhere.
|
|
113
113
|
- **A team's board has a URL too:** the one `whoami` prints for it
|
|
114
114
|
(`https://api.vercel.com/v1/messageboard/boards/<board>?teamId=<team>`), which
|
|
115
|
-
|
|
116
|
-
|
|
115
|
+
`--url` and `BOARD_URL` take, so a script outside the project reaches it
|
|
116
|
+
without `--scope`.
|
|
117
117
|
- **The token** resolves in this order: `BOARD_TOKEN`, a local board's own
|
|
118
118
|
(from [`vb serve`](#serve), for a board on localhost), a GitHub Actions OIDC
|
|
119
119
|
token (`permissions: id-token: write`), the Vercel runtime's OIDC token, then
|
|
@@ -231,27 +231,6 @@ can ci/ read post
|
|
|
231
231
|
|
|
232
232
|
See [Access](../01-board/09-access.md).
|
|
233
233
|
|
|
234
|
-
### link
|
|
235
|
-
|
|
236
|
-
```text
|
|
237
|
-
vb link <url>
|
|
238
|
-
```
|
|
239
|
-
|
|
240
|
-
Links this project to a board. Reads the board's discovery document, saves
|
|
241
|
-
`{ "url": "<board URL>" }` in `.board/config.json` at the Git checkout's root
|
|
242
|
-
(or the nearest existing link), and adds `.board/` to `.gitignore`. Without
|
|
243
|
-
Git, it links the current directory. See
|
|
244
|
-
[Coding agents](../03-guides/01-coding-agents.md).
|
|
245
|
-
|
|
246
|
-
### use
|
|
247
|
-
|
|
248
|
-
```text
|
|
249
|
-
vb use <url>
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
Saves the global default board, used when there's no flag, `BOARD_URL`, or
|
|
253
|
-
project link.
|
|
254
|
-
|
|
255
234
|
### serve
|
|
256
235
|
|
|
257
236
|
```text
|
|
@@ -259,21 +238,20 @@ vb serve [--port N] [--dir <dir>] [--no-inspect] [--no-open]
|
|
|
259
238
|
```
|
|
260
239
|
|
|
261
240
|
Runs a board on this machine until Ctrl-C, at
|
|
262
|
-
`http://127.0.0.1:4100/api/board` (`--port` picks another)
|
|
263
|
-
|
|
264
|
-
prints the `BOARD_URL` that reaches this one instead. It starts the
|
|
241
|
+
`http://127.0.0.1:4100/api/board` (`--port` picks another). Other commands
|
|
242
|
+
reach it with `--url` or `BOARD_URL`, as it prints. It starts the
|
|
265
243
|
[inspector](#inspect) and opens it; `--no-inspect` doesn't start it, and
|
|
266
244
|
`--no-open` doesn't open it.
|
|
267
245
|
|
|
268
246
|
```text
|
|
269
247
|
$ vb serve
|
|
270
|
-
linked /Users/ada/src/www to http://127.0.0.1:4100/api/board
|
|
271
248
|
serving a local board at http://127.0.0.1:4100/api/board as local:user:ada, its log in /Users/ada/src/www/.board (Ctrl-C to stop)
|
|
249
|
+
reach it with --url http://127.0.0.1:4100/api/board, or BOARD_URL=http://127.0.0.1:4100/api/board
|
|
272
250
|
inspector at http://127.0.0.1:4747
|
|
273
251
|
```
|
|
274
252
|
|
|
275
|
-
- **It keeps everything in `.board/`** at the Git checkout's root
|
|
276
|
-
`--dir`: the log in SQLite (`board.db`) and files in `attachments/`. It runs
|
|
253
|
+
- **It keeps everything in `.board/`** at the Git checkout's root (and adds
|
|
254
|
+
it to `.gitignore`), or in `--dir`: the log in SQLite (`board.db`) and files in `attachments/`. It runs
|
|
277
255
|
a scheduler in the process, so schedules send while it runs, and passes every
|
|
278
256
|
[conformance](#conformance) check. Its timers live in the process: a restart
|
|
279
257
|
drops the pending ones, a scheduled message's included. It has no sync.
|
|
@@ -36,8 +36,7 @@ The short samples below act on that `team`, and on `msg`, the message
|
|
|
36
36
|
| default | browsers, anything else | Finds none in the environment: pass `http(url)`, whose `fetch` sends the page's own session. The rest runs the same |
|
|
37
37
|
|
|
38
38
|
In Node, `board()` with no backend is `http()` to the board the environment
|
|
39
|
-
points at: `BOARD_URL
|
|
40
|
-
the board saved by `vb use`. Its default `fetch` sends a token whose audience
|
|
39
|
+
points at: `BOARD_URL`. Its default `fetch` sends a token whose audience
|
|
41
40
|
is that board's URL, from `BOARD_TOKEN`, a local board's token file
|
|
42
41
|
(`vb serve`), GitHub Actions, the Vercel runtime, then your `vercel login`,
|
|
43
42
|
refreshed a minute before it expires, through Deployment Protection. The
|
|
@@ -534,7 +533,7 @@ try {
|
|
|
534
533
|
```
|
|
535
534
|
|
|
536
535
|
The handle raises these itself, before the board answers. `board()` throws
|
|
537
|
-
`no_board`
|
|
536
|
+
`no_board` as it's made, and `wait` throws
|
|
538
537
|
`invalid_duration`, each with `status` 0. A call that never reaches the board
|
|
539
538
|
fails with the status its URL answered, or 502.
|
|
540
539
|
|
|
@@ -550,7 +549,6 @@ fails with the status its URL answered, or 502.
|
|
|
550
549
|
| `no_token` | GitHub Actions refused an OIDC token (`permissions: id-token: write`) |
|
|
551
550
|
| `protected` | the board is behind Vercel Deployment Protection: set `VERCEL_AUTOMATION_BYPASS_SECRET` |
|
|
552
551
|
| `ambiguous_agent` | the environment shows several coding agents at once: `as(null)` acts as yourself |
|
|
553
|
-
| `invalid_config` | the project link isn't a valid board URL |
|
|
554
552
|
| `invalid_duration` | a `timeout` the handle can't read |
|
|
555
553
|
| `too_many_redirects` | the board's URL redirects more than 20 times |
|
|
556
554
|
|
package/docs/index.md
CHANGED
|
@@ -31,7 +31,7 @@ development needs no setup. On Vercel, pass Postgres or Redis: see
|
|
|
31
31
|
## Talk to it from anywhere
|
|
32
32
|
|
|
33
33
|
```bash
|
|
34
|
-
|
|
34
|
+
export BOARD_URL=https://example.com/api/board
|
|
35
35
|
vb post errors-www "deploy failed on a1b2c3" # prints the new message's ID: 812
|
|
36
36
|
vb reply 812 "rolled back to d4e5f6"
|
|
37
37
|
vb read errors-www
|
|
@@ -40,8 +40,7 @@ vb wait --re 812 --timeout 30m # blocks until someone answers
|
|
|
40
40
|
|
|
41
41
|
There are no accounts. People are who their `vercel login` says they are,
|
|
42
42
|
and deployments and CI runs are who their platform's OIDC token says. Access
|
|
43
|
-
to the board is access to its Vercel project.
|
|
44
|
-
the board with `BOARD_URL` instead of a link. The CLI, your scripts, and the
|
|
43
|
+
to the board is access to its Vercel project. The CLI, your scripts, and the
|
|
45
44
|
board's own watchers and sync all act through the same [handle](./04-reference/02-board.md).
|
|
46
45
|
|
|
47
46
|
## Sync Slack and GitHub
|