heyio 1.13.0 → 3.0.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 (327) hide show
  1. package/dist/api/middleware/auth.d.ts +14 -0
  2. package/dist/api/middleware/auth.d.ts.map +1 -0
  3. package/dist/api/middleware/auth.js +66 -0
  4. package/dist/api/middleware/auth.js.map +1 -0
  5. package/dist/api/notifications.d.ts +14 -0
  6. package/dist/api/notifications.d.ts.map +1 -0
  7. package/dist/api/notifications.js +112 -0
  8. package/dist/api/notifications.js.map +1 -0
  9. package/dist/api/routes/activity.d.ts +3 -0
  10. package/dist/api/routes/activity.d.ts.map +1 -0
  11. package/dist/api/routes/activity.js +28 -0
  12. package/dist/api/routes/activity.js.map +1 -0
  13. package/dist/api/routes/attachments.d.ts +3 -0
  14. package/dist/api/routes/attachments.d.ts.map +1 -0
  15. package/dist/api/routes/attachments.js +83 -0
  16. package/dist/api/routes/attachments.js.map +1 -0
  17. package/dist/api/routes/config.d.ts +3 -0
  18. package/dist/api/routes/config.d.ts.map +1 -0
  19. package/dist/api/routes/config.js +106 -0
  20. package/dist/api/routes/config.js.map +1 -0
  21. package/dist/api/routes/conversations.d.ts +3 -0
  22. package/dist/api/routes/conversations.d.ts.map +1 -0
  23. package/dist/api/routes/conversations.js +69 -0
  24. package/dist/api/routes/conversations.js.map +1 -0
  25. package/dist/api/routes/health.d.ts +3 -0
  26. package/dist/api/routes/health.d.ts.map +1 -0
  27. package/dist/api/routes/health.js +16 -0
  28. package/dist/api/routes/health.js.map +1 -0
  29. package/dist/api/routes/inbox.d.ts +3 -0
  30. package/dist/api/routes/inbox.d.ts.map +1 -0
  31. package/dist/api/routes/inbox.js +88 -0
  32. package/dist/api/routes/inbox.js.map +1 -0
  33. package/dist/api/routes/schedules.d.ts +3 -0
  34. package/dist/api/routes/schedules.d.ts.map +1 -0
  35. package/dist/api/routes/schedules.js +96 -0
  36. package/dist/api/routes/schedules.js.map +1 -0
  37. package/dist/api/routes/skills.d.ts +2 -0
  38. package/dist/api/routes/skills.d.ts.map +1 -0
  39. package/dist/api/routes/skills.js +85 -0
  40. package/dist/api/routes/skills.js.map +1 -0
  41. package/dist/api/routes/squads.d.ts +3 -0
  42. package/dist/api/routes/squads.d.ts.map +1 -0
  43. package/dist/api/routes/squads.js +129 -0
  44. package/dist/api/routes/squads.js.map +1 -0
  45. package/dist/api/routes/usage.d.ts +3 -0
  46. package/dist/api/routes/usage.d.ts.map +1 -0
  47. package/dist/api/routes/usage.js +55 -0
  48. package/dist/api/routes/usage.js.map +1 -0
  49. package/dist/api/routes/wiki.d.ts +2 -0
  50. package/dist/api/routes/wiki.d.ts.map +1 -0
  51. package/dist/api/routes/wiki.js +43 -0
  52. package/dist/api/routes/wiki.js.map +1 -0
  53. package/dist/api/server.d.ts +7 -0
  54. package/dist/api/server.d.ts.map +1 -0
  55. package/dist/api/server.js +136 -634
  56. package/dist/api/server.js.map +1 -0
  57. package/dist/config.d.ts +3 -0
  58. package/dist/config.d.ts.map +1 -0
  59. package/dist/config.js +2 -91
  60. package/dist/config.js.map +1 -0
  61. package/dist/copilot/client.d.ts +5 -0
  62. package/dist/copilot/client.d.ts.map +1 -0
  63. package/dist/copilot/client.js +19 -11
  64. package/dist/copilot/client.js.map +1 -0
  65. package/dist/copilot/health-monitor.d.ts +14 -0
  66. package/dist/copilot/health-monitor.d.ts.map +1 -0
  67. package/dist/copilot/health-monitor.js +70 -0
  68. package/dist/copilot/health-monitor.js.map +1 -0
  69. package/dist/copilot/orchestrator.d.ts +5 -0
  70. package/dist/copilot/orchestrator.d.ts.map +1 -0
  71. package/dist/copilot/orchestrator.js +127 -123
  72. package/dist/copilot/orchestrator.js.map +1 -0
  73. package/dist/copilot/tools.d.ts +49 -0
  74. package/dist/copilot/tools.d.ts.map +1 -0
  75. package/dist/copilot/tools.js +545 -321
  76. package/dist/copilot/tools.js.map +1 -0
  77. package/dist/index.d.ts +3 -0
  78. package/dist/index.d.ts.map +1 -0
  79. package/dist/index.js +82 -26
  80. package/dist/index.js.map +1 -0
  81. package/dist/logging/logger.d.ts +6 -0
  82. package/dist/logging/logger.d.ts.map +1 -0
  83. package/dist/logging/logger.js +21 -0
  84. package/dist/logging/logger.js.map +1 -0
  85. package/dist/models/index.d.ts +6 -0
  86. package/dist/models/index.d.ts.map +1 -0
  87. package/dist/models/index.js +4 -0
  88. package/dist/models/index.js.map +1 -0
  89. package/dist/models/pricing.d.ts +25 -0
  90. package/dist/models/pricing.d.ts.map +1 -0
  91. package/dist/models/pricing.js +96 -0
  92. package/dist/models/pricing.js.map +1 -0
  93. package/dist/models/registry.d.ts +34 -0
  94. package/dist/models/registry.d.ts.map +1 -0
  95. package/dist/models/registry.js +109 -0
  96. package/dist/models/registry.js.map +1 -0
  97. package/dist/models/token-tracker.d.ts +40 -0
  98. package/dist/models/token-tracker.d.ts.map +1 -0
  99. package/dist/models/token-tracker.js +102 -0
  100. package/dist/models/token-tracker.js.map +1 -0
  101. package/dist/scheduler/engine.d.ts +9 -0
  102. package/dist/scheduler/engine.d.ts.map +1 -0
  103. package/dist/scheduler/engine.js +127 -0
  104. package/dist/scheduler/engine.js.map +1 -0
  105. package/dist/skills/index.d.ts +3 -0
  106. package/dist/skills/index.d.ts.map +1 -0
  107. package/dist/skills/index.js +2 -0
  108. package/dist/skills/index.js.map +1 -0
  109. package/dist/skills/store.d.ts +52 -0
  110. package/dist/skills/store.d.ts.map +1 -0
  111. package/dist/skills/store.js +148 -0
  112. package/dist/skills/store.js.map +1 -0
  113. package/dist/squad/agent.d.ts +46 -0
  114. package/dist/squad/agent.d.ts.map +1 -0
  115. package/dist/squad/agent.js +261 -0
  116. package/dist/squad/agent.js.map +1 -0
  117. package/dist/squad/autonomy.d.ts +16 -0
  118. package/dist/squad/autonomy.d.ts.map +1 -0
  119. package/dist/squad/autonomy.js +63 -0
  120. package/dist/squad/autonomy.js.map +1 -0
  121. package/dist/squad/event-bus.d.ts +22 -0
  122. package/dist/squad/event-bus.d.ts.map +1 -0
  123. package/dist/squad/event-bus.js +56 -0
  124. package/dist/squad/event-bus.js.map +1 -0
  125. package/dist/squad/execution/index.d.ts +12 -0
  126. package/dist/squad/execution/index.d.ts.map +1 -0
  127. package/dist/squad/execution/index.js +7 -0
  128. package/dist/squad/execution/index.js.map +1 -0
  129. package/dist/squad/execution/instance.d.ts +40 -0
  130. package/dist/squad/execution/instance.d.ts.map +1 -0
  131. package/dist/squad/execution/instance.js +138 -0
  132. package/dist/squad/execution/instance.js.map +1 -0
  133. package/dist/squad/execution/meeting.d.ts +25 -0
  134. package/dist/squad/execution/meeting.d.ts.map +1 -0
  135. package/dist/squad/execution/meeting.js +140 -0
  136. package/dist/squad/execution/meeting.js.map +1 -0
  137. package/dist/squad/execution/pr.d.ts +15 -0
  138. package/dist/squad/execution/pr.d.ts.map +1 -0
  139. package/dist/squad/execution/pr.js +93 -0
  140. package/dist/squad/execution/pr.js.map +1 -0
  141. package/dist/squad/execution/runner.d.ts +22 -0
  142. package/dist/squad/execution/runner.d.ts.map +1 -0
  143. package/dist/squad/execution/runner.js +68 -0
  144. package/dist/squad/execution/runner.js.map +1 -0
  145. package/dist/squad/execution/tasks.d.ts +11 -0
  146. package/dist/squad/execution/tasks.d.ts.map +1 -0
  147. package/dist/squad/execution/tasks.js +85 -0
  148. package/dist/squad/execution/tasks.js.map +1 -0
  149. package/dist/squad/execution/worktree.d.ts +26 -0
  150. package/dist/squad/execution/worktree.d.ts.map +1 -0
  151. package/dist/squad/execution/worktree.js +111 -0
  152. package/dist/squad/execution/worktree.js.map +1 -0
  153. package/dist/squad/hiring.d.ts +32 -0
  154. package/dist/squad/hiring.d.ts.map +1 -0
  155. package/dist/squad/hiring.js +200 -0
  156. package/dist/squad/hiring.js.map +1 -0
  157. package/dist/squad/index.d.ts +8 -0
  158. package/dist/squad/index.d.ts.map +1 -0
  159. package/dist/squad/index.js +6 -0
  160. package/dist/squad/index.js.map +1 -0
  161. package/dist/squad/manager.d.ts +48 -0
  162. package/dist/squad/manager.d.ts.map +1 -0
  163. package/dist/squad/manager.js +274 -0
  164. package/dist/squad/manager.js.map +1 -0
  165. package/dist/squad/name-generator.d.ts +16 -0
  166. package/dist/squad/name-generator.d.ts.map +1 -0
  167. package/dist/squad/name-generator.js +113 -0
  168. package/dist/squad/name-generator.js.map +1 -0
  169. package/dist/squad/roles/templates.d.ts +5 -0
  170. package/dist/squad/roles/templates.d.ts.map +1 -0
  171. package/dist/squad/roles/templates.js +102 -0
  172. package/dist/squad/roles/templates.js.map +1 -0
  173. package/dist/squad/skill-parser.d.ts +36 -0
  174. package/dist/squad/skill-parser.d.ts.map +1 -0
  175. package/dist/squad/skill-parser.js +83 -0
  176. package/dist/squad/skill-parser.js.map +1 -0
  177. package/dist/squad/source-resolver.d.ts +20 -0
  178. package/dist/squad/source-resolver.d.ts.map +1 -0
  179. package/dist/squad/source-resolver.js +52 -0
  180. package/dist/squad/source-resolver.js.map +1 -0
  181. package/dist/store/activity.d.ts +43 -0
  182. package/dist/store/activity.d.ts.map +1 -0
  183. package/dist/store/activity.js +131 -0
  184. package/dist/store/activity.js.map +1 -0
  185. package/dist/store/db.d.ts +5 -0
  186. package/dist/store/db.d.ts.map +1 -0
  187. package/dist/store/db.js +209 -248
  188. package/dist/store/db.js.map +1 -0
  189. package/dist/store/inbox.d.ts +53 -0
  190. package/dist/store/inbox.d.ts.map +1 -0
  191. package/dist/store/inbox.js +151 -0
  192. package/dist/store/inbox.js.map +1 -0
  193. package/dist/store/schedules.d.ts +53 -0
  194. package/dist/store/schedules.d.ts.map +1 -0
  195. package/dist/store/schedules.js +149 -54
  196. package/dist/store/schedules.js.map +1 -0
  197. package/dist/wiki/index.d.ts +3 -0
  198. package/dist/wiki/index.d.ts.map +1 -0
  199. package/dist/wiki/index.js +2 -0
  200. package/dist/wiki/index.js.map +1 -0
  201. package/dist/wiki/store.d.ts +49 -0
  202. package/dist/wiki/store.d.ts.map +1 -0
  203. package/dist/wiki/store.js +115 -0
  204. package/dist/wiki/store.js.map +1 -0
  205. package/package.json +52 -59
  206. package/src/api/middleware/auth.ts +76 -0
  207. package/src/api/notifications.ts +122 -0
  208. package/src/api/routes/activity.ts +29 -0
  209. package/src/api/routes/attachments.ts +93 -0
  210. package/src/api/routes/config.ts +115 -0
  211. package/src/api/routes/conversations.ts +87 -0
  212. package/src/api/routes/health.ts +18 -0
  213. package/src/api/routes/inbox.ts +98 -0
  214. package/src/api/routes/schedules.ts +121 -0
  215. package/src/api/routes/skills.ts +105 -0
  216. package/src/api/routes/squads.ts +145 -0
  217. package/src/api/routes/usage.ts +57 -0
  218. package/src/api/routes/wiki.ts +49 -0
  219. package/src/api/server.ts +186 -0
  220. package/src/config.ts +3 -0
  221. package/src/copilot/client.ts +42 -0
  222. package/src/copilot/health-monitor.ts +85 -0
  223. package/src/copilot/orchestrator.ts +222 -0
  224. package/src/copilot/tools.ts +707 -0
  225. package/src/index.ts +112 -0
  226. package/src/logging/logger.ts +26 -0
  227. package/src/models/index.ts +11 -0
  228. package/src/models/pricing.ts +121 -0
  229. package/src/models/registry.ts +131 -0
  230. package/src/models/token-tracker.ts +151 -0
  231. package/src/scheduler/engine.ts +146 -0
  232. package/src/skills/index.ts +13 -0
  233. package/src/skills/store.ts +188 -0
  234. package/src/squad/agent.ts +326 -0
  235. package/src/squad/autonomy.ts +78 -0
  236. package/src/squad/event-bus.ts +71 -0
  237. package/src/squad/execution/index.ts +17 -0
  238. package/src/squad/execution/instance.ts +186 -0
  239. package/src/squad/execution/meeting.ts +191 -0
  240. package/src/squad/execution/pr.ts +127 -0
  241. package/src/squad/execution/runner.ts +97 -0
  242. package/src/squad/execution/tasks.ts +111 -0
  243. package/src/squad/execution/worktree.ts +138 -0
  244. package/src/squad/hiring.ts +222 -0
  245. package/src/squad/index.ts +17 -0
  246. package/src/squad/manager.ts +337 -0
  247. package/src/squad/name-generator.ts +135 -0
  248. package/src/squad/roles/templates.ts +104 -0
  249. package/src/squad/skill-parser.ts +120 -0
  250. package/src/squad/source-resolver.ts +57 -0
  251. package/src/store/activity.ts +176 -0
  252. package/src/store/db.ts +237 -0
  253. package/src/store/inbox.ts +199 -0
  254. package/src/store/schedules.ts +199 -0
  255. package/src/wiki/index.ts +12 -0
  256. package/src/wiki/store.ts +139 -0
  257. package/tsconfig.json +9 -0
  258. package/LICENSE +0 -21
  259. package/README.md +0 -333
  260. package/dist/api/auth.js +0 -46
  261. package/dist/chat/attachments.js +0 -112
  262. package/dist/copilot/agents.js +0 -309
  263. package/dist/copilot/ceremonies.js +0 -174
  264. package/dist/copilot/gh-token.js +0 -64
  265. package/dist/copilot/io-scheduler.js +0 -79
  266. package/dist/copilot/model-router.js +0 -114
  267. package/dist/copilot/scheduler.js +0 -88
  268. package/dist/copilot/skills.js +0 -252
  269. package/dist/copilot/specialist-runner.js +0 -191
  270. package/dist/copilot/squad-tools.js +0 -258
  271. package/dist/copilot/system-message.js +0 -86
  272. package/dist/copilot/token-tracker.js +0 -98
  273. package/dist/copilot/trigger-schedule.js +0 -33
  274. package/dist/daemon.js +0 -67
  275. package/dist/logging.js +0 -27
  276. package/dist/mcp/config.js +0 -29
  277. package/dist/mcp/index.js +0 -3
  278. package/dist/mcp/registry.js +0 -42
  279. package/dist/notify.js +0 -25
  280. package/dist/paths.js +0 -17
  281. package/dist/setup.js +0 -35
  282. package/dist/store/agent-events.js +0 -19
  283. package/dist/store/audit-log.js +0 -71
  284. package/dist/store/conversations.js +0 -164
  285. package/dist/store/feed.js +0 -44
  286. package/dist/store/instances.js +0 -75
  287. package/dist/store/squad-colors.js +0 -23
  288. package/dist/store/squads.js +0 -60
  289. package/dist/store/tasks.js +0 -78
  290. package/dist/store/token-usage.js +0 -94
  291. package/dist/telegram/bot.js +0 -41
  292. package/dist/telegram/handlers.js +0 -42
  293. package/dist/watchdog.js +0 -37
  294. package/dist/wiki/backlinks.js +0 -51
  295. package/dist/wiki/fs.js +0 -108
  296. package/dist/wiki/search.js +0 -47
  297. package/web-dist/assets/AuditLogView-BzfjNXBT.js +0 -6
  298. package/web-dist/assets/ChatView-BdMukPKG.js +0 -1
  299. package/web-dist/assets/FeedView-BfPIabGr.js +0 -6
  300. package/web-dist/assets/HistoryView-BmEEk3Rs.js +0 -1
  301. package/web-dist/assets/LoginView-D7LrkeX7.js +0 -1
  302. package/web-dist/assets/McpView-BAP_ah3T.js +0 -1
  303. package/web-dist/assets/SchedulesView-CAtsUPCZ.js +0 -6
  304. package/web-dist/assets/SettingsView-BovjWZDa.js +0 -1
  305. package/web-dist/assets/SkillsView-DQSMM5LN.js +0 -16
  306. package/web-dist/assets/SquadDetailView-DBscu0m2.js +0 -26
  307. package/web-dist/assets/SquadHealthView-D686BuQo.js +0 -11
  308. package/web-dist/assets/SquadsView-AzMht2NJ.js +0 -6
  309. package/web-dist/assets/ToggleSwitch.vue_vue_type_script_setup_true_lang-DtShZAjW.js +0 -1
  310. package/web-dist/assets/UsageView-DiVn97aI.js +0 -16
  311. package/web-dist/assets/WikiView-Cn7KipkZ.js +0 -26
  312. package/web-dist/assets/api-D4mHJ3u0.js +0 -1
  313. package/web-dist/assets/arrow-left-D_qUNUWW.js +0 -6
  314. package/web-dist/assets/git-branch-DOM-orcl.js +0 -6
  315. package/web-dist/assets/index-Bo83B1LR.css +0 -1
  316. package/web-dist/assets/index-ELvnkQjd.js +0 -273
  317. package/web-dist/assets/pencil-CFsi7ufI.js +0 -6
  318. package/web-dist/assets/plus-BAzlGFd_.js +0 -6
  319. package/web-dist/assets/save-BmgCYJ1g.js +0 -6
  320. package/web-dist/assets/search-CS9zSIeW.js +0 -6
  321. package/web-dist/assets/squad-colors-B8B_Y-lz.js +0 -1
  322. package/web-dist/assets/trash-2-DLveUEsd.js +0 -6
  323. package/web-dist/assets/triangle-alert-lj4I30rL.js +0 -6
  324. package/web-dist/assets/x-CjXR97Fa.js +0 -6
  325. package/web-dist/favicon.svg +0 -10
  326. package/web-dist/index.html +0 -14
  327. package/web-dist/logo.svg +0 -10
@@ -0,0 +1,42 @@
1
+ import { CopilotClient } from '@github/copilot-sdk';
2
+ import type { Logger } from 'pino';
3
+ import { createChildLogger } from '../logging/logger.js';
4
+
5
+ let client: CopilotClient | undefined;
6
+ let logger: Logger;
7
+
8
+ function getLogger(): Logger {
9
+ if (!logger) {
10
+ logger = createChildLogger('copilot-client');
11
+ }
12
+ return logger;
13
+ }
14
+
15
+ export async function getClient(): Promise<CopilotClient> {
16
+ if (!client) {
17
+ client = new CopilotClient();
18
+ await client.start();
19
+ getLogger().info('Copilot client started');
20
+ }
21
+ return client;
22
+ }
23
+
24
+ export async function resetClient(): Promise<void> {
25
+ if (client) {
26
+ getLogger().warn('Resetting Copilot client');
27
+ try {
28
+ await client.stop();
29
+ } catch (err) {
30
+ getLogger().error({ err }, 'Error stopping client during reset');
31
+ }
32
+ client = undefined;
33
+ }
34
+ }
35
+
36
+ export async function stopClient(): Promise<void> {
37
+ if (client) {
38
+ await client.stop();
39
+ client = undefined;
40
+ getLogger().info('Copilot client stopped');
41
+ }
42
+ }
@@ -0,0 +1,85 @@
1
+ import { createChildLogger } from '../logging/logger.js';
2
+ import { getClient, resetClient } from './client.js';
3
+
4
+ const logger = () => createChildLogger('health-monitor');
5
+
6
+ let healthCheckInterval: ReturnType<typeof setInterval> | null = null;
7
+ let startTime: number = Date.now();
8
+
9
+ export interface HealthStatus {
10
+ status: 'healthy' | 'degraded' | 'unhealthy';
11
+ uptime: number;
12
+ copilotConnected: boolean;
13
+ lastCheck: Date;
14
+ }
15
+
16
+ let lastStatus: HealthStatus = {
17
+ status: 'healthy',
18
+ uptime: 0,
19
+ copilotConnected: false,
20
+ lastCheck: new Date(),
21
+ };
22
+
23
+ /**
24
+ * Start periodic health monitoring of the Copilot SDK connection.
25
+ * Attempts reconnect if connection is lost.
26
+ */
27
+ export function startHealthMonitor(intervalMs = 30_000): void {
28
+ startTime = Date.now();
29
+
30
+ healthCheckInterval = setInterval(async () => {
31
+ await checkHealth();
32
+ }, intervalMs);
33
+
34
+ // Initial check
35
+ checkHealth();
36
+ }
37
+
38
+ export function stopHealthMonitor(): void {
39
+ if (healthCheckInterval) {
40
+ clearInterval(healthCheckInterval);
41
+ healthCheckInterval = null;
42
+ }
43
+ }
44
+
45
+ export function getHealthStatus(): HealthStatus {
46
+ return {
47
+ ...lastStatus,
48
+ uptime: Math.floor((Date.now() - startTime) / 1000),
49
+ };
50
+ }
51
+
52
+ async function checkHealth(): Promise<void> {
53
+ const log = logger();
54
+
55
+ try {
56
+ // Verify we can get the client (it auto-starts if needed)
57
+ const client = await getClient();
58
+ lastStatus = {
59
+ status: 'healthy',
60
+ uptime: Math.floor((Date.now() - startTime) / 1000),
61
+ copilotConnected: true,
62
+ lastCheck: new Date(),
63
+ };
64
+ } catch (err) {
65
+ log.warn({ err }, 'Health check failed — Copilot client unavailable');
66
+ lastStatus = {
67
+ status: 'unhealthy',
68
+ uptime: Math.floor((Date.now() - startTime) / 1000),
69
+ copilotConnected: false,
70
+ lastCheck: new Date(),
71
+ };
72
+
73
+ // Attempt reconnect
74
+ try {
75
+ log.info('Attempting Copilot client reconnect...');
76
+ await resetClient();
77
+ await getClient();
78
+ log.info('Copilot client reconnected successfully');
79
+ lastStatus.status = 'healthy';
80
+ lastStatus.copilotConnected = true;
81
+ } catch (reconnectErr) {
82
+ log.error({ err: reconnectErr }, 'Reconnect failed');
83
+ }
84
+ }
85
+ }
@@ -0,0 +1,222 @@
1
+ import { approveAll } from '@github/copilot-sdk';
2
+ import type { IOConfig } from '../config.js';
3
+ import { createChildLogger } from '../logging/logger.js';
4
+ import { getActiveSkillsContent } from '../skills/index.js';
5
+ import { listSquads } from '../squad/manager.js';
6
+ import { getDatabase } from '../store/db.js';
7
+ import { getOrchestratorScopes, getPageListing } from '../wiki/index.js';
8
+ import { getClient } from './client.js';
9
+ import { createOrchestratorTools } from './tools.js';
10
+
11
+ type Session = Awaited<ReturnType<Awaited<ReturnType<typeof getClient>>['createSession']>>;
12
+
13
+ let logger: ReturnType<typeof createChildLogger>;
14
+
15
+ let session: Session | undefined;
16
+ let sessionId: string | undefined;
17
+
18
+ interface QueuedMessage {
19
+ prompt: string;
20
+ source?: 'tui' | 'telegram' | 'web';
21
+ onDelta: (accumulated: string, done: boolean) => void;
22
+ resolve: (value: string) => void;
23
+ reject: (reason: unknown) => void;
24
+ }
25
+
26
+ const messageQueue: QueuedMessage[] = [];
27
+ let processing = false;
28
+
29
+ const SYSTEM_MESSAGE_BASE = `You are IO, an AI orchestrator daemon. You help users manage their software projects through intelligent conversation and by coordinating specialized agent squads.
30
+
31
+ ## Your Capabilities
32
+ - Answer general questions directly
33
+ - Manage squads: create, monitor, and coordinate teams of AI agents for specific projects
34
+ - Delegate project-specific work to the appropriate squad's team lead
35
+ - Track token usage and costs across all squads
36
+ - Manage the inbox: squads send you deliverables and questions that need user attention
37
+
38
+ ## Routing Rules
39
+ - If the user's message relates to a project that has an assigned squad, ALWAYS delegate to that squad using the delegate_to_squad tool
40
+ - If the user asks about squad status, use the appropriate squad tools
41
+ - For general questions unrelated to any squad's project, answer directly
42
+ - NEVER answer project-specific questions yourself if a squad exists for that project
43
+
44
+ ## Inbox Rules
45
+ - When a squad has a pending question, proactively tell the user about it
46
+ - Use list_inbox to check for unread items when the user asks about notifications or inbox
47
+ - When the user answers a squad's question, use respond_to_inbox to deliver their response and unblock the squad
48
+ - Summarize deliverables in a friendly, readable way when presenting them to the user
49
+ `;
50
+
51
+ /**
52
+ * Build the system message with current squad registry context.
53
+ */
54
+ async function buildSystemMessage(): Promise<string> {
55
+ try {
56
+ const squads = await listSquads();
57
+ const wikiListing = getPageListing(getOrchestratorScopes());
58
+ const skillsContent = await getActiveSkillsContent('orchestrator');
59
+
60
+ const wikiSection = `\n## Wiki Knowledge\n${wikiListing}\n\nUse read_wiki to access page content. Use write_wiki to record important knowledge.\n`;
61
+
62
+ if (squads.length === 0) {
63
+ return `${SYSTEM_MESSAGE_BASE}\n## Active Squads\n(No squads currently active)${wikiSection}${skillsContent}`;
64
+ }
65
+
66
+ const squadList = squads
67
+ .map(
68
+ (s) =>
69
+ `- **${s.name}**: project at \`${s.projectPath}\`${s.repoUrl ? ` (${s.repoUrl})` : ''} [autonomy: ${s.autonomyTier}]`,
70
+ )
71
+ .join('\n');
72
+
73
+ return `${SYSTEM_MESSAGE_BASE}\n## Active Squads\n${squadList}\n\nWhen a user's message mentions any of the above projects (by name, path, or related topic), delegate to the corresponding squad.${wikiSection}${skillsContent}`;
74
+ } catch {
75
+ return `${SYSTEM_MESSAGE_BASE}\n## Active Squads\n(Unable to load squad registry)\n`;
76
+ }
77
+ }
78
+
79
+ export async function initOrchestrator(config: IOConfig): Promise<void> {
80
+ logger = createChildLogger('orchestrator');
81
+ const client = await getClient();
82
+
83
+ const systemMessage = await buildSystemMessage();
84
+
85
+ const sessionOptions = {
86
+ model: config.defaultModel,
87
+ streaming: true,
88
+ tools: createOrchestratorTools(),
89
+ systemMessage: { mode: 'replace' as const, content: systemMessage },
90
+ onPermissionRequest: approveAll,
91
+ infiniteSessions: {
92
+ enabled: true,
93
+ backgroundCompactionThreshold: 0.8,
94
+ bufferExhaustionThreshold: 0.95,
95
+ },
96
+ };
97
+
98
+ // Try to resume existing session
99
+ const savedSessionId = await getSavedSessionId();
100
+ if (savedSessionId) {
101
+ try {
102
+ session = await client.resumeSession(savedSessionId, sessionOptions);
103
+ sessionId = savedSessionId;
104
+ logger.info({ sessionId }, 'Resumed orchestrator session');
105
+ return;
106
+ } catch (err) {
107
+ logger.warn({ err, sessionId: savedSessionId }, 'Failed to resume session, creating new one');
108
+ }
109
+ }
110
+
111
+ // Create new session
112
+ session = await client.createSession(sessionOptions);
113
+ sessionId = session.sessionId;
114
+ await saveSessionId(sessionId);
115
+ logger.info({ sessionId }, 'Created new orchestrator session');
116
+ }
117
+
118
+ export function sendMessage(
119
+ prompt: string,
120
+ source: 'tui' | 'telegram' | 'web',
121
+ onDelta: (accumulated: string, done: boolean) => void,
122
+ ): Promise<string> {
123
+ return new Promise((resolve, reject) => {
124
+ messageQueue.push({ prompt, source, onDelta, resolve, reject });
125
+ processQueue();
126
+ });
127
+ }
128
+
129
+ async function processQueue(): Promise<void> {
130
+ if (processing || messageQueue.length === 0) return;
131
+ processing = true;
132
+
133
+ while (messageQueue.length > 0) {
134
+ const msg = messageQueue.shift()!;
135
+ try {
136
+ const response = await processMessage(msg);
137
+ msg.resolve(response);
138
+ } catch (err) {
139
+ logger.error({ err }, 'Error processing message');
140
+ msg.reject(err);
141
+ }
142
+ }
143
+
144
+ processing = false;
145
+ }
146
+
147
+ async function processMessage(msg: QueuedMessage): Promise<string> {
148
+ if (!session) {
149
+ throw new Error('Orchestrator session not initialized');
150
+ }
151
+
152
+ let accumulated = '';
153
+
154
+ // Subscribe to streaming deltas
155
+ const unsubDelta = session.on('assistant.message_delta', (event) => {
156
+ accumulated += event.data.deltaContent;
157
+ msg.onDelta(accumulated, false);
158
+ });
159
+
160
+ try {
161
+ const result = await session.sendAndWait(
162
+ { prompt: msg.prompt },
163
+ 600_000, // 10 minute timeout
164
+ );
165
+
166
+ const finalContent = result?.data?.content || accumulated || '(No response)';
167
+ msg.onDelta(finalContent, true);
168
+
169
+ // Persist conversation (fire-and-forget)
170
+ persistConversation(msg.prompt, finalContent, msg.source);
171
+
172
+ return finalContent;
173
+ } finally {
174
+ unsubDelta();
175
+ }
176
+ }
177
+
178
+ export async function destroyOrchestrator(): Promise<void> {
179
+ session = undefined;
180
+ sessionId = undefined;
181
+ }
182
+
183
+ async function getSavedSessionId(): Promise<string | undefined> {
184
+ try {
185
+ const db = getDatabase();
186
+ const result = await db.execute(
187
+ "SELECT value FROM io_state WHERE key = 'orchestrator_session_id'",
188
+ );
189
+ if (result.rows.length > 0) {
190
+ return result.rows[0].value as string;
191
+ }
192
+ return undefined;
193
+ } catch {
194
+ return undefined;
195
+ }
196
+ }
197
+
198
+ async function saveSessionId(id: string): Promise<void> {
199
+ const db = getDatabase();
200
+ await db.execute({
201
+ sql: "INSERT OR REPLACE INTO io_state (key, value) VALUES ('orchestrator_session_id', ?)",
202
+ args: [id],
203
+ });
204
+ }
205
+
206
+ function persistConversation(
207
+ userMessage: string,
208
+ assistantResponse: string,
209
+ source?: string,
210
+ ): void {
211
+ const db = getDatabase();
212
+ const now = new Date().toISOString();
213
+
214
+ db.execute({
215
+ sql: "INSERT INTO conversations (id, role, content, source, created_at) VALUES (?, 'user', ?, ?, ?)",
216
+ args: [crypto.randomUUID(), userMessage, source ?? null, now],
217
+ });
218
+ db.execute({
219
+ sql: "INSERT INTO conversations (id, role, content, source, created_at) VALUES (?, 'assistant', ?, ?, ?)",
220
+ args: [crypto.randomUUID(), assistantResponse, source ?? null, now],
221
+ });
222
+ }