agentic-qe 3.6.6 → 3.6.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/.claude/skills/skills-manifest.json +1 -1
  2. package/package.json +1 -1
  3. package/v3/CHANGELOG.md +28 -0
  4. package/v3/dist/cli/bundle.js +747 -147
  5. package/v3/dist/cli/commands/hooks.d.ts.map +1 -1
  6. package/v3/dist/cli/commands/hooks.js +172 -31
  7. package/v3/dist/cli/commands/hooks.js.map +1 -1
  8. package/v3/dist/coordination/dynamic-scaling/dynamic-scaler.d.ts +21 -0
  9. package/v3/dist/coordination/dynamic-scaling/dynamic-scaler.d.ts.map +1 -1
  10. package/v3/dist/coordination/dynamic-scaling/dynamic-scaler.js +76 -0
  11. package/v3/dist/coordination/dynamic-scaling/dynamic-scaler.js.map +1 -1
  12. package/v3/dist/coordination/mincut/mincut-persistence.d.ts +4 -0
  13. package/v3/dist/coordination/mincut/mincut-persistence.d.ts.map +1 -1
  14. package/v3/dist/coordination/mincut/mincut-persistence.js +30 -0
  15. package/v3/dist/coordination/mincut/mincut-persistence.js.map +1 -1
  16. package/v3/dist/coordination/mincut/time-crystal.d.ts +22 -0
  17. package/v3/dist/coordination/mincut/time-crystal.d.ts.map +1 -1
  18. package/v3/dist/coordination/mincut/time-crystal.js +95 -0
  19. package/v3/dist/coordination/mincut/time-crystal.js.map +1 -1
  20. package/v3/dist/domains/code-intelligence/coordinator.d.ts.map +1 -1
  21. package/v3/dist/domains/code-intelligence/coordinator.js +6 -3
  22. package/v3/dist/domains/code-intelligence/coordinator.js.map +1 -1
  23. package/v3/dist/domains/code-intelligence/services/knowledge-graph.d.ts.map +1 -1
  24. package/v3/dist/domains/code-intelligence/services/knowledge-graph.js +19 -34
  25. package/v3/dist/domains/code-intelligence/services/knowledge-graph.js.map +1 -1
  26. package/v3/dist/domains/coverage-analysis/services/hnsw-index.d.ts.map +1 -1
  27. package/v3/dist/domains/coverage-analysis/services/hnsw-index.js +5 -3
  28. package/v3/dist/domains/coverage-analysis/services/hnsw-index.js.map +1 -1
  29. package/v3/dist/domains/security-compliance/services/scanners/sast-scanner.d.ts.map +1 -1
  30. package/v3/dist/domains/security-compliance/services/scanners/sast-scanner.js +7 -3
  31. package/v3/dist/domains/security-compliance/services/scanners/sast-scanner.js.map +1 -1
  32. package/v3/dist/early-exit/early-exit-controller.d.ts +20 -0
  33. package/v3/dist/early-exit/early-exit-controller.d.ts.map +1 -1
  34. package/v3/dist/early-exit/early-exit-controller.js +72 -0
  35. package/v3/dist/early-exit/early-exit-controller.js.map +1 -1
  36. package/v3/dist/feedback/coverage-learner.d.ts +19 -0
  37. package/v3/dist/feedback/coverage-learner.d.ts.map +1 -1
  38. package/v3/dist/feedback/coverage-learner.js +134 -0
  39. package/v3/dist/feedback/coverage-learner.js.map +1 -1
  40. package/v3/dist/feedback/feedback-loop.d.ts +10 -1
  41. package/v3/dist/feedback/feedback-loop.d.ts.map +1 -1
  42. package/v3/dist/feedback/feedback-loop.js +20 -1
  43. package/v3/dist/feedback/feedback-loop.js.map +1 -1
  44. package/v3/dist/feedback/index.d.ts +1 -1
  45. package/v3/dist/feedback/index.d.ts.map +1 -1
  46. package/v3/dist/feedback/index.js +1 -1
  47. package/v3/dist/feedback/index.js.map +1 -1
  48. package/v3/dist/feedback/test-outcome-tracker.d.ts +19 -0
  49. package/v3/dist/feedback/test-outcome-tracker.d.ts.map +1 -1
  50. package/v3/dist/feedback/test-outcome-tracker.js +114 -0
  51. package/v3/dist/feedback/test-outcome-tracker.js.map +1 -1
  52. package/v3/dist/governance/compliance-reporter.d.ts +13 -0
  53. package/v3/dist/governance/compliance-reporter.d.ts.map +1 -1
  54. package/v3/dist/governance/compliance-reporter.js +63 -0
  55. package/v3/dist/governance/compliance-reporter.js.map +1 -1
  56. package/v3/dist/governance/continue-gate-integration.d.ts +8 -0
  57. package/v3/dist/governance/continue-gate-integration.d.ts.map +1 -1
  58. package/v3/dist/governance/continue-gate-integration.js +50 -2
  59. package/v3/dist/governance/continue-gate-integration.js.map +1 -1
  60. package/v3/dist/governance/evolution-pipeline-integration.d.ts +13 -0
  61. package/v3/dist/governance/evolution-pipeline-integration.d.ts.map +1 -1
  62. package/v3/dist/governance/evolution-pipeline-integration.js +53 -0
  63. package/v3/dist/governance/evolution-pipeline-integration.js.map +1 -1
  64. package/v3/dist/index.d.ts +1 -1
  65. package/v3/dist/index.d.ts.map +1 -1
  66. package/v3/dist/index.js +1 -1
  67. package/v3/dist/index.js.map +1 -1
  68. package/v3/dist/init/phases/07-hooks.d.ts.map +1 -1
  69. package/v3/dist/init/phases/07-hooks.js +26 -5
  70. package/v3/dist/init/phases/07-hooks.js.map +1 -1
  71. package/v3/dist/integrations/ruvector/ast-complexity.d.ts +8 -0
  72. package/v3/dist/integrations/ruvector/ast-complexity.d.ts.map +1 -1
  73. package/v3/dist/integrations/ruvector/ast-complexity.js +45 -0
  74. package/v3/dist/integrations/ruvector/ast-complexity.js.map +1 -1
  75. package/v3/dist/integrations/ruvector/attention-wrapper.d.ts +18 -1
  76. package/v3/dist/integrations/ruvector/attention-wrapper.d.ts.map +1 -1
  77. package/v3/dist/integrations/ruvector/attention-wrapper.js +60 -2
  78. package/v3/dist/integrations/ruvector/attention-wrapper.js.map +1 -1
  79. package/v3/dist/integrations/ruvector/coverage-router.d.ts +8 -0
  80. package/v3/dist/integrations/ruvector/coverage-router.d.ts.map +1 -1
  81. package/v3/dist/integrations/ruvector/coverage-router.js +45 -0
  82. package/v3/dist/integrations/ruvector/coverage-router.js.map +1 -1
  83. package/v3/dist/integrations/ruvector/diff-risk-classifier.d.ts +8 -0
  84. package/v3/dist/integrations/ruvector/diff-risk-classifier.d.ts.map +1 -1
  85. package/v3/dist/integrations/ruvector/diff-risk-classifier.js +45 -0
  86. package/v3/dist/integrations/ruvector/diff-risk-classifier.js.map +1 -1
  87. package/v3/dist/integrations/ruvector/graph-boundaries.d.ts +8 -0
  88. package/v3/dist/integrations/ruvector/graph-boundaries.d.ts.map +1 -1
  89. package/v3/dist/integrations/ruvector/graph-boundaries.js +45 -0
  90. package/v3/dist/integrations/ruvector/graph-boundaries.js.map +1 -1
  91. package/v3/dist/integrations/ruvector/index.d.ts.map +1 -1
  92. package/v3/dist/integrations/ruvector/index.js +5 -20
  93. package/v3/dist/integrations/ruvector/index.js.map +1 -1
  94. package/v3/dist/integrations/ruvector/persistent-q-router.d.ts +7 -3
  95. package/v3/dist/integrations/ruvector/persistent-q-router.d.ts.map +1 -1
  96. package/v3/dist/integrations/ruvector/persistent-q-router.js +7 -3
  97. package/v3/dist/integrations/ruvector/persistent-q-router.js.map +1 -1
  98. package/v3/dist/integrations/ruvector/q-learning-router.d.ts +13 -0
  99. package/v3/dist/integrations/ruvector/q-learning-router.d.ts.map +1 -1
  100. package/v3/dist/integrations/ruvector/q-learning-router.js +67 -0
  101. package/v3/dist/integrations/ruvector/q-learning-router.js.map +1 -1
  102. package/v3/dist/kernel/hybrid-backend.d.ts +1 -0
  103. package/v3/dist/kernel/hybrid-backend.d.ts.map +1 -1
  104. package/v3/dist/kernel/hybrid-backend.js +39 -0
  105. package/v3/dist/kernel/hybrid-backend.js.map +1 -1
  106. package/v3/dist/kernel/unified-memory.d.ts +1 -0
  107. package/v3/dist/kernel/unified-memory.d.ts.map +1 -1
  108. package/v3/dist/kernel/unified-memory.js +116 -4
  109. package/v3/dist/kernel/unified-memory.js.map +1 -1
  110. package/v3/dist/learning/experience-capture-middleware.d.ts.map +1 -1
  111. package/v3/dist/learning/experience-capture-middleware.js +45 -18
  112. package/v3/dist/learning/experience-capture-middleware.js.map +1 -1
  113. package/v3/dist/learning/pattern-store.d.ts.map +1 -1
  114. package/v3/dist/learning/pattern-store.js +12 -61
  115. package/v3/dist/learning/pattern-store.js.map +1 -1
  116. package/v3/dist/learning/qe-reasoning-bank.d.ts.map +1 -1
  117. package/v3/dist/learning/qe-reasoning-bank.js +15 -2
  118. package/v3/dist/learning/qe-reasoning-bank.js.map +1 -1
  119. package/v3/dist/learning/token-tracker.d.ts +23 -0
  120. package/v3/dist/learning/token-tracker.d.ts.map +1 -1
  121. package/v3/dist/learning/token-tracker.js +91 -0
  122. package/v3/dist/learning/token-tracker.js.map +1 -1
  123. package/v3/dist/mcp/bundle.js +635 -128
  124. package/v3/dist/routing/routing-feedback.d.ts +21 -0
  125. package/v3/dist/routing/routing-feedback.d.ts.map +1 -1
  126. package/v3/dist/routing/routing-feedback.js +95 -0
  127. package/v3/dist/routing/routing-feedback.js.map +1 -1
  128. package/v3/dist/shared/sql-safety.d.ts.map +1 -1
  129. package/v3/dist/shared/sql-safety.js +2 -0
  130. package/v3/dist/shared/sql-safety.js.map +1 -1
  131. package/v3/package.json +1 -1
@@ -595,6 +595,10 @@ var init_sql_safety = __esm({
595
595
  "mincut_observations",
596
596
  // SONA tables
597
597
  "sona_patterns",
598
+ // Feedback loop tables
599
+ "test_outcomes",
600
+ "routing_outcomes",
601
+ "coverage_sessions",
598
602
  // Sync tables
599
603
  "patterns",
600
604
  // Hypergraph tables
@@ -1539,12 +1543,16 @@ function findProjectRoot(startDir = process.cwd()) {
1539
1543
  let dir = startDir;
1540
1544
  const root = path.parse(dir).root;
1541
1545
  let checkDir = dir;
1546
+ let topmostAqeDir = null;
1542
1547
  while (checkDir !== root) {
1543
1548
  if (fs.existsSync(path.join(checkDir, ".agentic-qe"))) {
1544
- return checkDir;
1549
+ topmostAqeDir = checkDir;
1545
1550
  }
1546
1551
  checkDir = path.dirname(checkDir);
1547
1552
  }
1553
+ if (topmostAqeDir) {
1554
+ return topmostAqeDir;
1555
+ }
1548
1556
  checkDir = dir;
1549
1557
  while (checkDir !== root) {
1550
1558
  if (fs.existsSync(path.join(checkDir, ".git"))) {
@@ -1609,7 +1617,7 @@ function registerExitHandlers() {
1609
1617
  process.exit(0);
1610
1618
  });
1611
1619
  }
1612
- var DEFAULT_UNIFIED_MEMORY_CONFIG, SCHEMA_VERSION, SCHEMA_VERSION_TABLE, KV_STORE_SCHEMA, VECTORS_SCHEMA, RL_QVALUES_SCHEMA, GOAP_SCHEMA, DREAM_SCHEMA, QE_PATTERNS_SCHEMA, MINCUT_SCHEMA, SONA_PATTERNS_SCHEMA, BinaryHeap, InMemoryHNSWIndex, UnifiedMemoryManager, exitHandlersRegistered;
1620
+ var DEFAULT_UNIFIED_MEMORY_CONFIG, SCHEMA_VERSION, SCHEMA_VERSION_TABLE, KV_STORE_SCHEMA, VECTORS_SCHEMA, RL_QVALUES_SCHEMA, GOAP_SCHEMA, DREAM_SCHEMA, QE_PATTERNS_SCHEMA, MINCUT_SCHEMA, SONA_PATTERNS_SCHEMA, FEEDBACK_SCHEMA, BinaryHeap, InMemoryHNSWIndex, UnifiedMemoryManager, exitHandlersRegistered;
1613
1621
  var init_unified_memory = __esm({
1614
1622
  "src/kernel/unified-memory.ts"() {
1615
1623
  "use strict";
@@ -1629,7 +1637,7 @@ var init_unified_memory = __esm({
1629
1637
  busyTimeout: MEMORY_CONSTANTS.BUSY_TIMEOUT_MS,
1630
1638
  vectorDimensions: MEMORY_CONSTANTS.DEFAULT_VECTOR_DIMENSIONS
1631
1639
  };
1632
- SCHEMA_VERSION = 7;
1640
+ SCHEMA_VERSION = 8;
1633
1641
  SCHEMA_VERSION_TABLE = `
1634
1642
  CREATE TABLE IF NOT EXISTS schema_version (
1635
1643
  id INTEGER PRIMARY KEY CHECK (id = 1),
@@ -2100,6 +2108,81 @@ var init_unified_memory = __esm({
2100
2108
  CREATE INDEX IF NOT EXISTS idx_sona_patterns_domain ON sona_patterns(domain);
2101
2109
  CREATE INDEX IF NOT EXISTS idx_sona_patterns_confidence ON sona_patterns(confidence DESC);
2102
2110
  CREATE INDEX IF NOT EXISTS idx_sona_patterns_updated ON sona_patterns(updated_at DESC);
2111
+ `;
2112
+ FEEDBACK_SCHEMA = `
2113
+ -- Test outcomes (ADR-023: Quality Feedback Loop)
2114
+ CREATE TABLE IF NOT EXISTS test_outcomes (
2115
+ id TEXT PRIMARY KEY,
2116
+ test_id TEXT NOT NULL,
2117
+ test_name TEXT NOT NULL,
2118
+ generated_by TEXT NOT NULL,
2119
+ pattern_id TEXT,
2120
+ framework TEXT NOT NULL,
2121
+ language TEXT NOT NULL,
2122
+ domain TEXT NOT NULL,
2123
+ passed INTEGER NOT NULL,
2124
+ error_message TEXT,
2125
+ coverage_lines REAL DEFAULT 0,
2126
+ coverage_branches REAL DEFAULT 0,
2127
+ coverage_functions REAL DEFAULT 0,
2128
+ mutation_score REAL,
2129
+ execution_time_ms REAL NOT NULL,
2130
+ flaky INTEGER DEFAULT 0,
2131
+ flakiness_score REAL,
2132
+ maintainability_score REAL NOT NULL,
2133
+ complexity REAL,
2134
+ lines_of_code INTEGER,
2135
+ assertion_count INTEGER,
2136
+ file_path TEXT,
2137
+ source_file_path TEXT,
2138
+ metadata_json TEXT,
2139
+ created_at TEXT DEFAULT (datetime('now'))
2140
+ );
2141
+ CREATE INDEX IF NOT EXISTS idx_test_outcomes_pattern ON test_outcomes(pattern_id);
2142
+ CREATE INDEX IF NOT EXISTS idx_test_outcomes_agent ON test_outcomes(generated_by);
2143
+ CREATE INDEX IF NOT EXISTS idx_test_outcomes_domain ON test_outcomes(domain);
2144
+ CREATE INDEX IF NOT EXISTS idx_test_outcomes_created ON test_outcomes(created_at);
2145
+
2146
+ -- Routing outcomes (ADR-022: Adaptive QE Agent Routing)
2147
+ CREATE TABLE IF NOT EXISTS routing_outcomes (
2148
+ id TEXT PRIMARY KEY,
2149
+ task_json TEXT NOT NULL,
2150
+ decision_json TEXT NOT NULL,
2151
+ used_agent TEXT NOT NULL,
2152
+ followed_recommendation INTEGER NOT NULL,
2153
+ success INTEGER NOT NULL,
2154
+ quality_score REAL NOT NULL,
2155
+ duration_ms REAL NOT NULL,
2156
+ error TEXT,
2157
+ created_at TEXT DEFAULT (datetime('now'))
2158
+ );
2159
+ CREATE INDEX IF NOT EXISTS idx_routing_outcomes_agent ON routing_outcomes(used_agent);
2160
+ CREATE INDEX IF NOT EXISTS idx_routing_outcomes_created ON routing_outcomes(created_at);
2161
+
2162
+ -- Coverage sessions (ADR-023: Coverage Learning)
2163
+ CREATE TABLE IF NOT EXISTS coverage_sessions (
2164
+ id TEXT PRIMARY KEY,
2165
+ target_path TEXT NOT NULL,
2166
+ agent_id TEXT NOT NULL,
2167
+ technique TEXT NOT NULL,
2168
+ before_lines REAL DEFAULT 0,
2169
+ before_branches REAL DEFAULT 0,
2170
+ before_functions REAL DEFAULT 0,
2171
+ after_lines REAL DEFAULT 0,
2172
+ after_branches REAL DEFAULT 0,
2173
+ after_functions REAL DEFAULT 0,
2174
+ tests_generated INTEGER DEFAULT 0,
2175
+ tests_passed INTEGER DEFAULT 0,
2176
+ gaps_json TEXT,
2177
+ duration_ms REAL NOT NULL,
2178
+ started_at TEXT NOT NULL,
2179
+ completed_at TEXT NOT NULL,
2180
+ context_json TEXT,
2181
+ created_at TEXT DEFAULT (datetime('now'))
2182
+ );
2183
+ CREATE INDEX IF NOT EXISTS idx_coverage_sessions_technique ON coverage_sessions(technique);
2184
+ CREATE INDEX IF NOT EXISTS idx_coverage_sessions_agent ON coverage_sessions(agent_id);
2185
+ CREATE INDEX IF NOT EXISTS idx_coverage_sessions_created ON coverage_sessions(created_at);
2103
2186
  `;
2104
2187
  BinaryHeap = class {
2105
2188
  data = [];
@@ -2439,6 +2522,7 @@ var init_unified_memory = __esm({
2439
2522
  db = null;
2440
2523
  config;
2441
2524
  initialized = false;
2525
+ vectorsLoaded = false;
2442
2526
  initPromise = null;
2443
2527
  preparedStatements = /* @__PURE__ */ new Map();
2444
2528
  vectorIndex = new InMemoryHNSWIndex();
@@ -2516,7 +2600,7 @@ var init_unified_memory = __esm({
2516
2600
  this.db.pragma(`busy_timeout = ${this.config.busyTimeout}`);
2517
2601
  this.db.pragma("foreign_keys = ON");
2518
2602
  await this.runMigrations();
2519
- await this.loadVectorIndex();
2603
+ this.vectorsLoaded = false;
2520
2604
  this.initialized = true;
2521
2605
  console.log(`[UnifiedMemory] Initialized: ${this.config.dbPath}`);
2522
2606
  this.warnIfDuplicateDatabases();
@@ -2637,6 +2721,9 @@ var init_unified_memory = __esm({
2637
2721
  if (currentVersion < 7) {
2638
2722
  this.db.exec(SONA_PATTERNS_SCHEMA);
2639
2723
  }
2724
+ if (currentVersion < 8) {
2725
+ this.db.exec(FEEDBACK_SCHEMA);
2726
+ }
2640
2727
  this.db.prepare(`
2641
2728
  INSERT OR REPLACE INTO schema_version (id, version, migrated_at)
2642
2729
  VALUES (1, ?, datetime('now'))
@@ -2650,6 +2737,7 @@ var init_unified_memory = __esm({
2650
2737
  * Load all vectors from SQLite into HNSW index
2651
2738
  */
2652
2739
  async loadVectorIndex() {
2740
+ if (this.vectorsLoaded) return;
2653
2741
  if (!this.db) throw new Error("Database not initialized");
2654
2742
  this.vectorIndex.clear();
2655
2743
  const rows = this.db.prepare(
@@ -2659,6 +2747,7 @@ var init_unified_memory = __esm({
2659
2747
  const embedding = this.bufferToFloatArray(row.embedding, row.dimensions);
2660
2748
  this.vectorIndex.add(row.id, embedding);
2661
2749
  }
2750
+ this.vectorsLoaded = true;
2662
2751
  console.log(`[UnifiedMemory] Loaded ${rows.length} vectors into HNSW index`);
2663
2752
  }
2664
2753
  // ============================================================================
@@ -2782,6 +2871,9 @@ var init_unified_memory = __esm({
2782
2871
  */
2783
2872
  async vectorSearch(query, k68 = 10, namespace) {
2784
2873
  this.ensureInitialized();
2874
+ if (!this.vectorsLoaded) {
2875
+ await this.loadVectorIndex();
2876
+ }
2785
2877
  const results = this.vectorIndex.search(query, k68 * 2);
2786
2878
  if (results.length === 0) return [];
2787
2879
  const ids = results.map((r54) => r54.id);
@@ -6940,6 +7032,7 @@ var init_attention_wrapper = __esm({
6940
7032
  "src/integrations/ruvector/attention-wrapper.ts"() {
6941
7033
  "use strict";
6942
7034
  init_attention();
7035
+ init_unified_memory();
6943
7036
  QE_FLASH_ATTENTION_CONFIG = {
6944
7037
  "test-similarity": {
6945
7038
  dim: 384,
@@ -7053,11 +7146,19 @@ var init_attention_wrapper = __esm({
7053
7146
  }
7054
7147
  }
7055
7148
  };
7056
- QEFlashAttention = class {
7149
+ QEFlashAttention = class _QEFlashAttention {
7057
7150
  attention;
7058
7151
  config;
7059
7152
  workload;
7060
7153
  metrics = [];
7154
+ // kv_store persistence
7155
+ db = null;
7156
+ persistCount = 0;
7157
+ static KV_NAMESPACE = "attention-metrics";
7158
+ static KV_TTL = 3600;
7159
+ // 1 hour
7160
+ static PERSIST_INTERVAL = 10;
7161
+ // every 10 operations
7061
7162
  constructor(workload, customConfig) {
7062
7163
  this.workload = workload;
7063
7164
  const baseConfig = QE_FLASH_ATTENTION_CONFIG[workload];
@@ -7068,10 +7169,18 @@ var init_attention_wrapper = __esm({
7068
7169
  this.attention = AttentionFactory.create(this.config);
7069
7170
  }
7070
7171
  /**
7071
- * Initialize Flash Attention
7172
+ * Initialize Flash Attention and kv_store persistence
7072
7173
  * Note: @ruvector/attention doesn't require async initialization
7073
7174
  */
7074
7175
  async initialize() {
7176
+ try {
7177
+ this.db = getUnifiedMemory();
7178
+ if (!this.db.isInitialized()) await this.db.initialize();
7179
+ await this.loadFromKv();
7180
+ } catch (error) {
7181
+ console.warn("[QEFlashAttention] DB init failed, using memory-only:", error instanceof Error ? error.message : String(error));
7182
+ this.db = null;
7183
+ }
7075
7184
  }
7076
7185
  /**
7077
7186
  * Compute Flash Attention using @ruvector/attention
@@ -7116,6 +7225,7 @@ var init_attention_wrapper = __esm({
7116
7225
  throughput: seqLen * seqLen / ((endTime - startTime) / 1e3),
7117
7226
  peakMemoryMB: endMemory
7118
7227
  });
7228
+ this.maybePersistToKv();
7119
7229
  return output;
7120
7230
  }
7121
7231
  /**
@@ -7282,6 +7392,49 @@ var init_attention_wrapper = __esm({
7282
7392
  this.metrics = [];
7283
7393
  }
7284
7394
  // ========================================================================
7395
+ // kv_store Persistence
7396
+ // ========================================================================
7397
+ /**
7398
+ * Persist metrics snapshot to kv_store
7399
+ */
7400
+ async persistToKv() {
7401
+ if (!this.db) return;
7402
+ const kvKey = `attention-metrics-${this.workload}`;
7403
+ const snapshot = {
7404
+ workload: this.workload,
7405
+ metrics: this.metrics.slice(-50),
7406
+ savedAt: Date.now()
7407
+ };
7408
+ await this.db.kvSet(
7409
+ kvKey,
7410
+ snapshot,
7411
+ _QEFlashAttention.KV_NAMESPACE,
7412
+ _QEFlashAttention.KV_TTL
7413
+ );
7414
+ }
7415
+ /**
7416
+ * Load metrics snapshot from kv_store
7417
+ */
7418
+ async loadFromKv() {
7419
+ if (!this.db) return;
7420
+ const kvKey = `attention-metrics-${this.workload}`;
7421
+ const snapshot = await this.db.kvGet(kvKey, _QEFlashAttention.KV_NAMESPACE);
7422
+ if (snapshot?.metrics?.length) {
7423
+ this.metrics = snapshot.metrics;
7424
+ }
7425
+ }
7426
+ /**
7427
+ * Track operations and persist periodically
7428
+ */
7429
+ maybePersistToKv() {
7430
+ this.persistCount++;
7431
+ if (this.persistCount >= _QEFlashAttention.PERSIST_INTERVAL) {
7432
+ this.persistCount = 0;
7433
+ this.persistToKv().catch(() => {
7434
+ });
7435
+ }
7436
+ }
7437
+ // ========================================================================
7285
7438
  // Private Helper Methods
7286
7439
  // ========================================================================
7287
7440
  /**
@@ -8092,8 +8245,6 @@ var init_hnsw_index = __esm({
8092
8245
  const embedding = this.vectorToEmbedding(vector, key, metadata);
8093
8246
  this.ruvectorIndex.addEmbedding(embedding, label);
8094
8247
  this.vectorStore.set(key, vector);
8095
- const fullKey = this.buildKey(key);
8096
- await this.memory.storeVector(fullKey, vector, metadata);
8097
8248
  this.stats.insertOperations++;
8098
8249
  this.stats.vectorCount++;
8099
8250
  }
@@ -10009,13 +10160,6 @@ var init_knowledge_graph = __esm({
10009
10160
  async clear() {
10010
10161
  this.nodeCache.clear();
10011
10162
  this.edgeIndex.clear();
10012
- const nodePattern = `${this.config.namespace}:node:*`;
10013
- const edgePattern = `${this.config.namespace}:edge:*`;
10014
- const nodeKeys = await this.memory.search(nodePattern, this.config.maxNodes);
10015
- const edgeKeys = await this.memory.search(edgePattern, this.config.maxNodes * 10);
10016
- for (const key of [...nodeKeys, ...edgeKeys]) {
10017
- await this.memory.delete(key);
10018
- }
10019
10163
  }
10020
10164
  // ============================================================================
10021
10165
  // ADR-051: LLM Enhancement Methods
@@ -10250,26 +10394,18 @@ ${JSON.stringify(results.map((n61) => ({ id: n61.id, label: n61.label, propertie
10250
10394
  await this.createEdge(sourceId, targetId, rel.type);
10251
10395
  edgesCreated++;
10252
10396
  }
10253
- if (relationships.designPatterns.length > 0) {
10254
- await this.memory.set(
10255
- `${this.config.namespace}:patterns:${fileNodeId}`,
10256
- relationships.designPatterns,
10257
- { namespace: this.config.namespace }
10258
- );
10259
- }
10260
- if (relationships.architecturalBoundaries.length > 0) {
10261
- await this.memory.set(
10262
- `${this.config.namespace}:boundaries:${fileNodeId}`,
10263
- relationships.architecturalBoundaries,
10264
- { namespace: this.config.namespace }
10265
- );
10266
- }
10267
- if (relationships.dependencyImpacts.length > 0) {
10268
- await this.memory.set(
10269
- `${this.config.namespace}:impacts:${fileNodeId}`,
10270
- relationships.dependencyImpacts,
10271
- { namespace: this.config.namespace }
10272
- );
10397
+ const node = this.nodeCache.get(fileNodeId);
10398
+ if (node) {
10399
+ if (relationships.designPatterns.length > 0) {
10400
+ node.properties.designPatterns = relationships.designPatterns;
10401
+ }
10402
+ if (relationships.architecturalBoundaries.length > 0) {
10403
+ node.properties.architecturalBoundaries = relationships.architecturalBoundaries;
10404
+ }
10405
+ if (relationships.dependencyImpacts.length > 0) {
10406
+ node.properties.dependencyImpacts = relationships.dependencyImpacts;
10407
+ }
10408
+ this.nodeCache.set(fileNodeId, node);
10273
10409
  }
10274
10410
  return edgesCreated;
10275
10411
  }
@@ -10319,9 +10455,6 @@ ${JSON.stringify(results.map((n61) => ({ id: n61.id, label: n61.label, propertie
10319
10455
  target: targetId,
10320
10456
  type
10321
10457
  };
10322
- await this.memory.set(`${this.config.namespace}:edge:${edgeId}`, edge, {
10323
- namespace: this.config.namespace
10324
- });
10325
10458
  const sourceEdges = this.edgeIndex.get(sourceId) || [];
10326
10459
  sourceEdges.push(edge);
10327
10460
  this.edgeIndex.set(sourceId, sourceEdges);
@@ -10333,12 +10466,8 @@ ${JSON.stringify(results.map((n61) => ({ id: n61.id, label: n61.label, propertie
10333
10466
  if (firstKey) {
10334
10467
  this.nodeCache.delete(firstKey);
10335
10468
  this.edgeIndex.delete(firstKey);
10336
- await this.memory.delete(`${this.config.namespace}:node:${firstKey}`);
10337
10469
  }
10338
10470
  }
10339
- await this.memory.set(`${this.config.namespace}:node:${node.id}`, node, {
10340
- namespace: this.config.namespace
10341
- });
10342
10471
  this.nodeCache.set(node.id, node);
10343
10472
  }
10344
10473
  async extractEntities(filePath) {
@@ -10729,11 +10858,7 @@ ${JSON.stringify(results.map((n61) => ({ id: n61.id, label: n61.label, propertie
10729
10858
  return true;
10730
10859
  });
10731
10860
  }
10732
- async storeIndexMetadata(metadata) {
10733
- await this.memory.set(`${this.config.namespace}:metadata:index`, metadata, {
10734
- namespace: this.config.namespace,
10735
- persist: true
10736
- });
10861
+ async storeIndexMetadata(_metadata) {
10737
10862
  }
10738
10863
  async generateEmbedding(entity) {
10739
10864
  const text = `${entity.type} ${entity.name} ${entity.visibility}${entity.isAsync ? " async" : ""}`;
@@ -13812,31 +13937,6 @@ var init_pattern_store = __esm({
13812
13937
  * Load existing patterns from memory with timeout protection
13813
13938
  */
13814
13939
  async loadPatterns() {
13815
- try {
13816
- const timeoutMs = 5e3;
13817
- const searchPromise = this.memory.search(`${this.config.namespace}:pattern:*`, 1e4);
13818
- const timeoutPromise = new Promise(
13819
- (_56, reject) => setTimeout(() => reject(new Error("Pattern load timeout")), timeoutMs)
13820
- );
13821
- const keys = await Promise.race([searchPromise, timeoutPromise]);
13822
- const BATCH_SIZE = 50;
13823
- for (let i58 = 0; i58 < keys.length; i58 += BATCH_SIZE) {
13824
- const batch = keys.slice(i58, i58 + BATCH_SIZE);
13825
- const patterns = await Promise.all(
13826
- batch.map((key) => this.memory.get(key).catch(() => null))
13827
- );
13828
- for (const pattern of patterns) {
13829
- if (pattern) {
13830
- this.indexPattern(pattern);
13831
- }
13832
- }
13833
- }
13834
- if (this.patternCache.size > 0) {
13835
- console.log(`[PatternStore] Loaded ${this.patternCache.size} patterns`);
13836
- }
13837
- } catch (error) {
13838
- console.log(`[PatternStore] Starting fresh (no existing patterns loaded): ${error instanceof Error ? error.message : "unknown error"}`);
13839
- }
13840
13940
  }
13841
13941
  /**
13842
13942
  * Index a pattern in local caches
@@ -13884,10 +13984,6 @@ var init_pattern_store = __esm({
13884
13984
  if (domainCount >= this.config.maxPatternsPerDomain) {
13885
13985
  await this.cleanupDomain(pattern.qeDomain);
13886
13986
  }
13887
- const key = `${this.config.namespace}:pattern:${pattern.id}`;
13888
- await this.memory.set(key, pattern, {
13889
- persist: true
13890
- });
13891
13987
  this.indexPattern(pattern);
13892
13988
  if (pattern.embedding) {
13893
13989
  const hnsw = await this.ensureHNSW();
@@ -13984,15 +14080,7 @@ var init_pattern_store = __esm({
13984
14080
  if (!this.initialized) {
13985
14081
  await this.initialize();
13986
14082
  }
13987
- const cached = this.patternCache.get(id);
13988
- if (cached) return cached;
13989
- const key = `${this.config.namespace}:pattern:${id}`;
13990
- const pattern = await this.memory.get(key);
13991
- if (pattern) {
13992
- this.indexPattern(pattern);
13993
- return pattern;
13994
- }
13995
- return null;
14083
+ return this.patternCache.get(id) ?? null;
13996
14084
  }
13997
14085
  /**
13998
14086
  * Search for patterns
@@ -14189,10 +14277,6 @@ var init_pattern_store = __esm({
14189
14277
  if (shouldPromote && updated.tier === "short-term") {
14190
14278
  await this.promote(id);
14191
14279
  } else {
14192
- const key = `${this.config.namespace}:pattern:${id}`;
14193
- await this.memory.set(key, updated, {
14194
- persist: true
14195
- });
14196
14280
  this.patternCache.set(id, updated);
14197
14281
  }
14198
14282
  return ok(void 0);
@@ -14216,10 +14300,6 @@ var init_pattern_store = __esm({
14216
14300
  };
14217
14301
  this.tierIndex.get("short-term")?.delete(id);
14218
14302
  this.tierIndex.get("long-term")?.add(id);
14219
- const key = `${this.config.namespace}:pattern:${id}`;
14220
- await this.memory.set(key, promoted, {
14221
- persist: true
14222
- });
14223
14303
  this.patternCache.set(id, promoted);
14224
14304
  console.log(
14225
14305
  `[PatternStore] Promoted pattern ${id} (${pattern.name}) to long-term storage`
@@ -14235,8 +14315,6 @@ var init_pattern_store = __esm({
14235
14315
  return err(new Error(`Pattern not found: ${id}`));
14236
14316
  }
14237
14317
  this.unindexPattern(pattern);
14238
- const key = `${this.config.namespace}:pattern:${id}`;
14239
- await this.memory.delete(key);
14240
14318
  if (this.hnswIndex !== null) {
14241
14319
  try {
14242
14320
  await this.hnswIndex.delete(id);
@@ -15790,7 +15868,15 @@ var init_qe_reasoning_bank = __esm({
15790
15868
  await this.loadPretrainedPatterns();
15791
15869
  this.initialized = true;
15792
15870
  try {
15793
- await this.seedCrossDomainPatterns();
15871
+ const SEED_FLAG_KEY = "reasoning-bank:cross-domain-seeded";
15872
+ const alreadySeeded = await this.memory.get(SEED_FLAG_KEY);
15873
+ if (!alreadySeeded) {
15874
+ await this.memory.set(SEED_FLAG_KEY, true);
15875
+ await this.seedCrossDomainPatterns();
15876
+ } else {
15877
+ const stats = await this.patternStore.getStats();
15878
+ console.log(`[QEReasoningBank] Cross-domain transfer already complete (${stats.totalPatterns} patterns)`);
15879
+ }
15794
15880
  } catch (error) {
15795
15881
  console.warn("[QEReasoningBank] Cross-domain seeding failed (non-fatal):", error);
15796
15882
  }
@@ -17588,6 +17674,7 @@ var HybridMemoryBackend = class {
17588
17674
  unifiedMemory = null;
17589
17675
  config;
17590
17676
  cleanupInterval;
17677
+ cleanupCount = 0;
17591
17678
  initialized = false;
17592
17679
  constructor(config) {
17593
17680
  this.config = {
@@ -17804,6 +17891,31 @@ var HybridMemoryBackend = class {
17804
17891
  if (this.unifiedMemory?.isInitialized()) {
17805
17892
  try {
17806
17893
  await this.unifiedMemory.kvCleanupExpired();
17894
+ const db = this.unifiedMemory.getDatabase();
17895
+ try {
17896
+ const expired = db.prepare("DELETE FROM kv_store WHERE expires_at IS NOT NULL AND expires_at < ?").run(Date.now());
17897
+ if (expired.changes > 0) {
17898
+ console.log(`[HybridBackend] Expired ${expired.changes} kv_store entries`);
17899
+ }
17900
+ } catch (e20) {
17901
+ }
17902
+ this.cleanupCount++;
17903
+ if (this.cleanupCount % 10 === 0) {
17904
+ try {
17905
+ const kvCount = db.prepare("SELECT COUNT(*) as cnt FROM kv_store").get();
17906
+ if (kvCount.cnt > 5e3) {
17907
+ const deleted = db.prepare(`
17908
+ DELETE FROM kv_store WHERE rowid NOT IN (
17909
+ SELECT rowid FROM kv_store ORDER BY rowid DESC LIMIT 5000
17910
+ )
17911
+ `).run();
17912
+ if (deleted.changes > 0) {
17913
+ console.log(`[HybridBackend] kv_store retention: pruned ${deleted.changes} rows (kept 5000)`);
17914
+ }
17915
+ }
17916
+ } catch (e20) {
17917
+ }
17918
+ }
17807
17919
  } catch (error) {
17808
17920
  console.warn("[HybridBackend] Cleanup failed:", error);
17809
17921
  }
@@ -29479,11 +29591,19 @@ var isConstitutionalEnforcerEnabled = () => governanceFlags.isGateEnabled("const
29479
29591
  var isStrictMode = () => governanceFlags.getFlags().global.strictMode;
29480
29592
 
29481
29593
  // src/governance/continue-gate-integration.ts
29482
- var ContinueGateIntegration = class {
29594
+ init_unified_memory();
29595
+ var ContinueGateIntegration = class _ContinueGateIntegration {
29483
29596
  actionHistory = /* @__PURE__ */ new Map();
29484
29597
  throttledAgents = /* @__PURE__ */ new Map();
29485
29598
  guidanceContinueGate = null;
29486
29599
  initialized = false;
29600
+ db = null;
29601
+ persistCount = 0;
29602
+ static KV_NAMESPACE = "continue-gate-actions";
29603
+ static KV_KEY = "snapshot";
29604
+ static PERSIST_INTERVAL = 20;
29605
+ static KV_TTL = 3600;
29606
+ // 1 hour
29487
29607
  /**
29488
29608
  * Initialize the ContinueGate integration
29489
29609
  *
@@ -29494,8 +29614,48 @@ var ContinueGateIntegration = class {
29494
29614
  */
29495
29615
  async initialize() {
29496
29616
  if (this.initialized) return;
29617
+ try {
29618
+ this.db = getUnifiedMemory();
29619
+ if (!this.db.isInitialized()) await this.db.initialize();
29620
+ await this.loadFromKv();
29621
+ } catch (error) {
29622
+ console.warn("[ContinueGateIntegration] DB init failed, using memory-only:", error instanceof Error ? error.message : String(error));
29623
+ this.db = null;
29624
+ }
29497
29625
  this.initialized = true;
29498
29626
  }
29627
+ async loadFromKv() {
29628
+ if (!this.db) return;
29629
+ const data = await this.db.kvGet(_ContinueGateIntegration.KV_KEY, _ContinueGateIntegration.KV_NAMESPACE);
29630
+ if (data) {
29631
+ for (const [agentId, actions] of data.actionHistory) {
29632
+ this.actionHistory.set(agentId, actions);
29633
+ }
29634
+ const now = Date.now();
29635
+ for (const [agentId, until] of data.throttledAgents) {
29636
+ if (until > now) this.throttledAgents.set(agentId, until);
29637
+ }
29638
+ console.log("[ContinueGateIntegration] Loaded state from DB");
29639
+ }
29640
+ }
29641
+ async persistSnapshot() {
29642
+ if (!this.db) return;
29643
+ try {
29644
+ await this.db.kvSet(
29645
+ _ContinueGateIntegration.KV_KEY,
29646
+ {
29647
+ actionHistory: Array.from(this.actionHistory.entries()).map(
29648
+ ([agentId, actions]) => [agentId, actions.slice(-50)]
29649
+ ),
29650
+ throttledAgents: Array.from(this.throttledAgents.entries())
29651
+ },
29652
+ _ContinueGateIntegration.KV_NAMESPACE,
29653
+ _ContinueGateIntegration.KV_TTL
29654
+ );
29655
+ } catch (error) {
29656
+ console.warn("[ContinueGateIntegration] Persist failed:", error instanceof Error ? error.message : String(error));
29657
+ }
29658
+ }
29499
29659
  /**
29500
29660
  * Record an agent action for loop detection
29501
29661
  */
@@ -29507,6 +29667,11 @@ var ContinueGateIntegration = class {
29507
29667
  history.shift();
29508
29668
  }
29509
29669
  this.actionHistory.set(action.agentId, history);
29670
+ this.persistCount++;
29671
+ if (this.persistCount % _ContinueGateIntegration.PERSIST_INTERVAL === 0) {
29672
+ this.persistSnapshot().catch(() => {
29673
+ });
29674
+ }
29510
29675
  }
29511
29676
  /**
29512
29677
  * Evaluate whether an agent should continue
@@ -30786,6 +30951,7 @@ var DeterministicGatewayIntegration = class {
30786
30951
  var deterministicGatewayIntegration = new DeterministicGatewayIntegration();
30787
30952
 
30788
30953
  // src/governance/evolution-pipeline-integration.ts
30954
+ init_unified_memory();
30789
30955
  function isEvolutionPipelineEnabled() {
30790
30956
  const flags = governanceFlags.getFlags();
30791
30957
  if (!flags.global.enableAllGates) return false;
@@ -30801,11 +30967,18 @@ function getEvolutionFlags() {
30801
30967
  learningRate: 0.1
30802
30968
  };
30803
30969
  }
30804
- var EvolutionPipelineIntegration = class {
30970
+ var EvolutionPipelineIntegration = class _EvolutionPipelineIntegration {
30805
30971
  rules = /* @__PURE__ */ new Map();
30806
30972
  variantTests = /* @__PURE__ */ new Map();
30807
30973
  taskOutcomes = /* @__PURE__ */ new Map();
30808
30974
  initialized = false;
30975
+ // KV persistence
30976
+ db = null;
30977
+ persistCount = 0;
30978
+ static NAMESPACE = "rule-evolution";
30979
+ static TTL_SECONDS = 604800;
30980
+ // 7 days
30981
+ static PERSIST_INTERVAL = 10;
30809
30982
  // Statistics
30810
30983
  stats = {
30811
30984
  autoPromotions: 0,
@@ -30823,6 +30996,14 @@ var EvolutionPipelineIntegration = class {
30823
30996
  */
30824
30997
  async initialize() {
30825
30998
  if (this.initialized) return;
30999
+ try {
31000
+ this.db = getUnifiedMemory();
31001
+ if (!this.db.isInitialized()) await this.db.initialize();
31002
+ await this.loadFromKv();
31003
+ } catch (error) {
31004
+ console.warn("[EvolutionPipeline] DB init failed, using memory-only:", error instanceof Error ? error.message : String(error));
31005
+ this.db = null;
31006
+ }
30826
31007
  this.initialized = true;
30827
31008
  this.logEvent("initialize", "Evolution Pipeline initialized");
30828
31009
  }
@@ -30844,6 +31025,7 @@ var EvolutionPipelineIntegration = class {
30844
31025
  record.applications.push(application);
30845
31026
  this.pruneApplicationHistory(record);
30846
31027
  this.checkAutoPromotionDemotion(ruleId);
31028
+ this.persistSnapshot();
30847
31029
  this.logEvent("rule_application", `Rule ${ruleId} applied: ${success ? "success" : "failure"}`);
30848
31030
  }
30849
31031
  /**
@@ -31268,6 +31450,36 @@ var EvolutionPipelineIntegration = class {
31268
31450
  this.rules.delete(ruleId);
31269
31451
  }
31270
31452
  // ============================================================================
31453
+ // KV Persistence
31454
+ // ============================================================================
31455
+ /**
31456
+ * Load rules snapshot from KV store
31457
+ */
31458
+ async loadFromKv() {
31459
+ if (!this.db) return;
31460
+ const data = await this.db.kvGet("snapshot", _EvolutionPipelineIntegration.NAMESPACE);
31461
+ if (data) {
31462
+ for (const [key, record] of Object.entries(data)) {
31463
+ this.rules.set(key, record);
31464
+ }
31465
+ }
31466
+ }
31467
+ /**
31468
+ * Persist rules snapshot to KV store on interval
31469
+ */
31470
+ persistSnapshot() {
31471
+ if (!this.db) return;
31472
+ this.persistCount++;
31473
+ if (this.persistCount % _EvolutionPipelineIntegration.PERSIST_INTERVAL !== 0) return;
31474
+ try {
31475
+ const snapshot = Object.fromEntries(this.rules);
31476
+ this.db.kvSet("snapshot", snapshot, _EvolutionPipelineIntegration.NAMESPACE, _EvolutionPipelineIntegration.TTL_SECONDS).catch(() => {
31477
+ });
31478
+ } catch (error) {
31479
+ console.warn("[EvolutionPipeline] Persist failed:", error instanceof Error ? error.message : String(error));
31480
+ }
31481
+ }
31482
+ // ============================================================================
31271
31483
  // Private Helpers
31272
31484
  // ============================================================================
31273
31485
  /**
@@ -33612,6 +33824,7 @@ var ProofEnvelopeIntegration = class {
33612
33824
  var proofEnvelopeIntegration = new ProofEnvelopeIntegration();
33613
33825
 
33614
33826
  // src/governance/compliance-reporter.ts
33827
+ init_unified_memory();
33615
33828
  var DEFAULT_COMPLIANCE_REPORTER_FLAGS = {
33616
33829
  enabled: true,
33617
33830
  autoRecordViolations: true,
@@ -33628,7 +33841,7 @@ var SEVERITY_WEIGHTS = {
33628
33841
  var DEFAULT_SCORE = 100;
33629
33842
  var SCORE_DECAY_RATE = 0.5;
33630
33843
  var TREND_THRESHOLD = 5;
33631
- var ComplianceReporter = class {
33844
+ var ComplianceReporter = class _ComplianceReporter {
33632
33845
  violations = /* @__PURE__ */ new Map();
33633
33846
  alertThresholds = /* @__PURE__ */ new Map();
33634
33847
  proofIntegration;
@@ -33636,6 +33849,13 @@ var ComplianceReporter = class {
33636
33849
  initialized = false;
33637
33850
  scoreHistory = [];
33638
33851
  alertListeners = /* @__PURE__ */ new Set();
33852
+ // KV persistence
33853
+ db = null;
33854
+ persistCount = 0;
33855
+ static NAMESPACE = "compliance-audit";
33856
+ static TTL_SECONDS = 2592e3;
33857
+ // 30 days
33858
+ static PERSIST_INTERVAL = 10;
33639
33859
  /**
33640
33860
  * Create a new ComplianceReporter instance
33641
33861
  *
@@ -33651,6 +33871,14 @@ var ComplianceReporter = class {
33651
33871
  */
33652
33872
  async initialize() {
33653
33873
  if (this.initialized) return;
33874
+ try {
33875
+ this.db = getUnifiedMemory();
33876
+ if (!this.db.isInitialized()) await this.db.initialize();
33877
+ await this.loadFromKv();
33878
+ } catch (error) {
33879
+ console.warn("[ComplianceReporter] DB init failed, using memory-only:", error instanceof Error ? error.message : String(error));
33880
+ this.db = null;
33881
+ }
33654
33882
  if (!this.proofIntegration.isInitialized()) {
33655
33883
  await this.proofIntegration.initialize();
33656
33884
  }
@@ -33719,6 +33947,7 @@ var ComplianceReporter = class {
33719
33947
  if (this.flags.alertOnCritical && violation.severity === "critical") {
33720
33948
  this.triggerAlert(violation.gate, "Critical violation detected", "critical");
33721
33949
  }
33950
+ this.persistSnapshot();
33722
33951
  this.cleanupOldViolations();
33723
33952
  return id;
33724
33953
  }
@@ -34148,6 +34377,45 @@ var ComplianceReporter = class {
34148
34377
  this.initialized = false;
34149
34378
  }
34150
34379
  // ============================================================================
34380
+ // KV Persistence
34381
+ // ============================================================================
34382
+ /**
34383
+ * Load violations and score history from KV store
34384
+ */
34385
+ async loadFromKv() {
34386
+ if (!this.db) return;
34387
+ const data = await this.db.kvGet("snapshot", _ComplianceReporter.NAMESPACE);
34388
+ if (data) {
34389
+ if (data.violations) {
34390
+ for (const [key, violation] of Object.entries(data.violations)) {
34391
+ this.violations.set(key, violation);
34392
+ }
34393
+ }
34394
+ if (data.scoreHistory) {
34395
+ this.scoreHistory = data.scoreHistory;
34396
+ }
34397
+ }
34398
+ }
34399
+ /**
34400
+ * Persist violations and score history to KV store on interval
34401
+ */
34402
+ persistSnapshot() {
34403
+ if (!this.db) return;
34404
+ this.persistCount++;
34405
+ if (this.persistCount % _ComplianceReporter.PERSIST_INTERVAL !== 0) return;
34406
+ try {
34407
+ const violationEntries = Array.from(this.violations.entries()).slice(-500);
34408
+ const snapshot = {
34409
+ violations: Object.fromEntries(violationEntries),
34410
+ scoreHistory: this.scoreHistory.slice(-100)
34411
+ };
34412
+ this.db.kvSet("snapshot", snapshot, _ComplianceReporter.NAMESPACE, _ComplianceReporter.TTL_SECONDS).catch(() => {
34413
+ });
34414
+ } catch (error) {
34415
+ console.warn("[ComplianceReporter] Persist failed:", error instanceof Error ? error.message : String(error));
34416
+ }
34417
+ }
34418
+ // ============================================================================
34151
34419
  // Private Methods
34152
34420
  // ============================================================================
34153
34421
  /**
@@ -70941,9 +71209,11 @@ var CodeIntelligenceCoordinator = class {
70941
71209
  async initializeHypergraph() {
70942
71210
  try {
70943
71211
  const Database = (await Promise.resolve().then(() => (init_better_sqlite3(), better_sqlite3_exports))).default;
70944
- const dbPath = this.config.hypergraphDbPath || ".agentic-qe/hypergraph.db";
70945
71212
  const fs21 = await import("fs");
70946
71213
  const path23 = await import("path");
71214
+ const { findProjectRoot: findProjectRoot2 } = await Promise.resolve().then(() => (init_unified_memory(), unified_memory_exports));
71215
+ const projectRoot = findProjectRoot2();
71216
+ const dbPath = this.config.hypergraphDbPath || path23.join(projectRoot, ".agentic-qe", "hypergraph.db");
70947
71217
  const dir = path23.dirname(dbPath);
70948
71218
  if (!fs21.existsSync(dir)) {
70949
71219
  fs21.mkdirSync(dir, { recursive: true });
@@ -73574,17 +73844,22 @@ var SASTScanner = class {
73574
73844
  * Store scan results in memory
73575
73845
  */
73576
73846
  async storeScanResults(scanId, scanType, vulnerabilities, summary) {
73847
+ const scanSummary = {
73848
+ scanId,
73849
+ scanType,
73850
+ summary,
73851
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
73852
+ vulnerabilityCount: vulnerabilities.length,
73853
+ // Keep only critical/high vulnerabilities in stored result
73854
+ criticalVulnerabilities: vulnerabilities.filter(
73855
+ (v62) => v62.severity === "critical" || v62.severity === "high"
73856
+ )
73857
+ };
73577
73858
  await this.memory.set(
73578
73859
  `security:scan:${scanId}`,
73579
- {
73580
- scanId,
73581
- scanType,
73582
- vulnerabilities,
73583
- summary,
73584
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
73585
- },
73586
- { namespace: "security-compliance", ttl: 86400 * 7 }
73587
- // 7 days
73860
+ scanSummary,
73861
+ { namespace: "security-compliance", ttl: 86400 * 2 }
73862
+ // 2 days (reduced from 7)
73588
73863
  );
73589
73864
  }
73590
73865
  // ==========================================================================
@@ -103369,8 +103644,34 @@ var MinCutPersistence = class {
103369
103644
  JSON.stringify(snapshot.vertices),
103370
103645
  JSON.stringify(snapshot.edges)
103371
103646
  );
103647
+ await this.enforceRetention();
103372
103648
  return id;
103373
103649
  }
103650
+ /**
103651
+ * Enforce retention limits on snapshots and history to prevent DB bloat (Issue #258)
103652
+ */
103653
+ async enforceRetention(maxSnapshots = 200) {
103654
+ const db = this.memory.getDatabase();
103655
+ if (!db) return 0;
103656
+ const countRow = db.prepare("SELECT COUNT(*) as count FROM mincut_snapshots").get();
103657
+ if (!countRow || countRow.count <= maxSnapshots) return 0;
103658
+ const deleteCount = countRow.count - maxSnapshots;
103659
+ db.prepare(`
103660
+ DELETE FROM mincut_snapshots WHERE id IN (
103661
+ SELECT id FROM mincut_snapshots ORDER BY created_at ASC LIMIT ?
103662
+ )
103663
+ `).run(deleteCount);
103664
+ const historyCount = db.prepare("SELECT COUNT(*) as count FROM mincut_history").get();
103665
+ if (historyCount.count > 500) {
103666
+ const historyDelete = historyCount.count - 500;
103667
+ db.prepare(`
103668
+ DELETE FROM mincut_history WHERE id IN (
103669
+ SELECT id FROM mincut_history ORDER BY created_at ASC LIMIT ?
103670
+ )
103671
+ `).run(historyDelete);
103672
+ }
103673
+ return deleteCount;
103674
+ }
103374
103675
  /**
103375
103676
  * Get a snapshot by ID
103376
103677
  */
@@ -109347,7 +109648,8 @@ var DEFAULT_DYNAMIC_SCALING_CONFIG = {
109347
109648
 
109348
109649
  // src/coordination/dynamic-scaling/dynamic-scaler.ts
109349
109650
  import { randomUUID as randomUUID5 } from "node:crypto";
109350
- var DynamicScaler = class {
109651
+ init_unified_memory();
109652
+ var DynamicScaler = class _DynamicScaler {
109351
109653
  config;
109352
109654
  policy;
109353
109655
  metricsHistory = [];
@@ -109358,6 +109660,13 @@ var DynamicScaler = class {
109358
109660
  totalDecisions = 0;
109359
109661
  currentAgents;
109360
109662
  lastDecision;
109663
+ // KV store persistence (Tier 2)
109664
+ db = null;
109665
+ persistCount = 0;
109666
+ static KV_NAMESPACE = "scaling-metrics";
109667
+ static KV_KEY = "dynamic-scaler-snapshot";
109668
+ static PERSIST_INTERVAL = 10;
109669
+ static KV_TTL = 7200;
109361
109670
  /**
109362
109671
  * Create a new DynamicScaler.
109363
109672
  *
@@ -109383,6 +109692,11 @@ var DynamicScaler = class {
109383
109692
  if (this.metricsHistory.length > this.config.metricsHistorySize) {
109384
109693
  this.metricsHistory.shift();
109385
109694
  }
109695
+ this.persistCount++;
109696
+ if (this.persistCount % _DynamicScaler.PERSIST_INTERVAL === 0) {
109697
+ this.persistSnapshot().catch(() => {
109698
+ });
109699
+ }
109386
109700
  }
109387
109701
  // --------------------------------------------------------------------------
109388
109702
  // Evaluation
@@ -109580,6 +109894,23 @@ var DynamicScaler = class {
109580
109894
  // --------------------------------------------------------------------------
109581
109895
  // Lifecycle
109582
109896
  // --------------------------------------------------------------------------
109897
+ /**
109898
+ * Initialize persistence layer and load last snapshot from KV store.
109899
+ * Safe to call multiple times; will not throw on DB failure.
109900
+ */
109901
+ async initialize() {
109902
+ try {
109903
+ this.db = getUnifiedMemory();
109904
+ if (!this.db.isInitialized()) await this.db.initialize();
109905
+ await this.loadFromKv();
109906
+ } catch (error) {
109907
+ console.warn(
109908
+ "[DynamicScaler] DB init failed, using memory-only:",
109909
+ error instanceof Error ? error.message : String(error)
109910
+ );
109911
+ this.db = null;
109912
+ }
109913
+ }
109583
109914
  /**
109584
109915
  * Release internal buffers. The scaler should not be used after disposal.
109585
109916
  */
@@ -109620,12 +109951,68 @@ var DynamicScaler = class {
109620
109951
  }
109621
109952
  /**
109622
109953
  * Record a scaling event, evicting the oldest when the history cap is hit.
109954
+ * Triggers periodic persistence to KV store.
109623
109955
  */
109624
109956
  recordEvent(event) {
109625
109957
  this.events.push(event);
109626
109958
  if (this.events.length > this.config.decisionHistorySize) {
109627
109959
  this.events.shift();
109628
109960
  }
109961
+ this.persistCount++;
109962
+ if (this.persistCount % _DynamicScaler.PERSIST_INTERVAL === 0) {
109963
+ this.persistSnapshot().catch(() => {
109964
+ });
109965
+ }
109966
+ }
109967
+ /**
109968
+ * Load last persisted snapshot from KV store into in-memory state.
109969
+ */
109970
+ async loadFromKv() {
109971
+ if (!this.db) return;
109972
+ try {
109973
+ const snapshot = await this.db.kvGet(_DynamicScaler.KV_KEY, _DynamicScaler.KV_NAMESPACE);
109974
+ if (snapshot) {
109975
+ if (Array.isArray(snapshot.metricsHistory)) {
109976
+ for (const m74 of snapshot.metricsHistory) {
109977
+ this.metricsHistory.push(m74);
109978
+ }
109979
+ }
109980
+ if (Array.isArray(snapshot.events)) {
109981
+ for (const e20 of snapshot.events) {
109982
+ this.events.push(e20);
109983
+ }
109984
+ }
109985
+ }
109986
+ } catch (error) {
109987
+ console.warn(
109988
+ "[DynamicScaler] Failed to load KV snapshot:",
109989
+ error instanceof Error ? error.message : String(error)
109990
+ );
109991
+ }
109992
+ }
109993
+ /**
109994
+ * Persist a trimmed snapshot of metricsHistory and events to KV store.
109995
+ * Keeps only the last 50 entries of each to limit storage size.
109996
+ */
109997
+ async persistSnapshot() {
109998
+ if (!this.db) return;
109999
+ try {
110000
+ const snapshot = {
110001
+ metricsHistory: this.metricsHistory.slice(-50),
110002
+ events: this.events.slice(-50)
110003
+ };
110004
+ await this.db.kvSet(
110005
+ _DynamicScaler.KV_KEY,
110006
+ snapshot,
110007
+ _DynamicScaler.KV_NAMESPACE,
110008
+ _DynamicScaler.KV_TTL
110009
+ );
110010
+ } catch (error) {
110011
+ console.warn(
110012
+ "[DynamicScaler] Failed to persist KV snapshot:",
110013
+ error instanceof Error ? error.message : String(error)
110014
+ );
110015
+ }
109629
110016
  }
109630
110017
  };
109631
110018
  function createDynamicScaler(initialAgents, config) {
@@ -112275,6 +112662,7 @@ var EarlyExitTokenOptimizer = class {
112275
112662
  init_pattern_store();
112276
112663
 
112277
112664
  // src/learning/token-tracker.ts
112665
+ init_unified_memory();
112278
112666
  import { randomUUID as randomUUID6 } from "crypto";
112279
112667
  var DEFAULT_COST_CONFIG = {
112280
112668
  costPerInputToken: 3e-3 / 1e3,
@@ -112288,7 +112676,7 @@ var DEFAULT_PERSISTENCE_CONFIG2 = {
112288
112676
  // Auto-save every minute
112289
112677
  maxMetricsInMemory: 1e4
112290
112678
  };
112291
- var TokenMetricsCollectorImpl = class {
112679
+ var TokenMetricsCollectorImpl = class _TokenMetricsCollectorImpl {
112292
112680
  taskMetrics = [];
112293
112681
  agentMetrics = /* @__PURE__ */ new Map();
112294
112682
  domainMetrics = /* @__PURE__ */ new Map();
@@ -112304,6 +112692,15 @@ var TokenMetricsCollectorImpl = class {
112304
112692
  persistenceConfig = DEFAULT_PERSISTENCE_CONFIG2;
112305
112693
  autoSaveTimer = null;
112306
112694
  isDirty = false;
112695
+ // kv_store persistence
112696
+ db = null;
112697
+ kvPersistCount = 0;
112698
+ static KV_NAMESPACE = "token-usage-metrics";
112699
+ static KV_KEY = "token-tracker-snapshot";
112700
+ static KV_TTL = 604800;
112701
+ // 7 days
112702
+ static KV_PERSIST_INTERVAL = 10;
112703
+ // every 10 operations
112307
112704
  constructor() {
112308
112705
  this.sessionId = `session-${Date.now()}-${randomUUID6().substring(0, 8)}`;
112309
112706
  this.sessionStartTime = Date.now();
@@ -112718,6 +113115,88 @@ var TokenMetricsCollectorImpl = class {
112718
113115
  return this.isDirty;
112719
113116
  }
112720
113117
  // ============================================================================
113118
+ // kv_store Persistence
113119
+ // ============================================================================
113120
+ /**
113121
+ * Initialize kv_store persistence and restore snapshot if available.
113122
+ * This supplements the existing file-based persistence.
113123
+ */
113124
+ async initializeDb() {
113125
+ try {
113126
+ this.db = getUnifiedMemory();
113127
+ if (!this.db.isInitialized()) await this.db.initialize();
113128
+ await this.loadFromKv();
113129
+ } catch (error) {
113130
+ console.warn("[TokenMetricsCollector] DB init failed, using memory-only:", error instanceof Error ? error.message : String(error));
113131
+ this.db = null;
113132
+ }
113133
+ }
113134
+ /**
113135
+ * Persist current state snapshot to kv_store
113136
+ */
113137
+ async persistToKv() {
113138
+ if (!this.db) return;
113139
+ const snapshot = {
113140
+ version: "1.0.0",
113141
+ sessionId: this.sessionId,
113142
+ sessionStartTime: this.sessionStartTime,
113143
+ taskMetrics: this.taskMetrics.slice(-this.persistenceConfig.maxMetricsInMemory),
113144
+ optimizationStats: {
113145
+ cacheHits: this.cacheHits,
113146
+ earlyExits: this.earlyExits,
113147
+ totalTokensSaved: this.totalTokensSaved,
113148
+ totalPatternsReused: this.totalPatternsReused
113149
+ },
113150
+ lastSavedAt: Date.now()
113151
+ };
113152
+ await this.db.kvSet(
113153
+ _TokenMetricsCollectorImpl.KV_KEY,
113154
+ snapshot,
113155
+ _TokenMetricsCollectorImpl.KV_NAMESPACE,
113156
+ _TokenMetricsCollectorImpl.KV_TTL
113157
+ );
113158
+ }
113159
+ /**
113160
+ * Load state snapshot from kv_store
113161
+ */
113162
+ async loadFromKv() {
113163
+ if (!this.db) return false;
113164
+ const snapshot = await this.db.kvGet(
113165
+ _TokenMetricsCollectorImpl.KV_KEY,
113166
+ _TokenMetricsCollectorImpl.KV_NAMESPACE
113167
+ );
113168
+ if (!snapshot) return false;
113169
+ if (!snapshot.version || !snapshot.version.startsWith("1.")) {
113170
+ console.warn("[TokenMetricsCollector] Incompatible kv_store data version, skipping load");
113171
+ return false;
113172
+ }
113173
+ const historicalMetrics = snapshot.taskMetrics || [];
113174
+ this.taskMetrics = [...historicalMetrics, ...this.taskMetrics];
113175
+ this.cacheHits += snapshot.optimizationStats?.cacheHits || 0;
113176
+ this.earlyExits += snapshot.optimizationStats?.earlyExits || 0;
113177
+ this.totalTokensSaved += snapshot.optimizationStats?.totalTokensSaved || 0;
113178
+ this.totalPatternsReused += snapshot.optimizationStats?.totalPatternsReused || 0;
113179
+ for (const metric of historicalMetrics) {
113180
+ this.updateAgentMetrics(metric.agentId, metric.usage, metric.patternReused, metric.tokensSaved || 0);
113181
+ this.updateDomainMetrics(metric.domain, metric.usage);
113182
+ }
113183
+ if (this.taskMetrics.length > this.persistenceConfig.maxMetricsInMemory) {
113184
+ this.taskMetrics = this.taskMetrics.slice(-this.persistenceConfig.maxMetricsInMemory);
113185
+ }
113186
+ return true;
113187
+ }
113188
+ /**
113189
+ * Track state changes and persist to kv_store periodically
113190
+ */
113191
+ maybePersistToKv() {
113192
+ this.kvPersistCount++;
113193
+ if (this.kvPersistCount >= _TokenMetricsCollectorImpl.KV_PERSIST_INTERVAL) {
113194
+ this.kvPersistCount = 0;
113195
+ this.persistToKv().catch(() => {
113196
+ });
113197
+ }
113198
+ }
113199
+ // ============================================================================
112721
113200
  // Private Helper Methods
112722
113201
  // ============================================================================
112723
113202
  ensureInitialized() {
@@ -114421,7 +114900,7 @@ var ALL_DOMAINS2 = [
114421
114900
  "enterprise-integration"
114422
114901
  ];
114423
114902
  function getAQEVersion() {
114424
- return true ? "3.6.6" : "3.0.0";
114903
+ return true ? "3.6.7" : "3.0.0";
114425
114904
  }
114426
114905
  function createDefaultConfig(projectName, projectRoot) {
114427
114906
  return {
@@ -118935,9 +119414,22 @@ var HooksPhase = class extends BasePhase {
118935
119414
  * Uses `npx agentic-qe` for portability - works without global installation.
118936
119415
  * All hooks use --json output for structured data and fail silently with continueOnError.
118937
119416
  */
118938
- generateHooksConfig(config) {
119417
+ generateHooksConfig(_config) {
118939
119418
  return {
118940
119419
  PreToolUse: [
119420
+ // File guardian — MUST be first to block before learning hooks run
119421
+ {
119422
+ matcher: "^(Write|Edit|MultiEdit)$",
119423
+ hooks: [
119424
+ {
119425
+ type: "command",
119426
+ command: 'npx agentic-qe hooks guard --file "$TOOL_INPUT_file_path" --json',
119427
+ timeout: 3e3,
119428
+ continueOnError: true
119429
+ }
119430
+ ]
119431
+ },
119432
+ // Learning: pre-edit context
118941
119433
  {
118942
119434
  matcher: "^(Write|Edit|MultiEdit)$",
118943
119435
  hooks: [
@@ -118949,17 +119441,19 @@ var HooksPhase = class extends BasePhase {
118949
119441
  }
118950
119442
  ]
118951
119443
  },
119444
+ // Command bouncer — blocks dangerous commands
118952
119445
  {
118953
119446
  matcher: "^Bash$",
118954
119447
  hooks: [
118955
119448
  {
118956
119449
  type: "command",
118957
119450
  command: 'npx agentic-qe hooks pre-command --command "$TOOL_INPUT_command" --json',
118958
- timeout: 5e3,
119451
+ timeout: 3e3,
118959
119452
  continueOnError: true
118960
119453
  }
118961
119454
  ]
118962
119455
  },
119456
+ // Task routing
118963
119457
  {
118964
119458
  matcher: "^Task$",
118965
119459
  hooks: [
@@ -118978,7 +119472,7 @@ var HooksPhase = class extends BasePhase {
118978
119472
  hooks: [
118979
119473
  {
118980
119474
  type: "command",
118981
- command: 'npx agentic-qe hooks post-edit --file "$TOOL_INPUT_file_path" --success "$TOOL_SUCCESS" --json',
119475
+ command: 'npx agentic-qe hooks post-edit --file "$TOOL_INPUT_file_path" --success --json',
118982
119476
  timeout: 5e3,
118983
119477
  continueOnError: true
118984
119478
  }
@@ -118989,7 +119483,7 @@ var HooksPhase = class extends BasePhase {
118989
119483
  hooks: [
118990
119484
  {
118991
119485
  type: "command",
118992
- command: 'npx agentic-qe hooks post-command --command "$TOOL_INPUT_command" --success "$TOOL_SUCCESS" --json',
119486
+ command: 'npx agentic-qe hooks post-command --command "$TOOL_INPUT_command" --success --json',
118993
119487
  timeout: 5e3,
118994
119488
  continueOnError: true
118995
119489
  }
@@ -119000,7 +119494,7 @@ var HooksPhase = class extends BasePhase {
119000
119494
  hooks: [
119001
119495
  {
119002
119496
  type: "command",
119003
- command: 'npx agentic-qe hooks post-task --task-id "$TOOL_RESULT_agent_id" --success "$TOOL_SUCCESS" --json',
119497
+ command: 'npx agentic-qe hooks post-task --task-id "$TOOL_RESULT_agent_id" --success --json',
119004
119498
  timeout: 5e3,
119005
119499
  continueOnError: true
119006
119500
  }
@@ -137839,13 +138333,19 @@ Examples:
137839
138333
  });
137840
138334
  const result = results[0] || { success: true, guidance: [], routing: null };
137841
138335
  if (options.json) {
138336
+ const guidanceLines = result.guidance || [];
138337
+ const agentHint = result.routing?.recommendedAgent ? `Recommended agent: ${result.routing.recommendedAgent} (${(result.routing.confidence * 100).toFixed(0)}% confidence).` : "";
138338
+ const contextStr = [
138339
+ agentHint,
138340
+ ...guidanceLines.map((g67) => g67)
138341
+ ].filter(Boolean).join(" ");
137842
138342
  printJson({
137843
- success: result.success,
138343
+ hookSpecificOutput: {
138344
+ hookEventName: "PreToolUse",
138345
+ additionalContext: contextStr || void 0
138346
+ },
137844
138347
  file: options.file,
137845
138348
  operation: options.operation,
137846
- guidance: result.guidance || [],
137847
- recommendedAgent: result.routing?.recommendedAgent,
137848
- confidence: result.routing?.confidence,
137849
138349
  patterns: result.routing?.patterns?.length || 0
137850
138350
  });
137851
138351
  } else {
@@ -138161,18 +138661,32 @@ Registered: ${events.length}/${Object.keys(QE_HOOK_EVENTS).length}`)
138161
138661
  dreamState.totalDreamsThisSession = 0;
138162
138662
  }
138163
138663
  await memoryBackend2.set(DREAM_STATE_KEY, dreamState);
138664
+ const contextParts = [];
138665
+ contextParts.push(`AQE Learning: ${stats.totalPatterns} patterns loaded`);
138666
+ const domainEntries = Object.entries(stats.byDomain).filter(([, count]) => count > 0).sort(([, a37], [, b68]) => b68 - a37).slice(0, 5);
138667
+ if (domainEntries.length > 0) {
138668
+ contextParts.push(`Top domains: ${domainEntries.map(([d74, c70]) => `${d74}(${c70})`).join(", ")}`);
138669
+ }
138670
+ if (stats.patternSuccessRate > 0) {
138671
+ contextParts.push(`Pattern success rate: ${(stats.patternSuccessRate * 100).toFixed(0)}%`);
138672
+ }
138673
+ if (stats.routingRequests > 0) {
138674
+ contextParts.push(`Routing confidence: ${(stats.avgRoutingConfidence * 100).toFixed(0)}% across ${stats.routingRequests} requests`);
138675
+ }
138676
+ const additionalContext = contextParts.join(". ") + ".";
138164
138677
  if (options.json) {
138165
138678
  printJson({
138166
- success: true,
138679
+ hookSpecificOutput: {
138680
+ hookEventName: "SessionStart",
138681
+ additionalContext
138682
+ },
138167
138683
  sessionId,
138168
138684
  initialized: true,
138169
138685
  patternsLoaded: stats.totalPatterns,
138170
138686
  dreamScheduler: {
138171
138687
  enabled: true,
138172
138688
  lastDreamTime: dreamState.lastDreamTime,
138173
- pendingExperiences: dreamState.experienceCount,
138174
- intervalMs: DREAM_INTERVAL_MS,
138175
- experienceThreshold: DREAM_EXPERIENCE_THRESHOLD
138689
+ pendingExperiences: dreamState.experienceCount
138176
138690
  }
138177
138691
  });
138178
138692
  } else {
@@ -138199,8 +138713,9 @@ Registered: ${events.length}/${Object.keys(QE_HOOK_EVENTS).length}`)
138199
138713
  }
138200
138714
  }
138201
138715
  if (options.json) {
138716
+ const summary = stats ? `Session complete: ${stats.totalPatterns} patterns, ${stats.routingRequests} routings, ${(stats.patternSuccessRate * 100).toFixed(0)}% success rate` : "Session complete";
138202
138717
  printJson({
138203
- success: true,
138718
+ continue: true,
138204
138719
  sessionId,
138205
138720
  stateSaved: options.saveState || false,
138206
138721
  metricsExported: options.exportMetrics || false,
@@ -138324,34 +138839,119 @@ Registered: ${events.length}/${Object.keys(QE_HOOK_EVENTS).length}`)
138324
138839
  process.exit(0);
138325
138840
  }
138326
138841
  });
138327
- hooks.command("pre-command").description("Get context before executing a Bash command").option("-c, --command <cmd>", "Command to be executed").option("--json", "Output as JSON").action(async (options) => {
138328
- try {
138329
- const command = options.command || "";
138330
- const warnings = [];
138331
- if (command.includes("rm -rf /") || command.includes("rm -rf ~")) {
138332
- warnings.push("Dangerous recursive delete detected");
138333
- }
138334
- if (command.includes("> /dev/sd") || command.includes("dd if=")) {
138335
- warnings.push("Direct disk write detected");
138336
- }
138337
- if (command.includes(".agentic-qe") && command.includes("rm")) {
138338
- warnings.push("Deleting AQE data files");
138842
+ hooks.command("guard").description("File guardian - block edits to protected files").requiredOption("-f, --file <path>", "File path to check").option("--json", "Output as JSON (required for hook API)").action(async (options) => {
138843
+ try {
138844
+ const filePath = options.file || "";
138845
+ const normalizedPath = filePath.replace(/\\/g, "/");
138846
+ const protectedPatterns = [
138847
+ { pattern: /^\.env($|\.)/, reason: "Environment file contains secrets" },
138848
+ { pattern: /\.env\.[a-zA-Z]+$/, reason: "Environment file contains secrets" },
138849
+ { pattern: /\.lock$/, reason: "Lock files are auto-generated" },
138850
+ { pattern: /(^|\/)node_modules\//, reason: "node_modules is managed by package manager" },
138851
+ { pattern: /(^|\/)\.agentic-qe\/memory\.db/, reason: "AQE memory database must not be directly edited" },
138852
+ { pattern: /(^|\/)\.agentic-qe\/memory\.db-wal$/, reason: "AQE WAL file must not be directly edited" },
138853
+ { pattern: /(^|\/)\.agentic-qe\/memory\.db-shm$/, reason: "AQE shared memory file must not be directly edited" }
138854
+ ];
138855
+ const match = protectedPatterns.find((p74) => p74.pattern.test(normalizedPath));
138856
+ if (match) {
138857
+ if (options.json) {
138858
+ printJson({
138859
+ hookSpecificOutput: {
138860
+ hookEventName: "PreToolUse",
138861
+ permissionDecision: "deny",
138862
+ permissionDecisionReason: `Protected file: ${match.reason} (${filePath})`
138863
+ }
138864
+ });
138865
+ } else {
138866
+ printError(`Blocked: ${match.reason} (${filePath})`);
138867
+ }
138868
+ } else {
138869
+ if (options.json) {
138870
+ printJson({
138871
+ hookSpecificOutput: {
138872
+ hookEventName: "PreToolUse",
138873
+ permissionDecision: "allow"
138874
+ }
138875
+ });
138876
+ } else {
138877
+ printSuccess(`Allowed: ${filePath}`);
138878
+ }
138339
138879
  }
138880
+ process.exit(0);
138881
+ } catch (error) {
138340
138882
  if (options.json) {
138341
138883
  printJson({
138342
- success: true,
138343
- command: command.substring(0, 100),
138344
- warnings,
138345
- safe: warnings.length === 0
138884
+ hookSpecificOutput: {
138885
+ hookEventName: "PreToolUse",
138886
+ permissionDecision: "allow"
138887
+ }
138346
138888
  });
138347
- } else if (warnings.length > 0) {
138348
- console.log(chalk27.yellow("\n\u26A0\uFE0F Command Warnings:"));
138349
- warnings.forEach((w54) => console.log(chalk27.yellow(` - ${w54}`)));
138889
+ }
138890
+ process.exit(0);
138891
+ }
138892
+ });
138893
+ hooks.command("pre-command").description("Get context before executing a Bash command").option("-c, --command <cmd>", "Command to be executed").option("--json", "Output as JSON").action(async (options) => {
138894
+ try {
138895
+ const command = options.command || "";
138896
+ const dangerousPatterns = [
138897
+ { pattern: /rm\s+(-[a-zA-Z]*f[a-zA-Z]*\s+)?-[a-zA-Z]*r[a-zA-Z]*\s+\/(?!\w)/, reason: "Recursive delete of root filesystem" },
138898
+ { pattern: /rm\s+(-[a-zA-Z]*r[a-zA-Z]*\s+)?-[a-zA-Z]*f[a-zA-Z]*\s+\/(?!\w)/, reason: "Recursive delete of root filesystem" },
138899
+ { pattern: /rm\s+-rf\s+~/, reason: "Recursive delete of home directory" },
138900
+ { pattern: /DROP\s+(TABLE|DATABASE|SCHEMA)/i, reason: "Destructive SQL operation" },
138901
+ { pattern: /git\s+push\s+.*--force(?!-)/, reason: "Force push can overwrite remote history" },
138902
+ { pattern: /git\s+reset\s+--hard/, reason: "Hard reset discards uncommitted changes" },
138903
+ { pattern: />\s*\/dev\/sd[a-z]/, reason: "Direct write to block device" },
138904
+ { pattern: /dd\s+if=.*of=\/dev\/sd/, reason: "Direct disk write via dd" },
138905
+ { pattern: /chmod\s+777\s/, reason: "World-writable permissions are a security risk" },
138906
+ { pattern: /:\(\)\s*\{\s*:\|\s*:&\s*\}\s*;?\s*:/, reason: "Fork bomb detected" },
138907
+ { pattern: /mkfs\./, reason: "Filesystem format operation" },
138908
+ { pattern: />\s*\/dev\/null\s*2>&1\s*&\s*disown/, reason: "Stealth background process" }
138909
+ ];
138910
+ const warningPatterns = [
138911
+ { pattern: /\.agentic-qe.*rm/, reason: "Deleting AQE data files" },
138912
+ { pattern: /rm\s+-rf\s/, reason: "Recursive force delete" },
138913
+ { pattern: /git\s+clean\s+-[a-zA-Z]*f/, reason: "Force cleaning untracked files" }
138914
+ ];
138915
+ const dangerMatch = dangerousPatterns.find((p74) => p74.pattern.test(command));
138916
+ const warnings = warningPatterns.filter((p74) => p74.pattern.test(command)).map((p74) => p74.reason);
138917
+ if (dangerMatch) {
138918
+ if (options.json) {
138919
+ printJson({
138920
+ hookSpecificOutput: {
138921
+ hookEventName: "PreToolUse",
138922
+ permissionDecision: "deny",
138923
+ permissionDecisionReason: `Dangerous command blocked: ${dangerMatch.reason}`
138924
+ }
138925
+ });
138926
+ } else {
138927
+ printError(`Blocked: ${dangerMatch.reason}`);
138928
+ }
138929
+ } else {
138930
+ if (options.json) {
138931
+ const result = {
138932
+ hookSpecificOutput: {
138933
+ hookEventName: "PreToolUse",
138934
+ permissionDecision: "allow"
138935
+ }
138936
+ };
138937
+ if (warnings.length > 0) {
138938
+ result.hookSpecificOutput.additionalContext = `Warnings: ${warnings.join("; ")}`;
138939
+ }
138940
+ printJson(result);
138941
+ } else if (warnings.length > 0) {
138942
+ console.log(chalk27.yellow("\n\u26A0\uFE0F Command Warnings:"));
138943
+ warnings.forEach((w54) => console.log(chalk27.yellow(` - ${w54}`)));
138944
+ }
138350
138945
  }
138351
138946
  process.exit(0);
138352
138947
  } catch (error) {
138353
138948
  if (options.json) {
138354
- printJson({ success: false, error: error instanceof Error ? error.message : "unknown" });
138949
+ printJson({
138950
+ hookSpecificOutput: {
138951
+ hookEventName: "PreToolUse",
138952
+ permissionDecision: "allow"
138953
+ }
138954
+ });
138355
138955
  }
138356
138956
  process.exit(0);
138357
138957
  }
@@ -140349,7 +140949,7 @@ async function cleanupAndExit(code = 0) {
140349
140949
  process.exit(code);
140350
140950
  }
140351
140951
  var program = new Command18();
140352
- var VERSION = true ? "3.6.6" : "0.0.0-dev";
140952
+ var VERSION = true ? "3.6.7" : "0.0.0-dev";
140353
140953
  program.name("aqe").description("Agentic QE - Domain-Driven Quality Engineering").version(VERSION);
140354
140954
  var registry = createCommandRegistry(context, cleanupAndExit, ensureInitialized);
140355
140955
  registry.registerAll(program);