@portel/photon 1.4.1 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (395) hide show
  1. package/README.md +326 -1177
  2. package/dist/auto-ui/beam.d.ts +14 -0
  3. package/dist/auto-ui/beam.d.ts.map +1 -0
  4. package/dist/auto-ui/beam.js +3057 -0
  5. package/dist/auto-ui/beam.js.map +1 -0
  6. package/dist/auto-ui/bridge/index.d.ts +37 -0
  7. package/dist/auto-ui/bridge/index.d.ts.map +1 -0
  8. package/dist/auto-ui/bridge/index.js +555 -0
  9. package/dist/auto-ui/bridge/index.js.map +1 -0
  10. package/dist/auto-ui/bridge/openai-shim.d.ts +20 -0
  11. package/dist/auto-ui/bridge/openai-shim.d.ts.map +1 -0
  12. package/dist/auto-ui/bridge/openai-shim.js +231 -0
  13. package/dist/auto-ui/bridge/openai-shim.js.map +1 -0
  14. package/dist/auto-ui/bridge/photon-app.d.ts +162 -0
  15. package/dist/auto-ui/bridge/photon-app.d.ts.map +1 -0
  16. package/dist/auto-ui/bridge/photon-app.js +460 -0
  17. package/dist/auto-ui/bridge/photon-app.js.map +1 -0
  18. package/dist/auto-ui/bridge/types.d.ts +128 -0
  19. package/dist/auto-ui/bridge/types.d.ts.map +1 -0
  20. package/dist/auto-ui/bridge/types.js +7 -0
  21. package/dist/auto-ui/bridge/types.js.map +1 -0
  22. package/dist/auto-ui/components/card.d.ts +13 -0
  23. package/dist/auto-ui/components/card.d.ts.map +1 -0
  24. package/dist/auto-ui/components/card.js +64 -0
  25. package/dist/auto-ui/components/card.js.map +1 -0
  26. package/dist/auto-ui/components/form.d.ts +15 -0
  27. package/dist/auto-ui/components/form.d.ts.map +1 -0
  28. package/dist/auto-ui/components/form.js +72 -0
  29. package/dist/auto-ui/components/form.js.map +1 -0
  30. package/dist/auto-ui/components/list.d.ts +13 -0
  31. package/dist/auto-ui/components/list.d.ts.map +1 -0
  32. package/dist/auto-ui/components/list.js +58 -0
  33. package/dist/auto-ui/components/list.js.map +1 -0
  34. package/dist/auto-ui/components/progress.d.ts +18 -0
  35. package/dist/auto-ui/components/progress.d.ts.map +1 -0
  36. package/dist/auto-ui/components/progress.js +125 -0
  37. package/dist/auto-ui/components/progress.js.map +1 -0
  38. package/dist/auto-ui/components/table.d.ts +13 -0
  39. package/dist/auto-ui/components/table.d.ts.map +1 -0
  40. package/dist/auto-ui/components/table.js +82 -0
  41. package/dist/auto-ui/components/table.js.map +1 -0
  42. package/dist/auto-ui/components/tree.d.ts +13 -0
  43. package/dist/auto-ui/components/tree.d.ts.map +1 -0
  44. package/dist/auto-ui/components/tree.js +61 -0
  45. package/dist/auto-ui/components/tree.js.map +1 -0
  46. package/dist/auto-ui/daemon-tools.d.ts +45 -0
  47. package/dist/auto-ui/daemon-tools.d.ts.map +1 -0
  48. package/dist/auto-ui/daemon-tools.js +580 -0
  49. package/dist/auto-ui/daemon-tools.js.map +1 -0
  50. package/dist/auto-ui/design-system/index.d.ts +21 -0
  51. package/dist/auto-ui/design-system/index.d.ts.map +1 -0
  52. package/dist/auto-ui/design-system/index.js +27 -0
  53. package/dist/auto-ui/design-system/index.js.map +1 -0
  54. package/dist/auto-ui/design-system/tokens.d.ts +9 -0
  55. package/dist/auto-ui/design-system/tokens.d.ts.map +1 -0
  56. package/dist/auto-ui/design-system/tokens.js +27 -0
  57. package/dist/auto-ui/design-system/tokens.js.map +1 -0
  58. package/dist/auto-ui/design-system/transaction-ui.d.ts +70 -0
  59. package/dist/auto-ui/design-system/transaction-ui.d.ts.map +1 -0
  60. package/dist/auto-ui/design-system/transaction-ui.js +982 -0
  61. package/dist/auto-ui/design-system/transaction-ui.js.map +1 -0
  62. package/dist/auto-ui/frontend/index.html +84 -0
  63. package/dist/auto-ui/index.d.ts +23 -0
  64. package/dist/auto-ui/index.d.ts.map +1 -0
  65. package/dist/auto-ui/index.js +28 -0
  66. package/dist/auto-ui/index.js.map +1 -0
  67. package/dist/auto-ui/openapi-generator.d.ts +71 -0
  68. package/dist/auto-ui/openapi-generator.d.ts.map +1 -0
  69. package/dist/auto-ui/openapi-generator.js +223 -0
  70. package/dist/auto-ui/openapi-generator.js.map +1 -0
  71. package/dist/auto-ui/photon-bridge.d.ts +159 -0
  72. package/dist/auto-ui/photon-bridge.d.ts.map +1 -0
  73. package/dist/auto-ui/photon-bridge.js +262 -0
  74. package/dist/auto-ui/photon-bridge.js.map +1 -0
  75. package/dist/auto-ui/photon-host.d.ts +113 -0
  76. package/dist/auto-ui/photon-host.d.ts.map +1 -0
  77. package/dist/auto-ui/photon-host.js +284 -0
  78. package/dist/auto-ui/photon-host.js.map +1 -0
  79. package/dist/auto-ui/platform-compat.d.ts +71 -0
  80. package/dist/auto-ui/platform-compat.d.ts.map +1 -0
  81. package/dist/auto-ui/platform-compat.js +628 -0
  82. package/dist/auto-ui/platform-compat.js.map +1 -0
  83. package/dist/auto-ui/playground-html.d.ts +15 -0
  84. package/dist/auto-ui/playground-html.d.ts.map +1 -0
  85. package/dist/auto-ui/playground-html.js +1113 -0
  86. package/dist/auto-ui/playground-html.js.map +1 -0
  87. package/dist/auto-ui/playground-server.d.ts +7 -0
  88. package/dist/auto-ui/playground-server.d.ts.map +1 -0
  89. package/dist/auto-ui/playground-server.js +840 -0
  90. package/dist/auto-ui/playground-server.js.map +1 -0
  91. package/dist/auto-ui/registry.d.ts +13 -0
  92. package/dist/auto-ui/registry.d.ts.map +1 -0
  93. package/dist/auto-ui/registry.js +62 -0
  94. package/dist/auto-ui/registry.js.map +1 -0
  95. package/dist/auto-ui/renderer.d.ts +14 -0
  96. package/dist/auto-ui/renderer.d.ts.map +1 -0
  97. package/dist/auto-ui/renderer.js +88 -0
  98. package/dist/auto-ui/renderer.js.map +1 -0
  99. package/dist/auto-ui/rendering/components.d.ts +29 -0
  100. package/dist/auto-ui/rendering/components.d.ts.map +1 -0
  101. package/dist/auto-ui/rendering/components.js +773 -0
  102. package/dist/auto-ui/rendering/components.js.map +1 -0
  103. package/dist/auto-ui/rendering/field-analyzer.d.ts +48 -0
  104. package/dist/auto-ui/rendering/field-analyzer.d.ts.map +1 -0
  105. package/dist/auto-ui/rendering/field-analyzer.js +270 -0
  106. package/dist/auto-ui/rendering/field-analyzer.js.map +1 -0
  107. package/dist/auto-ui/rendering/field-renderers.d.ts +64 -0
  108. package/dist/auto-ui/rendering/field-renderers.d.ts.map +1 -0
  109. package/dist/auto-ui/rendering/field-renderers.js +317 -0
  110. package/dist/auto-ui/rendering/field-renderers.js.map +1 -0
  111. package/dist/auto-ui/rendering/index.d.ts +28 -0
  112. package/dist/auto-ui/rendering/index.d.ts.map +1 -0
  113. package/dist/auto-ui/rendering/index.js +60 -0
  114. package/dist/auto-ui/rendering/index.js.map +1 -0
  115. package/dist/auto-ui/rendering/layout-selector.d.ts +48 -0
  116. package/dist/auto-ui/rendering/layout-selector.d.ts.map +1 -0
  117. package/dist/auto-ui/rendering/layout-selector.js +352 -0
  118. package/dist/auto-ui/rendering/layout-selector.js.map +1 -0
  119. package/dist/auto-ui/rendering/template-engine.d.ts +41 -0
  120. package/dist/auto-ui/rendering/template-engine.d.ts.map +1 -0
  121. package/dist/auto-ui/rendering/template-engine.js +238 -0
  122. package/dist/auto-ui/rendering/template-engine.js.map +1 -0
  123. package/dist/auto-ui/streamable-http-transport.d.ts +103 -0
  124. package/dist/auto-ui/streamable-http-transport.d.ts.map +1 -0
  125. package/dist/auto-ui/streamable-http-transport.js +1875 -0
  126. package/dist/auto-ui/streamable-http-transport.js.map +1 -0
  127. package/dist/auto-ui/types.d.ts +384 -0
  128. package/dist/auto-ui/types.d.ts.map +1 -0
  129. package/dist/auto-ui/types.js +92 -0
  130. package/dist/auto-ui/types.js.map +1 -0
  131. package/dist/beam.bundle.js +63137 -0
  132. package/dist/beam.bundle.js.map +7 -0
  133. package/dist/claude-code-plugin.d.ts.map +1 -1
  134. package/dist/claude-code-plugin.js +30 -30
  135. package/dist/claude-code-plugin.js.map +1 -1
  136. package/dist/cli/commands/info.d.ts +11 -0
  137. package/dist/cli/commands/info.d.ts.map +1 -0
  138. package/dist/cli/commands/info.js +313 -0
  139. package/dist/cli/commands/info.js.map +1 -0
  140. package/dist/cli/commands/marketplace.d.ts +11 -0
  141. package/dist/cli/commands/marketplace.d.ts.map +1 -0
  142. package/dist/cli/commands/marketplace.js +198 -0
  143. package/dist/cli/commands/marketplace.js.map +1 -0
  144. package/dist/cli/commands/package-app.d.ts +9 -0
  145. package/dist/cli/commands/package-app.d.ts.map +1 -0
  146. package/dist/cli/commands/package-app.js +191 -0
  147. package/dist/cli/commands/package-app.js.map +1 -0
  148. package/dist/cli/commands/package.d.ts +11 -0
  149. package/dist/cli/commands/package.d.ts.map +1 -0
  150. package/dist/cli/commands/package.js +573 -0
  151. package/dist/cli/commands/package.js.map +1 -0
  152. package/dist/cli-alias.d.ts.map +1 -1
  153. package/dist/cli-alias.js +30 -28
  154. package/dist/cli-alias.js.map +1 -1
  155. package/dist/cli-formatter.d.ts +8 -24
  156. package/dist/cli-formatter.d.ts.map +1 -1
  157. package/dist/cli-formatter.js +8 -325
  158. package/dist/cli-formatter.js.map +1 -1
  159. package/dist/cli.d.ts +15 -1
  160. package/dist/cli.d.ts.map +1 -1
  161. package/dist/cli.js +1166 -1131
  162. package/dist/cli.js.map +1 -1
  163. package/dist/daemon/client.d.ts +84 -3
  164. package/dist/daemon/client.d.ts.map +1 -1
  165. package/dist/daemon/client.js +561 -11
  166. package/dist/daemon/client.js.map +1 -1
  167. package/dist/daemon/manager.d.ts +51 -12
  168. package/dist/daemon/manager.d.ts.map +1 -1
  169. package/dist/daemon/manager.js +122 -61
  170. package/dist/daemon/manager.js.map +1 -1
  171. package/dist/daemon/protocol.d.ts +62 -6
  172. package/dist/daemon/protocol.d.ts.map +1 -1
  173. package/dist/daemon/protocol.js +76 -1
  174. package/dist/daemon/protocol.js.map +1 -1
  175. package/dist/daemon/server.d.ts +6 -6
  176. package/dist/daemon/server.js +743 -133
  177. package/dist/daemon/server.js.map +1 -1
  178. package/dist/daemon/session-manager.d.ts +8 -1
  179. package/dist/daemon/session-manager.d.ts.map +1 -1
  180. package/dist/daemon/session-manager.js +32 -9
  181. package/dist/daemon/session-manager.js.map +1 -1
  182. package/dist/deploy/cloudflare.d.ts +12 -0
  183. package/dist/deploy/cloudflare.d.ts.map +1 -0
  184. package/dist/deploy/cloudflare.js +216 -0
  185. package/dist/deploy/cloudflare.js.map +1 -0
  186. package/dist/index.d.ts +1 -0
  187. package/dist/index.d.ts.map +1 -1
  188. package/dist/index.js +3 -0
  189. package/dist/index.js.map +1 -1
  190. package/dist/loader.d.ts +191 -21
  191. package/dist/loader.d.ts.map +1 -1
  192. package/dist/loader.js +1186 -319
  193. package/dist/loader.js.map +1 -1
  194. package/dist/markdown-utils.d.ts +8 -0
  195. package/dist/markdown-utils.d.ts.map +1 -0
  196. package/dist/markdown-utils.js +63 -0
  197. package/dist/markdown-utils.js.map +1 -0
  198. package/dist/marketplace-manager.d.ts +10 -0
  199. package/dist/marketplace-manager.d.ts.map +1 -1
  200. package/dist/marketplace-manager.js +112 -28
  201. package/dist/marketplace-manager.js.map +1 -1
  202. package/dist/mcp-client.d.ts +9 -0
  203. package/dist/mcp-client.d.ts.map +1 -0
  204. package/dist/mcp-client.js +11 -0
  205. package/dist/mcp-client.js.map +1 -0
  206. package/dist/mcp-elicitation.d.ts +32 -0
  207. package/dist/mcp-elicitation.d.ts.map +1 -0
  208. package/dist/mcp-elicitation.js +26 -0
  209. package/dist/mcp-elicitation.js.map +1 -0
  210. package/dist/path-resolver.d.ts +9 -12
  211. package/dist/path-resolver.d.ts.map +1 -1
  212. package/dist/path-resolver.js +13 -43
  213. package/dist/path-resolver.js.map +1 -1
  214. package/dist/photon-cli-runner.d.ts.map +1 -1
  215. package/dist/photon-cli-runner.js +204 -77
  216. package/dist/photon-cli-runner.js.map +1 -1
  217. package/dist/photon-doc-extractor.d.ts +89 -0
  218. package/dist/photon-doc-extractor.d.ts.map +1 -1
  219. package/dist/photon-doc-extractor.js +560 -32
  220. package/dist/photon-doc-extractor.js.map +1 -1
  221. package/dist/photons/maker.photon.d.ts +182 -0
  222. package/dist/photons/maker.photon.d.ts.map +1 -0
  223. package/dist/photons/maker.photon.js +504 -0
  224. package/dist/photons/maker.photon.js.map +1 -0
  225. package/dist/photons/maker.photon.ts +626 -0
  226. package/dist/photons/marketplace.photon.d.ts +110 -0
  227. package/dist/photons/marketplace.photon.d.ts.map +1 -0
  228. package/dist/photons/marketplace.photon.js +260 -0
  229. package/dist/photons/marketplace.photon.js.map +1 -0
  230. package/dist/photons/marketplace.photon.ts +378 -0
  231. package/dist/photons/tunnel.photon.d.ts +80 -0
  232. package/dist/photons/tunnel.photon.d.ts.map +1 -0
  233. package/dist/photons/tunnel.photon.js +269 -0
  234. package/dist/photons/tunnel.photon.js.map +1 -0
  235. package/dist/photons/tunnel.photon.ts +345 -0
  236. package/dist/security-scanner.d.ts.map +1 -1
  237. package/dist/security-scanner.js +18 -15
  238. package/dist/security-scanner.js.map +1 -1
  239. package/dist/serv/auth/jwt.d.ts +89 -0
  240. package/dist/serv/auth/jwt.d.ts.map +1 -0
  241. package/dist/serv/auth/jwt.js +239 -0
  242. package/dist/serv/auth/jwt.js.map +1 -0
  243. package/dist/serv/auth/oauth.d.ts +117 -0
  244. package/dist/serv/auth/oauth.d.ts.map +1 -0
  245. package/dist/serv/auth/oauth.js +395 -0
  246. package/dist/serv/auth/oauth.js.map +1 -0
  247. package/dist/serv/auth/well-known.d.ts +60 -0
  248. package/dist/serv/auth/well-known.d.ts.map +1 -0
  249. package/dist/serv/auth/well-known.js +154 -0
  250. package/dist/serv/auth/well-known.js.map +1 -0
  251. package/dist/serv/db/d1-client.d.ts +65 -0
  252. package/dist/serv/db/d1-client.d.ts.map +1 -0
  253. package/dist/serv/db/d1-client.js +137 -0
  254. package/dist/serv/db/d1-client.js.map +1 -0
  255. package/dist/serv/db/d1-stores.d.ts +62 -0
  256. package/dist/serv/db/d1-stores.d.ts.map +1 -0
  257. package/dist/serv/db/d1-stores.js +307 -0
  258. package/dist/serv/db/d1-stores.js.map +1 -0
  259. package/dist/serv/index.d.ts +114 -0
  260. package/dist/serv/index.d.ts.map +1 -0
  261. package/dist/serv/index.js +172 -0
  262. package/dist/serv/index.js.map +1 -0
  263. package/dist/serv/local.d.ts +118 -0
  264. package/dist/serv/local.d.ts.map +1 -0
  265. package/dist/serv/local.js +392 -0
  266. package/dist/serv/local.js.map +1 -0
  267. package/dist/serv/middleware/auth.d.ts +66 -0
  268. package/dist/serv/middleware/auth.d.ts.map +1 -0
  269. package/dist/serv/middleware/auth.js +178 -0
  270. package/dist/serv/middleware/auth.js.map +1 -0
  271. package/dist/serv/middleware/tenant.d.ts +94 -0
  272. package/dist/serv/middleware/tenant.d.ts.map +1 -0
  273. package/dist/serv/middleware/tenant.js +152 -0
  274. package/dist/serv/middleware/tenant.js.map +1 -0
  275. package/dist/serv/runtime/executor.d.ts +76 -0
  276. package/dist/serv/runtime/executor.d.ts.map +1 -0
  277. package/dist/serv/runtime/executor.js +105 -0
  278. package/dist/serv/runtime/executor.js.map +1 -0
  279. package/dist/serv/runtime/index.d.ts +8 -0
  280. package/dist/serv/runtime/index.d.ts.map +1 -0
  281. package/dist/serv/runtime/index.js +10 -0
  282. package/dist/serv/runtime/index.js.map +1 -0
  283. package/dist/serv/runtime/oauth-context.d.ts +121 -0
  284. package/dist/serv/runtime/oauth-context.d.ts.map +1 -0
  285. package/dist/serv/runtime/oauth-context.js +153 -0
  286. package/dist/serv/runtime/oauth-context.js.map +1 -0
  287. package/dist/serv/session/kv-store.d.ts +54 -0
  288. package/dist/serv/session/kv-store.d.ts.map +1 -0
  289. package/dist/serv/session/kv-store.js +149 -0
  290. package/dist/serv/session/kv-store.js.map +1 -0
  291. package/dist/serv/session/store.d.ts +113 -0
  292. package/dist/serv/session/store.d.ts.map +1 -0
  293. package/dist/serv/session/store.js +284 -0
  294. package/dist/serv/session/store.js.map +1 -0
  295. package/dist/serv/types/index.d.ts +147 -0
  296. package/dist/serv/types/index.d.ts.map +1 -0
  297. package/dist/serv/types/index.js +8 -0
  298. package/dist/serv/types/index.js.map +1 -0
  299. package/dist/serv/vault/token-vault.d.ts +102 -0
  300. package/dist/serv/vault/token-vault.d.ts.map +1 -0
  301. package/dist/serv/vault/token-vault.js +177 -0
  302. package/dist/serv/vault/token-vault.js.map +1 -0
  303. package/dist/server.d.ts +184 -0
  304. package/dist/server.d.ts.map +1 -1
  305. package/dist/server.js +1995 -86
  306. package/dist/server.js.map +1 -1
  307. package/dist/shared/cli-sections.d.ts +6 -0
  308. package/dist/shared/cli-sections.d.ts.map +1 -0
  309. package/dist/shared/cli-sections.js +16 -0
  310. package/dist/shared/cli-sections.js.map +1 -0
  311. package/dist/shared/cli-utils.d.ts +81 -0
  312. package/dist/shared/cli-utils.d.ts.map +1 -0
  313. package/dist/shared/cli-utils.js +174 -0
  314. package/dist/shared/cli-utils.js.map +1 -0
  315. package/dist/shared/config-docs.d.ts +6 -0
  316. package/dist/shared/config-docs.d.ts.map +1 -0
  317. package/dist/shared/config-docs.js +6 -0
  318. package/dist/shared/config-docs.js.map +1 -0
  319. package/dist/shared/error-handler.d.ts +128 -0
  320. package/dist/shared/error-handler.d.ts.map +1 -0
  321. package/dist/shared/error-handler.js +342 -0
  322. package/dist/shared/error-handler.js.map +1 -0
  323. package/dist/shared/logger.d.ts +42 -0
  324. package/dist/shared/logger.d.ts.map +1 -0
  325. package/dist/shared/logger.js +123 -0
  326. package/dist/shared/logger.js.map +1 -0
  327. package/dist/shared/performance.d.ts +65 -0
  328. package/dist/shared/performance.d.ts.map +1 -0
  329. package/dist/shared/performance.js +136 -0
  330. package/dist/shared/performance.js.map +1 -0
  331. package/dist/shared/task-runner.d.ts +2 -0
  332. package/dist/shared/task-runner.d.ts.map +1 -0
  333. package/dist/shared/task-runner.js +16 -0
  334. package/dist/shared/task-runner.js.map +1 -0
  335. package/dist/shared/validation.d.ts +6 -0
  336. package/dist/shared/validation.d.ts.map +1 -0
  337. package/dist/shared/validation.js +6 -0
  338. package/dist/shared/validation.js.map +1 -0
  339. package/dist/shared-utils.d.ts +63 -0
  340. package/dist/shared-utils.d.ts.map +1 -0
  341. package/dist/shared-utils.js +123 -0
  342. package/dist/shared-utils.js.map +1 -0
  343. package/dist/template-manager.d.ts +23 -2
  344. package/dist/template-manager.d.ts.map +1 -1
  345. package/dist/template-manager.js +176 -87
  346. package/dist/template-manager.js.map +1 -1
  347. package/dist/test-client.d.ts.map +1 -1
  348. package/dist/test-client.js +10 -8
  349. package/dist/test-client.js.map +1 -1
  350. package/dist/test-runner.d.ts +52 -0
  351. package/dist/test-runner.d.ts.map +1 -0
  352. package/dist/test-runner.js +785 -0
  353. package/dist/test-runner.js.map +1 -0
  354. package/dist/testing.d.ts +103 -0
  355. package/dist/testing.d.ts.map +1 -0
  356. package/dist/testing.js +163 -0
  357. package/dist/testing.js.map +1 -0
  358. package/dist/version-checker.d.ts.map +1 -1
  359. package/dist/version-checker.js +2 -2
  360. package/dist/version-checker.js.map +1 -1
  361. package/dist/version.d.ts +10 -0
  362. package/dist/version.d.ts.map +1 -0
  363. package/dist/version.js +21 -0
  364. package/dist/version.js.map +1 -0
  365. package/dist/watcher.d.ts +6 -3
  366. package/dist/watcher.d.ts.map +1 -1
  367. package/dist/watcher.js +49 -10
  368. package/dist/watcher.js.map +1 -1
  369. package/package.json +57 -7
  370. package/templates/cloudflare/worker.ts.template +381 -0
  371. package/templates/cloudflare/wrangler.toml.template +9 -0
  372. package/dist/base.d.ts +0 -58
  373. package/dist/base.d.ts.map +0 -1
  374. package/dist/base.js +0 -92
  375. package/dist/base.js.map +0 -1
  376. package/dist/dependency-manager.d.ts +0 -49
  377. package/dist/dependency-manager.d.ts.map +0 -1
  378. package/dist/dependency-manager.js +0 -165
  379. package/dist/dependency-manager.js.map +0 -1
  380. package/dist/registry-manager.d.ts +0 -76
  381. package/dist/registry-manager.d.ts.map +0 -1
  382. package/dist/registry-manager.js +0 -220
  383. package/dist/registry-manager.js.map +0 -1
  384. package/dist/schema-extractor.d.ts +0 -110
  385. package/dist/schema-extractor.d.ts.map +0 -1
  386. package/dist/schema-extractor.js +0 -727
  387. package/dist/schema-extractor.js.map +0 -1
  388. package/dist/test-marketplace-sources.d.ts +0 -5
  389. package/dist/test-marketplace-sources.d.ts.map +0 -1
  390. package/dist/test-marketplace-sources.js +0 -53
  391. package/dist/test-marketplace-sources.js.map +0 -1
  392. package/dist/types.d.ts +0 -109
  393. package/dist/types.d.ts.map +0 -1
  394. package/dist/types.js +0 -12
  395. package/dist/types.js.map +0 -1
@@ -0,0 +1,785 @@
1
+ /**
2
+ * Photon Test Runner
3
+ *
4
+ * Discovers and runs test* methods in photons
5
+ * Supports multiple test modes:
6
+ * - direct: Call methods directly on instance (unit tests)
7
+ * - cli: Call methods via CLI subprocess (integration tests)
8
+ * - mcp: Call methods via MCP protocol (integration tests)
9
+ *
10
+ * Usage: photon test [photon] [testName] [--mode direct|cli|all]
11
+ */
12
+ import * as path from 'path';
13
+ import { existsSync } from 'fs';
14
+ import { spawn } from 'child_process';
15
+ import { fileURLToPath } from 'url';
16
+ import { PhotonLoader } from './loader.js';
17
+ import { listPhotonMCPs, resolvePhotonPath } from './path-resolver.js';
18
+ import { logger } from './shared/logger.js';
19
+ import { SchemaExtractor } from '@portel/photon-core';
20
+ import chalk from 'chalk';
21
+ const __filename = fileURLToPath(import.meta.url);
22
+ const __dirname = path.dirname(__filename);
23
+ // Get the path to the CLI binary (either local dev or installed)
24
+ const CLI_PATH = path.resolve(__dirname, 'cli.js');
25
+ // ══════════════════════════════════════════════════════════════════════════════
26
+ // ISSUE URL GENERATOR
27
+ // ══════════════════════════════════════════════════════════════════════════════
28
+ const ISSUE_REPO = 'https://github.com/anthropics/photon';
29
+ /**
30
+ * Generate a pre-filled GitHub issue URL for a failed test
31
+ */
32
+ function generateIssueUrl(result, workingDir) {
33
+ const title = encodeURIComponent(`[Test Failure] ${result.photon}.${result.test} (${result.mode} mode)`);
34
+ const body = encodeURIComponent(`## Test Failure Report
35
+
36
+ **Photon:** \`${result.photon}\`
37
+ **Test:** \`${result.test}\`
38
+ **Mode:** ${result.mode}
39
+ **Duration:** ${result.duration}ms
40
+
41
+ ### Error
42
+ \`\`\`
43
+ ${result.error || 'No error message'}
44
+ \`\`\`
45
+
46
+ ### Environment
47
+ - Working Directory: \`${workingDir}\`
48
+ - Node Version: \`${process.version}\`
49
+ - Platform: \`${process.platform}\`
50
+
51
+ ### Steps to Reproduce
52
+ \`\`\`bash
53
+ photon test ${result.photon} ${result.test} --mode ${result.mode}
54
+ \`\`\`
55
+
56
+ ### Additional Context
57
+ <!-- Add any additional context about the problem here -->
58
+ `);
59
+ return `${ISSUE_REPO}/issues/new?title=${title}&body=${body}&labels=bug,test-failure`;
60
+ }
61
+ // ══════════════════════════════════════════════════════════════════════════════
62
+ // DIRECT TEST EXECUTION
63
+ // ══════════════════════════════════════════════════════════════════════════════
64
+ /**
65
+ * Extract test methods from a photon instance
66
+ * Excludes testBeforeAll and testAfterAll (lifecycle hooks)
67
+ */
68
+ function getTestMethods(instance) {
69
+ const methods = [];
70
+ const proto = Object.getPrototypeOf(instance);
71
+ for (const name of Object.getOwnPropertyNames(proto)) {
72
+ if (name.startsWith('test') &&
73
+ typeof instance[name] === 'function' &&
74
+ name !== 'constructor' &&
75
+ name !== 'testBeforeAll' &&
76
+ name !== 'testAfterAll') {
77
+ methods.push(name);
78
+ }
79
+ }
80
+ return methods.sort();
81
+ }
82
+ /**
83
+ * Check if photon has lifecycle hooks
84
+ */
85
+ function hasLifecycleHook(instance, hookName) {
86
+ return typeof instance[hookName] === 'function';
87
+ }
88
+ /**
89
+ * Run a single test method directly
90
+ */
91
+ async function runDirectTest(instance, photonName, testName, workingDir) {
92
+ const start = Date.now();
93
+ try {
94
+ const result = await instance[testName]();
95
+ const duration = Date.now() - start;
96
+ // Check result format
97
+ if (result && typeof result === 'object') {
98
+ // Handle skipped tests
99
+ if (result.skipped === true) {
100
+ return {
101
+ photon: photonName,
102
+ test: testName,
103
+ passed: true,
104
+ skipped: true,
105
+ duration,
106
+ message: result.reason || 'Skipped',
107
+ mode: 'direct',
108
+ };
109
+ }
110
+ if (result.passed === false) {
111
+ const failResult = {
112
+ photon: photonName,
113
+ test: testName,
114
+ passed: false,
115
+ duration,
116
+ error: result.error || result.message || 'Test returned passed: false',
117
+ mode: 'direct',
118
+ };
119
+ failResult.issueUrl = generateIssueUrl(failResult, workingDir);
120
+ return failResult;
121
+ }
122
+ return {
123
+ photon: photonName,
124
+ test: testName,
125
+ passed: true,
126
+ duration,
127
+ message: result.message,
128
+ mode: 'direct',
129
+ };
130
+ }
131
+ // If no explicit result, consider it passed
132
+ return {
133
+ photon: photonName,
134
+ test: testName,
135
+ passed: true,
136
+ duration,
137
+ mode: 'direct',
138
+ };
139
+ }
140
+ catch (error) {
141
+ const duration = Date.now() - start;
142
+ const failResult = {
143
+ photon: photonName,
144
+ test: testName,
145
+ passed: false,
146
+ duration,
147
+ error: error.message || String(error),
148
+ mode: 'direct',
149
+ };
150
+ failResult.issueUrl = generateIssueUrl(failResult, workingDir);
151
+ return failResult;
152
+ }
153
+ }
154
+ // ══════════════════════════════════════════════════════════════════════════════
155
+ // CLI INTERFACE TEST EXECUTION
156
+ // ══════════════════════════════════════════════════════════════════════════════
157
+ /**
158
+ * Get public methods with their schemas for interface testing
159
+ */
160
+ async function getPublicMethods(photonPath) {
161
+ try {
162
+ const extractor = new SchemaExtractor();
163
+ const schemas = await extractor.extractFromFile(photonPath);
164
+ return schemas.map((schema) => ({
165
+ name: schema.name,
166
+ params: schema.inputSchema?.properties
167
+ ? Object.entries(schema.inputSchema.properties).map(([name, prop]) => ({
168
+ name,
169
+ type: prop.type || 'string',
170
+ required: schema.inputSchema?.required?.includes(name) || false,
171
+ example: prop.examples?.[0],
172
+ }))
173
+ : [],
174
+ }));
175
+ }
176
+ catch {
177
+ return [];
178
+ }
179
+ }
180
+ /**
181
+ * Build example params for a method from its schema
182
+ */
183
+ function buildExampleParams(method) {
184
+ const params = {};
185
+ for (const param of method.params) {
186
+ if (param.example !== undefined) {
187
+ params[param.name] = param.example;
188
+ }
189
+ else if (param.required) {
190
+ // Generate default values based on type
191
+ switch (param.type) {
192
+ case 'string':
193
+ params[param.name] = 'test';
194
+ break;
195
+ case 'number':
196
+ case 'integer':
197
+ params[param.name] = 1;
198
+ break;
199
+ case 'boolean':
200
+ params[param.name] = true;
201
+ break;
202
+ case 'array':
203
+ params[param.name] = [];
204
+ break;
205
+ case 'object':
206
+ params[param.name] = {};
207
+ break;
208
+ }
209
+ }
210
+ }
211
+ return params;
212
+ }
213
+ /**
214
+ * Run a method via CLI subprocess
215
+ */
216
+ async function runCliTest(photonName, methodName, params, workingDir) {
217
+ const start = Date.now();
218
+ return new Promise((resolve) => {
219
+ // Build CLI arguments (use 'cli' command - the implicit run mode)
220
+ const args = ['cli', photonName, methodName, '--json', '--dir', workingDir];
221
+ // Add params as CLI flags
222
+ for (const [key, value] of Object.entries(params)) {
223
+ if (typeof value === 'object') {
224
+ args.push(`--${key}`, JSON.stringify(value));
225
+ }
226
+ else {
227
+ args.push(`--${key}`, String(value));
228
+ }
229
+ }
230
+ const proc = spawn('node', [CLI_PATH, ...args], {
231
+ cwd: workingDir,
232
+ stdio: ['pipe', 'pipe', 'pipe'],
233
+ timeout: 30000, // 30 second timeout
234
+ });
235
+ let stdout = '';
236
+ let stderr = '';
237
+ proc.stdout?.on('data', (data) => {
238
+ stdout += data.toString();
239
+ });
240
+ proc.stderr?.on('data', (data) => {
241
+ stderr += data.toString();
242
+ });
243
+ proc.on('close', (code) => {
244
+ const duration = Date.now() - start;
245
+ // Interface tests verify the transport layer works, not business logic.
246
+ // A method that returns an error still proves the CLI interface works.
247
+ // Check if we got any output (stdout or stderr) - indicates the CLI ran
248
+ const hasOutput = stdout.trim() || stderr.trim();
249
+ // Check for specific CLI infrastructure errors (not method errors)
250
+ const isInfraError = stderr.includes('Photon not found') ||
251
+ stderr.includes('command not found') ||
252
+ stderr.includes('Cannot find module') ||
253
+ stderr.includes('ENOENT');
254
+ if (hasOutput && !isInfraError) {
255
+ // Got a response - interface test passes
256
+ // Note: method may have returned an error, but CLI transport worked
257
+ resolve({
258
+ photon: photonName,
259
+ test: `cli:${methodName}`,
260
+ passed: true,
261
+ duration,
262
+ mode: 'cli',
263
+ });
264
+ }
265
+ else {
266
+ // CLI infrastructure failed
267
+ const failResult = {
268
+ photon: photonName,
269
+ test: `cli:${methodName}`,
270
+ passed: false,
271
+ duration,
272
+ error: stderr || `CLI exited with code ${code} (no output)`,
273
+ mode: 'cli',
274
+ };
275
+ failResult.issueUrl = generateIssueUrl(failResult, workingDir);
276
+ resolve(failResult);
277
+ }
278
+ });
279
+ proc.on('error', (err) => {
280
+ const duration = Date.now() - start;
281
+ const failResult = {
282
+ photon: photonName,
283
+ test: `cli:${methodName}`,
284
+ passed: false,
285
+ duration,
286
+ error: `Failed to spawn CLI: ${err.message}`,
287
+ mode: 'cli',
288
+ };
289
+ failResult.issueUrl = generateIssueUrl(failResult, workingDir);
290
+ resolve(failResult);
291
+ });
292
+ });
293
+ }
294
+ // ══════════════════════════════════════════════════════════════════════════════
295
+ // MCP INTERFACE TEST EXECUTION
296
+ // ══════════════════════════════════════════════════════════════════════════════
297
+ /**
298
+ * Run a method via MCP protocol
299
+ * This starts a temporary MCP server and calls the method through it
300
+ */
301
+ async function runMcpTest(photonPath, photonName, methodName, params, workingDir) {
302
+ const start = Date.now();
303
+ return new Promise((resolve) => {
304
+ // Start MCP server for this photon
305
+ const args = ['mcp', photonName, '--dir', workingDir];
306
+ const proc = spawn('node', [CLI_PATH, ...args], {
307
+ cwd: workingDir,
308
+ stdio: ['pipe', 'pipe', 'pipe'],
309
+ });
310
+ let initialized = false;
311
+ let responseReceived = false;
312
+ const requestId = 1;
313
+ // Send initialize request
314
+ const initRequest = {
315
+ jsonrpc: '2.0',
316
+ id: 0,
317
+ method: 'initialize',
318
+ params: {
319
+ protocolVersion: '2024-11-05',
320
+ capabilities: {},
321
+ clientInfo: { name: 'photon-test', version: '1.0.0' },
322
+ },
323
+ };
324
+ proc.stdin?.write(JSON.stringify(initRequest) + '\n');
325
+ proc.stdout?.on('data', (data) => {
326
+ const lines = data.toString().split('\n').filter(Boolean);
327
+ for (const line of lines) {
328
+ try {
329
+ const response = JSON.parse(line);
330
+ if (response.id === 0 && !initialized) {
331
+ // Initialize response received, send tool call
332
+ initialized = true;
333
+ const toolRequest = {
334
+ jsonrpc: '2.0',
335
+ id: requestId,
336
+ method: 'tools/call',
337
+ params: {
338
+ name: methodName,
339
+ arguments: params,
340
+ },
341
+ };
342
+ proc.stdin?.write(JSON.stringify(toolRequest) + '\n');
343
+ }
344
+ else if (response.id === requestId && !responseReceived) {
345
+ responseReceived = true;
346
+ const duration = Date.now() - start;
347
+ proc.kill();
348
+ // Interface tests verify the transport layer works, not business logic.
349
+ // A response (even an error response) proves the MCP protocol works.
350
+ // Only MCP-level errors (not method errors) should fail the test.
351
+ if (response.error && response.error.code && response.error.code < -32000) {
352
+ // JSON-RPC protocol error (not a method error)
353
+ const failResult = {
354
+ photon: photonName,
355
+ test: `mcp:${methodName}`,
356
+ passed: false,
357
+ duration,
358
+ error: response.error.message || JSON.stringify(response.error),
359
+ mode: 'mcp',
360
+ };
361
+ failResult.issueUrl = generateIssueUrl(failResult, workingDir);
362
+ resolve(failResult);
363
+ }
364
+ else {
365
+ // Got a valid MCP response - interface test passes
366
+ // Note: method may have returned an error, but MCP transport worked
367
+ resolve({
368
+ photon: photonName,
369
+ test: `mcp:${methodName}`,
370
+ passed: true,
371
+ duration,
372
+ mode: 'mcp',
373
+ });
374
+ }
375
+ }
376
+ }
377
+ catch {
378
+ // Ignore non-JSON lines
379
+ }
380
+ }
381
+ });
382
+ // Timeout after 30 seconds
383
+ setTimeout(() => {
384
+ if (!responseReceived) {
385
+ proc.kill();
386
+ const duration = Date.now() - start;
387
+ const failResult = {
388
+ photon: photonName,
389
+ test: `mcp:${methodName}`,
390
+ passed: false,
391
+ duration,
392
+ error: 'MCP request timed out after 30 seconds',
393
+ mode: 'mcp',
394
+ };
395
+ failResult.issueUrl = generateIssueUrl(failResult, workingDir);
396
+ resolve(failResult);
397
+ }
398
+ }, 30000);
399
+ proc.on('error', (err) => {
400
+ const duration = Date.now() - start;
401
+ const failResult = {
402
+ photon: photonName,
403
+ test: `mcp:${methodName}`,
404
+ passed: false,
405
+ duration,
406
+ error: `Failed to start MCP server: ${err.message}`,
407
+ mode: 'mcp',
408
+ };
409
+ failResult.issueUrl = generateIssueUrl(failResult, workingDir);
410
+ resolve(failResult);
411
+ });
412
+ });
413
+ }
414
+ // ══════════════════════════════════════════════════════════════════════════════
415
+ // TEST ORCHESTRATION
416
+ // ══════════════════════════════════════════════════════════════════════════════
417
+ /**
418
+ * Run tests for a single photon
419
+ */
420
+ async function runPhotonTests(photonPath, photonName, workingDir, mode, specificTest) {
421
+ const results = [];
422
+ const loader = new PhotonLoader(false);
423
+ try {
424
+ const photon = await loader.loadFile(photonPath);
425
+ const instance = photon.instance;
426
+ if (!instance) {
427
+ return [
428
+ {
429
+ photon: photonName,
430
+ test: '*',
431
+ passed: false,
432
+ duration: 0,
433
+ error: 'Failed to load photon instance',
434
+ mode: 'direct',
435
+ },
436
+ ];
437
+ }
438
+ // ─────────────────────────────────────────────────────────────────────────
439
+ // DIRECT TESTS (test* methods)
440
+ // ─────────────────────────────────────────────────────────────────────────
441
+ if (mode === 'direct' || mode === 'all') {
442
+ const testMethods = getTestMethods(instance);
443
+ if (testMethods.length > 0) {
444
+ // Filter to specific test if requested
445
+ const testsToRun = specificTest
446
+ ? testMethods.filter((t) => t === specificTest || t === `test${specificTest}`)
447
+ : testMethods;
448
+ if (specificTest && testsToRun.length === 0 && mode === 'direct') {
449
+ return [
450
+ {
451
+ photon: photonName,
452
+ test: specificTest,
453
+ passed: false,
454
+ duration: 0,
455
+ error: `Test not found: ${specificTest}`,
456
+ mode: 'direct',
457
+ },
458
+ ];
459
+ }
460
+ // Run testBeforeAll if it exists
461
+ if (hasLifecycleHook(instance, 'testBeforeAll')) {
462
+ try {
463
+ await instance.testBeforeAll();
464
+ }
465
+ catch (error) {
466
+ return [
467
+ {
468
+ photon: photonName,
469
+ test: 'beforeAll',
470
+ passed: false,
471
+ duration: 0,
472
+ error: `Setup failed: ${error.message}`,
473
+ mode: 'direct',
474
+ },
475
+ ];
476
+ }
477
+ }
478
+ // Run direct tests
479
+ for (const testName of testsToRun) {
480
+ const result = await runDirectTest(instance, photonName, testName, workingDir);
481
+ results.push(result);
482
+ }
483
+ // Run testAfterAll if it exists
484
+ if (hasLifecycleHook(instance, 'testAfterAll')) {
485
+ try {
486
+ await instance.testAfterAll();
487
+ }
488
+ catch (error) {
489
+ results.push({
490
+ photon: photonName,
491
+ test: 'afterAll',
492
+ passed: false,
493
+ duration: 0,
494
+ error: `Teardown failed: ${error.message}`,
495
+ mode: 'direct',
496
+ });
497
+ }
498
+ }
499
+ }
500
+ }
501
+ // ─────────────────────────────────────────────────────────────────────────
502
+ // CLI INTERFACE TESTS
503
+ // ─────────────────────────────────────────────────────────────────────────
504
+ if (mode === 'cli' || mode === 'all') {
505
+ const methods = await getPublicMethods(photonPath);
506
+ for (const method of methods) {
507
+ // Skip test methods and lifecycle hooks in interface tests
508
+ if (method.name.startsWith('test') || method.name.startsWith('on')) {
509
+ continue;
510
+ }
511
+ // Skip if specific test requested and doesn't match
512
+ if (specificTest && !`cli:${method.name}`.includes(specificTest)) {
513
+ continue;
514
+ }
515
+ const params = buildExampleParams(method);
516
+ const result = await runCliTest(photonName, method.name, params, workingDir);
517
+ results.push(result);
518
+ }
519
+ }
520
+ // ─────────────────────────────────────────────────────────────────────────
521
+ // MCP INTERFACE TESTS
522
+ // ─────────────────────────────────────────────────────────────────────────
523
+ if (mode === 'mcp' || mode === 'all') {
524
+ const methods = await getPublicMethods(photonPath);
525
+ for (const method of methods) {
526
+ // Skip test methods and lifecycle hooks in interface tests
527
+ if (method.name.startsWith('test') || method.name.startsWith('on')) {
528
+ continue;
529
+ }
530
+ // Skip if specific test requested and doesn't match
531
+ if (specificTest && !`mcp:${method.name}`.includes(specificTest)) {
532
+ continue;
533
+ }
534
+ const params = buildExampleParams(method);
535
+ const result = await runMcpTest(photonPath, photonName, method.name, params, workingDir);
536
+ results.push(result);
537
+ }
538
+ }
539
+ return results;
540
+ }
541
+ catch (error) {
542
+ return [
543
+ {
544
+ photon: photonName,
545
+ test: '*',
546
+ passed: false,
547
+ duration: 0,
548
+ error: `Failed to load photon: ${error.message}`,
549
+ mode: 'direct',
550
+ },
551
+ ];
552
+ }
553
+ }
554
+ // ══════════════════════════════════════════════════════════════════════════════
555
+ // OUTPUT FORMATTING
556
+ // ══════════════════════════════════════════════════════════════════════════════
557
+ /**
558
+ * Print a single test result
559
+ */
560
+ function printTestResult(result) {
561
+ let icon;
562
+ if (result.skipped) {
563
+ icon = chalk.yellow('○');
564
+ }
565
+ else if (result.passed) {
566
+ icon = chalk.green('✓');
567
+ }
568
+ else {
569
+ icon = chalk.red('✗');
570
+ }
571
+ // Format test name based on mode
572
+ let displayName;
573
+ if (result.test.startsWith('cli:') || result.test.startsWith('mcp:')) {
574
+ displayName = result.test;
575
+ }
576
+ else {
577
+ // Strip 'test' prefix and lowercase first char for direct tests
578
+ const stripped = result.test.replace(/^test/, '');
579
+ displayName = stripped.charAt(0).toLowerCase() + stripped.slice(1);
580
+ }
581
+ const modeTag = chalk.gray(`[${result.mode}]`);
582
+ const name = chalk.gray(`${result.photon}.`) + displayName;
583
+ const time = chalk.gray(`${result.duration}ms`);
584
+ if (result.skipped) {
585
+ console.log(` ${icon} ${modeTag} ${name} ${chalk.yellow('skipped')} ${time}`);
586
+ if (result.message) {
587
+ console.log(chalk.yellow(` ${result.message}`));
588
+ }
589
+ }
590
+ else {
591
+ console.log(` ${icon} ${modeTag} ${name} ${time}`);
592
+ if (!result.passed && result.error) {
593
+ console.log(chalk.red(` ${result.error}`));
594
+ if (result.issueUrl) {
595
+ console.log(chalk.gray(` File issue: ${result.issueUrl.substring(0, 80)}...`));
596
+ }
597
+ }
598
+ }
599
+ }
600
+ /**
601
+ * Print test summary
602
+ */
603
+ function printSummary(summary) {
604
+ console.log('');
605
+ console.log(chalk.bold('─'.repeat(60)));
606
+ console.log('');
607
+ const skippedInfo = summary.skipped > 0 ? chalk.yellow(` (${summary.skipped} skipped)`) : '';
608
+ const modeInfo = chalk.gray(` [mode: ${summary.mode}]`);
609
+ if (summary.failed === 0) {
610
+ console.log(chalk.green.bold(`✓ All ${summary.passed} tests passed`) +
611
+ skippedInfo +
612
+ chalk.gray(` (${summary.duration}ms)`) +
613
+ modeInfo);
614
+ }
615
+ else {
616
+ console.log(chalk.red.bold(`✗ ${summary.failed} of ${summary.total} tests failed`) +
617
+ skippedInfo +
618
+ chalk.gray(` (${summary.duration}ms)`) +
619
+ modeInfo);
620
+ // List failed tests
621
+ console.log('');
622
+ console.log(chalk.red('Failed tests:'));
623
+ for (const result of summary.results.filter((r) => !r.passed && !r.skipped)) {
624
+ console.log(chalk.red(` • [${result.mode}] ${result.photon}.${result.test}`));
625
+ if (result.error) {
626
+ console.log(chalk.gray(` ${result.error}`));
627
+ }
628
+ }
629
+ // Show issue filing hint
630
+ const interfaceFailures = summary.results.filter((r) => !r.passed && !r.skipped && (r.mode === 'cli' || r.mode === 'mcp'));
631
+ if (interfaceFailures.length > 0) {
632
+ console.log('');
633
+ console.log(chalk.yellow('Tip: Interface test failures may indicate MCP protocol issues.'));
634
+ console.log(chalk.yellow(' Run with --json to get issue URLs for bug reports.'));
635
+ }
636
+ }
637
+ console.log('');
638
+ }
639
+ // ══════════════════════════════════════════════════════════════════════════════
640
+ // PUBLIC API
641
+ // ══════════════════════════════════════════════════════════════════════════════
642
+ /**
643
+ * Main test runner
644
+ */
645
+ export async function runTests(workingDir, photonName, testName, options = {}) {
646
+ const startTime = Date.now();
647
+ const results = [];
648
+ const mode = options.mode || 'direct';
649
+ if (!options.json) {
650
+ console.log('');
651
+ console.log(chalk.bold('⚡ Photon Test Runner'));
652
+ console.log(chalk.gray(` ${workingDir}`));
653
+ console.log(chalk.gray(` Mode: ${mode}`));
654
+ console.log('');
655
+ }
656
+ if (photonName) {
657
+ // Run tests for specific photon
658
+ const photonPath = await resolvePhotonPath(photonName, workingDir);
659
+ if (!photonPath) {
660
+ logger.error(`Photon not found: ${photonName}`);
661
+ process.exit(1);
662
+ }
663
+ if (!options.json) {
664
+ console.log(chalk.bold(photonName));
665
+ }
666
+ const photonResults = await runPhotonTests(photonPath, photonName, workingDir, mode, testName);
667
+ results.push(...photonResults);
668
+ // Print progress for each result
669
+ if (!options.json) {
670
+ for (const result of photonResults) {
671
+ printTestResult(result);
672
+ }
673
+ }
674
+ }
675
+ else {
676
+ // Run tests for all photons
677
+ const photons = await listPhotonMCPs(workingDir);
678
+ if (photons.length === 0) {
679
+ if (!options.json) {
680
+ console.log(chalk.yellow('No photons found in working directory'));
681
+ }
682
+ return {
683
+ total: 0,
684
+ passed: 0,
685
+ failed: 0,
686
+ skipped: 0,
687
+ duration: 0,
688
+ results: [],
689
+ mode,
690
+ };
691
+ }
692
+ for (const photon of photons) {
693
+ const photonPath = path.join(workingDir, `${photon}.photon.ts`);
694
+ if (!existsSync(photonPath)) {
695
+ continue;
696
+ }
697
+ // Check if photon has any test methods before printing header (for direct mode)
698
+ if (mode === 'direct') {
699
+ const loader = new PhotonLoader(false);
700
+ try {
701
+ const loaded = await loader.loadFile(photonPath);
702
+ const testMethods = getTestMethods(loaded.instance);
703
+ if (testMethods.length === 0) {
704
+ continue; // Skip photons with no tests in direct mode
705
+ }
706
+ }
707
+ catch {
708
+ continue;
709
+ }
710
+ }
711
+ if (!options.json) {
712
+ console.log(chalk.bold(photon));
713
+ }
714
+ const photonResults = await runPhotonTests(photonPath, photon, workingDir, mode);
715
+ results.push(...photonResults);
716
+ // Print progress for each result
717
+ if (!options.json) {
718
+ for (const result of photonResults) {
719
+ printTestResult(result);
720
+ }
721
+ if (photonResults.length > 0) {
722
+ console.log('');
723
+ }
724
+ }
725
+ }
726
+ }
727
+ const duration = Date.now() - startTime;
728
+ const skipped = results.filter((r) => r.skipped).length;
729
+ const passed = results.filter((r) => r.passed && !r.skipped).length;
730
+ const failed = results.filter((r) => !r.passed).length;
731
+ const summary = {
732
+ total: results.length,
733
+ passed,
734
+ failed,
735
+ skipped,
736
+ duration,
737
+ results,
738
+ mode,
739
+ };
740
+ if (options.json) {
741
+ console.log(JSON.stringify(summary, null, 2));
742
+ }
743
+ else {
744
+ printSummary(summary);
745
+ }
746
+ return summary;
747
+ }
748
+ /**
749
+ * Check if a photon has test methods (for UI display)
750
+ */
751
+ export async function hasTests(photonPath) {
752
+ const loader = new PhotonLoader(false);
753
+ try {
754
+ const photon = await loader.loadFile(photonPath);
755
+ const testMethods = getTestMethods(photon.instance);
756
+ return testMethods.length > 0;
757
+ }
758
+ catch (error) {
759
+ logger.debug('Failed to check tests:', { error });
760
+ return false; // file unloadable → no tests
761
+ }
762
+ }
763
+ /**
764
+ * Get list of test methods for a photon (for UI display)
765
+ */
766
+ export async function getTests(photonPath) {
767
+ const loader = new PhotonLoader(false);
768
+ try {
769
+ const photon = await loader.loadFile(photonPath);
770
+ return getTestMethods(photon.instance);
771
+ }
772
+ catch {
773
+ return [];
774
+ }
775
+ }
776
+ /**
777
+ * Get public methods for interface testing (for UI display)
778
+ */
779
+ export async function getInterfaceTests(photonPath) {
780
+ const methods = await getPublicMethods(photonPath);
781
+ return methods
782
+ .filter((m) => !m.name.startsWith('test') && !m.name.startsWith('on'))
783
+ .map((m) => m.name);
784
+ }
785
+ //# sourceMappingURL=test-runner.js.map