@ken-jo/agent-connector 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/NOTICE +6 -0
- package/README.md +348 -0
- package/dist/amp-QSFH2V7Y.js +217 -0
- package/dist/amp-QSFH2V7Y.js.map +1 -0
- package/dist/amp-TULUPXXL.js +237 -0
- package/dist/amp-TULUPXXL.js.map +1 -0
- package/dist/antigravity-CX2YLSY7.js +17 -0
- package/dist/antigravity-CX2YLSY7.js.map +1 -0
- package/dist/antigravity-STHZWMP3.js +171 -0
- package/dist/antigravity-STHZWMP3.js.map +1 -0
- package/dist/antigravity-cli-P6HADOAO.js +121 -0
- package/dist/antigravity-cli-P6HADOAO.js.map +1 -0
- package/dist/antigravity-cli-YQDFVV4U.js +86 -0
- package/dist/antigravity-cli-YQDFVV4U.js.map +1 -0
- package/dist/chunk-54EMKTTX.js +191 -0
- package/dist/chunk-54EMKTTX.js.map +1 -0
- package/dist/chunk-7L6ITC4T.js +54 -0
- package/dist/chunk-7L6ITC4T.js.map +1 -0
- package/dist/chunk-7MSDGHJW.js +316 -0
- package/dist/chunk-7MSDGHJW.js.map +1 -0
- package/dist/chunk-BCHWFTV4.js +196 -0
- package/dist/chunk-BCHWFTV4.js.map +1 -0
- package/dist/chunk-DBQMX75U.js +36 -0
- package/dist/chunk-DBQMX75U.js.map +1 -0
- package/dist/chunk-EXLS7BSI.js +29 -0
- package/dist/chunk-EXLS7BSI.js.map +1 -0
- package/dist/chunk-JNM3TPLX.js +593 -0
- package/dist/chunk-JNM3TPLX.js.map +1 -0
- package/dist/chunk-JWNT5KW7.js +197 -0
- package/dist/chunk-JWNT5KW7.js.map +1 -0
- package/dist/chunk-KHO5WNTP.js +30 -0
- package/dist/chunk-KHO5WNTP.js.map +1 -0
- package/dist/chunk-LTT56GI3.js +155 -0
- package/dist/chunk-LTT56GI3.js.map +1 -0
- package/dist/chunk-MEH7GC7R.js +111 -0
- package/dist/chunk-MEH7GC7R.js.map +1 -0
- package/dist/chunk-MQPNU2CY.js +64 -0
- package/dist/chunk-MQPNU2CY.js.map +1 -0
- package/dist/chunk-OPXAP3AC.js +12 -0
- package/dist/chunk-OPXAP3AC.js.map +1 -0
- package/dist/chunk-RK6VBLXP.js +50 -0
- package/dist/chunk-RK6VBLXP.js.map +1 -0
- package/dist/chunk-TIIP3RG2.js +420 -0
- package/dist/chunk-TIIP3RG2.js.map +1 -0
- package/dist/chunk-TRKWUNO4.js +702 -0
- package/dist/chunk-TRKWUNO4.js.map +1 -0
- package/dist/chunk-TRQKHP7D.js +93 -0
- package/dist/chunk-TRQKHP7D.js.map +1 -0
- package/dist/chunk-WCETQWWK.js +59 -0
- package/dist/chunk-WCETQWWK.js.map +1 -0
- package/dist/chunk-WV63X7IK.js +357 -0
- package/dist/chunk-WV63X7IK.js.map +1 -0
- package/dist/chunk-XD7MY6HB.js +343 -0
- package/dist/chunk-XD7MY6HB.js.map +1 -0
- package/dist/chunk-XNAM7F35.js +276 -0
- package/dist/chunk-XNAM7F35.js.map +1 -0
- package/dist/chunk-XUCWLJY5.js +238 -0
- package/dist/chunk-XUCWLJY5.js.map +1 -0
- package/dist/chunk-YNZU6PAV.js +800 -0
- package/dist/chunk-YNZU6PAV.js.map +1 -0
- package/dist/chunk-YT43MUSJ.js +146 -0
- package/dist/chunk-YT43MUSJ.js.map +1 -0
- package/dist/claude-code-HKDV7T32.js +637 -0
- package/dist/claude-code-HKDV7T32.js.map +1 -0
- package/dist/claude-code-W74MNTAC.js +652 -0
- package/dist/claude-code-W74MNTAC.js.map +1 -0
- package/dist/cli/sdk.d.ts +54 -0
- package/dist/cli/sdk.js +82 -0
- package/dist/cli/sdk.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +15 -0
- package/dist/cli.js.map +1 -0
- package/dist/codebuff-3PMZJJHP.js +307 -0
- package/dist/codebuff-3PMZJJHP.js.map +1 -0
- package/dist/codebuff-QX57FJDN.js +220 -0
- package/dist/codebuff-QX57FJDN.js.map +1 -0
- package/dist/codex-JFQTS6LU.js +593 -0
- package/dist/codex-JFQTS6LU.js.map +1 -0
- package/dist/codex-Q3ATRRX3.js +364 -0
- package/dist/codex-Q3ATRRX3.js.map +1 -0
- package/dist/copilot-cli-MTCGHZ2T.js +622 -0
- package/dist/copilot-cli-MTCGHZ2T.js.map +1 -0
- package/dist/copilot-cli-SJGIXVSD.js +369 -0
- package/dist/copilot-cli-SJGIXVSD.js.map +1 -0
- package/dist/crush-I7PK3FGI.js +360 -0
- package/dist/crush-I7PK3FGI.js.map +1 -0
- package/dist/crush-LN5QFFR2.js +183 -0
- package/dist/crush-LN5QFFR2.js.map +1 -0
- package/dist/cursor-4TMXKJOZ.js +603 -0
- package/dist/cursor-4TMXKJOZ.js.map +1 -0
- package/dist/cursor-QZ6MTO74.js +194 -0
- package/dist/cursor-QZ6MTO74.js.map +1 -0
- package/dist/detect-WIAGVYS4.js +68 -0
- package/dist/detect-WIAGVYS4.js.map +1 -0
- package/dist/doctor-EZW2K4NI.js +372 -0
- package/dist/doctor-EZW2K4NI.js.map +1 -0
- package/dist/droid-KN6VRMMT.js +424 -0
- package/dist/droid-KN6VRMMT.js.map +1 -0
- package/dist/droid-W5WF5XEX.js +224 -0
- package/dist/droid-W5WF5XEX.js.map +1 -0
- package/dist/gemini-cli-CIRW37TU.js +369 -0
- package/dist/gemini-cli-CIRW37TU.js.map +1 -0
- package/dist/gemini-cli-Y35FFK4M.js +705 -0
- package/dist/gemini-cli-Y35FFK4M.js.map +1 -0
- package/dist/goose-A3M5GODH.js +212 -0
- package/dist/goose-A3M5GODH.js.map +1 -0
- package/dist/goose-ZTGTSUFJ.js +480 -0
- package/dist/goose-ZTGTSUFJ.js.map +1 -0
- package/dist/hermes-H2KV44GK.js +470 -0
- package/dist/hermes-H2KV44GK.js.map +1 -0
- package/dist/hermes-ZYLMOFLZ.js +196 -0
- package/dist/hermes-ZYLMOFLZ.js.map +1 -0
- package/dist/hook-YVDILAMZ.js +75 -0
- package/dist/hook-YVDILAMZ.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/install-HQRYZOQ2.js +60 -0
- package/dist/install-HQRYZOQ2.js.map +1 -0
- package/dist/jetbrains-copilot-HWA3DMH7.js +633 -0
- package/dist/jetbrains-copilot-HWA3DMH7.js.map +1 -0
- package/dist/kilo-NSWAVP6P.js +235 -0
- package/dist/kilo-NSWAVP6P.js.map +1 -0
- package/dist/kilo-QXJRCSLT.js +384 -0
- package/dist/kilo-QXJRCSLT.js.map +1 -0
- package/dist/kilo-cli-EAQTHXUW.js +587 -0
- package/dist/kilo-cli-EAQTHXUW.js.map +1 -0
- package/dist/kilo-cli-EVBKUODA.js +160 -0
- package/dist/kilo-cli-EVBKUODA.js.map +1 -0
- package/dist/kimi-EI3UM3ZV.js +155 -0
- package/dist/kimi-EI3UM3ZV.js.map +1 -0
- package/dist/kimi-GQ7VXNYT.js +423 -0
- package/dist/kimi-GQ7VXNYT.js.map +1 -0
- package/dist/kiro-UCLSLBW2.js +217 -0
- package/dist/kiro-UCLSLBW2.js.map +1 -0
- package/dist/kiro-VQTT6LO2.js +451 -0
- package/dist/kiro-VQTT6LO2.js.map +1 -0
- package/dist/leaderboard-K6ON3SWW.js +137 -0
- package/dist/leaderboard-K6ON3SWW.js.map +1 -0
- package/dist/mux-T2TV4CIQ.js +211 -0
- package/dist/mux-T2TV4CIQ.js.map +1 -0
- package/dist/mux-ZMLVAXOO.js +96 -0
- package/dist/mux-ZMLVAXOO.js.map +1 -0
- package/dist/omp-PB4VDKS6.js +586 -0
- package/dist/omp-PB4VDKS6.js.map +1 -0
- package/dist/openclaw-ETN2M63O.js +751 -0
- package/dist/openclaw-ETN2M63O.js.map +1 -0
- package/dist/openclaw-IYA7ASL6.js +150 -0
- package/dist/openclaw-IYA7ASL6.js.map +1 -0
- package/dist/opencode-FZ33JKUZ.js +734 -0
- package/dist/opencode-FZ33JKUZ.js.map +1 -0
- package/dist/opencode-HWT3RSMN.js +216 -0
- package/dist/opencode-HWT3RSMN.js.map +1 -0
- package/dist/package-DLOVE2E4.js +1132 -0
- package/dist/package-DLOVE2E4.js.map +1 -0
- package/dist/pi-CIU2QHT4.js +208 -0
- package/dist/pi-CIU2QHT4.js.map +1 -0
- package/dist/pi-UFX2OYFV.js +139 -0
- package/dist/pi-UFX2OYFV.js.map +1 -0
- package/dist/qwen-code-5POCNU6P.js +573 -0
- package/dist/qwen-code-5POCNU6P.js.map +1 -0
- package/dist/qwen-code-W7NUCDEN.js +134 -0
- package/dist/qwen-code-W7NUCDEN.js.map +1 -0
- package/dist/roo-code-IOIUXRDE.js +242 -0
- package/dist/roo-code-IOIUXRDE.js.map +1 -0
- package/dist/roo-code-ZLKH4A7N.js +229 -0
- package/dist/roo-code-ZLKH4A7N.js.map +1 -0
- package/dist/runtime/index.d.ts +157 -0
- package/dist/runtime/index.js +20 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/serve-HVWWY4B6.js +65 -0
- package/dist/serve-HVWWY4B6.js.map +1 -0
- package/dist/status-FE7TECZD.js +128 -0
- package/dist/status-FE7TECZD.js.map +1 -0
- package/dist/synthetic-UKR6SMGS.js +178 -0
- package/dist/synthetic-UKR6SMGS.js.map +1 -0
- package/dist/telemetry-36GESKQQ.js +349 -0
- package/dist/telemetry-36GESKQQ.js.map +1 -0
- package/dist/trae-JSNDZFKL.js +204 -0
- package/dist/trae-JSNDZFKL.js.map +1 -0
- package/dist/trae-PA26DPBW.js +157 -0
- package/dist/trae-PA26DPBW.js.map +1 -0
- package/dist/types-CYUB1OTr.d.ts +427 -0
- package/dist/uninstall-IGCKNOSF.js +72 -0
- package/dist/uninstall-IGCKNOSF.js.map +1 -0
- package/dist/upgrade-JV2VK242.js +104 -0
- package/dist/upgrade-JV2VK242.js.map +1 -0
- package/dist/usage-6ER6EMEY.js +324 -0
- package/dist/usage-6ER6EMEY.js.map +1 -0
- package/dist/usage-event-JKBI6XCF.js +48 -0
- package/dist/usage-event-JKBI6XCF.js.map +1 -0
- package/dist/vscode-copilot-CK3NO54M.js +715 -0
- package/dist/vscode-copilot-CK3NO54M.js.map +1 -0
- package/dist/warp-JNQA7PBU.js +126 -0
- package/dist/warp-JNQA7PBU.js.map +1 -0
- package/dist/warp-QNVDXOG4.js +199 -0
- package/dist/warp-QNVDXOG4.js.map +1 -0
- package/dist/zed-NNNX5MNT.js +272 -0
- package/dist/zed-NNNX5MNT.js.map +1 -0
- package/dist/zed-VRJKWYUR.js +209 -0
- package/dist/zed-VRJKWYUR.js.map +1 -0
- package/package.json +79 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/adapters/cursor/index.ts"],"sourcesContent":["/**\n * adapters/cursor — Cursor platform adapter for agent-connector.\n *\n * Generalized from context-mode's proven Cursor adapter: the served identity is\n * now `ctx.connector` (not a hardcoded \"context-mode\"), and every hook command\n * points at the single stable home binary (`buildHomeBinHookCommand`) so one\n * framework update propagates everywhere.\n *\n * Cursor is a json-stdio host:\n * - MCP servers: user scope → ~/.cursor/mcp.json (\"mcpServers\"); project scope\n * → <projectDir>/.cursor/mcp.json (\"mcpServers\").\n * - Hooks: <configDir>/hooks.json with shape `{ version, hooks: { <cursorEvent>:\n * [ { command, matcher? } ] } }`. Unlike Claude, each entry is a FLAT command\n * object (no `{ matcher, hooks:[...] }` wrapper).\n * - Reply: a JSON object on stdout (exit 0). deny/ask carry `permission` +\n * `user_message`; modify carries `updated_input`; context injects via\n * `agent_message` (PreToolUse) or `additional_context` (Post/SessionStart).\n *\n * Cursor supports its own `${env:VAR}` native interpolation, so env/header/url\n * values are rewritten to that native token rather than baked into the file.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport { BaseAdapter } from \"../base.js\";\nimport type { Adapter, HookReply, InstallContext, NormalizedEvent } from \"../spi.js\";\nimport type {\n ChangeRecord,\n CommandDef,\n DetectedPlatform,\n HealthCheck,\n HookEventName,\n HookParadigm,\n HookResponse,\n PlatformCapabilities,\n PlatformId,\n PostToolUseEvent,\n PreToolUseEvent,\n ServerDef,\n SessionStartEvent,\n SkillDef,\n StopEvent,\n SubagentDef,\n Transport,\n} from \"../../core/types.js\";\nimport { rewriteEnvRefs } from \"../../core/interpolate.js\";\nimport {\n buildHomeBinHookCommand,\n buildServeWrapperCommand,\n isHomeBinHookCommand,\n shouldWrapForTelemetry,\n} from \"../../core/spawn.js\";\n\nconst HOST: PlatformId = \"cursor\";\nconst MCP_ROOT_KEY = \"mcpServers\";\n\n/** Native hooks.json version Cursor expects. */\nconst CURSOR_HOOKS_VERSION = 1;\n\n/**\n * Cursor-native hook event names, in the lower-camel form Cursor reads from\n * hooks.json. These are the events the proven context-mode adapter registers.\n */\nconst CURSOR_EVENT = {\n PreToolUse: \"preToolUse\",\n PostToolUse: \"postToolUse\",\n SessionStart: \"sessionStart\",\n Stop: \"stop\",\n} as const;\n\n/**\n * Map our normalized event names to Cursor's native hook event names. Only the\n * events Cursor actually supports are present; everything else has no Cursor\n * equivalent and is reported as a skip/warn at install time.\n */\nconst EVENT_MAP: Partial<Record<HookEventName, string>> = {\n PreToolUse: CURSOR_EVENT.PreToolUse,\n PostToolUse: CURSOR_EVENT.PostToolUse,\n SessionStart: CURSOR_EVENT.SessionStart,\n Stop: CURSOR_EVENT.Stop,\n};\n\n/** A single Cursor native hook entry — a flat command object. */\ninterface CursorHookEntry {\n command: string;\n matcher?: string;\n}\n\n/** The shape of Cursor's hooks.json. */\ninterface CursorHooksFile {\n version?: number;\n hooks?: Record<string, CursorHookEntry[]>;\n}\n\n/** Native MCP server entry shapes Cursor accepts under `mcpServers`. */\ninterface CursorStdioServer {\n command: string;\n args?: string[];\n env?: Record<string, string>;\n cwd?: string;\n}\ninterface CursorHttpServer {\n url: string;\n headers?: Record<string, string>;\n}\n\n/** Raw Cursor hook stdin payload (snake_case wire fields). */\ninterface CursorWireInput {\n connector?: unknown;\n tool_name?: string;\n tool_input?: Record<string, unknown>;\n tool_output?: string;\n error_message?: string;\n cwd?: string;\n workspace_roots?: string[];\n conversation_id?: string;\n session_id?: string;\n generation_id?: string;\n source?: string;\n trigger?: string;\n status?: string;\n loop_count?: number;\n stop_hook_active?: boolean;\n}\n\nexport class CursorAdapter extends BaseAdapter implements Adapter {\n readonly id: PlatformId = HOST;\n readonly name = \"Cursor\";\n readonly paradigm: HookParadigm = \"json-stdio\";\n\n readonly capabilities: PlatformCapabilities = {\n // Cursor natively supports pre/post tool-use, session start, and stop.\n preToolUse: true,\n postToolUse: true,\n preCompact: false,\n sessionStart: true,\n sessionEnd: false,\n userPromptSubmit: false,\n stop: true,\n notification: false,\n // Cursor's preToolUse can rewrite tool input (updated_input) but cannot\n // rewrite already-emitted tool output.\n canModifyArgs: true,\n canModifyOutput: false,\n canInjectSessionContext: true,\n transports: [\"stdio\", \"http\"],\n // Content surfaces: Cursor supports all three (commands, skills, subagents).\n supportsCommands: true,\n supportsSkills: true,\n supportsSubagents: true,\n };\n\n // ── Detection ────────────────────────────────────────────────────────────\n\n detectInstalled(projectDir: string): DetectedPlatform {\n const userDir = join(homedir(), \".cursor\");\n const userMcp = join(userDir, \"mcp.json\");\n const userHooks = join(userDir, \"hooks.json\");\n const projectDirCursor = join(projectDir, \".cursor\");\n const installed =\n existsSync(userDir) ||\n existsSync(userMcp) ||\n existsSync(userHooks) ||\n existsSync(projectDirCursor);\n return {\n id: this.id,\n name: this.name,\n installed,\n paradigm: this.paradigm,\n capabilities: this.capabilities,\n configPath: userMcp,\n scope: \"user\",\n reason: installed\n ? `found Cursor config under ${userDir}`\n : `no Cursor config at ${userDir}`,\n confidence: installed ? \"high\" : \"low\",\n };\n }\n\n // ── Native paths ─────────────────────────────────────────────────────────\n\n getConfigDir(ctx: InstallContext): string {\n return ctx.scope === \"project\"\n ? join(ctx.projectDir, \".cursor\")\n : join(homedir(), \".cursor\");\n }\n\n getServerConfigPath(ctx: InstallContext): string {\n return join(this.getConfigDir(ctx), \"mcp.json\");\n }\n\n getHookConfigPath(ctx: InstallContext): string {\n return join(this.getConfigDir(ctx), \"hooks.json\");\n }\n\n // ── MCP server install / uninstall ───────────────────────────────────────\n\n installServer(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n const override = connector.platforms[HOST]?.server;\n if (!connector.server || override === false) {\n return [\n {\n platform: this.id,\n action: \"skip\",\n detail: connector.server\n ? \"server registration disabled for cursor\"\n : \"connector declares no MCP server\",\n },\n ];\n }\n\n // Shallow-merge any per-platform server override into the base ServerDef.\n const server: ServerDef =\n override && typeof override === \"object\"\n ? { ...connector.server, ...override }\n : connector.server;\n\n const serverPath = this.getServerConfigPath(ctx);\n const entry = this.renderServerEntry(ctx, server);\n\n return [\n this.upsertServerInJson(serverPath, MCP_ROOT_KEY, connector.id, entry, ctx.dryRun),\n ];\n }\n\n uninstallServer(ctx: InstallContext): ChangeRecord[] {\n const serverPath = this.getServerConfigPath(ctx);\n return [\n this.removeServerFromJson(serverPath, MCP_ROOT_KEY, ctx.connector.id, ctx.dryRun),\n ];\n }\n\n /** Render a normalized ServerDef into Cursor's native mcpServers entry. */\n private renderServerEntry(\n ctx: InstallContext,\n server: ServerDef,\n ): CursorStdioServer | CursorHttpServer {\n const transport: Transport = server.transport;\n\n if (transport === \"stdio\") {\n let command = server.command ?? \"\";\n let args = [...(server.args ?? [])];\n\n // Transparent telemetry wrapping: route the real command through\n // `<homeBin> serve --connector <id> -- <command> <args...>`.\n if (shouldWrapForTelemetry(server, ctx.connector.telemetry)) {\n const wrapped = buildServeWrapperCommand(\n ctx.homeBinPath,\n ctx.connector.id,\n command,\n args,\n ctx.scope,\n this.id,\n );\n command = wrapped.command;\n args = wrapped.args;\n }\n\n const entry: CursorStdioServer = { command: this.rewrite(command) };\n if (args.length > 0) entry.args = args.map((a) => this.rewrite(a));\n const env = this.renderEnv(server.env);\n if (env) entry.env = env;\n if (server.cwd) entry.cwd = this.rewrite(server.cwd);\n return entry;\n }\n\n // http (and any other remote transport we surface) — Cursor registers a URL.\n const entry: CursorHttpServer = { url: this.rewrite(server.url ?? \"\") };\n const headers = this.renderEnv(server.headers);\n if (headers) entry.headers = headers;\n return entry;\n }\n\n /**\n * Render env/header values. Cursor supports its own `${env:VAR}` native\n * interpolation, so translate `${env:VAR}` refs to that native token rather\n * than baking secrets into the file. Literals pass through unchanged.\n */\n private renderEnv(\n env: Record<string, string> | undefined,\n ): Record<string, string> | undefined {\n if (!env || Object.keys(env).length === 0) return undefined;\n const out: Record<string, string> = {};\n for (const [k, v] of Object.entries(env)) out[k] = this.rewrite(v);\n return out;\n }\n\n /** Translate `${env:VAR(:-default)}` to Cursor's native `${env:VAR}` token. */\n private rewrite(value: string): string {\n return rewriteEnvRefs(value, cursorEnvToken);\n }\n\n // ── Hook install / uninstall ─────────────────────────────────────────────\n\n installHooks(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n if (connector.platforms[HOST]?.hooks === false) {\n return [{ platform: this.id, action: \"skip\", detail: \"hooks disabled for cursor\" }];\n }\n if (connector.hookEvents.length === 0) {\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no hooks\" }];\n }\n\n const hooksPath = this.getHookConfigPath(ctx);\n const file = this.readJson<CursorHooksFile>(hooksPath) ?? {};\n const hooks = (file.hooks ??= {});\n\n const changes: ChangeRecord[] = [];\n let mutated = false;\n\n for (const event of connector.hookEvents) {\n const cursorEvent = EVENT_MAP[event];\n if (!cursorEvent) {\n // No Cursor equivalent for this normalized event — report and skip.\n changes.push({\n platform: this.id,\n action: \"warn\",\n path: hooksPath,\n detail: `${event} has no Cursor hook equivalent — skipped`,\n });\n continue;\n }\n\n const command = buildHomeBinHookCommand(ctx.homeBinPath, HOST, event, connector.id);\n const matcher = connector.hooks[event]?.matcher;\n const entry: CursorHookEntry = matcher ? { command, matcher } : { command };\n\n const bucket = (hooks[cursorEvent] ??= []);\n const existingIdx = bucket.findIndex((e) => this.isOurCommand(e.command, ctx));\n\n if (existingIdx >= 0) {\n if (JSON.stringify(bucket[existingIdx]) === JSON.stringify(entry)) {\n changes.push({\n platform: this.id,\n action: \"skip\",\n path: hooksPath,\n detail: `hooks.${cursorEvent} already registered`,\n });\n continue;\n }\n bucket[existingIdx] = entry;\n changes.push({\n platform: this.id,\n action: \"update\",\n path: hooksPath,\n detail: `hooks.${cursorEvent}`,\n });\n } else {\n bucket.push(entry);\n changes.push({\n platform: this.id,\n action: \"create\",\n path: hooksPath,\n detail: `hooks.${cursorEvent}`,\n });\n }\n mutated = true;\n }\n\n if (mutated) {\n file.version = CURSOR_HOOKS_VERSION;\n this.writeJson(hooksPath, file, ctx.dryRun);\n }\n return changes;\n }\n\n uninstallHooks(ctx: InstallContext): ChangeRecord[] {\n const hooksPath = this.getHookConfigPath(ctx);\n const file = this.readJson<CursorHooksFile>(hooksPath);\n const hooks = file?.hooks;\n if (!file || !hooks) {\n return [\n {\n platform: this.id,\n action: \"skip\",\n path: hooksPath,\n detail: \"no hooks section present\",\n },\n ];\n }\n\n const changes: ChangeRecord[] = [];\n let mutated = false;\n\n for (const cursorEvent of Object.keys(hooks)) {\n const bucket = hooks[cursorEvent];\n if (!Array.isArray(bucket)) continue;\n\n const before = bucket.length;\n const next = bucket.filter((e) => !this.isOurCommand(e.command, ctx));\n const removed = before - next.length;\n if (removed > 0) {\n if (next.length > 0) hooks[cursorEvent] = next;\n else delete hooks[cursorEvent];\n changes.push({\n platform: this.id,\n action: \"remove\",\n path: hooksPath,\n detail: `hooks.${cursorEvent} (${removed})`,\n });\n mutated = true;\n }\n }\n\n if (mutated) this.writeJson(hooksPath, file, ctx.dryRun);\n if (changes.length === 0) {\n changes.push({\n platform: this.id,\n action: \"skip\",\n path: hooksPath,\n detail: \"no matching hook entries\",\n });\n }\n return changes;\n }\n\n /** True when a hook command references our home binary AND this connector id\n * (anchored so a shared-prefix id can't collide — see isHomeBinHookCommand). */\n private isOurCommand(command: string | undefined, ctx: InstallContext): boolean {\n return isHomeBinHookCommand(command, ctx.homeBinPath, ctx.connector.id);\n }\n\n // ── Content surfaces: commands / skills / subagents ──────────────────────\n // CONTENT-ONLY: pure native-file writers under <configDir>/{commands,skills,\n // agents}. No runtime dispatch, no home-bin pointer, no telemetry wrap. Each\n // method is idempotent (byte-identical → skip) via BaseAdapter.writeContentFile\n // and reversible via removeContentFile. Honors platforms[\"cursor\"] per-surface\n // false to skip. Cursor commands are BODY-ONLY markdown (no frontmatter);\n // skills are the uniform <name>/SKILL.md + resources; subagents are md+fm.\n\n private commandsDir(ctx: InstallContext): string {\n return join(this.getConfigDir(ctx), \"commands\");\n }\n private skillsDir(ctx: InstallContext): string {\n return join(this.getConfigDir(ctx), \"skills\");\n }\n private agentsDir(ctx: InstallContext): string {\n return join(this.getConfigDir(ctx), \"agents\");\n }\n\n /** Native command file path: <configDir>/commands/<name>.md. */\n private commandPath(ctx: InstallContext, name: string): string {\n return join(this.commandsDir(ctx), `${name}.md`);\n }\n /** Native skill dir: <configDir>/skills/<name>. */\n private skillDir(ctx: InstallContext, name: string): string {\n return join(this.skillsDir(ctx), name);\n }\n /** Native subagent file path: <configDir>/agents/<name>.md. */\n private subagentPath(ctx: InstallContext, name: string): string {\n return join(this.agentsDir(ctx), `${name}.md`);\n }\n\n // ── Commands ──────────────────────────────────────────────────────────────\n\n override installCommands(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n if (connector.platforms[HOST]?.commands === false) {\n return [{ platform: this.id, action: \"skip\", detail: \"commands disabled for cursor\" }];\n }\n if (connector.commands.length === 0) {\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no commands\" }];\n }\n return connector.commands.map((cmd) =>\n this.writeContentFile(\n this.commandPath(ctx, cmd.name),\n this.renderCommand(cmd),\n ctx.dryRun,\n ),\n );\n }\n\n override uninstallCommands(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n if (connector.commands.length === 0) {\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no commands\" }];\n }\n return connector.commands.map((cmd) =>\n this.removeContentFile(this.commandPath(ctx, cmd.name), ctx.dryRun),\n );\n }\n\n /**\n * Render a Cursor command: BODY-ONLY markdown (no frontmatter). Cursor reads\n * the file as the command prompt verbatim. We prepend the one-line description\n * as an HTML comment header when present so authoring intent survives the\n * round-trip without leaking into the rendered prompt. A description containing\n * \"-->\" would prematurely CLOSE the HTML comment and leak the remainder into\n * the prompt, so we neutralize that sequence before embedding it.\n */\n private renderCommand(cmd: CommandDef): string {\n if (!cmd.description) return `${cmd.prompt}\\n`;\n // Break any literal comment-close so it cannot terminate our header early.\n const safe = cmd.description.replace(/--+>/g, (m) => m.replace(/>/g, \">\"));\n return `<!-- ${safe} -->\\n\\n${cmd.prompt}\\n`;\n }\n\n // ── Skills ────────────────────────────────────────────────────────────────\n\n override installSkills(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n if (connector.platforms[HOST]?.skills === false) {\n return [{ platform: this.id, action: \"skip\", detail: \"skills disabled for cursor\" }];\n }\n if (connector.skills.length === 0) {\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no skills\" }];\n }\n const changes: ChangeRecord[] = [];\n for (const skill of connector.skills) {\n const dir = this.skillDir(ctx, skill.name);\n changes.push(\n this.writeContentFile(join(dir, \"SKILL.md\"), this.renderSkill(skill), ctx.dryRun),\n );\n // Bundle any resource files beside SKILL.md (relative path → contents).\n // Defense-in-depth: skip+warn on any key that escapes the skill dir\n // (config-time validation already rejects these, but never trust input).\n for (const [rel, contents] of Object.entries(skill.resources ?? {})) {\n const target = this.resolveWithin(dir, rel);\n if (target === null) {\n changes.push({\n platform: this.id,\n action: \"warn\",\n detail: `skill resource \"${rel}\" escapes the skill dir; skipped`,\n });\n continue;\n }\n changes.push(this.writeContentFile(target, contents, ctx.dryRun));\n }\n }\n return changes;\n }\n\n override uninstallSkills(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n if (connector.skills.length === 0) {\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no skills\" }];\n }\n const changes: ChangeRecord[] = [];\n for (const skill of connector.skills) {\n const dir = this.skillDir(ctx, skill.name);\n // Remove only the files we wrote (SKILL.md + declared resources), then the\n // skill dir itself when we own its full contents.\n changes.push(this.removeContentFile(join(dir, \"SKILL.md\"), ctx.dryRun));\n for (const rel of Object.keys(skill.resources ?? {})) {\n const target = this.resolveWithin(dir, rel);\n if (target === null) continue; // never delete outside the skill dir\n changes.push(this.removeContentFile(target, ctx.dryRun));\n }\n // Only remove the skill dir when WE own its full contents — never rm -rf a\n // dir that still holds user-added / sibling-tool / shared files.\n changes.push(this.removeDirIfEmpty(dir, ctx.dryRun));\n }\n return changes;\n }\n\n /**\n * Render a skill's SKILL.md: frontmatter (name, description + optional model,\n * allowed-tools, disable-model-invocation) + body. Uniform across platforms;\n * only the parent dir differs.\n */\n private renderSkill(skill: SkillDef): string {\n const frontmatter: Record<string, unknown> = {\n name: skill.name,\n description: skill.description,\n };\n if (skill.model !== undefined) frontmatter.model = skill.model;\n const allow = skill.tools?.allow;\n if (allow && allow.length > 0) frontmatter[\"allowed-tools\"] = allow.join(\", \");\n if (skill.disableModelInvocation !== undefined) {\n frontmatter[\"disable-model-invocation\"] = skill.disableModelInvocation;\n }\n if (skill.extra) Object.assign(frontmatter, skill.extra);\n return this.renderFrontmatterMd(frontmatter, skill.body);\n }\n\n // ── Subagents ───────────────────────────────────────────────────────────────\n\n override installSubagents(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n if (connector.platforms[HOST]?.subagents === false) {\n return [{ platform: this.id, action: \"skip\", detail: \"subagents disabled for cursor\" }];\n }\n if (connector.subagents.length === 0) {\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no subagents\" }];\n }\n return connector.subagents.map((agent) =>\n this.writeContentFile(\n this.subagentPath(ctx, agent.name),\n this.renderSubagent(agent),\n ctx.dryRun,\n ),\n );\n }\n\n override uninstallSubagents(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n if (connector.subagents.length === 0) {\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no subagents\" }];\n }\n return connector.subagents.map((agent) =>\n this.removeContentFile(this.subagentPath(ctx, agent.name), ctx.dryRun),\n );\n }\n\n /** Render a Cursor subagent to md+frontmatter (name, description, model, readonly) + prompt body. */\n private renderSubagent(agent: SubagentDef): string {\n const frontmatter: Record<string, unknown> = {\n name: agent.name,\n description: agent.description,\n };\n if (agent.model !== undefined) frontmatter.model = agent.model;\n if (agent.readonly !== undefined) frontmatter.readonly = agent.readonly;\n if (agent.extra) Object.assign(frontmatter, agent.extra);\n return this.renderFrontmatterMd(frontmatter, agent.prompt);\n }\n\n // ── Diagnostics ──────────────────────────────────────────────────────────\n\n override getHealthChecks(ctx: InstallContext): readonly HealthCheck[] {\n const mcpPath = this.getServerConfigPath(ctx);\n const hooksPath = this.getHookConfigPath(ctx);\n const checks: HealthCheck[] = [\n {\n name: `${this.name}: mcp.json present`,\n check: () =>\n existsSync(mcpPath)\n ? { status: \"OK\", detail: mcpPath }\n : { status: \"FAIL\", detail: `not found: ${mcpPath}` },\n },\n {\n name: `${this.name}: hooks.json present`,\n check: () =>\n existsSync(hooksPath)\n ? { status: \"OK\", detail: hooksPath }\n : { status: \"FAIL\", detail: `not found: ${hooksPath}` },\n },\n ];\n\n // Content-surface checks: only assert presence of the files this connector\n // declares (skip silently for surfaces it never asked for).\n for (const cmd of ctx.connector.commands) {\n const p = this.commandPath(ctx, cmd.name);\n checks.push({\n name: `${this.name}: command ${cmd.name} present`,\n check: () =>\n existsSync(p) ? { status: \"OK\", detail: p } : { status: \"FAIL\", detail: `not found: ${p}` },\n });\n }\n for (const skill of ctx.connector.skills) {\n const p = join(this.skillDir(ctx, skill.name), \"SKILL.md\");\n checks.push({\n name: `${this.name}: skill ${skill.name} present`,\n check: () =>\n existsSync(p) ? { status: \"OK\", detail: p } : { status: \"FAIL\", detail: `not found: ${p}` },\n });\n }\n for (const agent of ctx.connector.subagents) {\n const p = this.subagentPath(ctx, agent.name);\n checks.push({\n name: `${this.name}: subagent ${agent.name} present`,\n check: () =>\n existsSync(p) ? { status: \"OK\", detail: p } : { status: \"FAIL\", detail: `not found: ${p}` },\n });\n }\n return checks;\n }\n\n // ── Runtime: parse Cursor stdin JSON → normalized event ──────────────────\n\n parseEvent(event: HookEventName, raw: unknown): NormalizedEvent {\n const input = (raw ?? {}) as CursorWireInput;\n const connectorId = typeof input.connector === \"string\" ? input.connector : \"\";\n const sessionId = extractSessionId(input);\n const projectDir = this.getProjectDir(input);\n\n const base = {\n hostPlatform: HOST,\n connectorId,\n sessionId,\n raw,\n ...(projectDir !== undefined ? { projectDir } : {}),\n } as const;\n\n switch (event) {\n case \"PreToolUse\": {\n const ev: PreToolUseEvent = {\n ...base,\n toolName: input.tool_name ?? \"\",\n toolInput: input.tool_input ?? {},\n };\n return ev;\n }\n case \"PostToolUse\": {\n const toolOutput = input.tool_output ?? input.error_message;\n const ev: PostToolUseEvent = {\n ...base,\n toolName: input.tool_name ?? \"\",\n toolInput: input.tool_input ?? {},\n ...(toolOutput !== undefined ? { toolOutput } : {}),\n ...(input.error_message ? { isError: true } : {}),\n };\n return ev;\n }\n case \"SessionStart\": {\n const ev: SessionStartEvent = {\n ...base,\n source: normalizeSessionSource(input.source ?? input.trigger),\n };\n return ev;\n }\n case \"Stop\": {\n const ev: StopEvent = {\n ...base,\n ...(typeof input.stop_hook_active === \"boolean\"\n ? { stopHookActive: input.stop_hook_active }\n : {}),\n };\n return ev;\n }\n default: {\n // Cursor never delivers SessionEnd / UserPromptSubmit / PreCompact /\n // Notification (no native equivalent). If the runtime dispatches one\n // anyway, surface a base event of the requested kind so it stays inert.\n throw new Error(`unsupported cursor hook event: ${String(event)}`);\n }\n }\n }\n\n private getProjectDir(input: CursorWireInput): string | undefined {\n return input.cwd ?? input.workspace_roots?.[0] ?? undefined;\n }\n\n // ── Runtime: normalized response → Cursor native hook reply ──────────────\n\n formatReply(event: HookEventName, response: HookResponse): HookReply {\n const decision = response.decision ?? \"allow\";\n\n // deny → block the action with a user-facing message.\n if (decision === \"deny\") {\n return this.stdout({\n permission: \"deny\",\n user_message: response.reason ?? \"Blocked by hook\",\n });\n }\n\n // ask → prompt the user to confirm.\n if (decision === \"ask\") {\n return this.stdout({\n permission: \"ask\",\n user_message: response.reason ?? \"Confirmation required by hook\",\n });\n }\n\n // modify → rewrite PreToolUse input (only where Cursor supports it).\n if (decision === \"modify\") {\n if (event === \"PreToolUse\" && response.updatedInput) {\n return this.stdout({ updated_input: response.updatedInput });\n }\n // Output rewrite is unsupported on Cursor; fall through to allow.\n }\n\n // context → inject soft guidance. PreToolUse uses `agent_message`; Post and\n // SessionStart use `additional_context`.\n if (decision === \"context\" && response.additionalContext) {\n return event === \"PreToolUse\"\n ? this.stdout({ agent_message: response.additionalContext })\n : this.stdout({ additional_context: response.additionalContext });\n }\n\n // SessionStart always emits valid JSON even on a no-op (Cursor rejects empty\n // stdout as \"no valid response\").\n if (event === \"SessionStart\") {\n return this.stdout({ additional_context: response.additionalContext ?? \"\" });\n }\n\n // allow / void → minimal no-op payload (Cursor rejects empty stdout).\n if (event === \"PreToolUse\") return this.stdout({ agent_message: \"\" });\n if (event === \"PostToolUse\") return this.stdout({ additional_context: \"\" });\n return { exitCode: 0 };\n }\n\n private stdout(payload: unknown): HookReply {\n return { exitCode: 0, stdout: JSON.stringify(payload) };\n }\n}\n\n/** Cursor native interpolation token: `${env:VAR}` → `${env:VAR}` (passthrough). */\nfunction cursorEnvToken(name: string): string {\n return `\\${env:${name}}`;\n}\n\nfunction extractSessionId(input: CursorWireInput): string {\n if (typeof input.conversation_id === \"string\") return input.conversation_id;\n if (typeof input.session_id === \"string\") return input.session_id;\n return \"\";\n}\n\nfunction normalizeSessionSource(source: string | undefined): SessionStartEvent[\"source\"] {\n switch (source) {\n case \"compact\":\n return \"compact\";\n case \"resume\":\n return \"resume\";\n case \"clear\":\n return \"clear\";\n default:\n return \"startup\";\n }\n}\n\nexport const adapter = new CursorAdapter();\nexport default adapter;\n"],"mappings":"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","names":["entry"]}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
firstExistingRoot,
|
|
4
|
+
walkFiles
|
|
5
|
+
} from "./chunk-JWNT5KW7.js";
|
|
6
|
+
import {
|
|
7
|
+
emptyTokens,
|
|
8
|
+
inferProvider
|
|
9
|
+
} from "./chunk-XD7MY6HB.js";
|
|
10
|
+
|
|
11
|
+
// src/usage/readers/cursor.ts
|
|
12
|
+
import { basename } from "path";
|
|
13
|
+
import { readFileSync } from "fs";
|
|
14
|
+
var PLATFORM_ID = "cursor";
|
|
15
|
+
var DEFAULT_PROVIDER = "cursor";
|
|
16
|
+
var V1_COLUMNS = {
|
|
17
|
+
model: 1,
|
|
18
|
+
inputCacheWrite: 2,
|
|
19
|
+
inputNoCache: 3,
|
|
20
|
+
cacheRead: 4,
|
|
21
|
+
output: 5,
|
|
22
|
+
cost: 7
|
|
23
|
+
};
|
|
24
|
+
var V2_COLUMNS = {
|
|
25
|
+
model: 2,
|
|
26
|
+
inputCacheWrite: 4,
|
|
27
|
+
inputNoCache: 5,
|
|
28
|
+
cacheRead: 6,
|
|
29
|
+
output: 7,
|
|
30
|
+
cost: 9
|
|
31
|
+
};
|
|
32
|
+
var V3_COLUMNS = {
|
|
33
|
+
model: 4,
|
|
34
|
+
inputCacheWrite: 6,
|
|
35
|
+
inputNoCache: 7,
|
|
36
|
+
cacheRead: 8,
|
|
37
|
+
output: 9,
|
|
38
|
+
cost: 11
|
|
39
|
+
};
|
|
40
|
+
function accountIdFromPath(path) {
|
|
41
|
+
const fileName = basename(path) || "usage.csv";
|
|
42
|
+
if (fileName === "usage.csv") return "active";
|
|
43
|
+
if (fileName.startsWith("usage.") && fileName.endsWith(".csv")) {
|
|
44
|
+
const stem = fileName.slice("usage.".length, fileName.length - ".csv".length);
|
|
45
|
+
let cleaned = "";
|
|
46
|
+
for (const ch of stem) {
|
|
47
|
+
cleaned += /[A-Za-z0-9._-]/.test(ch) ? ch : "-";
|
|
48
|
+
}
|
|
49
|
+
return cleaned === "" ? "unknown" : cleaned;
|
|
50
|
+
}
|
|
51
|
+
return "unknown";
|
|
52
|
+
}
|
|
53
|
+
function toNonNegInt(field) {
|
|
54
|
+
const trimmed = field.trim().replace(/^"|"$/g, "").trim();
|
|
55
|
+
const n = Number(trimmed);
|
|
56
|
+
if (!Number.isFinite(n)) return 0;
|
|
57
|
+
return Math.max(0, Math.trunc(n));
|
|
58
|
+
}
|
|
59
|
+
function parseCost(costStr) {
|
|
60
|
+
const cleaned = costStr.replace(/[$,]/g, "");
|
|
61
|
+
const trimmed = cleaned.trim();
|
|
62
|
+
if (trimmed === "" || trimmed.toLowerCase() === "nan" || !/[0-9]/.test(trimmed)) {
|
|
63
|
+
return 0;
|
|
64
|
+
}
|
|
65
|
+
const n = Number(trimmed);
|
|
66
|
+
return Number.isFinite(n) ? n : 0;
|
|
67
|
+
}
|
|
68
|
+
function parseCsvLine(line) {
|
|
69
|
+
const fields = [];
|
|
70
|
+
let start = 0;
|
|
71
|
+
let inQuotes = false;
|
|
72
|
+
for (let i = 0; i < line.length; i++) {
|
|
73
|
+
const ch = line[i];
|
|
74
|
+
if (ch === '"') {
|
|
75
|
+
inQuotes = !inQuotes;
|
|
76
|
+
} else if (ch === "," && !inQuotes) {
|
|
77
|
+
fields.push(line.slice(start, i));
|
|
78
|
+
start = i + 1;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
fields.push(line.slice(start));
|
|
82
|
+
return fields;
|
|
83
|
+
}
|
|
84
|
+
function unquote(field) {
|
|
85
|
+
return field.trim().replace(/^"|"$/g, "");
|
|
86
|
+
}
|
|
87
|
+
function parseDateToMs(dateStr) {
|
|
88
|
+
if (dateStr.includes("T")) {
|
|
89
|
+
const ms = Date.parse(dateStr);
|
|
90
|
+
return Number.isNaN(ms) ? null : ms;
|
|
91
|
+
}
|
|
92
|
+
const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(dateStr);
|
|
93
|
+
if (m !== null) {
|
|
94
|
+
const year = Number(m[1]);
|
|
95
|
+
const month = Number(m[2]);
|
|
96
|
+
const day = Number(m[3]);
|
|
97
|
+
const ms = Date.UTC(year, month - 1, day, 12, 0, 0, 0);
|
|
98
|
+
return Number.isNaN(ms) ? null : ms;
|
|
99
|
+
}
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
function detectColumns(header) {
|
|
103
|
+
if (!header.includes("Date") || !header.includes("Model")) return null;
|
|
104
|
+
const fields = parseCsvLine(header);
|
|
105
|
+
const hasKind = fields.some((f) => f.trim() === "Kind");
|
|
106
|
+
const columnCount = fields.length;
|
|
107
|
+
if (hasKind && columnCount >= 11) return V3_COLUMNS;
|
|
108
|
+
if (hasKind) return V2_COLUMNS;
|
|
109
|
+
return V1_COLUMNS;
|
|
110
|
+
}
|
|
111
|
+
function parseCursorFile(path) {
|
|
112
|
+
let content;
|
|
113
|
+
try {
|
|
114
|
+
content = readFileSync(path, "utf8");
|
|
115
|
+
} catch {
|
|
116
|
+
return [];
|
|
117
|
+
}
|
|
118
|
+
const lines = content.split("\n");
|
|
119
|
+
if (lines.length === 0) return [];
|
|
120
|
+
const header = lines[0];
|
|
121
|
+
if (header === void 0) return [];
|
|
122
|
+
const columns = detectColumns(header);
|
|
123
|
+
if (columns === null) return [];
|
|
124
|
+
const minFields = columns.cost + 1;
|
|
125
|
+
const accountId = accountIdFromPath(path);
|
|
126
|
+
const out = [];
|
|
127
|
+
for (let i = 1; i < lines.length; i++) {
|
|
128
|
+
const rawLine = lines[i];
|
|
129
|
+
if (rawLine === void 0) continue;
|
|
130
|
+
const line = rawLine.replace(/\r$/, "");
|
|
131
|
+
if (line.trim() === "") continue;
|
|
132
|
+
const fields = parseCsvLine(line);
|
|
133
|
+
if (fields.length < minFields) continue;
|
|
134
|
+
const dateStr = unquote(fields[0] ?? "");
|
|
135
|
+
const model = unquote(fields[columns.model] ?? "");
|
|
136
|
+
if (model === "") continue;
|
|
137
|
+
const ts = parseDateToMs(dateStr);
|
|
138
|
+
if (ts === null) continue;
|
|
139
|
+
const inputWithCacheWrite = toNonNegInt(fields[columns.inputCacheWrite] ?? "");
|
|
140
|
+
const inputWithoutCacheWrite = toNonNegInt(fields[columns.inputNoCache] ?? "");
|
|
141
|
+
const cacheReadTokens = toNonNegInt(fields[columns.cacheRead] ?? "");
|
|
142
|
+
const outputTokens = toNonNegInt(fields[columns.output] ?? "");
|
|
143
|
+
const cost = Math.max(0, parseCost(unquote(fields[columns.cost] ?? "")));
|
|
144
|
+
const cacheWrite = Math.max(0, inputWithCacheWrite - inputWithoutCacheWrite);
|
|
145
|
+
const input = Math.max(0, inputWithoutCacheWrite);
|
|
146
|
+
const providerId = inferProvider(model) ?? DEFAULT_PROVIDER;
|
|
147
|
+
const sessionId = `cursor-${accountId}-${dateStr}`;
|
|
148
|
+
const tokens = emptyTokens();
|
|
149
|
+
tokens.input = input;
|
|
150
|
+
tokens.output = outputTokens;
|
|
151
|
+
tokens.cacheRead = cacheReadTokens;
|
|
152
|
+
tokens.cacheWrite = cacheWrite;
|
|
153
|
+
const record = {
|
|
154
|
+
platformId: PLATFORM_ID,
|
|
155
|
+
modelId: model,
|
|
156
|
+
providerId,
|
|
157
|
+
sessionId,
|
|
158
|
+
tokens,
|
|
159
|
+
cost,
|
|
160
|
+
ts,
|
|
161
|
+
messageCount: 1,
|
|
162
|
+
dedupKey: sessionId,
|
|
163
|
+
confidence: "host-reported"
|
|
164
|
+
};
|
|
165
|
+
out.push(record);
|
|
166
|
+
}
|
|
167
|
+
return out;
|
|
168
|
+
}
|
|
169
|
+
var cursorReader = {
|
|
170
|
+
platformId: PLATFORM_ID,
|
|
171
|
+
kind: "synced",
|
|
172
|
+
async read({ sinceMs }) {
|
|
173
|
+
const root = firstExistingRoot(PLATFORM_ID);
|
|
174
|
+
if (root === void 0) return [];
|
|
175
|
+
const files = walkFiles(root, (name) => {
|
|
176
|
+
const lower = name.toLowerCase();
|
|
177
|
+
return lower.startsWith("usage") && lower.endsWith(".csv");
|
|
178
|
+
});
|
|
179
|
+
const records = [];
|
|
180
|
+
for (const file of files) {
|
|
181
|
+
const rows = parseCursorFile(file);
|
|
182
|
+
for (const row of rows) {
|
|
183
|
+
if (sinceMs !== void 0 && row.ts < sinceMs) continue;
|
|
184
|
+
records.push(row);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return records;
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
var cursor_default = cursorReader;
|
|
191
|
+
export {
|
|
192
|
+
cursor_default as default
|
|
193
|
+
};
|
|
194
|
+
//# sourceMappingURL=cursor-QZ6MTO74.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/usage/readers/cursor.ts"],"sourcesContent":["/**\n * usage/readers/cursor — Cursor IDE usage reader (SYNCED platform).\n *\n * Faithful port of tokscale sessions/cursor.rs. Cursor's per-event token usage\n * lives behind the Cursor dashboard export API; tokscale fetches it and caches\n * the result as CSV under ~/.config/tokscale/cursor-cache/. THIS reader never\n * authenticates and never calls that API — it only parses the cached CSV when a\n * tokscale run has already produced it. Hence kind:\"synced\":\n * - cache present → parse the CSV(s) and emit one record per data row;\n * - cache absent → return [] (the scan layer notes \"requires sync, skipped\").\n *\n * Cache layout (per docs/research/usage-readers.json + design §3d):\n * ~/.config/tokscale/cursor-cache/usage.csv (active account)\n * ~/.config/tokscale/cursor-cache/usage.<account>.csv (secondary accounts)\n * ~/.config/tokscale/cursor-cache/archive/*.csv (rotated exports)\n * paths.ts resolves the cache dir (env override AGENT_CONNECTOR_TOKSCALE_DIR\n * first, the tokscale ~/.config/tokscale default second).\n *\n * CSV formats (column maps mirror cursor.rs exactly):\n * v1 (no \"Kind\"): Date,Model,Input(w/CacheWrite),Input(w/oCacheWrite),CacheRead,Output,Total,Cost,CostToYou\n * → model 1, in+cw 2, in 3, cacheRead 4, output 5, cost 7\n * v2 (has \"Kind\", <11 cols): Date,Kind,Model,MaxMode,Input(w/CW),Input(w/oCW),CacheRead,Output,Total,Cost\n * → model 2, in+cw 4, in 5, cacheRead 6, output 7, cost 9\n * v3 (has \"Kind\", ≥11 cols): Date,CloudAgentID,AutomationID,Kind,Model,MaxMode,Input(w/CW),Input(w/oCW),CacheRead,Output,Total,Cost\n * → model 4, in+cw 6, in 7, cacheRead 8, output 9, cost 11\n *\n * Per-row token math (port of parse_cursor_file):\n * input = Input(w/o CacheWrite) (clamped ≥ 0)\n * cacheWrite = Input(w/ CacheWrite) − Input(w/o CacheWrite) (clamped ≥ 0)\n * cacheRead = Cache Read (clamped ≥ 0)\n * output = Output Tokens (clamped ≥ 0)\n * reasoning = 0 (Cursor does not report it)\n * Cost is parsed from the Cost column (\"$1,234.56\" → 1234.56; \"Included\"/\"-\"/\n * \"NaN\"/\"\" → 0). Timestamp parses the Date column (ISO 8601 with/without ms/Z,\n * or date-only → noon UTC so local-day filtering never shifts the row).\n *\n * Attribution: provider inferred from the model (defaults to \"cursor\" for\n * Cursor-only ids like \"auto\"/\"composer-2\"); sessionId is the composite\n * `cursor-<account>-<date>` where account derives from the filename\n * (usage.csv → \"active\", usage.<x>.csv → sanitized \"<x>\"). No project scope\n * (account-level usage). Cursor ships no dedup key; the composite session id is\n * the implicit dedup, so dedupKey mirrors it. Confidence is \"host-reported\"\n * (the cached data carries real host token counts).\n *\n * Fail-open: no cache dir → []; unreadable/malformed file → skipped; a row\n * missing columns, with an empty model, or an unparseable date → skipped.\n */\n\nimport { basename } from \"node:path\";\n\nimport type { TokenBreakdown, UsageReader, UsageRecord } from \"../types.js\";\nimport { emptyTokens } from \"../aggregate.js\";\nimport { inferProvider } from \"../normalize.js\";\nimport { firstExistingRoot, walkFiles } from \"../paths.js\";\n\nimport { readFileSync } from \"node:fs\";\n\nconst PLATFORM_ID = \"cursor\" as const;\nconst DEFAULT_PROVIDER = \"cursor\";\n\n/** Column-index map for one CSV format (mirrors cursor.rs tuple order). */\ninterface ColumnMap {\n model: number;\n inputCacheWrite: number;\n inputNoCache: number;\n cacheRead: number;\n output: number;\n cost: number;\n}\n\nconst V1_COLUMNS: ColumnMap = {\n model: 1,\n inputCacheWrite: 2,\n inputNoCache: 3,\n cacheRead: 4,\n output: 5,\n cost: 7,\n};\nconst V2_COLUMNS: ColumnMap = {\n model: 2,\n inputCacheWrite: 4,\n inputNoCache: 5,\n cacheRead: 6,\n output: 7,\n cost: 9,\n};\nconst V3_COLUMNS: ColumnMap = {\n model: 4,\n inputCacheWrite: 6,\n inputNoCache: 7,\n cacheRead: 8,\n output: 9,\n cost: 11,\n};\n\n/**\n * Derive the account id from a cache filename (port of\n * account_id_from_cursor_cache_path):\n * - \"usage.csv\" → \"active\";\n * - \"usage.<x>.csv\" → \"<x>\" with non-[A-Za-z0-9-_.] chars replaced by '-'\n * (empty after cleaning → \"unknown\");\n * - anything else → \"unknown\".\n */\nfunction accountIdFromPath(path: string): string {\n const fileName = basename(path) || \"usage.csv\";\n if (fileName === \"usage.csv\") return \"active\";\n\n if (fileName.startsWith(\"usage.\") && fileName.endsWith(\".csv\")) {\n const stem = fileName.slice(\"usage.\".length, fileName.length - \".csv\".length);\n let cleaned = \"\";\n for (const ch of stem) {\n cleaned += /[A-Za-z0-9._-]/.test(ch) ? ch : \"-\";\n }\n return cleaned === \"\" ? \"unknown\" : cleaned;\n }\n\n return \"unknown\";\n}\n\n/** Coerce a CSV field to a non-negative integer (0 on absence/garbage). */\nfunction toNonNegInt(field: string): number {\n const trimmed = field.trim().replace(/^\"|\"$/g, \"\").trim();\n const n = Number(trimmed);\n if (!Number.isFinite(n)) return 0;\n return Math.max(0, Math.trunc(n));\n}\n\n/**\n * Parse a cost string like \"$0.50\" / \"1,234.56\" to a number. Port of parse_cost:\n * strip '$' and ',', then 0 for empty / \"NaN\" / values with no ASCII digit\n * (e.g. \"Included\", \"-\"). Negative results are clamped to 0 by the caller.\n */\nfunction parseCost(costStr: string): number {\n const cleaned = costStr.replace(/[$,]/g, \"\");\n const trimmed = cleaned.trim();\n if (trimmed === \"\" || trimmed.toLowerCase() === \"nan\" || !/[0-9]/.test(trimmed)) {\n return 0;\n }\n const n = Number(trimmed);\n return Number.isFinite(n) ? n : 0;\n}\n\n/**\n * Simple CSV line splitter that respects quoted fields (port of parse_csv_line):\n * a '\"' toggles quote state, a ',' outside quotes ends a field. Quote characters\n * are kept in the slice (callers strip surrounding quotes per field), matching\n * the Rust byte-index behavior.\n */\nfunction parseCsvLine(line: string): string[] {\n const fields: string[] = [];\n let start = 0;\n let inQuotes = false;\n for (let i = 0; i < line.length; i++) {\n const ch = line[i];\n if (ch === '\"') {\n inQuotes = !inQuotes;\n } else if (ch === \",\" && !inQuotes) {\n fields.push(line.slice(start, i));\n start = i + 1;\n }\n }\n fields.push(line.slice(start));\n return fields;\n}\n\n/** Trim a field and strip a single layer of surrounding double quotes. */\nfunction unquote(field: string): string {\n return field.trim().replace(/^\"|\"$/g, \"\");\n}\n\n/**\n * Parse a Cursor Date string to epoch ms (port of parse_date_to_timestamp).\n * Tries ISO 8601 with/without ms and trailing Z, then date-only (→ noon UTC so\n * the local date is stable for any tz from UTC-12..UTC+14). Returns null when\n * unparseable (the row is then skipped, matching the Rust ts==0 skip).\n */\nfunction parseDateToMs(dateStr: string): number | null {\n // ISO forms with explicit time: Date.parse handles\n // \"YYYY-MM-DDTHH:MM:SS\", \"...SS.mmm\", and either with a trailing \"Z\".\n if (dateStr.includes(\"T\")) {\n const ms = Date.parse(dateStr);\n return Number.isNaN(ms) ? null : ms;\n }\n\n // Date-only \"YYYY-MM-DD\" → noon UTC (12:00:00Z).\n const m = /^(\\d{4})-(\\d{2})-(\\d{2})$/.exec(dateStr);\n if (m !== null) {\n const year = Number(m[1]);\n const month = Number(m[2]);\n const day = Number(m[3]);\n const ms = Date.UTC(year, month - 1, day, 12, 0, 0, 0);\n return Number.isNaN(ms) ? null : ms;\n }\n\n return null;\n}\n\n/**\n * Pick the column map for a header line (port of the cursor.rs format detect):\n * a \"Kind\" column with ≥11 total columns is v3; \"Kind\" with fewer is v2; no\n * \"Kind\" is v1. Returns null when the header is not a recognizable Cursor CSV\n * (must contain both \"Date\" and \"Model\").\n */\nfunction detectColumns(header: string): ColumnMap | null {\n if (!header.includes(\"Date\") || !header.includes(\"Model\")) return null;\n\n const fields = parseCsvLine(header);\n const hasKind = fields.some((f) => f.trim() === \"Kind\");\n const columnCount = fields.length;\n\n if (hasKind && columnCount >= 11) return V3_COLUMNS;\n if (hasKind) return V2_COLUMNS;\n return V1_COLUMNS;\n}\n\n/** Parse one cached Cursor CSV file into usage records (port of parse_cursor_file). */\nfunction parseCursorFile(path: string): UsageRecord[] {\n let content: string;\n try {\n content = readFileSync(path, \"utf8\");\n } catch {\n return []; // unreadable → fail-open\n }\n\n const lines = content.split(\"\\n\");\n if (lines.length === 0) return [];\n\n const header = lines[0];\n if (header === undefined) return [];\n\n const columns = detectColumns(header);\n if (columns === null) return []; // not a Cursor CSV\n\n const minFields = columns.cost + 1;\n const accountId = accountIdFromPath(path);\n const out: UsageRecord[] = [];\n\n for (let i = 1; i < lines.length; i++) {\n const rawLine = lines[i];\n if (rawLine === undefined) continue;\n // Strip a trailing CR (CRLF files) before the empty-line check.\n const line = rawLine.replace(/\\r$/, \"\");\n if (line.trim() === \"\") continue;\n\n const fields = parseCsvLine(line);\n if (fields.length < minFields) continue; // not enough columns for this format\n\n const dateStr = unquote(fields[0] ?? \"\");\n const model = unquote(fields[columns.model] ?? \"\");\n if (model === \"\") continue; // skip empty/errored entries\n\n const ts = parseDateToMs(dateStr);\n if (ts === null) continue; // unparseable date → skip (Rust ts==0)\n\n const inputWithCacheWrite = toNonNegInt(fields[columns.inputCacheWrite] ?? \"\");\n const inputWithoutCacheWrite = toNonNegInt(fields[columns.inputNoCache] ?? \"\");\n const cacheReadTokens = toNonNegInt(fields[columns.cacheRead] ?? \"\");\n const outputTokens = toNonNegInt(fields[columns.output] ?? \"\");\n const cost = Math.max(0, parseCost(unquote(fields[columns.cost] ?? \"\")));\n\n // cacheWrite = (w/ cache write) − (w/o cache write), clamped ≥ 0.\n const cacheWrite = Math.max(0, inputWithCacheWrite - inputWithoutCacheWrite);\n const input = Math.max(0, inputWithoutCacheWrite);\n\n const providerId = inferProvider(model) ?? DEFAULT_PROVIDER;\n // Composite session id is also the implicit dedup key (Cursor has none).\n const sessionId = `cursor-${accountId}-${dateStr}`;\n\n const tokens: TokenBreakdown = emptyTokens();\n tokens.input = input;\n tokens.output = outputTokens;\n tokens.cacheRead = cacheReadTokens;\n tokens.cacheWrite = cacheWrite;\n // reasoning stays 0 (Cursor does not report it).\n\n const record: UsageRecord = {\n platformId: PLATFORM_ID,\n modelId: model,\n providerId,\n sessionId,\n tokens,\n cost,\n ts,\n messageCount: 1,\n dedupKey: sessionId,\n confidence: \"host-reported\",\n };\n out.push(record);\n }\n\n return out;\n}\n\n/** The Cursor synced usage reader singleton. */\nconst cursorReader: UsageReader = {\n platformId: PLATFORM_ID,\n kind: \"synced\",\n async read({ sinceMs }: { sinceMs?: number }): Promise<UsageRecord[]> {\n // The cache dir is ~/.config/tokscale/cursor-cache (env override first).\n // Absent → [] so the scan layer reports \"requires sync, skipped\".\n const root = firstExistingRoot(PLATFORM_ID);\n if (root === undefined) return [];\n\n // Enumerate cached exports: usage*.csv at the cache root AND any archive/\n // subdir (walkFiles recurses), covering the active + secondary accounts.\n const files = walkFiles(root, (name) => {\n const lower = name.toLowerCase();\n return lower.startsWith(\"usage\") && lower.endsWith(\".csv\");\n });\n\n const records: UsageRecord[] = [];\n for (const file of files) {\n const rows = parseCursorFile(file);\n for (const row of rows) {\n if (sinceMs !== undefined && row.ts < sinceMs) continue;\n records.push(row);\n }\n }\n return records;\n },\n};\n\nexport default cursorReader;\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
print
|
|
4
|
+
} from "./chunk-54EMKTTX.js";
|
|
5
|
+
import {
|
|
6
|
+
detectInstalledPlatforms
|
|
7
|
+
} from "./chunk-XUCWLJY5.js";
|
|
8
|
+
|
|
9
|
+
// src/cli/commands/detect.ts
|
|
10
|
+
import { parseArgs } from "util";
|
|
11
|
+
function capabilitySummary(caps) {
|
|
12
|
+
const events = [];
|
|
13
|
+
if (caps.preToolUse) events.push("PreToolUse");
|
|
14
|
+
if (caps.postToolUse) events.push("PostToolUse");
|
|
15
|
+
if (caps.sessionStart) events.push("SessionStart");
|
|
16
|
+
if (caps.sessionEnd) events.push("SessionEnd");
|
|
17
|
+
if (caps.userPromptSubmit) events.push("UserPromptSubmit");
|
|
18
|
+
if (caps.preCompact) events.push("PreCompact");
|
|
19
|
+
if (caps.stop) events.push("Stop");
|
|
20
|
+
if (caps.notification) events.push("Notification");
|
|
21
|
+
const extras = [];
|
|
22
|
+
if (caps.canModifyArgs) extras.push("modifyArgs");
|
|
23
|
+
if (caps.canModifyOutput) extras.push("modifyOutput");
|
|
24
|
+
if (caps.canInjectSessionContext) extras.push("injectContext");
|
|
25
|
+
const transports = caps.transports.length > 0 ? caps.transports.join("/") : "none";
|
|
26
|
+
const parts = [
|
|
27
|
+
`events: ${events.length > 0 ? events.join(",") : "none"}`,
|
|
28
|
+
`transports: ${transports}`
|
|
29
|
+
];
|
|
30
|
+
if (extras.length > 0) parts.push(extras.join(","));
|
|
31
|
+
return parts.join(" | ");
|
|
32
|
+
}
|
|
33
|
+
async function run(argv) {
|
|
34
|
+
const { values } = parseArgs({
|
|
35
|
+
args: argv,
|
|
36
|
+
options: {
|
|
37
|
+
json: { type: "boolean", default: false },
|
|
38
|
+
project: { type: "string" }
|
|
39
|
+
},
|
|
40
|
+
allowPositionals: false
|
|
41
|
+
});
|
|
42
|
+
const projectDir = values.project ?? process.cwd();
|
|
43
|
+
const detected = await detectInstalledPlatforms(projectDir);
|
|
44
|
+
if (values.json) {
|
|
45
|
+
print(JSON.stringify(detected, null, 2));
|
|
46
|
+
return 0;
|
|
47
|
+
}
|
|
48
|
+
if (detected.length === 0) {
|
|
49
|
+
print("No supported AI-agent platforms detected on this machine.");
|
|
50
|
+
return 0;
|
|
51
|
+
}
|
|
52
|
+
print(`Detected ${detected.length} platform(s):
|
|
53
|
+
`);
|
|
54
|
+
for (const p of detected) {
|
|
55
|
+
print(`${p.name} (${p.id})`);
|
|
56
|
+
print(` paradigm: ${p.paradigm}`);
|
|
57
|
+
print(` scope: ${p.scope}`);
|
|
58
|
+
print(` configPath: ${p.configPath}`);
|
|
59
|
+
print(` confidence: ${p.confidence} (${p.reason})`);
|
|
60
|
+
print(` capabilities: ${capabilitySummary(p.capabilities)}`);
|
|
61
|
+
print("");
|
|
62
|
+
}
|
|
63
|
+
return 0;
|
|
64
|
+
}
|
|
65
|
+
export {
|
|
66
|
+
run
|
|
67
|
+
};
|
|
68
|
+
//# sourceMappingURL=detect-WIAGVYS4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/commands/detect.ts"],"sourcesContent":["/**\n * cli/commands/detect — list the AI-agent platforms installed on this machine.\n *\n * `detect` probes every registered adapter (via detectInstalledPlatforms) and\n * prints, for each installed host: id, name, hook paradigm, install scope, the\n * native config path that would be written, and a one-line capabilities summary.\n * `--json` emits the raw DetectedPlatform[] for scripting.\n */\n\nimport { parseArgs } from \"node:util\";\n\nimport type { DetectedPlatform, PlatformCapabilities } from \"../../core/types.js\";\nimport { detectInstalledPlatforms } from \"../../adapters/detect.js\";\nimport { print } from \"../app.js\";\n\n/** Compact, human one-line summary of what a host can honor. */\nfunction capabilitySummary(caps: PlatformCapabilities): string {\n const events: string[] = [];\n if (caps.preToolUse) events.push(\"PreToolUse\");\n if (caps.postToolUse) events.push(\"PostToolUse\");\n if (caps.sessionStart) events.push(\"SessionStart\");\n if (caps.sessionEnd) events.push(\"SessionEnd\");\n if (caps.userPromptSubmit) events.push(\"UserPromptSubmit\");\n if (caps.preCompact) events.push(\"PreCompact\");\n if (caps.stop) events.push(\"Stop\");\n if (caps.notification) events.push(\"Notification\");\n\n const extras: string[] = [];\n if (caps.canModifyArgs) extras.push(\"modifyArgs\");\n if (caps.canModifyOutput) extras.push(\"modifyOutput\");\n if (caps.canInjectSessionContext) extras.push(\"injectContext\");\n\n const transports = caps.transports.length > 0 ? caps.transports.join(\"/\") : \"none\";\n const parts = [\n `events: ${events.length > 0 ? events.join(\",\") : \"none\"}`,\n `transports: ${transports}`,\n ];\n if (extras.length > 0) parts.push(extras.join(\",\"));\n return parts.join(\" | \");\n}\n\nexport async function run(argv: string[]): Promise<number> {\n const { values } = parseArgs({\n args: argv,\n options: {\n json: { type: \"boolean\", default: false },\n project: { type: \"string\" },\n },\n allowPositionals: false,\n });\n\n const projectDir = values.project ?? process.cwd();\n const detected: DetectedPlatform[] = await detectInstalledPlatforms(projectDir);\n\n if (values.json) {\n print(JSON.stringify(detected, null, 2));\n return 0;\n }\n\n if (detected.length === 0) {\n print(\"No supported AI-agent platforms detected on this machine.\");\n return 0;\n }\n\n print(`Detected ${detected.length} platform(s):\\n`);\n for (const p of detected) {\n print(`${p.name} (${p.id})`);\n print(` paradigm: ${p.paradigm}`);\n print(` scope: ${p.scope}`);\n print(` configPath: ${p.configPath}`);\n print(` confidence: ${p.confidence} (${p.reason})`);\n print(` capabilities: ${capabilitySummary(p.capabilities)}`);\n print(\"\");\n }\n return 0;\n}\n"],"mappings":";;;;;;;;;AASA,SAAS,iBAAiB;AAO1B,SAAS,kBAAkB,MAAoC;AAC7D,QAAM,SAAmB,CAAC;AAC1B,MAAI,KAAK,WAAY,QAAO,KAAK,YAAY;AAC7C,MAAI,KAAK,YAAa,QAAO,KAAK,aAAa;AAC/C,MAAI,KAAK,aAAc,QAAO,KAAK,cAAc;AACjD,MAAI,KAAK,WAAY,QAAO,KAAK,YAAY;AAC7C,MAAI,KAAK,iBAAkB,QAAO,KAAK,kBAAkB;AACzD,MAAI,KAAK,WAAY,QAAO,KAAK,YAAY;AAC7C,MAAI,KAAK,KAAM,QAAO,KAAK,MAAM;AACjC,MAAI,KAAK,aAAc,QAAO,KAAK,cAAc;AAEjD,QAAM,SAAmB,CAAC;AAC1B,MAAI,KAAK,cAAe,QAAO,KAAK,YAAY;AAChD,MAAI,KAAK,gBAAiB,QAAO,KAAK,cAAc;AACpD,MAAI,KAAK,wBAAyB,QAAO,KAAK,eAAe;AAE7D,QAAM,aAAa,KAAK,WAAW,SAAS,IAAI,KAAK,WAAW,KAAK,GAAG,IAAI;AAC5E,QAAM,QAAQ;AAAA,IACZ,WAAW,OAAO,SAAS,IAAI,OAAO,KAAK,GAAG,IAAI,MAAM;AAAA,IACxD,eAAe,UAAU;AAAA,EAC3B;AACA,MAAI,OAAO,SAAS,EAAG,OAAM,KAAK,OAAO,KAAK,GAAG,CAAC;AAClD,SAAO,MAAM,KAAK,KAAK;AACzB;AAEA,eAAsB,IAAI,MAAiC;AACzD,QAAM,EAAE,OAAO,IAAI,UAAU;AAAA,IAC3B,MAAM;AAAA,IACN,SAAS;AAAA,MACP,MAAM,EAAE,MAAM,WAAW,SAAS,MAAM;AAAA,MACxC,SAAS,EAAE,MAAM,SAAS;AAAA,IAC5B;AAAA,IACA,kBAAkB;AAAA,EACpB,CAAC;AAED,QAAM,aAAa,OAAO,WAAW,QAAQ,IAAI;AACjD,QAAM,WAA+B,MAAM,yBAAyB,UAAU;AAE9E,MAAI,OAAO,MAAM;AACf,UAAM,KAAK,UAAU,UAAU,MAAM,CAAC,CAAC;AACvC,WAAO;AAAA,EACT;AAEA,MAAI,SAAS,WAAW,GAAG;AACzB,UAAM,2DAA2D;AACjE,WAAO;AAAA,EACT;AAEA,QAAM,YAAY,SAAS,MAAM;AAAA,CAAiB;AAClD,aAAW,KAAK,UAAU;AACxB,UAAM,GAAG,EAAE,IAAI,KAAK,EAAE,EAAE,GAAG;AAC3B,UAAM,kBAAkB,EAAE,QAAQ,EAAE;AACpC,UAAM,kBAAkB,EAAE,KAAK,EAAE;AACjC,UAAM,kBAAkB,EAAE,UAAU,EAAE;AACtC,UAAM,kBAAkB,EAAE,UAAU,MAAM,EAAE,MAAM,GAAG;AACrD,UAAM,mBAAmB,kBAAkB,EAAE,YAAY,CAAC,EAAE;AAC5D,UAAM,EAAE;AAAA,EACV;AACA,SAAO;AACT;","names":[]}
|