@ken-jo/agent-connector 0.6.4 → 0.6.5
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 +18 -12
- package/dist/{action-IKJ2J3X4.js → action-DFUJOXVJ.js} +9 -8
- package/dist/{action-IKJ2J3X4.js.map → action-DFUJOXVJ.js.map} +1 -1
- package/dist/{audit-5K2H7PAT.js → audit-IMNQJZ4W.js} +6 -5
- package/dist/{audit-5K2H7PAT.js.map → audit-IMNQJZ4W.js.map} +1 -1
- package/dist/{chunk-K67UJSJI.js → chunk-66TGBYSL.js} +5 -5
- package/dist/{chunk-QG26JEJF.js → chunk-7C3COFOD.js} +9 -9
- package/dist/{chunk-QG26JEJF.js.map → chunk-7C3COFOD.js.map} +1 -1
- package/dist/{chunk-HUL5CRF2.js → chunk-BAJL27XI.js} +4 -4
- package/dist/{codex-C7ERS3TW.js → chunk-BB4DFAHC.js} +21 -8
- package/dist/chunk-BB4DFAHC.js.map +1 -0
- package/dist/{chunk-STR3CRH3.js → chunk-C4NDV6GW.js} +2 -2
- package/dist/{chunk-LO6NIZSL.js → chunk-CG44RWYJ.js} +5 -5
- package/dist/chunk-D35FMUFZ.js +48 -0
- package/dist/chunk-D35FMUFZ.js.map +1 -0
- package/dist/{chunk-OXANBA4I.js → chunk-ITVST3SZ.js} +2 -2
- package/dist/{chunk-W4GVN3TJ.js → chunk-KQBRUI3Y.js} +3 -3
- package/dist/{chunk-TCJN5S4T.js → chunk-PTITNBSS.js} +22 -33
- package/dist/chunk-PTITNBSS.js.map +1 -0
- package/dist/{chunk-O7CFTOM5.js → chunk-S2TAC22E.js} +2 -2
- package/dist/{chunk-BD72ZF6D.js → chunk-V7GZ3AMV.js} +2 -2
- package/dist/{chunk-BGPVMJOG.js → chunk-ZYB2UFEN.js} +6 -2
- package/dist/chunk-ZYB2UFEN.js.map +1 -0
- package/dist/{claude-code-EIC4Q7OT.js → claude-code-JRKJARPH.js} +5 -4
- package/dist/{claude-code-EIC4Q7OT.js.map → claude-code-JRKJARPH.js.map} +1 -1
- package/dist/cli/sdk.js +5 -4
- package/dist/cli/sdk.js.map +1 -1
- package/dist/cli.js +2 -1
- package/dist/cli.js.map +1 -1
- package/dist/{cline-AJZ67XEE.js → cline-XAFNCZFQ.js} +26 -5
- package/dist/cline-XAFNCZFQ.js.map +1 -0
- package/dist/codex-X3WZZOJ4.js +22 -0
- package/dist/codex-X3WZZOJ4.js.map +1 -0
- package/dist/{define-connector-iosc34CA.d.ts → define-connector-D4UOI__e.d.ts} +1 -1
- package/dist/{detect-KYRQJUDY.js → detect-RT75DWQ5.js} +5 -4
- package/dist/{detect-KYRQJUDY.js.map → detect-RT75DWQ5.js.map} +1 -1
- package/dist/{doctor-BGWPZ676.js → doctor-F3RRQBQN.js} +135 -11
- package/dist/doctor-F3RRQBQN.js.map +1 -0
- package/dist/{hook-YMCFZRJE.js → hook-VYA4Q3YR.js} +9 -8
- package/dist/{hook-YMCFZRJE.js.map → hook-VYA4Q3YR.js.map} +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/{install-RCHVHCHO.js → install-XNTRLUZI.js} +9 -8
- package/dist/{install-RCHVHCHO.js.map → install-XNTRLUZI.js.map} +1 -1
- package/dist/{introspect-z3eKVWHN.d.ts → introspect-gaKVzg2q.d.ts} +1 -1
- package/dist/{leaderboard-V3DXXZNL.js → leaderboard-VF4W6PZ2.js} +3 -2
- package/dist/{leaderboard-V3DXXZNL.js.map → leaderboard-VF4W6PZ2.js.map} +1 -1
- package/dist/open-interpreter-ZHBMASXY.js +154 -0
- package/dist/open-interpreter-ZHBMASXY.js.map +1 -0
- package/dist/{package-75T46SXP.js → package-VRV5YHUJ.js} +7 -6
- package/dist/{package-75T46SXP.js.map → package-VRV5YHUJ.js.map} +1 -1
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/index.js +7 -6
- package/dist/sdk/index.d.ts +4 -4
- package/dist/sdk/index.js +3 -3
- package/dist/sdk/test.d.ts +2 -2
- package/dist/sdk/test.js +7 -6
- package/dist/{serve-IRMYJWFT.js → serve-EPEAGVOE.js} +9 -8
- package/dist/{serve-IRMYJWFT.js.map → serve-EPEAGVOE.js.map} +1 -1
- package/dist/{status-VJVNMWT7.js → status-3EHFFIQ7.js} +7 -6
- package/dist/{status-VJVNMWT7.js.map → status-3EHFFIQ7.js.map} +1 -1
- package/dist/{statusline-OKW44KFR.js → statusline-64IDYANK.js} +8 -7
- package/dist/{statusline-OKW44KFR.js.map → statusline-64IDYANK.js.map} +1 -1
- package/dist/{telemetry-YVMUXTDG.js → telemetry-AEE4TOFA.js} +6 -5
- package/dist/{telemetry-YVMUXTDG.js.map → telemetry-AEE4TOFA.js.map} +1 -1
- package/dist/{types-CAKApZpX.d.ts → types-htm_wrWo.d.ts} +6 -5
- package/dist/{uninstall-WZHO4CVL.js → uninstall-EJLQGZRN.js} +9 -8
- package/dist/{uninstall-WZHO4CVL.js.map → uninstall-EJLQGZRN.js.map} +1 -1
- package/dist/{upgrade-DZMEUPF2.js → upgrade-ZPHQELKG.js} +9 -8
- package/dist/{upgrade-DZMEUPF2.js.map → upgrade-ZPHQELKG.js.map} +1 -1
- package/dist/{usage-QSM4PP3E.js → usage-IWPGACHN.js} +3 -2
- package/dist/{usage-QSM4PP3E.js.map → usage-IWPGACHN.js.map} +1 -1
- package/dist/{usage-event-FH3X232T.js → usage-event-W5VLRA3X.js} +8 -7
- package/dist/{usage-event-FH3X232T.js.map → usage-event-W5VLRA3X.js.map} +1 -1
- package/package.json +1 -1
- package/dist/chunk-BGPVMJOG.js.map +0 -1
- package/dist/chunk-TCJN5S4T.js.map +0 -1
- package/dist/cline-AJZ67XEE.js.map +0 -1
- package/dist/codex-C7ERS3TW.js.map +0 -1
- package/dist/doctor-BGWPZ676.js.map +0 -1
- package/dist/open-interpreter-CXUCCZI3.js +0 -264
- package/dist/open-interpreter-CXUCCZI3.js.map +0 -1
- /package/dist/{chunk-K67UJSJI.js.map → chunk-66TGBYSL.js.map} +0 -0
- /package/dist/{chunk-HUL5CRF2.js.map → chunk-BAJL27XI.js.map} +0 -0
- /package/dist/{chunk-STR3CRH3.js.map → chunk-C4NDV6GW.js.map} +0 -0
- /package/dist/{chunk-LO6NIZSL.js.map → chunk-CG44RWYJ.js.map} +0 -0
- /package/dist/{chunk-OXANBA4I.js.map → chunk-ITVST3SZ.js.map} +0 -0
- /package/dist/{chunk-W4GVN3TJ.js.map → chunk-KQBRUI3Y.js.map} +0 -0
- /package/dist/{chunk-O7CFTOM5.js.map → chunk-S2TAC22E.js.map} +0 -0
- /package/dist/{chunk-BD72ZF6D.js.map → chunk-V7GZ3AMV.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/commands/doctor.ts","../src/runtime/probe.ts"],"sourcesContent":["/**\n * cli/commands/doctor — health-check every detected platform.\n *\n * For each detected host (or the explicit --targets list) we load its adapter,\n * build a uniform InstallContext, and run adapter.doctor(ctx). Results are\n * printed as pass/warn/fail with any suggested fix. Exit code is non-zero when\n * any check fails (warns alone do not fail the command).\n *\n * The connector context comes from the local config when present; otherwise a\n * minimal id-only connector is used so path-only checks still run.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { parseArgs } from \"node:util\";\n\nimport type {\n DiagnosticResult,\n InstallScope,\n PlatformId,\n ResolvedConnector,\n} from \"../../core/types.js\";\nimport type { InstallContext } from \"../../adapters/spi.js\";\nimport { detectInstalledPlatforms } from \"../../adapters/detect.js\";\nimport { loadAdapter, REGISTERED_PLATFORM_IDS } from \"../../adapters/registry.js\";\nimport {\n findConnectorConfig,\n listRegisteredConnectors,\n loadConnectorFromPath,\n readRegisteredMeta,\n} from \"../../core/load-connector.js\";\nimport { syncConnector } from \"../../core/installer.js\";\nimport { marketplaceDoctorChecks } from \"../../core/marketplace.js\";\nimport { readMarketplaceInstalls } from \"../../core/marketplace-state.js\";\nimport { dataRoot, homeBinPath } from \"../../core/paths.js\";\nimport { cliEntryOfLauncher, resolveOwnVersion, versionOfCliEntry } from \"../../core/version.js\";\nimport { probeStdioServer } from \"../../runtime/probe.js\";\nimport { explainHooks } from \"../../sdk/test-harness.js\";\nimport type { HookEventVerdict } from \"../../sdk/test-harness.js\";\nimport { fail, maybePrintBanner, parseScope, parseTargets, print } from \"../app.js\";\n\nconst STATUS_GLYPH: Record<DiagnosticResult[\"status\"], string> = {\n pass: \"[pass]\",\n warn: \"[warn]\",\n fail: \"[FAIL]\",\n};\n\n/** A resolved connector together with the path to its source module. */\ninterface ConnectorEntry {\n connector: ResolvedConnector;\n /** Absolute path to the connector source (JSON or JS/TS). Used by syncConnector. */\n modulePath: string;\n}\n\n/**\n * Resolve which connector(s) doctor should health-check, in precedence order:\n * 1. An explicit --connector path, or a local agent-connector.config.* file.\n * 2. Every connector registered under the data-root (what is actually\n * installed). This is the common case — `doctor` from anywhere reports on\n * the real installs, not a guess from the working directory.\n * 3. A minimal id-only placeholder so path-only checks still run.\n */\nasync function resolveDoctorConnectors(\n connectorPath: string | undefined,\n projectDir: string,\n): Promise<ConnectorEntry[] | { error: string }> {\n // When the user explicitly passed --connector <path>, any load failure is an\n // error they need to see — silently falling through to registered connectors\n // would report on a completely different set of installs with no indication\n // that the requested connector was never loaded.\n if (connectorPath !== undefined) {\n const { connector, modulePath } = await loadConnectorFromPath(connectorPath);\n return [{ connector, modulePath }];\n }\n\n const configPath = findConnectorConfig(projectDir);\n if (configPath) {\n try {\n const { connector, modulePath } = await loadConnectorFromPath(configPath);\n return [{ connector, modulePath }];\n } catch {\n /* fall through — implicit discovery failure is a convenience, not an error */\n }\n }\n\n const registered = listRegisteredConnectors();\n if (registered.length > 0) {\n return registered.map((connector) => {\n const meta = readRegisteredMeta(connector.id);\n return { connector, modulePath: meta?.modulePath ?? \"\" };\n });\n }\n\n const fallback: ResolvedConnector = {\n id: \"agent-connector\",\n displayName: \"agent-connector\",\n version: \"0.0.0\",\n hooks: {},\n hookEvents: [],\n telemetry: {\n enabled: true,\n modelFamilyHint: \"auto\",\n measureToolDefs: true,\n hostNativeUsage: false,\n store: \"ndjson\",\n calibration: { anthropicCountTokens: false },\n },\n commands: [],\n skills: [],\n subagents: [],\n memory: [],\n actions: [],\n platforms: {},\n targets: \"auto\",\n };\n return [{ connector: fallback, modulePath: \"\" }];\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/** A doctor output group: a host platform, or the framework's own checks. */\ntype DoctorBucket = PlatformId | typeof FRAMEWORK_BUCKET;\nconst FRAMEWORK_BUCKET = \"agent-connector\" as const;\n\n/**\n * Version checks (added in 0.6.5) — doctor is the one command a user runs to\n * learn whether an install is CURRENT, so it must say so explicitly:\n * - home-bin: the stable launcher exists, its CLI target exists, and that\n * target is the same agent-connector version as the CLI running doctor.\n * A launcher pointing at a removed/older install silently breaks hooks,\n * statusline and actions on every host.\n * - per connector: the framework version that rendered the install\n * (RegisteredMeta.frameworkVersion) equals the running CLI, and the\n * registered connector version equals the source connector's version.\n * Every finding here is `fixable` — a plain `upgrade` (or `doctor --heal`, which\n * syncs the same way) re-renders, re-registers and re-points the launcher.\n */\nfunction frameworkChecks(entries: ConnectorEntry[]): TaggedResult[] {\n const out: TaggedResult[] = [];\n // Framework-level findings are healed by syncing ANY registered connector;\n // attach them to the first entry that has a source module to sync from.\n const healEntry = Math.max(0, entries.findIndex((e) => !!e.modulePath));\n const push = (result: DiagnosticResult, entryIndex = healEntry) => out.push({ result, entryIndex });\n const own = resolveOwnVersion();\n const fix = \"run `upgrade` (or `doctor --heal`) to re-render and re-point the home binary\";\n\n const bin = homeBinPath();\n if (!existsSync(bin)) {\n push({\n check: \"agent-connector: home-bin\",\n status: entries.some((e) => e.modulePath) ? \"warn\" : \"pass\",\n message: entries.some((e) => e.modulePath)\n ? `launcher missing at ${bin} — host hooks/actions cannot reach agent-connector`\n : `no launcher yet at ${bin} (nothing installed)`,\n ...(entries.some((e) => e.modulePath) ? { fix, fixable: true } : {}),\n });\n } else {\n let text = \"\";\n try {\n text = readFileSync(bin, \"utf8\");\n } catch {\n /* unreadable → treated as foreign below */\n }\n const cli = cliEntryOfLauncher(text);\n if (!cli) {\n push({\n check: \"agent-connector: home-bin\",\n status: \"warn\",\n message: `launcher at ${bin} is not in the shape agent-connector writes`,\n fix,\n fixable: true,\n });\n } else if (!existsSync(cli)) {\n push({\n check: \"agent-connector: home-bin\",\n status: \"fail\",\n message: `launcher execs a CLI that no longer exists: ${cli} (an uninstalled or moved agent-connector)`,\n fix,\n fixable: true,\n });\n } else {\n push({ check: \"agent-connector: home-bin\", status: \"pass\", message: `execs ${cli}` });\n const target = versionOfCliEntry(cli);\n if (target === null) {\n push({\n check: \"agent-connector: home-bin version\",\n status: \"warn\",\n message: `cannot read the package version behind ${cli}`,\n fix,\n fixable: true,\n });\n } else if (target !== own) {\n push({\n check: \"agent-connector: home-bin version\",\n status: \"warn\",\n message: `launcher runs agent-connector ${target}, this CLI is ${own}`,\n fix,\n fixable: true,\n });\n } else {\n push({ check: \"agent-connector: home-bin version\", status: \"pass\", message: own });\n }\n }\n }\n\n entries.forEach((entry, i) => {\n if (!entry.modulePath) return; // placeholder — nothing registered to compare\n const meta = readRegisteredMeta(entry.connector.id);\n if (!meta) return; // not installed here; the platform checks report that\n const idFix = `run \\`upgrade\\` (or \\`doctor --heal\\`) to re-render ${entry.connector.id}`;\n if (!meta.frameworkVersion) {\n push(\n {\n check: `${entry.connector.id}: framework version`,\n status: \"warn\",\n message: `rendered by an agent-connector older than 0.6.5 (no version recorded); running ${own}`,\n fix: idFix,\n fixable: true,\n },\n i,\n );\n } else if (meta.frameworkVersion !== own) {\n push(\n {\n check: `${entry.connector.id}: framework version`,\n status: \"warn\",\n message: `rendered by agent-connector ${meta.frameworkVersion}, running ${own}`,\n fix: idFix,\n fixable: true,\n },\n i,\n );\n } else {\n push({ check: `${entry.connector.id}: framework version`, status: \"pass\", message: own }, i);\n }\n if (meta.version !== entry.connector.version) {\n push(\n {\n check: `${entry.connector.id}: connector version`,\n status: \"warn\",\n message: `registered ${meta.version}, source declares ${entry.connector.version}`,\n fix: idFix,\n fixable: true,\n },\n i,\n );\n } else {\n push(\n { check: `${entry.connector.id}: connector version`, status: \"pass\", message: meta.version },\n i,\n );\n }\n });\n return out;\n}\n\n/** Collected diagnostics tagged with the connector entry they came from. */\ninterface TaggedResult {\n result: DiagnosticResult;\n /** Index into the entries array — used to group by connector for heal. */\n entryIndex: number;\n}\n\n/**\n * Run all diagnostic checks for the given entries/ids and return tagged results\n * plus the flat byPlatform buckets for display.\n */\nasync function collectDiagnostics(\n entries: ConnectorEntry[],\n ids: PlatformId[],\n scope: InstallScope,\n projectDir: string,\n): Promise<{\n byPlatform: { platform: DoctorBucket; results: DiagnosticResult[] }[];\n tagged: TaggedResult[];\n anyFail: boolean;\n}> {\n const multi = entries.length > 1;\n const byPlatform: { platform: DoctorBucket; results: DiagnosticResult[] }[] = [];\n const tagged: TaggedResult[] = [];\n let anyFail = false;\n\n for (const id of ids) {\n const adapter = await loadAdapter(id);\n if (!adapter) {\n const r: DiagnosticResult = {\n check: `${id}: adapter`,\n status: \"fail\",\n message: `no adapter registered for ${id}`,\n };\n byPlatform.push({ platform: id, results: [r] });\n anyFail = true;\n continue;\n }\n const results: DiagnosticResult[] = [];\n for (let i = 0; i < entries.length; i++) {\n const { connector } = entries[i]!;\n // A connector with an explicit target list is only checked on those hosts.\n if (connector.targets !== \"auto\" && !connector.targets.includes(id)) continue;\n\n // MARKETPLACE-installed on this host: its surfaces are delivered via the\n // host's plugin (in the plugin cache), NOT the direct-config locations the\n // adapter's doctor() inspects — so the direct checks would falsely FAIL\n // (mcp_servers/command/skill \"not found\"). Skip them; the marketplace-method\n // checks below cover this install's real health.\n if (readMarketplaceInstalls(connector.id)[id]) {\n const note: DiagnosticResult = {\n check: `${connector.id}: ${id} delivery`,\n status: \"pass\",\n message: \"surfaces delivered via the marketplace plugin — see marketplace checks\",\n };\n const tagged_note = multi ? { ...note, check: `(${connector.id}) ${note.check}` } : note;\n results.push(tagged_note);\n tagged.push({ result: tagged_note, entryIndex: i });\n continue;\n }\n\n const ctx = buildContext(connector, id, scope, projectDir);\n let r: DiagnosticResult[];\n try {\n r = adapter.doctor(ctx);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n r = [{ check: `${adapter.name}: doctor`, status: \"fail\", message }];\n }\n // When checking multiple connectors, tag each check with the connector id.\n const tagged_r = multi ? r.map((d) => ({ ...d, check: `(${connector.id}) ${d.check}` })) : r;\n results.push(...tagged_r);\n for (const tr of tagged_r) tagged.push({ result: tr, entryIndex: i });\n }\n if (results.some((d) => d.status === \"fail\")) anyFail = true;\n byPlatform.push({ platform: id, results });\n }\n\n // ── Marketplace-method checks ─────────────────────────────────────────────\n for (let i = 0; i < entries.length; i++) {\n const { connector } = entries[i]!;\n const groups = await marketplaceDoctorChecks(connector, scope, projectDir);\n for (const group of groups) {\n const tagged_g = multi\n ? group.results.map((d) => ({ ...d, check: `(${connector.id}) ${d.check}` }))\n : group.results;\n if (tagged_g.some((d) => d.status === \"fail\")) anyFail = true;\n for (const tg of tagged_g) tagged.push({ result: tg, entryIndex: i });\n const bucket = byPlatform.find((b) => b.platform === group.platform);\n if (bucket) bucket.results.push(...tagged_g);\n else byPlatform.push({ platform: group.platform, results: tagged_g });\n }\n }\n\n // ── Framework checks (home-bin + version drift) — printed first ───────────\n const fw = frameworkChecks(entries);\n if (fw.length > 0) {\n if (fw.some((t) => t.result.status === \"fail\")) anyFail = true;\n tagged.push(...fw);\n byPlatform.unshift({ platform: FRAMEWORK_BUCKET, results: fw.map((t) => t.result) });\n }\n\n return { byPlatform, tagged, anyFail };\n}\n\nconst VERDICT_GLYPH: Record<HookEventVerdict[\"verdict\"], string> = {\n honored: \"[honored]\",\n degraded: \"[degraded]\",\n dropped: \"[dropped]\",\n};\n\n/**\n * Resolve which hosts `--explain` reports a connector against: an explicit\n * --targets list (intersected with the registry), else the connector's declared\n * targets, else (targets:\"auto\") every registered host. Detection-independent —\n * the per-event honor verdict is a static/offline property a dev wants BEFORE\n * installing, not gated on what happens to be installed.\n */\nfunction explainHostsFor(\n connector: ResolvedConnector,\n explicit: PlatformId[] | undefined,\n): PlatformId[] {\n if (explicit && explicit.length > 0) {\n return explicit.filter((id) => REGISTERED_PLATFORM_IDS.has(id));\n }\n if (connector.targets !== \"auto\") {\n return (connector.targets as PlatformId[]).filter((id) =>\n REGISTERED_PLATFORM_IDS.has(id),\n );\n }\n return [...REGISTERED_PLATFORM_IDS].sort();\n}\n\n/**\n * The exit rule for a single connector's per-event matrix. The principle: a\n * non-zero exit means \"something is wrong with YOUR connector\", NOT \"some host\n * cannot do hooks as designed\". So:\n * • `dropped` (mcp-only host / no native equivalent) is EXPECTED and NEVER\n * fails — it mirrors install's `skip` (= exit 0) for the very same\n * no-equivalent case the never-silent-skip work ships;\n * • `degraded` (the host FIRES the event but silently won't honor the reply,\n * e.g. a deny that fails open) is genuine silent misbehavior — but only a\n * finding worth FAILING on when the dev EXPLICITLY targeted that host\n * (`--targets`, or the connector's own `targets:[...]`). Under `targets:\"auto\"`\n * the matrix spans the whole fleet, where such gaps are expected, so it stays\n * informational (exit 0) — matching plain-doctor's scope-aware non-failure.\n */\nfunction explainConnectorFails(\n rows: HookEventVerdict[],\n scoped: boolean,\n): boolean {\n if (!scoped) return false;\n return rows.some((row) => row.verdict === \"degraded\");\n}\n\n/**\n * The `doctor --explain` body: for each resolved connector, the per-(host,\n * event) honor matrix from {@link explainHooks} (honored / degraded / dropped\n * with the simulate()-grade reason). ALL rows are always printed (visibility is\n * never gated on the exit rule). The exit code follows {@link explainConnectorFails}:\n * only a `degraded` cell on an EXPLICITLY-targeted host fails the command — a\n * `dropped` cell (a host that architecturally cannot fire hooks) never does.\n */\nasync function runExplain(\n entries: ConnectorEntry[],\n explicit: PlatformId[] | undefined,\n json: boolean,\n): Promise<number> {\n const report: {\n connector: string;\n rows: HookEventVerdict[];\n scoped: boolean;\n }[] = [];\n for (const { connector } of entries) {\n // \"scoped\" = the dev narrowed the host set deliberately (an explicit\n // --targets list, or the connector's own targets:[...]). Under targets:\"auto\"\n // the matrix is fleet-wide and degraded cells stay informational.\n const scoped =\n (explicit != null && explicit.length > 0) || connector.targets !== \"auto\";\n if (connector.hookEvents.length === 0) {\n report.push({ connector: connector.id, rows: [], scoped });\n continue;\n }\n const hosts = explainHostsFor(connector, explicit);\n const rows = await explainHooks(connector, hosts);\n report.push({ connector: connector.id, rows, scoped });\n }\n\n const anyFail = report.some((r) => explainConnectorFails(r.rows, r.scoped));\n\n if (json) {\n print(JSON.stringify(report.map(({ connector, rows }) => ({ connector, rows })), null, 2));\n return anyFail ? 1 : 0;\n }\n\n for (const { connector, rows } of report) {\n print(`${connector} — per-event hook honor:`);\n if (rows.length === 0) {\n print(\" (connector declares no hooks)\");\n print(\"\");\n continue;\n }\n for (const row of rows) {\n print(` ${VERDICT_GLYPH[row.verdict]} ${row.host} / ${row.event} — ${row.reason}`);\n }\n print(\"\");\n }\n // Footer states the verdict AND the exit rule, so a `dropped`-only run that\n // exits 0 (the common default-targets case) is not surprising.\n if (anyFail) {\n print(\n \"doctor --explain: a declared hook event is DEGRADED on an explicitly-targeted host (the host fires it but silently won't honor the reply).\",\n );\n } else if (report.some((r) => r.rows.some((row) => row.verdict !== \"honored\"))) {\n print(\n \"doctor --explain: some hosts drop or degrade declared events (expected for mcp-only / fleet-wide gaps) — informational, exit 0.\",\n );\n } else {\n print(\"doctor --explain: every declared hook event is honored on its target hosts.\");\n }\n return anyFail ? 1 : 0;\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 targets: { type: \"string\" },\n connector: { type: \"string\" },\n project: { type: \"string\" },\n json: { type: \"boolean\", default: false },\n probe: { type: \"boolean\", default: false },\n heal: { type: \"boolean\", default: false },\n explain: { type: \"boolean\", default: false },\n \"dry-run\": { type: \"boolean\", default: false },\n // Decorative-banner suppressor (no effect on command output bytes).\n quiet: { type: \"boolean\", default: false },\n },\n allowPositionals: false,\n });\n\n // Decorative header — suppressed under --json (machine output) and --quiet,\n // and whenever stdout is not a TTY (so piped/redirected doctor stays clean).\n maybePrintBanner({ json: values.json, quiet: values.quiet });\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 resolved = await resolveDoctorConnectors(values.connector, projectDir).catch(\n (err: unknown) => ({\n error: `cannot load connector \"${values.connector}\": ${err instanceof Error ? err.message : String(err)}`,\n }),\n );\n if (\"error\" in resolved) return fail(resolved.error);\n const entries = resolved;\n const connectors = entries.map((e) => e.connector);\n\n // ── Per-event explain path (--explain) ───────────────────────────────────\n // Additive, OFFLINE detail layer: the trustworthy per-(host, event) honor\n // matrix (honored / degraded / dropped) the coarse \"any hook present = OK\"\n // doctor cannot give. Resolves hosts from the connector's OWN targets (or\n // --targets), NOT from detection — a dev wants this BEFORE installing.\n if (values.explain) {\n return runExplain(entries, parseTargets(values.targets), values.json ?? false);\n }\n\n // Target set: explicit --targets (intersected with the registry), else the\n // same chain install uses — connector-declared targets ∩ detected platforms\n // (\"auto\" = everything detected). Without this, doctor red-flags every\n // detected host the connector never targeted (found dogfooding context-mode:\n // targets:[5 ids] installed clean, doctor FAILed the other 9 detected hosts).\n const explicit = parseTargets(values.targets);\n let ids: PlatformId[];\n if (explicit && explicit.length > 0) {\n ids = explicit.filter((id) => REGISTERED_PLATFORM_IDS.has(id));\n } else {\n const detected = await detectInstalledPlatforms(projectDir);\n ids = detected.map((p) => p.id);\n const anyAuto = connectors.some((c) => c.targets === \"auto\");\n if (!anyAuto) {\n const targeted = new Set(connectors.flatMap((c) => c.targets as PlatformId[]));\n ids = ids.filter((id) => targeted.has(id));\n }\n }\n\n if (ids.length === 0 && !values.probe) {\n print(\"doctor: no target platforms (none detected; pass --targets to force).\");\n return 0;\n }\n\n // ── Heal path ─────────────────────────────────────────────────────────────\n if (values.heal) {\n const { tagged, anyFail: preFail } = await collectDiagnostics(\n entries,\n ids,\n scope,\n projectDir,\n );\n\n // Partition: fixable vs deferred (non-pass, not fixable)\n const fixableByEntry = new Map<number, DiagnosticResult[]>();\n const deferredByEntry = new Map<number, DiagnosticResult[]>();\n for (const { result, entryIndex } of tagged) {\n if (result.status === \"pass\") continue;\n // A finding is only HEALABLE if it is fixable AND its connector has a\n // module path we can re-sync from. A placeholder/unregistered connector\n // (empty modulePath) must NEVER be synced — doing so would fabricate a\n // bogus registry record via registerConnector(connector, \"\"). Route its\n // fixable findings to deferred instead.\n const canSync = !!entries[entryIndex]!.modulePath;\n if (result.fixable && canSync) {\n if (!fixableByEntry.has(entryIndex)) fixableByEntry.set(entryIndex, []);\n fixableByEntry.get(entryIndex)!.push(result);\n } else {\n if (!deferredByEntry.has(entryIndex)) deferredByEntry.set(entryIndex, []);\n deferredByEntry.get(entryIndex)!.push(result);\n }\n }\n\n if (values[\"dry-run\"]) {\n // Dry-run: print what would happen, write nothing.\n for (const [idx, fixable] of fixableByEntry) {\n const { connector } = entries[idx]!;\n print(\n `would heal via sync (${connector.id}): ${fixable.map((r) => r.check).join(\", \")}`,\n );\n }\n for (const [idx, deferred] of deferredByEntry) {\n const { connector } = entries[idx]!;\n for (const r of deferred) {\n print(\n `would defer (${connector.id}): ${r.check} — ${r.fix ?? \"no auto-fix available\"}`,\n );\n }\n }\n if (fixableByEntry.size === 0 && deferredByEntry.size === 0) {\n print(\"doctor --heal --dry-run: nothing to heal.\");\n }\n return 0;\n }\n\n // Real heal: sync each connector that has fixable findings.\n for (const [idx] of fixableByEntry) {\n const { connector, modulePath } = entries[idx]!;\n await syncConnector({\n connector,\n modulePath,\n scope,\n projectDir,\n targets: ids,\n dryRun: false,\n });\n }\n\n // Re-run diagnostics to compute what changed.\n const { tagged: postTagged, anyFail: postFail } = await collectDiagnostics(\n entries,\n ids,\n scope,\n projectDir,\n );\n\n // Classify post-heal results.\n const preNonPass = new Set(\n tagged\n .filter((t) => t.result.status !== \"pass\")\n .map((t) => t.result.check),\n );\n const postNonPass = new Set(\n postTagged\n .filter((t) => t.result.status !== \"pass\")\n .map((t) => t.result.check),\n );\n\n const healed: string[] = [];\n const stillFailing: DiagnosticResult[] = [];\n const deferred: DiagnosticResult[] = [];\n\n // Healed = was non-pass before, now pass\n for (const check of preNonPass) {\n if (!postNonPass.has(check)) healed.push(check);\n }\n // Post-heal non-pass findings. Classify consistently with the pre-heal\n // partition: a fixable finding we could not sync (no modulePath) is deferred,\n // not \"still failing after sync\" — we never attempted a sync for it.\n for (const { result, entryIndex } of postTagged) {\n if (result.status === \"pass\") continue;\n const canSync = !!entries[entryIndex]!.modulePath;\n if (result.fixable && canSync) {\n stillFailing.push(result);\n } else {\n deferred.push(result);\n }\n }\n\n if (values.json) {\n print(JSON.stringify({ healed, deferred, stillFailing }, null, 2));\n return postFail ? 1 : 0;\n }\n\n if (healed.length > 0) {\n print(`healed (${healed.length}):`);\n for (const c of healed) print(` [pass] ${c}`);\n print(\"\");\n }\n if (stillFailing.length > 0) {\n print(`still failing after sync (${stillFailing.length}):`);\n for (const r of stillFailing) {\n print(` ${STATUS_GLYPH[r.status]} ${r.check} — ${r.message}`);\n if (r.fix) print(` fix: ${r.fix}`);\n }\n print(\"\");\n }\n if (deferred.length > 0) {\n print(`deferred — requires manual action (${deferred.length}):`);\n for (const r of deferred) {\n print(` ${STATUS_GLYPH[r.status]} ${r.check} — ${r.message}`);\n if (r.fix) print(` fix: ${r.fix}`);\n }\n print(\"\");\n }\n if (healed.length === 0 && stillFailing.length === 0 && deferred.length === 0 && !preFail) {\n print(\"doctor --heal: nothing to heal, all checks passed.\");\n } else if (stillFailing.length === 0 && deferred.length === 0) {\n print(\"doctor --heal: all fixable findings resolved.\");\n }\n return postFail ? 1 : 0;\n }\n\n // ── Normal diagnose path (no --heal) ─────────────────────────────────────\n const { byPlatform, anyFail } = await collectDiagnostics(entries, ids, scope, projectDir);\n\n // ── Live MCP probe (--probe): connector-scoped, not platform-scoped ──────\n // Spawns each connector's REAL stdio server and runs initialize → ping →\n // tools/list. Probe FAILs fold into the doctor exit code.\n const probes: { connector: string; results: DiagnosticResult[] }[] = [];\n if (values.probe) {\n for (const { connector } of entries) {\n const s = connector.server;\n if (!s || s.transport !== \"stdio\" || !s.command) {\n probes.push({\n connector: connector.id,\n results: [\n {\n check: `${connector.id}: MCP probe`,\n status: \"warn\",\n message: s\n ? `transport \"${s.transport}\" is not stdio — live probe skipped`\n : \"no server to probe\",\n },\n ],\n });\n continue;\n }\n const results = await probeStdioServer(s.command, s.args ?? [], {\n label: connector.id,\n ...(s.env ? { env: s.env } : {}),\n });\n probes.push({ connector: connector.id, results });\n }\n }\n\n const probesFail = probes.some((p) => p.results.some((r) => r.status === \"fail\"));\n\n if (values.json) {\n print(JSON.stringify(values.probe ? { platforms: byPlatform, probes } : byPlatform, null, 2));\n return anyFail || probesFail ? 1 : 0;\n }\n\n for (const { platform, results } of byPlatform) {\n print(`${platform}:`);\n for (const r of results) {\n print(` ${STATUS_GLYPH[r.status]} ${r.check} — ${r.message}`);\n if (r.fix) print(` fix: ${r.fix}`);\n }\n print(\"\");\n }\n for (const { connector, results } of probes) {\n print(`probe ${connector}:`);\n for (const r of results) {\n print(` ${STATUS_GLYPH[r.status]} ${r.check} — ${r.message}`);\n if (r.fix) print(` fix: ${r.fix}`);\n }\n print(\"\");\n }\n print(anyFail || probesFail ? \"doctor: one or more checks FAILED.\" : \"doctor: all checks passed.\");\n return anyFail || probesFail ? 1 : 0;\n}\n","/**\n * runtime/probe — a live MCP connection-lifecycle probe for `doctor --probe`.\n *\n * Where `doctor` checks files on disk, this spawns the connector's REAL stdio\n * server and speaks the MCP wire protocol to it: initialize → (read negotiated\n * protocolVersion + capabilities + serverInfo) → notifications/initialized →\n * ping (liveness) → tools/list (gated on the tools capability). It reuses the\n * SAME newline-delimited JSON-RPC framing + id-correlation as the telemetry\n * proxy (telemetry/jsonrpc), so the probe and the serve path read the wire\n * identically. Each step becomes a DiagnosticResult so doctor renders/aggregates\n * it uniformly; a dead/unlaunchable server FAILs (non-zero doctor exit).\n *\n * Negotiation rule: we OFFER {@link MCP_PROTOCOL_VERSION} but ACCEPT whatever\n * version the server returns (we only report it), per the spec — never a\n * hardcoded equality. There is no MCP shutdown message; we close stdin then\n * SIGTERM/SIGKILL.\n */\n\nimport type { DiagnosticResult } from \"../core/types.js\";\nimport { MCP_PROTOCOL_VERSION } from \"../core/mcp-standard.js\";\nimport { spawnChild } from \"../core/spawn-child.js\";\nimport { type JsonRpcMessage, LineBuffer, idKey, isObject } from \"../telemetry/jsonrpc.js\";\n\nconst DEFAULT_TIMEOUT_MS = 5000;\n\nexport interface ProbeOptions {\n /** Per-step timeout in ms (default 5000). */\n timeoutMs?: number;\n /** Prefix for each DiagnosticResult.check (e.g. the connector id). */\n label?: string;\n /** Env merged over process.env for the spawned server (${env:VAR} resolved). */\n env?: Record<string, string>;\n /** Protocol version offered in initialize. Default {@link MCP_PROTOCOL_VERSION}. */\n protocolVersion?: string;\n}\n\nfunction diag(\n status: DiagnosticResult[\"status\"],\n check: string,\n message: string,\n fix?: string,\n): DiagnosticResult {\n return { check, status, message, ...(fix ? { fix } : {}) };\n}\n\nfunction errMsg(e: unknown): string {\n return e instanceof Error ? e.message : String(e);\n}\n\n/** Resolve `${env:VAR}` references in env values against the current process env. */\nfunction resolveEnv(env: Record<string, string> | undefined): Record<string, string> {\n const out: Record<string, string> = {};\n for (const [k, v] of Object.entries(env ?? {})) {\n out[k] = v.replace(/\\$\\{env:([A-Za-z_][A-Za-z0-9_]*)\\}/g, (_m, name) => process.env[name] ?? \"\");\n }\n return out;\n}\n\n/**\n * Spawn the stdio MCP server `command args` and run a real lifecycle probe.\n * Always resolves (never rejects) with one DiagnosticResult per step.\n */\nexport async function probeStdioServer(\n command: string,\n args: string[],\n opts: ProbeOptions = {},\n): Promise<DiagnosticResult[]> {\n const label = opts.label ? `${opts.label}: ` : \"\";\n const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const protocolVersion = opts.protocolVersion ?? MCP_PROTOCOL_VERSION;\n const results: DiagnosticResult[] = [];\n\n // spawnChild resolves a bare Windows package runner (npx/uvx → .cmd/.exe) so\n // the probe agrees with the live serve path; no-op on macOS/Linux.\n const child = spawnChild(command, args, {\n stdio: [\"pipe\", \"pipe\", \"inherit\"],\n env: { ...process.env, ...resolveEnv(opts.env) },\n });\n\n interface Pending {\n resolve: (m: JsonRpcMessage) => void;\n reject: (e: Error) => void;\n }\n const pending = new Map<string, Pending>();\n let spawnErr: Error | null = null;\n let exitCode: number | null = null;\n\n const rejectAll = (e: Error): void => {\n for (const p of pending.values()) p.reject(e);\n pending.clear();\n };\n child.on(\"error\", (e) => {\n spawnErr = e;\n rejectAll(e);\n });\n child.on(\"exit\", (code) => {\n exitCode = code ?? 0;\n rejectAll(new Error(`server exited (code ${exitCode}) before responding`));\n });\n\n const lines = new LineBuffer((line) => {\n let parsed: unknown;\n try {\n parsed = JSON.parse(line);\n } catch {\n return; // non-JSON stdout noise — ignore\n }\n if (!isObject(parsed)) return;\n const k = idKey((parsed as JsonRpcMessage).id);\n if (k && pending.has(k)) {\n const p = pending.get(k)!;\n pending.delete(k);\n p.resolve(parsed as JsonRpcMessage);\n }\n });\n child.stdout?.on(\"data\", (c: Buffer) => lines.push(c));\n\n const send = (m: JsonRpcMessage): void => {\n if (child.stdin && child.stdin.writable) child.stdin.write(`${JSON.stringify(m)}\\n`);\n };\n const request = (id: number | string, method: string, params?: unknown): Promise<JsonRpcMessage> => {\n const key = idKey(id)!;\n return new Promise<JsonRpcMessage>((resolve, reject) => {\n const timer = setTimeout(() => {\n pending.delete(key);\n reject(new Error(`no response within ${timeoutMs}ms`));\n }, timeoutMs);\n if (typeof timer.unref === \"function\") timer.unref();\n pending.set(key, {\n resolve: (m) => {\n clearTimeout(timer);\n resolve(m);\n },\n reject: (e) => {\n clearTimeout(timer);\n reject(e);\n },\n });\n send({ jsonrpc: \"2.0\", id, method, ...(params !== undefined ? { params } : {}) });\n });\n };\n\n const cleanup = (): DiagnosticResult[] => {\n try {\n if (child.stdin && child.stdin.writable) child.stdin.end();\n } catch {\n /* ignore */\n }\n try {\n child.kill(\"SIGTERM\");\n } catch {\n /* ignore */\n }\n const killTimer = setTimeout(() => {\n try {\n child.kill(\"SIGKILL\");\n } catch {\n /* ignore */\n }\n }, 500);\n if (typeof killTimer.unref === \"function\") killTimer.unref();\n return results;\n };\n\n // 1. initialize\n let initResult: Record<string, unknown>;\n try {\n const res = await request(1, \"initialize\", {\n protocolVersion,\n capabilities: {},\n clientInfo: { name: \"agent-connector-probe\", version: \"1\" },\n });\n if (isObject(res.error)) {\n results.push(\n diag(\"fail\", `${label}MCP initialize`, `server returned error: ${JSON.stringify(res.error)}`),\n );\n return cleanup();\n }\n initResult = isObject(res.result) ? res.result : {};\n } catch (e) {\n if (spawnErr) {\n results.push(\n diag(\n \"fail\",\n `${label}MCP initialize`,\n `server not launchable: ${errMsg(spawnErr)}`,\n `check that \"${command}\" is installed and on PATH`,\n ),\n );\n } else if (exitCode !== null) {\n // On Windows an unresolvable command surfaces as an early non-zero exit\n // (cmd.exe \"command not found\") rather than a spawn 'error' event, so fold\n // the not-launchable hint in here too — useful whether the command is\n // missing or the server genuinely crashed before initialize.\n results.push(\n diag(\n \"fail\",\n `${label}MCP initialize`,\n `server not launchable, or it exited (code ${exitCode}) before initialize`,\n `check that \"${command}\" is installed and on PATH`,\n ),\n );\n } else {\n results.push(diag(\"fail\", `${label}MCP initialize`, errMsg(e)));\n }\n return cleanup();\n }\n\n const serverInfo = isObject(initResult.serverInfo) ? initResult.serverInfo : {};\n const sName = typeof serverInfo.name === \"string\" ? serverInfo.name : \"unknown\";\n const sVer = typeof serverInfo.version === \"string\" ? serverInfo.version : \"?\";\n const negotiated =\n typeof initResult.protocolVersion === \"string\" ? initResult.protocolVersion : \"(none)\";\n results.push(diag(\"pass\", `${label}MCP initialize`, `serverInfo ${sName}@${sVer}, protocol ${negotiated}`));\n\n // capabilities (presence = feature offered)\n const caps = isObject(initResult.capabilities) ? initResult.capabilities : {};\n const capNames = [\"tools\", \"resources\", \"prompts\", \"logging\", \"completions\"].filter((c) => c in caps);\n results.push(\n diag(\"pass\", `${label}capabilities`, capNames.length > 0 ? capNames.join(\", \") : \"(none advertised)\"),\n );\n\n // 2. initialized notification (required before normal requests)\n send({ jsonrpc: \"2.0\", method: \"notifications/initialized\" });\n\n // 3. ping — liveness confirm (warn, not fail, on timeout)\n try {\n await request(\"probe-ping\", \"ping\");\n results.push(diag(\"pass\", `${label}ping`, \"alive\"));\n } catch (e) {\n results.push(diag(\"warn\", `${label}ping`, `no ping response (${errMsg(e)})`));\n }\n\n // 4. tools/list — only if the server advertised a tools capability\n if (\"tools\" in caps) {\n try {\n const res = await request(2, \"tools/list\", {});\n const r = isObject(res.result) ? res.result : {};\n const tools = Array.isArray(r.tools) ? r.tools : [];\n results.push(diag(\"pass\", `${label}tools/list`, `${tools.length} tool(s)`));\n } catch (e) {\n results.push(diag(\"fail\", `${label}tools/list`, `no tools/list response (${errMsg(e)})`));\n }\n } else {\n results.push(\n diag(\"warn\", `${label}tools/list`, \"skipped — server advertised no tools capability\"),\n );\n }\n\n return cleanup();\n}\n"],"mappings":"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","names":["deferred"]}
|
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
fail
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-PTITNBSS.js";
|
|
5
|
+
import "./chunk-66TGBYSL.js";
|
|
6
6
|
import "./chunk-OP4KBXUO.js";
|
|
7
7
|
import "./chunk-GDIAHWNY.js";
|
|
8
|
-
import "./chunk-
|
|
8
|
+
import "./chunk-ITVST3SZ.js";
|
|
9
9
|
import {
|
|
10
10
|
isNativeHookDeclared,
|
|
11
11
|
runHook,
|
|
12
12
|
runNativeHook
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-KQBRUI3Y.js";
|
|
14
14
|
import "./chunk-IVAWP6HH.js";
|
|
15
15
|
import "./chunk-KHO5WNTP.js";
|
|
16
16
|
import "./chunk-4NFDNY3C.js";
|
|
17
|
-
import "./chunk-
|
|
18
|
-
import "./chunk-
|
|
19
|
-
import "./chunk-
|
|
17
|
+
import "./chunk-ZYB2UFEN.js";
|
|
18
|
+
import "./chunk-D35FMUFZ.js";
|
|
19
|
+
import "./chunk-S2TAC22E.js";
|
|
20
|
+
import "./chunk-7C3COFOD.js";
|
|
20
21
|
import "./chunk-NBYKLUF6.js";
|
|
21
22
|
import "./chunk-QSY74NAP.js";
|
|
22
23
|
import "./chunk-UMQ6NBQR.js";
|
|
@@ -94,4 +95,4 @@ export {
|
|
|
94
95
|
HOOK_EVENTS,
|
|
95
96
|
run
|
|
96
97
|
};
|
|
97
|
-
//# sourceMappingURL=hook-
|
|
98
|
+
//# sourceMappingURL=hook-VYA4Q3YR.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/commands/hook.ts"],"sourcesContent":["/**\n * cli/commands/hook — the universal json-stdio hook entrypoint.\n *\n * agent-connector hook <platform> <event> --connector <id>\n *\n * This is the single command every host's hook config points at (via the stable\n * home binary). It reads the ENTIRE host payload from stdin, dispatches through\n * runHook, writes any stdout/stderr the adapter produced, and exits with the\n * adapter's exit code (the host interprets it as allow/deny/etc.).\n *\n * Fail-open is the runtime's contract: runHook never rejects, so a framework or\n * handler bug can't wedge a host's tool call.\n */\n\nimport { parseArgs } from \"node:util\";\n\nimport type { HookEventName } from \"../../core/types.js\";\nimport { isNativeHookDeclared, runHook, runNativeHook } from \"../../runtime/index.js\";\nimport type { RunHookResult } from \"../../runtime/index.js\";\nimport { fail } from \"../app.js\";\n\n// The CLI hook-dispatch gate: every normalized HookEventName the entrypoint\n// accepts. MUST stay in sync with HookEventName / define-connector ALL_EVENTS —\n// a missing member silently rejects an installed hook at runtime. The\n// hook-dispatch-events test pins this set ⊇ ALL_EVENTS so it cannot drift.\nexport const HOOK_EVENTS: ReadonlySet<string> = new Set<HookEventName>([\n \"SessionStart\",\n \"SessionEnd\",\n \"UserPromptSubmit\",\n \"PreToolUse\",\n \"PostToolUse\",\n \"PreCompact\",\n \"Stop\",\n \"Notification\",\n \"PermissionRequest\",\n \"PostToolUseFailure\",\n \"SubagentStart\",\n \"SubagentStop\",\n \"PostCompact\",\n]);\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 const { values, positionals } = parseArgs({\n args: argv,\n options: {\n connector: { type: \"string\" },\n },\n allowPositionals: true,\n });\n\n const platformId = positionals[0];\n const event = positionals[1];\n if (!platformId || !event) {\n return fail(\"usage: agent-connector hook <platform> <event> --connector <id>\");\n }\n const connectorId = values.connector;\n if (!connectorId || connectorId.trim() === \"\") {\n return fail(\"hook requires --connector <id>\");\n }\n\n // NATIVE PASSTHROUGH: a non-union event name is accepted ONLY when the\n // resolved connector declares it under platforms[<platform>].nativeHooks —\n // dispatch then bypasses the normalized parse/format entirely (raw stdin →\n // handler → verbatim JSON stdout). Undeclared names keep the strict error.\n if (!HOOK_EVENTS.has(event)) {\n if (!(await isNativeHookDeclared(platformId, event, connectorId))) {\n return fail(`unknown hook event \"${event}\"`);\n }\n const stdin = await readAll(process.stdin);\n const reply = await runNativeHook({ platformId, event, connectorId, stdin });\n return exitWithReply(reply);\n }\n\n // Read the entire host payload before dispatching.\n const stdin = await readAll(process.stdin);\n\n const reply = await runHook({\n platformId,\n event: event as HookEventName,\n connectorId,\n stdin,\n });\n\n return exitWithReply(reply);\n}\n\n/** Write a hook reply's stdout/stderr and exit with its code. */\nfunction exitWithReply(reply: RunHookResult): never {\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 process.exit(reply.exitCode);\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/cli/commands/hook.ts"],"sourcesContent":["/**\n * cli/commands/hook — the universal json-stdio hook entrypoint.\n *\n * agent-connector hook <platform> <event> --connector <id>\n *\n * This is the single command every host's hook config points at (via the stable\n * home binary). It reads the ENTIRE host payload from stdin, dispatches through\n * runHook, writes any stdout/stderr the adapter produced, and exits with the\n * adapter's exit code (the host interprets it as allow/deny/etc.).\n *\n * Fail-open is the runtime's contract: runHook never rejects, so a framework or\n * handler bug can't wedge a host's tool call.\n */\n\nimport { parseArgs } from \"node:util\";\n\nimport type { HookEventName } from \"../../core/types.js\";\nimport { isNativeHookDeclared, runHook, runNativeHook } from \"../../runtime/index.js\";\nimport type { RunHookResult } from \"../../runtime/index.js\";\nimport { fail } from \"../app.js\";\n\n// The CLI hook-dispatch gate: every normalized HookEventName the entrypoint\n// accepts. MUST stay in sync with HookEventName / define-connector ALL_EVENTS —\n// a missing member silently rejects an installed hook at runtime. The\n// hook-dispatch-events test pins this set ⊇ ALL_EVENTS so it cannot drift.\nexport const HOOK_EVENTS: ReadonlySet<string> = new Set<HookEventName>([\n \"SessionStart\",\n \"SessionEnd\",\n \"UserPromptSubmit\",\n \"PreToolUse\",\n \"PostToolUse\",\n \"PreCompact\",\n \"Stop\",\n \"Notification\",\n \"PermissionRequest\",\n \"PostToolUseFailure\",\n \"SubagentStart\",\n \"SubagentStop\",\n \"PostCompact\",\n]);\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 const { values, positionals } = parseArgs({\n args: argv,\n options: {\n connector: { type: \"string\" },\n },\n allowPositionals: true,\n });\n\n const platformId = positionals[0];\n const event = positionals[1];\n if (!platformId || !event) {\n return fail(\"usage: agent-connector hook <platform> <event> --connector <id>\");\n }\n const connectorId = values.connector;\n if (!connectorId || connectorId.trim() === \"\") {\n return fail(\"hook requires --connector <id>\");\n }\n\n // NATIVE PASSTHROUGH: a non-union event name is accepted ONLY when the\n // resolved connector declares it under platforms[<platform>].nativeHooks —\n // dispatch then bypasses the normalized parse/format entirely (raw stdin →\n // handler → verbatim JSON stdout). Undeclared names keep the strict error.\n if (!HOOK_EVENTS.has(event)) {\n if (!(await isNativeHookDeclared(platformId, event, connectorId))) {\n return fail(`unknown hook event \"${event}\"`);\n }\n const stdin = await readAll(process.stdin);\n const reply = await runNativeHook({ platformId, event, connectorId, stdin });\n return exitWithReply(reply);\n }\n\n // Read the entire host payload before dispatching.\n const stdin = await readAll(process.stdin);\n\n const reply = await runHook({\n platformId,\n event: event as HookEventName,\n connectorId,\n stdin,\n });\n\n return exitWithReply(reply);\n}\n\n/** Write a hook reply's stdout/stderr and exit with its code. */\nfunction exitWithReply(reply: RunHookResult): never {\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 process.exit(reply.exitCode);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAcA,SAAS,iBAAiB;AAWnB,IAAM,cAAmC,oBAAI,IAAmB;AAAA,EACrE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAGD,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;AACzD,QAAM,EAAE,QAAQ,YAAY,IAAI,UAAU;AAAA,IACxC,MAAM;AAAA,IACN,SAAS;AAAA,MACP,WAAW,EAAE,MAAM,SAAS;AAAA,IAC9B;AAAA,IACA,kBAAkB;AAAA,EACpB,CAAC;AAED,QAAM,aAAa,YAAY,CAAC;AAChC,QAAM,QAAQ,YAAY,CAAC;AAC3B,MAAI,CAAC,cAAc,CAAC,OAAO;AACzB,WAAO,KAAK,iEAAiE;AAAA,EAC/E;AACA,QAAM,cAAc,OAAO;AAC3B,MAAI,CAAC,eAAe,YAAY,KAAK,MAAM,IAAI;AAC7C,WAAO,KAAK,gCAAgC;AAAA,EAC9C;AAMA,MAAI,CAAC,YAAY,IAAI,KAAK,GAAG;AAC3B,QAAI,CAAE,MAAM,qBAAqB,YAAY,OAAO,WAAW,GAAI;AACjE,aAAO,KAAK,uBAAuB,KAAK,GAAG;AAAA,IAC7C;AACA,UAAMA,SAAQ,MAAM,QAAQ,QAAQ,KAAK;AACzC,UAAMC,SAAQ,MAAM,cAAc,EAAE,YAAY,OAAO,aAAa,OAAAD,OAAM,CAAC;AAC3E,WAAO,cAAcC,MAAK;AAAA,EAC5B;AAGA,QAAM,QAAQ,MAAM,QAAQ,QAAQ,KAAK;AAEzC,QAAM,QAAQ,MAAM,QAAQ;AAAA,IAC1B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,SAAO,cAAc,KAAK;AAC5B;AAGA,SAAS,cAAc,OAA6B;AAClD,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,UAAQ,KAAK,MAAM,QAAQ;AAC7B;","names":["stdin","reply"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { C as ConnectorConfigError, d as defineAction, a as defineCommand, b as defineConfigPatch, c as defineConnector, e as defineHook, f as defineMemory, g as defineNativeHook, h as defineSkill, i as defineStatusline, j as defineSubagent } from './define-connector-
|
|
2
|
-
import { S as ServerDef, M as McpPackageIdentity, R as ResolvedMcpPackageIdentity } from './types-
|
|
3
|
-
export { A as ActionDef, a as ActionResult, b as AuthSpec, C as ChangeRecord, c as ConnectorConfig, D as DetectedPlatform, d as DiagnosticResult, E as EventPayloadMap, H as HookDefinition, e as HookEventName, f as HookParadigm, g as HookResponse, h as HooksConfig, i as HostCtx, I as InstallResult, j as InstallScope, k as MemoryDef, N as NativeHookDef, l as NativeHookEvent, m as NotificationEvent, P as PermissionRequestEvent, n as PlatformCapabilities, o as PlatformId, p as PlatformMemoryOverride, q as PlatformOverride, r as PostToolUseEvent, s as PostToolUseFailureEvent, t as PreCompactEvent, u as PreToolUseEvent, v as ResolvedConnector, w as SessionEndEvent, x as SessionStartEvent, y as StatuslineContext, z as StatuslineDef, B as StopEvent, F as SubagentStartEvent, G as SubagentStopEvent, T as TelemetryAccessor, J as TelemetryConfig, K as TelemetryUsageSummary, L as ToolFilter, O as Transport, U as UserPromptSubmitEvent } from './types-
|
|
1
|
+
export { C as ConnectorConfigError, d as defineAction, a as defineCommand, b as defineConfigPatch, c as defineConnector, e as defineHook, f as defineMemory, g as defineNativeHook, h as defineSkill, i as defineStatusline, j as defineSubagent } from './define-connector-D4UOI__e.js';
|
|
2
|
+
import { S as ServerDef, M as McpPackageIdentity, R as ResolvedMcpPackageIdentity } from './types-htm_wrWo.js';
|
|
3
|
+
export { A as ActionDef, a as ActionResult, b as AuthSpec, C as ChangeRecord, c as ConnectorConfig, D as DetectedPlatform, d as DiagnosticResult, E as EventPayloadMap, H as HookDefinition, e as HookEventName, f as HookParadigm, g as HookResponse, h as HooksConfig, i as HostCtx, I as InstallResult, j as InstallScope, k as MemoryDef, N as NativeHookDef, l as NativeHookEvent, m as NotificationEvent, P as PermissionRequestEvent, n as PlatformCapabilities, o as PlatformId, p as PlatformMemoryOverride, q as PlatformOverride, r as PostToolUseEvent, s as PostToolUseFailureEvent, t as PreCompactEvent, u as PreToolUseEvent, v as ResolvedConnector, w as SessionEndEvent, x as SessionStartEvent, y as StatuslineContext, z as StatuslineDef, B as StopEvent, F as SubagentStartEvent, G as SubagentStopEvent, T as TelemetryAccessor, J as TelemetryConfig, K as TelemetryUsageSummary, L as ToolFilter, O as Transport, U as UserPromptSubmitEvent } from './types-htm_wrWo.js';
|
|
4
4
|
|
|
5
5
|
/** Derive the host-facing MCP server key from a package name. */
|
|
6
6
|
declare function deriveHostAliasFromPackageName(packageName: string): string | undefined;
|
package/dist/index.js
CHANGED
|
@@ -15,8 +15,8 @@ import {
|
|
|
15
15
|
deriveHostAliasFromPackageName,
|
|
16
16
|
inferNpmPackageFromServer,
|
|
17
17
|
resolveMcpPackageIdentity
|
|
18
|
-
} from "./chunk-
|
|
19
|
-
import "./chunk-
|
|
18
|
+
} from "./chunk-S2TAC22E.js";
|
|
19
|
+
import "./chunk-7C3COFOD.js";
|
|
20
20
|
import "./chunk-NBYKLUF6.js";
|
|
21
21
|
import "./chunk-UMQ6NBQR.js";
|
|
22
22
|
import "./chunk-GZGLCCEE.js";
|
|
@@ -3,8 +3,8 @@ import {
|
|
|
3
3
|
installConnector,
|
|
4
4
|
installViaMarketplace,
|
|
5
5
|
parseInstallMethod
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-CG44RWYJ.js";
|
|
7
|
+
import "./chunk-C4NDV6GW.js";
|
|
8
8
|
import "./chunk-CWUPIT72.js";
|
|
9
9
|
import "./chunk-KOFCNA5T.js";
|
|
10
10
|
import "./chunk-WAALPWR4.js";
|
|
@@ -17,16 +17,17 @@ import {
|
|
|
17
17
|
parseTargets,
|
|
18
18
|
print,
|
|
19
19
|
renderInstallResult
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-PTITNBSS.js";
|
|
21
21
|
import "./chunk-GDIAHWNY.js";
|
|
22
|
-
import "./chunk-
|
|
22
|
+
import "./chunk-ITVST3SZ.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-ZYB2UFEN.js";
|
|
28
|
+
import "./chunk-D35FMUFZ.js";
|
|
29
|
+
import "./chunk-S2TAC22E.js";
|
|
30
|
+
import "./chunk-7C3COFOD.js";
|
|
30
31
|
import "./chunk-NBYKLUF6.js";
|
|
31
32
|
import "./chunk-H53QZQJI.js";
|
|
32
33
|
import "./chunk-BEFVJ2OE.js";
|
|
@@ -543,4 +544,4 @@ async function run(argv) {
|
|
|
543
544
|
export {
|
|
544
545
|
run
|
|
545
546
|
};
|
|
546
|
-
//# sourceMappingURL=install-
|
|
547
|
+
//# sourceMappingURL=install-XNTRLUZI.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/commands/install.ts","../src/core/fetch-source.ts"],"sourcesContent":["/**\n * cli/commands/install — deploy a connector across its target platforms.\n *\n * Resolves the connector config (--connector <path>, else findConnectorConfig\n * walking up from the project dir), loads it into a live ResolvedConnector, and\n * hands it to the chosen DELIVERY METHOD's orchestration:\n *\n * --method direct (default) — the installer renders each host's native\n * MCP + hook + content config in place (zero behavior\n * change for existing scripts).\n * --method marketplace — stage the connector's plugin bundle under the\n * data-root and DRIVE the host's own plugin/marketplace\n * install flow (v1 driver: claude-code; other hosts get\n * never-silent skip/warn records with manual commands).\n *\n * Both methods emit the same ChangeRecords, rendered as a readable diff;\n * --dry-run renders the plan without writing or spawning. A double-install\n * guard (both directions) enforces exactly one method per (connector, host,\n * scope) — a refusal is a `warn` record, so the exit-1-on-warn convention\n * carries over.\n */\n\nimport { parseArgs } from \"node:util\";\n\nimport { installConnector } from \"../../core/installer.js\";\nimport { installViaMarketplace, parseInstallMethod } from \"../../core/marketplace.js\";\nimport { findConnectorConfig, loadConnectorFromPath } from \"../../core/load-connector.js\";\nimport { classifySource, resolveRemoteSource } from \"../../core/fetch-source.js\";\nimport {\n buildConnectorSummary,\n fail,\n maybePrintBanner,\n parseScope,\n parseTargets,\n print,\n renderInstallResult,\n} from \"../app.js\";\n\nexport async function run(argv: string[]): Promise<number> {\n const { values, positionals } = parseArgs({\n args: argv,\n options: {\n method: { type: \"string\", default: \"direct\" },\n scope: { type: \"string\", default: \"user\" },\n targets: { type: \"string\" },\n connector: { type: \"string\" },\n project: { type: \"string\" },\n \"dry-run\": { type: \"boolean\", default: false },\n // Memory surface: overwrite USER-EDITED managed blocks (hash drift).\n // Default behavior is warn-and-leave; --force backs the file up first.\n force: { type: \"boolean\", default: false },\n // Decorative-banner suppressor (no effect on command output bytes).\n quiet: { type: \"boolean\", default: false },\n },\n // A single positional <source> (local path OR remote GitHub spec) is the\n // ergonomic alias of --connector; either may be remote.\n allowPositionals: true,\n });\n\n maybePrintBanner({ quiet: values.quiet });\n\n const method = parseInstallMethod(values.method);\n if (method == null) {\n return fail(`invalid --method \"${values.method}\" (use direct|marketplace)`);\n }\n\n const projectDir = values.project ?? process.cwd();\n\n // A connector source may arrive as the first positional or via --connector,\n // and may be a LOCAL path or a REMOTE source spec (GitHub/raw git, npm:, or\n // archive tarball). The positional and the flag are equivalent; reject\n // ambiguity when both name a source.\n const positionalSource = positionals[0];\n if (positionalSource != null && values.connector != null) {\n return fail(\"pass a connector source as EITHER the positional <source> OR --connector, not both.\");\n }\n const source = positionalSource ?? values.connector;\n\n const scope = parseScope(values.scope);\n if (scope == null) return fail(`invalid --scope \"${values.scope}\" (use user|project)`);\n if (method === \"marketplace\" && scope !== \"user\") {\n return fail(\n \"--method marketplace supports --scope user only (project-scope plugin installs are deferred)\",\n );\n }\n\n // Resolve the source to a loadable connector. A REMOTE spec is fetched into a\n // STABLE cache dir under the data-root and GATED (must be an agent-connector\n // package) before handing off to the existing install flow. A LOCAL source —\n // or no source at all — keeps today's path-discovery behavior unchanged.\n let connector: Awaited<ReturnType<typeof loadConnectorFromPath>>[\"connector\"];\n let modulePath: string;\n const spec = source != null ? classifySource(source) : null;\n if (source != null && spec == null) {\n return fail(\n `\"${source}\" is not a local path or a recognizable connector source ` +\n \"(owner/repo[/subpath][#ref], github URL, git URL, npm:<package>[@version], archive:<path-or-url>, or .tgz/.tar.gz).\",\n );\n }\n if (spec != null && spec.kind === \"remote\") {\n try {\n const resolved = await resolveRemoteSource(spec.remote);\n ({ connector, modulePath } = resolved);\n } catch (err) {\n return fail(err instanceof Error ? err.message : String(err));\n }\n } else {\n const configPath = source ?? findConnectorConfig(projectDir);\n if (!configPath) {\n return fail(\n \"no connector config found. Pass a <source> (local path, owner/repo, npm:<package>, or archive tarball) or \" +\n \"--connector <path>, or add an agent-connector.config.{mjs,js,json} to your project.\",\n );\n }\n ({ connector, modulePath } = await loadConnectorFromPath(configPath));\n }\n\n const targets = parseTargets(values.targets);\n\n const result =\n method === \"marketplace\"\n ? await installViaMarketplace({\n connector,\n modulePath,\n scope,\n projectDir,\n dryRun: values[\"dry-run\"],\n ...(targets ? { targets } : {}),\n })\n : await installConnector({\n connector,\n modulePath,\n scope,\n projectDir,\n dryRun: values[\"dry-run\"],\n force: values.force,\n ...(targets ? { targets } : {}),\n });\n\n result.connector = buildConnectorSummary(connector);\n print(renderInstallResult(result, \"install\"));\n return result.changes.some((c) => c.action === \"warn\") ? 1 : 0;\n}\n","/**\n * core/fetch-source — resolve an `install <source>` argument that may be a\n * LOCAL path OR a REMOTE package/source spec into a local connector-config path.\n *\n * Responsibilities (MVP):\n * 1. CLASSIFY a source string as local-path vs. remote GitHub spec. A value\n * that exists on disk, or that looks like a filesystem path (starts with\n * `.`, `/`, `~`, a `file://` URL, or a Windows drive/UNC), stays LOCAL and\n * keeps today's behavior. Everything else is parsed as a remote spec.\n * 2. PARSE the supported remote forms:\n * owner/repo · owner/repo#ref · owner/repo/sub · owner/repo/sub#ref\n * github:owner/repo · https://github.com/owner/repo[/tree/ref/sub]\n * git@github.com:owner/repo.git · the .git suffix on any of the above.\n * npm:<package>[@version] · archive:<path-or-url> · *.tgz / *.tar.gz\n * 3. FETCH + PERSIST the repo to a STABLE cache dir under the data-root\n * (`sources/<owner>__<repo>[__<ref>]/`), NOT a temp dir, so a connector\n * with a local stdio server keeps resolving after install. Re-fetch updates\n * it. `git clone --depth 1` is preferred; a codeload tarball is the\n * fallback when `git` is unavailable.\n * 4. GATE: the fetched (sub)dir MUST contain an `agent-connector.config.*`\n * that loads — otherwise the target is not an agent-connector connector.\n *\n * The actual fetch is injected via a {@link Fetcher} seam so tests can drive the\n * pipeline against a `file://` git fixture without any real network/GitHub hit.\n */\n\nimport { execFileSync } from \"node:child_process\";\nimport { createHash } from \"node:crypto\";\nimport {\n existsSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n renameSync,\n rmSync,\n writeFileSync,\n} from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { basename, isAbsolute, join, relative, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nimport { findConnectorConfig, loadConnectorFromPath } from \"./load-connector.js\";\nimport { sourcesDir } from \"./paths.js\";\nimport type { ResolvedConnector } from \"./types.js\";\n\n/** A parsed remote source to fetch (a GitHub spec, or a raw git clone URL such\n * as `file://`/`ssh://`/`git@…`). `ref` is a branch/tag/sha; `subpath` is the\n * directory within the repo that holds the connector config. */\nexport interface RemoteSource {\n owner: string;\n repo: string;\n /**\n * Non-git source kind. Omitted for GitHub/raw-git sources to preserve the\n * original object shape used by tests and callers.\n */\n sourceKind?: \"npm\" | \"archive\";\n /** Branch / tag / commit. Undefined → the repo default branch. */\n ref?: string;\n /** Sub-directory inside the repo holding the connector config. */\n subpath?: string;\n /**\n * A raw clone URL (file://, ssh://, git@host:…, https://non-github) when the\n * source is NOT a github.com owner/repo we can derive a URL for. Present → the\n * tarball fallback is unavailable (we can only `git clone` it).\n */\n cloneUrl?: string;\n /** npm package spec for sourceKind:\"npm\", e.g. \"@acme/db-mcp@1.2.3\". */\n packageSpec?: string;\n /** npm package name without version/tag, e.g. \"@acme/db-mcp\". */\n packageName?: string;\n /** Tarball path or URL for sourceKind:\"archive\". */\n archiveUrl?: string;\n}\n\n/** The classification of an `install <source>` argument. */\nexport type SourceSpec =\n | { kind: \"local\"; value: string }\n | { kind: \"remote\"; remote: RemoteSource };\n\nconst GITHUB_SEG = /^[A-Za-z0-9._-]+$/;\nconst NPM_UNSCOPED_NAME_RE = /^[a-z0-9][a-z0-9._~-]*$/i;\nconst NPM_SCOPE_RE = /^@[a-z0-9][a-z0-9._~-]*$/i;\n\nfunction isSafeGitHubSegment(segment: string): boolean {\n return GITHUB_SEG.test(segment) && segment !== \".\" && segment !== \"..\";\n}\n\nfunction isSafeSubpath(subpath: string | undefined): boolean {\n if (subpath === undefined || subpath === \"\") return true;\n return subpath\n .split(\"/\")\n .every((segment) => segment !== \"\" && segment !== \".\" && segment !== \"..\");\n}\n\n/**\n * True when `value` should be treated as a LOCAL path (existing behavior),\n * before any remote-spec parse is attempted. Conservative on purpose: a path\n * that exists wins, and the common path sigils (`.`, `/`, `~`, `file://`, a\n * Windows drive letter or UNC) are local even when nothing is on disk yet.\n */\nexport function looksLocal(value: string): boolean {\n if (value === \"\") return true;\n if (existsSync(value)) return true;\n if (\n value.startsWith(\"./\") ||\n value.startsWith(\"../\") ||\n value === \".\" ||\n value === \"..\" ||\n value.startsWith(\"/\") ||\n value.startsWith(\"~\") ||\n value.startsWith(\"file://\")\n ) {\n return true;\n }\n // Windows drive (C:\\ or C:/) or UNC (\\\\server\\share).\n if (/^[A-Za-z]:[\\\\/]/.test(value) || value.startsWith(\"\\\\\\\\\")) return true;\n return false;\n}\n\n/**\n * Parse a remote GitHub spec into a {@link RemoteSource}, or null when `value`\n * is not a recognizable GitHub source. Supports the bare `owner/repo[/sub][#ref]`\n * shorthand, `github:owner/repo`, full `https://github.com/...` (incl.\n * `/tree/<ref>/<subpath>`), and `git@github.com:owner/repo.git`.\n */\nexport function parseRemoteSource(value: string): RemoteSource | null {\n const raw = value.trim();\n if (raw === \"\") return null;\n\n // ── git@github.com:owner/repo(.git) ───────────────────────────────────────\n const scp = raw.match(/^git@github\\.com:([^/]+)\\/(.+?)(?:\\.git)?$/);\n if (scp) {\n return finalizeFromPath(scp[1]!, scp[2]!, undefined);\n }\n\n // ── https://github.com/owner/repo[/tree/<ref>/<subpath>][.git][#ref] ───────\n if (/^https?:\\/\\//i.test(raw) || raw.startsWith(\"git://\")) {\n let url: URL;\n try {\n url = new URL(raw.replace(/^git:\\/\\//, \"https://\"));\n } catch {\n return null;\n }\n if (!/(^|\\.)github\\.com$/i.test(url.hostname)) return null;\n const segs = url.pathname.replace(/^\\/+/, \"\").split(\"/\").filter(Boolean);\n if (segs.length < 2) return null;\n const owner = segs[0]!;\n let repo = segs[1]!.replace(/\\.git$/, \"\");\n let ref: string | undefined;\n let subpath: string | undefined;\n // /tree/<ref>/<subpath...> selects a ref + sub-directory.\n if (segs[2] === \"tree\" || segs[2] === \"blob\") {\n ref = segs[3];\n if (segs.length > 4) subpath = segs.slice(4).join(\"/\");\n } else if (segs.length > 2) {\n subpath = segs.slice(2).join(\"/\");\n }\n const hash = url.hash.replace(/^#/, \"\");\n if (hash) ref = hash;\n if (!isSafeGitHubSegment(owner) || !isSafeGitHubSegment(repo)) return null;\n return cleanRemote({ owner, repo, ref, subpath });\n }\n\n // ── github:owner/repo[...] ────────────────────────────────────────────────\n const shorthand = raw.startsWith(\"github:\") ? raw.slice(\"github:\".length) : raw;\n\n // ── owner/repo[/subpath][#ref] ────────────────────────────────────────────\n // Reject anything that doesn't look like the bare `owner/repo` shape (a single\n // path segment, or a leading slash) so we never misread a stray token.\n const [pathPart, refPart] = splitHash(shorthand);\n const segs = pathPart.split(\"/\").filter(Boolean);\n if (segs.length < 2) return null;\n const owner = segs[0]!;\n const repo = segs[1]!.replace(/\\.git$/, \"\");\n const subpath = segs.length > 2 ? segs.slice(2).join(\"/\") : undefined;\n if (!isSafeGitHubSegment(owner) || !isSafeGitHubSegment(repo)) return null;\n return cleanRemote({ owner, repo, ref: refPart, subpath });\n}\n\n/** Split a \"<path>#<ref>\" into [path, ref?]. */\nfunction splitHash(value: string): [string, string | undefined] {\n const i = value.indexOf(\"#\");\n if (i === -1) return [value, undefined];\n const ref = value.slice(i + 1).trim();\n return [value.slice(0, i), ref === \"\" ? undefined : ref];\n}\n\n/** scp-form helper: the repo half may itself carry `/sub` and `#ref`. */\nfunction finalizeFromPath(owner: string, repoAndRest: string, _ref: undefined): RemoteSource | null {\n const [pathPart, ref] = splitHash(repoAndRest);\n const segs = pathPart.split(\"/\").filter(Boolean);\n const repo = (segs[0] ?? \"\").replace(/\\.git$/, \"\");\n const subpath = segs.length > 1 ? segs.slice(1).join(\"/\") : undefined;\n if (!isSafeGitHubSegment(owner) || !isSafeGitHubSegment(repo)) return null;\n return cleanRemote({ owner, repo, ref, subpath });\n}\n\n/**\n * A git-refname-safe ref charset: branch/tag/sha names plus the `/`, `.`, `_`,\n * `-` they may contain. A LEADING `-` is rejected so a ref can never be read as\n * a git flag (e.g. `--upload-pack=…`) when passed to `git clone --branch`, and\n * the constrained charset keeps cache-dir names clean. Empty is invalid.\n */\nconst REF_RE = /^[A-Za-z0-9][A-Za-z0-9._/-]*$/;\n\n/** True when `ref` is a safe git refname (defense-in-depth before exec). */\nexport function isSafeRef(ref: string): boolean {\n return REF_RE.test(ref);\n}\n\n/**\n * Drop empty optional fields so equality/snapshot comparisons stay clean.\n * Returns null when a present `ref` is not git-refname-safe (defense-in-depth:\n * never pass an attacker-shaped ref to `git clone --branch`).\n */\nfunction cleanRemote(r: RemoteSource): RemoteSource | null {\n if (r.ref !== undefined && !isSafeRef(r.ref)) return null;\n if (!isSafeSubpath(r.subpath)) return null;\n const out: RemoteSource = { owner: r.owner, repo: r.repo };\n if (r.ref) out.ref = r.ref;\n if (r.subpath && r.subpath !== \"\") out.subpath = r.subpath;\n return out;\n}\n\n/**\n * Parse a RAW git clone URL (NOT a github.com owner/repo): `file://…`,\n * `ssh://…`, `git@host:owner/repo`, or `https://<non-github>/…`. These are\n * `git clone`-able directly. A trailing `#ref` selects a branch/tag/sha. These\n * forms point at a repo root (no in-URL subpath). Returns null for anything\n * that isn't a clone URL.\n */\nexport function parseGitUrl(value: string): RemoteSource | null {\n const [urlPart, ref] = splitHash(value.trim());\n const isScheme =\n urlPart.startsWith(\"file://\") ||\n urlPart.startsWith(\"ssh://\") ||\n urlPart.startsWith(\"git://\") ||\n /^https?:\\/\\//i.test(urlPart);\n const isScp = /^[^@\\s]+@[^:\\s]+:.+/.test(urlPart) && !urlPart.startsWith(\"git@github.com:\");\n if (!isScheme && !isScp) return null;\n // Reject an unsafe ref (e.g. a leading-dash flag) before it reaches git.\n if (ref !== undefined && !isSafeRef(ref)) return null;\n\n // Derive a stable owner/repo cache key from the URL's last two path segments.\n const stripped = urlPart.replace(/\\.git$/, \"\").replace(/\\/+$/, \"\");\n const segs = stripped.split(/[/:]/).filter(Boolean);\n const repo = segs[segs.length - 1] ?? \"repo\";\n const owner = segs[segs.length - 2] ?? \"git\";\n const out: RemoteSource = { owner, repo, cloneUrl: urlPart };\n if (ref) out.ref = ref;\n return out;\n}\n\n/** Parse an explicit npm source: npm:<package>[@version-or-tag]. */\nexport function parseNpmSource(value: string): RemoteSource | null {\n const raw = value.trim();\n if (!raw.startsWith(\"npm:\")) return null;\n const spec = raw.slice(\"npm:\".length).trim();\n if (spec === \"\" || /\\s/.test(spec) || spec.startsWith(\"-\")) return null;\n\n let packageName: string;\n if (spec.startsWith(\"@\")) {\n const match = spec.match(/^(@[^/@\\s]+\\/[^/@\\s]+)(?:@([^/\\s]+))?$/);\n if (!match) return null;\n packageName = match[1]!;\n } else {\n const match = spec.match(/^([^/@\\s]+)(?:@([^/\\s]+))?$/);\n if (!match) return null;\n packageName = match[1]!;\n }\n\n const parts = packageName.startsWith(\"@\") ? packageName.split(\"/\") : [packageName];\n if (parts.length === 2) {\n if (!NPM_SCOPE_RE.test(parts[0]!) || !NPM_UNSCOPED_NAME_RE.test(parts[1]!)) {\n return null;\n }\n } else if (parts.length === 1) {\n if (!NPM_UNSCOPED_NAME_RE.test(parts[0]!)) return null;\n } else {\n return null;\n }\n\n return {\n sourceKind: \"npm\",\n owner: \"npm\",\n repo: packageName.replace(/^@/, \"\").replace(/\\//g, \"__\"),\n packageName,\n packageSpec: spec,\n };\n}\n\nfunction stripQueryAndHash(value: string): string {\n return value.split(/[?#]/, 1)[0] ?? value;\n}\n\nfunction archivePathname(value: string): string {\n try {\n const url = new URL(value);\n return url.pathname;\n } catch {\n return value;\n }\n}\n\nfunction isTarballLike(value: string): boolean {\n const p = stripQueryAndHash(archivePathname(value)).toLowerCase();\n return p.endsWith(\".tgz\") || p.endsWith(\".tar.gz\");\n}\n\n/** Parse a tarball archive source: archive:<path-or-url> or direct *.tgz/*.tar.gz. */\nexport function parseArchiveSource(value: string): RemoteSource | null {\n const raw = value.trim();\n const explicit = raw.startsWith(\"archive:\");\n const source = explicit ? raw.slice(\"archive:\".length).trim() : raw;\n if (source === \"\") return null;\n if (!explicit && !isTarballLike(source)) return null;\n\n const pathish = stripQueryAndHash(archivePathname(source));\n const base = basename(pathish).replace(/\\.tar\\.gz$/i, \"\").replace(/\\.tgz$/i, \"\");\n const repo = base || \"source\";\n return {\n sourceKind: \"archive\",\n owner: \"archive\",\n repo,\n archiveUrl: source,\n };\n}\n\n/**\n * Classify an `install <source>` argument. A raw git clone URL (file://, ssh://,\n * git@…) or a GitHub spec is REMOTE (a fetch); a local FILESYSTEM path (existing\n * or path-shaped, EXCLUDING file:// which is a clone URL) keeps today's\n * behavior. Returns null when a non-local value is NOT a recognizable remote.\n */\nexport function classifySource(value: string): SourceSpec | null {\n const npm = parseNpmSource(value);\n if (npm) return { kind: \"remote\", remote: npm };\n const archive = parseArchiveSource(value);\n if (archive) return { kind: \"remote\", remote: archive };\n // A raw git clone URL (incl. file://) is always a FETCH, never a config path —\n // even though file:// is \"path-shaped\" it names a clonable repo, not a config.\n const gitUrl = parseGitUrl(value);\n if (gitUrl) return { kind: \"remote\", remote: gitUrl };\n if (looksLocal(value)) return { kind: \"local\", value };\n const remote = parseRemoteSource(value);\n return remote ? { kind: \"remote\", remote } : null;\n}\n\n/** The clone URL for a remote source (its raw cloneUrl, else the github URL). */\nexport function cloneUrl(r: RemoteSource): string {\n if (r.sourceKind === \"npm\" || r.sourceKind === \"archive\") {\n throw new Error(`${describeRemote(r)} is not a git clone source`);\n }\n return r.cloneUrl ?? `https://github.com/${r.owner}/${r.repo}.git`;\n}\n\n/** The codeload tarball URL for a github source (default branch when no ref). */\nexport function tarballUrl(r: RemoteSource): string {\n const ref = r.ref ?? \"HEAD\";\n return `https://codeload.github.com/${r.owner}/${r.repo}/tar.gz/${ref}`;\n}\n\n/** The STABLE cache directory a remote source is fetched into. */\nexport function sourceCacheDir(r: RemoteSource): string {\n const safe = (s: string) => s.replace(/[^A-Za-z0-9._-]/g, \"-\");\n if (r.sourceKind === \"npm\") {\n return join(sourcesDir(), `npm__${safe(r.packageName ?? r.repo)}__${shortHash(r.packageSpec ?? r.repo)}`);\n }\n if (r.sourceKind === \"archive\") {\n return join(sourcesDir(), `archive__${safe(r.repo)}__${shortHash(r.archiveUrl ?? r.repo)}`);\n }\n // A raw clone URL hashes its full URL into the key so two different file://\n // repos that share an owner/repo basename never collide in the cache.\n const base = r.cloneUrl\n ? `${safe(r.owner)}__${safe(r.repo)}__${shortHash(r.cloneUrl)}`\n : `${safe(r.owner)}__${safe(r.repo)}`;\n const name = r.ref ? `${base}__${safe(r.ref)}` : base;\n return join(sourcesDir(), name);\n}\n\n/** A short, filename-safe hash for disambiguating raw clone URLs in the cache. */\nfunction shortHash(value: string): string {\n return createHash(\"sha256\").update(value).digest(\"hex\").slice(0, 8);\n}\n\n/**\n * A fetcher fetches `remote` into the stable directory `dest`. Injected so tests\n * can drive the resolve pipeline against a `file://` git fixture (no network).\n * The default {@link gitFetcher} clones over HTTPS.\n */\nexport type Fetcher = (remote: RemoteSource, dest: string) => void | Promise<void>;\n\n/** True when a usable `git` is on PATH (probed once per process via a cheap call). */\nfunction gitAvailable(): boolean {\n try {\n execFileSync(\"git\", [\"--version\"], { stdio: \"ignore\" });\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * The default fetcher: `git clone --depth 1 [--branch <ref>] <url> <dest>`.\n * Re-fetch replaces the cache dir so the clone reflects the requested ref. The\n * caller may override the clone URL via `urlFor` (tests pass a `file://` repo).\n */\nexport function makeGitFetcher(urlFor: (r: RemoteSource) => string = cloneUrl): Fetcher {\n return (remote, dest) => {\n if (remote.sourceKind === \"npm\" || remote.sourceKind === \"archive\") {\n throw new Error(`${describeRemote(remote)} is not a git clone source`);\n }\n if (!gitAvailable()) {\n throw new Error(\n \"git is required to fetch a remote connector source but was not found on PATH. \" +\n \"Install git, or pass a local --connector <path>.\",\n );\n }\n rmSync(dest, { recursive: true, force: true });\n mkdirSync(dest, { recursive: true });\n const args = [\"clone\", \"--depth\", \"1\"];\n if (remote.ref) args.push(\"--branch\", remote.ref);\n args.push(urlFor(remote), dest);\n try {\n execFileSync(\"git\", args, { stdio: \"ignore\" });\n } catch (err) {\n throw new Error(\n `failed to clone ${urlFor(remote)}${remote.ref ? ` (ref ${remote.ref})` : \"\"}: ` +\n `${err instanceof Error ? err.message : String(err)}`,\n );\n }\n };\n}\n\n/**\n * Tarball fallback: download the GitHub codeload `tar.gz` and extract it with\n * the system `tar` (present on Linux, macOS, and Windows 10+). codeload nests\n * everything under a single `<repo>-<ref>/` top dir, which we flatten into\n * `dest`. Used only when `git` is unavailable.\n */\nasync function tarballFetch(remote: RemoteSource, dest: string): Promise<void> {\n const url = tarballUrl(remote);\n const res = await fetch(url);\n if (!res.ok) {\n throw new Error(`failed to download ${url}: HTTP ${res.status} ${res.statusText}`);\n }\n await extractTarballBuffer(Buffer.from(await res.arrayBuffer()), dest);\n}\n\nfunction extractTarballBuffer(buf: Buffer, dest: string): void {\n const work = join(tmpdir(), `ac-src-${process.pid}-${Date.now()}`);\n mkdirSync(work, { recursive: true });\n const tarPath = join(work, \"source.tar.gz\");\n writeFileSync(tarPath, buf);\n try {\n execFileSync(\"tar\", [\"-xzf\", tarPath, \"-C\", work], { stdio: \"ignore\" });\n } catch (err) {\n rmSync(work, { recursive: true, force: true });\n throw new Error(\n \"neither git nor a usable `tar` is available to fetch a remote connector \" +\n `source (${err instanceof Error ? err.message : String(err)}). Install git ` +\n \"or tar, or pass a local --connector <path>.\",\n );\n }\n // codeload nests under a single `<repo>-<ref>/` directory — flatten it.\n const entries = readdirSync(work).filter((e) => e !== \"source.tar.gz\");\n const top = entries.length === 1 ? join(work, entries[0]!) : work;\n rmSync(dest, { recursive: true, force: true });\n renameSync(top, dest);\n rmSync(work, { recursive: true, force: true });\n}\n\nasync function archiveFetch(remote: RemoteSource, dest: string): Promise<void> {\n const source = remote.archiveUrl;\n if (!source) throw new Error(\"archive source is missing archiveUrl\");\n\n if (/^https?:\\/\\//i.test(source)) {\n const res = await fetch(source);\n if (!res.ok) {\n throw new Error(`failed to download ${source}: HTTP ${res.status} ${res.statusText}`);\n }\n await extractTarballBuffer(Buffer.from(await res.arrayBuffer()), dest);\n return;\n }\n\n const archivePath = source.startsWith(\"file://\") ? fileURLToPath(source) : source;\n if (!existsSync(archivePath)) {\n throw new Error(`archive source not found: ${source}`);\n }\n extractTarballBuffer(readFileSync(archivePath), dest);\n}\n\nfunction npmAvailable(): boolean {\n try {\n execFileSync(\"npm\", [\"--version\"], { stdio: \"ignore\" });\n return true;\n } catch {\n return false;\n }\n}\n\nasync function npmFetch(remote: RemoteSource, dest: string): Promise<void> {\n const spec = remote.packageSpec;\n if (!spec) throw new Error(\"npm source is missing packageSpec\");\n if (!npmAvailable()) {\n throw new Error(\n `npm is required to fetch npm:${spec} but was not found on PATH. ` +\n \"Install npm, or pass a local --connector <path>.\",\n );\n }\n\n const work = join(tmpdir(), `ac-npm-${process.pid}-${Date.now()}`);\n mkdirSync(work, { recursive: true });\n let stdout: string;\n try {\n stdout = execFileSync(\n \"npm\",\n [\"pack\", spec, \"--pack-destination\", work, \"--silent\"],\n { encoding: \"utf8\" },\n );\n } catch (err) {\n rmSync(work, { recursive: true, force: true });\n throw new Error(\n `failed to fetch npm:${spec}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n const packed = stdout.trim().split(/\\r?\\n/).filter(Boolean).pop();\n if (!packed) {\n rmSync(work, { recursive: true, force: true });\n throw new Error(`failed to fetch npm:${spec}: npm pack produced no tarball`);\n }\n const tarPath = isAbsolute(packed) ? packed : join(work, packed);\n try {\n extractTarballBuffer(readFileSync(tarPath), dest);\n } finally {\n rmSync(work, { recursive: true, force: true });\n }\n}\n\n/**\n * The default network fetcher: `git clone` when git is on PATH, otherwise the\n * codeload tarball fallback (github.com sources only — a raw clone URL can only\n * be `git clone`d, so it requires git). A clear error is thrown when neither\n * applicable path works.\n */\nexport const gitFetcher: Fetcher = async (remote, dest) => {\n if (remote.sourceKind === \"npm\") {\n await npmFetch(remote, dest);\n return;\n }\n if (remote.sourceKind === \"archive\") {\n await archiveFetch(remote, dest);\n return;\n }\n if (gitAvailable()) {\n makeGitFetcher()(remote, dest);\n return;\n }\n if (remote.cloneUrl) {\n throw new Error(\n `git is required to fetch ${remote.cloneUrl} but was not found on PATH. ` +\n \"Install git, or pass a local --connector <path>.\",\n );\n }\n await tarballFetch(remote, dest);\n};\n\n/** The resolved output of {@link resolveRemoteSource}. */\nexport interface ResolvedSource {\n /** Absolute path to the agent-connector.config.* found inside the fetch. */\n configPath: string;\n /** The directory the source was fetched into (stable, under the data-root). */\n sourceDir: string;\n /** The (sub)directory the config was found in. */\n connectorDir: string;\n /** The live connector + its absolute module path (ready for the install flow). */\n connector: ResolvedConnector;\n modulePath: string;\n}\n\n/** Options for {@link resolveRemoteSource}. */\nexport interface ResolveOptions {\n /** Override the fetch (tests). Defaults to {@link gitFetcher}. */\n fetcher?: Fetcher;\n}\n\n/**\n * Fetch a remote source into its stable cache dir, honor the subpath, and GATE\n * it as a real agent-connector package: `findConnectorConfig` must locate an\n * `agent-connector.config.{mjs,js,json}` that `loadConnectorFromPath` can load.\n * Throws a clear, specific error when the target is not an agent-connector\n * connector. Returns everything the install flow needs.\n */\nexport async function resolveRemoteSource(\n remote: RemoteSource,\n opts: ResolveOptions = {},\n): Promise<ResolvedSource> {\n const fetcher = opts.fetcher ?? gitFetcher;\n const sourceDir = sourceCacheDir(remote);\n mkdirSync(sourcesDir(), { recursive: true });\n await fetcher(remote, sourceDir);\n\n const label = describeRemote(remote);\n if (!existsSync(sourceDir)) {\n throw new Error(`failed to fetch ${label}: nothing was written to ${sourceDir}`);\n }\n\n // Honor the subpath; guard against a `..` escape out of the fetched dir.\n // Containment is checked with path.relative (NOT a bare string prefix, which\n // a sibling dir sharing the cache-key prefix would defeat) — mirroring the\n // connectorDir() guard in paths.ts: reject when the relative path is empty,\n // starts with \"..\", or is absolute.\n const root = resolve(sourceDir);\n const searchDir = remote.subpath ? resolve(root, remote.subpath) : root;\n if (remote.subpath) {\n const rel = relative(root, searchDir);\n if (rel === \"\" || rel.startsWith(\"..\") || isAbsolute(rel)) {\n throw new Error(`subpath escapes the fetched source: ${remote.subpath}`);\n }\n }\n if (!existsSync(searchDir)) {\n throw new Error(\n `${label}: subpath \"${remote.subpath}\" does not exist in the repository.`,\n );\n }\n\n // ── PACKAGE GATE ──────────────────────────────────────────────────────────\n // Search only WITHIN the fetched (sub)dir. findConnectorConfig walks UPWARD to\n // the filesystem root, so confine the start dir and verify the hit is inside.\n const configPath = findConfigWithin(searchDir);\n if (!configPath) {\n throw new Error(\n `${label} is not an agent-connector connector — no ` +\n `agent-connector.config.{mjs,js,json} found in the repo` +\n (remote.subpath ? ` at subpath \"${remote.subpath}\"` : \"\") +\n \". The target must be a package built with agent-connector (defineConnector).\",\n );\n }\n\n let connector: ResolvedConnector;\n let modulePath: string;\n try {\n ({ connector, modulePath } = await loadConnectorFromPath(configPath));\n } catch (err) {\n throw new Error(\n `${label}: found ${configPath} but it failed to load as an agent-connector ` +\n `connector (${err instanceof Error ? err.message : String(err)}). The target ` +\n \"must be a package built with agent-connector (defineConnector).\",\n );\n }\n\n return {\n configPath,\n sourceDir,\n connectorDir: searchDir,\n connector,\n modulePath,\n };\n}\n\n/**\n * Locate `agent-connector.config.*` strictly within `dir` (not its ancestors).\n * `findConnectorConfig` walks upward, so we scope the result by asserting the\n * hit is in `dir` itself.\n */\nfunction findConfigWithin(dir: string): string | null {\n const hit = findConnectorConfig(dir);\n if (!hit) return null;\n // Must live directly in the (sub)dir we were pointed at — reject an ancestor\n // hit so a parent dir's config can't masquerade as the repo's.\n const dirAbs = resolve(dir);\n const hitDir = resolve(hit, \"..\");\n return hitDir === dirAbs ? hit : null;\n}\n\n/** A human label for a remote source used in error messages. */\nexport function describeRemote(r: RemoteSource): string {\n if (r.sourceKind === \"npm\") return `npm:${r.packageSpec ?? r.repo}`;\n if (r.sourceKind === \"archive\") return `archive:${r.archiveUrl ?? r.repo}`;\n let s = r.cloneUrl ?? `${r.owner}/${r.repo}`;\n if (r.subpath) s += `/${r.subpath}`;\n if (r.ref) s += `#${r.ref}`;\n return s;\n}\n"],"mappings":"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","names":["segs","owner","repo","subpath"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli/commands/install.ts","../src/core/fetch-source.ts"],"sourcesContent":["/**\n * cli/commands/install — deploy a connector across its target platforms.\n *\n * Resolves the connector config (--connector <path>, else findConnectorConfig\n * walking up from the project dir), loads it into a live ResolvedConnector, and\n * hands it to the chosen DELIVERY METHOD's orchestration:\n *\n * --method direct (default) — the installer renders each host's native\n * MCP + hook + content config in place (zero behavior\n * change for existing scripts).\n * --method marketplace — stage the connector's plugin bundle under the\n * data-root and DRIVE the host's own plugin/marketplace\n * install flow (v1 driver: claude-code; other hosts get\n * never-silent skip/warn records with manual commands).\n *\n * Both methods emit the same ChangeRecords, rendered as a readable diff;\n * --dry-run renders the plan without writing or spawning. A double-install\n * guard (both directions) enforces exactly one method per (connector, host,\n * scope) — a refusal is a `warn` record, so the exit-1-on-warn convention\n * carries over.\n */\n\nimport { parseArgs } from \"node:util\";\n\nimport { installConnector } from \"../../core/installer.js\";\nimport { installViaMarketplace, parseInstallMethod } from \"../../core/marketplace.js\";\nimport { findConnectorConfig, loadConnectorFromPath } from \"../../core/load-connector.js\";\nimport { classifySource, resolveRemoteSource } from \"../../core/fetch-source.js\";\nimport {\n buildConnectorSummary,\n fail,\n maybePrintBanner,\n parseScope,\n parseTargets,\n print,\n renderInstallResult,\n} from \"../app.js\";\n\nexport async function run(argv: string[]): Promise<number> {\n const { values, positionals } = parseArgs({\n args: argv,\n options: {\n method: { type: \"string\", default: \"direct\" },\n scope: { type: \"string\", default: \"user\" },\n targets: { type: \"string\" },\n connector: { type: \"string\" },\n project: { type: \"string\" },\n \"dry-run\": { type: \"boolean\", default: false },\n // Memory surface: overwrite USER-EDITED managed blocks (hash drift).\n // Default behavior is warn-and-leave; --force backs the file up first.\n force: { type: \"boolean\", default: false },\n // Decorative-banner suppressor (no effect on command output bytes).\n quiet: { type: \"boolean\", default: false },\n },\n // A single positional <source> (local path OR remote GitHub spec) is the\n // ergonomic alias of --connector; either may be remote.\n allowPositionals: true,\n });\n\n maybePrintBanner({ quiet: values.quiet });\n\n const method = parseInstallMethod(values.method);\n if (method == null) {\n return fail(`invalid --method \"${values.method}\" (use direct|marketplace)`);\n }\n\n const projectDir = values.project ?? process.cwd();\n\n // A connector source may arrive as the first positional or via --connector,\n // and may be a LOCAL path or a REMOTE source spec (GitHub/raw git, npm:, or\n // archive tarball). The positional and the flag are equivalent; reject\n // ambiguity when both name a source.\n const positionalSource = positionals[0];\n if (positionalSource != null && values.connector != null) {\n return fail(\"pass a connector source as EITHER the positional <source> OR --connector, not both.\");\n }\n const source = positionalSource ?? values.connector;\n\n const scope = parseScope(values.scope);\n if (scope == null) return fail(`invalid --scope \"${values.scope}\" (use user|project)`);\n if (method === \"marketplace\" && scope !== \"user\") {\n return fail(\n \"--method marketplace supports --scope user only (project-scope plugin installs are deferred)\",\n );\n }\n\n // Resolve the source to a loadable connector. A REMOTE spec is fetched into a\n // STABLE cache dir under the data-root and GATED (must be an agent-connector\n // package) before handing off to the existing install flow. A LOCAL source —\n // or no source at all — keeps today's path-discovery behavior unchanged.\n let connector: Awaited<ReturnType<typeof loadConnectorFromPath>>[\"connector\"];\n let modulePath: string;\n const spec = source != null ? classifySource(source) : null;\n if (source != null && spec == null) {\n return fail(\n `\"${source}\" is not a local path or a recognizable connector source ` +\n \"(owner/repo[/subpath][#ref], github URL, git URL, npm:<package>[@version], archive:<path-or-url>, or .tgz/.tar.gz).\",\n );\n }\n if (spec != null && spec.kind === \"remote\") {\n try {\n const resolved = await resolveRemoteSource(spec.remote);\n ({ connector, modulePath } = resolved);\n } catch (err) {\n return fail(err instanceof Error ? err.message : String(err));\n }\n } else {\n const configPath = source ?? findConnectorConfig(projectDir);\n if (!configPath) {\n return fail(\n \"no connector config found. Pass a <source> (local path, owner/repo, npm:<package>, or archive tarball) or \" +\n \"--connector <path>, or add an agent-connector.config.{mjs,js,json} to your project.\",\n );\n }\n ({ connector, modulePath } = await loadConnectorFromPath(configPath));\n }\n\n const targets = parseTargets(values.targets);\n\n const result =\n method === \"marketplace\"\n ? await installViaMarketplace({\n connector,\n modulePath,\n scope,\n projectDir,\n dryRun: values[\"dry-run\"],\n ...(targets ? { targets } : {}),\n })\n : await installConnector({\n connector,\n modulePath,\n scope,\n projectDir,\n dryRun: values[\"dry-run\"],\n force: values.force,\n ...(targets ? { targets } : {}),\n });\n\n result.connector = buildConnectorSummary(connector);\n print(renderInstallResult(result, \"install\"));\n return result.changes.some((c) => c.action === \"warn\") ? 1 : 0;\n}\n","/**\n * core/fetch-source — resolve an `install <source>` argument that may be a\n * LOCAL path OR a REMOTE package/source spec into a local connector-config path.\n *\n * Responsibilities (MVP):\n * 1. CLASSIFY a source string as local-path vs. remote GitHub spec. A value\n * that exists on disk, or that looks like a filesystem path (starts with\n * `.`, `/`, `~`, a `file://` URL, or a Windows drive/UNC), stays LOCAL and\n * keeps today's behavior. Everything else is parsed as a remote spec.\n * 2. PARSE the supported remote forms:\n * owner/repo · owner/repo#ref · owner/repo/sub · owner/repo/sub#ref\n * github:owner/repo · https://github.com/owner/repo[/tree/ref/sub]\n * git@github.com:owner/repo.git · the .git suffix on any of the above.\n * npm:<package>[@version] · archive:<path-or-url> · *.tgz / *.tar.gz\n * 3. FETCH + PERSIST the repo to a STABLE cache dir under the data-root\n * (`sources/<owner>__<repo>[__<ref>]/`), NOT a temp dir, so a connector\n * with a local stdio server keeps resolving after install. Re-fetch updates\n * it. `git clone --depth 1` is preferred; a codeload tarball is the\n * fallback when `git` is unavailable.\n * 4. GATE: the fetched (sub)dir MUST contain an `agent-connector.config.*`\n * that loads — otherwise the target is not an agent-connector connector.\n *\n * The actual fetch is injected via a {@link Fetcher} seam so tests can drive the\n * pipeline against a `file://` git fixture without any real network/GitHub hit.\n */\n\nimport { execFileSync } from \"node:child_process\";\nimport { createHash } from \"node:crypto\";\nimport {\n existsSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n renameSync,\n rmSync,\n writeFileSync,\n} from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { basename, isAbsolute, join, relative, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nimport { findConnectorConfig, loadConnectorFromPath } from \"./load-connector.js\";\nimport { sourcesDir } from \"./paths.js\";\nimport type { ResolvedConnector } from \"./types.js\";\n\n/** A parsed remote source to fetch (a GitHub spec, or a raw git clone URL such\n * as `file://`/`ssh://`/`git@…`). `ref` is a branch/tag/sha; `subpath` is the\n * directory within the repo that holds the connector config. */\nexport interface RemoteSource {\n owner: string;\n repo: string;\n /**\n * Non-git source kind. Omitted for GitHub/raw-git sources to preserve the\n * original object shape used by tests and callers.\n */\n sourceKind?: \"npm\" | \"archive\";\n /** Branch / tag / commit. Undefined → the repo default branch. */\n ref?: string;\n /** Sub-directory inside the repo holding the connector config. */\n subpath?: string;\n /**\n * A raw clone URL (file://, ssh://, git@host:…, https://non-github) when the\n * source is NOT a github.com owner/repo we can derive a URL for. Present → the\n * tarball fallback is unavailable (we can only `git clone` it).\n */\n cloneUrl?: string;\n /** npm package spec for sourceKind:\"npm\", e.g. \"@acme/db-mcp@1.2.3\". */\n packageSpec?: string;\n /** npm package name without version/tag, e.g. \"@acme/db-mcp\". */\n packageName?: string;\n /** Tarball path or URL for sourceKind:\"archive\". */\n archiveUrl?: string;\n}\n\n/** The classification of an `install <source>` argument. */\nexport type SourceSpec =\n | { kind: \"local\"; value: string }\n | { kind: \"remote\"; remote: RemoteSource };\n\nconst GITHUB_SEG = /^[A-Za-z0-9._-]+$/;\nconst NPM_UNSCOPED_NAME_RE = /^[a-z0-9][a-z0-9._~-]*$/i;\nconst NPM_SCOPE_RE = /^@[a-z0-9][a-z0-9._~-]*$/i;\n\nfunction isSafeGitHubSegment(segment: string): boolean {\n return GITHUB_SEG.test(segment) && segment !== \".\" && segment !== \"..\";\n}\n\nfunction isSafeSubpath(subpath: string | undefined): boolean {\n if (subpath === undefined || subpath === \"\") return true;\n return subpath\n .split(\"/\")\n .every((segment) => segment !== \"\" && segment !== \".\" && segment !== \"..\");\n}\n\n/**\n * True when `value` should be treated as a LOCAL path (existing behavior),\n * before any remote-spec parse is attempted. Conservative on purpose: a path\n * that exists wins, and the common path sigils (`.`, `/`, `~`, `file://`, a\n * Windows drive letter or UNC) are local even when nothing is on disk yet.\n */\nexport function looksLocal(value: string): boolean {\n if (value === \"\") return true;\n if (existsSync(value)) return true;\n if (\n value.startsWith(\"./\") ||\n value.startsWith(\"../\") ||\n value === \".\" ||\n value === \"..\" ||\n value.startsWith(\"/\") ||\n value.startsWith(\"~\") ||\n value.startsWith(\"file://\")\n ) {\n return true;\n }\n // Windows drive (C:\\ or C:/) or UNC (\\\\server\\share).\n if (/^[A-Za-z]:[\\\\/]/.test(value) || value.startsWith(\"\\\\\\\\\")) return true;\n return false;\n}\n\n/**\n * Parse a remote GitHub spec into a {@link RemoteSource}, or null when `value`\n * is not a recognizable GitHub source. Supports the bare `owner/repo[/sub][#ref]`\n * shorthand, `github:owner/repo`, full `https://github.com/...` (incl.\n * `/tree/<ref>/<subpath>`), and `git@github.com:owner/repo.git`.\n */\nexport function parseRemoteSource(value: string): RemoteSource | null {\n const raw = value.trim();\n if (raw === \"\") return null;\n\n // ── git@github.com:owner/repo(.git) ───────────────────────────────────────\n const scp = raw.match(/^git@github\\.com:([^/]+)\\/(.+?)(?:\\.git)?$/);\n if (scp) {\n return finalizeFromPath(scp[1]!, scp[2]!, undefined);\n }\n\n // ── https://github.com/owner/repo[/tree/<ref>/<subpath>][.git][#ref] ───────\n if (/^https?:\\/\\//i.test(raw) || raw.startsWith(\"git://\")) {\n let url: URL;\n try {\n url = new URL(raw.replace(/^git:\\/\\//, \"https://\"));\n } catch {\n return null;\n }\n if (!/(^|\\.)github\\.com$/i.test(url.hostname)) return null;\n const segs = url.pathname.replace(/^\\/+/, \"\").split(\"/\").filter(Boolean);\n if (segs.length < 2) return null;\n const owner = segs[0]!;\n let repo = segs[1]!.replace(/\\.git$/, \"\");\n let ref: string | undefined;\n let subpath: string | undefined;\n // /tree/<ref>/<subpath...> selects a ref + sub-directory.\n if (segs[2] === \"tree\" || segs[2] === \"blob\") {\n ref = segs[3];\n if (segs.length > 4) subpath = segs.slice(4).join(\"/\");\n } else if (segs.length > 2) {\n subpath = segs.slice(2).join(\"/\");\n }\n const hash = url.hash.replace(/^#/, \"\");\n if (hash) ref = hash;\n if (!isSafeGitHubSegment(owner) || !isSafeGitHubSegment(repo)) return null;\n return cleanRemote({ owner, repo, ref, subpath });\n }\n\n // ── github:owner/repo[...] ────────────────────────────────────────────────\n const shorthand = raw.startsWith(\"github:\") ? raw.slice(\"github:\".length) : raw;\n\n // ── owner/repo[/subpath][#ref] ────────────────────────────────────────────\n // Reject anything that doesn't look like the bare `owner/repo` shape (a single\n // path segment, or a leading slash) so we never misread a stray token.\n const [pathPart, refPart] = splitHash(shorthand);\n const segs = pathPart.split(\"/\").filter(Boolean);\n if (segs.length < 2) return null;\n const owner = segs[0]!;\n const repo = segs[1]!.replace(/\\.git$/, \"\");\n const subpath = segs.length > 2 ? segs.slice(2).join(\"/\") : undefined;\n if (!isSafeGitHubSegment(owner) || !isSafeGitHubSegment(repo)) return null;\n return cleanRemote({ owner, repo, ref: refPart, subpath });\n}\n\n/** Split a \"<path>#<ref>\" into [path, ref?]. */\nfunction splitHash(value: string): [string, string | undefined] {\n const i = value.indexOf(\"#\");\n if (i === -1) return [value, undefined];\n const ref = value.slice(i + 1).trim();\n return [value.slice(0, i), ref === \"\" ? undefined : ref];\n}\n\n/** scp-form helper: the repo half may itself carry `/sub` and `#ref`. */\nfunction finalizeFromPath(owner: string, repoAndRest: string, _ref: undefined): RemoteSource | null {\n const [pathPart, ref] = splitHash(repoAndRest);\n const segs = pathPart.split(\"/\").filter(Boolean);\n const repo = (segs[0] ?? \"\").replace(/\\.git$/, \"\");\n const subpath = segs.length > 1 ? segs.slice(1).join(\"/\") : undefined;\n if (!isSafeGitHubSegment(owner) || !isSafeGitHubSegment(repo)) return null;\n return cleanRemote({ owner, repo, ref, subpath });\n}\n\n/**\n * A git-refname-safe ref charset: branch/tag/sha names plus the `/`, `.`, `_`,\n * `-` they may contain. A LEADING `-` is rejected so a ref can never be read as\n * a git flag (e.g. `--upload-pack=…`) when passed to `git clone --branch`, and\n * the constrained charset keeps cache-dir names clean. Empty is invalid.\n */\nconst REF_RE = /^[A-Za-z0-9][A-Za-z0-9._/-]*$/;\n\n/** True when `ref` is a safe git refname (defense-in-depth before exec). */\nexport function isSafeRef(ref: string): boolean {\n return REF_RE.test(ref);\n}\n\n/**\n * Drop empty optional fields so equality/snapshot comparisons stay clean.\n * Returns null when a present `ref` is not git-refname-safe (defense-in-depth:\n * never pass an attacker-shaped ref to `git clone --branch`).\n */\nfunction cleanRemote(r: RemoteSource): RemoteSource | null {\n if (r.ref !== undefined && !isSafeRef(r.ref)) return null;\n if (!isSafeSubpath(r.subpath)) return null;\n const out: RemoteSource = { owner: r.owner, repo: r.repo };\n if (r.ref) out.ref = r.ref;\n if (r.subpath && r.subpath !== \"\") out.subpath = r.subpath;\n return out;\n}\n\n/**\n * Parse a RAW git clone URL (NOT a github.com owner/repo): `file://…`,\n * `ssh://…`, `git@host:owner/repo`, or `https://<non-github>/…`. These are\n * `git clone`-able directly. A trailing `#ref` selects a branch/tag/sha. These\n * forms point at a repo root (no in-URL subpath). Returns null for anything\n * that isn't a clone URL.\n */\nexport function parseGitUrl(value: string): RemoteSource | null {\n const [urlPart, ref] = splitHash(value.trim());\n const isScheme =\n urlPart.startsWith(\"file://\") ||\n urlPart.startsWith(\"ssh://\") ||\n urlPart.startsWith(\"git://\") ||\n /^https?:\\/\\//i.test(urlPart);\n const isScp = /^[^@\\s]+@[^:\\s]+:.+/.test(urlPart) && !urlPart.startsWith(\"git@github.com:\");\n if (!isScheme && !isScp) return null;\n // Reject an unsafe ref (e.g. a leading-dash flag) before it reaches git.\n if (ref !== undefined && !isSafeRef(ref)) return null;\n\n // Derive a stable owner/repo cache key from the URL's last two path segments.\n const stripped = urlPart.replace(/\\.git$/, \"\").replace(/\\/+$/, \"\");\n const segs = stripped.split(/[/:]/).filter(Boolean);\n const repo = segs[segs.length - 1] ?? \"repo\";\n const owner = segs[segs.length - 2] ?? \"git\";\n const out: RemoteSource = { owner, repo, cloneUrl: urlPart };\n if (ref) out.ref = ref;\n return out;\n}\n\n/** Parse an explicit npm source: npm:<package>[@version-or-tag]. */\nexport function parseNpmSource(value: string): RemoteSource | null {\n const raw = value.trim();\n if (!raw.startsWith(\"npm:\")) return null;\n const spec = raw.slice(\"npm:\".length).trim();\n if (spec === \"\" || /\\s/.test(spec) || spec.startsWith(\"-\")) return null;\n\n let packageName: string;\n if (spec.startsWith(\"@\")) {\n const match = spec.match(/^(@[^/@\\s]+\\/[^/@\\s]+)(?:@([^/\\s]+))?$/);\n if (!match) return null;\n packageName = match[1]!;\n } else {\n const match = spec.match(/^([^/@\\s]+)(?:@([^/\\s]+))?$/);\n if (!match) return null;\n packageName = match[1]!;\n }\n\n const parts = packageName.startsWith(\"@\") ? packageName.split(\"/\") : [packageName];\n if (parts.length === 2) {\n if (!NPM_SCOPE_RE.test(parts[0]!) || !NPM_UNSCOPED_NAME_RE.test(parts[1]!)) {\n return null;\n }\n } else if (parts.length === 1) {\n if (!NPM_UNSCOPED_NAME_RE.test(parts[0]!)) return null;\n } else {\n return null;\n }\n\n return {\n sourceKind: \"npm\",\n owner: \"npm\",\n repo: packageName.replace(/^@/, \"\").replace(/\\//g, \"__\"),\n packageName,\n packageSpec: spec,\n };\n}\n\nfunction stripQueryAndHash(value: string): string {\n return value.split(/[?#]/, 1)[0] ?? value;\n}\n\nfunction archivePathname(value: string): string {\n try {\n const url = new URL(value);\n return url.pathname;\n } catch {\n return value;\n }\n}\n\nfunction isTarballLike(value: string): boolean {\n const p = stripQueryAndHash(archivePathname(value)).toLowerCase();\n return p.endsWith(\".tgz\") || p.endsWith(\".tar.gz\");\n}\n\n/** Parse a tarball archive source: archive:<path-or-url> or direct *.tgz/*.tar.gz. */\nexport function parseArchiveSource(value: string): RemoteSource | null {\n const raw = value.trim();\n const explicit = raw.startsWith(\"archive:\");\n const source = explicit ? raw.slice(\"archive:\".length).trim() : raw;\n if (source === \"\") return null;\n if (!explicit && !isTarballLike(source)) return null;\n\n const pathish = stripQueryAndHash(archivePathname(source));\n const base = basename(pathish).replace(/\\.tar\\.gz$/i, \"\").replace(/\\.tgz$/i, \"\");\n const repo = base || \"source\";\n return {\n sourceKind: \"archive\",\n owner: \"archive\",\n repo,\n archiveUrl: source,\n };\n}\n\n/**\n * Classify an `install <source>` argument. A raw git clone URL (file://, ssh://,\n * git@…) or a GitHub spec is REMOTE (a fetch); a local FILESYSTEM path (existing\n * or path-shaped, EXCLUDING file:// which is a clone URL) keeps today's\n * behavior. Returns null when a non-local value is NOT a recognizable remote.\n */\nexport function classifySource(value: string): SourceSpec | null {\n const npm = parseNpmSource(value);\n if (npm) return { kind: \"remote\", remote: npm };\n const archive = parseArchiveSource(value);\n if (archive) return { kind: \"remote\", remote: archive };\n // A raw git clone URL (incl. file://) is always a FETCH, never a config path —\n // even though file:// is \"path-shaped\" it names a clonable repo, not a config.\n const gitUrl = parseGitUrl(value);\n if (gitUrl) return { kind: \"remote\", remote: gitUrl };\n if (looksLocal(value)) return { kind: \"local\", value };\n const remote = parseRemoteSource(value);\n return remote ? { kind: \"remote\", remote } : null;\n}\n\n/** The clone URL for a remote source (its raw cloneUrl, else the github URL). */\nexport function cloneUrl(r: RemoteSource): string {\n if (r.sourceKind === \"npm\" || r.sourceKind === \"archive\") {\n throw new Error(`${describeRemote(r)} is not a git clone source`);\n }\n return r.cloneUrl ?? `https://github.com/${r.owner}/${r.repo}.git`;\n}\n\n/** The codeload tarball URL for a github source (default branch when no ref). */\nexport function tarballUrl(r: RemoteSource): string {\n const ref = r.ref ?? \"HEAD\";\n return `https://codeload.github.com/${r.owner}/${r.repo}/tar.gz/${ref}`;\n}\n\n/** The STABLE cache directory a remote source is fetched into. */\nexport function sourceCacheDir(r: RemoteSource): string {\n const safe = (s: string) => s.replace(/[^A-Za-z0-9._-]/g, \"-\");\n if (r.sourceKind === \"npm\") {\n return join(sourcesDir(), `npm__${safe(r.packageName ?? r.repo)}__${shortHash(r.packageSpec ?? r.repo)}`);\n }\n if (r.sourceKind === \"archive\") {\n return join(sourcesDir(), `archive__${safe(r.repo)}__${shortHash(r.archiveUrl ?? r.repo)}`);\n }\n // A raw clone URL hashes its full URL into the key so two different file://\n // repos that share an owner/repo basename never collide in the cache.\n const base = r.cloneUrl\n ? `${safe(r.owner)}__${safe(r.repo)}__${shortHash(r.cloneUrl)}`\n : `${safe(r.owner)}__${safe(r.repo)}`;\n const name = r.ref ? `${base}__${safe(r.ref)}` : base;\n return join(sourcesDir(), name);\n}\n\n/** A short, filename-safe hash for disambiguating raw clone URLs in the cache. */\nfunction shortHash(value: string): string {\n return createHash(\"sha256\").update(value).digest(\"hex\").slice(0, 8);\n}\n\n/**\n * A fetcher fetches `remote` into the stable directory `dest`. Injected so tests\n * can drive the resolve pipeline against a `file://` git fixture (no network).\n * The default {@link gitFetcher} clones over HTTPS.\n */\nexport type Fetcher = (remote: RemoteSource, dest: string) => void | Promise<void>;\n\n/** True when a usable `git` is on PATH (probed once per process via a cheap call). */\nfunction gitAvailable(): boolean {\n try {\n execFileSync(\"git\", [\"--version\"], { stdio: \"ignore\" });\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * The default fetcher: `git clone --depth 1 [--branch <ref>] <url> <dest>`.\n * Re-fetch replaces the cache dir so the clone reflects the requested ref. The\n * caller may override the clone URL via `urlFor` (tests pass a `file://` repo).\n */\nexport function makeGitFetcher(urlFor: (r: RemoteSource) => string = cloneUrl): Fetcher {\n return (remote, dest) => {\n if (remote.sourceKind === \"npm\" || remote.sourceKind === \"archive\") {\n throw new Error(`${describeRemote(remote)} is not a git clone source`);\n }\n if (!gitAvailable()) {\n throw new Error(\n \"git is required to fetch a remote connector source but was not found on PATH. \" +\n \"Install git, or pass a local --connector <path>.\",\n );\n }\n rmSync(dest, { recursive: true, force: true });\n mkdirSync(dest, { recursive: true });\n const args = [\"clone\", \"--depth\", \"1\"];\n if (remote.ref) args.push(\"--branch\", remote.ref);\n args.push(urlFor(remote), dest);\n try {\n execFileSync(\"git\", args, { stdio: \"ignore\" });\n } catch (err) {\n throw new Error(\n `failed to clone ${urlFor(remote)}${remote.ref ? ` (ref ${remote.ref})` : \"\"}: ` +\n `${err instanceof Error ? err.message : String(err)}`,\n );\n }\n };\n}\n\n/**\n * Tarball fallback: download the GitHub codeload `tar.gz` and extract it with\n * the system `tar` (present on Linux, macOS, and Windows 10+). codeload nests\n * everything under a single `<repo>-<ref>/` top dir, which we flatten into\n * `dest`. Used only when `git` is unavailable.\n */\nasync function tarballFetch(remote: RemoteSource, dest: string): Promise<void> {\n const url = tarballUrl(remote);\n const res = await fetch(url);\n if (!res.ok) {\n throw new Error(`failed to download ${url}: HTTP ${res.status} ${res.statusText}`);\n }\n await extractTarballBuffer(Buffer.from(await res.arrayBuffer()), dest);\n}\n\nfunction extractTarballBuffer(buf: Buffer, dest: string): void {\n const work = join(tmpdir(), `ac-src-${process.pid}-${Date.now()}`);\n mkdirSync(work, { recursive: true });\n const tarPath = join(work, \"source.tar.gz\");\n writeFileSync(tarPath, buf);\n try {\n execFileSync(\"tar\", [\"-xzf\", tarPath, \"-C\", work], { stdio: \"ignore\" });\n } catch (err) {\n rmSync(work, { recursive: true, force: true });\n throw new Error(\n \"neither git nor a usable `tar` is available to fetch a remote connector \" +\n `source (${err instanceof Error ? err.message : String(err)}). Install git ` +\n \"or tar, or pass a local --connector <path>.\",\n );\n }\n // codeload nests under a single `<repo>-<ref>/` directory — flatten it.\n const entries = readdirSync(work).filter((e) => e !== \"source.tar.gz\");\n const top = entries.length === 1 ? join(work, entries[0]!) : work;\n rmSync(dest, { recursive: true, force: true });\n renameSync(top, dest);\n rmSync(work, { recursive: true, force: true });\n}\n\nasync function archiveFetch(remote: RemoteSource, dest: string): Promise<void> {\n const source = remote.archiveUrl;\n if (!source) throw new Error(\"archive source is missing archiveUrl\");\n\n if (/^https?:\\/\\//i.test(source)) {\n const res = await fetch(source);\n if (!res.ok) {\n throw new Error(`failed to download ${source}: HTTP ${res.status} ${res.statusText}`);\n }\n await extractTarballBuffer(Buffer.from(await res.arrayBuffer()), dest);\n return;\n }\n\n const archivePath = source.startsWith(\"file://\") ? fileURLToPath(source) : source;\n if (!existsSync(archivePath)) {\n throw new Error(`archive source not found: ${source}`);\n }\n extractTarballBuffer(readFileSync(archivePath), dest);\n}\n\nfunction npmAvailable(): boolean {\n try {\n execFileSync(\"npm\", [\"--version\"], { stdio: \"ignore\" });\n return true;\n } catch {\n return false;\n }\n}\n\nasync function npmFetch(remote: RemoteSource, dest: string): Promise<void> {\n const spec = remote.packageSpec;\n if (!spec) throw new Error(\"npm source is missing packageSpec\");\n if (!npmAvailable()) {\n throw new Error(\n `npm is required to fetch npm:${spec} but was not found on PATH. ` +\n \"Install npm, or pass a local --connector <path>.\",\n );\n }\n\n const work = join(tmpdir(), `ac-npm-${process.pid}-${Date.now()}`);\n mkdirSync(work, { recursive: true });\n let stdout: string;\n try {\n stdout = execFileSync(\n \"npm\",\n [\"pack\", spec, \"--pack-destination\", work, \"--silent\"],\n { encoding: \"utf8\" },\n );\n } catch (err) {\n rmSync(work, { recursive: true, force: true });\n throw new Error(\n `failed to fetch npm:${spec}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n const packed = stdout.trim().split(/\\r?\\n/).filter(Boolean).pop();\n if (!packed) {\n rmSync(work, { recursive: true, force: true });\n throw new Error(`failed to fetch npm:${spec}: npm pack produced no tarball`);\n }\n const tarPath = isAbsolute(packed) ? packed : join(work, packed);\n try {\n extractTarballBuffer(readFileSync(tarPath), dest);\n } finally {\n rmSync(work, { recursive: true, force: true });\n }\n}\n\n/**\n * The default network fetcher: `git clone` when git is on PATH, otherwise the\n * codeload tarball fallback (github.com sources only — a raw clone URL can only\n * be `git clone`d, so it requires git). A clear error is thrown when neither\n * applicable path works.\n */\nexport const gitFetcher: Fetcher = async (remote, dest) => {\n if (remote.sourceKind === \"npm\") {\n await npmFetch(remote, dest);\n return;\n }\n if (remote.sourceKind === \"archive\") {\n await archiveFetch(remote, dest);\n return;\n }\n if (gitAvailable()) {\n makeGitFetcher()(remote, dest);\n return;\n }\n if (remote.cloneUrl) {\n throw new Error(\n `git is required to fetch ${remote.cloneUrl} but was not found on PATH. ` +\n \"Install git, or pass a local --connector <path>.\",\n );\n }\n await tarballFetch(remote, dest);\n};\n\n/** The resolved output of {@link resolveRemoteSource}. */\nexport interface ResolvedSource {\n /** Absolute path to the agent-connector.config.* found inside the fetch. */\n configPath: string;\n /** The directory the source was fetched into (stable, under the data-root). */\n sourceDir: string;\n /** The (sub)directory the config was found in. */\n connectorDir: string;\n /** The live connector + its absolute module path (ready for the install flow). */\n connector: ResolvedConnector;\n modulePath: string;\n}\n\n/** Options for {@link resolveRemoteSource}. */\nexport interface ResolveOptions {\n /** Override the fetch (tests). Defaults to {@link gitFetcher}. */\n fetcher?: Fetcher;\n}\n\n/**\n * Fetch a remote source into its stable cache dir, honor the subpath, and GATE\n * it as a real agent-connector package: `findConnectorConfig` must locate an\n * `agent-connector.config.{mjs,js,json}` that `loadConnectorFromPath` can load.\n * Throws a clear, specific error when the target is not an agent-connector\n * connector. Returns everything the install flow needs.\n */\nexport async function resolveRemoteSource(\n remote: RemoteSource,\n opts: ResolveOptions = {},\n): Promise<ResolvedSource> {\n const fetcher = opts.fetcher ?? gitFetcher;\n const sourceDir = sourceCacheDir(remote);\n mkdirSync(sourcesDir(), { recursive: true });\n await fetcher(remote, sourceDir);\n\n const label = describeRemote(remote);\n if (!existsSync(sourceDir)) {\n throw new Error(`failed to fetch ${label}: nothing was written to ${sourceDir}`);\n }\n\n // Honor the subpath; guard against a `..` escape out of the fetched dir.\n // Containment is checked with path.relative (NOT a bare string prefix, which\n // a sibling dir sharing the cache-key prefix would defeat) — mirroring the\n // connectorDir() guard in paths.ts: reject when the relative path is empty,\n // starts with \"..\", or is absolute.\n const root = resolve(sourceDir);\n const searchDir = remote.subpath ? resolve(root, remote.subpath) : root;\n if (remote.subpath) {\n const rel = relative(root, searchDir);\n if (rel === \"\" || rel.startsWith(\"..\") || isAbsolute(rel)) {\n throw new Error(`subpath escapes the fetched source: ${remote.subpath}`);\n }\n }\n if (!existsSync(searchDir)) {\n throw new Error(\n `${label}: subpath \"${remote.subpath}\" does not exist in the repository.`,\n );\n }\n\n // ── PACKAGE GATE ──────────────────────────────────────────────────────────\n // Search only WITHIN the fetched (sub)dir. findConnectorConfig walks UPWARD to\n // the filesystem root, so confine the start dir and verify the hit is inside.\n const configPath = findConfigWithin(searchDir);\n if (!configPath) {\n throw new Error(\n `${label} is not an agent-connector connector — no ` +\n `agent-connector.config.{mjs,js,json} found in the repo` +\n (remote.subpath ? ` at subpath \"${remote.subpath}\"` : \"\") +\n \". The target must be a package built with agent-connector (defineConnector).\",\n );\n }\n\n let connector: ResolvedConnector;\n let modulePath: string;\n try {\n ({ connector, modulePath } = await loadConnectorFromPath(configPath));\n } catch (err) {\n throw new Error(\n `${label}: found ${configPath} but it failed to load as an agent-connector ` +\n `connector (${err instanceof Error ? err.message : String(err)}). The target ` +\n \"must be a package built with agent-connector (defineConnector).\",\n );\n }\n\n return {\n configPath,\n sourceDir,\n connectorDir: searchDir,\n connector,\n modulePath,\n };\n}\n\n/**\n * Locate `agent-connector.config.*` strictly within `dir` (not its ancestors).\n * `findConnectorConfig` walks upward, so we scope the result by asserting the\n * hit is in `dir` itself.\n */\nfunction findConfigWithin(dir: string): string | null {\n const hit = findConnectorConfig(dir);\n if (!hit) return null;\n // Must live directly in the (sub)dir we were pointed at — reject an ancestor\n // hit so a parent dir's config can't masquerade as the repo's.\n const dirAbs = resolve(dir);\n const hitDir = resolve(hit, \"..\");\n return hitDir === dirAbs ? hit : null;\n}\n\n/** A human label for a remote source used in error messages. */\nexport function describeRemote(r: RemoteSource): string {\n if (r.sourceKind === \"npm\") return `npm:${r.packageSpec ?? r.repo}`;\n if (r.sourceKind === \"archive\") return `archive:${r.archiveUrl ?? r.repo}`;\n let s = r.cloneUrl ?? `${r.owner}/${r.repo}`;\n if (r.subpath) s += `/${r.subpath}`;\n if (r.ref) s += `#${r.ref}`;\n return s;\n}\n"],"mappings":"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","names":["segs","owner","repo","subpath"]}
|
|
@@ -15,8 +15,9 @@ import "./chunk-XD7MY6HB.js";
|
|
|
15
15
|
import {
|
|
16
16
|
fail,
|
|
17
17
|
print
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-PTITNBSS.js";
|
|
19
19
|
import "./chunk-IVAWP6HH.js";
|
|
20
|
+
import "./chunk-D35FMUFZ.js";
|
|
20
21
|
import "./chunk-GZGLCCEE.js";
|
|
21
22
|
|
|
22
23
|
// src/cli/commands/leaderboard.ts
|
|
@@ -134,4 +135,4 @@ export {
|
|
|
134
135
|
parseSince,
|
|
135
136
|
run
|
|
136
137
|
};
|
|
137
|
-
//# sourceMappingURL=leaderboard-
|
|
138
|
+
//# sourceMappingURL=leaderboard-VF4W6PZ2.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/commands/leaderboard.ts"],"sourcesContent":["/**\n * cli/commands/leaderboard — the unified top-level `agent-connector leaderboard`.\n *\n * Prints THREE leaderboards, each clearly origin-labeled and NEVER summed:\n * 🔌 MCP / Plugin leaderboard ← origin `mcp-self`: the serve-proxy\n * telemetry store (which MCP server WE wrap costs the most — per-MCP `call`\n * + `tool_defs` rows; the `model_turn` rows are EXCLUDED here).\n * 🖥️ Host / User leaderboard ← origin `host-scan-logs`: the host usage\n * readers scanning agent CLI logs (which CLI / host spent the most).\n * 🛰️ Host-native turns (live, exact) ← origin `host-native-live`: the opt-in\n * AfterModel / PostInvocation usage hook (scope `model_turn`, confidence\n * host-native) — whole-conversation usage the host reported in real time.\n *\n * All three measure DIFFERENT things (per-MCP server bytes vs whole-conversation\n * usage from logs vs whole-conversation usage from a live hook). They are reported\n * side by side but their totals are NEVER added together.\n *\n * Flags:\n * --since 7d|24h|… lower-bound window applied to both sources.\n * --scope <value> MCP-section scope slice (user|project|npx|binary|http|…);\n * ignored by the host section (host logs carry no scope).\n * --connector <id> restrict the 🔌 MCP/plugin + 🛰️ host-native-turns\n * sections to ONE connector id. The 🖥️ host-scan section\n * is connector-agnostic (host CLI logs carry no connector\n * attribution) and is intentionally NOT filtered.\n * --json emit { mcp:[...], host:[...] } instead of the tables.\n */\n\nimport { parseArgs } from \"node:util\";\n\nimport {\n formatHostNativeTurns,\n formatMcpLeaderboard,\n hostNativeTurns,\n isScopeFilter,\n mcpLeaderboard,\n SCOPE_FILTER_VALUES,\n type ScopeFilter,\n} from \"../../telemetry/leaderboard.js\";\nimport { formatHostLeaderboard, hostLeaderboard } from \"../../usage/leaderboard.js\";\nimport { fail, print } from \"../app.js\";\n\n/**\n * Parse a relative duration (`Ns`/`Nm`/`Nh`/`Nd`) to a lower-bound epoch ms.\n * Returns undefined for empty input and null for a malformed one. (Kept local so\n * the leaderboard command stays decoupled from the report commands.)\n */\nexport function parseSince(since: string | undefined): number | null | undefined {\n if (since == null || since.trim() === \"\") return undefined;\n const m = since.trim().match(/^(\\d+)\\s*([smhd])$/i);\n if (!m || !m[1] || !m[2]) return null;\n const n = Number(m[1]);\n const unitMs: Record<string, number> = {\n s: 1000,\n m: 60_000,\n h: 3_600_000,\n d: 86_400_000,\n };\n const factor = unitMs[m[2].toLowerCase()];\n if (factor == null) return null;\n return Date.now() - n * factor;\n}\n\nexport async function run(argv: string[]): Promise<number> {\n const first = argv[0];\n if (first === \"--help\" || first === \"-h\") {\n print(\"usage: agent-connector leaderboard [flags]\");\n print(\" --since 7d|24h|… window applied to BOTH sources\");\n print(` --scope <value> MCP-section slice (${SCOPE_FILTER_VALUES.join(\"|\")})`);\n print(\" --connector <id> restrict the 🔌 MCP + 🛰️ host-native sections to one connector\");\n print(\" --json emit { mcp:[...], host:[...] } (never summed)\");\n return 0;\n }\n\n const { values } = parseArgs({\n args: argv,\n options: {\n since: { type: \"string\" },\n scope: { type: \"string\" },\n connector: { type: \"string\" },\n json: { type: \"boolean\", default: false },\n },\n allowPositionals: false,\n });\n\n const sinceMs = parseSince(values.since);\n if (sinceMs === null) {\n return fail(`invalid --since \"${values.since}\" (use forms like 30s, 15m, 24h, 7d)`);\n }\n\n let scope: ScopeFilter | undefined;\n if (values.scope !== undefined && values.scope.trim() !== \"\") {\n const s = values.scope.trim();\n if (!isScopeFilter(s)) {\n return fail(`invalid --scope \"${s}\" (use ${SCOPE_FILTER_VALUES.join(\"|\")})`);\n }\n scope = s;\n }\n\n // The optional --connector <id> FILTER restricts the two connector-attributed\n // sections (🔌 MCP/plugin + 🛰️ host-native turns) to one connector. The\n // 🖥️ host-scan section below is intentionally NOT filtered: host CLI logs carry\n // no connector attribution, so it stays connector-agnostic (whole-conversation).\n const connectorId =\n values.connector !== undefined && values.connector.trim() !== \"\"\n ? values.connector.trim()\n : undefined;\n\n // 🔌 MCP / Plugin leaderboard — serve-proxy telemetry (origin: mcp-self).\n const mcpOpts: { sinceMs?: number; scope?: ScopeFilter; connectorId?: string } = {};\n if (sinceMs !== undefined) mcpOpts.sinceMs = sinceMs;\n if (scope !== undefined) mcpOpts.scope = scope;\n if (connectorId !== undefined) mcpOpts.connectorId = connectorId;\n const mcp = mcpLeaderboard(mcpOpts);\n\n // 🖥️ Host / User leaderboard — host usage readers (origin: host-scan-logs).\n // Connector-agnostic by construction: NOT filtered by --connector.\n const hostOpts: { sinceMs?: number } = {};\n if (sinceMs !== undefined) hostOpts.sinceMs = sinceMs;\n const host = await hostLeaderboard(hostOpts);\n\n // 🛰️ Host-native turns — opt-in AfterModel usage hook (origin: host-native-live).\n // Scope `model_turn` rows ONLY; the MCP section above already excludes them.\n const turnsOpts: { sinceMs?: number; scope?: ScopeFilter; connectorId?: string } = {};\n if (sinceMs !== undefined) turnsOpts.sinceMs = sinceMs;\n if (scope !== undefined) turnsOpts.scope = scope;\n if (connectorId !== undefined) turnsOpts.connectorId = connectorId;\n const turns = hostNativeTurns(turnsOpts);\n\n if (values.json) {\n // Three separate arrays — by construction the consumer cannot sum origins.\n print(\n JSON.stringify(\n {\n mcp, // origin: mcp-self\n host: host.rows, // origin: host-scan-logs\n hostSkipped: host.skipped,\n hostNativeTurns: turns, // origin: host-native-live (scope model_turn)\n },\n null,\n 2,\n ),\n );\n return 0;\n }\n\n const lines: string[] = [];\n lines.push(\n \"🔌 MCP / Plugin leaderboard (origin: mcp-self — per-MCP server bytes we wrap; \" +\n \"excludes host-native model_turn rows)\",\n );\n if (scope !== undefined) lines.push(` scope: ${scope}`);\n if (connectorId !== undefined) lines.push(` connector: ${connectorId}`);\n lines.push(\"\");\n lines.push(formatMcpLeaderboard(mcp));\n lines.push(\"\");\n lines.push(\n \"🖥️ Host / User leaderboard (origin: host-scan-logs — whole-conversation usage from CLI logs)\",\n );\n if (connectorId !== undefined) {\n lines.push(\" (connector-agnostic — host CLI logs carry no connector attribution; --connector not applied here)\");\n }\n lines.push(\"\");\n lines.push(formatHostLeaderboard(host));\n lines.push(\"\");\n lines.push(\n \"🛰️ Host-native turns (live, exact) (origin: host-native-live — opt-in AfterModel usage hook)\",\n );\n lines.push(\"\");\n lines.push(formatHostNativeTurns(turns));\n lines.push(\"\");\n lines.push(\n \"note: the THREE leaderboards measure DIFFERENT things (per-MCP server bytes vs \" +\n \"whole-conversation usage from logs vs live host-native turns) and are never \" +\n \"summed together (their totals are NEVER added across origins).\",\n );\n print(lines.join(\"\\n\"));\n return 0;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/cli/commands/leaderboard.ts"],"sourcesContent":["/**\n * cli/commands/leaderboard — the unified top-level `agent-connector leaderboard`.\n *\n * Prints THREE leaderboards, each clearly origin-labeled and NEVER summed:\n * 🔌 MCP / Plugin leaderboard ← origin `mcp-self`: the serve-proxy\n * telemetry store (which MCP server WE wrap costs the most — per-MCP `call`\n * + `tool_defs` rows; the `model_turn` rows are EXCLUDED here).\n * 🖥️ Host / User leaderboard ← origin `host-scan-logs`: the host usage\n * readers scanning agent CLI logs (which CLI / host spent the most).\n * 🛰️ Host-native turns (live, exact) ← origin `host-native-live`: the opt-in\n * AfterModel / PostInvocation usage hook (scope `model_turn`, confidence\n * host-native) — whole-conversation usage the host reported in real time.\n *\n * All three measure DIFFERENT things (per-MCP server bytes vs whole-conversation\n * usage from logs vs whole-conversation usage from a live hook). They are reported\n * side by side but their totals are NEVER added together.\n *\n * Flags:\n * --since 7d|24h|… lower-bound window applied to both sources.\n * --scope <value> MCP-section scope slice (user|project|npx|binary|http|…);\n * ignored by the host section (host logs carry no scope).\n * --connector <id> restrict the 🔌 MCP/plugin + 🛰️ host-native-turns\n * sections to ONE connector id. The 🖥️ host-scan section\n * is connector-agnostic (host CLI logs carry no connector\n * attribution) and is intentionally NOT filtered.\n * --json emit { mcp:[...], host:[...] } instead of the tables.\n */\n\nimport { parseArgs } from \"node:util\";\n\nimport {\n formatHostNativeTurns,\n formatMcpLeaderboard,\n hostNativeTurns,\n isScopeFilter,\n mcpLeaderboard,\n SCOPE_FILTER_VALUES,\n type ScopeFilter,\n} from \"../../telemetry/leaderboard.js\";\nimport { formatHostLeaderboard, hostLeaderboard } from \"../../usage/leaderboard.js\";\nimport { fail, print } from \"../app.js\";\n\n/**\n * Parse a relative duration (`Ns`/`Nm`/`Nh`/`Nd`) to a lower-bound epoch ms.\n * Returns undefined for empty input and null for a malformed one. (Kept local so\n * the leaderboard command stays decoupled from the report commands.)\n */\nexport function parseSince(since: string | undefined): number | null | undefined {\n if (since == null || since.trim() === \"\") return undefined;\n const m = since.trim().match(/^(\\d+)\\s*([smhd])$/i);\n if (!m || !m[1] || !m[2]) return null;\n const n = Number(m[1]);\n const unitMs: Record<string, number> = {\n s: 1000,\n m: 60_000,\n h: 3_600_000,\n d: 86_400_000,\n };\n const factor = unitMs[m[2].toLowerCase()];\n if (factor == null) return null;\n return Date.now() - n * factor;\n}\n\nexport async function run(argv: string[]): Promise<number> {\n const first = argv[0];\n if (first === \"--help\" || first === \"-h\") {\n print(\"usage: agent-connector leaderboard [flags]\");\n print(\" --since 7d|24h|… window applied to BOTH sources\");\n print(` --scope <value> MCP-section slice (${SCOPE_FILTER_VALUES.join(\"|\")})`);\n print(\" --connector <id> restrict the 🔌 MCP + 🛰️ host-native sections to one connector\");\n print(\" --json emit { mcp:[...], host:[...] } (never summed)\");\n return 0;\n }\n\n const { values } = parseArgs({\n args: argv,\n options: {\n since: { type: \"string\" },\n scope: { type: \"string\" },\n connector: { type: \"string\" },\n json: { type: \"boolean\", default: false },\n },\n allowPositionals: false,\n });\n\n const sinceMs = parseSince(values.since);\n if (sinceMs === null) {\n return fail(`invalid --since \"${values.since}\" (use forms like 30s, 15m, 24h, 7d)`);\n }\n\n let scope: ScopeFilter | undefined;\n if (values.scope !== undefined && values.scope.trim() !== \"\") {\n const s = values.scope.trim();\n if (!isScopeFilter(s)) {\n return fail(`invalid --scope \"${s}\" (use ${SCOPE_FILTER_VALUES.join(\"|\")})`);\n }\n scope = s;\n }\n\n // The optional --connector <id> FILTER restricts the two connector-attributed\n // sections (🔌 MCP/plugin + 🛰️ host-native turns) to one connector. The\n // 🖥️ host-scan section below is intentionally NOT filtered: host CLI logs carry\n // no connector attribution, so it stays connector-agnostic (whole-conversation).\n const connectorId =\n values.connector !== undefined && values.connector.trim() !== \"\"\n ? values.connector.trim()\n : undefined;\n\n // 🔌 MCP / Plugin leaderboard — serve-proxy telemetry (origin: mcp-self).\n const mcpOpts: { sinceMs?: number; scope?: ScopeFilter; connectorId?: string } = {};\n if (sinceMs !== undefined) mcpOpts.sinceMs = sinceMs;\n if (scope !== undefined) mcpOpts.scope = scope;\n if (connectorId !== undefined) mcpOpts.connectorId = connectorId;\n const mcp = mcpLeaderboard(mcpOpts);\n\n // 🖥️ Host / User leaderboard — host usage readers (origin: host-scan-logs).\n // Connector-agnostic by construction: NOT filtered by --connector.\n const hostOpts: { sinceMs?: number } = {};\n if (sinceMs !== undefined) hostOpts.sinceMs = sinceMs;\n const host = await hostLeaderboard(hostOpts);\n\n // 🛰️ Host-native turns — opt-in AfterModel usage hook (origin: host-native-live).\n // Scope `model_turn` rows ONLY; the MCP section above already excludes them.\n const turnsOpts: { sinceMs?: number; scope?: ScopeFilter; connectorId?: string } = {};\n if (sinceMs !== undefined) turnsOpts.sinceMs = sinceMs;\n if (scope !== undefined) turnsOpts.scope = scope;\n if (connectorId !== undefined) turnsOpts.connectorId = connectorId;\n const turns = hostNativeTurns(turnsOpts);\n\n if (values.json) {\n // Three separate arrays — by construction the consumer cannot sum origins.\n print(\n JSON.stringify(\n {\n mcp, // origin: mcp-self\n host: host.rows, // origin: host-scan-logs\n hostSkipped: host.skipped,\n hostNativeTurns: turns, // origin: host-native-live (scope model_turn)\n },\n null,\n 2,\n ),\n );\n return 0;\n }\n\n const lines: string[] = [];\n lines.push(\n \"🔌 MCP / Plugin leaderboard (origin: mcp-self — per-MCP server bytes we wrap; \" +\n \"excludes host-native model_turn rows)\",\n );\n if (scope !== undefined) lines.push(` scope: ${scope}`);\n if (connectorId !== undefined) lines.push(` connector: ${connectorId}`);\n lines.push(\"\");\n lines.push(formatMcpLeaderboard(mcp));\n lines.push(\"\");\n lines.push(\n \"🖥️ Host / User leaderboard (origin: host-scan-logs — whole-conversation usage from CLI logs)\",\n );\n if (connectorId !== undefined) {\n lines.push(\" (connector-agnostic — host CLI logs carry no connector attribution; --connector not applied here)\");\n }\n lines.push(\"\");\n lines.push(formatHostLeaderboard(host));\n lines.push(\"\");\n lines.push(\n \"🛰️ Host-native turns (live, exact) (origin: host-native-live — opt-in AfterModel usage hook)\",\n );\n lines.push(\"\");\n lines.push(formatHostNativeTurns(turns));\n lines.push(\"\");\n lines.push(\n \"note: the THREE leaderboards measure DIFFERENT things (per-MCP server bytes vs \" +\n \"whole-conversation usage from logs vs live host-native turns) and are never \" +\n \"summed together (their totals are NEVER added across origins).\",\n );\n print(lines.join(\"\\n\"));\n return 0;\n}\n"],"mappings":"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","names":[]}
|