heyio 3.0.2 → 3.0.4

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 (65) hide show
  1. package/dist/api/server.js +1 -1
  2. package/dist/api/server.js.map +1 -1
  3. package/dist/index.js +8 -1
  4. package/dist/index.js.map +1 -1
  5. package/dist/logging/logger.d.ts.map +1 -1
  6. package/dist/logging/logger.js +13 -1
  7. package/dist/logging/logger.js.map +1 -1
  8. package/node_modules/@io/shared/package.json +1 -1
  9. package/package.json +7 -2
  10. package/public/assets/index-2RY89H3W.js +336 -0
  11. package/public/assets/index-2RY89H3W.js.map +1 -0
  12. package/public/assets/index-D3cGfBsj.css +1 -0
  13. package/public/index.html +14 -0
  14. package/src/api/middleware/auth.ts +0 -76
  15. package/src/api/notifications.ts +0 -122
  16. package/src/api/routes/activity.ts +0 -29
  17. package/src/api/routes/attachments.ts +0 -93
  18. package/src/api/routes/config.ts +0 -115
  19. package/src/api/routes/conversations.ts +0 -87
  20. package/src/api/routes/health.ts +0 -18
  21. package/src/api/routes/inbox.ts +0 -98
  22. package/src/api/routes/schedules.ts +0 -121
  23. package/src/api/routes/skills.ts +0 -105
  24. package/src/api/routes/squads.ts +0 -145
  25. package/src/api/routes/usage.ts +0 -57
  26. package/src/api/routes/wiki.ts +0 -49
  27. package/src/api/server.ts +0 -186
  28. package/src/config.ts +0 -3
  29. package/src/copilot/client.ts +0 -42
  30. package/src/copilot/health-monitor.ts +0 -85
  31. package/src/copilot/orchestrator.ts +0 -222
  32. package/src/copilot/tools.ts +0 -707
  33. package/src/index.ts +0 -113
  34. package/src/logging/logger.ts +0 -26
  35. package/src/models/index.ts +0 -11
  36. package/src/models/pricing.ts +0 -121
  37. package/src/models/registry.ts +0 -131
  38. package/src/models/token-tracker.ts +0 -151
  39. package/src/scheduler/engine.ts +0 -146
  40. package/src/skills/index.ts +0 -13
  41. package/src/skills/store.ts +0 -188
  42. package/src/squad/agent.ts +0 -326
  43. package/src/squad/autonomy.ts +0 -78
  44. package/src/squad/event-bus.ts +0 -71
  45. package/src/squad/execution/index.ts +0 -17
  46. package/src/squad/execution/instance.ts +0 -186
  47. package/src/squad/execution/meeting.ts +0 -191
  48. package/src/squad/execution/pr.ts +0 -127
  49. package/src/squad/execution/runner.ts +0 -97
  50. package/src/squad/execution/tasks.ts +0 -111
  51. package/src/squad/execution/worktree.ts +0 -138
  52. package/src/squad/hiring.ts +0 -222
  53. package/src/squad/index.ts +0 -17
  54. package/src/squad/manager.ts +0 -337
  55. package/src/squad/name-generator.ts +0 -135
  56. package/src/squad/roles/templates.ts +0 -104
  57. package/src/squad/skill-parser.ts +0 -120
  58. package/src/squad/source-resolver.ts +0 -57
  59. package/src/store/activity.ts +0 -176
  60. package/src/store/db.ts +0 -237
  61. package/src/store/inbox.ts +0 -199
  62. package/src/store/schedules.ts +0 -199
  63. package/src/wiki/index.ts +0 -12
  64. package/src/wiki/store.ts +0 -139
  65. package/tsconfig.json +0 -9
@@ -1,707 +0,0 @@
1
- import { defineTool } from '@github/copilot-sdk';
2
- import { z } from 'zod';
3
- import {
4
- activateSkill,
5
- deactivateSkill,
6
- getActiveSkills,
7
- installSkillFromUrl,
8
- listInstalledSkills,
9
- removeSkill,
10
- } from '../skills/index.js';
11
- import { runInstance } from '../squad/execution/runner.js';
12
- import { hireSquad } from '../squad/hiring.js';
13
- import {
14
- bootSquad,
15
- delegateToSquad,
16
- getSquadByName,
17
- getSquadMembers,
18
- getSquadRuntime,
19
- listSquads,
20
- rethemeSquad,
21
- } from '../squad/manager.js';
22
- import { listInboxEntries, resolveInboxEntry } from '../store/inbox.js';
23
- import { createSchedule, deleteSchedule, listSchedules } from '../store/schedules.js';
24
- import {
25
- getOrchestratorScopes,
26
- getPageListing,
27
- listWikiPages,
28
- readWikiPage,
29
- searchWiki,
30
- writeWikiPage,
31
- } from '../wiki/index.js';
32
-
33
- export function createOrchestratorTools() {
34
- return [
35
- defineTool('list_squads', {
36
- description:
37
- 'List all active squads and their current status. Use this when the user asks about their teams or projects.',
38
- parameters: z.object({}).strict(),
39
- handler: async () => {
40
- const squads = await listSquads();
41
- if (squads.length === 0) {
42
- return {
43
- textResultForLlm: JSON.stringify({
44
- squads: [],
45
- message: 'No squads currently active.',
46
- }),
47
- resultType: 'success' as const,
48
- };
49
- }
50
- const summary = await Promise.all(
51
- squads.map(async (s) => {
52
- const members = await getSquadMembers(s.id);
53
- return {
54
- name: s.name,
55
- project: s.projectPath,
56
- universe: s.universe,
57
- autonomy: s.autonomyTier,
58
- members: members.map((m) => `${m.displayName} (${m.roleName})`),
59
- status: s.status,
60
- };
61
- }),
62
- );
63
- return {
64
- textResultForLlm: JSON.stringify({ squads: summary }),
65
- resultType: 'success' as const,
66
- };
67
- },
68
- }),
69
-
70
- defineTool('get_squad_status', {
71
- description:
72
- 'Get the detailed status of a specific squad including active instances, team members, and recent activity.',
73
- parameters: z.object({
74
- squadName: z.string().describe('The name of the squad to check'),
75
- }),
76
- handler: async (args: { squadName: string }) => {
77
- const squad = await getSquadByName(args.squadName);
78
- if (!squad) {
79
- return {
80
- textResultForLlm: JSON.stringify({ error: `Squad '${args.squadName}' not found.` }),
81
- resultType: 'success' as const,
82
- };
83
- }
84
- const members = await getSquadMembers(squad.id);
85
- return {
86
- textResultForLlm: JSON.stringify({
87
- squad: {
88
- name: squad.name,
89
- project: squad.projectPath,
90
- repo: squad.repoUrl,
91
- universe: squad.universe,
92
- autonomy: squad.autonomyTier,
93
- status: squad.status,
94
- createdAt: squad.createdAt.toISOString(),
95
- },
96
- members: members.map((m) => ({
97
- name: m.displayName,
98
- role: m.roleName,
99
- veto: m.isVetoMember,
100
- tools: m.toolsAllowed,
101
- })),
102
- }),
103
- resultType: 'success' as const,
104
- };
105
- },
106
- }),
107
-
108
- defineTool('hire_squad', {
109
- description:
110
- '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.',
111
- parameters: z.object({
112
- repoUrl: z.string().describe('GitHub repository URL (e.g. https://github.com/owner/repo)'),
113
- name: z.string().optional().describe('Name for the squad (auto-generated if omitted)'),
114
- universe: z
115
- .string()
116
- .optional()
117
- .describe(
118
- 'Pop-culture universe for member names (a-team, marvel, star-wars, lord-of-the-rings, star-trek, firefly). Random if omitted.',
119
- ),
120
- }),
121
- handler: async (args: { repoUrl: string; name?: string; universe?: string }) => {
122
- try {
123
- const { ensureCloned } = await import('../squad/source-resolver.js');
124
- const projectPath = ensureCloned(args.repoUrl);
125
- const result = await hireSquad({
126
- projectPath,
127
- repoUrl: args.repoUrl,
128
- name: args.name,
129
- universe: args.universe,
130
- });
131
- return {
132
- textResultForLlm: JSON.stringify({
133
- message: `Squad '${args.name ?? result.analysis.name}' hired successfully!`,
134
- squadId: result.squadId,
135
- projectPath,
136
- universe: result.universe,
137
- analysis: result.analysis,
138
- members: result.members,
139
- }),
140
- resultType: 'success' as const,
141
- };
142
- } catch (err) {
143
- return {
144
- textResultForLlm: JSON.stringify({
145
- error: `Failed to hire squad: ${err instanceof Error ? err.message : String(err)}`,
146
- }),
147
- resultType: 'success' as const,
148
- };
149
- }
150
- },
151
- }),
152
-
153
- defineTool('retheme_squad', {
154
- description:
155
- "Change a squad's pop-culture universe. Generates new character names and personas for all members from the specified universe.",
156
- parameters: z.object({
157
- squadName: z.string().describe('Name of the squad to retheme'),
158
- universe: z
159
- .string()
160
- .describe('New pop-culture universe (e.g. "The Office", "Star Wars", "Breaking Bad")'),
161
- }),
162
- handler: async (args: { squadName: string; universe: string }) => {
163
- try {
164
- const squad = await getSquadByName(args.squadName);
165
- if (!squad) {
166
- return {
167
- textResultForLlm: JSON.stringify({ error: `Squad '${args.squadName}' not found.` }),
168
- resultType: 'success' as const,
169
- };
170
- }
171
- const members = await getSquadMembers(squad.id);
172
- const roles = members.map((m) => m.roleName);
173
-
174
- const { generateSquadNames } = await import('../squad/name-generator.js');
175
- const generated = await generateSquadNames(roles, args.universe);
176
-
177
- await rethemeSquad(squad.id, generated.universe, generated.assignments);
178
-
179
- return {
180
- textResultForLlm: JSON.stringify({
181
- message: `Squad '${args.squadName}' rethemed to ${generated.universe}!`,
182
- members: generated.assignments.map((a) => `${a.displayName} (${a.role})`),
183
- }),
184
- resultType: 'success' as const,
185
- };
186
- } catch (err) {
187
- return {
188
- textResultForLlm: JSON.stringify({
189
- error: `Failed to retheme squad: ${err instanceof Error ? err.message : String(err)}`,
190
- }),
191
- resultType: 'success' as const,
192
- };
193
- }
194
- },
195
- }),
196
-
197
- defineTool('delegate_to_squad', {
198
- description:
199
- "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.",
200
- parameters: z.object({
201
- squadName: z.string().describe('Name of the squad to delegate to'),
202
- message: z.string().describe('The full message or task to delegate'),
203
- }),
204
- handler: async (args: { squadName: string; message: string }) => {
205
- const squad = await getSquadByName(args.squadName);
206
- if (!squad) {
207
- return {
208
- textResultForLlm: JSON.stringify({
209
- error: `Squad '${args.squadName}' not found.`,
210
- }),
211
- resultType: 'success' as const,
212
- };
213
- }
214
-
215
- try {
216
- // Boot squad if not already running
217
- if (!getSquadRuntime(squad.id)) {
218
- await bootSquad(squad);
219
- }
220
-
221
- const response = await delegateToSquad(squad.id, args.message);
222
- return {
223
- textResultForLlm: JSON.stringify({
224
- delegatedTo: args.squadName,
225
- teamLeadResponse: response,
226
- }),
227
- resultType: 'success' as const,
228
- };
229
- } catch (err) {
230
- return {
231
- textResultForLlm: JSON.stringify({
232
- error: `Failed to delegate: ${err instanceof Error ? err.message : String(err)}`,
233
- }),
234
- resultType: 'success' as const,
235
- };
236
- }
237
- },
238
- }),
239
-
240
- defineTool('run_squad_instance', {
241
- description:
242
- '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.',
243
- parameters: z.object({
244
- squadName: z.string().describe('Name of the squad'),
245
- objective: z.string().describe('What the squad should accomplish'),
246
- issueRef: z.string().optional().describe('GitHub issue reference (e.g., #42)'),
247
- }),
248
- handler: async (args: { squadName: string; objective: string; issueRef?: string }) => {
249
- const squad = await getSquadByName(args.squadName);
250
- if (!squad) {
251
- return {
252
- textResultForLlm: JSON.stringify({ error: `Squad '${args.squadName}' not found.` }),
253
- resultType: 'success' as const,
254
- };
255
- }
256
-
257
- try {
258
- const result = await runInstance({
259
- squad,
260
- objective: args.objective,
261
- issueRef: args.issueRef,
262
- });
263
-
264
- return {
265
- textResultForLlm: JSON.stringify({
266
- instanceId: result.instanceId,
267
- success: result.success,
268
- pr: result.pr ? { url: result.pr.url, number: result.pr.number } : null,
269
- error: result.error,
270
- }),
271
- resultType: 'success' as const,
272
- };
273
- } catch (err) {
274
- return {
275
- textResultForLlm: JSON.stringify({
276
- error: `Failed to run instance: ${err instanceof Error ? err.message : String(err)}`,
277
- }),
278
- resultType: 'success' as const,
279
- };
280
- }
281
- },
282
- }),
283
-
284
- defineTool('list_inbox', {
285
- description:
286
- "List unread inbox entries from squads. Shows deliverables and pending questions that need the user's attention.",
287
- parameters: z.object({
288
- status: z
289
- .enum(['unread', 'read', 'resolved'])
290
- .optional()
291
- .describe('Filter by status (default: unread)'),
292
- }),
293
- handler: async (args: { status?: 'unread' | 'read' | 'resolved' }) => {
294
- const entries = await listInboxEntries({
295
- status: args.status ?? 'unread',
296
- limit: 20,
297
- });
298
-
299
- if (entries.length === 0) {
300
- return {
301
- textResultForLlm: JSON.stringify({ entries: [], message: 'No inbox entries.' }),
302
- resultType: 'success' as const,
303
- };
304
- }
305
-
306
- const summary = entries.map((e) => ({
307
- id: e.id,
308
- squad: e.squadId,
309
- kind: e.kind,
310
- title: e.title,
311
- content: e.content.slice(0, 500),
312
- status: e.status,
313
- createdAt: e.createdAt,
314
- }));
315
-
316
- return {
317
- textResultForLlm: JSON.stringify({ entries: summary }),
318
- resultType: 'success' as const,
319
- };
320
- },
321
- }),
322
-
323
- defineTool('respond_to_inbox', {
324
- description:
325
- "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.",
326
- parameters: z.object({
327
- entryId: z.string().describe('The inbox entry ID to respond to'),
328
- response: z.string().describe("The user's response to the squad's question"),
329
- }),
330
- handler: async (args: { entryId: string; response: string }) => {
331
- try {
332
- const unblocked = await resolveInboxEntry(args.entryId, args.response);
333
- return {
334
- textResultForLlm: JSON.stringify({
335
- resolved: true,
336
- squadUnblocked: unblocked,
337
- message: unblocked
338
- ? 'Response delivered — squad has been unblocked and will continue working.'
339
- : 'Response recorded (squad was not actively waiting).',
340
- }),
341
- resultType: 'success' as const,
342
- };
343
- } catch (err) {
344
- return {
345
- textResultForLlm: JSON.stringify({
346
- error: `Failed to respond: ${err instanceof Error ? err.message : String(err)}`,
347
- }),
348
- resultType: 'success' as const,
349
- };
350
- }
351
- },
352
- }),
353
-
354
- defineTool('create_schedule', {
355
- description:
356
- '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).',
357
- parameters: z.object({
358
- name: z.string().describe('Human-readable name for the schedule (e.g., "Daily Standup")'),
359
- targetType: z
360
- .enum(['squad', 'orchestrator'])
361
- .describe('Whether to target a squad or the orchestrator'),
362
- targetId: z.string().optional().describe('Squad name (required if targetType is "squad")'),
363
- cron: z.string().describe('Cron expression (e.g., "0 9 * * 1-5" for weekdays at 9am)'),
364
- prompt: z.string().describe('The prompt/message to send when the schedule fires'),
365
- }),
366
- handler: async (args: {
367
- name: string;
368
- targetType: 'squad' | 'orchestrator';
369
- targetId?: string;
370
- cron: string;
371
- prompt: string;
372
- }) => {
373
- try {
374
- // Validate squad exists if targeting a squad
375
- if (args.targetType === 'squad') {
376
- if (!args.targetId) {
377
- return {
378
- textResultForLlm: JSON.stringify({
379
- error: 'targetId (squad name) is required for squad schedules',
380
- }),
381
- resultType: 'success' as const,
382
- };
383
- }
384
- const squad = await getSquadByName(args.targetId);
385
- if (!squad) {
386
- return {
387
- textResultForLlm: JSON.stringify({ error: `Squad '${args.targetId}' not found` }),
388
- resultType: 'success' as const,
389
- };
390
- }
391
- args.targetId = squad.id;
392
- }
393
-
394
- const schedule = await createSchedule({
395
- name: args.name,
396
- targetType: args.targetType,
397
- targetId: args.targetId,
398
- cron: args.cron,
399
- prompt: args.prompt,
400
- });
401
-
402
- return {
403
- textResultForLlm: JSON.stringify({
404
- created: true,
405
- schedule: {
406
- id: schedule.id,
407
- name: schedule.name,
408
- cron: schedule.cron,
409
- nextRun: schedule.nextRun,
410
- },
411
- }),
412
- resultType: 'success' as const,
413
- };
414
- } catch (err) {
415
- return {
416
- textResultForLlm: JSON.stringify({
417
- error: `Failed to create schedule: ${err instanceof Error ? err.message : String(err)}`,
418
- }),
419
- resultType: 'success' as const,
420
- };
421
- }
422
- },
423
- }),
424
-
425
- defineTool('list_schedules', {
426
- description: 'List all configured schedules (cron-based automations).',
427
- parameters: z.object({}).strict(),
428
- handler: async () => {
429
- const schedules = await listSchedules();
430
- if (schedules.length === 0) {
431
- return {
432
- textResultForLlm: JSON.stringify({
433
- schedules: [],
434
- message: 'No schedules configured.',
435
- }),
436
- resultType: 'success' as const,
437
- };
438
- }
439
-
440
- const summary = schedules.map((s) => ({
441
- id: s.id,
442
- name: s.name,
443
- targetType: s.targetType,
444
- targetId: s.targetId,
445
- cron: s.cron,
446
- prompt: s.prompt.slice(0, 100),
447
- enabled: s.enabled,
448
- nextRun: s.nextRun,
449
- lastRun: s.lastRun,
450
- }));
451
-
452
- return {
453
- textResultForLlm: JSON.stringify({ schedules: summary }),
454
- resultType: 'success' as const,
455
- };
456
- },
457
- }),
458
-
459
- defineTool('delete_schedule', {
460
- description: 'Delete a schedule by ID. Use list_schedules first to find the ID.',
461
- parameters: z.object({
462
- scheduleId: z.string().describe('The ID of the schedule to delete'),
463
- }),
464
- handler: async (args: { scheduleId: string }) => {
465
- try {
466
- await deleteSchedule(args.scheduleId);
467
- return {
468
- textResultForLlm: JSON.stringify({ deleted: true, scheduleId: args.scheduleId }),
469
- resultType: 'success' as const,
470
- };
471
- } catch (err) {
472
- return {
473
- textResultForLlm: JSON.stringify({
474
- error: `Failed to delete: ${err instanceof Error ? err.message : String(err)}`,
475
- }),
476
- resultType: 'success' as const,
477
- };
478
- }
479
- },
480
- }),
481
-
482
- defineTool('read_wiki', {
483
- description:
484
- '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.',
485
- parameters: z.object({
486
- scope: z.enum(['io', 'shared']).describe('Which wiki scope to read from'),
487
- pageName: z
488
- .string()
489
- .optional()
490
- .describe('Page name to read (omit to list all pages in scope)'),
491
- }),
492
- handler: async (args: { scope: 'io' | 'shared'; pageName?: string }) => {
493
- if (!args.pageName) {
494
- const pages = listWikiPages(args.scope);
495
- return {
496
- textResultForLlm: JSON.stringify({
497
- scope: args.scope,
498
- pages: pages.length > 0 ? pages : '(empty)',
499
- }),
500
- resultType: 'success' as const,
501
- };
502
- }
503
- const page = readWikiPage(args.scope, args.pageName);
504
- if (!page) {
505
- return {
506
- textResultForLlm: JSON.stringify({
507
- error: `Page '${args.pageName}' not found in ${args.scope} wiki`,
508
- }),
509
- resultType: 'success' as const,
510
- };
511
- }
512
- return {
513
- textResultForLlm: JSON.stringify({
514
- scope: page.scope,
515
- name: page.name,
516
- content: page.content,
517
- }),
518
- resultType: 'success' as const,
519
- };
520
- },
521
- }),
522
-
523
- defineTool('write_wiki', {
524
- description:
525
- '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.',
526
- parameters: z.object({
527
- scope: z.enum(['io', 'shared']).describe('Which wiki scope to write to'),
528
- pageName: z
529
- .string()
530
- .describe('Page name (no .md extension, e.g., "preferences" or "routing-conventions")'),
531
- content: z.string().describe('Full markdown content for the page'),
532
- }),
533
- handler: async (args: { scope: 'io' | 'shared'; pageName: string; content: string }) => {
534
- writeWikiPage(args.scope, args.pageName, args.content);
535
- return {
536
- textResultForLlm: JSON.stringify({
537
- written: true,
538
- scope: args.scope,
539
- pageName: args.pageName,
540
- }),
541
- resultType: 'success' as const,
542
- };
543
- },
544
- }),
545
-
546
- defineTool('search_wiki', {
547
- description: 'Search across wiki pages by keyword. Searches IO-level and Shared scopes.',
548
- parameters: z.object({
549
- keyword: z.string().describe('Keyword or phrase to search for'),
550
- }),
551
- handler: async (args: { keyword: string }) => {
552
- const results = searchWiki(args.keyword, getOrchestratorScopes());
553
- if (results.length === 0) {
554
- return {
555
- textResultForLlm: JSON.stringify({ results: [], message: 'No matches found.' }),
556
- resultType: 'success' as const,
557
- };
558
- }
559
- return {
560
- textResultForLlm: JSON.stringify({ results }),
561
- resultType: 'success' as const,
562
- };
563
- },
564
- }),
565
-
566
- defineTool('install_skill', {
567
- description:
568
- '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.',
569
- parameters: z.object({
570
- name: z
571
- .string()
572
- .describe('Name for the skill (kebab-case, e.g., "tdd-workflow" or "code-review")'),
573
- url: z
574
- .string()
575
- .describe(
576
- 'URL to the raw SKILL.md content (e.g., raw.githubusercontent.com/.../SKILL.md)',
577
- ),
578
- }),
579
- handler: async (args: { name: string; url: string }) => {
580
- try {
581
- const skill = await installSkillFromUrl(args.name, args.url);
582
- return {
583
- textResultForLlm: JSON.stringify({
584
- installed: true,
585
- name: skill.name,
586
- preview: skill.content.slice(0, 200),
587
- }),
588
- resultType: 'success' as const,
589
- };
590
- } catch (err) {
591
- return {
592
- textResultForLlm: JSON.stringify({
593
- error: `Failed to install: ${err instanceof Error ? err.message : String(err)}`,
594
- }),
595
- resultType: 'success' as const,
596
- };
597
- }
598
- },
599
- }),
600
-
601
- defineTool('list_skills', {
602
- description: 'List all installed skills and their activation status.',
603
- parameters: z.object({}).strict(),
604
- handler: async () => {
605
- const installed = listInstalledSkills();
606
- const orchestratorActivations = await getActiveSkills('orchestrator');
607
-
608
- const summary = installed.map((s) => ({
609
- name: s.name,
610
- activatedForOrchestrator: orchestratorActivations.some((a) => a.skillName === s.name),
611
- preview: s.content.slice(0, 100),
612
- }));
613
-
614
- return {
615
- textResultForLlm: JSON.stringify({
616
- skills: summary.length > 0 ? summary : '(no skills installed)',
617
- }),
618
- resultType: 'success' as const,
619
- };
620
- },
621
- }),
622
-
623
- defineTool('activate_skill', {
624
- description:
625
- 'Activate an installed skill for the orchestrator or a specific squad. Active skills are injected into the system prompt.',
626
- parameters: z.object({
627
- skillName: z.string().describe('Name of the installed skill'),
628
- targetType: z
629
- .enum(['orchestrator', 'squad'])
630
- .describe('Activate for orchestrator or a specific squad'),
631
- targetId: z.string().optional().describe('Squad name (required if targetType is "squad")'),
632
- }),
633
- handler: async (args: {
634
- skillName: string;
635
- targetType: 'orchestrator' | 'squad';
636
- targetId?: string;
637
- }) => {
638
- try {
639
- let resolvedTargetId = args.targetId ?? null;
640
- if (args.targetType === 'squad' && args.targetId) {
641
- const squad = await getSquadByName(args.targetId);
642
- if (!squad) {
643
- return {
644
- textResultForLlm: JSON.stringify({ error: `Squad '${args.targetId}' not found` }),
645
- resultType: 'success' as const,
646
- };
647
- }
648
- resolvedTargetId = squad.id;
649
- }
650
-
651
- await activateSkill(args.skillName, args.targetType, resolvedTargetId ?? undefined);
652
- return {
653
- textResultForLlm: JSON.stringify({
654
- activated: true,
655
- skillName: args.skillName,
656
- target: args.targetType === 'orchestrator' ? 'orchestrator' : args.targetId,
657
- }),
658
- resultType: 'success' as const,
659
- };
660
- } catch (err) {
661
- return {
662
- textResultForLlm: JSON.stringify({
663
- error: `Failed to activate: ${err instanceof Error ? err.message : String(err)}`,
664
- }),
665
- resultType: 'success' as const,
666
- };
667
- }
668
- },
669
- }),
670
-
671
- defineTool('deactivate_skill', {
672
- description: 'Deactivate a skill (stop injecting it into the system prompt).',
673
- parameters: z.object({
674
- skillName: z.string().describe('Name of the skill to deactivate'),
675
- targetType: z
676
- .enum(['orchestrator', 'squad'])
677
- .describe('Deactivate from orchestrator or a specific squad'),
678
- targetId: z.string().optional().describe('Squad name (required if targetType is "squad")'),
679
- }),
680
- handler: async (args: {
681
- skillName: string;
682
- targetType: 'orchestrator' | 'squad';
683
- targetId?: string;
684
- }) => {
685
- await deactivateSkill(args.skillName, args.targetType, args.targetId ?? undefined);
686
- return {
687
- textResultForLlm: JSON.stringify({ deactivated: true, skillName: args.skillName }),
688
- resultType: 'success' as const,
689
- };
690
- },
691
- }),
692
-
693
- defineTool('remove_skill', {
694
- description: 'Uninstall a skill completely (removes files and all activations).',
695
- parameters: z.object({
696
- skillName: z.string().describe('Name of the skill to remove'),
697
- }),
698
- handler: async (args: { skillName: string }) => {
699
- removeSkill(args.skillName);
700
- return {
701
- textResultForLlm: JSON.stringify({ removed: true, skillName: args.skillName }),
702
- resultType: 'success' as const,
703
- };
704
- },
705
- }),
706
- ];
707
- }