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.
- package/README.md +162 -278
- 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/node_modules/@io/shared/dist/config.d.ts +25 -0
- package/node_modules/@io/shared/dist/config.d.ts.map +1 -0
- package/node_modules/@io/shared/dist/config.js +47 -0
- package/node_modules/@io/shared/dist/config.js.map +1 -0
- package/node_modules/@io/shared/dist/constants.d.ts +13 -0
- package/node_modules/@io/shared/dist/constants.d.ts.map +1 -0
- package/node_modules/@io/shared/dist/constants.js +34 -0
- package/node_modules/@io/shared/dist/constants.js.map +1 -0
- package/node_modules/@io/shared/dist/index.d.ts +11 -0
- package/node_modules/@io/shared/dist/index.d.ts.map +1 -0
- package/node_modules/@io/shared/dist/index.js +3 -0
- package/node_modules/@io/shared/dist/index.js.map +1 -0
- package/node_modules/@io/shared/dist/types/agents.d.ts +3 -0
- package/node_modules/@io/shared/dist/types/agents.d.ts.map +1 -0
- package/node_modules/@io/shared/dist/types/agents.js +2 -0
- package/node_modules/@io/shared/dist/types/agents.js.map +1 -0
- package/node_modules/@io/shared/dist/types/api.d.ts +33 -0
- package/node_modules/@io/shared/dist/types/api.d.ts.map +1 -0
- package/node_modules/@io/shared/dist/types/api.js +2 -0
- package/node_modules/@io/shared/dist/types/api.js.map +1 -0
- package/node_modules/@io/shared/dist/types/attachments.d.ts +10 -0
- package/node_modules/@io/shared/dist/types/attachments.d.ts.map +1 -0
- package/node_modules/@io/shared/dist/types/attachments.js +2 -0
- package/node_modules/@io/shared/dist/types/attachments.js.map +1 -0
- package/node_modules/@io/shared/dist/types/events.d.ts +44 -0
- package/node_modules/@io/shared/dist/types/events.d.ts.map +1 -0
- package/node_modules/@io/shared/dist/types/events.js +2 -0
- package/node_modules/@io/shared/dist/types/events.js.map +1 -0
- package/node_modules/@io/shared/dist/types/messages.d.ts +15 -0
- package/node_modules/@io/shared/dist/types/messages.d.ts.map +1 -0
- package/node_modules/@io/shared/dist/types/messages.js +2 -0
- package/node_modules/@io/shared/dist/types/messages.js.map +1 -0
- package/node_modules/@io/shared/dist/types/squads.d.ts +43 -0
- package/node_modules/@io/shared/dist/types/squads.d.ts.map +1 -0
- package/node_modules/@io/shared/dist/types/squads.js +2 -0
- package/node_modules/@io/shared/dist/types/squads.js.map +1 -0
- package/node_modules/@io/shared/dist/types/tokens.d.ts +19 -0
- package/node_modules/@io/shared/dist/types/tokens.d.ts.map +1 -0
- package/node_modules/@io/shared/dist/types/tokens.js +2 -0
- package/node_modules/@io/shared/dist/types/tokens.js.map +1 -0
- package/node_modules/@io/shared/package.json +18 -0
- package/node_modules/@io/shared/src/config.ts +74 -0
- package/node_modules/@io/shared/src/constants.ts +36 -0
- package/node_modules/@io/shared/src/index.ts +37 -0
- package/node_modules/@io/shared/src/types/agents.ts +3 -0
- package/node_modules/@io/shared/src/types/api.ts +35 -0
- package/node_modules/@io/shared/src/types/attachments.ts +9 -0
- package/node_modules/@io/shared/src/types/events.ts +81 -0
- package/node_modules/@io/shared/src/types/messages.ts +15 -0
- package/node_modules/@io/shared/src/types/squads.ts +53 -0
- package/node_modules/@io/shared/src/types/tokens.ts +19 -0
- package/node_modules/@io/shared/tsconfig.json +9 -0
- package/node_modules/@io/shared/tsconfig.tsbuildinfo +1 -0
- package/package.json +56 -59
- 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/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 -252
- 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-BzfjNXBT.js +0 -6
- package/web-dist/assets/ChatView-BdMukPKG.js +0 -1
- package/web-dist/assets/FeedView-BfPIabGr.js +0 -6
- package/web-dist/assets/HistoryView-BmEEk3Rs.js +0 -1
- package/web-dist/assets/LoginView-D7LrkeX7.js +0 -1
- package/web-dist/assets/McpView-BAP_ah3T.js +0 -1
- package/web-dist/assets/SchedulesView-CAtsUPCZ.js +0 -6
- package/web-dist/assets/SettingsView-BovjWZDa.js +0 -1
- package/web-dist/assets/SkillsView-DQSMM5LN.js +0 -16
- package/web-dist/assets/SquadDetailView-DBscu0m2.js +0 -26
- package/web-dist/assets/SquadHealthView-D686BuQo.js +0 -11
- package/web-dist/assets/SquadsView-AzMht2NJ.js +0 -6
- package/web-dist/assets/ToggleSwitch.vue_vue_type_script_setup_true_lang-DtShZAjW.js +0 -1
- package/web-dist/assets/UsageView-DiVn97aI.js +0 -16
- package/web-dist/assets/WikiView-Cn7KipkZ.js +0 -26
- package/web-dist/assets/api-D4mHJ3u0.js +0 -1
- package/web-dist/assets/arrow-left-D_qUNUWW.js +0 -6
- package/web-dist/assets/git-branch-DOM-orcl.js +0 -6
- package/web-dist/assets/index-Bo83B1LR.css +0 -1
- package/web-dist/assets/index-ELvnkQjd.js +0 -273
- package/web-dist/assets/pencil-CFsi7ufI.js +0 -6
- package/web-dist/assets/plus-BAzlGFd_.js +0 -6
- package/web-dist/assets/save-BmgCYJ1g.js +0 -6
- package/web-dist/assets/search-CS9zSIeW.js +0 -6
- package/web-dist/assets/squad-colors-B8B_Y-lz.js +0 -1
- package/web-dist/assets/trash-2-DLveUEsd.js +0 -6
- package/web-dist/assets/triangle-alert-lj4I30rL.js +0 -6
- package/web-dist/assets/x-CjXR97Fa.js +0 -6
- package/web-dist/favicon.svg +0 -10
- package/web-dist/index.html +0 -14
- package/web-dist/logo.svg +0 -10
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
import { loadConfig } from "../config.js";
|
|
2
|
-
import { getClient } from "./client.js";
|
|
3
|
-
import { logWarn } from "../logging.js";
|
|
4
|
-
// Cache discovered models so we don't call listModels() on every task
|
|
5
|
-
let discoveredModels;
|
|
6
|
-
/**
|
|
7
|
-
* Built-in model capability hints. Used as fallback when billing info
|
|
8
|
-
* isn't available from the SDK. Higher = more capable.
|
|
9
|
-
*/
|
|
10
|
-
const MODEL_CAPABILITY_HINTS = {
|
|
11
|
-
"claude-opus-4.7": 90,
|
|
12
|
-
"claude-opus-4.6": 88,
|
|
13
|
-
"claude-opus-4.5": 85,
|
|
14
|
-
"gpt-5.5": 87,
|
|
15
|
-
"gpt-5.4": 84,
|
|
16
|
-
"gpt-5.3-codex": 83,
|
|
17
|
-
"gpt-5.2-codex": 82,
|
|
18
|
-
"gpt-5.2": 80,
|
|
19
|
-
"claude-sonnet-4.6": 70,
|
|
20
|
-
"claude-sonnet-4.5": 68,
|
|
21
|
-
"gpt-4.1": 65,
|
|
22
|
-
"claude-haiku-4.5": 40,
|
|
23
|
-
"gpt-5.4-mini": 42,
|
|
24
|
-
"gpt-5-mini": 38,
|
|
25
|
-
};
|
|
26
|
-
/**
|
|
27
|
-
* Discover available models from the Copilot SDK and score them.
|
|
28
|
-
* Uses billing multiplier as primary capability signal, falls back to
|
|
29
|
-
* built-in hints for unknown models.
|
|
30
|
-
*/
|
|
31
|
-
export async function discoverModels() {
|
|
32
|
-
if (discoveredModels)
|
|
33
|
-
return discoveredModels;
|
|
34
|
-
try {
|
|
35
|
-
const client = await getClient();
|
|
36
|
-
const models = await client.listModels();
|
|
37
|
-
discoveredModels = models
|
|
38
|
-
.filter((m) => !m.policy || m.policy.state === "enabled")
|
|
39
|
-
.map((m) => ({
|
|
40
|
-
id: m.id,
|
|
41
|
-
// Use billing multiplier as capability proxy (higher cost = more capable)
|
|
42
|
-
// Fall back to built-in hints, then default of 50
|
|
43
|
-
score: m.billing
|
|
44
|
-
? Math.min(m.billing.multiplier * 10, 100)
|
|
45
|
-
: (MODEL_CAPABILITY_HINTS[m.id] ?? 50),
|
|
46
|
-
}))
|
|
47
|
-
.sort((a, b) => b.score - a.score);
|
|
48
|
-
}
|
|
49
|
-
catch (err) {
|
|
50
|
-
logWarn("Failed to discover models from SDK, falling back to configured default model", {}, err);
|
|
51
|
-
// SDK discovery failed — fall back to defaultModel only
|
|
52
|
-
const config = loadConfig();
|
|
53
|
-
discoveredModels = [{ id: config.defaultModel, score: 65 }];
|
|
54
|
-
}
|
|
55
|
-
return discoveredModels;
|
|
56
|
-
}
|
|
57
|
-
/** Reset cached models (e.g. after client reconnect) */
|
|
58
|
-
export function resetModelCache() {
|
|
59
|
-
discoveredModels = undefined;
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* Select the best available model for a given task complexity.
|
|
63
|
-
* Discovers models from the Copilot SDK and picks based on capability —
|
|
64
|
-
* zero configuration required.
|
|
65
|
-
*/
|
|
66
|
-
export async function selectModel(complexity) {
|
|
67
|
-
const config = loadConfig();
|
|
68
|
-
const scored = await discoverModels();
|
|
69
|
-
if (scored.length === 0)
|
|
70
|
-
return config.defaultModel;
|
|
71
|
-
if (complexity === "high") {
|
|
72
|
-
// Most capable model
|
|
73
|
-
return scored[0].id;
|
|
74
|
-
}
|
|
75
|
-
if (complexity === "low") {
|
|
76
|
-
// Cheapest model
|
|
77
|
-
return scored[scored.length - 1].id;
|
|
78
|
-
}
|
|
79
|
-
// Medium — pick a model around the middle of the ranked list
|
|
80
|
-
const midIdx = Math.floor(scored.length / 2);
|
|
81
|
-
return scored[midIdx].id;
|
|
82
|
-
}
|
|
83
|
-
export function classifyComplexity(task) {
|
|
84
|
-
const lower = task.toLowerCase();
|
|
85
|
-
const highPatterns = [
|
|
86
|
-
"architect",
|
|
87
|
-
"design system",
|
|
88
|
-
"refactor",
|
|
89
|
-
"security audit",
|
|
90
|
-
"performance optimization",
|
|
91
|
-
"migration",
|
|
92
|
-
"complex",
|
|
93
|
-
"deep analysis",
|
|
94
|
-
"debug",
|
|
95
|
-
"race condition",
|
|
96
|
-
];
|
|
97
|
-
if (highPatterns.some((p) => lower.includes(p)))
|
|
98
|
-
return "high";
|
|
99
|
-
const lowPatterns = [
|
|
100
|
-
"format",
|
|
101
|
-
"rename",
|
|
102
|
-
"typo",
|
|
103
|
-
"simple",
|
|
104
|
-
"lookup",
|
|
105
|
-
"list",
|
|
106
|
-
"read",
|
|
107
|
-
"status",
|
|
108
|
-
"check",
|
|
109
|
-
];
|
|
110
|
-
if (lowPatterns.some((p) => lower.includes(p)))
|
|
111
|
-
return "low";
|
|
112
|
-
return "medium";
|
|
113
|
-
}
|
|
114
|
-
//# sourceMappingURL=model-router.js.map
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import { listSchedules, updateScheduleLastRun } from "../store/schedules.js";
|
|
2
|
-
import { delegateTask } from "./agents.js";
|
|
3
|
-
import { addAuditEntry } from "../store/audit-log.js";
|
|
4
|
-
let schedulerInterval;
|
|
5
|
-
export function startSquadScheduler() {
|
|
6
|
-
// Check every minute for due schedules
|
|
7
|
-
schedulerInterval = setInterval(() => {
|
|
8
|
-
checkSquadSchedules();
|
|
9
|
-
}, 60_000);
|
|
10
|
-
schedulerInterval.unref();
|
|
11
|
-
}
|
|
12
|
-
function checkSquadSchedules() {
|
|
13
|
-
const schedules = listSchedules("squad");
|
|
14
|
-
const now = new Date();
|
|
15
|
-
for (const schedule of schedules) {
|
|
16
|
-
if (!schedule.enabled)
|
|
17
|
-
continue;
|
|
18
|
-
if (!isDue(schedule.cron, schedule.last_run, now))
|
|
19
|
-
continue;
|
|
20
|
-
if (!schedule.squad_id) {
|
|
21
|
-
console.warn(`[scheduler] Schedule ${schedule.id} skipped: missing squad_id.`);
|
|
22
|
-
continue;
|
|
23
|
-
}
|
|
24
|
-
const squadId = schedule.squad_id;
|
|
25
|
-
updateScheduleLastRun(schedule.id);
|
|
26
|
-
const task = schedule.prompt || `Run "triage" stand-up. Agenda: triage`;
|
|
27
|
-
addAuditEntry("schedule_triggered", `Schedule triggered for squad ${squadId}: ${task.slice(0, 200)}`, { squad_id: squadId, schedule_id: schedule.id, task: task.slice(0, 1000) }, { squad_id: squadId });
|
|
28
|
-
// Delegate directly to the squad lead — bypasses orchestrator rephrasing
|
|
29
|
-
delegateTask(squadId, task).catch((err) => {
|
|
30
|
-
const errMsg = err instanceof Error ? err.message : "Unknown error";
|
|
31
|
-
console.error(`[scheduler] Delegation failed for squad ${squadId}: ${errMsg}`);
|
|
32
|
-
addAuditEntry("schedule_error", `Scheduled delegation failed: ${errMsg}`, { squad_id: squadId, error: errMsg }, { squad_id: squadId });
|
|
33
|
-
});
|
|
34
|
-
console.log(`[scheduler] Task delegated to squad ${squadId}`);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
function isDue(cron, lastRun, now) {
|
|
38
|
-
// Simple cron matching: parse "minute hour day month weekday"
|
|
39
|
-
const parts = cron.split(" ");
|
|
40
|
-
if (parts.length !== 5)
|
|
41
|
-
return false;
|
|
42
|
-
const [minSpec, hourSpec, daySpec, monthSpec, weekdaySpec] = parts;
|
|
43
|
-
if (!matchesCronField(minSpec, now.getMinutes()))
|
|
44
|
-
return false;
|
|
45
|
-
if (!matchesCronField(hourSpec, now.getHours()))
|
|
46
|
-
return false;
|
|
47
|
-
if (!matchesCronField(daySpec, now.getDate()))
|
|
48
|
-
return false;
|
|
49
|
-
if (!matchesCronField(monthSpec, now.getMonth() + 1))
|
|
50
|
-
return false;
|
|
51
|
-
if (!matchesCronField(weekdaySpec, now.getDay()))
|
|
52
|
-
return false;
|
|
53
|
-
// Prevent running more than once per matching minute
|
|
54
|
-
if (lastRun) {
|
|
55
|
-
const lastDate = new Date(lastRun);
|
|
56
|
-
const diffMs = now.getTime() - lastDate.getTime();
|
|
57
|
-
if (diffMs < 60_000)
|
|
58
|
-
return false;
|
|
59
|
-
}
|
|
60
|
-
return true;
|
|
61
|
-
}
|
|
62
|
-
function matchesCronField(spec, value) {
|
|
63
|
-
if (spec === "*")
|
|
64
|
-
return true;
|
|
65
|
-
// Handle ranges (e.g., "1-5")
|
|
66
|
-
if (spec.includes("-")) {
|
|
67
|
-
const [start, end] = spec.split("-").map(Number);
|
|
68
|
-
return value >= start && value <= end;
|
|
69
|
-
}
|
|
70
|
-
// Handle lists (e.g., "1,3,5")
|
|
71
|
-
if (spec.includes(",")) {
|
|
72
|
-
return spec.split(",").map(Number).includes(value);
|
|
73
|
-
}
|
|
74
|
-
// Handle step values (e.g., "*/5")
|
|
75
|
-
if (spec.startsWith("*/")) {
|
|
76
|
-
const step = parseInt(spec.slice(2), 10);
|
|
77
|
-
return value % step === 0;
|
|
78
|
-
}
|
|
79
|
-
// Exact match
|
|
80
|
-
return parseInt(spec, 10) === value;
|
|
81
|
-
}
|
|
82
|
-
export function stopSquadScheduler() {
|
|
83
|
-
if (schedulerInterval) {
|
|
84
|
-
clearInterval(schedulerInterval);
|
|
85
|
-
schedulerInterval = undefined;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
//# sourceMappingURL=scheduler.js.map
|
package/dist/copilot/skills.js
DELETED
|
@@ -1,252 +0,0 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
-
import { join, basename, resolve, sep } from "node:path";
|
|
3
|
-
import { execFile } from "node:child_process";
|
|
4
|
-
import { promisify } from "node:util";
|
|
5
|
-
import { PATHS } from "../paths.js";
|
|
6
|
-
const execFileAsync = promisify(execFile);
|
|
7
|
-
export async function listSkills() {
|
|
8
|
-
if (!existsSync(PATHS.skills))
|
|
9
|
-
return [];
|
|
10
|
-
const entries = readdirSync(PATHS.skills, { withFileTypes: true });
|
|
11
|
-
const skills = [];
|
|
12
|
-
for (const entry of entries) {
|
|
13
|
-
if (!entry.isDirectory())
|
|
14
|
-
continue;
|
|
15
|
-
const skillMd = join(PATHS.skills, entry.name, "SKILL.md");
|
|
16
|
-
if (!existsSync(skillMd))
|
|
17
|
-
continue;
|
|
18
|
-
const content = readFileSync(skillMd, "utf-8");
|
|
19
|
-
const firstLine = content.split("\n").find((l) => l.startsWith("# "));
|
|
20
|
-
const name = firstLine?.replace(/^#\s+/, "") ?? entry.name;
|
|
21
|
-
const descLine = content
|
|
22
|
-
.split("\n")
|
|
23
|
-
.find((l) => l.trim() && !l.startsWith("#"));
|
|
24
|
-
const description = descLine?.trim() ?? "";
|
|
25
|
-
skills.push({
|
|
26
|
-
name,
|
|
27
|
-
slug: entry.name,
|
|
28
|
-
description,
|
|
29
|
-
path: join(PATHS.skills, entry.name),
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
return skills;
|
|
33
|
-
}
|
|
34
|
-
export async function addSkill(url) {
|
|
35
|
-
const slug = basename(url, ".git").replace(/[^a-z0-9-]/gi, "-").toLowerCase();
|
|
36
|
-
const dest = join(PATHS.skills, slug);
|
|
37
|
-
if (existsSync(dest)) {
|
|
38
|
-
throw new Error(`Skill "${slug}" is already installed.`);
|
|
39
|
-
}
|
|
40
|
-
await execFileAsync("git", ["clone", "--depth", "1", "--", url, dest]);
|
|
41
|
-
// Verify SKILL.md exists
|
|
42
|
-
if (!existsSync(join(dest, "SKILL.md"))) {
|
|
43
|
-
rmSync(dest, { recursive: true, force: true });
|
|
44
|
-
throw new Error("Repository does not contain a SKILL.md file.");
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
export async function removeSkill(slug) {
|
|
48
|
-
const dest = join(PATHS.skills, slug);
|
|
49
|
-
if (!existsSync(dest)) {
|
|
50
|
-
throw new Error(`Skill "${slug}" not found.`);
|
|
51
|
-
}
|
|
52
|
-
rmSync(dest, { recursive: true, force: true });
|
|
53
|
-
}
|
|
54
|
-
export async function getSkillContent(slug) {
|
|
55
|
-
const skillMd = join(PATHS.skills, slug, "SKILL.md");
|
|
56
|
-
if (!existsSync(skillMd)) {
|
|
57
|
-
throw new Error(`Skill "${slug}" not found.`);
|
|
58
|
-
}
|
|
59
|
-
return readFileSync(skillMd, "utf-8");
|
|
60
|
-
}
|
|
61
|
-
export async function updateSkillContent(slug, content) {
|
|
62
|
-
const skillMd = join(PATHS.skills, slug, "SKILL.md");
|
|
63
|
-
if (!existsSync(join(PATHS.skills, slug))) {
|
|
64
|
-
throw new Error(`Skill "${slug}" not found.`);
|
|
65
|
-
}
|
|
66
|
-
writeFileSync(skillMd, content);
|
|
67
|
-
}
|
|
68
|
-
export async function createSkill(slug, content) {
|
|
69
|
-
const cleanSlug = slug
|
|
70
|
-
.trim()
|
|
71
|
-
.replace(/[^a-z0-9-]/gi, "-")
|
|
72
|
-
.toLowerCase()
|
|
73
|
-
.replace(/-+/g, "-")
|
|
74
|
-
.replace(/^-|-$/g, "");
|
|
75
|
-
if (!cleanSlug) {
|
|
76
|
-
throw new Error("Skill title must contain at least one alphanumeric character.");
|
|
77
|
-
}
|
|
78
|
-
// Guard against path traversal: the resolved destination must be a direct
|
|
79
|
-
// child of the skills directory (not above or beside it).
|
|
80
|
-
const skillsRoot = resolve(PATHS.skills);
|
|
81
|
-
const dest = resolve(skillsRoot, cleanSlug);
|
|
82
|
-
if (!dest.startsWith(skillsRoot + sep)) {
|
|
83
|
-
throw new Error("Invalid skill slug.");
|
|
84
|
-
}
|
|
85
|
-
if (existsSync(dest)) {
|
|
86
|
-
throw new Error(`Skill "${cleanSlug}" already exists.`);
|
|
87
|
-
}
|
|
88
|
-
mkdirSync(dest, { recursive: true });
|
|
89
|
-
writeFileSync(join(dest, "SKILL.md"), content);
|
|
90
|
-
}
|
|
91
|
-
export async function loadSkillDirectories() {
|
|
92
|
-
if (!existsSync(PATHS.skills))
|
|
93
|
-
return [];
|
|
94
|
-
const entries = readdirSync(PATHS.skills, { withFileTypes: true });
|
|
95
|
-
return entries
|
|
96
|
-
.filter((e) => e.isDirectory() && existsSync(join(PATHS.skills, e.name, "SKILL.md")))
|
|
97
|
-
.map((e) => join(PATHS.skills, e.name));
|
|
98
|
-
}
|
|
99
|
-
export const GITHUB_REPO_PATH = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/;
|
|
100
|
-
export function isGitHubRepoPath(value) {
|
|
101
|
-
return GITHUB_REPO_PATH.test(value.trim());
|
|
102
|
-
}
|
|
103
|
-
const DISCOVERY_CACHE = new Map();
|
|
104
|
-
const CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes
|
|
105
|
-
/** Validate and return a safe slug, throwing if it contains unsafe characters. */
|
|
106
|
-
function validateSlug(slug) {
|
|
107
|
-
if (!slug || !/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/i.test(slug)) {
|
|
108
|
-
throw new Error("Invalid skill slug: must contain only letters, digits, and hyphens.");
|
|
109
|
-
}
|
|
110
|
-
return slug;
|
|
111
|
-
}
|
|
112
|
-
function parseAwesomeCopilotTable(markdown) {
|
|
113
|
-
const skills = [];
|
|
114
|
-
for (const line of markdown.split("\n")) {
|
|
115
|
-
if (!line.startsWith("|"))
|
|
116
|
-
continue;
|
|
117
|
-
const cells = line
|
|
118
|
-
.split("|")
|
|
119
|
-
.map((c) => c.trim())
|
|
120
|
-
.filter(Boolean);
|
|
121
|
-
if (cells.length < 2)
|
|
122
|
-
continue;
|
|
123
|
-
// First cell contains [slug](../skills/slug/SKILL.md)
|
|
124
|
-
const slugMatch = cells[0].match(/^\[([^\]]+)\]/);
|
|
125
|
-
if (!slugMatch)
|
|
126
|
-
continue;
|
|
127
|
-
const slug = slugMatch[1];
|
|
128
|
-
if (slug === "Name")
|
|
129
|
-
continue; // header row
|
|
130
|
-
// Second cell is the description (may contain <br /> markup)
|
|
131
|
-
const description = cells[1]
|
|
132
|
-
.replace(/<br\s*\/?>/gi, " ")
|
|
133
|
-
.replace(/\*\*([^*]+)\*\*/g, "$1")
|
|
134
|
-
.trim();
|
|
135
|
-
if (!description || description === "Description")
|
|
136
|
-
continue;
|
|
137
|
-
skills.push({ slug, name: slug, description, source: "awesome-copilot" });
|
|
138
|
-
}
|
|
139
|
-
return skills;
|
|
140
|
-
}
|
|
141
|
-
async function fetchAwesomeCopilotSkills() {
|
|
142
|
-
const url = "https://raw.githubusercontent.com/github/awesome-copilot/main/docs/README.skills.md";
|
|
143
|
-
const res = await fetch(url, { signal: AbortSignal.timeout(15_000) });
|
|
144
|
-
if (!res.ok)
|
|
145
|
-
throw new Error(`Failed to fetch awesome-copilot skills list: HTTP ${res.status}`);
|
|
146
|
-
const text = await res.text();
|
|
147
|
-
return parseAwesomeCopilotTable(text);
|
|
148
|
-
}
|
|
149
|
-
async function fetchSkillsShSkills(query) {
|
|
150
|
-
try {
|
|
151
|
-
const searchQuery = query?.trim() || "";
|
|
152
|
-
const url = `https://skills.sh/api/search?q=${encodeURIComponent(searchQuery)}`;
|
|
153
|
-
const res = await fetch(url, {
|
|
154
|
-
headers: { Accept: "application/json" },
|
|
155
|
-
signal: AbortSignal.timeout(10_000),
|
|
156
|
-
});
|
|
157
|
-
if (!res.ok)
|
|
158
|
-
return [];
|
|
159
|
-
const data = (await res.json());
|
|
160
|
-
return data.skills
|
|
161
|
-
.map((item) => ({
|
|
162
|
-
slug: item.skillId || item.name || "",
|
|
163
|
-
name: item.name || item.skillId || "",
|
|
164
|
-
description: "",
|
|
165
|
-
source: "skillssh",
|
|
166
|
-
sourceRepo: item.source,
|
|
167
|
-
installs: item.installs,
|
|
168
|
-
}))
|
|
169
|
-
.filter((item) => item.sourceRepo ? isGitHubRepoPath(item.sourceRepo) : false);
|
|
170
|
-
}
|
|
171
|
-
catch {
|
|
172
|
-
return [];
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
export async function discoverSkills(source, query) {
|
|
176
|
-
// For skills.sh, use the search API directly with the query
|
|
177
|
-
if (source === "skillssh") {
|
|
178
|
-
return fetchSkillsShSkills(query);
|
|
179
|
-
}
|
|
180
|
-
// For awesome-copilot, use caching and client-side filtering
|
|
181
|
-
const cached = DISCOVERY_CACHE.get(source);
|
|
182
|
-
let skills;
|
|
183
|
-
if (cached && Date.now() - cached.fetchedAt < CACHE_TTL_MS) {
|
|
184
|
-
skills = cached.skills;
|
|
185
|
-
}
|
|
186
|
-
else {
|
|
187
|
-
skills = await fetchAwesomeCopilotSkills();
|
|
188
|
-
DISCOVERY_CACHE.set(source, { skills, fetchedAt: Date.now() });
|
|
189
|
-
}
|
|
190
|
-
if (query) {
|
|
191
|
-
const q = query.toLowerCase();
|
|
192
|
-
skills = skills.filter((s) => s.slug.toLowerCase().includes(q) || s.description.toLowerCase().includes(q));
|
|
193
|
-
}
|
|
194
|
-
return skills;
|
|
195
|
-
}
|
|
196
|
-
/**
|
|
197
|
-
* Find the path to SKILL.md in a GitHub repo by searching the repo tree.
|
|
198
|
-
* Returns the full path (e.g., "skills/features/clerk-testing/SKILL.md").
|
|
199
|
-
*/
|
|
200
|
-
async function findSkillPathInRepo(repoPath, skillId) {
|
|
201
|
-
const treeUrl = `https://api.github.com/repos/${repoPath}/git/trees/main?recursive=1`;
|
|
202
|
-
const res = await fetch(treeUrl, { signal: AbortSignal.timeout(10_000) });
|
|
203
|
-
if (!res.ok) {
|
|
204
|
-
throw new Error(`Failed to fetch repo tree for "${repoPath}": HTTP ${res.status}`);
|
|
205
|
-
}
|
|
206
|
-
const data = (await res.json());
|
|
207
|
-
// Look for a SKILL.md file in a folder named after the skillId
|
|
208
|
-
const targetSuffix = `${skillId}/SKILL.md`;
|
|
209
|
-
const match = data.tree.find((item) => item.type === "blob" && item.path.endsWith(targetSuffix));
|
|
210
|
-
if (!match) {
|
|
211
|
-
throw new Error(`Could not find SKILL.md for "${skillId}" in repo "${repoPath}"`);
|
|
212
|
-
}
|
|
213
|
-
return match.path;
|
|
214
|
-
}
|
|
215
|
-
function remoteSkillMdUrl(source, safeSlug) {
|
|
216
|
-
const encodedSlug = encodeURIComponent(safeSlug);
|
|
217
|
-
if (source === "awesome-copilot") {
|
|
218
|
-
return `https://raw.githubusercontent.com/github/awesome-copilot/main/skills/${encodedSlug}/SKILL.md`;
|
|
219
|
-
}
|
|
220
|
-
// Legacy fallback for skillssh without sourceRepo (shouldn't be used anymore)
|
|
221
|
-
return `https://skills.sh/skills/${encodedSlug}/SKILL.md`;
|
|
222
|
-
}
|
|
223
|
-
export async function fetchRemoteSkillPreview(source, slug, sourceRepo) {
|
|
224
|
-
const safeSlug = validateSlug(slug);
|
|
225
|
-
// For skillssh with a sourceRepo, use GitHub directly
|
|
226
|
-
if (source === "skillssh" && sourceRepo) {
|
|
227
|
-
const skillPath = await findSkillPathInRepo(sourceRepo, safeSlug);
|
|
228
|
-
const rawUrl = `https://raw.githubusercontent.com/${sourceRepo}/main/${skillPath}`;
|
|
229
|
-
const res = await fetch(rawUrl, { signal: AbortSignal.timeout(10_000) });
|
|
230
|
-
if (!res.ok) {
|
|
231
|
-
throw new Error(`Failed to fetch preview for "${safeSlug}": HTTP ${res.status}`);
|
|
232
|
-
}
|
|
233
|
-
return res.text();
|
|
234
|
-
}
|
|
235
|
-
// Fallback to legacy URL approach
|
|
236
|
-
const url = remoteSkillMdUrl(source, safeSlug);
|
|
237
|
-
const res = await fetch(url, { signal: AbortSignal.timeout(10_000) });
|
|
238
|
-
if (!res.ok)
|
|
239
|
-
throw new Error(`Failed to fetch preview for "${safeSlug}": HTTP ${res.status}`);
|
|
240
|
-
return res.text();
|
|
241
|
-
}
|
|
242
|
-
export async function installFromSource(source, slug, sourceRepo) {
|
|
243
|
-
const safeSlug = validateSlug(slug);
|
|
244
|
-
const dest = join(PATHS.skills, safeSlug);
|
|
245
|
-
if (existsSync(dest)) {
|
|
246
|
-
throw new Error(`Skill "${safeSlug}" is already installed.`);
|
|
247
|
-
}
|
|
248
|
-
const content = await fetchRemoteSkillPreview(source, safeSlug, sourceRepo);
|
|
249
|
-
mkdirSync(dest, { recursive: true });
|
|
250
|
-
writeFileSync(join(dest, "SKILL.md"), content);
|
|
251
|
-
}
|
|
252
|
-
//# sourceMappingURL=skills.js.map
|
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
import { approveAll } from "@github/copilot-sdk";
|
|
2
|
-
import { getClient } from "./client.js";
|
|
3
|
-
import { selectModel, classifyComplexity } from "./model-router.js";
|
|
4
|
-
import { attachTokenTracker } from "./token-tracker.js";
|
|
5
|
-
import { createSquadTools } from "./squad-tools.js";
|
|
6
|
-
import { loadSkillDirectories } from "./skills.js";
|
|
7
|
-
import { getMcpServersForSession } from "../mcp/registry.js";
|
|
8
|
-
import { addAgentEvent } from "../store/agent-events.js";
|
|
9
|
-
import { addAuditEntry } from "../store/audit-log.js";
|
|
10
|
-
import { updateAgentStatus } from "../store/squads.js";
|
|
11
|
-
import { touchInstanceActivity } from "../store/instances.js";
|
|
12
|
-
/**
|
|
13
|
-
* Build the system message for a specialist agent session.
|
|
14
|
-
* Wiki knowledge is placed at the END for maximum LLM attention (recency bias).
|
|
15
|
-
*/
|
|
16
|
-
function buildSpecialistSystemMessage(agent, squad, wikiKnowledge, roster) {
|
|
17
|
-
return `# Squad Specialist: ${agent.character_name}
|
|
18
|
-
|
|
19
|
-
## 🚨 CRITICAL SECURITY RULE — ABSOLUTE, NON-NEGOTIABLE 🚨
|
|
20
|
-
|
|
21
|
-
You must NEVER expose secrets, credentials, or sensitive values in ANY publicly visible location. This includes:
|
|
22
|
-
- GitHub issues, pull requests, PR descriptions, comments, or commit messages
|
|
23
|
-
- Log output, error messages, or stack traces shared externally
|
|
24
|
-
- Wiki pages, feed items, or any content viewable by others
|
|
25
|
-
|
|
26
|
-
What counts as a secret: API keys, access tokens, passwords, connection strings, environment variable values, private config file contents, SSH keys, certificates, webhook URLs with tokens.
|
|
27
|
-
|
|
28
|
-
If you need to reference that a secret exists, use \`<REDACTED>\` or \`***\` as a placeholder. NEVER include the actual value.
|
|
29
|
-
|
|
30
|
-
Violation of this rule is a HARD FAILURE — no exceptions, no workarounds, no "just this once."
|
|
31
|
-
|
|
32
|
-
## Identity & Role
|
|
33
|
-
|
|
34
|
-
You are **${agent.character_name}**, a **${agent.role_title}** on the ${squad.name} squad.
|
|
35
|
-
You are an independent specialist — you execute implementation work within your domain of expertise.
|
|
36
|
-
|
|
37
|
-
## Your Responsibilities:
|
|
38
|
-
1. Execute the assigned sub-task fully and correctly
|
|
39
|
-
2. Write clean, tested, production-quality code
|
|
40
|
-
3. Follow project conventions and existing patterns
|
|
41
|
-
4. Commit work to the appropriate branch
|
|
42
|
-
5. Report completion or blockers clearly
|
|
43
|
-
|
|
44
|
-
## Squad Wiki = Your Source of Truth
|
|
45
|
-
Your squad wiki contains workflow rules set by the project owner. Read it (use \`wiki_read\`) and follow those rules exactly — branching, PR process, review format, merge criteria. If your task involves reviewing a PR, follow the wiki's review process precisely.
|
|
46
|
-
|
|
47
|
-
## Your Team (for context):
|
|
48
|
-
${roster}
|
|
49
|
-
|
|
50
|
-
## Workflow Rules:
|
|
51
|
-
- Always use the gh CLI for GitHub interactions
|
|
52
|
-
- Use \`--comment\` with "LGTM" for approvals (not \`--approve\`)
|
|
53
|
-
- When your work is complete, provide a clear summary of what was done
|
|
54
|
-
- Consult the squad wiki (wiki_read) for additional context when needed
|
|
55
|
-
- Follow all squad rules from the wiki — they are non-negotiable
|
|
56
|
-
${wikiKnowledge}
|
|
57
|
-
${agent.persona ? `## Personality:\n${agent.persona}` : ""}
|
|
58
|
-
`;
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* Run a specialist agent session independently.
|
|
62
|
-
* Creates a full Copilot SDK session with tools, executes the task, returns the result.
|
|
63
|
-
*/
|
|
64
|
-
export async function runSpecialistSession(request) {
|
|
65
|
-
const { agent, squad, squadSlug, squadId, task, wikiKnowledge, workDir, instanceId, parentTaskId } = request;
|
|
66
|
-
// Select model based on task complexity
|
|
67
|
-
const tier = classifyComplexity(task);
|
|
68
|
-
const model = await selectModel(tier);
|
|
69
|
-
// Build roster for context
|
|
70
|
-
const { getAgentsForSquad } = await import("../store/squads.js");
|
|
71
|
-
const agents = getAgentsForSquad(squadId);
|
|
72
|
-
const roster = agents
|
|
73
|
-
.map((a) => `- ${a.character_name} (${a.role_title})${a.is_lead ? " [LEAD]" : ""}${a.is_qa ? " [QA]" : ""}${a.is_test ? " [TEST]" : ""}`)
|
|
74
|
-
.join("\n");
|
|
75
|
-
const systemMessage = buildSpecialistSystemMessage(agent, squad, wikiKnowledge, roster);
|
|
76
|
-
// Update agent status
|
|
77
|
-
updateAgentStatus(agent.id, "working");
|
|
78
|
-
// Touch instance activity
|
|
79
|
-
if (instanceId) {
|
|
80
|
-
touchInstanceActivity(instanceId);
|
|
81
|
-
}
|
|
82
|
-
// Audit: specialist task started
|
|
83
|
-
addAuditEntry("specialist_task_started", `Specialist task delegated to ${agent.character_name} (${agent.role_title})`, { task: task.slice(0, 500), model, parentTaskId }, { squad_id: squadId, agent_id: agent.id });
|
|
84
|
-
addAgentEvent(parentTaskId, "status", `Sub-task delegated to specialist ${agent.character_name} (${agent.role_title})`, {
|
|
85
|
-
agent: agent.character_name,
|
|
86
|
-
role: agent.role_title,
|
|
87
|
-
task: task.slice(0, 300),
|
|
88
|
-
});
|
|
89
|
-
const client = await getClient();
|
|
90
|
-
try {
|
|
91
|
-
// Load squad-scoped tools, skills, and MCP servers
|
|
92
|
-
const squadTools = createSquadTools(squadSlug, squadId, squad.repo_url);
|
|
93
|
-
const skillDirs = await loadSkillDirectories();
|
|
94
|
-
const mcpServers = getMcpServersForSession();
|
|
95
|
-
const session = await client.createSession({
|
|
96
|
-
model,
|
|
97
|
-
streaming: true,
|
|
98
|
-
workingDirectory: workDir,
|
|
99
|
-
systemMessage: { content: systemMessage },
|
|
100
|
-
tools: squadTools,
|
|
101
|
-
skillDirectories: skillDirs,
|
|
102
|
-
mcpServers,
|
|
103
|
-
onPermissionRequest: approveAll,
|
|
104
|
-
infiniteSessions: {
|
|
105
|
-
enabled: true,
|
|
106
|
-
backgroundCompactionThreshold: 0.8,
|
|
107
|
-
bufferExhaustionThreshold: 0.95,
|
|
108
|
-
},
|
|
109
|
-
});
|
|
110
|
-
const flushTokens = attachTokenTracker(session, {
|
|
111
|
-
squadId,
|
|
112
|
-
agentId: agent.id,
|
|
113
|
-
taskId: parentTaskId,
|
|
114
|
-
});
|
|
115
|
-
// Stream deltas and broadcast via SSE
|
|
116
|
-
let accumulatedMessage = "";
|
|
117
|
-
const { broadcast } = await import("../api/server.js");
|
|
118
|
-
const unsubscribeDelta = session.on("assistant.message_delta", (event) => {
|
|
119
|
-
const delta = event.data?.deltaContent ?? "";
|
|
120
|
-
if (delta) {
|
|
121
|
-
accumulatedMessage += delta;
|
|
122
|
-
broadcast("agent_event", {
|
|
123
|
-
taskId: parentTaskId,
|
|
124
|
-
agentName: agent.character_name,
|
|
125
|
-
type: "specialist_delta",
|
|
126
|
-
summary: accumulatedMessage,
|
|
127
|
-
payload: { delta, accumulated: accumulatedMessage },
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
});
|
|
131
|
-
let result;
|
|
132
|
-
try {
|
|
133
|
-
const response = await session.sendAndWait({ prompt: `You have been assigned the following sub-task by your team lead:\n\n${task}\n\nExecute this task fully. When done, provide a clear summary of what was accomplished.` }, 7_200_000 // 2 hours — watchdog handles stale detection
|
|
134
|
-
);
|
|
135
|
-
result = response?.data?.content ?? "Task completed (no response content).";
|
|
136
|
-
}
|
|
137
|
-
finally {
|
|
138
|
-
unsubscribeDelta();
|
|
139
|
-
flushTokens();
|
|
140
|
-
await session.disconnect();
|
|
141
|
-
}
|
|
142
|
-
// Record completion
|
|
143
|
-
addAgentEvent(parentTaskId, "status", `Specialist ${agent.character_name} completed sub-task`, {
|
|
144
|
-
agent: agent.character_name,
|
|
145
|
-
role: agent.role_title,
|
|
146
|
-
result: result.slice(0, 500),
|
|
147
|
-
});
|
|
148
|
-
addAuditEntry("specialist_task_completed", `Specialist ${agent.character_name} completed task`, { result: result.slice(0, 500) }, { squad_id: squadId, agent_id: agent.id });
|
|
149
|
-
updateAgentStatus(agent.id, "idle");
|
|
150
|
-
return {
|
|
151
|
-
agentName: agent.character_name,
|
|
152
|
-
role: agent.role_title,
|
|
153
|
-
success: true,
|
|
154
|
-
result,
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
catch (err) {
|
|
158
|
-
const errMsg = err instanceof Error ? err.message : "Unknown error";
|
|
159
|
-
addAgentEvent(parentTaskId, "status", `Specialist ${agent.character_name} failed: ${errMsg}`, {
|
|
160
|
-
agent: agent.character_name,
|
|
161
|
-
error: errMsg,
|
|
162
|
-
});
|
|
163
|
-
addAuditEntry("specialist_task_failed", `Specialist ${agent.character_name} failed: ${errMsg.slice(0, 200)}`, { error: errMsg }, { squad_id: squadId, agent_id: agent.id });
|
|
164
|
-
updateAgentStatus(agent.id, "idle");
|
|
165
|
-
return {
|
|
166
|
-
agentName: agent.character_name,
|
|
167
|
-
role: agent.role_title,
|
|
168
|
-
success: false,
|
|
169
|
-
result: `Error: ${errMsg}`,
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
/**
|
|
174
|
-
* Run multiple specialist sessions in parallel.
|
|
175
|
-
* Returns results in the same order as the input requests.
|
|
176
|
-
*/
|
|
177
|
-
export async function runSpecialistsParallel(requests) {
|
|
178
|
-
const results = await Promise.allSettled(requests.map(runSpecialistSession));
|
|
179
|
-
return results.map((r, i) => {
|
|
180
|
-
if (r.status === "fulfilled") {
|
|
181
|
-
return r.value;
|
|
182
|
-
}
|
|
183
|
-
return {
|
|
184
|
-
agentName: requests[i].agent.character_name,
|
|
185
|
-
role: requests[i].agent.role_title,
|
|
186
|
-
success: false,
|
|
187
|
-
result: `Session error: ${r.reason instanceof Error ? r.reason.message : "Unknown error"}`,
|
|
188
|
-
};
|
|
189
|
-
});
|
|
190
|
-
}
|
|
191
|
-
//# sourceMappingURL=specialist-runner.js.map
|