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/store/db.js
CHANGED
|
@@ -1,263 +1,224 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { pickSquadColor } from "./squad-colors.js";
|
|
1
|
+
import { mkdirSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { createClient } from '@libsql/client';
|
|
4
|
+
import { createChildLogger } from '../logging/logger.js';
|
|
6
5
|
let db;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
6
|
+
let logger;
|
|
7
|
+
const MIGRATIONS = [
|
|
8
|
+
{
|
|
9
|
+
version: 1,
|
|
10
|
+
statements: [
|
|
11
|
+
`CREATE TABLE IF NOT EXISTS conversations (
|
|
12
|
+
id TEXT PRIMARY KEY,
|
|
13
|
+
role TEXT NOT NULL,
|
|
14
|
+
content TEXT NOT NULL,
|
|
15
|
+
source TEXT,
|
|
16
|
+
attachments TEXT,
|
|
17
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
18
|
+
)`,
|
|
19
|
+
`CREATE TABLE IF NOT EXISTS squads (
|
|
20
|
+
id TEXT PRIMARY KEY,
|
|
21
|
+
name TEXT NOT NULL UNIQUE,
|
|
22
|
+
project_path TEXT NOT NULL,
|
|
23
|
+
repo_url TEXT,
|
|
24
|
+
autonomy_tier TEXT NOT NULL DEFAULT 'medium',
|
|
25
|
+
autonomy_config TEXT,
|
|
26
|
+
status TEXT DEFAULT 'active',
|
|
27
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
28
|
+
)`,
|
|
29
|
+
`CREATE TABLE IF NOT EXISTS squad_members (
|
|
30
|
+
id TEXT PRIMARY KEY,
|
|
31
|
+
squad_id TEXT NOT NULL REFERENCES squads(id),
|
|
32
|
+
role_name TEXT NOT NULL,
|
|
33
|
+
skill_file_path TEXT,
|
|
34
|
+
tools_allowed TEXT,
|
|
35
|
+
is_veto_member INTEGER DEFAULT 0,
|
|
36
|
+
status TEXT DEFAULT 'active',
|
|
37
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
38
|
+
)`,
|
|
39
|
+
`CREATE TABLE IF NOT EXISTS squad_instances (
|
|
40
|
+
id TEXT PRIMARY KEY,
|
|
41
|
+
squad_id TEXT NOT NULL REFERENCES squads(id),
|
|
42
|
+
issue_ref TEXT,
|
|
43
|
+
worktree_path TEXT,
|
|
44
|
+
branch_name TEXT,
|
|
45
|
+
status TEXT DEFAULT 'planning',
|
|
46
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
47
|
+
completed_at DATETIME
|
|
48
|
+
)`,
|
|
49
|
+
`CREATE TABLE IF NOT EXISTS decisions (
|
|
50
|
+
id TEXT PRIMARY KEY,
|
|
51
|
+
squad_id TEXT NOT NULL REFERENCES squads(id),
|
|
52
|
+
instance_id TEXT REFERENCES squad_instances(id),
|
|
53
|
+
agent_role TEXT NOT NULL,
|
|
54
|
+
decision_type TEXT,
|
|
55
|
+
content TEXT NOT NULL,
|
|
56
|
+
rationale TEXT,
|
|
57
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
58
|
+
)`,
|
|
59
|
+
`CREATE TABLE IF NOT EXISTS token_usage (
|
|
60
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
61
|
+
squad_id TEXT REFERENCES squads(id),
|
|
62
|
+
instance_id TEXT REFERENCES squad_instances(id),
|
|
63
|
+
agent_role TEXT,
|
|
64
|
+
model TEXT NOT NULL,
|
|
65
|
+
input_tokens INTEGER NOT NULL,
|
|
66
|
+
output_tokens INTEGER NOT NULL,
|
|
67
|
+
estimated_cost_usd REAL,
|
|
68
|
+
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
69
|
+
)`,
|
|
70
|
+
`CREATE TABLE IF NOT EXISTS model_pricing (
|
|
71
|
+
model TEXT PRIMARY KEY,
|
|
72
|
+
input_cost_per_1m REAL NOT NULL,
|
|
73
|
+
output_cost_per_1m REAL NOT NULL,
|
|
74
|
+
tier TEXT,
|
|
75
|
+
last_updated DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
76
|
+
)`,
|
|
77
|
+
`CREATE TABLE IF NOT EXISTS attachments (
|
|
78
|
+
id TEXT PRIMARY KEY,
|
|
79
|
+
message_id TEXT,
|
|
80
|
+
filename TEXT NOT NULL,
|
|
81
|
+
mime_type TEXT,
|
|
82
|
+
size_bytes INTEGER,
|
|
83
|
+
disk_path TEXT NOT NULL,
|
|
84
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
85
|
+
)`,
|
|
86
|
+
`CREATE TABLE IF NOT EXISTS agent_activity (
|
|
87
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
88
|
+
squad_id TEXT REFERENCES squads(id),
|
|
89
|
+
instance_id TEXT REFERENCES squad_instances(id),
|
|
90
|
+
agent_role TEXT NOT NULL,
|
|
91
|
+
activity_type TEXT NOT NULL,
|
|
92
|
+
model_used TEXT,
|
|
93
|
+
content TEXT,
|
|
94
|
+
tokens_used INTEGER,
|
|
95
|
+
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
96
|
+
)`,
|
|
97
|
+
`CREATE TABLE IF NOT EXISTS schema_version (
|
|
98
|
+
version INTEGER PRIMARY KEY
|
|
99
|
+
)`,
|
|
100
|
+
`CREATE TABLE IF NOT EXISTS io_state (
|
|
101
|
+
key TEXT PRIMARY KEY,
|
|
102
|
+
value TEXT NOT NULL
|
|
103
|
+
)`,
|
|
104
|
+
'INSERT INTO schema_version (version) VALUES (1)',
|
|
105
|
+
],
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
version: 2,
|
|
109
|
+
statements: [
|
|
110
|
+
`CREATE TABLE IF NOT EXISTS inbox_entries (
|
|
111
|
+
id TEXT PRIMARY KEY,
|
|
112
|
+
squad_id TEXT NOT NULL REFERENCES squads(id),
|
|
113
|
+
instance_id TEXT REFERENCES squad_instances(id),
|
|
114
|
+
kind TEXT NOT NULL,
|
|
115
|
+
title TEXT NOT NULL,
|
|
116
|
+
content TEXT NOT NULL,
|
|
117
|
+
status TEXT DEFAULT 'unread',
|
|
118
|
+
response TEXT,
|
|
119
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
120
|
+
resolved_at DATETIME
|
|
121
|
+
)`,
|
|
122
|
+
'CREATE INDEX IF NOT EXISTS idx_inbox_status ON inbox_entries(status)',
|
|
123
|
+
'CREATE INDEX IF NOT EXISTS idx_inbox_squad ON inbox_entries(squad_id)',
|
|
124
|
+
'INSERT OR REPLACE INTO schema_version (version) VALUES (2)',
|
|
125
|
+
],
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
version: 3,
|
|
129
|
+
statements: [
|
|
130
|
+
`CREATE TABLE IF NOT EXISTS schedules (
|
|
131
|
+
id TEXT PRIMARY KEY,
|
|
132
|
+
name TEXT NOT NULL,
|
|
133
|
+
target_type TEXT NOT NULL,
|
|
134
|
+
target_id TEXT,
|
|
135
|
+
cron TEXT NOT NULL,
|
|
136
|
+
prompt TEXT NOT NULL,
|
|
137
|
+
enabled INTEGER DEFAULT 1,
|
|
138
|
+
last_run DATETIME,
|
|
139
|
+
next_run DATETIME,
|
|
140
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
141
|
+
)`,
|
|
142
|
+
'CREATE INDEX IF NOT EXISTS idx_schedules_enabled ON schedules(enabled)',
|
|
143
|
+
'CREATE INDEX IF NOT EXISTS idx_schedules_next_run ON schedules(next_run)',
|
|
144
|
+
'INSERT OR REPLACE INTO schema_version (version) VALUES (3)',
|
|
145
|
+
],
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
version: 4,
|
|
149
|
+
statements: [
|
|
150
|
+
`CREATE TABLE IF NOT EXISTS skill_activations (
|
|
151
|
+
skill_name TEXT NOT NULL,
|
|
152
|
+
target_type TEXT NOT NULL,
|
|
153
|
+
target_id TEXT,
|
|
154
|
+
activated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
155
|
+
PRIMARY KEY (skill_name, target_type, target_id)
|
|
156
|
+
)`,
|
|
157
|
+
'CREATE INDEX IF NOT EXISTS idx_skill_activations_target ON skill_activations(target_type, target_id)',
|
|
158
|
+
'INSERT OR REPLACE INTO schema_version (version) VALUES (4)',
|
|
159
|
+
],
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
version: 5,
|
|
163
|
+
statements: [
|
|
164
|
+
'ALTER TABLE squads ADD COLUMN universe TEXT',
|
|
165
|
+
'ALTER TABLE squad_members ADD COLUMN display_name TEXT',
|
|
166
|
+
'INSERT OR REPLACE INTO schema_version (version) VALUES (5)',
|
|
167
|
+
],
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
version: 6,
|
|
171
|
+
statements: [
|
|
172
|
+
'ALTER TABLE squad_members ADD COLUMN persona TEXT',
|
|
173
|
+
'INSERT OR REPLACE INTO schema_version (version) VALUES (6)',
|
|
174
|
+
],
|
|
175
|
+
},
|
|
176
|
+
];
|
|
177
|
+
export async function initDatabase(dataDir) {
|
|
178
|
+
logger = createChildLogger('store');
|
|
179
|
+
mkdirSync(dataDir, { recursive: true });
|
|
180
|
+
const dbPath = join(dataDir, 'io.db');
|
|
181
|
+
db = createClient({
|
|
182
|
+
url: `file:${dbPath}`,
|
|
183
|
+
});
|
|
184
|
+
await db.execute('PRAGMA journal_mode = WAL');
|
|
185
|
+
await db.execute('PRAGMA foreign_keys = ON');
|
|
186
|
+
await runMigrations();
|
|
187
|
+
logger.info({ path: dbPath }, 'Database initialized');
|
|
17
188
|
return db;
|
|
18
189
|
}
|
|
19
|
-
function runMigrations(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
if (version < 1) {
|
|
28
|
-
db.exec(`
|
|
29
|
-
CREATE TABLE IF NOT EXISTS squads (
|
|
30
|
-
id TEXT PRIMARY KEY,
|
|
31
|
-
name TEXT NOT NULL,
|
|
32
|
-
universe TEXT NOT NULL,
|
|
33
|
-
repo_url TEXT,
|
|
34
|
-
rules TEXT DEFAULT '',
|
|
35
|
-
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
36
|
-
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
37
|
-
);
|
|
38
|
-
|
|
39
|
-
CREATE TABLE IF NOT EXISTS agents (
|
|
40
|
-
id TEXT PRIMARY KEY,
|
|
41
|
-
squad_id TEXT NOT NULL REFERENCES squads(id) ON DELETE CASCADE,
|
|
42
|
-
character_name TEXT NOT NULL,
|
|
43
|
-
role_title TEXT NOT NULL,
|
|
44
|
-
persona TEXT DEFAULT '',
|
|
45
|
-
is_lead INTEGER NOT NULL DEFAULT 0,
|
|
46
|
-
is_qa INTEGER NOT NULL DEFAULT 0,
|
|
47
|
-
is_test INTEGER NOT NULL DEFAULT 0,
|
|
48
|
-
status TEXT NOT NULL DEFAULT 'idle',
|
|
49
|
-
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
50
|
-
);
|
|
51
|
-
|
|
52
|
-
CREATE TABLE IF NOT EXISTS tasks (
|
|
53
|
-
id TEXT PRIMARY KEY,
|
|
54
|
-
squad_id TEXT NOT NULL REFERENCES squads(id) ON DELETE CASCADE,
|
|
55
|
-
instance_id TEXT,
|
|
56
|
-
agent_id TEXT REFERENCES agents(id) ON DELETE SET NULL,
|
|
57
|
-
description TEXT NOT NULL,
|
|
58
|
-
status TEXT NOT NULL DEFAULT 'pending',
|
|
59
|
-
result TEXT,
|
|
60
|
-
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
61
|
-
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
62
|
-
);
|
|
63
|
-
|
|
64
|
-
CREATE TABLE IF NOT EXISTS instances (
|
|
65
|
-
id TEXT PRIMARY KEY,
|
|
66
|
-
squad_id TEXT NOT NULL REFERENCES squads(id) ON DELETE CASCADE,
|
|
67
|
-
branch TEXT NOT NULL,
|
|
68
|
-
worktree_path TEXT NOT NULL,
|
|
69
|
-
status TEXT NOT NULL DEFAULT 'active',
|
|
70
|
-
last_activity TEXT NOT NULL DEFAULT (datetime('now')),
|
|
71
|
-
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
72
|
-
);
|
|
73
|
-
|
|
74
|
-
CREATE TABLE IF NOT EXISTS feed_items (
|
|
75
|
-
id TEXT PRIMARY KEY,
|
|
76
|
-
source TEXT NOT NULL,
|
|
77
|
-
title TEXT NOT NULL,
|
|
78
|
-
content TEXT NOT NULL DEFAULT '',
|
|
79
|
-
read INTEGER NOT NULL DEFAULT 0,
|
|
80
|
-
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
81
|
-
);
|
|
82
|
-
|
|
83
|
-
CREATE TABLE IF NOT EXISTS schedules (
|
|
84
|
-
id TEXT PRIMARY KEY,
|
|
85
|
-
type TEXT NOT NULL CHECK(type IN ('squad', 'io')),
|
|
86
|
-
squad_id TEXT REFERENCES squads(id) ON DELETE CASCADE,
|
|
87
|
-
cron TEXT NOT NULL,
|
|
88
|
-
agenda TEXT NOT NULL DEFAULT '',
|
|
89
|
-
prompt TEXT NOT NULL DEFAULT '',
|
|
90
|
-
enabled INTEGER NOT NULL DEFAULT 1,
|
|
91
|
-
last_run TEXT,
|
|
92
|
-
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
93
|
-
);
|
|
94
|
-
|
|
95
|
-
CREATE TABLE IF NOT EXISTS session_state (
|
|
96
|
-
key TEXT PRIMARY KEY,
|
|
97
|
-
value TEXT NOT NULL
|
|
98
|
-
);
|
|
99
|
-
|
|
100
|
-
CREATE TABLE IF NOT EXISTS mcp_servers (
|
|
101
|
-
id TEXT PRIMARY KEY,
|
|
102
|
-
name TEXT NOT NULL,
|
|
103
|
-
type TEXT NOT NULL CHECK(type IN ('stdio', 'http')),
|
|
104
|
-
config TEXT NOT NULL DEFAULT '{}',
|
|
105
|
-
enabled INTEGER NOT NULL DEFAULT 1,
|
|
106
|
-
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
107
|
-
);
|
|
108
|
-
|
|
109
|
-
CREATE TABLE IF NOT EXISTS mcp_tools (
|
|
110
|
-
id TEXT PRIMARY KEY,
|
|
111
|
-
server_id TEXT NOT NULL REFERENCES mcp_servers(id) ON DELETE CASCADE,
|
|
112
|
-
name TEXT NOT NULL,
|
|
113
|
-
description TEXT DEFAULT '',
|
|
114
|
-
enabled INTEGER NOT NULL DEFAULT 1
|
|
115
|
-
);
|
|
116
|
-
`);
|
|
117
|
-
setSchemaVersion(db, 1);
|
|
118
|
-
}
|
|
119
|
-
if (version < 2) {
|
|
120
|
-
db.exec(`
|
|
121
|
-
ALTER TABLE squads ADD COLUMN slug TEXT;
|
|
122
|
-
`);
|
|
123
|
-
// Backfill slugs for existing squads
|
|
124
|
-
const squads = db.prepare("SELECT id, name FROM squads WHERE slug IS NULL").all();
|
|
125
|
-
const update = db.prepare("UPDATE squads SET slug = ? WHERE id = ?");
|
|
126
|
-
for (const s of squads) {
|
|
127
|
-
const slug = s.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
128
|
-
update.run(slug || s.id, s.id);
|
|
190
|
+
async function runMigrations() {
|
|
191
|
+
const currentVersion = await getCurrentVersion();
|
|
192
|
+
for (const migration of MIGRATIONS) {
|
|
193
|
+
if (migration.version > currentVersion) {
|
|
194
|
+
logger.info({ version: migration.version }, 'Running migration');
|
|
195
|
+
for (const statement of migration.statements) {
|
|
196
|
+
await db.execute(statement);
|
|
197
|
+
}
|
|
129
198
|
}
|
|
130
|
-
setSchemaVersion(db, 2);
|
|
131
|
-
}
|
|
132
|
-
if (version < 3) {
|
|
133
|
-
db.exec(`
|
|
134
|
-
CREATE TABLE IF NOT EXISTS agent_events (
|
|
135
|
-
id TEXT PRIMARY KEY,
|
|
136
|
-
task_id TEXT NOT NULL,
|
|
137
|
-
type TEXT NOT NULL,
|
|
138
|
-
summary TEXT NOT NULL DEFAULT '',
|
|
139
|
-
payload TEXT NOT NULL DEFAULT '{}',
|
|
140
|
-
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
141
|
-
);
|
|
142
|
-
|
|
143
|
-
CREATE INDEX IF NOT EXISTS idx_agent_events_task_id ON agent_events (task_id);
|
|
144
|
-
`);
|
|
145
|
-
setSchemaVersion(db, 3);
|
|
146
199
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
.
|
|
153
|
-
.all();
|
|
154
|
-
const update = db.prepare("UPDATE squads SET color = ? WHERE id = ?");
|
|
155
|
-
const usedColors = [];
|
|
156
|
-
for (let i = 0; i < squads.length; i++) {
|
|
157
|
-
const color = pickSquadColor(usedColors);
|
|
158
|
-
usedColors.push(color);
|
|
159
|
-
update.run(color, squads[i].id);
|
|
200
|
+
}
|
|
201
|
+
async function getCurrentVersion() {
|
|
202
|
+
try {
|
|
203
|
+
const result = await db.execute('SELECT version FROM schema_version ORDER BY version DESC LIMIT 1');
|
|
204
|
+
if (result.rows.length > 0) {
|
|
205
|
+
return result.rows[0].version;
|
|
160
206
|
}
|
|
161
|
-
|
|
162
|
-
}
|
|
163
|
-
if (version < 5) {
|
|
164
|
-
db.exec(`
|
|
165
|
-
CREATE TABLE IF NOT EXISTS conversation_messages (
|
|
166
|
-
id TEXT PRIMARY KEY,
|
|
167
|
-
conversation_id TEXT NOT NULL,
|
|
168
|
-
role TEXT NOT NULL CHECK(role IN ('user', 'assistant')),
|
|
169
|
-
content TEXT NOT NULL,
|
|
170
|
-
source TEXT NOT NULL DEFAULT 'web',
|
|
171
|
-
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
172
|
-
);
|
|
173
|
-
|
|
174
|
-
CREATE INDEX IF NOT EXISTS idx_conv_messages_conversation_id
|
|
175
|
-
ON conversation_messages(conversation_id);
|
|
176
|
-
|
|
177
|
-
CREATE INDEX IF NOT EXISTS idx_conv_messages_created_at
|
|
178
|
-
ON conversation_messages(created_at);
|
|
179
|
-
|
|
180
|
-
CREATE VIRTUAL TABLE IF NOT EXISTS conversation_messages_fts
|
|
181
|
-
USING fts5(content, content=conversation_messages, content_rowid=rowid);
|
|
182
|
-
|
|
183
|
-
CREATE TRIGGER IF NOT EXISTS conv_messages_fts_insert
|
|
184
|
-
AFTER INSERT ON conversation_messages BEGIN
|
|
185
|
-
INSERT INTO conversation_messages_fts(rowid, content) VALUES (new.rowid, new.content);
|
|
186
|
-
END;
|
|
187
|
-
|
|
188
|
-
CREATE TRIGGER IF NOT EXISTS conv_messages_fts_update
|
|
189
|
-
AFTER UPDATE ON conversation_messages BEGIN
|
|
190
|
-
INSERT INTO conversation_messages_fts(conversation_messages_fts, rowid, content) VALUES ('delete', old.rowid, old.content);
|
|
191
|
-
INSERT INTO conversation_messages_fts(rowid, content) VALUES (new.rowid, new.content);
|
|
192
|
-
END;
|
|
193
|
-
|
|
194
|
-
CREATE TRIGGER IF NOT EXISTS conv_messages_fts_delete
|
|
195
|
-
AFTER DELETE ON conversation_messages BEGIN
|
|
196
|
-
INSERT INTO conversation_messages_fts(conversation_messages_fts, rowid, content) VALUES ('delete', old.rowid, old.content);
|
|
197
|
-
END;
|
|
198
|
-
`);
|
|
199
|
-
setSchemaVersion(db, 5);
|
|
200
|
-
}
|
|
201
|
-
if (version < 6) {
|
|
202
|
-
db.exec(`
|
|
203
|
-
CREATE TABLE IF NOT EXISTS audit_log (
|
|
204
|
-
id TEXT PRIMARY KEY,
|
|
205
|
-
squad_id TEXT REFERENCES squads(id) ON DELETE SET NULL,
|
|
206
|
-
agent_id TEXT REFERENCES agents(id) ON DELETE SET NULL,
|
|
207
|
-
task_id TEXT,
|
|
208
|
-
action_type TEXT NOT NULL,
|
|
209
|
-
summary TEXT NOT NULL DEFAULT '',
|
|
210
|
-
payload TEXT NOT NULL DEFAULT '{}',
|
|
211
|
-
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
212
|
-
);
|
|
213
|
-
|
|
214
|
-
CREATE INDEX IF NOT EXISTS idx_audit_log_squad_id ON audit_log (squad_id);
|
|
215
|
-
CREATE INDEX IF NOT EXISTS idx_audit_log_agent_id ON audit_log (agent_id);
|
|
216
|
-
CREATE INDEX IF NOT EXISTS idx_audit_log_action_type ON audit_log (action_type);
|
|
217
|
-
CREATE INDEX IF NOT EXISTS idx_audit_log_created_at ON audit_log (created_at);
|
|
218
|
-
`);
|
|
219
|
-
setSchemaVersion(db, 6);
|
|
207
|
+
return 0;
|
|
220
208
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
CREATE TABLE IF NOT EXISTS token_usage (
|
|
224
|
-
id TEXT PRIMARY KEY,
|
|
225
|
-
squad_id TEXT REFERENCES squads(id) ON DELETE CASCADE,
|
|
226
|
-
agent_id TEXT REFERENCES agents(id) ON DELETE SET NULL,
|
|
227
|
-
task_id TEXT REFERENCES tasks(id) ON DELETE SET NULL,
|
|
228
|
-
model TEXT NOT NULL,
|
|
229
|
-
input_tokens INTEGER NOT NULL DEFAULT 0,
|
|
230
|
-
output_tokens INTEGER NOT NULL DEFAULT 0,
|
|
231
|
-
cost_usd REAL NOT NULL DEFAULT 0,
|
|
232
|
-
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
233
|
-
);
|
|
234
|
-
|
|
235
|
-
CREATE INDEX IF NOT EXISTS idx_token_usage_squad ON token_usage(squad_id);
|
|
236
|
-
CREATE INDEX IF NOT EXISTS idx_token_usage_agent ON token_usage(agent_id);
|
|
237
|
-
CREATE INDEX IF NOT EXISTS idx_token_usage_task ON token_usage(task_id);
|
|
238
|
-
CREATE INDEX IF NOT EXISTS idx_token_usage_created ON token_usage(created_at);
|
|
239
|
-
`);
|
|
240
|
-
setSchemaVersion(db, 7);
|
|
209
|
+
catch {
|
|
210
|
+
return 0;
|
|
241
211
|
}
|
|
242
|
-
if (version < 8) {
|
|
243
|
-
db.exec(`
|
|
244
|
-
ALTER TABLE conversation_messages
|
|
245
|
-
ADD COLUMN attachments TEXT NOT NULL DEFAULT '[]';
|
|
246
|
-
`);
|
|
247
|
-
setSchemaVersion(db, 8);
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
function getSchemaVersion(db) {
|
|
251
|
-
const row = db.prepare("SELECT value FROM meta WHERE key = 'schema_version'").get();
|
|
252
|
-
return row ? parseInt(row.value, 10) : 0;
|
|
253
212
|
}
|
|
254
|
-
function
|
|
255
|
-
|
|
213
|
+
export function getDatabase() {
|
|
214
|
+
if (!db) {
|
|
215
|
+
throw new Error('Database not initialized. Call initDatabase() first.');
|
|
216
|
+
}
|
|
217
|
+
return db;
|
|
256
218
|
}
|
|
257
|
-
export function
|
|
219
|
+
export function closeDatabase() {
|
|
258
220
|
if (db) {
|
|
259
221
|
db.close();
|
|
260
|
-
db = undefined;
|
|
261
222
|
}
|
|
262
223
|
}
|
|
263
224
|
//# sourceMappingURL=db.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db.js","sourceRoot":"","sources":["../../src/store/db.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export type InboxKind = 'deliverable' | 'question';
|
|
2
|
+
export type InboxStatus = 'unread' | 'read' | 'resolved';
|
|
3
|
+
export interface InboxEntry {
|
|
4
|
+
id: string;
|
|
5
|
+
squadId: string;
|
|
6
|
+
instanceId: string | null;
|
|
7
|
+
kind: InboxKind;
|
|
8
|
+
title: string;
|
|
9
|
+
content: string;
|
|
10
|
+
status: InboxStatus;
|
|
11
|
+
response: string | null;
|
|
12
|
+
createdAt: string;
|
|
13
|
+
resolvedAt: string | null;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Add a new inbox entry. For questions, returns a promise that resolves when the user responds.
|
|
17
|
+
*/
|
|
18
|
+
export declare function addInboxEntry(params: {
|
|
19
|
+
squadId: string;
|
|
20
|
+
instanceId?: string;
|
|
21
|
+
kind: InboxKind;
|
|
22
|
+
title: string;
|
|
23
|
+
content: string;
|
|
24
|
+
}): Promise<{
|
|
25
|
+
entry: InboxEntry;
|
|
26
|
+
waitForResponse?: Promise<string>;
|
|
27
|
+
}>;
|
|
28
|
+
/**
|
|
29
|
+
* List inbox entries with optional filters.
|
|
30
|
+
*/
|
|
31
|
+
export declare function listInboxEntries(filters?: {
|
|
32
|
+
status?: InboxStatus;
|
|
33
|
+
squadId?: string;
|
|
34
|
+
kind?: InboxKind;
|
|
35
|
+
limit?: number;
|
|
36
|
+
}): Promise<InboxEntry[]>;
|
|
37
|
+
/**
|
|
38
|
+
* Get a single inbox entry by ID.
|
|
39
|
+
*/
|
|
40
|
+
export declare function getInboxEntry(id: string): Promise<InboxEntry | null>;
|
|
41
|
+
/**
|
|
42
|
+
* Mark an entry as read.
|
|
43
|
+
*/
|
|
44
|
+
export declare function markInboxRead(id: string): Promise<void>;
|
|
45
|
+
/**
|
|
46
|
+
* Respond to an inbox question. Resolves the blocking promise if the squad is waiting.
|
|
47
|
+
*/
|
|
48
|
+
export declare function resolveInboxEntry(id: string, response: string): Promise<boolean>;
|
|
49
|
+
/**
|
|
50
|
+
* Get count of unread entries.
|
|
51
|
+
*/
|
|
52
|
+
export declare function getUnreadCount(): Promise<number>;
|
|
53
|
+
//# sourceMappingURL=inbox.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inbox.d.ts","sourceRoot":"","sources":["../../src/store/inbox.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,SAAS,GAAG,aAAa,GAAG,UAAU,CAAC;AACnD,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,MAAM,GAAG,UAAU,CAAC;AAEzD,MAAM,WAAW,UAAU;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAKD;;GAEG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC;IAAE,KAAK,EAAE,UAAU,CAAC;IAAC,eAAe,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,CAAA;CAAE,CAAC,CAoDpE;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,CAAC,EAAE;IAChD,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CACf,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CA8BxB;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAQ1E;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAM7D;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAiBtF;AAED;;GAEG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,CAMtD"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { createChildLogger } from '../logging/logger.js';
|
|
2
|
+
import { getEventBus } from '../squad/event-bus.js';
|
|
3
|
+
import { getDatabase } from './db.js';
|
|
4
|
+
const logger = () => createChildLogger('inbox');
|
|
5
|
+
// Pending question resolvers — keyed by entry ID
|
|
6
|
+
const pendingQuestions = new Map();
|
|
7
|
+
/**
|
|
8
|
+
* Add a new inbox entry. For questions, returns a promise that resolves when the user responds.
|
|
9
|
+
*/
|
|
10
|
+
export async function addInboxEntry(params) {
|
|
11
|
+
const db = getDatabase();
|
|
12
|
+
const id = crypto.randomUUID();
|
|
13
|
+
await db.execute({
|
|
14
|
+
sql: `INSERT INTO inbox_entries (id, squad_id, instance_id, kind, title, content)
|
|
15
|
+
VALUES (?, ?, ?, ?, ?, ?)`,
|
|
16
|
+
args: [
|
|
17
|
+
id,
|
|
18
|
+
params.squadId,
|
|
19
|
+
params.instanceId ?? null,
|
|
20
|
+
params.kind,
|
|
21
|
+
params.title,
|
|
22
|
+
params.content,
|
|
23
|
+
],
|
|
24
|
+
});
|
|
25
|
+
const entry = {
|
|
26
|
+
id,
|
|
27
|
+
squadId: params.squadId,
|
|
28
|
+
instanceId: params.instanceId ?? null,
|
|
29
|
+
kind: params.kind,
|
|
30
|
+
title: params.title,
|
|
31
|
+
content: params.content,
|
|
32
|
+
status: 'unread',
|
|
33
|
+
response: null,
|
|
34
|
+
createdAt: new Date().toISOString(),
|
|
35
|
+
resolvedAt: null,
|
|
36
|
+
};
|
|
37
|
+
let waitForResponse;
|
|
38
|
+
if (params.kind === 'question') {
|
|
39
|
+
waitForResponse = new Promise((resolve) => {
|
|
40
|
+
pendingQuestions.set(id, resolve);
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
// Emit event for WebSocket broadcast
|
|
44
|
+
getEventBus().emit({
|
|
45
|
+
type: 'inbox:new',
|
|
46
|
+
id: crypto.randomUUID(),
|
|
47
|
+
timestamp: new Date(),
|
|
48
|
+
squadId: params.squadId,
|
|
49
|
+
instanceId: params.instanceId,
|
|
50
|
+
kind: params.kind,
|
|
51
|
+
title: params.title,
|
|
52
|
+
entryId: id,
|
|
53
|
+
});
|
|
54
|
+
logger().info({ id, kind: params.kind, title: params.title }, 'Inbox entry created');
|
|
55
|
+
return { entry, waitForResponse };
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* List inbox entries with optional filters.
|
|
59
|
+
*/
|
|
60
|
+
export async function listInboxEntries(filters) {
|
|
61
|
+
const db = getDatabase();
|
|
62
|
+
const conditions = [];
|
|
63
|
+
const args = [];
|
|
64
|
+
if (filters?.status) {
|
|
65
|
+
conditions.push('status = ?');
|
|
66
|
+
args.push(filters.status);
|
|
67
|
+
}
|
|
68
|
+
if (filters?.squadId) {
|
|
69
|
+
conditions.push('squad_id = ?');
|
|
70
|
+
args.push(filters.squadId);
|
|
71
|
+
}
|
|
72
|
+
if (filters?.kind) {
|
|
73
|
+
conditions.push('kind = ?');
|
|
74
|
+
args.push(filters.kind);
|
|
75
|
+
}
|
|
76
|
+
const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
|
|
77
|
+
const limit = filters?.limit ?? 50;
|
|
78
|
+
const result = await db.execute({
|
|
79
|
+
sql: `SELECT id, squad_id, instance_id, kind, title, content, status, response, created_at, resolved_at
|
|
80
|
+
FROM inbox_entries ${where}
|
|
81
|
+
ORDER BY created_at DESC
|
|
82
|
+
LIMIT ?`,
|
|
83
|
+
args: [...args, limit],
|
|
84
|
+
});
|
|
85
|
+
return result.rows.map(rowToEntry);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Get a single inbox entry by ID.
|
|
89
|
+
*/
|
|
90
|
+
export async function getInboxEntry(id) {
|
|
91
|
+
const db = getDatabase();
|
|
92
|
+
const result = await db.execute({
|
|
93
|
+
sql: 'SELECT id, squad_id, instance_id, kind, title, content, status, response, created_at, resolved_at FROM inbox_entries WHERE id = ?',
|
|
94
|
+
args: [id],
|
|
95
|
+
});
|
|
96
|
+
if (result.rows.length === 0)
|
|
97
|
+
return null;
|
|
98
|
+
return rowToEntry(result.rows[0]);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Mark an entry as read.
|
|
102
|
+
*/
|
|
103
|
+
export async function markInboxRead(id) {
|
|
104
|
+
const db = getDatabase();
|
|
105
|
+
await db.execute({
|
|
106
|
+
sql: "UPDATE inbox_entries SET status = 'read' WHERE id = ? AND status = 'unread'",
|
|
107
|
+
args: [id],
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Respond to an inbox question. Resolves the blocking promise if the squad is waiting.
|
|
112
|
+
*/
|
|
113
|
+
export async function resolveInboxEntry(id, response) {
|
|
114
|
+
const db = getDatabase();
|
|
115
|
+
await db.execute({
|
|
116
|
+
sql: "UPDATE inbox_entries SET status = 'resolved', response = ?, resolved_at = CURRENT_TIMESTAMP WHERE id = ?",
|
|
117
|
+
args: [response, id],
|
|
118
|
+
});
|
|
119
|
+
// Resolve the pending promise if squad is waiting
|
|
120
|
+
const resolver = pendingQuestions.get(id);
|
|
121
|
+
if (resolver) {
|
|
122
|
+
resolver(response);
|
|
123
|
+
pendingQuestions.delete(id);
|
|
124
|
+
logger().info({ id }, 'Inbox question resolved — squad unblocked');
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Get count of unread entries.
|
|
131
|
+
*/
|
|
132
|
+
export async function getUnreadCount() {
|
|
133
|
+
const db = getDatabase();
|
|
134
|
+
const result = await db.execute("SELECT COUNT(*) as count FROM inbox_entries WHERE status = 'unread'");
|
|
135
|
+
return result.rows[0]?.count ?? 0;
|
|
136
|
+
}
|
|
137
|
+
function rowToEntry(row) {
|
|
138
|
+
return {
|
|
139
|
+
id: row.id,
|
|
140
|
+
squadId: row.squad_id,
|
|
141
|
+
instanceId: row.instance_id,
|
|
142
|
+
kind: row.kind,
|
|
143
|
+
title: row.title,
|
|
144
|
+
content: row.content,
|
|
145
|
+
status: row.status,
|
|
146
|
+
response: row.response,
|
|
147
|
+
createdAt: row.created_at,
|
|
148
|
+
resolvedAt: row.resolved_at,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=inbox.js.map
|