@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,426 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { promisify } from "node:util";
|
|
3
|
+
import { basename } from "node:path";
|
|
4
|
+
import { resolveConfig } from "../config.js";
|
|
5
|
+
import { forgetSession } from "../sessionstore.js";
|
|
6
|
+
import { makeCtx, workspaceId } from "../client.js";
|
|
7
|
+
import { fetchAndCacheDigest, nextActionableItem } from "./digest.js";
|
|
8
|
+
import { updateStatus } from "../version-check.js";
|
|
9
|
+
import { render } from "../output.js";
|
|
10
|
+
import { CodebusError, DeadSessionError, SessionStoreError } from "../errors.js";
|
|
11
|
+
const exec = promisify(execFile);
|
|
12
|
+
// Git context is best-effort: session rituals must work outside a repo, and
|
|
13
|
+
// each probe degrades independently (e.g. a commitless fresh repo has no
|
|
14
|
+
// resolvable HEAD, but symbolic-ref still names the branch).
|
|
15
|
+
async function gitContext() {
|
|
16
|
+
let repo = null;
|
|
17
|
+
let branch = null;
|
|
18
|
+
let changed = [];
|
|
19
|
+
try {
|
|
20
|
+
const { stdout } = await exec("git", ["rev-parse", "--show-toplevel"]);
|
|
21
|
+
repo = basename(stdout.trim());
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return { repo, branch, changed };
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
const { stdout } = await exec("git", ["symbolic-ref", "--short", "HEAD"]);
|
|
28
|
+
branch = stdout.trim();
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
try { // detached HEAD: fall back to the short sha
|
|
32
|
+
const { stdout } = await exec("git", ["rev-parse", "--short", "HEAD"]);
|
|
33
|
+
branch = stdout.trim();
|
|
34
|
+
}
|
|
35
|
+
catch { /* no commits and no symbolic ref — leave null */ }
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
const { stdout } = await exec("git", ["status", "--porcelain"]);
|
|
39
|
+
changed = stdout.split("\n").filter(Boolean).slice(0, 20);
|
|
40
|
+
}
|
|
41
|
+
catch { /* keep repo/branch */ }
|
|
42
|
+
return { repo, branch, changed };
|
|
43
|
+
}
|
|
44
|
+
async function personOf(ctx) {
|
|
45
|
+
const { data } = await ctx.supabase
|
|
46
|
+
.from("agents").select("people!person_id(slug)").eq("slug", ctx.agentSlug).single();
|
|
47
|
+
return data?.people?.slug ?? null;
|
|
48
|
+
}
|
|
49
|
+
function statuslineOf(snap) {
|
|
50
|
+
const parts = Object.entries(snap.counts).map(([k, v]) => `${v} ${k}`);
|
|
51
|
+
const speakNow = snap.speak_now_count ?? 0;
|
|
52
|
+
const urgentPrefix = speakNow > 0 ? `!! URGENT ${speakNow} | ` : "";
|
|
53
|
+
return `CodeBus: ${urgentPrefix}${parts.length ? parts.join(" | ") : "clear"}`;
|
|
54
|
+
}
|
|
55
|
+
// ── session start ─────────────────────────────────────────────────────────────
|
|
56
|
+
// Pull-at-session-start is the delivery contract (spec §7). Read-only by
|
|
57
|
+
// design: it never marks anything seen or acted unless --mark-seen is passed.
|
|
58
|
+
/**
|
|
59
|
+
* Resolve THIS command's identity via the SAME shared path as every other
|
|
60
|
+
* command (resolveConfig → sessionstore/rolestore) — the FM-4 consolidation
|
|
61
|
+
* tick.ts already got (docs/plans/codebus-v2-reliability.md §2.3, tick.ts's
|
|
62
|
+
* tickIdentity). This function REPLACES a hand-rolled, DIVERGENT identity
|
|
63
|
+
* resolver (formerly `hookToken` here): raw CODEBUS_TOKEN, then
|
|
64
|
+
* sessionIdentity() (which — this was the bug an ai-review gate caught —
|
|
65
|
+
* collapses resolveSession()'s "dead" and "none" into the SAME null), then
|
|
66
|
+
* an exact-basename dir binding, raw-token only. Collapsing "dead" into null
|
|
67
|
+
* meant a session that WAS checked in but whose role's credential later died
|
|
68
|
+
* (forgotten/rotated via `as --forget`) or aged out (the 30-day env-key
|
|
69
|
+
* policy) would silently run `session start --hook` as whatever the CWD
|
|
70
|
+
* happens to be bound to instead — the exact dead-tier violation
|
|
71
|
+
* resolveConfig's DeadSessionError exists to eliminate (§2.4 precedent 3),
|
|
72
|
+
* reintroduced here by a second, divergent resolver that never learned that
|
|
73
|
+
* rule.
|
|
74
|
+
*
|
|
75
|
+
* The hook's own gate on top of resolveConfig's shared precedence is
|
|
76
|
+
* UNCHANGED in intent from the old hookToken: identitySource "file" (the
|
|
77
|
+
* bare author fallback — config.json used only because nothing more
|
|
78
|
+
* specific matched) is excluded, same as "none" (truly nothing configured)
|
|
79
|
+
* — this runs machine-wide on every Claude Code session start, and the
|
|
80
|
+
* author's personal identity must never leak into an unrelated terminal.
|
|
81
|
+
* identitySource "cwd-binding" is DELIBERATELY still let through for a
|
|
82
|
+
* session with no checkin of its own (resolveSession() status "none"): that
|
|
83
|
+
* IS the old hookToken's exact-basename fallback for a session that was
|
|
84
|
+
* never itself checked in but sits in a directory someone else deliberately
|
|
85
|
+
* bound (`codebus as --bind`) — kept, just now driven by the same
|
|
86
|
+
* glob/full-path/{assume}-aware precedence every other command uses instead
|
|
87
|
+
* of a second, narrower hand-rolled reimplementation of it.
|
|
88
|
+
*
|
|
89
|
+
* DeadSessionError and SessionStoreError are the two exceptions that must
|
|
90
|
+
* NOT collapse to null: the session tier EXISTED for this session and
|
|
91
|
+
* either died or couldn't be trusted (a corrupt/unreadable
|
|
92
|
+
* session-roles.json — sessionstore fails closed rather than guess). Both
|
|
93
|
+
* propagate so startCmd's hook wrapper can swallow them to SILENCE — never
|
|
94
|
+
* to an inferred fallback identity, since resolveConfig itself already
|
|
95
|
+
* stopped before ever reaching the cwd-binding tier for either (dead-tier
|
|
96
|
+
* rule, same as resolveConfig's other callers).
|
|
97
|
+
*
|
|
98
|
+
* Exported for the regression suite.
|
|
99
|
+
*/
|
|
100
|
+
export function sessionStartIdentity(o, env = process.env) {
|
|
101
|
+
let cfg;
|
|
102
|
+
try {
|
|
103
|
+
cfg = resolveConfig(o, env);
|
|
104
|
+
}
|
|
105
|
+
catch (e) {
|
|
106
|
+
if (e instanceof DeadSessionError || e instanceof SessionStoreError)
|
|
107
|
+
throw e;
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
return cfg.identitySource === "file" || cfg.identitySource === "none" ? null : cfg;
|
|
111
|
+
}
|
|
112
|
+
export async function startCmd(o) {
|
|
113
|
+
if (o.hook) {
|
|
114
|
+
// SessionStart-hook contract (tick.ts philosophy): identity-explicit (or
|
|
115
|
+
// this session's own checkin, or a deliberate cwd binding — see
|
|
116
|
+
// sessionStartIdentity's doc comment) or SILENT, and a bus outage must
|
|
117
|
+
// never break session start — every error swallowed to a silent exit 0.
|
|
118
|
+
// Stdout from a SessionStart hook lands in the model's context, so when
|
|
119
|
+
// identity resolves we run the full orientation AS that identity; when
|
|
120
|
+
// it doesn't, print NOTHING (a hint in an unbound directory would nag
|
|
121
|
+
// every session on the machine). A DeadSessionError/SessionStoreError
|
|
122
|
+
// thrown by sessionStartIdentity is caught by this SAME try/catch and
|
|
123
|
+
// swallowed to silence too — loud in plain mode below (resolveConfig
|
|
124
|
+
// throws there with no wrapper), but hook mode's bus-outage-must-never-
|
|
125
|
+
// block-coding policy applies uniformly to every failure mode, the
|
|
126
|
+
// dead/untrusted-store tiers included.
|
|
127
|
+
try {
|
|
128
|
+
const cfg = sessionStartIdentity(o);
|
|
129
|
+
if (!cfg)
|
|
130
|
+
return;
|
|
131
|
+
const { hook: _hook, ...rest } = o;
|
|
132
|
+
await runStart(rest, cfg);
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
/* bus outage must never break session start */
|
|
136
|
+
}
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
await runStart(o);
|
|
140
|
+
}
|
|
141
|
+
/** `cfg`, when given, is a Config already resolved by the hook path above —
|
|
142
|
+
* used as-is (never re-resolved) so hook mode never calls resolveConfig
|
|
143
|
+
* twice for one session start (which would double the "acting as ..."
|
|
144
|
+
* stderr announcement resolveConfig makes for session/cwd-binding tiers). */
|
|
145
|
+
async function runStart(o, cfg) {
|
|
146
|
+
const ctx = await makeCtx(cfg ?? resolveConfig(o));
|
|
147
|
+
const ws = await workspaceId(ctx);
|
|
148
|
+
const [person, git] = await Promise.all([personOf(ctx), gitContext()]);
|
|
149
|
+
const snapshot = await fetchAndCacheDigest(ctx);
|
|
150
|
+
// NEXT is the top ACTIONABLE item — the same actionable-only selection
|
|
151
|
+
// `codebus next` and MCP `codebus_state.next` use (nextActionableItem skips
|
|
152
|
+
// class-8 FYI, 0061). A class-8 FYI is never presented as the next work item
|
|
153
|
+
// here either, so session-start/onboarding agrees with those surfaces; FYI
|
|
154
|
+
// mail stays visible in the statusline counts and via `codebus inbox --unread`.
|
|
155
|
+
const top = nextActionableItem(snapshot.items);
|
|
156
|
+
// FYI-only inbox: nothing actionable, but mail arrived — say so honestly
|
|
157
|
+
// rather than either a false "bus is clear" or a false work-order NEXT.
|
|
158
|
+
const fyiWaiting = !top && snapshot.items.length > 0 ? snapshot.items.length : 0;
|
|
159
|
+
// Onboarding reliability (field incident: a fresh checkin into a large inbox
|
|
160
|
+
// read only the NEXT teaser — a display_id and title, never learning WHO sent
|
|
161
|
+
// the top item or HOW to answer). When NEXT is a message, one cheap best-effort
|
|
162
|
+
// lookup resolves the sender + type; both the JSON and human surfaces carry it,
|
|
163
|
+
// so no delivery surface is left with a bare teaser. `top` is actionable by
|
|
164
|
+
// construction, so this is always a work order. Silent fallback on any failure.
|
|
165
|
+
const topIsMessage = typeof top?.display_id === "string" && top.display_id.startsWith("CB-MSG");
|
|
166
|
+
let nextFrom = null;
|
|
167
|
+
let nextType = null;
|
|
168
|
+
if (topIsMessage) {
|
|
169
|
+
try {
|
|
170
|
+
const { data: m } = await ctx.supabase
|
|
171
|
+
.from("messages")
|
|
172
|
+
.select("type, from_agent_id, agents:from_agent_id(slug)")
|
|
173
|
+
// display_id (CB-MSG-*) is unique per WORKSPACE, not globally — scope to
|
|
174
|
+
// the active workspace or a multi-workspace agent's lookup can match
|
|
175
|
+
// several rows (maybeSingle throws → enrichment lost) or surface the
|
|
176
|
+
// wrong workspace's message.
|
|
177
|
+
.eq("workspace_id", ws)
|
|
178
|
+
.eq("display_id", top.display_id)
|
|
179
|
+
.maybeSingle();
|
|
180
|
+
nextFrom = m?.agents?.slug ?? null;
|
|
181
|
+
nextType = m?.type ?? null;
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
/* best-effort; the NEXT/Reason lines still orient */
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
// adoption metric (best-effort: a logging failure never breaks the ritual)
|
|
188
|
+
await ctx.supabase.from("session_log")
|
|
189
|
+
.insert({ workspace_id: ws, kind: "start", repo: git.repo, branch: git.branch })
|
|
190
|
+
.then(() => undefined, () => undefined);
|
|
191
|
+
if (o.markSeen && top) {
|
|
192
|
+
await ctx.supabase.rpc("mark_seen", { p_kind: top.kind, p_subject: top.id, p_workspace: ws });
|
|
193
|
+
}
|
|
194
|
+
// Out-of-date / linked-build check against the bus-advertised release
|
|
195
|
+
// (best-effort; silent on any failure). Surfaced on both the human and JSON
|
|
196
|
+
// session-start surfaces so a stale or linked CLI is caught at every session.
|
|
197
|
+
const cli = await updateStatus(ctx);
|
|
198
|
+
if (o.json) {
|
|
199
|
+
// Same work-order contract as the human surface, in structured form: when
|
|
200
|
+
// NEXT is a message, a JSON consumer gets the sender, its type, and the
|
|
201
|
+
// directive — not just the teaser fields on `next`.
|
|
202
|
+
const nextMessage = top && topIsMessage
|
|
203
|
+
? {
|
|
204
|
+
from: nextFrom, type: nextType,
|
|
205
|
+
directive: "work order — read (codebus read <id> --thread), do what it asks, then reply with the outcome (not a bare acknowledgement)",
|
|
206
|
+
reply_cmd: `codebus reply ${top.display_id} --body "<what you did / your answer>"`,
|
|
207
|
+
}
|
|
208
|
+
: null;
|
|
209
|
+
console.log(JSON.stringify({
|
|
210
|
+
agent: ctx.agentSlug, person, workspace: ctx.workspaceSlug,
|
|
211
|
+
repo: git.repo, branch: git.branch, counts: snapshot.counts,
|
|
212
|
+
speak_now_count: snapshot.speak_now_count ?? 0, next: top,
|
|
213
|
+
next_message: nextMessage,
|
|
214
|
+
cli_update: cli.message
|
|
215
|
+
? { message: cli.message, local: cli.local, current: cli.current, dev_linked: cli.devLinked, behind: cli.behind }
|
|
216
|
+
: null,
|
|
217
|
+
}, null, 2));
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
// first session ever for this agent? (no prior session_log starts) → welcome
|
|
221
|
+
const { count: priorStarts } = await ctx.supabase.from("session_log")
|
|
222
|
+
.select("*", { count: "exact", head: true })
|
|
223
|
+
.eq("workspace_id", ws).eq("kind", "start")
|
|
224
|
+
.eq("agent_id", (await ctx.supabase.from("agents").select("id").eq("slug", ctx.agentSlug).single()).data?.id ?? "");
|
|
225
|
+
if ((priorStarts ?? 0) <= 1) { // <=1: the row this very session just wrote
|
|
226
|
+
const { data: meRow } = await ctx.supabase.from("agents")
|
|
227
|
+
.select("people!person_id(id)").eq("slug", ctx.agentSlug).single();
|
|
228
|
+
const myPersonId = meRow?.people?.id;
|
|
229
|
+
const { data: conn } = myPersonId ? await ctx.supabase.from("connections")
|
|
230
|
+
.select("kind, expires_at, inviter:other_person_id(slug)")
|
|
231
|
+
.eq("workspace_id", ws).eq("person_id", myPersonId) : { data: null };
|
|
232
|
+
const invitedBy = conn?.find((c) => c.kind === "invited_by")?.inviter?.slug;
|
|
233
|
+
const mentor = conn?.find((c) => c.kind === "mentor" && new Date(c.expires_at) > new Date())?.inviter?.slug;
|
|
234
|
+
const { data: repoRows } = await ctx.supabase.from("repos").select("slug").eq("workspace_id", ws).order("slug");
|
|
235
|
+
console.log(`Welcome to CodeBus.`);
|
|
236
|
+
if (invitedBy)
|
|
237
|
+
console.log(`You joined via: ${invitedBy}${mentor ? ` (your mentor for the first week — ask them anything: codebus question ask --to-mentor …)` : ""}`);
|
|
238
|
+
console.log(`Workspace: ${ctx.workspaceSlug}`);
|
|
239
|
+
if (repoRows?.length)
|
|
240
|
+
console.log(`Repositories: ${repoRows.map((r) => r.slug).join(", ")}`);
|
|
241
|
+
// Don't promise an onboarding question that may not exist: the welcome
|
|
242
|
+
// question is only minted on the invited-human path (0024), never for
|
|
243
|
+
// checkin-born agents — a newborn told to "answer your onboarding
|
|
244
|
+
// question" goes looking for something that isn't there.
|
|
245
|
+
console.log(`Next: review the current work below, then check your inbox.`);
|
|
246
|
+
// show what kind of work flows through CodeBus — not necessarily theirs to act on
|
|
247
|
+
const [{ data: oq }, { data: rt }, { data: dd }] = await Promise.all([
|
|
248
|
+
ctx.supabase.from("questions").select("display_id,title").eq("workspace_id", ws)
|
|
249
|
+
.eq("status", "open").not("title", "like", "Welcome %").limit(1),
|
|
250
|
+
ctx.supabase.from("tasks").select("display_id,title").eq("workspace_id", ws)
|
|
251
|
+
.eq("status", "review").limit(1),
|
|
252
|
+
ctx.supabase.from("decisions").select("display_id,title").eq("workspace_id", ws)
|
|
253
|
+
.eq("status", "accepted").order("created_at", { ascending: false }).limit(1),
|
|
254
|
+
]);
|
|
255
|
+
const suggestions = [
|
|
256
|
+
oq?.[0] && `Open question: ${oq[0].display_id} — ${oq[0].title}`,
|
|
257
|
+
rt?.[0] && `Review request: ${rt[0].display_id} — ${rt[0].title}`,
|
|
258
|
+
dd?.[0] && `Recent decision: ${dd[0].display_id} — ${dd[0].title}`,
|
|
259
|
+
].filter(Boolean);
|
|
260
|
+
if (suggestions.length) {
|
|
261
|
+
console.log(`Suggested work (to see what flows through here):`);
|
|
262
|
+
suggestions.forEach((x) => console.log(` ${x}`));
|
|
263
|
+
}
|
|
264
|
+
console.log(``);
|
|
265
|
+
}
|
|
266
|
+
console.log(`session: agent=${ctx.agentSlug} person=${person ?? "—"} repo=${git.repo ?? "—"} branch=${git.branch ?? "—"}`);
|
|
267
|
+
console.log(statuslineOf(snapshot));
|
|
268
|
+
if (top) {
|
|
269
|
+
console.log(`NEXT: ${top.display_id} — ${top.title}`);
|
|
270
|
+
console.log(`Reason: ${top.reason} · score ${top.score}`);
|
|
271
|
+
// Onboarding reliability (field incident: a fresh checkin into a large inbox
|
|
272
|
+
// read only this teaser — it never learned WHO to answer or HOW, so it
|
|
273
|
+
// neither acted nor replied). `top` is the top ACTIONABLE item, so when it's
|
|
274
|
+
// a message this is always a work order: one cheap best-effort lookup names
|
|
275
|
+
// the sender and gives the exact reply command. A lookup miss only drops the
|
|
276
|
+
// sender line, never the directive.
|
|
277
|
+
if (topIsMessage) {
|
|
278
|
+
if (nextFrom)
|
|
279
|
+
console.log(`From: ${nextFrom}${nextType ? ` · ${nextType}` : ""}`);
|
|
280
|
+
console.log(`→ Your move: this is a work order, not a notification. Read it ` +
|
|
281
|
+
`(codebus read ${top.display_id} --thread), do what it asks in THIS session, ` +
|
|
282
|
+
`then reply${nextFrom ? ` to ${nextFrom}` : ""} with the outcome — not a bare acknowledgement:`);
|
|
283
|
+
console.log(` codebus reply ${top.display_id} --body "<what you did / your answer>"`);
|
|
284
|
+
}
|
|
285
|
+
if (o.markSeen)
|
|
286
|
+
console.log("(marked seen)");
|
|
287
|
+
}
|
|
288
|
+
else if (fyiWaiting > 0) {
|
|
289
|
+
// Mail arrived but none of it is actionable — the same verdict `codebus next`
|
|
290
|
+
// gives, said honestly so FYI mail is neither hidden nor framed as owed work.
|
|
291
|
+
console.log(`NEXT: no actionable work — ${fyiWaiting} FYI item${fyiWaiting === 1 ? "" : "s"} waiting (plain note/plan). Skim: codebus inbox --unread · clear: codebus ack <id>`);
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
console.log("NEXT: nothing pending — bus is clear.");
|
|
295
|
+
}
|
|
296
|
+
// Update nudge last, so a stale/linked CLI is the final thing the reader sees.
|
|
297
|
+
if (cli.message)
|
|
298
|
+
console.log(cli.message);
|
|
299
|
+
}
|
|
300
|
+
const LINK_TABLE = {
|
|
301
|
+
task: { table: "tasks", kind: "task", re: /^CB-TASK-/i },
|
|
302
|
+
pr: { table: "pull_requests", kind: "pr", re: /^CB-PR-/i },
|
|
303
|
+
question: { table: "questions", kind: "question", re: /^CB-Q-/i },
|
|
304
|
+
};
|
|
305
|
+
/**
|
|
306
|
+
* Shared core: end a session with optional handoff/note.
|
|
307
|
+
* Exported for reuse in MCP tool.
|
|
308
|
+
*/
|
|
309
|
+
export async function endSessionCore(ctx, opts) {
|
|
310
|
+
const ws = await workspaceId(ctx);
|
|
311
|
+
const git = await gitContext();
|
|
312
|
+
const type = opts.type ?? "handoff";
|
|
313
|
+
if (!["handoff", "note"].includes(type))
|
|
314
|
+
throw new CodebusError(`--type must be handoff|note, got: ${type}`);
|
|
315
|
+
// Resolve linked entities up front so a typo fails before anything is posted.
|
|
316
|
+
const linked = [];
|
|
317
|
+
for (const [opt, cfg] of Object.entries(LINK_TABLE)) {
|
|
318
|
+
const raw = opts[opt];
|
|
319
|
+
if (!raw)
|
|
320
|
+
continue;
|
|
321
|
+
for (const display of raw.split(",").map((s) => s.trim()).filter(Boolean)) {
|
|
322
|
+
if (!cfg.re.test(display))
|
|
323
|
+
throw new CodebusError(`--${opt} expects ${cfg.re.source.replace(/[\^\\]/g, "")}… ids, got: ${display}`);
|
|
324
|
+
// display ids are only unique per workspace — always scope the lookup
|
|
325
|
+
const { data } = await ctx.supabase.from(cfg.table).select("id")
|
|
326
|
+
.eq("workspace_id", ws).eq("display_id", display.toUpperCase()).single();
|
|
327
|
+
if (!data)
|
|
328
|
+
throw new CodebusError(`${opt} not found: ${display}`);
|
|
329
|
+
linked.push({ kind: cfg.kind, id: data.id, display: display.toUpperCase() });
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
const body = [
|
|
333
|
+
"## Session handoff",
|
|
334
|
+
`Summary: ${opts.summary ?? "—"}`,
|
|
335
|
+
`Repo/branch: ${git.repo ?? "—"}${git.branch ? `@${git.branch}` : ""}`,
|
|
336
|
+
`Changed files:${git.changed.length ? "\n" + git.changed.map((f) => ` ${f}`).join("\n") : " —"}`,
|
|
337
|
+
`Links: ${linked.length ? linked.map((l) => l.display).join(" ") : "—"}`,
|
|
338
|
+
`Open questions: ${opts.openQuestion ?? "—"}`,
|
|
339
|
+
`Caveats: ${opts.caveat ?? "—"}`,
|
|
340
|
+
`Next: ${opts.next ?? "—"}`,
|
|
341
|
+
].join("\n");
|
|
342
|
+
const { data: msg, error } = await ctx.supabase.from("messages")
|
|
343
|
+
.insert({ workspace_id: ws, type, subject: `session end: ${ctx.agentSlug}`, body })
|
|
344
|
+
.select().single();
|
|
345
|
+
if (error)
|
|
346
|
+
throw new CodebusError(error.message);
|
|
347
|
+
if (opts.to) {
|
|
348
|
+
const slugs = opts.to.split(",").map((s) => s.trim()).filter(Boolean);
|
|
349
|
+
const { data: recips } = await ctx.supabase.from("agents").select("id,slug").in("slug", slugs);
|
|
350
|
+
const missing = slugs.filter((s) => !recips.some((r) => r.slug === s));
|
|
351
|
+
if (missing.length)
|
|
352
|
+
throw new CodebusError(`unknown recipient(s): ${missing.join(", ")}`);
|
|
353
|
+
await ctx.supabase.from("message_recipients")
|
|
354
|
+
.insert(recips.map((r) => ({ message_id: msg.id, agent_id: r.id })));
|
|
355
|
+
}
|
|
356
|
+
if (linked.length) {
|
|
357
|
+
const { error: lerr } = await ctx.supabase.from("links").insert(linked.map((l) => ({
|
|
358
|
+
workspace_id: ws, src_kind: "message", src_id: msg.id, rel: "relates_to",
|
|
359
|
+
dst_kind: l.kind, dst_id: l.id,
|
|
360
|
+
})));
|
|
361
|
+
if (lerr)
|
|
362
|
+
throw new CodebusError(lerr.message);
|
|
363
|
+
}
|
|
364
|
+
await ctx.supabase.from("session_log")
|
|
365
|
+
.insert({ workspace_id: ws, kind: "end", repo: git.repo, branch: git.branch })
|
|
366
|
+
.then(() => undefined, () => undefined);
|
|
367
|
+
await fetchAndCacheDigest(ctx); // statusline reflects post-handoff state
|
|
368
|
+
return {
|
|
369
|
+
display_id: msg.display_id,
|
|
370
|
+
type,
|
|
371
|
+
linked: linked.length ? linked.map((l) => l.display).join(",") : null,
|
|
372
|
+
id: msg.id,
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
async function endCmd(o) {
|
|
376
|
+
const ctx = await makeCtx(resolveConfig(o));
|
|
377
|
+
const result = await endSessionCore(ctx, {
|
|
378
|
+
summary: o.summary,
|
|
379
|
+
to: o.to,
|
|
380
|
+
type: o.type,
|
|
381
|
+
task: o.task,
|
|
382
|
+
pr: o.pr,
|
|
383
|
+
question: o.question,
|
|
384
|
+
openQuestion: o.openQuestion,
|
|
385
|
+
caveat: o.caveat,
|
|
386
|
+
next: o.next,
|
|
387
|
+
});
|
|
388
|
+
console.log(render([{
|
|
389
|
+
display_id: result.display_id, type: result.type, linked: result.linked,
|
|
390
|
+
}], { json: !!o.json }));
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* `codebus session forget` — the explicit escape hatch for durable env-keyed
|
|
394
|
+
* session entries (sessionstore.ts). Those entries outlive their process BY
|
|
395
|
+
* DESIGN (that's the whole fix for FM-1/root-cause §2.1 — mortal keys used to
|
|
396
|
+
* silently fall through to the directory tier on every restart) and are only
|
|
397
|
+
* ever pruned by age otherwise; this is how a human deliberately un-checks-in
|
|
398
|
+
* a session before that age-out.
|
|
399
|
+
*/
|
|
400
|
+
function forgetCmd() {
|
|
401
|
+
const role = forgetSession();
|
|
402
|
+
if (!role) {
|
|
403
|
+
console.log("no session identity here to forget (this session was never checked in, or its entry already aged out).");
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
console.log(`forgot this session's identity (was: ${role}) — it will resolve to a directory binding (if any) or need a fresh checkin.`);
|
|
407
|
+
}
|
|
408
|
+
export function registerSession(program, g) {
|
|
409
|
+
const s = program.command("session").description("session rituals (start/end)");
|
|
410
|
+
g(s.command("start"))
|
|
411
|
+
.option("--mark-seen", "mark the surfaced NEXT item as seen (explicit opt-in)")
|
|
412
|
+
.option("--hook", "SessionStart-hook mode: orient only when identity is explicit (CODEBUS_TOKEN or exact cwd binding), silent otherwise, never fail")
|
|
413
|
+
.action(startCmd);
|
|
414
|
+
g(s.command("end"))
|
|
415
|
+
.option("--summary <text>").option("--to <slugs>", "recipients (comma-separated)")
|
|
416
|
+
.option("--type <t>", "handoff|note", "handoff")
|
|
417
|
+
.option("--task <ids>", "CB-TASK-… (comma-separated)")
|
|
418
|
+
.option("--pr <ids>", "CB-PR-… (comma-separated)")
|
|
419
|
+
.option("--question <ids>", "CB-Q-… (comma-separated)")
|
|
420
|
+
.option("--open-question <text>").option("--caveat <text>").option("--next <text>")
|
|
421
|
+
.action(endCmd);
|
|
422
|
+
s.command("forget")
|
|
423
|
+
.description("remove THIS session's durable identity binding (env-keyed entries otherwise only age out — see sessionstore.ts)")
|
|
424
|
+
.action(forgetCmd);
|
|
425
|
+
}
|
|
426
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/commands/session.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { readCachedDigest } from "./digest.js";
|
|
2
|
+
// Statusline renders frequently (Claude Code re-runs it constantly), so it
|
|
3
|
+
// NEVER touches the network: no makeCtx, no JWT exchange, no Supabase query.
|
|
4
|
+
// It reads ~/.codebus/digest.json and degrades gracefully when absent/stale.
|
|
5
|
+
// MESSAGE (0048, delivery gap #1; narrowed to actionable-only by 0061):
|
|
6
|
+
// unhandled ask/handoff mail (or any type with required_action set),
|
|
7
|
+
// class_rank 7 — the tail of the actual-work ladder, after UNCLAIMED, since
|
|
8
|
+
// ordinary mail is lower pressure than open work; a speak_now message still
|
|
9
|
+
// gets its own urgent surface via the "!! URGENT N" prefix below
|
|
10
|
+
// (speak_now_count), independent of this order.
|
|
11
|
+
// FYI (0061 — RC2): unhandled note/plan mail with no required_action, class_
|
|
12
|
+
// rank 8. Ranked last of all: nothing here is owed, it's purely informational
|
|
13
|
+
// — kept visible (so it isn't silently dropped) but never mixed into the
|
|
14
|
+
// same count as genuine work orders above it.
|
|
15
|
+
const ORDER = ["ASK", "REVIEW", "BLOCKER", "STALE", "DECISION", "UNCLAIMED", "MESSAGE", "FYI"];
|
|
16
|
+
/**
|
|
17
|
+
* Count urgent (speak_now) messages from the cached digest snapshot.
|
|
18
|
+
* Zero network — derived entirely from the in-memory snapshot.
|
|
19
|
+
*/
|
|
20
|
+
export function countSpeakNow(snap) {
|
|
21
|
+
return snap.speak_now_count ?? 0;
|
|
22
|
+
}
|
|
23
|
+
export async function statuslineCmd(o) {
|
|
24
|
+
const snap = await readCachedDigest();
|
|
25
|
+
if (!snap) {
|
|
26
|
+
console.log("CodeBus: — (run: codebus digest refresh)");
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const ttlSec = parseInt(process.env.CODEBUS_STATUSLINE_TTL ?? "120", 10);
|
|
30
|
+
const ageSec = (Date.now() - Date.parse(snap.generated_at)) / 1000;
|
|
31
|
+
const stale = Number.isFinite(ageSec) ? ageSec > ttlSec : true;
|
|
32
|
+
const speakNowCount = countSpeakNow(snap);
|
|
33
|
+
if (o.json) {
|
|
34
|
+
console.log(JSON.stringify({ ...snap, stale, speak_now_count: speakNowCount }, null, 2));
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const parts = ORDER.filter((k) => snap.counts[k]).map((k) => `${snap.counts[k]} ${k}`);
|
|
38
|
+
const body = parts.length ? parts.join(" | ") : "clear";
|
|
39
|
+
// speak_now highlight: prefix with !! URGENT N to make it visually prominent.
|
|
40
|
+
const urgentPrefix = speakNowCount > 0 ? `!! URGENT ${speakNowCount} | ` : "";
|
|
41
|
+
console.log(`CodeBus: ${urgentPrefix}${body}${stale ? " (stale)" : ""}`);
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=statusline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"statusline.js","sourceRoot":"","sources":["../../src/commands/statusline.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAkB,MAAM,aAAa,CAAC;AAE/D,2EAA2E;AAC3E,6EAA6E;AAC7E,6EAA6E;AAC7E,wEAAwE;AACxE,qEAAqE;AACrE,4EAA4E;AAC5E,4EAA4E;AAC5E,iEAAiE;AACjE,gDAAgD;AAChD,6EAA6E;AAC7E,8EAA8E;AAC9E,yEAAyE;AACzE,8CAA8C;AAC9C,MAAM,KAAK,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;AAE/F;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,IAAoB;IAChD,OAAO,IAAI,CAAC,eAAe,IAAI,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,CAAqB;IACvD,MAAM,IAAI,GAAG,MAAM,gBAAgB,EAAE,CAAC;IACtC,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;QACxD,OAAO;IACT,CAAC;IACD,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,sBAAsB,IAAI,KAAK,EAAE,EAAE,CAAC,CAAC;IACzE,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,GAAG,IAAI,CAAC;IACnE,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;IAE/D,MAAM,aAAa,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IAE1C,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;QACX,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QACzF,OAAO;IACT,CAAC;IACD,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACvF,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IACxD,8EAA8E;IAC9E,MAAM,YAAY,GAAG,aAAa,GAAG,CAAC,CAAC,CAAC,CAAC,aAAa,aAAa,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9E,OAAO,CAAC,GAAG,CAAC,YAAY,YAAY,GAAG,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAC3E,CAAC"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { resolveConfig } from "../config.js";
|
|
2
|
+
import { makeCtx, workspaceId, projectId } from "../client.js";
|
|
3
|
+
import { render } from "../output.js";
|
|
4
|
+
import { CodebusError } from "../errors.js";
|
|
5
|
+
import { parseRef, writeRefs } from "./refs.js";
|
|
6
|
+
/**
|
|
7
|
+
* Resolve a task display ID (CB-TASK-…) or UUID to UUID.
|
|
8
|
+
* display ids are only unique per workspace (bus_counters, 0004) — always
|
|
9
|
+
* scope the lookup, or a multi-workspace agent can resolve the WRONG
|
|
10
|
+
* workspace's task when two workspaces happen to share a display_id.
|
|
11
|
+
*/
|
|
12
|
+
async function resolveTaskId(ctx, idOrDisplay) {
|
|
13
|
+
if (/^CB-TASK-/i.test(idOrDisplay)) {
|
|
14
|
+
const ws = await workspaceId(ctx);
|
|
15
|
+
const { data, error } = await ctx.supabase.from("tasks").select("id")
|
|
16
|
+
.eq("workspace_id", ws).eq("display_id", idOrDisplay.toUpperCase()).single();
|
|
17
|
+
if (error || !data)
|
|
18
|
+
throw new CodebusError(`task not found: ${idOrDisplay}`);
|
|
19
|
+
return data.id;
|
|
20
|
+
}
|
|
21
|
+
return idOrDisplay;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Shared core: create a task.
|
|
25
|
+
* Exported for reuse in MCP tool.
|
|
26
|
+
*/
|
|
27
|
+
export async function createTaskCore(ctx, opts) {
|
|
28
|
+
const ws = await workspaceId(ctx);
|
|
29
|
+
let ownerId = null;
|
|
30
|
+
if (opts.owner) {
|
|
31
|
+
const { data } = await ctx.supabase.from("agents").select("id").eq("slug", opts.owner).single();
|
|
32
|
+
if (!data)
|
|
33
|
+
throw new CodebusError(`unknown owner: ${opts.owner}`);
|
|
34
|
+
ownerId = data.id;
|
|
35
|
+
}
|
|
36
|
+
const projId = await projectId(ctx, ws, opts.project);
|
|
37
|
+
const { data: task, error } = await ctx.supabase.from("tasks")
|
|
38
|
+
.insert({ workspace_id: ws, project_id: projId, title: opts.title, body: opts.body ?? null, owner_agent_id: ownerId })
|
|
39
|
+
.select().single();
|
|
40
|
+
if (error)
|
|
41
|
+
throw new CodebusError(error.message);
|
|
42
|
+
// Write knowledge refs if provided
|
|
43
|
+
if (opts.refs && opts.refs.length > 0) {
|
|
44
|
+
const parsed = opts.refs.map((r) => parseRef(r));
|
|
45
|
+
await writeRefs(ctx, ws, "task", task.id, parsed);
|
|
46
|
+
}
|
|
47
|
+
return { display_id: task.display_id, title: task.title, status: task.status, id: task.id };
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Shared core: claim a task.
|
|
51
|
+
* Exported for reuse in MCP tool.
|
|
52
|
+
*/
|
|
53
|
+
export async function claimTaskCore(ctx, idOrDisplay) {
|
|
54
|
+
const id = await resolveTaskId(ctx, idOrDisplay);
|
|
55
|
+
const { data, error } = await ctx.supabase.rpc("claim_task", { p_task: id });
|
|
56
|
+
if (error)
|
|
57
|
+
throw new CodebusError(error.message);
|
|
58
|
+
const row = Array.isArray(data) ? data[0] : data;
|
|
59
|
+
return { display_id: row.display_id, status: row.status, done: row.done };
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Shared core: mark a task done.
|
|
63
|
+
* Exported for reuse in MCP tool.
|
|
64
|
+
*/
|
|
65
|
+
export async function completeTaskCore(ctx, idOrDisplay, opts = {}) {
|
|
66
|
+
const id = await resolveTaskId(ctx, idOrDisplay);
|
|
67
|
+
// Evidence-required done (plan §4 item 2): the RPC itself refuses bare
|
|
68
|
+
// completion (neither p_evidence nor p_no_evidence_reason), so the error
|
|
69
|
+
// surfaces from the server verbatim — no client-side pre-check duplicating
|
|
70
|
+
// that rule here.
|
|
71
|
+
const { data, error } = await ctx.supabase.rpc("complete_task", {
|
|
72
|
+
p_task: id,
|
|
73
|
+
p_evidence: opts.evidence ?? null,
|
|
74
|
+
p_note: opts.note ?? null,
|
|
75
|
+
p_no_evidence_reason: opts.noEvidenceReason ?? null,
|
|
76
|
+
});
|
|
77
|
+
if (error)
|
|
78
|
+
throw new CodebusError(error.message);
|
|
79
|
+
const row = Array.isArray(data) ? data[0] : data;
|
|
80
|
+
return { display_id: row.display_id, status: row.status, done: row.done };
|
|
81
|
+
}
|
|
82
|
+
async function createTask(o) {
|
|
83
|
+
const ctx = await makeCtx(resolveConfig(o));
|
|
84
|
+
const rawRefs = o.ref ? o.ref.split(",").map((s) => s.trim()).filter(Boolean) : undefined;
|
|
85
|
+
const task = await createTaskCore(ctx, { title: o.title, body: o.body, owner: o.owner, project: o.project, refs: rawRefs });
|
|
86
|
+
console.log(render([{ display_id: task.display_id, title: task.title, status: task.status }], { json: !!o.json }));
|
|
87
|
+
}
|
|
88
|
+
async function listTasks(o) {
|
|
89
|
+
const ctx = await makeCtx(resolveConfig(o));
|
|
90
|
+
const ws = await workspaceId(ctx);
|
|
91
|
+
const projId = await projectId(ctx, ws, o.project);
|
|
92
|
+
let q = ctx.supabase.from("tasks").select("display_id, title, status, done, owner_agent_id");
|
|
93
|
+
if (o.status)
|
|
94
|
+
q = q.eq("status", o.status);
|
|
95
|
+
if (projId)
|
|
96
|
+
q = q.eq("project_id", projId);
|
|
97
|
+
const { data, error } = await q.order("created_at", { ascending: false });
|
|
98
|
+
if (error)
|
|
99
|
+
throw new CodebusError(error.message);
|
|
100
|
+
console.log(render(data ?? [], { json: !!o.json }));
|
|
101
|
+
}
|
|
102
|
+
async function runRpc(name, args, o, idOrDisplay) {
|
|
103
|
+
const ctx = await makeCtx(resolveConfig(o));
|
|
104
|
+
const id = await resolveTaskId(ctx, idOrDisplay);
|
|
105
|
+
const { data, error } = await ctx.supabase.rpc(name, { p_task: id, ...args });
|
|
106
|
+
if (error)
|
|
107
|
+
throw new CodebusError(error.message);
|
|
108
|
+
const row = Array.isArray(data) ? data[0] : data;
|
|
109
|
+
console.log(render([{ display_id: row.display_id, status: row.status, done: row.done }], { json: !!o.json }));
|
|
110
|
+
}
|
|
111
|
+
export function registerTask(program, g) {
|
|
112
|
+
const task = program.command("task").description("task operations");
|
|
113
|
+
g(task.command("create")).requiredOption("--title <t>").option("--body <b>").option("--owner <slug>").option("--project <slug>").option("--ref <refs>", "comma-separated knowledge refs (e.g. CB-DEC-000001,commit:<sha>)").action(createTask);
|
|
114
|
+
g(task.command("list")).option("--owner <slug>").option("--status <s>").option("--project <slug>").action(listTasks);
|
|
115
|
+
g(task.command("claim").argument("<id>")).action(async (id, o) => {
|
|
116
|
+
const ctx = await makeCtx(resolveConfig(o));
|
|
117
|
+
const result = await claimTaskCore(ctx, id);
|
|
118
|
+
console.log(render([result], { json: !!o.json }));
|
|
119
|
+
});
|
|
120
|
+
g(task.command("done").argument("<id>"))
|
|
121
|
+
.option("--evidence <ref>")
|
|
122
|
+
.option("--note <n>")
|
|
123
|
+
// NOT named --no-evidence-reason: commander treats any --no-* flag as a
|
|
124
|
+
// boolean negation of a same-named positive option and stores its value
|
|
125
|
+
// under the prefix-stripped property (`evidenceReason`, not
|
|
126
|
+
// `noEvidenceReason`) regardless of whether it takes a value — a subtle
|
|
127
|
+
// footgun that silently dropped this flag's value in an earlier draft.
|
|
128
|
+
// --escape-reason sidesteps that parser special-case entirely.
|
|
129
|
+
.option("--escape-reason <reason>", "explicit escape hatch when there is truly no evidence to attach (recorded, not silent)")
|
|
130
|
+
.action(async (id, o) => {
|
|
131
|
+
const ctx = await makeCtx(resolveConfig(o));
|
|
132
|
+
const result = await completeTaskCore(ctx, id, { evidence: o.evidence, note: o.note, noEvidenceReason: o.escapeReason });
|
|
133
|
+
console.log(render([result], { json: !!o.json }));
|
|
134
|
+
});
|
|
135
|
+
g(task.command("block").argument("<id>")).requiredOption("--note <n>").action((id, o) => runRpc("block_task", { p_note: o.note }, o, id));
|
|
136
|
+
g(task.command("review").argument("<id>")).option("--note <n>").action((id, o) => runRpc("review_task", { p_note: o.note ?? null }, o, id));
|
|
137
|
+
g(task.command("reopen").argument("<id>")).option("--note <n>").action((id, o) => runRpc("reopen_task", { p_note: o.note ?? null }, o, id));
|
|
138
|
+
g(task.command("cancel").argument("<id>")).option("--note <n>").action((id, o) => runRpc("cancel_task", { p_note: o.note ?? null }, o, id));
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=task.js.map
|