@botbuddy/cli 1.17.0 → 1.18.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/package.json +1 -1
- package/src/commands.mjs +6 -1
- package/src/credential-kinds.mjs +66 -0
package/package.json
CHANGED
package/src/commands.mjs
CHANGED
|
@@ -3,6 +3,7 @@ import { doLogin } from "./auth.mjs";
|
|
|
3
3
|
import { runBridge } from "./codex-bridge.mjs";
|
|
4
4
|
import { loadConfig, getConfig, clearConfig, getConfigPath, SERVER_URL } from "./config.mjs";
|
|
5
5
|
import { resolveOwnerToken, resolveAgentKey, clearOwnerToken } from "./cli-credentials.mjs";
|
|
6
|
+
import { agentProfileKeyLabel } from "./credential-kinds.mjs";
|
|
6
7
|
import { buildAcquireResourcesPayload, LocksUsageError } from "./locks.mjs";
|
|
7
8
|
import { CallUsageError, discoveryUrlFor, formatDiscovery, parseCallArgs } from "./discovery.mjs";
|
|
8
9
|
import { cmdStack } from "./stack.mjs";
|
|
@@ -468,7 +469,11 @@ export async function cmdStatus({
|
|
|
468
469
|
}
|
|
469
470
|
const agentKey = await resolveAgent();
|
|
470
471
|
if (agentKey) {
|
|
471
|
-
|
|
472
|
+
// BOT-1573: name the credential by its prefix rather than always "agent key"
|
|
473
|
+
// — a profile slot can hold an agent, a carrier (legacy), or a CI key. A
|
|
474
|
+
// legacy bare-hex register_agent key (no prefix yet) still reads as an agent.
|
|
475
|
+
const label = agentProfileKeyLabel(agentKey);
|
|
476
|
+
log(`${green("✓")} Authenticated via ${label} ${dim("(Keychain profile store)")}`);
|
|
472
477
|
if (cfg.agent_name) log(` Agent: ${cyan(cfg.agent_name)}`);
|
|
473
478
|
await logServerStatus(call, { "x-agent-api-key": agentKey }, log);
|
|
474
479
|
return;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// BOT-1573 — classify a stored secret by its prefix and name its kind, so
|
|
2
|
+
// `botbuddy status` can say WHAT credential it holds ("agent", "client key",
|
|
3
|
+
// "OAuth owner token") instead of a generic "agent key".
|
|
4
|
+
//
|
|
5
|
+
// This mirrors the UI single source `src/components/credentials/types.ts`
|
|
6
|
+
// (CREDENTIAL_TYPES). The front-end registry is TypeScript in the web bundle and
|
|
7
|
+
// can't be imported into this CLI package, so the prefix→kind table is restated
|
|
8
|
+
// here — kept honest by tests on both sides. Classification is recognition ONLY;
|
|
9
|
+
// it is NEVER used for authorization (auth is the server's hashed lookup).
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Ordered longest-prefix-first so `bb_ci_` can't shadow a longer `bb_*` prefix,
|
|
13
|
+
* and the bare legacy `bb_` is matched last.
|
|
14
|
+
* @type {ReadonlyArray<{ prefix: string, kind: string, label: string }>}
|
|
15
|
+
*/
|
|
16
|
+
export const CREDENTIAL_PREFIXES = [
|
|
17
|
+
{ prefix: "mcp_at_", kind: "oauth", label: "OAuth owner token" },
|
|
18
|
+
{ prefix: "bb_pat_", kind: "pat", label: "personal access token" },
|
|
19
|
+
{ prefix: "bb_cli_", kind: "cli", label: "client key" },
|
|
20
|
+
// BOT-1573/1582 transition: TODAY every live bb_agent_ secret is an older
|
|
21
|
+
// shared service carrier (this PR keeps them authenticating), and the actual
|
|
22
|
+
// per-session agent token is bb_sess_ (BOT-1572). So bb_agent_ classifies as
|
|
23
|
+
// the carrier — matching the UI adapter — NOT as an agent. Once BOT-1582 makes
|
|
24
|
+
// register_agent MINT bb_agent_, this flips to the agent kind.
|
|
25
|
+
{ prefix: "bb_agent_", kind: "svc", label: "carrier (legacy)" },
|
|
26
|
+
{ prefix: "bb_sess_", kind: "agent", label: "agent (session)" },
|
|
27
|
+
{ prefix: "bb_ci_", kind: "ci", label: "CI key" },
|
|
28
|
+
{ prefix: "bb_svc_", kind: "svc", label: "carrier (legacy)" },
|
|
29
|
+
{ prefix: "bb_ios_", kind: "ios", label: "device pairing token" },
|
|
30
|
+
{ prefix: "bb_", kind: "legacy", label: "legacy personal key" },
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Classify a raw secret by its prefix.
|
|
35
|
+
* @param {unknown} secret
|
|
36
|
+
* @returns {{ prefix: string, kind: string, label: string } | null} null when it
|
|
37
|
+
* matches no known BotBuddy prefix.
|
|
38
|
+
*/
|
|
39
|
+
export function classifyCredential(secret) {
|
|
40
|
+
if (typeof secret !== "string" || secret.length === 0) return null;
|
|
41
|
+
for (const entry of CREDENTIAL_PREFIXES) {
|
|
42
|
+
if (secret.startsWith(entry.prefix)) return entry;
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** The operator-facing kind label for a secret, or a safe fallback. */
|
|
48
|
+
export function credentialKindLabel(secret) {
|
|
49
|
+
return classifyCredential(secret)?.label ?? "credential";
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** True for the legacy bare-hex agent api_key that `register_agent` still returns
|
|
53
|
+
* (64 lowercase hex, NO typed prefix). BOT-1574/1582 migrate profiles off it. */
|
|
54
|
+
export function isLegacyBareAgentKey(secret) {
|
|
55
|
+
return typeof secret === "string" && /^[0-9a-f]{64}$/.test(secret);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Kind label for a key resolved from the profile AGENT-key store. A typed
|
|
59
|
+
* prefix classifies normally; a legacy bare-hex api_key (register_agent, no
|
|
60
|
+
* prefix yet) is still an agent credential — not the generic fallback. */
|
|
61
|
+
export function agentProfileKeyLabel(secret) {
|
|
62
|
+
const classified = classifyCredential(secret);
|
|
63
|
+
if (classified) return classified.label;
|
|
64
|
+
if (isLegacyBareAgentKey(secret)) return "agent key (legacy profile)";
|
|
65
|
+
return "credential";
|
|
66
|
+
}
|