@bragi-gmbh/codebus 1.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.
Files changed (133) hide show
  1. package/bin/codebus.js +2 -0
  2. package/dist/binding-guard.js +97 -0
  3. package/dist/binding-guard.js.map +1 -0
  4. package/dist/client.js +94 -0
  5. package/dist/client.js.map +1 -0
  6. package/dist/commands/ack.js +47 -0
  7. package/dist/commands/ack.js.map +1 -0
  8. package/dist/commands/archive.js +21 -0
  9. package/dist/commands/archive.js.map +1 -0
  10. package/dist/commands/as.js +299 -0
  11. package/dist/commands/as.js.map +1 -0
  12. package/dist/commands/ask.js +189 -0
  13. package/dist/commands/ask.js.map +1 -0
  14. package/dist/commands/auth.js +33 -0
  15. package/dist/commands/auth.js.map +1 -0
  16. package/dist/commands/checkin.js +235 -0
  17. package/dist/commands/checkin.js.map +1 -0
  18. package/dist/commands/decision.js +52 -0
  19. package/dist/commands/decision.js.map +1 -0
  20. package/dist/commands/digest.js +117 -0
  21. package/dist/commands/digest.js.map +1 -0
  22. package/dist/commands/doctor.js +106 -0
  23. package/dist/commands/doctor.js.map +1 -0
  24. package/dist/commands/factory.js +191 -0
  25. package/dist/commands/factory.js.map +1 -0
  26. package/dist/commands/github-login.js +205 -0
  27. package/dist/commands/github-login.js.map +1 -0
  28. package/dist/commands/graph.js +88 -0
  29. package/dist/commands/graph.js.map +1 -0
  30. package/dist/commands/health.js +34 -0
  31. package/dist/commands/health.js.map +1 -0
  32. package/dist/commands/inbox.js +83 -0
  33. package/dist/commands/inbox.js.map +1 -0
  34. package/dist/commands/ingest.js +553 -0
  35. package/dist/commands/ingest.js.map +1 -0
  36. package/dist/commands/init.js +97 -0
  37. package/dist/commands/init.js.map +1 -0
  38. package/dist/commands/install.js +520 -0
  39. package/dist/commands/install.js.map +1 -0
  40. package/dist/commands/invite.js +152 -0
  41. package/dist/commands/invite.js.map +1 -0
  42. package/dist/commands/jira.js +237 -0
  43. package/dist/commands/jira.js.map +1 -0
  44. package/dist/commands/join.js +96 -0
  45. package/dist/commands/join.js.map +1 -0
  46. package/dist/commands/links.js +66 -0
  47. package/dist/commands/links.js.map +1 -0
  48. package/dist/commands/login.js +84 -0
  49. package/dist/commands/login.js.map +1 -0
  50. package/dist/commands/morning.js +121 -0
  51. package/dist/commands/morning.js.map +1 -0
  52. package/dist/commands/next.js +66 -0
  53. package/dist/commands/next.js.map +1 -0
  54. package/dist/commands/onboarding.js +109 -0
  55. package/dist/commands/onboarding.js.map +1 -0
  56. package/dist/commands/pack.js +276 -0
  57. package/dist/commands/pack.js.map +1 -0
  58. package/dist/commands/plan-gh.js +425 -0
  59. package/dist/commands/plan-gh.js.map +1 -0
  60. package/dist/commands/plan.js +465 -0
  61. package/dist/commands/plan.js.map +1 -0
  62. package/dist/commands/pr.js +88 -0
  63. package/dist/commands/pr.js.map +1 -0
  64. package/dist/commands/question.js +142 -0
  65. package/dist/commands/question.js.map +1 -0
  66. package/dist/commands/read.js +84 -0
  67. package/dist/commands/read.js.map +1 -0
  68. package/dist/commands/refs.js +357 -0
  69. package/dist/commands/refs.js.map +1 -0
  70. package/dist/commands/reply.js +38 -0
  71. package/dist/commands/reply.js.map +1 -0
  72. package/dist/commands/repo.js +1198 -0
  73. package/dist/commands/repo.js.map +1 -0
  74. package/dist/commands/report.js +41 -0
  75. package/dist/commands/report.js.map +1 -0
  76. package/dist/commands/resolve-refs.js +21 -0
  77. package/dist/commands/resolve-refs.js.map +1 -0
  78. package/dist/commands/resolve.js +93 -0
  79. package/dist/commands/resolve.js.map +1 -0
  80. package/dist/commands/send.js +168 -0
  81. package/dist/commands/send.js.map +1 -0
  82. package/dist/commands/sent.js +22 -0
  83. package/dist/commands/sent.js.map +1 -0
  84. package/dist/commands/session.js +426 -0
  85. package/dist/commands/session.js.map +1 -0
  86. package/dist/commands/statusline.js +43 -0
  87. package/dist/commands/statusline.js.map +1 -0
  88. package/dist/commands/task.js +140 -0
  89. package/dist/commands/task.js.map +1 -0
  90. package/dist/commands/tick.js +233 -0
  91. package/dist/commands/tick.js.map +1 -0
  92. package/dist/commands/upgrade.js +76 -0
  93. package/dist/commands/upgrade.js.map +1 -0
  94. package/dist/commands/watch.js +169 -0
  95. package/dist/commands/watch.js.map +1 -0
  96. package/dist/commands/whoami.js +27 -0
  97. package/dist/commands/whoami.js.map +1 -0
  98. package/dist/config.js +103 -0
  99. package/dist/config.js.map +1 -0
  100. package/dist/directives.js +102 -0
  101. package/dist/directives.js.map +1 -0
  102. package/dist/errors.js +110 -0
  103. package/dist/errors.js.map +1 -0
  104. package/dist/git-hooks.js +116 -0
  105. package/dist/git-hooks.js.map +1 -0
  106. package/dist/graph-bootstrap.js +95 -0
  107. package/dist/graph-bootstrap.js.map +1 -0
  108. package/dist/graph-remote.js +889 -0
  109. package/dist/graph-remote.js.map +1 -0
  110. package/dist/graph.js +335 -0
  111. package/dist/graph.js.map +1 -0
  112. package/dist/index.js +154 -0
  113. package/dist/index.js.map +1 -0
  114. package/dist/kit/graph-publish.mjs +400 -0
  115. package/dist/mail-latency.js +120 -0
  116. package/dist/mail-latency.js.map +1 -0
  117. package/dist/mcp-registry.js +859 -0
  118. package/dist/mcp-registry.js.map +1 -0
  119. package/dist/mcp.js +193 -0
  120. package/dist/mcp.js.map +1 -0
  121. package/dist/output.js +12 -0
  122. package/dist/output.js.map +1 -0
  123. package/dist/positioning.js +21 -0
  124. package/dist/positioning.js.map +1 -0
  125. package/dist/rolestore.js +89 -0
  126. package/dist/rolestore.js.map +1 -0
  127. package/dist/session.js +49 -0
  128. package/dist/session.js.map +1 -0
  129. package/dist/sessionstore.js +736 -0
  130. package/dist/sessionstore.js.map +1 -0
  131. package/dist/version-check.js +97 -0
  132. package/dist/version-check.js.map +1 -0
  133. package/package.json +47 -0
@@ -0,0 +1,205 @@
1
+ import { createServer } from "node:http";
2
+ import { randomBytes } from "node:crypto";
3
+ import { execFile } from "node:child_process";
4
+ import { createClient } from "@supabase/supabase-js";
5
+ import { saveFileConfig } from "../config.js";
6
+ import { validateConnection } from "./login.js";
7
+ import { CodebusError } from "../errors.js";
8
+ // `codebus login --github` — the CLI mirror of web/app/login/page.tsx:
9
+ // Supabase Auth signInWithOAuth({provider:'github'}) over a localhost PKCE
10
+ // callback → exchangeCodeForSession → the EXISTING github_web_login() RPC →
11
+ // store the returned agent token. NO new backend; github_web_login() unchanged.
12
+ //
13
+ // GitHub OAuth is not configured in local Supabase, so the end-to-end flow
14
+ // CANNOT run in CI. The irreducible external-OAuth I/O is c8-ignored
15
+ // (DEC-CB-009 EX-001, precedent: join.ts); the testable seams below are
16
+ // pure/covered functions exercised by unit tests.
17
+ const DEFAULT_REMOTE = "https://tcapyyzkzecgfeivbymf.supabase.co";
18
+ const CALLBACK_TIMEOUT_MS = 120_000; // 2 min — user has to finish the browser dance
19
+ export function buildOAuthRequest(port, state) {
20
+ const redirectTo = `http://127.0.0.1:${port}/callback?state=${encodeURIComponent(state)}`;
21
+ return { provider: "github", options: { redirectTo, skipBrowserRedirect: true } };
22
+ }
23
+ export function parseCallback(reqUrl, expectedState) {
24
+ // reqUrl is a path+query (e.g. "/callback?code=..&state=.."); host is irrelevant.
25
+ const u = new URL(reqUrl ?? "/", "http://127.0.0.1");
26
+ if (u.pathname !== "/callback")
27
+ return { ok: false, reason: "ignore" };
28
+ const err = u.searchParams.get("error");
29
+ if (err) {
30
+ const desc = u.searchParams.get("error_description");
31
+ return { ok: false, reason: `GitHub sign-in was denied or failed: ${desc ?? err}` };
32
+ }
33
+ const state = u.searchParams.get("state");
34
+ if (!state || state !== expectedState) {
35
+ // CSRF guard: a callback whose state doesn't match the one we minted is
36
+ // rejected outright — never exchange a code we didn't ask for.
37
+ return { ok: false, reason: "state mismatch — possible CSRF, aborting login" };
38
+ }
39
+ const code = u.searchParams.get("code");
40
+ if (!code)
41
+ return { ok: false, reason: "no authorization code in callback" };
42
+ return { ok: true, code };
43
+ }
44
+ export function persistWebLogin(url, anonKey, res) {
45
+ return saveFileConfig({
46
+ url, anonKey, workspace: res.workspace,
47
+ token: res.token, agent: res.agent_slug, person: res.person_slug,
48
+ });
49
+ }
50
+ // ── Seam 4: github_web_login() error → CLI message ───────────────────────────
51
+ // Mirror web error semantics (web/app/login/page.tsx surfaces the raw RPC
52
+ // message; the CLI is friendlier). The RPC raises:
53
+ // * 'no CodeBus identity for github user "X" — ask a teammate for an invite'
54
+ // → tell them the exact admin command.
55
+ // * 'github session required' → the Auth session didn't carry a github identity.
56
+ // Anything else passes through. `login` is the GitHub username if known.
57
+ export function mapGithubWebLoginError(message, login) {
58
+ if (/no CodeBus identity for github user/i.test(message)) {
59
+ const who = login ? ` <${login}>` : " <your-github-login>";
60
+ return `No CodeBus identity for your GitHub account, and no pending invite for it. `
61
+ + `Ask an admin to \`codebus invite${who}\`, then run \`codebus login --github\` again.`;
62
+ }
63
+ if (/github session required/i.test(message)) {
64
+ return "GitHub sign-in did not produce a usable session (no GitHub identity on the token). "
65
+ + "Make sure you completed the GitHub authorization in the browser.";
66
+ }
67
+ if (/fetch failed|ENOTFOUND|ECONNREFUSED|network/i.test(message)) {
68
+ return "Cannot reach the CodeBus server — check your network/VPN.";
69
+ }
70
+ return message;
71
+ }
72
+ // ── Orchestrator ─────────────────────────────────────────────────────────────
73
+ // Wires the four covered seams above (buildOAuthRequest, parseCallback,
74
+ // persistWebLogin, mapGithubWebLoginError — each unit-tested) into the live
75
+ // browser-OAuth flow. The flow CANNOT run in CI (GitHub provider not configured
76
+ // in local Supabase) and the orchestration here is irreducible external-OAuth
77
+ // I/O — network anon-key fetch, the localhost callback server, browser open,
78
+ // signInWithOAuth/exchangeCodeForSession — so it carries the DEC-CB-009 EX-001
79
+ // exemption (precedent: join.ts). The seams are NOT ignored; only this glue is.
80
+ /* c8 ignore start -- DEC-CB-009 EX-001: external OAuth (anon-key fetch, browser, localhost server, code exchange) */
81
+ // Fetch the server's public anon key (same well-known endpoint join.ts uses).
82
+ async function resolveAnonKey(url, o) {
83
+ let anonKey = o.anonKey ?? process.env.SUPABASE_ANON_KEY;
84
+ if (!anonKey) {
85
+ const res = await fetch(`${url}/functions/v1/www/config`);
86
+ if (res.ok)
87
+ anonKey = (await res.json()).anonKey;
88
+ }
89
+ if (!anonKey)
90
+ throw new CodebusError(`could not fetch server config from ${url} — check your network/VPN, or pass --anon-key`);
91
+ return anonKey;
92
+ }
93
+ /* c8 ignore stop */
94
+ /* c8 ignore start -- DEC-CB-009 EX-001: external OAuth (browser, localhost server, code exchange) */
95
+ // Best-effort browser open (reuses the platform open command, like other CLIs).
96
+ // Returns false if it can't open, so the caller can print the URL to paste.
97
+ function openBrowser(targetUrl) {
98
+ const cmd = process.platform === "darwin" ? "open"
99
+ : process.platform === "win32" ? "cmd" : "xdg-open";
100
+ const args = process.platform === "win32" ? ["/c", "start", "", targetUrl] : [targetUrl];
101
+ try {
102
+ execFile(cmd, args, () => { });
103
+ return true;
104
+ }
105
+ catch {
106
+ return false;
107
+ }
108
+ }
109
+ // Start an ephemeral localhost server and return its bound port immediately,
110
+ // plus a promise that resolves with the captured auth code.
111
+ function startCallbackServer(expectedState) {
112
+ return new Promise((resolveServer, rejectServer) => {
113
+ let resolveCode;
114
+ let rejectCode;
115
+ const codeP = new Promise((res, rej) => { resolveCode = res; rejectCode = rej; });
116
+ const server = createServer((req, res) => {
117
+ const result = parseCallback(req.url, expectedState);
118
+ if (result.ok === false && result.reason === "ignore") {
119
+ res.writeHead(404).end();
120
+ return;
121
+ }
122
+ if (result.ok) {
123
+ res.writeHead(200, { "content-type": "text/html" })
124
+ .end("<h2>CodeBus: GitHub sign-in complete.</h2><p>You can close this tab and return to the terminal.</p>");
125
+ clearTimeout(timer);
126
+ resolveCode(result.code);
127
+ }
128
+ else {
129
+ res.writeHead(400, { "content-type": "text/html" })
130
+ .end(`<h2>CodeBus sign-in failed.</h2><p>${result.reason}</p>`);
131
+ clearTimeout(timer);
132
+ rejectCode(new CodebusError(result.reason));
133
+ }
134
+ });
135
+ const timer = setTimeout(() => {
136
+ rejectCode(new CodebusError("GitHub sign-in timed out after 2 minutes — rerun `codebus login --github`."));
137
+ }, CALLBACK_TIMEOUT_MS);
138
+ server.on("error", (e) => { clearTimeout(timer); rejectServer(e); });
139
+ server.listen(0, "127.0.0.1", () => {
140
+ const port = server.address().port;
141
+ resolveServer({ port, code: codeP, close: () => { clearTimeout(timer); server.close(); } });
142
+ });
143
+ });
144
+ }
145
+ /* c8 ignore stop */
146
+ // `codebus login --github` entry point. Mirrors web/app/login/page.tsx exactly:
147
+ // signInWithOAuth(github) → exchangeCodeForSession → github_web_login() RPC
148
+ // (UNCHANGED) → persist token → validateConnection.
149
+ /* c8 ignore start -- DEC-CB-009 EX-001: external OAuth orchestration (uncov-able in CI; seams unit-tested separately) */
150
+ export async function githubLoginCmd(o) {
151
+ const url = o.url ?? process.env.CODEBUS_URL ?? DEFAULT_REMOTE;
152
+ const anonKey = await resolveAnonKey(url, o);
153
+ const state = randomBytes(16).toString("hex");
154
+ // PKCE: supabase-js generates the verifier+challenge and persists the verifier
155
+ // in its storage; the SAME client instance must do signInWithOAuth and
156
+ // exchangeCodeForSession so the verifier matches.
157
+ const sb = createClient(url, anonKey, {
158
+ auth: { flowType: "pkce", persistSession: false, autoRefreshToken: false, detectSessionInUrl: false },
159
+ });
160
+ const server = await startCallbackServer(state);
161
+ const oauthReq = buildOAuthRequest(server.port, state);
162
+ const { data: oauth, error: oauthErr } = await sb.auth.signInWithOAuth(oauthReq);
163
+ if (oauthErr) {
164
+ server.close();
165
+ throw new CodebusError(/provider is not enabled/i.test(oauthErr.message)
166
+ ? "GitHub sign-in isn't enabled on this server."
167
+ : oauthErr.message);
168
+ }
169
+ if (openBrowser(oauth.url))
170
+ console.log("Opening your browser to sign in with GitHub…");
171
+ else
172
+ console.log(`Open this URL in your browser to sign in with GitHub:\n ${oauth.url}`);
173
+ let code;
174
+ try {
175
+ code = await server.code;
176
+ }
177
+ finally { /* server closed on resolve below */ }
178
+ const { error: exErr } = await sb.auth.exchangeCodeForSession(code);
179
+ if (exErr) {
180
+ server.close();
181
+ throw new CodebusError(`could not complete GitHub sign-in: ${exErr.message}`);
182
+ }
183
+ // github_web_login() RPC — same call the web page makes, EXCEPT this surface
184
+ // passes p_surface: "cli" (0080_agent_tokens). Before 0080 both the CLI and
185
+ // the web app shared ONE token per person-linked agent, so whichever surface
186
+ // logged in last silently rotated the other's stored token out from under
187
+ // it (the CLI/web auth ping-pong). p_surface scopes rotation to THIS
188
+ // surface's own credential only — logging in here never invalidates a live
189
+ // web session for the same person, and vice versa.
190
+ const { data, error: rpcErr } = await sb.rpc("github_web_login", { p_surface: "cli" });
191
+ await sb.auth.signOut(); // proof consumed; the agent token takes over
192
+ server.close();
193
+ if (rpcErr)
194
+ throw new CodebusError(mapGithubWebLoginError(rpcErr.message));
195
+ const res = data;
196
+ persistWebLogin(url, anonKey, res);
197
+ const facts = await validateConnection({ url, anonKey, workspace: res.workspace, token: res.token });
198
+ if (o.json) {
199
+ console.log(JSON.stringify({ ...facts, rotated: res.rotated ?? false }, null, 2));
200
+ return;
201
+ }
202
+ console.log(`Logged in as ${facts.agent} (person: ${facts.person ?? res.person_slug}) @ ${facts.workspace} via GitHub.`);
203
+ }
204
+ /* c8 ignore stop */
205
+ //# sourceMappingURL=github-login.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github-login.js","sourceRoot":"","sources":["../../src/commands/github-login.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAe,MAAM,WAAW,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAuB,MAAM,uBAAuB,CAAC;AAC1E,OAAO,EAAa,cAAc,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,uEAAuE;AACvE,2EAA2E;AAC3E,4EAA4E;AAC5E,gFAAgF;AAChF,EAAE;AACF,2EAA2E;AAC3E,qEAAqE;AACrE,wEAAwE;AACxE,kDAAkD;AAElD,MAAM,cAAc,GAAG,0CAA0C,CAAC;AAClE,MAAM,mBAAmB,GAAG,OAAO,CAAC,CAAC,+CAA+C;AAapF,MAAM,UAAU,iBAAiB,CAAC,IAAY,EAAE,KAAa;IAC3D,MAAM,UAAU,GAAG,oBAAoB,IAAI,mBAAmB,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;IAC1F,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,UAAU,EAAE,mBAAmB,EAAE,IAAI,EAAE,EAAE,CAAC;AACpF,CAAC;AAWD,MAAM,UAAU,aAAa,CAAC,MAA0B,EAAE,aAAqB;IAC7E,kFAAkF;IAClF,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,EAAE,kBAAkB,CAAC,CAAC;IACrD,IAAI,CAAC,CAAC,QAAQ,KAAK,WAAW;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;IAEvE,MAAM,GAAG,GAAG,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACxC,IAAI,GAAG,EAAE,CAAC;QACR,MAAM,IAAI,GAAG,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;QACrD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,wCAAwC,IAAI,IAAI,GAAG,EAAE,EAAE,CAAC;IACtF,CAAC;IAED,MAAM,KAAK,GAAG,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC1C,IAAI,CAAC,KAAK,IAAI,KAAK,KAAK,aAAa,EAAE,CAAC;QACtC,wEAAwE;QACxE,+DAA+D;QAC/D,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,gDAAgD,EAAE,CAAC;IACjF,CAAC;IAED,MAAM,IAAI,GAAG,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACxC,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,mCAAmC,EAAE,CAAC;IAE7E,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AAC5B,CAAC;AAaD,MAAM,UAAU,eAAe,CAAC,GAAW,EAAE,OAAe,EAAE,GAAmB;IAC/E,OAAO,cAAc,CAAC;QACpB,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS;QACtC,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,CAAC,WAAW;KACjE,CAAC,CAAC;AACL,CAAC;AAED,gFAAgF;AAChF,0EAA0E;AAC1E,mDAAmD;AACnD,+EAA+E;AAC/E,2CAA2C;AAC3C,mFAAmF;AACnF,yEAAyE;AACzE,MAAM,UAAU,sBAAsB,CAAC,OAAe,EAAE,KAAc;IACpE,IAAI,sCAAsC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACzD,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,KAAK,GAAG,CAAC,CAAC,CAAC,sBAAsB,CAAC;QAC3D,OAAO,6EAA6E;cAChF,mCAAmC,GAAG,gDAAgD,CAAC;IAC7F,CAAC;IACD,IAAI,0BAA0B,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QAC7C,OAAO,qFAAqF;cACxF,kEAAkE,CAAC;IACzE,CAAC;IACD,IAAI,8CAA8C,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACjE,OAAO,2DAA2D,CAAC;IACrE,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,gFAAgF;AAChF,wEAAwE;AACxE,4EAA4E;AAC5E,gFAAgF;AAChF,8EAA8E;AAC9E,6EAA6E;AAC7E,+EAA+E;AAC/E,gFAAgF;AAEhF,qHAAqH;AACrH,8EAA8E;AAC9E,KAAK,UAAU,cAAc,CAAC,GAAW,EAAE,CAAY;IACrD,IAAI,OAAO,GAAG,CAAC,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IACzD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,GAAG,0BAA0B,CAAC,CAAC;QAC1D,IAAI,GAAG,CAAC,EAAE;YAAE,OAAO,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAA2B,CAAA,CAAC,OAAO,CAAC;IAC3E,CAAC;IACD,IAAI,CAAC,OAAO;QACV,MAAM,IAAI,YAAY,CAAC,sCAAsC,GAAG,+CAA+C,CAAC,CAAC;IACnH,OAAO,OAAO,CAAC;AACjB,CAAC;AACD,oBAAoB;AAEpB,qGAAqG;AACrG,gFAAgF;AAChF,4EAA4E;AAC5E,SAAS,WAAW,CAAC,SAAiB;IACpC,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM;QAChD,CAAC,CAAC,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC;IACtD,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IACzF,IAAI,CAAC;QACH,QAAQ,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,GAAsD,CAAC,CAAC,CAAC;QAClF,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAUD,6EAA6E;AAC7E,4DAA4D;AAC5D,SAAS,mBAAmB,CAAC,aAAqB;IAChD,OAAO,IAAI,OAAO,CAAC,CAAC,aAAa,EAAE,YAAY,EAAE,EAAE;QACjD,IAAI,WAAoC,CAAC;QACzC,IAAI,UAA+B,CAAC;QACpC,MAAM,KAAK,GAAG,IAAI,OAAO,CAAS,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,GAAG,WAAW,GAAG,GAAG,CAAC,CAAC,UAAU,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAE1F,MAAM,MAAM,GAAW,YAAY,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;YAC/C,MAAM,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;YACrD,IAAI,MAAM,CAAC,EAAE,KAAK,KAAK,IAAI,MAAM,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;gBAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;gBAAC,OAAO;YAAC,CAAC;YAC5F,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;gBACd,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC;qBAChD,GAAG,CAAC,qGAAqG,CAAC,CAAC;gBAC9G,YAAY,CAAC,KAAK,CAAC,CAAC;gBACpB,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAC3B,CAAC;iBAAM,CAAC;gBACN,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC;qBAChD,GAAG,CAAC,sCAAsC,MAAM,CAAC,MAAM,MAAM,CAAC,CAAC;gBAClE,YAAY,CAAC,KAAK,CAAC,CAAC;gBACpB,UAAU,CAAC,IAAI,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;YAC9C,CAAC;QACH,CAAC,CAAC,CAAC;QACH,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,UAAU,CAAC,IAAI,YAAY,CAAC,4EAA4E,CAAC,CAAC,CAAC;QAC7G,CAAC,EAAE,mBAAmB,CAAC,CAAC;QACxB,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACrE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE;YACjC,MAAM,IAAI,GAAI,MAAM,CAAC,OAAO,EAAuB,CAAC,IAAI,CAAC;YACzD,aAAa,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC9F,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AACD,oBAAoB;AAEpB,gFAAgF;AAChF,4EAA4E;AAC5E,oDAAoD;AACpD,yHAAyH;AACzH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,CAAiC;IACpE,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,cAAc,CAAC;IAC/D,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IAC7C,MAAM,KAAK,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAE9C,+EAA+E;IAC/E,uEAAuE;IACvE,kDAAkD;IAClD,MAAM,EAAE,GAAmB,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE;QACpD,IAAI,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,cAAc,EAAE,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,kBAAkB,EAAE,KAAK,EAAE;KACtG,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,KAAK,CAAC,CAAC;IAChD,MAAM,QAAQ,GAAG,iBAAiB,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACvD,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;IACjF,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,CAAC,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,YAAY,CAAC,0BAA0B,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;YACtE,CAAC,CAAC,8CAA8C;YAChD,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IACxB,CAAC;IAED,IAAI,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC;QAAE,OAAO,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC;;QACnF,OAAO,CAAC,GAAG,CAAC,4DAA4D,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC;IAE1F,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QAAC,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC;IAAC,CAAC;YACzB,CAAC,CAAC,oCAAoC,CAAC,CAAC;IAEhD,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,CAAC;IACpE,IAAI,KAAK,EAAE,CAAC;QAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAAC,MAAM,IAAI,YAAY,CAAC,sCAAsC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IAAC,CAAC;IAE7G,6EAA6E;IAC7E,4EAA4E;IAC5E,6EAA6E;IAC7E,0EAA0E;IAC1E,qEAAqE;IACrE,2EAA2E;IAC3E,mDAAmD;IACnD,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,GAAG,CAAC,kBAAkB,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;IACvF,MAAM,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,6CAA6C;IACtE,MAAM,CAAC,KAAK,EAAE,CAAC;IACf,IAAI,MAAM;QAAE,MAAM,IAAI,YAAY,CAAC,sBAAsB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;IAE3E,MAAM,GAAG,GAAG,IAAsB,CAAC;IACnC,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;IAEnC,MAAM,KAAK,GAAG,MAAM,kBAAkB,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;IACrG,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;QAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAAC,OAAO;IAAC,CAAC;IAC1G,OAAO,CAAC,GAAG,CAAC,gBAAgB,KAAK,CAAC,KAAK,aAAa,KAAK,CAAC,MAAM,IAAI,GAAG,CAAC,WAAW,OAAO,KAAK,CAAC,SAAS,cAAc,CAAC,CAAC;AAC3H,CAAC;AACD,oBAAoB"}
@@ -0,0 +1,88 @@
1
+ import { CodebusError } from "../errors.js";
2
+ import { loadGraphSnapshot, getGraphBuiltCommit, checkStaleness } from "../graph.js";
3
+ import { fetchRemoteStatus } from "../graph-remote.js";
4
+ /**
5
+ * CLI command: codebus graph status
6
+ * Prints local graph metadata + staleness, and (A6) the hub's attachment
7
+ * state and remote freshness for the connected repo, when reachable.
8
+ * The local fields are unchanged/additive vs pre-A6 for scripts already
9
+ * parsing --json output; `attachmentState`/`remote` are new.
10
+ */
11
+ export async function graphStatusCmd(options) {
12
+ try {
13
+ const repoRoot = options.repoRoot || process.cwd();
14
+ const snapshot = loadGraphSnapshot(repoRoot);
15
+ // Remote leg degrades to null silently (missing credentials, no git
16
+ // remote, repo not connected, or any RPC failure) — never fails the
17
+ // command just because the local leg already has an answer.
18
+ const remote = await fetchRemoteStatus(repoRoot, options.repo).catch(() => null);
19
+ if (!snapshot && !remote) {
20
+ throw new CodebusError("No graphify-out/graph.json found, and no remote-connected repo status reachable. Run graphify first, or pass --repo.", 1);
21
+ }
22
+ const status = {};
23
+ if (snapshot) {
24
+ const builtCommit = getGraphBuiltCommit(snapshot);
25
+ const staleness = await checkStaleness(snapshot, repoRoot, "dirty-only");
26
+ status.builtAtCommit = builtCommit;
27
+ status.isStale = staleness.isStale;
28
+ status.isDirty = staleness.isDirty;
29
+ status.stalenessNote = staleness.note;
30
+ status.nodeCount = snapshot.nodes?.length || 0;
31
+ status.edgeCount = snapshot.links?.length || 0;
32
+ }
33
+ if (remote) {
34
+ status.attachmentState = remote.attachmentState;
35
+ status.remote = {
36
+ repo: remote.repoSlug,
37
+ attachmentState: remote.attachmentState,
38
+ grade: remote.grade,
39
+ freshness: remote.freshness,
40
+ stale: remote.stale,
41
+ noGraph: remote.noGraph,
42
+ servingSha: remote.servingSha7,
43
+ headSha: remote.headSha7,
44
+ };
45
+ }
46
+ if (options.json) {
47
+ console.log(JSON.stringify(status, null, 2));
48
+ }
49
+ else {
50
+ if (snapshot) {
51
+ // Pre-A6 text-output contract, byte-for-byte (test/integration/ask.test.ts
52
+ // pins "Built at:"/"Nodes:"/"Edges:"/"Stale:") — the local leg's plain-text
53
+ // output must stay unchanged/additive, exactly like its JSON fields already
54
+ // are; the remote leg below is the only new output.
55
+ console.log(`Built at: ${status.builtAtCommit}`);
56
+ console.log(`Nodes: ${status.nodeCount}, Edges: ${status.edgeCount}`);
57
+ console.log(`Stale: ${status.isStale}`);
58
+ if (status.stalenessNote)
59
+ console.log(`Note: ${status.stalenessNote}`);
60
+ }
61
+ else {
62
+ console.log("Local: no graphify-out/graph.json found");
63
+ }
64
+ if (remote) {
65
+ console.log(`Remote (${remote.repoSlug}): attachment=${remote.attachmentState ?? "unknown"} grade=${remote.grade ?? "unknown"}`);
66
+ console.log(` Freshness: ${remote.freshness ?? "unknown"} (serving ${remote.servingSha7 ?? "—"}, head ${remote.headSha7 ?? "—"})`);
67
+ }
68
+ else {
69
+ console.log("Remote: not connected / not reachable");
70
+ }
71
+ }
72
+ }
73
+ catch (err) {
74
+ if (err instanceof CodebusError)
75
+ throw err;
76
+ throw new CodebusError(`Failed to get graph status: ${err instanceof Error ? err.message : String(err)}`, 1);
77
+ }
78
+ }
79
+ /**
80
+ * Register the graph command.
81
+ */
82
+ export function registerGraph(program, g) {
83
+ const graphCmd = program.command("graph");
84
+ g(graphCmd.command("status"))
85
+ .option("--repo <slug>", "check a specific connected repo's remote status (auto-detected from git remote if omitted)")
86
+ .action((opts) => graphStatusCmd(opts));
87
+ }
88
+ //# sourceMappingURL=graph.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph.js","sourceRoot":"","sources":["../../src/commands/graph.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ import { resolveConfig } from "../config.js";
2
+ import { makeCtx, workspaceId } from "../client.js";
3
+ import { CodebusError } from "../errors.js";
4
+ // Workspace health: the CEO view, computed from tables that already record
5
+ // everything (questions timestamps, task/PR status, escalations, session_log).
6
+ export async function healthCmd(o) {
7
+ const ctx = await makeCtx(resolveConfig(o));
8
+ const ws = await workspaceId(ctx);
9
+ const { data, error } = await ctx.supabase.rpc("bus_health", { p_workspace: ws });
10
+ if (error)
11
+ throw new CodebusError(error.message);
12
+ if (o.json) {
13
+ console.log(JSON.stringify(data, null, 2));
14
+ return;
15
+ }
16
+ const h = data;
17
+ const fmt = (v, suffix = "") => (v === null || v === undefined ? "—" : `${v}${suffix}`);
18
+ console.log(`Workspace Health (${ctx.workspaceSlug})`);
19
+ console.log(`Open Questions: ${fmt(h.open_questions)}`);
20
+ console.log(`Questions >24h: ${fmt(h.questions_over_24h)}`);
21
+ console.log(`Blocked Tasks: ${fmt(h.blocked_tasks)}`);
22
+ console.log(`Review Queue: ${fmt(h.review_queue)}`);
23
+ console.log(`Escalations (7d): ${fmt(h.escalations_7d)} (resolved: ${fmt(h.escalations_resolved_7d)})`);
24
+ console.log(`Escalation Rate (7d): ${fmt(h.escalation_rate_7d)}`);
25
+ console.log(`Median Answer Time: ${fmt(h.median_answer_minutes, "m")} (p95: ${fmt(h.p95_answer_minutes, "m")})`);
26
+ console.log(`Median Blocker Age: ${fmt(h.median_blocker_age_hours, "h")}`);
27
+ console.log(`Tasks Completed (7d): ${fmt(h.tasks_completed_7d)}`);
28
+ console.log(`Reviews Done (7d): ${fmt(h.reviews_completed_7d)}`);
29
+ console.log(`PRs Merged (7d): ${fmt(h.prs_merged_7d)}`);
30
+ console.log(`Session Starts (7d): ${fmt(h.session_starts_7d)} | digests: ${fmt(h.digest_refreshes_7d)} | next: ${fmt(h.next_invocations_7d)}`);
31
+ console.log(`Most Blocked Repo: ${fmt(h.most_blocked_repo)}`);
32
+ console.log(`Most Asked Repo: ${fmt(h.most_asked_repo)}`);
33
+ }
34
+ //# sourceMappingURL=health.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/commands/health.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,83 @@
1
+ import { resolveConfig } from "../config.js";
2
+ import { makeCtx, workspaceId, projectId, identityIsGuessed, guessedIdentityWarning } from "../client.js";
3
+ import { render } from "../output.js";
4
+ import { CodebusError } from "../errors.js";
5
+ import { isActionableMessage } from "../directives.js";
6
+ /**
7
+ * Shared core: fetch inbox items with optional filters.
8
+ * Used by both inboxCmd and MCP codebus_inbox tool.
9
+ *
10
+ * Ordering is OLDEST-FIRST (delivery gap #2): the old `created_at desc` order
11
+ * meant a newest-first drain starved old mail — an agent working the top of
12
+ * its inbox never reached anything below the newest few items, so old
13
+ * messages sat forever. `watch`'s backlog drain and `codebus inbox` both
14
+ * read this in arrival order now.
15
+ *
16
+ * `--unread` gates on handled_at IS NULL, not read_at (delivery gap #5/#6):
17
+ * read_at is a pure "opened" marker now — peeking a message must not clear it
18
+ * from every unread surface forever. handled_at clears on reply or explicit
19
+ * `codebus ack`.
20
+ */
21
+ export async function fetchInbox(ctx, opts) {
22
+ // recipient rows for me, joined to message body (RLS limits to my rows + member workspaces)
23
+ let q = ctx.supabase.from("message_recipients")
24
+ .select("read_at, handled_at, archived_at, messages!inner(display_id, type, subject, body, headline, required_action, in_reply_to, from_agent_id, created_at, project_id, workspace_id)")
25
+ .is("archived_at", null);
26
+ if (opts.unread)
27
+ q = q.is("handled_at", null);
28
+ if (opts.ws)
29
+ q = q.eq("messages.workspace_id", opts.ws);
30
+ if (opts.projId)
31
+ q = q.eq("messages.project_id", opts.projId);
32
+ const { data, error } = await q.order("created_at", { foreignTable: "messages", ascending: true });
33
+ if (error)
34
+ throw new CodebusError(error.message);
35
+ const rows = (data ?? [])
36
+ .map((r) => ({
37
+ ...r.messages,
38
+ read: r.read_at ? "read" : "unread",
39
+ handled: r.handled_at ? "handled" : "unhandled",
40
+ }))
41
+ .sort((a, b) => new Date(a.created_at).getTime() - new Date(b.created_at).getTime())
42
+ .filter((m) => !opts.type || m.type === opts.type);
43
+ return rows;
44
+ }
45
+ export async function inboxCmd(o) {
46
+ const ctx = await makeCtx(resolveConfig(o));
47
+ const ws = await workspaceId(ctx);
48
+ const projId = await projectId(ctx, ws, o.project);
49
+ const rows = await fetchInbox(ctx, {
50
+ unread: o.unread,
51
+ type: o.type,
52
+ projId,
53
+ ws,
54
+ });
55
+ // A guessed identity showing MAIL is the sharpest version of this risk —
56
+ // stdout, not stderr, so it survives in a transcript even if stderr scrolls
57
+ // past unread (field incident: a fresh session almost acted on it).
58
+ if (!o.json && identityIsGuessed(ctx))
59
+ process.stdout.write(guessedIdentityWarning(ctx, "messages"));
60
+ // RC2 field incident: a fresh inbox of 507 inbound/500 unread/504 unhandled
61
+ // broke down to 501 note (required_action NULL) and only 4 ask — a raw
62
+ // count told the reader nothing about how much of it actually needed a
63
+ // reply. Split the count the same way bus_digest's class 7/8 does
64
+ // (isActionableMessage, kept in lockstep in directives.ts) so that
65
+ // distinction is visible here too, not just in the ranked digest.
66
+ if (!o.json && rows.length > 0) {
67
+ const actionable = rows.filter((m) => isActionableMessage(m)).length;
68
+ console.log(`inbox: ${rows.length} shown — ${actionable} needs-reply, ${rows.length - actionable} FYI`);
69
+ }
70
+ // Delivery gap #9: headline/required_action render FIRST, ahead of the
71
+ // table, when present — that's the whole point of the structured-handover
72
+ // fields (dead columns since 0036 until this migration wired them up).
73
+ if (!o.json) {
74
+ for (const m of rows) {
75
+ if (m.headline) {
76
+ const ra = m.required_action ? ` — REQUIRED ACTION: ${m.required_action}` : "";
77
+ console.log(`[${m.display_id}] HEADLINE: ${m.headline}${ra}`);
78
+ }
79
+ }
80
+ }
81
+ console.log(render(rows, { json: !!o.json }));
82
+ }
83
+ //# sourceMappingURL=inbox.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inbox.js","sourceRoot":"","sources":["../../src/commands/inbox.ts"],"names":[],"mappings":"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"}