aimeat 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (412) hide show
  1. package/dist/locales/en.json +35 -1
  2. package/dist/locales/fi.json +35 -1
  3. package/dist/public/components/LinkPreview.js +101 -0
  4. package/dist/public/components/NotificationBell.js +18 -1
  5. package/dist/public/css/theme.css +57 -7
  6. package/dist/public/css/views/admin.css +8 -1
  7. package/dist/public/css/views/app-grant.css +18 -0
  8. package/dist/public/css/views/inbox.css +46 -0
  9. package/dist/public/css/views/portfolio.css +46 -0
  10. package/dist/public/css/views/profile.css +29 -4
  11. package/dist/public/js/services/apps.js +19 -3
  12. package/dist/public/js/services/messages-ai-prompts.js +38 -0
  13. package/dist/public/js/services/messages.js +26 -4
  14. package/dist/public/js/services/notebook.js +76 -0
  15. package/dist/public/js/services/unfurl.js +43 -0
  16. package/dist/public/lib/samples/LICENSE.md +11 -0
  17. package/dist/public/lib/samples/bass/A1.mp3 +0 -0
  18. package/dist/public/lib/samples/bass/B2.mp3 +0 -0
  19. package/dist/public/lib/samples/bass/D2.mp3 +0 -0
  20. package/dist/public/lib/samples/bass/E1.mp3 +0 -0
  21. package/dist/public/lib/samples/bass/E3.mp3 +0 -0
  22. package/dist/public/lib/samples/bass/G2.mp3 +0 -0
  23. package/dist/public/lib/samples/epiano/C2.mp3 +0 -0
  24. package/dist/public/lib/samples/epiano/C3.mp3 +0 -0
  25. package/dist/public/lib/samples/epiano/C4.mp3 +0 -0
  26. package/dist/public/lib/samples/epiano/C5.mp3 +0 -0
  27. package/dist/public/lib/samples/epiano/C6.mp3 +0 -0
  28. package/dist/public/lib/samples/epiano/G2.mp3 +0 -0
  29. package/dist/public/lib/samples/epiano/G3.mp3 +0 -0
  30. package/dist/public/lib/samples/epiano/G4.mp3 +0 -0
  31. package/dist/public/lib/samples/epiano/G5.mp3 +0 -0
  32. package/dist/public/lib/samples/guitar-steel/A2.mp3 +0 -0
  33. package/dist/public/lib/samples/guitar-steel/A4.mp3 +0 -0
  34. package/dist/public/lib/samples/guitar-steel/B3.mp3 +0 -0
  35. package/dist/public/lib/samples/guitar-steel/D3.mp3 +0 -0
  36. package/dist/public/lib/samples/guitar-steel/E2.mp3 +0 -0
  37. package/dist/public/lib/samples/guitar-steel/E4.mp3 +0 -0
  38. package/dist/public/lib/samples/guitar-steel/E5.mp3 +0 -0
  39. package/dist/public/lib/samples/guitar-steel/G3.mp3 +0 -0
  40. package/dist/public/lib/samples/organ/C2.mp3 +0 -0
  41. package/dist/public/lib/samples/organ/C3.mp3 +0 -0
  42. package/dist/public/lib/samples/organ/C4.mp3 +0 -0
  43. package/dist/public/lib/samples/organ/C5.mp3 +0 -0
  44. package/dist/public/lib/samples/organ/C6.mp3 +0 -0
  45. package/dist/public/lib/samples/organ/G2.mp3 +0 -0
  46. package/dist/public/lib/samples/organ/G3.mp3 +0 -0
  47. package/dist/public/lib/samples/organ/G4.mp3 +0 -0
  48. package/dist/public/lib/samples/organ/G5.mp3 +0 -0
  49. package/dist/public/lib/samples/strings/C2.mp3 +0 -0
  50. package/dist/public/lib/samples/strings/C3.mp3 +0 -0
  51. package/dist/public/lib/samples/strings/C4.mp3 +0 -0
  52. package/dist/public/lib/samples/strings/C5.mp3 +0 -0
  53. package/dist/public/lib/samples/strings/C6.mp3 +0 -0
  54. package/dist/public/lib/samples/strings/G2.mp3 +0 -0
  55. package/dist/public/lib/samples/strings/G3.mp3 +0 -0
  56. package/dist/public/lib/samples/strings/G4.mp3 +0 -0
  57. package/dist/public/lib/samples/strings/G5.mp3 +0 -0
  58. package/dist/public/lib/samples/trumpet/A3.mp3 +0 -0
  59. package/dist/public/lib/samples/trumpet/A4.mp3 +0 -0
  60. package/dist/public/lib/samples/trumpet/A5.mp3 +0 -0
  61. package/dist/public/lib/samples/trumpet/C4.mp3 +0 -0
  62. package/dist/public/lib/samples/trumpet/C5.mp3 +0 -0
  63. package/dist/public/lib/samples/trumpet/E3.mp3 +0 -0
  64. package/dist/public/lib/samples/trumpet/E4.mp3 +0 -0
  65. package/dist/public/lib/samples/trumpet/E5.mp3 +0 -0
  66. package/dist/public/spa.html +2 -0
  67. package/dist/public/views/app-grant.js +24 -4
  68. package/dist/public/views/portfolio.js +61 -6
  69. package/dist/public/views/profile/apps-tab.js +18 -1
  70. package/dist/public/views/profile/inbox-tab/ai-actions.js +86 -0
  71. package/dist/public/views/profile/inbox-tab/components.js +124 -9
  72. package/dist/public/views/profile/inbox-tab/helpers.js +26 -0
  73. package/dist/public/views/profile/inbox-tab/panels.js +18 -3
  74. package/dist/public/views/profile/inbox-tab/use-thread-ux.js +18 -1
  75. package/dist/public/views/profile/inbox-tab.js +46 -49
  76. package/dist/public/views/profile/landing-page.cards.js +7 -0
  77. package/dist/public/views/profile/landing-page.js +12 -1
  78. package/dist/public/views/profile/skills-tab.js +1 -1
  79. package/dist/public/views/public-workspace-viewer.js +1 -1
  80. package/dist/public/views/start.js +2 -1
  81. package/dist/scripts/build-sdk-libs.d.ts +16 -0
  82. package/dist/scripts/build-sdk-libs.d.ts.map +1 -0
  83. package/dist/scripts/build-sdk-libs.js +112 -0
  84. package/dist/scripts/build-sdk-libs.js.map +1 -0
  85. package/dist/src/cli/connect/auth.d.ts +15 -0
  86. package/dist/src/cli/connect/auth.d.ts.map +1 -1
  87. package/dist/src/cli/connect/auth.js +25 -6
  88. package/dist/src/cli/connect/auth.js.map +1 -1
  89. package/dist/src/cli/connect/keychain.d.ts +9 -0
  90. package/dist/src/cli/connect/keychain.d.ts.map +1 -1
  91. package/dist/src/cli/connect/keychain.js +21 -8
  92. package/dist/src/cli/connect/keychain.js.map +1 -1
  93. package/dist/src/cli/connect/mcp/tools/exchange.d.ts +18 -0
  94. package/dist/src/cli/connect/mcp/tools/exchange.d.ts.map +1 -0
  95. package/dist/src/cli/connect/mcp/tools/exchange.js +170 -0
  96. package/dist/src/cli/connect/mcp/tools/exchange.js.map +1 -0
  97. package/dist/src/cli/connect/mcp/tools/index.d.ts.map +1 -1
  98. package/dist/src/cli/connect/mcp/tools/index.js +2 -0
  99. package/dist/src/cli/connect/mcp/tools/index.js.map +1 -1
  100. package/dist/src/cli/connect/tool-call-defs-exchange.d.ts +3 -0
  101. package/dist/src/cli/connect/tool-call-defs-exchange.d.ts.map +1 -0
  102. package/dist/src/cli/connect/tool-call-defs-exchange.js +146 -0
  103. package/dist/src/cli/connect/tool-call-defs-exchange.js.map +1 -0
  104. package/dist/src/cli/connect/tool-call.d.ts.map +1 -1
  105. package/dist/src/cli/connect/tool-call.js +2 -0
  106. package/dist/src/cli/connect/tool-call.js.map +1 -1
  107. package/dist/src/commerce/session-service.d.ts +14 -0
  108. package/dist/src/commerce/session-service.d.ts.map +1 -1
  109. package/dist/src/commerce/session-service.js +1 -1
  110. package/dist/src/commerce/session-service.js.map +1 -1
  111. package/dist/src/data/app-templates/shells.d.ts +7 -3
  112. package/dist/src/data/app-templates/shells.d.ts.map +1 -1
  113. package/dist/src/data/app-templates/shells.js +10 -6
  114. package/dist/src/data/app-templates/shells.js.map +1 -1
  115. package/dist/src/data/appdev-pitfalls.d.ts +2 -0
  116. package/dist/src/data/appdev-pitfalls.d.ts.map +1 -1
  117. package/dist/src/data/appdev-pitfalls.js +24 -1
  118. package/dist/src/data/appdev-pitfalls.js.map +1 -1
  119. package/dist/src/generated/api-types.d.ts +1565 -9
  120. package/dist/src/generated/api-types.d.ts.map +1 -1
  121. package/dist/src/mcp/annotations.d.ts.map +1 -1
  122. package/dist/src/mcp/annotations.js +20 -0
  123. package/dist/src/mcp/annotations.js.map +1 -1
  124. package/dist/src/mcp/apps.d.ts.map +1 -1
  125. package/dist/src/mcp/apps.js +8 -4
  126. package/dist/src/mcp/apps.js.map +1 -1
  127. package/dist/src/mcp/catalog/definitions/exchange.d.ts +18 -0
  128. package/dist/src/mcp/catalog/definitions/exchange.d.ts.map +1 -0
  129. package/dist/src/mcp/catalog/definitions/exchange.js +182 -0
  130. package/dist/src/mcp/catalog/definitions/exchange.js.map +1 -0
  131. package/dist/src/mcp/catalog/definitions.d.ts.map +1 -1
  132. package/dist/src/mcp/catalog/definitions.js +2 -0
  133. package/dist/src/mcp/catalog/definitions.js.map +1 -1
  134. package/dist/src/mcp/catalog/scopes.d.ts.map +1 -1
  135. package/dist/src/mcp/catalog/scopes.js +22 -0
  136. package/dist/src/mcp/catalog/scopes.js.map +1 -1
  137. package/dist/src/mcp/catalog/surfaces.d.ts.map +1 -1
  138. package/dist/src/mcp/catalog/surfaces.js +14 -0
  139. package/dist/src/mcp/catalog/surfaces.js.map +1 -1
  140. package/dist/src/mcp/exchange-run.d.ts +5 -0
  141. package/dist/src/mcp/exchange-run.d.ts.map +1 -0
  142. package/dist/src/mcp/exchange-run.js +226 -0
  143. package/dist/src/mcp/exchange-run.js.map +1 -0
  144. package/dist/src/mcp/exchange.d.ts +5 -0
  145. package/dist/src/mcp/exchange.d.ts.map +1 -0
  146. package/dist/src/mcp/exchange.js +351 -0
  147. package/dist/src/mcp/exchange.js.map +1 -0
  148. package/dist/src/mcp/extensions.d.ts.map +1 -1
  149. package/dist/src/mcp/extensions.js +11 -0
  150. package/dist/src/mcp/extensions.js.map +1 -1
  151. package/dist/src/mcp/index.d.ts.map +1 -1
  152. package/dist/src/mcp/index.js +6 -2
  153. package/dist/src/mcp/index.js.map +1 -1
  154. package/dist/src/models/app-tool-schemas.d.ts +55 -1
  155. package/dist/src/models/app-tool-schemas.d.ts.map +1 -1
  156. package/dist/src/models/app-tool-schemas.js +20 -1
  157. package/dist/src/models/app-tool-schemas.js.map +1 -1
  158. package/dist/src/models/offer-schemas.d.ts +2 -2
  159. package/dist/src/models/schemas.d.ts +1 -0
  160. package/dist/src/models/schemas.d.ts.map +1 -1
  161. package/dist/src/models/schemas.js +3 -0
  162. package/dist/src/models/schemas.js.map +1 -1
  163. package/dist/src/routes/agents/device-auth.d.ts +4 -0
  164. package/dist/src/routes/agents/device-auth.d.ts.map +1 -1
  165. package/dist/src/routes/agents/device-auth.js +19 -4
  166. package/dist/src/routes/agents/device-auth.js.map +1 -1
  167. package/dist/src/routes/app-grants.d.ts +6 -0
  168. package/dist/src/routes/app-grants.d.ts.map +1 -1
  169. package/dist/src/routes/app-grants.js +35 -2
  170. package/dist/src/routes/app-grants.js.map +1 -1
  171. package/dist/src/routes/apps/fork-manage.d.ts.map +1 -1
  172. package/dist/src/routes/apps/fork-manage.js +24 -1
  173. package/dist/src/routes/apps/fork-manage.js.map +1 -1
  174. package/dist/src/routes/apps/publish.d.ts +2 -0
  175. package/dist/src/routes/apps/publish.d.ts.map +1 -1
  176. package/dist/src/routes/apps/publish.js +27 -1
  177. package/dist/src/routes/apps/publish.js.map +1 -1
  178. package/dist/src/routes/apps-cost.d.ts +25 -0
  179. package/dist/src/routes/apps-cost.d.ts.map +1 -0
  180. package/dist/src/routes/apps-cost.js +107 -0
  181. package/dist/src/routes/apps-cost.js.map +1 -0
  182. package/dist/src/routes/exchange-market.d.ts +28 -0
  183. package/dist/src/routes/exchange-market.d.ts.map +1 -0
  184. package/dist/src/routes/exchange-market.js +454 -0
  185. package/dist/src/routes/exchange-market.js.map +1 -0
  186. package/dist/src/routes/exchange.d.ts +33 -0
  187. package/dist/src/routes/exchange.d.ts.map +1 -0
  188. package/dist/src/routes/exchange.js +395 -0
  189. package/dist/src/routes/exchange.js.map +1 -0
  190. package/dist/src/routes/extensions/entitlement-gate.d.ts +33 -0
  191. package/dist/src/routes/extensions/entitlement-gate.d.ts.map +1 -0
  192. package/dist/src/routes/extensions/entitlement-gate.js +143 -0
  193. package/dist/src/routes/extensions/entitlement-gate.js.map +1 -0
  194. package/dist/src/routes/extensions/manifest.d.ts +9 -0
  195. package/dist/src/routes/extensions/manifest.d.ts.map +1 -1
  196. package/dist/src/routes/extensions/manifest.js +33 -1
  197. package/dist/src/routes/extensions/manifest.js.map +1 -1
  198. package/dist/src/routes/extensions/paywall.d.ts.map +1 -1
  199. package/dist/src/routes/extensions/paywall.js +9 -0
  200. package/dist/src/routes/extensions/paywall.js.map +1 -1
  201. package/dist/src/routes/federation-sync/messaging.d.ts.map +1 -1
  202. package/dist/src/routes/federation-sync/messaging.js +3 -1
  203. package/dist/src/routes/federation-sync/messaging.js.map +1 -1
  204. package/dist/src/routes/ghii/recovery.d.ts +2 -0
  205. package/dist/src/routes/ghii/recovery.d.ts.map +1 -1
  206. package/dist/src/routes/ghii/recovery.js +7 -0
  207. package/dist/src/routes/ghii/recovery.js.map +1 -1
  208. package/dist/src/routes/ghii/register-login.d.ts +4 -0
  209. package/dist/src/routes/ghii/register-login.d.ts.map +1 -1
  210. package/dist/src/routes/ghii/register-login.js +45 -22
  211. package/dist/src/routes/ghii/register-login.js.map +1 -1
  212. package/dist/src/routes/ghii/web-verify.d.ts +5 -0
  213. package/dist/src/routes/ghii/web-verify.d.ts.map +1 -1
  214. package/dist/src/routes/ghii/web-verify.js +24 -3
  215. package/dist/src/routes/ghii/web-verify.js.map +1 -1
  216. package/dist/src/routes/libs/sdk-serve.d.ts +11 -0
  217. package/dist/src/routes/libs/sdk-serve.d.ts.map +1 -0
  218. package/dist/src/routes/libs/sdk-serve.js +53 -0
  219. package/dist/src/routes/libs/sdk-serve.js.map +1 -0
  220. package/dist/src/routes/libs.d.ts +7 -1
  221. package/dist/src/routes/libs.d.ts.map +1 -1
  222. package/dist/src/routes/libs.js +65 -146
  223. package/dist/src/routes/libs.js.map +1 -1
  224. package/dist/src/routes/messages.d.ts +3 -0
  225. package/dist/src/routes/messages.d.ts.map +1 -1
  226. package/dist/src/routes/messages.js +9 -0
  227. package/dist/src/routes/messages.js.map +1 -1
  228. package/dist/src/routes/notifications.d.ts +6 -3
  229. package/dist/src/routes/notifications.d.ts.map +1 -1
  230. package/dist/src/routes/notifications.js +32 -3
  231. package/dist/src/routes/notifications.js.map +1 -1
  232. package/dist/src/routes/organisms/workspace-access.d.ts.map +1 -1
  233. package/dist/src/routes/organisms/workspace-access.js +38 -20
  234. package/dist/src/routes/organisms/workspace-access.js.map +1 -1
  235. package/dist/src/routes/unfurl.d.ts +27 -0
  236. package/dist/src/routes/unfurl.d.ts.map +1 -0
  237. package/dist/src/routes/unfurl.js +180 -0
  238. package/dist/src/routes/unfurl.js.map +1 -0
  239. package/dist/src/routes/upload.d.ts +2 -0
  240. package/dist/src/routes/upload.d.ts.map +1 -1
  241. package/dist/src/routes/upload.js +7 -0
  242. package/dist/src/routes/upload.js.map +1 -1
  243. package/dist/src/routes/webmcp.d.ts +3 -0
  244. package/dist/src/routes/webmcp.d.ts.map +1 -1
  245. package/dist/src/routes/webmcp.js +55 -0
  246. package/dist/src/routes/webmcp.js.map +1 -1
  247. package/dist/src/server-bootstrap/routes-loader.d.ts +1 -0
  248. package/dist/src/server-bootstrap/routes-loader.d.ts.map +1 -1
  249. package/dist/src/server-bootstrap/routes-loader.js +8 -0
  250. package/dist/src/server-bootstrap/routes-loader.js.map +1 -1
  251. package/dist/src/services/agent-face.d.ts +10 -2
  252. package/dist/src/services/agent-face.d.ts.map +1 -1
  253. package/dist/src/services/agent-face.js +10 -4
  254. package/dist/src/services/agent-face.js.map +1 -1
  255. package/dist/src/services/app-tool-interfaces.d.ts +37 -0
  256. package/dist/src/services/app-tool-interfaces.d.ts.map +1 -0
  257. package/dist/src/services/app-tool-interfaces.js +101 -0
  258. package/dist/src/services/app-tool-interfaces.js.map +1 -0
  259. package/dist/src/services/build-app-prompt.d.ts +3 -0
  260. package/dist/src/services/build-app-prompt.d.ts.map +1 -1
  261. package/dist/src/services/build-app-prompt.js +12 -1
  262. package/dist/src/services/build-app-prompt.js.map +1 -1
  263. package/dist/src/services/contacts.d.ts +25 -1
  264. package/dist/src/services/contacts.d.ts.map +1 -1
  265. package/dist/src/services/contacts.js +30 -0
  266. package/dist/src/services/contacts.js.map +1 -1
  267. package/dist/src/services/entitlement-money.d.ts +55 -0
  268. package/dist/src/services/entitlement-money.d.ts.map +1 -0
  269. package/dist/src/services/entitlement-money.js +68 -0
  270. package/dist/src/services/entitlement-money.js.map +1 -0
  271. package/dist/src/services/exchange-market.d.ts +247 -0
  272. package/dist/src/services/exchange-market.d.ts.map +1 -0
  273. package/dist/src/services/exchange-market.js +254 -0
  274. package/dist/src/services/exchange-market.js.map +1 -0
  275. package/dist/src/services/exchange-proposals.d.ts +47 -0
  276. package/dist/src/services/exchange-proposals.d.ts.map +1 -0
  277. package/dist/src/services/exchange-proposals.js +71 -0
  278. package/dist/src/services/exchange-proposals.js.map +1 -0
  279. package/dist/src/services/exchange-work.d.ts +30 -0
  280. package/dist/src/services/exchange-work.d.ts.map +1 -0
  281. package/dist/src/services/exchange-work.js +43 -0
  282. package/dist/src/services/exchange-work.js.map +1 -0
  283. package/dist/src/services/message-send.d.ts.map +1 -1
  284. package/dist/src/services/message-send.js +4 -1
  285. package/dist/src/services/message-send.js.map +1 -1
  286. package/dist/src/services/metered-entitlements.d.ts +203 -0
  287. package/dist/src/services/metered-entitlements.d.ts.map +1 -0
  288. package/dist/src/services/metered-entitlements.js +264 -0
  289. package/dist/src/services/metered-entitlements.js.map +1 -0
  290. package/dist/src/services/notify.d.ts +7 -0
  291. package/dist/src/services/notify.d.ts.map +1 -1
  292. package/dist/src/services/notify.js +35 -0
  293. package/dist/src/services/notify.js.map +1 -1
  294. package/dist/src/services/owner-memory.d.ts +16 -0
  295. package/dist/src/services/owner-memory.d.ts.map +1 -1
  296. package/dist/src/services/owner-memory.js +23 -0
  297. package/dist/src/services/owner-memory.js.map +1 -1
  298. package/dist/src/services/owner-provisioning.d.ts +5 -0
  299. package/dist/src/services/owner-provisioning.d.ts.map +1 -1
  300. package/dist/src/services/owner-provisioning.js +20 -2
  301. package/dist/src/services/owner-provisioning.js.map +1 -1
  302. package/dist/src/storage/providers/postgres-kysely/methods/apps.d.ts +1 -0
  303. package/dist/src/storage/providers/postgres-kysely/methods/apps.d.ts.map +1 -1
  304. package/dist/src/storage/providers/postgres-kysely/methods/apps.js +2 -0
  305. package/dist/src/storage/providers/postgres-kysely/methods/apps.js.map +1 -1
  306. package/dist/src/storage/providers/postgres-kysely/methods/identity.d.ts +1 -0
  307. package/dist/src/storage/providers/postgres-kysely/methods/identity.d.ts.map +1 -1
  308. package/dist/src/storage/providers/postgres-kysely/methods/identity.js +4 -0
  309. package/dist/src/storage/providers/postgres-kysely/methods/identity.js.map +1 -1
  310. package/dist/src/storage/providers/postgres-kysely/migrations/0011_unique_verified_email.sql +25 -0
  311. package/dist/src/storage/providers/sqlite/methods/apps.d.ts +1 -0
  312. package/dist/src/storage/providers/sqlite/methods/apps.d.ts.map +1 -1
  313. package/dist/src/storage/providers/sqlite/methods/apps.js +2 -0
  314. package/dist/src/storage/providers/sqlite/methods/apps.js.map +1 -1
  315. package/dist/src/storage/providers/sqlite/methods/identity-nodes.d.ts +1 -0
  316. package/dist/src/storage/providers/sqlite/methods/identity-nodes.d.ts.map +1 -1
  317. package/dist/src/storage/providers/sqlite/methods/identity-nodes.js +4 -0
  318. package/dist/src/storage/providers/sqlite/methods/identity-nodes.js.map +1 -1
  319. package/dist/src/storage/providers/sqlite/schema.d.ts.map +1 -1
  320. package/dist/src/storage/providers/sqlite/schema.js +20 -0
  321. package/dist/src/storage/providers/sqlite/schema.js.map +1 -1
  322. package/dist/src/storage/repositories/app.repository.d.ts +0 -0
  323. package/dist/src/storage/repositories/app.repository.d.ts.map +1 -1
  324. package/dist/src/storage/repositories/identity.repository.d.ts +6 -0
  325. package/dist/src/storage/repositories/identity.repository.d.ts.map +1 -1
  326. package/dist/src/storage/types/apps.d.ts +1 -0
  327. package/dist/src/storage/types/apps.d.ts.map +1 -1
  328. package/dist/src/storage/types/organisms-federation.d.ts +21 -0
  329. package/dist/src/storage/types/organisms-federation.d.ts.map +1 -1
  330. package/dist/src/utils/app-mobile-lint.d.ts +17 -0
  331. package/dist/src/utils/app-mobile-lint.d.ts.map +1 -0
  332. package/dist/src/utils/app-mobile-lint.js +40 -0
  333. package/dist/src/utils/app-mobile-lint.js.map +1 -0
  334. package/dist/static/app-catalog/_template.html +12 -77
  335. package/dist/static/app-catalog/js/apps-io.js +51 -165
  336. package/dist/static/app-catalog/js/cost.js +100 -0
  337. package/dist/static/app-catalog/js/db.js +23 -93
  338. package/dist/static/app-catalog/js/detail.js +158 -24
  339. package/dist/static/app-catalog/js/favorites.js +71 -0
  340. package/dist/static/app-catalog/js/i18n-data.js +90 -16
  341. package/dist/static/app-catalog/js/main.js +23 -103
  342. package/dist/static/app-catalog/js/migrate.js +88 -0
  343. package/dist/static/app-catalog/js/monetize.js +1 -1
  344. package/dist/static/app-catalog/js/promote.js +70 -0
  345. package/dist/static/app-catalog/js/render.js +26 -139
  346. package/dist/static/app-catalog/js/server-io.js +126 -223
  347. package/dist/static/app-catalog/js/settings.js +11 -204
  348. package/dist/static/app-catalog/styles/app-catalog.css +40 -0
  349. package/dist/static/app-catalog.html +790 -912
  350. package/dist/static/sdk-libs/_core/config.js +52 -0
  351. package/dist/static/sdk-libs/_core/http.js +52 -0
  352. package/dist/static/sdk-libs/_core/namespace.js +33 -0
  353. package/dist/static/sdk-libs/_core/sdk-globals.d.ts +50 -0
  354. package/dist/static/sdk-libs/_core/session.js +66 -0
  355. package/dist/static/sdk-libs/agentface/index.js +102 -0
  356. package/dist/static/sdk-libs/agents/index.js +267 -0
  357. package/dist/static/sdk-libs/ai/index.js +153 -0
  358. package/dist/static/sdk-libs/audio/core.js +111 -0
  359. package/dist/static/sdk-libs/audio/index.js +380 -0
  360. package/dist/static/sdk-libs/audio/instruments.js +369 -0
  361. package/dist/static/sdk-libs/auth/config.js +46 -0
  362. package/dist/static/sdk-libs/auth/crypto.js +166 -0
  363. package/dist/static/sdk-libs/auth/events.js +27 -0
  364. package/dist/static/sdk-libs/auth/i18n.js +64 -0
  365. package/dist/static/sdk-libs/auth/index.js +37 -0
  366. package/dist/static/sdk-libs/auth/modal.js +545 -0
  367. package/dist/static/sdk-libs/auth/pill.js +167 -0
  368. package/dist/static/sdk-libs/auth/session.js +792 -0
  369. package/dist/static/sdk-libs/auth/signup.js +232 -0
  370. package/dist/static/sdk-libs/auth/theme.js +96 -0
  371. package/dist/static/sdk-libs/capabilities/index.js +179 -0
  372. package/dist/static/sdk-libs/commerce/index.js +243 -0
  373. package/dist/static/sdk-libs/data/index.js +188 -0
  374. package/dist/static/sdk-libs/dist/aimeat-agentface.js +91 -0
  375. package/dist/static/sdk-libs/dist/aimeat-agents.js +315 -0
  376. package/dist/static/sdk-libs/dist/aimeat-ai.js +168 -0
  377. package/dist/static/sdk-libs/dist/aimeat-audio.js +979 -0
  378. package/dist/static/sdk-libs/dist/aimeat-auth.js +1831 -0
  379. package/dist/static/sdk-libs/dist/aimeat-capabilities.js +177 -0
  380. package/dist/static/sdk-libs/dist/aimeat-commerce.js +265 -0
  381. package/dist/static/sdk-libs/dist/aimeat-data.js +205 -0
  382. package/dist/static/sdk-libs/dist/aimeat-editor.js +299 -0
  383. package/dist/static/sdk-libs/dist/aimeat-header.js +270 -0
  384. package/dist/static/sdk-libs/dist/aimeat-intake.js +94 -0
  385. package/dist/static/sdk-libs/dist/aimeat-live.js +265 -0
  386. package/dist/static/sdk-libs/dist/aimeat-markdown.js +602 -0
  387. package/dist/static/sdk-libs/dist/aimeat-organism.js +394 -0
  388. package/dist/static/sdk-libs/dist/aimeat-portfolio-standalone.js +90 -0
  389. package/dist/static/sdk-libs/dist/aimeat-social.js +157 -0
  390. package/dist/static/sdk-libs/dist/aimeat-speech.js +300 -0
  391. package/dist/static/sdk-libs/dist/aimeat-storage.js +210 -0
  392. package/dist/static/sdk-libs/dist/aimeat-tunnel.js +383 -0
  393. package/dist/static/sdk-libs/dist/aimeat-wallet.js +118 -0
  394. package/dist/static/sdk-libs/dist/aimeat-webmcp.js +187 -0
  395. package/dist/static/sdk-libs/dist/aimeat-work.js +213 -0
  396. package/dist/static/sdk-libs/dist/aimeat-workflows.js +147 -0
  397. package/dist/static/sdk-libs/editor/index.js +229 -0
  398. package/dist/static/sdk-libs/header/index.js +249 -0
  399. package/dist/static/sdk-libs/intake/index.js +75 -0
  400. package/dist/static/sdk-libs/live/index.js +156 -0
  401. package/dist/static/sdk-libs/markdown/index.js +522 -0
  402. package/dist/static/sdk-libs/organism/index.js +381 -0
  403. package/dist/static/sdk-libs/portfolio-standalone/index.js +78 -0
  404. package/dist/static/sdk-libs/social/index.js +140 -0
  405. package/dist/static/sdk-libs/speech/index.js +321 -0
  406. package/dist/static/sdk-libs/storage/index.js +189 -0
  407. package/dist/static/sdk-libs/tunnel/index.js +428 -0
  408. package/dist/static/sdk-libs/wallet/index.js +115 -0
  409. package/dist/static/sdk-libs/webmcp/index.js +185 -0
  410. package/dist/static/sdk-libs/work/index.js +191 -0
  411. package/dist/static/sdk-libs/workflows/index.js +113 -0
  412. package/package.json +5 -2
@@ -14,6 +14,12 @@
14
14
  "inbox.quoteYou": "You",
15
15
  "inbox.replyingTo": "Replying to",
16
16
  "inbox.quoteCancel": "Cancel the quoted reply",
17
+ "inbox.linkPreview.label": "Previews",
18
+ "inbox.linkPreview.hide": "Hide this preview",
19
+ "inbox.linkPreview.hideAll": "Hide link previews",
20
+ "inbox.linkPreview.showAll": "Show link previews",
21
+ "inbox.thread.showAll": "Show all messages",
22
+ "inbox.thread.showRecent": "Show last 50",
17
23
  "inbox.attachmentRemove": "Remove attachment",
18
24
  "inbox.contactAgentSuffix": "(your agent)",
19
25
  "inbox.messageThis": "Send a message",
@@ -49,6 +55,23 @@
49
55
  "inbox.schedError": "Could not schedule.",
50
56
  "inbox.parkToNotebook": "Add to notebook for later",
51
57
  "inbox.parkedToNotebook": "Added to your notebook.",
58
+ "inbox.notebook.toNotebook": "Summarize to Notebook",
59
+ "inbox.notebook.toNotebookShort": "Notebook",
60
+ "inbox.notebook.modeAi": "AI summary (my key)",
61
+ "inbox.notebook.modeCopy": "Copy prompt",
62
+ "inbox.notebook.modeRaw": "Raw",
63
+ "inbox.notebook.hintAi": "Summarize this whole conversation with your own OpenRouter key, review it, then send it to the Notebook to file into a workspace.",
64
+ "inbox.notebook.hintCopy": "Copy this prompt into your own AI chat, then paste the summary back below and send it to the Notebook.",
65
+ "inbox.notebook.hintRaw": "Send the whole chain (text + images) to the Notebook as-is, and refine it there with classify / distribute.",
66
+ "inbox.notebook.genSummary": "Summarize with AI",
67
+ "inbox.notebook.summarizing": "Summarizing…",
68
+ "inbox.notebook.regen": "Regenerate",
69
+ "inbox.notebook.park": "Send to Notebook",
70
+ "inbox.notebook.parkRaw": "Send to Notebook",
71
+ "inbox.notebook.parked": "Sent to the Notebook.",
72
+ "inbox.notebook.pasteHint": "Paste the AI's summary here:",
73
+ "inbox.notebook.pastePh": "Paste the summary the AI gave you…",
74
+ "inbox.notebook.summaryEmpty": "The model returned nothing — try again.",
52
75
  "inbox.viaAgent": "via",
53
76
  "inbox.sentByAgent": "Sent by your agent",
54
77
  "inbox.viaAgentReadonly": "Sent by your agent {agent} — view only.",
@@ -148,6 +171,8 @@
148
171
  "admin.messages.detail": "Detail",
149
172
  "admin.messages.none": "No deliveries yet.",
150
173
  "inbox.attach": "Attach a file",
174
+ "inbox.expand": "Enlarge the editor",
175
+ "inbox.collapse": "Shrink the editor",
151
176
  "inbox.today": "Today",
152
177
  "inbox.yesterday": "Yesterday",
153
178
  "inbox.youPrefix": "You:",
@@ -579,7 +604,10 @@
579
604
  "loginCta": "Log in",
580
605
  "errorTitle": "Cannot grant access",
581
606
  "missing": "No authorization request.",
582
- "expired": "This request has expired."
607
+ "expired": "This request has expired.",
608
+ "ownBadge": "Your app",
609
+ "ownIntro": "This is your own app. It still uses a scoped, revocable key — never your login session.",
610
+ "newScope": "new"
583
611
  },
584
612
  "common": {
585
613
  "cancel": "Cancel",
@@ -607,6 +635,7 @@
607
635
  "notif": {
608
636
  "title": "Notifications",
609
637
  "empty": "No notifications yet",
638
+ "clearAll": "Clear all",
610
639
  "action": {
611
640
  "reply": "Reply",
612
641
  "approve": "Approve",
@@ -2888,6 +2917,8 @@
2888
2917
  "operatorHiddenHint": "An operator has hidden this app from public view. Only you can still see it. Contact the operator to appeal.",
2889
2918
  "agentBadge": "Ships an agent",
2890
2919
  "agentBadgeHint": "This app ships its own agent - deploy it onto your fleet below",
2920
+ "promotedBadge": "Promoted",
2921
+ "promotedBadgeHint": "Promoted on your public profile — manage the pitch in the app catalog",
2891
2922
  "agentsLabel": "Bundled agents",
2892
2923
  "agentDeploy": "Deploy to my fleet",
2893
2924
  "agentUndeploy": "Undeploy",
@@ -4502,6 +4533,8 @@
4502
4533
  "completeAccountTitle": "One last step",
4503
4534
  "completeAccountDesc": "Add an email to finish setting up your account. We’ll send a verification code to confirm it.",
4504
4535
  "completeAccountDescResend": "Confirm your email to finish signing in. We’ll send a verification code — edit the address if it’s wrong.",
4536
+ "registerEmailTitle": "Add your email",
4537
+ "registerEmailDesc": "Enter your email to create your account. We’ll send a verification code to confirm it.",
4505
4538
  "sendVerificationCode": "Send Verification Code",
4506
4539
  "enterCodeTitle": "Enter Verification Code",
4507
4540
  "enterCodeDesc": "We sent a 6-digit code to your email. Enter it below to finish and sign in.",
@@ -6447,6 +6480,7 @@
6447
6480
  "notFound": "Portfolio not found",
6448
6481
  "notFoundDesc": "This user hasn't published a portfolio yet.",
6449
6482
  "loginToSeeMore": "Log in to see more content",
6483
+ "promoted": "Promoted apps",
6450
6484
  "backToPortal": "Home",
6451
6485
  "fullscreen": "Fullscreen",
6452
6486
  "standalone": "Own address"
@@ -14,6 +14,12 @@
14
14
  "inbox.quoteYou": "Sinä",
15
15
  "inbox.replyingTo": "Vastataan:",
16
16
  "inbox.quoteCancel": "Peru lainattu vastaus",
17
+ "inbox.linkPreview.label": "Esikatselut",
18
+ "inbox.linkPreview.hide": "Piilota tämä esikatselu",
19
+ "inbox.linkPreview.hideAll": "Piilota linkkien esikatselut",
20
+ "inbox.linkPreview.showAll": "Näytä linkkien esikatselut",
21
+ "inbox.thread.showAll": "Näytä kaikki viestit",
22
+ "inbox.thread.showRecent": "Näytä viimeiset 50",
17
23
  "inbox.attachmentRemove": "Poista liite",
18
24
  "inbox.contactAgentSuffix": "(agenttisi)",
19
25
  "inbox.messageThis": "Lähetä viesti",
@@ -49,6 +55,23 @@
49
55
  "inbox.schedError": "Ajastus epäonnistui.",
50
56
  "inbox.parkToNotebook": "Lisää muistikirjaan myöhempää varten",
51
57
  "inbox.parkedToNotebook": "Lisätty muistikirjaasi.",
58
+ "inbox.notebook.toNotebook": "Yhteenveto Notebookiin",
59
+ "inbox.notebook.toNotebookShort": "Notebook",
60
+ "inbox.notebook.modeAi": "AI-yhteenveto (oma avain)",
61
+ "inbox.notebook.modeCopy": "Kopioi prompti",
62
+ "inbox.notebook.modeRaw": "Raakana",
63
+ "inbox.notebook.hintAi": "Tiivistä koko tämä keskustelu omalla OpenRouter-avaimellasi, tarkista se, ja vie se Notebookiin arkistoitavaksi workspaceen.",
64
+ "inbox.notebook.hintCopy": "Kopioi tämä prompti omaan AI-chattiisi, liitä yhteenveto alle ja vie se Notebookiin.",
65
+ "inbox.notebook.hintRaw": "Vie koko ketju (teksti + kuvat) Notebookiin sellaisenaan, ja jalosta se siellä classify / distribute -toiminnoilla.",
66
+ "inbox.notebook.genSummary": "Tee yhteenveto AI:lla",
67
+ "inbox.notebook.summarizing": "Tiivistetään…",
68
+ "inbox.notebook.regen": "Uudelleen",
69
+ "inbox.notebook.park": "Vie Notebookiin",
70
+ "inbox.notebook.parkRaw": "Vie Notebookiin",
71
+ "inbox.notebook.parked": "Viety Notebookiin.",
72
+ "inbox.notebook.pasteHint": "Liitä AI:n yhteenveto tähän:",
73
+ "inbox.notebook.pastePh": "Liitä AI:n antama yhteenveto…",
74
+ "inbox.notebook.summaryEmpty": "Malli ei palauttanut mitään — yritä uudelleen.",
52
75
  "inbox.viaAgent": "via",
53
76
  "inbox.sentByAgent": "Lähettänyt agenttisi",
54
77
  "inbox.viaAgentReadonly": "Lähettänyt agenttisi {agent} — vain katselu.",
@@ -148,6 +171,8 @@
148
171
  "admin.messages.detail": "Lisätieto",
149
172
  "admin.messages.none": "Ei toimituksia vielä.",
150
173
  "inbox.attach": "Liitä tiedosto",
174
+ "inbox.expand": "Suurenna editori",
175
+ "inbox.collapse": "Pienennä editori",
151
176
  "inbox.today": "Tänään",
152
177
  "inbox.yesterday": "Eilen",
153
178
  "inbox.youPrefix": "Sinä:",
@@ -579,7 +604,10 @@
579
604
  "loginCta": "Kirjaudu",
580
605
  "errorTitle": "Pääsyä ei voida myöntää",
581
606
  "missing": "Ei valtuutuspyyntöä.",
582
- "expired": "Tämä pyyntö on vanhentunut."
607
+ "expired": "Tämä pyyntö on vanhentunut.",
608
+ "ownBadge": "Oma appisi",
609
+ "ownIntro": "Tämä on oma appisi. Sekin käyttää rajattua, peruttavaa avainta — ei koskaan kirjautumisistuntoasi.",
610
+ "newScope": "uusi"
583
611
  },
584
612
  "common": {
585
613
  "cancel": "Peruuta",
@@ -607,6 +635,7 @@
607
635
  "notif": {
608
636
  "title": "Ilmoitukset",
609
637
  "empty": "Ei ilmoituksia vielä",
638
+ "clearAll": "Tyhjennä kaikki",
610
639
  "action": {
611
640
  "reply": "Vastaa",
612
641
  "approve": "Hyväksy",
@@ -2888,6 +2917,8 @@
2888
2917
  "operatorHiddenHint": "Operaattori on piilottanut tämän sovelluksen julkisesta näkymästä. Vain sinä näet sen edelleen. Ota yhteyttä operaattoriin valittaaksesi.",
2889
2918
  "agentBadge": "Sisältää agentin",
2890
2919
  "agentBadgeHint": "Tämä sovellus tuo mukanaan oman agentin - ota se käyttöön omaan laivueeseesi alta",
2920
+ "promotedBadge": "Nostettu",
2921
+ "promotedBadgeHint": "Nostettu julkiseen profiiliisi — hallitse myyntipuhetta sovelluskatalogissa",
2891
2922
  "agentsLabel": "Mukana tulevat agentit",
2892
2923
  "agentDeploy": "Ota käyttöön laivueeseeni",
2893
2924
  "agentUndeploy": "Poista käytöstä",
@@ -4502,6 +4533,8 @@
4502
4533
  "completeAccountTitle": "Vielä yksi vaihe",
4503
4534
  "completeAccountDesc": "Lisää sähköpostiosoite viimeistelläksesi tilisi. Lähetämme vahvistuskoodin sen vahvistamiseksi.",
4504
4535
  "completeAccountDescResend": "Vahvista sähköpostiosoitteesi kirjautuaksesi sisään. Lähetämme vahvistuskoodin — muokkaa osoitetta, jos se on väärin.",
4536
+ "registerEmailTitle": "Lisää sähköpostiosoitteesi",
4537
+ "registerEmailDesc": "Anna sähköpostiosoitteesi luodaksesi tilisi. Lähetämme vahvistuskoodin sen vahvistamiseksi.",
4505
4538
  "sendVerificationCode": "Lähetä vahvistuskoodi",
4506
4539
  "enterCodeTitle": "Syötä vahvistuskoodi",
4507
4540
  "enterCodeDesc": "Lähetimme 6-numeroisen koodin sähköpostiisi. Syötä se alle viimeistelläksesi ja kirjautuaksesi sisään.",
@@ -6447,6 +6480,7 @@
6447
6480
  "notFound": "Portfoliota ei löytynyt",
6448
6481
  "notFoundDesc": "Tämä käyttäjä ei ole julkaissut portfoliota.",
6449
6482
  "loginToSeeMore": "Kirjaudu sisään nähdäksesi lisää",
6483
+ "promoted": "Nostetut sovellukset",
6450
6484
  "backToPortal": "Koti",
6451
6485
  "fullscreen": "Koko näyttö",
6452
6486
  "standalone": "Oma osoite"
@@ -0,0 +1,101 @@
1
+ /**
2
+ * @file public/components/LinkPreview.js
3
+ * @description Rich link-preview (unfurl) cards for a pasted URL. `LinkPreview` fetches one URL's
4
+ * OpenGraph metadata from the node (`/js/services/unfurl.js`) and renders a card (site · title ·
5
+ * description · thumbnail); the thumbnail is pulled through the node's image proxy into a `blob:`
6
+ * URL so the SPA's remote-image CSP is satisfied. `MessageLinkPreviews` extracts the URLs from a
7
+ * message body and renders a card per link, each with a ✕ that hides it (persisted in localStorage,
8
+ * so a dismissed card stays hidden). `extractUrls` is exported for reuse/testing.
9
+ * @structure extractUrls(text,max) · LinkPreview({url,onDismiss}) · MessageLinkPreviews({msg})
10
+ * @usage html`<${MessageLinkPreviews} msg=${msg} />`
11
+ * @version-history
12
+ * v1.0.0 — 2026-07-21 — Initial link-preview cards (inbox message threads).
13
+ */
14
+ import { h } from 'preact';
15
+ import { useState, useEffect } from 'preact/hooks';
16
+ import htm from 'htm';
17
+ const html = htm.bind(h);
18
+ import { t } from '/js/i18n.js';
19
+ import { escHtml } from '/js/utils.js';
20
+ import * as unfurl from '/js/services/unfurl.js';
21
+
22
+ /** Pull up to `max` distinct bare http(s) URLs out of a message body, trimming trailing sentence
23
+ * punctuation (mirrors the Markdown autolink trimming so the card links the same target the text does). */
24
+ export function extractUrls(text, max = 3) {
25
+ const urls = [];
26
+ if (typeof text !== 'string') return urls;
27
+ const re = /(?:^|[\s(<[])(https?:\/\/[^\s<>()[\]]+)/gi;
28
+ let m;
29
+ while ((m = re.exec(text)) !== null && urls.length < max) {
30
+ let u = m[1].replace(/[.,;:!?'"]+$/, '');
31
+ if (u && !urls.includes(u)) urls.push(u);
32
+ }
33
+ return urls;
34
+ }
35
+
36
+ // Dismissed cards persist across reloads: a Set of `${messageId}::${url}` keys in localStorage (capped).
37
+ const DISMISS_KEY = 'aimeat.inbox.linkcard.dismissed';
38
+ function loadDismissed() {
39
+ try { return new Set(JSON.parse(localStorage.getItem(DISMISS_KEY) || '[]')); } catch { return new Set(); }
40
+ }
41
+ function saveDismissed(set) {
42
+ try { localStorage.setItem(DISMISS_KEY, JSON.stringify([...set].slice(-500))); } catch { /* quota */ }
43
+ }
44
+
45
+ /** One preview card. Renders nothing while loading, or if the link has no usable metadata. */
46
+ export function LinkPreview({ url, onDismiss }) {
47
+ const [meta, setMeta] = useState(undefined); // undefined = loading, null = nothing to show
48
+ const [imgUrl, setImgUrl] = useState(null);
49
+
50
+ useEffect(() => {
51
+ let alive = true;
52
+ let objectUrl = null;
53
+ setMeta(undefined); setImgUrl(null);
54
+ (async () => {
55
+ const m = await unfurl.fetchPreview(url);
56
+ if (!alive) return;
57
+ // A card with no title/description/image isn't worth showing (avoid an empty box on a bare domain).
58
+ if (!m || (!m.title && !m.description && !m.image)) { setMeta(null); return; }
59
+ setMeta(m);
60
+ if (m.image) {
61
+ objectUrl = await unfurl.fetchPreviewImageUrl(m.image);
62
+ if (!alive) { if (objectUrl) URL.revokeObjectURL(objectUrl); return; }
63
+ if (objectUrl) setImgUrl(objectUrl);
64
+ }
65
+ })();
66
+ return () => { alive = false; if (objectUrl) URL.revokeObjectURL(objectUrl); };
67
+ }, [url]);
68
+
69
+ if (meta === undefined || meta === null) return null;
70
+ return html`
71
+ <div class="inbox-linkcard">
72
+ <a class="inbox-linkcard-main" href=${meta.resolvedUrl || url} target="_blank" rel="noopener noreferrer nofollow">
73
+ ${imgUrl ? html`<span class="inbox-linkcard-thumb"><img src=${imgUrl} alt="" loading="lazy" /></span>` : null}
74
+ <span class="inbox-linkcard-text">
75
+ ${meta.siteName ? html`<span class="inbox-linkcard-site">${escHtml(meta.siteName)}</span>` : null}
76
+ ${meta.title ? html`<span class="inbox-linkcard-title">${escHtml(meta.title)}</span>` : null}
77
+ ${meta.description ? html`<span class="inbox-linkcard-desc">${escHtml(meta.description)}</span>` : null}
78
+ </span>
79
+ </a>
80
+ <button class="inbox-linkcard-x" title=${t('inbox.linkPreview.hide')}
81
+ onClick=${() => onDismiss?.(url)}>✕</button>
82
+ </div>`;
83
+ }
84
+
85
+ /** All preview cards for one message: a card per non-dismissed URL in its body. */
86
+ export function MessageLinkPreviews({ msg }) {
87
+ const urls = extractUrls(msg?.body || '');
88
+ const [dismissed, setDismissed] = useState(loadDismissed);
89
+ if (urls.length === 0) return null;
90
+ const visible = urls.filter(u => !dismissed.has(`${msg.id}::${u}`));
91
+ if (visible.length === 0) return null;
92
+ const dismiss = (u) => {
93
+ const next = new Set(dismissed);
94
+ next.add(`${msg.id}::${u}`);
95
+ setDismissed(next);
96
+ saveDismissed(next);
97
+ };
98
+ return html`<div class="inbox-linkcards">
99
+ ${visible.map(u => html`<${LinkPreview} key=${u} url=${u} onDismiss=${dismiss} />`)}
100
+ </div>`;
101
+ }
@@ -17,6 +17,8 @@
17
17
  * same deep-link translation as bell clicks (supports both '#hash' and '?tab=' forms).
18
18
  * v1.2.0 — 2026-07-18 — Inline notification actions: reply box (POST /v1/messages) + api buttons
19
19
  * (approve/deny/accept/decline/reject) that call the action endpoint with the owner's session.
20
+ * v1.3.0 — 2026-07-19 — "Clear all" in the dropdown head (DELETE /v1/notifications) — deletes every
21
+ * notification for the owner (not just mark-read), optimistic empty + reconcile.
20
22
  */
21
23
  import { h } from 'preact';
22
24
  import { useState, useEffect, useRef, useCallback } from 'preact/hooks';
@@ -99,11 +101,23 @@ export function NotificationBell({ t, onNavigate }) {
99
101
  const [results, setResults] = useState({}); // notifId → { ok, msg }
100
102
  const ref = useRef(null);
101
103
 
104
+ const [clearing, setClearing] = useState(false);
105
+
102
106
  const load = useCallback(async () => {
103
107
  const r = await api('/v1/notifications');
104
108
  if (r && r.data) { setItems(r.data.notifications || []); setUnread(r.data.unread || 0); }
105
109
  }, []);
106
110
 
111
+ // "Clear all" — delete every notification for the owner (not just mark read). Optimistic: empty the
112
+ // list + zero the badge immediately, then reconcile from the server response.
113
+ const clearAll = useCallback(async () => {
114
+ setClearing(true);
115
+ setItems([]); setUnread(0); setReplyFor(null); setResults({});
116
+ await api('/v1/notifications', { method: 'DELETE', body: JSON.stringify({}) });
117
+ setClearing(false);
118
+ load();
119
+ }, [load]);
120
+
107
121
  useEffect(() => {
108
122
  load();
109
123
  return onLiveUpdate(['agent-messages', 'agent-tasks', 'notifications', 'workspace-access'], () => load());
@@ -215,7 +229,10 @@ export function NotificationBell({ t, onNavigate }) {
215
229
  </button>
216
230
  ${open ? html`
217
231
  <div class="notif-dropdown">
218
- <div class="notif-dropdown-head">${tr('notif.title', 'Notifications')}</div>
232
+ <div class="notif-dropdown-head">
233
+ <span>${tr('notif.title', 'Notifications')}</span>
234
+ ${items.length > 0 ? html`<button class="notif-clear-all" disabled=${clearing} onClick=${(e) => { e.stopPropagation(); clearAll(); }}>${clearing ? '…' : tr('notif.clearAll', 'Clear all')}</button>` : null}
235
+ </div>
219
236
  ${items.length === 0
220
237
  ? html`<div class="notif-empty">${tr('notif.empty', 'No notifications yet')}</div>`
221
238
  : items.map(n => renderItem(n))}
@@ -10,6 +10,14 @@
10
10
  @usage Loaded first in spa.html <head>; the theme is toggled by /js/theme.js
11
11
  which flips the data-theme attribute on <html>.
12
12
  @version-history
13
+ v1.24.0 — 2026-07-21 — App-shell scroll model: html/body no longer scroll (height:100%;
14
+ overflow:hidden); #app is a full-viewport (100dvh) flex column with the topnav as a fixed-height
15
+ row and .page-content as the sole overflow-y:auto scroll region. Removes the ~nav-height phantom
16
+ overscroll and stops view content sliding under the (formerly sticky, now in-frame) header. Coupled
17
+ offset fixes: .pf-sidebar/.adm-sidebar stick to top:0 of the region and cap at 100dvh−nav-height.
18
+ v1.23.1 — 2026-07-20 — Mobile: pin .notif-dropdown to fixed viewport insets under 560px (the
19
+ 320px, right:0-anchored panel ran off the LEFT edge — the bell sits mid-right of the bar — and
20
+ got clipped by body{overflow-x:hidden}); long notif titles/bodies wrap (overflow-wrap:anywhere).
13
21
  v1.23.0 — 2026-07-18 — Notification bell inline actions: split .notif-item into a clickable
14
22
  .notif-item-main + an actions row; add .notif-actions/.notif-action-btn/.notif-reply*/.notif-result.
15
23
  v1.22.0 — 2026-07-17 — UI-unification foundation: extend the spacing scale (--sp-5=20/--sp-6=24/
@@ -307,15 +315,22 @@
307
315
  }
308
316
 
309
317
  /* ── Base ── */
310
- html { scroll-behavior: smooth; }
318
+ html { scroll-behavior: smooth; height: 100%; }
311
319
 
312
320
  body {
313
321
  font-family: var(--font);
314
322
  background: var(--bg);
315
323
  color: var(--text);
316
324
  line-height: 1.6;
317
- min-height: 100vh;
318
- overflow-x: hidden;
325
+ height: 100%;
326
+ margin: 0; /* zero the UA default 8px — with the fixed app-shell frame it would push #app past the viewport */
327
+ /* App-shell: the page (html/body) never scrolls. The topnav is a fixed-height
328
+ flex row and .page-content owns the ONLY scroll region (see #app +
329
+ .page-content). This is what stops view content sliding under the header and
330
+ removes the ~nav-height phantom overscroll that body-scroll + an in-flow
331
+ (sticky) header produced — the content fills the space below the header and
332
+ scrolls within it. overflow:hidden also subsumes the old overflow-x clip. */
333
+ overflow: hidden;
319
334
  -webkit-font-smoothing: antialiased;
320
335
  }
321
336
 
@@ -402,14 +417,28 @@ a { color: inherit; text-decoration: none; }
402
417
  #app {
403
418
  position: relative;
404
419
  z-index: 1;
420
+ /* App-shell frame: a full-viewport flex column — topnav (fixed height) on top,
421
+ .page-content (the scroll region) filling the rest. dvh keeps the frame flush
422
+ with the visual viewport as mobile browser chrome shows/hides. */
423
+ height: 100vh;
424
+ height: 100dvh;
425
+ display: flex;
426
+ flex-direction: column;
405
427
  }
406
428
 
407
429
  /* ── Top Navigation ── */
408
430
  .topnav {
409
- position: sticky;
410
- top: 0;
431
+ /* App-shell: a fixed-height flex row inside #app (no longer sticky — #app
432
+ itself doesn't scroll, so the header stays put for free). z-index keeps the
433
+ header's own dropdowns (notifications, mobile menu) above .page-content. */
434
+ position: relative;
411
435
  z-index: 100;
436
+ flex: 0 0 auto;
412
437
  height: var(--nav-height);
438
+ /* border-box so the 1px border-bottom is INCLUDED in --nav-height — otherwise the
439
+ header renders 1px taller than the token and every `100dvh - var(--nav-height)`
440
+ scroll region (sidebars) is 1px too tall and can't stay pinned. */
441
+ box-sizing: border-box;
413
442
  display: flex;
414
443
  align-items: center;
415
444
  justify-content: space-between;
@@ -481,7 +510,10 @@ a { color: inherit; text-decoration: none; }
481
510
  .notif-bell-btn:hover { background: var(--bg-dim); }
482
511
  .notif-badge { position: absolute; top: -1px; right: -1px; background: var(--accent); color: #fff; border-radius: 10px; font-size: 0.6rem; font-weight: 700; min-width: 15px; height: 15px; padding: 0 3px; display: flex; align-items: center; justify-content: center; }
483
512
  .notif-dropdown { position: absolute; right: 0; top: calc(100% + 6px); width: 320px; max-height: 60vh; overflow-y: auto; background: var(--card); border: 1px solid var(--border); border-radius: 10px; box-shadow: 0 10px 30px rgba(0,0,0,0.18); z-index: 1200; }
484
- .notif-dropdown-head { font-weight: 700; font-size: 0.9rem; color: var(--text); padding: 0.6rem 0.85rem; border-bottom: 1px solid var(--border-subtle); position: sticky; top: 0; background: var(--card); }
513
+ .notif-dropdown-head { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; font-weight: 700; font-size: 0.9rem; color: var(--text); padding: 0.6rem 0.85rem; border-bottom: 1px solid var(--border-subtle); position: sticky; top: 0; background: var(--card); z-index: 1; }
514
+ .notif-clear-all { font-weight: 600; font-size: 0.78rem; color: var(--muted); background: none; border: none; padding: 0.15rem 0.35rem; border-radius: 6px; cursor: pointer; }
515
+ .notif-clear-all:hover:not(:disabled) { color: var(--brand); background: var(--bg-dim); }
516
+ .notif-clear-all:disabled { opacity: 0.6; cursor: default; }
485
517
  .notif-empty { padding: 1rem 0.85rem; color: var(--muted); font-size: 0.85rem; }
486
518
  .notif-item { display: block; border-bottom: 1px solid var(--border-subtle); }
487
519
  .notif-item.unread { background: var(--accent-subtle); }
@@ -499,6 +531,21 @@ a { color: inherit; text-decoration: none; }
499
531
  .notif-result { font-size: 0.76rem; padding: 0.3rem 0.85rem 0.55rem; }
500
532
  .notif-result.ok { color: var(--success, #4caf50); }
501
533
  .notif-result.err { color: var(--danger, #e0564a); }
534
+ /* Long sender GHIIs / subjects wrap instead of forcing the panel wider than the screen. */
535
+ .notif-item-title, .notif-item-body { overflow-wrap: anywhere; }
536
+ /* Mobile: the 320px-wide, right:0-anchored dropdown runs off the LEFT edge (the bell sits
537
+ mid-right of the bar) and gets clipped by body{overflow-x:hidden}. Pin it to fixed viewport
538
+ insets so it spans the screen width minus small margins, regardless of the bell's position. */
539
+ @media (max-width: 560px) {
540
+ .notif-dropdown {
541
+ position: fixed;
542
+ top: calc(var(--nav-height, 56px) + 4px);
543
+ right: 8px;
544
+ left: 8px;
545
+ width: auto;
546
+ max-height: 72vh;
547
+ }
548
+ }
502
549
 
503
550
  .topnav-right a {
504
551
  font-size: 0.84rem;
@@ -1277,7 +1324,10 @@ select.input-field { cursor: pointer; }
1277
1324
  }
1278
1325
 
1279
1326
  /* ── Page entrance ── */
1280
- .page-content { animation: pageIn 0.8s ease; }
1327
+ /* App-shell scroll region: fills the space under the topnav and owns the only
1328
+ scroll. min-height:0 lets the flex child shrink so overflow-y actually scrolls;
1329
+ overflow-x:hidden replaces the clip that used to live on body. */
1330
+ .page-content { flex: 1 1 auto; min-height: 0; overflow-y: auto; overflow-x: hidden; animation: pageIn 0.8s ease; }
1281
1331
 
1282
1332
  /* ── Responsive ── */
1283
1333
  @media (max-width: 480px) {
@@ -4,6 +4,9 @@
4
4
  * its distinct indigo accent and a permanently-dark sidebar, but all content
5
5
  * surfaces map to global theme.css tokens so they flip with dark/light mode.
6
6
  * @version-history
7
+ * v1.10.0 — 2026-07-21 — App-shell scroll model (theme.css v1.24.0): .adm-sidebar height 100vh →
8
+ * calc(100dvh − nav-height) so the sticky sidebar fills the .page-content scroll region instead of
9
+ * overflowing the frame by the header's height.
7
10
  * v1.9.0 — 2026-07-16 — Drop the dead .adm-nav-item .icon rule (nav is label-only now).
8
11
  * v1.8.0 — 2026-06-25 — Applications tab: .adm-apps-rowactions (Hide/Restore + Delete row).
9
12
  * v1.7.0 — 2026-06-24 — Applications moderation tab: .adm-apps-* (filters row,
@@ -53,9 +56,13 @@
53
56
  border-right: none;
54
57
  padding: 16px 0;
55
58
  flex-shrink: 0;
59
+ /* App-shell: sticks to the top of the .page-content scroll region; height caps
60
+ at that region (viewport minus the fixed header) so the sidebar's own nav
61
+ scrolls instead of overflowing past the frame by the header's height. */
56
62
  position: sticky;
57
63
  top: 0;
58
- height: 100vh;
64
+ height: calc(100dvh - var(--nav-height, 56px));
65
+ box-sizing: border-box; /* fold the 16px vertical padding into the height so it fits the scroll region */
59
66
  overflow-y: auto;
60
67
  display: flex;
61
68
  flex-direction: column;
@@ -4,6 +4,7 @@
4
4
  * screen where an owner reviews a published app's requested scopes (H-2 Phase 3).
5
5
  * @version-history
6
6
  * v1.0.0 — 2026-06-20 — Initial (H-2 app-origin isolation, Phase 3).
7
+ * v1.1.0 — 2026-07-19 — Own-app badge variant + "new" chip for newly requested scopes.
7
8
  */
8
9
 
9
10
  .agr-wrap { max-width: 540px; margin: 3rem auto; padding: 0 1.25rem; }
@@ -64,6 +65,23 @@
64
65
  padding: 0.18rem 0.6rem;
65
66
  margin-bottom: 0.6rem;
66
67
  }
68
+ /* The signed-in owner's OWN app — reassuring, not warning */
69
+ .agr-badge-own { color: var(--success, #3dbf6e); }
70
+
71
+ /* Chip on a scope the app requests but the existing grant doesn't hold yet */
72
+ .agr-scope-newbadge {
73
+ display: inline-block;
74
+ font-size: 0.68rem;
75
+ font-weight: 700;
76
+ letter-spacing: 0.04em;
77
+ text-transform: uppercase;
78
+ color: var(--accent);
79
+ border: 1px solid var(--accent);
80
+ border-radius: 999px;
81
+ padding: 0 0.4rem;
82
+ margin-left: 0.45rem;
83
+ vertical-align: 0.08em;
84
+ }
67
85
 
68
86
  /* Advanced toggle (link-style button) */
69
87
  .agr-advanced-toggle {
@@ -5,6 +5,8 @@
5
5
  * ticks, and a sticky composer. All colors/spacing use theme.css variables (dark-mode safe).
6
6
  * Classes are `inbox-` prefixed. NOTE: this file must be linked in spa.html (useViewCSS is a no-op).
7
7
  * @version-history
8
+ * v1.7.0 -- 2026-07-21 -- Link-preview (unfurl) cards under a pasted link (.inbox-linkcard*) + the
9
+ * thread-head show/hide toggle (.inbox-linkprev-toggle).
8
10
  * v1.6.0 -- 2026-07-18 -- TRUE full-screen mobile chat: ≤760px open panel becomes `position:fixed;inset:0`
9
11
  * over the whole viewport (covers the app shell nav/menu/breadcrumb); body height var(--inbox-avail,
10
12
  * 100dvh) + safe-area padding under the composer. ← Back drops `.inbox--panel` → shell returns. Pairs
@@ -485,7 +487,14 @@
485
487
  font-size: 14px;
486
488
  }
487
489
 
490
+ /* Expanded composer (the ⤢ toggle): grow the fallback/simple textarea + preview to ~60vh so a long or
491
+ formatted draft is fully visible. The rich Toast UI editor is resized in JS via setHeight instead. */
492
+ .inbox-composer--tall .inbox-textarea { min-height: 60vh; }
493
+ .inbox-composer--tall .inbox-textarea--chat { max-height: 60vh; }
494
+ .inbox-composer--tall .inbox-md-preview { max-height: 60vh; }
495
+
488
496
  .inbox-composer-bar { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
497
+ .inbox-bar-left { display: flex; align-items: center; gap: 8px; }
489
498
  .inbox-attach-btn {
490
499
  display: inline-flex;
491
500
  align-items: center;
@@ -743,3 +752,40 @@
743
752
  .inbox-sched-new { display: flex; flex-direction: column; gap: 6px; }
744
753
  .inbox-sched-new .btn-primary { align-self: flex-start; }
745
754
  .inbox-sched-desc { min-height: 38px; resize: vertical; }
755
+
756
+ /* ── Link previews (unfurl cards) — a rich card under a pasted link in a message bubble. The card is a
757
+ * clickable row (thumbnail · site · title · description) plus a ✕ to hide it. Theme tokens only. ── */
758
+ .inbox-linkcards { display: flex; flex-direction: column; gap: 6px; margin-top: 8px; }
759
+ .inbox-linkcard {
760
+ position: relative; display: flex; align-items: stretch;
761
+ border: 1px solid var(--border-subtle); border-radius: var(--radius-sm);
762
+ background: var(--card-bg-alt); overflow: hidden;
763
+ }
764
+ .inbox-linkcard-main {
765
+ display: flex; align-items: stretch; gap: 10px; min-width: 0; flex: 1;
766
+ padding: 8px 10px; text-decoration: none; color: inherit;
767
+ }
768
+ .inbox-linkcard-main:hover { background: var(--surface-hover); }
769
+ .inbox-linkcard-thumb { flex: none; width: 72px; display: flex; align-items: center; justify-content: center; }
770
+ .inbox-linkcard-thumb img {
771
+ width: 72px; height: 72px; object-fit: cover; border-radius: var(--radius-xs); display: block; margin: 0;
772
+ }
773
+ .inbox-linkcard-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; justify-content: center; }
774
+ .inbox-linkcard-site { font-size: 11px; color: var(--text-dim); text-transform: uppercase; letter-spacing: .02em; }
775
+ .inbox-linkcard-title {
776
+ font-size: 13px; font-weight: 600; color: var(--text); line-height: 1.3;
777
+ overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
778
+ }
779
+ .inbox-linkcard-desc {
780
+ font-size: 12px; color: var(--text-dim); line-height: 1.35;
781
+ overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
782
+ }
783
+ .inbox-linkcard-x {
784
+ flex: none; align-self: flex-start; border: none; background: transparent; cursor: pointer;
785
+ color: var(--text-dim); font-size: 12px; line-height: 1; padding: 6px 8px; border-radius: var(--radius-xs);
786
+ }
787
+ .inbox-linkcard-x:hover { color: var(--text); background: var(--surface-hover); }
788
+
789
+ /* Thread-head toggle: show/hide all link previews (persisted). --on marks the active state. */
790
+ .inbox-linkprev-toggle { flex: none; white-space: nowrap; }
791
+ .inbox-linkprev-toggle--on { background: var(--accent-subtle); border-color: var(--accent-border); color: var(--accent); }
@@ -317,6 +317,52 @@
317
317
  margin-bottom: 0.5rem;
318
318
  }
319
319
 
320
+ /* ── Promoted apps (public profile) ── */
321
+ .portfolio-profile-head {
322
+ text-align: center;
323
+ padding: 3rem 2rem 1rem;
324
+ color: var(--text-dim, #6B7280);
325
+ }
326
+ .portfolio-profile-head h2 { color: var(--text, #1A1A2E); margin-bottom: 0.5rem; }
327
+ .portfolio-promoted {
328
+ max-width: 900px;
329
+ margin: 0 auto;
330
+ padding: 0 1.5rem 1rem;
331
+ }
332
+ .portfolio-promoted-title {
333
+ font-size: 1rem;
334
+ color: var(--text, #1A1A2E);
335
+ margin: 0 0 0.75rem;
336
+ }
337
+ .portfolio-promoted-grid {
338
+ display: grid;
339
+ grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
340
+ gap: 0.75rem;
341
+ }
342
+ .portfolio-promoted-card {
343
+ display: block;
344
+ text-decoration: none;
345
+ border: 1px solid var(--border, #E5E7EB);
346
+ border-radius: 12px;
347
+ padding: 0.85rem 1rem;
348
+ background: var(--card, #fff);
349
+ transition: border-color 0.15s, transform 0.15s;
350
+ }
351
+ .portfolio-promoted-card:hover {
352
+ border-color: var(--accent, #E8564A);
353
+ transform: translateY(-1px);
354
+ }
355
+ .portfolio-promoted-name {
356
+ font-weight: 700;
357
+ color: var(--text, #1A1A2E);
358
+ margin-bottom: 0.3rem;
359
+ }
360
+ .portfolio-promoted-pitch {
361
+ font-size: 0.85rem;
362
+ color: var(--text-dim, #6B7280);
363
+ line-height: 1.4;
364
+ }
365
+
320
366
  /* ── Upload Section ── */
321
367
  .portfolio-upload-zone {
322
368
  border: 2px dashed var(--border, #E5E7EB);