ohwow 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.
Files changed (34) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +147 -0
  3. package/bin/ohwow.js +2 -0
  4. package/dist/db/migrations/001-data-plane-tables.sql +250 -0
  5. package/dist/db/migrations/002-agents-table.sql +40 -0
  6. package/dist/db/migrations/003-orchestrator-a2a.sql +111 -0
  7. package/dist/db/migrations/004-whatsapp.sql +37 -0
  8. package/dist/db/migrations/005-telegram.sql +27 -0
  9. package/dist/db/migrations/006-deferred-actions.sql +3 -0
  10. package/dist/db/migrations/007-deliverables.sql +23 -0
  11. package/dist/db/migrations/008-plans.sql +36 -0
  12. package/dist/db/migrations/009-nudges.sql +16 -0
  13. package/dist/db/migrations/010-local-crm.sql +35 -0
  14. package/dist/db/migrations/011-notification-preferences.sql +5 -0
  15. package/dist/db/migrations/012-orchestrator-memory.sql +14 -0
  16. package/dist/db/migrations/013-voice-profile-settings.sql +9 -0
  17. package/dist/db/migrations/014-webhooks-and-triggers.sql +53 -0
  18. package/dist/db/migrations/015-file-attachments.sql +19 -0
  19. package/dist/db/migrations/016-dashboard-tables.sql +47 -0
  20. package/dist/db/migrations/017-workflow-triggers.sql +24 -0
  21. package/dist/db/migrations/018-workspace-onboarding.sql +20 -0
  22. package/dist/db/migrations/019-custom-webhooks.sql +9 -0
  23. package/dist/db/migrations/020-automation-action-chains.sql +9 -0
  24. package/dist/db/migrations/021-unify-automations.sql +12 -0
  25. package/dist/db/migrations/022-knowledge-base.sql +66 -0
  26. package/dist/db/migrations/023-local-file-access.sql +19 -0
  27. package/dist/db/migrations/024-model-stats.sql +25 -0
  28. package/dist/index.d.ts +91 -0
  29. package/dist/index.js +1169 -0
  30. package/dist/web/assets/index-C5TP_l1N.css +1 -0
  31. package/dist/web/assets/index-Dylm-A3c.js +75 -0
  32. package/dist/web/favicon.svg +4 -0
  33. package/dist/web/index.html +14 -0
  34. package/package.json +70 -0
@@ -0,0 +1,36 @@
1
+ -- 008-plans.sql
2
+ -- Autonomous Goal Planner tables
3
+
4
+ CREATE TABLE IF NOT EXISTS agent_workforce_plans (
5
+ id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),
6
+ workspace_id TEXT NOT NULL,
7
+ goal TEXT NOT NULL,
8
+ status TEXT NOT NULL DEFAULT 'draft' CHECK (status IN ('draft', 'approved', 'executing', 'completed', 'failed', 'rejected')),
9
+ constraints TEXT DEFAULT '{}',
10
+ total_steps INTEGER NOT NULL DEFAULT 0,
11
+ completed_steps INTEGER NOT NULL DEFAULT 0,
12
+ failed_steps INTEGER NOT NULL DEFAULT 0,
13
+ created_at TEXT DEFAULT (datetime('now')),
14
+ updated_at TEXT DEFAULT (datetime('now'))
15
+ );
16
+
17
+ CREATE INDEX IF NOT EXISTS idx_plans_workspace ON agent_workforce_plans(workspace_id);
18
+ CREATE INDEX IF NOT EXISTS idx_plans_status ON agent_workforce_plans(status);
19
+
20
+ CREATE TABLE IF NOT EXISTS agent_workforce_plan_steps (
21
+ id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),
22
+ plan_id TEXT NOT NULL REFERENCES agent_workforce_plans(id) ON DELETE CASCADE,
23
+ step_index INTEGER NOT NULL,
24
+ title TEXT NOT NULL,
25
+ prompt TEXT NOT NULL,
26
+ agent_id TEXT,
27
+ depends_on TEXT DEFAULT '[]',
28
+ status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'in_progress', 'completed', 'failed', 'skipped')),
29
+ task_id TEXT,
30
+ output_summary TEXT,
31
+ created_at TEXT DEFAULT (datetime('now')),
32
+ updated_at TEXT DEFAULT (datetime('now'))
33
+ );
34
+
35
+ CREATE INDEX IF NOT EXISTS idx_plan_steps_plan ON agent_workforce_plan_steps(plan_id);
36
+ CREATE INDEX IF NOT EXISTS idx_plan_steps_status ON agent_workforce_plan_steps(status);
@@ -0,0 +1,16 @@
1
+ -- 009-nudges.sql
2
+ -- Proactive nudges for the autonomous runtime
3
+
4
+ CREATE TABLE IF NOT EXISTS agent_workforce_nudges (
5
+ id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),
6
+ workspace_id TEXT NOT NULL,
7
+ nudge_type TEXT NOT NULL CHECK (nudge_type IN ('overdue_task', 'aging_approval', 'idle_agent', 'stale_contact', 'plan_blocked', 'streak_risk')),
8
+ title TEXT NOT NULL,
9
+ description TEXT,
10
+ suggested_action TEXT,
11
+ status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'dismissed', 'acted')),
12
+ created_at TEXT DEFAULT (datetime('now')),
13
+ updated_at TEXT DEFAULT (datetime('now'))
14
+ );
15
+
16
+ CREATE INDEX IF NOT EXISTS idx_nudges_workspace_status ON agent_workforce_nudges(workspace_id, status);
@@ -0,0 +1,35 @@
1
+ -- 010-local-crm.sql
2
+ -- Local CRM tables for data sovereignty
3
+
4
+ CREATE TABLE IF NOT EXISTS agent_workforce_contacts (
5
+ id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),
6
+ workspace_id TEXT NOT NULL,
7
+ name TEXT NOT NULL,
8
+ email TEXT,
9
+ phone TEXT,
10
+ company TEXT,
11
+ contact_type TEXT NOT NULL DEFAULT 'lead' CHECK (contact_type IN ('lead', 'customer', 'partner', 'other')),
12
+ status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'inactive')),
13
+ tags TEXT DEFAULT '[]',
14
+ custom_fields TEXT DEFAULT '{}',
15
+ notes TEXT,
16
+ created_at TEXT DEFAULT (datetime('now')),
17
+ updated_at TEXT DEFAULT (datetime('now'))
18
+ );
19
+
20
+ CREATE INDEX IF NOT EXISTS idx_contacts_workspace ON agent_workforce_contacts(workspace_id);
21
+ CREATE INDEX IF NOT EXISTS idx_contacts_type ON agent_workforce_contacts(workspace_id, contact_type);
22
+
23
+ CREATE TABLE IF NOT EXISTS agent_workforce_revenue_entries (
24
+ id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),
25
+ workspace_id TEXT NOT NULL,
26
+ amount_cents INTEGER NOT NULL DEFAULT 0,
27
+ month INTEGER NOT NULL CHECK (month >= 1 AND month <= 12),
28
+ year INTEGER NOT NULL CHECK (year >= 2000 AND year <= 2100),
29
+ source TEXT,
30
+ notes TEXT,
31
+ created_at TEXT DEFAULT (datetime('now')),
32
+ updated_at TEXT DEFAULT (datetime('now'))
33
+ );
34
+
35
+ CREATE INDEX IF NOT EXISTS idx_revenue_workspace ON agent_workforce_revenue_entries(workspace_id);
@@ -0,0 +1,5 @@
1
+ CREATE TABLE IF NOT EXISTS runtime_settings (
2
+ key TEXT PRIMARY KEY,
3
+ value TEXT NOT NULL,
4
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
5
+ );
@@ -0,0 +1,14 @@
1
+ CREATE TABLE IF NOT EXISTS orchestrator_memory (
2
+ id TEXT PRIMARY KEY,
3
+ workspace_id TEXT NOT NULL,
4
+ memory_type TEXT NOT NULL CHECK (memory_type IN ('preference', 'pattern', 'context', 'correction')),
5
+ content TEXT NOT NULL,
6
+ source_session_id TEXT,
7
+ relevance_score REAL NOT NULL DEFAULT 0.5,
8
+ is_active INTEGER NOT NULL DEFAULT 1,
9
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
10
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
11
+ );
12
+
13
+ CREATE INDEX IF NOT EXISTS idx_orch_memory_workspace ON orchestrator_memory(workspace_id);
14
+ CREATE INDEX IF NOT EXISTS idx_orch_memory_active ON orchestrator_memory(workspace_id, is_active);
@@ -0,0 +1,9 @@
1
+ -- Key-value settings table for runtime-level config (e.g. orchestrator voice)
2
+ CREATE TABLE IF NOT EXISTS runtime_settings (
3
+ key TEXT PRIMARY KEY,
4
+ value TEXT NOT NULL,
5
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
6
+ );
7
+
8
+ -- @statement
9
+ ALTER TABLE agent_workforce_agents ADD COLUMN voice_profile_id TEXT DEFAULT NULL;
@@ -0,0 +1,53 @@
1
+ -- 014: Webhooks and Local Triggers
2
+ -- Stores incoming webhook events and trigger-to-action mappings for event-driven automation.
3
+
4
+ -- Audit log of all incoming webhook payloads
5
+ CREATE TABLE IF NOT EXISTS webhook_events (
6
+ id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),
7
+ source TEXT NOT NULL DEFAULT 'ghl',
8
+ event_type TEXT NOT NULL,
9
+ payload TEXT NOT NULL DEFAULT '{}',
10
+ headers TEXT NOT NULL DEFAULT '{}',
11
+ processed INTEGER NOT NULL DEFAULT 0,
12
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
13
+ );
14
+
15
+ CREATE INDEX IF NOT EXISTS idx_webhook_events_source ON webhook_events(source, event_type);
16
+ CREATE INDEX IF NOT EXISTS idx_webhook_events_created ON webhook_events(created_at);
17
+
18
+ -- Event-to-action mappings
19
+ CREATE TABLE IF NOT EXISTS local_triggers (
20
+ id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),
21
+ name TEXT NOT NULL,
22
+ description TEXT NOT NULL DEFAULT '',
23
+ enabled INTEGER NOT NULL DEFAULT 1,
24
+ source TEXT NOT NULL DEFAULT 'ghl',
25
+ event_type TEXT NOT NULL,
26
+ conditions TEXT NOT NULL DEFAULT '{}',
27
+ action_type TEXT NOT NULL DEFAULT 'run_agent',
28
+ action_config TEXT NOT NULL DEFAULT '{}',
29
+ cooldown_seconds INTEGER NOT NULL DEFAULT 60,
30
+ last_fired_at TEXT,
31
+ fire_count INTEGER NOT NULL DEFAULT 0,
32
+ last_error TEXT,
33
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
34
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
35
+ );
36
+
37
+ CREATE INDEX IF NOT EXISTS idx_local_triggers_source ON local_triggers(source, event_type);
38
+
39
+ -- Execution audit log per trigger firing
40
+ CREATE TABLE IF NOT EXISTS local_trigger_executions (
41
+ id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),
42
+ trigger_id TEXT NOT NULL REFERENCES local_triggers(id) ON DELETE CASCADE,
43
+ source_event TEXT NOT NULL,
44
+ source_metadata TEXT NOT NULL DEFAULT '{}',
45
+ action_type TEXT NOT NULL,
46
+ action_result TEXT,
47
+ status TEXT NOT NULL DEFAULT 'pending',
48
+ error_message TEXT,
49
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
50
+ );
51
+
52
+ CREATE INDEX IF NOT EXISTS idx_trigger_executions_trigger ON local_trigger_executions(trigger_id);
53
+ CREATE INDEX IF NOT EXISTS idx_trigger_executions_created ON local_trigger_executions(created_at);
@@ -0,0 +1,19 @@
1
+ -- File attachments metadata table (SQLite)
2
+ CREATE TABLE IF NOT EXISTS agent_workforce_attachments (
3
+ id TEXT PRIMARY KEY,
4
+ workspace_id TEXT NOT NULL,
5
+ entity_type TEXT NOT NULL CHECK (entity_type IN ('contact', 'task', 'plan_step')),
6
+ entity_id TEXT NOT NULL,
7
+ filename TEXT NOT NULL,
8
+ file_type TEXT NOT NULL,
9
+ file_size INTEGER NOT NULL CHECK (file_size > 0),
10
+ storage_path TEXT NOT NULL,
11
+ uploaded_by TEXT,
12
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
13
+ );
14
+
15
+ CREATE INDEX IF NOT EXISTS idx_workforce_attachments_workspace
16
+ ON agent_workforce_attachments(workspace_id);
17
+
18
+ CREATE INDEX IF NOT EXISTS idx_workforce_attachments_entity
19
+ ON agent_workforce_attachments(entity_type, entity_id);
@@ -0,0 +1,47 @@
1
+ -- 016-dashboard-tables.sql
2
+ -- Additional tables needed by the web dashboard init endpoint.
3
+ -- Contacts and revenue already exist (010-local-crm.sql).
4
+
5
+ CREATE TABLE IF NOT EXISTS agent_workforce_departments (
6
+ id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),
7
+ workspace_id TEXT NOT NULL,
8
+ name TEXT NOT NULL,
9
+ color TEXT,
10
+ description TEXT,
11
+ sort_order INTEGER NOT NULL DEFAULT 0,
12
+ created_at TEXT DEFAULT (datetime('now')),
13
+ updated_at TEXT DEFAULT (datetime('now'))
14
+ );
15
+
16
+ CREATE INDEX IF NOT EXISTS idx_departments_workspace ON agent_workforce_departments(workspace_id);
17
+
18
+ CREATE TABLE IF NOT EXISTS agent_workforce_team_members (
19
+ id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),
20
+ workspace_id TEXT NOT NULL,
21
+ name TEXT NOT NULL,
22
+ email TEXT,
23
+ role TEXT,
24
+ start_date TEXT,
25
+ skills TEXT DEFAULT '[]',
26
+ capacity_hours INTEGER,
27
+ created_at TEXT DEFAULT (datetime('now')),
28
+ updated_at TEXT DEFAULT (datetime('now'))
29
+ );
30
+
31
+ CREATE INDEX IF NOT EXISTS idx_team_members_workspace ON agent_workforce_team_members(workspace_id);
32
+
33
+ CREATE TABLE IF NOT EXISTS agent_workforce_custom_roadmap_stages (
34
+ id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),
35
+ workspace_id TEXT NOT NULL,
36
+ stage_id INTEGER NOT NULL,
37
+ tagline TEXT,
38
+ focus_areas TEXT DEFAULT '[]',
39
+ key_metrics TEXT DEFAULT '[]',
40
+ next_milestone TEXT,
41
+ priority TEXT,
42
+ priority_description TEXT,
43
+ quick_actions TEXT DEFAULT '[]',
44
+ generated_at TEXT DEFAULT (datetime('now'))
45
+ );
46
+
47
+ CREATE INDEX IF NOT EXISTS idx_custom_roadmap_workspace ON agent_workforce_custom_roadmap_stages(workspace_id);
@@ -0,0 +1,24 @@
1
+ -- Workflow triggers: event-based automation that auto-runs workflows
2
+ CREATE TABLE IF NOT EXISTS agent_workforce_workflow_triggers (
3
+ id TEXT PRIMARY KEY,
4
+ workspace_id TEXT NOT NULL,
5
+ workflow_id TEXT NOT NULL,
6
+ name TEXT NOT NULL,
7
+ trigger_event TEXT NOT NULL CHECK (trigger_event IN (
8
+ 'task_completed', 'task_failed', 'task_needs_approval',
9
+ 'task_approved', 'task_rejected', 'human_task_completed',
10
+ 'task_handoff', 'email_received', 'contact_created'
11
+ )),
12
+ conditions TEXT, -- JSON conditions for conditional firing
13
+ cooldown_seconds INTEGER DEFAULT 0,
14
+ enabled INTEGER DEFAULT 1,
15
+ fire_count INTEGER DEFAULT 0,
16
+ last_fired_at TEXT,
17
+ created_at TEXT DEFAULT (datetime('now')),
18
+ updated_at TEXT DEFAULT (datetime('now'))
19
+ );
20
+
21
+ CREATE INDEX IF NOT EXISTS idx_workflow_triggers_workspace
22
+ ON agent_workforce_workflow_triggers(workspace_id);
23
+ CREATE INDEX IF NOT EXISTS idx_workflow_triggers_event
24
+ ON agent_workforce_workflow_triggers(trigger_event, enabled);
@@ -0,0 +1,20 @@
1
+ -- 018-workspace-onboarding.sql
2
+ -- Workspace-level data collected during onboarding (business info, founder stage).
3
+ -- Stores onboarding context for agent recommendations and personalization.
4
+
5
+ CREATE TABLE IF NOT EXISTS agent_workforce_workspaces (
6
+ id TEXT PRIMARY KEY,
7
+ business_name TEXT,
8
+ business_type TEXT,
9
+ business_description TEXT,
10
+ founder_path TEXT,
11
+ founder_focus TEXT,
12
+ growth_stage TEXT,
13
+ onboarding_complete INTEGER NOT NULL DEFAULT 0,
14
+ timezone TEXT,
15
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
16
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
17
+ );
18
+
19
+ -- Seed a default local workspace row
20
+ INSERT OR IGNORE INTO agent_workforce_workspaces (id) VALUES ('local');
@@ -0,0 +1,9 @@
1
+ -- Custom webhook support for local triggers
2
+ -- Adds per-trigger webhook URLs, sample payload storage, and field discovery
3
+
4
+ ALTER TABLE local_triggers ADD COLUMN webhook_token TEXT;
5
+ ALTER TABLE local_triggers ADD COLUMN sample_payload TEXT;
6
+ ALTER TABLE local_triggers ADD COLUMN sample_fields TEXT;
7
+
8
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_local_triggers_webhook_token
9
+ ON local_triggers(webhook_token) WHERE webhook_token IS NOT NULL;
@@ -0,0 +1,9 @@
1
+ -- Migration 020: Add action chains to local triggers
2
+ -- Adds multi-step action support (Zapier-style linear chains)
3
+
4
+ ALTER TABLE local_triggers ADD COLUMN actions TEXT;
5
+ -- JSON array: [{ "id": "step_1", "action_type": "...", "action_config": {...}, "label": "..." }]
6
+ -- When null, evaluator falls back to legacy action_type/action_config columns
7
+
8
+ ALTER TABLE local_trigger_executions ADD COLUMN step_index INTEGER;
9
+ ALTER TABLE local_trigger_executions ADD COLUMN step_id TEXT;
@@ -0,0 +1,12 @@
1
+ -- ============================================================================
2
+ -- 021: Unify Automations
3
+ --
4
+ -- Add trigger_type, trigger_config, and variables columns to local_triggers
5
+ -- so that all automation types (webhook, schedule, event, manual) can be
6
+ -- represented in a single table. Also adds support for agent_prompt and
7
+ -- a2a_call step types in the actions chain.
8
+ -- ============================================================================
9
+
10
+ ALTER TABLE local_triggers ADD COLUMN trigger_type TEXT DEFAULT 'webhook';
11
+ ALTER TABLE local_triggers ADD COLUMN trigger_config TEXT DEFAULT '{}';
12
+ ALTER TABLE local_triggers ADD COLUMN variables TEXT;
@@ -0,0 +1,66 @@
1
+ -- ============================================================================
2
+ -- 022: Knowledge Base
3
+ --
4
+ -- Adds knowledge document storage, chunking, and per-agent configuration
5
+ -- for the local (TUI) knowledge base feature.
6
+ -- ============================================================================
7
+
8
+ CREATE TABLE IF NOT EXISTS agent_workforce_knowledge_documents (
9
+ id TEXT PRIMARY KEY,
10
+ workspace_id TEXT NOT NULL,
11
+ agent_id TEXT,
12
+ title TEXT NOT NULL,
13
+ description TEXT,
14
+ filename TEXT NOT NULL,
15
+ file_type TEXT NOT NULL,
16
+ file_size INTEGER NOT NULL,
17
+ storage_path TEXT NOT NULL,
18
+ source_type TEXT NOT NULL DEFAULT 'upload',
19
+ source_url TEXT,
20
+ processing_status TEXT NOT NULL DEFAULT 'pending',
21
+ processing_error TEXT,
22
+ processed_at TEXT,
23
+ compiled_text TEXT,
24
+ compiled_token_count INTEGER DEFAULT 0,
25
+ chunk_count INTEGER DEFAULT 0,
26
+ version INTEGER NOT NULL DEFAULT 1,
27
+ content_hash TEXT,
28
+ times_used INTEGER NOT NULL DEFAULT 0,
29
+ last_used_at TEXT,
30
+ is_active INTEGER NOT NULL DEFAULT 1,
31
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
32
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
33
+ );
34
+
35
+ CREATE INDEX IF NOT EXISTS idx_knowledge_docs_workspace
36
+ ON agent_workforce_knowledge_documents(workspace_id, is_active);
37
+
38
+ CREATE TABLE IF NOT EXISTS agent_workforce_knowledge_chunks (
39
+ id TEXT PRIMARY KEY,
40
+ document_id TEXT NOT NULL REFERENCES agent_workforce_knowledge_documents(id) ON DELETE CASCADE,
41
+ workspace_id TEXT NOT NULL,
42
+ chunk_index INTEGER NOT NULL,
43
+ content TEXT NOT NULL,
44
+ token_count INTEGER NOT NULL,
45
+ summary TEXT,
46
+ keywords TEXT,
47
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
48
+ );
49
+
50
+ CREATE INDEX IF NOT EXISTS idx_knowledge_chunks_document
51
+ ON agent_workforce_knowledge_chunks(document_id, chunk_index);
52
+
53
+ CREATE TABLE IF NOT EXISTS agent_workforce_knowledge_agent_config (
54
+ id TEXT PRIMARY KEY,
55
+ document_id TEXT NOT NULL REFERENCES agent_workforce_knowledge_documents(id) ON DELETE CASCADE,
56
+ agent_id TEXT NOT NULL,
57
+ workspace_id TEXT NOT NULL,
58
+ opted_out INTEGER NOT NULL DEFAULT 0,
59
+ injection_mode TEXT NOT NULL DEFAULT 'auto',
60
+ priority INTEGER NOT NULL DEFAULT 0,
61
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
62
+ UNIQUE(document_id, agent_id)
63
+ );
64
+
65
+ ALTER TABLE agent_workforce_agents ADD COLUMN knowledge_document TEXT DEFAULT '';
66
+ ALTER TABLE agent_workforce_agents ADD COLUMN knowledge_token_count INTEGER DEFAULT 0;
@@ -0,0 +1,19 @@
1
+ -- ============================================================================
2
+ -- 023: Local File Access
3
+ --
4
+ -- Adds per-agent directory allowlists for read-only filesystem access.
5
+ -- Agents can read files from configured directories during task execution.
6
+ -- ============================================================================
7
+
8
+ CREATE TABLE IF NOT EXISTS agent_file_access_paths (
9
+ id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),
10
+ agent_id TEXT NOT NULL,
11
+ workspace_id TEXT NOT NULL,
12
+ path TEXT NOT NULL,
13
+ label TEXT,
14
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
15
+ UNIQUE(agent_id, path)
16
+ );
17
+
18
+ CREATE INDEX IF NOT EXISTS idx_file_access_agent
19
+ ON agent_file_access_paths(agent_id);
@@ -0,0 +1,25 @@
1
+ -- Model detection and usage stats for Ollama models
2
+
3
+ CREATE TABLE IF NOT EXISTS ollama_model_snapshots (
4
+ model_name TEXT PRIMARY KEY,
5
+ status TEXT NOT NULL DEFAULT 'installed' CHECK (status IN ('loaded', 'installed', 'unavailable')),
6
+ size_bytes INTEGER,
7
+ vram_bytes INTEGER,
8
+ processor TEXT,
9
+ quantization TEXT,
10
+ family TEXT,
11
+ expires_at TEXT,
12
+ last_seen_at TEXT NOT NULL DEFAULT (datetime('now')),
13
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
14
+ );
15
+
16
+ CREATE TABLE IF NOT EXISTS ollama_model_stats (
17
+ model_name TEXT PRIMARY KEY,
18
+ total_requests INTEGER NOT NULL DEFAULT 0,
19
+ total_input_tokens INTEGER NOT NULL DEFAULT 0,
20
+ total_output_tokens INTEGER NOT NULL DEFAULT 0,
21
+ total_duration_ms INTEGER NOT NULL DEFAULT 0,
22
+ last_used_at TEXT,
23
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
24
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
25
+ );
@@ -0,0 +1,91 @@
1
+ import Database from 'better-sqlite3';
2
+
3
+ /**
4
+ * DatabaseAdapter Interface (Runtime Copy)
5
+ *
6
+ * Abstracts the query builder pattern used by Supabase's PostgREST client.
7
+ * Both the Supabase adapter (cloud) and SQLite adapter (enterprise runtime)
8
+ * implement this interface, allowing all agent services to work with either backend.
9
+ *
10
+ * Mirrors the SupabaseClient chaining API: .from(table).select().eq().single()
11
+ */
12
+ interface DbResult<T> {
13
+ data: T | null;
14
+ error: DbError | null;
15
+ count?: number | null;
16
+ }
17
+ interface DbError {
18
+ message: string;
19
+ code?: string;
20
+ details?: string;
21
+ hint?: string;
22
+ }
23
+ interface FilterBuilder<T> {
24
+ eq(column: string, value: unknown): FilterBuilder<T>;
25
+ neq(column: string, value: unknown): FilterBuilder<T>;
26
+ gt(column: string, value: unknown): FilterBuilder<T>;
27
+ gte(column: string, value: unknown): FilterBuilder<T>;
28
+ lt(column: string, value: unknown): FilterBuilder<T>;
29
+ lte(column: string, value: unknown): FilterBuilder<T>;
30
+ in(column: string, values: unknown[]): FilterBuilder<T>;
31
+ is(column: string, value: null | boolean): FilterBuilder<T>;
32
+ or(filters: string, options?: {
33
+ foreignTable?: string;
34
+ }): FilterBuilder<T>;
35
+ not(column: string, operator: string, value: unknown): FilterBuilder<T>;
36
+ order(column: string, options?: {
37
+ ascending?: boolean;
38
+ }): FilterBuilder<T>;
39
+ limit(count: number): FilterBuilder<T>;
40
+ range(from: number, to: number): FilterBuilder<T>;
41
+ single(): PromiseLike<DbResult<T>>;
42
+ maybeSingle(): PromiseLike<DbResult<T | null>>;
43
+ then<TResult1 = DbResult<T[]>, TResult2 = never>(onfulfilled?: ((value: DbResult<T[]>) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null): PromiseLike<TResult1 | TResult2>;
44
+ }
45
+ type SelectBuilder<T> = FilterBuilder<T>;
46
+ interface InsertBuilder<T> {
47
+ select(columns?: string): FilterBuilder<T>;
48
+ then<TResult1 = DbResult<null>, TResult2 = never>(onfulfilled?: ((value: DbResult<null>) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null): PromiseLike<TResult1 | TResult2>;
49
+ }
50
+ interface UpdateBuilder<T> extends FilterBuilder<T> {
51
+ eq(column: string, value: unknown): UpdateBuilder<T>;
52
+ neq(column: string, value: unknown): UpdateBuilder<T>;
53
+ select(columns?: string): FilterBuilder<T>;
54
+ }
55
+ type DeleteBuilder<T> = FilterBuilder<T>;
56
+ interface TableBuilder<T = Record<string, unknown>> {
57
+ select(columns?: string, options?: {
58
+ count?: 'exact';
59
+ head?: boolean;
60
+ }): SelectBuilder<T>;
61
+ insert(data: Partial<T> | Partial<T>[]): InsertBuilder<T>;
62
+ update(data: Partial<T>): UpdateBuilder<T>;
63
+ delete(): DeleteBuilder<T>;
64
+ }
65
+ interface DatabaseAdapter {
66
+ from<T = Record<string, unknown>>(table: string): TableBuilder<T>;
67
+ rpc<T = unknown>(fn: string, params?: Record<string, unknown>): PromiseLike<DbResult<T>>;
68
+ }
69
+
70
+ /**
71
+ * SQLite Adapter
72
+ *
73
+ * Implements the DatabaseAdapter interface using better-sqlite3.
74
+ * Translates the SupabaseClient-shaped query builder API into SQL queries
75
+ * against a local SQLite database.
76
+ *
77
+ * Used by the enterprise runtime for local data plane storage.
78
+ */
79
+
80
+ /**
81
+ * Map of registered RPC functions for the SQLite adapter.
82
+ * In Supabase, .rpc() calls server-side Postgres functions.
83
+ * In SQLite, we register JS functions that perform the same logic.
84
+ */
85
+ type RpcHandler = (params: Record<string, unknown>) => unknown;
86
+ interface SqliteAdapterOptions {
87
+ rpcHandlers?: Record<string, RpcHandler>;
88
+ }
89
+ declare function createSqliteAdapter(db: Database.Database, options?: SqliteAdapterOptions): DatabaseAdapter;
90
+
91
+ export { type SqliteAdapterOptions, createSqliteAdapter };