heyio 1.13.0 → 3.0.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 (380) hide show
  1. package/README.md +162 -278
  2. package/dist/api/middleware/auth.d.ts +14 -0
  3. package/dist/api/middleware/auth.d.ts.map +1 -0
  4. package/dist/api/middleware/auth.js +66 -0
  5. package/dist/api/middleware/auth.js.map +1 -0
  6. package/dist/api/notifications.d.ts +14 -0
  7. package/dist/api/notifications.d.ts.map +1 -0
  8. package/dist/api/notifications.js +112 -0
  9. package/dist/api/notifications.js.map +1 -0
  10. package/dist/api/routes/activity.d.ts +3 -0
  11. package/dist/api/routes/activity.d.ts.map +1 -0
  12. package/dist/api/routes/activity.js +28 -0
  13. package/dist/api/routes/activity.js.map +1 -0
  14. package/dist/api/routes/attachments.d.ts +3 -0
  15. package/dist/api/routes/attachments.d.ts.map +1 -0
  16. package/dist/api/routes/attachments.js +83 -0
  17. package/dist/api/routes/attachments.js.map +1 -0
  18. package/dist/api/routes/config.d.ts +3 -0
  19. package/dist/api/routes/config.d.ts.map +1 -0
  20. package/dist/api/routes/config.js +106 -0
  21. package/dist/api/routes/config.js.map +1 -0
  22. package/dist/api/routes/conversations.d.ts +3 -0
  23. package/dist/api/routes/conversations.d.ts.map +1 -0
  24. package/dist/api/routes/conversations.js +69 -0
  25. package/dist/api/routes/conversations.js.map +1 -0
  26. package/dist/api/routes/health.d.ts +3 -0
  27. package/dist/api/routes/health.d.ts.map +1 -0
  28. package/dist/api/routes/health.js +16 -0
  29. package/dist/api/routes/health.js.map +1 -0
  30. package/dist/api/routes/inbox.d.ts +3 -0
  31. package/dist/api/routes/inbox.d.ts.map +1 -0
  32. package/dist/api/routes/inbox.js +88 -0
  33. package/dist/api/routes/inbox.js.map +1 -0
  34. package/dist/api/routes/schedules.d.ts +3 -0
  35. package/dist/api/routes/schedules.d.ts.map +1 -0
  36. package/dist/api/routes/schedules.js +96 -0
  37. package/dist/api/routes/schedules.js.map +1 -0
  38. package/dist/api/routes/skills.d.ts +2 -0
  39. package/dist/api/routes/skills.d.ts.map +1 -0
  40. package/dist/api/routes/skills.js +85 -0
  41. package/dist/api/routes/skills.js.map +1 -0
  42. package/dist/api/routes/squads.d.ts +3 -0
  43. package/dist/api/routes/squads.d.ts.map +1 -0
  44. package/dist/api/routes/squads.js +129 -0
  45. package/dist/api/routes/squads.js.map +1 -0
  46. package/dist/api/routes/usage.d.ts +3 -0
  47. package/dist/api/routes/usage.d.ts.map +1 -0
  48. package/dist/api/routes/usage.js +55 -0
  49. package/dist/api/routes/usage.js.map +1 -0
  50. package/dist/api/routes/wiki.d.ts +2 -0
  51. package/dist/api/routes/wiki.d.ts.map +1 -0
  52. package/dist/api/routes/wiki.js +43 -0
  53. package/dist/api/routes/wiki.js.map +1 -0
  54. package/dist/api/server.d.ts +7 -0
  55. package/dist/api/server.d.ts.map +1 -0
  56. package/dist/api/server.js +136 -634
  57. package/dist/api/server.js.map +1 -0
  58. package/dist/config.d.ts +3 -0
  59. package/dist/config.d.ts.map +1 -0
  60. package/dist/config.js +2 -91
  61. package/dist/config.js.map +1 -0
  62. package/dist/copilot/client.d.ts +5 -0
  63. package/dist/copilot/client.d.ts.map +1 -0
  64. package/dist/copilot/client.js +19 -11
  65. package/dist/copilot/client.js.map +1 -0
  66. package/dist/copilot/health-monitor.d.ts +14 -0
  67. package/dist/copilot/health-monitor.d.ts.map +1 -0
  68. package/dist/copilot/health-monitor.js +70 -0
  69. package/dist/copilot/health-monitor.js.map +1 -0
  70. package/dist/copilot/orchestrator.d.ts +5 -0
  71. package/dist/copilot/orchestrator.d.ts.map +1 -0
  72. package/dist/copilot/orchestrator.js +127 -123
  73. package/dist/copilot/orchestrator.js.map +1 -0
  74. package/dist/copilot/tools.d.ts +49 -0
  75. package/dist/copilot/tools.d.ts.map +1 -0
  76. package/dist/copilot/tools.js +545 -321
  77. package/dist/copilot/tools.js.map +1 -0
  78. package/dist/index.d.ts +3 -0
  79. package/dist/index.d.ts.map +1 -0
  80. package/dist/index.js +82 -26
  81. package/dist/index.js.map +1 -0
  82. package/dist/logging/logger.d.ts +6 -0
  83. package/dist/logging/logger.d.ts.map +1 -0
  84. package/dist/logging/logger.js +21 -0
  85. package/dist/logging/logger.js.map +1 -0
  86. package/dist/models/index.d.ts +6 -0
  87. package/dist/models/index.d.ts.map +1 -0
  88. package/dist/models/index.js +4 -0
  89. package/dist/models/index.js.map +1 -0
  90. package/dist/models/pricing.d.ts +25 -0
  91. package/dist/models/pricing.d.ts.map +1 -0
  92. package/dist/models/pricing.js +96 -0
  93. package/dist/models/pricing.js.map +1 -0
  94. package/dist/models/registry.d.ts +34 -0
  95. package/dist/models/registry.d.ts.map +1 -0
  96. package/dist/models/registry.js +109 -0
  97. package/dist/models/registry.js.map +1 -0
  98. package/dist/models/token-tracker.d.ts +40 -0
  99. package/dist/models/token-tracker.d.ts.map +1 -0
  100. package/dist/models/token-tracker.js +102 -0
  101. package/dist/models/token-tracker.js.map +1 -0
  102. package/dist/scheduler/engine.d.ts +9 -0
  103. package/dist/scheduler/engine.d.ts.map +1 -0
  104. package/dist/scheduler/engine.js +127 -0
  105. package/dist/scheduler/engine.js.map +1 -0
  106. package/dist/skills/index.d.ts +3 -0
  107. package/dist/skills/index.d.ts.map +1 -0
  108. package/dist/skills/index.js +2 -0
  109. package/dist/skills/index.js.map +1 -0
  110. package/dist/skills/store.d.ts +52 -0
  111. package/dist/skills/store.d.ts.map +1 -0
  112. package/dist/skills/store.js +148 -0
  113. package/dist/skills/store.js.map +1 -0
  114. package/dist/squad/agent.d.ts +46 -0
  115. package/dist/squad/agent.d.ts.map +1 -0
  116. package/dist/squad/agent.js +261 -0
  117. package/dist/squad/agent.js.map +1 -0
  118. package/dist/squad/autonomy.d.ts +16 -0
  119. package/dist/squad/autonomy.d.ts.map +1 -0
  120. package/dist/squad/autonomy.js +63 -0
  121. package/dist/squad/autonomy.js.map +1 -0
  122. package/dist/squad/event-bus.d.ts +22 -0
  123. package/dist/squad/event-bus.d.ts.map +1 -0
  124. package/dist/squad/event-bus.js +56 -0
  125. package/dist/squad/event-bus.js.map +1 -0
  126. package/dist/squad/execution/index.d.ts +12 -0
  127. package/dist/squad/execution/index.d.ts.map +1 -0
  128. package/dist/squad/execution/index.js +7 -0
  129. package/dist/squad/execution/index.js.map +1 -0
  130. package/dist/squad/execution/instance.d.ts +40 -0
  131. package/dist/squad/execution/instance.d.ts.map +1 -0
  132. package/dist/squad/execution/instance.js +138 -0
  133. package/dist/squad/execution/instance.js.map +1 -0
  134. package/dist/squad/execution/meeting.d.ts +25 -0
  135. package/dist/squad/execution/meeting.d.ts.map +1 -0
  136. package/dist/squad/execution/meeting.js +140 -0
  137. package/dist/squad/execution/meeting.js.map +1 -0
  138. package/dist/squad/execution/pr.d.ts +15 -0
  139. package/dist/squad/execution/pr.d.ts.map +1 -0
  140. package/dist/squad/execution/pr.js +93 -0
  141. package/dist/squad/execution/pr.js.map +1 -0
  142. package/dist/squad/execution/runner.d.ts +22 -0
  143. package/dist/squad/execution/runner.d.ts.map +1 -0
  144. package/dist/squad/execution/runner.js +68 -0
  145. package/dist/squad/execution/runner.js.map +1 -0
  146. package/dist/squad/execution/tasks.d.ts +11 -0
  147. package/dist/squad/execution/tasks.d.ts.map +1 -0
  148. package/dist/squad/execution/tasks.js +85 -0
  149. package/dist/squad/execution/tasks.js.map +1 -0
  150. package/dist/squad/execution/worktree.d.ts +26 -0
  151. package/dist/squad/execution/worktree.d.ts.map +1 -0
  152. package/dist/squad/execution/worktree.js +111 -0
  153. package/dist/squad/execution/worktree.js.map +1 -0
  154. package/dist/squad/hiring.d.ts +32 -0
  155. package/dist/squad/hiring.d.ts.map +1 -0
  156. package/dist/squad/hiring.js +200 -0
  157. package/dist/squad/hiring.js.map +1 -0
  158. package/dist/squad/index.d.ts +8 -0
  159. package/dist/squad/index.d.ts.map +1 -0
  160. package/dist/squad/index.js +6 -0
  161. package/dist/squad/index.js.map +1 -0
  162. package/dist/squad/manager.d.ts +48 -0
  163. package/dist/squad/manager.d.ts.map +1 -0
  164. package/dist/squad/manager.js +274 -0
  165. package/dist/squad/manager.js.map +1 -0
  166. package/dist/squad/name-generator.d.ts +16 -0
  167. package/dist/squad/name-generator.d.ts.map +1 -0
  168. package/dist/squad/name-generator.js +113 -0
  169. package/dist/squad/name-generator.js.map +1 -0
  170. package/dist/squad/roles/templates.d.ts +5 -0
  171. package/dist/squad/roles/templates.d.ts.map +1 -0
  172. package/dist/squad/roles/templates.js +102 -0
  173. package/dist/squad/roles/templates.js.map +1 -0
  174. package/dist/squad/skill-parser.d.ts +36 -0
  175. package/dist/squad/skill-parser.d.ts.map +1 -0
  176. package/dist/squad/skill-parser.js +83 -0
  177. package/dist/squad/skill-parser.js.map +1 -0
  178. package/dist/squad/source-resolver.d.ts +20 -0
  179. package/dist/squad/source-resolver.d.ts.map +1 -0
  180. package/dist/squad/source-resolver.js +52 -0
  181. package/dist/squad/source-resolver.js.map +1 -0
  182. package/dist/store/activity.d.ts +43 -0
  183. package/dist/store/activity.d.ts.map +1 -0
  184. package/dist/store/activity.js +131 -0
  185. package/dist/store/activity.js.map +1 -0
  186. package/dist/store/db.d.ts +5 -0
  187. package/dist/store/db.d.ts.map +1 -0
  188. package/dist/store/db.js +209 -248
  189. package/dist/store/db.js.map +1 -0
  190. package/dist/store/inbox.d.ts +53 -0
  191. package/dist/store/inbox.d.ts.map +1 -0
  192. package/dist/store/inbox.js +151 -0
  193. package/dist/store/inbox.js.map +1 -0
  194. package/dist/store/schedules.d.ts +53 -0
  195. package/dist/store/schedules.d.ts.map +1 -0
  196. package/dist/store/schedules.js +149 -54
  197. package/dist/store/schedules.js.map +1 -0
  198. package/dist/wiki/index.d.ts +3 -0
  199. package/dist/wiki/index.d.ts.map +1 -0
  200. package/dist/wiki/index.js +2 -0
  201. package/dist/wiki/index.js.map +1 -0
  202. package/dist/wiki/store.d.ts +49 -0
  203. package/dist/wiki/store.d.ts.map +1 -0
  204. package/dist/wiki/store.js +115 -0
  205. package/dist/wiki/store.js.map +1 -0
  206. package/node_modules/@io/shared/dist/config.d.ts +25 -0
  207. package/node_modules/@io/shared/dist/config.d.ts.map +1 -0
  208. package/node_modules/@io/shared/dist/config.js +47 -0
  209. package/node_modules/@io/shared/dist/config.js.map +1 -0
  210. package/node_modules/@io/shared/dist/constants.d.ts +13 -0
  211. package/node_modules/@io/shared/dist/constants.d.ts.map +1 -0
  212. package/node_modules/@io/shared/dist/constants.js +34 -0
  213. package/node_modules/@io/shared/dist/constants.js.map +1 -0
  214. package/node_modules/@io/shared/dist/index.d.ts +11 -0
  215. package/node_modules/@io/shared/dist/index.d.ts.map +1 -0
  216. package/node_modules/@io/shared/dist/index.js +3 -0
  217. package/node_modules/@io/shared/dist/index.js.map +1 -0
  218. package/node_modules/@io/shared/dist/types/agents.d.ts +3 -0
  219. package/node_modules/@io/shared/dist/types/agents.d.ts.map +1 -0
  220. package/node_modules/@io/shared/dist/types/agents.js +2 -0
  221. package/node_modules/@io/shared/dist/types/agents.js.map +1 -0
  222. package/node_modules/@io/shared/dist/types/api.d.ts +33 -0
  223. package/node_modules/@io/shared/dist/types/api.d.ts.map +1 -0
  224. package/node_modules/@io/shared/dist/types/api.js +2 -0
  225. package/node_modules/@io/shared/dist/types/api.js.map +1 -0
  226. package/node_modules/@io/shared/dist/types/attachments.d.ts +10 -0
  227. package/node_modules/@io/shared/dist/types/attachments.d.ts.map +1 -0
  228. package/node_modules/@io/shared/dist/types/attachments.js +2 -0
  229. package/node_modules/@io/shared/dist/types/attachments.js.map +1 -0
  230. package/node_modules/@io/shared/dist/types/events.d.ts +44 -0
  231. package/node_modules/@io/shared/dist/types/events.d.ts.map +1 -0
  232. package/node_modules/@io/shared/dist/types/events.js +2 -0
  233. package/node_modules/@io/shared/dist/types/events.js.map +1 -0
  234. package/node_modules/@io/shared/dist/types/messages.d.ts +15 -0
  235. package/node_modules/@io/shared/dist/types/messages.d.ts.map +1 -0
  236. package/node_modules/@io/shared/dist/types/messages.js +2 -0
  237. package/node_modules/@io/shared/dist/types/messages.js.map +1 -0
  238. package/node_modules/@io/shared/dist/types/squads.d.ts +43 -0
  239. package/node_modules/@io/shared/dist/types/squads.d.ts.map +1 -0
  240. package/node_modules/@io/shared/dist/types/squads.js +2 -0
  241. package/node_modules/@io/shared/dist/types/squads.js.map +1 -0
  242. package/node_modules/@io/shared/dist/types/tokens.d.ts +19 -0
  243. package/node_modules/@io/shared/dist/types/tokens.d.ts.map +1 -0
  244. package/node_modules/@io/shared/dist/types/tokens.js +2 -0
  245. package/node_modules/@io/shared/dist/types/tokens.js.map +1 -0
  246. package/node_modules/@io/shared/package.json +18 -0
  247. package/node_modules/@io/shared/src/config.ts +74 -0
  248. package/node_modules/@io/shared/src/constants.ts +36 -0
  249. package/node_modules/@io/shared/src/index.ts +37 -0
  250. package/node_modules/@io/shared/src/types/agents.ts +3 -0
  251. package/node_modules/@io/shared/src/types/api.ts +35 -0
  252. package/node_modules/@io/shared/src/types/attachments.ts +9 -0
  253. package/node_modules/@io/shared/src/types/events.ts +81 -0
  254. package/node_modules/@io/shared/src/types/messages.ts +15 -0
  255. package/node_modules/@io/shared/src/types/squads.ts +53 -0
  256. package/node_modules/@io/shared/src/types/tokens.ts +19 -0
  257. package/node_modules/@io/shared/tsconfig.json +9 -0
  258. package/node_modules/@io/shared/tsconfig.tsbuildinfo +1 -0
  259. package/package.json +56 -59
  260. package/src/api/middleware/auth.ts +76 -0
  261. package/src/api/notifications.ts +122 -0
  262. package/src/api/routes/activity.ts +29 -0
  263. package/src/api/routes/attachments.ts +93 -0
  264. package/src/api/routes/config.ts +115 -0
  265. package/src/api/routes/conversations.ts +87 -0
  266. package/src/api/routes/health.ts +18 -0
  267. package/src/api/routes/inbox.ts +98 -0
  268. package/src/api/routes/schedules.ts +121 -0
  269. package/src/api/routes/skills.ts +105 -0
  270. package/src/api/routes/squads.ts +145 -0
  271. package/src/api/routes/usage.ts +57 -0
  272. package/src/api/routes/wiki.ts +49 -0
  273. package/src/api/server.ts +186 -0
  274. package/src/config.ts +3 -0
  275. package/src/copilot/client.ts +42 -0
  276. package/src/copilot/health-monitor.ts +85 -0
  277. package/src/copilot/orchestrator.ts +222 -0
  278. package/src/copilot/tools.ts +707 -0
  279. package/src/index.ts +112 -0
  280. package/src/logging/logger.ts +26 -0
  281. package/src/models/index.ts +11 -0
  282. package/src/models/pricing.ts +121 -0
  283. package/src/models/registry.ts +131 -0
  284. package/src/models/token-tracker.ts +151 -0
  285. package/src/scheduler/engine.ts +146 -0
  286. package/src/skills/index.ts +13 -0
  287. package/src/skills/store.ts +188 -0
  288. package/src/squad/agent.ts +326 -0
  289. package/src/squad/autonomy.ts +78 -0
  290. package/src/squad/event-bus.ts +71 -0
  291. package/src/squad/execution/index.ts +17 -0
  292. package/src/squad/execution/instance.ts +186 -0
  293. package/src/squad/execution/meeting.ts +191 -0
  294. package/src/squad/execution/pr.ts +127 -0
  295. package/src/squad/execution/runner.ts +97 -0
  296. package/src/squad/execution/tasks.ts +111 -0
  297. package/src/squad/execution/worktree.ts +138 -0
  298. package/src/squad/hiring.ts +222 -0
  299. package/src/squad/index.ts +17 -0
  300. package/src/squad/manager.ts +337 -0
  301. package/src/squad/name-generator.ts +135 -0
  302. package/src/squad/roles/templates.ts +104 -0
  303. package/src/squad/skill-parser.ts +120 -0
  304. package/src/squad/source-resolver.ts +57 -0
  305. package/src/store/activity.ts +176 -0
  306. package/src/store/db.ts +237 -0
  307. package/src/store/inbox.ts +199 -0
  308. package/src/store/schedules.ts +199 -0
  309. package/src/wiki/index.ts +12 -0
  310. package/src/wiki/store.ts +139 -0
  311. package/tsconfig.json +9 -0
  312. package/LICENSE +0 -21
  313. package/dist/api/auth.js +0 -46
  314. package/dist/chat/attachments.js +0 -112
  315. package/dist/copilot/agents.js +0 -309
  316. package/dist/copilot/ceremonies.js +0 -174
  317. package/dist/copilot/gh-token.js +0 -64
  318. package/dist/copilot/io-scheduler.js +0 -79
  319. package/dist/copilot/model-router.js +0 -114
  320. package/dist/copilot/scheduler.js +0 -88
  321. package/dist/copilot/skills.js +0 -252
  322. package/dist/copilot/specialist-runner.js +0 -191
  323. package/dist/copilot/squad-tools.js +0 -258
  324. package/dist/copilot/system-message.js +0 -86
  325. package/dist/copilot/token-tracker.js +0 -98
  326. package/dist/copilot/trigger-schedule.js +0 -33
  327. package/dist/daemon.js +0 -67
  328. package/dist/logging.js +0 -27
  329. package/dist/mcp/config.js +0 -29
  330. package/dist/mcp/index.js +0 -3
  331. package/dist/mcp/registry.js +0 -42
  332. package/dist/notify.js +0 -25
  333. package/dist/paths.js +0 -17
  334. package/dist/setup.js +0 -35
  335. package/dist/store/agent-events.js +0 -19
  336. package/dist/store/audit-log.js +0 -71
  337. package/dist/store/conversations.js +0 -164
  338. package/dist/store/feed.js +0 -44
  339. package/dist/store/instances.js +0 -75
  340. package/dist/store/squad-colors.js +0 -23
  341. package/dist/store/squads.js +0 -60
  342. package/dist/store/tasks.js +0 -78
  343. package/dist/store/token-usage.js +0 -94
  344. package/dist/telegram/bot.js +0 -41
  345. package/dist/telegram/handlers.js +0 -42
  346. package/dist/watchdog.js +0 -37
  347. package/dist/wiki/backlinks.js +0 -51
  348. package/dist/wiki/fs.js +0 -108
  349. package/dist/wiki/search.js +0 -47
  350. package/web-dist/assets/AuditLogView-BzfjNXBT.js +0 -6
  351. package/web-dist/assets/ChatView-BdMukPKG.js +0 -1
  352. package/web-dist/assets/FeedView-BfPIabGr.js +0 -6
  353. package/web-dist/assets/HistoryView-BmEEk3Rs.js +0 -1
  354. package/web-dist/assets/LoginView-D7LrkeX7.js +0 -1
  355. package/web-dist/assets/McpView-BAP_ah3T.js +0 -1
  356. package/web-dist/assets/SchedulesView-CAtsUPCZ.js +0 -6
  357. package/web-dist/assets/SettingsView-BovjWZDa.js +0 -1
  358. package/web-dist/assets/SkillsView-DQSMM5LN.js +0 -16
  359. package/web-dist/assets/SquadDetailView-DBscu0m2.js +0 -26
  360. package/web-dist/assets/SquadHealthView-D686BuQo.js +0 -11
  361. package/web-dist/assets/SquadsView-AzMht2NJ.js +0 -6
  362. package/web-dist/assets/ToggleSwitch.vue_vue_type_script_setup_true_lang-DtShZAjW.js +0 -1
  363. package/web-dist/assets/UsageView-DiVn97aI.js +0 -16
  364. package/web-dist/assets/WikiView-Cn7KipkZ.js +0 -26
  365. package/web-dist/assets/api-D4mHJ3u0.js +0 -1
  366. package/web-dist/assets/arrow-left-D_qUNUWW.js +0 -6
  367. package/web-dist/assets/git-branch-DOM-orcl.js +0 -6
  368. package/web-dist/assets/index-Bo83B1LR.css +0 -1
  369. package/web-dist/assets/index-ELvnkQjd.js +0 -273
  370. package/web-dist/assets/pencil-CFsi7ufI.js +0 -6
  371. package/web-dist/assets/plus-BAzlGFd_.js +0 -6
  372. package/web-dist/assets/save-BmgCYJ1g.js +0 -6
  373. package/web-dist/assets/search-CS9zSIeW.js +0 -6
  374. package/web-dist/assets/squad-colors-B8B_Y-lz.js +0 -1
  375. package/web-dist/assets/trash-2-DLveUEsd.js +0 -6
  376. package/web-dist/assets/triangle-alert-lj4I30rL.js +0 -6
  377. package/web-dist/assets/x-CjXR97Fa.js +0 -6
  378. package/web-dist/favicon.svg +0 -10
  379. package/web-dist/index.html +0 -14
  380. package/web-dist/logo.svg +0 -10
@@ -1,402 +1,626 @@
1
- import { z } from "zod";
2
- import { defineTool } from "@github/copilot-sdk";
3
- import { addAuditEntry } from "../store/audit-log.js";
4
- export function createTools() {
1
+ import { defineTool } from '@github/copilot-sdk';
2
+ import { z } from 'zod';
3
+ import { activateSkill, deactivateSkill, getActiveSkills, installSkillFromUrl, listInstalledSkills, removeSkill, } from '../skills/index.js';
4
+ import { runInstance } from '../squad/execution/runner.js';
5
+ import { hireSquad } from '../squad/hiring.js';
6
+ import { bootSquad, delegateToSquad, getSquadByName, getSquadMembers, getSquadRuntime, listSquads, rethemeSquad, } from '../squad/manager.js';
7
+ import { listInboxEntries, resolveInboxEntry } from '../store/inbox.js';
8
+ import { createSchedule, deleteSchedule, listSchedules } from '../store/schedules.js';
9
+ import { getOrchestratorScopes, getPageListing, listWikiPages, readWikiPage, searchWiki, writeWikiPage, } from '../wiki/index.js';
10
+ export function createOrchestratorTools() {
5
11
  return [
6
- // --- Wiki Tools ---
7
- defineTool("wiki_read", {
8
- description: "Read a wiki page by path (relative to ~/.io/wiki/pages/)",
9
- parameters: z.object({
10
- path: z.string().describe("Page path relative to pages/ (e.g., 'notes/todo.md')"),
11
- }),
12
- handler: async ({ path }) => {
13
- const { readPage } = await import("../wiki/fs.js");
14
- return await readPage(path);
15
- },
16
- }),
17
- defineTool("wiki_write", {
18
- description: "Write or update a wiki page",
19
- parameters: z.object({
20
- path: z.string().describe("Page path relative to pages/"),
21
- content: z.string().describe("Markdown content to write"),
22
- }),
23
- handler: async ({ path, content }) => {
24
- const { writePage } = await import("../wiki/fs.js");
25
- await writePage(path, content);
26
- return `Page saved: ${path}`;
27
- },
28
- }),
29
- defineTool("wiki_list", {
30
- description: "List all wiki pages",
31
- parameters: z.object({}),
12
+ defineTool('list_squads', {
13
+ description: 'List all active squads and their current status. Use this when the user asks about their teams or projects.',
14
+ parameters: z.object({}).strict(),
32
15
  handler: async () => {
33
- const { listPages } = await import("../wiki/fs.js");
34
- return await listPages();
35
- },
36
- }),
37
- defineTool("wiki_search", {
38
- description: "Search wiki pages by keyword",
39
- parameters: z.object({
40
- query: z.string().describe("Search query"),
41
- }),
42
- handler: async ({ query }) => {
43
- const { searchPages } = await import("../wiki/search.js");
44
- return await searchPages(query);
16
+ const squads = await listSquads();
17
+ if (squads.length === 0) {
18
+ return {
19
+ textResultForLlm: JSON.stringify({
20
+ squads: [],
21
+ message: 'No squads currently active.',
22
+ }),
23
+ resultType: 'success',
24
+ };
25
+ }
26
+ const summary = await Promise.all(squads.map(async (s) => {
27
+ const members = await getSquadMembers(s.id);
28
+ return {
29
+ name: s.name,
30
+ project: s.projectPath,
31
+ universe: s.universe,
32
+ autonomy: s.autonomyTier,
33
+ members: members.map((m) => `${m.displayName} (${m.roleName})`),
34
+ status: s.status,
35
+ };
36
+ }));
37
+ return {
38
+ textResultForLlm: JSON.stringify({ squads: summary }),
39
+ resultType: 'success',
40
+ };
45
41
  },
46
42
  }),
47
- defineTool("wiki_delete", {
48
- description: "Delete a wiki page",
43
+ defineTool('get_squad_status', {
44
+ description: 'Get the detailed status of a specific squad including active instances, team members, and recent activity.',
49
45
  parameters: z.object({
50
- path: z.string().describe("Page path relative to pages/"),
46
+ squadName: z.string().describe('The name of the squad to check'),
51
47
  }),
52
- handler: async ({ path }) => {
53
- const { deletePage } = await import("../wiki/fs.js");
54
- await deletePage(path);
55
- return `Page deleted: ${path}`;
48
+ handler: async (args) => {
49
+ const squad = await getSquadByName(args.squadName);
50
+ if (!squad) {
51
+ return {
52
+ textResultForLlm: JSON.stringify({ error: `Squad '${args.squadName}' not found.` }),
53
+ resultType: 'success',
54
+ };
55
+ }
56
+ const members = await getSquadMembers(squad.id);
57
+ return {
58
+ textResultForLlm: JSON.stringify({
59
+ squad: {
60
+ name: squad.name,
61
+ project: squad.projectPath,
62
+ repo: squad.repoUrl,
63
+ universe: squad.universe,
64
+ autonomy: squad.autonomyTier,
65
+ status: squad.status,
66
+ createdAt: squad.createdAt.toISOString(),
67
+ },
68
+ members: members.map((m) => ({
69
+ name: m.displayName,
70
+ role: m.roleName,
71
+ veto: m.isVetoMember,
72
+ tools: m.toolsAllowed,
73
+ })),
74
+ }),
75
+ resultType: 'success',
76
+ };
56
77
  },
57
78
  }),
58
- defineTool("wiki_backlinks", {
59
- description: "Find all wiki pages that link to the given page",
79
+ defineTool('hire_squad', {
80
+ description: 'Create a new squad for a project. Provide a GitHub repo URL and the project will be cloned automatically to ~/.io/source/{owner}/{repo}. Analyzes the project and recommends team composition. Each squad member gets a character name from a pop-culture universe.',
60
81
  parameters: z.object({
61
- path: z.string().describe("Page path relative to pages/ (e.g., 'notes/todo.md')"),
82
+ repoUrl: z.string().describe('GitHub repository URL (e.g. https://github.com/owner/repo)'),
83
+ name: z.string().optional().describe('Name for the squad (auto-generated if omitted)'),
84
+ universe: z
85
+ .string()
86
+ .optional()
87
+ .describe('Pop-culture universe for member names (a-team, marvel, star-wars, lord-of-the-rings, star-trek, firefly). Random if omitted.'),
62
88
  }),
63
- handler: async ({ path }) => {
64
- const { getBacklinks } = await import("../wiki/backlinks.js");
65
- return await getBacklinks(path);
89
+ handler: async (args) => {
90
+ try {
91
+ const { ensureCloned } = await import('../squad/source-resolver.js');
92
+ const projectPath = ensureCloned(args.repoUrl);
93
+ const result = await hireSquad({
94
+ projectPath,
95
+ repoUrl: args.repoUrl,
96
+ name: args.name,
97
+ universe: args.universe,
98
+ });
99
+ return {
100
+ textResultForLlm: JSON.stringify({
101
+ message: `Squad '${args.name ?? result.analysis.name}' hired successfully!`,
102
+ squadId: result.squadId,
103
+ projectPath,
104
+ universe: result.universe,
105
+ analysis: result.analysis,
106
+ members: result.members,
107
+ }),
108
+ resultType: 'success',
109
+ };
110
+ }
111
+ catch (err) {
112
+ return {
113
+ textResultForLlm: JSON.stringify({
114
+ error: `Failed to hire squad: ${err instanceof Error ? err.message : String(err)}`,
115
+ }),
116
+ resultType: 'success',
117
+ };
118
+ }
66
119
  },
67
120
  }),
68
- // --- Squad Tools ---
69
- defineTool("squad_create", {
70
- description: "Create a new project squad. Research the chosen universe to assign character names — never hardcode.",
121
+ defineTool('retheme_squad', {
122
+ description: "Change a squad's pop-culture universe. Generates new character names and personas for all members from the specified universe.",
71
123
  parameters: z.object({
72
- name: z.string().describe("Squad name (e.g., 'Project Alpha')"),
124
+ squadName: z.string().describe('Name of the squad to retheme'),
73
125
  universe: z
74
126
  .string()
75
- .describe("Pop culture universe theme (e.g., 'A-Team', 'Transformers', 'ThunderCats')"),
76
- repo_url: z.string().optional().describe("Git repository URL for the project"),
127
+ .describe('New pop-culture universe (e.g. "The Office", "Star Wars", "Breaking Bad")'),
77
128
  }),
78
- handler: async ({ name, universe, repo_url }) => {
79
- const { createSquad } = await import("../store/squads.js");
80
- const squad = createSquad(name, universe, repo_url);
81
- let cloneMsg = "";
82
- // Copy squad wiki templates into the new squad's wiki directory
83
- const { copySquadTemplates } = await import("../wiki/fs.js");
84
- await copySquadTemplates(squad.slug);
85
- if (repo_url) {
86
- const { exec } = await import("node:child_process");
87
- const { promisify } = await import("node:util");
88
- const { existsSync, mkdirSync } = await import("node:fs");
89
- const { join } = await import("node:path");
90
- const { PATHS } = await import("../paths.js");
91
- const execAsync = promisify(exec);
92
- // Extract owner/repo from URL (supports https and git@ formats)
93
- const match = repo_url.match(/[/:]([^/]+)\/([^/.]+?)(?:\.git)?$/);
94
- if (match) {
95
- const [, owner, repo] = match;
96
- const sourceDir = join(PATHS.source, owner, repo);
97
- if (!existsSync(sourceDir)) {
98
- const parentDir = join(PATHS.source, owner);
99
- if (!existsSync(parentDir))
100
- mkdirSync(parentDir, { recursive: true });
101
- try {
102
- await execAsync(`git clone ${repo_url} ${sourceDir}`, {
103
- timeout: 120_000,
104
- });
105
- cloneMsg = ` Repo cloned to ~/.io/source/${owner}/${repo}.`;
106
- }
107
- catch (err) {
108
- cloneMsg = ` (Clone failed: ${err.stderr?.trim() || err.message})`;
109
- }
110
- }
111
- else {
112
- cloneMsg = ` Repo already exists at ~/.io/source/${owner}/${repo}.`;
113
- }
129
+ handler: async (args) => {
130
+ try {
131
+ const squad = await getSquadByName(args.squadName);
132
+ if (!squad) {
133
+ return {
134
+ textResultForLlm: JSON.stringify({ error: `Squad '${args.squadName}' not found.` }),
135
+ resultType: 'success',
136
+ };
114
137
  }
138
+ const members = await getSquadMembers(squad.id);
139
+ const roles = members.map((m) => m.roleName);
140
+ const { generateSquadNames } = await import('../squad/name-generator.js');
141
+ const generated = await generateSquadNames(roles, args.universe);
142
+ await rethemeSquad(squad.id, generated.universe, generated.assignments);
143
+ return {
144
+ textResultForLlm: JSON.stringify({
145
+ message: `Squad '${args.squadName}' rethemed to ${generated.universe}!`,
146
+ members: generated.assignments.map((a) => `${a.displayName} (${a.role})`),
147
+ }),
148
+ resultType: 'success',
149
+ };
150
+ }
151
+ catch (err) {
152
+ return {
153
+ textResultForLlm: JSON.stringify({
154
+ error: `Failed to retheme squad: ${err instanceof Error ? err.message : String(err)}`,
155
+ }),
156
+ resultType: 'success',
157
+ };
115
158
  }
116
- const msg = `Squad "${name}" created with universe "${universe}". ID: ${squad.id}, Slug: ${squad.slug}. Wiki path: ~/.io/wiki/squads/${squad.slug}/${cloneMsg}`;
117
- addAuditEntry("squad_created", `Squad "${name}" created (universe: ${universe})`, { squad_id: squad.id, name, universe, repo_url }, { squad_id: squad.id });
118
- return msg;
119
159
  },
120
160
  }),
121
- defineTool("squad_add_agent", {
122
- description: "Add a specialist agent to a squad",
161
+ defineTool('delegate_to_squad', {
162
+ description: "Delegate a message or task to a specific squad's team lead. Use this when the user's message relates to a project that has an assigned squad.",
123
163
  parameters: z.object({
124
- squad_id: z.string().describe("Squad ID"),
125
- character_name: z.string().describe("Character name from the squad's universe"),
126
- role_title: z.string().describe("Specialist role (e.g., 'Vue 3 Frontend Developer')"),
127
- persona: z.string().optional().describe("Personality/work style description"),
128
- is_lead: z.boolean().optional().describe("Is this the team lead?"),
129
- is_qa: z.boolean().optional().describe("Is this a QA reviewer?"),
130
- is_test: z.boolean().optional().describe("Is this a test/quality specialist?"),
164
+ squadName: z.string().describe('Name of the squad to delegate to'),
165
+ message: z.string().describe('The full message or task to delegate'),
131
166
  }),
132
- handler: async ({ squad_id, character_name, role_title, persona, is_lead, is_qa, is_test }) => {
133
- const { addAgent } = await import("../store/squads.js");
134
- const agent = addAgent(squad_id, {
135
- character_name,
136
- role_title,
137
- persona: persona ?? "",
138
- is_lead: is_lead ?? false,
139
- is_qa: is_qa ?? false,
140
- is_test: is_test ?? false,
141
- });
142
- return `Agent "${character_name}" (${role_title}) added to squad. ID: ${agent.id}`;
143
- },
144
- }),
145
- defineTool("squad_list", {
146
- description: "List all squads and their agents",
147
- parameters: z.object({}),
148
- handler: async () => {
149
- const { listSquads } = await import("../store/squads.js");
150
- return listSquads();
167
+ handler: async (args) => {
168
+ const squad = await getSquadByName(args.squadName);
169
+ if (!squad) {
170
+ return {
171
+ textResultForLlm: JSON.stringify({
172
+ error: `Squad '${args.squadName}' not found.`,
173
+ }),
174
+ resultType: 'success',
175
+ };
176
+ }
177
+ try {
178
+ // Boot squad if not already running
179
+ if (!getSquadRuntime(squad.id)) {
180
+ await bootSquad(squad);
181
+ }
182
+ const response = await delegateToSquad(squad.id, args.message);
183
+ return {
184
+ textResultForLlm: JSON.stringify({
185
+ delegatedTo: args.squadName,
186
+ teamLeadResponse: response,
187
+ }),
188
+ resultType: 'success',
189
+ };
190
+ }
191
+ catch (err) {
192
+ return {
193
+ textResultForLlm: JSON.stringify({
194
+ error: `Failed to delegate: ${err instanceof Error ? err.message : String(err)}`,
195
+ }),
196
+ resultType: 'success',
197
+ };
198
+ }
151
199
  },
152
200
  }),
153
- defineTool("squad_delegate", {
154
- description: "Delegate a task to a squad's team lead. The lead will break it down and route to specialists. Use this for direct execution without a planning meeting.",
201
+ defineTool('run_squad_instance', {
202
+ description: 'Start a new work instance for a squad. This kicks off the full lifecycle: meeting task execution PR creation. Use when the user asks a squad to work on something specific.',
155
203
  parameters: z.object({
156
- squad_id: z.string().describe("Squad ID"),
157
- task: z.string().describe("Detailed task description"),
158
- instance_id: z.string().optional().describe("Instance ID (for parallel work)"),
204
+ squadName: z.string().describe('Name of the squad'),
205
+ objective: z.string().describe('What the squad should accomplish'),
206
+ issueRef: z.string().optional().describe('GitHub issue reference (e.g., #42)'),
159
207
  }),
160
- handler: async ({ squad_id, task, instance_id }) => {
161
- const { delegateTask } = await import("./agents.js");
162
- const { getActiveMessageAttachments } = await import("./orchestrator.js");
163
- const attachments = getActiveMessageAttachments();
164
- addAuditEntry("task_delegated", `Task delegated to squad ${squad_id}: ${task.slice(0, 200)}`, {
165
- squad_id,
166
- task: task.slice(0, 1000),
167
- instance_id,
168
- attachments: attachments.map((attachment) => ({
169
- name: attachment.name,
170
- mimeType: attachment.mimeType,
171
- size: attachment.size,
172
- })),
173
- }, { squad_id });
174
- // Fire-and-forget: start delegation in background so the orchestrator can respond immediately
175
- delegateTask(squad_id, task, instance_id, attachments).catch((err) => {
176
- const errMsg = err instanceof Error ? err.message : "Unknown error";
177
- addAuditEntry("task_delegation_error", `Background delegation failed: ${errMsg}`, { squad_id, error: errMsg }, { squad_id });
178
- });
179
- return `Task delegated to squad ${squad_id}. The squad is now working on it in the background. You will be notified via the inbox when work is complete.`;
208
+ handler: async (args) => {
209
+ const squad = await getSquadByName(args.squadName);
210
+ if (!squad) {
211
+ return {
212
+ textResultForLlm: JSON.stringify({ error: `Squad '${args.squadName}' not found.` }),
213
+ resultType: 'success',
214
+ };
215
+ }
216
+ try {
217
+ const result = await runInstance({
218
+ squad,
219
+ objective: args.objective,
220
+ issueRef: args.issueRef,
221
+ });
222
+ return {
223
+ textResultForLlm: JSON.stringify({
224
+ instanceId: result.instanceId,
225
+ success: result.success,
226
+ pr: result.pr ? { url: result.pr.url, number: result.pr.number } : null,
227
+ error: result.error,
228
+ }),
229
+ resultType: 'success',
230
+ };
231
+ }
232
+ catch (err) {
233
+ return {
234
+ textResultForLlm: JSON.stringify({
235
+ error: `Failed to run instance: ${err instanceof Error ? err.message : String(err)}`,
236
+ }),
237
+ resultType: 'success',
238
+ };
239
+ }
180
240
  },
181
241
  }),
182
- defineTool("squad_meeting", {
183
- description: "Trigger a planning meeting for a squad. All relevant specialists provide input before work begins. Use this for complex multi-agent tasks where team input improves the plan. Set execute_after=true to start work immediately after planning, or false to post the plan to the feed for user review.",
242
+ defineTool('list_inbox', {
243
+ description: "List unread inbox entries from squads. Shows deliverables and pending questions that need the user's attention.",
184
244
  parameters: z.object({
185
- squad_id: z.string().describe("Squad ID"),
186
- task: z.string().describe("Detailed task description for the team to plan"),
187
- execute_after: z
188
- .boolean()
189
- .describe("If true, execute the plan immediately after the meeting. If false, post plan to feed and wait for user approval."),
245
+ status: z
246
+ .enum(['unread', 'read', 'resolved'])
247
+ .optional()
248
+ .describe('Filter by status (default: unread)'),
190
249
  }),
191
- handler: async ({ squad_id, task, execute_after }) => {
192
- const { squadMeeting } = await import("./ceremonies.js");
193
- const { getActiveMessageAttachments } = await import("./orchestrator.js");
194
- const attachments = getActiveMessageAttachments();
195
- addAuditEntry("squad_meeting", `Planning meeting started for squad ${squad_id}: ${task.slice(0, 200)}`, {
196
- squad_id,
197
- task: task.slice(0, 1000),
198
- execute_after,
199
- attachments: attachments.map((attachment) => ({
200
- name: attachment.name,
201
- mimeType: attachment.mimeType,
202
- size: attachment.size,
203
- })),
204
- }, { squad_id });
205
- // Fire-and-forget: start meeting in background so the orchestrator can respond immediately
206
- squadMeeting(squad_id, task, execute_after, attachments).catch((err) => {
207
- const errMsg = err instanceof Error ? err.message : "Unknown error";
208
- addAuditEntry("squad_meeting_error", `Background meeting failed: ${errMsg}`, { squad_id, error: errMsg }, { squad_id });
250
+ handler: async (args) => {
251
+ const entries = await listInboxEntries({
252
+ status: args.status ?? 'unread',
253
+ limit: 20,
209
254
  });
210
- return `Planning meeting started for squad ${squad_id}. The squad is discussing the task in the background.${execute_after ? " Work will begin automatically after planning." : " The plan will be posted to the feed for your review."}`;
255
+ if (entries.length === 0) {
256
+ return {
257
+ textResultForLlm: JSON.stringify({ entries: [], message: 'No inbox entries.' }),
258
+ resultType: 'success',
259
+ };
260
+ }
261
+ const summary = entries.map((e) => ({
262
+ id: e.id,
263
+ squad: e.squadId,
264
+ kind: e.kind,
265
+ title: e.title,
266
+ content: e.content.slice(0, 500),
267
+ status: e.status,
268
+ createdAt: e.createdAt,
269
+ }));
270
+ return {
271
+ textResultForLlm: JSON.stringify({ entries: summary }),
272
+ resultType: 'success',
273
+ };
211
274
  },
212
275
  }),
213
- defineTool("squad_task_status", {
214
- description: "Check the status of tasks for a squad",
276
+ defineTool('respond_to_inbox', {
277
+ description: "Respond to an inbox question from a squad. Use this when the user provides an answer to a squad's pending question. This unblocks the squad so it can continue working.",
215
278
  parameters: z.object({
216
- squad_id: z.string().describe("Squad ID"),
279
+ entryId: z.string().describe('The inbox entry ID to respond to'),
280
+ response: z.string().describe("The user's response to the squad's question"),
217
281
  }),
218
- handler: async ({ squad_id }) => {
219
- const { getTasksForSquad } = await import("../store/tasks.js");
220
- return getTasksForSquad(squad_id);
282
+ handler: async (args) => {
283
+ try {
284
+ const unblocked = await resolveInboxEntry(args.entryId, args.response);
285
+ return {
286
+ textResultForLlm: JSON.stringify({
287
+ resolved: true,
288
+ squadUnblocked: unblocked,
289
+ message: unblocked
290
+ ? 'Response delivered — squad has been unblocked and will continue working.'
291
+ : 'Response recorded (squad was not actively waiting).',
292
+ }),
293
+ resultType: 'success',
294
+ };
295
+ }
296
+ catch (err) {
297
+ return {
298
+ textResultForLlm: JSON.stringify({
299
+ error: `Failed to respond: ${err instanceof Error ? err.message : String(err)}`,
300
+ }),
301
+ resultType: 'success',
302
+ };
303
+ }
221
304
  },
222
305
  }),
223
- defineTool("squad_instance_create", {
224
- description: "Create a new parallel instance (worktree) for a squad. Max 3 per squad.",
306
+ defineTool('create_schedule', {
307
+ description: 'Create a cron-based schedule that triggers a squad or the orchestrator with a predefined prompt at specified times. Use standard cron syntax (e.g., "0 9 * * 1-5" for weekdays at 9am).',
225
308
  parameters: z.object({
226
- squad_id: z.string().describe("Squad ID"),
227
- branch: z.string().describe("Branch name for the worktree"),
309
+ name: z.string().describe('Human-readable name for the schedule (e.g., "Daily Standup")'),
310
+ targetType: z
311
+ .enum(['squad', 'orchestrator'])
312
+ .describe('Whether to target a squad or the orchestrator'),
313
+ targetId: z.string().optional().describe('Squad name (required if targetType is "squad")'),
314
+ cron: z.string().describe('Cron expression (e.g., "0 9 * * 1-5" for weekdays at 9am)'),
315
+ prompt: z.string().describe('The prompt/message to send when the schedule fires'),
228
316
  }),
229
- handler: async ({ squad_id, branch }) => {
230
- const { createInstance } = await import("../store/instances.js");
231
- const instance = await createInstance(squad_id, branch);
232
- return `Instance created: ${instance.id} on branch ${branch}`;
317
+ handler: async (args) => {
318
+ try {
319
+ // Validate squad exists if targeting a squad
320
+ if (args.targetType === 'squad') {
321
+ if (!args.targetId) {
322
+ return {
323
+ textResultForLlm: JSON.stringify({
324
+ error: 'targetId (squad name) is required for squad schedules',
325
+ }),
326
+ resultType: 'success',
327
+ };
328
+ }
329
+ const squad = await getSquadByName(args.targetId);
330
+ if (!squad) {
331
+ return {
332
+ textResultForLlm: JSON.stringify({ error: `Squad '${args.targetId}' not found` }),
333
+ resultType: 'success',
334
+ };
335
+ }
336
+ args.targetId = squad.id;
337
+ }
338
+ const schedule = await createSchedule({
339
+ name: args.name,
340
+ targetType: args.targetType,
341
+ targetId: args.targetId,
342
+ cron: args.cron,
343
+ prompt: args.prompt,
344
+ });
345
+ return {
346
+ textResultForLlm: JSON.stringify({
347
+ created: true,
348
+ schedule: {
349
+ id: schedule.id,
350
+ name: schedule.name,
351
+ cron: schedule.cron,
352
+ nextRun: schedule.nextRun,
353
+ },
354
+ }),
355
+ resultType: 'success',
356
+ };
357
+ }
358
+ catch (err) {
359
+ return {
360
+ textResultForLlm: JSON.stringify({
361
+ error: `Failed to create schedule: ${err instanceof Error ? err.message : String(err)}`,
362
+ }),
363
+ resultType: 'success',
364
+ };
365
+ }
233
366
  },
234
367
  }),
235
- defineTool("squad_instance_destroy", {
236
- description: "Destroy a squad instance and clean up its worktree",
237
- parameters: z.object({
238
- instance_id: z.string().describe("Instance ID"),
239
- }),
240
- handler: async ({ instance_id }) => {
241
- const { destroyInstance } = await import("../store/instances.js");
242
- await destroyInstance(instance_id);
243
- return `Instance ${instance_id} destroyed.`;
368
+ defineTool('list_schedules', {
369
+ description: 'List all configured schedules (cron-based automations).',
370
+ parameters: z.object({}).strict(),
371
+ handler: async () => {
372
+ const schedules = await listSchedules();
373
+ if (schedules.length === 0) {
374
+ return {
375
+ textResultForLlm: JSON.stringify({
376
+ schedules: [],
377
+ message: 'No schedules configured.',
378
+ }),
379
+ resultType: 'success',
380
+ };
381
+ }
382
+ const summary = schedules.map((s) => ({
383
+ id: s.id,
384
+ name: s.name,
385
+ targetType: s.targetType,
386
+ targetId: s.targetId,
387
+ cron: s.cron,
388
+ prompt: s.prompt.slice(0, 100),
389
+ enabled: s.enabled,
390
+ nextRun: s.nextRun,
391
+ lastRun: s.lastRun,
392
+ }));
393
+ return {
394
+ textResultForLlm: JSON.stringify({ schedules: summary }),
395
+ resultType: 'success',
396
+ };
244
397
  },
245
398
  }),
246
- defineTool("squad_remove_agent", {
247
- description: "Remove an agent from a squad",
399
+ defineTool('delete_schedule', {
400
+ description: 'Delete a schedule by ID. Use list_schedules first to find the ID.',
248
401
  parameters: z.object({
249
- agent_id: z.string().describe("Agent ID to remove"),
402
+ scheduleId: z.string().describe('The ID of the schedule to delete'),
250
403
  }),
251
- handler: async ({ agent_id }) => {
252
- const { removeAgent } = await import("../store/squads.js");
253
- removeAgent(agent_id);
254
- return `Agent ${agent_id} removed.`;
404
+ handler: async (args) => {
405
+ try {
406
+ await deleteSchedule(args.scheduleId);
407
+ return {
408
+ textResultForLlm: JSON.stringify({ deleted: true, scheduleId: args.scheduleId }),
409
+ resultType: 'success',
410
+ };
411
+ }
412
+ catch (err) {
413
+ return {
414
+ textResultForLlm: JSON.stringify({
415
+ error: `Failed to delete: ${err instanceof Error ? err.message : String(err)}`,
416
+ }),
417
+ resultType: 'success',
418
+ };
419
+ }
255
420
  },
256
421
  }),
257
- defineTool("squad_delete", {
258
- description: "Delete an entire squad and all its agents, tasks, and instances",
422
+ defineTool('read_wiki', {
423
+ description: 'Read from the wiki knowledge base. Call with no pageName to list available pages, or with a pageName to read its content. You have access to IO-level and Shared wiki scopes.',
259
424
  parameters: z.object({
260
- squad_id: z.string().describe("Squad ID to delete"),
425
+ scope: z.enum(['io', 'shared']).describe('Which wiki scope to read from'),
426
+ pageName: z
427
+ .string()
428
+ .optional()
429
+ .describe('Page name to read (omit to list all pages in scope)'),
261
430
  }),
262
- handler: async ({ squad_id }) => {
263
- const { deleteSquad } = await import("../store/squads.js");
264
- deleteSquad(squad_id);
265
- return `Squad ${squad_id} deleted.`;
431
+ handler: async (args) => {
432
+ if (!args.pageName) {
433
+ const pages = listWikiPages(args.scope);
434
+ return {
435
+ textResultForLlm: JSON.stringify({
436
+ scope: args.scope,
437
+ pages: pages.length > 0 ? pages : '(empty)',
438
+ }),
439
+ resultType: 'success',
440
+ };
441
+ }
442
+ const page = readWikiPage(args.scope, args.pageName);
443
+ if (!page) {
444
+ return {
445
+ textResultForLlm: JSON.stringify({
446
+ error: `Page '${args.pageName}' not found in ${args.scope} wiki`,
447
+ }),
448
+ resultType: 'success',
449
+ };
450
+ }
451
+ return {
452
+ textResultForLlm: JSON.stringify({
453
+ scope: page.scope,
454
+ name: page.name,
455
+ content: page.content,
456
+ }),
457
+ resultType: 'success',
458
+ };
266
459
  },
267
460
  }),
268
- // --- Feed Tools ---
269
- defineTool("feed_post", {
270
- description: "Post a deliverable to the unified feed/inbox",
461
+ defineTool('write_wiki', {
462
+ description: 'Write a page to the wiki knowledge base. Provide the full page content (read existing first and merge if updating). You can write to IO-level and Shared scopes.',
271
463
  parameters: z.object({
272
- source: z.string().describe("Source identifier (e.g., 'orchestrator', 'squad-alpha')"),
273
- title: z.string().describe("Title of the deliverable"),
274
- content: z.string().describe("Full content (markdown supported)"),
464
+ scope: z.enum(['io', 'shared']).describe('Which wiki scope to write to'),
465
+ pageName: z
466
+ .string()
467
+ .describe('Page name (no .md extension, e.g., "preferences" or "routing-conventions")'),
468
+ content: z.string().describe('Full markdown content for the page'),
275
469
  }),
276
- handler: async ({ source, title, content }) => {
277
- const { postFeedItem } = await import("../store/feed.js");
278
- const item = postFeedItem(source, title, content);
279
- return `Posted to feed: "${title}" (ID: ${item.id})`;
470
+ handler: async (args) => {
471
+ writeWikiPage(args.scope, args.pageName, args.content);
472
+ return {
473
+ textResultForLlm: JSON.stringify({
474
+ written: true,
475
+ scope: args.scope,
476
+ pageName: args.pageName,
477
+ }),
478
+ resultType: 'success',
479
+ };
280
480
  },
281
481
  }),
282
- defineTool("feed_list", {
283
- description: "List feed/inbox items. Can filter by unread or source.",
482
+ defineTool('search_wiki', {
483
+ description: 'Search across wiki pages by keyword. Searches IO-level and Shared scopes.',
284
484
  parameters: z.object({
285
- unread_only: z.boolean().optional().describe("Only show unread items"),
286
- source: z.string().optional().describe("Filter by source"),
287
- limit: z.number().optional().describe("Max items to return (default 20)"),
485
+ keyword: z.string().describe('Keyword or phrase to search for'),
288
486
  }),
289
- handler: async ({ unread_only, source, limit }) => {
290
- const { getFeedItems } = await import("../store/feed.js");
291
- return getFeedItems({ unreadOnly: unread_only, source, limit: limit ?? 20 });
292
- },
293
- }),
294
- // --- MCP Tools ---
295
- defineTool("mcp_list_servers", {
296
- description: "List configured MCP servers and their status",
297
- parameters: z.object({}),
298
- handler: async () => {
299
- const { listServers } = await import("../mcp/registry.js");
300
- return listServers();
487
+ handler: async (args) => {
488
+ const results = searchWiki(args.keyword, getOrchestratorScopes());
489
+ if (results.length === 0) {
490
+ return {
491
+ textResultForLlm: JSON.stringify({ results: [], message: 'No matches found.' }),
492
+ resultType: 'success',
493
+ };
494
+ }
495
+ return {
496
+ textResultForLlm: JSON.stringify({ results }),
497
+ resultType: 'success',
498
+ };
301
499
  },
302
500
  }),
303
- // --- Schedule Tools ---
304
- defineTool("schedule_create", {
305
- description: "Create a cron-based schedule",
501
+ defineTool('install_skill', {
502
+ description: 'Install a skill from a URL (raw GitHub URL to a SKILL.md file). Skills extend IO or squad capabilities with additional instructions and behaviors.',
306
503
  parameters: z.object({
307
- type: z.enum(["squad", "io"]).describe("Schedule type"),
308
- cron: z.string().describe("Cron expression (e.g., '0 9 * * 1-5')"),
309
- squad_id: z.string().describe("Target squad ID"),
310
- agenda: z
504
+ name: z
311
505
  .string()
312
- .optional()
313
- .describe("Agenda type for squad schedules (triage, prioritize, ideation, or custom)"),
314
- prompt: z.string().optional().describe("Prompt text for the schedule"),
506
+ .describe('Name for the skill (kebab-case, e.g., "tdd-workflow" or "code-review")'),
507
+ url: z
508
+ .string()
509
+ .describe('URL to the raw SKILL.md content (e.g., raw.githubusercontent.com/.../SKILL.md)'),
315
510
  }),
316
- handler: async ({ type, cron, squad_id, agenda, prompt }) => {
317
- const { createSchedule } = await import("../store/schedules.js");
318
- const schedule = createSchedule({ type, cron, squad_id, agenda, prompt });
319
- return `Schedule created: ${schedule.id}`;
511
+ handler: async (args) => {
512
+ try {
513
+ const skill = await installSkillFromUrl(args.name, args.url);
514
+ return {
515
+ textResultForLlm: JSON.stringify({
516
+ installed: true,
517
+ name: skill.name,
518
+ preview: skill.content.slice(0, 200),
519
+ }),
520
+ resultType: 'success',
521
+ };
522
+ }
523
+ catch (err) {
524
+ return {
525
+ textResultForLlm: JSON.stringify({
526
+ error: `Failed to install: ${err instanceof Error ? err.message : String(err)}`,
527
+ }),
528
+ resultType: 'success',
529
+ };
530
+ }
320
531
  },
321
532
  }),
322
- defineTool("schedule_list", {
323
- description: "List all schedules, optionally filtered by type",
324
- parameters: z.object({
325
- type: z.enum(["squad", "io"]).optional().describe("Filter by schedule type"),
326
- }),
327
- handler: async ({ type }) => {
328
- const { listSchedules } = await import("../store/schedules.js");
329
- return listSchedules(type);
533
+ defineTool('list_skills', {
534
+ description: 'List all installed skills and their activation status.',
535
+ parameters: z.object({}).strict(),
536
+ handler: async () => {
537
+ const installed = listInstalledSkills();
538
+ const orchestratorActivations = await getActiveSkills('orchestrator');
539
+ const summary = installed.map((s) => ({
540
+ name: s.name,
541
+ activatedForOrchestrator: orchestratorActivations.some((a) => a.skillName === s.name),
542
+ preview: s.content.slice(0, 100),
543
+ }));
544
+ return {
545
+ textResultForLlm: JSON.stringify({
546
+ skills: summary.length > 0 ? summary : '(no skills installed)',
547
+ }),
548
+ resultType: 'success',
549
+ };
330
550
  },
331
551
  }),
332
- defineTool("schedule_delete", {
333
- description: "Delete a schedule by ID",
552
+ defineTool('activate_skill', {
553
+ description: 'Activate an installed skill for the orchestrator or a specific squad. Active skills are injected into the system prompt.',
334
554
  parameters: z.object({
335
- id: z.string().describe("Schedule ID to delete"),
555
+ skillName: z.string().describe('Name of the installed skill'),
556
+ targetType: z
557
+ .enum(['orchestrator', 'squad'])
558
+ .describe('Activate for orchestrator or a specific squad'),
559
+ targetId: z.string().optional().describe('Squad name (required if targetType is "squad")'),
336
560
  }),
337
- handler: async ({ id }) => {
338
- const { deleteSchedule } = await import("../store/schedules.js");
339
- deleteSchedule(id);
340
- return `Schedule ${id} deleted.`;
561
+ handler: async (args) => {
562
+ try {
563
+ let resolvedTargetId = args.targetId ?? null;
564
+ if (args.targetType === 'squad' && args.targetId) {
565
+ const squad = await getSquadByName(args.targetId);
566
+ if (!squad) {
567
+ return {
568
+ textResultForLlm: JSON.stringify({ error: `Squad '${args.targetId}' not found` }),
569
+ resultType: 'success',
570
+ };
571
+ }
572
+ resolvedTargetId = squad.id;
573
+ }
574
+ await activateSkill(args.skillName, args.targetType, resolvedTargetId ?? undefined);
575
+ return {
576
+ textResultForLlm: JSON.stringify({
577
+ activated: true,
578
+ skillName: args.skillName,
579
+ target: args.targetType === 'orchestrator' ? 'orchestrator' : args.targetId,
580
+ }),
581
+ resultType: 'success',
582
+ };
583
+ }
584
+ catch (err) {
585
+ return {
586
+ textResultForLlm: JSON.stringify({
587
+ error: `Failed to activate: ${err instanceof Error ? err.message : String(err)}`,
588
+ }),
589
+ resultType: 'success',
590
+ };
591
+ }
341
592
  },
342
593
  }),
343
- defineTool("schedule_update", {
344
- description: "Update an existing schedule's cron, agenda, prompt, or enabled status",
594
+ defineTool('deactivate_skill', {
595
+ description: 'Deactivate a skill (stop injecting it into the system prompt).',
345
596
  parameters: z.object({
346
- id: z.string().describe("Schedule ID to update"),
347
- cron: z.string().optional().describe("New cron expression"),
348
- agenda: z.string().optional().describe("New agenda text"),
349
- prompt: z.string().optional().describe("New prompt text"),
350
- enabled: z.boolean().optional().describe("Enable or disable the schedule"),
597
+ skillName: z.string().describe('Name of the skill to deactivate'),
598
+ targetType: z
599
+ .enum(['orchestrator', 'squad'])
600
+ .describe('Deactivate from orchestrator or a specific squad'),
601
+ targetId: z.string().optional().describe('Squad name (required if targetType is "squad")'),
351
602
  }),
352
- handler: async ({ id, cron, agenda, prompt, enabled }) => {
353
- const { updateSchedule } = await import("../store/schedules.js");
354
- const schedule = updateSchedule(id, { cron, agenda, prompt, enabled });
355
- return `Schedule ${id} updated. Cron: ${schedule.cron}, Enabled: ${!!schedule.enabled}`;
603
+ handler: async (args) => {
604
+ await deactivateSkill(args.skillName, args.targetType, args.targetId ?? undefined);
605
+ return {
606
+ textResultForLlm: JSON.stringify({ deactivated: true, skillName: args.skillName }),
607
+ resultType: 'success',
608
+ };
356
609
  },
357
610
  }),
358
- // --- Shell Tool ---
359
- defineTool("shell_exec", {
360
- description: "Execute a shell command on the host machine. Use for git, gh CLI, file operations, etc. Commands run in the user's environment with their credentials.",
611
+ defineTool('remove_skill', {
612
+ description: 'Uninstall a skill completely (removes files and all activations).',
361
613
  parameters: z.object({
362
- command: z.string().describe("Shell command to execute"),
363
- cwd: z.string().optional().describe("Working directory (defaults to home directory)"),
614
+ skillName: z.string().describe('Name of the skill to remove'),
364
615
  }),
365
- handler: async ({ command, cwd }) => {
366
- const { exec } = await import("node:child_process");
367
- const { promisify } = await import("node:util");
368
- const { homedir } = await import("node:os");
369
- const { getGhToken } = await import("./gh-token.js");
370
- const execAsync = promisify(exec);
371
- // Inject cached GH token for GitHub CLI operations
372
- const shellEnv = { ...process.env, GH_PROMPT_DISABLED: "1" };
373
- const ghToken = getGhToken();
374
- if (ghToken) {
375
- shellEnv.GH_TOKEN = ghToken;
376
- }
377
- try {
378
- const { stdout } = await execAsync(command, {
379
- cwd: cwd ?? homedir(),
380
- timeout: 60_000,
381
- maxBuffer: 1024 * 1024,
382
- env: shellEnv,
383
- });
384
- const output = stdout.trim() || "(no output)";
385
- addAuditEntry("shell_command", `Command: ${command.slice(0, 200)}`, { command, cwd, output: output.slice(0, 500), exit_code: 0 });
386
- return output;
387
- }
388
- catch (err) {
389
- const stderr = err.stderr?.toString().trim() ?? "";
390
- const stdout = err.stdout?.toString().trim() ?? "";
391
- const output = `Error (exit ${err.code}): ${stderr || stdout || err.message}`;
392
- addAuditEntry("shell_command", `Command: ${command.slice(0, 200)}`, { command, cwd, output: output.slice(0, 500), exit_code: err.code ?? 1 });
393
- return output;
394
- }
616
+ handler: async (args) => {
617
+ removeSkill(args.skillName);
618
+ return {
619
+ textResultForLlm: JSON.stringify({ removed: true, skillName: args.skillName }),
620
+ resultType: 'success',
621
+ };
395
622
  },
396
623
  }),
397
- // --- Web Tools ---
398
- // NOTE: web_search and web_fetch are provided by the Copilot SDK as built-in tools.
399
- // Do not define them here to avoid conflicts.
400
624
  ];
401
625
  }
402
626
  //# sourceMappingURL=tools.js.map