db4ai 0.3.0 → 0.3.2

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 (89) hide show
  1. package/dist/chunk-3DWAMVV5.js +305 -0
  2. package/dist/chunk-3DWAMVV5.js.map +1 -0
  3. package/dist/chunk-COTPYBYM.js +618 -0
  4. package/dist/chunk-COTPYBYM.js.map +1 -0
  5. package/dist/chunk-EERD6CDF.js +735 -0
  6. package/dist/chunk-EERD6CDF.js.map +1 -0
  7. package/dist/chunk-FUF4HJTC.js +758 -0
  8. package/dist/chunk-FUF4HJTC.js.map +1 -0
  9. package/dist/chunk-JLL6FH5L.js +16 -0
  10. package/dist/chunk-JLL6FH5L.js.map +1 -0
  11. package/dist/chunk-JXFW6AIT.js +192 -0
  12. package/dist/chunk-JXFW6AIT.js.map +1 -0
  13. package/dist/chunk-XLSYCQPG.js +854 -0
  14. package/dist/chunk-XLSYCQPG.js.map +1 -0
  15. package/dist/chunk-Y5IXAS7F.js +569 -0
  16. package/dist/chunk-Y5IXAS7F.js.map +1 -0
  17. package/dist/cli/bin.d.ts +13 -12
  18. package/dist/cli/bin.js +277 -307
  19. package/dist/cli/bin.js.map +1 -1
  20. package/dist/cli/dashboard/index.d.ts +295 -14
  21. package/dist/cli/dashboard/index.js +60 -15
  22. package/dist/cli/dashboard/index.js.map +1 -1
  23. package/dist/cli/index.d.ts +10 -16
  24. package/dist/cli/index.js +94 -47
  25. package/dist/cli/index.js.map +1 -1
  26. package/dist/cli/runtime/index.d.ts +52 -23
  27. package/dist/cli/runtime/index.js +10 -704
  28. package/dist/cli/runtime/index.js.map +1 -1
  29. package/dist/cli/scanner/index.d.ts +17 -15
  30. package/dist/cli/scanner/index.js +8 -639
  31. package/dist/cli/scanner/index.js.map +1 -1
  32. package/dist/cli/seed/index.d.ts +16 -12
  33. package/dist/cli/seed/index.js +12 -773
  34. package/dist/cli/seed/index.js.map +1 -1
  35. package/dist/cli/sync/index.d.ts +54 -53
  36. package/dist/cli/sync/index.js +23 -704
  37. package/dist/cli/sync/index.js.map +1 -1
  38. package/dist/cli/terminal.d.ts +9 -8
  39. package/dist/cli/terminal.js +6 -209
  40. package/dist/cli/terminal.js.map +1 -1
  41. package/dist/cli/workflow/index.d.ts +18 -10
  42. package/dist/cli/workflow/index.js +6 -307
  43. package/dist/cli/workflow/index.js.map +1 -1
  44. package/dist/handlers.d.ts +10 -9
  45. package/dist/handlers.js +6 -38
  46. package/dist/handlers.js.map +1 -1
  47. package/dist/index.d.ts +120 -118
  48. package/dist/index.js +1972 -3125
  49. package/dist/index.js.map +1 -1
  50. package/package.json +3 -4
  51. package/dist/cli/bin.d.ts.map +0 -1
  52. package/dist/cli/dashboard/App.d.ts +0 -16
  53. package/dist/cli/dashboard/App.d.ts.map +0 -1
  54. package/dist/cli/dashboard/App.js +0 -116
  55. package/dist/cli/dashboard/App.js.map +0 -1
  56. package/dist/cli/dashboard/components/index.d.ts +0 -70
  57. package/dist/cli/dashboard/components/index.d.ts.map +0 -1
  58. package/dist/cli/dashboard/components/index.js +0 -192
  59. package/dist/cli/dashboard/components/index.js.map +0 -1
  60. package/dist/cli/dashboard/hooks/index.d.ts +0 -76
  61. package/dist/cli/dashboard/hooks/index.d.ts.map +0 -1
  62. package/dist/cli/dashboard/hooks/index.js +0 -201
  63. package/dist/cli/dashboard/hooks/index.js.map +0 -1
  64. package/dist/cli/dashboard/index.d.ts.map +0 -1
  65. package/dist/cli/dashboard/types.d.ts +0 -84
  66. package/dist/cli/dashboard/types.d.ts.map +0 -1
  67. package/dist/cli/dashboard/types.js +0 -5
  68. package/dist/cli/dashboard/types.js.map +0 -1
  69. package/dist/cli/dashboard/views/index.d.ts +0 -51
  70. package/dist/cli/dashboard/views/index.d.ts.map +0 -1
  71. package/dist/cli/dashboard/views/index.js +0 -72
  72. package/dist/cli/dashboard/views/index.js.map +0 -1
  73. package/dist/cli/index.d.ts.map +0 -1
  74. package/dist/cli/runtime/index.d.ts.map +0 -1
  75. package/dist/cli/scanner/index.d.ts.map +0 -1
  76. package/dist/cli/seed/index.d.ts.map +0 -1
  77. package/dist/cli/sync/index.d.ts.map +0 -1
  78. package/dist/cli/terminal.d.ts.map +0 -1
  79. package/dist/cli/workflow/index.d.ts.map +0 -1
  80. package/dist/errors.d.ts +0 -43
  81. package/dist/errors.d.ts.map +0 -1
  82. package/dist/errors.js +0 -47
  83. package/dist/errors.js.map +0 -1
  84. package/dist/handlers.d.ts.map +0 -1
  85. package/dist/index.d.ts.map +0 -1
  86. package/dist/types.d.ts +0 -276
  87. package/dist/types.d.ts.map +0 -1
  88. package/dist/types.js +0 -12
  89. package/dist/types.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../cli/runtime/index.ts"],"sourcesContent":["/**\n * Module 14: Local Runtime\n *\n * SQLite-based local database runtime for offline-first development.\n * Provides the same interface as the Cloudflare Durable Object for\n * seamless local development and testing.\n */\n\nimport Database from 'better-sqlite3'\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport * as crypto from 'node:crypto'\n\n// ============================================================================\n// Type Definitions\n// ============================================================================\n\nexport interface Thing {\n rowid: number\n type: string\n id: string\n data: Record<string, unknown>\n content_hash: string\n created_at: number\n created_by_action?: number\n}\n\nexport interface UpsertResult {\n rowid: number\n created: boolean\n}\n\nexport interface UpsertParams {\n type: string\n id: string\n data: Record<string, unknown>\n created_by_action?: number\n}\n\nexport interface GetParams {\n type: string\n id: string\n}\n\nexport interface ListParams {\n type?: string\n limit?: number\n offset?: number\n where?: Record<string, unknown>\n order?: 'asc' | 'desc'\n}\n\nexport interface Relationship {\n rowid: number\n from_rowid: number\n to_rowid: number\n type: string\n path: string\n label: string\n created_at: number\n created_by_action?: number\n}\n\nexport interface CreateRelationshipParams {\n from_rowid: number\n to_rowid: number\n type: string\n path: string\n label: string\n created_by_action?: number\n}\n\nexport interface TraverseParams {\n from_rowid: number\n type?: string\n}\n\nexport interface IncomingParams {\n to_rowid: number\n type?: string\n}\n\nexport interface TraverseMultiHopParams {\n from_rowid: number\n depth: number\n type?: string\n}\n\nexport interface TraverseMultiHopResult {\n to_rowid: number\n depth: number\n}\n\nexport interface Action {\n rowid: number\n type: 'mutation' | 'generation' | 'resolution' | 'function' | 'evaluate'\n input_hash: string\n input: Record<string, unknown>\n output?: Record<string, unknown>\n model?: string\n status: 'pending' | 'complete' | 'error'\n error?: string\n duration_ms?: number\n cost_tokens?: number\n created_at: number\n}\n\nexport interface CreateActionParams {\n type: 'mutation' | 'generation' | 'resolution' | 'function' | 'evaluate'\n input: Record<string, unknown>\n model?: string\n}\n\nexport interface CompleteActionParams {\n rowid: number\n output: Record<string, unknown>\n duration_ms?: number\n cost_tokens?: number\n}\n\nexport interface FailActionParams {\n rowid: number\n error: string\n}\n\nexport interface DBEvent {\n rowid: number\n type: string\n action: 'created' | 'updated' | 'deleted' | 'generated'\n entity_type: string\n entity_id: string\n entity_rowid: number\n data: Record<string, unknown>\n changes?: Record<string, unknown>\n timestamp: number\n action_id?: number\n correlation_id?: string\n}\n\nexport interface EmitEventParams {\n type: string\n action: 'created' | 'updated' | 'deleted' | 'generated'\n entity_type: string\n entity_id: string\n entity_rowid: number\n data: Record<string, unknown>\n changes?: Record<string, unknown>\n action_id?: number\n correlation_id?: string\n}\n\nexport interface ListEventsParams {\n type?: string\n action?: 'created' | 'updated' | 'deleted' | 'generated'\n since?: number\n correlation_id?: string\n limit?: number\n}\n\n// ============================================================================\n// Utility Functions\n// ============================================================================\n\n/**\n * Computes a deterministic hash of an object by sorting keys recursively.\n */\nfunction computeHash(obj: Record<string, unknown>): string {\n const sortedJson = stableStringify(obj)\n return crypto.createHash('sha256').update(sortedJson).digest('hex').slice(0, 16)\n}\n\n/**\n * Stable JSON stringify that sorts object keys for consistent hashing.\n */\nfunction stableStringify(obj: unknown): string {\n if (obj === null || typeof obj !== 'object') {\n return JSON.stringify(obj)\n }\n\n if (Array.isArray(obj)) {\n return '[' + obj.map(stableStringify).join(',') + ']'\n }\n\n const keys = Object.keys(obj as Record<string, unknown>).sort()\n const pairs = keys.map(\n (key) => JSON.stringify(key) + ':' + stableStringify((obj as Record<string, unknown>)[key])\n )\n return '{' + pairs.join(',') + '}'\n}\n\n/**\n * Ensures parent directories exist for a given file path.\n * Silently handles errors (e.g., permission denied, root paths).\n */\nfunction ensureDirectoryExists(filePath: string): void {\n const dir = path.dirname(filePath)\n try {\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true })\n }\n } catch {\n // Silently ignore - the database open will fail with a more specific error\n }\n}\n\n// ============================================================================\n// Connection Pool (Singleton Pattern)\n// ============================================================================\n\n/**\n * Connection pool for reusing database instances.\n * SQLite with better-sqlite3 uses file-level locking, so we maintain\n * a singleton instance per database path to avoid resource contention.\n */\nclass ConnectionPool {\n private static instances = new Map<string, { db: Database.Database; refCount: number }>()\n\n /**\n * Acquire a database connection. Creates a new one or returns existing.\n */\n static acquire(dbPath: string): Database.Database {\n const normalizedPath = path.resolve(dbPath)\n const existing = this.instances.get(normalizedPath)\n\n if (existing) {\n existing.refCount++\n return existing.db\n }\n\n // Ensure directory exists before opening\n ensureDirectoryExists(normalizedPath)\n\n // Open new connection\n let db: Database.Database\n try {\n db = new Database(normalizedPath)\n } catch {\n // Fallback to in-memory for invalid paths\n db = new Database(':memory:')\n }\n\n // Enable WAL mode for better concurrent performance\n try {\n db.pragma('journal_mode = WAL')\n } catch {\n // WAL mode may not be available for in-memory databases\n }\n\n this.instances.set(normalizedPath, { db, refCount: 1 })\n return db\n }\n\n /**\n * Release a database connection. Closes when ref count reaches 0.\n */\n static release(dbPath: string): void {\n const normalizedPath = path.resolve(dbPath)\n const entry = this.instances.get(normalizedPath)\n\n if (!entry) return\n\n entry.refCount--\n if (entry.refCount <= 0) {\n entry.db.close()\n this.instances.delete(normalizedPath)\n }\n }\n\n /**\n * Force close all connections (for testing cleanup).\n */\n static closeAll(): void {\n for (const [path, entry] of this.instances) {\n entry.db.close()\n this.instances.delete(path)\n }\n }\n}\n\n// ============================================================================\n// Database Schema Version\n// ============================================================================\n\nconst SCHEMA_VERSION = 2\n\nconst SCHEMA_SQL = `\n -- Things table (entities)\n CREATE TABLE IF NOT EXISTS things (\n rowid INTEGER PRIMARY KEY AUTOINCREMENT,\n type TEXT NOT NULL,\n id TEXT NOT NULL,\n data TEXT NOT NULL,\n content_hash TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n created_by_action INTEGER,\n FOREIGN KEY (created_by_action) REFERENCES actions(rowid)\n );\n\n -- Indexes for things table\n CREATE INDEX IF NOT EXISTS idx_things_type_id ON things(type, id);\n CREATE INDEX IF NOT EXISTS idx_things_content_hash ON things(content_hash);\n CREATE INDEX IF NOT EXISTS idx_things_type ON things(type);\n -- Optimized index for latest version lookups (covering index)\n CREATE INDEX IF NOT EXISTS idx_things_type_id_rowid ON things(type, id, rowid DESC);\n -- Index for content hash deduplication queries\n CREATE INDEX IF NOT EXISTS idx_things_type_id_hash ON things(type, id, content_hash);\n\n -- Relationships table (edges)\n CREATE TABLE IF NOT EXISTS relationships (\n rowid INTEGER PRIMARY KEY AUTOINCREMENT,\n from_rowid INTEGER NOT NULL,\n to_rowid INTEGER NOT NULL,\n type TEXT NOT NULL,\n path TEXT NOT NULL,\n label TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n created_by_action INTEGER,\n FOREIGN KEY (from_rowid) REFERENCES things(rowid),\n FOREIGN KEY (to_rowid) REFERENCES things(rowid),\n FOREIGN KEY (created_by_action) REFERENCES actions(rowid),\n UNIQUE (from_rowid, to_rowid, path)\n );\n\n -- Indexes for relationships table\n CREATE INDEX IF NOT EXISTS idx_relationships_from ON relationships(from_rowid);\n CREATE INDEX IF NOT EXISTS idx_relationships_to ON relationships(to_rowid);\n CREATE INDEX IF NOT EXISTS idx_relationships_type ON relationships(type);\n -- Optimized composite index for filtered traversals\n CREATE INDEX IF NOT EXISTS idx_relationships_from_type ON relationships(from_rowid, type);\n CREATE INDEX IF NOT EXISTS idx_relationships_to_type ON relationships(to_rowid, type);\n\n -- Actions table (for caching and tracking)\n CREATE TABLE IF NOT EXISTS actions (\n rowid INTEGER PRIMARY KEY AUTOINCREMENT,\n type TEXT NOT NULL,\n input_hash TEXT NOT NULL,\n input TEXT NOT NULL,\n output TEXT,\n model TEXT,\n status TEXT NOT NULL DEFAULT 'pending',\n error TEXT,\n duration_ms INTEGER,\n cost_tokens INTEGER,\n created_at INTEGER NOT NULL\n );\n\n -- Indexes for actions table\n CREATE INDEX IF NOT EXISTS idx_actions_input_hash ON actions(input_hash);\n CREATE INDEX IF NOT EXISTS idx_actions_status ON actions(status);\n -- Optimized composite index for cache lookups (input_hash + status)\n CREATE INDEX IF NOT EXISTS idx_actions_hash_status ON actions(input_hash, status);\n\n -- Events table (audit log)\n CREATE TABLE IF NOT EXISTS events (\n rowid INTEGER PRIMARY KEY AUTOINCREMENT,\n type TEXT NOT NULL,\n action TEXT NOT NULL,\n entity_type TEXT NOT NULL,\n entity_id TEXT NOT NULL,\n entity_rowid INTEGER NOT NULL,\n data TEXT NOT NULL,\n changes TEXT,\n timestamp INTEGER NOT NULL,\n action_id INTEGER,\n correlation_id TEXT,\n FOREIGN KEY (action_id) REFERENCES actions(rowid)\n );\n\n -- Indexes for events table\n CREATE INDEX IF NOT EXISTS idx_events_type ON events(type);\n CREATE INDEX IF NOT EXISTS idx_events_action ON events(action);\n CREATE INDEX IF NOT EXISTS idx_events_timestamp ON events(timestamp);\n CREATE INDEX IF NOT EXISTS idx_events_correlation_id ON events(correlation_id);\n -- Optimized composite index for entity-based event lookups\n CREATE INDEX IF NOT EXISTS idx_events_entity ON events(entity_type, entity_id);\n -- Composite index for filtered event queries\n CREATE INDEX IF NOT EXISTS idx_events_type_action ON events(type, action);\n\n -- Schema version tracking\n CREATE TABLE IF NOT EXISTS schema_version (\n version INTEGER NOT NULL\n );\n`\n\n// Migration from version 1 to version 2\nconst MIGRATION_V1_TO_V2 = `\n -- Add new optimized indexes for version 2\n CREATE INDEX IF NOT EXISTS idx_things_type_id_rowid ON things(type, id, rowid DESC);\n CREATE INDEX IF NOT EXISTS idx_things_type_id_hash ON things(type, id, content_hash);\n CREATE INDEX IF NOT EXISTS idx_relationships_from_type ON relationships(from_rowid, type);\n CREATE INDEX IF NOT EXISTS idx_relationships_to_type ON relationships(to_rowid, type);\n CREATE INDEX IF NOT EXISTS idx_actions_hash_status ON actions(input_hash, status);\n CREATE INDEX IF NOT EXISTS idx_events_entity ON events(entity_type, entity_id);\n CREATE INDEX IF NOT EXISTS idx_events_type_action ON events(type, action);\n`\n\n// ============================================================================\n// LocalDB Class\n// ============================================================================\n\nexport class LocalDB {\n private db: Database.Database\n private usePool: boolean\n public readonly path: string\n public readonly version: number = SCHEMA_VERSION\n\n public readonly things: ThingsAPI\n public readonly relationships: RelationshipsAPI\n public readonly actions: ActionsAPI\n public readonly events: EventsAPI\n\n constructor(dbPath?: string, options?: { usePool?: boolean }) {\n // Use default path if not provided\n this.path = dbPath || path.join(process.cwd(), '.db4', 'local.db')\n this.usePool = options?.usePool ?? false\n\n if (this.usePool) {\n // Use connection pool for shared access\n this.db = ConnectionPool.acquire(this.path)\n } else {\n // Direct connection (default for backwards compatibility with tests)\n ensureDirectoryExists(this.path)\n\n try {\n this.db = new Database(this.path)\n } catch {\n // Fallback to in-memory for invalid paths\n this.db = new Database(':memory:')\n }\n\n // Enable WAL mode for better concurrent performance\n try {\n this.db.pragma('journal_mode = WAL')\n } catch {\n // WAL mode may not be available for in-memory databases\n }\n }\n\n // Initialize schema\n this.initSchema()\n\n // Initialize APIs\n this.things = new ThingsAPI(this.db)\n this.relationships = new RelationshipsAPI(this.db)\n this.actions = new ActionsAPI(this.db)\n this.events = new EventsAPI(this.db)\n }\n\n private initSchema(): void {\n // Check if schema exists\n const tableCheck = this.db\n .prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name='schema_version'`)\n .get()\n\n if (!tableCheck) {\n // Initialize fresh database with latest schema\n this.db.exec(SCHEMA_SQL)\n this.db.prepare('INSERT INTO schema_version (version) VALUES (?)').run(SCHEMA_VERSION)\n } else {\n // Check for migrations\n this.runMigrations()\n }\n }\n\n /**\n * Run any pending database migrations.\n */\n private runMigrations(): void {\n const row = this.db.prepare('SELECT version FROM schema_version LIMIT 1').get() as\n | { version: number }\n | undefined\n const currentVersion = row?.version ?? 1\n\n if (currentVersion < SCHEMA_VERSION) {\n // Run migrations in order\n if (currentVersion < 2) {\n this.db.exec(MIGRATION_V1_TO_V2)\n }\n\n // Update schema version\n this.db.prepare('UPDATE schema_version SET version = ?').run(SCHEMA_VERSION)\n }\n }\n\n /**\n * Closes the database connection.\n */\n close(): void {\n if (this.usePool) {\n ConnectionPool.release(this.path)\n } else {\n this.db.close()\n }\n }\n\n /**\n * Runs VACUUM to reclaim disk space.\n */\n vacuum(): Promise<void> {\n this.db.exec('VACUUM')\n return Promise.resolve()\n }\n}\n\n// ============================================================================\n// Things API\n// ============================================================================\n\nclass ThingsAPI {\n constructor(private db: Database.Database) {}\n\n /**\n * Upsert a thing. Returns existing rowid if content_hash matches,\n * otherwise creates a new version.\n */\n async upsert(params: UpsertParams): Promise<UpsertResult> {\n const { type, id, data, created_by_action } = params\n const dataJson = JSON.stringify(data)\n const content_hash = computeHash({ type, id, data })\n const created_at = Date.now()\n\n // Check if identical content already exists\n const existing = this.db\n .prepare('SELECT rowid FROM things WHERE type = ? AND id = ? AND content_hash = ?')\n .get(type, id, content_hash) as { rowid: number } | undefined\n\n if (existing) {\n return { rowid: existing.rowid, created: false }\n }\n\n // Insert new version\n const result = this.db\n .prepare(\n `INSERT INTO things (type, id, data, content_hash, created_at, created_by_action)\n VALUES (?, ?, ?, ?, ?, ?)`\n )\n .run(type, id, dataJson, content_hash, created_at, created_by_action || null)\n\n return { rowid: result.lastInsertRowid as number, created: true }\n }\n\n /**\n * Get the latest version of a thing by type and id.\n */\n async get(params: GetParams): Promise<Thing | null> {\n const { type, id } = params\n\n const row = this.db\n .prepare(\n `SELECT rowid, type, id, data, content_hash, created_at, created_by_action\n FROM things\n WHERE type = ? AND id = ?\n ORDER BY rowid DESC\n LIMIT 1`\n )\n .get(type, id) as\n | {\n rowid: number\n type: string\n id: string\n data: string\n content_hash: string\n created_at: number\n created_by_action: number | null\n }\n | undefined\n\n if (!row) return null\n\n return {\n rowid: row.rowid,\n type: row.type,\n id: row.id,\n data: JSON.parse(row.data),\n content_hash: row.content_hash,\n created_at: row.created_at,\n created_by_action: row.created_by_action ?? undefined,\n }\n }\n\n /**\n * Get a specific version by rowid.\n */\n async getByRowid(rowid: number): Promise<Thing | null> {\n const row = this.db\n .prepare(\n `SELECT rowid, type, id, data, content_hash, created_at, created_by_action\n FROM things\n WHERE rowid = ?`\n )\n .get(rowid) as\n | {\n rowid: number\n type: string\n id: string\n data: string\n content_hash: string\n created_at: number\n created_by_action: number | null\n }\n | undefined\n\n if (!row) return null\n\n return {\n rowid: row.rowid,\n type: row.type,\n id: row.id,\n data: JSON.parse(row.data),\n content_hash: row.content_hash,\n created_at: row.created_at,\n created_by_action: row.created_by_action ?? undefined,\n }\n }\n\n /**\n * List things with optional filters.\n */\n async list(params: ListParams = {}): Promise<Thing[]> {\n const { type, limit, offset, where, order = 'asc' } = params\n\n let sql = `\n SELECT t.rowid, t.type, t.id, t.data, t.content_hash, t.created_at, t.created_by_action\n FROM things t\n INNER JOIN (\n SELECT type, id, MAX(rowid) as max_rowid\n FROM things\n ${type ? 'WHERE type = ?' : ''}\n GROUP BY type, id\n ) latest ON t.rowid = latest.max_rowid\n `\n\n const queryParams: unknown[] = []\n if (type) {\n queryParams.push(type)\n }\n\n // Handle where clause\n if (where && Object.keys(where).length > 0) {\n const whereConditions = Object.keys(where).map((key) => {\n const value = where[key]\n // json_extract returns the raw value, so for strings we compare directly\n queryParams.push(value)\n return `json_extract(t.data, '$.${key}') = ?`\n })\n\n sql += ` WHERE ${whereConditions.join(' AND ')}`\n }\n\n sql += ` ORDER BY t.rowid ${order === 'desc' ? 'DESC' : 'ASC'}`\n\n if (limit !== undefined) {\n sql += ` LIMIT ?`\n queryParams.push(limit)\n }\n\n if (offset !== undefined) {\n sql += ` OFFSET ?`\n queryParams.push(offset)\n }\n\n const rows = this.db.prepare(sql).all(...queryParams) as Array<{\n rowid: number\n type: string\n id: string\n data: string\n content_hash: string\n created_at: number\n created_by_action: number | null\n }>\n\n return rows.map((row) => ({\n rowid: row.rowid,\n type: row.type,\n id: row.id,\n data: JSON.parse(row.data),\n content_hash: row.content_hash,\n created_at: row.created_at,\n created_by_action: row.created_by_action ?? undefined,\n }))\n }\n\n /**\n * Delete a thing by rowid.\n */\n async delete(rowid: number): Promise<void> {\n this.db.prepare('DELETE FROM things WHERE rowid = ?').run(rowid)\n }\n}\n\n// ============================================================================\n// Relationships API\n// ============================================================================\n\nclass RelationshipsAPI {\n constructor(private db: Database.Database) {}\n\n /**\n * Create or update a relationship edge.\n * If (from_rowid, to_rowid, path) already exists, updates it.\n */\n async create(params: CreateRelationshipParams): Promise<Relationship> {\n const { from_rowid, to_rowid, type, path, label, created_by_action } = params\n const created_at = Date.now()\n\n // Check if edge exists with same from/to/path\n const existing = this.db\n .prepare(\n `SELECT rowid FROM relationships\n WHERE from_rowid = ? AND to_rowid = ? AND path = ?`\n )\n .get(from_rowid, to_rowid, path) as { rowid: number } | undefined\n\n if (existing) {\n // Update existing edge\n this.db\n .prepare(\n `UPDATE relationships\n SET type = ?, label = ?, created_by_action = ?\n WHERE rowid = ?`\n )\n .run(type, label, created_by_action || null, existing.rowid)\n\n const row = this.db\n .prepare(\n `SELECT rowid, from_rowid, to_rowid, type, path, label, created_at, created_by_action\n FROM relationships WHERE rowid = ?`\n )\n .get(existing.rowid) as {\n rowid: number\n from_rowid: number\n to_rowid: number\n type: string\n path: string\n label: string\n created_at: number\n created_by_action: number | null\n }\n\n return {\n rowid: row.rowid,\n from_rowid: row.from_rowid,\n to_rowid: row.to_rowid,\n type: row.type,\n path: row.path,\n label: row.label,\n created_at: row.created_at,\n created_by_action: row.created_by_action ?? undefined,\n }\n }\n\n // Insert new edge\n const result = this.db\n .prepare(\n `INSERT INTO relationships (from_rowid, to_rowid, type, path, label, created_at, created_by_action)\n VALUES (?, ?, ?, ?, ?, ?, ?)`\n )\n .run(from_rowid, to_rowid, type, path, label, created_at, created_by_action || null)\n\n return {\n rowid: result.lastInsertRowid as number,\n from_rowid,\n to_rowid,\n type,\n path,\n label,\n created_at,\n created_by_action,\n }\n }\n\n /**\n * List all relationships.\n */\n async list(): Promise<Relationship[]> {\n const rows = this.db\n .prepare(\n `SELECT rowid, from_rowid, to_rowid, type, path, label, created_at, created_by_action\n FROM relationships`\n )\n .all() as Array<{\n rowid: number\n from_rowid: number\n to_rowid: number\n type: string\n path: string\n label: string\n created_at: number\n created_by_action: number | null\n }>\n\n return rows.map((row) => ({\n rowid: row.rowid,\n from_rowid: row.from_rowid,\n to_rowid: row.to_rowid,\n type: row.type,\n path: row.path,\n label: row.label,\n created_at: row.created_at,\n created_by_action: row.created_by_action ?? undefined,\n }))\n }\n\n /**\n * Traverse forward from an entity.\n */\n async traverse(params: TraverseParams): Promise<Relationship[]> {\n const { from_rowid, type } = params\n\n let sql = `\n SELECT rowid, from_rowid, to_rowid, type, path, label, created_at, created_by_action\n FROM relationships\n WHERE from_rowid = ?\n `\n const queryParams: unknown[] = [from_rowid]\n\n if (type) {\n sql += ' AND type = ?'\n queryParams.push(type)\n }\n\n const rows = this.db.prepare(sql).all(...queryParams) as Array<{\n rowid: number\n from_rowid: number\n to_rowid: number\n type: string\n path: string\n label: string\n created_at: number\n created_by_action: number | null\n }>\n\n return rows.map((row) => ({\n rowid: row.rowid,\n from_rowid: row.from_rowid,\n to_rowid: row.to_rowid,\n type: row.type,\n path: row.path,\n label: row.label,\n created_at: row.created_at,\n created_by_action: row.created_by_action ?? undefined,\n }))\n }\n\n /**\n * Find incoming edges to an entity.\n */\n async incoming(params: IncomingParams): Promise<Relationship[]> {\n const { to_rowid, type } = params\n\n let sql = `\n SELECT rowid, from_rowid, to_rowid, type, path, label, created_at, created_by_action\n FROM relationships\n WHERE to_rowid = ?\n `\n const queryParams: unknown[] = [to_rowid]\n\n if (type) {\n sql += ' AND type = ?'\n queryParams.push(type)\n }\n\n const rows = this.db.prepare(sql).all(...queryParams) as Array<{\n rowid: number\n from_rowid: number\n to_rowid: number\n type: string\n path: string\n label: string\n created_at: number\n created_by_action: number | null\n }>\n\n return rows.map((row) => ({\n rowid: row.rowid,\n from_rowid: row.from_rowid,\n to_rowid: row.to_rowid,\n type: row.type,\n path: row.path,\n label: row.label,\n created_at: row.created_at,\n created_by_action: row.created_by_action ?? undefined,\n }))\n }\n\n /**\n * Traverse multiple hops from an entity (BFS).\n */\n async traverseMultiHop(params: TraverseMultiHopParams): Promise<TraverseMultiHopResult[]> {\n const { from_rowid, depth, type } = params\n\n const visited = new Set<number>([from_rowid])\n const results: TraverseMultiHopResult[] = []\n let currentLevel = [from_rowid]\n\n for (let d = 1; d <= depth && currentLevel.length > 0; d++) {\n const nextLevel: number[] = []\n\n for (const nodeId of currentLevel) {\n const edges = await this.traverse({ from_rowid: nodeId, type })\n\n for (const edge of edges) {\n if (!visited.has(edge.to_rowid)) {\n visited.add(edge.to_rowid)\n results.push({ to_rowid: edge.to_rowid, depth: d })\n nextLevel.push(edge.to_rowid)\n }\n }\n }\n\n currentLevel = nextLevel\n }\n\n return results\n }\n}\n\n// ============================================================================\n// Actions API\n// ============================================================================\n\nclass ActionsAPI {\n constructor(private db: Database.Database) {}\n\n /**\n * Create a new action in pending status.\n */\n async create(params: CreateActionParams): Promise<Action> {\n const { type, input, model } = params\n const inputJson = JSON.stringify(input)\n const input_hash = computeHash(input)\n const created_at = Date.now()\n\n const result = this.db\n .prepare(\n `INSERT INTO actions (type, input_hash, input, model, status, created_at)\n VALUES (?, ?, ?, ?, 'pending', ?)`\n )\n .run(type, input_hash, inputJson, model || null, created_at)\n\n return {\n rowid: result.lastInsertRowid as number,\n type,\n input_hash,\n input,\n model,\n status: 'pending',\n created_at,\n }\n }\n\n /**\n * Find a completed action by input hash (cache lookup).\n * Only returns actions with status='complete'.\n */\n async findByHash(input_hash: string): Promise<Action | null> {\n const row = this.db\n .prepare(\n `SELECT rowid, type, input_hash, input, output, model, status, error, duration_ms, cost_tokens, created_at\n FROM actions\n WHERE input_hash = ? AND status = 'complete'\n ORDER BY rowid DESC\n LIMIT 1`\n )\n .get(input_hash) as\n | {\n rowid: number\n type: string\n input_hash: string\n input: string\n output: string | null\n model: string | null\n status: string\n error: string | null\n duration_ms: number | null\n cost_tokens: number | null\n created_at: number\n }\n | undefined\n\n if (!row) return null\n\n return {\n rowid: row.rowid,\n type: row.type as Action['type'],\n input_hash: row.input_hash,\n input: JSON.parse(row.input),\n output: row.output ? JSON.parse(row.output) : undefined,\n model: row.model ?? undefined,\n status: row.status as Action['status'],\n error: row.error ?? undefined,\n duration_ms: row.duration_ms ?? undefined,\n cost_tokens: row.cost_tokens ?? undefined,\n created_at: row.created_at,\n }\n }\n\n /**\n * Complete an action with output.\n */\n async complete(params: CompleteActionParams): Promise<Action> {\n const { rowid, output, duration_ms, cost_tokens } = params\n const outputJson = JSON.stringify(output)\n\n // Check if action exists and is pending\n const existing = this.db\n .prepare('SELECT status FROM actions WHERE rowid = ?')\n .get(rowid) as { status: string } | undefined\n\n if (!existing) {\n throw new Error(`Action with rowid ${rowid} not found`)\n }\n\n if (existing.status !== 'pending') {\n throw new Error(`Cannot complete action with status '${existing.status}'`)\n }\n\n this.db\n .prepare(\n `UPDATE actions\n SET status = 'complete', output = ?, duration_ms = ?, cost_tokens = ?\n WHERE rowid = ?`\n )\n .run(outputJson, duration_ms || null, cost_tokens || null, rowid)\n\n const row = this.db\n .prepare(\n `SELECT rowid, type, input_hash, input, output, model, status, error, duration_ms, cost_tokens, created_at\n FROM actions WHERE rowid = ?`\n )\n .get(rowid) as {\n rowid: number\n type: string\n input_hash: string\n input: string\n output: string | null\n model: string | null\n status: string\n error: string | null\n duration_ms: number | null\n cost_tokens: number | null\n created_at: number\n }\n\n return {\n rowid: row.rowid,\n type: row.type as Action['type'],\n input_hash: row.input_hash,\n input: JSON.parse(row.input),\n output: row.output ? JSON.parse(row.output) : undefined,\n model: row.model ?? undefined,\n status: row.status as Action['status'],\n error: row.error ?? undefined,\n duration_ms: row.duration_ms ?? undefined,\n cost_tokens: row.cost_tokens ?? undefined,\n created_at: row.created_at,\n }\n }\n\n /**\n * Mark an action as failed.\n */\n async fail(params: FailActionParams): Promise<Action> {\n const { rowid, error } = params\n\n // Check if action exists and is pending\n const existing = this.db\n .prepare('SELECT status FROM actions WHERE rowid = ?')\n .get(rowid) as { status: string } | undefined\n\n if (!existing) {\n throw new Error(`Action with rowid ${rowid} not found`)\n }\n\n if (existing.status !== 'pending') {\n throw new Error(`Cannot fail action with status '${existing.status}'`)\n }\n\n this.db.prepare(`UPDATE actions SET status = 'error', error = ? WHERE rowid = ?`).run(error, rowid)\n\n const row = this.db\n .prepare(\n `SELECT rowid, type, input_hash, input, output, model, status, error, duration_ms, cost_tokens, created_at\n FROM actions WHERE rowid = ?`\n )\n .get(rowid) as {\n rowid: number\n type: string\n input_hash: string\n input: string\n output: string | null\n model: string | null\n status: string\n error: string | null\n duration_ms: number | null\n cost_tokens: number | null\n created_at: number\n }\n\n return {\n rowid: row.rowid,\n type: row.type as Action['type'],\n input_hash: row.input_hash,\n input: JSON.parse(row.input),\n output: row.output ? JSON.parse(row.output) : undefined,\n model: row.model ?? undefined,\n status: row.status as Action['status'],\n error: row.error ?? undefined,\n duration_ms: row.duration_ms ?? undefined,\n cost_tokens: row.cost_tokens ?? undefined,\n created_at: row.created_at,\n }\n }\n}\n\n// ============================================================================\n// Events API\n// ============================================================================\n\nclass EventsAPI {\n constructor(private db: Database.Database) {}\n\n /**\n * Emit an event.\n */\n async emit(params: EmitEventParams): Promise<DBEvent> {\n const {\n type,\n action,\n entity_type,\n entity_id,\n entity_rowid,\n data,\n changes,\n action_id,\n correlation_id,\n } = params\n const timestamp = Date.now()\n const dataJson = JSON.stringify(data)\n const changesJson = changes ? JSON.stringify(changes) : null\n\n const result = this.db\n .prepare(\n `INSERT INTO events (type, action, entity_type, entity_id, entity_rowid, data, changes, timestamp, action_id, correlation_id)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`\n )\n .run(\n type,\n action,\n entity_type,\n entity_id,\n entity_rowid,\n dataJson,\n changesJson,\n timestamp,\n action_id || null,\n correlation_id || null\n )\n\n return {\n rowid: result.lastInsertRowid as number,\n type,\n action,\n entity_type,\n entity_id,\n entity_rowid,\n data,\n changes,\n timestamp,\n action_id,\n correlation_id,\n }\n }\n\n /**\n * List events with optional filters.\n */\n async list(params: ListEventsParams = {}): Promise<DBEvent[]> {\n const { type, action, since, correlation_id, limit } = params\n\n let sql = `\n SELECT rowid, type, action, entity_type, entity_id, entity_rowid, data, changes, timestamp, action_id, correlation_id\n FROM events\n WHERE 1=1\n `\n const queryParams: unknown[] = []\n\n if (type) {\n sql += ' AND type = ?'\n queryParams.push(type)\n }\n\n if (action) {\n sql += ' AND action = ?'\n queryParams.push(action)\n }\n\n if (since !== undefined) {\n sql += ' AND timestamp > ?'\n queryParams.push(since)\n }\n\n if (correlation_id) {\n sql += ' AND correlation_id = ?'\n queryParams.push(correlation_id)\n }\n\n sql += ' ORDER BY timestamp ASC'\n\n if (limit !== undefined) {\n sql += ' LIMIT ?'\n queryParams.push(limit)\n }\n\n const rows = this.db.prepare(sql).all(...queryParams) as Array<{\n rowid: number\n type: string\n action: string\n entity_type: string\n entity_id: string\n entity_rowid: number\n data: string\n changes: string | null\n timestamp: number\n action_id: number | null\n correlation_id: string | null\n }>\n\n return rows.map((row) => ({\n rowid: row.rowid,\n type: row.type,\n action: row.action as DBEvent['action'],\n entity_type: row.entity_type,\n entity_id: row.entity_id,\n entity_rowid: row.entity_rowid,\n data: JSON.parse(row.data),\n changes: row.changes ? JSON.parse(row.changes) : undefined,\n timestamp: row.timestamp,\n action_id: row.action_id ?? undefined,\n correlation_id: row.correlation_id ?? undefined,\n }))\n }\n}\n\n// Export ConnectionPool for advanced usage and testing\nexport { ConnectionPool }\n\n// Default export for convenience\nexport default LocalDB\n"],"mappings":"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","names":["path"]}
@@ -0,0 +1,16 @@
1
+ // handlers.ts
2
+ function serializeFunction(name, fn) {
3
+ const fnStr = fn.toString();
4
+ const isAsync = fnStr.trimStart().startsWith("async");
5
+ let params = [];
6
+ const paramMatch = fnStr.match(/^(?:async\s*)?(?:function\s*\w*)?\s*\(([^)]*)\)/);
7
+ if (paramMatch && paramMatch[1]) {
8
+ params = paramMatch[1].split(",").map((p) => p.trim().split(":")[0].split("=")[0].trim()).filter(Boolean);
9
+ }
10
+ return { name, body: fnStr, params, async: isAsync };
11
+ }
12
+
13
+ export {
14
+ serializeFunction
15
+ };
16
+ //# sourceMappingURL=chunk-JLL6FH5L.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../handlers.ts"],"sourcesContent":["// ============================================================================\n// Handler Types\n//\n// Shared types for handler-related functionality used by both SDK and API.\n// This module defines types for function serialization and lifecycle handlers.\n// ============================================================================\n\n/**\n * Serialized representation of a function for transport to server.\n *\n * Functions defined in schema definitions (like lifecycle handlers) are\n * serialized into this format for execution on the server side.\n *\n * @example\n * ```typescript\n * const serialized: SerializedFunction = {\n * name: '$created',\n * body: '(entity, $) => $.OtherType(entity.name)',\n * params: ['entity', '$'],\n * async: true\n * }\n * ```\n */\nexport interface SerializedFunction {\n /** The name of the function (e.g., '$created', 'validateUser') */\n name: string\n /** The stringified function body */\n body: string\n /** Array of parameter names extracted from the function signature */\n params: string[]\n /** Whether the function is async */\n async: boolean\n}\n\n/**\n * Serialize a function for server-side execution.\n *\n * Converts a JavaScript function into a serializable format that can be\n * sent to the server and executed in a sandboxed environment.\n *\n * @param name - The name to assign to the serialized function\n * @param fn - The function to serialize\n * @returns A SerializedFunction object\n *\n * @example\n * ```typescript\n * const handler = async (entity: any, $: any) => {\n * await $.OtherType(entity.name)\n * }\n * const serialized = serializeFunction('$created', handler)\n * // { name: '$created', body: 'async (entity, $) => {...}', params: ['entity', '$'], async: true }\n * ```\n */\nexport function serializeFunction(name: string, fn: Function): SerializedFunction {\n const fnStr = fn.toString()\n const isAsync = fnStr.trimStart().startsWith('async')\n let params: string[] = []\n const paramMatch = fnStr.match(/^(?:async\\s*)?(?:function\\s*\\w*)?\\s*\\(([^)]*)\\)/)\n if (paramMatch && paramMatch[1]) {\n params = paramMatch[1]\n .split(',')\n .map((p: string) => p.trim().split(':')[0].split('=')[0].trim())\n .filter(Boolean)\n }\n return { name, body: fnStr, params, async: isAsync }\n}\n\n// ============================================================================\n// Lifecycle Handler Types\n// ============================================================================\n\n/**\n * Entity-level lifecycle handler types.\n *\n * These handlers are triggered on individual entity operations:\n * - `$created` - Called after a new entity is created\n * - `$updated` - Called after an entity is updated\n * - `$deleted` - Called after an entity is deleted\n *\n * @example\n * ```typescript\n * DB({\n * User: {\n * name: 'User name',\n * $created: async (entity, $) => {\n * await $.WelcomeEmail({ to: entity.email })\n * }\n * }\n * })\n * ```\n */\nexport type EntityHandlerType = '$created' | '$updated' | '$deleted'\n\n/**\n * Schema-level lifecycle handler types.\n *\n * These handlers are triggered on schema-wide events:\n * - `$seeded` - Called after seed data is loaded for a type\n * - `$ready` - Called when the schema is fully initialized\n * - `$error` - Called when a schema-level error occurs\n *\n * @example\n * ```typescript\n * DB({\n * $seeded: async ($) => {\n * console.log('Seed data loaded')\n * }\n * })\n * ```\n */\nexport type SchemaHandlerType = '$seeded' | '$ready' | '$error'\n\n/**\n * All lifecycle handler types (entity + schema level).\n *\n * This union type includes all handler types that can be defined:\n * - Entity handlers: `$created`, `$updated`, `$deleted`\n * - Schema handlers: `$seeded`, `$ready`, `$error`\n */\nexport type LifecycleHandlerType = EntityHandlerType | SchemaHandlerType\n\n/**\n * State machine handler types.\n *\n * These handlers are triggered during state transitions:\n * - `$entry` - Called when entering a state\n * - `$exit` - Called when exiting a state\n *\n * @example\n * ```typescript\n * DB({\n * Order: {\n * $state: {\n * $initial: 'pending',\n * pending: {\n * $entry: (entity) => console.log('Order is now pending'),\n * confirm: 'confirmed'\n * }\n * }\n * }\n * })\n * ```\n */\nexport type StateHandlerType = '$entry' | '$exit'\n\n/**\n * Handler execution result from the sandboxed environment.\n *\n * Contains the outcome of executing a serialized handler function\n * in an isolated V8 sandbox.\n */\nexport interface HandlerExecutionResult {\n /** Whether execution completed without error */\n success: boolean\n /** Return value from the handler (if any) */\n result?: unknown\n /** Error message if execution failed */\n error?: string\n /** Execution time in milliseconds */\n duration: number\n}\n\n/**\n * Log entry captured during handler execution.\n *\n * Console output from handlers is captured and returned\n * for debugging and monitoring purposes.\n */\nexport interface HandlerLogEntry {\n /** Log level (log, warn, error, info, debug) */\n level: 'log' | 'warn' | 'error' | 'info' | 'debug'\n /** The log message content */\n message: string\n /** Timestamp when the log was created */\n timestamp: number\n}\n"],"mappings":";AAqDO,SAAS,kBAAkB,MAAc,IAAkC;AAChF,QAAM,QAAQ,GAAG,SAAS;AAC1B,QAAM,UAAU,MAAM,UAAU,EAAE,WAAW,OAAO;AACpD,MAAI,SAAmB,CAAC;AACxB,QAAM,aAAa,MAAM,MAAM,iDAAiD;AAChF,MAAI,cAAc,WAAW,CAAC,GAAG;AAC/B,aAAS,WAAW,CAAC,EAClB,MAAM,GAAG,EACT,IAAI,CAAC,MAAc,EAAE,KAAK,EAAE,MAAM,GAAG,EAAE,CAAC,EAAE,MAAM,GAAG,EAAE,CAAC,EAAE,KAAK,CAAC,EAC9D,OAAO,OAAO;AAAA,EACnB;AACA,SAAO,EAAE,MAAM,MAAM,OAAO,QAAQ,OAAO,QAAQ;AACrD;","names":[]}
@@ -0,0 +1,192 @@
1
+ // cli/terminal.ts
2
+ function createDashboard(options = {}) {
3
+ const {
4
+ title = "db4 dev",
5
+ showLogs = true,
6
+ showStats = true,
7
+ maxLogEntries = 10,
8
+ colors = true,
9
+ stdout = process.stdout,
10
+ stdin = process.stdin
11
+ } = options;
12
+ let running = false;
13
+ const progress = /* @__PURE__ */ new Map();
14
+ const logs = [];
15
+ let stats = {};
16
+ const workflows = /* @__PURE__ */ new Map();
17
+ let refreshInterval = null;
18
+ let keyResolver = null;
19
+ const color = (code, text) => colors ? `\x1B[${code}m${text}\x1B[0m` : text;
20
+ const green = (text) => color("32", text);
21
+ const yellow = (text) => color("33", text);
22
+ const red = (text) => color("31", text);
23
+ const blue = (text) => color("34", text);
24
+ const dim = (text) => color("2", text);
25
+ const bold = (text) => color("1", text);
26
+ const formatProgress = (p) => {
27
+ const bar = createProgressBar(p.percentage, 20);
28
+ const status = p.status === "completed" ? green("\u2713") : p.status === "failed" ? red("\u2717") : blue("\u25CF");
29
+ const rateStr = p.rate ? ` ${p.rate.toFixed(1)}/s` : "";
30
+ const etaStr = p.eta ? ` ETA: ${formatDuration(p.eta)}` : "";
31
+ return `${status} ${p.seedName.padEnd(20)} ${bar} ${p.current}/${p.total}${rateStr}${etaStr}`;
32
+ };
33
+ const createProgressBar = (percentage, width) => {
34
+ const clampedPercentage = Math.max(0, Math.min(100, percentage));
35
+ const filled = Math.round(clampedPercentage / 100 * width);
36
+ const empty = width - filled;
37
+ return `[${"\u2588".repeat(filled)}${dim("\u2591".repeat(empty))}]`;
38
+ };
39
+ const formatDuration = (ms) => {
40
+ const seconds = Math.floor(ms / 1e3);
41
+ const minutes = Math.floor(seconds / 60);
42
+ const remainingSeconds = seconds % 60;
43
+ if (minutes > 0) {
44
+ return `${minutes}m ${remainingSeconds}s`;
45
+ }
46
+ return `${seconds}s`;
47
+ };
48
+ const formatLog = (entry) => {
49
+ const levelColors = {
50
+ debug: dim,
51
+ info: blue,
52
+ warn: yellow,
53
+ error: red
54
+ };
55
+ const colorFn = levelColors[entry.level];
56
+ const timestamp = entry.timestamp ? new Date(entry.timestamp).toLocaleTimeString() : "";
57
+ const prefix = colorFn(`[${entry.level.toUpperCase()}]`);
58
+ const dataStr = entry.data ? ` ${dim(JSON.stringify(entry.data))}` : "";
59
+ return `${dim(timestamp)} ${prefix} ${entry.message}${dataStr}`;
60
+ };
61
+ const render = () => {
62
+ if (!running) return;
63
+ const lines = [];
64
+ lines.push("");
65
+ lines.push(bold(` ${title}`));
66
+ lines.push(dim(" " + "\u2500".repeat(40)));
67
+ if (progress.size > 0) {
68
+ lines.push("");
69
+ lines.push(bold(" Progress"));
70
+ for (const p of progress.values()) {
71
+ lines.push(` ${formatProgress(p)}`);
72
+ }
73
+ }
74
+ if (workflows.size > 0) {
75
+ lines.push("");
76
+ lines.push(bold(" Workflows"));
77
+ for (const w of workflows.values()) {
78
+ const status = w.status === "completed" ? green("\u2713") : w.status === "failed" ? red("\u2717") : w.status === "running" ? blue("\u25CF") : dim("\u25CB");
79
+ const progressStr = w.progress !== void 0 ? ` ${w.progress}%` : "";
80
+ const entityStr = w.entityId ? dim(` (${w.entityId})`) : "";
81
+ const errorStr = w.error ? red(` Error: ${w.error}`) : "";
82
+ lines.push(` ${status} ${w.name}${progressStr}${entityStr}${errorStr}`);
83
+ }
84
+ }
85
+ if (showStats && Object.keys(stats).length > 0) {
86
+ lines.push("");
87
+ lines.push(bold(" Stats"));
88
+ if (stats.seeds !== void 0) lines.push(` Seeds: ${stats.seeds}`);
89
+ if (stats.workflows !== void 0) lines.push(` Workflows: ${stats.workflows}`);
90
+ if (stats.entities !== void 0) lines.push(` Entities: ${stats.entities}`);
91
+ if (stats.errors !== void 0 && stats.errors > 0) {
92
+ lines.push(` ${red(`Errors: ${stats.errors}`)}`);
93
+ }
94
+ if (stats.duration !== void 0) {
95
+ lines.push(` Duration: ${formatDuration(stats.duration)}`);
96
+ }
97
+ }
98
+ if (showLogs && logs.length > 0) {
99
+ lines.push("");
100
+ lines.push(bold(" Logs"));
101
+ const recentLogs = logs.slice(-maxLogEntries);
102
+ for (const log of recentLogs) {
103
+ lines.push(` ${formatLog(log)}`);
104
+ }
105
+ }
106
+ lines.push("");
107
+ stdout.write("\x1B[2J\x1B[H");
108
+ stdout.write(lines.join("\n"));
109
+ };
110
+ const setupKeyListener = () => {
111
+ if (stdin.isTTY) {
112
+ stdin.setRawMode?.(true);
113
+ stdin.resume();
114
+ stdin.setEncoding("utf8");
115
+ stdin.on("data", (key) => {
116
+ if (key === "") {
117
+ process.exit();
118
+ }
119
+ if (keyResolver) {
120
+ keyResolver(key);
121
+ keyResolver = null;
122
+ }
123
+ });
124
+ }
125
+ };
126
+ return {
127
+ start() {
128
+ if (running) return;
129
+ running = true;
130
+ render();
131
+ refreshInterval = setInterval(render, 100);
132
+ setupKeyListener();
133
+ },
134
+ stop() {
135
+ if (!running) return;
136
+ running = false;
137
+ if (refreshInterval) {
138
+ clearInterval(refreshInterval);
139
+ refreshInterval = null;
140
+ }
141
+ stdout.write("\x1B[?25h");
142
+ },
143
+ updateProgress(update) {
144
+ progress.set(update.seedName, update);
145
+ if (update.status === "completed" || update.status === "failed") {
146
+ setTimeout(() => {
147
+ const current = progress.get(update.seedName);
148
+ if (current?.status === "completed" || current?.status === "failed") {
149
+ progress.delete(update.seedName);
150
+ }
151
+ }, 2e3);
152
+ }
153
+ render();
154
+ },
155
+ addLog(entry) {
156
+ logs.push({
157
+ ...entry,
158
+ timestamp: entry.timestamp ?? Date.now()
159
+ });
160
+ while (logs.length > maxLogEntries * 2) {
161
+ logs.shift();
162
+ }
163
+ render();
164
+ },
165
+ setStats(newStats) {
166
+ stats = { ...stats, ...newStats };
167
+ render();
168
+ },
169
+ setWorkflowStatus(status) {
170
+ workflows.set(status.name, status);
171
+ render();
172
+ },
173
+ clearProgress() {
174
+ progress.clear();
175
+ workflows.clear();
176
+ render();
177
+ },
178
+ isRunning() {
179
+ return running;
180
+ },
181
+ waitForKey() {
182
+ return new Promise((resolve) => {
183
+ keyResolver = resolve;
184
+ });
185
+ }
186
+ };
187
+ }
188
+
189
+ export {
190
+ createDashboard
191
+ };
192
+ //# sourceMappingURL=chunk-JXFW6AIT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../cli/terminal.ts"],"sourcesContent":["/**\n * Module 17: Dashboard\n *\n * Terminal UI for displaying seed/workflow progress.\n * Provides a simple text-based dashboard that can be used\n * for monitoring CLI operations.\n */\n\n// =============================================================================\n// Type Definitions\n// =============================================================================\n\nexport interface DashboardOptions {\n title?: string\n showLogs?: boolean\n showStats?: boolean\n maxLogEntries?: number\n colors?: boolean\n stdout?: NodeJS.WriteStream\n stdin?: NodeJS.ReadStream\n}\n\nexport interface ProgressUpdate {\n seedName: string\n type?: string\n phase?: 'static' | 'generated'\n current: number\n total: number\n percentage: number\n rate?: number\n eta?: number\n status?: 'running' | 'completed' | 'failed'\n}\n\nexport interface LogEntry {\n level: 'debug' | 'info' | 'warn' | 'error'\n message: string\n data?: Record<string, unknown>\n timestamp?: number\n}\n\nexport interface DashboardStats {\n seeds?: number\n workflows?: number\n entities?: number\n errors?: number\n duration?: number\n}\n\nexport interface WorkflowStatus {\n name: string\n status: 'pending' | 'running' | 'completed' | 'failed'\n entityId?: string\n progress?: number\n error?: string\n}\n\nexport interface Dashboard {\n start(): void\n stop(): void\n updateProgress(progress: ProgressUpdate): void\n addLog(entry: LogEntry): void\n setStats(stats: DashboardStats): void\n setWorkflowStatus(status: WorkflowStatus): void\n clearProgress(): void\n isRunning(): boolean\n waitForKey(): Promise<string>\n}\n\n// =============================================================================\n// Dashboard Implementation\n// =============================================================================\n\nexport function createDashboard(options: DashboardOptions = {}): Dashboard {\n const {\n title = 'db4 dev',\n showLogs = true,\n showStats = true,\n maxLogEntries = 10,\n colors = true,\n stdout = process.stdout,\n stdin = process.stdin,\n } = options\n\n let running = false\n const progress = new Map<string, ProgressUpdate>()\n const logs: LogEntry[] = []\n let stats: DashboardStats = {}\n const workflows = new Map<string, WorkflowStatus>()\n let refreshInterval: ReturnType<typeof setInterval> | null = null\n let keyResolver: ((key: string) => void) | null = null\n\n const color = (code: string, text: string) => (colors ? `\\x1b[${code}m${text}\\x1b[0m` : text)\n const green = (text: string) => color('32', text)\n const yellow = (text: string) => color('33', text)\n const red = (text: string) => color('31', text)\n const blue = (text: string) => color('34', text)\n const dim = (text: string) => color('2', text)\n const bold = (text: string) => color('1', text)\n\n const formatProgress = (p: ProgressUpdate): string => {\n const bar = createProgressBar(p.percentage, 20)\n const status =\n p.status === 'completed' ? green('✓') : p.status === 'failed' ? red('✗') : blue('●')\n const rateStr = p.rate ? ` ${p.rate.toFixed(1)}/s` : ''\n const etaStr = p.eta ? ` ETA: ${formatDuration(p.eta)}` : ''\n return `${status} ${p.seedName.padEnd(20)} ${bar} ${p.current}/${p.total}${rateStr}${etaStr}`\n }\n\n const createProgressBar = (percentage: number, width: number): string => {\n // Clamp percentage between 0 and 100 to handle edge cases\n const clampedPercentage = Math.max(0, Math.min(100, percentage))\n const filled = Math.round((clampedPercentage / 100) * width)\n const empty = width - filled\n return `[${'█'.repeat(filled)}${dim('░'.repeat(empty))}]`\n }\n\n const formatDuration = (ms: number): string => {\n const seconds = Math.floor(ms / 1000)\n const minutes = Math.floor(seconds / 60)\n const remainingSeconds = seconds % 60\n if (minutes > 0) {\n return `${minutes}m ${remainingSeconds}s`\n }\n return `${seconds}s`\n }\n\n const formatLog = (entry: LogEntry): string => {\n const levelColors = {\n debug: dim,\n info: blue,\n warn: yellow,\n error: red,\n }\n const colorFn = levelColors[entry.level]\n const timestamp = entry.timestamp ? new Date(entry.timestamp).toLocaleTimeString() : ''\n const prefix = colorFn(`[${entry.level.toUpperCase()}]`)\n const dataStr = entry.data ? ` ${dim(JSON.stringify(entry.data))}` : ''\n return `${dim(timestamp)} ${prefix} ${entry.message}${dataStr}`\n }\n\n const render = () => {\n if (!running) return\n\n const lines: string[] = []\n\n // Title\n lines.push('')\n lines.push(bold(` ${title}`))\n lines.push(dim(' ' + '─'.repeat(40)))\n\n // Progress section\n if (progress.size > 0) {\n lines.push('')\n lines.push(bold(' Progress'))\n for (const p of progress.values()) {\n lines.push(` ${formatProgress(p)}`)\n }\n }\n\n // Workflows section\n if (workflows.size > 0) {\n lines.push('')\n lines.push(bold(' Workflows'))\n for (const w of workflows.values()) {\n const status =\n w.status === 'completed'\n ? green('✓')\n : w.status === 'failed'\n ? red('✗')\n : w.status === 'running'\n ? blue('●')\n : dim('○')\n const progressStr = w.progress !== undefined ? ` ${w.progress}%` : ''\n const entityStr = w.entityId ? dim(` (${w.entityId})`) : ''\n const errorStr = w.error ? red(` Error: ${w.error}`) : ''\n lines.push(` ${status} ${w.name}${progressStr}${entityStr}${errorStr}`)\n }\n }\n\n // Stats section\n if (showStats && Object.keys(stats).length > 0) {\n lines.push('')\n lines.push(bold(' Stats'))\n if (stats.seeds !== undefined) lines.push(` Seeds: ${stats.seeds}`)\n if (stats.workflows !== undefined) lines.push(` Workflows: ${stats.workflows}`)\n if (stats.entities !== undefined) lines.push(` Entities: ${stats.entities}`)\n if (stats.errors !== undefined && stats.errors > 0) {\n lines.push(` ${red(`Errors: ${stats.errors}`)}`)\n }\n if (stats.duration !== undefined) {\n lines.push(` Duration: ${formatDuration(stats.duration)}`)\n }\n }\n\n // Logs section\n if (showLogs && logs.length > 0) {\n lines.push('')\n lines.push(bold(' Logs'))\n const recentLogs = logs.slice(-maxLogEntries)\n for (const log of recentLogs) {\n lines.push(` ${formatLog(log)}`)\n }\n }\n\n lines.push('')\n\n // Clear and write\n stdout.write('\\x1b[2J\\x1b[H') // Clear screen and move to top\n stdout.write(lines.join('\\n'))\n }\n\n const setupKeyListener = () => {\n if (stdin.isTTY) {\n stdin.setRawMode?.(true)\n stdin.resume()\n stdin.setEncoding('utf8')\n stdin.on('data', (key: string) => {\n if (key === '\\u0003') {\n // Ctrl+C\n process.exit()\n }\n if (keyResolver) {\n keyResolver(key)\n keyResolver = null\n }\n })\n }\n }\n\n return {\n start(): void {\n if (running) return\n running = true\n render()\n refreshInterval = setInterval(render, 100)\n setupKeyListener()\n },\n\n stop(): void {\n if (!running) return\n running = false\n if (refreshInterval) {\n clearInterval(refreshInterval)\n refreshInterval = null\n }\n stdout.write('\\x1b[?25h') // Show cursor\n },\n\n updateProgress(update: ProgressUpdate): void {\n progress.set(update.seedName, update)\n if (update.status === 'completed' || update.status === 'failed') {\n // Keep completed/failed for a brief moment\n setTimeout(() => {\n const current = progress.get(update.seedName)\n if (current?.status === 'completed' || current?.status === 'failed') {\n progress.delete(update.seedName)\n }\n }, 2000)\n }\n render()\n },\n\n addLog(entry: LogEntry): void {\n logs.push({\n ...entry,\n timestamp: entry.timestamp ?? Date.now(),\n })\n while (logs.length > maxLogEntries * 2) {\n logs.shift()\n }\n render()\n },\n\n setStats(newStats: DashboardStats): void {\n stats = { ...stats, ...newStats }\n render()\n },\n\n setWorkflowStatus(status: WorkflowStatus): void {\n workflows.set(status.name, status)\n render()\n },\n\n clearProgress(): void {\n progress.clear()\n workflows.clear()\n render()\n },\n\n isRunning(): boolean {\n return running\n },\n\n waitForKey(): Promise<string> {\n return new Promise((resolve) => {\n keyResolver = resolve\n })\n },\n }\n}\n"],"mappings":"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","names":[]}