agentic-qe 3.7.20 → 3.7.22

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 (115) 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 +7 -4
  8. package/.claude/helpers/statusline-v3.cjs +7 -4
  9. package/.claude/skills/skills-manifest.json +1 -1
  10. package/CHANGELOG.md +34 -0
  11. package/README.md +0 -12
  12. package/assets/agents/v3/qe-deployment-advisor.md +14 -0
  13. package/assets/agents/v3/qe-gap-detector.md +8 -0
  14. package/assets/agents/v3/qe-impact-analyzer.md +11 -0
  15. package/assets/agents/v3/qe-queen-coordinator.md +45 -0
  16. package/assets/agents/v3/qe-root-cause-analyzer.md +11 -0
  17. package/assets/agents/v3/qe-security-scanner.md +25 -16
  18. package/assets/helpers/statusline-v3.cjs +7 -4
  19. package/dist/adapters/claude-flow/model-router-bridge.d.ts +0 -6
  20. package/dist/adapters/claude-flow/model-router-bridge.js +4 -17
  21. package/dist/adapters/claude-flow/pretrain-bridge.d.ts +0 -6
  22. package/dist/adapters/claude-flow/pretrain-bridge.js +6 -19
  23. package/dist/adapters/claude-flow/trajectory-bridge.d.ts +0 -6
  24. package/dist/adapters/claude-flow/trajectory-bridge.js +21 -23
  25. package/dist/cli/brain-commands.js +6 -10
  26. package/dist/cli/bundle.js +3124 -3622
  27. package/dist/cli/commands/hooks.js +29 -6
  28. package/dist/cli/commands/init.js +1 -73
  29. package/dist/cli/commands/learning.js +164 -12
  30. package/dist/cli/handlers/init-handler.d.ts +0 -1
  31. package/dist/cli/handlers/init-handler.js +0 -6
  32. package/dist/cli/index.js +0 -2
  33. package/dist/context/sources/defect-source.js +2 -2
  34. package/dist/context/sources/memory-source.js +2 -2
  35. package/dist/context/sources/requirements-source.js +2 -2
  36. package/dist/coordination/protocols/security-audit.d.ts +3 -6
  37. package/dist/coordination/protocols/security-audit.js +8 -88
  38. package/dist/coordination/queen-coordinator.d.ts +13 -0
  39. package/dist/coordination/queen-coordinator.js +76 -0
  40. package/dist/coordination/queen-task-management.d.ts +2 -0
  41. package/dist/coordination/queen-task-management.js +10 -0
  42. package/dist/coordination/queen-types.d.ts +3 -0
  43. package/dist/coordination/task-executor.js +7 -5
  44. package/dist/domains/security-compliance/services/scanners/sast-scanner.d.ts +25 -1
  45. package/dist/domains/security-compliance/services/scanners/sast-scanner.js +140 -11
  46. package/dist/domains/security-compliance/services/scanners/scanner-types.d.ts +2 -0
  47. package/dist/domains/security-compliance/services/scanners/scanner-types.js +1 -0
  48. package/dist/domains/test-execution/services/mincut-test-optimizer.js +2 -0
  49. package/dist/init/agents-installer.d.ts +2 -0
  50. package/dist/init/agents-installer.js +13 -0
  51. package/dist/init/enhancements/claude-flow-adapter.js +51 -24
  52. package/dist/init/index.d.ts +0 -2
  53. package/dist/init/index.js +0 -1
  54. package/dist/init/init-wizard-steps.d.ts +10 -0
  55. package/dist/init/init-wizard-steps.js +87 -1
  56. package/dist/init/init-wizard.d.ts +1 -9
  57. package/dist/init/init-wizard.js +3 -69
  58. package/dist/init/orchestrator.js +0 -1
  59. package/dist/init/phases/01-detection.js +0 -27
  60. package/dist/init/phases/07-hooks.js +12 -10
  61. package/dist/init/phases/phase-interface.d.ts +0 -1
  62. package/dist/init/settings-merge.js +1 -1
  63. package/dist/integrations/ruvector/brain-rvf-exporter.js +14 -2
  64. package/dist/kernel/unified-memory.js +5 -6
  65. package/dist/learning/experience-capture-middleware.js +23 -1
  66. package/dist/learning/index.d.ts +0 -2
  67. package/dist/learning/index.js +0 -4
  68. package/dist/learning/metrics-tracker.js +15 -13
  69. package/dist/learning/pattern-lifecycle.d.ts +1 -1
  70. package/dist/learning/pattern-lifecycle.js +18 -20
  71. package/dist/learning/qe-reasoning-bank.js +3 -3
  72. package/dist/learning/qe-unified-memory.js +1 -28
  73. package/dist/learning/sqlite-persistence.js +16 -0
  74. package/dist/learning/token-tracker.js +4 -2
  75. package/dist/mcp/bundle.js +1162 -478
  76. package/dist/routing/agent-dependency-graph.d.ts +77 -0
  77. package/dist/routing/agent-dependency-graph.js +359 -0
  78. package/dist/routing/co-execution-repository.d.ts +68 -0
  79. package/dist/routing/co-execution-repository.js +184 -0
  80. package/dist/routing/index.d.ts +6 -0
  81. package/dist/routing/index.js +6 -0
  82. package/dist/routing/qe-task-router.d.ts +7 -0
  83. package/dist/routing/qe-task-router.js +63 -1
  84. package/dist/routing/signal-merger.d.ts +81 -0
  85. package/dist/routing/signal-merger.js +136 -0
  86. package/dist/routing/types.d.ts +1 -0
  87. package/dist/shared/llm/providers/azure-openai.js +3 -2
  88. package/dist/shared/llm/providers/bedrock.js +3 -2
  89. package/dist/shared/llm/providers/claude.js +3 -2
  90. package/dist/shared/llm/providers/gemini.js +3 -2
  91. package/dist/shared/llm/providers/openai.js +3 -2
  92. package/dist/shared/llm/providers/openrouter.js +3 -2
  93. package/dist/shared/llm/retry.d.ts +10 -0
  94. package/dist/shared/llm/retry.js +16 -0
  95. package/dist/shared/llm/router/agent-router-config.d.ts +2 -1
  96. package/dist/shared/llm/router/agent-router-config.js +38 -88
  97. package/dist/validation/index.d.ts +2 -0
  98. package/dist/validation/index.js +4 -0
  99. package/dist/validation/steps/agent-mcp-validator.d.ts +88 -0
  100. package/dist/validation/steps/agent-mcp-validator.js +254 -0
  101. package/package.json +1 -1
  102. package/dist/cli/commands/migrate.d.ts +0 -9
  103. package/dist/cli/commands/migrate.js +0 -566
  104. package/dist/init/init-wizard-migration.d.ts +0 -52
  105. package/dist/init/init-wizard-migration.js +0 -345
  106. package/dist/init/migration/config-migrator.d.ts +0 -31
  107. package/dist/init/migration/config-migrator.js +0 -149
  108. package/dist/init/migration/data-migrator.d.ts +0 -72
  109. package/dist/init/migration/data-migrator.js +0 -232
  110. package/dist/init/migration/detector.d.ts +0 -44
  111. package/dist/init/migration/detector.js +0 -105
  112. package/dist/init/migration/index.d.ts +0 -8
  113. package/dist/init/migration/index.js +0 -8
  114. package/dist/learning/v2-to-v3-migration.d.ts +0 -86
  115. package/dist/learning/v2-to-v3-migration.js +0 -529
@@ -57,8 +57,6 @@ export { SQLitePatternStore, createSQLitePatternStore, DEFAULT_SQLITE_CONFIG, }
57
57
  export type { SQLitePersistenceConfig, } from './sqlite-persistence.js';
58
58
  export { QEUnifiedMemory, createQEUnifiedMemory, createDefaultQEUnifiedMemory, QE_MEMORY_DOMAINS, QE_DOMAIN_HNSW_CONFIGS, DEFAULT_QE_UNIFIED_MEMORY_CONFIG, } from './qe-unified-memory.js';
59
59
  export type { QEMemoryDomain, QEMemoryMetadata, TestSuiteMetadata, DefectMetadata, QualityMetricsMetadata, LearningPatternMetadata, CoordinationMetadata, QEMemorySearchResult, QEMemorySearchOptions, MigrationConfig, MigrationProgress, MigrationResult, MigrationSource, QEUnifiedMemoryConfig, QEUnifiedMemoryStats, QEMemoryDomainStats, IQEUnifiedMemory, } from './qe-unified-memory.js';
60
- export { V2ToV3Migrator, migrateV2ToV3, } from './v2-to-v3-migration.js';
61
- export type { V2MigrationConfig, V2MigrationProgress, V2MigrationResult, } from './v2-to-v3-migration.js';
62
60
  export { TokenMetricsCollector, TokenMetricsCollectorImpl, formatCostUsd, estimateTokens, } from './token-tracker.js';
63
61
  export type { TokenUsage, TaskTokenMetric, AgentTokenMetrics, SessionTokenSummary, TokenEfficiencyReport, Timeframe, TokenCostConfig, } from './token-tracker.js';
64
62
  export { ConceptGraph, createConceptGraph, DEFAULT_CONCEPT_GRAPH_CONFIG, } from './dream/index.js';
@@ -92,10 +92,6 @@ export { SQLitePatternStore, createSQLitePatternStore, DEFAULT_SQLITE_CONFIG, }
92
92
  // ============================================================================
93
93
  export { QEUnifiedMemory, createQEUnifiedMemory, createDefaultQEUnifiedMemory, QE_MEMORY_DOMAINS, QE_DOMAIN_HNSW_CONFIGS, DEFAULT_QE_UNIFIED_MEMORY_CONFIG, } from './qe-unified-memory.js';
94
94
  // ============================================================================
95
- // V2 to V3 Migration (ADR-038)
96
- // ============================================================================
97
- export { V2ToV3Migrator, migrateV2ToV3, } from './v2-to-v3-migration.js';
98
- // ============================================================================
99
95
  // Token Tracking (ADR-042)
100
96
  // ============================================================================
101
97
  export {
@@ -87,7 +87,7 @@ export class LearningMetricsTracker {
87
87
  const oneWeekAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString().split('T')[0];
88
88
  // Pattern metrics
89
89
  const patternStats = this.getPatternStats(today);
90
- // Experience metrics (from learning_experiences if exists, or qe_pattern_usage)
90
+ // Experience metrics (from captured_experiences or qe_pattern_usage)
91
91
  const experienceStats = this.getExperienceStats(today);
92
92
  // Q-value metrics
93
93
  const qValueStats = this.getQValueStats();
@@ -169,16 +169,17 @@ export class LearningMetricsTracker {
169
169
  if (!this.db) {
170
170
  return { total: 0, recordedToday: 0, avgReward: 0, successRate: 0 };
171
171
  }
172
- // Try learning_experiences table first (v2 compatible)
173
- const learningTableExists = this.db.prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name='learning_experiences'`).get();
174
- if (learningTableExists) {
172
+ // Use captured_experiences table
173
+ const capturedTableExists = this.db.prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name='captured_experiences'`).get();
174
+ if (capturedTableExists) {
175
175
  const stats = this.db.prepare(`
176
176
  SELECT
177
177
  COUNT(*) as total,
178
- SUM(CASE WHEN date(datetime(created_at, 'unixepoch')) = ? THEN 1 ELSE 0 END) as recorded_today,
179
- AVG(reward) as avg_reward,
180
- AVG(CASE WHEN reward >= 0.5 THEN 1.0 ELSE 0.0 END) as success_rate
181
- FROM learning_experiences
178
+ SUM(CASE WHEN date(started_at) = ? THEN 1 ELSE 0 END) as recorded_today,
179
+ AVG(quality) as avg_reward,
180
+ AVG(CASE WHEN success = 1 THEN 1.0 ELSE 0.0 END) as success_rate
181
+ FROM captured_experiences
182
+ WHERE agent != 'cli-hook'
182
183
  `).get(today);
183
184
  return {
184
185
  total: stats.total || 0,
@@ -252,13 +253,14 @@ export class LearningMetricsTracker {
252
253
  getHistoricalAvgReward(date) {
253
254
  if (!this.db)
254
255
  return 0;
255
- // Try learning_experiences first
256
- const tableExists = this.db.prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name='learning_experiences'`).get();
256
+ // Use captured_experiences
257
+ const tableExists = this.db.prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name='captured_experiences'`).get();
257
258
  if (tableExists) {
258
259
  const result = this.db.prepare(`
259
- SELECT AVG(reward) as avg_reward
260
- FROM learning_experiences
261
- WHERE datetime(created_at, 'unixepoch') <= datetime(?)
260
+ SELECT AVG(quality) as avg_reward
261
+ FROM captured_experiences
262
+ WHERE started_at <= datetime(?)
263
+ AND agent != 'cli-hook'
262
264
  `).get(date + ' 23:59:59');
263
265
  return result?.avg_reward || 0;
264
266
  }
@@ -126,7 +126,7 @@ export declare class PatternLifecycleManager {
126
126
  */
127
127
  private ensureSchema;
128
128
  /**
129
- * Get recent experiences from learning_experiences table
129
+ * Get recent experiences from captured_experiences table.
130
130
  */
131
131
  getRecentExperiences(options?: {
132
132
  minReward?: number;
@@ -99,40 +99,38 @@ export class PatternLifecycleManager {
99
99
  // Experience Extraction
100
100
  // ============================================================================
101
101
  /**
102
- * Get recent experiences from learning_experiences table
102
+ * Get recent experiences from captured_experiences table.
103
103
  */
104
104
  getRecentExperiences(options = {}) {
105
105
  const minReward = options.minReward ?? this.config.promotionRewardThreshold;
106
106
  const limit = options.limit ?? 100;
107
107
  const sinceDays = options.sinceDays ?? 7;
108
- const sinceTimestamp = Date.now() - (sinceDays * 24 * 60 * 60 * 1000);
109
- // Check if learning_experiences table exists
110
- const tableExists = this.db.prepare(`
111
- SELECT name FROM sqlite_master
112
- WHERE type='table' AND name='learning_experiences'
113
- `).get();
108
+ const tableExists = this.db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='captured_experiences'").get();
114
109
  if (!tableExists) {
115
- console.log('[PatternLifecycle] learning_experiences table not found');
110
+ logger.debug('captured_experiences table not found');
116
111
  return [];
117
112
  }
113
+ const sinceDate = new Date(Date.now() - sinceDays * 86400000)
114
+ .toISOString().replace('T', ' ').slice(0, 19);
118
115
  const aggregates = this.db.prepare(`
119
116
  SELECT
120
- task_type,
117
+ domain as task_type,
121
118
  COUNT(*) as count,
122
- AVG(reward) as avg_reward,
123
- MAX(reward) as max_reward,
124
- MIN(reward) as min_reward,
125
- SUM(CASE WHEN reward >= ? THEN 1 ELSE 0 END) as success_count,
126
- GROUP_CONCAT(DISTINCT action) as actions,
127
- MAX(created_at) as latest_at
128
- FROM learning_experiences
129
- WHERE created_at >= ? AND reward >= ?
130
- GROUP BY task_type
119
+ AVG(quality) as avg_reward,
120
+ MAX(quality) as max_reward,
121
+ MIN(quality) as min_reward,
122
+ SUM(CASE WHEN quality >= ? THEN 1 ELSE 0 END) as success_count,
123
+ GROUP_CONCAT(DISTINCT agent) as actions,
124
+ MAX(started_at) as latest_at
125
+ FROM captured_experiences
126
+ WHERE started_at >= ?
127
+ AND quality >= ?
128
+ AND agent != 'cli-hook'
129
+ GROUP BY domain
131
130
  HAVING COUNT(*) >= ?
132
131
  ORDER BY avg_reward DESC
133
132
  LIMIT ?
134
- `).all(minReward, sinceTimestamp, minReward * 0.5, // Include experiences above half threshold for context
135
- this.config.promotionMinOccurrences, limit);
133
+ `).all(minReward, sinceDate, minReward * 0.5, this.config.promotionMinOccurrences, limit);
136
134
  return aggregates.map(agg => ({
137
135
  taskType: agg.task_type,
138
136
  domain: this.taskTypeToQEDomain(agg.task_type),
@@ -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({
@@ -22,7 +22,6 @@
22
22
  import { LoggerFactory } from '../logging/index.js';
23
23
  const logger = LoggerFactory.create('qe-unified-memory');
24
24
  import { ok, err } from '../shared/types/index.js';
25
- import { migrateV2ToV3 } from './v2-to-v3-migration.js';
26
25
  import { EMBEDDING_CONFIG } from '../shared/embeddings/types.js';
27
26
  import { toErrorMessage } from '../shared/error-utils.js';
28
27
  import { HNSWIndex, } from '../domains/coverage-analysis/services/hnsw-index.js';
@@ -508,33 +507,7 @@ export class QEUnifiedMemory {
508
507
  // Private Migration Helpers
509
508
  // -------------------------------------------------------------------------
510
509
  async migrateFromSQLite(config) {
511
- // Check if this is a V2 to V3 migration (patterns table)
512
- const sourcePath = config.sourceConfig?.path || '.agentic-qe/memory.db';
513
- // For V2 to V3 migration, use the dedicated migrator
514
- if (config.domain === 'learning' || config.migrateAll) {
515
- logger.info('Starting V2 to V3 migration', { sourcePath });
516
- const result = await migrateV2ToV3(sourcePath, '.agentic-qe/memory.db', (progress) => {
517
- logger.info('Migration progress', {
518
- stage: progress.stage,
519
- message: progress.message,
520
- table: progress.table,
521
- current: progress.current,
522
- total: progress.total,
523
- });
524
- });
525
- if (result.success) {
526
- logger.info('V2 migration completed successfully', {
527
- tablesMigrated: result.tablesMigrated,
528
- totalRecords: Object.values(result.counts).reduce((a, b) => a + b, 0),
529
- durationSeconds: Number((result.duration / 1000).toFixed(2)),
530
- });
531
- }
532
- else {
533
- logger.error('V2 migration failed', undefined, { errors: result.errors });
534
- }
535
- return Object.values(result.counts).reduce((a, b) => a + b, 0);
536
- }
537
- // Generic SQLite migration for other domains
510
+ // Generic SQLite migration
538
511
  logger.warn('Generic SQLite migration not yet implemented', { domain: config.domain });
539
512
  return 0;
540
513
  }
@@ -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
  // ============================================================================