@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,189 @@
|
|
|
1
|
+
import { CodebusError } from "../errors.js";
|
|
2
|
+
import { rankByRelevance, formatNodeCitation, formatEdgeCitation, checkStaleness, isUsingFallbackSnapshot, isProseNode } from "../graph.js";
|
|
3
|
+
import { resolveGraphSource } from "../graph-remote.js";
|
|
4
|
+
/**
|
|
5
|
+
* Core ask logic shared by CLI and MCP.
|
|
6
|
+
* Returns a budgeted, cited answer over the graph.
|
|
7
|
+
*
|
|
8
|
+
* A6: routes through resolveGraphSource (local current wins unless an
|
|
9
|
+
* explicit `repo` names a different one -> remote -> last-good -> none).
|
|
10
|
+
* When no `repo` is given and a local graphify-out/ snapshot exists, this is
|
|
11
|
+
* BIT-IDENTICAL to the pre-A6 behavior and touches no network at all.
|
|
12
|
+
*/
|
|
13
|
+
export async function askGraph(question, options = {}) {
|
|
14
|
+
const budgetTokens = options.budget ?? 500;
|
|
15
|
+
const repoRoot = options.repoRoot || process.cwd();
|
|
16
|
+
const resolved = await resolveGraphSource(question, { repo: options.repo, repoRoot });
|
|
17
|
+
const snapshot = resolved.snapshot;
|
|
18
|
+
if (!snapshot) {
|
|
19
|
+
return {
|
|
20
|
+
answer: "",
|
|
21
|
+
citations: [],
|
|
22
|
+
error: options.repo
|
|
23
|
+
? `No local graphify-out/graph.json found, and no remote graph reachable for repo '${options.repo}'.`
|
|
24
|
+
: "No graphify-out/graph.json found. Run `graphify` or check the repo root.",
|
|
25
|
+
source: resolved.source,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
const isRemote = resolved.source === "remote";
|
|
29
|
+
// Check if we're using a fallback (last-good) snapshot due to a failed build
|
|
30
|
+
const usingFallback = isRemote ? false : resolved.source === "last-good" || isUsingFallbackSnapshot(repoRoot);
|
|
31
|
+
// Check staleness: local checkStaleness for local/last-good sources; the
|
|
32
|
+
// remote leg already computed its own 3-state verdict via graph_status.
|
|
33
|
+
const staleness = isRemote
|
|
34
|
+
? (resolved.staleness ?? { isStale: false, isDirty: false, unknown: true })
|
|
35
|
+
: await checkStaleness(snapshot, repoRoot, "dirty-only");
|
|
36
|
+
// Rank by relevance
|
|
37
|
+
const { nodes: rankedNodes, edges, matchCount: rankedMatchCount } = rankByRelevance(snapshot, question, 15);
|
|
38
|
+
// Remote-only: rankByRelevance drops score-0 matches (graph.ts), which would
|
|
39
|
+
// silently vanish a trigram-only graph_search hit that shares no literal
|
|
40
|
+
// substring with the query. Append any search hit missing from the ranked
|
|
41
|
+
// result rather than dropping it (Round-3 review finding 7's sibling
|
|
42
|
+
// concern for graph_search, same "never silently drop a real hit" rule).
|
|
43
|
+
let nodes = rankedNodes;
|
|
44
|
+
let matchCount = rankedMatchCount;
|
|
45
|
+
if (isRemote && resolved.searchHits && resolved.searchHits.length > 0) {
|
|
46
|
+
const present = new Set(rankedNodes.map((n) => n.id));
|
|
47
|
+
const missing = resolved.searchHits.filter((h) => !present.has(h.id));
|
|
48
|
+
if (missing.length > 0) {
|
|
49
|
+
nodes = [...rankedNodes, ...missing];
|
|
50
|
+
matchCount = rankedMatchCount + missing.length;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// [remote@sha7] citation markers: applied to every citation pushed below
|
|
54
|
+
// when the answer was built from a remote slice, so a reader can tell a
|
|
55
|
+
// remote-sourced citation apart from a local one at a glance.
|
|
56
|
+
const remoteMarker = isRemote && resolved.remoteSha7 ? ` [remote@${resolved.remoteSha7}]` : "";
|
|
57
|
+
const cite = (c) => c + remoteMarker;
|
|
58
|
+
// Build answer with budget tracking
|
|
59
|
+
let answer = "";
|
|
60
|
+
const citations = [];
|
|
61
|
+
let tokens = 0;
|
|
62
|
+
if (matchCount === 0) {
|
|
63
|
+
answer = `No results found for "${question}".`;
|
|
64
|
+
tokens += 10;
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
// Add summary
|
|
68
|
+
const summary = `Found ${matchCount} relevant items in the graph:`;
|
|
69
|
+
answer = summary + "\n";
|
|
70
|
+
tokens += 5;
|
|
71
|
+
// Partition nodes into prose (docs/decisions) and code for distinct sections
|
|
72
|
+
const proseNodes = nodes.filter(isProseNode);
|
|
73
|
+
const codeNodes = nodes.filter((n) => !isProseNode(n));
|
|
74
|
+
// Add prose/doc nodes first under a dedicated section header
|
|
75
|
+
if (proseNodes.length > 0) {
|
|
76
|
+
answer += "\n## Docs & Decisions:\n";
|
|
77
|
+
tokens += 3;
|
|
78
|
+
for (const node of proseNodes) {
|
|
79
|
+
if (tokens >= budgetTokens * 0.85)
|
|
80
|
+
break;
|
|
81
|
+
const citation = cite(formatNodeCitation(node));
|
|
82
|
+
const line = `- ${node.label} (${citation})\n`;
|
|
83
|
+
answer += line;
|
|
84
|
+
citations.push(citation);
|
|
85
|
+
tokens += Math.ceil(line.split(/\s+/).length);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// Add code nodes
|
|
89
|
+
if (codeNodes.length > 0) {
|
|
90
|
+
answer += "\n## Files & Symbols:\n";
|
|
91
|
+
tokens += 3;
|
|
92
|
+
for (const node of codeNodes) {
|
|
93
|
+
if (tokens >= budgetTokens * 0.85)
|
|
94
|
+
break; // Leave 15% headroom
|
|
95
|
+
const citation = cite(formatNodeCitation(node));
|
|
96
|
+
const line = `- ${node.label} (${citation})\n`;
|
|
97
|
+
answer += line;
|
|
98
|
+
citations.push(citation);
|
|
99
|
+
tokens += Math.ceil(line.split(/\s+/).length);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// Add edges
|
|
103
|
+
if (edges.length > 0) {
|
|
104
|
+
answer += "\n## Contexts & Relationships:\n";
|
|
105
|
+
tokens += 3;
|
|
106
|
+
for (const edge of edges) {
|
|
107
|
+
if (tokens >= budgetTokens * 0.85)
|
|
108
|
+
break;
|
|
109
|
+
const citation = cite(formatEdgeCitation(edge));
|
|
110
|
+
const nodesList = edge.nodes.slice(0, 3).join(", ") + (edge.nodes.length > 3 ? "…" : "");
|
|
111
|
+
const line = `- ${edge.label}: ${nodesList} (${citation})\n`;
|
|
112
|
+
answer += line;
|
|
113
|
+
citations.push(citation);
|
|
114
|
+
tokens += Math.ceil(line.split(/\s+/).length);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// Truncate if over budget
|
|
118
|
+
if (tokens > budgetTokens) {
|
|
119
|
+
const lines = answer.split("\n");
|
|
120
|
+
answer = "";
|
|
121
|
+
tokens = 0;
|
|
122
|
+
for (const line of lines) {
|
|
123
|
+
const lineTokens = Math.ceil(line.split(/\s+/).length);
|
|
124
|
+
if (tokens + lineTokens <= budgetTokens) {
|
|
125
|
+
answer += line + "\n";
|
|
126
|
+
tokens += lineTokens;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
answer += `\n[…truncated at ~${budgetTokens} tokens]`;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
// Add staleness note if applicable.
|
|
133
|
+
// When git is unavailable, staleness is unknown — surface that explicitly rather than
|
|
134
|
+
// silently claiming the snapshot is fresh.
|
|
135
|
+
let stalenessNote;
|
|
136
|
+
if (usingFallback) {
|
|
137
|
+
stalenessNote = "(using last-good snapshot; build may have failed)";
|
|
138
|
+
}
|
|
139
|
+
else if (staleness.unknown) {
|
|
140
|
+
stalenessNote = isRemote ? "(staleness unknown: remote)" : "(staleness unknown: git unavailable)";
|
|
141
|
+
}
|
|
142
|
+
else if (staleness.note) {
|
|
143
|
+
stalenessNote = staleness.note;
|
|
144
|
+
}
|
|
145
|
+
// Round-3 review finding 7: graph_subgraph's `truncated` flag means the
|
|
146
|
+
// returned slice may be missing reachable nodes within the requested depth
|
|
147
|
+
// — surface it rather than silently trusting an incomplete traversal.
|
|
148
|
+
if (isRemote && resolved.truncated) {
|
|
149
|
+
const truncNote = "remote slice truncated — some reachable nodes may be missing";
|
|
150
|
+
stalenessNote = stalenessNote ? `${stalenessNote}; ${truncNote}` : `(${truncNote})`;
|
|
151
|
+
}
|
|
152
|
+
return { answer, citations, stalenessNote, source: resolved.source };
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* CLI command: codebus ask <question>
|
|
156
|
+
*/
|
|
157
|
+
export async function askCmd(question, options) {
|
|
158
|
+
try {
|
|
159
|
+
const budget = options.budget ? parseInt(options.budget, 10) : 500;
|
|
160
|
+
const result = await askGraph(question, { budget, repoRoot: options.repoRoot, repo: options.repo });
|
|
161
|
+
if (result.error) {
|
|
162
|
+
throw new CodebusError(result.error, 1);
|
|
163
|
+
}
|
|
164
|
+
if (options.json) {
|
|
165
|
+
console.log(JSON.stringify(result, null, 2));
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
console.log(result.answer);
|
|
169
|
+
if (result.stalenessNote) {
|
|
170
|
+
console.log(`\n[${result.stalenessNote}]`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
catch (err) {
|
|
175
|
+
if (err instanceof CodebusError)
|
|
176
|
+
throw err;
|
|
177
|
+
throw new CodebusError(`Failed to query graph: ${err instanceof Error ? err.message : String(err)}`, 1);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Register the ask command.
|
|
182
|
+
*/
|
|
183
|
+
export function registerAsk(program, g) {
|
|
184
|
+
g(program.command("ask").argument("<question>", "question to ask the graph"))
|
|
185
|
+
.option("--budget <tokens>", "max output tokens (default 500)")
|
|
186
|
+
.option("--repo <slug>", "query a connected repo's remote graph instead of the local checkout")
|
|
187
|
+
.action((question, opts) => askCmd(question, opts));
|
|
188
|
+
}
|
|
189
|
+
//# sourceMappingURL=ask.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ask.js","sourceRoot":"","sources":["../../src/commands/ask.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { readdir, rm } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { CACHE_DIR } from "../session.js";
|
|
4
|
+
import { DIGEST_FILE } from "./digest.js";
|
|
5
|
+
// Cache hygiene: cached session JWTs embed agent uuids, which die on any
|
|
6
|
+
// `supabase db reset` — the CLI then fails with "not a member" until the
|
|
7
|
+
// stale cache is cleared. `codebus auth reset` removes session caches;
|
|
8
|
+
// --all also drops the digest snapshot.
|
|
9
|
+
async function resetCmd(o) {
|
|
10
|
+
let removed = 0;
|
|
11
|
+
try {
|
|
12
|
+
for (const f of await readdir(CACHE_DIR)) {
|
|
13
|
+
if (/^session-[0-9a-f]{16}\.json$/.test(f)) {
|
|
14
|
+
await rm(join(CACHE_DIR, f), { force: true });
|
|
15
|
+
removed++;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
// no cache dir yet — nothing to do
|
|
21
|
+
}
|
|
22
|
+
if (o.all) {
|
|
23
|
+
await rm(DIGEST_FILE, { force: true });
|
|
24
|
+
console.log(`cleared ${removed} session cache(s) + digest snapshot`);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
console.log(`cleared ${removed} session cache(s)`);
|
|
28
|
+
}
|
|
29
|
+
export function registerAuth(program, g) {
|
|
30
|
+
const auth = program.command("auth").description("session/auth utilities");
|
|
31
|
+
g(auth.command("reset")).option("--all", "also remove the digest snapshot").action(resetCmd);
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,yEAAyE;AACzE,yEAAyE;AACzE,uEAAuE;AACvE,wCAAwC;AACxC,KAAK,UAAU,QAAQ,CAAC,CAAoB;IAC1C,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,IAAI,CAAC;QACH,KAAK,MAAM,CAAC,IAAI,MAAM,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;YACzC,IAAI,8BAA8B,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC3C,MAAM,EAAE,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC9C,OAAO,EAAE,CAAC;YACZ,CAAC;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,mCAAmC;IACrC,CAAC;IACD,IAAI,CAAC,CAAC,GAAG,EAAE,CAAC;QACV,MAAM,EAAE,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,WAAW,OAAO,qCAAqC,CAAC,CAAC;QACrE,OAAO;IACT,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,WAAW,OAAO,mBAAmB,CAAC,CAAC;AACrD,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,OAAgB,EAAE,CAA0B;IACvE,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,wBAAwB,CAAC,CAAC;IAC3E,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,iCAAiC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AAC/F,CAAC"}
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import { resolveConfig } from "../config.js";
|
|
2
|
+
import { makeCtx } from "../client.js";
|
|
3
|
+
import { CodebusError } from "../errors.js";
|
|
4
|
+
import { loadRoles, saveRoles, rolesFile } from "./as.js";
|
|
5
|
+
import { startCmd } from "./session.js";
|
|
6
|
+
import { watchCmd } from "./watch.js";
|
|
7
|
+
import { recordSessionRole } from "../sessionstore.js";
|
|
8
|
+
import { stopHookInstalled, inClaudeCodeSession, codexHooksInstalled, inCodexSession, watchRecentlyArmed, MAIL_LATENCY_WARNING } from "../mail-latency.js";
|
|
9
|
+
// `codebus checkin <name>` — the one-line onboarding. Design brief:
|
|
10
|
+
// docs/checkin-design-brief.md. The author types this into any already-running
|
|
11
|
+
// agent session; from that moment the agent is addressable at <name> on the bus.
|
|
12
|
+
//
|
|
13
|
+
// What it does, in order:
|
|
14
|
+
// 1. authenticates as the AUTHOR using the machine's existing credential
|
|
15
|
+
// (config.json / env — the person-linked agent from `codebus login --github`),
|
|
16
|
+
// 2. calls checkin_role(<name>) — mints or rebinds a durable, author-owned
|
|
17
|
+
// principal named exactly what the author said (idempotent by name),
|
|
18
|
+
// 3. persists the returned token into the role store (~/.codebus/roles.json)
|
|
19
|
+
// and binds THIS SESSION (sessionstore.ts) to it,
|
|
20
|
+
// 4. re-runs session-start orientation AS the new identity, printing output
|
|
21
|
+
// written for the agent to read: who it is, its inbox, what's next, and
|
|
22
|
+
// how to participate.
|
|
23
|
+
//
|
|
24
|
+
// checkin does NOT bind the directory (owner decision §6.1, docs/plans/
|
|
25
|
+
// codebus-v2-reliability.md — reversed from the earlier design). A directory
|
|
26
|
+
// binding is now created ONLY by a deliberate `codebus as --bind`: checkin
|
|
27
|
+
// used to also claim the cwd's basename as an ambient default, which is
|
|
28
|
+
// exactly how a generic-but-real name ('CodeBus') or a decommissioned
|
|
29
|
+
// automation's leftover binding ends up silently handing an unrelated session
|
|
30
|
+
// somebody else's identity (FM-1/FM-7). Session-scoped identity plus an
|
|
31
|
+
// explicit opt-in for anything more durable is the whole fix.
|
|
32
|
+
//
|
|
33
|
+
// Failures surface loudly and verbatim — the competitor's worst failure class
|
|
34
|
+
// is agents that die silently (block/buzz issues #2265/#5500/#5495).
|
|
35
|
+
const PARTICIPATION = (slug) => [
|
|
36
|
+
"── How to participate (for the agent reading this) ─────────────────────────",
|
|
37
|
+
`You are '${slug}' on CodeBus, this workspace's coordination bus. Habits:`,
|
|
38
|
+
" • DURABLE AUTO-CHECK — Claude Code gets this for free via its Stop hook",
|
|
39
|
+
" (codebus install claude). Codex has its own native Stop hook too: run",
|
|
40
|
+
" `codebus install codex` ONCE to wire `codebus tick --hook` into",
|
|
41
|
+
" ~/.codex/hooks.json — after that, new mail surfaces automatically at",
|
|
42
|
+
" every Codex turn boundary (Codex feeds it back as your next prompt),",
|
|
43
|
+
" exactly like Claude Code. Without that install, fall back to:",
|
|
44
|
+
" • STANDING LOOP — whenever you are idle, run:",
|
|
45
|
+
" codebus watch --mine --first --timeout 280000",
|
|
46
|
+
" It blocks and exits the moment mail/work for you arrives (or quietly on",
|
|
47
|
+
" timeout). What it prints is a WORK ORDER, not a notification: read the",
|
|
48
|
+
" message, do what it asks in this session, and reply with the outcome —",
|
|
49
|
+
" never a bare acknowledgement. Then re-arm the loop.",
|
|
50
|
+
" • Between tasks and at natural pauses, check for work/mail:",
|
|
51
|
+
" codebus inbox (or MCP tool: codebus_inbox)",
|
|
52
|
+
" codebus next (or MCP tool: codebus_next)",
|
|
53
|
+
" • Read and reply (add --thread to walk a whole chain; --all to CC every",
|
|
54
|
+
" original recipient of a group send):",
|
|
55
|
+
" codebus read <id> [--thread] · codebus reply <id> --body \"...\" [--all]",
|
|
56
|
+
" • Mail that needed no reply but was actually handled: codebus ack <id>",
|
|
57
|
+
" • Check whether recipients read/handled what you sent: codebus sent",
|
|
58
|
+
" • Send to another agent or person:",
|
|
59
|
+
" codebus send --to <slug> --type note --body \"...\"",
|
|
60
|
+
" (add --headline/--required-action for a structured handover)",
|
|
61
|
+
" • Claim/finish work:",
|
|
62
|
+
" codebus task claim <id> · codebus task done <id> --evidence <ref>",
|
|
63
|
+
" • Record decisions / ask questions: codebus decision add · codebus question ask",
|
|
64
|
+
" • End your session with a handoff: codebus session end --summary \"...\"",
|
|
65
|
+
`Anyone on the bus can now reach you at '${slug}'.`,
|
|
66
|
+
"────────────────────────────────────────────────────────────────────────────",
|
|
67
|
+
].join("\n");
|
|
68
|
+
async function checkinCmd(name, o) {
|
|
69
|
+
const cfg = resolveConfig({ ...o, noRoleBinding: true });
|
|
70
|
+
const ctx = await makeCtx(cfg);
|
|
71
|
+
// p_function_role only when given — the RPC validates against the 0043
|
|
72
|
+
// vocabulary and its error names the allowed values, so pass user input
|
|
73
|
+
// through verbatim rather than pre-validating a second list here.
|
|
74
|
+
const args = { p_name: name, p_adopt: !!o.adopt };
|
|
75
|
+
if (o.role)
|
|
76
|
+
args.p_function_role = o.role;
|
|
77
|
+
const { data, error } = await ctx.supabase.rpc("checkin_role", args);
|
|
78
|
+
if (error) {
|
|
79
|
+
// Server messages are written to be actionable; pass them through verbatim
|
|
80
|
+
// and add the one hint the server can't know (the CLI flag spelling).
|
|
81
|
+
const hint = error.message.includes("unowned legacy role")
|
|
82
|
+
? `\n hint: re-run as: codebus checkin ${name} --adopt`
|
|
83
|
+
: error.message.includes("has no person_id")
|
|
84
|
+
? `\n hint: this machine's credential is not person-linked — run: codebus login --github`
|
|
85
|
+
: "";
|
|
86
|
+
throw new CodebusError(`checkin failed: ${error.message}${hint}`);
|
|
87
|
+
}
|
|
88
|
+
const r = data;
|
|
89
|
+
// Persist into the same store `codebus as` uses — checkin and as are one system.
|
|
90
|
+
const store = loadRoles();
|
|
91
|
+
store.roles[r.agent_slug] = { token: r.token, agent: r.agent_slug, added_at: new Date().toISOString() };
|
|
92
|
+
saveRoles(store);
|
|
93
|
+
// THIS SESSION (durable env id when the host has one, else process
|
|
94
|
+
// ancestry — sessionstore.ts): multiple agents must share one repository
|
|
95
|
+
// (researcher/planner/coder/verifier on the same checkout), so identity
|
|
96
|
+
// binds to the running session, never to the directory. checkin does NOT
|
|
97
|
+
// touch ~/.codebus/roles.json's `bindings` — that's `codebus as --bind`'s
|
|
98
|
+
// job alone, deliberately, so a checkin can never silently displace (or be
|
|
99
|
+
// displaced by) another agent's directory default (observed live:
|
|
100
|
+
// codex-host-ingress silently stole legacy-android-host-app from
|
|
101
|
+
// claude-master-planner's open session; and separately, a checkin from
|
|
102
|
+
// /tmp once bound the literal pattern 'tmp' machine-wide).
|
|
103
|
+
const sessionKey = recordSessionRole(r.agent_slug);
|
|
104
|
+
const verb = r.created ? "created" : r.adopted ? "adopted" : "rebound (token rotated)";
|
|
105
|
+
console.log(`✓ ${r.agent_slug} ${verb} — you own this name; the token is stored in ${rolesFile()}`);
|
|
106
|
+
if (sessionKey) {
|
|
107
|
+
console.log(`✓ THIS session now acts as ${r.agent_slug} (other sessions, including other dirs' bindings, are unaffected)`);
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
console.log(`⚠ could not read a durable session id or this session's process ancestry — identity did not bind. Re-run this checkin once that's fixed (doctor may help diagnose why).`);
|
|
111
|
+
}
|
|
112
|
+
console.log(` (to also make this directory's default identity ${r.agent_slug} for future sessions here: codebus as --bind ${r.agent_slug})`);
|
|
113
|
+
if (r.rotated && !r.adopted)
|
|
114
|
+
console.log(` note: any other session using the previous token for '${r.agent_slug}' must re-checkin.`);
|
|
115
|
+
if (o.json) {
|
|
116
|
+
console.log(JSON.stringify({ agent: r.agent_slug, created: r.created, adopted: r.adopted, rotated: r.rotated, session_bound: !!sessionKey }, null, 2));
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
// Orient AS the new identity: same output as `codebus session start`, which
|
|
120
|
+
// includes the first-ever-session welcome. The token override unpins the
|
|
121
|
+
// author's file identity for this call only.
|
|
122
|
+
console.log("");
|
|
123
|
+
await startCmd({ url: cfg.url, anonKey: cfg.anonKey, workspace: cfg.workspace, token: r.token });
|
|
124
|
+
console.log(PARTICIPATION(r.agent_slug));
|
|
125
|
+
// Auto-arm the listener (owner ruling: checkin should start the monitor).
|
|
126
|
+
// Skipped whenever THIS session is live inside an actual agentic-tool turn
|
|
127
|
+
// (Claude Code or, as of RC3, Codex) — blocking for a watch window would
|
|
128
|
+
// stall that turn for nothing regardless of whether a Stop hook is wired
|
|
129
|
+
// up, since a blocked turn gets no chance to run ANY hook, real-time
|
|
130
|
+
// listener or otherwise, until it unblocks. Everywhere else (a plain
|
|
131
|
+
// shell, or a tool session neither of these two detectors recognizes),
|
|
132
|
+
// one watch window opens right here: the checkin line makes the agent
|
|
133
|
+
// live.
|
|
134
|
+
//
|
|
135
|
+
// Bug fix (found while investigating PR #54 CI failures on
|
|
136
|
+
// checkin-command-coverage.test.ts's watch-window branch-selection
|
|
137
|
+
// suite — confirmed via a bisect against 65a448a/origin/main that this
|
|
138
|
+
// predates both that PR and #53, so it is not a regression either
|
|
139
|
+
// introduced): this gating condition used to be `!hookAppliesHere`
|
|
140
|
+
// (`hookAppliesHere = (underClaudeCode && claudeHookOk) || (underCodex &&
|
|
141
|
+
// codexHookOk)`), which — despite the comment two paragraphs below
|
|
142
|
+
// ("Review MAJOR finding #5") already documenting that "a hook being
|
|
143
|
+
// INSTALLED is not the same as it being able to fire for THIS process" as
|
|
144
|
+
// a genuinely separate case from "not under the tool at all" — still
|
|
145
|
+
// routed BOTH cases into this same blocking branch: `hookAppliesHere` is
|
|
146
|
+
// false whenever the hook isn't installed, `!hookAppliesHere` is
|
|
147
|
+
// therefore true, and the code blocked exactly as if no tool were
|
|
148
|
+
// running at all. That contradicts the finding's own stated intent
|
|
149
|
+
// (never block inside a live tool turn, hook or not — the two cases
|
|
150
|
+
// differ only in WHICH message to print, not whether to block) and the
|
|
151
|
+
// dedicated non-blocking "mail latency unbounded" warning path in the
|
|
152
|
+
// `else` branch below existed but was UNREACHABLE for exactly the
|
|
153
|
+
// scenario it was written for. Fixed by gating on tool presence alone
|
|
154
|
+
// (`!underClaudeCode && !underCodex`); `hookAppliesHere` is still used
|
|
155
|
+
// below, but now purely to pick which message the non-blocking branch
|
|
156
|
+
// prints, never whether to enter it.
|
|
157
|
+
const underClaudeCode = inClaudeCodeSession();
|
|
158
|
+
const underCodex = inCodexSession();
|
|
159
|
+
const claudeHookOk = stopHookInstalled();
|
|
160
|
+
const codexHookOk = codexHooksInstalled();
|
|
161
|
+
const hookAppliesHere = (underClaudeCode && claudeHookOk) || (underCodex && codexHookOk);
|
|
162
|
+
const windowMs = parseInt(process.env.CODEBUS_WATCH_WINDOW_MS ?? "280000", 10);
|
|
163
|
+
if (o.watch !== false && !underClaudeCode && !underCodex) {
|
|
164
|
+
console.log("");
|
|
165
|
+
console.log(`listening for your mail now (${Math.round(windowMs / 1000)}s window; exits on first event — handle it, then re-arm with the standing loop):`);
|
|
166
|
+
// Review fix (Luna, PR #54 comment 3826518135): this branch requires
|
|
167
|
+
// `!underCodex` to even be entered (see the condition above), so a
|
|
168
|
+
// check for `underCodex && !codexHookOk` HERE can never be true — this
|
|
169
|
+
// used to be exactly that dead check, orphaned by the branch-selection
|
|
170
|
+
// fix earlier in this same PR (the fix moved the "never block inside a
|
|
171
|
+
// live Codex turn" decision out from under `hookAppliesHere`, but left
|
|
172
|
+
// this Codex-specific tip sitting in the branch it can no longer reach,
|
|
173
|
+
// silently dropping it for everyone rather than firing it for anyone).
|
|
174
|
+
// The genuine "under Codex, no hook" case now correctly lands in the
|
|
175
|
+
// `else` branch below instead (it never blocks) — the equivalent tip
|
|
176
|
+
// is given there.
|
|
177
|
+
await watchCmd({ url: cfg.url, anonKey: cfg.anonKey, workspace: cfg.workspace, token: r.token, mine: true, first: true, timeout: String(windowMs) });
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
// Either a session already covered by a real turn-boundary hook (auto-arm
|
|
181
|
+
// skipped) or an explicit --no-watch. Review MAJOR finding #5: a hook
|
|
182
|
+
// being INSTALLED (machine-wide config) is not the same as it being able
|
|
183
|
+
// to fire for THIS process — Claude's only ever fires inside an actual
|
|
184
|
+
// Claude Code session, and Codex's only ever fires inside an actual Codex
|
|
185
|
+
// session (CODEX_THREAD_ID). A hook installed while this checkin runs
|
|
186
|
+
// under the OTHER tool, or a plain shell (--no-watch, say), cannot help
|
|
187
|
+
// this agent at all; require a recently-armed watch (scoped to this
|
|
188
|
+
// workspace) instead, and warn loudly if neither applies (delivery gap #8).
|
|
189
|
+
console.log("");
|
|
190
|
+
if (underClaudeCode && claudeHookOk) {
|
|
191
|
+
console.log("(Claude Code session: new mail is surfaced automatically at turn boundaries by the Stop hook — no listener needed.)");
|
|
192
|
+
}
|
|
193
|
+
else if (underCodex && codexHookOk) {
|
|
194
|
+
console.log("(Codex session: new mail is surfaced automatically at turn boundaries by Codex's own Stop hook (wired via `codebus install codex` into ~/.codex/hooks.json) — no listener needed. Like Claude Code's Stop hook, it feeds the reported mail back as your next prompt.)");
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
const armed = await watchRecentlyArmed({
|
|
198
|
+
supabase: ctx.supabase, agentSlug: r.agent_slug, workspaceSlug: cfg.workspace, identitySource: ctx.identitySource,
|
|
199
|
+
});
|
|
200
|
+
if (armed) {
|
|
201
|
+
console.log("(--no-watch, and a watch window was recently armed for this workspace — mail latency stays bounded.)");
|
|
202
|
+
}
|
|
203
|
+
else if (underCodex && !codexHookOk) {
|
|
204
|
+
// Review fix (Luna, PR #54 comment 3826518135): the genuine "live
|
|
205
|
+
// Codex session, hook not installed" case — this branch is where it
|
|
206
|
+
// ACTUALLY lands now (it never blocks per the fix above), so the
|
|
207
|
+
// actionable, Codex-specific tip belongs here, not in the blocking
|
|
208
|
+
// branch it can no longer reach. Checked ahead of the two
|
|
209
|
+
// hook-installed-elsewhere cases below since underCodex is true
|
|
210
|
+
// here, making `codexHookOk && !underCodex` structurally impossible
|
|
211
|
+
// to also match for this same call.
|
|
212
|
+
console.log(`⚠ ${MAIL_LATENCY_WARNING} Run \`codebus install codex\` once to wire Codex's own Stop hook for durable auto-checking; otherwise keep re-arming \`codebus watch --mine --first\` by hand.`);
|
|
213
|
+
}
|
|
214
|
+
else if (claudeHookOk && !underClaudeCode) {
|
|
215
|
+
console.log(`⚠ a Claude Stop hook is installed, but this session is not running inside Claude Code, so it cannot fire for it. ${MAIL_LATENCY_WARNING}`);
|
|
216
|
+
}
|
|
217
|
+
else if (codexHookOk && !underCodex) {
|
|
218
|
+
console.log(`⚠ a Codex Stop hook is installed, but this session is not running inside Codex, so it cannot fire for it. ${MAIL_LATENCY_WARNING}`);
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
console.log(`⚠ ${MAIL_LATENCY_WARNING}`);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
export function registerCheckin(program, g) {
|
|
227
|
+
g(program.command("checkin"))
|
|
228
|
+
.description("one-line onboarding: mint/rebind an author-owned agent named <name> and orient it")
|
|
229
|
+
.argument("<name>", "the name this agent will be addressable at (you own it; idempotent)")
|
|
230
|
+
.option("--adopt", "take ownership of an existing unowned legacy role (rotates its token)")
|
|
231
|
+
.option("--role <function_role>", "functional role for routing (planner|builder|reviewer|consultant|researcher|router|monitor — docs/role-vocabulary.md)")
|
|
232
|
+
.option("--no-watch", "do not auto-arm the watch listener after checkin")
|
|
233
|
+
.action(checkinCmd);
|
|
234
|
+
}
|
|
235
|
+
//# sourceMappingURL=checkin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkin.js","sourceRoot":"","sources":["../../src/commands/checkin.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAa,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,cAAc,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAE3J,oEAAoE;AACpE,+EAA+E;AAC/E,iFAAiF;AACjF,EAAE;AACF,0BAA0B;AAC1B,2EAA2E;AAC3E,oFAAoF;AACpF,6EAA6E;AAC7E,0EAA0E;AAC1E,+EAA+E;AAC/E,uDAAuD;AACvD,8EAA8E;AAC9E,6EAA6E;AAC7E,2BAA2B;AAC3B,EAAE;AACF,wEAAwE;AACxE,6EAA6E;AAC7E,2EAA2E;AAC3E,wEAAwE;AACxE,sEAAsE;AACtE,8EAA8E;AAC9E,wEAAwE;AACxE,8DAA8D;AAC9D,EAAE;AACF,8EAA8E;AAC9E,qEAAqE;AAErE,MAAM,aAAa,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC;IACtC,8EAA8E;IAC9E,YAAY,IAAI,0DAA0D;IAC1E,2EAA2E;IAC3E,2EAA2E;IAC3E,qEAAqE;IACrE,0EAA0E;IAC1E,0EAA0E;IAC1E,mEAAmE;IACnE,iDAAiD;IACjD,qDAAqD;IACrD,6EAA6E;IAC7E,4EAA4E;IAC5E,4EAA4E;IAC5E,yDAAyD;IACzD,+DAA+D;IAC/D,6DAA6D;IAC7D,4DAA4D;IAC5D,2EAA2E;IAC3E,0CAA0C;IAC1C,oFAAoF;IACpF,0EAA0E;IAC1E,uEAAuE;IACvE,sCAAsC;IACtC,2DAA2D;IAC3D,oEAAoE;IACpE,wBAAwB;IACxB,2EAA2E;IAC3E,mFAAmF;IACnF,4EAA4E;IAC5E,2CAA2C,IAAI,IAAI;IACnD,8EAA8E;CAC/E,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEb,KAAK,UAAU,UAAU,CAAC,IAAY,EAAE,CAAkF;IACxH,MAAM,GAAG,GAAG,aAAa,CAAC,EAAE,GAAG,CAAC,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IACzD,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC;IAE/B,uEAAuE;IACvE,wEAAwE;IACxE,kEAAkE;IAClE,MAAM,IAAI,GAA4B,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC;IAC3E,IAAI,CAAC,CAAC,IAAI;QAAE,IAAI,CAAC,eAAe,GAAG,CAAC,CAAC,IAAI,CAAC;IAC1C,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,cAAc,EAAE,IAAI,CAAC,CAAC;IACrE,IAAI,KAAK,EAAE,CAAC;QACV,2EAA2E;QAC3E,sEAAsE;QACtE,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAC;YACxD,CAAC,CAAC,wCAAwC,IAAI,UAAU;YACxD,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAC;gBAC1C,CAAC,CAAC,wFAAwF;gBAC1F,CAAC,CAAC,EAAE,CAAC;QACT,MAAM,IAAI,YAAY,CAAC,mBAAmB,KAAK,CAAC,OAAO,GAAG,IAAI,EAAE,CAAC,CAAC;IACpE,CAAC;IAED,MAAM,CAAC,GAAG,IAAqH,CAAC;IAEhI,iFAAiF;IACjF,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC;IAC1B,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,UAAU,EAAE,QAAQ,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC;IACxG,SAAS,CAAC,KAAK,CAAC,CAAC;IAEjB,mEAAmE;IACnE,yEAAyE;IACzE,wEAAwE;IACxE,yEAAyE;IACzE,0EAA0E;IAC1E,2EAA2E;IAC3E,kEAAkE;IAClE,iEAAiE;IACjE,uEAAuE;IACvE,2DAA2D;IAC3D,MAAM,UAAU,GAAG,iBAAiB,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;IAEnD,MAAM,IAAI,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,yBAAyB,CAAC;IACvF,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,UAAU,IAAI,IAAI,gDAAgD,SAAS,EAAE,EAAE,CAAC,CAAC;IACpG,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC,UAAU,mEAAmE,CAAC,CAAC;IAC7H,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,yKAAyK,CAAC,CAAC;IACzL,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,qDAAqD,CAAC,CAAC,UAAU,gDAAgD,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC;IAC9I,IAAI,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,OAAO;QAAE,OAAO,CAAC,GAAG,CAAC,2DAA2D,CAAC,CAAC,UAAU,oBAAoB,CAAC,CAAC;IAEtI,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;QACX,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,UAAU,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,aAAa,EAAE,CAAC,CAAC,UAAU,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QACvJ,OAAO;IACT,CAAC;IAED,4EAA4E;IAC5E,yEAAyE;IACzE,6CAA6C;IAC7C,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,MAAM,QAAQ,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;IACjG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;IAEzC,0EAA0E;IAC1E,2EAA2E;IAC3E,yEAAyE;IACzE,yEAAyE;IACzE,qEAAqE;IACrE,qEAAqE;IACrE,uEAAuE;IACvE,sEAAsE;IACtE,QAAQ;IACR,EAAE;IACF,2DAA2D;IAC3D,mEAAmE;IACnE,uEAAuE;IACvE,kEAAkE;IAClE,mEAAmE;IACnE,0EAA0E;IAC1E,mEAAmE;IACnE,qEAAqE;IACrE,0EAA0E;IAC1E,qEAAqE;IACrE,yEAAyE;IACzE,iEAAiE;IACjE,kEAAkE;IAClE,mEAAmE;IACnE,oEAAoE;IACpE,uEAAuE;IACvE,sEAAsE;IACtE,kEAAkE;IAClE,sEAAsE;IACtE,uEAAuE;IACvE,sEAAsE;IACtE,qCAAqC;IACrC,MAAM,eAAe,GAAG,mBAAmB,EAAE,CAAC;IAC9C,MAAM,UAAU,GAAG,cAAc,EAAE,CAAC;IACpC,MAAM,YAAY,GAAG,iBAAiB,EAAE,CAAC;IACzC,MAAM,WAAW,GAAG,mBAAmB,EAAE,CAAC;IAC1C,MAAM,eAAe,GAAG,CAAC,eAAe,IAAI,YAAY,CAAC,IAAI,CAAC,UAAU,IAAI,WAAW,CAAC,CAAC;IACzF,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,uBAAuB,IAAI,QAAQ,EAAE,EAAE,CAAC,CAAC;IAC/E,IAAI,CAAC,CAAC,KAAK,KAAK,KAAK,IAAI,CAAC,eAAe,IAAI,CAAC,UAAU,EAAE,CAAC;QACzD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,gCAAgC,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC,kFAAkF,CAAC,CAAC;QAC3J,qEAAqE;QACrE,mEAAmE;QACnE,uEAAuE;QACvE,uEAAuE;QACvE,uEAAuE;QACvE,uEAAuE;QACvE,wEAAwE;QACxE,uEAAuE;QACvE,qEAAqE;QACrE,qEAAqE;QACrE,kBAAkB;QAClB,MAAM,QAAQ,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IACvJ,CAAC;SAAM,CAAC;QACN,0EAA0E;QAC1E,sEAAsE;QACtE,yEAAyE;QACzE,uEAAuE;QACvE,0EAA0E;QAC1E,sEAAsE;QACtE,wEAAwE;QACxE,oEAAoE;QACpE,4EAA4E;QAC5E,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,IAAI,eAAe,IAAI,YAAY,EAAE,CAAC;YACpC,OAAO,CAAC,GAAG,CAAC,qHAAqH,CAAC,CAAC;QACrI,CAAC;aAAM,IAAI,UAAU,IAAI,WAAW,EAAE,CAAC;YACrC,OAAO,CAAC,GAAG,CAAC,uQAAuQ,CAAC,CAAC;QACvR,CAAC;aAAM,CAAC;YACN,MAAM,KAAK,GAAG,MAAM,kBAAkB,CAAC;gBACrC,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC,UAAU,EAAE,aAAa,EAAE,GAAG,CAAC,SAAS,EAAE,cAAc,EAAE,GAAG,CAAC,cAAc;aAClH,CAAC,CAAC;YACH,IAAI,KAAK,EAAE,CAAC;gBACV,OAAO,CAAC,GAAG,CAAC,sGAAsG,CAAC,CAAC;YACtH,CAAC;iBAAM,IAAI,UAAU,IAAI,CAAC,WAAW,EAAE,CAAC;gBACtC,kEAAkE;gBAClE,oEAAoE;gBACpE,iEAAiE;gBACjE,mEAAmE;gBACnE,0DAA0D;gBAC1D,gEAAgE;gBAChE,oEAAoE;gBACpE,oCAAoC;gBACpC,OAAO,CAAC,GAAG,CAAC,KAAK,oBAAoB,iKAAiK,CAAC,CAAC;YAC1M,CAAC;iBAAM,IAAI,YAAY,IAAI,CAAC,eAAe,EAAE,CAAC;gBAC5C,OAAO,CAAC,GAAG,CAAC,oHAAoH,oBAAoB,EAAE,CAAC,CAAC;YAC1J,CAAC;iBAAM,IAAI,WAAW,IAAI,CAAC,UAAU,EAAE,CAAC;gBACtC,OAAO,CAAC,GAAG,CAAC,6GAA6G,oBAAoB,EAAE,CAAC,CAAC;YACnJ,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,GAAG,CAAC,KAAK,oBAAoB,EAAE,CAAC,CAAC;YAC3C,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,OAAgB,EAAE,CAA0B;IAC1E,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;SAC1B,WAAW,CAAC,mFAAmF,CAAC;SAChG,QAAQ,CAAC,QAAQ,EAAE,qEAAqE,CAAC;SACzF,MAAM,CAAC,SAAS,EAAE,uEAAuE,CAAC;SAC1F,MAAM,CAAC,wBAAwB,EAAE,uHAAuH,CAAC;SACzJ,MAAM,CAAC,YAAY,EAAE,kDAAkD,CAAC;SACxE,MAAM,CAAC,UAAU,CAAC,CAAC;AACxB,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { resolveConfig } from "../config.js";
|
|
2
|
+
import { makeCtx, workspaceId } from "../client.js";
|
|
3
|
+
import { render } from "../output.js";
|
|
4
|
+
import { CodebusError } from "../errors.js";
|
|
5
|
+
/**
|
|
6
|
+
* Shared core: create a decision.
|
|
7
|
+
* Exported for reuse in MCP tool.
|
|
8
|
+
*/
|
|
9
|
+
export async function createDecisionCore(ctx, opts) {
|
|
10
|
+
const ws = await workspaceId(ctx);
|
|
11
|
+
const slug = opts.slug ?? opts.title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 60);
|
|
12
|
+
const { data, error } = await ctx.supabase.from("decisions")
|
|
13
|
+
.insert({ workspace_id: ws, slug, title: opts.title, body: opts.body ?? null }).select().single();
|
|
14
|
+
if (error)
|
|
15
|
+
throw new CodebusError(error.message);
|
|
16
|
+
return { display_id: data.display_id, slug: data.slug, status: data.status, id: data.id };
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Shared core: accept a decision.
|
|
20
|
+
* Exported for reuse in MCP tool.
|
|
21
|
+
*/
|
|
22
|
+
export async function acceptDecisionCore(ctx, idOrDisplay) {
|
|
23
|
+
const isDisplay = /^CB-DEC-/i.test(idOrDisplay);
|
|
24
|
+
const sel = isDisplay ? "display_id" : "id";
|
|
25
|
+
const val = isDisplay ? idOrDisplay.toUpperCase() : idOrDisplay;
|
|
26
|
+
// display ids are only unique per workspace (bus_counters, 0004) — scope
|
|
27
|
+
// the display_id lookup, or a multi-workspace agent could accept the WRONG
|
|
28
|
+
// workspace's decision when two workspaces happen to share a display_id.
|
|
29
|
+
let q = ctx.supabase.from("decisions").update({ status: "accepted" }).eq(sel, val);
|
|
30
|
+
if (isDisplay)
|
|
31
|
+
q = q.eq("workspace_id", await workspaceId(ctx));
|
|
32
|
+
const { data, error } = await q.select().single();
|
|
33
|
+
if (error)
|
|
34
|
+
throw new CodebusError(`accept failed (owner-only): ${error.message}`);
|
|
35
|
+
return { display_id: data.display_id, status: data.status, id: data.id };
|
|
36
|
+
}
|
|
37
|
+
async function addDecision(o) {
|
|
38
|
+
const ctx = await makeCtx(resolveConfig(o));
|
|
39
|
+
const result = await createDecisionCore(ctx, { title: o.title, slug: o.slug, body: o.body });
|
|
40
|
+
console.log(render([{ display_id: result.display_id, slug: result.slug, status: result.status }], { json: !!o.json }));
|
|
41
|
+
}
|
|
42
|
+
async function acceptDecision(idOrDisplay, o) {
|
|
43
|
+
const ctx = await makeCtx(resolveConfig(o));
|
|
44
|
+
const result = await acceptDecisionCore(ctx, idOrDisplay);
|
|
45
|
+
console.log(render([{ display_id: result.display_id, status: result.status }], { json: !!o.json }));
|
|
46
|
+
}
|
|
47
|
+
export function registerDecision(program, g) {
|
|
48
|
+
const dec = program.command("decision").description("decision operations");
|
|
49
|
+
g(dec.command("add")).requiredOption("--title <t>").option("--slug <s>").option("--body <b>").action(addDecision);
|
|
50
|
+
g(dec.command("accept").argument("<id>")).action((id, o) => acceptDecision(id, o));
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=decision.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decision.js","sourceRoot":"","sources":["../../src/commands/decision.ts"],"names":[],"mappings":"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"}
|