@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.
Files changed (203) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +6 -0
  3. package/README.md +348 -0
  4. package/dist/amp-QSFH2V7Y.js +217 -0
  5. package/dist/amp-QSFH2V7Y.js.map +1 -0
  6. package/dist/amp-TULUPXXL.js +237 -0
  7. package/dist/amp-TULUPXXL.js.map +1 -0
  8. package/dist/antigravity-CX2YLSY7.js +17 -0
  9. package/dist/antigravity-CX2YLSY7.js.map +1 -0
  10. package/dist/antigravity-STHZWMP3.js +171 -0
  11. package/dist/antigravity-STHZWMP3.js.map +1 -0
  12. package/dist/antigravity-cli-P6HADOAO.js +121 -0
  13. package/dist/antigravity-cli-P6HADOAO.js.map +1 -0
  14. package/dist/antigravity-cli-YQDFVV4U.js +86 -0
  15. package/dist/antigravity-cli-YQDFVV4U.js.map +1 -0
  16. package/dist/chunk-54EMKTTX.js +191 -0
  17. package/dist/chunk-54EMKTTX.js.map +1 -0
  18. package/dist/chunk-7L6ITC4T.js +54 -0
  19. package/dist/chunk-7L6ITC4T.js.map +1 -0
  20. package/dist/chunk-7MSDGHJW.js +316 -0
  21. package/dist/chunk-7MSDGHJW.js.map +1 -0
  22. package/dist/chunk-BCHWFTV4.js +196 -0
  23. package/dist/chunk-BCHWFTV4.js.map +1 -0
  24. package/dist/chunk-DBQMX75U.js +36 -0
  25. package/dist/chunk-DBQMX75U.js.map +1 -0
  26. package/dist/chunk-EXLS7BSI.js +29 -0
  27. package/dist/chunk-EXLS7BSI.js.map +1 -0
  28. package/dist/chunk-JNM3TPLX.js +593 -0
  29. package/dist/chunk-JNM3TPLX.js.map +1 -0
  30. package/dist/chunk-JWNT5KW7.js +197 -0
  31. package/dist/chunk-JWNT5KW7.js.map +1 -0
  32. package/dist/chunk-KHO5WNTP.js +30 -0
  33. package/dist/chunk-KHO5WNTP.js.map +1 -0
  34. package/dist/chunk-LTT56GI3.js +155 -0
  35. package/dist/chunk-LTT56GI3.js.map +1 -0
  36. package/dist/chunk-MEH7GC7R.js +111 -0
  37. package/dist/chunk-MEH7GC7R.js.map +1 -0
  38. package/dist/chunk-MQPNU2CY.js +64 -0
  39. package/dist/chunk-MQPNU2CY.js.map +1 -0
  40. package/dist/chunk-OPXAP3AC.js +12 -0
  41. package/dist/chunk-OPXAP3AC.js.map +1 -0
  42. package/dist/chunk-RK6VBLXP.js +50 -0
  43. package/dist/chunk-RK6VBLXP.js.map +1 -0
  44. package/dist/chunk-TIIP3RG2.js +420 -0
  45. package/dist/chunk-TIIP3RG2.js.map +1 -0
  46. package/dist/chunk-TRKWUNO4.js +702 -0
  47. package/dist/chunk-TRKWUNO4.js.map +1 -0
  48. package/dist/chunk-TRQKHP7D.js +93 -0
  49. package/dist/chunk-TRQKHP7D.js.map +1 -0
  50. package/dist/chunk-WCETQWWK.js +59 -0
  51. package/dist/chunk-WCETQWWK.js.map +1 -0
  52. package/dist/chunk-WV63X7IK.js +357 -0
  53. package/dist/chunk-WV63X7IK.js.map +1 -0
  54. package/dist/chunk-XD7MY6HB.js +343 -0
  55. package/dist/chunk-XD7MY6HB.js.map +1 -0
  56. package/dist/chunk-XNAM7F35.js +276 -0
  57. package/dist/chunk-XNAM7F35.js.map +1 -0
  58. package/dist/chunk-XUCWLJY5.js +238 -0
  59. package/dist/chunk-XUCWLJY5.js.map +1 -0
  60. package/dist/chunk-YNZU6PAV.js +800 -0
  61. package/dist/chunk-YNZU6PAV.js.map +1 -0
  62. package/dist/chunk-YT43MUSJ.js +146 -0
  63. package/dist/chunk-YT43MUSJ.js.map +1 -0
  64. package/dist/claude-code-HKDV7T32.js +637 -0
  65. package/dist/claude-code-HKDV7T32.js.map +1 -0
  66. package/dist/claude-code-W74MNTAC.js +652 -0
  67. package/dist/claude-code-W74MNTAC.js.map +1 -0
  68. package/dist/cli/sdk.d.ts +54 -0
  69. package/dist/cli/sdk.js +82 -0
  70. package/dist/cli/sdk.js.map +1 -0
  71. package/dist/cli.d.ts +2 -0
  72. package/dist/cli.js +15 -0
  73. package/dist/cli.js.map +1 -0
  74. package/dist/codebuff-3PMZJJHP.js +307 -0
  75. package/dist/codebuff-3PMZJJHP.js.map +1 -0
  76. package/dist/codebuff-QX57FJDN.js +220 -0
  77. package/dist/codebuff-QX57FJDN.js.map +1 -0
  78. package/dist/codex-JFQTS6LU.js +593 -0
  79. package/dist/codex-JFQTS6LU.js.map +1 -0
  80. package/dist/codex-Q3ATRRX3.js +364 -0
  81. package/dist/codex-Q3ATRRX3.js.map +1 -0
  82. package/dist/copilot-cli-MTCGHZ2T.js +622 -0
  83. package/dist/copilot-cli-MTCGHZ2T.js.map +1 -0
  84. package/dist/copilot-cli-SJGIXVSD.js +369 -0
  85. package/dist/copilot-cli-SJGIXVSD.js.map +1 -0
  86. package/dist/crush-I7PK3FGI.js +360 -0
  87. package/dist/crush-I7PK3FGI.js.map +1 -0
  88. package/dist/crush-LN5QFFR2.js +183 -0
  89. package/dist/crush-LN5QFFR2.js.map +1 -0
  90. package/dist/cursor-4TMXKJOZ.js +603 -0
  91. package/dist/cursor-4TMXKJOZ.js.map +1 -0
  92. package/dist/cursor-QZ6MTO74.js +194 -0
  93. package/dist/cursor-QZ6MTO74.js.map +1 -0
  94. package/dist/detect-WIAGVYS4.js +68 -0
  95. package/dist/detect-WIAGVYS4.js.map +1 -0
  96. package/dist/doctor-EZW2K4NI.js +372 -0
  97. package/dist/doctor-EZW2K4NI.js.map +1 -0
  98. package/dist/droid-KN6VRMMT.js +424 -0
  99. package/dist/droid-KN6VRMMT.js.map +1 -0
  100. package/dist/droid-W5WF5XEX.js +224 -0
  101. package/dist/droid-W5WF5XEX.js.map +1 -0
  102. package/dist/gemini-cli-CIRW37TU.js +369 -0
  103. package/dist/gemini-cli-CIRW37TU.js.map +1 -0
  104. package/dist/gemini-cli-Y35FFK4M.js +705 -0
  105. package/dist/gemini-cli-Y35FFK4M.js.map +1 -0
  106. package/dist/goose-A3M5GODH.js +212 -0
  107. package/dist/goose-A3M5GODH.js.map +1 -0
  108. package/dist/goose-ZTGTSUFJ.js +480 -0
  109. package/dist/goose-ZTGTSUFJ.js.map +1 -0
  110. package/dist/hermes-H2KV44GK.js +470 -0
  111. package/dist/hermes-H2KV44GK.js.map +1 -0
  112. package/dist/hermes-ZYLMOFLZ.js +196 -0
  113. package/dist/hermes-ZYLMOFLZ.js.map +1 -0
  114. package/dist/hook-YVDILAMZ.js +75 -0
  115. package/dist/hook-YVDILAMZ.js.map +1 -0
  116. package/dist/index.d.ts +22 -0
  117. package/dist/index.js +10 -0
  118. package/dist/index.js.map +1 -0
  119. package/dist/install-HQRYZOQ2.js +60 -0
  120. package/dist/install-HQRYZOQ2.js.map +1 -0
  121. package/dist/jetbrains-copilot-HWA3DMH7.js +633 -0
  122. package/dist/jetbrains-copilot-HWA3DMH7.js.map +1 -0
  123. package/dist/kilo-NSWAVP6P.js +235 -0
  124. package/dist/kilo-NSWAVP6P.js.map +1 -0
  125. package/dist/kilo-QXJRCSLT.js +384 -0
  126. package/dist/kilo-QXJRCSLT.js.map +1 -0
  127. package/dist/kilo-cli-EAQTHXUW.js +587 -0
  128. package/dist/kilo-cli-EAQTHXUW.js.map +1 -0
  129. package/dist/kilo-cli-EVBKUODA.js +160 -0
  130. package/dist/kilo-cli-EVBKUODA.js.map +1 -0
  131. package/dist/kimi-EI3UM3ZV.js +155 -0
  132. package/dist/kimi-EI3UM3ZV.js.map +1 -0
  133. package/dist/kimi-GQ7VXNYT.js +423 -0
  134. package/dist/kimi-GQ7VXNYT.js.map +1 -0
  135. package/dist/kiro-UCLSLBW2.js +217 -0
  136. package/dist/kiro-UCLSLBW2.js.map +1 -0
  137. package/dist/kiro-VQTT6LO2.js +451 -0
  138. package/dist/kiro-VQTT6LO2.js.map +1 -0
  139. package/dist/leaderboard-K6ON3SWW.js +137 -0
  140. package/dist/leaderboard-K6ON3SWW.js.map +1 -0
  141. package/dist/mux-T2TV4CIQ.js +211 -0
  142. package/dist/mux-T2TV4CIQ.js.map +1 -0
  143. package/dist/mux-ZMLVAXOO.js +96 -0
  144. package/dist/mux-ZMLVAXOO.js.map +1 -0
  145. package/dist/omp-PB4VDKS6.js +586 -0
  146. package/dist/omp-PB4VDKS6.js.map +1 -0
  147. package/dist/openclaw-ETN2M63O.js +751 -0
  148. package/dist/openclaw-ETN2M63O.js.map +1 -0
  149. package/dist/openclaw-IYA7ASL6.js +150 -0
  150. package/dist/openclaw-IYA7ASL6.js.map +1 -0
  151. package/dist/opencode-FZ33JKUZ.js +734 -0
  152. package/dist/opencode-FZ33JKUZ.js.map +1 -0
  153. package/dist/opencode-HWT3RSMN.js +216 -0
  154. package/dist/opencode-HWT3RSMN.js.map +1 -0
  155. package/dist/package-DLOVE2E4.js +1132 -0
  156. package/dist/package-DLOVE2E4.js.map +1 -0
  157. package/dist/pi-CIU2QHT4.js +208 -0
  158. package/dist/pi-CIU2QHT4.js.map +1 -0
  159. package/dist/pi-UFX2OYFV.js +139 -0
  160. package/dist/pi-UFX2OYFV.js.map +1 -0
  161. package/dist/qwen-code-5POCNU6P.js +573 -0
  162. package/dist/qwen-code-5POCNU6P.js.map +1 -0
  163. package/dist/qwen-code-W7NUCDEN.js +134 -0
  164. package/dist/qwen-code-W7NUCDEN.js.map +1 -0
  165. package/dist/roo-code-IOIUXRDE.js +242 -0
  166. package/dist/roo-code-IOIUXRDE.js.map +1 -0
  167. package/dist/roo-code-ZLKH4A7N.js +229 -0
  168. package/dist/roo-code-ZLKH4A7N.js.map +1 -0
  169. package/dist/runtime/index.d.ts +157 -0
  170. package/dist/runtime/index.js +20 -0
  171. package/dist/runtime/index.js.map +1 -0
  172. package/dist/serve-HVWWY4B6.js +65 -0
  173. package/dist/serve-HVWWY4B6.js.map +1 -0
  174. package/dist/status-FE7TECZD.js +128 -0
  175. package/dist/status-FE7TECZD.js.map +1 -0
  176. package/dist/synthetic-UKR6SMGS.js +178 -0
  177. package/dist/synthetic-UKR6SMGS.js.map +1 -0
  178. package/dist/telemetry-36GESKQQ.js +349 -0
  179. package/dist/telemetry-36GESKQQ.js.map +1 -0
  180. package/dist/trae-JSNDZFKL.js +204 -0
  181. package/dist/trae-JSNDZFKL.js.map +1 -0
  182. package/dist/trae-PA26DPBW.js +157 -0
  183. package/dist/trae-PA26DPBW.js.map +1 -0
  184. package/dist/types-CYUB1OTr.d.ts +427 -0
  185. package/dist/uninstall-IGCKNOSF.js +72 -0
  186. package/dist/uninstall-IGCKNOSF.js.map +1 -0
  187. package/dist/upgrade-JV2VK242.js +104 -0
  188. package/dist/upgrade-JV2VK242.js.map +1 -0
  189. package/dist/usage-6ER6EMEY.js +324 -0
  190. package/dist/usage-6ER6EMEY.js.map +1 -0
  191. package/dist/usage-event-JKBI6XCF.js +48 -0
  192. package/dist/usage-event-JKBI6XCF.js.map +1 -0
  193. package/dist/vscode-copilot-CK3NO54M.js +715 -0
  194. package/dist/vscode-copilot-CK3NO54M.js.map +1 -0
  195. package/dist/warp-JNQA7PBU.js +126 -0
  196. package/dist/warp-JNQA7PBU.js.map +1 -0
  197. package/dist/warp-QNVDXOG4.js +199 -0
  198. package/dist/warp-QNVDXOG4.js.map +1 -0
  199. package/dist/zed-NNNX5MNT.js +272 -0
  200. package/dist/zed-NNNX5MNT.js.map +1 -0
  201. package/dist/zed-VRJKWYUR.js +209 -0
  202. package/dist/zed-VRJKWYUR.js.map +1 -0
  203. package/package.json +79 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/adapters/jetbrains-copilot/index.ts"],"sourcesContent":["/**\n * adapters/jetbrains-copilot — JetBrains Copilot platform adapter for agent-connector.\n *\n * JetBrains Copilot shares the Copilot hook paradigm with VS Code Copilot\n * (Claude-compatible json-stdio), but diverges on MCP registration:\n *\n * - MCP servers: JetBrains stores MCP server registration via the IDE Settings\n * UI (Settings > Tools > GitHub Copilot > MCP > Configure), NOT in any file\n * we can reliably write — the runtime owns the `servers` key behind the UI.\n * So `installServer` writes NOTHING and returns a \"warn\" ChangeRecord telling\n * the user to add the server via the JetBrains MCP settings UI. Writing a\n * bogus file would be ignored at best and corrupt real UI state at worst.\n * `getHealthChecks` surfaces this as a WARN (not FAIL).\n *\n * - Hooks (Copilot Preview hooks): file-based and identical in shape to VS Code\n * Copilot. We write one per-connector file at\n * <projectDir>/.github/hooks/<connector-id>.json shaped as:\n * { \"version\": 1, \"hooks\": { <Event>: [ { \"type\": \"command\", \"command\" } ] } }\n * The top-level `version: 1` is REQUIRED — the Copilot hooks runtime rejects a\n * version-less file and no hooks fire. Each entry is a FLAT { type, command }\n * object (no Claude-style { matcher, hooks:[...] } wrapper). JetBrains parses\n * matchers but IGNORES them — ALL hooks fire on ALL tools — so we omit the\n * matcher entirely rather than persist an advisory one that never applies.\n *\n * - Reply: Claude-compatible JSON on stdout (exit 0), a `hookSpecificOutput`\n * object keyed by the PascalCase `hookEventName` carrying permissionDecision\n * (deny|ask) + permissionDecisionReason and additionalContext. This mirrors\n * vscode-copilot/claude-code exactly EXCEPT JetBrains cannot rewrite tool\n * input (canModifyArgs:false), so a \"modify\" decision degrades to allow.\n *\n * Env interpolation: GitHub Copilot does not document a portable native env\n * token for the hooks file, and the hooks file only ever carries our home-bin\n * hook command (no secrets), so there is nothing to interpolate here. MCP env\n * interpolation is moot because we never write the MCP file.\n */\n\nimport { existsSync, rmSync } from \"node:fs\";\nimport { dirname, 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 NotificationEvent,\n PlatformCapabilities,\n PlatformId,\n PostToolUseEvent,\n PreCompactEvent,\n PreToolUseEvent,\n SessionEndEvent,\n SessionStartEvent,\n SkillDef,\n StopEvent,\n UserPromptSubmitEvent,\n} from \"../../core/types.js\";\nimport {\n buildHomeBinHookCommand,\n isHomeBinHookCommand,\n} from \"../../core/spawn.js\";\n\nconst HOST: PlatformId = \"jetbrains-copilot\";\n\n/** Top-level version the Copilot hooks runtime requires; a version-less file is rejected. */\nconst JETBRAINS_HOOKS_VERSION = 1;\n\n/**\n * JetBrains Copilot reads PascalCase hook event names from its hooks file —\n * identical to VS Code Copilot / Claude Code. Only the events JetBrains actually\n * delivers are registered; everything else has no Copilot equivalent and is\n * reported as a warn/skip at install time.\n */\nconst EVENT_MAP: Partial<Record<HookEventName, string>> = {\n PreToolUse: \"PreToolUse\",\n PostToolUse: \"PostToolUse\",\n PreCompact: \"PreCompact\",\n SessionStart: \"SessionStart\",\n};\n\n/** A single JetBrains Copilot native hook entry — a flat command object. */\ninterface JetBrainsHookEntry {\n type: \"command\";\n command: string;\n}\n\n/** The shape of a JetBrains Copilot .github/hooks/<connector>.json file. */\ninterface JetBrainsHooksFile {\n version?: number;\n hooks?: Record<string, JetBrainsHookEntry[]>;\n}\n\n/** Raw JetBrains Copilot hook stdin payload (Claude-compatible snake_case fields). */\ninterface JetBrainsWireInput {\n session_id?: string;\n transcript_path?: string;\n cwd?: string;\n workspace_roots?: string[];\n hook_event_name?: string;\n\n // tool events\n tool_name?: string;\n tool_input?: Record<string, unknown>;\n tool_response?: unknown;\n tool_output?: string;\n error_message?: string;\n\n // SessionStart\n source?: string;\n // SessionEnd\n reason?: string;\n // UserPromptSubmit\n prompt?: string;\n // PreCompact\n trigger?: string;\n // Stop\n stop_hook_active?: boolean;\n // Notification\n message?: string;\n\n /** Injected by the entrypoint so the runtime knows which connector to dispatch. */\n connector?: string;\n}\n\nexport class JetBrainsCopilotAdapter extends BaseAdapter implements Adapter {\n readonly id: PlatformId = HOST;\n readonly name = \"JetBrains Copilot\";\n readonly paradigm: HookParadigm = \"json-stdio\";\n\n readonly capabilities: PlatformCapabilities = {\n // JetBrains Copilot's Preview hooks runtime delivers Pre/PostToolUse,\n // PreCompact, and SessionStart (the four events its schema documents) —\n // same surface as VS Code Copilot.\n preToolUse: true,\n postToolUse: true,\n preCompact: true,\n sessionStart: true,\n sessionEnd: false,\n userPromptSubmit: false,\n stop: false,\n notification: false,\n // Per the JetBrains spec this host is deny/ask-only: a PreToolUse hook\n // CANNOT rewrite tool input, and PostToolUse cannot rewrite tool output.\n canModifyArgs: false,\n canModifyOutput: false,\n canInjectSessionContext: true,\n // MCP is managed via the IDE Settings UI; the only transport that surfaces\n // there is a local stdio server.\n transports: [\"stdio\"],\n // Content surfaces: JetBrains Copilot consumes the GitHub Copilot .github/\n // files (it has no distinct authoring location), so it is an ALIAS of the\n // vscode-copilot writer for prompt files and Agent Skills. It has no native\n // subagent/chat-mode surface, so subagents stay unsupported (BaseAdapter\n // returns the skip/warn default).\n supportsCommands: true,\n supportsSkills: true,\n supportsSubagents: false,\n };\n\n // ── Detection ────────────────────────────────────────────────────────────\n\n detectInstalled(projectDir: string): DetectedPlatform {\n // JetBrains Copilot integration is observable through two markers:\n // • the project hooks tree (<projectDir>/.github/hooks) we write to, and\n // • our per-connector hooks file specifically.\n // There is no reliable user-profile MCP file to probe (the UI owns it), so\n // detection is project-scoped and keyed on the hooks footprint.\n const githubDir = join(projectDir, \".github\");\n const hooksDir = join(githubDir, \"hooks\");\n const installed = existsSync(hooksDir) || existsSync(githubDir);\n const configPath = hooksDir;\n return {\n id: this.id,\n name: this.name,\n installed,\n paradigm: this.paradigm,\n capabilities: this.capabilities,\n configPath,\n scope: \"project\",\n reason: installed\n ? `found JetBrains Copilot hooks tree at ${hooksDir}`\n : `no JetBrains Copilot hooks tree at ${hooksDir}`,\n confidence: installed ? \"medium\" : \"low\",\n };\n }\n\n // ── Native paths ─────────────────────────────────────────────────────────\n\n /** Hooks live under the workspace .github tree for both scopes. */\n getConfigDir(ctx: InstallContext): string {\n return join(ctx.projectDir, \".github\");\n }\n\n /**\n * MCP server registration has NO writable file on JetBrains — the IDE owns it\n * behind the Settings UI. We still return a stable path (the hooks file) so the\n * base-adapter `doctor`/`backupSettings` helpers have a sensible target rather\n * than a nonexistent/bogus MCP path. `installServer` never writes here.\n */\n getServerConfigPath(ctx: InstallContext): string {\n return this.getHookConfigPath(ctx);\n }\n\n /**\n * Hook registration lives in the workspace-discovered .github/hooks tree, which\n * JetBrains Copilot scans for *.json hook files. We write one file per connector\n * so installs/uninstalls never clobber another connector's hooks. Anchored on\n * projectDir for both scopes — .github/hooks is a workspace concept (there is no\n * user-profile equivalent in the Copilot hooks schema).\n */\n getHookConfigPath(ctx: InstallContext): string {\n return join(ctx.projectDir, \".github\", \"hooks\", `${ctx.connector.id}.json`);\n }\n\n // ── MCP server install / uninstall ───────────────────────────────────────\n\n /**\n * JetBrains MCP registration is UI-only. We never write a file: a bogus file is\n * ignored at best and corrupts real UI-managed state at worst. Emit a \"warn\"\n * ChangeRecord that tells the user exactly where to add the server by hand.\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 jetbrains-copilot\"\n : \"connector declares no MCP server\",\n },\n ];\n }\n\n return [\n {\n platform: this.id,\n action: \"warn\",\n detail:\n `JetBrains Copilot manages MCP servers via the IDE Settings UI — ` +\n `add \"${connector.id}\" manually under Settings > Tools > GitHub Copilot ` +\n `> MCP > Configure (no file is written here).`,\n },\n ];\n }\n\n /**\n * Nothing was written for the MCP server, so there is nothing to remove. Mirror\n * the install-time guidance as a \"warn\" so an uninstall report is honest about\n * the UI-managed entry the user may still want to remove by hand.\n */\n uninstallServer(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n if (!connector.server || connector.platforms[HOST]?.server === false) {\n return [\n {\n platform: this.id,\n action: \"skip\",\n detail: \"no MCP server was registered for jetbrains-copilot\",\n },\n ];\n }\n return [\n {\n platform: this.id,\n action: \"warn\",\n detail:\n `JetBrains Copilot MCP servers are UI-managed — if \"${connector.id}\" was ` +\n `added manually, remove it under Settings > Tools > GitHub Copilot > MCP.`,\n },\n ];\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 [\n { platform: this.id, action: \"skip\", detail: \"hooks disabled for jetbrains-copilot\" },\n ];\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<JetBrainsHooksFile>(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 jetbrainsEvent = EVENT_MAP[event];\n if (!jetbrainsEvent) {\n // No JetBrains Copilot equivalent for this normalized event — report+skip.\n changes.push({\n platform: this.id,\n action: \"warn\",\n path: hooksPath,\n detail: `${event} has no JetBrains Copilot hook equivalent — skipped`,\n });\n continue;\n }\n\n const command = buildHomeBinHookCommand(ctx.homeBinPath, HOST, event, connector.id);\n // Matchers are IGNORED by JetBrains (all hooks fire on all tools), so we omit\n // the matcher entirely — a flat { type, command } entry.\n const entry: JetBrainsHookEntry = { type: \"command\", command };\n\n const bucket = (hooks[jetbrainsEvent] ??= []);\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.${jetbrainsEvent} 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.${jetbrainsEvent}`,\n });\n } else {\n bucket.push(entry);\n changes.push({\n platform: this.id,\n action: \"create\",\n path: hooksPath,\n detail: `hooks.${jetbrainsEvent}`,\n });\n }\n mutated = true;\n }\n\n if (mutated) {\n // The top-level version is REQUIRED — a version-less file is rejected and\n // no hooks fire. Always (re)assert it when we write.\n file.version = JETBRAINS_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<JetBrainsHooksFile>(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 jetbrainsEvent of Object.keys(hooks)) {\n const bucket = hooks[jetbrainsEvent];\n if (!Array.isArray(bucket)) continue;\n\n const before = bucket.length;\n // Only strip OUR connector's home-bin commands — never another connector's\n // (isHomeBinHookCommand is id-anchored against a shared-prefix collision).\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[jetbrainsEvent] = next;\n else delete hooks[jetbrainsEvent];\n changes.push({\n platform: this.id,\n action: \"remove\",\n path: hooksPath,\n detail: `hooks.${jetbrainsEvent} (${removed})`,\n });\n mutated = true;\n }\n }\n\n if (mutated) {\n // The hooks file is connector-OWNED (<connector-id>.json), so when our\n // strip leaves it with NO hooks we must DELETE the whole file rather than\n // rewrite a `{ \"hooks\": {}, \"version\": 1 }` shell — an empty shell is an\n // orphan per-connector file that lingers after uninstall. A non-empty\n // result still belongs to us, so we rewrite it as before. dryRun reports\n // the would-be remove without mutating the filesystem.\n if (Object.keys(hooks).length === 0) {\n if (!ctx.dryRun) rmSync(hooksPath, { force: true });\n changes.push({\n platform: this.id,\n action: \"remove\",\n path: hooksPath,\n detail: \"removed empty connector hooks file\",\n });\n // Clean up the parent .github/hooks dir only when it is now empty (it is\n // a per-connector tree; leave it in place if other connectors' files\n // remain).\n changes.push(this.removeDirIfEmpty(dirname(hooksPath), ctx.dryRun));\n } else {\n this.writeJson(hooksPath, file, ctx.dryRun);\n }\n }\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 ──────────────────────────────────\n // CONTENT-ONLY: pure native-file writers under the workspace .github/ tree\n // ({prompts,skills}). No runtime dispatch, no home-bin pointer, no telemetry\n // wrap. Each method is idempotent (byte-identical → skip) via\n // BaseAdapter.writeContentFile and reversible via removeContentFile. Honors\n // platforms[\"jetbrains-copilot\"] per-surface false to skip.\n //\n // ALIAS of vscode-copilot: JetBrains consumes the GitHub Copilot .github/\n // files and has no distinct authoring location, so the rendered content +\n // paths here are IDENTICAL to the vscode-copilot writer.\n //\n // SHARED .github TREE: vscode-copilot, copilot-cli, and jetbrains-copilot all\n // write under the SAME project <projectDir>/.github tree. The rendered content\n // is identical and idempotent across those connectors, and uninstall here only\n // removes the files THIS connector declared — never another writer's files.\n //\n // SCOPE NOTE: .github is a workspace concept and this adapter is project-\n // scoped (no user-profile .github authoring location exists in the Copilot\n // prompt/skill discovery), so the content root is always the project .github\n // tree — the same dir getConfigDir already anchors on.\n\n /** Root of the content tree — the project .github tree (see getConfigDir). */\n private contentRootDir(ctx: InstallContext): string {\n return this.getConfigDir(ctx);\n }\n\n private promptsDir(ctx: InstallContext): string {\n return join(this.contentRootDir(ctx), \"prompts\");\n }\n private skillsDir(ctx: InstallContext): string {\n return join(this.contentRootDir(ctx), \"skills\");\n }\n\n /** Native command file path: <ghDir>/prompts/<name>.prompt.md. */\n private commandPath(ctx: InstallContext, name: string): string {\n return join(this.promptsDir(ctx), `${name}.prompt.md`);\n }\n /** Native skill dir: <ghDir>/skills/<name>. */\n private skillDir(ctx: InstallContext, name: string): string {\n return join(this.skillsDir(ctx), name);\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 jetbrains-copilot\" }];\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 /** Render a Copilot prompt file: md+frontmatter(description, tools, model, argument-hint). */\n private renderCommand(cmd: CommandDef): string {\n const frontmatter: Record<string, unknown> = {};\n if (cmd.description !== undefined) frontmatter.description = cmd.description;\n // Copilot prompt files express tool access as a `tools` array, sourced from\n // the portable tools.allow policy.\n const allow = cmd.tools?.allow;\n if (allow && allow.length > 0) frontmatter.tools = [...allow];\n if (cmd.model !== undefined) frontmatter.model = cmd.model;\n if (cmd.argumentHint !== undefined) frontmatter[\"argument-hint\"] = cmd.argumentHint;\n if (cmd.extra) Object.assign(frontmatter, cmd.extra);\n return this.renderFrontmatterMd(frontmatter, cmd.prompt);\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 jetbrains-copilot\" }];\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 — the uniform Agent Skills format: frontmatter\n * (name, description + optional model, allowed-tools, disable-model-invocation)\n * + body. Byte-identical to the other .github-sharing connectors so a shared\n * skill folder never thrashes.\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 // ── Diagnostics ──────────────────────────────────────────────────────────\n\n override getHealthChecks(ctx: InstallContext): readonly HealthCheck[] {\n const hooksPath = this.getHookConfigPath(ctx);\n const connectorId = ctx.connector.id;\n const homeBin = ctx.homeBinPath;\n const hookEvents = ctx.connector.hookEvents;\n const hasServer =\n ctx.connector.server != null &&\n ctx.connector.platforms[HOST]?.server !== false;\n const checks: HealthCheck[] = [\n {\n // MCP cannot be verified from disk — JetBrains owns it behind the UI.\n // BaseAdapter.doctor maps != OK to a hard FAIL, but an unverifiable\n // UI-managed surface must NOT hard-fail doctor (that contradicts the\n // install-time WARN). Return OK with a verify-in-UI detail instead.\n name: `${this.name}: MCP server (UI-managed)`,\n check: () =>\n hasServer\n ? {\n status: \"OK\",\n detail:\n \"MCP is UI-managed — verify in Settings > Tools > GitHub Copilot > MCP\",\n }\n : { status: \"OK\", detail: \"connector declares no MCP server\" },\n },\n {\n name: `${this.name}: hook command registered`,\n check: () => {\n if (hookEvents.length === 0) {\n return { status: \"OK\", detail: \"no hooks declared\" };\n }\n const file = this.readJson<JetBrainsHooksFile>(hooksPath);\n if (!file) return { status: \"FAIL\", detail: `not found: ${hooksPath}` };\n if (file.version !== JETBRAINS_HOOKS_VERSION) {\n return {\n status: \"FAIL\",\n detail: `${hooksPath} missing required \"version\": ${JETBRAINS_HOOKS_VERSION} — Copilot rejects it`,\n };\n }\n const registered = Object.values(file.hooks ?? {}).some((entries) =>\n (entries ?? []).some((e) =>\n isHomeBinHookCommand(e.command, homeBin, connectorId),\n ),\n );\n return registered\n ? { status: \"OK\", detail: \"hook command present\" }\n : { status: \"FAIL\", detail: `no hook for ${connectorId} in ${hooksPath}` };\n },\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). Subagents are\n // unsupported here, so they are never checked.\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 return checks;\n }\n\n // ── Runtime: parse JetBrains Copilot stdin JSON → normalized event ────────\n\n parseEvent(event: HookEventName, raw: unknown): NormalizedEvent {\n const input = (raw ?? {}) as JetBrainsWireInput;\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 =\n toolResponseToString(input.tool_response) ??\n input.tool_output ??\n 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 \"PreCompact\": {\n const ev: PreCompactEvent = {\n ...base,\n ...(input.trigger === \"auto\" || input.trigger === \"manual\"\n ? { trigger: input.trigger }\n : {}),\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 \"SessionEnd\": {\n const ev: SessionEndEvent = {\n ...base,\n ...(typeof input.reason === \"string\" ? { reason: input.reason } : {}),\n };\n return ev;\n }\n case \"UserPromptSubmit\": {\n const ev: UserPromptSubmitEvent = {\n ...base,\n prompt: typeof input.prompt === \"string\" ? input.prompt : \"\",\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 case \"Notification\": {\n const ev: NotificationEvent = {\n ...base,\n message: typeof input.message === \"string\" ? input.message : \"\",\n };\n return ev;\n }\n default: {\n // Exhaustive guard — every HookEventName is handled above. (JetBrains only\n // delivers the four it declares; the rest are handled defensively so a\n // mis-dispatch stays inert rather than crashing.)\n const _never: never = event;\n throw new Error(`unsupported jetbrains-copilot hook event: ${String(_never)}`);\n }\n }\n }\n\n /** Resolve the project dir from the wire payload, preferring the explicit cwd. */\n private getProjectDir(input: JetBrainsWireInput): string | undefined {\n return input.cwd ?? input.workspace_roots?.[0] ?? undefined;\n }\n\n // ── Runtime: normalized response → JetBrains Copilot native hook reply ────\n\n formatReply(event: HookEventName, response: HookResponse): HookReply {\n const hookEventName = event;\n const decision = response.decision ?? \"allow\";\n\n // deny → block the action with a reason (exit 0; JSON carries the decision).\n // JetBrains Copilot is Claude-compatible: the decision lives inside\n // `hookSpecificOutput`, keyed by the PascalCase event name.\n if (decision === \"deny\") {\n return this.stdout({\n hookSpecificOutput: {\n hookEventName,\n permissionDecision: \"deny\",\n permissionDecisionReason: response.reason ?? \"Blocked by hook\",\n },\n });\n }\n\n // ask → prompt the user to confirm.\n if (decision === \"ask\") {\n return this.stdout({\n hookSpecificOutput: {\n hookEventName,\n permissionDecision: \"ask\",\n permissionDecisionReason:\n response.reason ?? \"Confirmation required by hook\",\n },\n });\n }\n\n // modify → unsupported on JetBrains (canModifyArgs:false): a PreToolUse hook\n // cannot rewrite tool input here, so degrade to allow rather than emit an\n // updatedInput the host will ignore.\n\n // context → inject soft guidance (also the SessionStart context path).\n if (decision === \"context\" && response.additionalContext) {\n return this.stdout({\n hookSpecificOutput: { hookEventName, additionalContext: response.additionalContext },\n });\n }\n\n // allow / void / modify-degradation / unsupported → pass through with exit 0.\n return { exitCode: 0 };\n }\n\n private stdout(payload: unknown): HookReply {\n return { exitCode: 0, stdout: JSON.stringify(payload) };\n }\n}\n\n/**\n * Extract a stable session id from a JetBrains Copilot wire payload. Priority\n * mirrors the Claude-compatible wire: transcript UUID > session_id > \"\" (the\n * framework uses \"\" when no id is available — no ppid fabrication here).\n */\nfunction extractSessionId(input: JetBrainsWireInput): string {\n if (typeof input.transcript_path === \"string\") {\n const m = input.transcript_path.match(/([a-f0-9-]{36})\\.jsonl$/);\n if (m && m[1]) return m[1];\n }\n if (typeof input.session_id === \"string\" && input.session_id !== \"\") {\n return input.session_id;\n }\n return \"\";\n}\n\n/** Coerce a Claude-compatible PostToolUse `tool_response` into a string. */\nfunction toolResponseToString(value: unknown): string | undefined {\n if (value == null) return undefined;\n if (typeof value === \"string\") return value;\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\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 JetBrainsCopilotAdapter();\nexport default adapter;\n"],"mappings":"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","names":[]}
@@ -0,0 +1,235 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ readJsonFile
4
+ } from "./chunk-RK6VBLXP.js";
5
+ import {
6
+ expandHome,
7
+ walkFiles
8
+ } from "./chunk-JWNT5KW7.js";
9
+ import {
10
+ emptyTokens
11
+ } from "./chunk-XD7MY6HB.js";
12
+
13
+ // src/usage/readers/kilo.ts
14
+ import { existsSync, readFileSync } from "fs";
15
+ import { homedir, platform as osPlatform } from "os";
16
+ import { basename, dirname, isAbsolute, join, resolve } from "path";
17
+ var PLATFORM_ID = "kilo";
18
+ var DEFAULT_MODEL = "unknown";
19
+ var DEFAULT_PROVIDER = "unknown";
20
+ var DEFAULT_SESSION = "unknown";
21
+ var KILO_EXTENSION_ID = "kilocode.kilo-code";
22
+ function vscodeUserDir() {
23
+ const home = homedir();
24
+ switch (osPlatform()) {
25
+ case "darwin":
26
+ return join(home, "Library", "Application Support", "Code", "User");
27
+ case "win32": {
28
+ const appData = process.env.APPDATA ?? join(home, "AppData", "Roaming");
29
+ return join(appData, "Code", "User");
30
+ }
31
+ default:
32
+ return join(home, ".config", "Code", "User");
33
+ }
34
+ }
35
+ function tasksRoots() {
36
+ const raw = process.env.AGENT_CONNECTOR_KILO_DIR;
37
+ if (raw != null && raw.trim() !== "") {
38
+ const expanded = expandHome(raw.trim());
39
+ return [isAbsolute(expanded) ? expanded : resolve(expanded)];
40
+ }
41
+ const home = homedir();
42
+ return [
43
+ join(vscodeUserDir(), "globalStorage", KILO_EXTENSION_ID, "tasks"),
44
+ join(home, ".vscode-server", "data", "User", "globalStorage", KILO_EXTENSION_ID, "tasks")
45
+ ];
46
+ }
47
+ function extractI64(v) {
48
+ if (typeof v === "number") {
49
+ if (!Number.isFinite(v)) return void 0;
50
+ return Math.trunc(v);
51
+ }
52
+ if (typeof v === "string") {
53
+ const trimmed = v.trim();
54
+ if (!/^[+-]?\d+$/.test(trimmed)) return void 0;
55
+ const n = Number(trimmed);
56
+ return Number.isFinite(n) ? Math.trunc(n) : void 0;
57
+ }
58
+ return void 0;
59
+ }
60
+ function tokenField(v) {
61
+ const n = extractI64(v);
62
+ return n === void 0 ? 0 : Math.max(0, n);
63
+ }
64
+ function extractF64(v) {
65
+ if (typeof v === "number") return Number.isFinite(v) ? v : void 0;
66
+ if (typeof v === "string") {
67
+ const n = Number(v.trim());
68
+ return Number.isFinite(n) ? n : void 0;
69
+ }
70
+ return void 0;
71
+ }
72
+ function parseEntryTimestamp(v) {
73
+ let s;
74
+ if (typeof v === "string") s = v;
75
+ else if (typeof v === "number" && Number.isFinite(v)) s = String(Math.trunc(v));
76
+ else return null;
77
+ return parseTimestampStr(s);
78
+ }
79
+ function parseTimestampStr(value) {
80
+ const ms = Date.parse(value);
81
+ if (!Number.isNaN(ms)) return ms;
82
+ if (/^[+-]?\d+$/.test(value.trim())) {
83
+ const numeric = Number(value.trim());
84
+ if (!Number.isFinite(numeric) || numeric <= 0) return null;
85
+ return numeric >= 1e12 ? numeric : numeric * 1e3;
86
+ }
87
+ return null;
88
+ }
89
+ function extractSessionId(path) {
90
+ const parent = basename(dirname(path));
91
+ return parent !== "" ? parent : DEFAULT_SESSION;
92
+ }
93
+ function readTaskMetadata(uiMessagesPath) {
94
+ const historyPath = join(dirname(uiMessagesPath), "api_conversation_history.json");
95
+ let content;
96
+ try {
97
+ content = readFileSync(historyPath, "utf8");
98
+ } catch {
99
+ return { model: DEFAULT_MODEL };
100
+ }
101
+ return extractModelAndAgent(content);
102
+ }
103
+ function extractModelAndAgent(content) {
104
+ const ENV_START = "<environment_details>";
105
+ const ENV_END = "</environment_details>";
106
+ let offset = 0;
107
+ let lastModel;
108
+ let lastSlug;
109
+ let lastName;
110
+ for (; ; ) {
111
+ const startRel = content.indexOf(ENV_START, offset);
112
+ if (startRel < 0) break;
113
+ const startIdx = startRel + ENV_START.length;
114
+ const endRel = content.indexOf(ENV_END, startIdx);
115
+ if (endRel < 0) break;
116
+ const block = content.slice(startIdx, endRel);
117
+ const model = extractTagValue(block, "model");
118
+ if (model !== void 0) lastModel = model;
119
+ const slug = extractTagValue(block, "slug");
120
+ if (slug !== void 0) lastSlug = slug;
121
+ const name = extractTagValue(block, "name");
122
+ if (name !== void 0) lastName = name;
123
+ offset = endRel + ENV_END.length;
124
+ }
125
+ const agent = lastSlug ?? lastName;
126
+ const result = { model: lastModel ?? DEFAULT_MODEL };
127
+ if (agent !== void 0) result.agent = agent;
128
+ return result;
129
+ }
130
+ function extractTagValue(block, tag) {
131
+ const open = `<${tag}>`;
132
+ const close = `</${tag}>`;
133
+ const openIdx = block.indexOf(open);
134
+ if (openIdx < 0) return void 0;
135
+ const start = openIdx + open.length;
136
+ const endRel = block.indexOf(close, start);
137
+ if (endRel < 0) return void 0;
138
+ const value = block.slice(start, endRel).trim();
139
+ return value === "" ? void 0 : value;
140
+ }
141
+ function parseApiReqStartedPayload(text) {
142
+ let value;
143
+ try {
144
+ value = JSON.parse(text);
145
+ } catch {
146
+ return void 0;
147
+ }
148
+ if (typeof value !== "object" || value === null) return void 0;
149
+ const obj = value;
150
+ const cost = Math.max(0, extractF64(obj["cost"]) ?? 0);
151
+ const apiProtocolRaw = typeof obj["apiProtocol"] === "string" ? obj["apiProtocol"] : void 0;
152
+ const payload = {
153
+ cost,
154
+ tokensIn: tokenField(obj["tokensIn"]),
155
+ tokensOut: tokenField(obj["tokensOut"]),
156
+ cacheReads: tokenField(obj["cacheReads"]),
157
+ cacheWrites: tokenField(obj["cacheWrites"])
158
+ };
159
+ if (apiProtocolRaw !== void 0) payload.apiProtocol = apiProtocolRaw;
160
+ return payload;
161
+ }
162
+ function providerFromApiProtocol(apiProtocol) {
163
+ if (apiProtocol === void 0) return DEFAULT_PROVIDER;
164
+ const trimmed = apiProtocol.trim();
165
+ return trimmed === "" ? DEFAULT_PROVIDER : trimmed;
166
+ }
167
+ function parseKiloFile(path) {
168
+ const data = readJsonFile(path);
169
+ if (!Array.isArray(data)) return [];
170
+ const sessionId = extractSessionId(path);
171
+ const { model, agent } = readTaskMetadata(path);
172
+ const out = [];
173
+ for (const raw of data) {
174
+ if (typeof raw !== "object" || raw === null) continue;
175
+ const entry = raw;
176
+ if (entry.type !== "say" || entry.say !== "api_req_started") continue;
177
+ if (typeof entry.text !== "string") continue;
178
+ const ts = parseEntryTimestamp(entry.ts);
179
+ if (ts === null) continue;
180
+ const payload = parseApiReqStartedPayload(entry.text);
181
+ if (payload === void 0) continue;
182
+ const providerId = providerFromApiProtocol(payload.apiProtocol);
183
+ const tokens = emptyTokens();
184
+ tokens.input = payload.tokensIn;
185
+ tokens.output = payload.tokensOut;
186
+ tokens.cacheRead = payload.cacheReads;
187
+ tokens.cacheWrite = payload.cacheWrites;
188
+ const record = {
189
+ platformId: PLATFORM_ID,
190
+ modelId: model,
191
+ providerId,
192
+ sessionId,
193
+ tokens,
194
+ ts,
195
+ messageCount: 1,
196
+ confidence: "host-reported"
197
+ };
198
+ if (payload.cost > 0) record.cost = payload.cost;
199
+ if (agent !== void 0) record.agent = agent;
200
+ out.push(record);
201
+ }
202
+ return out;
203
+ }
204
+ var kiloReader = {
205
+ platformId: PLATFORM_ID,
206
+ kind: "local",
207
+ async read({ sinceMs }) {
208
+ const roots = tasksRoots().filter((root) => existsSync(root));
209
+ if (roots.length === 0) return [];
210
+ const records = [];
211
+ for (const root of roots) {
212
+ const files = walkFiles(root, (name, abs) => {
213
+ return name === "ui_messages.json" && /[\\/]ui_messages\.json$/.test(abs);
214
+ });
215
+ for (const file of files) {
216
+ let rows;
217
+ try {
218
+ rows = parseKiloFile(file);
219
+ } catch {
220
+ continue;
221
+ }
222
+ for (const row of rows) {
223
+ if (sinceMs !== void 0 && row.ts < sinceMs) continue;
224
+ records.push(row);
225
+ }
226
+ }
227
+ }
228
+ return records;
229
+ }
230
+ };
231
+ var kilo_default = kiloReader;
232
+ export {
233
+ kilo_default as default
234
+ };
235
+ //# sourceMappingURL=kilo-NSWAVP6P.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/usage/readers/kilo.ts"],"sourcesContent":["/**\n * usage/readers/kilo — Kilo Code (VS Code extension) task-log reader.\n *\n * Faithful port of tokscale sessions/kilocode.rs, which is a one-line wrapper\n * around roocode.rs `parse_roo_kilo_file(path, \"kilocode\")` — Kilo Code shares\n * the EXACT same task-log format as Roo Code, differing only in its VS Code\n * extension id (`kilocode.kilo-code`) and the source label. This is the Kilo\n * VS Code extension usage (distinct from the kilo-cli SQLite reader, platformId\n * \"kilo-cli\", which lands separately).\n *\n * Kilo Code (kilocode.kilo-code) persists per-task logs under its VS Code\n * globalStorage:\n * <vscodeUserDir>/globalStorage/kilocode.kilo-code/tasks/<taskId>/\n * ui_messages.json (the UI message stream — token source)\n * api_conversation_history.json (sibling — model/agent source)\n * The Rust scanner additionally discovers a remote-host server path under\n * ~/.vscode-server/data/User/globalStorage/kilocode.kilo-code/tasks, so we scan\n * both the desktop and server tasks roots that exist.\n *\n * kilo is NOT in paths.ts hostRoots (that per-platform table targets CLIs with\n * ~/.<tool> roots, not VS Code extension globalStorage), so this reader resolves\n * the cross-OS VS Code \"User\" dir itself, mirroring readers/roo-code.ts:\n * - macOS → ~/Library/Application Support/Code/User\n * - Windows → %APPDATA%/Code/User (else ~/AppData/Roaming/Code/User)\n * - Linux → ~/.config/Code/User\n * An AGENT_CONNECTOR_KILO_DIR override (verbatim, non-empty, ~-expanded, resolved\n * against CWD when relative) points directly at a single `tasks` parent when set,\n * matching the env convention in paths.ts hostRoots.\n *\n * Tokens (ui_messages.json): the file is a JSON ARRAY of entries; only entries\n * with type==\"say\" AND say==\"api_req_started\" carry usage. Each such entry's\n * `text` field is a JSON-in-string payload (SAME shape as Roo Code):\n * tokensIn → input\n * tokensOut → output\n * cacheReads → cacheRead\n * cacheWrites → cacheWrite\n * cost (f64) → cost\n * apiProtocol → providerId (preserved verbatim, e.g. \"azure/openai\")\n * reasoning is ALWAYS 0 (Kilo Code does not report it). A malformed text payload,\n * a missing text, or an unparseable `ts` skips just that entry.\n *\n * model / agent (api_conversation_history.json): scan every\n * <environment_details>…</environment_details> block for <model>, <slug>, <name>\n * tags; the LAST <model> wins (default \"unknown\"); agent prefers <slug> then\n * <name> (optional). When the sibling file is absent/unreadable: model \"unknown\",\n * no agent — exactly the Rust read_task_metadata fallback.\n *\n * session id is the taskId — the parent directory name of ui_messages.json\n * (port of extract_session_id), defaulting to \"unknown\". provider from\n * apiProtocol (trimmed, default \"unknown\"). No project attribution (Kilo Code's\n * logs carry no cwd). No dedup — one row per api_req_started event (file\n * isolation is the implicit unique context). Confidence is \"host-reported\"\n * (real host-logged token counts; the design rates this medium qualitatively).\n *\n * Fail-open: no root → []; unreadable/malformed file, entry, or payload → skipped\n * (never throws). Read-only.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { homedir, platform as osPlatform } from \"node:os\";\nimport { basename, dirname, isAbsolute, join, resolve } from \"node:path\";\n\nimport type { UsageReader, UsageRecord } from \"../types.js\";\nimport { emptyTokens } from \"../aggregate.js\";\nimport { readJsonFile } from \"../jsonl.js\";\nimport { expandHome, walkFiles } from \"../paths.js\";\n\nconst PLATFORM_ID = \"kilo\" as const;\nconst DEFAULT_MODEL = \"unknown\";\nconst DEFAULT_PROVIDER = \"unknown\";\nconst DEFAULT_SESSION = \"unknown\";\n\n/** Kilo Code extension id → its VS Code globalStorage folder. */\nconst KILO_EXTENSION_ID = \"kilocode.kilo-code\";\n\n// ─────────────────────────────────────────────────────────────────────────\n// Storage-root resolution (mirrors readers/roo-code.ts vscodeUserDir + the\n// AGENT_CONNECTOR_<PLATFORM>_DIR env convention in paths.ts hostRoots, plus the\n// remote .vscode-server server path the Rust scanner adds for KiloCode)\n// ─────────────────────────────────────────────────────────────────────────\n\n/** Resolve the cross-OS VS Code per-user \"User\" dir (the globalStorage parent). */\nfunction vscodeUserDir(): string {\n const home = homedir();\n switch (osPlatform()) {\n case \"darwin\":\n return join(home, \"Library\", \"Application Support\", \"Code\", \"User\");\n case \"win32\": {\n const appData = process.env.APPDATA ?? join(home, \"AppData\", \"Roaming\");\n return join(appData, \"Code\", \"User\");\n }\n default:\n return join(home, \".config\", \"Code\", \"User\");\n }\n}\n\n/**\n * The `tasks` roots holding per-task subdirectories. An\n * AGENT_CONNECTOR_KILO_DIR override (verbatim, non-empty, ~-expanded, resolved\n * against CWD when relative) short-circuits to that single root. Otherwise we\n * return the desktop globalStorage tasks dir and the remote-host\n * ~/.vscode-server tasks dir (the two roots the Rust scanner discovers for\n * KiloCode); the caller scans whichever exist.\n */\nfunction tasksRoots(): string[] {\n const raw = process.env.AGENT_CONNECTOR_KILO_DIR;\n if (raw != null && raw.trim() !== \"\") {\n const expanded = expandHome(raw.trim());\n return [isAbsolute(expanded) ? expanded : resolve(expanded)];\n }\n const home = homedir();\n return [\n join(vscodeUserDir(), \"globalStorage\", KILO_EXTENSION_ID, \"tasks\"),\n join(home, \".vscode-server\", \"data\", \"User\", \"globalStorage\", KILO_EXTENSION_ID, \"tasks\"),\n ];\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Value coercion (ports of utils.rs extract_i64 / extract_f64 / parse_timestamp_str)\n// ─────────────────────────────────────────────────────────────────────────\n\n/** Port of extract_i64: number / numeric-string → integer, else undefined. */\nfunction extractI64(v: unknown): number | undefined {\n if (typeof v === \"number\") {\n if (!Number.isFinite(v)) return undefined;\n return Math.trunc(v);\n }\n if (typeof v === \"string\") {\n const trimmed = v.trim();\n if (!/^[+-]?\\d+$/.test(trimmed)) return undefined; // Rust parses as i64 (integer-only)\n const n = Number(trimmed);\n return Number.isFinite(n) ? Math.trunc(n) : undefined;\n }\n return undefined;\n}\n\n/** A non-negative integer from a payload field (0 on absence/garbage, clamped ≥ 0). */\nfunction tokenField(v: unknown): number {\n const n = extractI64(v);\n return n === undefined ? 0 : Math.max(0, n);\n}\n\n/** Port of extract_f64: number / numeric-string → f64, else undefined. */\nfunction extractF64(v: unknown): number | undefined {\n if (typeof v === \"number\") return Number.isFinite(v) ? v : undefined;\n if (typeof v === \"string\") {\n const n = Number(v.trim());\n return Number.isFinite(n) ? n : undefined;\n }\n return undefined;\n}\n\n/**\n * Port of utils.rs parse_timestamp_str / parse_entry_timestamp: an RFC3339 string\n * → epoch ms; an integer (string or number) → ms (×1000 when below the 1e12 ms\n * threshold); rejects ≤ 0. Returns null when unusable so the entry is skipped.\n */\nfunction parseEntryTimestamp(v: unknown): number | null {\n let s: string;\n if (typeof v === \"string\") s = v;\n else if (typeof v === \"number\" && Number.isFinite(v)) s = String(Math.trunc(v));\n else return null;\n\n return parseTimestampStr(s);\n}\n\nfunction parseTimestampStr(value: string): number | null {\n const ms = Date.parse(value);\n if (!Number.isNaN(ms)) return ms; // RFC3339 / any Date-parseable form\n\n if (/^[+-]?\\d+$/.test(value.trim())) {\n const numeric = Number(value.trim());\n if (!Number.isFinite(numeric) || numeric <= 0) return null;\n return numeric >= 1_000_000_000_000 ? numeric : numeric * 1000;\n }\n return null;\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// session id (port of extract_session_id)\n// ─────────────────────────────────────────────────────────────────────────\n\n/** Session id = the parent directory (taskId) of ui_messages.json, else \"unknown\". */\nfunction extractSessionId(path: string): string {\n const parent = basename(dirname(path));\n return parent !== \"\" ? parent : DEFAULT_SESSION;\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// model / agent (ports of read_task_metadata / extract_model_and_agent / extract_tag_value)\n// ─────────────────────────────────────────────────────────────────────────\n\ninterface TaskMetadata {\n model: string;\n agent?: string;\n}\n\n/** Read the sibling api_conversation_history.json for model/agent (fail-open). */\nfunction readTaskMetadata(uiMessagesPath: string): TaskMetadata {\n const historyPath = join(dirname(uiMessagesPath), \"api_conversation_history.json\");\n let content: string;\n try {\n content = readFileSync(historyPath, \"utf8\");\n } catch {\n return { model: DEFAULT_MODEL }; // missing/unreadable → (\"unknown\", None)\n }\n return extractModelAndAgent(content);\n}\n\n/**\n * Scan every <environment_details>…</environment_details> block, extracting\n * <model>, <slug>, <name>. The LAST non-empty value of each tag wins (port of the\n * Rust last_* accumulation). model defaults to \"unknown\"; agent prefers slug then\n * name (and is omitted when neither is present).\n */\nfunction extractModelAndAgent(content: string): TaskMetadata {\n const ENV_START = \"<environment_details>\";\n const ENV_END = \"</environment_details>\";\n\n let offset = 0;\n let lastModel: string | undefined;\n let lastSlug: string | undefined;\n let lastName: string | undefined;\n\n for (;;) {\n const startRel = content.indexOf(ENV_START, offset);\n if (startRel < 0) break;\n const startIdx = startRel + ENV_START.length;\n\n const endRel = content.indexOf(ENV_END, startIdx);\n if (endRel < 0) break;\n\n const block = content.slice(startIdx, endRel);\n\n const model = extractTagValue(block, \"model\");\n if (model !== undefined) lastModel = model;\n const slug = extractTagValue(block, \"slug\");\n if (slug !== undefined) lastSlug = slug;\n const name = extractTagValue(block, \"name\");\n if (name !== undefined) lastName = name;\n\n offset = endRel + ENV_END.length;\n }\n\n const agent = lastSlug ?? lastName;\n const result: TaskMetadata = { model: lastModel ?? DEFAULT_MODEL };\n if (agent !== undefined) result.agent = agent;\n return result;\n}\n\n/** First <tag>…</tag> value in `block`, trimmed; undefined when absent or empty. */\nfunction extractTagValue(block: string, tag: string): string | undefined {\n const open = `<${tag}>`;\n const close = `</${tag}>`;\n\n const openIdx = block.indexOf(open);\n if (openIdx < 0) return undefined;\n const start = openIdx + open.length;\n const endRel = block.indexOf(close, start);\n if (endRel < 0) return undefined;\n\n const value = block.slice(start, endRel).trim();\n return value === \"\" ? undefined : value;\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// api_req_started payload (port of parse_api_req_started_payload + provider_from_api_protocol)\n// ─────────────────────────────────────────────────────────────────────────\n\ninterface ApiReqStartedPayload {\n cost: number;\n tokensIn: number;\n tokensOut: number;\n cacheReads: number;\n cacheWrites: number;\n apiProtocol?: string;\n}\n\n/** Parse the JSON-in-string `text` payload of an api_req_started entry. */\nfunction parseApiReqStartedPayload(text: string): ApiReqStartedPayload | undefined {\n let value: unknown;\n try {\n value = JSON.parse(text);\n } catch {\n return undefined;\n }\n if (typeof value !== \"object\" || value === null) return undefined;\n const obj = value as Record<string, unknown>;\n\n // cost: extract_f64(.cost).unwrap_or(0.0).max(0.0)\n const cost = Math.max(0, extractF64(obj[\"cost\"]) ?? 0);\n const apiProtocolRaw = typeof obj[\"apiProtocol\"] === \"string\" ? (obj[\"apiProtocol\"] as string) : undefined;\n\n const payload: ApiReqStartedPayload = {\n cost,\n tokensIn: tokenField(obj[\"tokensIn\"]),\n tokensOut: tokenField(obj[\"tokensOut\"]),\n cacheReads: tokenField(obj[\"cacheReads\"]),\n cacheWrites: tokenField(obj[\"cacheWrites\"]),\n };\n if (apiProtocolRaw !== undefined) payload.apiProtocol = apiProtocolRaw;\n return payload;\n}\n\n/** Provider from apiProtocol: trimmed, non-empty, else \"unknown\" (verbatim — no inference). */\nfunction providerFromApiProtocol(apiProtocol: string | undefined): string {\n if (apiProtocol === undefined) return DEFAULT_PROVIDER;\n const trimmed = apiProtocol.trim();\n return trimmed === \"\" ? DEFAULT_PROVIDER : trimmed;\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// File parse (port of parse_roo_kilo_file with source \"kilocode\")\n// ─────────────────────────────────────────────────────────────────────────\n\n/** The fields we read off a ui_messages.json entry (all optional / unknown). */\ninterface UiMessageEntry {\n type?: unknown;\n say?: unknown;\n text?: unknown;\n ts?: unknown;\n}\n\n/** Parse one task's ui_messages.json into usage records. */\nfunction parseKiloFile(path: string): UsageRecord[] {\n const data = readJsonFile(path);\n if (!Array.isArray(data)) return []; // malformed / non-array → no rows\n\n const sessionId = extractSessionId(path);\n const { model, agent } = readTaskMetadata(path);\n\n const out: UsageRecord[] = [];\n for (const raw of data) {\n if (typeof raw !== \"object\" || raw === null) continue;\n const entry = raw as UiMessageEntry;\n\n if (entry.type !== \"say\" || entry.say !== \"api_req_started\") continue;\n\n if (typeof entry.text !== \"string\") continue; // None => skip\n const ts = parseEntryTimestamp(entry.ts);\n if (ts === null) continue; // unparseable ts => skip\n\n const payload = parseApiReqStartedPayload(entry.text);\n if (payload === undefined) continue; // malformed payload => skip\n\n const providerId = providerFromApiProtocol(payload.apiProtocol);\n\n const tokens = emptyTokens();\n tokens.input = payload.tokensIn;\n tokens.output = payload.tokensOut;\n tokens.cacheRead = payload.cacheReads;\n tokens.cacheWrite = payload.cacheWrites;\n // reasoning stays 0 (Kilo Code does not report it).\n\n const record: UsageRecord = {\n platformId: PLATFORM_ID,\n modelId: model,\n providerId,\n sessionId,\n tokens,\n ts,\n messageCount: 1,\n confidence: \"host-reported\",\n };\n if (payload.cost > 0) record.cost = payload.cost;\n if (agent !== undefined) record.agent = agent;\n out.push(record);\n }\n\n return out;\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Reader singleton\n// ─────────────────────────────────────────────────────────────────────────\n\n/** The Kilo Code (VS Code extension) usage reader singleton. */\nconst kiloReader: UsageReader = {\n platformId: PLATFORM_ID,\n kind: \"local\",\n async read({ sinceMs }: { sinceMs?: number }): Promise<UsageRecord[]> {\n const roots = tasksRoots().filter((root) => existsSync(root));\n if (roots.length === 0) return []; // no tasks dir → fail-open\n\n const records: UsageRecord[] = [];\n for (const root of roots) {\n // <root>/<taskId>/ui_messages.json\n const files = walkFiles(root, (name, abs) => {\n return name === \"ui_messages.json\" && /[\\\\/]ui_messages\\.json$/.test(abs);\n });\n\n for (const file of files) {\n let rows: UsageRecord[];\n try {\n rows = parseKiloFile(file);\n } catch {\n continue; // fail-open per file\n }\n for (const row of rows) {\n if (sinceMs !== undefined && row.ts < sinceMs) continue;\n records.push(row);\n }\n }\n }\n return records;\n },\n};\n\nexport default kiloReader;\n"],"mappings":";;;;;;;;;;;;;AA0DA,SAAS,YAAY,oBAAoB;AACzC,SAAS,SAAS,YAAY,kBAAkB;AAChD,SAAS,UAAU,SAAS,YAAY,MAAM,eAAe;AAO7D,IAAM,cAAc;AACpB,IAAM,gBAAgB;AACtB,IAAM,mBAAmB;AACzB,IAAM,kBAAkB;AAGxB,IAAM,oBAAoB;AAS1B,SAAS,gBAAwB;AAC/B,QAAM,OAAO,QAAQ;AACrB,UAAQ,WAAW,GAAG;AAAA,IACpB,KAAK;AACH,aAAO,KAAK,MAAM,WAAW,uBAAuB,QAAQ,MAAM;AAAA,IACpE,KAAK,SAAS;AACZ,YAAM,UAAU,QAAQ,IAAI,WAAW,KAAK,MAAM,WAAW,SAAS;AACtE,aAAO,KAAK,SAAS,QAAQ,MAAM;AAAA,IACrC;AAAA,IACA;AACE,aAAO,KAAK,MAAM,WAAW,QAAQ,MAAM;AAAA,EAC/C;AACF;AAUA,SAAS,aAAuB;AAC9B,QAAM,MAAM,QAAQ,IAAI;AACxB,MAAI,OAAO,QAAQ,IAAI,KAAK,MAAM,IAAI;AACpC,UAAM,WAAW,WAAW,IAAI,KAAK,CAAC;AACtC,WAAO,CAAC,WAAW,QAAQ,IAAI,WAAW,QAAQ,QAAQ,CAAC;AAAA,EAC7D;AACA,QAAM,OAAO,QAAQ;AACrB,SAAO;AAAA,IACL,KAAK,cAAc,GAAG,iBAAiB,mBAAmB,OAAO;AAAA,IACjE,KAAK,MAAM,kBAAkB,QAAQ,QAAQ,iBAAiB,mBAAmB,OAAO;AAAA,EAC1F;AACF;AAOA,SAAS,WAAW,GAAgC;AAClD,MAAI,OAAO,MAAM,UAAU;AACzB,QAAI,CAAC,OAAO,SAAS,CAAC,EAAG,QAAO;AAChC,WAAO,KAAK,MAAM,CAAC;AAAA,EACrB;AACA,MAAI,OAAO,MAAM,UAAU;AACzB,UAAM,UAAU,EAAE,KAAK;AACvB,QAAI,CAAC,aAAa,KAAK,OAAO,EAAG,QAAO;AACxC,UAAM,IAAI,OAAO,OAAO;AACxB,WAAO,OAAO,SAAS,CAAC,IAAI,KAAK,MAAM,CAAC,IAAI;AAAA,EAC9C;AACA,SAAO;AACT;AAGA,SAAS,WAAW,GAAoB;AACtC,QAAM,IAAI,WAAW,CAAC;AACtB,SAAO,MAAM,SAAY,IAAI,KAAK,IAAI,GAAG,CAAC;AAC5C;AAGA,SAAS,WAAW,GAAgC;AAClD,MAAI,OAAO,MAAM,SAAU,QAAO,OAAO,SAAS,CAAC,IAAI,IAAI;AAC3D,MAAI,OAAO,MAAM,UAAU;AACzB,UAAM,IAAI,OAAO,EAAE,KAAK,CAAC;AACzB,WAAO,OAAO,SAAS,CAAC,IAAI,IAAI;AAAA,EAClC;AACA,SAAO;AACT;AAOA,SAAS,oBAAoB,GAA2B;AACtD,MAAI;AACJ,MAAI,OAAO,MAAM,SAAU,KAAI;AAAA,WACtB,OAAO,MAAM,YAAY,OAAO,SAAS,CAAC,EAAG,KAAI,OAAO,KAAK,MAAM,CAAC,CAAC;AAAA,MACzE,QAAO;AAEZ,SAAO,kBAAkB,CAAC;AAC5B;AAEA,SAAS,kBAAkB,OAA8B;AACvD,QAAM,KAAK,KAAK,MAAM,KAAK;AAC3B,MAAI,CAAC,OAAO,MAAM,EAAE,EAAG,QAAO;AAE9B,MAAI,aAAa,KAAK,MAAM,KAAK,CAAC,GAAG;AACnC,UAAM,UAAU,OAAO,MAAM,KAAK,CAAC;AACnC,QAAI,CAAC,OAAO,SAAS,OAAO,KAAK,WAAW,EAAG,QAAO;AACtD,WAAO,WAAW,OAAoB,UAAU,UAAU;AAAA,EAC5D;AACA,SAAO;AACT;AAOA,SAAS,iBAAiB,MAAsB;AAC9C,QAAM,SAAS,SAAS,QAAQ,IAAI,CAAC;AACrC,SAAO,WAAW,KAAK,SAAS;AAClC;AAYA,SAAS,iBAAiB,gBAAsC;AAC9D,QAAM,cAAc,KAAK,QAAQ,cAAc,GAAG,+BAA+B;AACjF,MAAI;AACJ,MAAI;AACF,cAAU,aAAa,aAAa,MAAM;AAAA,EAC5C,QAAQ;AACN,WAAO,EAAE,OAAO,cAAc;AAAA,EAChC;AACA,SAAO,qBAAqB,OAAO;AACrC;AAQA,SAAS,qBAAqB,SAA+B;AAC3D,QAAM,YAAY;AAClB,QAAM,UAAU;AAEhB,MAAI,SAAS;AACb,MAAI;AACJ,MAAI;AACJ,MAAI;AAEJ,aAAS;AACP,UAAM,WAAW,QAAQ,QAAQ,WAAW,MAAM;AAClD,QAAI,WAAW,EAAG;AAClB,UAAM,WAAW,WAAW,UAAU;AAEtC,UAAM,SAAS,QAAQ,QAAQ,SAAS,QAAQ;AAChD,QAAI,SAAS,EAAG;AAEhB,UAAM,QAAQ,QAAQ,MAAM,UAAU,MAAM;AAE5C,UAAM,QAAQ,gBAAgB,OAAO,OAAO;AAC5C,QAAI,UAAU,OAAW,aAAY;AACrC,UAAM,OAAO,gBAAgB,OAAO,MAAM;AAC1C,QAAI,SAAS,OAAW,YAAW;AACnC,UAAM,OAAO,gBAAgB,OAAO,MAAM;AAC1C,QAAI,SAAS,OAAW,YAAW;AAEnC,aAAS,SAAS,QAAQ;AAAA,EAC5B;AAEA,QAAM,QAAQ,YAAY;AAC1B,QAAM,SAAuB,EAAE,OAAO,aAAa,cAAc;AACjE,MAAI,UAAU,OAAW,QAAO,QAAQ;AACxC,SAAO;AACT;AAGA,SAAS,gBAAgB,OAAe,KAAiC;AACvE,QAAM,OAAO,IAAI,GAAG;AACpB,QAAM,QAAQ,KAAK,GAAG;AAEtB,QAAM,UAAU,MAAM,QAAQ,IAAI;AAClC,MAAI,UAAU,EAAG,QAAO;AACxB,QAAM,QAAQ,UAAU,KAAK;AAC7B,QAAM,SAAS,MAAM,QAAQ,OAAO,KAAK;AACzC,MAAI,SAAS,EAAG,QAAO;AAEvB,QAAM,QAAQ,MAAM,MAAM,OAAO,MAAM,EAAE,KAAK;AAC9C,SAAO,UAAU,KAAK,SAAY;AACpC;AAgBA,SAAS,0BAA0B,MAAgD;AACjF,MAAI;AACJ,MAAI;AACF,YAAQ,KAAK,MAAM,IAAI;AAAA,EACzB,QAAQ;AACN,WAAO;AAAA,EACT;AACA,MAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;AACxD,QAAM,MAAM;AAGZ,QAAM,OAAO,KAAK,IAAI,GAAG,WAAW,IAAI,MAAM,CAAC,KAAK,CAAC;AACrD,QAAM,iBAAiB,OAAO,IAAI,aAAa,MAAM,WAAY,IAAI,aAAa,IAAe;AAEjG,QAAM,UAAgC;AAAA,IACpC;AAAA,IACA,UAAU,WAAW,IAAI,UAAU,CAAC;AAAA,IACpC,WAAW,WAAW,IAAI,WAAW,CAAC;AAAA,IACtC,YAAY,WAAW,IAAI,YAAY,CAAC;AAAA,IACxC,aAAa,WAAW,IAAI,aAAa,CAAC;AAAA,EAC5C;AACA,MAAI,mBAAmB,OAAW,SAAQ,cAAc;AACxD,SAAO;AACT;AAGA,SAAS,wBAAwB,aAAyC;AACxE,MAAI,gBAAgB,OAAW,QAAO;AACtC,QAAM,UAAU,YAAY,KAAK;AACjC,SAAO,YAAY,KAAK,mBAAmB;AAC7C;AAeA,SAAS,cAAc,MAA6B;AAClD,QAAM,OAAO,aAAa,IAAI;AAC9B,MAAI,CAAC,MAAM,QAAQ,IAAI,EAAG,QAAO,CAAC;AAElC,QAAM,YAAY,iBAAiB,IAAI;AACvC,QAAM,EAAE,OAAO,MAAM,IAAI,iBAAiB,IAAI;AAE9C,QAAM,MAAqB,CAAC;AAC5B,aAAW,OAAO,MAAM;AACtB,QAAI,OAAO,QAAQ,YAAY,QAAQ,KAAM;AAC7C,UAAM,QAAQ;AAEd,QAAI,MAAM,SAAS,SAAS,MAAM,QAAQ,kBAAmB;AAE7D,QAAI,OAAO,MAAM,SAAS,SAAU;AACpC,UAAM,KAAK,oBAAoB,MAAM,EAAE;AACvC,QAAI,OAAO,KAAM;AAEjB,UAAM,UAAU,0BAA0B,MAAM,IAAI;AACpD,QAAI,YAAY,OAAW;AAE3B,UAAM,aAAa,wBAAwB,QAAQ,WAAW;AAE9D,UAAM,SAAS,YAAY;AAC3B,WAAO,QAAQ,QAAQ;AACvB,WAAO,SAAS,QAAQ;AACxB,WAAO,YAAY,QAAQ;AAC3B,WAAO,aAAa,QAAQ;AAG5B,UAAM,SAAsB;AAAA,MAC1B,YAAY;AAAA,MACZ,SAAS;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,cAAc;AAAA,MACd,YAAY;AAAA,IACd;AACA,QAAI,QAAQ,OAAO,EAAG,QAAO,OAAO,QAAQ;AAC5C,QAAI,UAAU,OAAW,QAAO,QAAQ;AACxC,QAAI,KAAK,MAAM;AAAA,EACjB;AAEA,SAAO;AACT;AAOA,IAAM,aAA0B;AAAA,EAC9B,YAAY;AAAA,EACZ,MAAM;AAAA,EACN,MAAM,KAAK,EAAE,QAAQ,GAAiD;AACpE,UAAM,QAAQ,WAAW,EAAE,OAAO,CAAC,SAAS,WAAW,IAAI,CAAC;AAC5D,QAAI,MAAM,WAAW,EAAG,QAAO,CAAC;AAEhC,UAAM,UAAyB,CAAC;AAChC,eAAW,QAAQ,OAAO;AAExB,YAAM,QAAQ,UAAU,MAAM,CAAC,MAAM,QAAQ;AAC3C,eAAO,SAAS,sBAAsB,0BAA0B,KAAK,GAAG;AAAA,MAC1E,CAAC;AAED,iBAAW,QAAQ,OAAO;AACxB,YAAI;AACJ,YAAI;AACF,iBAAO,cAAc,IAAI;AAAA,QAC3B,QAAQ;AACN;AAAA,QACF;AACA,mBAAW,OAAO,MAAM;AACtB,cAAI,YAAY,UAAa,IAAI,KAAK,QAAS;AAC/C,kBAAQ,KAAK,GAAG;AAAA,QAClB;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACF;AAEA,IAAO,eAAQ;","names":[]}