heyio 0.42.0 → 1.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/README.md +40 -52
- package/dist/api/auth.js +35 -38
- package/dist/api/server.js +157 -1139
- package/dist/config.js +49 -32
- package/dist/copilot/agents.js +72 -1055
- package/dist/copilot/client.js +6 -17
- package/dist/copilot/io-scheduler.js +55 -139
- package/dist/copilot/model-router.js +100 -72
- package/dist/copilot/orchestrator.js +91 -515
- package/dist/copilot/scheduler.js +67 -189
- package/dist/copilot/skills.js +41 -366
- package/dist/copilot/system-message.js +40 -200
- package/dist/copilot/tools.js +191 -2042
- package/dist/daemon.js +54 -201
- package/dist/index.js +15 -133
- package/dist/mcp/config.js +23 -31
- package/dist/mcp/index.js +2 -3
- package/dist/mcp/registry.js +33 -88
- package/dist/notify.js +18 -100
- package/dist/paths.js +13 -24
- package/dist/setup.js +35 -0
- package/dist/store/db.js +111 -297
- package/dist/store/feed.js +29 -97
- package/dist/store/instances.js +56 -121
- package/dist/store/schedules.js +21 -73
- package/dist/store/squads.js +35 -186
- package/dist/store/tasks.js +25 -168
- package/dist/telegram/bot.js +20 -312
- package/dist/telegram/handlers.js +39 -3
- package/dist/watchdog.js +31 -45
- package/dist/wiki/fs.js +38 -155
- package/dist/wiki/search.js +31 -44
- package/package.json +5 -8
- package/web-dist/assets/ChatView-EFFiln1H.js +11 -0
- package/web-dist/assets/FeedView-bN4NMOL7.js +6 -0
- package/web-dist/assets/LoginView-CNtasq3n.js +1 -0
- package/web-dist/assets/McpView-C2CHiwsi.js +1 -0
- package/web-dist/assets/SchedulesView-CyilLban.js +1 -0
- package/web-dist/assets/SettingsView-1wLXKEF4.js +1 -0
- package/web-dist/assets/SkillsView-BLsD-0u0.js +1 -0
- package/web-dist/assets/SquadDetailView-CsCw2ZLp.js +21 -0
- package/web-dist/assets/SquadsView-DQ3vFlyO.js +6 -0
- package/web-dist/assets/WikiView-19M3oqnq.js +21 -0
- package/web-dist/assets/api-WGvTsXaE.js +1 -0
- package/web-dist/assets/index-D7M5O-_l.css +1 -0
- package/web-dist/assets/index-DZOS9syn.js +95 -0
- package/web-dist/assets/plus-BOvyX1BC.js +6 -0
- package/web-dist/assets/trash-2-DHoetkC4.js +6 -0
- package/web-dist/favicon.svg +4 -1
- package/web-dist/index.html +7 -10
- package/dist/api/logout.test.js +0 -129
- package/dist/api/mcp.test.js +0 -285
- package/dist/api/wiki.test.js +0 -283
- package/dist/auth/session-logic.js +0 -79
- package/dist/auth/session-logic.test.js +0 -201
- package/dist/copilot/auto-complete-instance.test.js +0 -104
- package/dist/copilot/cron.js +0 -136
- package/dist/copilot/event-summary.js +0 -286
- package/dist/copilot/instance-deactivate.test.js +0 -119
- package/dist/copilot/model-router.test.js +0 -71
- package/dist/copilot/review-backfill.js +0 -57
- package/dist/copilot/session-timeout.js +0 -112
- package/dist/copilot/session-timeout.test.js +0 -372
- package/dist/copilot/skills.test.js +0 -55
- package/dist/copilot/universes.js +0 -469
- package/dist/instance-watchdog.js +0 -104
- package/dist/instance-watchdog.test.js +0 -183
- package/dist/mcp/client.js +0 -109
- package/dist/mcp/client.test.js +0 -99
- package/dist/mcp/config.test.js +0 -49
- package/dist/mcp/registry.test.js +0 -79
- package/dist/notify.test.js +0 -232
- package/dist/store/feed.test.js +0 -279
- package/dist/store/instances.test.js +0 -310
- package/dist/store/io-schedules.js +0 -63
- package/dist/store/notifications.js +0 -79
- package/dist/store/notifications.test.js +0 -197
- package/dist/store/schedule-runs.js +0 -46
- package/dist/store/squads.test.js +0 -405
- package/dist/store/tasks.test.js +0 -150
- package/dist/store/worktrees.js +0 -83
- package/dist/tui/index.js +0 -286
- package/dist/update.js +0 -81
- package/dist/watchdog.test.js +0 -83
- package/dist/wiki/wiki-squad.test.js +0 -54
- package/web-dist/assets/AgentActivityView-CedxxE6K.js +0 -1
- package/web-dist/assets/ChatView-DMkYQo_V.js +0 -4
- package/web-dist/assets/FeedView-BH4q-31V.js +0 -1
- package/web-dist/assets/InboxView-BVwVP4EW.js +0 -1
- package/web-dist/assets/LoginView-DRPDhnwu.js +0 -1
- package/web-dist/assets/McpView-D8yWz-lq.js +0 -1
- package/web-dist/assets/SchedulesView-BzzyncGF.js +0 -1
- package/web-dist/assets/SettingsTabs.vue_vue_type_script_setup_true_lang-oW3ySu7Y.js +0 -1
- package/web-dist/assets/SkillsView-oxpYuhx7.js +0 -1
- package/web-dist/assets/SquadsView-CaKUIKlq.js +0 -1
- package/web-dist/assets/StatusIndicator.vue_vue_type_script_setup_true_lang-8U15Qp_Q.js +0 -1
- package/web-dist/assets/WikiView-C5jXUlfW.js +0 -1
- package/web-dist/assets/index-BrWzNw-N.css +0 -10
- package/web-dist/assets/index-f67odrrt.js +0 -81
- package/web-dist/icons.svg +0 -24
|
@@ -1,202 +1,80 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
//
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
//
|
|
11
|
-
// Schedules survive daemon restarts because next_run_at is persisted. On
|
|
12
|
-
// startup we backfill any next_run_at fields that became stale (or are NULL).
|
|
13
|
-
import { listSchedules, listDueSchedules, recordScheduleRun, setScheduleTimestamps, updateNextRun } from "../store/schedules.js";
|
|
14
|
-
import { getSquad } from "../store/squads.js";
|
|
15
|
-
import { delegateToAgent } from "./agents.js";
|
|
16
|
-
import { nextRun } from "./cron.js";
|
|
17
|
-
import { notifyBackground } from "../notify.js";
|
|
18
|
-
import { startScheduleRun, completeScheduleRun, failScheduleRun } from "../store/schedule-runs.js";
|
|
19
|
-
import { createFeedEntry } from "../store/feed.js";
|
|
20
|
-
import { shouldRouteToInbox } from "./tools.js";
|
|
21
|
-
const TICK_MS = 30_000;
|
|
22
|
-
const AGENDA_BLOCKS = {
|
|
23
|
-
triage: `**Triage**
|
|
24
|
-
- Use the GitHub CLI (\`gh issue list\`) to pull open issues with the \`needs-triage\` label.
|
|
25
|
-
- For each issue: read the body and decide on appropriate labels (priority, area, type, etc).
|
|
26
|
-
- Apply labels with \`gh issue edit <num> --add-label "..."\` and remove \`needs-triage\` once labelled.
|
|
27
|
-
- If the issue lacks information, post a clarifying comment with \`gh issue comment\` instead of labelling, and leave \`needs-triage\` on it.`,
|
|
28
|
-
prioritize: `**Prioritize**
|
|
29
|
-
- Identify open issues that are ready to be worked on: properly labelled, not blocked, no \`needs-triage\` or \`needs-review\` label, no open PR already addressing them.
|
|
30
|
-
- Rank by priority labels and surface the top candidate.
|
|
31
|
-
- After the stand-up, the team lead should immediately begin work on the highest-priority ready issue by delegating it to the right teammate.`,
|
|
32
|
-
ideation: `**Ideation**
|
|
33
|
-
- Brainstorm 1–3 concrete improvements or new features for the project.
|
|
34
|
-
- Discuss as a team (use \`delegate_to_teammate\` to gather input from members whose expertise fits the idea).
|
|
35
|
-
- For each idea the team agrees on, create a GitHub issue with \`gh issue create\` tagged with the \`needs-review\` label so the human can approve it before work begins.`,
|
|
36
|
-
};
|
|
37
|
-
function buildStandupPrompt(squad, schedule) {
|
|
38
|
-
const blocks = schedule.agenda
|
|
39
|
-
.map((item) => AGENDA_BLOCKS[item] ?? `**${item}** _(no built-in template — improvise)_`)
|
|
40
|
-
.join("\n\n");
|
|
41
|
-
const notes = schedule.notes ? `\n\n**Operator notes:** ${schedule.notes}` : "";
|
|
42
|
-
return `# Scheduled stand-up: ${schedule.name}
|
|
43
|
-
|
|
44
|
-
You are the team lead for the **${squad.name}** squad (\`${squad.slug}\`). Run a stand-up meeting now.
|
|
45
|
-
|
|
46
|
-
**Project path:** \`${squad.project_path}\` — \`cd\` here before invoking the GitHub CLI so it picks up the right repo.
|
|
47
|
-
|
|
48
|
-
**Agenda** (work through these in order; use \`delegate_to_teammate\` to pull in the right specialist for each item):
|
|
49
|
-
|
|
50
|
-
${blocks}
|
|
51
|
-
|
|
52
|
-
When you finish the agenda, summarise what was triaged, what was prioritised (and what work you've kicked off), and what new issues were filed during ideation.${notes}`;
|
|
1
|
+
import { listSchedules, updateScheduleLastRun } from "../store/schedules.js";
|
|
2
|
+
import { sendToOrchestrator } from "./orchestrator.js";
|
|
3
|
+
let schedulerInterval;
|
|
4
|
+
export function startSquadScheduler() {
|
|
5
|
+
// Check every minute for due schedules
|
|
6
|
+
schedulerInterval = setInterval(() => {
|
|
7
|
+
checkSquadSchedules();
|
|
8
|
+
}, 60_000);
|
|
9
|
+
schedulerInterval.unref();
|
|
53
10
|
}
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
try {
|
|
69
|
-
nextIso = nextRun(schedule.cron_expr, ranAt).toISOString();
|
|
70
|
-
}
|
|
71
|
-
catch (err) {
|
|
72
|
-
console.error(`[io] scheduler: cron parse error for schedule ${schedule.id}:`, err instanceof Error ? err.message : err);
|
|
73
|
-
}
|
|
74
|
-
recordScheduleRun(schedule.id, ranAt, nextIso);
|
|
75
|
-
const prompt = buildStandupPrompt({ name: squad.name, slug: squad.slug, project_path: squad.project_path }, schedule);
|
|
76
|
-
console.log(`[io] scheduler: firing schedule "${schedule.name}" for squad "${squad.slug}" (next run: ${nextIso ?? "never"})`);
|
|
77
|
-
const run = startScheduleRun({
|
|
78
|
-
schedule_type: "squad",
|
|
79
|
-
schedule_id: schedule.id,
|
|
80
|
-
schedule_name: schedule.name,
|
|
81
|
-
squad_slug: squad.slug,
|
|
82
|
-
});
|
|
83
|
-
try {
|
|
84
|
-
await delegateToAgent(squad.slug, prompt, (_taskId, result) => {
|
|
85
|
-
if (shouldRouteToInbox(prompt)) {
|
|
86
|
-
createFeedEntry({ type: "inbox", title: `[${squad.slug}] ${schedule.name}`, body: result });
|
|
87
|
-
console.error(`[io] Schedule ${schedule.id} result routed to inbox`);
|
|
88
|
-
completeScheduleRun(run.id, 0);
|
|
89
|
-
}
|
|
90
|
-
else {
|
|
91
|
-
void notifyBackground({
|
|
92
|
-
source: {
|
|
93
|
-
type: "squad-schedule",
|
|
94
|
-
scheduleId: schedule.id,
|
|
95
|
-
squadSlug: squad.slug,
|
|
96
|
-
scheduleName: schedule.name,
|
|
97
|
-
},
|
|
98
|
-
title: `${squad.name}: ${schedule.name}`,
|
|
99
|
-
text: result,
|
|
100
|
-
}).then((notifyResult) => {
|
|
101
|
-
completeScheduleRun(run.id, notifyResult.id);
|
|
102
|
-
}).catch((err) => {
|
|
103
|
-
failScheduleRun(run.id, err instanceof Error ? err.message : String(err));
|
|
104
|
-
});
|
|
11
|
+
function checkSquadSchedules() {
|
|
12
|
+
const schedules = listSchedules("squad");
|
|
13
|
+
const now = new Date();
|
|
14
|
+
for (const schedule of schedules) {
|
|
15
|
+
if (!schedule.enabled)
|
|
16
|
+
continue;
|
|
17
|
+
if (!isDue(schedule.cron, schedule.last_run, now))
|
|
18
|
+
continue;
|
|
19
|
+
updateScheduleLastRun(schedule.id);
|
|
20
|
+
const agenda = schedule.agenda || "triage";
|
|
21
|
+
const prompt = `[Squad Schedule] Run "${agenda}" stand-up for squad ${schedule.squad_id}. Agenda: ${agenda}`;
|
|
22
|
+
sendToOrchestrator(prompt, "scheduler", (_text, done) => {
|
|
23
|
+
if (done) {
|
|
24
|
+
console.log(`[scheduler] Squad stand-up completed for ${schedule.squad_id}`);
|
|
105
25
|
}
|
|
106
26
|
});
|
|
107
27
|
}
|
|
108
|
-
catch (err) {
|
|
109
|
-
failScheduleRun(run.id, err instanceof Error ? err.message : String(err));
|
|
110
|
-
console.error(`[io] scheduler: failed to delegate stand-up for schedule ${schedule.id}:`, err instanceof Error ? err.message : err);
|
|
111
|
-
}
|
|
112
|
-
finally {
|
|
113
|
-
inFlight.delete(schedule.id);
|
|
114
|
-
}
|
|
115
28
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
29
|
+
function isDue(cron, lastRun, now) {
|
|
30
|
+
// Simple cron matching: parse "minute hour day month weekday"
|
|
31
|
+
const parts = cron.split(" ");
|
|
32
|
+
if (parts.length !== 5)
|
|
33
|
+
return false;
|
|
34
|
+
const [minSpec, hourSpec, daySpec, monthSpec, weekdaySpec] = parts;
|
|
35
|
+
if (!matchesCronField(minSpec, now.getMinutes()))
|
|
36
|
+
return false;
|
|
37
|
+
if (!matchesCronField(hourSpec, now.getHours()))
|
|
38
|
+
return false;
|
|
39
|
+
if (!matchesCronField(daySpec, now.getDate()))
|
|
40
|
+
return false;
|
|
41
|
+
if (!matchesCronField(monthSpec, now.getMonth() + 1))
|
|
42
|
+
return false;
|
|
43
|
+
if (!matchesCronField(weekdaySpec, now.getDay()))
|
|
44
|
+
return false;
|
|
45
|
+
// Prevent running more than once per matching minute
|
|
46
|
+
if (lastRun) {
|
|
47
|
+
const lastDate = new Date(lastRun);
|
|
48
|
+
const diffMs = now.getTime() - lastDate.getTime();
|
|
49
|
+
if (diffMs < 60_000)
|
|
50
|
+
return false;
|
|
120
51
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
function matchesCronField(spec, value) {
|
|
55
|
+
if (spec === "*")
|
|
56
|
+
return true;
|
|
57
|
+
// Handle ranges (e.g., "1-5")
|
|
58
|
+
if (spec.includes("-")) {
|
|
59
|
+
const [start, end] = spec.split("-").map(Number);
|
|
60
|
+
return value >= start && value <= end;
|
|
124
61
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
62
|
+
// Handle lists (e.g., "1,3,5")
|
|
63
|
+
if (spec.includes(",")) {
|
|
64
|
+
return spec.split(",").map(Number).includes(value);
|
|
128
65
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
* to the next future occurrence rather than replaying missed runs.
|
|
134
|
-
*/
|
|
135
|
-
export function reconcileSchedules(now = new Date()) {
|
|
136
|
-
for (const s of listSchedules()) {
|
|
137
|
-
if (!s.enabled)
|
|
138
|
-
continue;
|
|
139
|
-
let needsUpdate = false;
|
|
140
|
-
if (!s.next_run_at) {
|
|
141
|
-
needsUpdate = true;
|
|
142
|
-
}
|
|
143
|
-
else {
|
|
144
|
-
const next = new Date(s.next_run_at);
|
|
145
|
-
if (Number.isNaN(next.getTime()) || next <= now)
|
|
146
|
-
needsUpdate = true;
|
|
147
|
-
}
|
|
148
|
-
if (!needsUpdate)
|
|
149
|
-
continue;
|
|
150
|
-
try {
|
|
151
|
-
const next = nextRun(s.cron_expr, now);
|
|
152
|
-
updateNextRun(s.id, next.toISOString());
|
|
153
|
-
}
|
|
154
|
-
catch (err) {
|
|
155
|
-
console.error(`[io] scheduler: invalid cron "${s.cron_expr}" on schedule ${s.id}; disabling next_run_at:`, err instanceof Error ? err.message : err);
|
|
156
|
-
updateNextRun(s.id, null);
|
|
157
|
-
}
|
|
66
|
+
// Handle step values (e.g., "*/5")
|
|
67
|
+
if (spec.startsWith("*/")) {
|
|
68
|
+
const step = parseInt(spec.slice(2), 10);
|
|
69
|
+
return value % step === 0;
|
|
158
70
|
}
|
|
71
|
+
// Exact match
|
|
72
|
+
return parseInt(spec, 10) === value;
|
|
159
73
|
}
|
|
160
|
-
export function
|
|
161
|
-
if (
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
timer = setInterval(() => {
|
|
165
|
-
void tick();
|
|
166
|
-
}, TICK_MS);
|
|
167
|
-
if (typeof timer.unref === "function")
|
|
168
|
-
timer.unref();
|
|
169
|
-
console.log(`[io] Scheduler started (tick every ${TICK_MS / 1000}s)`);
|
|
170
|
-
}
|
|
171
|
-
export function stopScheduler() {
|
|
172
|
-
if (!timer)
|
|
173
|
-
return;
|
|
174
|
-
clearInterval(timer);
|
|
175
|
-
timer = undefined;
|
|
176
|
-
}
|
|
177
|
-
/**
|
|
178
|
-
* Manually fire a schedule. Used by squad_schedule_run_now.
|
|
179
|
-
*
|
|
180
|
-
* Snapshots last_run_at and next_run_at before firing and restores them
|
|
181
|
-
* after, so a manual fire never disturbs the regular schedule (a user
|
|
182
|
-
* testing a 05:00 schedule at 04:30 should not have today's 05:00 run
|
|
183
|
-
* skipped or shifted). The fireSchedule path itself advances both fields
|
|
184
|
-
* because that's correct for an automatic firing — only manual runs need
|
|
185
|
-
* to leave the schedule untouched.
|
|
186
|
-
*/
|
|
187
|
-
export async function runScheduleNow(scheduleId) {
|
|
188
|
-
const all = listSchedules();
|
|
189
|
-
const s = all.find((x) => x.id === scheduleId);
|
|
190
|
-
if (!s)
|
|
191
|
-
return { ok: false, error: `Schedule ${scheduleId} not found` };
|
|
192
|
-
const previousLast = s.last_run_at;
|
|
193
|
-
const previousNext = s.next_run_at;
|
|
194
|
-
try {
|
|
195
|
-
await fireSchedule(s);
|
|
196
|
-
}
|
|
197
|
-
finally {
|
|
198
|
-
setScheduleTimestamps(scheduleId, previousLast, previousNext);
|
|
74
|
+
export function stopSquadScheduler() {
|
|
75
|
+
if (schedulerInterval) {
|
|
76
|
+
clearInterval(schedulerInterval);
|
|
77
|
+
schedulerInterval = undefined;
|
|
199
78
|
}
|
|
200
|
-
return { ok: true };
|
|
201
79
|
}
|
|
202
80
|
//# sourceMappingURL=scheduler.js.map
|