openvibe 0.63.2 → 0.63.3

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 (158) hide show
  1. package/CHANGELOG.md +81 -0
  2. package/README.md +39 -0
  3. package/README_CN.md +1 -1
  4. package/dist/cli/args.d.ts +3 -1
  5. package/dist/cli/args.d.ts.map +1 -1
  6. package/dist/cli/args.js +22 -2
  7. package/dist/cli/args.js.map +1 -1
  8. package/dist/core/agent-session.d.ts.map +1 -1
  9. package/dist/core/agent-session.js +5 -3
  10. package/dist/core/agent-session.js.map +1 -1
  11. package/dist/core/companion/executor/bash-executor.d.ts +30 -0
  12. package/dist/core/companion/executor/bash-executor.d.ts.map +1 -0
  13. package/dist/core/companion/executor/bash-executor.js +105 -0
  14. package/dist/core/companion/executor/bash-executor.js.map +1 -0
  15. package/dist/core/companion/executor/code-executor.d.ts +33 -0
  16. package/dist/core/companion/executor/code-executor.d.ts.map +1 -0
  17. package/dist/core/companion/executor/code-executor.js +144 -0
  18. package/dist/core/companion/executor/code-executor.js.map +1 -0
  19. package/dist/core/companion/executor/resource-monitor.d.ts +55 -0
  20. package/dist/core/companion/executor/resource-monitor.d.ts.map +1 -0
  21. package/dist/core/companion/executor/resource-monitor.js +141 -0
  22. package/dist/core/companion/executor/resource-monitor.js.map +1 -0
  23. package/dist/core/companion/http-server.d.ts +92 -0
  24. package/dist/core/companion/http-server.d.ts.map +1 -0
  25. package/dist/core/companion/http-server.js +229 -0
  26. package/dist/core/companion/http-server.js.map +1 -0
  27. package/dist/core/companion/index.d.ts +29 -0
  28. package/dist/core/companion/index.d.ts.map +1 -0
  29. package/dist/core/companion/index.js +48 -0
  30. package/dist/core/companion/index.js.map +1 -0
  31. package/dist/core/companion/scheduler/resource-scheduler.d.ts +82 -0
  32. package/dist/core/companion/scheduler/resource-scheduler.d.ts.map +1 -0
  33. package/dist/core/companion/scheduler/resource-scheduler.js +333 -0
  34. package/dist/core/companion/scheduler/resource-scheduler.js.map +1 -0
  35. package/dist/core/companion/scheduler/workers/base-worker.d.ts +87 -0
  36. package/dist/core/companion/scheduler/workers/base-worker.d.ts.map +1 -0
  37. package/dist/core/companion/scheduler/workers/base-worker.js +70 -0
  38. package/dist/core/companion/scheduler/workers/base-worker.js.map +1 -0
  39. package/dist/core/companion/scheduler/workers/cpu-worker.d.ts +12 -0
  40. package/dist/core/companion/scheduler/workers/cpu-worker.d.ts.map +1 -0
  41. package/dist/core/companion/scheduler/workers/cpu-worker.js +134 -0
  42. package/dist/core/companion/scheduler/workers/cpu-worker.js.map +1 -0
  43. package/dist/core/companion/scheduler/workers/gpu-worker.d.ts +16 -0
  44. package/dist/core/companion/scheduler/workers/gpu-worker.d.ts.map +1 -0
  45. package/dist/core/companion/scheduler/workers/gpu-worker.js +167 -0
  46. package/dist/core/companion/scheduler/workers/gpu-worker.js.map +1 -0
  47. package/dist/core/companion/scheduler/workers/index.d.ts +6 -0
  48. package/dist/core/companion/scheduler/workers/index.d.ts.map +1 -0
  49. package/dist/core/companion/scheduler/workers/index.js +6 -0
  50. package/dist/core/companion/scheduler/workers/index.js.map +1 -0
  51. package/dist/core/companion/scheduler/workers/io-worker.d.ts +17 -0
  52. package/dist/core/companion/scheduler/workers/io-worker.d.ts.map +1 -0
  53. package/dist/core/companion/scheduler/workers/io-worker.js +197 -0
  54. package/dist/core/companion/scheduler/workers/io-worker.js.map +1 -0
  55. package/dist/core/companion/scheduler/workers/network-worker.d.ts +13 -0
  56. package/dist/core/companion/scheduler/workers/network-worker.d.ts.map +1 -0
  57. package/dist/core/companion/scheduler/workers/network-worker.js +167 -0
  58. package/dist/core/companion/scheduler/workers/network-worker.js.map +1 -0
  59. package/dist/core/companion/security/security-manager.d.ts +50 -0
  60. package/dist/core/companion/security/security-manager.d.ts.map +1 -0
  61. package/dist/core/companion/security/security-manager.js +102 -0
  62. package/dist/core/companion/security/security-manager.js.map +1 -0
  63. package/dist/core/hybrid-cloud/extension.d.ts +8 -0
  64. package/dist/core/hybrid-cloud/extension.d.ts.map +1 -0
  65. package/dist/core/hybrid-cloud/extension.js +64 -0
  66. package/dist/core/hybrid-cloud/extension.js.map +1 -0
  67. package/dist/core/hybrid-cloud/index.d.ts +98 -0
  68. package/dist/core/hybrid-cloud/index.d.ts.map +1 -0
  69. package/dist/core/hybrid-cloud/index.js +211 -0
  70. package/dist/core/hybrid-cloud/index.js.map +1 -0
  71. package/dist/core/keybindings.d.ts +1 -1
  72. package/dist/core/keybindings.d.ts.map +1 -1
  73. package/dist/core/keybindings.js +3 -1
  74. package/dist/core/keybindings.js.map +1 -1
  75. package/dist/core/package-manager.d.ts.map +1 -1
  76. package/dist/core/package-manager.js +6 -1
  77. package/dist/core/package-manager.js.map +1 -1
  78. package/dist/core/settings-manager.d.ts +13 -0
  79. package/dist/core/settings-manager.d.ts.map +1 -1
  80. package/dist/core/settings-manager.js +35 -0
  81. package/dist/core/settings-manager.js.map +1 -1
  82. package/dist/core/slash-commands.d.ts.map +1 -1
  83. package/dist/core/slash-commands.js +7 -0
  84. package/dist/core/slash-commands.js.map +1 -1
  85. package/dist/core/system-prompt.d.ts.map +1 -1
  86. package/dist/core/system-prompt.js +46 -0
  87. package/dist/core/system-prompt.js.map +1 -1
  88. package/dist/core/todo-manager.d.ts +32 -0
  89. package/dist/core/todo-manager.d.ts.map +1 -0
  90. package/dist/core/todo-manager.js +117 -0
  91. package/dist/core/todo-manager.js.map +1 -0
  92. package/dist/core/tools/batch-write.d.ts +42 -0
  93. package/dist/core/tools/batch-write.d.ts.map +1 -0
  94. package/dist/core/tools/batch-write.js +267 -0
  95. package/dist/core/tools/batch-write.js.map +1 -0
  96. package/dist/core/tools/edit.d.ts.map +1 -1
  97. package/dist/core/tools/edit.js +10 -2
  98. package/dist/core/tools/edit.js.map +1 -1
  99. package/dist/core/tools/fast-executor.d.ts +6 -1
  100. package/dist/core/tools/fast-executor.d.ts.map +1 -1
  101. package/dist/core/tools/fast-executor.js +83 -4
  102. package/dist/core/tools/fast-executor.js.map +1 -1
  103. package/dist/core/tools/index.d.ts +141 -0
  104. package/dist/core/tools/index.d.ts.map +1 -1
  105. package/dist/core/tools/index.js +30 -0
  106. package/dist/core/tools/index.js.map +1 -1
  107. package/dist/core/tools/todo.d.ts +47 -0
  108. package/dist/core/tools/todo.d.ts.map +1 -0
  109. package/dist/core/tools/todo.js +212 -0
  110. package/dist/core/tools/todo.js.map +1 -0
  111. package/dist/core/tools/unified.d.ts +121 -0
  112. package/dist/core/tools/unified.d.ts.map +1 -0
  113. package/dist/core/tools/unified.js +481 -0
  114. package/dist/core/tools/unified.js.map +1 -0
  115. package/dist/core/tools/write.d.ts +1 -1
  116. package/dist/core/tools/write.d.ts.map +1 -1
  117. package/dist/core/tools/write.js +20 -5
  118. package/dist/core/tools/write.js.map +1 -1
  119. package/dist/main.d.ts.map +1 -1
  120. package/dist/main.js +63 -1
  121. package/dist/main.js.map +1 -1
  122. package/dist/modes/index.d.ts +2 -0
  123. package/dist/modes/index.d.ts.map +1 -1
  124. package/dist/modes/index.js +2 -0
  125. package/dist/modes/index.js.map +1 -1
  126. package/dist/modes/interactive/components/index.d.ts +1 -0
  127. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  128. package/dist/modes/interactive/components/index.js +1 -0
  129. package/dist/modes/interactive/components/index.js.map +1 -1
  130. package/dist/modes/interactive/components/todo-display.d.ts +9 -0
  131. package/dist/modes/interactive/components/todo-display.d.ts.map +1 -0
  132. package/dist/modes/interactive/components/todo-display.js +60 -0
  133. package/dist/modes/interactive/components/todo-display.js.map +1 -0
  134. package/dist/modes/interactive/interactive-mode.d.ts +8 -0
  135. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  136. package/dist/modes/interactive/interactive-mode.js +151 -0
  137. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  138. package/dist/modes/plan-mode.d.ts +14 -0
  139. package/dist/modes/plan-mode.d.ts.map +1 -0
  140. package/dist/modes/plan-mode.js +107 -0
  141. package/dist/modes/plan-mode.js.map +1 -0
  142. package/dist/modes/spec-mode.d.ts +16 -0
  143. package/dist/modes/spec-mode.d.ts.map +1 -0
  144. package/dist/modes/spec-mode.js +186 -0
  145. package/dist/modes/spec-mode.js.map +1 -0
  146. package/dist/utils/version-check.d.ts.map +1 -1
  147. package/dist/utils/version-check.js +2 -2
  148. package/dist/utils/version-check.js.map +1 -1
  149. package/docs/HYBRID_CLOUD_README.md +188 -0
  150. package/docs/hybrid-architecture-design.md +317 -0
  151. package/docs/todo.md +71 -0
  152. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  153. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  154. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  155. package/examples/extensions/custom-provider-qwen-cli/package.json +1 -1
  156. package/examples/extensions/with-deps/package-lock.json +2 -2
  157. package/examples/extensions/with-deps/package.json +1 -1
  158. package/package.json +4 -4
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/hybrid-cloud/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAEpE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAE7D,UAAU,iBAAiB;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;IACrB,gBAAgB,EAAE;QACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,MAAM,CAAC,EAAE,OAAO,CAAC;KACjB,CAAC;CACF;AAED;;;GAGG;AACH,qBAAa,kBAAkB;IAC9B,OAAO,CAAC,SAAS,CAAoC;IACrD,OAAO,CAAC,MAAM,CAAoB;IAElC,YAAY,QAAQ,EAAE,YAAY,EAAE,MAAM,GAAE,OAAO,CAAC,iBAAiB,CAAM,EAc1E;IAED;;OAEG;IACH,oBAAoB,CAAC,YAAY,EAAE;QAClC,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B,WAAW,CAAC,EAAE,OAAO,CAAC;QACtB,aAAa,CAAC,EAAE,OAAO,CAAC;KACxB,GAAG,OAAO,CAgCV;IAED;;OAEG;IACH,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAWrB;IAED;;OAEG;IACG,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,UAAU,CAAC,CAW3G;IAED;;OAEG;IACG,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,UAAU,CAAC,CAWrG;IAED;;OAEG;IACH,WAAW,IAAI,cAAc,EAAE,CAoH9B;IAED;;OAEG;IACH,SAAS;;;;MAMR;CACD;AAED,YAAY,EAAE,iBAAiB,EAAE,CAAC","sourcesContent":["/**\n * Hybrid Cloud Integration for OpenVibe\n *\n * 直接使用内部 Companion 服务\n */\n\nimport { type Static, Type } from \"@sinclair/typebox\";\nimport type { AgentSession } from \"../agent-session.js\";\nimport type { BashResult, CodeResult } from \"../companion/index.js\";\nimport { type CompanionHttpServer, getCompanion } from \"../companion/index.js\";\nimport type { ToolDefinition } from \"../extensions/index.js\";\n\ninterface HybridCloudConfig {\n\tenabled: boolean;\n\tautoConnect: boolean;\n\toffloadThreshold: {\n\t\tcpuCores?: number;\n\t\tmemoryMb?: number;\n\t\tuseGpu?: boolean;\n\t};\n}\n\n/**\n * Hybrid Cloud Manager\n * 管理云端与本地代理的协同工作\n */\nexport class HybridCloudManager {\n\tprivate companion: CompanionHttpServer | null = null;\n\tprivate config: HybridCloudConfig;\n\n\tconstructor(_session: AgentSession, config: Partial<HybridCloudConfig> = {}) {\n\t\tthis.config = {\n\t\t\tenabled: config.enabled ?? false,\n\t\t\tautoConnect: config.autoConnect ?? true,\n\t\t\toffloadThreshold: config.offloadThreshold || {\n\t\t\t\tcpuCores: 4,\n\t\t\t\tmemoryMb: 4096,\n\t\t\t\tuseGpu: true,\n\t\t\t},\n\t\t};\n\n\t\tif (this.config.enabled) {\n\t\t\tthis.companion = getCompanion();\n\t\t}\n\t}\n\n\t/**\n\t * 检查是否应该将任务卸载到本地执行\n\t */\n\tshouldOffloadToLocal(requirements: {\n\t\testimatedCpuCores?: number;\n\t\testimatedMemoryMb?: number;\n\t\trequiresGpu?: boolean;\n\t\tisLongRunning?: boolean;\n\t}): boolean {\n\t\tif (!this.config.enabled || !this.companion?.isActive()) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst threshold = this.config.offloadThreshold;\n\n\t\tif (requirements.requiresGpu && threshold.useGpu) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif (\n\t\t\trequirements.estimatedCpuCores &&\n\t\t\tthreshold.cpuCores &&\n\t\t\trequirements.estimatedCpuCores >= threshold.cpuCores\n\t\t) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif (\n\t\t\trequirements.estimatedMemoryMb &&\n\t\t\tthreshold.memoryMb &&\n\t\t\trequirements.estimatedMemoryMb >= threshold.memoryMb\n\t\t) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif (requirements.isLongRunning) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * 获取本地资源状态\n\t */\n\tgetLocalResourceStatus() {\n\t\tif (!this.companion?.isActive()) {\n\t\t\treturn null;\n\t\t}\n\n\t\ttry {\n\t\t\treturn this.companion.getResourceStatus();\n\t\t} catch (error) {\n\t\t\tconsole.error(\"[HybridCloud] Failed to get resource status:\", error);\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/**\n\t * 执行 Bash 命令\n\t */\n\tasync executeBash(command: string, options?: { workingDir?: string; timeout?: number }): Promise<BashResult> {\n\t\tif (!this.companion?.isActive()) {\n\t\t\tthrow new Error(\"Companion not running\");\n\t\t}\n\n\t\tconst scheduler = (this.companion as any).scheduler;\n\t\treturn scheduler.scheduleBash({\n\t\t\tcommand,\n\t\t\tworkingDir: options?.workingDir,\n\t\t\ttimeout: options?.timeout || 300,\n\t\t});\n\t}\n\n\t/**\n\t * 执行代码\n\t */\n\tasync executeCode(code: string, language: string, options?: { timeout?: number }): Promise<CodeResult> {\n\t\tif (!this.companion?.isActive()) {\n\t\t\tthrow new Error(\"Companion not running\");\n\t\t}\n\n\t\tconst scheduler = (this.companion as any).scheduler;\n\t\treturn scheduler.scheduleCode({\n\t\t\tcode,\n\t\t\tlanguage,\n\t\t\ttimeout: options?.timeout || 300,\n\t\t});\n\t}\n\n\t/**\n\t * 创建用于 OpenVibe 扩展的工具定义\n\t */\n\tcreateTools(): ToolDefinition[] {\n\t\tif (!this.config.enabled) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst localExecuteSchema = Type.Object({\n\t\t\ttype: Type.Union(\n\t\t\t\t[Type.Literal(\"bash\"), Type.Literal(\"python\"), Type.Literal(\"javascript\"), Type.Literal(\"rust\")],\n\t\t\t\t{ description: \"Type of execution\" },\n\t\t\t),\n\t\t\tcode: Type.String({ description: \"Code or command to execute\" }),\n\t\t\tworkingDir: Type.Optional(Type.String({ description: \"Working directory for execution\" })),\n\t\t\ttimeout: Type.Optional(Type.Number({ description: \"Timeout in seconds (default: 300)\" })),\n\t\t});\n\n\t\tconst localResourceStatusSchema = Type.Object({});\n\n\t\treturn [\n\t\t\t{\n\t\t\t\tname: \"local_execute\",\n\t\t\t\tlabel: \"local_execute\",\n\t\t\t\tdescription:\n\t\t\t\t\t\"Execute code or commands on the local machine. Use this for tasks that require significant local resources (CPU/GPU), long-running computations, or direct file system access.\",\n\t\t\t\tparameters: localExecuteSchema,\n\t\t\t\texecute: async (_toolCallId: string, args: Static<typeof localExecuteSchema>) => {\n\t\t\t\t\tif (!this.companion?.isActive()) {\n\t\t\t\t\t\tthrow new Error(\"Local agent not running\");\n\t\t\t\t\t}\n\n\t\t\t\t\tconst timeout = args.timeout || 300;\n\n\t\t\t\t\tif (args.type === \"bash\") {\n\t\t\t\t\t\tconst result = await this.executeBash(args.code, {\n\t\t\t\t\t\t\tworkingDir: args.workingDir,\n\t\t\t\t\t\t\ttimeout,\n\t\t\t\t\t\t});\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t\t{ type: \"text\" as const, text: result.success ? result.stdout || \"\" : result.error || \"\" },\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tdetails: { exitCode: result.exitCode, stderr: result.stderr },\n\t\t\t\t\t\t};\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst result = await this.executeCode(args.code, args.type, { timeout });\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t\t{ type: \"text\" as const, text: result.success ? result.output || \"\" : result.error || \"\" },\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tdetails: {},\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"local_resource_status\",\n\t\t\t\tlabel: \"local_resource_status\",\n\t\t\t\tdescription: \"Get the current resource status of the local machine (CPU, GPU, memory, disk).\",\n\t\t\t\tparameters: localResourceStatusSchema,\n\t\t\t\texecute: async () => {\n\t\t\t\t\tconst status = this.getLocalResourceStatus();\n\t\t\t\t\tif (!status) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tcontent: [{ type: \"text\" as const, text: \"Local agent not available\" }],\n\t\t\t\t\t\t\tdetails: {},\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\tconst formatBytes = (bytes: number) => {\n\t\t\t\t\t\tconst gb = bytes / (1024 * 1024 * 1024);\n\t\t\t\t\t\treturn `${gb.toFixed(2)} GB`;\n\t\t\t\t\t};\n\n\t\t\t\t\tconst lines = [\n\t\t\t\t\t\t\"# Local Resource Status\",\n\t\t\t\t\t\t\"\",\n\t\t\t\t\t\t\"## CPU\",\n\t\t\t\t\t\t`- Cores: ${status.cpu?.coreCount || \"N/A\"}`,\n\t\t\t\t\t\t`- Usage: ${status.cpu?.usagePercent.toFixed(1) || \"N/A\"}%`,\n\t\t\t\t\t\t`- Available: ${status.cpu?.availableCores || \"N/A\"}`,\n\t\t\t\t\t\t\"\",\n\t\t\t\t\t\t\"## Memory\",\n\t\t\t\t\t\t`- Total: ${status.memory?.totalMb || \"N/A\"} MB`,\n\t\t\t\t\t\t`- Used: ${status.memory?.usedMb || \"N/A\"} MB`,\n\t\t\t\t\t\t`- Free: ${status.memory?.freeMb || \"N/A\"} MB`,\n\t\t\t\t\t\t`- Usage: ${status.memory?.usagePercent.toFixed(1) || \"N/A\"}%`,\n\t\t\t\t\t\t\"\",\n\t\t\t\t\t\t\"## GPU\",\n\t\t\t\t\t\t`- Devices: ${status.gpu?.deviceCount || 0}`,\n\t\t\t\t\t];\n\n\t\t\t\t\tif (status.gpu?.devices) {\n\t\t\t\t\t\tfor (const gpu of status.gpu.devices) {\n\t\t\t\t\t\t\tlines.push(\n\t\t\t\t\t\t\t\t` - ${gpu.name}: ${gpu.memoryUsedMb}/${gpu.memoryTotalMb} MB (${gpu.memoryUsagePercent.toFixed(1)}%)`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tlines.push(\"\");\n\t\t\t\t\tlines.push(\"## Disk\");\n\n\t\t\t\t\tif (status.disk?.disks) {\n\t\t\t\t\t\tfor (const disk of status.disk.disks) {\n\t\t\t\t\t\t\tlines.push(\n\t\t\t\t\t\t\t\t`- ${disk.mountPoint}: ${formatBytes(disk.usedBytes)}/${formatBytes(disk.totalBytes)} (${disk.usagePercent.toFixed(1)}%)`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: [{ type: \"text\" as const, text: lines.join(\"\\n\") }],\n\t\t\t\t\t\tdetails: {},\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t},\n\t\t];\n\t}\n\n\t/**\n\t * 获取状态信息用于展示\n\t */\n\tgetStatus() {\n\t\treturn {\n\t\t\tenabled: this.config.enabled,\n\t\t\tconnected: this.companion?.isActive() ?? false,\n\t\t\taddress: this.companion?.getAddress(),\n\t\t};\n\t}\n}\n\nexport type { HybridCloudConfig };\n"]}
@@ -0,0 +1,211 @@
1
+ /**
2
+ * Hybrid Cloud Integration for OpenVibe
3
+ *
4
+ * 直接使用内部 Companion 服务
5
+ */
6
+ import { Type } from "@sinclair/typebox";
7
+ import { getCompanion } from "../companion/index.js";
8
+ /**
9
+ * Hybrid Cloud Manager
10
+ * 管理云端与本地代理的协同工作
11
+ */
12
+ export class HybridCloudManager {
13
+ companion = null;
14
+ config;
15
+ constructor(_session, config = {}) {
16
+ this.config = {
17
+ enabled: config.enabled ?? false,
18
+ autoConnect: config.autoConnect ?? true,
19
+ offloadThreshold: config.offloadThreshold || {
20
+ cpuCores: 4,
21
+ memoryMb: 4096,
22
+ useGpu: true,
23
+ },
24
+ };
25
+ if (this.config.enabled) {
26
+ this.companion = getCompanion();
27
+ }
28
+ }
29
+ /**
30
+ * 检查是否应该将任务卸载到本地执行
31
+ */
32
+ shouldOffloadToLocal(requirements) {
33
+ if (!this.config.enabled || !this.companion?.isActive()) {
34
+ return false;
35
+ }
36
+ const threshold = this.config.offloadThreshold;
37
+ if (requirements.requiresGpu && threshold.useGpu) {
38
+ return true;
39
+ }
40
+ if (requirements.estimatedCpuCores &&
41
+ threshold.cpuCores &&
42
+ requirements.estimatedCpuCores >= threshold.cpuCores) {
43
+ return true;
44
+ }
45
+ if (requirements.estimatedMemoryMb &&
46
+ threshold.memoryMb &&
47
+ requirements.estimatedMemoryMb >= threshold.memoryMb) {
48
+ return true;
49
+ }
50
+ if (requirements.isLongRunning) {
51
+ return true;
52
+ }
53
+ return false;
54
+ }
55
+ /**
56
+ * 获取本地资源状态
57
+ */
58
+ getLocalResourceStatus() {
59
+ if (!this.companion?.isActive()) {
60
+ return null;
61
+ }
62
+ try {
63
+ return this.companion.getResourceStatus();
64
+ }
65
+ catch (error) {
66
+ console.error("[HybridCloud] Failed to get resource status:", error);
67
+ return null;
68
+ }
69
+ }
70
+ /**
71
+ * 执行 Bash 命令
72
+ */
73
+ async executeBash(command, options) {
74
+ if (!this.companion?.isActive()) {
75
+ throw new Error("Companion not running");
76
+ }
77
+ const scheduler = this.companion.scheduler;
78
+ return scheduler.scheduleBash({
79
+ command,
80
+ workingDir: options?.workingDir,
81
+ timeout: options?.timeout || 300,
82
+ });
83
+ }
84
+ /**
85
+ * 执行代码
86
+ */
87
+ async executeCode(code, language, options) {
88
+ if (!this.companion?.isActive()) {
89
+ throw new Error("Companion not running");
90
+ }
91
+ const scheduler = this.companion.scheduler;
92
+ return scheduler.scheduleCode({
93
+ code,
94
+ language,
95
+ timeout: options?.timeout || 300,
96
+ });
97
+ }
98
+ /**
99
+ * 创建用于 OpenVibe 扩展的工具定义
100
+ */
101
+ createTools() {
102
+ if (!this.config.enabled) {
103
+ return [];
104
+ }
105
+ const localExecuteSchema = Type.Object({
106
+ type: Type.Union([Type.Literal("bash"), Type.Literal("python"), Type.Literal("javascript"), Type.Literal("rust")], { description: "Type of execution" }),
107
+ code: Type.String({ description: "Code or command to execute" }),
108
+ workingDir: Type.Optional(Type.String({ description: "Working directory for execution" })),
109
+ timeout: Type.Optional(Type.Number({ description: "Timeout in seconds (default: 300)" })),
110
+ });
111
+ const localResourceStatusSchema = Type.Object({});
112
+ return [
113
+ {
114
+ name: "local_execute",
115
+ label: "local_execute",
116
+ description: "Execute code or commands on the local machine. Use this for tasks that require significant local resources (CPU/GPU), long-running computations, or direct file system access.",
117
+ parameters: localExecuteSchema,
118
+ execute: async (_toolCallId, args) => {
119
+ if (!this.companion?.isActive()) {
120
+ throw new Error("Local agent not running");
121
+ }
122
+ const timeout = args.timeout || 300;
123
+ if (args.type === "bash") {
124
+ const result = await this.executeBash(args.code, {
125
+ workingDir: args.workingDir,
126
+ timeout,
127
+ });
128
+ return {
129
+ content: [
130
+ { type: "text", text: result.success ? result.stdout || "" : result.error || "" },
131
+ ],
132
+ details: { exitCode: result.exitCode, stderr: result.stderr },
133
+ };
134
+ }
135
+ else {
136
+ const result = await this.executeCode(args.code, args.type, { timeout });
137
+ return {
138
+ content: [
139
+ { type: "text", text: result.success ? result.output || "" : result.error || "" },
140
+ ],
141
+ details: {},
142
+ };
143
+ }
144
+ },
145
+ },
146
+ {
147
+ name: "local_resource_status",
148
+ label: "local_resource_status",
149
+ description: "Get the current resource status of the local machine (CPU, GPU, memory, disk).",
150
+ parameters: localResourceStatusSchema,
151
+ execute: async () => {
152
+ const status = this.getLocalResourceStatus();
153
+ if (!status) {
154
+ return {
155
+ content: [{ type: "text", text: "Local agent not available" }],
156
+ details: {},
157
+ };
158
+ }
159
+ const formatBytes = (bytes) => {
160
+ const gb = bytes / (1024 * 1024 * 1024);
161
+ return `${gb.toFixed(2)} GB`;
162
+ };
163
+ const lines = [
164
+ "# Local Resource Status",
165
+ "",
166
+ "## CPU",
167
+ `- Cores: ${status.cpu?.coreCount || "N/A"}`,
168
+ `- Usage: ${status.cpu?.usagePercent.toFixed(1) || "N/A"}%`,
169
+ `- Available: ${status.cpu?.availableCores || "N/A"}`,
170
+ "",
171
+ "## Memory",
172
+ `- Total: ${status.memory?.totalMb || "N/A"} MB`,
173
+ `- Used: ${status.memory?.usedMb || "N/A"} MB`,
174
+ `- Free: ${status.memory?.freeMb || "N/A"} MB`,
175
+ `- Usage: ${status.memory?.usagePercent.toFixed(1) || "N/A"}%`,
176
+ "",
177
+ "## GPU",
178
+ `- Devices: ${status.gpu?.deviceCount || 0}`,
179
+ ];
180
+ if (status.gpu?.devices) {
181
+ for (const gpu of status.gpu.devices) {
182
+ lines.push(` - ${gpu.name}: ${gpu.memoryUsedMb}/${gpu.memoryTotalMb} MB (${gpu.memoryUsagePercent.toFixed(1)}%)`);
183
+ }
184
+ }
185
+ lines.push("");
186
+ lines.push("## Disk");
187
+ if (status.disk?.disks) {
188
+ for (const disk of status.disk.disks) {
189
+ lines.push(`- ${disk.mountPoint}: ${formatBytes(disk.usedBytes)}/${formatBytes(disk.totalBytes)} (${disk.usagePercent.toFixed(1)}%)`);
190
+ }
191
+ }
192
+ return {
193
+ content: [{ type: "text", text: lines.join("\n") }],
194
+ details: {},
195
+ };
196
+ },
197
+ },
198
+ ];
199
+ }
200
+ /**
201
+ * 获取状态信息用于展示
202
+ */
203
+ getStatus() {
204
+ return {
205
+ enabled: this.config.enabled,
206
+ connected: this.companion?.isActive() ?? false,
207
+ address: this.companion?.getAddress(),
208
+ };
209
+ }
210
+ }
211
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/hybrid-cloud/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Hybrid Cloud Integration for OpenVibe\n *\n * 直接使用内部 Companion 服务\n */\n\nimport { type Static, Type } from \"@sinclair/typebox\";\nimport type { AgentSession } from \"../agent-session.js\";\nimport type { BashResult, CodeResult } from \"../companion/index.js\";\nimport { type CompanionHttpServer, getCompanion } from \"../companion/index.js\";\nimport type { ToolDefinition } from \"../extensions/index.js\";\n\ninterface HybridCloudConfig {\n\tenabled: boolean;\n\tautoConnect: boolean;\n\toffloadThreshold: {\n\t\tcpuCores?: number;\n\t\tmemoryMb?: number;\n\t\tuseGpu?: boolean;\n\t};\n}\n\n/**\n * Hybrid Cloud Manager\n * 管理云端与本地代理的协同工作\n */\nexport class HybridCloudManager {\n\tprivate companion: CompanionHttpServer | null = null;\n\tprivate config: HybridCloudConfig;\n\n\tconstructor(_session: AgentSession, config: Partial<HybridCloudConfig> = {}) {\n\t\tthis.config = {\n\t\t\tenabled: config.enabled ?? false,\n\t\t\tautoConnect: config.autoConnect ?? true,\n\t\t\toffloadThreshold: config.offloadThreshold || {\n\t\t\t\tcpuCores: 4,\n\t\t\t\tmemoryMb: 4096,\n\t\t\t\tuseGpu: true,\n\t\t\t},\n\t\t};\n\n\t\tif (this.config.enabled) {\n\t\t\tthis.companion = getCompanion();\n\t\t}\n\t}\n\n\t/**\n\t * 检查是否应该将任务卸载到本地执行\n\t */\n\tshouldOffloadToLocal(requirements: {\n\t\testimatedCpuCores?: number;\n\t\testimatedMemoryMb?: number;\n\t\trequiresGpu?: boolean;\n\t\tisLongRunning?: boolean;\n\t}): boolean {\n\t\tif (!this.config.enabled || !this.companion?.isActive()) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst threshold = this.config.offloadThreshold;\n\n\t\tif (requirements.requiresGpu && threshold.useGpu) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif (\n\t\t\trequirements.estimatedCpuCores &&\n\t\t\tthreshold.cpuCores &&\n\t\t\trequirements.estimatedCpuCores >= threshold.cpuCores\n\t\t) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif (\n\t\t\trequirements.estimatedMemoryMb &&\n\t\t\tthreshold.memoryMb &&\n\t\t\trequirements.estimatedMemoryMb >= threshold.memoryMb\n\t\t) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif (requirements.isLongRunning) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * 获取本地资源状态\n\t */\n\tgetLocalResourceStatus() {\n\t\tif (!this.companion?.isActive()) {\n\t\t\treturn null;\n\t\t}\n\n\t\ttry {\n\t\t\treturn this.companion.getResourceStatus();\n\t\t} catch (error) {\n\t\t\tconsole.error(\"[HybridCloud] Failed to get resource status:\", error);\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/**\n\t * 执行 Bash 命令\n\t */\n\tasync executeBash(command: string, options?: { workingDir?: string; timeout?: number }): Promise<BashResult> {\n\t\tif (!this.companion?.isActive()) {\n\t\t\tthrow new Error(\"Companion not running\");\n\t\t}\n\n\t\tconst scheduler = (this.companion as any).scheduler;\n\t\treturn scheduler.scheduleBash({\n\t\t\tcommand,\n\t\t\tworkingDir: options?.workingDir,\n\t\t\ttimeout: options?.timeout || 300,\n\t\t});\n\t}\n\n\t/**\n\t * 执行代码\n\t */\n\tasync executeCode(code: string, language: string, options?: { timeout?: number }): Promise<CodeResult> {\n\t\tif (!this.companion?.isActive()) {\n\t\t\tthrow new Error(\"Companion not running\");\n\t\t}\n\n\t\tconst scheduler = (this.companion as any).scheduler;\n\t\treturn scheduler.scheduleCode({\n\t\t\tcode,\n\t\t\tlanguage,\n\t\t\ttimeout: options?.timeout || 300,\n\t\t});\n\t}\n\n\t/**\n\t * 创建用于 OpenVibe 扩展的工具定义\n\t */\n\tcreateTools(): ToolDefinition[] {\n\t\tif (!this.config.enabled) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst localExecuteSchema = Type.Object({\n\t\t\ttype: Type.Union(\n\t\t\t\t[Type.Literal(\"bash\"), Type.Literal(\"python\"), Type.Literal(\"javascript\"), Type.Literal(\"rust\")],\n\t\t\t\t{ description: \"Type of execution\" },\n\t\t\t),\n\t\t\tcode: Type.String({ description: \"Code or command to execute\" }),\n\t\t\tworkingDir: Type.Optional(Type.String({ description: \"Working directory for execution\" })),\n\t\t\ttimeout: Type.Optional(Type.Number({ description: \"Timeout in seconds (default: 300)\" })),\n\t\t});\n\n\t\tconst localResourceStatusSchema = Type.Object({});\n\n\t\treturn [\n\t\t\t{\n\t\t\t\tname: \"local_execute\",\n\t\t\t\tlabel: \"local_execute\",\n\t\t\t\tdescription:\n\t\t\t\t\t\"Execute code or commands on the local machine. Use this for tasks that require significant local resources (CPU/GPU), long-running computations, or direct file system access.\",\n\t\t\t\tparameters: localExecuteSchema,\n\t\t\t\texecute: async (_toolCallId: string, args: Static<typeof localExecuteSchema>) => {\n\t\t\t\t\tif (!this.companion?.isActive()) {\n\t\t\t\t\t\tthrow new Error(\"Local agent not running\");\n\t\t\t\t\t}\n\n\t\t\t\t\tconst timeout = args.timeout || 300;\n\n\t\t\t\t\tif (args.type === \"bash\") {\n\t\t\t\t\t\tconst result = await this.executeBash(args.code, {\n\t\t\t\t\t\t\tworkingDir: args.workingDir,\n\t\t\t\t\t\t\ttimeout,\n\t\t\t\t\t\t});\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t\t{ type: \"text\" as const, text: result.success ? result.stdout || \"\" : result.error || \"\" },\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tdetails: { exitCode: result.exitCode, stderr: result.stderr },\n\t\t\t\t\t\t};\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst result = await this.executeCode(args.code, args.type, { timeout });\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t\t{ type: \"text\" as const, text: result.success ? result.output || \"\" : result.error || \"\" },\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tdetails: {},\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"local_resource_status\",\n\t\t\t\tlabel: \"local_resource_status\",\n\t\t\t\tdescription: \"Get the current resource status of the local machine (CPU, GPU, memory, disk).\",\n\t\t\t\tparameters: localResourceStatusSchema,\n\t\t\t\texecute: async () => {\n\t\t\t\t\tconst status = this.getLocalResourceStatus();\n\t\t\t\t\tif (!status) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tcontent: [{ type: \"text\" as const, text: \"Local agent not available\" }],\n\t\t\t\t\t\t\tdetails: {},\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\tconst formatBytes = (bytes: number) => {\n\t\t\t\t\t\tconst gb = bytes / (1024 * 1024 * 1024);\n\t\t\t\t\t\treturn `${gb.toFixed(2)} GB`;\n\t\t\t\t\t};\n\n\t\t\t\t\tconst lines = [\n\t\t\t\t\t\t\"# Local Resource Status\",\n\t\t\t\t\t\t\"\",\n\t\t\t\t\t\t\"## CPU\",\n\t\t\t\t\t\t`- Cores: ${status.cpu?.coreCount || \"N/A\"}`,\n\t\t\t\t\t\t`- Usage: ${status.cpu?.usagePercent.toFixed(1) || \"N/A\"}%`,\n\t\t\t\t\t\t`- Available: ${status.cpu?.availableCores || \"N/A\"}`,\n\t\t\t\t\t\t\"\",\n\t\t\t\t\t\t\"## Memory\",\n\t\t\t\t\t\t`- Total: ${status.memory?.totalMb || \"N/A\"} MB`,\n\t\t\t\t\t\t`- Used: ${status.memory?.usedMb || \"N/A\"} MB`,\n\t\t\t\t\t\t`- Free: ${status.memory?.freeMb || \"N/A\"} MB`,\n\t\t\t\t\t\t`- Usage: ${status.memory?.usagePercent.toFixed(1) || \"N/A\"}%`,\n\t\t\t\t\t\t\"\",\n\t\t\t\t\t\t\"## GPU\",\n\t\t\t\t\t\t`- Devices: ${status.gpu?.deviceCount || 0}`,\n\t\t\t\t\t];\n\n\t\t\t\t\tif (status.gpu?.devices) {\n\t\t\t\t\t\tfor (const gpu of status.gpu.devices) {\n\t\t\t\t\t\t\tlines.push(\n\t\t\t\t\t\t\t\t` - ${gpu.name}: ${gpu.memoryUsedMb}/${gpu.memoryTotalMb} MB (${gpu.memoryUsagePercent.toFixed(1)}%)`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tlines.push(\"\");\n\t\t\t\t\tlines.push(\"## Disk\");\n\n\t\t\t\t\tif (status.disk?.disks) {\n\t\t\t\t\t\tfor (const disk of status.disk.disks) {\n\t\t\t\t\t\t\tlines.push(\n\t\t\t\t\t\t\t\t`- ${disk.mountPoint}: ${formatBytes(disk.usedBytes)}/${formatBytes(disk.totalBytes)} (${disk.usagePercent.toFixed(1)}%)`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: [{ type: \"text\" as const, text: lines.join(\"\\n\") }],\n\t\t\t\t\t\tdetails: {},\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t},\n\t\t];\n\t}\n\n\t/**\n\t * 获取状态信息用于展示\n\t */\n\tgetStatus() {\n\t\treturn {\n\t\t\tenabled: this.config.enabled,\n\t\t\tconnected: this.companion?.isActive() ?? false,\n\t\t\taddress: this.companion?.getAddress(),\n\t\t};\n\t}\n}\n\nexport type { HybridCloudConfig };\n"]}
@@ -1,5 +1,5 @@
1
1
  import { type EditorAction, type KeyId } from "@boxiaolanya2008/pi-tui";
2
- export type AppAction = "interrupt" | "clear" | "exit" | "suspend" | "cycleThinkingLevel" | "cycleModelForward" | "cycleModelBackward" | "selectModel" | "expandTools" | "toggleThinking" | "toggleSessionNamedFilter" | "externalEditor" | "followUp" | "dequeue" | "pasteImage" | "newSession" | "tree" | "fork" | "resume";
2
+ export type AppAction = "interrupt" | "clear" | "exit" | "suspend" | "cycleMode" | "cycleThinkingLevel" | "cycleModelForward" | "cycleModelBackward" | "selectModel" | "expandTools" | "toggleThinking" | "toggleSessionNamedFilter" | "externalEditor" | "followUp" | "dequeue" | "pasteImage" | "newSession" | "tree" | "fork" | "resume";
3
3
  export type KeyAction = AppAction | EditorAction;
4
4
  export type KeybindingsConfig = {
5
5
  [K in KeyAction]?: KeyId | KeyId[];
@@ -1 +1 @@
1
- {"version":3,"file":"keybindings.d.ts","sourceRoot":"","sources":["../../src/core/keybindings.ts"],"names":[],"mappings":"AAAA,OAAO,EAEN,KAAK,YAAY,EAGjB,KAAK,KAAK,EAGV,MAAM,yBAAyB,CAAC;AAIjC,MAAM,MAAM,SAAS,GAClB,WAAW,GACX,OAAO,GACP,MAAM,GACN,SAAS,GACT,oBAAoB,GACpB,mBAAmB,GACnB,oBAAoB,GACpB,aAAa,GACb,aAAa,GACb,gBAAgB,GAChB,0BAA0B,GAC1B,gBAAgB,GAChB,UAAU,GACV,SAAS,GACT,YAAY,GACZ,YAAY,GACZ,MAAM,GACN,MAAM,GACN,QAAQ,CAAC;AACZ,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,YAAY,CAAC;AACjD,MAAM,MAAM,iBAAiB,GAAG;KAC9B,CAAC,IAAI,SAAS,CAAC,CAAC,EAAE,KAAK,GAAG,KAAK,EAAE;CAClC,CAAC;AACF,eAAO,MAAM,uBAAuB,EAAE,MAAM,CAAC,SAAS,EAAE,KAAK,GAAG,KAAK,EAAE,CAoBtE,CAAC;AACF,eAAO,MAAM,mBAAmB,EAAE,QAAQ,CAAC,iBAAiB,CAG3D,CAAC;AAyBF,qBAAa,kBAAkB;IAC9B,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,eAAe,CAA0B;IACjD,OAAO,eAIN;IACD,MAAM,CAAC,MAAM,CAAC,QAAQ,GAAE,MAAsB,GAAG,kBAAkB,CAYlE;IACD,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAE,iBAAsB,GAAG,kBAAkB,CAElE;IACD,OAAO,CAAC,MAAM,CAAC,YAAY;IAQ3B,OAAO,CAAC,SAAS;IAYjB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,GAAG,OAAO,CAOhD;IACD,OAAO,CAAC,MAAM,EAAE,SAAS,GAAG,KAAK,EAAE,CAElC;IACD,kBAAkB,IAAI,QAAQ,CAAC,iBAAiB,CAAC,CAQhD;CACD;AACD,YAAY,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC","sourcesContent":["import {\n\tDEFAULT_EDITOR_KEYBINDINGS,\n\ttype EditorAction,\n\ttype EditorKeybindingsConfig,\n\tEditorKeybindingsManager,\n\ttype KeyId,\n\tmatchesKey,\n\tsetEditorKeybindings,\n} from \"@boxiaolanya2008/pi-tui\";\nimport { existsSync, readFileSync } from \"fs\";\nimport { join } from \"path\";\nimport { getAgentDir } from \"../config.js\";\nexport type AppAction =\n\t| \"interrupt\"\n\t| \"clear\"\n\t| \"exit\"\n\t| \"suspend\"\n\t| \"cycleThinkingLevel\"\n\t| \"cycleModelForward\"\n\t| \"cycleModelBackward\"\n\t| \"selectModel\"\n\t| \"expandTools\"\n\t| \"toggleThinking\"\n\t| \"toggleSessionNamedFilter\"\n\t| \"externalEditor\"\n\t| \"followUp\"\n\t| \"dequeue\"\n\t| \"pasteImage\"\n\t| \"newSession\"\n\t| \"tree\"\n\t| \"fork\"\n\t| \"resume\";\nexport type KeyAction = AppAction | EditorAction;\nexport type KeybindingsConfig = {\n\t[K in KeyAction]?: KeyId | KeyId[];\n};\nexport const DEFAULT_APP_KEYBINDINGS: Record<AppAction, KeyId | KeyId[]> = {\n\tinterrupt: \"escape\",\n\tclear: \"ctrl+c\",\n\texit: \"ctrl+d\",\n\tsuspend: \"ctrl+z\",\n\tcycleThinkingLevel: \"shift+tab\",\n\tcycleModelForward: \"ctrl+p\",\n\tcycleModelBackward: \"shift+ctrl+p\",\n\tselectModel: \"ctrl+l\",\n\texpandTools: \"ctrl+o\",\n\ttoggleThinking: \"ctrl+t\",\n\ttoggleSessionNamedFilter: \"ctrl+n\",\n\texternalEditor: \"ctrl+g\",\n\tfollowUp: \"alt+enter\",\n\tdequeue: \"alt+up\",\n\tpasteImage: process.platform === \"win32\" ? \"alt+v\" : \"ctrl+v\",\n\tnewSession: [],\n\ttree: [],\n\tfork: [],\n\tresume: [],\n};\nexport const DEFAULT_KEYBINDINGS: Required<KeybindingsConfig> = {\n\t...DEFAULT_EDITOR_KEYBINDINGS,\n\t...DEFAULT_APP_KEYBINDINGS,\n};\nconst APP_ACTIONS: AppAction[] = [\n\t\"interrupt\",\n\t\"clear\",\n\t\"exit\",\n\t\"suspend\",\n\t\"cycleThinkingLevel\",\n\t\"cycleModelForward\",\n\t\"cycleModelBackward\",\n\t\"selectModel\",\n\t\"expandTools\",\n\t\"toggleThinking\",\n\t\"toggleSessionNamedFilter\",\n\t\"externalEditor\",\n\t\"followUp\",\n\t\"dequeue\",\n\t\"pasteImage\",\n\t\"newSession\",\n\t\"tree\",\n\t\"fork\",\n\t\"resume\",\n];\nfunction isAppAction(action: string): action is AppAction {\n\treturn APP_ACTIONS.includes(action as AppAction);\n}\nexport class KeybindingsManager {\n\tprivate config: KeybindingsConfig;\n\tprivate appActionToKeys: Map<AppAction, KeyId[]>;\n\tprivate constructor(config: KeybindingsConfig) {\n\t\tthis.config = config;\n\t\tthis.appActionToKeys = new Map();\n\t\tthis.buildMaps();\n\t}\n\tstatic create(agentDir: string = getAgentDir()): KeybindingsManager {\n\t\tconst configPath = join(agentDir, \"keybindings.json\");\n\t\tconst config = KeybindingsManager.loadFromFile(configPath);\n\t\tconst manager = new KeybindingsManager(config);\n\t\tconst editorConfig: EditorKeybindingsConfig = {};\n\t\tfor (const [action, keys] of Object.entries(config)) {\n\t\t\tif (!isAppAction(action) || action === \"expandTools\") {\n\t\t\t\teditorConfig[action as EditorAction] = keys;\n\t\t\t}\n\t\t}\n\t\tsetEditorKeybindings(new EditorKeybindingsManager(editorConfig));\n\t\treturn manager;\n\t}\n\tstatic inMemory(config: KeybindingsConfig = {}): KeybindingsManager {\n\t\treturn new KeybindingsManager(config);\n\t}\n\tprivate static loadFromFile(path: string): KeybindingsConfig {\n\t\tif (!existsSync(path)) return {};\n\t\ttry {\n\t\t\treturn JSON.parse(readFileSync(path, \"utf-8\"));\n\t\t} catch {\n\t\t\treturn {};\n\t\t}\n\t}\n\tprivate buildMaps(): void {\n\t\tthis.appActionToKeys.clear();\n\t\tfor (const [action, keys] of Object.entries(DEFAULT_APP_KEYBINDINGS)) {\n\t\t\tconst keyArray = Array.isArray(keys) ? keys : [keys];\n\t\t\tthis.appActionToKeys.set(action as AppAction, [...keyArray]);\n\t\t}\n\t\tfor (const [action, keys] of Object.entries(this.config)) {\n\t\t\tif (keys === undefined || !isAppAction(action)) continue;\n\t\t\tconst keyArray = Array.isArray(keys) ? keys : [keys];\n\t\t\tthis.appActionToKeys.set(action, keyArray);\n\t\t}\n\t}\n\tmatches(data: string, action: AppAction): boolean {\n\t\tconst keys = this.appActionToKeys.get(action);\n\t\tif (!keys) return false;\n\t\tfor (const key of keys) {\n\t\t\tif (matchesKey(data, key)) return true;\n\t\t}\n\t\treturn false;\n\t}\n\tgetKeys(action: AppAction): KeyId[] {\n\t\treturn this.appActionToKeys.get(action) ?? [];\n\t}\n\tgetEffectiveConfig(): Required<KeybindingsConfig> {\n\t\tconst result = { ...DEFAULT_KEYBINDINGS };\n\t\tfor (const [action, keys] of Object.entries(this.config)) {\n\t\t\tif (keys !== undefined) {\n\t\t\t\t(result as KeybindingsConfig)[action as KeyAction] = keys;\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n}\nexport type { EditorAction, KeyId };\n"]}
1
+ {"version":3,"file":"keybindings.d.ts","sourceRoot":"","sources":["../../src/core/keybindings.ts"],"names":[],"mappings":"AAAA,OAAO,EAEN,KAAK,YAAY,EAGjB,KAAK,KAAK,EAGV,MAAM,yBAAyB,CAAC;AAIjC,MAAM,MAAM,SAAS,GAClB,WAAW,GACX,OAAO,GACP,MAAM,GACN,SAAS,GACT,WAAW,GACX,oBAAoB,GACpB,mBAAmB,GACnB,oBAAoB,GACpB,aAAa,GACb,aAAa,GACb,gBAAgB,GAChB,0BAA0B,GAC1B,gBAAgB,GAChB,UAAU,GACV,SAAS,GACT,YAAY,GACZ,YAAY,GACZ,MAAM,GACN,MAAM,GACN,QAAQ,CAAC;AACZ,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,YAAY,CAAC;AACjD,MAAM,MAAM,iBAAiB,GAAG;KAC9B,CAAC,IAAI,SAAS,CAAC,CAAC,EAAE,KAAK,GAAG,KAAK,EAAE;CAClC,CAAC;AACF,eAAO,MAAM,uBAAuB,EAAE,MAAM,CAAC,SAAS,EAAE,KAAK,GAAG,KAAK,EAAE,CAqBtE,CAAC;AACF,eAAO,MAAM,mBAAmB,EAAE,QAAQ,CAAC,iBAAiB,CAG3D,CAAC;AA0BF,qBAAa,kBAAkB;IAC9B,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,eAAe,CAA0B;IACjD,OAAO,eAIN;IACD,MAAM,CAAC,MAAM,CAAC,QAAQ,GAAE,MAAsB,GAAG,kBAAkB,CAYlE;IACD,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAE,iBAAsB,GAAG,kBAAkB,CAElE;IACD,OAAO,CAAC,MAAM,CAAC,YAAY;IAQ3B,OAAO,CAAC,SAAS;IAYjB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,GAAG,OAAO,CAOhD;IACD,OAAO,CAAC,MAAM,EAAE,SAAS,GAAG,KAAK,EAAE,CAElC;IACD,kBAAkB,IAAI,QAAQ,CAAC,iBAAiB,CAAC,CAQhD;CACD;AACD,YAAY,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC","sourcesContent":["import {\n\tDEFAULT_EDITOR_KEYBINDINGS,\n\ttype EditorAction,\n\ttype EditorKeybindingsConfig,\n\tEditorKeybindingsManager,\n\ttype KeyId,\n\tmatchesKey,\n\tsetEditorKeybindings,\n} from \"@boxiaolanya2008/pi-tui\";\nimport { existsSync, readFileSync } from \"fs\";\nimport { join } from \"path\";\nimport { getAgentDir } from \"../config.js\";\nexport type AppAction =\n\t| \"interrupt\"\n\t| \"clear\"\n\t| \"exit\"\n\t| \"suspend\"\n\t| \"cycleMode\"\n\t| \"cycleThinkingLevel\"\n\t| \"cycleModelForward\"\n\t| \"cycleModelBackward\"\n\t| \"selectModel\"\n\t| \"expandTools\"\n\t| \"toggleThinking\"\n\t| \"toggleSessionNamedFilter\"\n\t| \"externalEditor\"\n\t| \"followUp\"\n\t| \"dequeue\"\n\t| \"pasteImage\"\n\t| \"newSession\"\n\t| \"tree\"\n\t| \"fork\"\n\t| \"resume\";\nexport type KeyAction = AppAction | EditorAction;\nexport type KeybindingsConfig = {\n\t[K in KeyAction]?: KeyId | KeyId[];\n};\nexport const DEFAULT_APP_KEYBINDINGS: Record<AppAction, KeyId | KeyId[]> = {\n\tinterrupt: \"escape\",\n\tclear: \"ctrl+c\",\n\texit: \"ctrl+d\",\n\tsuspend: \"ctrl+z\",\n\tcycleMode: \"shift+tab\",\n\tcycleThinkingLevel: [],\n\tcycleModelForward: \"ctrl+p\",\n\tcycleModelBackward: \"shift+ctrl+p\",\n\tselectModel: \"ctrl+l\",\n\texpandTools: \"ctrl+o\",\n\ttoggleThinking: \"ctrl+t\",\n\ttoggleSessionNamedFilter: \"ctrl+n\",\n\texternalEditor: \"ctrl+g\",\n\tfollowUp: \"alt+enter\",\n\tdequeue: \"alt+up\",\n\tpasteImage: process.platform === \"win32\" ? \"alt+v\" : \"ctrl+v\",\n\tnewSession: [],\n\ttree: [],\n\tfork: [],\n\tresume: [],\n};\nexport const DEFAULT_KEYBINDINGS: Required<KeybindingsConfig> = {\n\t...DEFAULT_EDITOR_KEYBINDINGS,\n\t...DEFAULT_APP_KEYBINDINGS,\n};\nconst APP_ACTIONS: AppAction[] = [\n\t\"interrupt\",\n\t\"clear\",\n\t\"exit\",\n\t\"suspend\",\n\t\"cycleMode\",\n\t\"cycleThinkingLevel\",\n\t\"cycleModelForward\",\n\t\"cycleModelBackward\",\n\t\"selectModel\",\n\t\"expandTools\",\n\t\"toggleThinking\",\n\t\"toggleSessionNamedFilter\",\n\t\"externalEditor\",\n\t\"followUp\",\n\t\"dequeue\",\n\t\"pasteImage\",\n\t\"newSession\",\n\t\"tree\",\n\t\"fork\",\n\t\"resume\",\n];\nfunction isAppAction(action: string): action is AppAction {\n\treturn APP_ACTIONS.includes(action as AppAction);\n}\nexport class KeybindingsManager {\n\tprivate config: KeybindingsConfig;\n\tprivate appActionToKeys: Map<AppAction, KeyId[]>;\n\tprivate constructor(config: KeybindingsConfig) {\n\t\tthis.config = config;\n\t\tthis.appActionToKeys = new Map();\n\t\tthis.buildMaps();\n\t}\n\tstatic create(agentDir: string = getAgentDir()): KeybindingsManager {\n\t\tconst configPath = join(agentDir, \"keybindings.json\");\n\t\tconst config = KeybindingsManager.loadFromFile(configPath);\n\t\tconst manager = new KeybindingsManager(config);\n\t\tconst editorConfig: EditorKeybindingsConfig = {};\n\t\tfor (const [action, keys] of Object.entries(config)) {\n\t\t\tif (!isAppAction(action) || action === \"expandTools\") {\n\t\t\t\teditorConfig[action as EditorAction] = keys;\n\t\t\t}\n\t\t}\n\t\tsetEditorKeybindings(new EditorKeybindingsManager(editorConfig));\n\t\treturn manager;\n\t}\n\tstatic inMemory(config: KeybindingsConfig = {}): KeybindingsManager {\n\t\treturn new KeybindingsManager(config);\n\t}\n\tprivate static loadFromFile(path: string): KeybindingsConfig {\n\t\tif (!existsSync(path)) return {};\n\t\ttry {\n\t\t\treturn JSON.parse(readFileSync(path, \"utf-8\"));\n\t\t} catch {\n\t\t\treturn {};\n\t\t}\n\t}\n\tprivate buildMaps(): void {\n\t\tthis.appActionToKeys.clear();\n\t\tfor (const [action, keys] of Object.entries(DEFAULT_APP_KEYBINDINGS)) {\n\t\t\tconst keyArray = Array.isArray(keys) ? keys : [keys];\n\t\t\tthis.appActionToKeys.set(action as AppAction, [...keyArray]);\n\t\t}\n\t\tfor (const [action, keys] of Object.entries(this.config)) {\n\t\t\tif (keys === undefined || !isAppAction(action)) continue;\n\t\t\tconst keyArray = Array.isArray(keys) ? keys : [keys];\n\t\t\tthis.appActionToKeys.set(action, keyArray);\n\t\t}\n\t}\n\tmatches(data: string, action: AppAction): boolean {\n\t\tconst keys = this.appActionToKeys.get(action);\n\t\tif (!keys) return false;\n\t\tfor (const key of keys) {\n\t\t\tif (matchesKey(data, key)) return true;\n\t\t}\n\t\treturn false;\n\t}\n\tgetKeys(action: AppAction): KeyId[] {\n\t\treturn this.appActionToKeys.get(action) ?? [];\n\t}\n\tgetEffectiveConfig(): Required<KeybindingsConfig> {\n\t\tconst result = { ...DEFAULT_KEYBINDINGS };\n\t\tfor (const [action, keys] of Object.entries(this.config)) {\n\t\t\tif (keys !== undefined) {\n\t\t\t\t(result as KeybindingsConfig)[action as KeyAction] = keys;\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n}\nexport type { EditorAction, KeyId };\n"]}
@@ -7,7 +7,8 @@ export const DEFAULT_APP_KEYBINDINGS = {
7
7
  clear: "ctrl+c",
8
8
  exit: "ctrl+d",
9
9
  suspend: "ctrl+z",
10
- cycleThinkingLevel: "shift+tab",
10
+ cycleMode: "shift+tab",
11
+ cycleThinkingLevel: [],
11
12
  cycleModelForward: "ctrl+p",
12
13
  cycleModelBackward: "shift+ctrl+p",
13
14
  selectModel: "ctrl+l",
@@ -32,6 +33,7 @@ const APP_ACTIONS = [
32
33
  "clear",
33
34
  "exit",
34
35
  "suspend",
36
+ "cycleMode",
35
37
  "cycleThinkingLevel",
36
38
  "cycleModelForward",
37
39
  "cycleModelBackward",
@@ -1 +1 @@
1
- {"version":3,"file":"keybindings.js","sourceRoot":"","sources":["../../src/core/keybindings.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,0BAA0B,EAG1B,wBAAwB,EAExB,UAAU,EACV,oBAAoB,GACpB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAC9C,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAyB3C,MAAM,CAAC,MAAM,uBAAuB,GAAuC;IAC1E,SAAS,EAAE,QAAQ;IACnB,KAAK,EAAE,QAAQ;IACf,IAAI,EAAE,QAAQ;IACd,OAAO,EAAE,QAAQ;IACjB,kBAAkB,EAAE,WAAW;IAC/B,iBAAiB,EAAE,QAAQ;IAC3B,kBAAkB,EAAE,cAAc;IAClC,WAAW,EAAE,QAAQ;IACrB,WAAW,EAAE,QAAQ;IACrB,cAAc,EAAE,QAAQ;IACxB,wBAAwB,EAAE,QAAQ;IAClC,cAAc,EAAE,QAAQ;IACxB,QAAQ,EAAE,WAAW;IACrB,OAAO,EAAE,QAAQ;IACjB,UAAU,EAAE,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ;IAC7D,UAAU,EAAE,EAAE;IACd,IAAI,EAAE,EAAE;IACR,IAAI,EAAE,EAAE;IACR,MAAM,EAAE,EAAE;CACV,CAAC;AACF,MAAM,CAAC,MAAM,mBAAmB,GAAgC;IAC/D,GAAG,0BAA0B;IAC7B,GAAG,uBAAuB;CAC1B,CAAC;AACF,MAAM,WAAW,GAAgB;IAChC,WAAW;IACX,OAAO;IACP,MAAM;IACN,SAAS;IACT,oBAAoB;IACpB,mBAAmB;IACnB,oBAAoB;IACpB,aAAa;IACb,aAAa;IACb,gBAAgB;IAChB,0BAA0B;IAC1B,gBAAgB;IAChB,UAAU;IACV,SAAS;IACT,YAAY;IACZ,YAAY;IACZ,MAAM;IACN,MAAM;IACN,QAAQ;CACR,CAAC;AACF,SAAS,WAAW,CAAC,MAAc,EAAuB;IACzD,OAAO,WAAW,CAAC,QAAQ,CAAC,MAAmB,CAAC,CAAC;AAAA,CACjD;AACD,MAAM,OAAO,kBAAkB;IACtB,MAAM,CAAoB;IAC1B,eAAe,CAA0B;IACjD,YAAoB,MAAyB,EAAE;QAC9C,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,eAAe,GAAG,IAAI,GAAG,EAAE,CAAC;QACjC,IAAI,CAAC,SAAS,EAAE,CAAC;IAAA,CACjB;IACD,MAAM,CAAC,MAAM,CAAC,QAAQ,GAAW,WAAW,EAAE,EAAsB;QACnE,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,EAAE,kBAAkB,CAAC,CAAC;QACtD,MAAM,MAAM,GAAG,kBAAkB,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC;QAC3D,MAAM,OAAO,GAAG,IAAI,kBAAkB,CAAC,MAAM,CAAC,CAAC;QAC/C,MAAM,YAAY,GAA4B,EAAE,CAAC;QACjD,KAAK,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YACrD,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,MAAM,KAAK,aAAa,EAAE,CAAC;gBACtD,YAAY,CAAC,MAAsB,CAAC,GAAG,IAAI,CAAC;YAC7C,CAAC;QACF,CAAC;QACD,oBAAoB,CAAC,IAAI,wBAAwB,CAAC,YAAY,CAAC,CAAC,CAAC;QACjE,OAAO,OAAO,CAAC;IAAA,CACf;IACD,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAsB,EAAE,EAAsB;QACnE,OAAO,IAAI,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAAA,CACtC;IACO,MAAM,CAAC,YAAY,CAAC,IAAY,EAAqB;QAC5D,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,OAAO,EAAE,CAAC;QACjC,IAAI,CAAC;YACJ,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;QAChD,CAAC;QAAC,MAAM,CAAC;YACR,OAAO,EAAE,CAAC;QACX,CAAC;IAAA,CACD;IACO,SAAS,GAAS;QACzB,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC;QAC7B,KAAK,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,uBAAuB,CAAC,EAAE,CAAC;YACtE,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YACrD,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,MAAmB,EAAE,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC;QAC9D,CAAC;QACD,KAAK,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YAC1D,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;gBAAE,SAAS;YACzD,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YACrD,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAC5C,CAAC;IAAA,CACD;IACD,OAAO,CAAC,IAAY,EAAE,MAAiB,EAAW;QACjD,MAAM,IAAI,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC9C,IAAI,CAAC,IAAI;YAAE,OAAO,KAAK,CAAC;QACxB,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACxB,IAAI,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC;gBAAE,OAAO,IAAI,CAAC;QACxC,CAAC;QACD,OAAO,KAAK,CAAC;IAAA,CACb;IACD,OAAO,CAAC,MAAiB,EAAW;QACnC,OAAO,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;IAAA,CAC9C;IACD,kBAAkB,GAAgC;QACjD,MAAM,MAAM,GAAG,EAAE,GAAG,mBAAmB,EAAE,CAAC;QAC1C,KAAK,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YAC1D,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;gBACvB,MAA4B,CAAC,MAAmB,CAAC,GAAG,IAAI,CAAC;YAC3D,CAAC;QACF,CAAC;QACD,OAAO,MAAM,CAAC;IAAA,CACd;CACD","sourcesContent":["import {\n\tDEFAULT_EDITOR_KEYBINDINGS,\n\ttype EditorAction,\n\ttype EditorKeybindingsConfig,\n\tEditorKeybindingsManager,\n\ttype KeyId,\n\tmatchesKey,\n\tsetEditorKeybindings,\n} from \"@boxiaolanya2008/pi-tui\";\nimport { existsSync, readFileSync } from \"fs\";\nimport { join } from \"path\";\nimport { getAgentDir } from \"../config.js\";\nexport type AppAction =\n\t| \"interrupt\"\n\t| \"clear\"\n\t| \"exit\"\n\t| \"suspend\"\n\t| \"cycleThinkingLevel\"\n\t| \"cycleModelForward\"\n\t| \"cycleModelBackward\"\n\t| \"selectModel\"\n\t| \"expandTools\"\n\t| \"toggleThinking\"\n\t| \"toggleSessionNamedFilter\"\n\t| \"externalEditor\"\n\t| \"followUp\"\n\t| \"dequeue\"\n\t| \"pasteImage\"\n\t| \"newSession\"\n\t| \"tree\"\n\t| \"fork\"\n\t| \"resume\";\nexport type KeyAction = AppAction | EditorAction;\nexport type KeybindingsConfig = {\n\t[K in KeyAction]?: KeyId | KeyId[];\n};\nexport const DEFAULT_APP_KEYBINDINGS: Record<AppAction, KeyId | KeyId[]> = {\n\tinterrupt: \"escape\",\n\tclear: \"ctrl+c\",\n\texit: \"ctrl+d\",\n\tsuspend: \"ctrl+z\",\n\tcycleThinkingLevel: \"shift+tab\",\n\tcycleModelForward: \"ctrl+p\",\n\tcycleModelBackward: \"shift+ctrl+p\",\n\tselectModel: \"ctrl+l\",\n\texpandTools: \"ctrl+o\",\n\ttoggleThinking: \"ctrl+t\",\n\ttoggleSessionNamedFilter: \"ctrl+n\",\n\texternalEditor: \"ctrl+g\",\n\tfollowUp: \"alt+enter\",\n\tdequeue: \"alt+up\",\n\tpasteImage: process.platform === \"win32\" ? \"alt+v\" : \"ctrl+v\",\n\tnewSession: [],\n\ttree: [],\n\tfork: [],\n\tresume: [],\n};\nexport const DEFAULT_KEYBINDINGS: Required<KeybindingsConfig> = {\n\t...DEFAULT_EDITOR_KEYBINDINGS,\n\t...DEFAULT_APP_KEYBINDINGS,\n};\nconst APP_ACTIONS: AppAction[] = [\n\t\"interrupt\",\n\t\"clear\",\n\t\"exit\",\n\t\"suspend\",\n\t\"cycleThinkingLevel\",\n\t\"cycleModelForward\",\n\t\"cycleModelBackward\",\n\t\"selectModel\",\n\t\"expandTools\",\n\t\"toggleThinking\",\n\t\"toggleSessionNamedFilter\",\n\t\"externalEditor\",\n\t\"followUp\",\n\t\"dequeue\",\n\t\"pasteImage\",\n\t\"newSession\",\n\t\"tree\",\n\t\"fork\",\n\t\"resume\",\n];\nfunction isAppAction(action: string): action is AppAction {\n\treturn APP_ACTIONS.includes(action as AppAction);\n}\nexport class KeybindingsManager {\n\tprivate config: KeybindingsConfig;\n\tprivate appActionToKeys: Map<AppAction, KeyId[]>;\n\tprivate constructor(config: KeybindingsConfig) {\n\t\tthis.config = config;\n\t\tthis.appActionToKeys = new Map();\n\t\tthis.buildMaps();\n\t}\n\tstatic create(agentDir: string = getAgentDir()): KeybindingsManager {\n\t\tconst configPath = join(agentDir, \"keybindings.json\");\n\t\tconst config = KeybindingsManager.loadFromFile(configPath);\n\t\tconst manager = new KeybindingsManager(config);\n\t\tconst editorConfig: EditorKeybindingsConfig = {};\n\t\tfor (const [action, keys] of Object.entries(config)) {\n\t\t\tif (!isAppAction(action) || action === \"expandTools\") {\n\t\t\t\teditorConfig[action as EditorAction] = keys;\n\t\t\t}\n\t\t}\n\t\tsetEditorKeybindings(new EditorKeybindingsManager(editorConfig));\n\t\treturn manager;\n\t}\n\tstatic inMemory(config: KeybindingsConfig = {}): KeybindingsManager {\n\t\treturn new KeybindingsManager(config);\n\t}\n\tprivate static loadFromFile(path: string): KeybindingsConfig {\n\t\tif (!existsSync(path)) return {};\n\t\ttry {\n\t\t\treturn JSON.parse(readFileSync(path, \"utf-8\"));\n\t\t} catch {\n\t\t\treturn {};\n\t\t}\n\t}\n\tprivate buildMaps(): void {\n\t\tthis.appActionToKeys.clear();\n\t\tfor (const [action, keys] of Object.entries(DEFAULT_APP_KEYBINDINGS)) {\n\t\t\tconst keyArray = Array.isArray(keys) ? keys : [keys];\n\t\t\tthis.appActionToKeys.set(action as AppAction, [...keyArray]);\n\t\t}\n\t\tfor (const [action, keys] of Object.entries(this.config)) {\n\t\t\tif (keys === undefined || !isAppAction(action)) continue;\n\t\t\tconst keyArray = Array.isArray(keys) ? keys : [keys];\n\t\t\tthis.appActionToKeys.set(action, keyArray);\n\t\t}\n\t}\n\tmatches(data: string, action: AppAction): boolean {\n\t\tconst keys = this.appActionToKeys.get(action);\n\t\tif (!keys) return false;\n\t\tfor (const key of keys) {\n\t\t\tif (matchesKey(data, key)) return true;\n\t\t}\n\t\treturn false;\n\t}\n\tgetKeys(action: AppAction): KeyId[] {\n\t\treturn this.appActionToKeys.get(action) ?? [];\n\t}\n\tgetEffectiveConfig(): Required<KeybindingsConfig> {\n\t\tconst result = { ...DEFAULT_KEYBINDINGS };\n\t\tfor (const [action, keys] of Object.entries(this.config)) {\n\t\t\tif (keys !== undefined) {\n\t\t\t\t(result as KeybindingsConfig)[action as KeyAction] = keys;\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n}\nexport type { EditorAction, KeyId };\n"]}
1
+ {"version":3,"file":"keybindings.js","sourceRoot":"","sources":["../../src/core/keybindings.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\tDEFAULT_EDITOR_KEYBINDINGS,\n\ttype EditorAction,\n\ttype EditorKeybindingsConfig,\n\tEditorKeybindingsManager,\n\ttype KeyId,\n\tmatchesKey,\n\tsetEditorKeybindings,\n} from \"@boxiaolanya2008/pi-tui\";\nimport { existsSync, readFileSync } from \"fs\";\nimport { join } from \"path\";\nimport { getAgentDir } from \"../config.js\";\nexport type AppAction =\n\t| \"interrupt\"\n\t| \"clear\"\n\t| \"exit\"\n\t| \"suspend\"\n\t| \"cycleMode\"\n\t| \"cycleThinkingLevel\"\n\t| \"cycleModelForward\"\n\t| \"cycleModelBackward\"\n\t| \"selectModel\"\n\t| \"expandTools\"\n\t| \"toggleThinking\"\n\t| \"toggleSessionNamedFilter\"\n\t| \"externalEditor\"\n\t| \"followUp\"\n\t| \"dequeue\"\n\t| \"pasteImage\"\n\t| \"newSession\"\n\t| \"tree\"\n\t| \"fork\"\n\t| \"resume\";\nexport type KeyAction = AppAction | EditorAction;\nexport type KeybindingsConfig = {\n\t[K in KeyAction]?: KeyId | KeyId[];\n};\nexport const DEFAULT_APP_KEYBINDINGS: Record<AppAction, KeyId | KeyId[]> = {\n\tinterrupt: \"escape\",\n\tclear: \"ctrl+c\",\n\texit: \"ctrl+d\",\n\tsuspend: \"ctrl+z\",\n\tcycleMode: \"shift+tab\",\n\tcycleThinkingLevel: [],\n\tcycleModelForward: \"ctrl+p\",\n\tcycleModelBackward: \"shift+ctrl+p\",\n\tselectModel: \"ctrl+l\",\n\texpandTools: \"ctrl+o\",\n\ttoggleThinking: \"ctrl+t\",\n\ttoggleSessionNamedFilter: \"ctrl+n\",\n\texternalEditor: \"ctrl+g\",\n\tfollowUp: \"alt+enter\",\n\tdequeue: \"alt+up\",\n\tpasteImage: process.platform === \"win32\" ? \"alt+v\" : \"ctrl+v\",\n\tnewSession: [],\n\ttree: [],\n\tfork: [],\n\tresume: [],\n};\nexport const DEFAULT_KEYBINDINGS: Required<KeybindingsConfig> = {\n\t...DEFAULT_EDITOR_KEYBINDINGS,\n\t...DEFAULT_APP_KEYBINDINGS,\n};\nconst APP_ACTIONS: AppAction[] = [\n\t\"interrupt\",\n\t\"clear\",\n\t\"exit\",\n\t\"suspend\",\n\t\"cycleMode\",\n\t\"cycleThinkingLevel\",\n\t\"cycleModelForward\",\n\t\"cycleModelBackward\",\n\t\"selectModel\",\n\t\"expandTools\",\n\t\"toggleThinking\",\n\t\"toggleSessionNamedFilter\",\n\t\"externalEditor\",\n\t\"followUp\",\n\t\"dequeue\",\n\t\"pasteImage\",\n\t\"newSession\",\n\t\"tree\",\n\t\"fork\",\n\t\"resume\",\n];\nfunction isAppAction(action: string): action is AppAction {\n\treturn APP_ACTIONS.includes(action as AppAction);\n}\nexport class KeybindingsManager {\n\tprivate config: KeybindingsConfig;\n\tprivate appActionToKeys: Map<AppAction, KeyId[]>;\n\tprivate constructor(config: KeybindingsConfig) {\n\t\tthis.config = config;\n\t\tthis.appActionToKeys = new Map();\n\t\tthis.buildMaps();\n\t}\n\tstatic create(agentDir: string = getAgentDir()): KeybindingsManager {\n\t\tconst configPath = join(agentDir, \"keybindings.json\");\n\t\tconst config = KeybindingsManager.loadFromFile(configPath);\n\t\tconst manager = new KeybindingsManager(config);\n\t\tconst editorConfig: EditorKeybindingsConfig = {};\n\t\tfor (const [action, keys] of Object.entries(config)) {\n\t\t\tif (!isAppAction(action) || action === \"expandTools\") {\n\t\t\t\teditorConfig[action as EditorAction] = keys;\n\t\t\t}\n\t\t}\n\t\tsetEditorKeybindings(new EditorKeybindingsManager(editorConfig));\n\t\treturn manager;\n\t}\n\tstatic inMemory(config: KeybindingsConfig = {}): KeybindingsManager {\n\t\treturn new KeybindingsManager(config);\n\t}\n\tprivate static loadFromFile(path: string): KeybindingsConfig {\n\t\tif (!existsSync(path)) return {};\n\t\ttry {\n\t\t\treturn JSON.parse(readFileSync(path, \"utf-8\"));\n\t\t} catch {\n\t\t\treturn {};\n\t\t}\n\t}\n\tprivate buildMaps(): void {\n\t\tthis.appActionToKeys.clear();\n\t\tfor (const [action, keys] of Object.entries(DEFAULT_APP_KEYBINDINGS)) {\n\t\t\tconst keyArray = Array.isArray(keys) ? keys : [keys];\n\t\t\tthis.appActionToKeys.set(action as AppAction, [...keyArray]);\n\t\t}\n\t\tfor (const [action, keys] of Object.entries(this.config)) {\n\t\t\tif (keys === undefined || !isAppAction(action)) continue;\n\t\t\tconst keyArray = Array.isArray(keys) ? keys : [keys];\n\t\t\tthis.appActionToKeys.set(action, keyArray);\n\t\t}\n\t}\n\tmatches(data: string, action: AppAction): boolean {\n\t\tconst keys = this.appActionToKeys.get(action);\n\t\tif (!keys) return false;\n\t\tfor (const key of keys) {\n\t\t\tif (matchesKey(data, key)) return true;\n\t\t}\n\t\treturn false;\n\t}\n\tgetKeys(action: AppAction): KeyId[] {\n\t\treturn this.appActionToKeys.get(action) ?? [];\n\t}\n\tgetEffectiveConfig(): Required<KeybindingsConfig> {\n\t\tconst result = { ...DEFAULT_KEYBINDINGS };\n\t\tfor (const [action, keys] of Object.entries(this.config)) {\n\t\t\tif (keys !== undefined) {\n\t\t\t\t(result as KeybindingsConfig)[action as KeyAction] = keys;\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n}\nexport type { EditorAction, KeyId };\n"]}