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,243 @@
1
+ /**
2
+ * @file agent-webhook.ts
3
+ * @description REST endpoints for agent webhook CRUD (register, get, delete, test, delivery log).
4
+ * Owners can manage webhooks for any of their agents; agents can manage their own.
5
+ * @structure
6
+ * - PUT /v1/agents/:name/webhook -- Register or update webhook
7
+ * - GET /v1/agents/:name/webhook -- Get webhook config and status
8
+ * - DELETE /v1/agents/:name/webhook -- Remove webhook
9
+ * - POST /v1/agents/:name/webhook/test -- Send a test event to the webhook
10
+ * - GET /v1/agents/:name/webhook/log -- Get delivery log
11
+ * @version-history
12
+ * v1.0.0 -- 2026-05-23 -- Initial creation for Agent Dashboard webhook management
13
+ */
14
+ import { Router } from 'express';
15
+ import { randomBytes, randomUUID, createHmac } from 'node:crypto';
16
+ import { z } from 'zod';
17
+ import { success, error } from '../middleware/envelope.js';
18
+ import { requireAuth } from '../auth/middleware.js';
19
+ import { buildGAII } from '../utils/gaii.js';
20
+ import { validateOutboundUrl } from '../utils/url-validator.js';
21
+ import { emitChange } from '../services/event-bus.js';
22
+ /* ── Zod validation schema ── */
23
+ const WebhookPutSchema = z.object({
24
+ url: z.string().url().max(2048),
25
+ secret: z.string().min(16).max(256).optional(),
26
+ });
27
+ export function agentWebhookRouter(config, storage) {
28
+ const router = Router();
29
+ /** Build GAII for the named agent under the authenticated owner */
30
+ function resolveAgentGaii(req, agentName) {
31
+ const owner = req.auth.owner;
32
+ return buildGAII(agentName, owner, config.nodeId);
33
+ }
34
+ /** Check if current session can access an agent's webhook */
35
+ function canAccessAgent(req, agentName) {
36
+ const roles = req.auth.roles;
37
+ const isOwnerSession = roles.includes('owner') && !roles.includes('agent');
38
+ if (isOwnerSession)
39
+ return true;
40
+ if (roles.includes('agent')) {
41
+ return req.auth.sub === resolveAgentGaii(req, agentName);
42
+ }
43
+ return false;
44
+ }
45
+ /* ── PUT /v1/agents/:name/webhook -- Register or update webhook ── */
46
+ router.put('/v1/agents/:name/webhook', requireAuth(), async (req, res) => {
47
+ const agentName = req.params.name;
48
+ if (!canAccessAgent(req, agentName)) {
49
+ res.status(403).json(error(config.nodeId, 'FORBIDDEN', 'Access denied'));
50
+ return;
51
+ }
52
+ const agentGaii = resolveAgentGaii(req, agentName);
53
+ // Verify agent exists
54
+ const agent = await storage.getAgent(agentGaii);
55
+ if (!agent) {
56
+ res.status(404).json(error(config.nodeId, 'NOT_FOUND', `Agent '${agentName}' not found`));
57
+ return;
58
+ }
59
+ // Validate body
60
+ const parsed = WebhookPutSchema.safeParse(req.body);
61
+ if (!parsed.success) {
62
+ res.status(400).json(error(config.nodeId, 'INVALID_INPUT', parsed.error.issues.map(i => `${i.path.join('.')}: ${i.message}`).join('; ')));
63
+ return;
64
+ }
65
+ const { url, secret } = parsed.data;
66
+ // SSRF check
67
+ const urlCheck = await validateOutboundUrl(url);
68
+ if (!urlCheck.valid) {
69
+ res.status(400).json(error(config.nodeId, 'INVALID_URL', urlCheck.reason ?? 'URL is not allowed'));
70
+ return;
71
+ }
72
+ // Generate a random secret if not provided
73
+ const webhookSecret = secret ?? randomBytes(32).toString('hex');
74
+ await storage.updateAgent(agentGaii, {
75
+ webhookUrl: url,
76
+ webhookSecret,
77
+ webhookEnabled: true,
78
+ webhookFailCount: 0,
79
+ });
80
+ emitChange('agents');
81
+ res.json(success(config.nodeId, {
82
+ url,
83
+ secret: webhookSecret,
84
+ enabled: true,
85
+ }));
86
+ });
87
+ /* ── GET /v1/agents/:name/webhook -- Get webhook config and status ── */
88
+ router.get('/v1/agents/:name/webhook', requireAuth(), async (req, res) => {
89
+ const agentName = req.params.name;
90
+ if (!canAccessAgent(req, agentName)) {
91
+ res.status(403).json(error(config.nodeId, 'FORBIDDEN', 'Access denied'));
92
+ return;
93
+ }
94
+ const agentGaii = resolveAgentGaii(req, agentName);
95
+ const agent = await storage.getAgent(agentGaii);
96
+ if (!agent) {
97
+ res.status(404).json(error(config.nodeId, 'NOT_FOUND', `Agent '${agentName}' not found`));
98
+ return;
99
+ }
100
+ if (!agent.webhookUrl) {
101
+ res.json(success(config.nodeId, {
102
+ configured: false,
103
+ }));
104
+ return;
105
+ }
106
+ res.json(success(config.nodeId, {
107
+ configured: true,
108
+ url: agent.webhookUrl,
109
+ enabled: agent.webhookEnabled ?? false,
110
+ last_success: agent.webhookLastSuccess ?? null,
111
+ last_failure: agent.webhookLastFailure ?? null,
112
+ fail_count: agent.webhookFailCount ?? 0,
113
+ }));
114
+ });
115
+ /* ── DELETE /v1/agents/:name/webhook -- Remove webhook ── */
116
+ router.delete('/v1/agents/:name/webhook', requireAuth(), async (req, res) => {
117
+ const agentName = req.params.name;
118
+ if (!canAccessAgent(req, agentName)) {
119
+ res.status(403).json(error(config.nodeId, 'FORBIDDEN', 'Access denied'));
120
+ return;
121
+ }
122
+ const agentGaii = resolveAgentGaii(req, agentName);
123
+ const agent = await storage.getAgent(agentGaii);
124
+ if (!agent) {
125
+ res.status(404).json(error(config.nodeId, 'NOT_FOUND', `Agent '${agentName}' not found`));
126
+ return;
127
+ }
128
+ // Use null (cast through any) to clear nullable fields in MongoDB/Prisma.
129
+ // Prisma treats undefined as "don't update" but null as "set to null".
130
+ await storage.updateAgent(agentGaii, {
131
+ webhookUrl: null,
132
+ webhookSecret: null,
133
+ webhookEnabled: false,
134
+ webhookFailCount: 0,
135
+ webhookLastSuccess: null,
136
+ webhookLastFailure: null,
137
+ });
138
+ emitChange('agents');
139
+ res.json(success(config.nodeId, { removed: true }));
140
+ });
141
+ /* ── POST /v1/agents/:name/webhook/test -- Send test event ── */
142
+ router.post('/v1/agents/:name/webhook/test', requireAuth(), async (req, res) => {
143
+ const agentName = req.params.name;
144
+ if (!canAccessAgent(req, agentName)) {
145
+ res.status(403).json(error(config.nodeId, 'FORBIDDEN', 'Access denied'));
146
+ return;
147
+ }
148
+ const agentGaii = resolveAgentGaii(req, agentName);
149
+ const agent = await storage.getAgent(agentGaii);
150
+ if (!agent) {
151
+ res.status(404).json(error(config.nodeId, 'NOT_FOUND', `Agent '${agentName}' not found`));
152
+ return;
153
+ }
154
+ if (!agent.webhookUrl || !agent.webhookSecret) {
155
+ res.status(400).json(error(config.nodeId, 'NO_WEBHOOK', 'No webhook configured for this agent'));
156
+ return;
157
+ }
158
+ // Build test payload
159
+ const payload = {
160
+ event: 'webhook.test',
161
+ agent: agentGaii,
162
+ node: config.nodeId,
163
+ timestamp: new Date().toISOString(),
164
+ data: { message: 'Webhook test delivery' },
165
+ };
166
+ const body = JSON.stringify(payload);
167
+ const signature = createHmac('sha256', agent.webhookSecret).update(body).digest('hex');
168
+ const startMs = Date.now();
169
+ let httpStatus;
170
+ let deliveryError;
171
+ try {
172
+ const resp = await fetch(agent.webhookUrl, {
173
+ method: 'POST',
174
+ headers: {
175
+ 'Content-Type': 'application/json',
176
+ 'X-AIMEAT-Signature': `sha256=${signature}`,
177
+ 'X-AIMEAT-Event': 'webhook.test',
178
+ },
179
+ body,
180
+ signal: AbortSignal.timeout(10_000),
181
+ });
182
+ httpStatus = resp.status;
183
+ if (!resp.ok) {
184
+ deliveryError = `HTTP ${resp.status}`;
185
+ }
186
+ }
187
+ catch (err) {
188
+ deliveryError = err instanceof Error ? err.message : 'Delivery failed';
189
+ }
190
+ const latencyMs = Date.now() - startMs;
191
+ const deliveryStatus = deliveryError ? 'failed' : 'success';
192
+ // Log the delivery
193
+ await storage.appendDeliveryLog({
194
+ id: randomUUID(),
195
+ agentGaii,
196
+ event: 'webhook.test',
197
+ payload,
198
+ status: deliveryStatus,
199
+ httpStatus,
200
+ errorMessage: deliveryError,
201
+ attemptCount: 1,
202
+ latencyMs,
203
+ createdAt: new Date().toISOString(),
204
+ });
205
+ // Update last success/failure on the agent
206
+ const now = new Date().toISOString();
207
+ if (deliveryStatus === 'success') {
208
+ await storage.updateAgent(agentGaii, { webhookLastSuccess: now });
209
+ }
210
+ else {
211
+ await storage.updateAgent(agentGaii, {
212
+ webhookLastFailure: now,
213
+ webhookFailCount: (agent.webhookFailCount ?? 0) + 1,
214
+ });
215
+ }
216
+ res.json(success(config.nodeId, {
217
+ delivered: deliveryStatus === 'success',
218
+ status: deliveryStatus,
219
+ http_status: httpStatus ?? null,
220
+ error: deliveryError ?? null,
221
+ latency_ms: latencyMs,
222
+ }));
223
+ });
224
+ /* ── GET /v1/agents/:name/webhook/log -- Delivery log ── */
225
+ router.get('/v1/agents/:name/webhook/log', requireAuth(), async (req, res) => {
226
+ const agentName = req.params.name;
227
+ if (!canAccessAgent(req, agentName)) {
228
+ res.status(403).json(error(config.nodeId, 'FORBIDDEN', 'Access denied'));
229
+ return;
230
+ }
231
+ const agentGaii = resolveAgentGaii(req, agentName);
232
+ const agent = await storage.getAgent(agentGaii);
233
+ if (!agent) {
234
+ res.status(404).json(error(config.nodeId, 'NOT_FOUND', `Agent '${agentName}' not found`));
235
+ return;
236
+ }
237
+ const limit = Math.min(Math.max(parseInt(req.query.limit) || 50, 1), 200);
238
+ const deliveries = await storage.listDeliveryLog(agentGaii, limit);
239
+ res.json(success(config.nodeId, { deliveries }));
240
+ });
241
+ return router;
242
+ }
243
+ //# sourceMappingURL=agent-webhook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-webhook.js","sourceRoot":"","sources":["../../../src/routes/agent-webhook.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../../src/routes/agents.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAOjC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAgBvD,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,CAkjC3E"}
1
+ {"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../../src/routes/agents.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAOjC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAkBvD,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,CA6wC3E"}
@@ -15,6 +15,8 @@ import { AgentRegistrationSchema, validateBody } from '../models/schemas.js';
15
15
  import { verifyJWT, issueJWT, generateSessionId } from '../auth/jwt.js';
16
16
  import { rateLimit } from '../middleware/rate-limit.js';
17
17
  import { emitChange } from '../services/event-bus.js';
18
+ import { createDefaultSteps } from '../models/agent-onboarding-schemas.js';
19
+ import { detectPlatform } from '../services/platform-detector.js';
18
20
  /** Device authorization code expires after 30 minutes */
19
21
  const DEVICE_AUTH_EXPIRY_MS = 1_800_000;
20
22
  export function agentsRouter(config, storage) {
@@ -78,8 +80,9 @@ export function agentsRouter(config, storage) {
78
80
  verification_uri_complete: verificationUriComplete,
79
81
  expires_in: 1800,
80
82
  interval: 5,
83
+ user_instructions: `Tell your owner to approve this request. They can find it in their AIMEAT profile under Agents (${baseUrl}/v1/profile -> Agents tab). The verification code is: ${userCode}. Once approved, poll POST /v1/agents/device-token with { "device_code": "${deviceCode}", "grant_type": "urn:ietf:params:oauth:grant-type:device_code" } every 5 seconds until you receive your token.`,
81
84
  }, [
82
- { description: 'Open this URL in a browser', method: 'GET', url: `/v1/agents/verify?code=${userCode}` },
85
+ { description: 'Owner approves in AIMEAT profile -> Agents tab', method: 'GET', url: `${baseUrl}/v1/profile` },
83
86
  { description: 'Poll for authorization result', method: 'POST', url: '/v1/agents/device-token' },
84
87
  ]));
85
88
  emitChange('agents');
@@ -141,17 +144,41 @@ export function agentsRouter(config, storage) {
141
144
  // Return credentials and immediately clear them
142
145
  const creds = request.agentCredentials;
143
146
  await storage.updateDeviceAuth(device_code, { agentCredentials: null });
147
+ const baseUrl = config.baseUrl;
148
+ const agentName = request.agentName;
144
149
  res.json({
150
+ access_token: creds.token,
151
+ token: creds.token,
152
+ token_type: 'Bearer',
145
153
  gaii: creds.gaii,
146
- name: request.agentName,
154
+ name: agentName,
147
155
  owner: request.ownerName,
148
- token: creds.token,
149
156
  expires_at: creds.expires_at,
150
157
  privateKey: creds.privateKey,
151
158
  publicKey: creds.publicKey,
152
159
  scopes: request.scopes,
153
160
  morselBalance: 0,
154
- note: 'Use the token directly: Authorization: Bearer <token>. The privateKey is provided for advanced use (Ed25519 signing) but is not required.',
161
+ next_steps: {
162
+ message: 'Authentication successful. Your MANDATORY first action: download and read your skill bundle.',
163
+ step_1_skill_bundle: {
164
+ action: 'Download your skill bundle ZIP, extract it, and read SKILL.md. It contains your personalized operating instructions, directives, rules, and complete API reference.',
165
+ method: 'GET',
166
+ url: `${baseUrl}/v1/agents/${agentName}/skill-bundle`,
167
+ auth: 'Authorization: Bearer <your token from above>',
168
+ },
169
+ step_2_system_prompt: {
170
+ action: 'Read your system prompt for additional operating context.',
171
+ method: 'GET',
172
+ url: `${baseUrl}/v1/prompts/tier1`,
173
+ auth: 'Authorization: Bearer <your token from above>',
174
+ },
175
+ step_3_hello_integration: {
176
+ action: 'Check your onboarding status and complete the Hello Integration steps. A test task is already created for you. GET this endpoint auto-validates steps and auto-starts the test task after you propose todos -- always re-check here instead of trying POST /start.',
177
+ method: 'GET',
178
+ url: `${baseUrl}/v1/agents/${agentName}/onboarding`,
179
+ auth: 'Authorization: Bearer <your token from above>',
180
+ },
181
+ },
155
182
  });
156
183
  return;
157
184
  }
@@ -310,6 +337,150 @@ export function agentsRouter(config, storage) {
310
337
  existing_agent: !!existing,
311
338
  }));
312
339
  emitChange('agents');
340
+ // ── Auto-start Hello Integration onboarding ──
341
+ const onboardingSteps = createDefaultSteps();
342
+ onboardingSteps[0].status = 'passed';
343
+ onboardingSteps[0].validatedAt = now;
344
+ onboardingSteps[0].validationMethod = 'automatic';
345
+ onboardingSteps[0].details = { createdAt: existing?.createdAt ?? now };
346
+ const detectedPlatform = detectPlatform(req.headers['user-agent']);
347
+ if (detectedPlatform) {
348
+ onboardingSteps[1].status = 'passed';
349
+ onboardingSteps[1].validatedAt = now;
350
+ onboardingSteps[1].validationMethod = 'automatic';
351
+ onboardingSteps[1].details = { platform: detectedPlatform.id, version: detectedPlatform.version };
352
+ await storage.updateAgent(gaii, {
353
+ platform: detectedPlatform.id,
354
+ platformVersion: detectedPlatform.version,
355
+ platformDetectedBy: detectedPlatform.detectedBy,
356
+ });
357
+ }
358
+ const existingOnboarding = await storage.getOnboarding(gaii);
359
+ if (!existingOnboarding) {
360
+ const testTaskId = randomUUID();
361
+ await storage.createAgentTask({
362
+ id: testTaskId,
363
+ agentGaii: gaii,
364
+ ownerGaii: `${ownerPayload.owner}@${config.nodeId}`,
365
+ title: 'Onboarding verification',
366
+ description: 'This is a test task created during Hello Integration. Propose todos, get approval, execute, and complete.',
367
+ status: 'queued',
368
+ scope: [],
369
+ rules: [],
370
+ todos: [],
371
+ verification: { userExpects: 'Agent completes the onboarding test task successfully', technicalChecks: [] },
372
+ createdAt: now,
373
+ updatedAt: now,
374
+ });
375
+ onboardingSteps[8].details = { testTaskId };
376
+ await storage.createOnboarding({
377
+ agentGaii: gaii,
378
+ status: 'in_progress',
379
+ startedAt: now,
380
+ steps: onboardingSteps,
381
+ detectedPlatform: detectedPlatform?.id,
382
+ });
383
+ emitChange('agent-onboarding');
384
+ }
385
+ });
386
+ // POST /v1/agents/connect — register an agent via connectivity key (no auth required)
387
+ router.post('/v1/agents/connect', async (req, res) => {
388
+ const { connectivity_key, agent_name, display_name } = req.body ?? {};
389
+ if (!connectivity_key) {
390
+ res.status(400).json(error(config.nodeId, 'INVALID_INPUT', 'connectivity_key is required'));
391
+ return;
392
+ }
393
+ const otk = await storage.consumeOtk(connectivity_key, config.otkGraceMs);
394
+ if (!otk || otk.action !== 'register_agent') {
395
+ res.status(404).json(error(config.nodeId, 'INVALID_KEY', 'Connectivity key not found, already used, or invalid'));
396
+ return;
397
+ }
398
+ const owner = otk.params.owner;
399
+ const finalName = agent_name ?? otk.params.agent_name;
400
+ if (!finalName) {
401
+ res.status(400).json(error(config.nodeId, 'INVALID_INPUT', 'agent_name is required (either in the connectivity key or in the request body)'));
402
+ return;
403
+ }
404
+ const nameError = validateAgentName(finalName);
405
+ if (nameError) {
406
+ res.status(400).json(error(config.nodeId, 'INVALID_INPUT', nameError));
407
+ return;
408
+ }
409
+ const ownerRecord = await storage.getOwner(owner);
410
+ if (!ownerRecord) {
411
+ res.status(404).json(error(config.nodeId, 'NOT_FOUND', `Owner "${owner}" not found`));
412
+ return;
413
+ }
414
+ const gaii = buildGAII(finalName, owner, config.nodeId);
415
+ const existing = await storage.getAgent(gaii);
416
+ if (existing) {
417
+ res.status(409).json(error(config.nodeId, 'NAME_TAKEN', `Agent "${finalName}" already exists under owner "${owner}"`));
418
+ return;
419
+ }
420
+ const keyPair = await generateKeyPair();
421
+ const now = new Date().toISOString();
422
+ const description = otk.params.description ?? undefined;
423
+ const requestedScopes = config.defaultAgentScopes;
424
+ await storage.createAgent({
425
+ name: finalName,
426
+ owner,
427
+ gaii,
428
+ displayName: display_name ?? finalName,
429
+ description,
430
+ capabilities: [],
431
+ defaultScopes: requestedScopes,
432
+ publicKey: keyPair.publicKey,
433
+ trustScore: 50,
434
+ morselBalance: 0,
435
+ createdAt: now,
436
+ lastSeen: now,
437
+ });
438
+ fireHook(config, storage, 'post_agent_registration', { gaii, owner });
439
+ // Auto-start Hello Integration onboarding
440
+ const connectSteps = createDefaultSteps();
441
+ connectSteps[0].status = 'passed';
442
+ connectSteps[0].validatedAt = now;
443
+ connectSteps[0].validationMethod = 'automatic';
444
+ connectSteps[0].details = { createdAt: now };
445
+ const connectDetected = detectPlatform(req.headers['user-agent']);
446
+ if (connectDetected) {
447
+ connectSteps[1].status = 'passed';
448
+ connectSteps[1].validatedAt = now;
449
+ connectSteps[1].validationMethod = 'automatic';
450
+ connectSteps[1].details = { platform: connectDetected.id, version: connectDetected.version };
451
+ await storage.updateAgent(gaii, {
452
+ platform: connectDetected.id,
453
+ platformVersion: connectDetected.version,
454
+ platformDetectedBy: connectDetected.detectedBy,
455
+ });
456
+ }
457
+ await storage.createOnboarding({
458
+ agentGaii: gaii,
459
+ status: 'in_progress',
460
+ startedAt: now,
461
+ steps: connectSteps,
462
+ detectedPlatform: connectDetected?.id,
463
+ });
464
+ emitChange('agent-onboarding');
465
+ res.set('Cache-Control', 'no-store');
466
+ res.set('Pragma', 'no-cache');
467
+ res.status(201).json(success(config.nodeId, {
468
+ agent: {
469
+ gaii,
470
+ display_name: display_name ?? finalName,
471
+ description,
472
+ scopes: requestedScopes,
473
+ },
474
+ private_key: keyPair.privateKey,
475
+ public_key: keyPair.publicKey,
476
+ }, [
477
+ {
478
+ description: 'Authenticate as this agent to get a JWT',
479
+ method: 'POST',
480
+ url: '/v1/auth/token',
481
+ },
482
+ ]));
483
+ emitChange('agents');
313
484
  });
314
485
  // POST /v1/agents — register a new agent (requires owner JWT, local session only)
315
486
  router.post('/v1/agents', requireAuth(), requireLocalSession(), requireRole('owner'), validateBody(AgentRegistrationSchema, config.nodeId), async (req, res) => {
@@ -416,6 +587,32 @@ export function agentsRouter(config, storage) {
416
587
  },
417
588
  ]));
418
589
  emitChange('agents');
590
+ // ── Auto-start Hello Integration onboarding (direct registration path) ──
591
+ const regOnboardingSteps = createDefaultSteps();
592
+ regOnboardingSteps[0].status = 'passed';
593
+ regOnboardingSteps[0].validatedAt = now;
594
+ regOnboardingSteps[0].validationMethod = 'automatic';
595
+ regOnboardingSteps[0].details = { createdAt: now };
596
+ const regDetected = detectPlatform(req.headers['user-agent']);
597
+ if (regDetected) {
598
+ regOnboardingSteps[1].status = 'passed';
599
+ regOnboardingSteps[1].validatedAt = now;
600
+ regOnboardingSteps[1].validationMethod = 'automatic';
601
+ regOnboardingSteps[1].details = { platform: regDetected.id, version: regDetected.version };
602
+ await storage.updateAgent(gaii, {
603
+ platform: regDetected.id,
604
+ platformVersion: regDetected.version,
605
+ platformDetectedBy: regDetected.detectedBy,
606
+ });
607
+ }
608
+ await storage.createOnboarding({
609
+ agentGaii: gaii,
610
+ status: 'in_progress',
611
+ startedAt: now,
612
+ steps: regOnboardingSteps,
613
+ detectedPlatform: regDetected?.id,
614
+ });
615
+ emitChange('agent-onboarding');
419
616
  });
420
617
  // GET /v1/agents/device-authorize/pending — list pending device auth requests for the logged-in owner
421
618
  router.get('/v1/agents/device-authorize/pending', requireAuth(), requireRole('owner'), async (req, res) => {
@@ -522,6 +719,8 @@ export function agentsRouter(config, storage) {
522
719
  display_name: a.displayName,
523
720
  description: a.description,
524
721
  capabilities: a.capabilities,
722
+ technical_capabilities: a.technicalCapabilities,
723
+ domain_capabilities: a.domainCapabilities,
525
724
  default_scopes: a.defaultScopes ?? ['*'],
526
725
  trust_score: a.trustScore,
527
726
  morsel_balance: a.morselBalance,