@vercel/board 0.21.1 → 0.23.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.
Files changed (32) hide show
  1. package/dist/{a2-_m1s1wSE.mjs → a2-NMEbIKNZ.mjs} +1 -1
  2. package/dist/backend-a2.mjs +1 -1
  3. package/dist/{backend-http-BvZqHIkS.mjs → backend-http-DQUsVgML.mjs} +1 -1
  4. package/dist/{backend-http-BYfh45ZM.mjs → backend-http-D_rjJVmW.mjs} +1 -1
  5. package/dist/backend-http.mjs +1 -1
  6. package/dist/backend-http.node.mjs +1 -1
  7. package/dist/{backend-vercel-C-AGfm88.mjs → backend-vercel-BSuIfOyF.mjs} +1 -1
  8. package/dist/{backend-vercel-DRl9xzAj.mjs → backend-vercel-BWVAihZC.mjs} +53 -6
  9. package/dist/backend-vercel.mjs +1 -1
  10. package/dist/backend-vercel.node.mjs +1 -1
  11. package/dist/cli-commands.d.mts +2 -0
  12. package/dist/cli-commands.mjs +2 -0
  13. package/dist/cli-embedded.d.mts +5 -1
  14. package/dist/cli-embedded.mjs +1 -1
  15. package/dist/cli.mjs +81 -58
  16. package/dist/commands-D0wXq6CY.d.mts +268 -0
  17. package/dist/commands-D_ODblQY.mjs +770 -0
  18. package/dist/{exports-DW1PLPFH.mjs → exports-DAVHon9y.mjs} +1 -1
  19. package/dist/{index.default-B0rK6NS5.mjs → index.default-TBybqjGV.mjs} +1 -1
  20. package/dist/index.mjs +2 -2
  21. package/dist/index.node.mjs +1 -1
  22. package/dist/inspect/app.js +109 -109
  23. package/dist/{main-CkGrzdD4.mjs → main-B5BCEQ0l.mjs} +175 -127
  24. package/dist/{serve-C-Ppvvu2.mjs → serve-BC218-NQ.mjs} +2 -2
  25. package/dist/{server-C8eMjwmE.mjs → server-BxUruJxv.mjs} +2 -2
  26. package/dist/sync-github.d.mts +1 -1
  27. package/dist/sync-github.mjs +20 -1
  28. package/dist/{watchers-hash-BMvgVhPV.mjs → watchers-hash-DYu8WWXj.mjs} +9 -11
  29. package/docs/01-board/05-reading.md +1 -0
  30. package/docs/02-sync/04-github.md +2 -1
  31. package/docs/04-reference/01-cli.md +45 -3
  32. package/package.json +5 -1
@@ -1,7 +1,7 @@
1
1
  import { n as DIRECT_UPLOAD_BYTES_MAX, r as IMPORT_BYTES_MAX, t as ATTACHMENT_BYTES_MAX } from "./files-SniSmeEr.mjs";
2
2
  import { _ as RemoteWatcherId, b as actorKind, i as Attachment, x as platformAvatar } from "./schemas-Be08nyfW.mjs";
3
3
  import "./external-BV_cUncs.mjs";
4
- import { f as VERSION, n as compileWatcher, o as METHODS, p as SYNC, r as hasCriteria, t as canonicalWatchers } from "./watchers-hash-BMvgVhPV.mjs";
4
+ import { a as METHODS, d as VERSION, f as SYNC, n as compileWatcher, r as hasCriteria, t as canonicalWatchers } from "./watchers-hash-DYu8WWXj.mjs";
5
5
  import { r as duration, t as BoardError } from "./client-ClznIBMg.mjs";
6
6
  import { n as derivedId, r as isKeyIdOf } from "./ids-C6AYo1bu.mjs";
7
7
  import { a as forbidden, c as toErrorResponse, i as duplicateId, r as badRequest, s as notFound, t as HttpError } from "./errors-CQ-fwxM3.mjs";
@@ -1,2 +1,2 @@
1
- import { n as fsBlob, r as memoryBlob, t as a2 } from "./a2-_m1s1wSE.mjs";
1
+ import { n as fsBlob, r as memoryBlob, t as a2 } from "./a2-NMEbIKNZ.mjs";
2
2
  export { a2, fsBlob, memoryBlob };
@@ -1,6 +1,6 @@
1
1
  import "./files-SniSmeEr.mjs";
2
2
  import "./schemas-Be08nyfW.mjs";
3
- import { k as RegisterBody, n as compileWatcher, o as METHODS, q as routes, t as canonicalWatchers } from "./watchers-hash-BMvgVhPV.mjs";
3
+ import { K as routes, O as RegisterBody, a as METHODS, n as compileWatcher, t as canonicalWatchers } from "./watchers-hash-DYu8WWXj.mjs";
4
4
  import { n as createBoardClient, t as BoardError } from "./client-ClznIBMg.mjs";
5
5
  import { a as sha256, i as keyId, n as derivedId, t as DERIVED_ID } from "./ids-C6AYo1bu.mjs";
6
6
  import { a as forbidden, o as json, t as HttpError } from "./errors-CQ-fwxM3.mjs";
@@ -1,4 +1,4 @@
1
- import { r as createHttp } from "./backend-http-BvZqHIkS.mjs";
1
+ import { r as createHttp } from "./backend-http-DQUsVgML.mjs";
2
2
  import { i as environmentProfile, r as connect, t as boardUrl } from "./node-BeKPcokJ.mjs";
3
3
  //#region src/backend-http/index.ts
4
4
  const environment = {
@@ -1,2 +1,2 @@
1
- import { t as http } from "./index.default-B0rK6NS5.mjs";
1
+ import { t as http } from "./index.default-TBybqjGV.mjs";
2
2
  export { http };
@@ -1,2 +1,2 @@
1
- import { t as http } from "./backend-http-BYfh45ZM.mjs";
1
+ import { t as http } from "./backend-http-D_rjJVmW.mjs";
2
2
  export { http };
@@ -1,6 +1,6 @@
1
1
  import { t as HttpError } from "./errors-CQ-fwxM3.mjs";
2
2
  import { c as vercelLogin, i as environmentProfile, l as vercelProjectFile } from "./node-BeKPcokJ.mjs";
3
- import { t as createVercel } from "./backend-vercel-DRl9xzAj.mjs";
3
+ import { t as createVercel } from "./backend-vercel-BWVAihZC.mjs";
4
4
  import { readFile } from "node:fs/promises";
5
5
  import { decodeJwt } from "jose";
6
6
  import { getVercelOidcToken } from "@vercel/oidc";
@@ -1,8 +1,8 @@
1
1
  import { _ as RemoteWatcherId } from "./schemas-Be08nyfW.mjs";
2
- import { f as VERSION, k as RegisterBody, n as compileWatcher, o as METHODS, t as canonicalWatchers } from "./watchers-hash-BMvgVhPV.mjs";
2
+ import { O as RegisterBody, a as METHODS, d as VERSION, n as compileWatcher, t as canonicalWatchers } from "./watchers-hash-DYu8WWXj.mjs";
3
3
  import { a as sha256, n as derivedId } from "./ids-C6AYo1bu.mjs";
4
4
  import { a as forbidden, o as json, s as notFound, t as HttpError } from "./errors-CQ-fwxM3.mjs";
5
- import { a as wakePath, i as registrant, n as callerProfile, t as PROJECTS_OWN } from "./backend-http-BvZqHIkS.mjs";
5
+ import { a as wakePath, i as registrant, n as callerProfile, t as PROJECTS_OWN } from "./backend-http-DQUsVgML.mjs";
6
6
  //#region src/server/backend-vercel.ts
7
7
  const PROFILE = /^[A-Za-z][A-Za-z0-9-]{0,31}$/;
8
8
  const SESSION = /^[A-Za-z0-9_.:-]{1,128}$/;
@@ -253,6 +253,51 @@ function createVercel(options, environment) {
253
253
  for (const reaction of await all(who, path, "reactions")) (out[reaction.emoji] ??= []).push(reaction.actor.id);
254
254
  return out;
255
255
  }
256
+ /** Who's written here, by actor ID, as the API names them: messages carry only the actor. */
257
+ let actorNames = null;
258
+ /** How long names are kept before they're read again: someone renamed shows by their new name after this. */
259
+ const NAMES_FRESH_MS = 3e5;
260
+ /** Actors a list read again for them didn't have: it isn't read again for them. */
261
+ const unlisted = /* @__PURE__ */ new Set();
262
+ /** Reads the list, kept as the current one; a read that fails isn't kept, so the next name tries again. */
263
+ const readNames = (who) => {
264
+ const views = (async () => new Map((await all(who, await onBoard(who, "/actors"), "actors")).map((view) => [view.id, view])))();
265
+ const read = {
266
+ at: Date.now(),
267
+ views
268
+ };
269
+ actorNames = read;
270
+ views.catch(() => {
271
+ if (actorNames === read) actorNames = null;
272
+ });
273
+ return read;
274
+ };
275
+ /** The actor in a read of the list, or undefined when it doesn't have them or failed. */
276
+ const inList = (read, id) => read.views.then((views) => views.get(id), () => void 0);
277
+ /**
278
+ * An actor as board shows them: a person by their Vercel username and name, and an agent acting
279
+ * for a person by its profile under them, as the API names them; anyone else (a project, an app,
280
+ * an agent of one), or someone the API doesn't list, by their principal. The list is read again
281
+ * every few minutes, and at once for someone who wrote since it was.
282
+ */
283
+ async function nameOf(who, actor) {
284
+ const current = !actorNames || Date.now() - actorNames.at > NAMES_FRESH_MS ? readNames(who) : actorNames;
285
+ let found = await inList(current, actor.id);
286
+ if (!found && !unlisted.has(actor.id)) {
287
+ const again = actorNames && actorNames !== current ? actorNames : readNames(who);
288
+ found = await inList(again, actor.id);
289
+ if (!found && await again.views.then(() => true, () => false)) unlisted.add(actor.id);
290
+ }
291
+ const kind = found && apiKind(found.kind);
292
+ if (!found || !(kind === "person" || kind === "agent" && actor.principal.type === "user")) return actorView(actor);
293
+ return {
294
+ id: actor.id,
295
+ kind,
296
+ handle: found.handle,
297
+ name: found.name ?? found.handle,
298
+ avatar: found.avatar ?? null
299
+ };
300
+ }
256
301
  async function view(who, message, channel) {
257
302
  const root = message.sequence === 1;
258
303
  return {
@@ -276,7 +321,7 @@ function createVercel(options, environment) {
276
321
  attachments: [],
277
322
  links: [],
278
323
  version: message.version,
279
- author: actorView(message.createdBy)
324
+ author: await nameOf(who, message.createdBy)
280
325
  };
281
326
  }
282
327
  const positions = /* @__PURE__ */ new Map();
@@ -566,7 +611,7 @@ function createVercel(options, environment) {
566
611
  createdAt: iso(change.createdAt),
567
612
  payload,
568
613
  message,
569
- actor: actorView(change.actor)
614
+ actor: await nameOf(who, change.actor)
570
615
  };
571
616
  }
572
617
  /**
@@ -930,11 +975,13 @@ function createVercel(options, environment) {
930
975
  session: null
931
976
  };
932
977
  const team = await teamId();
978
+ if (options.board) await api(who, "GET", await onBoard(who));
979
+ const id = team?.startsWith("team_") ? team : (await self(who)).teamId;
933
980
  return {
934
981
  version: VERSION,
935
- url: `${origin}/v1/messageboard${await onBoard(who)}`,
982
+ url: `${origin}/v1/messageboard${await onBoard(who)}?teamId=${encodeURIComponent(id)}`,
936
983
  audience: origin,
937
- team_id: team?.startsWith("team_") ? team : (await self(who)).teamId,
984
+ team_id: id,
938
985
  project_id: null,
939
986
  sync: [],
940
987
  wake_by_path: true
@@ -1,4 +1,4 @@
1
- import { t as createVercel } from "./backend-vercel-DRl9xzAj.mjs";
1
+ import { t as createVercel } from "./backend-vercel-BWVAihZC.mjs";
2
2
  //#region src/backend-vercel/index.default.ts
3
3
  /**
4
4
  * Your team's board, in Vercel's API. Outside Node there's no environment to find credentials or
@@ -1,2 +1,2 @@
1
- import { n as vercel, t as credentialSource } from "./backend-vercel-C-AGfm88.mjs";
1
+ import { n as vercel, t as credentialSource } from "./backend-vercel-BSuIfOyF.mjs";
2
2
  export { credentialSource, vercel };
@@ -0,0 +1,2 @@
1
+ import { a as OptionName, c as globalOptions, d as options, f as usage, i as CliOption, l as groups, n as CliCommand, o as commands, r as CliExample, s as filters, t as CliArgument, u as option } from "./commands-D0wXq6CY.mjs";
2
+ export { CliArgument, CliCommand, CliExample, CliOption, OptionName, commands, filters, globalOptions, groups, option, options, usage };
@@ -0,0 +1,2 @@
1
+ import { a as option, i as groups, n as filters, o as options, r as globalOptions, s as usage, t as commands } from "./commands-D_ODblQY.mjs";
2
+ export { commands, filters, globalOptions, groups, option, options, usage };
@@ -1,7 +1,11 @@
1
1
  import { d as Board } from "./backend-CWmd4UH-.mjs";
2
2
  import "./index-DsMPCv_K.mjs";
3
3
  //#region src/cli/main.d.ts
4
- /** The command word: the first argument that isn't a flag or a string flag's value (a bare `--mentions` takes none). */
4
+ /**
5
+ * The command `argv` runs, by its own name (`delete` for `rm`), as the parser reads it: the
6
+ * first positional, past every flag and value however they're written (`-an 1`, `--limit=1`). A
7
+ * bare `--mentions` takes none.
8
+ */
5
9
  export declare function commandWord(argv: string[]): string | undefined;
6
10
  //#endregion
7
11
  //#region src/cli/embedded.d.ts
@@ -1,4 +1,4 @@
1
- import { n as main, r as mainWith, t as commandWord } from "./main-CkGrzdD4.mjs";
1
+ import { n as main, r as mainWith, t as commandWord } from "./main-B5BCEQ0l.mjs";
2
2
  //#region src/cli/embedded.ts
3
3
  /**
4
4
  * Board's CLI as `appName` names it in help, usage, and errors (`vercel board`). With no board
package/dist/cli.mjs CHANGED
@@ -1,8 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import { t as ATTACHMENT_BYTES_MAX } from "./files-SniSmeEr.mjs";
3
3
  import "./schemas-Be08nyfW.mjs";
4
+ import { a as option } from "./commands-D_ODblQY.mjs";
4
5
  import { o as projectDir, s as projectUrl } from "./node-BeKPcokJ.mjs";
5
- import { i as who, n as main } from "./main-CkGrzdD4.mjs";
6
+ import { i as who, n as main } from "./main-B5BCEQ0l.mjs";
6
7
  import { randomBytes, timingSafeEqual } from "node:crypto";
7
8
  import { readFile } from "node:fs/promises";
8
9
  import { join } from "node:path";
@@ -604,68 +605,90 @@ const stopped = () => new Promise((resolve) => {
604
605
  process.once("SIGINT", done);
605
606
  process.once("SIGTERM", done);
606
607
  });
607
- //#endregion
608
- //#region src/cli/bin.ts
609
- main(process.argv.slice(2), {
610
- name: "board",
611
- commands: {
612
- inspect: {
613
- help: " inspect [--port N] [--no-open] the board in your browser, as you: read, post, react (local only)",
614
- async run(_args, { flags, out, portFlag, client, openBrowser }) {
615
- const port = portFlag();
616
- const inspector = await startInspector({
617
- client: client(),
618
- ...port !== void 0 ? { port } : {}
619
- });
620
- out(`inspecting ${inspector.board} as ${who(inspector.me)} at ${inspector.url} (Ctrl-C to stop)`);
621
- if (!flags["no-open"]) openBrowser(inspector.url);
622
- await stopped();
623
- await inspector.close();
624
- return 0;
625
- }
608
+ /** The commands only the standalone `board` has, in the order its help lists them. */
609
+ const local = {
610
+ inspect: {
611
+ spec: {
612
+ name: "inspect",
613
+ description: "the board in your browser, as you: read, post, react (local only)",
614
+ arguments: [],
615
+ options: [option("port", "the port to listen on (default: a free one)"), option("no-open")],
616
+ examples: [{
617
+ name: "open the board in your browser",
618
+ value: "inspect"
619
+ }]
626
620
  },
627
- serve: {
628
- help: ` serve [--port N] [--dir <dir>] [--no-inspect] [--no-open]
629
- run a board on this machine (127.0.0.1:4100, no sync), link this
630
- project to it, and open the inspector; its log lives in .board/,
631
- and you're local:user:<your OS user> (or --handle)`,
632
- async run(args, { flags, out, usage, portFlag, connection, openBrowser, saveLink, linkedByServe }) {
633
- if (args.length > 0) throw usage("usage: board serve [--port N] [--dir <dir>] [--no-inspect] [--no-open]");
634
- const port = portFlag();
635
- const root = projectDir();
636
- const { localHandle, serveLocal } = await import("./serve-C-Ppvvu2.mjs");
637
- const handle = flags.handle ?? process.env.BOARD_HANDLE;
638
- const local = await serveLocal({
639
- dir: flags.dir ?? join(root, ".board"),
640
- ...port !== void 0 ? { port } : {},
641
- ...handle ? { handle: localHandle(handle) } : {}
642
- });
643
- let inspector = null;
644
- try {
645
- const linked = projectUrl();
646
- if (linked === void 0 || linked === local.url || linkedByServe(root)) {
647
- await saveLink(root, local.url, { serve: true });
648
- if (linked !== local.url) out(`linked ${root} to ${local.url}`);
649
- } else out(`${root} stays linked to ${linked}; reach this board with BOARD_URL=${local.url}`);
650
- out(`serving a local board at ${local.url} as ${local.principal}, its log in ${local.dir} (Ctrl-C to stop)`);
651
- if (!flags["no-inspect"]) {
652
- const { board } = connection(local.url, {
653
- token: local.token,
654
- handle: local.handle
655
- });
656
- inspector = await startInspector({ client: board.as(null) });
657
- out(`inspector at ${inspector.url}`);
658
- if (!flags["no-open"]) openBrowser(inspector.url);
659
- }
660
- await stopped();
661
- } finally {
662
- await inspector?.close();
663
- await local.close();
621
+ async run(_args, { flags, out, portFlag, client, openBrowser }) {
622
+ const port = portFlag();
623
+ const inspector = await startInspector({
624
+ client: client(),
625
+ ...port !== void 0 ? { port } : {}
626
+ });
627
+ out(`inspecting ${inspector.board} as ${who(inspector.me)} at ${inspector.url} (Ctrl-C to stop)`);
628
+ if (!flags["no-open"]) openBrowser(inspector.url);
629
+ await stopped();
630
+ await inspector.close();
631
+ return 0;
632
+ }
633
+ },
634
+ serve: {
635
+ spec: {
636
+ name: "serve",
637
+ description: "run a board on this machine (127.0.0.1:4100, no sync), link this project to it, and open the inspector; its log lives in .board/, and you're local:user:<your OS user> (or --handle)",
638
+ arguments: [],
639
+ options: [
640
+ option("port", "the port to listen on (default: 4100)"),
641
+ option("dir"),
642
+ option("no-inspect"),
643
+ option("no-open")
644
+ ],
645
+ examples: [{
646
+ name: "run a board here, and open it",
647
+ value: "serve"
648
+ }]
649
+ },
650
+ async run(args, { flags, out, usage, portFlag, connection, openBrowser, saveLink, linkedByServe }) {
651
+ if (args.length > 0) throw usage("usage: board serve [--port N] [--dir <dir>] [--no-inspect] [--no-open]");
652
+ const port = portFlag();
653
+ const root = projectDir();
654
+ const { localHandle, serveLocal } = await import("./serve-BC218-NQ.mjs");
655
+ const handle = flags.handle ?? process.env.BOARD_HANDLE;
656
+ const local = await serveLocal({
657
+ dir: flags.dir ?? join(root, ".board"),
658
+ ...port !== void 0 ? { port } : {},
659
+ ...handle ? { handle: localHandle(handle) } : {}
660
+ });
661
+ let inspector = null;
662
+ try {
663
+ const linked = projectUrl();
664
+ if (linked === void 0 || linked === local.url || linkedByServe(root)) {
665
+ await saveLink(root, local.url, { serve: true });
666
+ if (linked !== local.url) out(`linked ${root} to ${local.url}`);
667
+ } else out(`${root} stays linked to ${linked}; reach this board with BOARD_URL=${local.url}`);
668
+ out(`serving a local board at ${local.url} as ${local.principal}, its log in ${local.dir} (Ctrl-C to stop)`);
669
+ if (!flags["no-inspect"]) {
670
+ const { board } = connection(local.url, {
671
+ token: local.token,
672
+ handle: local.handle
673
+ });
674
+ inspector = await startInspector({ client: board.as(null) });
675
+ out(`inspector at ${inspector.url}`);
676
+ if (!flags["no-open"]) openBrowser(inspector.url);
664
677
  }
665
- return 0;
678
+ await stopped();
679
+ } finally {
680
+ await inspector?.close();
681
+ await local.close();
666
682
  }
683
+ return 0;
667
684
  }
668
685
  }
686
+ };
687
+ //#endregion
688
+ //#region src/cli/bin.ts
689
+ main(process.argv.slice(2), {
690
+ name: "board",
691
+ commands: local
669
692
  }).then(exit, (error) => {
670
693
  process.stderr.write(`error: ${error.message}\n`);
671
694
  exit(1);
@@ -0,0 +1,268 @@
1
+ //#region src/cli/commands.d.ts
2
+ /** An option, as the parser takes it (`type`, `short`, `multiple`) and as help shows it. */
3
+ type CliOption = {
4
+ readonly name: string;
5
+ readonly type: 'string' | 'boolean';
6
+ readonly short?: string;
7
+ /** It can be given more than once; each adds a value. */
8
+ readonly multiple?: true;
9
+ /** What it takes, as help shows it: `N`, `k=v`. A boolean takes nothing. */
10
+ readonly value?: string;
11
+ /** It may be given alone, without its value, as a bare `--mentions` means mentions of you. */
12
+ readonly optionalValue?: true;
13
+ readonly description: string;
14
+ /** Kept for what still passes it, out of help. */
15
+ readonly hidden?: true;
16
+ };
17
+ type CliArgument = {
18
+ readonly name: string;
19
+ readonly required: boolean;
20
+ /** It takes one or more (or, optional, zero or more). */
21
+ readonly multiple?: true;
22
+ readonly description?: string;
23
+ };
24
+ /** A command line that does a job, as it follows the CLI's name (`read dev`). */
25
+ type CliExample = {
26
+ readonly name: string;
27
+ readonly value: string;
28
+ };
29
+ type CliCommand = {
30
+ readonly name: string;
31
+ /** Other names it runs by: `rm` for `delete`. */
32
+ readonly aliases?: readonly string[];
33
+ readonly description: string;
34
+ readonly arguments: readonly CliArgument[];
35
+ /** Its own options: the filters (with `filters`) and the global options apply too. */
36
+ readonly options: readonly CliOption[];
37
+ /** It takes the filters (`--re`, `--by`, `--label`, …) as well. */
38
+ readonly filters?: true;
39
+ readonly examples: readonly CliExample[];
40
+ readonly subcommands?: readonly CliCommand[];
41
+ /** Its arguments come before its subcommand, as in `sources <key> read <target>`. */
42
+ readonly argumentsBeforeSubcommand?: true;
43
+ /** It does something without a subcommand too, as `identity` lists your links. */
44
+ readonly runsWithoutSubcommand?: true;
45
+ /** Out of help: it still runs, for what calls it. */
46
+ readonly hidden?: true;
47
+ };
48
+ /** Every option, by name: what the parser accepts, and what each means where a command doesn't say more. */
49
+ declare const options: {
50
+ readonly re: {
51
+ readonly type: 'string';
52
+ readonly value: 'id';
53
+ readonly description: "in a thread: its root's ID";
54
+ };
55
+ readonly by: {
56
+ readonly type: 'string';
57
+ readonly value: 'handle';
58
+ readonly description: 'by an author: a handle, me, or an actor ID';
59
+ };
60
+ readonly mentions: {
61
+ readonly type: 'string';
62
+ readonly value: '@handle';
63
+ readonly optionalValue: true;
64
+ readonly description: 'mentioning a handle, or you without one';
65
+ };
66
+ readonly label: {
67
+ readonly type: 'string';
68
+ readonly multiple: true;
69
+ readonly value: 'k[=v|w]';
70
+ readonly description: "with a label on the message or its thread's root";
71
+ };
72
+ readonly from: {
73
+ readonly type: 'string';
74
+ readonly value: 'source';
75
+ readonly description: 'from a source: a sync key such as slack, or board';
76
+ };
77
+ readonly text: {
78
+ readonly type: 'string';
79
+ readonly value: 'words';
80
+ readonly description: 'containing these words';
81
+ };
82
+ readonly after: {
83
+ readonly type: 'string';
84
+ readonly value: 'id';
85
+ readonly description: 'after a message or a cursor';
86
+ };
87
+ readonly url: {
88
+ readonly type: 'string';
89
+ readonly value: 'url';
90
+ readonly description: "the board at this URL, not the one the environment points at";
91
+ };
92
+ readonly scope: {
93
+ readonly type: 'string';
94
+ readonly value: 'team';
95
+ readonly description: "a team's board in Vercel's API, by its slug or ID";
96
+ };
97
+ readonly team: {
98
+ readonly type: 'string';
99
+ readonly value: 'team';
100
+ readonly description: 'the same as --scope';
101
+ readonly hidden: true;
102
+ };
103
+ readonly as: {
104
+ readonly type: 'string';
105
+ readonly value: 'profile';
106
+ readonly description: "write as a profile, such as an agent's name";
107
+ };
108
+ readonly avatar: {
109
+ readonly type: 'string';
110
+ readonly value: 'url';
111
+ readonly description: "the profile's avatar, with --as";
112
+ };
113
+ readonly human: {
114
+ readonly type: 'boolean';
115
+ readonly description: 'write as yourself, with no profile or session';
116
+ };
117
+ readonly handle: {
118
+ readonly type: 'string';
119
+ readonly value: 'h';
120
+ readonly description: 'your handle (default: your Vercel username)';
121
+ };
122
+ readonly json: {
123
+ readonly type: 'boolean';
124
+ readonly description: 'one JSON object per line, for programs';
125
+ };
126
+ readonly help: {
127
+ readonly type: 'boolean';
128
+ readonly short: 'h';
129
+ readonly description: "this help, or a command's";
130
+ };
131
+ readonly version: {
132
+ readonly type: 'boolean';
133
+ readonly short: 'v';
134
+ readonly description: "the CLI's version";
135
+ };
136
+ readonly limit: {
137
+ readonly type: 'string';
138
+ readonly short: 'n';
139
+ readonly value: 'N';
140
+ readonly description: 'how many';
141
+ };
142
+ readonly id: {
143
+ readonly type: 'string';
144
+ readonly value: 'key';
145
+ readonly description: 'a client ID: sending the same one again posts once';
146
+ };
147
+ readonly sync: {
148
+ readonly type: 'string';
149
+ readonly multiple: true;
150
+ readonly value: 'target';
151
+ readonly description: 'sync the new thread to a target too, e.g. slack:#incidents';
152
+ };
153
+ readonly 'no-sync': {
154
+ readonly type: 'boolean';
155
+ readonly description: 'keep it on the board: sync it nowhere';
156
+ };
157
+ readonly attach: {
158
+ readonly type: 'string';
159
+ readonly multiple: true;
160
+ readonly value: 'file';
161
+ readonly description: 'attach a file';
162
+ };
163
+ readonly unset: {
164
+ readonly type: 'string';
165
+ readonly multiple: true;
166
+ readonly value: 'k';
167
+ readonly description: 'remove a label';
168
+ };
169
+ readonly channel: {
170
+ readonly type: 'string';
171
+ readonly value: 'c';
172
+ readonly description: 'in a channel';
173
+ };
174
+ readonly remove: {
175
+ readonly type: 'boolean';
176
+ readonly description: 'take the reaction back';
177
+ };
178
+ readonly all: {
179
+ readonly type: 'boolean';
180
+ readonly short: 'a';
181
+ readonly description: 'everything, not only what most want';
182
+ };
183
+ readonly timeout: {
184
+ readonly type: 'string';
185
+ readonly value: 'duration';
186
+ readonly description: 'how long to wait (default: 30m)';
187
+ };
188
+ readonly code: {
189
+ readonly type: 'boolean';
190
+ readonly description: 'post a code from your account instead of signing in';
191
+ };
192
+ readonly 'no-wait': {
193
+ readonly type: 'boolean';
194
+ readonly description: "start linking, and don't wait for it to finish";
195
+ };
196
+ readonly 'no-open': {
197
+ readonly type: 'boolean';
198
+ readonly description: "don't open the browser";
199
+ };
200
+ readonly in: {
201
+ readonly type: 'string';
202
+ readonly value: 'duration';
203
+ readonly description: 'once, this long from now, e.g. 1d';
204
+ };
205
+ readonly at: {
206
+ readonly type: 'string';
207
+ readonly value: 'time';
208
+ readonly description: 'at a time: once, or with --every, the first';
209
+ };
210
+ readonly every: {
211
+ readonly type: 'string';
212
+ readonly value: 'duration';
213
+ readonly description: 'repeating at this interval, e.g. 30m';
214
+ };
215
+ readonly until: {
216
+ readonly type: 'string';
217
+ readonly short: 'u';
218
+ readonly value: 'time';
219
+ readonly description: 'repeating until a time';
220
+ };
221
+ readonly for: {
222
+ readonly type: 'string';
223
+ readonly value: 'duration';
224
+ readonly description: 'repeating for this long, e.g. 24h';
225
+ };
226
+ readonly times: {
227
+ readonly type: 'string';
228
+ readonly value: 'N';
229
+ readonly description: 'repeating this many times';
230
+ };
231
+ readonly port: {
232
+ readonly type: 'string';
233
+ readonly value: 'N';
234
+ readonly description: 'the port to listen on';
235
+ };
236
+ readonly dir: {
237
+ readonly type: 'string';
238
+ readonly value: 'dir';
239
+ readonly description: 'where the board keeps its log (default: .board/)';
240
+ };
241
+ readonly 'no-inspect': {
242
+ readonly type: 'boolean';
243
+ readonly description: "don't start the inspector";
244
+ };
245
+ readonly agent: {
246
+ readonly type: 'string';
247
+ readonly value: 'name';
248
+ readonly description: "the agent whose turn ended";
249
+ readonly hidden: true;
250
+ };
251
+ };
252
+ type OptionName = keyof typeof options;
253
+ /** The option `name`, saying `description` (and taking `value`) where it means something particular to a command. */
254
+ declare const option: (name: OptionName, description?: string, value?: string) => CliOption;
255
+ /** What `read`, `tail`, and `wait` match: every one given must hold. */
256
+ declare const filters: readonly CliOption[];
257
+ /** What every command takes. */
258
+ declare const globalOptions: readonly CliOption[];
259
+ /** What one of the CLI's help pages lists together, in this order. */
260
+ declare const groups: readonly ['you', 'the board', 'messages', 'agents', 'live'];
261
+ /** Board's commands, by `groups`, in the order its help lists them. */
262
+ declare const commands: readonly (CliCommand & {
263
+ readonly group: (typeof groups)[number];
264
+ })[];
265
+ /** One line of `usage`: a command's path and its arguments, as `<required>` and `[optional]`. */
266
+ declare function usage(path: readonly CliCommand[]): string;
267
+ //#endregion
268
+ export { OptionName as a, globalOptions as c, options as d, usage as f, CliOption as i, groups as l, CliCommand as n, commands as o, CliExample as r, filters as s, CliArgument as t, option as u };