heyio 0.30.1 → 0.32.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/server.js +85 -9
- package/dist/copilot/agents.js +41 -0
- package/dist/copilot/auto-complete-instance.test.js +104 -0
- package/dist/copilot/instance-deactivate.test.js +119 -0
- package/dist/copilot/orchestrator.js +35 -1
- package/dist/copilot/scheduler.js +1 -1
- package/dist/copilot/tools.js +140 -2
- package/dist/instance-watchdog.js +43 -9
- package/dist/instance-watchdog.test.js +77 -6
- package/dist/mcp/client.js +109 -0
- package/dist/mcp/client.test.js +99 -0
- package/dist/mcp/config.js +29 -0
- package/dist/mcp/config.test.js +49 -0
- package/dist/mcp/index.js +4 -0
- package/dist/mcp/registry.js +96 -0
- package/dist/mcp/registry.test.js +79 -0
- package/dist/store/db.js +21 -1
- package/dist/store/feed.js +3 -3
- package/dist/store/feed.test.js +20 -20
- package/dist/store/squads.js +1 -1
- package/dist/store/squads.test.js +353 -0
- package/dist/tui/index.js +2 -2
- package/package.json +4 -3
- package/web-dist/assets/index-Ddn6rUkk.js +88 -0
- package/web-dist/assets/index-KNbOV6QX.css +10 -0
- package/web-dist/index.html +2 -2
- package/dist/store/inbox.js +0 -28
- package/web-dist/assets/index-BvKvht8h.js +0 -88
- package/web-dist/assets/index-DmthMbtN.css +0 -10
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for src/store/squads.ts — the most-depended-on store module.
|
|
3
|
+
*
|
|
4
|
+
* DB isolation: setDbPathForTests() redirects the SQLite singleton to a
|
|
5
|
+
* fresh tmp file so these tests never touch ~/.io/io.db.
|
|
6
|
+
*/
|
|
7
|
+
import { before, after, beforeEach, describe, it } from "node:test";
|
|
8
|
+
import assert from "node:assert/strict";
|
|
9
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
10
|
+
import { tmpdir } from "node:os";
|
|
11
|
+
import { join } from "node:path";
|
|
12
|
+
import { setDbPathForTests, closeDb, getDb } from "./db.js";
|
|
13
|
+
import { createSquad, getSquad, listSquads, updateSquadSession, updateSquadStatus, updateSquadModel, deleteSquad, addSquadAgent, getSquadAgent, listSquadAgents, removeSquadAgent, updateAgentSession, updateAgentStatus, clearAgentSession, reconcileAgentStatuses, reconcileSquadStatuses, logDecision, getDecisions, getDecisionsSummary, setSquadLead, getSquadLead, setSquadQA, } from "./squads.js";
|
|
14
|
+
// ── DB isolation ─────────────────────────────────────────────────────────────
|
|
15
|
+
let tmpDir;
|
|
16
|
+
before(() => {
|
|
17
|
+
tmpDir = mkdtempSync(join(tmpdir(), "io-squads-test-"));
|
|
18
|
+
setDbPathForTests(join(tmpDir, "io.db"));
|
|
19
|
+
});
|
|
20
|
+
after(() => {
|
|
21
|
+
closeDb();
|
|
22
|
+
rmSync(tmpDir, { recursive: true, force: true });
|
|
23
|
+
});
|
|
24
|
+
beforeEach(() => {
|
|
25
|
+
const db = getDb();
|
|
26
|
+
db.prepare("DELETE FROM squad_decisions").run();
|
|
27
|
+
db.prepare("DELETE FROM squad_agents").run();
|
|
28
|
+
db.prepare("DELETE FROM squads").run();
|
|
29
|
+
});
|
|
30
|
+
// ── helpers ───────────────────────────────────────────────────────────────────
|
|
31
|
+
function makeSquad(slug = "test-squad") {
|
|
32
|
+
// Insert directly so tests don't depend on universe randomization
|
|
33
|
+
getDb()
|
|
34
|
+
.prepare("INSERT INTO squads (slug, name, project_path, universe) VALUES (?, ?, ?, ?)")
|
|
35
|
+
.run(slug, `${slug} name`, "/tmp/test", "thundercats");
|
|
36
|
+
return getSquad(slug);
|
|
37
|
+
}
|
|
38
|
+
// ── createSquad ───────────────────────────────────────────────────────────────
|
|
39
|
+
describe("createSquad", () => {
|
|
40
|
+
it("creates and returns a squad with correct fields", () => {
|
|
41
|
+
const squad = createSquad("my-squad", "My Squad", "/tmp/my-squad");
|
|
42
|
+
assert.equal(squad.slug, "my-squad");
|
|
43
|
+
assert.equal(squad.name, "My Squad");
|
|
44
|
+
assert.equal(squad.project_path, "/tmp/my-squad");
|
|
45
|
+
assert.equal(squad.status, "idle");
|
|
46
|
+
assert.equal(squad.copilot_session_id, null);
|
|
47
|
+
assert.ok(squad.universe); // assigned by randomUniverse()
|
|
48
|
+
assert.ok(squad.created_at);
|
|
49
|
+
});
|
|
50
|
+
it("throws on duplicate slug", () => {
|
|
51
|
+
createSquad("dup-squad", "Dup", "/tmp/dup");
|
|
52
|
+
assert.throws(() => createSquad("dup-squad", "Dup2", "/tmp/dup2"));
|
|
53
|
+
});
|
|
54
|
+
it("accepts an explicit universeId", () => {
|
|
55
|
+
const squad = createSquad("universe-squad", "Uni Squad", "/tmp/uni", "thundercats");
|
|
56
|
+
assert.equal(squad.universe, "thundercats");
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
// ── getSquad ──────────────────────────────────────────────────────────────────
|
|
60
|
+
describe("getSquad", () => {
|
|
61
|
+
it("returns undefined for non-existent slug", () => {
|
|
62
|
+
assert.equal(getSquad("no-such-squad"), undefined);
|
|
63
|
+
});
|
|
64
|
+
it("returns the correct squad after creation", () => {
|
|
65
|
+
makeSquad("get-test");
|
|
66
|
+
const squad = getSquad("get-test");
|
|
67
|
+
assert.ok(squad);
|
|
68
|
+
assert.equal(squad.slug, "get-test");
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
// ── listSquads ────────────────────────────────────────────────────────────────
|
|
72
|
+
describe("listSquads", () => {
|
|
73
|
+
it("returns empty array on clean DB", () => {
|
|
74
|
+
assert.deepEqual(listSquads(), []);
|
|
75
|
+
});
|
|
76
|
+
it("returns all squads newest first", () => {
|
|
77
|
+
makeSquad("squad-a");
|
|
78
|
+
makeSquad("squad-b");
|
|
79
|
+
const squads = listSquads();
|
|
80
|
+
assert.equal(squads.length, 2);
|
|
81
|
+
// Both are present
|
|
82
|
+
assert.ok(squads.some((s) => s.slug === "squad-a"));
|
|
83
|
+
assert.ok(squads.some((s) => s.slug === "squad-b"));
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
// ── updateSquadSession ────────────────────────────────────────────────────────
|
|
87
|
+
describe("updateSquadSession", () => {
|
|
88
|
+
it("sets copilot_session_id", () => {
|
|
89
|
+
makeSquad();
|
|
90
|
+
updateSquadSession("test-squad", "session-abc");
|
|
91
|
+
assert.equal(getSquad("test-squad")?.copilot_session_id, "session-abc");
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
// ── updateSquadStatus ─────────────────────────────────────────────────────────
|
|
95
|
+
describe("updateSquadStatus", () => {
|
|
96
|
+
it("updates status field", () => {
|
|
97
|
+
makeSquad();
|
|
98
|
+
updateSquadStatus("test-squad", "working");
|
|
99
|
+
assert.equal(getSquad("test-squad")?.status, "working");
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
// ── updateSquadModel ──────────────────────────────────────────────────────────
|
|
103
|
+
describe("updateSquadModel", () => {
|
|
104
|
+
it("sets model to a string", () => {
|
|
105
|
+
makeSquad();
|
|
106
|
+
updateSquadModel("test-squad", "gpt-4.1");
|
|
107
|
+
assert.equal(getSquad("test-squad")?.model, "gpt-4.1");
|
|
108
|
+
});
|
|
109
|
+
it("sets model to null", () => {
|
|
110
|
+
makeSquad();
|
|
111
|
+
updateSquadModel("test-squad", "gpt-4.1");
|
|
112
|
+
updateSquadModel("test-squad", null);
|
|
113
|
+
assert.equal(getSquad("test-squad")?.model, null);
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
// ── deleteSquad ───────────────────────────────────────────────────────────────
|
|
117
|
+
describe("deleteSquad", () => {
|
|
118
|
+
it("removes the squad row", () => {
|
|
119
|
+
makeSquad();
|
|
120
|
+
deleteSquad("test-squad");
|
|
121
|
+
assert.equal(getSquad("test-squad"), undefined);
|
|
122
|
+
});
|
|
123
|
+
it("cascades to remove agents and decisions", () => {
|
|
124
|
+
makeSquad();
|
|
125
|
+
logDecision("test-squad", "a decision");
|
|
126
|
+
addSquadAgent("test-squad", "Engineer", "Build things");
|
|
127
|
+
deleteSquad("test-squad");
|
|
128
|
+
assert.deepEqual(listSquadAgents("test-squad"), []);
|
|
129
|
+
assert.deepEqual(getDecisions("test-squad"), []);
|
|
130
|
+
});
|
|
131
|
+
it("is safe to call on a non-existent slug", () => {
|
|
132
|
+
assert.doesNotThrow(() => deleteSquad("no-such-squad"));
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
// ── addSquadAgent ─────────────────────────────────────────────────────────────
|
|
136
|
+
describe("addSquadAgent", () => {
|
|
137
|
+
it("creates an agent with correct fields", () => {
|
|
138
|
+
makeSquad();
|
|
139
|
+
const agent = addSquadAgent("test-squad", "Engineer", "Build things", "medium");
|
|
140
|
+
assert.equal(agent.squad_slug, "test-squad");
|
|
141
|
+
assert.equal(agent.role_title, "Engineer");
|
|
142
|
+
assert.equal(agent.charter, "Build things");
|
|
143
|
+
assert.equal(agent.model_tier, "medium");
|
|
144
|
+
assert.equal(agent.status, "idle");
|
|
145
|
+
assert.equal(agent.is_lead, 0);
|
|
146
|
+
assert.equal(agent.is_qa, 0);
|
|
147
|
+
assert.ok(agent.character_name); // assigned from universe
|
|
148
|
+
assert.ok(agent.personality);
|
|
149
|
+
});
|
|
150
|
+
it("assigns distinct character names to multiple agents", () => {
|
|
151
|
+
makeSquad();
|
|
152
|
+
const a1 = addSquadAgent("test-squad", "Engineer", "Build");
|
|
153
|
+
const a2 = addSquadAgent("test-squad", "Designer", "Design");
|
|
154
|
+
assert.notEqual(a1.character_name, a2.character_name);
|
|
155
|
+
});
|
|
156
|
+
it("throws for non-existent squad", () => {
|
|
157
|
+
assert.throws(() => addSquadAgent("no-squad", "Dev", "Code"), /Squad not found/);
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
// ── getSquadAgent ─────────────────────────────────────────────────────────────
|
|
161
|
+
describe("getSquadAgent", () => {
|
|
162
|
+
it("returns undefined for non-existent agent", () => {
|
|
163
|
+
makeSquad();
|
|
164
|
+
assert.equal(getSquadAgent("test-squad", "Nonexistent"), undefined);
|
|
165
|
+
});
|
|
166
|
+
it("returns the agent after creation", () => {
|
|
167
|
+
makeSquad();
|
|
168
|
+
const agent = addSquadAgent("test-squad", "Dev", "Code things");
|
|
169
|
+
const fetched = getSquadAgent("test-squad", agent.character_name);
|
|
170
|
+
assert.ok(fetched);
|
|
171
|
+
assert.equal(fetched.role_title, "Dev");
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
// ── listSquadAgents ───────────────────────────────────────────────────────────
|
|
175
|
+
describe("listSquadAgents", () => {
|
|
176
|
+
it("returns empty array for squad with no agents", () => {
|
|
177
|
+
makeSquad();
|
|
178
|
+
assert.deepEqual(listSquadAgents("test-squad"), []);
|
|
179
|
+
});
|
|
180
|
+
it("returns all agents for the squad", () => {
|
|
181
|
+
makeSquad();
|
|
182
|
+
addSquadAgent("test-squad", "Dev", "Code");
|
|
183
|
+
addSquadAgent("test-squad", "QA", "Test");
|
|
184
|
+
assert.equal(listSquadAgents("test-squad").length, 2);
|
|
185
|
+
});
|
|
186
|
+
it("does not return agents from other squads", () => {
|
|
187
|
+
makeSquad("squad-a");
|
|
188
|
+
makeSquad("squad-b");
|
|
189
|
+
addSquadAgent("squad-a", "Dev", "Code");
|
|
190
|
+
assert.equal(listSquadAgents("squad-b").length, 0);
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
// ── removeSquadAgent ──────────────────────────────────────────────────────────
|
|
194
|
+
describe("removeSquadAgent", () => {
|
|
195
|
+
it("removes the agent and returns true", () => {
|
|
196
|
+
makeSquad();
|
|
197
|
+
const agent = addSquadAgent("test-squad", "Dev", "Code");
|
|
198
|
+
const result = removeSquadAgent("test-squad", agent.character_name);
|
|
199
|
+
assert.equal(result, true);
|
|
200
|
+
assert.equal(listSquadAgents("test-squad").length, 0);
|
|
201
|
+
});
|
|
202
|
+
it("returns false for non-existent agent", () => {
|
|
203
|
+
makeSquad();
|
|
204
|
+
assert.equal(removeSquadAgent("test-squad", "Ghost"), false);
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
// ── updateAgentSession ────────────────────────────────────────────────────────
|
|
208
|
+
describe("updateAgentSession / clearAgentSession", () => {
|
|
209
|
+
it("sets and clears copilot_session_id", () => {
|
|
210
|
+
makeSquad();
|
|
211
|
+
const agent = addSquadAgent("test-squad", "Dev", "Code");
|
|
212
|
+
updateAgentSession("test-squad", agent.character_name, "session-xyz");
|
|
213
|
+
assert.equal(getSquadAgent("test-squad", agent.character_name)?.copilot_session_id, "session-xyz");
|
|
214
|
+
clearAgentSession("test-squad", agent.character_name);
|
|
215
|
+
assert.equal(getSquadAgent("test-squad", agent.character_name)?.copilot_session_id, null);
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
// ── updateAgentStatus ─────────────────────────────────────────────────────────
|
|
219
|
+
describe("updateAgentStatus", () => {
|
|
220
|
+
it("updates agent status field", () => {
|
|
221
|
+
makeSquad();
|
|
222
|
+
const agent = addSquadAgent("test-squad", "Dev", "Code");
|
|
223
|
+
updateAgentStatus("test-squad", agent.character_name, "working");
|
|
224
|
+
assert.equal(getSquadAgent("test-squad", agent.character_name)?.status, "working");
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
// ── reconcileAgentStatuses ────────────────────────────────────────────────────
|
|
228
|
+
describe("reconcileAgentStatuses", () => {
|
|
229
|
+
it("resets working/error agents to idle and returns count", () => {
|
|
230
|
+
makeSquad();
|
|
231
|
+
const a1 = addSquadAgent("test-squad", "Dev", "Code");
|
|
232
|
+
const a2 = addSquadAgent("test-squad", "QA", "Test");
|
|
233
|
+
updateAgentStatus("test-squad", a1.character_name, "working");
|
|
234
|
+
updateAgentStatus("test-squad", a2.character_name, "error");
|
|
235
|
+
const count = reconcileAgentStatuses();
|
|
236
|
+
assert.equal(count, 2);
|
|
237
|
+
assert.equal(getSquadAgent("test-squad", a1.character_name)?.status, "idle");
|
|
238
|
+
assert.equal(getSquadAgent("test-squad", a2.character_name)?.status, "idle");
|
|
239
|
+
});
|
|
240
|
+
it("does not touch already-idle agents", () => {
|
|
241
|
+
makeSquad();
|
|
242
|
+
addSquadAgent("test-squad", "Dev", "Code");
|
|
243
|
+
const count = reconcileAgentStatuses();
|
|
244
|
+
assert.equal(count, 0);
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
// ── reconcileSquadStatuses ────────────────────────────────────────────────────
|
|
248
|
+
describe("reconcileSquadStatuses", () => {
|
|
249
|
+
it("resets working/error squads to idle", () => {
|
|
250
|
+
makeSquad("sq-working");
|
|
251
|
+
makeSquad("sq-error");
|
|
252
|
+
updateSquadStatus("sq-working", "working");
|
|
253
|
+
updateSquadStatus("sq-error", "error");
|
|
254
|
+
const count = reconcileSquadStatuses();
|
|
255
|
+
assert.equal(count, 2);
|
|
256
|
+
assert.equal(getSquad("sq-working")?.status, "idle");
|
|
257
|
+
assert.equal(getSquad("sq-error")?.status, "idle");
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
// ── logDecision / getDecisions ────────────────────────────────────────────────
|
|
261
|
+
describe("logDecision / getDecisions", () => {
|
|
262
|
+
it("round-trips a decision with context", () => {
|
|
263
|
+
makeSquad();
|
|
264
|
+
logDecision("test-squad", "use TypeScript", "type safety");
|
|
265
|
+
const decisions = getDecisions("test-squad");
|
|
266
|
+
assert.equal(decisions.length, 1);
|
|
267
|
+
assert.equal(decisions[0].decision, "use TypeScript");
|
|
268
|
+
assert.equal(decisions[0].context, "type safety");
|
|
269
|
+
assert.equal(decisions[0].squad_slug, "test-squad");
|
|
270
|
+
});
|
|
271
|
+
it("stores null context when not provided", () => {
|
|
272
|
+
makeSquad();
|
|
273
|
+
logDecision("test-squad", "no context decision");
|
|
274
|
+
assert.equal(getDecisions("test-squad")[0].context, null);
|
|
275
|
+
});
|
|
276
|
+
it("returns newest first by default", () => {
|
|
277
|
+
makeSquad();
|
|
278
|
+
// Use explicit timestamps to avoid same-second ordering ambiguity
|
|
279
|
+
const db = getDb();
|
|
280
|
+
db.prepare("INSERT INTO squad_decisions (squad_slug, decision, context, created_at) VALUES (?, ?, ?, ?)").run("test-squad", "older", null, "2020-01-01 00:00:01");
|
|
281
|
+
db.prepare("INSERT INTO squad_decisions (squad_slug, decision, context, created_at) VALUES (?, ?, ?, ?)").run("test-squad", "newer", null, "2020-01-01 00:00:02");
|
|
282
|
+
const decisions = getDecisions("test-squad");
|
|
283
|
+
assert.equal(decisions[0].decision, "newer");
|
|
284
|
+
assert.equal(decisions[1].decision, "older");
|
|
285
|
+
});
|
|
286
|
+
it("respects the limit parameter", () => {
|
|
287
|
+
makeSquad();
|
|
288
|
+
for (let i = 0; i < 10; i++)
|
|
289
|
+
logDecision("test-squad", `decision ${i}`);
|
|
290
|
+
assert.equal(getDecisions("test-squad", 5).length, 5);
|
|
291
|
+
});
|
|
292
|
+
it("returns empty array for squad with no decisions", () => {
|
|
293
|
+
makeSquad();
|
|
294
|
+
assert.deepEqual(getDecisions("test-squad"), []);
|
|
295
|
+
});
|
|
296
|
+
});
|
|
297
|
+
// ── getDecisionsSummary ───────────────────────────────────────────────────────
|
|
298
|
+
describe("getDecisionsSummary", () => {
|
|
299
|
+
it("returns 'No decisions recorded.' for empty squad", () => {
|
|
300
|
+
makeSquad();
|
|
301
|
+
assert.equal(getDecisionsSummary("test-squad"), "No decisions recorded.");
|
|
302
|
+
});
|
|
303
|
+
it("includes decision text in summary", () => {
|
|
304
|
+
makeSquad();
|
|
305
|
+
logDecision("test-squad", "use SQLite", "simple and fast");
|
|
306
|
+
const summary = getDecisionsSummary("test-squad");
|
|
307
|
+
assert.ok(summary.includes("use SQLite"));
|
|
308
|
+
assert.ok(summary.includes("simple and fast"));
|
|
309
|
+
});
|
|
310
|
+
});
|
|
311
|
+
// ── setSquadLead / getSquadLead ───────────────────────────────────────────────
|
|
312
|
+
describe("setSquadLead / getSquadLead", () => {
|
|
313
|
+
it("sets and retrieves the squad lead", () => {
|
|
314
|
+
makeSquad();
|
|
315
|
+
const agent = addSquadAgent("test-squad", "Lead Dev", "Lead the team");
|
|
316
|
+
setSquadLead("test-squad", agent.character_name);
|
|
317
|
+
const lead = getSquadLead("test-squad");
|
|
318
|
+
assert.ok(lead);
|
|
319
|
+
assert.equal(lead.character_name, agent.character_name);
|
|
320
|
+
assert.equal(lead.is_lead, 1);
|
|
321
|
+
});
|
|
322
|
+
it("replaces previous lead (only one lead at a time)", () => {
|
|
323
|
+
makeSquad();
|
|
324
|
+
const a1 = addSquadAgent("test-squad", "Dev 1", "Code");
|
|
325
|
+
const a2 = addSquadAgent("test-squad", "Dev 2", "Code more");
|
|
326
|
+
setSquadLead("test-squad", a1.character_name);
|
|
327
|
+
setSquadLead("test-squad", a2.character_name);
|
|
328
|
+
assert.equal(getSquadLead("test-squad")?.character_name, a2.character_name);
|
|
329
|
+
assert.equal(getSquadAgent("test-squad", a1.character_name)?.is_lead, 0);
|
|
330
|
+
});
|
|
331
|
+
it("returns undefined when no lead is set", () => {
|
|
332
|
+
makeSquad();
|
|
333
|
+
addSquadAgent("test-squad", "Dev", "Code");
|
|
334
|
+
assert.equal(getSquadLead("test-squad"), undefined);
|
|
335
|
+
});
|
|
336
|
+
});
|
|
337
|
+
// ── setSquadQA ────────────────────────────────────────────────────────────────
|
|
338
|
+
describe("setSquadQA", () => {
|
|
339
|
+
it("marks an agent as QA", () => {
|
|
340
|
+
makeSquad();
|
|
341
|
+
const agent = addSquadAgent("test-squad", "QA", "Test all the things");
|
|
342
|
+
setSquadQA("test-squad", agent.character_name, true);
|
|
343
|
+
assert.equal(getSquadAgent("test-squad", agent.character_name)?.is_qa, 1);
|
|
344
|
+
});
|
|
345
|
+
it("unmarks a QA agent", () => {
|
|
346
|
+
makeSquad();
|
|
347
|
+
const agent = addSquadAgent("test-squad", "QA", "Test");
|
|
348
|
+
setSquadQA("test-squad", agent.character_name, true);
|
|
349
|
+
setSquadQA("test-squad", agent.character_name, false);
|
|
350
|
+
assert.equal(getSquadAgent("test-squad", agent.character_name)?.is_qa, 0);
|
|
351
|
+
});
|
|
352
|
+
});
|
|
353
|
+
//# sourceMappingURL=squads.test.js.map
|
package/dist/tui/index.js
CHANGED
|
@@ -129,7 +129,7 @@ function renderActivity(taskIdArg) {
|
|
|
129
129
|
}
|
|
130
130
|
}
|
|
131
131
|
function renderInbox() {
|
|
132
|
-
const entries = listFeedEntries({ type: "
|
|
132
|
+
const entries = listFeedEntries({ type: "inbox" });
|
|
133
133
|
if (entries.length === 0) {
|
|
134
134
|
console.log("\u2705 Inbox is empty.");
|
|
135
135
|
return;
|
|
@@ -205,7 +205,7 @@ export async function startTui() {
|
|
|
205
205
|
renderInbox();
|
|
206
206
|
}
|
|
207
207
|
else if (sub === "clear") {
|
|
208
|
-
const entries = listFeedEntries({ type: "
|
|
208
|
+
const entries = listFeedEntries({ type: "inbox" });
|
|
209
209
|
let deleted = 0;
|
|
210
210
|
for (const entry of entries) {
|
|
211
211
|
if (deleteFeedEntry(entry.id))
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "heyio",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.32.0",
|
|
4
4
|
"description": "IO — a personal AI assistant built on the GitHub Copilot SDK",
|
|
5
5
|
"bin": {
|
|
6
6
|
"io": "dist/index.js"
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"tui": "tsx src/tui/index.ts",
|
|
20
20
|
"dev": "tsx --watch src/daemon.ts",
|
|
21
21
|
"prepublishOnly": "npm run build:all",
|
|
22
|
-
"test": "node --import tsx --test 'src/**/*.test.ts'"
|
|
22
|
+
"test": "node --import tsx --test 'src/**/*.test.ts' && npm test --prefix web"
|
|
23
23
|
},
|
|
24
24
|
"engines": {
|
|
25
25
|
"node": ">=22"
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
"homepage": "https://github.com/michaeljolley/io#readme",
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"@github/copilot-sdk": "^0.2.2",
|
|
45
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
45
46
|
"better-sqlite3": "^12.6.2",
|
|
46
47
|
"commander": "^14.0.0",
|
|
47
48
|
"dotenv": "^17.3.1",
|
|
@@ -52,7 +53,7 @@
|
|
|
52
53
|
"devDependencies": {
|
|
53
54
|
"@types/better-sqlite3": "^7.6.13",
|
|
54
55
|
"@types/express": "^5.0.6",
|
|
55
|
-
"@types/node": "^25.
|
|
56
|
+
"@types/node": "^25.9.1",
|
|
56
57
|
"tsx": "^4.21.0",
|
|
57
58
|
"typescript": "^5.9.3",
|
|
58
59
|
"vue-tsc": "^3.2.9"
|