aimeat 1.2.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 (1366) hide show
  1. package/dist/.env.example +300 -0
  2. package/dist/bin/aimeat.d.ts +3 -0
  3. package/dist/bin/aimeat.d.ts.map +1 -0
  4. package/dist/bin/aimeat.js +22 -0
  5. package/dist/bin/aimeat.js.map +1 -0
  6. package/dist/locales/en.json +4566 -0
  7. package/dist/locales/fi.json +4566 -0
  8. package/dist/public/BingSiteAuth.xml +4 -0
  9. package/dist/public/agent-consent.html +521 -0
  10. package/dist/public/aimeat-developers.html +679 -0
  11. package/dist/public/assets/mcp_1_add_custom_connector.png +0 -0
  12. package/dist/public/assets/mcp_2_connect_disconnect_connector.png +0 -0
  13. package/dist/public/components/Alert.js +18 -0
  14. package/dist/public/components/Card.js +19 -0
  15. package/dist/public/components/CopyButton.js +24 -0
  16. package/dist/public/components/FormField.js +16 -0
  17. package/dist/public/components/Modal.js +121 -0
  18. package/dist/public/components/Spinner.js +11 -0
  19. package/dist/public/components/Toast.js +26 -0
  20. package/dist/public/components/index.js +8 -0
  21. package/dist/public/components/useViewCSS.js +12 -0
  22. package/dist/public/cortex-bundled/aimeat-canvas.js +1408 -0
  23. package/dist/public/cortex-bundled/aimeat-canvas.yaml +241 -0
  24. package/dist/public/cortex-bundled/aimeat-charts.js +455 -0
  25. package/dist/public/cortex-bundled/aimeat-charts.yaml +178 -0
  26. package/dist/public/cortex-bundled/aimeat-ui-dialogs.js +667 -0
  27. package/dist/public/cortex-bundled/aimeat-ui-dialogs.yaml +66 -0
  28. package/dist/public/cortex-bundled/aimeat-ui-forms.js +1106 -0
  29. package/dist/public/cortex-bundled/aimeat-ui-forms.yaml +90 -0
  30. package/dist/public/cortex-bundled/aimeat-ui-layout.js +436 -0
  31. package/dist/public/cortex-bundled/aimeat-ui-layout.yaml +87 -0
  32. package/dist/public/cortex-bundled/aimeat-ui-nav.js +722 -0
  33. package/dist/public/cortex-bundled/aimeat-ui-nav.yaml +73 -0
  34. package/dist/public/cortex-bundled/aimeat-ui-viewers.js +602 -0
  35. package/dist/public/cortex-bundled/aimeat-ui-viewers.yaml +73 -0
  36. package/dist/public/css/components/tags.css +67 -0
  37. package/dist/public/css/theme.css +716 -0
  38. package/dist/public/css/views/admin.css +576 -0
  39. package/dist/public/css/views/aimeat-os.css +153 -0
  40. package/dist/public/css/views/calibrator.css +480 -0
  41. package/dist/public/css/views/foundry.css +1334 -0
  42. package/dist/public/css/views/help.css +136 -0
  43. package/dist/public/css/views/hobbies.css +73 -0
  44. package/dist/public/css/views/marketplace.css +134 -0
  45. package/dist/public/css/views/openclaw.css +33 -0
  46. package/dist/public/css/views/portal-classic.css +484 -0
  47. package/dist/public/css/views/portal-dev.css +139 -0
  48. package/dist/public/css/views/portal.css +365 -0
  49. package/dist/public/css/views/portfolio.css +322 -0
  50. package/dist/public/css/views/profile.css +1799 -0
  51. package/dist/public/echat.html +442 -0
  52. package/dist/public/img/genesis-001-badge.png +0 -0
  53. package/dist/public/img/platforms/chatgpt.png +0 -0
  54. package/dist/public/img/platforms/claude.png +0 -0
  55. package/dist/public/img/platforms/copilot.png +0 -0
  56. package/dist/public/img/platforms/deepseek.png +0 -0
  57. package/dist/public/img/platforms/gemini.png +0 -0
  58. package/dist/public/img/platforms/grok.png +0 -0
  59. package/dist/public/img/platforms/lmstudio.png +0 -0
  60. package/dist/public/img/platforms/m365copilot.png +0 -0
  61. package/dist/public/img/platforms/openclaw.png +0 -0
  62. package/dist/public/img/platforms/other.png +0 -0
  63. package/dist/public/js/api.js +123 -0
  64. package/dist/public/js/components/auth-image.js +59 -0
  65. package/dist/public/js/components/tag-cloud.js +31 -0
  66. package/dist/public/js/components/tag-editor.js +46 -0
  67. package/dist/public/js/hooks.js +63 -0
  68. package/dist/public/js/i18n.js +76 -0
  69. package/dist/public/js/services/admin.js +239 -0
  70. package/dist/public/js/services/agents.js +57 -0
  71. package/dist/public/js/services/apps.js +35 -0
  72. package/dist/public/js/services/auth.js +40 -0
  73. package/dist/public/js/services/boards.js +79 -0
  74. package/dist/public/js/services/calibrator.js +97 -0
  75. package/dist/public/js/services/catalogue.js +39 -0
  76. package/dist/public/js/services/consent.js +57 -0
  77. package/dist/public/js/services/cortex.js +95 -0
  78. package/dist/public/js/services/extensions.js +61 -0
  79. package/dist/public/js/services/federation.js +11 -0
  80. package/dist/public/js/services/foundry-context-bundle.js +128 -0
  81. package/dist/public/js/services/foundry-contract.js +117 -0
  82. package/dist/public/js/services/foundry-packaging.js +762 -0
  83. package/dist/public/js/services/foundry-probe-reconcile.js +52 -0
  84. package/dist/public/js/services/foundry-prompts-base.js +1886 -0
  85. package/dist/public/js/services/foundry-prompts-build.js +2187 -0
  86. package/dist/public/js/services/foundry-prompts-cortex-app.js +154 -0
  87. package/dist/public/js/services/foundry-prompts-cortex-data.js +241 -0
  88. package/dist/public/js/services/foundry-prompts-cortex-feature.js +281 -0
  89. package/dist/public/js/services/foundry-prompts-fix.js +408 -0
  90. package/dist/public/js/services/foundry-prompts-test.js +520 -0
  91. package/dist/public/js/services/foundry-prompts.js +31 -0
  92. package/dist/public/js/services/foundry-smoke.js +65 -0
  93. package/dist/public/js/services/foundry-testing.js +64 -0
  94. package/dist/public/js/services/foundry-validate.js +1082 -0
  95. package/dist/public/js/services/foundry.js +1194 -0
  96. package/dist/public/js/services/generator-context-bundle.js +134 -0
  97. package/dist/public/js/services/generator-contract.js +117 -0
  98. package/dist/public/js/services/generator-packaging.js +762 -0
  99. package/dist/public/js/services/generator-probe-reconcile.js +52 -0
  100. package/dist/public/js/services/generator-prompts-base.js +1890 -0
  101. package/dist/public/js/services/generator-prompts-build.js +1126 -0
  102. package/dist/public/js/services/generator-prompts-cortex-app.js +155 -0
  103. package/dist/public/js/services/generator-prompts-cortex-data.js +199 -0
  104. package/dist/public/js/services/generator-prompts-cortex-feature.js +276 -0
  105. package/dist/public/js/services/generator-prompts-fix.js +316 -0
  106. package/dist/public/js/services/generator-prompts-test.js +402 -0
  107. package/dist/public/js/services/generator-prompts.js +31 -0
  108. package/dist/public/js/services/generator-smoke.js +65 -0
  109. package/dist/public/js/services/generator-spec-tests.js +280 -0
  110. package/dist/public/js/services/generator-spec-validate.js +192 -0
  111. package/dist/public/js/services/generator-specs.js +369 -0
  112. package/dist/public/js/services/generator-testing.js +64 -0
  113. package/dist/public/js/services/generator-validate.js +916 -0
  114. package/dist/public/js/services/generator.js +952 -0
  115. package/dist/public/js/services/knowledge.js +120 -0
  116. package/dist/public/js/services/memory.js +112 -0
  117. package/dist/public/js/services/nodes.js +55 -0
  118. package/dist/public/js/services/organisms.js +74 -0
  119. package/dist/public/js/services/packages.js +97 -0
  120. package/dist/public/js/services/security.js +67 -0
  121. package/dist/public/js/services/stats.js +11 -0
  122. package/dist/public/js/services/wallet.js +24 -0
  123. package/dist/public/js/services/work.js +51 -0
  124. package/dist/public/js/utils.js +184 -0
  125. package/dist/public/lib/htm.mjs +4 -0
  126. package/dist/public/lib/live-updates.js +89 -0
  127. package/dist/public/lib/minidenticons.min.js +1 -0
  128. package/dist/public/lib/preact-hooks.mjs +3 -0
  129. package/dist/public/lib/preact.mjs +3 -0
  130. package/dist/public/lib/realtime.js +549 -0
  131. package/dist/public/lib/three.min.js +6 -0
  132. package/dist/public/lib/yaml.mjs +141 -0
  133. package/dist/public/llms-template.txt +1043 -0
  134. package/dist/public/oauth-consent.html +388 -0
  135. package/dist/public/og-image.png +0 -0
  136. package/dist/public/robots.txt +52 -0
  137. package/dist/public/spa.html +533 -0
  138. package/dist/public/sw.js +34 -0
  139. package/dist/public/tmp-paste.txt +223 -0
  140. package/dist/public/views/_template.js +85 -0
  141. package/dist/public/views/admin/actions-tab.js +41 -0
  142. package/dist/public/views/admin/agents-tab.js +84 -0
  143. package/dist/public/views/admin/boards-tab.js +154 -0
  144. package/dist/public/views/admin/chat-instances-tab.js +207 -0
  145. package/dist/public/views/admin/config-tab.js +151 -0
  146. package/dist/public/views/admin/consul-tab.js +77 -0
  147. package/dist/public/views/admin/cors-tab.js +240 -0
  148. package/dist/public/views/admin/cortex-tab.js +171 -0
  149. package/dist/public/views/admin/csm-tab.js +261 -0
  150. package/dist/public/views/admin/directory-tab.js +44 -0
  151. package/dist/public/views/admin/economy-tab.js +80 -0
  152. package/dist/public/views/admin/email-tab.js +460 -0
  153. package/dist/public/views/admin/federation-tab.js +412 -0
  154. package/dist/public/views/admin/generator-debug-tab.js +238 -0
  155. package/dist/public/views/admin/genesis-tab.js +70 -0
  156. package/dist/public/views/admin/ghii-tab.js +101 -0
  157. package/dist/public/views/admin/hooks-tab.js +69 -0
  158. package/dist/public/views/admin/knowledge-tab.js +297 -0
  159. package/dist/public/views/admin/maintenance-tab.js +98 -0
  160. package/dist/public/views/admin/matching-tab.js +44 -0
  161. package/dist/public/views/admin/memory-tab.js +222 -0
  162. package/dist/public/views/admin/msm-tab.js +342 -0
  163. package/dist/public/views/admin/overview-tab.js +90 -0
  164. package/dist/public/views/admin/owners-tab.js +55 -0
  165. package/dist/public/views/admin/packages-tab.js +510 -0
  166. package/dist/public/views/admin/portal-tab.js +211 -0
  167. package/dist/public/views/admin/prompts-tab.js +287 -0
  168. package/dist/public/views/admin/push-tab.js +291 -0
  169. package/dist/public/views/admin/realtime-tab.js +68 -0
  170. package/dist/public/views/admin/scheduler-tab.js +156 -0
  171. package/dist/public/views/admin/services-tab.js +981 -0
  172. package/dist/public/views/admin/shared.js +148 -0
  173. package/dist/public/views/admin/stats-tab.js +187 -0
  174. package/dist/public/views/admin/work-tab.js +45 -0
  175. package/dist/public/views/admin.js +400 -0
  176. package/dist/public/views/aimeat-os.js +259 -0
  177. package/dist/public/views/guides.js +402 -0
  178. package/dist/public/views/help.js +79 -0
  179. package/dist/public/views/hobbies.js +697 -0
  180. package/dist/public/views/marketplace.js +647 -0
  181. package/dist/public/views/openclaw.js +223 -0
  182. package/dist/public/views/portal-classic.js +519 -0
  183. package/dist/public/views/portal-dev.js +816 -0
  184. package/dist/public/views/portal.js +1354 -0
  185. package/dist/public/views/portfolio.js +795 -0
  186. package/dist/public/views/profile/access-tab.js +58 -0
  187. package/dist/public/views/profile/agents-tab.js +689 -0
  188. package/dist/public/views/profile/apps-tab.js +197 -0
  189. package/dist/public/views/profile/boards-tab.js +323 -0
  190. package/dist/public/views/profile/calibrator-batch.js +926 -0
  191. package/dist/public/views/profile/calibrator-chart.js +135 -0
  192. package/dist/public/views/profile/calibrator-llm-editor.js +205 -0
  193. package/dist/public/views/profile/calibrator-tab.js +535 -0
  194. package/dist/public/views/profile/chat-sessions-tab.js +184 -0
  195. package/dist/public/views/profile/data-wallet-tab.js +313 -0
  196. package/dist/public/views/profile/email-tab.js +157 -0
  197. package/dist/public/views/profile/extensions-tab.js +711 -0
  198. package/dist/public/views/profile/federation-tab.js +63 -0
  199. package/dist/public/views/profile/foundry-dashboard/DebugPanel.js +193 -0
  200. package/dist/public/views/profile/foundry-dashboard/DiagnosticsPanel.js +69 -0
  201. package/dist/public/views/profile/foundry-dashboard/EditModePanel.js +141 -0
  202. package/dist/public/views/profile/foundry-dashboard/PackageDialog.js +96 -0
  203. package/dist/public/views/profile/foundry-dashboard/RemovePanel.js +53 -0
  204. package/dist/public/views/profile/foundry-dashboard/use-autopilot-state.js +53 -0
  205. package/dist/public/views/profile/foundry-dashboard/use-autopilot.js +1016 -0
  206. package/dist/public/views/profile/foundry-dashboard/use-dashboard-core.js +154 -0
  207. package/dist/public/views/profile/foundry-dashboard/use-edit-mode.js +294 -0
  208. package/dist/public/views/profile/foundry-dashboard/use-lifecycle.js +101 -0
  209. package/dist/public/views/profile/foundry-dashboard/use-packaging.js +97 -0
  210. package/dist/public/views/profile/foundry-dashboard/use-test-execution.js +275 -0
  211. package/dist/public/views/profile/foundry-dashboard.js +395 -0
  212. package/dist/public/views/profile/foundry-detail.js +1178 -0
  213. package/dist/public/views/profile/foundry-settings.js +377 -0
  214. package/dist/public/views/profile/foundry-tab.js +546 -0
  215. package/dist/public/views/profile/generator-dashboard/DebugPanel.js +193 -0
  216. package/dist/public/views/profile/generator-dashboard/DiagnosticsPanel.js +69 -0
  217. package/dist/public/views/profile/generator-dashboard/EditModePanel.js +141 -0
  218. package/dist/public/views/profile/generator-dashboard/PackageDialog.js +96 -0
  219. package/dist/public/views/profile/generator-dashboard/RemovePanel.js +53 -0
  220. package/dist/public/views/profile/generator-dashboard/use-autopilot-state.js +53 -0
  221. package/dist/public/views/profile/generator-dashboard/use-autopilot.js +136 -0
  222. package/dist/public/views/profile/generator-dashboard/use-dashboard-core.js +143 -0
  223. package/dist/public/views/profile/generator-dashboard/use-edit-mode.js +296 -0
  224. package/dist/public/views/profile/generator-dashboard/use-lifecycle.js +101 -0
  225. package/dist/public/views/profile/generator-dashboard/use-packaging.js +97 -0
  226. package/dist/public/views/profile/generator-dashboard/use-test-execution.js +275 -0
  227. package/dist/public/views/profile/generator-dashboard.js +377 -0
  228. package/dist/public/views/profile/generator-detail.js +1007 -0
  229. package/dist/public/views/profile/generator-settings.js +417 -0
  230. package/dist/public/views/profile/generator-tab.js +544 -0
  231. package/dist/public/views/profile/inline-panels.js +277 -0
  232. package/dist/public/views/profile/knowledge-tab.js +735 -0
  233. package/dist/public/views/profile/landing-page.js +539 -0
  234. package/dist/public/views/profile/mcp-tab.js +140 -0
  235. package/dist/public/views/profile/memory-tab.js +599 -0
  236. package/dist/public/views/profile/node-stats-tab.js +132 -0
  237. package/dist/public/views/profile/nodes-tab.js +195 -0
  238. package/dist/public/views/profile/notifications-tab.js +274 -0
  239. package/dist/public/views/profile/organisms-tab.js +402 -0
  240. package/dist/public/views/profile/packages-tab.js +393 -0
  241. package/dist/public/views/profile/portfolio-tab.js +31 -0
  242. package/dist/public/views/profile/security-tab.js +219 -0
  243. package/dist/public/views/profile/services-tab.js +281 -0
  244. package/dist/public/views/profile/shared.js +58 -0
  245. package/dist/public/views/profile/wallet-tab.js +272 -0
  246. package/dist/public/views/profile/work-tab.js +220 -0
  247. package/dist/public/views/profile.js +271 -0
  248. package/dist/public/wizard.html +1320 -0
  249. package/dist/scripts/db-init.d.ts +19 -0
  250. package/dist/scripts/db-init.d.ts.map +1 -0
  251. package/dist/scripts/db-init.js +168 -0
  252. package/dist/scripts/db-init.js.map +1 -0
  253. package/dist/scripts/db-reset.d.ts +15 -0
  254. package/dist/scripts/db-reset.d.ts.map +1 -0
  255. package/dist/scripts/db-reset.js +162 -0
  256. package/dist/scripts/db-reset.js.map +1 -0
  257. package/dist/scripts/indexnow.d.ts +18 -0
  258. package/dist/scripts/indexnow.d.ts.map +1 -0
  259. package/dist/scripts/indexnow.js +104 -0
  260. package/dist/scripts/indexnow.js.map +1 -0
  261. package/dist/scripts/kill-port.d.ts +3 -0
  262. package/dist/scripts/kill-port.d.ts.map +1 -0
  263. package/dist/scripts/kill-port.js +89 -0
  264. package/dist/scripts/kill-port.js.map +1 -0
  265. package/dist/scripts/seed-digital-signage.d.ts +13 -0
  266. package/dist/scripts/seed-digital-signage.d.ts.map +1 -0
  267. package/dist/scripts/seed-digital-signage.js +85 -0
  268. package/dist/scripts/seed-digital-signage.js.map +1 -0
  269. package/dist/src/auth/jwt.d.ts +40 -0
  270. package/dist/src/auth/jwt.d.ts.map +1 -0
  271. package/dist/src/auth/jwt.js +139 -0
  272. package/dist/src/auth/jwt.js.map +1 -0
  273. package/dist/src/auth/keypair.d.ts +8 -0
  274. package/dist/src/auth/keypair.d.ts.map +1 -0
  275. package/dist/src/auth/keypair.js +35 -0
  276. package/dist/src/auth/keypair.js.map +1 -0
  277. package/dist/src/auth/middleware.d.ts +50 -0
  278. package/dist/src/auth/middleware.d.ts.map +1 -0
  279. package/dist/src/auth/middleware.js +241 -0
  280. package/dist/src/auth/middleware.js.map +1 -0
  281. package/dist/src/auth/node-keys.d.ts +7 -0
  282. package/dist/src/auth/node-keys.d.ts.map +1 -0
  283. package/dist/src/auth/node-keys.js +116 -0
  284. package/dist/src/auth/node-keys.js.map +1 -0
  285. package/dist/src/cli/config-export.d.ts +9 -0
  286. package/dist/src/cli/config-export.d.ts.map +1 -0
  287. package/dist/src/cli/config-export.js +90 -0
  288. package/dist/src/cli/config-export.js.map +1 -0
  289. package/dist/src/cli/config-import.d.ts +10 -0
  290. package/dist/src/cli/config-import.d.ts.map +1 -0
  291. package/dist/src/cli/config-import.js +124 -0
  292. package/dist/src/cli/config-import.js.map +1 -0
  293. package/dist/src/cli/federation-join.d.ts +13 -0
  294. package/dist/src/cli/federation-join.d.ts.map +1 -0
  295. package/dist/src/cli/federation-join.js +395 -0
  296. package/dist/src/cli/federation-join.js.map +1 -0
  297. package/dist/src/cli/init-wizard.d.ts +8 -0
  298. package/dist/src/cli/init-wizard.d.ts.map +1 -0
  299. package/dist/src/cli/init-wizard.js +1489 -0
  300. package/dist/src/cli/init-wizard.js.map +1 -0
  301. package/dist/src/cli/scaffold.d.ts +33 -0
  302. package/dist/src/cli/scaffold.d.ts.map +1 -0
  303. package/dist/src/cli/scaffold.js +142 -0
  304. package/dist/src/cli/scaffold.js.map +1 -0
  305. package/dist/src/config.d.ts +272 -0
  306. package/dist/src/config.d.ts.map +1 -0
  307. package/dist/src/config.js +362 -0
  308. package/dist/src/config.js.map +1 -0
  309. package/dist/src/data/example-packages.d.ts +49 -0
  310. package/dist/src/data/example-packages.d.ts.map +1 -0
  311. package/dist/src/data/example-packages.js +814 -0
  312. package/dist/src/data/example-packages.js.map +1 -0
  313. package/dist/src/i18n.d.ts +19 -0
  314. package/dist/src/i18n.d.ts.map +1 -0
  315. package/dist/src/i18n.js +126 -0
  316. package/dist/src/i18n.js.map +1 -0
  317. package/dist/src/index.d.ts +3 -0
  318. package/dist/src/index.d.ts.map +1 -0
  319. package/dist/src/index.js +608 -0
  320. package/dist/src/index.js.map +1 -0
  321. package/dist/src/mcp/boards.d.ts +18 -0
  322. package/dist/src/mcp/boards.d.ts.map +1 -0
  323. package/dist/src/mcp/boards.js +279 -0
  324. package/dist/src/mcp/boards.js.map +1 -0
  325. package/dist/src/mcp/catalogue.d.ts +17 -0
  326. package/dist/src/mcp/catalogue.d.ts.map +1 -0
  327. package/dist/src/mcp/catalogue.js +114 -0
  328. package/dist/src/mcp/catalogue.js.map +1 -0
  329. package/dist/src/mcp/chat-instances.d.ts +18 -0
  330. package/dist/src/mcp/chat-instances.d.ts.map +1 -0
  331. package/dist/src/mcp/chat-instances.js +161 -0
  332. package/dist/src/mcp/chat-instances.js.map +1 -0
  333. package/dist/src/mcp/consent.d.ts +18 -0
  334. package/dist/src/mcp/consent.d.ts.map +1 -0
  335. package/dist/src/mcp/consent.js +158 -0
  336. package/dist/src/mcp/consent.js.map +1 -0
  337. package/dist/src/mcp/core.d.ts +18 -0
  338. package/dist/src/mcp/core.d.ts.map +1 -0
  339. package/dist/src/mcp/core.js +489 -0
  340. package/dist/src/mcp/core.js.map +1 -0
  341. package/dist/src/mcp/extensions.d.ts +18 -0
  342. package/dist/src/mcp/extensions.d.ts.map +1 -0
  343. package/dist/src/mcp/extensions.js +299 -0
  344. package/dist/src/mcp/extensions.js.map +1 -0
  345. package/dist/src/mcp/flags.d.ts +18 -0
  346. package/dist/src/mcp/flags.d.ts.map +1 -0
  347. package/dist/src/mcp/flags.js +59 -0
  348. package/dist/src/mcp/flags.js.map +1 -0
  349. package/dist/src/mcp/index.d.ts +31 -0
  350. package/dist/src/mcp/index.d.ts.map +1 -0
  351. package/dist/src/mcp/index.js +694 -0
  352. package/dist/src/mcp/index.js.map +1 -0
  353. package/dist/src/mcp/knowledge.d.ts +18 -0
  354. package/dist/src/mcp/knowledge.d.ts.map +1 -0
  355. package/dist/src/mcp/knowledge.js +214 -0
  356. package/dist/src/mcp/knowledge.js.map +1 -0
  357. package/dist/src/mcp/memory-extended.d.ts +18 -0
  358. package/dist/src/mcp/memory-extended.d.ts.map +1 -0
  359. package/dist/src/mcp/memory-extended.js +73 -0
  360. package/dist/src/mcp/memory-extended.js.map +1 -0
  361. package/dist/src/mcp/organisms.d.ts +18 -0
  362. package/dist/src/mcp/organisms.d.ts.map +1 -0
  363. package/dist/src/mcp/organisms.js +291 -0
  364. package/dist/src/mcp/organisms.js.map +1 -0
  365. package/dist/src/mcp/prompts.d.ts +17 -0
  366. package/dist/src/mcp/prompts.d.ts.map +1 -0
  367. package/dist/src/mcp/prompts.js +65 -0
  368. package/dist/src/mcp/prompts.js.map +1 -0
  369. package/dist/src/mcp/wallet-extended.d.ts +17 -0
  370. package/dist/src/mcp/wallet-extended.d.ts.map +1 -0
  371. package/dist/src/mcp/wallet-extended.js +42 -0
  372. package/dist/src/mcp/wallet-extended.js.map +1 -0
  373. package/dist/src/middleware/__tests__/cookie-consent.test.d.ts +2 -0
  374. package/dist/src/middleware/__tests__/cookie-consent.test.d.ts.map +1 -0
  375. package/dist/src/middleware/__tests__/cookie-consent.test.js +432 -0
  376. package/dist/src/middleware/__tests__/cookie-consent.test.js.map +1 -0
  377. package/dist/src/middleware/cookie-consent.d.ts +19 -0
  378. package/dist/src/middleware/cookie-consent.d.ts.map +1 -0
  379. package/dist/src/middleware/cookie-consent.js +127 -0
  380. package/dist/src/middleware/cookie-consent.js.map +1 -0
  381. package/dist/src/middleware/cors.d.ts +12 -0
  382. package/dist/src/middleware/cors.d.ts.map +1 -0
  383. package/dist/src/middleware/cors.js +112 -0
  384. package/dist/src/middleware/cors.js.map +1 -0
  385. package/dist/src/middleware/envelope.d.ts +33 -0
  386. package/dist/src/middleware/envelope.d.ts.map +1 -0
  387. package/dist/src/middleware/envelope.js +32 -0
  388. package/dist/src/middleware/envelope.js.map +1 -0
  389. package/dist/src/middleware/idempotency.d.ts +3 -0
  390. package/dist/src/middleware/idempotency.d.ts.map +1 -0
  391. package/dist/src/middleware/idempotency.js +64 -0
  392. package/dist/src/middleware/idempotency.js.map +1 -0
  393. package/dist/src/middleware/metrics.d.ts +8 -0
  394. package/dist/src/middleware/metrics.d.ts.map +1 -0
  395. package/dist/src/middleware/metrics.js +25 -0
  396. package/dist/src/middleware/metrics.js.map +1 -0
  397. package/dist/src/middleware/rate-limit.d.ts +4 -0
  398. package/dist/src/middleware/rate-limit.d.ts.map +1 -0
  399. package/dist/src/middleware/rate-limit.js +73 -0
  400. package/dist/src/middleware/rate-limit.js.map +1 -0
  401. package/dist/src/middleware/request-id.d.ts +18 -0
  402. package/dist/src/middleware/request-id.d.ts.map +1 -0
  403. package/dist/src/middleware/request-id.js +23 -0
  404. package/dist/src/middleware/request-id.js.map +1 -0
  405. package/dist/src/middleware/stats.d.ts +4 -0
  406. package/dist/src/middleware/stats.d.ts.map +1 -0
  407. package/dist/src/middleware/stats.js +11 -0
  408. package/dist/src/middleware/stats.js.map +1 -0
  409. package/dist/src/middleware/workspace-access.d.ts +16 -0
  410. package/dist/src/middleware/workspace-access.d.ts.map +1 -0
  411. package/dist/src/middleware/workspace-access.js +115 -0
  412. package/dist/src/middleware/workspace-access.js.map +1 -0
  413. package/dist/src/models/schemas.d.ts +311 -0
  414. package/dist/src/models/schemas.d.ts.map +1 -0
  415. package/dist/src/models/schemas.js +281 -0
  416. package/dist/src/models/schemas.js.map +1 -0
  417. package/dist/src/routes/actions.d.ts +5 -0
  418. package/dist/src/routes/actions.d.ts.map +1 -0
  419. package/dist/src/routes/actions.js +199 -0
  420. package/dist/src/routes/actions.js.map +1 -0
  421. package/dist/src/routes/admin-agents.d.ts +5 -0
  422. package/dist/src/routes/admin-agents.d.ts.map +1 -0
  423. package/dist/src/routes/admin-agents.js +60 -0
  424. package/dist/src/routes/admin-agents.js.map +1 -0
  425. package/dist/src/routes/admin-config.d.ts +7 -0
  426. package/dist/src/routes/admin-config.d.ts.map +1 -0
  427. package/dist/src/routes/admin-config.js +209 -0
  428. package/dist/src/routes/admin-config.js.map +1 -0
  429. package/dist/src/routes/admin-economy.d.ts +5 -0
  430. package/dist/src/routes/admin-economy.d.ts.map +1 -0
  431. package/dist/src/routes/admin-economy.js +57 -0
  432. package/dist/src/routes/admin-economy.js.map +1 -0
  433. package/dist/src/routes/admin-extensions.d.ts +6 -0
  434. package/dist/src/routes/admin-extensions.d.ts.map +1 -0
  435. package/dist/src/routes/admin-extensions.js +619 -0
  436. package/dist/src/routes/admin-extensions.js.map +1 -0
  437. package/dist/src/routes/admin-features.d.ts +16 -0
  438. package/dist/src/routes/admin-features.d.ts.map +1 -0
  439. package/dist/src/routes/admin-features.js +672 -0
  440. package/dist/src/routes/admin-features.js.map +1 -0
  441. package/dist/src/routes/admin-maintenance.d.ts +8 -0
  442. package/dist/src/routes/admin-maintenance.d.ts.map +1 -0
  443. package/dist/src/routes/admin-maintenance.js +86 -0
  444. package/dist/src/routes/admin-maintenance.js.map +1 -0
  445. package/dist/src/routes/admin-memory.d.ts +12 -0
  446. package/dist/src/routes/admin-memory.d.ts.map +1 -0
  447. package/dist/src/routes/admin-memory.js +64 -0
  448. package/dist/src/routes/admin-memory.js.map +1 -0
  449. package/dist/src/routes/admin-monitoring.d.ts +5 -0
  450. package/dist/src/routes/admin-monitoring.d.ts.map +1 -0
  451. package/dist/src/routes/admin-monitoring.js +343 -0
  452. package/dist/src/routes/admin-monitoring.js.map +1 -0
  453. package/dist/src/routes/admin-prompts.d.ts +5 -0
  454. package/dist/src/routes/admin-prompts.d.ts.map +1 -0
  455. package/dist/src/routes/admin-prompts.js +198 -0
  456. package/dist/src/routes/admin-prompts.js.map +1 -0
  457. package/dist/src/routes/admin-scheduler.d.ts +6 -0
  458. package/dist/src/routes/admin-scheduler.d.ts.map +1 -0
  459. package/dist/src/routes/admin-scheduler.js +153 -0
  460. package/dist/src/routes/admin-scheduler.js.map +1 -0
  461. package/dist/src/routes/admin.d.ts +10 -0
  462. package/dist/src/routes/admin.d.ts.map +1 -0
  463. package/dist/src/routes/admin.js +847 -0
  464. package/dist/src/routes/admin.js.map +1 -0
  465. package/dist/src/routes/agents.d.ts +5 -0
  466. package/dist/src/routes/agents.d.ts.map +1 -0
  467. package/dist/src/routes/agents.js +946 -0
  468. package/dist/src/routes/agents.js.map +1 -0
  469. package/dist/src/routes/app-store.d.ts +25 -0
  470. package/dist/src/routes/app-store.d.ts.map +1 -0
  471. package/dist/src/routes/app-store.js +269 -0
  472. package/dist/src/routes/app-store.js.map +1 -0
  473. package/dist/src/routes/appeals.d.ts +5 -0
  474. package/dist/src/routes/appeals.d.ts.map +1 -0
  475. package/dist/src/routes/appeals.js +241 -0
  476. package/dist/src/routes/appeals.js.map +1 -0
  477. package/dist/src/routes/apps.d.ts +14 -0
  478. package/dist/src/routes/apps.d.ts.map +1 -0
  479. package/dist/src/routes/apps.js +395 -0
  480. package/dist/src/routes/apps.js.map +1 -0
  481. package/dist/src/routes/auth.d.ts +13 -0
  482. package/dist/src/routes/auth.d.ts.map +1 -0
  483. package/dist/src/routes/auth.js +517 -0
  484. package/dist/src/routes/auth.js.map +1 -0
  485. package/dist/src/routes/boards.d.ts +5 -0
  486. package/dist/src/routes/boards.d.ts.map +1 -0
  487. package/dist/src/routes/boards.js +614 -0
  488. package/dist/src/routes/boards.js.map +1 -0
  489. package/dist/src/routes/bootstrap.d.ts +6 -0
  490. package/dist/src/routes/bootstrap.d.ts.map +1 -0
  491. package/dist/src/routes/bootstrap.js +360 -0
  492. package/dist/src/routes/bootstrap.js.map +1 -0
  493. package/dist/src/routes/calibrator.d.ts +28 -0
  494. package/dist/src/routes/calibrator.d.ts.map +1 -0
  495. package/dist/src/routes/calibrator.js +556 -0
  496. package/dist/src/routes/calibrator.js.map +1 -0
  497. package/dist/src/routes/catalogue.d.ts +7 -0
  498. package/dist/src/routes/catalogue.d.ts.map +1 -0
  499. package/dist/src/routes/catalogue.js +377 -0
  500. package/dist/src/routes/catalogue.js.map +1 -0
  501. package/dist/src/routes/chat-instances.d.ts +5 -0
  502. package/dist/src/routes/chat-instances.d.ts.map +1 -0
  503. package/dist/src/routes/chat-instances.js +131 -0
  504. package/dist/src/routes/chat-instances.js.map +1 -0
  505. package/dist/src/routes/consent.d.ts +6 -0
  506. package/dist/src/routes/consent.d.ts.map +1 -0
  507. package/dist/src/routes/consent.js +188 -0
  508. package/dist/src/routes/consent.js.map +1 -0
  509. package/dist/src/routes/cortex.d.ts +5 -0
  510. package/dist/src/routes/cortex.d.ts.map +1 -0
  511. package/dist/src/routes/cortex.js +617 -0
  512. package/dist/src/routes/cortex.js.map +1 -0
  513. package/dist/src/routes/csm.d.ts +5 -0
  514. package/dist/src/routes/csm.d.ts.map +1 -0
  515. package/dist/src/routes/csm.js +258 -0
  516. package/dist/src/routes/csm.js.map +1 -0
  517. package/dist/src/routes/disputes.d.ts +5 -0
  518. package/dist/src/routes/disputes.d.ts.map +1 -0
  519. package/dist/src/routes/disputes.js +528 -0
  520. package/dist/src/routes/disputes.js.map +1 -0
  521. package/dist/src/routes/extensions.d.ts +6 -0
  522. package/dist/src/routes/extensions.d.ts.map +1 -0
  523. package/dist/src/routes/extensions.js +1149 -0
  524. package/dist/src/routes/extensions.js.map +1 -0
  525. package/dist/src/routes/federation-genesis.d.ts +11 -0
  526. package/dist/src/routes/federation-genesis.d.ts.map +1 -0
  527. package/dist/src/routes/federation-genesis.js +638 -0
  528. package/dist/src/routes/federation-genesis.js.map +1 -0
  529. package/dist/src/routes/federation-peer.d.ts +10 -0
  530. package/dist/src/routes/federation-peer.d.ts.map +1 -0
  531. package/dist/src/routes/federation-peer.js +613 -0
  532. package/dist/src/routes/federation-peer.js.map +1 -0
  533. package/dist/src/routes/federation-settlements.d.ts +10 -0
  534. package/dist/src/routes/federation-settlements.d.ts.map +1 -0
  535. package/dist/src/routes/federation-settlements.js +231 -0
  536. package/dist/src/routes/federation-settlements.js.map +1 -0
  537. package/dist/src/routes/federation-sync.d.ts +15 -0
  538. package/dist/src/routes/federation-sync.d.ts.map +1 -0
  539. package/dist/src/routes/federation-sync.js +629 -0
  540. package/dist/src/routes/federation-sync.js.map +1 -0
  541. package/dist/src/routes/federation.d.ts +15 -0
  542. package/dist/src/routes/federation.d.ts.map +1 -0
  543. package/dist/src/routes/federation.js +23 -0
  544. package/dist/src/routes/federation.js.map +1 -0
  545. package/dist/src/routes/flags.d.ts +5 -0
  546. package/dist/src/routes/flags.d.ts.map +1 -0
  547. package/dist/src/routes/flags.js +194 -0
  548. package/dist/src/routes/flags.js.map +1 -0
  549. package/dist/src/routes/foundry.d.ts +5 -0
  550. package/dist/src/routes/foundry.d.ts.map +1 -0
  551. package/dist/src/routes/foundry.js +955 -0
  552. package/dist/src/routes/foundry.js.map +1 -0
  553. package/dist/src/routes/generator-autopilot.d.ts +12 -0
  554. package/dist/src/routes/generator-autopilot.d.ts.map +1 -0
  555. package/dist/src/routes/generator-autopilot.js +71 -0
  556. package/dist/src/routes/generator-autopilot.js.map +1 -0
  557. package/dist/src/routes/generator.d.ts +5 -0
  558. package/dist/src/routes/generator.d.ts.map +1 -0
  559. package/dist/src/routes/generator.js +1313 -0
  560. package/dist/src/routes/generator.js.map +1 -0
  561. package/dist/src/routes/ghii.d.ts +16 -0
  562. package/dist/src/routes/ghii.d.ts.map +1 -0
  563. package/dist/src/routes/ghii.js +1115 -0
  564. package/dist/src/routes/ghii.js.map +1 -0
  565. package/dist/src/routes/instances.d.ts +31 -0
  566. package/dist/src/routes/instances.d.ts.map +1 -0
  567. package/dist/src/routes/instances.js +722 -0
  568. package/dist/src/routes/instances.js.map +1 -0
  569. package/dist/src/routes/knowledge.d.ts +33 -0
  570. package/dist/src/routes/knowledge.d.ts.map +1 -0
  571. package/dist/src/routes/knowledge.js +1108 -0
  572. package/dist/src/routes/knowledge.js.map +1 -0
  573. package/dist/src/routes/lib-data.d.ts +7 -0
  574. package/dist/src/routes/lib-data.d.ts.map +1 -0
  575. package/dist/src/routes/lib-data.js +189 -0
  576. package/dist/src/routes/lib-data.js.map +1 -0
  577. package/dist/src/routes/lib-social.d.ts +7 -0
  578. package/dist/src/routes/lib-social.d.ts.map +1 -0
  579. package/dist/src/routes/lib-social.js +159 -0
  580. package/dist/src/routes/lib-social.js.map +1 -0
  581. package/dist/src/routes/lib-storage.d.ts +7 -0
  582. package/dist/src/routes/lib-storage.d.ts.map +1 -0
  583. package/dist/src/routes/lib-storage.js +202 -0
  584. package/dist/src/routes/lib-storage.js.map +1 -0
  585. package/dist/src/routes/lib-tunnel.d.ts +8 -0
  586. package/dist/src/routes/lib-tunnel.d.ts.map +1 -0
  587. package/dist/src/routes/lib-tunnel.js +442 -0
  588. package/dist/src/routes/lib-tunnel.js.map +1 -0
  589. package/dist/src/routes/lib-wallet.d.ts +7 -0
  590. package/dist/src/routes/lib-wallet.d.ts.map +1 -0
  591. package/dist/src/routes/lib-wallet.js +129 -0
  592. package/dist/src/routes/lib-wallet.js.map +1 -0
  593. package/dist/src/routes/lib-work.d.ts +7 -0
  594. package/dist/src/routes/lib-work.d.ts.map +1 -0
  595. package/dist/src/routes/lib-work.js +210 -0
  596. package/dist/src/routes/lib-work.js.map +1 -0
  597. package/dist/src/routes/libs.d.ts +10 -0
  598. package/dist/src/routes/libs.d.ts.map +1 -0
  599. package/dist/src/routes/libs.js +989 -0
  600. package/dist/src/routes/libs.js.map +1 -0
  601. package/dist/src/routes/matches.d.ts +10 -0
  602. package/dist/src/routes/matches.d.ts.map +1 -0
  603. package/dist/src/routes/matches.js +218 -0
  604. package/dist/src/routes/matches.js.map +1 -0
  605. package/dist/src/routes/memory.d.ts +6 -0
  606. package/dist/src/routes/memory.d.ts.map +1 -0
  607. package/dist/src/routes/memory.js +796 -0
  608. package/dist/src/routes/memory.js.map +1 -0
  609. package/dist/src/routes/micro-memory.d.ts +5 -0
  610. package/dist/src/routes/micro-memory.d.ts.map +1 -0
  611. package/dist/src/routes/micro-memory.js +488 -0
  612. package/dist/src/routes/micro-memory.js.map +1 -0
  613. package/dist/src/routes/msm.d.ts +5 -0
  614. package/dist/src/routes/msm.d.ts.map +1 -0
  615. package/dist/src/routes/msm.js +242 -0
  616. package/dist/src/routes/msm.js.map +1 -0
  617. package/dist/src/routes/openrouter.d.ts +23 -0
  618. package/dist/src/routes/openrouter.d.ts.map +1 -0
  619. package/dist/src/routes/openrouter.js +337 -0
  620. package/dist/src/routes/openrouter.js.map +1 -0
  621. package/dist/src/routes/organisms.d.ts +5 -0
  622. package/dist/src/routes/organisms.d.ts.map +1 -0
  623. package/dist/src/routes/organisms.js +415 -0
  624. package/dist/src/routes/organisms.js.map +1 -0
  625. package/dist/src/routes/owners.d.ts +5 -0
  626. package/dist/src/routes/owners.d.ts.map +1 -0
  627. package/dist/src/routes/owners.js +637 -0
  628. package/dist/src/routes/owners.js.map +1 -0
  629. package/dist/src/routes/packages.d.ts +35 -0
  630. package/dist/src/routes/packages.d.ts.map +1 -0
  631. package/dist/src/routes/packages.js +600 -0
  632. package/dist/src/routes/packages.js.map +1 -0
  633. package/dist/src/routes/permissions.d.ts +5 -0
  634. package/dist/src/routes/permissions.d.ts.map +1 -0
  635. package/dist/src/routes/permissions.js +85 -0
  636. package/dist/src/routes/permissions.js.map +1 -0
  637. package/dist/src/routes/personal.d.ts +7 -0
  638. package/dist/src/routes/personal.d.ts.map +1 -0
  639. package/dist/src/routes/personal.js +594 -0
  640. package/dist/src/routes/personal.js.map +1 -0
  641. package/dist/src/routes/portal-api.d.ts +9 -0
  642. package/dist/src/routes/portal-api.d.ts.map +1 -0
  643. package/dist/src/routes/portal-api.js +49 -0
  644. package/dist/src/routes/portal-api.js.map +1 -0
  645. package/dist/src/routes/portal-human.d.ts +12 -0
  646. package/dist/src/routes/portal-human.d.ts.map +1 -0
  647. package/dist/src/routes/portal-human.js +2652 -0
  648. package/dist/src/routes/portal-human.js.map +1 -0
  649. package/dist/src/routes/portal.d.ts +24 -0
  650. package/dist/src/routes/portal.d.ts.map +1 -0
  651. package/dist/src/routes/portal.js +372 -0
  652. package/dist/src/routes/portal.js.map +1 -0
  653. package/dist/src/routes/portfolio.d.ts +5 -0
  654. package/dist/src/routes/portfolio.d.ts.map +1 -0
  655. package/dist/src/routes/portfolio.js +231 -0
  656. package/dist/src/routes/portfolio.js.map +1 -0
  657. package/dist/src/routes/profile.d.ts +5 -0
  658. package/dist/src/routes/profile.d.ts.map +1 -0
  659. package/dist/src/routes/profile.js +2042 -0
  660. package/dist/src/routes/profile.js.map +1 -0
  661. package/dist/src/routes/prompts.d.ts +5 -0
  662. package/dist/src/routes/prompts.d.ts.map +1 -0
  663. package/dist/src/routes/prompts.js +318 -0
  664. package/dist/src/routes/prompts.js.map +1 -0
  665. package/dist/src/routes/push.d.ts +6 -0
  666. package/dist/src/routes/push.d.ts.map +1 -0
  667. package/dist/src/routes/push.js +75 -0
  668. package/dist/src/routes/push.js.map +1 -0
  669. package/dist/src/routes/realtime.d.ts +7 -0
  670. package/dist/src/routes/realtime.d.ts.map +1 -0
  671. package/dist/src/routes/realtime.js +289 -0
  672. package/dist/src/routes/realtime.js.map +1 -0
  673. package/dist/src/routes/schemas.d.ts +5 -0
  674. package/dist/src/routes/schemas.d.ts.map +1 -0
  675. package/dist/src/routes/schemas.js +130 -0
  676. package/dist/src/routes/schemas.js.map +1 -0
  677. package/dist/src/routes/setup.d.ts +7 -0
  678. package/dist/src/routes/setup.d.ts.map +1 -0
  679. package/dist/src/routes/setup.js +243 -0
  680. package/dist/src/routes/setup.js.map +1 -0
  681. package/dist/src/routes/site.d.ts +6 -0
  682. package/dist/src/routes/site.d.ts.map +1 -0
  683. package/dist/src/routes/site.js +201 -0
  684. package/dist/src/routes/site.js.map +1 -0
  685. package/dist/src/routes/spec.d.ts +3 -0
  686. package/dist/src/routes/spec.d.ts.map +1 -0
  687. package/dist/src/routes/spec.js +47 -0
  688. package/dist/src/routes/spec.js.map +1 -0
  689. package/dist/src/routes/sse.d.ts +5 -0
  690. package/dist/src/routes/sse.d.ts.map +1 -0
  691. package/dist/src/routes/sse.js +66 -0
  692. package/dist/src/routes/sse.js.map +1 -0
  693. package/dist/src/routes/stats.d.ts +7 -0
  694. package/dist/src/routes/stats.d.ts.map +1 -0
  695. package/dist/src/routes/stats.js +98 -0
  696. package/dist/src/routes/stats.js.map +1 -0
  697. package/dist/src/routes/storage-files.d.ts +5 -0
  698. package/dist/src/routes/storage-files.d.ts.map +1 -0
  699. package/dist/src/routes/storage-files.js +460 -0
  700. package/dist/src/routes/storage-files.js.map +1 -0
  701. package/dist/src/routes/templates.d.ts +30 -0
  702. package/dist/src/routes/templates.d.ts.map +1 -0
  703. package/dist/src/routes/templates.js +511 -0
  704. package/dist/src/routes/templates.js.map +1 -0
  705. package/dist/src/routes/totp.d.ts +5 -0
  706. package/dist/src/routes/totp.d.ts.map +1 -0
  707. package/dist/src/routes/totp.js +166 -0
  708. package/dist/src/routes/totp.js.map +1 -0
  709. package/dist/src/routes/validate.d.ts +4 -0
  710. package/dist/src/routes/validate.d.ts.map +1 -0
  711. package/dist/src/routes/validate.js +71 -0
  712. package/dist/src/routes/validate.js.map +1 -0
  713. package/dist/src/routes/verification.d.ts +8 -0
  714. package/dist/src/routes/verification.d.ts.map +1 -0
  715. package/dist/src/routes/verification.js +259 -0
  716. package/dist/src/routes/verification.js.map +1 -0
  717. package/dist/src/routes/wallet.d.ts +18 -0
  718. package/dist/src/routes/wallet.d.ts.map +1 -0
  719. package/dist/src/routes/wallet.js +164 -0
  720. package/dist/src/routes/wallet.js.map +1 -0
  721. package/dist/src/routes/wellknown.d.ts +5 -0
  722. package/dist/src/routes/wellknown.d.ts.map +1 -0
  723. package/dist/src/routes/wellknown.js +57 -0
  724. package/dist/src/routes/wellknown.js.map +1 -0
  725. package/dist/src/routes/work.d.ts +21 -0
  726. package/dist/src/routes/work.d.ts.map +1 -0
  727. package/dist/src/routes/work.js +654 -0
  728. package/dist/src/routes/work.js.map +1 -0
  729. package/dist/src/schemas/knowledge-package.d.ts +203 -0
  730. package/dist/src/schemas/knowledge-package.d.ts.map +1 -0
  731. package/dist/src/schemas/knowledge-package.js +233 -0
  732. package/dist/src/schemas/knowledge-package.js.map +1 -0
  733. package/dist/src/server-bootstrap/config-init.d.ts +16 -0
  734. package/dist/src/server-bootstrap/config-init.d.ts.map +1 -0
  735. package/dist/src/server-bootstrap/config-init.js +113 -0
  736. package/dist/src/server-bootstrap/config-init.js.map +1 -0
  737. package/dist/src/server-bootstrap/middleware-guards.d.ts +15 -0
  738. package/dist/src/server-bootstrap/middleware-guards.d.ts.map +1 -0
  739. package/dist/src/server-bootstrap/middleware-guards.js +244 -0
  740. package/dist/src/server-bootstrap/middleware-guards.js.map +1 -0
  741. package/dist/src/server-bootstrap/routes-loader.d.ts +35 -0
  742. package/dist/src/server-bootstrap/routes-loader.d.ts.map +1 -0
  743. package/dist/src/server-bootstrap/routes-loader.js +290 -0
  744. package/dist/src/server-bootstrap/routes-loader.js.map +1 -0
  745. package/dist/src/server-bootstrap/service-init.d.ts +24 -0
  746. package/dist/src/server-bootstrap/service-init.d.ts.map +1 -0
  747. package/dist/src/server-bootstrap/service-init.js +195 -0
  748. package/dist/src/server-bootstrap/service-init.js.map +1 -0
  749. package/dist/src/server-bootstrap/static-files.d.ts +7 -0
  750. package/dist/src/server-bootstrap/static-files.d.ts.map +1 -0
  751. package/dist/src/server-bootstrap/static-files.js +119 -0
  752. package/dist/src/server-bootstrap/static-files.js.map +1 -0
  753. package/dist/src/server.d.ts +22 -0
  754. package/dist/src/server.d.ts.map +1 -0
  755. package/dist/src/server.js +133 -0
  756. package/dist/src/server.js.map +1 -0
  757. package/dist/src/services/cache-cleanup.d.ts +31 -0
  758. package/dist/src/services/cache-cleanup.d.ts.map +1 -0
  759. package/dist/src/services/cache-cleanup.js +123 -0
  760. package/dist/src/services/cache-cleanup.js.map +1 -0
  761. package/dist/src/services/catalogue-sync.d.ts +45 -0
  762. package/dist/src/services/catalogue-sync.d.ts.map +1 -0
  763. package/dist/src/services/catalogue-sync.js +196 -0
  764. package/dist/src/services/catalogue-sync.js.map +1 -0
  765. package/dist/src/services/component-registrar.d.ts +46 -0
  766. package/dist/src/services/component-registrar.d.ts.map +1 -0
  767. package/dist/src/services/component-registrar.js +389 -0
  768. package/dist/src/services/component-registrar.js.map +1 -0
  769. package/dist/src/services/config-loader.d.ts +42 -0
  770. package/dist/src/services/config-loader.d.ts.map +1 -0
  771. package/dist/src/services/config-loader.js +187 -0
  772. package/dist/src/services/config-loader.js.map +1 -0
  773. package/dist/src/services/config-provenance.d.ts +32 -0
  774. package/dist/src/services/config-provenance.d.ts.map +1 -0
  775. package/dist/src/services/config-provenance.js +59 -0
  776. package/dist/src/services/config-provenance.js.map +1 -0
  777. package/dist/src/services/config-schema.d.ts +52 -0
  778. package/dist/src/services/config-schema.d.ts.map +1 -0
  779. package/dist/src/services/config-schema.js +288 -0
  780. package/dist/src/services/config-schema.js.map +1 -0
  781. package/dist/src/services/consent.d.ts +43 -0
  782. package/dist/src/services/consent.d.ts.map +1 -0
  783. package/dist/src/services/consent.js +137 -0
  784. package/dist/src/services/consent.js.map +1 -0
  785. package/dist/src/services/consul-config.d.ts +30 -0
  786. package/dist/src/services/consul-config.d.ts.map +1 -0
  787. package/dist/src/services/consul-config.js +110 -0
  788. package/dist/src/services/consul-config.js.map +1 -0
  789. package/dist/src/services/core-jobs.d.ts +8 -0
  790. package/dist/src/services/core-jobs.d.ts.map +1 -0
  791. package/dist/src/services/core-jobs.js +161 -0
  792. package/dist/src/services/core-jobs.js.map +1 -0
  793. package/dist/src/services/cortex-manifest.d.ts +17 -0
  794. package/dist/src/services/cortex-manifest.d.ts.map +1 -0
  795. package/dist/src/services/cortex-manifest.js +343 -0
  796. package/dist/src/services/cortex-manifest.js.map +1 -0
  797. package/dist/src/services/cortex-seeder.d.ts +18 -0
  798. package/dist/src/services/cortex-seeder.d.ts.map +1 -0
  799. package/dist/src/services/cortex-seeder.js +86 -0
  800. package/dist/src/services/cortex-seeder.js.map +1 -0
  801. package/dist/src/services/cross-node-matching.d.ts +23 -0
  802. package/dist/src/services/cross-node-matching.d.ts.map +1 -0
  803. package/dist/src/services/cross-node-matching.js +62 -0
  804. package/dist/src/services/cross-node-matching.js.map +1 -0
  805. package/dist/src/services/csm-parser.d.ts +57 -0
  806. package/dist/src/services/csm-parser.d.ts.map +1 -0
  807. package/dist/src/services/csm-parser.js +161 -0
  808. package/dist/src/services/csm-parser.js.map +1 -0
  809. package/dist/src/services/csm-seed.d.ts +15 -0
  810. package/dist/src/services/csm-seed.d.ts.map +1 -0
  811. package/dist/src/services/csm-seed.js +89 -0
  812. package/dist/src/services/csm-seed.js.map +1 -0
  813. package/dist/src/services/directory.d.ts +86 -0
  814. package/dist/src/services/directory.d.ts.map +1 -0
  815. package/dist/src/services/directory.js +307 -0
  816. package/dist/src/services/directory.js.map +1 -0
  817. package/dist/src/services/email-templates.d.ts +29 -0
  818. package/dist/src/services/email-templates.d.ts.map +1 -0
  819. package/dist/src/services/email-templates.js +204 -0
  820. package/dist/src/services/email-templates.js.map +1 -0
  821. package/dist/src/services/email.d.ts +18 -0
  822. package/dist/src/services/email.d.ts.map +1 -0
  823. package/dist/src/services/email.js +102 -0
  824. package/dist/src/services/email.js.map +1 -0
  825. package/dist/src/services/encryption.d.ts +31 -0
  826. package/dist/src/services/encryption.d.ts.map +1 -0
  827. package/dist/src/services/encryption.js +51 -0
  828. package/dist/src/services/encryption.js.map +1 -0
  829. package/dist/src/services/eudiw.d.ts +15 -0
  830. package/dist/src/services/eudiw.d.ts.map +1 -0
  831. package/dist/src/services/eudiw.js +89 -0
  832. package/dist/src/services/eudiw.js.map +1 -0
  833. package/dist/src/services/event-bus.d.ts +8 -0
  834. package/dist/src/services/event-bus.d.ts.map +1 -0
  835. package/dist/src/services/event-bus.js +13 -0
  836. package/dist/src/services/event-bus.js.map +1 -0
  837. package/dist/src/services/extension-runtime.d.ts +72 -0
  838. package/dist/src/services/extension-runtime.d.ts.map +1 -0
  839. package/dist/src/services/extension-runtime.js +282 -0
  840. package/dist/src/services/extension-runtime.js.map +1 -0
  841. package/dist/src/services/federation-helpers.d.ts +37 -0
  842. package/dist/src/services/federation-helpers.d.ts.map +1 -0
  843. package/dist/src/services/federation-helpers.js +100 -0
  844. package/dist/src/services/federation-helpers.js.map +1 -0
  845. package/dist/src/services/federation.d.ts +32 -0
  846. package/dist/src/services/federation.d.ts.map +1 -0
  847. package/dist/src/services/federation.js +201 -0
  848. package/dist/src/services/federation.js.map +1 -0
  849. package/dist/src/services/foundry-debug.d.ts +77 -0
  850. package/dist/src/services/foundry-debug.d.ts.map +1 -0
  851. package/dist/src/services/foundry-debug.js +214 -0
  852. package/dist/src/services/foundry-debug.js.map +1 -0
  853. package/dist/src/services/foundry-registration.d.ts +42 -0
  854. package/dist/src/services/foundry-registration.d.ts.map +1 -0
  855. package/dist/src/services/foundry-registration.js +330 -0
  856. package/dist/src/services/foundry-registration.js.map +1 -0
  857. package/dist/src/services/foundry-testing.d.ts +90 -0
  858. package/dist/src/services/foundry-testing.d.ts.map +1 -0
  859. package/dist/src/services/foundry-testing.js +253 -0
  860. package/dist/src/services/foundry-testing.js.map +1 -0
  861. package/dist/src/services/foundry-validate.d.ts +115 -0
  862. package/dist/src/services/foundry-validate.d.ts.map +1 -0
  863. package/dist/src/services/foundry-validate.js +781 -0
  864. package/dist/src/services/foundry-validate.js.map +1 -0
  865. package/dist/src/services/generator-autopilot.d.ts +37 -0
  866. package/dist/src/services/generator-autopilot.d.ts.map +1 -0
  867. package/dist/src/services/generator-autopilot.js +1076 -0
  868. package/dist/src/services/generator-autopilot.js.map +1 -0
  869. package/dist/src/services/generator-debug.d.ts +79 -0
  870. package/dist/src/services/generator-debug.d.ts.map +1 -0
  871. package/dist/src/services/generator-debug.js +218 -0
  872. package/dist/src/services/generator-debug.js.map +1 -0
  873. package/dist/src/services/generator-prompt-seeds.d.ts +13 -0
  874. package/dist/src/services/generator-prompt-seeds.d.ts.map +1 -0
  875. package/dist/src/services/generator-prompt-seeds.js +2694 -0
  876. package/dist/src/services/generator-prompt-seeds.js.map +1 -0
  877. package/dist/src/services/generator-prompts/bundle.d.ts +17 -0
  878. package/dist/src/services/generator-prompts/bundle.d.ts.map +1 -0
  879. package/dist/src/services/generator-prompts/bundle.js +95 -0
  880. package/dist/src/services/generator-prompts/bundle.js.map +1 -0
  881. package/dist/src/services/generator-prompts/index.d.ts +48 -0
  882. package/dist/src/services/generator-prompts/index.d.ts.map +1 -0
  883. package/dist/src/services/generator-prompts/index.js +97 -0
  884. package/dist/src/services/generator-prompts/index.js.map +1 -0
  885. package/dist/src/services/generator-prompts/resolvers.d.ts +21 -0
  886. package/dist/src/services/generator-prompts/resolvers.d.ts.map +1 -0
  887. package/dist/src/services/generator-prompts/resolvers.js +1553 -0
  888. package/dist/src/services/generator-prompts/resolvers.js.map +1 -0
  889. package/dist/src/services/generator-prompts/spec-validate.d.ts +29 -0
  890. package/dist/src/services/generator-prompts/spec-validate.d.ts.map +1 -0
  891. package/dist/src/services/generator-prompts/spec-validate.js +190 -0
  892. package/dist/src/services/generator-prompts/spec-validate.js.map +1 -0
  893. package/dist/src/services/generator-prompts/strip.d.ts +13 -0
  894. package/dist/src/services/generator-prompts/strip.d.ts.map +1 -0
  895. package/dist/src/services/generator-prompts/strip.js +60 -0
  896. package/dist/src/services/generator-prompts/strip.js.map +1 -0
  897. package/dist/src/services/generator-prompts/types.d.ts +229 -0
  898. package/dist/src/services/generator-prompts/types.d.ts.map +1 -0
  899. package/dist/src/services/generator-prompts/types.js +8 -0
  900. package/dist/src/services/generator-prompts/types.js.map +1 -0
  901. package/dist/src/services/generator-prompts/validate.d.ts +48 -0
  902. package/dist/src/services/generator-prompts/validate.d.ts.map +1 -0
  903. package/dist/src/services/generator-prompts/validate.js +927 -0
  904. package/dist/src/services/generator-prompts/validate.js.map +1 -0
  905. package/dist/src/services/generator-registration.d.ts +43 -0
  906. package/dist/src/services/generator-registration.d.ts.map +1 -0
  907. package/dist/src/services/generator-registration.js +343 -0
  908. package/dist/src/services/generator-registration.js.map +1 -0
  909. package/dist/src/services/generator-testing.d.ts +93 -0
  910. package/dist/src/services/generator-testing.d.ts.map +1 -0
  911. package/dist/src/services/generator-testing.js +300 -0
  912. package/dist/src/services/generator-testing.js.map +1 -0
  913. package/dist/src/services/generator-validate.d.ts +117 -0
  914. package/dist/src/services/generator-validate.d.ts.map +1 -0
  915. package/dist/src/services/generator-validate.js +790 -0
  916. package/dist/src/services/generator-validate.js.map +1 -0
  917. package/dist/src/services/genesis-peering.d.ts +12 -0
  918. package/dist/src/services/genesis-peering.d.ts.map +1 -0
  919. package/dist/src/services/genesis-peering.js +91 -0
  920. package/dist/src/services/genesis-peering.js.map +1 -0
  921. package/dist/src/services/genesis-sync.d.ts +29 -0
  922. package/dist/src/services/genesis-sync.d.ts.map +1 -0
  923. package/dist/src/services/genesis-sync.js +370 -0
  924. package/dist/src/services/genesis-sync.js.map +1 -0
  925. package/dist/src/services/hooks.d.ts +21 -0
  926. package/dist/src/services/hooks.d.ts.map +1 -0
  927. package/dist/src/services/hooks.js +85 -0
  928. package/dist/src/services/hooks.js.map +1 -0
  929. package/dist/src/services/job-seeding.d.ts +7 -0
  930. package/dist/src/services/job-seeding.d.ts.map +1 -0
  931. package/dist/src/services/job-seeding.js +39 -0
  932. package/dist/src/services/job-seeding.js.map +1 -0
  933. package/dist/src/services/knowledge.d.ts +13 -0
  934. package/dist/src/services/knowledge.d.ts.map +1 -0
  935. package/dist/src/services/knowledge.js +15 -0
  936. package/dist/src/services/knowledge.js.map +1 -0
  937. package/dist/src/services/mailbox-notification.d.ts +37 -0
  938. package/dist/src/services/mailbox-notification.d.ts.map +1 -0
  939. package/dist/src/services/mailbox-notification.js +249 -0
  940. package/dist/src/services/mailbox-notification.js.map +1 -0
  941. package/dist/src/services/mailbox.d.ts +16 -0
  942. package/dist/src/services/mailbox.d.ts.map +1 -0
  943. package/dist/src/services/mailbox.js +77 -0
  944. package/dist/src/services/mailbox.js.map +1 -0
  945. package/dist/src/services/match-notification.d.ts +12 -0
  946. package/dist/src/services/match-notification.d.ts.map +1 -0
  947. package/dist/src/services/match-notification.js +121 -0
  948. package/dist/src/services/match-notification.js.map +1 -0
  949. package/dist/src/services/matching.d.ts +54 -0
  950. package/dist/src/services/matching.d.ts.map +1 -0
  951. package/dist/src/services/matching.js +293 -0
  952. package/dist/src/services/matching.js.map +1 -0
  953. package/dist/src/services/memory-replication.d.ts +43 -0
  954. package/dist/src/services/memory-replication.d.ts.map +1 -0
  955. package/dist/src/services/memory-replication.js +213 -0
  956. package/dist/src/services/memory-replication.js.map +1 -0
  957. package/dist/src/services/morsel.d.ts +49 -0
  958. package/dist/src/services/morsel.d.ts.map +1 -0
  959. package/dist/src/services/morsel.js +174 -0
  960. package/dist/src/services/morsel.js.map +1 -0
  961. package/dist/src/services/msm-parser.d.ts +55 -0
  962. package/dist/src/services/msm-parser.d.ts.map +1 -0
  963. package/dist/src/services/msm-parser.js +186 -0
  964. package/dist/src/services/msm-parser.js.map +1 -0
  965. package/dist/src/services/mydata-receipt.d.ts +29 -0
  966. package/dist/src/services/mydata-receipt.d.ts.map +1 -0
  967. package/dist/src/services/mydata-receipt.js +31 -0
  968. package/dist/src/services/mydata-receipt.js.map +1 -0
  969. package/dist/src/services/notification-templates.d.ts +40 -0
  970. package/dist/src/services/notification-templates.d.ts.map +1 -0
  971. package/dist/src/services/notification-templates.js +109 -0
  972. package/dist/src/services/notification-templates.js.map +1 -0
  973. package/dist/src/services/openrouter.d.ts +30 -0
  974. package/dist/src/services/openrouter.d.ts.map +1 -0
  975. package/dist/src/services/openrouter.js +95 -0
  976. package/dist/src/services/openrouter.js.map +1 -0
  977. package/dist/src/services/organism-reputation.d.ts +7 -0
  978. package/dist/src/services/organism-reputation.d.ts.map +1 -0
  979. package/dist/src/services/organism-reputation.js +107 -0
  980. package/dist/src/services/organism-reputation.js.map +1 -0
  981. package/dist/src/services/package-hash.d.ts +19 -0
  982. package/dist/src/services/package-hash.d.ts.map +1 -0
  983. package/dist/src/services/package-hash.js +22 -0
  984. package/dist/src/services/package-hash.js.map +1 -0
  985. package/dist/src/services/package-zip.d.ts +60 -0
  986. package/dist/src/services/package-zip.d.ts.map +1 -0
  987. package/dist/src/services/package-zip.js +267 -0
  988. package/dist/src/services/package-zip.js.map +1 -0
  989. package/dist/src/services/password.d.ts +9 -0
  990. package/dist/src/services/password.d.ts.map +1 -0
  991. package/dist/src/services/password.js +32 -0
  992. package/dist/src/services/password.js.map +1 -0
  993. package/dist/src/services/personal-routing.d.ts +21 -0
  994. package/dist/src/services/personal-routing.d.ts.map +1 -0
  995. package/dist/src/services/personal-routing.js +77 -0
  996. package/dist/src/services/personal-routing.js.map +1 -0
  997. package/dist/src/services/personal-tunnel.d.ts +39 -0
  998. package/dist/src/services/personal-tunnel.d.ts.map +1 -0
  999. package/dist/src/services/personal-tunnel.js +371 -0
  1000. package/dist/src/services/personal-tunnel.js.map +1 -0
  1001. package/dist/src/services/profile-schemas.d.ts +12 -0
  1002. package/dist/src/services/profile-schemas.d.ts.map +1 -0
  1003. package/dist/src/services/profile-schemas.js +100 -0
  1004. package/dist/src/services/profile-schemas.js.map +1 -0
  1005. package/dist/src/services/prometheus.d.ts +32 -0
  1006. package/dist/src/services/prometheus.d.ts.map +1 -0
  1007. package/dist/src/services/prometheus.js +162 -0
  1008. package/dist/src/services/prometheus.js.map +1 -0
  1009. package/dist/src/services/prompt-defaults.d.ts +33 -0
  1010. package/dist/src/services/prompt-defaults.d.ts.map +1 -0
  1011. package/dist/src/services/prompt-defaults.js +1675 -0
  1012. package/dist/src/services/prompt-defaults.js.map +1 -0
  1013. package/dist/src/services/prompt-seeder.d.ts +8 -0
  1014. package/dist/src/services/prompt-seeder.d.ts.map +1 -0
  1015. package/dist/src/services/prompt-seeder.js +65 -0
  1016. package/dist/src/services/prompt-seeder.js.map +1 -0
  1017. package/dist/src/services/prompt-variables.d.ts +15 -0
  1018. package/dist/src/services/prompt-variables.d.ts.map +1 -0
  1019. package/dist/src/services/prompt-variables.js +34 -0
  1020. package/dist/src/services/prompt-variables.js.map +1 -0
  1021. package/dist/src/services/push.d.ts +26 -0
  1022. package/dist/src/services/push.d.ts.map +1 -0
  1023. package/dist/src/services/push.js +70 -0
  1024. package/dist/src/services/push.js.map +1 -0
  1025. package/dist/src/services/quota.d.ts +45 -0
  1026. package/dist/src/services/quota.d.ts.map +1 -0
  1027. package/dist/src/services/quota.js +129 -0
  1028. package/dist/src/services/quota.js.map +1 -0
  1029. package/dist/src/services/realtime-manager.d.ts +144 -0
  1030. package/dist/src/services/realtime-manager.d.ts.map +1 -0
  1031. package/dist/src/services/realtime-manager.js +640 -0
  1032. package/dist/src/services/realtime-manager.js.map +1 -0
  1033. package/dist/src/services/scheduler.d.ts +55 -0
  1034. package/dist/src/services/scheduler.d.ts.map +1 -0
  1035. package/dist/src/services/scheduler.js +420 -0
  1036. package/dist/src/services/scheduler.js.map +1 -0
  1037. package/dist/src/services/schema-validator.d.ts +20 -0
  1038. package/dist/src/services/schema-validator.d.ts.map +1 -0
  1039. package/dist/src/services/schema-validator.js +68 -0
  1040. package/dist/src/services/schema-validator.js.map +1 -0
  1041. package/dist/src/services/site-sync.d.ts +15 -0
  1042. package/dist/src/services/site-sync.d.ts.map +1 -0
  1043. package/dist/src/services/site-sync.js +99 -0
  1044. package/dist/src/services/site-sync.js.map +1 -0
  1045. package/dist/src/services/site.d.ts +65 -0
  1046. package/dist/src/services/site.d.ts.map +1 -0
  1047. package/dist/src/services/site.js +378 -0
  1048. package/dist/src/services/site.js.map +1 -0
  1049. package/dist/src/services/stats.d.ts +75 -0
  1050. package/dist/src/services/stats.d.ts.map +1 -0
  1051. package/dist/src/services/stats.js +124 -0
  1052. package/dist/src/services/stats.js.map +1 -0
  1053. package/dist/src/services/sync-health.d.ts +53 -0
  1054. package/dist/src/services/sync-health.d.ts.map +1 -0
  1055. package/dist/src/services/sync-health.js +122 -0
  1056. package/dist/src/services/sync-health.js.map +1 -0
  1057. package/dist/src/services/sync-scheduler.d.ts +25 -0
  1058. package/dist/src/services/sync-scheduler.d.ts.map +1 -0
  1059. package/dist/src/services/sync-scheduler.js +211 -0
  1060. package/dist/src/services/sync-scheduler.js.map +1 -0
  1061. package/dist/src/services/totp.d.ts +31 -0
  1062. package/dist/src/services/totp.d.ts.map +1 -0
  1063. package/dist/src/services/totp.js +96 -0
  1064. package/dist/src/services/totp.js.map +1 -0
  1065. package/dist/src/services/trust-broadcast.d.ts +37 -0
  1066. package/dist/src/services/trust-broadcast.d.ts.map +1 -0
  1067. package/dist/src/services/trust-broadcast.js +107 -0
  1068. package/dist/src/services/trust-broadcast.js.map +1 -0
  1069. package/dist/src/services/trust.d.ts +16 -0
  1070. package/dist/src/services/trust.d.ts.map +1 -0
  1071. package/dist/src/services/trust.js +109 -0
  1072. package/dist/src/services/trust.js.map +1 -0
  1073. package/dist/src/services/vc-issuer.d.ts +14 -0
  1074. package/dist/src/services/vc-issuer.d.ts.map +1 -0
  1075. package/dist/src/services/vc-issuer.js +24 -0
  1076. package/dist/src/services/vc-issuer.js.map +1 -0
  1077. package/dist/src/storage/interface.d.ts +1161 -0
  1078. package/dist/src/storage/interface.d.ts.map +1 -0
  1079. package/dist/src/storage/interface.js +2 -0
  1080. package/dist/src/storage/interface.js.map +1 -0
  1081. package/dist/src/storage/pattern-utils.d.ts +20 -0
  1082. package/dist/src/storage/pattern-utils.d.ts.map +1 -0
  1083. package/dist/src/storage/pattern-utils.js +57 -0
  1084. package/dist/src/storage/pattern-utils.js.map +1 -0
  1085. package/dist/src/storage/providers/mongodb/index.d.ts +608 -0
  1086. package/dist/src/storage/providers/mongodb/index.d.ts.map +1 -0
  1087. package/dist/src/storage/providers/mongodb/index.js +4931 -0
  1088. package/dist/src/storage/providers/mongodb/index.js.map +1 -0
  1089. package/dist/src/storage/providers/sqlite/index.d.ts +602 -0
  1090. package/dist/src/storage/providers/sqlite/index.d.ts.map +1 -0
  1091. package/dist/src/storage/providers/sqlite/index.js +4156 -0
  1092. package/dist/src/storage/providers/sqlite/index.js.map +1 -0
  1093. package/dist/src/storage/providers/sqlite/repos/action.d.ts +13 -0
  1094. package/dist/src/storage/providers/sqlite/repos/action.d.ts.map +1 -0
  1095. package/dist/src/storage/providers/sqlite/repos/action.js +79 -0
  1096. package/dist/src/storage/providers/sqlite/repos/action.js.map +1 -0
  1097. package/dist/src/storage/providers/sqlite/repos/agent.d.ts +13 -0
  1098. package/dist/src/storage/providers/sqlite/repos/agent.d.ts.map +1 -0
  1099. package/dist/src/storage/providers/sqlite/repos/agent.js +103 -0
  1100. package/dist/src/storage/providers/sqlite/repos/agent.js.map +1 -0
  1101. package/dist/src/storage/providers/sqlite/repos/auth.d.ts +56 -0
  1102. package/dist/src/storage/providers/sqlite/repos/auth.d.ts.map +1 -0
  1103. package/dist/src/storage/providers/sqlite/repos/auth.js +282 -0
  1104. package/dist/src/storage/providers/sqlite/repos/auth.js.map +1 -0
  1105. package/dist/src/storage/providers/sqlite/repos/board.d.ts +24 -0
  1106. package/dist/src/storage/providers/sqlite/repos/board.d.ts.map +1 -0
  1107. package/dist/src/storage/providers/sqlite/repos/board.js +154 -0
  1108. package/dist/src/storage/providers/sqlite/repos/board.js.map +1 -0
  1109. package/dist/src/storage/providers/sqlite/repos/community.d.ts +33 -0
  1110. package/dist/src/storage/providers/sqlite/repos/community.d.ts.map +1 -0
  1111. package/dist/src/storage/providers/sqlite/repos/community.js +202 -0
  1112. package/dist/src/storage/providers/sqlite/repos/community.js.map +1 -0
  1113. package/dist/src/storage/providers/sqlite/repos/consent.d.ts +23 -0
  1114. package/dist/src/storage/providers/sqlite/repos/consent.d.ts.map +1 -0
  1115. package/dist/src/storage/providers/sqlite/repos/consent.js +187 -0
  1116. package/dist/src/storage/providers/sqlite/repos/consent.js.map +1 -0
  1117. package/dist/src/storage/providers/sqlite/repos/dispute.d.ts +20 -0
  1118. package/dist/src/storage/providers/sqlite/repos/dispute.d.ts.map +1 -0
  1119. package/dist/src/storage/providers/sqlite/repos/dispute.js +118 -0
  1120. package/dist/src/storage/providers/sqlite/repos/dispute.js.map +1 -0
  1121. package/dist/src/storage/providers/sqlite/repos/flag.d.ts +26 -0
  1122. package/dist/src/storage/providers/sqlite/repos/flag.d.ts.map +1 -0
  1123. package/dist/src/storage/providers/sqlite/repos/flag.js +147 -0
  1124. package/dist/src/storage/providers/sqlite/repos/flag.js.map +1 -0
  1125. package/dist/src/storage/providers/sqlite/repos/identity.d.ts +36 -0
  1126. package/dist/src/storage/providers/sqlite/repos/identity.d.ts.map +1 -0
  1127. package/dist/src/storage/providers/sqlite/repos/identity.js +297 -0
  1128. package/dist/src/storage/providers/sqlite/repos/identity.js.map +1 -0
  1129. package/dist/src/storage/providers/sqlite/repos/mailbox.d.ts +18 -0
  1130. package/dist/src/storage/providers/sqlite/repos/mailbox.d.ts.map +1 -0
  1131. package/dist/src/storage/providers/sqlite/repos/mailbox.js +91 -0
  1132. package/dist/src/storage/providers/sqlite/repos/mailbox.js.map +1 -0
  1133. package/dist/src/storage/providers/sqlite/repos/memory.d.ts +28 -0
  1134. package/dist/src/storage/providers/sqlite/repos/memory.d.ts.map +1 -0
  1135. package/dist/src/storage/providers/sqlite/repos/memory.js +152 -0
  1136. package/dist/src/storage/providers/sqlite/repos/memory.js.map +1 -0
  1137. package/dist/src/storage/providers/sqlite/repos/owner.d.ts +14 -0
  1138. package/dist/src/storage/providers/sqlite/repos/owner.d.ts.map +1 -0
  1139. package/dist/src/storage/providers/sqlite/repos/owner.js +124 -0
  1140. package/dist/src/storage/providers/sqlite/repos/owner.js.map +1 -0
  1141. package/dist/src/storage/providers/sqlite/repos/service-manifest.d.ts +17 -0
  1142. package/dist/src/storage/providers/sqlite/repos/service-manifest.d.ts.map +1 -0
  1143. package/dist/src/storage/providers/sqlite/repos/service-manifest.js +114 -0
  1144. package/dist/src/storage/providers/sqlite/repos/service-manifest.js.map +1 -0
  1145. package/dist/src/storage/providers/sqlite/repos/storage-file.d.ts +19 -0
  1146. package/dist/src/storage/providers/sqlite/repos/storage-file.d.ts.map +1 -0
  1147. package/dist/src/storage/providers/sqlite/repos/storage-file.js +128 -0
  1148. package/dist/src/storage/providers/sqlite/repos/storage-file.js.map +1 -0
  1149. package/dist/src/storage/providers/sqlite/repos/work.d.ts +13 -0
  1150. package/dist/src/storage/providers/sqlite/repos/work.d.ts.map +1 -0
  1151. package/dist/src/storage/providers/sqlite/repos/work.js +86 -0
  1152. package/dist/src/storage/providers/sqlite/repos/work.js.map +1 -0
  1153. package/dist/src/storage/providers/sqlite/schema.d.ts +7 -0
  1154. package/dist/src/storage/providers/sqlite/schema.d.ts.map +1 -0
  1155. package/dist/src/storage/providers/sqlite/schema.js +1090 -0
  1156. package/dist/src/storage/providers/sqlite/schema.js.map +1 -0
  1157. package/dist/src/storage/repositories/action.repository.d.ts +14 -0
  1158. package/dist/src/storage/repositories/action.repository.d.ts.map +1 -0
  1159. package/dist/src/storage/repositories/action.repository.js +2 -0
  1160. package/dist/src/storage/repositories/action.repository.js.map +1 -0
  1161. package/dist/src/storage/repositories/agent.repository.d.ts +18 -0
  1162. package/dist/src/storage/repositories/agent.repository.d.ts.map +1 -0
  1163. package/dist/src/storage/repositories/agent.repository.js +2 -0
  1164. package/dist/src/storage/repositories/agent.repository.js.map +1 -0
  1165. package/dist/src/storage/repositories/app-marketplace.repository.d.ts +9 -0
  1166. package/dist/src/storage/repositories/app-marketplace.repository.d.ts.map +1 -0
  1167. package/dist/src/storage/repositories/app-marketplace.repository.js +2 -0
  1168. package/dist/src/storage/repositories/app-marketplace.repository.js.map +1 -0
  1169. package/dist/src/storage/repositories/app.repository.d.ts +17 -0
  1170. package/dist/src/storage/repositories/app.repository.d.ts.map +1 -0
  1171. package/dist/src/storage/repositories/app.repository.js +2 -0
  1172. package/dist/src/storage/repositories/app.repository.js.map +1 -0
  1173. package/dist/src/storage/repositories/auth.repository.d.ts +6 -0
  1174. package/dist/src/storage/repositories/auth.repository.d.ts.map +1 -0
  1175. package/dist/src/storage/repositories/auth.repository.js +2 -0
  1176. package/dist/src/storage/repositories/auth.repository.js.map +1 -0
  1177. package/dist/src/storage/repositories/board.repository.d.ts +27 -0
  1178. package/dist/src/storage/repositories/board.repository.d.ts.map +1 -0
  1179. package/dist/src/storage/repositories/board.repository.js +2 -0
  1180. package/dist/src/storage/repositories/board.repository.js.map +1 -0
  1181. package/dist/src/storage/repositories/catalogue.repository.d.ts +18 -0
  1182. package/dist/src/storage/repositories/catalogue.repository.d.ts.map +1 -0
  1183. package/dist/src/storage/repositories/catalogue.repository.js +2 -0
  1184. package/dist/src/storage/repositories/catalogue.repository.js.map +1 -0
  1185. package/dist/src/storage/repositories/config.repository.d.ts +17 -0
  1186. package/dist/src/storage/repositories/config.repository.d.ts.map +1 -0
  1187. package/dist/src/storage/repositories/config.repository.js +2 -0
  1188. package/dist/src/storage/repositories/config.repository.js.map +1 -0
  1189. package/dist/src/storage/repositories/consent.repository.d.ts +19 -0
  1190. package/dist/src/storage/repositories/consent.repository.d.ts.map +1 -0
  1191. package/dist/src/storage/repositories/consent.repository.js +2 -0
  1192. package/dist/src/storage/repositories/consent.repository.js.map +1 -0
  1193. package/dist/src/storage/repositories/device-auth.repository.d.ts +11 -0
  1194. package/dist/src/storage/repositories/device-auth.repository.d.ts.map +1 -0
  1195. package/dist/src/storage/repositories/device-auth.repository.js +2 -0
  1196. package/dist/src/storage/repositories/device-auth.repository.js.map +1 -0
  1197. package/dist/src/storage/repositories/dispute.repository.d.ts +12 -0
  1198. package/dist/src/storage/repositories/dispute.repository.d.ts.map +1 -0
  1199. package/dist/src/storage/repositories/dispute.repository.js +2 -0
  1200. package/dist/src/storage/repositories/dispute.repository.js.map +1 -0
  1201. package/dist/src/storage/repositories/extension-instance.repository.d.ts +9 -0
  1202. package/dist/src/storage/repositories/extension-instance.repository.d.ts.map +1 -0
  1203. package/dist/src/storage/repositories/extension-instance.repository.js +2 -0
  1204. package/dist/src/storage/repositories/extension-instance.repository.js.map +1 -0
  1205. package/dist/src/storage/repositories/federation.repository.d.ts +37 -0
  1206. package/dist/src/storage/repositories/federation.repository.d.ts.map +1 -0
  1207. package/dist/src/storage/repositories/federation.repository.js +2 -0
  1208. package/dist/src/storage/repositories/federation.repository.js.map +1 -0
  1209. package/dist/src/storage/repositories/file.repository.d.ts +14 -0
  1210. package/dist/src/storage/repositories/file.repository.d.ts.map +1 -0
  1211. package/dist/src/storage/repositories/file.repository.js +2 -0
  1212. package/dist/src/storage/repositories/file.repository.js.map +1 -0
  1213. package/dist/src/storage/repositories/identity.repository.d.ts +29 -0
  1214. package/dist/src/storage/repositories/identity.repository.d.ts.map +1 -0
  1215. package/dist/src/storage/repositories/identity.repository.js +2 -0
  1216. package/dist/src/storage/repositories/identity.repository.js.map +1 -0
  1217. package/dist/src/storage/repositories/index.d.ts +34 -0
  1218. package/dist/src/storage/repositories/index.d.ts.map +1 -0
  1219. package/dist/src/storage/repositories/index.js +2 -0
  1220. package/dist/src/storage/repositories/index.js.map +1 -0
  1221. package/dist/src/storage/repositories/knowledge.repository.d.ts +18 -0
  1222. package/dist/src/storage/repositories/knowledge.repository.d.ts.map +1 -0
  1223. package/dist/src/storage/repositories/knowledge.repository.js +2 -0
  1224. package/dist/src/storage/repositories/knowledge.repository.js.map +1 -0
  1225. package/dist/src/storage/repositories/marketplace.repository.d.ts +23 -0
  1226. package/dist/src/storage/repositories/marketplace.repository.d.ts.map +1 -0
  1227. package/dist/src/storage/repositories/marketplace.repository.js +2 -0
  1228. package/dist/src/storage/repositories/marketplace.repository.js.map +1 -0
  1229. package/dist/src/storage/repositories/memory.repository.d.ts +32 -0
  1230. package/dist/src/storage/repositories/memory.repository.d.ts.map +1 -0
  1231. package/dist/src/storage/repositories/memory.repository.js +2 -0
  1232. package/dist/src/storage/repositories/memory.repository.js.map +1 -0
  1233. package/dist/src/storage/repositories/micro-memory.repository.d.ts +10 -0
  1234. package/dist/src/storage/repositories/micro-memory.repository.d.ts.map +1 -0
  1235. package/dist/src/storage/repositories/micro-memory.repository.js +2 -0
  1236. package/dist/src/storage/repositories/micro-memory.repository.js.map +1 -0
  1237. package/dist/src/storage/repositories/moderation.repository.d.ts +36 -0
  1238. package/dist/src/storage/repositories/moderation.repository.d.ts.map +1 -0
  1239. package/dist/src/storage/repositories/moderation.repository.js +2 -0
  1240. package/dist/src/storage/repositories/moderation.repository.js.map +1 -0
  1241. package/dist/src/storage/repositories/node.repository.d.ts +59 -0
  1242. package/dist/src/storage/repositories/node.repository.d.ts.map +1 -0
  1243. package/dist/src/storage/repositories/node.repository.js +2 -0
  1244. package/dist/src/storage/repositories/node.repository.js.map +1 -0
  1245. package/dist/src/storage/repositories/notification-template.repository.d.ts +8 -0
  1246. package/dist/src/storage/repositories/notification-template.repository.d.ts.map +1 -0
  1247. package/dist/src/storage/repositories/notification-template.repository.js +2 -0
  1248. package/dist/src/storage/repositories/notification-template.repository.js.map +1 -0
  1249. package/dist/src/storage/repositories/notification.repository.d.ts +14 -0
  1250. package/dist/src/storage/repositories/notification.repository.d.ts.map +1 -0
  1251. package/dist/src/storage/repositories/notification.repository.js +2 -0
  1252. package/dist/src/storage/repositories/notification.repository.js.map +1 -0
  1253. package/dist/src/storage/repositories/oauth.repository.d.ts +19 -0
  1254. package/dist/src/storage/repositories/oauth.repository.d.ts.map +1 -0
  1255. package/dist/src/storage/repositories/oauth.repository.js +2 -0
  1256. package/dist/src/storage/repositories/oauth.repository.js.map +1 -0
  1257. package/dist/src/storage/repositories/organism.repository.d.ts +34 -0
  1258. package/dist/src/storage/repositories/organism.repository.d.ts.map +1 -0
  1259. package/dist/src/storage/repositories/organism.repository.js +2 -0
  1260. package/dist/src/storage/repositories/organism.repository.js.map +1 -0
  1261. package/dist/src/storage/repositories/otk.repository.d.ts +9 -0
  1262. package/dist/src/storage/repositories/otk.repository.d.ts.map +1 -0
  1263. package/dist/src/storage/repositories/otk.repository.js +2 -0
  1264. package/dist/src/storage/repositories/otk.repository.js.map +1 -0
  1265. package/dist/src/storage/repositories/owner.repository.d.ts +9 -0
  1266. package/dist/src/storage/repositories/owner.repository.d.ts.map +1 -0
  1267. package/dist/src/storage/repositories/owner.repository.js +2 -0
  1268. package/dist/src/storage/repositories/owner.repository.js.map +1 -0
  1269. package/dist/src/storage/repositories/package-instance.repository.d.ts +26 -0
  1270. package/dist/src/storage/repositories/package-instance.repository.d.ts.map +1 -0
  1271. package/dist/src/storage/repositories/package-instance.repository.js +12 -0
  1272. package/dist/src/storage/repositories/package-instance.repository.js.map +1 -0
  1273. package/dist/src/storage/repositories/package.repository.d.ts +28 -0
  1274. package/dist/src/storage/repositories/package.repository.d.ts.map +1 -0
  1275. package/dist/src/storage/repositories/package.repository.js +12 -0
  1276. package/dist/src/storage/repositories/package.repository.js.map +1 -0
  1277. package/dist/src/storage/repositories/replication-queue.repository.d.ts +10 -0
  1278. package/dist/src/storage/repositories/replication-queue.repository.d.ts.map +1 -0
  1279. package/dist/src/storage/repositories/replication-queue.repository.js +2 -0
  1280. package/dist/src/storage/repositories/replication-queue.repository.js.map +1 -0
  1281. package/dist/src/storage/repositories/scheduler.repository.d.ts +30 -0
  1282. package/dist/src/storage/repositories/scheduler.repository.d.ts.map +1 -0
  1283. package/dist/src/storage/repositories/scheduler.repository.js +2 -0
  1284. package/dist/src/storage/repositories/scheduler.repository.js.map +1 -0
  1285. package/dist/src/storage/repositories/schema.repository.d.ts +9 -0
  1286. package/dist/src/storage/repositories/schema.repository.d.ts.map +1 -0
  1287. package/dist/src/storage/repositories/schema.repository.js +2 -0
  1288. package/dist/src/storage/repositories/schema.repository.js.map +1 -0
  1289. package/dist/src/storage/repositories/session.repository.d.ts +22 -0
  1290. package/dist/src/storage/repositories/session.repository.d.ts.map +1 -0
  1291. package/dist/src/storage/repositories/session.repository.js +2 -0
  1292. package/dist/src/storage/repositories/session.repository.js.map +1 -0
  1293. package/dist/src/storage/repositories/system-prompt.repository.d.ts +14 -0
  1294. package/dist/src/storage/repositories/system-prompt.repository.d.ts.map +1 -0
  1295. package/dist/src/storage/repositories/system-prompt.repository.js +2 -0
  1296. package/dist/src/storage/repositories/system-prompt.repository.js.map +1 -0
  1297. package/dist/src/storage/repositories/template-listing.repository.d.ts +44 -0
  1298. package/dist/src/storage/repositories/template-listing.repository.d.ts.map +1 -0
  1299. package/dist/src/storage/repositories/template-listing.repository.js +13 -0
  1300. package/dist/src/storage/repositories/template-listing.repository.js.map +1 -0
  1301. package/dist/src/storage/repositories/wallet.repository.d.ts +8 -0
  1302. package/dist/src/storage/repositories/wallet.repository.d.ts.map +1 -0
  1303. package/dist/src/storage/repositories/wallet.repository.js +2 -0
  1304. package/dist/src/storage/repositories/wallet.repository.js.map +1 -0
  1305. package/dist/src/storage/repositories/work.repository.d.ts +10 -0
  1306. package/dist/src/storage/repositories/work.repository.d.ts.map +1 -0
  1307. package/dist/src/storage/repositories/work.repository.js +2 -0
  1308. package/dist/src/storage/repositories/work.repository.js.map +1 -0
  1309. package/dist/src/storage/storage-factory.d.ts +9 -0
  1310. package/dist/src/storage/storage-factory.d.ts.map +1 -0
  1311. package/dist/src/storage/storage-factory.js +20 -0
  1312. package/dist/src/storage/storage-factory.js.map +1 -0
  1313. package/dist/src/types/route-manifest.d.ts +53 -0
  1314. package/dist/src/types/route-manifest.d.ts.map +1 -0
  1315. package/dist/src/types/route-manifest.js +44 -0
  1316. package/dist/src/types/route-manifest.js.map +1 -0
  1317. package/dist/src/utils/catalogue-hash.d.ts +10 -0
  1318. package/dist/src/utils/catalogue-hash.d.ts.map +1 -0
  1319. package/dist/src/utils/catalogue-hash.js +23 -0
  1320. package/dist/src/utils/catalogue-hash.js.map +1 -0
  1321. package/dist/src/utils/env-config.d.ts +8 -0
  1322. package/dist/src/utils/env-config.d.ts.map +1 -0
  1323. package/dist/src/utils/env-config.js +1264 -0
  1324. package/dist/src/utils/env-config.js.map +1 -0
  1325. package/dist/src/utils/env-validator.d.ts +14 -0
  1326. package/dist/src/utils/env-validator.d.ts.map +1 -0
  1327. package/dist/src/utils/env-validator.js +338 -0
  1328. package/dist/src/utils/env-validator.js.map +1 -0
  1329. package/dist/src/utils/fire-hook.d.ts +9 -0
  1330. package/dist/src/utils/fire-hook.d.ts.map +1 -0
  1331. package/dist/src/utils/fire-hook.js +12 -0
  1332. package/dist/src/utils/fire-hook.js.map +1 -0
  1333. package/dist/src/utils/gaii.d.ts +57 -0
  1334. package/dist/src/utils/gaii.d.ts.map +1 -0
  1335. package/dist/src/utils/gaii.js +148 -0
  1336. package/dist/src/utils/gaii.js.map +1 -0
  1337. package/dist/src/utils/ghii-resolver.d.ts +14 -0
  1338. package/dist/src/utils/ghii-resolver.d.ts.map +1 -0
  1339. package/dist/src/utils/ghii-resolver.js +21 -0
  1340. package/dist/src/utils/ghii-resolver.js.map +1 -0
  1341. package/dist/src/utils/logger.d.ts +9 -0
  1342. package/dist/src/utils/logger.d.ts.map +1 -0
  1343. package/dist/src/utils/logger.js +36 -0
  1344. package/dist/src/utils/logger.js.map +1 -0
  1345. package/dist/src/utils/otk.d.ts +2 -0
  1346. package/dist/src/utils/otk.d.ts.map +1 -0
  1347. package/dist/src/utils/otk.js +5 -0
  1348. package/dist/src/utils/otk.js.map +1 -0
  1349. package/dist/src/utils/tracking-code.d.ts +9 -0
  1350. package/dist/src/utils/tracking-code.d.ts.map +1 -0
  1351. package/dist/src/utils/tracking-code.js +16 -0
  1352. package/dist/src/utils/tracking-code.js.map +1 -0
  1353. package/dist/src/utils/url-validator.d.ts +5 -0
  1354. package/dist/src/utils/url-validator.d.ts.map +1 -0
  1355. package/dist/src/utils/url-validator.js +56 -0
  1356. package/dist/src/utils/url-validator.js.map +1 -0
  1357. package/dist/static/app-catalog.html +4401 -0
  1358. package/dist/static/cookieconsent.css +1 -0
  1359. package/dist/static/cookieconsent.umd.js +7 -0
  1360. package/dist/static/icons/icon-maskable.svg +27 -0
  1361. package/dist/static/icons/icon.svg +27 -0
  1362. package/dist/static/manifest.json +17 -0
  1363. package/dist/static/offline.html +167 -0
  1364. package/dist/static/sw.js +260 -0
  1365. package/package.json +182 -0
  1366. package/prisma/schema.prisma +1086 -0
@@ -0,0 +1,4401 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8"/>
5
+ <meta name="viewport" content="width=device-width, initial-scale=1"/>
6
+ <meta name="theme-color" content="#FAFAF8"/>
7
+ <link rel="preconnect" href="https://fonts.googleapis.com"/>
8
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/>
9
+ <link href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&display=swap" rel="stylesheet"/>
10
+ <title>My Apps — AIMEAT</title>
11
+ <style>
12
+ :root {
13
+ --bg: #FAFAF8;
14
+ --surface: #FFFFFF;
15
+ --text: #1A1A2E;
16
+ --accent: #E8564A;
17
+ --accent2: #F3E8E6;
18
+ --surface-glass: rgba(255, 255, 255, .85);
19
+ --border-subtle: #E5E7EB;
20
+ --border-hover: #D1D5DB;
21
+ --text-muted: #6B7280;
22
+ --text-dim: #9CA3AF;
23
+ --radius: 16px;
24
+ --radius-sm: 10px;
25
+ --transition: .25s cubic-bezier(.16, 1, .3, 1);
26
+ }
27
+
28
+ * { margin: 0; padding: 0; box-sizing: border-box; }
29
+
30
+ body {
31
+ background: var(--bg);
32
+ color: var(--text);
33
+ font-family: 'DM Sans', system-ui, sans-serif;
34
+ min-height: 100vh;
35
+ display: flex;
36
+ flex-direction: column;
37
+ overflow-x: hidden;
38
+ }
39
+
40
+ body::before {
41
+ content: '';
42
+ position: fixed;
43
+ inset: 0;
44
+ background:
45
+ radial-gradient(ellipse at 20% 10%, rgba(232, 86, 74, .04) 0%, transparent 50%),
46
+ radial-gradient(ellipse at 80% 90%, rgba(232, 86, 74, .03) 0%, transparent 50%),
47
+ radial-gradient(ellipse at 50% 50%, rgba(243, 232, 230, .15) 0%, transparent 60%);
48
+ z-index: 0;
49
+ pointer-events: none;
50
+ }
51
+
52
+ /* ── Header ─────────────────────────────────────── */
53
+
54
+ header {
55
+ position: sticky;
56
+ top: 0;
57
+ z-index: 100;
58
+ background: rgba(255, 255, 255, .92);
59
+ backdrop-filter: blur(24px);
60
+ -webkit-backdrop-filter: blur(24px);
61
+ border-bottom: 1px solid #E5E7EB;
62
+ padding: 16px 24px;
63
+ display: flex;
64
+ align-items: center;
65
+ gap: 16px;
66
+ flex-wrap: wrap;
67
+ }
68
+
69
+ header h1 {
70
+ font-size: 1.3rem;
71
+ font-weight: 700;
72
+ color: #1A1A2E;
73
+ white-space: nowrap;
74
+ flex-shrink: 0;
75
+ }
76
+
77
+ #search-input {
78
+ flex: 1;
79
+ min-width: 160px;
80
+ background: var(--surface-glass);
81
+ border: 1px solid var(--border-subtle);
82
+ border-radius: var(--radius-sm);
83
+ padding: 10px 16px;
84
+ color: var(--text);
85
+ font-size: .9rem;
86
+ outline: none;
87
+ transition: border-color var(--transition), box-shadow var(--transition);
88
+ }
89
+
90
+ #search-input::placeholder {
91
+ color: var(--text-dim);
92
+ }
93
+
94
+ #search-input:focus {
95
+ border-color: var(--accent);
96
+ box-shadow: 0 0 0 3px rgba(232, 86, 74, .12);
97
+ }
98
+
99
+ .header-actions {
100
+ display: flex;
101
+ gap: 8px;
102
+ flex-shrink: 0;
103
+ }
104
+
105
+ .icon-btn {
106
+ width: 40px;
107
+ height: 40px;
108
+ display: inline-flex;
109
+ align-items: center;
110
+ justify-content: center;
111
+ background: var(--surface-glass);
112
+ border: 1px solid var(--border-subtle);
113
+ border-radius: var(--radius-sm);
114
+ color: var(--text);
115
+ font-size: 1.2rem;
116
+ cursor: pointer;
117
+ transition: border-color var(--transition), transform var(--transition),
118
+ box-shadow var(--transition), background var(--transition);
119
+ user-select: none;
120
+ }
121
+
122
+ .icon-btn:hover {
123
+ border-color: var(--border-hover);
124
+ transform: translateY(-1px);
125
+ box-shadow: 0 4px 16px rgba(0, 0, 0, .06);
126
+ background: #F3F4F6;
127
+ }
128
+
129
+ .icon-btn:active {
130
+ transform: translateY(0);
131
+ }
132
+
133
+ #add-btn {
134
+ background: #E8564A;
135
+ border-color: transparent;
136
+ color: #fff;
137
+ font-weight: 700;
138
+ font-size: 1.4rem;
139
+ }
140
+
141
+ #add-btn:hover {
142
+ box-shadow: 0 4px 20px rgba(232, 86, 74, .25);
143
+ border-color: transparent;
144
+ background: #D64A3F;
145
+ }
146
+
147
+ /* ── Tag Bar ────────────────────────────────────── */
148
+
149
+ #tag-bar {
150
+ position: relative;
151
+ z-index: 1;
152
+ padding: 12px 24px;
153
+ display: flex;
154
+ gap: 8px;
155
+ overflow-x: auto;
156
+ scrollbar-width: none;
157
+ -ms-overflow-style: none;
158
+ }
159
+
160
+ #tag-bar::-webkit-scrollbar {
161
+ display: none;
162
+ }
163
+
164
+ .tag {
165
+ display: inline-flex;
166
+ align-items: center;
167
+ padding: 6px 14px;
168
+ background: var(--surface-glass);
169
+ border: 1px solid var(--border-subtle);
170
+ border-radius: 20px;
171
+ color: var(--text-muted);
172
+ font-size: .8rem;
173
+ font-weight: 500;
174
+ cursor: pointer;
175
+ white-space: nowrap;
176
+ transition: all var(--transition);
177
+ user-select: none;
178
+ }
179
+
180
+ .tag:hover {
181
+ border-color: var(--border-hover);
182
+ color: var(--text);
183
+ }
184
+
185
+ .tag.active {
186
+ background: #E8564A;
187
+ border-color: transparent;
188
+ color: #fff;
189
+ font-weight: 600;
190
+ }
191
+
192
+ /* ── App Grid ───────────────────────────────────── */
193
+
194
+ #app-grid {
195
+ position: relative;
196
+ z-index: 1;
197
+ flex: 1;
198
+ padding: 8px 24px 24px;
199
+ display: grid;
200
+ grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
201
+ gap: 16px;
202
+ align-content: start;
203
+ }
204
+
205
+ .app-card {
206
+ background: #FFFFFF;
207
+ border: 1px solid #E5E7EB;
208
+ border-radius: var(--radius);
209
+ padding: 20px 16px;
210
+ display: flex;
211
+ flex-direction: column;
212
+ align-items: center;
213
+ gap: 10px;
214
+ cursor: pointer;
215
+ transition: border-color var(--transition), transform var(--transition),
216
+ box-shadow var(--transition);
217
+ position: relative;
218
+ text-align: center;
219
+ animation: cardIn .5s cubic-bezier(.16, 1, .3, 1) both;
220
+ }
221
+
222
+ @keyframes cardIn {
223
+ from { opacity: 0; transform: translateY(12px) scale(.96); }
224
+ to { opacity: 1; transform: translateY(0) scale(1); }
225
+ }
226
+
227
+ .app-card:hover {
228
+ border-color: var(--border-hover);
229
+ transform: translateY(-3px);
230
+ box-shadow: 0 8px 24px rgba(0, 0, 0, .08);
231
+ }
232
+
233
+ .app-card:active {
234
+ transform: translateY(-1px);
235
+ }
236
+
237
+ .app-card.dragging {
238
+ opacity: .35;
239
+ transform: scale(.95);
240
+ box-shadow: none;
241
+ }
242
+
243
+ .app-card.drag-over {
244
+ border-color: var(--accent);
245
+ box-shadow: 0 0 0 2px var(--accent);
246
+ transform: translateY(-2px);
247
+ }
248
+
249
+ .app-card .app-icon {
250
+ width: 56px;
251
+ height: 56px;
252
+ border-radius: 14px;
253
+ display: flex;
254
+ align-items: center;
255
+ justify-content: center;
256
+ font-size: 1.8rem;
257
+ background: #F3E8E6;
258
+ border: 1px solid #E5E7EB;
259
+ flex-shrink: 0;
260
+ }
261
+
262
+ .app-card .app-name {
263
+ font-size: .85rem;
264
+ font-weight: 600;
265
+ line-height: 1.3;
266
+ word-break: break-word;
267
+ }
268
+
269
+ .app-card .app-source {
270
+ font-size: .7rem;
271
+ color: var(--text-dim);
272
+ }
273
+
274
+ .app-card .app-actions {
275
+ display: flex;
276
+ gap: 6px;
277
+ margin-top: 4px;
278
+ opacity: 0;
279
+ transition: opacity var(--transition);
280
+ }
281
+
282
+ .app-card:hover .app-actions {
283
+ opacity: 1;
284
+ }
285
+
286
+ .app-card .app-actions button {
287
+ padding: 4px 10px;
288
+ border-radius: 6px;
289
+ border: 1px solid var(--border-subtle);
290
+ background: var(--surface-glass);
291
+ color: var(--text-muted);
292
+ font-size: .7rem;
293
+ font-weight: 500;
294
+ cursor: pointer;
295
+ transition: all var(--transition);
296
+ font-family: inherit;
297
+ }
298
+
299
+ .app-card .app-actions button:hover {
300
+ border-color: var(--accent);
301
+ color: var(--text);
302
+ background: rgba(232, 86, 74, .08);
303
+ }
304
+
305
+ .app-card .fav-star {
306
+ position: absolute;
307
+ top: 8px;
308
+ left: 10px;
309
+ font-size: .85rem;
310
+ opacity: 0;
311
+ transition: opacity var(--transition);
312
+ }
313
+
314
+ .app-card:hover .fav-star,
315
+ .app-card .fav-star.visible {
316
+ opacity: 1;
317
+ }
318
+
319
+ /* ── Card Menu Button ─────────────────────────────── */
320
+
321
+ .card-menu-btn {
322
+ position: absolute;
323
+ top: 0.4rem;
324
+ right: 0.4rem;
325
+ background: var(--surface-glass);
326
+ border: 1px solid var(--border-subtle);
327
+ color: var(--text);
328
+ width: 28px;
329
+ height: 28px;
330
+ border-radius: 6px;
331
+ cursor: pointer;
332
+ font-size: 1.1rem;
333
+ display: flex;
334
+ align-items: center;
335
+ justify-content: center;
336
+ opacity: 0;
337
+ transition: opacity 0.2s;
338
+ z-index: 2;
339
+ }
340
+ .app-card:hover .card-menu-btn,
341
+ .card-menu-btn:focus { opacity: 1; }
342
+ .card-menu-btn:hover { background: var(--accent); }
343
+
344
+ /* ── Empty State ────────────────────────────────── */
345
+
346
+ .empty-state {
347
+ grid-column: 1 / -1;
348
+ display: flex;
349
+ flex-direction: column;
350
+ align-items: center;
351
+ justify-content: center;
352
+ padding: 72px 24px;
353
+ text-align: center;
354
+ color: var(--text-dim);
355
+ }
356
+
357
+ .empty-state .empty-icon {
358
+ font-size: 4rem;
359
+ margin-bottom: 20px;
360
+ opacity: .6;
361
+ filter: drop-shadow(0 4px 12px rgba(232, 86, 74, .10));
362
+ }
363
+
364
+ .empty-state h3 {
365
+ font-size: 1.15rem;
366
+ font-weight: 600;
367
+ color: var(--text-muted);
368
+ margin-bottom: 8px;
369
+ }
370
+
371
+ .empty-state p {
372
+ font-size: .9rem;
373
+ line-height: 1.6;
374
+ max-width: 340px;
375
+ margin-bottom: 6px;
376
+ }
377
+
378
+ .empty-state .empty-formats {
379
+ font-size: .78rem;
380
+ color: var(--text-dim);
381
+ opacity: .7;
382
+ margin-top: 4px;
383
+ }
384
+
385
+ /* ── Footer ─────────────────────────────────────── */
386
+
387
+ footer {
388
+ position: relative;
389
+ z-index: 1;
390
+ padding: 14px 24px;
391
+ border-top: 1px solid var(--border-subtle);
392
+ display: flex;
393
+ align-items: center;
394
+ justify-content: space-between;
395
+ }
396
+
397
+ #stats {
398
+ font-size: .75rem;
399
+ color: var(--text-dim);
400
+ letter-spacing: .04em;
401
+ }
402
+
403
+ .footer-brand {
404
+ font-size: .7rem;
405
+ color: var(--text-dim);
406
+ letter-spacing: .1em;
407
+ text-transform: uppercase;
408
+ opacity: .6;
409
+ }
410
+
411
+ /* ── Modal Overlay ──────────────────────────────── */
412
+
413
+ #modal-overlay {
414
+ position: fixed;
415
+ inset: 0;
416
+ z-index: 500;
417
+ background: rgba(0, 0, 0, .3);
418
+ backdrop-filter: blur(6px);
419
+ -webkit-backdrop-filter: blur(6px);
420
+ display: flex;
421
+ align-items: center;
422
+ justify-content: center;
423
+ padding: 24px;
424
+ }
425
+
426
+ #modal-overlay[hidden] {
427
+ display: none;
428
+ }
429
+
430
+ .modal {
431
+ background: #FFFFFF;
432
+ border: 1px solid #E5E7EB;
433
+ border-radius: var(--radius);
434
+ padding: 32px;
435
+ max-width: 480px;
436
+ width: 100%;
437
+ box-shadow: 0 8px 40px rgba(0, 0, 0, .12);
438
+ animation: cardIn .4s cubic-bezier(.16, 1, .3, 1);
439
+ }
440
+
441
+ .modal h2 {
442
+ font-size: 1.15rem;
443
+ margin-bottom: 20px;
444
+ color: #1A1A2E;
445
+ }
446
+
447
+ /* ── Modal Form Elements ──────────────────────────── */
448
+
449
+ .modal-tabs {
450
+ display: flex;
451
+ gap: 0;
452
+ margin-bottom: 20px;
453
+ border: 1px solid var(--border-subtle);
454
+ border-radius: var(--radius-sm);
455
+ overflow: hidden;
456
+ }
457
+
458
+ .modal-tab {
459
+ flex: 1;
460
+ padding: 10px 16px;
461
+ background: transparent;
462
+ border: none;
463
+ color: var(--text-muted);
464
+ font-size: .85rem;
465
+ font-weight: 500;
466
+ cursor: pointer;
467
+ transition: all var(--transition);
468
+ }
469
+
470
+ .modal-tab:not(:last-child) {
471
+ border-right: 1px solid var(--border-subtle);
472
+ }
473
+
474
+ .modal-tab:hover {
475
+ color: var(--text);
476
+ background: #F9FAFB;
477
+ }
478
+
479
+ .modal-tab.active {
480
+ background: #E8564A;
481
+ color: #fff;
482
+ font-weight: 600;
483
+ }
484
+
485
+ .tab-content {
486
+ display: none;
487
+ margin-bottom: 16px;
488
+ }
489
+
490
+ .tab-content.active {
491
+ display: block;
492
+ }
493
+
494
+ .modal-label {
495
+ display: block;
496
+ font-size: .78rem;
497
+ font-weight: 600;
498
+ color: var(--text-muted);
499
+ margin-bottom: 6px;
500
+ text-transform: uppercase;
501
+ letter-spacing: .04em;
502
+ }
503
+
504
+ .label-hint {
505
+ font-weight: 400;
506
+ text-transform: none;
507
+ letter-spacing: 0;
508
+ color: var(--text-dim);
509
+ }
510
+
511
+ .modal-input {
512
+ width: 100%;
513
+ background: var(--surface-glass);
514
+ border: 1px solid var(--border-subtle);
515
+ border-radius: var(--radius-sm);
516
+ padding: 10px 14px;
517
+ color: var(--text);
518
+ font-size: .88rem;
519
+ outline: none;
520
+ transition: border-color var(--transition), box-shadow var(--transition);
521
+ font-family: inherit;
522
+ }
523
+
524
+ .modal-input::placeholder {
525
+ color: var(--text-dim);
526
+ }
527
+
528
+ .modal-input:focus {
529
+ border-color: var(--accent);
530
+ box-shadow: 0 0 0 3px rgba(232, 86, 74, .12);
531
+ }
532
+
533
+ select.modal-input {
534
+ appearance: none;
535
+ -webkit-appearance: none;
536
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='%236B7280' viewBox='0 0 16 16'%3E%3Cpath d='M4 6l4 4 4-4'/%3E%3C/svg%3E");
537
+ background-repeat: no-repeat;
538
+ background-position: right 12px center;
539
+ padding-right: 32px;
540
+ cursor: pointer;
541
+ }
542
+
543
+ select.modal-input option {
544
+ background: var(--surface);
545
+ color: var(--text);
546
+ }
547
+
548
+ .modal-fields {
549
+ display: flex;
550
+ flex-direction: column;
551
+ gap: 14px;
552
+ margin-bottom: 24px;
553
+ }
554
+
555
+ .modal-row {
556
+ display: flex;
557
+ gap: 12px;
558
+ }
559
+
560
+ .modal-field {
561
+ display: flex;
562
+ flex-direction: column;
563
+ }
564
+
565
+ .modal-actions {
566
+ display: flex;
567
+ gap: 10px;
568
+ justify-content: flex-end;
569
+ }
570
+
571
+ .modal-btn {
572
+ padding: 10px 22px;
573
+ border-radius: var(--radius-sm);
574
+ border: 1px solid var(--border-subtle);
575
+ font-size: .85rem;
576
+ font-weight: 600;
577
+ cursor: pointer;
578
+ transition: all var(--transition);
579
+ font-family: inherit;
580
+ }
581
+
582
+ .modal-btn.secondary {
583
+ background: transparent;
584
+ color: var(--text-muted);
585
+ }
586
+
587
+ .modal-btn.secondary:hover {
588
+ color: var(--text);
589
+ border-color: var(--border-hover);
590
+ }
591
+
592
+ .modal-btn.primary {
593
+ background: #E8564A;
594
+ border-color: transparent;
595
+ color: #fff;
596
+ }
597
+
598
+ .modal-btn.primary:hover:not(:disabled) {
599
+ box-shadow: 0 4px 20px rgba(232, 86, 74, .25);
600
+ background: #D64A3F;
601
+ }
602
+
603
+ .modal-btn:disabled {
604
+ opacity: 0.4;
605
+ cursor: not-allowed;
606
+ }
607
+
608
+ /* ── Drop Zone ──────────────────────────────────── */
609
+
610
+ .drop-zone {
611
+ border: 2px dashed var(--border-subtle);
612
+ border-radius: var(--radius-sm);
613
+ padding: 28px 20px;
614
+ text-align: center;
615
+ transition: border-color var(--transition), background var(--transition);
616
+ cursor: pointer;
617
+ }
618
+
619
+ .drop-zone.dragover {
620
+ border-color: var(--accent);
621
+ background: rgba(232, 86, 74, .04);
622
+ }
623
+
624
+ .drop-zone-icon {
625
+ font-size: 2rem;
626
+ margin-bottom: 8px;
627
+ opacity: .5;
628
+ }
629
+
630
+ .drop-zone-text {
631
+ font-size: .85rem;
632
+ color: var(--text-muted);
633
+ margin-bottom: 4px;
634
+ }
635
+
636
+ .drop-zone-hint {
637
+ font-size: .75rem;
638
+ color: var(--text-dim);
639
+ margin-bottom: 10px;
640
+ }
641
+
642
+ .browse-btn {
643
+ padding: 7px 18px;
644
+ border-radius: var(--radius-sm);
645
+ border: 1px solid var(--border-subtle);
646
+ background: var(--surface-glass);
647
+ color: var(--text);
648
+ font-size: .8rem;
649
+ font-weight: 500;
650
+ cursor: pointer;
651
+ transition: all var(--transition);
652
+ font-family: inherit;
653
+ }
654
+
655
+ .browse-btn:hover {
656
+ border-color: var(--border-hover);
657
+ background: #F3F4F6;
658
+ }
659
+
660
+ .drop-zone-selected {
661
+ margin-top: 10px;
662
+ font-size: .8rem;
663
+ color: var(--accent);
664
+ font-weight: 500;
665
+ min-height: 1.2em;
666
+ }
667
+
668
+ /* ── Iframe View ────────────────────────────────── */
669
+
670
+ #iframe-view {
671
+ position: fixed;
672
+ inset: 0;
673
+ z-index: 600;
674
+ background: var(--bg);
675
+ display: flex;
676
+ flex-direction: column;
677
+ }
678
+
679
+ #iframe-view[hidden] {
680
+ display: none;
681
+ }
682
+
683
+ #iframe-view .iframe-toolbar {
684
+ display: flex;
685
+ align-items: center;
686
+ gap: 12px;
687
+ padding: 10px 16px;
688
+ background: rgba(255, 255, 255, .95);
689
+ backdrop-filter: blur(20px);
690
+ -webkit-backdrop-filter: blur(20px);
691
+ border-bottom: 1px solid #E5E7EB;
692
+ }
693
+
694
+ #iframe-view .iframe-toolbar .iframe-title {
695
+ flex: 1;
696
+ font-size: .85rem;
697
+ font-weight: 600;
698
+ color: var(--text);
699
+ overflow: hidden;
700
+ text-overflow: ellipsis;
701
+ white-space: nowrap;
702
+ }
703
+
704
+ #iframe-view iframe {
705
+ flex: 1;
706
+ border: none;
707
+ width: 100%;
708
+ }
709
+
710
+ /* ── Context Menu ──────────────────────────────── */
711
+
712
+ #context-menu {
713
+ position: fixed;
714
+ z-index: 700;
715
+ background: rgba(255, 255, 255, .98);
716
+ backdrop-filter: blur(24px);
717
+ -webkit-backdrop-filter: blur(24px);
718
+ border: 1px solid #E5E7EB;
719
+ border-radius: var(--radius-sm);
720
+ padding: 6px 0;
721
+ min-width: 180px;
722
+ box-shadow: 0 8px 32px rgba(0, 0, 0, .12);
723
+ animation: cardIn .2s cubic-bezier(.16, 1, .3, 1);
724
+ }
725
+
726
+ #context-menu[hidden] {
727
+ display: none;
728
+ }
729
+
730
+ #context-menu button {
731
+ display: flex;
732
+ align-items: center;
733
+ gap: 8px;
734
+ width: 100%;
735
+ padding: 9px 16px;
736
+ background: none;
737
+ border: none;
738
+ color: var(--text);
739
+ font-size: .84rem;
740
+ font-family: inherit;
741
+ cursor: pointer;
742
+ transition: background var(--transition);
743
+ text-align: left;
744
+ }
745
+
746
+ #context-menu button:hover {
747
+ background: #F3F4F6;
748
+ }
749
+
750
+ #context-menu button.danger {
751
+ color: var(--accent);
752
+ }
753
+
754
+ #context-menu button.danger:hover {
755
+ background: rgba(232, 86, 74, .08);
756
+ }
757
+
758
+ #context-menu hr {
759
+ border: none;
760
+ border-top: 1px solid var(--border-subtle);
761
+ margin: 4px 0;
762
+ }
763
+
764
+ /* ── Responsive ─────────────────────────────────── */
765
+
766
+ @media (max-width: 480px) {
767
+ header {
768
+ padding: 12px 16px;
769
+ gap: 10px;
770
+ }
771
+
772
+ header h1 {
773
+ font-size: 1.1rem;
774
+ }
775
+
776
+ #search-input {
777
+ min-width: 0;
778
+ order: 3;
779
+ flex-basis: 100%;
780
+ }
781
+
782
+ #tag-bar {
783
+ padding: 10px 16px;
784
+ }
785
+
786
+ #app-grid {
787
+ padding: 8px 16px 20px;
788
+ grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
789
+ gap: 12px;
790
+ }
791
+
792
+ footer {
793
+ padding: 12px 16px;
794
+ }
795
+ }
796
+
797
+ /* Light theme is now the default — no data-theme overrides needed */
798
+
799
+ /* ── Source Modal ──────────────────────────────── */
800
+
801
+ #source-overlay {
802
+ position: fixed;
803
+ inset: 0;
804
+ z-index: 500;
805
+ background: rgba(0, 0, 0, .3);
806
+ backdrop-filter: blur(6px);
807
+ -webkit-backdrop-filter: blur(6px);
808
+ display: flex;
809
+ align-items: center;
810
+ justify-content: center;
811
+ padding: 24px;
812
+ }
813
+
814
+ #source-overlay[hidden] {
815
+ display: none;
816
+ }
817
+
818
+ .source-modal { max-width: 800px; width: 95vw; }
819
+ #source-code {
820
+ width: 100%;
821
+ min-height: 400px;
822
+ max-height: 60vh;
823
+ background: #F9FAFB;
824
+ color: #1A1A2E;
825
+ border: 1px solid var(--border-subtle);
826
+ border-radius: 8px;
827
+ padding: 1rem;
828
+ font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
829
+ font-size: 0.85rem;
830
+ line-height: 1.5;
831
+ resize: vertical;
832
+ tab-size: 2;
833
+ }
834
+
835
+ /* ── Settings Modal ──────────────────────────────── */
836
+
837
+ #settings-overlay {
838
+ position: fixed;
839
+ inset: 0;
840
+ z-index: 500;
841
+ background: rgba(0, 0, 0, .3);
842
+ backdrop-filter: blur(6px);
843
+ -webkit-backdrop-filter: blur(6px);
844
+ display: flex;
845
+ align-items: center;
846
+ justify-content: center;
847
+ padding: 24px;
848
+ }
849
+
850
+ #settings-overlay[hidden] {
851
+ display: none;
852
+ }
853
+
854
+ .settings-section {
855
+ margin-bottom: 20px;
856
+ }
857
+
858
+ .settings-section-title {
859
+ font-size: .78rem;
860
+ font-weight: 600;
861
+ color: var(--text-muted);
862
+ text-transform: uppercase;
863
+ letter-spacing: .04em;
864
+ margin-bottom: 12px;
865
+ padding-bottom: 6px;
866
+ border-bottom: 1px solid var(--border-subtle);
867
+ }
868
+
869
+ .settings-row {
870
+ display: flex;
871
+ align-items: center;
872
+ gap: 12px;
873
+ margin-bottom: 10px;
874
+ }
875
+
876
+ .settings-row label {
877
+ flex: 0 0 130px;
878
+ font-size: .84rem;
879
+ color: var(--text-muted);
880
+ }
881
+
882
+ .settings-row .modal-input {
883
+ flex: 1;
884
+ }
885
+
886
+ .settings-backup-actions {
887
+ display: flex;
888
+ gap: 10px;
889
+ flex-wrap: wrap;
890
+ }
891
+
892
+ .modal-btn.danger {
893
+ background: transparent;
894
+ border-color: var(--accent);
895
+ color: var(--accent);
896
+ }
897
+
898
+ .modal-btn.danger:hover {
899
+ background: rgba(232, 86, 74, .08);
900
+ }
901
+
902
+ /* ── AIMEAT Import Dialog ─────────────────────────── */
903
+
904
+ #aimeat-import-overlay {
905
+ position: fixed;
906
+ inset: 0;
907
+ z-index: 550;
908
+ background: rgba(0, 0, 0, .3);
909
+ backdrop-filter: blur(6px);
910
+ -webkit-backdrop-filter: blur(6px);
911
+ display: flex;
912
+ align-items: center;
913
+ justify-content: center;
914
+ padding: 24px;
915
+ }
916
+
917
+ #aimeat-import-overlay[hidden] {
918
+ display: none;
919
+ }
920
+
921
+ .aimeat-app-list {
922
+ max-height: 300px;
923
+ overflow-y: auto;
924
+ margin-bottom: 16px;
925
+ }
926
+
927
+ .aimeat-app-item {
928
+ display: flex;
929
+ align-items: center;
930
+ gap: 10px;
931
+ padding: 10px 12px;
932
+ border: 1px solid var(--border-subtle);
933
+ border-radius: var(--radius-sm);
934
+ margin-bottom: 8px;
935
+ transition: border-color var(--transition);
936
+ }
937
+
938
+ .aimeat-app-item:hover {
939
+ border-color: var(--border-hover);
940
+ }
941
+
942
+ .aimeat-app-item input[type="checkbox"] {
943
+ flex-shrink: 0;
944
+ width: 18px;
945
+ height: 18px;
946
+ cursor: pointer;
947
+ }
948
+
949
+ .aimeat-app-info {
950
+ flex: 1;
951
+ min-width: 0;
952
+ }
953
+
954
+ .aimeat-app-name {
955
+ font-size: .85rem;
956
+ font-weight: 600;
957
+ overflow: hidden;
958
+ text-overflow: ellipsis;
959
+ white-space: nowrap;
960
+ }
961
+
962
+ .aimeat-app-size {
963
+ font-size: .72rem;
964
+ color: var(--text-dim);
965
+ }
966
+
967
+ .aimeat-app-item select {
968
+ flex-shrink: 0;
969
+ background: var(--surface-glass);
970
+ border: 1px solid var(--border-subtle);
971
+ border-radius: 6px;
972
+ padding: 4px 8px;
973
+ color: var(--text);
974
+ font-size: .78rem;
975
+ font-family: inherit;
976
+ cursor: pointer;
977
+ }
978
+
979
+ .aimeat-app-item select option {
980
+ background: var(--surface);
981
+ color: var(--text);
982
+ }
983
+
984
+ /* ── Publish Modal ──────────────────────────────── */
985
+
986
+ #publish-overlay {
987
+ position: fixed;
988
+ inset: 0;
989
+ z-index: 560;
990
+ background: rgba(0, 0, 0, .3);
991
+ backdrop-filter: blur(6px);
992
+ -webkit-backdrop-filter: blur(6px);
993
+ display: flex;
994
+ align-items: center;
995
+ justify-content: center;
996
+ padding: 24px;
997
+ }
998
+
999
+ #publish-overlay[hidden] {
1000
+ display: none;
1001
+ }
1002
+
1003
+ /* ── Published Apps Section ──────────────────────── */
1004
+
1005
+ #published-section {
1006
+ margin: 0 24px 24px;
1007
+ position: relative;
1008
+ z-index: 1;
1009
+ }
1010
+
1011
+ .published-header {
1012
+ display: flex;
1013
+ align-items: center;
1014
+ justify-content: space-between;
1015
+ margin-bottom: 12px;
1016
+ cursor: pointer;
1017
+ user-select: none;
1018
+ }
1019
+
1020
+ .published-header h2 {
1021
+ font-size: 1rem;
1022
+ font-weight: 700;
1023
+ color: #34d399;
1024
+ display: flex;
1025
+ align-items: center;
1026
+ gap: 8px;
1027
+ }
1028
+
1029
+ .published-header .arrow {
1030
+ transition: transform var(--transition);
1031
+ font-size: .8rem;
1032
+ color: var(--text-muted);
1033
+ }
1034
+
1035
+ .published-header .arrow.open {
1036
+ transform: rotate(180deg);
1037
+ }
1038
+
1039
+ .published-grid {
1040
+ display: grid;
1041
+ grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
1042
+ gap: 12px;
1043
+ }
1044
+
1045
+ .published-card {
1046
+ background: var(--surface-glass);
1047
+ border: 1px solid rgba(52, 211, 153, .25);
1048
+ border-radius: var(--radius-sm);
1049
+ padding: 14px;
1050
+ display: flex;
1051
+ flex-direction: column;
1052
+ gap: 8px;
1053
+ transition: border-color var(--transition), box-shadow var(--transition);
1054
+ }
1055
+
1056
+ .published-card:hover {
1057
+ border-color: rgba(52, 211, 153, .5);
1058
+ box-shadow: 0 4px 20px rgba(52, 211, 153, .08);
1059
+ }
1060
+
1061
+ .published-card-name {
1062
+ font-weight: 600;
1063
+ font-size: .88rem;
1064
+ overflow: hidden;
1065
+ text-overflow: ellipsis;
1066
+ white-space: nowrap;
1067
+ }
1068
+
1069
+ .published-card-meta {
1070
+ font-size: .72rem;
1071
+ color: var(--text-muted);
1072
+ display: flex;
1073
+ gap: 8px;
1074
+ flex-wrap: wrap;
1075
+ }
1076
+
1077
+ .published-card-actions {
1078
+ display: flex;
1079
+ gap: 6px;
1080
+ margin-top: 4px;
1081
+ }
1082
+
1083
+ .published-card-actions button {
1084
+ background: var(--surface-glass);
1085
+ border: 1px solid var(--border-subtle);
1086
+ border-radius: 6px;
1087
+ padding: 5px 10px;
1088
+ color: var(--text);
1089
+ font-size: .72rem;
1090
+ font-family: inherit;
1091
+ cursor: pointer;
1092
+ transition: background var(--transition), border-color var(--transition);
1093
+ }
1094
+
1095
+ .published-card-actions button:hover {
1096
+ border-color: var(--border-hover);
1097
+ background: #F3F4F6;
1098
+ }
1099
+
1100
+ .published-card-actions button.danger:hover {
1101
+ border-color: var(--accent);
1102
+ background: rgba(232, 86, 74, .08);
1103
+ color: var(--accent);
1104
+ }
1105
+
1106
+ .published-empty {
1107
+ padding: 16px;
1108
+ text-align: center;
1109
+ color: var(--text-dim);
1110
+ font-size: .85rem;
1111
+ }
1112
+
1113
+ /* ── Cortex Extensions Bar ──────────────────────── */
1114
+
1115
+ .cortex-mini-card{background:#FFFFFF;border:1px solid #E5E7EB;border-radius:10px;padding:.75rem 1rem;cursor:pointer;min-width:160px;flex-shrink:0;transition:all .15s}
1116
+ .cortex-mini-card:hover{background:#F9FAFB;border-color:#D1D5DB}
1117
+ .cortex-mini-name{font-weight:600;font-size:.85rem;margin-bottom:.25rem;white-space:nowrap}
1118
+ .cortex-mini-meta{font-size:.7rem;color:#6B7280}
1119
+
1120
+ /* ── Prompt Builder Panel ──────────────────────── */
1121
+ #prompt-builder-overlay {
1122
+ position: fixed; inset: 0; z-index: 600;
1123
+ background: rgba(0,0,0,.3); backdrop-filter: blur(6px);
1124
+ display: none; align-items: center; justify-content: center; padding: 24px;
1125
+ }
1126
+ .prompt-builder-modal {
1127
+ background: #FFFFFF;
1128
+ border: 1px solid #E5E7EB; border-radius: 16px;
1129
+ padding: 28px; max-width: 900px; width: 96vw; max-height: 90vh;
1130
+ display: flex; flex-direction: column; overflow: hidden;
1131
+ box-shadow: 0 8px 40px rgba(0,0,0,.12);
1132
+ }
1133
+ .prompt-builder-modal h2 { margin: 0 0 16px; font-size: 1.1rem; }
1134
+ .pb-mode-row { display: flex; gap: 12px; margin-bottom: 14px; }
1135
+ .pb-mode-radio { display: flex; align-items: center; gap: 6px; cursor: pointer; font-size: .88rem; }
1136
+ .pb-mode-radio input { accent-color: #E8564A; }
1137
+ .pb-desc-area {
1138
+ width: 100%; min-height: 60px; max-height: 120px; resize: vertical;
1139
+ background: #F9FAFB; border: 1px solid #E5E7EB;
1140
+ border-radius: 10px; padding: 10px 14px; color: inherit; font-size: .85rem;
1141
+ font-family: inherit; line-height: 1.5; margin-bottom: 14px;
1142
+ }
1143
+ .pb-desc-area:focus { outline: none; border-color: #E8564A; }
1144
+ .pb-ext-toggle { display: flex; align-items: center; gap: 8px; cursor: pointer; font-size: .85rem; margin-bottom: 10px; }
1145
+ .pb-ext-toggle input { accent-color: #E8564A; }
1146
+ .pb-ext-list {
1147
+ display: none; gap: 8px; flex-wrap: wrap; margin-bottom: 14px; padding: 10px;
1148
+ background: #F9FAFB; border: 1px solid #E5E7EB;
1149
+ border-radius: 10px; max-height: 160px; overflow-y: auto;
1150
+ }
1151
+ .pb-ext-list.open { display: flex; }
1152
+ .pb-ext-chip {
1153
+ display: flex; align-items: center; gap: 6px; padding: 6px 12px;
1154
+ background: #F9FAFB; border: 1px solid #E5E7EB;
1155
+ border-radius: 8px; cursor: pointer; font-size: .8rem; transition: all .15s;
1156
+ }
1157
+ .pb-ext-chip:hover { background: #F3F4F6; }
1158
+ .pb-ext-chip.selected { background: rgba(232,86,74,.08); border-color: rgba(232,86,74,.35); }
1159
+ .pb-ext-chip input { accent-color: #E8564A; pointer-events: none; }
1160
+ .pb-preview {
1161
+ flex: 1; min-height: 120px; overflow-y: auto; margin-bottom: 14px; padding: 12px;
1162
+ background: #F9FAFB; border: 1px solid #E5E7EB;
1163
+ border-radius: 10px; font-family: 'Consolas','Monaco','Courier New',monospace;
1164
+ font-size: .75rem; line-height: 1.5; white-space: pre-wrap; word-break: break-word;
1165
+ color: #6B7280;
1166
+ }
1167
+ .pb-preview-label { font-size: .75rem; text-transform: uppercase; letter-spacing: .1em; color: #6B7280; margin-bottom: 6px; }
1168
+ </style>
1169
+ </head>
1170
+ <body>
1171
+
1172
+ <header>
1173
+ <h1>My Apps</h1>
1174
+ <input type="text" id="search-input" placeholder="Search apps..." autocomplete="off" spellcheck="false"/>
1175
+ <div class="header-actions">
1176
+ <button class="icon-btn" id="add-btn" title="Add app">+</button>
1177
+ <button class="icon-btn" id="generate-btn" title="Generate with AI">&#x2728;</button>
1178
+ <button class="icon-btn" id="homepage-btn" title="Generate Homepage">&#x1F3E0;</button>
1179
+ <button class="icon-btn" id="settings-btn" title="Settings">&#x2699;</button>
1180
+ </div>
1181
+ </header>
1182
+
1183
+ <nav id="tag-bar"></nav>
1184
+
1185
+ <!-- Active Extensions Bar -->
1186
+ <div id="cortex-bar" style="display:none;margin:0 24px 1.5rem;position:relative;z-index:1">
1187
+ <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:.75rem">
1188
+ <h3 style="margin:0;font-size:.95rem;color:#6B7280">&#x1F50C; Active Extensions</h3>
1189
+ <button onclick="document.getElementById('cortex-bar-grid').style.display=document.getElementById('cortex-bar-grid').style.display==='none'?'flex':'none'" style="background:none;border:none;color:#6B7280;cursor:pointer;font-size:.8rem">&#x25BC; toggle</button>
1190
+ </div>
1191
+ <div id="cortex-bar-grid" style="display:flex;gap:.75rem;overflow-x:auto;padding-bottom:.5rem"></div>
1192
+ </div>
1193
+
1194
+ <!-- Extension Popup Overlay -->
1195
+ <div id="cortex-popup-overlay" style="display:none;position:fixed;inset:0;z-index:500;background:rgba(0,0,0,.3);backdrop-filter:blur(6px);align-items:center;justify-content:center;padding:24px">
1196
+ <div style="background:#FFFFFF;border:1px solid #E5E7EB;border-radius:16px;padding:32px;max-width:500px;width:100%;max-height:80vh;overflow-y:auto;box-shadow:0 8px 40px rgba(0,0,0,.12)">
1197
+ <div id="cortex-popup-content"></div>
1198
+ <div style="display:flex;justify-content:flex-end;margin-top:1rem">
1199
+ <button onclick="document.getElementById('cortex-popup-overlay').style.display='none'" style="padding:6px 16px;border-radius:8px;border:1px solid #E5E7EB;background:transparent;color:#6B7280;cursor:pointer">Close</button>
1200
+ </div>
1201
+ </div>
1202
+ </div>
1203
+
1204
+ <!-- Cortex Extension Editor Overlay -->
1205
+ <div id="cortex-editor-overlay" style="display:none;position:fixed;inset:0;z-index:600;background:rgba(0,0,0,.35);backdrop-filter:blur(8px);align-items:center;justify-content:center;padding:24px">
1206
+ <div style="background:#FFFFFF;border:1px solid #E5E7EB;border-radius:16px;padding:32px;max-width:800px;width:100%;max-height:90vh;overflow-y:auto;box-shadow:0 8px 40px rgba(0,0,0,.12)">
1207
+ <h2 style="margin-top:0;font-size:1.1rem">&#x1F6E0;&#xFE0F; Extension Editor</h2>
1208
+ <p id="cortex-editor-name" style="color:#6B7280;font-size:.85rem;margin-top:-.5rem"></p>
1209
+ <div id="cortex-editor-status" style="font-size:.8rem;margin-bottom:1rem;min-height:1.2em;color:#34d399"></div>
1210
+ <div style="margin-bottom:1rem">
1211
+ <label style="font-size:.85rem;font-weight:600;display:block;margin-bottom:.5rem">Manifest (YAML)</label>
1212
+ <textarea id="cortex-editor-manifest" spellcheck="false" style="width:100%;min-height:300px;background:#F9FAFB;color:#1A1A2E;border:1px solid #E5E7EB;border-radius:8px;padding:12px;font-family:monospace;font-size:.8rem;resize:vertical;tab-size:2"></textarea>
1213
+ </div>
1214
+ <div id="cortex-editor-libs"></div>
1215
+ <div style="margin-bottom:1.5rem">
1216
+ <button onclick="window._launcher.cortexEditorAddLib()" style="font-size:.8rem;padding:4px 12px;border-radius:6px;border:1px solid #E5E7EB;background:transparent;color:#6B7280;cursor:pointer">+ Add Lib File</button>
1217
+ </div>
1218
+ <div style="display:flex;gap:.75rem;justify-content:flex-end;flex-wrap:wrap">
1219
+ <button onclick="window._launcher.cortexEditorExport()" style="padding:6px 16px;border-radius:8px;border:1px solid #E5E7EB;background:transparent;color:#6B7280;cursor:pointer">&#x1F4E5; Export Files</button>
1220
+ <button onclick="window._launcher.cortexEditorSave()" id="cortex-editor-save-btn" style="padding:6px 20px;border-radius:8px;border:none;background:#E8564A;color:#fff;font-weight:600;cursor:pointer">Save &amp; Re-install</button>
1221
+ <button onclick="window._launcher.closeCortexEditor()" style="padding:6px 16px;border-radius:8px;border:1px solid #E5E7EB;background:transparent;color:#6B7280;cursor:pointer">Cancel</button>
1222
+ </div>
1223
+ </div>
1224
+ </div>
1225
+
1226
+ <!-- Published Apps Section -->
1227
+ <div id="published-section" style="display:none">
1228
+ <div class="published-header" onclick="window._launcher.togglePublished()">
1229
+ <h2>&#x1F680; Published Apps <span id="published-count"></span></h2>
1230
+ <span class="arrow open" id="published-arrow">&#x25BC;</span>
1231
+ </div>
1232
+ <div id="published-grid" class="published-grid"></div>
1233
+ </div>
1234
+
1235
+ <!-- Recently Opened Strip -->
1236
+ <div id="recent-section" style="display:none;margin:0 24px 1rem">
1237
+ <h3 style="margin:0 0 .5rem;font-size:.9rem;color:#6B7280">&#x1F552; Recently Opened</h3>
1238
+ <div id="recent-strip" style="display:flex;gap:.75rem;overflow-x:auto;padding-bottom:.5rem"></div>
1239
+ </div>
1240
+
1241
+ <main id="app-grid"></main>
1242
+
1243
+ <footer>
1244
+ <span id="stats">0 apps</span>
1245
+ <span class="footer-brand">AIMEAT</span>
1246
+ </footer>
1247
+
1248
+ <div id="modal-overlay" hidden>
1249
+ <div class="modal" id="add-app-modal">
1250
+ <h2 id="modal-title">Add App</h2>
1251
+
1252
+ <!-- Source tabs -->
1253
+ <div class="modal-tabs">
1254
+ <button class="modal-tab active" data-tab="url">URL</button>
1255
+ <button class="modal-tab" data-tab="file">File</button>
1256
+ <button class="modal-tab" data-tab="paste">Paste</button>
1257
+ <button class="modal-tab" data-tab="aimeat">AIMEAT</button>
1258
+ </div>
1259
+
1260
+ <!-- URL tab content -->
1261
+ <div class="tab-content active" id="tab-url">
1262
+ <label class="modal-label" for="app-url">App URL</label>
1263
+ <input type="url" id="app-url" class="modal-input" placeholder="https://example.com/app.html" autocomplete="off"/>
1264
+ </div>
1265
+
1266
+ <!-- File tab content -->
1267
+ <div class="tab-content" id="tab-file">
1268
+ <label class="modal-label">HTML File</label>
1269
+ <div class="drop-zone" id="drop-zone">
1270
+ <div class="drop-zone-icon">&#x1F4C4;</div>
1271
+ <p class="drop-zone-text">Drag &amp; drop an HTML file here</p>
1272
+ <p class="drop-zone-hint">or</p>
1273
+ <button type="button" class="browse-btn" id="browse-btn">Browse files</button>
1274
+ <input type="file" id="file-input" accept=".html,.htm,.zip" hidden/>
1275
+ <p class="drop-zone-selected" id="selected-file-name"></p>
1276
+ </div>
1277
+ </div>
1278
+
1279
+ <!-- Paste tab content -->
1280
+ <div class="tab-content" id="tab-paste">
1281
+ <label class="modal-label" for="app-paste-code">Paste HTML Source Code</label>
1282
+ <textarea id="app-paste-code" class="modal-input" rows="10" placeholder="Paste your HTML source code here..." style="font-family:'Consolas','Monaco','Courier New',monospace;font-size:.8rem;resize:vertical;min-height:160px;line-height:1.4"></textarea>
1283
+ </div>
1284
+
1285
+ <!-- AIMEAT tab content -->
1286
+ <div class="tab-content" id="tab-aimeat">
1287
+ <p style="font-size:.85rem;color:var(--text-muted);margin-bottom:14px;line-height:1.5">
1288
+ Import apps from a connected AIMEAT server. Configure the server URL in Settings first.
1289
+ </p>
1290
+ <button type="button" class="modal-btn primary" onclick="window._launcher.importFromAimeat()" style="width:100%">
1291
+ Fetch Available Apps
1292
+ </button>
1293
+ </div>
1294
+
1295
+ <!-- Common fields -->
1296
+ <div class="modal-fields">
1297
+ <div class="modal-row">
1298
+ <div class="modal-field" style="flex:1">
1299
+ <label class="modal-label" for="app-name">App Name</label>
1300
+ <input type="text" id="app-name" class="modal-input" placeholder="My App" autocomplete="off"/>
1301
+ </div>
1302
+ <div class="modal-field" style="width:72px">
1303
+ <label class="modal-label" for="app-icon">Icon</label>
1304
+ <input type="text" id="app-icon" class="modal-input" maxlength="4" placeholder="&#x1F4DD;" style="text-align:center;font-size:1.2rem"/>
1305
+ </div>
1306
+ </div>
1307
+ <div class="modal-field">
1308
+ <label class="modal-label" for="app-tags">Tags <span class="label-hint">(comma separated)</span></label>
1309
+ <input type="text" id="app-tags" class="modal-input" placeholder="tools, productivity" autocomplete="off"/>
1310
+ </div>
1311
+ <div class="modal-field">
1312
+ <label class="modal-label" for="app-open-mode">Open Mode</label>
1313
+ <select id="app-open-mode" class="modal-input">
1314
+ <option value="tab">New Tab</option>
1315
+ <option value="iframe">Inline (iframe)</option>
1316
+ </select>
1317
+ </div>
1318
+ </div>
1319
+
1320
+ <!-- Actions -->
1321
+ <div class="modal-actions">
1322
+ <button type="button" class="modal-btn secondary" id="modal-cancel-btn">Cancel</button>
1323
+ <button type="button" class="modal-btn primary" id="modal-save-btn">Save</button>
1324
+ </div>
1325
+ </div>
1326
+ </div>
1327
+
1328
+ <div id="iframe-view" hidden>
1329
+ <div class="iframe-toolbar">
1330
+ <button class="icon-btn" onclick="window._launcher.closeIframe()" title="Close">&#x2715;</button>
1331
+ <span class="iframe-title" id="iframe-title"></span>
1332
+ <button class="icon-btn" onclick="window._launcher.openExternal()" title="Open in new tab">&#x2197;</button>
1333
+ </div>
1334
+ <iframe id="app-iframe" sandbox="allow-scripts allow-forms allow-popups"></iframe>
1335
+ </div>
1336
+
1337
+ <div id="context-menu" hidden>
1338
+ <button data-action="edit">&#x270F;&#xFE0F; Edit</button>
1339
+ <button data-action="favorite">&#x2B50; Toggle favorite</button>
1340
+ <button data-action="toggle-mode">&#x1F504; Switch open mode</button>
1341
+ <button data-action="view-source">&#x1F441; View / Edit Source</button>
1342
+ <button data-action="improve-ai">&#x2728; Improve with AI</button>
1343
+ <button data-action="share-prompt">&#x1F4E4; Share as Prompt</button>
1344
+ <hr>
1345
+ <button data-action="publish">&#x1F680; Publish to server</button>
1346
+ <hr>
1347
+ <button data-action="delete" class="danger">&#x1F5D1;&#xFE0F; Delete</button>
1348
+ </div>
1349
+
1350
+ <!-- Settings Modal -->
1351
+ <div id="settings-overlay" hidden>
1352
+ <div class="modal" id="settings-modal">
1353
+ <h2>Settings</h2>
1354
+
1355
+ <div class="settings-section">
1356
+ <div class="settings-section-title">Appearance</div>
1357
+ <div class="settings-row">
1358
+ <label for="setting-theme">Theme</label>
1359
+ <select id="setting-theme" class="modal-input">
1360
+ <option value="dark">Dark</option>
1361
+ <option value="light">Light</option>
1362
+ </select>
1363
+ </div>
1364
+ </div>
1365
+
1366
+ <div class="settings-section">
1367
+ <div class="settings-section-title">Defaults</div>
1368
+ <div class="settings-row">
1369
+ <label for="setting-open-mode">Default open mode</label>
1370
+ <select id="setting-open-mode" class="modal-input">
1371
+ <option value="tab">New Tab</option>
1372
+ <option value="iframe">Inline (iframe)</option>
1373
+ </select>
1374
+ </div>
1375
+ </div>
1376
+
1377
+ <div class="settings-section">
1378
+ <div class="settings-section-title">AIMEAT Server</div>
1379
+ <div class="settings-row">
1380
+ <label for="setting-aimeat-url">Server URL</label>
1381
+ <input type="url" id="setting-aimeat-url" class="modal-input" placeholder="http://localhost:40050" autocomplete="off"/>
1382
+ </div>
1383
+ </div>
1384
+
1385
+ <div class="settings-section">
1386
+ <div class="settings-section-title">Backup &amp; Restore</div>
1387
+ <div class="settings-backup-actions">
1388
+ <button type="button" class="modal-btn secondary" onclick="window._launcher.exportBackup()">Export JSON</button>
1389
+ <button type="button" class="modal-btn secondary" onclick="document.getElementById('import-file-input').click()">Import JSON</button>
1390
+ <input type="file" id="import-file-input" accept=".json" hidden/>
1391
+ </div>
1392
+ </div>
1393
+
1394
+ <div class="settings-section" style="margin-bottom:0">
1395
+ <div class="settings-section-title">Danger Zone</div>
1396
+ <button type="button" class="modal-btn danger" onclick="window._launcher.clearAllData()">Clear All Data</button>
1397
+ </div>
1398
+
1399
+ <div class="modal-actions" style="margin-top:24px">
1400
+ <button type="button" class="modal-btn secondary" id="settings-cancel-btn">Cancel</button>
1401
+ <button type="button" class="modal-btn primary" id="settings-save-btn">Save</button>
1402
+ </div>
1403
+ </div>
1404
+ </div>
1405
+
1406
+ <!-- View Source Modal -->
1407
+ <div id="source-overlay" hidden>
1408
+ <div class="modal source-modal">
1409
+ <h2 id="source-title">View Source</h2>
1410
+ <textarea id="source-code"></textarea>
1411
+ <div class="modal-actions">
1412
+ <button class="modal-btn secondary" id="copy-source-btn">Copy Source</button>
1413
+ <button class="modal-btn primary" id="copy-prompt-btn">Copy with AI Prompt</button>
1414
+ <button class="modal-btn primary" id="save-source-btn" disabled>Save Changes</button>
1415
+ <button class="modal-btn secondary" id="close-source-btn">Close</button>
1416
+ </div>
1417
+ </div>
1418
+ </div>
1419
+
1420
+ <!-- AIMEAT Import Dialog (dynamically populated) -->
1421
+ <div id="aimeat-import-overlay" hidden>
1422
+ <div class="modal" id="aimeat-import-modal">
1423
+ <h2>Import from AIMEAT</h2>
1424
+ <div class="aimeat-app-list" id="aimeat-app-list"></div>
1425
+ <div class="modal-actions">
1426
+ <button type="button" class="modal-btn secondary" onclick="document.getElementById('aimeat-import-overlay').hidden = true">Cancel</button>
1427
+ <button type="button" class="modal-btn primary" onclick="window._launcher.processAimeatImport()">Import Selected</button>
1428
+ </div>
1429
+ </div>
1430
+ </div>
1431
+
1432
+ <!-- Publish Modal -->
1433
+ <div id="publish-overlay" hidden>
1434
+ <div class="modal" id="publish-modal">
1435
+ <h2>&#x1F680; Publish App</h2>
1436
+ <div class="form-group">
1437
+ <label for="publish-filename">Filename</label>
1438
+ <input type="text" id="publish-filename" class="modal-input" placeholder="my-app.html" autocomplete="off"/>
1439
+ <div style="font-size:.75rem;color:var(--text-muted);margin-top:4px">Letters, numbers, dots, hyphens, underscores. Must end in .html</div>
1440
+ </div>
1441
+ <div class="form-group">
1442
+ <label for="publish-access-code">Access Code (optional)</label>
1443
+ <input type="text" id="publish-access-code" class="modal-input" placeholder="Leave empty for public" autocomplete="off"/>
1444
+ <div style="font-size:.75rem;color:var(--text-muted);margin-top:4px">4-64 chars. If set, only people with the code can download.</div>
1445
+ </div>
1446
+ <div id="publish-status" style="margin-top:8px;font-size:.85rem"></div>
1447
+ <div class="modal-actions">
1448
+ <button type="button" class="modal-btn secondary" onclick="document.getElementById('publish-overlay').hidden = true">Cancel</button>
1449
+ <button type="button" class="modal-btn primary" id="publish-submit-btn" onclick="window._launcher.submitPublish()">Publish</button>
1450
+ </div>
1451
+ </div>
1452
+ </div>
1453
+
1454
+ <!-- Prompt Builder Panel -->
1455
+ <div id="prompt-builder-overlay">
1456
+ <div class="prompt-builder-modal">
1457
+ <h2 id="pb-title">&#x2728; Generate App Prompt</h2>
1458
+ <div class="pb-mode-row">
1459
+ <label class="pb-mode-radio"><input type="radio" name="pb-mode" value="new" checked> New App</label>
1460
+ <label class="pb-mode-radio"><input type="radio" name="pb-mode" value="improve"> Improve This App</label>
1461
+ </div>
1462
+ <textarea class="pb-desc-area" id="pb-description" placeholder="Describe what the app should do, or what changes to make..."></textarea>
1463
+ <label class="pb-ext-toggle"><input type="checkbox" id="pb-ext-checkbox"> Include Cortex Extensions</label>
1464
+ <div class="pb-ext-list" id="pb-ext-list"></div>
1465
+ <div class="pb-preview-label">Live Preview</div>
1466
+ <div class="pb-preview" id="pb-preview"></div>
1467
+ <div class="modal-actions">
1468
+ <button class="modal-btn secondary" id="pb-cancel-btn">Cancel</button>
1469
+ <button class="modal-btn primary" id="pb-copy-btn">Copy Prompt</button>
1470
+ </div>
1471
+ </div>
1472
+ </div>
1473
+
1474
+ <!-- Published Apps Section (inserted before grid, toggled) -->
1475
+
1476
+ <script>
1477
+ (function () {
1478
+ 'use strict';
1479
+
1480
+ // ── IndexedDB wrapper ──────────────────────────────
1481
+
1482
+ const DB_NAME = 'AppLauncherDB';
1483
+ const DB_VERSION = 2;
1484
+ const STORE_NAME = 'apps';
1485
+
1486
+ let dbInstance = null;
1487
+
1488
+ function openDB() {
1489
+ if (dbInstance) return Promise.resolve(dbInstance);
1490
+ return new Promise(function (resolve, reject) {
1491
+ const request = indexedDB.open(DB_NAME, DB_VERSION);
1492
+
1493
+ request.onupgradeneeded = function (event) {
1494
+ const db = event.target.result;
1495
+ var store;
1496
+ if (!db.objectStoreNames.contains(STORE_NAME)) {
1497
+ store = db.createObjectStore(STORE_NAME, { keyPath: 'id' });
1498
+ store.createIndex('tags', 'tags', { multiEntry: true });
1499
+ store.createIndex('source', 'source', { unique: false });
1500
+ store.createIndex('favorite', 'favorite', { unique: false });
1501
+ store.createIndex('sortOrder', 'sortOrder', { unique: false });
1502
+ } else {
1503
+ store = event.target.transaction.objectStore(STORE_NAME);
1504
+ if (!store.indexNames.contains('sortOrder')) {
1505
+ store.createIndex('sortOrder', 'sortOrder', { unique: false });
1506
+ }
1507
+ }
1508
+ };
1509
+
1510
+ request.onsuccess = function (event) {
1511
+ dbInstance = event.target.result;
1512
+ resolve(dbInstance);
1513
+ };
1514
+
1515
+ request.onerror = function (event) {
1516
+ reject(event.target.error);
1517
+ };
1518
+ });
1519
+ }
1520
+
1521
+ function getAllApps() {
1522
+ return openDB().then(function (db) {
1523
+ return new Promise(function (resolve, reject) {
1524
+ const tx = db.transaction(STORE_NAME, 'readonly');
1525
+ const store = tx.objectStore(STORE_NAME);
1526
+ const request = store.getAll();
1527
+
1528
+ request.onsuccess = function () {
1529
+ resolve(request.result);
1530
+ };
1531
+ request.onerror = function () {
1532
+ reject(request.error);
1533
+ };
1534
+ });
1535
+ });
1536
+ }
1537
+
1538
+ function saveApp(app) {
1539
+ return openDB().then(function (db) {
1540
+ return new Promise(function (resolve, reject) {
1541
+ const tx = db.transaction(STORE_NAME, 'readwrite');
1542
+ tx.objectStore(STORE_NAME).put(app);
1543
+ tx.oncomplete = function () { resolve(); };
1544
+ tx.onerror = function () { reject(tx.error); };
1545
+ tx.onabort = function () { reject(tx.error); };
1546
+ });
1547
+ });
1548
+ }
1549
+
1550
+ function deleteApp(id) {
1551
+ return openDB().then(function (db) {
1552
+ return new Promise(function (resolve, reject) {
1553
+ const tx = db.transaction(STORE_NAME, 'readwrite');
1554
+ tx.objectStore(STORE_NAME).delete(id);
1555
+ tx.oncomplete = function () { resolve(); };
1556
+ tx.onerror = function () { reject(tx.error); };
1557
+ tx.onabort = function () { reject(tx.error); };
1558
+ });
1559
+ });
1560
+ }
1561
+
1562
+ // ── Config (localStorage) ─────────────────────────
1563
+
1564
+ const DEFAULT_CONFIG = {
1565
+ theme: 'light',
1566
+ defaultOpenMode: 'tab',
1567
+ aimeatUrl: '',
1568
+ language: 'en'
1569
+ };
1570
+
1571
+ function loadConfig() {
1572
+ try {
1573
+ return Object.assign({}, DEFAULT_CONFIG, JSON.parse(localStorage.getItem('appLauncherConfig') || '{}'));
1574
+ } catch (e) {
1575
+ return Object.assign({}, DEFAULT_CONFIG);
1576
+ }
1577
+ }
1578
+
1579
+ function saveConfig(config) {
1580
+ localStorage.setItem('appLauncherConfig', JSON.stringify(config));
1581
+ }
1582
+
1583
+ // ── ID Generator ─────────────────────────────────
1584
+
1585
+ function generateId() {
1586
+ if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
1587
+ return crypto.randomUUID();
1588
+ }
1589
+ // Fallback for older browsers
1590
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
1591
+ var r = Math.random() * 16 | 0;
1592
+ var v = c === 'x' ? r : (r & 0x3 | 0x8);
1593
+ return v.toString(16);
1594
+ });
1595
+ }
1596
+
1597
+ // ── File Reading Helper ─────────────────────────
1598
+
1599
+ function readFileAsText(file) {
1600
+ return new Promise(function (resolve, reject) {
1601
+ var reader = new FileReader();
1602
+ reader.onload = function () {
1603
+ resolve(reader.result);
1604
+ };
1605
+ reader.onerror = function () {
1606
+ reject(reader.error);
1607
+ };
1608
+ reader.readAsText(file);
1609
+ });
1610
+ }
1611
+
1612
+ // ── ZIP Helpers ────────────────────────────────
1613
+
1614
+ function mimeFromExtension(name) {
1615
+ var ext = (name.split('.').pop() || '').toLowerCase();
1616
+ var map = {
1617
+ html: 'text/html', htm: 'text/html',
1618
+ css: 'text/css',
1619
+ js: 'application/javascript', mjs: 'application/javascript',
1620
+ json: 'application/json',
1621
+ svg: 'image/svg+xml',
1622
+ png: 'image/png',
1623
+ jpg: 'image/jpeg', jpeg: 'image/jpeg',
1624
+ gif: 'image/gif',
1625
+ webp: 'image/webp',
1626
+ ico: 'image/x-icon',
1627
+ woff: 'font/woff', woff2: 'font/woff2',
1628
+ ttf: 'font/ttf', otf: 'font/otf',
1629
+ eot: 'application/vnd.ms-fontobject',
1630
+ mp3: 'audio/mpeg', ogg: 'audio/ogg', wav: 'audio/wav',
1631
+ mp4: 'video/mp4', webm: 'video/webm',
1632
+ xml: 'application/xml',
1633
+ txt: 'text/plain',
1634
+ pdf: 'application/pdf'
1635
+ };
1636
+ return map[ext] || 'application/octet-stream';
1637
+ }
1638
+
1639
+ function toBase64(uint8arr) {
1640
+ var binary = '';
1641
+ for (var i = 0; i < uint8arr.length; i++) {
1642
+ binary += String.fromCharCode(uint8arr[i]);
1643
+ }
1644
+ return btoa(binary);
1645
+ }
1646
+
1647
+ // ── Minimal ZIP Parser ────────────────────────────
1648
+
1649
+ async function extractZip(arrayBuffer) {
1650
+ var view = new DataView(arrayBuffer);
1651
+ var files = [];
1652
+ var offset = 0;
1653
+
1654
+ while (offset < view.byteLength - 4) {
1655
+ var sig = view.getUint32(offset, true);
1656
+ if (sig !== 0x04034b50) break; // Not a local file header
1657
+
1658
+ var compressionMethod = view.getUint16(offset + 8, true);
1659
+ var compressedSize = view.getUint32(offset + 18, true);
1660
+ var nameLen = view.getUint16(offset + 26, true);
1661
+ var extraLen = view.getUint16(offset + 28, true);
1662
+ var name = new TextDecoder().decode(new Uint8Array(arrayBuffer, offset + 30, nameLen));
1663
+ var dataStart = offset + 30 + nameLen + extraLen;
1664
+ var rawData = new Uint8Array(arrayBuffer, dataStart, compressedSize);
1665
+
1666
+ var data;
1667
+ if (compressionMethod === 0) {
1668
+ data = rawData; // Stored (no compression)
1669
+ } else if (compressionMethod === 8) {
1670
+ // Deflate — use browser's DecompressionStream
1671
+ var ds = new DecompressionStream('raw');
1672
+ var writer = ds.writable.getWriter();
1673
+ writer.write(rawData);
1674
+ writer.close();
1675
+ var reader = ds.readable.getReader();
1676
+ var chunks = [];
1677
+ while (true) {
1678
+ var result = await reader.read();
1679
+ if (result.done) break;
1680
+ chunks.push(result.value);
1681
+ }
1682
+ var totalLen = chunks.reduce(function (s, c) { return s + c.length; }, 0);
1683
+ data = new Uint8Array(totalLen);
1684
+ var pos = 0;
1685
+ for (var ci = 0; ci < chunks.length; ci++) {
1686
+ data.set(chunks[ci], pos);
1687
+ pos += chunks[ci].length;
1688
+ }
1689
+ } else {
1690
+ throw new Error('Unsupported compression method: ' + compressionMethod);
1691
+ }
1692
+
1693
+ if (!name.endsWith('/')) { // Skip directories
1694
+ files.push({ name: name, data: data });
1695
+ }
1696
+ offset = dataStart + compressedSize;
1697
+ }
1698
+
1699
+ return files;
1700
+ }
1701
+
1702
+ // ── ZIP Inline Bundler ────────────────────────────
1703
+
1704
+ async function bundleZip(files) {
1705
+ // 1. Find index.html or any .html file as the base
1706
+ var htmlFile = null;
1707
+ for (var i = 0; i < files.length; i++) {
1708
+ var lowerName = files[i].name.toLowerCase();
1709
+ if (lowerName === 'index.html' || lowerName.endsWith('/index.html')) {
1710
+ htmlFile = files[i];
1711
+ break;
1712
+ }
1713
+ }
1714
+ if (!htmlFile) {
1715
+ for (var i = 0; i < files.length; i++) {
1716
+ if (files[i].name.toLowerCase().match(/\.html?$/)) {
1717
+ htmlFile = files[i];
1718
+ break;
1719
+ }
1720
+ }
1721
+ }
1722
+ if (!htmlFile) {
1723
+ throw new Error('No HTML file found in ZIP');
1724
+ }
1725
+
1726
+ // 2. Determine the base path (directory containing the HTML file)
1727
+ var lastSlash = htmlFile.name.lastIndexOf('/');
1728
+ var basePath = lastSlash >= 0 ? htmlFile.name.substring(0, lastSlash + 1) : '';
1729
+
1730
+ // 3. Build a map of relative file paths to file data
1731
+ var fileMap = {};
1732
+ for (var i = 0; i < files.length; i++) {
1733
+ var fname = files[i].name;
1734
+ // Store path relative to base
1735
+ if (basePath && fname.startsWith(basePath)) {
1736
+ fileMap[fname.substring(basePath.length)] = files[i].data;
1737
+ }
1738
+ // Also store the full path for lookup
1739
+ fileMap[fname] = files[i].data;
1740
+ }
1741
+
1742
+ // Helper: resolve a reference relative to the HTML file's directory
1743
+ function resolveRef(ref) {
1744
+ // Strip leading ./
1745
+ var cleaned = ref.replace(/^\.\//, '');
1746
+ // Try direct lookup
1747
+ if (fileMap[cleaned]) return fileMap[cleaned];
1748
+ // Try with basePath prepended
1749
+ if (fileMap[basePath + cleaned]) return fileMap[basePath + cleaned];
1750
+ return null;
1751
+ }
1752
+
1753
+ // Helper: get file content as text
1754
+ function fileAsText(data) {
1755
+ return new TextDecoder().decode(data);
1756
+ }
1757
+
1758
+ // Helper: get file content as data URL
1759
+ function fileAsDataUrl(ref, data) {
1760
+ var mime = mimeFromExtension(ref);
1761
+ return 'data:' + mime + ';base64,' + toBase64(data);
1762
+ }
1763
+
1764
+ var html = fileAsText(htmlFile.data);
1765
+
1766
+ // 4. Replace <link rel="stylesheet" href="..."> with inline <style>
1767
+ html = html.replace(/<link\s+[^>]*rel\s*=\s*["']stylesheet["'][^>]*>/gi, function (tag) {
1768
+ var hrefMatch = tag.match(/href\s*=\s*["']([^"']+)["']/i);
1769
+ if (!hrefMatch) return tag;
1770
+ var href = hrefMatch[1];
1771
+ var fileData = resolveRef(href);
1772
+ if (!fileData) return tag; // keep original if file not found
1773
+ var cssContent = fileAsText(fileData);
1774
+ // Inline CSS url() references within the stylesheet
1775
+ cssContent = inlineCssUrls(cssContent);
1776
+ return '<style>/* ' + href + ' */\n' + cssContent + '</style>';
1777
+ });
1778
+
1779
+ // 5. Replace script-src tags with inline script blocks
1780
+ html = html.replace(/<script\s+[^>]*src\s*=\s*["']([^"']+)["'][^>]*>\s*<\/script>/gi, function (tag, src) {
1781
+ var fileData = resolveRef(src);
1782
+ if (!fileData) return tag; // keep original if file not found
1783
+ return '<script>/* ' + src + ' */\n' + fileAsText(fileData) + '<\/script>';
1784
+ });
1785
+
1786
+ // 6. Replace src="..." and href="..." pointing to binary assets with data URLs
1787
+ html = html.replace(/(src|href)\s*=\s*["']([^"']+)["']/gi, function (match, attr, ref) {
1788
+ // Skip data: URLs, http(s) URLs, # anchors, and javascript:
1789
+ if (ref.match(/^(data:|https?:|#|javascript:|mailto:)/i)) return match;
1790
+ // Skip already-inlined stylesheets and scripts (they won't match since already replaced)
1791
+ var fileData = resolveRef(ref);
1792
+ if (!fileData) return match;
1793
+ var mime = mimeFromExtension(ref);
1794
+ // Only inline binary/image/font assets, not html/css/js (already handled above)
1795
+ if (mime.match(/^(image|font|audio|video)\//)) {
1796
+ return attr + '="' + fileAsDataUrl(ref, fileData) + '"';
1797
+ }
1798
+ return match;
1799
+ });
1800
+
1801
+ // 7. Replace CSS url(...) references in inline <style> blocks
1802
+ html = html.replace(/<style[^>]*>([\s\S]*?)<\/style>/gi, function (tag, cssContent) {
1803
+ var inlined = inlineCssUrls(cssContent);
1804
+ if (inlined !== cssContent) {
1805
+ return tag.replace(cssContent, inlined);
1806
+ }
1807
+ return tag;
1808
+ });
1809
+
1810
+ function inlineCssUrls(css) {
1811
+ return css.replace(/url\(\s*["']?([^"')]+)["']?\s*\)/gi, function (match, ref) {
1812
+ if (ref.match(/^(data:|https?:|#)/i)) return match;
1813
+ var fileData = resolveRef(ref);
1814
+ if (!fileData) return match;
1815
+ return 'url("' + fileAsDataUrl(ref, fileData) + '")';
1816
+ });
1817
+ }
1818
+
1819
+ return html;
1820
+ }
1821
+
1822
+ // ── App Creation from ZIP ─────────────────────────
1823
+
1824
+ async function addAppFromZip(name, arrayBuffer, icon, tags, openMode) {
1825
+ var files = await extractZip(arrayBuffer);
1826
+ var bundledHtml = await bundleZip(files);
1827
+ var encoded = btoa(unescape(encodeURIComponent(bundledHtml)));
1828
+ var app = {
1829
+ id: generateId(),
1830
+ name: name,
1831
+ description: '',
1832
+ source: 'zip',
1833
+ url: null,
1834
+ blob: encoded,
1835
+ tags: tags,
1836
+ openMode: openMode,
1837
+ icon: icon || '\u{1F4E6}',
1838
+ screenshot: null,
1839
+ favorite: false,
1840
+ addedAt: new Date().toISOString(),
1841
+ lastOpenedAt: null
1842
+ };
1843
+ await saveApp(app);
1844
+ return app;
1845
+ }
1846
+
1847
+ // ── App Creation from URL ───────────────────────
1848
+
1849
+ function addAppFromUrl(name, url, icon, tags, openMode) {
1850
+ var app = {
1851
+ id: generateId(),
1852
+ name: name,
1853
+ description: '',
1854
+ source: 'url',
1855
+ url: url,
1856
+ blob: null,
1857
+ tags: tags,
1858
+ openMode: openMode,
1859
+ icon: icon || '\u{1F4DD}',
1860
+ screenshot: null,
1861
+ favorite: false,
1862
+ addedAt: new Date().toISOString(),
1863
+ lastOpenedAt: null
1864
+ };
1865
+ return saveApp(app).then(function () {
1866
+ return app;
1867
+ });
1868
+ }
1869
+
1870
+ // ── App Creation from File ──────────────────────
1871
+
1872
+ function addAppFromFile(name, file, icon, tags, openMode) {
1873
+ return readFileAsText(file).then(function (content) {
1874
+ var encoded = btoa(unescape(encodeURIComponent(content)));
1875
+ var app = {
1876
+ id: generateId(),
1877
+ name: name,
1878
+ description: '',
1879
+ source: 'local',
1880
+ url: null,
1881
+ blob: encoded,
1882
+ tags: tags,
1883
+ openMode: openMode,
1884
+ icon: icon || '\u{1F4DD}',
1885
+ screenshot: null,
1886
+ favorite: false,
1887
+ addedAt: new Date().toISOString(),
1888
+ lastOpenedAt: null
1889
+ };
1890
+ return saveApp(app).then(function () {
1891
+ return app;
1892
+ });
1893
+ });
1894
+ }
1895
+
1896
+ // ── App Creation from Pasted Source ─────────────
1897
+
1898
+ function addAppFromSource(name, sourceCode, icon, tags, openMode) {
1899
+ var encoded = btoa(unescape(encodeURIComponent(sourceCode)));
1900
+ var app = {
1901
+ id: generateId(),
1902
+ name: name,
1903
+ description: '',
1904
+ source: 'local',
1905
+ url: null,
1906
+ blob: encoded,
1907
+ tags: tags,
1908
+ openMode: openMode,
1909
+ icon: icon || '\u{1F4DD}',
1910
+ screenshot: null,
1911
+ favorite: false,
1912
+ addedAt: new Date().toISOString(),
1913
+ lastOpenedAt: null
1914
+ };
1915
+ return saveApp(app).then(function () {
1916
+ return app;
1917
+ });
1918
+ }
1919
+
1920
+ // ── Modal State ─────────────────────────────────
1921
+
1922
+ var selectedFile = null;
1923
+ var editingAppId = null;
1924
+
1925
+ function showModal() {
1926
+ document.getElementById('modal-overlay').hidden = false;
1927
+ document.getElementById('modal-title').textContent = 'Add App';
1928
+ // Default to URL tab
1929
+ switchTab('url');
1930
+ }
1931
+
1932
+ function closeModal() {
1933
+ document.getElementById('modal-overlay').hidden = true;
1934
+ // Reset form
1935
+ document.getElementById('app-url').value = '';
1936
+ document.getElementById('app-name').value = '';
1937
+ document.getElementById('app-icon').value = '';
1938
+ document.getElementById('app-tags').value = '';
1939
+ document.getElementById('app-open-mode').value = 'tab';
1940
+ document.getElementById('selected-file-name').textContent = '';
1941
+ document.getElementById('file-input').value = '';
1942
+ document.getElementById('app-paste-code').value = '';
1943
+ selectedFile = null;
1944
+ editingAppId = null;
1945
+ }
1946
+
1947
+ function switchTab(tabName) {
1948
+ // Toggle tab buttons
1949
+ var tabs = document.querySelectorAll('.modal-tab');
1950
+ tabs.forEach(function (tab) {
1951
+ if (tab.getAttribute('data-tab') === tabName) {
1952
+ tab.classList.add('active');
1953
+ } else {
1954
+ tab.classList.remove('active');
1955
+ }
1956
+ });
1957
+ // Toggle tab content
1958
+ var contents = document.querySelectorAll('.tab-content');
1959
+ contents.forEach(function (content) {
1960
+ if (content.id === 'tab-' + tabName) {
1961
+ content.classList.add('active');
1962
+ } else {
1963
+ content.classList.remove('active');
1964
+ }
1965
+ });
1966
+ }
1967
+
1968
+ function handleFileDrop(file) {
1969
+ if (!file) return;
1970
+ if (file.name.toLowerCase().endsWith('.zip')) {
1971
+ selectedFile = file;
1972
+ document.getElementById('selected-file-name').textContent = file.name;
1973
+ var nameInput = document.getElementById('app-name');
1974
+ if (!nameInput.value.trim()) {
1975
+ nameInput.value = file.name.replace(/\.zip$/i, '');
1976
+ }
1977
+ return;
1978
+ }
1979
+ if (!file.name.match(/\.html?$/i)) {
1980
+ alert('Please select an HTML or ZIP file (.html, .htm, or .zip)');
1981
+ return;
1982
+ }
1983
+ selectedFile = file;
1984
+ document.getElementById('selected-file-name').textContent = file.name;
1985
+ // Auto-fill name from filename if empty
1986
+ var nameInput = document.getElementById('app-name');
1987
+ if (!nameInput.value.trim()) {
1988
+ nameInput.value = file.name.replace(/\.html?$/i, '');
1989
+ }
1990
+ }
1991
+
1992
+ function handleSave() {
1993
+ var name = document.getElementById('app-name').value.trim();
1994
+ var icon = document.getElementById('app-icon').value.trim();
1995
+ var tagsRaw = document.getElementById('app-tags').value.trim();
1996
+ var openMode = document.getElementById('app-open-mode').value;
1997
+
1998
+ var tags = tagsRaw ? tagsRaw.split(',').map(function (t) { return t.trim(); }).filter(Boolean) : [];
1999
+
2000
+ // ── Edit mode: update existing app ──
2001
+ if (editingAppId) {
2002
+ var app = null;
2003
+ for (var i = 0; i < allApps.length; i++) {
2004
+ if (allApps[i].id === editingAppId) { app = allApps[i]; break; }
2005
+ }
2006
+ if (!app) {
2007
+ closeModal();
2008
+ return;
2009
+ }
2010
+ if (!name) {
2011
+ alert('Please enter a name');
2012
+ return;
2013
+ }
2014
+ app.name = name;
2015
+ app.icon = icon || app.icon;
2016
+ app.tags = tags;
2017
+ app.openMode = openMode;
2018
+ saveApp(app).then(function () {
2019
+ closeModal();
2020
+ renderApps();
2021
+ });
2022
+ return;
2023
+ }
2024
+
2025
+ // ── Create mode ──
2026
+ var activeTab = document.querySelector('.modal-tab.active');
2027
+ var tabName = activeTab ? activeTab.getAttribute('data-tab') : 'url';
2028
+
2029
+ if (tabName === 'url') {
2030
+ var url = document.getElementById('app-url').value.trim();
2031
+ if (!url) {
2032
+ alert('Please enter a URL');
2033
+ return;
2034
+ }
2035
+ if (!name) {
2036
+ // Derive name from URL
2037
+ try {
2038
+ name = new URL(url).hostname;
2039
+ } catch (e) {
2040
+ name = url;
2041
+ }
2042
+ }
2043
+ addAppFromUrl(name, url, icon, tags, openMode).then(function () {
2044
+ closeModal();
2045
+ renderApps();
2046
+ });
2047
+ } else if (tabName === 'paste') {
2048
+ var pastedCode = document.getElementById('app-paste-code').value.trim();
2049
+ if (!pastedCode) {
2050
+ alert('Please paste your HTML source code');
2051
+ return;
2052
+ }
2053
+ if (!name) {
2054
+ // Try to extract title from HTML
2055
+ var titleMatch = pastedCode.match(/<title[^>]*>([^<]+)<\/title>/i);
2056
+ name = titleMatch ? titleMatch[1].trim() : 'Pasted App';
2057
+ }
2058
+ addAppFromSource(name, pastedCode, icon, tags, openMode).then(function () {
2059
+ closeModal();
2060
+ renderApps();
2061
+ });
2062
+ } else if (tabName === 'file') {
2063
+ if (!selectedFile) {
2064
+ alert('Please select a file');
2065
+ return;
2066
+ }
2067
+ if (selectedFile.name.toLowerCase().endsWith('.zip')) {
2068
+ // ZIP file — extract and bundle
2069
+ if (!name) {
2070
+ name = selectedFile.name.replace(/\.zip$/i, '');
2071
+ }
2072
+ selectedFile.arrayBuffer().then(function (arrayBuffer) {
2073
+ return addAppFromZip(name, arrayBuffer, icon, tags, openMode);
2074
+ }).then(function () {
2075
+ closeModal();
2076
+ renderApps();
2077
+ }).catch(function (err) {
2078
+ alert('ZIP import failed: ' + (err.message || err));
2079
+ });
2080
+ } else {
2081
+ // HTML file
2082
+ if (!name) {
2083
+ name = selectedFile.name.replace(/\.html?$/i, '');
2084
+ }
2085
+ addAppFromFile(name, selectedFile, icon, tags, openMode).then(function () {
2086
+ closeModal();
2087
+ renderApps();
2088
+ });
2089
+ }
2090
+ }
2091
+ }
2092
+
2093
+ // ── Module-level state ──────────────────────────────
2094
+
2095
+ var allApps = [];
2096
+ var activeTag = null;
2097
+ var searchQuery = '';
2098
+
2099
+ // ── Helpers ────────────────────────────────────────
2100
+
2101
+ function escapeHtml(str) {
2102
+ var div = document.createElement('div');
2103
+ div.textContent = str;
2104
+ return div.innerHTML;
2105
+ }
2106
+
2107
+ function sourceLabel(source) {
2108
+ switch (source) {
2109
+ case 'local': return '\u{1F4C4} local';
2110
+ case 'url': return '\u{1F310} url';
2111
+ case 'aimeat': return '\u{1F4E6} aimeat';
2112
+ case 'zip': return '\u{1F4E6} zip';
2113
+ default: return source || 'unknown';
2114
+ }
2115
+ }
2116
+
2117
+ // ── Tag Rendering ─────────────────────────────────
2118
+
2119
+ function renderTags() {
2120
+ var tagBar = document.getElementById('tag-bar');
2121
+ var tagSet = {};
2122
+ var hasFavorites = false;
2123
+
2124
+ for (var i = 0; i < allApps.length; i++) {
2125
+ var app = allApps[i];
2126
+ if (app.favorite) hasFavorites = true;
2127
+ if (app.tags && app.tags.length) {
2128
+ for (var j = 0; j < app.tags.length; j++) {
2129
+ tagSet[app.tags[j]] = true;
2130
+ }
2131
+ }
2132
+ }
2133
+
2134
+ var uniqueTags = Object.keys(tagSet).sort();
2135
+ var html = '';
2136
+
2137
+ // "All" button
2138
+ html += '<button class="tag' + (activeTag === null ? ' active' : '') + '" onclick="window._launcher.filterByTag(null)">All</button>';
2139
+
2140
+ // Favorites button (only if any favorites exist)
2141
+ if (hasFavorites) {
2142
+ html += '<button class="tag' + (activeTag === '__favorites__' ? ' active' : '') + '" onclick="window._launcher.filterByTag(\'__favorites__\')">\u2B50 Favorites</button>';
2143
+ }
2144
+
2145
+ // One button per unique tag
2146
+ for (var k = 0; k < uniqueTags.length; k++) {
2147
+ var tag = uniqueTags[k];
2148
+ html += '<button class="tag' + (activeTag === tag ? ' active' : '') + '" onclick="window._launcher.filterByTag(\'' + escapeHtml(tag.replace(/'/g, "\\'")) + '\')">' + escapeHtml(tag) + '</button>';
2149
+ }
2150
+
2151
+ tagBar.innerHTML = html;
2152
+ }
2153
+
2154
+ // ── Tag Filtering ─────────────────────────────────
2155
+
2156
+ function filterByTag(tag) {
2157
+ activeTag = tag;
2158
+ renderApps();
2159
+ }
2160
+
2161
+ // ── Launch App ──────────────────────────────────
2162
+
2163
+ function launchApp(id, mode) {
2164
+ var app = null;
2165
+ for (var i = 0; i < allApps.length; i++) {
2166
+ if (allApps[i].id === id) { app = allApps[i]; break; }
2167
+ }
2168
+ if (!app) return;
2169
+
2170
+ app.lastOpenedAt = new Date().toISOString();
2171
+ saveApp(app).then(function () {
2172
+ if (mode === 'tab') {
2173
+ launchInTab(app);
2174
+ } else if (mode === 'iframe') {
2175
+ launchInIframe(app);
2176
+ }
2177
+ });
2178
+ }
2179
+
2180
+ function launchInTab(app) {
2181
+ if (app.source === 'url' && app.url) {
2182
+ window.open(app.url, '_blank', 'noopener');
2183
+ } else if (app.blob) {
2184
+ // Use blob URL instead of document.write to maintain browser sandbox
2185
+ var html = decodeURIComponent(escape(atob(app.blob)));
2186
+ var blob = new Blob([html], { type: 'text/html' });
2187
+ var blobUrl = URL.createObjectURL(blob);
2188
+ window.open(blobUrl, '_blank', 'noopener');
2189
+ // Revoke after a short delay to allow the tab to load
2190
+ setTimeout(function () { URL.revokeObjectURL(blobUrl); }, 5000);
2191
+ }
2192
+ }
2193
+
2194
+ function launchInIframe(app) {
2195
+ var view = document.getElementById('iframe-view');
2196
+ var iframe = document.getElementById('app-iframe');
2197
+ var title = document.getElementById('iframe-title');
2198
+
2199
+ title.textContent = app.name || 'App';
2200
+ iframe.dataset.appId = app.id;
2201
+
2202
+ if (app.source === 'url' && app.url) {
2203
+ iframe.removeAttribute('srcdoc');
2204
+ iframe.src = app.url;
2205
+ currentIframeUrl = app.url;
2206
+ } else if (app.blob) {
2207
+ var html = decodeURIComponent(escape(atob(app.blob)));
2208
+ iframe.removeAttribute('src');
2209
+ iframe.srcdoc = html;
2210
+ currentIframeUrl = '';
2211
+ }
2212
+
2213
+ view.hidden = false;
2214
+ }
2215
+
2216
+ // ── Rendering ─────────────────────────────────────
2217
+
2218
+ function renderApps() {
2219
+ getAllApps().then(function (apps) {
2220
+ allApps = apps;
2221
+
2222
+ // Sort: favorites first, then by sortOrder (if set), then by date
2223
+ allApps.sort(function (a, b) {
2224
+ // Favorites first
2225
+ if (a.favorite && !b.favorite) return -1;
2226
+ if (!a.favorite && b.favorite) return 1;
2227
+ // Then by explicit sortOrder if present
2228
+ var oA = typeof a.sortOrder === 'number' ? a.sortOrder : Infinity;
2229
+ var oB = typeof b.sortOrder === 'number' ? b.sortOrder : Infinity;
2230
+ if (oA !== oB) return oA - oB;
2231
+ // Then by most recently used/added
2232
+ var dateA = a.lastOpenedAt || a.addedAt || '';
2233
+ var dateB = b.lastOpenedAt || b.addedAt || '';
2234
+ if (dateA > dateB) return -1;
2235
+ if (dateA < dateB) return 1;
2236
+ return 0;
2237
+ });
2238
+
2239
+ // Filter by activeTag
2240
+ var filtered = allApps;
2241
+ if (activeTag === '__favorites__') {
2242
+ filtered = allApps.filter(function (app) { return app.favorite; });
2243
+ } else if (activeTag !== null) {
2244
+ filtered = allApps.filter(function (app) {
2245
+ return app.tags && app.tags.indexOf(activeTag) !== -1;
2246
+ });
2247
+ }
2248
+
2249
+ // Filter by searchQuery
2250
+ if (searchQuery) {
2251
+ var q = searchQuery.toLowerCase();
2252
+ filtered = filtered.filter(function (app) {
2253
+ if (app.name && app.name.toLowerCase().indexOf(q) !== -1) return true;
2254
+ if (app.tags) {
2255
+ for (var i = 0; i < app.tags.length; i++) {
2256
+ if (app.tags[i].toLowerCase().indexOf(q) !== -1) return true;
2257
+ }
2258
+ }
2259
+ return false;
2260
+ });
2261
+ }
2262
+
2263
+ var grid = document.getElementById('app-grid');
2264
+
2265
+ if (filtered.length === 0) {
2266
+ if (!activeTag && !searchQuery && allApps.length === 0) {
2267
+ // No apps at all — show helpful empty state
2268
+ grid.innerHTML =
2269
+ '<div class="empty-state">' +
2270
+ '<div class="empty-icon">\u{1F680}</div>' +
2271
+ '<h3>No apps yet</h3>' +
2272
+ '<p>Add your first app using the <strong>+</strong> button above</p>' +
2273
+ '<span class="empty-formats">Supports: HTML files, URLs, ZIP packages, AIMEAT imports</span>' +
2274
+ '</div>';
2275
+ } else {
2276
+ // Filters active but no matches
2277
+ grid.innerHTML =
2278
+ '<div class="empty-state">' +
2279
+ '<div class="empty-icon">\u{1F50D}</div>' +
2280
+ '<h3>No matches</h3>' +
2281
+ '<p>No apps match the current filter. Try a different search term or tag.</p>' +
2282
+ '</div>';
2283
+ }
2284
+ } else {
2285
+ var html = '';
2286
+ for (var i = 0; i < filtered.length; i++) {
2287
+ var app = filtered[i];
2288
+ var iconDisplay = app.icon || '\u{1F4DD}';
2289
+ html +=
2290
+ '<div class="app-card" draggable="true" data-id="' + escapeHtml(app.id) + '" onclick="window._launcher.launchApp(\'' + escapeHtml(app.id) + '\', \'' + escapeHtml(app.openMode || 'tab') + '\')" oncontextmenu="window._launcher.showContextMenu(event, \'' + escapeHtml(app.id) + '\')" ondragstart="window._launcher.onCardDragStart(event)" ondragend="window._launcher.onCardDragEnd(event)" ondragover="window._launcher.onCardDragOver(event)" ondrop="window._launcher.onCardDrop(event)" style="animation-delay:' + (i * 0.04) + 's">' +
2291
+ '<button class="card-menu-btn" onclick="event.stopPropagation(); window._launcher.showContextMenu(event, \'' + escapeHtml(app.id) + '\')" title="Menu">\u22EE</button>' +
2292
+ '<div class="app-icon">' + escapeHtml(iconDisplay) + '</div>' +
2293
+ '<div class="app-name">' + escapeHtml(app.name) + '</div>' +
2294
+ '<div class="app-source">' + sourceLabel(app.source) + '</div>' +
2295
+ '<div class="app-actions">' +
2296
+ '<button onclick="event.stopPropagation(); window._launcher.launchApp(\'' + escapeHtml(app.id) + '\', \'tab\')" title="Open in tab">\u25B6 Tab</button>' +
2297
+ '<button onclick="event.stopPropagation(); window._launcher.launchApp(\'' + escapeHtml(app.id) + '\', \'iframe\')" title="Open in iframe">\u25FB</button>' +
2298
+ '</div>' +
2299
+ (app.favorite ? '<span class="fav-star visible">\u2B50</span>' : '') +
2300
+ '</div>';
2301
+ }
2302
+ grid.innerHTML = html;
2303
+ }
2304
+
2305
+ // Update stats
2306
+ var statsEl = document.getElementById('stats');
2307
+ var totalSize = 0;
2308
+ for (var s = 0; s < allApps.length; s++) {
2309
+ if (allApps[s].blob) {
2310
+ totalSize += allApps[s].blob.length;
2311
+ }
2312
+ }
2313
+ var sizeLabel = totalSize < 1024 ? totalSize + ' B'
2314
+ : totalSize < 1048576 ? (totalSize / 1024).toFixed(1) + ' KB'
2315
+ : (totalSize / 1048576).toFixed(1) + ' MB';
2316
+ statsEl.textContent = allApps.length + ' app' + (allApps.length !== 1 ? 's' : '') + ' \u00B7 ' + sizeLabel + ' stored';
2317
+
2318
+ // Render tag bar
2319
+ renderTags();
2320
+
2321
+ // Render recently opened strip
2322
+ renderRecentlyOpened();
2323
+ });
2324
+ }
2325
+
2326
+ function renderRecentlyOpened() {
2327
+ var section = document.getElementById('recent-section');
2328
+ var strip = document.getElementById('recent-strip');
2329
+ var recent = allApps
2330
+ .filter(function(a) { return a.lastOpenedAt; })
2331
+ .sort(function(a, b) { return (b.lastOpenedAt || '') > (a.lastOpenedAt || '') ? 1 : -1; })
2332
+ .slice(0, 5);
2333
+ if (recent.length === 0) { section.style.display = 'none'; return; }
2334
+ section.style.display = 'block';
2335
+ strip.innerHTML = recent.map(function(app) {
2336
+ var icon = app.icon || '\u{1F4DD}';
2337
+ return '<div style="background:var(--surface-glass);border:1px solid var(--border-subtle);border-radius:10px;padding:.6rem .8rem;cursor:pointer;min-width:120px;flex-shrink:0;transition:all .15s" onclick="window._launcher.launchApp(\'' + escapeHtml(app.id) + '\', \'' + escapeHtml(app.openMode || 'tab') + '\')" onmouseover="this.style.borderColor=\'#D1D5DB\'" onmouseout="this.style.borderColor=\'#E5E7EB\'">' +
2338
+ '<div style="font-size:1.3rem;text-align:center">' + escapeHtml(icon) + '</div>' +
2339
+ '<div style="font-size:.75rem;font-weight:600;text-align:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100px">' + escapeHtml(app.name) + '</div>' +
2340
+ '</div>';
2341
+ }).join('');
2342
+ }
2343
+
2344
+ // ── Iframe helpers ────────────────────────────────
2345
+
2346
+ var currentIframeUrl = '';
2347
+
2348
+ function closeIframe() {
2349
+ var view = document.getElementById('iframe-view');
2350
+ var iframe = document.getElementById('app-iframe');
2351
+ view.hidden = true;
2352
+ iframe.removeAttribute('src');
2353
+ iframe.removeAttribute('srcdoc');
2354
+ delete iframe.dataset.appId;
2355
+ currentIframeUrl = '';
2356
+ }
2357
+
2358
+ function openExternal() {
2359
+ var iframe = document.getElementById('app-iframe');
2360
+ var appId = iframe.dataset.appId;
2361
+ if (currentIframeUrl) {
2362
+ window.open(currentIframeUrl, '_blank');
2363
+ } else if (appId) {
2364
+ // Blob app — find it and launch in tab
2365
+ var app = null;
2366
+ for (var i = 0; i < allApps.length; i++) {
2367
+ if (allApps[i].id === appId) { app = allApps[i]; break; }
2368
+ }
2369
+ if (app) launchInTab(app);
2370
+ }
2371
+ }
2372
+
2373
+ // ── Context Menu ────────────────────────────────
2374
+
2375
+ var contextAppId = null;
2376
+
2377
+ function showContextMenu(event, id) {
2378
+ if (event.preventDefault) event.preventDefault();
2379
+ if (event.stopPropagation) event.stopPropagation();
2380
+ contextAppId = id;
2381
+
2382
+ var menu = document.getElementById('context-menu');
2383
+ menu.hidden = false;
2384
+
2385
+ // Position at cursor, but keep on screen
2386
+ var x = event.clientX;
2387
+ var y = event.clientY;
2388
+ var menuWidth = 200; // approximate min-width
2389
+ var menuHeight = 160; // approximate height
2390
+
2391
+ if (x + menuWidth > window.innerWidth) {
2392
+ x = window.innerWidth - menuWidth - 8;
2393
+ }
2394
+ if (y + menuHeight > window.innerHeight) {
2395
+ y = window.innerHeight - menuHeight - 8;
2396
+ }
2397
+
2398
+ menu.style.left = x + 'px';
2399
+ menu.style.top = y + 'px';
2400
+ }
2401
+
2402
+ function hideContextMenu() {
2403
+ var menu = document.getElementById('context-menu');
2404
+ menu.hidden = true;
2405
+ contextAppId = null;
2406
+ }
2407
+
2408
+ function handleContextAction(action) {
2409
+ if (!contextAppId) return;
2410
+ var appId = contextAppId;
2411
+ hideContextMenu();
2412
+
2413
+ var app = null;
2414
+ for (var i = 0; i < allApps.length; i++) {
2415
+ if (allApps[i].id === appId) { app = allApps[i]; break; }
2416
+ }
2417
+ if (!app) return;
2418
+
2419
+ switch (action) {
2420
+ case 'edit':
2421
+ // Open modal pre-filled with app data
2422
+ editingAppId = appId;
2423
+ document.getElementById('modal-title').textContent = 'Edit App';
2424
+ document.getElementById('app-name').value = app.name || '';
2425
+ document.getElementById('app-icon').value = app.icon || '';
2426
+ document.getElementById('app-tags').value = (app.tags || []).join(', ');
2427
+ document.getElementById('app-open-mode').value = app.openMode || 'tab';
2428
+
2429
+ // Set the correct source tab
2430
+ if (app.source === 'url') {
2431
+ switchTab('url');
2432
+ document.getElementById('app-url').value = app.url || '';
2433
+ } else {
2434
+ switchTab('file');
2435
+ document.getElementById('selected-file-name').textContent = '(existing file)';
2436
+ }
2437
+
2438
+ document.getElementById('modal-overlay').hidden = false;
2439
+ break;
2440
+
2441
+ case 'favorite':
2442
+ app.favorite = !app.favorite;
2443
+ saveApp(app).then(function () {
2444
+ renderApps();
2445
+ });
2446
+ break;
2447
+
2448
+ case 'toggle-mode':
2449
+ app.openMode = app.openMode === 'iframe' ? 'tab' : 'iframe';
2450
+ saveApp(app).then(function () {
2451
+ renderApps();
2452
+ });
2453
+ break;
2454
+
2455
+ case 'view-source':
2456
+ viewSource(app);
2457
+ break;
2458
+
2459
+ case 'delete':
2460
+ if (confirm('Delete "' + (app.name || 'this app') + '"?')) {
2461
+ deleteApp(appId).then(function () {
2462
+ renderApps();
2463
+ loadPublishedApps();
2464
+ });
2465
+ }
2466
+ break;
2467
+
2468
+ case 'publish':
2469
+ showPublishModal(appId);
2470
+ break;
2471
+
2472
+ case 'improve-ai':
2473
+ openPromptBuilder(app);
2474
+ break;
2475
+
2476
+ case 'share-prompt':
2477
+ generateSharePrompt(app);
2478
+ break;
2479
+ }
2480
+ }
2481
+
2482
+ // ── View Source ──────────────────────────────────
2483
+
2484
+ function viewSource(app) {
2485
+ var overlay = document.getElementById('source-overlay');
2486
+ var textarea = document.getElementById('source-code');
2487
+ var title = document.getElementById('source-title');
2488
+ var saveBtn = document.getElementById('save-source-btn');
2489
+
2490
+ title.textContent = 'View / Edit Source: ' + (app.name || 'App');
2491
+
2492
+ var isEditable = !!app.blob; // Only blob-based apps can be edited
2493
+ if (app.blob) {
2494
+ textarea.value = decodeURIComponent(escape(atob(app.blob)));
2495
+ } else if (app.url) {
2496
+ textarea.value = '// This app is URL-based (' + app.url + ')\n// Source code is not stored locally.\n// Open the URL to view the app.';
2497
+ } else {
2498
+ textarea.value = '// No source available';
2499
+ }
2500
+
2501
+ textarea.readOnly = !isEditable;
2502
+ saveBtn.disabled = true;
2503
+ saveBtn.style.display = isEditable ? '' : 'none';
2504
+ overlay.hidden = false;
2505
+ // Store app metadata for save and prompt
2506
+ overlay.dataset.appName = app.name || 'App';
2507
+ overlay.dataset.appId = app.id || '';
2508
+ overlay.dataset.originalSource = textarea.value;
2509
+ }
2510
+
2511
+ // ── Share as Prompt ────────────────────────────
2512
+
2513
+ function generateSharePrompt(app) {
2514
+ if (!app || !app.blob) {
2515
+ alert('Only local HTML apps can be shared as prompts.');
2516
+ return;
2517
+ }
2518
+
2519
+ var source = decodeURIComponent(escape(atob(app.blob)));
2520
+ var prompt = 'Recreate this HTML app exactly as provided.\n\n';
2521
+ prompt += 'App name: ' + (app.name || 'Untitled') + '\n';
2522
+ if (app.tags && app.tags.length) {
2523
+ prompt += 'Tags: ' + app.tags.join(', ') + '\n';
2524
+ }
2525
+ prompt += '\nReturn the COMPLETE HTML file below without modifications.\n';
2526
+ prompt += 'If the user asks for changes, apply them to this source.\n\n';
2527
+ prompt += '--- Source Code ---\n' + source;
2528
+
2529
+ navigator.clipboard.writeText(prompt).then(function() {
2530
+ alert('Share prompt copied! Paste it into any AI chat to recreate this app.');
2531
+ }).catch(function() {
2532
+ // Fallback: show in source overlay
2533
+ var overlay = document.getElementById('source-overlay');
2534
+ var textarea = document.getElementById('source-code');
2535
+ var title = document.getElementById('source-title');
2536
+ var saveBtn = document.getElementById('save-source-btn');
2537
+ title.textContent = 'Share Prompt: ' + (app.name || 'App');
2538
+ textarea.value = prompt;
2539
+ textarea.readOnly = true;
2540
+ saveBtn.style.display = 'none';
2541
+ overlay.hidden = false;
2542
+ overlay.dataset.appId = '';
2543
+ overlay.dataset.originalSource = '';
2544
+ });
2545
+ }
2546
+
2547
+ // ── Generate Homepage Prompt ──────────────────────
2548
+
2549
+ function generateHomepagePrompt() {
2550
+ if (allApps.length === 0) {
2551
+ alert('Add some apps first before generating a homepage.');
2552
+ return;
2553
+ }
2554
+
2555
+ var appList = allApps.map(function(app) {
2556
+ var launchInfo = '';
2557
+ if (app.url) {
2558
+ launchInfo = 'URL: ' + app.url;
2559
+ } else {
2560
+ launchInfo = 'Local HTML app (user will open it from their launcher)';
2561
+ }
2562
+ return '- ' + (app.icon || '') + ' ' + app.name +
2563
+ (app.description ? ' (' + app.description + ')' : '') +
2564
+ ' [' + launchInfo + ']' +
2565
+ (app.tags.length ? ' Tags: ' + app.tags.join(', ') : '');
2566
+ }).join('\n');
2567
+
2568
+ var prompt = 'Create a single HTML file that serves as my personal homepage/dashboard.\n\n' +
2569
+ 'My apps:\n' + appList + '\n\n' +
2570
+ 'Requirements:\n' +
2571
+ '- Show each app as a clickable card with its icon and name\n' +
2572
+ '- For URL-based apps, clicking opens the URL in a new tab\n' +
2573
+ '- For local apps, show a note that they can be opened from the App Launcher\n' +
2574
+ '- Modern, responsive design with light theme\n' +
2575
+ '- Group apps by their tags if they have tags\n' +
2576
+ '- Everything in one self-contained HTML file, no external dependencies\n' +
2577
+ '- Add a header with my name/title (I will customize this)\n' +
2578
+ '- Make it visually distinctive and professional';
2579
+
2580
+ // Reuse the source overlay for displaying the prompt
2581
+ var overlay = document.getElementById('source-overlay');
2582
+ var textarea = document.getElementById('source-code');
2583
+ var title = document.getElementById('source-title');
2584
+
2585
+ title.textContent = 'Generate Homepage - Copy this prompt to AI';
2586
+ textarea.value = prompt;
2587
+ overlay.dataset.appName = 'Homepage';
2588
+ overlay.hidden = false;
2589
+ }
2590
+
2591
+ // ── Theme ────────────────────────────────────────
2592
+
2593
+ function applyTheme(theme) {
2594
+ if (theme === 'light') {
2595
+ document.documentElement.setAttribute('data-theme', 'light');
2596
+ } else {
2597
+ document.documentElement.removeAttribute('data-theme');
2598
+ }
2599
+ }
2600
+
2601
+ // ── Settings ────────────────────────────────────
2602
+
2603
+ function openSettings() {
2604
+ var config = loadConfig();
2605
+ document.getElementById('setting-theme').value = config.theme || 'dark';
2606
+ document.getElementById('setting-open-mode').value = config.defaultOpenMode || 'tab';
2607
+ document.getElementById('setting-aimeat-url').value = config.aimeatUrl || '';
2608
+ document.getElementById('settings-overlay').hidden = false;
2609
+ }
2610
+
2611
+ function saveSettings() {
2612
+ var config = loadConfig();
2613
+ config.theme = document.getElementById('setting-theme').value;
2614
+ config.defaultOpenMode = document.getElementById('setting-open-mode').value;
2615
+ config.aimeatUrl = document.getElementById('setting-aimeat-url').value.trim();
2616
+ saveConfig(config);
2617
+ applyTheme(config.theme);
2618
+ document.getElementById('settings-overlay').hidden = true;
2619
+ // Sync config to server (best-effort)
2620
+ syncConfigToServer(config);
2621
+ }
2622
+
2623
+ function syncConfigToServer(config) {
2624
+ var url = config.aimeatUrl;
2625
+ if (!url) return;
2626
+ url = url.replace(/\/+$/, '');
2627
+ // Only sync safe fields, not the URL itself
2628
+ var syncPayload = {
2629
+ theme: config.theme,
2630
+ defaultOpenMode: config.defaultOpenMode,
2631
+ language: config.language || 'en'
2632
+ };
2633
+ fetch(url + '/v1/auth/anonymous', { method: 'POST' })
2634
+ .then(function (r) { return r.json(); })
2635
+ .then(function (auth) {
2636
+ var token = auth.data && auth.data.token;
2637
+ if (!token) return;
2638
+ return fetch(url + '/v1/memory', {
2639
+ method: 'POST',
2640
+ headers: {
2641
+ 'Content-Type': 'application/json',
2642
+ 'Authorization': 'Bearer ' + token
2643
+ },
2644
+ body: JSON.stringify({
2645
+ key: 'app-launcher/config',
2646
+ value: syncPayload,
2647
+ visibility: 'private'
2648
+ })
2649
+ });
2650
+ })
2651
+ .catch(function () { /* best-effort */ });
2652
+ }
2653
+
2654
+ function loadConfigFromServer() {
2655
+ var config = loadConfig();
2656
+ var url = config.aimeatUrl;
2657
+ if (!url) return;
2658
+ url = url.replace(/\/+$/, '');
2659
+ fetch(url + '/v1/auth/anonymous', { method: 'POST' })
2660
+ .then(function (r) { return r.json(); })
2661
+ .then(function (auth) {
2662
+ var token = auth.data && auth.data.token;
2663
+ if (!token) return;
2664
+ var gaii = auth.data.gaii || auth.data.sub || '';
2665
+ if (!gaii) return;
2666
+ return fetch(url + '/v1/memory/app-launcher%2Fconfig', {
2667
+ headers: { 'Authorization': 'Bearer ' + token }
2668
+ }).then(function (r) {
2669
+ if (!r.ok) return null;
2670
+ return r.json();
2671
+ });
2672
+ })
2673
+ .then(function (json) {
2674
+ if (!json || !json.data || !json.data.value) return;
2675
+ var remote = json.data.value;
2676
+ var local = loadConfig();
2677
+ var changed = false;
2678
+ // Merge remote into local (remote wins for preferences, but don't overwrite aimeatUrl)
2679
+ if (remote.theme && remote.theme !== local.theme) {
2680
+ local.theme = remote.theme;
2681
+ changed = true;
2682
+ }
2683
+ if (remote.defaultOpenMode && remote.defaultOpenMode !== local.defaultOpenMode) {
2684
+ local.defaultOpenMode = remote.defaultOpenMode;
2685
+ changed = true;
2686
+ }
2687
+ if (remote.language && remote.language !== local.language) {
2688
+ local.language = remote.language;
2689
+ changed = true;
2690
+ }
2691
+ if (changed) {
2692
+ saveConfig(local);
2693
+ applyTheme(local.theme);
2694
+ }
2695
+ })
2696
+ .catch(function () { /* best-effort */ });
2697
+ }
2698
+
2699
+ function closeSettings() {
2700
+ document.getElementById('settings-overlay').hidden = true;
2701
+ }
2702
+
2703
+ // ── Export / Import ─────────────────────────────
2704
+
2705
+ function exportBackup() {
2706
+ getAllApps().then(function (apps) {
2707
+ var config = loadConfig();
2708
+ var backup = {
2709
+ version: 1,
2710
+ exportedAt: new Date().toISOString(),
2711
+ config: config,
2712
+ apps: apps
2713
+ };
2714
+ var json = JSON.stringify(backup, null, 2);
2715
+ var blob = new Blob([json], { type: 'application/json' });
2716
+ var url = URL.createObjectURL(blob);
2717
+ var a = document.createElement('a');
2718
+ a.href = url;
2719
+ a.download = 'app-catalog-backup-' + new Date().toISOString().slice(0, 10) + '.json';
2720
+ document.body.appendChild(a);
2721
+ a.click();
2722
+ document.body.removeChild(a);
2723
+ URL.revokeObjectURL(url);
2724
+ });
2725
+ }
2726
+
2727
+ function handleImportBackup(file) {
2728
+ if (!file) return;
2729
+ var reader = new FileReader();
2730
+ reader.onload = function () {
2731
+ try {
2732
+ var backup = JSON.parse(reader.result);
2733
+ if (!backup.apps || !Array.isArray(backup.apps)) {
2734
+ alert('Invalid backup file: missing apps array');
2735
+ return;
2736
+ }
2737
+ // Import config if present
2738
+ if (backup.config && typeof backup.config === 'object') {
2739
+ var currentConfig = loadConfig();
2740
+ var merged = Object.assign({}, currentConfig, backup.config);
2741
+ saveConfig(merged);
2742
+ applyTheme(merged.theme);
2743
+ }
2744
+ // Import apps with new IDs to avoid conflicts
2745
+ var promises = [];
2746
+ for (var i = 0; i < backup.apps.length; i++) {
2747
+ var app = Object.assign({}, backup.apps[i]);
2748
+ app.id = generateId(); // New ID to avoid conflicts
2749
+ promises.push(saveApp(app));
2750
+ }
2751
+ Promise.all(promises).then(function () {
2752
+ alert('Imported ' + backup.apps.length + ' app(s) successfully');
2753
+ renderApps();
2754
+ });
2755
+ } catch (e) {
2756
+ alert('Failed to parse backup file: ' + (e.message || e));
2757
+ }
2758
+ };
2759
+ reader.readAsText(file);
2760
+ }
2761
+
2762
+ // ── Clear All Data ──────────────────────────────
2763
+
2764
+ function clearAllData() {
2765
+ if (!confirm('Are you sure you want to clear all data? This cannot be undone.')) return;
2766
+ if (!confirm('This will delete ALL apps and reset settings. Continue?')) return;
2767
+
2768
+ openDB().then(function (db) {
2769
+ return new Promise(function (resolve, reject) {
2770
+ var tx = db.transaction(STORE_NAME, 'readwrite');
2771
+ tx.objectStore(STORE_NAME).clear();
2772
+ tx.oncomplete = function () { resolve(); };
2773
+ tx.onerror = function () { reject(tx.error); };
2774
+ });
2775
+ }).then(function () {
2776
+ localStorage.removeItem('appLauncherConfig');
2777
+ applyTheme('dark');
2778
+ renderApps();
2779
+ document.getElementById('settings-overlay').hidden = true;
2780
+ alert('All data cleared');
2781
+ });
2782
+ }
2783
+
2784
+ // ── AIMEAT Import ───────────────────────────────
2785
+
2786
+ var aimeatAppsCache = [];
2787
+
2788
+ function formatFileSize(bytes) {
2789
+ if (bytes < 1024) return bytes + ' B';
2790
+ if (bytes < 1048576) return (bytes / 1024).toFixed(1) + ' KB';
2791
+ return (bytes / 1048576).toFixed(1) + ' MB';
2792
+ }
2793
+
2794
+ function importFromAimeat() {
2795
+ var config = loadConfig();
2796
+ if (!config.aimeatUrl) {
2797
+ alert('Set AIMEAT server URL in Settings first');
2798
+ return;
2799
+ }
2800
+
2801
+ var aimeatUrl = config.aimeatUrl.replace(/\/+$/, ''); // strip trailing slash
2802
+ closeModal();
2803
+
2804
+ fetch(aimeatUrl + '/v1/apps?include_peers=true')
2805
+ .then(function (resp) {
2806
+ if (!resp.ok) throw new Error('Server returned ' + resp.status);
2807
+ return resp.json();
2808
+ })
2809
+ .then(function (json) {
2810
+ var apps = json.data && json.data.apps ? json.data.apps : [];
2811
+ var peerApps = json.data && json.data.peer_apps ? json.data.peer_apps : [];
2812
+ // Merge local and peer apps; tag peer apps with source info
2813
+ for (var p = 0; p < peerApps.length; p++) {
2814
+ peerApps[p]._from_peer = true;
2815
+ }
2816
+ var allFetched = apps.concat(peerApps);
2817
+ if (allFetched.length === 0) {
2818
+ alert('No apps found on the AIMEAT server');
2819
+ return;
2820
+ }
2821
+ aimeatAppsCache = allFetched;
2822
+ showAimeatImportDialog(allFetched, aimeatUrl);
2823
+ })
2824
+ .catch(function (err) {
2825
+ var msg = 'Failed to fetch apps from AIMEAT server.\n\n' + (err.message || err);
2826
+ if (err.message && err.message.indexOf('Failed to fetch') !== -1) {
2827
+ msg += '\n\nIf the launcher is opened via file://, CORS will block the request. Open it from the AIMEAT server instead.';
2828
+ }
2829
+ alert(msg);
2830
+ });
2831
+ }
2832
+
2833
+ function showAimeatImportDialog(apps, aimeatUrl) {
2834
+ var listEl = document.getElementById('aimeat-app-list');
2835
+ var html = '';
2836
+ for (var i = 0; i < apps.length; i++) {
2837
+ var app = apps[i];
2838
+ var displayName = (app.manifest && app.manifest.name) ? app.manifest.name : app.filename;
2839
+ var displayAuthor = (app.manifest && app.manifest.authorDisplay) ? app.manifest.authorDisplay : (app.owner || '');
2840
+ var displayDesc = (app.manifest && app.manifest.description) ? app.manifest.description : '';
2841
+ var displayVer = app.version_number ? 'v' + app.version_number : '';
2842
+ var displayCat = (app.manifest && app.manifest.category) ? app.manifest.category : '';
2843
+ var peerLabel = app._from_peer && app._peer_node ? ' \u00B7 \uD83C\uDF10 ' + escapeHtml(app._peer_node) : '';
2844
+ html +=
2845
+ '<div class="aimeat-app-item">' +
2846
+ '<input type="checkbox" data-index="' + i + '" checked/>' +
2847
+ '<div class="aimeat-app-info">' +
2848
+ '<div class="aimeat-app-name">' + escapeHtml(displayName) + (displayVer ? ' <span style="opacity:.5;font-size:.85em">' + escapeHtml(displayVer) + '</span>' : '') + '</div>' +
2849
+ '<div class="aimeat-app-size">' + formatFileSize(app.size) + (displayAuthor ? ' \u00B7 ' + escapeHtml(displayAuthor) : '') + (displayCat ? ' \u00B7 ' + escapeHtml(displayCat) : '') + peerLabel + '</div>' +
2850
+ (displayDesc ? '<div class="aimeat-app-size" style="opacity:.6">' + escapeHtml(displayDesc.substring(0, 100)) + '</div>' : '') +
2851
+ '</div>' +
2852
+ '<select data-index="' + i + '">' +
2853
+ '<option value="link">Link (online only)</option>' +
2854
+ '<option value="download">Download (offline)</option>' +
2855
+ '</select>' +
2856
+ '</div>';
2857
+ }
2858
+ listEl.innerHTML = html;
2859
+ // Store the aimeatUrl for processing
2860
+ listEl.dataset.aimeatUrl = aimeatUrl;
2861
+ document.getElementById('aimeat-import-overlay').hidden = false;
2862
+ }
2863
+
2864
+ function processAimeatImport() {
2865
+ var listEl = document.getElementById('aimeat-app-list');
2866
+ var aimeatUrl = listEl.dataset.aimeatUrl;
2867
+ var checkboxes = listEl.querySelectorAll('input[type="checkbox"]');
2868
+ var selects = listEl.querySelectorAll('select');
2869
+ var config = loadConfig();
2870
+ var defaultOpenMode = config.defaultOpenMode || 'tab';
2871
+
2872
+ var toImport = [];
2873
+ for (var i = 0; i < checkboxes.length; i++) {
2874
+ if (checkboxes[i].checked) {
2875
+ var idx = parseInt(checkboxes[i].getAttribute('data-index'), 10);
2876
+ var mode = selects[i].value;
2877
+ toImport.push({ app: aimeatAppsCache[idx], mode: mode });
2878
+ }
2879
+ }
2880
+
2881
+ if (toImport.length === 0) {
2882
+ alert('No apps selected');
2883
+ return;
2884
+ }
2885
+
2886
+ var promises = [];
2887
+ for (var j = 0; j < toImport.length; j++) {
2888
+ (function (item) {
2889
+ var app = item.app;
2890
+ var name = (app.manifest && app.manifest.name) ? app.manifest.name : app.filename.replace(/\.html?$/i, '');
2891
+ var importedVersion = app.version_number || 1;
2892
+ // For peer apps, use the peer's URL as the base
2893
+ var baseUrl = (app._from_peer && app._peer_url) ? app._peer_url.replace(/\/+$/, '') : aimeatUrl;
2894
+
2895
+ if (item.mode === 'link') {
2896
+ // Link mode: store URL with ?mode=inline, pinned to latest
2897
+ var inlineUrl = baseUrl + app.download_url + '?mode=inline';
2898
+ promises.push(addAppFromUrl(name, inlineUrl, '\u{1F4E6}', ['aimeat'], defaultOpenMode));
2899
+ } else {
2900
+ // Download mode: fetch content and store blob (pinned to current version)
2901
+ var downloadUrl = baseUrl + app.download_url;
2902
+ promises.push(
2903
+ fetch(downloadUrl)
2904
+ .then(function (resp) {
2905
+ if (!resp.ok) throw new Error('Download failed: ' + resp.status);
2906
+ return resp.text();
2907
+ })
2908
+ .then(function (content) {
2909
+ var encoded = btoa(unescape(encodeURIComponent(content)));
2910
+ var record = {
2911
+ id: generateId(),
2912
+ name: name,
2913
+ description: (app.manifest && app.manifest.description) ? app.manifest.description : '',
2914
+ source: 'aimeat',
2915
+ aimeatOwner: app.owner || null,
2916
+ aimeatFilename: app.filename || null,
2917
+ aimeatVersion: importedVersion,
2918
+ url: null,
2919
+ blob: encoded,
2920
+ tags: ['aimeat'],
2921
+ openMode: defaultOpenMode,
2922
+ icon: '\u{1F4E6}',
2923
+ screenshot: null,
2924
+ favorite: false,
2925
+ addedAt: new Date().toISOString(),
2926
+ lastOpenedAt: null
2927
+ };
2928
+ return saveApp(record);
2929
+ })
2930
+ );
2931
+ }
2932
+ })(toImport[j]);
2933
+ }
2934
+
2935
+ Promise.all(promises).then(function () {
2936
+ document.getElementById('aimeat-import-overlay').hidden = true;
2937
+ renderApps();
2938
+ }).catch(function (err) {
2939
+ alert('Import error: ' + (err.message || err));
2940
+ });
2941
+ }
2942
+
2943
+ // ── Publish to AIMEAT ───────────────────────────
2944
+
2945
+ var publishAppId = null;
2946
+
2947
+ function showPublishModal(appId) {
2948
+ var app = null;
2949
+ for (var i = 0; i < allApps.length; i++) {
2950
+ if (allApps[i].id === appId) { app = allApps[i]; break; }
2951
+ }
2952
+ if (!app) return;
2953
+
2954
+ var config = loadConfig();
2955
+ if (!config.aimeatUrl) {
2956
+ alert('Set AIMEAT server URL in Settings first');
2957
+ return;
2958
+ }
2959
+
2960
+ publishAppId = appId;
2961
+ var safeName = (app.name || 'app').replace(/[^a-zA-Z0-9._-]/g, '-').replace(/-+/g, '-').toLowerCase();
2962
+ if (!/\.html?$/i.test(safeName)) safeName += '.html';
2963
+ document.getElementById('publish-filename').value = safeName;
2964
+ document.getElementById('publish-access-code').value = '';
2965
+ document.getElementById('publish-status').textContent = '';
2966
+ document.getElementById('publish-submit-btn').disabled = false;
2967
+ document.getElementById('publish-overlay').hidden = false;
2968
+ }
2969
+
2970
+ function submitPublish() {
2971
+ if (!publishAppId) return;
2972
+
2973
+ var app = null;
2974
+ for (var i = 0; i < allApps.length; i++) {
2975
+ if (allApps[i].id === publishAppId) { app = allApps[i]; break; }
2976
+ }
2977
+ if (!app) return;
2978
+
2979
+ var config = loadConfig();
2980
+ var aimeatUrl = config.aimeatUrl.replace(/\/+$/, '');
2981
+ var filename = document.getElementById('publish-filename').value.trim();
2982
+ var accessCode = document.getElementById('publish-access-code').value.trim();
2983
+ var statusEl = document.getElementById('publish-status');
2984
+ var submitBtn = document.getElementById('publish-submit-btn');
2985
+
2986
+ if (!filename || !/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,99}$/.test(filename)) {
2987
+ statusEl.textContent = 'Invalid filename. Use letters, numbers, dots, hyphens, underscores.';
2988
+ statusEl.style.color = 'var(--accent)';
2989
+ return;
2990
+ }
2991
+
2992
+ if (accessCode && (accessCode.length < 4 || accessCode.length > 64)) {
2993
+ statusEl.textContent = 'Access code must be 4-64 characters.';
2994
+ statusEl.style.color = 'var(--accent)';
2995
+ return;
2996
+ }
2997
+
2998
+ // Get the HTML content
2999
+ var htmlContent = '';
3000
+ if (app.blob) {
3001
+ htmlContent = app.blob; // already base64
3002
+ } else if (app.url) {
3003
+ statusEl.textContent = 'Cannot publish URL-linked apps. Download it first (right-click \u2192 View Source \u2192 Save).';
3004
+ statusEl.style.color = 'var(--accent)';
3005
+ return;
3006
+ } else {
3007
+ statusEl.textContent = 'No app content found.';
3008
+ statusEl.style.color = 'var(--accent)';
3009
+ return;
3010
+ }
3011
+
3012
+ statusEl.textContent = 'Publishing...';
3013
+ statusEl.style.color = '#34d399';
3014
+ submitBtn.disabled = true;
3015
+
3016
+ // Get auth token first
3017
+ fetch(aimeatUrl + '/v1/auth/anonymous', { method: 'POST' })
3018
+ .then(function(resp) { return resp.json(); })
3019
+ .then(function(authJson) {
3020
+ var token = authJson.data && authJson.data.token;
3021
+ if (!token) throw new Error('Could not get auth token');
3022
+
3023
+ var body = {
3024
+ filename: filename,
3025
+ content: htmlContent,
3026
+ mime_type: 'text/html',
3027
+ name: app.name || filename.replace(/\.html?$/i, ''),
3028
+ description: app.description || '',
3029
+ category: 'utility',
3030
+ tags: app.tags || [],
3031
+ uses_cortex: []
3032
+ };
3033
+ if (accessCode) body.access_code = accessCode;
3034
+
3035
+ return fetch(aimeatUrl + '/v1/apps', {
3036
+ method: 'POST',
3037
+ headers: {
3038
+ 'Content-Type': 'application/json',
3039
+ 'Authorization': 'Bearer ' + token
3040
+ },
3041
+ body: JSON.stringify(body)
3042
+ });
3043
+ })
3044
+ .then(function(resp) { return resp.json(); })
3045
+ .then(function(json) {
3046
+ if (json.ok) {
3047
+ statusEl.textContent = '\u2714 Published! ' + (json.data.download_url || '');
3048
+ statusEl.style.color = '#34d399';
3049
+ // Mark app as published in IndexedDB
3050
+ app.published = true;
3051
+ app.publishedFilename = filename;
3052
+ app.publishedAt = new Date().toISOString();
3053
+ app.publishedUrl = json.data.download_url || null;
3054
+ app.publishedVersionNumber = json.data.version_number || 1;
3055
+ app.publishedVersionsUrl = json.data.versions_url || null;
3056
+ saveApp(app).then(function() {
3057
+ loadPublishedApps();
3058
+ });
3059
+ } else {
3060
+ statusEl.textContent = '\u2718 ' + (json.error_description || json.error_code || 'Publish failed');
3061
+ statusEl.style.color = 'var(--accent)';
3062
+ submitBtn.disabled = false;
3063
+ }
3064
+ })
3065
+ .catch(function(err) {
3066
+ statusEl.textContent = '\u2718 ' + (err.message || 'Publish failed');
3067
+ statusEl.style.color = 'var(--accent)';
3068
+ submitBtn.disabled = false;
3069
+ });
3070
+ }
3071
+
3072
+ // ── Published Apps Section ──────────────────────
3073
+
3074
+ var publishedVisible = true;
3075
+
3076
+ function togglePublished() {
3077
+ publishedVisible = !publishedVisible;
3078
+ var grid = document.getElementById('published-grid');
3079
+ var arrow = document.getElementById('published-arrow');
3080
+ grid.style.display = publishedVisible ? '' : 'none';
3081
+ arrow.classList.toggle('open', publishedVisible);
3082
+ }
3083
+
3084
+ function loadPublishedApps() {
3085
+ getAllApps().then(function(apps) {
3086
+ var published = apps.filter(function(a) { return a.published; });
3087
+ var section = document.getElementById('published-section');
3088
+ var grid = document.getElementById('published-grid');
3089
+ var countEl = document.getElementById('published-count');
3090
+
3091
+ if (published.length === 0) {
3092
+ section.style.display = 'none';
3093
+ return;
3094
+ }
3095
+
3096
+ section.style.display = '';
3097
+ countEl.textContent = '(' + published.length + ')';
3098
+ var config = loadConfig();
3099
+ var aimeatUrl = config.aimeatUrl ? config.aimeatUrl.replace(/\/+$/, '') : '';
3100
+
3101
+ var html = '';
3102
+ for (var i = 0; i < published.length; i++) {
3103
+ var app = published[i];
3104
+ var url = app.publishedUrl ? (aimeatUrl + app.publishedUrl) : '';
3105
+ html +=
3106
+ '<div class="published-card">' +
3107
+ '<div class="published-card-name">' + escapeHtml(app.name || app.publishedFilename || 'Untitled') + (app.publishedVersionNumber ? ' <span style="opacity:.5;font-size:.85em">v' + app.publishedVersionNumber + '</span>' : '') + '</div>' +
3108
+ '<div class="published-card-meta">' +
3109
+ '<span>' + escapeHtml(app.publishedFilename || '') + '</span>' +
3110
+ '<span>' + (app.publishedAt ? new Date(app.publishedAt).toLocaleDateString() : '') + '</span>' +
3111
+ '</div>' +
3112
+ '<div class="published-card-actions">' +
3113
+ (url ? '<button onclick="window.open(\'' + escapeHtml(url) + '?mode=inline\', \'_blank\')">&#x1F441; View</button>' : '') +
3114
+ '<button onclick="window._launcher.unpublishApp(\'' + escapeHtml(app.id) + '\')" class="danger">&#x1F5D1; Remove</button>' +
3115
+ '</div>' +
3116
+ '</div>';
3117
+ }
3118
+ grid.innerHTML = html;
3119
+ });
3120
+ }
3121
+
3122
+ function unpublishApp(appId) {
3123
+ if (!confirm('Remove this published app from the server?')) return;
3124
+
3125
+ var app = null;
3126
+ for (var i = 0; i < allApps.length; i++) {
3127
+ if (allApps[i].id === appId) { app = allApps[i]; break; }
3128
+ }
3129
+ if (!app || !app.publishedFilename) return;
3130
+
3131
+ var config = loadConfig();
3132
+ var aimeatUrl = config.aimeatUrl.replace(/\/+$/, '');
3133
+
3134
+ // Get auth token and delete
3135
+ fetch(aimeatUrl + '/v1/auth/anonymous', { method: 'POST' })
3136
+ .then(function(resp) { return resp.json(); })
3137
+ .then(function(authJson) {
3138
+ var token = authJson.data && authJson.data.token;
3139
+ if (!token) throw new Error('Could not get auth token');
3140
+ return fetch(aimeatUrl + '/v1/apps/' + encodeURIComponent(app.publishedFilename), {
3141
+ method: 'DELETE',
3142
+ headers: { 'Authorization': 'Bearer ' + token }
3143
+ });
3144
+ })
3145
+ .then(function(resp) { return resp.json(); })
3146
+ .then(function(json) {
3147
+ if (json.ok) {
3148
+ app.published = false;
3149
+ delete app.publishedFilename;
3150
+ delete app.publishedAt;
3151
+ delete app.publishedUrl;
3152
+ delete app.publishedVersionNumber;
3153
+ delete app.publishedVersionsUrl;
3154
+ saveApp(app).then(function() {
3155
+ loadPublishedApps();
3156
+ });
3157
+ } else {
3158
+ alert('Failed to remove: ' + (json.error_description || 'Unknown error'));
3159
+ }
3160
+ })
3161
+ .catch(function(err) {
3162
+ alert('Error: ' + (err.message || err));
3163
+ });
3164
+ }
3165
+
3166
+ // ── Cortex Extensions Bar ─────────────────────────
3167
+
3168
+ var cortexToken = null;
3169
+
3170
+ function cortexEsc(str) {
3171
+ var div = document.createElement('div');
3172
+ div.textContent = str;
3173
+ return div.innerHTML;
3174
+ }
3175
+
3176
+ function loadCortexExtensions() {
3177
+ var config = loadConfig();
3178
+ if (!config.aimeatUrl) return;
3179
+ var url = config.aimeatUrl.replace(/\/+$/, '');
3180
+
3181
+ // Get anonymous token first (same pattern as AIMEAT import)
3182
+ fetch(url + '/v1/auth/anonymous', { method: 'POST' })
3183
+ .then(function(r) { return r.json(); })
3184
+ .then(function(authData) {
3185
+ var token = authData.data && authData.data.token;
3186
+ if (!token) return;
3187
+ cortexToken = token;
3188
+ return fetch(url + '/v1/cortex?status=active', {
3189
+ headers: { 'Authorization': 'Bearer ' + token }
3190
+ });
3191
+ })
3192
+ .then(function(r) { return r ? r.json() : null; })
3193
+ .then(function(data) {
3194
+ if (!data || !data.data || !data.data.extensions) return;
3195
+ var exts = data.data.extensions;
3196
+ if (!exts.length) return;
3197
+
3198
+ document.getElementById('cortex-bar').style.display = 'block';
3199
+ var grid = document.getElementById('cortex-bar-grid');
3200
+ grid.innerHTML = exts.map(function(ext) {
3201
+ var types = ext.component_types || [];
3202
+ var libCount = types.filter(function(t) { return t === 'lib'; }).length;
3203
+ var schemaCount = types.filter(function(t) { return t === 'schema'; }).length;
3204
+ return '<div class="cortex-mini-card" onclick="showCortexPopup(\'' + encodeURIComponent(ext.name) + '\')">'
3205
+ + '<div class="cortex-mini-name">&#x1F4E6; ' + cortexEsc(ext.short_name || ext.name) + '</div>'
3206
+ + '<div class="cortex-mini-meta">' + libCount + ' lib &middot; ' + schemaCount + ' schema</div>'
3207
+ + '</div>';
3208
+ }).join('');
3209
+ })
3210
+ .catch(function(e) { console.warn('Cortex bar load failed:', e); });
3211
+ }
3212
+
3213
+ function showCortexPopup(encodedName) {
3214
+ var config = loadConfig();
3215
+ var url = config.aimeatUrl.replace(/\/+$/, '');
3216
+ var el = document.getElementById('cortex-popup-content');
3217
+ el.innerHTML = '<p>Loading...</p>';
3218
+ document.getElementById('cortex-popup-overlay').style.display = 'flex';
3219
+
3220
+ if (!cortexToken) { el.innerHTML = '<p>No auth token available</p>'; return; }
3221
+
3222
+ fetch(url + '/v1/cortex/' + encodedName, {
3223
+ headers: { 'Authorization': 'Bearer ' + cortexToken }
3224
+ })
3225
+ .then(function(r) { return r.json(); })
3226
+ .then(function(data) {
3227
+ var ext = data.data;
3228
+ var comps = ext.components || [];
3229
+ var html = '<h2 style="margin-top:0">' + cortexEsc(ext.name) + '</h2>';
3230
+ html += '<p style="color:#6B7280">' + cortexEsc(ext.description || '') + '</p>';
3231
+ html += '<h3 style="font-size:.9rem">Available for your apps:</h3>';
3232
+
3233
+ // Libs
3234
+ comps.filter(function(c) { return c.type === 'lib'; }).forEach(function(lib) {
3235
+ var scriptUrl = url + '/v1/cortex/' + encodedName + '/libs/' + encodeURIComponent(lib.filename);
3236
+ var tag = '<script src="' + scriptUrl + '"><\/script>';
3237
+ html += '<div style="margin-bottom:1rem">'
3238
+ + '<div style="font-weight:600;font-size:.85rem">&#x1F4E6; Lib: ' + cortexEsc(lib.filename) + '</div>'
3239
+ + '<div style="font-family:monospace;font-size:.75rem;background:#F3F4F6;padding:8px;border-radius:6px;margin-top:4px;word-break:break-all">' + cortexEsc(tag) + '</div>'
3240
+ + '<button onclick="cortexCopy(\'' + tag.replace(/'/g, "\\'").replace(/"/g, '&quot;') + '\',this)" style="font-size:.7rem;margin-top:4px;padding:2px 8px;border-radius:4px;border:1px solid #E5E7EB;background:transparent;color:#6B7280;cursor:pointer">Copy</button>';
3241
+ if (lib.api_surface) {
3242
+ html += '<div style="font-size:.8rem;font-weight:600;margin-top:8px">API Surface:</div>'
3243
+ + '<div style="font-family:monospace;font-size:.75rem;background:#F3F4F6;padding:8px;border-radius:6px;margin-top:4px;white-space:pre-wrap">' + cortexEsc(lib.api_surface) + '</div>'
3244
+ + '<button onclick="cortexCopy(\'' + (lib.api_surface || '').replace(/\\/g,'\\\\').replace(/'/g, "\\'").replace(/"/g, '&quot;').replace(/\n/g, '\\n') + '\',this)" style="font-size:.7rem;margin-top:4px;padding:2px 8px;border-radius:4px;border:1px solid #E5E7EB;background:transparent;color:#6B7280;cursor:pointer">Copy API</button>';
3245
+ }
3246
+ html += '</div>';
3247
+ });
3248
+
3249
+ // Schemas
3250
+ comps.filter(function(c) { return c.type === 'schema'; }).forEach(function(s) {
3251
+ html += '<div style="margin-bottom:.5rem;font-size:.85rem">&#x1F4D0; Schema: <code>' + cortexEsc(s.key_pattern) + '</code> &mdash; data validated automatically</div>';
3252
+ });
3253
+
3254
+ // Prompts
3255
+ comps.filter(function(c) { return c.type === 'prompt'; }).forEach(function(p) {
3256
+ var preview = (p.content || '').substring(0, 150);
3257
+ html += '<div style="margin-bottom:.5rem">'
3258
+ + '<div style="font-size:.85rem">&#x1F4AC; Prompt: ' + cortexEsc(p.name) + '</div>'
3259
+ + '<div style="font-size:.75rem;color:#6B7280">&ldquo;' + cortexEsc(preview) + '...&rdquo;</div>'
3260
+ + '<button onclick="cortexCopy(\'' + (p.content || '').replace(/\\/g,'\\\\').replace(/'/g, "\\'").replace(/"/g, '&quot;').replace(/\n/g, '\\n') + '\',this)" style="font-size:.7rem;margin-top:2px;padding:2px 8px;border-radius:4px;border:1px solid #E5E7EB;background:transparent;color:#6B7280;cursor:pointer">Copy Prompt</button>'
3261
+ + '</div>';
3262
+ });
3263
+
3264
+ // Edit button (only if owner session available)
3265
+ var hasSession = false;
3266
+ try { hasSession = !!getCortexOwnerToken(); } catch(e) {}
3267
+ if (hasSession) {
3268
+ html += '<div style="margin-top:1.5rem;padding-top:1rem;border-top:1px solid #E5E7EB">'
3269
+ + '<button onclick="window._launcher.openCortexEditor(\'' + encodedName + '\')" style="padding:6px 16px;border-radius:8px;border:1px solid var(--accent,#34d399);background:transparent;color:var(--accent,#34d399);cursor:pointer;font-size:.85rem">&#x1F6E0;&#xFE0F; Edit Extension</button>'
3270
+ + '</div>';
3271
+ }
3272
+
3273
+ el.innerHTML = html;
3274
+ })
3275
+ .catch(function(e) {
3276
+ el.innerHTML = '<p>Error: ' + cortexEsc(e.message) + '</p>';
3277
+ });
3278
+ }
3279
+
3280
+ function cortexCopy(text, btn) {
3281
+ navigator.clipboard.writeText(text.replace(/\\n/g, '\n')).then(function() {
3282
+ var orig = btn.textContent;
3283
+ btn.textContent = 'Copied!';
3284
+ setTimeout(function() { btn.textContent = orig; }, 1500);
3285
+ });
3286
+ }
3287
+
3288
+ // ── Cortex Extension Editor ───────────────────────
3289
+
3290
+ var cortexEditorExtName = null; // name of extension being edited
3291
+ var cortexEditorWasActive = false; // was it active before editing?
3292
+ var cortexEditorLibCounter = 0; // counter for unique lib section IDs
3293
+
3294
+ function getCortexOwnerToken() {
3295
+ try {
3296
+ if (window.AIMEAT && window.AIMEAT.auth && window.AIMEAT.auth.getSession()) {
3297
+ return window.AIMEAT.auth.getSession().jwt;
3298
+ }
3299
+ var stored = localStorage.getItem('aimeat_session');
3300
+ if (stored) {
3301
+ var parsed = JSON.parse(stored);
3302
+ return parsed.jwt || null;
3303
+ }
3304
+ } catch(e) {}
3305
+ return null;
3306
+ }
3307
+
3308
+ function openCortexEditor(encodedName) {
3309
+ var config = loadConfig();
3310
+ var url = config.aimeatUrl.replace(/\/+$/, '');
3311
+ var token = getCortexOwnerToken();
3312
+ if (!token) { alert('You must be logged in as an owner to edit extensions.'); return; }
3313
+
3314
+ var statusEl = document.getElementById('cortex-editor-status');
3315
+ statusEl.textContent = 'Loading extension data...';
3316
+ statusEl.style.color = '#34d399';
3317
+ document.getElementById('cortex-editor-manifest').value = '';
3318
+ document.getElementById('cortex-editor-libs').innerHTML = '';
3319
+ document.getElementById('cortex-editor-name').textContent = '';
3320
+ cortexEditorLibCounter = 0;
3321
+
3322
+ // Close the detail popup
3323
+ document.getElementById('cortex-popup-overlay').style.display = 'none';
3324
+ document.getElementById('cortex-editor-overlay').style.display = 'flex';
3325
+
3326
+ fetch(url + '/v1/cortex/' + encodedName + '/export', {
3327
+ headers: { 'Authorization': 'Bearer ' + token }
3328
+ })
3329
+ .then(function(r) { return r.json(); })
3330
+ .then(function(data) {
3331
+ if (!data.data) { statusEl.textContent = 'Error: ' + (data.error || 'Unknown error'); statusEl.style.color = 'var(--accent,#e74c6f)'; return; }
3332
+ var ext = data.data;
3333
+ cortexEditorExtName = ext.name;
3334
+ cortexEditorWasActive = (ext.status === 'active');
3335
+ document.getElementById('cortex-editor-name').textContent = ext.name + (cortexEditorWasActive ? ' (active)' : ' (inactive)');
3336
+ document.getElementById('cortex-editor-manifest').value = ext.manifest || '';
3337
+
3338
+ // Render lib editors
3339
+ var libsHtml = '';
3340
+ var libs = ext.libs || {};
3341
+ var filenames = Object.keys(libs);
3342
+ for (var i = 0; i < filenames.length; i++) {
3343
+ cortexEditorLibCounter++;
3344
+ var fname = filenames[i];
3345
+ libsHtml += cortexEditorLibSection(cortexEditorLibCounter, fname, libs[fname]);
3346
+ }
3347
+ document.getElementById('cortex-editor-libs').innerHTML = libsHtml;
3348
+ statusEl.textContent = 'Loaded. ' + filenames.length + ' lib file' + (filenames.length !== 1 ? 's' : '') + '.';
3349
+ })
3350
+ .catch(function(e) {
3351
+ statusEl.textContent = 'Error loading: ' + e.message;
3352
+ statusEl.style.color = 'var(--accent,#e74c6f)';
3353
+ });
3354
+ }
3355
+
3356
+ function cortexEditorLibSection(id, filename, content) {
3357
+ return '<div id="cortex-lib-' + id + '" style="margin-bottom:1rem;border:1px solid #E5E7EB;border-radius:8px;padding:12px">'
3358
+ + '<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:.5rem">'
3359
+ + '<label style="font-size:.85rem;font-weight:600">Lib: <input type="text" value="' + cortexEsc(filename) + '" data-lib-name="' + id + '" style="background:#F9FAFB;border:1px solid #E5E7EB;border-radius:4px;padding:2px 6px;color:#1A1A2E;font-family:monospace;font-size:.8rem;width:200px" /></label>'
3360
+ + '<button onclick="document.getElementById(\'cortex-lib-' + id + '\').remove()" style="font-size:.7rem;padding:2px 8px;border-radius:4px;border:1px solid rgba(232,86,74,.3);background:transparent;color:#E8564A;cursor:pointer">Remove</button>'
3361
+ + '</div>'
3362
+ + '<textarea data-lib-content="' + id + '" spellcheck="false" style="width:100%;min-height:150px;background:#F9FAFB;color:#1A1A2E;border:1px solid #E5E7EB;border-radius:8px;padding:10px;font-family:monospace;font-size:.78rem;resize:vertical;tab-size:2">' + cortexEsc(content || '') + '</textarea>'
3363
+ + '</div>';
3364
+ }
3365
+
3366
+ function cortexEditorAddLib() {
3367
+ cortexEditorLibCounter++;
3368
+ var container = document.getElementById('cortex-editor-libs');
3369
+ container.insertAdjacentHTML('beforeend', cortexEditorLibSection(cortexEditorLibCounter, 'new-lib.js', ''));
3370
+ }
3371
+
3372
+ function cortexEditorCollectLibs() {
3373
+ var libs = {};
3374
+ var container = document.getElementById('cortex-editor-libs');
3375
+ var nameInputs = container.querySelectorAll('input[data-lib-name]');
3376
+ for (var i = 0; i < nameInputs.length; i++) {
3377
+ var id = nameInputs[i].getAttribute('data-lib-name');
3378
+ var fname = nameInputs[i].value.trim();
3379
+ var contentEl = container.querySelector('textarea[data-lib-content="' + id + '"]');
3380
+ if (fname && contentEl) {
3381
+ libs[fname] = contentEl.value;
3382
+ }
3383
+ }
3384
+ return libs;
3385
+ }
3386
+
3387
+ function cortexEditorSave() {
3388
+ var config = loadConfig();
3389
+ var url = config.aimeatUrl.replace(/\/+$/, '');
3390
+ var token = getCortexOwnerToken();
3391
+ if (!token) { alert('No auth token available.'); return; }
3392
+
3393
+ var manifest = document.getElementById('cortex-editor-manifest').value;
3394
+ if (!manifest.trim()) { alert('Manifest cannot be empty.'); return; }
3395
+
3396
+ var libs = cortexEditorCollectLibs();
3397
+ var statusEl = document.getElementById('cortex-editor-status');
3398
+ var saveBtn = document.getElementById('cortex-editor-save-btn');
3399
+ var oldName = cortexEditorExtName;
3400
+ var wasActive = cortexEditorWasActive;
3401
+
3402
+ statusEl.textContent = 'Deleting old extension...';
3403
+ statusEl.style.color = '#34d399';
3404
+ saveBtn.disabled = true;
3405
+
3406
+ // Step 1: Delete old extension
3407
+ fetch(url + '/v1/cortex/' + encodeURIComponent(oldName), {
3408
+ method: 'DELETE',
3409
+ headers: { 'Authorization': 'Bearer ' + token }
3410
+ })
3411
+ .then(function(r) {
3412
+ if (!r.ok && r.status !== 404) throw new Error('Delete failed: ' + r.status);
3413
+ statusEl.textContent = 'Installing updated extension...';
3414
+ // Step 2: Install new
3415
+ return fetch(url + '/v1/cortex', {
3416
+ method: 'POST',
3417
+ headers: { 'Authorization': 'Bearer ' + token, 'Content-Type': 'application/json' },
3418
+ body: JSON.stringify({ manifest: manifest, libs: libs })
3419
+ });
3420
+ })
3421
+ .then(function(r) { return r.json(); })
3422
+ .then(function(data) {
3423
+ if (data.status !== 'ok') {
3424
+ var errMsg = data.error || 'Install failed';
3425
+ if (data.details && data.details.errors) errMsg += ': ' + data.details.errors.join('; ');
3426
+ throw new Error(errMsg);
3427
+ }
3428
+ var newName = data.data.name;
3429
+ cortexEditorExtName = newName;
3430
+
3431
+ // Step 3: Activate if was active before
3432
+ if (wasActive) {
3433
+ statusEl.textContent = 'Activating...';
3434
+ return fetch(url + '/v1/cortex/' + encodeURIComponent(newName) + '/activate', {
3435
+ method: 'POST',
3436
+ headers: { 'Authorization': 'Bearer ' + token }
3437
+ }).then(function(r) { return r.json(); });
3438
+ }
3439
+ return null;
3440
+ })
3441
+ .then(function(activateData) {
3442
+ saveBtn.disabled = false;
3443
+ if (activateData && activateData.status !== 'ok') {
3444
+ statusEl.textContent = 'Installed but activation failed: ' + (activateData.error || 'unknown');
3445
+ statusEl.style.color = 'orange';
3446
+ } else {
3447
+ statusEl.textContent = 'Saved and re-installed successfully!';
3448
+ statusEl.style.color = '#34d399';
3449
+ cortexEditorWasActive = wasActive; // preserve
3450
+ // Refresh the cortex bar
3451
+ loadCortexExtensions();
3452
+ }
3453
+ })
3454
+ .catch(function(e) {
3455
+ saveBtn.disabled = false;
3456
+ statusEl.textContent = 'Error: ' + e.message;
3457
+ statusEl.style.color = '#E8564A';
3458
+ });
3459
+ }
3460
+
3461
+ function cortexEditorExport() {
3462
+ var manifest = document.getElementById('cortex-editor-manifest').value;
3463
+ var libs = cortexEditorCollectLibs();
3464
+ var name = (cortexEditorExtName || 'extension').replace(/\//g, '-');
3465
+
3466
+ // Download manifest
3467
+ var manifestBlob = new Blob([manifest], { type: 'text/yaml' });
3468
+ var a = document.createElement('a');
3469
+ a.href = URL.createObjectURL(manifestBlob);
3470
+ a.download = name + '.yaml';
3471
+ a.click();
3472
+ URL.revokeObjectURL(a.href);
3473
+
3474
+ // Download each lib file
3475
+ var filenames = Object.keys(libs);
3476
+ for (var i = 0; i < filenames.length; i++) {
3477
+ var libBlob = new Blob([libs[filenames[i]]], { type: 'application/javascript' });
3478
+ var b = document.createElement('a');
3479
+ b.href = URL.createObjectURL(libBlob);
3480
+ b.download = filenames[i];
3481
+ b.click();
3482
+ URL.revokeObjectURL(b.href);
3483
+ }
3484
+ }
3485
+
3486
+ function closeCortexEditor() {
3487
+ document.getElementById('cortex-editor-overlay').style.display = 'none';
3488
+ cortexEditorExtName = null;
3489
+ }
3490
+
3491
+ // ── Prompt Builder Panel ──────────────────────────
3492
+
3493
+ var pbExtensionsCache = null; // cached cortex extension list
3494
+ var pbExtDetailCache = {}; // cached extension details (name → detail object)
3495
+ var pbSourceApp = null; // app being improved (null = new app mode)
3496
+
3497
+ function openPromptBuilder(app) {
3498
+ pbSourceApp = app || null;
3499
+ var overlay = document.getElementById('prompt-builder-overlay');
3500
+ var desc = document.getElementById('pb-description');
3501
+ var extCheckbox = document.getElementById('pb-ext-checkbox');
3502
+ var extList = document.getElementById('pb-ext-list');
3503
+
3504
+ // Reset state
3505
+ desc.value = '';
3506
+ extCheckbox.checked = false;
3507
+ extList.classList.remove('open');
3508
+
3509
+ // Set mode based on whether we have a source app
3510
+ var radios = document.querySelectorAll('input[name="pb-mode"]');
3511
+ if (pbSourceApp) {
3512
+ radios[1].checked = true; // Improve This App
3513
+ desc.placeholder = 'Describe what changes to make to "' + (pbSourceApp.name || 'this app') + '"...';
3514
+ } else {
3515
+ radios[0].checked = true; // New App
3516
+ desc.placeholder = 'Describe what the app should do...';
3517
+ }
3518
+
3519
+ // Load Cortex extensions into picker
3520
+ loadPbExtensions();
3521
+
3522
+ overlay.style.display = 'flex';
3523
+ desc.focus();
3524
+ updatePbPreview();
3525
+ }
3526
+
3527
+ function closePbPanel() {
3528
+ document.getElementById('prompt-builder-overlay').style.display = 'none';
3529
+ pbSourceApp = null;
3530
+ }
3531
+
3532
+ function loadPbExtensions() {
3533
+ var list = document.getElementById('pb-ext-list');
3534
+ var config = loadConfig();
3535
+ if (!config.aimeatUrl) {
3536
+ list.innerHTML = '<span style="color:var(--text-muted);font-size:.8rem">Configure AIMEAT URL in Settings to load extensions</span>';
3537
+ return;
3538
+ }
3539
+
3540
+ // Use cached data if available
3541
+ if (pbExtensionsCache) {
3542
+ renderPbExtensions(pbExtensionsCache);
3543
+ return;
3544
+ }
3545
+
3546
+ list.innerHTML = '<span style="color:var(--text-muted);font-size:.8rem">Loading extensions...</span>';
3547
+ var url = config.aimeatUrl.replace(/\/+$/, '');
3548
+
3549
+ var token = cortexToken;
3550
+ var fetchExts = function(authToken) {
3551
+ fetch(url + '/v1/cortex?status=active', {
3552
+ headers: { 'Authorization': 'Bearer ' + authToken }
3553
+ })
3554
+ .then(function(r) { return r.json(); })
3555
+ .then(function(data) {
3556
+ if (!data || !data.data || !data.data.extensions) {
3557
+ list.innerHTML = '<span style="color:var(--text-muted);font-size:.8rem">No extensions available</span>';
3558
+ return;
3559
+ }
3560
+ pbExtensionsCache = data.data.extensions;
3561
+ renderPbExtensions(pbExtensionsCache);
3562
+ })
3563
+ .catch(function() {
3564
+ list.innerHTML = '<span style="color:var(--text-muted);font-size:.8rem">Failed to load extensions</span>';
3565
+ });
3566
+ };
3567
+
3568
+ if (token) {
3569
+ fetchExts(token);
3570
+ } else {
3571
+ fetch(url + '/v1/auth/anonymous', { method: 'POST' })
3572
+ .then(function(r) { return r.json(); })
3573
+ .then(function(authData) {
3574
+ var t = authData.data && authData.data.token;
3575
+ if (!t) { list.innerHTML = '<span style="color:var(--text-muted);font-size:.8rem">Auth failed</span>'; return; }
3576
+ cortexToken = t;
3577
+ fetchExts(t);
3578
+ })
3579
+ .catch(function() {
3580
+ list.innerHTML = '<span style="color:var(--text-muted);font-size:.8rem">Failed to authenticate</span>';
3581
+ });
3582
+ }
3583
+ }
3584
+
3585
+ function renderPbExtensions(extensions) {
3586
+ var list = document.getElementById('pb-ext-list');
3587
+ if (!extensions.length) {
3588
+ list.innerHTML = '<span style="color:var(--text-muted);font-size:.8rem">No active extensions</span>';
3589
+ return;
3590
+ }
3591
+ list.innerHTML = extensions.map(function(ext, i) {
3592
+ var types = (ext.component_types || []).join(', ');
3593
+ return '<label class="pb-ext-chip" data-ext-index="' + i + '">'
3594
+ + '<input type="checkbox" data-ext-name="' + cortexEsc(ext.name) + '"> '
3595
+ + cortexEsc(ext.short_name || ext.name)
3596
+ + ' <span style="font-size:.7rem;color:var(--text-muted)">(' + cortexEsc(types) + ')</span>'
3597
+ + '</label>';
3598
+ }).join('');
3599
+
3600
+ // Toggle selected class and update preview on change
3601
+ list.querySelectorAll('input[type="checkbox"]').forEach(function(cb) {
3602
+ cb.addEventListener('change', function() {
3603
+ this.closest('.pb-ext-chip').classList.toggle('selected', this.checked);
3604
+ if (this.checked) {
3605
+ fetchExtDetail(this.getAttribute('data-ext-name'));
3606
+ } else {
3607
+ updatePbPreview();
3608
+ }
3609
+ });
3610
+ });
3611
+ }
3612
+
3613
+ function getSelectedExtensions() {
3614
+ var selected = [];
3615
+ var checkboxes = document.querySelectorAll('#pb-ext-list input[type="checkbox"]:checked');
3616
+ checkboxes.forEach(function(cb) {
3617
+ var name = cb.getAttribute('data-ext-name');
3618
+ // Prefer detail cache, fall back to list data
3619
+ if (pbExtDetailCache[name]) {
3620
+ selected.push(pbExtDetailCache[name]);
3621
+ } else if (pbExtensionsCache) {
3622
+ for (var i = 0; i < pbExtensionsCache.length; i++) {
3623
+ if (pbExtensionsCache[i].name === name) {
3624
+ selected.push(pbExtensionsCache[i]);
3625
+ break;
3626
+ }
3627
+ }
3628
+ }
3629
+ });
3630
+ return selected;
3631
+ }
3632
+
3633
+ function fetchExtDetail(extName) {
3634
+ // Already cached
3635
+ if (pbExtDetailCache[extName]) { updatePbPreview(); return; }
3636
+ var config = loadConfig();
3637
+ if (!config.aimeatUrl || !cortexToken) { updatePbPreview(); return; }
3638
+ var url = config.aimeatUrl.replace(/\/+$/, '');
3639
+ fetch(url + '/v1/cortex/' + encodeURIComponent(extName), {
3640
+ headers: { 'Authorization': 'Bearer ' + cortexToken }
3641
+ })
3642
+ .then(function(r) { return r.json(); })
3643
+ .then(function(data) {
3644
+ if (data && data.data) {
3645
+ pbExtDetailCache[extName] = data.data;
3646
+ }
3647
+ updatePbPreview();
3648
+ })
3649
+ .catch(function() { updatePbPreview(); });
3650
+ }
3651
+
3652
+ function buildPromptFromBuilder() {
3653
+ var config = loadConfig();
3654
+ var nodeUrl = config.aimeatUrl ? config.aimeatUrl.replace(/\/+$/, '') : 'https://your-aimeat-node.example';
3655
+ var mode = document.querySelector('input[name="pb-mode"]:checked').value;
3656
+ var description = document.getElementById('pb-description').value.trim();
3657
+ var selectedExts = document.getElementById('pb-ext-checkbox').checked ? getSelectedExtensions() : [];
3658
+
3659
+ var prompt = '';
3660
+
3661
+ // Header
3662
+ if (mode === 'improve' && pbSourceApp) {
3663
+ prompt += 'Here is an HTML app called "' + (pbSourceApp.name || 'Untitled') + '".\n';
3664
+ prompt += 'Make the following change: ' + (description || '[DESCRIBE YOUR CHANGE HERE]') + '\n\n';
3665
+ prompt += 'Return the COMPLETE updated HTML file. Do not omit any parts.\n\n';
3666
+ } else {
3667
+ prompt += 'Create a new single-file HTML app.\n';
3668
+ prompt += 'Description: ' + (description || '[DESCRIBE WHAT THE APP SHOULD DO]') + '\n\n';
3669
+ }
3670
+
3671
+ // AIMEAT Platform Instructions
3672
+ prompt += '## AIMEAT Platform Instructions\n\n';
3673
+ prompt += 'This app runs in the AIMEAT ecosystem. Here is what you need to know:\n\n';
3674
+
3675
+ // Core libraries
3676
+ prompt += '### Available Client Libraries\n';
3677
+ prompt += 'Load via script tags from the AIMEAT node (' + nodeUrl + '):\n';
3678
+ prompt += '- aimeat-auth (' + nodeUrl + '/v1/libs/aimeat-auth.js) - Identity, login, JWT, session management\n';
3679
+ prompt += '- aimeat-data (' + nodeUrl + '/v1/libs/aimeat-data.js) - Memory storage, search, key-value data\n';
3680
+ prompt += '- aimeat-storage (' + nodeUrl + '/v1/libs/aimeat-storage.js) - File upload/download\n';
3681
+ prompt += '- aimeat-social (' + nodeUrl + '/v1/libs/aimeat-social.js) - Boards, posts, reactions\n';
3682
+ prompt += '- aimeat-wallet (' + nodeUrl + '/v1/libs/aimeat-wallet.js) - Balance, transactions\n';
3683
+ prompt += '- aimeat-work (' + nodeUrl + '/v1/libs/aimeat-work.js) - Actions, work requests\n\n';
3684
+
3685
+ // Cortex extension instructions
3686
+ if (selectedExts.length > 0) {
3687
+ prompt += '### Cortex Extensions (include these)\n\n';
3688
+ selectedExts.forEach(function(ext) {
3689
+ prompt += '#### ' + ext.name + '\n';
3690
+ prompt += ext.description ? ext.description + '\n' : '';
3691
+
3692
+ // Use detailed components if available
3693
+ var comps = ext.components;
3694
+ if (comps && comps.length) {
3695
+ comps.forEach(function(c) {
3696
+ if (c.type === 'lib' && c.filename) {
3697
+ prompt += 'Load the library:\n```html\n';
3698
+ prompt += '<script src="' + nodeUrl + '/v1/cortex/' + encodeURIComponent(ext.name) + '/libs/' + encodeURIComponent(c.filename) + '"></' + 'script>\n';
3699
+ prompt += '```\n';
3700
+ if (c.api_surface) {
3701
+ prompt += 'API Surface:\n```\n' + c.api_surface + '\n```\n';
3702
+ }
3703
+ } else if (c.type === 'schema') {
3704
+ prompt += 'Data schema: `' + (c.key_pattern || '') + '` — data is validated automatically.\n';
3705
+ } else if (c.type === 'prompt') {
3706
+ prompt += 'Prompt template: ' + (c.name || '') + '\n';
3707
+ }
3708
+ });
3709
+ } else {
3710
+ // Fallback: only list-level type info
3711
+ var types = ext.component_types || [];
3712
+ if (types.indexOf('lib') !== -1) {
3713
+ prompt += 'Includes a JS library (load via `<script src="' + nodeUrl + '/v1/cortex/' + encodeURIComponent(ext.name) + '/libs/...">`).\n';
3714
+ }
3715
+ if (types.indexOf('schema') !== -1) {
3716
+ prompt += 'Provides validated data schemas.\n';
3717
+ }
3718
+ if (types.indexOf('prompt') !== -1) {
3719
+ prompt += 'Includes prompt templates.\n';
3720
+ }
3721
+ }
3722
+ prompt += '\n';
3723
+ });
3724
+ }
3725
+
3726
+ // Auth pattern
3727
+ prompt += '### Auth Pattern\n';
3728
+ prompt += '```html\n';
3729
+ prompt += '<script src="' + nodeUrl + '/v1/libs/aimeat-auth.js"></' + 'script>\n';
3730
+ prompt += '<script>\n';
3731
+ prompt += 'AIMEAT.auth.mountLoginButton("#login", {\n';
3732
+ prompt += ' onLogin: function(session) { /* session.owner, session.jwt, session.fetch() */ },\n';
3733
+ prompt += ' onLogout: function() { /* hide content */ }\n';
3734
+ prompt += '});\n';
3735
+ prompt += '</' + 'script>\n';
3736
+ prompt += '```\n\n';
3737
+
3738
+ // Data storage
3739
+ prompt += '### Data Storage\n';
3740
+ prompt += '```javascript\n';
3741
+ prompt += 'await AIMEAT.data.set("key", "value", { visibility: "private", tags: ["t1"] });\n';
3742
+ prompt += 'var val = await AIMEAT.data.get("key");\n';
3743
+ prompt += 'var results = await AIMEAT.data.search("query");\n';
3744
+ prompt += '```\n\n';
3745
+
3746
+ // Design guidelines
3747
+ prompt += '### Design Guidelines\n';
3748
+ prompt += 'Recommended light theme:\n';
3749
+ prompt += '```css\n';
3750
+ prompt += ':root { --bg:#FAFAF8; --card:#FFFFFF; --text:#1A1A2E;\n';
3751
+ prompt += ' --accent:#E8564A; --border:#E5E7EB; --radius:12px; }\n';
3752
+ prompt += '```\n';
3753
+ prompt += 'Always include: <meta name="viewport" content="width=device-width, initial-scale=1.0">\n';
3754
+ prompt += 'Mobile-first responsive. Single HTML file with embedded CSS and JS.\n\n';
3755
+
3756
+ // Rules
3757
+ prompt += '### Important Rules\n';
3758
+ prompt += '- Return the COMPLETE HTML file, not fragments\n';
3759
+ prompt += '- Never use literal closing script tags in JS comments or strings\n';
3760
+ prompt += '- Keep it as a single self-contained HTML file\n';
3761
+ prompt += '- Include error handling and loading states for API calls\n\n';
3762
+
3763
+ // Source code for improve mode
3764
+ if (mode === 'improve' && pbSourceApp && pbSourceApp.blob) {
3765
+ var source = decodeURIComponent(escape(atob(pbSourceApp.blob)));
3766
+ prompt += '--- Source Code ---\n' + source;
3767
+ }
3768
+
3769
+ return prompt;
3770
+ }
3771
+
3772
+ function updatePbPreview() {
3773
+ var preview = document.getElementById('pb-preview');
3774
+ var prompt = buildPromptFromBuilder();
3775
+ // Show first ~2000 chars with truncation indicator
3776
+ if (prompt.length > 2000) {
3777
+ preview.textContent = prompt.substring(0, 2000) + '\n\n... (' + prompt.length + ' chars total)';
3778
+ } else {
3779
+ preview.textContent = prompt;
3780
+ }
3781
+ }
3782
+
3783
+ // ── Drag & Drop Reordering ─────────────────────
3784
+
3785
+ var dragSourceId = null;
3786
+
3787
+ function onCardDragStart(e) {
3788
+ var card = e.target.closest('.app-card');
3789
+ if (!card) return;
3790
+ dragSourceId = card.dataset.id;
3791
+ card.classList.add('dragging');
3792
+ e.dataTransfer.effectAllowed = 'move';
3793
+ e.dataTransfer.setData('text/plain', dragSourceId);
3794
+ }
3795
+
3796
+ function onCardDragEnd(e) {
3797
+ var card = e.target.closest('.app-card');
3798
+ if (card) card.classList.remove('dragging');
3799
+ // Remove all drag-over highlights
3800
+ var cards = document.querySelectorAll('.app-card.drag-over');
3801
+ for (var i = 0; i < cards.length; i++) cards[i].classList.remove('drag-over');
3802
+ dragSourceId = null;
3803
+ }
3804
+
3805
+ function onCardDragOver(e) {
3806
+ e.preventDefault();
3807
+ e.dataTransfer.dropEffect = 'move';
3808
+ var card = e.target.closest('.app-card');
3809
+ if (!card || card.dataset.id === dragSourceId) return;
3810
+ // Remove highlight from others
3811
+ var cards = document.querySelectorAll('.app-card.drag-over');
3812
+ for (var i = 0; i < cards.length; i++) cards[i].classList.remove('drag-over');
3813
+ card.classList.add('drag-over');
3814
+ }
3815
+
3816
+ function onCardDrop(e) {
3817
+ e.preventDefault();
3818
+ var targetCard = e.target.closest('.app-card');
3819
+ if (!targetCard) return;
3820
+ var targetId = targetCard.dataset.id;
3821
+ if (!dragSourceId || dragSourceId === targetId) return;
3822
+
3823
+ // Find indexes in the currently rendered/sorted allApps
3824
+ var srcIdx = -1, tgtIdx = -1;
3825
+ for (var i = 0; i < allApps.length; i++) {
3826
+ if (allApps[i].id === dragSourceId) srcIdx = i;
3827
+ if (allApps[i].id === targetId) tgtIdx = i;
3828
+ }
3829
+ if (srcIdx === -1 || tgtIdx === -1) return;
3830
+
3831
+ // Move the source app to the target position
3832
+ var moved = allApps.splice(srcIdx, 1)[0];
3833
+ allApps.splice(tgtIdx, 0, moved);
3834
+
3835
+ // Assign sortOrder values based on new positions
3836
+ var saves = [];
3837
+ for (var j = 0; j < allApps.length; j++) {
3838
+ allApps[j].sortOrder = j;
3839
+ saves.push(saveApp(allApps[j]));
3840
+ }
3841
+
3842
+ // Re-render immediately (no animation delay for reorder)
3843
+ var grid = document.getElementById('app-grid');
3844
+ var cards = grid.querySelectorAll('.app-card');
3845
+ for (var k = 0; k < cards.length; k++) {
3846
+ cards[k].classList.remove('drag-over', 'dragging');
3847
+ }
3848
+
3849
+ Promise.all(saves).then(function () {
3850
+ renderApps();
3851
+ });
3852
+ }
3853
+
3854
+ // ── Public API ────────────────────────────────────
3855
+
3856
+ window._launcher = {
3857
+ openDB: openDB,
3858
+ getAllApps: getAllApps,
3859
+ saveApp: saveApp,
3860
+ deleteApp: deleteApp,
3861
+ loadConfig: loadConfig,
3862
+ saveConfig: saveConfig,
3863
+ renderApps: renderApps,
3864
+ renderTags: renderTags,
3865
+ filterByTag: filterByTag,
3866
+ launchApp: launchApp,
3867
+ launchInTab: launchInTab,
3868
+ launchInIframe: launchInIframe,
3869
+ closeIframe: closeIframe,
3870
+ openExternal: openExternal,
3871
+ setCurrentIframeUrl: function (url) { currentIframeUrl = url; },
3872
+ showContextMenu: showContextMenu,
3873
+ hideContextMenu: hideContextMenu,
3874
+ handleContextAction: handleContextAction,
3875
+ generateId: generateId,
3876
+ readFileAsText: readFileAsText,
3877
+ addAppFromUrl: addAppFromUrl,
3878
+ addAppFromFile: addAppFromFile,
3879
+ addAppFromSource: addAppFromSource,
3880
+ addAppFromZip: addAppFromZip,
3881
+ showModal: showModal,
3882
+ closeModal: closeModal,
3883
+ openSettings: openSettings,
3884
+ saveSettings: saveSettings,
3885
+ closeSettings: closeSettings,
3886
+ applyTheme: applyTheme,
3887
+ exportBackup: exportBackup,
3888
+ clearAllData: clearAllData,
3889
+ importFromAimeat: importFromAimeat,
3890
+ processAimeatImport: processAimeatImport,
3891
+ viewSource: viewSource,
3892
+ generateHomepagePrompt: generateHomepagePrompt,
3893
+ showPublishModal: showPublishModal,
3894
+ submitPublish: submitPublish,
3895
+ loadPublishedApps: loadPublishedApps,
3896
+ togglePublished: togglePublished,
3897
+ unpublishApp: unpublishApp,
3898
+ renderRecentlyOpened: renderRecentlyOpened,
3899
+ loadCortexExtensions: loadCortexExtensions,
3900
+ showCortexPopup: showCortexPopup,
3901
+ cortexCopy: cortexCopy,
3902
+ openCortexEditor: openCortexEditor,
3903
+ closeCortexEditor: closeCortexEditor,
3904
+ cortexEditorAddLib: cortexEditorAddLib,
3905
+ cortexEditorSave: cortexEditorSave,
3906
+ cortexEditorExport: cortexEditorExport,
3907
+ openPromptBuilder: openPromptBuilder,
3908
+ closePbPanel: closePbPanel,
3909
+ onCardDragStart: onCardDragStart,
3910
+ onCardDragEnd: onCardDragEnd,
3911
+ onCardDragOver: onCardDragOver,
3912
+ onCardDrop: onCardDrop,
3913
+ syncConfigToServer: syncConfigToServer,
3914
+ loadConfigFromServer: loadConfigFromServer
3915
+ };
3916
+
3917
+ // Expose cortex functions globally for inline onclick handlers
3918
+ window.showCortexPopup = showCortexPopup;
3919
+ window.cortexCopy = cortexCopy;
3920
+
3921
+ // ── Bootstrap ─────────────────────────────────────
3922
+
3923
+ document.addEventListener('DOMContentLoaded', function () {
3924
+ // ── Apply theme on load ─────────────────────────
3925
+ applyTheme(loadConfig().theme);
3926
+
3927
+ renderApps();
3928
+ loadPublishedApps();
3929
+ loadCortexExtensions();
3930
+ loadConfigFromServer();
3931
+
3932
+ // ── Search input ─────────────────────────────────
3933
+ document.getElementById('search-input').addEventListener('input', function (e) {
3934
+ searchQuery = e.target.value.trim();
3935
+ renderApps();
3936
+ });
3937
+
3938
+ // ── Add App button ──────────────────────────────
3939
+ document.getElementById('add-btn').addEventListener('click', function () {
3940
+ showModal();
3941
+ });
3942
+
3943
+ // ── Generate with AI button ─────────────────────
3944
+ document.getElementById('generate-btn').addEventListener('click', function () {
3945
+ openPromptBuilder(null);
3946
+ });
3947
+
3948
+ // ── Settings button ─────────────────────────────
3949
+ document.getElementById('settings-btn').addEventListener('click', function () {
3950
+ openSettings();
3951
+ });
3952
+
3953
+ // ── Settings save / cancel ──────────────────────
3954
+ document.getElementById('settings-save-btn').addEventListener('click', function () {
3955
+ saveSettings();
3956
+ });
3957
+
3958
+ document.getElementById('settings-cancel-btn').addEventListener('click', function () {
3959
+ closeSettings();
3960
+ });
3961
+
3962
+ // ── Click settings overlay to close ─────────────
3963
+ document.getElementById('settings-overlay').addEventListener('click', function (e) {
3964
+ if (e.target === this) {
3965
+ closeSettings();
3966
+ }
3967
+ });
3968
+
3969
+ // ── Import backup file input ────────────────────
3970
+ document.getElementById('import-file-input').addEventListener('change', function () {
3971
+ if (this.files && this.files.length > 0) {
3972
+ handleImportBackup(this.files[0]);
3973
+ this.value = ''; // Reset for re-import
3974
+ }
3975
+ });
3976
+
3977
+ // ── Click AIMEAT import overlay to close ────────
3978
+ document.getElementById('aimeat-import-overlay').addEventListener('click', function (e) {
3979
+ if (e.target === this) {
3980
+ this.hidden = true;
3981
+ }
3982
+ });
3983
+
3984
+ // ── Click publish overlay to close ──────────────
3985
+ document.getElementById('publish-overlay').addEventListener('click', function (e) {
3986
+ if (e.target === this) {
3987
+ this.hidden = true;
3988
+ }
3989
+ });
3990
+
3991
+ // ── Click cortex popup overlay to close ─────────
3992
+ document.getElementById('cortex-popup-overlay').addEventListener('click', function (e) {
3993
+ if (e.target === this) {
3994
+ this.style.display = 'none';
3995
+ }
3996
+ });
3997
+
3998
+ // ── Click cortex editor overlay to close ────────
3999
+ document.getElementById('cortex-editor-overlay').addEventListener('click', function (e) {
4000
+ if (e.target === this) {
4001
+ closeCortexEditor();
4002
+ }
4003
+ });
4004
+
4005
+ // ── Tab switching ───────────────────────────────
4006
+ var tabBtns = document.querySelectorAll('#add-app-modal .modal-tab');
4007
+ tabBtns.forEach(function (btn) {
4008
+ btn.addEventListener('click', function () {
4009
+ switchTab(btn.getAttribute('data-tab'));
4010
+ });
4011
+ });
4012
+
4013
+ // ── Drop zone events ────────────────────────────
4014
+ var dropZone = document.getElementById('drop-zone');
4015
+ var fileInput = document.getElementById('file-input');
4016
+ var browseBtn = document.getElementById('browse-btn');
4017
+
4018
+ dropZone.addEventListener('dragover', function (e) {
4019
+ e.preventDefault();
4020
+ e.stopPropagation();
4021
+ dropZone.classList.add('dragover');
4022
+ });
4023
+
4024
+ dropZone.addEventListener('dragleave', function (e) {
4025
+ e.preventDefault();
4026
+ e.stopPropagation();
4027
+ dropZone.classList.remove('dragover');
4028
+ });
4029
+
4030
+ dropZone.addEventListener('drop', function (e) {
4031
+ e.preventDefault();
4032
+ e.stopPropagation();
4033
+ dropZone.classList.remove('dragover');
4034
+ if (e.dataTransfer && e.dataTransfer.files && e.dataTransfer.files.length > 0) {
4035
+ handleFileDrop(e.dataTransfer.files[0]);
4036
+ }
4037
+ });
4038
+
4039
+ browseBtn.addEventListener('click', function (e) {
4040
+ e.stopPropagation();
4041
+ fileInput.click();
4042
+ });
4043
+
4044
+ fileInput.addEventListener('change', function () {
4045
+ if (fileInput.files && fileInput.files.length > 0) {
4046
+ handleFileDrop(fileInput.files[0]);
4047
+ }
4048
+ });
4049
+
4050
+ // ── Modal save / cancel ─────────────────────────
4051
+ document.getElementById('modal-save-btn').addEventListener('click', function () {
4052
+ handleSave();
4053
+ });
4054
+
4055
+ document.getElementById('modal-cancel-btn').addEventListener('click', function () {
4056
+ closeModal();
4057
+ });
4058
+
4059
+ // ── Click overlay to close ──────────────────────
4060
+ document.getElementById('modal-overlay').addEventListener('click', function (e) {
4061
+ if (e.target === this) {
4062
+ closeModal();
4063
+ }
4064
+ });
4065
+
4066
+ // ── Context menu action buttons ─────────────────
4067
+ var contextMenu = document.getElementById('context-menu');
4068
+ var contextBtns = contextMenu.querySelectorAll('button[data-action]');
4069
+ contextBtns.forEach(function (btn) {
4070
+ btn.addEventListener('click', function (e) {
4071
+ e.stopPropagation();
4072
+ handleContextAction(btn.getAttribute('data-action'));
4073
+ });
4074
+ });
4075
+
4076
+ // ── PostMessage auth protocol for sandboxed iframes ──
4077
+ window.addEventListener('message', function(e) {
4078
+ var iframe = document.getElementById('app-iframe');
4079
+ if (!iframe || !iframe.contentWindow) return;
4080
+ // Only respond to messages from our iframe
4081
+ if (e.source !== iframe.contentWindow) return;
4082
+ if (!e.data || e.data.type !== 'aimeat-request-auth') return;
4083
+
4084
+ // Get JWT from aimeat-auth library if available, else from localStorage
4085
+ var jwt = null;
4086
+ var nodeUrl = '';
4087
+ try {
4088
+ if (window.AIMEAT && window.AIMEAT.auth && window.AIMEAT.auth.getSession()) {
4089
+ var session = window.AIMEAT.auth.getSession();
4090
+ jwt = session.jwt;
4091
+ nodeUrl = session.nodeUrl || '';
4092
+ } else {
4093
+ var stored = localStorage.getItem('aimeat_session');
4094
+ if (stored) {
4095
+ var parsed = JSON.parse(stored);
4096
+ jwt = parsed.jwt || null;
4097
+ }
4098
+ var config = loadConfig();
4099
+ nodeUrl = config.aimeatUrl || '';
4100
+ }
4101
+ } catch(err) { /* ignore parse errors */ }
4102
+
4103
+ iframe.contentWindow.postMessage({
4104
+ type: 'aimeat-auth',
4105
+ jwt: jwt,
4106
+ nodeUrl: nodeUrl
4107
+ }, '*');
4108
+ });
4109
+
4110
+ // ── Click anywhere to close context menu ────────
4111
+ document.addEventListener('click', function () {
4112
+ hideContextMenu();
4113
+ });
4114
+
4115
+ // ── Keyboard shortcuts ──────────────────────────
4116
+ document.addEventListener('keydown', function (e) {
4117
+ // Escape — close modals / overlays (source-overlay first in cascade)
4118
+ if (e.key === 'Escape') {
4119
+ if (document.getElementById('cortex-editor-overlay').style.display === 'flex') {
4120
+ closeCortexEditor();
4121
+ } else if (document.getElementById('prompt-builder-overlay').style.display === 'flex') {
4122
+ closePbPanel();
4123
+ } else if (!document.getElementById('source-overlay').hidden) {
4124
+ document.getElementById('source-overlay').hidden = true;
4125
+ } else if (!document.getElementById('context-menu').hidden) {
4126
+ hideContextMenu();
4127
+ } else if (!document.getElementById('aimeat-import-overlay').hidden) {
4128
+ document.getElementById('aimeat-import-overlay').hidden = true;
4129
+ } else if (!document.getElementById('publish-overlay').hidden) {
4130
+ document.getElementById('publish-overlay').hidden = true;
4131
+ } else if (!document.getElementById('settings-overlay').hidden) {
4132
+ closeSettings();
4133
+ } else if (!document.getElementById('modal-overlay').hidden) {
4134
+ closeModal();
4135
+ }
4136
+ return;
4137
+ }
4138
+ // Ctrl+N / Cmd+N — open Add App modal
4139
+ if ((e.ctrlKey || e.metaKey) && e.key === 'n') {
4140
+ e.preventDefault();
4141
+ showModal();
4142
+ return;
4143
+ }
4144
+ // Ctrl+F / Cmd+F — focus search
4145
+ if ((e.ctrlKey || e.metaKey) && e.key === 'f') {
4146
+ e.preventDefault();
4147
+ document.getElementById('search-input').focus();
4148
+ }
4149
+ });
4150
+
4151
+ // ── Long-press for touch devices ─────────────────
4152
+ document.getElementById('app-grid').addEventListener('touchstart', function(e) {
4153
+ var card = e.target.closest('.app-card');
4154
+ if (!card) return;
4155
+ var appId = card.getAttribute('data-id');
4156
+ card._longPressTimer = setTimeout(function() {
4157
+ e.preventDefault();
4158
+ window._launcher.showContextMenu(e.touches[0], appId);
4159
+ }, 500);
4160
+ }, { passive: false });
4161
+
4162
+ document.getElementById('app-grid').addEventListener('touchend', function(e) {
4163
+ var card = e.target.closest('.app-card');
4164
+ if (card && card._longPressTimer) clearTimeout(card._longPressTimer);
4165
+ });
4166
+
4167
+ document.getElementById('app-grid').addEventListener('touchmove', function(e) {
4168
+ var card = e.target.closest('.app-card');
4169
+ if (card && card._longPressTimer) clearTimeout(card._longPressTimer);
4170
+ });
4171
+
4172
+ // ── Copy Source button ───────────────────────────
4173
+ document.getElementById('copy-source-btn').addEventListener('click', function() {
4174
+ var code = document.getElementById('source-code').value;
4175
+ var btn = this;
4176
+ if (navigator.clipboard && navigator.clipboard.writeText) {
4177
+ navigator.clipboard.writeText(code).then(function() {
4178
+ btn.textContent = 'Copied!';
4179
+ setTimeout(function() { btn.textContent = 'Copy Source'; }, 1500);
4180
+ });
4181
+ } else {
4182
+ // Fallback: select text in textarea
4183
+ var ta = document.getElementById('source-code');
4184
+ ta.select();
4185
+ document.execCommand('copy');
4186
+ btn.textContent = 'Copied!';
4187
+ setTimeout(function() { btn.textContent = 'Copy Source'; }, 1500);
4188
+ }
4189
+ });
4190
+
4191
+ // ── Build rich AI prompt with AIMEAT instructions ─
4192
+ function buildAiPrompt(appName, code) {
4193
+ var config = loadConfig();
4194
+ var nodeUrl = config.aimeatUrl ? config.aimeatUrl.replace(/\/+$/, '') : 'https://your-aimeat-node.example';
4195
+
4196
+ return 'Here is an HTML app called "' + appName + '".\n' +
4197
+ 'Make the following change: [DESCRIBE YOUR CHANGE HERE]\n\n' +
4198
+ 'Return the COMPLETE updated HTML file. Do not omit any parts.\n\n' +
4199
+ '## AIMEAT Platform Instructions\n\n' +
4200
+ 'This app runs in the AIMEAT ecosystem. Here is what you need to know:\n\n' +
4201
+ '### Available Client Libraries\n' +
4202
+ 'Load via script tags from the AIMEAT node (' + nodeUrl + '):\n' +
4203
+ '- aimeat-auth (' + nodeUrl + '/v1/libs/aimeat-auth.js) - Identity, login, JWT, session management\n' +
4204
+ '- aimeat-data (' + nodeUrl + '/v1/libs/aimeat-data.js) - Memory storage, search, key-value data\n' +
4205
+ '- aimeat-storage (' + nodeUrl + '/v1/libs/aimeat-storage.js) - File upload/download\n' +
4206
+ '- aimeat-social (' + nodeUrl + '/v1/libs/aimeat-social.js) - Boards, posts, reactions\n' +
4207
+ '- aimeat-wallet (' + nodeUrl + '/v1/libs/aimeat-wallet.js) - Balance, transactions\n' +
4208
+ '- aimeat-work (' + nodeUrl + '/v1/libs/aimeat-work.js) - Actions, work requests\n\n' +
4209
+ '### Auth Pattern\n' +
4210
+ '```html\n' +
4211
+ '<script src="' + nodeUrl + '/v1/libs/aimeat-auth.js"></' + 'script>\n' +
4212
+ '<script>\n' +
4213
+ 'AIMEAT.auth.mountLoginButton("#login", {\n' +
4214
+ ' onLogin: function(session) { /* session.owner, session.jwt, session.fetch() */ },\n' +
4215
+ ' onLogout: function() { /* hide content */ }\n' +
4216
+ '});\n' +
4217
+ '</' + 'script>\n' +
4218
+ '```\n\n' +
4219
+ '### Data Storage\n' +
4220
+ '```javascript\n' +
4221
+ 'await AIMEAT.data.set("key", "value", { visibility: "private", tags: ["t1"] });\n' +
4222
+ 'var val = await AIMEAT.data.get("key");\n' +
4223
+ 'var results = await AIMEAT.data.search("query");\n' +
4224
+ '```\n\n' +
4225
+ '### Upload to AIMEAT Node\n' +
4226
+ 'After updating, the user can upload the app to their AIMEAT node:\n' +
4227
+ '```\n' +
4228
+ 'POST ' + nodeUrl + '/v1/apps\n' +
4229
+ 'Authorization: Bearer <jwt>\n' +
4230
+ 'Content-Type: application/json\n' +
4231
+ '{ "filename": "app.html", "content": "<base64>", "mime_type": "text/html" }\n' +
4232
+ '```\n\n' +
4233
+ '### Self-Download Pattern\n' +
4234
+ 'Include a download button so users can save the app:\n' +
4235
+ '```javascript\n' +
4236
+ 'function downloadSelf() {\n' +
4237
+ ' var html = document.documentElement.outerHTML;\n' +
4238
+ ' var blob = new Blob(["<!DOCTYPE html>" + html], {type:"text/html"});\n' +
4239
+ ' var a = document.createElement("a");\n' +
4240
+ ' a.href = URL.createObjectURL(blob); a.download = "my-app.html"; a.click();\n' +
4241
+ '}\n' +
4242
+ '```\n\n' +
4243
+ '### Browser APIs Available\n' +
4244
+ 'Canvas, WebGL, Web Audio, WebRTC, Camera, Geolocation, LocalStorage, IndexedDB,\n' +
4245
+ 'Notifications, Drag & Drop, Clipboard, Speech API, Fullscreen, Web Workers,\n' +
4246
+ 'CSS Animations, SVG, Gamepad API, Share API.\n\n' +
4247
+ '### Design Guidelines\n' +
4248
+ 'Recommended light theme:\n' +
4249
+ '```css\n' +
4250
+ ':root { --bg:#FAFAF8; --card:#FFFFFF; --text:#1A1A2E;\n' +
4251
+ ' --accent:#E8564A; --border:#E5E7EB; --radius:12px; }\n' +
4252
+ '```\n' +
4253
+ 'Always include: <meta name="viewport" content="width=device-width, initial-scale=1.0">\n' +
4254
+ 'Mobile-first responsive. Single HTML file with embedded CSS and JS.\n\n' +
4255
+ '### Important Rules\n' +
4256
+ '- Return the COMPLETE HTML file, not fragments\n' +
4257
+ '- Never use literal closing script tags in JS comments or strings (breaks HTML parser)\n' +
4258
+ '- Keep it as a single self-contained HTML file\n' +
4259
+ '- Include error handling and loading states for API calls\n\n' +
4260
+ '--- Source Code ---\n' + code;
4261
+ }
4262
+
4263
+ // ── Copy with AI Prompt button → opens Prompt Builder ───
4264
+ document.getElementById('copy-prompt-btn').addEventListener('click', function() {
4265
+ var overlay = document.getElementById('source-overlay');
4266
+ var appId = overlay.dataset.appId;
4267
+ var app = null;
4268
+ for (var i = 0; i < allApps.length; i++) {
4269
+ if (allApps[i].id === appId) { app = allApps[i]; break; }
4270
+ }
4271
+ openPromptBuilder(app);
4272
+ });
4273
+
4274
+ // ── Enable/disable Save button when source changes ─
4275
+ document.getElementById('source-code').addEventListener('input', function() {
4276
+ var overlay = document.getElementById('source-overlay');
4277
+ var saveBtn = document.getElementById('save-source-btn');
4278
+ var original = overlay.dataset.originalSource || '';
4279
+ saveBtn.disabled = (this.value === original);
4280
+ });
4281
+
4282
+ // ── Save Changes button ──────────────────────────
4283
+ document.getElementById('save-source-btn').addEventListener('click', function() {
4284
+ var overlay = document.getElementById('source-overlay');
4285
+ var textarea = document.getElementById('source-code');
4286
+ var appId = overlay.dataset.appId;
4287
+ var btn = this;
4288
+
4289
+ if (!appId) {
4290
+ alert('Cannot save: no app ID found.');
4291
+ return;
4292
+ }
4293
+
4294
+ var newSource = textarea.value;
4295
+ // Encode to base64 blob
4296
+ var newBlob = btoa(unescape(encodeURIComponent(newSource)));
4297
+
4298
+ // Find the app in allApps and update it
4299
+ var app = null;
4300
+ for (var i = 0; i < allApps.length; i++) {
4301
+ if (allApps[i].id === appId) {
4302
+ app = allApps[i];
4303
+ break;
4304
+ }
4305
+ }
4306
+
4307
+ if (!app) {
4308
+ alert('App not found in library.');
4309
+ return;
4310
+ }
4311
+
4312
+ app.blob = newBlob;
4313
+ btn.textContent = 'Saving...';
4314
+ btn.disabled = true;
4315
+
4316
+ saveApp(app).then(function() {
4317
+ btn.textContent = 'Saved!';
4318
+ overlay.dataset.originalSource = newSource;
4319
+ setTimeout(function() {
4320
+ btn.textContent = 'Save Changes';
4321
+ btn.disabled = true;
4322
+ }, 1500);
4323
+ renderApps();
4324
+ }).catch(function(err) {
4325
+ btn.textContent = 'Save Changes';
4326
+ btn.disabled = false;
4327
+ alert('Failed to save: ' + (err.message || err));
4328
+ });
4329
+ });
4330
+
4331
+ // ── Close source modal helper ─────────────────────
4332
+ function closeSourceModal() {
4333
+ var saveBtn = document.getElementById('save-source-btn');
4334
+ if (!saveBtn.disabled) {
4335
+ if (!confirm('You have unsaved changes. Close anyway?')) return;
4336
+ }
4337
+ document.getElementById('source-overlay').hidden = true;
4338
+ }
4339
+
4340
+ // ── Click source overlay background to close ─────
4341
+ document.getElementById('source-overlay').addEventListener('click', function(e) {
4342
+ if (e.target === this) closeSourceModal();
4343
+ });
4344
+
4345
+ // ── Close button in source modal ─────────────────
4346
+ document.getElementById('close-source-btn').addEventListener('click', closeSourceModal);
4347
+
4348
+ // ── Homepage button ──────────────────────────────
4349
+ document.getElementById('homepage-btn').addEventListener('click', generateHomepagePrompt);
4350
+
4351
+ // ── Prompt Builder event listeners ───────────────
4352
+ document.getElementById('pb-cancel-btn').addEventListener('click', closePbPanel);
4353
+
4354
+ document.getElementById('pb-copy-btn').addEventListener('click', function() {
4355
+ var prompt = buildPromptFromBuilder();
4356
+ var btn = this;
4357
+ if (navigator.clipboard && navigator.clipboard.writeText) {
4358
+ navigator.clipboard.writeText(prompt).then(function() {
4359
+ btn.textContent = 'Copied!';
4360
+ setTimeout(function() { btn.textContent = 'Copy Prompt'; closePbPanel(); }, 1200);
4361
+ });
4362
+ } else {
4363
+ var ta = document.createElement('textarea');
4364
+ ta.value = prompt;
4365
+ document.body.appendChild(ta);
4366
+ ta.select();
4367
+ document.execCommand('copy');
4368
+ document.body.removeChild(ta);
4369
+ btn.textContent = 'Copied!';
4370
+ setTimeout(function() { btn.textContent = 'Copy Prompt'; closePbPanel(); }, 1200);
4371
+ }
4372
+ });
4373
+
4374
+ document.getElementById('pb-ext-checkbox').addEventListener('change', function() {
4375
+ document.getElementById('pb-ext-list').classList.toggle('open', this.checked);
4376
+ updatePbPreview();
4377
+ });
4378
+
4379
+ document.querySelectorAll('input[name="pb-mode"]').forEach(function(radio) {
4380
+ radio.addEventListener('change', function() {
4381
+ var desc = document.getElementById('pb-description');
4382
+ if (this.value === 'improve' && pbSourceApp) {
4383
+ desc.placeholder = 'Describe what changes to make to "' + (pbSourceApp.name || 'this app') + '"...';
4384
+ } else {
4385
+ desc.placeholder = 'Describe what the app should do...';
4386
+ }
4387
+ updatePbPreview();
4388
+ });
4389
+ });
4390
+
4391
+ document.getElementById('pb-description').addEventListener('input', updatePbPreview);
4392
+
4393
+ document.getElementById('prompt-builder-overlay').addEventListener('click', function(e) {
4394
+ if (e.target === this) closePbPanel();
4395
+ });
4396
+ });
4397
+
4398
+ })();
4399
+ </script>
4400
+ </body>
4401
+ </html>