aimeat 1.7.0 → 1.9.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 (261) hide show
  1. package/dist/.env.example +4 -1
  2. package/dist/locales/en.json +573 -10
  3. package/dist/locales/fi.json +572 -9
  4. package/dist/public/css/views/admin-agent-integration.css +304 -0
  5. package/dist/public/css/views/agents-detail.css +1697 -120
  6. package/dist/public/css/views/profile.css +22 -2
  7. package/dist/public/css/views/public-knowledge-viewer.css +479 -0
  8. package/dist/public/js/i18n.js +9 -3
  9. package/dist/public/js/services/admin-agent-integration.js +52 -0
  10. package/dist/public/js/services/agent-integration.js +80 -0
  11. package/dist/public/js/services/agent-messages.js +3 -1
  12. package/dist/public/js/services/generator-spec-validate.js +23 -0
  13. package/dist/public/js/services/memory.js +39 -0
  14. package/dist/public/lib/live-updates.js +9 -4
  15. package/dist/public/llms-template.txt +106 -0
  16. package/dist/public/spa.html +7 -2
  17. package/dist/public/views/admin/agent-integration-tab.js +390 -0
  18. package/dist/public/views/admin/federation-tab.js +5 -5
  19. package/dist/public/views/admin/prompts-tab.js +9 -10
  20. package/dist/public/views/admin.js +2 -0
  21. package/dist/public/views/profile/access-tab.js +18 -0
  22. package/dist/public/views/profile/agents/agent-card.js +396 -0
  23. package/dist/public/views/profile/agents/shared-board.js +97 -0
  24. package/dist/public/views/profile/agents/state-detector.js +62 -0
  25. package/dist/public/views/profile/agents/tab-activity.js +232 -0
  26. package/dist/public/views/profile/agents/tab-agent-config.js +199 -0
  27. package/dist/public/views/profile/agents/tab-data-access.js +304 -0
  28. package/dist/public/views/profile/agents/tab-directives.js +178 -0
  29. package/dist/public/views/profile/agents/tab-integration.js +505 -0
  30. package/dist/public/views/profile/agents/tab-messages.js +278 -0
  31. package/dist/public/views/profile/agents/tab-services.js +17 -0
  32. package/dist/public/views/profile/agents/tab-tasks.js +17 -0
  33. package/dist/public/views/profile/agents-messages-subtab.js +12 -10
  34. package/dist/public/views/profile/agents-services-subtab.js +17 -11
  35. package/dist/public/views/profile/agents-tab.js +159 -255
  36. package/dist/public/views/profile/agents-task-builder.js +403 -0
  37. package/dist/public/views/profile/agents-tasks-subtab.js +186 -140
  38. package/dist/public/views/profile/generator-detail.js +8 -1
  39. package/dist/public/views/profile/memory-tab.js +371 -7
  40. package/dist/public/views/profile/wallet-tab.js +14 -0
  41. package/dist/public/views/public-knowledge-viewer.js +650 -0
  42. package/dist/src/auth/middleware.d.ts.map +1 -1
  43. package/dist/src/auth/middleware.js +17 -0
  44. package/dist/src/auth/middleware.js.map +1 -1
  45. package/dist/src/config.d.ts +1 -0
  46. package/dist/src/config.d.ts.map +1 -1
  47. package/dist/src/config.js +1 -0
  48. package/dist/src/config.js.map +1 -1
  49. package/dist/src/middleware/readiness-gate.d.ts +18 -0
  50. package/dist/src/middleware/readiness-gate.d.ts.map +1 -0
  51. package/dist/src/middleware/readiness-gate.js +50 -0
  52. package/dist/src/middleware/readiness-gate.js.map +1 -0
  53. package/dist/src/models/agent-capabilities-schemas.d.ts +3 -0
  54. package/dist/src/models/agent-capabilities-schemas.d.ts.map +1 -1
  55. package/dist/src/models/agent-capabilities-schemas.js +3 -0
  56. package/dist/src/models/agent-capabilities-schemas.js.map +1 -1
  57. package/dist/src/models/agent-directives-schemas.d.ts +12 -0
  58. package/dist/src/models/agent-directives-schemas.d.ts.map +1 -1
  59. package/dist/src/models/agent-directives-schemas.js +7 -0
  60. package/dist/src/models/agent-directives-schemas.js.map +1 -1
  61. package/dist/src/models/agent-onboarding-schemas.d.ts +45 -0
  62. package/dist/src/models/agent-onboarding-schemas.d.ts.map +1 -0
  63. package/dist/src/models/agent-onboarding-schemas.js +91 -0
  64. package/dist/src/models/agent-onboarding-schemas.js.map +1 -0
  65. package/dist/src/models/webhook-schemas.d.ts +266 -0
  66. package/dist/src/models/webhook-schemas.d.ts.map +1 -0
  67. package/dist/src/models/webhook-schemas.js +137 -0
  68. package/dist/src/models/webhook-schemas.js.map +1 -0
  69. package/dist/src/routes/admin-agent-integration.d.ts +24 -0
  70. package/dist/src/routes/admin-agent-integration.d.ts.map +1 -0
  71. package/dist/src/routes/admin-agent-integration.js +186 -0
  72. package/dist/src/routes/admin-agent-integration.js.map +1 -0
  73. package/dist/src/routes/admin-monitoring.js +12 -7
  74. package/dist/src/routes/admin-monitoring.js.map +1 -1
  75. package/dist/src/routes/agent-activity.d.ts.map +1 -1
  76. package/dist/src/routes/agent-activity.js +17 -0
  77. package/dist/src/routes/agent-activity.js.map +1 -1
  78. package/dist/src/routes/agent-capabilities.d.ts +1 -0
  79. package/dist/src/routes/agent-capabilities.d.ts.map +1 -1
  80. package/dist/src/routes/agent-capabilities.js +9 -0
  81. package/dist/src/routes/agent-capabilities.js.map +1 -1
  82. package/dist/src/routes/agent-directives.d.ts +5 -1
  83. package/dist/src/routes/agent-directives.d.ts.map +1 -1
  84. package/dist/src/routes/agent-directives.js +74 -20
  85. package/dist/src/routes/agent-directives.js.map +1 -1
  86. package/dist/src/routes/agent-integration.d.ts +1 -0
  87. package/dist/src/routes/agent-integration.d.ts.map +1 -1
  88. package/dist/src/routes/agent-integration.js +128 -11
  89. package/dist/src/routes/agent-integration.js.map +1 -1
  90. package/dist/src/routes/agent-messages.d.ts +5 -1
  91. package/dist/src/routes/agent-messages.d.ts.map +1 -1
  92. package/dist/src/routes/agent-messages.js +20 -1
  93. package/dist/src/routes/agent-messages.js.map +1 -1
  94. package/dist/src/routes/agent-onboarding.d.ts +23 -0
  95. package/dist/src/routes/agent-onboarding.d.ts.map +1 -0
  96. package/dist/src/routes/agent-onboarding.js +374 -0
  97. package/dist/src/routes/agent-onboarding.js.map +1 -0
  98. package/dist/src/routes/agent-skill-bundle.d.ts +16 -0
  99. package/dist/src/routes/agent-skill-bundle.d.ts.map +1 -0
  100. package/dist/src/routes/agent-skill-bundle.js +133 -0
  101. package/dist/src/routes/agent-skill-bundle.js.map +1 -0
  102. package/dist/src/routes/agent-tasks.d.ts +8 -1
  103. package/dist/src/routes/agent-tasks.d.ts.map +1 -1
  104. package/dist/src/routes/agent-tasks.js +192 -14
  105. package/dist/src/routes/agent-tasks.js.map +1 -1
  106. package/dist/src/routes/agent-telemetry.d.ts +15 -0
  107. package/dist/src/routes/agent-telemetry.d.ts.map +1 -0
  108. package/dist/src/routes/agent-telemetry.js +99 -0
  109. package/dist/src/routes/agent-telemetry.js.map +1 -0
  110. package/dist/src/routes/agent-webhook.d.ts +18 -0
  111. package/dist/src/routes/agent-webhook.d.ts.map +1 -0
  112. package/dist/src/routes/agent-webhook.js +243 -0
  113. package/dist/src/routes/agent-webhook.js.map +1 -0
  114. package/dist/src/routes/agents.d.ts.map +1 -1
  115. package/dist/src/routes/agents.js +203 -4
  116. package/dist/src/routes/agents.js.map +1 -1
  117. package/dist/src/routes/auth.d.ts.map +1 -1
  118. package/dist/src/routes/auth.js +45 -2
  119. package/dist/src/routes/auth.js.map +1 -1
  120. package/dist/src/routes/federation-auth.d.ts.map +1 -1
  121. package/dist/src/routes/federation-auth.js +3 -1
  122. package/dist/src/routes/federation-auth.js.map +1 -1
  123. package/dist/src/routes/federation-peer.d.ts.map +1 -1
  124. package/dist/src/routes/federation-peer.js +11 -2
  125. package/dist/src/routes/federation-peer.js.map +1 -1
  126. package/dist/src/routes/federation-sync.d.ts +1 -0
  127. package/dist/src/routes/federation-sync.d.ts.map +1 -1
  128. package/dist/src/routes/federation-sync.js +29 -0
  129. package/dist/src/routes/federation-sync.js.map +1 -1
  130. package/dist/src/routes/ghii.d.ts.map +1 -1
  131. package/dist/src/routes/ghii.js +42 -5
  132. package/dist/src/routes/ghii.js.map +1 -1
  133. package/dist/src/routes/knowledge.d.ts.map +1 -1
  134. package/dist/src/routes/knowledge.js +19 -7
  135. package/dist/src/routes/knowledge.js.map +1 -1
  136. package/dist/src/routes/memory.d.ts +9 -0
  137. package/dist/src/routes/memory.d.ts.map +1 -1
  138. package/dist/src/routes/memory.js +307 -12
  139. package/dist/src/routes/memory.js.map +1 -1
  140. package/dist/src/routes/portal.d.ts.map +1 -1
  141. package/dist/src/routes/portal.js +1 -0
  142. package/dist/src/routes/portal.js.map +1 -1
  143. package/dist/src/routes/prompts.d.ts +1 -0
  144. package/dist/src/routes/prompts.d.ts.map +1 -1
  145. package/dist/src/routes/prompts.js +40 -1
  146. package/dist/src/routes/prompts.js.map +1 -1
  147. package/dist/src/routes/sharing-groups.d.ts.map +1 -1
  148. package/dist/src/routes/sharing-groups.js +8 -2
  149. package/dist/src/routes/sharing-groups.js.map +1 -1
  150. package/dist/src/routes/wallet.d.ts.map +1 -1
  151. package/dist/src/routes/wallet.js +2 -0
  152. package/dist/src/routes/wallet.js.map +1 -1
  153. package/dist/src/server-bootstrap/routes-loader.d.ts.map +1 -1
  154. package/dist/src/server-bootstrap/routes-loader.js +47 -3
  155. package/dist/src/server-bootstrap/routes-loader.js.map +1 -1
  156. package/dist/src/services/config-schema.d.ts.map +1 -1
  157. package/dist/src/services/config-schema.js +2 -1
  158. package/dist/src/services/config-schema.js.map +1 -1
  159. package/dist/src/services/core-jobs.d.ts.map +1 -1
  160. package/dist/src/services/core-jobs.js +3 -2
  161. package/dist/src/services/core-jobs.js.map +1 -1
  162. package/dist/src/services/federation-helpers.d.ts +1 -0
  163. package/dist/src/services/federation-helpers.d.ts.map +1 -1
  164. package/dist/src/services/federation-helpers.js +1 -1
  165. package/dist/src/services/federation-helpers.js.map +1 -1
  166. package/dist/src/services/generator-autopilot.d.ts.map +1 -1
  167. package/dist/src/services/generator-autopilot.js +125 -26
  168. package/dist/src/services/generator-autopilot.js.map +1 -1
  169. package/dist/src/services/generator-prompts/index.d.ts +1 -1
  170. package/dist/src/services/generator-prompts/index.d.ts.map +1 -1
  171. package/dist/src/services/generator-prompts/index.js +1 -1
  172. package/dist/src/services/generator-prompts/index.js.map +1 -1
  173. package/dist/src/services/generator-prompts/spec-validate.d.ts +1 -0
  174. package/dist/src/services/generator-prompts/spec-validate.d.ts.map +1 -1
  175. package/dist/src/services/generator-prompts/spec-validate.js +20 -0
  176. package/dist/src/services/generator-prompts/spec-validate.js.map +1 -1
  177. package/dist/src/services/generator-prompts/validate.d.ts +7 -1
  178. package/dist/src/services/generator-prompts/validate.d.ts.map +1 -1
  179. package/dist/src/services/generator-prompts/validate.js +70 -0
  180. package/dist/src/services/generator-prompts/validate.js.map +1 -1
  181. package/dist/src/services/onboarding-validator.d.ts +22 -0
  182. package/dist/src/services/onboarding-validator.d.ts.map +1 -0
  183. package/dist/src/services/onboarding-validator.js +202 -0
  184. package/dist/src/services/onboarding-validator.js.map +1 -0
  185. package/dist/src/services/platform-detector.d.ts +27 -0
  186. package/dist/src/services/platform-detector.d.ts.map +1 -0
  187. package/dist/src/services/platform-detector.js +73 -0
  188. package/dist/src/services/platform-detector.js.map +1 -0
  189. package/dist/src/services/prompt-defaults.d.ts +1 -0
  190. package/dist/src/services/prompt-defaults.d.ts.map +1 -1
  191. package/dist/src/services/prompt-defaults.js +875 -47
  192. package/dist/src/services/prompt-defaults.js.map +1 -1
  193. package/dist/src/services/prompt-seeder.js +1 -1
  194. package/dist/src/services/prompt-seeder.js.map +1 -1
  195. package/dist/src/services/readiness-scorer.d.ts +34 -0
  196. package/dist/src/services/readiness-scorer.d.ts.map +1 -0
  197. package/dist/src/services/readiness-scorer.js +87 -0
  198. package/dist/src/services/readiness-scorer.js.map +1 -0
  199. package/dist/src/services/skill-bundle/generator.d.ts +17 -0
  200. package/dist/src/services/skill-bundle/generator.d.ts.map +1 -0
  201. package/dist/src/services/skill-bundle/generator.js +387 -0
  202. package/dist/src/services/skill-bundle/generator.js.map +1 -0
  203. package/dist/src/services/skill-bundle/generic-adapter.d.ts +16 -0
  204. package/dist/src/services/skill-bundle/generic-adapter.d.ts.map +1 -0
  205. package/dist/src/services/skill-bundle/generic-adapter.js +96 -0
  206. package/dist/src/services/skill-bundle/generic-adapter.js.map +1 -0
  207. package/dist/src/services/skill-bundle/hermes-adapter.d.ts +25 -0
  208. package/dist/src/services/skill-bundle/hermes-adapter.d.ts.map +1 -0
  209. package/dist/src/services/skill-bundle/hermes-adapter.js +302 -0
  210. package/dist/src/services/skill-bundle/hermes-adapter.js.map +1 -0
  211. package/dist/src/services/skill-bundle/types.d.ts +54 -0
  212. package/dist/src/services/skill-bundle/types.d.ts.map +1 -0
  213. package/dist/src/services/skill-bundle/types.js +8 -0
  214. package/dist/src/services/skill-bundle/types.js.map +1 -0
  215. package/dist/src/services/task-stall-detector.d.ts +10 -2
  216. package/dist/src/services/task-stall-detector.d.ts.map +1 -1
  217. package/dist/src/services/task-stall-detector.js +34 -5
  218. package/dist/src/services/task-stall-detector.js.map +1 -1
  219. package/dist/src/services/webhook-dispatcher.d.ts +71 -0
  220. package/dist/src/services/webhook-dispatcher.d.ts.map +1 -0
  221. package/dist/src/services/webhook-dispatcher.js +259 -0
  222. package/dist/src/services/webhook-dispatcher.js.map +1 -0
  223. package/dist/src/storage/interface.d.ts +82 -2
  224. package/dist/src/storage/interface.d.ts.map +1 -1
  225. package/dist/src/storage/providers/mongodb/index.d.ts +20 -1
  226. package/dist/src/storage/providers/mongodb/index.d.ts.map +1 -1
  227. package/dist/src/storage/providers/mongodb/index.js +254 -3
  228. package/dist/src/storage/providers/mongodb/index.js.map +1 -1
  229. package/dist/src/storage/providers/sqlite/index.d.ts +18 -1
  230. package/dist/src/storage/providers/sqlite/index.d.ts.map +1 -1
  231. package/dist/src/storage/providers/sqlite/index.js +173 -4
  232. package/dist/src/storage/providers/sqlite/index.js.map +1 -1
  233. package/dist/src/storage/providers/sqlite/repos/agent-directives.d.ts.map +1 -1
  234. package/dist/src/storage/providers/sqlite/repos/agent-directives.js +8 -4
  235. package/dist/src/storage/providers/sqlite/repos/agent-directives.js.map +1 -1
  236. package/dist/src/storage/providers/sqlite/repos/agent.d.ts.map +1 -1
  237. package/dist/src/storage/providers/sqlite/repos/agent.js +25 -4
  238. package/dist/src/storage/providers/sqlite/repos/agent.js.map +1 -1
  239. package/dist/src/storage/providers/sqlite/schema.d.ts.map +1 -1
  240. package/dist/src/storage/providers/sqlite/schema.js +73 -1
  241. package/dist/src/storage/providers/sqlite/schema.js.map +1 -1
  242. package/dist/src/storage/repositories/agent-onboarding.repository.d.ts +16 -0
  243. package/dist/src/storage/repositories/agent-onboarding.repository.d.ts.map +1 -0
  244. package/dist/src/storage/repositories/agent-onboarding.repository.js +8 -0
  245. package/dist/src/storage/repositories/agent-onboarding.repository.js.map +1 -0
  246. package/dist/src/storage/repositories/agent-webhook.repository.d.ts +21 -0
  247. package/dist/src/storage/repositories/agent-webhook.repository.d.ts.map +1 -0
  248. package/dist/src/storage/repositories/agent-webhook.repository.js +2 -0
  249. package/dist/src/storage/repositories/agent-webhook.repository.js.map +1 -0
  250. package/dist/src/storage/repositories/agent.repository.d.ts +1 -0
  251. package/dist/src/storage/repositories/agent.repository.d.ts.map +1 -1
  252. package/dist/src/storage/repositories/index.d.ts +2 -0
  253. package/dist/src/storage/repositories/index.d.ts.map +1 -1
  254. package/dist/src/utils/env-config.d.ts.map +1 -1
  255. package/dist/src/utils/env-config.js +7 -1
  256. package/dist/src/utils/env-config.js.map +1 -1
  257. package/dist/src/utils/url-validator.d.ts.map +1 -1
  258. package/dist/src/utils/url-validator.js +3 -0
  259. package/dist/src/utils/url-validator.js.map +1 -1
  260. package/package.json +1 -1
  261. package/prisma/schema.prisma +67 -7
@@ -0,0 +1,62 @@
1
+ /**
2
+ * @file state-detector.js
3
+ * @description Determines agent state from onboarding record and agent data.
4
+ * States: 'new' | 'onboarding' | 'problem' | 'idle' | 'production'
5
+ * Also provides default tab selection and state color mapping.
6
+ * @version-history
7
+ * v1.3.0 -- 2026-05-24 -- Remove unused getStateLabel() export (audit fix #7)
8
+ * v1.2.1 -- 2026-05-24 -- Document idle state in design spec, align with audit findings
9
+ * v1.2.0 -- 2026-05-24 -- Add idle state for inactive production agents
10
+ * v1.1.0 -- 2026-05-24 -- Fix: onboarding color to yellow, add readiness drop detection for problem state
11
+ * v1.0.0 -- 2026-05-24 -- Initial creation for Agent Detail Tab-View
12
+ */
13
+
14
+ /**
15
+ * Detect agent state from onboarding record and agent data.
16
+ * Checked in priority order: new > onboarding > problem > idle > production.
17
+ */
18
+ export function detectAgentState(agent, onboarding) {
19
+ if (!onboarding || onboarding.status === 'pending' || onboarding.status === 'not_started') return 'new';
20
+ if (onboarding.status === 'in_progress') return 'onboarding';
21
+
22
+ const webhookDown = (agent.webhookFailCount ?? 0) >= 5;
23
+ const noTelemetry = !agent.last_seen || isStale(agent.last_seen, 24 * 60);
24
+ const readinessDrop = onboarding.previousReadinessLevel && onboarding.readinessLevel
25
+ && readinessRank(onboarding.readinessLevel) < readinessRank(onboarding.previousReadinessLevel);
26
+ if (webhookDown || noTelemetry || readinessDrop) return 'problem';
27
+
28
+ if (!agent.last_seen || isStale(agent.last_seen, 60)) return 'idle';
29
+ return 'production';
30
+ }
31
+
32
+ export function getDefaultTab(state) {
33
+ switch (state) {
34
+ case 'new': return 'integration';
35
+ case 'onboarding': return 'integration';
36
+ case 'problem': return 'integration';
37
+ case 'idle': return 'tasks';
38
+ case 'production': return 'tasks';
39
+ default: return 'tasks';
40
+ }
41
+ }
42
+
43
+ export function getStateColor(state) {
44
+ switch (state) {
45
+ case 'new': return 'var(--warning)';
46
+ case 'onboarding': return 'var(--warning)';
47
+ case 'problem': return 'var(--danger)';
48
+ case 'idle': return 'var(--text-muted)';
49
+ case 'production': return 'var(--success)';
50
+ default: return 'var(--text-muted)';
51
+ }
52
+ }
53
+
54
+ const READINESS_RANKS = { none: 0, basic: 1, standard: 2, advanced: 3, full: 4 };
55
+ function readinessRank(level) {
56
+ return READINESS_RANKS[level] ?? 0;
57
+ }
58
+
59
+ function isStale(isoDate, thresholdMinutes) {
60
+ const diff = Date.now() - new Date(isoDate).getTime();
61
+ return diff > thresholdMinutes * 60 * 1000;
62
+ }
@@ -0,0 +1,232 @@
1
+ /**
2
+ * @file tab-activity.js
3
+ * @description Enhanced Activity tab with governance filter and category badges.
4
+ * Wraps the existing activity subtab with additional filter pills.
5
+ * @version-history
6
+ * v1.4.0 -- 2026-05-24 -- Audit fix: two-line event layout with secondary detail row
7
+ * v1.3.0 -- 2026-05-24 -- Wire up MCP status in delivery health from agent data
8
+ * v1.2.0 -- 2026-05-24 -- Fix: F17 task breakdown, F18 violation red badge, M5 governance i18n namespace
9
+ * v1.1.0 -- 2026-05-24 -- Fix: HH:MM timestamps, token budget %, readiness/override categories, audit trail footer, fix locale prefix
10
+ * v1.0.0 -- 2026-05-24 -- Initial creation for Agent Detail Tab-View
11
+ */
12
+
13
+ import { h } from 'preact';
14
+ import { useState, useEffect, useRef } from 'preact/hooks';
15
+ import htm from 'htm';
16
+ import { t } from '/js/i18n.js';
17
+ import { timeAgo } from '/js/utils.js';
18
+ import { getActivity, getActivityLog } from '/js/services/agent-activity.js';
19
+ import { getDirectives } from '/js/services/agent-directives.js';
20
+ import { getWebhookConfig, getTelemetry, getDeliveryLog } from '/js/services/agent-integration.js';
21
+
22
+ const html = htm.bind(h);
23
+
24
+ const FILTERS = [
25
+ { id: 'all', key: 'profile.agents.detail.activity.filterAll' },
26
+ { id: 'tasks', key: 'profile.agents.detail.activity.filterTasks' },
27
+ { id: 'messages', key: 'profile.agents.detail.activity.filterMessages' },
28
+ { id: 'governance', key: 'profile.agents.detail.activity.filterGovernance' },
29
+ { id: 'system', key: 'profile.agents.detail.activity.filterSystem' },
30
+ ];
31
+
32
+ function eventCategory(event) {
33
+ const type = (event.type || event.event || '').toLowerCase();
34
+ if (type.includes('task') || type.includes('todo')) return 'tasks';
35
+ if (type.includes('message') || type.includes('msg')) return 'messages';
36
+ if (type.includes('approve') || type.includes('scope') || type.includes('permission') || type.includes('governance') || type.includes('policy') || type.includes('readiness') || type.includes('override')) return 'governance';
37
+ return 'system';
38
+ }
39
+
40
+ export default function TabActivity({ agent, agentName, session, showToast }) {
41
+ const [events, setEvents] = useState([]);
42
+ const [stats, setStats] = useState(null);
43
+ const [governance, setGovernance] = useState(null);
44
+ const [loading, setLoading] = useState(true);
45
+ const [filter, setFilter] = useState('all');
46
+ const [logPage, setLogPage] = useState(1);
47
+ const [hasMore, setHasMore] = useState(false);
48
+
49
+ async function loadData() {
50
+ setLoading(true);
51
+ try {
52
+ const [actResp, logResp, dirResp, whResp, telResp] = await Promise.all([
53
+ getActivity(agentName, 30).catch(() => null),
54
+ getActivityLog(agentName, 1, 50).catch(() => null),
55
+ getDirectives(agentName).catch(() => null),
56
+ getWebhookConfig(agentName).catch(() => null),
57
+ getTelemetry(agentName, { days: 1 }).catch(() => null),
58
+ ]);
59
+ setStats(actResp?.data?.activity_stats || null);
60
+ setEvents(logResp?.data?.events || []);
61
+ setHasMore((logResp?.data?.events || []).length >= 50);
62
+ setLogPage(1);
63
+
64
+ const allEvents = logResp?.data?.events || [];
65
+ const todayStart = new Date(); todayStart.setHours(0,0,0,0);
66
+ const todayEvents = allEvents.filter(ev => new Date(ev.timestamp) >= todayStart);
67
+ const govEvents = todayEvents.filter(ev => eventCategory(ev) === 'governance');
68
+ const taskEvents = todayEvents.filter(ev => eventCategory(ev) === 'tasks');
69
+ const tasksCompleted = taskEvents.filter(e => { const tp = (e.type || '').toLowerCase(); return tp.includes('completed') || tp.includes('done'); }).length;
70
+ const tasksActive = taskEvents.filter(e => { const tp = (e.type || '').toLowerCase(); return tp.includes('started') || tp.includes('active'); }).length;
71
+ const tasksFailed = taskEvents.filter(e => { const tp = (e.type || '').toLowerCase(); return tp.includes('failed') || tp.includes('error'); }).length;
72
+ const budget = dirResp?.data?.budget_limits;
73
+ const wh = whResp?.data?.webhook;
74
+ const telemetryEntries = telResp?.data?.entries || [];
75
+
76
+ setGovernance({
77
+ budget,
78
+ tokensUsedToday: telemetryEntries.reduce((sum, e) => sum + (e.tokens_used || 0), 0),
79
+ tasksToday: taskEvents.length,
80
+ tasksCompleted,
81
+ tasksActive,
82
+ tasksFailed,
83
+ policyIssues: govEvents.length,
84
+ telemetryCount: telemetryEntries.length,
85
+ webhookEnabled: wh?.enabled ?? false,
86
+ webhookSuccessCount: wh?.success_count ?? 0,
87
+ webhookTotalCount: (wh?.success_count ?? 0) + (wh?.fail_count ?? 0),
88
+ mcpActive: agent?.mcpEnabled || agent?.mcp_enabled || false,
89
+ });
90
+ } catch {
91
+ setStats(null);
92
+ setEvents([]);
93
+ }
94
+ setLoading(false);
95
+ }
96
+
97
+ useEffect(() => { loadData(); }, [agentName]);
98
+
99
+ const loadRef = useRef(loadData);
100
+ loadRef.current = loadData;
101
+ useEffect(() => {
102
+ const handler = () => loadRef.current();
103
+ window.addEventListener('aimeat-live-update', handler);
104
+ return () => window.removeEventListener('aimeat-live-update', handler);
105
+ }, []);
106
+
107
+ async function handleLoadMore() {
108
+ const nextPage = logPage + 1;
109
+ try {
110
+ const resp = await getActivityLog(agentName, nextPage, 50);
111
+ const newEvents = resp?.data?.events || [];
112
+ setEvents(prev => [...prev, ...newEvents]);
113
+ setLogPage(nextPage);
114
+ setHasMore(newEvents.length >= 50);
115
+ } catch { /* silent */ }
116
+ }
117
+
118
+ if (loading) {
119
+ return html`<div class="pf-agd-empty">${t('profile.loading')}</div>`;
120
+ }
121
+
122
+ const filtered = filter === 'all' ? events : events.filter(ev => eventCategory(ev) === filter);
123
+
124
+ return html`
125
+ <div>
126
+ <!-- Stats summary -->
127
+ ${stats && html`
128
+ <div class="pf-agd-stats-grid">
129
+ <div class="pf-agd-stat-card">
130
+ <div class="pf-agd-stat-value">${stats.tasksCompleted ?? 0}</div>
131
+ <div class="pf-agd-stat-label">${t('profile.agents.activity.tasksCompleted')}</div>
132
+ </div>
133
+ <div class="pf-agd-stat-card">
134
+ <div class="pf-agd-stat-value">${stats.tokensUsed30d ?? 0}</div>
135
+ <div class="pf-agd-stat-label">${t('profile.agents.activity.tokensUsed')}</div>
136
+ </div>
137
+ <div class="pf-agd-stat-card">
138
+ <div class="pf-agd-stat-value">${stats.successRate != null ? `${Math.round(stats.successRate)}%` : '-'}</div>
139
+ <div class="pf-agd-stat-label">${t('profile.agents.activity.successRate')}</div>
140
+ </div>
141
+ </div>
142
+ `}
143
+
144
+ <!-- Governance summary -->
145
+ ${governance && html`
146
+ <div class="pf-agd-governance-section">
147
+ <div class="pf-agd-section-title">${t('profile.agents.detail.activity.governance.title')}</div>
148
+ <div class="pf-agd-governance-grid">
149
+ ${governance.budget ? html`
150
+ <div class="pf-agd-governance-item">
151
+ <span class="pf-agd-governance-label">${t('profile.agents.detail.activity.governance.tokenBudget')}</span>
152
+ <span class="pf-agd-governance-value">${(governance.tokensUsedToday || 0).toLocaleString()} / ${(governance.budget.max_tokens_per_day || '---').toLocaleString()}${governance.budget.max_tokens_per_day ? ` (${Math.round((governance.tokensUsedToday || 0) / governance.budget.max_tokens_per_day * 100)}%)` : ''}</span>
153
+ </div>
154
+ ` : ''}
155
+ <div class="pf-agd-governance-item">
156
+ <span class="pf-agd-governance-label">${t('profile.agents.detail.activity.governance.tasksToday')}</span>
157
+ <span class="pf-agd-governance-value">${t('profile.agents.detail.activity.governance.completed')}: ${governance.tasksCompleted}, ${t('profile.agents.detail.activity.governance.activeTasks')}: ${governance.tasksActive}, ${t('profile.agents.detail.activity.governance.failed')}: ${governance.tasksFailed}</span>
158
+ </div>
159
+ <div class="pf-agd-governance-item">
160
+ <span class="pf-agd-governance-label">${t('profile.agents.detail.activity.governance.policyIssues')}</span>
161
+ <span class="pf-agd-governance-value ${governance.policyIssues > 0 ? 'pf-agd-warning-text' : ''}">${governance.policyIssues}</span>
162
+ </div>
163
+ <div class="pf-agd-governance-item">
164
+ <span class="pf-agd-governance-label">${t('profile.agents.detail.activity.governance.telemetryEvents')}</span>
165
+ <span class="pf-agd-governance-value">${governance.telemetryCount}</span>
166
+ </div>
167
+ </div>
168
+ <div class="pf-agd-governance-delivery">
169
+ <span class="pf-agd-governance-label">${t('profile.agents.detail.activity.governance.deliveryHealth')}</span>
170
+ <span class="pf-agd-governance-value">
171
+ ${governance.mcpActive
172
+ ? html`<span class="pf-agd-status-dot pf-agd-status-dot--active"></span> ${t('profile.agents.detail.activity.governance.mcpLabel')}: ${t('profile.agents.detail.activity.governance.connected')}`
173
+ : html`<span class="pf-agd-status-dot pf-agd-status-dot--inactive"></span> ${t('profile.agents.detail.activity.governance.mcpLabel')}: ${t('profile.agents.detail.activity.governance.notConfigured')}`
174
+ }
175
+ ${' | '}
176
+ ${governance.webhookEnabled
177
+ ? `${t('profile.agents.webhook.title')}: ${governance.webhookSuccessCount}/${governance.webhookTotalCount}`
178
+ : t('profile.agents.detail.integration.webhookNotConfigured')
179
+ }
180
+ </span>
181
+ </div>
182
+ </div>
183
+ `}
184
+
185
+ <!-- Filter bar -->
186
+ <div class="pf-agd-filter-bar">
187
+ ${FILTERS.map(f => {
188
+ const label = t(f.key);
189
+ return html`
190
+ <button key=${f.id}
191
+ class="pf-agd-filter-pill ${filter === f.id ? 'pf-agd-filter-pill--active' : ''}"
192
+ onClick=${() => setFilter(f.id)}>
193
+ ${label !== f.key ? label : f.id.charAt(0).toUpperCase() + f.id.slice(1)}
194
+ </button>
195
+ `;
196
+ })}
197
+ </div>
198
+
199
+ <!-- Event log -->
200
+ <div class="pf-agd-event-log-scroll">
201
+ ${filtered.length === 0 && html`
202
+ <div class="pf-agd-empty">${t('profile.agents.detail.empty.activity')}</div>
203
+ `}
204
+ ${filtered.map((ev, i) => {
205
+ const cat = eventCategory(ev);
206
+ const evType = (ev.type || '').toLowerCase();
207
+ const badgeClass = (evType.includes('policy') || evType.includes('violation'))
208
+ ? 'pf-agd-event-badge--violation'
209
+ : `pf-agd-event-badge--${cat}`;
210
+ return html`
211
+ <div key=${ev.id || i} class="pf-agd-log-entry pf-agd-log-entry--two-line">
212
+ <div class="pf-agd-log-entry-primary">
213
+ <span class="pf-agd-log-time">${ev.timestamp ? new Date(ev.timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }) : '-'}</span>
214
+ <span class="pf-agd-event-badge ${badgeClass}">${t(FILTERS.find(f => f.id === cat)?.key || '') || cat}</span>
215
+ <span class="pf-agd-log-type">${ev.type || ev.event || '-'}</span>
216
+ </div>
217
+ ${ev.message && html`<div class="pf-agd-log-entry-detail">${ev.message}</div>`}
218
+ </div>
219
+ `;
220
+ })}
221
+ </div>
222
+
223
+ ${hasMore && html`
224
+ <button class="btn-ghost btn-sm" onClick=${handleLoadMore}>
225
+ ${t('profile.agents.detail.showAll')}
226
+ </button>
227
+ `}
228
+
229
+ <div class="pf-agd-help-text">${t('profile.agents.detail.activity.auditTrail')}</div>
230
+ </div>
231
+ `;
232
+ }
@@ -0,0 +1,199 @@
1
+ /**
2
+ * @file tab-agent-config.js
3
+ * @description Agent Config tab -- platform-specific config files with preview
4
+ * and two-way sync. Shows files pushed by the agent (soul.md, AGENTS.md, etc).
5
+ * Supports edit, copy, download, and upload actions.
6
+ * @version-history
7
+ * v1.0.0 -- 2026-05-24 -- Initial creation for Agent Detail Tab-View
8
+ * v1.1.0 -- 2026-05-24 -- Add edit/copy/download buttons (F8), edit mode (F9), upload (F10), file metadata (F11)
9
+ */
10
+
11
+ import { h } from 'preact';
12
+ import { useState, useEffect, useRef } from 'preact/hooks';
13
+ import htm from 'htm';
14
+ import { t } from '/js/i18n.js';
15
+ import { apiGet, apiPut } from '/js/api.js';
16
+
17
+ const html = htm.bind(h);
18
+
19
+ export default function TabAgentConfig({ agent, agentName, session, showToast }) {
20
+ const [files, setFiles] = useState([]);
21
+ const [selectedFile, setSelectedFile] = useState(null);
22
+ const [preview, setPreview] = useState('');
23
+ const [loading, setLoading] = useState(true);
24
+ const [editing, setEditing] = useState(false);
25
+ const [editContent, setEditContent] = useState('');
26
+ const fileInputRef = useRef(null);
27
+
28
+ async function loadFiles() {
29
+ setLoading(true);
30
+ try {
31
+ const gaii = agent?.gaii || agentName;
32
+ const resp = await apiGet(`/v1/memory?prefix=agents.config.&agent=${encodeURIComponent(gaii)}`);
33
+ const items = resp?.data?.items || resp?.data?.memories || [];
34
+ const configFiles = items.map(item => ({
35
+ key: item.key,
36
+ filename: item.key.replace(/^agents\.(?:config\.|[^.]+\.config\.)/, ''),
37
+ content: typeof item.value === 'string' ? item.value : JSON.stringify(item.value, null, 2),
38
+ updatedAt: item.updated_at || item.updatedAt,
39
+ description: item.description,
40
+ platform: item.platform,
41
+ active: item.active,
42
+ }));
43
+ setFiles(configFiles);
44
+ if (configFiles.length > 0 && !selectedFile) {
45
+ setSelectedFile(configFiles[0].key);
46
+ setPreview(configFiles[0].content);
47
+ }
48
+ } catch {
49
+ setFiles([]);
50
+ }
51
+ setLoading(false);
52
+ }
53
+
54
+ useEffect(() => { loadFiles(); }, [agentName]);
55
+
56
+ const loadRef = useRef(loadFiles);
57
+ loadRef.current = loadFiles;
58
+ useEffect(() => {
59
+ const handler = () => loadRef.current();
60
+ window.addEventListener('aimeat-live-update', handler);
61
+ return () => window.removeEventListener('aimeat-live-update', handler);
62
+ }, []);
63
+
64
+ function selectFile(file) {
65
+ setSelectedFile(file.key);
66
+ setPreview(file.content);
67
+ setEditing(false);
68
+ }
69
+
70
+ function handleEdit() {
71
+ setEditContent(preview);
72
+ setEditing(true);
73
+ }
74
+
75
+ function handleCancelEdit() {
76
+ setEditing(false);
77
+ }
78
+
79
+ async function handleSave() {
80
+ try {
81
+ await apiPut(`/v1/memory/${encodeURIComponent(selectedFile)}`, { value: editContent });
82
+ setPreview(editContent);
83
+ setEditing(false);
84
+ const updated = files.map(f => f.key === selectedFile ? { ...f, content: editContent } : f);
85
+ setFiles(updated);
86
+ showToast(t('profile.agents.detail.agent_config.saved'));
87
+ } catch (err) {
88
+ showToast(err.message || t('profile.agents.detail.agent_config.saveError'), true);
89
+ }
90
+ }
91
+
92
+ function handleCopy() {
93
+ navigator.clipboard.writeText(preview).then(() => {
94
+ showToast(t('profile.agents.detail.agent_config.copy'));
95
+ });
96
+ }
97
+
98
+ function handleDownload() {
99
+ const file = files.find(f => f.key === selectedFile);
100
+ if (!file) return;
101
+ const blob = new Blob([file.content], { type: 'text/plain' });
102
+ const url = URL.createObjectURL(blob);
103
+ const a = document.createElement('a');
104
+ a.href = url;
105
+ a.download = file.filename;
106
+ a.click();
107
+ URL.revokeObjectURL(url);
108
+ }
109
+
110
+ function handleUploadClick() {
111
+ fileInputRef.current?.click();
112
+ }
113
+
114
+ async function handleFileUpload(e) {
115
+ const file = e.target.files?.[0];
116
+ if (!file) return;
117
+ const reader = new FileReader();
118
+ reader.onload = async () => {
119
+ const content = reader.result;
120
+ const key = `agents.${agentName}.config.${file.name}`;
121
+ try {
122
+ await apiPut(`/v1/memory/${encodeURIComponent(key)}`, { value: content });
123
+ showToast(t('profile.agents.detail.agent_config.uploaded'));
124
+ await loadFiles();
125
+ setSelectedFile(key);
126
+ setPreview(content);
127
+ } catch (err) {
128
+ showToast(err.message || t('profile.agents.detail.agent_config.uploadError'), true);
129
+ }
130
+ };
131
+ reader.readAsText(file);
132
+ e.target.value = '';
133
+ }
134
+
135
+ if (loading) {
136
+ return html`<div class="pf-agd-empty">${t('profile.loading')}</div>`;
137
+ }
138
+
139
+ if (files.length === 0) {
140
+ return html`
141
+ <div>
142
+ <div class="pf-agd-config-upload">
143
+ <button class="btn-outline btn-sm" onClick=${handleUploadClick}>+ ${t('profile.agents.detail.agent_config.upload')}</button>
144
+ <input ref=${fileInputRef} type="file" accept=".md,.yaml,.yml,.json" class="pf-agd-hidden-input" onChange=${handleFileUpload} />
145
+ </div>
146
+ <div class="pf-agd-empty">${t('profile.agents.detail.empty.agent_config')}</div>
147
+ </div>
148
+ `;
149
+ }
150
+
151
+ return html`
152
+ <div>
153
+ <div class="pf-agd-config-upload">
154
+ <button class="btn-outline btn-sm" onClick=${handleUploadClick}>+ ${t('profile.agents.detail.agent_config.upload')}</button>
155
+ <input ref=${fileInputRef} type="file" accept=".md,.yaml,.yml,.json" class="pf-agd-hidden-input" onChange=${handleFileUpload} />
156
+ </div>
157
+
158
+ <div class="pf-agd-config-list">
159
+ ${files.map(file => html`
160
+ <div key=${file.key}
161
+ class="pf-agd-config-item ${selectedFile === file.key ? 'pf-agd-config-item--active' : ''}"
162
+ onClick=${() => selectFile(file)}>
163
+ ${file.active !== false && html`<span class="pf-agd-status-dot pf-agd-status-dot--active"></span>`}
164
+ <span class="pf-agd-config-name">${file.filename}</span>
165
+ ${file.description && html`<span class="pf-agd-config-desc">${file.description}</span>`}
166
+ ${!file.description && html`<span class="pf-agd-config-desc">${file.updatedAt ? `${t('profile.agents.tasks.updated')}: ${new Date(file.updatedAt).toLocaleDateString()}` : ''}</span>`}
167
+ ${file.platform && html`<span class="pf-agd-config-platform">${file.platform}</span>`}
168
+ </div>
169
+ `)}
170
+ </div>
171
+
172
+ ${selectedFile && html`
173
+ <div>
174
+ <div class="pf-agd-config-preview-header">
175
+ <span>${t('profile.agents.detail.agent_config.viewing')}: ${files.find(f => f.key === selectedFile)?.filename || ''}</span>
176
+ <div class="pf-agd-config-actions">
177
+ ${!editing && html`
178
+ <button class="btn-outline btn-sm" onClick=${handleEdit}>${t('profile.agents.detail.agent_config.edit')}</button>
179
+ <button class="btn-outline btn-sm" onClick=${handleCopy}>${t('profile.agents.detail.agent_config.copy')}</button>
180
+ <button class="btn-outline btn-sm" onClick=${handleDownload}>${t('profile.agents.detail.agent_config.download')}</button>
181
+ `}
182
+ </div>
183
+ </div>
184
+ ${editing ? html`
185
+ <div class="pf-agd-config-edit">
186
+ <textarea class="pf-agd-config-textarea" value=${editContent} onInput=${(e) => setEditContent(e.target.value)}></textarea>
187
+ <div class="pf-agd-form-actions">
188
+ <button class="btn-primary btn-sm" onClick=${handleSave}>${t('profile.agents.detail.agent_config.save')}</button>
189
+ <button class="btn-outline btn-sm" onClick=${handleCancelEdit}>${t('profile.agents.detail.agent_config.cancel')}</button>
190
+ </div>
191
+ </div>
192
+ ` : html`
193
+ <div class="pf-agd-config-preview">${preview}</div>
194
+ `}
195
+ </div>
196
+ `}
197
+ </div>
198
+ `;
199
+ }