agentic-qe 3.7.19 → 3.7.21

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 (77) hide show
  1. package/.claude/agents/v3/qe-deployment-advisor.md +14 -0
  2. package/.claude/agents/v3/qe-gap-detector.md +8 -0
  3. package/.claude/agents/v3/qe-impact-analyzer.md +11 -0
  4. package/.claude/agents/v3/qe-queen-coordinator.md +45 -0
  5. package/.claude/agents/v3/qe-root-cause-analyzer.md +11 -0
  6. package/.claude/agents/v3/qe-security-scanner.md +25 -16
  7. package/.claude/helpers/brain-checkpoint.cjs +3 -3
  8. package/.claude/helpers/statusline-v3.cjs +4 -3
  9. package/.claude/skills/skills-manifest.json +1 -1
  10. package/CHANGELOG.md +27 -0
  11. package/assets/agents/v3/qe-deployment-advisor.md +14 -0
  12. package/assets/agents/v3/qe-gap-detector.md +8 -0
  13. package/assets/agents/v3/qe-impact-analyzer.md +11 -0
  14. package/assets/agents/v3/qe-queen-coordinator.md +45 -0
  15. package/assets/agents/v3/qe-root-cause-analyzer.md +11 -0
  16. package/assets/agents/v3/qe-security-scanner.md +25 -16
  17. package/assets/helpers/statusline-v3.cjs +4 -3
  18. package/dist/adapters/claude-flow/model-router-bridge.d.ts +0 -6
  19. package/dist/adapters/claude-flow/model-router-bridge.js +4 -17
  20. package/dist/adapters/claude-flow/pretrain-bridge.d.ts +0 -6
  21. package/dist/adapters/claude-flow/pretrain-bridge.js +6 -19
  22. package/dist/adapters/claude-flow/trajectory-bridge.d.ts +0 -6
  23. package/dist/adapters/claude-flow/trajectory-bridge.js +21 -23
  24. package/dist/cli/bundle.js +1821 -986
  25. package/dist/coordination/protocols/security-audit.d.ts +3 -6
  26. package/dist/coordination/protocols/security-audit.js +8 -88
  27. package/dist/coordination/queen-coordinator.d.ts +13 -0
  28. package/dist/coordination/queen-coordinator.js +76 -0
  29. package/dist/coordination/queen-task-management.d.ts +2 -0
  30. package/dist/coordination/queen-task-management.js +10 -0
  31. package/dist/coordination/queen-types.d.ts +3 -0
  32. package/dist/coordination/task-executor.js +7 -5
  33. package/dist/domains/security-compliance/services/scanners/sast-scanner.d.ts +25 -1
  34. package/dist/domains/security-compliance/services/scanners/sast-scanner.js +140 -11
  35. package/dist/domains/security-compliance/services/scanners/scanner-types.d.ts +2 -0
  36. package/dist/domains/security-compliance/services/scanners/scanner-types.js +1 -0
  37. package/dist/domains/test-execution/services/mincut-test-optimizer.js +2 -0
  38. package/dist/governance/continue-gate-integration.js +1 -1
  39. package/dist/governance/feature-flags.js +2 -2
  40. package/dist/init/agents-installer.d.ts +2 -0
  41. package/dist/init/agents-installer.js +13 -0
  42. package/dist/init/enhancements/claude-flow-adapter.js +51 -24
  43. package/dist/init/init-wizard.js +1 -1
  44. package/dist/init/phases/07-hooks.js +6 -6
  45. package/dist/init/settings-merge.js +2 -0
  46. package/dist/integrations/ruvector/brain-rvf-exporter.js +14 -2
  47. package/dist/learning/experience-capture-middleware.js +3 -1
  48. package/dist/learning/qe-reasoning-bank.js +3 -3
  49. package/dist/learning/sqlite-persistence.js +16 -0
  50. package/dist/learning/token-tracker.js +4 -2
  51. package/dist/mcp/bundle.js +1183 -504
  52. package/dist/routing/agent-dependency-graph.d.ts +77 -0
  53. package/dist/routing/agent-dependency-graph.js +359 -0
  54. package/dist/routing/co-execution-repository.d.ts +68 -0
  55. package/dist/routing/co-execution-repository.js +184 -0
  56. package/dist/routing/index.d.ts +6 -0
  57. package/dist/routing/index.js +6 -0
  58. package/dist/routing/qe-task-router.d.ts +7 -0
  59. package/dist/routing/qe-task-router.js +63 -1
  60. package/dist/routing/signal-merger.d.ts +81 -0
  61. package/dist/routing/signal-merger.js +136 -0
  62. package/dist/routing/types.d.ts +1 -0
  63. package/dist/shared/llm/providers/azure-openai.js +3 -2
  64. package/dist/shared/llm/providers/bedrock.js +3 -2
  65. package/dist/shared/llm/providers/claude.js +3 -2
  66. package/dist/shared/llm/providers/gemini.js +3 -2
  67. package/dist/shared/llm/providers/openai.js +3 -2
  68. package/dist/shared/llm/providers/openrouter.js +3 -2
  69. package/dist/shared/llm/retry.d.ts +10 -0
  70. package/dist/shared/llm/retry.js +16 -0
  71. package/dist/shared/llm/router/agent-router-config.d.ts +2 -1
  72. package/dist/shared/llm/router/agent-router-config.js +38 -88
  73. package/dist/validation/index.d.ts +2 -0
  74. package/dist/validation/index.js +4 -0
  75. package/dist/validation/steps/agent-mcp-validator.d.ts +88 -0
  76. package/dist/validation/steps/agent-mcp-validator.js +254 -0
  77. package/package.json +1 -1
@@ -263,6 +263,8 @@ export class MinCutTestOptimizerImpl {
263
263
  criticalTests.add(promotedId);
264
264
  skippableTests.delete(promotedId);
265
265
  const promotedTest = testMap.get(promotedId);
266
+ if (!promotedTest)
267
+ continue;
266
268
  for (const file of promotedTest.coveredFiles) {
267
269
  covered.add(file);
268
270
  }
@@ -153,7 +153,7 @@ export class ContinueGateIntegration {
153
153
  budgetRemaining: {
154
154
  tokens: Math.max(0, (flags.maxConsecutiveRetries * 10 * 500) - (history.length * 500)),
155
155
  toolCalls: Math.max(0, (flags.maxConsecutiveRetries * 10) - history.length),
156
- timeMs: Math.max(0, flags.idleTimeoutMs - (history.length > 0 ? Date.now() - history[0].timestamp : 0)),
156
+ timeMs: Math.max(0, flags.idleTimeoutMs - (history.length > 0 ? Date.now() - history[history.length - 1].timestamp : 0)),
157
157
  },
158
158
  recentDecisions: [],
159
159
  };
@@ -16,7 +16,7 @@ export const DEFAULT_GOVERNANCE_FLAGS = {
16
16
  enabled: true,
17
17
  maxConsecutiveRetries: 3,
18
18
  reworkRatioThreshold: 0.5,
19
- idleTimeoutMs: 5 * 60 * 1000, // 5 minutes
19
+ idleTimeoutMs: 15 * 60 * 1000, // 15 minutes
20
20
  throttleOnExceed: true,
21
21
  },
22
22
  memoryWriteGate: {
@@ -124,7 +124,7 @@ export function loadFlagsFromEnv() {
124
124
  enabled: env.GOVERNANCE_CONTINUE_GATE !== 'false',
125
125
  maxConsecutiveRetries: parseInt(env.GOVERNANCE_MAX_RETRIES || '3', 10),
126
126
  reworkRatioThreshold: parseFloat(env.GOVERNANCE_REWORK_THRESHOLD || '0.5'),
127
- idleTimeoutMs: parseInt(env.GOVERNANCE_IDLE_TIMEOUT || '300000', 10),
127
+ idleTimeoutMs: parseInt(env.GOVERNANCE_IDLE_TIMEOUT || '900000', 10),
128
128
  throttleOnExceed: env.GOVERNANCE_THROTTLE !== 'false',
129
129
  },
130
130
  memoryWriteGate: {
@@ -21,6 +21,8 @@ export interface AgentsInstallResult {
21
21
  overlaysApplied?: string[];
22
22
  /** Warnings from overlay loading */
23
23
  overlayWarnings?: string[];
24
+ /** MCP dependency validation warnings (advisory only) */
25
+ mcpValidationWarnings?: string[];
24
26
  }
25
27
  export interface AgentsInstallerOptions {
26
28
  /** Project root directory */
@@ -10,6 +10,7 @@ import { join, dirname } from 'path';
10
10
  import { fileURLToPath } from 'url';
11
11
  import { toErrorMessage } from '../shared/error-utils.js';
12
12
  import { loadOverlays, applyOverlayToContent } from '../agents/overlay-loader.js';
13
+ import { validateFleetMcpDeps } from '../validation/steps/agent-mcp-validator.js';
13
14
  // ============================================================================
14
15
  // Agent Categories
15
16
  // ============================================================================
@@ -298,6 +299,18 @@ export class AgentsInstaller {
298
299
  if (result.overlaysApplied.length > 0) {
299
300
  console.error(`[AgentsInstaller] Applied ${result.overlaysApplied.length} agent overlay(s): ${result.overlaysApplied.join(', ')}`);
300
301
  }
302
+ // Validate MCP dependencies (advisory only -- Issue #342 Item 1)
303
+ const mcpValidation = validateFleetMcpDeps(targetAgentsDir, this.projectRoot);
304
+ result.mcpValidationWarnings = mcpValidation.warnings;
305
+ if (mcpValidation.warnings.length > 0) {
306
+ console.error(`[AgentsInstaller] MCP dependency warnings (${mcpValidation.agentsWithMissingDeps.length} agents affected):`);
307
+ for (const warning of mcpValidation.warnings.slice(0, 10)) {
308
+ console.error(` ${warning}`);
309
+ }
310
+ if (mcpValidation.warnings.length > 10) {
311
+ console.error(` ... and ${mcpValidation.warnings.length - 10} more warnings`);
312
+ }
313
+ }
301
314
  // Create agents index file
302
315
  await this.createAgentsIndex(targetAgentsDir, result.installed);
303
316
  return result;
@@ -11,9 +11,18 @@
11
11
  */
12
12
  import { detectClaudeFlow } from '../../adapters/claude-flow/detect.js';
13
13
  import { safeJsonParse } from '../../shared/safe-json.js';
14
- /** Shared execSync options for cross-platform CLI calls */
15
- const SHELL = process.platform === 'win32' ? 'cmd.exe' : '/bin/sh';
16
- const EXEC_OPTS = { encoding: 'utf-8', shell: SHELL };
14
+ /** Shared execFileSync options */
15
+ const EXEC_OPTS = { encoding: 'utf-8' };
16
+ /**
17
+ * Build args array for npx @claude-flow/cli calls.
18
+ * Using execFileSync with explicit args prevents shell injection.
19
+ */
20
+ function cfCliArgs(...subcommand) {
21
+ return {
22
+ bin: 'npx',
23
+ args: ['--no-install', '@claude-flow/cli', ...subcommand],
24
+ };
25
+ }
17
26
  /**
18
27
  * Claude Flow Adapter Implementation
19
28
  * Falls back gracefully when Claude Flow is not available
@@ -86,9 +95,12 @@ export class ClaudeFlowAdapterImpl {
86
95
  return `aqe-trajectory-${Date.now()}`;
87
96
  }
88
97
  try {
89
- const { execSync } = await import('child_process');
90
- const agentArg = agent ? `--agent "${agent}"` : '';
91
- const result = execSync(`npx --no-install @claude-flow/cli hooks intelligence trajectory-start --task "${task}" ${agentArg}`, { ...EXEC_OPTS, timeout: 10000 });
98
+ const { execFileSync } = await import('child_process');
99
+ const { bin, args } = cfCliArgs('hooks', 'intelligence', 'trajectory-start', '--task', task);
100
+ if (agent) {
101
+ args.push('--agent', agent);
102
+ }
103
+ const result = execFileSync(bin, args, { ...EXEC_OPTS, timeout: 10000 });
92
104
  // Parse trajectory ID from result
93
105
  const match = result.match(/trajectoryId[:\s]+["']?([^"'\s]+)/i);
94
106
  return match?.[1] || `cf-trajectory-${Date.now()}`;
@@ -104,10 +116,15 @@ export class ClaudeFlowAdapterImpl {
104
116
  if (!this.available)
105
117
  return;
106
118
  try {
107
- const { execSync } = await import('child_process');
108
- const resultArg = result ? `--result "${result}"` : '';
109
- const qualityArg = quality !== undefined ? `--quality ${quality}` : '';
110
- execSync(`npx --no-install @claude-flow/cli hooks intelligence trajectory-step --trajectory-id "${trajectoryId}" --action "${action}" ${resultArg} ${qualityArg}`, { ...EXEC_OPTS, timeout: 10000 });
119
+ const { execFileSync } = await import('child_process');
120
+ const { bin, args } = cfCliArgs('hooks', 'intelligence', 'trajectory-step', '--trajectory-id', trajectoryId, '--action', action);
121
+ if (result) {
122
+ args.push('--result', result);
123
+ }
124
+ if (quality !== undefined) {
125
+ args.push('--quality', String(quality));
126
+ }
127
+ execFileSync(bin, args, { ...EXEC_OPTS, timeout: 10000 });
111
128
  }
112
129
  catch (error) {
113
130
  // Non-critical: trajectory tracking is optional
@@ -121,9 +138,12 @@ export class ClaudeFlowAdapterImpl {
121
138
  if (!this.available)
122
139
  return;
123
140
  try {
124
- const { execSync } = await import('child_process');
125
- const feedbackArg = feedback ? `--feedback "${feedback}"` : '';
126
- execSync(`npx --no-install @claude-flow/cli hooks intelligence trajectory-end --trajectory-id "${trajectoryId}" --success ${success} ${feedbackArg}`, { ...EXEC_OPTS, timeout: 10000 });
141
+ const { execFileSync } = await import('child_process');
142
+ const { bin, args } = cfCliArgs('hooks', 'intelligence', 'trajectory-end', '--trajectory-id', trajectoryId, '--success', String(success));
143
+ if (feedback) {
144
+ args.push('--feedback', feedback);
145
+ }
146
+ execFileSync(bin, args, { ...EXEC_OPTS, timeout: 10000 });
127
147
  }
128
148
  catch (error) {
129
149
  // Non-critical: trajectory end is optional
@@ -139,8 +159,9 @@ export class ClaudeFlowAdapterImpl {
139
159
  return { model: 'sonnet', confidence: 0.5 };
140
160
  }
141
161
  try {
142
- const { execSync } = await import('child_process');
143
- const result = execSync(`npx --no-install @claude-flow/cli hooks model-route --task "${task}"`, { ...EXEC_OPTS, timeout: 10000 });
162
+ const { execFileSync } = await import('child_process');
163
+ const { bin, args } = cfCliArgs('hooks', 'model-route', '--task', task);
164
+ const result = execFileSync(bin, args, { ...EXEC_OPTS, timeout: 10000 });
144
165
  // Parse result
145
166
  const modelMatch = result.match(/model[:\s]+["']?(haiku|sonnet|opus)/i);
146
167
  const confMatch = result.match(/confidence[:\s]+([0-9.]+)/i);
@@ -162,8 +183,9 @@ export class ClaudeFlowAdapterImpl {
162
183
  if (!this.available)
163
184
  return;
164
185
  try {
165
- const { execSync } = await import('child_process');
166
- execSync(`npx --no-install @claude-flow/cli hooks model-outcome --task "${task}" --model ${model} --outcome ${outcome}`, { ...EXEC_OPTS, timeout: 10000 });
186
+ const { execFileSync } = await import('child_process');
187
+ const { bin, args } = cfCliArgs('hooks', 'model-outcome', '--task', task, '--model', model, '--outcome', outcome);
188
+ execFileSync(bin, args, { ...EXEC_OPTS, timeout: 10000 });
167
189
  }
168
190
  catch (error) {
169
191
  // Non-critical: outcome recording is optional
@@ -178,8 +200,9 @@ export class ClaudeFlowAdapterImpl {
178
200
  return { success: false, reason: 'Claude Flow not available' };
179
201
  }
180
202
  try {
181
- const { execSync } = await import('child_process');
182
- const result = execSync(`npx --no-install @claude-flow/cli hooks pretrain --path "${path}" --depth ${depth}`, { ...EXEC_OPTS, timeout: 60000 });
203
+ const { execFileSync } = await import('child_process');
204
+ const { bin, args } = cfCliArgs('hooks', 'pretrain', '--path', path, '--depth', depth);
205
+ const result = execFileSync(bin, args, { ...EXEC_OPTS, timeout: 60000 });
183
206
  // Try to parse JSON result
184
207
  try {
185
208
  return safeJsonParse(result);
@@ -199,9 +222,12 @@ export class ClaudeFlowAdapterImpl {
199
222
  if (!this.available)
200
223
  return;
201
224
  try {
202
- const { execSync } = await import('child_process');
203
- const metadataArg = metadata ? `--metadata '${JSON.stringify(metadata)}'` : '';
204
- execSync(`npx --no-install @claude-flow/cli hooks intelligence pattern-store --pattern "${pattern}" --type ${type} --confidence ${confidence} ${metadataArg}`, { ...EXEC_OPTS, timeout: 10000 });
225
+ const { execFileSync } = await import('child_process');
226
+ const { bin, args } = cfCliArgs('hooks', 'intelligence', 'pattern-store', '--pattern', pattern, '--type', type, '--confidence', String(confidence));
227
+ if (metadata) {
228
+ args.push('--metadata', JSON.stringify(metadata));
229
+ }
230
+ execFileSync(bin, args, { ...EXEC_OPTS, timeout: 10000 });
205
231
  }
206
232
  catch (error) {
207
233
  // Non-critical: pattern storage is optional
@@ -216,8 +242,9 @@ export class ClaudeFlowAdapterImpl {
216
242
  return [];
217
243
  }
218
244
  try {
219
- const { execSync } = await import('child_process');
220
- const result = execSync(`npx --no-install @claude-flow/cli hooks intelligence pattern-search --query "${query}" --top-k ${topK}`, { ...EXEC_OPTS, timeout: 10000 });
245
+ const { execFileSync } = await import('child_process');
246
+ const { bin, args } = cfCliArgs('hooks', 'intelligence', 'pattern-search', '--query', query, '--top-k', String(topK));
247
+ const result = execFileSync(bin, args, { ...EXEC_OPTS, timeout: 10000 });
221
248
  // Try to parse JSON result
222
249
  try {
223
250
  const parsed = safeJsonParse(result);
@@ -272,7 +272,7 @@ export class InitOrchestrator {
272
272
  if (this.options.autoMigrate) {
273
273
  console.log('Auto-migrate mode enabled. Running migration...\n');
274
274
  // Fire and forget - the caller will await initialize() which runs migration inline
275
- runV2Migration(this.projectRoot, v2Detection).catch(() => { });
275
+ runV2Migration(this.projectRoot, v2Detection).catch((e) => { console.warn('[InitWizard] V2 migration failed:', e instanceof Error ? e.message : e); });
276
276
  return null;
277
277
  }
278
278
  // Warn and suggest migration
@@ -285,9 +285,9 @@ export class HooksPhase extends BasePhase {
285
285
  */
286
286
  const fs = require('fs');
287
287
  const path = require('path');
288
- const { execSync } = require('child_process');
288
+ const { execFileSync } = require('child_process');
289
289
 
290
- function q(cmd, d) { try { return execSync(cmd, { encoding: 'utf-8', timeout: 3000 }).trim(); } catch { return d || ''; } }
290
+ function q(bin, args, d) { try { return execFileSync(bin, args, { encoding: 'utf-8', timeout: 3000, stdio: ['pipe', 'pipe', 'pipe'] }).trim(); } catch { return d || ''; } }
291
291
 
292
292
  const dir = process.cwd();
293
293
  const dbPath = path.join(dir, '.agentic-qe', 'memory.db');
@@ -301,7 +301,7 @@ try {
301
301
  }
302
302
  } catch { /* ignore */ }
303
303
 
304
- const branch = q('git branch --show-current 2>/dev/null');
304
+ const branch = q('git', ['branch', '--show-current']);
305
305
  const branchStr = branch ? \` \\x1b[34m⎇ \${branch}\\x1b[0m\` : '';
306
306
  const patStr = patterns > 0 ? \` \\x1b[35m🎓 \${patterns} patterns\\x1b[0m\` : '';
307
307
 
@@ -321,7 +321,7 @@ console.log(\`\\x1b[1m\\x1b[35m▊ Agentic QE v3\\x1b[0m\${branchStr}\${patStr}\
321
321
  * node brain-checkpoint.cjs export # Export brain to aqe.rvf (session-end)
322
322
  * node brain-checkpoint.cjs verify # Verify aqe.rvf exists (session-start)
323
323
  */
324
- const { execSync } = require('child_process');
324
+ const { execFileSync } = require('child_process');
325
325
  const fs = require('fs');
326
326
  const path = require('path');
327
327
 
@@ -338,8 +338,8 @@ function exportBrain() {
338
338
  if (fs.existsSync(RVF_PATH)) fs.unlinkSync(RVF_PATH);
339
339
  const idmap = RVF_PATH + '.idmap.json';
340
340
  if (fs.existsSync(idmap)) fs.unlinkSync(idmap);
341
- const result = execSync(
342
- 'npx agentic-qe brain export -o "' + RVF_PATH + '" --format rvf 2>&1',
341
+ const result = execFileSync(
342
+ 'npx', ['agentic-qe', 'brain', 'export', '-o', RVF_PATH, '--format', 'rvf'],
343
343
  { timeout: 60000, encoding: 'utf-8' }
344
344
  );
345
345
  const m = result.match(/Patterns:\\s+(\\d+)/);
@@ -13,6 +13,8 @@ const AQE_COMMAND_PATTERNS = [
13
13
  /\bagentic-qe\b/i,
14
14
  /\bnpx\s+agentic-qe\b/i,
15
15
  /\bnpx\s+@anthropics\/agentic-qe\b/i,
16
+ /brain-checkpoint\.cjs/i,
17
+ /\.claude\/helpers\//i,
16
18
  ];
17
19
  /**
18
20
  * Check if a single hook entry belongs to AQE (any variant).
@@ -195,7 +195,13 @@ export function importBrainFromRvf(db, rvfPath, options) {
195
195
  if (!kernel || !kernel.image) {
196
196
  throw new Error('No brain data found in RVF file (missing kernel segment)');
197
197
  }
198
- const brainData = JSON.parse(kernel.image.toString('utf-8'));
198
+ let brainData;
199
+ try {
200
+ brainData = JSON.parse(kernel.image.toString('utf-8'));
201
+ }
202
+ catch (parseErr) {
203
+ throw new Error(`Failed to parse brain kernel data as JSON: ${parseErr instanceof Error ? parseErr.message : parseErr}`);
204
+ }
199
205
  if (options.dryRun) {
200
206
  let total = 0;
201
207
  if (brainData.tables) {
@@ -296,7 +302,13 @@ export function brainInfoFromRvf(rvfPath) {
296
302
  throw new Error('No brain data found in RVF file');
297
303
  }
298
304
  const brainJson = kernel.image.toString('utf-8');
299
- const brainData = JSON.parse(brainJson);
305
+ let brainData;
306
+ try {
307
+ brainData = JSON.parse(brainJson);
308
+ }
309
+ catch (parseErr) {
310
+ throw new Error(`Failed to parse brain kernel data as JSON: ${parseErr instanceof Error ? parseErr.message : parseErr}`);
311
+ }
300
312
  const status = rvf.status();
301
313
  const fileSize = statSync(filePath).size;
302
314
  const t = brainData.tables;
@@ -14,6 +14,8 @@
14
14
  import { v4 as uuidv4 } from 'uuid';
15
15
  import { getUnifiedMemory } from '../kernel/unified-memory.js';
16
16
  import { toErrorMessage } from '../shared/error-utils.js';
17
+ import { createLogger } from '../logging/logger-factory.js';
18
+ const ecLogger = createLogger('ExperienceCapture');
17
19
  // ============================================================================
18
20
  // Active Experience Tracking
19
21
  // ============================================================================
@@ -269,7 +271,7 @@ async function persistExperience(context, outcome) {
269
271
  `);
270
272
  stmt.run(outcome.id, context.task, context.agent, context.domain, outcome.success ? 1 : 0, outcome.quality, outcome.durationMs, context.modelTier || null, safeJsonStringify(context.routing), safeJsonStringify(outcome.steps), safeJsonStringify(outcome.result), outcome.error || null, context.startedAt.toISOString(), 'middleware');
271
273
  // Fire-and-forget: compute and store embedding for this experience
272
- computeExperienceEmbedding(db, outcome.id, context.task, context.domain).catch(() => { });
274
+ computeExperienceEmbedding(db, outcome.id, context.task, context.domain).catch((e) => { ecLogger.warn('Embedding computation failed', { error: e instanceof Error ? e.message : String(e), experienceId: outcome.id, domain: context.domain }); });
273
275
  }
274
276
  catch (error) {
275
277
  console.error('[ExperienceCaptureMiddleware] Failed to persist experience:', error);
@@ -1059,7 +1059,7 @@ On promotion:
1059
1059
  const result = await this.patternStore.create(options);
1060
1060
  // ADR-070: Record pattern creation in witness chain
1061
1061
  if (result.success) {
1062
- getWitnessChain().then(wc => wc.append('PATTERN_CREATE', { patternId: result.value.id, domain: result.value.qeDomain, confidence: result.value.confidence, name: result.value.name }, 'reasoning-bank')).catch(() => { });
1062
+ getWitnessChain().then(wc => wc.append('PATTERN_CREATE', { patternId: result.value.id, domain: result.value.qeDomain, confidence: result.value.confidence, name: result.value.name }, 'reasoning-bank')).catch((e) => { logger.warn('Witness chain PATTERN_CREATE failed', { error: toErrorMessage(e) }); });
1063
1063
  // Phase 3: Best-effort RVF dual-write for vector replication
1064
1064
  if (this.rvfDualWriter && result.value.embedding && result.value.embedding.length > 0) {
1065
1065
  try {
@@ -1137,7 +1137,7 @@ On promotion:
1137
1137
  this.stats.successfulOutcomes++;
1138
1138
  }
1139
1139
  // ADR-070: Record pattern update in witness chain
1140
- getWitnessChain().then(wc => wc.append('PATTERN_UPDATE', { patternId: outcome.patternId, success: outcome.success }, 'reasoning-bank')).catch(() => { });
1140
+ getWitnessChain().then(wc => wc.append('PATTERN_UPDATE', { patternId: outcome.patternId, success: outcome.success }, 'reasoning-bank')).catch((e) => { logger.warn('Witness chain PATTERN_UPDATE failed', { error: toErrorMessage(e) }); });
1141
1141
  // Check if pattern should be promoted (with coherence gate)
1142
1142
  const pattern = await this.getPattern(outcome.patternId);
1143
1143
  if (pattern && await this.checkPatternPromotionWithCoherence(pattern)) {
@@ -1240,7 +1240,7 @@ On promotion:
1240
1240
  }
1241
1241
  }
1242
1242
  // ADR-070: Record pattern promotion in witness chain
1243
- getWitnessChain().then(wc => wc.append('PATTERN_PROMOTE', { patternId }, 'reasoning-bank')).catch(() => { });
1243
+ getWitnessChain().then(wc => wc.append('PATTERN_PROMOTE', { patternId }, 'reasoning-bank')).catch((e) => { logger.warn('Witness chain PATTERN_PROMOTE failed', { error: toErrorMessage(e) }); });
1244
1244
  logger.info('Promoted pattern to long-term', { patternId });
1245
1245
  if (this.eventBus) {
1246
1246
  await this.eventBus.publish({
@@ -183,6 +183,22 @@ export class SQLitePatternStore {
183
183
  FOREIGN KEY (pattern_id) REFERENCES qe_patterns(id) ON DELETE CASCADE
184
184
  );
185
185
 
186
+ -- Agent co-execution tracking (Issue #342 Item 3)
187
+ CREATE TABLE IF NOT EXISTS qe_agent_co_execution (
188
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
189
+ agent_a TEXT NOT NULL,
190
+ agent_b TEXT NOT NULL,
191
+ domain TEXT NOT NULL,
192
+ success INTEGER NOT NULL DEFAULT 0,
193
+ task_description TEXT,
194
+ created_at TEXT DEFAULT (datetime('now'))
195
+ );
196
+
197
+ CREATE INDEX IF NOT EXISTS idx_co_exec_agents
198
+ ON qe_agent_co_execution(agent_a, agent_b);
199
+ CREATE INDEX IF NOT EXISTS idx_co_exec_domain
200
+ ON qe_agent_co_execution(domain);
201
+
186
202
  -- Unique constraint to prevent duplicate patterns
187
203
  CREATE UNIQUE INDEX IF NOT EXISTS idx_patterns_unique_name_domain_type
188
204
  ON qe_patterns(name, qe_domain, pattern_type);
@@ -34,6 +34,8 @@ import { randomUUID } from 'crypto';
34
34
  import { getUnifiedMemory } from '../kernel/unified-memory.js';
35
35
  import { toErrorMessage } from '../shared/error-utils.js';
36
36
  import { safeJsonParse } from '../shared/safe-json.js';
37
+ import { createLogger } from '../logging/logger-factory.js';
38
+ const ttLogger = createLogger('TokenTracker');
37
39
  const DEFAULT_COST_CONFIG = {
38
40
  costPerInputToken: 0.003 / 1000, // $3 per 1M input tokens
39
41
  costPerOutputToken: 0.015 / 1000, // $15 per 1M output tokens
@@ -84,7 +86,7 @@ class TokenMetricsCollectorImpl {
84
86
  this.costConfig = { ...DEFAULT_COST_CONFIG, ...config };
85
87
  }
86
88
  // Activate DB-backed persistence and auto-save timer
87
- this.initializeDb().catch(() => { });
89
+ this.initializeDb().catch((e) => { ttLogger.warn('DB initialization failed', { error: e instanceof Error ? e.message : String(e) }); });
88
90
  this.startAutoSave();
89
91
  }
90
92
  /**
@@ -601,7 +603,7 @@ class TokenMetricsCollectorImpl {
601
603
  this.kvPersistCount++;
602
604
  if (this.kvPersistCount >= TokenMetricsCollectorImpl.KV_PERSIST_INTERVAL) {
603
605
  this.kvPersistCount = 0;
604
- this.persistToKv().catch(() => { });
606
+ this.persistToKv().catch((e) => { ttLogger.warn('KV persist failed', { error: e instanceof Error ? e.message : String(e) }); });
605
607
  }
606
608
  }
607
609
  // ============================================================================