@agenthippo-ai/agenthippo 1.110.9 → 1.110.19

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 (533) hide show
  1. package/out/agentpack/types.js +2 -5
  2. package/out/analytics/dashboard/artifactManager.js +2 -439
  3. package/out/analytics/dashboard/fleetDisplayUtils.js +2 -162
  4. package/out/analytics/dashboard/fleetOrchestrator.js +3 -142
  5. package/out/analytics/dashboard/fleetRegistry.js +2 -79
  6. package/out/analytics/dashboard/fleetRowDefaults.js +2 -87
  7. package/out/analytics/dashboard/fleetScriptAdapter.js +2 -146
  8. package/out/analytics/dashboard/fleetTypes.js +2 -29
  9. package/out/analytics/dashboard/index.js +2 -17
  10. package/out/analytics/dashboard/indexingService.js +2 -422
  11. package/out/analytics/dashboard/localFleetAdapter.js +2 -222
  12. package/out/analytics/dashboard/performanceMonitor.js +5 -76
  13. package/out/analytics/dashboard/processManager.js +2 -209
  14. package/out/analytics/dashboard/provider.js +38 -3817
  15. package/out/analytics/dashboard/queryRunner.js +62 -750
  16. package/out/analytics/dashboard/scheduledFleetStorage.js +2 -241
  17. package/out/analytics/dashboard/sessionJsonlFleet.js +3 -204
  18. package/out/analytics/dashboard/teamViewDiscovery.js +2 -106
  19. package/out/analytics/dashboard/webview/panel.js +34 -2318
  20. package/out/analytics/dashboard/webview/runtime-bridge.js +2 -82
  21. package/out/analytics/lifecycle.js +2 -43
  22. package/out/analytics/service.js +8 -1277
  23. package/out/auth/authBaseUrl.js +2 -59
  24. package/out/auth/bootstrapApply.js +2 -71
  25. package/out/auth/brokerClient.js +2 -160
  26. package/out/auth/callbackUri.js +2 -59
  27. package/out/auth/githubStoreGate.js +2 -70
  28. package/out/auth/loopbackAuthServer.js +4 -159
  29. package/out/auth/onboardingPrompt.js +2 -112
  30. package/out/auth/pkce.js +2 -9
  31. package/out/auth/provider.js +2 -226
  32. package/out/auth/sessionStore.js +2 -156
  33. package/out/auth/signInFlow.js +2 -183
  34. package/out/cli/index.js +619 -551
  35. package/out/cli/run-custom-engine-runner.js +3 -318
  36. package/out/cli/vscode-shim.js +2 -86
  37. package/out/engines/factory.js +2 -45
  38. package/out/engines/types.js +2 -17
  39. package/out/examples/run-headless-repl.js +6 -286
  40. package/out/examples/run-headless.js +2 -187
  41. package/out/extension.js +32 -4473
  42. package/out/gateway/gatewayRouteIndex.js +6 -371
  43. package/out/gateway/gatewaySessionStore.js +3 -243
  44. package/out/gateway/index.js +2 -31
  45. package/out/gateway/resetMappings.js +2 -52
  46. package/out/gateway/service.js +5 -1249
  47. package/out/mcp/publish.js +2 -143
  48. package/out/remote/handleRemoteChat.js +2 -169
  49. package/out/remote/remotePackStatusBar.js +3 -103
  50. package/out/remote/remoteTrust.js +6 -277
  51. package/out/remote/serveClient.js +4 -277
  52. package/out/remoteSkills.js +3 -191
  53. package/out/runtime/index.js +2 -32
  54. package/out/runtime/vscode/index.js +2 -20
  55. package/out/runtime/vscode/vscode-config-provider.js +2 -77
  56. package/out/runtime/vscode/vscode-edit-tracker.js +2 -122
  57. package/out/runtime/vscode/vscode-logger.js +2 -30
  58. package/out/runtime/vscode/vscode-permission-handler.js +2 -72
  59. package/out/scripts/agentide-litellm.sh +0 -1
  60. package/out/scripts/agentide_litellm_hooks_v1.py +170 -418
  61. package/out/scripts/analytics/agent-fleet-widget.js +18 -257
  62. package/out/scripts/analytics/agentide-litellm-otel.config.yaml +4 -4
  63. package/out/scripts/analytics/duckdbLocator.js +2 -28
  64. package/out/scripts/analytics/generate-default-charts.py +43 -323
  65. package/out/scripts/analytics/hotspot-analysis-widget.js +4 -430
  66. package/out/scripts/analytics/index-traces.py +78 -1036
  67. package/out/scripts/analytics/session-comparison-widget.js +26 -472
  68. package/out/scripts/analytics/session-timeline-widget.js +25 -846
  69. package/out/scripts/analytics/setup-analytics.ps1 +8 -1
  70. package/out/scripts/analytics/setup-analytics.sh +13 -2
  71. package/out/scripts/analytics/token-cost-flamegraph-widget.js +4 -461
  72. package/out/scripts/analytics/token-cost-trend-widget.js +4 -534
  73. package/out/scripts/analytics/workflows-collector.cjs +4 -314
  74. package/out/scripts/analytics/workflows-daemon.mjs +9 -185
  75. package/out/scripts/analytics/workflows-widget.cjs +15 -159
  76. package/out/scripts/analytics/wow-model-widget.js +10 -120
  77. package/out/scripts/vendor-tools.mjs +2 -233
  78. package/out/skills/publish.js +3 -178
  79. package/out/store/github/setup.js +7 -212
  80. package/out/store/oramaIndex.js +2 -884
  81. package/out/sync.js +26 -1829
  82. package/out/terminalLogger.js +5 -358
  83. package/out/utils/pathSafety.js +2 -60
  84. package/out/utils/pythonRunner.js +4 -258
  85. package/out/utils/toolPath.js +2 -83
  86. package/out/workspaceFolders.js +2 -59
  87. package/package.json +1 -1
  88. package/out/agentpack/github.js +0 -547
  89. package/out/agentpack/index.js +0 -67
  90. package/out/agentpack/install.js +0 -297
  91. package/out/agentpack/manager.js +0 -441
  92. package/out/agentpack/manifest.js +0 -135
  93. package/out/agentpack/paths.js +0 -498
  94. package/out/agentpack/publish.js +0 -248
  95. package/out/agentpack/stores.js +0 -554
  96. package/out/analytics/dashboard/fleetStatusUtils.js +0 -30
  97. package/out/analytics/dashboard/fleetTitleUtils.js +0 -68
  98. package/out/analytics/dashboard/refreshPolicy.js +0 -16
  99. package/out/analytics/dashboard/scheduledFleetFingerprint.js +0 -22
  100. package/out/analytics/dashboard/scheduledFleetUtils.js +0 -22
  101. package/out/analytics/dashboard/sessionEventFleetStats.js +0 -118
  102. package/out/analytics/dashboard/viewsConfigMerge.js +0 -221
  103. package/out/analytics/dashboard/webview/codicon.ttf +0 -0
  104. package/out/analytics/identity.js +0 -0
  105. package/out/analytics/sessionEvents.js +0 -323
  106. package/out/auth/callbackUriParse.js +0 -59
  107. package/out/auth/types.js +0 -12
  108. package/out/auth-broker/config.js +0 -112
  109. package/out/auth-broker/jwt.js +0 -105
  110. package/out/auth-broker/pkce.js +0 -59
  111. package/out/auth-broker/server.js +0 -677
  112. package/out/auth-broker/store.js +0 -275
  113. package/out/authority/warrant.js +0 -206
  114. package/out/base-prompts/mcp-servers/.mcp.json +0 -13
  115. package/out/base-prompts/mcp-servers/langfuse-analytics/README.md +0 -142
  116. package/out/base-prompts/mcp-servers/langfuse-analytics/mcp.json +0 -13
  117. package/out/base-prompts/mcp-servers/langfuse-analytics/package-lock.json +0 -1192
  118. package/out/base-prompts/mcp-servers/langfuse-analytics/package.json +0 -23
  119. package/out/base-prompts/mcp-servers/langfuse-analytics/scripts/run-with-env.sh +0 -12
  120. package/out/base-prompts/mcp-servers/langfuse-analytics/scripts/sdk-test.js +0 -102
  121. package/out/base-prompts/mcp-servers/langfuse-analytics/scripts/simple-test.js +0 -137
  122. package/out/base-prompts/mcp-servers/langfuse-analytics/scripts/test-client.js +0 -118
  123. package/out/base-prompts/mcp-servers/langfuse-analytics/scripts/test-server.js +0 -209
  124. package/out/base-prompts/mcp-servers/langfuse-analytics/src/client.ts +0 -431
  125. package/out/base-prompts/mcp-servers/langfuse-analytics/src/index.ts +0 -270
  126. package/out/base-prompts/mcp-servers/langfuse-analytics/tsconfig.json +0 -18
  127. package/out/base-prompts/rules/AGENTS.md +0 -204
  128. package/out/base-prompts/skills/agent-browser/SKILL.md +0 -102
  129. package/out/base-prompts/skills/agent-builder/SKILL.md +0 -73
  130. package/out/base-prompts/skills/agent-builder/references/agent-pack.md +0 -63
  131. package/out/base-prompts/skills/agent-builder/references/crewai.md +0 -66
  132. package/out/base-prompts/skills/agent-builder/references/langchain.md +0 -60
  133. package/out/base-prompts/skills/agent-builder/references/raw-sdk.md +0 -73
  134. package/out/base-prompts/skills/agent-engine-creator/SKILL.md +0 -586
  135. package/out/base-prompts/skills/agent-engine-installer/SKILL.md +0 -106
  136. package/out/base-prompts/skills/agent-engine-installer/scripts/install-engine.mjs +0 -259
  137. package/out/base-prompts/skills/agent-engine-installer/scripts/install-engine.ps1 +0 -189
  138. package/out/base-prompts/skills/agenthippo-cli/SKILL.md +0 -69
  139. package/out/base-prompts/skills/agenthippo-cli/scripts/install.sh +0 -63
  140. package/out/base-prompts/skills/agentpack-creator/SKILL.md +0 -375
  141. package/out/base-prompts/skills/agentpack-creator/references/agent-templates.md +0 -261
  142. package/out/base-prompts/skills/agentpack-creator/references/agents-md-guide.md +0 -195
  143. package/out/base-prompts/skills/agentpack-creator/scripts/init_pack.py +0 -391
  144. package/out/base-prompts/skills/agentpack-creator/scripts/init_pack_test.py +0 -294
  145. package/out/base-prompts/skills/agentpack-testbench/SKILL.md +0 -135
  146. package/out/base-prompts/skills/algorithmic-art/LICENSE.txt +0 -202
  147. package/out/base-prompts/skills/algorithmic-art/SKILL.md +0 -405
  148. package/out/base-prompts/skills/algorithmic-art/templates/generator_template.js +0 -223
  149. package/out/base-prompts/skills/algorithmic-art/templates/viewer.html +0 -599
  150. package/out/base-prompts/skills/debug-agent/SKILL.md +0 -83
  151. package/out/base-prompts/skills/desktop-automation/SKILL.md +0 -166
  152. package/out/base-prompts/skills/desktop-automation/references/agenthippo-ui-recipes.md +0 -441
  153. package/out/base-prompts/skills/desktop-automation/scripts/windows-desktop-uia.psm1 +0 -280
  154. package/out/base-prompts/skills/docx/LICENSE.txt +0 -30
  155. package/out/base-prompts/skills/docx/SKILL.md +0 -197
  156. package/out/base-prompts/skills/docx/docx-js.md +0 -350
  157. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +0 -1499
  158. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +0 -146
  159. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +0 -1085
  160. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +0 -11
  161. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +0 -3081
  162. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +0 -23
  163. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +0 -185
  164. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +0 -287
  165. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +0 -1676
  166. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +0 -28
  167. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +0 -144
  168. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +0 -174
  169. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +0 -25
  170. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +0 -18
  171. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +0 -59
  172. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +0 -56
  173. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +0 -195
  174. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +0 -582
  175. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +0 -25
  176. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +0 -4439
  177. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +0 -570
  178. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +0 -509
  179. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +0 -12
  180. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +0 -108
  181. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +0 -96
  182. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +0 -3646
  183. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +0 -116
  184. package/out/base-prompts/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +0 -42
  185. package/out/base-prompts/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +0 -50
  186. package/out/base-prompts/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +0 -49
  187. package/out/base-prompts/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +0 -33
  188. package/out/base-prompts/skills/docx/ooxml/schemas/mce/mc.xsd +0 -75
  189. package/out/base-prompts/skills/docx/ooxml/schemas/microsoft/wml-2010.xsd +0 -560
  190. package/out/base-prompts/skills/docx/ooxml/schemas/microsoft/wml-2012.xsd +0 -67
  191. package/out/base-prompts/skills/docx/ooxml/schemas/microsoft/wml-2018.xsd +0 -14
  192. package/out/base-prompts/skills/docx/ooxml/schemas/microsoft/wml-cex-2018.xsd +0 -20
  193. package/out/base-prompts/skills/docx/ooxml/schemas/microsoft/wml-cid-2016.xsd +0 -13
  194. package/out/base-prompts/skills/docx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +0 -4
  195. package/out/base-prompts/skills/docx/ooxml/schemas/microsoft/wml-symex-2015.xsd +0 -8
  196. package/out/base-prompts/skills/docx/ooxml/scripts/pack.py +0 -159
  197. package/out/base-prompts/skills/docx/ooxml/scripts/unpack.py +0 -29
  198. package/out/base-prompts/skills/docx/ooxml/scripts/validate.py +0 -69
  199. package/out/base-prompts/skills/docx/ooxml/scripts/validation/__init__.py +0 -15
  200. package/out/base-prompts/skills/docx/ooxml/scripts/validation/base.py +0 -951
  201. package/out/base-prompts/skills/docx/ooxml/scripts/validation/docx.py +0 -274
  202. package/out/base-prompts/skills/docx/ooxml/scripts/validation/pptx.py +0 -315
  203. package/out/base-prompts/skills/docx/ooxml/scripts/validation/redlining.py +0 -279
  204. package/out/base-prompts/skills/docx/ooxml.md +0 -610
  205. package/out/base-prompts/skills/docx/scripts/__init__.py +0 -1
  206. package/out/base-prompts/skills/docx/scripts/document.py +0 -1276
  207. package/out/base-prompts/skills/docx/scripts/templates/comments.xml +0 -3
  208. package/out/base-prompts/skills/docx/scripts/templates/commentsExtended.xml +0 -3
  209. package/out/base-prompts/skills/docx/scripts/templates/commentsExtensible.xml +0 -3
  210. package/out/base-prompts/skills/docx/scripts/templates/commentsIds.xml +0 -3
  211. package/out/base-prompts/skills/docx/scripts/templates/people.xml +0 -3
  212. package/out/base-prompts/skills/docx/scripts/utilities.py +0 -374
  213. package/out/base-prompts/skills/gateway-outbound/SKILL.md +0 -136
  214. package/out/base-prompts/skills/mcp-builder/LICENSE.txt +0 -202
  215. package/out/base-prompts/skills/mcp-builder/SKILL.md +0 -328
  216. package/out/base-prompts/skills/mcp-builder/reference/evaluation.md +0 -602
  217. package/out/base-prompts/skills/mcp-builder/reference/mcp_best_practices.md +0 -249
  218. package/out/base-prompts/skills/mcp-builder/reference/node_mcp_server.md +0 -970
  219. package/out/base-prompts/skills/mcp-builder/reference/python_mcp_server.md +0 -719
  220. package/out/base-prompts/skills/mcp-builder/scripts/connections.py +0 -151
  221. package/out/base-prompts/skills/mcp-builder/scripts/evaluation.py +0 -373
  222. package/out/base-prompts/skills/mcp-builder/scripts/example_evaluation.xml +0 -22
  223. package/out/base-prompts/skills/mcp-builder/scripts/requirements.txt +0 -2
  224. package/out/base-prompts/skills/openclaw/SKILL.md +0 -406
  225. package/out/base-prompts/skills/openclaw/scripts/run-smoke.sh +0 -61
  226. package/out/base-prompts/skills/pdf/LICENSE.txt +0 -30
  227. package/out/base-prompts/skills/pdf/SKILL.md +0 -294
  228. package/out/base-prompts/skills/pdf/forms.md +0 -205
  229. package/out/base-prompts/skills/pdf/reference.md +0 -612
  230. package/out/base-prompts/skills/pdf/scripts/check_bounding_boxes.py +0 -70
  231. package/out/base-prompts/skills/pdf/scripts/check_bounding_boxes_test.py +0 -226
  232. package/out/base-prompts/skills/pdf/scripts/check_fillable_fields.py +0 -12
  233. package/out/base-prompts/skills/pdf/scripts/convert_pdf_to_images.py +0 -35
  234. package/out/base-prompts/skills/pdf/scripts/create_validation_image.py +0 -41
  235. package/out/base-prompts/skills/pdf/scripts/extract_form_field_info.py +0 -152
  236. package/out/base-prompts/skills/pdf/scripts/fill_fillable_fields.py +0 -114
  237. package/out/base-prompts/skills/pdf/scripts/fill_pdf_form_with_annotations.py +0 -108
  238. package/out/base-prompts/skills/pptx/LICENSE.txt +0 -30
  239. package/out/base-prompts/skills/pptx/SKILL.md +0 -484
  240. package/out/base-prompts/skills/pptx/html2pptx.md +0 -625
  241. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +0 -1499
  242. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +0 -146
  243. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +0 -1085
  244. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +0 -11
  245. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +0 -3081
  246. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +0 -23
  247. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +0 -185
  248. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +0 -287
  249. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +0 -1676
  250. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +0 -28
  251. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +0 -144
  252. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +0 -174
  253. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +0 -25
  254. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +0 -18
  255. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +0 -59
  256. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +0 -56
  257. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +0 -195
  258. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +0 -582
  259. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +0 -25
  260. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +0 -4439
  261. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +0 -570
  262. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +0 -509
  263. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +0 -12
  264. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +0 -108
  265. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +0 -96
  266. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +0 -3646
  267. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +0 -116
  268. package/out/base-prompts/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +0 -42
  269. package/out/base-prompts/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +0 -50
  270. package/out/base-prompts/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +0 -49
  271. package/out/base-prompts/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +0 -33
  272. package/out/base-prompts/skills/pptx/ooxml/schemas/mce/mc.xsd +0 -75
  273. package/out/base-prompts/skills/pptx/ooxml/schemas/microsoft/wml-2010.xsd +0 -560
  274. package/out/base-prompts/skills/pptx/ooxml/schemas/microsoft/wml-2012.xsd +0 -67
  275. package/out/base-prompts/skills/pptx/ooxml/schemas/microsoft/wml-2018.xsd +0 -14
  276. package/out/base-prompts/skills/pptx/ooxml/schemas/microsoft/wml-cex-2018.xsd +0 -20
  277. package/out/base-prompts/skills/pptx/ooxml/schemas/microsoft/wml-cid-2016.xsd +0 -13
  278. package/out/base-prompts/skills/pptx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +0 -4
  279. package/out/base-prompts/skills/pptx/ooxml/schemas/microsoft/wml-symex-2015.xsd +0 -8
  280. package/out/base-prompts/skills/pptx/ooxml/scripts/pack.py +0 -159
  281. package/out/base-prompts/skills/pptx/ooxml/scripts/unpack.py +0 -29
  282. package/out/base-prompts/skills/pptx/ooxml/scripts/validate.py +0 -69
  283. package/out/base-prompts/skills/pptx/ooxml/scripts/validation/__init__.py +0 -15
  284. package/out/base-prompts/skills/pptx/ooxml/scripts/validation/base.py +0 -951
  285. package/out/base-prompts/skills/pptx/ooxml/scripts/validation/docx.py +0 -274
  286. package/out/base-prompts/skills/pptx/ooxml/scripts/validation/pptx.py +0 -315
  287. package/out/base-prompts/skills/pptx/ooxml/scripts/validation/redlining.py +0 -279
  288. package/out/base-prompts/skills/pptx/ooxml.md +0 -427
  289. package/out/base-prompts/skills/pptx/scripts/html2pptx.js +0 -984
  290. package/out/base-prompts/skills/pptx/scripts/inventory.py +0 -1020
  291. package/out/base-prompts/skills/pptx/scripts/rearrange.py +0 -231
  292. package/out/base-prompts/skills/pptx/scripts/replace.py +0 -385
  293. package/out/base-prompts/skills/pptx/scripts/thumbnail.py +0 -450
  294. package/out/base-prompts/skills/prompt-lab/SKILL.md +0 -149
  295. package/out/base-prompts/skills/prompt-lab/scripts/query-analytics.sh +0 -2551
  296. package/out/base-prompts/skills/skill-creator/LICENSE.txt +0 -202
  297. package/out/base-prompts/skills/skill-creator/SKILL.md +0 -371
  298. package/out/base-prompts/skills/skill-creator/references/output-patterns.md +0 -82
  299. package/out/base-prompts/skills/skill-creator/references/workflows.md +0 -28
  300. package/out/base-prompts/skills/skill-creator/scripts/init_skill.py +0 -303
  301. package/out/base-prompts/skills/skill-creator/scripts/package_skill.py +0 -110
  302. package/out/base-prompts/skills/skill-creator/scripts/quick_validate.py +0 -95
  303. package/out/base-prompts/skills/skill-installer/SKILL.md +0 -251
  304. package/out/base-prompts/skills/skill-installer/references/store-api.md +0 -219
  305. package/out/base-prompts/skills/spotlight-dashboard/SKILL.md +0 -83
  306. package/out/base-prompts/skills/spotlight-insights/SKILL.md +0 -101
  307. package/out/base-prompts/skills/spotlight-optimize/SKILL.md +0 -93
  308. package/out/base-prompts/skills/spotlight-optimize/scripts/query-analytics.sh +0 -2551
  309. package/out/base-prompts/skills/spotlight-query/SKILL.md +0 -314
  310. package/out/base-prompts/skills/spotlight-query/references/otel-schema.md +0 -163
  311. package/out/base-prompts/skills/spotlight-query/scripts/query-analytics.sh +0 -2551
  312. package/out/base-prompts/skills/spotlight-query/scripts/query-analytics.test.sh +0 -744
  313. package/out/base-prompts/skills/spotlight-query/scripts/test-fixtures/analytics/sessions/sess-test-1.jsonl +0 -14
  314. package/out/base-prompts/skills/spotlight-query/scripts/test-fixtures/analytics/traces/.duckdb-index.json +0 -7
  315. package/out/base-prompts/skills/spotlight-query/scripts/test-fixtures/analytics/traces/sample.jsonl +0 -5
  316. package/out/base-prompts/skills/spotlight-report/SKILL.md +0 -86
  317. package/out/base-prompts/skills/spotlight-visualize/SKILL.md +0 -92
  318. package/out/base-prompts/skills/spotlight-visualize/scripts/query-analytics.sh +0 -2551
  319. package/out/base-prompts/skills/xlsx/LICENSE.txt +0 -30
  320. package/out/base-prompts/skills/xlsx/SKILL.md +0 -289
  321. package/out/base-prompts/skills/xlsx/recalc.py +0 -178
  322. package/out/branding.js +0 -49
  323. package/out/cli/commands/anywhere.js +0 -66
  324. package/out/cli/commands/ask.js +0 -246
  325. package/out/cli/commands/auth-broker.js +0 -24
  326. package/out/cli/commands/auth.js +0 -219
  327. package/out/cli/commands/chat.js +0 -357
  328. package/out/cli/commands/conformance.js +0 -249
  329. package/out/cli/commands/data-plane.js +0 -67
  330. package/out/cli/commands/deploy.js +0 -263
  331. package/out/cli/commands/gateway.js +0 -218
  332. package/out/cli/commands/idp.js +0 -85
  333. package/out/cli/commands/pack.js +0 -399
  334. package/out/cli/commands/probe-custom-engine.js +0 -82
  335. package/out/cli/commands/sandbox.js +0 -332
  336. package/out/cli/commands/serve.js +0 -1758
  337. package/out/cli/commands/store.js +0 -927
  338. package/out/cli/credential-context.js +0 -91
  339. package/out/cli/data-plane/broker.js +0 -78
  340. package/out/cli/data-plane/connector-host.js +0 -121
  341. package/out/cli/data-plane/egress.js +0 -189
  342. package/out/cli/data-plane/gateway.js +0 -218
  343. package/out/cli/data-plane/index.js +0 -152
  344. package/out/cli/data-plane/registry.js +0 -89
  345. package/out/cli/data-plane/remote.js +0 -106
  346. package/out/cli/data-plane/sidecar.js +0 -161
  347. package/out/cli/deploy/blueprints/registry.js +0 -84
  348. package/out/cli/deploy/layers/identity.js +0 -172
  349. package/out/cli/deploy-init.js +0 -3023
  350. package/out/cli/deps.js +0 -342
  351. package/out/cli/idp-init.js +0 -338
  352. package/out/cli/pack-install-ref.js +0 -15
  353. package/out/cli/pack-loader.js +0 -418
  354. package/out/cli/pack-runtime.js +0 -61
  355. package/out/cli/runtime.js +0 -450
  356. package/out/cli/serve-hardening.js +0 -607
  357. package/out/cli/state-sync.js +0 -424
  358. package/out/cli/utils.js +0 -231
  359. package/out/engines/base.js +0 -188
  360. package/out/engines/claude.js +0 -1254
  361. package/out/engines/codex.js +0 -862
  362. package/out/engines/custom.js +0 -674
  363. package/out/engines/customEngineIpc.js +0 -95
  364. package/out/engines/customEngineRunnerEmbed.js +0 -107
  365. package/out/engines/customRegistry.js +0 -274
  366. package/out/engines/embeddedCustomEngineRunner.generated.js +0 -9
  367. package/out/engines/engineApiKey.js +0 -138
  368. package/out/engines/install.js +0 -372
  369. package/out/engines/persistentEngineWorker.js +0 -320
  370. package/out/engines/publish.js +0 -341
  371. package/out/evidence/sessionShip.js +0 -610
  372. package/out/gateway/bridge.js +0 -843
  373. package/out/gateway/cli-agent-id.js +0 -36
  374. package/out/gateway/client.js +0 -336
  375. package/out/gateway/client.test.js +0 -395
  376. package/out/gateway/gateway-scope-errors.js +0 -14
  377. package/out/gateway/gatewayBackup.js +0 -76
  378. package/out/gateway/installSource.js +0 -68
  379. package/out/gateway/lifecycle.js +0 -3190
  380. package/out/gateway/openclaw-channel-routing.js +0 -317
  381. package/out/gateway/outboundHandles.js +0 -373
  382. package/out/gateway/outboundPaths.js +0 -75
  383. package/out/gateway/outboundSend.js +0 -254
  384. package/out/gateway/protocol.js +0 -48
  385. package/out/gateway/secretsPreflight.js +0 -90
  386. package/out/gateway/sessionRouting.js +0 -77
  387. package/out/headless/index.js +0 -539
  388. package/out/headless/sync.js +0 -473
  389. package/out/live-e2e/mcp-demo/server.mjs +0 -32
  390. package/out/live-probe/connector.mjs +0 -8
  391. package/out/live-probe/env-report.mjs +0 -8
  392. package/out/mcp.js +0 -654
  393. package/out/pack/caps.js +0 -271
  394. package/out/pack/governor.js +0 -309
  395. package/out/pack/lease-schema.js +0 -270
  396. package/out/pack/lease.js +0 -640
  397. package/out/pack/reconcile.js +0 -217
  398. package/out/pack/signature.js +0 -839
  399. package/out/permissions.js +0 -108
  400. package/out/permissions.mapping.yaml +0 -68
  401. package/out/registry/index.js +0 -332
  402. package/out/runner/host.js +0 -131
  403. package/out/runner/protocol.js +0 -108
  404. package/out/runner/remoteEngine.js +0 -130
  405. package/out/runtime/interfaces/config-provider.js +0 -32
  406. package/out/runtime/interfaces/edit-tracker.js +0 -24
  407. package/out/runtime/interfaces/index.js +0 -29
  408. package/out/runtime/interfaces/logger.js +0 -40
  409. package/out/runtime/interfaces/permission-handler.js +0 -66
  410. package/out/runtime/interfaces/session-store.js +0 -342
  411. package/out/runtime/vscode/vscode-session-store.js +0 -22
  412. package/out/sandbox/containerDriver.js +0 -570
  413. package/out/sandbox/processDriver.js +0 -315
  414. package/out/sandbox/sandboxRunner.js +0 -191
  415. package/out/sandbox/support.js +0 -301
  416. package/out/sandbox/types.js +0 -55
  417. package/out/scripts/analytics/fleet-local-adapter.js +0 -246
  418. package/out/scripts/analytics/live-fleet-4-collector.cjs +0 -315
  419. package/out/scripts/analytics/live-fleet-4-daemon.mjs +0 -134
  420. package/out/scripts/analytics/live-fleet-4-widget.cjs +0 -433
  421. package/out/scripts/gateway/Dockerfile.serve +0 -45
  422. package/out/scripts/gateway/docker-serve.sh +0 -248
  423. package/out/scripts/gateway/setup-gateway-server.ps1 +0 -953
  424. package/out/scripts/gateway/setup-gateway-server.sh +0 -935
  425. package/out/session.js +0 -272
  426. package/out/shared/agentEngines.js +0 -170
  427. package/out/shared/index.js +0 -109
  428. package/out/shared/models.js +0 -136
  429. package/out/shared/providers.js +0 -205
  430. package/out/spotlight/install.js +0 -345
  431. package/out/spotlight/publish.js +0 -544
  432. package/out/spotlight/yaml.js +0 -31
  433. package/out/store/index.js +0 -786
  434. package/out/store/shared.js +0 -241
  435. package/out/test/agentEnvFile.test.js +0 -97
  436. package/out/test/agentYaml.test.js +0 -373
  437. package/out/test/agentpack.test.js +0 -639
  438. package/out/test/analytics-lifecycle.test.js +0 -174
  439. package/out/test/analytics.test.js +0 -756
  440. package/out/test/auth-baseurl.test.js +0 -132
  441. package/out/test/auth-bootstrapApply.test.js +0 -123
  442. package/out/test/auth-broker-hardening.test.js +0 -227
  443. package/out/test/auth-broker.test.js +0 -541
  444. package/out/test/auth-callback.test.js +0 -62
  445. package/out/test/blueprint-registry.test.js +0 -105
  446. package/out/test/branding.test.js +0 -242
  447. package/out/test/caps-governor.test.js +0 -455
  448. package/out/test/cli-agent-id.test.js +0 -55
  449. package/out/test/codex-new-file-survival.test.js +0 -119
  450. package/out/test/configuration-scopes.test.js +0 -131
  451. package/out/test/credential-context.test.js +0 -160
  452. package/out/test/custom-env-layering.test.js +0 -151
  453. package/out/test/customEngineInstall.test.js +0 -100
  454. package/out/test/customRegistry.test.js +0 -122
  455. package/out/test/data-plane-engine-wiring.test.js +0 -250
  456. package/out/test/data-plane.test.js +0 -311
  457. package/out/test/deploy-init.test.js +0 -854
  458. package/out/test/deps-auto-install.test.js +0 -81
  459. package/out/test/egress-broker.test.js +0 -172
  460. package/out/test/engine-integration.test.js +0 -297
  461. package/out/test/enginePaths.test.js +0 -195
  462. package/out/test/enginePublish.test.js +0 -82
  463. package/out/test/fleetDisplayUtils.test.js +0 -100
  464. package/out/test/gateway-client.test.js +0 -409
  465. package/out/test/gateway-install-source.test.js +0 -111
  466. package/out/test/gateway-lifecycle.test.js +0 -608
  467. package/out/test/gateway-outbound.test.js +0 -538
  468. package/out/test/gateway-reset-mappings.test.js +0 -221
  469. package/out/test/gateway-route-index.test.js +0 -235
  470. package/out/test/gateway-secrets-preflight.test.js +0 -127
  471. package/out/test/gateway-session-routing.test.js +0 -65
  472. package/out/test/gateway-session-store.test.js +0 -216
  473. package/out/test/github.test.js +0 -232
  474. package/out/test/governor-hardening.test.js +0 -217
  475. package/out/test/headless-sync.test.js +0 -301
  476. package/out/test/helpers/manifest-fixtures.js +0 -27
  477. package/out/test/idp-init.test.js +0 -151
  478. package/out/test/lease-signature.test.js +0 -357
  479. package/out/test/lease-trust-root.test.js +0 -273
  480. package/out/test/lease-validation.test.js +0 -169
  481. package/out/test/lease.test.js +0 -114
  482. package/out/test/mcp-obo.test.js +0 -107
  483. package/out/test/mcp.test.js +0 -389
  484. package/out/test/model-routing.test.js +0 -133
  485. package/out/test/openclaw-channel-routing.test.js +0 -191
  486. package/out/test/pack-admission.test.js +0 -216
  487. package/out/test/pack-digest-parity.test.js +0 -140
  488. package/out/test/pack-reconcile.test.js +0 -183
  489. package/out/test/pack-signature-artifact.test.js +0 -103
  490. package/out/test/pack-signature.test.js +0 -176
  491. package/out/test/pack-trust-root.test.js +0 -202
  492. package/out/test/pathSafety.test.js +0 -63
  493. package/out/test/permissions.test.js +0 -175
  494. package/out/test/persistent-engine-worker.test.js +0 -220
  495. package/out/test/refreshPolicy.test.js +0 -60
  496. package/out/test/registry.test.js +0 -351
  497. package/out/test/remote-trust.test.js +0 -242
  498. package/out/test/runner-protocol.test.js +0 -249
  499. package/out/test/runtime.test.js +0 -349
  500. package/out/test/sandbox-driver.test.js +0 -553
  501. package/out/test/sandbox-hardening.test.js +0 -395
  502. package/out/test/sandbox-runner.test.js +0 -343
  503. package/out/test/scheduledFleetStorage.test.js +0 -72
  504. package/out/test/serve-gateway-turn.test.js +0 -267
  505. package/out/test/serve-hardening.test.js +0 -418
  506. package/out/test/serveClient.test.js +0 -209
  507. package/out/test/sessionJsonlFleet.test.js +0 -78
  508. package/out/test/sessionShip.test.js +0 -560
  509. package/out/test/shared.test.js +0 -173
  510. package/out/test/skills-mcp.test.js +0 -299
  511. package/out/test/spotlightPublish.test.js +0 -327
  512. package/out/test/spotlightYaml.test.js +0 -58
  513. package/out/test/state-sync-peer.test.js +0 -156
  514. package/out/test/store-install-safe.test.js +0 -69
  515. package/out/test/store.test.js +0 -331
  516. package/out/test/stores.test.js +0 -504
  517. package/out/test/sync-switch.test.js +0 -251
  518. package/out/test/teamViewDiscovery.test.js +0 -90
  519. package/out/test/tls-bypass.test.js +0 -90
  520. package/out/test/toolPath.test.js +0 -120
  521. package/out/test/utils.test.js +0 -308
  522. package/out/test/viewsConfigMerge.test.js +0 -180
  523. package/out/test/warrant.test.js +0 -138
  524. package/out/test/windows-command-line.test.js +0 -75
  525. package/out/utils/agentEnvFile.js +0 -131
  526. package/out/utils/binary.js +0 -175
  527. package/out/utils/index.js +0 -37
  528. package/out/utils/network.js +0 -74
  529. package/out/utils/paths.js +0 -116
  530. package/out/utils/pid.js +0 -180
  531. package/out/utils/resolveNodeBinary.js +0 -168
  532. package/out/utils/windowsCommandLine.js +0 -29
  533. package/out/utils.js +0 -968
package/out/extension.js CHANGED
@@ -1,4448 +1,36 @@
1
- "use strict";
2
- /*---------------------------------------------------------------------------------------------
3
- * Copyright (c) AgentHippo.ai. All rights reserved.
4
- *--------------------------------------------------------------------------------------------*/
5
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
- if (k2 === undefined) k2 = k;
7
- var desc = Object.getOwnPropertyDescriptor(m, k);
8
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
- desc = { enumerable: true, get: function() { return m[k]; } };
10
- }
11
- Object.defineProperty(o, k2, desc);
12
- }) : (function(o, m, k, k2) {
13
- if (k2 === undefined) k2 = k;
14
- o[k2] = m[k];
15
- }));
16
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
- Object.defineProperty(o, "default", { enumerable: true, value: v });
18
- }) : function(o, v) {
19
- o["default"] = v;
20
- });
21
- var __importStar = (this && this.__importStar) || (function () {
22
- var ownKeys = function(o) {
23
- ownKeys = Object.getOwnPropertyNames || function (o) {
24
- var ar = [];
25
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
- return ar;
27
- };
28
- return ownKeys(o);
29
- };
30
- return function (mod) {
31
- if (mod && mod.__esModule) return mod;
32
- var result = {};
33
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
- __setModuleDefault(result, mod);
35
- return result;
36
- };
37
- })();
38
- Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.activate = activate;
40
- exports.deactivate = deactivate;
41
- /* eslint-disable local/code-no-unexternalized-strings */
42
- const vscode = __importStar(require("vscode"));
43
- const fs_1 = require("fs");
44
- const path = __importStar(require("path"));
45
- const os = __importStar(require("os"));
46
- const types_1 = require("./engines/types");
47
- const factory_1 = require("./engines/factory");
48
- const sync_1 = require("./sync");
49
- const session_1 = require("./session");
50
- const utils_1 = require("./utils");
51
- const agentEnvFile_1 = require("./utils/agentEnvFile");
52
- const index_1 = require("./utils/index");
53
- const runtime_1 = require("./cli/runtime");
54
- const mcp_1 = require("./mcp");
55
- const terminalLogger_1 = require("./terminalLogger");
56
- const workspaceFolders_1 = require("./workspaceFolders");
57
- const branding_1 = require("./branding");
58
- const binary_1 = require("./utils/binary");
59
- const paths_1 = require("./agentpack/paths");
60
- const permissions_1 = require("./permissions");
61
- const vscode_edit_tracker_1 = require("./runtime/vscode/vscode-edit-tracker");
62
- const vscode_logger_1 = require("./runtime/vscode/vscode-logger");
63
- const vscode_config_provider_1 = require("./runtime/vscode/vscode-config-provider");
64
- const permission_handler_1 = require("./runtime/interfaces/permission-handler");
65
- const customRegistry_1 = require("./engines/customRegistry");
66
- const handleRemoteChat_js_1 = require("./remote/handleRemoteChat.js");
67
- const serveClient_js_1 = require("./remote/serveClient.js");
68
- const remotePackStatusBar_js_1 = require("./remote/remotePackStatusBar.js");
69
- const provider_js_1 = require("./auth/provider.js");
70
- const signInFlow_js_1 = require("./auth/signInFlow.js");
71
- const onboardingPrompt_js_1 = require("./auth/onboardingPrompt.js");
72
- const githubStoreGate_js_1 = require("./auth/githubStoreGate.js");
73
- const sessionEvents_1 = require("./analytics/sessionEvents");
74
- const base_1 = require("./engines/base");
75
- /** globalState key for user-installed bundled tools dir (from "Install Bundled Tools" command). */
76
- const BUNDLED_TOOLS_DIR_KEY = 'agentide.bundledToolsDir';
77
- const AGENTIDE_SESSIONS_DIR_NAME = `${paths_1.AGENT_CONSTANTS.AGENTIDE_DIR_NAME}/${paths_1.AGENT_CONSTANTS.SESSIONS_DIR}`;
78
- const TERMINAL_LOG_FILE_NAME = "terminal.md";
79
- const MAX_TERMINAL_LOG_BYTES = 2 * 1024 * 1024; // 2MB per session, then rotate
80
- const ATTACHMENTS_DIR_NAME = "attachments";
81
- let _state;
82
- let _extensionContext;
83
- const _activeRunsByStreamId = new Map();
84
- const _pendingQuestionsById = new Map();
85
- const STREAM_QUESTION_TIMEOUT_MS = 1000 * 60 * 10;
86
- function resolvePendingQuestion(questionId, answer) {
87
- const pending = _pendingQuestionsById.get(questionId);
88
- if (!pending) {
89
- return false;
90
- }
91
- clearTimeout(pending.timeout);
92
- _pendingQuestionsById.delete(questionId);
93
- pending.resolver(answer);
94
- return true;
95
- }
96
- function rejectPendingQuestionsForStream(streamId, reason) {
97
- for (const [questionId, pending] of _pendingQuestionsById) {
98
- if (pending.streamId !== streamId) {
99
- continue;
100
- }
101
- clearTimeout(pending.timeout);
102
- _pendingQuestionsById.delete(questionId);
103
- pending.rejecter(new Error(reason));
104
- }
105
- }
106
- async function askQuestionFromChatUI(streamId, question) {
107
- return await new Promise((resolve, reject) => {
108
- const timeout = setTimeout(() => {
109
- _pendingQuestionsById.delete(question.questionId);
110
- reject(new Error('Question timed out waiting for user response'));
111
- }, STREAM_QUESTION_TIMEOUT_MS);
112
- _pendingQuestionsById.set(question.questionId, {
113
- streamId,
114
- question,
115
- resolver: resolve,
116
- rejecter: reject,
117
- timeout,
118
- });
119
- void Promise.resolve(vscode.commands.executeCommand('agentide.streamCallback', {
120
- streamId,
121
- type: 'question',
122
- metadata: question,
123
- })).catch((err) => {
124
- clearTimeout(timeout);
125
- _pendingQuestionsById.delete(question.questionId);
126
- reject(err instanceof Error ? err : new Error(String(err)));
127
- });
128
- });
129
- }
130
- function normalizeQuestionAnswer(answer) {
131
- const candidate = (answer && typeof answer === 'object') ? answer : {};
132
- const selected = Array.isArray(candidate.selected)
133
- ? candidate.selected.filter((item) => typeof item === 'string' && item.trim().length > 0)
134
- : [];
135
- const freeText = typeof candidate.freeText === 'string'
136
- ? candidate.freeText
137
- : (candidate.freeText === null ? null : null);
138
- return {
139
- selected,
140
- freeText,
141
- declined: candidate.declined === true,
142
- timedOut: candidate.timedOut === true,
143
- cancelled: candidate.cancelled === true,
144
- };
145
- }
146
- function questionPromptToHeader(prompt) {
147
- const firstLine = prompt.split(/\r?\n/, 1)[0]?.trim() || 'Question';
148
- if (firstLine.length <= 50) {
149
- return firstLine;
150
- }
151
- return `${firstLine.slice(0, 47)}...`;
152
- }
153
- /** Map our stream question payload to the workbench askQuestions tool input. */
154
- function streamPayloadToAskQuestionsInput(payload) {
155
- const header = questionPromptToHeader(payload.prompt);
156
- const question = {
157
- header,
158
- question: payload.prompt,
159
- multiSelect: payload.multiSelect,
160
- allowFreeformInput: payload.allowFreeText,
161
- };
162
- if (payload.options?.length) {
163
- question.options = payload.options.map(o => ({
164
- label: o.label,
165
- description: o.description,
166
- recommended: o.recommended,
167
- }));
168
- }
169
- return { questions: [question] };
170
- }
171
- /**
172
- * Ask a question via the workbench's built-in askQuestions tool (same path as Copilot).
173
- * Uses vscode.lm.invokeTool so the chat UI shows the question carousel and returns the user's answer.
174
- */
175
- async function askQuestionViaWorkbenchTool(sessionResource, _requestId, payload, abortSignal) {
176
- const tokenSource = new vscode.CancellationTokenSource();
177
- abortSignal.addEventListener('abort', () => tokenSource.cancel(), { once: true });
178
- try {
179
- const input = streamPayloadToAskQuestionsInput(payload);
180
- // Workbench expects IToolInvocationContext { sessionResource } for chat-attached tool UX
181
- const result = await vscode.lm.invokeTool('vscode_askQuestions', {
182
- input,
183
- toolInvocationToken: { sessionResource: vscode.Uri.parse(sessionResource) },
184
- }, tokenSource.token);
185
- // Result content: [{ kind: 'text', value: jsonString }]. JSON is IAnswerResult { answers: Record<header, IQuestionAnswer> }.
186
- const firstText = result?.content?.find((p) => typeof p.value === 'string');
187
- const jsonStr = firstText?.value;
188
- if (!jsonStr) {
189
- return { selected: [], freeText: null, declined: true };
190
- }
191
- const parsed = JSON.parse(jsonStr);
192
- const answers = parsed?.answers ?? {};
193
- const firstKey = Object.keys(answers)[0];
194
- const answer = firstKey ? answers[firstKey] : undefined;
195
- if (!answer) {
196
- return { selected: [], freeText: null, declined: true };
197
- }
198
- return {
199
- selected: answer.selected ?? [],
200
- freeText: answer.freeText ?? null,
201
- declined: answer.skipped === true,
202
- };
203
- }
204
- catch (err) {
205
- // User cancelled or tool failed
206
- const cancelled = err instanceof Error && (err.name === 'Canceled' || err.message?.includes('cancel'));
207
- return { selected: [], freeText: null, declined: true, cancelled };
208
- }
209
- finally {
210
- tokenSource.dispose();
211
- }
212
- }
213
- // -----------------------------------------------------------------------------
214
- // Constants
215
- // -----------------------------------------------------------------------------
216
- const SESSION_CLEANUP_INTERVAL_MS = 1000 * 60 * 5; // 5 minutes
217
- function log(outputChannel, message) {
218
- outputChannel.appendLine((0, branding_1.brandify)(message));
219
- }
220
- function logConsole(message) {
221
- console.log((0, branding_1.brandify)(message));
222
- }
223
- function showInfo(message) {
224
- return vscode.window.showInformationMessage((0, branding_1.brandify)(message));
225
- }
226
- function showWarning(message) {
227
- return vscode.window.showWarningMessage((0, branding_1.brandify)(message));
228
- }
229
- function showError(message) {
230
- return vscode.window.showErrorMessage((0, branding_1.brandify)(message));
231
- }
232
- // -----------------------------------------------------------------------------
233
- // Activation
234
- // -----------------------------------------------------------------------------
235
- async function activate(context) {
236
- const outputChannel = vscode.window.createOutputChannel(branding_1.AGENTIDE_EXTENSION_NAME);
237
- log(outputChannel, `${branding_1.AGENTIDE_BRAND_NAME} extension activating...`);
238
- logConsole(`${branding_1.AGENTIDE_BRAND_NAME} extension activating...`);
239
- try {
240
- const envMerge = await (0, agentEnvFile_1.mergeAgentHomeEnvIntoProcessEnv)();
241
- if (envMerge.applied.length > 0) {
242
- log(outputChannel, `[AgentIDE] Loaded ${envMerge.applied.length} env var(s) from ${envMerge.envFilePath} (shell env wins on conflict)`);
243
- }
244
- }
245
- catch (err) {
246
- const message = err instanceof Error ? err.message : String(err);
247
- log(outputChannel, `[AgentIDE] Warning: failed to load ~/.agent-hippo/.env: ${message}`);
248
- }
249
- _extensionContext = context;
250
- // Expose extension scripts directory to agent shells
251
- // This allows skills to reference setup scripts via $AGENTIDE_ANALYTICS_SCRIPTS_DIR
252
- const analyticsScriptsDir = (0, utils_1.getAnalyticsScriptsDir)(context.extensionPath);
253
- process.env.AGENTIDE_ANALYTICS_SCRIPTS_DIR = analyticsScriptsDir;
254
- log(outputChannel, `[AgentIDE] Analytics scripts dir: ${analyticsScriptsDir}`);
255
- // Initialize session persistence
256
- (0, session_1.initSessionStore)(context);
257
- // Setup cleanup interval - runs maintenance on all providers generically
258
- const maintenanceLogger = new vscode_logger_1.VSCodeLogger(outputChannel, "[Maintenance]");
259
- const cleanupInterval = setInterval(() => {
260
- (0, session_1.runSessionMaintenance)();
261
- if (_state) {
262
- for (const engine of Object.values(_state.engines)) {
263
- engine.onMaintenance(maintenanceLogger);
264
- }
265
- }
266
- }, SESSION_CLEANUP_INTERVAL_MS);
267
- context.subscriptions.push(new vscode.Disposable(() => clearInterval(cleanupInterval)));
268
- // Prepare workspace-scoped engine directories from registry
269
- const storageBase = context.storageUri ?? context.globalStorageUri;
270
- const storageType = context.storageUri ? "per-workspace" : "global";
271
- // Build config from AGENT_ENGINES
272
- const config = {
273
- storagePath: storageBase.fsPath,
274
- };
275
- // Spotlight setup generates the local proxy's key into ~/.agent-hippo/.env (already merged
276
- // into process.env above). Adopt it so a first-run user never has to copy a key by hand;
277
- // a key the user enters in Settings arrives later via setParticipantApiKey and wins.
278
- const generatedLiteLLMKey = process.env.AGENTHIPPO_LITELLM_API_KEY?.trim() ||
279
- process.env.LITELLM_MASTER_KEY?.trim();
280
- if (generatedLiteLLMKey) {
281
- config.litellmApiKey = generatedLiteLLMKey;
282
- log(outputChannel, "[AgentIDE] Using local LiteLLM key from ~/.agent-hippo/.env");
283
- }
284
- for (const engine of Object.values(types_1.AGENT_ENGINES)) {
285
- const dirPath = path.join(storageBase.fsPath, engine.id);
286
- try {
287
- await fs_1.promises.mkdir(dirPath, { recursive: true });
288
- log(outputChannel, `[AgentIDE] ${engine.displayName} dir: ${dirPath} (${storageType})`);
289
- // Dynamically set config directory based on engine's configEnvVar
290
- if (engine.configEnvVar === "CODEX_HOME") {
291
- config.codexHome = dirPath;
292
- }
293
- else if (engine.configEnvVar === "CLAUDE_CONFIG_DIR") {
294
- config.claudeConfigDir = dirPath;
295
- }
296
- }
297
- catch (e) {
298
- log(outputChannel, `[AgentIDE] Warning: failed to create ${engine.id} dir: ${e instanceof Error ? e.message : String(e)}`);
299
- }
300
- }
301
- // Create sync service
302
- const syncService = new sync_1.SyncService(() => getBundledBasePromptsDir());
303
- // Create engines from factory
304
- const engines = (0, factory_1.createEngines)({
305
- config,
306
- syncService,
307
- getBundledBasePromptsDir: () => getBundledBasePromptsDir(),
308
- });
309
- // Store state
310
- _state = {
311
- outputChannel,
312
- engines,
313
- syncService,
314
- config,
315
- };
316
- // Enable Agent Skills by default (VS Code promptSyntax setting renamed in main7)
317
- try {
318
- const chatConfig = vscode.workspace.getConfiguration("chat");
319
- const inspect = chatConfig.inspect("useAgentSkills");
320
- if (inspect &&
321
- !inspect.globalValue &&
322
- !inspect.workspaceValue &&
323
- !inspect.workspaceFolderValue) {
324
- await chatConfig.update("useAgentSkills", true, vscode.ConfigurationTarget.Global);
325
- log(outputChannel, "[AgentIDE] Enabled Agent Skills by default");
326
- }
327
- }
328
- catch (e) {
329
- log(outputChannel, `[AgentIDE] Warning: failed to enable Agent Skills setting: ${e instanceof Error ? e.message : String(e)}`);
330
- }
331
- // Register bundled MCP servers with VS Code
332
- await registerBundledMcpServers(context, outputChannel);
333
- (0, provider_js_1.registerAgentHippoAuth)(context);
334
- void (0, provider_js_1.refreshBootstrapIfSignedIn)(context);
335
- context.subscriptions.push((0, provider_js_1.startAgentHippoTokenRefreshTimer)(context));
336
- (0, onboardingPrompt_js_1.scheduleSignInOnboardingPrompt)(context);
337
- // Register commands
338
- registerCommands(context, _state);
339
- const remotePackStatusBar = new remotePackStatusBar_js_1.RemotePackStatusBar(syncService, () => getWorkspaceRoot(outputChannel).workspaceRoot, outputChannel);
340
- _state.remotePackStatusBar = remotePackStatusBar;
341
- context.subscriptions.push(remotePackStatusBar);
342
- void remotePackStatusBar.refresh();
343
- // Initialize Agent Anywhere lifecycle manager (detect/install/start/stop gateway)
344
- // This is the user-facing "Agent Anywhere" feature -- all opt-in, nothing auto-starts.
345
- // The lifecycle manager owns the single status bar icon and handles connect/disconnect.
346
- const { GatewayLifecycleManager } = await import('./gateway/lifecycle.js');
347
- _state.gatewayLifecycle = new GatewayLifecycleManager(outputChannel, context);
348
- context.subscriptions.push({ dispose: () => _state?.gatewayLifecycle?.dispose() });
349
- // Initialize Gateway bridge service (WebSocket connection to gateway)
350
- // Routes messages via VS Code Chat UI commands -- no direct engine access needed.
351
- const { GatewayService: GatewayServiceClass } = await import('./gateway/service.js');
352
- _state.gatewayService = new GatewayServiceClass(context, outputChannel);
353
- context.subscriptions.push({ dispose: () => _state?.gatewayService?.dispose() });
354
- // Wire lifecycle ↔ bridge: lifecycle manages connect/disconnect via the single icon
355
- _state.gatewayLifecycle.setBridgeRef(_state.gatewayService);
356
- // Meet Agent Anywhere is only opened from the command palette / Agent Anywhere menu — not after connect.
357
- // Auto-connect bridge when gateway starts running (if autoConnect is enabled)
358
- _state.gatewayLifecycle.onStatusChange(async (status) => {
359
- if (status === 'running') {
360
- const autoConnect = vscode.workspace.getConfiguration('agentide.anywhere').get('autoConnect', false);
361
- if (autoConnect && _state?.gatewayLifecycle) {
362
- void _state.gatewayLifecycle.connectBridge();
363
- }
364
- }
365
- });
366
- // Initialize Analytics service (for LiteLLM Spotlight)
367
- const { AnalyticsService: AnalyticsServiceClass } = await import('./analytics/service.js');
368
- _state.analyticsService = new AnalyticsServiceClass(context, outputChannel);
369
- context.subscriptions.push({ dispose: () => _state?.analyticsService?.dispose() });
370
- // Initialize Spotlight Dashboard (WebView sidebar with charts + chat)
371
- const { AnalyticsDashboardProvider, ArtifactManagerImpl, QueryRunnerImpl, ensureBundledFleetAdapters, } = await import('./analytics/dashboard/index.js');
372
- const spotlightArtifactManager = new ArtifactManagerImpl(outputChannel);
373
- const teamArtifactManager = new ArtifactManagerImpl(outputChannel);
374
- const queryRunner = new QueryRunnerImpl(outputChannel);
375
- ensureBundledFleetAdapters(queryRunner);
376
- const analyticsService = _state.analyticsService;
377
- _state.analyticsDashboard = new AnalyticsDashboardProvider(context, queryRunner, spotlightArtifactManager, outputChannel, () => analyticsService?.getIndexingService());
378
- const teamDashboard = new AnalyticsDashboardProvider(context, queryRunner, teamArtifactManager, outputChannel, () => analyticsService?.getIndexingService(), 'team');
379
- _state.analyticsTeamDashboard = teamDashboard;
380
- context.subscriptions.push(vscode.window.registerWebviewViewProvider(AnalyticsDashboardProvider.viewType, _state.analyticsDashboard, { webviewOptions: { retainContextWhenHidden: true } }), vscode.window.registerWebviewViewProvider('agentide.teamView', teamDashboard, { webviewOptions: { retainContextWhenHidden: true } }), _state.analyticsDashboard, teamDashboard, { dispose: () => spotlightArtifactManager.dispose() }, { dispose: () => teamArtifactManager.dispose() }, { dispose: () => queryRunner.dispose() });
381
- // Spotlight dashboard commands
382
- context.subscriptions.push(vscode.commands.registerCommand('agentide.analytics.openDashboard', () => {
383
- vscode.commands.executeCommand('agentide.analyticsView.focus');
384
- }), vscode.commands.registerCommand('agentide.fleet.open', async () => {
385
- const team = _state?.analyticsTeamDashboard;
386
- if (team) {
387
- await team.openWithView('fleet');
388
- }
389
- await vscode.commands.executeCommand('agentide.teamView.focus');
390
- }), vscode.commands.registerCommand('agentide.analytics.clearArtifacts', async () => {
391
- const result = await spotlightArtifactManager.cleanup(0);
392
- await context.workspaceState.update('analytics.generatedDefaultDashboard', false);
393
- vscode.window.showInformationMessage(`Cleared ${result.deletedCount} Spotlight artifacts (${(result.freedBytes / 1024).toFixed(1)} KB)`);
394
- }), vscode.commands.registerCommand('agentide.analytics.regenerateDefaults', async () => {
395
- if (_state?.analyticsDashboard) {
396
- queryRunner.invalidateCache();
397
- await _state.analyticsDashboard.runDefaultChartScript();
398
- }
399
- }), vscode.commands.registerCommand('agentide.persistChatVote', async (payload) => {
400
- if (!payload?.sessionId || !payload?.requestId)
401
- return;
402
- await _sessionEventWriter.append(payload.sessionId, payload.requestId, 'vote', {
403
- direction: payload.direction,
404
- reason: payload.reason,
405
- agentId: payload.agentId,
406
- command: payload.command,
407
- });
408
- }));
409
- // Activate terminal activity logger (logs all terminal commands to the agent terminals directory)
410
- // Terminal logs are automatically truncated to max N lines (configurable)
411
- // Session cleanup happens opportunistically when sessions are deleted
412
- (0, terminalLogger_1.activateTerminalLogger)(context);
413
- // Simplest retention behavior: best-effort cleanup on startup (non-blocking).
414
- // Manual cleanup is also available via 'AgentIDE: Cleanup Old Session Logs'.
415
- const sessionsCleanupTimeout = setTimeout(() => {
416
- void (0, terminalLogger_1.cleanupOldSessionLogs)(outputChannel);
417
- }, 5_000);
418
- context.subscriptions.push(new vscode.Disposable(() => clearTimeout(sessionsCleanupTimeout)));
419
- // Initialize store index in background (non-blocking)
420
- // This preloads the Orama search index for faster store browsing
421
- const storeIndexTimeout = setTimeout(async () => {
422
- try {
423
- const { initializeStoreIndex } = await import("./store/oramaIndex.js");
424
- await initializeStoreIndex(outputChannel);
425
- }
426
- catch (e) {
427
- log(outputChannel, `[AgentIDE] Store index init: ${e instanceof Error ? e.message : String(e)}`);
428
- }
429
- }, 3_000); // Delay slightly to prioritize other startup tasks
430
- context.subscriptions.push(new vscode.Disposable(() => clearTimeout(storeIndexTimeout)));
431
- // Setup workspace watchers and repair unregistered packs
432
- if (vscode.workspace.workspaceFolders?.length) {
433
- void refreshAgentideProject(_state).then(async () => {
434
- syncService.ensureAgentideWatchers(outputChannel);
435
- // Auto-repair: register any untracked packs found on disk
436
- try {
437
- const { workspaceRoot } = getWorkspaceRoot(outputChannel);
438
- const { AgentPackManager } = await import("./agentpack/index.js");
439
- const packManager = new AgentPackManager(syncService, () => workspaceRoot, () => config.storagePath, outputChannel);
440
- const { registered } = await packManager.repairUnregisteredAgents();
441
- if (registered.length > 0) {
442
- log(outputChannel, `[AgentIDE] Auto-repaired ${registered.length} unregistered pack(s): ${registered.join(", ")}`);
443
- }
444
- }
445
- catch (e) {
446
- log(outputChannel, `[AgentIDE] Pack repair check failed: ${e instanceof Error ? e.message : String(e)}`);
447
- }
448
- // Note: Pack restoration is now handled by the workbench (AgentPackService).
449
- // The workbench persists the active pack ID in IStorageService and calls
450
- // agentide.pack.setActive on startup to restore pack files.
451
- // Mode/model preferences are stored in the chat widget's storage and
452
- // restored by the chat widget itself.
453
- void _state?.remotePackStatusBar?.refresh();
454
- });
455
- }
456
- context.subscriptions.push(vscode.workspace.onDidChangeWorkspaceFolders(() => {
457
- syncService.ensureAgentideWatchers(outputChannel);
458
- if (_state) {
459
- void refreshAgentideProject(_state);
460
- void _state.remotePackStatusBar?.refresh();
461
- }
462
- }));
463
- context.subscriptions.push(new vscode.Disposable(() => {
464
- syncService.disposeAllWatchers();
465
- }));
466
- log(outputChannel, "[AgentIDE] Extension activation complete");
467
- }
468
- function deactivate() {
469
- if (_state) {
470
- for (const engine of Object.values(_state.engines)) {
471
- try {
472
- engine.dispose();
473
- }
474
- catch {
475
- // ignore
476
- }
477
- }
478
- }
479
- _state = undefined;
480
- }
481
- function escapeRegExp(value) {
482
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
483
- }
484
- function quoteEnvValue(value) {
485
- if (/^[A-Za-z0-9_./:@-]+$/.test(value)) {
486
- return value;
487
- }
488
- return `'${value.replace(/'/g, `'\\''`)}'`;
489
- }
490
- function upsertEnvVar(content, variable, value) {
491
- const lines = content.split(/\r?\n/);
492
- const matcher = new RegExp(`^\\s*(?:export\\s+)?${escapeRegExp(variable)}\\s*=`);
493
- let replaced = false;
494
- for (let i = 0; i < lines.length; i++) {
495
- const line = lines[i];
496
- const trimmed = line.trim();
497
- if (!trimmed || trimmed.startsWith("#")) {
498
- continue;
499
- }
500
- if (matcher.test(line)) {
501
- lines[i] = `${variable}=${quoteEnvValue(value)}`;
502
- replaced = true;
503
- }
504
- }
505
- if (!replaced) {
506
- if (lines.length > 0 && lines[lines.length - 1].trim() !== "") {
507
- lines.push("");
508
- }
509
- lines.push(`${variable}=${quoteEnvValue(value)}`);
510
- }
511
- return lines.join("\n").replace(/\s*$/, "\n");
512
- }
513
- function hasEnvVar(content, variable) {
514
- const matcher = new RegExp(`^\\s*(?:export\\s+)?${escapeRegExp(variable)}\\s*=`);
515
- return content.split(/\r?\n/).some(line => {
516
- const trimmed = line.trim();
517
- if (!trimmed || trimmed.startsWith("#")) {
518
- return false;
519
- }
520
- return matcher.test(line);
521
- });
522
- }
523
- // -----------------------------------------------------------------------------
524
- // Command Registration
525
- // -----------------------------------------------------------------------------
526
- function registerCommands(context, state) {
527
- const { outputChannel, syncService, config } = state;
528
- // Set API keys (called from Workbench)
529
- context.subscriptions.push(vscode.commands.registerCommand("agentide.setParticipantApiKey", (args) => {
530
- log(outputChannel, `[AgentIDE] Setting API key for ${args.provider}${args.baseUrl ? ` with baseUrl: ${args.baseUrl}` : ""}`);
531
- if (args.provider === "litellm") {
532
- config.litellmApiKey = args.apiKey;
533
- config.litellmBaseUrl = args.baseUrl;
534
- }
535
- }));
536
- context.subscriptions.push(vscode.commands.registerCommand("agentide.binary.findOnPath", async (args) => {
537
- const name = args?.name?.trim();
538
- if (!name) {
539
- throw new Error("Binary name is required");
540
- }
541
- return (0, binary_1.findBinaryCached)(name, (0, binary_1.getCommonBinaryPaths)(name));
542
- }));
543
- context.subscriptions.push(vscode.commands.registerCommand("agentide.openaiCodex.loginOAuth", async () => {
544
- log(outputChannel, "[AgentIDE] Starting native OpenAI Codex OAuth login");
545
- const { loginOpenAICodex } = await import("@mariozechner/pi-ai");
546
- const creds = await loginOpenAICodex({
547
- onAuth: async ({ url }) => {
548
- log(outputChannel, `[AgentIDE] OpenAI Codex OAuth URL: ${url}`);
549
- try {
550
- await vscode.env.openExternal(vscode.Uri.parse(url));
551
- void showInfo("Complete ChatGPT sign-in in your browser. Return here if prompted for a redirect URL.");
552
- }
553
- catch (error) {
554
- log(outputChannel, `[AgentIDE] Failed to auto-open OAuth URL: ${String(error)}`);
555
- void showWarning(`Open this URL in your browser: ${url}`);
556
- }
557
- },
558
- onPrompt: async (prompt) => {
559
- const input = await vscode.window.showInputBox({
560
- title: "OpenAI Codex OAuth",
561
- prompt: prompt.message,
562
- placeHolder: prompt.placeholder,
563
- ignoreFocusOut: true,
564
- validateInput: value => value.trim().length > 0 ? undefined : "Required"
565
- });
566
- if (!input || input.trim().length === 0) {
567
- throw new Error("OpenAI Codex OAuth cancelled");
568
- }
569
- return input.trim();
570
- },
571
- onProgress: (message) => {
572
- log(outputChannel, `[AgentIDE] OpenAI Codex OAuth: ${message}`);
573
- }
574
- });
575
- const apiKey = creds?.access?.trim();
576
- if (!apiKey) {
577
- throw new Error("OpenAI Codex OAuth completed without an access token");
578
- }
579
- const oauthCredential = { type: "oauth", ...creds };
580
- const result = {
581
- apiKey,
582
- oauthCredential,
583
- expiresAt: typeof creds.expires === "number" ? creds.expires : undefined
584
- };
585
- log(outputChannel, "[AgentIDE] OpenAI Codex OAuth login complete");
586
- return result;
587
- }));
588
- context.subscriptions.push(vscode.commands.registerCommand("agentide.openaiCodex.getValidApiKey", async (args) => {
589
- const oauthCredential = args?.oauthCredential;
590
- if (!oauthCredential || typeof oauthCredential !== "object") {
591
- throw new Error("Missing openai-codex OAuth credential payload.");
592
- }
593
- const { getOAuthApiKey } = await import("@mariozechner/pi-ai");
594
- const normalized = ((oauthCredential.type === "oauth")
595
- ? oauthCredential
596
- : { type: "oauth", ...oauthCredential });
597
- const authMap = {
598
- "openai-codex": normalized,
599
- };
600
- const resolved = await getOAuthApiKey("openai-codex", authMap);
601
- if (!resolved?.apiKey) {
602
- throw new Error("OpenAI Codex OAuth credential is invalid or expired. Please sign in again.");
603
- }
604
- return {
605
- apiKey: String(resolved.apiKey),
606
- oauthCredential: { type: "oauth", ...resolved.newCredentials },
607
- expiresAt: typeof resolved.newCredentials?.expires === "number"
608
- ? resolved.newCredentials.expires
609
- : undefined
610
- };
611
- }));
612
- context.subscriptions.push(vscode.commands.registerCommand("agentide.litellm.setUpstreamApiKey", async (args) => {
613
- const envVar = args?.envVar?.trim() ?? "";
614
- const apiKey = args?.apiKey?.trim() ?? "";
615
- if (!envVar || !/^[A-Z][A-Z0-9_]*$/.test(envVar)) {
616
- throw new Error(`Invalid env var name: ${envVar}`);
617
- }
618
- if (!apiKey) {
619
- throw new Error(`API key value cannot be empty for ${envVar}`);
620
- }
621
- const agentHomeDir = (0, index_1.getAgentideHome)();
622
- const envFilePath = path.join(agentHomeDir, ".env");
623
- await fs_1.promises.mkdir(agentHomeDir, { recursive: true, mode: 0o700 });
624
- let existingContent = "";
625
- try {
626
- existingContent = await fs_1.promises.readFile(envFilePath, "utf8");
627
- }
628
- catch {
629
- // File does not exist yet, we'll create it below.
630
- }
631
- const updatedContent = upsertEnvVar(existingContent, envVar, apiKey);
632
- await fs_1.promises.writeFile(envFilePath, updatedContent, "utf8");
633
- try {
634
- await fs_1.promises.chmod(envFilePath, 0o600);
635
- }
636
- catch {
637
- // Best-effort on platforms that may not support chmod.
638
- }
639
- log(outputChannel, `[AgentIDE] Updated LiteLLM upstream key in ${envFilePath} (${envVar})`);
640
- return { envFilePath, envVar };
641
- }));
642
- context.subscriptions.push(vscode.commands.registerCommand("agentide.litellm.getUpstreamApiKeyStatus", async (args) => {
643
- const envVar = args?.envVar?.trim() ?? "";
644
- if (!envVar || !/^[A-Z][A-Z0-9_]*$/.test(envVar)) {
645
- throw new Error(`Invalid env var name: ${envVar}`);
646
- }
647
- const agentHomeDir = (0, index_1.getAgentideHome)();
648
- const envFilePath = path.join(agentHomeDir, ".env");
649
- let existingContent = "";
650
- try {
651
- existingContent = await fs_1.promises.readFile(envFilePath, "utf8");
652
- }
653
- catch {
654
- // Missing file means key is not configured yet.
655
- }
656
- return {
657
- envFilePath,
658
- envVar,
659
- exists: hasEnvVar(existingContent, envVar),
660
- };
661
- }));
662
- // Clear managed resources
663
- context.subscriptions.push(vscode.commands.registerCommand("agentide.clearManagedResources", async () => {
664
- const confirm = await vscode.window.showWarningMessage((0, branding_1.brandify)("Clear all AgentIDE managed resources?"), {
665
- modal: true,
666
- detail: `This will remove derived folders and generated files. User-managed files in \`${paths_1.AGENT_CONSTANTS.AGENTIDE_DIR_NAME}/\` will NOT be deleted.`,
667
- }, "Clear Resources", "Cancel");
668
- if (confirm !== "Clear Resources") {
669
- return;
670
- }
671
- const { workspaceRoot, additionalDirectories, isHomeFallback } = getWorkspaceRoot(outputChannel);
672
- if (isHomeFallback) {
673
- // Ensure fallback exists before doing any filesystem work.
674
- await ensureFallbackDirectoryExists(outputChannel);
675
- }
676
- const { cleared, skipped, errors } = await syncService.clearManagedResources(config.codexHome, config.claudeConfigDir, workspaceRoot, additionalDirectories, outputChannel);
677
- const message = [
678
- `Cleared: ${cleared.length} resources`,
679
- skipped.length > 0 ? `Skipped: ${skipped.length} (user files)` : "",
680
- errors.length > 0 ? `Errors: ${errors.length}` : "",
681
- ]
682
- .filter(Boolean)
683
- .join(" | ");
684
- if (errors.length > 0) {
685
- showError(`AgentIDE: ${message}`);
686
- log(outputChannel, `[AgentIDE] Errors: ${errors.join(", ")}`);
687
- }
688
- else {
689
- showInfo(`AgentIDE: ${message}`);
690
- }
691
- log(outputChannel, `[AgentIDE] Clear complete: ${message}`);
692
- }));
693
- // Sync remote skills into the default agent skills directory (best-effort)
694
- context.subscriptions.push(vscode.commands.registerCommand("agentide.skills.syncRemote", async () => {
695
- const { workspaceRoot, additionalDirectories, isHomeFallback } = getWorkspaceRoot(outputChannel);
696
- if (isHomeFallback) {
697
- await ensureFallbackDirectoryExists(outputChannel);
698
- }
699
- // Ensure project exists (creates agent root if missing)
700
- await syncService.ensureAgentideProjectPrepared(workspaceRoot, additionalDirectories, outputChannel);
701
- // Force a remote skills sync regardless of syncOnStartup
702
- await syncService.syncRemoteSkillsIfEnabled(workspaceRoot, outputChannel, { force: true });
703
- // Apply changes immediately (refresh manifest + derived dirs if needed)
704
- await syncService.flushAgentideRootUpdate(workspaceRoot, outputChannel, {
705
- allowDuringActiveTurn: true,
706
- force: false,
707
- });
708
- void showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: Remote skills sync complete (see ${branding_1.AGENTIDE_BRAND_NAME} output for details).`);
709
- }));
710
- // Show managed resources
711
- context.subscriptions.push(vscode.commands.registerCommand("agentide.showManagedResources", async () => {
712
- const { workspaceRoot, additionalDirectories, isHomeFallback } = getWorkspaceRoot(outputChannel);
713
- if (isHomeFallback) {
714
- // Ensure fallback exists before writing derived files.
715
- await ensureFallbackDirectoryExists(outputChannel);
716
- }
717
- await syncService.writeManagedPathsManifest(config.codexHome, config.claudeConfigDir, workspaceRoot, additionalDirectories, outputChannel);
718
- const manifestPath = path.join((0, paths_1.getAgentideDir)(workspaceRoot), "paths.md");
719
- if (await (0, utils_1.pathExists)(manifestPath)) {
720
- const doc = await vscode.workspace.openTextDocument(manifestPath);
721
- await vscode.window.showTextDocument(doc);
722
- }
723
- }));
724
- // Cleanup old session logs
725
- context.subscriptions.push(vscode.commands.registerCommand("agentide.cleanupSessionLogs", async () => {
726
- const result = await (0, terminalLogger_1.cleanupOldSessionLogs)(outputChannel);
727
- if (result.cleaned > 0) {
728
- showInfo(`AgentIDE: Cleaned up ${result.cleaned} old session(s)`);
729
- }
730
- else if (result.errors.length > 0) {
731
- showWarning(`AgentIDE: Cleanup completed with ${result.errors.length} error(s)`);
732
- }
733
- else {
734
- showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: No old sessions to clean up`);
735
- }
736
- }));
737
- // Delete specific session logs and opportunistically clean up old sessions
738
- context.subscriptions.push(vscode.commands.registerCommand("agentide.deleteSessionLogs", async (args) => {
739
- const sessionId = args?.sessionId;
740
- if (!sessionId) {
741
- return { deleted: false, error: "sessionId is required" };
742
- }
743
- const result = await (0, terminalLogger_1.deleteSessionLogs)(sessionId);
744
- if (result.deleted) {
745
- log(outputChannel, `[AgentIDE] Deleted session logs: ${sessionId}`);
746
- // Optional: run best-effort retention cleanup after deletion.
747
- void (0, terminalLogger_1.cleanupOldSessionLogs)(outputChannel);
748
- }
749
- else if (result.error) {
750
- log(outputChannel, `[AgentIDE] Failed to delete session logs: ${result.error}`);
751
- }
752
- return result;
753
- }));
754
- // -------------------------------------------------------------------------
755
- // CLI Setup
756
- // -------------------------------------------------------------------------
757
- context.subscriptions.push(vscode.commands.registerCommand("agentide.cli.status", async () => {
758
- const configuredCliPath = vscode.workspace
759
- .getConfiguration("agentide")
760
- .get("cli.path", "");
761
- const health = await (0, runtime_1.getCliHealth)({
762
- configuredPath: configuredCliPath,
763
- extensionPath: context.extensionPath,
764
- });
765
- const toolsHealth = (0, runtime_1.getBundledToolsHealth)({
766
- extensionPath: context.extensionPath,
767
- binaryDirHint: health.path ? path.dirname(health.path) : undefined,
768
- });
769
- const availableTools = toolsHealth.tools.filter(tool => tool.available).map(tool => tool.name);
770
- if (health.installed) {
771
- const sourceLabel = health.source === 'setting'
772
- ? 'configured path'
773
- : health.source === 'bundled'
774
- ? 'bundled binary'
775
- : 'system PATH';
776
- const toolsSuffix = availableTools.length > 0
777
- ? `; tools: ${availableTools.join(', ')}`
778
- : '; tools: none';
779
- showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: CLI available (${sourceLabel})${health.version ? ` ${health.version}` : ''}${toolsSuffix}`);
780
- }
781
- else {
782
- showWarning(`${branding_1.AGENTIDE_BRAND_NAME}: CLI not found. Run '${branding_1.AGENTIDE_BRAND_NAME}: Setup AgentHippo CLI'.`);
783
- }
784
- return health;
785
- }));
786
- context.subscriptions.push(vscode.commands.registerCommand("agentide.cli.isInstalled", async () => {
787
- const configuredCliPath = vscode.workspace
788
- .getConfiguration("agentide")
789
- .get("cli.path", "");
790
- const health = await (0, runtime_1.getCliHealth)({
791
- configuredPath: configuredCliPath,
792
- extensionPath: context.extensionPath,
793
- });
794
- return health.installed;
795
- }));
796
- context.subscriptions.push(vscode.commands.registerCommand("agentide.installBundledTools", async () => {
797
- const toolsHealth = (0, runtime_1.getBundledToolsHealth)({ extensionPath: context.extensionPath });
798
- if (!toolsHealth.platformKey) {
799
- showError(`${branding_1.AGENTIDE_BRAND_NAME}: Unsupported platform ${process.platform}-${process.arch}. Cannot install bundled tools.`);
800
- return;
801
- }
802
- const storageUri = context.globalStorageUri;
803
- if (!storageUri) {
804
- showError(`${branding_1.AGENTIDE_BRAND_NAME}: No global storage path. Cannot install bundled tools.`);
805
- return;
806
- }
807
- const outBaseDir = path.join(storageUri.fsPath, 'tools');
808
- const scriptCandidates = [
809
- path.join(context.extensionPath, 'out', 'scripts', 'vendor-tools.mjs'),
810
- path.join(context.extensionPath, 'scripts', 'vendor-tools.mjs'),
811
- ];
812
- const scriptPath = scriptCandidates.find((p) => {
813
- try {
814
- return require('fs').statSync(p).isFile();
815
- }
816
- catch {
817
- return false;
818
- }
819
- });
820
- if (!scriptPath) {
821
- showError(`${branding_1.AGENTIDE_BRAND_NAME}: vendor-tools script not found. Run from extension source or rebuild.`);
822
- return;
823
- }
824
- log(outputChannel, `[AgentIDE] Installing bundled tools (rg, sg, tree-sitter) into ${outBaseDir} ...`);
825
- try {
826
- const { spawn } = await import('child_process');
827
- await new Promise((resolve, reject) => {
828
- const child = spawn(process.execPath, [scriptPath, '--out-dir', outBaseDir, '--clean'], {
829
- stdio: ['ignore', 'pipe', 'pipe'],
830
- env: { ...process.env },
831
- });
832
- let stderr = '';
833
- child.stdout?.on('data', (chunk) => log(outputChannel, chunk.toString()));
834
- child.stderr?.on('data', (chunk) => { stderr += chunk.toString(); log(outputChannel, chunk.toString()); });
835
- child.on('error', reject);
836
- child.on('close', (code) => (code === 0 ? resolve() : reject(new Error(`Exit ${code}: ${stderr}`))));
837
- });
838
- const toolsDir = path.join(outBaseDir, toolsHealth.platformKey);
839
- await context.globalState.update(BUNDLED_TOOLS_DIR_KEY, toolsDir);
840
- showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: Bundled tools installed to ${toolsDir}. They will be used by the agent.`);
841
- }
842
- catch (e) {
843
- const msg = e instanceof Error ? e.message : String(e);
844
- log(outputChannel, `[AgentIDE] Install bundled tools failed: ${msg}`);
845
- showError(`${branding_1.AGENTIDE_BRAND_NAME}: Failed to install bundled tools. Check Output > Agent Hippo. ${msg}`);
846
- }
847
- }));
848
- context.subscriptions.push(vscode.commands.registerCommand("agentide.setupCli", async () => {
849
- log(outputChannel, "[AgentIDE] Starting CLI setup...");
850
- const cliConfig = vscode.workspace.getConfiguration("agentide.cli");
851
- const configuredCliPath = cliConfig.get("path", "");
852
- const installSource = cliConfig.get("installSource", "").trim();
853
- if (installSource && /[;`|$&\n\r"']/.test(installSource)) {
854
- showError(`${branding_1.AGENTIDE_BRAND_NAME}: Invalid CLI install source. Remove shell control characters from '${(0, branding_1.describeSettingKey)("agentide.cli.installSource")}'.`);
855
- return { success: false, error: "Invalid install source" };
856
- }
857
- const health = await (0, runtime_1.getCliHealth)({
858
- configuredPath: configuredCliPath,
859
- extensionPath: context.extensionPath,
860
- forceRefresh: true,
861
- });
862
- if (health.installed && health.path) {
863
- await vscode.workspace
864
- .getConfiguration("agentide")
865
- .update("cli.path", health.path, vscode.ConfigurationTarget.Global);
866
- showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: CLI is ready at ${health.path}`);
867
- return { success: true, path: health.path };
868
- }
869
- const isWindows = process.platform === "win32";
870
- const scriptName = isWindows ? "setup-cli.ps1" : "setup-cli.sh";
871
- const candidates = [
872
- path.join(context.extensionPath, "out", "scripts", scriptName),
873
- path.join(context.extensionPath, "scripts", scriptName),
874
- ];
875
- const scriptPath = candidates.find((p) => {
876
- try {
877
- require("fs").accessSync(p);
878
- return true;
879
- }
880
- catch {
881
- return false;
882
- }
883
- });
884
- if (!scriptPath) {
885
- showError(`${branding_1.AGENTIDE_BRAND_NAME}: CLI setup script not found. Build CLI via extensions/agentide/scripts/build-cli.sh and set ${(0, branding_1.describeSettingKey)("agentide.cli.path")}.`);
886
- return { success: false, error: "Script not found" };
887
- }
888
- const setupResult = await runCliSetup(scriptPath, outputChannel, installSource);
889
- if (!setupResult.success) {
890
- return setupResult;
891
- }
892
- const refreshed = await (0, runtime_1.getCliHealth)({
893
- configuredPath: configuredCliPath,
894
- extensionPath: context.extensionPath,
895
- forceRefresh: true,
896
- });
897
- if (refreshed.installed && refreshed.path) {
898
- await vscode.workspace
899
- .getConfiguration("agentide")
900
- .update("cli.path", refreshed.path, vscode.ConfigurationTarget.Global);
901
- showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: CLI configured at ${refreshed.path}`);
902
- return { success: true, path: refreshed.path };
903
- }
904
- showWarning(`${branding_1.AGENTIDE_BRAND_NAME}: Setup launched. Re-run '${branding_1.AGENTIDE_BRAND_NAME}: CLI Status' after terminal setup completes.`);
905
- return { success: true, pending: true };
906
- }));
907
- async function runCliSetup(scriptPath, outputChannel, installSource) {
908
- const isWindows = process.platform === "win32";
909
- const isUrlSource = /^https?:\/\//i.test(installSource);
910
- const sourceArg = installSource
911
- ? isWindows
912
- ? `-Source \"${installSource}\"`
913
- : `--source \"${installSource}\"`
914
- : "";
915
- const terminal = isWindows
916
- ? vscode.window.createTerminal({
917
- name: "AgentHippo CLI Setup",
918
- cwd: path.dirname(scriptPath),
919
- shellPath: "powershell.exe",
920
- shellArgs: [
921
- "-NoProfile",
922
- "-NoExit",
923
- "-ExecutionPolicy",
924
- "Bypass",
925
- "-Command",
926
- `& "${scriptPath}" ${sourceArg} -Yes; Write-Host ""; Write-Host "You can close this window."`,
927
- ],
928
- })
929
- : vscode.window.createTerminal({
930
- name: "AgentHippo CLI Setup",
931
- cwd: path.dirname(scriptPath),
932
- shellPath: "/bin/bash",
933
- shellArgs: [
934
- "-c",
935
- `"${scriptPath}" ${sourceArg} --yes; echo ''; echo 'Press any key to close...'; read -n 1`,
936
- ],
937
- });
938
- if (installSource) {
939
- log(outputChannel, `[AgentIDE] CLI install source configured (${isUrlSource ? 'url' : 'package/path'}): ${installSource}`);
940
- }
941
- terminal.show();
942
- showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: CLI setup started. Check the terminal for progress.`);
943
- log(outputChannel, "[AgentIDE] CLI setup terminal opened");
944
- return { success: true };
945
- }
946
- // -------------------------------------------------------------------------
947
- // Spotlight Setup
948
- // -------------------------------------------------------------------------
949
- // Install or repair Spotlight (OTEL Collector + DuckDB)
950
- // Scripts are bundled with the extension for reliable access
951
- context.subscriptions.push(vscode.commands.registerCommand("agentide.setupAnalytics", async () => {
952
- log(outputChannel, "[AgentIDE] Starting Spotlight install/repair...");
953
- const isWindows = process.platform === "win32";
954
- const scriptName = isWindows ? "setup-analytics.ps1" : "setup-analytics.sh";
955
- const extensionPath = context.extensionPath;
956
- // Try bundled location first, then dev location
957
- const candidates = [
958
- path.join(extensionPath, "out", "scripts", "analytics", scriptName),
959
- path.join(extensionPath, "scripts", "analytics", scriptName),
960
- ];
961
- const scriptPath = candidates.find((p) => {
962
- try {
963
- require("fs").accessSync(p);
964
- return true;
965
- }
966
- catch {
967
- return false;
968
- }
969
- });
970
- if (!scriptPath) {
971
- showError(`Spotlight install script not found. Please run 'scripts/analytics/${scriptName}' manually from the AgentIDE repository.`);
972
- return { success: false, error: "Script not found" };
973
- }
974
- if (isWindows && _state?.analyticsService) {
975
- return _state.analyticsService.setupWindowsSpotlight({ reinstall: false });
976
- }
977
- return runAnalyticsSetup(scriptPath, outputChannel);
978
- }));
979
- async function runAnalyticsSetup(scriptPath, outputChannel) {
980
- const isWindows = process.platform === "win32";
981
- const agentHomeDir = path.join(os.homedir(), branding_1.AGENTIDE_DIR_NAME);
982
- const terminal = isWindows
983
- ? vscode.window.createTerminal({
984
- name: "Spotlight Install",
985
- cwd: path.dirname(scriptPath),
986
- env: { AGENT_HOME_DIR: agentHomeDir },
987
- shellPath: "powershell.exe",
988
- shellArgs: ["-NoProfile", "-NoExit", "-ExecutionPolicy", "Bypass", "-Command",
989
- `& "${scriptPath}" -Yes; Write-Host ""; Write-Host "You can close this window."`],
990
- })
991
- : vscode.window.createTerminal({
992
- name: "Spotlight Install",
993
- cwd: path.dirname(scriptPath),
994
- env: { AGENT_HOME_DIR: agentHomeDir },
995
- shellPath: "/bin/bash",
996
- shellArgs: ["-c", `"${scriptPath}" --yes; echo ''; echo 'Press any key to close...'; read -n 1`],
997
- });
998
- terminal.show();
999
- showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: Spotlight install started. Check the terminal for progress.`);
1000
- log(outputChannel, "[AgentIDE] Spotlight install terminal opened");
1001
- return { success: true };
1002
- }
1003
- // -------------------------------------------------------------------------
1004
- // AgentPack Commands
1005
- // -------------------------------------------------------------------------
1006
- // Install agent pack from local folder
1007
- context.subscriptions.push(vscode.commands.registerCommand("agentide.pack.install", async () => {
1008
- const { workspaceRoot, isHomeFallback } = getWorkspaceRoot(outputChannel);
1009
- if (isHomeFallback) {
1010
- await ensureFallbackDirectoryExists(outputChannel);
1011
- }
1012
- const folders = await vscode.window.showOpenDialog({
1013
- canSelectFolders: true,
1014
- canSelectFiles: false,
1015
- canSelectMany: false,
1016
- openLabel: "Select Agent Pack Folder",
1017
- title: "Install Agent Pack",
1018
- });
1019
- if (!folders || folders.length === 0) {
1020
- return;
1021
- }
1022
- const sourcePath = folders[0].fsPath;
1023
- const { AgentPackManager } = await import("./agentpack/index.js");
1024
- const packManager = new AgentPackManager(syncService, () => workspaceRoot, () => config.storagePath, outputChannel);
1025
- try {
1026
- const installed = await packManager.installFromLocal(sourcePath);
1027
- showInfo(`AgentIDE: Installed pack "${installed.id}" v${installed.version}`);
1028
- }
1029
- catch (e) {
1030
- const errorMsg = e instanceof Error ? e.message : String(e);
1031
- log(outputChannel, `[AgentIDE] Pack install error: ${errorMsg}`);
1032
- showError(`AgentIDE: Failed to install pack - ${errorMsg}`);
1033
- }
1034
- }));
1035
- // List installed packs
1036
- context.subscriptions.push(vscode.commands.registerCommand("agentide.pack.list", async () => {
1037
- const { workspaceRoot } = getWorkspaceRoot(outputChannel);
1038
- const { AgentPackManager } = await import("./agentpack/index.js");
1039
- const packManager = new AgentPackManager(syncService, () => workspaceRoot, () => config.storagePath, outputChannel);
1040
- const packs = await packManager.listInstalled();
1041
- if (packs.length === 0) {
1042
- showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: No agent packs installed`);
1043
- return;
1044
- }
1045
- const items = packs.map((p) => ({
1046
- label: p.id,
1047
- description: `v${p.version} (${p.preferredEngine})`,
1048
- detail: `Status: ${p.status} | Installed: ${new Date(p.installedAt).toLocaleDateString()}`,
1049
- }));
1050
- const selected = await vscode.window.showQuickPick(items, {
1051
- placeHolder: "Select a pack to view details",
1052
- title: "Installed Agent Packs",
1053
- });
1054
- if (selected) {
1055
- log(outputChannel, `[AgentIDE] Pack selected: ${selected.label}`);
1056
- outputChannel.show();
1057
- }
1058
- }));
1059
- // Get installed packs (data-only, no UI)
1060
- context.subscriptions.push(vscode.commands.registerCommand("agentide.pack.getInstalled", async () => {
1061
- const { workspaceRoot } = getWorkspaceRoot(outputChannel);
1062
- const { AgentPackManager } = await import("./agentpack/index.js");
1063
- const packManager = new AgentPackManager(syncService, () => workspaceRoot, () => config.storagePath, outputChannel);
1064
- try {
1065
- return await packManager.listInstalled();
1066
- }
1067
- catch (e) {
1068
- const errorMsg = e instanceof Error ? e.message : String(e);
1069
- log(outputChannel, `[AgentIDE] Pack list error: ${errorMsg}`);
1070
- return [];
1071
- }
1072
- }));
1073
- // List discovered custom engines (data-only, no UI)
1074
- context.subscriptions.push(vscode.commands.registerCommand("agentide.customEngine.list", (args) => {
1075
- const additionalEngineDir = getConfiguredAdditionalEngineDir();
1076
- const explicitWorkspaceRoot = args?.workspaceRoot?.trim();
1077
- const workspaceFolderRoots = (vscode.workspace.workspaceFolders ?? [])
1078
- .map((folder) => folder.uri.fsPath)
1079
- .filter((value) => !!value?.trim());
1080
- const processCwd = process.cwd?.();
1081
- const candidateRoots = Array.from(new Set([
1082
- explicitWorkspaceRoot,
1083
- ...workspaceFolderRoots,
1084
- processCwd,
1085
- ]
1086
- .map((value) => value?.trim())
1087
- .filter((value) => !!value)));
1088
- const manifestsById = new Map();
1089
- for (const root of candidateRoots) {
1090
- try {
1091
- const manifests = (0, customRegistry_1.discoverCustomEngineManifests)(root, additionalEngineDir);
1092
- for (const manifest of manifests) {
1093
- if (!manifestsById.has(manifest.id)) {
1094
- manifestsById.set(manifest.id, {
1095
- id: manifest.id,
1096
- displayName: manifest.displayName || manifest.id,
1097
- description: manifest.description,
1098
- defaultModel: manifest.model?.defaultModel,
1099
- });
1100
- }
1101
- }
1102
- }
1103
- catch (e) {
1104
- const errorMsg = e instanceof Error ? e.message : String(e);
1105
- log(outputChannel, `[AgentIDE] Custom engine list warning for root ${root}: ${errorMsg}`);
1106
- }
1107
- }
1108
- if (manifestsById.size === 0) {
1109
- try {
1110
- const manifests = (0, customRegistry_1.discoverCustomEngineManifests)(undefined, additionalEngineDir);
1111
- for (const manifest of manifests) {
1112
- manifestsById.set(manifest.id, {
1113
- id: manifest.id,
1114
- displayName: manifest.displayName || manifest.id,
1115
- description: manifest.description,
1116
- defaultModel: manifest.model?.defaultModel,
1117
- });
1118
- }
1119
- }
1120
- catch (e) {
1121
- const errorMsg = e instanceof Error ? e.message : String(e);
1122
- log(outputChannel, `[AgentIDE] Custom engine list error: ${errorMsg}`);
1123
- }
1124
- }
1125
- log(outputChannel, `[AgentIDE] Custom engine list: ${manifestsById.size} discovered (${Array.from(manifestsById.keys()).join(", ") || "none"}) from roots: ${candidateRoots.join("; ") || "(home only)"}`);
1126
- return Array.from(manifestsById.values());
1127
- }));
1128
- // Uninstall a custom engine from the default home install root
1129
- context.subscriptions.push(vscode.commands.registerCommand("agentide.engine.uninstall", async (args) => {
1130
- const { listInstalledCustomEngines, uninstallCustomEngine, } = await import("./engines/install.js");
1131
- let engineId = args?.id?.trim();
1132
- let displayName = engineId;
1133
- if (!engineId) {
1134
- const installed = await listInstalledCustomEngines();
1135
- if (installed.length === 0) {
1136
- showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: No custom engines are installed`);
1137
- return;
1138
- }
1139
- const selected = await vscode.window.showQuickPick(installed.map(engine => ({
1140
- label: engine.displayName,
1141
- description: engine.id,
1142
- detail: engine.installDir,
1143
- engine,
1144
- })), {
1145
- placeHolder: "Select a custom engine to uninstall",
1146
- title: "Uninstall Custom Engine",
1147
- });
1148
- if (!selected) {
1149
- return;
1150
- }
1151
- engineId = selected.engine.id;
1152
- displayName = selected.engine.displayName;
1153
- }
1154
- if (!engineId) {
1155
- return;
1156
- }
1157
- if (args?.skipConfirmation !== true) {
1158
- const confirmed = await vscode.window.showWarningMessage(`Uninstall custom engine "${displayName || engineId}"?`, { modal: true }, "Uninstall", "Cancel");
1159
- if (confirmed !== "Uninstall") {
1160
- return;
1161
- }
1162
- }
1163
- const result = await uninstallCustomEngine(engineId, { logger: outputChannel });
1164
- if (!result.removed) {
1165
- showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: Custom engine "${result.id}" is not installed`);
1166
- return;
1167
- }
1168
- clearCustomEngineRuntimeCache(state, result.id);
1169
- const { invalidateLocalIndex } = await import("./store/oramaIndex.js");
1170
- invalidateLocalIndex();
1171
- await refreshCustomEnginePicker(outputChannel);
1172
- showInfo(`Uninstalled engine "${result.displayName || result.id}"`);
1173
- }));
1174
- // Publish custom engine to store (fork + PR)
1175
- context.subscriptions.push(vscode.commands.registerCommand("agentide.engine.publish", async () => {
1176
- const { workspaceRoot } = getWorkspaceRoot(outputChannel);
1177
- const { collectEngineFiles, discoverPublishableEngines, isValidPublishVersion, validateEngineForPublish, } = await import("./engines/publish.js");
1178
- const { publishToStore, STORE_CONFIG, canPublishDirectlyToStore } = await import("./store/index.js");
1179
- const engines = await discoverPublishableEngines(workspaceRoot);
1180
- if (engines.length === 0) {
1181
- showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: No custom engines found. Add engine.manifest.json under .agent-hippo/engines/<id>/`);
1182
- return;
1183
- }
1184
- const selected = await vscode.window.showQuickPick(engines.map(engine => ({
1185
- label: engine.displayName,
1186
- description: engine.id,
1187
- detail: `${engine.sourceLabel}: ${engine.sourceDir}`,
1188
- engine,
1189
- })), {
1190
- placeHolder: "Select a custom engine to publish",
1191
- title: `Publish to ${STORE_CONFIG.owner}/${STORE_CONFIG.repo}`,
1192
- });
1193
- if (!selected) {
1194
- return;
1195
- }
1196
- try {
1197
- const validation = await validateEngineForPublish(selected.engine.sourceDir, selected.engine.id);
1198
- if (!validation.valid) {
1199
- showError(`${branding_1.AGENTIDE_BRAND_NAME}: Cannot publish - ${validation.errors.join(", ")}`);
1200
- return;
1201
- }
1202
- if (validation.warnings.length > 0) {
1203
- const proceed = await vscode.window.showWarningMessage(`Warnings: ${validation.warnings.join(", ")}`, "Publish Anyway", "Cancel");
1204
- if (proceed !== "Publish Anyway") {
1205
- return;
1206
- }
1207
- }
1208
- const versionInput = await vscode.window.showInputBox({
1209
- prompt: "Publish version (semver)",
1210
- value: validation.metadata?.suggestedVersion || "1.0.0",
1211
- placeHolder: "e.g., 1.0.0",
1212
- validateInput: value => value && isValidPublishVersion(value.replace(/^v/, ""))
1213
- ? null
1214
- : "Use semver format (e.g., 1.0.0)",
1215
- });
1216
- if (!versionInput) {
1217
- return;
1218
- }
1219
- const version = versionInput.replace(/^v/, "");
1220
- const changelog = await vscode.window.showInputBox({
1221
- prompt: "What changed in this version? (optional)",
1222
- placeHolder: "Initial release, bug fixes...",
1223
- });
1224
- const files = await collectEngineFiles(selected.engine.sourceDir);
1225
- const publishDirect = await canPublishDirectlyToStore();
1226
- const confirm = await vscode.window.showWarningMessage(publishDirect
1227
- ? `Publish "${selected.engine.id}" v${version} to ${STORE_CONFIG.owner}/${STORE_CONFIG.repo}?\n\nThis will open a pull request on the store repository.`
1228
- : `Submit "${selected.engine.id}" v${version} to ${STORE_CONFIG.owner}/${STORE_CONFIG.repo}?\n\nThis will create a pull request from your fork.`, { modal: true }, "Submit PR");
1229
- if (confirm !== "Submit PR") {
1230
- return;
1231
- }
1232
- const result = await vscode.window.withProgress({
1233
- location: vscode.ProgressLocation.Window,
1234
- title: `Publishing engine ${selected.engine.id} v${version}`,
1235
- cancellable: false,
1236
- }, async (progress) => {
1237
- progress.report({
1238
- message: publishDirect
1239
- ? `Publishing to ${STORE_CONFIG.owner}/${STORE_CONFIG.repo}...`
1240
- : "Preparing fork...",
1241
- });
1242
- const res = await publishToStore({
1243
- type: "engine",
1244
- slug: selected.engine.id,
1245
- version,
1246
- files,
1247
- changelog,
1248
- }, outputChannel);
1249
- progress.report({ message: "Creating PR..." });
1250
- return res;
1251
- });
1252
- const viewAction = await vscode.window.showInformationMessage(`Published engine "${selected.engine.id}" v${version}! PR created.`, "View PR");
1253
- if (viewAction === "View PR") {
1254
- vscode.env.openExternal(vscode.Uri.parse(result.prUrl));
1255
- }
1256
- }
1257
- catch (e) {
1258
- const errorMsg = e instanceof Error ? e.message : String(e);
1259
- log(outputChannel, `[AgentIDE] Engine publish error: ${errorMsg}`);
1260
- showError(`${branding_1.AGENTIDE_BRAND_NAME}: ${errorMsg}`);
1261
- }
1262
- }));
1263
- // Uninstall agent pack
1264
- context.subscriptions.push(vscode.commands.registerCommand("agentide.pack.uninstall", async () => {
1265
- const { workspaceRoot } = getWorkspaceRoot(outputChannel);
1266
- const { AgentPackManager, isDefaultAgent } = await import("./agentpack/index.js");
1267
- const packManager = new AgentPackManager(syncService, () => workspaceRoot, () => config.storagePath, outputChannel);
1268
- const packs = await packManager.listInstalled();
1269
- // Filter out the default agent - it cannot be uninstalled
1270
- const uninstallablePacks = packs.filter((p) => !isDefaultAgent(p.id));
1271
- if (uninstallablePacks.length === 0) {
1272
- showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: No agent packs available to uninstall`);
1273
- return;
1274
- }
1275
- const items = uninstallablePacks.map((p) => ({
1276
- label: p.id,
1277
- description: `v${p.version}${state.activePackId === p.id ? " (active)" : ""}`,
1278
- }));
1279
- const selected = await vscode.window.showQuickPick(items, {
1280
- placeHolder: "Select a pack to uninstall",
1281
- title: "Uninstall Agent Pack",
1282
- });
1283
- if (!selected) {
1284
- return;
1285
- }
1286
- const packIdToUninstall = selected.label;
1287
- const wasActive = state.activePackId === packIdToUninstall;
1288
- const confirm = await vscode.window.showWarningMessage(`Uninstall agent pack "${packIdToUninstall}"?${wasActive ? " This will switch to the default agent." : ""}`, { modal: true }, "Uninstall", "Cancel");
1289
- if (confirm !== "Uninstall") {
1290
- return;
1291
- }
1292
- try {
1293
- await packManager.uninstall(packIdToUninstall);
1294
- // If uninstalling the active pack, switch to default agent
1295
- if (wasActive) {
1296
- const appliedPackId = await syncService.switchToPack(workspaceRoot, undefined, // Switch to default
1297
- outputChannel, { importDerivedSkills: true });
1298
- state.activePackId = appliedPackId;
1299
- syncService.setActivePackId(workspaceRoot, appliedPackId);
1300
- log(outputChannel, `[AgentIDE] Switched to default agent after uninstalling active pack`);
1301
- // Notify workbench to update its pack state
1302
- try {
1303
- await vscode.commands.executeCommand("agentide.applyPackPreferences", {
1304
- packId: "default",
1305
- silent: true,
1306
- });
1307
- }
1308
- catch {
1309
- // Workbench command may not be available
1310
- }
1311
- }
1312
- showInfo(`AgentIDE: Uninstalled pack "${packIdToUninstall}"${wasActive ? " - switched to default agent" : ""}`);
1313
- }
1314
- catch (e) {
1315
- const errorMsg = e instanceof Error ? e.message : String(e);
1316
- log(outputChannel, `[AgentIDE] Pack uninstall error: ${errorMsg}`);
1317
- showError(`AgentIDE: Failed to uninstall pack - ${errorMsg}`);
1318
- }
1319
- }));
1320
- // Set active pack (for next request) - syncs pack content to workspace .claude/.codex
1321
- // NOTE: This is an INTERNAL command (not in package.json contributions).
1322
- // It only handles file syncing. Mode/model switching is done via agentide.applyPackPreferences
1323
- // on the workbench side. For interactive UI, use workbench.action.chat.openAgentPackPicker.
1324
- context.subscriptions.push(vscode.commands.registerCommand("agentide.pack.setActive", async (args) => {
1325
- if (!args?.packId) {
1326
- throw new Error("packId is required. Use workbench.action.chat.openAgentPackPicker for interactive selection.");
1327
- }
1328
- const { workspaceRoot } = getWorkspaceRoot(outputChannel);
1329
- // Switch pack and sync derived dirs
1330
- const packId = args.packId === "default" ? undefined : args.packId;
1331
- const appliedPackId = await syncService.switchToPack(workspaceRoot, packId, outputChannel, { importDerivedSkills: true });
1332
- state.activePackId = appliedPackId;
1333
- // Track active pack in SyncService for file-watcher awareness
1334
- syncService.setActivePackId(workspaceRoot, appliedPackId);
1335
- log(outputChannel, `[AgentIDE] Active pack switched to: ${appliedPackId ?? "default"}`);
1336
- await state.remotePackStatusBar?.refresh({ notifyOnActivate: true });
1337
- // Note: Pack ID is now persisted by the workbench (IAgentPackService)
1338
- // The extension just handles file sync operations
1339
- return { activePackId: state.activePackId ?? "default" };
1340
- }));
1341
- // Get active pack ID
1342
- context.subscriptions.push(vscode.commands.registerCommand("agentide.pack.getActive", () => {
1343
- return { activePackId: state.activePackId ?? "default" };
1344
- }));
1345
- // Remote pack URL for the active (or specified) pack — used by the workbench to bypass
1346
- // local engine credential resolution when spec.remote.url is set.
1347
- context.subscriptions.push(vscode.commands.registerCommand("agentide.pack.getRemoteServeUrl", async (args) => {
1348
- const { workspaceRoot } = getWorkspaceRoot(outputChannel);
1349
- const packId = args?.packId?.trim()
1350
- || syncService.getActivePackId(workspaceRoot)
1351
- || state.activePackId;
1352
- if (!packId || packId === 'default') {
1353
- return undefined;
1354
- }
1355
- const manifest = await syncService.getActiveAgentManifest(workspaceRoot, outputChannel, packId);
1356
- const remoteUrl = (0, serveClient_js_1.getRemoteServeUrl)(manifest);
1357
- if (!remoteUrl) {
1358
- return undefined;
1359
- }
1360
- return {
1361
- packId,
1362
- remoteUrl,
1363
- preferredEngine: manifest?.spec?.engine,
1364
- };
1365
- }));
1366
- // Create a new agent pack scaffold
1367
- context.subscriptions.push(vscode.commands.registerCommand("agentide.pack.create", async () => {
1368
- const { workspaceRoot, isHomeFallback } = getWorkspaceRoot(outputChannel);
1369
- if (isHomeFallback) {
1370
- await ensureFallbackDirectoryExists(outputChannel);
1371
- }
1372
- // Get current chat state to capture current model (best effort)
1373
- // We use modelId (e.g., 'claude-sonnet-4-20250514', 'litellm::gpt-nano') for reliable matching
1374
- let currentModelId;
1375
- try {
1376
- const chatState = await vscode.commands.executeCommand("agentide.getChatState");
1377
- currentModelId = chatState?.modelId;
1378
- log(outputChannel, `[AgentIDE] Current chat state: mode=${chatState?.mode}, modelId=${currentModelId}, modelName=${chatState?.modelName}`);
1379
- }
1380
- catch {
1381
- // Command may not be available yet
1382
- }
1383
- // Prompt for pack name with inline validation (including "already exists" check)
1384
- const rawPackName = await vscode.window.showInputBox({
1385
- prompt: "Enter the agent pack name",
1386
- placeHolder: "e.g., code-reviewer, security-auditor, My Code Reviewer",
1387
- validateInput: async (input) => {
1388
- const normalized = (0, paths_1.normalizePackName)(input);
1389
- // Check for invalid name first
1390
- const nameError = (0, paths_1.getPackNameError)(normalized);
1391
- if (nameError) {
1392
- return nameError;
1393
- }
1394
- // Check if pack already exists
1395
- const existingPackRoot = path.join((0, paths_1.getAgentideDir)(workspaceRoot), paths_1.AGENT_CONSTANTS.AGENTS_DIR, normalized);
1396
- if (await (0, utils_1.pathExists)(existingPackRoot)) {
1397
- return `A pack named "${normalized}" already exists. Choose a different name.`;
1398
- }
1399
- return undefined;
1400
- },
1401
- });
1402
- if (!rawPackName) {
1403
- return;
1404
- }
1405
- // Normalize the pack name (lowercase, hyphens, no special chars)
1406
- const packName = (0, paths_1.normalizePackName)(rawPackName);
1407
- log(outputChannel, `[AgentIDE] Pack name normalized: "${rawPackName}" -> "${packName}"`);
1408
- const packRoot = path.join((0, paths_1.getAgentideDir)(workspaceRoot), paths_1.AGENT_CONSTANTS.AGENTS_DIR, packName);
1409
- // Prompt for description
1410
- const description = await vscode.window.showInputBox({
1411
- prompt: "Enter a short description for the pack",
1412
- placeHolder: "e.g., Advanced code review agent with security analysis",
1413
- });
1414
- // Prompt for preferred engine
1415
- const engineChoice = await vscode.window.showQuickPick([
1416
- {
1417
- label: "Claude",
1418
- description: "Anthropic Claude Agent SDK",
1419
- engine: "claude",
1420
- },
1421
- { label: "Codex", description: "OpenAI Codex SDK", engine: "codex" },
1422
- ], {
1423
- placeHolder: "Select the preferred engine for this pack",
1424
- title: "Preferred Engine",
1425
- });
1426
- if (!engineChoice) {
1427
- return;
1428
- }
1429
- try {
1430
- await fs_1.promises.mkdir(path.join(packRoot, "rules"), { recursive: true });
1431
- await fs_1.promises.mkdir(path.join(packRoot, "skills"), { recursive: true });
1432
- await fs_1.promises.mkdir(path.join(packRoot, "mcp"), { recursive: true });
1433
- // Create agent.yaml manifest using centralized template
1434
- // Use current model if available, otherwise let the template use the default
1435
- const manifest = (0, paths_1.generateAgentYaml)(packName, {
1436
- description: description || undefined,
1437
- engine: engineChoice.engine,
1438
- model: currentModelId,
1439
- });
1440
- await fs_1.promises.writeFile(path.join(packRoot, "agent.yaml"), manifest);
1441
- // Create AGENTS.md using centralized template
1442
- const agentsMd = (0, paths_1.generateAgentsMd)(packName, {
1443
- description: description || undefined,
1444
- });
1445
- await fs_1.promises.writeFile(path.join(packRoot, "AGENTS.md"), agentsMd);
1446
- // Note: We don't sync pack-internal derived dirs (.codex/.claude) here.
1447
- // Those folders should only exist at workspace root level, not inside packs.
1448
- // The pack's content will be synced to workspace root when it's activated.
1449
- // Register the pack in the manifest
1450
- const { AgentPackManager } = await import("./agentpack/index.js");
1451
- const packManager = new AgentPackManager(syncService, () => workspaceRoot, () => config.storagePath, outputChannel);
1452
- await packManager.installFromLocal(packRoot);
1453
- log(outputChannel, `[AgentIDE] Created agent pack scaffold: ${packName}`);
1454
- showInfo(`AgentIDE: Created agent pack "${packName}" at ${paths_1.AGENT_CONSTANTS.AGENTIDE_DIR_NAME}/${paths_1.AGENT_CONSTANTS.AGENTS_DIR}/${packName}/`);
1455
- // Open the AGENTS.md file
1456
- const agentsMdUri = vscode.Uri.file(path.join(packRoot, "AGENTS.md"));
1457
- await vscode.window.showTextDocument(agentsMdUri);
1458
- // Offer agent-assisted configuration
1459
- const choice = await vscode.window.showInformationMessage(`Agent pack "${packName}" created. Would you like help generating a specialized configuration?`, "Yes, help me configure it", "No, I'll edit manually");
1460
- if (choice === "Yes, help me configure it") {
1461
- // Build a prompt that leverages the agentpack-creator skill
1462
- const configureQuery = [
1463
- `I just created a new agent pack called "${packName}"`,
1464
- description ? ` that should: ${description}.` : ".",
1465
- "\n\nPlease help me write a proper AGENTS.md file for this agent. ",
1466
- "Ask me clarifying questions about:\n",
1467
- "1. What specific tasks this agent should excel at\n",
1468
- "2. What domain expertise it should have\n",
1469
- "3. What constraints or limitations it should follow\n",
1470
- "4. How it should format its outputs\n\n",
1471
- `The AGENTS.md file is at: ${paths_1.AGENT_CONSTANTS.AGENTIDE_DIR_NAME}/agents/${packName}/AGENTS.md`,
1472
- ].join("");
1473
- // Open chat with the query - attach the AGENTS.md file for context
1474
- await vscode.commands.executeCommand("workbench.action.chat.open", {
1475
- query: configureQuery,
1476
- isPartialQuery: false,
1477
- mode: "agent",
1478
- attachFiles: [agentsMdUri],
1479
- });
1480
- }
1481
- }
1482
- catch (e) {
1483
- const errorMsg = e instanceof Error ? e.message : String(e);
1484
- log(outputChannel, `[AgentIDE] Pack create error: ${errorMsg}`);
1485
- showError(`AgentIDE: Failed to create pack - ${errorMsg}`);
1486
- }
1487
- }));
1488
- // -------------------------------------------------------------------------
1489
- // Agent Stores Commands (UAL + Hydration)
1490
- // -------------------------------------------------------------------------
1491
- // Share agent to User Library
1492
- context.subscriptions.push(vscode.commands.registerCommand("agentide.pack.share", async () => {
1493
- const { workspaceRoot } = getWorkspaceRoot(outputChannel);
1494
- const { AgentPackManager } = await import("./agentpack/index.js");
1495
- const packManager = new AgentPackManager(syncService, () => workspaceRoot, () => config.storagePath, outputChannel);
1496
- const packs = await packManager.listInstalledWithCleanup();
1497
- // Filter out default agent - can't share it
1498
- const shareable = packs.filter((p) => p.id !== "default");
1499
- if (shareable.length === 0) {
1500
- showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: No agents to share (create an agent first)`);
1501
- return;
1502
- }
1503
- const items = shareable.map((p) => ({
1504
- label: p.id,
1505
- description: `v${p.version}`,
1506
- }));
1507
- const selected = await vscode.window.showQuickPick(items, {
1508
- placeHolder: "Select an agent to share to User Library",
1509
- title: "Share Agent to User Library",
1510
- });
1511
- if (!selected) {
1512
- return;
1513
- }
1514
- try {
1515
- const version = await packManager.shareToUserLibrary(selected.label);
1516
- showInfo(`AgentIDE: Shared "${selected.label}" v${version} to User Library`);
1517
- }
1518
- catch (e) {
1519
- const errorMsg = e instanceof Error ? e.message : String(e);
1520
- log(outputChannel, `[AgentIDE] Share error: ${errorMsg}`);
1521
- showError(`AgentIDE: ${errorMsg}`);
1522
- }
1523
- }));
1524
- // Share skill to User Library
1525
- context.subscriptions.push(vscode.commands.registerCommand("agentide.skill.share", async () => {
1526
- const { workspaceRoot } = getWorkspaceRoot(outputChannel);
1527
- const { AgentPackManager } = await import("./agentpack/index.js");
1528
- const { getAgentSkillsDir, getUserSkillDir, } = await import("./agentpack/paths.js");
1529
- const { copyDirRecursive, pathExists } = await import("./utils.js");
1530
- const packManager = new AgentPackManager(syncService, () => workspaceRoot, () => config.storagePath, outputChannel);
1531
- // Get installed packs
1532
- const packs = await packManager.listInstalledWithCleanup();
1533
- if (packs.length === 0) {
1534
- showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: No agents found`);
1535
- return;
1536
- }
1537
- // Let user pick a pack
1538
- const packPick = await vscode.window.showQuickPick(packs.map((p) => ({ label: p.id, description: `v${p.version}` })), {
1539
- placeHolder: "Select agent containing the skill",
1540
- title: "Save Skill to User Library",
1541
- });
1542
- if (!packPick) {
1543
- return;
1544
- }
1545
- // List skills in that pack
1546
- const skillsDir = getAgentSkillsDir(workspaceRoot, packPick.label);
1547
- const skillsDirExists = await pathExists(skillsDir);
1548
- if (!skillsDirExists) {
1549
- showInfo(`AgentIDE: No skills found in ${packPick.label}`);
1550
- return;
1551
- }
1552
- const skillEntries = await fs_1.promises.readdir(skillsDir, { withFileTypes: true });
1553
- const skillDirs = skillEntries
1554
- .filter((e) => e.isDirectory() && !e.name.startsWith("."))
1555
- .map((e) => e.name);
1556
- if (skillDirs.length === 0) {
1557
- showInfo(`AgentIDE: No skills found in ${packPick.label}`);
1558
- return;
1559
- }
1560
- const skillPick = await vscode.window.showQuickPick(skillDirs.map((s) => ({ label: s })), {
1561
- placeHolder: "Select skill to save to User Library",
1562
- title: "Save Skill to User Library",
1563
- });
1564
- if (!skillPick) {
1565
- return;
1566
- }
1567
- const sourceDir = path.join(skillsDir, skillPick.label);
1568
- const targetDir = getUserSkillDir(skillPick.label);
1569
- // Check if skill already exists in library
1570
- if (await pathExists(targetDir)) {
1571
- const overwrite = await vscode.window.showWarningMessage(`Skill "${skillPick.label}" already exists in User Library. Overwrite?`, { modal: true }, "Overwrite", "Cancel");
1572
- if (overwrite !== "Overwrite") {
1573
- return;
1574
- }
1575
- await fs_1.promises.rm(targetDir, { recursive: true, force: true });
1576
- }
1577
- try {
1578
- await copyDirRecursive(sourceDir, targetDir);
1579
- // Register in local registry
1580
- const { getRegistry } = await import("./registry/index.js");
1581
- const registry = getRegistry(outputChannel);
1582
- await registry.registerSkill({
1583
- slug: skillPick.label,
1584
- displayName: skillPick.label,
1585
- latestVersion: "local",
1586
- tags: [],
1587
- stats: { installs: 1 },
1588
- });
1589
- // Invalidate local index cache
1590
- const { invalidateLocalIndex } = await import("./store/oramaIndex.js");
1591
- invalidateLocalIndex();
1592
- showInfo(`AgentIDE: Saved skill "${skillPick.label}" to User Library`);
1593
- }
1594
- catch (e) {
1595
- const errorMsg = e instanceof Error ? e.message : String(e);
1596
- log(outputChannel, `[AgentIDE] Share skill error: ${errorMsg}`);
1597
- showError(`AgentIDE: ${errorMsg}`);
1598
- }
1599
- }));
1600
- // Share MCP to User Library
1601
- context.subscriptions.push(vscode.commands.registerCommand("agentide.mcp.share", async () => {
1602
- const { workspaceRoot } = getWorkspaceRoot(outputChannel);
1603
- const { AgentPackManager } = await import("./agentpack/index.js");
1604
- const { getAgentMcpDir, getUserMcpServerDir, } = await import("./agentpack/paths.js");
1605
- const { copyDirRecursive, pathExists } = await import("./utils.js");
1606
- const packManager = new AgentPackManager(syncService, () => workspaceRoot, () => config.storagePath, outputChannel);
1607
- // Get installed packs
1608
- const packs = await packManager.listInstalledWithCleanup();
1609
- if (packs.length === 0) {
1610
- showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: No agents found`);
1611
- return;
1612
- }
1613
- // Let user pick a pack
1614
- const packPick = await vscode.window.showQuickPick(packs.map((p) => ({ label: p.id, description: `v${p.version}` })), {
1615
- placeHolder: "Select agent containing the MCP server",
1616
- title: "Save MCP Server to User Library",
1617
- });
1618
- if (!packPick) {
1619
- return;
1620
- }
1621
- // Read .mcp.json to get configured MCP servers
1622
- const mcpDir = getAgentMcpDir(workspaceRoot, packPick.label);
1623
- const mcpJsonPath = path.join(mcpDir, ".mcp.json");
1624
- let mcpConfig = {
1625
- mcpServers: {},
1626
- };
1627
- try {
1628
- const content = await fs_1.promises.readFile(mcpJsonPath, "utf-8");
1629
- mcpConfig = JSON.parse(content);
1630
- }
1631
- catch {
1632
- showInfo(`AgentIDE: No MCP servers configured in ${packPick.label}`);
1633
- return;
1634
- }
1635
- if (!mcpConfig.mcpServers ||
1636
- Object.keys(mcpConfig.mcpServers).length === 0) {
1637
- showInfo(`AgentIDE: No MCP servers configured in ${packPick.label}`);
1638
- return;
1639
- }
1640
- const mcpNames = Object.keys(mcpConfig.mcpServers);
1641
- const mcpPick = await vscode.window.showQuickPick(mcpNames.map((m) => ({ label: m })), {
1642
- placeHolder: "Select MCP server to save to User Library",
1643
- title: "Save MCP Server to User Library",
1644
- });
1645
- if (!mcpPick) {
1646
- return;
1647
- }
1648
- const targetDir = getUserMcpServerDir(mcpPick.label);
1649
- // Check if MCP already exists in library
1650
- if (await pathExists(targetDir)) {
1651
- const overwrite = await vscode.window.showWarningMessage(`MCP "${mcpPick.label}" already exists in User Library. Overwrite?`, { modal: true }, "Overwrite", "Cancel");
1652
- if (overwrite !== "Overwrite") {
1653
- return;
1654
- }
1655
- await fs_1.promises.rm(targetDir, { recursive: true, force: true });
1656
- }
1657
- try {
1658
- await fs_1.promises.mkdir(targetDir, { recursive: true });
1659
- // Save the MCP config as mcp.json
1660
- const mcpServerConfig = mcpConfig.mcpServers[mcpPick.label];
1661
- await fs_1.promises.writeFile(path.join(targetDir, "mcp.json"), JSON.stringify({
1662
- name: mcpPick.label,
1663
- ...mcpServerConfig,
1664
- }, null, 2));
1665
- // Copy any additional files from the MCP subdirectory if it exists
1666
- const mcpSubDir = path.join(mcpDir, mcpPick.label);
1667
- if (await pathExists(mcpSubDir)) {
1668
- await copyDirRecursive(mcpSubDir, targetDir);
1669
- }
1670
- // Register in local registry
1671
- const { getRegistry } = await import("./registry/index.js");
1672
- const registry = getRegistry(outputChannel);
1673
- await registry.registerMcp({
1674
- slug: mcpPick.label,
1675
- displayName: mcpPick.label,
1676
- transport: mcpServerConfig.transport || "stdio",
1677
- latestVersion: "local",
1678
- tags: [],
1679
- stats: { installs: 1 },
1680
- });
1681
- // Invalidate local index cache
1682
- const { invalidateLocalIndex } = await import("./store/oramaIndex.js");
1683
- invalidateLocalIndex();
1684
- showInfo(`AgentIDE: Saved MCP "${mcpPick.label}" to User Library`);
1685
- }
1686
- catch (e) {
1687
- const errorMsg = e instanceof Error ? e.message : String(e);
1688
- log(outputChannel, `[AgentIDE] Share MCP error: ${errorMsg}`);
1689
- showError(`AgentIDE: ${errorMsg}`);
1690
- }
1691
- }));
1692
- // Publish agent to store (fork → PR workflow)
1693
- context.subscriptions.push(vscode.commands.registerCommand("agentide.pack.publish", async () => {
1694
- await (0, githubStoreGate_js_1.ensureGitHubStoreAccess)(context);
1695
- const { workspaceRoot } = getWorkspaceRoot(outputChannel);
1696
- const { AgentPackManager, validateForPublish } = await import("./agentpack/index.js");
1697
- const { publishToStore, STORE_CONFIG } = await import("./store/index.js");
1698
- const packManager = new AgentPackManager(syncService, () => workspaceRoot, () => config.storagePath, outputChannel);
1699
- const packs = await packManager.listInstalledWithCleanup();
1700
- const publishable = packs.filter((p) => p.id !== "default");
1701
- if (publishable.length === 0) {
1702
- showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: No agents to publish (create an agent first)`);
1703
- return;
1704
- }
1705
- // Select pack
1706
- const selectedPack = await vscode.window.showQuickPick(publishable.map((p) => ({
1707
- label: p.id,
1708
- description: `v${p.version}`,
1709
- })), {
1710
- placeHolder: "Select an agent pack to publish",
1711
- title: `Publish to ${STORE_CONFIG.owner}/${STORE_CONFIG.repo}`,
1712
- });
1713
- if (!selectedPack) {
1714
- return;
1715
- }
1716
- // Validate before publishing
1717
- const validation = await validateForPublish(workspaceRoot, selectedPack.label);
1718
- if (!validation.valid) {
1719
- showError(`AgentIDE: Cannot publish - ${validation.errors.join(", ")}`);
1720
- return;
1721
- }
1722
- if (validation.warnings.length > 0) {
1723
- const proceed = await vscode.window.showWarningMessage(`Warnings: ${validation.warnings.join(", ")}`, "Publish Anyway", "Cancel");
1724
- if (proceed !== "Publish Anyway") {
1725
- return;
1726
- }
1727
- }
1728
- // Changelog
1729
- const changelog = await vscode.window.showInputBox({
1730
- prompt: "What changed in this version? (optional)",
1731
- placeHolder: "Added new features, fixed bugs...",
1732
- });
1733
- // Collect files
1734
- const { getAgentRoot } = await import("./agentpack/paths.js");
1735
- const agentRoot = getAgentRoot(workspaceRoot, selectedPack.label);
1736
- const files = [];
1737
- async function collectFiles(dir, prefix) {
1738
- const entries = await fs_1.promises.readdir(dir);
1739
- for (const entry of entries) {
1740
- if (entry.startsWith(".")) {
1741
- continue;
1742
- }
1743
- const fullPath = path.join(dir, entry);
1744
- const relativePath = prefix ? `${prefix}/${entry}` : entry;
1745
- const stat = await fs_1.promises.stat(fullPath);
1746
- if (stat.isDirectory()) {
1747
- await collectFiles(fullPath, relativePath);
1748
- }
1749
- else {
1750
- const content = await fs_1.promises.readFile(fullPath, "utf-8");
1751
- files.push({ path: relativePath, content });
1752
- }
1753
- }
1754
- }
1755
- await collectFiles(agentRoot, "");
1756
- const pack = publishable.find((p) => p.id === selectedPack.label);
1757
- // Confirm
1758
- const confirm = await vscode.window.showWarningMessage(`Submit "${pack.id}" v${pack.version} to ${STORE_CONFIG.owner}/${STORE_CONFIG.repo}?\n\nThis will create a pull request.`, { modal: true }, "Submit PR");
1759
- if (confirm !== "Submit PR") {
1760
- return;
1761
- }
1762
- try {
1763
- const result = await vscode.window.withProgress({
1764
- location: vscode.ProgressLocation.Window,
1765
- title: `Publishing ${pack.id} v${pack.version}`,
1766
- cancellable: false,
1767
- }, async (progress) => {
1768
- progress.report({ message: "Preparing fork..." });
1769
- const res = await publishToStore({
1770
- type: "pack",
1771
- slug: pack.id,
1772
- version: pack.version,
1773
- files,
1774
- changelog,
1775
- }, outputChannel);
1776
- progress.report({ message: "Creating PR..." });
1777
- return res;
1778
- });
1779
- const viewAction = await vscode.window.showInformationMessage(`Created PR #${result.prNumber} for ${pack.id} v${pack.version}`, "View PR");
1780
- if (viewAction === "View PR") {
1781
- vscode.env.openExternal(vscode.Uri.parse(result.prUrl));
1782
- }
1783
- }
1784
- catch (e) {
1785
- const errorMsg = e instanceof Error ? e.message : String(e);
1786
- log(outputChannel, `[AgentIDE] Publish error: ${errorMsg}`);
1787
- showError(`AgentIDE: ${errorMsg}`);
1788
- }
1789
- }));
1790
- // Install agent from GitHub
1791
- context.subscriptions.push(vscode.commands.registerCommand("agentide.pack.installFromGitHub", async (sourceArg) => {
1792
- const { workspaceRoot } = getWorkspaceRoot(outputChannel);
1793
- const { installFromGitHub } = await import("./agentpack/index.js");
1794
- // Get source from arg or prompt
1795
- let source = sourceArg;
1796
- if (!source) {
1797
- source = await vscode.window.showInputBox({
1798
- prompt: "Enter GitHub repository URL or owner/repo",
1799
- placeHolder: "e.g., user/my-agent-pack or github://user/pack@v1.0.0",
1800
- validateInput: (value) => {
1801
- if (!value.trim()) {
1802
- return "Please enter a repository";
1803
- }
1804
- if (!value.includes("/")) {
1805
- return "Expected format: owner/repo or github://owner/repo@version";
1806
- }
1807
- return null;
1808
- },
1809
- });
1810
- }
1811
- if (!source) {
1812
- return;
1813
- }
1814
- try {
1815
- const result = await vscode.window.withProgress({
1816
- location: vscode.ProgressLocation.Window,
1817
- title: "Installing from GitHub",
1818
- cancellable: false,
1819
- }, async (progress) => {
1820
- progress.report({ message: "Downloading..." });
1821
- return await installFromGitHub(workspaceRoot, {
1822
- source,
1823
- force: false,
1824
- }, outputChannel);
1825
- });
1826
- // Refresh pack list
1827
- await vscode.commands.executeCommand("agentide.packsChanged");
1828
- await syncService.seedAgentDataIfNeeded(workspaceRoot, result.agentId, outputChannel);
1829
- const activateAction = await vscode.window.showInformationMessage(`Installed ${result.agentId} ${result.version}!`, "Activate");
1830
- if (activateAction === "Activate") {
1831
- await vscode.commands.executeCommand("agentide.pack.switch", result.agentId);
1832
- }
1833
- }
1834
- catch (e) {
1835
- const errorMsg = e instanceof Error ? e.message : String(e);
1836
- // Check if it's "already exists" error
1837
- if (errorMsg.includes("already exists")) {
1838
- const overwrite = await vscode.window.showWarningMessage(errorMsg, "Overwrite", "Cancel");
1839
- if (overwrite === "Overwrite") {
1840
- try {
1841
- const result = await vscode.window.withProgress({
1842
- location: vscode.ProgressLocation.Window,
1843
- title: "Installing from GitHub",
1844
- cancellable: false,
1845
- }, async (progress) => {
1846
- progress.report({ message: "Downloading..." });
1847
- return await installFromGitHub(workspaceRoot, {
1848
- source,
1849
- force: true,
1850
- }, outputChannel);
1851
- });
1852
- await vscode.commands.executeCommand("agentide.packsChanged");
1853
- await syncService.seedAgentDataIfNeeded(workspaceRoot, result.agentId, outputChannel);
1854
- showInfo(`AgentIDE: Installed ${result.agentId} ${result.version}`);
1855
- }
1856
- catch (e2) {
1857
- const errorMsg2 = e2 instanceof Error ? e2.message : String(e2);
1858
- showError(`AgentIDE: ${errorMsg2}`);
1859
- }
1860
- }
1861
- }
1862
- else {
1863
- log(outputChannel, `[AgentIDE] Install error: ${errorMsg}`);
1864
- showError(`AgentIDE: ${errorMsg}`);
1865
- }
1866
- }
1867
- }));
1868
- // Browse User Library
1869
- context.subscriptions.push(vscode.commands.registerCommand("agentide.pack.browseLibrary", async () => {
1870
- const { workspaceRoot } = getWorkspaceRoot(outputChannel);
1871
- const { AgentPackManager } = await import("./agentpack/index.js");
1872
- const packManager = new AgentPackManager(syncService, () => workspaceRoot, () => config.storagePath, outputChannel);
1873
- const agents = await packManager.listUserLibrary();
1874
- if (agents.length === 0) {
1875
- showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: User Library is empty. Share agents with "${branding_1.AGENTIDE_BRAND_NAME}: Share Agent to User Library"`);
1876
- return;
1877
- }
1878
- const items = agents.map((a) => ({
1879
- label: a.id,
1880
- description: a.currentVersion
1881
- ? `v${a.currentVersion}`
1882
- : `${a.versions.length} version(s)`,
1883
- detail: a.description ||
1884
- `Preferred engine: ${a.preferredEngine || "unknown"}`,
1885
- agentId: a.id,
1886
- currentVersion: a.currentVersion,
1887
- }));
1888
- const selected = await vscode.window.showQuickPick(items, {
1889
- placeHolder: "Select an agent to install",
1890
- title: "User Agent Library",
1891
- });
1892
- if (!selected) {
1893
- return;
1894
- }
1895
- // Offer to install
1896
- const action = await vscode.window.showQuickPick([
1897
- { label: "Install to Workspace", action: "install" },
1898
- { label: "Cancel", action: "cancel" },
1899
- ], {
1900
- placeHolder: `What would you like to do with "${selected.agentId}"?`,
1901
- });
1902
- if (action?.action !== "install") {
1903
- return;
1904
- }
1905
- try {
1906
- const result = await packManager.installAgentToWorkspace(selected.agentId);
1907
- if (result.installed) {
1908
- const msg = result.hydrated
1909
- ? `Installed "${selected.agentId}" v${result.version} to workspace from User Library`
1910
- : `"${selected.agentId}" is already installed in this workspace`;
1911
- showInfo(`AgentIDE: ${msg}`);
1912
- }
1913
- else {
1914
- showError(`AgentIDE: Failed to install "${selected.agentId}"`);
1915
- }
1916
- }
1917
- catch (e) {
1918
- const errorMsg = e instanceof Error ? e.message : String(e);
1919
- log(outputChannel, `[AgentIDE] Install error: ${errorMsg}`);
1920
- showError(`AgentIDE: ${errorMsg}`);
1921
- }
1922
- }));
1923
- // Publish skill to GitHub
1924
- context.subscriptions.push(vscode.commands.registerCommand("agentide.skill.publish", async () => {
1925
- const { workspaceRoot } = getWorkspaceRoot(outputChannel);
1926
- // Find skills in current workspace
1927
- const skillsDir = path.join(workspaceRoot, ".agent-hippo", "agents");
1928
- const skills = [];
1929
- if (await (0, utils_1.pathExists)(skillsDir)) {
1930
- // Look for SKILL.md in agent packs
1931
- const agents = await fs_1.promises.readdir(skillsDir);
1932
- for (const agent of agents) {
1933
- const agentSkillsDir = path.join(skillsDir, agent, "skills");
1934
- if (await (0, utils_1.pathExists)(agentSkillsDir)) {
1935
- const skillFolders = await fs_1.promises.readdir(agentSkillsDir);
1936
- for (const skill of skillFolders) {
1937
- const skillPath = path.join(agentSkillsDir, skill);
1938
- const skillMd = path.join(skillPath, "SKILL.md");
1939
- if (await (0, utils_1.pathExists)(skillMd)) {
1940
- skills.push({ name: skill, path: skillPath });
1941
- }
1942
- }
1943
- }
1944
- }
1945
- }
1946
- if (skills.length === 0) {
1947
- showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: No skills found. Create a skill with SKILL.md in your agent's skills/ folder.`);
1948
- return;
1949
- }
1950
- // Select skill
1951
- const selected = await vscode.window.showQuickPick(skills.map((s) => ({ label: s.name, path: s.path })), { placeHolder: "Select a skill to publish" });
1952
- if (!selected) {
1953
- return;
1954
- }
1955
- try {
1956
- const { validateSkillForPublish, collectSkillFiles } = await import("./skills/publish.js");
1957
- const { publishToStore } = await import("./store/index.js");
1958
- const validation = await validateSkillForPublish(selected.path);
1959
- if (!validation.valid) {
1960
- showError(`AgentIDE: ${validation.errors.join(", ")}`);
1961
- return;
1962
- }
1963
- // Get version (optional for skills)
1964
- const version = validation.metadata?.version ||
1965
- (await vscode.window.showInputBox({
1966
- prompt: "Version (semver)",
1967
- placeHolder: "e.g., 1.0.0",
1968
- validateInput: (v) => /^\d+\.\d+\.\d+/.test(v)
1969
- ? null
1970
- : "Use semver format (e.g., 1.0.0)",
1971
- }));
1972
- if (!version) {
1973
- return;
1974
- }
1975
- // Collect files
1976
- const files = await collectSkillFiles(selected.path);
1977
- // Publish to store via fork + PR with progress
1978
- const result = await vscode.window.withProgress({
1979
- location: vscode.ProgressLocation.Window,
1980
- title: `Publishing skill "${selected.label}"`,
1981
- cancellable: false,
1982
- }, async (progress) => {
1983
- progress.report({ message: "Preparing fork..." });
1984
- const res = await publishToStore({
1985
- type: "skill",
1986
- slug: selected.label,
1987
- version,
1988
- files,
1989
- }, outputChannel);
1990
- progress.report({ message: "Creating PR..." });
1991
- return res;
1992
- });
1993
- // Register in local registry
1994
- const { getRegistry } = await import("./registry/index.js");
1995
- const { STORE_CONFIG } = await import("./store/index.js");
1996
- const registry = getRegistry(outputChannel);
1997
- await registry.registerSkill({
1998
- slug: selected.label,
1999
- displayName: validation.metadata?.name || selected.label,
2000
- description: validation.metadata?.description,
2001
- github: { owner: STORE_CONFIG.owner, repo: STORE_CONFIG.repo },
2002
- latestVersion: version,
2003
- tags: validation.metadata?.tags || [],
2004
- stats: { installs: 0 },
2005
- });
2006
- const viewAction = await vscode.window.showInformationMessage(`Published skill "${selected.label}" v${version}! PR created.`, "View PR");
2007
- if (viewAction === "View PR") {
2008
- vscode.env.openExternal(vscode.Uri.parse(result.prUrl));
2009
- }
2010
- }
2011
- catch (e) {
2012
- const errorMsg = e instanceof Error ? e.message : String(e);
2013
- log(outputChannel, `[AgentIDE] Skill publish error: ${errorMsg}`);
2014
- showError(`AgentIDE: ${errorMsg}`);
2015
- }
2016
- }));
2017
- // Publish MCP server to store
2018
- context.subscriptions.push(vscode.commands.registerCommand("agentide.mcp.publish", async () => {
2019
- const { workspaceRoot } = getWorkspaceRoot(outputChannel);
2020
- // Find MCP configs in current workspace
2021
- const agentsDir = path.join(workspaceRoot, ".agentide", "agents");
2022
- const mcpConfigs = [];
2023
- if (await (0, utils_1.pathExists)(agentsDir)) {
2024
- const agents = await fs_1.promises.readdir(agentsDir);
2025
- for (const agent of agents) {
2026
- const mcpDir = path.join(agentsDir, agent, "mcp");
2027
- const mcpConfigPath = path.join(mcpDir, ".mcp.json");
2028
- if (await (0, utils_1.pathExists)(mcpConfigPath)) {
2029
- try {
2030
- const content = await fs_1.promises.readFile(mcpConfigPath, "utf-8");
2031
- const config = JSON.parse(content);
2032
- // Each MCP config can have multiple servers
2033
- if (config.mcpServers) {
2034
- for (const serverName of Object.keys(config.mcpServers)) {
2035
- mcpConfigs.push({
2036
- name: serverName,
2037
- agentId: agent,
2038
- configPath: mcpConfigPath,
2039
- mcpDir,
2040
- });
2041
- }
2042
- }
2043
- }
2044
- catch {
2045
- // Skip invalid configs
2046
- }
2047
- }
2048
- }
2049
- }
2050
- if (mcpConfigs.length === 0) {
2051
- showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: No MCP servers found. Add MCP servers to your agent's mcp/.mcp.json file.`);
2052
- return;
2053
- }
2054
- // Select MCP server
2055
- const selected = await vscode.window.showQuickPick(mcpConfigs.map((m) => ({
2056
- label: m.name,
2057
- description: `from ${m.agentId}`,
2058
- detail: m.configPath,
2059
- config: m,
2060
- })), { placeHolder: "Select an MCP server to publish" });
2061
- if (!selected) {
2062
- return;
2063
- }
2064
- try {
2065
- const { publishToStore, STORE_CONFIG } = await import("./store/index.js");
2066
- const { collectMcpFiles, validateMcpConfig } = await import("./mcp/publish.js");
2067
- const { getRegistry } = await import("./registry/index.js");
2068
- // Read the full config
2069
- const configContent = await fs_1.promises.readFile(selected.config.configPath, "utf-8");
2070
- const fullConfig = JSON.parse(configContent);
2071
- const serverConfig = fullConfig.mcpServers[selected.config.name];
2072
- // Validate
2073
- const validation = validateMcpConfig({
2074
- name: selected.config.name,
2075
- version: serverConfig.version || "1.0.0",
2076
- description: serverConfig.description,
2077
- transport: serverConfig.transport || "stdio",
2078
- command: serverConfig.command,
2079
- args: serverConfig.args,
2080
- env: serverConfig.env,
2081
- url: serverConfig.url,
2082
- npmPackage: serverConfig.npmPackage,
2083
- });
2084
- if (!validation.valid) {
2085
- showError(`AgentIDE: ${validation.errors.join(", ")}`);
2086
- return;
2087
- }
2088
- // Get version (if not in config)
2089
- const version = serverConfig.version ||
2090
- (await vscode.window.showInputBox({
2091
- prompt: "Version (semver)",
2092
- placeHolder: "e.g., 1.0.0",
2093
- value: "1.0.0",
2094
- validateInput: (v) => /^\d+\.\d+\.\d+/.test(v)
2095
- ? null
2096
- : "Use semver format (e.g., 1.0.0)",
2097
- }));
2098
- if (!version) {
2099
- return;
2100
- }
2101
- // Get description if missing
2102
- let description = serverConfig.description;
2103
- if (!description) {
2104
- description = await vscode.window.showInputBox({
2105
- prompt: "Description (required)",
2106
- placeHolder: "What does this MCP server do?",
2107
- });
2108
- if (!description) {
2109
- showError(`${branding_1.AGENTIDE_BRAND_NAME}: Description is required`);
2110
- return;
2111
- }
2112
- }
2113
- // Collect files from MCP directory
2114
- const files = await collectMcpFiles(selected.config.mcpDir);
2115
- // Add/update mcp.json manifest
2116
- const manifest = {
2117
- name: selected.config.name,
2118
- version,
2119
- description,
2120
- transport: serverConfig.transport || "stdio",
2121
- command: serverConfig.command,
2122
- args: serverConfig.args,
2123
- env: serverConfig.env,
2124
- url: serverConfig.url,
2125
- npmPackage: serverConfig.npmPackage,
2126
- };
2127
- // Remove undefined fields
2128
- const cleanManifest = JSON.parse(JSON.stringify(manifest));
2129
- files.push({
2130
- path: "mcp.json",
2131
- content: JSON.stringify(cleanManifest, null, 2),
2132
- });
2133
- // Publish to store via fork + PR with progress
2134
- const result = await vscode.window.withProgress({
2135
- location: vscode.ProgressLocation.Window,
2136
- title: `Publishing MCP "${selected.config.name}"`,
2137
- cancellable: false,
2138
- }, async (progress) => {
2139
- progress.report({ message: "Preparing fork..." });
2140
- const res = await publishToStore({
2141
- type: "mcp",
2142
- slug: selected.config.name,
2143
- version,
2144
- files,
2145
- }, outputChannel);
2146
- progress.report({ message: "Creating PR..." });
2147
- return res;
2148
- });
2149
- // Register in local registry
2150
- const registry = getRegistry(outputChannel);
2151
- await registry.registerMcp({
2152
- slug: selected.config.name,
2153
- displayName: selected.config.name,
2154
- description,
2155
- transport: (serverConfig.transport || "stdio"),
2156
- github: { owner: STORE_CONFIG.owner, repo: STORE_CONFIG.repo },
2157
- latestVersion: version,
2158
- tags: [],
2159
- stats: { installs: 0 },
2160
- });
2161
- const viewAction = await vscode.window.showInformationMessage(`Published MCP "${selected.config.name}" v${version}! PR created.`, "View PR");
2162
- if (viewAction === "View PR") {
2163
- vscode.env.openExternal(vscode.Uri.parse(result.prUrl));
2164
- }
2165
- }
2166
- catch (e) {
2167
- const errorMsg = e instanceof Error ? e.message : String(e);
2168
- log(outputChannel, `[AgentIDE] MCP publish error: ${errorMsg}`);
2169
- showError(`AgentIDE: ${errorMsg}`);
2170
- }
2171
- }));
2172
- // Publish Spotlight view to store
2173
- context.subscriptions.push(vscode.commands.registerCommand("agentide.spotlight.publish", async (viewIdArg, publishOptions) => {
2174
- const bundleMode = publishOptions?.bundle === "scripts-only" ? "scripts-only" : "full";
2175
- const { workspaceRoot } = getWorkspaceRoot(outputChannel);
2176
- const { collectViewFiles, discoverPublishableViews, validateViewForPublish, } = await import("./spotlight/publish.js");
2177
- const { publishToStore, STORE_CONFIG, canPublishDirectlyToStore } = await import("./store/index.js");
2178
- const { isValidPublishVersion } = await import("./engines/publish.js");
2179
- const views = await discoverPublishableViews(workspaceRoot);
2180
- if (views.length === 0) {
2181
- showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: No publishable Spotlight views found. Create a view under .agent-hippo/analytics and register it in panel/views.yaml.`);
2182
- return;
2183
- }
2184
- const requestedViewId = typeof viewIdArg === "string" ? viewIdArg.trim() : "";
2185
- let selectedView = requestedViewId
2186
- ? views.find((view) => view.id === requestedViewId)
2187
- : undefined;
2188
- if (requestedViewId && !selectedView) {
2189
- showError(`${branding_1.AGENTIDE_BRAND_NAME}: View "${requestedViewId}" is not publishable. Add widget scripts under .agent-hippo/analytics/views/${requestedViewId}/scripts and register the view in panel/views.yaml.`);
2190
- return;
2191
- }
2192
- if (!selectedView) {
2193
- const selected = await vscode.window.showQuickPick(views.map((view) => ({
2194
- label: view.name,
2195
- description: view.id,
2196
- detail: `${view.sourceLabel} • ${view.scope} • ${view.scripts.length} script(s)`,
2197
- view,
2198
- })), {
2199
- placeHolder: "Select a Spotlight view to publish",
2200
- title: `Publish to ${STORE_CONFIG.owner}/${STORE_CONFIG.repo}`,
2201
- });
2202
- if (!selected) {
2203
- return;
2204
- }
2205
- selectedView = selected.view;
2206
- }
2207
- try {
2208
- const validation = await validateViewForPublish(selectedView, {
2209
- expectedId: selectedView.id,
2210
- mode: bundleMode,
2211
- });
2212
- if (!validation.valid) {
2213
- showError(`${branding_1.AGENTIDE_BRAND_NAME}: Cannot publish - ${validation.errors.join(", ")}`);
2214
- return;
2215
- }
2216
- if (validation.warnings.length > 0) {
2217
- const proceed = await vscode.window.showWarningMessage(`Warnings: ${validation.warnings.join(", ")}`, "Publish Anyway", "Cancel");
2218
- if (proceed !== "Publish Anyway") {
2219
- return;
2220
- }
2221
- }
2222
- const versionInput = await vscode.window.showInputBox({
2223
- prompt: "Publish version (semver)",
2224
- value: validation.metadata?.publishVersion || "1.0.0",
2225
- placeHolder: "e.g., 1.0.0",
2226
- validateInput: (value) => value && isValidPublishVersion(value.replace(/^v/, ""))
2227
- ? null
2228
- : "Use semver format (e.g., 1.0.0)",
2229
- });
2230
- if (!versionInput || !validation.metadata) {
2231
- return;
2232
- }
2233
- const version = versionInput.replace(/^v/, "");
2234
- const changelog = await vscode.window.showInputBox({
2235
- prompt: "What changed in this version? (optional)",
2236
- placeHolder: "Initial release, new widgets...",
2237
- });
2238
- const files = await collectViewFiles(selectedView, version, validation.metadata, bundleMode);
2239
- const bundleLabel = bundleMode === "full"
2240
- ? "full bundle (scripts + assets + charts/exports)"
2241
- : "scripts only";
2242
- const publishDirect = await canPublishDirectlyToStore();
2243
- const confirm = await vscode.window.showWarningMessage(publishDirect
2244
- ? `Publish Spotlight view "${selectedView.id}" v${version} (${bundleLabel}) to ${STORE_CONFIG.owner}/${STORE_CONFIG.repo}?\n\nThis will open a pull request on the store repository.`
2245
- : `Submit Spotlight view "${selectedView.id}" v${version} (${bundleLabel}) to ${STORE_CONFIG.owner}/${STORE_CONFIG.repo}?\n\nThis will create a pull request from your fork.`, { modal: true }, "Submit PR");
2246
- if (confirm !== "Submit PR") {
2247
- return;
2248
- }
2249
- const result = await vscode.window.withProgress({
2250
- location: vscode.ProgressLocation.Window,
2251
- title: `Publishing Spotlight view ${selectedView.id} v${version}`,
2252
- cancellable: false,
2253
- }, async (progress) => {
2254
- progress.report({
2255
- message: publishDirect
2256
- ? `Publishing to ${STORE_CONFIG.owner}/${STORE_CONFIG.repo}...`
2257
- : "Preparing fork...",
2258
- });
2259
- return await publishToStore({
2260
- type: "view",
2261
- slug: selectedView.id,
2262
- version,
2263
- files,
2264
- changelog,
2265
- }, outputChannel);
2266
- });
2267
- const viewAction = await vscode.window.showInformationMessage(`Published Spotlight view "${selectedView.name}" v${version}! PR created.`, "View PR");
2268
- if (viewAction === "View PR") {
2269
- vscode.env.openExternal(vscode.Uri.parse(result.prUrl));
2270
- }
2271
- }
2272
- catch (e) {
2273
- const errorMsg = e instanceof Error ? e.message : String(e);
2274
- log(outputChannel, `[AgentIDE] Spotlight publish error: ${errorMsg}`);
2275
- showError(`${branding_1.AGENTIDE_BRAND_NAME}: ${errorMsg}`);
2276
- }
2277
- }));
2278
- // Install from store (routes based on artifact type)
2279
- context.subscriptions.push(vscode.commands.registerCommand("agentide.store.install", async (urlArg) => {
2280
- await (0, githubStoreGate_js_1.ensureGitHubStoreAccess)(context);
2281
- const { parseStoreUrl } = await import("./store/index.js");
2282
- // Get URL from arg or prompt
2283
- let url = urlArg;
2284
- if (!url) {
2285
- url = await vscode.window.showInputBox({
2286
- prompt: "Enter store URL or GitHub link",
2287
- placeHolder: "e.g., engine/gemini or https://github.com/.../engines/gemini",
2288
- validateInput: (value) => {
2289
- if (!value.trim()) {
2290
- return "Please enter a URL";
2291
- }
2292
- // Allow GitHub URLs or path-based URLs
2293
- if (!value.includes("/")) {
2294
- return "Expected: type/slug, or GitHub URL";
2295
- }
2296
- return null;
2297
- },
2298
- });
2299
- }
2300
- if (!url) {
2301
- return;
2302
- }
2303
- try {
2304
- const artifact = parseStoreUrl(url);
2305
- // Route to appropriate install command based on type
2306
- switch (artifact.type) {
2307
- case "pack":
2308
- await vscode.commands.executeCommand("agentide.pack.storeInstall", artifact);
2309
- break;
2310
- case "skill":
2311
- await vscode.commands.executeCommand("agentide.skill.install", artifact);
2312
- break;
2313
- case "mcp":
2314
- await vscode.commands.executeCommand("agentide.mcp.install", artifact);
2315
- break;
2316
- case "engine":
2317
- await vscode.commands.executeCommand("agentide.engine.install", artifact);
2318
- break;
2319
- case "view":
2320
- await vscode.commands.executeCommand("agentide.view.install", artifact);
2321
- break;
2322
- }
2323
- }
2324
- catch (e) {
2325
- const errorMsg = e instanceof Error ? e.message : String(e);
2326
- log(outputChannel, `[AgentIDE] Store install error: ${errorMsg}`);
2327
- showError(`AgentIDE: ${errorMsg}`);
2328
- }
2329
- }));
2330
- // Browse store - unified install command
2331
- // If URL provided: direct install (detects type automatically)
2332
- // If no URL: interactive picker with Orama-powered search
2333
- context.subscriptions.push(vscode.commands.registerCommand("agentide.store.find", async (arg) => {
2334
- await (0, githubStoreGate_js_1.ensureGitHubStoreAccess)(context);
2335
- const { isStoreUrl, parseStoreUrl, parseGitHubUrl, detectArtifactType, } = await import("./store/index.js");
2336
- const { searchMerged, listMergedArtifacts } = await import("./store/oramaIndex.js");
2337
- let urlArg;
2338
- let initialTypeFilter = "all";
2339
- if (typeof arg === "string") {
2340
- urlArg = arg;
2341
- }
2342
- else if (arg && typeof arg === "object" && arg.typeFilter) {
2343
- initialTypeFilter = arg.typeFilter;
2344
- }
2345
- // If URL provided, do direct install
2346
- if (urlArg) {
2347
- try {
2348
- let type;
2349
- let slug;
2350
- let version;
2351
- if (isStoreUrl(urlArg)) {
2352
- // Store URL - parse type from path prefix
2353
- const parsed = parseStoreUrl(urlArg);
2354
- type = parsed.type;
2355
- slug = parsed.slug;
2356
- version = parsed.version;
2357
- }
2358
- else {
2359
- // Generic GitHub URL - detect type from marker files
2360
- const ghParsed = parseGitHubUrl(urlArg);
2361
- type = await vscode.window.withProgress({
2362
- location: vscode.ProgressLocation.Notification,
2363
- title: "Detecting artifact type...",
2364
- cancellable: false,
2365
- }, async () => {
2366
- return await detectArtifactType(ghParsed.owner, ghParsed.repo, ghParsed.ref, ghParsed.path, outputChannel);
2367
- });
2368
- // Extract just the last part of the path as the slug name
2369
- const pathParts = (ghParsed.path || ghParsed.repo).split("/");
2370
- slug = pathParts[pathParts.length - 1] || ghParsed.repo;
2371
- version = ghParsed.ref;
2372
- }
2373
- // Route to appropriate install command
2374
- switch (type) {
2375
- case "pack":
2376
- await vscode.commands.executeCommand("agentide.pack.storeInstall", {
2377
- type: "pack",
2378
- slug,
2379
- version,
2380
- sourceUrl: urlArg, // Pass original URL for non-store installs
2381
- });
2382
- break;
2383
- case "skill":
2384
- await vscode.commands.executeCommand("agentide.skill.install", {
2385
- type: "skill",
2386
- slug,
2387
- version,
2388
- sourceUrl: urlArg,
2389
- });
2390
- break;
2391
- case "mcp":
2392
- await vscode.commands.executeCommand("agentide.mcp.install", {
2393
- type: "mcp",
2394
- slug,
2395
- version,
2396
- sourceUrl: urlArg,
2397
- });
2398
- break;
2399
- case "engine":
2400
- await vscode.commands.executeCommand("agentide.engine.install", {
2401
- type: "engine",
2402
- slug,
2403
- version,
2404
- sourceUrl: urlArg,
2405
- });
2406
- break;
2407
- case "view":
2408
- await vscode.commands.executeCommand("agentide.view.install", {
2409
- type: "view",
2410
- slug,
2411
- version,
2412
- sourceUrl: urlArg,
2413
- });
2414
- break;
2415
- }
2416
- return;
2417
- }
2418
- catch (e) {
2419
- const errorMsg = e instanceof Error ? e.message : String(e);
2420
- log(outputChannel, `[AgentIDE] Install error: ${errorMsg}`);
2421
- showError(`AgentIDE: ${errorMsg}`);
2422
- return;
2423
- }
2424
- }
2425
- // No URL - show interactive picker
2426
- // Import shared icons (consistent with CLI)
2427
- const { STORE_ICONS } = await import("./store/shared.js");
2428
- const typeIcons = {
2429
- pack: STORE_ICONS.pack,
2430
- skill: STORE_ICONS.skill,
2431
- mcp: STORE_ICONS.mcp,
2432
- engine: STORE_ICONS.engine,
2433
- view: STORE_ICONS.view,
2434
- };
2435
- const typeFilters = ["all", "pack", "skill", "mcp", "engine", "view"];
2436
- // Create interactive QuickPick
2437
- const quickPick = vscode.window.createQuickPick();
2438
- quickPick.title =
2439
- initialTypeFilter === "view"
2440
- ? "Install Spotlight View"
2441
- : "Install Packs, Skills, MCP Tools, Engines, Spotlight Views";
2442
- quickPick.placeholder = "Search or paste a GitHub URL to install...";
2443
- quickPick.matchOnDescription = true;
2444
- quickPick.matchOnDetail = true;
2445
- quickPick.busy = true;
2446
- let allItems = [];
2447
- let currentFilter = initialTypeFilter;
2448
- let searchDebounceTimer;
2449
- // Source icons for Local/Remote display (from shared)
2450
- const sourceIcons = {
2451
- local: STORE_ICONS.local,
2452
- remote: STORE_ICONS.remote,
2453
- };
2454
- const updateItems = (items) => {
2455
- const itemsToShow = items ?? allItems;
2456
- const filtered = currentFilter === "all"
2457
- ? itemsToShow
2458
- : itemsToShow.filter((item) => item.type === currentFilter);
2459
- // Filter header buttons
2460
- const filterButtons = typeFilters.map((f) => ({
2461
- label: f === "all"
2462
- ? "$(list-flat) All"
2463
- : `${typeIcons[f]} ${f.charAt(0).toUpperCase() + f.slice(1)}s`,
2464
- description: f === currentFilter ? "$(check)" : "",
2465
- alwaysShow: true,
2466
- itemType: "filter",
2467
- filter: f,
2468
- }));
2469
- // Artifact items - show source icon (Local/Remote) and installed badge
2470
- const artifactItems = filtered.map((item) => {
2471
- const sourceIcon = item.source === "local" ? sourceIcons.local : sourceIcons.remote;
2472
- const installedBadge = item.installed ? "$(check)" : "";
2473
- // Build description: source + type + installed badge
2474
- const descParts = [
2475
- item.source === "local" ? "Local" : "Remote",
2476
- item.type,
2477
- ];
2478
- if (installedBadge) {
2479
- descParts.push(installedBadge);
2480
- }
2481
- // Build detail: description + installed packs info
2482
- let detail = item.description || item.path;
2483
- if (item.installedTo && item.installedTo.length > 0) {
2484
- detail += ` • Installed to: ${item.installedTo.join(", ")}`;
2485
- }
2486
- return {
2487
- label: `${sourceIcon} ${typeIcons[item.type]} ${item.slug}`,
2488
- description: descParts.join(" • "),
2489
- detail,
2490
- itemType: "artifact",
2491
- artifact: item,
2492
- };
2493
- });
2494
- quickPick.items = [
2495
- ...filterButtons,
2496
- {
2497
- label: "",
2498
- kind: vscode.QuickPickItemKind.Separator,
2499
- itemType: "filter",
2500
- },
2501
- ...artifactItems,
2502
- ];
2503
- };
2504
- // Live search handler using Orama
2505
- const handleSearch = async (query) => {
2506
- if (searchDebounceTimer) {
2507
- clearTimeout(searchDebounceTimer);
2508
- }
2509
- const trimmedQuery = query.trim();
2510
- // If empty query or looks like URL, show all items
2511
- if (!trimmedQuery ||
2512
- trimmedQuery.startsWith("http") ||
2513
- trimmedQuery.startsWith("store://") ||
2514
- trimmedQuery.startsWith("github.com")) {
2515
- updateItems(allItems);
2516
- return;
2517
- }
2518
- // Debounce search
2519
- searchDebounceTimer = setTimeout(async () => {
2520
- try {
2521
- const typeFilter = currentFilter === "all"
2522
- ? undefined
2523
- : currentFilter;
2524
- const results = await searchMerged(trimmedQuery, { type: typeFilter, limit: 50 }, outputChannel);
2525
- const searchItems = results.map((r) => ({
2526
- type: r.type,
2527
- slug: r.slug,
2528
- path: `${r.type}s/${r.slug}`,
2529
- description: r.description,
2530
- installed: r.installed,
2531
- installedVersion: r.installedVersion,
2532
- source: r.source,
2533
- installedTo: r.installedTo,
2534
- }));
2535
- updateItems(searchItems);
2536
- }
2537
- catch (e) {
2538
- // Fall back to showing all items on search error
2539
- log(outputChannel, `[AgentIDE] Search error: ${e instanceof Error ? e.message : String(e)}`);
2540
- updateItems(allItems);
2541
- }
2542
- }, 150); // 150ms debounce
2543
- };
2544
- // Listen for input changes for live search
2545
- quickPick.onDidChangeValue(handleSearch);
2546
- // Load items from store using merged Orama index (local + remote)
2547
- try {
2548
- const storeItems = await listMergedArtifacts(undefined, outputChannel);
2549
- // Map to expected format - includes installed status, source, and installedTo
2550
- allItems = storeItems.map((item) => ({
2551
- type: item.type,
2552
- slug: item.slug,
2553
- path: `${item.type}s/${item.slug}`,
2554
- description: item.description,
2555
- installed: item.installed,
2556
- installedVersion: item.installedVersion,
2557
- source: item.source,
2558
- installedTo: item.installedTo,
2559
- }));
2560
- quickPick.busy = false;
2561
- updateItems();
2562
- if (allItems.length === 0) {
2563
- quickPick.placeholder =
2564
- "Store is empty or index not synced yet. Try again later!";
2565
- }
2566
- }
2567
- catch (e) {
2568
- const errorMsg = e instanceof Error ? e.message : String(e);
2569
- log(outputChannel, `[AgentIDE] Store browse error: ${errorMsg}`);
2570
- quickPick.hide();
2571
- showError(`AgentIDE: ${errorMsg}`);
2572
- return;
2573
- }
2574
- // Helper to check if input looks like a URL
2575
- const looksLikeUrl = (input) => {
2576
- const trimmed = input.trim();
2577
- return (trimmed.startsWith("https://") ||
2578
- trimmed.startsWith("http://") ||
2579
- trimmed.startsWith("github.com/") ||
2580
- trimmed.startsWith("store://"));
2581
- };
2582
- // Handle selection or URL input
2583
- quickPick.onDidAccept(async () => {
2584
- const selected = quickPick.selectedItems[0];
2585
- const inputValue = quickPick.value.trim();
2586
- // Check if input looks like a URL FIRST - prioritize URL over selection
2587
- if (inputValue && looksLikeUrl(inputValue)) {
2588
- quickPick.hide();
2589
- log(outputChannel, `[AgentIDE] Browse Store: detected URL input: ${inputValue}`);
2590
- // Re-run the command with the URL
2591
- await vscode.commands.executeCommand("agentide.store.find", inputValue);
2592
- return;
2593
- }
2594
- if (!selected) {
2595
- return;
2596
- }
2597
- // Handle filter selection
2598
- if (selected.itemType === "filter" && selected.filter) {
2599
- currentFilter = selected.filter;
2600
- updateItems();
2601
- return;
2602
- }
2603
- // Handle artifact selection
2604
- if (selected.itemType === "artifact" && selected.artifact) {
2605
- quickPick.hide();
2606
- const { artifact } = selected;
2607
- switch (artifact.type) {
2608
- case "pack":
2609
- await vscode.commands.executeCommand("agentide.pack.storeInstall", {
2610
- type: "pack",
2611
- slug: artifact.slug,
2612
- });
2613
- break;
2614
- case "skill":
2615
- await vscode.commands.executeCommand("agentide.skill.install", {
2616
- type: "skill",
2617
- slug: artifact.slug,
2618
- });
2619
- break;
2620
- case "mcp":
2621
- await vscode.commands.executeCommand("agentide.mcp.install", {
2622
- type: "mcp",
2623
- slug: artifact.slug,
2624
- });
2625
- break;
2626
- case "engine":
2627
- await vscode.commands.executeCommand("agentide.engine.install", {
2628
- type: "engine",
2629
- slug: artifact.slug,
2630
- });
2631
- break;
2632
- case "view":
2633
- await vscode.commands.executeCommand("agentide.view.install", {
2634
- type: "view",
2635
- slug: artifact.slug,
2636
- });
2637
- break;
2638
- }
2639
- }
2640
- });
2641
- quickPick.onDidHide(() => quickPick.dispose());
2642
- quickPick.show();
2643
- }));
2644
- // Store search API - for agent skill scripts to search without UI
2645
- // Returns merged results from both local library and remote store
2646
- context.subscriptions.push(vscode.commands.registerCommand("agentide.store.search", async (query, options) => {
2647
- const { searchMerged } = await import("./store/oramaIndex.js");
2648
- return searchMerged(query, options, outputChannel);
2649
- }));
2650
- // Store sync API - force refresh the store index
2651
- context.subscriptions.push(vscode.commands.registerCommand("agentide.store.sync", async () => {
2652
- const { forceRefresh, getIndexMeta } = await import("./store/oramaIndex.js");
2653
- await vscode.window.withProgress({
2654
- location: vscode.ProgressLocation.Notification,
2655
- title: "Syncing store index...",
2656
- cancellable: false,
2657
- }, async () => {
2658
- await forceRefresh(outputChannel);
2659
- });
2660
- const meta = await getIndexMeta();
2661
- if (meta) {
2662
- void showInfo(`Store index synced: ${meta.artifactCount} artifacts (updated ${new Date(meta.generatedAt).toLocaleDateString()})`);
2663
- }
2664
- }));
2665
- // Store setup - automate store index in a GitHub repo
2666
- context.subscriptions.push(vscode.commands.registerCommand("agentide.store.setup", async () => {
2667
- const { setupStoreAutomation } = await import("./store/github/setup.js");
2668
- // Get repo URL from user
2669
- const repoUrl = await vscode.window.showInputBox({
2670
- prompt: "Enter GitHub repository URL for your store",
2671
- placeHolder: "https://github.com/owner/repo or owner/repo",
2672
- validateInput: (value) => {
2673
- if (!value) {
2674
- return "Repository URL is required";
2675
- }
2676
- const match = value.match(/(?:github\.com\/)?([^/]+)\/([^/]+)/);
2677
- if (!match) {
2678
- return "Invalid format. Use: owner/repo or https://github.com/owner/repo";
2679
- }
2680
- return null;
2681
- },
2682
- });
2683
- if (!repoUrl) {
2684
- return;
2685
- }
2686
- const match = repoUrl.match(/(?:github\.com\/)?([^/]+)\/([^/]+)/);
2687
- if (!match) {
2688
- void showError("Invalid repository URL");
2689
- return;
2690
- }
2691
- const [, owner, repo] = match;
2692
- const cleanRepo = repo.replace(/\.git$/, "");
2693
- const result = await vscode.window.withProgress({
2694
- location: vscode.ProgressLocation.Notification,
2695
- title: `Setting up store automation for ${owner}/${cleanRepo}...`,
2696
- cancellable: false,
2697
- }, async () => {
2698
- return await setupStoreAutomation(owner, cleanRepo, outputChannel);
2699
- });
2700
- if (result.success && result.pullRequestUrl) {
2701
- // Update store configuration to use this repo for publish/find
2702
- const storeConfig = vscode.workspace.getConfiguration("agentide");
2703
- const newStoreRepo = `${owner}/${cleanRepo}`;
2704
- const currentStoreRepo = storeConfig.get("storeRepo", "");
2705
- const currentIndexUrl = storeConfig.get("store.indexUrl", "");
2706
- const newIndexUrl = `https://${owner}.github.io/${cleanRepo}`;
2707
- let currentDefaultIndexUrl = "";
2708
- if (currentStoreRepo) {
2709
- const matchStore = currentStoreRepo.match(/^(?:https?:\/\/github\.com\/)?([^/]+)\/([^/]+?)(?:\.git)?$/);
2710
- if (matchStore) {
2711
- currentDefaultIndexUrl = `https://${matchStore[1]}.github.io/${matchStore[2]}`;
2712
- }
2713
- }
2714
- await storeConfig.update("storeRepo", newStoreRepo, vscode.ConfigurationTarget.Global);
2715
- if (!currentIndexUrl ||
2716
- (currentDefaultIndexUrl && currentIndexUrl === currentDefaultIndexUrl)) {
2717
- await storeConfig.update("store.indexUrl", newIndexUrl, vscode.ConfigurationTarget.Global);
2718
- }
2719
- const action = await vscode.window.showInformationMessage(
2720
- // allow-any-unicode-next-line
2721
- `🦛 ${result.message}`, "Open Pull Request", "Copy URL");
2722
- if (action === "Open Pull Request") {
2723
- await vscode.env.openExternal(vscode.Uri.parse(result.pullRequestUrl));
2724
- }
2725
- else if (action === "Copy URL") {
2726
- await vscode.env.clipboard.writeText(result.pullRequestUrl);
2727
- void showInfo("Pull request URL copied to clipboard");
2728
- }
2729
- }
2730
- else if (!result.success) {
2731
- void showError(`Setup failed: ${result.message}`);
2732
- }
2733
- }));
2734
- // Install pack from store (internal command)
2735
- context.subscriptions.push(vscode.commands.registerCommand("agentide.pack.storeInstall", async (artifactArg) => {
2736
- const { workspaceRoot } = getWorkspaceRoot(outputChannel);
2737
- const { downloadFromStore, listStoreVersions } = await import("./store/index.js");
2738
- const { getAgentRoot } = await import("./agentpack/paths.js");
2739
- const artifact = artifactArg || {
2740
- type: "pack",
2741
- slug: "",
2742
- version: undefined,
2743
- };
2744
- // If no version specified, show version picker or use main
2745
- if (!artifact.version) {
2746
- const versions = await listStoreVersions("pack", artifact.slug);
2747
- if (versions.length === 0) {
2748
- // No tags - will download from main branch
2749
- artifact.version = "main";
2750
- }
2751
- else {
2752
- const selected = await vscode.window.showQuickPick(versions.map((v) => ({
2753
- label: v.version,
2754
- description: v.isPrerelease ? "(pre-release)" : "",
2755
- })), { placeHolder: "Select version to install" });
2756
- if (!selected) {
2757
- return;
2758
- }
2759
- artifact.version = selected.label;
2760
- }
2761
- }
2762
- const targetDir = getAgentRoot(workspaceRoot, artifact.slug);
2763
- const targetExists = await fs_1.promises
2764
- .access(targetDir)
2765
- .then(() => true)
2766
- .catch(() => false);
2767
- if (targetExists) {
2768
- const overwrite = await vscode.window.showWarningMessage(`Pack "${artifact.slug}" already exists. Overwrite?`, { modal: true }, "Overwrite", "Cancel");
2769
- if (overwrite !== "Overwrite") {
2770
- return;
2771
- }
2772
- await fs_1.promises.rm(targetDir, { recursive: true, force: true });
2773
- }
2774
- await vscode.window.withProgress({
2775
- location: vscode.ProgressLocation.Window,
2776
- title: `Installing pack "${artifact.slug}"`,
2777
- cancellable: false,
2778
- }, async (progress) => {
2779
- progress.report({ message: "Downloading from store..." });
2780
- const files = await downloadFromStore({
2781
- type: "pack",
2782
- slug: artifact.slug,
2783
- version: artifact.version,
2784
- }, outputChannel);
2785
- progress.report({ message: "Extracting files..." });
2786
- await fs_1.promises.mkdir(targetDir, { recursive: true });
2787
- for (const file of files) {
2788
- const filePath = path.join(targetDir, file.path);
2789
- await fs_1.promises.mkdir(path.dirname(filePath), { recursive: true });
2790
- await fs_1.promises.writeFile(filePath, file.content);
2791
- }
2792
- });
2793
- await vscode.commands.executeCommand("agentide.packsChanged");
2794
- // Register the installed pack in local registry
2795
- const { getRegistry } = await import("./registry/index.js");
2796
- const registry = getRegistry(outputChannel);
2797
- await registry.registerPack({
2798
- slug: artifact.slug,
2799
- displayName: artifact.slug,
2800
- latestVersion: artifact.version || "main",
2801
- tags: [],
2802
- stats: { installs: 1, stars: 0 },
2803
- });
2804
- // Invalidate local index cache so merged search sees the new item
2805
- const { invalidateLocalIndex } = await import("./store/oramaIndex.js");
2806
- invalidateLocalIndex();
2807
- const activateAction = await vscode.window.showInformationMessage(`Installed pack "${artifact.slug}" v${artifact.version}`, "Activate");
2808
- if (activateAction === "Activate") {
2809
- await vscode.commands.executeCommand("agentide.pack.switch", artifact.slug);
2810
- }
2811
- }));
2812
- // Install skill from store or external GitHub
2813
- context.subscriptions.push(vscode.commands.registerCommand("agentide.skill.install", async (artifactArg) => {
2814
- const { workspaceRoot } = getWorkspaceRoot(outputChannel);
2815
- const { downloadFromStore, downloadFromExternalGitHub, listStoreVersions, isStoreUrl, parseGitHubUrl, } = await import("./store/index.js");
2816
- const { AgentPackManager } = await import("./agentpack/index.js");
2817
- const packManager = new AgentPackManager(syncService, () => workspaceRoot, () => config.storagePath, outputChannel);
2818
- // Get artifact info
2819
- let artifact = artifactArg;
2820
- if (!artifact) {
2821
- const url = await vscode.window.showInputBox({
2822
- prompt: "Enter skill store URL or GitHub URL",
2823
- placeHolder: "e.g., skills/typescript-testing@v1.0.0 or https://github.com/user/repo",
2824
- });
2825
- if (!url) {
2826
- return;
2827
- }
2828
- const { parseStoreUrl } = await import("./store/index.js");
2829
- artifact = parseStoreUrl(url);
2830
- }
2831
- // Determine if this is a store URL or external GitHub
2832
- const isExternal = artifact.sourceUrl && !isStoreUrl(artifact.sourceUrl);
2833
- // If no version specified and not external, show version picker
2834
- if (!artifact.version && !isExternal) {
2835
- const versions = await listStoreVersions("skill", artifact.slug);
2836
- if (versions.length === 0) {
2837
- artifact.version = "main";
2838
- }
2839
- else {
2840
- const selected = await vscode.window.showQuickPick(versions.map((v) => ({
2841
- label: v.version,
2842
- description: v.isPrerelease ? "(pre-release)" : "",
2843
- })), { placeHolder: "Select version to install" });
2844
- if (!selected) {
2845
- return;
2846
- }
2847
- artifact.version = selected.label;
2848
- }
2849
- }
2850
- // Select which agent to install the skill to
2851
- const packs = await packManager.listInstalledWithCleanup();
2852
- if (packs.length === 0) {
2853
- showError(`${branding_1.AGENTIDE_BRAND_NAME}: No agents found. Create an agent first.`);
2854
- return;
2855
- }
2856
- const targetPack = await vscode.window.showQuickPick(packs.map((p) => ({ label: p.id, description: `v${p.version}` })), { placeHolder: "Select agent to install skill to" });
2857
- if (!targetPack) {
2858
- return;
2859
- }
2860
- const { getAgentRoot } = await import("./agentpack/paths.js");
2861
- const agentRoot = getAgentRoot(workspaceRoot, targetPack.label);
2862
- const skillsDir = path.join(agentRoot, "skills", artifact.slug);
2863
- const targetExists = await fs_1.promises
2864
- .access(skillsDir)
2865
- .then(() => true)
2866
- .catch(() => false);
2867
- if (targetExists) {
2868
- const overwrite = await vscode.window.showWarningMessage(`Skill "${artifact.slug}" already exists in ${targetPack.label}. Overwrite?`, { modal: true }, "Overwrite", "Cancel");
2869
- if (overwrite !== "Overwrite") {
2870
- return;
2871
- }
2872
- await fs_1.promises.rm(skillsDir, { recursive: true, force: true });
2873
- }
2874
- await vscode.window.withProgress({
2875
- location: vscode.ProgressLocation.Window,
2876
- title: `Installing skill "${artifact.slug}"`,
2877
- cancellable: false,
2878
- }, async (progress) => {
2879
- let files;
2880
- if (isExternal && artifact.sourceUrl) {
2881
- // Download from external GitHub
2882
- progress.report({ message: "Downloading from GitHub..." });
2883
- const parsed = parseGitHubUrl(artifact.sourceUrl);
2884
- files = await downloadFromExternalGitHub({
2885
- owner: parsed.owner,
2886
- repo: parsed.repo,
2887
- ref: parsed.ref || "main",
2888
- path: parsed.path,
2889
- }, outputChannel);
2890
- }
2891
- else {
2892
- // Download from store
2893
- progress.report({ message: "Downloading from store..." });
2894
- files = await downloadFromStore({
2895
- type: "skill",
2896
- slug: artifact.slug,
2897
- version: artifact.version,
2898
- }, outputChannel);
2899
- }
2900
- progress.report({ message: "Extracting files..." });
2901
- await fs_1.promises.mkdir(skillsDir, { recursive: true });
2902
- for (const file of files) {
2903
- const filePath = path.join(skillsDir, file.path);
2904
- await fs_1.promises.mkdir(path.dirname(filePath), { recursive: true });
2905
- await fs_1.promises.writeFile(filePath, file.content);
2906
- }
2907
- });
2908
- // Register the installed skill in local registry
2909
- const { getRegistry } = await import("./registry/index.js");
2910
- const registry = getRegistry(outputChannel);
2911
- await registry.registerSkill({
2912
- slug: artifact.slug,
2913
- displayName: artifact.slug,
2914
- latestVersion: artifact.version || "main",
2915
- tags: [],
2916
- stats: { installs: 1 },
2917
- agentPackId: targetPack.label,
2918
- });
2919
- // Invalidate local index cache so merged search sees the new item
2920
- const { invalidateLocalIndex } = await import("./store/oramaIndex.js");
2921
- invalidateLocalIndex();
2922
- showInfo(`Installed skill "${artifact.slug}" to ${targetPack.label}`);
2923
- }));
2924
- // Install MCP from store
2925
- context.subscriptions.push(vscode.commands.registerCommand("agentide.mcp.install", async (artifactArg) => {
2926
- const { workspaceRoot } = getWorkspaceRoot(outputChannel);
2927
- const { downloadFromStore, listStoreVersions } = await import("./store/index.js");
2928
- const { AgentPackManager } = await import("./agentpack/index.js");
2929
- const packManager = new AgentPackManager(syncService, () => workspaceRoot, () => config.storagePath, outputChannel);
2930
- // Get artifact info
2931
- let artifact = artifactArg;
2932
- if (!artifact) {
2933
- const url = await vscode.window.showInputBox({
2934
- prompt: "Enter MCP store URL",
2935
- placeHolder: "e.g., mcp/github@v1.0.0",
2936
- });
2937
- if (!url) {
2938
- return;
2939
- }
2940
- const { parseStoreUrl } = await import("./store/index.js");
2941
- artifact = parseStoreUrl(url);
2942
- }
2943
- // If no version specified, show version picker or use main
2944
- if (!artifact.version) {
2945
- const versions = await listStoreVersions("mcp", artifact.slug);
2946
- if (versions.length === 0) {
2947
- // No tags - will download from main branch
2948
- artifact.version = "main";
2949
- }
2950
- else {
2951
- const selected = await vscode.window.showQuickPick(versions.map((v) => ({
2952
- label: v.version,
2953
- description: v.isPrerelease ? "(pre-release)" : "",
2954
- })), { placeHolder: "Select version to install" });
2955
- if (!selected) {
2956
- return;
2957
- }
2958
- artifact.version = selected.label;
2959
- }
2960
- }
2961
- // Select which agent to install the MCP to
2962
- const packs = await packManager.listInstalledWithCleanup();
2963
- if (packs.length === 0) {
2964
- showError(`${branding_1.AGENTIDE_BRAND_NAME}: No agents found. Create an agent first.`);
2965
- return;
2966
- }
2967
- const targetPack = await vscode.window.showQuickPick(packs.map((p) => ({ label: p.id, description: `v${p.version}` })), { placeHolder: "Select agent to add MCP server to" });
2968
- if (!targetPack) {
2969
- return;
2970
- }
2971
- await vscode.window.withProgress({
2972
- location: vscode.ProgressLocation.Window,
2973
- title: `Installing MCP "${artifact.slug}"`,
2974
- cancellable: false,
2975
- }, async (progress) => {
2976
- progress.report({ message: "Downloading from store..." });
2977
- const files = await downloadFromStore({
2978
- type: "mcp",
2979
- slug: artifact.slug,
2980
- version: artifact.version,
2981
- }, outputChannel);
2982
- progress.report({ message: "Merging MCP config..." });
2983
- // Find mcp.json in downloaded files
2984
- const mcpJsonFile = files.find((f) => f.path === "mcp.json" || f.path.endsWith("/mcp.json"));
2985
- if (!mcpJsonFile) {
2986
- throw new Error("Downloaded MCP package missing mcp.json");
2987
- }
2988
- const mcpConfig = JSON.parse(mcpJsonFile.content.toString());
2989
- // Read existing .mcp.json or create new one
2990
- const { getAgentRoot } = await import("./agentpack/paths.js");
2991
- const agentRoot = getAgentRoot(workspaceRoot, targetPack.label);
2992
- const mcpDir = path.join(agentRoot, "mcp");
2993
- const mcpJsonPath = path.join(mcpDir, ".mcp.json");
2994
- await fs_1.promises.mkdir(mcpDir, { recursive: true });
2995
- let existingConfig = {
2996
- mcpServers: {},
2997
- };
2998
- try {
2999
- const content = await fs_1.promises.readFile(mcpJsonPath, "utf-8");
3000
- existingConfig = JSON.parse(content);
3001
- if (!existingConfig.mcpServers) {
3002
- existingConfig.mcpServers = {};
3003
- }
3004
- }
3005
- catch {
3006
- // File doesn't exist, use default
3007
- }
3008
- // Add/update the MCP server
3009
- existingConfig.mcpServers[artifact.slug] = {
3010
- transport: mcpConfig.transport || "stdio",
3011
- command: mcpConfig.command,
3012
- args: mcpConfig.args,
3013
- env: mcpConfig.env,
3014
- url: mcpConfig.url,
3015
- npmPackage: mcpConfig.npmPackage,
3016
- // Store metadata
3017
- _version: artifact.version,
3018
- _description: mcpConfig.description,
3019
- };
3020
- // Write back
3021
- await fs_1.promises.writeFile(mcpJsonPath, JSON.stringify(existingConfig, null, 2));
3022
- // Also save any additional source files
3023
- for (const file of files) {
3024
- if (file.path !== "mcp.json" &&
3025
- !file.path.endsWith("/mcp.json")) {
3026
- const filePath = path.join(mcpDir, artifact.slug, file.path);
3027
- await fs_1.promises.mkdir(path.dirname(filePath), { recursive: true });
3028
- await fs_1.promises.writeFile(filePath, file.content);
3029
- }
3030
- }
3031
- });
3032
- // Register the installed MCP in local registry
3033
- const { getRegistry } = await import("./registry/index.js");
3034
- const registry = getRegistry(outputChannel);
3035
- await registry.registerMcp({
3036
- slug: artifact.slug,
3037
- displayName: artifact.slug,
3038
- transport: "stdio",
3039
- latestVersion: artifact.version || "main",
3040
- tags: [],
3041
- stats: { installs: 1 },
3042
- agentPackId: targetPack.label,
3043
- });
3044
- // Invalidate local index cache so merged search sees the new item
3045
- const { invalidateLocalIndex } = await import("./store/oramaIndex.js");
3046
- invalidateLocalIndex();
3047
- showInfo(`Installed MCP "${artifact.slug}" v${artifact.version} to ${targetPack.label}`);
3048
- }));
3049
- // Install custom engine from store or external GitHub
3050
- context.subscriptions.push(vscode.commands.registerCommand("agentide.engine.install", async (artifactArg) => {
3051
- const { downloadFromStore, downloadFromExternalGitHub, listStoreVersions, isStoreUrl, parseGitHubUrl, parseStoreUrl, } = await import("./store/index.js");
3052
- const { installCustomEngineFromFiles } = await import("./engines/install.js");
3053
- let artifact = artifactArg;
3054
- if (!artifact) {
3055
- const url = await vscode.window.showInputBox({
3056
- prompt: "Enter custom engine store URL or GitHub URL",
3057
- placeHolder: "e.g., engine/gemini or https://github.com/user/repo/tree/main/gemini",
3058
- });
3059
- if (!url) {
3060
- return;
3061
- }
3062
- if (isStoreUrl(url)) {
3063
- artifact = parseStoreUrl(url);
3064
- }
3065
- else {
3066
- const parsed = parseGitHubUrl(url);
3067
- const pathParts = (parsed.path || parsed.repo).split("/");
3068
- artifact = {
3069
- type: "engine",
3070
- slug: pathParts[pathParts.length - 1] || parsed.repo,
3071
- version: parsed.ref,
3072
- sourceUrl: url,
3073
- };
3074
- }
3075
- }
3076
- const isExternal = artifact.sourceUrl && !isStoreUrl(artifact.sourceUrl);
3077
- if (!artifact.version && !isExternal) {
3078
- const versions = await listStoreVersions("engine", artifact.slug);
3079
- if (versions.length === 0) {
3080
- artifact.version = "main";
3081
- }
3082
- else {
3083
- const selected = await vscode.window.showQuickPick(versions.map((v) => ({
3084
- label: v.version,
3085
- description: v.isPrerelease ? "(pre-release)" : "",
3086
- })), { placeHolder: "Select version to install" });
3087
- if (!selected) {
3088
- return;
3089
- }
3090
- artifact.version = selected.label;
3091
- }
3092
- }
3093
- const installOnce = async (overwrite) => {
3094
- return await vscode.window.withProgress({
3095
- location: vscode.ProgressLocation.Window,
3096
- title: `Installing engine "${artifact.slug}"`,
3097
- cancellable: false,
3098
- }, async (progress) => {
3099
- let files;
3100
- if (isExternal && artifact.sourceUrl) {
3101
- progress.report({ message: "Downloading from GitHub..." });
3102
- const parsed = parseGitHubUrl(artifact.sourceUrl);
3103
- files = await downloadFromExternalGitHub({
3104
- owner: parsed.owner,
3105
- repo: parsed.repo,
3106
- ref: parsed.ref || "main",
3107
- path: parsed.path,
3108
- }, outputChannel);
3109
- }
3110
- else {
3111
- progress.report({ message: "Downloading from store..." });
3112
- files = await downloadFromStore({
3113
- type: "engine",
3114
- slug: artifact.slug,
3115
- version: artifact.version,
3116
- }, outputChannel);
3117
- }
3118
- progress.report({ message: "Validating and installing..." });
3119
- return await installCustomEngineFromFiles(files, {
3120
- slug: artifact.slug,
3121
- version: artifact.version,
3122
- sourceUrl: artifact.sourceUrl,
3123
- overwrite,
3124
- logger: outputChannel,
3125
- });
3126
- });
3127
- };
3128
- let result;
3129
- try {
3130
- result = await installOnce(false);
3131
- }
3132
- catch (error) {
3133
- const errorMsg = error instanceof Error ? error.message : String(error);
3134
- if (!errorMsg.includes("already exists")) {
3135
- log(outputChannel, `[AgentIDE] Engine install error: ${errorMsg}`);
3136
- showError(`AgentIDE: ${errorMsg}`);
3137
- return;
3138
- }
3139
- const overwrite = await vscode.window.showWarningMessage(errorMsg, { modal: true }, "Overwrite", "Cancel");
3140
- if (overwrite !== "Overwrite") {
3141
- return;
3142
- }
3143
- try {
3144
- result = await installOnce(true);
3145
- }
3146
- catch (retryError) {
3147
- const retryMsg = retryError instanceof Error ? retryError.message : String(retryError);
3148
- log(outputChannel, `[AgentIDE] Engine install error: ${retryMsg}`);
3149
- showError(`AgentIDE: ${retryMsg}`);
3150
- return;
3151
- }
3152
- }
3153
- const { invalidateLocalIndex } = await import("./store/oramaIndex.js");
3154
- invalidateLocalIndex();
3155
- if (!result) {
3156
- return;
3157
- }
3158
- clearCustomEngineRuntimeCache(state, result.id);
3159
- await refreshCustomEnginePicker(outputChannel);
3160
- const action = await vscode.window.showInformationMessage(`Installed engine "${result.displayName}"`, "List Engines");
3161
- if (action === "List Engines") {
3162
- await vscode.commands.executeCommand("agentide.customEngine.list");
3163
- }
3164
- }));
3165
- // Install Spotlight view from store or external GitHub
3166
- context.subscriptions.push(vscode.commands.registerCommand("agentide.view.install", async (artifactArg) => {
3167
- const { workspaceRoot } = getWorkspaceRoot(outputChannel);
3168
- const { downloadFromStore, downloadFromExternalGitHub, listStoreVersions, isStoreUrl, parseGitHubUrl, parseStoreUrl, } = await import("./store/index.js");
3169
- const { installSpotlightViewFromFiles } = await import("./spotlight/install.js");
3170
- let artifact = artifactArg;
3171
- if (!artifact) {
3172
- const url = await vscode.window.showInputBox({
3173
- prompt: "Enter Spotlight view store URL or GitHub URL",
3174
- placeHolder: "e.g., view/cost-ops or https://github.com/user/repo/tree/main/spotlight/cost-ops",
3175
- });
3176
- if (!url) {
3177
- return;
3178
- }
3179
- if (isStoreUrl(url)) {
3180
- artifact = parseStoreUrl(url);
3181
- }
3182
- else {
3183
- const parsed = parseGitHubUrl(url);
3184
- const pathParts = (parsed.path || parsed.repo).split("/");
3185
- artifact = {
3186
- type: "view",
3187
- slug: pathParts[pathParts.length - 1] || parsed.repo,
3188
- version: parsed.ref,
3189
- sourceUrl: url,
3190
- };
3191
- }
3192
- }
3193
- const isExternal = artifact.sourceUrl && !isStoreUrl(artifact.sourceUrl);
3194
- if (!artifact.version && !isExternal) {
3195
- const versions = await listStoreVersions("view", artifact.slug);
3196
- if (versions.length === 0) {
3197
- artifact.version = "main";
3198
- }
3199
- else {
3200
- const selected = await vscode.window.showQuickPick(versions.map((v) => ({
3201
- label: v.version,
3202
- description: v.isPrerelease ? "(pre-release)" : "",
3203
- })), { placeHolder: "Select version to install" });
3204
- if (!selected) {
3205
- return;
3206
- }
3207
- artifact.version = selected.label;
3208
- }
3209
- }
3210
- const installOnce = async (overwrite, activate) => {
3211
- return await vscode.window.withProgress({
3212
- location: vscode.ProgressLocation.Window,
3213
- title: `Installing Spotlight view "${artifact.slug}"`,
3214
- cancellable: false,
3215
- }, async (progress) => {
3216
- let files;
3217
- if (isExternal && artifact.sourceUrl) {
3218
- progress.report({ message: "Downloading from GitHub..." });
3219
- const parsed = parseGitHubUrl(artifact.sourceUrl);
3220
- const externalFiles = await downloadFromExternalGitHub({
3221
- owner: parsed.owner,
3222
- repo: parsed.repo,
3223
- ref: parsed.ref || "main",
3224
- path: parsed.path,
3225
- }, outputChannel);
3226
- files = externalFiles.map((file) => ({
3227
- path: file.path,
3228
- content: file.content,
3229
- }));
3230
- }
3231
- else {
3232
- progress.report({ message: "Downloading from store..." });
3233
- const storeFiles = await downloadFromStore({
3234
- type: "view",
3235
- slug: artifact.slug,
3236
- version: artifact.version,
3237
- }, outputChannel);
3238
- files = storeFiles;
3239
- }
3240
- progress.report({ message: "Installing view..." });
3241
- return await installSpotlightViewFromFiles(files, {
3242
- slug: artifact.slug,
3243
- version: artifact.version,
3244
- overwrite,
3245
- activate,
3246
- workspaceRoot,
3247
- logger: outputChannel,
3248
- });
3249
- });
3250
- };
3251
- let result;
3252
- try {
3253
- result = await installOnce(false, false);
3254
- }
3255
- catch (error) {
3256
- const errorMsg = error instanceof Error ? error.message : String(error);
3257
- if (!errorMsg.includes("already exists")) {
3258
- log(outputChannel, `[AgentIDE] Spotlight view install error: ${errorMsg}`);
3259
- showError(`AgentIDE: ${errorMsg}`);
3260
- return;
3261
- }
3262
- const overwrite = await vscode.window.showWarningMessage(errorMsg, { modal: true }, "Overwrite", "Cancel");
3263
- if (overwrite !== "Overwrite") {
3264
- return;
3265
- }
3266
- try {
3267
- result = await installOnce(true, false);
3268
- }
3269
- catch (retryError) {
3270
- const retryMsg = retryError instanceof Error ? retryError.message : String(retryError);
3271
- log(outputChannel, `[AgentIDE] Spotlight view install error: ${retryMsg}`);
3272
- showError(`AgentIDE: ${retryMsg}`);
3273
- return;
3274
- }
3275
- }
3276
- const { invalidateLocalIndex } = await import("./store/oramaIndex.js");
3277
- invalidateLocalIndex();
3278
- if (!result) {
3279
- return;
3280
- }
3281
- const dashboard = _state?.analyticsDashboard;
3282
- if (dashboard) {
3283
- await dashboard.refreshViewsFromDisk();
3284
- }
3285
- const action = await vscode.window.showInformationMessage(`Installed Spotlight view "${result.id}" v${result.version || artifact.version || "main"}`, "Open Spotlight", "Activate View");
3286
- if (action === "Open Spotlight") {
3287
- await vscode.commands.executeCommand("agentide.analytics.openDashboard");
3288
- }
3289
- else if (action === "Activate View") {
3290
- const { setActiveSpotlightView } = await import("./spotlight/install.js");
3291
- await setActiveSpotlightView(result.viewsConfigPath, result.id);
3292
- const dashboardAfterActivate = _state?.analyticsDashboard;
3293
- if (dashboardAfterActivate) {
3294
- await dashboardAfterActivate.refreshViewsFromDisk();
3295
- }
3296
- await vscode.commands.executeCommand("agentide.analytics.openDashboard");
3297
- }
3298
- }));
3299
- // Update agent from User Library
3300
- context.subscriptions.push(vscode.commands.registerCommand("agentide.pack.update", async () => {
3301
- const { workspaceRoot } = getWorkspaceRoot(outputChannel);
3302
- const { AgentPackManager } = await import("./agentpack/index.js");
3303
- const packManager = new AgentPackManager(syncService, () => workspaceRoot, () => config.storagePath, outputChannel);
3304
- const packs = await packManager.listInstalledWithCleanup();
3305
- const updatable = [];
3306
- for (const pack of packs) {
3307
- if (pack.id === "default") {
3308
- continue;
3309
- }
3310
- const newVersion = await packManager.checkAgentUpdate(pack.id);
3311
- if (newVersion) {
3312
- updatable.push({ id: pack.id, version: pack.version, newVersion });
3313
- }
3314
- }
3315
- if (updatable.length === 0) {
3316
- showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: All agents are up to date`);
3317
- return;
3318
- }
3319
- const items = updatable.map((u) => ({
3320
- label: u.id,
3321
- description: `v${u.version} → v${u.newVersion}`,
3322
- }));
3323
- const selected = await vscode.window.showQuickPick(items, {
3324
- placeHolder: "Select an agent to update",
3325
- title: "Update Agent from User Library",
3326
- });
3327
- if (!selected) {
3328
- return;
3329
- }
3330
- const confirm = await vscode.window.showWarningMessage(`Update "${selected.label}" from User Library? Current version will be backed up.`, { modal: true }, "Update", "Cancel");
3331
- if (confirm !== "Update") {
3332
- return;
3333
- }
3334
- try {
3335
- const version = await packManager.updateFromLibrary(selected.label);
3336
- showInfo(`AgentIDE: Updated "${selected.label}" to v${version}`);
3337
- }
3338
- catch (e) {
3339
- const errorMsg = e instanceof Error ? e.message : String(e);
3340
- log(outputChannel, `[AgentIDE] Update error: ${errorMsg}`);
3341
- showError(`AgentIDE: ${errorMsg}`);
3342
- }
3343
- }));
3344
- // Duplicate agent
3345
- context.subscriptions.push(vscode.commands.registerCommand("agentide.pack.duplicate", async () => {
3346
- const { workspaceRoot } = getWorkspaceRoot(outputChannel);
3347
- const { AgentPackManager } = await import("./agentpack/index.js");
3348
- const packManager = new AgentPackManager(syncService, () => workspaceRoot, () => config.storagePath, outputChannel);
3349
- const packs = await packManager.listInstalledWithCleanup();
3350
- if (packs.length === 0) {
3351
- showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: No agents to duplicate`);
3352
- return;
3353
- }
3354
- const items = packs.map((p) => ({
3355
- label: p.id,
3356
- description: `v${p.version}`,
3357
- }));
3358
- const selected = await vscode.window.showQuickPick(items, {
3359
- placeHolder: "Select an agent to duplicate",
3360
- title: "Duplicate Agent",
3361
- });
3362
- if (!selected) {
3363
- return;
3364
- }
3365
- try {
3366
- const newAgentId = await packManager.duplicate(selected.label);
3367
- showInfo(`AgentIDE: Created "${newAgentId}" as copy of "${selected.label}"`);
3368
- // Open the new agent's AGENTS.md
3369
- const agentsPath = path.join((0, paths_1.getAgentideDir)(workspaceRoot), paths_1.AGENT_CONSTANTS.AGENTS_DIR, newAgentId, paths_1.AGENT_CONSTANTS.AGENTS_MD);
3370
- if (await (0, utils_1.pathExists)(agentsPath)) {
3371
- const doc = await vscode.workspace.openTextDocument(agentsPath);
3372
- await vscode.window.showTextDocument(doc);
3373
- }
3374
- }
3375
- catch (e) {
3376
- const errorMsg = e instanceof Error ? e.message : String(e);
3377
- log(outputChannel, `[AgentIDE] Duplicate error: ${errorMsg}`);
3378
- showError(`AgentIDE: ${errorMsg}`);
3379
- }
3380
- }));
3381
- // Refresh/discover packs - finds and registers any new packs on disk
3382
- context.subscriptions.push(vscode.commands.registerCommand("agentide.pack.refresh", async () => {
3383
- const { workspaceRoot } = getWorkspaceRoot(outputChannel);
3384
- const { AgentPackManager } = await import("./agentpack/index.js");
3385
- const packManager = new AgentPackManager(syncService, () => workspaceRoot, () => config.storagePath, outputChannel);
3386
- try {
3387
- const { registered } = await packManager.repairUnregisteredAgents();
3388
- if (registered.length > 0) {
3389
- showInfo(`AgentIDE: Discovered ${registered.length} new pack(s): ${registered.join(", ")}`);
3390
- }
3391
- else {
3392
- showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: No new packs found`);
3393
- }
3394
- return { registered };
3395
- }
3396
- catch (e) {
3397
- const errorMsg = e instanceof Error ? e.message : String(e);
3398
- log(outputChannel, `[AgentIDE] Pack refresh error: ${errorMsg}`);
3399
- showError(`AgentIDE: ${errorMsg}`);
3400
- return { registered: [] };
3401
- }
3402
- }));
3403
- // Reset default agent
3404
- context.subscriptions.push(vscode.commands.registerCommand("agentide.pack.resetDefault", async () => {
3405
- const confirm = await vscode.window.showWarningMessage("Reset the default agent? This will restore it from bundled templates. Current default agent will be backed up.", { modal: true }, "Reset", "Cancel");
3406
- if (confirm !== "Reset") {
3407
- return;
3408
- }
3409
- const { workspaceRoot } = getWorkspaceRoot(outputChannel);
3410
- const { AgentPackManager } = await import("./agentpack/index.js");
3411
- const packManager = new AgentPackManager(syncService, () => workspaceRoot, () => config.storagePath, outputChannel);
3412
- try {
3413
- await packManager.resetDefault(getBundledBasePromptsDir());
3414
- showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: Default agent reset from bundled templates`);
3415
- // Force sync
3416
- await syncService.flushAgentideRootUpdate(workspaceRoot, outputChannel, { force: true, allowDuringActiveTurn: true });
3417
- }
3418
- catch (e) {
3419
- const errorMsg = e instanceof Error ? e.message : String(e);
3420
- log(outputChannel, `[AgentIDE] Reset error: ${errorMsg}`);
3421
- showError(`AgentIDE: ${errorMsg}`);
3422
- }
3423
- }));
3424
- // Main chat command
3425
- context.subscriptions.push(vscode.commands.registerCommand("agentide.chat", async (args) => {
3426
- return handleChatCommand(state, args);
3427
- }));
3428
- // Cancel an in-flight streamed chat run
3429
- context.subscriptions.push(vscode.commands.registerCommand("agentide.chat.cancel", async (args) => {
3430
- const streamId = args?.streamId;
3431
- if (!streamId) {
3432
- return { cancelled: false, error: "streamId is required" };
3433
- }
3434
- const run = _activeRunsByStreamId.get(streamId);
3435
- if (!run) {
3436
- log(outputChannel, `[AgentIDE] Cancel ignored: no active run for streamId=${streamId}`);
3437
- rejectPendingQuestionsForStream(streamId, 'Run cancelled');
3438
- return { cancelled: false };
3439
- }
3440
- log(outputChannel, `[AgentIDE] Cancel requested: streamId=${streamId}, engine=${run.engine}, ageMs=${Date.now() - run.startedAt}`);
3441
- try {
3442
- run.abortController.abort();
3443
- }
3444
- catch {
3445
- // ignore
3446
- }
3447
- rejectPendingQuestionsForStream(streamId, 'Run cancelled');
3448
- return { cancelled: true };
3449
- }));
3450
- context.subscriptions.push(vscode.commands.registerCommand("agentide.chat.answerQuestion", async (args) => {
3451
- const streamId = args?.streamId;
3452
- const questionId = args?.questionId;
3453
- if (!streamId || !questionId) {
3454
- return { ok: false, error: 'streamId and questionId are required' };
3455
- }
3456
- const pending = _pendingQuestionsById.get(questionId);
3457
- if (!pending || pending.streamId !== streamId) {
3458
- return { ok: false, error: 'Question not found or already resolved' };
3459
- }
3460
- const normalized = normalizeQuestionAnswer(args?.answer);
3461
- resolvePendingQuestion(questionId, normalized);
3462
- return { ok: true };
3463
- }));
3464
- }
3465
- // -----------------------------------------------------------------------------
3466
- // User Permission Mapping
3467
- // -----------------------------------------------------------------------------
3468
- /**
3469
- * Get user permissions from VS Code settings (unified model).
3470
- */
3471
- function getUserPermissions() {
3472
- const cfg = vscode.workspace.getConfiguration("agentide");
3473
- return {
3474
- fileAccess: cfg.get("permissions.fileAccess", "full"),
3475
- };
3476
- }
3477
- function getConfiguredAdditionalEngineDir() {
3478
- return vscode.workspace
3479
- .getConfiguration("agentide")
3480
- .get("additionalEngineDir");
3481
- }
3482
- function clearCustomEngineRuntimeCache(state, engineId) {
3483
- const customEngine = state.engines.custom;
3484
- try {
3485
- customEngine?.clearInstances?.(engineId);
3486
- }
3487
- catch (error) {
3488
- log(state.outputChannel, `[AgentIDE] Custom engine cache clear warning: ${error instanceof Error ? error.message : String(error)}`);
3489
- }
3490
- }
3491
- async function refreshCustomEnginePicker(outputChannel) {
3492
- try {
3493
- await vscode.commands.executeCommand("agentide.engine.refresh");
3494
- }
3495
- catch (error) {
3496
- log(outputChannel, `[AgentIDE] Custom engine picker refresh warning: ${error instanceof Error ? error.message : String(error)}`);
3497
- }
3498
- }
3499
- // -----------------------------------------------------------------------------
3500
- // Chat Command Handler
3501
- // -----------------------------------------------------------------------------
3502
- // Shared session event writer for IDE Layer 2 analytics (singleton to avoid repeated mkdir)
3503
- const _sessionEventWriter = new sessionEvents_1.SessionEventWriter();
3504
- async function handleChatCommand(state, args) {
3505
- const { outputChannel, engines, syncService, config } = state;
3506
- const { engine: engineId, streamId } = args;
3507
- let { message } = args;
3508
- const incomingOptions = args.options ?? {};
3509
- // Check for gateway request marker: [gw:token]message
3510
- // If present, extract the token and look up the gateway emitter for composite streaming
3511
- let gatewayEmitter;
3512
- const gatewayMarkerMatch = message.match(/^\[gw:(gw-[^\]]+)\]/);
3513
- if (gatewayMarkerMatch) {
3514
- const gatewayToken = gatewayMarkerMatch[1];
3515
- // Strip the marker from the message
3516
- message = message.slice(gatewayMarkerMatch[0].length);
3517
- log(outputChannel, `[AgentIDE] Gateway request detected, token=${gatewayToken.slice(0, 20)}...`);
3518
- // Look up the gateway emitter
3519
- const { GatewayService } = await import("./gateway/service.js");
3520
- gatewayEmitter = GatewayService.getGatewayEmitter(gatewayToken);
3521
- if (gatewayEmitter) {
3522
- log(outputChannel, `[AgentIDE] Gateway emitter found, will stream to both Chat UI and Gateway`);
3523
- }
3524
- else {
3525
- log(outputChannel, `[AgentIDE] Gateway emitter NOT found for token ${gatewayToken.slice(0, 20)}...`);
3526
- }
3527
- }
3528
- // Resolve workspace root
3529
- const { workspaceRoot, additionalDirectories, isHomeFallback } = getWorkspaceRoot(outputChannel, incomingOptions.workspaceRoot, incomingOptions.additionalDirectories);
3530
- if (streamId && isHomeFallback) {
3531
- await warnHomeFallbackOnce(outputChannel, streamId);
3532
- }
3533
- const remoteManifest = await syncService.getActiveAgentManifest(workspaceRoot, outputChannel, syncService.getActivePackId(workspaceRoot) ?? state.activePackId);
3534
- const remoteUrl = remoteManifest?.spec?.remote?.url?.trim();
3535
- if (remoteUrl) {
3536
- return (0, handleRemoteChat_js_1.handleRemoteServeChat)({
3537
- outputChannel,
3538
- syncService,
3539
- sessionEventWriter: _sessionEventWriter,
3540
- activeRunsByStreamId: _activeRunsByStreamId,
3541
- rejectPendingQuestionsForStream,
3542
- askQuestionViaWorkbenchTool,
3543
- askQuestionFromChatUI,
3544
- getServeAuth: async () => {
3545
- if (!_extensionContext) {
3546
- return undefined;
3547
- }
3548
- const session = await (0, provider_js_1.getAgentHippoAccessToken)(_extensionContext);
3549
- if (!session) {
3550
- return undefined;
3551
- }
3552
- return {
3553
- accessToken: session.accessToken,
3554
- userEmail: session.email,
3555
- };
3556
- },
3557
- ensureSignedIn: async () => {
3558
- if (!_extensionContext) {
3559
- return undefined;
3560
- }
3561
- const session = await (0, signInFlow_js_1.ensureAgentHippoSignedIn)(_extensionContext);
3562
- if (!session) {
3563
- return undefined;
3564
- }
3565
- return {
3566
- accessToken: session.accessToken,
3567
- userEmail: session.email,
3568
- };
3569
- },
3570
- log,
3571
- }, {
3572
- engine: engineId,
3573
- message,
3574
- options: args.options,
3575
- streamId,
3576
- sessionResource: args.sessionResource,
3577
- requestId: args.requestId,
3578
- remoteUrl,
3579
- remoteManifest,
3580
- workspaceRoot,
3581
- incomingOptions,
3582
- gatewayEmitter,
3583
- });
3584
- }
3585
- // Build resolved options (include activePackId from state)
3586
- let options = {
3587
- ...incomingOptions,
3588
- workspaceRoot,
3589
- additionalDirectories,
3590
- agentPackId: state.activePackId, // Pass active pack to engine
3591
- // agentPackVersion is set below after manifest is loaded
3592
- };
3593
- if (!streamId) {
3594
- return {
3595
- error: "streamId is required - non-streaming mode is no longer supported",
3596
- };
3597
- }
3598
- // Resolve engine. Custom engine IDs are routed through the dynamic custom loader.
3599
- let runtimeEngineId = engineId;
3600
- let engine = engines[runtimeEngineId];
3601
- if (!engine &&
3602
- runtimeEngineId !== "codex" &&
3603
- runtimeEngineId !== "claude" &&
3604
- engines.custom) {
3605
- options = {
3606
- ...options,
3607
- engineId: options.engineId ?? runtimeEngineId,
3608
- };
3609
- runtimeEngineId = "custom";
3610
- engine = engines.custom;
3611
- log(outputChannel, `[AgentIDE] Routing requested engine "${engineId}" through custom runtime loader`);
3612
- }
3613
- if (!engine) {
3614
- const errorMsg = `Unknown engine: ${engineId}`;
3615
- log(outputChannel, `[AgentIDE] Error: ${errorMsg}`);
3616
- return { error: errorMsg };
3617
- }
3618
- log(outputChannel, `[AgentIDE] Chat request for engine=${engineId} (runtime=${runtimeEngineId}), streamId: ${streamId}, useLiteLLM: ${options.useLiteLLM || false}`);
3619
- // Create per-run abort controller so Workbench can cancel this stream
3620
- const abortController = new AbortController();
3621
- _activeRunsByStreamId.set(streamId, {
3622
- streamId,
3623
- engine: runtimeEngineId,
3624
- startedAt: Date.now(),
3625
- abortController,
3626
- });
3627
- // Create emitter - if gateway emitter is present, create a composite that streams to both
3628
- const ipcEmitter = (0, utils_1.createIPCStreamEmitter)(streamId);
3629
- const chatSessionResource = args.sessionResource;
3630
- const chatRequestId = args.requestId;
3631
- const questionEmitter = {
3632
- ...ipcEmitter,
3633
- async question(payload) {
3634
- // Use workbench askQuestions tool when we have session context (same path as Copilot)
3635
- if (chatSessionResource) {
3636
- return await askQuestionViaWorkbenchTool(chatSessionResource, chatRequestId, payload, abortController.signal);
3637
- }
3638
- return await askQuestionFromChatUI(streamId, payload);
3639
- },
3640
- };
3641
- const emitter = gatewayEmitter ? {
3642
- ...questionEmitter,
3643
- // Composite emitter: streams to both Chat UI (via IPC) and Gateway (via websocket)
3644
- async thinking(delta) {
3645
- await ipcEmitter.thinking(delta);
3646
- // Send to Gateway with raw tags for CLI formatting
3647
- await gatewayEmitter.thinking(`<thinking>${delta}</thinking>`);
3648
- },
3649
- async text(delta) {
3650
- await ipcEmitter.text(delta);
3651
- await gatewayEmitter.text(delta);
3652
- },
3653
- async toolStart(toolName, input, toolCallId, metadata) {
3654
- await ipcEmitter.toolStart(toolName, input, toolCallId, metadata);
3655
- await gatewayEmitter.toolStart(toolName, input, toolCallId, metadata);
3656
- },
3657
- async toolEnd(toolName, toolCallId, result, isError, metadata) {
3658
- await ipcEmitter.toolEnd(toolName, toolCallId, result, isError, metadata);
3659
- await gatewayEmitter.toolEnd(toolName, toolCallId, result, isError, metadata);
3660
- },
3661
- async progress(msg) {
3662
- await ipcEmitter.progress(msg);
3663
- await gatewayEmitter.progress(msg);
3664
- },
3665
- async question(payload) {
3666
- const answer = await questionEmitter.question(payload);
3667
- await gatewayEmitter.progress(`Question answered: ${questionPromptToHeader(payload.prompt)}`);
3668
- return answer;
3669
- },
3670
- async error(msg) {
3671
- await ipcEmitter.error(msg);
3672
- await gatewayEmitter.error(msg);
3673
- },
3674
- async done() {
3675
- await ipcEmitter.done();
3676
- await gatewayEmitter.done();
3677
- },
3678
- } : questionEmitter;
3679
- const terminalLog = getTerminalLogInfo(options);
3680
- await appendTerminalAttachmentsToLog(args.context, streamId, outputChannel, terminalLog?.uri);
3681
- // Persist image attachments (so agents can read a real file path instead of guessing)
3682
- await persistImageAttachments(args.context, options, outputChannel);
3683
- // Persist file/folder attachments (so agents can read them even if they were outside the workspace)
3684
- await persistFileAndDirectoryAttachments(args.context, options, outputChannel);
3685
- const contextSuffix = formatSdkContextSuffix(args.context, terminalLog?.relativePath);
3686
- const enrichedMessage = contextSuffix
3687
- ? `${message}\n\n${contextSuffix}`
3688
- : message;
3689
- // Create Layer 2 session event observability (before try so it's accessible in catch)
3690
- const requestId = (0, base_1.generateRequestId)();
3691
- const sessionId = options.sessionId ?? `ide-${Date.now()}`;
3692
- const observableEmitter = (0, sessionEvents_1.wrapEmitterWithObservability)(emitter, _sessionEventWriter, sessionId, requestId);
3693
- try {
3694
- // Prepare project sync
3695
- syncService.incrementActiveAgentTurns();
3696
- await syncService.ensureAgentideProjectPrepared(workspaceRoot, additionalDirectories, outputChannel);
3697
- // Always write paths.md for the effective workspaceRoot so users can discover what AgentIDE manages.
3698
- await syncService.writeManagedPathsManifest(config.codexHome, config.claudeConfigDir, workspaceRoot, additionalDirectories, outputChannel);
3699
- // Load manifest and resolve permissions
3700
- const manifest = await syncService.getActiveAgentManifest(workspaceRoot, outputChannel);
3701
- const manifestPerms = (0, permissions_1.parseManifestPermissions)(manifest);
3702
- const userPerms = getUserPermissions();
3703
- const effectivePerms = (0, permissions_1.enforcePermissions)(manifestPerms, userPerms);
3704
- log(outputChannel, `[AgentIDE] Permissions: manifest(files=${manifestPerms.fileAccess}) + user(files=${userPerms.fileAccess}) = effective(files=${effectivePerms.fileAccess})`);
3705
- // Add permissions + agent version + requestId to options
3706
- const optionsWithPerms = {
3707
- ...options,
3708
- sessionId,
3709
- permissions: effectivePerms,
3710
- agentPackVersion: manifest?.metadata?.version,
3711
- requestId, // Same requestId used by ObservableStreamEmitter for Layer 1/2 correlation
3712
- };
3713
- // Create runtime context with VS Code implementations.
3714
- // V1 permissions are non-interactive; always auto-approve tool requests.
3715
- const logger = new vscode_logger_1.VSCodeLogger(outputChannel);
3716
- const permissionHandler = new permission_handler_1.AutoApprovePermissionHandler();
3717
- const configuredCliPath = vscode.workspace
3718
- .getConfiguration("agentide")
3719
- .get("cli.path", "");
3720
- const cliHealth = await (0, runtime_1.getCliHealth)({
3721
- configuredPath: configuredCliPath,
3722
- extensionPath: _extensionContext?.extensionPath,
3723
- });
3724
- const userInstalledToolsDir = _extensionContext?.globalState?.get(BUNDLED_TOOLS_DIR_KEY);
3725
- const cliEnvPatch = (0, runtime_1.buildCliEnvPatch)({
3726
- cliPath: cliHealth.path,
3727
- workspaceRoot,
3728
- agentId: optionsWithPerms.agentPackId ?? 'default',
3729
- chatSessionId: optionsWithPerms.sessionId?.trim() || optionsWithPerms.contextSessionId?.trim(),
3730
- baseEnv: process.env,
3731
- extensionPath: _extensionContext?.extensionPath,
3732
- userInstalledToolsDir: userInstalledToolsDir ?? undefined,
3733
- });
3734
- if (cliEnvPatch.AGENTHIPPO_TOOLS_DIR) {
3735
- log(outputChannel, `[AgentIDE] Bundled tools dir available for runtime: ${cliEnvPatch.AGENTHIPPO_TOOLS_DIR}`);
3736
- }
3737
- const runtimeContext = {
3738
- logger,
3739
- editTracker: new vscode_edit_tracker_1.VSCodeEditTracker(new vscode_logger_1.VSCodeLogger(outputChannel, "[EditTracker]")),
3740
- configProvider: new vscode_config_provider_1.VSCodeConfigProvider(),
3741
- permissionHandler,
3742
- cliEnvPatch,
3743
- };
3744
- if (cliHealth.installed && cliHealth.path) {
3745
- log(outputChannel, `[AgentIDE] CLI available for agent runtime: ${cliHealth.path}`);
3746
- }
3747
- else {
3748
- log(outputChannel, `[AgentIDE] CLI not detected for runtime (skills may rely on '${branding_1.AGENTIDE_CLI_NAME}' on PATH)`);
3749
- }
3750
- log(outputChannel, `[AgentIDE] Analytics: session=${sessionId}, request=${requestId}, agent=${optionsWithPerms.agentPackId ?? 'default'}, version=${optionsWithPerms.agentPackVersion ?? 'workspace'}`);
3751
- // Emit turn_start event
3752
- await observableEmitter.emitTurnStart();
3753
- // Stream response
3754
- await engine.stream(enrichedMessage, optionsWithPerms, observableEmitter, runtimeContext, abortController.signal);
3755
- // Emit turn_end event
3756
- await observableEmitter.emitTurnEnd(true);
3757
- return { streaming: true };
3758
- }
3759
- catch (err) {
3760
- const errorMsg = err instanceof Error ? err.message : String(err);
3761
- log(outputChannel, `[AgentIDE] Error: ${errorMsg}`);
3762
- // Use observableEmitter (not raw emitter) so error is captured in Layer 2 session events
3763
- await observableEmitter.error(errorMsg);
3764
- await observableEmitter.emitTurnEnd(false);
3765
- return { error: errorMsg };
3766
- }
3767
- finally {
3768
- rejectPendingQuestionsForStream(streamId, 'Run finished');
3769
- _activeRunsByStreamId.delete(streamId);
3770
- syncService.decrementActiveAgentTurns();
3771
- }
3772
- }
3773
- function resolveWorkspaceRootUri(workspaceRoot) {
3774
- const folders = vscode.workspace.workspaceFolders ?? [];
3775
- const match = folders.find((f) => f.uri.fsPath === workspaceRoot);
3776
- if (match) {
3777
- return match.uri;
3778
- }
3779
- const primary = folders[0];
3780
- if (primary && workspaceRoot.startsWith("/")) {
3781
- // Preserve remote scheme/authority when possible.
3782
- return vscode.Uri.from({
3783
- scheme: primary.uri.scheme,
3784
- authority: primary.uri.authority,
3785
- path: workspaceRoot,
3786
- });
3787
- }
3788
- return vscode.Uri.file(workspaceRoot);
3789
- }
3790
- function dirnameUri(uri) {
3791
- const idx = uri.path.lastIndexOf("/");
3792
- return idx >= 0 ? uri.with({ path: uri.path.slice(0, idx) }) : uri;
3793
- }
3794
- function getTerminalLogInfo(options) {
3795
- const contextSessionId = options.contextSessionId?.trim() || options.sessionId?.trim();
3796
- if (!contextSessionId) {
3797
- return undefined;
3798
- }
3799
- const workspaceRootUri = resolveWorkspaceRootUri(options.workspaceRoot);
3800
- const uri = vscode.Uri.joinPath(workspaceRootUri, paths_1.AGENT_CONSTANTS.AGENTIDE_DIR_NAME, paths_1.AGENT_CONSTANTS.SESSIONS_DIR, contextSessionId, TERMINAL_LOG_FILE_NAME);
3801
- return {
3802
- uri,
3803
- relativePath: `${AGENTIDE_SESSIONS_DIR_NAME}/${contextSessionId}/${TERMINAL_LOG_FILE_NAME}`,
3804
- };
3805
- }
3806
- function getSessionAttachmentsDirInfo(options) {
3807
- const contextSessionId = options.contextSessionId?.trim() || options.sessionId?.trim();
3808
- if (!contextSessionId) {
3809
- return undefined;
3810
- }
3811
- const workspaceRootUri = resolveWorkspaceRootUri(options.workspaceRoot);
3812
- const dirUri = vscode.Uri.joinPath(workspaceRootUri, paths_1.AGENT_CONSTANTS.AGENTIDE_DIR_NAME, paths_1.AGENT_CONSTANTS.SESSIONS_DIR, contextSessionId, ATTACHMENTS_DIR_NAME);
3813
- return {
3814
- dirUri,
3815
- relativeDirPath: `${AGENTIDE_SESSIONS_DIR_NAME}/${contextSessionId}/${ATTACHMENTS_DIR_NAME}`,
3816
- };
3817
- }
3818
- function slugifyFileStem(name) {
3819
- const stem = name
3820
- .toLowerCase()
3821
- .replace(/[^a-z0-9]+/g, "-")
3822
- .replace(/^-+|-+$/g, "")
3823
- .slice(0, 60);
3824
- return stem || "attachment";
3825
- }
3826
- function imageExtensionFromMimeType(mimeType) {
3827
- switch ((mimeType ?? "").toLowerCase()) {
3828
- case "image/png":
3829
- return "png";
3830
- case "image/jpeg":
3831
- case "image/jpg":
3832
- return "jpg";
3833
- case "image/gif":
3834
- return "gif";
3835
- case "image/webp":
3836
- return "webp";
3837
- default:
3838
- return "png";
3839
- }
3840
- }
3841
- async function persistImageAttachments(ctx, options, outputChannel) {
3842
- const variables = ctx?.variables ?? [];
3843
- if (!ctx || variables.length === 0) {
3844
- return;
3845
- }
3846
- const images = variables.filter((v) => v.kind === "image" &&
3847
- typeof v.dataBase64 === "string" &&
3848
- v.dataBase64.length > 0);
3849
- if (images.length === 0) {
3850
- return;
3851
- }
3852
- const info = getSessionAttachmentsDirInfo(options);
3853
- if (!info) {
3854
- // No stable session folder -> cannot persist; leave bytes for now.
3855
- log(outputChannel, "[AgentIDE] Note: image attachment present but no contextSessionId; skipping persistence");
3856
- return;
3857
- }
3858
- try {
3859
- await (0, terminalLogger_1.ensureDirectory)(info.dirUri);
3860
- }
3861
- catch (e) {
3862
- log(outputChannel, `[AgentIDE] Warning: failed to create session attachments dir: ${e instanceof Error ? e.message : String(e)}`);
3863
- return;
3864
- }
3865
- let index = 0;
3866
- for (const img of images) {
3867
- index++;
3868
- const stem = slugifyFileStem(img.name || `image-${index}`);
3869
- const ext = imageExtensionFromMimeType(img.mimeType);
3870
- const fileName = images.length > 1 ? `${stem}-${index}.${ext}` : `${stem}.${ext}`;
3871
- const fileUri = vscode.Uri.joinPath(info.dirUri, fileName);
3872
- try {
3873
- const bytes = Buffer.from(img.dataBase64, "base64");
3874
- await vscode.workspace.fs.writeFile(fileUri, bytes);
3875
- // Update the variable entry to point at a real workspace path the agent can read.
3876
- img.uri = `${info.relativeDirPath}/${fileName}`;
3877
- // Drop bytes from the payload to keep prompt + memory small downstream.
3878
- delete img.dataBase64;
3879
- }
3880
- catch (e) {
3881
- log(outputChannel, `[AgentIDE] Warning: failed to persist image attachment "${img.name}": ${e instanceof Error ? e.message : String(e)}`);
3882
- }
3883
- }
3884
- }
3885
- async function persistFileAndDirectoryAttachments(ctx, options, outputChannel) {
3886
- const variables = ctx?.variables ?? [];
3887
- if (!ctx || variables.length === 0) {
3888
- return;
3889
- }
3890
- const candidates = variables.filter((v) => (v.kind === "file" || v.kind === "directory") &&
3891
- typeof v.uri === "string" &&
3892
- v.uri.trim().length > 0);
3893
- if (candidates.length === 0) {
3894
- return;
3895
- }
3896
- const info = getSessionAttachmentsDirInfo(options);
3897
- if (!info) {
3898
- log(outputChannel, "[AgentIDE] Note: file/folder attachment present but no contextSessionId; skipping persistence");
3899
- return;
3900
- }
3901
- try {
3902
- await (0, terminalLogger_1.ensureDirectory)(info.dirUri);
3903
- }
3904
- catch (e) {
3905
- log(outputChannel, `[AgentIDE] Warning: failed to create session attachments dir: ${e instanceof Error ? e.message : String(e)}`);
3906
- return;
3907
- }
3908
- const manifestUri = vscode.Uri.joinPath(info.dirUri, "manifest.json");
3909
- const readManifest = async () => {
3910
- try {
3911
- const raw = await vscode.workspace.fs.readFile(manifestUri);
3912
- const parsed = JSON.parse(Buffer.from(raw).toString("utf8"));
3913
- if (parsed &&
3914
- parsed.version === 1 &&
3915
- typeof parsed.files === "object" &&
3916
- typeof parsed.directories === "object") {
3917
- return parsed;
3918
- }
3919
- }
3920
- catch {
3921
- // ignore
3922
- }
3923
- return { version: 1, files: {}, directories: {} };
3924
- };
3925
- const writeManifest = async (manifest) => {
3926
- try {
3927
- const bytes = Buffer.from(JSON.stringify(manifest, null, 2), "utf8");
3928
- await vscode.workspace.fs.writeFile(manifestUri, bytes);
3929
- }
3930
- catch {
3931
- // ignore (best-effort)
3932
- }
3933
- };
3934
- const manifest = await readManifest();
3935
- let manifestDirty = false;
3936
- const MAX_FILES = 500;
3937
- const MAX_TOTAL_BYTES = 25 * 1024 * 1024; // 25MB total per request (best-effort)
3938
- const MAX_SINGLE_FILE_BYTES = 10 * 1024 * 1024; // 10MB per file (best-effort)
3939
- let totalFiles = 0;
3940
- let totalBytes = 0;
3941
- const isUnder = (parent, candidate) => {
3942
- try {
3943
- const parentNorm = path.resolve(parent);
3944
- const candidateNorm = path.resolve(candidate);
3945
- const rel = path.relative(parentNorm, candidateNorm);
3946
- return rel === "" || (!rel.startsWith("..") && !path.isAbsolute(rel));
3947
- }
3948
- catch {
3949
- return false;
3950
- }
3951
- };
3952
- const workspaceRoot = options.workspaceRoot;
3953
- const sessionRootSegment = path.normalize(`${path.sep}${AGENTIDE_SESSIONS_DIR_NAME.split("/").join(path.sep)}${path.sep}`);
3954
- const exists = async (uri) => {
3955
- try {
3956
- await vscode.workspace.fs.stat(uri);
3957
- return true;
3958
- }
3959
- catch {
3960
- return false;
3961
- }
3962
- };
3963
- const uniqueNameInDir = async (dir, name) => {
3964
- let candidateName = name;
3965
- let attempt = 1;
3966
- while (await exists(vscode.Uri.joinPath(dir, candidateName))) {
3967
- attempt++;
3968
- const ext = path.extname(name);
3969
- const base = ext ? name.slice(0, -ext.length) : name;
3970
- candidateName = `${base}-${attempt}${ext}`;
3971
- }
3972
- return candidateName;
3973
- };
3974
- const copyFile = async (srcPath, destDir) => {
3975
- const srcUri = vscode.Uri.file(srcPath);
3976
- try {
3977
- const stat = await vscode.workspace.fs.stat(srcUri);
3978
- if (stat.type !== vscode.FileType.File) {
3979
- return undefined;
3980
- }
3981
- const key = `${srcPath}::${stat.size}::${stat.mtime}`;
3982
- const existing = manifest.files[key];
3983
- if (existing) {
3984
- const existingUri = vscode.Uri.joinPath(destDir, existing.destName);
3985
- if (await exists(existingUri)) {
3986
- return existing.destName;
3987
- }
3988
- }
3989
- const baseName = path.basename(srcPath);
3990
- const destName = await uniqueNameInDir(destDir, baseName || "attachment");
3991
- const destUri = vscode.Uri.joinPath(destDir, destName);
3992
- if (stat.size > MAX_SINGLE_FILE_BYTES) {
3993
- log(outputChannel, `[AgentIDE] Note: skipping large file attachment (${stat.size} bytes): ${srcPath}`);
3994
- return undefined;
3995
- }
3996
- if (totalFiles + 1 > MAX_FILES ||
3997
- totalBytes + stat.size > MAX_TOTAL_BYTES) {
3998
- log(outputChannel, "[AgentIDE] Note: skipping additional file attachments due to size limits");
3999
- return undefined;
4000
- }
4001
- const bytes = await vscode.workspace.fs.readFile(srcUri);
4002
- await vscode.workspace.fs.writeFile(destUri, bytes);
4003
- totalFiles += 1;
4004
- totalBytes += stat.size;
4005
- manifest.files[key] = {
4006
- destName,
4007
- sourcePath: srcPath,
4008
- size: stat.size,
4009
- mtime: stat.mtime,
4010
- };
4011
- manifestDirty = true;
4012
- return destName;
4013
- }
4014
- catch (e) {
4015
- log(outputChannel, `[AgentIDE] Warning: failed to persist file attachment "${srcPath}": ${e instanceof Error ? e.message : String(e)}`);
4016
- return undefined;
4017
- }
4018
- };
4019
- const copyDirRecursive = async (srcUri, destUri) => {
4020
- const entries = await vscode.workspace.fs.readDirectory(srcUri);
4021
- for (const [name, type] of entries) {
4022
- if (totalFiles >= MAX_FILES || totalBytes >= MAX_TOTAL_BYTES) {
4023
- return;
4024
- }
4025
- const childSrc = vscode.Uri.joinPath(srcUri, name);
4026
- const childDest = vscode.Uri.joinPath(destUri, name);
4027
- if (type === vscode.FileType.Directory) {
4028
- await (0, terminalLogger_1.ensureDirectory)(childDest);
4029
- await copyDirRecursive(childSrc, childDest);
4030
- }
4031
- else if (type === vscode.FileType.File) {
4032
- try {
4033
- const stat = await vscode.workspace.fs.stat(childSrc);
4034
- if (stat.size > MAX_SINGLE_FILE_BYTES) {
4035
- continue;
4036
- }
4037
- if (totalFiles + 1 > MAX_FILES ||
4038
- totalBytes + stat.size > MAX_TOTAL_BYTES) {
4039
- return;
4040
- }
4041
- const bytes = await vscode.workspace.fs.readFile(childSrc);
4042
- await vscode.workspace.fs.writeFile(childDest, bytes);
4043
- totalFiles += 1;
4044
- totalBytes += stat.size;
4045
- }
4046
- catch {
4047
- // ignore
4048
- }
4049
- }
4050
- }
4051
- };
4052
- for (const v of candidates) {
4053
- const sourcePath = v.uri.trim();
4054
- // Only persist absolute, local paths outside the workspace root.
4055
- if (!path.isAbsolute(sourcePath)) {
4056
- continue;
4057
- }
4058
- if (workspaceRoot && isUnder(workspaceRoot, sourcePath)) {
4059
- continue;
4060
- }
4061
- if (path.normalize(sourcePath).includes(sessionRootSegment)) {
4062
- continue;
4063
- }
4064
- try {
4065
- const srcUri = vscode.Uri.file(sourcePath);
4066
- const stat = await vscode.workspace.fs.stat(srcUri);
4067
- if (stat.type === vscode.FileType.Directory && v.kind === "directory") {
4068
- const key = `${sourcePath}::${stat.mtime}`;
4069
- const existing = manifest.directories[key];
4070
- if (existing) {
4071
- const existingUri = vscode.Uri.joinPath(info.dirUri, existing.destName);
4072
- if (await exists(existingUri)) {
4073
- v.uri = `${info.relativeDirPath}/${existing.destName}`;
4074
- continue;
4075
- }
4076
- }
4077
- const baseName = path.basename(sourcePath) || "folder";
4078
- const destName = await uniqueNameInDir(info.dirUri, baseName);
4079
- const destDirUri = vscode.Uri.joinPath(info.dirUri, destName);
4080
- await (0, terminalLogger_1.ensureDirectory)(destDirUri);
4081
- await copyDirRecursive(srcUri, destDirUri);
4082
- manifest.directories[key] = { destName, sourcePath, mtime: stat.mtime };
4083
- manifestDirty = true;
4084
- v.uri = `${info.relativeDirPath}/${destName}`;
4085
- }
4086
- else if (stat.type === vscode.FileType.File && v.kind === "file") {
4087
- const destName = await copyFile(sourcePath, info.dirUri);
4088
- if (destName) {
4089
- v.uri = `${info.relativeDirPath}/${destName}`;
4090
- }
4091
- }
4092
- }
4093
- catch {
4094
- // ignore (best-effort)
4095
- }
4096
- }
4097
- if (manifestDirty) {
4098
- await writeManifest(manifest);
4099
- }
4100
- }
4101
- async function appendTerminalAttachmentsToLog(ctx, streamId, outputChannel, terminalLogUri) {
4102
- if (!terminalLogUri) {
4103
- return;
4104
- }
4105
- const variables = ctx?.variables ?? [];
4106
- // Terminal command attachments (from @terminalCommand or terminal command history)
4107
- const terminalCmdVars = variables.filter((v) => v.kind === "terminalCommand" &&
4108
- typeof v.output === "string" &&
4109
- v.output.trim().length > 0);
4110
- // Terminal selection attachments (generated by terminal chat tools with a stable id prefix).
4111
- const terminalSelectionVars = variables.filter((v) => v.kind === "generic" &&
4112
- typeof v.text === "string" &&
4113
- v.text.trim().length > 0 &&
4114
- (v.isTerminalSelection ||
4115
- (typeof v.id === "string" && v.id.startsWith("terminal-selection-"))));
4116
- if (terminalCmdVars.length === 0 && terminalSelectionVars.length === 0) {
4117
- return;
4118
- }
4119
- try {
4120
- await (0, terminalLogger_1.ensureDirectory)(dirnameUri(terminalLogUri));
4121
- const nowIso = new Date().toISOString();
4122
- const lines = [];
4123
- lines.push(`<!-- TERMINAL_ATTACHMENTS STREAM:${streamId} TIME:${nowIso} -->`);
4124
- lines.push("");
4125
- // Write terminal command outputs
4126
- for (const t of terminalCmdVars) {
4127
- const cmd = (t.command ?? t.name ?? "").toString().trim();
4128
- lines.push("## Terminal Command");
4129
- if (cmd) {
4130
- lines.push(`- Command: ${cmd}`);
4131
- }
4132
- if (typeof t.exitCode === "number") {
4133
- lines.push(`- Exit code: ${t.exitCode}`);
4134
- }
4135
- if (t.uri) {
4136
- lines.push(`- Resource: ${t.uri}`);
4137
- }
4138
- lines.push("");
4139
- lines.push("```text");
4140
- lines.push(t.output ?? "");
4141
- lines.push("```");
4142
- lines.push("");
4143
- }
4144
- // Write terminal selection content
4145
- for (const t of terminalSelectionVars) {
4146
- const title = t.name || "Terminal Selection";
4147
- lines.push(`## ${title}`);
4148
- lines.push("");
4149
- lines.push("```text");
4150
- lines.push(t.text ?? "");
4151
- lines.push("```");
4152
- lines.push("");
4153
- }
4154
- lines.push(`<!-- TERMINAL_ATTACHMENTS_END STREAM:${streamId} -->`);
4155
- lines.push("");
4156
- await (0, terminalLogger_1.appendTextFileWithRotation)(terminalLogUri, lines.join("\n"), MAX_TERMINAL_LOG_BYTES);
4157
- }
4158
- catch (e) {
4159
- log(outputChannel, `[AgentIDE] Warning: failed to persist terminal attachments for grep: ${e instanceof Error ? e.message : String(e)}`);
4160
- }
4161
- }
4162
- function formatSdkContextSuffix(ctx, terminalLogRelPath) {
4163
- if (!ctx) {
4164
- return "";
4165
- }
4166
- const parts = [];
4167
- if (ctx.selection?.text && ctx.selection.text.trim()) {
4168
- const headerBits = [];
4169
- if (ctx.selection.uri) {
4170
- headerBits.push(`**File:** \`${ctx.selection.uri}\``);
4171
- }
4172
- if (ctx.selection.range) {
4173
- const r = ctx.selection.range;
4174
- headerBits.push(`**Range:** ${r.startLineNumber}:${r.startColumn}-${r.endLineNumber}:${r.endColumn}`);
4175
- }
4176
- parts.push("## Currently Selected Code");
4177
- if (headerBits.length) {
4178
- parts.push(headerBits.join(" \n"));
4179
- parts.push("");
4180
- }
4181
- const lang = (ctx.selection.languageId ?? "").trim();
4182
- parts.push(`\`\`\`${lang}`);
4183
- parts.push(ctx.selection.text);
4184
- parts.push("```");
4185
- }
4186
- const variables = ctx.variables ?? [];
4187
- if (variables.length) {
4188
- parts.push("## Attached Context");
4189
- for (const v of variables) {
4190
- switch (v.kind) {
4191
- case "terminalCommand": {
4192
- const cmd = v.command?.trim() || v.name;
4193
- parts.push(`### Terminal`);
4194
- parts.push(`**Command:** \`${cmd}\``);
4195
- if (v.uri) {
4196
- parts.push(`**Resource:** \`${v.uri}\``);
4197
- }
4198
- if (typeof v.exitCode === "number") {
4199
- parts.push(`**Exit code:** ${v.exitCode}`);
4200
- }
4201
- // Keep prompt small: persist output to a session log file and tell the agent where to grep.
4202
- if (terminalLogRelPath) {
4203
- parts.push(`**Output:** saved to \`${terminalLogRelPath}\` (use \`rg\`/ \`grep\`)`);
4204
- }
4205
- else if (v.output && v.output.trim()) {
4206
- // Fallback when no session id is available: inline a small tail so the agent still sees errors.
4207
- const tail = v.output.length > 2000
4208
- ? `…(truncated)\n${v.output.slice(-2000)}`
4209
- : v.output;
4210
- parts.push("");
4211
- parts.push("```text");
4212
- parts.push(tail);
4213
- parts.push("```");
4214
- }
4215
- parts.push("");
4216
- break;
4217
- }
4218
- case "paste": {
4219
- const lang = (v.language ?? "").trim();
4220
- const title = v.name || "Paste";
4221
- parts.push(`### ${title}`);
4222
- if (v.code && v.code.trim()) {
4223
- parts.push(`\`\`\`${lang}`);
4224
- parts.push(v.code);
4225
- parts.push("```");
4226
- }
4227
- parts.push("");
4228
- break;
4229
- }
4230
- case "file":
4231
- case "directory":
4232
- case "promptFile": {
4233
- const target = v.uri ?? v.name;
4234
- parts.push(`- **${v.kind}**: \`${target}\``);
4235
- break;
4236
- }
4237
- case "image":
4238
- case "notebookOutput": {
4239
- const target = v.uri ?? v.name;
4240
- const extra = v.mimeType ? ` (${v.mimeType})` : "";
4241
- parts.push(`- **${v.kind}**: \`${target}\`${extra}`);
4242
- break;
4243
- }
4244
- case "implicit": {
4245
- if (v.isSelection) {
4246
- const target = v.uri ?? v.name;
4247
- parts.push(`- **selection reference**: \`${target}\``);
4248
- }
4249
- else if (v.uri) {
4250
- parts.push(`- **reference**: \`${v.uri}\``);
4251
- }
4252
- break;
4253
- }
4254
- case "generic": {
4255
- // Generic attachments like Terminal Selection
4256
- const title = v.name || "Context";
4257
- const isTerminalSelection = !!v.isTerminalSelection ||
4258
- (typeof v.id === "string" &&
4259
- v.id.startsWith("terminal-selection-"));
4260
- parts.push(`### ${title}`);
4261
- if (isTerminalSelection && v.text && v.text.trim()) {
4262
- // Terminal selection content is stored in terminal.md for grep-ability
4263
- if (terminalLogRelPath) {
4264
- parts.push(`**Content:** saved to \`${terminalLogRelPath}\` (use \`rg\`/\`grep\`)`);
4265
- }
4266
- else {
4267
- // Fallback: inline small tail if no session
4268
- const tail = v.text.length > 2000
4269
- ? `…(truncated)\n${v.text.slice(-2000)}`
4270
- : v.text;
4271
- parts.push("```text");
4272
- parts.push(tail);
4273
- parts.push("```");
4274
- }
4275
- // Parse terminal name from "Terminal Selection (zsh)" format and point to the activity log
4276
- const terminalNameMatch = v.name?.match(/Terminal Selection \((.+)\)/);
4277
- if (terminalNameMatch) {
4278
- const terminalName = terminalNameMatch[1];
4279
- const terminalSlug = (0, terminalLogger_1.terminalNameToSlug)(terminalName);
4280
- parts.push(`**Full terminal history:** \`${paths_1.AGENT_CONSTANTS.AGENTIDE_DIR_NAME}/terminals/${terminalSlug}.md\``);
4281
- }
4282
- else {
4283
- // Point to the terminals directory for all terminal logs
4284
- parts.push(`**All terminal logs:** \`${paths_1.AGENT_CONSTANTS.AGENTIDE_DIR_NAME}/terminals/\``);
4285
- }
4286
- }
4287
- else if (v.text && v.text.trim()) {
4288
- // Non-terminal generic content: inline it
4289
- parts.push("```text");
4290
- parts.push(v.text);
4291
- parts.push("```");
4292
- }
4293
- else if (v.uri) {
4294
- parts.push(`**Resource:** \`${v.uri}\``);
4295
- }
4296
- parts.push("");
4297
- break;
4298
- }
4299
- default: {
4300
- const target = v.uri ?? v.name;
4301
- parts.push(`- **${v.kind}**: ${target}`);
4302
- break;
4303
- }
4304
- }
4305
- }
4306
- }
4307
- const out = parts.join("\n").trim();
4308
- return out ? out + "\n" : "";
4309
- }
4310
- // -----------------------------------------------------------------------------
4311
- // Helpers
4312
- // -----------------------------------------------------------------------------
4313
- function getBundledBasePromptsDir() {
4314
- if (!_extensionContext) {
4315
- return undefined;
4316
- }
4317
- return path.join(_extensionContext.extensionPath, "base-prompts");
4318
- }
4319
- /**
4320
- * Register bundled MCP servers with VS Code's MCP infrastructure.
4321
- * This allows the VS Code native chat (DirectLLM) to discover and use MCP servers.
4322
- */
4323
- async function registerBundledMcpServers(context, outputChannel) {
4324
- const basePromptsDir = getBundledBasePromptsDir();
4325
- if (!basePromptsDir) {
4326
- log(outputChannel, "[AgentIDE] Cannot register MCP servers: base-prompts dir not found");
4327
- return;
4328
- }
4329
- try {
4330
- const servers = await (0, mcp_1.loadBundledMcpServers)(basePromptsDir);
4331
- if (servers.length === 0) {
4332
- log(outputChannel, "[AgentIDE] No bundled MCP servers found");
4333
- return;
4334
- }
4335
- // Register MCP server definition provider with VS Code
4336
- // The ID must match what's declared in package.json contributes.mcpServerDefinitionProviders
4337
- const disposable = vscode.lm.registerMcpServerDefinitionProvider("bundled-mcp-servers", {
4338
- provideMcpServerDefinitions: async () => {
4339
- return servers.map((server) => new vscode.McpStdioServerDefinition(server.label, server.command, server.args, server.env ?? {}));
4340
- },
4341
- });
4342
- context.subscriptions.push(disposable);
4343
- log(outputChannel, `[AgentIDE] Registered ${servers.length} bundled MCP server(s) with VS Code: ${servers.map((s) => s.name).join(", ")}`);
4344
- }
4345
- catch (e) {
4346
- log(outputChannel, `[AgentIDE] Warning: failed to register MCP servers: ${e instanceof Error ? e.message : String(e)}`);
4347
- }
4348
- }
4349
- async function refreshAgentideProject(state) {
4350
- const { outputChannel, syncService, config } = state;
4351
- const { workspaceRoot, additionalDirectories, isHomeFallback } = getWorkspaceRoot(outputChannel);
4352
- if (isHomeFallback) {
4353
- // Don't sync/watch when no workspace is open; fallback is only for running ad-hoc agent tools.
4354
- return;
4355
- }
4356
- try {
4357
- await syncService.ensureAgentideProjectPrepared(workspaceRoot, additionalDirectories, outputChannel);
4358
- await syncService.writeManagedPathsManifest(config.codexHome, config.claudeConfigDir, workspaceRoot, additionalDirectories, outputChannel);
4359
- log(outputChannel, "[AgentIDE] Project sync complete");
4360
- }
4361
- catch (e) {
4362
- log(outputChannel, `[AgentIDE] Warning: failed to refresh project sync: ${e instanceof Error ? e.message : String(e)}`);
4363
- }
4364
- }
4365
- /**
4366
- * Get the configured fallback directory path.
4367
- * Reads from `agentide.fallbackDirectory` setting (directory name relative to home).
4368
- */
4369
- function getFallbackDirectoryPath() {
4370
- const config = vscode.workspace.getConfiguration("agentide");
4371
- const dirName = config.get("fallbackDirectory") || ".agent-hippo";
4372
- return path.join(os.homedir(), dirName);
4373
- }
4374
- function getWorkspaceRoot(outputChannel, explicitWorkspaceRoot, explicitAdditionalDirs) {
4375
- const folders = vscode.workspace.workspaceFolders;
4376
- const allFolderPaths = (0, workspaceFolders_1.getWorkspaceFolderFsPaths)();
4377
- const candidate = explicitWorkspaceRoot?.trim();
4378
- if (candidate) {
4379
- const additionalDirectories = explicitAdditionalDirs ?? allFolderPaths.filter((p) => p !== candidate);
4380
- if (folders && folders.length > 1) {
4381
- log(outputChannel, `[AgentIDE] Multi-root workspace (${folders.length} folders). Primary: ${candidate}, Additional: ${additionalDirectories.length}`);
4382
- }
4383
- else {
4384
- log(outputChannel, `[AgentIDE] Using explicit workspaceRoot=${candidate}`);
4385
- }
4386
- return {
4387
- workspaceRoot: candidate,
4388
- additionalDirectories,
4389
- isHomeFallback: false,
4390
- };
4391
- }
4392
- if (folders && folders.length > 0) {
4393
- const primaryFolder = folders[0].uri.fsPath;
4394
- const additionalDirectories = allFolderPaths.slice(1);
4395
- if (folders.length > 1) {
4396
- log(outputChannel, `[AgentIDE] Multi-root workspace (${folders.length} folders). Primary: ${primaryFolder}, Additional: ${additionalDirectories.length}`);
4397
- }
4398
- else {
4399
- log(outputChannel, `[AgentIDE] Using workspace folder: ${primaryFolder}`);
4400
- }
4401
- return {
4402
- workspaceRoot: primaryFolder,
4403
- additionalDirectories,
4404
- isHomeFallback: false,
4405
- };
4406
- }
4407
- // Use fallback workspace (configurable via agentide.fallbackDirectory, default: ~/myagentide)
4408
- const fallbackDir = getFallbackDirectoryPath();
4409
- log(outputChannel, `[AgentIDE] No workspace open, using fallback directory: ${fallbackDir}`);
4410
- return {
4411
- workspaceRoot: fallbackDir,
4412
- additionalDirectories: [],
4413
- isHomeFallback: true,
4414
- };
4415
- }
4416
- /**
4417
- * Ensure the fallback directory exists with git initialized.
4418
- * Called before using the fallback as a workspace root.
4419
- */
4420
- async function ensureFallbackDirectoryExists(outputChannel) {
4421
- const fallbackDir = getFallbackDirectoryPath();
4422
- try {
4423
- // Check if directory exists
4424
- const exists = await (0, utils_1.pathExists)(fallbackDir);
4425
- if (!exists) {
4426
- // Create the directory
4427
- await fs_1.promises.mkdir(fallbackDir, { recursive: true });
4428
- log(outputChannel, `[AgentIDE] Created fallback directory: ${fallbackDir}`);
4429
- // Initialize git repository
4430
- try {
4431
- const { execFile } = await import("child_process");
4432
- const { promisify } = await import("util");
4433
- const execFileAsync = promisify(execFile);
4434
- await execFileAsync("git", ["init"], { cwd: fallbackDir });
4435
- log(outputChannel, `[AgentIDE] Initialized git in fallback directory`);
4436
- // Create a .gitignore to keep things clean
4437
- const gitignorePath = path.join(fallbackDir, ".gitignore");
4438
- const gitignoreContent = `# ${branding_1.AGENTIDE_BRAND_NAME} fallback workspace
1
+ /*! Copyright (c) 2026 AgentHippo.ai. All rights reserved. Proprietary; see LICENSE. */
2
+ "use strict";var __createBinding=this&&this.__createBinding||(Object.create?(function(i,o,e,p){p===void 0&&(p=e);var b=Object.getOwnPropertyDescriptor(o,e);(!b||("get"in b?!o.__esModule:b.writable||b.configurable))&&(b={enumerable:!0,get:function(){return o[e]}}),Object.defineProperty(i,p,b)}):(function(i,o,e,p){p===void 0&&(p=e),i[p]=o[e]})),__setModuleDefault=this&&this.__setModuleDefault||(Object.create?(function(i,o){Object.defineProperty(i,"default",{enumerable:!0,value:o})}):function(i,o){i.default=o}),__importStar=this&&this.__importStar||(function(){var i=function(o){return i=Object.getOwnPropertyNames||function(e){var p=[];for(var b in e)Object.prototype.hasOwnProperty.call(e,b)&&(p[p.length]=b);return p},i(o)};return function(o){if(o&&o.__esModule)return o;var e={};if(o!=null)for(var p=i(o),b=0;b<p.length;b++)p[b]!=="default"&&__createBinding(e,o,p[b]);return __setModuleDefault(e,o),e}})();Object.defineProperty(exports,"__esModule",{value:!0}),exports.activate=activate,exports.deactivate=deactivate;const vscode=__importStar(require("vscode")),fs_1=require("fs"),path=__importStar(require("path")),os=__importStar(require("os")),types_1=require("./engines/types"),factory_1=require("./engines/factory"),sync_1=require("./sync"),session_1=require("./session"),utils_1=require("./utils"),agentEnvFile_1=require("./utils/agentEnvFile"),index_1=require("./utils/index"),runtime_1=require("./cli/runtime"),mcp_1=require("./mcp"),terminalLogger_1=require("./terminalLogger"),workspaceFolders_1=require("./workspaceFolders"),branding_1=require("./branding"),binary_1=require("./utils/binary"),paths_1=require("./agentpack/paths"),permissions_1=require("./permissions"),vscode_edit_tracker_1=require("./runtime/vscode/vscode-edit-tracker"),vscode_logger_1=require("./runtime/vscode/vscode-logger"),vscode_config_provider_1=require("./runtime/vscode/vscode-config-provider"),permission_handler_1=require("./runtime/interfaces/permission-handler"),customRegistry_1=require("./engines/customRegistry"),handleRemoteChat_js_1=require("./remote/handleRemoteChat.js"),serveClient_js_1=require("./remote/serveClient.js"),remotePackStatusBar_js_1=require("./remote/remotePackStatusBar.js"),provider_js_1=require("./auth/provider.js"),signInFlow_js_1=require("./auth/signInFlow.js"),onboardingPrompt_js_1=require("./auth/onboardingPrompt.js"),githubStoreGate_js_1=require("./auth/githubStoreGate.js"),sessionEvents_1=require("./analytics/sessionEvents"),base_1=require("./engines/base"),BUNDLED_TOOLS_DIR_KEY="agentide.bundledToolsDir",AGENTIDE_SESSIONS_DIR_NAME=`${paths_1.AGENT_CONSTANTS.AGENTIDE_DIR_NAME}/${paths_1.AGENT_CONSTANTS.SESSIONS_DIR}`,TERMINAL_LOG_FILE_NAME="terminal.md",MAX_TERMINAL_LOG_BYTES=2*1024*1024,ATTACHMENTS_DIR_NAME="attachments";let _state,_extensionContext;const _activeRunsByStreamId=new Map,_pendingQuestionsById=new Map,STREAM_QUESTION_TIMEOUT_MS=1e3*60*10;function resolvePendingQuestion(i,o){const e=_pendingQuestionsById.get(i);return e?(clearTimeout(e.timeout),_pendingQuestionsById.delete(i),e.resolver(o),!0):!1}function rejectPendingQuestionsForStream(i,o){for(const[e,p]of _pendingQuestionsById)p.streamId===i&&(clearTimeout(p.timeout),_pendingQuestionsById.delete(e),p.rejecter(new Error(o)))}async function askQuestionFromChatUI(i,o){return await new Promise((e,p)=>{const b=setTimeout(()=>{_pendingQuestionsById.delete(o.questionId),p(new Error("Question timed out waiting for user response"))},STREAM_QUESTION_TIMEOUT_MS);_pendingQuestionsById.set(o.questionId,{streamId:i,question:o,resolver:e,rejecter:p,timeout:b}),Promise.resolve(vscode.commands.executeCommand("agentide.streamCallback",{streamId:i,type:"question",metadata:o})).catch(f=>{clearTimeout(b),_pendingQuestionsById.delete(o.questionId),p(f instanceof Error?f:new Error(String(f)))})})}function normalizeQuestionAnswer(i){const o=i&&typeof i=="object"?i:{},e=Array.isArray(o.selected)?o.selected.filter(b=>typeof b=="string"&&b.trim().length>0):[],p=typeof o.freeText=="string"?o.freeText:(o.freeText===null,null);return{selected:e,freeText:p,declined:o.declined===!0,timedOut:o.timedOut===!0,cancelled:o.cancelled===!0}}function questionPromptToHeader(i){const o=i.split(/\r?\n/,1)[0]?.trim()||"Question";return o.length<=50?o:`${o.slice(0,47)}...`}function streamPayloadToAskQuestionsInput(i){const e={header:questionPromptToHeader(i.prompt),question:i.prompt,multiSelect:i.multiSelect,allowFreeformInput:i.allowFreeText};return i.options?.length&&(e.options=i.options.map(p=>({label:p.label,description:p.description,recommended:p.recommended}))),{questions:[e]}}async function askQuestionViaWorkbenchTool(i,o,e,p){const b=new vscode.CancellationTokenSource;p.addEventListener("abort",()=>b.cancel(),{once:!0});try{const f=streamPayloadToAskQuestionsInput(e),n=(await vscode.lm.invokeTool("vscode_askQuestions",{input:f,toolInvocationToken:{sessionResource:vscode.Uri.parse(i)}},b.token))?.content?.find(u=>typeof u.value=="string")?.value;if(!n)return{selected:[],freeText:null,declined:!0};const s=JSON.parse(n)?.answers??{},c=Object.keys(s)[0],r=c?s[c]:void 0;return r?{selected:r.selected??[],freeText:r.freeText??null,declined:r.skipped===!0}:{selected:[],freeText:null,declined:!0}}catch(f){const N=f instanceof Error&&(f.name==="Canceled"||f.message?.includes("cancel"));return{selected:[],freeText:null,declined:!0,cancelled:N}}finally{b.dispose()}}const SESSION_CLEANUP_INTERVAL_MS=1e3*60*5;function log(i,o){i.appendLine((0,branding_1.brandify)(o))}function logConsole(i){console.log((0,branding_1.brandify)(i))}function showInfo(i){return vscode.window.showInformationMessage((0,branding_1.brandify)(i))}function showWarning(i){return vscode.window.showWarningMessage((0,branding_1.brandify)(i))}function showError(i){return vscode.window.showErrorMessage((0,branding_1.brandify)(i))}async function activate(i){const o=vscode.window.createOutputChannel(branding_1.AGENTIDE_EXTENSION_NAME);log(o,`${branding_1.AGENTIDE_BRAND_NAME} extension activating...`),logConsole(`${branding_1.AGENTIDE_BRAND_NAME} extension activating...`);try{const m=await(0,agentEnvFile_1.mergeAgentHomeEnvIntoProcessEnv)();m.applied.length>0&&log(o,`[AgentIDE] Loaded ${m.applied.length} env var(s) from ${m.envFilePath} (shell env wins on conflict)`)}catch(m){const h=m instanceof Error?m.message:String(m);log(o,`[AgentIDE] Warning: failed to load ~/.agent-hippo/.env: ${h}`)}_extensionContext=i;const e=(0,utils_1.getAnalyticsScriptsDir)(i.extensionPath);process.env.AGENTIDE_ANALYTICS_SCRIPTS_DIR=e,log(o,`[AgentIDE] Analytics scripts dir: ${e}`),(0,session_1.initSessionStore)(i);const p=new vscode_logger_1.VSCodeLogger(o,"[Maintenance]"),b=setInterval(()=>{if((0,session_1.runSessionMaintenance)(),_state)for(const m of Object.values(_state.engines))m.onMaintenance(p)},SESSION_CLEANUP_INTERVAL_MS);i.subscriptions.push(new vscode.Disposable(()=>clearInterval(b)));const f=i.storageUri??i.globalStorageUri,N=i.storageUri?"per-workspace":"global",t={storagePath:f.fsPath},n=process.env.AGENTHIPPO_LITELLM_API_KEY?.trim()||process.env.LITELLM_MASTER_KEY?.trim();n&&(t.litellmApiKey=n,log(o,"[AgentIDE] Using local LiteLLM key from ~/.agent-hippo/.env"));for(const m of Object.values(types_1.AGENT_ENGINES)){const h=path.join(f.fsPath,m.id);try{await fs_1.promises.mkdir(h,{recursive:!0}),log(o,`[AgentIDE] ${m.displayName} dir: ${h} (${N})`),m.configEnvVar==="CODEX_HOME"?t.codexHome=h:m.configEnvVar==="CLAUDE_CONFIG_DIR"&&(t.claudeConfigDir=h)}catch(I){log(o,`[AgentIDE] Warning: failed to create ${m.id} dir: ${I instanceof Error?I.message:String(I)}`)}}const a=new sync_1.SyncService(()=>getBundledBasePromptsDir()),s=(0,factory_1.createEngines)({config:t,syncService:a,getBundledBasePromptsDir:()=>getBundledBasePromptsDir()});_state={outputChannel:o,engines:s,syncService:a,config:t};try{const m=vscode.workspace.getConfiguration("chat"),h=m.inspect("useAgentSkills");h&&!h.globalValue&&!h.workspaceValue&&!h.workspaceFolderValue&&(await m.update("useAgentSkills",!0,vscode.ConfigurationTarget.Global),log(o,"[AgentIDE] Enabled Agent Skills by default"))}catch(m){log(o,`[AgentIDE] Warning: failed to enable Agent Skills setting: ${m instanceof Error?m.message:String(m)}`)}await registerBundledMcpServers(i,o),(0,provider_js_1.registerAgentHippoAuth)(i),(0,provider_js_1.refreshBootstrapIfSignedIn)(i),i.subscriptions.push((0,provider_js_1.startAgentHippoTokenRefreshTimer)(i)),(0,onboardingPrompt_js_1.scheduleSignInOnboardingPrompt)(i),registerCommands(i,_state);const c=new remotePackStatusBar_js_1.RemotePackStatusBar(a,()=>getWorkspaceRoot(o).workspaceRoot,o);_state.remotePackStatusBar=c,i.subscriptions.push(c),c.refresh();const{GatewayLifecycleManager:r}=await import("./gateway/lifecycle.js");_state.gatewayLifecycle=new r(o,i),i.subscriptions.push({dispose:()=>_state?.gatewayLifecycle?.dispose()});const{GatewayService:u}=await import("./gateway/service.js");_state.gatewayService=new u(i,o),i.subscriptions.push({dispose:()=>_state?.gatewayService?.dispose()}),_state.gatewayLifecycle.setBridgeRef(_state.gatewayService),_state.gatewayLifecycle.onStatusChange(async m=>{m==="running"&&vscode.workspace.getConfiguration("agentide.anywhere").get("autoConnect",!1)&&_state?.gatewayLifecycle&&_state.gatewayLifecycle.connectBridge()});const{AnalyticsService:d}=await import("./analytics/service.js");_state.analyticsService=new d(i,o),i.subscriptions.push({dispose:()=>_state?.analyticsService?.dispose()});const{AnalyticsDashboardProvider:l,ArtifactManagerImpl:g,QueryRunnerImpl:D,ensureBundledFleetAdapters:v}=await import("./analytics/dashboard/index.js"),y=new g(o),S=new g(o),k=new D(o);v(k);const E=_state.analyticsService;_state.analyticsDashboard=new l(i,k,y,o,()=>E?.getIndexingService());const w=new l(i,k,S,o,()=>E?.getIndexingService(),"team");_state.analyticsTeamDashboard=w,i.subscriptions.push(vscode.window.registerWebviewViewProvider(l.viewType,_state.analyticsDashboard,{webviewOptions:{retainContextWhenHidden:!0}}),vscode.window.registerWebviewViewProvider("agentide.teamView",w,{webviewOptions:{retainContextWhenHidden:!0}}),_state.analyticsDashboard,w,{dispose:()=>y.dispose()},{dispose:()=>S.dispose()},{dispose:()=>k.dispose()}),i.subscriptions.push(vscode.commands.registerCommand("agentide.analytics.openDashboard",()=>{vscode.commands.executeCommand("agentide.analyticsView.focus")}),vscode.commands.registerCommand("agentide.fleet.open",async()=>{const m=_state?.analyticsTeamDashboard;m&&await m.openWithView("fleet"),await vscode.commands.executeCommand("agentide.teamView.focus")}),vscode.commands.registerCommand("agentide.analytics.clearArtifacts",async()=>{const m=await y.cleanup(0);await i.workspaceState.update("analytics.generatedDefaultDashboard",!1),vscode.window.showInformationMessage(`Cleared ${m.deletedCount} Spotlight artifacts (${(m.freedBytes/1024).toFixed(1)} KB)`)}),vscode.commands.registerCommand("agentide.analytics.regenerateDefaults",async()=>{_state?.analyticsDashboard&&(k.invalidateCache(),await _state.analyticsDashboard.runDefaultChartScript())}),vscode.commands.registerCommand("agentide.persistChatVote",async m=>{!m?.sessionId||!m?.requestId||await _sessionEventWriter.append(m.sessionId,m.requestId,"vote",{direction:m.direction,reason:m.reason,agentId:m.agentId,command:m.command})})),(0,terminalLogger_1.activateTerminalLogger)(i);const A=setTimeout(()=>{(0,terminalLogger_1.cleanupOldSessionLogs)(o)},5e3);i.subscriptions.push(new vscode.Disposable(()=>clearTimeout(A)));const C=setTimeout(async()=>{try{const{initializeStoreIndex:m}=await import("./store/oramaIndex.js");await m(o)}catch(m){log(o,`[AgentIDE] Store index init: ${m instanceof Error?m.message:String(m)}`)}},3e3);i.subscriptions.push(new vscode.Disposable(()=>clearTimeout(C))),vscode.workspace.workspaceFolders?.length&&refreshAgentideProject(_state).then(async()=>{a.ensureAgentideWatchers(o);try{const{workspaceRoot:m}=getWorkspaceRoot(o),{AgentPackManager:h}=await import("./agentpack/index.js"),I=new h(a,()=>m,()=>t.storagePath,o),{registered:P}=await I.repairUnregisteredAgents();P.length>0&&log(o,`[AgentIDE] Auto-repaired ${P.length} unregistered pack(s): ${P.join(", ")}`)}catch(m){log(o,`[AgentIDE] Pack repair check failed: ${m instanceof Error?m.message:String(m)}`)}_state?.remotePackStatusBar?.refresh()}),i.subscriptions.push(vscode.workspace.onDidChangeWorkspaceFolders(()=>{a.ensureAgentideWatchers(o),_state&&(refreshAgentideProject(_state),_state.remotePackStatusBar?.refresh())})),i.subscriptions.push(new vscode.Disposable(()=>{a.disposeAllWatchers()})),log(o,"[AgentIDE] Extension activation complete")}function deactivate(){if(_state)for(const i of Object.values(_state.engines))try{i.dispose()}catch{}_state=void 0}function escapeRegExp(i){return i.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function quoteEnvValue(i){return/^[A-Za-z0-9_./:@-]+$/.test(i)?i:`'${i.replace(/'/g,"'\\''")}'`}function upsertEnvVar(i,o,e){const p=i.split(/\r?\n/),b=new RegExp(`^\\s*(?:export\\s+)?${escapeRegExp(o)}\\s*=`);let f=!1;for(let N=0;N<p.length;N++){const t=p[N],n=t.trim();!n||n.startsWith("#")||b.test(t)&&(p[N]=`${o}=${quoteEnvValue(e)}`,f=!0)}return f||(p.length>0&&p[p.length-1].trim()!==""&&p.push(""),p.push(`${o}=${quoteEnvValue(e)}`)),p.join(`
3
+ `).replace(/\s*$/,`
4
+ `)}function hasEnvVar(i,o){const e=new RegExp(`^\\s*(?:export\\s+)?${escapeRegExp(o)}\\s*=`);return i.split(/\r?\n/).some(p=>{const b=p.trim();return!b||b.startsWith("#")?!1:e.test(p)})}function registerCommands(i,o){const{outputChannel:e,syncService:p,config:b}=o;i.subscriptions.push(vscode.commands.registerCommand("agentide.setParticipantApiKey",t=>{log(e,`[AgentIDE] Setting API key for ${t.provider}${t.baseUrl?` with baseUrl: ${t.baseUrl}`:""}`),t.provider==="litellm"&&(b.litellmApiKey=t.apiKey,b.litellmBaseUrl=t.baseUrl)})),i.subscriptions.push(vscode.commands.registerCommand("agentide.binary.findOnPath",async t=>{const n=t?.name?.trim();if(!n)throw new Error("Binary name is required");return(0,binary_1.findBinaryCached)(n,(0,binary_1.getCommonBinaryPaths)(n))})),i.subscriptions.push(vscode.commands.registerCommand("agentide.openaiCodex.loginOAuth",async()=>{log(e,"[AgentIDE] Starting native OpenAI Codex OAuth login");const{loginOpenAICodex:t}=await import("@mariozechner/pi-ai"),n=await t({onAuth:async({url:r})=>{log(e,`[AgentIDE] OpenAI Codex OAuth URL: ${r}`);try{await vscode.env.openExternal(vscode.Uri.parse(r)),showInfo("Complete ChatGPT sign-in in your browser. Return here if prompted for a redirect URL.")}catch(u){log(e,`[AgentIDE] Failed to auto-open OAuth URL: ${String(u)}`),showWarning(`Open this URL in your browser: ${r}`)}},onPrompt:async r=>{const u=await vscode.window.showInputBox({title:"OpenAI Codex OAuth",prompt:r.message,placeHolder:r.placeholder,ignoreFocusOut:!0,validateInput:d=>d.trim().length>0?void 0:"Required"});if(!u||u.trim().length===0)throw new Error("OpenAI Codex OAuth cancelled");return u.trim()},onProgress:r=>{log(e,`[AgentIDE] OpenAI Codex OAuth: ${r}`)}}),a=n?.access?.trim();if(!a)throw new Error("OpenAI Codex OAuth completed without an access token");const s={type:"oauth",...n},c={apiKey:a,oauthCredential:s,expiresAt:typeof n.expires=="number"?n.expires:void 0};return log(e,"[AgentIDE] OpenAI Codex OAuth login complete"),c})),i.subscriptions.push(vscode.commands.registerCommand("agentide.openaiCodex.getValidApiKey",async t=>{const n=t?.oauthCredential;if(!n||typeof n!="object")throw new Error("Missing openai-codex OAuth credential payload.");const{getOAuthApiKey:a}=await import("@mariozechner/pi-ai"),c={"openai-codex":n.type==="oauth"?n:{type:"oauth",...n}},r=await a("openai-codex",c);if(!r?.apiKey)throw new Error("OpenAI Codex OAuth credential is invalid or expired. Please sign in again.");return{apiKey:String(r.apiKey),oauthCredential:{type:"oauth",...r.newCredentials},expiresAt:typeof r.newCredentials?.expires=="number"?r.newCredentials.expires:void 0}})),i.subscriptions.push(vscode.commands.registerCommand("agentide.litellm.setUpstreamApiKey",async t=>{const n=t?.envVar?.trim()??"",a=t?.apiKey?.trim()??"";if(!n||!/^[A-Z][A-Z0-9_]*$/.test(n))throw new Error(`Invalid env var name: ${n}`);if(!a)throw new Error(`API key value cannot be empty for ${n}`);const s=(0,index_1.getAgentideHome)(),c=path.join(s,".env");await fs_1.promises.mkdir(s,{recursive:!0,mode:448});let r="";try{r=await fs_1.promises.readFile(c,"utf8")}catch{}const u=upsertEnvVar(r,n,a);await fs_1.promises.writeFile(c,u,"utf8");try{await fs_1.promises.chmod(c,384)}catch{}return log(e,`[AgentIDE] Updated LiteLLM upstream key in ${c} (${n})`),{envFilePath:c,envVar:n}})),i.subscriptions.push(vscode.commands.registerCommand("agentide.litellm.getUpstreamApiKeyStatus",async t=>{const n=t?.envVar?.trim()??"";if(!n||!/^[A-Z][A-Z0-9_]*$/.test(n))throw new Error(`Invalid env var name: ${n}`);const a=(0,index_1.getAgentideHome)(),s=path.join(a,".env");let c="";try{c=await fs_1.promises.readFile(s,"utf8")}catch{}return{envFilePath:s,envVar:n,exists:hasEnvVar(c,n)}})),i.subscriptions.push(vscode.commands.registerCommand("agentide.clearManagedResources",async()=>{if(await vscode.window.showWarningMessage((0,branding_1.brandify)("Clear all AgentIDE managed resources?"),{modal:!0,detail:`This will remove derived folders and generated files. User-managed files in \`${paths_1.AGENT_CONSTANTS.AGENTIDE_DIR_NAME}/\` will NOT be deleted.`},"Clear Resources","Cancel")!=="Clear Resources")return;const{workspaceRoot:n,additionalDirectories:a,isHomeFallback:s}=getWorkspaceRoot(e);s&&await ensureFallbackDirectoryExists(e);const{cleared:c,skipped:r,errors:u}=await p.clearManagedResources(b.codexHome,b.claudeConfigDir,n,a,e),d=[`Cleared: ${c.length} resources`,r.length>0?`Skipped: ${r.length} (user files)`:"",u.length>0?`Errors: ${u.length}`:""].filter(Boolean).join(" | ");u.length>0?(showError(`AgentIDE: ${d}`),log(e,`[AgentIDE] Errors: ${u.join(", ")}`)):showInfo(`AgentIDE: ${d}`),log(e,`[AgentIDE] Clear complete: ${d}`)})),i.subscriptions.push(vscode.commands.registerCommand("agentide.skills.syncRemote",async()=>{const{workspaceRoot:t,additionalDirectories:n,isHomeFallback:a}=getWorkspaceRoot(e);a&&await ensureFallbackDirectoryExists(e),await p.ensureAgentideProjectPrepared(t,n,e),await p.syncRemoteSkillsIfEnabled(t,e,{force:!0}),await p.flushAgentideRootUpdate(t,e,{allowDuringActiveTurn:!0,force:!1}),showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: Remote skills sync complete (see ${branding_1.AGENTIDE_BRAND_NAME} output for details).`)})),i.subscriptions.push(vscode.commands.registerCommand("agentide.showManagedResources",async()=>{const{workspaceRoot:t,additionalDirectories:n,isHomeFallback:a}=getWorkspaceRoot(e);a&&await ensureFallbackDirectoryExists(e),await p.writeManagedPathsManifest(b.codexHome,b.claudeConfigDir,t,n,e);const s=path.join((0,paths_1.getAgentideDir)(t),"paths.md");if(await(0,utils_1.pathExists)(s)){const c=await vscode.workspace.openTextDocument(s);await vscode.window.showTextDocument(c)}})),i.subscriptions.push(vscode.commands.registerCommand("agentide.cleanupSessionLogs",async()=>{const t=await(0,terminalLogger_1.cleanupOldSessionLogs)(e);t.cleaned>0?showInfo(`AgentIDE: Cleaned up ${t.cleaned} old session(s)`):t.errors.length>0?showWarning(`AgentIDE: Cleanup completed with ${t.errors.length} error(s)`):showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: No old sessions to clean up`)})),i.subscriptions.push(vscode.commands.registerCommand("agentide.deleteSessionLogs",async t=>{const n=t?.sessionId;if(!n)return{deleted:!1,error:"sessionId is required"};const a=await(0,terminalLogger_1.deleteSessionLogs)(n);return a.deleted?(log(e,`[AgentIDE] Deleted session logs: ${n}`),(0,terminalLogger_1.cleanupOldSessionLogs)(e)):a.error&&log(e,`[AgentIDE] Failed to delete session logs: ${a.error}`),a})),i.subscriptions.push(vscode.commands.registerCommand("agentide.cli.status",async()=>{const t=vscode.workspace.getConfiguration("agentide").get("cli.path",""),n=await(0,runtime_1.getCliHealth)({configuredPath:t,extensionPath:i.extensionPath}),s=(0,runtime_1.getBundledToolsHealth)({extensionPath:i.extensionPath,binaryDirHint:n.path?path.dirname(n.path):void 0}).tools.filter(c=>c.available).map(c=>c.name);if(n.installed){const c=n.source==="setting"?"configured path":n.source==="bundled"?"bundled binary":"system PATH",r=s.length>0?`; tools: ${s.join(", ")}`:"; tools: none";showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: CLI available (${c})${n.version?` ${n.version}`:""}${r}`)}else showWarning(`${branding_1.AGENTIDE_BRAND_NAME}: CLI not found. Run '${branding_1.AGENTIDE_BRAND_NAME}: Setup AgentHippo CLI'.`);return n})),i.subscriptions.push(vscode.commands.registerCommand("agentide.cli.isInstalled",async()=>{const t=vscode.workspace.getConfiguration("agentide").get("cli.path","");return(await(0,runtime_1.getCliHealth)({configuredPath:t,extensionPath:i.extensionPath})).installed})),i.subscriptions.push(vscode.commands.registerCommand("agentide.installBundledTools",async()=>{const t=(0,runtime_1.getBundledToolsHealth)({extensionPath:i.extensionPath});if(!t.platformKey){showError(`${branding_1.AGENTIDE_BRAND_NAME}: Unsupported platform ${process.platform}-${process.arch}. Cannot install bundled tools.`);return}const n=i.globalStorageUri;if(!n){showError(`${branding_1.AGENTIDE_BRAND_NAME}: No global storage path. Cannot install bundled tools.`);return}const a=path.join(n.fsPath,"tools"),c=[path.join(i.extensionPath,"out","scripts","vendor-tools.mjs"),path.join(i.extensionPath,"scripts","vendor-tools.mjs")].find(r=>{try{return require("fs").statSync(r).isFile()}catch{return!1}});if(!c){showError(`${branding_1.AGENTIDE_BRAND_NAME}: vendor-tools script not found. Run from extension source or rebuild.`);return}log(e,`[AgentIDE] Installing bundled tools (rg, sg, tree-sitter) into ${a} ...`);try{const{spawn:r}=await import("child_process");await new Promise((d,l)=>{const g=r(process.execPath,[c,"--out-dir",a,"--clean"],{stdio:["ignore","pipe","pipe"],env:{...process.env}});let D="";g.stdout?.on("data",v=>log(e,v.toString())),g.stderr?.on("data",v=>{D+=v.toString(),log(e,v.toString())}),g.on("error",l),g.on("close",v=>v===0?d():l(new Error(`Exit ${v}: ${D}`)))});const u=path.join(a,t.platformKey);await i.globalState.update(BUNDLED_TOOLS_DIR_KEY,u),showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: Bundled tools installed to ${u}. They will be used by the agent.`)}catch(r){const u=r instanceof Error?r.message:String(r);log(e,`[AgentIDE] Install bundled tools failed: ${u}`),showError(`${branding_1.AGENTIDE_BRAND_NAME}: Failed to install bundled tools. Check Output > Agent Hippo. ${u}`)}})),i.subscriptions.push(vscode.commands.registerCommand("agentide.setupCli",async()=>{log(e,"[AgentIDE] Starting CLI setup...");const t=vscode.workspace.getConfiguration("agentide.cli"),n=t.get("path",""),a=t.get("installSource","").trim();if(a&&/[;`|$&\n\r"']/.test(a))return showError(`${branding_1.AGENTIDE_BRAND_NAME}: Invalid CLI install source. Remove shell control characters from '${(0,branding_1.describeSettingKey)("agentide.cli.installSource")}'.`),{success:!1,error:"Invalid install source"};const s=await(0,runtime_1.getCliHealth)({configuredPath:n,extensionPath:i.extensionPath,forceRefresh:!0});if(s.installed&&s.path)return await vscode.workspace.getConfiguration("agentide").update("cli.path",s.path,vscode.ConfigurationTarget.Global),showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: CLI is ready at ${s.path}`),{success:!0,path:s.path};const r=process.platform==="win32"?"setup-cli.ps1":"setup-cli.sh",d=[path.join(i.extensionPath,"out","scripts",r),path.join(i.extensionPath,"scripts",r)].find(D=>{try{return require("fs").accessSync(D),!0}catch{return!1}});if(!d)return showError(`${branding_1.AGENTIDE_BRAND_NAME}: CLI setup script not found. Build CLI via extensions/agentide/scripts/build-cli.sh and set ${(0,branding_1.describeSettingKey)("agentide.cli.path")}.`),{success:!1,error:"Script not found"};const l=await f(d,e,a);if(!l.success)return l;const g=await(0,runtime_1.getCliHealth)({configuredPath:n,extensionPath:i.extensionPath,forceRefresh:!0});return g.installed&&g.path?(await vscode.workspace.getConfiguration("agentide").update("cli.path",g.path,vscode.ConfigurationTarget.Global),showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: CLI configured at ${g.path}`),{success:!0,path:g.path}):(showWarning(`${branding_1.AGENTIDE_BRAND_NAME}: Setup launched. Re-run '${branding_1.AGENTIDE_BRAND_NAME}: CLI Status' after terminal setup completes.`),{success:!0,pending:!0})}));async function f(t,n,a){const s=process.platform==="win32",c=/^https?:\/\//i.test(a),r=a?s?`-Source "${a}"`:`--source "${a}"`:"",u=s?vscode.window.createTerminal({name:"AgentHippo CLI Setup",cwd:path.dirname(t),shellPath:"powershell.exe",shellArgs:["-NoProfile","-NoExit","-ExecutionPolicy","Bypass","-Command",`& "${t}" ${r} -Yes; Write-Host ""; Write-Host "You can close this window."`]}):vscode.window.createTerminal({name:"AgentHippo CLI Setup",cwd:path.dirname(t),shellPath:"/bin/bash",shellArgs:["-c",`"${t}" ${r} --yes; echo ''; echo 'Press any key to close...'; read -n 1`]});return a&&log(n,`[AgentIDE] CLI install source configured (${c?"url":"package/path"}): ${a}`),u.show(),showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: CLI setup started. Check the terminal for progress.`),log(n,"[AgentIDE] CLI setup terminal opened"),{success:!0}}i.subscriptions.push(vscode.commands.registerCommand("agentide.setupAnalytics",async()=>{log(e,"[AgentIDE] Starting Spotlight install/repair...");const t=process.platform==="win32",n=t?"setup-analytics.ps1":"setup-analytics.sh",a=i.extensionPath,c=[path.join(a,"out","scripts","analytics",n),path.join(a,"scripts","analytics",n)].find(r=>{try{return require("fs").accessSync(r),!0}catch{return!1}});return c?t&&_state?.analyticsService?_state.analyticsService.setupWindowsSpotlight({reinstall:!1}):N(c,e):(showError(`Spotlight install script not found. Please run 'scripts/analytics/${n}' manually from the AgentIDE repository.`),{success:!1,error:"Script not found"})}));async function N(t,n){const a=process.platform==="win32",s=path.join(os.homedir(),branding_1.AGENTIDE_DIR_NAME);return(a?vscode.window.createTerminal({name:"Spotlight Install",cwd:path.dirname(t),env:{AGENT_HOME_DIR:s},shellPath:"powershell.exe",shellArgs:["-NoProfile","-NoExit","-ExecutionPolicy","Bypass","-Command",`& "${t}" -Yes; Write-Host ""; Write-Host "You can close this window."`]}):vscode.window.createTerminal({name:"Spotlight Install",cwd:path.dirname(t),env:{AGENT_HOME_DIR:s},shellPath:"/bin/bash",shellArgs:["-c",`"${t}" --yes; echo ''; echo 'Press any key to close...'; read -n 1`]})).show(),showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: Spotlight install started. Check the terminal for progress.`),log(n,"[AgentIDE] Spotlight install terminal opened"),{success:!0}}i.subscriptions.push(vscode.commands.registerCommand("agentide.pack.install",async()=>{const{workspaceRoot:t,isHomeFallback:n}=getWorkspaceRoot(e);n&&await ensureFallbackDirectoryExists(e);const a=await vscode.window.showOpenDialog({canSelectFolders:!0,canSelectFiles:!1,canSelectMany:!1,openLabel:"Select Agent Pack Folder",title:"Install Agent Pack"});if(!a||a.length===0)return;const s=a[0].fsPath,{AgentPackManager:c}=await import("./agentpack/index.js"),r=new c(p,()=>t,()=>b.storagePath,e);try{const u=await r.installFromLocal(s);showInfo(`AgentIDE: Installed pack "${u.id}" v${u.version}`)}catch(u){const d=u instanceof Error?u.message:String(u);log(e,`[AgentIDE] Pack install error: ${d}`),showError(`AgentIDE: Failed to install pack - ${d}`)}})),i.subscriptions.push(vscode.commands.registerCommand("agentide.pack.list",async()=>{const{workspaceRoot:t}=getWorkspaceRoot(e),{AgentPackManager:n}=await import("./agentpack/index.js"),s=await new n(p,()=>t,()=>b.storagePath,e).listInstalled();if(s.length===0){showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: No agent packs installed`);return}const c=s.map(u=>({label:u.id,description:`v${u.version} (${u.preferredEngine})`,detail:`Status: ${u.status} | Installed: ${new Date(u.installedAt).toLocaleDateString()}`})),r=await vscode.window.showQuickPick(c,{placeHolder:"Select a pack to view details",title:"Installed Agent Packs"});r&&(log(e,`[AgentIDE] Pack selected: ${r.label}`),e.show())})),i.subscriptions.push(vscode.commands.registerCommand("agentide.pack.getInstalled",async()=>{const{workspaceRoot:t}=getWorkspaceRoot(e),{AgentPackManager:n}=await import("./agentpack/index.js"),a=new n(p,()=>t,()=>b.storagePath,e);try{return await a.listInstalled()}catch(s){const c=s instanceof Error?s.message:String(s);return log(e,`[AgentIDE] Pack list error: ${c}`),[]}})),i.subscriptions.push(vscode.commands.registerCommand("agentide.customEngine.list",t=>{const n=getConfiguredAdditionalEngineDir(),a=t?.workspaceRoot?.trim(),s=(vscode.workspace.workspaceFolders??[]).map(d=>d.uri.fsPath).filter(d=>!!d?.trim()),c=process.cwd?.(),r=Array.from(new Set([a,...s,c].map(d=>d?.trim()).filter(d=>!!d))),u=new Map;for(const d of r)try{const l=(0,customRegistry_1.discoverCustomEngineManifests)(d,n);for(const g of l)u.has(g.id)||u.set(g.id,{id:g.id,displayName:g.displayName||g.id,description:g.description,defaultModel:g.model?.defaultModel})}catch(l){const g=l instanceof Error?l.message:String(l);log(e,`[AgentIDE] Custom engine list warning for root ${d}: ${g}`)}if(u.size===0)try{const d=(0,customRegistry_1.discoverCustomEngineManifests)(void 0,n);for(const l of d)u.set(l.id,{id:l.id,displayName:l.displayName||l.id,description:l.description,defaultModel:l.model?.defaultModel})}catch(d){const l=d instanceof Error?d.message:String(d);log(e,`[AgentIDE] Custom engine list error: ${l}`)}return log(e,`[AgentIDE] Custom engine list: ${u.size} discovered (${Array.from(u.keys()).join(", ")||"none"}) from roots: ${r.join("; ")||"(home only)"}`),Array.from(u.values())})),i.subscriptions.push(vscode.commands.registerCommand("agentide.engine.uninstall",async t=>{const{listInstalledCustomEngines:n,uninstallCustomEngine:a}=await import("./engines/install.js");let s=t?.id?.trim(),c=s;if(!s){const d=await n();if(d.length===0){showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: No custom engines are installed`);return}const l=await vscode.window.showQuickPick(d.map(g=>({label:g.displayName,description:g.id,detail:g.installDir,engine:g})),{placeHolder:"Select a custom engine to uninstall",title:"Uninstall Custom Engine"});if(!l)return;s=l.engine.id,c=l.engine.displayName}if(!s||t?.skipConfirmation!==!0&&await vscode.window.showWarningMessage(`Uninstall custom engine "${c||s}"?`,{modal:!0},"Uninstall","Cancel")!=="Uninstall")return;const r=await a(s,{logger:e});if(!r.removed){showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: Custom engine "${r.id}" is not installed`);return}clearCustomEngineRuntimeCache(o,r.id);const{invalidateLocalIndex:u}=await import("./store/oramaIndex.js");u(),await refreshCustomEnginePicker(e),showInfo(`Uninstalled engine "${r.displayName||r.id}"`)})),i.subscriptions.push(vscode.commands.registerCommand("agentide.engine.publish",async()=>{const{workspaceRoot:t}=getWorkspaceRoot(e),{collectEngineFiles:n,discoverPublishableEngines:a,isValidPublishVersion:s,validateEngineForPublish:c}=await import("./engines/publish.js"),{publishToStore:r,STORE_CONFIG:u,canPublishDirectlyToStore:d}=await import("./store/index.js"),l=await a(t);if(l.length===0){showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: No custom engines found. Add engine.manifest.json under .agent-hippo/engines/<id>/`);return}const g=await vscode.window.showQuickPick(l.map(D=>({label:D.displayName,description:D.id,detail:`${D.sourceLabel}: ${D.sourceDir}`,engine:D})),{placeHolder:"Select a custom engine to publish",title:`Publish to ${u.owner}/${u.repo}`});if(g)try{const D=await c(g.engine.sourceDir,g.engine.id);if(!D.valid){showError(`${branding_1.AGENTIDE_BRAND_NAME}: Cannot publish - ${D.errors.join(", ")}`);return}if(D.warnings.length>0&&await vscode.window.showWarningMessage(`Warnings: ${D.warnings.join(", ")}`,"Publish Anyway","Cancel")!=="Publish Anyway")return;const v=await vscode.window.showInputBox({prompt:"Publish version (semver)",value:D.metadata?.suggestedVersion||"1.0.0",placeHolder:"e.g., 1.0.0",validateInput:m=>m&&s(m.replace(/^v/,""))?null:"Use semver format (e.g., 1.0.0)"});if(!v)return;const y=v.replace(/^v/,""),S=await vscode.window.showInputBox({prompt:"What changed in this version? (optional)",placeHolder:"Initial release, bug fixes..."}),k=await n(g.engine.sourceDir),E=await d();if(await vscode.window.showWarningMessage(E?`Publish "${g.engine.id}" v${y} to ${u.owner}/${u.repo}?
5
+
6
+ This will open a pull request on the store repository.`:`Submit "${g.engine.id}" v${y} to ${u.owner}/${u.repo}?
7
+
8
+ This will create a pull request from your fork.`,{modal:!0},"Submit PR")!=="Submit PR")return;const A=await vscode.window.withProgress({location:vscode.ProgressLocation.Window,title:`Publishing engine ${g.engine.id} v${y}`,cancellable:!1},async m=>{m.report({message:E?`Publishing to ${u.owner}/${u.repo}...`:"Preparing fork..."});const h=await r({type:"engine",slug:g.engine.id,version:y,files:k,changelog:S},e);return m.report({message:"Creating PR..."}),h});await vscode.window.showInformationMessage(`Published engine "${g.engine.id}" v${y}! PR created.`,"View PR")==="View PR"&&vscode.env.openExternal(vscode.Uri.parse(A.prUrl))}catch(D){const v=D instanceof Error?D.message:String(D);log(e,`[AgentIDE] Engine publish error: ${v}`),showError(`${branding_1.AGENTIDE_BRAND_NAME}: ${v}`)}})),i.subscriptions.push(vscode.commands.registerCommand("agentide.pack.uninstall",async()=>{const{workspaceRoot:t}=getWorkspaceRoot(e),{AgentPackManager:n,isDefaultAgent:a}=await import("./agentpack/index.js"),s=new n(p,()=>t,()=>b.storagePath,e),r=(await s.listInstalled()).filter(v=>!a(v.id));if(r.length===0){showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: No agent packs available to uninstall`);return}const u=r.map(v=>({label:v.id,description:`v${v.version}${o.activePackId===v.id?" (active)":""}`})),d=await vscode.window.showQuickPick(u,{placeHolder:"Select a pack to uninstall",title:"Uninstall Agent Pack"});if(!d)return;const l=d.label,g=o.activePackId===l;if(await vscode.window.showWarningMessage(`Uninstall agent pack "${l}"?${g?" This will switch to the default agent.":""}`,{modal:!0},"Uninstall","Cancel")==="Uninstall")try{if(await s.uninstall(l),g){const v=await p.switchToPack(t,void 0,e,{importDerivedSkills:!0});o.activePackId=v,p.setActivePackId(t,v),log(e,"[AgentIDE] Switched to default agent after uninstalling active pack");try{await vscode.commands.executeCommand("agentide.applyPackPreferences",{packId:"default",silent:!0})}catch{}}showInfo(`AgentIDE: Uninstalled pack "${l}"${g?" - switched to default agent":""}`)}catch(v){const y=v instanceof Error?v.message:String(v);log(e,`[AgentIDE] Pack uninstall error: ${y}`),showError(`AgentIDE: Failed to uninstall pack - ${y}`)}})),i.subscriptions.push(vscode.commands.registerCommand("agentide.pack.setActive",async t=>{if(!t?.packId)throw new Error("packId is required. Use workbench.action.chat.openAgentPackPicker for interactive selection.");const{workspaceRoot:n}=getWorkspaceRoot(e),a=t.packId==="default"?void 0:t.packId,s=await p.switchToPack(n,a,e,{importDerivedSkills:!0});return o.activePackId=s,p.setActivePackId(n,s),log(e,`[AgentIDE] Active pack switched to: ${s??"default"}`),await o.remotePackStatusBar?.refresh({notifyOnActivate:!0}),{activePackId:o.activePackId??"default"}})),i.subscriptions.push(vscode.commands.registerCommand("agentide.pack.getActive",()=>({activePackId:o.activePackId??"default"}))),i.subscriptions.push(vscode.commands.registerCommand("agentide.pack.getRemoteServeUrl",async t=>{const{workspaceRoot:n}=getWorkspaceRoot(e),a=t?.packId?.trim()||p.getActivePackId(n)||o.activePackId;if(!a||a==="default")return;const s=await p.getActiveAgentManifest(n,e,a),c=(0,serveClient_js_1.getRemoteServeUrl)(s);if(c)return{packId:a,remoteUrl:c,preferredEngine:s?.spec?.engine}})),i.subscriptions.push(vscode.commands.registerCommand("agentide.pack.create",async()=>{const{workspaceRoot:t,isHomeFallback:n}=getWorkspaceRoot(e);n&&await ensureFallbackDirectoryExists(e);let a;try{const l=await vscode.commands.executeCommand("agentide.getChatState");a=l?.modelId,log(e,`[AgentIDE] Current chat state: mode=${l?.mode}, modelId=${a}, modelName=${l?.modelName}`)}catch{}const s=await vscode.window.showInputBox({prompt:"Enter the agent pack name",placeHolder:"e.g., code-reviewer, security-auditor, My Code Reviewer",validateInput:async l=>{const g=(0,paths_1.normalizePackName)(l),D=(0,paths_1.getPackNameError)(g);if(D)return D;const v=path.join((0,paths_1.getAgentideDir)(t),paths_1.AGENT_CONSTANTS.AGENTS_DIR,g);if(await(0,utils_1.pathExists)(v))return`A pack named "${g}" already exists. Choose a different name.`}});if(!s)return;const c=(0,paths_1.normalizePackName)(s);log(e,`[AgentIDE] Pack name normalized: "${s}" -> "${c}"`);const r=path.join((0,paths_1.getAgentideDir)(t),paths_1.AGENT_CONSTANTS.AGENTS_DIR,c),u=await vscode.window.showInputBox({prompt:"Enter a short description for the pack",placeHolder:"e.g., Advanced code review agent with security analysis"}),d=await vscode.window.showQuickPick([{label:"Claude",description:"Anthropic Claude Agent SDK",engine:"claude"},{label:"Codex",description:"OpenAI Codex SDK",engine:"codex"}],{placeHolder:"Select the preferred engine for this pack",title:"Preferred Engine"});if(d)try{await fs_1.promises.mkdir(path.join(r,"rules"),{recursive:!0}),await fs_1.promises.mkdir(path.join(r,"skills"),{recursive:!0}),await fs_1.promises.mkdir(path.join(r,"mcp"),{recursive:!0});const l=(0,paths_1.generateAgentYaml)(c,{description:u||void 0,engine:d.engine,model:a});await fs_1.promises.writeFile(path.join(r,"agent.yaml"),l);const g=(0,paths_1.generateAgentsMd)(c,{description:u||void 0});await fs_1.promises.writeFile(path.join(r,"AGENTS.md"),g);const{AgentPackManager:D}=await import("./agentpack/index.js");await new D(p,()=>t,()=>b.storagePath,e).installFromLocal(r),log(e,`[AgentIDE] Created agent pack scaffold: ${c}`),showInfo(`AgentIDE: Created agent pack "${c}" at ${paths_1.AGENT_CONSTANTS.AGENTIDE_DIR_NAME}/${paths_1.AGENT_CONSTANTS.AGENTS_DIR}/${c}/`);const y=vscode.Uri.file(path.join(r,"AGENTS.md"));if(await vscode.window.showTextDocument(y),await vscode.window.showInformationMessage(`Agent pack "${c}" created. Would you like help generating a specialized configuration?`,"Yes, help me configure it","No, I'll edit manually")==="Yes, help me configure it"){const k=[`I just created a new agent pack called "${c}"`,u?` that should: ${u}.`:".",`
9
+
10
+ Please help me write a proper AGENTS.md file for this agent. `,`Ask me clarifying questions about:
11
+ `,`1. What specific tasks this agent should excel at
12
+ `,`2. What domain expertise it should have
13
+ `,`3. What constraints or limitations it should follow
14
+ `,`4. How it should format its outputs
15
+
16
+ `,`The AGENTS.md file is at: ${paths_1.AGENT_CONSTANTS.AGENTIDE_DIR_NAME}/agents/${c}/AGENTS.md`].join("");await vscode.commands.executeCommand("workbench.action.chat.open",{query:k,isPartialQuery:!1,mode:"agent",attachFiles:[y]})}}catch(l){const g=l instanceof Error?l.message:String(l);log(e,`[AgentIDE] Pack create error: ${g}`),showError(`AgentIDE: Failed to create pack - ${g}`)}})),i.subscriptions.push(vscode.commands.registerCommand("agentide.pack.share",async()=>{const{workspaceRoot:t}=getWorkspaceRoot(e),{AgentPackManager:n}=await import("./agentpack/index.js"),a=new n(p,()=>t,()=>b.storagePath,e),c=(await a.listInstalledWithCleanup()).filter(d=>d.id!=="default");if(c.length===0){showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: No agents to share (create an agent first)`);return}const r=c.map(d=>({label:d.id,description:`v${d.version}`})),u=await vscode.window.showQuickPick(r,{placeHolder:"Select an agent to share to User Library",title:"Share Agent to User Library"});if(u)try{const d=await a.shareToUserLibrary(u.label);showInfo(`AgentIDE: Shared "${u.label}" v${d} to User Library`)}catch(d){const l=d instanceof Error?d.message:String(d);log(e,`[AgentIDE] Share error: ${l}`),showError(`AgentIDE: ${l}`)}})),i.subscriptions.push(vscode.commands.registerCommand("agentide.skill.share",async()=>{const{workspaceRoot:t}=getWorkspaceRoot(e),{AgentPackManager:n}=await import("./agentpack/index.js"),{getAgentSkillsDir:a,getUserSkillDir:s}=await import("./agentpack/paths.js"),{copyDirRecursive:c,pathExists:r}=await import("./utils.js"),d=await new n(p,()=>t,()=>b.storagePath,e).listInstalledWithCleanup();if(d.length===0){showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: No agents found`);return}const l=await vscode.window.showQuickPick(d.map(w=>({label:w.id,description:`v${w.version}`})),{placeHolder:"Select agent containing the skill",title:"Save Skill to User Library"});if(!l)return;const g=a(t,l.label);if(!await r(g)){showInfo(`AgentIDE: No skills found in ${l.label}`);return}const y=(await fs_1.promises.readdir(g,{withFileTypes:!0})).filter(w=>w.isDirectory()&&!w.name.startsWith(".")).map(w=>w.name);if(y.length===0){showInfo(`AgentIDE: No skills found in ${l.label}`);return}const S=await vscode.window.showQuickPick(y.map(w=>({label:w})),{placeHolder:"Select skill to save to User Library",title:"Save Skill to User Library"});if(!S)return;const k=path.join(g,S.label),E=s(S.label);if(await r(E)){if(await vscode.window.showWarningMessage(`Skill "${S.label}" already exists in User Library. Overwrite?`,{modal:!0},"Overwrite","Cancel")!=="Overwrite")return;await fs_1.promises.rm(E,{recursive:!0,force:!0})}try{await c(k,E);const{getRegistry:w}=await import("./registry/index.js");await w(e).registerSkill({slug:S.label,displayName:S.label,latestVersion:"local",tags:[],stats:{installs:1}});const{invalidateLocalIndex:C}=await import("./store/oramaIndex.js");C(),showInfo(`AgentIDE: Saved skill "${S.label}" to User Library`)}catch(w){const A=w instanceof Error?w.message:String(w);log(e,`[AgentIDE] Share skill error: ${A}`),showError(`AgentIDE: ${A}`)}})),i.subscriptions.push(vscode.commands.registerCommand("agentide.mcp.share",async()=>{const{workspaceRoot:t}=getWorkspaceRoot(e),{AgentPackManager:n}=await import("./agentpack/index.js"),{getAgentMcpDir:a,getUserMcpServerDir:s}=await import("./agentpack/paths.js"),{copyDirRecursive:c,pathExists:r}=await import("./utils.js"),d=await new n(p,()=>t,()=>b.storagePath,e).listInstalledWithCleanup();if(d.length===0){showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: No agents found`);return}const l=await vscode.window.showQuickPick(d.map(E=>({label:E.id,description:`v${E.version}`})),{placeHolder:"Select agent containing the MCP server",title:"Save MCP Server to User Library"});if(!l)return;const g=a(t,l.label),D=path.join(g,".mcp.json");let v={mcpServers:{}};try{const E=await fs_1.promises.readFile(D,"utf-8");v=JSON.parse(E)}catch{showInfo(`AgentIDE: No MCP servers configured in ${l.label}`);return}if(!v.mcpServers||Object.keys(v.mcpServers).length===0){showInfo(`AgentIDE: No MCP servers configured in ${l.label}`);return}const y=Object.keys(v.mcpServers),S=await vscode.window.showQuickPick(y.map(E=>({label:E})),{placeHolder:"Select MCP server to save to User Library",title:"Save MCP Server to User Library"});if(!S)return;const k=s(S.label);if(await r(k)){if(await vscode.window.showWarningMessage(`MCP "${S.label}" already exists in User Library. Overwrite?`,{modal:!0},"Overwrite","Cancel")!=="Overwrite")return;await fs_1.promises.rm(k,{recursive:!0,force:!0})}try{await fs_1.promises.mkdir(k,{recursive:!0});const E=v.mcpServers[S.label];await fs_1.promises.writeFile(path.join(k,"mcp.json"),JSON.stringify({name:S.label,...E},null,2));const w=path.join(g,S.label);await r(w)&&await c(w,k);const{getRegistry:A}=await import("./registry/index.js");await A(e).registerMcp({slug:S.label,displayName:S.label,transport:E.transport||"stdio",latestVersion:"local",tags:[],stats:{installs:1}});const{invalidateLocalIndex:m}=await import("./store/oramaIndex.js");m(),showInfo(`AgentIDE: Saved MCP "${S.label}" to User Library`)}catch(E){const w=E instanceof Error?E.message:String(E);log(e,`[AgentIDE] Share MCP error: ${w}`),showError(`AgentIDE: ${w}`)}})),i.subscriptions.push(vscode.commands.registerCommand("agentide.pack.publish",async()=>{await(0,githubStoreGate_js_1.ensureGitHubStoreAccess)(i);const{workspaceRoot:t}=getWorkspaceRoot(e),{AgentPackManager:n,validateForPublish:a}=await import("./agentpack/index.js"),{publishToStore:s,STORE_CONFIG:c}=await import("./store/index.js"),d=(await new n(p,()=>t,()=>b.storagePath,e).listInstalledWithCleanup()).filter(A=>A.id!=="default");if(d.length===0){showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: No agents to publish (create an agent first)`);return}const l=await vscode.window.showQuickPick(d.map(A=>({label:A.id,description:`v${A.version}`})),{placeHolder:"Select an agent pack to publish",title:`Publish to ${c.owner}/${c.repo}`});if(!l)return;const g=await a(t,l.label);if(!g.valid){showError(`AgentIDE: Cannot publish - ${g.errors.join(", ")}`);return}if(g.warnings.length>0&&await vscode.window.showWarningMessage(`Warnings: ${g.warnings.join(", ")}`,"Publish Anyway","Cancel")!=="Publish Anyway")return;const D=await vscode.window.showInputBox({prompt:"What changed in this version? (optional)",placeHolder:"Added new features, fixed bugs..."}),{getAgentRoot:v}=await import("./agentpack/paths.js"),y=v(t,l.label),S=[];async function k(A,C){const m=await fs_1.promises.readdir(A);for(const h of m){if(h.startsWith("."))continue;const I=path.join(A,h),P=C?`${C}/${h}`:h;if((await fs_1.promises.stat(I)).isDirectory())await k(I,P);else{const M=await fs_1.promises.readFile(I,"utf-8");S.push({path:P,content:M})}}}await k(y,"");const E=d.find(A=>A.id===l.label);if(await vscode.window.showWarningMessage(`Submit "${E.id}" v${E.version} to ${c.owner}/${c.repo}?
17
+
18
+ This will create a pull request.`,{modal:!0},"Submit PR")==="Submit PR")try{const A=await vscode.window.withProgress({location:vscode.ProgressLocation.Window,title:`Publishing ${E.id} v${E.version}`,cancellable:!1},async m=>{m.report({message:"Preparing fork..."});const h=await s({type:"pack",slug:E.id,version:E.version,files:S,changelog:D},e);return m.report({message:"Creating PR..."}),h});await vscode.window.showInformationMessage(`Created PR #${A.prNumber} for ${E.id} v${E.version}`,"View PR")==="View PR"&&vscode.env.openExternal(vscode.Uri.parse(A.prUrl))}catch(A){const C=A instanceof Error?A.message:String(A);log(e,`[AgentIDE] Publish error: ${C}`),showError(`AgentIDE: ${C}`)}})),i.subscriptions.push(vscode.commands.registerCommand("agentide.pack.installFromGitHub",async t=>{const{workspaceRoot:n}=getWorkspaceRoot(e),{installFromGitHub:a}=await import("./agentpack/index.js");let s=t;if(s||(s=await vscode.window.showInputBox({prompt:"Enter GitHub repository URL or owner/repo",placeHolder:"e.g., user/my-agent-pack or github://user/pack@v1.0.0",validateInput:c=>c.trim()?c.includes("/")?null:"Expected format: owner/repo or github://owner/repo@version":"Please enter a repository"})),!!s)try{const c=await vscode.window.withProgress({location:vscode.ProgressLocation.Window,title:"Installing from GitHub",cancellable:!1},async u=>(u.report({message:"Downloading..."}),await a(n,{source:s,force:!1},e)));await vscode.commands.executeCommand("agentide.packsChanged"),await p.seedAgentDataIfNeeded(n,c.agentId,e),await vscode.window.showInformationMessage(`Installed ${c.agentId} ${c.version}!`,"Activate")==="Activate"&&await vscode.commands.executeCommand("agentide.pack.switch",c.agentId)}catch(c){const r=c instanceof Error?c.message:String(c);if(r.includes("already exists")){if(await vscode.window.showWarningMessage(r,"Overwrite","Cancel")==="Overwrite")try{const d=await vscode.window.withProgress({location:vscode.ProgressLocation.Window,title:"Installing from GitHub",cancellable:!1},async l=>(l.report({message:"Downloading..."}),await a(n,{source:s,force:!0},e)));await vscode.commands.executeCommand("agentide.packsChanged"),await p.seedAgentDataIfNeeded(n,d.agentId,e),showInfo(`AgentIDE: Installed ${d.agentId} ${d.version}`)}catch(d){const l=d instanceof Error?d.message:String(d);showError(`AgentIDE: ${l}`)}}else log(e,`[AgentIDE] Install error: ${r}`),showError(`AgentIDE: ${r}`)}})),i.subscriptions.push(vscode.commands.registerCommand("agentide.pack.browseLibrary",async()=>{const{workspaceRoot:t}=getWorkspaceRoot(e),{AgentPackManager:n}=await import("./agentpack/index.js"),a=new n(p,()=>t,()=>b.storagePath,e),s=await a.listUserLibrary();if(s.length===0){showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: User Library is empty. Share agents with "${branding_1.AGENTIDE_BRAND_NAME}: Share Agent to User Library"`);return}const c=s.map(d=>({label:d.id,description:d.currentVersion?`v${d.currentVersion}`:`${d.versions.length} version(s)`,detail:d.description||`Preferred engine: ${d.preferredEngine||"unknown"}`,agentId:d.id,currentVersion:d.currentVersion})),r=await vscode.window.showQuickPick(c,{placeHolder:"Select an agent to install",title:"User Agent Library"});if(!(!r||(await vscode.window.showQuickPick([{label:"Install to Workspace",action:"install"},{label:"Cancel",action:"cancel"}],{placeHolder:`What would you like to do with "${r.agentId}"?`}))?.action!=="install"))try{const d=await a.installAgentToWorkspace(r.agentId);if(d.installed){const l=d.hydrated?`Installed "${r.agentId}" v${d.version} to workspace from User Library`:`"${r.agentId}" is already installed in this workspace`;showInfo(`AgentIDE: ${l}`)}else showError(`AgentIDE: Failed to install "${r.agentId}"`)}catch(d){const l=d instanceof Error?d.message:String(d);log(e,`[AgentIDE] Install error: ${l}`),showError(`AgentIDE: ${l}`)}})),i.subscriptions.push(vscode.commands.registerCommand("agentide.skill.publish",async()=>{const{workspaceRoot:t}=getWorkspaceRoot(e),n=path.join(t,".agent-hippo","agents"),a=[];if(await(0,utils_1.pathExists)(n)){const c=await fs_1.promises.readdir(n);for(const r of c){const u=path.join(n,r,"skills");if(await(0,utils_1.pathExists)(u)){const d=await fs_1.promises.readdir(u);for(const l of d){const g=path.join(u,l),D=path.join(g,"SKILL.md");await(0,utils_1.pathExists)(D)&&a.push({name:l,path:g})}}}}if(a.length===0){showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: No skills found. Create a skill with SKILL.md in your agent's skills/ folder.`);return}const s=await vscode.window.showQuickPick(a.map(c=>({label:c.name,path:c.path})),{placeHolder:"Select a skill to publish"});if(s)try{const{validateSkillForPublish:c,collectSkillFiles:r}=await import("./skills/publish.js"),{publishToStore:u}=await import("./store/index.js"),d=await c(s.path);if(!d.valid){showError(`AgentIDE: ${d.errors.join(", ")}`);return}const l=d.metadata?.version||await vscode.window.showInputBox({prompt:"Version (semver)",placeHolder:"e.g., 1.0.0",validateInput:E=>/^\d+\.\d+\.\d+/.test(E)?null:"Use semver format (e.g., 1.0.0)"});if(!l)return;const g=await r(s.path),D=await vscode.window.withProgress({location:vscode.ProgressLocation.Window,title:`Publishing skill "${s.label}"`,cancellable:!1},async E=>{E.report({message:"Preparing fork..."});const w=await u({type:"skill",slug:s.label,version:l,files:g},e);return E.report({message:"Creating PR..."}),w}),{getRegistry:v}=await import("./registry/index.js"),{STORE_CONFIG:y}=await import("./store/index.js");await v(e).registerSkill({slug:s.label,displayName:d.metadata?.name||s.label,description:d.metadata?.description,github:{owner:y.owner,repo:y.repo},latestVersion:l,tags:d.metadata?.tags||[],stats:{installs:0}}),await vscode.window.showInformationMessage(`Published skill "${s.label}" v${l}! PR created.`,"View PR")==="View PR"&&vscode.env.openExternal(vscode.Uri.parse(D.prUrl))}catch(c){const r=c instanceof Error?c.message:String(c);log(e,`[AgentIDE] Skill publish error: ${r}`),showError(`AgentIDE: ${r}`)}})),i.subscriptions.push(vscode.commands.registerCommand("agentide.mcp.publish",async()=>{const{workspaceRoot:t}=getWorkspaceRoot(e),n=path.join(t,".agentide","agents"),a=[];if(await(0,utils_1.pathExists)(n)){const c=await fs_1.promises.readdir(n);for(const r of c){const u=path.join(n,r,"mcp"),d=path.join(u,".mcp.json");if(await(0,utils_1.pathExists)(d))try{const l=await fs_1.promises.readFile(d,"utf-8"),g=JSON.parse(l);if(g.mcpServers)for(const D of Object.keys(g.mcpServers))a.push({name:D,agentId:r,configPath:d,mcpDir:u})}catch{}}}if(a.length===0){showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: No MCP servers found. Add MCP servers to your agent's mcp/.mcp.json file.`);return}const s=await vscode.window.showQuickPick(a.map(c=>({label:c.name,description:`from ${c.agentId}`,detail:c.configPath,config:c})),{placeHolder:"Select an MCP server to publish"});if(s)try{const{publishToStore:c,STORE_CONFIG:r}=await import("./store/index.js"),{collectMcpFiles:u,validateMcpConfig:d}=await import("./mcp/publish.js"),{getRegistry:l}=await import("./registry/index.js"),g=await fs_1.promises.readFile(s.config.configPath,"utf-8"),v=JSON.parse(g).mcpServers[s.config.name],y=d({name:s.config.name,version:v.version||"1.0.0",description:v.description,transport:v.transport||"stdio",command:v.command,args:v.args,env:v.env,url:v.url,npmPackage:v.npmPackage});if(!y.valid){showError(`AgentIDE: ${y.errors.join(", ")}`);return}const S=v.version||await vscode.window.showInputBox({prompt:"Version (semver)",placeHolder:"e.g., 1.0.0",value:"1.0.0",validateInput:I=>/^\d+\.\d+\.\d+/.test(I)?null:"Use semver format (e.g., 1.0.0)"});if(!S)return;let k=v.description;if(!k&&(k=await vscode.window.showInputBox({prompt:"Description (required)",placeHolder:"What does this MCP server do?"}),!k)){showError(`${branding_1.AGENTIDE_BRAND_NAME}: Description is required`);return}const E=await u(s.config.mcpDir),w={name:s.config.name,version:S,description:k,transport:v.transport||"stdio",command:v.command,args:v.args,env:v.env,url:v.url,npmPackage:v.npmPackage},A=JSON.parse(JSON.stringify(w));E.push({path:"mcp.json",content:JSON.stringify(A,null,2)});const C=await vscode.window.withProgress({location:vscode.ProgressLocation.Window,title:`Publishing MCP "${s.config.name}"`,cancellable:!1},async I=>{I.report({message:"Preparing fork..."});const P=await c({type:"mcp",slug:s.config.name,version:S,files:E},e);return I.report({message:"Creating PR..."}),P});await l(e).registerMcp({slug:s.config.name,displayName:s.config.name,description:k,transport:v.transport||"stdio",github:{owner:r.owner,repo:r.repo},latestVersion:S,tags:[],stats:{installs:0}}),await vscode.window.showInformationMessage(`Published MCP "${s.config.name}" v${S}! PR created.`,"View PR")==="View PR"&&vscode.env.openExternal(vscode.Uri.parse(C.prUrl))}catch(c){const r=c instanceof Error?c.message:String(c);log(e,`[AgentIDE] MCP publish error: ${r}`),showError(`AgentIDE: ${r}`)}})),i.subscriptions.push(vscode.commands.registerCommand("agentide.spotlight.publish",async(t,n)=>{const a=n?.bundle==="scripts-only"?"scripts-only":"full",{workspaceRoot:s}=getWorkspaceRoot(e),{collectViewFiles:c,discoverPublishableViews:r,validateViewForPublish:u}=await import("./spotlight/publish.js"),{publishToStore:d,STORE_CONFIG:l,canPublishDirectlyToStore:g}=await import("./store/index.js"),{isValidPublishVersion:D}=await import("./engines/publish.js"),v=await r(s);if(v.length===0){showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: No publishable Spotlight views found. Create a view under .agent-hippo/analytics and register it in panel/views.yaml.`);return}const y=typeof t=="string"?t.trim():"";let S=y?v.find(k=>k.id===y):void 0;if(y&&!S){showError(`${branding_1.AGENTIDE_BRAND_NAME}: View "${y}" is not publishable. Add widget scripts under .agent-hippo/analytics/views/${y}/scripts and register the view in panel/views.yaml.`);return}if(!S){const k=await vscode.window.showQuickPick(v.map(E=>({label:E.name,description:E.id,detail:`${E.sourceLabel} \u2022 ${E.scope} \u2022 ${E.scripts.length} script(s)`,view:E})),{placeHolder:"Select a Spotlight view to publish",title:`Publish to ${l.owner}/${l.repo}`});if(!k)return;S=k.view}try{const k=await u(S,{expectedId:S.id,mode:a});if(!k.valid){showError(`${branding_1.AGENTIDE_BRAND_NAME}: Cannot publish - ${k.errors.join(", ")}`);return}if(k.warnings.length>0&&await vscode.window.showWarningMessage(`Warnings: ${k.warnings.join(", ")}`,"Publish Anyway","Cancel")!=="Publish Anyway")return;const E=await vscode.window.showInputBox({prompt:"Publish version (semver)",value:k.metadata?.publishVersion||"1.0.0",placeHolder:"e.g., 1.0.0",validateInput:M=>M&&D(M.replace(/^v/,""))?null:"Use semver format (e.g., 1.0.0)"});if(!E||!k.metadata)return;const w=E.replace(/^v/,""),A=await vscode.window.showInputBox({prompt:"What changed in this version? (optional)",placeHolder:"Initial release, new widgets..."}),C=await c(S,w,k.metadata,a),m=a==="full"?"full bundle (scripts + assets + charts/exports)":"scripts only",h=await g();if(await vscode.window.showWarningMessage(h?`Publish Spotlight view "${S.id}" v${w} (${m}) to ${l.owner}/${l.repo}?
19
+
20
+ This will open a pull request on the store repository.`:`Submit Spotlight view "${S.id}" v${w} (${m}) to ${l.owner}/${l.repo}?
21
+
22
+ This will create a pull request from your fork.`,{modal:!0},"Submit PR")!=="Submit PR")return;const P=await vscode.window.withProgress({location:vscode.ProgressLocation.Window,title:`Publishing Spotlight view ${S.id} v${w}`,cancellable:!1},async M=>(M.report({message:h?`Publishing to ${l.owner}/${l.repo}...`:"Preparing fork..."}),await d({type:"view",slug:S.id,version:w,files:C,changelog:A},e)));await vscode.window.showInformationMessage(`Published Spotlight view "${S.name}" v${w}! PR created.`,"View PR")==="View PR"&&vscode.env.openExternal(vscode.Uri.parse(P.prUrl))}catch(k){const E=k instanceof Error?k.message:String(k);log(e,`[AgentIDE] Spotlight publish error: ${E}`),showError(`${branding_1.AGENTIDE_BRAND_NAME}: ${E}`)}})),i.subscriptions.push(vscode.commands.registerCommand("agentide.store.install",async t=>{await(0,githubStoreGate_js_1.ensureGitHubStoreAccess)(i);const{parseStoreUrl:n}=await import("./store/index.js");let a=t;if(a||(a=await vscode.window.showInputBox({prompt:"Enter store URL or GitHub link",placeHolder:"e.g., engine/gemini or https://github.com/.../engines/gemini",validateInput:s=>s.trim()?s.includes("/")?null:"Expected: type/slug, or GitHub URL":"Please enter a URL"})),!!a)try{const s=n(a);switch(s.type){case"pack":await vscode.commands.executeCommand("agentide.pack.storeInstall",s);break;case"skill":await vscode.commands.executeCommand("agentide.skill.install",s);break;case"mcp":await vscode.commands.executeCommand("agentide.mcp.install",s);break;case"engine":await vscode.commands.executeCommand("agentide.engine.install",s);break;case"view":await vscode.commands.executeCommand("agentide.view.install",s);break}}catch(s){const c=s instanceof Error?s.message:String(s);log(e,`[AgentIDE] Store install error: ${c}`),showError(`AgentIDE: ${c}`)}})),i.subscriptions.push(vscode.commands.registerCommand("agentide.store.find",async t=>{await(0,githubStoreGate_js_1.ensureGitHubStoreAccess)(i);const{isStoreUrl:n,parseStoreUrl:a,parseGitHubUrl:s,detectArtifactType:c}=await import("./store/index.js"),{searchMerged:r,listMergedArtifacts:u}=await import("./store/oramaIndex.js");let d,l="all";if(typeof t=="string"?d=t:t&&typeof t=="object"&&t.typeFilter&&(l=t.typeFilter),d)try{let h,I,P;if(n(d)){const T=a(d);h=T.type,I=T.slug,P=T.version}else{const T=s(d);h=await vscode.window.withProgress({location:vscode.ProgressLocation.Notification,title:"Detecting artifact type...",cancellable:!1},async()=>await c(T.owner,T.repo,T.ref,T.path,e));const M=(T.path||T.repo).split("/");I=M[M.length-1]||T.repo,P=T.ref}switch(h){case"pack":await vscode.commands.executeCommand("agentide.pack.storeInstall",{type:"pack",slug:I,version:P,sourceUrl:d});break;case"skill":await vscode.commands.executeCommand("agentide.skill.install",{type:"skill",slug:I,version:P,sourceUrl:d});break;case"mcp":await vscode.commands.executeCommand("agentide.mcp.install",{type:"mcp",slug:I,version:P,sourceUrl:d});break;case"engine":await vscode.commands.executeCommand("agentide.engine.install",{type:"engine",slug:I,version:P,sourceUrl:d});break;case"view":await vscode.commands.executeCommand("agentide.view.install",{type:"view",slug:I,version:P,sourceUrl:d});break}return}catch(h){const I=h instanceof Error?h.message:String(h);log(e,`[AgentIDE] Install error: ${I}`),showError(`AgentIDE: ${I}`);return}const{STORE_ICONS:g}=await import("./store/shared.js"),D={pack:g.pack,skill:g.skill,mcp:g.mcp,engine:g.engine,view:g.view},v=["all","pack","skill","mcp","engine","view"],y=vscode.window.createQuickPick();y.title=l==="view"?"Install Spotlight View":"Install Packs, Skills, MCP Tools, Engines, Spotlight Views",y.placeholder="Search or paste a GitHub URL to install...",y.matchOnDescription=!0,y.matchOnDetail=!0,y.busy=!0;let S=[],k=l,E;const w={local:g.local,remote:g.remote},A=h=>{const I=h??S,P=k==="all"?I:I.filter($=>$.type===k),T=v.map($=>({label:$==="all"?"$(list-flat) All":`${D[$]} ${$.charAt(0).toUpperCase()+$.slice(1)}s`,description:$===k?"$(check)":"",alwaysShow:!0,itemType:"filter",filter:$})),M=P.map($=>{const _=$.source==="local"?w.local:w.remote,U=$.installed?"$(check)":"",x=[$.source==="local"?"Local":"Remote",$.type];U&&x.push(U);let R=$.description||$.path;return $.installedTo&&$.installedTo.length>0&&(R+=` \u2022 Installed to: ${$.installedTo.join(", ")}`),{label:`${_} ${D[$.type]} ${$.slug}`,description:x.join(" \u2022 "),detail:R,itemType:"artifact",artifact:$}});y.items=[...T,{label:"",kind:vscode.QuickPickItemKind.Separator,itemType:"filter"},...M]},C=async h=>{E&&clearTimeout(E);const I=h.trim();if(!I||I.startsWith("http")||I.startsWith("store://")||I.startsWith("github.com")){A(S);return}E=setTimeout(async()=>{try{const M=(await r(I,{type:k==="all"?void 0:k,limit:50},e)).map($=>({type:$.type,slug:$.slug,path:`${$.type}s/${$.slug}`,description:$.description,installed:$.installed,installedVersion:$.installedVersion,source:$.source,installedTo:$.installedTo}));A(M)}catch(P){log(e,`[AgentIDE] Search error: ${P instanceof Error?P.message:String(P)}`),A(S)}},150)};y.onDidChangeValue(C);try{S=(await u(void 0,e)).map(I=>({type:I.type,slug:I.slug,path:`${I.type}s/${I.slug}`,description:I.description,installed:I.installed,installedVersion:I.installedVersion,source:I.source,installedTo:I.installedTo})),y.busy=!1,A(),S.length===0&&(y.placeholder="Store is empty or index not synced yet. Try again later!")}catch(h){const I=h instanceof Error?h.message:String(h);log(e,`[AgentIDE] Store browse error: ${I}`),y.hide(),showError(`AgentIDE: ${I}`);return}const m=h=>{const I=h.trim();return I.startsWith("https://")||I.startsWith("http://")||I.startsWith("github.com/")||I.startsWith("store://")};y.onDidAccept(async()=>{const h=y.selectedItems[0],I=y.value.trim();if(I&&m(I)){y.hide(),log(e,`[AgentIDE] Browse Store: detected URL input: ${I}`),await vscode.commands.executeCommand("agentide.store.find",I);return}if(h){if(h.itemType==="filter"&&h.filter){k=h.filter,A();return}if(h.itemType==="artifact"&&h.artifact){y.hide();const{artifact:P}=h;switch(P.type){case"pack":await vscode.commands.executeCommand("agentide.pack.storeInstall",{type:"pack",slug:P.slug});break;case"skill":await vscode.commands.executeCommand("agentide.skill.install",{type:"skill",slug:P.slug});break;case"mcp":await vscode.commands.executeCommand("agentide.mcp.install",{type:"mcp",slug:P.slug});break;case"engine":await vscode.commands.executeCommand("agentide.engine.install",{type:"engine",slug:P.slug});break;case"view":await vscode.commands.executeCommand("agentide.view.install",{type:"view",slug:P.slug});break}}}}),y.onDidHide(()=>y.dispose()),y.show()})),i.subscriptions.push(vscode.commands.registerCommand("agentide.store.search",async(t,n)=>{const{searchMerged:a}=await import("./store/oramaIndex.js");return a(t,n,e)})),i.subscriptions.push(vscode.commands.registerCommand("agentide.store.sync",async()=>{const{forceRefresh:t,getIndexMeta:n}=await import("./store/oramaIndex.js");await vscode.window.withProgress({location:vscode.ProgressLocation.Notification,title:"Syncing store index...",cancellable:!1},async()=>{await t(e)});const a=await n();a&&showInfo(`Store index synced: ${a.artifactCount} artifacts (updated ${new Date(a.generatedAt).toLocaleDateString()})`)})),i.subscriptions.push(vscode.commands.registerCommand("agentide.store.setup",async()=>{const{setupStoreAutomation:t}=await import("./store/github/setup.js"),n=await vscode.window.showInputBox({prompt:"Enter GitHub repository URL for your store",placeHolder:"https://github.com/owner/repo or owner/repo",validateInput:d=>d?d.match(/(?:github\.com\/)?([^/]+)\/([^/]+)/)?null:"Invalid format. Use: owner/repo or https://github.com/owner/repo":"Repository URL is required"});if(!n)return;const a=n.match(/(?:github\.com\/)?([^/]+)\/([^/]+)/);if(!a){showError("Invalid repository URL");return}const[,s,c]=a,r=c.replace(/\.git$/,""),u=await vscode.window.withProgress({location:vscode.ProgressLocation.Notification,title:`Setting up store automation for ${s}/${r}...`,cancellable:!1},async()=>await t(s,r,e));if(u.success&&u.pullRequestUrl){const d=vscode.workspace.getConfiguration("agentide"),l=`${s}/${r}`,g=d.get("storeRepo",""),D=d.get("store.indexUrl",""),v=`https://${s}.github.io/${r}`;let y="";if(g){const k=g.match(/^(?:https?:\/\/github\.com\/)?([^/]+)\/([^/]+?)(?:\.git)?$/);k&&(y=`https://${k[1]}.github.io/${k[2]}`)}await d.update("storeRepo",l,vscode.ConfigurationTarget.Global),(!D||y&&D===y)&&await d.update("store.indexUrl",v,vscode.ConfigurationTarget.Global);const S=await vscode.window.showInformationMessage(`\u{1F99B} ${u.message}`,"Open Pull Request","Copy URL");S==="Open Pull Request"?await vscode.env.openExternal(vscode.Uri.parse(u.pullRequestUrl)):S==="Copy URL"&&(await vscode.env.clipboard.writeText(u.pullRequestUrl),showInfo("Pull request URL copied to clipboard"))}else u.success||showError(`Setup failed: ${u.message}`)})),i.subscriptions.push(vscode.commands.registerCommand("agentide.pack.storeInstall",async t=>{const{workspaceRoot:n}=getWorkspaceRoot(e),{downloadFromStore:a,listStoreVersions:s}=await import("./store/index.js"),{getAgentRoot:c}=await import("./agentpack/paths.js"),r=t||{type:"pack",slug:"",version:void 0};if(!r.version){const y=await s("pack",r.slug);if(y.length===0)r.version="main";else{const S=await vscode.window.showQuickPick(y.map(k=>({label:k.version,description:k.isPrerelease?"(pre-release)":""})),{placeHolder:"Select version to install"});if(!S)return;r.version=S.label}}const u=c(n,r.slug);if(await fs_1.promises.access(u).then(()=>!0).catch(()=>!1)){if(await vscode.window.showWarningMessage(`Pack "${r.slug}" already exists. Overwrite?`,{modal:!0},"Overwrite","Cancel")!=="Overwrite")return;await fs_1.promises.rm(u,{recursive:!0,force:!0})}await vscode.window.withProgress({location:vscode.ProgressLocation.Window,title:`Installing pack "${r.slug}"`,cancellable:!1},async y=>{y.report({message:"Downloading from store..."});const S=await a({type:"pack",slug:r.slug,version:r.version},e);y.report({message:"Extracting files..."}),await fs_1.promises.mkdir(u,{recursive:!0});for(const k of S){const E=path.join(u,k.path);await fs_1.promises.mkdir(path.dirname(E),{recursive:!0}),await fs_1.promises.writeFile(E,k.content)}}),await vscode.commands.executeCommand("agentide.packsChanged");const{getRegistry:l}=await import("./registry/index.js");await l(e).registerPack({slug:r.slug,displayName:r.slug,latestVersion:r.version||"main",tags:[],stats:{installs:1,stars:0}});const{invalidateLocalIndex:D}=await import("./store/oramaIndex.js");D(),await vscode.window.showInformationMessage(`Installed pack "${r.slug}" v${r.version}`,"Activate")==="Activate"&&await vscode.commands.executeCommand("agentide.pack.switch",r.slug)})),i.subscriptions.push(vscode.commands.registerCommand("agentide.skill.install",async t=>{const{workspaceRoot:n}=getWorkspaceRoot(e),{downloadFromStore:a,downloadFromExternalGitHub:s,listStoreVersions:c,isStoreUrl:r,parseGitHubUrl:u}=await import("./store/index.js"),{AgentPackManager:d}=await import("./agentpack/index.js"),l=new d(p,()=>n,()=>b.storagePath,e);let g=t;if(!g){const h=await vscode.window.showInputBox({prompt:"Enter skill store URL or GitHub URL",placeHolder:"e.g., skills/typescript-testing@v1.0.0 or https://github.com/user/repo"});if(!h)return;const{parseStoreUrl:I}=await import("./store/index.js");g=I(h)}const D=g.sourceUrl&&!r(g.sourceUrl);if(!g.version&&!D){const h=await c("skill",g.slug);if(h.length===0)g.version="main";else{const I=await vscode.window.showQuickPick(h.map(P=>({label:P.version,description:P.isPrerelease?"(pre-release)":""})),{placeHolder:"Select version to install"});if(!I)return;g.version=I.label}}const v=await l.listInstalledWithCleanup();if(v.length===0){showError(`${branding_1.AGENTIDE_BRAND_NAME}: No agents found. Create an agent first.`);return}const y=await vscode.window.showQuickPick(v.map(h=>({label:h.id,description:`v${h.version}`})),{placeHolder:"Select agent to install skill to"});if(!y)return;const{getAgentRoot:S}=await import("./agentpack/paths.js"),k=S(n,y.label),E=path.join(k,"skills",g.slug);if(await fs_1.promises.access(E).then(()=>!0).catch(()=>!1)){if(await vscode.window.showWarningMessage(`Skill "${g.slug}" already exists in ${y.label}. Overwrite?`,{modal:!0},"Overwrite","Cancel")!=="Overwrite")return;await fs_1.promises.rm(E,{recursive:!0,force:!0})}await vscode.window.withProgress({location:vscode.ProgressLocation.Window,title:`Installing skill "${g.slug}"`,cancellable:!1},async h=>{let I;if(D&&g.sourceUrl){h.report({message:"Downloading from GitHub..."});const P=u(g.sourceUrl);I=await s({owner:P.owner,repo:P.repo,ref:P.ref||"main",path:P.path},e)}else h.report({message:"Downloading from store..."}),I=await a({type:"skill",slug:g.slug,version:g.version},e);h.report({message:"Extracting files..."}),await fs_1.promises.mkdir(E,{recursive:!0});for(const P of I){const T=path.join(E,P.path);await fs_1.promises.mkdir(path.dirname(T),{recursive:!0}),await fs_1.promises.writeFile(T,P.content)}});const{getRegistry:A}=await import("./registry/index.js");await A(e).registerSkill({slug:g.slug,displayName:g.slug,latestVersion:g.version||"main",tags:[],stats:{installs:1},agentPackId:y.label});const{invalidateLocalIndex:m}=await import("./store/oramaIndex.js");m(),showInfo(`Installed skill "${g.slug}" to ${y.label}`)})),i.subscriptions.push(vscode.commands.registerCommand("agentide.mcp.install",async t=>{const{workspaceRoot:n}=getWorkspaceRoot(e),{downloadFromStore:a,listStoreVersions:s}=await import("./store/index.js"),{AgentPackManager:c}=await import("./agentpack/index.js"),r=new c(p,()=>n,()=>b.storagePath,e);let u=t;if(!u){const y=await vscode.window.showInputBox({prompt:"Enter MCP store URL",placeHolder:"e.g., mcp/github@v1.0.0"});if(!y)return;const{parseStoreUrl:S}=await import("./store/index.js");u=S(y)}if(!u.version){const y=await s("mcp",u.slug);if(y.length===0)u.version="main";else{const S=await vscode.window.showQuickPick(y.map(k=>({label:k.version,description:k.isPrerelease?"(pre-release)":""})),{placeHolder:"Select version to install"});if(!S)return;u.version=S.label}}const d=await r.listInstalledWithCleanup();if(d.length===0){showError(`${branding_1.AGENTIDE_BRAND_NAME}: No agents found. Create an agent first.`);return}const l=await vscode.window.showQuickPick(d.map(y=>({label:y.id,description:`v${y.version}`})),{placeHolder:"Select agent to add MCP server to"});if(!l)return;await vscode.window.withProgress({location:vscode.ProgressLocation.Window,title:`Installing MCP "${u.slug}"`,cancellable:!1},async y=>{y.report({message:"Downloading from store..."});const S=await a({type:"mcp",slug:u.slug,version:u.version},e);y.report({message:"Merging MCP config..."});const k=S.find(I=>I.path==="mcp.json"||I.path.endsWith("/mcp.json"));if(!k)throw new Error("Downloaded MCP package missing mcp.json");const E=JSON.parse(k.content.toString()),{getAgentRoot:w}=await import("./agentpack/paths.js"),A=w(n,l.label),C=path.join(A,"mcp"),m=path.join(C,".mcp.json");await fs_1.promises.mkdir(C,{recursive:!0});let h={mcpServers:{}};try{const I=await fs_1.promises.readFile(m,"utf-8");h=JSON.parse(I),h.mcpServers||(h.mcpServers={})}catch{}h.mcpServers[u.slug]={transport:E.transport||"stdio",command:E.command,args:E.args,env:E.env,url:E.url,npmPackage:E.npmPackage,_version:u.version,_description:E.description},await fs_1.promises.writeFile(m,JSON.stringify(h,null,2));for(const I of S)if(I.path!=="mcp.json"&&!I.path.endsWith("/mcp.json")){const P=path.join(C,u.slug,I.path);await fs_1.promises.mkdir(path.dirname(P),{recursive:!0}),await fs_1.promises.writeFile(P,I.content)}});const{getRegistry:g}=await import("./registry/index.js");await g(e).registerMcp({slug:u.slug,displayName:u.slug,transport:"stdio",latestVersion:u.version||"main",tags:[],stats:{installs:1},agentPackId:l.label});const{invalidateLocalIndex:v}=await import("./store/oramaIndex.js");v(),showInfo(`Installed MCP "${u.slug}" v${u.version} to ${l.label}`)})),i.subscriptions.push(vscode.commands.registerCommand("agentide.engine.install",async t=>{const{downloadFromStore:n,downloadFromExternalGitHub:a,listStoreVersions:s,isStoreUrl:c,parseGitHubUrl:r,parseStoreUrl:u}=await import("./store/index.js"),{installCustomEngineFromFiles:d}=await import("./engines/install.js");let l=t;if(!l){const k=await vscode.window.showInputBox({prompt:"Enter custom engine store URL or GitHub URL",placeHolder:"e.g., engine/gemini or https://github.com/user/repo/tree/main/gemini"});if(!k)return;if(c(k))l=u(k);else{const E=r(k),w=(E.path||E.repo).split("/");l={type:"engine",slug:w[w.length-1]||E.repo,version:E.ref,sourceUrl:k}}}const g=l.sourceUrl&&!c(l.sourceUrl);if(!l.version&&!g){const k=await s("engine",l.slug);if(k.length===0)l.version="main";else{const E=await vscode.window.showQuickPick(k.map(w=>({label:w.version,description:w.isPrerelease?"(pre-release)":""})),{placeHolder:"Select version to install"});if(!E)return;l.version=E.label}}const D=async k=>await vscode.window.withProgress({location:vscode.ProgressLocation.Window,title:`Installing engine "${l.slug}"`,cancellable:!1},async E=>{let w;if(g&&l.sourceUrl){E.report({message:"Downloading from GitHub..."});const A=r(l.sourceUrl);w=await a({owner:A.owner,repo:A.repo,ref:A.ref||"main",path:A.path},e)}else E.report({message:"Downloading from store..."}),w=await n({type:"engine",slug:l.slug,version:l.version},e);return E.report({message:"Validating and installing..."}),await d(w,{slug:l.slug,version:l.version,sourceUrl:l.sourceUrl,overwrite:k,logger:e})});let v;try{v=await D(!1)}catch(k){const E=k instanceof Error?k.message:String(k);if(!E.includes("already exists")){log(e,`[AgentIDE] Engine install error: ${E}`),showError(`AgentIDE: ${E}`);return}if(await vscode.window.showWarningMessage(E,{modal:!0},"Overwrite","Cancel")!=="Overwrite")return;try{v=await D(!0)}catch(A){const C=A instanceof Error?A.message:String(A);log(e,`[AgentIDE] Engine install error: ${C}`),showError(`AgentIDE: ${C}`);return}}const{invalidateLocalIndex:y}=await import("./store/oramaIndex.js");if(y(),!v)return;clearCustomEngineRuntimeCache(o,v.id),await refreshCustomEnginePicker(e),await vscode.window.showInformationMessage(`Installed engine "${v.displayName}"`,"List Engines")==="List Engines"&&await vscode.commands.executeCommand("agentide.customEngine.list")})),i.subscriptions.push(vscode.commands.registerCommand("agentide.view.install",async t=>{const{workspaceRoot:n}=getWorkspaceRoot(e),{downloadFromStore:a,downloadFromExternalGitHub:s,listStoreVersions:c,isStoreUrl:r,parseGitHubUrl:u,parseStoreUrl:d}=await import("./store/index.js"),{installSpotlightViewFromFiles:l}=await import("./spotlight/install.js");let g=t;if(!g){const w=await vscode.window.showInputBox({prompt:"Enter Spotlight view store URL or GitHub URL",placeHolder:"e.g., view/cost-ops or https://github.com/user/repo/tree/main/spotlight/cost-ops"});if(!w)return;if(r(w))g=d(w);else{const A=u(w),C=(A.path||A.repo).split("/");g={type:"view",slug:C[C.length-1]||A.repo,version:A.ref,sourceUrl:w}}}const D=g.sourceUrl&&!r(g.sourceUrl);if(!g.version&&!D){const w=await c("view",g.slug);if(w.length===0)g.version="main";else{const A=await vscode.window.showQuickPick(w.map(C=>({label:C.version,description:C.isPrerelease?"(pre-release)":""})),{placeHolder:"Select version to install"});if(!A)return;g.version=A.label}}const v=async(w,A)=>await vscode.window.withProgress({location:vscode.ProgressLocation.Window,title:`Installing Spotlight view "${g.slug}"`,cancellable:!1},async C=>{let m;if(D&&g.sourceUrl){C.report({message:"Downloading from GitHub..."});const h=u(g.sourceUrl);m=(await s({owner:h.owner,repo:h.repo,ref:h.ref||"main",path:h.path},e)).map(P=>({path:P.path,content:P.content}))}else C.report({message:"Downloading from store..."}),m=await a({type:"view",slug:g.slug,version:g.version},e);return C.report({message:"Installing view..."}),await l(m,{slug:g.slug,version:g.version,overwrite:w,activate:A,workspaceRoot:n,logger:e})});let y;try{y=await v(!1,!1)}catch(w){const A=w instanceof Error?w.message:String(w);if(!A.includes("already exists")){log(e,`[AgentIDE] Spotlight view install error: ${A}`),showError(`AgentIDE: ${A}`);return}if(await vscode.window.showWarningMessage(A,{modal:!0},"Overwrite","Cancel")!=="Overwrite")return;try{y=await v(!0,!1)}catch(m){const h=m instanceof Error?m.message:String(m);log(e,`[AgentIDE] Spotlight view install error: ${h}`),showError(`AgentIDE: ${h}`);return}}const{invalidateLocalIndex:S}=await import("./store/oramaIndex.js");if(S(),!y)return;const k=_state?.analyticsDashboard;k&&await k.refreshViewsFromDisk();const E=await vscode.window.showInformationMessage(`Installed Spotlight view "${y.id}" v${y.version||g.version||"main"}`,"Open Spotlight","Activate View");if(E==="Open Spotlight")await vscode.commands.executeCommand("agentide.analytics.openDashboard");else if(E==="Activate View"){const{setActiveSpotlightView:w}=await import("./spotlight/install.js");await w(y.viewsConfigPath,y.id);const A=_state?.analyticsDashboard;A&&await A.refreshViewsFromDisk(),await vscode.commands.executeCommand("agentide.analytics.openDashboard")}})),i.subscriptions.push(vscode.commands.registerCommand("agentide.pack.update",async()=>{const{workspaceRoot:t}=getWorkspaceRoot(e),{AgentPackManager:n}=await import("./agentpack/index.js"),a=new n(p,()=>t,()=>b.storagePath,e),s=await a.listInstalledWithCleanup(),c=[];for(const l of s){if(l.id==="default")continue;const g=await a.checkAgentUpdate(l.id);g&&c.push({id:l.id,version:l.version,newVersion:g})}if(c.length===0){showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: All agents are up to date`);return}const r=c.map(l=>({label:l.id,description:`v${l.version} \u2192 v${l.newVersion}`})),u=await vscode.window.showQuickPick(r,{placeHolder:"Select an agent to update",title:"Update Agent from User Library"});if(!(!u||await vscode.window.showWarningMessage(`Update "${u.label}" from User Library? Current version will be backed up.`,{modal:!0},"Update","Cancel")!=="Update"))try{const l=await a.updateFromLibrary(u.label);showInfo(`AgentIDE: Updated "${u.label}" to v${l}`)}catch(l){const g=l instanceof Error?l.message:String(l);log(e,`[AgentIDE] Update error: ${g}`),showError(`AgentIDE: ${g}`)}})),i.subscriptions.push(vscode.commands.registerCommand("agentide.pack.duplicate",async()=>{const{workspaceRoot:t}=getWorkspaceRoot(e),{AgentPackManager:n}=await import("./agentpack/index.js"),a=new n(p,()=>t,()=>b.storagePath,e),s=await a.listInstalledWithCleanup();if(s.length===0){showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: No agents to duplicate`);return}const c=s.map(u=>({label:u.id,description:`v${u.version}`})),r=await vscode.window.showQuickPick(c,{placeHolder:"Select an agent to duplicate",title:"Duplicate Agent"});if(r)try{const u=await a.duplicate(r.label);showInfo(`AgentIDE: Created "${u}" as copy of "${r.label}"`);const d=path.join((0,paths_1.getAgentideDir)(t),paths_1.AGENT_CONSTANTS.AGENTS_DIR,u,paths_1.AGENT_CONSTANTS.AGENTS_MD);if(await(0,utils_1.pathExists)(d)){const l=await vscode.workspace.openTextDocument(d);await vscode.window.showTextDocument(l)}}catch(u){const d=u instanceof Error?u.message:String(u);log(e,`[AgentIDE] Duplicate error: ${d}`),showError(`AgentIDE: ${d}`)}})),i.subscriptions.push(vscode.commands.registerCommand("agentide.pack.refresh",async()=>{const{workspaceRoot:t}=getWorkspaceRoot(e),{AgentPackManager:n}=await import("./agentpack/index.js"),a=new n(p,()=>t,()=>b.storagePath,e);try{const{registered:s}=await a.repairUnregisteredAgents();return s.length>0?showInfo(`AgentIDE: Discovered ${s.length} new pack(s): ${s.join(", ")}`):showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: No new packs found`),{registered:s}}catch(s){const c=s instanceof Error?s.message:String(s);return log(e,`[AgentIDE] Pack refresh error: ${c}`),showError(`AgentIDE: ${c}`),{registered:[]}}})),i.subscriptions.push(vscode.commands.registerCommand("agentide.pack.resetDefault",async()=>{if(await vscode.window.showWarningMessage("Reset the default agent? This will restore it from bundled templates. Current default agent will be backed up.",{modal:!0},"Reset","Cancel")!=="Reset")return;const{workspaceRoot:n}=getWorkspaceRoot(e),{AgentPackManager:a}=await import("./agentpack/index.js"),s=new a(p,()=>n,()=>b.storagePath,e);try{await s.resetDefault(getBundledBasePromptsDir()),showInfo(`${branding_1.AGENTIDE_BRAND_NAME}: Default agent reset from bundled templates`),await p.flushAgentideRootUpdate(n,e,{force:!0,allowDuringActiveTurn:!0})}catch(c){const r=c instanceof Error?c.message:String(c);log(e,`[AgentIDE] Reset error: ${r}`),showError(`AgentIDE: ${r}`)}})),i.subscriptions.push(vscode.commands.registerCommand("agentide.chat",async t=>handleChatCommand(o,t))),i.subscriptions.push(vscode.commands.registerCommand("agentide.chat.cancel",async t=>{const n=t?.streamId;if(!n)return{cancelled:!1,error:"streamId is required"};const a=_activeRunsByStreamId.get(n);if(!a)return log(e,`[AgentIDE] Cancel ignored: no active run for streamId=${n}`),rejectPendingQuestionsForStream(n,"Run cancelled"),{cancelled:!1};log(e,`[AgentIDE] Cancel requested: streamId=${n}, engine=${a.engine}, ageMs=${Date.now()-a.startedAt}`);try{a.abortController.abort()}catch{}return rejectPendingQuestionsForStream(n,"Run cancelled"),{cancelled:!0}})),i.subscriptions.push(vscode.commands.registerCommand("agentide.chat.answerQuestion",async t=>{const n=t?.streamId,a=t?.questionId;if(!n||!a)return{ok:!1,error:"streamId and questionId are required"};const s=_pendingQuestionsById.get(a);if(!s||s.streamId!==n)return{ok:!1,error:"Question not found or already resolved"};const c=normalizeQuestionAnswer(t?.answer);return resolvePendingQuestion(a,c),{ok:!0}}))}function getUserPermissions(){return{fileAccess:vscode.workspace.getConfiguration("agentide").get("permissions.fileAccess","full")}}function getConfiguredAdditionalEngineDir(){return vscode.workspace.getConfiguration("agentide").get("additionalEngineDir")}function clearCustomEngineRuntimeCache(i,o){const e=i.engines.custom;try{e?.clearInstances?.(o)}catch(p){log(i.outputChannel,`[AgentIDE] Custom engine cache clear warning: ${p instanceof Error?p.message:String(p)}`)}}async function refreshCustomEnginePicker(i){try{await vscode.commands.executeCommand("agentide.engine.refresh")}catch(o){log(i,`[AgentIDE] Custom engine picker refresh warning: ${o instanceof Error?o.message:String(o)}`)}}const _sessionEventWriter=new sessionEvents_1.SessionEventWriter;async function handleChatCommand(i,o){const{outputChannel:e,engines:p,syncService:b,config:f}=i,{engine:N,streamId:t}=o;let{message:n}=o;const a=o.options??{};let s;const c=n.match(/^\[gw:(gw-[^\]]+)\]/);if(c){const $=c[1];n=n.slice(c[0].length),log(e,`[AgentIDE] Gateway request detected, token=${$.slice(0,20)}...`);const{GatewayService:_}=await import("./gateway/service.js");s=_.getGatewayEmitter($),s?log(e,"[AgentIDE] Gateway emitter found, will stream to both Chat UI and Gateway"):log(e,`[AgentIDE] Gateway emitter NOT found for token ${$.slice(0,20)}...`)}const{workspaceRoot:r,additionalDirectories:u,isHomeFallback:d}=getWorkspaceRoot(e,a.workspaceRoot,a.additionalDirectories);t&&d&&await warnHomeFallbackOnce(e,t);const l=await b.getActiveAgentManifest(r,e,b.getActivePackId(r)??i.activePackId),g=l?.spec?.remote?.url?.trim();if(g)return(0,handleRemoteChat_js_1.handleRemoteServeChat)({outputChannel:e,syncService:b,sessionEventWriter:_sessionEventWriter,activeRunsByStreamId:_activeRunsByStreamId,rejectPendingQuestionsForStream,askQuestionViaWorkbenchTool,askQuestionFromChatUI,getServeAuth:async()=>{if(!_extensionContext)return;const $=await(0,provider_js_1.getAgentHippoAccessToken)(_extensionContext);if($)return{accessToken:$.accessToken,userEmail:$.email}},ensureSignedIn:async()=>{if(!_extensionContext)return;const $=await(0,signInFlow_js_1.ensureAgentHippoSignedIn)(_extensionContext);if($)return{accessToken:$.accessToken,userEmail:$.email}},log},{engine:N,message:n,options:o.options,streamId:t,sessionResource:o.sessionResource,requestId:o.requestId,remoteUrl:g,remoteManifest:l,workspaceRoot:r,incomingOptions:a,gatewayEmitter:s});let D={...a,workspaceRoot:r,additionalDirectories:u,agentPackId:i.activePackId};if(!t)return{error:"streamId is required - non-streaming mode is no longer supported"};let v=N,y=p[v];if(!y&&v!=="codex"&&v!=="claude"&&p.custom&&(D={...D,engineId:D.engineId??v},v="custom",y=p.custom,log(e,`[AgentIDE] Routing requested engine "${N}" through custom runtime loader`)),!y){const $=`Unknown engine: ${N}`;return log(e,`[AgentIDE] Error: ${$}`),{error:$}}log(e,`[AgentIDE] Chat request for engine=${N} (runtime=${v}), streamId: ${t}, useLiteLLM: ${D.useLiteLLM||!1}`);const S=new AbortController;_activeRunsByStreamId.set(t,{streamId:t,engine:v,startedAt:Date.now(),abortController:S});const k=(0,utils_1.createIPCStreamEmitter)(t),E=o.sessionResource,w=o.requestId,A={...k,async question($){return E?await askQuestionViaWorkbenchTool(E,w,$,S.signal):await askQuestionFromChatUI(t,$)}},C=s?{...A,async thinking($){await k.thinking($),await s.thinking(`<thinking>${$}</thinking>`)},async text($){await k.text($),await s.text($)},async toolStart($,_,U,x){await k.toolStart($,_,U,x),await s.toolStart($,_,U,x)},async toolEnd($,_,U,x,R){await k.toolEnd($,_,U,x,R),await s.toolEnd($,_,U,x,R)},async progress($){await k.progress($),await s.progress($)},async question($){const _=await A.question($);return await s.progress(`Question answered: ${questionPromptToHeader($.prompt)}`),_},async error($){await k.error($),await s.error($)},async done(){await k.done(),await s.done()}}:A,m=getTerminalLogInfo(D);await appendTerminalAttachmentsToLog(o.context,t,e,m?.uri),await persistImageAttachments(o.context,D,e),await persistFileAndDirectoryAttachments(o.context,D,e);const h=formatSdkContextSuffix(o.context,m?.relativePath),I=h?`${n}
23
+
24
+ ${h}`:n,P=(0,base_1.generateRequestId)(),T=D.sessionId??`ide-${Date.now()}`,M=(0,sessionEvents_1.wrapEmitterWithObservability)(C,_sessionEventWriter,T,P);try{b.incrementActiveAgentTurns(),await b.ensureAgentideProjectPrepared(r,u,e),await b.writeManagedPathsManifest(f.codexHome,f.claudeConfigDir,r,u,e);const $=await b.getActiveAgentManifest(r,e),_=(0,permissions_1.parseManifestPermissions)($),U=getUserPermissions(),x=(0,permissions_1.enforcePermissions)(_,U);log(e,`[AgentIDE] Permissions: manifest(files=${_.fileAccess}) + user(files=${U.fileAccess}) = effective(files=${x.fileAccess})`);const R={...D,sessionId:T,permissions:x,agentPackVersion:$?.metadata?.version,requestId:P},F=new vscode_logger_1.VSCodeLogger(e),G=new permission_handler_1.AutoApprovePermissionHandler,j=vscode.workspace.getConfiguration("agentide").get("cli.path",""),L=await(0,runtime_1.getCliHealth)({configuredPath:j,extensionPath:_extensionContext?.extensionPath}),H=_extensionContext?.globalState?.get(BUNDLED_TOOLS_DIR_KEY),O=(0,runtime_1.buildCliEnvPatch)({cliPath:L.path,workspaceRoot:r,agentId:R.agentPackId??"default",chatSessionId:R.sessionId?.trim()||R.contextSessionId?.trim(),baseEnv:process.env,extensionPath:_extensionContext?.extensionPath,userInstalledToolsDir:H??void 0});O.AGENTHIPPO_TOOLS_DIR&&log(e,`[AgentIDE] Bundled tools dir available for runtime: ${O.AGENTHIPPO_TOOLS_DIR}`);const B={logger:F,editTracker:new vscode_edit_tracker_1.VSCodeEditTracker(new vscode_logger_1.VSCodeLogger(e,"[EditTracker]")),configProvider:new vscode_config_provider_1.VSCodeConfigProvider,permissionHandler:G,cliEnvPatch:O};return L.installed&&L.path?log(e,`[AgentIDE] CLI available for agent runtime: ${L.path}`):log(e,`[AgentIDE] CLI not detected for runtime (skills may rely on '${branding_1.AGENTIDE_CLI_NAME}' on PATH)`),log(e,`[AgentIDE] Analytics: session=${T}, request=${P}, agent=${R.agentPackId??"default"}, version=${R.agentPackVersion??"workspace"}`),await M.emitTurnStart(),await y.stream(I,R,M,B,S.signal),await M.emitTurnEnd(!0),{streaming:!0}}catch($){const _=$ instanceof Error?$.message:String($);return log(e,`[AgentIDE] Error: ${_}`),await M.error(_),await M.emitTurnEnd(!1),{error:_}}finally{rejectPendingQuestionsForStream(t,"Run finished"),_activeRunsByStreamId.delete(t),b.decrementActiveAgentTurns()}}function resolveWorkspaceRootUri(i){const o=vscode.workspace.workspaceFolders??[],e=o.find(b=>b.uri.fsPath===i);if(e)return e.uri;const p=o[0];return p&&i.startsWith("/")?vscode.Uri.from({scheme:p.uri.scheme,authority:p.uri.authority,path:i}):vscode.Uri.file(i)}function dirnameUri(i){const o=i.path.lastIndexOf("/");return o>=0?i.with({path:i.path.slice(0,o)}):i}function getTerminalLogInfo(i){const o=i.contextSessionId?.trim()||i.sessionId?.trim();if(!o)return;const e=resolveWorkspaceRootUri(i.workspaceRoot);return{uri:vscode.Uri.joinPath(e,paths_1.AGENT_CONSTANTS.AGENTIDE_DIR_NAME,paths_1.AGENT_CONSTANTS.SESSIONS_DIR,o,TERMINAL_LOG_FILE_NAME),relativePath:`${AGENTIDE_SESSIONS_DIR_NAME}/${o}/${TERMINAL_LOG_FILE_NAME}`}}function getSessionAttachmentsDirInfo(i){const o=i.contextSessionId?.trim()||i.sessionId?.trim();if(!o)return;const e=resolveWorkspaceRootUri(i.workspaceRoot);return{dirUri:vscode.Uri.joinPath(e,paths_1.AGENT_CONSTANTS.AGENTIDE_DIR_NAME,paths_1.AGENT_CONSTANTS.SESSIONS_DIR,o,ATTACHMENTS_DIR_NAME),relativeDirPath:`${AGENTIDE_SESSIONS_DIR_NAME}/${o}/${ATTACHMENTS_DIR_NAME}`}}function slugifyFileStem(i){return i.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,60)||"attachment"}function imageExtensionFromMimeType(i){switch((i??"").toLowerCase()){case"image/png":return"png";case"image/jpeg":case"image/jpg":return"jpg";case"image/gif":return"gif";case"image/webp":return"webp";default:return"png"}}async function persistImageAttachments(i,o,e){const p=i?.variables??[];if(!i||p.length===0)return;const b=p.filter(t=>t.kind==="image"&&typeof t.dataBase64=="string"&&t.dataBase64.length>0);if(b.length===0)return;const f=getSessionAttachmentsDirInfo(o);if(!f){log(e,"[AgentIDE] Note: image attachment present but no contextSessionId; skipping persistence");return}try{await(0,terminalLogger_1.ensureDirectory)(f.dirUri)}catch(t){log(e,`[AgentIDE] Warning: failed to create session attachments dir: ${t instanceof Error?t.message:String(t)}`);return}let N=0;for(const t of b){N++;const n=slugifyFileStem(t.name||`image-${N}`),a=imageExtensionFromMimeType(t.mimeType),s=b.length>1?`${n}-${N}.${a}`:`${n}.${a}`,c=vscode.Uri.joinPath(f.dirUri,s);try{const r=Buffer.from(t.dataBase64,"base64");await vscode.workspace.fs.writeFile(c,r),t.uri=`${f.relativeDirPath}/${s}`,delete t.dataBase64}catch(r){log(e,`[AgentIDE] Warning: failed to persist image attachment "${t.name}": ${r instanceof Error?r.message:String(r)}`)}}}async function persistFileAndDirectoryAttachments(i,o,e){const p=i?.variables??[];if(!i||p.length===0)return;const b=p.filter(w=>(w.kind==="file"||w.kind==="directory")&&typeof w.uri=="string"&&w.uri.trim().length>0);if(b.length===0)return;const f=getSessionAttachmentsDirInfo(o);if(!f){log(e,"[AgentIDE] Note: file/folder attachment present but no contextSessionId; skipping persistence");return}try{await(0,terminalLogger_1.ensureDirectory)(f.dirUri)}catch(w){log(e,`[AgentIDE] Warning: failed to create session attachments dir: ${w instanceof Error?w.message:String(w)}`);return}const N=vscode.Uri.joinPath(f.dirUri,"manifest.json"),t=async()=>{try{const w=await vscode.workspace.fs.readFile(N),A=JSON.parse(Buffer.from(w).toString("utf8"));if(A&&A.version===1&&typeof A.files=="object"&&typeof A.directories=="object")return A}catch{}return{version:1,files:{},directories:{}}},n=async w=>{try{const A=Buffer.from(JSON.stringify(w,null,2),"utf8");await vscode.workspace.fs.writeFile(N,A)}catch{}},a=await t();let s=!1;const c=500,r=25*1024*1024,u=10*1024*1024;let d=0,l=0;const g=(w,A)=>{try{const C=path.resolve(w),m=path.resolve(A),h=path.relative(C,m);return h===""||!h.startsWith("..")&&!path.isAbsolute(h)}catch{return!1}},D=o.workspaceRoot,v=path.normalize(`${path.sep}${AGENTIDE_SESSIONS_DIR_NAME.split("/").join(path.sep)}${path.sep}`),y=async w=>{try{return await vscode.workspace.fs.stat(w),!0}catch{return!1}},S=async(w,A)=>{let C=A,m=1;for(;await y(vscode.Uri.joinPath(w,C));){m++;const h=path.extname(A);C=`${h?A.slice(0,-h.length):A}-${m}${h}`}return C},k=async(w,A)=>{const C=vscode.Uri.file(w);try{const m=await vscode.workspace.fs.stat(C);if(m.type!==vscode.FileType.File)return;const h=`${w}::${m.size}::${m.mtime}`,I=a.files[h];if(I){const _=vscode.Uri.joinPath(A,I.destName);if(await y(_))return I.destName}const P=path.basename(w),T=await S(A,P||"attachment"),M=vscode.Uri.joinPath(A,T);if(m.size>u){log(e,`[AgentIDE] Note: skipping large file attachment (${m.size} bytes): ${w}`);return}if(d+1>c||l+m.size>r){log(e,"[AgentIDE] Note: skipping additional file attachments due to size limits");return}const $=await vscode.workspace.fs.readFile(C);return await vscode.workspace.fs.writeFile(M,$),d+=1,l+=m.size,a.files[h]={destName:T,sourcePath:w,size:m.size,mtime:m.mtime},s=!0,T}catch(m){log(e,`[AgentIDE] Warning: failed to persist file attachment "${w}": ${m instanceof Error?m.message:String(m)}`);return}},E=async(w,A)=>{const C=await vscode.workspace.fs.readDirectory(w);for(const[m,h]of C){if(d>=c||l>=r)return;const I=vscode.Uri.joinPath(w,m),P=vscode.Uri.joinPath(A,m);if(h===vscode.FileType.Directory)await(0,terminalLogger_1.ensureDirectory)(P),await E(I,P);else if(h===vscode.FileType.File)try{const T=await vscode.workspace.fs.stat(I);if(T.size>u)continue;if(d+1>c||l+T.size>r)return;const M=await vscode.workspace.fs.readFile(I);await vscode.workspace.fs.writeFile(P,M),d+=1,l+=T.size}catch{}}};for(const w of b){const A=w.uri.trim();if(path.isAbsolute(A)&&!(D&&g(D,A))&&!path.normalize(A).includes(v))try{const C=vscode.Uri.file(A),m=await vscode.workspace.fs.stat(C);if(m.type===vscode.FileType.Directory&&w.kind==="directory"){const h=`${A}::${m.mtime}`,I=a.directories[h];if(I){const $=vscode.Uri.joinPath(f.dirUri,I.destName);if(await y($)){w.uri=`${f.relativeDirPath}/${I.destName}`;continue}}const P=path.basename(A)||"folder",T=await S(f.dirUri,P),M=vscode.Uri.joinPath(f.dirUri,T);await(0,terminalLogger_1.ensureDirectory)(M),await E(C,M),a.directories[h]={destName:T,sourcePath:A,mtime:m.mtime},s=!0,w.uri=`${f.relativeDirPath}/${T}`}else if(m.type===vscode.FileType.File&&w.kind==="file"){const h=await k(A,f.dirUri);h&&(w.uri=`${f.relativeDirPath}/${h}`)}}catch{}}s&&await n(a)}async function appendTerminalAttachmentsToLog(i,o,e,p){if(!p)return;const b=i?.variables??[],f=b.filter(t=>t.kind==="terminalCommand"&&typeof t.output=="string"&&t.output.trim().length>0),N=b.filter(t=>t.kind==="generic"&&typeof t.text=="string"&&t.text.trim().length>0&&(t.isTerminalSelection||typeof t.id=="string"&&t.id.startsWith("terminal-selection-")));if(!(f.length===0&&N.length===0))try{await(0,terminalLogger_1.ensureDirectory)(dirnameUri(p));const t=new Date().toISOString(),n=[];n.push(`<!-- TERMINAL_ATTACHMENTS STREAM:${o} TIME:${t} -->`),n.push("");for(const a of f){const s=(a.command??a.name??"").toString().trim();n.push("## Terminal Command"),s&&n.push(`- Command: ${s}`),typeof a.exitCode=="number"&&n.push(`- Exit code: ${a.exitCode}`),a.uri&&n.push(`- Resource: ${a.uri}`),n.push(""),n.push("```text"),n.push(a.output??""),n.push("```"),n.push("")}for(const a of N){const s=a.name||"Terminal Selection";n.push(`## ${s}`),n.push(""),n.push("```text"),n.push(a.text??""),n.push("```"),n.push("")}n.push(`<!-- TERMINAL_ATTACHMENTS_END STREAM:${o} -->`),n.push(""),await(0,terminalLogger_1.appendTextFileWithRotation)(p,n.join(`
25
+ `),MAX_TERMINAL_LOG_BYTES)}catch(t){log(e,`[AgentIDE] Warning: failed to persist terminal attachments for grep: ${t instanceof Error?t.message:String(t)}`)}}function formatSdkContextSuffix(i,o){if(!i)return"";const e=[];if(i.selection?.text&&i.selection.text.trim()){const f=[];if(i.selection.uri&&f.push(`**File:** \`${i.selection.uri}\``),i.selection.range){const t=i.selection.range;f.push(`**Range:** ${t.startLineNumber}:${t.startColumn}-${t.endLineNumber}:${t.endColumn}`)}e.push("## Currently Selected Code"),f.length&&(e.push(f.join(`
26
+ `)),e.push(""));const N=(i.selection.languageId??"").trim();e.push(`\`\`\`${N}`),e.push(i.selection.text),e.push("```")}const p=i.variables??[];if(p.length){e.push("## Attached Context");for(const f of p)switch(f.kind){case"terminalCommand":{const N=f.command?.trim()||f.name;if(e.push("### Terminal"),e.push(`**Command:** \`${N}\``),f.uri&&e.push(`**Resource:** \`${f.uri}\``),typeof f.exitCode=="number"&&e.push(`**Exit code:** ${f.exitCode}`),o)e.push(`**Output:** saved to \`${o}\` (use \`rg\`/ \`grep\`)`);else if(f.output&&f.output.trim()){const t=f.output.length>2e3?`\u2026(truncated)
27
+ ${f.output.slice(-2e3)}`:f.output;e.push(""),e.push("```text"),e.push(t),e.push("```")}e.push("");break}case"paste":{const N=(f.language??"").trim(),t=f.name||"Paste";e.push(`### ${t}`),f.code&&f.code.trim()&&(e.push(`\`\`\`${N}`),e.push(f.code),e.push("```")),e.push("");break}case"file":case"directory":case"promptFile":{const N=f.uri??f.name;e.push(`- **${f.kind}**: \`${N}\``);break}case"image":case"notebookOutput":{const N=f.uri??f.name,t=f.mimeType?` (${f.mimeType})`:"";e.push(`- **${f.kind}**: \`${N}\`${t}`);break}case"implicit":{if(f.isSelection){const N=f.uri??f.name;e.push(`- **selection reference**: \`${N}\``)}else f.uri&&e.push(`- **reference**: \`${f.uri}\``);break}case"generic":{const N=f.name||"Context",t=!!f.isTerminalSelection||typeof f.id=="string"&&f.id.startsWith("terminal-selection-");if(e.push(`### ${N}`),t&&f.text&&f.text.trim()){if(o)e.push(`**Content:** saved to \`${o}\` (use \`rg\`/\`grep\`)`);else{const a=f.text.length>2e3?`\u2026(truncated)
28
+ ${f.text.slice(-2e3)}`:f.text;e.push("```text"),e.push(a),e.push("```")}const n=f.name?.match(/Terminal Selection \((.+)\)/);if(n){const a=n[1],s=(0,terminalLogger_1.terminalNameToSlug)(a);e.push(`**Full terminal history:** \`${paths_1.AGENT_CONSTANTS.AGENTIDE_DIR_NAME}/terminals/${s}.md\``)}else e.push(`**All terminal logs:** \`${paths_1.AGENT_CONSTANTS.AGENTIDE_DIR_NAME}/terminals/\``)}else f.text&&f.text.trim()?(e.push("```text"),e.push(f.text),e.push("```")):f.uri&&e.push(`**Resource:** \`${f.uri}\``);e.push("");break}default:{const N=f.uri??f.name;e.push(`- **${f.kind}**: ${N}`);break}}}const b=e.join(`
29
+ `).trim();return b?b+`
30
+ `:""}function getBundledBasePromptsDir(){if(_extensionContext)return path.join(_extensionContext.extensionPath,"base-prompts")}async function registerBundledMcpServers(i,o){const e=getBundledBasePromptsDir();if(!e){log(o,"[AgentIDE] Cannot register MCP servers: base-prompts dir not found");return}try{const p=await(0,mcp_1.loadBundledMcpServers)(e);if(p.length===0){log(o,"[AgentIDE] No bundled MCP servers found");return}const b=vscode.lm.registerMcpServerDefinitionProvider("bundled-mcp-servers",{provideMcpServerDefinitions:async()=>p.map(f=>new vscode.McpStdioServerDefinition(f.label,f.command,f.args,f.env??{}))});i.subscriptions.push(b),log(o,`[AgentIDE] Registered ${p.length} bundled MCP server(s) with VS Code: ${p.map(f=>f.name).join(", ")}`)}catch(p){log(o,`[AgentIDE] Warning: failed to register MCP servers: ${p instanceof Error?p.message:String(p)}`)}}async function refreshAgentideProject(i){const{outputChannel:o,syncService:e,config:p}=i,{workspaceRoot:b,additionalDirectories:f,isHomeFallback:N}=getWorkspaceRoot(o);if(!N)try{await e.ensureAgentideProjectPrepared(b,f,o),await e.writeManagedPathsManifest(p.codexHome,p.claudeConfigDir,b,f,o),log(o,"[AgentIDE] Project sync complete")}catch(t){log(o,`[AgentIDE] Warning: failed to refresh project sync: ${t instanceof Error?t.message:String(t)}`)}}function getFallbackDirectoryPath(){const o=vscode.workspace.getConfiguration("agentide").get("fallbackDirectory")||".agent-hippo";return path.join(os.homedir(),o)}function getWorkspaceRoot(i,o,e){const p=vscode.workspace.workspaceFolders,b=(0,workspaceFolders_1.getWorkspaceFolderFsPaths)(),f=o?.trim();if(f){const t=e??b.filter(n=>n!==f);return p&&p.length>1?log(i,`[AgentIDE] Multi-root workspace (${p.length} folders). Primary: ${f}, Additional: ${t.length}`):log(i,`[AgentIDE] Using explicit workspaceRoot=${f}`),{workspaceRoot:f,additionalDirectories:t,isHomeFallback:!1}}if(p&&p.length>0){const t=p[0].uri.fsPath,n=b.slice(1);return p.length>1?log(i,`[AgentIDE] Multi-root workspace (${p.length} folders). Primary: ${t}, Additional: ${n.length}`):log(i,`[AgentIDE] Using workspace folder: ${t}`),{workspaceRoot:t,additionalDirectories:n,isHomeFallback:!1}}const N=getFallbackDirectoryPath();return log(i,`[AgentIDE] No workspace open, using fallback directory: ${N}`),{workspaceRoot:N,additionalDirectories:[],isHomeFallback:!0}}async function ensureFallbackDirectoryExists(i){const o=getFallbackDirectoryPath();try{if(!await(0,utils_1.pathExists)(o)){await fs_1.promises.mkdir(o,{recursive:!0}),log(i,`[AgentIDE] Created fallback directory: ${o}`);try{const{execFile:p}=await import("child_process"),{promisify:b}=await import("util");await b(p)("git",["init"],{cwd:o}),log(i,"[AgentIDE] Initialized git in fallback directory");const N=path.join(o,".gitignore"),t=`# ${branding_1.AGENTIDE_BRAND_NAME} fallback workspace
4439
31
  ${paths_1.AGENT_CONSTANTS.AGENTIDE_DIR_NAME}/${paths_1.AGENT_CONSTANTS.SESSIONS_DIR}/
4440
32
  *.log
4441
- `;
4442
- await fs_1.promises.writeFile(gitignorePath, gitignoreContent, "utf8");
4443
- // Create a README
4444
- const readmePath = path.join(fallbackDir, "README.md");
4445
- const readmeContent = `# My ${branding_1.AGENTIDE_BRAND_NAME} Workspace
33
+ `;await fs_1.promises.writeFile(N,t,"utf8");const n=path.join(o,"README.md"),a=`# My ${branding_1.AGENTIDE_BRAND_NAME} Workspace
4446
34
 
4447
35
  This is the default ${branding_1.AGENTIDE_BRAND_NAME} workspace, created automatically when no folder is open.
4448
36
 
@@ -4451,33 +39,4 @@ This is the default ${branding_1.AGENTIDE_BRAND_NAME} workspace, created automat
4451
39
  Files created here:
4452
40
  - Agent-generated files when no workspace is open
4453
41
  - Temporary experiments
4454
- `;
4455
- await fs_1.promises.writeFile(readmePath, readmeContent, "utf8");
4456
- }
4457
- catch (gitError) {
4458
- // Git init failed - that's okay, directory still exists
4459
- log(outputChannel, `[AgentIDE] Note: Could not initialize git in fallback directory: ${gitError instanceof Error ? gitError.message : String(gitError)}`);
4460
- }
4461
- }
4462
- }
4463
- catch (error) {
4464
- log(outputChannel, `[AgentIDE] Warning: Failed to ensure fallback directory: ${error instanceof Error ? error.message : String(error)}`);
4465
- }
4466
- return fallbackDir;
4467
- }
4468
- let _hasWarnedHomeFallbackInThisSession = false;
4469
- async function warnHomeFallbackOnce(outputChannel, streamId) {
4470
- if (_hasWarnedHomeFallbackInThisSession) {
4471
- return;
4472
- }
4473
- _hasWarnedHomeFallbackInThisSession = true;
4474
- // Ensure fallback directory exists with git init
4475
- const fallbackDir = await ensureFallbackDirectoryExists(outputChannel);
4476
- const msg = `No folder is open. Running agent tools in: ${fallbackDir}`;
4477
- log(outputChannel, `[AgentIDE] ${msg}`);
4478
- void vscode.commands.executeCommand("agentide.streamCallback", {
4479
- streamId,
4480
- type: "progress",
4481
- data: msg,
4482
- });
4483
- }
42
+ `;await fs_1.promises.writeFile(n,a,"utf8")}catch(p){log(i,`[AgentIDE] Note: Could not initialize git in fallback directory: ${p instanceof Error?p.message:String(p)}`)}}}catch(e){log(i,`[AgentIDE] Warning: Failed to ensure fallback directory: ${e instanceof Error?e.message:String(e)}`)}return o}let _hasWarnedHomeFallbackInThisSession=!1;async function warnHomeFallbackOnce(i,o){if(_hasWarnedHomeFallbackInThisSession)return;_hasWarnedHomeFallbackInThisSession=!0;const p=`No folder is open. Running agent tools in: ${await ensureFallbackDirectoryExists(i)}`;log(i,`[AgentIDE] ${p}`),vscode.commands.executeCommand("agentide.streamCallback",{streamId:o,type:"progress",data:p})}