heyio 1.12.1 → 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.
- package/dist/api/middleware/auth.d.ts +14 -0
- package/dist/api/middleware/auth.d.ts.map +1 -0
- package/dist/api/middleware/auth.js +66 -0
- package/dist/api/middleware/auth.js.map +1 -0
- package/dist/api/notifications.d.ts +14 -0
- package/dist/api/notifications.d.ts.map +1 -0
- package/dist/api/notifications.js +112 -0
- package/dist/api/notifications.js.map +1 -0
- package/dist/api/routes/activity.d.ts +3 -0
- package/dist/api/routes/activity.d.ts.map +1 -0
- package/dist/api/routes/activity.js +28 -0
- package/dist/api/routes/activity.js.map +1 -0
- package/dist/api/routes/attachments.d.ts +3 -0
- package/dist/api/routes/attachments.d.ts.map +1 -0
- package/dist/api/routes/attachments.js +83 -0
- package/dist/api/routes/attachments.js.map +1 -0
- package/dist/api/routes/config.d.ts +3 -0
- package/dist/api/routes/config.d.ts.map +1 -0
- package/dist/api/routes/config.js +106 -0
- package/dist/api/routes/config.js.map +1 -0
- package/dist/api/routes/conversations.d.ts +3 -0
- package/dist/api/routes/conversations.d.ts.map +1 -0
- package/dist/api/routes/conversations.js +69 -0
- package/dist/api/routes/conversations.js.map +1 -0
- package/dist/api/routes/health.d.ts +3 -0
- package/dist/api/routes/health.d.ts.map +1 -0
- package/dist/api/routes/health.js +16 -0
- package/dist/api/routes/health.js.map +1 -0
- package/dist/api/routes/inbox.d.ts +3 -0
- package/dist/api/routes/inbox.d.ts.map +1 -0
- package/dist/api/routes/inbox.js +88 -0
- package/dist/api/routes/inbox.js.map +1 -0
- package/dist/api/routes/schedules.d.ts +3 -0
- package/dist/api/routes/schedules.d.ts.map +1 -0
- package/dist/api/routes/schedules.js +96 -0
- package/dist/api/routes/schedules.js.map +1 -0
- package/dist/api/routes/skills.d.ts +2 -0
- package/dist/api/routes/skills.d.ts.map +1 -0
- package/dist/api/routes/skills.js +85 -0
- package/dist/api/routes/skills.js.map +1 -0
- package/dist/api/routes/squads.d.ts +3 -0
- package/dist/api/routes/squads.d.ts.map +1 -0
- package/dist/api/routes/squads.js +129 -0
- package/dist/api/routes/squads.js.map +1 -0
- package/dist/api/routes/usage.d.ts +3 -0
- package/dist/api/routes/usage.d.ts.map +1 -0
- package/dist/api/routes/usage.js +55 -0
- package/dist/api/routes/usage.js.map +1 -0
- package/dist/api/routes/wiki.d.ts +2 -0
- package/dist/api/routes/wiki.d.ts.map +1 -0
- package/dist/api/routes/wiki.js +43 -0
- package/dist/api/routes/wiki.js.map +1 -0
- package/dist/api/server.d.ts +7 -0
- package/dist/api/server.d.ts.map +1 -0
- package/dist/api/server.js +136 -634
- package/dist/api/server.js.map +1 -0
- package/dist/config.d.ts +3 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +2 -91
- package/dist/config.js.map +1 -0
- package/dist/copilot/client.d.ts +5 -0
- package/dist/copilot/client.d.ts.map +1 -0
- package/dist/copilot/client.js +19 -11
- package/dist/copilot/client.js.map +1 -0
- package/dist/copilot/health-monitor.d.ts +14 -0
- package/dist/copilot/health-monitor.d.ts.map +1 -0
- package/dist/copilot/health-monitor.js +70 -0
- package/dist/copilot/health-monitor.js.map +1 -0
- package/dist/copilot/orchestrator.d.ts +5 -0
- package/dist/copilot/orchestrator.d.ts.map +1 -0
- package/dist/copilot/orchestrator.js +127 -123
- package/dist/copilot/orchestrator.js.map +1 -0
- package/dist/copilot/tools.d.ts +49 -0
- package/dist/copilot/tools.d.ts.map +1 -0
- package/dist/copilot/tools.js +545 -321
- package/dist/copilot/tools.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +82 -26
- package/dist/index.js.map +1 -0
- package/dist/logging/logger.d.ts +6 -0
- package/dist/logging/logger.d.ts.map +1 -0
- package/dist/logging/logger.js +21 -0
- package/dist/logging/logger.js.map +1 -0
- package/dist/models/index.d.ts +6 -0
- package/dist/models/index.d.ts.map +1 -0
- package/dist/models/index.js +4 -0
- package/dist/models/index.js.map +1 -0
- package/dist/models/pricing.d.ts +25 -0
- package/dist/models/pricing.d.ts.map +1 -0
- package/dist/models/pricing.js +96 -0
- package/dist/models/pricing.js.map +1 -0
- package/dist/models/registry.d.ts +34 -0
- package/dist/models/registry.d.ts.map +1 -0
- package/dist/models/registry.js +109 -0
- package/dist/models/registry.js.map +1 -0
- package/dist/models/token-tracker.d.ts +40 -0
- package/dist/models/token-tracker.d.ts.map +1 -0
- package/dist/models/token-tracker.js +102 -0
- package/dist/models/token-tracker.js.map +1 -0
- package/dist/scheduler/engine.d.ts +9 -0
- package/dist/scheduler/engine.d.ts.map +1 -0
- package/dist/scheduler/engine.js +127 -0
- package/dist/scheduler/engine.js.map +1 -0
- package/dist/skills/index.d.ts +3 -0
- package/dist/skills/index.d.ts.map +1 -0
- package/dist/skills/index.js +2 -0
- package/dist/skills/index.js.map +1 -0
- package/dist/skills/store.d.ts +52 -0
- package/dist/skills/store.d.ts.map +1 -0
- package/dist/skills/store.js +148 -0
- package/dist/skills/store.js.map +1 -0
- package/dist/squad/agent.d.ts +46 -0
- package/dist/squad/agent.d.ts.map +1 -0
- package/dist/squad/agent.js +261 -0
- package/dist/squad/agent.js.map +1 -0
- package/dist/squad/autonomy.d.ts +16 -0
- package/dist/squad/autonomy.d.ts.map +1 -0
- package/dist/squad/autonomy.js +63 -0
- package/dist/squad/autonomy.js.map +1 -0
- package/dist/squad/event-bus.d.ts +22 -0
- package/dist/squad/event-bus.d.ts.map +1 -0
- package/dist/squad/event-bus.js +56 -0
- package/dist/squad/event-bus.js.map +1 -0
- package/dist/squad/execution/index.d.ts +12 -0
- package/dist/squad/execution/index.d.ts.map +1 -0
- package/dist/squad/execution/index.js +7 -0
- package/dist/squad/execution/index.js.map +1 -0
- package/dist/squad/execution/instance.d.ts +40 -0
- package/dist/squad/execution/instance.d.ts.map +1 -0
- package/dist/squad/execution/instance.js +138 -0
- package/dist/squad/execution/instance.js.map +1 -0
- package/dist/squad/execution/meeting.d.ts +25 -0
- package/dist/squad/execution/meeting.d.ts.map +1 -0
- package/dist/squad/execution/meeting.js +140 -0
- package/dist/squad/execution/meeting.js.map +1 -0
- package/dist/squad/execution/pr.d.ts +15 -0
- package/dist/squad/execution/pr.d.ts.map +1 -0
- package/dist/squad/execution/pr.js +93 -0
- package/dist/squad/execution/pr.js.map +1 -0
- package/dist/squad/execution/runner.d.ts +22 -0
- package/dist/squad/execution/runner.d.ts.map +1 -0
- package/dist/squad/execution/runner.js +68 -0
- package/dist/squad/execution/runner.js.map +1 -0
- package/dist/squad/execution/tasks.d.ts +11 -0
- package/dist/squad/execution/tasks.d.ts.map +1 -0
- package/dist/squad/execution/tasks.js +85 -0
- package/dist/squad/execution/tasks.js.map +1 -0
- package/dist/squad/execution/worktree.d.ts +26 -0
- package/dist/squad/execution/worktree.d.ts.map +1 -0
- package/dist/squad/execution/worktree.js +111 -0
- package/dist/squad/execution/worktree.js.map +1 -0
- package/dist/squad/hiring.d.ts +32 -0
- package/dist/squad/hiring.d.ts.map +1 -0
- package/dist/squad/hiring.js +200 -0
- package/dist/squad/hiring.js.map +1 -0
- package/dist/squad/index.d.ts +8 -0
- package/dist/squad/index.d.ts.map +1 -0
- package/dist/squad/index.js +6 -0
- package/dist/squad/index.js.map +1 -0
- package/dist/squad/manager.d.ts +48 -0
- package/dist/squad/manager.d.ts.map +1 -0
- package/dist/squad/manager.js +274 -0
- package/dist/squad/manager.js.map +1 -0
- package/dist/squad/name-generator.d.ts +16 -0
- package/dist/squad/name-generator.d.ts.map +1 -0
- package/dist/squad/name-generator.js +113 -0
- package/dist/squad/name-generator.js.map +1 -0
- package/dist/squad/roles/templates.d.ts +5 -0
- package/dist/squad/roles/templates.d.ts.map +1 -0
- package/dist/squad/roles/templates.js +102 -0
- package/dist/squad/roles/templates.js.map +1 -0
- package/dist/squad/skill-parser.d.ts +36 -0
- package/dist/squad/skill-parser.d.ts.map +1 -0
- package/dist/squad/skill-parser.js +83 -0
- package/dist/squad/skill-parser.js.map +1 -0
- package/dist/squad/source-resolver.d.ts +20 -0
- package/dist/squad/source-resolver.d.ts.map +1 -0
- package/dist/squad/source-resolver.js +52 -0
- package/dist/squad/source-resolver.js.map +1 -0
- package/dist/store/activity.d.ts +43 -0
- package/dist/store/activity.d.ts.map +1 -0
- package/dist/store/activity.js +131 -0
- package/dist/store/activity.js.map +1 -0
- package/dist/store/db.d.ts +5 -0
- package/dist/store/db.d.ts.map +1 -0
- package/dist/store/db.js +209 -248
- package/dist/store/db.js.map +1 -0
- package/dist/store/inbox.d.ts +53 -0
- package/dist/store/inbox.d.ts.map +1 -0
- package/dist/store/inbox.js +151 -0
- package/dist/store/inbox.js.map +1 -0
- package/dist/store/schedules.d.ts +53 -0
- package/dist/store/schedules.d.ts.map +1 -0
- package/dist/store/schedules.js +149 -54
- package/dist/store/schedules.js.map +1 -0
- package/dist/wiki/index.d.ts +3 -0
- package/dist/wiki/index.d.ts.map +1 -0
- package/dist/wiki/index.js +2 -0
- package/dist/wiki/index.js.map +1 -0
- package/dist/wiki/store.d.ts +49 -0
- package/dist/wiki/store.d.ts.map +1 -0
- package/dist/wiki/store.js +115 -0
- package/dist/wiki/store.js.map +1 -0
- package/package.json +52 -56
- package/src/api/middleware/auth.ts +76 -0
- package/src/api/notifications.ts +122 -0
- package/src/api/routes/activity.ts +29 -0
- package/src/api/routes/attachments.ts +93 -0
- package/src/api/routes/config.ts +115 -0
- package/src/api/routes/conversations.ts +87 -0
- package/src/api/routes/health.ts +18 -0
- package/src/api/routes/inbox.ts +98 -0
- package/src/api/routes/schedules.ts +121 -0
- package/src/api/routes/skills.ts +105 -0
- package/src/api/routes/squads.ts +145 -0
- package/src/api/routes/usage.ts +57 -0
- package/src/api/routes/wiki.ts +49 -0
- package/src/api/server.ts +186 -0
- package/src/config.ts +3 -0
- package/src/copilot/client.ts +42 -0
- package/src/copilot/health-monitor.ts +85 -0
- package/src/copilot/orchestrator.ts +222 -0
- package/src/copilot/tools.ts +707 -0
- package/src/index.ts +112 -0
- package/src/logging/logger.ts +26 -0
- package/src/models/index.ts +11 -0
- package/src/models/pricing.ts +121 -0
- package/src/models/registry.ts +131 -0
- package/src/models/token-tracker.ts +151 -0
- package/src/scheduler/engine.ts +146 -0
- package/src/skills/index.ts +13 -0
- package/src/skills/store.ts +188 -0
- package/src/squad/agent.ts +326 -0
- package/src/squad/autonomy.ts +78 -0
- package/src/squad/event-bus.ts +71 -0
- package/src/squad/execution/index.ts +17 -0
- package/src/squad/execution/instance.ts +186 -0
- package/src/squad/execution/meeting.ts +191 -0
- package/src/squad/execution/pr.ts +127 -0
- package/src/squad/execution/runner.ts +97 -0
- package/src/squad/execution/tasks.ts +111 -0
- package/src/squad/execution/worktree.ts +138 -0
- package/src/squad/hiring.ts +222 -0
- package/src/squad/index.ts +17 -0
- package/src/squad/manager.ts +337 -0
- package/src/squad/name-generator.ts +135 -0
- package/src/squad/roles/templates.ts +104 -0
- package/src/squad/skill-parser.ts +120 -0
- package/src/squad/source-resolver.ts +57 -0
- package/src/store/activity.ts +176 -0
- package/src/store/db.ts +237 -0
- package/src/store/inbox.ts +199 -0
- package/src/store/schedules.ts +199 -0
- package/src/wiki/index.ts +12 -0
- package/src/wiki/store.ts +139 -0
- package/tsconfig.json +9 -0
- package/LICENSE +0 -21
- package/README.md +0 -333
- package/dist/api/auth.js +0 -46
- package/dist/chat/attachments.js +0 -112
- package/dist/copilot/agents.js +0 -309
- package/dist/copilot/ceremonies.js +0 -174
- package/dist/copilot/gh-token.js +0 -64
- package/dist/copilot/io-scheduler.js +0 -79
- package/dist/copilot/model-router.js +0 -114
- package/dist/copilot/scheduler.js +0 -88
- package/dist/copilot/skills.js +0 -246
- package/dist/copilot/specialist-runner.js +0 -191
- package/dist/copilot/squad-tools.js +0 -258
- package/dist/copilot/system-message.js +0 -86
- package/dist/copilot/token-tracker.js +0 -98
- package/dist/copilot/trigger-schedule.js +0 -33
- package/dist/daemon.js +0 -67
- package/dist/logging.js +0 -27
- package/dist/mcp/config.js +0 -29
- package/dist/mcp/index.js +0 -3
- package/dist/mcp/registry.js +0 -42
- package/dist/notify.js +0 -25
- package/dist/paths.js +0 -17
- package/dist/setup.js +0 -35
- package/dist/store/agent-events.js +0 -19
- package/dist/store/audit-log.js +0 -71
- package/dist/store/conversations.js +0 -164
- package/dist/store/feed.js +0 -44
- package/dist/store/instances.js +0 -75
- package/dist/store/squad-colors.js +0 -23
- package/dist/store/squads.js +0 -60
- package/dist/store/tasks.js +0 -78
- package/dist/store/token-usage.js +0 -94
- package/dist/telegram/bot.js +0 -41
- package/dist/telegram/handlers.js +0 -42
- package/dist/watchdog.js +0 -37
- package/dist/wiki/backlinks.js +0 -51
- package/dist/wiki/fs.js +0 -108
- package/dist/wiki/search.js +0 -47
- package/web-dist/assets/AuditLogView-C5QtUQBq.js +0 -6
- package/web-dist/assets/ChatView-DLu9BMg8.js +0 -1
- package/web-dist/assets/FeedView-6OV-l6Gl.js +0 -6
- package/web-dist/assets/HistoryView-DizPqv0y.js +0 -1
- package/web-dist/assets/LoginView-CG1O9fmR.js +0 -1
- package/web-dist/assets/McpView-TJN-fZvI.js +0 -1
- package/web-dist/assets/SchedulesView-BDFpImX6.js +0 -6
- package/web-dist/assets/SettingsView-D-K1iC1c.js +0 -1
- package/web-dist/assets/SkillsView-DnNmO192.js +0 -15
- package/web-dist/assets/SquadDetailView-BBvrgHzn.js +0 -26
- package/web-dist/assets/SquadHealthView-DF2zF9D3.js +0 -11
- package/web-dist/assets/SquadsView-CPVzko7k.js +0 -6
- package/web-dist/assets/ToggleSwitch.vue_vue_type_script_setup_true_lang-Bk_t9_Rn.js +0 -1
- package/web-dist/assets/UsageView-OcyM5k14.js +0 -16
- package/web-dist/assets/WikiView-KhFqBZI0.js +0 -26
- package/web-dist/assets/api-BiDVwQrs.js +0 -1
- package/web-dist/assets/arrow-left-DFbf2tii.js +0 -6
- package/web-dist/assets/git-branch-BLstr_Gr.js +0 -6
- package/web-dist/assets/index-B-o45ao1.css +0 -1
- package/web-dist/assets/index-DCJUYZtV.js +0 -269
- package/web-dist/assets/pencil-D4Zz_t0y.js +0 -6
- package/web-dist/assets/plus-gmwiZVfr.js +0 -6
- package/web-dist/assets/save-BvtAs5WB.js +0 -6
- package/web-dist/assets/search-BabUvoGD.js +0 -6
- package/web-dist/assets/squad-colors-B8B_Y-lz.js +0 -1
- package/web-dist/assets/trash-2-C21cNLJl.js +0 -6
- package/web-dist/assets/triangle-alert-BrzY_E1n.js +0 -6
- package/web-dist/assets/x-xgLSmc9e.js +0 -6
- package/web-dist/favicon.svg +0 -10
- package/web-dist/index.html +0 -14
- package/web-dist/logo.svg +0 -10
package/dist/copilot/tools.js
CHANGED
|
@@ -1,402 +1,626 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
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
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const
|
|
44
|
-
|
|
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(
|
|
48
|
-
description:
|
|
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
|
-
|
|
46
|
+
squadName: z.string().describe('The name of the squad to check'),
|
|
51
47
|
}),
|
|
52
|
-
handler: async (
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
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(
|
|
59
|
-
description:
|
|
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
|
-
|
|
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 (
|
|
64
|
-
|
|
65
|
-
|
|
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
|
-
|
|
69
|
-
|
|
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
|
-
|
|
124
|
+
squadName: z.string().describe('Name of the squad to retheme'),
|
|
73
125
|
universe: z
|
|
74
126
|
.string()
|
|
75
|
-
.describe(
|
|
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 (
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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(
|
|
122
|
-
description: "
|
|
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
|
-
|
|
125
|
-
|
|
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 (
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
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(
|
|
154
|
-
description:
|
|
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
|
-
|
|
157
|
-
|
|
158
|
-
|
|
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 (
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
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(
|
|
183
|
-
description: "
|
|
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
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
.
|
|
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 (
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
|
|
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
|
-
|
|
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(
|
|
214
|
-
description: "
|
|
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
|
-
|
|
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 (
|
|
219
|
-
|
|
220
|
-
|
|
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(
|
|
224
|
-
description:
|
|
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
|
-
|
|
227
|
-
|
|
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 (
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
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(
|
|
236
|
-
description:
|
|
237
|
-
parameters: z.object({
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
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(
|
|
247
|
-
description:
|
|
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
|
-
|
|
402
|
+
scheduleId: z.string().describe('The ID of the schedule to delete'),
|
|
250
403
|
}),
|
|
251
|
-
handler: async (
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
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(
|
|
258
|
-
description:
|
|
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
|
-
|
|
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 (
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
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
|
-
|
|
269
|
-
|
|
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
|
-
|
|
273
|
-
|
|
274
|
-
|
|
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 (
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
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(
|
|
283
|
-
description:
|
|
482
|
+
defineTool('search_wiki', {
|
|
483
|
+
description: 'Search across wiki pages by keyword. Searches IO-level and Shared scopes.',
|
|
284
484
|
parameters: z.object({
|
|
285
|
-
|
|
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 (
|
|
290
|
-
const
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
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
|
-
|
|
304
|
-
|
|
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
|
-
|
|
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
|
-
.
|
|
313
|
-
|
|
314
|
-
|
|
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 (
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
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(
|
|
323
|
-
description:
|
|
324
|
-
parameters: z.object({
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
const
|
|
329
|
-
|
|
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(
|
|
333
|
-
description:
|
|
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
|
-
|
|
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 (
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
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(
|
|
344
|
-
description:
|
|
594
|
+
defineTool('deactivate_skill', {
|
|
595
|
+
description: 'Deactivate a skill (stop injecting it into the system prompt).',
|
|
345
596
|
parameters: z.object({
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
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 (
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
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
|
-
|
|
359
|
-
|
|
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
|
-
|
|
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 (
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
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
|