@ken-jo/agent-connector 0.4.93 → 0.4.95

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 (73) hide show
  1. package/README.md +162 -51
  2. package/dist/{action-DOWHWEDZ.js → action-Q7GGO4PA.js} +8 -8
  3. package/dist/{chunk-2RIFORQS.js → chunk-3NH2ARIS.js} +2 -2
  4. package/dist/{chunk-KJLFGQQM.js → chunk-5IOTP7LQ.js} +3 -3
  5. package/dist/{chunk-KJLFGQQM.js.map → chunk-5IOTP7LQ.js.map} +1 -1
  6. package/dist/{chunk-P23RVIUY.js → chunk-7F5KHLEP.js} +4 -4
  7. package/dist/{chunk-B5W3RHTI.js → chunk-APZDTY76.js} +2 -2
  8. package/dist/{chunk-SILKSP2Y.js → chunk-D4ELPBB5.js} +2 -2
  9. package/dist/{chunk-OEADFFKO.js → chunk-H33M77DD.js} +19 -19
  10. package/dist/chunk-H33M77DD.js.map +1 -0
  11. package/dist/{chunk-I5TO42QC.js → chunk-I5UXHIDT.js} +3 -3
  12. package/dist/{chunk-ZMAJ2XFD.js → chunk-ISEJWBFF.js} +2 -2
  13. package/dist/{chunk-TTKSYJRY.js → chunk-PAPMUAR5.js} +5 -5
  14. package/dist/{chunk-KSPMSRVU.js → chunk-PW42ZXCB.js} +2 -2
  15. package/dist/{chunk-EHP7WISI.js → chunk-YPAXJ7EW.js} +11 -6
  16. package/dist/chunk-YPAXJ7EW.js.map +1 -0
  17. package/dist/{claude-code-DUZNOAS2.js → claude-code-GRWO6XBZ.js} +4 -4
  18. package/dist/cli/sdk.d.ts +53 -12
  19. package/dist/cli/sdk.js +82 -14
  20. package/dist/cli/sdk.js.map +1 -1
  21. package/dist/cli.js +1 -1
  22. package/dist/{define-connector-LQFJL_at.d.ts → define-connector-DTWb46UB.d.ts} +1 -1
  23. package/dist/{detect-DYQNUMXL.js → detect-6V4LC3MA.js} +4 -4
  24. package/dist/{doctor-H6XXAR63.js → doctor-2YDUVSAU.js} +11 -11
  25. package/dist/{hook-GIQTUDMN.js → hook-OEVRDMXD.js} +8 -8
  26. package/dist/index.d.ts +3 -3
  27. package/dist/index.js +2 -2
  28. package/dist/{install-T27662FW.js → install-5NMCUDG5.js} +8 -8
  29. package/dist/{introspect-D4fEGuhN.d.ts → introspect-dNekqPDY.d.ts} +1 -1
  30. package/dist/{leaderboard-CIMQBOUS.js → leaderboard-XEKS7B3H.js} +2 -2
  31. package/dist/{package-LIPZKHAQ.js → package-G25GVTH2.js} +6 -6
  32. package/dist/runtime/index.d.ts +1 -1
  33. package/dist/runtime/index.js +6 -6
  34. package/dist/sdk/index.d.ts +4 -4
  35. package/dist/sdk/index.js +3 -3
  36. package/dist/sdk/test.d.ts +2 -2
  37. package/dist/sdk/test.js +6 -6
  38. package/dist/{serve-ABTO2NA2.js → serve-XTMIUHKK.js} +8 -8
  39. package/dist/{status-J7SOUH7O.js → status-VJAGO4Z7.js} +6 -6
  40. package/dist/{statusline-QF4G724E.js → statusline-EY2E2UGF.js} +7 -7
  41. package/dist/{telemetry-EICCFEIF.js → telemetry-OLZQBADT.js} +5 -5
  42. package/dist/{types-BhcUEIJJ.d.ts → types-JyhpJHJa.d.ts} +4 -2
  43. package/dist/{uninstall-NJNNZZZY.js → uninstall-AZEUPAND.js} +8 -8
  44. package/dist/{upgrade-TIBUOQNM.js → upgrade-CAUUHSSC.js} +8 -8
  45. package/dist/{usage-VEVBWPLS.js → usage-3KHZ4RYZ.js} +2 -2
  46. package/dist/{usage-event-GRQE7XWT.js → usage-event-TZWOZPRJ.js} +7 -7
  47. package/package.json +2 -2
  48. package/dist/chunk-EHP7WISI.js.map +0 -1
  49. package/dist/chunk-OEADFFKO.js.map +0 -1
  50. /package/dist/{action-DOWHWEDZ.js.map → action-Q7GGO4PA.js.map} +0 -0
  51. /package/dist/{chunk-2RIFORQS.js.map → chunk-3NH2ARIS.js.map} +0 -0
  52. /package/dist/{chunk-P23RVIUY.js.map → chunk-7F5KHLEP.js.map} +0 -0
  53. /package/dist/{chunk-B5W3RHTI.js.map → chunk-APZDTY76.js.map} +0 -0
  54. /package/dist/{chunk-SILKSP2Y.js.map → chunk-D4ELPBB5.js.map} +0 -0
  55. /package/dist/{chunk-I5TO42QC.js.map → chunk-I5UXHIDT.js.map} +0 -0
  56. /package/dist/{chunk-ZMAJ2XFD.js.map → chunk-ISEJWBFF.js.map} +0 -0
  57. /package/dist/{chunk-TTKSYJRY.js.map → chunk-PAPMUAR5.js.map} +0 -0
  58. /package/dist/{chunk-KSPMSRVU.js.map → chunk-PW42ZXCB.js.map} +0 -0
  59. /package/dist/{claude-code-DUZNOAS2.js.map → claude-code-GRWO6XBZ.js.map} +0 -0
  60. /package/dist/{detect-DYQNUMXL.js.map → detect-6V4LC3MA.js.map} +0 -0
  61. /package/dist/{doctor-H6XXAR63.js.map → doctor-2YDUVSAU.js.map} +0 -0
  62. /package/dist/{hook-GIQTUDMN.js.map → hook-OEVRDMXD.js.map} +0 -0
  63. /package/dist/{install-T27662FW.js.map → install-5NMCUDG5.js.map} +0 -0
  64. /package/dist/{leaderboard-CIMQBOUS.js.map → leaderboard-XEKS7B3H.js.map} +0 -0
  65. /package/dist/{package-LIPZKHAQ.js.map → package-G25GVTH2.js.map} +0 -0
  66. /package/dist/{serve-ABTO2NA2.js.map → serve-XTMIUHKK.js.map} +0 -0
  67. /package/dist/{status-J7SOUH7O.js.map → status-VJAGO4Z7.js.map} +0 -0
  68. /package/dist/{statusline-QF4G724E.js.map → statusline-EY2E2UGF.js.map} +0 -0
  69. /package/dist/{telemetry-EICCFEIF.js.map → telemetry-OLZQBADT.js.map} +0 -0
  70. /package/dist/{uninstall-NJNNZZZY.js.map → uninstall-AZEUPAND.js.map} +0 -0
  71. /package/dist/{upgrade-TIBUOQNM.js.map → upgrade-CAUUHSSC.js.map} +0 -0
  72. /package/dist/{usage-VEVBWPLS.js.map → usage-3KHZ4RYZ.js.map} +0 -0
  73. /package/dist/{usage-event-GRQE7XWT.js.map → usage-event-TZWOZPRJ.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/app.ts","../src/cli/banner.ts"],"sourcesContent":["/**\n * cli/app — shared CLI helpers + command dispatch (NO side effects).\n *\n * Command modules import the shared helpers (print, fail, parse-flags,\n * renderInstallResult) from here, and main() dispatches the first positional to a\n * command module.\n * This module never auto-runs — `cli/index.ts` is the thin bin entry that calls\n * `main()`. Keeping the auto-run out of here is what prevents a dispatch recursion\n * (a command module importing a helper must not re-trigger the program) and makes\n * it robust to bundler entry-splitting (the old import.meta.url entry-guard broke\n * once tsup hoisted this code into a shared chunk).\n */\n\nimport { createRequire } from \"node:module\";\nimport { homedir } from \"node:os\";\n\nimport { PALETTES, renderBrandBanner, resolveColorMode, shouldShowBanner } from \"./banner.js\";\nimport type {\n ChangeRecord,\n ConnectorSummary,\n InstallResult,\n InstallScope,\n PlatformId,\n ResolvedConnector,\n} from \"../core/types.js\";\n\n// ─────────────────────────────────────────────────────────────────────────\n// Shared helpers (imported by the command modules)\n// ─────────────────────────────────────────────────────────────────────────\n\n/** Print a line to stdout (machine-readable payloads must stay on stdout). */\nexport function print(line: string): void {\n process.stdout.write(`${line}\\n`);\n}\n\n/**\n * The brand active for THIS invocation. main() sets it from\n * {@link MainOptions.programName} before dispatch, so error messages printed by\n * command modules via {@link fail} read as the embedding tool (e.g. `acme-db:`)\n * instead of always `agent-connector:`.\n */\nlet activeProgramName = \"agent-connector\";\n\n/** Print an error to stderr (branded) and return a non-zero exit code (default 2). */\nexport function fail(message: string, code = 2): number {\n process.stderr.write(`${activeProgramName}: ${message}\\n`);\n return code;\n}\n\n/**\n * The brand active for THIS invocation (what the banner renders in ASCII art).\n * main() sets it from {@link MainOptions.programName} before dispatch; reading it\n * here keeps the banner branded for an embedding SDK CLI without each command\n * module needing the program name threaded through.\n */\nexport function getActiveProgramName(): string {\n return activeProgramName;\n}\n\n/**\n * Print the branded ASCII banner once, atop install / uninstall / upgrade /\n * doctor — but ONLY for an interactive TTY (suppressed when piped/redirected,\n * under --json, or under --quiet) so scripts and pipelines see byte-identical\n * command output. The pure render lives in cli/banner; this thin wrapper reads\n * the real stdout/env and feeds it in.\n */\nexport function maybePrintBanner(flags: { json?: boolean; quiet?: boolean }): void {\n const isTTY = process.stdout.isTTY === true;\n const noColor = process.env.NO_COLOR != null && process.env.NO_COLOR !== \"\";\n if (!shouldShowBanner({ isTTY, noColor, json: flags.json === true, quiet: flags.quiet === true })) {\n return;\n }\n const color = resolveColorMode({\n noColor,\n colorterm: process.env.COLORTERM,\n term: process.env.TERM,\n });\n // Coerce an unknown/zero width to a conservative 80 so an unknown-width TTY\n // shows the safe one-line title rather than the 129-col block art.\n const c = process.stdout.columns;\n const columns = typeof c === \"number\" && c > 0 ? c : 80;\n // Rotate the gradient per run so each real invocation reads differently. The\n // random pick lives HERE (the impure wrapper) so the pure renderer stays\n // deterministic for tests/direct callers.\n const palette = PALETTES[Math.floor(Math.random() * PALETTES.length)]!;\n print(renderBrandBanner(activeProgramName, { color, columns, palette }));\n print(\"\");\n}\n\n/**\n * Resolve agent-connector's own package version at runtime. Works from both the\n * bundled dist layout (dist/*.js → ../package.json) and the src layout under\n * tsx/vitest (src/cli/ → ../../package.json); the name check guards against\n * accidentally reading some other package.json on the walk.\n */\nexport function resolveOwnVersion(): string {\n const req = createRequire(import.meta.url);\n for (const rel of [\"../package.json\", \"../../package.json\", \"../../../package.json\"]) {\n try {\n const pkg = req(rel) as { name?: string; version?: string };\n if (pkg.name === \"@ken-jo/agent-connector\" && typeof pkg.version === \"string\") {\n return pkg.version;\n }\n } catch {\n /* keep walking */\n }\n }\n return \"0.0.0\";\n}\n\n/** Parse a --scope value the CLI accepts (user|project) into an InstallScope. */\nexport function parseScope(value: string | undefined): InstallScope | null {\n if (value === \"user\" || value === \"project\") return value;\n return null;\n}\n\n/**\n * Parse a comma-separated --targets value into PlatformId[]. Returns undefined\n * when the flag is absent/empty so callers can fall back to connector/detection.\n */\nexport function parseTargets(value: string | undefined): PlatformId[] | undefined {\n if (value == null || value.trim() === \"\") return undefined;\n const ids = value\n .split(\",\")\n .map((s) => s.trim())\n .filter((s) => s !== \"\") as PlatformId[];\n return ids.length > 0 ? ids : undefined;\n}\n\n/**\n * Build the render-only {@link ConnectorSummary} from a resolved connector. The\n * command modules call this on the {@link ResolvedConnector} they already loaded\n * and attach the result to {@link InstallResult.connector}, so the friendly\n * renderer can print a header describing WHAT was deployed without importing the\n * heavyweight connector type or its live handlers.\n */\nexport function buildConnectorSummary(connector: ResolvedConnector): ConnectorSummary {\n let server: ConnectorSummary[\"server\"];\n if (connector.server) {\n const s = connector.server;\n // stdio → \"node server.mjs\"; remote → the URL (best-effort one-liner).\n // HOME-relativize each part so a bundled absolute server path reads short.\n const cmd =\n s.transport === \"stdio\"\n ? [s.command, ...(s.args ?? [])]\n .filter((p): p is string => p != null && p !== \"\")\n .map((p) => tildify(p))\n .join(\" \")\n : (s.url ?? \"\");\n server = { transport: s.transport, command: cmd };\n }\n return {\n id: connector.id,\n version: connector.version,\n displayName: connector.displayName,\n server,\n hookEvents: [...connector.hookEvents],\n telemetryEnabled: connector.telemetry.enabled,\n commands: connector.commands.length,\n skills: connector.skills.length,\n subagents: connector.subagents.length,\n memory: connector.memory.length,\n hasStatusline: connector.statusline != null,\n actions: connector.actions.length,\n };\n}\n\n/**\n * Rewrite an absolute path under the user's home dir to a leading `~/…` so the\n * per-host paths read short. Leaves non-home and relative paths untouched.\n */\nfunction tildify(path: string): string {\n // Normalize both to forward slashes so the home-prefix check is separator-\n // robust (Windows mixes `\\` and `/`) and the displayed path reads `~/…`\n // consistently on every platform (Windows terminals accept `/` fine).\n const home = homedir().replace(/\\\\/g, \"/\");\n const np = path.replace(/\\\\/g, \"/\");\n if (home && (np === home || np.startsWith(home + \"/\"))) {\n return \"~\" + np.slice(home.length);\n }\n return np;\n}\n\n/** Truncate a long single-line command for the header (keeps it scannable). */\nfunction truncateCommand(cmd: string, max = 64): string {\n if (cmd.length <= max) return cmd;\n return cmd.slice(0, max - 1) + \"…\";\n}\n\n/**\n * The surface a ChangeRecord touched, derived from its detail (primary signal)\n * then its path (fallback for content files whose detail is a bare basename).\n */\ntype Surface = \"mcp\" | \"hooks\" | \"commands\" | \"skills\" | \"subagents\" | \"memory\" | \"statusline\" | \"actions\" | \"backup\" | \"other\";\n\nfunction classifySurface(c: ChangeRecord): Surface {\n const detail = c.detail.toLowerCase();\n // A safety backup the installer wrote before a destructive change.\n if (detail.startsWith(\"backed up\") || detail.includes(\"backup\")) return \"backup\";\n // MCP server entry: mcpServers.<id> / mcp_servers.<id> / mcp.servers.<id>.\n if (/^mcp[._]?servers?\\./.test(detail) || detail.startsWith(\"mcp.\")) return \"mcp\";\n // Normalized + native hook entries: hooks.<Event> (case varies per host).\n if (detail.startsWith(\"hooks.\") || detail.startsWith(\"hook \")) return \"hooks\";\n if (detail.includes(\"nativehooks\")) return \"hooks\";\n if (detail.startsWith(\"memory\")) return \"memory\";\n if (detail.startsWith(\"statusline\")) return \"statusline\";\n if (detail.startsWith(\"actions\") || detail.startsWith(\"action \")) return \"actions\";\n if (detail.includes(\"configpatch\")) return \"other\";\n // Path-based fallback for content-file surfaces (detail is a bare basename).\n const p = (c.path ?? \"\").replace(/\\\\/g, \"/\").toLowerCase();\n if (/\\/commands?\\//.test(p)) return \"commands\";\n if (/\\/skills?\\//.test(p)) return \"skills\";\n if (/\\/(subagents?|agents?)\\//.test(p)) return \"subagents\";\n // Detail mentions a surface noun (skip/warn lines like \"no skills\").\n if (/\\bcommands?\\b/.test(detail)) return \"commands\";\n if (/\\bskills?\\b/.test(detail)) return \"skills\";\n if (/\\bsubagents?\\b/.test(detail)) return \"subagents\";\n return \"other\";\n}\n\nconst SURFACE_LABEL_SINGULAR: Record<Surface, string> = {\n mcp: \"MCP server\",\n hooks: \"hook\",\n commands: \"command\",\n skills: \"skill\",\n subagents: \"subagent\",\n memory: \"memory block\",\n statusline: \"status line\",\n actions: \"action\",\n backup: \"backup\",\n other: \"change\",\n};\n\n/** Pluralize a surface count, e.g. (2,\"hooks\") → \"2 hooks\". */\nfunction countLabel(n: number, surface: Surface): string {\n const base = SURFACE_LABEL_SINGULAR[surface];\n if (surface === \"mcp\") return \"MCP server\"; // singular by construction\n return n === 1 ? `1 ${base}` : `${n} ${base}s`;\n}\n\n/** Verb-appropriate glyph for a host's NET status. */\nfunction hostGlyph(status: \"ok\" | \"skip\" | \"warn\"): string {\n return status === \"warn\" ? \"!\" : status === \"skip\" ? \"=\" : \"✓\";\n}\n\n/**\n * One host's collapsed view: its net status, a surface summary line, the\n * deduped HOME-relativized paths it touched, and any inline warnings.\n */\ninterface HostGroup {\n platform: PlatformId;\n status: \"ok\" | \"skip\" | \"warn\";\n summary: string;\n paths: string[];\n warnings: string[];\n}\n\n/**\n * Collapse the per-(host,surface) ChangeRecords into ONE entry per host:\n * - status: warn if any record warned; ok if any created/updated/removed;\n * else skip (everything was a no-op).\n * - summary: the active (non-skip) surfaces, joined (\"MCP server + 2 hooks\").\n * When every record skipped, the reason is surfaced instead.\n */\nfunction groupByHost(changes: ChangeRecord[], verb: Verb): HostGroup[] {\n const order: PlatformId[] = [];\n const byHost = new Map<PlatformId, ChangeRecord[]>();\n for (const c of changes) {\n if (!byHost.has(c.platform)) {\n byHost.set(c.platform, []);\n order.push(c.platform);\n }\n byHost.get(c.platform)!.push(c);\n }\n\n const groups: HostGroup[] = [];\n for (const platform of order) {\n const recs = byHost.get(platform)!;\n // A safety backup the installer wrote is INCIDENTAL, not an installed\n // surface: it must not flip an otherwise-no-op host to \"changed\" (an\n // idempotent re-install that only re-backs-up should still read \"already\n // current\"). It is shown only ALONGSIDE a real surface change.\n const written = recs.filter((c) => c.action !== \"skip\" && c.action !== \"warn\");\n const realChanges = written.filter((c) => classifySurface(c) !== \"backup\");\n const warned = recs.filter((c) => c.action === \"warn\");\n const status: HostGroup[\"status\"] =\n warned.length > 0 ? \"warn\" : realChanges.length > 0 ? \"ok\" : \"skip\";\n\n // Surface summary from the written records (created/updated/removed),\n // preserving a stable surface order and collapsing per-surface counts. The\n // incidental `backup` surface is included ONLY when a real surface changed.\n const SURFACE_ORDER: Surface[] = [\n \"mcp\",\n \"hooks\",\n \"commands\",\n \"skills\",\n \"subagents\",\n \"memory\",\n \"statusline\",\n \"actions\",\n \"backup\",\n \"other\",\n ];\n const counts = new Map<Surface, number>();\n const summarySource = realChanges.length > 0 ? written : realChanges;\n for (const c of summarySource) {\n const s = classifySurface(c);\n counts.set(s, (counts.get(s) ?? 0) + 1);\n }\n const parts = SURFACE_ORDER.filter((s) => counts.has(s)).map((s) =>\n countLabel(counts.get(s)!, s),\n );\n\n let summary: string;\n if (parts.length > 0) {\n summary = parts.join(\" + \");\n } else if (status === \"warn\") {\n // No real surface change but a warning — the warning line carries detail.\n summary = \"\";\n } else {\n // Nothing real changed: surface a skip reason (or note the incidental\n // backup) for context.\n const reason =\n recs.find((c) => c.action === \"skip\")?.detail ??\n (written.length > 0 ? \"already current (re-backed-up only)\" : \"no changes\");\n summary = verb === \"uninstall\" ? `nothing to remove (${reason})` : `unchanged (${reason})`;\n }\n\n const paths = [\n ...new Set(\n recs\n .filter((c) => c.path != null && c.path !== \"\")\n .map((c) => tildify(c.path!)),\n ),\n ];\n const warnings = warned.map((c) => c.detail);\n\n groups.push({ platform, status, summary, paths, warnings });\n }\n return groups;\n}\n\ntype Verb = \"install\" | \"upgrade\" | \"uninstall\";\n\n/**\n * Render an InstallResult as a friendly, grouped report (the DEFAULT output):\n * 1. a connector header (id/version/displayName + server/hooks/telemetry +\n * one line per shipped content surface), when the summary is threaded in;\n * 2. one line per host (net glyph + surface summary + deduped ~/… paths),\n * with any host warnings inline beneath it;\n * 3. a friendly closing line + restart hint + doctor/uninstall next steps.\n *\n * Used by install / upgrade / uninstall. The exit-non-zero-on-warn convention\n * is enforced by the callers (this function only renders).\n */\nexport function renderInstallResult(result: InstallResult, verb: Verb): string {\n const lines: string[] = [];\n const summary = result.connector;\n\n // ── 1. Connector header ───────────────────────────────────────────────────\n if (summary) {\n const head = [`${summary.id} v${summary.version}`];\n if (summary.displayName && summary.displayName !== summary.id) {\n head.push(summary.displayName);\n }\n lines.push(head.join(\" · \"));\n\n if (summary.server) {\n lines.push(\n ` server ${summary.server.transport} · ${truncateCommand(summary.server.command)}`,\n );\n } else {\n lines.push(\" server (hooks-only)\");\n }\n if (summary.hookEvents.length > 0) {\n lines.push(` hooks ${summary.hookEvents.join(\", \")}`);\n }\n lines.push(` telemetry ${summary.telemetryEnabled ? \"on\" : \"off\"}`);\n if (summary.commands > 0)\n lines.push(` commands ${summary.commands}`);\n if (summary.skills > 0) lines.push(` skills ${summary.skills}`);\n if (summary.subagents > 0)\n lines.push(` subagents ${summary.subagents}`);\n if (summary.memory > 0) lines.push(` memory ${summary.memory}`);\n if (summary.hasStatusline) lines.push(` statusline 1`);\n if (summary.actions > 0) lines.push(` actions ${summary.actions}`);\n lines.push(\"\");\n } else {\n // No summary threaded (back-compat): keep a minimal verb header.\n const mode = result.dryRun ? \" (dry-run — nothing written)\" : \"\";\n lines.push(`${verb} \"${result.connectorId}\"${mode}`);\n }\n\n // ── 2. Per-host grouping ──────────────────────────────────────────────────\n const groups = groupByHost(result.changes, verb);\n if (groups.length === 0) {\n lines.push(\"(no changes)\");\n } else {\n const verbed = verb === \"uninstall\" ? \"removed from\" : verb === \"upgrade\" ? \"synced to\" : \"detected\";\n lines.push(`→ ${groups.length} agent ${groups.length === 1 ? \"CLI\" : \"CLIs\"} ${verbed}:`);\n // Width-align the platform column for a scannable table; the summary column\n // gets a fixed min width but always keeps a 2-space gap before the paths\n // even when an unusually long summary overflows it.\n const pad = Math.max(...groups.map((g) => g.platform.length));\n for (const g of groups) {\n const glyph = hostGlyph(g.status);\n const name = g.platform.padEnd(pad);\n const pathsCol = g.paths.join(\", \");\n const gap = pathsCol === \"\" ? \"\" : \" \";\n const summaryCol = pathsCol === \"\" ? g.summary : g.summary.padEnd(26) + gap;\n lines.push(` ${glyph} ${name} ${summaryCol}${pathsCol}`.trimEnd());\n for (const w of g.warnings) lines.push(` ! ${w}`);\n }\n }\n\n // ── 3. Closing summary + next steps ───────────────────────────────────────\n // The headline file tally counts only REAL surface writes — an incidental\n // safety backup must not masquerade as an installed file, so a re-install\n // whose only write was a backup honestly reports 0 files / \"already current\".\n const tally = result.changes.reduce(\n (acc, c) => {\n const isWrite = c.action === \"create\" || c.action === \"update\" || c.action === \"remove\";\n if (isWrite && classifySurface(c) !== \"backup\") acc.files += 1;\n if (c.action === \"warn\") acc.warns += 1;\n return acc;\n },\n { files: 0, warns: 0 },\n );\n const cliCount = groups.length;\n const cliWord = cliCount === 1 ? \"CLI\" : \"CLIs\";\n const fileWord = tally.files === 1 ? \"file\" : \"files\";\n\n lines.push(\"\");\n if (verb === \"uninstall\") {\n if (result.dryRun) {\n lines.push(`✓ Would remove ${summary?.id ?? result.connectorId} from ${cliCount} ${cliWord} · ${tally.files} ${fileWord} (dry-run — nothing written).`);\n } else if (tally.files === 0 && tally.warns === 0) {\n lines.push(`✓ Nothing to remove — ${summary?.id ?? result.connectorId} was not installed (zero residue).`);\n } else {\n lines.push(`✓ Removed ${summary?.id ?? result.connectorId} from ${cliCount} ${cliWord} · ${tally.files} ${fileWord} cleaned${tally.warns === 0 ? \" (zero residue)\" : \"\"}.`);\n }\n } else {\n const what = verb === \"upgrade\" ? \"Synced\" : \"Installed\";\n const wouldWhat = verb === \"upgrade\" ? \"sync\" : \"install\";\n if (result.dryRun) {\n lines.push(`✓ Would ${wouldWhat} ${summary?.id ?? result.connectorId} to ${cliCount} ${cliWord} · ${tally.files} ${fileWord} (dry-run — nothing written).`);\n } else if (tally.files === 0) {\n lines.push(`✓ ${summary?.id ?? result.connectorId}: already current on ${cliCount} ${cliWord} — nothing to write.`);\n } else {\n lines.push(`✓ ${what} ${summary?.id ?? result.connectorId} to ${cliCount} ${cliWord} · ${tally.files} ${fileWord}. Restart each CLI to load it.`);\n }\n }\n\n // Warnings block (kept explicit — callers exit non-zero on any warn). A\n // remote-transport connector pushes the SAME string to both a warn\n // ChangeRecord (already shown inline on its host line) and result.warnings, so\n // skip any bottom-block entry already surfaced inline to show each warning ONCE.\n const inlineWarnings = new Set(groups.flatMap((g) => g.warnings));\n const blockWarnings = result.warnings.filter((w) => !inlineWarnings.has(w));\n if (blockWarnings.length > 0) {\n lines.push(\"\");\n lines.push(\"warnings:\");\n for (const w of blockWarnings) lines.push(` ! ${w}`);\n }\n\n // Next-step hints (the verbs read as the active brand).\n if (verb === \"uninstall\") {\n lines.push(` Verify it's gone: ${activeProgramName} doctor`);\n } else {\n lines.push(\n ` Verify: ${activeProgramName} doctor · Remove: ${activeProgramName} uninstall`,\n );\n }\n\n return lines.join(\"\\n\");\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Command dispatch\n// ─────────────────────────────────────────────────────────────────────────\n\n/** A command module: takes the post-command argv slice, returns an exit code. */\ntype CommandModule = { run: (argv: string[]) => Promise<number> | number };\n\n/** Lazy command loaders — keyed by the first positional. Imported on demand. */\nconst COMMANDS: Record<string, () => Promise<CommandModule>> = {\n detect: () => import(\"./commands/detect.js\"),\n install: () => import(\"./commands/install.js\"),\n uninstall: () => import(\"./commands/uninstall.js\"),\n // `upgrade` is the single \"bring everything current\" verb (re-render host\n // config + refresh the home pointer + managed channel guidance). `sync` and\n // `update` are kept as back-compat aliases that route to the same module so\n // existing scripts/docs keep working without a second concept to learn.\n upgrade: () => import(\"./commands/upgrade.js\"),\n sync: () => import(\"./commands/upgrade.js\"),\n update: () => import(\"./commands/upgrade.js\"),\n package: () => import(\"./commands/package.js\"),\n doctor: () => import(\"./commands/doctor.js\"),\n status: () => import(\"./commands/status.js\"),\n telemetry: () => import(\"./commands/telemetry.js\"),\n usage: () => import(\"./commands/usage.js\"),\n leaderboard: () => import(\"./commands/leaderboard.js\"),\n hook: () => import(\"./commands/hook.js\"),\n // Internal (omitted from USAGE): the statusline (HUD) entrypoint a host's\n // status line config points at. Fail-safe: always exits 0 with at most a\n // rendered line. See cli/commands/statusline.ts.\n statusline: () => import(\"./commands/statusline.js\"),\n // Internal (omitted from USAGE): the user-invokable action entrypoint a future\n // host affordance points at. USER-TRIGGERED: surfaces errors (exit 1 + stderr),\n // unlike the fail-open hook / fail-safe statusline. See cli/commands/action.ts.\n action: () => import(\"./commands/action.js\"),\n serve: () => import(\"./commands/serve.js\"),\n // Hidden (omitted from USAGE): the opt-in host-native turn-usage entrypoint an\n // AfterModel / PostInvocation hook points at. Always exits 0; records a\n // distinct `model_turn` row. See cli/commands/usage-event.ts.\n \"usage-event\": () => import(\"./commands/usage-event.js\"),\n};\n\n/** Default program name; an embedding SDK CLI overrides it via {@link MainOptions}. */\nexport const DEFAULT_PROGRAM_NAME = \"agent-connector\";\n\n/**\n * One-line usage signature per command — the single central copy behind\n * `<command> --help` and the friendly bad-flag error. Command modules use\n * node:util parseArgs (strict), which THROWS on an unknown flag; without the\n * dispatcher-level handling in {@link main}, `agent-connector install --help`\n * would die with a raw ERR_PARSE_ARGS stack trace — the very invocation the\n * root help tells users to run.\n */\nconst COMMAND_USAGE: Record<string, string> = {\n detect: \"detect [--json] [--project <dir>]\",\n install:\n \"install [<source>] [--method direct|marketplace] [--connector <source>] [--scope user|project] [--targets a,b] [--project <dir>] [--dry-run] [--force] [--quiet]\\n\" +\n \" <source> a local path OR a remote GitHub connector: owner/repo[/subpath][#ref], a github.com URL (incl. /tree/<ref>/<sub>), git@github.com:owner/repo, or github:owner/repo. Remote sources are fetched to ~/.agent-connector/sources/ and must be an agent-connector package (have an agent-connector.config.{mjs,js,json}).\",\n uninstall:\n \"uninstall [--method auto|direct|marketplace] [--connector <path>] [--connector-id <id>] [--scope user|project] [--targets a,b] [--project <dir>] [--dry-run] [--purge] [--quiet]\",\n upgrade:\n \"upgrade [--method direct|marketplace] [--channel stable|latest] [--connector <path>] [--scope user|project] [--targets a,b] [--project <dir>] [--dry-run] [--quiet]\",\n sync: \"sync — alias of upgrade (see `upgrade --help`)\",\n update: \"update — alias of upgrade (see `upgrade --help`)\",\n package:\n \"package [--connector <path>] [--format <fmt>|all] [--out <dir>] [--project <dir>] [--dry-run]\",\n doctor:\n \"doctor [--targets a,b] [--connector <path>] [--scope user|project] [--project <dir>] [--probe] [--explain] [--json] [--heal] [--dry-run] [--quiet]\\n\" +\n \" --explain per-(host,event) hook honor matrix (honored/degraded/dropped). Exit non-zero ONLY when an explicitly-targeted host DEGRADES a declared event (fires it but silently won't honor the reply); dropped/mcp-only hosts and fleet-wide (targets:auto) gaps are informational (exit 0).\",\n status: \"status [--connector <path>] [--scope user|project] [--project <dir>] [--json]\",\n telemetry:\n \"telemetry report|export|leaderboard [--by <dim>] [--since <dur>] [--connector <id>] [--scope <slice>] [--format csv|json] [--out <file>] [--json]\",\n usage:\n \"usage report|export|leaderboard [--by <dim>] [--since <dur>] [--platform <id>] [--format csv|json] [--out <file>] [--json]\",\n leaderboard: \"leaderboard [--since <dur>] [--connector <id>] [--scope <slice>] [--json]\",\n hook: \"hook <platform> <event> --connector <id> (internal — host hook configs point here)\",\n statusline:\n \"statusline <platform> --connector <id> (internal — host status line configs point here)\",\n action:\n \"action <platform> <actionId> --connector <id> (internal — host action affordances point here)\",\n serve:\n \"serve --connector <id> [--scope user|project] [--host <platformId>] -- <command> [args...] (internal — host MCP entries point here)\",\n};\n\n/**\n * Build the top-level usage string for a given program name. The brand replaces\n * \"agent-connector\" in the title, the `usage:` line, and the per-command help\n * footer so an embedded CLI (e.g. `acme-db`) reads as its own tool.\n */\nfunction buildUsage(programName: string): string {\n return `${programName} — write your MCP server + hooks once, install everywhere.\n\nusage: ${programName} <command> [flags]\n\ncommands:\n detect List the AI-agent platforms installed on this machine.\n install Deploy a connector across its target platforms (--method direct writes host config; --method marketplace drives the host's plugin install).\n uninstall Remove a connector's registrations (--method auto reverses whichever method is actually installed).\n upgrade Bring everything current: re-render host config + heal the home pointer + managed update guidance (alias: update, sync).\n package Emit a marketplace/extension bundle (10 host formats, or the standard artifacts mcp-server-json | mcpb).\n doctor Health-check every detected platform; non-zero exit on any failure.\n status Light install-state summary: which connectors are present on which hosts (always exits 0).\n telemetry Inspect local per-tool token telemetry (report | export | leaderboard).\n usage Inspect host-native token usage from agent CLI logs (report | export | leaderboard).\n leaderboard Three leaderboards: 🔌 MCP/plugin (mcp-self) + 🖥️ host/user (host-scan-logs) + 🛰️ host-native turns (host-native-live) — never summed.\n hook Universal json-stdio hook entrypoint (hosts call this).\n serve Telemetry-wrapping MCP stdio proxy (wraps a real server command).\n\nRun \\`${programName} <command> --help\\` for command-specific flags.`;\n}\n\n/** Options accepted by {@link main}. */\nexport interface MainOptions {\n /**\n * The brand shown in usage/help text. Defaults to {@link DEFAULT_PROGRAM_NAME}.\n * An embedding SDK CLI (see cli/sdk.ts) passes its own bin name so every\n * subcommand's help reads as the developer's tool.\n */\n programName?: string;\n /**\n * Version shown by --version. Defaults to agent-connector's own package version.\n * Embedded branded CLIs pass their package.json version.\n */\n programVersion?: string;\n}\n\nexport async function main(argv: string[], opts: MainOptions = {}): Promise<number> {\n const programName = opts.programName ?? DEFAULT_PROGRAM_NAME;\n activeProgramName = programName; // brand every fail() in this invocation\n const usage = buildUsage(programName);\n const command = argv[0];\n\n if (command == null || command === \"--help\" || command === \"-h\" || command === \"help\") {\n print(usage);\n return command == null ? 1 : 0;\n }\n if (command === \"--version\" || command === \"-v\") {\n print(`${programName} ${opts.programVersion ?? resolveOwnVersion()}`);\n return 0;\n }\n\n const loader = COMMANDS[command];\n if (!loader) {\n process.stderr.write(`${programName}: unknown command \"${command}\"\\n\\n`);\n process.stderr.write(`${usage}\\n`);\n return 2;\n }\n\n // Per-command help: no command module defines a --help flag (strict parseArgs\n // would throw on it), so answer it centrally from COMMAND_USAGE.\n const rest = argv.slice(1);\n if (rest.includes(\"--help\") || rest.includes(\"-h\")) {\n const sig = COMMAND_USAGE[command];\n if (sig) {\n print(`usage: ${programName} ${sig}`);\n return 0;\n }\n }\n\n const mod = await loader();\n try {\n return await mod.run(rest);\n } catch (err) {\n // Friendly bad-flag errors: strict parseArgs throws ERR_PARSE_ARGS_* for an\n // unknown/malformed option — print the message + the usage line instead of\n // letting a raw stack trace reach the user. Everything else still rethrows\n // (the bin entry reports those as fatal).\n const code = (err as { code?: string }).code;\n if (typeof code === \"string\" && code.startsWith(\"ERR_PARSE_ARGS\")) {\n const message = err instanceof Error ? err.message : String(err);\n const sig = COMMAND_USAGE[command];\n if (sig) process.stderr.write(`usage: ${programName} ${sig}\\n`);\n return fail(message);\n }\n throw err;\n }\n}\n","/**\n * cli/banner — the branded ASCII-art header shown once atop install / uninstall\n * / upgrade / doctor.\n *\n * Two PURE functions drive everything (no process.* reads here — the command\n * wiring injects the real env so tests can call these directly without a TTY):\n *\n * renderBrandBanner(name, { color, columns, palette }) → the banner string\n * shouldShowBanner({ isTTY, noColor, json, quiet }) → whether to show it\n *\n * RESPONSIVE (one line, NEVER stacked), two forms:\n * • WIDE — a 6-row \"ANSI Shadow\" block font (solid `█` + `╗╔╝╚║═` shadow,\n * ~8 cols/char, hand-transcribed + fixed-width so it tiles cleanly) when its\n * render fits the terminal width.\n * • NARROW — a single-line gradient TITLE `◆ AGENT-CONNECTOR` (the brand\n * uppercased, each char colored along the palette + bold). ~18 cols, so it\n * fits any real terminal; it is the universal narrow form.\n * The WIDE font covers the connector-id charset [A-Za-z0-9 ._-].\n *\n * COLOR: a palette gradient (three RGB stops, a {@link Palette}) — swept per\n * column across the block art, or per character across the title. The render is\n * PURE and palette-parameterized — the caller picks the palette (the impure\n * app.ts wrapper rotates {@link PALETTES} per run). truecolor→256→16→none tiers\n * all honor the palette; NO_COLOR = zero ANSI.\n */\n\n/** Color capability the host terminal advertises, highest → lowest. */\nexport type ColorMode = \"truecolor\" | \"ansi256\" | \"ansi16\" | \"none\";\n\n/** A 24-bit RGB triple. */\nexport type RGB = readonly [number, number, number];\n\n/** A 3-stop gradient: the sweep lerps stop0 → stop1 → stop2 across the columns. */\nexport type Palette = readonly [RGB, RGB, RGB];\n\n/**\n * The 10 rotation palettes. The impure {@link maybePrintBanner} wrapper picks one\n * at random per run so each real invocation shows a different color; the pure\n * renderer defaults to PALETTES[0] so direct callers + tests stay deterministic.\n */\nexport const PALETTES: readonly Palette[] = [\n [[255, 210, 0], [255, 110, 10], [220, 30, 25]], // Sunset\n [[255, 225, 90], [255, 120, 0], [200, 20, 20]], // Lava\n [[230, 30, 30], [255, 120, 0], [255, 220, 0]], // Fire\n [[255, 225, 120], [255, 170, 40], [225, 110, 20]], // Amber gold\n [[255, 205, 150], [255, 150, 130], [255, 120, 175]], // Peach pastel\n [[255, 80, 170], [200, 40, 200], [100, 60, 210]], // Berry\n [[0, 220, 180], [0, 160, 230], [60, 90, 230]], // Ocean\n [[80, 230, 140], [0, 200, 210], [150, 90, 235]], // Aurora\n [[170, 230, 90], [60, 200, 120], [20, 150, 140]], // Forest\n [[0, 200, 200], [40, 80, 230], [200, 40, 200]], // Synthwave\n] as const;\n\n/** Inputs to {@link renderBrandBanner} — all injected, never read from process. */\nexport interface BannerOptions {\n /** Color capability to render at. \"none\" emits zero ANSI codes. */\n color: ColorMode;\n /** Terminal width in columns; selects the form (wide block art → one-line title). */\n columns: number;\n /** The 3-stop gradient. Defaults to {@link PALETTES}[0] (Sunset) when omitted. */\n palette?: Palette;\n}\n\n/** Inputs to {@link shouldShowBanner} — the real env, injected by the caller. */\nexport interface BannerGate {\n /** process.stdout.isTTY (banner is suppressed entirely when not a TTY). */\n isTTY: boolean;\n /** NO_COLOR is set (the banner still shows, but with zero color codes). */\n noColor: boolean;\n /** A machine-readable --json was requested (suppress entirely). */\n json: boolean;\n /** An explicit --quiet was passed (suppress entirely). */\n quiet: boolean;\n}\n\n/**\n * Whether to print the banner at all. The banner is decorative, so it shows ONLY\n * for an interactive TTY and never when output is being consumed by a script or\n * pipeline: not when piped/redirected (`!isTTY`), not under `--json`, and not\n * under `--quiet`. `NO_COLOR` does NOT suppress it — the banner renders without\n * color in that case (handled by {@link resolveColorMode}).\n */\nexport function shouldShowBanner(gate: BannerGate): boolean {\n return gate.isTTY && !gate.json && !gate.quiet;\n}\n\n/**\n * Resolve the color tier from the (injected) terminal env. 24-bit when the\n * terminal advertises it (COLORTERM=truecolor|24bit), 256-color when TERM names\n * a 256 palette, else 16-color — and PLAIN (no color) under NO_COLOR or a dumb /\n * absent TERM.\n */\nexport function resolveColorMode(env: {\n noColor: boolean;\n colorterm?: string | undefined;\n term?: string | undefined;\n}): ColorMode {\n if (env.noColor) return \"none\";\n const term = (env.term ?? \"\").toLowerCase();\n if (term === \"\" || term === \"dumb\") return \"none\";\n const colorterm = (env.colorterm ?? \"\").toLowerCase();\n if (colorterm === \"truecolor\" || colorterm === \"24bit\") return \"truecolor\";\n if (term.includes(\"256\")) return \"ansi256\";\n return \"ansi16\";\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// WIDE font — \"ANSI Shadow\" (6 rows). Hand-transcribed bold figlet glyphs —\n// solid `█` with a `╗╔╝╚║═` 3D shadow — fixed-width per glyph so they TILE\n// cleanly when concatenated (~8 cols/char → \"agent-connector\" ≈ 126 cols on\n// one line). Used only when the terminal is wide enough.\n// ─────────────────────────────────────────────────────────────────────────\n\nconst WIDE_FONT: Record<string, readonly string[]> = {\n A: [\" █████╗ \", \"██╔══██╗\", \"███████║\", \"██╔══██║\", \"██║ ██║\", \"╚═╝ ╚═╝\"],\n B: [\"██████╗ \", \"██╔══██╗\", \"██████╔╝\", \"██╔══██╗\", \"██████╔╝\", \"╚═════╝ \"],\n C: [\" ██████╗\", \"██╔════╝\", \"██║ \", \"██║ \", \"╚██████╗\", \" ╚═════╝\"],\n D: [\"██████╗ \", \"██╔══██╗\", \"██║ ██║\", \"██║ ██║\", \"██████╔╝\", \"╚═════╝ \"],\n E: [\"███████╗\", \"██╔════╝\", \"█████╗ \", \"██╔══╝ \", \"███████╗\", \"╚══════╝\"],\n F: [\"███████╗\", \"██╔════╝\", \"█████╗ \", \"██╔══╝ \", \"██║ \", \"╚═╝ \"],\n G: [\" ██████╗ \", \"██╔════╝ \", \"██║ ███╗\", \"██║ ██║\", \"╚██████╔╝\", \" ╚═════╝ \"],\n H: [\"██╗ ██╗\", \"██║ ██║\", \"███████║\", \"██╔══██║\", \"██║ ██║\", \"╚═╝ ╚═╝\"],\n I: [\"██╗\", \"██║\", \"██║\", \"██║\", \"██║\", \"╚═╝\"],\n J: [\" ██╗\", \" ██║\", \" ██║\", \"██ ██║\", \"╚█████╔╝\", \" ╚════╝ \"],\n K: [\"██╗ ██╗\", \"██║ ██╔╝\", \"█████╔╝ \", \"██╔═██╗ \", \"██║ ██╗\", \"╚═╝ ╚═╝\"],\n L: [\"██╗ \", \"██║ \", \"██║ \", \"██║ \", \"███████╗\", \"╚══════╝\"],\n M: [\"███╗ ███╗\", \"████╗ ████║\", \"██╔████╔██║\", \"██║╚██╔╝██║\", \"██║ ╚═╝ ██║\", \"╚═╝ ╚═╝\"],\n N: [\"███╗ ██╗\", \"████╗ ██║\", \"██╔██╗ ██║\", \"██║╚██╗██║\", \"██║ ╚████║\", \"╚═╝ ╚═══╝\"],\n O: [\" ██████╗ \", \"██╔═══██╗\", \"██║ ██║\", \"██║ ██║\", \"╚██████╔╝\", \" ╚═════╝ \"],\n P: [\"██████╗ \", \"██╔══██╗\", \"██████╔╝\", \"██╔═══╝ \", \"██║ \", \"╚═╝ \"],\n Q: [\" ██████╗ \", \"██╔═══██╗\", \"██║ ██║\", \"██║▄▄ ██║\", \"╚██████╔╝\", \" ╚══▀▀═╝ \"],\n R: [\"██████╗ \", \"██╔══██╗\", \"██████╔╝\", \"██╔══██╗\", \"██║ ██║\", \"╚═╝ ╚═╝\"],\n S: [\"███████╗\", \"██╔════╝\", \"███████╗\", \"╚════██║\", \"███████║\", \"╚══════╝\"],\n T: [\"████████╗\", \"╚══██╔══╝\", \" ██║ \", \" ██║ \", \" ██║ \", \" ╚═╝ \"],\n U: [\"██╗ ██╗\", \"██║ ██║\", \"██║ ██║\", \"██║ ██║\", \"╚██████╔╝\", \" ╚═════╝ \"],\n V: [\"██╗ ██╗\", \"██║ ██║\", \"██║ ██║\", \"╚██╗ ██╔╝\", \" ╚████╔╝ \", \" ╚═══╝ \"],\n W: [\"██╗ ██╗\", \"██║ ██║\", \"██║ █╗ ██║\", \"██║███╗██║\", \"╚███╔███╔╝\", \" ╚══╝╚══╝ \"],\n X: [\"██╗ ██╗\", \"╚██╗██╔╝\", \" ╚███╔╝ \", \" ██╔██╗ \", \"██╔╝ ██╗\", \"╚═╝ ╚═╝\"],\n Y: [\"██╗ ██╗\", \"╚██╗ ██╔╝\", \" ╚████╔╝ \", \" ╚██╔╝ \", \" ██║ \", \" ╚═╝ \"],\n Z: [\"███████╗\", \"╚══███╔╝\", \" ███╔╝ \", \" ███╔╝ \", \"███████╗\", \"╚══════╝\"],\n \"0\": [\" ██████╗ \", \"██╔═████╗\", \"██║██╔██║\", \"████╔╝██║\", \"╚██████╔╝\", \" ╚═════╝ \"],\n \"1\": [\" ██╗\", \"███║\", \"╚██║\", \" ██║\", \" ██║\", \" ╚═╝\"],\n \"2\": [\"██████╗ \", \"╚════██╗\", \" █████╔╝\", \"██╔═══╝ \", \"███████╗\", \"╚══════╝\"],\n \"3\": [\"██████╗ \", \"╚════██╗\", \" █████╔╝\", \" ╚═══██╗\", \"██████╔╝\", \"╚═════╝ \"],\n \"4\": [\"██╗ ██╗\", \"██║ ██║\", \"███████║\", \"╚════██║\", \" ██║\", \" ╚═╝\"],\n \"5\": [\"███████╗\", \"██╔════╝\", \"███████╗\", \"╚════██║\", \"███████║\", \"╚══════╝\"],\n \"6\": [\" ██████╗ \", \"██╔════╝ \", \"███████╗ \", \"██╔═══██╗\", \"╚██████╔╝\", \" ╚═════╝ \"],\n \"7\": [\"███████╗\", \"╚════██║\", \" ██╔╝\", \" ██╔╝ \", \" ██║ \", \" ╚═╝ \"],\n \"8\": [\" █████╗ \", \"██╔══██╗\", \"╚█████╔╝\", \"██╔══██╗\", \"╚█████╔╝\", \" ╚════╝ \"],\n \"9\": [\" █████╗ \", \"██╔══██╗\", \"╚██████║\", \" ╚═══██║\", \" █████╔╝\", \" ╚════╝ \"],\n \"-\": [\" \", \" \", \"█████╗\", \"╚════╝\", \" \", \" \"],\n \"_\": [\" \", \" \", \" \", \" \", \"███████╗\", \"╚══════╝\"],\n \".\": [\" \", \" \", \" \", \" \", \"██╗\", \"╚═╝\"],\n \" \": [\" \", \" \", \" \", \" \", \" \", \" \"],\n};\n\nconst GLYPH_ROWS = 6;\n\n/** Visible column count of a string (full-block + box-drawing are 1 cell each). */\nfunction vlen(s: string): number {\n return [...s].length;\n}\n\n/**\n * Render `name` into the fixed-width `font` as GLYPH_ROWS lines. The ANSI-Shadow\n * glyphs already carry their own trailing shadow column and tile cleanly with NO\n * inter-glyph gap. Returns null when the name has no renderable characters; the\n * glyphs are width-consistent per glyph, so the rows stay aligned.\n */\nfunction renderWithFont(name: string, font: Record<string, readonly string[]>): string[] | null {\n const chars = [...name];\n if (chars.length === 0) return null;\n const blank = font[\" \"]!;\n const rows: string[] = Array.from({ length: GLYPH_ROWS }, () => \"\");\n for (const ch of chars) {\n const glyph = font[ch.toUpperCase()] ?? blank;\n for (let r = 0; r < GLYPH_ROWS; r++) {\n rows[r] += glyph[r] ?? \"\";\n }\n }\n // Drop any fully-blank bottom rows so a name built from narrower glyphs (e.g.\n // \".\" / \"_\") never pads the banner with trailing empty lines.\n while (rows.length > 1 && rows[rows.length - 1]!.trim() === \"\") rows.pop();\n return rows;\n}\n\n/** Max visible width across an art block's rows. */\nfunction blockWidth(rows: string[]): number {\n return rows.length === 0 ? 0 : Math.max(...rows.map(vlen));\n}\n\n/**\n * The WIDE ANSI-Shadow block art for `name` when it fits `columns` (ONE line,\n * never stacked); else null so the caller renders the narrow one-line title.\n * `columns <= 0` means \"no constraint\" → always the WIDE art.\n */\nfunction selectWideArt(name: string, columns: number): string[] | null {\n const limit = columns > 0 ? columns : Infinity;\n const wide = renderWithFont(name, WIDE_FONT);\n return wide != null && blockWidth(wide) <= limit ? wide : null;\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Palette-parameterized gradient. The sweep lerps the three palette stops\n// across each row's columns (t∈[0,1]). truecolor uses the exact RGB; 256 and 16\n// derive the nearest representable code FROM the same RGB, so every palette\n// works in every tier. \"none\" emits the bare char.\n// ─────────────────────────────────────────────────────────────────────────\n\n/** The interpolated RGB of `palette` at gradient position t∈[0,1]. */\nfunction gradientRGB(t: number, palette: Palette): RGB {\n const clamp = Math.max(0, Math.min(1, t));\n const seg = clamp >= 0.5 ? 1 : 0;\n const local = (clamp - seg * 0.5) / 0.5;\n const a = palette[seg]!;\n const b = palette[seg + 1]!;\n return [\n Math.round(a[0] + (b[0] - a[0]) * local),\n Math.round(a[1] + (b[1] - a[1]) * local),\n Math.round(a[2] + (b[2] - a[2]) * local),\n ];\n}\n\n/** Nearest xterm-256 cube index (16..231) for an RGB triple. */\nfunction rgbTo256(r: number, g: number, b: number): number {\n const q = (v: number): number => (v < 48 ? 0 : v < 115 ? 1 : Math.round((v - 35) / 40));\n return 16 + 36 * q(r) + 6 * q(g) + q(b);\n}\n\n/** Nearest of the 8 bright 16-color fg codes (90..97) for an RGB triple. */\nfunction rgbTo16(r: number, g: number, b: number): number {\n // Threshold each channel; map the on/off triple to its bright SGR code.\n const hi = (v: number): number => (v >= 128 ? 1 : 0);\n const key = (hi(r) << 2) | (hi(g) << 1) | hi(b);\n // index: RGB bits → code. 0:black(90) 1:blue(94) 2:green(92) 3:cyan(96)\n // 4:red(91) 5:magenta(95) 6:yellow(93) 7:white(97)\n return [90, 94, 92, 96, 91, 95, 93, 97][key]!;\n}\n\nconst RESET = \"\\x1b[0m\";\n\n/**\n * Wrap a single grapheme `ch` at gradient position `t` in the SGR escape for the\n * given color tier + palette. Whitespace is never colored (no point paying for\n * an escape around a space) and \"none\" returns the bare char.\n */\nfunction colorChar(ch: string, t: number, color: ColorMode, palette: Palette): string {\n if (color === \"none\" || ch.trim() === \"\") return ch;\n const [r, g, b] = gradientRGB(t, palette);\n if (color === \"truecolor\") return `\\x1b[38;2;${r};${g};${b}m${ch}${RESET}`;\n if (color === \"ansi256\") return `\\x1b[38;5;${rgbTo256(r, g, b)}m${ch}${RESET}`;\n return `\\x1b[${rgbTo16(r, g, b)}m${ch}${RESET}`;\n}\n\n/** Apply the left-to-right gradient across one art row (by visible column). */\nfunction colorizeRow(row: string, color: ColorMode, palette: Palette): string {\n if (color === \"none\") return row;\n const chars = [...row];\n const width = Math.max(1, chars.length - 1);\n let out = \"\";\n for (let i = 0; i < chars.length; i++) {\n out += colorChar(chars[i]!, i / width, color, palette);\n }\n return out;\n}\n\n/** A single BOLD grapheme at gradient position `t` (used by the narrow title). */\nfunction boldColorChar(ch: string, t: number, color: ColorMode, palette: Palette): string {\n if (color === \"none\") return ch;\n const [r, g, b] = gradientRGB(t, palette);\n const fg =\n color === \"truecolor\"\n ? `38;2;${r};${g};${b}`\n : color === \"ansi256\"\n ? `38;5;${rgbTo256(r, g, b)}`\n : `${rgbTo16(r, g, b)}`;\n return `\\x1b[1;${fg}m${ch}${RESET}`;\n}\n\n/**\n * The NARROW one-line title `◆ AGENT-CONNECTOR`: a colored leading diamond (the\n * palette mid stop), two spaces, then the UPPERCASED brand with each character\n * colored along the palette gradient (i → t = i/(len-1)) and bold. Under \"none\"\n * it is the plain text with ZERO ANSI. ~18 cols for \"agent-connector\", so it\n * fits any real terminal.\n */\nfunction renderTitle(name: string, color: ColorMode, palette: Palette): string {\n const upper = name.toUpperCase();\n if (color === \"none\") return `◆ ${upper}`;\n const diamond = boldColorChar(\"◆\", 0.5, color, palette);\n const chars = [...upper];\n const span = Math.max(1, chars.length - 1);\n let title = \"\";\n for (let i = 0; i < chars.length; i++) {\n title += boldColorChar(chars[i]!, i / span, color, palette);\n }\n return `${diamond} ${title}`;\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Footer (engine attribution). Shown on BOTH the global and branded CLIs — the\n// \"powered by\" wording is intentional.\n// ─────────────────────────────────────────────────────────────────────────\n\nconst FOOTER_LINES = [\n \"powered by @ken-jo/agent-connector\",\n \"more → https://github.com/ken-jo/agent-connector\",\n] as const;\n\n/** Dim (de-emphasized) footer line; plain under \"none\". */\nfunction dim(text: string, color: ColorMode): string {\n return color === \"none\" ? text : `\\x1b[2m${text}${RESET}`;\n}\n\n/**\n * Render the full banner: a responsive brand title with a palette-driven\n * gradient, then a two-line dim footer directly below.\n *\n * • WIDE — the ANSI-Shadow block art when it fits `columns` (ONE line, never\n * stacked; `columns <= 0` = no constraint).\n * • NARROW — the one-line `◆ AGENT-CONNECTOR` gradient title (the universal\n * narrow form, ~18 cols) when the block art would overflow.\n * • `palette` defaults to PALETTES[0] so direct callers + tests are\n * deterministic; the impure app.ts wrapper rotates the palettes per run.\n * • Under `color: \"none\"` (NO_COLOR / dumb term) the output carries zero ANSI\n * escape codes — only the raw art/title + footer text.\n *\n * The result has NO trailing newline; the caller prints it with one.\n */\nexport function renderBrandBanner(name: string, opts: BannerOptions): string {\n const { color, columns } = opts;\n const palette = opts.palette ?? PALETTES[0]!;\n const footer = FOOTER_LINES.map((l) => dim(l, color)).join(\"\\n\");\n\n const art = selectWideArt(name, columns);\n const body =\n art != null\n ? art.map((row) => colorizeRow(row, color, palette)).join(\"\\n\")\n : renderTitle(name, color, palette);\n return `${body}\\n${footer}`;\n}\n"],"mappings":"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","names":[]}
@@ -12,11 +12,11 @@ import {
12
12
  import {
13
13
  loadRegisteredConnector,
14
14
  readRegisteredMeta
15
- } from "./chunk-KSPMSRVU.js";
15
+ } from "./chunk-PW42ZXCB.js";
16
16
  import {
17
17
  REGISTERED_PLATFORM_IDS,
18
18
  loadAdapter
19
- } from "./chunk-SILKSP2Y.js";
19
+ } from "./chunk-D4ELPBB5.js";
20
20
  import {
21
21
  projectIdentity
22
22
  } from "./chunk-GZGLCCEE.js";
@@ -371,4 +371,4 @@ export {
371
371
  isNativeHookDeclared,
372
372
  runNativeHook
373
373
  };
374
- //# sourceMappingURL=chunk-I5TO42QC.js.map
374
+ //# sourceMappingURL=chunk-I5UXHIDT.js.map
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  ADAPTER_REGISTRY
4
- } from "./chunk-SILKSP2Y.js";
4
+ } from "./chunk-D4ELPBB5.js";
5
5
 
6
6
  // src/adapters/detect.ts
7
7
  async function detectInstalledPlatforms(projectDir) {
@@ -85,4 +85,4 @@ export {
85
85
  detectInstalledPlatforms,
86
86
  detectRuntimeHost
87
87
  };
88
- //# sourceMappingURL=chunk-ZMAJ2XFD.js.map
88
+ //# sourceMappingURL=chunk-ISEJWBFF.js.map
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  installInstructions,
4
4
  packageConnector
5
- } from "./chunk-B5W3RHTI.js";
5
+ } from "./chunk-APZDTY76.js";
6
6
  import {
7
7
  MARKETPLACE_NAME,
8
8
  agyPluginInstalled,
@@ -49,7 +49,7 @@ import {
49
49
  } from "./chunk-Z2MRSS2I.js";
50
50
  import {
51
51
  detectInstalledPlatforms
52
- } from "./chunk-ZMAJ2XFD.js";
52
+ } from "./chunk-ISEJWBFF.js";
53
53
  import {
54
54
  log
55
55
  } from "./chunk-KHO5WNTP.js";
@@ -57,11 +57,11 @@ import {
57
57
  deregisterConnector,
58
58
  loadRegisteredConnector,
59
59
  registerConnector
60
- } from "./chunk-KSPMSRVU.js";
60
+ } from "./chunk-PW42ZXCB.js";
61
61
  import {
62
62
  REGISTERED_PLATFORM_IDS,
63
63
  loadAdapter
64
- } from "./chunk-SILKSP2Y.js";
64
+ } from "./chunk-D4ELPBB5.js";
65
65
  import {
66
66
  configPatchManualEdit
67
67
  } from "./chunk-NBYKLUF6.js";
@@ -3396,4 +3396,4 @@ export {
3396
3396
  upgradeViaMarketplace,
3397
3397
  marketplaceDoctorChecks
3398
3398
  };
3399
- //# sourceMappingURL=chunk-TTKSYJRY.js.map
3399
+ //# sourceMappingURL=chunk-PAPMUAR5.js.map
@@ -3,7 +3,7 @@ import {
3
3
  defineConnector,
4
4
  readConnectorPackageMetadataNearFile,
5
5
  withConnectorPackageMetadata
6
- } from "./chunk-KJLFGQQM.js";
6
+ } from "./chunk-5IOTP7LQ.js";
7
7
  import {
8
8
  assertNoSymlinkInPath,
9
9
  connectorDir,
@@ -193,4 +193,4 @@ export {
193
193
  connectorFromMeta,
194
194
  listRegisteredConnectors
195
195
  };
196
- //# sourceMappingURL=chunk-KSPMSRVU.js.map
196
+ //# sourceMappingURL=chunk-PW42ZXCB.js.map
@@ -9,13 +9,13 @@ import {
9
9
  } from "./chunk-Z2MRSS2I.js";
10
10
  import {
11
11
  detectRuntimeHost
12
- } from "./chunk-ZMAJ2XFD.js";
12
+ } from "./chunk-ISEJWBFF.js";
13
13
  import {
14
14
  attachLazyTelemetryUsage,
15
15
  buildTelemetryAccessor,
16
16
  measureToolCall,
17
17
  measureToolDefs
18
- } from "./chunk-I5TO42QC.js";
18
+ } from "./chunk-I5UXHIDT.js";
19
19
  import {
20
20
  log
21
21
  } from "./chunk-KHO5WNTP.js";
@@ -28,11 +28,11 @@ import {
28
28
  import {
29
29
  loadRegisteredConnector,
30
30
  readRegisteredMeta
31
- } from "./chunk-KSPMSRVU.js";
31
+ } from "./chunk-PW42ZXCB.js";
32
32
  import {
33
33
  REGISTERED_PLATFORM_IDS,
34
34
  loadAdapter
35
- } from "./chunk-SILKSP2Y.js";
35
+ } from "./chunk-D4ELPBB5.js";
36
36
  import {
37
37
  detectLaunchMethod
38
38
  } from "./chunk-4NHXLXSD.js";
@@ -442,7 +442,12 @@ async function runServe(opts) {
442
442
  if (dataDir !== void 0 && dataDir.trim() !== "") {
443
443
  process.env.AGENT_CONNECTOR_DATA_DIR = dataDir;
444
444
  }
445
- const connector = await loadRegisteredConnector(connectorId);
445
+ const connector = readRegisteredMeta(connectorId);
446
+ if (!connector) {
447
+ throw new Error(
448
+ `Connector "${connectorId}" is not registered. Run an install/register step first.`
449
+ );
450
+ }
446
451
  const id = projectIdentity(process.cwd());
447
452
  const hostPlatform = hostPlatformOverride !== void 0 && REGISTERED_PLATFORM_IDS.has(hostPlatformOverride) ? hostPlatformOverride : detectRuntimeHost().platform;
448
453
  const sessionId = resolveSessionId();
@@ -701,4 +706,4 @@ export {
701
706
  runStatusline,
702
707
  runAction
703
708
  };
704
- //# sourceMappingURL=chunk-EHP7WISI.js.map
709
+ //# sourceMappingURL=chunk-YPAXJ7EW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/runtime/serve.ts","../src/telemetry/calibration.ts","../src/telemetry/proxy.ts","../src/runtime/usage-event.ts","../src/runtime/statusline-entrypoint.ts","../src/runtime/action-entrypoint.ts"],"sourcesContent":["/**\n * runtime/serve — the `agent-connector serve` telemetry-wrapping entrypoint.\n *\n * When a stdio MCP server opts into transparent telemetry, its host config is\n * rewritten (by the adapter, via core/spawn.buildServeWrapperCommand) to launch\n * <homeBin> serve --connector <id> -- <realCommand> <realArgs...>\n * instead of the server directly. The CLI parses those flags and calls\n * {@link runServe}, which stands up the per-session telemetry context (store,\n * tokenizer, project identity, host detection) and hands off to the proxy.\n *\n * The proxy (telemetry/proxy.runServeProxy) forwards bytes VERBATIM in both\n * directions and measures aggregate per-tool token counts out of band, so this\n * wrapper is transparent to both the host and the real server. It resolves with\n * the child server's exit code, which the CLI uses as its own.\n */\n\nimport { randomUUID } from \"node:crypto\";\n\nimport { detectRuntimeHost } from \"../adapters/detect.js\";\nimport { REGISTERED_PLATFORM_IDS } from \"../adapters/registry.js\";\nimport { readRegisteredMeta } from \"../core/load-connector.js\";\nimport { projectIdentity } from \"../core/paths.js\";\nimport { detectLaunchMethod } from \"../core/spawn.js\";\nimport type { PlatformId } from \"../core/types.js\";\nimport { runServeProxy } from \"../telemetry/proxy.js\";\nimport { openStore } from \"../telemetry/store.js\";\nimport { getTokenizer } from \"../telemetry/tokenizer.js\";\nimport type { TelemetryInstallScope } from \"../telemetry/types.js\";\n\n/** Flags the CLI hands to {@link runServe}. */\nexport interface RunServeOptions {\n /** Connector id from `--connector <id>`; selects telemetry config + stamps records. */\n connectorId: string;\n /** The real MCP server executable to spawn (everything after `--`). */\n serverCommand: string;\n /** Arguments passed to that executable. */\n serverArgs: string[];\n /**\n * Install scope from `--scope <user|project>`. OPTIONAL: absent for configs\n * written before scope plumbing existed — left unstamped so older rows read\n * as \"unknown\". Stamped verbatim onto every telemetry record when present.\n */\n installScope?: TelemetryInstallScope;\n /**\n * Install TARGET platform id from `--host <platformId>` (baked into the\n * wrapper at install time). OPTIONAL: when a recognized platform id, it\n * OVERRIDES runtime env detection so headless spawns stamp hostPlatform\n * correctly (detectRuntimeHost only knows env markers for a few hosts and\n * otherwise mis-attributes). Absent/unrecognized → fall back to detection.\n */\n hostPlatformOverride?: PlatformId;\n /**\n * Framework data-root from `--data-dir <path>` (baked into the wrapper at\n * install time, only for a NON-DEFAULT root). OPTIONAL: when present, it pins\n * the data-root the WHOLE child resolves — connector record lookup AND the\n * telemetry store — by populating AGENT_CONNECTOR_DATA_DIR before anything\n * reads it. This is the env-independent path for hosts (codex) that strip the\n * MCP child's environment and would otherwise drop the override, leaving the\n * child to resolve the default `~/.agent-connector` and fail \"not registered\".\n * Absent → resolve the data-root the usual way (env or default).\n */\n dataDir?: string;\n}\n\n/**\n * Launch the developer's real MCP server under the telemetry-wrapping proxy.\n *\n * Resolves with the child server's exit code (propagated as this process's exit\n * code by the CLI). The session id comes from AGENT_CONNECTOR_SESSION when the\n * host sets it (empty otherwise); the host platform is detected from runtime env\n * markers; the project identity partitions telemetry by the stable project key.\n */\n/**\n * Resolve a session id for telemetry attribution. Prefers a host-provided\n * session/thread marker (so records from the same host session group together);\n * falls back to a per-process UUID — each `serve` invocation is one server\n * session, a sensible default granularity — so `--by session` rollups are never\n * collapsed into a single empty-keyed group.\n */\nfunction resolveSessionId(env: NodeJS.ProcessEnv = process.env): string {\n return (\n env.AGENT_CONNECTOR_SESSION ||\n env.CLAUDE_SESSION_ID ||\n env.CODEX_THREAD_ID ||\n env.CURSOR_TRACE_ID ||\n env.MCP_SESSION_ID ||\n `proc-${randomUUID()}`\n );\n}\n\nexport async function runServe(opts: RunServeOptions): Promise<number> {\n const {\n connectorId,\n serverCommand,\n serverArgs,\n installScope,\n hostPlatformOverride,\n dataDir,\n } = opts;\n\n // Pin the data-root BEFORE anything resolves it (the connector record lookup\n // below and openStore later both read dataRoot()). The wrapper passes\n // --data-dir only for a non-default root on a host that may strip the child\n // env (codex) — populating AGENT_CONNECTOR_DATA_DIR here makes the whole child\n // resolve that root regardless of whether the host propagated the env var.\n if (dataDir !== undefined && dataDir.trim() !== \"\") {\n process.env.AGENT_CONNECTOR_DATA_DIR = dataDir;\n }\n\n const connector = readRegisteredMeta(connectorId);\n if (!connector) {\n throw new Error(\n `Connector \"${connectorId}\" is not registered. Run an install/register step first.`,\n );\n }\n\n const id = projectIdentity(process.cwd());\n // Prefer the install TARGET platform baked into the wrapper (--host), but only\n // when it is a KNOWN registered platform id — a bad/unknown value falls back to\n // runtime env detection so a config typo can never poison hostPlatform.\n const hostPlatform: PlatformId =\n hostPlatformOverride !== undefined &&\n REGISTERED_PLATFORM_IDS.has(hostPlatformOverride)\n ? hostPlatformOverride\n : detectRuntimeHost().platform;\n const sessionId = resolveSessionId();\n\n // `serve` only ever wraps a locally-spawned stdio server (a remote/http server\n // is never launched through the proxy), so isRemote is always false here.\n const launchMethod = detectLaunchMethod(serverCommand, serverArgs);\n\n const store = openStore({});\n const tok = getTokenizer();\n\n return runServeProxy({\n connectorId,\n command: serverCommand,\n args: serverArgs,\n store,\n tokenizer: tok,\n modelFamilyHint: connector.telemetry.modelFamilyHint,\n hostPlatform,\n sessionId,\n projectKey: id.key,\n projectDir: id.dir,\n measureToolDefs: connector.telemetry.measureToolDefs,\n installScope,\n launchMethod,\n });\n}\n","/**\n * telemetry/calibration — OPT-IN Anthropic count_tokens calibration.\n *\n * The default tokenizer counts every family with the OpenAI o200k_base BPE, so\n * an Anthropic session's counts are an honest-but-approximate stand-in\n * (\"tokenizer-approx\"). This module lets a developer OPT IN to calibrating that\n * approximation against Anthropic's real `count_tokens` endpoint: we sample a\n * tiny fraction of tool calls off-box, learn a per-family correction factor\n * (rolling mean of exact/approx), and apply it to the locally-tokenized counts\n * so they land much closer to the host's real numbers — labeled honestly as\n * \"tokenizer-calibrated\".\n *\n * PRIVACY + SAFETY — load-bearing invariants:\n * • OPT-IN only. Nothing here runs unless BOTH AGENT_CONNECTOR_CALIBRATE\n * contains \"anthropic\" AND ANTHROPIC_API_KEY is set (see isCalibrationEnabled).\n * • Sampling only — shouldSample() rate-limits hard so we never hammer the API.\n * • Content leaves the box ONLY on a sampled call, ONLY when opted in. We store\n * a single scalar factor + sample count — NEVER the sampled text itself.\n * • Fail-open everywhere: a network/parse/IO error returns null / passes the\n * approximation through unchanged and NEVER throws into a tool call or hook.\n *\n * No new dependencies: uses Node's global fetch (Node >= 18) and node:fs.\n */\n\nimport { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nimport { dataRoot, ensureDir } from \"../core/paths.js\";\nimport type { ConfidenceSource, ModelFamily } from \"./types.js\";\n\n// ── Env switches ──────────────────────────────────────────────────────────\n\n/**\n * Is opt-in Anthropic calibration enabled for this process?\n *\n * Requires BOTH:\n * • AGENT_CONNECTOR_CALIBRATE — a comma-separated allowlist that INCLUDES\n * `anthropic` (so a future `AGENT_CONNECTOR_CALIBRATE=openai,anthropic` can\n * opt other families in without touching this gate), and\n * • ANTHROPIC_API_KEY — a non-empty key to authenticate the off-box call.\n *\n * Either missing → disabled (the privacy-safe default).\n */\nexport function isCalibrationEnabled(): boolean {\n const families = (process.env.AGENT_CONNECTOR_CALIBRATE || \"\")\n .split(\",\")\n .map((s) => s.trim())\n .filter((s) => s !== \"\");\n const key = (process.env.ANTHROPIC_API_KEY || \"\").trim();\n return families.includes(\"anthropic\") && key !== \"\";\n}\n\n// ── Factor store (dataRoot/calibration.json) ────────────────────────────────\n\n/** One learned correction factor for a model family: factor + sample count. */\nexport interface CalibrationFactor {\n /** Multiply an approx count by this to estimate the real count. */\n factor: number;\n /** How many samples have folded into the rolling mean. */\n samples: number;\n}\n\n/** The on-disk factor map, keyed by model family. */\nexport type CalibrationFactors = Partial<Record<ModelFamily, CalibrationFactor>>;\n\n/** Path to the learned-factor store: dataRoot()/calibration.json. */\nexport function calibrationPath(): string {\n return join(dataRoot(), \"calibration.json\");\n}\n\n/**\n * Clamp a measured exact/approx ratio into a sane range. A pathological sample\n * (e.g. an empty-string approx of 0 → Infinity, or a parse glitch) must never\n * poison the rolling mean, so ratios are pinned to [0.2, 5].\n */\nconst RATIO_MIN = 0.2;\nconst RATIO_MAX = 5;\n\nfunction clampRatio(ratio: number): number | null {\n if (!Number.isFinite(ratio) || ratio <= 0) return null;\n if (ratio < RATIO_MIN) return RATIO_MIN;\n if (ratio > RATIO_MAX) return RATIO_MAX;\n return ratio;\n}\n\n/**\n * Load the learned factors from disk. Fail-open: a missing/unreadable/malformed\n * file returns an empty map rather than throwing.\n */\nexport function loadFactors(): CalibrationFactors {\n const path = calibrationPath();\n if (!existsSync(path)) return {};\n try {\n const parsed = JSON.parse(readFileSync(path, \"utf8\")) as unknown;\n if (parsed === null || typeof parsed !== \"object\") return {};\n const out: CalibrationFactors = {};\n for (const [family, value] of Object.entries(parsed as Record<string, unknown>)) {\n if (value === null || typeof value !== \"object\") continue;\n const rec = value as Record<string, unknown>;\n const factor = rec[\"factor\"];\n const samples = rec[\"samples\"];\n if (\n typeof factor === \"number\" &&\n Number.isFinite(factor) &&\n factor > 0 &&\n typeof samples === \"number\" &&\n Number.isFinite(samples) &&\n samples >= 0\n ) {\n (out as Record<string, CalibrationFactor>)[family] = {\n factor,\n samples,\n };\n }\n }\n return out;\n } catch {\n return {};\n }\n}\n\n/**\n * Fold one observed exact/approx `ratio` into the rolling mean for `family` and\n * persist it. A running average converges to the true mean while staying cheap\n * and stateless across processes (each writer reads the prior count, blends in\n * the new sample, writes back). Fail-open: any read/write/clamp problem leaves\n * the store untouched and never throws.\n */\nexport function recordSample(family: ModelFamily, ratio: number): void {\n const clamped = clampRatio(ratio);\n if (clamped === null) return;\n try {\n const factors = loadFactors();\n const prior = factors[family];\n let next: CalibrationFactor;\n if (prior === undefined || prior.samples <= 0) {\n next = { factor: clamped, samples: 1 };\n } else {\n const samples = prior.samples + 1;\n // Running average: new mean = old mean + (sample - old mean) / n.\n const factor = prior.factor + (clamped - prior.factor) / samples;\n next = { factor, samples };\n }\n const updated: CalibrationFactors = { ...factors, [family]: next };\n const path = calibrationPath();\n ensureDir(dataRoot());\n writeFileSync(path, `${JSON.stringify(updated, null, 2)}\\n`, \"utf8\");\n } catch {\n /* fail-open: a calibration write must never break a tool call */\n }\n}\n\n// ── Anthropic count_tokens (off-box, sampled, fail-open) ─────────────────────\n\n/** Default model used for count_tokens when no family→model map applies. */\nconst DEFAULT_ANTHROPIC_MODEL = \"claude-3-5-sonnet-latest\";\n\n/** Anthropic count_tokens endpoint. */\nconst COUNT_TOKENS_URL = \"https://api.anthropic.com/v1/messages/count_tokens\";\n\n/** The single field we read out of a successful response. */\ninterface CountTokensResponse {\n input_tokens?: unknown;\n}\n\n/**\n * Ask Anthropic's `count_tokens` endpoint for the exact token count of `text`\n * under `model`. Returns the integer count, or `null` on ANY failure (no key,\n * non-200, network error, unparseable body) — fail-open by contract.\n *\n * Only ever called on a SAMPLED tool call when calibration is opted in, so the\n * sampled text leaves the box only under explicit operator consent.\n */\nexport async function countTokensAnthropic(\n text: string,\n model: string = DEFAULT_ANTHROPIC_MODEL,\n): Promise<number | null> {\n const apiKey = (process.env.ANTHROPIC_API_KEY || \"\").trim();\n if (apiKey === \"\") return null;\n try {\n const res = await fetch(COUNT_TOKENS_URL, {\n method: \"POST\",\n headers: {\n \"x-api-key\": apiKey,\n \"anthropic-version\": \"2023-06-01\",\n \"content-type\": \"application/json\",\n },\n body: JSON.stringify({\n model,\n messages: [{ role: \"user\", content: text }],\n }),\n });\n if (!res.ok) return null;\n const body = (await res.json()) as CountTokensResponse;\n const n = body.input_tokens;\n if (typeof n === \"number\" && Number.isFinite(n) && n >= 0) {\n return n;\n }\n return null;\n } catch {\n return null;\n }\n}\n\n// ── Sampling (rate-limit so we never hammer the API) ─────────────────────────\n\n/**\n * Sample roughly 1 in {@link SAMPLE_EVERY} calls, with a hard per-minute cap so\n * a burst of tool calls can never fan out into a burst of API calls. Both\n * counters are in-memory (per process) — calibration is a best-effort,\n * low-volume background signal, not a per-call requirement.\n */\nconst SAMPLE_EVERY = 20;\nconst MAX_SAMPLES_PER_MINUTE = 10;\n\nlet callCounter = 0;\nlet windowStartMs = 0;\nlet samplesThisWindow = 0;\n\n/**\n * Should THIS call fire an off-box count_tokens sample? Combines a 1-in-N\n * counter with a rolling per-minute cap. Pure in-memory bookkeeping; never\n * throws, never blocks.\n */\nexport function shouldSample(now: number = Date.now()): boolean {\n // Roll the per-minute window.\n if (now - windowStartMs >= 60_000) {\n windowStartMs = now;\n samplesThisWindow = 0;\n }\n callCounter += 1;\n if (callCounter % SAMPLE_EVERY !== 0) return false;\n if (samplesThisWindow >= MAX_SAMPLES_PER_MINUTE) return false;\n samplesThisWindow += 1;\n return true;\n}\n\n/** Reset the in-memory sampling counters. Test-only seam; cheap + side-effect-free. */\nexport function _resetSamplingForTest(): void {\n callCounter = 0;\n windowStartMs = 0;\n samplesThisWindow = 0;\n}\n\n// ── Apply a learned factor to a local approximation ──────────────────────────\n\n/** Result of {@link applyCalibration}: the adjusted count + its honest source. */\nexport interface CalibratedCount {\n tokens: number;\n source: Extract<ConfidenceSource, \"tokenizer-approx\" | \"tokenizer-calibrated\">;\n}\n\n/**\n * Adjust a locally-tokenized `approxTokens` count by the learned factor for\n * `family`. When a stored factor exists for the anthropic family, return the\n * scaled count labeled \"tokenizer-calibrated\"; otherwise pass the approximation\n * through unchanged as \"tokenizer-approx\". Pure: reads the factor store but\n * mutates nothing.\n */\nexport function applyCalibration(\n approxTokens: number,\n family: ModelFamily,\n factors: CalibrationFactors = loadFactors(),\n): CalibratedCount {\n if (family === \"anthropic\") {\n const f = factors[family];\n if (f !== undefined && f.samples > 0 && Number.isFinite(f.factor) && f.factor > 0) {\n return {\n tokens: Math.max(0, Math.round(approxTokens * f.factor)),\n source: \"tokenizer-calibrated\",\n };\n }\n }\n return { tokens: approxTokens, source: \"tokenizer-approx\" };\n}\n\n/** The model used for a family's count_tokens sample (anthropic → default model). */\nexport function modelForFamily(_family: ModelFamily): string {\n return DEFAULT_ANTHROPIC_MODEL;\n}\n","/**\n * telemetry/proxy — the telemetry-wrapping MCP stdio proxy.\n *\n * `agent-connector serve <command> <args…>` spawns the developer's REAL MCP\n * server as a child and sits transparently between the host and that server,\n * speaking the MCP stdio wire format: NEWLINE-DELIMITED JSON-RPC (one single-line\n * JSON object per message, terminated by `\\n`; stdio has NO Content-Length\n * framing). Bytes are forwarded VERBATIM in both directions so the proxy can\n * never corrupt the stream; a side line-buffer tees a COPY of each direction,\n * parses complete messages, and measures per-tool token usage out of band.\n *\n * Honesty / safety rules baked in here:\n * • Forwarding always happens FIRST. Measurement runs after the bytes are out\n * the door and is wrapped so a measurement bug can never break a tool call.\n * • Telemetry stores AGGREGATE COUNTS ONLY — the parsed `tools/call` arguments\n * and results are tokenized and discarded; raw content is never persisted.\n * • AGENT_CONNECTOR_TELEMETRY=0 → still proxy transparently, skip all measure.\n *\n * The proxy resolves with the child's exit code and propagates SIGINT/SIGTERM.\n */\n\nimport type { PlatformId } from \"../core/types.js\";\nimport { spawnChild } from \"../core/spawn-child.js\";\nimport { type JsonRpcMessage, LineBuffer, idKey, isObject } from \"./jsonrpc.js\";\nimport {\n applyCalibration,\n countTokensAnthropic,\n isCalibrationEnabled,\n modelForFamily,\n recordSample,\n shouldSample,\n} from \"./calibration.js\";\nimport { measureToolCall, measureToolDefs } from \"./measure.js\";\nimport { newRecordId } from \"./store.js\";\nimport { inferModelFamily } from \"./tokenizer.js\";\nimport type {\n ConfidenceSource,\n LaunchMethod,\n ModelFamily,\n TelemetryInstallScope,\n TelemetryStore,\n Tokenizer,\n ToolEventRecord,\n} from \"./types.js\";\n\n/** Options for {@link runServeProxy}. */\nexport interface RunServeProxyOptions {\n /** Connector id this server belongs to (stamped on every record). */\n connectorId: string;\n /** The real MCP server executable to spawn. */\n command: string;\n /** Arguments passed to that executable. */\n args: string[];\n /** Where measured records are appended. */\n store: TelemetryStore;\n /** Tokenizer used for measurement (defaults baked into measure helpers). */\n tokenizer: Tokenizer;\n /**\n * Telemetry model-family hint. \"auto\" infers the family from the MCP client's\n * `initialize` clientInfo.name; any explicit family wins outright.\n */\n modelFamilyHint: \"auto\" | ModelFamily;\n /** Host platform executing this proxy (stamped on every record). */\n hostPlatform: PlatformId;\n /** Host session id (stamped on every record). */\n sessionId: string;\n /** Hashed stable project identity (stamped on every record). */\n projectKey: string;\n /** Human-readable project directory (stamped on every record). */\n projectDir: string;\n /** When true, tokenize the `tools/list` schema once → tool-defs overhead. */\n measureToolDefs: boolean;\n /**\n * Install scope (global user vs project-local) stamped on every record.\n * OPTIONAL: omitted for configs written before scope plumbing existed, leaving\n * the field off the row so it reads as \"unknown\".\n */\n installScope?: TelemetryInstallScope;\n /**\n * How the wrapped server was launched (npx/bunx/uvx/node/binary/http), stamped\n * on every record. OPTIONAL for the same backward-compat reason as above.\n */\n launchMethod?: LaunchMethod;\n}\n\n// ── JSON-RPC shapes we read (kept local + narrow; everything else opaque) ─────\n\n/** A client→server `tools/call` we remember until its result comes back. */\ninterface PendingCall {\n toolName: string;\n args: unknown;\n}\n\n/**\n * Canonical string form of a tool call's arguments for an off-box count_tokens\n * sample — mirrors the tokenizer's own serialization so the sampled text equals\n * the bytes we approximated locally. A string passes through; anything else is\n * JSON-stringified; a value that stringifies to undefined becomes \"\".\n */\nfunction canonicalArgs(value: unknown): string {\n if (typeof value === \"string\") return value;\n try {\n return JSON.stringify(value) ?? \"\";\n } catch {\n return \"\";\n }\n}\n\n/**\n * Run the telemetry-wrapping MCP stdio proxy.\n *\n * Spawns `command args` with piped stdin/stdout (stderr inherited), forwards\n * both directions byte-for-byte, and measures `tools/call` round-trips and the\n * one-time `tools/list` tool-defs overhead into `store`. Resolves with the\n * child's exit code (or a signal-derived code) once the child closes.\n */\nexport async function runServeProxy(\n opts: RunServeProxyOptions,\n): Promise<number> {\n const {\n connectorId,\n command,\n args,\n store,\n tokenizer,\n modelFamilyHint,\n hostPlatform,\n sessionId,\n projectKey,\n projectDir,\n measureToolDefs: shouldMeasureToolDefs,\n installScope,\n launchMethod,\n } = opts;\n\n // Global kill switch: still proxy transparently, but skip ALL measurement.\n const measuringEnabled = process.env.AGENT_CONNECTOR_TELEMETRY !== \"0\";\n // OPT-IN Anthropic count_tokens calibration. Resolved once per session — the\n // gate (AGENT_CONNECTOR_CALIBRATE + ANTHROPIC_API_KEY) is process-level and\n // does not change mid-session. Off by default; privacy-safe.\n const calibrationEnabled = isCalibrationEnabled();\n\n // spawnChild fixes native-Windows package-runner launches: a bare npx/uvx\n // resolves to a .cmd shim that raw CreateProcess can't find/launch, so it is\n // run via a quoted single command line with a shell. No-op on macOS/Linux.\n const child = spawnChild(command, args, {\n stdio: [\"pipe\", \"pipe\", \"inherit\"],\n env: process.env,\n });\n\n // ── Per-session measurement state ───────────────────────────────────────\n // Family resolved from the client's `initialize` (or the hint) and cached.\n let family: ModelFamily = inferModelFamily(\"\", modelFamilyHint);\n // Outstanding tools/call requests, keyed by JSON-RPC id.\n const pending = new Map<string, PendingCall>();\n // Monotonic sequence so two records in the same ms still get distinct ids.\n let seq = 0;\n // tools/list overhead is measured exactly once per session.\n let toolDefsMeasured = false;\n\n /**\n * Build a base record stamped with the per-session identity fields plus the\n * scope dimensions. `installScope` / `launchMethod` are spread in ONLY when\n * defined, so a session without them leaves those fields off the row entirely\n * (read as \"unknown\") rather than writing an explicit `undefined`.\n */\n function baseRecord(): Omit<\n ToolEventRecord,\n \"toolName\" | \"scope\" | \"inputTokens\" | \"outputTokens\" | \"confidenceSource\" | \"isError\"\n > {\n return {\n id: newRecordId(seq++),\n ts: Date.now(),\n connectorId,\n hostPlatform,\n sessionId,\n projectKey,\n projectDir,\n ...(installScope !== undefined ? { installScope } : {}),\n ...(launchMethod !== undefined ? { launchMethod } : {}),\n };\n }\n\n /**\n * Inspect one parsed CLIENT→SERVER message. Caches the model family on\n * `initialize` and remembers `tools/call` requests so their results can be\n * measured when they come back. Never throws into the data path.\n */\n function onClientMessage(msg: JsonRpcMessage): void {\n const method = msg.method;\n if (method === \"initialize\") {\n const params = isObject(msg.params) ? msg.params : undefined;\n const clientInfo =\n params && isObject(params[\"clientInfo\"])\n ? (params[\"clientInfo\"] as Record<string, unknown>)\n : undefined;\n const clientName =\n clientInfo && typeof clientInfo[\"name\"] === \"string\"\n ? (clientInfo[\"name\"] as string)\n : \"\";\n family = inferModelFamily(clientName, modelFamilyHint);\n return;\n }\n\n if (method === \"tools/call\") {\n const key = idKey(msg.id);\n if (key === null) return; // a call with no id has no result to match\n const params = isObject(msg.params) ? msg.params : undefined;\n const toolName =\n params && typeof params[\"name\"] === \"string\"\n ? (params[\"name\"] as string)\n : \"unknown\";\n const callArgs = params ? params[\"arguments\"] : undefined;\n pending.set(key, { toolName, args: callArgs });\n }\n }\n\n /**\n * Inspect one parsed SERVER→CLIENT message. Matches `tools/call` results to\n * remembered requests and measures them; measures `tools/list` results once.\n * Never throws into the data path.\n */\n function onServerMessage(msg: JsonRpcMessage): void {\n const key = idKey(msg.id);\n if (key === null) return; // notifications carry no id we can correlate\n\n const pendingCall = pending.get(key);\n if (pendingCall !== undefined) {\n pending.delete(key);\n recordToolCall(pendingCall, msg);\n return;\n }\n\n // Not a tracked tools/call — it may be the tools/list result we measure\n // once for the fixed tool-definition overhead.\n if (shouldMeasureToolDefs && !toolDefsMeasured) {\n const result = isObject(msg.result) ? msg.result : undefined;\n const tools = result ? result[\"tools\"] : undefined;\n if (Array.isArray(tools)) {\n recordToolDefs(tools);\n }\n }\n }\n\n /** Measure a matched tools/call round-trip and append the record. */\n function recordToolCall(call: PendingCall, response: JsonRpcMessage): void {\n const hasError = response.error !== undefined;\n const result = response.result;\n // A JSON-RPC error has no `result`; measure against an empty object so the\n // input (args) tokens are still recorded honestly.\n const resultForMeasure = hasError ? {} : result;\n const measurement = measureToolCall(\n call.args,\n resultForMeasure,\n family,\n tokenizer,\n );\n\n // OPT-IN calibration: for an anthropic session, nudge the locally-tokenized\n // approx counts toward Anthropic's real numbers via the learned factor, and\n // fire a sampled off-box count_tokens to keep that factor fresh. Both steps\n // are best-effort and wrapped so they can never break the record path.\n let inputTokens = measurement.inputTokens;\n let outputTokens = measurement.outputTokens;\n let confidenceSource: ConfidenceSource = measurement.source;\n if (calibrationEnabled && family === \"anthropic\") {\n try {\n ({ inputTokens, outputTokens, confidenceSource } = calibrateCounts(\n measurement.inputTokens,\n measurement.outputTokens,\n measurement.source,\n ));\n maybeSampleCalibration(call.args, measurement.inputTokens);\n } catch {\n // Calibration is a non-essential enrichment — fall back to the raw\n // measurement values already captured above.\n }\n }\n\n // MCP signals a tool-level failure via result.isError===true; a JSON-RPC\n // protocol error (response.error) is also a failure.\n const resultIsError =\n isObject(result) && result[\"isError\"] === true;\n store.append({\n ...baseRecord(),\n toolName: call.toolName,\n scope: \"call\",\n inputTokens,\n outputTokens,\n confidenceSource,\n isError: hasError || resultIsError,\n });\n }\n\n /**\n * Apply the learned anthropic factor to the approx input/output counts. Only\n * a `tokenizer-approx` measurement is calibratable (a heuristic fallback or\n * host-native count is left exactly as-is); the combined source becomes\n * `tokenizer-calibrated` only when at least one side was actually scaled.\n */\n function calibrateCounts(\n rawIn: number,\n rawOut: number,\n rawSource: ConfidenceSource,\n ): { inputTokens: number; outputTokens: number; confidenceSource: ConfidenceSource } {\n if (rawSource !== \"tokenizer-approx\") {\n return { inputTokens: rawIn, outputTokens: rawOut, confidenceSource: rawSource };\n }\n const cin = applyCalibration(rawIn, family);\n const cout = applyCalibration(rawOut, family);\n const calibrated =\n cin.source === \"tokenizer-calibrated\" || cout.source === \"tokenizer-calibrated\";\n return {\n inputTokens: cin.tokens,\n outputTokens: cout.tokens,\n confidenceSource: calibrated ? \"tokenizer-calibrated\" : \"tokenizer-approx\",\n };\n }\n\n /**\n * On a SAMPLED call, fire-and-forget an off-box count_tokens for the call's\n * input args and fold the resulting exact/approx ratio into the learned\n * factor. Returns immediately — the network round-trip never blocks\n * forwarding or measurement. Fail-open: any error is swallowed.\n */\n function maybeSampleCalibration(args: unknown, approxInputTokens: number): void {\n if (approxInputTokens <= 0) return; // nothing to ratio against\n if (!shouldSample()) return;\n const text = canonicalArgs(args);\n if (text === \"\") return;\n // Detached promise — intentionally NOT awaited so the proxy never blocks on\n // the network. Errors are handled inside countTokensAnthropic (returns null)\n // and the .catch is a belt-and-braces guard against an unhandled rejection.\n void countTokensAnthropic(text, modelForFamily(family))\n .then((exact) => {\n if (exact !== null && exact > 0) {\n recordSample(family, exact / approxInputTokens);\n }\n })\n .catch(() => {\n /* fail-open: a calibration sample must never surface an error */\n });\n }\n\n /** Measure the one-time tools/list overhead and append the record. */\n function recordToolDefs(tools: readonly unknown[]): void {\n toolDefsMeasured = true;\n const count = measureToolDefs(tools, family, tokenizer);\n store.append({\n ...baseRecord(),\n toolName: \"*\",\n scope: \"tool_defs\",\n inputTokens: count.tokens,\n outputTokens: 0,\n confidenceSource: count.source,\n isError: false,\n });\n }\n\n /** Parse one NDJSON line and route it, swallowing any measurement error. */\n function handleLine(line: string, direction: \"client\" | \"server\"): void {\n if (!measuringEnabled) return;\n let msg: JsonRpcMessage;\n try {\n const parsed = JSON.parse(line) as unknown;\n if (!isObject(parsed)) return;\n msg = parsed as JsonRpcMessage;\n } catch {\n return; // not a complete/valid JSON message — ignore for telemetry\n }\n try {\n if (direction === \"client\") onClientMessage(msg);\n else onServerMessage(msg);\n } catch {\n // Measurement must NEVER break the proxy. Drop the record silently.\n }\n }\n\n const clientLines = new LineBuffer((line) => handleLine(line, \"client\"));\n const serverLines = new LineBuffer((line) => handleLine(line, \"server\"));\n\n // ── Transparent byte forwarding (host stdin → child stdin) ───────────────\n // Forward VERBATIM first, then tee a copy into the line buffer to measure.\n // Honor backpressure: if the child's stdin buffer is full, pause the host\n // stdin and resume on drain so a slow server can't make us buffer unboundedly.\n process.stdin.on(\"data\", (chunk: Buffer) => {\n if (child.stdin && child.stdin.writable) {\n const ok = child.stdin.write(chunk);\n if (!ok) {\n process.stdin.pause();\n child.stdin.once(\"drain\", () => process.stdin.resume());\n }\n }\n if (measuringEnabled) {\n try {\n clientLines.push(chunk);\n } catch {\n /* tee side-channel must never affect forwarding */\n }\n }\n });\n process.stdin.on(\"end\", () => {\n if (child.stdin && !child.stdin.destroyed) child.stdin.end();\n });\n\n // ── Transparent byte forwarding (child stdout → host stdout) ─────────────\n if (child.stdout) {\n const childStdout = child.stdout;\n childStdout.on(\"data\", (chunk: Buffer) => {\n const ok = process.stdout.write(chunk);\n if (!ok) {\n childStdout.pause();\n process.stdout.once(\"drain\", () => childStdout.resume());\n }\n if (measuringEnabled) {\n try {\n serverLines.push(chunk);\n } catch {\n /* tee side-channel must never affect forwarding */\n }\n }\n });\n }\n\n // ── Signal propagation: forward SIGINT/SIGTERM to the child ──────────────\n const forwardSignal = (signal: NodeJS.Signals): void => {\n try {\n if (!child.killed) child.kill(signal);\n } catch {\n /* child may already be gone */\n }\n };\n const onSigint = (): void => forwardSignal(\"SIGINT\");\n const onSigterm = (): void => forwardSignal(\"SIGTERM\");\n process.on(\"SIGINT\", onSigint);\n process.on(\"SIGTERM\", onSigterm);\n\n // ── Resolve with the child's exit code (or signal-derived code) ──────────\n return await new Promise<number>((resolve) => {\n const finish = (code: number): void => {\n process.removeListener(\"SIGINT\", onSigint);\n process.removeListener(\"SIGTERM\", onSigterm);\n try {\n store.close();\n } catch {\n /* best-effort flush */\n }\n resolve(code);\n };\n\n child.on(\"error\", () => {\n // The server could not be spawned/launched. Surface a conventional\n // \"command not executable\" style failure code.\n finish(126);\n });\n\n child.on(\"close\", (code, signal) => {\n if (typeof code === \"number\") {\n finish(code);\n return;\n }\n // Killed by a signal → conventional 128 + signal number where known.\n if (signal) {\n const num = signalToNumber(signal);\n finish(num === undefined ? 1 : 128 + num);\n return;\n }\n finish(1);\n });\n });\n}\n\n/** Map the common termination signals to their numbers for exit-code math. */\nfunction signalToNumber(signal: NodeJS.Signals): number | undefined {\n const table: Partial<Record<NodeJS.Signals, number>> = {\n SIGINT: 2,\n SIGQUIT: 3,\n SIGKILL: 9,\n SIGTERM: 15,\n };\n return table[signal];\n}\n\nexport default runServeProxy;\n","/**\n * runtime/usage-event — the OPT-IN host-native turn-usage enricher (enricher 4a).\n *\n * Gemini CLI / Antigravity fire an `AfterModel` (Antigravity CLI: `PostInvocation`)\n * hook AFTER each model turn, whose stdin payload carries a `usageMetadata` block\n * with the host's OWN exact token accounting for that whole conversation turn:\n * { promptTokenCount, candidatesTokenCount, cachedContentTokenCount,\n * thoughtsTokenCount, totalTokenCount }\n * This is the single point in the whole matrix where a host reports REAL per-turn\n * usage to a command we control — so we record it as `confidenceSource:\"host-native\"`\n * (the top of CONFIDENCE_RANK), upgrading those rows from the serve-proxy estimate.\n *\n * DISTINCT, NEVER-SUMMED ORIGIN. Host-native turn usage is WHOLE-CONVERSATION, not\n * per-MCP. To avoid double-counting against (a) the per-MCP serve-proxy `call`\n * rows and (b) the usage-reader host-scan numbers, every record written here uses\n * the DISTINCT scope `\"model_turn\"`. The MCP leaderboard excludes that scope (just\n * as it special-cases `tool_defs`); the unified leaderboard surfaces it as its own\n * clearly-labeled section that is explicitly never added to the other two origins.\n *\n * PRIVACY + FAIL-OPEN. This enricher is OPT-IN at install time (see the adapters);\n * it stores AGGREGATE COUNTS ONLY (no raw content — the payload's prompt/response\n * text is never read). ANY parse / store / IO error degrades to exit 0 and records\n * NOTHING: a host-native usage hook must never break a model turn. This function\n * never throws.\n */\n\nimport { projectIdentity } from \"../core/paths.js\";\nimport { newRecordId, openStore } from \"../telemetry/store.js\";\nimport type { PlatformId } from \"../core/types.js\";\nimport type { ToolEventRecord } from \"../telemetry/types.js\";\n\n/** Flags + stdin the CLI hands to {@link runUsageEvent}. */\nexport interface RunUsageEventOptions {\n /** Host platform id from the command (`usage-event <platformId> …`). */\n platformId: string;\n /** Connector id from `--connector <id>` (stamped on the record). */\n connectorId: string;\n /** Raw stdin payload (host-native JSON). Empty string is tolerated → no record. */\n stdin: string;\n}\n\n/** Process-level result the CLI translates into an exit code. */\nexport interface RunUsageEventResult {\n /** Always 0 — a host-native usage hook must never block a model turn. */\n exitCode: number;\n /** True when a `model_turn` record was appended (false on any fail-open path). */\n recorded: boolean;\n}\n\n/** The never-records, never-throws result. */\nconst NOOP: RunUsageEventResult = { exitCode: 0, recorded: false };\n\nfunction isObject(v: unknown): v is Record<string, unknown> {\n return typeof v === \"object\" && v !== null && !Array.isArray(v);\n}\n\n/** Coerce a value to a non-negative safe integer (NaN/negatives/floats → 0). */\nfunction toNonNegInt(v: unknown): number {\n const n = typeof v === \"number\" ? v : typeof v === \"string\" ? Number(v) : NaN;\n if (!Number.isFinite(n) || n < 0) return 0;\n return Math.floor(n);\n}\n\n/** First non-empty string among the given keys of an object. */\nfunction firstStr(obj: Record<string, unknown>, keys: readonly string[]): string | undefined {\n for (const k of keys) {\n const v = obj[k];\n if (typeof v === \"string\" && v.trim() !== \"\") return v;\n }\n return undefined;\n}\n\n/** Read a token field tolerant of both camelCase and snake_case spellings. */\nfunction tokenField(\n meta: Record<string, unknown>,\n keys: readonly string[],\n): number {\n for (const k of keys) {\n if (k in meta) return toNonNegInt(meta[k]);\n }\n return 0;\n}\n\n/** Locate the `usageMetadata` block under either spelling, top-level or nested. */\nfunction findUsageMetadata(root: Record<string, unknown>): Record<string, unknown> | undefined {\n for (const k of [\"usageMetadata\", \"usage_metadata\"]) {\n if (isObject(root[k])) return root[k] as Record<string, unknown>;\n }\n // Some hosts nest the model response (with its usage) under a `response` /\n // `modelResponse` envelope — probe one level down, best-effort.\n for (const k of [\"response\", \"modelResponse\", \"model_response\"]) {\n const nested = root[k];\n if (isObject(nested)) {\n for (const mk of [\"usageMetadata\", \"usage_metadata\"]) {\n if (isObject(nested[mk])) return nested[mk] as Record<string, unknown>;\n }\n }\n }\n return undefined;\n}\n\n/** A registered PlatformId, or \"unknown\" when the id is not one we know. */\nconst KNOWN_PLATFORMS: ReadonlySet<string> = new Set<PlatformId>([\n \"claude-code\", \"codex\", \"cursor\", \"vscode-copilot\", \"jetbrains-copilot\",\n \"copilot-cli\", \"gemini-cli\", \"opencode\", \"kilo\", \"kilo-cli\", \"warp\", \"hermes\",\n \"openclaw\", \"zed\", \"antigravity\", \"antigravity-cli\", \"kiro\", \"qwen-code\",\n \"kimi\", \"pi\", \"omp\", \"droid\", \"roo-code\", \"trae\", \"amp\", \"codebuff\", \"mux\",\n \"crush\", \"goose\", \"synthetic\", \"unknown\",\n]);\n\nfunction asPlatformId(id: string): PlatformId {\n return (KNOWN_PLATFORMS.has(id) ? id : \"unknown\") as PlatformId;\n}\n\n/**\n * Record one host-native model turn. Parses the host's `usageMetadata`, maps it to\n * a DISTINCT `model_turn` `ToolEventRecord` (confidence `host-native`, toolName\n * `\"*\"`), and appends it to the shared telemetry store. NEVER throws and never\n * blocks the turn: every failure path resolves to {@link NOOP} (exit 0, nothing\n * recorded).\n */\nexport async function runUsageEvent(\n opts: RunUsageEventOptions,\n): Promise<RunUsageEventResult> {\n try {\n // Global telemetry kill switch is honored by the store's append (no-op when\n // AGENT_CONNECTOR_TELEMETRY=0); we still parse cheaply and let append drop it.\n const trimmed = opts.stdin.trim();\n if (trimmed === \"\") return NOOP;\n\n let raw: unknown;\n try {\n raw = JSON.parse(trimmed);\n } catch {\n return NOOP; // malformed payload → fail-open, record nothing\n }\n if (!isObject(raw)) return NOOP;\n\n const meta = findUsageMetadata(raw);\n if (meta === undefined) return NOOP;\n\n const promptTokens = tokenField(meta, [\"promptTokenCount\", \"prompt_token_count\"]);\n const candidates = tokenField(meta, [\"candidatesTokenCount\", \"candidates_token_count\"]);\n const cached = tokenField(meta, [\"cachedContentTokenCount\", \"cached_content_token_count\"]);\n const thoughts = tokenField(meta, [\"thoughtsTokenCount\", \"thoughts_token_count\"]);\n\n // promptTokenCount is cache-INCLUSIVE (Gemini-family semantics, mirrored by\n // the antigravity-shared usage reader): net fresh input = prompt - cached.\n const inputTokens = Math.max(0, promptTokens - Math.min(cached, promptTokens));\n // Output = generated candidates + reasoning (\"thoughts\") tokens.\n const outputTokens = candidates + thoughts;\n\n // A turn with no measurable tokens is not worth a row.\n if (inputTokens === 0 && outputTokens === 0) return NOOP;\n\n // Identity: prefer payload session/cwd; fall back to process.cwd() for the\n // project key so a turn always lands in a stable project partition.\n const sessionId =\n firstStr(raw, [\"session_id\", \"sessionId\", \"conversationId\", \"conversation_id\"]) ?? \"\";\n const cwd = firstStr(raw, [\"cwd\", \"workspace\", \"projectDir\", \"project_dir\"]) ?? process.cwd();\n const id = projectIdentity(cwd);\n\n const record: ToolEventRecord = {\n id: newRecordId(0),\n ts: Date.now(),\n connectorId: opts.connectorId,\n toolName: \"*\",\n scope: \"model_turn\",\n hostPlatform: asPlatformId(opts.platformId),\n sessionId,\n projectKey: id.key,\n projectDir: id.dir,\n inputTokens,\n outputTokens,\n confidenceSource: \"host-native\",\n isError: false,\n };\n\n const store = openStore({});\n try {\n store.append(record);\n } finally {\n try {\n store.close();\n } catch {\n /* best-effort flush */\n }\n }\n return { exitCode: 0, recorded: true };\n } catch {\n // Fail-open: a host-native usage enricher must never surface an error.\n return NOOP;\n }\n}\n\nexport default runUsageEvent;\n","/**\n * runtime/statusline-entrypoint — the universal statusline (HUD) renderer.\n *\n * A statusline-supporting host points its status line config at the single stable\n * home binary (`<homeBin> statusline <platformId> --connector <id>`, built by\n * core/spawn.buildHomeBinStatuslineCommand). The CLI reads stdin and calls\n * {@link runStatusline} with the parsed flags + the raw stdin string. This module:\n *\n * 1. Loads the registered connector (live render handler) and the host adapter.\n * 2. Parses the host's raw status payload into a normalized StatuslineContext.\n * 3. Calls the connector's render(ctx) and coerces the result to a string.\n * 4. Formats the line into the host's native status reply (exit code + stdout).\n *\n * FAIL-SAFE is the contract (NOT fail-open with carve-outs like hooks): a status\n * line is decorative — it must NEVER wedge the host or spew an error/stack trace\n * into the status bar. So ANY error path — bad payload, missing connector,\n * throwing render, adapter without statusline support — returns exit 0 with NO\n * stdout (an empty status line), never a non-zero exit and never partial output.\n *\n * NOTE (follow-up): no telemetry is recorded for statusline renders in v1 (out of\n * scope). When added, it MUST stay inside the same fail-safe envelope.\n */\n\nimport type { PlatformId } from \"../core/types.js\";\nimport { log } from \"../core/logger.js\";\nimport {\n loadRegisteredConnector,\n readRegisteredMeta,\n} from \"../core/load-connector.js\";\nimport { loadAdapter } from \"../adapters/registry.js\";\nimport {\n attachLazyTelemetryUsage,\n buildTelemetryAccessor,\n} from \"./telemetry-accessor.js\";\n\n/** Flags + stdin the CLI hands to {@link runStatusline}. */\nexport interface RunStatuslineOptions {\n /** Host platform id from the command (`statusline <platformId> …`). */\n platformId: string;\n /** Connector id from `--connector <id>`. */\n connectorId: string;\n /** Raw stdin payload (host-native status JSON). Empty string is tolerated → `{}`. */\n stdin: string;\n}\n\n/** Process-level result the CLI translates into exit code + stdout/stderr. */\nexport interface RunStatuslineResult {\n exitCode: number;\n stdout?: string;\n stderr?: string;\n}\n\n/** The fail-safe result: exit 0, no output (an empty status line). */\nconst EMPTY: RunStatuslineResult = { exitCode: 0 };\n\n/**\n * Tolerantly parse the host's stdin payload. Empty / whitespace-only input is a\n * legitimate \"no payload\" signal and resolves to `{}`. Malformed JSON also\n * degrades to `{}` rather than throwing — fail-safe is the contract.\n */\nfunction parseStdin(stdin: string): unknown {\n const trimmed = stdin.trim();\n if (trimmed === \"\") return {};\n try {\n return JSON.parse(trimmed);\n } catch {\n return {};\n }\n}\n\n/**\n * Render one host status-line invocation. Always resolves (never rejects): every\n * failure path returns the empty {@link EMPTY} result so the CLI exits cleanly\n * with an empty status line. See the module header for the fail-safe contract.\n */\nexport async function runStatusline(\n opts: RunStatuslineOptions,\n): Promise<RunStatuslineResult> {\n const { platformId, connectorId, stdin } = opts;\n\n try {\n const connector = await loadRegisteredConnector(connectorId);\n const adapter = await loadAdapter(platformId);\n\n // Nothing to render: no statusline declared, or the host adapter has no\n // statusline runtime support (parse/format pair). Empty line, exit 0.\n if (\n !connector.statusline ||\n typeof connector.statusline.render !== \"function\" ||\n !adapter ||\n !adapter.parseStatusInput ||\n !adapter.formatStatusOutput\n ) {\n return EMPTY;\n }\n\n const raw = parseStdin(stdin);\n const ctx = adapter.parseStatusInput(raw);\n // The command carries the authoritative connector id; stamp it so render()\n // sees the connector it was dispatched for.\n ctx.connectorId = connectorId;\n // capabilities is REQUIRED on StatuslineContext. claude-code's parseStatusInput\n // sets it, but a future/third-party adapter could omit it — backfill so the\n // runtime guarantee matches the type (mirrors the simulate harness). Never\n // let render() see undefined capabilities while the type claims it is present.\n if (ctx.capabilities == null) ctx.capabilities = adapter.capabilities;\n // Recover the install scope from the registered metadata (sync) and stamp it\n // onto the ctx — scope is an install-time property the entrypoint has no\n // other access to. Undefined when the meta carries none. Also expose the\n // per-connector telemetry usage accessor (lazy, fail-safe to zeros).\n ctx.scope = readRegisteredMeta(connectorId)?.scope;\n ctx.telemetry = buildTelemetryAccessor(connectorId);\n // Keep `ctx.usage` synchronous for render functions, but compute it only if\n // the render actually reads the property. Status lines refresh frequently,\n // and the NDJSON backend has to scan the store for an all-time summary.\n attachLazyTelemetryUsage(ctx, connectorId);\n\n // Per-host render override: when rendering for host X, `hosts[X].render`\n // wins over the top-level render; a host not listed (or a per-host entry\n // that is somehow not a function) falls back to the top-level render.\n // Selection NEVER throws — fail-safe is preserved.\n const perHost = connector.statusline.hosts?.[platformId as PlatformId]?.render;\n const render =\n typeof perHost === \"function\" ? perHost : connector.statusline.render;\n\n const rendered = await render(ctx);\n // Coerce: a non-string return (number, accidental object) is stringified so\n // a misbehaving render never crashes the format step. null/undefined → \"\".\n const line = rendered == null ? \"\" : String(rendered);\n\n const reply = adapter.formatStatusOutput(line);\n return {\n exitCode: reply.exitCode,\n ...(reply.stdout !== undefined ? { stdout: reply.stdout } : {}),\n ...(reply.stderr !== undefined ? { stderr: reply.stderr } : {}),\n };\n } catch (err) {\n // FAIL-SAFE: a status line must never wedge the host or surface an error.\n // Log for diagnostics (stderr of the home binary — not the status bar) and\n // return the empty line.\n const message = err instanceof Error ? err.message : String(err);\n log.error(`statusline ${platformId} (${connectorId}) failed:`, message);\n return EMPTY;\n }\n}\n\nexport default runStatusline;\n","/**\n * runtime/action-entrypoint — the universal user-invokable action dispatcher.\n *\n * A future host affordance (slash command / keybinding) points at the single\n * stable home binary (`<homeBin> action <platformId> <actionId> --connector\n * <id>`, built by core/spawn.buildHomeBinActionCommand). The CLI parses the\n * flags and calls {@link runAction}. This module:\n *\n * 1. Loads the registered connector (live run handler) and the host adapter.\n * 2. Builds the shared {@link HostCtx} (host + the adapter's capabilities; NO\n * stdin — an action takes no host payload, unlike a hook or status line).\n * 3. Finds the action by id, resolves the per-host run override, runs it, and\n * prints the optional result.message.\n *\n * USER-TRIGGERED ERROR SEMANTICS (the key difference from hooks/statusline):\n * actions are invoked DELIBERATELY by a user, so errors are SURFACED, never\n * failed silently. An unknown action id or a throwing run → exit 1 + a stderr\n * message. (Hooks fail-open to exit 0; the statusline fail-safes to an empty\n * line — both are passive surfaces a host fires automatically. An action is not:\n * swallowing its failure would leave the user staring at nothing, unable to\n * tell the action ran.)\n *\n * NOTE (follow-up): no telemetry is recorded for action runs in v1 (out of\n * scope), and no adapter EMITS the affordance yet — v1 ships the dispatch\n * backbone only.\n */\n\nimport type {\n HostCtx,\n PlatformCapabilities,\n PlatformId,\n} from \"../core/types.js\";\nimport {\n loadRegisteredConnector,\n readRegisteredMeta,\n} from \"../core/load-connector.js\";\nimport { loadAdapter, REGISTERED_PLATFORM_IDS } from \"../adapters/registry.js\";\nimport { buildTelemetryAccessor } from \"./telemetry-accessor.js\";\n\n/** Flags the CLI hands to {@link runAction} (no stdin — actions take no payload). */\nexport interface RunActionOptions {\n /** Host platform id from the command (`action <platformId> <actionId> …`). */\n platformId: string;\n /** Connector id from `--connector <id>`. */\n connectorId: string;\n /** The action id positional (`action <platformId> <actionId> …`). */\n actionId: string;\n}\n\n/** Process-level result the CLI translates into exit code + stdout/stderr. */\nexport interface RunActionResult {\n exitCode: number;\n stdout?: string;\n stderr?: string;\n}\n\n/**\n * Minimal all-false capabilities for the fallback ctx when the host adapter is\n * unknown/unregistered. The action still runs (it takes no host payload), but\n * branching on `ctx.capabilities` reads every flag as off — no affordance is\n * advertised for a host we cannot describe.\n */\nconst EMPTY_CAPABILITIES: PlatformCapabilities = {\n preToolUse: false,\n postToolUse: false,\n preCompact: false,\n sessionStart: false,\n sessionEnd: false,\n userPromptSubmit: false,\n stop: false,\n notification: false,\n canModifyArgs: false,\n canModifyOutput: false,\n canInjectSessionContext: false,\n transports: [],\n};\n\n/**\n * Dispatch one user-invokable action. Always resolves (never rejects): every\n * path returns a concrete {@link RunActionResult} so the CLI can exit cleanly,\n * but UNLIKE the hook/statusline runtimes an error resolves to exit 1 + a stderr\n * message (actions are user-triggered — surface the failure). See the module\n * header for the user-triggered error contract.\n */\nexport async function runAction(\n opts: RunActionOptions,\n): Promise<RunActionResult> {\n const { platformId, connectorId, actionId } = opts;\n\n let connector;\n try {\n connector = await loadRegisteredConnector(connectorId);\n } catch (err) {\n // A user asked to run an action on a connector we cannot load — surface it\n // (do NOT fail-open: the user would otherwise see nothing and assume it ran).\n const message = err instanceof Error ? err.message : String(err);\n return { exitCode: 1, stderr: message };\n }\n\n const action = connector.actions.find((a) => a.id === actionId);\n if (!action) {\n return {\n exitCode: 1,\n stderr: `no action \"${actionId}\" on connector ${connectorId}`,\n };\n }\n\n // Build the shared HostCtx. capabilities come from the adapter; an unknown\n // adapter still runs with the minimal ctx (an action takes no host payload).\n const adapter = await loadAdapter(platformId).catch(() => undefined);\n const host: PlatformId = REGISTERED_PLATFORM_IDS.has(platformId as PlatformId)\n ? (platformId as PlatformId)\n : \"unknown\";\n const ctx: HostCtx = {\n host,\n capabilities: adapter?.capabilities ?? EMPTY_CAPABILITIES,\n // Recover the install scope from the registered metadata (sync) — scope is\n // an install-time property the entrypoint otherwise has no access to —\n // and expose the per-connector telemetry usage accessor (lazy, fail-safe).\n scope: readRegisteredMeta(connectorId)?.scope,\n telemetry: buildTelemetryAccessor(connectorId),\n };\n\n // Per-host run override: when running for host X, `hosts[X].run` wins over the\n // top-level run; a host not listed (or a per-host entry that is somehow not a\n // function) falls back to the top-level run.\n const perHost = action.hosts?.[platformId as PlatformId]?.run;\n const run = typeof perHost === \"function\" ? perHost : action.run;\n\n try {\n const result = await run(ctx);\n const message = result?.message;\n if (typeof message === \"string\" && message !== \"\") {\n return { exitCode: 0, stdout: message };\n }\n // void / no message → success with no output.\n return { exitCode: 0 };\n } catch (err) {\n // USER-TRIGGERED: a throwing action surfaces its failure (exit 1 + stderr),\n // never a silent fail-open. This is the documented difference from\n // hooks/statusline.\n const message = err instanceof Error ? err.message : String(err);\n return {\n exitCode: 1,\n stderr: `action \"${actionId}\" failed: ${message}`,\n };\n }\n}\n\nexport default runAction;\n"],"mappings":"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","names":["args","isObject"]}
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  readRegisteredMeta
4
- } from "./chunk-KSPMSRVU.js";
5
- import "./chunk-KJLFGQQM.js";
6
- import "./chunk-SILKSP2Y.js";
4
+ } from "./chunk-PW42ZXCB.js";
5
+ import "./chunk-5IOTP7LQ.js";
6
+ import "./chunk-D4ELPBB5.js";
7
7
  import {
8
8
  addLedgerOwner,
9
9
  configPatchManualEdit,
@@ -1493,4 +1493,4 @@ export {
1493
1493
  claudeSensitiveKeyViolation,
1494
1494
  claude_code_default as default
1495
1495
  };
1496
- //# sourceMappingURL=claude-code-DUZNOAS2.js.map
1496
+ //# sourceMappingURL=claude-code-GRWO6XBZ.js.map
package/dist/cli/sdk.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { URL } from 'node:url';
2
+
1
3
  /**
2
4
  * cli/sdk — the EMBEDDED SDK entry point for a developer-branded CLI.
3
5
  *
@@ -7,13 +9,11 @@
7
9
  * delegated and AUTO-SCOPED to the developer's connector:
8
10
  *
9
11
  * #!/usr/bin/env node
10
- * import { fileURLToPath } from "node:url";
11
12
  * import { createConnectorCli } from "@ken-jo/agent-connector/cli";
12
13
  * createConnectorCli({
13
- * name: "acme-db",
14
- * connector: fileURLToPath(new URL("./agent-connector.config.mjs", import.meta.url)),
14
+ * packageJson: new URL("./package.json", import.meta.url),
15
+ * connector: new URL("./agent-connector.config.mjs", import.meta.url),
15
16
  * }).run();
16
- * // fileURLToPath, NOT URL.pathname — .pathname yields "/C:/…" on Windows.
17
17
  *
18
18
  * Then a consumer runs `acme-db install`, `acme-db leaderboard`, `acme-db
19
19
  * telemetry`, `acme-db doctor`, etc. — and each one targets the developer's
@@ -21,28 +21,69 @@
21
21
  *
22
22
  * This module is PURE ARGUMENT TRANSFORMATION: it injects the right --connector
23
23
  * (path) or --connector <id> filter when the user did not supply one, then hands
24
- * off to {@link main} with the developer's program name. It never duplicates any
25
- * command logic — every behavior still lives in the command modules.
24
+ * off to {@link main} with the developer's program name/version. It never
25
+ * duplicates any command logic — every behavior still lives in the command
26
+ * modules.
26
27
  */
28
+
29
+ type ConnectorCliPath = string | URL;
30
+ interface ConnectorCliContext {
31
+ /** Resolved brand/bin name shown in usage, errors, and --version output. */
32
+ programName: string;
33
+ /** Resolved branded package version shown by --version. */
34
+ programVersion: string;
35
+ /** Absolute connector config path injected into connector-targeted commands. */
36
+ connector: string;
37
+ /** Lazily resolves the connector id for telemetry/serve/hook scoping. */
38
+ connectorId(): Promise<string>;
39
+ }
40
+ interface ConnectorCliPassthrough {
41
+ /**
42
+ * Return true when this invocation should be handled by custom package logic
43
+ * instead of the agent-connector command dispatcher.
44
+ */
45
+ when(argv: readonly string[], context: ConnectorCliContext): boolean;
46
+ /** Handle a matched invocation. Return the process exit code. */
47
+ run(argv: readonly string[], context: ConnectorCliContext): number | Promise<number>;
48
+ }
27
49
  /** Options for {@link createConnectorCli}. */
28
50
  interface CreateConnectorCliOptions {
29
- /** The developer's bin/brand name (shown in usage/help, e.g. "acme-db"). */
30
- name: string;
31
51
  /**
32
- * Absolute path to the developer's connector config (.mjs / .js / .json) that
33
- * ships inside their package. Injected as `--connector <path>` for the
52
+ * The developer's bin/brand name (shown in usage/help, e.g. "acme-db").
53
+ * Prefer `packageJson` for packaged connectors so name/version stay in one
54
+ * source of truth; this remains available for custom launchers and tests.
55
+ */
56
+ name?: string;
57
+ /**
58
+ * package.json for the branded connector package. When supplied, the CLI
59
+ * derives the bin name and version from package metadata.
60
+ */
61
+ packageJson?: ConnectorCliPath;
62
+ /**
63
+ * Absolute path or file URL to the developer's connector config (.mjs / .js /
64
+ * .json) that ships inside their package. Injected as `--connector <path>` for
34
65
  * connector-targeted subcommands when the user did not pass one.
35
66
  */
36
- connector: string;
67
+ connector: ConnectorCliPath;
37
68
  /**
38
69
  * The connector id used for the telemetry/leaderboard FILTER injection. When
39
70
  * omitted it is derived lazily by loading the connector config the first time a
40
71
  * telemetry/leaderboard subcommand runs.
41
72
  */
42
73
  connectorId?: string;
74
+ /**
75
+ * Package-specific command escapes that should run before agent-connector's
76
+ * dispatcher. Use sparingly for legacy/runtime commands that intentionally
77
+ * live outside the universal connector surface.
78
+ */
79
+ passthrough?: readonly ConnectorCliPassthrough[];
43
80
  }
44
81
  /** The runner returned by {@link createConnectorCli}. */
45
82
  interface ConnectorCli {
83
+ /** Resolved brand/bin name. */
84
+ name: string;
85
+ /** Resolved branded package version. */
86
+ version: string;
46
87
  /**
47
88
  * Run a branded invocation. `argv` defaults to `process.argv.slice(2)`.
48
89
  * Resolves to the process exit code (0 success, non-zero failure).
@@ -51,4 +92,4 @@ interface ConnectorCli {
51
92
  }
52
93
  declare function createConnectorCli(opts: CreateConnectorCliOptions): ConnectorCli;
53
94
 
54
- export { type ConnectorCli, type CreateConnectorCliOptions, createConnectorCli };
95
+ export { type ConnectorCli, type ConnectorCliContext, type ConnectorCliPassthrough, type ConnectorCliPath, type CreateConnectorCliOptions, createConnectorCli };