hungry-ghost-hive 0.21.5 → 0.21.6

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.
@@ -821,6 +821,13 @@ export declare const HiveConfigSchema: z.ZodObject<{
821
821
  story_similarity_threshold?: number | undefined;
822
822
  }>>;
823
823
  }, "strip", z.ZodTypeAny, {
824
+ agents: {
825
+ poll_interval: number;
826
+ max_retries: number;
827
+ checkpoint_threshold: number;
828
+ llm_timeout_ms: number;
829
+ llm_max_retries: number;
830
+ };
824
831
  qa: {
825
832
  quality_checks: string[];
826
833
  build_command: string;
@@ -830,13 +837,6 @@ export declare const HiveConfigSchema: z.ZodObject<{
830
837
  max_agents: number;
831
838
  } | undefined;
832
839
  };
833
- agents: {
834
- poll_interval: number;
835
- max_retries: number;
836
- checkpoint_threshold: number;
837
- llm_timeout_ms: number;
838
- llm_max_retries: number;
839
- };
840
840
  scaling: {
841
841
  senior_capacity: number;
842
842
  junior_max_complexity: number;
@@ -922,6 +922,13 @@ export declare const HiveConfigSchema: z.ZodObject<{
922
922
  auth_token?: string | undefined;
923
923
  };
924
924
  }, {
925
+ agents?: {
926
+ poll_interval?: number | undefined;
927
+ max_retries?: number | undefined;
928
+ checkpoint_threshold?: number | undefined;
929
+ llm_timeout_ms?: number | undefined;
930
+ llm_max_retries?: number | undefined;
931
+ } | undefined;
925
932
  qa?: {
926
933
  quality_checks?: string[] | undefined;
927
934
  build_command?: string | undefined;
@@ -931,13 +938,6 @@ export declare const HiveConfigSchema: z.ZodObject<{
931
938
  max_agents?: number | undefined;
932
939
  } | undefined;
933
940
  } | undefined;
934
- agents?: {
935
- poll_interval?: number | undefined;
936
- max_retries?: number | undefined;
937
- checkpoint_threshold?: number | undefined;
938
- llm_timeout_ms?: number | undefined;
939
- llm_max_retries?: number | undefined;
940
- } | undefined;
941
941
  scaling?: {
942
942
  senior_capacity?: number | undefined;
943
943
  junior_max_complexity?: number | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/db/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/db/client.ts"],"names":[],"mappings":"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"}
package/dist/db/client.js CHANGED
@@ -1,8 +1,8 @@
1
1
  // Licensed under the Hungry Ghost Hive License. See LICENSE.
2
- import { existsSync, readFileSync, writeFileSync } from 'fs';
2
+ import { copyFileSync, existsSync, readFileSync, statSync, writeFileSync } from 'fs';
3
3
  import { join } from 'path';
4
4
  import initSqlJs from 'sql.js';
5
- import { InitializationError } from '../errors/index.js';
5
+ import { DatabaseCorruptionError, InitializationError } from '../errors/index.js';
6
6
  // Embedded initial migration SQL
7
7
  const INITIAL_MIGRATION = `
8
8
  -- Hive Orchestrator Initial Schema
@@ -150,29 +150,83 @@ async function getSqlJs() {
150
150
  }
151
151
  return SQL;
152
152
  }
153
+ // Minimum file size (in bytes) that indicates a database had meaningful data.
154
+ // Files below this threshold are likely new or schema-only databases.
155
+ const CORRUPTION_CHECK_MIN_FILE_SIZE = 50 * 1024; // 50KB
156
+ // Core tables that should have rows in a populated database
157
+ const CORE_TABLES = ['teams', 'agents', 'stories'];
158
+ /**
159
+ * Validate that a loaded database is not a silently-corrupted empty copy.
160
+ * If the source file was large (>50KB) but the loaded DB has core tables
161
+ * with zero rows, that indicates sql.js silently returned an empty DB.
162
+ */
163
+ function validateLoadedDatabase(db, fileSize) {
164
+ if (fileSize < CORRUPTION_CHECK_MIN_FILE_SIZE) {
165
+ return; // Small file — likely a new or schema-only DB, skip validation
166
+ }
167
+ // Check if any core table has data
168
+ for (const table of CORE_TABLES) {
169
+ try {
170
+ const result = db.exec(`SELECT COUNT(*) FROM ${table}`);
171
+ if (result.length > 0 && result[0].values[0][0] > 0) {
172
+ return; // At least one core table has data — DB looks valid
173
+ }
174
+ }
175
+ catch {
176
+ // Table doesn't exist yet — that's fine, migrations haven't run
177
+ continue;
178
+ }
179
+ }
180
+ // File was large but all core tables are empty — likely corruption
181
+ throw new DatabaseCorruptionError(`Database file is ${fileSize} bytes but loaded with zero rows in core tables (${CORE_TABLES.join(', ')}). ` +
182
+ 'This likely indicates a corrupted or partially-read database file. ' +
183
+ 'Refusing to proceed to prevent data loss. Check the backup at hive.db.bak if available.');
184
+ }
153
185
  export async function createDatabase(dbPath) {
154
186
  const SqlJs = await getSqlJs();
155
187
  if (!SqlJs)
156
188
  throw new InitializationError('Failed to initialize sql.js');
157
189
  let db;
190
+ const backupPath = dbPath + '.bak';
158
191
  // Load existing database or create new one
159
192
  if (existsSync(dbPath)) {
160
193
  const buffer = readFileSync(dbPath);
161
- db = new SqlJs.Database(buffer);
194
+ const fileSize = statSync(dbPath).size;
195
+ try {
196
+ db = new SqlJs.Database(buffer);
197
+ // Verify the database is usable by running a basic command
198
+ db.run('PRAGMA foreign_keys = ON');
199
+ db.exec('SELECT 1');
200
+ }
201
+ catch (error) {
202
+ throw new DatabaseCorruptionError(`Failed to load database file at ${dbPath}: ${error instanceof Error ? error.message : String(error)}`);
203
+ }
204
+ // Validate the loaded DB is not silently empty from a corrupt file
205
+ validateLoadedDatabase(db, fileSize);
206
+ // Run migrations on loaded DB — wrap in try-catch to detect subtle corruption
207
+ try {
208
+ runMigrations(db);
209
+ }
210
+ catch (error) {
211
+ throw new DatabaseCorruptionError(`Database file at ${dbPath} appears corrupted (migrations failed): ${error instanceof Error ? error.message : String(error)}`);
212
+ }
162
213
  }
163
214
  else {
164
215
  db = new SqlJs.Database();
216
+ // Enable foreign keys
217
+ db.run('PRAGMA foreign_keys = ON');
218
+ // Run migrations on new DB
219
+ runMigrations(db);
165
220
  }
166
- // Enable foreign keys
167
- db.run('PRAGMA foreign_keys = ON');
168
221
  const save = () => {
222
+ // Write backup before overwriting the main database file
223
+ if (existsSync(dbPath)) {
224
+ copyFileSync(dbPath, backupPath);
225
+ }
169
226
  const data = db.export();
170
227
  const buffer = Buffer.from(data);
171
228
  writeFileSync(dbPath, buffer);
172
229
  };
173
- // Auto-run migrations
174
- runMigrations(db);
175
- save();
176
230
  const client = {
177
231
  db,
178
232
  close: () => {
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/db/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/db/client.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAE7D,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AACrF,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,SAAwC,MAAM,QAAQ,CAAC;AAC9D,OAAO,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AASlF,iCAAiC;AACjC,MAAM,iBAAiB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0IzB,CAAC;AAEF,IAAI,GAAG,GAAiD,IAAI,CAAC;AAE7D,KAAK,UAAU,QAAQ;IACrB,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,GAAG,GAAG,MAAM,SAAS,EAAE,CAAC;IAC1B,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,8EAA8E;AAC9E,sEAAsE;AACtE,MAAM,8BAA8B,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,OAAO;AAEzD,4DAA4D;AAC5D,MAAM,WAAW,GAAG,CAAC,OAAO,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;AAEnD;;;;GAIG;AACH,SAAS,sBAAsB,CAAC,EAAiB,EAAE,QAAgB;IACjE,IAAI,QAAQ,GAAG,8BAA8B,EAAE,CAAC;QAC9C,OAAO,CAAC,+DAA+D;IACzE,CAAC;IAED,mCAAmC;IACnC,KAAK,MAAM,KAAK,IAAI,WAAW,EAAE,CAAC;QAChC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,EAAE,CAAC,IAAI,CAAC,wBAAwB,KAAK,EAAE,CAAC,CAAC;YACxD,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,IAAK,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAY,GAAG,CAAC,EAAE,CAAC;gBAChE,OAAO,CAAC,oDAAoD;YAC9D,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,gEAAgE;YAChE,SAAS;QACX,CAAC;IACH,CAAC;IAED,mEAAmE;IACnE,MAAM,IAAI,uBAAuB,CAC/B,oBAAoB,QAAQ,oDAAoD,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK;QACzG,qEAAqE;QACrE,yFAAyF,CAC5F,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,MAAc;IACjD,MAAM,KAAK,GAAG,MAAM,QAAQ,EAAE,CAAC;IAC/B,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,mBAAmB,CAAC,6BAA6B,CAAC,CAAC;IAEzE,IAAI,EAAiB,CAAC;IACtB,MAAM,UAAU,GAAG,MAAM,GAAG,MAAM,CAAC;IAEnC,2CAA2C;IAC3C,IAAI,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACvB,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;QACpC,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC;QAEvC,IAAI,CAAC;YACH,EAAE,GAAG,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YAChC,2DAA2D;YAC3D,EAAE,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;YACnC,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACtB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,uBAAuB,CAC/B,mCAAmC,MAAM,KAAK,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CACvG,CAAC;QACJ,CAAC;QAED,mEAAmE;QACnE,sBAAsB,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;QAErC,8EAA8E;QAC9E,IAAI,CAAC;YACH,aAAa,CAAC,EAAE,CAAC,CAAC;QACpB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,uBAAuB,CAC/B,oBAAoB,MAAM,2CAA2C,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAC9H,CAAC;QACJ,CAAC;IACH,CAAC;SAAM,CAAC;QACN,EAAE,GAAG,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;QAC1B,sBAAsB;QACtB,EAAE,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;QACnC,2BAA2B;QAC3B,aAAa,CAAC,EAAE,CAAC,CAAC;IACpB,CAAC;IAED,MAAM,IAAI,GAAG,GAAG,EAAE;QAChB,yDAAyD;QACzD,IAAI,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YACvB,YAAY,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QACnC,CAAC;QACD,MAAM,IAAI,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjC,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,CAAC,CAAC;IAEF,MAAM,MAAM,GAAmB;QAC7B,EAAE;QACF,KAAK,EAAE,GAAG,EAAE;YACV,IAAI,EAAE,CAAC;YACP,EAAE,CAAC,KAAK,EAAE,CAAC;QACb,CAAC;QACD,IAAI;QACJ,aAAa,EAAE,GAAG,EAAE;YAClB,aAAa,CAAC,EAAE,CAAC,CAAC;YAClB,IAAI,EAAE,CAAC;QACT,CAAC;KACF,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,aAAa,CAAC,EAAiB;IACtC,8CAA8C;IAC9C,EAAE,CAAC,GAAG,CAAC;;;;;;GAMN,CAAC,CAAC;IAEH,yCAAyC;IACzC,MAAM,MAAM,GAAG,EAAE,CAAC,IAAI,CAAC,4DAA4D,CAAC,CAAC;IACrF,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;IAE1E,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACtB,0BAA0B;QAC1B,EAAE,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;QAC1B,EAAE,CAAC,GAAG,CAAC,0DAA0D,CAAC,CAAC;IACrE,CAAC;IAED,kDAAkD;IAClD,MAAM,SAAS,GAAG,EAAE,CAAC,IAAI,CAAC,oEAAoE,CAAC,CAAC;IAChG,MAAM,mBAAmB,GAAG,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;IAEnF,IAAI,CAAC,mBAAmB,EAAE,CAAC;QACzB,kFAAkF;QAClF,MAAM,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;QACrD,MAAM,cAAc,GAClB,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAc,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC;QAEvF,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,EAAE,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;QACrD,CAAC;QACD,EAAE,CAAC,GAAG,CAAC,kEAAkE,CAAC,CAAC;IAC7E,CAAC;IAED,gEAAgE;IAChE,MAAM,SAAS,GAAG,EAAE,CAAC,IAAI,CAAC,sEAAsE,CAAC,CAAC;IAClG,MAAM,mBAAmB,GAAG,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;IAEnF,IAAI,CAAC,mBAAmB,EAAE,CAAC;QACzB,8DAA8D;QAC9D,MAAM,SAAS,GAAG,EAAE,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;QAC9D,MAAM,aAAa,GACjB,SAAS,CAAC,MAAM,GAAG,CAAC;YACpB,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAc,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,aAAa,CAAC,CAAC;QAEzE,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,0FAA0F;YAC1F,EAAE,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;OAgBN,CAAC,CAAC;YAEH,oDAAoD;YACpD,EAAE,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;OAgBN,CAAC,CAAC;YAEH,oCAAoC;YACpC,EAAE,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;YACnC,EAAE,CAAC,GAAG,CAAC,uDAAuD,CAAC,CAAC;QAClE,CAAC;QAED,EAAE,CAAC,GAAG,CAAC,oEAAoE,CAAC,CAAC;IAC/E,CAAC;IAED,kEAAkE;IAClE,MAAM,SAAS,GAAG,EAAE,CAAC,IAAI,CAAC,iEAAiE,CAAC,CAAC;IAC7F,MAAM,mBAAmB,GAAG,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;IAEnF,IAAI,CAAC,mBAAmB,EAAE,CAAC;QACzB,gCAAgC;QAChC,MAAM,MAAM,GAAG,EAAE,CAAC,IAAI,CAAC,uEAAuE,CAAC,CAAC;QAChG,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;QAE1E,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACtB,EAAE,CAAC,GAAG,CAAC;;;;;;;;;;;;OAYN,CAAC,CAAC;QACL,CAAC;QAED,EAAE,CAAC,GAAG,CAAC,+DAA+D,CAAC,CAAC;IAC1E,CAAC;IAED,wEAAwE;IACxE,MAAM,SAAS,GAAG,EAAE,CAAC,IAAI,CACvB,wEAAwE,CACzE,CAAC;IACF,MAAM,mBAAmB,GAAG,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;IAEnF,IAAI,CAAC,mBAAmB,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;QACrD,MAAM,iBAAiB,GACrB,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAc,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,WAAW,CAAC,CAAC;QAE3F,IAAI,CAAC,iBAAiB,EAAE,CAAC;YACvB,8DAA8D;YAC9D,EAAE,CAAC,GAAG,CAAC,mDAAmD,CAAC,CAAC;QAC9D,CAAC;QACD,EAAE,CAAC,GAAG,CAAC,sEAAsE,CAAC,CAAC;IACjF,CAAC;IAED,+EAA+E;IAC/E,MAAM,SAAS,GAAG,EAAE,CAAC,IAAI,CACvB,uEAAuE,CACxE,CAAC;IACF,MAAM,mBAAmB,GAAG,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;IAEnF,IAAI,CAAC,mBAAmB,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;QACrD,MAAM,qBAAqB,GACzB,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAc,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,eAAe,CAAC,CAAC;QAE/F,IAAI,CAAC,qBAAqB,EAAE,CAAC;YAC3B,EAAE,CAAC,GAAG,CAAC,kDAAkD,CAAC,CAAC;QAC7D,CAAC;QACD,EAAE,CAAC,GAAG,CAAC,qEAAqE,CAAC,CAAC;IAChF,CAAC;IAED,4DAA4D;IAC5D,MAAM,SAAS,GAAG,EAAE,CAAC,IAAI,CAAC,gEAAgE,CAAC,CAAC;IAC5F,MAAM,mBAAmB,GAAG,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;IAEnF,IAAI,CAAC,mBAAmB,EAAE,CAAC;QACzB,+CAA+C;QAC/C,EAAE,CAAC,GAAG,CAAC,kEAAkE,CAAC,CAAC;QAC3E,EAAE,CAAC,GAAG,CAAC,oEAAoE,CAAC,CAAC;QAC7E,EAAE,CAAC,GAAG,CACJ,wFAAwF,CACzF,CAAC;QACF,EAAE,CAAC,GAAG,CAAC,kFAAkF,CAAC,CAAC;QAC3F,EAAE,CAAC,GAAG,CAAC,kEAAkE,CAAC,CAAC;QAC3E,EAAE,CAAC,GAAG,CAAC,gEAAgE,CAAC,CAAC;QACzE,EAAE,CAAC,GAAG,CACJ,4FAA4F,CAC7F,CAAC;QACF,EAAE,CAAC,GAAG,CAAC,kFAAkF,CAAC,CAAC;QAC3F,EAAE,CAAC,GAAG,CAAC,4EAA4E,CAAC,CAAC;QACrF,EAAE,CAAC,GAAG,CAAC,0EAA0E,CAAC,CAAC;QAEnF,EAAE,CAAC,GAAG,CAAC,8DAA8D,CAAC,CAAC;IACzE,CAAC;IAED,0DAA0D;IAC1D,MAAM,SAAS,GAAG,EAAE,CAAC,IAAI,CAAC,gEAAgE,CAAC,CAAC;IAC5F,MAAM,mBAAmB,GAAG,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;IAEnF,IAAI,CAAC,mBAAmB,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;QAC3D,MAAM,gBAAgB,GACpB,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAc,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC;QAEzF,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACtB,EAAE,CAAC,GAAG,CAAC,+DAA+D,CAAC,CAAC;QAC1E,CAAC;QACD,EAAE,CAAC,GAAG,CAAC,8DAA8D,CAAC,CAAC;IACzE,CAAC;IAED,6EAA6E;IAC7E,MAAM,SAAS,GAAG,EAAE,CAAC,IAAI,CACvB,wEAAwE,CACzE,CAAC;IACF,MAAM,mBAAmB,GAAG,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;IAEnF,IAAI,CAAC,mBAAmB,EAAE,CAAC;QACzB,EAAE,CAAC,GAAG,CACJ,kGAAkG,CACnG,CAAC;QACF,EAAE,CAAC,GAAG,CACJ,kGAAkG,CACnG,CAAC;QACF,EAAE,CAAC,GAAG,CAAC,sEAAsE,CAAC,CAAC;IACjF,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,OAAe;IAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IACxC,OAAO,cAAc,CAAC,MAAM,CAAC,CAAC;AAChC,CAAC;AAED,4DAA4D;AAC5D,MAAM,UAAU,QAAQ,CAAI,EAAiB,EAAE,GAAW,EAAE,SAAoB,EAAE;IAChF,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC7B,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAElB,MAAM,OAAO,GAAQ,EAAE,CAAC;IACxB,OAAO,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;QACnB,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QAC/B,OAAO,CAAC,IAAI,CAAC,GAAQ,CAAC,CAAC;IACzB,CAAC;IACD,IAAI,CAAC,IAAI,EAAE,CAAC;IACZ,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,yDAAyD;AACzD,MAAM,UAAU,QAAQ,CAAI,EAAiB,EAAE,GAAW,EAAE,SAAoB,EAAE;IAChF,MAAM,OAAO,GAAG,QAAQ,CAAI,EAAE,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;IAC7C,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC;AACpB,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,GAAG,CAAC,EAAiB,EAAE,GAAW,EAAE,SAAoB,EAAE;IACxE,EAAE,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;AACtB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAI,EAAiB,EAAE,EAAwB;IAClF,IAAI,CAAC;QACH,EAAE,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;QAC1B,MAAM,MAAM,GAAG,MAAM,EAAE,EAAE,CAAC;QAC1B,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACjB,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC;YACH,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QACrB,CAAC;QAAC,OAAO,MAAM,EAAE,CAAC;YAChB,yEAAyE;QAC3E,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=client.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.test.d.ts","sourceRoot":"","sources":["../../src/db/client.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,223 @@
1
+ import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'fs';
2
+ import { tmpdir } from 'os';
3
+ import { join } from 'path';
4
+ import initSqlJs from 'sql.js';
5
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
6
+ import { DatabaseCorruptionError } from '../errors/index.js';
7
+ import { createDatabase } from './client.js';
8
+ /**
9
+ * Helper to create a valid SQLite database buffer with the core schema
10
+ * that is compatible with runMigrations().
11
+ */
12
+ async function createValidDbBuffer(opts = {}) {
13
+ const SQL = await initSqlJs();
14
+ const db = new SQL.Database();
15
+ // Use a schema that matches the initial migration so runMigrations works
16
+ db.run(`
17
+ CREATE TABLE IF NOT EXISTS teams (
18
+ id TEXT PRIMARY KEY, repo_url TEXT NOT NULL, repo_path TEXT NOT NULL,
19
+ name TEXT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
20
+ );
21
+ CREATE TABLE IF NOT EXISTS agents (
22
+ id TEXT PRIMARY KEY,
23
+ type TEXT NOT NULL CHECK (type IN ('tech_lead', 'senior', 'intermediate', 'junior', 'qa')),
24
+ team_id TEXT REFERENCES teams(id), tmux_session TEXT, model TEXT,
25
+ status TEXT DEFAULT 'idle' CHECK (status IN ('idle', 'working', 'blocked', 'terminated')),
26
+ current_story_id TEXT, memory_state TEXT, last_seen TIMESTAMP, worktree_path TEXT,
27
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
28
+ );
29
+ CREATE TABLE IF NOT EXISTS requirements (
30
+ id TEXT PRIMARY KEY, title TEXT NOT NULL, description TEXT NOT NULL,
31
+ submitted_by TEXT DEFAULT 'human',
32
+ status TEXT DEFAULT 'pending' CHECK (status IN ('pending', 'planning', 'planned', 'in_progress', 'completed')),
33
+ godmode BOOLEAN DEFAULT 0, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
34
+ );
35
+ CREATE TABLE IF NOT EXISTS stories (
36
+ id TEXT PRIMARY KEY, requirement_id TEXT REFERENCES requirements(id),
37
+ team_id TEXT REFERENCES teams(id), title TEXT NOT NULL, description TEXT NOT NULL,
38
+ acceptance_criteria TEXT,
39
+ complexity_score INTEGER CHECK (complexity_score BETWEEN 1 AND 13),
40
+ story_points INTEGER,
41
+ status TEXT DEFAULT 'draft' CHECK (status IN ('draft','estimated','planned','in_progress','review','qa','qa_failed','pr_submitted','merged')),
42
+ assigned_agent_id TEXT REFERENCES agents(id), branch_name TEXT, pr_url TEXT,
43
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
44
+ );
45
+ CREATE TABLE IF NOT EXISTS story_dependencies (
46
+ story_id TEXT REFERENCES stories(id), depends_on_story_id TEXT REFERENCES stories(id),
47
+ PRIMARY KEY (story_id, depends_on_story_id)
48
+ );
49
+ CREATE TABLE IF NOT EXISTS agent_logs (
50
+ id INTEGER PRIMARY KEY AUTOINCREMENT, agent_id TEXT NOT NULL REFERENCES agents(id),
51
+ story_id TEXT REFERENCES stories(id), event_type TEXT NOT NULL, status TEXT,
52
+ message TEXT, metadata TEXT, timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP
53
+ );
54
+ CREATE INDEX IF NOT EXISTS idx_agent_logs_agent ON agent_logs(agent_id);
55
+ CREATE INDEX IF NOT EXISTS idx_agent_logs_story ON agent_logs(story_id);
56
+ CREATE INDEX IF NOT EXISTS idx_agent_logs_timestamp ON agent_logs(timestamp);
57
+ CREATE TABLE IF NOT EXISTS escalations (
58
+ id TEXT PRIMARY KEY, story_id TEXT REFERENCES stories(id),
59
+ from_agent_id TEXT REFERENCES agents(id), to_agent_id TEXT REFERENCES agents(id),
60
+ reason TEXT NOT NULL,
61
+ status TEXT DEFAULT 'pending' CHECK (status IN ('pending', 'acknowledged', 'resolved')),
62
+ resolution TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, resolved_at TIMESTAMP
63
+ );
64
+ CREATE TABLE IF NOT EXISTS pull_requests (
65
+ id TEXT PRIMARY KEY, story_id TEXT REFERENCES stories(id), team_id TEXT REFERENCES teams(id),
66
+ branch_name TEXT NOT NULL, github_pr_number INTEGER, github_pr_url TEXT,
67
+ submitted_by TEXT, reviewed_by TEXT,
68
+ status TEXT DEFAULT 'queued' CHECK (status IN ('queued','reviewing','approved','merged','rejected','closed')),
69
+ review_notes TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
70
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, reviewed_at TIMESTAMP
71
+ );
72
+ CREATE TABLE IF NOT EXISTS messages (
73
+ id TEXT PRIMARY KEY, from_session TEXT NOT NULL, to_session TEXT NOT NULL,
74
+ subject TEXT, body TEXT NOT NULL, reply TEXT,
75
+ status TEXT DEFAULT 'pending' CHECK (status IN ('pending', 'read', 'replied')),
76
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, replied_at TIMESTAMP
77
+ );
78
+ CREATE TABLE IF NOT EXISTS migrations (
79
+ id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL UNIQUE,
80
+ applied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
81
+ );
82
+ INSERT INTO migrations (name) VALUES ('001-initial.sql');
83
+ INSERT INTO migrations (name) VALUES ('002-add-agent-model.sql');
84
+ INSERT INTO migrations (name) VALUES ('003-fix-pull-requests.sql');
85
+ INSERT INTO migrations (name) VALUES ('004-add-messages.sql');
86
+ INSERT INTO migrations (name) VALUES ('005-add-agent-last-seen.sql');
87
+ INSERT INTO migrations (name) VALUES ('006-add-agent-worktree.sql');
88
+ INSERT INTO migrations (name) VALUES ('007-add-indexes.sql');
89
+ INSERT INTO migrations (name) VALUES ('008-add-godmode.sql');
90
+ INSERT INTO migrations (name) VALUES ('009-add-pr-sync-indexes.sql');
91
+ `);
92
+ if (opts.withData) {
93
+ db.run("INSERT INTO teams VALUES ('t1', 'https://example.com', '/tmp/repo', 'Test Team', datetime('now'))");
94
+ }
95
+ if (opts.withPadding) {
96
+ db.run('CREATE TABLE IF NOT EXISTS padding (id INTEGER PRIMARY KEY, data TEXT)');
97
+ for (let i = 0; i < 500; i++) {
98
+ db.run('INSERT INTO padding VALUES (?, ?)', [i, 'x'.repeat(100)]);
99
+ }
100
+ }
101
+ const data = db.export();
102
+ db.close();
103
+ return data;
104
+ }
105
+ describe('createDatabase', () => {
106
+ let tempDir;
107
+ beforeEach(() => {
108
+ tempDir = mkdtempSync(join(tmpdir(), 'hive-db-test-'));
109
+ });
110
+ afterEach(() => {
111
+ rmSync(tempDir, { recursive: true, force: true });
112
+ });
113
+ it('should create a new database when no file exists', async () => {
114
+ const dbPath = join(tempDir, 'new.db');
115
+ const client = await createDatabase(dbPath);
116
+ expect(client.db).toBeDefined();
117
+ // New database should not auto-save to disk
118
+ expect(existsSync(dbPath)).toBe(false);
119
+ client.close();
120
+ });
121
+ it('should load an existing valid database file', async () => {
122
+ const dbPath = join(tempDir, 'existing.db');
123
+ const data = await createValidDbBuffer({ withData: true });
124
+ writeFileSync(dbPath, Buffer.from(data));
125
+ const client = await createDatabase(dbPath);
126
+ const result = client.db.exec('SELECT COUNT(*) FROM teams');
127
+ expect(result[0].values[0][0]).toBe(1);
128
+ client.close();
129
+ });
130
+ it('should throw DatabaseCorruptionError when sql.js fails to parse buffer', async () => {
131
+ const dbPath = join(tempDir, 'corrupt.db');
132
+ // Write garbage data that is not valid SQLite
133
+ const garbageBuffer = Buffer.alloc(100);
134
+ garbageBuffer.write('NOT_A_SQLITE_DATABASE', 0);
135
+ writeFileSync(dbPath, garbageBuffer);
136
+ await expect(createDatabase(dbPath)).rejects.toThrow(DatabaseCorruptionError);
137
+ await expect(createDatabase(dbPath)).rejects.toThrow('Failed to load database file');
138
+ });
139
+ it('should detect corruption when large file loads with empty core tables', async () => {
140
+ const dbPath = join(tempDir, 'wiped.db');
141
+ // Create a large database with padding but NO data in core tables
142
+ const data = await createValidDbBuffer({ withData: false, withPadding: true });
143
+ writeFileSync(dbPath, Buffer.from(data));
144
+ // Verify the file is >50KB
145
+ expect(Buffer.from(data).length).toBeGreaterThan(50 * 1024);
146
+ await expect(createDatabase(dbPath)).rejects.toThrow(DatabaseCorruptionError);
147
+ await expect(createDatabase(dbPath)).rejects.toThrow('zero rows in core tables');
148
+ });
149
+ it('should NOT flag corruption when file is small (<50KB)', async () => {
150
+ const dbPath = join(tempDir, 'small-empty.db');
151
+ // Create an empty database (no tables yet — migrations will handle it)
152
+ const SQL = await initSqlJs();
153
+ const smallDb = new SQL.Database();
154
+ const data = smallDb.export();
155
+ smallDb.close();
156
+ writeFileSync(dbPath, Buffer.from(data));
157
+ // Verify the file is <50KB
158
+ expect(Buffer.from(data).length).toBeLessThan(50 * 1024);
159
+ // Should pass — small file skips corruption check, migrations create schema
160
+ const client = await createDatabase(dbPath);
161
+ expect(client.db).toBeDefined();
162
+ client.close();
163
+ });
164
+ it('should NOT flag corruption when large file has data in core tables', async () => {
165
+ const dbPath = join(tempDir, 'large-valid.db');
166
+ // Create a large database WITH data in core tables
167
+ const data = await createValidDbBuffer({ withData: true, withPadding: true });
168
+ writeFileSync(dbPath, Buffer.from(data));
169
+ expect(Buffer.from(data).length).toBeGreaterThan(50 * 1024);
170
+ // Should pass — core table has data
171
+ const client = await createDatabase(dbPath);
172
+ expect(client.db).toBeDefined();
173
+ client.close();
174
+ });
175
+ describe('save() backup behavior', () => {
176
+ it('should create a backup file before saving', async () => {
177
+ const dbPath = join(tempDir, 'backup-test.db');
178
+ const backupPath = dbPath + '.bak';
179
+ const client = await createDatabase(dbPath);
180
+ client.save(); // First save — creates the file, no prior file to back up
181
+ expect(existsSync(dbPath)).toBe(true);
182
+ // Save again — now a backup should be created from the existing file
183
+ client.save();
184
+ expect(existsSync(backupPath)).toBe(true);
185
+ client.close();
186
+ });
187
+ it('should preserve backup content from the previous version', async () => {
188
+ const dbPath = join(tempDir, 'backup-content.db');
189
+ const backupPath = dbPath + '.bak';
190
+ const client = await createDatabase(dbPath);
191
+ client.db.run('CREATE TABLE IF NOT EXISTS test_data (val TEXT)');
192
+ client.save(); // version 1
193
+ const firstSaveContent = readFileSync(dbPath);
194
+ // Modify and save again — version 2
195
+ client.db.run("INSERT INTO test_data VALUES ('version2')");
196
+ client.save();
197
+ // Backup should contain version 1's content
198
+ const backupContent = readFileSync(backupPath);
199
+ expect(backupContent).toEqual(firstSaveContent);
200
+ client.close();
201
+ });
202
+ });
203
+ describe('auto-save removal', () => {
204
+ it('should NOT auto-save after initialization of a new database', async () => {
205
+ const dbPath = join(tempDir, 'no-autosave.db');
206
+ await createDatabase(dbPath);
207
+ // File should NOT exist because we removed the auto-save on init
208
+ expect(existsSync(dbPath)).toBe(false);
209
+ });
210
+ it('should NOT auto-save when loading an existing database', async () => {
211
+ const dbPath = join(tempDir, 'no-autosave-existing.db');
212
+ const data = await createValidDbBuffer({ withData: true });
213
+ writeFileSync(dbPath, Buffer.from(data));
214
+ const originalContent = readFileSync(dbPath);
215
+ // Loading should not modify the file on disk
216
+ const client = await createDatabase(dbPath);
217
+ const afterLoadContent = readFileSync(dbPath);
218
+ expect(afterLoadContent).toEqual(originalContent);
219
+ client.close();
220
+ });
221
+ });
222
+ });
223
+ //# sourceMappingURL=client.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.test.js","sourceRoot":"","sources":["../../src/db/client.test.ts"],"names":[],"mappings":"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"}
@@ -59,6 +59,12 @@ export declare class TimeoutError extends HiveError {
59
59
  export declare class NotFoundError extends HiveError {
60
60
  constructor(message: string);
61
61
  }
62
+ /**
63
+ * Database corruption errors (empty DB loaded from non-empty file, parse failures)
64
+ */
65
+ export declare class DatabaseCorruptionError extends HiveError {
66
+ constructor(message: string);
67
+ }
62
68
  /**
63
69
  * Helper function to convert generic errors to Hive errors
64
70
  */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/errors/index.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,qBAAa,SAAU,SAAQ,KAAK;IAClC,SAAgB,IAAI,EAAE,MAAM,CAAC;gBAEjB,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE,MAAqB;CAMzD;AAED;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,SAAS;gBACnC,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,qBAAa,eAAgB,SAAQ,SAAS;gBAChC,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,qBAAa,eAAgB,SAAQ,SAAS;gBAChC,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,qBAAa,gBAAiB,SAAQ,SAAS;gBACjC,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,SAAS;gBACpC,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,qBAAa,gBAAiB,SAAQ,SAAS;gBACjC,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,qBAAa,uBAAwB,SAAQ,SAAS;gBACxC,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,qBAAa,YAAa,SAAQ,SAAS;gBAC7B,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,qBAAa,aAAc,SAAQ,SAAS;gBAC9B,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,YAAY,GAAE,OAAO,SAAqB,GAAG,SAAS,CAQjG"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/errors/index.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,qBAAa,SAAU,SAAQ,KAAK;IAClC,SAAgB,IAAI,EAAE,MAAM,CAAC;gBAEjB,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE,MAAqB;CAMzD;AAED;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,SAAS;gBACnC,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,qBAAa,eAAgB,SAAQ,SAAS;gBAChC,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,qBAAa,eAAgB,SAAQ,SAAS;gBAChC,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,qBAAa,gBAAiB,SAAQ,SAAS;gBACjC,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,SAAS;gBACpC,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,qBAAa,gBAAiB,SAAQ,SAAS;gBACjC,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,qBAAa,uBAAwB,SAAQ,SAAS;gBACxC,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,qBAAa,YAAa,SAAQ,SAAS;gBAC7B,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,qBAAa,aAAc,SAAQ,SAAS;gBAC9B,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,qBAAa,uBAAwB,SAAQ,SAAS;gBACxC,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,YAAY,GAAE,OAAO,SAAqB,GAAG,SAAS,CAQjG"}
@@ -92,6 +92,15 @@ export class NotFoundError extends HiveError {
92
92
  Object.setPrototypeOf(this, NotFoundError.prototype);
93
93
  }
94
94
  }
95
+ /**
96
+ * Database corruption errors (empty DB loaded from non-empty file, parse failures)
97
+ */
98
+ export class DatabaseCorruptionError extends HiveError {
99
+ constructor(message) {
100
+ super(message, 'DATABASE_CORRUPTION_ERROR');
101
+ Object.setPrototypeOf(this, DatabaseCorruptionError.prototype);
102
+ }
103
+ }
95
104
  /**
96
105
  * Helper function to convert generic errors to Hive errors
97
106
  */
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/errors/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/errors/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hungry-ghost-hive",
3
- "version": "0.21.5",
3
+ "version": "0.21.6",
4
4
  "description": "AI Agent Orchestrator - Manages agile software development teams of AI agents",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,276 @@
1
+ import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'fs';
2
+ import { tmpdir } from 'os';
3
+ import { join } from 'path';
4
+ import initSqlJs from 'sql.js';
5
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
6
+ import { DatabaseCorruptionError } from '../errors/index.js';
7
+ import { createDatabase } from './client.js';
8
+
9
+ /**
10
+ * Helper to create a valid SQLite database buffer with the core schema
11
+ * that is compatible with runMigrations().
12
+ */
13
+ async function createValidDbBuffer(
14
+ opts: { withData?: boolean; withPadding?: boolean } = {}
15
+ ): Promise<Uint8Array> {
16
+ const SQL = await initSqlJs();
17
+ const db = new SQL.Database();
18
+
19
+ // Use a schema that matches the initial migration so runMigrations works
20
+ db.run(`
21
+ CREATE TABLE IF NOT EXISTS teams (
22
+ id TEXT PRIMARY KEY, repo_url TEXT NOT NULL, repo_path TEXT NOT NULL,
23
+ name TEXT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
24
+ );
25
+ CREATE TABLE IF NOT EXISTS agents (
26
+ id TEXT PRIMARY KEY,
27
+ type TEXT NOT NULL CHECK (type IN ('tech_lead', 'senior', 'intermediate', 'junior', 'qa')),
28
+ team_id TEXT REFERENCES teams(id), tmux_session TEXT, model TEXT,
29
+ status TEXT DEFAULT 'idle' CHECK (status IN ('idle', 'working', 'blocked', 'terminated')),
30
+ current_story_id TEXT, memory_state TEXT, last_seen TIMESTAMP, worktree_path TEXT,
31
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
32
+ );
33
+ CREATE TABLE IF NOT EXISTS requirements (
34
+ id TEXT PRIMARY KEY, title TEXT NOT NULL, description TEXT NOT NULL,
35
+ submitted_by TEXT DEFAULT 'human',
36
+ status TEXT DEFAULT 'pending' CHECK (status IN ('pending', 'planning', 'planned', 'in_progress', 'completed')),
37
+ godmode BOOLEAN DEFAULT 0, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
38
+ );
39
+ CREATE TABLE IF NOT EXISTS stories (
40
+ id TEXT PRIMARY KEY, requirement_id TEXT REFERENCES requirements(id),
41
+ team_id TEXT REFERENCES teams(id), title TEXT NOT NULL, description TEXT NOT NULL,
42
+ acceptance_criteria TEXT,
43
+ complexity_score INTEGER CHECK (complexity_score BETWEEN 1 AND 13),
44
+ story_points INTEGER,
45
+ status TEXT DEFAULT 'draft' CHECK (status IN ('draft','estimated','planned','in_progress','review','qa','qa_failed','pr_submitted','merged')),
46
+ assigned_agent_id TEXT REFERENCES agents(id), branch_name TEXT, pr_url TEXT,
47
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
48
+ );
49
+ CREATE TABLE IF NOT EXISTS story_dependencies (
50
+ story_id TEXT REFERENCES stories(id), depends_on_story_id TEXT REFERENCES stories(id),
51
+ PRIMARY KEY (story_id, depends_on_story_id)
52
+ );
53
+ CREATE TABLE IF NOT EXISTS agent_logs (
54
+ id INTEGER PRIMARY KEY AUTOINCREMENT, agent_id TEXT NOT NULL REFERENCES agents(id),
55
+ story_id TEXT REFERENCES stories(id), event_type TEXT NOT NULL, status TEXT,
56
+ message TEXT, metadata TEXT, timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP
57
+ );
58
+ CREATE INDEX IF NOT EXISTS idx_agent_logs_agent ON agent_logs(agent_id);
59
+ CREATE INDEX IF NOT EXISTS idx_agent_logs_story ON agent_logs(story_id);
60
+ CREATE INDEX IF NOT EXISTS idx_agent_logs_timestamp ON agent_logs(timestamp);
61
+ CREATE TABLE IF NOT EXISTS escalations (
62
+ id TEXT PRIMARY KEY, story_id TEXT REFERENCES stories(id),
63
+ from_agent_id TEXT REFERENCES agents(id), to_agent_id TEXT REFERENCES agents(id),
64
+ reason TEXT NOT NULL,
65
+ status TEXT DEFAULT 'pending' CHECK (status IN ('pending', 'acknowledged', 'resolved')),
66
+ resolution TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, resolved_at TIMESTAMP
67
+ );
68
+ CREATE TABLE IF NOT EXISTS pull_requests (
69
+ id TEXT PRIMARY KEY, story_id TEXT REFERENCES stories(id), team_id TEXT REFERENCES teams(id),
70
+ branch_name TEXT NOT NULL, github_pr_number INTEGER, github_pr_url TEXT,
71
+ submitted_by TEXT, reviewed_by TEXT,
72
+ status TEXT DEFAULT 'queued' CHECK (status IN ('queued','reviewing','approved','merged','rejected','closed')),
73
+ review_notes TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
74
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, reviewed_at TIMESTAMP
75
+ );
76
+ CREATE TABLE IF NOT EXISTS messages (
77
+ id TEXT PRIMARY KEY, from_session TEXT NOT NULL, to_session TEXT NOT NULL,
78
+ subject TEXT, body TEXT NOT NULL, reply TEXT,
79
+ status TEXT DEFAULT 'pending' CHECK (status IN ('pending', 'read', 'replied')),
80
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, replied_at TIMESTAMP
81
+ );
82
+ CREATE TABLE IF NOT EXISTS migrations (
83
+ id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL UNIQUE,
84
+ applied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
85
+ );
86
+ INSERT INTO migrations (name) VALUES ('001-initial.sql');
87
+ INSERT INTO migrations (name) VALUES ('002-add-agent-model.sql');
88
+ INSERT INTO migrations (name) VALUES ('003-fix-pull-requests.sql');
89
+ INSERT INTO migrations (name) VALUES ('004-add-messages.sql');
90
+ INSERT INTO migrations (name) VALUES ('005-add-agent-last-seen.sql');
91
+ INSERT INTO migrations (name) VALUES ('006-add-agent-worktree.sql');
92
+ INSERT INTO migrations (name) VALUES ('007-add-indexes.sql');
93
+ INSERT INTO migrations (name) VALUES ('008-add-godmode.sql');
94
+ INSERT INTO migrations (name) VALUES ('009-add-pr-sync-indexes.sql');
95
+ `);
96
+
97
+ if (opts.withData) {
98
+ db.run(
99
+ "INSERT INTO teams VALUES ('t1', 'https://example.com', '/tmp/repo', 'Test Team', datetime('now'))"
100
+ );
101
+ }
102
+
103
+ if (opts.withPadding) {
104
+ db.run('CREATE TABLE IF NOT EXISTS padding (id INTEGER PRIMARY KEY, data TEXT)');
105
+ for (let i = 0; i < 500; i++) {
106
+ db.run('INSERT INTO padding VALUES (?, ?)', [i, 'x'.repeat(100)]);
107
+ }
108
+ }
109
+
110
+ const data = db.export();
111
+ db.close();
112
+ return data;
113
+ }
114
+
115
+ describe('createDatabase', () => {
116
+ let tempDir: string;
117
+
118
+ beforeEach(() => {
119
+ tempDir = mkdtempSync(join(tmpdir(), 'hive-db-test-'));
120
+ });
121
+
122
+ afterEach(() => {
123
+ rmSync(tempDir, { recursive: true, force: true });
124
+ });
125
+
126
+ it('should create a new database when no file exists', async () => {
127
+ const dbPath = join(tempDir, 'new.db');
128
+ const client = await createDatabase(dbPath);
129
+
130
+ expect(client.db).toBeDefined();
131
+ // New database should not auto-save to disk
132
+ expect(existsSync(dbPath)).toBe(false);
133
+
134
+ client.close();
135
+ });
136
+
137
+ it('should load an existing valid database file', async () => {
138
+ const dbPath = join(tempDir, 'existing.db');
139
+
140
+ const data = await createValidDbBuffer({ withData: true });
141
+ writeFileSync(dbPath, Buffer.from(data));
142
+
143
+ const client = await createDatabase(dbPath);
144
+ const result = client.db.exec('SELECT COUNT(*) FROM teams');
145
+ expect(result[0].values[0][0]).toBe(1);
146
+
147
+ client.close();
148
+ });
149
+
150
+ it('should throw DatabaseCorruptionError when sql.js fails to parse buffer', async () => {
151
+ const dbPath = join(tempDir, 'corrupt.db');
152
+
153
+ // Write garbage data that is not valid SQLite
154
+ const garbageBuffer = Buffer.alloc(100);
155
+ garbageBuffer.write('NOT_A_SQLITE_DATABASE', 0);
156
+ writeFileSync(dbPath, garbageBuffer);
157
+
158
+ await expect(createDatabase(dbPath)).rejects.toThrow(DatabaseCorruptionError);
159
+ await expect(createDatabase(dbPath)).rejects.toThrow('Failed to load database file');
160
+ });
161
+
162
+ it('should detect corruption when large file loads with empty core tables', async () => {
163
+ const dbPath = join(tempDir, 'wiped.db');
164
+
165
+ // Create a large database with padding but NO data in core tables
166
+ const data = await createValidDbBuffer({ withData: false, withPadding: true });
167
+ writeFileSync(dbPath, Buffer.from(data));
168
+
169
+ // Verify the file is >50KB
170
+ expect(Buffer.from(data).length).toBeGreaterThan(50 * 1024);
171
+
172
+ await expect(createDatabase(dbPath)).rejects.toThrow(DatabaseCorruptionError);
173
+ await expect(createDatabase(dbPath)).rejects.toThrow('zero rows in core tables');
174
+ });
175
+
176
+ it('should NOT flag corruption when file is small (<50KB)', async () => {
177
+ const dbPath = join(tempDir, 'small-empty.db');
178
+
179
+ // Create an empty database (no tables yet — migrations will handle it)
180
+ const SQL = await initSqlJs();
181
+ const smallDb = new SQL.Database();
182
+ const data = smallDb.export();
183
+ smallDb.close();
184
+ writeFileSync(dbPath, Buffer.from(data));
185
+
186
+ // Verify the file is <50KB
187
+ expect(Buffer.from(data).length).toBeLessThan(50 * 1024);
188
+
189
+ // Should pass — small file skips corruption check, migrations create schema
190
+ const client = await createDatabase(dbPath);
191
+ expect(client.db).toBeDefined();
192
+ client.close();
193
+ });
194
+
195
+ it('should NOT flag corruption when large file has data in core tables', async () => {
196
+ const dbPath = join(tempDir, 'large-valid.db');
197
+
198
+ // Create a large database WITH data in core tables
199
+ const data = await createValidDbBuffer({ withData: true, withPadding: true });
200
+ writeFileSync(dbPath, Buffer.from(data));
201
+
202
+ expect(Buffer.from(data).length).toBeGreaterThan(50 * 1024);
203
+
204
+ // Should pass — core table has data
205
+ const client = await createDatabase(dbPath);
206
+ expect(client.db).toBeDefined();
207
+ client.close();
208
+ });
209
+
210
+ describe('save() backup behavior', () => {
211
+ it('should create a backup file before saving', async () => {
212
+ const dbPath = join(tempDir, 'backup-test.db');
213
+ const backupPath = dbPath + '.bak';
214
+
215
+ const client = await createDatabase(dbPath);
216
+ client.save(); // First save — creates the file, no prior file to back up
217
+
218
+ expect(existsSync(dbPath)).toBe(true);
219
+
220
+ // Save again — now a backup should be created from the existing file
221
+ client.save();
222
+ expect(existsSync(backupPath)).toBe(true);
223
+
224
+ client.close();
225
+ });
226
+
227
+ it('should preserve backup content from the previous version', async () => {
228
+ const dbPath = join(tempDir, 'backup-content.db');
229
+ const backupPath = dbPath + '.bak';
230
+
231
+ const client = await createDatabase(dbPath);
232
+ client.db.run('CREATE TABLE IF NOT EXISTS test_data (val TEXT)');
233
+ client.save(); // version 1
234
+
235
+ const firstSaveContent = readFileSync(dbPath);
236
+
237
+ // Modify and save again — version 2
238
+ client.db.run("INSERT INTO test_data VALUES ('version2')");
239
+ client.save();
240
+
241
+ // Backup should contain version 1's content
242
+ const backupContent = readFileSync(backupPath);
243
+ expect(backupContent).toEqual(firstSaveContent);
244
+
245
+ client.close();
246
+ });
247
+ });
248
+
249
+ describe('auto-save removal', () => {
250
+ it('should NOT auto-save after initialization of a new database', async () => {
251
+ const dbPath = join(tempDir, 'no-autosave.db');
252
+
253
+ await createDatabase(dbPath);
254
+
255
+ // File should NOT exist because we removed the auto-save on init
256
+ expect(existsSync(dbPath)).toBe(false);
257
+ });
258
+
259
+ it('should NOT auto-save when loading an existing database', async () => {
260
+ const dbPath = join(tempDir, 'no-autosave-existing.db');
261
+
262
+ const data = await createValidDbBuffer({ withData: true });
263
+ writeFileSync(dbPath, Buffer.from(data));
264
+
265
+ const originalContent = readFileSync(dbPath);
266
+
267
+ // Loading should not modify the file on disk
268
+ const client = await createDatabase(dbPath);
269
+
270
+ const afterLoadContent = readFileSync(dbPath);
271
+ expect(afterLoadContent).toEqual(originalContent);
272
+
273
+ client.close();
274
+ });
275
+ });
276
+ });
package/src/db/client.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  // Licensed under the Hungry Ghost Hive License. See LICENSE.
2
2
 
3
- import { existsSync, readFileSync, writeFileSync } from 'fs';
3
+ import { copyFileSync, existsSync, readFileSync, statSync, writeFileSync } from 'fs';
4
4
  import { join } from 'path';
5
5
  import initSqlJs, { Database as SqlJsDatabase } from 'sql.js';
6
- import { InitializationError } from '../errors/index.js';
6
+ import { DatabaseCorruptionError, InitializationError } from '../errors/index.js';
7
7
 
8
8
  export interface DatabaseClient {
9
9
  db: SqlJsDatabase;
@@ -162,33 +162,96 @@ async function getSqlJs(): Promise<typeof SQL> {
162
162
  return SQL;
163
163
  }
164
164
 
165
+ // Minimum file size (in bytes) that indicates a database had meaningful data.
166
+ // Files below this threshold are likely new or schema-only databases.
167
+ const CORRUPTION_CHECK_MIN_FILE_SIZE = 50 * 1024; // 50KB
168
+
169
+ // Core tables that should have rows in a populated database
170
+ const CORE_TABLES = ['teams', 'agents', 'stories'];
171
+
172
+ /**
173
+ * Validate that a loaded database is not a silently-corrupted empty copy.
174
+ * If the source file was large (>50KB) but the loaded DB has core tables
175
+ * with zero rows, that indicates sql.js silently returned an empty DB.
176
+ */
177
+ function validateLoadedDatabase(db: SqlJsDatabase, fileSize: number): void {
178
+ if (fileSize < CORRUPTION_CHECK_MIN_FILE_SIZE) {
179
+ return; // Small file — likely a new or schema-only DB, skip validation
180
+ }
181
+
182
+ // Check if any core table has data
183
+ for (const table of CORE_TABLES) {
184
+ try {
185
+ const result = db.exec(`SELECT COUNT(*) FROM ${table}`);
186
+ if (result.length > 0 && (result[0].values[0][0] as number) > 0) {
187
+ return; // At least one core table has data — DB looks valid
188
+ }
189
+ } catch {
190
+ // Table doesn't exist yet — that's fine, migrations haven't run
191
+ continue;
192
+ }
193
+ }
194
+
195
+ // File was large but all core tables are empty — likely corruption
196
+ throw new DatabaseCorruptionError(
197
+ `Database file is ${fileSize} bytes but loaded with zero rows in core tables (${CORE_TABLES.join(', ')}). ` +
198
+ 'This likely indicates a corrupted or partially-read database file. ' +
199
+ 'Refusing to proceed to prevent data loss. Check the backup at hive.db.bak if available.'
200
+ );
201
+ }
202
+
165
203
  export async function createDatabase(dbPath: string): Promise<DatabaseClient> {
166
204
  const SqlJs = await getSqlJs();
167
205
  if (!SqlJs) throw new InitializationError('Failed to initialize sql.js');
168
206
 
169
207
  let db: SqlJsDatabase;
208
+ const backupPath = dbPath + '.bak';
170
209
 
171
210
  // Load existing database or create new one
172
211
  if (existsSync(dbPath)) {
173
212
  const buffer = readFileSync(dbPath);
174
- db = new SqlJs.Database(buffer);
213
+ const fileSize = statSync(dbPath).size;
214
+
215
+ try {
216
+ db = new SqlJs.Database(buffer);
217
+ // Verify the database is usable by running a basic command
218
+ db.run('PRAGMA foreign_keys = ON');
219
+ db.exec('SELECT 1');
220
+ } catch (error) {
221
+ throw new DatabaseCorruptionError(
222
+ `Failed to load database file at ${dbPath}: ${error instanceof Error ? error.message : String(error)}`
223
+ );
224
+ }
225
+
226
+ // Validate the loaded DB is not silently empty from a corrupt file
227
+ validateLoadedDatabase(db, fileSize);
228
+
229
+ // Run migrations on loaded DB — wrap in try-catch to detect subtle corruption
230
+ try {
231
+ runMigrations(db);
232
+ } catch (error) {
233
+ throw new DatabaseCorruptionError(
234
+ `Database file at ${dbPath} appears corrupted (migrations failed): ${error instanceof Error ? error.message : String(error)}`
235
+ );
236
+ }
175
237
  } else {
176
238
  db = new SqlJs.Database();
239
+ // Enable foreign keys
240
+ db.run('PRAGMA foreign_keys = ON');
241
+ // Run migrations on new DB
242
+ runMigrations(db);
177
243
  }
178
244
 
179
- // Enable foreign keys
180
- db.run('PRAGMA foreign_keys = ON');
181
-
182
245
  const save = () => {
246
+ // Write backup before overwriting the main database file
247
+ if (existsSync(dbPath)) {
248
+ copyFileSync(dbPath, backupPath);
249
+ }
183
250
  const data = db.export();
184
251
  const buffer = Buffer.from(data);
185
252
  writeFileSync(dbPath, buffer);
186
253
  };
187
254
 
188
- // Auto-run migrations
189
- runMigrations(db);
190
- save();
191
-
192
255
  const client: DatabaseClient = {
193
256
  db,
194
257
  close: () => {
@@ -104,6 +104,16 @@ export class NotFoundError extends HiveError {
104
104
  }
105
105
  }
106
106
 
107
+ /**
108
+ * Database corruption errors (empty DB loaded from non-empty file, parse failures)
109
+ */
110
+ export class DatabaseCorruptionError extends HiveError {
111
+ constructor(message: string) {
112
+ super(message, 'DATABASE_CORRUPTION_ERROR');
113
+ Object.setPrototypeOf(this, DatabaseCorruptionError.prototype);
114
+ }
115
+ }
116
+
107
117
  /**
108
118
  * Helper function to convert generic errors to Hive errors
109
119
  */