hive-am 1.1.0 → 1.2.1

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 (262) hide show
  1. package/CHANGELOG.md +100 -1
  2. package/README.md +9 -1
  3. package/package.json +13 -2
  4. package/server/dist/api.js +42 -762
  5. package/server/dist/connections/channel-skill.js +13 -1
  6. package/server/dist/connections/files.js +45 -1
  7. package/server/dist/connections/manager.js +41 -3
  8. package/server/dist/connections/outbound.js +2 -1
  9. package/server/dist/connections/prompt.js +4 -0
  10. package/server/dist/connections/router.js +3 -2
  11. package/server/dist/connections/store.js +4 -43
  12. package/server/dist/connections/telegram.js +43 -3
  13. package/server/dist/cron.js +2 -1
  14. package/server/dist/db/json.js +16 -0
  15. package/server/dist/db/migrations.js +199 -0
  16. package/server/dist/db.js +98 -196
  17. package/server/dist/errors.js +11 -0
  18. package/server/dist/git/browse.js +99 -0
  19. package/server/dist/git/ops.js +136 -19
  20. package/server/dist/git/repo.js +2 -1
  21. package/server/dist/history/claude.js +21 -21
  22. package/server/dist/history/index.js +17 -9
  23. package/server/dist/history/kiro.js +17 -12
  24. package/server/dist/history/lines.js +12 -0
  25. package/server/dist/history/opencode.js +18 -1
  26. package/server/dist/http/body.js +46 -0
  27. package/server/dist/http/errors.js +21 -0
  28. package/server/dist/http/guards.js +44 -0
  29. package/server/dist/http/router.js +24 -0
  30. package/server/dist/http/routes/agents.js +124 -0
  31. package/server/dist/http/routes/channel.js +16 -0
  32. package/server/dist/http/routes/colonies.js +9 -0
  33. package/server/dist/http/routes/connections.js +36 -0
  34. package/server/dist/http/routes/fs.js +22 -0
  35. package/server/dist/http/routes/git.js +90 -0
  36. package/server/dist/http/routes/meta.js +11 -0
  37. package/server/dist/http/routes/notebook.js +34 -0
  38. package/server/dist/http/routes/orchestration.js +32 -0
  39. package/server/dist/http/routes/resources.js +68 -0
  40. package/server/dist/http/routes/schedules.js +40 -0
  41. package/server/dist/http/routes/skills.js +47 -0
  42. package/server/dist/http/routes/terminals.js +18 -0
  43. package/server/dist/http/routes/types.js +36 -0
  44. package/server/dist/http/validate.js +65 -0
  45. package/server/dist/index.js +67 -5
  46. package/server/dist/instructions.js +8 -2
  47. package/server/dist/objects/agent.js +49 -0
  48. package/server/dist/objects/database.js +451 -0
  49. package/server/dist/objects/db-history.js +79 -0
  50. package/server/dist/objects/docker-info.js +75 -0
  51. package/server/dist/objects/docker.js +285 -0
  52. package/server/dist/objects/driver-props.js +196 -0
  53. package/server/dist/objects/exec.js +16 -0
  54. package/server/dist/objects/http-history.js +44 -0
  55. package/server/dist/objects/http-script.js +644 -0
  56. package/server/dist/objects/http.js +735 -0
  57. package/server/dist/objects/index.js +445 -0
  58. package/server/dist/objects/model.js +250 -0
  59. package/server/dist/objects/runner.js +211 -0
  60. package/server/dist/objects/stats.js +106 -0
  61. package/server/dist/objects/store.js +115 -0
  62. package/server/dist/objects/supervisor.js +111 -0
  63. package/server/dist/objects/templates.js +67 -0
  64. package/server/dist/providers/claude.js +3 -13
  65. package/server/dist/providers/index.js +7 -1
  66. package/server/dist/providers/kiro.js +2 -5
  67. package/server/dist/providers/opencode-server.js +45 -0
  68. package/server/dist/providers/opencode.js +52 -9
  69. package/server/dist/providers/preamble.js +2 -0
  70. package/server/dist/providers/spawn.js +31 -3
  71. package/server/dist/runtime.js +8 -6
  72. package/server/dist/schedules.js +2 -21
  73. package/server/dist/seed.js +15 -11
  74. package/server/dist/services/agents.js +90 -0
  75. package/server/dist/services/colonies.js +38 -0
  76. package/server/dist/services/connections.js +76 -0
  77. package/server/dist/services/notebook.js +22 -0
  78. package/server/dist/services/providers.js +27 -0
  79. package/server/dist/services/schedules.js +18 -0
  80. package/server/dist/sessions-summary.js +51 -0
  81. package/server/dist/skills/defaults.js +37 -0
  82. package/server/dist/skills/notebook.js +3 -8
  83. package/server/dist/terminals.js +185 -0
  84. package/server/dist/wake.js +13 -16
  85. package/server/dist/watch.js +2 -8
  86. package/server/mcp/dispatch.mjs +70 -1
  87. package/web/.next/BUILD_ID +1 -1
  88. package/web/.next/app-build-manifest.json +146 -94
  89. package/web/.next/app-path-routes-manifest.json +6 -4
  90. package/web/.next/build-manifest.json +14 -14
  91. package/web/.next/prerender-manifest.json +67 -43
  92. package/web/.next/react-loadable-manifest.json +26 -1
  93. package/web/.next/required-server-files.json +13 -1
  94. package/web/.next/routes-manifest.json +26 -0
  95. package/web/.next/server/app/_not-found/page.js +2 -2
  96. package/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  97. package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  98. package/web/.next/server/app/_not-found.html +1 -1
  99. package/web/.next/server/app/_not-found.rsc +12 -11
  100. package/web/.next/server/app/agents/[id]/page.js +4 -4
  101. package/web/.next/server/app/agents/[id]/page.js.nft.json +1 -1
  102. package/web/.next/server/app/agents/[id]/page_client-reference-manifest.js +1 -1
  103. package/web/.next/server/app/agents/page.js +2 -2
  104. package/web/.next/server/app/agents/page.js.nft.json +1 -1
  105. package/web/.next/server/app/agents/page_client-reference-manifest.js +1 -1
  106. package/web/.next/server/app/agents.html +1 -1
  107. package/web/.next/server/app/agents.rsc +14 -13
  108. package/web/.next/server/app/connections/page.js +2 -2
  109. package/web/.next/server/app/connections/page.js.nft.json +1 -1
  110. package/web/.next/server/app/connections/page_client-reference-manifest.js +1 -1
  111. package/web/.next/server/app/connections.html +1 -1
  112. package/web/.next/server/app/connections.rsc +14 -13
  113. package/web/.next/server/app/index.html +1 -1
  114. package/web/.next/server/app/index.rsc +14 -13
  115. package/web/.next/server/app/page.js +2 -2
  116. package/web/.next/server/app/page.js.nft.json +1 -1
  117. package/web/.next/server/app/page_client-reference-manifest.js +1 -1
  118. package/web/.next/server/app/relations/page.js +2 -2
  119. package/web/.next/server/app/relations/page.js.nft.json +1 -1
  120. package/web/.next/server/app/relations/page_client-reference-manifest.js +1 -1
  121. package/web/.next/server/app/relations.html +1 -1
  122. package/web/.next/server/app/relations.rsc +14 -13
  123. package/web/.next/server/app/resources/[id]/page.js +2 -0
  124. package/web/.next/server/app/resources/[id]/page.js.nft.json +1 -0
  125. package/web/.next/server/app/resources/[id]/page_client-reference-manifest.js +1 -0
  126. package/web/.next/server/app/resources/page.js +2 -0
  127. package/web/.next/server/app/resources/page.js.nft.json +1 -0
  128. package/web/.next/server/app/resources/page_client-reference-manifest.js +1 -0
  129. package/web/.next/server/app/resources.html +1 -0
  130. package/web/.next/server/app/resources.meta +15 -0
  131. package/web/.next/server/app/resources.rsc +25 -0
  132. package/web/.next/server/app/schedules/page.js +2 -2
  133. package/web/.next/server/app/schedules/page.js.nft.json +1 -1
  134. package/web/.next/server/app/schedules/page_client-reference-manifest.js +1 -1
  135. package/web/.next/server/app/schedules.html +1 -1
  136. package/web/.next/server/app/schedules.rsc +14 -13
  137. package/web/.next/server/app/sessions/page.js +2 -2
  138. package/web/.next/server/app/sessions/page.js.nft.json +1 -1
  139. package/web/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
  140. package/web/.next/server/app/sessions.html +1 -1
  141. package/web/.next/server/app/sessions.rsc +14 -13
  142. package/web/.next/server/app/skills/page.js +2 -2
  143. package/web/.next/server/app/skills/page.js.nft.json +1 -1
  144. package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  145. package/web/.next/server/app/skills.html +1 -1
  146. package/web/.next/server/app/skills.rsc +14 -13
  147. package/web/.next/server/app/types/page.js +2 -2
  148. package/web/.next/server/app/types/page.js.nft.json +1 -1
  149. package/web/.next/server/app/types/page_client-reference-manifest.js +1 -1
  150. package/web/.next/server/app/types.html +1 -1
  151. package/web/.next/server/app/types.rsc +14 -13
  152. package/web/.next/server/app-paths-manifest.json +6 -4
  153. package/web/.next/server/chunks/143.js +1 -1
  154. package/web/.next/server/chunks/274.js +1 -0
  155. package/web/.next/server/chunks/306.js +1 -0
  156. package/web/.next/server/chunks/423.js +1 -0
  157. package/web/.next/server/chunks/505.js +6 -0
  158. package/web/.next/server/chunks/555.js +1 -0
  159. package/web/.next/server/chunks/612.js +1 -0
  160. package/web/.next/server/chunks/638.js +1 -0
  161. package/web/.next/server/chunks/692.js +18 -0
  162. package/web/.next/server/chunks/716.js +2 -0
  163. package/web/.next/server/chunks/790.js +11 -0
  164. package/web/.next/server/chunks/802.js +1 -0
  165. package/web/.next/server/chunks/890.js +1 -1
  166. package/web/.next/server/chunks/919.js +1 -0
  167. package/web/.next/server/chunks/950.js +6 -0
  168. package/web/.next/server/middleware-build-manifest.js +1 -1
  169. package/web/.next/server/middleware-react-loadable-manifest.js +1 -1
  170. package/web/.next/server/next-font-manifest.js +1 -1
  171. package/web/.next/server/next-font-manifest.json +1 -1
  172. package/web/.next/server/pages/404.html +1 -1
  173. package/web/.next/server/pages/500.html +1 -1
  174. package/web/.next/server/server-reference-manifest.json +1 -1
  175. package/web/.next/static/Bz7onClw1BajMUCwqpU8o/_buildManifest.js +1 -0
  176. package/web/.next/static/chunks/0937d497-114a2a3de515565e.js +1 -0
  177. package/web/.next/static/chunks/176-aeaf907a6ea5627d.js +1 -0
  178. package/web/.next/static/chunks/291-efae53ea5f7ee92d.js +1 -0
  179. package/web/.next/static/chunks/2b9ff8ee-969e65cc354b2150.js +1 -0
  180. package/web/.next/static/chunks/30-9adcbe92b15a6815.js +1 -0
  181. package/web/.next/static/chunks/316-26da9cc233ba7557.js +1 -0
  182. package/web/.next/static/chunks/350-56599dc3bf06066d.js +1 -0
  183. package/web/.next/static/chunks/486-13e08542f3a1cbac.js +1 -0
  184. package/web/.next/static/chunks/491-6b4e6201f5110dff.js +1 -0
  185. package/web/.next/static/chunks/517-ccaf8cc5c733cbd8.js +1 -0
  186. package/web/.next/static/chunks/545.bfbd92b7632c09de.js +1 -0
  187. package/web/.next/static/chunks/{805-d946ebedb7e85f73.js → 562-7c2e33d838e869bf.js} +1 -1
  188. package/web/.next/static/chunks/581-3ad5c4343dad3f50.js +1 -0
  189. package/web/.next/static/chunks/586-f7017d585a84738d.js +1 -0
  190. package/web/.next/static/chunks/657.b4c39e676c3e20dc.js +1 -0
  191. package/web/.next/static/chunks/701.6abcaf5e60463eef.js +6 -0
  192. package/web/.next/static/chunks/705-c7e75806f77b880c.js +1 -0
  193. package/web/.next/static/chunks/706-fa2be0f10ffebe6a.js +1 -0
  194. package/web/.next/static/chunks/837-33c7480524f48577.js +1 -0
  195. package/web/.next/static/chunks/839-4aefe6e71be6e1ef.js +1 -0
  196. package/web/.next/static/chunks/844-fe55292e0701f436.js +1 -0
  197. package/web/.next/static/chunks/89-b194fcffe5120c44.js +1 -0
  198. package/web/.next/static/chunks/97.594543c2196de524.js +1 -0
  199. package/web/.next/static/chunks/app/_not-found/page-238a7b80bda6b4ae.js +1 -0
  200. package/web/.next/static/chunks/app/agents/[id]/page-3faf40800981a736.js +1 -0
  201. package/web/.next/static/chunks/app/agents/page-f4c4c80f955f3967.js +1 -0
  202. package/web/.next/static/chunks/app/connections/page-0936beaf02d863c6.js +1 -0
  203. package/web/.next/static/chunks/app/layout-99620746d028dda8.js +1 -0
  204. package/web/.next/static/chunks/app/page-a7f292117b7d76bf.js +1 -0
  205. package/web/.next/static/chunks/app/relations/page-fba25393c8688714.js +1 -0
  206. package/web/.next/static/chunks/app/resources/[id]/page-d110d89bb8b5fca7.js +1 -0
  207. package/web/.next/static/chunks/app/resources/page-bbd0b450d3f3131d.js +1 -0
  208. package/web/.next/static/chunks/app/schedules/page-a1124397fc760413.js +1 -0
  209. package/web/.next/static/chunks/app/sessions/page-0e322811b0cde724.js +1 -0
  210. package/web/.next/static/chunks/app/skills/page-22ea0ef89d9f7a13.js +1 -0
  211. package/web/.next/static/chunks/app/types/page-18c4e1db2724d41d.js +1 -0
  212. package/web/.next/static/chunks/fcafe1ac.366e4950d3b0d4b7.js +18 -0
  213. package/web/.next/static/chunks/framework-bbac72adbbe2d328.js +1 -0
  214. package/web/.next/static/chunks/main-app-6086068e5fb5eacd.js +1 -0
  215. package/web/.next/static/chunks/main-c15f3fee674e0303.js +1 -0
  216. package/web/.next/static/chunks/pages/_app-d1670a2c6ce392fc.js +1 -0
  217. package/web/.next/static/chunks/pages/_error-95aac014d202fa7a.js +1 -0
  218. package/web/.next/static/chunks/webpack-ef515e41a83a16ac.js +1 -0
  219. package/web/.next/static/css/945795da867f5250.css +1 -0
  220. package/web/.next/static/css/b7a03c62468f4263.css +1 -0
  221. package/web/.next/trace +29 -23
  222. package/web/.next/types/app/resources/[id]/page.ts +84 -0
  223. package/web/.next/types/app/resources/page.ts +84 -0
  224. package/web/.next/types/routes.d.ts +6 -2
  225. package/web/.next/types/validator.ts +18 -0
  226. package/web/next.config.mjs +4 -0
  227. package/web/.next/server/chunks/247.js +0 -1
  228. package/web/.next/server/chunks/484.js +0 -11
  229. package/web/.next/server/chunks/851.js +0 -1
  230. package/web/.next/server/chunks/932.js +0 -2
  231. package/web/.next/static/_z2hBOHhwiR5ytdI_8alh/_buildManifest.js +0 -1
  232. package/web/.next/static/chunks/0937d497-44abb0f9355ace92.js +0 -1
  233. package/web/.next/static/chunks/2b9ff8ee-c3b61ac1e608c57d.js +0 -1
  234. package/web/.next/static/chunks/463-6ae35cdefdc59169.js +0 -1
  235. package/web/.next/static/chunks/493-50d2adf9fd5ec680.js +0 -1
  236. package/web/.next/static/chunks/517-eb26c72f6059aa26.js +0 -1
  237. package/web/.next/static/chunks/589-8bf536f331de4269.js +0 -1
  238. package/web/.next/static/chunks/657.f1e03b7b65eba1d9.js +0 -1
  239. package/web/.next/static/chunks/687-3a4205f51be38602.js +0 -1
  240. package/web/.next/static/chunks/837-fd7623601dc78ed8.js +0 -1
  241. package/web/.next/static/chunks/850-318f32484989dd59.js +0 -1
  242. package/web/.next/static/chunks/89-ace2e1aa63babfdf.js +0 -1
  243. package/web/.next/static/chunks/951-e250b541b67da7ce.js +0 -1
  244. package/web/.next/static/chunks/app/_not-found/page-bbd54d7b9a55d7ae.js +0 -1
  245. package/web/.next/static/chunks/app/agents/[id]/page-a8b7a43d2c18483f.js +0 -1
  246. package/web/.next/static/chunks/app/agents/page-e9b17f1c3439ef98.js +0 -1
  247. package/web/.next/static/chunks/app/connections/page-477f36fcd5b13d78.js +0 -1
  248. package/web/.next/static/chunks/app/layout-a2d38e3de5911b1b.js +0 -1
  249. package/web/.next/static/chunks/app/page-6fc87fc5a128a204.js +0 -1
  250. package/web/.next/static/chunks/app/relations/page-0355a93a8eb67989.js +0 -1
  251. package/web/.next/static/chunks/app/schedules/page-39befd15b3b20586.js +0 -1
  252. package/web/.next/static/chunks/app/sessions/page-beae9a74a07d69e0.js +0 -1
  253. package/web/.next/static/chunks/app/skills/page-4f839ac913e26d32.js +0 -1
  254. package/web/.next/static/chunks/app/types/page-4f6b99af3232f861.js +0 -1
  255. package/web/.next/static/chunks/framework-0e68884e76d9a8d3.js +0 -1
  256. package/web/.next/static/chunks/main-app-d6f73ccd41f325c5.js +0 -1
  257. package/web/.next/static/chunks/main-cd22509db15764e2.js +0 -1
  258. package/web/.next/static/chunks/pages/_app-0f75d689c738a6fc.js +0 -1
  259. package/web/.next/static/chunks/pages/_error-d481f6d49fb4455d.js +0 -1
  260. package/web/.next/static/chunks/webpack-d40de72e52f65f79.js +0 -1
  261. package/web/.next/static/css/da22f0402b1c40ae.css +0 -1
  262. /package/web/.next/static/{_z2hBOHhwiR5ytdI_8alh → Bz7onClw1BajMUCwqpU8o}/_ssgManifest.js +0 -0
@@ -0,0 +1,185 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { existsSync, statSync } from 'node:fs';
3
+ import { execFileSync } from 'node:child_process';
4
+ import { dirname } from 'node:path';
5
+ import { homedir } from 'node:os';
6
+ import { agents, resolved } from './db.js';
7
+ import { DomainError } from './errors.js';
8
+ import { objectsStore } from './objects/store.js';
9
+ import { containerName } from './objects/docker.js';
10
+ /**
11
+ * Terminals: real shells (a pseudo-terminal each) that the interface shows in its bottom panel. They are the user's own shell on their own
12
+ * machine, so they are as powerful as that: the server only serves them to pages and programs of this machine (see `isLocalRequest` in http/guards.ts) and
13
+ * `HIVE_AM_TERMINALS=0` turns them off. A terminal lives in the server, not in the page: reloading the page, or opening another one,
14
+ * shows the same terminals with what they printed last. They end when the server stops.
15
+ */
16
+ const MAX_TERMINALS = 12, BUFFER = 256 * 1024;
17
+ const MODE = /\x1b\[\?([0-9;]+)([hl])/g;
18
+ export const terminalsEnabled = () => process.env.HIVE_AM_TERMINALS !== '0';
19
+ let lib;
20
+ async function ptyLib() {
21
+ if (lib !== undefined)
22
+ return lib;
23
+ try {
24
+ lib = await import('@homebridge/node-pty-prebuilt-multiarch');
25
+ }
26
+ catch {
27
+ lib = null;
28
+ }
29
+ return lib;
30
+ }
31
+ export class TerminalError extends DomainError {
32
+ }
33
+ const terms = new Map();
34
+ export const listTerminals = () => [...terms.values()].map((t) => ({ id: t.id, title: t.title, cwd: t.cwd, command: t.command, created: t.created, alive: !t.exit, exitCode: t.exit?.code ?? null }));
35
+ /** Where and what to run: the user's shell in a folder, or a shell inside a container of an object. */
36
+ function plan(spec) {
37
+ const shell = process.env.SHELL && existsSync(process.env.SHELL) ? process.env.SHELL : '/bin/bash';
38
+ let cwd = typeof spec.cwd === 'string' && spec.cwd ? spec.cwd : homedir(), title = typeof spec.title === 'string' ? spec.title.slice(0, 60) : '';
39
+ let file = shell, args = shell.endsWith('bash') || shell.endsWith('zsh') ? ['-i'] : [];
40
+ if (typeof spec.agentId === 'string') {
41
+ const a = agents.get(spec.agentId);
42
+ if (!a)
43
+ throw new TerminalError('That agent no longer exists');
44
+ cwd = resolved(a).cwd;
45
+ title ||= a.name;
46
+ }
47
+ if (typeof spec.objectId === 'string') {
48
+ const o = objectsStore.get(spec.objectId);
49
+ if (!o)
50
+ throw new TerminalError('That resource no longer exists');
51
+ title ||= o.name;
52
+ if (o.kind === 'server')
53
+ cwd = o.config.cwd;
54
+ else if (o.kind === 'docker') {
55
+ const c = o.config;
56
+ let target;
57
+ if (c.mode === 'compose') {
58
+ if (typeof spec.service !== 'string' || !/^[\w][\w.-]{0,80}$/.test(spec.service))
59
+ throw new TerminalError('A compose project has several containers: pick a service.');
60
+ if (!existsSync(c.file))
61
+ throw new TerminalError('The compose file is missing');
62
+ let id = '';
63
+ try {
64
+ id = execFileSync('docker', ['compose', '-f', c.file, ...(c.project ? ['-p', c.project] : []), 'ps', '-q', spec.service], { cwd: dirname(c.file), encoding: 'utf8', timeout: 10_000 }).trim().split('\n')[0];
65
+ }
66
+ catch { /* reported below */ }
67
+ if (!id)
68
+ throw new TerminalError(`The service ${spec.service} has no container: start it first.`);
69
+ target = id;
70
+ title = `${o.name}/${spec.service}`;
71
+ }
72
+ else
73
+ target = c.mode === 'existing' ? c.container : containerName(o.id);
74
+ // A shell inside the container: bash when it has one, sh otherwise.
75
+ file = 'docker';
76
+ args = ['exec', '-it', target, 'sh', '-c', 'command -v bash >/dev/null 2>&1 && exec bash || exec sh'];
77
+ }
78
+ else
79
+ throw new TerminalError('This kind of resource has no terminal.');
80
+ }
81
+ if (!existsSync(cwd) || !statSync(cwd).isDirectory())
82
+ throw new TerminalError(`The folder ${cwd} does not exist`);
83
+ return { cwd, file, args, title: title || cwd.split('/').filter(Boolean).pop() || '/' };
84
+ }
85
+ export async function createTerminal(spec) {
86
+ if (!terminalsEnabled())
87
+ throw new TerminalError('Terminals are turned off (HIVE_AM_TERMINALS=0).');
88
+ const p = await ptyLib();
89
+ if (!p)
90
+ throw new TerminalError('Terminals need the node-pty library, which could not be loaded on this system. Reinstall hive-am without --omit=optional, or install @homebridge/node-pty-prebuilt-multiarch.');
91
+ if (terms.size >= MAX_TERMINALS)
92
+ throw new TerminalError(`There are already ${MAX_TERMINALS} terminals: close one first.`);
93
+ const { cwd, file, args, title } = plan(spec);
94
+ const env = Object.fromEntries(Object.entries(process.env).filter(([k, v]) => v !== undefined && !k.startsWith('HIVE_AM_') && k !== 'HIVE_AGENT_ID' && k !== 'HIVE_CAPS'));
95
+ const pty = p.spawn(file, args, { name: 'xterm-256color', cols: 100, rows: 28, cwd, env: { ...env, TERM: 'xterm-256color', COLORTERM: 'truecolor' } });
96
+ const t = { id: randomUUID(), title, cwd, command: [file, ...args].join(' '), created: Date.now(), cols: 100, rows: 28, pty, chunks: [], size: 0, modes: new Set(), clients: new Set() };
97
+ terms.set(t.id, t);
98
+ pty.onData((d) => {
99
+ t.chunks.push(d);
100
+ t.size += d.length;
101
+ for (const m of d.matchAll(MODE))
102
+ for (const n of m[1].split(';')) {
103
+ if (m[2] === 'h')
104
+ t.modes.add(n);
105
+ else
106
+ t.modes.delete(n);
107
+ }
108
+ while (t.size > BUFFER && t.chunks.length > 1)
109
+ t.size -= t.chunks.shift().length; // the oldest output goes first
110
+ const msg = JSON.stringify({ t: 'out', d });
111
+ for (const c of t.clients)
112
+ if (c.readyState === c.OPEN)
113
+ c.send(msg);
114
+ });
115
+ pty.onExit(({ exitCode, signal }) => {
116
+ t.exit = { code: exitCode, signal };
117
+ const msg = JSON.stringify({ t: 'exit', code: exitCode });
118
+ for (const c of t.clients)
119
+ if (c.readyState === c.OPEN)
120
+ c.send(msg);
121
+ });
122
+ return { id: t.id, title: t.title, cwd: t.cwd };
123
+ }
124
+ export function closeTerminal(id) {
125
+ const t = terms.get(id);
126
+ if (!t)
127
+ return false;
128
+ try {
129
+ if (!t.exit)
130
+ t.pty.kill();
131
+ }
132
+ catch { /* already gone */ }
133
+ for (const c of t.clients) {
134
+ try {
135
+ c.close();
136
+ }
137
+ catch { /* closed */ }
138
+ }
139
+ terms.delete(id);
140
+ return true;
141
+ }
142
+ /** A page attaches to a terminal: it gets what the terminal printed so far, then everything live. Input and resizes come back as JSON. */
143
+ export function attachTerminal(ws, id) {
144
+ const t = terms.get(id);
145
+ if (!t) {
146
+ ws.send(JSON.stringify({ t: 'gone' }));
147
+ ws.close();
148
+ return;
149
+ }
150
+ t.clients.add(ws);
151
+ ws.send(JSON.stringify({ t: 'init', title: t.title, cols: t.cols, rows: t.rows, alive: !t.exit }));
152
+ if (t.chunks.length)
153
+ ws.send(JSON.stringify({ t: 'out', d: [...t.modes].map((n) => `\x1b[?${n}h`).join('') + t.chunks.join('') }));
154
+ if (t.exit)
155
+ ws.send(JSON.stringify({ t: 'exit', code: t.exit.code }));
156
+ ws.on('message', (raw) => {
157
+ let m;
158
+ try {
159
+ m = JSON.parse(String(raw));
160
+ }
161
+ catch {
162
+ return;
163
+ }
164
+ if (t.exit)
165
+ return;
166
+ if (m.t === 'in' && typeof m.d === 'string' && m.d.length < 100_000)
167
+ t.pty.write(m.d);
168
+ else if (m.t === 'resize') {
169
+ const cols = Math.max(2, Math.min(500, Math.floor(Number(m.cols)))), rows = Math.max(2, Math.min(200, Math.floor(Number(m.rows))));
170
+ if (Number.isFinite(cols) && Number.isFinite(rows) && (cols !== t.cols || rows !== t.rows)) {
171
+ t.cols = cols;
172
+ t.rows = rows;
173
+ try {
174
+ t.pty.resize(cols, rows);
175
+ }
176
+ catch { /* ended */ }
177
+ }
178
+ }
179
+ });
180
+ ws.on('close', () => t.clients.delete(ws));
181
+ }
182
+ /** When hive-am stops, so do the shells it started. */
183
+ export function closeAllTerminals() { for (const id of [...terms.keys()])
184
+ closeTerminal(id); }
185
+ process.on('exit', closeAllTerminals);
@@ -4,31 +4,19 @@ import { adapterFor } from './connections/manager.js';
4
4
  import { deliverScheduled } from './connections/router.js';
5
5
  import { connections, threads } from './connections/store.js';
6
6
  import { liveOrigin, liveSource, sendTurn } from './runtime.js';
7
+ import { DomainError } from './errors.js';
7
8
  /**
8
9
  * Wake-ups. An agent only runs while it handles a message, so "I'll tell you when it finishes" cannot be kept by an agent that just
9
10
  * says it: it has to ask hive-am to wake it. `wake_me` stores the request; when it is due, the agent receives a message and answers.
10
11
  * Asked from a chat (Telegram, Slack…) the wake-up comes back to that same thread; asked from the hive-am web chat it comes back as a
11
12
  * message of the agent's own conversation.
12
13
  */
13
- export class WakeError extends Error {
14
+ export class WakeError extends DomainError {
14
15
  }
15
16
  export const WAKE_MIN_MINUTES = 1, WAKE_MAX_MINUTES = 240, WAKE_MAX_PENDING = 5;
16
17
  const WAKE_MS = Number(process.env.HIVE_AM_WAKE_MS_PER_MINUTE) || 60_000; // tests shrink a "minute"
18
+ const RETRY_MS = Number(process.env.HIVE_AM_WAKE_RETRY_MS) || 5000; // wait before trying a delivery again
17
19
  const TOO_LATE_MS = 2 * 3_600_000; // after a long outage, an old reminder is no longer useful
18
- db.exec(`
19
- DROP TABLE IF EXISTS wakeups;
20
- CREATE TABLE IF NOT EXISTS agent_wakeups (
21
- id TEXT PRIMARY KEY, agent_id TEXT NOT NULL REFERENCES agents(id) ON DELETE CASCADE,
22
- connection_id TEXT, thread_id TEXT REFERENCES threads(id) ON DELETE CASCADE,
23
- due_at INTEGER NOT NULL, note TEXT NOT NULL, created_at INTEGER NOT NULL
24
- );`);
25
- // Who asked (only kept when it was in a group): the reminder mentions them. Older databases get the columns here.
26
- for (const col of ['req_id TEXT', 'req_name TEXT']) {
27
- try {
28
- db.exec(`ALTER TABLE agent_wakeups ADD COLUMN ${col}`);
29
- }
30
- catch { /* already there */ }
31
- }
32
20
  const rows = {
33
21
  get: (id) => db.prepare('SELECT * FROM agent_wakeups WHERE id=?').get(id),
34
22
  all: () => db.prepare('SELECT * FROM agent_wakeups ORDER BY due_at').all(),
@@ -93,7 +81,7 @@ async function fire(id, tries) {
93
81
  const out = await deliverTo(w, wakeText(w, 'channel_reply'), `🔔 ${wakeText(w)}`, () => { rows.remove(id); });
94
82
  if (out === 'retry') {
95
83
  if (tries < 12) {
96
- w.due_at = Date.now() + 5000;
84
+ w.due_at = Date.now() + RETRY_MS;
97
85
  arm(w, tries + 1);
98
86
  }
99
87
  else
@@ -104,6 +92,15 @@ async function fire(id, tries) {
104
92
  }
105
93
  catch (e) {
106
94
  console.warn(`[wake] wake-up of agent ${agents.get(w.agent_id)?.name ?? w.agent_id} failed: ${e instanceof Error ? e.message : e}`);
95
+ // A failure before the message was handed over (the platform erred) must not strand the row: with no timer it would count as pending until the next restart. Try again a few times, then give up.
96
+ if (rows.get(id)) {
97
+ if (tries < 12) {
98
+ w.due_at = Date.now() + RETRY_MS;
99
+ arm(w, tries + 1);
100
+ }
101
+ else
102
+ rows.remove(id);
103
+ }
107
104
  }
108
105
  }
109
106
  /** Re-arms the wake-ups saved before a restart (called once at startup). */
@@ -8,24 +8,18 @@ import { liveOrigin, liveSource } from './runtime.js';
8
8
  import { adapterFor } from './connections/manager.js';
9
9
  import { connections, threadMessages, threads } from './connections/store.js';
10
10
  import { deliverTo } from './wake.js';
11
+ import { DomainError } from './errors.js';
11
12
  /**
12
13
  * "Tell me the moment it finishes." The agent starts a long command in the background itself (`nohup … > log 2>&1 &`) and asks hive-am to
13
14
  * watch its process: when it ends (or a marker file appears, or the waiting time runs out) the agent is woken in the same place where it
14
15
  * was asked, to read the result and report. hive-am only checks that a process is alive; it never runs anything. A job on another machine
15
16
  * works too when it is started through a local `ssh`, which lives as long as the remote command does.
16
17
  */
17
- export class WatchError extends Error {
18
+ export class WatchError extends DomainError {
18
19
  }
19
20
  const POLL_MS = Number(process.env.HIVE_AM_WATCH_POLL_MS) || 1500;
20
21
  const MS_PER_MINUTE = Number(process.env.HIVE_AM_WAKE_MS_PER_MINUTE) || 60_000;
21
22
  export const WATCH_DEFAULT_MINUTES = 120, WATCH_MAX_MINUTES = 240, WATCH_MAX_PENDING = 5;
22
- db.exec(`
23
- CREATE TABLE IF NOT EXISTS agent_watches (
24
- id TEXT PRIMARY KEY, agent_id TEXT NOT NULL REFERENCES agents(id) ON DELETE CASCADE,
25
- connection_id TEXT, thread_id TEXT REFERENCES threads(id) ON DELETE CASCADE,
26
- pid INTEGER NOT NULL, pid_stamp TEXT, file TEXT, log TEXT, note TEXT NOT NULL,
27
- started_at INTEGER NOT NULL, deadline INTEGER NOT NULL, req_id TEXT, req_name TEXT
28
- );`);
29
23
  const rows = {
30
24
  all: () => db.prepare('SELECT * FROM agent_watches ORDER BY started_at').all(),
31
25
  forAgent: (agentId) => db.prepare('SELECT * FROM agent_watches WHERE agent_id=?').all(agentId),
@@ -1,8 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  // Minimal MCP stdio server for hive-am agents. Tool groups come from HIVE_CAPS:
3
3
  // dispatch → list_agents, dispatch (orchestrators with a team)
4
- // channel → channel_reply, channel_send_file, channel_mute (agents linked to Telegram/Slack)
4
+ // channel → channel_reply, channel_send_file, channel_react, channel_mute (agents linked to Telegram/Slack)
5
5
  // wake → wake_me, wake_when_done, schedule_create, schedule_list, schedule_cancel (agents with the Wake-ups skill: to be woken later in the same place)
6
+ // objects → object_list, object_logs, object_action (agents with the Colony objects skill: the servers and containers of their colony)
6
7
  // It only talks to the hive-am HTTP API; all rules (assignments, queueing) live there.
7
8
  import { createInterface } from 'node:readline';
8
9
 
@@ -101,6 +102,17 @@ const allTools = [
101
102
  additionalProperties: false,
102
103
  },
103
104
  },
105
+ {
106
+ cap: 'channel',
107
+ name: 'channel_react',
108
+ description: 'React with ONE emoji to the message you are handling (a thumbs-up to say "got it", a heart to say thanks). It is lighter than a reply and counts as your answer when nothing else needs saying. Each platform allows only some emoji (on Telegram a fixed list: 👍 👎 ❤ 🔥 👏 🎉 🙏 👌 👀 💯 🤔 😁 😢 ✍ 🫡 …); an emoji that is not allowed is refused and the error lists the ones you can use. Follow the "Chat channels" skill for when to react.',
109
+ inputSchema: {
110
+ type: 'object',
111
+ properties: { emoji: { type: 'string', description: 'A single emoji, e.g. 👍.' } },
112
+ required: ['emoji'],
113
+ additionalProperties: false,
114
+ },
115
+ },
104
116
  {
105
117
  cap: 'channel',
106
118
  name: 'channel_mute',
@@ -112,6 +124,40 @@ const allTools = [
112
124
  additionalProperties: false,
113
125
  },
114
126
  },
127
+ {
128
+ cap: 'objects',
129
+ name: 'object_list',
130
+ description: 'List the objects of your colony (servers and Docker containers that hive-am keeps running): name, kind, state (running, starting, stopped, error, unknown) and the reason when there is one. Use the exact names in the other object tools.',
131
+ inputSchema: { type: 'object', properties: {}, additionalProperties: false },
132
+ },
133
+ {
134
+ cap: 'objects',
135
+ name: 'object_logs',
136
+ description: 'Read the latest output of an object of your colony (a server or a container). Read it before restarting something that fails. Logs can contain secrets: never repeat them in a chat.',
137
+ inputSchema: {
138
+ type: 'object',
139
+ properties: {
140
+ name: { type: 'string', description: 'The exact name of the object, as object_list shows it.' },
141
+ tail: { type: 'number', description: 'How many of the last lines to read (default 80, at most 500).' },
142
+ },
143
+ required: ['name'],
144
+ additionalProperties: false,
145
+ },
146
+ },
147
+ {
148
+ cap: 'objects',
149
+ name: 'object_action',
150
+ description: 'Start, stop or restart an object of your colony. Not available in read-only mode. It answers with the state it ended in: check it with object_list a moment later, since a server can take a while to come up. Starting, stopping and restarting interrupt whoever uses it: do not do it for something that runs fine unless you were asked.',
151
+ inputSchema: {
152
+ type: 'object',
153
+ properties: {
154
+ name: { type: 'string', description: 'The exact name of the object.' },
155
+ action: { type: 'string', enum: ['start', 'stop', 'restart'] },
156
+ },
157
+ required: ['name', 'action'],
158
+ additionalProperties: false,
159
+ },
160
+ },
115
161
  {
116
162
  cap: 'wake',
117
163
  name: 'wake_me',
@@ -229,6 +275,15 @@ async function call(name, args) {
229
275
  if (!r.ok) throw new Error(j.error ?? `channel_send_file failed (${r.status})`);
230
276
  return `Sent ${j.name} (${j.kind}).`;
231
277
  }
278
+ if (name === 'channel_react') {
279
+ const r = await fetch(`${API}/api/channel/react`, {
280
+ method: 'POST', headers: { 'content-type': 'application/json' },
281
+ body: JSON.stringify({ from: FROM, emoji: args.emoji }),
282
+ });
283
+ const j = await r.json();
284
+ if (!r.ok) throw new Error(j.error ?? `channel_react failed (${r.status})`);
285
+ return `Reacted with ${j.emoji}.`;
286
+ }
232
287
  if (name === 'channel_mute') {
233
288
  const r = await fetch(`${API}/api/channel/mute`, {
234
289
  method: 'POST', headers: { 'content-type': 'application/json' },
@@ -238,6 +293,20 @@ async function call(name, args) {
238
293
  if (!r.ok) throw new Error(j.error ?? `channel_mute failed (${r.status})`);
239
294
  return j.muted ? `Muted in this thread (${j.place}). You will only be woken when someone mentions you or replies to you.` : `Unmuted in this thread (${j.place}).`;
240
295
  }
296
+ if (name === 'object_list' || name === 'object_logs' || name === 'object_action') {
297
+ const r = await fetch(`${API}/api/agent-objects/${name.slice('object_'.length)}`, {
298
+ method: 'POST', headers: { 'content-type': 'application/json' },
299
+ body: JSON.stringify({ from: FROM, ...args }),
300
+ });
301
+ const j = await r.json();
302
+ if (!r.ok) throw new Error(j.error ?? `${name} failed (${r.status})`);
303
+ if (name === 'object_list') {
304
+ if (!j.objects.length) return 'Your colony has no objects.';
305
+ return j.objects.map((o) => `${o.name} · ${o.kind} · ${o.status}${o.detail ? ` (${o.detail})` : ''}`).join('\n');
306
+ }
307
+ if (name === 'object_logs') return j.text.trim() ? `Last lines of ${j.name}:\n${j.text}` : `${j.name} has not printed anything.`;
308
+ return `${j.name}: ${j.status}${j.detail ? ` (${j.detail})` : ''}. Check again with object_list in a moment.`;
309
+ }
241
310
  if (name === 'wake_me') {
242
311
  const r = await fetch(`${API}/api/wake`, {
243
312
  method: 'POST', headers: { 'content-type': 'application/json' },
@@ -1 +1 @@
1
- _z2hBOHhwiR5ytdI_8alh
1
+ Bz7onClw1BajMUCwqpU8o
@@ -1,116 +1,168 @@
1
1
  {
2
2
  "pages": {
3
3
  "/_not-found/page": [
4
- "static/chunks/webpack-d40de72e52f65f79.js",
5
- "static/chunks/0937d497-44abb0f9355ace92.js",
6
- "static/chunks/89-ace2e1aa63babfdf.js",
7
- "static/chunks/main-app-d6f73ccd41f325c5.js",
8
- "static/chunks/app/_not-found/page-bbd54d7b9a55d7ae.js"
4
+ "static/chunks/webpack-ef515e41a83a16ac.js",
5
+ "static/chunks/0937d497-114a2a3de515565e.js",
6
+ "static/chunks/89-b194fcffe5120c44.js",
7
+ "static/chunks/main-app-6086068e5fb5eacd.js",
8
+ "static/chunks/app/_not-found/page-238a7b80bda6b4ae.js"
9
9
  ],
10
10
  "/layout": [
11
- "static/chunks/webpack-d40de72e52f65f79.js",
12
- "static/chunks/0937d497-44abb0f9355ace92.js",
13
- "static/chunks/89-ace2e1aa63babfdf.js",
14
- "static/chunks/main-app-d6f73ccd41f325c5.js",
15
- "static/css/da22f0402b1c40ae.css",
16
- "static/chunks/463-6ae35cdefdc59169.js",
17
- "static/chunks/493-50d2adf9fd5ec680.js",
18
- "static/chunks/app/layout-a2d38e3de5911b1b.js"
11
+ "static/chunks/webpack-ef515e41a83a16ac.js",
12
+ "static/chunks/0937d497-114a2a3de515565e.js",
13
+ "static/chunks/89-b194fcffe5120c44.js",
14
+ "static/chunks/main-app-6086068e5fb5eacd.js",
15
+ "static/css/945795da867f5250.css",
16
+ "static/css/b7a03c62468f4263.css",
17
+ "static/chunks/586-f7017d585a84738d.js",
18
+ "static/chunks/839-4aefe6e71be6e1ef.js",
19
+ "static/chunks/app/layout-99620746d028dda8.js"
19
20
  ],
20
21
  "/connections/page": [
21
- "static/chunks/webpack-d40de72e52f65f79.js",
22
- "static/chunks/0937d497-44abb0f9355ace92.js",
23
- "static/chunks/89-ace2e1aa63babfdf.js",
24
- "static/chunks/main-app-d6f73ccd41f325c5.js",
25
- "static/chunks/493-50d2adf9fd5ec680.js",
26
- "static/chunks/app/connections/page-477f36fcd5b13d78.js"
22
+ "static/chunks/webpack-ef515e41a83a16ac.js",
23
+ "static/chunks/0937d497-114a2a3de515565e.js",
24
+ "static/chunks/89-b194fcffe5120c44.js",
25
+ "static/chunks/main-app-6086068e5fb5eacd.js",
26
+ "static/chunks/586-f7017d585a84738d.js",
27
+ "static/chunks/839-4aefe6e71be6e1ef.js",
28
+ "static/chunks/app/connections/page-0936beaf02d863c6.js"
27
29
  ],
28
- "/schedules/page": [
29
- "static/chunks/webpack-d40de72e52f65f79.js",
30
- "static/chunks/0937d497-44abb0f9355ace92.js",
31
- "static/chunks/89-ace2e1aa63babfdf.js",
32
- "static/chunks/main-app-d6f73ccd41f325c5.js",
33
- "static/chunks/493-50d2adf9fd5ec680.js",
34
- "static/chunks/app/schedules/page-39befd15b3b20586.js"
30
+ "/agents/[id]/page": [
31
+ "static/chunks/webpack-ef515e41a83a16ac.js",
32
+ "static/chunks/0937d497-114a2a3de515565e.js",
33
+ "static/chunks/89-b194fcffe5120c44.js",
34
+ "static/chunks/main-app-6086068e5fb5eacd.js",
35
+ "static/chunks/586-f7017d585a84738d.js",
36
+ "static/chunks/706-fa2be0f10ffebe6a.js",
37
+ "static/chunks/837-33c7480524f48577.js",
38
+ "static/chunks/486-13e08542f3a1cbac.js",
39
+ "static/chunks/316-26da9cc233ba7557.js",
40
+ "static/chunks/839-4aefe6e71be6e1ef.js",
41
+ "static/chunks/517-ccaf8cc5c733cbd8.js",
42
+ "static/chunks/350-56599dc3bf06066d.js",
43
+ "static/chunks/291-efae53ea5f7ee92d.js",
44
+ "static/chunks/30-9adcbe92b15a6815.js",
45
+ "static/chunks/705-c7e75806f77b880c.js",
46
+ "static/chunks/app/agents/[id]/page-3faf40800981a736.js"
35
47
  ],
36
- "/agents/page": [
37
- "static/chunks/webpack-d40de72e52f65f79.js",
38
- "static/chunks/0937d497-44abb0f9355ace92.js",
39
- "static/chunks/89-ace2e1aa63babfdf.js",
40
- "static/chunks/main-app-d6f73ccd41f325c5.js",
41
- "static/chunks/951-e250b541b67da7ce.js",
42
- "static/chunks/463-6ae35cdefdc59169.js",
43
- "static/chunks/493-50d2adf9fd5ec680.js",
44
- "static/chunks/517-eb26c72f6059aa26.js",
45
- "static/chunks/app/agents/page-e9b17f1c3439ef98.js"
48
+ "/resources/[id]/page": [
49
+ "static/chunks/webpack-ef515e41a83a16ac.js",
50
+ "static/chunks/0937d497-114a2a3de515565e.js",
51
+ "static/chunks/89-b194fcffe5120c44.js",
52
+ "static/chunks/main-app-6086068e5fb5eacd.js",
53
+ "static/chunks/586-f7017d585a84738d.js",
54
+ "static/chunks/706-fa2be0f10ffebe6a.js",
55
+ "static/chunks/837-33c7480524f48577.js",
56
+ "static/chunks/486-13e08542f3a1cbac.js",
57
+ "static/chunks/581-3ad5c4343dad3f50.js",
58
+ "static/chunks/839-4aefe6e71be6e1ef.js",
59
+ "static/chunks/517-ccaf8cc5c733cbd8.js",
60
+ "static/chunks/350-56599dc3bf06066d.js",
61
+ "static/chunks/291-efae53ea5f7ee92d.js",
62
+ "static/chunks/844-fe55292e0701f436.js",
63
+ "static/chunks/30-9adcbe92b15a6815.js",
64
+ "static/chunks/491-6b4e6201f5110dff.js",
65
+ "static/chunks/app/resources/[id]/page-d110d89bb8b5fca7.js"
46
66
  ],
47
- "/sessions/page": [
48
- "static/chunks/webpack-d40de72e52f65f79.js",
49
- "static/chunks/0937d497-44abb0f9355ace92.js",
50
- "static/chunks/89-ace2e1aa63babfdf.js",
51
- "static/chunks/main-app-d6f73ccd41f325c5.js",
52
- "static/chunks/951-e250b541b67da7ce.js",
53
- "static/chunks/463-6ae35cdefdc59169.js",
54
- "static/chunks/493-50d2adf9fd5ec680.js",
55
- "static/chunks/app/sessions/page-beae9a74a07d69e0.js"
67
+ "/resources/page": [
68
+ "static/chunks/webpack-ef515e41a83a16ac.js",
69
+ "static/chunks/0937d497-114a2a3de515565e.js",
70
+ "static/chunks/89-b194fcffe5120c44.js",
71
+ "static/chunks/main-app-6086068e5fb5eacd.js",
72
+ "static/chunks/586-f7017d585a84738d.js",
73
+ "static/chunks/706-fa2be0f10ffebe6a.js",
74
+ "static/chunks/837-33c7480524f48577.js",
75
+ "static/chunks/486-13e08542f3a1cbac.js",
76
+ "static/chunks/581-3ad5c4343dad3f50.js",
77
+ "static/chunks/839-4aefe6e71be6e1ef.js",
78
+ "static/chunks/517-ccaf8cc5c733cbd8.js",
79
+ "static/chunks/350-56599dc3bf06066d.js",
80
+ "static/chunks/291-efae53ea5f7ee92d.js",
81
+ "static/chunks/844-fe55292e0701f436.js",
82
+ "static/chunks/30-9adcbe92b15a6815.js",
83
+ "static/chunks/491-6b4e6201f5110dff.js",
84
+ "static/chunks/app/resources/page-bbd0b450d3f3131d.js"
56
85
  ],
57
- "/types/page": [
58
- "static/chunks/webpack-d40de72e52f65f79.js",
59
- "static/chunks/0937d497-44abb0f9355ace92.js",
60
- "static/chunks/89-ace2e1aa63babfdf.js",
61
- "static/chunks/main-app-d6f73ccd41f325c5.js",
62
- "static/chunks/951-e250b541b67da7ce.js",
63
- "static/chunks/493-50d2adf9fd5ec680.js",
64
- "static/chunks/517-eb26c72f6059aa26.js",
65
- "static/chunks/app/types/page-4f6b99af3232f861.js"
86
+ "/schedules/page": [
87
+ "static/chunks/webpack-ef515e41a83a16ac.js",
88
+ "static/chunks/0937d497-114a2a3de515565e.js",
89
+ "static/chunks/89-b194fcffe5120c44.js",
90
+ "static/chunks/main-app-6086068e5fb5eacd.js",
91
+ "static/chunks/586-f7017d585a84738d.js",
92
+ "static/chunks/839-4aefe6e71be6e1ef.js",
93
+ "static/chunks/app/schedules/page-a1124397fc760413.js"
94
+ ],
95
+ "/sessions/page": [
96
+ "static/chunks/webpack-ef515e41a83a16ac.js",
97
+ "static/chunks/0937d497-114a2a3de515565e.js",
98
+ "static/chunks/89-b194fcffe5120c44.js",
99
+ "static/chunks/main-app-6086068e5fb5eacd.js",
100
+ "static/chunks/586-f7017d585a84738d.js",
101
+ "static/chunks/706-fa2be0f10ffebe6a.js",
102
+ "static/chunks/176-aeaf907a6ea5627d.js",
103
+ "static/chunks/839-4aefe6e71be6e1ef.js",
104
+ "static/chunks/350-56599dc3bf06066d.js",
105
+ "static/chunks/705-c7e75806f77b880c.js",
106
+ "static/chunks/app/sessions/page-0e322811b0cde724.js"
66
107
  ],
67
108
  "/skills/page": [
68
- "static/chunks/webpack-d40de72e52f65f79.js",
69
- "static/chunks/0937d497-44abb0f9355ace92.js",
70
- "static/chunks/89-ace2e1aa63babfdf.js",
71
- "static/chunks/main-app-d6f73ccd41f325c5.js",
72
- "static/chunks/951-e250b541b67da7ce.js",
73
- "static/chunks/493-50d2adf9fd5ec680.js",
74
- "static/chunks/app/skills/page-4f839ac913e26d32.js"
109
+ "static/chunks/webpack-ef515e41a83a16ac.js",
110
+ "static/chunks/0937d497-114a2a3de515565e.js",
111
+ "static/chunks/89-b194fcffe5120c44.js",
112
+ "static/chunks/main-app-6086068e5fb5eacd.js",
113
+ "static/chunks/586-f7017d585a84738d.js",
114
+ "static/chunks/706-fa2be0f10ffebe6a.js",
115
+ "static/chunks/839-4aefe6e71be6e1ef.js",
116
+ "static/chunks/app/skills/page-22ea0ef89d9f7a13.js"
75
117
  ],
76
- "/agents/[id]/page": [
77
- "static/chunks/webpack-d40de72e52f65f79.js",
78
- "static/chunks/0937d497-44abb0f9355ace92.js",
79
- "static/chunks/89-ace2e1aa63babfdf.js",
80
- "static/chunks/main-app-d6f73ccd41f325c5.js",
81
- "static/chunks/951-e250b541b67da7ce.js",
82
- "static/chunks/463-6ae35cdefdc59169.js",
83
- "static/chunks/837-fd7623601dc78ed8.js",
84
- "static/chunks/687-3a4205f51be38602.js",
85
- "static/chunks/589-8bf536f331de4269.js",
86
- "static/chunks/493-50d2adf9fd5ec680.js",
87
- "static/chunks/517-eb26c72f6059aa26.js",
88
- "static/chunks/850-318f32484989dd59.js",
89
- "static/chunks/app/agents/[id]/page-a8b7a43d2c18483f.js"
118
+ "/types/page": [
119
+ "static/chunks/webpack-ef515e41a83a16ac.js",
120
+ "static/chunks/0937d497-114a2a3de515565e.js",
121
+ "static/chunks/89-b194fcffe5120c44.js",
122
+ "static/chunks/main-app-6086068e5fb5eacd.js",
123
+ "static/chunks/586-f7017d585a84738d.js",
124
+ "static/chunks/706-fa2be0f10ffebe6a.js",
125
+ "static/chunks/839-4aefe6e71be6e1ef.js",
126
+ "static/chunks/517-ccaf8cc5c733cbd8.js",
127
+ "static/chunks/app/types/page-18c4e1db2724d41d.js"
128
+ ],
129
+ "/agents/page": [
130
+ "static/chunks/webpack-ef515e41a83a16ac.js",
131
+ "static/chunks/0937d497-114a2a3de515565e.js",
132
+ "static/chunks/89-b194fcffe5120c44.js",
133
+ "static/chunks/main-app-6086068e5fb5eacd.js",
134
+ "static/chunks/586-f7017d585a84738d.js",
135
+ "static/chunks/706-fa2be0f10ffebe6a.js",
136
+ "static/chunks/839-4aefe6e71be6e1ef.js",
137
+ "static/chunks/517-ccaf8cc5c733cbd8.js",
138
+ "static/chunks/app/agents/page-f4c4c80f955f3967.js"
90
139
  ],
91
140
  "/page": [
92
- "static/chunks/webpack-d40de72e52f65f79.js",
93
- "static/chunks/0937d497-44abb0f9355ace92.js",
94
- "static/chunks/89-ace2e1aa63babfdf.js",
95
- "static/chunks/main-app-d6f73ccd41f325c5.js",
96
- "static/chunks/951-e250b541b67da7ce.js",
97
- "static/chunks/463-6ae35cdefdc59169.js",
98
- "static/chunks/687-3a4205f51be38602.js",
99
- "static/chunks/493-50d2adf9fd5ec680.js",
100
- "static/chunks/517-eb26c72f6059aa26.js",
101
- "static/chunks/850-318f32484989dd59.js",
102
- "static/chunks/app/page-6fc87fc5a128a204.js"
141
+ "static/chunks/webpack-ef515e41a83a16ac.js",
142
+ "static/chunks/0937d497-114a2a3de515565e.js",
143
+ "static/chunks/89-b194fcffe5120c44.js",
144
+ "static/chunks/main-app-6086068e5fb5eacd.js",
145
+ "static/chunks/586-f7017d585a84738d.js",
146
+ "static/chunks/706-fa2be0f10ffebe6a.js",
147
+ "static/chunks/486-13e08542f3a1cbac.js",
148
+ "static/chunks/839-4aefe6e71be6e1ef.js",
149
+ "static/chunks/517-ccaf8cc5c733cbd8.js",
150
+ "static/chunks/350-56599dc3bf06066d.js",
151
+ "static/chunks/291-efae53ea5f7ee92d.js",
152
+ "static/chunks/844-fe55292e0701f436.js",
153
+ "static/chunks/app/page-a7f292117b7d76bf.js"
103
154
  ],
104
155
  "/relations/page": [
105
- "static/chunks/webpack-d40de72e52f65f79.js",
106
- "static/chunks/0937d497-44abb0f9355ace92.js",
107
- "static/chunks/89-ace2e1aa63babfdf.js",
108
- "static/chunks/main-app-d6f73ccd41f325c5.js",
156
+ "static/chunks/webpack-ef515e41a83a16ac.js",
157
+ "static/chunks/0937d497-114a2a3de515565e.js",
158
+ "static/chunks/89-b194fcffe5120c44.js",
159
+ "static/chunks/main-app-6086068e5fb5eacd.js",
109
160
  "static/css/c4a545148b5320ec.css",
110
- "static/chunks/2b9ff8ee-c3b61ac1e608c57d.js",
111
- "static/chunks/805-d946ebedb7e85f73.js",
112
- "static/chunks/493-50d2adf9fd5ec680.js",
113
- "static/chunks/app/relations/page-0355a93a8eb67989.js"
161
+ "static/chunks/2b9ff8ee-969e65cc354b2150.js",
162
+ "static/chunks/586-f7017d585a84738d.js",
163
+ "static/chunks/562-7c2e33d838e869bf.js",
164
+ "static/chunks/839-4aefe6e71be6e1ef.js",
165
+ "static/chunks/app/relations/page-fba25393c8688714.js"
114
166
  ]
115
167
  }
116
168
  }