aimeat 1.16.2 → 1.18.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 (281) hide show
  1. package/dist/.env.example +6 -1
  2. package/dist/locales/en.json +166 -4
  3. package/dist/locales/fi.json +166 -4
  4. package/dist/public/components/Card.js +17 -3
  5. package/dist/public/components/Collapsible.js +39 -0
  6. package/dist/public/components/CopyButton.js +55 -24
  7. package/dist/public/components/DataTable.js +57 -0
  8. package/dist/public/components/EmptyState.js +28 -0
  9. package/dist/public/components/KeyValueRow.js +37 -0
  10. package/dist/public/components/Modal.js +22 -5
  11. package/dist/public/components/Pagination.js +70 -0
  12. package/dist/public/components/SearchBar.js +44 -0
  13. package/dist/public/components/StatusDot.js +29 -0
  14. package/dist/public/components/TagList.js +53 -0
  15. package/dist/public/components/ToggleSwitch.js +28 -0
  16. package/dist/public/components/index.js +41 -1
  17. package/dist/public/css/components/tags.css +24 -0
  18. package/dist/public/css/style-testbed.css +135 -0
  19. package/dist/public/css/theme.css +556 -34
  20. package/dist/public/css/views/admin-agent-integration.css +2 -33
  21. package/dist/public/css/views/admin.css +730 -686
  22. package/dist/public/css/views/agents-detail.css +402 -14
  23. package/dist/public/css/views/help.css +2 -1
  24. package/dist/public/css/views/hobbies.css +53 -33
  25. package/dist/public/css/views/marketplace.css +73 -60
  26. package/dist/public/css/views/openclaw.css +12 -6
  27. package/dist/public/css/views/portal-classic.css +34 -26
  28. package/dist/public/css/views/portal-dev.css +41 -32
  29. package/dist/public/css/views/portal.css +14 -18
  30. package/dist/public/css/views/profile.css +252 -164
  31. package/dist/public/css/views/public-knowledge-viewer.css +18 -6
  32. package/dist/public/css/views/scheduler.css +100 -0
  33. package/dist/public/js/format.js +41 -0
  34. package/dist/public/js/services/agent-tasks.js +14 -1
  35. package/dist/public/js/services/generator-spec-validate.js +5 -1
  36. package/dist/public/js/services/schedules.js +53 -0
  37. package/dist/public/js/style-testbed.js +170 -0
  38. package/dist/public/js/theme.js +114 -0
  39. package/dist/public/spa.html +74 -16
  40. package/dist/public/style-testbed.html +420 -0
  41. package/dist/public/views/admin/agent-integration-tab.js +23 -38
  42. package/dist/public/views/admin/agent-tasks-tab.js +14 -21
  43. package/dist/public/views/admin/chat-instances-tab.js +1 -1
  44. package/dist/public/views/admin/config-tab.js +7 -2
  45. package/dist/public/views/admin/cortex-tab.js +20 -14
  46. package/dist/public/views/admin/csm-tab.js +22 -18
  47. package/dist/public/views/admin/directory-tab.js +3 -3
  48. package/dist/public/views/admin/email-tab.js +23 -28
  49. package/dist/public/views/admin/federation-tab.js +15 -5
  50. package/dist/public/views/admin/generator-debug-tab.js +10 -8
  51. package/dist/public/views/admin/genesis-tab.js +4 -4
  52. package/dist/public/views/admin/ghii-tab.js +3 -3
  53. package/dist/public/views/admin/knowledge-tab.js +15 -5
  54. package/dist/public/views/admin/matching-tab.js +3 -3
  55. package/dist/public/views/admin/memory-tab.js +16 -20
  56. package/dist/public/views/admin/msm-tab.js +30 -17
  57. package/dist/public/views/admin/overview-tab.js +7 -7
  58. package/dist/public/views/admin/packages-tab.js +10 -9
  59. package/dist/public/views/admin/portal-tab.js +14 -4
  60. package/dist/public/views/admin/prompts-tab.js +5 -5
  61. package/dist/public/views/admin/push-tab.js +15 -4
  62. package/dist/public/views/admin/realtime-tab.js +3 -3
  63. package/dist/public/views/admin/services-tab.js +18 -27
  64. package/dist/public/views/admin/shared.js +48 -58
  65. package/dist/public/views/admin/sharing-groups-tab.js +5 -10
  66. package/dist/public/views/admin/stats-tab.js +3 -3
  67. package/dist/public/views/guides.js +9 -13
  68. package/dist/public/views/help.js +3 -24
  69. package/dist/public/views/hobbies.js +47 -41
  70. package/dist/public/views/marketplace.js +42 -34
  71. package/dist/public/views/openclaw.js +0 -1
  72. package/dist/public/views/portal-classic.js +4 -15
  73. package/dist/public/views/portal-dev.js +28 -30
  74. package/dist/public/views/portal.js +16 -21
  75. package/dist/public/views/portfolio.js +11 -12
  76. package/dist/public/views/profile/access-tab.js +250 -1
  77. package/dist/public/views/profile/agents/agent-card.js +75 -4
  78. package/dist/public/views/profile/agents/tab-activity.js +15 -13
  79. package/dist/public/views/profile/agents/tab-agent-config.js +60 -6
  80. package/dist/public/views/profile/agents/tab-integration.js +37 -60
  81. package/dist/public/views/profile/agents/tab-messages.js +10 -1
  82. package/dist/public/views/profile/agents/tab-quality.js +25 -19
  83. package/dist/public/views/profile/agents/tab-schedules.js +110 -0
  84. package/dist/public/views/profile/agents-activity-subtab.js +4 -4
  85. package/dist/public/views/profile/agents-services-subtab.js +5 -4
  86. package/dist/public/views/profile/agents-tab.js +141 -37
  87. package/dist/public/views/profile/agents-tasks-subtab.js +221 -26
  88. package/dist/public/views/profile/calibrator-batch.js +5 -11
  89. package/dist/public/views/profile/calibrator-tab.js +4 -9
  90. package/dist/public/views/profile/chat-sessions-tab.js +9 -5
  91. package/dist/public/views/profile/email-tab.js +2 -2
  92. package/dist/public/views/profile/extensions-tab.js +27 -22
  93. package/dist/public/views/profile/federation-tab.js +4 -1
  94. package/dist/public/views/profile/foundry-detail.js +22 -23
  95. package/dist/public/views/profile/foundry-tab.js +12 -13
  96. package/dist/public/views/profile/generator-dashboard/DebugPanel.js +4 -7
  97. package/dist/public/views/profile/generator-dashboard/use-dashboard-core.js +4 -1
  98. package/dist/public/views/profile/generator-dashboard/use-edit-mode.js +3 -2
  99. package/dist/public/views/profile/generator-detail.js +26 -30
  100. package/dist/public/views/profile/generator-tab.js +5 -5
  101. package/dist/public/views/profile/knowledge-tab.js +12 -12
  102. package/dist/public/views/profile/landing-page.js +100 -149
  103. package/dist/public/views/profile/memory-tab.js +15 -11
  104. package/dist/public/views/profile/node-stats-tab.js +3 -3
  105. package/dist/public/views/profile/nodes-tab.js +10 -3
  106. package/dist/public/views/profile/notifications-tab.js +3 -3
  107. package/dist/public/views/profile/packages-tab.js +14 -14
  108. package/dist/public/views/profile/scheduler-tab.js +340 -0
  109. package/dist/public/views/profile/services-tab.js +1 -1
  110. package/dist/public/views/profile/shared.js +16 -12
  111. package/dist/public/views/profile/wallet-tab.js +27 -50
  112. package/dist/public/views/profile/work-tab.js +29 -31
  113. package/dist/public/views/profile.js +24 -0
  114. package/dist/public/views/public-knowledge-viewer.js +9 -18
  115. package/dist/src/auth/middleware.d.ts +3 -2
  116. package/dist/src/auth/middleware.d.ts.map +1 -1
  117. package/dist/src/auth/middleware.js +78 -3
  118. package/dist/src/auth/middleware.js.map +1 -1
  119. package/dist/src/cli/init-wizard.d.ts.map +1 -1
  120. package/dist/src/cli/init-wizard.js +13 -1
  121. package/dist/src/cli/init-wizard.js.map +1 -1
  122. package/dist/src/config.d.ts +6 -0
  123. package/dist/src/config.d.ts.map +1 -1
  124. package/dist/src/config.js +12 -1
  125. package/dist/src/config.js.map +1 -1
  126. package/dist/src/generated/api-types.d.ts +708 -8
  127. package/dist/src/generated/api-types.d.ts.map +1 -1
  128. package/dist/src/mcp/agent-schedules.d.ts +23 -0
  129. package/dist/src/mcp/agent-schedules.d.ts.map +1 -0
  130. package/dist/src/mcp/agent-schedules.js +175 -0
  131. package/dist/src/mcp/agent-schedules.js.map +1 -0
  132. package/dist/src/mcp/annotations.d.ts.map +1 -1
  133. package/dist/src/mcp/annotations.js +6 -0
  134. package/dist/src/mcp/annotations.js.map +1 -1
  135. package/dist/src/mcp/catalog/definitions.d.ts.map +1 -1
  136. package/dist/src/mcp/catalog/definitions.js +55 -0
  137. package/dist/src/mcp/catalog/definitions.js.map +1 -1
  138. package/dist/src/mcp/catalog/scopes.d.ts.map +1 -1
  139. package/dist/src/mcp/catalog/scopes.js +12 -0
  140. package/dist/src/mcp/catalog/scopes.js.map +1 -1
  141. package/dist/src/mcp/catalog/surfaces.d.ts.map +1 -1
  142. package/dist/src/mcp/catalog/surfaces.js +2 -0
  143. package/dist/src/mcp/catalog/surfaces.js.map +1 -1
  144. package/dist/src/mcp/index.d.ts.map +1 -1
  145. package/dist/src/mcp/index.js +2 -0
  146. package/dist/src/mcp/index.js.map +1 -1
  147. package/dist/src/models/agent-task-schemas.d.ts +6 -0
  148. package/dist/src/models/agent-task-schemas.d.ts.map +1 -1
  149. package/dist/src/models/agent-task-schemas.js +6 -0
  150. package/dist/src/models/agent-task-schemas.js.map +1 -1
  151. package/dist/src/models/schemas.d.ts +1 -0
  152. package/dist/src/models/schemas.d.ts.map +1 -1
  153. package/dist/src/models/schemas.js +4 -0
  154. package/dist/src/models/schemas.js.map +1 -1
  155. package/dist/src/routes/access-tokens.d.ts +17 -0
  156. package/dist/src/routes/access-tokens.d.ts.map +1 -0
  157. package/dist/src/routes/access-tokens.js +164 -0
  158. package/dist/src/routes/access-tokens.js.map +1 -0
  159. package/dist/src/routes/agent-tasks.d.ts +2 -0
  160. package/dist/src/routes/agent-tasks.d.ts.map +1 -1
  161. package/dist/src/routes/agent-tasks.js +118 -23
  162. package/dist/src/routes/agent-tasks.js.map +1 -1
  163. package/dist/src/routes/agents.d.ts.map +1 -1
  164. package/dist/src/routes/agents.js +46 -0
  165. package/dist/src/routes/agents.js.map +1 -1
  166. package/dist/src/routes/ai.d.ts +6 -9
  167. package/dist/src/routes/ai.d.ts.map +1 -1
  168. package/dist/src/routes/ai.js +26 -175
  169. package/dist/src/routes/ai.js.map +1 -1
  170. package/dist/src/routes/apps.d.ts.map +1 -1
  171. package/dist/src/routes/apps.js +104 -34
  172. package/dist/src/routes/apps.js.map +1 -1
  173. package/dist/src/routes/auth.d.ts.map +1 -1
  174. package/dist/src/routes/auth.js +77 -4
  175. package/dist/src/routes/auth.js.map +1 -1
  176. package/dist/src/routes/cortex.d.ts +2 -1
  177. package/dist/src/routes/cortex.d.ts.map +1 -1
  178. package/dist/src/routes/cortex.js +13 -8
  179. package/dist/src/routes/cortex.js.map +1 -1
  180. package/dist/src/routes/extensions.d.ts.map +1 -1
  181. package/dist/src/routes/extensions.js +85 -51
  182. package/dist/src/routes/extensions.js.map +1 -1
  183. package/dist/src/routes/generator.d.ts.map +1 -1
  184. package/dist/src/routes/generator.js +109 -43
  185. package/dist/src/routes/generator.js.map +1 -1
  186. package/dist/src/routes/ghii.d.ts.map +1 -1
  187. package/dist/src/routes/ghii.js +34 -13
  188. package/dist/src/routes/ghii.js.map +1 -1
  189. package/dist/src/routes/libs.d.ts +15 -0
  190. package/dist/src/routes/libs.d.ts.map +1 -1
  191. package/dist/src/routes/libs.js +178 -55
  192. package/dist/src/routes/libs.js.map +1 -1
  193. package/dist/src/routes/portal.d.ts.map +1 -1
  194. package/dist/src/routes/portal.js +1 -0
  195. package/dist/src/routes/portal.js.map +1 -1
  196. package/dist/src/routes/schedules.d.ts +33 -0
  197. package/dist/src/routes/schedules.d.ts.map +1 -0
  198. package/dist/src/routes/schedules.js +380 -0
  199. package/dist/src/routes/schedules.js.map +1 -0
  200. package/dist/src/server-bootstrap/config-init.js +2 -2
  201. package/dist/src/server-bootstrap/config-init.js.map +1 -1
  202. package/dist/src/server-bootstrap/routes-loader.d.ts.map +1 -1
  203. package/dist/src/server-bootstrap/routes-loader.js +7 -0
  204. package/dist/src/server-bootstrap/routes-loader.js.map +1 -1
  205. package/dist/src/server-bootstrap/service-init.d.ts.map +1 -1
  206. package/dist/src/server-bootstrap/service-init.js +2 -1
  207. package/dist/src/server-bootstrap/service-init.js.map +1 -1
  208. package/dist/src/services/access-token.d.ts +28 -0
  209. package/dist/src/services/access-token.d.ts.map +1 -0
  210. package/dist/src/services/access-token.js +37 -0
  211. package/dist/src/services/access-token.js.map +1 -0
  212. package/dist/src/services/ai-completion.d.ts +83 -0
  213. package/dist/src/services/ai-completion.d.ts.map +1 -0
  214. package/dist/src/services/ai-completion.js +187 -0
  215. package/dist/src/services/ai-completion.js.map +1 -0
  216. package/dist/src/services/config-schema.d.ts.map +1 -1
  217. package/dist/src/services/config-schema.js +3 -0
  218. package/dist/src/services/config-schema.js.map +1 -1
  219. package/dist/src/services/generator-prompt-seeds.d.ts.map +1 -1
  220. package/dist/src/services/generator-prompt-seeds.js +6 -3
  221. package/dist/src/services/generator-prompt-seeds.js.map +1 -1
  222. package/dist/src/services/generator-prompts/spec-validate.d.ts.map +1 -1
  223. package/dist/src/services/generator-prompts/spec-validate.js +6 -2
  224. package/dist/src/services/generator-prompts/spec-validate.js.map +1 -1
  225. package/dist/src/services/generator-registration.d.ts +12 -4
  226. package/dist/src/services/generator-registration.d.ts.map +1 -1
  227. package/dist/src/services/generator-registration.js +71 -0
  228. package/dist/src/services/generator-registration.js.map +1 -1
  229. package/dist/src/services/generator-validate.d.ts +10 -0
  230. package/dist/src/services/generator-validate.d.ts.map +1 -1
  231. package/dist/src/services/generator-validate.js +180 -36
  232. package/dist/src/services/generator-validate.js.map +1 -1
  233. package/dist/src/services/owner-session.d.ts +43 -0
  234. package/dist/src/services/owner-session.d.ts.map +1 -0
  235. package/dist/src/services/owner-session.js +175 -0
  236. package/dist/src/services/owner-session.js.map +1 -0
  237. package/dist/src/services/schedule-constraints.d.ts +65 -0
  238. package/dist/src/services/schedule-constraints.d.ts.map +1 -0
  239. package/dist/src/services/schedule-constraints.js +106 -0
  240. package/dist/src/services/schedule-constraints.js.map +1 -0
  241. package/dist/src/services/scheduler.d.ts +34 -0
  242. package/dist/src/services/scheduler.d.ts.map +1 -1
  243. package/dist/src/services/scheduler.js +266 -22
  244. package/dist/src/services/scheduler.js.map +1 -1
  245. package/dist/src/services/skill-bundle/generator.js +19 -0
  246. package/dist/src/services/skill-bundle/generator.js.map +1 -1
  247. package/dist/src/storage/interface.d.ts +48 -4
  248. package/dist/src/storage/interface.d.ts.map +1 -1
  249. package/dist/src/storage/interface.js.map +1 -1
  250. package/dist/src/storage/providers/mongodb/index.d.ts +31 -0
  251. package/dist/src/storage/providers/mongodb/index.d.ts.map +1 -1
  252. package/dist/src/storage/providers/mongodb/index.js +187 -9
  253. package/dist/src/storage/providers/mongodb/index.js.map +1 -1
  254. package/dist/src/storage/providers/sqlite/index.d.ts +31 -0
  255. package/dist/src/storage/providers/sqlite/index.d.ts.map +1 -1
  256. package/dist/src/storage/providers/sqlite/index.js +131 -8
  257. package/dist/src/storage/providers/sqlite/index.js.map +1 -1
  258. package/dist/src/storage/providers/sqlite/repos/agent-task.d.ts.map +1 -1
  259. package/dist/src/storage/providers/sqlite/repos/agent-task.js +6 -4
  260. package/dist/src/storage/providers/sqlite/repos/agent-task.js.map +1 -1
  261. package/dist/src/storage/providers/sqlite/schema.d.ts.map +1 -1
  262. package/dist/src/storage/providers/sqlite/schema.js +79 -8
  263. package/dist/src/storage/providers/sqlite/schema.js.map +1 -1
  264. package/dist/src/storage/repositories/pat.repository.d.ts +40 -0
  265. package/dist/src/storage/repositories/pat.repository.d.ts.map +1 -0
  266. package/dist/src/storage/repositories/pat.repository.js +14 -0
  267. package/dist/src/storage/repositories/pat.repository.js.map +1 -0
  268. package/dist/src/storage/repositories/scheduler.repository.d.ts +2 -0
  269. package/dist/src/storage/repositories/scheduler.repository.d.ts.map +1 -1
  270. package/dist/src/storage/repositories/session.repository.d.ts +51 -0
  271. package/dist/src/storage/repositories/session.repository.d.ts.map +1 -1
  272. package/dist/src/storage/repositories/session.repository.js +12 -0
  273. package/dist/src/storage/repositories/session.repository.js.map +1 -1
  274. package/dist/src/utils/env-config.d.ts.map +1 -1
  275. package/dist/src/utils/env-config.js +25 -1
  276. package/dist/src/utils/env-config.js.map +1 -1
  277. package/dist/src/utils/env-validator.d.ts.map +1 -1
  278. package/dist/src/utils/env-validator.js +4 -0
  279. package/dist/src/utils/env-validator.js.map +1 -1
  280. package/package.json +1 -1
  281. package/prisma/schema.prisma +48 -0
package/dist/.env.example CHANGED
@@ -84,7 +84,12 @@ AIMEAT_PORT=40050
84
84
  # AIMEAT_FEDERATION_DEFAULT_SCOPES=memory:read,catalogue:read
85
85
 
86
86
  # ── Auth & Tokens ──────────────────────────────────────────────
87
- # AIMEAT_JWT_TTL=3600 # JWT lifetime in seconds (default: 1h)
87
+ # AIMEAT_JWT_TTL=3600 # Legacy / agent JWT lifetime in seconds (default: 1h)
88
+ # Owner sessions: short access token + rotating httpOnly refresh cookie (no key re-signing).
89
+ # AIMEAT_ACCESS_TTL=900 # Owner access-token (JWT) lifetime in seconds (default: 15min)
90
+ # AIMEAT_REFRESH_IDLE_DAYS=30 # Owner refresh-cookie idle window in days (default: 30)
91
+ # AIMEAT_REFRESH_ABSOLUTE_DAYS=90 # Owner refresh-cookie hard cap in days, never extended (default: 90)
92
+ # AIMEAT_REFRESH_GRACE_MS=60000 # Refresh-rotation grace window in ms for concurrency (default: 60s)
88
93
  # AIMEAT_OTK_TTL_MS=300000 # OTK expiry in ms (default: 5min)
89
94
  # AIMEAT_OTK_GRACE_MS=60000 # OTK grace period in ms (default: 1min)
90
95
 
@@ -1,4 +1,85 @@
1
1
  {
2
+ "profile.landing.home": "Home",
3
+ "profile.landing.menu": "Menu",
4
+ "profile.tabs.scheduler": "Scheduler",
5
+ "profile.agents.detail.tabs.schedules": "Schedules",
6
+ "profile.scheduler.title": "Scheduler",
7
+ "profile.scheduler.desc": "Every recurring job running for your profile — AIMEAT-managed and your agents' own.",
8
+ "profile.scheduler.loading": "Loading schedules…",
9
+ "profile.scheduler.newSchedule": "New schedule",
10
+ "profile.scheduler.close": "Close",
11
+ "profile.scheduler.triggered": "Schedule run started",
12
+ "profile.scheduler.cancelled": "Schedule cancelled",
13
+ "profile.scheduler.created": "Schedule created",
14
+ "profile.scheduler.saving": "Saving…",
15
+ "profile.scheduler.create": "Create schedule",
16
+ "profile.scheduler.confirmCancel": "Cancel this schedule? Future runs will stop.",
17
+ "profile.scheduler.managedTitle": "AIMEAT-managed",
18
+ "profile.scheduler.noManaged": "No managed schedules yet.",
19
+ "profile.scheduler.extTitle": "Extension cron jobs",
20
+ "profile.scheduler.internalTitle": "Agent internal",
21
+ "profile.scheduler.internalNote": "Self-reported by your agents. AIMEAT displays these but does not run them.",
22
+ "profile.scheduler.never": "Never",
23
+ "profile.scheduler.byAgent": "created by agent",
24
+ "profile.scheduler.pause": "Pause",
25
+ "profile.scheduler.resume": "Resume",
26
+ "profile.scheduler.runNow": "Run now",
27
+ "profile.scheduler.cancel": "Cancel",
28
+ "profile.scheduler.agentDesc": "Schedules running for this agent.",
29
+ "profile.scheduler.dispatchedTitle": "AIMEAT-dispatched",
30
+ "profile.scheduler.noDispatched": "No schedules for this agent yet.",
31
+ "profile.scheduler.noInternal": "This agent has not reported any internal schedules.",
32
+ "profile.scheduler.col.name": "Name",
33
+ "profile.scheduler.col.kind": "Type",
34
+ "profile.scheduler.col.cron": "Schedule",
35
+ "profile.scheduler.col.agent": "Agent",
36
+ "profile.scheduler.col.lastRun": "Last run",
37
+ "profile.scheduler.col.nextRun": "Next run",
38
+ "profile.scheduler.col.runs": "Runs",
39
+ "profile.scheduler.col.extension": "Extension",
40
+ "profile.scheduler.kind.ai": "AI",
41
+ "profile.scheduler.kind.agent_task": "Agent task",
42
+ "profile.scheduler.kind.extension": "Extension",
43
+ "profile.scheduler.kind.core": "Core",
44
+ "profile.scheduler.kindHint.ai": "server runs a model on your key",
45
+ "profile.scheduler.kindHint.agent_task": "queues a task for an agent",
46
+ "profile.scheduler.kindHint.extension": "runs an extension action (free)",
47
+ "profile.scheduler.field.kind": "Type",
48
+ "profile.scheduler.field.displayName": "Name",
49
+ "profile.scheduler.field.schedule": "Schedule",
50
+ "profile.scheduler.field.inputKeys": "Input memory keys (comma-separated)",
51
+ "profile.scheduler.field.prompt": "Prompt",
52
+ "profile.scheduler.field.outputKey": "Output memory key (optional)",
53
+ "profile.scheduler.field.agent": "Agent",
54
+ "profile.scheduler.field.taskTitle": "Task title",
55
+ "profile.scheduler.field.taskDescription": "Task description",
56
+ "profile.scheduler.field.extensionName": "Extension name",
57
+ "profile.scheduler.field.actionId": "Action id",
58
+ "profile.scheduler.field.purpose": "Purpose (optional)",
59
+ "profile.scheduler.ph.displayName": "e.g. Morning news translation",
60
+ "profile.scheduler.ph.timezone": "IANA timezone, e.g. Europe/Helsinki",
61
+ "profile.scheduler.ph.inputKeys": "e.g. news.morning.raw, news.sources",
62
+ "profile.scheduler.ph.prompt": "e.g. Translate the news below into Finnish and summarise the top 5 items.",
63
+ "profile.scheduler.ph.outputKey": "auto-generated if left blank",
64
+ "profile.scheduler.ph.agent": "Select an agent…",
65
+ "profile.scheduler.ph.purpose": "Why this runs",
66
+ "profile.scheduler.preset.morning": "Every morning",
67
+ "profile.scheduler.preset.evening": "Every evening",
68
+ "profile.scheduler.preset.hourly": "Hourly",
69
+ "profile.scheduler.preset.custom": "Custom",
70
+ "profile.scheduler.constraints": "Budget guards (optional)",
71
+ "profile.scheduler.maxRuns": "Stop after N runs",
72
+ "profile.scheduler.dailyLimit": "Daily AI spend limit (USD)",
73
+ "profile.scheduler.err.name": "Name is required",
74
+ "profile.scheduler.err.cron": "Schedule (cron) is required",
75
+ "profile.scheduler.err.prompt": "Prompt is required for AI schedules",
76
+ "profile.scheduler.err.agent": "Select an agent",
77
+ "profile.scheduler.err.taskTitle": "Task title is required",
78
+ "profile.scheduler.err.ext": "Extension name and action id are required",
79
+ "profile.scheduler.budgetTitle": "Schedule budget guards",
80
+ "profile.scheduler.budgetDesc": "Default opt-in limits applied to schedules created for this agent.",
81
+ "profile.scheduler.budgetSave": "Save budget guards",
82
+ "profile.scheduler.budgetSaved": "Budget guards saved",
2
83
  "common": {
3
84
  "cancel": "Cancel",
4
85
  "confirm": "Confirm",
@@ -14,7 +95,10 @@
14
95
  "name": "Name",
15
96
  "add": "Add",
16
97
  "yes": "Yes",
17
- "no": "No"
98
+ "no": "No",
99
+ "copy": "Copy",
100
+ "copied": "✓ Copied",
101
+ "error": "Error"
18
102
  },
19
103
  "nav": {
20
104
  "try": "Try it",
@@ -25,7 +109,9 @@
25
109
  "logout": "Log Out",
26
110
  "loggedInAs": "logged in as",
27
111
  "help": "Help",
28
- "admin": "Admin"
112
+ "admin": "Admin",
113
+ "themeToDark": "Switch to dark mode",
114
+ "themeToLight": "Switch to light mode"
29
115
  },
30
116
  "hero": {
31
117
  "title": "Your data is yours. Your AI works for you.",
@@ -325,6 +411,8 @@
325
411
  "domainCatalogue": "Catalogue",
326
412
  "domainGenerator": "Generator",
327
413
  "domainTask": "Tasks",
414
+ "domainCortex": "Cortex (install/activate browser libraries)",
415
+ "domainExt": "Extensions (activate server-side extensions)",
328
416
  "permExecute": "Execute",
329
417
  "permRead": "Read",
330
418
  "permWrite": "Write",
@@ -426,6 +514,37 @@
426
514
  "saved": "Concurrency updated",
427
515
  "error": "Failed to update concurrency"
428
516
  },
517
+ "bucket": {
518
+ "recent": "Recent",
519
+ "keep": "Keep",
520
+ "archive": "Archive",
521
+ "empty": {
522
+ "recent": "No recent tasks.",
523
+ "keep": "Nothing kept. Use ★ Keep on a task to pin it here.",
524
+ "archive": "Archive is empty."
525
+ }
526
+ },
527
+ "search": {
528
+ "toggle": "Search",
529
+ "placeholder": "Search tasks…",
530
+ "noResults": "No tasks match your search.",
531
+ "time": { "all": "All", "today": "Today", "7d": "7d", "30d": "30d" }
532
+ },
533
+ "triage": {
534
+ "keep": "Keep",
535
+ "archive": "Archive",
536
+ "restore": "Restore",
537
+ "keepHint": "Pin to the Keep tab (won't auto-archive)",
538
+ "archiveHint": "Move to the Archive tab",
539
+ "kept": "Moved to Keep",
540
+ "archived": "Archived",
541
+ "restored": "Restored to Recent",
542
+ "error": "Failed to update task"
543
+ },
544
+ "memory": {
545
+ "show": "Memory entries",
546
+ "none": "No memory entries linked to this task yet."
547
+ },
429
548
  "createTask": "Create Task",
430
549
  "cancel": "Cancel",
431
550
  "titleLabel": "Title (optional)",
@@ -672,13 +791,16 @@
672
791
  "integration": "Integration",
673
792
  "tasks": "Tasks",
674
793
  "messages": "Messages",
675
- "data_access": "Data Access",
794
+ "data_access": "Memory",
676
795
  "directives": "Directives",
677
796
  "agent_config": "Agent Config",
678
797
  "activity": "Activity",
679
798
  "services": "Services",
680
799
  "quality": "Quality"
681
800
  },
801
+ "changes": {
802
+ "title": "New since you last looked"
803
+ },
682
804
  "quality": {
683
805
  "performanceTitle": "Performance",
684
806
  "performanceDesc": "How much this agent has done and how fast — computed from its tasks.",
@@ -939,7 +1061,7 @@
939
1061
  "readme": "No README published",
940
1062
  "tasks": "No tasks yet. Create a task to give this agent work.",
941
1063
  "messages": "No messages yet. Send a message or use a command.",
942
- "data_access": "No data access configured. Use the buttons below to add tags, memory areas, or knowledge packages.",
1064
+ "data_access": "No memory configured yet. Use the buttons below to add tags, memory areas, or knowledge packages.",
943
1065
  "agent_config": "No configuration files. The agent will push its config files after the skill bundle is installed.",
944
1066
  "activity": "No activity recorded yet. Events will appear here once the agent starts working.",
945
1067
  "services": "No services declared. The agent can declare services during Hello Integration Step 11."
@@ -1392,6 +1514,46 @@
1392
1514
  "hoverReveal": "Click to copy",
1393
1515
  "keepSafe": "Keep this safe — it's your owner recovery key.",
1394
1516
  "keyCopied": "Key copied to clipboard!",
1517
+ "patTitle": "Agent Access Tokens",
1518
+ "patDesc": "Create a revocable token an agent can use (as a Bearer header) to log in and test your apps. One token can be shared across all your agents.",
1519
+ "patLabelRequired": "Give the token a name",
1520
+ "patScopeRequired": "Select at least one scope, or Full / Operator",
1521
+ "patCreateError": "Failed to create token",
1522
+ "patConfirmRevoke": "Revoke token \"{name}\"? Agents using it lose access immediately.",
1523
+ "patRevoked": "Token revoked",
1524
+ "patOperator": "Operator",
1525
+ "patFullOwner": "Full owner",
1526
+ "patScopes": "scopes",
1527
+ "patCreatedTitle": "Token created — copy it now",
1528
+ "patShownOnce": "This token is shown only once. Store it now; you cannot see it again.",
1529
+ "patCopied": "Token copied",
1530
+ "patAgentPrompt": "Ready-made agent prompt",
1531
+ "patPromptCopied": "Prompt copied",
1532
+ "patDone": "Done",
1533
+ "patLoading": "Loading...",
1534
+ "patEmpty": "No access tokens yet.",
1535
+ "patCreatedAt": "Created",
1536
+ "patLastUsed": "Last used",
1537
+ "patNever": "never",
1538
+ "patExpires": "Expires",
1539
+ "patNoExpiry": "No expiry",
1540
+ "patRevoke": "Revoke",
1541
+ "patCreate": "New Token",
1542
+ "patCreateTitle": "Create Access Token",
1543
+ "patLabel": "Name",
1544
+ "patLabelPlaceholder": "e.g. App tester",
1545
+ "patLevel": "Permissions",
1546
+ "patFullOwnerHint": "acts as you; sees all apps & data",
1547
+ "patOperatorHint": "full node administration (master key)",
1548
+ "patMasterKeyWarn": "Master key — guard it like a password",
1549
+ "patSelectScopes": "Scopes",
1550
+ "patReadOwnerData": "Also read my data (otherwise a clean sandbox)",
1551
+ "patExpiry": "Expiry",
1552
+ "patExpiry1d": "24 hours",
1553
+ "patExpiry7d": "7 days",
1554
+ "patExpiry30d": "30 days",
1555
+ "patCreateBtn": "Create Token",
1556
+ "patCancel": "Cancel",
1395
1557
  "mcpEndpoint": "MCP Endpoint",
1396
1558
  "mcpDesc": "Use this URL to connect MCP-compatible AI platforms to your node.",
1397
1559
  "fedTitle": "Federation Access",
@@ -1,4 +1,85 @@
1
1
  {
2
+ "profile.landing.home": "Etusivu",
3
+ "profile.landing.menu": "Valikko",
4
+ "profile.tabs.scheduler": "Ajastin",
5
+ "profile.agents.detail.tabs.schedules": "Ajastukset",
6
+ "profile.scheduler.title": "Ajastin",
7
+ "profile.scheduler.desc": "Kaikki profiilisi toistuvat ajastukset — AIMEATin hallinnoimat ja agenttiesi omat.",
8
+ "profile.scheduler.loading": "Ladataan ajastuksia…",
9
+ "profile.scheduler.newSchedule": "Uusi ajastus",
10
+ "profile.scheduler.close": "Sulje",
11
+ "profile.scheduler.triggered": "Ajastuksen suoritus käynnistetty",
12
+ "profile.scheduler.cancelled": "Ajastus peruttu",
13
+ "profile.scheduler.created": "Ajastus luotu",
14
+ "profile.scheduler.saving": "Tallennetaan…",
15
+ "profile.scheduler.create": "Luo ajastus",
16
+ "profile.scheduler.confirmCancel": "Perutaanko tämä ajastus? Tulevat suoritukset pysäytetään.",
17
+ "profile.scheduler.managedTitle": "AIMEATin hallinnoimat",
18
+ "profile.scheduler.noManaged": "Ei vielä hallinnoituja ajastuksia.",
19
+ "profile.scheduler.extTitle": "Laajennusten cron-työt",
20
+ "profile.scheduler.internalTitle": "Agentin sisäiset",
21
+ "profile.scheduler.internalNote": "Agenttiesi itse ilmoittamat. AIMEAT näyttää nämä mutta ei suorita niitä.",
22
+ "profile.scheduler.never": "Ei koskaan",
23
+ "profile.scheduler.byAgent": "agentin luoma",
24
+ "profile.scheduler.pause": "Keskeytä",
25
+ "profile.scheduler.resume": "Jatka",
26
+ "profile.scheduler.runNow": "Suorita nyt",
27
+ "profile.scheduler.cancel": "Peruuta",
28
+ "profile.scheduler.agentDesc": "Tälle agentille ajossa olevat ajastukset.",
29
+ "profile.scheduler.dispatchedTitle": "AIMEATin lähettämät",
30
+ "profile.scheduler.noDispatched": "Ei vielä ajastuksia tälle agentille.",
31
+ "profile.scheduler.noInternal": "Tämä agentti ei ole ilmoittanut sisäisiä ajastuksia.",
32
+ "profile.scheduler.col.name": "Nimi",
33
+ "profile.scheduler.col.kind": "Tyyppi",
34
+ "profile.scheduler.col.cron": "Ajastus",
35
+ "profile.scheduler.col.agent": "Agentti",
36
+ "profile.scheduler.col.lastRun": "Edellinen ajo",
37
+ "profile.scheduler.col.nextRun": "Seuraava ajo",
38
+ "profile.scheduler.col.runs": "Ajot",
39
+ "profile.scheduler.col.extension": "Laajennus",
40
+ "profile.scheduler.kind.ai": "Tekoäly",
41
+ "profile.scheduler.kind.agent_task": "Agenttitehtävä",
42
+ "profile.scheduler.kind.extension": "Laajennus",
43
+ "profile.scheduler.kind.core": "Ydin",
44
+ "profile.scheduler.kindHint.ai": "palvelin ajaa mallin avaimellasi",
45
+ "profile.scheduler.kindHint.agent_task": "lisää tehtävän agentin jonoon",
46
+ "profile.scheduler.kindHint.extension": "ajaa laajennuksen toiminnon (ilmainen)",
47
+ "profile.scheduler.field.kind": "Tyyppi",
48
+ "profile.scheduler.field.displayName": "Nimi",
49
+ "profile.scheduler.field.schedule": "Ajastus",
50
+ "profile.scheduler.field.inputKeys": "Syötteen muistiavaimet (pilkuin eroteltuna)",
51
+ "profile.scheduler.field.prompt": "Kehote",
52
+ "profile.scheduler.field.outputKey": "Tuloksen muistiavain (valinnainen)",
53
+ "profile.scheduler.field.agent": "Agentti",
54
+ "profile.scheduler.field.taskTitle": "Tehtävän otsikko",
55
+ "profile.scheduler.field.taskDescription": "Tehtävän kuvaus",
56
+ "profile.scheduler.field.extensionName": "Laajennuksen nimi",
57
+ "profile.scheduler.field.actionId": "Toiminnon tunnus",
58
+ "profile.scheduler.field.purpose": "Tarkoitus (valinnainen)",
59
+ "profile.scheduler.ph.displayName": "esim. Aamu-uutisten käännös",
60
+ "profile.scheduler.ph.timezone": "IANA-aikavyöhyke, esim. Europe/Helsinki",
61
+ "profile.scheduler.ph.inputKeys": "esim. news.morning.raw, news.sources",
62
+ "profile.scheduler.ph.prompt": "esim. Käännä alla olevat uutiset suomeksi ja tiivistä 5 tärkeintä.",
63
+ "profile.scheduler.ph.outputKey": "luodaan automaattisesti jos tyhjä",
64
+ "profile.scheduler.ph.agent": "Valitse agentti…",
65
+ "profile.scheduler.ph.purpose": "Miksi tämä ajetaan",
66
+ "profile.scheduler.preset.morning": "Joka aamu",
67
+ "profile.scheduler.preset.evening": "Joka ilta",
68
+ "profile.scheduler.preset.hourly": "Tunneittain",
69
+ "profile.scheduler.preset.custom": "Mukautettu",
70
+ "profile.scheduler.constraints": "Budjettirajat (valinnainen)",
71
+ "profile.scheduler.maxRuns": "Pysäytä N ajon jälkeen",
72
+ "profile.scheduler.dailyLimit": "Päivittäinen tekoälykulujen raja (USD)",
73
+ "profile.scheduler.err.name": "Nimi vaaditaan",
74
+ "profile.scheduler.err.cron": "Ajastus (cron) vaaditaan",
75
+ "profile.scheduler.err.prompt": "Kehote vaaditaan tekoälyajastuksille",
76
+ "profile.scheduler.err.agent": "Valitse agentti",
77
+ "profile.scheduler.err.taskTitle": "Tehtävän otsikko vaaditaan",
78
+ "profile.scheduler.err.ext": "Laajennuksen nimi ja toiminnon tunnus vaaditaan",
79
+ "profile.scheduler.budgetTitle": "Ajastusten budjettirajat",
80
+ "profile.scheduler.budgetDesc": "Oletusarvoiset valinnaiset rajat, jotka koskevat tälle agentille luotuja ajastuksia.",
81
+ "profile.scheduler.budgetSave": "Tallenna budjettirajat",
82
+ "profile.scheduler.budgetSaved": "Budjettirajat tallennettu",
2
83
  "common": {
3
84
  "cancel": "Peruuta",
4
85
  "confirm": "Vahvista",
@@ -14,7 +95,10 @@
14
95
  "name": "Nimi",
15
96
  "add": "Lisää",
16
97
  "yes": "Kyllä",
17
- "no": "Ei"
98
+ "no": "Ei",
99
+ "copy": "Kopioi",
100
+ "copied": "✓ Kopioitu",
101
+ "error": "Virhe"
18
102
  },
19
103
  "nav": {
20
104
  "try": "Kokeile",
@@ -25,7 +109,9 @@
25
109
  "logout": "Kirjaudu ulos",
26
110
  "loggedInAs": "kirjautuneena",
27
111
  "help": "Apua",
28
- "admin": "Hallinta"
112
+ "admin": "Hallinta",
113
+ "themeToDark": "Vaihda tummaan tilaan",
114
+ "themeToLight": "Vaihda vaaleaan tilaan"
29
115
  },
30
116
  "hero": {
31
117
  "title": "Tietosi on sinun. AI:si työskentelee puolestasi.",
@@ -325,6 +411,8 @@
325
411
  "domainCatalogue": "Hakemisto",
326
412
  "domainGenerator": "Generaattori",
327
413
  "domainTask": "Tehtävät",
414
+ "domainCortex": "Cortex (asenna/aktivoi selainkirjastoja)",
415
+ "domainExt": "Laajennukset (aktivoi palvelinpuolen laajennuksia)",
328
416
  "permExecute": "Suoritus",
329
417
  "permRead": "Luku",
330
418
  "permWrite": "Kirjoitus",
@@ -426,6 +514,37 @@
426
514
  "saved": "Rinnakkaisuus päivitetty",
427
515
  "error": "Rinnakkaisuuden päivitys epäonnistui"
428
516
  },
517
+ "bucket": {
518
+ "recent": "Viimeaikaiset",
519
+ "keep": "Tarpeelliset",
520
+ "archive": "Arkisto",
521
+ "empty": {
522
+ "recent": "Ei viimeaikaisia tehtäviä.",
523
+ "keep": "Ei talteen nostettuja. Käytä ★ Talteen kiinnittääksesi tehtävän tänne.",
524
+ "archive": "Arkisto on tyhjä."
525
+ }
526
+ },
527
+ "search": {
528
+ "toggle": "Haku",
529
+ "placeholder": "Hae tehtäviä…",
530
+ "noResults": "Mikään tehtävä ei vastaa hakua.",
531
+ "time": { "all": "Kaikki", "today": "Tänään", "7d": "7pv", "30d": "30pv" }
532
+ },
533
+ "triage": {
534
+ "keep": "Talteen",
535
+ "archive": "Arkistoi",
536
+ "restore": "Palauta",
537
+ "keepHint": "Kiinnitä Tarpeelliset-välilehdelle (ei auto-arkistoidu)",
538
+ "archiveHint": "Siirrä Arkisto-välilehdelle",
539
+ "kept": "Siirretty Tarpeellisiin",
540
+ "archived": "Arkistoitu",
541
+ "restored": "Palautettu Viimeaikaisiin",
542
+ "error": "Tehtävän päivitys epäonnistui"
543
+ },
544
+ "memory": {
545
+ "show": "Muistimerkinnät",
546
+ "none": "Tähän tehtävään ei ole vielä linkitetty muistimerkintöjä."
547
+ },
429
548
  "createTask": "Luo tehtävä",
430
549
  "cancel": "Peruuta",
431
550
  "titleLabel": "Otsikko (valinnainen)",
@@ -672,13 +791,16 @@
672
791
  "integration": "Integraatio",
673
792
  "tasks": "Tehtävät",
674
793
  "messages": "Viestit",
675
- "data_access": "Datayhteydet",
794
+ "data_access": "Muisti",
676
795
  "directives": "Ohjeistukset",
677
796
  "agent_config": "Agenttiasetukset",
678
797
  "activity": "Toiminta",
679
798
  "services": "Palvelut",
680
799
  "quality": "Laatu"
681
800
  },
801
+ "changes": {
802
+ "title": "Uutta sitten kun viimeksi katsoit"
803
+ },
682
804
  "quality": {
683
805
  "performanceTitle": "Suorituskyky",
684
806
  "performanceDesc": "Kuinka paljon agentti on tehnyt ja kuinka nopeasti — laskettu sen tehtävistä.",
@@ -939,7 +1061,7 @@
939
1061
  "readme": "Ei README:tä julkaistu",
940
1062
  "tasks": "Ei tehtäviä. Luo tehtävä antaaksesi agentille työtä.",
941
1063
  "messages": "Ei viestejä. Lähetä viesti tai käytä komentoa.",
942
- "data_access": "Ei datayhteyksien asetuksia. Lisää tunnisteita, muistialueita tai tietopaketteja alla olevilla painikkeilla.",
1064
+ "data_access": "Ei muistia määritetty. Lisää tunnisteita, muistialueita tai tietopaketteja alla olevilla painikkeilla.",
943
1065
  "agent_config": "Ei asetustiedostoja. Agentti lähettää asetustiedostot taitopaketin asennuksen jälkeen.",
944
1066
  "activity": "Ei tallennettua toimintaa. Tapahtumat ilmestyvät tähän kun agentti aloittaa työskentelyn.",
945
1067
  "services": "Ei ilmoitettuja palveluja. Agentti voi ilmoittaa palvelut Hello-integraation vaiheessa 11."
@@ -1392,6 +1514,46 @@
1392
1514
  "hoverReveal": "Klikkaa kopioidaksesi",
1393
1515
  "keepSafe": "Pidä tämä turvassa — se on palautusavaimesi.",
1394
1516
  "keyCopied": "Avain kopioitu leikepöydälle!",
1517
+ "patTitle": "Agenttien käyttötokenit",
1518
+ "patDesc": "Luo peruutettava token, jota agentti voi käyttää (Bearer-headerina) kirjautuakseen ja testatakseen appejasi. Yhtä tokenia voi jakaa kaikille agenteillesi.",
1519
+ "patLabelRequired": "Anna tokenille nimi",
1520
+ "patScopeRequired": "Valitse vähintään yksi scope, tai Full / Operator",
1521
+ "patCreateError": "Tokenin luonti epäonnistui",
1522
+ "patConfirmRevoke": "Peruutetaanko token \"{name}\"? Sitä käyttävät agentit menettävät pääsyn heti.",
1523
+ "patRevoked": "Token peruutettu",
1524
+ "patOperator": "Operaattori",
1525
+ "patFullOwner": "Täysi omistaja",
1526
+ "patScopes": "scopea",
1527
+ "patCreatedTitle": "Token luotu — kopioi se nyt",
1528
+ "patShownOnce": "Token näytetään vain kerran. Tallenna se nyt; et näe sitä enää uudelleen.",
1529
+ "patCopied": "Token kopioitu",
1530
+ "patAgentPrompt": "Valmis agentti-promptti",
1531
+ "patPromptCopied": "Promptti kopioitu",
1532
+ "patDone": "Valmis",
1533
+ "patLoading": "Ladataan...",
1534
+ "patEmpty": "Ei käyttötokeneita vielä.",
1535
+ "patCreatedAt": "Luotu",
1536
+ "patLastUsed": "Viimeksi käytetty",
1537
+ "patNever": "ei koskaan",
1538
+ "patExpires": "Vanhenee",
1539
+ "patNoExpiry": "Ei vanhene",
1540
+ "patRevoke": "Peruuta",
1541
+ "patCreate": "Uusi token",
1542
+ "patCreateTitle": "Luo käyttötoken",
1543
+ "patLabel": "Nimi",
1544
+ "patLabelPlaceholder": "esim. App-testaaja",
1545
+ "patLevel": "Oikeudet",
1546
+ "patFullOwnerHint": "toimii sinuna; näkee kaikki appsit ja datan",
1547
+ "patOperatorHint": "koko noden hallinta (master-avain)",
1548
+ "patMasterKeyWarn": "Master-avain — säilytä kuin salasana",
1549
+ "patSelectScopes": "Scopet",
1550
+ "patReadOwnerData": "Lue myös minun dataani (muuten puhdas hiekkalaatikko)",
1551
+ "patExpiry": "Vanheneminen",
1552
+ "patExpiry1d": "24 tuntia",
1553
+ "patExpiry7d": "7 päivää",
1554
+ "patExpiry30d": "30 päivää",
1555
+ "patCreateBtn": "Luo token",
1556
+ "patCancel": "Peruuta",
1395
1557
  "mcpEndpoint": "MCP-päätepiste",
1396
1558
  "mcpDesc": "Käytä tätä URL:iä yhdistääksesi MCP-yhteensopivat AI-alustat solmuusi.",
1397
1559
  "fedTitle": "Federaatioyhteys",
@@ -1,14 +1,28 @@
1
+ /**
2
+ * @file Card.js
3
+ * @description Canonical themed card container (.card). Renders an optional
4
+ * header (title/subtitle) and arbitrary children. The `variant` prop selects
5
+ * a tokenized modifier — `variant="glass"` adds `.card-glass` (the former
6
+ * profile `.pf-glass-card` appearance) so profile's GlassCard can delegate here.
7
+ * @structure Card({ title, subtitle, onClick, hoverable, className, variant, children })
8
+ * @usage import { Card } from '/components/Card.js'; html`<${Card} variant="glass">…<//>`
9
+ * @version-history
10
+ * v1.0.0 — prior — Initial canonical card (title/subtitle/hoverable/className).
11
+ * v1.1.0 — 2026-06-02 — Component unification (#22): add `variant` prop;
12
+ * `variant="glass"` appends `.card-glass` so profile's GlassCard folds into Card.
13
+ */
1
14
  import { h } from 'preact';
2
15
  import htm from 'htm';
3
16
  const html = htm.bind(h);
4
17
 
5
18
  /**
6
19
  * Card — themed card container.
7
- * @param {{ title?: string, subtitle?: string, onClick?: () => void, hoverable?: boolean, className?: string, children: any }} props
20
+ * @param {{ title?: string, subtitle?: string, onClick?: () => void, hoverable?: boolean, className?: string, variant?: 'glass', children: any }} props
8
21
  */
9
- export function Card({ title, subtitle, onClick, hoverable = true, className = '', children }) {
22
+ export function Card({ title, subtitle, onClick, hoverable = true, className = '', variant, children }) {
23
+ const variantClass = variant === 'glass' ? 'card-glass' : '';
10
24
  return html`
11
- <div class="card ${hoverable ? 'card-hoverable' : ''} ${className}" onClick=${onClick}>
25
+ <div class="card ${variantClass} ${hoverable ? 'card-hoverable' : ''} ${className}" onClick=${onClick}>
12
26
  ${(title || subtitle) && html`
13
27
  <div class="card-header">
14
28
  ${title && html`<span class="card-title">${title}</span>`}
@@ -0,0 +1,39 @@
1
+ import { h } from 'preact';
2
+ import htm from 'htm';
3
+ const html = htm.bind(h);
4
+
5
+ /**
6
+ * @file Collapsible.js
7
+ * @description Canonical expand/collapse (chevron) section — a clickable header
8
+ * (title + a chevron that rotates 180° when open) with its body rendered only
9
+ * while open. CONTROLLED component: the parent owns the `open` state and is
10
+ * notified via `onToggle`. Backed by `.collapsible*` in theme.css, whose colors
11
+ * are all theme tokens so it flips correctly in dark mode. Establishes the
12
+ * canonical shape for the hand-rolled toggles scattered across views
13
+ * (.expand-btn + .pf-chevron, .scope-advanced-toggle, .pkv-entry-arrow); those
14
+ * bespoke toggles are left in place where their expanded markup is wired into
15
+ * view state — this is the target for new collapsible sections.
16
+ * @structure Collapsible({ title, open, onToggle, children }) — renders
17
+ * `<div class="collapsible">` containing a `.collapsible-header` button
18
+ * (title + `.collapsible-chevron` with an `.open` modifier) and, when open, a
19
+ * `.collapsible-body` wrapping the children.
20
+ * @usage
21
+ * import { Collapsible } from '/components/index.js';
22
+ * const [open, setOpen] = useState(false);
23
+ * html`<${Collapsible} title=${t('...')} open=${open} onToggle=${() => setOpen(!open)}>
24
+ * ${body}
25
+ * <//>`
26
+ * @version-history
27
+ * v1.0.0 — 2026-06-02 — Component unification (#23): created canonical
28
+ * expand/collapse section, consolidating the .expand-btn + .pf-chevron,
29
+ * .scope-advanced-toggle and .pkv-entry-arrow toggle patterns.
30
+ */
31
+ export function Collapsible({ title, open, onToggle, children }) {
32
+ return html`<div class="collapsible">
33
+ <button type="button" class="collapsible-header" aria-expanded=${!!open} onClick=${onToggle}>
34
+ <span class="collapsible-title">${title}</span>
35
+ <span class="collapsible-chevron ${open ? 'open' : ''}">▼</span>
36
+ </button>
37
+ ${open && html`<div class="collapsible-body">${children}</div>`}
38
+ </div>`;
39
+ }
@@ -1,24 +1,55 @@
1
- import { h } from 'preact';
2
- import { useState, useCallback } from 'preact/hooks';
3
- import htm from 'htm';
4
- import { copyToClipboard } from '/js/utils.js';
5
- const html = htm.bind(h);
6
-
7
- /**
8
- * CopyButton button with visual feedback after copying.
9
- * @param {{ text: string, label?: string, className?: string }} props
10
- */
11
- export function CopyButton({ text, label = 'Copy', className = '' }) {
12
- const [copied, setCopied] = useState(false);
13
-
14
- const handleCopy = useCallback(async () => {
15
- await copyToClipboard(text);
16
- setCopied(true);
17
- setTimeout(() => setCopied(false), 2000);
18
- }, [text]);
19
-
20
- return html`
21
- <button class="btn-ghost ${className}" onClick=${handleCopy}>
22
- ${copied ? '✓ Copied' : label}
23
- </button>`;
24
- }
1
+ /**
2
+ * @file CopyButton.js
3
+ * @description Canonical clipboard button — copies `text` and shows a brief
4
+ * "copied" confirmation. Replaces the ~80 hand-rolled clipboard sites; the
5
+ * actual copy is delegated to /js/utils.js copyToClipboard.
6
+ * @structure CopyButton({ text, label?, copiedLabel?, className?, title?, onCopied? })
7
+ * @usage import { CopyButton } from '/components/CopyButton.js';
8
+ * html`<${CopyButton} text=${value} />`
9
+ * html`<${CopyButton} text=${value} label=${t('x.copyUrl')} onCopied=${() => showToast('Copied')} />`
10
+ * @version-history
11
+ * v1.0.0 2026-03 Initial copy button with copied-state feedback
12
+ * v1.1.0 2026-06-02 — i18n the labels (default t('common.copy') / t('common.copied')),
13
+ * add onCopied hook (for sites that also toast), copiedLabel, title, type="button",
14
+ * and a `copied` class in the confirmed state (so bespoke classes like
15
+ * .dv-copy-btn.copied / .copy-btn.copied can style it) — for the #1 sweep.
16
+ * v1.1.1 — 2026-06-02 — Compute the button class as a single interpolated string
17
+ * (className-or-base + optional `copied` modifier) — cleaner than two attribute
18
+ * holes and avoids a trailing space. Browser-verified: copied→"…btn-sm copied",
19
+ * default→"btn-ghost". (A stale cached build had briefly masked the copied class
20
+ * during testing — htm itself handles multi-hole class attributes fine.)
21
+ */
22
+ import { h } from 'preact';
23
+ import { useState, useCallback } from 'preact/hooks';
24
+ import htm from 'htm';
25
+ import { copyToClipboard } from '/js/utils.js';
26
+ import { t } from '/js/i18n.js';
27
+ const html = htm.bind(h);
28
+
29
+ /**
30
+ * CopyButton — button with visual feedback after copying.
31
+ * @param {{ text: string, label?: string, copiedLabel?: string, className?: string,
32
+ * title?: string, onCopied?: () => void }} props
33
+ * - label / copiedLabel default to i18n t('common.copy') / t('common.copied')
34
+ * - onCopied: optional callback after a successful copy (e.g. to also show a toast)
35
+ */
36
+ export function CopyButton({ text, label, copiedLabel, className = '', title, onCopied }) {
37
+ const [copied, setCopied] = useState(false);
38
+
39
+ const handleCopy = useCallback(async () => {
40
+ await copyToClipboard(text);
41
+ setCopied(true);
42
+ if (onCopied) onCopied();
43
+ setTimeout(() => setCopied(false), 2000);
44
+ }, [text, onCopied]);
45
+
46
+ // Class as a single computed string: className replaces the btn-ghost base
47
+ // (so callers can pass btn-primary/btn-outline/etc.), plus the `copied` modifier
48
+ // when confirmed (bespoke styles like .hlp-copy-btn.copied hook onto it).
49
+ const cls = `${className || 'btn-ghost'}${copied ? ' copied' : ''}`;
50
+
51
+ return html`
52
+ <button class=${cls} type="button" title=${title} onClick=${handleCopy}>
53
+ ${copied ? (copiedLabel || t('common.copied')) : (label || t('common.copy'))}
54
+ </button>`;
55
+ }