@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
@@ -1,854 +0,0 @@
1
- "use strict";
2
- /*---------------------------------------------------------------------------------------------
3
- * Deploy Init Test Suite (serve-v3 §A4)
4
- *
5
- * Verifies the generator emits well-formed artifacts for every target:
6
- * YAML/JSON parse, Dockerfile shape, shell scripts pass `bash -n`, and the
7
- * .env.example scan reflects the pack's ${env:...} references.
8
- *--------------------------------------------------------------------------------------------*/
9
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- var desc = Object.getOwnPropertyDescriptor(m, k);
12
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
13
- desc = { enumerable: true, get: function() { return m[k]; } };
14
- }
15
- Object.defineProperty(o, k2, desc);
16
- }) : (function(o, m, k, k2) {
17
- if (k2 === undefined) k2 = k;
18
- o[k2] = m[k];
19
- }));
20
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
21
- Object.defineProperty(o, "default", { enumerable: true, value: v });
22
- }) : function(o, v) {
23
- o["default"] = v;
24
- });
25
- var __importStar = (this && this.__importStar) || (function () {
26
- var ownKeys = function(o) {
27
- ownKeys = Object.getOwnPropertyNames || function (o) {
28
- var ar = [];
29
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
30
- return ar;
31
- };
32
- return ownKeys(o);
33
- };
34
- return function (mod) {
35
- if (mod && mod.__esModule) return mod;
36
- var result = {};
37
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
38
- __setModuleDefault(result, mod);
39
- return result;
40
- };
41
- })();
42
- Object.defineProperty(exports, "__esModule", { value: true });
43
- require("mocha");
44
- const assert = __importStar(require("assert"));
45
- const fs = __importStar(require("fs"));
46
- const os = __importStar(require("os"));
47
- const path = __importStar(require("path"));
48
- const child_process_1 = require("child_process");
49
- const yaml = __importStar(require("js-yaml"));
50
- const deploy_init_1 = require("../cli/deploy-init");
51
- const deploy_1 = require("../cli/commands/deploy");
52
- const idp_init_1 = require("../cli/idp-init");
53
- const CTX = {
54
- packName: 'databricks-analyst',
55
- packVersion: '0.1.0',
56
- image: 'ghcr.io/agenthippo/runtime:2026.06',
57
- port: 8080,
58
- engine: 'claude',
59
- envVars: ['DATABRICKS_HOST', 'DATABRICKS_HTTP_PATH'],
60
- publicHostname: deploy_init_1.DEPLOY_PUBLIC_HOSTNAME,
61
- };
62
- suite('deploy-init: target registry', () => {
63
- test('isDeployTarget recognizes known and rejects unknown', () => {
64
- for (const t of deploy_init_1.DEPLOY_TARGETS) {
65
- assert.ok((0, deploy_init_1.isDeployTarget)(t));
66
- }
67
- assert.strictEqual((0, deploy_init_1.isDeployTarget)('heroku'), false);
68
- assert.strictEqual((0, deploy_init_1.isDeployTarget)('all'), false); // handled separately by the command
69
- });
70
- });
71
- suite('deploy-init: scanEnvRefs', () => {
72
- let dir;
73
- setup(() => {
74
- dir = fs.mkdtempSync(path.join(os.tmpdir(), 'ah-scan-'));
75
- });
76
- teardown(() => {
77
- fs.rmSync(dir, { recursive: true, force: true });
78
- });
79
- test('collects ${env:VAR} across files, de-dupes and sorts', () => {
80
- fs.mkdirSync(path.join(dir, 'mcp'), { recursive: true });
81
- fs.writeFileSync(path.join(dir, 'mcp', 'databricks.mcp.json'), JSON.stringify({ env: { H: '${env:DATABRICKS_HOST}', T: '${env:DATABRICKS_TOKEN}' } }));
82
- fs.writeFileSync(path.join(dir, 'agent.yaml'), 'x: ${env:DATABRICKS_HOST}\n'); // dup
83
- assert.deepStrictEqual((0, deploy_init_1.scanEnvRefs)(dir), ['DATABRICKS_HOST', 'DATABRICKS_TOKEN']);
84
- });
85
- test('skips node_modules / deploy / .git', () => {
86
- fs.mkdirSync(path.join(dir, 'node_modules'), { recursive: true });
87
- fs.writeFileSync(path.join(dir, 'node_modules', 'x.json'), '${env:SHOULD_NOT_APPEAR}');
88
- fs.mkdirSync(path.join(dir, 'deploy'), { recursive: true });
89
- fs.writeFileSync(path.join(dir, 'deploy', 'y.json'), '${env:ALSO_NOT}');
90
- fs.writeFileSync(path.join(dir, 'agent.yaml'), 'name: ${env:REAL_ONE}');
91
- assert.deepStrictEqual((0, deploy_init_1.scanEnvRefs)(dir), ['REAL_ONE']);
92
- });
93
- test('empty pack → no vars', () => {
94
- fs.writeFileSync(path.join(dir, 'agent.yaml'), 'metadata:\n name: x\n');
95
- assert.deepStrictEqual((0, deploy_init_1.scanEnvRefs)(dir), []);
96
- });
97
- });
98
- suite('deploy-init: renderEnvExample', () => {
99
- test('lists scanned vars and model credential', () => {
100
- const out = (0, deploy_init_1.renderEnvExample)(['FOO', 'BAR']);
101
- assert.ok(!out.includes('AGENTHIPPO_SERVE_API_KEY='), 'serve bearer key must not appear — auth is the deploy layer');
102
- assert.ok(out.includes('ANTHROPIC_API_KEY='));
103
- assert.ok(out.includes('FOO='));
104
- assert.ok(out.includes('BAR='));
105
- });
106
- test('edge .env keeps only the public hostname; auth secrets live in .env.auth', () => {
107
- const out = (0, deploy_init_1.renderEnvExample)([], { edge: true });
108
- assert.ok(out.includes(`AGENTHIPPO_PUBLIC_HOSTNAME=${deploy_init_1.DEPLOY_PUBLIC_HOSTNAME}`));
109
- // The agent loads .env — the token-signing key and OAuth secrets must not be here.
110
- assert.ok(!out.includes('AGENTHIPPO_AUTH_JWT_SECRET'), 'JWT secret must not be in the agent-shared .env');
111
- assert.ok(!out.includes('OAUTH2_PROXY_CLIENT_SECRET'), 'OAuth secret must not be in the agent-shared .env');
112
- assert.ok(out.includes('.env.auth'), 'edge .env should point operators at .env.auth');
113
- });
114
- test('renderAuthEnvExample carries the oauth2-proxy + JWT secrets', () => {
115
- const out = (0, deploy_init_1.renderAuthEnvExample)();
116
- assert.ok(out.includes('OAUTH2_PROXY_CLIENT_ID='));
117
- assert.ok(out.includes('OAUTH2_PROXY_REDIRECT_URL='));
118
- assert.ok(out.includes('OAUTH2_PROXY_REVERSE_PROXY=true'));
119
- assert.ok(out.includes('AGENTHIPPO_AUTH_JWT_SECRET='));
120
- assert.ok(out.includes('AGENTHIPPO_AUTH_DEV=0'), 'AUTH_DEV must default off in generated auth env');
121
- });
122
- test('renderAuthEnvExample honors custom hostname', () => {
123
- const out = (0, deploy_init_1.renderAuthEnvExample)({ hostname: 'agents.example.com' });
124
- assert.ok(out.includes('https://agents.example.com/oauth2/callback'));
125
- assert.ok(!out.includes('auth.agenthippo.ai'));
126
- });
127
- test('vm target embeds custom hostname in cloudflared and README', () => {
128
- const files = (0, deploy_init_1.renderTarget)('vm', { ...CTX, publicHostname: 'agents.example.com' });
129
- assert.ok(files['cloudflared.yml'].includes('agents.example.com'));
130
- assert.ok(files['README.md'].includes('https://agents.example.com'));
131
- assert.ok(files['run-edge-tunnel.sh'].includes('https://agents.example.com'));
132
- });
133
- test('cursor engine seeds CURSOR_API_KEY instead of ANTHROPIC', () => {
134
- const out = (0, deploy_init_1.renderEnvExample)([], { engine: 'cursor' });
135
- assert.ok(out.includes('CURSOR_API_KEY='));
136
- assert.ok(!out.includes('ANTHROPIC_API_KEY='));
137
- });
138
- test('serveCmdArgs includes custom engine and model', () => {
139
- const args = (0, deploy_init_1.serveCmdArgs)({ ...CTX, engine: 'cursor', model: 'auto', image: 'x', envVars: [] });
140
- assert.ok(args.includes('--engine'));
141
- assert.ok(args.includes('cursor'));
142
- assert.ok(args.includes('--model'));
143
- assert.ok(args.includes('auto'));
144
- assert.ok(!args.includes('--host'), 'bind address is set via AGENTHIPPO_SERVE_HOST in Dockerfile, not --host');
145
- });
146
- test('serveCmdArgs can include www-dir for cloudrun browser UI', () => {
147
- const args = (0, deploy_init_1.serveCmdArgs)({ ...CTX, image: 'x', envVars: [] }, { wwwDir: '/app/pack/deploy/www' });
148
- assert.ok(args.includes('--www-dir'));
149
- assert.ok(args.includes('/app/pack/deploy/www'));
150
- });
151
- test('defaultRuntimeImage picks cursor layer for cursor engine', () => {
152
- assert.ok((0, deploy_init_1.defaultRuntimeImage)('cursor').includes('cursor'));
153
- assert.ok(!(0, deploy_init_1.defaultRuntimeImage)('claude').includes('cursor'));
154
- });
155
- });
156
- suite('deploy-init: renderTarget produces well-formed artifacts', () => {
157
- test('every target includes a scanned .env.example with the pack vars', () => {
158
- for (const t of deploy_init_1.DEPLOY_TARGETS) {
159
- const files = (0, deploy_init_1.renderTarget)(t, CTX);
160
- assert.ok(files['.env.example'], `${t} missing .env.example`);
161
- assert.ok(files['.env.example'].includes('DATABRICKS_HOST'), `${t} .env.example missing scanned var`);
162
- assert.ok(files['README.md'], `${t} missing README.md`);
163
- }
164
- });
165
- test('every target ships a DATA-ACCESS.md summary (governance layer)', () => {
166
- for (const t of deploy_init_1.DEPLOY_TARGETS) {
167
- const files = (0, deploy_init_1.renderTarget)(t, CTX);
168
- const doc = files['DATA-ACCESS.md'];
169
- assert.ok(doc, `${t} missing DATA-ACCESS.md`);
170
- assert.ok(doc.includes('## Secrets') && doc.includes('## Egress') && doc.includes('## Blast radius per component'), `${t} DATA-ACCESS.md missing a required section`);
171
- assert.ok(doc.includes('api.anthropic.com:443'), `${t} DATA-ACCESS.md must name the model API host`);
172
- }
173
- });
174
- test('DATA-ACCESS.md lists auth secrets + oauth2-proxy blast radius only for self-issued edge targets', () => {
175
- const selfIssued = (0, deploy_init_1.renderTarget)('vm', CTX)['DATA-ACCESS.md'];
176
- assert.ok(selfIssued.includes('AGENTHIPPO_AUTH_JWT_SECRET'));
177
- assert.ok(selfIssued.includes('OAUTH2_PROXY_CLIENT_SECRET'));
178
- assert.ok(selfIssued.includes('**oauth2-proxy**'));
179
- const federated = (0, deploy_init_1.renderTarget)('vm', { ...CTX, ingress: 'edge-fed', idpUrl: 'https://auth.corp.example' })['DATA-ACCESS.md'];
180
- assert.ok(federated.includes('AGENTHIPPO_AUTH_JWT_SECRET'));
181
- assert.ok(!federated.includes('OAUTH2_PROXY_CLIENT_SECRET'), 'federated deployments mint no Google OAuth client');
182
- assert.ok(!federated.includes('**oauth2-proxy**'), 'federated deployments run no oauth2-proxy');
183
- const noEdge = (0, deploy_init_1.renderTarget)('databricks-app', CTX)['DATA-ACCESS.md'];
184
- assert.ok(!noEdge.includes('AGENTHIPPO_AUTH_JWT_SECRET'), 'platform-native targets mint no JWT secret');
185
- });
186
- test('image-based targets emit pack provenance header and OCI labels', () => {
187
- const marker = 'Generated from Agent Pack databricks-analyst@0.1.0 — packs.agenthippo.ai';
188
- for (const t of ['vm', 'compose', 'cloudrun', 'spcs', 'cloudflare']) {
189
- const files = (0, deploy_init_1.renderTarget)(t, CTX);
190
- const df = files['Dockerfile'];
191
- assert.ok(df.includes(marker), `${t} Dockerfile missing attribution`);
192
- assert.ok(df.includes('LABEL ai.agenthippo.pack.name="databricks-analyst"'), `${t} missing pack.name label`);
193
- assert.ok(df.includes('LABEL ai.agenthippo.pack.version="0.1.0"'), `${t} missing pack.version label`);
194
- assert.ok(df.includes('LABEL ai.agenthippo.pack.engine="claude"'), `${t} missing pack.engine label`);
195
- assert.ok(files['.env.example'].includes(marker), `${t} .env.example missing attribution`);
196
- assert.ok(files['README.md'].includes(marker), `${t} README missing attribution`);
197
- }
198
- const vmRun = (0, deploy_init_1.renderTarget)('vm', CTX)['run.sh'];
199
- assert.ok(vmRun.startsWith('#!'), 'run.sh keeps shebang first');
200
- assert.ok(vmRun.includes(`# ${marker}`), 'run.sh attributes after shebang');
201
- });
202
- test('image-based targets emit a valid 5-line-style Dockerfile referencing the runtime image', () => {
203
- for (const t of ['vm', 'compose', 'cloudrun', 'spcs', 'cloudflare']) {
204
- const df = (0, deploy_init_1.renderTarget)(t, CTX)['Dockerfile'];
205
- assert.ok(df, `${t} missing Dockerfile`);
206
- assert.ok(df.includes('FROM ghcr.io/agenthippo/runtime:2026.06'), `${t} Dockerfile missing FROM`);
207
- assert.ok(df.includes('COPY . /app/pack/'), `${t} Dockerfile missing COPY`);
208
- assert.ok(/EXPOSE 8080/.test(df), `${t} Dockerfile missing EXPOSE`);
209
- assert.ok(df.includes('CMD ["serve"'), `${t} Dockerfile CMD must append to runtime ENTRYPOINT`);
210
- assert.ok(!df.includes('CMD ["agenthippo"'), `${t} Dockerfile must not duplicate agenthippo in CMD`);
211
- assert.ok(df.includes('ENV AGENTHIPPO_SERVE_HOST=0.0.0.0'), `${t} Dockerfile must bind on all interfaces in-container`);
212
- assert.ok(!df.includes('"--host"'), `${t} Dockerfile must not pass unsupported --host to older runtimes`);
213
- }
214
- });
215
- test('image-based targets ship a .dockerignore that keeps skills and drops node_modules', () => {
216
- for (const t of ['vm', 'compose', 'cloudrun', 'spcs', 'cloudflare']) {
217
- const di = (0, deploy_init_1.renderTarget)(t, CTX)['.dockerignore'];
218
- assert.ok(di, `${t} missing .dockerignore`);
219
- assert.ok(di.includes('**/node_modules'), `${t} .dockerignore should exclude node_modules`);
220
- assert.ok(di.includes('.git'), `${t} .dockerignore should exclude .git`);
221
- // Ship only deploy/www/ from deploy/ (drops deploy/.env, credentials, build artifacts).
222
- assert.ok(di.includes('deploy/*'), `${t} should exclude deploy/*`);
223
- assert.ok(di.includes('!deploy/www/**'), `${t} should re-include deploy/www/**`);
224
- // Defensive secret ignores — any-extension credentials + common private-key formats,
225
- // not just *credentials*.json (see isSecretLikeBasename in deploy-init.ts).
226
- assert.ok(di.includes('**/.env'), `${t} should ignore **/.env`);
227
- assert.ok(di.includes('**/*credentials*'), `${t} should ignore credentials of any extension`);
228
- assert.ok(di.includes('**/*.pem'), `${t} should ignore .pem files`);
229
- assert.ok(di.includes('**/*.key'), `${t} should ignore .key files`);
230
- assert.ok(di.includes('**/id_rsa'), `${t} should ignore id_rsa`);
231
- // skills/, scripts/, references/ must NOT be ignored lines.
232
- const ignored = di.split('\n').map((l) => l.trim()).filter((l) => l && !l.startsWith('#'));
233
- for (const keep of ['skills/', 'scripts/', 'references/', 'skills', 'scripts', 'references']) {
234
- assert.ok(!ignored.includes(keep), `${t} .dockerignore must not ignore ${keep}`);
235
- }
236
- }
237
- // Source-based target ships no Dockerfile and no .dockerignore.
238
- assert.strictEqual((0, deploy_init_1.renderTarget)('databricks-app', CTX)['.dockerignore'], undefined);
239
- assert.strictEqual((0, deploy_init_1.renderTarget)('databricks-app', CTX)['Dockerfile'], undefined);
240
- });
241
- test('build scripts anchor to the staging root so they run from any cwd', () => {
242
- // cloudrun + vm run.sh use `docker build -f deploy/Dockerfile .` → must cd to staging root.
243
- assert.ok((0, deploy_init_1.renderTarget)('cloudrun', CTX)['cloudrun-deploy.sh'].includes('cd "$(dirname "$0")/.."'), 'cloudrun-deploy.sh must anchor to staging root');
244
- assert.ok((0, deploy_init_1.renderTarget)('vm', CTX)['run.sh'].includes('cd "$(dirname "$0")/.."'), 'vm run.sh must anchor to staging root');
245
- // edge tunnel uses docker compose (paths resolve relative to the compose file), so it
246
- // anchors to deploy/ itself, not the staging root.
247
- assert.ok((0, deploy_init_1.renderTarget)('vm', CTX)['run-edge-tunnel.sh'].includes('cd "$(dirname "$0")"'));
248
- assert.ok(!(0, deploy_init_1.renderTarget)('vm', CTX)['run-edge-tunnel.sh'].includes('cd "$(dirname "$0")/.."'));
249
- });
250
- test('image-based Dockerfiles install skill requirements.txt/package.json deps at build time', () => {
251
- for (const t of ['vm', 'compose', 'cloudrun', 'spcs', 'cloudflare']) {
252
- const df = (0, deploy_init_1.renderTarget)(t, CTX)['Dockerfile'];
253
- assert.ok(df.includes('requirements.txt'), `${t} Dockerfile should install python skill deps`);
254
- assert.ok(df.includes('package.json'), `${t} Dockerfile should install node skill deps`);
255
- assert.ok(df.includes('USER root') && df.includes('USER agent'), `${t} skill-deps step must run as root then drop back to agent`);
256
- // Must not clobber the runtime ENTRYPOINT/CMD.
257
- assert.ok(df.includes('CMD ["serve"'), `${t} CMD still present after skill-deps step`);
258
- }
259
- });
260
- test('databricks-app is source-based (no Dockerfile) with OBO scopes', () => {
261
- const files = (0, deploy_init_1.renderTarget)('databricks-app', CTX);
262
- assert.strictEqual(files['Dockerfile'], undefined);
263
- const app = yaml.load(files['app.yaml']);
264
- assert.deepStrictEqual(app.user_authorization?.scopes, ['sql']);
265
- const pkg = JSON.parse(files['package.json']);
266
- assert.ok(pkg.dependencies['@anthropic-ai/claude-code']);
267
- assert.ok(pkg.dependencies['@agenthippo-ai/agenthippo']);
268
- });
269
- test('YAML artifacts parse', () => {
270
- assert.doesNotThrow(() => yaml.load((0, deploy_init_1.renderTarget)('vm', CTX)['docker-compose.yml']));
271
- assert.doesNotThrow(() => yaml.load((0, deploy_init_1.renderTarget)('compose', CTX)['docker-compose.yml']));
272
- assert.doesNotThrow(() => yaml.load((0, deploy_init_1.renderTarget)('spcs', CTX)['spec.yaml']));
273
- assert.doesNotThrow(() => yaml.load((0, deploy_init_1.renderTarget)('databricks-app', CTX)['app.yaml']));
274
- });
275
- test('JSON artifacts parse (wrangler, package.json)', () => {
276
- assert.doesNotThrow(() => JSON.parse((0, deploy_init_1.renderTarget)('cloudflare', CTX)['wrangler.jsonc']));
277
- assert.doesNotThrow(() => JSON.parse((0, deploy_init_1.renderTarget)('databricks-app', CTX)['package.json']));
278
- });
279
- test('shell scripts are syntactically valid (bash -n)', () => {
280
- const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'ah-sh-'));
281
- try {
282
- const scripts = [
283
- ['run.sh', (0, deploy_init_1.renderTarget)('vm', CTX)['run.sh']],
284
- ['run-edge-tunnel.sh', (0, deploy_init_1.renderTarget)('vm', CTX)['run-edge-tunnel.sh']],
285
- ['cloudrun-deploy.sh', (0, deploy_init_1.renderTarget)('cloudrun', CTX)['cloudrun-deploy.sh']],
286
- ['cloudrun-edge-deploy.sh', (0, deploy_init_1.renderTarget)('cloudrun', { ...CTX, ingress: 'edge' })['cloudrun-deploy.sh']],
287
- ];
288
- for (const [name, content] of scripts) {
289
- const p = path.join(tmp, name);
290
- fs.writeFileSync(p, content);
291
- assert.doesNotThrow(() => (0, child_process_1.execFileSync)('bash', ['-n', p]), `${name} failed bash -n`);
292
- }
293
- }
294
- finally {
295
- fs.rmSync(tmp, { recursive: true, force: true });
296
- }
297
- });
298
- test('cloudrun IAP is applied on the beta track with IAM bindings (no GA --iap on deploy)', () => {
299
- const sh = (0, deploy_init_1.renderTarget)('cloudrun', CTX)['cloudrun-deploy.sh'];
300
- assert.ok(sh.includes('--iap'), 'IAP enablement still referenced');
301
- // Beta track: gcloud beta run services update --iap (GA `gcloud run ... --iap` is unsupported).
302
- assert.ok(sh.includes('gcloud beta run services update'), 'IAP must be enabled on the beta track');
303
- // Public access is governed by the run.invoker binding, stripped here; IAP role granted per IAP_MEMBERS.
304
- assert.ok(sh.includes('remove-iam-policy-binding'), 'must strip allUsers invoker binding to keep service private');
305
- assert.ok(sh.includes('roles/iap.httpsResourceAccessor'), 'must grant IAP-secured Web User role');
306
- assert.ok(sh.includes('IAP_MEMBERS'), 'must surface IAP_MEMBERS for per-principal grants');
307
- // The old GA `services update --no-allow-unauthenticated` (not a real flag) and inline IAP_FLAG are gone.
308
- assert.ok(!sh.includes('IAP_FLAG'), 'IAP_FLAG array removed in favor of the beta-track block');
309
- assert.ok(!sh.includes('--no-allow-unauthenticated "${IAP_FLAG[@]}"'), 'old GA IAP update line removed');
310
- assert.ok(!sh.includes('AGENTHIPPO_SERVE_API_KEY'), 'serve bearer key must not appear — auth is IAP');
311
- assert.ok(sh.includes('docker build'));
312
- assert.ok(sh.includes('deploy/Dockerfile'));
313
- });
314
- test('cloudrun --ingress edge (Option B) fronts the agent with the AgentHippo edge, no IAP', () => {
315
- const files = (0, deploy_init_1.renderTarget)('cloudrun', { ...CTX, ingress: 'edge' });
316
- const svc = files['service.yaml'];
317
- const caddy = files['Caddyfile'];
318
- const sh = files['cloudrun-deploy.sh'];
319
- // Edge artifacts present; IAP artifacts absent.
320
- assert.ok(caddy, 'Caddyfile present');
321
- assert.ok(svc.includes('name: caddy') && svc.includes('name: auth-broker') && svc.includes('name: oauth2-proxy'));
322
- assert.ok(svc.includes('name: agent') && svc.includes('name: litellm') && svc.includes('name: otel-collector'), 'Spotlight sidecars still present behind the edge');
323
- // Caddy is the ONLY ingress (one port); the agent is no longer ingress.
324
- assert.strictEqual((svc.match(/containerPort:/g) || []).length, 1);
325
- assert.ok(/- name: caddy\n image: caddy:/.test(svc), 'caddy is the first/ingress container');
326
- // Agent listens on the internal edge port (not $PORT), so it doesn't clash with Caddy.
327
- assert.ok(svc.includes('"--port", "8090"'), 'agent args override the port to the internal edge port');
328
- assert.ok(svc.includes('"--www-dir", "/app/pack/deploy/www"'), 'agent still serves the www landing page');
329
- // Sidecars share the pod's localhost (Cloud Run multi-container), not docker-DNS names.
330
- assert.ok(!caddy.includes('oauth2-proxy:4180') && !caddy.includes('auth-broker:9780') && !caddy.includes('agent:8080'), 'edge Caddyfile must use localhost upstreams, not docker-DNS names');
331
- assert.ok(caddy.includes('localhost:4180') && caddy.includes('localhost:9780') && caddy.includes('localhost:8090'), 'edge Caddyfile routes to oauth2-proxy / auth-broker / agent on localhost');
332
- assert.ok(caddy.includes(':{$PORT}') && caddy.includes('auto_https off'), 'Caddy listens on HTTP :$PORT (Cloud Run terminates TLS)');
333
- // IDE PKCE authorize must be SSO-gated before the catch-all /oauth/* → broker route.
334
- assert.ok(caddy.includes('handle /oauth/authorize {'), 'edge Caddyfile gates /oauth/authorize');
335
- assert.ok(/handle \/oauth\/authorize \{[\s\S]*?forward_auth localhost:4180[\s\S]*?copy_headers X-Auth-Request-Email/.test(caddy), '/oauth/authorize forward_auth copies X-Auth-Request-Email via localhost oauth2-proxy');
336
- assert.ok(caddy.indexOf('handle /oauth/authorize {') < caddy.indexOf('handle /oauth/* {'), '/oauth/authorize must precede the catch-all /oauth/* handle');
337
- assert.ok(caddy.includes('handle /oauth/browser-login {'), 'edge Caddyfile gates /oauth/browser-login');
338
- // Caddyfile is mounted from a Secret (the deploy script upserts it).
339
- assert.ok(svc.includes('${SERVICE}-caddyfile'), 'Caddyfile mounted from a secret');
340
- // auth-broker reuses the agent image (CLI ships `auth-broker`).
341
- assert.ok(/- name: auth-broker\n image: \$\{IMAGE\}/.test(svc) && svc.includes('args: ["auth-broker"]'), 'auth-broker reuses the agent image with `auth-broker` args');
342
- // No IAP anywhere in the edge path.
343
- assert.ok(!sh.includes('--iap') && !sh.includes('iap.httpsResourceAccessor') && !sh.includes('IAP_MEMBERS'), 'edge deploy must not enable IAP');
344
- // Cloud Run is public (allUsers invoker) so traffic can reach Caddy to be authed.
345
- assert.ok(sh.includes('add-iam-policy-binding') && sh.includes('allUsers') && sh.includes('roles/run.invoker'), 'edge deploy grants allUsers invoker (Caddy is the gate, not Cloud Run)');
346
- // Edge secrets upserted.
347
- assert.ok(sh.includes('${SERVICE}-caddyfile') && sh.includes('${SERVICE}-auth-jwt-secret')
348
- && sh.includes('${SERVICE}-oauth-client-id') && sh.includes('${SERVICE}-oauth-cookie-secret'), 'edge deploy upserts Caddyfile + JWT + OAuth secrets');
349
- // Render includes the edge placeholders.
350
- assert.ok(sh.includes('${PUBLIC_HOSTNAME}') && sh.includes('${ALLOWED_DOMAINS}'), 'deploy renders edge hostname/domain placeholders');
351
- // The edge split auth env is shipped (so the agent container never loads the JWT/OAuth secrets).
352
- assert.ok(files['.env.auth.example'], 'edge ships .env.auth.example (split auth secrets)');
353
- assert.ok(files['.env.auth.example'].includes('OAUTH2_PROXY_CLIENT_ID') && files['.env.auth.example'].includes('AGENTHIPPO_AUTH_JWT_SECRET'));
354
- // Note: service.yaml is a sed-template (${SERVICE}/${IMAGE}/${PUBLIC_HOSTNAME}/…), so it is
355
- // only valid YAML after the deploy script substitutes placeholders — same as the IAP template.
356
- assert.ok(files['README.md'].includes('**Egress:**'), 'edge README documents the egress allowlist');
357
- });
358
- test('cloudrun --ingress edge-fed --model-routing gateway drops LiteLLM/OTEL — agent calls gateway.agenthippo.ai', () => {
359
- const files = (0, deploy_init_1.renderTarget)('cloudrun', {
360
- ...CTX, ingress: 'edge-fed', modelRouting: 'gateway', model: 'ah-auto',
361
- idpUrl: 'https://auth.agenthippo.ai', cookieDomain: '.agenthippo.ai',
362
- });
363
- const svc = files['service.yaml'];
364
- const sh = files['cloudrun-deploy.sh'];
365
- assert.ok(svc.includes('name: caddy') && svc.includes('name: auth-broker') && svc.includes('name: agent'));
366
- assert.ok(!svc.includes('name: litellm') && !svc.includes('name: otel-collector'), 'no Spotlight sidecars');
367
- assert.ok(svc.includes('https://gateway.agenthippo.ai/v1'), 'agent points at org gateway');
368
- assert.ok(!svc.includes('http://localhost:4443'), 'agent must not route through in-pod LiteLLM');
369
- assert.ok(!files['otel-collector.yaml'], 'no otel config artifact');
370
- assert.ok(!sh.includes('LITELLM_KEY') && !sh.includes('otel-config'), 'deploy skips litellm/otel secrets');
371
- assert.ok(sh.includes('${SERVICE}-provider-key'), 'gateway key stored as provider-key secret');
372
- assert.ok(files['.env.example'].includes('AGENTHIPPO_LITELLM_BASE_URL=https://gateway.agenthippo.ai/v1'));
373
- assert.doesNotThrow(() => (0, child_process_1.execFileSync)('bash', ['-n', '-c', sh]));
374
- const rendered = svc
375
- .replace(/\$\{SERVICE\}/g, 'emoji-gateway')
376
- .replace(/\$\{IMAGE\}/g, 'us-docker.pkg.dev/x/y/z:latest')
377
- .replace(/\$\{PUBLIC_HOSTNAME\}/g, 'emoji.agenthippo.ai')
378
- .replace(/\$\{ALLOWED_DOMAINS\}/g, 'agenthippo.ai');
379
- assert.doesNotThrow(() => yaml.load(rendered), 'rendered gateway-direct service.yaml is valid YAML');
380
- });
381
- test('cloudrun --ingress edge-fed (A′) verifies the shared JWT — no oauth2-proxy, no per-service OAuth', () => {
382
- const files = (0, deploy_init_1.renderTarget)('cloudrun', {
383
- ...CTX, ingress: 'edge-fed', idpUrl: 'https://auth.agenthippo.ai', cookieDomain: '.agenthippo.ai',
384
- });
385
- const svc = files['service.yaml'];
386
- const caddy = files['Caddyfile'];
387
- const sh = files['cloudrun-deploy.sh'];
388
- // Federated artifacts present.
389
- assert.ok(caddy && svc && sh);
390
- // Caddy + auth-broker + agent + Spotlight sidecars, but NO oauth2-proxy container.
391
- assert.ok(svc.includes('name: caddy') && svc.includes('name: auth-broker') && svc.includes('name: agent'));
392
- assert.ok(svc.includes('name: litellm') && svc.includes('name: otel-collector'), 'Spotlight sidecars present');
393
- assert.ok(!svc.includes('name: oauth2-proxy'), 'edge-fed must NOT ship an oauth2-proxy container');
394
- assert.strictEqual((svc.match(/containerPort:/g) || []).length, 1, 'Caddy is the only ingress port');
395
- // auth-broker carries the federated cookie/IdP config + the shared JWT secret.
396
- assert.ok(svc.includes('AGENTHIPPO_AUTH_COOKIE_DOMAIN') && svc.includes('AGENTHIPPO_AUTH_IDP_URL'), 'auth-broker gets the federated cookie domain + IdP URL');
397
- assert.ok(svc.includes('${SERVICE}-auth-jwt-secret'), 'shared JWT secret mounted from a secret');
398
- assert.ok(svc.includes('AGENTHIPPO_AUTH_COOKIE_NAME'), 'cookie name configured');
399
- // In-memory state (no GCS bucket → no STATE_BUCKET requirement, no gcsfuse).
400
- assert.ok(svc.includes('emptyDir') && svc.includes('medium: Memory'), 'state is in-memory emptyDir');
401
- assert.ok(!svc.includes('gcsfuse') && !svc.includes('${STATE_BUCKET}'), 'no GCS state volume');
402
- // Caddyfile: forward_auth to auth-broker only; no oauth2-proxy routes; IdP browser-login redirect.
403
- assert.ok(caddy.includes('forward_auth localhost:9780'), 'Caddy verifies via auth-broker');
404
- assert.ok(!caddy.includes('localhost:4180') && !caddy.includes('/oauth2/'), 'no oauth2-proxy routes in Caddyfile');
405
- assert.ok(caddy.includes('https://auth.agenthippo.ai/oauth/browser-login'), 'browser 401 redirects to the central IdP browser-login endpoint');
406
- assert.ok(caddy.includes('return_to='), 'redirect carries a return_to for the round trip');
407
- // Deploy script: NO OAuth client/cookie secrets; upserts caddyfile + JWT + provider/litellm;
408
- // allUsers invoker; domain-mappings create; no IAP; no STATE_BUCKET.
409
- assert.ok(!sh.includes('OAUTH_CLIENT_ID') && !sh.includes('OAUTH_CLIENT_SECRET') && !sh.includes('OAUTH_COOKIE_SECRET'), 'edge-fed deploy must not reference any Google OAuth client');
410
- assert.ok(sh.includes('${SERVICE}-caddyfile') && sh.includes('${SERVICE}-auth-jwt-secret')
411
- && sh.includes('${SERVICE}-provider-key') && sh.includes('${SERVICE}-litellm-key'), 'edge-fed deploy upserts caddyfile + shared JWT + provider/litellm secrets');
412
- assert.ok(!sh.includes('STATE_BUCKET'), 'edge-fed has no STATE_BUCKET (in-memory state)');
413
- assert.ok(sh.includes('allUsers') && sh.includes('roles/run.invoker'), 'allUsers invoker (Caddy is the gate)');
414
- assert.ok(sh.includes('domain-mappings create'), 'maps the *.agenthippo.ai subdomain');
415
- assert.ok(!sh.includes('--iap') && !sh.includes('iap.httpsResourceAccessor'), 'no IAP');
416
- // Split auth env is federated: shared JWT secret + cookie domain + IdP URL, NO Google OAuth client.
417
- const auth = files['.env.auth.example'];
418
- assert.ok(auth, 'edge-fed ships .env.auth.example');
419
- assert.ok(auth.includes('AGENTHIPPO_AUTH_JWT_SECRET') && auth.includes('AGENTHIPPO_AUTH_COOKIE_DOMAIN')
420
- && auth.includes('AGENTHIPPO_AUTH_IDP_URL'), 'federated auth env carries the shared JWT + cookie/IdP config');
421
- assert.ok(!auth.includes('OAUTH2_PROXY_CLIENT_ID'), 'federated auth env has no Google OAuth client');
422
- // Shell + rendered YAML are well-formed.
423
- assert.doesNotThrow(() => (0, child_process_1.execFileSync)('bash', ['-n', '-c', sh]));
424
- const rendered = svc
425
- .replace(/\$\{SERVICE\}/g, 'customer-service-edge')
426
- .replace(/\$\{IMAGE\}/g, 'us-docker.pkg.dev/x/y/z:latest')
427
- .replace(/\$\{LITELLM_IMAGE\}/g, 'ghcr.io/agenthippo/litellm-gateway:2026.06')
428
- .replace(/\$\{PUBLIC_HOSTNAME\}/g, 'cs.agenthippo.ai')
429
- .replace(/\$\{ALLOWED_DOMAINS\}/g, 'agenthippo.ai');
430
- assert.doesNotThrow(() => yaml.load(rendered), 'rendered service.yaml is valid YAML');
431
- assert.ok(files['README.md'].includes('**Egress:**'), 'edge-fed README documents the egress allowlist');
432
- });
433
- test('renderAuthEnvExample fed variant has no Google OAuth client', () => {
434
- const out = (0, deploy_init_1.renderAuthEnvExample)({ hostname: 'cs.agenthippo.ai', fed: true, idpUrl: 'https://auth.agenthippo.ai', cookieDomain: '.agenthippo.ai' });
435
- assert.ok(out.includes('AGENTHIPPO_AUTH_JWT_SECRET'));
436
- assert.ok(out.includes('AGENTHIPPO_AUTH_COOKIE_DOMAIN=.agenthippo.ai'));
437
- assert.ok(out.includes('AGENTHIPPO_AUTH_IDP_URL=https://auth.agenthippo.ai'));
438
- assert.ok(!out.includes('OAUTH2_PROXY_CLIENT_ID'));
439
- });
440
- test('cloudrun claude pack ships the Spotlight multi-container stack (litellm + otel sidecars)', () => {
441
- const files = (0, deploy_init_1.renderTarget)('cloudrun', CTX); // CTX engine = claude → model-routed → Spotlight
442
- const svc = files['service.yaml'];
443
- assert.ok(svc, 'service.yaml present');
444
- assert.ok(svc.includes('name: agent') && svc.includes('name: litellm') && svc.includes('name: otel-collector'));
445
- // Agent routes through the in-pod LiteLLM; LiteLLM exports to the in-pod collector.
446
- assert.ok(svc.includes('http://localhost:4443'), 'agent → litellm on localhost');
447
- assert.ok(svc.includes('http://localhost:4318'), 'litellm → collector on localhost');
448
- assert.ok(svc.includes('gcsfuse.run.googleapis.com'), 'GCS-backed /state volume');
449
- assert.ok(files['otel-collector.yaml'].includes('file/jsonl'), 'collector writes JSONL traces');
450
- // Exactly one container exposes a port (Cloud Run ingress requirement).
451
- assert.strictEqual((svc.match(/containerPort:/g) || []).length, 1);
452
- // The CLAUDE_CODE_USE_VERTEX-vs-LiteLLM contradiction is gone from the active deploy.
453
- assert.ok(!svc.includes('CLAUDE_CODE_USE_VERTEX'));
454
- assert.ok(!files['cloudrun-deploy.sh'].includes('CLAUDE_CODE_USE_VERTEX'));
455
- });
456
- test('cloudrun cursor pack wires CURSOR_API_KEY secret and engine flags', () => {
457
- const ctx = { ...CTX, packName: 'customer-service', engine: 'cursor', model: 'auto', image: 'ghcr.io/agenthippo/runtime:latest-cursor' };
458
- const sh = (0, deploy_init_1.renderTarget)('cloudrun', ctx)['cloudrun-deploy.sh'];
459
- const df = (0, deploy_init_1.renderTarget)('cloudrun', ctx)['Dockerfile'];
460
- assert.ok(sh.includes('CURSOR_API_KEY=agenthippo-cursor-key:latest'));
461
- assert.ok(sh.includes('AGENTHIPPO_CUSTOM_ENGINES_DIR=/engines'));
462
- assert.ok(df.includes('"--engine","cursor"'));
463
- assert.ok(df.includes('"--model","auto"'));
464
- assert.ok(df.includes('runtime:latest-cursor'));
465
- assert.ok(df.includes('"--www-dir","/app/pack/deploy/www"'));
466
- assert.ok((0, deploy_init_1.renderTarget)('cloudrun', ctx)['www/index.html'].includes('<h1>customer-service</h1>'));
467
- const env = (0, deploy_init_1.renderTarget)('cloudrun', ctx)['.env.example'];
468
- assert.ok(env.includes('CURSOR_API_KEY='));
469
- });
470
- test('cloudrun IAP paths pin AGENTHIPPO_IDENTITY_HEADER so X-Agent-User cannot spoof identity', () => {
471
- // Claude/codex → Spotlight multi-container path (renderCloudrunServiceYaml).
472
- const spotlight = (0, deploy_init_1.renderTarget)('cloudrun', CTX);
473
- assert.ok(spotlight['service.yaml'].includes('AGENTHIPPO_IDENTITY_HEADER'), 'Spotlight service.yaml must declare AGENTHIPPO_IDENTITY_HEADER');
474
- assert.ok(spotlight['cloudrun-deploy.sh'].includes('x-goog-authenticated-user-email'), 'Spotlight deploy script must fill the pin with the IAP header when ENABLE_IAP=1');
475
- // Cursor → T1-generic single-container path.
476
- const cursorCtx = { ...CTX, engine: 'cursor', model: 'auto', image: 'ghcr.io/agenthippo/runtime:latest-cursor' };
477
- const generic = (0, deploy_init_1.renderTarget)('cloudrun', cursorCtx);
478
- assert.ok(generic['cloudrun-deploy.sh'].includes('AGENTHIPPO_IDENTITY_HEADER=x-goog-authenticated-user-email'), 'T1-generic deploy script must pin AGENTHIPPO_IDENTITY_HEADER to the IAP header');
479
- // Both must skip the pin when ENABLE_IAP=0 (IAP never sets the header then — pinning
480
- // unconditionally would make every request resolve to anonymous during bootstrap).
481
- assert.ok(spotlight['cloudrun-deploy.sh'].includes('ENABLE_IAP'), 'Spotlight pin must be ENABLE_IAP-conditional');
482
- assert.ok(generic['cloudrun-deploy.sh'].includes('IDENTITY_ENV='), 'T1-generic pin must be ENABLE_IAP-conditional');
483
- });
484
- test('databricks-app pins AGENTHIPPO_IDENTITY_HEADER to x-forwarded-email', () => {
485
- const start = (0, deploy_init_1.renderTarget)('databricks-app', CTX)['start.js'];
486
- assert.ok(start.includes("AGENTHIPPO_IDENTITY_HEADER: 'x-forwarded-email'"), 'Databricks App start.js must pin identity to the workspace SSO header');
487
- // Bootstrap escape hatch (analogous to Cloud Run ENABLE_IAP=0).
488
- assert.ok(start.includes("AGENTHIPPO_PIN_IDENTITY === '0'"), 'Databricks pin must be skippable via AGENTHIPPO_PIN_IDENTITY=0');
489
- });
490
- test('spcs egress is limited to the model API via one EAI', () => {
491
- const sql = (0, deploy_init_1.renderTarget)('spcs', CTX)['deploy.sql'];
492
- assert.ok(sql.includes('api.anthropic.com:443'));
493
- assert.ok(/EXTERNAL ACCESS INTEGRATION/.test(sql));
494
- });
495
- test('aws-ecs bare (no ingress) is a single-container task with no edge opinion', () => {
496
- const files = (0, deploy_init_1.renderTarget)('aws-ecs', CTX);
497
- assert.ok(!files['Caddyfile'], 'bare aws-ecs ships no Caddy');
498
- assert.ok(!files['.env.auth.example'], 'bare aws-ecs has no local auth secrets');
499
- const task = JSON.parse(files['task-definition.json']);
500
- assert.strictEqual(task.networkMode, 'awsvpc');
501
- assert.deepStrictEqual(task.requiresCompatibilities, ['FARGATE']);
502
- assert.strictEqual(task.containerDefinitions.length, 1, 'exactly one container: the agent');
503
- assert.strictEqual(task.containerDefinitions[0].name, 'agent');
504
- assert.doesNotThrow(() => (0, child_process_1.execFileSync)('bash', ['-n', '-c', files['deploy.sh']]));
505
- });
506
- test('aws-ecs --ingress edge reuses the Cloud Run edge Caddyfile verbatim (shared sidecar identity layer)', () => {
507
- const files = (0, deploy_init_1.renderTarget)('aws-ecs', { ...CTX, ingress: 'edge' });
508
- const task = JSON.parse(files['task-definition.json']);
509
- const names = task.containerDefinitions.map((c) => c.name);
510
- assert.deepStrictEqual(names, ['caddy', 'oauth2-proxy', 'auth-broker', 'agent']);
511
- assert.strictEqual(task.networkMode, 'awsvpc', 'one task, containers share localhost — same shape as Cloud Run sidecars');
512
- assert.ok(files['Caddyfile'].includes('localhost:4180') && files['Caddyfile'].includes('localhost:9780'), 'localhost addressing (awsvpc shared network), not docker-DNS names');
513
- assert.ok(files['.env.auth.example'].includes('OAUTH2_PROXY_CLIENT_ID'));
514
- assert.doesNotThrow(() => (0, child_process_1.execFileSync)('bash', ['-n', '-c', files['deploy.sh']]));
515
- });
516
- test('aws-ecs --ingress edge-fed drops oauth2-proxy from the task and Caddyfile', () => {
517
- const files = (0, deploy_init_1.renderTarget)('aws-ecs', { ...CTX, ingress: 'edge-fed', idpUrl: 'https://auth.corp.example' });
518
- const task = JSON.parse(files['task-definition.json']);
519
- const names = task.containerDefinitions.map((c) => c.name);
520
- assert.deepStrictEqual(names, ['caddy', 'auth-broker', 'agent']);
521
- assert.ok(!files['Caddyfile'].includes('localhost:4180'), 'no oauth2-proxy upstream in a federated Caddyfile');
522
- assert.ok(files['Caddyfile'].includes('forward_auth localhost:9780'), 'verifies via auth-broker');
523
- assert.ok(files['Caddyfile'].includes('https://auth.corp.example/oauth/browser-login'));
524
- assert.ok(!files['.env.auth.example'].includes('OAUTH2_PROXY_CLIENT_ID'));
525
- assert.doesNotThrow(() => (0, child_process_1.execFileSync)('bash', ['-n', '-c', files['deploy.sh']]));
526
- });
527
- test('azure-container-apps bare (no ingress) is a single-container app with no edge opinion', () => {
528
- const files = (0, deploy_init_1.renderTarget)('azure-container-apps', CTX);
529
- assert.ok(!files['Caddyfile'], 'bare azure-container-apps ships no Caddy');
530
- assert.ok(!files['.env.auth.example'], 'bare azure-container-apps has no local auth secrets');
531
- const spec = JSON.parse(files['containerapp.json']);
532
- assert.strictEqual(spec.properties.template.containers.length, 1, 'exactly one container: the agent');
533
- assert.strictEqual(spec.properties.template.containers[0].name, 'agent');
534
- assert.strictEqual(spec.properties.configuration.ingress.external, true);
535
- assert.doesNotThrow(() => (0, child_process_1.execFileSync)('bash', ['-n', '-c', files['deploy.sh']]));
536
- });
537
- test('azure-container-apps --ingress edge reuses the Cloud Run edge Caddyfile verbatim (shared sidecar identity layer)', () => {
538
- const files = (0, deploy_init_1.renderTarget)('azure-container-apps', { ...CTX, ingress: 'edge' });
539
- const spec = JSON.parse(files['containerapp.json']);
540
- const names = spec.properties.template.containers.map((c) => c.name);
541
- assert.deepStrictEqual(names, ['caddy', 'oauth2-proxy', 'auth-broker', 'agent']);
542
- assert.ok(files['Caddyfile'].includes('localhost:4180') && files['Caddyfile'].includes('localhost:9780'), 'localhost addressing (containers in one replica share it), not docker-DNS names');
543
- assert.ok(files['.env.auth.example'].includes('OAUTH2_PROXY_CLIENT_ID'));
544
- assert.doesNotThrow(() => (0, child_process_1.execFileSync)('bash', ['-n', '-c', files['deploy.sh']]));
545
- });
546
- test('azure-container-apps --ingress edge-fed drops oauth2-proxy from the spec and Caddyfile', () => {
547
- const files = (0, deploy_init_1.renderTarget)('azure-container-apps', { ...CTX, ingress: 'edge-fed', idpUrl: 'https://auth.corp.example' });
548
- const spec = JSON.parse(files['containerapp.json']);
549
- const names = spec.properties.template.containers.map((c) => c.name);
550
- assert.deepStrictEqual(names, ['caddy', 'auth-broker', 'agent']);
551
- assert.ok(!files['Caddyfile'].includes('localhost:4180'), 'no oauth2-proxy upstream in a federated Caddyfile');
552
- assert.ok(files['Caddyfile'].includes('forward_auth localhost:9780'), 'verifies via auth-broker');
553
- assert.ok(files['Caddyfile'].includes('https://auth.corp.example/oauth/browser-login'));
554
- assert.ok(!files['.env.auth.example'].includes('OAUTH2_PROXY_CLIENT_ID'));
555
- assert.doesNotThrow(() => (0, child_process_1.execFileSync)('bash', ['-n', '-c', files['deploy.sh']]));
556
- });
557
- // Governance (PLAN/deploy.md §6): every target must document what it can reach outbound —
558
- // spcs enforces it via a network rule (tested above); every other target must at least name
559
- // the host in its README so a security review doesn't have to reverse-engineer it.
560
- test('every non-spcs target documents its egress allowlist in README', () => {
561
- for (const target of deploy_init_1.DEPLOY_TARGETS) {
562
- if (target === 'spcs') {
563
- continue;
564
- }
565
- const readme = (0, deploy_init_1.renderTarget)(target, CTX)['README.md'];
566
- assert.ok(readme?.includes('**Egress:**'), `${target} README must document its egress allowlist`);
567
- assert.ok(readme.includes('api.anthropic.com:443'), `${target} README must name the model API host`);
568
- }
569
- });
570
- // Governance (PLAN/deploy.md §6): a container that might ever be reached directly (bypassing
571
- // its fronting proxy/Worker) must pin AGENTHIPPO_IDENTITY_HEADER so it can't be spoofed by an
572
- // unauthenticated caller naming themselves via the same header name serve otherwise trusts as
573
- // an unpinned alias. iap/databricks-app are covered by their own tests above; cloudflare here.
574
- test('cloudflare pins AGENTHIPPO_IDENTITY_HEADER so a directly-reached container cannot be spoofed', () => {
575
- const files = (0, deploy_init_1.renderTarget)('cloudflare', CTX);
576
- assert.ok(files['Dockerfile'].includes('ENV AGENTHIPPO_IDENTITY_HEADER=x-agent-user'), 'cloudflare Dockerfile must pin identity to the header its own Worker sets');
577
- assert.ok(files['README.md'].includes('Identity pin'), 'README must document the pin for whoever wires the Worker');
578
- });
579
- test('vm target includes edge compose profile; agent has no SSO-bypass host port', () => {
580
- const files = (0, deploy_init_1.renderTarget)('vm', CTX);
581
- const compose = files['docker-compose.yml'];
582
- assert.ok(compose.includes('profiles: ["edge"]'));
583
- assert.ok(compose.includes('profiles: ["tunnel"]'));
584
- assert.ok(compose.includes('cloudflared:'));
585
- assert.ok(compose.includes('oauth2-proxy'));
586
- assert.ok(compose.includes('caddy:'));
587
- assert.ok(!compose.includes('127.0.0.1:8080:8080'), 'agent must not publish host port in compose (SSO bypass)');
588
- assert.ok(compose.includes('OAUTH2_PROXY_REVERSE_PROXY'));
589
- assert.ok(compose.includes('./www:/srv/www'));
590
- assert.ok(files['run.sh'].includes('127.0.0.1:8080'));
591
- assert.ok(files['run-edge-tunnel.sh'].includes('--profile edge --profile tunnel'));
592
- assert.ok(files['Caddyfile'].includes('lb_policy header X-Agent-User'));
593
- assert.ok(files['Caddyfile'].includes('reverse_proxy agent:8080'));
594
- assert.ok(files['Caddyfile'].includes('{$AGENTHIPPO_PUBLIC_HOSTNAME}'));
595
- assert.ok(files['Caddyfile'].includes('@health path /health /ready'));
596
- assert.ok(!files['Caddyfile'].includes('@api path /v1/* /health /ready'));
597
- // IDE PKCE authorize must be SSO-gated (oauth2-proxy → X-Auth-Request-Email), not dumped via /oauth/*.
598
- const caddy = files['Caddyfile'];
599
- assert.ok(caddy.includes('handle /oauth/authorize {'), 'Caddyfile gates /oauth/authorize');
600
- assert.ok(/handle \/oauth\/authorize \{[\s\S]*?forward_auth oauth2-proxy:4180[\s\S]*?copy_headers X-Auth-Request-Email/.test(caddy), '/oauth/authorize forward_auth copies X-Auth-Request-Email');
601
- assert.ok(caddy.indexOf('handle /oauth/authorize {') < caddy.indexOf('handle /oauth/* {'), '/oauth/authorize must precede the catch-all /oauth/* handle');
602
- assert.ok(caddy.includes('handle /oauth/browser-login {'), 'Caddyfile gates /oauth/browser-login');
603
- assert.ok(files['www/index.html'].includes('<form id="chat">'));
604
- // In-compose config-file tunnel (the proven-live path): cloudflared container → caddy:80.
605
- assert.ok(files['cloudflared.yml'].includes('http://caddy:80'), 'in-compose cloudflared reaches Caddy on the docker network');
606
- assert.ok(!files['cloudflared.yml'].includes('http://127.0.0.1:80'), 'a container cannot reach Caddy via 127.0.0.1');
607
- assert.ok(!files['cloudflared.yml'].includes('localhost:8080'));
608
- assert.ok(compose.includes('tunnel --config /etc/cloudflared/config.yml run'), 'config-file mode');
609
- assert.ok(compose.includes('./cloudflared.yml:/etc/cloudflared/config.yml'), 'mounts the routing config');
610
- assert.ok(compose.includes('./tunnel-credentials.json:/etc/cloudflared/credentials.json'), 'mounts the creds');
611
- assert.ok(!compose.includes('TUNNEL_TOKEN'), 'config-file mode does not use a token');
612
- assert.ok(files['agenthippo-edge.service'].includes('--profile tunnel'));
613
- assert.ok(files['.env.auth.example'].includes('OAUTH2_PROXY_CLIENT_ID'));
614
- assert.ok(!files['.env.example'].includes('OAUTH2_PROXY_CLIENT_SECRET'), 'OAuth secret lives in .env.auth, not the agent-shared .env');
615
- assert.ok(files['.env.example'].includes('tunnel-credentials.json'), 'edge env documents the creds file, not a token');
616
- assert.ok(!files['.env.example'].includes('CLOUDFLARE_TUNNEL_TOKEN'), 'token mode removed');
617
- assert.ok(files['.env.example'].includes(`AGENTHIPPO_PUBLIC_HOSTNAME=${deploy_init_1.DEPLOY_PUBLIC_HOSTNAME}`));
618
- });
619
- test('compose target includes edge profile and Caddyfile', () => {
620
- const files = (0, deploy_init_1.renderTarget)('compose', CTX);
621
- assert.ok(files['docker-compose.yml'].includes('profiles: ["edge"]'));
622
- assert.ok(files['Caddyfile']);
623
- assert.ok(files['.env.auth.example'].includes('OAUTH2_PROXY_PROVIDER'));
624
- });
625
- for (const target of ['vm', 'compose']) {
626
- test(`${target} --ingress edge-fed verifies the shared JWT — no oauth2-proxy, no per-agent OAuth`, () => {
627
- const fedCtx = {
628
- ...CTX, ingress: 'edge-fed', idpUrl: 'https://auth.corp.example', cookieDomain: '.corp.example',
629
- };
630
- const files = (0, deploy_init_1.renderTarget)(target, fedCtx);
631
- const compose = files['docker-compose.yml'];
632
- const caddy = files['Caddyfile'];
633
- const auth = files['.env.auth.example'];
634
- assert.ok(!/^\s*oauth2-proxy:/m.test(compose), `${target} edge-fed must not ship an oauth2-proxy container`);
635
- assert.ok(compose.includes('depends_on: [agent, auth-broker]'), 'caddy no longer depends on oauth2-proxy');
636
- assert.ok(!caddy.includes('oauth2-proxy:4180') && !caddy.includes('/oauth2/*'), 'no oauth2-proxy routes in a federated Caddyfile');
637
- assert.ok(caddy.includes('forward_auth auth-broker:9780'), 'Caddy verifies via auth-broker');
638
- assert.ok(caddy.includes('https://auth.corp.example/oauth/browser-login'), 'browser 401 redirects to the central IdP browser-login endpoint');
639
- assert.ok(caddy.includes('return_to='), 'redirect carries a return_to for the round trip');
640
- // Target-specific behavior (sticky lb / static file split) must survive federation —
641
- // identity mode and deployment shape are independent axes.
642
- assert.ok(caddy.includes('lb_policy header X-Agent-User'), 'sticky agent proxy unaffected by identity mode');
643
- assert.ok(caddy.includes('root * /srv/www'), 'static file serving unaffected by identity mode');
644
- assert.ok(auth.includes('AGENTHIPPO_AUTH_JWT_SECRET') && auth.includes('AGENTHIPPO_AUTH_IDP_URL'));
645
- assert.ok(!auth.includes('OAUTH2_PROXY_CLIENT_ID'), 'federated auth env has no Google OAuth client');
646
- });
647
- }
648
- for (const target of ['vm', 'compose']) {
649
- test(`${target} --ingress edge-fed --colocate ships only the agent — no Caddy/oauth2-proxy/auth-broker`, () => {
650
- const colocateCtx = {
651
- ...CTX, ingress: 'edge-fed', idpUrl: 'https://auth.corp.example', colocate: true,
652
- };
653
- const files = (0, deploy_init_1.renderTarget)(target, colocateCtx);
654
- const compose = files['docker-compose.yml'];
655
- const snippet = files['agent-route.caddy'];
656
- assert.ok(!files['Caddyfile'], `${target} colocate must not ship its own Caddyfile`);
657
- assert.ok(!files['.env.auth.example'], `${target} colocate must not ship any local auth secrets`);
658
- assert.ok(!/^\s*(caddy|oauth2-proxy|auth-broker):/m.test(compose), `${target} colocate compose must contain only the agent service`);
659
- assert.ok(compose.includes('container_name: databricks-analyst-agent'), 'fixed, predictable container name');
660
- assert.ok(compose.includes('networks: [colocate]') && compose.includes('external: true'), 'agent joins the IdP\'s external colocate network');
661
- assert.ok(!compose.includes('ports:'), 'no host port — reached only via the IdP\'s Caddy, over the shared network');
662
- assert.ok(snippet, 'route snippet generated for the operator to drop onto the IdP host');
663
- // http:// (not https://) — must match the IdP Caddyfile's TLS model: auto_https is
664
- // off there and TLS terminates in front, so an imported https:// block wouldn't
665
- // match plaintext traffic forwarded from the front proxy.
666
- assert.ok(snippet.includes(`http://${CTX.publicHostname} {`), 'snippet is a plain-HTTP site block, matching the IdP\'s own');
667
- assert.ok(!snippet.includes(`https://${CTX.publicHostname}`), 'must not use https:// — the IdP Caddyfile has auto_https off');
668
- assert.ok(snippet.includes('reverse_proxy databricks-analyst-agent:8080'), 'snippet proxies to the fixed container name');
669
- assert.ok(snippet.includes('forward_auth auth-broker:9780'), 'identity is verified via the IdP\'s own auth-broker');
670
- assert.ok(!snippet.includes('oauth2-proxy'), 'no oauth2-proxy — federated identity only');
671
- assert.ok(snippet.includes('https://auth.corp.example/oauth/browser-login'), 'unauthenticated browsers redirect to the IdP');
672
- const dataAccess = files['DATA-ACCESS.md'];
673
- assert.ok(!dataAccess.includes('AGENTHIPPO_AUTH_JWT_SECRET'), 'colocated agent holds no JWT secret of its own');
674
- assert.ok(!dataAccess.includes('**oauth2-proxy**'), 'colocated agent runs no oauth2-proxy');
675
- assert.ok(files['www/index.html'], 'colocated agent ships browser landing page at GET /');
676
- assert.ok(files['Dockerfile'].includes('--www-dir'), 'serve enables static chat UI after SSO');
677
- });
678
- }
679
- test('colocate + edgeTurnConnector emits the P1 edge turn-registration block (obo-inprogress §2)', () => {
680
- const ctx = {
681
- ...CTX, ingress: 'edge-fed', idpUrl: 'https://auth.corp.example', colocate: true,
682
- edgeTurnConnector: 'databricks-analyst-connector:9091',
683
- };
684
- const snippet = (0, deploy_init_1.renderTarget)('vm', ctx)['agent-route.caddy'];
685
- // Hygiene: a client-supplied nonce header must never pass through.
686
- assert.ok(snippet.includes('request_header -X-Agent-Turn-Nonce'), 'inbound X-Agent-Turn-Nonce is stripped at the edge');
687
- // Only POST chat turns register.
688
- assert.ok(snippet.includes('@turnStart'), 'chat-turn matcher present');
689
- assert.ok(/@turnStart\s*\{\s*\n\s*method POST\s*\n\s*path \/v1\/chat \/v1\/chat\/stream/m.test(snippet), '@turnStart matches POST /v1/chat and /v1/chat/stream only');
690
- // The registration hop itself: forward_auth to the connector control API, nonce copied
691
- // onto the proxied request, register token from the EDGE stack env (never the agent).
692
- assert.ok(snippet.includes('forward_auth @turnStart databricks-analyst-connector:9091'), 'turn registration targets the connector control API');
693
- assert.ok(snippet.includes('uri /edge/turn'), 'registration path is /edge/turn');
694
- assert.ok(snippet.includes('copy_headers X-Agent-Turn-Nonce'), 'minted nonce copied onto the request');
695
- assert.ok(snippet.includes('header_up Authorization "Bearer {$DATABRICKS_ANALYST_DATA_PLANE_TOKEN}"'), 'register token comes from the derived edge-stack env var');
696
- // Ordering (the Caddy footgun the hand-built overlay documents): two forward_auth in one
697
- // handle do NOT run in source order unless wrapped in route {} — identity must run first
698
- // so X-Agent-User exists when the sidecar mints the nonce.
699
- assert.ok(snippet.includes('route {'), 'gated sequence wrapped in route {} to force source order');
700
- const apiBlock = snippet.slice(snippet.indexOf('handle @apiWithAuth'));
701
- const identityIdx = apiBlock.indexOf('forward_auth auth-broker:9780');
702
- const turnIdx = apiBlock.indexOf('forward_auth @turnStart');
703
- const proxyIdx = apiBlock.indexOf('reverse_proxy databricks-analyst-agent:8080');
704
- assert.ok(identityIdx >= 0 && turnIdx > identityIdx && proxyIdx > turnIdx, 'order inside route {}: identity → turn registration → proxy');
705
- // Both gated paths carry the hop: Bearer API clients AND cookie-auth browser clients.
706
- assert.strictEqual(snippet.split('uri /edge/turn').length - 1, 2, 'turn registration on both the @apiWithAuth and browser catch-all paths');
707
- // The operator README says where the token goes (IdP stack env, never the agent).
708
- const readme = (0, deploy_init_1.renderTarget)('vm', ctx)['README.md'];
709
- assert.ok(readme.includes('DATABRICKS_ANALYST_DATA_PLANE_TOKEN'), 'README documents the edge-stack register token env var');
710
- });
711
- test('without edgeTurnConnector the route snippet is unchanged — no /edge/turn, no route {}', () => {
712
- const ctx = {
713
- ...CTX, ingress: 'edge-fed', idpUrl: 'https://auth.corp.example', colocate: true,
714
- };
715
- const snippet = (0, deploy_init_1.renderTarget)('vm', ctx)['agent-route.caddy'];
716
- assert.ok(!snippet.includes('/edge/turn') && !snippet.includes('@turnStart')
717
- && !snippet.includes('X-Agent-Turn-Nonce') && !snippet.includes('route {'), 'turn registration is strictly opt-in; default output must not change');
718
- });
719
- test('--colocate is a no-op without --ingress edge-fed (still ships the normal self-issued edge)', () => {
720
- const files = (0, deploy_init_1.renderTarget)('vm', { ...CTX, colocate: true });
721
- assert.ok(files['Caddyfile'], 'no ingress edge-fed → colocate does not apply, normal vm artifacts render');
722
- assert.ok(!files['agent-route.caddy']);
723
- });
724
- test('agent service does not load .env.auth; broker + oauth2-proxy do', () => {
725
- const compose = (0, deploy_init_1.renderTarget)('compose', CTX)['docker-compose.yml'];
726
- // The agent runs model-driven tool calls — it must never receive the token-signing key.
727
- const agentBlock = compose.slice(compose.indexOf(' agent:'), compose.indexOf(' oauth2-proxy:'));
728
- assert.ok(agentBlock.includes('env_file:'), 'sanity: located the agent service block');
729
- assert.ok(!agentBlock.includes('.env.auth'), 'agent must not load .env.auth (JWT signing key + OAuth secrets)');
730
- assert.ok(compose.includes('.env.auth'), 'broker/oauth2-proxy must load .env.auth');
731
- });
732
- });
733
- suite('deploy-init: deployCommand stages a self-contained pack', () => {
734
- let pack;
735
- let staging;
736
- setup(() => {
737
- pack = fs.mkdtempSync(path.join(os.tmpdir(), 'ah-pack-'));
738
- staging = fs.mkdtempSync(path.join(os.tmpdir(), 'ah-stage-'));
739
- fs.writeFileSync(path.join(pack, 'agent.yaml'), 'apiVersion: agenthippo.ai/v1\nkind: Agent\nmetadata:\n name: cs-test\n version: 0.1.0\nspec:\n engine: claude\n model: litellm/gpt-5.5\n');
740
- fs.writeFileSync(path.join(pack, 'AGENTS.md'), '# cs-test\n');
741
- fs.mkdirSync(path.join(pack, 'skills', 'demo', 'scripts'), { recursive: true });
742
- fs.writeFileSync(path.join(pack, 'skills', 'demo', 'scripts', 'run.sh'), 'echo hi\n');
743
- fs.writeFileSync(path.join(pack, 'skills', 'demo', 'scripts', 'requirements.txt'), 'requests\n');
744
- // Ignored by the copy filter: dev cache, secrets, source deploy/.
745
- fs.mkdirSync(path.join(pack, 'node_modules', 'foo'), { recursive: true });
746
- fs.writeFileSync(path.join(pack, 'node_modules', 'foo', 'index.js'), 'x');
747
- fs.writeFileSync(path.join(pack, '.env'), 'SECRET=1\n');
748
- fs.writeFileSync(path.join(pack, 'my-credentials.json'), '{}\n');
749
- fs.writeFileSync(path.join(pack, 'service-account.pem'), 'FAKE PEM\n');
750
- fs.writeFileSync(path.join(pack, 'id_rsa'), 'FAKE PRIVATE KEY\n');
751
- fs.mkdirSync(path.join(pack, 'deploy'), { recursive: true });
752
- fs.writeFileSync(path.join(pack, 'deploy', 'leftover.yaml'), 'stale\n');
753
- });
754
- teardown(() => {
755
- fs.rmSync(pack, { recursive: true, force: true });
756
- fs.rmSync(staging, { recursive: true, force: true });
757
- });
758
- test('copies pack into staging root, drops node_modules/.env/credentials, writes deploy/ + root .dockerignore', async () => {
759
- await (0, deploy_1.deployCommand)('init', pack, { target: 'cloudrun', out: staging, port: 8080, force: true });
760
- // Pack content at the staging root.
761
- assert.ok(fs.existsSync(path.join(staging, 'agent.yaml')), 'agent.yaml copied to staging root');
762
- assert.ok(fs.existsSync(path.join(staging, 'AGENTS.md')), 'AGENTS.md copied to staging root');
763
- assert.ok(fs.existsSync(path.join(staging, 'skills', 'demo', 'scripts', 'requirements.txt')), 'skill requirements.txt copied (needed by the build-time install step)');
764
- // Filtered out (mirrors .dockerignore): no dev caches, no secrets.
765
- assert.ok(!fs.existsSync(path.join(staging, 'node_modules')), 'node_modules must not be copied into staging');
766
- assert.ok(!fs.existsSync(path.join(staging, '.env')), '.env must not be copied into staging');
767
- assert.ok(!fs.existsSync(path.join(staging, 'my-credentials.json')), 'credentials json must not be copied');
768
- assert.ok(!fs.existsSync(path.join(staging, 'service-account.pem')), '.pem key must not be copied');
769
- assert.ok(!fs.existsSync(path.join(staging, 'id_rsa')), 'id_rsa key must not be copied');
770
- // The source pack's own deploy/ is not copied (the generator owns staging/deploy/).
771
- assert.ok(!fs.existsSync(path.join(staging, 'deploy', 'leftover.yaml')), 'source deploy/ must not be copied');
772
- // Generated artifacts under staging/deploy/.
773
- assert.ok(fs.existsSync(path.join(staging, 'deploy', 'Dockerfile')), 'Dockerfile at staging/deploy/Dockerfile');
774
- assert.ok(fs.existsSync(path.join(staging, 'deploy', 'service.yaml')), 'service.yaml at staging/deploy/');
775
- assert.ok(fs.existsSync(path.join(staging, 'deploy', 'cloudrun-deploy.sh')), 'cloudrun-deploy.sh at staging/deploy/');
776
- // .dockerignore at the staging root (build-context root), NOT under deploy/.
777
- assert.ok(fs.existsSync(path.join(staging, '.dockerignore')), '.dockerignore at staging root (context root)');
778
- assert.ok(!fs.existsSync(path.join(staging, 'deploy', '.dockerignore')), '.dockerignore must not be under deploy/ (Docker would ignore it)');
779
- // The generated build script self-anchors to the staging root.
780
- const sh = fs.readFileSync(path.join(staging, 'deploy', 'cloudrun-deploy.sh'), 'utf8');
781
- assert.ok(sh.includes('cd "$(dirname "$0")/.."'), 'cloudrun-deploy.sh anchors to staging root');
782
- assert.ok(sh.includes('docker build') && sh.includes('deploy/Dockerfile') && sh.includes('-t "$IMAGE"'), 'build sources deploy/Dockerfile (sed-rewritten to AR base) with the staging root as context');
783
- });
784
- test('--packdir flag is honored as an alternative to the positional arg', async () => {
785
- await (0, deploy_1.deployCommand)('init', undefined, { target: 'cloudrun', out: staging, port: 8080, force: true, packdir: pack });
786
- assert.ok(fs.existsSync(path.join(staging, 'agent.yaml')), 'packdir flag resolved the pack');
787
- assert.ok(fs.existsSync(path.join(staging, 'deploy', 'Dockerfile')), 'artifacts generated from packdir pack');
788
- });
789
- test('--blueprint team-pilot --platform cloudrun resolves to IAP (no Caddyfile, no oauth2-proxy)', async () => {
790
- await (0, deploy_1.deployCommand)('init', pack, {
791
- target: 'vm', blueprint: 'team-pilot', platform: 'cloudrun', out: staging, port: 8080, force: true,
792
- });
793
- assert.ok(fs.existsSync(path.join(staging, 'deploy', 'cloudrun-deploy.sh')), 'cloudrun artifacts generated');
794
- assert.ok(!fs.existsSync(path.join(staging, 'deploy', 'Caddyfile')), 'team-pilot on cloudrun is IAP — no Caddy edge');
795
- const sh = fs.readFileSync(path.join(staging, 'deploy', 'cloudrun-deploy.sh'), 'utf8');
796
- assert.ok(sh.includes('--iap'), 'blueprint-resolved --ingress iap reaches the actual IAP deploy path');
797
- });
798
- test('--blueprint enterprise-fleet --platform vm resolves to a federated (no oauth2-proxy) edge', async () => {
799
- await (0, deploy_1.deployCommand)('init', pack, {
800
- target: 'cloudrun', blueprint: 'enterprise-fleet', platform: 'vm', out: staging, port: 8080, force: true,
801
- idpUrl: 'https://auth.corp.example',
802
- });
803
- const caddy = fs.readFileSync(path.join(staging, 'deploy', 'Caddyfile'), 'utf8');
804
- const compose = fs.readFileSync(path.join(staging, 'deploy', 'docker-compose.yml'), 'utf8');
805
- assert.ok(!caddy.includes('oauth2-proxy:4180'), 'enterprise-fleet federates — no oauth2-proxy in the Caddyfile');
806
- assert.ok(!/^\s*oauth2-proxy:/m.test(compose), 'enterprise-fleet federates — no oauth2-proxy container');
807
- });
808
- });
809
- suite('deploy-init: copyPackToStaging dereferences symlinks + skips broken ones', () => {
810
- let pack;
811
- let staging;
812
- setup(() => {
813
- pack = fs.mkdtempSync(path.join(os.tmpdir(), 'ah-pack-'));
814
- staging = fs.mkdtempSync(path.join(os.tmpdir(), 'ah-stage-'));
815
- fs.writeFileSync(path.join(pack, 'agent.yaml'), 'apiVersion: agenthippo.ai/v1\nkind: Agent\nmetadata:\n name: link-test\n version: 0.1.0\nspec:\n engine: claude\n');
816
- // Real skill content + a shared file the skill links to (relative symlink → resolved on copy).
817
- fs.mkdirSync(path.join(pack, 'skills', 'demo'), { recursive: true });
818
- fs.writeFileSync(path.join(pack, 'skills', 'demo', 'REAL.md'), '# real content\n');
819
- fs.symlinkSync('REAL.md', path.join(pack, 'skills', 'demo', 'SKILL.md')); // valid relative symlink
820
- // Broken symlink: target does not exist (the data-analyst hydration bug pattern).
821
- fs.mkdirSync(path.join(pack, 'skills', 'broken'), { recursive: true });
822
- fs.symlinkSync('/nonexistent/abs/path/SKILL.md', path.join(pack, 'skills', 'broken', 'SKILL.md'));
823
- });
824
- teardown(() => {
825
- fs.rmSync(pack, { recursive: true, force: true });
826
- fs.rmSync(staging, { recursive: true, force: true });
827
- });
828
- test('valid symlinks are dereferenced to real files; broken symlinks are skipped + reported', () => {
829
- const broken = (0, deploy_1.copyPackToStaging)(pack, staging);
830
- // Valid symlink → real file content in staging (not a symlink). Docker-safe.
831
- const staged = path.join(staging, 'skills', 'demo', 'SKILL.md');
832
- assert.ok(fs.existsSync(staged), 'valid symlink content copied to staging');
833
- assert.ok(!fs.lstatSync(staged).isSymbolicLink(), 'staged entry is a real file, not a symlink');
834
- assert.strictEqual(fs.readFileSync(staged, 'utf8'), '# real content\n');
835
- // Broken symlink → not staged, and reported in the broken list.
836
- assert.ok(!fs.existsSync(path.join(staging, 'skills', 'broken', 'SKILL.md')), 'broken symlink must not be staged');
837
- assert.ok(broken.includes('skills/broken/SKILL.md'), 'broken symlink reported in returned list');
838
- });
839
- });
840
- suite('deploy-init: enterprise-deploy/idp/ (customer 0) stays in sync with `agenthippo idp init`', () => {
841
- // PLAN/deploy.md — AgentHippo's own auth.agenthippo.ai instance is "customer 0": it must be
842
- // stood up with the exact same `agenthippo idp init` a real enterprise customer would use,
843
- // not a bespoke hand-maintained copy. This fails loudly if the checked-in files drift from
844
- // what the generator produces for the same hostname (regenerate with:
845
- // `agenthippo idp init --hostname auth.agenthippo.ai --out enterprise-deploy/idp --force`).
846
- test('checked-in files are byte-identical to renderIdpArtifacts({ hostname: "auth.agenthippo.ai" })', () => {
847
- const idpDir = path.join(__dirname, '..', '..', '..', '..', 'enterprise-deploy', 'idp');
848
- const files = (0, idp_init_1.renderIdpArtifacts)({ hostname: 'auth.agenthippo.ai' });
849
- for (const [rel, expected] of Object.entries(files)) {
850
- const actual = fs.readFileSync(path.join(idpDir, rel), 'utf8');
851
- assert.strictEqual(actual, expected, `enterprise-deploy/idp/${rel} is stale — regenerate with: agenthippo idp init --hostname auth.agenthippo.ai --out enterprise-deploy/idp --force`);
852
- }
853
- });
854
- });