aimeat 1.36.0 β†’ 1.37.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 (240) hide show
  1. package/dist/.env.example +6 -0
  2. package/dist/locales/en.json +186 -25
  3. package/dist/locales/fi.json +186 -25
  4. package/dist/public/components/Markdown.js +9 -0
  5. package/dist/public/components/MemoryEmbed.js +151 -0
  6. package/dist/public/components/Mermaid.js +4 -1
  7. package/dist/public/components/NotificationBell.js +45 -19
  8. package/dist/public/css/components/markdown.css +15 -0
  9. package/dist/public/css/views/agents-detail.css +17 -0
  10. package/dist/public/css/views/portfolio.css +51 -0
  11. package/dist/public/css/views/profile.css +31 -0
  12. package/dist/public/js/services/agents.js +9 -0
  13. package/dist/public/js/services/organisms.js +37 -1
  14. package/dist/public/llms-template.txt +278 -0
  15. package/dist/public/spa.html +34 -1
  16. package/dist/public/sw.js +50 -34
  17. package/dist/public/views/portfolio.js +267 -44
  18. package/dist/public/views/profile/agents/agent-card.js +4 -0
  19. package/dist/public/views/profile/agents/tab-contracts.js +112 -0
  20. package/dist/public/views/profile/landing-page.js +10 -1
  21. package/dist/public/views/profile/memory-tab.js +6 -2
  22. package/dist/public/views/profile/notifications-tab.js +9 -1
  23. package/dist/public/views/profile/organisms/home.js +23 -3
  24. package/dist/public/views/profile/organisms/participants-panel.js +89 -17
  25. package/dist/public/views/profile/organisms/workspace-apps.js +130 -0
  26. package/dist/public/views/profile/organisms/workspace.js +5 -0
  27. package/dist/public/views/profile/organisms-tab.js +1 -1
  28. package/dist/src/cli/init-wizard.d.ts.map +1 -1
  29. package/dist/src/cli/init-wizard.js +32 -0
  30. package/dist/src/cli/init-wizard.js.map +1 -1
  31. package/dist/src/config.d.ts +13 -0
  32. package/dist/src/config.d.ts.map +1 -1
  33. package/dist/src/config.js +9 -0
  34. package/dist/src/config.js.map +1 -1
  35. package/dist/src/data/aimeat-iam-package.d.ts +10 -2
  36. package/dist/src/data/aimeat-iam-package.d.ts.map +1 -1
  37. package/dist/src/data/aimeat-iam-package.js +39 -10
  38. package/dist/src/data/aimeat-iam-package.js.map +1 -1
  39. package/dist/src/generated/api-types.d.ts +328 -23
  40. package/dist/src/generated/api-types.d.ts.map +1 -1
  41. package/dist/src/generated/prisma-postgres/edge.js +4 -3
  42. package/dist/src/generated/prisma-postgres/index-browser.js +1 -0
  43. package/dist/src/generated/prisma-postgres/index.d.ts +30 -1
  44. package/dist/src/generated/prisma-postgres/index.js +4 -3
  45. package/dist/src/generated/prisma-postgres/package.json +1 -1
  46. package/dist/src/generated/prisma-postgres/schema.prisma +1 -0
  47. package/dist/src/generated/prisma-postgres/wasm.js +4 -3
  48. package/dist/src/mcp/annotations.d.ts.map +1 -1
  49. package/dist/src/mcp/annotations.js +1 -0
  50. package/dist/src/mcp/annotations.js.map +1 -1
  51. package/dist/src/mcp/catalog/definitions.d.ts +3 -0
  52. package/dist/src/mcp/catalog/definitions.d.ts.map +1 -1
  53. package/dist/src/mcp/catalog/definitions.js +21 -7
  54. package/dist/src/mcp/catalog/definitions.js.map +1 -1
  55. package/dist/src/mcp/catalog/surfaces.js +1 -1
  56. package/dist/src/mcp/catalog/surfaces.js.map +1 -1
  57. package/dist/src/mcp/core.js +1 -1
  58. package/dist/src/mcp/core.js.map +1 -1
  59. package/dist/src/mcp/extensions.d.ts.map +1 -1
  60. package/dist/src/mcp/extensions.js +21 -0
  61. package/dist/src/mcp/extensions.js.map +1 -1
  62. package/dist/src/mcp/memory-extended.js +1 -1
  63. package/dist/src/mcp/memory-extended.js.map +1 -1
  64. package/dist/src/mcp/organisms.d.ts +1 -0
  65. package/dist/src/mcp/organisms.d.ts.map +1 -1
  66. package/dist/src/mcp/organisms.js +23 -6
  67. package/dist/src/mcp/organisms.js.map +1 -1
  68. package/dist/src/mcp/workspaces.d.ts +3 -0
  69. package/dist/src/mcp/workspaces.d.ts.map +1 -1
  70. package/dist/src/mcp/workspaces.js +7 -2
  71. package/dist/src/mcp/workspaces.js.map +1 -1
  72. package/dist/src/middleware/subdomain.d.ts +9 -0
  73. package/dist/src/middleware/subdomain.d.ts.map +1 -1
  74. package/dist/src/middleware/subdomain.js +24 -3
  75. package/dist/src/middleware/subdomain.js.map +1 -1
  76. package/dist/src/models/schemas.d.ts +2 -0
  77. package/dist/src/models/schemas.d.ts.map +1 -1
  78. package/dist/src/models/schemas.js +2 -2
  79. package/dist/src/models/schemas.js.map +1 -1
  80. package/dist/src/routes/admin-features.js +1 -1
  81. package/dist/src/routes/admin-features.js.map +1 -1
  82. package/dist/src/routes/agent-onboarding.d.ts.map +1 -1
  83. package/dist/src/routes/agent-onboarding.js +44 -7
  84. package/dist/src/routes/agent-onboarding.js.map +1 -1
  85. package/dist/src/routes/agents.d.ts +1 -0
  86. package/dist/src/routes/agents.d.ts.map +1 -1
  87. package/dist/src/routes/agents.js +43 -0
  88. package/dist/src/routes/agents.js.map +1 -1
  89. package/dist/src/routes/app-grants.d.ts +5 -0
  90. package/dist/src/routes/app-grants.d.ts.map +1 -1
  91. package/dist/src/routes/app-grants.js +52 -20
  92. package/dist/src/routes/app-grants.js.map +1 -1
  93. package/dist/src/routes/boards.d.ts.map +1 -1
  94. package/dist/src/routes/boards.js +4 -1
  95. package/dist/src/routes/boards.js.map +1 -1
  96. package/dist/src/routes/bootstrap.d.ts +2 -0
  97. package/dist/src/routes/bootstrap.d.ts.map +1 -1
  98. package/dist/src/routes/bootstrap.js +5 -0
  99. package/dist/src/routes/bootstrap.js.map +1 -1
  100. package/dist/src/routes/capabilities.d.ts.map +1 -1
  101. package/dist/src/routes/capabilities.js +4 -1
  102. package/dist/src/routes/capabilities.js.map +1 -1
  103. package/dist/src/routes/catalogue.d.ts.map +1 -1
  104. package/dist/src/routes/catalogue.js +5 -4
  105. package/dist/src/routes/catalogue.js.map +1 -1
  106. package/dist/src/routes/extensions.d.ts.map +1 -1
  107. package/dist/src/routes/extensions.js +11 -0
  108. package/dist/src/routes/extensions.js.map +1 -1
  109. package/dist/src/routes/ghii.d.ts.map +1 -1
  110. package/dist/src/routes/ghii.js +65 -17
  111. package/dist/src/routes/ghii.js.map +1 -1
  112. package/dist/src/routes/lib-editor.d.ts +26 -0
  113. package/dist/src/routes/lib-editor.d.ts.map +1 -0
  114. package/dist/src/routes/lib-editor.js +215 -0
  115. package/dist/src/routes/lib-editor.js.map +1 -0
  116. package/dist/src/routes/lib-markdown.d.ts +16 -1
  117. package/dist/src/routes/lib-markdown.d.ts.map +1 -1
  118. package/dist/src/routes/lib-markdown.js +281 -2
  119. package/dist/src/routes/lib-markdown.js.map +1 -1
  120. package/dist/src/routes/lib-organism.d.ts +28 -0
  121. package/dist/src/routes/lib-organism.d.ts.map +1 -0
  122. package/dist/src/routes/lib-organism.js +298 -0
  123. package/dist/src/routes/lib-organism.js.map +1 -0
  124. package/dist/src/routes/lib-portfolio-standalone.d.ts +22 -0
  125. package/dist/src/routes/lib-portfolio-standalone.d.ts.map +1 -0
  126. package/dist/src/routes/lib-portfolio-standalone.js +68 -0
  127. package/dist/src/routes/lib-portfolio-standalone.js.map +1 -0
  128. package/dist/src/routes/libs.d.ts +4 -0
  129. package/dist/src/routes/libs.d.ts.map +1 -1
  130. package/dist/src/routes/libs.js +60 -1
  131. package/dist/src/routes/libs.js.map +1 -1
  132. package/dist/src/routes/memory.d.ts +3 -0
  133. package/dist/src/routes/memory.d.ts.map +1 -1
  134. package/dist/src/routes/memory.js +58 -4
  135. package/dist/src/routes/memory.js.map +1 -1
  136. package/dist/src/routes/notifications.d.ts +5 -1
  137. package/dist/src/routes/notifications.d.ts.map +1 -1
  138. package/dist/src/routes/notifications.js +68 -3
  139. package/dist/src/routes/notifications.js.map +1 -1
  140. package/dist/src/routes/organisms.d.ts +2 -0
  141. package/dist/src/routes/organisms.d.ts.map +1 -1
  142. package/dist/src/routes/organisms.js +171 -11
  143. package/dist/src/routes/organisms.js.map +1 -1
  144. package/dist/src/routes/owners.d.ts.map +1 -1
  145. package/dist/src/routes/owners.js +12 -8
  146. package/dist/src/routes/owners.js.map +1 -1
  147. package/dist/src/routes/portfolio.d.ts +41 -1
  148. package/dist/src/routes/portfolio.d.ts.map +1 -1
  149. package/dist/src/routes/portfolio.js +94 -30
  150. package/dist/src/routes/portfolio.js.map +1 -1
  151. package/dist/src/routes/push.d.ts +15 -0
  152. package/dist/src/routes/push.d.ts.map +1 -1
  153. package/dist/src/routes/push.js +16 -1
  154. package/dist/src/routes/push.js.map +1 -1
  155. package/dist/src/routes/subdomains.d.ts +5 -0
  156. package/dist/src/routes/subdomains.d.ts.map +1 -1
  157. package/dist/src/routes/subdomains.js +56 -0
  158. package/dist/src/routes/subdomains.js.map +1 -1
  159. package/dist/src/server-bootstrap/routes-loader.d.ts.map +1 -1
  160. package/dist/src/server-bootstrap/routes-loader.js +2 -0
  161. package/dist/src/server-bootstrap/routes-loader.js.map +1 -1
  162. package/dist/src/server-bootstrap/static-files.d.ts.map +1 -1
  163. package/dist/src/server-bootstrap/static-files.js +9 -4
  164. package/dist/src/server-bootstrap/static-files.js.map +1 -1
  165. package/dist/src/services/access-guard.d.ts.map +1 -1
  166. package/dist/src/services/access-guard.js +7 -0
  167. package/dist/src/services/access-guard.js.map +1 -1
  168. package/dist/src/services/ecosystem-access.d.ts +24 -8
  169. package/dist/src/services/ecosystem-access.d.ts.map +1 -1
  170. package/dist/src/services/ecosystem-access.js +27 -5
  171. package/dist/src/services/ecosystem-access.js.map +1 -1
  172. package/dist/src/services/iam/app-commands.d.ts +75 -0
  173. package/dist/src/services/iam/app-commands.d.ts.map +1 -0
  174. package/dist/src/services/iam/app-commands.js +55 -0
  175. package/dist/src/services/iam/app-commands.js.map +1 -0
  176. package/dist/src/services/iam/define-app-iam.d.ts +45 -0
  177. package/dist/src/services/iam/define-app-iam.d.ts.map +1 -0
  178. package/dist/src/services/iam/define-app-iam.js +75 -0
  179. package/dist/src/services/iam/define-app-iam.js.map +1 -0
  180. package/dist/src/services/iam/model.d.ts +113 -0
  181. package/dist/src/services/iam/model.d.ts.map +1 -0
  182. package/dist/src/services/iam/model.js +115 -0
  183. package/dist/src/services/iam/model.js.map +1 -0
  184. package/dist/src/services/mailbox-notification.d.ts +1 -0
  185. package/dist/src/services/mailbox-notification.d.ts.map +1 -1
  186. package/dist/src/services/mailbox-notification.js +3 -0
  187. package/dist/src/services/mailbox-notification.js.map +1 -1
  188. package/dist/src/services/notify.d.ts +11 -1
  189. package/dist/src/services/notify.d.ts.map +1 -1
  190. package/dist/src/services/notify.js +39 -2
  191. package/dist/src/services/notify.js.map +1 -1
  192. package/dist/src/services/organism-privacy.d.ts +46 -0
  193. package/dist/src/services/organism-privacy.d.ts.map +1 -0
  194. package/dist/src/services/organism-privacy.js +42 -0
  195. package/dist/src/services/organism-privacy.js.map +1 -0
  196. package/dist/src/services/prompt-defaults.d.ts +2 -0
  197. package/dist/src/services/prompt-defaults.d.ts.map +1 -1
  198. package/dist/src/services/prompt-defaults.js +5 -0
  199. package/dist/src/services/prompt-defaults.js.map +1 -1
  200. package/dist/src/services/scheduler.d.ts.map +1 -1
  201. package/dist/src/services/scheduler.js +11 -3
  202. package/dist/src/services/scheduler.js.map +1 -1
  203. package/dist/src/services/workspace-access.d.ts +2 -0
  204. package/dist/src/services/workspace-access.d.ts.map +1 -1
  205. package/dist/src/services/workspace-access.js +20 -8
  206. package/dist/src/services/workspace-access.js.map +1 -1
  207. package/dist/src/services/workspace-engagements.d.ts +65 -0
  208. package/dist/src/services/workspace-engagements.d.ts.map +1 -0
  209. package/dist/src/services/workspace-engagements.js +92 -0
  210. package/dist/src/services/workspace-engagements.js.map +1 -0
  211. package/dist/src/services/workspace-meta.d.ts +9 -2
  212. package/dist/src/services/workspace-meta.d.ts.map +1 -1
  213. package/dist/src/services/workspace-meta.js +22 -2
  214. package/dist/src/services/workspace-meta.js.map +1 -1
  215. package/dist/src/storage/interface.d.ts +8 -1
  216. package/dist/src/storage/interface.d.ts.map +1 -1
  217. package/dist/src/storage/interface.js.map +1 -1
  218. package/dist/src/storage/providers/mongodb/index.js +2 -2
  219. package/dist/src/storage/providers/mongodb/index.js.map +1 -1
  220. package/dist/src/storage/providers/sqlite/index.d.ts.map +1 -1
  221. package/dist/src/storage/providers/sqlite/index.js +5 -4
  222. package/dist/src/storage/providers/sqlite/index.js.map +1 -1
  223. package/dist/src/storage/providers/sqlite/schema.d.ts.map +1 -1
  224. package/dist/src/storage/providers/sqlite/schema.js +3 -0
  225. package/dist/src/storage/providers/sqlite/schema.js.map +1 -1
  226. package/dist/src/utils/env-config.d.ts.map +1 -1
  227. package/dist/src/utils/env-config.js +12 -0
  228. package/dist/src/utils/env-config.js.map +1 -1
  229. package/dist/src/utils/env-validator.d.ts.map +1 -1
  230. package/dist/src/utils/env-validator.js +8 -0
  231. package/dist/src/utils/env-validator.js.map +1 -1
  232. package/dist/static/app-catalog.html +8 -2
  233. package/dist/static/icons/badge-96.png +0 -0
  234. package/dist/static/icons/icon-192.png +0 -0
  235. package/dist/static/icons/icon-512.png +0 -0
  236. package/dist/static/manifest.json +19 -17
  237. package/dist/static/sw.js +13 -11
  238. package/package.json +1 -1
  239. package/prisma/schema.postgres.prisma +1 -0
  240. package/prisma/schema.prisma +1 -0
@@ -82,7 +82,6 @@
82
82
  "inbox.attachmentOpenRaw": "Avaa raakana",
83
83
  "inbox.attachmentDownload": "Lataa",
84
84
  "inbox.attachmentLoadError": "LiitettΓ€ ei voitu ladata.",
85
- "inbox.close": "Sulje",
86
85
  "inbox.directThread": "Suora",
87
86
  "inbox.subjectPlaceholder": "Aihe (valinnainen β€” aloittaa uuden ketjun)",
88
87
  "admin.messages.title": "Suorat viestit",
@@ -666,9 +665,24 @@
666
665
  "needPrefix": "Anna seurattava memory-prefiksi",
667
666
  "created": "Triggeri luotu",
668
667
  "error": "Triggeri epΓ€onnistui",
669
- "kind": { "time": "TiettynΓ€ pΓ€ivΓ€nΓ€", "recurring": "Toistuva", "completion": "Kun jokin valmistuu", "condition": "Kun ehto tΓ€yttyy" },
670
- "cad": { "none": "Ei toistoa", "daily": "PΓ€ivittΓ€in", "weekly": "Viikoittain", "monthly": "Kuukausittain" },
671
- "ct": { "memory_count": "Kohteiden mÀÀrÀ saavuttaa", "workspace_count": "Tyâtilan kohteet saavuttavat", "no_activity": "Ei aktiviteettia N pÀivÀÀn", "memory_exists": "Jotain ilmestyy" },
668
+ "kind": {
669
+ "time": "TiettynΓ€ pΓ€ivΓ€nΓ€",
670
+ "recurring": "Toistuva",
671
+ "completion": "Kun jokin valmistuu",
672
+ "condition": "Kun ehto tΓ€yttyy"
673
+ },
674
+ "cad": {
675
+ "none": "Ei toistoa",
676
+ "daily": "PΓ€ivittΓ€in",
677
+ "weekly": "Viikoittain",
678
+ "monthly": "Kuukausittain"
679
+ },
680
+ "ct": {
681
+ "memory_count": "Kohteiden mÀÀrÀ saavuttaa",
682
+ "workspace_count": "TyΓΆtilan kohteet saavuttavat",
683
+ "no_activity": "Ei aktiviteettia N pÀivÀÀn",
684
+ "memory_exists": "Jotain ilmestyy"
685
+ },
672
686
  "act": {
673
687
  "label": "Kun se laukeaa",
674
688
  "remind": "Muistuta minua",
@@ -710,7 +724,11 @@
710
724
  "replanApply": "Ota kΓ€yttΓΆΓΆn",
711
725
  "replanErr": "Uudelleensuunnittelu epΓ€onnistui",
712
726
  "targetChanged": "Tavoitetila muuttui β€” sÀÀdΓ€ vΓ€lietapit ja muu suunnitelma siihen sopivaksi.",
713
- "status": { "not-started": "Aloittamatta", "in-progress": "KΓ€ynnissΓ€", "reached": "Saavutettu" }
727
+ "status": {
728
+ "not-started": "Aloittamatta",
729
+ "in-progress": "KΓ€ynnissΓ€",
730
+ "reached": "Saavutettu"
731
+ }
714
732
  },
715
733
  "reset": {
716
734
  "title": "Nollaa sihteeri",
@@ -791,7 +809,12 @@
791
809
  "dailyBudgetHint": "YlΓ€raja sille mitΓ€ itsenΓ€iset toimet saavat kuluttaa pΓ€ivΓ€ssΓ€.",
792
810
  "noLimit": "Ei rajaa",
793
811
  "bandsNote": "NΓ€mΓ€ mÀÀrÀÀvΓ€t mitΓ€ sihteeri saa tehdΓ€ itsenΓ€isesti. Kukin astuu voimaan kun kyseinen kyvykkyys valmistuu.",
794
- "band": { "act": "Tee", "draft": "Luonnostele", "ask": "Kysy", "off": "Pois" },
812
+ "band": {
813
+ "act": "Tee",
814
+ "draft": "Luonnostele",
815
+ "ask": "Kysy",
816
+ "off": "Pois"
817
+ },
795
818
  "locked": "aina pÀÀllΓ€",
796
819
  "enterprise": "Enterprise",
797
820
  "capCosts": "kuluttaa / ulospΓ€in",
@@ -1095,7 +1118,6 @@
1095
1118
  "running": "Ajetaan…",
1096
1119
  "queued": "jonossa",
1097
1120
  "startNew": "Aloita uusi rutiini",
1098
- "discard": "HylkÀÀ",
1099
1121
  "decisionChosen": "HyvΓ€ksyttiin tΓ€mΓ€ rutiinin vaihe",
1100
1122
  "routinesTitle": "Rutiinit",
1101
1123
  "last": "Viimeisin",
@@ -1124,7 +1146,11 @@
1124
1146
  "checkResult": "Tarkista tulos",
1125
1147
  "repeats": "Toistuu",
1126
1148
  "nextRun": "Seuraava ajo",
1127
- "cadence": { "none": "Kerran (ei toistoa)", "daily": "PΓ€ivittΓ€in", "weekly": "Viikoittain" },
1149
+ "cadence": {
1150
+ "none": "Kerran (ei toistoa)",
1151
+ "daily": "PΓ€ivittΓ€in",
1152
+ "weekly": "Viikoittain"
1153
+ },
1128
1154
  "status": {
1129
1155
  "done": "valmis",
1130
1156
  "skipped": "ohitettu",
@@ -1153,12 +1179,18 @@
1153
1179
  "suggestEmpty": "Ei uusia ehdotuksia",
1154
1180
  "error": "Pikatoiminnot epΓ€onnistui",
1155
1181
  "composeTarget": "avaa",
1156
- "kind": { "prompt": "viesti", "compose": "avaa" }
1182
+ "kind": {
1183
+ "prompt": "viesti",
1184
+ "compose": "avaa"
1185
+ }
1157
1186
  },
1158
1187
  "items": {
1159
1188
  "title": "Toimenpiteet",
1160
1189
  "dismiss": "HylkÀÀ",
1161
- "handle": { "advance": "Avaa", "check-delegate": "Tarkista tulos" },
1190
+ "handle": {
1191
+ "advance": "Avaa",
1192
+ "check-delegate": "Tarkista tulos"
1193
+ },
1162
1194
  "text": {
1163
1195
  "approve": "HyvΓ€ksy: {summary}",
1164
1196
  "ready": "Valmis ajettavaksi: {summary}",
@@ -1717,11 +1749,43 @@
1717
1749
  "autoSection": "⏱ PyΓΆrii automaattisesti",
1718
1750
  "manualSection": "PyynnΓΆstΓ€",
1719
1751
  "ungrouped": "Muu",
1720
- "axis": { "need": "Tarpeen mukaan", "agent": "Agentin mukaan", "auto": "Automaation mukaan", "tag": "Tagin mukaan", "capability": "Kyvyn mukaan" },
1721
- "sort": { "standing": "Arvokkaimmat", "cost": "Halvimmat", "speed": "Nopeimmat", "name": "A–Ö" },
1722
- "facet": { "cost": "Hinta", "latency": "Nopeus", "verification": "Luotettavuus", "dataHandling": "Tietosuoja", "format": "Tuotos" },
1723
- "format": { "document": "dokumentti", "record": "tietue", "board-post": "tauluviesti", "file": "tiedosto", "app": "sovellus", "image": "kuva", "json": "data (JSON)" },
1724
- "need": { "create": "Luo", "analyze": "Analysoi & pÀÀtÀ", "communicate": "Viesti & kÀÀnnÀ", "build": "Rakenna & automatisoi", "inspect": "Tarkasta & raportoi", "other": "Muu" },
1752
+ "axis": {
1753
+ "need": "Tarpeen mukaan",
1754
+ "agent": "Agentin mukaan",
1755
+ "auto": "Automaation mukaan",
1756
+ "tag": "Tagin mukaan",
1757
+ "capability": "Kyvyn mukaan"
1758
+ },
1759
+ "sort": {
1760
+ "standing": "Arvokkaimmat",
1761
+ "cost": "Halvimmat",
1762
+ "speed": "Nopeimmat",
1763
+ "name": "A–Ö"
1764
+ },
1765
+ "facet": {
1766
+ "cost": "Hinta",
1767
+ "latency": "Nopeus",
1768
+ "verification": "Luotettavuus",
1769
+ "dataHandling": "Tietosuoja",
1770
+ "format": "Tuotos"
1771
+ },
1772
+ "format": {
1773
+ "document": "dokumentti",
1774
+ "record": "tietue",
1775
+ "board-post": "tauluviesti",
1776
+ "file": "tiedosto",
1777
+ "app": "sovellus",
1778
+ "image": "kuva",
1779
+ "json": "data (JSON)"
1780
+ },
1781
+ "need": {
1782
+ "create": "Luo",
1783
+ "analyze": "Analysoi & pÀÀtÀ",
1784
+ "communicate": "Viesti & kÀÀnnÀ",
1785
+ "build": "Rakenna & automatisoi",
1786
+ "inspect": "Tarkasta & raportoi",
1787
+ "other": "Muu"
1788
+ },
1725
1789
  "aiSearch": "Hae tarpeella",
1726
1790
  "aiThinking": "Sovitetaan tarvettasi…",
1727
1791
  "aiResultsTitle": "Parhaat osumat tarpeeseesi",
@@ -1733,12 +1797,41 @@
1733
1797
  "buildForNeed": "Rakenna agentti tΓ€hΓ€n β†’",
1734
1798
  "buildRequested": "Pyydettiin {agent} rakentamaan agentti tΓ€hΓ€n.",
1735
1799
  "noBuilder": "Agenttirakentajaa ei ole. YhdistΓ€ crew-forge ensin.",
1736
- "visibility": { "private": "Yksityinen (vain minΓ€)", "unlisted": "Listaamaton (linkillΓ€)", "public": "Julkinen (listattu)" },
1737
- "status": { "done": "valmis", "failed": "epΓ€onnistui", "active": "kΓ€ynnissΓ€", "paused": "tauolla", "stalled": "jumissa", "queued": "jonossa", "revision_requested": "muutospyyntΓΆ", "draft": "luonnos" },
1738
- "verification": { "deterministic": "deterministinen", "gated": "varmennettu", "ungated": "varmentamaton" },
1739
- "dataHandling": { "local-only": "vain paikallinen", "llm-provider": "LLM:n kautta", "third-party": "kolmas osapuoli" },
1740
- "cost": { "free": "ilmainen", "cheap": "halpa", "expensive": "$$$" },
1741
- "latency": { "seconds": "sekunteja", "minutes": "minuutteja", "long-running": "pitkΓ€kestoinen" },
1800
+ "visibility": {
1801
+ "private": "Yksityinen (vain minΓ€)",
1802
+ "unlisted": "Listaamaton (linkillΓ€)",
1803
+ "public": "Julkinen (listattu)"
1804
+ },
1805
+ "status": {
1806
+ "done": "valmis",
1807
+ "failed": "epΓ€onnistui",
1808
+ "active": "kΓ€ynnissΓ€",
1809
+ "paused": "tauolla",
1810
+ "stalled": "jumissa",
1811
+ "queued": "jonossa",
1812
+ "revision_requested": "muutospyyntΓΆ",
1813
+ "draft": "luonnos"
1814
+ },
1815
+ "verification": {
1816
+ "deterministic": "deterministinen",
1817
+ "gated": "varmennettu",
1818
+ "ungated": "varmentamaton"
1819
+ },
1820
+ "dataHandling": {
1821
+ "local-only": "vain paikallinen",
1822
+ "llm-provider": "LLM:n kautta",
1823
+ "third-party": "kolmas osapuoli"
1824
+ },
1825
+ "cost": {
1826
+ "free": "ilmainen",
1827
+ "cheap": "halpa",
1828
+ "expensive": "$$$"
1829
+ },
1830
+ "latency": {
1831
+ "seconds": "sekunteja",
1832
+ "minutes": "minuutteja",
1833
+ "long-running": "pitkΓ€kestoinen"
1834
+ },
1742
1835
  "consequence": {
1743
1836
  "creates-agent": "luo agentin",
1744
1837
  "creates-schedule": "luo ajastuksen",
@@ -2423,6 +2516,7 @@
2423
2516
  "tasks": "TehtΓ€vΓ€t",
2424
2517
  "messages": "Keskustelu",
2425
2518
  "data_access": "Muisti",
2519
+ "contracts": "Sopimukset",
2426
2520
  "directives": "Ohjeistukset",
2427
2521
  "agent_config": "Agenttiasetukset",
2428
2522
  "activity": "Toiminta",
@@ -2575,6 +2669,18 @@
2575
2669
  "sendError": "Viestin lΓ€hetys epΓ€onnistui",
2576
2670
  "command": "komento"
2577
2671
  },
2672
+ "contracts": {
2673
+ "offersTitle": "Sopimukset joita tΓ€mΓ€ agentti tarjoaa",
2674
+ "offersDesc": "TyΓΆtilasopimukset, joita tΓ€mΓ€ agentti mainostaa. Omistajat nΓ€kevΓ€t nΓ€mΓ€ valitessaan agenttia tyΓΆtilaan.",
2675
+ "noOffers": "TÀmÀ agentti ei mainosta tyâtilasopimusta (lisÀÀ workspace-contract + contract.<id> -tunniste Muisti-vÀlilehdellÀ).",
2676
+ "activeTitle": "Aktiivinen nΓ€issΓ€ tyΓΆtiloissa",
2677
+ "noneActive": "Ei vielÀ aktiivinen missÀÀn tyâtilassa. Omistajat ottavat tÀmÀn agentin kÀyttâân tyâtilan Ihmiset-paneelista.",
2678
+ "retiredTitle": "Poistettu kΓ€ytΓΆstΓ€ (historia)",
2679
+ "since": "alkaen {d}",
2680
+ "until": "kÀytâssÀ tÀÀllÀ {d} asti",
2681
+ "retiredToast": "Poistettu kΓ€ytΓΆstΓ€ β€” agentti ohittaa tΓ€mΓ€n tyΓΆtilan",
2682
+ "readoptedToast": "Otettu uudelleen kΓ€yttΓΆΓΆn β€” agentti jatkaa tΓ€ssΓ€ tyΓΆtilassa"
2683
+ },
2578
2684
  "data_access": {
2579
2685
  "sharedTagsTitle": "Jaetut tunnisteet",
2580
2686
  "addTag": "LisÀÀ tunniste",
@@ -3523,6 +3629,7 @@
3523
3629
  "testBtn": "LΓ€hetΓ€ testi",
3524
3630
  "subscribeSuccess": "Push-ilmoitukset kΓ€ytΓΆssΓ€!",
3525
3631
  "subscribeFailed": "Push-ilmoitusten kΓ€yttΓΆΓΆnotto epΓ€onnistui. Salli ilmoitukset selaimessasi.",
3632
+ "permissionDenied": "Ilmoitukset on estetty tΓ€lle sivustolle. Salli ilmoitukset selaimen sivustoasetuksista ja yritΓ€ uudelleen.",
3526
3633
  "unsubscribeSuccess": "Push-ilmoitukset poistettu kΓ€ytΓΆstΓ€.",
3527
3634
  "unsubscribeFailed": "Push-ilmoitusten poisto epΓ€onnistui.",
3528
3635
  "testSent": "Testi-ilmoitus lΓ€hetetty!",
@@ -4442,6 +4549,8 @@
4442
4549
  "profileBtn": "Profiili",
4443
4550
  "editLocaleHint": "Ensisijainen kielesi. KΓ€ytetÀÀn portaalin kΓ€yttΓΆliittymΓ€ssΓ€; agentit voivat lukea sen profiilistasi ja vastata sillΓ€.",
4444
4551
  "editEmailLink": "Vaihda SΓ€hkΓΆposti-vΓ€lilehdellΓ€ β†’",
4552
+ "editDirectoryListed": "NΓ€ytΓ€ minut jΓ€senluettelossa",
4553
+ "editDirectoryHint": "Oletuksena pois pÀÀltÀ. PÀÀllÀ muut kirjautuneet jÀsenet lâytÀvÀt sinut (nimi, bio, avatar) luettelosta. Anonyymit vierailijat eivÀt koskaan nÀe sitÀ.",
4445
4554
  "pwMin": "VΓ€hintÀÀn 8 merkkiΓ€",
4446
4555
  "pwUpper": "Iso kirjain",
4447
4556
  "pwLower": "Pieni kirjain",
@@ -4864,7 +4973,10 @@
4864
4973
  "appOrigin": "Tarjotaanko kΓ€yttΓ€jien sovellukset erillisestΓ€ sovellusalkuperΓ€stΓ€ (*.apps.<domain>) niiden eristΓ€miseksi istunnostasi? Vaatii DNS:n + jokerimerkki-TLS-varmenteen (katso docs/internal/app-origin-deployment.md). Oletuksena pois pÀÀltΓ€.",
4865
4974
  "appHost": "SovellusalkuperΓ€n isΓ€ntΓ€ (esim. apps.example.com)",
4866
4975
  "appHostHint": "MÀÀritΓ€ ensin DNS (apps.<domain> + jokerimerkki *.apps.<domain>) ja jokerimerkki-TLS-varmenne, katso docs/internal/app-origin-deployment.md",
4867
- "appHostRequired": "SovellusisΓ€ntΓ€ vaaditaan, kun sovellusalkuperΓ€n eristys on kΓ€ytΓΆssΓ€"
4976
+ "appHostRequired": "SovellusisΓ€ntΓ€ vaaditaan, kun sovellusalkuperΓ€n eristys on kΓ€ytΓΆssΓ€",
4977
+ "portfolioOrigin": "Tarjotaanko julkaistut portfoliot omilla osoitteillaan <kÀyttÀjÀnimi>.portfolio.<domain>? Vaatii DNS:n + jokerimerkki-TLS-varmenteen (sama pystytys kuin sovellusalkuperÀllÀ). Oletuksena pois pÀÀltÀ.",
4978
+ "portfolioHost": "Portfolio-alkuperΓ€n isΓ€ntΓ€ (esim. portfolio.example.com)",
4979
+ "portfolioHostRequired": "Portfolio-isΓ€ntΓ€ vaaditaan, kun portfolio-alkuperΓ€ on kΓ€ytΓΆssΓ€"
4868
4980
  },
4869
4981
  "join": {
4870
4982
  "title": "Liity AIMEAT-federaatioon",
@@ -7104,6 +7216,9 @@
7104
7216
  "unpublish": "Poista julkaisusta",
7105
7217
  "unpublished": "Portfolio poistettu julkaisusta",
7106
7218
  "unpublishConfirm": "Poistetaanko portfolio julkaisusta? Julkinen sivu lakkaa toimimasta kunnes julkaiset uudelleen.",
7219
+ "viewStandalone": "Oma osoite",
7220
+ "standaloneTarget": "Tarjoillaan myΓΆs omassa osoitteessa:",
7221
+ "showBadge": "NΓ€ytΓ€ aimeat.io-badge omalla sivulla",
7107
7222
  "customTypePlaceholder": "Kuvaile millaisen portfolion haluat…",
7108
7223
  "customGatePlaceholder": "Kuvaile kirjautumisen takana olevat omat osiot…",
7109
7224
  "backToProfile": "Profiili",
@@ -7117,7 +7232,9 @@
7117
7232
  "notFound": "Portfoliota ei lΓΆytynyt",
7118
7233
  "notFoundDesc": "TΓ€mΓ€ kΓ€yttΓ€jΓ€ ei ole julkaissut portfoliota.",
7119
7234
  "loginToSeeMore": "Kirjaudu sisÀÀn nΓ€hdΓ€ksesi lisÀÀ",
7120
- "backToPortal": "Koti"
7235
+ "backToPortal": "Koti",
7236
+ "fullscreen": "Koko nΓ€yttΓΆ",
7237
+ "standalone": "Oma osoite"
7121
7238
  }
7122
7239
  },
7123
7240
  "cli": {
@@ -7257,7 +7374,8 @@
7257
7374
  "private": "Yksityinen",
7258
7375
  "owner": "Omat agentit",
7259
7376
  "shared": "Omat agentit",
7260
- "group": "Ryhma"
7377
+ "group": "Ryhma",
7378
+ "members": "JΓ€senet (kirjautuneet kΓ€yttΓ€jΓ€t)"
7261
7379
  },
7262
7380
  "federate": "Federoi",
7263
7381
  "federated": "Federoitu",
@@ -7574,6 +7692,14 @@
7574
7692
  "adoptFailed": "KΓ€yttΓΆΓΆnottotehtΓ€vΓ€n jonotus epΓ€onnistui",
7575
7693
  "contractActive": "toimii tÀÀllΓ€",
7576
7694
  "contractActiveHint": "TΓ€mΓ€ agentti tyΓΆskentelee jo tΓ€ssΓ€ tyΓΆtilassa",
7695
+ "retire": "Poista kΓ€ytΓΆstΓ€",
7696
+ "retireHint": "Lopeta tΓ€mΓ€n agentin tyΓΆskentely TΓ„SSΓ„ tyΓΆtilassa β€” sen silmukka ohittaa sen ja merkki muuttuu ”poistettu”. Sen aiempi tyΓΆ sΓ€ilyy historiana.",
7697
+ "retireFailed": "Sopimuksen poistaminen kΓ€ytΓΆstΓ€ epΓ€onnistui",
7698
+ "retired": "{agent} poistettu tΓ€stΓ€ tyΓΆtilasta",
7699
+ "retiredTag": "poistettu",
7700
+ "retiredUntilHint": "Poistettu kΓ€ytΓΆstΓ€ β€” tΓ€mΓ€ agentti palveli tÀÀllΓ€ tΓ€hΓ€n pΓ€ivΓ€mÀÀrÀÀn asti. Sen aiempi tyΓΆ sΓ€ilyy nΓ€kyvissΓ€.",
7701
+ "reAdopt": "Ota uudelleen kΓ€yttΓΆΓΆn",
7702
+ "bareContract": "sopimus",
7577
7703
  "spaceTasksBacked": "TΓ€mΓ€ tila osoittaa tehtΓ€vΓ€jΓ€rjestelmÀÀn: sen sisΓ€ltΓΆ on tehtΓ€viΓ€, ei tyΓΆtilan tietueita. Hallitse niitΓ€ TehtΓ€vΓ€t-nΓ€kymissΓ€.",
7578
7704
  "spaceBackingUnsupported": "TΓ€mΓ€n tilan backing-arvoa ei tueta, joten sen sisΓ€ltΓΆΓ€ ei nΓ€ytetΓ€ tΓ€ssΓ€. Muokkaa tyΓΆtilaa (manifestia) ja vaihda tilan backing-arvoksi \"memory\" palauttaaksesi sen. Tiedostot ja tietopaketit liitetÀÀn LΓ€hteiden tai dokumenttien kuvien kautta.",
7579
7705
  "onePerLine": "yksi per rivi",
@@ -7694,6 +7820,14 @@
7694
7820
  "fieldInterests": "Aiheet",
7695
7821
  "fieldType": "Tyyppi",
7696
7822
  "fieldVisibility": "NΓ€kyvyys",
7823
+ "memberVisLabel": "JΓ€senlista",
7824
+ "memberVisHint": "Kuka nΓ€kee ketkΓ€ kuuluvat tΓ€nne. Piilottaa vain jΓ€senLISTAN β€” sisΓ€llΓΆn tekijΓ€t (kommentit, tietueet, aktiviteetti) nΓ€kyvΓ€t silti, ja luoja/adminit nΓ€ytetÀÀn aina.",
7825
+ "memberVis": {
7826
+ "authenticated": "Kirjautuneet kΓ€yttΓ€jΓ€t",
7827
+ "members": "Vain jΓ€senet",
7828
+ "admins": "Vain adminit",
7829
+ "public": "Julkinen (kaikki)"
7830
+ },
7697
7831
  "formIdentity": "Identiteetti",
7698
7832
  "formAccess": "PÀÀsy",
7699
7833
  "addTag": "LisÀÀ…",
@@ -7821,6 +7955,24 @@
7821
7955
  "copyChatPrompt": "Kopioi chat-prompt",
7822
7956
  "copyCodingPrompt": "Kopioi koodausagentin prompt",
7823
7957
  "agentAccess": "AgenttipÀÀsy",
7958
+ "apps": {
7959
+ "title": "Sovellukset",
7960
+ "hint": "Kiinnitetty tΓ€hΓ€n tyΓΆtilaan β€” avautuvat tyΓΆtila kontekstinaan.",
7961
+ "manage": "Hallitse",
7962
+ "done": "Valmis",
7963
+ "open": "Avaa",
7964
+ "none": "Ei vielΓ€ kiinnitettyjΓ€ sovelluksia.",
7965
+ "noneHint": "KiinnitÀ julkaistu sovellus, niin jÀsenet voivat kÀynnistÀÀ sen tÀstÀ.",
7966
+ "pickerDesc": "Valitse julkaistut sovellukset, jotka nΓ€ytetÀÀn tΓ€ssΓ€ tyΓΆtilassa. Kiinnitys lisÀÀ vain kΓ€ynnistyskortin β€” datan pÀÀsy noudattaa tyΓΆtilan pÀÀsyΓ€.",
7967
+ "search": "Hae sovelluksia…",
7968
+ "noMatch": "Ei osumia.",
7969
+ "catalogEmpty": "TΓ€llΓ€ nodella ei ole vielΓ€ julkaistuja sovelluksia.",
7970
+ "pin": "KiinnitΓ€",
7971
+ "unpin": "Irrota",
7972
+ "saved": "TyΓΆtilan sovellukset pΓ€ivitetty",
7973
+ "saveError": "Sovellusten pΓ€ivitys epΓ€onnistui",
7974
+ "missing": "Ei lΓΆydy katalogista (poistettu?)"
7975
+ },
7824
7976
  "formProcess": "Prosessi",
7825
7977
  "spacesRemoveHint": "NΓ€mΓ€ toiminnot tapahtuvat heti. Tilan poisto piilottaa sen osion: data sΓ€ilyy muistissa ja palaa, jos samanniminen tila lisΓ€tÀÀn uudelleen.",
7826
7978
  "autonomyLevels": {
@@ -8761,5 +8913,14 @@
8761
8913
  "ctaDemo": "Varaa demo β†’",
8762
8914
  "ctaPricing": "Katso hinnat β†’",
8763
8915
  "writtenToday": "kirjoitettu tΓ€nÀÀn klo"
8764
- }
8916
+ },
8917
+ "markdown.embed.loading": "Ladataan…",
8918
+ "markdown.embed.notFound": "Avainta ei lΓΆytynyt",
8919
+ "markdown.embed.signIn": "Kirjaudu nΓ€hdΓ€ksesi tΓ€mΓ€n datan",
8920
+ "markdown.embed.noAccess": "Ei oikeutta lukea tΓ€tΓ€ avainta",
8921
+ "markdown.embed.error": "Lataus epΓ€onnistui",
8922
+ "markdown.embed.empty": "(tyhjΓ€)",
8923
+ "markdown.embed.refresh": "PΓ€ivitΓ€",
8924
+ "markdown.embed.moreRows": "riviÀ lisÀÀ",
8925
+ "markdown.embed.missingKey": "Lohkosta puuttuu key-rivi"
8765
8926
  }
@@ -28,9 +28,13 @@
28
28
  * v1.3.0 -- 2026-06-16 -- Horizontal rules (---, ***, ___) render as <hr>; LIST ITEMS may span
29
29
  * multiple lines (wrapped continuation lines join the current item) so ordered-list numbering no
30
30
  * longer restarts at 1 on every wrapped line.
31
+ * v1.4.0 -- 2026-07-02 -- ```aimeat-memory fenced blocks render as LIVE data embeds (MemoryEmbed):
32
+ * the named memory key is fetched at render time and shown as a table/props/list/value, so a
33
+ * document referencing agent-produced data is fresh on every open.
31
34
  */
32
35
  import { h } from 'preact';
33
36
  import { Mermaid } from './Mermaid.js';
37
+ import { MemoryEmbed } from './MemoryEmbed.js';
34
38
 
35
39
  // Only these schemes may appear in a rendered link. Everything else (javascript:,
36
40
  // data:, vbscript:, file:, etc.) is dropped β€” the anchor renders without href.
@@ -217,6 +221,11 @@ function parseBlocks(src, onWikiLink) {
217
221
  if (lang === 'mermaid') {
218
222
  // ```mermaid β†’ render the diagram (Mermaid lazy-loads its 3MB renderer only when used).
219
223
  blocks.push(h(Mermaid, { chart: codeLines.join('\n') }));
224
+ } else if (lang === 'aimeat-memory') {
225
+ // ```aimeat-memory β†’ live data embed: the named memory key is fetched at render time and
226
+ // shown as a table/props/list/value, so the document is fresh on every open. Access is the
227
+ // server's memory read (workspace rules + entry visibility) β€” denials render a placeholder.
228
+ blocks.push(h(MemoryEmbed, { spec: codeLines.join('\n') }));
220
229
  } else {
221
230
  blocks.push(h('pre', { class: 'md-pre' }, h('code', { class: 'md-code' }, codeLines.join('\n'))));
222
231
  }
@@ -0,0 +1,151 @@
1
+ /**
2
+ * @file MemoryEmbed.js
3
+ * @description Live memory embed for markdown documents: an ```aimeat-memory fenced block names a
4
+ * memory key and this component fetches it AT RENDER TIME and shows the value as a table /
5
+ * property list / list / value β€” so a document that references agent-produced data is fresh every
6
+ * time it is opened, with no sync machinery. Access control is entirely the server's: the memory
7
+ * read applies workspace rules + the entry's visibility, and a 401/403/404 renders as a friendly
8
+ * placeholder (the embed never widens access). All values render via text nodes β€” no HTML surface.
9
+ * @structure
10
+ * - parseEmbedSpec(text) β€” parse the fence body (key/owner/view/fields/title lines)
11
+ * - MemoryEmbed({ spec }) — fetch + render (auto view: array-of-objects→table, object→props,
12
+ * array→list, scalar→value; explicit view: table|props|list|value|json), header shows the key,
13
+ * updated-at and a refresh button.
14
+ * @usage import { MemoryEmbed } from '/components/MemoryEmbed.js'; html`<${MemoryEmbed} spec=${body} />`
15
+ * Fence example:
16
+ * ```aimeat-memory
17
+ * key: organism.{id}.w.{ws}.shared.metrics.weekly.latest
18
+ * view: table
19
+ * fields: week, sales, delta
20
+ * ```
21
+ * Optional `owner: <gaii>` reads another identity's PUBLIC key via /v1/memory/:gaii/:key.
22
+ * @version-history
23
+ * v1.0.0 β€” 2026-07-02 β€” Initial: live data embeds for organism/workspace documents.
24
+ */
25
+ import { h } from 'preact';
26
+ import { useEffect, useState, useCallback } from 'preact/hooks';
27
+ import htm from 'htm';
28
+ import { apiGet } from '/js/api.js';
29
+ import { tOr } from '/js/i18n.js';
30
+ const html = htm.bind(h);
31
+
32
+ const MAX_ROWS = 200;
33
+ const MAX_COLS = 10;
34
+ const MAX_CELL = 160;
35
+
36
+ /** Parse the fence body: `key: value` (or `key=value`) lines; fields is a comma list. */
37
+ export function parseEmbedSpec(text) {
38
+ const spec = {};
39
+ String(text || '').split('\n').forEach((line) => {
40
+ const m = line.match(/^\s*([a-zA-Z_-]+)\s*[:=]\s*(.+?)\s*$/);
41
+ if (!m) return;
42
+ const k = m[1].toLowerCase();
43
+ if (k === 'fields') spec.fields = m[2].split(',').map((s) => s.trim()).filter(Boolean);
44
+ else spec[k] = m[2];
45
+ });
46
+ return spec;
47
+ }
48
+
49
+ function cellText(v) {
50
+ if (v == null) return 'β€”';
51
+ const s = typeof v === 'object' ? JSON.stringify(v) : String(v);
52
+ return s.length > MAX_CELL ? s.slice(0, MAX_CELL) + '…' : s;
53
+ }
54
+ function isPlainObject(v) { return v !== null && typeof v === 'object' && !Array.isArray(v); }
55
+
56
+ function pickView(spec, value) {
57
+ const v = (spec.view || 'auto').toLowerCase();
58
+ if (v !== 'auto') return v;
59
+ if (Array.isArray(value)) return value.length && value.every(isPlainObject) ? 'table' : 'list';
60
+ if (isPlainObject(value)) return 'props';
61
+ return 'value';
62
+ }
63
+
64
+ function renderTable(value, fields) {
65
+ const rows = Array.isArray(value) ? value.filter(isPlainObject) : [];
66
+ let cols = fields && fields.length ? fields : [];
67
+ if (!cols.length) {
68
+ const seen = [];
69
+ rows.forEach((r) => Object.keys(r).forEach((k) => { if (!seen.includes(k)) seen.push(k); }));
70
+ cols = seen.slice(0, MAX_COLS);
71
+ }
72
+ const shown = rows.slice(0, MAX_ROWS);
73
+ return html`
74
+ <table>
75
+ <thead><tr>${cols.map((c) => html`<th key=${c}>${c}</th>`)}</tr></thead>
76
+ <tbody>
77
+ ${shown.map((r, i) => html`<tr key=${i}>${cols.map((c) => html`<td key=${c}>${cellText(r[c])}</td>`)}</tr>`)}
78
+ </tbody>
79
+ </table>
80
+ ${rows.length > MAX_ROWS ? html`<div class="md-mem-more">… ${rows.length - MAX_ROWS} ${tOr('markdown.embed.moreRows', 'more rows')}</div>` : null}
81
+ `;
82
+ }
83
+ function renderProps(value) {
84
+ const obj = isPlainObject(value) ? value : {};
85
+ return html`
86
+ <table>
87
+ <tbody>
88
+ ${Object.keys(obj).map((k) => html`<tr key=${k}><th>${k}</th><td>${cellText(obj[k])}</td></tr>`)}
89
+ </tbody>
90
+ </table>
91
+ `;
92
+ }
93
+ function renderList(value) {
94
+ const arr = Array.isArray(value) ? value : [value];
95
+ return html`<ul>${arr.slice(0, MAX_ROWS).map((v, i) => html`<li key=${i}>${cellText(v)}</li>`)}</ul>`;
96
+ }
97
+ function renderJson(value) {
98
+ return html`<pre class="md-pre"><code class="md-code">${JSON.stringify(value, null, 2)}</code></pre>`;
99
+ }
100
+
101
+ /** MemoryEmbed β€” fetch a memory key at render time and show it as live data. */
102
+ export function MemoryEmbed({ spec: rawSpec }) {
103
+ const [state, setState] = useState({ status: 'loading' });
104
+ const load = useCallback(async () => {
105
+ const spec = parseEmbedSpec(rawSpec);
106
+ if (!spec.key) { setState({ status: 'error', msg: tOr('markdown.embed.missingKey', 'The block declares no key') }); return; }
107
+ setState({ status: 'loading' });
108
+ try {
109
+ // owner_scope: read across the owner's identities (GHII + agents), so keys an MCP
110
+ // agent wrote resolve too β€” mirrors the Memory tab's owner-scope reads.
111
+ const path = spec.owner
112
+ ? '/v1/memory/' + encodeURIComponent(spec.owner) + '/' + encodeURIComponent(spec.key)
113
+ : '/v1/memory/' + encodeURIComponent(spec.key) + '?owner_scope=true';
114
+ const resp = await apiGet(path);
115
+ setState({ status: 'ok', value: resp?.data?.value, updatedAt: resp?.data?.updated_at || null });
116
+ } catch (e) {
117
+ const code = e.code || '';
118
+ let msg;
119
+ if (code === 'NOT_FOUND' || e.status === 404) msg = tOr('markdown.embed.notFound', 'Key not found');
120
+ else if (e.status === 401 || code === 'AUTH_REQUIRED') msg = tOr('markdown.embed.signIn', 'Sign in to view this data');
121
+ else if (e.status === 403 || /SCOPE|FORBIDDEN|CONSENT|ACCESS|DENIED/.test(code)) msg = tOr('markdown.embed.noAccess', 'No permission to read this key');
122
+ else msg = tOr('markdown.embed.error', 'Could not load') + ' (' + (e.message || code || '?') + ')';
123
+ setState({ status: 'error', msg });
124
+ }
125
+ }, [rawSpec]);
126
+ useEffect(() => { load(); }, [load]);
127
+
128
+ const spec = parseEmbedSpec(rawSpec);
129
+ let body;
130
+ if (state.status === 'loading') body = html`<div class="md-mem-note">${tOr('markdown.embed.loading', 'Loading…')}</div>`;
131
+ else if (state.status === 'error') body = html`<div class="md-mem-note md-mem-err">πŸ”’ ${state.msg}</div>`;
132
+ else if (state.value == null) body = html`<div class="md-mem-note">${tOr('markdown.embed.empty', '(empty)')}</div>`;
133
+ else {
134
+ const view = pickView(spec, state.value);
135
+ if (view === 'table') body = renderTable(state.value, spec.fields);
136
+ else if (view === 'props') body = renderProps(state.value);
137
+ else if (view === 'list') body = renderList(state.value);
138
+ else if (view === 'json') body = renderJson(state.value);
139
+ else body = html`<div class="md-mem-value">${cellText(state.value)}</div>`;
140
+ }
141
+ return html`
142
+ <div class="md-mem">
143
+ <div class="md-mem-head">
144
+ <span class="md-mem-title">${spec.title || spec.key || 'aimeat-memory'}</span>
145
+ ${state.updatedAt ? html`<span class="md-mem-upd">${new Date(state.updatedAt).toLocaleString()}</span>` : null}
146
+ <button type="button" class="md-mem-refresh" title=${tOr('markdown.embed.refresh', 'Refresh')} onClick=${load}>↻</button>
147
+ </div>
148
+ ${body}
149
+ </div>
150
+ `;
151
+ }
@@ -7,6 +7,9 @@
7
7
  * @structure Mermaid({ chart }) β€” chart is the Mermaid source string.
8
8
  * @usage import { Mermaid } from '/components/Mermaid.js'; html`<${Mermaid} chart=${src} />`
9
9
  * @version-history
10
+ * v1.1.0 β€” 2026-07-02 β€” suppressErrorRendering: mermaid v11 otherwise injects its "Syntax error
11
+ * in text" bomb SVG into <body> on parse failure even though render() rejects; the component's
12
+ * own raw-source fallback already covers the error UX.
10
13
  * v1.0.0 β€” 2026-06-08 β€” Initial: lazy-loaded vendored Mermaid renderer for organism/workspace charts.
11
14
  */
12
15
  import { h } from 'preact';
@@ -25,7 +28,7 @@ function loadMermaid() {
25
28
  s.src = '/lib/mermaid/mermaid.min.js' + (window.__B || '');
26
29
  s.onload = () => {
27
30
  try {
28
- window.mermaid.initialize({ startOnLoad: false, securityLevel: 'strict', theme: 'neutral', flowchart: { htmlLabels: false } });
31
+ window.mermaid.initialize({ startOnLoad: false, securityLevel: 'strict', theme: 'neutral', flowchart: { htmlLabels: false }, suppressErrorRendering: true });
29
32
  resolve(window.mermaid);
30
33
  } catch (e) { reject(e); }
31
34
  };
@@ -4,11 +4,17 @@
4
4
  * in-app notifications (GET /v1/notifications). Opening the dropdown marks them read. Refreshes on
5
5
  * the SSE `aimeat-live-update` event and a 45s poll, so a workspace-access approval (or request)
6
6
  * surfaces without the user having to guess. Self-contained: reads the JWT from window.AIMEAT.auth.
7
- * @structure NotificationBell({ t, onNavigate }) β€” t = i18n fn, onNavigate(path) = SPA navigate.
7
+ * Exports openNotificationLink() β€” the ONE translation from a notification link/URL into SPA
8
+ * navigation, shared by the bell dropdown and the service-worker push-click handler (spa.html).
9
+ * @structure
10
+ * - openNotificationLink(link, onNavigate) β€” deep-link a bell/push notification target
11
+ * - NotificationBell({ t, onNavigate }) β€” t = i18n fn, onNavigate(path) = SPA navigate.
8
12
  * @usage import { NotificationBell } from '/components/NotificationBell.js'; html`<${NotificationBell} t=${t} onNavigate=${navigate} />`
9
13
  * @version-history
10
14
  * v1.0.0 β€” 2026-06-08 β€” Initial: header bell + dropdown + mark-read for the notification inbox.
11
15
  * v1.0.1 β€” 2026-06-19 β€” JSDoc type annotations for frontend type-checking
16
+ * v1.1.0 β€” 2026-07-02 β€” Extract openNotificationLink() so push-notification clicks reuse the
17
+ * same deep-link translation as bell clicks (supports both '#hash' and '?tab=' forms).
12
18
  */
13
19
  import { h } from 'preact';
14
20
  import { useState, useEffect, useRef, useCallback } from 'preact/hooks';
@@ -36,6 +42,43 @@ function relTime(iso) {
36
42
  } catch { return ''; }
37
43
  }
38
44
 
45
+ /**
46
+ * Deep-link a notification target into the SPA. Handles both notification link vocabularies:
47
+ * the bell's hash form ('/v1/profile#organisms', '/v1/profile#inbox/<conversationId>') and the
48
+ * push URL form ('/v1/profile?tab=messages#inbox/<id>'). Profile targets switch tabs in place:
49
+ * prime sessionStorage so a cold profile mount opens the tab, navigate, then dispatch
50
+ * aimeat-open-tab so an already-mounted profile reacts too. Anything else just navigates.
51
+ * @param {string} link
52
+ * @param {(path: string) => void} [onNavigate]
53
+ */
54
+ export function openNotificationLink(link, onNavigate) {
55
+ if (!link) return;
56
+ let url;
57
+ try { url = new URL(link, window.location.origin); } catch { return; }
58
+ if (url.origin === window.location.origin && url.pathname === '/v1/profile') {
59
+ const hashMatch = /^#([a-z]+)(?:\/(.+))?$/i.exec(url.hash || '');
60
+ const rawTab = url.searchParams.get('tab') || (hashMatch ? hashMatch[1] : '');
61
+ if (rawTab) {
62
+ const tabId = rawTab.toLowerCase() === 'inbox' ? 'messages' : rawTab;
63
+ const rest = hashMatch ? (hashMatch[2] || '') : '';
64
+ try {
65
+ sessionStorage.setItem('aimeat-profile-tab', JSON.stringify({ tabId, slot: 'main' }));
66
+ if (tabId === 'messages' && rest) sessionStorage.setItem('aimeat.inbox.open', rest);
67
+ } catch { /* noop */ }
68
+ if (onNavigate) onNavigate('/v1/profile');
69
+ setTimeout(() => window.dispatchEvent(new CustomEvent('aimeat-open-tab', { detail: { tabId } })), 60);
70
+ return;
71
+ }
72
+ }
73
+ // App pages ('/v1/apps/<owner>/<file>') and other non-SPA documents are served by the
74
+ // backend (and may 301 to the isolated app origin) β€” a hard navigation, not SPA routing.
75
+ if (/^\/v1\/apps\//.test(url.pathname) || /\.html$/i.test(url.pathname)) {
76
+ window.location.assign(url.pathname + url.search + url.hash);
77
+ return;
78
+ }
79
+ if (onNavigate) onNavigate(url.pathname + url.search + url.hash);
80
+ }
81
+
39
82
  export function NotificationBell({ t, onNavigate }) {
40
83
  const tr = (k, fb) => (t ? t(k) : null) || fb;
41
84
  const [items, setItems] = useState([]);
@@ -72,24 +115,7 @@ export function NotificationBell({ t, onNavigate }) {
72
115
  };
73
116
  const clickNotif = (n) => {
74
117
  setOpen(false);
75
- if (!n.link) return;
76
- // Profile tab deep-links carry a #hash that the SPA router ignores (it matches on pathname
77
- // only). Translate them into the profile's tab-open mechanism: prime sessionStorage so a cold
78
- // mount opens the tab, navigate to the profile, then dispatch aimeat-open-tab so an
79
- // already-mounted profile reacts too. `#inbox[/<conversationId|requests>]` opens that thread.
80
- const m = /\/v1\/profile#([a-z]+)(?:\/(.+))?$/i.exec(n.link);
81
- if (m) {
82
- const tabId = m[1] === 'inbox' ? 'messages' : m[1];
83
- const rest = m[2] || '';
84
- try {
85
- sessionStorage.setItem('aimeat-profile-tab', JSON.stringify({ tabId, slot: 'main' }));
86
- if (tabId === 'messages' && rest) sessionStorage.setItem('aimeat.inbox.open', rest);
87
- } catch { /* noop */ }
88
- if (onNavigate) onNavigate('/v1/profile');
89
- setTimeout(() => window.dispatchEvent(new CustomEvent('aimeat-open-tab', { detail: { tabId } })), 60);
90
- return;
91
- }
92
- if (onNavigate) onNavigate(n.link);
118
+ openNotificationLink(n.link, onNavigate);
93
119
  };
94
120
 
95
121
  return html`