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/agents.js
DELETED
|
@@ -1,309 +0,0 @@
|
|
|
1
|
-
import { approveAll } from "@github/copilot-sdk";
|
|
2
|
-
import { getClient } from "./client.js";
|
|
3
|
-
import { getLeadForSquad, getAgentsForSquad, updateAgentStatus, getSquad } from "../store/squads.js";
|
|
4
|
-
import { createTask, updateTaskStatus, getTask } from "../store/tasks.js";
|
|
5
|
-
import { touchInstanceActivity, getInstance } from "../store/instances.js";
|
|
6
|
-
import { selectModel, classifyComplexity } from "./model-router.js";
|
|
7
|
-
import { postFeedItem } from "../store/feed.js";
|
|
8
|
-
import { attachTokenTracker } from "./token-tracker.js";
|
|
9
|
-
import { addAuditEntry } from "../store/audit-log.js";
|
|
10
|
-
import { addAgentEvent } from "../store/agent-events.js";
|
|
11
|
-
import { PATHS } from "../paths.js";
|
|
12
|
-
import { createSquadTools, createLeadDelegationTools } from "./squad-tools.js";
|
|
13
|
-
import { loadSkillDirectories } from "./skills.js";
|
|
14
|
-
import { getMcpServersForSession } from "../mcp/registry.js";
|
|
15
|
-
import { buildAttachmentPathSummary, saveAttachmentsToDisk, toCopilotBlobAttachments } from "../chat/attachments.js";
|
|
16
|
-
import { existsSync, mkdirSync } from "node:fs";
|
|
17
|
-
import { join } from "node:path";
|
|
18
|
-
import { exec } from "node:child_process";
|
|
19
|
-
import { promisify } from "node:util";
|
|
20
|
-
import { logWarn } from "../logging.js";
|
|
21
|
-
const execAsync = promisify(exec);
|
|
22
|
-
// Registry of active agent sessions keyed by task ID
|
|
23
|
-
const activeSessions = new Map();
|
|
24
|
-
/**
|
|
25
|
-
* Resolve the working directory for a squad agent session.
|
|
26
|
-
* Priority: instance worktree → cloned repo → process.cwd()
|
|
27
|
-
*/
|
|
28
|
-
async function resolveSquadWorkingDirectory(squad, instanceId) {
|
|
29
|
-
// If an instance is specified, use its worktree path
|
|
30
|
-
if (instanceId) {
|
|
31
|
-
const instance = getInstance(instanceId);
|
|
32
|
-
if (instance?.worktree_path && existsSync(instance.worktree_path)) {
|
|
33
|
-
return instance.worktree_path;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
// Derive from squad repo_url → ~/.io/source/{owner}/{repo}
|
|
37
|
-
if (squad.repo_url) {
|
|
38
|
-
const match = squad.repo_url.match(/[/:]([^/]+)\/([^/.]+?)(?:\.git)?$/);
|
|
39
|
-
if (match) {
|
|
40
|
-
const [, owner, repo] = match;
|
|
41
|
-
const sourceDir = join(PATHS.source, owner, repo);
|
|
42
|
-
if (existsSync(sourceDir)) {
|
|
43
|
-
return sourceDir;
|
|
44
|
-
}
|
|
45
|
-
// Attempt to clone if missing
|
|
46
|
-
const parentDir = join(PATHS.source, owner);
|
|
47
|
-
if (!existsSync(parentDir))
|
|
48
|
-
mkdirSync(parentDir, { recursive: true });
|
|
49
|
-
try {
|
|
50
|
-
await execAsync(`git clone ${squad.repo_url} ${sourceDir}`, { timeout: 120_000 });
|
|
51
|
-
return sourceDir;
|
|
52
|
-
}
|
|
53
|
-
catch (err) {
|
|
54
|
-
logWarn("Failed to clone squad repository, falling back to current working directory", { repoUrl: squad.repo_url }, err);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
return process.cwd();
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* Stop a running agent by task ID. Disconnects the session and marks the task as stopped.
|
|
62
|
-
*/
|
|
63
|
-
export async function stopTask(taskId) {
|
|
64
|
-
const session = activeSessions.get(taskId);
|
|
65
|
-
if (!session) {
|
|
66
|
-
throw new Error(`Task is not currently running or has already completed`);
|
|
67
|
-
}
|
|
68
|
-
try {
|
|
69
|
-
await session.disconnect();
|
|
70
|
-
}
|
|
71
|
-
finally {
|
|
72
|
-
activeSessions.delete(taskId);
|
|
73
|
-
}
|
|
74
|
-
updateTaskStatus(taskId, "stopped", "Stopped by user");
|
|
75
|
-
addAgentEvent(taskId, "status", "Task stopped by user", { reason: "user_requested" });
|
|
76
|
-
// Reset agent status to idle
|
|
77
|
-
const task = getTask(taskId);
|
|
78
|
-
if (task?.agent_id) {
|
|
79
|
-
updateAgentStatus(task.agent_id, "idle");
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
export async function delegateTask(squadId, task, instanceId, attachments = []) {
|
|
83
|
-
const lead = getLeadForSquad(squadId);
|
|
84
|
-
if (!lead) {
|
|
85
|
-
throw new Error("Squad has no team lead. Add a lead agent first.");
|
|
86
|
-
}
|
|
87
|
-
const squad = getSquad(squadId);
|
|
88
|
-
const squadSlug = squad?.slug ?? squadId;
|
|
89
|
-
const agents = getAgentsForSquad(squadId);
|
|
90
|
-
const taskRecord = createTask(squadId, task, instanceId, lead.id);
|
|
91
|
-
// Update lead status
|
|
92
|
-
updateAgentStatus(lead.id, "working");
|
|
93
|
-
// Touch instance activity if applicable
|
|
94
|
-
if (instanceId) {
|
|
95
|
-
touchInstanceActivity(instanceId);
|
|
96
|
-
}
|
|
97
|
-
// Select model based on task complexity
|
|
98
|
-
const tier = classifyComplexity(task);
|
|
99
|
-
const model = await selectModel(tier);
|
|
100
|
-
// Audit: task delegated
|
|
101
|
-
addAuditEntry("task_delegated", `Task delegated to ${lead.character_name} (${lead.role_title})`, { task: task.slice(0, 500), model }, { squad_id: squadId, agent_id: lead.id, task_id: taskRecord.id });
|
|
102
|
-
// Create ephemeral agent session for the lead
|
|
103
|
-
const client = await getClient();
|
|
104
|
-
const agentRoster = agents
|
|
105
|
-
.map((a) => `- ${a.character_name} (${a.role_title})${a.is_lead ? " [LEAD]" : ""}${a.is_qa ? " [QA]" : ""}${a.is_test ? " [TEST]" : ""}`)
|
|
106
|
-
.join("\n");
|
|
107
|
-
// Load squad wiki pages as immutable knowledge context
|
|
108
|
-
const { listPages, readPage } = await import("../wiki/fs.js");
|
|
109
|
-
const wikiPrefix = `squads/${squadSlug}`;
|
|
110
|
-
let wikiKnowledge = "";
|
|
111
|
-
try {
|
|
112
|
-
const pages = await listPages(wikiPrefix);
|
|
113
|
-
const pageContents = [];
|
|
114
|
-
for (const page of pages.slice(0, 20)) { // Cap at 20 pages to avoid token overload
|
|
115
|
-
try {
|
|
116
|
-
const content = await readPage(`${wikiPrefix}/${page}`);
|
|
117
|
-
pageContents.push(`### ${page}\n${content}`);
|
|
118
|
-
}
|
|
119
|
-
catch {
|
|
120
|
-
// Skip unreadable pages
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
if (pageContents.length > 0) {
|
|
124
|
-
wikiKnowledge = `\n## ⚠️ MANDATORY SQUAD RULES & KNOWLEDGE (from squad wiki)\n\nThese rules were written by the project owner specifically for this squad. You MUST follow them in ALL work — every task, every PR, every decision. Violating them is a critical failure.\n\nBefore starting any task, re-read these rules. Before submitting any PR or review, verify compliance.\n\n${pageContents.join("\n\n---\n\n")}\n`;
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
catch {
|
|
128
|
-
// Wiki not available — proceed without
|
|
129
|
-
}
|
|
130
|
-
const systemMessage = `# Squad Team Lead: ${lead.character_name}
|
|
131
|
-
|
|
132
|
-
## 🚨 CRITICAL SECURITY RULE — ABSOLUTE, NON-NEGOTIABLE 🚨
|
|
133
|
-
|
|
134
|
-
You must NEVER expose secrets, credentials, or sensitive values in ANY publicly visible location. This includes:
|
|
135
|
-
- GitHub issues, pull requests, PR descriptions, comments, or commit messages
|
|
136
|
-
- Log output, error messages, or stack traces shared externally
|
|
137
|
-
- Wiki pages, feed items, or any content viewable by others
|
|
138
|
-
|
|
139
|
-
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.
|
|
140
|
-
|
|
141
|
-
If you need to reference that a secret exists, use \`<REDACTED>\` or \`***\` as a placeholder. NEVER include the actual value.
|
|
142
|
-
|
|
143
|
-
Violation of this rule is a HARD FAILURE — no exceptions, no workarounds, no "just this once."
|
|
144
|
-
|
|
145
|
-
## Identity & Role
|
|
146
|
-
|
|
147
|
-
You are ${lead.character_name}, the team lead for this squad. Your PRIMARY role is coordination and delegation — you break down tasks and route implementation work to specialists via the \`delegate_to_specialist\` or \`delegate_to_specialists_parallel\` tools.
|
|
148
|
-
|
|
149
|
-
## How Delegation Works
|
|
150
|
-
|
|
151
|
-
When you call \`delegate_to_specialist\`, a **real, independent AI agent session** is spawned for that specialist. They have:
|
|
152
|
-
- Their own full Copilot session with shell access, tools, and MCP servers
|
|
153
|
-
- The squad wiki rules (immutable — they MUST follow them too)
|
|
154
|
-
- Complete autonomy to implement their assigned sub-task
|
|
155
|
-
|
|
156
|
-
This means specialists work IN PARALLEL with you and with each other. Use \`delegate_to_specialists_parallel\` when multiple independent sub-tasks can run concurrently.
|
|
157
|
-
|
|
158
|
-
## Your Responsibilities:
|
|
159
|
-
1. Break down tasks into smaller pieces and delegate to specialists
|
|
160
|
-
2. Route work to the appropriate specialist based on their role
|
|
161
|
-
3. Use \`delegate_to_specialists_parallel\` for independent sub-tasks (faster!)
|
|
162
|
-
4. Orchestrate the full review/merge process as defined in your squad wiki
|
|
163
|
-
5. Ensure quality gates are met before merging
|
|
164
|
-
6. Report progress and blockers via feed_post
|
|
165
|
-
|
|
166
|
-
## IMPORTANT — Prefer Delegation:
|
|
167
|
-
- For implementation work (writing code, running tests, creating PRs), ALWAYS delegate to the appropriate specialist
|
|
168
|
-
- For code review, delegate to squad members so they can independently review and post their own comments
|
|
169
|
-
- You may perform coordination tasks directly: reading issues, checking CI status, promoting PRs, merging PRs
|
|
170
|
-
- If no suitable specialist exists for a sub-task, report that back — do NOT attempt implementation yourself
|
|
171
|
-
|
|
172
|
-
## Your Team:
|
|
173
|
-
${agentRoster}
|
|
174
|
-
|
|
175
|
-
## 🔒 SQUAD WIKI = YOUR SOURCE OF TRUTH
|
|
176
|
-
|
|
177
|
-
Your squad wiki contains your **authoritative workflow rules** — branching conventions, PR process, review requirements, merge criteria, labeling, and any squad-specific constraints.
|
|
178
|
-
|
|
179
|
-
**Before starting ANY task:**
|
|
180
|
-
1. Read your squad wiki (use \`wiki_read\` or \`wiki_list\` to find relevant pages)
|
|
181
|
-
2. Follow those rules EXACTLY — they are non-negotiable instructions from the project owner
|
|
182
|
-
3. Do NOT invent your own workflow or skip steps defined in the wiki
|
|
183
|
-
|
|
184
|
-
**If the wiki says all members must review → delegate reviews to all members.**
|
|
185
|
-
**If the wiki says only veto members must approve → ensure veto members approve.**
|
|
186
|
-
**If the wiki defines merge criteria → follow them precisely.**
|
|
187
|
-
|
|
188
|
-
Failure to follow squad wiki rules is a CRITICAL FAILURE.
|
|
189
|
-
|
|
190
|
-
## General Rules:
|
|
191
|
-
- Always use the gh CLI for GitHub interactions
|
|
192
|
-
- Use \`--comment\` for review approvals (not \`--approve\` — GitHub blocks self-approval)
|
|
193
|
-
- When work is complete, ALWAYS notify the user via feed_post with a summary
|
|
194
|
-
${wikiKnowledge}
|
|
195
|
-
${lead.persona ? `## Personality:\n${lead.persona}` : ""}
|
|
196
|
-
`;
|
|
197
|
-
let result;
|
|
198
|
-
try {
|
|
199
|
-
// Load squad-scoped tools, skills, and MCP servers
|
|
200
|
-
const squadTools = createSquadTools(squadSlug, squadId, squad?.repo_url);
|
|
201
|
-
const skillDirs = await loadSkillDirectories();
|
|
202
|
-
const mcpServers = getMcpServersForSession();
|
|
203
|
-
// Resolve correct working directory for the squad's project
|
|
204
|
-
const workDir = await resolveSquadWorkingDirectory(squad, instanceId);
|
|
205
|
-
// Create lead-specific delegation tools (allows spawning real specialist sessions)
|
|
206
|
-
const leadTools = createLeadDelegationTools(squadId, squadSlug, squad, wikiKnowledge, workDir, taskRecord.id, instanceId);
|
|
207
|
-
const session = await client.createSession({
|
|
208
|
-
model,
|
|
209
|
-
streaming: true,
|
|
210
|
-
workingDirectory: workDir,
|
|
211
|
-
systemMessage: { content: systemMessage },
|
|
212
|
-
tools: [...squadTools, ...leadTools],
|
|
213
|
-
skillDirectories: skillDirs,
|
|
214
|
-
mcpServers,
|
|
215
|
-
onPermissionRequest: approveAll,
|
|
216
|
-
infiniteSessions: {
|
|
217
|
-
enabled: true,
|
|
218
|
-
backgroundCompactionThreshold: 0.8,
|
|
219
|
-
bufferExhaustionThreshold: 0.95,
|
|
220
|
-
},
|
|
221
|
-
});
|
|
222
|
-
// Register session so it can be stopped externally
|
|
223
|
-
activeSessions.set(taskRecord.id, session);
|
|
224
|
-
const flushTokens = attachTokenTracker(session, {
|
|
225
|
-
squadId,
|
|
226
|
-
agentId: lead.id,
|
|
227
|
-
taskId: taskRecord.id,
|
|
228
|
-
});
|
|
229
|
-
try {
|
|
230
|
-
// Mark task as in progress and record start event
|
|
231
|
-
updateTaskStatus(taskRecord.id, "in_progress");
|
|
232
|
-
addAgentEvent(taskRecord.id, "status", `Task started by ${lead.character_name}`, {
|
|
233
|
-
agent: lead.character_name,
|
|
234
|
-
role: lead.role_title,
|
|
235
|
-
task,
|
|
236
|
-
attachments: attachments.map((attachment) => ({
|
|
237
|
-
name: attachment.name,
|
|
238
|
-
mimeType: attachment.mimeType,
|
|
239
|
-
size: attachment.size,
|
|
240
|
-
})),
|
|
241
|
-
});
|
|
242
|
-
// Capture streaming message deltas and broadcast via SSE
|
|
243
|
-
let accumulatedMessage = "";
|
|
244
|
-
const { broadcast } = await import("../api/server.js");
|
|
245
|
-
const unsubscribeDelta = session.on("assistant.message_delta", (event) => {
|
|
246
|
-
const delta = event.data?.deltaContent ?? "";
|
|
247
|
-
if (delta) {
|
|
248
|
-
accumulatedMessage += delta;
|
|
249
|
-
broadcast("agent_event", {
|
|
250
|
-
taskId: taskRecord.id,
|
|
251
|
-
type: "message_delta",
|
|
252
|
-
summary: accumulatedMessage,
|
|
253
|
-
payload: { delta, accumulated: accumulatedMessage },
|
|
254
|
-
});
|
|
255
|
-
}
|
|
256
|
-
});
|
|
257
|
-
try {
|
|
258
|
-
// Save attachments to disk so squad agents can access them via shell_exec
|
|
259
|
-
const savedAttachments = saveAttachmentsToDisk(attachments);
|
|
260
|
-
const attachmentPathInfo = buildAttachmentPathSummary(savedAttachments);
|
|
261
|
-
const response = await session.sendAndWait({
|
|
262
|
-
prompt: `Task delegated to you:\n\n${task}${attachmentPathInfo}`,
|
|
263
|
-
attachments: toCopilotBlobAttachments(attachments),
|
|
264
|
-
}, 7_200_000 // 2 hours — watchdog handles stale detection
|
|
265
|
-
);
|
|
266
|
-
result = response?.data?.content ?? "Task completed (no response content).";
|
|
267
|
-
// Record the final message event if we have meaningful content
|
|
268
|
-
if (accumulatedMessage.trim()) {
|
|
269
|
-
addAgentEvent(taskRecord.id, "message", accumulatedMessage, {
|
|
270
|
-
agent: lead.character_name,
|
|
271
|
-
content: accumulatedMessage,
|
|
272
|
-
});
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
finally {
|
|
276
|
-
unsubscribeDelta();
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
finally {
|
|
280
|
-
activeSessions.delete(taskRecord.id);
|
|
281
|
-
flushTokens();
|
|
282
|
-
await session.disconnect();
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
catch (err) {
|
|
286
|
-
const errMsg = err instanceof Error ? err.message : "Unknown error";
|
|
287
|
-
addAgentEvent(taskRecord.id, "status", `Task failed: ${errMsg}`, { error: errMsg });
|
|
288
|
-
updateTaskStatus(taskRecord.id, "failed", errMsg);
|
|
289
|
-
updateAgentStatus(lead.id, "idle");
|
|
290
|
-
// Audit: task failed
|
|
291
|
-
addAuditEntry("task_failed", `Task failed: ${errMsg.slice(0, 200)}`, { error: errMsg }, { squad_id: squadId, agent_id: lead.id, task_id: taskRecord.id });
|
|
292
|
-
throw err;
|
|
293
|
-
}
|
|
294
|
-
// Update task and agent status
|
|
295
|
-
updateTaskStatus(taskRecord.id, "done", result);
|
|
296
|
-
updateAgentStatus(lead.id, "idle");
|
|
297
|
-
// Audit: task completed
|
|
298
|
-
addAuditEntry("task_completed", `Task completed by ${lead.character_name}`, { result: result.slice(0, 500) }, { squad_id: squadId, agent_id: lead.id, task_id: taskRecord.id });
|
|
299
|
-
// Record completion event
|
|
300
|
-
addAgentEvent(taskRecord.id, "status", `Task completed by ${lead.character_name}`, {
|
|
301
|
-
agent: lead.character_name,
|
|
302
|
-
result: result.slice(0, 500),
|
|
303
|
-
});
|
|
304
|
-
// Post to feed
|
|
305
|
-
const squadSource = `squad-${squadSlug}`;
|
|
306
|
-
postFeedItem(squadSource, `Task completed by ${lead.character_name}`, result.slice(0, 2000));
|
|
307
|
-
return result;
|
|
308
|
-
}
|
|
309
|
-
//# sourceMappingURL=agents.js.map
|
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
import { approveAll } from "@github/copilot-sdk";
|
|
2
|
-
import { getClient } from "./client.js";
|
|
3
|
-
import { getLeadForSquad, getAgentsForSquad, getSquad } from "../store/squads.js";
|
|
4
|
-
import { selectModel } from "./model-router.js";
|
|
5
|
-
import { postFeedItem } from "../store/feed.js";
|
|
6
|
-
import { attachTokenTracker } from "./token-tracker.js";
|
|
7
|
-
import { buildAttachmentSummary, toCopilotBlobAttachments } from "../chat/attachments.js";
|
|
8
|
-
function buildFacilitatorPrompt(lead, agents, task) {
|
|
9
|
-
const roster = agents
|
|
10
|
-
.filter((a) => !a.is_lead)
|
|
11
|
-
.map((a) => `- ${a.character_name} (${a.role_title})${a.is_qa ? " [QA]" : ""}${a.is_test ? " [TEST]" : ""}`)
|
|
12
|
-
.join("\n");
|
|
13
|
-
return `# Planning Meeting Facilitator: ${lead.character_name}
|
|
14
|
-
|
|
15
|
-
You are facilitating a planning meeting for your squad. Your job is to gather input from specialists, then synthesize a clear action plan.
|
|
16
|
-
|
|
17
|
-
## The Task
|
|
18
|
-
${task}
|
|
19
|
-
|
|
20
|
-
## Your Team (Specialists)
|
|
21
|
-
${roster}
|
|
22
|
-
|
|
23
|
-
## Instructions
|
|
24
|
-
For each specialist who is relevant to this task, think about what their domain expertise would contribute. Then synthesize ALL perspectives into a structured plan.
|
|
25
|
-
|
|
26
|
-
Consider each relevant specialist's likely concerns:
|
|
27
|
-
${agents
|
|
28
|
-
.filter((a) => !a.is_lead)
|
|
29
|
-
.map((a) => `- ${a.character_name} (${a.role_title}): What risks, technical suggestions, or constraints would they raise?`)
|
|
30
|
-
.join("\n")}
|
|
31
|
-
|
|
32
|
-
## Output Format
|
|
33
|
-
Produce a plan in this exact format:
|
|
34
|
-
|
|
35
|
-
### Task Summary
|
|
36
|
-
(One sentence summary of what we're building)
|
|
37
|
-
|
|
38
|
-
### Plan
|
|
39
|
-
(Numbered list of work items with agent assignments)
|
|
40
|
-
|
|
41
|
-
### Risks & Concerns
|
|
42
|
-
(Bullet list of risks identified, with mitigation strategies)
|
|
43
|
-
|
|
44
|
-
### Dependencies
|
|
45
|
-
(What must happen in order, what can be parallel)
|
|
46
|
-
|
|
47
|
-
### Assignments
|
|
48
|
-
(Clear mapping: Agent → what they own)
|
|
49
|
-
|
|
50
|
-
## Rules
|
|
51
|
-
- You are ONLY planning — do NOT execute any work
|
|
52
|
-
- Assign work to specialists based on their role titles
|
|
53
|
-
- Identify what can be done in parallel vs what has dependencies
|
|
54
|
-
- Flag if any expertise is missing from the team
|
|
55
|
-
${lead.persona ? `\n## Your Style:\n${lead.persona}` : ""}
|
|
56
|
-
`;
|
|
57
|
-
}
|
|
58
|
-
function buildSpecialistPrompt(agent, task) {
|
|
59
|
-
return `# Planning Input: ${agent.character_name}
|
|
60
|
-
|
|
61
|
-
You are ${agent.character_name}, a ${agent.role_title}. Your team is planning a new task and needs your expert input.
|
|
62
|
-
|
|
63
|
-
## The Task
|
|
64
|
-
${task}
|
|
65
|
-
|
|
66
|
-
## Your Role
|
|
67
|
-
Provide input ONLY from your area of expertise (${agent.role_title}). Be specific and actionable.
|
|
68
|
-
|
|
69
|
-
## Respond With
|
|
70
|
-
1. **Concerns/Risks**: What could go wrong in your domain?
|
|
71
|
-
2. **Technical Suggestions**: How would you approach your part?
|
|
72
|
-
3. **Dependencies**: What do you need from other team members before you can start?
|
|
73
|
-
4. **Estimated Complexity**: Simple / Moderate / Complex for your portion
|
|
74
|
-
5. **Questions**: Anything unclear that affects your work?
|
|
75
|
-
|
|
76
|
-
Keep your response focused and concise — this is a planning meeting, not implementation.
|
|
77
|
-
${agent.persona ? `\n## Your Style:\n${agent.persona}` : ""}
|
|
78
|
-
`;
|
|
79
|
-
}
|
|
80
|
-
export async function planningMeeting(squadId, task, attachments = []) {
|
|
81
|
-
const lead = getLeadForSquad(squadId);
|
|
82
|
-
if (!lead) {
|
|
83
|
-
throw new Error("Squad has no team lead. Add a lead agent first.");
|
|
84
|
-
}
|
|
85
|
-
const agents = getAgentsForSquad(squadId);
|
|
86
|
-
const relevantAgents = agents.filter((a) => !a.is_lead);
|
|
87
|
-
if (relevantAgents.length === 0) {
|
|
88
|
-
throw new Error("Squad has no specialists to consult. Add agents first.");
|
|
89
|
-
}
|
|
90
|
-
const client = await getClient();
|
|
91
|
-
// Phase 1: Gather specialist input in parallel
|
|
92
|
-
const specialistInputs = await Promise.allSettled(relevantAgents.map(async (agent) => {
|
|
93
|
-
const model = await selectModel("low");
|
|
94
|
-
const session = await client.createSession({
|
|
95
|
-
model,
|
|
96
|
-
streaming: true,
|
|
97
|
-
workingDirectory: process.cwd(),
|
|
98
|
-
systemMessage: { content: buildSpecialistPrompt(agent, task) },
|
|
99
|
-
onPermissionRequest: approveAll,
|
|
100
|
-
});
|
|
101
|
-
const flushTokens = attachTokenTracker(session, { squadId, agentId: agent.id });
|
|
102
|
-
try {
|
|
103
|
-
const response = await session.sendAndWait({
|
|
104
|
-
prompt: `Please provide your planning input for this task.${buildAttachmentSummary(attachments)}`,
|
|
105
|
-
attachments: toCopilotBlobAttachments(attachments),
|
|
106
|
-
}, 7_200_000 // 2 hours — watchdog handles stale detection
|
|
107
|
-
);
|
|
108
|
-
return {
|
|
109
|
-
agent: agent.character_name,
|
|
110
|
-
role: agent.role_title,
|
|
111
|
-
input: response?.data?.content ?? "(no response)",
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
finally {
|
|
115
|
-
flushTokens();
|
|
116
|
-
await session.disconnect();
|
|
117
|
-
}
|
|
118
|
-
}));
|
|
119
|
-
// Collect successful inputs
|
|
120
|
-
const inputs = specialistInputs
|
|
121
|
-
.filter((r) => r.status === "fulfilled")
|
|
122
|
-
.map((r) => r.value);
|
|
123
|
-
const inputsSummary = inputs
|
|
124
|
-
.map((i) => `### ${i.agent} (${i.role})\n${i.input}`)
|
|
125
|
-
.join("\n\n");
|
|
126
|
-
// Phase 2: Lead synthesizes the plan
|
|
127
|
-
const facilitatorModel = await selectModel("medium");
|
|
128
|
-
const facilitatorSession = await client.createSession({
|
|
129
|
-
model: facilitatorModel,
|
|
130
|
-
streaming: true,
|
|
131
|
-
workingDirectory: process.cwd(),
|
|
132
|
-
systemMessage: { content: buildFacilitatorPrompt(lead, agents, task) },
|
|
133
|
-
onPermissionRequest: approveAll,
|
|
134
|
-
});
|
|
135
|
-
const flushFacilitatorTokens = attachTokenTracker(facilitatorSession, {
|
|
136
|
-
squadId,
|
|
137
|
-
agentId: lead.id,
|
|
138
|
-
});
|
|
139
|
-
let plan;
|
|
140
|
-
try {
|
|
141
|
-
const prompt = `Here is the input gathered from your team:\n\n${inputsSummary}\n\nNow synthesize this into a clear, structured action plan.`;
|
|
142
|
-
const response = await facilitatorSession.sendAndWait({
|
|
143
|
-
prompt,
|
|
144
|
-
attachments: toCopilotBlobAttachments(attachments),
|
|
145
|
-
}, 7_200_000 // 2 hours — watchdog handles stale detection
|
|
146
|
-
);
|
|
147
|
-
plan = response?.data?.content ?? "Planning meeting completed but no plan was produced.";
|
|
148
|
-
}
|
|
149
|
-
finally {
|
|
150
|
-
flushFacilitatorTokens();
|
|
151
|
-
await facilitatorSession.disconnect();
|
|
152
|
-
}
|
|
153
|
-
return {
|
|
154
|
-
plan,
|
|
155
|
-
participants: [lead.character_name, ...inputs.map((i) => i.agent)],
|
|
156
|
-
};
|
|
157
|
-
}
|
|
158
|
-
export async function squadMeeting(squadId, task, executeAfter, attachments = []) {
|
|
159
|
-
const result = await planningMeeting(squadId, task, attachments);
|
|
160
|
-
const summary = `## Planning Meeting Complete\n\n**Participants:** ${result.participants.join(", ")}\n\n${result.plan}`;
|
|
161
|
-
if (!executeAfter) {
|
|
162
|
-
// Post to feed and wait for user to trigger execution
|
|
163
|
-
const squad = getSquad(squadId);
|
|
164
|
-
const squadSource = squad ? `squad-${squad.slug}` : `squad-${squadId}`;
|
|
165
|
-
postFeedItem(squadSource, "Planning meeting complete — awaiting approval", summary);
|
|
166
|
-
return summary;
|
|
167
|
-
}
|
|
168
|
-
// Execute: delegate with the plan as additional context
|
|
169
|
-
const { delegateTask } = await import("./agents.js");
|
|
170
|
-
const enrichedTask = `${task}\n\n---\n## Approved Plan (from team meeting)\n${result.plan}`;
|
|
171
|
-
const execResult = await delegateTask(squadId, enrichedTask, undefined, attachments);
|
|
172
|
-
return `Meeting held, then executed.\n\n${summary}\n\n---\n## Execution Result\n${execResult}`;
|
|
173
|
-
}
|
|
174
|
-
//# sourceMappingURL=ceremonies.js.map
|
package/dist/copilot/gh-token.js
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { execSync } from "node:child_process";
|
|
2
|
-
import { loadConfig, resetConfigCache } from "../config.js";
|
|
3
|
-
/**
|
|
4
|
-
* Cached GitHub token for CLI operations.
|
|
5
|
-
* Resolution order: GH_TOKEN env → GITHUB_TOKEN env → config.githubToken → `gh auth token` CLI.
|
|
6
|
-
* If no token found, retries on next call (config may have been updated).
|
|
7
|
-
*/
|
|
8
|
-
let cachedToken;
|
|
9
|
-
let resolved = false;
|
|
10
|
-
export function resetGhTokenCache() {
|
|
11
|
-
cachedToken = undefined;
|
|
12
|
-
resolved = false;
|
|
13
|
-
}
|
|
14
|
-
export function getGhToken() {
|
|
15
|
-
if (resolved && cachedToken)
|
|
16
|
-
return cachedToken;
|
|
17
|
-
// 1. Prefer explicit env vars
|
|
18
|
-
if (process.env.GH_TOKEN) {
|
|
19
|
-
cachedToken = process.env.GH_TOKEN;
|
|
20
|
-
resolved = true;
|
|
21
|
-
return cachedToken;
|
|
22
|
-
}
|
|
23
|
-
if (process.env.GITHUB_TOKEN) {
|
|
24
|
-
cachedToken = process.env.GITHUB_TOKEN;
|
|
25
|
-
resolved = true;
|
|
26
|
-
return cachedToken;
|
|
27
|
-
}
|
|
28
|
-
// 2. Check IO config file (re-read in case it was updated since last attempt)
|
|
29
|
-
try {
|
|
30
|
-
if (!cachedToken)
|
|
31
|
-
resetConfigCache();
|
|
32
|
-
const config = loadConfig();
|
|
33
|
-
if (config.githubToken) {
|
|
34
|
-
cachedToken = config.githubToken;
|
|
35
|
-
resolved = true;
|
|
36
|
-
return cachedToken;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
catch {
|
|
40
|
-
// Config not available
|
|
41
|
-
}
|
|
42
|
-
// 3. Try extracting from gh CLI auth (only on first attempt)
|
|
43
|
-
if (!resolved) {
|
|
44
|
-
try {
|
|
45
|
-
const token = execSync("gh auth token", {
|
|
46
|
-
timeout: 5_000,
|
|
47
|
-
encoding: "utf-8",
|
|
48
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
49
|
-
}).trim();
|
|
50
|
-
if (token) {
|
|
51
|
-
cachedToken = token;
|
|
52
|
-
resolved = true;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
catch {
|
|
56
|
-
// gh not available or not authenticated
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
// Mark resolved only if we found a token — otherwise retry next call
|
|
60
|
-
if (cachedToken)
|
|
61
|
-
resolved = true;
|
|
62
|
-
return cachedToken;
|
|
63
|
-
}
|
|
64
|
-
//# sourceMappingURL=gh-token.js.map
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import { listSchedules, updateScheduleLastRun } from "../store/schedules.js";
|
|
2
|
-
import { sendToOrchestrator } from "./orchestrator.js";
|
|
3
|
-
let ioSchedulerInterval;
|
|
4
|
-
export function startIoScheduler() {
|
|
5
|
-
ioSchedulerInterval = setInterval(() => {
|
|
6
|
-
checkIoSchedules();
|
|
7
|
-
}, 60_000);
|
|
8
|
-
ioSchedulerInterval.unref();
|
|
9
|
-
}
|
|
10
|
-
function checkIoSchedules() {
|
|
11
|
-
const schedules = listSchedules("io");
|
|
12
|
-
const now = new Date();
|
|
13
|
-
for (const schedule of schedules) {
|
|
14
|
-
if (!schedule.enabled)
|
|
15
|
-
continue;
|
|
16
|
-
if (!isDue(schedule.cron, schedule.last_run, now))
|
|
17
|
-
continue;
|
|
18
|
-
if (!schedule.squad_id) {
|
|
19
|
-
console.warn(`[io-scheduler] Schedule ${schedule.id} skipped: missing squad_id.`);
|
|
20
|
-
continue;
|
|
21
|
-
}
|
|
22
|
-
updateScheduleLastRun(schedule.id);
|
|
23
|
-
sendToOrchestrator(buildSquadScopedPrompt(schedule), "io-scheduler", (_text, done) => {
|
|
24
|
-
if (done) {
|
|
25
|
-
console.log(`[io-scheduler] Schedule ${schedule.id} completed.`);
|
|
26
|
-
}
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
export function buildSquadScopedPrompt(schedule) {
|
|
31
|
-
const squadId = schedule.squad_id ?? "unknown";
|
|
32
|
-
return `[Squad Schedule] Run for squad ${squadId}. Prompt: ${schedule.prompt}`;
|
|
33
|
-
}
|
|
34
|
-
function isDue(cron, lastRun, now) {
|
|
35
|
-
const parts = cron.split(" ");
|
|
36
|
-
if (parts.length !== 5)
|
|
37
|
-
return false;
|
|
38
|
-
const [minSpec, hourSpec, daySpec, monthSpec, weekdaySpec] = parts;
|
|
39
|
-
if (!matchesCronField(minSpec, now.getMinutes()))
|
|
40
|
-
return false;
|
|
41
|
-
if (!matchesCronField(hourSpec, now.getHours()))
|
|
42
|
-
return false;
|
|
43
|
-
if (!matchesCronField(daySpec, now.getDate()))
|
|
44
|
-
return false;
|
|
45
|
-
if (!matchesCronField(monthSpec, now.getMonth() + 1))
|
|
46
|
-
return false;
|
|
47
|
-
if (!matchesCronField(weekdaySpec, now.getDay()))
|
|
48
|
-
return false;
|
|
49
|
-
if (lastRun) {
|
|
50
|
-
const lastDate = new Date(lastRun);
|
|
51
|
-
const diffMs = now.getTime() - lastDate.getTime();
|
|
52
|
-
if (diffMs < 60_000)
|
|
53
|
-
return false;
|
|
54
|
-
}
|
|
55
|
-
return true;
|
|
56
|
-
}
|
|
57
|
-
function matchesCronField(spec, value) {
|
|
58
|
-
if (spec === "*")
|
|
59
|
-
return true;
|
|
60
|
-
if (spec.includes("-")) {
|
|
61
|
-
const [start, end] = spec.split("-").map(Number);
|
|
62
|
-
return value >= start && value <= end;
|
|
63
|
-
}
|
|
64
|
-
if (spec.includes(",")) {
|
|
65
|
-
return spec.split(",").map(Number).includes(value);
|
|
66
|
-
}
|
|
67
|
-
if (spec.startsWith("*/")) {
|
|
68
|
-
const step = parseInt(spec.slice(2), 10);
|
|
69
|
-
return value % step === 0;
|
|
70
|
-
}
|
|
71
|
-
return parseInt(spec, 10) === value;
|
|
72
|
-
}
|
|
73
|
-
export function stopIoScheduler() {
|
|
74
|
-
if (ioSchedulerInterval) {
|
|
75
|
-
clearInterval(ioSchedulerInterval);
|
|
76
|
-
ioSchedulerInterval = undefined;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
//# sourceMappingURL=io-scheduler.js.map
|