@agenthippo-ai/agenthippo 1.110.11 → 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 (534) 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 -302
  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 -1283
  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 +617 -564
  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 +127 -459
  61. package/out/scripts/analytics/agent-fleet-widget.js +18 -257
  62. package/out/scripts/analytics/agentide-litellm-otel.config.yaml +0 -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/token-cost-flamegraph-widget.js +4 -461
  70. package/out/scripts/analytics/token-cost-trend-widget.js +4 -534
  71. package/out/scripts/analytics/workflows-collector.cjs +4 -314
  72. package/out/scripts/analytics/workflows-daemon.mjs +9 -185
  73. package/out/scripts/analytics/workflows-widget.cjs +15 -159
  74. package/out/scripts/analytics/wow-model-widget.js +10 -120
  75. package/out/scripts/vendor-tools.mjs +2 -233
  76. package/out/skills/publish.js +3 -178
  77. package/out/store/github/setup.js +7 -212
  78. package/out/store/oramaIndex.js +2 -884
  79. package/out/sync.js +26 -1829
  80. package/out/terminalLogger.js +5 -358
  81. package/out/utils/pathSafety.js +2 -60
  82. package/out/utils/pythonRunner.js +4 -258
  83. package/out/utils/toolPath.js +2 -83
  84. package/out/workspaceFolders.js +2 -59
  85. package/package.json +1 -1
  86. package/out/agentpack/github.js +0 -547
  87. package/out/agentpack/index.js +0 -69
  88. package/out/agentpack/install.js +0 -297
  89. package/out/agentpack/manager.js +0 -441
  90. package/out/agentpack/manifest.js +0 -135
  91. package/out/agentpack/paths.js +0 -521
  92. package/out/agentpack/publish.js +0 -248
  93. package/out/agentpack/stores.js +0 -554
  94. package/out/analytics/dashboard/fleetStatusUtils.js +0 -30
  95. package/out/analytics/dashboard/fleetTitleUtils.js +0 -68
  96. package/out/analytics/dashboard/refreshPolicy.js +0 -16
  97. package/out/analytics/dashboard/scheduledFleetFingerprint.js +0 -22
  98. package/out/analytics/dashboard/scheduledFleetUtils.js +0 -22
  99. package/out/analytics/dashboard/sessionEventFleetStats.js +0 -118
  100. package/out/analytics/dashboard/viewsConfigMerge.js +0 -221
  101. package/out/analytics/dashboard/webview/codicon.ttf +0 -0
  102. package/out/analytics/identity.js +0 -0
  103. package/out/analytics/sessionEvents.js +0 -324
  104. package/out/auth/callbackUriParse.js +0 -59
  105. package/out/auth/types.js +0 -12
  106. package/out/auth-broker/config.js +0 -112
  107. package/out/auth-broker/jwt.js +0 -105
  108. package/out/auth-broker/pkce.js +0 -59
  109. package/out/auth-broker/server.js +0 -681
  110. package/out/auth-broker/store.js +0 -275
  111. package/out/authority/warrant.js +0 -206
  112. package/out/base-prompts/mcp-servers/.mcp.json +0 -13
  113. package/out/base-prompts/mcp-servers/langfuse-analytics/README.md +0 -142
  114. package/out/base-prompts/mcp-servers/langfuse-analytics/mcp.json +0 -13
  115. package/out/base-prompts/mcp-servers/langfuse-analytics/package-lock.json +0 -1192
  116. package/out/base-prompts/mcp-servers/langfuse-analytics/package.json +0 -23
  117. package/out/base-prompts/mcp-servers/langfuse-analytics/scripts/run-with-env.sh +0 -12
  118. package/out/base-prompts/mcp-servers/langfuse-analytics/scripts/sdk-test.js +0 -102
  119. package/out/base-prompts/mcp-servers/langfuse-analytics/scripts/simple-test.js +0 -137
  120. package/out/base-prompts/mcp-servers/langfuse-analytics/scripts/test-client.js +0 -118
  121. package/out/base-prompts/mcp-servers/langfuse-analytics/scripts/test-server.js +0 -209
  122. package/out/base-prompts/mcp-servers/langfuse-analytics/src/client.ts +0 -431
  123. package/out/base-prompts/mcp-servers/langfuse-analytics/src/index.ts +0 -270
  124. package/out/base-prompts/mcp-servers/langfuse-analytics/tsconfig.json +0 -18
  125. package/out/base-prompts/rules/AGENTS.md +0 -204
  126. package/out/base-prompts/skills/agent-browser/SKILL.md +0 -102
  127. package/out/base-prompts/skills/agent-builder/SKILL.md +0 -73
  128. package/out/base-prompts/skills/agent-builder/references/agent-pack.md +0 -63
  129. package/out/base-prompts/skills/agent-builder/references/crewai.md +0 -66
  130. package/out/base-prompts/skills/agent-builder/references/langchain.md +0 -60
  131. package/out/base-prompts/skills/agent-builder/references/raw-sdk.md +0 -73
  132. package/out/base-prompts/skills/agent-engine-creator/SKILL.md +0 -586
  133. package/out/base-prompts/skills/agent-engine-installer/SKILL.md +0 -106
  134. package/out/base-prompts/skills/agent-engine-installer/scripts/install-engine.mjs +0 -259
  135. package/out/base-prompts/skills/agent-engine-installer/scripts/install-engine.ps1 +0 -189
  136. package/out/base-prompts/skills/agenthippo-cli/SKILL.md +0 -69
  137. package/out/base-prompts/skills/agenthippo-cli/scripts/install.sh +0 -63
  138. package/out/base-prompts/skills/agentpack-creator/SKILL.md +0 -375
  139. package/out/base-prompts/skills/agentpack-creator/references/agent-templates.md +0 -261
  140. package/out/base-prompts/skills/agentpack-creator/references/agents-md-guide.md +0 -195
  141. package/out/base-prompts/skills/agentpack-creator/scripts/init_pack.py +0 -391
  142. package/out/base-prompts/skills/agentpack-creator/scripts/init_pack_test.py +0 -294
  143. package/out/base-prompts/skills/agentpack-testbench/SKILL.md +0 -135
  144. package/out/base-prompts/skills/algorithmic-art/LICENSE.txt +0 -202
  145. package/out/base-prompts/skills/algorithmic-art/SKILL.md +0 -405
  146. package/out/base-prompts/skills/algorithmic-art/templates/generator_template.js +0 -223
  147. package/out/base-prompts/skills/algorithmic-art/templates/viewer.html +0 -599
  148. package/out/base-prompts/skills/debug-agent/SKILL.md +0 -83
  149. package/out/base-prompts/skills/desktop-automation/SKILL.md +0 -166
  150. package/out/base-prompts/skills/desktop-automation/references/agenthippo-ui-recipes.md +0 -441
  151. package/out/base-prompts/skills/desktop-automation/scripts/windows-desktop-uia.psm1 +0 -280
  152. package/out/base-prompts/skills/docx/LICENSE.txt +0 -30
  153. package/out/base-prompts/skills/docx/SKILL.md +0 -197
  154. package/out/base-prompts/skills/docx/docx-js.md +0 -350
  155. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +0 -1499
  156. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +0 -146
  157. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +0 -1085
  158. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +0 -11
  159. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +0 -3081
  160. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +0 -23
  161. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +0 -185
  162. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +0 -287
  163. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +0 -1676
  164. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +0 -28
  165. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +0 -144
  166. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +0 -174
  167. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +0 -25
  168. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +0 -18
  169. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +0 -59
  170. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +0 -56
  171. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +0 -195
  172. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +0 -582
  173. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +0 -25
  174. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +0 -4439
  175. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +0 -570
  176. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +0 -509
  177. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +0 -12
  178. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +0 -108
  179. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +0 -96
  180. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +0 -3646
  181. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +0 -116
  182. package/out/base-prompts/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +0 -42
  183. package/out/base-prompts/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +0 -50
  184. package/out/base-prompts/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +0 -49
  185. package/out/base-prompts/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +0 -33
  186. package/out/base-prompts/skills/docx/ooxml/schemas/mce/mc.xsd +0 -75
  187. package/out/base-prompts/skills/docx/ooxml/schemas/microsoft/wml-2010.xsd +0 -560
  188. package/out/base-prompts/skills/docx/ooxml/schemas/microsoft/wml-2012.xsd +0 -67
  189. package/out/base-prompts/skills/docx/ooxml/schemas/microsoft/wml-2018.xsd +0 -14
  190. package/out/base-prompts/skills/docx/ooxml/schemas/microsoft/wml-cex-2018.xsd +0 -20
  191. package/out/base-prompts/skills/docx/ooxml/schemas/microsoft/wml-cid-2016.xsd +0 -13
  192. package/out/base-prompts/skills/docx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +0 -4
  193. package/out/base-prompts/skills/docx/ooxml/schemas/microsoft/wml-symex-2015.xsd +0 -8
  194. package/out/base-prompts/skills/docx/ooxml/scripts/pack.py +0 -159
  195. package/out/base-prompts/skills/docx/ooxml/scripts/unpack.py +0 -29
  196. package/out/base-prompts/skills/docx/ooxml/scripts/validate.py +0 -69
  197. package/out/base-prompts/skills/docx/ooxml/scripts/validation/__init__.py +0 -15
  198. package/out/base-prompts/skills/docx/ooxml/scripts/validation/base.py +0 -951
  199. package/out/base-prompts/skills/docx/ooxml/scripts/validation/docx.py +0 -274
  200. package/out/base-prompts/skills/docx/ooxml/scripts/validation/pptx.py +0 -315
  201. package/out/base-prompts/skills/docx/ooxml/scripts/validation/redlining.py +0 -279
  202. package/out/base-prompts/skills/docx/ooxml.md +0 -610
  203. package/out/base-prompts/skills/docx/scripts/__init__.py +0 -1
  204. package/out/base-prompts/skills/docx/scripts/document.py +0 -1276
  205. package/out/base-prompts/skills/docx/scripts/templates/comments.xml +0 -3
  206. package/out/base-prompts/skills/docx/scripts/templates/commentsExtended.xml +0 -3
  207. package/out/base-prompts/skills/docx/scripts/templates/commentsExtensible.xml +0 -3
  208. package/out/base-prompts/skills/docx/scripts/templates/commentsIds.xml +0 -3
  209. package/out/base-prompts/skills/docx/scripts/templates/people.xml +0 -3
  210. package/out/base-prompts/skills/docx/scripts/utilities.py +0 -374
  211. package/out/base-prompts/skills/gateway-outbound/SKILL.md +0 -136
  212. package/out/base-prompts/skills/mcp-builder/LICENSE.txt +0 -202
  213. package/out/base-prompts/skills/mcp-builder/SKILL.md +0 -328
  214. package/out/base-prompts/skills/mcp-builder/reference/evaluation.md +0 -602
  215. package/out/base-prompts/skills/mcp-builder/reference/mcp_best_practices.md +0 -249
  216. package/out/base-prompts/skills/mcp-builder/reference/node_mcp_server.md +0 -970
  217. package/out/base-prompts/skills/mcp-builder/reference/python_mcp_server.md +0 -719
  218. package/out/base-prompts/skills/mcp-builder/scripts/connections.py +0 -151
  219. package/out/base-prompts/skills/mcp-builder/scripts/evaluation.py +0 -373
  220. package/out/base-prompts/skills/mcp-builder/scripts/example_evaluation.xml +0 -22
  221. package/out/base-prompts/skills/mcp-builder/scripts/requirements.txt +0 -2
  222. package/out/base-prompts/skills/openclaw/SKILL.md +0 -406
  223. package/out/base-prompts/skills/openclaw/scripts/run-smoke.sh +0 -61
  224. package/out/base-prompts/skills/pdf/LICENSE.txt +0 -30
  225. package/out/base-prompts/skills/pdf/SKILL.md +0 -294
  226. package/out/base-prompts/skills/pdf/forms.md +0 -205
  227. package/out/base-prompts/skills/pdf/reference.md +0 -612
  228. package/out/base-prompts/skills/pdf/scripts/check_bounding_boxes.py +0 -70
  229. package/out/base-prompts/skills/pdf/scripts/check_bounding_boxes_test.py +0 -226
  230. package/out/base-prompts/skills/pdf/scripts/check_fillable_fields.py +0 -12
  231. package/out/base-prompts/skills/pdf/scripts/convert_pdf_to_images.py +0 -35
  232. package/out/base-prompts/skills/pdf/scripts/create_validation_image.py +0 -41
  233. package/out/base-prompts/skills/pdf/scripts/extract_form_field_info.py +0 -152
  234. package/out/base-prompts/skills/pdf/scripts/fill_fillable_fields.py +0 -114
  235. package/out/base-prompts/skills/pdf/scripts/fill_pdf_form_with_annotations.py +0 -108
  236. package/out/base-prompts/skills/pptx/LICENSE.txt +0 -30
  237. package/out/base-prompts/skills/pptx/SKILL.md +0 -484
  238. package/out/base-prompts/skills/pptx/html2pptx.md +0 -625
  239. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +0 -1499
  240. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +0 -146
  241. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +0 -1085
  242. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +0 -11
  243. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +0 -3081
  244. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +0 -23
  245. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +0 -185
  246. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +0 -287
  247. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +0 -1676
  248. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +0 -28
  249. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +0 -144
  250. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +0 -174
  251. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +0 -25
  252. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +0 -18
  253. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +0 -59
  254. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +0 -56
  255. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +0 -195
  256. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +0 -582
  257. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +0 -25
  258. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +0 -4439
  259. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +0 -570
  260. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +0 -509
  261. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +0 -12
  262. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +0 -108
  263. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +0 -96
  264. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +0 -3646
  265. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +0 -116
  266. package/out/base-prompts/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +0 -42
  267. package/out/base-prompts/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +0 -50
  268. package/out/base-prompts/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +0 -49
  269. package/out/base-prompts/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +0 -33
  270. package/out/base-prompts/skills/pptx/ooxml/schemas/mce/mc.xsd +0 -75
  271. package/out/base-prompts/skills/pptx/ooxml/schemas/microsoft/wml-2010.xsd +0 -560
  272. package/out/base-prompts/skills/pptx/ooxml/schemas/microsoft/wml-2012.xsd +0 -67
  273. package/out/base-prompts/skills/pptx/ooxml/schemas/microsoft/wml-2018.xsd +0 -14
  274. package/out/base-prompts/skills/pptx/ooxml/schemas/microsoft/wml-cex-2018.xsd +0 -20
  275. package/out/base-prompts/skills/pptx/ooxml/schemas/microsoft/wml-cid-2016.xsd +0 -13
  276. package/out/base-prompts/skills/pptx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +0 -4
  277. package/out/base-prompts/skills/pptx/ooxml/schemas/microsoft/wml-symex-2015.xsd +0 -8
  278. package/out/base-prompts/skills/pptx/ooxml/scripts/pack.py +0 -159
  279. package/out/base-prompts/skills/pptx/ooxml/scripts/unpack.py +0 -29
  280. package/out/base-prompts/skills/pptx/ooxml/scripts/validate.py +0 -69
  281. package/out/base-prompts/skills/pptx/ooxml/scripts/validation/__init__.py +0 -15
  282. package/out/base-prompts/skills/pptx/ooxml/scripts/validation/base.py +0 -951
  283. package/out/base-prompts/skills/pptx/ooxml/scripts/validation/docx.py +0 -274
  284. package/out/base-prompts/skills/pptx/ooxml/scripts/validation/pptx.py +0 -315
  285. package/out/base-prompts/skills/pptx/ooxml/scripts/validation/redlining.py +0 -279
  286. package/out/base-prompts/skills/pptx/ooxml.md +0 -427
  287. package/out/base-prompts/skills/pptx/scripts/html2pptx.js +0 -984
  288. package/out/base-prompts/skills/pptx/scripts/inventory.py +0 -1020
  289. package/out/base-prompts/skills/pptx/scripts/rearrange.py +0 -231
  290. package/out/base-prompts/skills/pptx/scripts/replace.py +0 -385
  291. package/out/base-prompts/skills/pptx/scripts/thumbnail.py +0 -450
  292. package/out/base-prompts/skills/prompt-lab/SKILL.md +0 -149
  293. package/out/base-prompts/skills/prompt-lab/scripts/query-analytics.sh +0 -2551
  294. package/out/base-prompts/skills/skill-creator/LICENSE.txt +0 -202
  295. package/out/base-prompts/skills/skill-creator/SKILL.md +0 -371
  296. package/out/base-prompts/skills/skill-creator/references/output-patterns.md +0 -82
  297. package/out/base-prompts/skills/skill-creator/references/workflows.md +0 -28
  298. package/out/base-prompts/skills/skill-creator/scripts/init_skill.py +0 -303
  299. package/out/base-prompts/skills/skill-creator/scripts/package_skill.py +0 -110
  300. package/out/base-prompts/skills/skill-creator/scripts/quick_validate.py +0 -95
  301. package/out/base-prompts/skills/skill-installer/SKILL.md +0 -251
  302. package/out/base-prompts/skills/skill-installer/references/store-api.md +0 -219
  303. package/out/base-prompts/skills/spotlight-dashboard/SKILL.md +0 -83
  304. package/out/base-prompts/skills/spotlight-insights/SKILL.md +0 -101
  305. package/out/base-prompts/skills/spotlight-optimize/SKILL.md +0 -93
  306. package/out/base-prompts/skills/spotlight-optimize/scripts/query-analytics.sh +0 -2551
  307. package/out/base-prompts/skills/spotlight-query/SKILL.md +0 -314
  308. package/out/base-prompts/skills/spotlight-query/references/otel-schema.md +0 -163
  309. package/out/base-prompts/skills/spotlight-query/scripts/query-analytics.sh +0 -2551
  310. package/out/base-prompts/skills/spotlight-query/scripts/query-analytics.test.sh +0 -744
  311. package/out/base-prompts/skills/spotlight-query/scripts/test-fixtures/analytics/sessions/sess-test-1.jsonl +0 -14
  312. package/out/base-prompts/skills/spotlight-query/scripts/test-fixtures/analytics/traces/.duckdb-index.json +0 -7
  313. package/out/base-prompts/skills/spotlight-query/scripts/test-fixtures/analytics/traces/sample.jsonl +0 -5
  314. package/out/base-prompts/skills/spotlight-report/SKILL.md +0 -86
  315. package/out/base-prompts/skills/spotlight-visualize/SKILL.md +0 -92
  316. package/out/base-prompts/skills/spotlight-visualize/scripts/query-analytics.sh +0 -2551
  317. package/out/base-prompts/skills/xlsx/LICENSE.txt +0 -30
  318. package/out/base-prompts/skills/xlsx/SKILL.md +0 -289
  319. package/out/base-prompts/skills/xlsx/recalc.py +0 -178
  320. package/out/branding.js +0 -49
  321. package/out/cli/commands/anywhere.js +0 -66
  322. package/out/cli/commands/ask.js +0 -246
  323. package/out/cli/commands/auth-broker.js +0 -24
  324. package/out/cli/commands/auth.js +0 -219
  325. package/out/cli/commands/chat.js +0 -357
  326. package/out/cli/commands/conformance.js +0 -249
  327. package/out/cli/commands/data-plane.js +0 -151
  328. package/out/cli/commands/deploy.js +0 -263
  329. package/out/cli/commands/gateway.js +0 -218
  330. package/out/cli/commands/idp.js +0 -85
  331. package/out/cli/commands/pack.js +0 -399
  332. package/out/cli/commands/probe-custom-engine.js +0 -82
  333. package/out/cli/commands/sandbox.js +0 -351
  334. package/out/cli/commands/serve.js +0 -1950
  335. package/out/cli/commands/store.js +0 -927
  336. package/out/cli/credential-context.js +0 -108
  337. package/out/cli/data-plane/broker.js +0 -78
  338. package/out/cli/data-plane/connector-host.js +0 -121
  339. package/out/cli/data-plane/egress.js +0 -189
  340. package/out/cli/data-plane/gateway.js +0 -218
  341. package/out/cli/data-plane/index.js +0 -153
  342. package/out/cli/data-plane/registry.js +0 -89
  343. package/out/cli/data-plane/remote.js +0 -106
  344. package/out/cli/data-plane/sidecar.js +0 -225
  345. package/out/cli/deploy/blueprints/registry.js +0 -84
  346. package/out/cli/deploy/layers/identity.js +0 -175
  347. package/out/cli/deploy-init.js +0 -3023
  348. package/out/cli/deps.js +0 -342
  349. package/out/cli/idp-init.js +0 -338
  350. package/out/cli/pack-install-ref.js +0 -15
  351. package/out/cli/pack-loader.js +0 -418
  352. package/out/cli/pack-runtime.js +0 -61
  353. package/out/cli/runtime.js +0 -450
  354. package/out/cli/serve-hardening.js +0 -776
  355. package/out/cli/state-sync.js +0 -424
  356. package/out/cli/utils.js +0 -231
  357. package/out/engines/base.js +0 -188
  358. package/out/engines/claude.js +0 -1254
  359. package/out/engines/codex.js +0 -862
  360. package/out/engines/custom.js +0 -680
  361. package/out/engines/customEngineIpc.js +0 -95
  362. package/out/engines/customEngineRunnerEmbed.js +0 -107
  363. package/out/engines/customRegistry.js +0 -274
  364. package/out/engines/embeddedCustomEngineRunner.generated.js +0 -9
  365. package/out/engines/engineApiKey.js +0 -138
  366. package/out/engines/install.js +0 -372
  367. package/out/engines/persistentEngineWorker.js +0 -320
  368. package/out/engines/publish.js +0 -341
  369. package/out/evidence/sessionShip.js +0 -643
  370. package/out/gateway/bridge.js +0 -843
  371. package/out/gateway/cli-agent-id.js +0 -36
  372. package/out/gateway/client.js +0 -336
  373. package/out/gateway/client.test.js +0 -395
  374. package/out/gateway/gateway-scope-errors.js +0 -14
  375. package/out/gateway/gatewayBackup.js +0 -76
  376. package/out/gateway/installSource.js +0 -68
  377. package/out/gateway/lifecycle.js +0 -3190
  378. package/out/gateway/openclaw-channel-routing.js +0 -317
  379. package/out/gateway/outboundHandles.js +0 -373
  380. package/out/gateway/outboundPaths.js +0 -75
  381. package/out/gateway/outboundSend.js +0 -254
  382. package/out/gateway/protocol.js +0 -48
  383. package/out/gateway/secretsPreflight.js +0 -90
  384. package/out/gateway/sessionRouting.js +0 -77
  385. package/out/headless/index.js +0 -546
  386. package/out/headless/sync.js +0 -473
  387. package/out/live-e2e/mcp-demo/server.mjs +0 -32
  388. package/out/live-probe/connector.mjs +0 -8
  389. package/out/live-probe/env-report.mjs +0 -8
  390. package/out/mcp.js +0 -654
  391. package/out/pack/caps.js +0 -271
  392. package/out/pack/governor.js +0 -326
  393. package/out/pack/lease-schema.js +0 -273
  394. package/out/pack/lease.js +0 -682
  395. package/out/pack/reconcile.js +0 -217
  396. package/out/pack/signature.js +0 -839
  397. package/out/permissions.js +0 -108
  398. package/out/permissions.mapping.yaml +0 -68
  399. package/out/registry/index.js +0 -332
  400. package/out/runner/host.js +0 -141
  401. package/out/runner/protocol.js +0 -128
  402. package/out/runner/remoteEngine.js +0 -166
  403. package/out/runtime/interfaces/config-provider.js +0 -32
  404. package/out/runtime/interfaces/edit-tracker.js +0 -24
  405. package/out/runtime/interfaces/index.js +0 -29
  406. package/out/runtime/interfaces/logger.js +0 -40
  407. package/out/runtime/interfaces/permission-handler.js +0 -66
  408. package/out/runtime/interfaces/session-store.js +0 -342
  409. package/out/runtime/vscode/vscode-session-store.js +0 -22
  410. package/out/sandbox/containerDriver.js +0 -572
  411. package/out/sandbox/processDriver.js +0 -318
  412. package/out/sandbox/sandboxRunner.js +0 -303
  413. package/out/sandbox/support.js +0 -301
  414. package/out/sandbox/types.js +0 -55
  415. package/out/scripts/analytics/fleet-local-adapter.js +0 -246
  416. package/out/scripts/analytics/live-fleet-4-collector.cjs +0 -315
  417. package/out/scripts/analytics/live-fleet-4-daemon.mjs +0 -134
  418. package/out/scripts/analytics/live-fleet-4-widget.cjs +0 -433
  419. package/out/scripts/gateway/Dockerfile.serve +0 -45
  420. package/out/scripts/gateway/docker-serve.sh +0 -248
  421. package/out/scripts/gateway/setup-gateway-server.ps1 +0 -953
  422. package/out/scripts/gateway/setup-gateway-server.sh +0 -935
  423. package/out/session.js +0 -272
  424. package/out/shared/agentEngines.js +0 -170
  425. package/out/shared/index.js +0 -109
  426. package/out/shared/models.js +0 -136
  427. package/out/shared/providers.js +0 -205
  428. package/out/spotlight/install.js +0 -345
  429. package/out/spotlight/publish.js +0 -544
  430. package/out/spotlight/yaml.js +0 -31
  431. package/out/store/index.js +0 -786
  432. package/out/store/shared.js +0 -241
  433. package/out/test/agentEnvFile.test.js +0 -97
  434. package/out/test/agentYaml.test.js +0 -373
  435. package/out/test/agentpack.test.js +0 -639
  436. package/out/test/analytics-lifecycle.test.js +0 -174
  437. package/out/test/analytics.test.js +0 -756
  438. package/out/test/auth-baseurl.test.js +0 -132
  439. package/out/test/auth-bootstrapApply.test.js +0 -123
  440. package/out/test/auth-broker-hardening.test.js +0 -227
  441. package/out/test/auth-broker.test.js +0 -541
  442. package/out/test/auth-callback.test.js +0 -62
  443. package/out/test/blueprint-registry.test.js +0 -105
  444. package/out/test/branding.test.js +0 -242
  445. package/out/test/caps-governor.test.js +0 -460
  446. package/out/test/cli-agent-id.test.js +0 -55
  447. package/out/test/codex-new-file-survival.test.js +0 -119
  448. package/out/test/configuration-scopes.test.js +0 -131
  449. package/out/test/credential-context.test.js +0 -160
  450. package/out/test/custom-env-layering.test.js +0 -151
  451. package/out/test/customEngineInstall.test.js +0 -100
  452. package/out/test/customRegistry.test.js +0 -122
  453. package/out/test/data-plane-engine-wiring.test.js +0 -282
  454. package/out/test/data-plane.test.js +0 -624
  455. package/out/test/deploy-init.test.js +0 -860
  456. package/out/test/deps-auto-install.test.js +0 -81
  457. package/out/test/egress-broker.test.js +0 -172
  458. package/out/test/engine-integration.test.js +0 -297
  459. package/out/test/enginePaths.test.js +0 -195
  460. package/out/test/enginePublish.test.js +0 -82
  461. package/out/test/fleetDisplayUtils.test.js +0 -100
  462. package/out/test/gateway-client.test.js +0 -409
  463. package/out/test/gateway-install-source.test.js +0 -111
  464. package/out/test/gateway-lifecycle.test.js +0 -608
  465. package/out/test/gateway-outbound.test.js +0 -538
  466. package/out/test/gateway-reset-mappings.test.js +0 -221
  467. package/out/test/gateway-route-index.test.js +0 -235
  468. package/out/test/gateway-secrets-preflight.test.js +0 -127
  469. package/out/test/gateway-session-routing.test.js +0 -65
  470. package/out/test/gateway-session-store.test.js +0 -216
  471. package/out/test/github.test.js +0 -232
  472. package/out/test/governor-hardening.test.js +0 -222
  473. package/out/test/headless-sync.test.js +0 -301
  474. package/out/test/helpers/manifest-fixtures.js +0 -27
  475. package/out/test/idp-init.test.js +0 -151
  476. package/out/test/lease-signature.test.js +0 -357
  477. package/out/test/lease-trust-root.test.js +0 -273
  478. package/out/test/lease-validation.test.js +0 -224
  479. package/out/test/lease.test.js +0 -114
  480. package/out/test/localFleetAdapter.test.js +0 -91
  481. package/out/test/mcp-obo.test.js +0 -107
  482. package/out/test/mcp.test.js +0 -389
  483. package/out/test/model-routing.test.js +0 -133
  484. package/out/test/openclaw-channel-routing.test.js +0 -191
  485. package/out/test/pack-admission.test.js +0 -216
  486. package/out/test/pack-digest-parity.test.js +0 -140
  487. package/out/test/pack-reconcile.test.js +0 -183
  488. package/out/test/pack-signature-artifact.test.js +0 -103
  489. package/out/test/pack-signature.test.js +0 -176
  490. package/out/test/pack-trust-root.test.js +0 -202
  491. package/out/test/pathSafety.test.js +0 -63
  492. package/out/test/permissions.test.js +0 -175
  493. package/out/test/persistent-engine-worker.test.js +0 -220
  494. package/out/test/refreshPolicy.test.js +0 -60
  495. package/out/test/registry.test.js +0 -351
  496. package/out/test/remote-trust.test.js +0 -242
  497. package/out/test/runner-protocol.test.js +0 -249
  498. package/out/test/runtime.test.js +0 -349
  499. package/out/test/sandbox-driver.test.js +0 -553
  500. package/out/test/sandbox-hardening.test.js +0 -406
  501. package/out/test/sandbox-runner.test.js +0 -343
  502. package/out/test/sandbox-scope.test.js +0 -449
  503. package/out/test/scheduledFleetStorage.test.js +0 -72
  504. package/out/test/serve-cron-acceptance.test.js +0 -370
  505. package/out/test/serve-gateway-turn.test.js +0 -389
  506. package/out/test/serve-hardening.test.js +0 -591
  507. package/out/test/serveClient.test.js +0 -209
  508. package/out/test/sessionJsonlFleet.test.js +0 -78
  509. package/out/test/sessionShip.test.js +0 -618
  510. package/out/test/shared.test.js +0 -173
  511. package/out/test/skills-mcp.test.js +0 -299
  512. package/out/test/spotlightPublish.test.js +0 -327
  513. package/out/test/spotlightYaml.test.js +0 -58
  514. package/out/test/state-sync-peer.test.js +0 -156
  515. package/out/test/store-install-safe.test.js +0 -69
  516. package/out/test/store.test.js +0 -331
  517. package/out/test/stores.test.js +0 -504
  518. package/out/test/sync-switch.test.js +0 -251
  519. package/out/test/teamViewDiscovery.test.js +0 -90
  520. package/out/test/tls-bypass.test.js +0 -90
  521. package/out/test/toolPath.test.js +0 -120
  522. package/out/test/utils.test.js +0 -308
  523. package/out/test/viewsConfigMerge.test.js +0 -180
  524. package/out/test/warrant.test.js +0 -138
  525. package/out/test/windows-command-line.test.js +0 -75
  526. package/out/utils/agentEnvFile.js +0 -131
  527. package/out/utils/binary.js +0 -175
  528. package/out/utils/index.js +0 -37
  529. package/out/utils/network.js +0 -74
  530. package/out/utils/paths.js +0 -116
  531. package/out/utils/pid.js +0 -180
  532. package/out/utils/resolveNodeBinary.js +0 -168
  533. package/out/utils/windowsCommandLine.js +0 -29
  534. package/out/utils.js +0 -968
@@ -1,860 +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/agenthippoai/agenthippo-litellm: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
- // PR-F1 (agent-identity.md §8.5 G1): the edge must forward the user ASSERTION, not just
688
- // the identifier, or the turn carries no inboundToken — `passthrough` then fails closed on
689
- // every call and an `exchange` provider has no subject_token. Forged copies are stripped
690
- // for the same reason as the nonce: this one becomes the turn's inboundToken.
691
- assert.ok(snippet.includes('request_header -X-Agent-User-Assertion'), 'inbound X-Agent-User-Assertion is stripped at the edge');
692
- assert.ok(snippet.includes('copy_headers X-Agent-User X-Agent-User-Assertion'), 'the verified assertion is copied from /api/ide/me alongside the identity');
693
- // Only POST chat turns register.
694
- assert.ok(snippet.includes('@turnStart'), 'chat-turn matcher present');
695
- 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');
696
- // The registration hop itself: forward_auth to the connector control API, nonce copied
697
- // onto the proxied request, register token from the EDGE stack env (never the agent).
698
- assert.ok(snippet.includes('forward_auth @turnStart databricks-analyst-connector:9091'), 'turn registration targets the connector control API');
699
- assert.ok(snippet.includes('uri /edge/turn'), 'registration path is /edge/turn');
700
- assert.ok(snippet.includes('copy_headers X-Agent-Turn-Nonce'), 'minted nonce copied onto the request');
701
- assert.ok(snippet.includes('header_up Authorization "Bearer {$DATABRICKS_ANALYST_DATA_PLANE_TOKEN}"'), 'register token comes from the derived edge-stack env var');
702
- // Ordering (the Caddy footgun the hand-built overlay documents): two forward_auth in one
703
- // handle do NOT run in source order unless wrapped in route {} — identity must run first
704
- // so X-Agent-User exists when the sidecar mints the nonce.
705
- assert.ok(snippet.includes('route {'), 'gated sequence wrapped in route {} to force source order');
706
- const apiBlock = snippet.slice(snippet.indexOf('handle @apiWithAuth'));
707
- const identityIdx = apiBlock.indexOf('forward_auth auth-broker:9780');
708
- const turnIdx = apiBlock.indexOf('forward_auth @turnStart');
709
- const proxyIdx = apiBlock.indexOf('reverse_proxy databricks-analyst-agent:8080');
710
- assert.ok(identityIdx >= 0 && turnIdx > identityIdx && proxyIdx > turnIdx, 'order inside route {}: identity → turn registration → proxy');
711
- // Both gated paths carry the hop: Bearer API clients AND cookie-auth browser clients.
712
- assert.strictEqual(snippet.split('uri /edge/turn').length - 1, 2, 'turn registration on both the @apiWithAuth and browser catch-all paths');
713
- // The operator README says where the token goes (IdP stack env, never the agent).
714
- const readme = (0, deploy_init_1.renderTarget)('vm', ctx)['README.md'];
715
- assert.ok(readme.includes('DATABRICKS_ANALYST_DATA_PLANE_TOKEN'), 'README documents the edge-stack register token env var');
716
- });
717
- test('without edgeTurnConnector the route snippet is unchanged — no /edge/turn, no route {}', () => {
718
- const ctx = {
719
- ...CTX, ingress: 'edge-fed', idpUrl: 'https://auth.corp.example', colocate: true,
720
- };
721
- const snippet = (0, deploy_init_1.renderTarget)('vm', ctx)['agent-route.caddy'];
722
- assert.ok(!snippet.includes('/edge/turn') && !snippet.includes('@turnStart')
723
- && !snippet.includes('X-Agent-Turn-Nonce') && !snippet.includes('route {'), 'turn registration is strictly opt-in; default output must not change');
724
- });
725
- test('--colocate is a no-op without --ingress edge-fed (still ships the normal self-issued edge)', () => {
726
- const files = (0, deploy_init_1.renderTarget)('vm', { ...CTX, colocate: true });
727
- assert.ok(files['Caddyfile'], 'no ingress edge-fed → colocate does not apply, normal vm artifacts render');
728
- assert.ok(!files['agent-route.caddy']);
729
- });
730
- test('agent service does not load .env.auth; broker + oauth2-proxy do', () => {
731
- const compose = (0, deploy_init_1.renderTarget)('compose', CTX)['docker-compose.yml'];
732
- // The agent runs model-driven tool calls — it must never receive the token-signing key.
733
- const agentBlock = compose.slice(compose.indexOf(' agent:'), compose.indexOf(' oauth2-proxy:'));
734
- assert.ok(agentBlock.includes('env_file:'), 'sanity: located the agent service block');
735
- assert.ok(!agentBlock.includes('.env.auth'), 'agent must not load .env.auth (JWT signing key + OAuth secrets)');
736
- assert.ok(compose.includes('.env.auth'), 'broker/oauth2-proxy must load .env.auth');
737
- });
738
- });
739
- suite('deploy-init: deployCommand stages a self-contained pack', () => {
740
- let pack;
741
- let staging;
742
- setup(() => {
743
- pack = fs.mkdtempSync(path.join(os.tmpdir(), 'ah-pack-'));
744
- staging = fs.mkdtempSync(path.join(os.tmpdir(), 'ah-stage-'));
745
- 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');
746
- fs.writeFileSync(path.join(pack, 'AGENTS.md'), '# cs-test\n');
747
- fs.mkdirSync(path.join(pack, 'skills', 'demo', 'scripts'), { recursive: true });
748
- fs.writeFileSync(path.join(pack, 'skills', 'demo', 'scripts', 'run.sh'), 'echo hi\n');
749
- fs.writeFileSync(path.join(pack, 'skills', 'demo', 'scripts', 'requirements.txt'), 'requests\n');
750
- // Ignored by the copy filter: dev cache, secrets, source deploy/.
751
- fs.mkdirSync(path.join(pack, 'node_modules', 'foo'), { recursive: true });
752
- fs.writeFileSync(path.join(pack, 'node_modules', 'foo', 'index.js'), 'x');
753
- fs.writeFileSync(path.join(pack, '.env'), 'SECRET=1\n');
754
- fs.writeFileSync(path.join(pack, 'my-credentials.json'), '{}\n');
755
- fs.writeFileSync(path.join(pack, 'service-account.pem'), 'FAKE PEM\n');
756
- fs.writeFileSync(path.join(pack, 'id_rsa'), 'FAKE PRIVATE KEY\n');
757
- fs.mkdirSync(path.join(pack, 'deploy'), { recursive: true });
758
- fs.writeFileSync(path.join(pack, 'deploy', 'leftover.yaml'), 'stale\n');
759
- });
760
- teardown(() => {
761
- fs.rmSync(pack, { recursive: true, force: true });
762
- fs.rmSync(staging, { recursive: true, force: true });
763
- });
764
- test('copies pack into staging root, drops node_modules/.env/credentials, writes deploy/ + root .dockerignore', async () => {
765
- await (0, deploy_1.deployCommand)('init', pack, { target: 'cloudrun', out: staging, port: 8080, force: true });
766
- // Pack content at the staging root.
767
- assert.ok(fs.existsSync(path.join(staging, 'agent.yaml')), 'agent.yaml copied to staging root');
768
- assert.ok(fs.existsSync(path.join(staging, 'AGENTS.md')), 'AGENTS.md copied to staging root');
769
- assert.ok(fs.existsSync(path.join(staging, 'skills', 'demo', 'scripts', 'requirements.txt')), 'skill requirements.txt copied (needed by the build-time install step)');
770
- // Filtered out (mirrors .dockerignore): no dev caches, no secrets.
771
- assert.ok(!fs.existsSync(path.join(staging, 'node_modules')), 'node_modules must not be copied into staging');
772
- assert.ok(!fs.existsSync(path.join(staging, '.env')), '.env must not be copied into staging');
773
- assert.ok(!fs.existsSync(path.join(staging, 'my-credentials.json')), 'credentials json must not be copied');
774
- assert.ok(!fs.existsSync(path.join(staging, 'service-account.pem')), '.pem key must not be copied');
775
- assert.ok(!fs.existsSync(path.join(staging, 'id_rsa')), 'id_rsa key must not be copied');
776
- // The source pack's own deploy/ is not copied (the generator owns staging/deploy/).
777
- assert.ok(!fs.existsSync(path.join(staging, 'deploy', 'leftover.yaml')), 'source deploy/ must not be copied');
778
- // Generated artifacts under staging/deploy/.
779
- assert.ok(fs.existsSync(path.join(staging, 'deploy', 'Dockerfile')), 'Dockerfile at staging/deploy/Dockerfile');
780
- assert.ok(fs.existsSync(path.join(staging, 'deploy', 'service.yaml')), 'service.yaml at staging/deploy/');
781
- assert.ok(fs.existsSync(path.join(staging, 'deploy', 'cloudrun-deploy.sh')), 'cloudrun-deploy.sh at staging/deploy/');
782
- // .dockerignore at the staging root (build-context root), NOT under deploy/.
783
- assert.ok(fs.existsSync(path.join(staging, '.dockerignore')), '.dockerignore at staging root (context root)');
784
- assert.ok(!fs.existsSync(path.join(staging, 'deploy', '.dockerignore')), '.dockerignore must not be under deploy/ (Docker would ignore it)');
785
- // The generated build script self-anchors to the staging root.
786
- const sh = fs.readFileSync(path.join(staging, 'deploy', 'cloudrun-deploy.sh'), 'utf8');
787
- assert.ok(sh.includes('cd "$(dirname "$0")/.."'), 'cloudrun-deploy.sh anchors to staging root');
788
- 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');
789
- });
790
- test('--packdir flag is honored as an alternative to the positional arg', async () => {
791
- await (0, deploy_1.deployCommand)('init', undefined, { target: 'cloudrun', out: staging, port: 8080, force: true, packdir: pack });
792
- assert.ok(fs.existsSync(path.join(staging, 'agent.yaml')), 'packdir flag resolved the pack');
793
- assert.ok(fs.existsSync(path.join(staging, 'deploy', 'Dockerfile')), 'artifacts generated from packdir pack');
794
- });
795
- test('--blueprint team-pilot --platform cloudrun resolves to IAP (no Caddyfile, no oauth2-proxy)', async () => {
796
- await (0, deploy_1.deployCommand)('init', pack, {
797
- target: 'vm', blueprint: 'team-pilot', platform: 'cloudrun', out: staging, port: 8080, force: true,
798
- });
799
- assert.ok(fs.existsSync(path.join(staging, 'deploy', 'cloudrun-deploy.sh')), 'cloudrun artifacts generated');
800
- assert.ok(!fs.existsSync(path.join(staging, 'deploy', 'Caddyfile')), 'team-pilot on cloudrun is IAP — no Caddy edge');
801
- const sh = fs.readFileSync(path.join(staging, 'deploy', 'cloudrun-deploy.sh'), 'utf8');
802
- assert.ok(sh.includes('--iap'), 'blueprint-resolved --ingress iap reaches the actual IAP deploy path');
803
- });
804
- test('--blueprint enterprise-fleet --platform vm resolves to a federated (no oauth2-proxy) edge', async () => {
805
- await (0, deploy_1.deployCommand)('init', pack, {
806
- target: 'cloudrun', blueprint: 'enterprise-fleet', platform: 'vm', out: staging, port: 8080, force: true,
807
- idpUrl: 'https://auth.corp.example',
808
- });
809
- const caddy = fs.readFileSync(path.join(staging, 'deploy', 'Caddyfile'), 'utf8');
810
- const compose = fs.readFileSync(path.join(staging, 'deploy', 'docker-compose.yml'), 'utf8');
811
- assert.ok(!caddy.includes('oauth2-proxy:4180'), 'enterprise-fleet federates — no oauth2-proxy in the Caddyfile');
812
- assert.ok(!/^\s*oauth2-proxy:/m.test(compose), 'enterprise-fleet federates — no oauth2-proxy container');
813
- });
814
- });
815
- suite('deploy-init: copyPackToStaging dereferences symlinks + skips broken ones', () => {
816
- let pack;
817
- let staging;
818
- setup(() => {
819
- pack = fs.mkdtempSync(path.join(os.tmpdir(), 'ah-pack-'));
820
- staging = fs.mkdtempSync(path.join(os.tmpdir(), 'ah-stage-'));
821
- 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');
822
- // Real skill content + a shared file the skill links to (relative symlink → resolved on copy).
823
- fs.mkdirSync(path.join(pack, 'skills', 'demo'), { recursive: true });
824
- fs.writeFileSync(path.join(pack, 'skills', 'demo', 'REAL.md'), '# real content\n');
825
- fs.symlinkSync('REAL.md', path.join(pack, 'skills', 'demo', 'SKILL.md')); // valid relative symlink
826
- // Broken symlink: target does not exist (the data-analyst hydration bug pattern).
827
- fs.mkdirSync(path.join(pack, 'skills', 'broken'), { recursive: true });
828
- fs.symlinkSync('/nonexistent/abs/path/SKILL.md', path.join(pack, 'skills', 'broken', 'SKILL.md'));
829
- });
830
- teardown(() => {
831
- fs.rmSync(pack, { recursive: true, force: true });
832
- fs.rmSync(staging, { recursive: true, force: true });
833
- });
834
- test('valid symlinks are dereferenced to real files; broken symlinks are skipped + reported', () => {
835
- const broken = (0, deploy_1.copyPackToStaging)(pack, staging);
836
- // Valid symlink → real file content in staging (not a symlink). Docker-safe.
837
- const staged = path.join(staging, 'skills', 'demo', 'SKILL.md');
838
- assert.ok(fs.existsSync(staged), 'valid symlink content copied to staging');
839
- assert.ok(!fs.lstatSync(staged).isSymbolicLink(), 'staged entry is a real file, not a symlink');
840
- assert.strictEqual(fs.readFileSync(staged, 'utf8'), '# real content\n');
841
- // Broken symlink → not staged, and reported in the broken list.
842
- assert.ok(!fs.existsSync(path.join(staging, 'skills', 'broken', 'SKILL.md')), 'broken symlink must not be staged');
843
- assert.ok(broken.includes('skills/broken/SKILL.md'), 'broken symlink reported in returned list');
844
- });
845
- });
846
- suite('deploy-init: enterprise-deploy/idp/ (customer 0) stays in sync with `agenthippo idp init`', () => {
847
- // PLAN/deploy.md — AgentHippo's own auth.agenthippo.ai instance is "customer 0": it must be
848
- // stood up with the exact same `agenthippo idp init` a real enterprise customer would use,
849
- // not a bespoke hand-maintained copy. This fails loudly if the checked-in files drift from
850
- // what the generator produces for the same hostname (regenerate with:
851
- // `agenthippo idp init --hostname auth.agenthippo.ai --out enterprise-deploy/idp --force`).
852
- test('checked-in files are byte-identical to renderIdpArtifacts({ hostname: "auth.agenthippo.ai" })', () => {
853
- const idpDir = path.join(__dirname, '..', '..', '..', '..', 'enterprise-deploy', 'idp');
854
- const files = (0, idp_init_1.renderIdpArtifacts)({ hostname: 'auth.agenthippo.ai' });
855
- for (const [rel, expected] of Object.entries(files)) {
856
- const actual = fs.readFileSync(path.join(idpDir, rel), 'utf8');
857
- assert.strictEqual(actual, expected, `enterprise-deploy/idp/${rel} is stale — regenerate with: agenthippo idp init --hostname auth.agenthippo.ai --out enterprise-deploy/idp --force`);
858
- }
859
- });
860
- });