agent-bundle 0.1.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 (376) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +161 -0
  3. package/dist/agent/agent.d.ts +32 -0
  4. package/dist/agent/agent.js +241 -0
  5. package/dist/agent/agent.js.map +1 -0
  6. package/dist/agent/agent.test-helpers.d.ts +63 -0
  7. package/dist/agent/agent.test-helpers.js +170 -0
  8. package/dist/agent/agent.test-helpers.js.map +1 -0
  9. package/dist/agent/define-agent.d.ts +2 -0
  10. package/dist/agent/define-agent.js +18 -0
  11. package/dist/agent/define-agent.js.map +1 -0
  12. package/dist/agent/dependencies.d.ts +15 -0
  13. package/dist/agent/dependencies.js +14 -0
  14. package/dist/agent/dependencies.js.map +1 -0
  15. package/dist/agent/index.d.ts +4 -0
  16. package/dist/agent/index.js +5 -0
  17. package/dist/agent/index.js.map +1 -0
  18. package/dist/agent/internals.d.ts +28 -0
  19. package/dist/agent/internals.js +160 -0
  20. package/dist/agent/internals.js.map +1 -0
  21. package/dist/agent/session.d.ts +4 -0
  22. package/dist/agent/session.js +2 -0
  23. package/dist/agent/session.js.map +1 -0
  24. package/dist/agent/types.d.ts +52 -0
  25. package/dist/agent/types.js +2 -0
  26. package/dist/agent/types.js.map +1 -0
  27. package/dist/agent-loop/agent-loop.d.ts +27 -0
  28. package/dist/agent-loop/agent-loop.js +2 -0
  29. package/dist/agent-loop/agent-loop.js.map +1 -0
  30. package/dist/agent-loop/index.d.ts +4 -0
  31. package/dist/agent-loop/index.js +5 -0
  32. package/dist/agent-loop/index.js.map +1 -0
  33. package/dist/agent-loop/pi-mono/events.d.ts +3 -0
  34. package/dist/agent-loop/pi-mono/events.js +73 -0
  35. package/dist/agent-loop/pi-mono/events.js.map +1 -0
  36. package/dist/agent-loop/pi-mono/index.d.ts +1 -0
  37. package/dist/agent-loop/pi-mono/index.js +2 -0
  38. package/dist/agent-loop/pi-mono/index.js.map +1 -0
  39. package/dist/agent-loop/pi-mono/input.d.ts +6 -0
  40. package/dist/agent-loop/pi-mono/input.js +120 -0
  41. package/dist/agent-loop/pi-mono/input.js.map +1 -0
  42. package/dist/agent-loop/pi-mono/model.d.ts +7 -0
  43. package/dist/agent-loop/pi-mono/model.js +72 -0
  44. package/dist/agent-loop/pi-mono/model.js.map +1 -0
  45. package/dist/agent-loop/pi-mono/pi-mono-loop.d.ts +11 -0
  46. package/dist/agent-loop/pi-mono/pi-mono-loop.js +167 -0
  47. package/dist/agent-loop/pi-mono/pi-mono-loop.js.map +1 -0
  48. package/dist/agent-loop/pi-mono/pi-mono-loop.test-helpers.d.ts +28 -0
  49. package/dist/agent-loop/pi-mono/pi-mono-loop.test-helpers.js +76 -0
  50. package/dist/agent-loop/pi-mono/pi-mono-loop.test-helpers.js.map +1 -0
  51. package/dist/agent-loop/pi-mono/queue.d.ts +9 -0
  52. package/dist/agent-loop/pi-mono/queue.js +37 -0
  53. package/dist/agent-loop/pi-mono/queue.js.map +1 -0
  54. package/dist/agent-loop/pi-mono/tools.d.ts +4 -0
  55. package/dist/agent-loop/pi-mono/tools.js +164 -0
  56. package/dist/agent-loop/pi-mono/tools.js.map +1 -0
  57. package/dist/agent-loop/pi-mono/utils.d.ts +14 -0
  58. package/dist/agent-loop/pi-mono/utils.js +83 -0
  59. package/dist/agent-loop/pi-mono/utils.js.map +1 -0
  60. package/dist/agent-loop/system-prompt/fill.d.ts +1 -0
  61. package/dist/agent-loop/system-prompt/fill.js +19 -0
  62. package/dist/agent-loop/system-prompt/fill.js.map +1 -0
  63. package/dist/agent-loop/system-prompt/generate.d.ts +11 -0
  64. package/dist/agent-loop/system-prompt/generate.js +21 -0
  65. package/dist/agent-loop/system-prompt/generate.js.map +1 -0
  66. package/dist/agent-loop/system-prompt/index.d.ts +2 -0
  67. package/dist/agent-loop/system-prompt/index.js +3 -0
  68. package/dist/agent-loop/system-prompt/index.js.map +1 -0
  69. package/dist/agent-loop/types.d.ts +77 -0
  70. package/dist/agent-loop/types.js +2 -0
  71. package/dist/agent-loop/types.js.map +1 -0
  72. package/dist/cli/build/build.d.ts +35 -0
  73. package/dist/cli/build/build.js +174 -0
  74. package/dist/cli/build/build.js.map +1 -0
  75. package/dist/cli/build/build.test-helpers.d.ts +9 -0
  76. package/dist/cli/build/build.test-helpers.js +50 -0
  77. package/dist/cli/build/build.test-helpers.js.map +1 -0
  78. package/dist/cli/build/codegen-commands.d.ts +16 -0
  79. package/dist/cli/build/codegen-commands.js +81 -0
  80. package/dist/cli/build/codegen-commands.js.map +1 -0
  81. package/dist/cli/build/codegen.d.ts +55 -0
  82. package/dist/cli/build/codegen.js +212 -0
  83. package/dist/cli/build/codegen.js.map +1 -0
  84. package/dist/cli/build/e2b-template.d.ts +38 -0
  85. package/dist/cli/build/e2b-template.js +210 -0
  86. package/dist/cli/build/e2b-template.js.map +1 -0
  87. package/dist/cli/build/e2b-template.test-helpers.d.ts +19 -0
  88. package/dist/cli/build/e2b-template.test-helpers.js +80 -0
  89. package/dist/cli/build/e2b-template.test-helpers.js.map +1 -0
  90. package/dist/cli/build/sandbox-image.d.ts +35 -0
  91. package/dist/cli/build/sandbox-image.js +57 -0
  92. package/dist/cli/build/sandbox-image.js.map +1 -0
  93. package/dist/cli/build-codegen.d.ts +41 -0
  94. package/dist/cli/build-codegen.js +168 -0
  95. package/dist/cli/build-codegen.js.map +1 -0
  96. package/dist/cli/build-e2b-template.d.ts +38 -0
  97. package/dist/cli/build-e2b-template.js +223 -0
  98. package/dist/cli/build-e2b-template.js.map +1 -0
  99. package/dist/cli/build-e2b-template.test-helpers.d.ts +19 -0
  100. package/dist/cli/build-e2b-template.test-helpers.js +80 -0
  101. package/dist/cli/build-e2b-template.test-helpers.js.map +1 -0
  102. package/dist/cli/build-sandbox-image.d.ts +35 -0
  103. package/dist/cli/build-sandbox-image.js +57 -0
  104. package/dist/cli/build-sandbox-image.js.map +1 -0
  105. package/dist/cli/build.d.ts +30 -0
  106. package/dist/cli/build.js +151 -0
  107. package/dist/cli/build.js.map +1 -0
  108. package/dist/cli/build.test-helpers.d.ts +9 -0
  109. package/dist/cli/build.test-helpers.js +50 -0
  110. package/dist/cli/build.test-helpers.js.map +1 -0
  111. package/dist/cli/config/load-bundle-config.d.ts +2 -0
  112. package/dist/cli/config/load-bundle-config.js +20 -0
  113. package/dist/cli/config/load-bundle-config.js.map +1 -0
  114. package/dist/cli/config/resolve-project-root.d.ts +1 -0
  115. package/dist/cli/config/resolve-project-root.js +19 -0
  116. package/dist/cli/config/resolve-project-root.js.map +1 -0
  117. package/dist/cli/deploy/aws-cli.d.ts +42 -0
  118. package/dist/cli/deploy/aws-cli.js +95 -0
  119. package/dist/cli/deploy/aws-cli.js.map +1 -0
  120. package/dist/cli/deploy/aws-ecr.d.ts +20 -0
  121. package/dist/cli/deploy/aws-ecr.js +97 -0
  122. package/dist/cli/deploy/aws-ecr.js.map +1 -0
  123. package/dist/cli/deploy/aws-ecs-infra.d.ts +39 -0
  124. package/dist/cli/deploy/aws-ecs-infra.js +169 -0
  125. package/dist/cli/deploy/aws-ecs-infra.js.map +1 -0
  126. package/dist/cli/deploy/aws-ecs-role.d.ts +9 -0
  127. package/dist/cli/deploy/aws-ecs-role.js +114 -0
  128. package/dist/cli/deploy/aws-ecs-role.js.map +1 -0
  129. package/dist/cli/deploy/aws-ecs-service.d.ts +37 -0
  130. package/dist/cli/deploy/aws-ecs-service.js +207 -0
  131. package/dist/cli/deploy/aws-ecs-service.js.map +1 -0
  132. package/dist/cli/deploy/aws-ecs-shared.d.ts +59 -0
  133. package/dist/cli/deploy/aws-ecs-shared.js +30 -0
  134. package/dist/cli/deploy/aws-ecs-shared.js.map +1 -0
  135. package/dist/cli/deploy/aws-ecs.d.ts +3 -0
  136. package/dist/cli/deploy/aws-ecs.js +141 -0
  137. package/dist/cli/deploy/aws-ecs.js.map +1 -0
  138. package/dist/cli/deploy/aws-prerequisites.d.ts +16 -0
  139. package/dist/cli/deploy/aws-prerequisites.js +28 -0
  140. package/dist/cli/deploy/aws-prerequisites.js.map +1 -0
  141. package/dist/cli/deploy/aws-teardown.d.ts +13 -0
  142. package/dist/cli/deploy/aws-teardown.js +204 -0
  143. package/dist/cli/deploy/aws-teardown.js.map +1 -0
  144. package/dist/cli/deploy/deploy.d.ts +36 -0
  145. package/dist/cli/deploy/deploy.js +209 -0
  146. package/dist/cli/deploy/deploy.js.map +1 -0
  147. package/dist/cli/error.d.ts +1 -0
  148. package/dist/cli/error.js +4 -0
  149. package/dist/cli/error.js.map +1 -0
  150. package/dist/cli/generate/generate.d.ts +37 -0
  151. package/dist/cli/generate/generate.js +121 -0
  152. package/dist/cli/generate/generate.js.map +1 -0
  153. package/dist/cli/generate.d.ts +32 -0
  154. package/dist/cli/generate.js +102 -0
  155. package/dist/cli/generate.js.map +1 -0
  156. package/dist/cli/index.d.ts +2 -0
  157. package/dist/cli/index.js +182 -0
  158. package/dist/cli/index.js.map +1 -0
  159. package/dist/cli/load-bundle-config.d.ts +2 -0
  160. package/dist/cli/load-bundle-config.js +20 -0
  161. package/dist/cli/load-bundle-config.js.map +1 -0
  162. package/dist/cli/resolve-project-root.d.ts +1 -0
  163. package/dist/cli/resolve-project-root.js +19 -0
  164. package/dist/cli/resolve-project-root.js.map +1 -0
  165. package/dist/cli/serve/dev.d.ts +6 -0
  166. package/dist/cli/serve/dev.js +73 -0
  167. package/dist/cli/serve/dev.js.map +1 -0
  168. package/dist/cli/serve/http.d.ts +12 -0
  169. package/dist/cli/serve/http.js +123 -0
  170. package/dist/cli/serve/http.js.map +1 -0
  171. package/dist/cli/serve/init.d.ts +42 -0
  172. package/dist/cli/serve/init.js +110 -0
  173. package/dist/cli/serve/init.js.map +1 -0
  174. package/dist/cli/serve/runtime.d.ts +25 -0
  175. package/dist/cli/serve/runtime.js +142 -0
  176. package/dist/cli/serve/runtime.js.map +1 -0
  177. package/dist/cli/serve/serve.d.ts +7 -0
  178. package/dist/cli/serve/serve.js +63 -0
  179. package/dist/cli/serve/serve.js.map +1 -0
  180. package/dist/cli/serve/serve.test-helpers.d.ts +36 -0
  181. package/dist/cli/serve/serve.test-helpers.js +205 -0
  182. package/dist/cli/serve/serve.test-helpers.js.map +1 -0
  183. package/dist/cli/serve/worktree-port.d.ts +36 -0
  184. package/dist/cli/serve/worktree-port.js +124 -0
  185. package/dist/cli/serve/worktree-port.js.map +1 -0
  186. package/dist/cli/serve-http.d.ts +12 -0
  187. package/dist/cli/serve-http.js +112 -0
  188. package/dist/cli/serve-http.js.map +1 -0
  189. package/dist/cli/serve-runtime.d.ts +16 -0
  190. package/dist/cli/serve-runtime.js +122 -0
  191. package/dist/cli/serve-runtime.js.map +1 -0
  192. package/dist/cli/serve.d.ts +33 -0
  193. package/dist/cli/serve.js +150 -0
  194. package/dist/cli/serve.js.map +1 -0
  195. package/dist/cli/serve.test-helpers.d.ts +30 -0
  196. package/dist/cli/serve.test-helpers.js +145 -0
  197. package/dist/cli/serve.test-helpers.js.map +1 -0
  198. package/dist/code-formatter/bundle.json +41 -0
  199. package/dist/code-formatter/index.ts +26 -0
  200. package/dist/code-formatter/package.json +10 -0
  201. package/dist/code-formatter/types.ts +2 -0
  202. package/dist/code-formatter-e2b/bundle.json +40 -0
  203. package/dist/code-formatter-e2b/index.ts +25 -0
  204. package/dist/code-formatter-e2b/package.json +10 -0
  205. package/dist/code-formatter-e2b/types.ts +2 -0
  206. package/dist/coding-assistant-ollama/bundle.json +43 -0
  207. package/dist/coding-assistant-ollama/index.ts +28 -0
  208. package/dist/coding-assistant-ollama/package.json +10 -0
  209. package/dist/coding-assistant-ollama/types.ts +2 -0
  210. package/dist/commands/find.d.ts +8 -0
  211. package/dist/commands/find.js +11 -0
  212. package/dist/commands/find.js.map +1 -0
  213. package/dist/commands/loader.d.ts +13 -0
  214. package/dist/commands/loader.js +163 -0
  215. package/dist/commands/loader.js.map +1 -0
  216. package/dist/commands/types.d.ts +7 -0
  217. package/dist/commands/types.js +2 -0
  218. package/dist/commands/types.js.map +1 -0
  219. package/dist/commands/with-commands.d.ts +6 -0
  220. package/dist/commands/with-commands.js +19 -0
  221. package/dist/commands/with-commands.js.map +1 -0
  222. package/dist/data-analyst/bundle.json +40 -0
  223. package/dist/data-analyst/index.ts +25 -0
  224. package/dist/data-analyst/package.json +10 -0
  225. package/dist/data-analyst/types.ts +2 -0
  226. package/dist/financial-analyst/bundle.json +40 -0
  227. package/dist/financial-analyst/index.ts +25 -0
  228. package/dist/financial-analyst/package.json +10 -0
  229. package/dist/financial-analyst/types.ts +2 -0
  230. package/dist/mcp/client-manager.d.ts +26 -0
  231. package/dist/mcp/client-manager.js +101 -0
  232. package/dist/mcp/client-manager.js.map +1 -0
  233. package/dist/mcp/connect-server.d.ts +21 -0
  234. package/dist/mcp/connect-server.js +170 -0
  235. package/dist/mcp/connect-server.js.map +1 -0
  236. package/dist/mcp/index.d.ts +2 -0
  237. package/dist/mcp/index.js +3 -0
  238. package/dist/mcp/index.js.map +1 -0
  239. package/dist/mcp/sandbox-stdio-transport.d.ts +32 -0
  240. package/dist/mcp/sandbox-stdio-transport.js +199 -0
  241. package/dist/mcp/sandbox-stdio-transport.js.map +1 -0
  242. package/dist/observability/hooks.d.ts +10 -0
  243. package/dist/observability/hooks.js +97 -0
  244. package/dist/observability/hooks.js.map +1 -0
  245. package/dist/observability/index.d.ts +6 -0
  246. package/dist/observability/index.js +7 -0
  247. package/dist/observability/index.js.map +1 -0
  248. package/dist/observability/metrics.d.ts +31 -0
  249. package/dist/observability/metrics.js +61 -0
  250. package/dist/observability/metrics.js.map +1 -0
  251. package/dist/observability/middleware.d.ts +12 -0
  252. package/dist/observability/middleware.js +45 -0
  253. package/dist/observability/middleware.js.map +1 -0
  254. package/dist/observability/otel-harness.test-util.d.ts +37 -0
  255. package/dist/observability/otel-harness.test-util.js +96 -0
  256. package/dist/observability/otel-harness.test-util.js.map +1 -0
  257. package/dist/observability/provider.d.ts +8 -0
  258. package/dist/observability/provider.js +19 -0
  259. package/dist/observability/provider.js.map +1 -0
  260. package/dist/observability/tracing.d.ts +14 -0
  261. package/dist/observability/tracing.js +40 -0
  262. package/dist/observability/tracing.js.map +1 -0
  263. package/dist/observability/types.d.ts +39 -0
  264. package/dist/observability/types.js +31 -0
  265. package/dist/observability/types.js.map +1 -0
  266. package/dist/personalized-recommend/bundle.json +64 -0
  267. package/dist/personalized-recommend/index.ts +41 -0
  268. package/dist/personalized-recommend/package.json +10 -0
  269. package/dist/personalized-recommend/types.ts +2 -0
  270. package/dist/plugins/loader.d.ts +11 -0
  271. package/dist/plugins/loader.js +100 -0
  272. package/dist/plugins/loader.js.map +1 -0
  273. package/dist/plugins/merge.d.ts +10 -0
  274. package/dist/plugins/merge.js +22 -0
  275. package/dist/plugins/merge.js.map +1 -0
  276. package/dist/plugins/parse.d.ts +10 -0
  277. package/dist/plugins/parse.js +139 -0
  278. package/dist/plugins/parse.js.map +1 -0
  279. package/dist/plugins/types.d.ts +28 -0
  280. package/dist/plugins/types.js +2 -0
  281. package/dist/plugins/types.js.map +1 -0
  282. package/dist/plugins/urls.d.ts +7 -0
  283. package/dist/plugins/urls.js +40 -0
  284. package/dist/plugins/urls.js.map +1 -0
  285. package/dist/runtime.d.ts +5 -0
  286. package/dist/runtime.js +3 -0
  287. package/dist/runtime.js.map +1 -0
  288. package/dist/sandbox/factory.d.ts +2 -0
  289. package/dist/sandbox/factory.js +27 -0
  290. package/dist/sandbox/factory.js.map +1 -0
  291. package/dist/sandbox/index.d.ts +4 -0
  292. package/dist/sandbox/index.js +5 -0
  293. package/dist/sandbox/index.js.map +1 -0
  294. package/dist/sandbox/providers/e2b.d.ts +28 -0
  295. package/dist/sandbox/providers/e2b.js +294 -0
  296. package/dist/sandbox/providers/e2b.js.map +1 -0
  297. package/dist/sandbox/providers/kubernetes-command-run.d.ts +8 -0
  298. package/dist/sandbox/providers/kubernetes-command-run.js +195 -0
  299. package/dist/sandbox/providers/kubernetes-command-run.js.map +1 -0
  300. package/dist/sandbox/providers/kubernetes-helpers.d.ts +31 -0
  301. package/dist/sandbox/providers/kubernetes-helpers.js +152 -0
  302. package/dist/sandbox/providers/kubernetes-helpers.js.map +1 -0
  303. package/dist/sandbox/providers/kubernetes-kubeconfig.d.ts +7 -0
  304. package/dist/sandbox/providers/kubernetes-kubeconfig.js +51 -0
  305. package/dist/sandbox/providers/kubernetes-kubeconfig.js.map +1 -0
  306. package/dist/sandbox/providers/kubernetes-spawn.d.ts +2 -0
  307. package/dist/sandbox/providers/kubernetes-spawn.js +42 -0
  308. package/dist/sandbox/providers/kubernetes-spawn.js.map +1 -0
  309. package/dist/sandbox/providers/kubernetes-spawn.utils.d.ts +32 -0
  310. package/dist/sandbox/providers/kubernetes-spawn.utils.js +249 -0
  311. package/dist/sandbox/providers/kubernetes-spawn.utils.js.map +1 -0
  312. package/dist/sandbox/providers/kubernetes.constants.d.ts +3 -0
  313. package/dist/sandbox/providers/kubernetes.constants.js +4 -0
  314. package/dist/sandbox/providers/kubernetes.constants.js.map +1 -0
  315. package/dist/sandbox/providers/kubernetes.d.ts +37 -0
  316. package/dist/sandbox/providers/kubernetes.js +258 -0
  317. package/dist/sandbox/providers/kubernetes.js.map +1 -0
  318. package/dist/sandbox/types.d.ts +57 -0
  319. package/dist/sandbox/types.js +2 -0
  320. package/dist/sandbox/types.js.map +1 -0
  321. package/dist/sandbox/utils.d.ts +1 -0
  322. package/dist/sandbox/utils.js +4 -0
  323. package/dist/sandbox/utils.js.map +1 -0
  324. package/dist/schema/bundle.d.ts +143 -0
  325. package/dist/schema/bundle.js +203 -0
  326. package/dist/schema/bundle.js.map +1 -0
  327. package/dist/service/command-routes.d.ts +8 -0
  328. package/dist/service/command-routes.js +44 -0
  329. package/dist/service/command-routes.js.map +1 -0
  330. package/dist/service/create-server.d.ts +9 -0
  331. package/dist/service/create-server.js +113 -0
  332. package/dist/service/create-server.js.map +1 -0
  333. package/dist/service/index.d.ts +1 -0
  334. package/dist/service/index.js +2 -0
  335. package/dist/service/index.js.map +1 -0
  336. package/dist/skills/index.d.ts +1 -0
  337. package/dist/skills/index.js +2 -0
  338. package/dist/skills/index.js.map +1 -0
  339. package/dist/skills/loader.d.ts +18 -0
  340. package/dist/skills/loader.js +142 -0
  341. package/dist/skills/loader.js.map +1 -0
  342. package/dist/skills/summaries.d.ts +8 -0
  343. package/dist/skills/summaries.js +9 -0
  344. package/dist/skills/summaries.js.map +1 -0
  345. package/dist/test-helpers/env.d.ts +2 -0
  346. package/dist/test-helpers/env.js +20 -0
  347. package/dist/test-helpers/env.js.map +1 -0
  348. package/dist/test-helpers/mock-agent.d.ts +56 -0
  349. package/dist/test-helpers/mock-agent.js +180 -0
  350. package/dist/test-helpers/mock-agent.js.map +1 -0
  351. package/dist/test-helpers/mock-sandbox.d.ts +33 -0
  352. package/dist/test-helpers/mock-sandbox.js +200 -0
  353. package/dist/test-helpers/mock-sandbox.js.map +1 -0
  354. package/dist/tui/index.d.ts +2 -0
  355. package/dist/tui/index.js +3 -0
  356. package/dist/tui/index.js.map +1 -0
  357. package/dist/tui/render.d.ts +8 -0
  358. package/dist/tui/render.js +40 -0
  359. package/dist/tui/render.js.map +1 -0
  360. package/dist/tui/tui.d.ts +19 -0
  361. package/dist/tui/tui.js +133 -0
  362. package/dist/tui/tui.js.map +1 -0
  363. package/dist/webui/create-webui-server.d.ts +22 -0
  364. package/dist/webui/create-webui-server.js +293 -0
  365. package/dist/webui/create-webui-server.js.map +1 -0
  366. package/dist/webui/event-bus.d.ts +16 -0
  367. package/dist/webui/event-bus.js +24 -0
  368. package/dist/webui/event-bus.js.map +1 -0
  369. package/dist/webui/index.d.ts +2 -0
  370. package/dist/webui/index.js +3 -0
  371. package/dist/webui/index.js.map +1 -0
  372. package/dist/webui/public/app.js +847 -0
  373. package/dist/webui/public/file-transfer.js +114 -0
  374. package/dist/webui/public/index.html +166 -0
  375. package/dist/webui/public/styles.css +1678 -0
  376. package/package.json +99 -0
@@ -0,0 +1,847 @@
1
+ /* global marked, hljs */
2
+
3
+ (function () {
4
+ "use strict";
5
+
6
+ // -- DOM References --
7
+ var chatMessages = document.getElementById("chat-messages");
8
+ var welcomeState = document.getElementById("welcome-state");
9
+ var promptChips = document.getElementById("prompt-chips");
10
+ var skillBadges = document.getElementById("skill-badges");
11
+ var fileTreeEl = document.getElementById("file-tree");
12
+ var filePanel = document.getElementById("file-panel");
13
+ var previewArea = document.getElementById("preview-area");
14
+ var previewContent = document.getElementById("preview-content");
15
+ var previewFilename = document.getElementById("preview-filename");
16
+ var previewClose = document.getElementById("preview-close");
17
+ var imageModal = document.getElementById("image-modal");
18
+ var modalImage = document.getElementById("modal-image");
19
+ var modalClose = document.getElementById("modal-close");
20
+ var chatForm = document.getElementById("chat-form");
21
+ var chatInput = document.getElementById("chat-input");
22
+ var sendBtn = document.getElementById("send-btn");
23
+ var statusBadge = document.getElementById("status-badge");
24
+ var menuToggle = document.getElementById("menu-toggle");
25
+ var panelOverlay = document.querySelector(".panel-overlay");
26
+ // -- Markdown Configuration
27
+ marked.setOptions({ breaks: true, gfm: true });
28
+
29
+ // -- State
30
+ var isStreaming = false;
31
+ var FILE_POLL_MS = 3000;
32
+ var filePollingTimer = null;
33
+ var ws = null;
34
+
35
+ // Streaming text accumulation
36
+ var currentAgentText = "";
37
+ var currentAgentEl = null;
38
+ var renderTimer = null;
39
+ var RENDER_DEBOUNCE_MS = 80;
40
+
41
+ // File tree state
42
+ var previousFilePaths = new Set();
43
+ var expandedDirs = new Set(); // tracks expanded directories
44
+ var expandedDirsInitialized = false;
45
+
46
+ // Currently active tool message for status updates
47
+ var currentToolEl = null;
48
+
49
+ // Track active file for preview highlighting
50
+ var activeFilePath = null;
51
+
52
+ // Welcome state
53
+ var welcomeVisible = true;
54
+
55
+ // Workspace state machine: "welcome" | "empty-no-files" | "empty-with-files" | "preview"
56
+ var workspaceState = "welcome";
57
+
58
+ // -- Workspace View Helpers
59
+ var emptyNoFiles = document.getElementById("empty-no-files");
60
+ var emptyWithFiles = document.getElementById("empty-with-files");
61
+ var fileCardGrid = document.getElementById("file-card-grid");
62
+
63
+ function setWorkspaceState(newState) {
64
+ workspaceState = newState;
65
+ var map = { "welcome": welcomeState, "empty-no-files": emptyNoFiles, "empty-with-files": emptyWithFiles, "preview": previewArea };
66
+ [welcomeState, emptyNoFiles, emptyWithFiles, previewArea].forEach(function(el) { el.style.display = "none"; });
67
+ if (map[newState]) map[newState].style.display = "";
68
+ if (newState === "empty-with-files") renderFileCards();
69
+ }
70
+
71
+ function showPreview() {
72
+ setWorkspaceState("preview");
73
+ }
74
+
75
+ function showWelcomeOrHide() {
76
+ if (previousFilePaths.size > 0) setWorkspaceState("empty-with-files");
77
+ else if (workspaceState === "preview") setWorkspaceState("empty-no-files");
78
+ else setWorkspaceState(workspaceState === "welcome" ? "welcome" : "empty-no-files");
79
+ }
80
+
81
+ // -- Hamburger Menu (Mobile File Tree Toggle)
82
+ function openFilePanel() { filePanel.classList.add("panel--open"); panelOverlay.classList.add("panel-overlay--visible"); }
83
+ function closeFilePanel() { filePanel.classList.remove("panel--open"); panelOverlay.classList.remove("panel-overlay--visible"); }
84
+
85
+ menuToggle.addEventListener("click", function () {
86
+ filePanel.classList.contains("panel--open") ? closeFilePanel() : openFilePanel();
87
+ });
88
+
89
+ panelOverlay.addEventListener("click", closeFilePanel);
90
+
91
+ // -- Status Badge
92
+ function setStatus(s) { statusBadge.textContent = s; statusBadge.className = "badge badge--" + s; }
93
+ function setInputEnabled(en) { chatInput.disabled = !en; sendBtn.disabled = !en; if (en) chatInput.focus(); }
94
+
95
+ // -- Welcome State
96
+ function hideWelcome() {
97
+ if (workspaceState === "welcome") setWorkspaceState("empty-no-files");
98
+ welcomeVisible = false;
99
+ }
100
+
101
+ function fetchAgentInfo() {
102
+ fetch("/api/info")
103
+ .then(function (res) { return res.json(); })
104
+ .then(function (data) {
105
+ if (data.name) {
106
+ var titleEl = document.getElementById("welcome-agent-name");
107
+ if (titleEl) titleEl.textContent = data.name;
108
+ }
109
+ if (data.skills && data.skills.length > 0) {
110
+ skillBadges.innerHTML = "";
111
+ data.skills.forEach(function (skill) {
112
+ var badge = document.createElement("span");
113
+ badge.className = "skill-badge";
114
+ badge.innerHTML = '<span class="skill-icon">&#9881;</span> ' + escapeHtml(skill.name);
115
+ skillBadges.appendChild(badge);
116
+ });
117
+ }
118
+ })
119
+ .catch(function () { /* silent */ });
120
+ }
121
+
122
+ // -- Prompt Chips
123
+ promptChips.addEventListener("click", function (e) {
124
+ var chip = e.target.closest(".prompt-chip");
125
+ if (!chip) return;
126
+ var prompt = chip.getAttribute("data-prompt");
127
+ if (prompt) {
128
+ chatInput.value = prompt;
129
+ sendMessage(prompt);
130
+ chatInput.value = "";
131
+ }
132
+ });
133
+
134
+ // Empty state suggestion clicks
135
+ if (emptyNoFiles) {
136
+ emptyNoFiles.addEventListener("click", function(e) {
137
+ var suggestion = e.target.closest(".workspace-empty-suggestion");
138
+ if (!suggestion) return;
139
+ var prompt = suggestion.getAttribute("data-prompt");
140
+ if (prompt) { chatInput.value = prompt; sendMessage(prompt); chatInput.value = ""; }
141
+ });
142
+ }
143
+
144
+ // -- Chat Message Rendering
145
+ function scrollToBottom() {
146
+ chatMessages.scrollTop = chatMessages.scrollHeight;
147
+ }
148
+
149
+ function escapeHtml(text) {
150
+ var div = document.createElement("div");
151
+ div.textContent = text;
152
+ return div.innerHTML;
153
+ }
154
+
155
+ function highlightCodeBlocks(container) {
156
+ container.querySelectorAll("pre code").forEach(function (block) { hljs.highlightElement(block); });
157
+ }
158
+
159
+ function makeImagesClickable(container) {
160
+ container.querySelectorAll("img").forEach(function (img) {
161
+ if (!img.classList.contains("chat-image")) img.classList.add("chat-image");
162
+ img.style.cursor = "pointer";
163
+ img.addEventListener("click", function () { openImageModal(img.src); });
164
+ });
165
+ }
166
+
167
+ function addCopyButtons(container) {
168
+ container.querySelectorAll('pre code').forEach(function(block) {
169
+ var pre = block.parentElement;
170
+ if (pre.querySelector('.code-copy-btn')) return;
171
+ var btn = document.createElement('button');
172
+ btn.className = 'code-copy-btn'; btn.setAttribute('aria-label', 'Copy code'); btn.innerHTML = '\u2398';
173
+ btn.addEventListener('click', function(e) {
174
+ e.stopPropagation();
175
+ navigator.clipboard.writeText(block.textContent).then(function() {
176
+ btn.classList.add('code-copy-btn--copied'); btn.innerHTML = '\u2713';
177
+ setTimeout(function() { btn.classList.remove('code-copy-btn--copied'); btn.innerHTML = '\u2398'; }, 2000);
178
+ });
179
+ });
180
+ pre.appendChild(btn);
181
+ });
182
+ }
183
+
184
+ function addUserMessage(text) {
185
+ hideWelcome();
186
+ var msg = document.createElement("div");
187
+ msg.className = "message message--user";
188
+ msg.innerHTML = '<div class="message-content">' + escapeHtml(text) + "</div>";
189
+ chatMessages.appendChild(msg);
190
+ scrollToBottom();
191
+ }
192
+
193
+ function createAgentMessage() {
194
+ hideWelcome();
195
+ var msg = document.createElement("div");
196
+ msg.className = "message message--agent";
197
+ var content = document.createElement("div");
198
+ content.className = "message-content streaming-cursor";
199
+ msg.appendChild(content);
200
+ chatMessages.appendChild(msg);
201
+ scrollToBottom();
202
+ return content;
203
+ }
204
+
205
+ function renderAgentText(final) {
206
+ if (!currentAgentEl) return;
207
+ currentAgentEl.innerHTML = marked.parse(currentAgentText);
208
+ highlightCodeBlocks(currentAgentEl); addCopyButtons(currentAgentEl);
209
+ makeImagesClickable(currentAgentEl); detectAndInsertImages(currentAgentEl, currentAgentText);
210
+ if (final) currentAgentEl.classList.remove("streaming-cursor");
211
+ scrollToBottom();
212
+ }
213
+
214
+ function scheduleRender() {
215
+ if (renderTimer) return;
216
+ renderTimer = setTimeout(function () { renderTimer = null; renderAgentText(false); }, RENDER_DEBOUNCE_MS);
217
+ }
218
+
219
+ function showThinkingIndicator() {
220
+ hideWelcome(); removeThinkingIndicator();
221
+ var el = document.createElement("div");
222
+ el.id = "thinking-msg"; el.className = "thinking-indicator";
223
+ el.innerHTML = '<span class="dot"></span><span class="dot"></span><span class="dot"></span><span class="thinking-label">Thinking...</span>';
224
+ chatMessages.appendChild(el); scrollToBottom();
225
+ }
226
+
227
+ function removeThinkingIndicator() { var el = document.getElementById("thinking-msg"); if (el) el.remove(); }
228
+
229
+ function addToolCallMessage(toolName) {
230
+ hideWelcome();
231
+ var msg = document.createElement("div");
232
+ msg.className = "message message--tool";
233
+
234
+ var wrapper = document.createElement("div");
235
+ wrapper.className = "message-content";
236
+
237
+ var headerEl = document.createElement("div");
238
+ headerEl.className = "tool-header";
239
+ headerEl.setAttribute('role', 'button');
240
+ headerEl.setAttribute('tabindex', '0');
241
+ headerEl.setAttribute('aria-expanded', 'false');
242
+ headerEl.innerHTML =
243
+ '<span class="tool-icon">&#9881;</span>' +
244
+ '<span class="tool-name">' + escapeHtml(toolName) + "</span>" +
245
+ '<span class="tool-status">running...</span>' +
246
+ '<span class="tool-chevron">&#9656;</span>';
247
+
248
+ var body = document.createElement("div");
249
+ body.className = "tool-body";
250
+
251
+ headerEl.addEventListener("click", function () {
252
+ var chevron = headerEl.querySelector(".tool-chevron");
253
+ if (body.classList.contains("tool-body--open")) {
254
+ body.classList.remove("tool-body--open");
255
+ chevron.classList.remove("tool-chevron--open");
256
+ } else {
257
+ body.classList.add("tool-body--open");
258
+ chevron.classList.add("tool-chevron--open");
259
+ }
260
+ headerEl.setAttribute('aria-expanded', body.classList.contains('tool-body--open') ? 'true' : 'false');
261
+ });
262
+
263
+ headerEl.addEventListener('keydown', function(e) {
264
+ if (e.key === 'Enter' || e.key === ' ') {
265
+ e.preventDefault();
266
+ headerEl.click();
267
+ }
268
+ });
269
+
270
+ wrapper.appendChild(headerEl);
271
+ wrapper.appendChild(body);
272
+ msg.appendChild(wrapper);
273
+ chatMessages.appendChild(msg);
274
+ scrollToBottom();
275
+
276
+ currentToolEl = msg;
277
+ return msg;
278
+ }
279
+
280
+ function updateToolStatus(isError) {
281
+ if (!currentToolEl) return;
282
+ var statusEl = currentToolEl.querySelector(".tool-status");
283
+ if (!statusEl) return;
284
+ statusEl.textContent = isError ? "error" : "done";
285
+ statusEl.className = "tool-status tool-status--" + (isError ? "error" : "success");
286
+ }
287
+
288
+ function addErrorMessage(text) {
289
+ hideWelcome();
290
+ var msg = document.createElement("div"); msg.className = "message message--error";
291
+ msg.innerHTML = '<div class="message-content">Error: ' + escapeHtml(text) + "</div>";
292
+ chatMessages.appendChild(msg); scrollToBottom();
293
+ }
294
+
295
+ // -- Inline Image Detection
296
+ var IMAGE_EXTENSIONS = /\.(png|jpg|jpeg|gif|svg|webp)$/i;
297
+ var WORKSPACE_PATH_RE = /(?:\/workspace\/|(?:^|\s))([^\s]+\.(png|jpg|jpeg|gif|svg|webp))/gi;
298
+
299
+ var MIME_MAP = {
300
+ ".png": "image/png", ".jpg": "image/jpeg", ".jpeg": "image/jpeg",
301
+ ".gif": "image/gif", ".svg": "image/svg+xml", ".webp": "image/webp",
302
+ };
303
+ function extToMime(ext) { return MIME_MAP[ext] || "image/png"; }
304
+
305
+ function detectAndInsertImages(container, rawText) {
306
+ WORKSPACE_PATH_RE.lastIndex = 0;
307
+ var matches = [];
308
+ var match;
309
+ while ((match = WORKSPACE_PATH_RE.exec(rawText)) !== null) {
310
+ var filePath = match[1];
311
+ var relative = filePath.replace(/^\/workspace\//, "");
312
+ if (matches.indexOf(relative) === -1) {
313
+ matches.push(relative);
314
+ }
315
+ }
316
+
317
+ matches.forEach(function (relPath) {
318
+ if (container.querySelector('img[data-path="' + relPath + '"]')) return;
319
+
320
+ fetch("/api/file-content/" + encodeURIComponent(relPath))
321
+ .then(function (res) { return res.ok ? res.json() : null; })
322
+ .then(function (data) {
323
+ if (!data || data.type !== "image" || !data.base64) return;
324
+ var src = "data:" + extToMime(data.ext || ".png") + ";base64," + data.base64;
325
+ var img = document.createElement("img");
326
+ img.className = "chat-image";
327
+ img.setAttribute("data-path", relPath);
328
+ img.alt = relPath;
329
+ img.src = src;
330
+ img.addEventListener("click", function () { openImageModal(src); });
331
+ container.appendChild(img);
332
+ })
333
+ .catch(function () { /* ignore missing images */ });
334
+ });
335
+ }
336
+
337
+ // -- Image Modal
338
+ function openImageModal(src) { modalImage.src = src; imageModal.style.display = "flex"; imageModal.classList.add("image-modal--open"); }
339
+ function closeImageModal() { imageModal.classList.remove("image-modal--open"); imageModal.style.display = "none"; modalImage.src = ""; }
340
+ modalClose.addEventListener("click", closeImageModal);
341
+ imageModal.addEventListener("click", function (e) { if (e.target === imageModal) closeImageModal(); });
342
+ document.addEventListener("keydown", function (e) { if (e.key === "Escape") closeImageModal(); });
343
+
344
+ // -- File Tree
345
+ var FILE_ICON_MAP = {
346
+ ".py": { icon: "\uD83D\uDC0D", cls: "ft-icon--py" },
347
+ ".js": { icon: "\u2B21", cls: "ft-icon--js" },
348
+ ".ts": { icon: "\u2B21", cls: "ft-icon--ts" },
349
+ ".json": { icon: "{}", cls: "ft-icon--json" },
350
+ ".md": { icon: "\u270E", cls: "ft-icon--md" },
351
+ ".csv": { icon: "\u2637", cls: "ft-icon--csv" },
352
+ ".html": { icon: "\u2039\u203A", cls: "ft-icon--html" },
353
+ ".css": { icon: "#", cls: "ft-icon--css" },
354
+ ".png": { icon: "\u25A3", cls: "ft-icon--png" },
355
+ ".jpg": { icon: "\u25A3", cls: "ft-icon--jpg" },
356
+ ".jpeg": { icon: "\u25A3", cls: "ft-icon--jpg" },
357
+ ".gif": { icon: "\u25A3", cls: "ft-icon--gif" },
358
+ ".svg": { icon: "\u25C7", cls: "ft-icon--svg" },
359
+ ".yaml": { icon: "\u2699", cls: "ft-icon--yaml" },
360
+ ".yml": { icon: "\u2699", cls: "ft-icon--yml" },
361
+ ".txt": { icon: "\u2261", cls: "ft-icon--default" },
362
+ };
363
+
364
+ function getFileIcon(name, isDir) {
365
+ if (isDir) return { icon: "\u25B6", cls: "ft-icon--dir" };
366
+ var ext = name.lastIndexOf(".") !== -1 ? name.substring(name.lastIndexOf(".")) : "";
367
+ return FILE_ICON_MAP[ext.toLowerCase()] || { icon: "\u2022", cls: "ft-icon--default" };
368
+ }
369
+
370
+ function collectPaths(entries, set) {
371
+ entries.forEach(function (entry) {
372
+ set.add(entry.path);
373
+ if (entry.children) collectPaths(entry.children, set);
374
+ });
375
+ }
376
+
377
+ function collectDirPaths(entries, set) {
378
+ entries.forEach(function (entry) {
379
+ if (entry.type === "directory") {
380
+ set.add(entry.path);
381
+ if (entry.children) collectDirPaths(entry.children, set);
382
+ }
383
+ });
384
+ }
385
+
386
+ function renderFileTree(entries, parentEl, depth, newPaths) {
387
+ var sorted = entries.slice().sort(function (a, b) {
388
+ if (a.type !== b.type) return a.type === "directory" ? -1 : 1;
389
+ return a.name.localeCompare(b.name);
390
+ });
391
+
392
+ sorted.forEach(function (entry) {
393
+ var isDir = entry.type === "directory";
394
+ var isExpanded = isDir && expandedDirs.has(entry.path);
395
+
396
+ var item = document.createElement("div");
397
+ item.className = "ft-item";
398
+ if (newPaths.has(entry.path)) item.classList.add("ft-item--new");
399
+ if (entry.path === activeFilePath) item.classList.add("ft-item--active");
400
+
401
+ var indent = document.createElement("span");
402
+ indent.className = "ft-indent";
403
+ indent.style.width = depth * 16 + "px";
404
+ item.appendChild(indent);
405
+
406
+ if (isDir) {
407
+ // Chevron for expand/collapse
408
+ var chevron = document.createElement("span");
409
+ chevron.className = "ft-icon--dir-chevron";
410
+ chevron.textContent = "\u25B8";
411
+ if (isExpanded) chevron.classList.add("expanded");
412
+ item.appendChild(chevron);
413
+ }
414
+
415
+ var fi = getFileIcon(entry.name, isDir);
416
+ var icon = document.createElement("span");
417
+ icon.className = "ft-icon " + fi.cls;
418
+ icon.textContent = isDir ? "\uD83D\uDCC1" : fi.icon;
419
+ item.appendChild(icon);
420
+
421
+ var nameSpan = document.createElement("span");
422
+ nameSpan.className = "ft-name";
423
+ nameSpan.textContent = entry.name;
424
+ item.appendChild(nameSpan);
425
+
426
+ if (isDir) {
427
+ item.addEventListener("click", function () {
428
+ if (expandedDirs.has(entry.path)) {
429
+ expandedDirs.delete(entry.path);
430
+ } else {
431
+ expandedDirs.add(entry.path);
432
+ }
433
+ refreshFileTreeUI();
434
+ });
435
+ } else {
436
+ item.addEventListener("click", function () {
437
+ openFilePreview(entry.path, entry.name);
438
+ });
439
+ }
440
+
441
+ parentEl.appendChild(item);
442
+
443
+ // Render children only if expanded
444
+ if (isDir && isExpanded && entry.children && entry.children.length > 0) {
445
+ renderFileTree(entry.children, parentEl, depth + 1, newPaths);
446
+ }
447
+ });
448
+ }
449
+
450
+ // Cache the last fetched entries for UI-only refreshes
451
+ var lastFileEntries = null;
452
+ var lastNewPaths = new Set();
453
+
454
+ function refreshFileTreeUI() {
455
+ if (!lastFileEntries) return;
456
+ fileTreeEl.innerHTML = "";
457
+ if (lastFileEntries.length > 0) {
458
+ renderFileTree(lastFileEntries, fileTreeEl, 0, lastNewPaths);
459
+ } else {
460
+ var empty = document.createElement("div");
461
+ empty.className = "ft-item";
462
+ empty.style.color = "var(--text-muted)";
463
+ empty.textContent = "(empty)";
464
+ fileTreeEl.appendChild(empty);
465
+ }
466
+ }
467
+
468
+ // -- File Cards (workspace empty-with-files state)
469
+ function renderFileCards() {
470
+ if (!fileCardGrid || !lastFileEntries) return;
471
+ fileCardGrid.innerHTML = "";
472
+ var files = [];
473
+ (function collect(entries) {
474
+ entries.forEach(function(e) { if (e.type === "file") files.push(e); else if (e.children) collect(e.children); });
475
+ })(lastFileEntries);
476
+ files.reverse().slice(0, 8).forEach(function(file, index) {
477
+ var card = document.createElement("div");
478
+ card.className = "file-card";
479
+ if (lastNewPaths.has(file.path)) card.classList.add("file-card--new");
480
+ card.style.animationDelay = (index * 50) + "ms";
481
+ var nameEl = document.createElement("div");
482
+ nameEl.className = "file-card-name";
483
+ nameEl.textContent = file.name;
484
+ card.appendChild(nameEl);
485
+ var ext = getExtension(file.name);
486
+ var pEl = document.createElement("div");
487
+ pEl.className = "file-card-preview";
488
+ if (IMAGE_EXT_SET.has(ext)) { pEl.innerHTML = '<span style="color:var(--pink);">Image file</span>'; }
489
+ else { var fi = getFileIcon(file.name, false); pEl.innerHTML = '<span>' + fi.icon + ' ' + escapeHtml(ext || 'file') + '</span>'; }
490
+ card.appendChild(pEl);
491
+ card.addEventListener("click", function() { openFilePreview(file.path, file.name); });
492
+ fileCardGrid.appendChild(card);
493
+ });
494
+ }
495
+
496
+ function refreshFileTree() {
497
+ fetch("/api/files")
498
+ .then(function (res) { return res.json(); })
499
+ .then(function (data) {
500
+ if (!data.entries) return;
501
+
502
+ var currentPaths = new Set();
503
+ collectPaths(data.entries, currentPaths);
504
+
505
+ var newPaths = new Set();
506
+ if (previousFilePaths.size > 0) {
507
+ currentPaths.forEach(function (p) {
508
+ if (!previousFilePaths.has(p)) newPaths.add(p);
509
+ });
510
+ }
511
+ previousFilePaths = currentPaths;
512
+
513
+ // Initialize expanded dirs: expand all on first load
514
+ if (!expandedDirsInitialized) {
515
+ expandedDirsInitialized = true;
516
+ collectDirPaths(data.entries, expandedDirs);
517
+ }
518
+
519
+ lastFileEntries = data.entries;
520
+ lastNewPaths = newPaths;
521
+ refreshFileTreeUI();
522
+
523
+ // Transition from empty-no-files to empty-with-files when files appear
524
+ if (workspaceState === "empty-no-files" && currentPaths.size > 0) {
525
+ setWorkspaceState("empty-with-files");
526
+ } else if (workspaceState === "empty-with-files") {
527
+ renderFileCards();
528
+ }
529
+ })
530
+ .catch(function () { /* silent retry */ });
531
+ }
532
+
533
+ function startFilePolling() {
534
+ refreshFileTree();
535
+ filePollingTimer = setInterval(refreshFileTree, FILE_POLL_MS);
536
+ }
537
+
538
+ function stopFilePolling() {
539
+ if (filePollingTimer !== null) {
540
+ clearInterval(filePollingTimer);
541
+ filePollingTimer = null;
542
+ }
543
+ }
544
+
545
+ // -- File Preview (in Workspace)
546
+ var IMAGE_EXT_SET = new Set([".png", ".jpg", ".jpeg", ".gif", ".svg", ".webp"]);
547
+
548
+ function getExtension(name) {
549
+ var idx = name.lastIndexOf(".");
550
+ return idx !== -1 ? name.substring(idx).toLowerCase() : "";
551
+ }
552
+
553
+ var LANG_MAP = {
554
+ ".js": "javascript", ".ts": "typescript", ".tsx": "typescript", ".jsx": "javascript",
555
+ ".py": "python", ".json": "json", ".html": "html", ".css": "css", ".md": "markdown",
556
+ ".sh": "bash", ".yml": "yaml", ".yaml": "yaml", ".xml": "xml", ".sql": "sql",
557
+ ".rb": "ruby", ".go": "go", ".rs": "rust", ".java": "java", ".c": "c", ".cpp": "cpp",
558
+ };
559
+ function extToLang(ext) { return LANG_MAP[ext] || ""; }
560
+
561
+ function openFilePreview(filePath, fileName) {
562
+ activeFilePath = filePath;
563
+ previewArea.setAttribute("data-file-path", filePath);
564
+ previewFilename.textContent = fileName;
565
+
566
+ // Render breadcrumb path
567
+ var breadcrumb = document.getElementById("preview-breadcrumb");
568
+ if (breadcrumb) {
569
+ breadcrumb.innerHTML = "";
570
+ var parts = filePath.replace(/^\/workspace\//, "").split("/");
571
+ parts.forEach(function(part, i) {
572
+ var span = document.createElement("span");
573
+ if (i < parts.length - 1) {
574
+ span.className = "preview-breadcrumb-segment";
575
+ span.textContent = part;
576
+ breadcrumb.appendChild(span);
577
+ var sep = document.createElement("span");
578
+ sep.className = "preview-breadcrumb-separator";
579
+ sep.textContent = "\u203A";
580
+ breadcrumb.appendChild(sep);
581
+ } else {
582
+ span.className = "preview-breadcrumb-current";
583
+ span.id = "preview-filename";
584
+ span.textContent = part;
585
+ breadcrumb.appendChild(span);
586
+ }
587
+ });
588
+ }
589
+
590
+ previewContent.innerHTML = '<div style="color:var(--text-muted);padding:12px;">Loading...</div>';
591
+
592
+ showPreview();
593
+
594
+ var relative = filePath.replace(/^\/workspace\//, "");
595
+ var ext = getExtension(fileName);
596
+
597
+ fetch("/api/file-content/" + encodeURIComponent(relative))
598
+ .then(function (res) {
599
+ if (!res.ok) throw new Error("Not found");
600
+ return res.json();
601
+ })
602
+ .then(function (data) {
603
+ previewContent.innerHTML = "";
604
+ if (data.type === "image" && data.base64) {
605
+ var src = "data:" + extToMime(data.ext || ext) + ";base64," + data.base64;
606
+ var img = document.createElement("img");
607
+ img.src = src;
608
+ img.style.maxWidth = "100%";
609
+ img.style.borderRadius = "var(--radius)";
610
+ img.style.cursor = "pointer";
611
+ img.addEventListener("click", function () { openImageModal(src); });
612
+ previewContent.appendChild(img);
613
+ } else {
614
+ var text = data.content || "";
615
+ var pre = document.createElement("pre");
616
+ var code = document.createElement("code");
617
+ var lang = extToLang(data.ext || ext);
618
+ if (lang) code.className = "language-" + lang;
619
+ code.textContent = text;
620
+ pre.appendChild(code);
621
+ previewContent.appendChild(pre);
622
+ hljs.highlightElement(code);
623
+ }
624
+ })
625
+ .catch(function () {
626
+ previewContent.innerHTML = '<div style="color:var(--red);padding:12px;">Failed to load file.</div>';
627
+ });
628
+
629
+ refreshFileTree();
630
+ }
631
+
632
+ function closeFilePreview() {
633
+ activeFilePath = null;
634
+ showWelcomeOrHide();
635
+ refreshFileTree();
636
+ }
637
+
638
+ previewClose.addEventListener("click", closeFilePreview);
639
+
640
+ // -- Chat Input (Auto-expand Textarea)
641
+ var INPUT_LINE_HEIGHT = 21;
642
+ var INPUT_MAX_ROWS = 4;
643
+
644
+ chatInput.addEventListener("input", function () {
645
+ chatInput.style.height = "auto";
646
+ var maxH = INPUT_LINE_HEIGHT * INPUT_MAX_ROWS + 20;
647
+ chatInput.style.height = Math.min(chatInput.scrollHeight, maxH) + "px";
648
+ });
649
+
650
+ chatInput.addEventListener("keydown", function (e) {
651
+ if (e.key === "Enter" && !e.shiftKey) {
652
+ e.preventDefault();
653
+ chatForm.dispatchEvent(new Event("submit", { cancelable: true }));
654
+ }
655
+ });
656
+
657
+ // -- Chat Submission
658
+ function sendMessage(text) {
659
+ if (!text || isStreaming) return;
660
+ if (!ws || ws.readyState !== WebSocket.OPEN) {
661
+ addErrorMessage("Not connected to agent.");
662
+ return;
663
+ }
664
+
665
+ isStreaming = true;
666
+ setStatus("running");
667
+ setInputEnabled(false);
668
+ addUserMessage(text);
669
+
670
+ ws.send(JSON.stringify({
671
+ type: "chat",
672
+ input: [{ role: "user", content: text }],
673
+ }));
674
+ }
675
+
676
+ chatForm.addEventListener("submit", function (e) {
677
+ e.preventDefault();
678
+ var text = chatInput.value.trim();
679
+ if (text.length === 0) return;
680
+ chatInput.value = "";
681
+ chatInput.style.height = "auto";
682
+ sendMessage(text);
683
+ });
684
+
685
+ // -- Agent Event Handling (WebSocket)
686
+ function handleAgentEvent(event) {
687
+ switch (event.type) {
688
+ case "response.created":
689
+ setStatus("running");
690
+ showThinkingIndicator();
691
+ break;
692
+
693
+ case "response.output_text.delta":
694
+ removeThinkingIndicator();
695
+ if (!currentAgentEl) {
696
+ currentAgentText = "";
697
+ currentAgentEl = createAgentMessage();
698
+ }
699
+ currentAgentText += event.delta;
700
+ scheduleRender();
701
+ break;
702
+
703
+ case "response.output_text.done":
704
+ removeThinkingIndicator();
705
+ if (currentAgentEl) {
706
+ if (event.text) currentAgentText = event.text;
707
+ if (renderTimer) { clearTimeout(renderTimer); renderTimer = null; }
708
+ renderAgentText(true);
709
+ }
710
+ currentAgentEl = null;
711
+ currentAgentText = "";
712
+ break;
713
+
714
+ case "response.tool_call.created":
715
+ removeThinkingIndicator();
716
+ if (currentAgentEl) {
717
+ if (renderTimer) { clearTimeout(renderTimer); renderTimer = null; }
718
+ renderAgentText(true);
719
+ currentAgentEl = null;
720
+ currentAgentText = "";
721
+ }
722
+ var toolName = (event.toolCall && event.toolCall.name) || "tool";
723
+ addToolCallMessage(toolName);
724
+ break;
725
+
726
+ case "response.tool_call.done":
727
+ var isError = event.result && event.result.isError;
728
+ updateToolStatus(isError);
729
+ if (isError && event.result.output) {
730
+ if (currentToolEl) {
731
+ var body = currentToolEl.querySelector(".tool-body");
732
+ if (body) {
733
+ body.textContent = typeof event.result.output === "string"
734
+ ? event.result.output
735
+ : JSON.stringify(event.result.output, null, 2);
736
+ body.classList.add("tool-body--open");
737
+ var chevron = currentToolEl.querySelector(".tool-chevron");
738
+ if (chevron) chevron.classList.add("tool-chevron--open");
739
+ }
740
+ }
741
+ }
742
+ currentToolEl = null;
743
+ break;
744
+
745
+ case "response.completed":
746
+ removeThinkingIndicator();
747
+ if (currentAgentEl) {
748
+ if (renderTimer) { clearTimeout(renderTimer); renderTimer = null; }
749
+ renderAgentText(true);
750
+ currentAgentEl = null;
751
+ currentAgentText = "";
752
+ }
753
+ setStatus("idle");
754
+ setInputEnabled(true);
755
+ isStreaming = false;
756
+ refreshFileTree();
757
+
758
+ // Auto-open highest priority new file
759
+ var newFiles = [];
760
+ if (previousFilePaths.size > 0) {
761
+ var nowPaths = new Set();
762
+ collectPaths(lastFileEntries || [], nowPaths);
763
+ nowPaths.forEach(function(p) { if (!previousFilePaths.has(p)) newFiles.push(p); });
764
+ }
765
+ if (newFiles.length > 0) {
766
+ newFiles.sort(function(a, b) {
767
+ var ea = getExtension(a), eb = getExtension(b);
768
+ return (IMAGE_EXT_SET.has(ea) ? 0 : ea === ".md" ? 1 : 2) - (IMAGE_EXT_SET.has(eb) ? 0 : eb === ".md" ? 1 : 2);
769
+ });
770
+ openFilePreview(newFiles[0], newFiles[0].split("/").pop());
771
+ }
772
+ break;
773
+
774
+ case "response.error":
775
+ removeThinkingIndicator();
776
+ if (currentAgentEl) {
777
+ if (renderTimer) { clearTimeout(renderTimer); renderTimer = null; }
778
+ renderAgentText(true);
779
+ currentAgentEl = null;
780
+ currentAgentText = "";
781
+ }
782
+ addErrorMessage(event.error || "Unknown error");
783
+ setStatus("error");
784
+ setInputEnabled(true);
785
+ isStreaming = false;
786
+ break;
787
+
788
+ case "files_changed":
789
+ refreshFileTree();
790
+ break;
791
+ }
792
+ }
793
+
794
+ // -- WebSocket Connection
795
+ var disconnectedShown = false;
796
+
797
+ function connectWebSocket() {
798
+ var protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
799
+ var url = protocol + "//" + window.location.host + "/ws";
800
+ ws = new WebSocket(url);
801
+
802
+ ws.onopen = function () {
803
+ disconnectedShown = false;
804
+ setStatus("idle");
805
+ };
806
+
807
+ ws.onmessage = function (msg) {
808
+ try {
809
+ var event = JSON.parse(msg.data);
810
+ handleAgentEvent(event);
811
+ } catch (_) { /* ignore */ }
812
+ };
813
+
814
+ ws.onclose = function () {
815
+ if (!disconnectedShown) {
816
+ disconnectedShown = true;
817
+ }
818
+ setStatus("idle");
819
+ setInputEnabled(true);
820
+ isStreaming = false;
821
+ setTimeout(connectWebSocket, 3000);
822
+ };
823
+
824
+ ws.onerror = function () { /* onclose fires after */ };
825
+ }
826
+
827
+ // -- Keyboard Shortcuts
828
+ document.addEventListener('keydown', function(e) {
829
+ // Escape closes file preview
830
+ if (e.key === 'Escape' && activeFilePath) {
831
+ closeFilePreview();
832
+ return;
833
+ }
834
+ // Cmd/Ctrl + K focuses chat input
835
+ if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
836
+ e.preventDefault();
837
+ chatInput.focus();
838
+ return;
839
+ }
840
+ });
841
+
842
+ // -- Init
843
+ window.addEventListener("files-changed", refreshFileTree);
844
+ fetchAgentInfo();
845
+ startFilePolling();
846
+ connectWebSocket();
847
+ })();