@usejarvis/brain 0.1.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/LICENSE +153 -0
- package/README.md +278 -0
- package/bin/jarvis.ts +413 -0
- package/package.json +74 -0
- package/scripts/ensure-bun.cjs +8 -0
- package/src/actions/README.md +421 -0
- package/src/actions/app-control/desktop-controller.test.ts +26 -0
- package/src/actions/app-control/desktop-controller.ts +438 -0
- package/src/actions/app-control/interface.ts +64 -0
- package/src/actions/app-control/linux.ts +273 -0
- package/src/actions/app-control/macos.ts +54 -0
- package/src/actions/app-control/sidecar-launcher.test.ts +23 -0
- package/src/actions/app-control/sidecar-launcher.ts +286 -0
- package/src/actions/app-control/windows.ts +44 -0
- package/src/actions/browser/cdp.ts +138 -0
- package/src/actions/browser/chrome-launcher.ts +252 -0
- package/src/actions/browser/session.ts +437 -0
- package/src/actions/browser/stealth.ts +49 -0
- package/src/actions/index.ts +20 -0
- package/src/actions/terminal/executor.ts +157 -0
- package/src/actions/terminal/wsl-bridge.ts +126 -0
- package/src/actions/test.ts +93 -0
- package/src/actions/tools/agents.ts +321 -0
- package/src/actions/tools/builtin.ts +846 -0
- package/src/actions/tools/commitments.ts +192 -0
- package/src/actions/tools/content.ts +217 -0
- package/src/actions/tools/delegate.ts +147 -0
- package/src/actions/tools/desktop.test.ts +55 -0
- package/src/actions/tools/desktop.ts +305 -0
- package/src/actions/tools/goals.ts +376 -0
- package/src/actions/tools/local-tools-guard.ts +20 -0
- package/src/actions/tools/registry.ts +171 -0
- package/src/actions/tools/research.ts +111 -0
- package/src/actions/tools/sidecar-list.ts +57 -0
- package/src/actions/tools/sidecar-route.ts +105 -0
- package/src/actions/tools/workflows.ts +216 -0
- package/src/agents/agent.ts +132 -0
- package/src/agents/delegation.ts +107 -0
- package/src/agents/hierarchy.ts +113 -0
- package/src/agents/index.ts +19 -0
- package/src/agents/messaging.ts +125 -0
- package/src/agents/orchestrator.ts +576 -0
- package/src/agents/role-discovery.ts +61 -0
- package/src/agents/sub-agent-runner.ts +307 -0
- package/src/agents/task-manager.ts +151 -0
- package/src/authority/approval-delivery.ts +59 -0
- package/src/authority/approval.ts +196 -0
- package/src/authority/audit.ts +158 -0
- package/src/authority/authority.test.ts +519 -0
- package/src/authority/deferred-executor.ts +103 -0
- package/src/authority/emergency.ts +66 -0
- package/src/authority/engine.ts +297 -0
- package/src/authority/index.ts +12 -0
- package/src/authority/learning.ts +111 -0
- package/src/authority/tool-action-map.ts +74 -0
- package/src/awareness/analytics.ts +466 -0
- package/src/awareness/awareness.test.ts +332 -0
- package/src/awareness/capture-engine.ts +305 -0
- package/src/awareness/context-graph.ts +130 -0
- package/src/awareness/context-tracker.ts +349 -0
- package/src/awareness/index.ts +25 -0
- package/src/awareness/intelligence.ts +321 -0
- package/src/awareness/ocr-engine.ts +88 -0
- package/src/awareness/service.ts +528 -0
- package/src/awareness/struggle-detector.ts +342 -0
- package/src/awareness/suggestion-engine.ts +476 -0
- package/src/awareness/types.ts +201 -0
- package/src/cli/autostart.ts +241 -0
- package/src/cli/deps.ts +449 -0
- package/src/cli/doctor.ts +230 -0
- package/src/cli/helpers.ts +401 -0
- package/src/cli/onboard.ts +580 -0
- package/src/comms/README.md +329 -0
- package/src/comms/auth-error.html +48 -0
- package/src/comms/channels/discord.ts +228 -0
- package/src/comms/channels/signal.ts +56 -0
- package/src/comms/channels/telegram.ts +316 -0
- package/src/comms/channels/whatsapp.ts +60 -0
- package/src/comms/channels.test.ts +173 -0
- package/src/comms/desktop-notify.ts +114 -0
- package/src/comms/example.ts +129 -0
- package/src/comms/index.ts +129 -0
- package/src/comms/streaming.ts +142 -0
- package/src/comms/voice.test.ts +152 -0
- package/src/comms/voice.ts +291 -0
- package/src/comms/websocket.test.ts +409 -0
- package/src/comms/websocket.ts +473 -0
- package/src/config/README.md +387 -0
- package/src/config/index.ts +6 -0
- package/src/config/loader.test.ts +137 -0
- package/src/config/loader.ts +142 -0
- package/src/config/types.ts +260 -0
- package/src/daemon/README.md +232 -0
- package/src/daemon/agent-service-interface.ts +9 -0
- package/src/daemon/agent-service.ts +600 -0
- package/src/daemon/api-routes.ts +2119 -0
- package/src/daemon/background-agent-service.ts +396 -0
- package/src/daemon/background-agent.test.ts +78 -0
- package/src/daemon/channel-service.ts +201 -0
- package/src/daemon/commitment-executor.ts +297 -0
- package/src/daemon/event-classifier.ts +239 -0
- package/src/daemon/event-coalescer.ts +123 -0
- package/src/daemon/event-reactor.ts +214 -0
- package/src/daemon/health.ts +220 -0
- package/src/daemon/index.ts +1004 -0
- package/src/daemon/llm-settings.ts +316 -0
- package/src/daemon/observer-service.ts +150 -0
- package/src/daemon/pid.ts +98 -0
- package/src/daemon/research-queue.ts +155 -0
- package/src/daemon/services.ts +175 -0
- package/src/daemon/ws-service.ts +788 -0
- package/src/goals/accountability.ts +240 -0
- package/src/goals/awareness-bridge.ts +185 -0
- package/src/goals/estimator.ts +185 -0
- package/src/goals/events.ts +28 -0
- package/src/goals/goals.test.ts +400 -0
- package/src/goals/integration.test.ts +329 -0
- package/src/goals/nl-builder.test.ts +220 -0
- package/src/goals/nl-builder.ts +256 -0
- package/src/goals/rhythm.test.ts +177 -0
- package/src/goals/rhythm.ts +275 -0
- package/src/goals/service.test.ts +135 -0
- package/src/goals/service.ts +348 -0
- package/src/goals/types.ts +106 -0
- package/src/goals/workflow-bridge.ts +96 -0
- package/src/integrations/google-api.ts +134 -0
- package/src/integrations/google-auth.ts +175 -0
- package/src/llm/README.md +291 -0
- package/src/llm/anthropic.ts +386 -0
- package/src/llm/gemini.ts +371 -0
- package/src/llm/index.ts +19 -0
- package/src/llm/manager.ts +153 -0
- package/src/llm/ollama.ts +307 -0
- package/src/llm/openai.ts +350 -0
- package/src/llm/provider.test.ts +231 -0
- package/src/llm/provider.ts +60 -0
- package/src/llm/test.ts +87 -0
- package/src/observers/README.md +278 -0
- package/src/observers/calendar.ts +113 -0
- package/src/observers/clipboard.ts +136 -0
- package/src/observers/email.ts +109 -0
- package/src/observers/example.ts +58 -0
- package/src/observers/file-watcher.ts +124 -0
- package/src/observers/index.ts +159 -0
- package/src/observers/notifications.ts +197 -0
- package/src/observers/observers.test.ts +203 -0
- package/src/observers/processes.ts +225 -0
- package/src/personality/README.md +61 -0
- package/src/personality/adapter.ts +196 -0
- package/src/personality/index.ts +20 -0
- package/src/personality/learner.ts +209 -0
- package/src/personality/model.ts +132 -0
- package/src/personality/personality.test.ts +236 -0
- package/src/roles/README.md +252 -0
- package/src/roles/authority.ts +119 -0
- package/src/roles/example-usage.ts +198 -0
- package/src/roles/index.ts +42 -0
- package/src/roles/loader.ts +143 -0
- package/src/roles/prompt-builder.ts +194 -0
- package/src/roles/test-multi.ts +102 -0
- package/src/roles/test-role.yaml +77 -0
- package/src/roles/test-utils.ts +93 -0
- package/src/roles/test.ts +106 -0
- package/src/roles/tool-guide.ts +190 -0
- package/src/roles/types.ts +36 -0
- package/src/roles/utils.ts +200 -0
- package/src/scripts/google-setup.ts +168 -0
- package/src/sidecar/connection.ts +179 -0
- package/src/sidecar/index.ts +6 -0
- package/src/sidecar/manager.ts +542 -0
- package/src/sidecar/protocol.ts +85 -0
- package/src/sidecar/rpc.ts +161 -0
- package/src/sidecar/scheduler.ts +136 -0
- package/src/sidecar/types.ts +112 -0
- package/src/sidecar/validator.ts +144 -0
- package/src/vault/README.md +110 -0
- package/src/vault/awareness.ts +341 -0
- package/src/vault/commitments.ts +299 -0
- package/src/vault/content-pipeline.ts +260 -0
- package/src/vault/conversations.ts +173 -0
- package/src/vault/entities.ts +180 -0
- package/src/vault/extractor.test.ts +356 -0
- package/src/vault/extractor.ts +345 -0
- package/src/vault/facts.ts +190 -0
- package/src/vault/goals.ts +477 -0
- package/src/vault/index.ts +87 -0
- package/src/vault/keychain.ts +99 -0
- package/src/vault/observations.ts +115 -0
- package/src/vault/relationships.ts +178 -0
- package/src/vault/retrieval.test.ts +126 -0
- package/src/vault/retrieval.ts +227 -0
- package/src/vault/schema.ts +658 -0
- package/src/vault/settings.ts +38 -0
- package/src/vault/vectors.ts +92 -0
- package/src/vault/workflows.ts +403 -0
- package/src/workflows/auto-suggest.ts +290 -0
- package/src/workflows/engine.ts +366 -0
- package/src/workflows/events.ts +24 -0
- package/src/workflows/executor.ts +207 -0
- package/src/workflows/nl-builder.ts +198 -0
- package/src/workflows/nodes/actions/agent-task.ts +73 -0
- package/src/workflows/nodes/actions/calendar-action.ts +85 -0
- package/src/workflows/nodes/actions/code-execution.ts +73 -0
- package/src/workflows/nodes/actions/discord.ts +77 -0
- package/src/workflows/nodes/actions/file-write.ts +73 -0
- package/src/workflows/nodes/actions/gmail.ts +69 -0
- package/src/workflows/nodes/actions/http-request.ts +117 -0
- package/src/workflows/nodes/actions/notification.ts +85 -0
- package/src/workflows/nodes/actions/run-tool.ts +55 -0
- package/src/workflows/nodes/actions/send-message.ts +82 -0
- package/src/workflows/nodes/actions/shell-command.ts +76 -0
- package/src/workflows/nodes/actions/telegram.ts +60 -0
- package/src/workflows/nodes/builtin.ts +119 -0
- package/src/workflows/nodes/error/error-handler.ts +37 -0
- package/src/workflows/nodes/error/fallback.ts +47 -0
- package/src/workflows/nodes/error/retry.ts +82 -0
- package/src/workflows/nodes/logic/delay.ts +42 -0
- package/src/workflows/nodes/logic/if-else.ts +41 -0
- package/src/workflows/nodes/logic/loop.ts +90 -0
- package/src/workflows/nodes/logic/merge.ts +38 -0
- package/src/workflows/nodes/logic/race.ts +40 -0
- package/src/workflows/nodes/logic/switch.ts +59 -0
- package/src/workflows/nodes/logic/template-render.ts +53 -0
- package/src/workflows/nodes/logic/variable-get.ts +37 -0
- package/src/workflows/nodes/logic/variable-set.ts +59 -0
- package/src/workflows/nodes/registry.ts +99 -0
- package/src/workflows/nodes/transform/aggregate.ts +99 -0
- package/src/workflows/nodes/transform/csv-parse.ts +70 -0
- package/src/workflows/nodes/transform/json-parse.ts +63 -0
- package/src/workflows/nodes/transform/map-filter.ts +84 -0
- package/src/workflows/nodes/transform/regex-match.ts +89 -0
- package/src/workflows/nodes/triggers/calendar.ts +33 -0
- package/src/workflows/nodes/triggers/clipboard.ts +32 -0
- package/src/workflows/nodes/triggers/cron.ts +40 -0
- package/src/workflows/nodes/triggers/email.ts +40 -0
- package/src/workflows/nodes/triggers/file-change.ts +45 -0
- package/src/workflows/nodes/triggers/git.ts +46 -0
- package/src/workflows/nodes/triggers/manual.ts +23 -0
- package/src/workflows/nodes/triggers/poll.ts +81 -0
- package/src/workflows/nodes/triggers/process.ts +44 -0
- package/src/workflows/nodes/triggers/screen-event.ts +37 -0
- package/src/workflows/nodes/triggers/webhook.ts +39 -0
- package/src/workflows/safe-eval.ts +139 -0
- package/src/workflows/template.ts +118 -0
- package/src/workflows/triggers/cron.ts +311 -0
- package/src/workflows/triggers/manager.ts +285 -0
- package/src/workflows/triggers/observer-bridge.ts +172 -0
- package/src/workflows/triggers/poller.ts +201 -0
- package/src/workflows/triggers/screen-condition.ts +218 -0
- package/src/workflows/triggers/triggers.test.ts +740 -0
- package/src/workflows/triggers/webhook.ts +191 -0
- package/src/workflows/types.ts +133 -0
- package/src/workflows/variables.ts +72 -0
- package/src/workflows/workflows.test.ts +383 -0
- package/src/workflows/yaml.ts +104 -0
- package/ui/dist/index-j75njzc1.css +1199 -0
- package/ui/dist/index-p2zh407q.js +80603 -0
- package/ui/dist/index.html +13 -0
- package/ui/public/openwakeword/models/embedding_model.onnx +0 -0
- package/ui/public/openwakeword/models/hey_jarvis_v0.1.onnx +0 -0
- package/ui/public/openwakeword/models/melspectrogram.onnx +0 -0
- package/ui/public/openwakeword/models/silero_vad.onnx +0 -0
- package/ui/public/ort/ort-wasm-simd-threaded.jsep.mjs +106 -0
- package/ui/public/ort/ort-wasm-simd-threaded.jsep.wasm +0 -0
- package/ui/public/ort/ort-wasm-simd-threaded.mjs +59 -0
- package/ui/public/ort/ort-wasm-simd-threaded.wasm +0 -0
|
@@ -0,0 +1,658 @@
|
|
|
1
|
+
import { Database } from "bun:sqlite";
|
|
2
|
+
|
|
3
|
+
let dbInstance: Database | null = null;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Generate a short unique ID for database records
|
|
7
|
+
*/
|
|
8
|
+
export function generateId(): string {
|
|
9
|
+
return crypto.randomUUID();
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Get the current database instance (singleton)
|
|
14
|
+
* @throws Error if database has not been initialized
|
|
15
|
+
*/
|
|
16
|
+
export function getDb(): Database {
|
|
17
|
+
if (!dbInstance) {
|
|
18
|
+
throw new Error(
|
|
19
|
+
"Database not initialized. Call initDatabase() first."
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
return dbInstance;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Close the database connection
|
|
27
|
+
*/
|
|
28
|
+
export function closeDb(): void {
|
|
29
|
+
if (dbInstance) {
|
|
30
|
+
dbInstance.close();
|
|
31
|
+
dbInstance = null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Initialize the SQLite database with all required tables
|
|
37
|
+
* @param dbPath - Path to the database file. Defaults to :memory: for testing
|
|
38
|
+
* @returns Database instance
|
|
39
|
+
*/
|
|
40
|
+
export function initDatabase(dbPath: string = ":memory:"): Database {
|
|
41
|
+
try {
|
|
42
|
+
// Close existing connection if any
|
|
43
|
+
closeDb();
|
|
44
|
+
|
|
45
|
+
// Create new database connection
|
|
46
|
+
dbInstance = new Database(dbPath, { create: true });
|
|
47
|
+
|
|
48
|
+
// Enable WAL mode for better concurrency
|
|
49
|
+
dbInstance.exec("PRAGMA journal_mode=WAL");
|
|
50
|
+
|
|
51
|
+
// Enable foreign key constraints
|
|
52
|
+
dbInstance.exec("PRAGMA foreign_keys=ON");
|
|
53
|
+
|
|
54
|
+
// Create all tables
|
|
55
|
+
createTables(dbInstance);
|
|
56
|
+
|
|
57
|
+
console.log(`Database initialized at: ${dbPath}`);
|
|
58
|
+
return dbInstance;
|
|
59
|
+
} catch (error) {
|
|
60
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
61
|
+
throw new Error(`Failed to initialize database: ${message}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Create all database tables and indexes
|
|
67
|
+
*/
|
|
68
|
+
function createTables(db: Database): void {
|
|
69
|
+
// Entities table: people, places, projects, tools, concepts
|
|
70
|
+
db.run(`
|
|
71
|
+
CREATE TABLE IF NOT EXISTS entities (
|
|
72
|
+
id TEXT PRIMARY KEY,
|
|
73
|
+
type TEXT NOT NULL,
|
|
74
|
+
name TEXT NOT NULL,
|
|
75
|
+
properties TEXT,
|
|
76
|
+
created_at INTEGER NOT NULL,
|
|
77
|
+
updated_at INTEGER NOT NULL,
|
|
78
|
+
source TEXT,
|
|
79
|
+
CHECK(type IN ('person', 'project', 'tool', 'place', 'concept', 'event'))
|
|
80
|
+
)
|
|
81
|
+
`);
|
|
82
|
+
|
|
83
|
+
db.run(`
|
|
84
|
+
CREATE INDEX IF NOT EXISTS idx_entities_type ON entities(type)
|
|
85
|
+
`);
|
|
86
|
+
|
|
87
|
+
db.run(`
|
|
88
|
+
CREATE INDEX IF NOT EXISTS idx_entities_name ON entities(name)
|
|
89
|
+
`);
|
|
90
|
+
|
|
91
|
+
// Facts table: atomic pieces of knowledge with confidence
|
|
92
|
+
db.run(`
|
|
93
|
+
CREATE TABLE IF NOT EXISTS facts (
|
|
94
|
+
id TEXT PRIMARY KEY,
|
|
95
|
+
subject_id TEXT NOT NULL REFERENCES entities(id) ON DELETE CASCADE,
|
|
96
|
+
predicate TEXT NOT NULL,
|
|
97
|
+
object TEXT NOT NULL,
|
|
98
|
+
confidence REAL DEFAULT 1.0,
|
|
99
|
+
source TEXT,
|
|
100
|
+
created_at INTEGER NOT NULL,
|
|
101
|
+
verified_at INTEGER,
|
|
102
|
+
CHECK(confidence >= 0.0 AND confidence <= 1.0)
|
|
103
|
+
)
|
|
104
|
+
`);
|
|
105
|
+
|
|
106
|
+
db.run(`
|
|
107
|
+
CREATE INDEX IF NOT EXISTS idx_facts_subject ON facts(subject_id)
|
|
108
|
+
`);
|
|
109
|
+
|
|
110
|
+
db.run(`
|
|
111
|
+
CREATE INDEX IF NOT EXISTS idx_facts_predicate ON facts(predicate)
|
|
112
|
+
`);
|
|
113
|
+
|
|
114
|
+
// Relationships table: edges between entities
|
|
115
|
+
db.run(`
|
|
116
|
+
CREATE TABLE IF NOT EXISTS relationships (
|
|
117
|
+
id TEXT PRIMARY KEY,
|
|
118
|
+
from_id TEXT NOT NULL REFERENCES entities(id) ON DELETE CASCADE,
|
|
119
|
+
to_id TEXT NOT NULL REFERENCES entities(id) ON DELETE CASCADE,
|
|
120
|
+
type TEXT NOT NULL,
|
|
121
|
+
properties TEXT,
|
|
122
|
+
created_at INTEGER NOT NULL
|
|
123
|
+
)
|
|
124
|
+
`);
|
|
125
|
+
|
|
126
|
+
db.run(`
|
|
127
|
+
CREATE INDEX IF NOT EXISTS idx_rel_from ON relationships(from_id)
|
|
128
|
+
`);
|
|
129
|
+
|
|
130
|
+
db.run(`
|
|
131
|
+
CREATE INDEX IF NOT EXISTS idx_rel_to ON relationships(to_id)
|
|
132
|
+
`);
|
|
133
|
+
|
|
134
|
+
db.run(`
|
|
135
|
+
CREATE INDEX IF NOT EXISTS idx_rel_type ON relationships(type)
|
|
136
|
+
`);
|
|
137
|
+
|
|
138
|
+
// Commitments table: things the AI promised to do
|
|
139
|
+
db.run(`
|
|
140
|
+
CREATE TABLE IF NOT EXISTS commitments (
|
|
141
|
+
id TEXT PRIMARY KEY,
|
|
142
|
+
what TEXT NOT NULL,
|
|
143
|
+
when_due INTEGER,
|
|
144
|
+
context TEXT,
|
|
145
|
+
priority TEXT DEFAULT 'normal' CHECK(priority IN ('low','normal','high','critical')),
|
|
146
|
+
status TEXT DEFAULT 'pending' CHECK(status IN ('pending','active','completed','failed','escalated')),
|
|
147
|
+
retry_policy TEXT,
|
|
148
|
+
created_from TEXT,
|
|
149
|
+
assigned_to TEXT,
|
|
150
|
+
created_at INTEGER NOT NULL,
|
|
151
|
+
completed_at INTEGER,
|
|
152
|
+
result TEXT,
|
|
153
|
+
sort_order INTEGER DEFAULT 0
|
|
154
|
+
)
|
|
155
|
+
`);
|
|
156
|
+
|
|
157
|
+
// Migration: add sort_order to existing databases
|
|
158
|
+
try { db.run('ALTER TABLE commitments ADD COLUMN sort_order INTEGER DEFAULT 0'); } catch {}
|
|
159
|
+
|
|
160
|
+
db.run(`
|
|
161
|
+
CREATE INDEX IF NOT EXISTS idx_commitments_status ON commitments(status)
|
|
162
|
+
`);
|
|
163
|
+
|
|
164
|
+
db.run(`
|
|
165
|
+
CREATE INDEX IF NOT EXISTS idx_commitments_due ON commitments(when_due)
|
|
166
|
+
`);
|
|
167
|
+
|
|
168
|
+
db.run(`
|
|
169
|
+
CREATE INDEX IF NOT EXISTS idx_commitments_sort ON commitments(status, sort_order)
|
|
170
|
+
`);
|
|
171
|
+
|
|
172
|
+
// Observations table: raw events from the observation layer
|
|
173
|
+
db.run(`
|
|
174
|
+
CREATE TABLE IF NOT EXISTS observations (
|
|
175
|
+
id TEXT PRIMARY KEY,
|
|
176
|
+
type TEXT NOT NULL,
|
|
177
|
+
data TEXT NOT NULL,
|
|
178
|
+
processed INTEGER DEFAULT 0,
|
|
179
|
+
created_at INTEGER NOT NULL,
|
|
180
|
+
CHECK(processed IN (0, 1))
|
|
181
|
+
)
|
|
182
|
+
`);
|
|
183
|
+
|
|
184
|
+
db.run(`
|
|
185
|
+
CREATE INDEX IF NOT EXISTS idx_obs_type ON observations(type)
|
|
186
|
+
`);
|
|
187
|
+
|
|
188
|
+
db.run(`
|
|
189
|
+
CREATE INDEX IF NOT EXISTS idx_obs_processed ON observations(processed)
|
|
190
|
+
`);
|
|
191
|
+
|
|
192
|
+
// Vectors table: embeddings for semantic search
|
|
193
|
+
db.run(`
|
|
194
|
+
CREATE TABLE IF NOT EXISTS vectors (
|
|
195
|
+
id TEXT PRIMARY KEY,
|
|
196
|
+
ref_type TEXT,
|
|
197
|
+
ref_id TEXT,
|
|
198
|
+
embedding BLOB,
|
|
199
|
+
model TEXT,
|
|
200
|
+
created_at INTEGER NOT NULL
|
|
201
|
+
)
|
|
202
|
+
`);
|
|
203
|
+
|
|
204
|
+
db.run(`
|
|
205
|
+
CREATE INDEX IF NOT EXISTS idx_vectors_ref ON vectors(ref_type, ref_id)
|
|
206
|
+
`);
|
|
207
|
+
|
|
208
|
+
// Agent messages table: inter-agent communication
|
|
209
|
+
db.run(`
|
|
210
|
+
CREATE TABLE IF NOT EXISTS agent_messages (
|
|
211
|
+
id TEXT PRIMARY KEY,
|
|
212
|
+
from_agent TEXT NOT NULL,
|
|
213
|
+
to_agent TEXT NOT NULL,
|
|
214
|
+
type TEXT NOT NULL CHECK(type IN ('task','report','question','escalation')),
|
|
215
|
+
content TEXT NOT NULL,
|
|
216
|
+
priority TEXT DEFAULT 'normal' CHECK(priority IN ('low','normal','high','urgent')),
|
|
217
|
+
requires_response INTEGER DEFAULT 0,
|
|
218
|
+
deadline INTEGER,
|
|
219
|
+
created_at INTEGER NOT NULL,
|
|
220
|
+
CHECK(requires_response IN (0, 1))
|
|
221
|
+
)
|
|
222
|
+
`);
|
|
223
|
+
|
|
224
|
+
db.run(`
|
|
225
|
+
CREATE INDEX IF NOT EXISTS idx_msg_to ON agent_messages(to_agent)
|
|
226
|
+
`);
|
|
227
|
+
|
|
228
|
+
db.run(`
|
|
229
|
+
CREATE INDEX IF NOT EXISTS idx_msg_from ON agent_messages(from_agent)
|
|
230
|
+
`);
|
|
231
|
+
|
|
232
|
+
// Personality state table
|
|
233
|
+
db.run(`
|
|
234
|
+
CREATE TABLE IF NOT EXISTS personality_state (
|
|
235
|
+
id TEXT PRIMARY KEY DEFAULT 'default',
|
|
236
|
+
data TEXT NOT NULL,
|
|
237
|
+
updated_at INTEGER NOT NULL
|
|
238
|
+
)
|
|
239
|
+
`);
|
|
240
|
+
|
|
241
|
+
// Conversations table: context tracking
|
|
242
|
+
db.run(`
|
|
243
|
+
CREATE TABLE IF NOT EXISTS conversations (
|
|
244
|
+
id TEXT PRIMARY KEY,
|
|
245
|
+
agent_id TEXT,
|
|
246
|
+
channel TEXT,
|
|
247
|
+
started_at INTEGER NOT NULL,
|
|
248
|
+
last_message_at INTEGER NOT NULL,
|
|
249
|
+
message_count INTEGER DEFAULT 0,
|
|
250
|
+
metadata TEXT,
|
|
251
|
+
CHECK(message_count >= 0)
|
|
252
|
+
)
|
|
253
|
+
`);
|
|
254
|
+
|
|
255
|
+
db.run(`
|
|
256
|
+
CREATE INDEX IF NOT EXISTS idx_conversations_agent ON conversations(agent_id)
|
|
257
|
+
`);
|
|
258
|
+
|
|
259
|
+
db.run(`
|
|
260
|
+
CREATE INDEX IF NOT EXISTS idx_conversations_channel ON conversations(channel)
|
|
261
|
+
`);
|
|
262
|
+
|
|
263
|
+
// Conversation messages table: individual chat messages
|
|
264
|
+
db.run(`
|
|
265
|
+
CREATE TABLE IF NOT EXISTS conversation_messages (
|
|
266
|
+
id TEXT PRIMARY KEY,
|
|
267
|
+
conversation_id TEXT NOT NULL REFERENCES conversations(id) ON DELETE CASCADE,
|
|
268
|
+
role TEXT NOT NULL CHECK(role IN ('user','assistant','system')),
|
|
269
|
+
content TEXT NOT NULL,
|
|
270
|
+
tool_calls TEXT,
|
|
271
|
+
created_at INTEGER NOT NULL
|
|
272
|
+
)
|
|
273
|
+
`);
|
|
274
|
+
|
|
275
|
+
db.run(`
|
|
276
|
+
CREATE INDEX IF NOT EXISTS idx_conv_msg_conv ON conversation_messages(conversation_id)
|
|
277
|
+
`);
|
|
278
|
+
|
|
279
|
+
db.run(`
|
|
280
|
+
CREATE INDEX IF NOT EXISTS idx_conv_msg_time ON conversation_messages(created_at)
|
|
281
|
+
`);
|
|
282
|
+
|
|
283
|
+
// Content pipeline: items moving through creation stages
|
|
284
|
+
db.run(`
|
|
285
|
+
CREATE TABLE IF NOT EXISTS content_items (
|
|
286
|
+
id TEXT PRIMARY KEY,
|
|
287
|
+
title TEXT NOT NULL,
|
|
288
|
+
body TEXT DEFAULT '',
|
|
289
|
+
content_type TEXT NOT NULL DEFAULT 'blog'
|
|
290
|
+
CHECK(content_type IN ('youtube','blog','twitter','instagram','tiktok','linkedin','podcast','newsletter','short_form','other')),
|
|
291
|
+
stage TEXT NOT NULL DEFAULT 'idea'
|
|
292
|
+
CHECK(stage IN ('idea','research','outline','draft','assets','review','scheduled','published')),
|
|
293
|
+
tags TEXT,
|
|
294
|
+
scheduled_at INTEGER,
|
|
295
|
+
published_at INTEGER,
|
|
296
|
+
published_url TEXT,
|
|
297
|
+
created_by TEXT DEFAULT 'user',
|
|
298
|
+
sort_order INTEGER DEFAULT 0,
|
|
299
|
+
created_at INTEGER NOT NULL,
|
|
300
|
+
updated_at INTEGER NOT NULL
|
|
301
|
+
)
|
|
302
|
+
`);
|
|
303
|
+
|
|
304
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_content_stage ON content_items(stage)`);
|
|
305
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_content_type ON content_items(content_type)`);
|
|
306
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_content_sort ON content_items(stage, sort_order)`);
|
|
307
|
+
|
|
308
|
+
// Content pipeline: per-stage notes from user or JARVIS
|
|
309
|
+
db.run(`
|
|
310
|
+
CREATE TABLE IF NOT EXISTS content_stage_notes (
|
|
311
|
+
id TEXT PRIMARY KEY,
|
|
312
|
+
content_id TEXT NOT NULL REFERENCES content_items(id) ON DELETE CASCADE,
|
|
313
|
+
stage TEXT NOT NULL
|
|
314
|
+
CHECK(stage IN ('idea','research','outline','draft','assets','review','scheduled','published')),
|
|
315
|
+
note TEXT NOT NULL,
|
|
316
|
+
author TEXT NOT NULL DEFAULT 'user',
|
|
317
|
+
created_at INTEGER NOT NULL
|
|
318
|
+
)
|
|
319
|
+
`);
|
|
320
|
+
|
|
321
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_stage_notes_content ON content_stage_notes(content_id)`);
|
|
322
|
+
|
|
323
|
+
// Content pipeline: file/image attachments (files stored on disk)
|
|
324
|
+
db.run(`
|
|
325
|
+
CREATE TABLE IF NOT EXISTS content_attachments (
|
|
326
|
+
id TEXT PRIMARY KEY,
|
|
327
|
+
content_id TEXT NOT NULL REFERENCES content_items(id) ON DELETE CASCADE,
|
|
328
|
+
filename TEXT NOT NULL,
|
|
329
|
+
disk_path TEXT NOT NULL,
|
|
330
|
+
mime_type TEXT NOT NULL,
|
|
331
|
+
size_bytes INTEGER NOT NULL,
|
|
332
|
+
label TEXT,
|
|
333
|
+
created_at INTEGER NOT NULL
|
|
334
|
+
)
|
|
335
|
+
`);
|
|
336
|
+
|
|
337
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_attachments_content ON content_attachments(content_id)`);
|
|
338
|
+
|
|
339
|
+
// Authority: Approval requests
|
|
340
|
+
db.run(`
|
|
341
|
+
CREATE TABLE IF NOT EXISTS approval_requests (
|
|
342
|
+
id TEXT PRIMARY KEY,
|
|
343
|
+
agent_id TEXT NOT NULL,
|
|
344
|
+
agent_name TEXT NOT NULL,
|
|
345
|
+
tool_name TEXT NOT NULL,
|
|
346
|
+
tool_arguments TEXT NOT NULL,
|
|
347
|
+
action_category TEXT NOT NULL,
|
|
348
|
+
urgency TEXT NOT NULL DEFAULT 'normal'
|
|
349
|
+
CHECK(urgency IN ('urgent', 'normal')),
|
|
350
|
+
reason TEXT NOT NULL,
|
|
351
|
+
context TEXT NOT NULL DEFAULT '',
|
|
352
|
+
status TEXT NOT NULL DEFAULT 'pending'
|
|
353
|
+
CHECK(status IN ('pending', 'approved', 'denied', 'expired', 'executed')),
|
|
354
|
+
decided_at INTEGER,
|
|
355
|
+
decided_by TEXT,
|
|
356
|
+
executed_at INTEGER,
|
|
357
|
+
execution_result TEXT,
|
|
358
|
+
created_at INTEGER NOT NULL
|
|
359
|
+
)
|
|
360
|
+
`);
|
|
361
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_approval_status ON approval_requests(status)`);
|
|
362
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_approval_agent ON approval_requests(agent_id)`);
|
|
363
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_approval_category ON approval_requests(action_category)`);
|
|
364
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_approval_created ON approval_requests(created_at)`);
|
|
365
|
+
|
|
366
|
+
// Authority: Audit trail
|
|
367
|
+
db.run(`
|
|
368
|
+
CREATE TABLE IF NOT EXISTS audit_trail (
|
|
369
|
+
id TEXT PRIMARY KEY,
|
|
370
|
+
agent_id TEXT NOT NULL,
|
|
371
|
+
agent_name TEXT NOT NULL,
|
|
372
|
+
tool_name TEXT NOT NULL,
|
|
373
|
+
action_category TEXT NOT NULL,
|
|
374
|
+
authority_decision TEXT NOT NULL
|
|
375
|
+
CHECK(authority_decision IN ('allowed', 'denied', 'approval_required')),
|
|
376
|
+
approval_id TEXT,
|
|
377
|
+
executed INTEGER NOT NULL DEFAULT 0,
|
|
378
|
+
execution_time_ms INTEGER,
|
|
379
|
+
created_at INTEGER NOT NULL,
|
|
380
|
+
CHECK(executed IN (0, 1))
|
|
381
|
+
)
|
|
382
|
+
`);
|
|
383
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_audit_agent ON audit_trail(agent_id)`);
|
|
384
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_audit_category ON audit_trail(action_category)`);
|
|
385
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_audit_created ON audit_trail(created_at)`);
|
|
386
|
+
|
|
387
|
+
// Authority: Approval patterns (for learning)
|
|
388
|
+
db.run(`
|
|
389
|
+
CREATE TABLE IF NOT EXISTS approval_patterns (
|
|
390
|
+
id TEXT PRIMARY KEY,
|
|
391
|
+
action_category TEXT NOT NULL,
|
|
392
|
+
tool_name TEXT NOT NULL,
|
|
393
|
+
consecutive_approvals INTEGER NOT NULL DEFAULT 0,
|
|
394
|
+
last_approval_at INTEGER NOT NULL,
|
|
395
|
+
suggestion_sent INTEGER NOT NULL DEFAULT 0,
|
|
396
|
+
UNIQUE(action_category, tool_name)
|
|
397
|
+
)
|
|
398
|
+
`);
|
|
399
|
+
|
|
400
|
+
// ── Awareness (M13): Screen captures, sessions, suggestions ──
|
|
401
|
+
|
|
402
|
+
db.run(`
|
|
403
|
+
CREATE TABLE IF NOT EXISTS screen_captures (
|
|
404
|
+
id TEXT PRIMARY KEY,
|
|
405
|
+
timestamp INTEGER NOT NULL,
|
|
406
|
+
session_id TEXT,
|
|
407
|
+
image_path TEXT,
|
|
408
|
+
thumbnail_path TEXT,
|
|
409
|
+
pixel_change_pct REAL,
|
|
410
|
+
ocr_text TEXT,
|
|
411
|
+
app_name TEXT,
|
|
412
|
+
window_title TEXT,
|
|
413
|
+
url TEXT,
|
|
414
|
+
file_path TEXT,
|
|
415
|
+
retention_tier TEXT NOT NULL DEFAULT 'full'
|
|
416
|
+
CHECK(retention_tier IN ('full', 'key_moment', 'metadata_only')),
|
|
417
|
+
created_at INTEGER NOT NULL
|
|
418
|
+
)
|
|
419
|
+
`);
|
|
420
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_captures_timestamp ON screen_captures(timestamp)`);
|
|
421
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_captures_session ON screen_captures(session_id)`);
|
|
422
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_captures_retention ON screen_captures(retention_tier)`);
|
|
423
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_captures_app ON screen_captures(app_name)`);
|
|
424
|
+
|
|
425
|
+
db.run(`
|
|
426
|
+
CREATE TABLE IF NOT EXISTS awareness_sessions (
|
|
427
|
+
id TEXT PRIMARY KEY,
|
|
428
|
+
started_at INTEGER NOT NULL,
|
|
429
|
+
ended_at INTEGER,
|
|
430
|
+
topic TEXT,
|
|
431
|
+
apps TEXT,
|
|
432
|
+
project_context TEXT,
|
|
433
|
+
action_types TEXT,
|
|
434
|
+
entity_links TEXT,
|
|
435
|
+
summary TEXT,
|
|
436
|
+
capture_count INTEGER DEFAULT 0,
|
|
437
|
+
created_at INTEGER NOT NULL
|
|
438
|
+
)
|
|
439
|
+
`);
|
|
440
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_sessions_started ON awareness_sessions(started_at)`);
|
|
441
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_sessions_topic ON awareness_sessions(topic)`);
|
|
442
|
+
|
|
443
|
+
db.run(`
|
|
444
|
+
CREATE TABLE IF NOT EXISTS awareness_suggestions (
|
|
445
|
+
id TEXT PRIMARY KEY,
|
|
446
|
+
type TEXT NOT NULL CHECK(type IN ('error', 'stuck', 'automation', 'knowledge', 'schedule', 'break', 'general')),
|
|
447
|
+
trigger_capture_id TEXT,
|
|
448
|
+
title TEXT NOT NULL,
|
|
449
|
+
body TEXT NOT NULL,
|
|
450
|
+
context TEXT,
|
|
451
|
+
delivered INTEGER DEFAULT 0,
|
|
452
|
+
delivered_at INTEGER,
|
|
453
|
+
delivery_channel TEXT,
|
|
454
|
+
dismissed INTEGER DEFAULT 0,
|
|
455
|
+
acted_on INTEGER DEFAULT 0,
|
|
456
|
+
created_at INTEGER NOT NULL,
|
|
457
|
+
CHECK(delivered IN (0, 1)),
|
|
458
|
+
CHECK(dismissed IN (0, 1)),
|
|
459
|
+
CHECK(acted_on IN (0, 1))
|
|
460
|
+
)
|
|
461
|
+
`);
|
|
462
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_suggestions_type ON awareness_suggestions(type)`);
|
|
463
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_suggestions_created ON awareness_suggestions(created_at)`);
|
|
464
|
+
|
|
465
|
+
// ── Workflows (M14): Automation engine ──
|
|
466
|
+
|
|
467
|
+
db.run(`
|
|
468
|
+
CREATE TABLE IF NOT EXISTS workflows (
|
|
469
|
+
id TEXT PRIMARY KEY,
|
|
470
|
+
name TEXT NOT NULL,
|
|
471
|
+
description TEXT DEFAULT '',
|
|
472
|
+
enabled INTEGER NOT NULL DEFAULT 1,
|
|
473
|
+
authority_level INTEGER NOT NULL DEFAULT 3,
|
|
474
|
+
authority_approved INTEGER NOT NULL DEFAULT 0,
|
|
475
|
+
approved_at INTEGER,
|
|
476
|
+
approved_by TEXT,
|
|
477
|
+
tags TEXT,
|
|
478
|
+
current_version INTEGER NOT NULL DEFAULT 1,
|
|
479
|
+
execution_count INTEGER NOT NULL DEFAULT 0,
|
|
480
|
+
last_executed_at INTEGER,
|
|
481
|
+
last_success_at INTEGER,
|
|
482
|
+
last_failure_at INTEGER,
|
|
483
|
+
created_at INTEGER NOT NULL,
|
|
484
|
+
updated_at INTEGER NOT NULL,
|
|
485
|
+
CHECK(enabled IN (0, 1)),
|
|
486
|
+
CHECK(authority_approved IN (0, 1))
|
|
487
|
+
)
|
|
488
|
+
`);
|
|
489
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_workflows_enabled ON workflows(enabled)`);
|
|
490
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_workflows_updated ON workflows(updated_at)`);
|
|
491
|
+
|
|
492
|
+
db.run(`
|
|
493
|
+
CREATE TABLE IF NOT EXISTS workflow_versions (
|
|
494
|
+
id TEXT PRIMARY KEY,
|
|
495
|
+
workflow_id TEXT NOT NULL REFERENCES workflows(id) ON DELETE CASCADE,
|
|
496
|
+
version INTEGER NOT NULL,
|
|
497
|
+
definition TEXT NOT NULL,
|
|
498
|
+
changelog TEXT,
|
|
499
|
+
created_by TEXT NOT NULL DEFAULT 'user',
|
|
500
|
+
created_at INTEGER NOT NULL,
|
|
501
|
+
UNIQUE(workflow_id, version)
|
|
502
|
+
)
|
|
503
|
+
`);
|
|
504
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_wv_workflow ON workflow_versions(workflow_id)`);
|
|
505
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_wv_version ON workflow_versions(workflow_id, version)`);
|
|
506
|
+
|
|
507
|
+
db.run(`
|
|
508
|
+
CREATE TABLE IF NOT EXISTS workflow_executions (
|
|
509
|
+
id TEXT PRIMARY KEY,
|
|
510
|
+
workflow_id TEXT NOT NULL REFERENCES workflows(id) ON DELETE CASCADE,
|
|
511
|
+
version INTEGER NOT NULL,
|
|
512
|
+
trigger_type TEXT NOT NULL,
|
|
513
|
+
trigger_data TEXT,
|
|
514
|
+
status TEXT NOT NULL DEFAULT 'running'
|
|
515
|
+
CHECK(status IN ('running', 'completed', 'failed', 'cancelled', 'paused')),
|
|
516
|
+
variables TEXT,
|
|
517
|
+
error_message TEXT,
|
|
518
|
+
started_at INTEGER NOT NULL,
|
|
519
|
+
completed_at INTEGER,
|
|
520
|
+
duration_ms INTEGER
|
|
521
|
+
)
|
|
522
|
+
`);
|
|
523
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_we_workflow ON workflow_executions(workflow_id)`);
|
|
524
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_we_status ON workflow_executions(status)`);
|
|
525
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_we_started ON workflow_executions(started_at)`);
|
|
526
|
+
|
|
527
|
+
db.run(`
|
|
528
|
+
CREATE TABLE IF NOT EXISTS workflow_step_results (
|
|
529
|
+
id TEXT PRIMARY KEY,
|
|
530
|
+
execution_id TEXT NOT NULL REFERENCES workflow_executions(id) ON DELETE CASCADE,
|
|
531
|
+
node_id TEXT NOT NULL,
|
|
532
|
+
node_type TEXT NOT NULL,
|
|
533
|
+
status TEXT NOT NULL DEFAULT 'pending'
|
|
534
|
+
CHECK(status IN ('pending', 'running', 'completed', 'failed', 'skipped', 'waiting')),
|
|
535
|
+
input_data TEXT,
|
|
536
|
+
output_data TEXT,
|
|
537
|
+
error_message TEXT,
|
|
538
|
+
retry_count INTEGER NOT NULL DEFAULT 0,
|
|
539
|
+
started_at INTEGER,
|
|
540
|
+
completed_at INTEGER,
|
|
541
|
+
duration_ms INTEGER
|
|
542
|
+
)
|
|
543
|
+
`);
|
|
544
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_wsr_execution ON workflow_step_results(execution_id)`);
|
|
545
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_wsr_node ON workflow_step_results(node_id)`);
|
|
546
|
+
|
|
547
|
+
db.run(`
|
|
548
|
+
CREATE TABLE IF NOT EXISTS workflow_variables (
|
|
549
|
+
id TEXT PRIMARY KEY,
|
|
550
|
+
workflow_id TEXT NOT NULL REFERENCES workflows(id) ON DELETE CASCADE,
|
|
551
|
+
key TEXT NOT NULL,
|
|
552
|
+
value TEXT NOT NULL,
|
|
553
|
+
updated_at INTEGER NOT NULL,
|
|
554
|
+
UNIQUE(workflow_id, key)
|
|
555
|
+
)
|
|
556
|
+
`);
|
|
557
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_wvar_workflow ON workflow_variables(workflow_id)`);
|
|
558
|
+
|
|
559
|
+
// ── M16: Goal Pursuit ─────────────────────────────────────────────
|
|
560
|
+
|
|
561
|
+
db.run(`
|
|
562
|
+
CREATE TABLE IF NOT EXISTS goals (
|
|
563
|
+
id TEXT PRIMARY KEY,
|
|
564
|
+
parent_id TEXT REFERENCES goals(id) ON DELETE CASCADE,
|
|
565
|
+
level TEXT NOT NULL
|
|
566
|
+
CHECK(level IN ('objective', 'key_result', 'milestone', 'task', 'daily_action')),
|
|
567
|
+
title TEXT NOT NULL,
|
|
568
|
+
description TEXT DEFAULT '',
|
|
569
|
+
success_criteria TEXT DEFAULT '',
|
|
570
|
+
time_horizon TEXT NOT NULL DEFAULT 'quarterly'
|
|
571
|
+
CHECK(time_horizon IN ('life', 'yearly', 'quarterly', 'monthly', 'weekly', 'daily')),
|
|
572
|
+
score REAL NOT NULL DEFAULT 0.0,
|
|
573
|
+
score_reason TEXT,
|
|
574
|
+
status TEXT NOT NULL DEFAULT 'draft'
|
|
575
|
+
CHECK(status IN ('draft', 'active', 'paused', 'completed', 'failed', 'killed')),
|
|
576
|
+
health TEXT NOT NULL DEFAULT 'on_track'
|
|
577
|
+
CHECK(health IN ('on_track', 'at_risk', 'behind', 'critical')),
|
|
578
|
+
deadline INTEGER,
|
|
579
|
+
started_at INTEGER,
|
|
580
|
+
estimated_hours REAL,
|
|
581
|
+
actual_hours REAL NOT NULL DEFAULT 0,
|
|
582
|
+
authority_level INTEGER NOT NULL DEFAULT 3,
|
|
583
|
+
tags TEXT,
|
|
584
|
+
dependencies TEXT,
|
|
585
|
+
escalation_stage TEXT NOT NULL DEFAULT 'none'
|
|
586
|
+
CHECK(escalation_stage IN ('none', 'pressure', 'root_cause', 'suggest_kill')),
|
|
587
|
+
escalation_started_at INTEGER,
|
|
588
|
+
sort_order INTEGER NOT NULL DEFAULT 0,
|
|
589
|
+
created_at INTEGER NOT NULL,
|
|
590
|
+
updated_at INTEGER NOT NULL,
|
|
591
|
+
completed_at INTEGER
|
|
592
|
+
)
|
|
593
|
+
`);
|
|
594
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_goals_parent ON goals(parent_id)`);
|
|
595
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_goals_status ON goals(status)`);
|
|
596
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_goals_level ON goals(level)`);
|
|
597
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_goals_health ON goals(health)`);
|
|
598
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_goals_deadline ON goals(deadline)`);
|
|
599
|
+
|
|
600
|
+
db.run(`
|
|
601
|
+
CREATE TABLE IF NOT EXISTS goal_progress (
|
|
602
|
+
id TEXT PRIMARY KEY,
|
|
603
|
+
goal_id TEXT NOT NULL REFERENCES goals(id) ON DELETE CASCADE,
|
|
604
|
+
type TEXT NOT NULL
|
|
605
|
+
CHECK(type IN ('manual', 'auto_detected', 'review', 'system')),
|
|
606
|
+
score_before REAL NOT NULL,
|
|
607
|
+
score_after REAL NOT NULL,
|
|
608
|
+
note TEXT NOT NULL DEFAULT '',
|
|
609
|
+
source TEXT NOT NULL DEFAULT 'user',
|
|
610
|
+
created_at INTEGER NOT NULL
|
|
611
|
+
)
|
|
612
|
+
`);
|
|
613
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_gprog_goal ON goal_progress(goal_id)`);
|
|
614
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_gprog_created ON goal_progress(created_at)`);
|
|
615
|
+
|
|
616
|
+
db.run(`
|
|
617
|
+
CREATE TABLE IF NOT EXISTS goal_check_ins (
|
|
618
|
+
id TEXT PRIMARY KEY,
|
|
619
|
+
type TEXT NOT NULL
|
|
620
|
+
CHECK(type IN ('morning_plan', 'evening_review')),
|
|
621
|
+
summary TEXT NOT NULL DEFAULT '',
|
|
622
|
+
goals_reviewed TEXT,
|
|
623
|
+
actions_planned TEXT,
|
|
624
|
+
actions_completed TEXT,
|
|
625
|
+
created_at INTEGER NOT NULL
|
|
626
|
+
)
|
|
627
|
+
`);
|
|
628
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_gci_type ON goal_check_ins(type)`);
|
|
629
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_gci_created ON goal_check_ins(created_at)`);
|
|
630
|
+
|
|
631
|
+
// Sidecars table: enrolled sidecar processes
|
|
632
|
+
db.run(`
|
|
633
|
+
CREATE TABLE IF NOT EXISTS sidecars (
|
|
634
|
+
id TEXT PRIMARY KEY,
|
|
635
|
+
name TEXT NOT NULL UNIQUE,
|
|
636
|
+
token_id TEXT NOT NULL UNIQUE,
|
|
637
|
+
enrolled_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
638
|
+
last_seen_at TEXT,
|
|
639
|
+
status TEXT NOT NULL DEFAULT 'enrolled'
|
|
640
|
+
CHECK(status IN ('enrolled', 'revoked')),
|
|
641
|
+
hostname TEXT,
|
|
642
|
+
os TEXT,
|
|
643
|
+
platform TEXT,
|
|
644
|
+
capabilities TEXT
|
|
645
|
+
)
|
|
646
|
+
`);
|
|
647
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_sidecars_name ON sidecars(name)`);
|
|
648
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_sidecars_token_id ON sidecars(token_id)`);
|
|
649
|
+
|
|
650
|
+
// Settings table: key-value store for dashboard-managed configuration
|
|
651
|
+
db.run(`
|
|
652
|
+
CREATE TABLE IF NOT EXISTS settings (
|
|
653
|
+
key TEXT PRIMARY KEY,
|
|
654
|
+
value TEXT NOT NULL,
|
|
655
|
+
updated_at INTEGER NOT NULL DEFAULT (unixepoch())
|
|
656
|
+
)
|
|
657
|
+
`);
|
|
658
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Key-value settings store backed by SQLite.
|
|
3
|
+
*
|
|
4
|
+
* Used for persistent configuration that can be edited from the dashboard
|
|
5
|
+
* (e.g., LLM provider/model preferences).
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { getDb } from './schema.ts';
|
|
9
|
+
|
|
10
|
+
export function getSetting(key: string): string | null {
|
|
11
|
+
const db = getDb();
|
|
12
|
+
const row = db.query('SELECT value FROM settings WHERE key = ?').get(key) as { value: string } | null;
|
|
13
|
+
return row?.value ?? null;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function setSetting(key: string, value: string): void {
|
|
17
|
+
const db = getDb();
|
|
18
|
+
db.run(
|
|
19
|
+
`INSERT INTO settings (key, value, updated_at) VALUES (?, ?, unixepoch())
|
|
20
|
+
ON CONFLICT(key) DO UPDATE SET value = excluded.value, updated_at = excluded.updated_at`,
|
|
21
|
+
[key, value],
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function deleteSetting(key: string): void {
|
|
26
|
+
const db = getDb();
|
|
27
|
+
db.run('DELETE FROM settings WHERE key = ?', [key]);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function getSettingsByPrefix(prefix: string): Record<string, string> {
|
|
31
|
+
const db = getDb();
|
|
32
|
+
const rows = db.query('SELECT key, value FROM settings WHERE key LIKE ?').all(`${prefix}%`) as Array<{ key: string; value: string }>;
|
|
33
|
+
const result: Record<string, string> = {};
|
|
34
|
+
for (const row of rows) {
|
|
35
|
+
result[row.key] = row.value;
|
|
36
|
+
}
|
|
37
|
+
return result;
|
|
38
|
+
}
|