@ken-jo/agent-connector 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/NOTICE +6 -0
- package/README.md +348 -0
- package/dist/amp-QSFH2V7Y.js +217 -0
- package/dist/amp-QSFH2V7Y.js.map +1 -0
- package/dist/amp-TULUPXXL.js +237 -0
- package/dist/amp-TULUPXXL.js.map +1 -0
- package/dist/antigravity-CX2YLSY7.js +17 -0
- package/dist/antigravity-CX2YLSY7.js.map +1 -0
- package/dist/antigravity-STHZWMP3.js +171 -0
- package/dist/antigravity-STHZWMP3.js.map +1 -0
- package/dist/antigravity-cli-P6HADOAO.js +121 -0
- package/dist/antigravity-cli-P6HADOAO.js.map +1 -0
- package/dist/antigravity-cli-YQDFVV4U.js +86 -0
- package/dist/antigravity-cli-YQDFVV4U.js.map +1 -0
- package/dist/chunk-54EMKTTX.js +191 -0
- package/dist/chunk-54EMKTTX.js.map +1 -0
- package/dist/chunk-7L6ITC4T.js +54 -0
- package/dist/chunk-7L6ITC4T.js.map +1 -0
- package/dist/chunk-7MSDGHJW.js +316 -0
- package/dist/chunk-7MSDGHJW.js.map +1 -0
- package/dist/chunk-BCHWFTV4.js +196 -0
- package/dist/chunk-BCHWFTV4.js.map +1 -0
- package/dist/chunk-DBQMX75U.js +36 -0
- package/dist/chunk-DBQMX75U.js.map +1 -0
- package/dist/chunk-EXLS7BSI.js +29 -0
- package/dist/chunk-EXLS7BSI.js.map +1 -0
- package/dist/chunk-JNM3TPLX.js +593 -0
- package/dist/chunk-JNM3TPLX.js.map +1 -0
- package/dist/chunk-JWNT5KW7.js +197 -0
- package/dist/chunk-JWNT5KW7.js.map +1 -0
- package/dist/chunk-KHO5WNTP.js +30 -0
- package/dist/chunk-KHO5WNTP.js.map +1 -0
- package/dist/chunk-LTT56GI3.js +155 -0
- package/dist/chunk-LTT56GI3.js.map +1 -0
- package/dist/chunk-MEH7GC7R.js +111 -0
- package/dist/chunk-MEH7GC7R.js.map +1 -0
- package/dist/chunk-MQPNU2CY.js +64 -0
- package/dist/chunk-MQPNU2CY.js.map +1 -0
- package/dist/chunk-OPXAP3AC.js +12 -0
- package/dist/chunk-OPXAP3AC.js.map +1 -0
- package/dist/chunk-RK6VBLXP.js +50 -0
- package/dist/chunk-RK6VBLXP.js.map +1 -0
- package/dist/chunk-TIIP3RG2.js +420 -0
- package/dist/chunk-TIIP3RG2.js.map +1 -0
- package/dist/chunk-TRKWUNO4.js +702 -0
- package/dist/chunk-TRKWUNO4.js.map +1 -0
- package/dist/chunk-TRQKHP7D.js +93 -0
- package/dist/chunk-TRQKHP7D.js.map +1 -0
- package/dist/chunk-WCETQWWK.js +59 -0
- package/dist/chunk-WCETQWWK.js.map +1 -0
- package/dist/chunk-WV63X7IK.js +357 -0
- package/dist/chunk-WV63X7IK.js.map +1 -0
- package/dist/chunk-XD7MY6HB.js +343 -0
- package/dist/chunk-XD7MY6HB.js.map +1 -0
- package/dist/chunk-XNAM7F35.js +276 -0
- package/dist/chunk-XNAM7F35.js.map +1 -0
- package/dist/chunk-XUCWLJY5.js +238 -0
- package/dist/chunk-XUCWLJY5.js.map +1 -0
- package/dist/chunk-YNZU6PAV.js +800 -0
- package/dist/chunk-YNZU6PAV.js.map +1 -0
- package/dist/chunk-YT43MUSJ.js +146 -0
- package/dist/chunk-YT43MUSJ.js.map +1 -0
- package/dist/claude-code-HKDV7T32.js +637 -0
- package/dist/claude-code-HKDV7T32.js.map +1 -0
- package/dist/claude-code-W74MNTAC.js +652 -0
- package/dist/claude-code-W74MNTAC.js.map +1 -0
- package/dist/cli/sdk.d.ts +54 -0
- package/dist/cli/sdk.js +82 -0
- package/dist/cli/sdk.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +15 -0
- package/dist/cli.js.map +1 -0
- package/dist/codebuff-3PMZJJHP.js +307 -0
- package/dist/codebuff-3PMZJJHP.js.map +1 -0
- package/dist/codebuff-QX57FJDN.js +220 -0
- package/dist/codebuff-QX57FJDN.js.map +1 -0
- package/dist/codex-JFQTS6LU.js +593 -0
- package/dist/codex-JFQTS6LU.js.map +1 -0
- package/dist/codex-Q3ATRRX3.js +364 -0
- package/dist/codex-Q3ATRRX3.js.map +1 -0
- package/dist/copilot-cli-MTCGHZ2T.js +622 -0
- package/dist/copilot-cli-MTCGHZ2T.js.map +1 -0
- package/dist/copilot-cli-SJGIXVSD.js +369 -0
- package/dist/copilot-cli-SJGIXVSD.js.map +1 -0
- package/dist/crush-I7PK3FGI.js +360 -0
- package/dist/crush-I7PK3FGI.js.map +1 -0
- package/dist/crush-LN5QFFR2.js +183 -0
- package/dist/crush-LN5QFFR2.js.map +1 -0
- package/dist/cursor-4TMXKJOZ.js +603 -0
- package/dist/cursor-4TMXKJOZ.js.map +1 -0
- package/dist/cursor-QZ6MTO74.js +194 -0
- package/dist/cursor-QZ6MTO74.js.map +1 -0
- package/dist/detect-WIAGVYS4.js +68 -0
- package/dist/detect-WIAGVYS4.js.map +1 -0
- package/dist/doctor-EZW2K4NI.js +372 -0
- package/dist/doctor-EZW2K4NI.js.map +1 -0
- package/dist/droid-KN6VRMMT.js +424 -0
- package/dist/droid-KN6VRMMT.js.map +1 -0
- package/dist/droid-W5WF5XEX.js +224 -0
- package/dist/droid-W5WF5XEX.js.map +1 -0
- package/dist/gemini-cli-CIRW37TU.js +369 -0
- package/dist/gemini-cli-CIRW37TU.js.map +1 -0
- package/dist/gemini-cli-Y35FFK4M.js +705 -0
- package/dist/gemini-cli-Y35FFK4M.js.map +1 -0
- package/dist/goose-A3M5GODH.js +212 -0
- package/dist/goose-A3M5GODH.js.map +1 -0
- package/dist/goose-ZTGTSUFJ.js +480 -0
- package/dist/goose-ZTGTSUFJ.js.map +1 -0
- package/dist/hermes-H2KV44GK.js +470 -0
- package/dist/hermes-H2KV44GK.js.map +1 -0
- package/dist/hermes-ZYLMOFLZ.js +196 -0
- package/dist/hermes-ZYLMOFLZ.js.map +1 -0
- package/dist/hook-YVDILAMZ.js +75 -0
- package/dist/hook-YVDILAMZ.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/install-HQRYZOQ2.js +60 -0
- package/dist/install-HQRYZOQ2.js.map +1 -0
- package/dist/jetbrains-copilot-HWA3DMH7.js +633 -0
- package/dist/jetbrains-copilot-HWA3DMH7.js.map +1 -0
- package/dist/kilo-NSWAVP6P.js +235 -0
- package/dist/kilo-NSWAVP6P.js.map +1 -0
- package/dist/kilo-QXJRCSLT.js +384 -0
- package/dist/kilo-QXJRCSLT.js.map +1 -0
- package/dist/kilo-cli-EAQTHXUW.js +587 -0
- package/dist/kilo-cli-EAQTHXUW.js.map +1 -0
- package/dist/kilo-cli-EVBKUODA.js +160 -0
- package/dist/kilo-cli-EVBKUODA.js.map +1 -0
- package/dist/kimi-EI3UM3ZV.js +155 -0
- package/dist/kimi-EI3UM3ZV.js.map +1 -0
- package/dist/kimi-GQ7VXNYT.js +423 -0
- package/dist/kimi-GQ7VXNYT.js.map +1 -0
- package/dist/kiro-UCLSLBW2.js +217 -0
- package/dist/kiro-UCLSLBW2.js.map +1 -0
- package/dist/kiro-VQTT6LO2.js +451 -0
- package/dist/kiro-VQTT6LO2.js.map +1 -0
- package/dist/leaderboard-K6ON3SWW.js +137 -0
- package/dist/leaderboard-K6ON3SWW.js.map +1 -0
- package/dist/mux-T2TV4CIQ.js +211 -0
- package/dist/mux-T2TV4CIQ.js.map +1 -0
- package/dist/mux-ZMLVAXOO.js +96 -0
- package/dist/mux-ZMLVAXOO.js.map +1 -0
- package/dist/omp-PB4VDKS6.js +586 -0
- package/dist/omp-PB4VDKS6.js.map +1 -0
- package/dist/openclaw-ETN2M63O.js +751 -0
- package/dist/openclaw-ETN2M63O.js.map +1 -0
- package/dist/openclaw-IYA7ASL6.js +150 -0
- package/dist/openclaw-IYA7ASL6.js.map +1 -0
- package/dist/opencode-FZ33JKUZ.js +734 -0
- package/dist/opencode-FZ33JKUZ.js.map +1 -0
- package/dist/opencode-HWT3RSMN.js +216 -0
- package/dist/opencode-HWT3RSMN.js.map +1 -0
- package/dist/package-DLOVE2E4.js +1132 -0
- package/dist/package-DLOVE2E4.js.map +1 -0
- package/dist/pi-CIU2QHT4.js +208 -0
- package/dist/pi-CIU2QHT4.js.map +1 -0
- package/dist/pi-UFX2OYFV.js +139 -0
- package/dist/pi-UFX2OYFV.js.map +1 -0
- package/dist/qwen-code-5POCNU6P.js +573 -0
- package/dist/qwen-code-5POCNU6P.js.map +1 -0
- package/dist/qwen-code-W7NUCDEN.js +134 -0
- package/dist/qwen-code-W7NUCDEN.js.map +1 -0
- package/dist/roo-code-IOIUXRDE.js +242 -0
- package/dist/roo-code-IOIUXRDE.js.map +1 -0
- package/dist/roo-code-ZLKH4A7N.js +229 -0
- package/dist/roo-code-ZLKH4A7N.js.map +1 -0
- package/dist/runtime/index.d.ts +157 -0
- package/dist/runtime/index.js +20 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/serve-HVWWY4B6.js +65 -0
- package/dist/serve-HVWWY4B6.js.map +1 -0
- package/dist/status-FE7TECZD.js +128 -0
- package/dist/status-FE7TECZD.js.map +1 -0
- package/dist/synthetic-UKR6SMGS.js +178 -0
- package/dist/synthetic-UKR6SMGS.js.map +1 -0
- package/dist/telemetry-36GESKQQ.js +349 -0
- package/dist/telemetry-36GESKQQ.js.map +1 -0
- package/dist/trae-JSNDZFKL.js +204 -0
- package/dist/trae-JSNDZFKL.js.map +1 -0
- package/dist/trae-PA26DPBW.js +157 -0
- package/dist/trae-PA26DPBW.js.map +1 -0
- package/dist/types-CYUB1OTr.d.ts +427 -0
- package/dist/uninstall-IGCKNOSF.js +72 -0
- package/dist/uninstall-IGCKNOSF.js.map +1 -0
- package/dist/upgrade-JV2VK242.js +104 -0
- package/dist/upgrade-JV2VK242.js.map +1 -0
- package/dist/usage-6ER6EMEY.js +324 -0
- package/dist/usage-6ER6EMEY.js.map +1 -0
- package/dist/usage-event-JKBI6XCF.js +48 -0
- package/dist/usage-event-JKBI6XCF.js.map +1 -0
- package/dist/vscode-copilot-CK3NO54M.js +715 -0
- package/dist/vscode-copilot-CK3NO54M.js.map +1 -0
- package/dist/warp-JNQA7PBU.js +126 -0
- package/dist/warp-JNQA7PBU.js.map +1 -0
- package/dist/warp-QNVDXOG4.js +199 -0
- package/dist/warp-QNVDXOG4.js.map +1 -0
- package/dist/zed-NNNX5MNT.js +272 -0
- package/dist/zed-NNNX5MNT.js.map +1 -0
- package/dist/zed-VRJKWYUR.js +209 -0
- package/dist/zed-VRJKWYUR.js.map +1 -0
- package/package.json +79 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/commands/leaderboard.ts"],"sourcesContent":["/**\n * cli/commands/leaderboard — the unified top-level `agent-connector leaderboard`.\n *\n * Prints THREE leaderboards, each clearly origin-labeled and NEVER summed:\n * 🔌 MCP / Plugin leaderboard ← origin `mcp-self`: the serve-proxy\n * telemetry store (which MCP server WE wrap costs the most — per-MCP `call`\n * + `tool_defs` rows; the `model_turn` rows are EXCLUDED here).\n * 🖥️ Host / User leaderboard ← origin `host-scan-logs`: the host usage\n * readers scanning agent CLI logs (which CLI / host spent the most).\n * 🛰️ Host-native turns (live, exact) ← origin `host-native-live`: the opt-in\n * AfterModel / PostInvocation usage hook (scope `model_turn`, confidence\n * host-native) — whole-conversation usage the host reported in real time.\n *\n * All three measure DIFFERENT things (per-MCP server bytes vs whole-conversation\n * usage from logs vs whole-conversation usage from a live hook). They are reported\n * side by side but their totals are NEVER added together.\n *\n * Flags:\n * --since 7d|24h|… lower-bound window applied to both sources.\n * --scope <value> MCP-section scope slice (user|project|npx|binary|http|…);\n * ignored by the host section (host logs carry no scope).\n * --connector <id> restrict the 🔌 MCP/plugin + 🛰️ host-native-turns\n * sections to ONE connector id. The 🖥️ host-scan section\n * is connector-agnostic (host CLI logs carry no connector\n * attribution) and is intentionally NOT filtered.\n * --json emit { mcp:[...], host:[...] } instead of the tables.\n */\n\nimport { parseArgs } from \"node:util\";\n\nimport {\n formatHostNativeTurns,\n formatMcpLeaderboard,\n hostNativeTurns,\n isScopeFilter,\n mcpLeaderboard,\n SCOPE_FILTER_VALUES,\n type ScopeFilter,\n} from \"../../telemetry/leaderboard.js\";\nimport { formatHostLeaderboard, hostLeaderboard } from \"../../usage/leaderboard.js\";\nimport { fail, print } from \"../app.js\";\n\n/**\n * Parse a relative duration (`Ns`/`Nm`/`Nh`/`Nd`) to a lower-bound epoch ms.\n * Returns undefined for empty input and null for a malformed one. (Kept local so\n * the leaderboard command stays decoupled from the report commands.)\n */\nexport function parseSince(since: string | undefined): number | null | undefined {\n if (since == null || since.trim() === \"\") return undefined;\n const m = since.trim().match(/^(\\d+)\\s*([smhd])$/i);\n if (!m || !m[1] || !m[2]) return null;\n const n = Number(m[1]);\n const unitMs: Record<string, number> = {\n s: 1000,\n m: 60_000,\n h: 3_600_000,\n d: 86_400_000,\n };\n const factor = unitMs[m[2].toLowerCase()];\n if (factor == null) return null;\n return Date.now() - n * factor;\n}\n\nexport async function run(argv: string[]): Promise<number> {\n const first = argv[0];\n if (first === \"--help\" || first === \"-h\") {\n print(\"usage: agent-connector leaderboard [flags]\");\n print(\" --since 7d|24h|… window applied to BOTH sources\");\n print(` --scope <value> MCP-section slice (${SCOPE_FILTER_VALUES.join(\"|\")})`);\n print(\" --connector <id> restrict the 🔌 MCP + 🛰️ host-native sections to one connector\");\n print(\" --json emit { mcp:[...], host:[...] } (never summed)\");\n return 0;\n }\n\n const { values } = parseArgs({\n args: argv,\n options: {\n since: { type: \"string\" },\n scope: { type: \"string\" },\n connector: { type: \"string\" },\n json: { type: \"boolean\", default: false },\n },\n allowPositionals: false,\n });\n\n const sinceMs = parseSince(values.since);\n if (sinceMs === null) {\n return fail(`invalid --since \"${values.since}\" (use forms like 30s, 15m, 24h, 7d)`);\n }\n\n let scope: ScopeFilter | undefined;\n if (values.scope !== undefined && values.scope.trim() !== \"\") {\n const s = values.scope.trim();\n if (!isScopeFilter(s)) {\n return fail(`invalid --scope \"${s}\" (use ${SCOPE_FILTER_VALUES.join(\"|\")})`);\n }\n scope = s;\n }\n\n // The optional --connector <id> FILTER restricts the two connector-attributed\n // sections (🔌 MCP/plugin + 🛰️ host-native turns) to one connector. The\n // 🖥️ host-scan section below is intentionally NOT filtered: host CLI logs carry\n // no connector attribution, so it stays connector-agnostic (whole-conversation).\n const connectorId =\n values.connector !== undefined && values.connector.trim() !== \"\"\n ? values.connector.trim()\n : undefined;\n\n // 🔌 MCP / Plugin leaderboard — serve-proxy telemetry (origin: mcp-self).\n const mcpOpts: { sinceMs?: number; scope?: ScopeFilter; connectorId?: string } = {};\n if (sinceMs !== undefined) mcpOpts.sinceMs = sinceMs;\n if (scope !== undefined) mcpOpts.scope = scope;\n if (connectorId !== undefined) mcpOpts.connectorId = connectorId;\n const mcp = mcpLeaderboard(mcpOpts);\n\n // 🖥️ Host / User leaderboard — host usage readers (origin: host-scan-logs).\n // Connector-agnostic by construction: NOT filtered by --connector.\n const hostOpts: { sinceMs?: number } = {};\n if (sinceMs !== undefined) hostOpts.sinceMs = sinceMs;\n const host = await hostLeaderboard(hostOpts);\n\n // 🛰️ Host-native turns — opt-in AfterModel usage hook (origin: host-native-live).\n // Scope `model_turn` rows ONLY; the MCP section above already excludes them.\n const turnsOpts: { sinceMs?: number; scope?: ScopeFilter; connectorId?: string } = {};\n if (sinceMs !== undefined) turnsOpts.sinceMs = sinceMs;\n if (scope !== undefined) turnsOpts.scope = scope;\n if (connectorId !== undefined) turnsOpts.connectorId = connectorId;\n const turns = hostNativeTurns(turnsOpts);\n\n if (values.json) {\n // Three separate arrays — by construction the consumer cannot sum origins.\n print(\n JSON.stringify(\n {\n mcp, // origin: mcp-self\n host: host.rows, // origin: host-scan-logs\n hostSkipped: host.skipped,\n hostNativeTurns: turns, // origin: host-native-live (scope model_turn)\n },\n null,\n 2,\n ),\n );\n return 0;\n }\n\n const lines: string[] = [];\n lines.push(\n \"🔌 MCP / Plugin leaderboard (origin: mcp-self — per-MCP server bytes we wrap; \" +\n \"excludes host-native model_turn rows)\",\n );\n if (scope !== undefined) lines.push(` scope: ${scope}`);\n if (connectorId !== undefined) lines.push(` connector: ${connectorId}`);\n lines.push(\"\");\n lines.push(formatMcpLeaderboard(mcp));\n lines.push(\"\");\n lines.push(\n \"🖥️ Host / User leaderboard (origin: host-scan-logs — whole-conversation usage from CLI logs)\",\n );\n if (connectorId !== undefined) {\n lines.push(\" (connector-agnostic — host CLI logs carry no connector attribution; --connector not applied here)\");\n }\n lines.push(\"\");\n lines.push(formatHostLeaderboard(host));\n lines.push(\"\");\n lines.push(\n \"🛰️ Host-native turns (live, exact) (origin: host-native-live — opt-in AfterModel usage hook)\",\n );\n lines.push(\"\");\n lines.push(formatHostNativeTurns(turns));\n lines.push(\"\");\n lines.push(\n \"note: the THREE leaderboards measure DIFFERENT things (per-MCP server bytes vs \" +\n \"whole-conversation usage from logs vs live host-native turns) and are never \" +\n \"summed together (their totals are NEVER added across origins).\",\n );\n print(lines.join(\"\\n\"));\n return 0;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
resolveEnvRefs,
|
|
4
|
+
resolveEnvRefsDeep
|
|
5
|
+
} from "./chunk-DBQMX75U.js";
|
|
6
|
+
import {
|
|
7
|
+
BaseAdapter
|
|
8
|
+
} from "./chunk-TIIP3RG2.js";
|
|
9
|
+
import "./chunk-7L6ITC4T.js";
|
|
10
|
+
import {
|
|
11
|
+
buildServeWrapperCommand,
|
|
12
|
+
shouldWrapForTelemetry
|
|
13
|
+
} from "./chunk-MEH7GC7R.js";
|
|
14
|
+
import "./chunk-TRQKHP7D.js";
|
|
15
|
+
|
|
16
|
+
// src/adapters/mux/index.ts
|
|
17
|
+
import { existsSync } from "fs";
|
|
18
|
+
import { homedir } from "os";
|
|
19
|
+
import { join } from "path";
|
|
20
|
+
var HOST = "mux";
|
|
21
|
+
var MCP_ROOT_KEY = "servers";
|
|
22
|
+
function quoteToken(token) {
|
|
23
|
+
return /\s/.test(token) ? `"${token}"` : token;
|
|
24
|
+
}
|
|
25
|
+
function buildCommandString(command, args) {
|
|
26
|
+
return [command, ...args].map(quoteToken).join(" ");
|
|
27
|
+
}
|
|
28
|
+
var MuxAdapter = class extends BaseAdapter {
|
|
29
|
+
id = HOST;
|
|
30
|
+
name = "Mux";
|
|
31
|
+
paradigm = "mcp-only";
|
|
32
|
+
capabilities = {
|
|
33
|
+
// Mux has no lifecycle hook system — every hook capability is false.
|
|
34
|
+
preToolUse: false,
|
|
35
|
+
postToolUse: false,
|
|
36
|
+
preCompact: false,
|
|
37
|
+
sessionStart: false,
|
|
38
|
+
sessionEnd: false,
|
|
39
|
+
userPromptSubmit: false,
|
|
40
|
+
stop: false,
|
|
41
|
+
notification: false,
|
|
42
|
+
canModifyArgs: false,
|
|
43
|
+
canModifyOutput: false,
|
|
44
|
+
canInjectSessionContext: false,
|
|
45
|
+
// Mux's command-string server entry is stdio-only.
|
|
46
|
+
transports: ["stdio"]
|
|
47
|
+
};
|
|
48
|
+
// ── Detection ────────────────────────────────────────────────────────────
|
|
49
|
+
detectInstalled(projectDir) {
|
|
50
|
+
const userDir = join(homedir(), ".mux");
|
|
51
|
+
const userMcp = join(userDir, "mcp.jsonc");
|
|
52
|
+
const projDir = join(projectDir, ".mux");
|
|
53
|
+
const projMcp = join(projDir, "mcp.jsonc");
|
|
54
|
+
const userInstalled = existsSync(userDir) || existsSync(userMcp);
|
|
55
|
+
const projInstalled = existsSync(projDir) || existsSync(projMcp);
|
|
56
|
+
const installed = userInstalled || projInstalled;
|
|
57
|
+
const scope = projInstalled && !userInstalled ? "project" : "user";
|
|
58
|
+
const configPath = scope === "project" ? projMcp : userMcp;
|
|
59
|
+
return {
|
|
60
|
+
id: this.id,
|
|
61
|
+
name: this.name,
|
|
62
|
+
installed,
|
|
63
|
+
paradigm: this.paradigm,
|
|
64
|
+
capabilities: this.capabilities,
|
|
65
|
+
configPath,
|
|
66
|
+
scope,
|
|
67
|
+
reason: installed ? `found Mux config (${scope})` : `no Mux config at ${userDir} or ${projDir}`,
|
|
68
|
+
confidence: installed ? "high" : "low"
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
// ── Native paths ─────────────────────────────────────────────────────────
|
|
72
|
+
getConfigDir(ctx) {
|
|
73
|
+
return ctx.scope === "project" ? join(ctx.projectDir, ".mux") : join(homedir(), ".mux");
|
|
74
|
+
}
|
|
75
|
+
getServerConfigPath(ctx) {
|
|
76
|
+
return join(this.getConfigDir(ctx), "mcp.jsonc");
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Mux has no hook file — hooks are not a thing here. The hook "config path"
|
|
80
|
+
* is the same mcp.jsonc so the generic doctor/backup behave sensibly.
|
|
81
|
+
*/
|
|
82
|
+
getHookConfigPath(ctx) {
|
|
83
|
+
return this.getServerConfigPath(ctx);
|
|
84
|
+
}
|
|
85
|
+
// ── MCP server install / uninstall ───────────────────────────────────────
|
|
86
|
+
installServer(ctx) {
|
|
87
|
+
const { connector, dryRun } = ctx;
|
|
88
|
+
const override = connector.platforms[HOST]?.server;
|
|
89
|
+
if (!connector.server || override === false) {
|
|
90
|
+
return [
|
|
91
|
+
{
|
|
92
|
+
platform: this.id,
|
|
93
|
+
action: "skip",
|
|
94
|
+
detail: connector.server ? "server registration disabled for mux" : "connector declares no MCP server"
|
|
95
|
+
}
|
|
96
|
+
];
|
|
97
|
+
}
|
|
98
|
+
const server = override && typeof override === "object" ? { ...connector.server, ...override } : connector.server;
|
|
99
|
+
const path = this.getServerConfigPath(ctx);
|
|
100
|
+
if (server.transport !== "stdio" || !server.command) {
|
|
101
|
+
return [
|
|
102
|
+
{
|
|
103
|
+
platform: this.id,
|
|
104
|
+
action: "skip",
|
|
105
|
+
path,
|
|
106
|
+
detail: `transport "${server.transport}" not registrable (mux expects a stdio command string)`
|
|
107
|
+
}
|
|
108
|
+
];
|
|
109
|
+
}
|
|
110
|
+
const entry = this.renderCommandString(ctx, server);
|
|
111
|
+
const cfg = this.readJson(path) ?? {};
|
|
112
|
+
const bucket = cfg[MCP_ROOT_KEY] ??= {};
|
|
113
|
+
const before = JSON.stringify(bucket[connector.id]);
|
|
114
|
+
const after = JSON.stringify(entry);
|
|
115
|
+
let action;
|
|
116
|
+
if (before === void 0) action = "create";
|
|
117
|
+
else if (before === after) action = "skip";
|
|
118
|
+
else action = "update";
|
|
119
|
+
if (action !== "skip") {
|
|
120
|
+
bucket[connector.id] = entry;
|
|
121
|
+
this.writeJson(path, cfg, dryRun);
|
|
122
|
+
}
|
|
123
|
+
return [
|
|
124
|
+
{ platform: this.id, action, path, detail: `${MCP_ROOT_KEY}.${connector.id}` }
|
|
125
|
+
];
|
|
126
|
+
}
|
|
127
|
+
uninstallServer(ctx) {
|
|
128
|
+
const path = this.getServerConfigPath(ctx);
|
|
129
|
+
return [
|
|
130
|
+
this.removeServerFromJson(path, MCP_ROOT_KEY, ctx.connector.id, ctx.dryRun)
|
|
131
|
+
];
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Render a stdio ServerDef into Mux's single shell-command string. Honors the
|
|
135
|
+
* telemetry serve-wrapper and resolves every `${env:VAR}` to a literal (Mux
|
|
136
|
+
* documents no native interpolation token).
|
|
137
|
+
*/
|
|
138
|
+
renderCommandString(ctx, server) {
|
|
139
|
+
let command = server.command ?? "";
|
|
140
|
+
let args = [...server.args ?? []];
|
|
141
|
+
if (shouldWrapForTelemetry(server, ctx.connector.telemetry)) {
|
|
142
|
+
const wrapped = buildServeWrapperCommand(
|
|
143
|
+
ctx.homeBinPath,
|
|
144
|
+
ctx.connector.id,
|
|
145
|
+
command,
|
|
146
|
+
args,
|
|
147
|
+
ctx.scope,
|
|
148
|
+
this.id
|
|
149
|
+
);
|
|
150
|
+
command = wrapped.command;
|
|
151
|
+
args = wrapped.args;
|
|
152
|
+
}
|
|
153
|
+
command = resolveEnvRefs(command);
|
|
154
|
+
args = resolveEnvRefsDeep(args);
|
|
155
|
+
return buildCommandString(command, args);
|
|
156
|
+
}
|
|
157
|
+
// ── Hooks (unavailable — Mux is mcp-only) ─────────────────────────────────
|
|
158
|
+
installHooks(_ctx) {
|
|
159
|
+
return [
|
|
160
|
+
{
|
|
161
|
+
platform: this.id,
|
|
162
|
+
action: "skip",
|
|
163
|
+
detail: "hooks unavailable (Mux is mcp-only)"
|
|
164
|
+
}
|
|
165
|
+
];
|
|
166
|
+
}
|
|
167
|
+
uninstallHooks(_ctx) {
|
|
168
|
+
return [
|
|
169
|
+
{
|
|
170
|
+
platform: this.id,
|
|
171
|
+
action: "skip",
|
|
172
|
+
detail: "hooks unavailable (Mux is mcp-only)"
|
|
173
|
+
}
|
|
174
|
+
];
|
|
175
|
+
}
|
|
176
|
+
// ── Diagnostics ──────────────────────────────────────────────────────────
|
|
177
|
+
getHealthChecks(ctx) {
|
|
178
|
+
const mcpPath = this.getServerConfigPath(ctx);
|
|
179
|
+
const connectorId = ctx.connector.id;
|
|
180
|
+
return [
|
|
181
|
+
{
|
|
182
|
+
name: `${this.name}: mcp.jsonc present`,
|
|
183
|
+
check: () => existsSync(mcpPath) ? { status: "OK", detail: mcpPath } : { status: "FAIL", detail: `not found: ${mcpPath}` }
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
name: `${this.name}: server entry registered`,
|
|
187
|
+
check: () => {
|
|
188
|
+
const cfg = this.readJson(
|
|
189
|
+
mcpPath
|
|
190
|
+
);
|
|
191
|
+
const bucket = cfg?.[MCP_ROOT_KEY];
|
|
192
|
+
if (!cfg || !bucket) {
|
|
193
|
+
return { status: "FAIL", detail: `no ${MCP_ROOT_KEY} in ${mcpPath}` };
|
|
194
|
+
}
|
|
195
|
+
return connectorId in bucket ? { status: "OK", detail: `${MCP_ROOT_KEY}.${connectorId} present` } : {
|
|
196
|
+
status: "FAIL",
|
|
197
|
+
detail: `no ${MCP_ROOT_KEY}.${connectorId} in ${mcpPath}`
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
];
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
var adapter = new MuxAdapter();
|
|
205
|
+
var mux_default = adapter;
|
|
206
|
+
export {
|
|
207
|
+
MuxAdapter,
|
|
208
|
+
adapter,
|
|
209
|
+
mux_default as default
|
|
210
|
+
};
|
|
211
|
+
//# sourceMappingURL=mux-T2TV4CIQ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/adapters/mux/index.ts"],"sourcesContent":["/**\n * adapters/mux — Mux (Coder) platform adapter for agent-connector.\n *\n * Mux is an **mcp-only** host: it exposes no lifecycle hook system, and MCP is\n * its extensibility mechanism. This adapter therefore installs only the MCP\n * server and reports hooks as unavailable — the same shape as the Warp\n * reference adapter.\n *\n * MCP config:\n * - user scope → ~/.mux/mcp.jsonc\n * - project scope → <projectDir>/.mux/mcp.jsonc\n * Both are JSONC (comments allowed) but we write strict JSON. The root key is\n * \"servers\", and this file doubles as the (non-existent) hook config — there\n * is no separate hook file here.\n *\n * QUIRK: Mux models each server entry as a single shell-command STRING, not an\n * object. So `servers[id]` is `\"<exe> <arg1> <arg2> ...\"` — space-joined, with\n * any token containing whitespace double-quoted. We therefore build that string\n * ourselves and upsert it idempotently (the generic object upsert helper would\n * write the wrong shape). When telemetry-wrapping, the string is the home-bin\n * `serve` wrapper command followed by its args.\n *\n * Mux documents no native `${env:VAR}` interpolation token, so env-refs in the\n * command/args are resolved to literals at install time. The string form has no\n * place for an env map, so server.env is dropped with no native equivalent.\n */\n\nimport { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport { BaseAdapter } from \"../base.js\";\nimport type { Adapter, InstallContext } from \"../spi.js\";\nimport type {\n ChangeRecord,\n DetectedPlatform,\n HealthCheck,\n HookParadigm,\n PlatformCapabilities,\n PlatformId,\n ServerDef,\n} from \"../../core/types.js\";\nimport { resolveEnvRefs, resolveEnvRefsDeep } from \"../../core/interpolate.js\";\nimport {\n buildServeWrapperCommand,\n shouldWrapForTelemetry,\n} from \"../../core/spawn.js\";\n\nconst HOST: PlatformId = \"mux\";\nconst MCP_ROOT_KEY = \"servers\";\n\n/** Quote a token only when it contains whitespace (Mux command-string form). */\nfunction quoteToken(token: string): string {\n return /\\s/.test(token) ? `\"${token}\"` : token;\n}\n\n/** Join an executable + args into Mux's single shell-command string. */\nfunction buildCommandString(command: string, args: readonly string[]): string {\n return [command, ...args].map(quoteToken).join(\" \");\n}\n\nexport class MuxAdapter extends BaseAdapter implements Adapter {\n readonly id: PlatformId = HOST;\n readonly name = \"Mux\";\n readonly paradigm: HookParadigm = \"mcp-only\";\n\n readonly capabilities: PlatformCapabilities = {\n // Mux has no lifecycle hook system — every hook capability is false.\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 // Mux's command-string server entry is stdio-only.\n transports: [\"stdio\"],\n };\n\n // ── Detection ────────────────────────────────────────────────────────────\n\n detectInstalled(projectDir: string): DetectedPlatform {\n const userDir = join(homedir(), \".mux\");\n const userMcp = join(userDir, \"mcp.jsonc\");\n const projDir = join(projectDir, \".mux\");\n const projMcp = join(projDir, \"mcp.jsonc\");\n\n const userInstalled = existsSync(userDir) || existsSync(userMcp);\n const projInstalled = existsSync(projDir) || existsSync(projMcp);\n const installed = userInstalled || projInstalled;\n const scope = projInstalled && !userInstalled ? \"project\" : \"user\";\n const configPath = scope === \"project\" ? projMcp : userMcp;\n\n return {\n id: this.id,\n name: this.name,\n installed,\n paradigm: this.paradigm,\n capabilities: this.capabilities,\n configPath,\n scope,\n reason: installed\n ? `found Mux config (${scope})`\n : `no Mux config at ${userDir} or ${projDir}`,\n confidence: installed ? \"high\" : \"low\",\n };\n }\n\n // ── Native paths ─────────────────────────────────────────────────────────\n\n getConfigDir(ctx: InstallContext): string {\n return ctx.scope === \"project\"\n ? join(ctx.projectDir, \".mux\")\n : join(homedir(), \".mux\");\n }\n\n getServerConfigPath(ctx: InstallContext): string {\n return join(this.getConfigDir(ctx), \"mcp.jsonc\");\n }\n\n /**\n * Mux has no hook file — hooks are not a thing here. The hook \"config path\"\n * is the same mcp.jsonc so the generic doctor/backup behave sensibly.\n */\n getHookConfigPath(ctx: InstallContext): string {\n return this.getServerConfigPath(ctx);\n }\n\n // ── MCP server install / uninstall ───────────────────────────────────────\n\n installServer(ctx: InstallContext): ChangeRecord[] {\n const { connector, dryRun } = ctx;\n const override = connector.platforms[HOST]?.server;\n if (!connector.server || override === false) {\n return [\n {\n platform: this.id,\n action: \"skip\",\n detail: connector.server\n ? \"server registration disabled for mux\"\n : \"connector declares no MCP server\",\n },\n ];\n }\n\n // Shallow-merge any per-platform server override into the base ServerDef.\n const server: ServerDef =\n override && typeof override === \"object\"\n ? { ...connector.server, ...override }\n : connector.server;\n\n const path = this.getServerConfigPath(ctx);\n\n if (server.transport !== \"stdio\" || !server.command) {\n // Mux's command-string entry is stdio-only; remote transports skip.\n return [\n {\n platform: this.id,\n action: \"skip\",\n path,\n detail: `transport \"${server.transport}\" not registrable (mux expects a stdio command string)`,\n },\n ];\n }\n\n const entry = this.renderCommandString(ctx, server);\n\n // QUIRK: each server value is a STRING, not an object — so we cannot use the\n // generic object upsert helper. Build the string and upsert idempotently.\n const cfg =\n this.readJson<Record<string, Record<string, unknown>>>(path) ?? {};\n const bucket = (cfg[MCP_ROOT_KEY] ??= {});\n const before = JSON.stringify(bucket[connector.id]);\n const after = JSON.stringify(entry);\n\n let action: ChangeRecord[\"action\"];\n if (before === undefined) action = \"create\";\n else if (before === after) action = \"skip\";\n else action = \"update\";\n\n if (action !== \"skip\") {\n bucket[connector.id] = entry;\n this.writeJson(path, cfg, dryRun);\n }\n return [\n { platform: this.id, action, path, detail: `${MCP_ROOT_KEY}.${connector.id}` },\n ];\n }\n\n uninstallServer(ctx: InstallContext): ChangeRecord[] {\n const path = this.getServerConfigPath(ctx);\n return [\n this.removeServerFromJson(path, MCP_ROOT_KEY, ctx.connector.id, ctx.dryRun),\n ];\n }\n\n /**\n * Render a stdio ServerDef into Mux's single shell-command string. Honors the\n * telemetry serve-wrapper and resolves every `${env:VAR}` to a literal (Mux\n * documents no native interpolation token).\n */\n private renderCommandString(ctx: InstallContext, server: ServerDef): string {\n let command = server.command ?? \"\";\n let args = [...(server.args ?? [])];\n\n // Transparent telemetry wrapping: route the real command through\n // `<homeBin> serve --connector <id> -- <command> <args...>`.\n if (shouldWrapForTelemetry(server, ctx.connector.telemetry)) {\n const wrapped = buildServeWrapperCommand(\n ctx.homeBinPath,\n ctx.connector.id,\n command,\n args,\n ctx.scope,\n this.id,\n );\n command = wrapped.command;\n args = wrapped.args;\n }\n\n // Resolve env-refs to literals (Mux has no native interpolation token).\n command = resolveEnvRefs(command);\n args = resolveEnvRefsDeep(args);\n\n return buildCommandString(command, args);\n }\n\n // ── Hooks (unavailable — Mux is mcp-only) ─────────────────────────────────\n\n installHooks(_ctx: InstallContext): ChangeRecord[] {\n return [\n {\n platform: this.id,\n action: \"skip\",\n detail: \"hooks unavailable (Mux is mcp-only)\",\n },\n ];\n }\n\n uninstallHooks(_ctx: InstallContext): ChangeRecord[] {\n return [\n {\n platform: this.id,\n action: \"skip\",\n detail: \"hooks unavailable (Mux is mcp-only)\",\n },\n ];\n }\n\n // ── Diagnostics ──────────────────────────────────────────────────────────\n\n override getHealthChecks(ctx: InstallContext): readonly HealthCheck[] {\n const mcpPath = this.getServerConfigPath(ctx);\n const connectorId = ctx.connector.id;\n return [\n {\n name: `${this.name}: mcp.jsonc present`,\n check: () =>\n existsSync(mcpPath)\n ? { status: \"OK\", detail: mcpPath }\n : { status: \"FAIL\", detail: `not found: ${mcpPath}` },\n },\n {\n name: `${this.name}: server entry registered`,\n check: () => {\n const cfg = this.readJson<{ [k: string]: Record<string, unknown> }>(\n mcpPath,\n );\n const bucket = cfg?.[MCP_ROOT_KEY];\n if (!cfg || !bucket) {\n return { status: \"FAIL\", detail: `no ${MCP_ROOT_KEY} in ${mcpPath}` };\n }\n return connectorId in bucket\n ? { status: \"OK\", detail: `${MCP_ROOT_KEY}.${connectorId} present` }\n : {\n status: \"FAIL\",\n detail: `no ${MCP_ROOT_KEY}.${connectorId} in ${mcpPath}`,\n };\n },\n },\n ];\n }\n}\n\nexport const adapter = new MuxAdapter();\nexport default adapter;\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
fileMtimeMs,
|
|
4
|
+
readJsonFile
|
|
5
|
+
} from "./chunk-RK6VBLXP.js";
|
|
6
|
+
import {
|
|
7
|
+
firstExistingRoot,
|
|
8
|
+
walkFiles
|
|
9
|
+
} from "./chunk-JWNT5KW7.js";
|
|
10
|
+
import {
|
|
11
|
+
emptyTokens
|
|
12
|
+
} from "./chunk-XD7MY6HB.js";
|
|
13
|
+
|
|
14
|
+
// src/usage/readers/mux.ts
|
|
15
|
+
import { basename, dirname } from "path";
|
|
16
|
+
var PLATFORM_ID = "mux";
|
|
17
|
+
function bucketTokens(bucket) {
|
|
18
|
+
const v = bucket?.tokens;
|
|
19
|
+
const n = typeof v === "number" ? v : typeof v === "string" ? Number(v) : NaN;
|
|
20
|
+
if (!Number.isFinite(n)) return 0;
|
|
21
|
+
return Math.max(0, Math.trunc(n));
|
|
22
|
+
}
|
|
23
|
+
function parseTimestampMs(v) {
|
|
24
|
+
if (typeof v === "number" && Number.isFinite(v) && v > 0) return Math.trunc(v);
|
|
25
|
+
if (typeof v === "string") {
|
|
26
|
+
const n = Number(v);
|
|
27
|
+
if (Number.isFinite(n) && n > 0) return Math.trunc(n);
|
|
28
|
+
}
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
function splitModelKey(key) {
|
|
32
|
+
const colon = key.indexOf(":");
|
|
33
|
+
if (colon < 0) return { provider: "", model: key };
|
|
34
|
+
return { provider: key.slice(0, colon), model: key.slice(colon + 1) };
|
|
35
|
+
}
|
|
36
|
+
function parseMuxFile(path) {
|
|
37
|
+
const raw = readJsonFile(path);
|
|
38
|
+
if (typeof raw !== "object" || raw === null) return [];
|
|
39
|
+
const usage = raw;
|
|
40
|
+
const byModel = usage.byModel;
|
|
41
|
+
if (typeof byModel !== "object" || byModel === null) return [];
|
|
42
|
+
const ts = parseTimestampMs(usage.lastRequest?.timestamp) ?? fileMtimeMs(path);
|
|
43
|
+
const sessionId = basename(dirname(path));
|
|
44
|
+
const out = [];
|
|
45
|
+
for (const [modelKey, value] of Object.entries(byModel)) {
|
|
46
|
+
if (typeof value !== "object" || value === null) continue;
|
|
47
|
+
const modelUsage = value;
|
|
48
|
+
const input = bucketTokens(modelUsage.input);
|
|
49
|
+
const cacheRead = bucketTokens(modelUsage.cached);
|
|
50
|
+
const cacheWrite = bucketTokens(modelUsage.cacheCreate);
|
|
51
|
+
const output = bucketTokens(modelUsage.output);
|
|
52
|
+
const reasoning = bucketTokens(modelUsage.reasoning);
|
|
53
|
+
if (input + cacheRead + cacheWrite + output + reasoning === 0) continue;
|
|
54
|
+
const { provider, model } = splitModelKey(modelKey);
|
|
55
|
+
const tokens = emptyTokens();
|
|
56
|
+
tokens.input = input;
|
|
57
|
+
tokens.output = output;
|
|
58
|
+
tokens.cacheRead = cacheRead;
|
|
59
|
+
tokens.cacheWrite = cacheWrite;
|
|
60
|
+
tokens.reasoning = reasoning;
|
|
61
|
+
out.push({
|
|
62
|
+
platformId: PLATFORM_ID,
|
|
63
|
+
modelId: model,
|
|
64
|
+
providerId: provider,
|
|
65
|
+
sessionId,
|
|
66
|
+
tokens,
|
|
67
|
+
ts,
|
|
68
|
+
messageCount: 1,
|
|
69
|
+
confidence: "host-reported"
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
return out;
|
|
73
|
+
}
|
|
74
|
+
var muxReader = {
|
|
75
|
+
platformId: PLATFORM_ID,
|
|
76
|
+
kind: "local",
|
|
77
|
+
async read({ sinceMs }) {
|
|
78
|
+
const root = firstExistingRoot(PLATFORM_ID);
|
|
79
|
+
if (root === void 0) return [];
|
|
80
|
+
const files = walkFiles(root, (name) => name === "session-usage.json");
|
|
81
|
+
const records = [];
|
|
82
|
+
for (const file of files) {
|
|
83
|
+
const rows = parseMuxFile(file);
|
|
84
|
+
for (const row of rows) {
|
|
85
|
+
if (sinceMs !== void 0 && row.ts < sinceMs) continue;
|
|
86
|
+
records.push(row);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return records;
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
var mux_default = muxReader;
|
|
93
|
+
export {
|
|
94
|
+
mux_default as default
|
|
95
|
+
};
|
|
96
|
+
//# sourceMappingURL=mux-ZMLVAXOO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/usage/readers/mux.ts"],"sourcesContent":["/**\n * usage/readers/mux — Mux (Coder) native session-usage reader.\n *\n * Faithful port of tokscale sessions/mux.rs. Reads the aggregate\n * ~/.mux/sessions/<workspaceId>/session-usage.json file (one per workspace).\n * This is NOT a JSONL log: each file is a single JSON object carrying a\n * `byModel` map keyed by `<provider>:<model>`, with one cumulative token bucket\n * group per model used in the session:\n * byModel.<key>.input.tokens → input\n * byModel.<key>.cached.tokens → cacheRead\n * byModel.<key>.cacheCreate.tokens → cacheWrite\n * byModel.<key>.output.tokens → output\n * byModel.<key>.reasoning.tokens → reasoning\n * Each bucket also carries an optional `.cost_usd`; the Rust sums those across\n * the five buckets into a source cost, but cost is out of scope for v1 readers\n * (matching the droid/amp JSON siblings) so we do not emit it. Negative token\n * counts are clamped to 0 and an entry whose five dimensions sum to 0 is dropped.\n *\n * One UsageRecord is produced per `byModel` entry (model used in the session).\n * The model key is split on the FIRST ':' only: the prefix is the provider id,\n * the remainder is the model id (so \"provider:sub:model\" → provider=\"provider\",\n * model=\"sub:model\"). A key with no ':' yields an empty provider and the full\n * key as the model id (matching the Rust empty-string provider).\n *\n * Session id is the parent directory name (the workspaceId), e.g.\n * \".../sessions/abc123/session-usage.json\" → \"abc123\". The session-usage.json\n * structure carries no cwd/dir, so there is no project attribution. Timestamp\n * prefers `lastRequest.timestamp` (i64 epoch milliseconds), falling back to the\n * file mtime. No dedup is needed — the file is an aggregate, not an incremental\n * log, and each model key appears once. Confidence is \"host-reported\".\n *\n * Fail-open: no root → []; unreadable/malformed file → skipped (never throws).\n */\n\nimport { basename, dirname } from \"node:path\";\n\nimport type { UsageReader, UsageRecord } from \"../types.js\";\nimport { emptyTokens } from \"../aggregate.js\";\nimport { fileMtimeMs, readJsonFile } from \"../jsonl.js\";\nimport { firstExistingRoot, walkFiles } from \"../paths.js\";\n\nconst PLATFORM_ID = \"mux\" as const;\n\n/** A single token bucket within a model entry (every field optional / unknown). */\ninterface MuxTokenBucket {\n tokens?: unknown;\n}\n\n/** One model entry under `byModel` (every bucket optional / unknown). */\ninterface MuxModelUsage {\n input?: MuxTokenBucket;\n cached?: MuxTokenBucket;\n cacheCreate?: MuxTokenBucket;\n output?: MuxTokenBucket;\n reasoning?: MuxTokenBucket;\n}\n\n/** The session-usage.json shape we read (everything optional / unknown). */\ninterface MuxSessionUsage {\n byModel?: unknown;\n lastRequest?: {\n timestamp?: unknown;\n };\n}\n\n/**\n * Coerce a bucket's token count to a non-negative integer, mirroring the Rust\n * closure `b.as_ref().and_then(|b| b.tokens).unwrap_or(0).max(0)`: absent or\n * non-numeric → 0, negatives clamped to 0.\n */\nfunction bucketTokens(bucket: MuxTokenBucket | undefined): number {\n const v = bucket?.tokens;\n const n = typeof v === \"number\" ? v : typeof v === \"string\" ? Number(v) : NaN;\n if (!Number.isFinite(n)) return 0;\n return Math.max(0, Math.trunc(n));\n}\n\n/**\n * Parse a `lastRequest.timestamp` to epoch ms, or null when unusable. Mux logs\n * an i64 of epoch milliseconds, so a positive finite number is taken verbatim\n * (no seconds heuristic — the Rust treats it as raw millis).\n */\nfunction parseTimestampMs(v: unknown): number | null {\n if (typeof v === \"number\" && Number.isFinite(v) && v > 0) return Math.trunc(v);\n if (typeof v === \"string\") {\n const n = Number(v);\n if (Number.isFinite(n) && n > 0) return Math.trunc(n);\n }\n return null;\n}\n\n/**\n * Split a model key on the FIRST ':' into provider + model (port of the Rust\n * splitn(2, ':')): \"anthropic:claude-opus-4-6\" → { provider: \"anthropic\",\n * model: \"claude-opus-4-6\" }; \"provider:sub:model\" → { provider: \"provider\",\n * model: \"sub:model\" }; a key with no ':' → empty provider, full key as model.\n */\nfunction splitModelKey(key: string): { provider: string; model: string } {\n const colon = key.indexOf(\":\");\n if (colon < 0) return { provider: \"\", model: key };\n return { provider: key.slice(0, colon), model: key.slice(colon + 1) };\n}\n\n/** Parse one mux session-usage.json file into usage records (port of parse_mux_file). */\nfunction parseMuxFile(path: string): UsageRecord[] {\n const raw = readJsonFile(path);\n if (typeof raw !== \"object\" || raw === null) return [];\n const usage = raw as MuxSessionUsage;\n\n const byModel = usage.byModel;\n if (typeof byModel !== \"object\" || byModel === null) return [];\n\n // Timestamp: lastRequest.timestamp (epoch ms) else the file mtime.\n const ts = parseTimestampMs(usage.lastRequest?.timestamp) ?? fileMtimeMs(path);\n\n // Session id = the parent directory name (the workspaceId).\n const sessionId = basename(dirname(path));\n\n const out: UsageRecord[] = [];\n for (const [modelKey, value] of Object.entries(byModel as Record<string, unknown>)) {\n if (typeof value !== \"object\" || value === null) continue;\n const modelUsage = value as MuxModelUsage;\n\n const input = bucketTokens(modelUsage.input);\n const cacheRead = bucketTokens(modelUsage.cached);\n const cacheWrite = bucketTokens(modelUsage.cacheCreate);\n const output = bucketTokens(modelUsage.output);\n const reasoning = bucketTokens(modelUsage.reasoning);\n\n // Skip entries with no tokens in any dimension.\n if (input + cacheRead + cacheWrite + output + reasoning === 0) continue;\n\n const { provider, model } = splitModelKey(modelKey);\n\n const tokens = emptyTokens();\n tokens.input = input;\n tokens.output = output;\n tokens.cacheRead = cacheRead;\n tokens.cacheWrite = cacheWrite;\n tokens.reasoning = reasoning;\n\n out.push({\n platformId: PLATFORM_ID,\n modelId: model,\n providerId: provider,\n sessionId,\n tokens,\n ts,\n messageCount: 1,\n confidence: \"host-reported\",\n });\n }\n\n return out;\n}\n\n/** The Mux (Coder) usage reader singleton. */\nconst muxReader: UsageReader = {\n platformId: PLATFORM_ID,\n kind: \"local\",\n async read({ sinceMs }: { sinceMs?: number }): Promise<UsageRecord[]> {\n const root = firstExistingRoot(PLATFORM_ID);\n if (root === undefined) return []; // no ~/.mux/sessions → fail-open\n\n // ~/.mux/sessions/<workspaceId>/session-usage.json\n const files = walkFiles(root, (name) => name === \"session-usage.json\");\n\n const records: UsageRecord[] = [];\n for (const file of files) {\n const rows = parseMuxFile(file);\n for (const row of rows) {\n if (sinceMs !== undefined && row.ts < sinceMs) continue;\n records.push(row);\n }\n }\n return records;\n },\n};\n\nexport default muxReader;\n"],"mappings":";;;;;;;;;;;;;;AAkCA,SAAS,UAAU,eAAe;AAOlC,IAAM,cAAc;AA6BpB,SAAS,aAAa,QAA4C;AAChE,QAAM,IAAI,QAAQ;AAClB,QAAM,IAAI,OAAO,MAAM,WAAW,IAAI,OAAO,MAAM,WAAW,OAAO,CAAC,IAAI;AAC1E,MAAI,CAAC,OAAO,SAAS,CAAC,EAAG,QAAO;AAChC,SAAO,KAAK,IAAI,GAAG,KAAK,MAAM,CAAC,CAAC;AAClC;AAOA,SAAS,iBAAiB,GAA2B;AACnD,MAAI,OAAO,MAAM,YAAY,OAAO,SAAS,CAAC,KAAK,IAAI,EAAG,QAAO,KAAK,MAAM,CAAC;AAC7E,MAAI,OAAO,MAAM,UAAU;AACzB,UAAM,IAAI,OAAO,CAAC;AAClB,QAAI,OAAO,SAAS,CAAC,KAAK,IAAI,EAAG,QAAO,KAAK,MAAM,CAAC;AAAA,EACtD;AACA,SAAO;AACT;AAQA,SAAS,cAAc,KAAkD;AACvE,QAAM,QAAQ,IAAI,QAAQ,GAAG;AAC7B,MAAI,QAAQ,EAAG,QAAO,EAAE,UAAU,IAAI,OAAO,IAAI;AACjD,SAAO,EAAE,UAAU,IAAI,MAAM,GAAG,KAAK,GAAG,OAAO,IAAI,MAAM,QAAQ,CAAC,EAAE;AACtE;AAGA,SAAS,aAAa,MAA6B;AACjD,QAAM,MAAM,aAAa,IAAI;AAC7B,MAAI,OAAO,QAAQ,YAAY,QAAQ,KAAM,QAAO,CAAC;AACrD,QAAM,QAAQ;AAEd,QAAM,UAAU,MAAM;AACtB,MAAI,OAAO,YAAY,YAAY,YAAY,KAAM,QAAO,CAAC;AAG7D,QAAM,KAAK,iBAAiB,MAAM,aAAa,SAAS,KAAK,YAAY,IAAI;AAG7E,QAAM,YAAY,SAAS,QAAQ,IAAI,CAAC;AAExC,QAAM,MAAqB,CAAC;AAC5B,aAAW,CAAC,UAAU,KAAK,KAAK,OAAO,QAAQ,OAAkC,GAAG;AAClF,QAAI,OAAO,UAAU,YAAY,UAAU,KAAM;AACjD,UAAM,aAAa;AAEnB,UAAM,QAAQ,aAAa,WAAW,KAAK;AAC3C,UAAM,YAAY,aAAa,WAAW,MAAM;AAChD,UAAM,aAAa,aAAa,WAAW,WAAW;AACtD,UAAM,SAAS,aAAa,WAAW,MAAM;AAC7C,UAAM,YAAY,aAAa,WAAW,SAAS;AAGnD,QAAI,QAAQ,YAAY,aAAa,SAAS,cAAc,EAAG;AAE/D,UAAM,EAAE,UAAU,MAAM,IAAI,cAAc,QAAQ;AAElD,UAAM,SAAS,YAAY;AAC3B,WAAO,QAAQ;AACf,WAAO,SAAS;AAChB,WAAO,YAAY;AACnB,WAAO,aAAa;AACpB,WAAO,YAAY;AAEnB,QAAI,KAAK;AAAA,MACP,YAAY;AAAA,MACZ,SAAS;AAAA,MACT,YAAY;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA,MACA,cAAc;AAAA,MACd,YAAY;AAAA,IACd,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAGA,IAAM,YAAyB;AAAA,EAC7B,YAAY;AAAA,EACZ,MAAM;AAAA,EACN,MAAM,KAAK,EAAE,QAAQ,GAAiD;AACpE,UAAM,OAAO,kBAAkB,WAAW;AAC1C,QAAI,SAAS,OAAW,QAAO,CAAC;AAGhC,UAAM,QAAQ,UAAU,MAAM,CAAC,SAAS,SAAS,oBAAoB;AAErE,UAAM,UAAyB,CAAC;AAChC,eAAW,QAAQ,OAAO;AACxB,YAAM,OAAO,aAAa,IAAI;AAC9B,iBAAW,OAAO,MAAM;AACtB,YAAI,YAAY,UAAa,IAAI,KAAK,QAAS;AAC/C,gBAAQ,KAAK,GAAG;AAAA,MAClB;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACF;AAEA,IAAO,cAAQ;","names":[]}
|