@agent-flow-board/bridge 0.2.0 → 0.3.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 (51) hide show
  1. package/README.md +16 -0
  2. package/dist/checks/appdir.js +105 -0
  3. package/dist/checks/approve.js +213 -0
  4. package/dist/checks/audit.js +3 -2
  5. package/dist/checks/bind.js +3 -2
  6. package/dist/checks/broker.js +439 -0
  7. package/dist/checks/browser.js +137 -32
  8. package/dist/checks/browserpool.js +221 -0
  9. package/dist/checks/cache.js +710 -0
  10. package/dist/checks/command.js +75 -88
  11. package/dist/checks/commands.js +219 -0
  12. package/dist/checks/connections.js +4 -3
  13. package/dist/checks/copy.js +320 -0
  14. package/dist/checks/dbpool.js +710 -0
  15. package/dist/checks/doctor.js +649 -0
  16. package/dist/checks/envPolicy.js +50 -1
  17. package/dist/checks/envrules.js +322 -0
  18. package/dist/checks/evidence.js +114 -0
  19. package/dist/checks/fsretry.js +29 -0
  20. package/dist/checks/importlegacy.js +300 -0
  21. package/dist/checks/install.js +150 -0
  22. package/dist/checks/live.js +76 -0
  23. package/dist/checks/lock.js +28 -4
  24. package/dist/checks/login.js +203 -0
  25. package/dist/checks/mailguard-hook.cjs +216 -0
  26. package/dist/checks/mailguard.js +98 -0
  27. package/dist/checks/paths.js +24 -0
  28. package/dist/checks/preview.js +418 -191
  29. package/dist/checks/profiles.js +110 -0
  30. package/dist/checks/provision.js +1 -1
  31. package/dist/checks/recipe.js +19 -5
  32. package/dist/checks/registry.js +548 -0
  33. package/dist/checks/repoenv.js +162 -0
  34. package/dist/checks/roots.js +144 -0
  35. package/dist/checks/routing.js +68 -0
  36. package/dist/checks/run.js +243 -53
  37. package/dist/checks/sandbox.js +32 -10
  38. package/dist/checks/scheduler.js +383 -0
  39. package/dist/checks/scope.js +119 -30
  40. package/dist/checks/sealedNames.js +39 -0
  41. package/dist/checks/secrets.js +452 -0
  42. package/dist/checks/secretscmd.js +80 -0
  43. package/dist/checks/service.js +589 -0
  44. package/dist/checks/signin.js +7 -1
  45. package/dist/checks/singleflight.js +307 -0
  46. package/dist/checks/store.js +92 -0
  47. package/dist/checks/surface.js +124 -0
  48. package/dist/checks/warm.js +342 -0
  49. package/dist/checks/watch.js +190 -63
  50. package/dist/checks/wire.js +87 -0
  51. package/package.json +1 -1
@@ -0,0 +1,87 @@
1
+ // WHAT THE BOARD IS TOLD ABOUT THE REGISTRATIONS. Every call carries the header x-afb-tool-registrations: a base64url JSON list of {p: board project, n: NAME, r: folder name, b: branch}, at most 16,
2
+ // only this organisation's, refreshed every 20 seconds. The board reads the text of whoever holds the token, so each field is checked against the board's own plain pattern first. A bad
3
+ // r or b is dropped from its entry (the board would call the whole header damaged); the entry stays. Never a path, a command or a secret.
4
+ // -- DEP-MODULES -- //
5
+ import { existsSync, readFileSync, statSync } from 'node:fs';
6
+ import { basename, dirname, isAbsolute, join, resolve } from 'node:path';
7
+ // -- MODULES -- //
8
+ import { PROJECT_KEY, REGISTRATION_NAME } from './registry.js';
9
+ // -- CONSTANTS -- //
10
+ export const REGISTRATIONS_HEADER = 'x-afb-tool-registrations';
11
+ /** How often the list is sent again, in milliseconds. */
12
+ export const REGISTRATIONS_REFRESH_MS = 20_000;
13
+ export const MAX_WIRE_REGISTRATIONS = 16;
14
+ /** The board refuses a header longer than this. */
15
+ const MAX_HEADER_CHARS = 6000;
16
+ const REPO = /^[A-Za-z0-9 ._-]{1,100}$/;
17
+ const BRANCH = /^[A-Za-z0-9._/-]{1,100}$/;
18
+ // -- FUNCTIONS -- //
19
+ /** The checked out branch of a repo, read from .git/HEAD without starting git. Null for a detached HEAD, no repo or a head it cannot read. */
20
+ export function readBranch(repo) {
21
+ try {
22
+ let gitDir = join(repo, '.git');
23
+ if (statSync(gitDir).isFile()) {
24
+ const m = /^gitdir:\s*(.+)$/m.exec(readFileSync(gitDir, 'utf8'));
25
+ if (!m?.[1])
26
+ return null;
27
+ const target = m[1].trim();
28
+ gitDir = isAbsolute(target) ? target : resolve(dirname(gitDir), target);
29
+ }
30
+ const head = readFileSync(join(gitDir, 'HEAD'), 'utf8').trim();
31
+ const ref = /^ref:\s*refs\/heads\/(.+)$/.exec(head);
32
+ return ref?.[1] ?? null;
33
+ }
34
+ catch {
35
+ return null;
36
+ }
37
+ }
38
+ /** The registrations of one organisation as board entries, with the fields that do not match dropped. */
39
+ export function wireEntries(org, registrations) {
40
+ const out = [];
41
+ for (const r of registrations) {
42
+ if (r.org !== org)
43
+ continue;
44
+ // An entry without a valid project key or name cannot be sent at all: the board would refuse the whole header
45
+ if (!PROJECT_KEY.test(r.boardProject) || !REGISTRATION_NAME.test(r.name))
46
+ continue;
47
+ const entry = { p: r.boardProject, n: r.name };
48
+ const folder = r.repoName ?? (r.repo ? basename(r.repo) : null);
49
+ if (folder && REPO.test(folder))
50
+ entry.r = folder;
51
+ if (r.branch && BRANCH.test(r.branch))
52
+ entry.b = r.branch;
53
+ out.push(entry);
54
+ if (out.length === MAX_WIRE_REGISTRATIONS)
55
+ break;
56
+ }
57
+ return out;
58
+ }
59
+ /** The header value for one organisation, or '' when it has none. The list is cut from the end until it fits what the board accepts. */
60
+ export function registrationsHeader(org, registrations) {
61
+ const list = wireEntries(org, registrations);
62
+ while (list.length) {
63
+ const value = Buffer.from(JSON.stringify(list)).toString('base64url');
64
+ if (value.length <= MAX_HEADER_CHARS)
65
+ return value;
66
+ list.pop();
67
+ }
68
+ return '';
69
+ }
70
+ /** Gives a registration its branch from the repo (no git process), for the header and the report. */
71
+ export function withBranch(reg) {
72
+ return { ...reg, branch: reg.repo && existsSync(reg.repo) ? readBranch(reg.repo) : null };
73
+ }
74
+ /**
75
+ * Cleans the registration fields of a run report before it is sent: a registration that is not a plain name, and a folder name or branch that does not match the board's pattern,
76
+ * are removed from the report (the rest of the report stays).
77
+ */
78
+ export function sanitiseReport(report) {
79
+ const out = { ...report };
80
+ if (out.registration !== undefined && !REGISTRATION_NAME.test(out.registration))
81
+ delete out.registration;
82
+ if (out.repoName !== undefined && !REPO.test(out.repoName))
83
+ delete out.repoName;
84
+ if (out.branch !== undefined && !BRANCH.test(out.branch))
85
+ delete out.branch;
86
+ return out;
87
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-flow-board/bridge",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
5
  "description": "Local bridge to an agent-flow-board server: forwards MCP calls over stdio, runs the coding tool hooks, writes the editor status and runs browser checks on this machine. It holds no board tool code.",
6
6
  "license": "MIT",