@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.
- package/bin/codebus.js +2 -0
- package/dist/binding-guard.js +97 -0
- package/dist/binding-guard.js.map +1 -0
- package/dist/client.js +94 -0
- package/dist/client.js.map +1 -0
- package/dist/commands/ack.js +47 -0
- package/dist/commands/ack.js.map +1 -0
- package/dist/commands/archive.js +21 -0
- package/dist/commands/archive.js.map +1 -0
- package/dist/commands/as.js +299 -0
- package/dist/commands/as.js.map +1 -0
- package/dist/commands/ask.js +189 -0
- package/dist/commands/ask.js.map +1 -0
- package/dist/commands/auth.js +33 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/checkin.js +235 -0
- package/dist/commands/checkin.js.map +1 -0
- package/dist/commands/decision.js +52 -0
- package/dist/commands/decision.js.map +1 -0
- package/dist/commands/digest.js +117 -0
- package/dist/commands/digest.js.map +1 -0
- package/dist/commands/doctor.js +106 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/factory.js +191 -0
- package/dist/commands/factory.js.map +1 -0
- package/dist/commands/github-login.js +205 -0
- package/dist/commands/github-login.js.map +1 -0
- package/dist/commands/graph.js +88 -0
- package/dist/commands/graph.js.map +1 -0
- package/dist/commands/health.js +34 -0
- package/dist/commands/health.js.map +1 -0
- package/dist/commands/inbox.js +83 -0
- package/dist/commands/inbox.js.map +1 -0
- package/dist/commands/ingest.js +553 -0
- package/dist/commands/ingest.js.map +1 -0
- package/dist/commands/init.js +97 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/install.js +520 -0
- package/dist/commands/install.js.map +1 -0
- package/dist/commands/invite.js +152 -0
- package/dist/commands/invite.js.map +1 -0
- package/dist/commands/jira.js +237 -0
- package/dist/commands/jira.js.map +1 -0
- package/dist/commands/join.js +96 -0
- package/dist/commands/join.js.map +1 -0
- package/dist/commands/links.js +66 -0
- package/dist/commands/links.js.map +1 -0
- package/dist/commands/login.js +84 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/morning.js +121 -0
- package/dist/commands/morning.js.map +1 -0
- package/dist/commands/next.js +66 -0
- package/dist/commands/next.js.map +1 -0
- package/dist/commands/onboarding.js +109 -0
- package/dist/commands/onboarding.js.map +1 -0
- package/dist/commands/pack.js +276 -0
- package/dist/commands/pack.js.map +1 -0
- package/dist/commands/plan-gh.js +425 -0
- package/dist/commands/plan-gh.js.map +1 -0
- package/dist/commands/plan.js +465 -0
- package/dist/commands/plan.js.map +1 -0
- package/dist/commands/pr.js +88 -0
- package/dist/commands/pr.js.map +1 -0
- package/dist/commands/question.js +142 -0
- package/dist/commands/question.js.map +1 -0
- package/dist/commands/read.js +84 -0
- package/dist/commands/read.js.map +1 -0
- package/dist/commands/refs.js +357 -0
- package/dist/commands/refs.js.map +1 -0
- package/dist/commands/reply.js +38 -0
- package/dist/commands/reply.js.map +1 -0
- package/dist/commands/repo.js +1198 -0
- package/dist/commands/repo.js.map +1 -0
- package/dist/commands/report.js +41 -0
- package/dist/commands/report.js.map +1 -0
- package/dist/commands/resolve-refs.js +21 -0
- package/dist/commands/resolve-refs.js.map +1 -0
- package/dist/commands/resolve.js +93 -0
- package/dist/commands/resolve.js.map +1 -0
- package/dist/commands/send.js +168 -0
- package/dist/commands/send.js.map +1 -0
- package/dist/commands/sent.js +22 -0
- package/dist/commands/sent.js.map +1 -0
- package/dist/commands/session.js +426 -0
- package/dist/commands/session.js.map +1 -0
- package/dist/commands/statusline.js +43 -0
- package/dist/commands/statusline.js.map +1 -0
- package/dist/commands/task.js +140 -0
- package/dist/commands/task.js.map +1 -0
- package/dist/commands/tick.js +233 -0
- package/dist/commands/tick.js.map +1 -0
- package/dist/commands/upgrade.js +76 -0
- package/dist/commands/upgrade.js.map +1 -0
- package/dist/commands/watch.js +169 -0
- package/dist/commands/watch.js.map +1 -0
- package/dist/commands/whoami.js +27 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/config.js +103 -0
- package/dist/config.js.map +1 -0
- package/dist/directives.js +102 -0
- package/dist/directives.js.map +1 -0
- package/dist/errors.js +110 -0
- package/dist/errors.js.map +1 -0
- package/dist/git-hooks.js +116 -0
- package/dist/git-hooks.js.map +1 -0
- package/dist/graph-bootstrap.js +95 -0
- package/dist/graph-bootstrap.js.map +1 -0
- package/dist/graph-remote.js +889 -0
- package/dist/graph-remote.js.map +1 -0
- package/dist/graph.js +335 -0
- package/dist/graph.js.map +1 -0
- package/dist/index.js +154 -0
- package/dist/index.js.map +1 -0
- package/dist/kit/graph-publish.mjs +400 -0
- package/dist/mail-latency.js +120 -0
- package/dist/mail-latency.js.map +1 -0
- package/dist/mcp-registry.js +859 -0
- package/dist/mcp-registry.js.map +1 -0
- package/dist/mcp.js +193 -0
- package/dist/mcp.js.map +1 -0
- package/dist/output.js +12 -0
- package/dist/output.js.map +1 -0
- package/dist/positioning.js +21 -0
- package/dist/positioning.js.map +1 -0
- package/dist/rolestore.js +89 -0
- package/dist/rolestore.js.map +1 -0
- package/dist/session.js +49 -0
- package/dist/session.js.map +1 -0
- package/dist/sessionstore.js +736 -0
- package/dist/sessionstore.js.map +1 -0
- package/dist/version-check.js +97 -0
- package/dist/version-check.js.map +1 -0
- 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":"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"}
|
|
@@ -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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"}
|