@ken-jo/agent-connector 0.4.0 → 0.4.6
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/README.md +9 -9
- package/dist/{action-PLZW5BGX.js → action-EV63GAPY.js} +11 -10
- package/dist/{action-PLZW5BGX.js.map → action-EV63GAPY.js.map} +1 -1
- package/dist/amazon-q-COAL3764.js +276 -0
- package/dist/amazon-q-COAL3764.js.map +1 -0
- package/dist/amp-XJQ4TDAU.js +666 -0
- package/dist/amp-XJQ4TDAU.js.map +1 -0
- package/dist/{antigravity-ANDKF3K7.js → antigravity-AMKKKHS4.js} +4 -4
- package/dist/{antigravity-cli-LLRPDDOT.js → antigravity-cli-XERXEH5W.js} +4 -4
- package/dist/{chunk-MAH6QQTO.js → chunk-2X4EH2D7.js} +5 -4
- package/dist/chunk-2X4EH2D7.js.map +1 -0
- package/dist/{chunk-G3ER4SY5.js → chunk-5G4EPJ4Y.js} +9 -9
- package/dist/chunk-BMD7ANKF.js +237 -0
- package/dist/chunk-BMD7ANKF.js.map +1 -0
- package/dist/{chunk-IW77FFNX.js → chunk-CPLK7GTE.js} +41 -5
- package/dist/chunk-CPLK7GTE.js.map +1 -0
- package/dist/{chunk-ADTHT2FN.js → chunk-DCK5FADX.js} +10 -173
- package/dist/chunk-DCK5FADX.js.map +1 -0
- package/dist/{chunk-J3D5W5T2.js → chunk-EROJDXMW.js} +2 -2
- package/dist/{chunk-22Y24V7O.js → chunk-F5RX62T7.js} +2 -2
- package/dist/chunk-FAHIMJRU.js +177 -0
- package/dist/chunk-FAHIMJRU.js.map +1 -0
- package/dist/{chunk-BHUCB6LY.js → chunk-H67V7DEL.js} +8 -7
- package/dist/{chunk-BHUCB6LY.js.map → chunk-H67V7DEL.js.map} +1 -1
- package/dist/{chunk-BXGFUENQ.js → chunk-I5MLE6S7.js} +14 -1
- package/dist/{chunk-BXGFUENQ.js.map → chunk-I5MLE6S7.js.map} +1 -1
- package/dist/{chunk-LL4OBGRU.js → chunk-LQRAPXS4.js} +3 -3
- package/dist/{chunk-KGJWE6A2.js → chunk-MZF2YCXX.js} +2 -2
- package/dist/{chunk-KGXDYGNJ.js → chunk-QC5A3TFQ.js} +19 -19
- package/dist/{chunk-KGXDYGNJ.js.map → chunk-QC5A3TFQ.js.map} +1 -1
- package/dist/{chunk-CIRDOY2V.js → chunk-QOGMDOUX.js} +3 -3
- package/dist/{chunk-KGGBNKI4.js → chunk-RQPKL62M.js} +144 -21
- package/dist/chunk-RQPKL62M.js.map +1 -0
- package/dist/{chunk-6XHB6BE3.js → chunk-SCVBYSF7.js} +1 -1
- package/dist/{chunk-76FUSVIA.js → chunk-SRVAA2VN.js} +6 -5
- package/dist/chunk-SRVAA2VN.js.map +1 -0
- package/dist/chunk-WZA4CSGJ.js +28 -0
- package/dist/chunk-WZA4CSGJ.js.map +1 -0
- package/dist/{claude-code-MLWS7CW6.js → claude-code-T2LPFNC3.js} +20 -30
- package/dist/claude-code-T2LPFNC3.js.map +1 -0
- package/dist/cli/sdk.js +5 -4
- package/dist/cli/sdk.js.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/cline-WRYMNS7Z.js +442 -0
- package/dist/cline-WRYMNS7Z.js.map +1 -0
- package/dist/{codebuff-SH2S3QAN.js → codebuff-PODYPOOP.js} +130 -5
- package/dist/codebuff-PODYPOOP.js.map +1 -0
- package/dist/{codex-BXA4FIF4.js → codex-O4G7D7KK.js} +61 -13
- package/dist/codex-O4G7D7KK.js.map +1 -0
- package/dist/continue-K43SUHLQ.js +790 -0
- package/dist/continue-K43SUHLQ.js.map +1 -0
- package/dist/{copilot-cli-ROIBTTDT.js → copilot-cli-Q3SSPT4V.js} +70 -12
- package/dist/copilot-cli-Q3SSPT4V.js.map +1 -0
- package/dist/{crush-QLEFLHUC.js → crush-MBEH2R3I.js} +130 -6
- package/dist/crush-MBEH2R3I.js.map +1 -0
- package/dist/{cursor-ASJPWZ4R.js → cursor-TMBXDYR4.js} +119 -19
- package/dist/cursor-TMBXDYR4.js.map +1 -0
- package/dist/{detect-ZIIS55LD.js → detect-AHJIUMBO.js} +5 -4
- package/dist/{detect-ZIIS55LD.js.map → detect-AHJIUMBO.js.map} +1 -1
- package/dist/{doctor-TJUGSQ5C.js → doctor-G5MLCPAB.js} +221 -95
- package/dist/doctor-G5MLCPAB.js.map +1 -0
- package/dist/{droid-NCSS3B5Y.js → droid-JC2NT6S4.js} +135 -13
- package/dist/droid-JC2NT6S4.js.map +1 -0
- package/dist/{gemini-cli-SLVWLXJW.js → gemini-cli-ILR7M5X3.js} +62 -10
- package/dist/gemini-cli-ILR7M5X3.js.map +1 -0
- package/dist/{goose-PBA7KTE5.js → goose-SFO5BBGW.js} +15 -8
- package/dist/goose-SFO5BBGW.js.map +1 -0
- package/dist/{hermes-ONDCECP2.js → hermes-3N7WN4WS.js} +329 -15
- package/dist/hermes-3N7WN4WS.js.map +1 -0
- package/dist/{hook-OU522ABV.js → hook-76JBKTUX.js} +14 -11
- package/dist/hook-76JBKTUX.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -2
- package/dist/{install-UDCBL7HP.js → install-R7252QFH.js} +11 -10
- package/dist/{install-UDCBL7HP.js.map → install-R7252QFH.js.map} +1 -1
- package/dist/{introspect-DuZSPSHB.d.ts → introspect-Cn3MSA4_.d.ts} +1 -1
- package/dist/{jetbrains-copilot-YABZ3HFA.js → jetbrains-copilot-NRZHI5PC.js} +85 -18
- package/dist/jetbrains-copilot-NRZHI5PC.js.map +1 -0
- package/dist/{kilo-F3ZDZKCT.js → kilo-IX4T3OHJ.js} +115 -19
- package/dist/kilo-IX4T3OHJ.js.map +1 -0
- package/dist/{kilo-cli-3HWPWBY4.js → kilo-cli-2AYCXBQD.js} +109 -13
- package/dist/kilo-cli-2AYCXBQD.js.map +1 -0
- package/dist/{kimi-NV72FVAO.js → kimi-2YFK2GBA.js} +87 -25
- package/dist/kimi-2YFK2GBA.js.map +1 -0
- package/dist/{kiro-C5W6AGDR.js → kiro-YL6AWUYG.js} +3 -3
- package/dist/{leaderboard-TIBVONVT.js → leaderboard-V6VWA5ZV.js} +3 -3
- package/dist/{mimo-code-IMM5YM3M.js → mimo-code-FTMGSKMQ.js} +41 -5
- package/dist/mimo-code-FTMGSKMQ.js.map +1 -0
- package/dist/{mux-DSSH4AFS.js → mux-5XZFB44C.js} +156 -6
- package/dist/mux-5XZFB44C.js.map +1 -0
- package/dist/{nemoclaw-3EVNKD3I.js → nemoclaw-CQYXZVQN.js} +4 -4
- package/dist/{omp-Z6FRNDPN.js → omp-2QMEY6HD.js} +138 -18
- package/dist/omp-2QMEY6HD.js.map +1 -0
- package/dist/{openclaw-7G437NT7.js → openclaw-UZC437RW.js} +4 -4
- package/dist/{opencode-Q6KBSAKW.js → opencode-L4BGFP25.js} +87 -27
- package/dist/opencode-L4BGFP25.js.map +1 -0
- package/dist/{package-RMPN57YZ.js → package-DNLQTPNN.js} +8 -7
- package/dist/{package-RMPN57YZ.js.map → package-DNLQTPNN.js.map} +1 -1
- package/dist/{pi-LZT6WWAZ.js → pi-PVVPVWKG.js} +3 -2
- package/dist/{pi-LZT6WWAZ.js.map → pi-PVVPVWKG.js.map} +1 -1
- package/dist/{qwen-code-WQBKRPWJ.js → qwen-code-G4CXKUHR.js} +426 -10
- package/dist/qwen-code-G4CXKUHR.js.map +1 -0
- package/dist/{roo-code-GWSNU3OW.js → roo-code-67TYJIQR.js} +3 -3
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/index.js +9 -8
- package/dist/sdk/index.d.ts +3 -3
- package/dist/sdk/index.js +4 -3
- package/dist/sdk/index.js.map +1 -1
- package/dist/sdk/test.d.ts +2 -2
- package/dist/sdk/test.js +6 -5
- package/dist/sdk/test.js.map +1 -1
- package/dist/{serve-D3GO36UT.js → serve-EOVWYBGZ.js} +11 -10
- package/dist/{serve-D3GO36UT.js.map → serve-EOVWYBGZ.js.map} +1 -1
- package/dist/{status-KOSKCETC.js → status-VTD6XXLW.js} +7 -6
- package/dist/{status-KOSKCETC.js.map → status-VTD6XXLW.js.map} +1 -1
- package/dist/{statusline-ZNTCL5YC.js → statusline-3ET5YPQ5.js} +10 -9
- package/dist/{statusline-ZNTCL5YC.js.map → statusline-3ET5YPQ5.js.map} +1 -1
- package/dist/{telemetry-XIKUUGTQ.js → telemetry-QCTMKDBQ.js} +6 -5
- package/dist/{telemetry-XIKUUGTQ.js.map → telemetry-QCTMKDBQ.js.map} +1 -1
- package/dist/{trae-NWT3TMSZ.js → trae-7CZZGOGI.js} +3 -3
- package/dist/{types-BEKsAium.d.ts → types-_6arHbX9.d.ts} +67 -24
- package/dist/{uninstall-2LBLQVFA.js → uninstall-FL3SH2DT.js} +11 -10
- package/dist/{uninstall-2LBLQVFA.js.map → uninstall-FL3SH2DT.js.map} +1 -1
- package/dist/{upgrade-ZC2S7VRN.js → upgrade-SLFG2FCT.js} +11 -10
- package/dist/{upgrade-ZC2S7VRN.js.map → upgrade-SLFG2FCT.js.map} +1 -1
- package/dist/{usage-E2A4O2CY.js → usage-IRBLVUZM.js} +3 -3
- package/dist/{usage-event-JKMC4QC4.js → usage-event-VFF77WYY.js} +10 -9
- package/dist/{usage-event-JKMC4QC4.js.map → usage-event-VFF77WYY.js.map} +1 -1
- package/dist/{vscode-copilot-ALV45XF6.js → vscode-copilot-MF2CDNMT.js} +23 -10
- package/dist/vscode-copilot-MF2CDNMT.js.map +1 -0
- package/dist/{warp-H6IX4U3J.js → warp-VKG55TAT.js} +55 -4
- package/dist/warp-VKG55TAT.js.map +1 -0
- package/dist/windsurf-FU5G4SHF.js +443 -0
- package/dist/windsurf-FU5G4SHF.js.map +1 -0
- package/dist/{zed-RH34TNSW.js → zed-SFUHL3GS.js} +3 -3
- package/package.json +2 -2
- package/dist/amp-B524U6LO.js +0 -300
- package/dist/amp-B524U6LO.js.map +0 -1
- package/dist/chunk-3PFFTFCU.js +0 -190
- package/dist/chunk-3PFFTFCU.js.map +0 -1
- package/dist/chunk-76FUSVIA.js.map +0 -1
- package/dist/chunk-ADTHT2FN.js.map +0 -1
- package/dist/chunk-IW77FFNX.js.map +0 -1
- package/dist/chunk-KGGBNKI4.js.map +0 -1
- package/dist/chunk-MAH6QQTO.js.map +0 -1
- package/dist/claude-code-MLWS7CW6.js.map +0 -1
- package/dist/codebuff-SH2S3QAN.js.map +0 -1
- package/dist/codex-BXA4FIF4.js.map +0 -1
- package/dist/copilot-cli-ROIBTTDT.js.map +0 -1
- package/dist/crush-QLEFLHUC.js.map +0 -1
- package/dist/cursor-ASJPWZ4R.js.map +0 -1
- package/dist/doctor-TJUGSQ5C.js.map +0 -1
- package/dist/droid-NCSS3B5Y.js.map +0 -1
- package/dist/gemini-cli-SLVWLXJW.js.map +0 -1
- package/dist/goose-PBA7KTE5.js.map +0 -1
- package/dist/hermes-ONDCECP2.js.map +0 -1
- package/dist/hook-OU522ABV.js.map +0 -1
- package/dist/jetbrains-copilot-YABZ3HFA.js.map +0 -1
- package/dist/kilo-F3ZDZKCT.js.map +0 -1
- package/dist/kilo-cli-3HWPWBY4.js.map +0 -1
- package/dist/kimi-NV72FVAO.js.map +0 -1
- package/dist/mimo-code-IMM5YM3M.js.map +0 -1
- package/dist/mux-DSSH4AFS.js.map +0 -1
- package/dist/omp-Z6FRNDPN.js.map +0 -1
- package/dist/opencode-Q6KBSAKW.js.map +0 -1
- package/dist/qwen-code-WQBKRPWJ.js.map +0 -1
- package/dist/vscode-copilot-ALV45XF6.js.map +0 -1
- package/dist/warp-H6IX4U3J.js.map +0 -1
- /package/dist/{antigravity-ANDKF3K7.js.map → antigravity-AMKKKHS4.js.map} +0 -0
- /package/dist/{antigravity-cli-LLRPDDOT.js.map → antigravity-cli-XERXEH5W.js.map} +0 -0
- /package/dist/{chunk-G3ER4SY5.js.map → chunk-5G4EPJ4Y.js.map} +0 -0
- /package/dist/{chunk-J3D5W5T2.js.map → chunk-EROJDXMW.js.map} +0 -0
- /package/dist/{chunk-22Y24V7O.js.map → chunk-F5RX62T7.js.map} +0 -0
- /package/dist/{chunk-LL4OBGRU.js.map → chunk-LQRAPXS4.js.map} +0 -0
- /package/dist/{chunk-KGJWE6A2.js.map → chunk-MZF2YCXX.js.map} +0 -0
- /package/dist/{chunk-CIRDOY2V.js.map → chunk-QOGMDOUX.js.map} +0 -0
- /package/dist/{chunk-6XHB6BE3.js.map → chunk-SCVBYSF7.js.map} +0 -0
- /package/dist/{kiro-C5W6AGDR.js.map → kiro-YL6AWUYG.js.map} +0 -0
- /package/dist/{leaderboard-TIBVONVT.js.map → leaderboard-V6VWA5ZV.js.map} +0 -0
- /package/dist/{nemoclaw-3EVNKD3I.js.map → nemoclaw-CQYXZVQN.js.map} +0 -0
- /package/dist/{openclaw-7G437NT7.js.map → openclaw-UZC437RW.js.map} +0 -0
- /package/dist/{roo-code-GWSNU3OW.js.map → roo-code-67TYJIQR.js.map} +0 -0
- /package/dist/{trae-NWT3TMSZ.js.map → trae-7CZZGOGI.js.map} +0 -0
- /package/dist/{usage-E2A4O2CY.js.map → usage-IRBLVUZM.js.map} +0 -0
- /package/dist/{zed-RH34TNSW.js.map → zed-SFUHL3GS.js.map} +0 -0
|
@@ -6,19 +6,20 @@ import {
|
|
|
6
6
|
fail,
|
|
7
7
|
parseScope,
|
|
8
8
|
print
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-QC5A3TFQ.js";
|
|
10
10
|
import {
|
|
11
11
|
detectInstalledPlatforms
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-EROJDXMW.js";
|
|
13
13
|
import {
|
|
14
14
|
findConnectorConfig,
|
|
15
15
|
listRegisteredConnectors,
|
|
16
16
|
loadConnectorFromPath
|
|
17
|
-
} from "./chunk-
|
|
18
|
-
import "./chunk-
|
|
17
|
+
} from "./chunk-MZF2YCXX.js";
|
|
18
|
+
import "./chunk-DCK5FADX.js";
|
|
19
19
|
import {
|
|
20
20
|
loadAdapter
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-BMD7ANKF.js";
|
|
22
|
+
import "./chunk-FAHIMJRU.js";
|
|
22
23
|
import "./chunk-N6HH7K6P.js";
|
|
23
24
|
import {
|
|
24
25
|
dataRoot,
|
|
@@ -137,4 +138,4 @@ async function run(argv) {
|
|
|
137
138
|
export {
|
|
138
139
|
run
|
|
139
140
|
};
|
|
140
|
-
//# sourceMappingURL=status-
|
|
141
|
+
//# sourceMappingURL=status-VTD6XXLW.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/commands/status.ts"],"sourcesContent":["/**\n * cli/commands/status — a light, glanceable install-state summary.\n *\n * There is NO MCP standard for \"which connectors are installed into which host\n * configs on this machine\" — distribution/wire standards (server.json, MCPB,\n * the lifecycle) cover publishing + the protocol, not local install state. So\n * `status` is purely agent-connector infrastructure, and we design it for the\n * everyday question it answers in one line per platform:\n *\n * \"which of my connectors are present on which hosts?\"\n *\n * It REUSES detect (host enumeration) + the adapters' own config-path resolvers\n * (a read-only presence check) — NO new adapter SPI methods. Unlike `doctor`\n * (deep health checks, non-zero exit on failure) and `doctor --probe` (a live\n * protocol probe that FAILs on a dead server), `status` ALWAYS exits 0: it\n * describes, it never gates. A connector being absent is informational.\n */\n\nimport { parseArgs } from \"node:util\";\nimport { readFileSync } from \"node:fs\";\n\nimport type { InstallScope, PlatformId, ResolvedConnector } from \"../../core/types.js\";\nimport type { InstallContext } from \"../../adapters/spi.js\";\nimport { detectInstalledPlatforms } from \"../../adapters/detect.js\";\nimport { loadAdapter } from \"../../adapters/registry.js\";\nimport {\n findConnectorConfig,\n listRegisteredConnectors,\n loadConnectorFromPath,\n} from \"../../core/load-connector.js\";\nimport { marketplaceEvidence } from \"../../core/marketplace-state.js\";\nimport { dataRoot, homeBinPath } from \"../../core/paths.js\";\nimport { fail, parseScope, print } from \"../app.js\";\n\n/**\n * Resolve which connector(s) status reports on: an explicit --connector path or\n * a local config first, else every connector registered under the data-root\n * (what is actually installed). Empty array when none — status still lists the\n * detected platforms.\n */\nasync function resolveConnectors(\n connectorPath: string | undefined,\n projectDir: string,\n): Promise<ResolvedConnector[]> {\n const configPath = connectorPath ?? findConnectorConfig(projectDir);\n if (configPath) {\n try {\n const { connector } = await loadConnectorFromPath(configPath);\n return [connector];\n } catch {\n /* fall through to the registry */\n }\n }\n return listRegisteredConnectors();\n}\n\nfunction buildContext(\n connector: ResolvedConnector,\n id: PlatformId,\n scope: InstallScope,\n projectDir: string,\n): InstallContext {\n return {\n connector,\n scope: connector.platforms[id]?.scope ?? scope,\n projectDir,\n homeBinPath: homeBinPath(),\n dataRoot: dataRoot(),\n dryRun: true,\n };\n}\n\n/** Read-only: does the file at `path` mention `needle`? Missing/unreadable → false. */\nfunction fileMentions(path: string, needle: string): boolean {\n try {\n return readFileSync(path, \"utf8\").includes(needle);\n } catch {\n return false;\n }\n}\n\ninterface ConnStatus {\n id: string;\n serverPresent: boolean;\n hooksPresent: boolean;\n /**\n * Delivery method actually present on this host: `direct` (managed entries in\n * the host config), `marketplace` (the host's own plugin state / our install\n * record), `both` (the double-install invariant is VIOLATED — doctor FAILs\n * it), or null when absent.\n */\n method: \"direct\" | \"marketplace\" | \"both\" | null;\n}\ninterface StatusRow {\n platform: PlatformId;\n scope: InstallScope;\n configPath: string;\n connectors: ConnStatus[];\n}\n\nexport async function run(argv: string[]): Promise<number> {\n const { values } = parseArgs({\n args: argv,\n options: {\n scope: { type: \"string\", default: \"user\" },\n connector: { type: \"string\" },\n project: { type: \"string\" },\n json: { type: \"boolean\", default: false },\n },\n allowPositionals: false,\n });\n\n const projectDir = values.project ?? process.cwd();\n const scope = parseScope(values.scope);\n if (scope == null) return fail(`invalid --scope \"${values.scope}\" (use user|project)`);\n\n const connectors = await resolveConnectors(values.connector, projectDir);\n const detected = await detectInstalledPlatforms(projectDir);\n\n const rows: StatusRow[] = [];\n for (const p of detected) {\n const adapter = await loadAdapter(p.id);\n if (!adapter) continue;\n const connStatuses: ConnStatus[] = connectors.map((connector) => {\n const ctx = buildContext(connector, p.id, scope, projectDir);\n let serverPath = \"\";\n let hookPath = \"\";\n try {\n serverPath = adapter.getServerConfigPath(ctx);\n } catch {\n /* adapter has no server config path */\n }\n try {\n hookPath = adapter.getHookConfigPath(ctx);\n } catch {\n /* adapter has no hook config path */\n }\n const serverPresent = serverPath\n ? fileMentions(serverPath, connector.id)\n : false;\n const hooksPresent = hookPath ? fileMentions(hookPath, connector.id) : false;\n const direct = serverPresent || hooksPresent;\n const viaMarketplace = marketplaceEvidence(connector.id, p.id) != null;\n return {\n id: connector.id,\n serverPresent,\n hooksPresent,\n method: direct && viaMarketplace\n ? (\"both\" as const)\n : direct\n ? (\"direct\" as const)\n : viaMarketplace\n ? (\"marketplace\" as const)\n : null,\n };\n });\n rows.push({\n platform: p.id,\n scope: p.scope,\n configPath: p.configPath,\n connectors: connStatuses,\n });\n }\n\n if (values.json) {\n print(JSON.stringify(rows, null, 2));\n return 0;\n }\n\n if (rows.length === 0) {\n print(\"status: no agent platforms detected.\");\n return 0;\n }\n if (connectors.length === 0) {\n print(\"status: no connectors found (pass --connector <path> or install one).\\n\");\n }\n\n for (const r of rows) {\n print(`${r.platform} [${r.scope}] ${r.configPath}`);\n if (r.connectors.length === 0) {\n print(\" (no connectors to check)\");\n } else {\n for (const c of r.connectors) {\n const mark = c.method != null ? \"[installed]\" : \"[absent ]\";\n const server = c.serverPresent ? \"server ✓\" : \"server ·\";\n const hooks = c.hooksPresent ? \"hooks ✓\" : \"hooks ·\";\n // `both(!)` flags a violated one-method-per-host invariant — doctor's\n // duplicate-registration check FAILs it with the fix.\n const method =\n c.method == null ? \"\" : c.method === \"both\" ? \" (both!)\" : ` (${c.method})`;\n print(` ${mark} ${c.id} ${server} ${hooks}${method}`);\n }\n }\n print(\"\");\n }\n\n // Always 0: status is descriptive (what is installed where), never a gate —\n // that contrast with doctor (non-zero on FAIL) is the reason it exists.\n return 0;\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/cli/commands/status.ts"],"sourcesContent":["/**\n * cli/commands/status — a light, glanceable install-state summary.\n *\n * There is NO MCP standard for \"which connectors are installed into which host\n * configs on this machine\" — distribution/wire standards (server.json, MCPB,\n * the lifecycle) cover publishing + the protocol, not local install state. So\n * `status` is purely agent-connector infrastructure, and we design it for the\n * everyday question it answers in one line per platform:\n *\n * \"which of my connectors are present on which hosts?\"\n *\n * It REUSES detect (host enumeration) + the adapters' own config-path resolvers\n * (a read-only presence check) — NO new adapter SPI methods. Unlike `doctor`\n * (deep health checks, non-zero exit on failure) and `doctor --probe` (a live\n * protocol probe that FAILs on a dead server), `status` ALWAYS exits 0: it\n * describes, it never gates. A connector being absent is informational.\n */\n\nimport { parseArgs } from \"node:util\";\nimport { readFileSync } from \"node:fs\";\n\nimport type { InstallScope, PlatformId, ResolvedConnector } from \"../../core/types.js\";\nimport type { InstallContext } from \"../../adapters/spi.js\";\nimport { detectInstalledPlatforms } from \"../../adapters/detect.js\";\nimport { loadAdapter } from \"../../adapters/registry.js\";\nimport {\n findConnectorConfig,\n listRegisteredConnectors,\n loadConnectorFromPath,\n} from \"../../core/load-connector.js\";\nimport { marketplaceEvidence } from \"../../core/marketplace-state.js\";\nimport { dataRoot, homeBinPath } from \"../../core/paths.js\";\nimport { fail, parseScope, print } from \"../app.js\";\n\n/**\n * Resolve which connector(s) status reports on: an explicit --connector path or\n * a local config first, else every connector registered under the data-root\n * (what is actually installed). Empty array when none — status still lists the\n * detected platforms.\n */\nasync function resolveConnectors(\n connectorPath: string | undefined,\n projectDir: string,\n): Promise<ResolvedConnector[]> {\n const configPath = connectorPath ?? findConnectorConfig(projectDir);\n if (configPath) {\n try {\n const { connector } = await loadConnectorFromPath(configPath);\n return [connector];\n } catch {\n /* fall through to the registry */\n }\n }\n return listRegisteredConnectors();\n}\n\nfunction buildContext(\n connector: ResolvedConnector,\n id: PlatformId,\n scope: InstallScope,\n projectDir: string,\n): InstallContext {\n return {\n connector,\n scope: connector.platforms[id]?.scope ?? scope,\n projectDir,\n homeBinPath: homeBinPath(),\n dataRoot: dataRoot(),\n dryRun: true,\n };\n}\n\n/** Read-only: does the file at `path` mention `needle`? Missing/unreadable → false. */\nfunction fileMentions(path: string, needle: string): boolean {\n try {\n return readFileSync(path, \"utf8\").includes(needle);\n } catch {\n return false;\n }\n}\n\ninterface ConnStatus {\n id: string;\n serverPresent: boolean;\n hooksPresent: boolean;\n /**\n * Delivery method actually present on this host: `direct` (managed entries in\n * the host config), `marketplace` (the host's own plugin state / our install\n * record), `both` (the double-install invariant is VIOLATED — doctor FAILs\n * it), or null when absent.\n */\n method: \"direct\" | \"marketplace\" | \"both\" | null;\n}\ninterface StatusRow {\n platform: PlatformId;\n scope: InstallScope;\n configPath: string;\n connectors: ConnStatus[];\n}\n\nexport async function run(argv: string[]): Promise<number> {\n const { values } = parseArgs({\n args: argv,\n options: {\n scope: { type: \"string\", default: \"user\" },\n connector: { type: \"string\" },\n project: { type: \"string\" },\n json: { type: \"boolean\", default: false },\n },\n allowPositionals: false,\n });\n\n const projectDir = values.project ?? process.cwd();\n const scope = parseScope(values.scope);\n if (scope == null) return fail(`invalid --scope \"${values.scope}\" (use user|project)`);\n\n const connectors = await resolveConnectors(values.connector, projectDir);\n const detected = await detectInstalledPlatforms(projectDir);\n\n const rows: StatusRow[] = [];\n for (const p of detected) {\n const adapter = await loadAdapter(p.id);\n if (!adapter) continue;\n const connStatuses: ConnStatus[] = connectors.map((connector) => {\n const ctx = buildContext(connector, p.id, scope, projectDir);\n let serverPath = \"\";\n let hookPath = \"\";\n try {\n serverPath = adapter.getServerConfigPath(ctx);\n } catch {\n /* adapter has no server config path */\n }\n try {\n hookPath = adapter.getHookConfigPath(ctx);\n } catch {\n /* adapter has no hook config path */\n }\n const serverPresent = serverPath\n ? fileMentions(serverPath, connector.id)\n : false;\n const hooksPresent = hookPath ? fileMentions(hookPath, connector.id) : false;\n const direct = serverPresent || hooksPresent;\n const viaMarketplace = marketplaceEvidence(connector.id, p.id) != null;\n return {\n id: connector.id,\n serverPresent,\n hooksPresent,\n method: direct && viaMarketplace\n ? (\"both\" as const)\n : direct\n ? (\"direct\" as const)\n : viaMarketplace\n ? (\"marketplace\" as const)\n : null,\n };\n });\n rows.push({\n platform: p.id,\n scope: p.scope,\n configPath: p.configPath,\n connectors: connStatuses,\n });\n }\n\n if (values.json) {\n print(JSON.stringify(rows, null, 2));\n return 0;\n }\n\n if (rows.length === 0) {\n print(\"status: no agent platforms detected.\");\n return 0;\n }\n if (connectors.length === 0) {\n print(\"status: no connectors found (pass --connector <path> or install one).\\n\");\n }\n\n for (const r of rows) {\n print(`${r.platform} [${r.scope}] ${r.configPath}`);\n if (r.connectors.length === 0) {\n print(\" (no connectors to check)\");\n } else {\n for (const c of r.connectors) {\n const mark = c.method != null ? \"[installed]\" : \"[absent ]\";\n const server = c.serverPresent ? \"server ✓\" : \"server ·\";\n const hooks = c.hooksPresent ? \"hooks ✓\" : \"hooks ·\";\n // `both(!)` flags a violated one-method-per-host invariant — doctor's\n // duplicate-registration check FAILs it with the fix.\n const method =\n c.method == null ? \"\" : c.method === \"both\" ? \" (both!)\" : ` (${c.method})`;\n print(` ${mark} ${c.id} ${server} ${hooks}${method}`);\n }\n }\n print(\"\");\n }\n\n // Always 0: status is descriptive (what is installed where), never a gate —\n // that contrast with doctor (non-zero on FAIL) is the reason it exists.\n return 0;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
runStatusline
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-H67V7DEL.js";
|
|
5
5
|
import "./chunk-OP4KBXUO.js";
|
|
6
|
-
import "./chunk-
|
|
7
|
-
import "./chunk-
|
|
8
|
-
import "./chunk-
|
|
6
|
+
import "./chunk-F5RX62T7.js";
|
|
7
|
+
import "./chunk-EROJDXMW.js";
|
|
8
|
+
import "./chunk-QOGMDOUX.js";
|
|
9
9
|
import "./chunk-BCHWFTV4.js";
|
|
10
10
|
import "./chunk-KHO5WNTP.js";
|
|
11
|
-
import "./chunk-
|
|
12
|
-
import "./chunk-
|
|
13
|
-
import "./chunk-
|
|
14
|
-
import "./chunk-
|
|
11
|
+
import "./chunk-MZF2YCXX.js";
|
|
12
|
+
import "./chunk-DCK5FADX.js";
|
|
13
|
+
import "./chunk-BMD7ANKF.js";
|
|
14
|
+
import "./chunk-FAHIMJRU.js";
|
|
15
|
+
import "./chunk-I5MLE6S7.js";
|
|
15
16
|
import "./chunk-N6HH7K6P.js";
|
|
16
17
|
import "./chunk-TRQKHP7D.js";
|
|
17
18
|
|
|
@@ -56,4 +57,4 @@ async function run(argv) {
|
|
|
56
57
|
export {
|
|
57
58
|
run
|
|
58
59
|
};
|
|
59
|
-
//# sourceMappingURL=statusline-
|
|
60
|
+
//# sourceMappingURL=statusline-3ET5YPQ5.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/commands/statusline.ts"],"sourcesContent":["/**\n * cli/commands/statusline — the universal statusline (HUD) entrypoint.\n *\n * agent-connector statusline <platform> --connector <id>\n *\n * A statusline-supporting host points its status line config at the single stable\n * home binary (via core/spawn.buildHomeBinStatuslineCommand). This command reads\n * the ENTIRE host payload from stdin, dispatches through runStatusline, writes the\n * rendered line to stdout, and exits with the adapter's exit code.\n *\n * FAIL-SAFE is the runtime's contract: a status line must NEVER wedge the host or\n * spew an error into the status bar. runStatusline never rejects (always exits 0\n * with at most a rendered line), and even a malformed invocation here degrades to\n * exit 0 with no output — never the strict `fail()` non-zero used by other\n * commands.\n */\n\nimport { parseArgs } from \"node:util\";\n\nimport { runStatusline } from \"../../runtime/index.js\";\n\n/** Read all of a readable stream to a UTF-8 string. */\nasync function readAll(stream: NodeJS.ReadStream): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of stream) {\n chunks.push(typeof chunk === \"string\" ? Buffer.from(chunk) : chunk);\n }\n return Buffer.concat(chunks).toString(\"utf8\");\n}\n\nexport async function run(argv: string[]): Promise<number> {\n // strict:false so a future flag from a newer install can never make this throw\n // and surface a non-zero exit into the host's status bar.\n let platformId = \"\";\n let connectorId = \"\";\n try {\n const { values, positionals } = parseArgs({\n args: argv,\n options: { connector: { type: \"string\" } },\n allowPositionals: true,\n strict: false,\n });\n platformId = positionals[0] ?? \"\";\n connectorId = typeof values.connector === \"string\" ? values.connector : \"\";\n } catch {\n // A malformed invocation must still fail-safe (render nothing, exit 0).\n return 0;\n }\n\n // Drain stdin regardless — a host expects the command to consume its payload.\n const stdin = await readAll(process.stdin).catch(() => \"\");\n\n // Missing platform/connector → render nothing, exit 0 (never a non-zero exit).\n if (platformId === \"\" || connectorId === \"\") {\n return 0;\n }\n\n const reply = await runStatusline({ platformId, connectorId, stdin });\n if (reply.stdout !== undefined && reply.stdout !== \"\") {\n process.stdout.write(reply.stdout);\n }\n if (reply.stderr !== undefined && reply.stderr !== \"\") {\n process.stderr.write(reply.stderr.endsWith(\"\\n\") ? reply.stderr : `${reply.stderr}\\n`);\n }\n return reply.exitCode;\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/cli/commands/statusline.ts"],"sourcesContent":["/**\n * cli/commands/statusline — the universal statusline (HUD) entrypoint.\n *\n * agent-connector statusline <platform> --connector <id>\n *\n * A statusline-supporting host points its status line config at the single stable\n * home binary (via core/spawn.buildHomeBinStatuslineCommand). This command reads\n * the ENTIRE host payload from stdin, dispatches through runStatusline, writes the\n * rendered line to stdout, and exits with the adapter's exit code.\n *\n * FAIL-SAFE is the runtime's contract: a status line must NEVER wedge the host or\n * spew an error into the status bar. runStatusline never rejects (always exits 0\n * with at most a rendered line), and even a malformed invocation here degrades to\n * exit 0 with no output — never the strict `fail()` non-zero used by other\n * commands.\n */\n\nimport { parseArgs } from \"node:util\";\n\nimport { runStatusline } from \"../../runtime/index.js\";\n\n/** Read all of a readable stream to a UTF-8 string. */\nasync function readAll(stream: NodeJS.ReadStream): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of stream) {\n chunks.push(typeof chunk === \"string\" ? Buffer.from(chunk) : chunk);\n }\n return Buffer.concat(chunks).toString(\"utf8\");\n}\n\nexport async function run(argv: string[]): Promise<number> {\n // strict:false so a future flag from a newer install can never make this throw\n // and surface a non-zero exit into the host's status bar.\n let platformId = \"\";\n let connectorId = \"\";\n try {\n const { values, positionals } = parseArgs({\n args: argv,\n options: { connector: { type: \"string\" } },\n allowPositionals: true,\n strict: false,\n });\n platformId = positionals[0] ?? \"\";\n connectorId = typeof values.connector === \"string\" ? values.connector : \"\";\n } catch {\n // A malformed invocation must still fail-safe (render nothing, exit 0).\n return 0;\n }\n\n // Drain stdin regardless — a host expects the command to consume its payload.\n const stdin = await readAll(process.stdin).catch(() => \"\");\n\n // Missing platform/connector → render nothing, exit 0 (never a non-zero exit).\n if (platformId === \"\" || connectorId === \"\") {\n return 0;\n }\n\n const reply = await runStatusline({ platformId, connectorId, stdin });\n if (reply.stdout !== undefined && reply.stdout !== \"\") {\n process.stdout.write(reply.stdout);\n }\n if (reply.stderr !== undefined && reply.stderr !== \"\") {\n process.stderr.write(reply.stderr.endsWith(\"\\n\") ? reply.stderr : `${reply.stderr}\\n`);\n }\n return reply.exitCode;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAiBA,SAAS,iBAAiB;AAK1B,eAAe,QAAQ,QAA4C;AACjE,QAAM,SAAmB,CAAC;AAC1B,mBAAiB,SAAS,QAAQ;AAChC,WAAO,KAAK,OAAO,UAAU,WAAW,OAAO,KAAK,KAAK,IAAI,KAAK;AAAA,EACpE;AACA,SAAO,OAAO,OAAO,MAAM,EAAE,SAAS,MAAM;AAC9C;AAEA,eAAsB,IAAI,MAAiC;AAGzD,MAAI,aAAa;AACjB,MAAI,cAAc;AAClB,MAAI;AACF,UAAM,EAAE,QAAQ,YAAY,IAAI,UAAU;AAAA,MACxC,MAAM;AAAA,MACN,SAAS,EAAE,WAAW,EAAE,MAAM,SAAS,EAAE;AAAA,MACzC,kBAAkB;AAAA,MAClB,QAAQ;AAAA,IACV,CAAC;AACD,iBAAa,YAAY,CAAC,KAAK;AAC/B,kBAAc,OAAO,OAAO,cAAc,WAAW,OAAO,YAAY;AAAA,EAC1E,QAAQ;AAEN,WAAO;AAAA,EACT;AAGA,QAAM,QAAQ,MAAM,QAAQ,QAAQ,KAAK,EAAE,MAAM,MAAM,EAAE;AAGzD,MAAI,eAAe,MAAM,gBAAgB,IAAI;AAC3C,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,MAAM,cAAc,EAAE,YAAY,aAAa,MAAM,CAAC;AACpE,MAAI,MAAM,WAAW,UAAa,MAAM,WAAW,IAAI;AACrD,YAAQ,OAAO,MAAM,MAAM,MAAM;AAAA,EACnC;AACA,MAAI,MAAM,WAAW,UAAa,MAAM,WAAW,IAAI;AACrD,YAAQ,OAAO,MAAM,MAAM,OAAO,SAAS,IAAI,IAAI,MAAM,SAAS,GAAG,MAAM,MAAM;AAAA,CAAI;AAAA,EACvF;AACA,SAAO,MAAM;AACf;","names":[]}
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
import {
|
|
13
13
|
fail,
|
|
14
14
|
print
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-QC5A3TFQ.js";
|
|
16
16
|
import {
|
|
17
17
|
openStore
|
|
18
18
|
} from "./chunk-BCHWFTV4.js";
|
|
@@ -21,9 +21,10 @@ import {
|
|
|
21
21
|
listRegisteredConnectors,
|
|
22
22
|
loadRegisteredConnector,
|
|
23
23
|
readRegisteredMeta
|
|
24
|
-
} from "./chunk-
|
|
25
|
-
import "./chunk-
|
|
26
|
-
import "./chunk-
|
|
24
|
+
} from "./chunk-MZF2YCXX.js";
|
|
25
|
+
import "./chunk-DCK5FADX.js";
|
|
26
|
+
import "./chunk-BMD7ANKF.js";
|
|
27
|
+
import "./chunk-FAHIMJRU.js";
|
|
27
28
|
import "./chunk-N6HH7K6P.js";
|
|
28
29
|
import "./chunk-TRQKHP7D.js";
|
|
29
30
|
|
|
@@ -348,4 +349,4 @@ export {
|
|
|
348
349
|
parseSince,
|
|
349
350
|
run
|
|
350
351
|
};
|
|
351
|
-
//# sourceMappingURL=telemetry-
|
|
352
|
+
//# sourceMappingURL=telemetry-QCTMKDBQ.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/commands/telemetry.ts","../src/telemetry/report.ts"],"sourcesContent":["/**\n * cli/commands/telemetry — inspect the local per-tool token telemetry store.\n *\n * Subcommands:\n * report --by tool|session|project (default tool) --since 7d|24h|… --connector <id> [--json]\n * → summarize(openStore({}), …) + formatReport (the aligned table).\n * export --format csv|json (default json) --out <file> [--since/--connector …]\n * → toCSV / toJSONExport of the raw records.\n *\n * Telemetry rows are aggregate counts only (never raw arguments/results).\n */\n\nimport { writeFileSync } from \"node:fs\";\nimport { parseArgs } from \"node:util\";\n\nimport type { QueryFilter } from \"../../telemetry/types.js\";\nimport type { RollupDimension } from \"../../telemetry/report.js\";\nimport { openStore } from \"../../telemetry/store.js\";\nimport { summarize, toCSV, toJSONExport } from \"../../telemetry/report.js\";\nimport {\n formatMcpLeaderboard,\n formatSurfaceLeaderboard,\n formatToolLeaderboard,\n isScopeFilter,\n mcpLeaderboard,\n SCOPE_FILTER_VALUES,\n surfaceLeaderboard,\n toolLeaderboard,\n type LeaderboardOptions,\n type ScopeFilter,\n type SurfaceLeaderboardOptions,\n} from \"../../telemetry/leaderboard.js\";\nimport {\n connectorFromMeta,\n listRegisteredConnectors,\n loadRegisteredConnector,\n readRegisteredMeta,\n} from \"../../core/load-connector.js\";\nimport type { ResolvedConnector } from \"../../core/types.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 an empty input and null for a malformed one.\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\n/** Build a QueryFilter from the shared --since / --connector flags. */\nfunction buildFilter(\n since: string | undefined,\n connectorId: string | undefined,\n): QueryFilter | null {\n const sinceMs = parseSince(since);\n if (sinceMs === null) return null;\n const filter: QueryFilter = {};\n if (sinceMs !== undefined) filter.sinceMs = sinceMs;\n if (connectorId && connectorId.trim() !== \"\") filter.connectorId = connectorId;\n return filter;\n}\n\nfunction runReport(argv: string[]): number {\n const { values } = parseArgs({\n args: argv,\n options: {\n by: { type: \"string\", default: \"tool\" },\n since: { type: \"string\" },\n connector: { type: \"string\" },\n json: { type: \"boolean\", default: false },\n },\n allowPositionals: false,\n });\n\n const by = values.by;\n if (by !== \"tool\" && by !== \"session\" && by !== \"project\") {\n return fail(`invalid --by \"${by}\" (use tool|session|project)`);\n }\n const dimension: RollupDimension = by;\n\n const filter = buildFilter(values.since, values.connector);\n if (filter === null) {\n return fail(`invalid --since \"${values.since}\" (use forms like 30s, 15m, 24h, 7d)`);\n }\n\n const store = openStore({});\n try {\n const { rows, text } = summarize(store, { by: dimension, filter });\n if (values.json) {\n print(JSON.stringify(rows, null, 2));\n } else {\n print(text);\n }\n } finally {\n store.close();\n }\n return 0;\n}\n\nfunction runExport(argv: string[]): number {\n const { values } = parseArgs({\n args: argv,\n options: {\n format: { type: \"string\", default: \"json\" },\n out: { type: \"string\" },\n since: { type: \"string\" },\n connector: { type: \"string\" },\n },\n allowPositionals: false,\n });\n\n const format = values.format;\n if (format !== \"csv\" && format !== \"json\") {\n return fail(`invalid --format \"${format}\" (use csv|json)`);\n }\n\n const filter = buildFilter(values.since, values.connector);\n if (filter === null) {\n return fail(`invalid --since \"${values.since}\" (use forms like 30s, 15m, 24h, 7d)`);\n }\n\n const store = openStore({});\n let serialized: string;\n try {\n const records = store.query(filter);\n serialized = format === \"csv\" ? toCSV(records) : toJSONExport(records);\n } finally {\n store.close();\n }\n\n if (values.out && values.out.trim() !== \"\") {\n writeFileSync(values.out, serialized, \"utf8\");\n print(`wrote ${format.toUpperCase()} export → ${values.out}`);\n } else {\n print(serialized);\n }\n return 0;\n}\n\n/**\n * `telemetry leaderboard` — rank the per-MCP telemetry by connector (--by mcp,\n * the default and signature \"which MCP server costs the most\" metric), by tool\n * (--by tool), or by developer-axis surface (--by surface — the FIVE surfaces:\n * server + hook runtime rows plus static command/skill/subagent footprints).\n * Honors --since / --connector and the scope slice (--scope).\n */\nasync function runLeaderboard(argv: string[]): Promise<number> {\n const { values } = parseArgs({\n args: argv,\n options: {\n by: { type: \"string\", default: \"mcp\" },\n since: { type: \"string\" },\n connector: { type: \"string\" },\n scope: { type: \"string\" },\n json: { type: \"boolean\", default: false },\n },\n allowPositionals: false,\n });\n\n const by = values.by;\n if (by !== \"mcp\" && by !== \"tool\" && by !== \"surface\") {\n return fail(`invalid --by \"${by}\" (use mcp|tool|surface)`);\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 const opts: LeaderboardOptions = {};\n if (sinceMs !== undefined) opts.sinceMs = sinceMs;\n if (values.connector && values.connector.trim() !== \"\") {\n opts.connectorId = values.connector.trim();\n }\n if (scope !== undefined) opts.scope = scope;\n\n if (by === \"tool\") {\n const rows = toolLeaderboard(opts);\n print(values.json ? JSON.stringify(rows, null, 2) : formatToolLeaderboard(rows));\n } else if (by === \"surface\") {\n // The per-surface view folds the STATIC command/skill/subagent footprints of\n // the registered connector(s) into the runtime server/hook rows.\n const connectorId = values.connector?.trim();\n const surfaceOpts: SurfaceLeaderboardOptions = {\n ...opts,\n connectors: await gatherConnectors(connectorId),\n };\n const rows = surfaceLeaderboard(surfaceOpts);\n print(values.json ? JSON.stringify(rows, null, 2) : formatSurfaceLeaderboard(rows));\n } else {\n const rows = mcpLeaderboard(opts);\n print(values.json ? JSON.stringify(rows, null, 2) : formatMcpLeaderboard(rows));\n }\n return 0;\n}\n\n/**\n * Gather the registered connector(s) whose STATIC command/skill/subagent\n * footprints feed the per-surface view. When `connectorId` is given, prefer the\n * LIVE module (freshest content) and fall back to the persisted meta record;\n * otherwise enumerate every registered connector from its meta. Best-effort: a\n * connector that cannot be loaded is skipped (the surface view still renders the\n * runtime rows it can read from the store).\n */\nasync function gatherConnectors(\n connectorId: string | undefined,\n): Promise<ResolvedConnector[]> {\n if (connectorId !== undefined && connectorId !== \"\") {\n try {\n return [await loadRegisteredConnector(connectorId)];\n } catch {\n const meta = readRegisteredMetaSafe(connectorId);\n return meta ? [connectorFromMeta(meta)] : [];\n }\n }\n return listRegisteredConnectors();\n}\n\n/** readRegisteredMeta wrapped so a missing/corrupt record never throws here. */\nfunction readRegisteredMetaSafe(id: string): ReturnType<typeof readRegisteredMeta> {\n try {\n return readRegisteredMeta(id);\n } catch {\n return null;\n }\n}\n\nexport async function run(argv: string[]): Promise<number> {\n const sub = argv[0];\n const rest = argv.slice(1);\n\n switch (sub) {\n case \"report\":\n return runReport(rest);\n case \"export\":\n return runExport(rest);\n case \"leaderboard\":\n return await runLeaderboard(rest);\n case undefined:\n case \"--help\":\n case \"-h\":\n print(\"usage: agent-connector telemetry <report|export|leaderboard> [flags]\");\n print(\" report --by tool|session|project --since 7d --connector <id> --json\");\n print(\" export --format csv|json --out <file> --since 7d --connector <id>\");\n print(\" leaderboard --by mcp|tool|surface --since 7d --connector <id> --scope <slice> --json\");\n return sub === undefined ? 1 : 0;\n default:\n return fail(`unknown telemetry subcommand \"${sub}\" (use report|export|leaderboard)`);\n }\n}\n","/**\n * telemetry/report — CLI-facing formatting for telemetry rollups and exports.\n *\n * Pure functions: take store output (rollup rows / raw records) and render text,\n * CSV, or JSON. No IO except {@link summarize}, which reads through a passed-in\n * {@link TelemetryStore}. Confidence is surfaced verbatim so heuristic/approx\n * numbers are never mistaken for exact host-reported usage.\n */\n\nimport type { TelemetryStore } from \"./types.js\";\nimport type {\n ConfidenceSource,\n QueryFilter,\n RollupRow,\n ToolEventRecord,\n} from \"./types.js\";\n\n/** Grouping dimension, mirrored from {@link TelemetryStore.rollup}. */\nexport type RollupDimension = \"tool\" | \"session\" | \"project\";\n\n/** Human label for the leading KEY column, per grouping dimension. */\nconst KEY_HEADER: Record<RollupDimension, string> = {\n tool: \"TOOL\",\n session: \"SESSION\",\n project: \"PROJECT\",\n};\n\n/**\n * Sources whose counts are estimates (vs. real / host-reported numbers).\n * `tokenizer-calibrated` is still an estimate — an approximation nudged toward\n * truth by a sampled Anthropic count_tokens factor — so it belongs here too.\n */\nconst ESTIMATE_SOURCES: ReadonlySet<ConfidenceSource> = new Set<ConfidenceSource>([\n \"heuristic\",\n \"tokenizer-approx\",\n \"tokenizer-calibrated\",\n]);\n\n/** Compact, fixed-width integer formatting with thousands separators. */\nfunction fmtInt(n: number): string {\n return n.toLocaleString(\"en-US\");\n}\n\n/** Pad a cell to a column width (right-pad text, used for left-aligned cols). */\nfunction padRight(s: string, width: number): string {\n return s.length >= width ? s : s + \" \".repeat(width - s.length);\n}\n\n/** Pad a cell to a column width (left-pad, used for right-aligned numbers). */\nfunction padLeft(s: string, width: number): string {\n return s.length >= width ? s : \" \".repeat(width - s.length) + s;\n}\n\n/**\n * Render an aligned text table of rollup rows, sorted by total tokens desc, with\n * a TOTAL footer and a short legend noting which confidence labels are estimates.\n */\nexport function formatReport(rows: RollupRow[], by: RollupDimension): string {\n const keyHeader = KEY_HEADER[by];\n const headers = [keyHeader, \"CALLS\", \"IN\", \"OUT\", \"TOTAL\", \"CONFIDENCE\"];\n\n const sorted = [...rows].sort((a, b) => b.totalTokens - a.totalTokens);\n\n // Build the data matrix (string cells) first so we can measure widths.\n const dataRows = sorted.map((r) => [\n r.key,\n fmtInt(r.calls),\n fmtInt(r.inputTokens),\n fmtInt(r.outputTokens),\n fmtInt(r.totalTokens),\n r.confidence,\n ]);\n\n // Totals footer. Confidence is the worst (least-confident) across all rows.\n const totals = sorted.reduce(\n (acc, r) => {\n acc.calls += r.calls;\n acc.inputTokens += r.inputTokens;\n acc.outputTokens += r.outputTokens;\n acc.totalTokens += r.totalTokens;\n return acc;\n },\n { calls: 0, inputTokens: 0, outputTokens: 0, totalTokens: 0 },\n );\n const totalRow = [\n \"TOTAL\",\n fmtInt(totals.calls),\n fmtInt(totals.inputTokens),\n fmtInt(totals.outputTokens),\n fmtInt(totals.totalTokens),\n \"\",\n ];\n\n // Column widths: max over header, every data cell, and the totals row.\n const widths = headers.map((h, col) => {\n let w = h.length;\n for (const row of dataRows) w = Math.max(w, (row[col] ?? \"\").length);\n w = Math.max(w, (totalRow[col] ?? \"\").length);\n return w;\n });\n\n // Column 0 (KEY) is left-aligned; numeric/label columns are right-aligned.\n const renderRow = (cells: string[]): string =>\n cells\n .map((c, col) =>\n col === 0\n ? padRight(c, widths[col] ?? 0)\n : padLeft(c, widths[col] ?? 0),\n )\n .join(\" \")\n .trimEnd();\n\n const ruleWidth = widths.reduce((a, b) => a + b, 0) + 2 * (widths.length - 1);\n const rule = \"-\".repeat(ruleWidth);\n\n const lines: string[] = [];\n lines.push(renderRow(headers));\n lines.push(rule);\n if (dataRows.length === 0) {\n lines.push(\"(no telemetry recorded)\");\n } else {\n for (const row of dataRows) lines.push(renderRow(row));\n }\n lines.push(rule);\n lines.push(renderRow(totalRow));\n\n // Legend — honest labeling of which confidence values are estimates.\n const hasEstimate = sorted.some((r) => ESTIMATE_SOURCES.has(r.confidence));\n if (hasEstimate) {\n lines.push(\"\");\n lines.push(\n \"note: heuristic and tokenizer-approx token counts are estimates, \" +\n \"not exact host-reported usage.\",\n );\n if (sorted.some((r) => r.confidence === \"tokenizer-calibrated\")) {\n lines.push(\n \"note: tokenizer-calibrated = local approx adjusted by a sampled \" +\n \"Anthropic count_tokens factor (opt-in; content sampled off-box only \" +\n \"when AGENT_CONNECTOR_CALIBRATE=anthropic).\",\n );\n }\n }\n\n return lines.join(\"\\n\");\n}\n\n/** Ordered columns for {@link toCSV}, matching the {@link ToolEventRecord} shape. */\nconst CSV_COLUMNS = [\n \"id\",\n \"ts\",\n \"connectorId\",\n \"toolName\",\n \"scope\",\n \"hostPlatform\",\n \"sessionId\",\n \"projectKey\",\n \"projectDir\",\n \"inputTokens\",\n \"outputTokens\",\n \"confidenceSource\",\n \"isError\",\n // installScope / launchMethod mirror the JSON export so the scope dimension is\n // not silently dropped from CSV; absent on a record → an empty cell.\n \"installScope\",\n \"launchMethod\",\n] as const satisfies ReadonlyArray<keyof ToolEventRecord>;\n\n/** RFC-4180-ish CSV escaping: quote when the cell holds a comma, quote, or newline. */\nfunction csvCell(value: unknown): string {\n // An absent field (optional column like installScope/launchMethod) renders as\n // an empty cell rather than the literal \"undefined\" — the JSON export omits\n // the key entirely, so the CSV should likewise carry no value.\n if (value === undefined || value === null) return \"\";\n const s = String(value);\n if (/[\",\\n\\r]/.test(s)) {\n return `\"${s.replace(/\"/g, '\"\"')}\"`;\n }\n return s;\n}\n\n/** Serialize raw records to CSV (header + one line per record, CRLF-terminated). */\nexport function toCSV(records: ToolEventRecord[]): string {\n const lines: string[] = [];\n lines.push(CSV_COLUMNS.join(\",\"));\n for (const record of records) {\n lines.push(CSV_COLUMNS.map((col) => csvCell(record[col])).join(\",\"));\n }\n return lines.join(\"\\r\\n\");\n}\n\n/** Serialize raw records to a pretty-printed JSON array string. */\nexport function toJSONExport(records: ToolEventRecord[]): string {\n return JSON.stringify(records, null, 2);\n}\n\n/** Options for {@link summarize}. */\nexport interface SummarizeOptions {\n /** Grouping dimension. Default \"tool\". */\n by?: RollupDimension;\n /** Query filter forwarded to the store. Default: no filter (all records). */\n filter?: QueryFilter;\n}\n\n/**\n * Roll up a store and render it in one call. Returns the structured rows (for\n * machine use) alongside the formatted text table (for the CLI).\n */\nexport function summarize(\n store: TelemetryStore,\n opts?: SummarizeOptions,\n): { rows: RollupRow[]; text: string } {\n const by = opts?.by ?? \"tool\";\n const filter = opts?.filter ?? {};\n const rows = store.rollup(by, filter);\n return { rows, text: formatReport(rows, by) };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/cli/commands/telemetry.ts","../src/telemetry/report.ts"],"sourcesContent":["/**\n * cli/commands/telemetry — inspect the local per-tool token telemetry store.\n *\n * Subcommands:\n * report --by tool|session|project (default tool) --since 7d|24h|… --connector <id> [--json]\n * → summarize(openStore({}), …) + formatReport (the aligned table).\n * export --format csv|json (default json) --out <file> [--since/--connector …]\n * → toCSV / toJSONExport of the raw records.\n *\n * Telemetry rows are aggregate counts only (never raw arguments/results).\n */\n\nimport { writeFileSync } from \"node:fs\";\nimport { parseArgs } from \"node:util\";\n\nimport type { QueryFilter } from \"../../telemetry/types.js\";\nimport type { RollupDimension } from \"../../telemetry/report.js\";\nimport { openStore } from \"../../telemetry/store.js\";\nimport { summarize, toCSV, toJSONExport } from \"../../telemetry/report.js\";\nimport {\n formatMcpLeaderboard,\n formatSurfaceLeaderboard,\n formatToolLeaderboard,\n isScopeFilter,\n mcpLeaderboard,\n SCOPE_FILTER_VALUES,\n surfaceLeaderboard,\n toolLeaderboard,\n type LeaderboardOptions,\n type ScopeFilter,\n type SurfaceLeaderboardOptions,\n} from \"../../telemetry/leaderboard.js\";\nimport {\n connectorFromMeta,\n listRegisteredConnectors,\n loadRegisteredConnector,\n readRegisteredMeta,\n} from \"../../core/load-connector.js\";\nimport type { ResolvedConnector } from \"../../core/types.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 an empty input and null for a malformed one.\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\n/** Build a QueryFilter from the shared --since / --connector flags. */\nfunction buildFilter(\n since: string | undefined,\n connectorId: string | undefined,\n): QueryFilter | null {\n const sinceMs = parseSince(since);\n if (sinceMs === null) return null;\n const filter: QueryFilter = {};\n if (sinceMs !== undefined) filter.sinceMs = sinceMs;\n if (connectorId && connectorId.trim() !== \"\") filter.connectorId = connectorId;\n return filter;\n}\n\nfunction runReport(argv: string[]): number {\n const { values } = parseArgs({\n args: argv,\n options: {\n by: { type: \"string\", default: \"tool\" },\n since: { type: \"string\" },\n connector: { type: \"string\" },\n json: { type: \"boolean\", default: false },\n },\n allowPositionals: false,\n });\n\n const by = values.by;\n if (by !== \"tool\" && by !== \"session\" && by !== \"project\") {\n return fail(`invalid --by \"${by}\" (use tool|session|project)`);\n }\n const dimension: RollupDimension = by;\n\n const filter = buildFilter(values.since, values.connector);\n if (filter === null) {\n return fail(`invalid --since \"${values.since}\" (use forms like 30s, 15m, 24h, 7d)`);\n }\n\n const store = openStore({});\n try {\n const { rows, text } = summarize(store, { by: dimension, filter });\n if (values.json) {\n print(JSON.stringify(rows, null, 2));\n } else {\n print(text);\n }\n } finally {\n store.close();\n }\n return 0;\n}\n\nfunction runExport(argv: string[]): number {\n const { values } = parseArgs({\n args: argv,\n options: {\n format: { type: \"string\", default: \"json\" },\n out: { type: \"string\" },\n since: { type: \"string\" },\n connector: { type: \"string\" },\n },\n allowPositionals: false,\n });\n\n const format = values.format;\n if (format !== \"csv\" && format !== \"json\") {\n return fail(`invalid --format \"${format}\" (use csv|json)`);\n }\n\n const filter = buildFilter(values.since, values.connector);\n if (filter === null) {\n return fail(`invalid --since \"${values.since}\" (use forms like 30s, 15m, 24h, 7d)`);\n }\n\n const store = openStore({});\n let serialized: string;\n try {\n const records = store.query(filter);\n serialized = format === \"csv\" ? toCSV(records) : toJSONExport(records);\n } finally {\n store.close();\n }\n\n if (values.out && values.out.trim() !== \"\") {\n writeFileSync(values.out, serialized, \"utf8\");\n print(`wrote ${format.toUpperCase()} export → ${values.out}`);\n } else {\n print(serialized);\n }\n return 0;\n}\n\n/**\n * `telemetry leaderboard` — rank the per-MCP telemetry by connector (--by mcp,\n * the default and signature \"which MCP server costs the most\" metric), by tool\n * (--by tool), or by developer-axis surface (--by surface — the FIVE surfaces:\n * server + hook runtime rows plus static command/skill/subagent footprints).\n * Honors --since / --connector and the scope slice (--scope).\n */\nasync function runLeaderboard(argv: string[]): Promise<number> {\n const { values } = parseArgs({\n args: argv,\n options: {\n by: { type: \"string\", default: \"mcp\" },\n since: { type: \"string\" },\n connector: { type: \"string\" },\n scope: { type: \"string\" },\n json: { type: \"boolean\", default: false },\n },\n allowPositionals: false,\n });\n\n const by = values.by;\n if (by !== \"mcp\" && by !== \"tool\" && by !== \"surface\") {\n return fail(`invalid --by \"${by}\" (use mcp|tool|surface)`);\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 const opts: LeaderboardOptions = {};\n if (sinceMs !== undefined) opts.sinceMs = sinceMs;\n if (values.connector && values.connector.trim() !== \"\") {\n opts.connectorId = values.connector.trim();\n }\n if (scope !== undefined) opts.scope = scope;\n\n if (by === \"tool\") {\n const rows = toolLeaderboard(opts);\n print(values.json ? JSON.stringify(rows, null, 2) : formatToolLeaderboard(rows));\n } else if (by === \"surface\") {\n // The per-surface view folds the STATIC command/skill/subagent footprints of\n // the registered connector(s) into the runtime server/hook rows.\n const connectorId = values.connector?.trim();\n const surfaceOpts: SurfaceLeaderboardOptions = {\n ...opts,\n connectors: await gatherConnectors(connectorId),\n };\n const rows = surfaceLeaderboard(surfaceOpts);\n print(values.json ? JSON.stringify(rows, null, 2) : formatSurfaceLeaderboard(rows));\n } else {\n const rows = mcpLeaderboard(opts);\n print(values.json ? JSON.stringify(rows, null, 2) : formatMcpLeaderboard(rows));\n }\n return 0;\n}\n\n/**\n * Gather the registered connector(s) whose STATIC command/skill/subagent\n * footprints feed the per-surface view. When `connectorId` is given, prefer the\n * LIVE module (freshest content) and fall back to the persisted meta record;\n * otherwise enumerate every registered connector from its meta. Best-effort: a\n * connector that cannot be loaded is skipped (the surface view still renders the\n * runtime rows it can read from the store).\n */\nasync function gatherConnectors(\n connectorId: string | undefined,\n): Promise<ResolvedConnector[]> {\n if (connectorId !== undefined && connectorId !== \"\") {\n try {\n return [await loadRegisteredConnector(connectorId)];\n } catch {\n const meta = readRegisteredMetaSafe(connectorId);\n return meta ? [connectorFromMeta(meta)] : [];\n }\n }\n return listRegisteredConnectors();\n}\n\n/** readRegisteredMeta wrapped so a missing/corrupt record never throws here. */\nfunction readRegisteredMetaSafe(id: string): ReturnType<typeof readRegisteredMeta> {\n try {\n return readRegisteredMeta(id);\n } catch {\n return null;\n }\n}\n\nexport async function run(argv: string[]): Promise<number> {\n const sub = argv[0];\n const rest = argv.slice(1);\n\n switch (sub) {\n case \"report\":\n return runReport(rest);\n case \"export\":\n return runExport(rest);\n case \"leaderboard\":\n return await runLeaderboard(rest);\n case undefined:\n case \"--help\":\n case \"-h\":\n print(\"usage: agent-connector telemetry <report|export|leaderboard> [flags]\");\n print(\" report --by tool|session|project --since 7d --connector <id> --json\");\n print(\" export --format csv|json --out <file> --since 7d --connector <id>\");\n print(\" leaderboard --by mcp|tool|surface --since 7d --connector <id> --scope <slice> --json\");\n return sub === undefined ? 1 : 0;\n default:\n return fail(`unknown telemetry subcommand \"${sub}\" (use report|export|leaderboard)`);\n }\n}\n","/**\n * telemetry/report — CLI-facing formatting for telemetry rollups and exports.\n *\n * Pure functions: take store output (rollup rows / raw records) and render text,\n * CSV, or JSON. No IO except {@link summarize}, which reads through a passed-in\n * {@link TelemetryStore}. Confidence is surfaced verbatim so heuristic/approx\n * numbers are never mistaken for exact host-reported usage.\n */\n\nimport type { TelemetryStore } from \"./types.js\";\nimport type {\n ConfidenceSource,\n QueryFilter,\n RollupRow,\n ToolEventRecord,\n} from \"./types.js\";\n\n/** Grouping dimension, mirrored from {@link TelemetryStore.rollup}. */\nexport type RollupDimension = \"tool\" | \"session\" | \"project\";\n\n/** Human label for the leading KEY column, per grouping dimension. */\nconst KEY_HEADER: Record<RollupDimension, string> = {\n tool: \"TOOL\",\n session: \"SESSION\",\n project: \"PROJECT\",\n};\n\n/**\n * Sources whose counts are estimates (vs. real / host-reported numbers).\n * `tokenizer-calibrated` is still an estimate — an approximation nudged toward\n * truth by a sampled Anthropic count_tokens factor — so it belongs here too.\n */\nconst ESTIMATE_SOURCES: ReadonlySet<ConfidenceSource> = new Set<ConfidenceSource>([\n \"heuristic\",\n \"tokenizer-approx\",\n \"tokenizer-calibrated\",\n]);\n\n/** Compact, fixed-width integer formatting with thousands separators. */\nfunction fmtInt(n: number): string {\n return n.toLocaleString(\"en-US\");\n}\n\n/** Pad a cell to a column width (right-pad text, used for left-aligned cols). */\nfunction padRight(s: string, width: number): string {\n return s.length >= width ? s : s + \" \".repeat(width - s.length);\n}\n\n/** Pad a cell to a column width (left-pad, used for right-aligned numbers). */\nfunction padLeft(s: string, width: number): string {\n return s.length >= width ? s : \" \".repeat(width - s.length) + s;\n}\n\n/**\n * Render an aligned text table of rollup rows, sorted by total tokens desc, with\n * a TOTAL footer and a short legend noting which confidence labels are estimates.\n */\nexport function formatReport(rows: RollupRow[], by: RollupDimension): string {\n const keyHeader = KEY_HEADER[by];\n const headers = [keyHeader, \"CALLS\", \"IN\", \"OUT\", \"TOTAL\", \"CONFIDENCE\"];\n\n const sorted = [...rows].sort((a, b) => b.totalTokens - a.totalTokens);\n\n // Build the data matrix (string cells) first so we can measure widths.\n const dataRows = sorted.map((r) => [\n r.key,\n fmtInt(r.calls),\n fmtInt(r.inputTokens),\n fmtInt(r.outputTokens),\n fmtInt(r.totalTokens),\n r.confidence,\n ]);\n\n // Totals footer. Confidence is the worst (least-confident) across all rows.\n const totals = sorted.reduce(\n (acc, r) => {\n acc.calls += r.calls;\n acc.inputTokens += r.inputTokens;\n acc.outputTokens += r.outputTokens;\n acc.totalTokens += r.totalTokens;\n return acc;\n },\n { calls: 0, inputTokens: 0, outputTokens: 0, totalTokens: 0 },\n );\n const totalRow = [\n \"TOTAL\",\n fmtInt(totals.calls),\n fmtInt(totals.inputTokens),\n fmtInt(totals.outputTokens),\n fmtInt(totals.totalTokens),\n \"\",\n ];\n\n // Column widths: max over header, every data cell, and the totals row.\n const widths = headers.map((h, col) => {\n let w = h.length;\n for (const row of dataRows) w = Math.max(w, (row[col] ?? \"\").length);\n w = Math.max(w, (totalRow[col] ?? \"\").length);\n return w;\n });\n\n // Column 0 (KEY) is left-aligned; numeric/label columns are right-aligned.\n const renderRow = (cells: string[]): string =>\n cells\n .map((c, col) =>\n col === 0\n ? padRight(c, widths[col] ?? 0)\n : padLeft(c, widths[col] ?? 0),\n )\n .join(\" \")\n .trimEnd();\n\n const ruleWidth = widths.reduce((a, b) => a + b, 0) + 2 * (widths.length - 1);\n const rule = \"-\".repeat(ruleWidth);\n\n const lines: string[] = [];\n lines.push(renderRow(headers));\n lines.push(rule);\n if (dataRows.length === 0) {\n lines.push(\"(no telemetry recorded)\");\n } else {\n for (const row of dataRows) lines.push(renderRow(row));\n }\n lines.push(rule);\n lines.push(renderRow(totalRow));\n\n // Legend — honest labeling of which confidence values are estimates.\n const hasEstimate = sorted.some((r) => ESTIMATE_SOURCES.has(r.confidence));\n if (hasEstimate) {\n lines.push(\"\");\n lines.push(\n \"note: heuristic and tokenizer-approx token counts are estimates, \" +\n \"not exact host-reported usage.\",\n );\n if (sorted.some((r) => r.confidence === \"tokenizer-calibrated\")) {\n lines.push(\n \"note: tokenizer-calibrated = local approx adjusted by a sampled \" +\n \"Anthropic count_tokens factor (opt-in; content sampled off-box only \" +\n \"when AGENT_CONNECTOR_CALIBRATE=anthropic).\",\n );\n }\n }\n\n return lines.join(\"\\n\");\n}\n\n/** Ordered columns for {@link toCSV}, matching the {@link ToolEventRecord} shape. */\nconst CSV_COLUMNS = [\n \"id\",\n \"ts\",\n \"connectorId\",\n \"toolName\",\n \"scope\",\n \"hostPlatform\",\n \"sessionId\",\n \"projectKey\",\n \"projectDir\",\n \"inputTokens\",\n \"outputTokens\",\n \"confidenceSource\",\n \"isError\",\n // installScope / launchMethod mirror the JSON export so the scope dimension is\n // not silently dropped from CSV; absent on a record → an empty cell.\n \"installScope\",\n \"launchMethod\",\n] as const satisfies ReadonlyArray<keyof ToolEventRecord>;\n\n/** RFC-4180-ish CSV escaping: quote when the cell holds a comma, quote, or newline. */\nfunction csvCell(value: unknown): string {\n // An absent field (optional column like installScope/launchMethod) renders as\n // an empty cell rather than the literal \"undefined\" — the JSON export omits\n // the key entirely, so the CSV should likewise carry no value.\n if (value === undefined || value === null) return \"\";\n const s = String(value);\n if (/[\",\\n\\r]/.test(s)) {\n return `\"${s.replace(/\"/g, '\"\"')}\"`;\n }\n return s;\n}\n\n/** Serialize raw records to CSV (header + one line per record, CRLF-terminated). */\nexport function toCSV(records: ToolEventRecord[]): string {\n const lines: string[] = [];\n lines.push(CSV_COLUMNS.join(\",\"));\n for (const record of records) {\n lines.push(CSV_COLUMNS.map((col) => csvCell(record[col])).join(\",\"));\n }\n return lines.join(\"\\r\\n\");\n}\n\n/** Serialize raw records to a pretty-printed JSON array string. */\nexport function toJSONExport(records: ToolEventRecord[]): string {\n return JSON.stringify(records, null, 2);\n}\n\n/** Options for {@link summarize}. */\nexport interface SummarizeOptions {\n /** Grouping dimension. Default \"tool\". */\n by?: RollupDimension;\n /** Query filter forwarded to the store. Default: no filter (all records). */\n filter?: QueryFilter;\n}\n\n/**\n * Roll up a store and render it in one call. Returns the structured rows (for\n * machine use) alongside the formatted text table (for the CLI).\n */\nexport function summarize(\n store: TelemetryStore,\n opts?: SummarizeOptions,\n): { rows: RollupRow[]; text: string } {\n const by = opts?.by ?? \"tool\";\n const filter = opts?.filter ?? {};\n const rows = store.rollup(by, filter);\n return { rows, text: formatReport(rows, by) };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -4,13 +4,13 @@ import {
|
|
|
4
4
|
} from "./chunk-DBQMX75U.js";
|
|
5
5
|
import {
|
|
6
6
|
BaseAdapter
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-CPLK7GTE.js";
|
|
8
8
|
import "./chunk-7L6ITC4T.js";
|
|
9
9
|
import {
|
|
10
10
|
buildServeWrapperCommand,
|
|
11
11
|
isHomeBinHookCommand,
|
|
12
12
|
shouldWrapForTelemetry
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-I5MLE6S7.js";
|
|
14
14
|
import "./chunk-N6HH7K6P.js";
|
|
15
15
|
import "./chunk-TRQKHP7D.js";
|
|
16
16
|
|
|
@@ -302,4 +302,4 @@ export {
|
|
|
302
302
|
adapter,
|
|
303
303
|
trae_default as default
|
|
304
304
|
};
|
|
305
|
-
//# sourceMappingURL=trae-
|
|
305
|
+
//# sourceMappingURL=trae-7CZZGOGI.js.map
|
|
@@ -23,22 +23,23 @@
|
|
|
23
23
|
* exposes no writable MCP config to install into. The registry-completeness test
|
|
24
24
|
* (tests/adapters/registry-completeness.test.ts) allowlists it for this reason.
|
|
25
25
|
*/
|
|
26
|
-
type PlatformId = "claude-code" | "codex" | "cursor" | "vscode-copilot" | "jetbrains-copilot" | "copilot-cli" | "gemini-cli" | "opencode" | "mimo-code" | "kilo" | "kilo-cli" | "warp" | "hermes" | "nemoclaw" | "openclaw" | "zed" | "antigravity" | "antigravity-cli" | "kiro" | "qwen-code" | "kimi" | "pi" | "omp" | "droid" | "roo-code" | "trae" | "amp" | "codebuff" | "mux" | "crush" | "goose" | "synthetic" | "unknown";
|
|
26
|
+
type PlatformId = "claude-code" | "codex" | "cursor" | "vscode-copilot" | "jetbrains-copilot" | "copilot-cli" | "gemini-cli" | "opencode" | "mimo-code" | "kilo" | "kilo-cli" | "warp" | "hermes" | "nemoclaw" | "openclaw" | "zed" | "antigravity" | "antigravity-cli" | "kiro" | "qwen-code" | "kimi" | "pi" | "omp" | "droid" | "roo-code" | "cline" | "trae" | "amp" | "codebuff" | "mux" | "crush" | "goose" | "amazon-q" | "continue" | "windsurf" | "synthetic" | "unknown";
|
|
27
27
|
/**
|
|
28
28
|
* Hook I/O paradigm — the deepest cross-platform divergence (report §4).
|
|
29
29
|
* Canonical shipped sets (keep in sync with src/adapters/registry.ts — this
|
|
30
30
|
* comment once drifted and seeded a docs-wide misclassification):
|
|
31
|
-
* - "json-stdio" (
|
|
31
|
+
* - "json-stdio" (17): host pipes JSON to a command on stdin, reads
|
|
32
32
|
* JSON/exit-code back — Claude Code, Codex, Cursor, VS Code/JetBrains
|
|
33
33
|
* Copilot, Copilot CLI, Gemini CLI, Qwen, Kiro, Kimi, Crush, Goose, Hermes,
|
|
34
|
-
* Droid (Factory), Antigravity (+ the agy CLI). One universal
|
|
35
|
-
* binary handles all of them.
|
|
36
|
-
* - "ts-plugin" (
|
|
34
|
+
* Droid (Factory), Antigravity (+ the agy CLI), Continue. One universal
|
|
35
|
+
* entrypoint binary handles all of them.
|
|
36
|
+
* - "ts-plugin" (8): host loads a JS/TS module exporting lifecycle functions
|
|
37
37
|
* — OpenCode, MiMoCode (an OpenCode fork), Kilo CLI, Kilo, OMP, OpenClaw,
|
|
38
|
-
* NemoClaw (an OpenClaw wrapper/fork). Framework
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
38
|
+
* NemoClaw (an OpenClaw wrapper/fork), Amp (.amp/plugins/*.ts). Framework
|
|
39
|
+
* generates the module.
|
|
40
|
+
* - "mcp-only" (10): no hook layer at all — Warp, Roo Code, Cline, Trae, Zed,
|
|
41
|
+
* Codebuff, Mux, Pi, Amazon Q, Windsurf. Only the MCP server (or skills
|
|
42
|
+
* surface) is installed; hooks are reported unavailable.
|
|
42
43
|
*/
|
|
43
44
|
type HookParadigm = "json-stdio" | "ts-plugin" | "mcp-only";
|
|
44
45
|
/**
|
|
@@ -88,12 +89,14 @@ interface ServerDef {
|
|
|
88
89
|
/**
|
|
89
90
|
* Canonical, platform-agnostic lifecycle event names.
|
|
90
91
|
*
|
|
91
|
-
* The
|
|
92
|
-
* SubagentStop
|
|
93
|
-
* native analog mark them unsupported in capabilities and the install
|
|
94
|
-
* a skip-warn — an event is never silently dropped.
|
|
92
|
+
* The newer additions (PermissionRequest / PostToolUseFailure / SubagentStart /
|
|
93
|
+
* SubagentStop and the trailing PostCompact) have cross-host analogs; hosts
|
|
94
|
+
* without a native analog mark them unsupported in capabilities and the install
|
|
95
|
+
* reports a skip-warn — an event is never silently dropped. PostCompact is
|
|
96
|
+
* observational only (the post-compaction sibling of PreCompact; cannot
|
|
97
|
+
* block/modify) and is appended LAST to keep the canonical order append-only.
|
|
95
98
|
*/
|
|
96
|
-
type HookEventName = "SessionStart" | "SessionEnd" | "UserPromptSubmit" | "PreToolUse" | "PostToolUse" | "PreCompact" | "Stop" | "Notification" | "PermissionRequest" | "PostToolUseFailure" | "SubagentStart" | "SubagentStop";
|
|
99
|
+
type HookEventName = "SessionStart" | "SessionEnd" | "UserPromptSubmit" | "PreToolUse" | "PostToolUse" | "PreCompact" | "Stop" | "Notification" | "PermissionRequest" | "PostToolUseFailure" | "SubagentStart" | "SubagentStop" | "PostCompact";
|
|
97
100
|
interface BaseEvent {
|
|
98
101
|
/** Which host produced this event (from runtime detection). */
|
|
99
102
|
hostPlatform: PlatformId;
|
|
@@ -139,6 +142,17 @@ interface UserPromptSubmitEvent extends BaseEvent {
|
|
|
139
142
|
interface PreCompactEvent extends BaseEvent {
|
|
140
143
|
trigger?: "auto" | "manual";
|
|
141
144
|
}
|
|
145
|
+
/**
|
|
146
|
+
* PostCompact — the post-compaction sibling of {@link PreCompactEvent}. Fires
|
|
147
|
+
* AFTER the host finishes compacting/summarizing the conversation. Observational
|
|
148
|
+
* only: it cannot block or modify (compaction already happened), exactly like
|
|
149
|
+
* PreCompact's reply contract. The single normalized field is `trigger`
|
|
150
|
+
* (manual|auto); everything else rides on `raw`. Codex is the verified firing
|
|
151
|
+
* host (its hook system ships PreCompact AND PostCompact).
|
|
152
|
+
*/
|
|
153
|
+
interface PostCompactEvent extends BaseEvent {
|
|
154
|
+
trigger?: "auto" | "manual";
|
|
155
|
+
}
|
|
142
156
|
interface StopEvent extends BaseEvent {
|
|
143
157
|
/** True when the stop hook itself was triggered during a previous stop hook. */
|
|
144
158
|
stopHookActive?: boolean;
|
|
@@ -225,6 +239,7 @@ interface EventPayloadMap {
|
|
|
225
239
|
PostToolUseFailure: PostToolUseFailureEvent;
|
|
226
240
|
SubagentStart: SubagentStartEvent;
|
|
227
241
|
SubagentStop: SubagentStopEvent;
|
|
242
|
+
PostCompact: PostCompactEvent;
|
|
228
243
|
}
|
|
229
244
|
/**
|
|
230
245
|
* Normalized hook response. A handler returns a subset of these; the adapter
|
|
@@ -301,6 +316,7 @@ interface HooksConfig {
|
|
|
301
316
|
PostToolUseFailure?: HookDefinition<"PostToolUseFailure">;
|
|
302
317
|
SubagentStart?: HookDefinition<"SubagentStart">;
|
|
303
318
|
SubagentStop?: HookDefinition<"SubagentStop">;
|
|
319
|
+
PostCompact?: HookDefinition<"PostCompact">;
|
|
304
320
|
}
|
|
305
321
|
/**
|
|
306
322
|
* The payload a NATIVE (passthrough) hook handler receives. Unlike the
|
|
@@ -431,6 +447,14 @@ interface PlatformCapabilities {
|
|
|
431
447
|
postToolUseFailure?: boolean;
|
|
432
448
|
subagentStart?: boolean;
|
|
433
449
|
subagentStop?: boolean;
|
|
450
|
+
/**
|
|
451
|
+
* PostCompact — observational post-compaction event (the sibling of
|
|
452
|
+
* preCompact). OPTIONAL, read as `?? false`: a host that leaves it unset does
|
|
453
|
+
* not fire PostCompact natively and a declared hook for it warn-skips at
|
|
454
|
+
* install. v1: codex only (its hook system ships both PreCompact and
|
|
455
|
+
* PostCompact).
|
|
456
|
+
*/
|
|
457
|
+
postCompact?: boolean;
|
|
434
458
|
/** Can a PreToolUse hook rewrite tool arguments? */
|
|
435
459
|
canModifyArgs: boolean;
|
|
436
460
|
/** Can a PostToolUse hook rewrite tool output? */
|
|
@@ -487,14 +511,15 @@ interface PlatformCapabilities {
|
|
|
487
511
|
supportsStatusline?: boolean;
|
|
488
512
|
/**
|
|
489
513
|
* Action-surface support — can this adapter EMIT a host affordance (slash
|
|
490
|
-
* command /
|
|
514
|
+
* command / palette workflow / exec-file) bound to the universal
|
|
491
515
|
* `<homeBin> action <host> <actionId> --connector <id>` verb? OPTIONAL, read
|
|
492
|
-
* as `?? false` (supportsStatusline precedent).
|
|
493
|
-
*
|
|
494
|
-
*
|
|
495
|
-
*
|
|
496
|
-
*
|
|
497
|
-
*
|
|
516
|
+
* as `?? false` (supportsStatusline precedent). The dispatch BACKBONE shipped
|
|
517
|
+
* first; the EMITTERS now ship on the hosts with a verifiable target: droid
|
|
518
|
+
* (executable command file), hermes (quick_commands exec slash command), warp
|
|
519
|
+
* (palette workflow — pastes the command for the user to run). Hosts whose
|
|
520
|
+
* slash commands are prompt templates that cannot run a shell verb, or whose
|
|
521
|
+
* plugin APIs expose no command registration, leave this unset — every such
|
|
522
|
+
* adapter's BaseAdapter install/uninstall defaults honestly skip-warn.
|
|
498
523
|
*/
|
|
499
524
|
supportsActions?: boolean;
|
|
500
525
|
}
|
|
@@ -556,7 +581,7 @@ interface SubagentDef {
|
|
|
556
581
|
* writes it as a MANAGED BLOCK (marker-fenced, hash-stamped,
|
|
557
582
|
* uninstall-reversible — see core/managed-block.ts) into the memory/rules file
|
|
558
583
|
* that host actually reads: AGENTS.md wherever the host supports the agents.md
|
|
559
|
-
* standard (29/
|
|
584
|
+
* standard (29/35 hosts), the host's own file (CLAUDE.md / GEMINI.md)
|
|
560
585
|
* otherwise. CONTENT-ONLY like commands/skills/subagents: no runtime dispatch,
|
|
561
586
|
* no telemetry wrapping — a pure, surgical file edit that never touches bytes
|
|
562
587
|
* outside its own marker pair.
|
|
@@ -655,6 +680,16 @@ interface StatuslineContext extends HostCtx {
|
|
|
655
680
|
maxTokens?: number;
|
|
656
681
|
percent?: number;
|
|
657
682
|
};
|
|
683
|
+
/**
|
|
684
|
+
* THIS connector's OWN recorded MCP telemetry usage (token sums + call count),
|
|
685
|
+
* pre-computed by the runtime so render() can read it synchronously. ALL-TIME
|
|
686
|
+
* for the connector (every stored row) — NOT the host context-window (see
|
|
687
|
+
* `context`) and NOT session-scoped. When pre-computed it is always a real
|
|
688
|
+
* summary (zeros when there's no telemetry or it's switched off, never
|
|
689
|
+
* undefined); it is undefined only for a context that does not pre-compute it.
|
|
690
|
+
* render() can still `await ctx.telemetry?.()` to fetch a live or custom slice.
|
|
691
|
+
*/
|
|
692
|
+
usage?: TelemetryUsageSummary;
|
|
658
693
|
/** Path to the session transcript, when the host reports one. */
|
|
659
694
|
transcriptPath?: string;
|
|
660
695
|
/** The host's verbatim status payload (escape hatch). */
|
|
@@ -817,13 +852,13 @@ interface PlatformOverride {
|
|
|
817
852
|
* VERBATIM. This immediately covers all 30 current Claude Code events (e.g.
|
|
818
853
|
* TaskCreated, TaskCompleted, TeammateIdle, StopFailure, MessageDisplay,
|
|
819
854
|
* WorktreeCreate/WorktreeRemove, Elicitation/ElicitationResult,
|
|
820
|
-
* InstructionsLoaded, ConfigChange, FileChanged,
|
|
855
|
+
* InstructionsLoaded, ConfigChange, FileChanged, CwdChanged, …) and any
|
|
821
856
|
* future event a host adds — with zero agent-connector releases.
|
|
822
857
|
*
|
|
823
858
|
* Scoping: per-platform-keyed, so a declaration only ever applies to the
|
|
824
859
|
* platform it is declared under. Adapters without
|
|
825
860
|
* {@link PlatformCapabilities.supportsNativeHooks} report a skip-warn
|
|
826
|
-
* ChangeRecord at install (never silent). Declaring one of the
|
|
861
|
+
* ChangeRecord at install (never silent). Declaring one of the 13 normalized
|
|
827
862
|
* event names here is a ConnectorConfigError — use the normalized `hooks`
|
|
828
863
|
* API for those.
|
|
829
864
|
*
|
|
@@ -859,6 +894,8 @@ interface PlatformOverride {
|
|
|
859
894
|
memory?: boolean | PlatformMemoryOverride;
|
|
860
895
|
/** false → do not wire the status line on this platform (no object form in v1). */
|
|
861
896
|
statusline?: boolean;
|
|
897
|
+
/** false → do not emit the action affordance(s) on this platform (no object form in v1). */
|
|
898
|
+
actions?: boolean;
|
|
862
899
|
/** Verbatim fields merged into the native config (reach platform-exclusive features). */
|
|
863
900
|
extra?: Record<string, unknown>;
|
|
864
901
|
}
|
|
@@ -1014,6 +1051,12 @@ interface DiagnosticResult {
|
|
|
1014
1051
|
status: "pass" | "fail" | "warn";
|
|
1015
1052
|
message: string;
|
|
1016
1053
|
fix?: string;
|
|
1054
|
+
/**
|
|
1055
|
+
* true ⇒ a plain re-sync re-asserts this (the surface is simply absent and
|
|
1056
|
+
* agent-connector owns it). Omitted/false ⇒ heal must DEFER (drift we'd
|
|
1057
|
+
* clobber, external dep, or ambiguous ownership).
|
|
1058
|
+
*/
|
|
1059
|
+
fixable?: boolean;
|
|
1017
1060
|
}
|
|
1018
1061
|
|
|
1019
1062
|
export type { ActionDef as A, SubagentDef as B, CommandDef as C, SubagentStartEvent as D, EventPayloadMap as E, SubagentStopEvent as F, SurfaceToolPolicy as G, HookDefinition as H, InstallScope as I, JsonValue as J, TelemetryConfig as K, TelemetryUsageSummary as L, MemoryDef as M, NativeHookDef as N, ToolFilter as O, PlatformId as P, Transport as Q, ResolvedConnector as R, ServerDef as S, TelemetryAccessor as T, UserPromptSubmitEvent as U, ChangeRecord as V, DetectedPlatform as W, DiagnosticResult as X, InstallResult as Y, ActionResult as a, AuthSpec as b, ConfigPatchDef as c, ConnectorConfig as d, HookEventName as e, HookParadigm as f, HookResponse as g, HooksConfig as h, HostCtx as i, NativeHookEvent as j, NotificationEvent as k, PermissionRequestEvent as l, PlatformCapabilities as m, PlatformMemoryOverride as n, PlatformOverride as o, PostToolUseEvent as p, PostToolUseFailureEvent as q, PreCompactEvent as r, PreToolUseEvent as s, PublishConfig as t, SessionEndEvent as u, SessionStartEvent as v, SkillDef as w, StatuslineContext as x, StatuslineDef as y, StopEvent as z };
|
|
@@ -5,8 +5,8 @@ import {
|
|
|
5
5
|
resolveUninstallTargets,
|
|
6
6
|
uninstallConnector,
|
|
7
7
|
uninstallViaMarketplace
|
|
8
|
-
} from "./chunk-
|
|
9
|
-
import "./chunk-
|
|
8
|
+
} from "./chunk-5G4EPJ4Y.js";
|
|
9
|
+
import "./chunk-2X4EH2D7.js";
|
|
10
10
|
import {
|
|
11
11
|
marketplaceEvidence,
|
|
12
12
|
readMarketplaceInstalls
|
|
@@ -17,19 +17,20 @@ import {
|
|
|
17
17
|
parseTargets,
|
|
18
18
|
print,
|
|
19
19
|
renderInstallResult
|
|
20
|
-
} from "./chunk-
|
|
21
|
-
import "./chunk-
|
|
22
|
-
import "./chunk-
|
|
20
|
+
} from "./chunk-QC5A3TFQ.js";
|
|
21
|
+
import "./chunk-F5RX62T7.js";
|
|
22
|
+
import "./chunk-EROJDXMW.js";
|
|
23
23
|
import "./chunk-KHO5WNTP.js";
|
|
24
24
|
import {
|
|
25
25
|
findConnectorConfig,
|
|
26
26
|
loadConnectorFromPath
|
|
27
|
-
} from "./chunk-
|
|
28
|
-
import "./chunk-
|
|
29
|
-
import "./chunk-
|
|
27
|
+
} from "./chunk-MZF2YCXX.js";
|
|
28
|
+
import "./chunk-DCK5FADX.js";
|
|
29
|
+
import "./chunk-BMD7ANKF.js";
|
|
30
|
+
import "./chunk-FAHIMJRU.js";
|
|
30
31
|
import "./chunk-OPXAP3AC.js";
|
|
31
32
|
import "./chunk-7L6ITC4T.js";
|
|
32
|
-
import "./chunk-
|
|
33
|
+
import "./chunk-I5MLE6S7.js";
|
|
33
34
|
import "./chunk-N6HH7K6P.js";
|
|
34
35
|
import "./chunk-TRQKHP7D.js";
|
|
35
36
|
|
|
@@ -161,4 +162,4 @@ async function run(argv) {
|
|
|
161
162
|
export {
|
|
162
163
|
run
|
|
163
164
|
};
|
|
164
|
-
//# sourceMappingURL=uninstall-
|
|
165
|
+
//# sourceMappingURL=uninstall-FL3SH2DT.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/commands/uninstall.ts"],"sourcesContent":["/**\n * cli/commands/uninstall — strip a connector's registrations, method-aware.\n *\n * The connector id is taken from --connector-id, or inferred from the local\n * connector config (--connector <path> / findConnectorConfig).\n *\n * --method auto (default) reverses WHATEVER is actually there, per target:\n * targets with marketplace evidence (the state record, or the host's own plugin\n * state) get the HOST plugin uninstall; everything else gets the existing\n * direct adapter strip. Install chooses a method (a user decision); uninstall\n * reverses what exists (a state decision) — and since the double-install guard\n * enforces exactly one method per (connector, host, scope), auto is\n * unambiguous. Explicit --method direct|marketplace forces one path for every\n * target. Config removal vs plugin uninstall is therefore method-resolved:\n * never both, never neither.\n *\n * --purge additionally removes the framework-state this connector left behind:\n * its DATA-dir connector record (connectorDir(id)), the empty marketplace\n * staging root, and, when no connectors remain, the shared home-bin launcher.\n * Without --purge those linger so the connector can be re-synced without\n * re-registering.\n */\n\nimport { parseArgs } from \"node:util\";\n\nimport {\n purgeFrameworkState,\n resolveUninstallTargets,\n uninstallConnector,\n} from \"../../core/installer.js\";\nimport {\n marketplaceEvidence,\n parseUninstallMethod,\n uninstallViaMarketplace,\n} from \"../../core/marketplace.js\";\nimport { readMarketplaceInstalls } from \"../../core/marketplace-state.js\";\nimport { findConnectorConfig, loadConnectorFromPath } from \"../../core/load-connector.js\";\nimport type { InstallResult, PlatformId } from \"../../core/types.js\";\nimport { fail, parseScope, parseTargets, print, renderInstallResult } from \"../app.js\";\n\n/** Resolve the connector id from flags, then from a local config file. */\nasync function resolveConnectorId(\n explicitId: string | undefined,\n connectorPath: string | undefined,\n projectDir: string,\n): Promise<string | null> {\n if (explicitId && explicitId.trim() !== \"\") return explicitId;\n const configPath = connectorPath ?? findConnectorConfig(projectDir);\n if (!configPath) return null;\n const { connector } = await loadConnectorFromPath(configPath);\n return connector.id;\n}\n\nexport async function run(argv: string[]): Promise<number> {\n const { values } = parseArgs({\n args: argv,\n options: {\n method: { type: \"string\", default: \"auto\" },\n scope: { type: \"string\", default: \"user\" },\n targets: { type: \"string\" },\n connector: { type: \"string\" },\n \"connector-id\": { type: \"string\" },\n project: { type: \"string\" },\n \"dry-run\": { type: \"boolean\", default: false },\n purge: { type: \"boolean\", default: false },\n },\n allowPositionals: false,\n });\n\n const method = parseUninstallMethod(values.method);\n if (method == null) {\n return fail(`invalid --method \"${values.method}\" (use auto|direct|marketplace)`);\n }\n\n const projectDir = values.project ?? process.cwd();\n\n const scope = parseScope(values.scope);\n if (scope == null) return fail(`invalid --scope \"${values.scope}\" (use user|project)`);\n\n const connectorId = await resolveConnectorId(\n values[\"connector-id\"],\n values.connector,\n projectDir,\n );\n if (!connectorId) {\n return fail(\n \"could not determine connector id. Pass --connector-id <id>, \" +\n \"--connector <path>, or run inside a project with an agent-connector config.\",\n );\n }\n\n const targets = parseTargets(values.targets);\n const dryRun = values[\"dry-run\"];\n\n // ── Explicit --method marketplace: every target goes to the marketplace path\n // (targets default to the recorded installs); framework purge runs here since\n // no direct pass follows.\n if (method === \"marketplace\") {\n const result = await uninstallViaMarketplace({\n connectorId,\n projectDir,\n dryRun,\n purge: values.purge,\n ...(targets ? { targets } : {}),\n });\n if (values.purge) purgeFrameworkState(connectorId, dryRun, result);\n print(renderInstallResult(result, \"uninstall\"));\n return result.changes.some((c) => c.action === \"warn\") ? 1 : 0;\n }\n\n // ── --method auto: partition the resolved targets by marketplace evidence.\n // (--method direct keeps every target on the adapter strip — today's path.)\n let marketplaceTargets: PlatformId[] = [];\n let directTargets: PlatformId[] = [];\n if (method === \"auto\") {\n const resolved = await resolveUninstallTargets(connectorId, targets, projectDir);\n // With no explicit --targets, recorded marketplace platforms are unioned\n // in: the state record IS the authority for what we installed, and host\n // detection can miss a host whose probe-able config dir was relocated.\n // An explicit --targets list is always respected as-is.\n const recorded = targets\n ? []\n : (Object.keys(readMarketplaceInstalls(connectorId)) as PlatformId[]);\n const candidates = [...new Set([...resolved, ...recorded])];\n marketplaceTargets = candidates.filter(\n (id) => marketplaceEvidence(connectorId, id) != null,\n );\n directTargets = resolved.filter((id) => !marketplaceTargets.includes(id));\n }\n\n // No marketplace evidence anywhere (or --method direct): exactly today's\n // single-orchestration path, byte-for-byte — zero behavior change for users\n // who never touched the marketplace method.\n if (marketplaceTargets.length === 0) {\n const result = await uninstallConnector({\n connectorId,\n scope,\n projectDir,\n dryRun,\n purge: values.purge,\n ...(targets ? { targets } : {}),\n });\n print(renderInstallResult(result, \"uninstall\"));\n return result.changes.some((c) => c.action === \"warn\") ? 1 : 0;\n }\n\n const results: InstallResult[] = [\n await uninstallViaMarketplace({\n connectorId,\n projectDir,\n targets: marketplaceTargets,\n dryRun,\n purge: values.purge,\n }),\n ];\n\n // The direct strip runs only for its partition (never both methods on one\n // target). When every target was marketplace-routed, --purge still runs the\n // framework purge (the marketplace records were just cleared, so it can\n // proceed to the connector record + home-bin).\n if (directTargets.length > 0) {\n results.push(\n await uninstallConnector({\n connectorId,\n scope,\n projectDir,\n dryRun,\n purge: values.purge,\n targets: directTargets,\n }),\n );\n } else if (values.purge) {\n const purgeResult: InstallResult = {\n connectorId,\n dryRun,\n changes: [],\n warnings: [],\n };\n if (dryRun) {\n // On a real run the marketplace records are removed BEFORE this purge;\n // calling purgeFrameworkState now would false-refuse on records that the\n // marketplace pass only PLANNED to remove. Report the plan instead.\n purgeResult.changes.push({\n platform: connectorId as PlatformId,\n action: \"remove\",\n detail:\n \"would purge framework state (connector record; home-bin when no connectors remain)\",\n });\n } else {\n purgeFrameworkState(connectorId, dryRun, purgeResult);\n }\n results.push(purgeResult);\n }\n\n const merged: InstallResult = {\n connectorId,\n dryRun,\n changes: results.flatMap((r) => r.changes),\n warnings: results.flatMap((r) => r.warnings),\n };\n print(renderInstallResult(merged, \"uninstall\"));\n return merged.changes.some((c) => c.action === \"warn\") ? 1 : 0;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/cli/commands/uninstall.ts"],"sourcesContent":["/**\n * cli/commands/uninstall — strip a connector's registrations, method-aware.\n *\n * The connector id is taken from --connector-id, or inferred from the local\n * connector config (--connector <path> / findConnectorConfig).\n *\n * --method auto (default) reverses WHATEVER is actually there, per target:\n * targets with marketplace evidence (the state record, or the host's own plugin\n * state) get the HOST plugin uninstall; everything else gets the existing\n * direct adapter strip. Install chooses a method (a user decision); uninstall\n * reverses what exists (a state decision) — and since the double-install guard\n * enforces exactly one method per (connector, host, scope), auto is\n * unambiguous. Explicit --method direct|marketplace forces one path for every\n * target. Config removal vs plugin uninstall is therefore method-resolved:\n * never both, never neither.\n *\n * --purge additionally removes the framework-state this connector left behind:\n * its DATA-dir connector record (connectorDir(id)), the empty marketplace\n * staging root, and, when no connectors remain, the shared home-bin launcher.\n * Without --purge those linger so the connector can be re-synced without\n * re-registering.\n */\n\nimport { parseArgs } from \"node:util\";\n\nimport {\n purgeFrameworkState,\n resolveUninstallTargets,\n uninstallConnector,\n} from \"../../core/installer.js\";\nimport {\n marketplaceEvidence,\n parseUninstallMethod,\n uninstallViaMarketplace,\n} from \"../../core/marketplace.js\";\nimport { readMarketplaceInstalls } from \"../../core/marketplace-state.js\";\nimport { findConnectorConfig, loadConnectorFromPath } from \"../../core/load-connector.js\";\nimport type { InstallResult, PlatformId } from \"../../core/types.js\";\nimport { fail, parseScope, parseTargets, print, renderInstallResult } from \"../app.js\";\n\n/** Resolve the connector id from flags, then from a local config file. */\nasync function resolveConnectorId(\n explicitId: string | undefined,\n connectorPath: string | undefined,\n projectDir: string,\n): Promise<string | null> {\n if (explicitId && explicitId.trim() !== \"\") return explicitId;\n const configPath = connectorPath ?? findConnectorConfig(projectDir);\n if (!configPath) return null;\n const { connector } = await loadConnectorFromPath(configPath);\n return connector.id;\n}\n\nexport async function run(argv: string[]): Promise<number> {\n const { values } = parseArgs({\n args: argv,\n options: {\n method: { type: \"string\", default: \"auto\" },\n scope: { type: \"string\", default: \"user\" },\n targets: { type: \"string\" },\n connector: { type: \"string\" },\n \"connector-id\": { type: \"string\" },\n project: { type: \"string\" },\n \"dry-run\": { type: \"boolean\", default: false },\n purge: { type: \"boolean\", default: false },\n },\n allowPositionals: false,\n });\n\n const method = parseUninstallMethod(values.method);\n if (method == null) {\n return fail(`invalid --method \"${values.method}\" (use auto|direct|marketplace)`);\n }\n\n const projectDir = values.project ?? process.cwd();\n\n const scope = parseScope(values.scope);\n if (scope == null) return fail(`invalid --scope \"${values.scope}\" (use user|project)`);\n\n const connectorId = await resolveConnectorId(\n values[\"connector-id\"],\n values.connector,\n projectDir,\n );\n if (!connectorId) {\n return fail(\n \"could not determine connector id. Pass --connector-id <id>, \" +\n \"--connector <path>, or run inside a project with an agent-connector config.\",\n );\n }\n\n const targets = parseTargets(values.targets);\n const dryRun = values[\"dry-run\"];\n\n // ── Explicit --method marketplace: every target goes to the marketplace path\n // (targets default to the recorded installs); framework purge runs here since\n // no direct pass follows.\n if (method === \"marketplace\") {\n const result = await uninstallViaMarketplace({\n connectorId,\n projectDir,\n dryRun,\n purge: values.purge,\n ...(targets ? { targets } : {}),\n });\n if (values.purge) purgeFrameworkState(connectorId, dryRun, result);\n print(renderInstallResult(result, \"uninstall\"));\n return result.changes.some((c) => c.action === \"warn\") ? 1 : 0;\n }\n\n // ── --method auto: partition the resolved targets by marketplace evidence.\n // (--method direct keeps every target on the adapter strip — today's path.)\n let marketplaceTargets: PlatformId[] = [];\n let directTargets: PlatformId[] = [];\n if (method === \"auto\") {\n const resolved = await resolveUninstallTargets(connectorId, targets, projectDir);\n // With no explicit --targets, recorded marketplace platforms are unioned\n // in: the state record IS the authority for what we installed, and host\n // detection can miss a host whose probe-able config dir was relocated.\n // An explicit --targets list is always respected as-is.\n const recorded = targets\n ? []\n : (Object.keys(readMarketplaceInstalls(connectorId)) as PlatformId[]);\n const candidates = [...new Set([...resolved, ...recorded])];\n marketplaceTargets = candidates.filter(\n (id) => marketplaceEvidence(connectorId, id) != null,\n );\n directTargets = resolved.filter((id) => !marketplaceTargets.includes(id));\n }\n\n // No marketplace evidence anywhere (or --method direct): exactly today's\n // single-orchestration path, byte-for-byte — zero behavior change for users\n // who never touched the marketplace method.\n if (marketplaceTargets.length === 0) {\n const result = await uninstallConnector({\n connectorId,\n scope,\n projectDir,\n dryRun,\n purge: values.purge,\n ...(targets ? { targets } : {}),\n });\n print(renderInstallResult(result, \"uninstall\"));\n return result.changes.some((c) => c.action === \"warn\") ? 1 : 0;\n }\n\n const results: InstallResult[] = [\n await uninstallViaMarketplace({\n connectorId,\n projectDir,\n targets: marketplaceTargets,\n dryRun,\n purge: values.purge,\n }),\n ];\n\n // The direct strip runs only for its partition (never both methods on one\n // target). When every target was marketplace-routed, --purge still runs the\n // framework purge (the marketplace records were just cleared, so it can\n // proceed to the connector record + home-bin).\n if (directTargets.length > 0) {\n results.push(\n await uninstallConnector({\n connectorId,\n scope,\n projectDir,\n dryRun,\n purge: values.purge,\n targets: directTargets,\n }),\n );\n } else if (values.purge) {\n const purgeResult: InstallResult = {\n connectorId,\n dryRun,\n changes: [],\n warnings: [],\n };\n if (dryRun) {\n // On a real run the marketplace records are removed BEFORE this purge;\n // calling purgeFrameworkState now would false-refuse on records that the\n // marketplace pass only PLANNED to remove. Report the plan instead.\n purgeResult.changes.push({\n platform: connectorId as PlatformId,\n action: \"remove\",\n detail:\n \"would purge framework state (connector record; home-bin when no connectors remain)\",\n });\n } else {\n purgeFrameworkState(connectorId, dryRun, purgeResult);\n }\n results.push(purgeResult);\n }\n\n const merged: InstallResult = {\n connectorId,\n dryRun,\n changes: results.flatMap((r) => r.changes),\n warnings: results.flatMap((r) => r.warnings),\n };\n print(renderInstallResult(merged, \"uninstall\"));\n return merged.changes.some((c) => c.action === \"warn\") ? 1 : 0;\n}\n"],"mappings":"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","names":[]}
|