aimeat 3.0.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (211) hide show
  1. package/dist/build-stamp.json +4 -4
  2. package/dist/locales/en.json +9103 -9101
  3. package/dist/locales/es.json +9095 -0
  4. package/dist/locales/fi.json +9103 -9101
  5. package/dist/public/cortex-bundled/aimeat-input.js +611 -0
  6. package/dist/public/cortex-bundled/aimeat-input.yaml +149 -0
  7. package/dist/public/css/views/agents-detail.css +11 -0
  8. package/dist/public/js/utils.js +12 -7
  9. package/dist/public/spa.html +5 -2
  10. package/dist/public/views/admin/email-tab.js +459 -458
  11. package/dist/public/views/profile/agents/agent-card.js +25 -0
  12. package/dist/public/views/profile/agents/scope-model.js +296 -288
  13. package/dist/public/views/profile/agents-tab.js +26 -3
  14. package/dist/scripts/check-ai-disclosure.d.ts.map +1 -1
  15. package/dist/scripts/check-ai-disclosure.js +33 -18
  16. package/dist/scripts/check-ai-disclosure.js.map +1 -1
  17. package/dist/scripts/check-locales.d.ts +2 -0
  18. package/dist/scripts/check-locales.d.ts.map +1 -0
  19. package/dist/scripts/check-locales.js +46 -0
  20. package/dist/scripts/check-locales.js.map +1 -0
  21. package/dist/scripts/lib/locale-files.d.ts +40 -0
  22. package/dist/scripts/lib/locale-files.d.ts.map +1 -0
  23. package/dist/scripts/lib/locale-files.js +181 -0
  24. package/dist/scripts/lib/locale-files.js.map +1 -0
  25. package/dist/scripts/locale-extract.d.ts +2 -0
  26. package/dist/scripts/locale-extract.d.ts.map +1 -0
  27. package/dist/scripts/locale-extract.js +99 -0
  28. package/dist/scripts/locale-extract.js.map +1 -0
  29. package/dist/scripts/locale-merge.d.ts +2 -0
  30. package/dist/scripts/locale-merge.d.ts.map +1 -0
  31. package/dist/scripts/locale-merge.js +114 -0
  32. package/dist/scripts/locale-merge.js.map +1 -0
  33. package/dist/src/auth/middleware.d.ts +6 -0
  34. package/dist/src/auth/middleware.d.ts.map +1 -1
  35. package/dist/src/auth/middleware.js +24 -4
  36. package/dist/src/auth/middleware.js.map +1 -1
  37. package/dist/src/cli/connect/mcp/tools/agent-management.d.ts +1 -0
  38. package/dist/src/cli/connect/mcp/tools/agent-management.d.ts.map +1 -1
  39. package/dist/src/cli/connect/mcp/tools/agent-management.js +9 -0
  40. package/dist/src/cli/connect/mcp/tools/agent-management.js.map +1 -1
  41. package/dist/src/cli/connect/mcp/tools/schedules.d.ts +3 -0
  42. package/dist/src/cli/connect/mcp/tools/schedules.d.ts.map +1 -1
  43. package/dist/src/cli/connect/mcp/tools/schedules.js +5 -0
  44. package/dist/src/cli/connect/mcp/tools/schedules.js.map +1 -1
  45. package/dist/src/cli/connect/tool-call-defs-agent.d.ts +2 -0
  46. package/dist/src/cli/connect/tool-call-defs-agent.d.ts.map +1 -1
  47. package/dist/src/cli/connect/tool-call-defs-agent.js +16 -0
  48. package/dist/src/cli/connect/tool-call-defs-agent.js.map +1 -1
  49. package/dist/src/cli/connect/tool-call-defs-organism.d.ts.map +1 -1
  50. package/dist/src/cli/connect/tool-call-defs-organism.js +6 -0
  51. package/dist/src/cli/connect/tool-call-defs-organism.js.map +1 -1
  52. package/dist/src/config-operator.d.ts +4 -1
  53. package/dist/src/config-operator.d.ts.map +1 -1
  54. package/dist/src/config-operator.js +4 -4
  55. package/dist/src/config-operator.js.map +1 -1
  56. package/dist/src/data/library-packs/cortex.d.ts +3 -0
  57. package/dist/src/data/library-packs/cortex.d.ts.map +1 -1
  58. package/dist/src/data/library-packs/cortex.js +58 -0
  59. package/dist/src/data/library-packs/cortex.js.map +1 -1
  60. package/dist/src/generated/api-types.d.ts +90 -2
  61. package/dist/src/generated/api-types.d.ts.map +1 -1
  62. package/dist/src/i18n.d.ts +1 -1
  63. package/dist/src/i18n.d.ts.map +1 -1
  64. package/dist/src/i18n.js +13 -6
  65. package/dist/src/i18n.js.map +1 -1
  66. package/dist/src/mcp/agent-management.d.ts +6 -2
  67. package/dist/src/mcp/agent-management.d.ts.map +1 -1
  68. package/dist/src/mcp/agent-management.js +34 -3
  69. package/dist/src/mcp/agent-management.js.map +1 -1
  70. package/dist/src/mcp/agent-schedules.d.ts +6 -2
  71. package/dist/src/mcp/agent-schedules.d.ts.map +1 -1
  72. package/dist/src/mcp/agent-schedules.js +22 -1
  73. package/dist/src/mcp/agent-schedules.js.map +1 -1
  74. package/dist/src/mcp/annotations.d.ts +1 -0
  75. package/dist/src/mcp/annotations.d.ts.map +1 -1
  76. package/dist/src/mcp/annotations.js +5 -0
  77. package/dist/src/mcp/annotations.js.map +1 -1
  78. package/dist/src/mcp/catalog/definitions/agent-messaging.d.ts +2 -0
  79. package/dist/src/mcp/catalog/definitions/agent-messaging.d.ts.map +1 -1
  80. package/dist/src/mcp/catalog/definitions/agent-messaging.js +12 -0
  81. package/dist/src/mcp/catalog/definitions/agent-messaging.js.map +1 -1
  82. package/dist/src/mcp/catalog/definitions/schedules-tasks-memory.d.ts.map +1 -1
  83. package/dist/src/mcp/catalog/definitions/schedules-tasks-memory.js +7 -0
  84. package/dist/src/mcp/catalog/definitions/schedules-tasks-memory.js.map +1 -1
  85. package/dist/src/mcp/catalog/scopes.d.ts.map +1 -1
  86. package/dist/src/mcp/catalog/scopes.js +5 -0
  87. package/dist/src/mcp/catalog/scopes.js.map +1 -1
  88. package/dist/src/mcp/catalog/surfaces.d.ts.map +1 -1
  89. package/dist/src/mcp/catalog/surfaces.js +4 -2
  90. package/dist/src/mcp/catalog/surfaces.js.map +1 -1
  91. package/dist/src/routes/admin-features.d.ts.map +1 -1
  92. package/dist/src/routes/admin-features.js +5 -4
  93. package/dist/src/routes/admin-features.js.map +1 -1
  94. package/dist/src/routes/agents/constants.d.ts +18 -2
  95. package/dist/src/routes/agents/constants.d.ts.map +1 -1
  96. package/dist/src/routes/agents/constants.js +18 -2
  97. package/dist/src/routes/agents/constants.js.map +1 -1
  98. package/dist/src/routes/agents/device-auth.d.ts +2 -0
  99. package/dist/src/routes/agents/device-auth.d.ts.map +1 -1
  100. package/dist/src/routes/agents/device-auth.js +22 -2
  101. package/dist/src/routes/agents/device-auth.js.map +1 -1
  102. package/dist/src/routes/agents/management.d.ts +7 -0
  103. package/dist/src/routes/agents/management.d.ts.map +1 -1
  104. package/dist/src/routes/agents/management.js +59 -4
  105. package/dist/src/routes/agents/management.js.map +1 -1
  106. package/dist/src/routes/agents/profile-metadata.d.ts +4 -0
  107. package/dist/src/routes/agents/profile-metadata.d.ts.map +1 -1
  108. package/dist/src/routes/agents/profile-metadata.js +31 -2
  109. package/dist/src/routes/agents/profile-metadata.js.map +1 -1
  110. package/dist/src/routes/agents/registration.d.ts +2 -0
  111. package/dist/src/routes/agents/registration.d.ts.map +1 -1
  112. package/dist/src/routes/agents/registration.js +3 -0
  113. package/dist/src/routes/agents/registration.js.map +1 -1
  114. package/dist/src/routes/ai-transparency.d.ts.map +1 -1
  115. package/dist/src/routes/ai-transparency.js +5 -1
  116. package/dist/src/routes/ai-transparency.js.map +1 -1
  117. package/dist/src/routes/auth.d.ts +3 -0
  118. package/dist/src/routes/auth.d.ts.map +1 -1
  119. package/dist/src/routes/auth.js +22 -5
  120. package/dist/src/routes/auth.js.map +1 -1
  121. package/dist/src/routes/portal.d.ts +3 -0
  122. package/dist/src/routes/portal.d.ts.map +1 -1
  123. package/dist/src/routes/portal.js +39 -17
  124. package/dist/src/routes/portal.js.map +1 -1
  125. package/dist/src/routes/schedules.d.ts +3 -0
  126. package/dist/src/routes/schedules.d.ts.map +1 -1
  127. package/dist/src/routes/schedules.js +16 -29
  128. package/dist/src/routes/schedules.js.map +1 -1
  129. package/dist/src/services/agent-profile-write.d.ts +13 -1
  130. package/dist/src/services/agent-profile-write.d.ts.map +1 -1
  131. package/dist/src/services/agent-profile-write.js +55 -0
  132. package/dist/src/services/agent-profile-write.js.map +1 -1
  133. package/dist/src/services/build-app-prompt.d.ts.map +1 -1
  134. package/dist/src/services/build-app-prompt.js +22 -0
  135. package/dist/src/services/build-app-prompt.js.map +1 -1
  136. package/dist/src/services/email-templates.d.ts.map +1 -1
  137. package/dist/src/services/email-templates.js +79 -3
  138. package/dist/src/services/email-templates.js.map +1 -1
  139. package/dist/src/services/notification-templates.d.ts +5 -3
  140. package/dist/src/services/notification-templates.d.ts.map +1 -1
  141. package/dist/src/services/notification-templates.js +23 -3
  142. package/dist/src/services/notification-templates.js.map +1 -1
  143. package/dist/src/services/schedule-write.d.ts +25 -2
  144. package/dist/src/services/schedule-write.d.ts.map +1 -1
  145. package/dist/src/services/schedule-write.js +44 -0
  146. package/dist/src/services/schedule-write.js.map +1 -1
  147. package/dist/src/storage/providers/postgres-kysely/db-types.d.ts +2 -0
  148. package/dist/src/storage/providers/postgres-kysely/db-types.d.ts.map +1 -1
  149. package/dist/src/storage/providers/postgres-kysely/methods/identity.d.ts.map +1 -1
  150. package/dist/src/storage/providers/postgres-kysely/methods/identity.js +5 -1
  151. package/dist/src/storage/providers/postgres-kysely/methods/identity.js.map +1 -1
  152. package/dist/src/storage/providers/postgres-kysely/methods/sessions.d.ts +1 -0
  153. package/dist/src/storage/providers/postgres-kysely/methods/sessions.d.ts.map +1 -1
  154. package/dist/src/storage/providers/postgres-kysely/methods/sessions.js +4 -0
  155. package/dist/src/storage/providers/postgres-kysely/methods/sessions.js.map +1 -1
  156. package/dist/src/storage/providers/postgres-kysely/migrations/0034_agent_console_url.sql +16 -0
  157. package/dist/src/storage/providers/postgres-kysely/migrations/0035_agent_registered_by.sql +19 -0
  158. package/dist/src/storage/providers/sqlite/methods/extensions-notify.d.ts +2 -0
  159. package/dist/src/storage/providers/sqlite/methods/extensions-notify.d.ts.map +1 -1
  160. package/dist/src/storage/providers/sqlite/methods/extensions-notify.js +4 -0
  161. package/dist/src/storage/providers/sqlite/methods/extensions-notify.js.map +1 -1
  162. package/dist/src/storage/providers/sqlite/methods/owner.d.ts +5 -0
  163. package/dist/src/storage/providers/sqlite/methods/owner.d.ts.map +1 -1
  164. package/dist/src/storage/providers/sqlite/methods/owner.js +13 -4
  165. package/dist/src/storage/providers/sqlite/methods/owner.js.map +1 -1
  166. package/dist/src/storage/providers/sqlite/repos/auth.d.ts +2 -0
  167. package/dist/src/storage/providers/sqlite/repos/auth.d.ts.map +1 -1
  168. package/dist/src/storage/providers/sqlite/repos/auth.js +4 -0
  169. package/dist/src/storage/providers/sqlite/repos/auth.js.map +1 -1
  170. package/dist/src/storage/providers/sqlite/schema-tables-1.d.ts +3 -0
  171. package/dist/src/storage/providers/sqlite/schema-tables-1.d.ts.map +1 -1
  172. package/dist/src/storage/providers/sqlite/schema-tables-1.js +4 -2
  173. package/dist/src/storage/providers/sqlite/schema-tables-1.js.map +1 -1
  174. package/dist/src/storage/providers/sqlite/schema-tables-2.d.ts +3 -0
  175. package/dist/src/storage/providers/sqlite/schema-tables-2.d.ts.map +1 -1
  176. package/dist/src/storage/providers/sqlite/schema-tables-2.js +4 -3
  177. package/dist/src/storage/providers/sqlite/schema-tables-2.js.map +1 -1
  178. package/dist/src/storage/providers/sqlite/schema-tables-3.d.ts +3 -0
  179. package/dist/src/storage/providers/sqlite/schema-tables-3.d.ts.map +1 -1
  180. package/dist/src/storage/providers/sqlite/schema-tables-3.js +6 -9
  181. package/dist/src/storage/providers/sqlite/schema-tables-3.js.map +1 -1
  182. package/dist/src/storage/providers/sqlite/schema.d.ts +6 -0
  183. package/dist/src/storage/providers/sqlite/schema.d.ts.map +1 -1
  184. package/dist/src/storage/providers/sqlite/schema.js +9 -0
  185. package/dist/src/storage/providers/sqlite/schema.js.map +1 -1
  186. package/dist/src/storage/repositories/session.repository.d.ts +14 -0
  187. package/dist/src/storage/repositories/session.repository.d.ts.map +1 -1
  188. package/dist/src/storage/repositories/session.repository.js +2 -0
  189. package/dist/src/storage/repositories/session.repository.js.map +1 -1
  190. package/dist/src/storage/storage-factory.d.ts +6 -0
  191. package/dist/src/storage/storage-factory.d.ts.map +1 -1
  192. package/dist/src/storage/storage-factory.js +38 -19
  193. package/dist/src/storage/storage-factory.js.map +1 -1
  194. package/dist/src/storage/types/identity.d.ts +31 -0
  195. package/dist/src/storage/types/identity.d.ts.map +1 -1
  196. package/dist/src/utils/gaii.d.ts +11 -0
  197. package/dist/src/utils/gaii.d.ts.map +1 -1
  198. package/dist/src/utils/gaii.js +16 -0
  199. package/dist/src/utils/gaii.js.map +1 -1
  200. package/dist/static/sdk-libs/ai/strings.js +5 -2
  201. package/dist/static/sdk-libs/auth/i18n.js +9 -4
  202. package/dist/static/sdk-libs/auth/modal.js +11 -3
  203. package/dist/static/sdk-libs/auth/pill-strings.js +52 -0
  204. package/dist/static/sdk-libs/auth/pill.js +16 -2
  205. package/dist/static/sdk-libs/dist/aimeat-ai.js +30 -1
  206. package/dist/static/sdk-libs/dist/aimeat-auth.js +61 -5
  207. package/dist/static/sdk-libs/dist/aimeat-game.js +32 -2
  208. package/dist/static/sdk-libs/dist/aimeat-header.js +9 -4
  209. package/dist/static/sdk-libs/game/i18n.js +38 -7
  210. package/dist/static/sdk-libs/header/index.js +11 -5
  211. package/package.json +4 -1
@@ -0,0 +1,149 @@
1
+ apiVersion: cortex.aimeat.org/v1
2
+ kind: Extension
3
+ metadata:
4
+ name: aimeat-input
5
+ namespace: aimeat
6
+ description: "Touch and pointer input as one implementation: tap, double-tap, long-press, swipe, drag, a virtual thumbstick, and a keyboard equivalent for each so the same code answers a finger, a mouse and a keyboard. Derives touch-action from the handlers you register, so a horizontal swipe leaves vertical scrolling alive. Zero dependencies, structural CSS only, composes with aimeat-viewport rather than competing with it."
7
+ author: AIMEAT
8
+ tags: [input, touch, gesture, tap, swipe, mobile, pointer, accessibility, ui]
9
+ labels:
10
+ domain: ui
11
+
12
+ spec:
13
+ version: "1.0.0"
14
+ license: MIT
15
+ components:
16
+ - type: prompt
17
+ name: input-assistant
18
+ content: |
19
+ You are an input assistant for an AIMEAT app. The user's node is at {{node_url}}.
20
+
21
+ aimeat-input is GESTURES ON AN ELEMENT. Reach for it when a control has to answer a finger
22
+ as well as a mouse: a card that opens on tap, a row that archives on swipe, a canvas that
23
+ drags, a game that needs a thumbstick. For a movable surface with its own camera (pan, zoom,
24
+ pinch over arbitrary content) use aimeat-viewport, which owns that and is designed to
25
+ compose with this pack through claimFor(). For a graph, a diagram or freehand drawing use
26
+ aimeat-dag, aimeat-flow or aimeat-canvas, each of which already handles its own pointers.
27
+
28
+ Include ONE tag:
29
+ <script src="{{node_url}}/v1/cortex/aimeat-input/libs/aimeat-input.js"></script>
30
+
31
+ START HERE, because it decides most cases correctly on its own:
32
+
33
+ AIMEAT.input.tappable(elOrSelector, onActivate, { size?, role?, label?, haptic? })
34
+
35
+ Use it for every button, card, tile, chip and list row. It listens for `click`, not for
36
+ touchstart, and that is deliberate: the browser already turns a tap into a correct click,
37
+ routes Enter and Space to it, and announces it to a screen reader. What it does not do is
38
+ remove the 300ms tap delay or the grey iOS flash, so tappable() adds `touch-action:
39
+ manipulation`, enforces the 44px minimum target through --ai-touch, and gives a plain
40
+ element the role, tabindex and key handling a real button already has.
41
+
42
+ Hand-rolling `addEventListener('touchstart', …)` produces three bugs at once: the handler
43
+ fires twice (touch then the synthetic click), it triggers while the user is scrolling past,
44
+ and the control becomes unreachable by keyboard. Reach for tappable() instead.
45
+
46
+ WHEN A CLICK IS NOT ENOUGH — a canvas, a map, a row that both taps and swipes:
47
+
48
+ const g = AIMEAT.input.on(elOrSelector, {
49
+ tap(ev, info) {}, doubleTap(ev, info) {}, longPress(ev, info) {},
50
+ swipe(dir, info) {}, // 'left' | 'right' | 'up' | 'down'
51
+ dragStart(ev, info) {}, dragMove(ev, info) {}, dragEnd(ev, info) {},
52
+ }, {
53
+ axis: 'x' | 'y' | 'both', // default 'both'
54
+ keyboard: true, slop: 10, longPressMs: 500, doubleTapMs: 300,
55
+ swipeMinPx: 40, swipeMaxMs: 600, touchAction: 'pan-y', haptic: 'light',
56
+ })
57
+ g.update(newHandlers) · g.destroy()
58
+
59
+ `info` carries { dx, dy, duration, velocity, pointerType, source }, and `source` is
60
+ 'pointer', 'keyboard' or 'contextmenu' so a handler can tell a flick from an arrow key.
61
+
62
+ DECLARE `axis` ON ANYTHING THAT ALSO SCROLLS. The pack sets touch-action from the handlers
63
+ you registered: swipe with axis 'x' becomes `pan-y`, so the user can still scroll the list
64
+ vertically while swiping a row sideways. Leaving axis at 'both' takes the element out of
65
+ scrolling entirely, which is right for a canvas and wrong for a list. This one line is the
66
+ difference between a swipeable list and a list nobody can scroll.
67
+
68
+ EVERY GESTURE HAS A DESKTOP PATH, on by default: arrow keys fire `swipe`, Enter and Space
69
+ fire `tap`, a right click fires `longPress`. An element that reports taps is given
70
+ tabindex="0" when it has none, so it can be reached at all. Keep this on unless the app
71
+ provides its own keyboard route to the same action.
72
+
73
+ THE DOUBLE-FIRE IS ALREADY HANDLED: once a gesture consumes an interaction, the synthetic
74
+ click that follows a tap is swallowed for 400ms, so a handler runs once.
75
+
76
+ A GAME PAD, for a game that needs continuous direction:
77
+
78
+ const stick = AIMEAT.input.pad(hostElOrSelector, {
79
+ mode: 'stick' | 'dpad', floating: true, deadZone: 0.12, keyboard: true,
80
+ onChange({ x, y, angle, distance, active, source }) {},
81
+ })
82
+ stick.value() // read this from the game loop; WASD and the arrows drive the same vector
83
+
84
+ The host needs a SIZE. The pad renders two unpainted elements (.ai-pad-base, .ai-pad-stick)
85
+ and positions them; how they LOOK is the app's own CSS, the same way a skin for aimeat-game
86
+ is written through --ag-* variables alone. Geometry comes from --ai-pad-size and
87
+ --ai-pad-stick.
88
+
89
+ WITH aimeat-viewport, when the app has both a camera and draggable children:
90
+ onClaimPointer: (ev) => {
91
+ const card = ev.target.closest('[data-card]');
92
+ return card ? AIMEAT.input.claimFor({ onMove: (dx, dy) => nudge(card, dx, dy) }) : null;
93
+ }
94
+ The viewport keeps pan, zoom and pinch; this pack says what a gesture on a child means.
95
+
96
+ ALSO: AIMEAT.input.haptic('light'|'medium'|'heavy'|'success'|'warning') buzzes where the
97
+ device allows it and is silent everywhere else, so it is safe to call unconditionally — make
98
+ it a reinforcement of feedback that is already on screen, never the only feedback.
99
+ AIMEAT.input.isCoarse() and .hasHover() report the device, and they are for CHOOSING a
100
+ layout. Both inputs stay supported whatever they return: a laptop with a touchscreen answers
101
+ true to both.
102
+ variables:
103
+ - "{{node_url}}"
104
+
105
+ - type: lib
106
+ name: aimeat-input
107
+ filename: aimeat-input.js
108
+ exports:
109
+ - on
110
+ - tappable
111
+ - haptic
112
+ - pad
113
+ - claimFor
114
+ - isCoarse
115
+ - hasHover
116
+ - injectCss
117
+ api_surface: |
118
+ AIMEAT.input.tappable(elOrSelector, onActivate, { size?, role?, label?, haptic? })
119
+ -> { destroy() }
120
+ The default choice for buttons, cards, tiles and rows. Built on `click`, so a tap, a
121
+ mouse and Enter/Space all arrive the same way and a screen reader announces the control.
122
+ Adds touch-action: manipulation (no 300ms delay), removes the iOS grey flash, enforces the
123
+ 44px minimum target via --ai-touch, and gives a non-native element role + tabindex.
124
+
125
+ AIMEAT.input.on(elOrSelector, { tap, doubleTap, longPress, swipe, dragStart, dragMove,
126
+ dragEnd }, { axis?, keyboard?, slop?, longPressMs?, doubleTapMs?, swipeMinPx?,
127
+ swipeMaxMs?, touchAction?, haptic? })
128
+ -> { el, update(handlers), destroy() }
129
+ Pointer Events only, one gesture per element, a second finger never corrupts one in
130
+ flight, and pointercancel ends a drag cleanly. touch-action is derived from the handlers
131
+ registered: drag -> none, swipe axis 'x' -> pan-y, axis 'y' -> pan-x, tap only ->
132
+ manipulation. Handlers receive info { dx, dy, duration, velocity, pointerType, source }.
133
+
134
+ AIMEAT.input.pad(hostElOrSelector, { mode?, floating?, deadZone?, keyboard?, onChange? })
135
+ -> { host, value(), destroy() }
136
+ Virtual thumbstick or 8-way dpad, with WASD and the arrow keys driving the same normalized
137
+ vector on a desktop. Renders unpainted geometry only; the app skins it.
138
+
139
+ AIMEAT.input.claimFor({ onMove, onEnd }) -> a drag handle for aimeat-viewport's
140
+ onClaimPointer delegate, so the camera and the gestures never fight for one pointer.
141
+
142
+ AIMEAT.input.haptic(kind) -> boolean · isCoarse() · hasHover() · injectCss()
143
+
144
+ Keyboard equivalence is ON by default: arrows fire swipe, Enter/Space fire tap, a right
145
+ click fires longPress. The synthetic click following a consumed gesture is suppressed for
146
+ 400ms, so a handler runs once.
147
+
148
+ Zero dependencies. Structural CSS only (touch-action, target size, pad geometry) — the app
149
+ owns every colour, radius and shadow. Idempotent namespace guard.
@@ -4,6 +4,8 @@
4
4
  * Uses agd- prefix to avoid collisions with other profile styles.
5
5
  * All colors use CSS variables from theme.css.
6
6
  * @version-history
7
+ * v1.21.0 -- 2026-08-13 -- The card-footer host link truncates instead of wrapping: a hostname is
8
+ * one unbreakable token, and wrapping it took the footer row from 31px to 54px at 390px.
7
9
  * v1.20.0 -- 2026-07-17 -- Generalize the card scheme: .pf-agd-card (standalone or
8
10
  * grid child) + .pf-agd-card-grid/--full replace the integration-only
9
11
  * .pf-agd-prod-grid; quality section titles drop the stacked-layout margin-top.
@@ -3187,6 +3189,15 @@
3187
3189
  display: flex;
3188
3190
  gap: 0.5rem;
3189
3191
  }
3192
+ /* The link through to the agent's host carries a hostname, which can be long and is one
3193
+ unbreakable token. Left to wrap it doubled the footer row on a phone (31px → 54px measured at
3194
+ 390px), so it stays on one line and truncates; the full address is in the title. */
3195
+ .pf .pf-agd-card-actions a {
3196
+ max-width: 14rem;
3197
+ overflow: hidden;
3198
+ text-overflow: ellipsis;
3199
+ white-space: nowrap;
3200
+ }
3190
3201
 
3191
3202
  /* ── Input wrapper for autocomplete ── */
3192
3203
  .pf .pf-agd-input-wrap {
@@ -8,12 +8,14 @@ import { swallowed } from '/js/swallowed.js';
8
8
  * @structure
9
9
  * - escHtml/escAttr/decodeEntities: XSS-safe escaping + reversal of double-escaped names
10
10
  * - timeAgo/formatBytes: human-readable time and size formatting
11
- * - detectLocale/persistLocale: en/fi preference via URL → localStorage → cookie → navigator
11
+ * - LOCALES/detectLocale/persistLocale: language preference via URL → localStorage → cookie → navigator
12
12
  * - sanitizeHtml: strip to a safe tag/attribute whitelist
13
13
  * - copyToClipboard/generateStars/handleImgError: clipboard, background stars, image error placeholder
14
14
  *
15
15
  * @version-history
16
16
  * v1.0.0 — 2026-07-13 — Header added; file pre-dates header standard
17
+ * v1.1.0 — 2026-08-12 — Spanish added. detectLocale reads the LOCALES list instead of naming two
18
+ * languages in four places.
17
19
  */
18
20
 
19
21
  /** Micros per whole currency unit — money amounts are 6-decimal micro-units (matches USDC/x402). */
@@ -107,24 +109,27 @@ export async function copyToClipboard(text) {
107
109
  }
108
110
  }
109
111
 
112
+ /** The languages this node ships UI text in. Mirrors LOCALES in src/i18n.ts. */
113
+ export const LOCALES = ['en', 'fi', 'es'];
114
+
110
115
  /** Detect user's preferred locale from URL → localStorage → cookie → navigator. */
111
116
  export function detectLocale() {
112
117
  // 1. URL parameter
113
118
  const params = new URLSearchParams(window.location.search);
114
119
  const langParam = params.get('lang');
115
- if (langParam === 'en' || langParam === 'fi') return langParam;
120
+ if (LOCALES.includes(langParam)) return langParam;
116
121
 
117
122
  // 2. localStorage
118
123
  const stored = localStorage.getItem('aimeat-lang');
119
- if (stored === 'en' || stored === 'fi') return stored;
124
+ if (LOCALES.includes(stored)) return stored;
120
125
 
121
126
  // 3. Cookie
122
- const match = document.cookie.match(/(?:^|;\s*)aimeat-lang=(en|fi)(?:;|$)/);
123
- if (match) return match[1];
127
+ const match = document.cookie.match(/(?:^|;\s*)aimeat-lang=([a-z]{2})(?:;|$)/);
128
+ if (match && LOCALES.includes(match[1])) return match[1];
124
129
 
125
- // 4. Browser language
130
+ // 4. Browser language. 'es-CO' and 'es-419' both answer 'es'.
126
131
  const nav = (navigator.language || '').split('-')[0].toLowerCase();
127
- if (nav === 'fi') return 'fi';
132
+ if (LOCALES.includes(nav)) return nav;
128
133
 
129
134
  return 'en';
130
135
  }
@@ -352,6 +352,7 @@
352
352
  import { useState, useEffect, useCallback, useRef } from 'preact/hooks';
353
353
  import htm from 'htm';
354
354
  import { loadTranslations, t, getLocale, switchLocale, onLocaleChange } from '/js/i18n.js';
355
+ import { LOCALES } from '/js/utils.js';
355
356
  import { initThemeSystem } from '/js/theme.js';
356
357
  import { siteLink } from '/js/site.js';
357
358
  import { NotificationBell, openNotificationLink } from '/components/NotificationBell.js';
@@ -818,8 +819,10 @@
818
819
  `}
819
820
  `}
820
821
  <div class="topnav-center">
821
- <button class="lang-btn ${locale === 'en' ? 'active' : ''}" onClick=${() => handleLangSwitch('en')}>EN</button>
822
- <button class="lang-btn ${locale === 'fi' ? 'active' : ''}" onClick=${() => handleLangSwitch('fi')}>FI</button>
822
+ ${LOCALES.map((l) => html`
823
+ <button class="lang-btn ${locale === l ? 'active' : ''}"
824
+ onClick=${() => handleLangSwitch(l)}>${l.toUpperCase()}</button>
825
+ `)}
823
826
  </div>
824
827
  </div>
825
828
  ${session && html`<${OpenItemsButton} t=${t} onNavigate=${(p) => navigate(p)} />`}