@groeponline/pi-missions 0.3.7 → 0.3.8

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/CHANGELOG.md CHANGED
@@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.3.8] - 2026-08-30
11
+
10
12
  ## [0.3.7] - 2026-08-30
11
13
 
12
14
  ## [0.3.6] - 2026-08-28
package/dist/cli/index.js CHANGED
@@ -11,6 +11,14 @@ var db = null;
11
11
  var require2 = createRequire(import.meta.url);
12
12
  var databaseDriver = null;
13
13
  var CURRENT_SCHEMA_VERSION = 1;
14
+ var DEFAULT_SQLITE_BUSY_TIMEOUT_MS = 250;
15
+ var MAX_SQLITE_BUSY_TIMEOUT_MS = 1e3;
16
+ function parseSqliteBusyTimeoutMs(value = process.env.PI_MISSIONS_SQLITE_BUSY_TIMEOUT_MS) {
17
+ if (value == null || value.trim() === "") return DEFAULT_SQLITE_BUSY_TIMEOUT_MS;
18
+ const parsed = Number(value);
19
+ if (!Number.isInteger(parsed) || parsed < 0) return DEFAULT_SQLITE_BUSY_TIMEOUT_MS;
20
+ return Math.min(parsed, MAX_SQLITE_BUSY_TIMEOUT_MS);
21
+ }
14
22
  function describeLoadError(error) {
15
23
  return error instanceof Error ? error.message : String(error);
16
24
  }
@@ -75,6 +83,8 @@ function getDatabase() {
75
83
  const candidateDb = openSqliteDatabase(dbFile);
76
84
  try {
77
85
  applyPragma(candidateDb, "journal_mode = WAL");
86
+ applyPragma(candidateDb, "synchronous = NORMAL");
87
+ applyPragma(candidateDb, `busy_timeout = ${parseSqliteBusyTimeoutMs()}`);
78
88
  applyPragma(candidateDb, "foreign_keys = ON");
79
89
  initializeSchema(candidateDb);
80
90
  runMigrations(candidateDb);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/database/index.ts","../../src/cli/index.ts"],"sourcesContent":["/**\n * Pi Missions Database Module\n * \n * SQLite database for persistent mission storage, pattern recognition,\n * and learning system.\n */\n\nimport type Database from 'better-sqlite3';\nimport { createRequire } from 'node:module';\nimport { readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { existsSync, mkdirSync } from 'node:fs';\nimport { homedir } from 'node:os';\n\n// ═══════════════════════════════════════════════════════════════════════════\n// Database singleton\n// ═══════════════════════════════════════════════════════════════════════════\n\nlet db: Database.Database | null = null;\n\nconst require = createRequire(import.meta.url);\nlet databaseDriver: 'better-sqlite3' | 'node:sqlite' | null = null;\nconst CURRENT_SCHEMA_VERSION = 1;\n\ntype DatabaseConstructor = new (filename: string) => Database.Database;\n\nfunction describeLoadError(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction openSqliteDatabase(filename: string): Database.Database {\n try {\n const BetterSqlite3 = require('better-sqlite3') as DatabaseConstructor;\n databaseDriver = 'better-sqlite3';\n return new BetterSqlite3(filename);\n } catch (betterSqliteError) {\n try {\n const { DatabaseSync } = require('node:sqlite') as { DatabaseSync: DatabaseConstructor };\n databaseDriver = 'node:sqlite';\n return new DatabaseSync(filename);\n } catch (nodeSqliteError) {\n throw new Error(\n 'Unable to initialize SQLite. Run on Node.js >=22.5.0, or install better-sqlite3 manually. ' +\n `better-sqlite3: ${describeLoadError(betterSqliteError)}; ` +\n `node:sqlite: ${describeLoadError(nodeSqliteError)}`,\n );\n }\n }\n}\n\nfunction applyPragma(database: Database.Database, pragma: string): void {\n const maybePragma = (database as unknown as { pragma?: (statement: string) => unknown }).pragma;\n if (typeof maybePragma === 'function') {\n maybePragma.call(database, pragma);\n } else {\n database.exec(`PRAGMA ${pragma}`);\n }\n}\n\nexport function getDatabaseDriver(): string | null {\n return databaseDriver;\n}\n\nfunction resolveSchemaPath(): string {\n const moduleDir = dirname(fileURLToPath(import.meta.url));\n const candidates = [\n join(moduleDir, 'schema.sql'),\n join(moduleDir, 'database', 'schema.sql'),\n join(moduleDir, '..', 'database', 'schema.sql'),\n join(process.cwd(), 'src', 'database', 'schema.sql'),\n join(process.cwd(), 'dist', 'database', 'schema.sql'),\n ];\n const schemaPath = candidates.find(existsSync);\n if (!schemaPath) {\n throw new Error(`Unable to locate database schema.sql. Searched: ${candidates.join(', ')}`);\n }\n return schemaPath;\n}\n\nexport function getDatabase(): Database.Database {\n if (!db) {\n const dbPath = getDatabasePath();\n \n // If dbPath is a directory, use it; otherwise use its parent\n let dbDir: string;\n let dbFile: string;\n \n if (dbPath === ':memory:') {\n dbDir = '';\n dbFile = dbPath;\n } else if (dbPath.endsWith('.db')) {\n dbDir = dirname(dbPath);\n dbFile = dbPath;\n } else {\n dbDir = dbPath;\n dbFile = join(dbPath, 'pi-missions.db');\n }\n \n if (dbDir && !existsSync(dbDir)) {\n mkdirSync(dbDir, { recursive: true });\n }\n \n const candidateDb = openSqliteDatabase(dbFile);\n try {\n applyPragma(candidateDb, 'journal_mode = WAL');\n applyPragma(candidateDb, 'foreign_keys = ON');\n\n // Initialize schema before publishing singleton\n initializeSchema(candidateDb);\n runMigrations(candidateDb);\n db = candidateDb;\n } catch (error) {\n candidateDb.close();\n throw error;\n }\n }\n \n return db;\n}\n\nexport function getDatabasePath(): string {\n return process.env.PI_MISSIONS_DB_PATH || join(homedir(), '.pi', 'missions', 'database');\n}\n\nfunction initializeSchema(db: Database.Database): void {\n const schemaPath = resolveSchemaPath();\n const schema = readFileSync(schemaPath, 'utf-8');\n\n try {\n db.exec(schema);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to initialize database schema from ${schemaPath}: ${message}`);\n }\n}\n\nfunction ensureSchemaVersionTable(database: Database.Database): void {\n database.exec(`\n CREATE TABLE IF NOT EXISTS schema_version (\n id INTEGER PRIMARY KEY CHECK(id = 1),\n version INTEGER NOT NULL,\n updated_at INTEGER NOT NULL DEFAULT (unixepoch() * 1000)\n );\n `);\n}\n\nfunction getSchemaVersion(database: Database.Database): number {\n ensureSchemaVersionTable(database);\n const row = database.prepare('SELECT version FROM schema_version WHERE id = 1').get() as { version?: number } | undefined;\n return row?.version ?? 0;\n}\n\nfunction setSchemaVersion(database: Database.Database, version: number): void {\n database.prepare(`\n INSERT INTO schema_version (id, version, updated_at)\n VALUES (1, ?, ?)\n ON CONFLICT(id) DO UPDATE SET\n version = excluded.version,\n updated_at = excluded.updated_at\n `).run(version, Date.now());\n}\n\nfunction baselineExistingSchema(database: Database.Database): void {\n const row = database.prepare(`\n SELECT 1 AS exists_flag\n FROM sqlite_master\n WHERE type = 'table' AND name = 'missions'\n LIMIT 1\n `).get() as { exists_flag?: number } | undefined;\n\n if (row?.exists_flag === 1) {\n setSchemaVersion(database, 1);\n }\n}\n\nfunction runMigrations(database: Database.Database): void {\n ensureSchemaVersionTable(database);\n\n const migrateBody = () => {\n let version = getSchemaVersion(database);\n\n if (version === 0) {\n baselineExistingSchema(database);\n version = getSchemaVersion(database);\n }\n\n if (version === 0) {\n setSchemaVersion(database, CURRENT_SCHEMA_VERSION);\n }\n };\n\n const maybeTransaction = (database as unknown as { transaction?: (fn: () => void) => () => void }).transaction;\n if (typeof maybeTransaction === 'function') {\n const migrate = maybeTransaction.call(database, migrateBody);\n migrate();\n return;\n }\n\n database.exec('BEGIN');\n try {\n migrateBody();\n database.exec('COMMIT');\n } catch (error) {\n database.exec('ROLLBACK');\n throw error;\n }\n}\n\nexport function closeDatabase(): void {\n if (db) {\n db.close();\n db = null;\n }\n}\n\n// ═══════════════════════════════════════════════════════════════════════════\n// Repository interfaces\n// ═══════════════════════════════════════════════════════════════════════════\n\nexport interface MissionRow {\n id: string;\n title: string;\n goal: string | null;\n status: string;\n created_at: number;\n updated_at: number;\n completed_at: number | null;\n total_tokens: number;\n total_features: number;\n features_completed: number;\n features_failed: number;\n success_rate: number;\n tags: string; // JSON\n metadata: string; // JSON\n}\n\nexport interface MilestoneRow {\n id: string;\n mission_id: string;\n title: string;\n description: string | null;\n status: string;\n sort_order: number;\n created_at: number;\n completed_at: number | null;\n}\n\nexport interface FeatureRow {\n id: string;\n milestone_id: string;\n mission_id: string;\n title: string;\n description: string | null;\n priority: number;\n status: string;\n depends_on: string; // JSON\n acceptance_criteria: string; // JSON\n sessions: string; // JSON\n tool_call_count: number;\n tokens_used: number;\n error_count: number;\n blockers: string; // JSON\n notes: string | null;\n created_at: number;\n started_at: number | null;\n completed_at: number | null;\n evidence: string | null;\n}\n\nexport interface HistoryRow {\n id: number;\n mission_id: string;\n feature_id: string | null;\n event: string;\n note: string | null;\n details: string; // JSON\n timestamp: number;\n session_id: string | null;\n}\n\nexport interface LearningRow {\n id: number;\n mission_id: string | null;\n feature_id: string | null;\n type: string;\n category: string | null;\n insight: string;\n confidence: number;\n applicable_to: string; // JSON\n context: string; // JSON\n created_at: number;\n used_count: number;\n success_count: number;\n}\n\nexport interface PatternRow {\n id: number;\n pattern_type: string;\n name: string;\n description: string;\n pattern_data: string; // JSON\n success_count: number;\n failure_count: number;\n success_rate: number;\n avg_duration_ms: number | null;\n avg_tokens: number | null;\n example_missions: string; // JSON\n tags: string; // JSON\n created_at: number;\n updated_at: number;\n}\n\nexport interface TemplateRow {\n id: string;\n name: string;\n description: string | null;\n author: string | null;\n version: string;\n content: string; // JSON\n tags: string; // JSON\n difficulty: string;\n estimated_time_hours: number | null;\n estimated_tokens: number | null;\n usage_count: number;\n rating: number;\n rating_count: number;\n created_at: number;\n updated_at: number;\n is_builtin: number;\n}\n\nexport interface SessionRow {\n id: string;\n mission_id: string | null;\n feature_id: string | null;\n started_at: number;\n ended_at: number | null;\n tokens_used: number;\n tool_calls: number;\n errors: number;\n status: string;\n}\n\nexport interface MetricRow {\n id: number;\n metric_type: string;\n metric_name: string;\n value: number;\n unit: string | null;\n tags: string; // JSON\n recorded_at: number;\n period_start: number | null;\n period_end: number | null;\n}\n\nexport interface PredictionRow {\n id: number;\n mission_id: string | null;\n feature_id: string | null;\n prediction_type: string;\n predicted_value: number;\n actual_value: number | null;\n confidence: number;\n accuracy: number | null;\n model_version: string | null;\n created_at: number;\n validated_at: number | null;\n}\n\n// ═══════════════════════════════════════════════════════════════════════════\n// Repository classes\n// ═══════════════════════════════════════════════════════════════════════════\n\nconst MISSION_UPDATABLE_COLUMNS = new Set([\n 'title', 'goal', 'status', 'updated_at', 'completed_at',\n 'total_tokens', 'total_features', 'features_completed',\n 'features_failed', 'success_rate', 'tags', 'metadata'\n]);\n\nexport class MissionRepository {\n private db: Database.Database;\n \n constructor(db: Database.Database) {\n this.db = db;\n }\n \n create(mission: Omit<MissionRow, 'created_at' | 'updated_at'>): MissionRow {\n const now = Date.now();\n const stmt = this.db.prepare(`\n INSERT INTO missions (id, title, goal, status, created_at, updated_at, completed_at, \n total_tokens, total_features, features_completed, features_failed, \n success_rate, tags, metadata)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n \n stmt.run(\n mission.id, mission.title, mission.goal, mission.status,\n now, now, mission.completed_at,\n mission.total_tokens, mission.total_features, mission.features_completed,\n mission.features_failed, mission.success_rate, mission.tags, mission.metadata\n );\n \n return this.findById(mission.id)!;\n }\n \n findById(id: string): MissionRow | undefined {\n return this.db.prepare('SELECT * FROM missions WHERE id = ?').get(id) as MissionRow | undefined;\n }\n \n findAll(limit = 100, offset = 0): MissionRow[] {\n return this.db.prepare('SELECT * FROM missions ORDER BY updated_at DESC LIMIT ? OFFSET ?')\n .all(limit, offset) as MissionRow[];\n }\n \n findByStatus(status: string): MissionRow[] {\n return this.db.prepare('SELECT * FROM missions WHERE status = ? ORDER BY updated_at DESC')\n .all(status) as MissionRow[];\n }\n \n update(id: string, updates: Partial<MissionRow>): MissionRow | undefined {\n const fields = Object.keys(updates).filter(k => MISSION_UPDATABLE_COLUMNS.has(k));\n if (fields.length === 0) return this.findById(id);\n \n const setClause = fields.map(f => `${f} = ?`).join(', ');\n const values = fields.map(f => updates[f as keyof MissionRow]);\n \n this.db.prepare(`UPDATE missions SET ${setClause}, updated_at = ? WHERE id = ?`)\n .run(...values, Date.now(), id);\n \n return this.findById(id);\n }\n \n delete(id: string): boolean {\n const result = this.db.prepare('DELETE FROM missions WHERE id = ?').run(id);\n return result.changes > 0;\n }\n \n count(): number {\n const row = this.db.prepare('SELECT COUNT(*) as count FROM missions').get() as { count: number } | undefined;\n return row?.count ?? 0;\n }\n}\n\nconst FEATURE_UPDATABLE_COLUMNS = new Set([\n 'milestone_id', 'title', 'description', 'priority', 'status',\n 'depends_on', 'acceptance_criteria', 'sessions', 'tool_call_count',\n 'tokens_used', 'error_count', 'blockers', 'notes', 'started_at',\n 'completed_at', 'evidence'\n]);\n\nexport class FeatureRepository {\n private db: Database.Database;\n \n constructor(db: Database.Database) {\n this.db = db;\n }\n \n create(feature: Omit<FeatureRow, 'created_at'>): FeatureRow {\n const stmt = this.db.prepare(`\n INSERT INTO features (id, milestone_id, mission_id, title, description, priority, status,\n depends_on, acceptance_criteria, sessions, tool_call_count, tokens_used,\n error_count, blockers, notes, created_at, started_at, completed_at, evidence)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n \n stmt.run(\n feature.id, feature.milestone_id, feature.mission_id, feature.title, feature.description,\n feature.priority, feature.status, feature.depends_on, feature.acceptance_criteria,\n feature.sessions, feature.tool_call_count, feature.tokens_used, feature.error_count,\n feature.blockers, feature.notes, Date.now(), feature.started_at, feature.completed_at,\n feature.evidence\n );\n \n return this.findById(feature.id, feature.mission_id)!;\n }\n \n findById(id: string, missionId: string): FeatureRow | undefined {\n return this.db.prepare('SELECT * FROM features WHERE id = ? AND mission_id = ?')\n .get(id, missionId) as FeatureRow | undefined;\n }\n \n findByMission(missionId: string): FeatureRow[] {\n return this.db.prepare('SELECT * FROM features WHERE mission_id = ? ORDER BY created_at')\n .all(missionId) as FeatureRow[];\n }\n \n findByStatus(missionId: string, status: string): FeatureRow[] {\n return this.db.prepare('SELECT * FROM features WHERE mission_id = ? AND status = ?')\n .all(missionId, status) as FeatureRow[];\n }\n \n update(id: string, missionId: string, updates: Partial<FeatureRow>): FeatureRow | undefined {\n const fields = Object.keys(updates).filter(k => FEATURE_UPDATABLE_COLUMNS.has(k));\n if (fields.length === 0) return this.findById(id, missionId);\n \n const setClause = fields.map(f => `${f} = ?`).join(', ');\n const values = fields.map(f => updates[f as keyof FeatureRow]);\n \n this.db.prepare(`UPDATE features SET ${setClause} WHERE id = ? AND mission_id = ?`)\n .run(...values, id, missionId);\n \n return this.findById(id, missionId);\n }\n \n delete(id: string, missionId: string): boolean {\n const result = this.db.prepare('DELETE FROM features WHERE id = ? AND mission_id = ?')\n .run(id, missionId);\n return result.changes > 0;\n }\n}\n\nexport class HistoryRepository {\n private db: Database.Database;\n \n constructor(db: Database.Database) {\n this.db = db;\n }\n \n append(entry: Omit<HistoryRow, 'id' | 'timestamp'>): HistoryRow {\n const stmt = this.db.prepare(`\n INSERT INTO history (mission_id, feature_id, event, note, details, timestamp, session_id)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n `);\n \n const result = stmt.run(\n entry.mission_id, entry.feature_id, entry.event, entry.note,\n entry.details, Date.now(), entry.session_id\n );\n \n return this.db.prepare('SELECT * FROM history WHERE id = ?')\n .get(result.lastInsertRowid) as HistoryRow;\n }\n \n findByMission(missionId: string, limit = 100): HistoryRow[] {\n return this.db.prepare('SELECT * FROM history WHERE mission_id = ? ORDER BY timestamp DESC LIMIT ?')\n .all(missionId, limit) as HistoryRow[];\n }\n \n findByFeature(featureId: string, limit = 50): HistoryRow[] {\n return this.db.prepare('SELECT * FROM history WHERE feature_id = ? ORDER BY timestamp DESC LIMIT ?')\n .all(featureId, limit) as HistoryRow[];\n }\n \n findByEvent(event: string, limit = 50): HistoryRow[] {\n return this.db.prepare('SELECT * FROM history WHERE event = ? ORDER BY timestamp DESC LIMIT ?')\n .all(event, limit) as HistoryRow[];\n }\n \n search(query: string, limit = 50): HistoryRow[] {\n return this.db.prepare(`\n SELECT * FROM history \n WHERE note LIKE ? OR event LIKE ? \n ORDER BY timestamp DESC LIMIT ?\n `).all(`%${query}%`, `%${query}%`, limit) as HistoryRow[];\n }\n}\n\nexport class LearningRepository {\n private db: Database.Database;\n \n constructor(db: Database.Database) {\n this.db = db;\n }\n \n create(learning: Omit<LearningRow, 'id' | 'created_at' | 'used_count' | 'success_count'>): LearningRow {\n const stmt = this.db.prepare(`\n INSERT INTO learnings (mission_id, feature_id, type, category, insight, confidence, applicable_to, context)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)\n `);\n \n const result = stmt.run(\n learning.mission_id, learning.feature_id, learning.type, learning.category,\n learning.insight, learning.confidence, learning.applicable_to, learning.context\n );\n \n return this.db.prepare('SELECT * FROM learnings WHERE id = ?')\n .get(result.lastInsertRowid) as LearningRow;\n }\n \n findByType(type: string, limit = 50): LearningRow[] {\n return this.db.prepare('SELECT * FROM learnings WHERE type = ? ORDER BY confidence DESC LIMIT ?')\n .all(type, limit) as LearningRow[];\n }\n \n findByCategory(category: string, limit = 50): LearningRow[] {\n return this.db.prepare('SELECT * FROM learnings WHERE category = ? ORDER BY confidence DESC LIMIT ?')\n .all(category, limit) as LearningRow[];\n }\n \n findRelevant(tags: string[], limit = 10): LearningRow[] {\n if (tags.length === 0) return [];\n\n const placeholders = tags.map(() => '?').join(',');\n return this.db.prepare(`\n SELECT * FROM learnings \n WHERE json_valid(learnings.applicable_to)\n AND EXISTS (\n SELECT 1\n FROM json_each(learnings.applicable_to)\n WHERE json_each.value IN (${placeholders})\n )\n ORDER BY confidence DESC, used_count DESC\n LIMIT ?\n `).all(...tags, limit) as LearningRow[];\n }\n \n recordUsage(id: string, success: boolean): void {\n if (success) {\n this.db.prepare('UPDATE learnings SET used_count = used_count + 1, success_count = success_count + 1 WHERE id = ?')\n .run(id);\n } else {\n this.db.prepare('UPDATE learnings SET used_count = used_count + 1 WHERE id = ?')\n .run(id);\n }\n }\n}\n\nexport class PatternRepository {\n private db: Database.Database;\n \n constructor(db: Database.Database) {\n this.db = db;\n }\n \n create(pattern: Omit<PatternRow, 'id' | 'created_at' | 'updated_at'>): PatternRow {\n const stmt = this.db.prepare(`\n INSERT INTO patterns (pattern_type, name, description, pattern_data, success_count, failure_count,\n success_rate, avg_duration_ms, avg_tokens, example_missions, tags)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n \n const result = stmt.run(\n pattern.pattern_type, pattern.name, pattern.description, pattern.pattern_data,\n pattern.success_count, pattern.failure_count, pattern.success_rate,\n pattern.avg_duration_ms, pattern.avg_tokens, pattern.example_missions, pattern.tags\n );\n \n return this.db.prepare('SELECT * FROM patterns WHERE id = ?')\n .get(result.lastInsertRowid) as PatternRow;\n }\n \n findByType(type: string, limit = 20): PatternRow[] {\n return this.db.prepare('SELECT * FROM patterns WHERE pattern_type = ? ORDER BY success_rate DESC LIMIT ?')\n .all(type, limit) as PatternRow[];\n }\n \n findSuccessful(limit = 20): PatternRow[] {\n return this.db.prepare('SELECT * FROM patterns WHERE success_rate > 0.7 ORDER BY success_rate DESC LIMIT ?')\n .all(limit) as PatternRow[];\n }\n \n recordOutcome(id: string, success: boolean): void {\n if (success) {\n this.db.prepare(`\n UPDATE patterns \n SET success_count = success_count + 1,\n success_rate = CAST(success_count + 1 AS REAL) / (success_count + failure_count + 1),\n updated_at = ?\n WHERE id = ?\n `).run(Date.now(), id);\n } else {\n this.db.prepare(`\n UPDATE patterns \n SET failure_count = failure_count + 1,\n success_rate = CAST(success_count AS REAL) / (success_count + failure_count + 1),\n updated_at = ?\n WHERE id = ?\n `).run(Date.now(), id);\n }\n }\n}\n\nexport class TemplateRepository {\n private db: Database.Database;\n \n constructor(db: Database.Database) {\n this.db = db;\n }\n \n findById(id: string): TemplateRow | undefined {\n return this.db.prepare('SELECT * FROM templates WHERE id = ?').get(id) as TemplateRow | undefined;\n }\n \n findAll(limit = 50): TemplateRow[] {\n return this.db.prepare('SELECT * FROM templates ORDER BY rating DESC, usage_count DESC LIMIT ?')\n .all(limit) as TemplateRow[];\n }\n \n findByTags(tags: string[]): TemplateRow[] {\n if (tags.length === 0) return [];\n\n const placeholders = tags.map(() => '?').join(',');\n return this.db.prepare(`\n SELECT * FROM templates \n WHERE json_valid(templates.tags)\n AND EXISTS (\n SELECT 1\n FROM json_each(templates.tags)\n WHERE json_each.value IN (${placeholders})\n )\n ORDER BY rating DESC\n `).all(...tags) as TemplateRow[];\n }\n \n create(template: Omit<TemplateRow, 'created_at' | 'updated_at' | 'usage_count' | 'rating' | 'rating_count'>): TemplateRow {\n const now = Date.now();\n const stmt = this.db.prepare(`\n INSERT INTO templates (id, name, description, author, version, content, tags, difficulty,\n estimated_time_hours, estimated_tokens, usage_count, rating, rating_count,\n created_at, updated_at, is_builtin)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0, 0, 0, ?, ?, ?)\n `);\n \n stmt.run(\n template.id, template.name, template.description, template.author, template.version,\n template.content, template.tags, template.difficulty, template.estimated_time_hours,\n template.estimated_tokens, now, now, template.is_builtin\n );\n \n return this.findById(template.id)!;\n }\n \n incrementUsage(id: string): void {\n this.db.prepare('UPDATE templates SET usage_count = usage_count + 1, updated_at = ? WHERE id = ?')\n .run(Date.now(), id);\n }\n \n rate(id: string, rating: number): void {\n this.db.prepare(`\n UPDATE templates \n SET rating = (rating * rating_count + ?) / (rating_count + 1),\n rating_count = rating_count + 1,\n updated_at = ?\n WHERE id = ?\n `).run(rating, Date.now(), id);\n }\n}\n\nexport class MetricRepository {\n private db: Database.Database;\n \n constructor(db: Database.Database) {\n this.db = db;\n }\n \n record(metric: Omit<MetricRow, 'id' | 'recorded_at'>): MetricRow {\n const stmt = this.db.prepare(`\n INSERT INTO metrics (metric_type, metric_name, value, unit, tags, recorded_at, period_start, period_end)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)\n `);\n \n const result = stmt.run(\n metric.metric_type, metric.metric_name, metric.value, metric.unit,\n metric.tags, Date.now(), metric.period_start, metric.period_end\n );\n \n return this.db.prepare('SELECT * FROM metrics WHERE id = ?')\n .get(result.lastInsertRowid) as MetricRow;\n }\n \n findByType(type: string, name?: string, limit = 100): MetricRow[] {\n if (name) {\n return this.db.prepare('SELECT * FROM metrics WHERE metric_type = ? AND metric_name = ? ORDER BY recorded_at DESC LIMIT ?')\n .all(type, name, limit) as MetricRow[];\n }\n return this.db.prepare('SELECT * FROM metrics WHERE metric_type = ? ORDER BY recorded_at DESC LIMIT ?')\n .all(type, limit) as MetricRow[];\n }\n \n getAggregated(type: string, name: string, periodMs: number): { avg: number; min: number; max: number; count: number } {\n const since = Date.now() - periodMs;\n const row = this.db.prepare(`\n SELECT \n AVG(value) as avg,\n MIN(value) as min,\n MAX(value) as max,\n COUNT(*) as count\n FROM metrics \n WHERE metric_type = ? AND metric_name = ? AND recorded_at > ?\n `).get(type, name, since) as { avg?: number; min?: number; max?: number; count?: number } | undefined;\n \n return {\n avg: row?.avg ?? 0,\n min: row?.min ?? 0,\n max: row?.max ?? 0,\n count: row?.count ?? 0,\n };\n }\n}\n\nexport class PredictionRepository {\n private db: Database.Database;\n \n constructor(db: Database.Database) {\n this.db = db;\n }\n \n create(prediction: Omit<PredictionRow, 'id' | 'created_at' | 'validated_at' | 'accuracy' | 'actual_value'> & { actual_value?: number | null }): PredictionRow {\n const stmt = this.db.prepare(`\n INSERT INTO predictions (mission_id, feature_id, prediction_type, predicted_value, actual_value, confidence, model_version)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n `);\n \n const result = stmt.run(\n prediction.mission_id, prediction.feature_id, prediction.prediction_type,\n prediction.predicted_value, prediction.actual_value ?? null, prediction.confidence, prediction.model_version\n );\n \n return this.db.prepare('SELECT * FROM predictions WHERE id = ?')\n .get(result.lastInsertRowid) as PredictionRow;\n }\n \n validate(id: string, actualValue: number): void {\n const prediction = this.db.prepare('SELECT * FROM predictions WHERE id = ?').get(id) as PredictionRow;\n if (!prediction) return;\n \n const accuracy = 1 - Math.abs(prediction.predicted_value - actualValue) / Math.max(prediction.predicted_value, actualValue);\n \n this.db.prepare(`\n UPDATE predictions \n SET actual_value = ?, accuracy = ?, validated_at = ?\n WHERE id = ?\n `).run(actualValue, accuracy, Date.now(), id);\n }\n \n findByType(type: string, limit = 50): PredictionRow[] {\n return this.db.prepare('SELECT * FROM predictions WHERE prediction_type = ? ORDER BY created_at DESC LIMIT ?')\n .all(type, limit) as PredictionRow[];\n }\n \n getAccuracy(type: string): number {\n const row = this.db.prepare(`\n SELECT AVG(accuracy) as avg_accuracy \n FROM predictions \n WHERE prediction_type = ? AND accuracy IS NOT NULL\n `).get(type) as { avg_accuracy?: number } | undefined;\n \n return row?.avg_accuracy ?? 0;\n }\n}\n\n// ═══════════════════════════════════════════════════════════════════════════\n// Convenience function to get all repositories\n// ═══════════════════════════════════════════════════════════════════════════\n\nexport function getRepositories() {\n const db = getDatabase();\n return {\n missions: new MissionRepository(db),\n features: new FeatureRepository(db),\n history: new HistoryRepository(db),\n learnings: new LearningRepository(db),\n patterns: new PatternRepository(db),\n templates: new TemplateRepository(db),\n metrics: new MetricRepository(db),\n predictions: new PredictionRepository(db),\n };\n}\n","#!/usr/bin/env node\nimport { getRepositories } from '../database/index.js';\nimport { pathToFileURL } from 'node:url';\n\nexport interface CLICommand {\n name: string;\n description: string;\n execute(args: string[]): Promise<string>;\n}\n\nexport class CLI {\n private commands = new Map<string, CLICommand>();\n \n constructor() {\n this.registerDefaultCommands();\n }\n \n registerCommand(cmd: CLICommand) {\n this.commands.set(cmd.name, cmd);\n }\n \n async execute(args: string[]): Promise<string> {\n const [cmd, ...rest] = args;\n if (!cmd || cmd === '--help' || cmd === '-h') return this.showHelp();\n const command = this.commands.get(cmd);\n if (!command) return `Unknown command: ${cmd}. Use --help for available commands.`;\n return command.execute(rest);\n }\n \n showHelp(): string {\n const lines = ['Pi Missions CLI', 'Usage: pi-missions <command> [options]', '', 'Commands:'];\n for (const [name, cmd] of this.commands) lines.push(` ${name.padEnd(15)} ${cmd.description}`);\n return lines.join('\\n');\n }\n \n private registerDefaultCommands() {\n this.registerCommand({ name: 'list', description: 'List all missions', execute: async () => {\n const repos = getRepositories();\n const missions = repos.missions.findAll(50);\n if (!missions.length) return 'No missions found.';\n return missions.map(m => `${m.id} [${m.status}] ${m.title}`).join('\\n');\n }});\n \n this.registerCommand({ name: 'status', description: 'Show mission status', execute: async (args) => {\n const repos = getRepositories();\n const id = args[0];\n if (!id) return 'Usage: pi-missions status <mission-id>';\n const m = repos.missions.findById(id);\n if (!m) return `Mission not found: ${id}`;\n const features = repos.features.findByMission(id);\n const done = features.filter(f => f.status === 'done').length;\n return `${m.title}\\nStatus: ${m.status}\\nProgress: ${done}/${features.length}\\nTokens: ${m.total_tokens}`;\n }});\n \n this.registerCommand({ name: 'analytics', description: 'Show analytics', execute: async () => {\n const repos = getRepositories();\n const missions = repos.missions.findAll(100);\n const total = missions.length;\n const completed = missions.filter(m => m.status === 'complete').length;\n const active = missions.filter(m => m.status === 'active').length;\n return `📊 Analytics\\nTotal: ${total}\\nActive: ${active}\\nCompleted: ${completed}\\nSuccess Rate: ${total > 0 ? Math.round(completed/total*100) : 0}%`;\n }});\n \n this.registerCommand({ name: 'templates', description: 'List templates', execute: async () => {\n const repos = getRepositories();\n const templates = repos.templates.findAll();\n return templates.map(t => `${t.id.padEnd(15)} ${t.name} - ${t.description || ''}`).join('\\n');\n }});\n \n this.registerCommand({ name: 'history', description: 'Show mission history', execute: async (args) => {\n const repos = getRepositories();\n const id = args[0];\n if (!id) return 'Usage: pi-missions history <mission-id>';\n const history = repos.history.findByMission(id, 20);\n if (!history.length) return 'No history entries.';\n return history.map(h => `${new Date(h.timestamp).toISOString()} ${h.event} ${h.note || ''}`).join('\\n');\n }});\n \n this.registerCommand({ name: 'doctor', description: 'Run diagnostics', execute: async () => {\n const repos = getRepositories();\n const missions = repos.missions.count();\n const templates = repos.templates.findAll().length;\n return `✅ Database: OK\\n📊 Missions: ${missions}\\n📋 Templates: ${templates}`;\n }});\n }\n}\n\nexport function createCLI(): CLI {\n return new CLI();\n}\n\nfunction isDirectExecution(): boolean {\n const entry = process.argv[1];\n return Boolean(entry && import.meta.url === pathToFileURL(entry).href);\n}\n\nif (isDirectExecution()) {\n createCLI().execute(process.argv.slice(2))\n .then((output) => {\n if (output) console.log(output);\n })\n .catch((error: unknown) => {\n console.error(error instanceof Error ? error.message : String(error));\n process.exitCode = 1;\n });\n}\n"],"mappings":"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","names":["require","db","db"]}
1
+ {"version":3,"sources":["../../src/database/index.ts","../../src/cli/index.ts"],"sourcesContent":["/**\n * Pi Missions Database Module\n * \n * SQLite database for persistent mission storage, pattern recognition,\n * and learning system.\n */\n\nimport type Database from 'better-sqlite3';\nimport { createRequire } from 'node:module';\nimport { readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { existsSync, mkdirSync } from 'node:fs';\nimport { homedir } from 'node:os';\n\n// ═══════════════════════════════════════════════════════════════════════════\n// Database singleton\n// ═══════════════════════════════════════════════════════════════════════════\n\nlet db: Database.Database | null = null;\n\nconst require = createRequire(import.meta.url);\nlet databaseDriver: 'better-sqlite3' | 'node:sqlite' | null = null;\nconst CURRENT_SCHEMA_VERSION = 1;\nconst DEFAULT_SQLITE_BUSY_TIMEOUT_MS = 250;\nconst MAX_SQLITE_BUSY_TIMEOUT_MS = 1000;\n\n/** Parse the external busy-timeout setting into a bounded main-thread stall budget. */\nexport function parseSqliteBusyTimeoutMs(value = process.env.PI_MISSIONS_SQLITE_BUSY_TIMEOUT_MS): number {\n if (value == null || value.trim() === '') return DEFAULT_SQLITE_BUSY_TIMEOUT_MS;\n const parsed = Number(value);\n if (!Number.isInteger(parsed) || parsed < 0) return DEFAULT_SQLITE_BUSY_TIMEOUT_MS;\n return Math.min(parsed, MAX_SQLITE_BUSY_TIMEOUT_MS);\n}\n\ntype DatabaseConstructor = new (filename: string) => Database.Database;\n\nfunction describeLoadError(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction openSqliteDatabase(filename: string): Database.Database {\n try {\n const BetterSqlite3 = require('better-sqlite3') as DatabaseConstructor;\n databaseDriver = 'better-sqlite3';\n return new BetterSqlite3(filename);\n } catch (betterSqliteError) {\n try {\n const { DatabaseSync } = require('node:sqlite') as { DatabaseSync: DatabaseConstructor };\n databaseDriver = 'node:sqlite';\n return new DatabaseSync(filename);\n } catch (nodeSqliteError) {\n throw new Error(\n 'Unable to initialize SQLite. Run on Node.js >=22.5.0, or install better-sqlite3 manually. ' +\n `better-sqlite3: ${describeLoadError(betterSqliteError)}; ` +\n `node:sqlite: ${describeLoadError(nodeSqliteError)}`,\n );\n }\n }\n}\n\nfunction applyPragma(database: Database.Database, pragma: string): void {\n const maybePragma = (database as unknown as { pragma?: (statement: string) => unknown }).pragma;\n if (typeof maybePragma === 'function') {\n maybePragma.call(database, pragma);\n } else {\n database.exec(`PRAGMA ${pragma}`);\n }\n}\n\nexport function getDatabaseDriver(): string | null {\n return databaseDriver;\n}\n\nfunction resolveSchemaPath(): string {\n const moduleDir = dirname(fileURLToPath(import.meta.url));\n const candidates = [\n join(moduleDir, 'schema.sql'),\n join(moduleDir, 'database', 'schema.sql'),\n join(moduleDir, '..', 'database', 'schema.sql'),\n join(process.cwd(), 'src', 'database', 'schema.sql'),\n join(process.cwd(), 'dist', 'database', 'schema.sql'),\n ];\n const schemaPath = candidates.find(existsSync);\n if (!schemaPath) {\n throw new Error(`Unable to locate database schema.sql. Searched: ${candidates.join(', ')}`);\n }\n return schemaPath;\n}\n\nexport function getDatabase(): Database.Database {\n if (!db) {\n const dbPath = getDatabasePath();\n \n // If dbPath is a directory, use it; otherwise use its parent\n let dbDir: string;\n let dbFile: string;\n \n if (dbPath === ':memory:') {\n dbDir = '';\n dbFile = dbPath;\n } else if (dbPath.endsWith('.db')) {\n dbDir = dirname(dbPath);\n dbFile = dbPath;\n } else {\n dbDir = dbPath;\n dbFile = join(dbPath, 'pi-missions.db');\n }\n \n if (dbDir && !existsSync(dbDir)) {\n mkdirSync(dbDir, { recursive: true });\n }\n \n const candidateDb = openSqliteDatabase(dbFile);\n try {\n applyPragma(candidateDb, 'journal_mode = WAL');\n applyPragma(candidateDb, 'synchronous = NORMAL');\n applyPragma(candidateDb, `busy_timeout = ${parseSqliteBusyTimeoutMs()}`);\n applyPragma(candidateDb, 'foreign_keys = ON');\n\n // Initialize schema before publishing singleton\n initializeSchema(candidateDb);\n runMigrations(candidateDb);\n db = candidateDb;\n } catch (error) {\n candidateDb.close();\n throw error;\n }\n }\n \n return db;\n}\n\nexport function getDatabasePath(): string {\n return process.env.PI_MISSIONS_DB_PATH || join(homedir(), '.pi', 'missions', 'database');\n}\n\nfunction initializeSchema(db: Database.Database): void {\n const schemaPath = resolveSchemaPath();\n const schema = readFileSync(schemaPath, 'utf-8');\n\n try {\n db.exec(schema);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to initialize database schema from ${schemaPath}: ${message}`);\n }\n}\n\nfunction ensureSchemaVersionTable(database: Database.Database): void {\n database.exec(`\n CREATE TABLE IF NOT EXISTS schema_version (\n id INTEGER PRIMARY KEY CHECK(id = 1),\n version INTEGER NOT NULL,\n updated_at INTEGER NOT NULL DEFAULT (unixepoch() * 1000)\n );\n `);\n}\n\nfunction getSchemaVersion(database: Database.Database): number {\n ensureSchemaVersionTable(database);\n const row = database.prepare('SELECT version FROM schema_version WHERE id = 1').get() as { version?: number } | undefined;\n return row?.version ?? 0;\n}\n\nfunction setSchemaVersion(database: Database.Database, version: number): void {\n database.prepare(`\n INSERT INTO schema_version (id, version, updated_at)\n VALUES (1, ?, ?)\n ON CONFLICT(id) DO UPDATE SET\n version = excluded.version,\n updated_at = excluded.updated_at\n `).run(version, Date.now());\n}\n\nfunction baselineExistingSchema(database: Database.Database): void {\n const row = database.prepare(`\n SELECT 1 AS exists_flag\n FROM sqlite_master\n WHERE type = 'table' AND name = 'missions'\n LIMIT 1\n `).get() as { exists_flag?: number } | undefined;\n\n if (row?.exists_flag === 1) {\n setSchemaVersion(database, 1);\n }\n}\n\nfunction runMigrations(database: Database.Database): void {\n ensureSchemaVersionTable(database);\n\n const migrateBody = () => {\n let version = getSchemaVersion(database);\n\n if (version === 0) {\n baselineExistingSchema(database);\n version = getSchemaVersion(database);\n }\n\n if (version === 0) {\n setSchemaVersion(database, CURRENT_SCHEMA_VERSION);\n }\n };\n\n const maybeTransaction = (database as unknown as { transaction?: (fn: () => void) => () => void }).transaction;\n if (typeof maybeTransaction === 'function') {\n const migrate = maybeTransaction.call(database, migrateBody);\n migrate();\n return;\n }\n\n database.exec('BEGIN');\n try {\n migrateBody();\n database.exec('COMMIT');\n } catch (error) {\n database.exec('ROLLBACK');\n throw error;\n }\n}\n\nexport function closeDatabase(): void {\n if (db) {\n db.close();\n db = null;\n }\n}\n\n// ═══════════════════════════════════════════════════════════════════════════\n// Repository interfaces\n// ═══════════════════════════════════════════════════════════════════════════\n\nexport interface MissionRow {\n id: string;\n title: string;\n goal: string | null;\n status: string;\n created_at: number;\n updated_at: number;\n completed_at: number | null;\n total_tokens: number;\n total_features: number;\n features_completed: number;\n features_failed: number;\n success_rate: number;\n tags: string; // JSON\n metadata: string; // JSON\n}\n\nexport interface MilestoneRow {\n id: string;\n mission_id: string;\n title: string;\n description: string | null;\n status: string;\n sort_order: number;\n created_at: number;\n completed_at: number | null;\n}\n\nexport interface FeatureRow {\n id: string;\n milestone_id: string;\n mission_id: string;\n title: string;\n description: string | null;\n priority: number;\n status: string;\n depends_on: string; // JSON\n acceptance_criteria: string; // JSON\n sessions: string; // JSON\n tool_call_count: number;\n tokens_used: number;\n error_count: number;\n blockers: string; // JSON\n notes: string | null;\n created_at: number;\n started_at: number | null;\n completed_at: number | null;\n evidence: string | null;\n}\n\nexport interface HistoryRow {\n id: number;\n mission_id: string;\n feature_id: string | null;\n event: string;\n note: string | null;\n details: string; // JSON\n timestamp: number;\n session_id: string | null;\n}\n\nexport interface LearningRow {\n id: number;\n mission_id: string | null;\n feature_id: string | null;\n type: string;\n category: string | null;\n insight: string;\n confidence: number;\n applicable_to: string; // JSON\n context: string; // JSON\n created_at: number;\n used_count: number;\n success_count: number;\n}\n\nexport interface PatternRow {\n id: number;\n pattern_type: string;\n name: string;\n description: string;\n pattern_data: string; // JSON\n success_count: number;\n failure_count: number;\n success_rate: number;\n avg_duration_ms: number | null;\n avg_tokens: number | null;\n example_missions: string; // JSON\n tags: string; // JSON\n created_at: number;\n updated_at: number;\n}\n\nexport interface TemplateRow {\n id: string;\n name: string;\n description: string | null;\n author: string | null;\n version: string;\n content: string; // JSON\n tags: string; // JSON\n difficulty: string;\n estimated_time_hours: number | null;\n estimated_tokens: number | null;\n usage_count: number;\n rating: number;\n rating_count: number;\n created_at: number;\n updated_at: number;\n is_builtin: number;\n}\n\nexport interface SessionRow {\n id: string;\n mission_id: string | null;\n feature_id: string | null;\n started_at: number;\n ended_at: number | null;\n tokens_used: number;\n tool_calls: number;\n errors: number;\n status: string;\n}\n\nexport interface MetricRow {\n id: number;\n metric_type: string;\n metric_name: string;\n value: number;\n unit: string | null;\n tags: string; // JSON\n recorded_at: number;\n period_start: number | null;\n period_end: number | null;\n}\n\nexport interface PredictionRow {\n id: number;\n mission_id: string | null;\n feature_id: string | null;\n prediction_type: string;\n predicted_value: number;\n actual_value: number | null;\n confidence: number;\n accuracy: number | null;\n model_version: string | null;\n created_at: number;\n validated_at: number | null;\n}\n\n// ═══════════════════════════════════════════════════════════════════════════\n// Repository classes\n// ═══════════════════════════════════════════════════════════════════════════\n\nconst MISSION_UPDATABLE_COLUMNS = new Set([\n 'title', 'goal', 'status', 'updated_at', 'completed_at',\n 'total_tokens', 'total_features', 'features_completed',\n 'features_failed', 'success_rate', 'tags', 'metadata'\n]);\n\nexport class MissionRepository {\n private db: Database.Database;\n \n constructor(db: Database.Database) {\n this.db = db;\n }\n \n create(mission: Omit<MissionRow, 'created_at' | 'updated_at'>): MissionRow {\n const now = Date.now();\n const stmt = this.db.prepare(`\n INSERT INTO missions (id, title, goal, status, created_at, updated_at, completed_at, \n total_tokens, total_features, features_completed, features_failed, \n success_rate, tags, metadata)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n \n stmt.run(\n mission.id, mission.title, mission.goal, mission.status,\n now, now, mission.completed_at,\n mission.total_tokens, mission.total_features, mission.features_completed,\n mission.features_failed, mission.success_rate, mission.tags, mission.metadata\n );\n \n return this.findById(mission.id)!;\n }\n \n findById(id: string): MissionRow | undefined {\n return this.db.prepare('SELECT * FROM missions WHERE id = ?').get(id) as MissionRow | undefined;\n }\n \n findAll(limit = 100, offset = 0): MissionRow[] {\n return this.db.prepare('SELECT * FROM missions ORDER BY updated_at DESC LIMIT ? OFFSET ?')\n .all(limit, offset) as MissionRow[];\n }\n \n findByStatus(status: string): MissionRow[] {\n return this.db.prepare('SELECT * FROM missions WHERE status = ? ORDER BY updated_at DESC')\n .all(status) as MissionRow[];\n }\n \n update(id: string, updates: Partial<MissionRow>): MissionRow | undefined {\n const fields = Object.keys(updates).filter(k => MISSION_UPDATABLE_COLUMNS.has(k));\n if (fields.length === 0) return this.findById(id);\n \n const setClause = fields.map(f => `${f} = ?`).join(', ');\n const values = fields.map(f => updates[f as keyof MissionRow]);\n \n this.db.prepare(`UPDATE missions SET ${setClause}, updated_at = ? WHERE id = ?`)\n .run(...values, Date.now(), id);\n \n return this.findById(id);\n }\n \n delete(id: string): boolean {\n const result = this.db.prepare('DELETE FROM missions WHERE id = ?').run(id);\n return result.changes > 0;\n }\n \n count(): number {\n const row = this.db.prepare('SELECT COUNT(*) as count FROM missions').get() as { count: number } | undefined;\n return row?.count ?? 0;\n }\n}\n\nconst FEATURE_UPDATABLE_COLUMNS = new Set([\n 'milestone_id', 'title', 'description', 'priority', 'status',\n 'depends_on', 'acceptance_criteria', 'sessions', 'tool_call_count',\n 'tokens_used', 'error_count', 'blockers', 'notes', 'started_at',\n 'completed_at', 'evidence'\n]);\n\nexport class FeatureRepository {\n private db: Database.Database;\n \n constructor(db: Database.Database) {\n this.db = db;\n }\n \n create(feature: Omit<FeatureRow, 'created_at'>): FeatureRow {\n const stmt = this.db.prepare(`\n INSERT INTO features (id, milestone_id, mission_id, title, description, priority, status,\n depends_on, acceptance_criteria, sessions, tool_call_count, tokens_used,\n error_count, blockers, notes, created_at, started_at, completed_at, evidence)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n \n stmt.run(\n feature.id, feature.milestone_id, feature.mission_id, feature.title, feature.description,\n feature.priority, feature.status, feature.depends_on, feature.acceptance_criteria,\n feature.sessions, feature.tool_call_count, feature.tokens_used, feature.error_count,\n feature.blockers, feature.notes, Date.now(), feature.started_at, feature.completed_at,\n feature.evidence\n );\n \n return this.findById(feature.id, feature.mission_id)!;\n }\n \n findById(id: string, missionId: string): FeatureRow | undefined {\n return this.db.prepare('SELECT * FROM features WHERE id = ? AND mission_id = ?')\n .get(id, missionId) as FeatureRow | undefined;\n }\n \n findByMission(missionId: string): FeatureRow[] {\n return this.db.prepare('SELECT * FROM features WHERE mission_id = ? ORDER BY created_at')\n .all(missionId) as FeatureRow[];\n }\n \n findByStatus(missionId: string, status: string): FeatureRow[] {\n return this.db.prepare('SELECT * FROM features WHERE mission_id = ? AND status = ?')\n .all(missionId, status) as FeatureRow[];\n }\n \n update(id: string, missionId: string, updates: Partial<FeatureRow>): FeatureRow | undefined {\n const fields = Object.keys(updates).filter(k => FEATURE_UPDATABLE_COLUMNS.has(k));\n if (fields.length === 0) return this.findById(id, missionId);\n \n const setClause = fields.map(f => `${f} = ?`).join(', ');\n const values = fields.map(f => updates[f as keyof FeatureRow]);\n \n this.db.prepare(`UPDATE features SET ${setClause} WHERE id = ? AND mission_id = ?`)\n .run(...values, id, missionId);\n \n return this.findById(id, missionId);\n }\n \n delete(id: string, missionId: string): boolean {\n const result = this.db.prepare('DELETE FROM features WHERE id = ? AND mission_id = ?')\n .run(id, missionId);\n return result.changes > 0;\n }\n}\n\nexport class HistoryRepository {\n private db: Database.Database;\n \n constructor(db: Database.Database) {\n this.db = db;\n }\n \n append(entry: Omit<HistoryRow, 'id' | 'timestamp'>): HistoryRow {\n const stmt = this.db.prepare(`\n INSERT INTO history (mission_id, feature_id, event, note, details, timestamp, session_id)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n `);\n \n const result = stmt.run(\n entry.mission_id, entry.feature_id, entry.event, entry.note,\n entry.details, Date.now(), entry.session_id\n );\n \n return this.db.prepare('SELECT * FROM history WHERE id = ?')\n .get(result.lastInsertRowid) as HistoryRow;\n }\n \n findByMission(missionId: string, limit = 100): HistoryRow[] {\n return this.db.prepare('SELECT * FROM history WHERE mission_id = ? ORDER BY timestamp DESC LIMIT ?')\n .all(missionId, limit) as HistoryRow[];\n }\n \n findByFeature(featureId: string, limit = 50): HistoryRow[] {\n return this.db.prepare('SELECT * FROM history WHERE feature_id = ? ORDER BY timestamp DESC LIMIT ?')\n .all(featureId, limit) as HistoryRow[];\n }\n \n findByEvent(event: string, limit = 50): HistoryRow[] {\n return this.db.prepare('SELECT * FROM history WHERE event = ? ORDER BY timestamp DESC LIMIT ?')\n .all(event, limit) as HistoryRow[];\n }\n \n search(query: string, limit = 50): HistoryRow[] {\n return this.db.prepare(`\n SELECT * FROM history \n WHERE note LIKE ? OR event LIKE ? \n ORDER BY timestamp DESC LIMIT ?\n `).all(`%${query}%`, `%${query}%`, limit) as HistoryRow[];\n }\n}\n\nexport class LearningRepository {\n private db: Database.Database;\n \n constructor(db: Database.Database) {\n this.db = db;\n }\n \n create(learning: Omit<LearningRow, 'id' | 'created_at' | 'used_count' | 'success_count'>): LearningRow {\n const stmt = this.db.prepare(`\n INSERT INTO learnings (mission_id, feature_id, type, category, insight, confidence, applicable_to, context)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)\n `);\n \n const result = stmt.run(\n learning.mission_id, learning.feature_id, learning.type, learning.category,\n learning.insight, learning.confidence, learning.applicable_to, learning.context\n );\n \n return this.db.prepare('SELECT * FROM learnings WHERE id = ?')\n .get(result.lastInsertRowid) as LearningRow;\n }\n \n findByType(type: string, limit = 50): LearningRow[] {\n return this.db.prepare('SELECT * FROM learnings WHERE type = ? ORDER BY confidence DESC LIMIT ?')\n .all(type, limit) as LearningRow[];\n }\n \n findByCategory(category: string, limit = 50): LearningRow[] {\n return this.db.prepare('SELECT * FROM learnings WHERE category = ? ORDER BY confidence DESC LIMIT ?')\n .all(category, limit) as LearningRow[];\n }\n \n findRelevant(tags: string[], limit = 10): LearningRow[] {\n if (tags.length === 0) return [];\n\n const placeholders = tags.map(() => '?').join(',');\n return this.db.prepare(`\n SELECT * FROM learnings \n WHERE json_valid(learnings.applicable_to)\n AND EXISTS (\n SELECT 1\n FROM json_each(learnings.applicable_to)\n WHERE json_each.value IN (${placeholders})\n )\n ORDER BY confidence DESC, used_count DESC\n LIMIT ?\n `).all(...tags, limit) as LearningRow[];\n }\n \n recordUsage(id: string, success: boolean): void {\n if (success) {\n this.db.prepare('UPDATE learnings SET used_count = used_count + 1, success_count = success_count + 1 WHERE id = ?')\n .run(id);\n } else {\n this.db.prepare('UPDATE learnings SET used_count = used_count + 1 WHERE id = ?')\n .run(id);\n }\n }\n}\n\nexport class PatternRepository {\n private db: Database.Database;\n \n constructor(db: Database.Database) {\n this.db = db;\n }\n \n create(pattern: Omit<PatternRow, 'id' | 'created_at' | 'updated_at'>): PatternRow {\n const stmt = this.db.prepare(`\n INSERT INTO patterns (pattern_type, name, description, pattern_data, success_count, failure_count,\n success_rate, avg_duration_ms, avg_tokens, example_missions, tags)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n \n const result = stmt.run(\n pattern.pattern_type, pattern.name, pattern.description, pattern.pattern_data,\n pattern.success_count, pattern.failure_count, pattern.success_rate,\n pattern.avg_duration_ms, pattern.avg_tokens, pattern.example_missions, pattern.tags\n );\n \n return this.db.prepare('SELECT * FROM patterns WHERE id = ?')\n .get(result.lastInsertRowid) as PatternRow;\n }\n \n findByType(type: string, limit = 20): PatternRow[] {\n return this.db.prepare('SELECT * FROM patterns WHERE pattern_type = ? ORDER BY success_rate DESC LIMIT ?')\n .all(type, limit) as PatternRow[];\n }\n \n findSuccessful(limit = 20): PatternRow[] {\n return this.db.prepare('SELECT * FROM patterns WHERE success_rate > 0.7 ORDER BY success_rate DESC LIMIT ?')\n .all(limit) as PatternRow[];\n }\n \n recordOutcome(id: string, success: boolean): void {\n if (success) {\n this.db.prepare(`\n UPDATE patterns \n SET success_count = success_count + 1,\n success_rate = CAST(success_count + 1 AS REAL) / (success_count + failure_count + 1),\n updated_at = ?\n WHERE id = ?\n `).run(Date.now(), id);\n } else {\n this.db.prepare(`\n UPDATE patterns \n SET failure_count = failure_count + 1,\n success_rate = CAST(success_count AS REAL) / (success_count + failure_count + 1),\n updated_at = ?\n WHERE id = ?\n `).run(Date.now(), id);\n }\n }\n}\n\nexport class TemplateRepository {\n private db: Database.Database;\n \n constructor(db: Database.Database) {\n this.db = db;\n }\n \n findById(id: string): TemplateRow | undefined {\n return this.db.prepare('SELECT * FROM templates WHERE id = ?').get(id) as TemplateRow | undefined;\n }\n \n findAll(limit = 50): TemplateRow[] {\n return this.db.prepare('SELECT * FROM templates ORDER BY rating DESC, usage_count DESC LIMIT ?')\n .all(limit) as TemplateRow[];\n }\n \n findByTags(tags: string[]): TemplateRow[] {\n if (tags.length === 0) return [];\n\n const placeholders = tags.map(() => '?').join(',');\n return this.db.prepare(`\n SELECT * FROM templates \n WHERE json_valid(templates.tags)\n AND EXISTS (\n SELECT 1\n FROM json_each(templates.tags)\n WHERE json_each.value IN (${placeholders})\n )\n ORDER BY rating DESC\n `).all(...tags) as TemplateRow[];\n }\n \n create(template: Omit<TemplateRow, 'created_at' | 'updated_at' | 'usage_count' | 'rating' | 'rating_count'>): TemplateRow {\n const now = Date.now();\n const stmt = this.db.prepare(`\n INSERT INTO templates (id, name, description, author, version, content, tags, difficulty,\n estimated_time_hours, estimated_tokens, usage_count, rating, rating_count,\n created_at, updated_at, is_builtin)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0, 0, 0, ?, ?, ?)\n `);\n \n stmt.run(\n template.id, template.name, template.description, template.author, template.version,\n template.content, template.tags, template.difficulty, template.estimated_time_hours,\n template.estimated_tokens, now, now, template.is_builtin\n );\n \n return this.findById(template.id)!;\n }\n \n incrementUsage(id: string): void {\n this.db.prepare('UPDATE templates SET usage_count = usage_count + 1, updated_at = ? WHERE id = ?')\n .run(Date.now(), id);\n }\n \n rate(id: string, rating: number): void {\n this.db.prepare(`\n UPDATE templates \n SET rating = (rating * rating_count + ?) / (rating_count + 1),\n rating_count = rating_count + 1,\n updated_at = ?\n WHERE id = ?\n `).run(rating, Date.now(), id);\n }\n}\n\nexport class MetricRepository {\n private db: Database.Database;\n \n constructor(db: Database.Database) {\n this.db = db;\n }\n \n record(metric: Omit<MetricRow, 'id' | 'recorded_at'>): MetricRow {\n const stmt = this.db.prepare(`\n INSERT INTO metrics (metric_type, metric_name, value, unit, tags, recorded_at, period_start, period_end)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)\n `);\n \n const result = stmt.run(\n metric.metric_type, metric.metric_name, metric.value, metric.unit,\n metric.tags, Date.now(), metric.period_start, metric.period_end\n );\n \n return this.db.prepare('SELECT * FROM metrics WHERE id = ?')\n .get(result.lastInsertRowid) as MetricRow;\n }\n \n findByType(type: string, name?: string, limit = 100): MetricRow[] {\n if (name) {\n return this.db.prepare('SELECT * FROM metrics WHERE metric_type = ? AND metric_name = ? ORDER BY recorded_at DESC LIMIT ?')\n .all(type, name, limit) as MetricRow[];\n }\n return this.db.prepare('SELECT * FROM metrics WHERE metric_type = ? ORDER BY recorded_at DESC LIMIT ?')\n .all(type, limit) as MetricRow[];\n }\n \n getAggregated(type: string, name: string, periodMs: number): { avg: number; min: number; max: number; count: number } {\n const since = Date.now() - periodMs;\n const row = this.db.prepare(`\n SELECT \n AVG(value) as avg,\n MIN(value) as min,\n MAX(value) as max,\n COUNT(*) as count\n FROM metrics \n WHERE metric_type = ? AND metric_name = ? AND recorded_at > ?\n `).get(type, name, since) as { avg?: number; min?: number; max?: number; count?: number } | undefined;\n \n return {\n avg: row?.avg ?? 0,\n min: row?.min ?? 0,\n max: row?.max ?? 0,\n count: row?.count ?? 0,\n };\n }\n}\n\nexport class PredictionRepository {\n private db: Database.Database;\n \n constructor(db: Database.Database) {\n this.db = db;\n }\n \n create(prediction: Omit<PredictionRow, 'id' | 'created_at' | 'validated_at' | 'accuracy' | 'actual_value'> & { actual_value?: number | null }): PredictionRow {\n const stmt = this.db.prepare(`\n INSERT INTO predictions (mission_id, feature_id, prediction_type, predicted_value, actual_value, confidence, model_version)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n `);\n \n const result = stmt.run(\n prediction.mission_id, prediction.feature_id, prediction.prediction_type,\n prediction.predicted_value, prediction.actual_value ?? null, prediction.confidence, prediction.model_version\n );\n \n return this.db.prepare('SELECT * FROM predictions WHERE id = ?')\n .get(result.lastInsertRowid) as PredictionRow;\n }\n \n validate(id: string, actualValue: number): void {\n const prediction = this.db.prepare('SELECT * FROM predictions WHERE id = ?').get(id) as PredictionRow;\n if (!prediction) return;\n \n const accuracy = 1 - Math.abs(prediction.predicted_value - actualValue) / Math.max(prediction.predicted_value, actualValue);\n \n this.db.prepare(`\n UPDATE predictions \n SET actual_value = ?, accuracy = ?, validated_at = ?\n WHERE id = ?\n `).run(actualValue, accuracy, Date.now(), id);\n }\n \n findByType(type: string, limit = 50): PredictionRow[] {\n return this.db.prepare('SELECT * FROM predictions WHERE prediction_type = ? ORDER BY created_at DESC LIMIT ?')\n .all(type, limit) as PredictionRow[];\n }\n \n getAccuracy(type: string): number {\n const row = this.db.prepare(`\n SELECT AVG(accuracy) as avg_accuracy \n FROM predictions \n WHERE prediction_type = ? AND accuracy IS NOT NULL\n `).get(type) as { avg_accuracy?: number } | undefined;\n \n return row?.avg_accuracy ?? 0;\n }\n}\n\n// ═══════════════════════════════════════════════════════════════════════════\n// Convenience function to get all repositories\n// ═══════════════════════════════════════════════════════════════════════════\n\nexport function getRepositories() {\n const db = getDatabase();\n return {\n missions: new MissionRepository(db),\n features: new FeatureRepository(db),\n history: new HistoryRepository(db),\n learnings: new LearningRepository(db),\n patterns: new PatternRepository(db),\n templates: new TemplateRepository(db),\n metrics: new MetricRepository(db),\n predictions: new PredictionRepository(db),\n };\n}\n","#!/usr/bin/env node\nimport { getRepositories } from '../database/index.js';\nimport { pathToFileURL } from 'node:url';\n\nexport interface CLICommand {\n name: string;\n description: string;\n execute(args: string[]): Promise<string>;\n}\n\nexport class CLI {\n private commands = new Map<string, CLICommand>();\n \n constructor() {\n this.registerDefaultCommands();\n }\n \n registerCommand(cmd: CLICommand) {\n this.commands.set(cmd.name, cmd);\n }\n \n async execute(args: string[]): Promise<string> {\n const [cmd, ...rest] = args;\n if (!cmd || cmd === '--help' || cmd === '-h') return this.showHelp();\n const command = this.commands.get(cmd);\n if (!command) return `Unknown command: ${cmd}. Use --help for available commands.`;\n return command.execute(rest);\n }\n \n showHelp(): string {\n const lines = ['Pi Missions CLI', 'Usage: pi-missions <command> [options]', '', 'Commands:'];\n for (const [name, cmd] of this.commands) lines.push(` ${name.padEnd(15)} ${cmd.description}`);\n return lines.join('\\n');\n }\n \n private registerDefaultCommands() {\n this.registerCommand({ name: 'list', description: 'List all missions', execute: async () => {\n const repos = getRepositories();\n const missions = repos.missions.findAll(50);\n if (!missions.length) return 'No missions found.';\n return missions.map(m => `${m.id} [${m.status}] ${m.title}`).join('\\n');\n }});\n \n this.registerCommand({ name: 'status', description: 'Show mission status', execute: async (args) => {\n const repos = getRepositories();\n const id = args[0];\n if (!id) return 'Usage: pi-missions status <mission-id>';\n const m = repos.missions.findById(id);\n if (!m) return `Mission not found: ${id}`;\n const features = repos.features.findByMission(id);\n const done = features.filter(f => f.status === 'done').length;\n return `${m.title}\\nStatus: ${m.status}\\nProgress: ${done}/${features.length}\\nTokens: ${m.total_tokens}`;\n }});\n \n this.registerCommand({ name: 'analytics', description: 'Show analytics', execute: async () => {\n const repos = getRepositories();\n const missions = repos.missions.findAll(100);\n const total = missions.length;\n const completed = missions.filter(m => m.status === 'complete').length;\n const active = missions.filter(m => m.status === 'active').length;\n return `📊 Analytics\\nTotal: ${total}\\nActive: ${active}\\nCompleted: ${completed}\\nSuccess Rate: ${total > 0 ? Math.round(completed/total*100) : 0}%`;\n }});\n \n this.registerCommand({ name: 'templates', description: 'List templates', execute: async () => {\n const repos = getRepositories();\n const templates = repos.templates.findAll();\n return templates.map(t => `${t.id.padEnd(15)} ${t.name} - ${t.description || ''}`).join('\\n');\n }});\n \n this.registerCommand({ name: 'history', description: 'Show mission history', execute: async (args) => {\n const repos = getRepositories();\n const id = args[0];\n if (!id) return 'Usage: pi-missions history <mission-id>';\n const history = repos.history.findByMission(id, 20);\n if (!history.length) return 'No history entries.';\n return history.map(h => `${new Date(h.timestamp).toISOString()} ${h.event} ${h.note || ''}`).join('\\n');\n }});\n \n this.registerCommand({ name: 'doctor', description: 'Run diagnostics', execute: async () => {\n const repos = getRepositories();\n const missions = repos.missions.count();\n const templates = repos.templates.findAll().length;\n return `✅ Database: OK\\n📊 Missions: ${missions}\\n📋 Templates: ${templates}`;\n }});\n }\n}\n\nexport function createCLI(): CLI {\n return new CLI();\n}\n\nfunction isDirectExecution(): boolean {\n const entry = process.argv[1];\n return Boolean(entry && import.meta.url === pathToFileURL(entry).href);\n}\n\nif (isDirectExecution()) {\n createCLI().execute(process.argv.slice(2))\n .then((output) => {\n if (output) console.log(output);\n })\n .catch((error: unknown) => {\n console.error(error instanceof Error ? error.message : String(error));\n process.exitCode = 1;\n });\n}\n"],"mappings":"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","names":["require","db","db"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@groeponline/pi-missions",
3
- "version": "0.3.7",
3
+ "version": "0.3.8",
4
4
  "description": "Persistent mission orchestration for Pi: durable plans, task queues, evidence trails, SQLite state, resumable execution, and handoffs across agent sessions.",
5
5
  "type": "module",
6
6
  "private": false,