@bragi-gmbh/codebus 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/bin/codebus.js +2 -0
  2. package/dist/binding-guard.js +97 -0
  3. package/dist/binding-guard.js.map +1 -0
  4. package/dist/client.js +94 -0
  5. package/dist/client.js.map +1 -0
  6. package/dist/commands/ack.js +47 -0
  7. package/dist/commands/ack.js.map +1 -0
  8. package/dist/commands/archive.js +21 -0
  9. package/dist/commands/archive.js.map +1 -0
  10. package/dist/commands/as.js +299 -0
  11. package/dist/commands/as.js.map +1 -0
  12. package/dist/commands/ask.js +189 -0
  13. package/dist/commands/ask.js.map +1 -0
  14. package/dist/commands/auth.js +33 -0
  15. package/dist/commands/auth.js.map +1 -0
  16. package/dist/commands/checkin.js +235 -0
  17. package/dist/commands/checkin.js.map +1 -0
  18. package/dist/commands/decision.js +52 -0
  19. package/dist/commands/decision.js.map +1 -0
  20. package/dist/commands/digest.js +117 -0
  21. package/dist/commands/digest.js.map +1 -0
  22. package/dist/commands/doctor.js +106 -0
  23. package/dist/commands/doctor.js.map +1 -0
  24. package/dist/commands/factory.js +191 -0
  25. package/dist/commands/factory.js.map +1 -0
  26. package/dist/commands/github-login.js +205 -0
  27. package/dist/commands/github-login.js.map +1 -0
  28. package/dist/commands/graph.js +88 -0
  29. package/dist/commands/graph.js.map +1 -0
  30. package/dist/commands/health.js +34 -0
  31. package/dist/commands/health.js.map +1 -0
  32. package/dist/commands/inbox.js +83 -0
  33. package/dist/commands/inbox.js.map +1 -0
  34. package/dist/commands/ingest.js +553 -0
  35. package/dist/commands/ingest.js.map +1 -0
  36. package/dist/commands/init.js +97 -0
  37. package/dist/commands/init.js.map +1 -0
  38. package/dist/commands/install.js +520 -0
  39. package/dist/commands/install.js.map +1 -0
  40. package/dist/commands/invite.js +152 -0
  41. package/dist/commands/invite.js.map +1 -0
  42. package/dist/commands/jira.js +237 -0
  43. package/dist/commands/jira.js.map +1 -0
  44. package/dist/commands/join.js +96 -0
  45. package/dist/commands/join.js.map +1 -0
  46. package/dist/commands/links.js +66 -0
  47. package/dist/commands/links.js.map +1 -0
  48. package/dist/commands/login.js +84 -0
  49. package/dist/commands/login.js.map +1 -0
  50. package/dist/commands/morning.js +121 -0
  51. package/dist/commands/morning.js.map +1 -0
  52. package/dist/commands/next.js +66 -0
  53. package/dist/commands/next.js.map +1 -0
  54. package/dist/commands/onboarding.js +109 -0
  55. package/dist/commands/onboarding.js.map +1 -0
  56. package/dist/commands/pack.js +276 -0
  57. package/dist/commands/pack.js.map +1 -0
  58. package/dist/commands/plan-gh.js +425 -0
  59. package/dist/commands/plan-gh.js.map +1 -0
  60. package/dist/commands/plan.js +465 -0
  61. package/dist/commands/plan.js.map +1 -0
  62. package/dist/commands/pr.js +88 -0
  63. package/dist/commands/pr.js.map +1 -0
  64. package/dist/commands/question.js +142 -0
  65. package/dist/commands/question.js.map +1 -0
  66. package/dist/commands/read.js +84 -0
  67. package/dist/commands/read.js.map +1 -0
  68. package/dist/commands/refs.js +357 -0
  69. package/dist/commands/refs.js.map +1 -0
  70. package/dist/commands/reply.js +38 -0
  71. package/dist/commands/reply.js.map +1 -0
  72. package/dist/commands/repo.js +1198 -0
  73. package/dist/commands/repo.js.map +1 -0
  74. package/dist/commands/report.js +41 -0
  75. package/dist/commands/report.js.map +1 -0
  76. package/dist/commands/resolve-refs.js +21 -0
  77. package/dist/commands/resolve-refs.js.map +1 -0
  78. package/dist/commands/resolve.js +93 -0
  79. package/dist/commands/resolve.js.map +1 -0
  80. package/dist/commands/send.js +168 -0
  81. package/dist/commands/send.js.map +1 -0
  82. package/dist/commands/sent.js +22 -0
  83. package/dist/commands/sent.js.map +1 -0
  84. package/dist/commands/session.js +426 -0
  85. package/dist/commands/session.js.map +1 -0
  86. package/dist/commands/statusline.js +43 -0
  87. package/dist/commands/statusline.js.map +1 -0
  88. package/dist/commands/task.js +140 -0
  89. package/dist/commands/task.js.map +1 -0
  90. package/dist/commands/tick.js +233 -0
  91. package/dist/commands/tick.js.map +1 -0
  92. package/dist/commands/upgrade.js +76 -0
  93. package/dist/commands/upgrade.js.map +1 -0
  94. package/dist/commands/watch.js +169 -0
  95. package/dist/commands/watch.js.map +1 -0
  96. package/dist/commands/whoami.js +27 -0
  97. package/dist/commands/whoami.js.map +1 -0
  98. package/dist/config.js +103 -0
  99. package/dist/config.js.map +1 -0
  100. package/dist/directives.js +102 -0
  101. package/dist/directives.js.map +1 -0
  102. package/dist/errors.js +110 -0
  103. package/dist/errors.js.map +1 -0
  104. package/dist/git-hooks.js +116 -0
  105. package/dist/git-hooks.js.map +1 -0
  106. package/dist/graph-bootstrap.js +95 -0
  107. package/dist/graph-bootstrap.js.map +1 -0
  108. package/dist/graph-remote.js +889 -0
  109. package/dist/graph-remote.js.map +1 -0
  110. package/dist/graph.js +335 -0
  111. package/dist/graph.js.map +1 -0
  112. package/dist/index.js +154 -0
  113. package/dist/index.js.map +1 -0
  114. package/dist/kit/graph-publish.mjs +400 -0
  115. package/dist/mail-latency.js +120 -0
  116. package/dist/mail-latency.js.map +1 -0
  117. package/dist/mcp-registry.js +859 -0
  118. package/dist/mcp-registry.js.map +1 -0
  119. package/dist/mcp.js +193 -0
  120. package/dist/mcp.js.map +1 -0
  121. package/dist/output.js +12 -0
  122. package/dist/output.js.map +1 -0
  123. package/dist/positioning.js +21 -0
  124. package/dist/positioning.js.map +1 -0
  125. package/dist/rolestore.js +89 -0
  126. package/dist/rolestore.js.map +1 -0
  127. package/dist/session.js +49 -0
  128. package/dist/session.js.map +1 -0
  129. package/dist/sessionstore.js +736 -0
  130. package/dist/sessionstore.js.map +1 -0
  131. package/dist/version-check.js +97 -0
  132. package/dist/version-check.js.map +1 -0
  133. package/package.json +47 -0
package/bin/codebus.js ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import("../dist/index.js");
@@ -0,0 +1,97 @@
1
+ // Shared directory-binding safety guard (FM-7, docs/plans/
2
+ // codebus-v2-reliability.md §2.3 + §6.1). Used by BOTH commands that can
3
+ // create a directory binding today — `codebus as --bind` (the only one, per
4
+ // the owner's locked decision: checkin stops auto-binding directories) — and
5
+ // kept in its own module so a future second writer never has to reimplement
6
+ // or diverge from it. Two independent hazards, one guard:
7
+ //
8
+ // 1. GENERIC_DIRS: a fixed list of directory names too common to trust as a
9
+ // machine-wide identity anchor (field incident: a checkin from /tmp bound
10
+ // the literal pattern 'tmp', which then matched EVERY tmp dir on the
11
+ // machine — unrelated sessions silently resolved as that agent).
12
+ // 2. Uniqueness-by-recorded-path: a fixed list can never catch a
13
+ // real-but-shared name — 'CodeBus' slipped it (a genuine, specific name
14
+ // that still recurs across clones/checkouts) and ended up bound
15
+ // machine-wide. Instead of guessing more names onto the list, track the
16
+ // actual directory each bare-basename binding was recorded from
17
+ // (Binding.boundFrom, rolestore.ts); a second bind of the same basename
18
+ // from a DIFFERENT recorded path means the pattern is genuinely ambiguous
19
+ // — refuse and point at a full-path pattern instead (which globToRegExp
20
+ // matches against the whole absolute path, not just the basename).
21
+ //
22
+ // That comparison only fires when the EXISTING binding has a boundFrom to
23
+ // compare against. A legacy binding (written before this field existed, so
24
+ // `boundFrom` is simply absent — every pre-existing roles.json entry keeps
25
+ // loading unchanged, by design) has no recorded path at all, and the old
26
+ // check's `!!b.boundFrom` term silently treated "no provenance" as "no
27
+ // conflict" — a second `as --bind` of the same bare basename from a
28
+ // DIFFERENT clone would sail through and silently replace the legacy
29
+ // mapping, which is exactly the takeover this guard exists to stop. There
30
+ // is no way to tell "same directory, re-bound" from "different directory,
31
+ // ambiguous" without a recorded path to compare against, so a matching
32
+ // legacy binding fails closed unconditionally: bind it again only via an
33
+ // explicit `as --unbind` first, or sidestep the ambiguity with a full-path
34
+ // pattern.
35
+ //
36
+ // Round-2 review: the legacy check used `.find()`, which only inspects the
37
+ // FIRST binding matching `pattern` — a store can (and, once one write path
38
+ // has a bug, does) hold more than one binding for the same pattern, e.g.
39
+ // [{pattern:'lane', role:'new', boundFrom:'/same/lane'},
40
+ // {pattern:'lane', role:'legacy'}]. `.find()` stops at the first (safe,
41
+ // provenanced) entry and never looks at the second (legacy, unprovenanced)
42
+ // one, so `bindRole` sails through and silently overwrites/duplicates the
43
+ // legacy mapping — the exact takeover the legacy check above exists to
44
+ // stop. Every binding matching `pattern` is now collected and checked: if
45
+ // ANY of them lacks boundFrom, the whole bind is refused, regardless of
46
+ // where it sits in the list.
47
+ export const GENERIC_DIRS = new Set([
48
+ "tmp", "temp", "src", "lib", "bin", "cli", "app", "web", "api", "test",
49
+ "tests", "build", "dist", "out", "home", "work", "code", "repo", "repos",
50
+ "dev", "docs", "scripts", "packages", "desktop", "documents", "downloads",
51
+ ]);
52
+ /**
53
+ * Guard a candidate (pattern, cwd) pair BEFORE it's written as a binding.
54
+ * Only bare-basename patterns (no `/`) are checked — a full-path pattern is
55
+ * already unambiguous by construction.
56
+ */
57
+ export function checkBindingSafety(store, pattern, cwd) {
58
+ if (pattern.includes("/"))
59
+ return { ok: true };
60
+ const lower = pattern.toLowerCase();
61
+ if (GENERIC_DIRS.has(lower)) {
62
+ return {
63
+ ok: false,
64
+ reason: `'${pattern}' is too generic a name to bind — it would match every '${pattern}' directory on ` +
65
+ `the machine. Use a full-path pattern instead: --pattern '${cwd}'`,
66
+ };
67
+ }
68
+ // ALL bindings matching this pattern, not just the first — a store can
69
+ // hold more than one entry for the same pattern (a prior bug, a hand-edited
70
+ // file, a partially-applied migration), and a legacy one hiding behind a
71
+ // provenanced one must still be caught.
72
+ const matches = (store.bindings ?? []).filter((b) => b.pattern === pattern);
73
+ const legacy = matches.find((b) => !b.boundFrom);
74
+ if (legacy) {
75
+ // Legacy binding, no recorded source directory — cannot prove this is a
76
+ // same-directory re-bind rather than a different clone silently stealing
77
+ // the mapping, so refuse unconditionally rather than guess. Fail closed.
78
+ return {
79
+ ok: false,
80
+ reason: `'${pattern}' is already bound to '${legacy.role}' from a legacy entry with no recorded source ` +
81
+ `directory — binding it again from ${cwd} could silently replace a DIFFERENT directory's mapping (there's ` +
82
+ `no provenance to check it against). Either remove the legacy binding first (codebus as --unbind ` +
83
+ `'${pattern}') or use a full-path pattern instead: --pattern '${cwd}'`,
84
+ };
85
+ }
86
+ const conflict = matches.find((b) => b.boundFrom !== cwd);
87
+ if (conflict) {
88
+ return {
89
+ ok: false,
90
+ reason: `'${pattern}' is already bound from a different directory (${conflict.boundFrom}) — binding it ` +
91
+ `again from ${cwd} would make the pattern ambiguous between the two. Use a full-path pattern instead: ` +
92
+ `--pattern '${cwd}'`,
93
+ };
94
+ }
95
+ return { ok: true };
96
+ }
97
+ //# sourceMappingURL=binding-guard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"binding-guard.js","sourceRoot":"","sources":["../src/binding-guard.ts"],"names":[],"mappings":"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"}
package/dist/client.js ADDED
@@ -0,0 +1,94 @@
1
+ import { createClient } from "@supabase/supabase-js";
2
+ import { getSession } from "./session.js";
3
+ import { CodebusError } from "./errors.js";
4
+ export async function makeCtx(cfg) {
5
+ // supabase-js needs an apikey; resolved by config (flags > env > config file).
6
+ const ANON = cfg.anonKey ?? "";
7
+ // cfg.assume: the token is the AUTHOR's credential and the session is minted
8
+ // server-side AS the named role (auth edge function ownership check).
9
+ const session = await getSession(cfg.url, cfg.token, fetch, ANON, cfg.assume);
10
+ if (cfg.agent && cfg.agent !== session.agent.slug)
11
+ throw new CodebusError(`--agent/CODEBUS_AGENT='${cfg.agent}' does not match the authenticated agent '${session.agent.slug}' (check CODEBUS_TOKEN)`);
12
+ const supabase = createClient(cfg.url, ANON, {
13
+ global: { headers: { Authorization: `Bearer ${session.jwt}`, apikey: ANON } },
14
+ auth: { persistSession: false, autoRefreshToken: false },
15
+ });
16
+ // Realtime authenticates separately from the HTTP headers above; without this,
17
+ // `watch` subscriptions connect as anon and RLS hides the agent's changes.
18
+ supabase.realtime.setAuth(session.jwt);
19
+ return { supabase, agentSlug: session.agent.slug, workspaceSlug: cfg.workspace, identitySource: cfg.identitySource };
20
+ }
21
+ /** True when `ctx`'s identity came from this directory's default binding
22
+ * rather than something the caller actually asserted (a flag, env token, or
23
+ * THIS session's own checkin). Safe in a directory one agent alone owns;
24
+ * unsafe the moment that directory is shared, since a fresh session's very
25
+ * first command — before it has checked in — silently inherits whichever
26
+ * agent the directory happens to default to. Callers that render one
27
+ * identity's private data (inbox, read, next) should warn on this. */
28
+ export function identityIsGuessed(ctx) {
29
+ return ctx.identitySource === "cwd-binding";
30
+ }
31
+ export const guessedIdentityWarning = (ctx, what = "results") => `⚠ codebus: these ${what} belong to '${ctx.agentSlug}', via this directory's DEFAULT binding — not an identity you asserted. ` +
32
+ `If you are not '${ctx.agentSlug}', STOP and run: codebus checkin <your-name>\n`;
33
+ // Resolves a workspace slug to its id (member-visible under RLS).
34
+ export async function workspaceId(ctx) {
35
+ const { data, error } = await ctx.supabase.from("workspaces").select("id").eq("slug", ctx.workspaceSlug).single();
36
+ if (error || !data)
37
+ throw new CodebusError(`workspace not found or not a member: ${ctx.workspaceSlug}`);
38
+ return data.id;
39
+ }
40
+ // Resolves an optional project slug to its id within a workspace.
41
+ export async function projectId(ctx, ws, slug) {
42
+ if (!slug)
43
+ return null;
44
+ const { data, error } = await ctx.supabase.from("projects").select("id").eq("workspace_id", ws).eq("slug", slug).single();
45
+ if (error || !data)
46
+ throw new CodebusError(`project not found in workspace: ${slug}`);
47
+ return data.id;
48
+ }
49
+ // Resolves an optional repo slug to its id within a workspace.
50
+ //
51
+ // Round-20 review finding (CONFIRMED, PR #55 comment 3827670905): this used
52
+ // to be a bare `.eq("slug", slug)` lookup — it neither rejected a retired
53
+ // row nor followed `retired_into`, so any of this function's callers
54
+ // (repo.ts's statusAction via the `resolveRepoIdBySlug` alias, pr.ts,
55
+ // jira.ts, question.ts, plan.ts) resolved a retired `-dup-<n>` loser slug
56
+ // (collapse_duplicate_repo_group renames a loser, never deletes it) to
57
+ // that dead repo_id instead of transparently following the chain to its
58
+ // canonical repo — the exact class of bug the round-17 `graph_resolve_
59
+ // repo_id` fix (0070_repo_connect.sql) already closed for every graph
60
+ // query RPC. Fixed here, in this ONE shared helper, by delegating to that
61
+ // same RPC (`security invoker`, granted to `authenticated`, already called
62
+ // this way from graph-remote.ts) rather than re-implementing its bounded
63
+ // retired_into-chain walk client-side — every caller above gets the fix
64
+ // for free, with no change to their own code. `ws` is kept in the
65
+ // signature for interface stability (every caller already derives it from
66
+ // this same `ctx` via `workspaceId()` above, so `ctx.workspaceSlug` names
67
+ // the identical workspace) even though the RPC call below no longer reads
68
+ // it directly. The not-found error message is deliberately preserved
69
+ // verbatim rather than passed through from the RPC's own exception text,
70
+ // so this remains a pure internal-resolution swap with no user-visible
71
+ // wording change for the (unaffected, already-correct) "truly unknown
72
+ // slug" case.
73
+ //
74
+ // Deliberately does NOT surface a "resolved to canonical slug" redirect
75
+ // note the way ingest.ts's resolveConnectedRepo/`repo connect` do — this
76
+ // function returns a bare id, not a row a caller could compare requested-
77
+ // vs-resolved against, and giving it that would mean widening this shared
78
+ // helper's return shape plus touching every one of the 5 call sites' own
79
+ // human-mode output — materially larger than closing the correctness gap
80
+ // itself. The resolution is correct either way; only the redirect UX is
81
+ // narrower here than on the ingest/connect paths.
82
+ export async function repoId(ctx, ws, slug) {
83
+ if (!slug)
84
+ return null;
85
+ const { data, error } = await ctx.supabase.rpc("graph_resolve_repo_id", {
86
+ p_caller: "codebus-cli",
87
+ p_repo_slug: slug,
88
+ p_workspace_slug: ctx.workspaceSlug,
89
+ });
90
+ if (error || !data)
91
+ throw new CodebusError(`repo not found in workspace: ${slug}`);
92
+ return data;
93
+ }
94
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAkB,MAAM,uBAAuB,CAAC;AACrE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAS3C,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,GAAW;IACvC,+EAA+E;IAC/E,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC;IAC/B,6EAA6E;IAC7E,sEAAsE;IACtE,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC9E,IAAI,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,KAAK,KAAK,OAAO,CAAC,KAAK,CAAC,IAAI;QAC/C,MAAM,IAAI,YAAY,CAAC,0BAA0B,GAAG,CAAC,KAAK,6CAA6C,OAAO,CAAC,KAAK,CAAC,IAAI,yBAAyB,CAAC,CAAC;IACtJ,MAAM,QAAQ,GAAG,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE;QAC3C,MAAM,EAAE,EAAE,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE;QAC7E,IAAI,EAAE,EAAE,cAAc,EAAE,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE;KACzD,CAAC,CAAC;IACH,+EAA+E;IAC/E,2EAA2E;IAC3E,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACvC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,aAAa,EAAE,GAAG,CAAC,SAAS,EAAE,cAAc,EAAE,GAAG,CAAC,cAAc,EAAE,CAAC;AACvH,CAAC;AAED;;;;;;sEAMsE;AACtE,MAAM,UAAU,iBAAiB,CAAC,GAAQ;IACxC,OAAO,GAAG,CAAC,cAAc,KAAK,aAAa,CAAC;AAC9C,CAAC;AAED,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,GAAQ,EAAE,IAAI,GAAG,SAAS,EAAE,EAAE,CACnE,oBAAoB,IAAI,eAAe,GAAG,CAAC,SAAS,0EAA0E;IAC9H,mBAAmB,GAAG,CAAC,SAAS,gDAAgD,CAAC;AAEnF,kEAAkE;AAClE,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,GAAQ;IACxC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,CAAC,aAAa,CAAC,CAAC,MAAM,EAAE,CAAC;IAClH,IAAI,KAAK,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,YAAY,CAAC,wCAAwC,GAAG,CAAC,aAAa,EAAE,CAAC,CAAC;IACxG,OAAO,IAAI,CAAC,EAAE,CAAC;AACjB,CAAC;AAED,kEAAkE;AAClE,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,GAAQ,EAAE,EAAU,EAAE,IAAa;IACjE,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC;IAC1H,IAAI,KAAK,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,YAAY,CAAC,mCAAmC,IAAI,EAAE,CAAC,CAAC;IACtF,OAAO,IAAI,CAAC,EAAE,CAAC;AACjB,CAAC;AAED,+DAA+D;AAC/D,EAAE;AACF,4EAA4E;AAC5E,0EAA0E;AAC1E,qEAAqE;AACrE,sEAAsE;AACtE,0EAA0E;AAC1E,uEAAuE;AACvE,wEAAwE;AACxE,uEAAuE;AACvE,sEAAsE;AACtE,0EAA0E;AAC1E,2EAA2E;AAC3E,yEAAyE;AACzE,wEAAwE;AACxE,kEAAkE;AAClE,0EAA0E;AAC1E,0EAA0E;AAC1E,0EAA0E;AAC1E,qEAAqE;AACrE,yEAAyE;AACzE,uEAAuE;AACvE,sEAAsE;AACtE,cAAc;AACd,EAAE;AACF,wEAAwE;AACxE,yEAAyE;AACzE,0EAA0E;AAC1E,0EAA0E;AAC1E,yEAAyE;AACzE,yEAAyE;AACzE,wEAAwE;AACxE,kDAAkD;AAClD,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,GAAQ,EAAE,EAAU,EAAE,IAAa;IAC9D,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,uBAAuB,EAAE;QACtE,QAAQ,EAAE,aAAa;QACvB,WAAW,EAAE,IAAI;QACjB,gBAAgB,EAAE,GAAG,CAAC,aAAa;KACpC,CAAC,CAAC;IACH,IAAI,KAAK,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,YAAY,CAAC,gCAAgC,IAAI,EAAE,CAAC,CAAC;IACnF,OAAO,IAAc,CAAC;AACxB,CAAC"}
@@ -0,0 +1,47 @@
1
+ import { resolveConfig } from "../config.js";
2
+ import { makeCtx, workspaceId } from "../client.js";
3
+ import { CodebusError } from "../errors.js";
4
+ // `codebus ack <id>` — explicit handled-marker (delivery gap #5). Replying
5
+ // already marks the original handled for the replier (0048 trigger); `ack` is
6
+ // the other lawful way to clear a message from every unread surface — for
7
+ // mail that needed no reply (an FYI, a broadcast note) but was actually acted
8
+ // on / read and dealt with. Mirrors archive.ts's shape (resolve, update own
9
+ // recipient row, done); the mr_update RLS policy (0007) already scopes the
10
+ // update to the caller's own row.
11
+ export async function ackCmd(idOrDisplay, o) {
12
+ const ctx = await makeCtx(resolveConfig(o));
13
+ const isDisplay = /^CB-MSG-/i.test(idOrDisplay);
14
+ const sel = isDisplay ? "display_id" : "id";
15
+ const val = isDisplay ? idOrDisplay.toUpperCase() : idOrDisplay;
16
+ // display ids are only unique per workspace (bus_counters, 0004) — scope
17
+ // the display_id lookup, or a multi-workspace agent could ack the WRONG
18
+ // workspace's message when two workspaces happen to share a display_id.
19
+ let q = ctx.supabase.from("messages").select("id").eq(sel, val);
20
+ if (isDisplay)
21
+ q = q.eq("workspace_id", await workspaceId(ctx));
22
+ const { data: msg, error } = await q.single();
23
+ if (error || !msg)
24
+ throw new CodebusError(`message not found: ${idOrDisplay}`);
25
+ // Review MAJOR finding #6: the update's error/rowcount used to be ignored
26
+ // entirely — a caller who is NOT a recipient of this message (mr_update
27
+ // RLS, 0007, scopes updates to `agent_id = current_agent_id()`) matched zero
28
+ // rows, got no error back from PostgREST, and still printed a success
29
+ // message claiming the message was acked/handled. Select the row back
30
+ // (`.select()`) so the actual affected-row count is visible, and fail
31
+ // loudly on either an error or an empty result.
32
+ const { data: updated, error: uerr } = await ctx.supabase
33
+ .from("message_recipients")
34
+ .update({ handled_at: new Date().toISOString() })
35
+ .eq("message_id", msg.id)
36
+ .select("message_id");
37
+ if (uerr)
38
+ throw new CodebusError(`ack failed: ${uerr.message}`);
39
+ if (!updated || updated.length === 0) {
40
+ throw new CodebusError(`ack failed: you are not a recipient of ${idOrDisplay} (nothing to ack)`);
41
+ }
42
+ if (o.json)
43
+ console.log(JSON.stringify({ acked: idOrDisplay }));
44
+ else
45
+ console.log(`acked ${idOrDisplay} (handled)`);
46
+ }
47
+ //# sourceMappingURL=ack.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ack.js","sourceRoot":"","sources":["../../src/commands/ack.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAa,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,2EAA2E;AAC3E,8EAA8E;AAC9E,0EAA0E;AAC1E,8EAA8E;AAC9E,4EAA4E;AAC5E,2EAA2E;AAC3E,kCAAkC;AAClC,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,WAAmB,EAAE,CAAiC;IACjF,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5C,MAAM,SAAS,GAAG,WAAW,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAChD,MAAM,GAAG,GAAG,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC;IAC5C,MAAM,GAAG,GAAG,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC;IAChE,yEAAyE;IACzE,wEAAwE;IACxE,wEAAwE;IACxE,IAAI,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAChE,IAAI,SAAS;QAAE,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;IAChE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC,CAAC,MAAM,EAAE,CAAC;IAC9C,IAAI,KAAK,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,YAAY,CAAC,sBAAsB,WAAW,EAAE,CAAC,CAAC;IAC/E,0EAA0E;IAC1E,wEAAwE;IACxE,6EAA6E;IAC7E,sEAAsE;IACtE,sEAAsE;IACtE,sEAAsE;IACtE,gDAAgD;IAChD,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,MAAM,GAAG,CAAC,QAAQ;SACtD,IAAI,CAAC,oBAAoB,CAAC;SAC1B,MAAM,CAAC,EAAE,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC;SAChD,EAAE,CAAC,YAAY,EAAE,GAAG,CAAC,EAAE,CAAC;SACxB,MAAM,CAAC,YAAY,CAAC,CAAC;IACxB,IAAI,IAAI;QAAE,MAAM,IAAI,YAAY,CAAC,eAAe,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;IAChE,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrC,MAAM,IAAI,YAAY,CAAC,0CAA0C,WAAW,mBAAmB,CAAC,CAAC;IACnG,CAAC;IACD,IAAI,CAAC,CAAC,IAAI;QAAE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC;;QAC3D,OAAO,CAAC,GAAG,CAAC,SAAS,WAAW,YAAY,CAAC,CAAC;AACrD,CAAC"}
@@ -0,0 +1,21 @@
1
+ import { resolveConfig } from "../config.js";
2
+ import { makeCtx, workspaceId } from "../client.js";
3
+ import { CodebusError } from "../errors.js";
4
+ export async function archiveCmd(idOrDisplay, o) {
5
+ const ctx = await makeCtx(resolveConfig(o));
6
+ const isDisplay = /^CB-MSG-/i.test(idOrDisplay);
7
+ const sel = isDisplay ? "display_id" : "id";
8
+ const val = isDisplay ? idOrDisplay.toUpperCase() : idOrDisplay;
9
+ // display ids are only unique per workspace (bus_counters, 0004) — scope
10
+ // the display_id lookup, or a multi-workspace agent can archive the WRONG
11
+ // workspace's message when two workspaces happen to share a display_id.
12
+ let q = ctx.supabase.from("messages").select("id").eq(sel, val);
13
+ if (isDisplay)
14
+ q = q.eq("workspace_id", await workspaceId(ctx));
15
+ const { data: msg, error } = await q.single();
16
+ if (error || !msg)
17
+ throw new CodebusError(`message not found: ${idOrDisplay}`);
18
+ await ctx.supabase.from("message_recipients").update({ archived_at: new Date().toISOString() }).eq("message_id", msg.id);
19
+ console.log(`archived ${idOrDisplay}`);
20
+ }
21
+ //# sourceMappingURL=archive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"archive.js","sourceRoot":"","sources":["../../src/commands/archive.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAa,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,WAAmB,EAAE,CAAY;IAChE,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5C,MAAM,SAAS,GAAG,WAAW,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAChD,MAAM,GAAG,GAAG,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC;IAC5C,MAAM,GAAG,GAAG,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC;IAChE,yEAAyE;IACzE,0EAA0E;IAC1E,wEAAwE;IACxE,IAAI,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAChE,IAAI,SAAS;QAAE,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;IAChE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC,CAAC,MAAM,EAAE,CAAC;IAC9C,IAAI,KAAK,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,YAAY,CAAC,sBAAsB,WAAW,EAAE,CAAC,CAAC;IAC/E,MAAM,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,YAAY,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;IACzH,OAAO,CAAC,GAAG,CAAC,YAAY,WAAW,EAAE,CAAC,CAAC;AACzC,CAAC"}
@@ -0,0 +1,299 @@
1
+ import { spawn } from "node:child_process";
2
+ import { resolveConfig } from "../config.js";
3
+ import { makeCtx } from "../client.js";
4
+ import { render } from "../output.js";
5
+ import { CodebusError } from "../errors.js";
6
+ // `codebus as <role> -- <cmd>` — run a command as a specific bus role.
7
+ //
8
+ // Why this exists: a session must never own its identity. provision_my_agent()
9
+ // mints a NEW principal per call, which is how nihviid-claude / nihviid-web /
10
+ // nihviid-default got created — the "address-book graveyard" the founding brief
11
+ // bans. Roles are durable and few; sessions are ephemeral and many. This command
12
+ // binds an ephemeral session to a durable role for the life of one process, via
13
+ // CODEBUS_TOKEN in the child env (config.ts precedence: flags > env > file).
14
+ //
15
+ // Tokens are stored ONCE, verified at write time, and never printed again.
16
+ // This is deliberately a local token store, not real credential delegation: N
17
+ // long-lived role tokens on disk is acceptable for one machine and one human,
18
+ // and becomes a liability the moment other people are involved. The proper fix
19
+ // is a server-side assume_role() issuing short-lived JWTs — no such primitive
20
+ // exists yet, so this is honest scaffolding, not the finished thing.
21
+ export { rolesFile, loadRoles, saveRoles } from "../rolestore.js";
22
+ import { rolesFile, loadRoles, saveRoles, inferRole } from "../rolestore.js";
23
+ import { checkBindingSafety } from "../binding-guard.js";
24
+ /**
25
+ * The child env for a role entry — exported for the regression suite (FM-5).
26
+ * A nested `codebus as roleA -- codebus as roleB -- cmd` (or simply running
27
+ * `as` from inside a session that already has CODEBUS_AGENT/CODEBUS_ASSUME
28
+ * set) must not leak the OUTER identity pin into the child: spreading the
29
+ * base env and overlaying only ONE of {CODEBUS_TOKEN, CODEBUS_ASSUME} left
30
+ * CODEBUS_AGENT and/or the other of {CODEBUS_TOKEN, CODEBUS_ASSUME} in place
31
+ * whenever the parent process happened to have them set — a raw-token role
32
+ * would then fail the identity check against a stale CODEBUS_AGENT, and an
33
+ * {assume} role's token-backed child would authenticate under the WRONG
34
+ * assumed role via a stale CODEBUS_ASSUME. Delete every conflicting inherited
35
+ * var first, then set exactly the one shape this entry actually has.
36
+ */
37
+ export function childEnvFor(entry, base = process.env) {
38
+ const env = { ...base };
39
+ delete env.CODEBUS_TOKEN;
40
+ delete env.CODEBUS_AGENT;
41
+ delete env.CODEBUS_ASSUME;
42
+ if (entry.token)
43
+ env.CODEBUS_TOKEN = entry.token;
44
+ else
45
+ env.CODEBUS_ASSUME = entry.assume;
46
+ return env;
47
+ }
48
+ /**
49
+ * Read a secret without echoing it. Tokens must never reach argv — argv leaks
50
+ * into shell history and `ps` output — so --set always prompts or reads a pipe.
51
+ */
52
+ async function readSecret(prompt) {
53
+ const stdin = process.stdin;
54
+ if (!stdin.isTTY) {
55
+ // piped / CI: consume stdin as the token
56
+ return new Promise((resolve, reject) => {
57
+ let data = "";
58
+ stdin.setEncoding("utf8");
59
+ stdin.on("data", (c) => (data += c));
60
+ stdin.on("end", () => resolve(data.trim()));
61
+ stdin.on("error", reject);
62
+ });
63
+ }
64
+ // Prompt on stderr so stdout stays clean for piping.
65
+ process.stderr.write(prompt);
66
+ return new Promise((resolve) => {
67
+ let buf = "";
68
+ stdin.setRawMode(true);
69
+ stdin.resume();
70
+ stdin.setEncoding("utf8");
71
+ const onData = (ch) => {
72
+ if (ch === "\r" || ch === "\n" || ch === "\u0004") {
73
+ stdin.setRawMode(false);
74
+ stdin.pause();
75
+ stdin.removeListener("data", onData);
76
+ process.stderr.write("\n");
77
+ resolve(buf);
78
+ }
79
+ else if (ch === "\u0003") {
80
+ stdin.setRawMode(false);
81
+ process.stderr.write("\n");
82
+ process.exit(130); // ctrl-c
83
+ }
84
+ else if (ch === "\u007f" || ch === "\b") {
85
+ buf = buf.slice(0, -1);
86
+ }
87
+ else {
88
+ buf += ch;
89
+ }
90
+ };
91
+ stdin.on("data", onData);
92
+ });
93
+ }
94
+ /**
95
+ * Store a role's token. Verifies the token authenticates AS the named role
96
+ * before writing — a token stored under the wrong name would silently make
97
+ * every future session act as the wrong identity, which is far worse than
98
+ * failing here.
99
+ */
100
+ async function setRole(role, o) {
101
+ const token = await readSecret(`token for ${role} (not echoed): `);
102
+ if (!token)
103
+ throw new CodebusError("no token provided");
104
+ const cfg = resolveConfig({ url: o.url, anonKey: o.anonKey, token });
105
+ let authed;
106
+ try {
107
+ const ctx = await makeCtx(cfg);
108
+ authed = ctx.agentSlug;
109
+ }
110
+ catch (e) {
111
+ throw new CodebusError(`token rejected: ${e.message}`);
112
+ }
113
+ if (authed !== role) {
114
+ throw new CodebusError(`token authenticates as '${authed}', not '${role}'. ` +
115
+ `Store it under its real name (codebus as --set ${authed}) or use the right token.`);
116
+ }
117
+ const store = loadRoles();
118
+ const existed = !!store.roles[role];
119
+ store.roles[role] = { token, agent: authed, added_at: new Date().toISOString() };
120
+ saveRoles(store);
121
+ console.log(`${existed ? "updated" : "stored"} ${role} (verified as ${authed}) → ${rolesFile()}`);
122
+ }
123
+ function listRoles(o) {
124
+ const store = loadRoles();
125
+ const rows = Object.entries(store.roles).map(([role, e]) => ({
126
+ role, agent: e.agent, added_at: e.added_at,
127
+ }));
128
+ if (!rows.length) {
129
+ console.log(`no roles bound yet — add one with: codebus as --set <role>`);
130
+ return;
131
+ }
132
+ console.log(render(rows, { json: !!o.json })); // never renders tokens
133
+ }
134
+ function forgetRole(role) {
135
+ const store = loadRoles();
136
+ if (!store.roles[role])
137
+ throw new CodebusError(`no such bound role: ${role}`);
138
+ delete store.roles[role];
139
+ saveRoles(store);
140
+ console.log(`forgot ${role}`);
141
+ }
142
+ /**
143
+ * Bind a directory pattern to a role, so `codebus as -- <cmd>` needs no role.
144
+ * The ONLY command that creates directory bindings (owner decision §6.1,
145
+ * docs/plans/codebus-v2-reliability.md — checkin stops auto-binding). Guarded
146
+ * against generic basenames and cross-directory name collisions
147
+ * (binding-guard.ts, FM-7) — both catch the same underlying hazard: a bare
148
+ * basename pattern matching more than the one directory the human meant.
149
+ */
150
+ function bindRole(role, pattern) {
151
+ const store = loadRoles();
152
+ if (!store.roles[role]) {
153
+ throw new CodebusError(`role '${role}' has no stored token yet — run: codebus as --set ${role}`);
154
+ }
155
+ // Default to the current directory's basename as a pattern rather than its
156
+ // full path: the enclosing dir is usually the lane, and a basename pattern
157
+ // survives the worktree being recreated elsewhere.
158
+ const cwd = process.cwd();
159
+ const pat = pattern ?? (cwd.split("/").filter(Boolean).pop() ?? cwd);
160
+ const guard = checkBindingSafety(store, pat, cwd);
161
+ if (!guard.ok)
162
+ throw new CodebusError(guard.reason);
163
+ store.bindings = (store.bindings ?? []).filter((b) => b.pattern !== pat);
164
+ store.bindings.push({ pattern: pat, role, boundFrom: cwd });
165
+ saveRoles(store);
166
+ console.log(`bound ${pat} → ${role}`);
167
+ }
168
+ function unbindPattern(pattern) {
169
+ const store = loadRoles();
170
+ const before = (store.bindings ?? []).length;
171
+ store.bindings = (store.bindings ?? []).filter((b) => b.pattern !== pattern);
172
+ if (store.bindings.length === before) {
173
+ throw new CodebusError(`no binding for pattern: ${pattern}`);
174
+ }
175
+ saveRoles(store);
176
+ console.log(`unbound ${pattern}`);
177
+ }
178
+ function listBindings(o) {
179
+ const store = loadRoles();
180
+ const rows = (store.bindings ?? []).map((b) => ({ pattern: b.pattern, role: b.role }));
181
+ if (!rows.length) {
182
+ console.log(`no path bindings — add one with: codebus as --bind <role> [--pattern '<glob>']`);
183
+ return;
184
+ }
185
+ const hit = inferRole(store, process.cwd());
186
+ console.log(render(rows, { json: !!o.json }));
187
+ console.log(hit ? `\ncwd matches: ${hit.pattern} → ${hit.role}` : `\ncwd matches: (none)`);
188
+ }
189
+ /**
190
+ * Exec a child process bound to a role. Inherits stdio so interactive tools
191
+ * (claude, codex) behave normally, and propagates the child's exit code so
192
+ * this is transparent in scripts and wrappers.
193
+ *
194
+ * Returns a Promise that never itself resolves — index.ts's top-level
195
+ * `program.parseAsync().then(() => process.exit(0))` would otherwise race
196
+ * ahead of the child (commander's action returns as soon as spawn() is
197
+ * called, long before the child finishes) and always exit 0 regardless of
198
+ * the child's real outcome. The event handlers below call process.exit(...)
199
+ * directly with the real code/signal once the child is actually done, which
200
+ * terminates the process before that outer `.then` ever runs.
201
+ */
202
+ function runAs(role, argv) {
203
+ const store = loadRoles();
204
+ const entry = store.roles[role];
205
+ if (!entry) {
206
+ const known = Object.keys(store.roles);
207
+ throw new CodebusError(`role '${role}' is not bound. ${known.length ? `Bound: ${known.join(", ")}. ` : ""}` +
208
+ `Add it with: codebus as --set ${role}`);
209
+ }
210
+ if (!argv.length)
211
+ throw new CodebusError(`nothing to run — usage: codebus as ${role} -- <command> [args…]`);
212
+ if (!entry.token && !entry.assume) {
213
+ throw new CodebusError(`role '${role}' has neither a token nor an assume target — re-add it with: codebus as --set ${role}`);
214
+ }
215
+ const childEnv = childEnvFor(entry); // FM-5: never leaks a stale outer identity pin, see childEnvFor
216
+ const [cmd, ...rest] = argv;
217
+ const child = spawn(cmd, rest, {
218
+ stdio: "inherit",
219
+ // CODEBUS_TOKEN overrides the config file's identity for this process tree.
220
+ // CODEBUS_AGENT is deliberately NOT set: config.ts treats a mismatch between
221
+ // it and the authenticated agent as a hard error, and the token is already
222
+ // authoritative. Setting both invites a confusing failure for no benefit.
223
+ // An {assume} entry has no token to export — CODEBUS_ASSUME names the role
224
+ // instead, and each child mints its session from the author's config.json
225
+ // credential (config.ts threads it; spreading an undefined CODEBUS_TOKEN
226
+ // here would silently run the child as the AUTHOR, the exact misfire `as`
227
+ // exists to prevent).
228
+ env: childEnv,
229
+ });
230
+ child.on("error", (e) => {
231
+ console.error(`error: cannot run '${cmd}': ${e.message}`);
232
+ process.exit(127);
233
+ });
234
+ child.on("exit", (code, signal) => {
235
+ if (signal)
236
+ process.kill(process.pid, signal);
237
+ else
238
+ process.exit(code ?? 0);
239
+ });
240
+ return new Promise(() => { });
241
+ }
242
+ export function registerAs(program, g) {
243
+ g(program.command("as"))
244
+ .description("run a command as a bus role (codebus as <role> -- <cmd>)")
245
+ .argument("[role]", "bound role slug")
246
+ .option("--set <role>", "store a token for a role (prompts; never echoed)")
247
+ .option("--list", "list bound roles (never prints tokens)")
248
+ .option("--forget <role>", "remove a bound role")
249
+ .option("--bind <role>", "bind a directory pattern to a role (default: this dir's name)")
250
+ .option("--pattern <glob>", "pattern for --bind (e.g. 'wt-playkit-*')")
251
+ .option("--unbind <pattern>", "remove a path→role binding")
252
+ .option("--bindings", "list path→role bindings and what cwd resolves to")
253
+ .allowUnknownOption() // everything after `--` belongs to the child
254
+ .action(async (role, o) => {
255
+ if (o.set)
256
+ return setRole(o.set, o);
257
+ if (o.list)
258
+ return listRoles(o);
259
+ if (o.forget)
260
+ return forgetRole(o.forget);
261
+ if (o.bind)
262
+ return bindRole(o.bind, o.pattern);
263
+ if (o.unbind)
264
+ return unbindPattern(o.unbind);
265
+ if (o.bindings)
266
+ return listBindings(o);
267
+ // Read the child argv straight from process.argv: commander's own
268
+ // parsing of `--` passthrough varies with option placement, and getting
269
+ // this wrong would silently run the wrong command.
270
+ const dd = process.argv.indexOf("--");
271
+ const childArgv = dd >= 0 ? process.argv.slice(dd + 1) : [];
272
+ // Commander fills the [role] positional from the FIRST token after `--`
273
+ // (so `as -- echo hi` arrives as role='echo'), which would silently treat
274
+ // the child command as a role name. Only trust `role` if it actually
275
+ // appears before `--` in argv.
276
+ const beforeDD = dd >= 0 ? process.argv.slice(0, dd) : process.argv;
277
+ let resolved = role !== undefined && beforeDD.includes(role) ? role : undefined;
278
+ // No explicit role → infer from cwd. This is the zero-touch path: a
279
+ // session in a bound worktree needs no role argument at all.
280
+ if (!resolved) {
281
+ const store = loadRoles();
282
+ const hit = inferRole(store, process.cwd());
283
+ if (!hit) {
284
+ const bound = Object.keys(store.roles);
285
+ throw new CodebusError(`no role bound for ${process.cwd()}.\n` +
286
+ (bound.length
287
+ ? ` bind it: codebus as --bind <role> [--pattern '<glob>'] (stored roles: ${bound.join(", ")})\n`
288
+ : ` add one: codebus as --set <role>\n`) +
289
+ ` or name it: codebus as <role> -- <command>`);
290
+ }
291
+ resolved = hit.role;
292
+ // Say which rule fired — silent inference of identity is how you end
293
+ // up acting as the wrong agent without noticing.
294
+ console.error(`codebus: ${hit.pattern} → ${resolved}`);
295
+ }
296
+ await runAs(resolved, childArgv);
297
+ });
298
+ }
299
+ //# sourceMappingURL=as.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"as.js","sourceRoot":"","sources":["../../src/commands/as.ts"],"names":[],"mappings":"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"}