@cloudstreamsoftware/claude-tools 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +152 -37
- package/agents/INDEX.md +183 -0
- package/agents/architect.md +247 -0
- package/agents/build-error-resolver.md +555 -0
- package/agents/catalyst-deployer.md +132 -0
- package/agents/code-reviewer.md +121 -0
- package/agents/compliance-auditor.md +148 -0
- package/agents/creator-architect.md +395 -0
- package/agents/deluge-reviewer.md +98 -0
- package/agents/doc-updater.md +471 -0
- package/agents/e2e-runner.md +711 -0
- package/agents/planner.md +122 -0
- package/agents/refactor-cleaner.md +309 -0
- package/agents/security-reviewer.md +582 -0
- package/agents/tdd-guide.md +302 -0
- package/config/versions.json +63 -0
- package/dist/hooks/hooks.json +209 -0
- package/dist/index.js +47 -0
- package/dist/lib/asset-value.js +609 -0
- package/dist/lib/client-manager.js +300 -0
- package/dist/lib/command-matcher.js +242 -0
- package/dist/lib/cross-session-patterns.js +754 -0
- package/dist/lib/intent-classifier.js +1075 -0
- package/dist/lib/package-manager.js +374 -0
- package/dist/lib/recommendation-engine.js +597 -0
- package/dist/lib/session-memory.js +489 -0
- package/dist/lib/skill-effectiveness.js +486 -0
- package/dist/lib/skill-matcher.js +595 -0
- package/dist/lib/tutorial-metrics.js +242 -0
- package/dist/lib/tutorial-progress.js +209 -0
- package/dist/lib/tutorial-renderer.js +431 -0
- package/dist/lib/utils.js +380 -0
- package/dist/lib/verify-formatter.js +143 -0
- package/dist/lib/workflow-state.js +249 -0
- package/hooks/hooks.json +209 -0
- package/package.json +5 -1
- package/scripts/aggregate-sessions.js +290 -0
- package/scripts/branch-name-validator.js +291 -0
- package/scripts/build.js +101 -0
- package/scripts/commands/client-switch.js +231 -0
- package/scripts/deprecate-skill.js +610 -0
- package/scripts/diagnose.js +324 -0
- package/scripts/doc-freshness.js +168 -0
- package/scripts/generate-weekly-digest.js +393 -0
- package/scripts/health-check.js +270 -0
- package/scripts/hooks/credential-check.js +101 -0
- package/scripts/hooks/evaluate-session.js +81 -0
- package/scripts/hooks/pre-compact.js +66 -0
- package/scripts/hooks/prompt-analyzer.js +276 -0
- package/scripts/hooks/prompt-router.js +422 -0
- package/scripts/hooks/quality-gate-enforcer.js +371 -0
- package/scripts/hooks/session-end.js +156 -0
- package/scripts/hooks/session-start.js +195 -0
- package/scripts/hooks/skill-injector.js +333 -0
- package/scripts/hooks/suggest-compact.js +58 -0
- package/scripts/lib/asset-value.js +609 -0
- package/scripts/lib/client-manager.js +300 -0
- package/scripts/lib/command-matcher.js +242 -0
- package/scripts/lib/cross-session-patterns.js +754 -0
- package/scripts/lib/intent-classifier.js +1075 -0
- package/scripts/lib/package-manager.js +374 -0
- package/scripts/lib/recommendation-engine.js +597 -0
- package/scripts/lib/session-memory.js +489 -0
- package/scripts/lib/skill-effectiveness.js +486 -0
- package/scripts/lib/skill-matcher.js +595 -0
- package/scripts/lib/tutorial-metrics.js +242 -0
- package/scripts/lib/tutorial-progress.js +209 -0
- package/scripts/lib/tutorial-renderer.js +431 -0
- package/scripts/lib/utils.js +380 -0
- package/scripts/lib/verify-formatter.js +143 -0
- package/scripts/lib/workflow-state.js +249 -0
- package/scripts/onboard.js +363 -0
- package/scripts/quarterly-report.js +692 -0
- package/scripts/setup-package-manager.js +204 -0
- package/scripts/sync-upstream.js +391 -0
- package/scripts/test.js +108 -0
- package/scripts/tutorial-runner.js +351 -0
- package/scripts/validate-all.js +201 -0
- package/scripts/verifiers/agents.js +245 -0
- package/scripts/verifiers/config.js +186 -0
- package/scripts/verifiers/environment.js +123 -0
- package/scripts/verifiers/hooks.js +188 -0
- package/scripts/verifiers/index.js +38 -0
- package/scripts/verifiers/persistence.js +140 -0
- package/scripts/verifiers/plugin.js +215 -0
- package/scripts/verifiers/skills.js +209 -0
- package/scripts/verify-setup.js +164 -0
- package/skills/INDEX.md +157 -0
- package/skills/backend-patterns/SKILL.md +586 -0
- package/skills/backend-patterns/catalyst-patterns.md +128 -0
- package/skills/bigquery-patterns/SKILL.md +27 -0
- package/skills/bigquery-patterns/performance-optimization.md +518 -0
- package/skills/bigquery-patterns/query-patterns.md +372 -0
- package/skills/bigquery-patterns/schema-design.md +78 -0
- package/skills/cloudstream-project-template/SKILL.md +20 -0
- package/skills/cloudstream-project-template/structure.md +65 -0
- package/skills/coding-standards/SKILL.md +524 -0
- package/skills/coding-standards/deluge-standards.md +83 -0
- package/skills/compliance-patterns/SKILL.md +28 -0
- package/skills/compliance-patterns/hipaa/audit-requirements.md +251 -0
- package/skills/compliance-patterns/hipaa/baa-process.md +298 -0
- package/skills/compliance-patterns/hipaa/data-archival-strategy.md +387 -0
- package/skills/compliance-patterns/hipaa/phi-handling.md +52 -0
- package/skills/compliance-patterns/pci-dss/saq-a-requirements.md +307 -0
- package/skills/compliance-patterns/pci-dss/tokenization-patterns.md +382 -0
- package/skills/compliance-patterns/pci-dss/zoho-checkout-patterns.md +56 -0
- package/skills/compliance-patterns/soc2/access-controls.md +344 -0
- package/skills/compliance-patterns/soc2/audit-logging.md +458 -0
- package/skills/compliance-patterns/soc2/change-management.md +403 -0
- package/skills/compliance-patterns/soc2/deluge-execution-logging.md +407 -0
- package/skills/consultancy-workflows/SKILL.md +19 -0
- package/skills/consultancy-workflows/client-isolation.md +21 -0
- package/skills/consultancy-workflows/documentation-automation.md +454 -0
- package/skills/consultancy-workflows/handoff-procedures.md +257 -0
- package/skills/consultancy-workflows/knowledge-capture.md +513 -0
- package/skills/consultancy-workflows/time-tracking.md +26 -0
- package/skills/continuous-learning/SKILL.md +84 -0
- package/skills/continuous-learning/config.json +18 -0
- package/skills/continuous-learning/evaluate-session.sh +60 -0
- package/skills/continuous-learning-v2/SKILL.md +126 -0
- package/skills/continuous-learning-v2/config.json +61 -0
- package/skills/frontend-patterns/SKILL.md +635 -0
- package/skills/frontend-patterns/zoho-widget-patterns.md +103 -0
- package/skills/gcp-data-engineering/SKILL.md +36 -0
- package/skills/gcp-data-engineering/bigquery/performance-optimization.md +337 -0
- package/skills/gcp-data-engineering/dataflow/error-handling.md +496 -0
- package/skills/gcp-data-engineering/dataflow/pipeline-patterns.md +444 -0
- package/skills/gcp-data-engineering/dbt/model-organization.md +63 -0
- package/skills/gcp-data-engineering/dbt/testing-patterns.md +503 -0
- package/skills/gcp-data-engineering/medallion-architecture/bronze-layer.md +60 -0
- package/skills/gcp-data-engineering/medallion-architecture/gold-layer.md +311 -0
- package/skills/gcp-data-engineering/medallion-architecture/layer-transitions.md +517 -0
- package/skills/gcp-data-engineering/medallion-architecture/silver-layer.md +305 -0
- package/skills/gcp-data-engineering/zoho-to-gcp/data-extraction.md +543 -0
- package/skills/gcp-data-engineering/zoho-to-gcp/real-time-vs-batch.md +337 -0
- package/skills/security-review/SKILL.md +498 -0
- package/skills/security-review/compliance-checklist.md +53 -0
- package/skills/strategic-compact/SKILL.md +67 -0
- package/skills/tdd-workflow/SKILL.md +413 -0
- package/skills/tdd-workflow/zoho-testing.md +124 -0
- package/skills/tutorial/SKILL.md +249 -0
- package/skills/tutorial/docs/ACCESSIBILITY.md +169 -0
- package/skills/tutorial/lessons/00-philosophy-and-workflow.md +198 -0
- package/skills/tutorial/lessons/01-basics.md +81 -0
- package/skills/tutorial/lessons/02-training.md +86 -0
- package/skills/tutorial/lessons/03-commands.md +109 -0
- package/skills/tutorial/lessons/04-workflows.md +115 -0
- package/skills/tutorial/lessons/05-compliance.md +116 -0
- package/skills/tutorial/lessons/06-zoho.md +121 -0
- package/skills/tutorial/lessons/07-hooks-system.md +277 -0
- package/skills/tutorial/lessons/08-mcp-servers.md +316 -0
- package/skills/tutorial/lessons/09-client-management.md +215 -0
- package/skills/tutorial/lessons/10-testing-e2e.md +260 -0
- package/skills/tutorial/lessons/11-skills-deep-dive.md +272 -0
- package/skills/tutorial/lessons/12-rules-system.md +326 -0
- package/skills/tutorial/lessons/13-golden-standard-graduation.md +213 -0
- package/skills/tutorial/lessons/14-fork-setup-and-sync.md +312 -0
- package/skills/tutorial/lessons/15-living-examples-system.md +221 -0
- package/skills/tutorial/tracks/accelerated/README.md +134 -0
- package/skills/tutorial/tracks/accelerated/assessment/checkpoint-1.md +161 -0
- package/skills/tutorial/tracks/accelerated/assessment/checkpoint-2.md +175 -0
- package/skills/tutorial/tracks/accelerated/day-1-core-concepts.md +234 -0
- package/skills/tutorial/tracks/accelerated/day-2-essential-commands.md +270 -0
- package/skills/tutorial/tracks/accelerated/day-3-workflow-mastery.md +305 -0
- package/skills/tutorial/tracks/accelerated/day-4-compliance-zoho.md +304 -0
- package/skills/tutorial/tracks/accelerated/day-5-hooks-skills.md +344 -0
- package/skills/tutorial/tracks/accelerated/day-6-client-testing.md +386 -0
- package/skills/tutorial/tracks/accelerated/day-7-graduation.md +369 -0
- package/skills/zoho-patterns/CHANGELOG.md +108 -0
- package/skills/zoho-patterns/SKILL.md +446 -0
- package/skills/zoho-patterns/analytics/dashboard-patterns.md +352 -0
- package/skills/zoho-patterns/analytics/zoho-to-bigquery-pipeline.md +427 -0
- package/skills/zoho-patterns/catalyst/appsail-deployment.md +349 -0
- package/skills/zoho-patterns/catalyst/context-close-patterns.md +354 -0
- package/skills/zoho-patterns/catalyst/cron-batch-processing.md +374 -0
- package/skills/zoho-patterns/catalyst/function-patterns.md +439 -0
- package/skills/zoho-patterns/creator/form-design.md +304 -0
- package/skills/zoho-patterns/creator/publish-api-patterns.md +313 -0
- package/skills/zoho-patterns/creator/widget-integration.md +306 -0
- package/skills/zoho-patterns/creator/workflow-automation.md +253 -0
- package/skills/zoho-patterns/deluge/api-patterns.md +468 -0
- package/skills/zoho-patterns/deluge/batch-processing.md +403 -0
- package/skills/zoho-patterns/deluge/cross-app-integration.md +356 -0
- package/skills/zoho-patterns/deluge/error-handling.md +423 -0
- package/skills/zoho-patterns/deluge/syntax-reference.md +65 -0
- package/skills/zoho-patterns/integration/cors-proxy-architecture.md +426 -0
- package/skills/zoho-patterns/integration/crm-books-native-sync.md +277 -0
- package/skills/zoho-patterns/integration/oauth-token-management.md +461 -0
- package/skills/zoho-patterns/integration/zoho-flow-patterns.md +334 -0
|
@@ -0,0 +1,754 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-Session Pattern Detection Engine
|
|
3
|
+
*
|
|
4
|
+
* Analyzes archived sessions to discover high-confidence patterns
|
|
5
|
+
* appearing across multiple sessions. This is the core of the
|
|
6
|
+
* cross-session learning and aggregation system.
|
|
7
|
+
*
|
|
8
|
+
* Key capabilities:
|
|
9
|
+
* 1. Load and parse all archived sessions
|
|
10
|
+
* 2. Detect patterns appearing in 3+ sessions
|
|
11
|
+
* 3. Analyze patterns by technology/compliance context
|
|
12
|
+
* 4. Time-series trend analysis
|
|
13
|
+
* 5. Build skill-correction correlation matrix
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const fs = require('fs');
|
|
17
|
+
const path = require('path');
|
|
18
|
+
const {
|
|
19
|
+
getClaudeDir,
|
|
20
|
+
ensureDir,
|
|
21
|
+
readFile,
|
|
22
|
+
writeFile,
|
|
23
|
+
getDateTimeString,
|
|
24
|
+
getDateString,
|
|
25
|
+
log,
|
|
26
|
+
} = require('./utils');
|
|
27
|
+
|
|
28
|
+
// Paths
|
|
29
|
+
const KNOWLEDGE_DIR = path.join(getClaudeDir(), 'knowledge');
|
|
30
|
+
const SESSIONS_DIR = path.join(KNOWLEDGE_DIR, 'sessions');
|
|
31
|
+
const AGGREGATED_DIR = path.join(KNOWLEDGE_DIR, 'aggregated');
|
|
32
|
+
|
|
33
|
+
// Thresholds
|
|
34
|
+
const THRESHOLDS = {
|
|
35
|
+
MIN_SESSIONS_FOR_PATTERN: 3, // Minimum sessions to consider a pattern
|
|
36
|
+
MIN_SESSIONS_FOR_ANALYSIS: 5, // Minimum sessions before running analysis
|
|
37
|
+
HIGH_CONFIDENCE: 0.7, // Above this = high confidence pattern
|
|
38
|
+
EMERGING_THRESHOLD: 2, // Pattern appearing in recent sessions
|
|
39
|
+
DECLINING_DAYS: 30, // No occurrences in this many days = declining
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// Category weights for confidence scoring
|
|
43
|
+
const CATEGORY_WEIGHTS = {
|
|
44
|
+
approach: 1.0, // Most important - affects overall methodology
|
|
45
|
+
tool_usage: 0.8, // Important - efficiency impact
|
|
46
|
+
code_style: 0.5, // Less critical but still relevant
|
|
47
|
+
communication: 0.3, // Lowest weight
|
|
48
|
+
general: 0.6,
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Load all archived sessions from knowledge/sessions/
|
|
53
|
+
* @returns {Array} Array of session objects with parsed data
|
|
54
|
+
*/
|
|
55
|
+
function loadArchivedSessions() {
|
|
56
|
+
ensureDir(SESSIONS_DIR);
|
|
57
|
+
|
|
58
|
+
const sessions = [];
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
const files = fs.readdirSync(SESSIONS_DIR);
|
|
62
|
+
|
|
63
|
+
for (const file of files) {
|
|
64
|
+
if (!file.endsWith('.json')) continue;
|
|
65
|
+
|
|
66
|
+
const filePath = path.join(SESSIONS_DIR, file);
|
|
67
|
+
const content = readFile(filePath);
|
|
68
|
+
|
|
69
|
+
if (!content) continue;
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
const session = JSON.parse(content);
|
|
73
|
+
session._filePath = filePath;
|
|
74
|
+
session._fileName = file;
|
|
75
|
+
sessions.push(session);
|
|
76
|
+
} catch (err) {
|
|
77
|
+
log(`[CrossSessionPatterns] Error parsing ${file}: ${err.message}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
} catch (err) {
|
|
81
|
+
log(`[CrossSessionPatterns] Error loading sessions: ${err.message}`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Sort by start time (oldest first)
|
|
85
|
+
sessions.sort((a, b) => {
|
|
86
|
+
const dateA = new Date(a.startedAt?.replace(' ', 'T') || 0);
|
|
87
|
+
const dateB = new Date(b.startedAt?.replace(' ', 'T') || 0);
|
|
88
|
+
return dateA - dateB;
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
return sessions;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Extract all corrections from sessions
|
|
96
|
+
* @param {Array} sessions - Array of session objects
|
|
97
|
+
* @returns {Array} Flattened array of corrections with session metadata
|
|
98
|
+
*/
|
|
99
|
+
function extractAllCorrections(sessions) {
|
|
100
|
+
const corrections = [];
|
|
101
|
+
|
|
102
|
+
for (const session of sessions) {
|
|
103
|
+
if (!session.corrections || !Array.isArray(session.corrections)) continue;
|
|
104
|
+
|
|
105
|
+
for (const correction of session.corrections) {
|
|
106
|
+
corrections.push({
|
|
107
|
+
...correction,
|
|
108
|
+
sessionId: session.sessionId,
|
|
109
|
+
sessionDate: session.startedAt,
|
|
110
|
+
technologies: session.context?.technologies || [],
|
|
111
|
+
complianceMode: session.context?.complianceMode || 'standard',
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return corrections;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Analyze all sessions and extract comprehensive data
|
|
121
|
+
* @returns {object} { sessions, corrections, patterns, contexts, summary }
|
|
122
|
+
*/
|
|
123
|
+
function analyzeAllSessions() {
|
|
124
|
+
const sessions = loadArchivedSessions();
|
|
125
|
+
|
|
126
|
+
if (sessions.length < THRESHOLDS.MIN_SESSIONS_FOR_ANALYSIS) {
|
|
127
|
+
return {
|
|
128
|
+
sessions: [],
|
|
129
|
+
corrections: [],
|
|
130
|
+
patterns: [],
|
|
131
|
+
contexts: { technologies: {}, complianceModes: {} },
|
|
132
|
+
summary: { sessionCount: sessions.length, insufficient: true },
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const corrections = extractAllCorrections(sessions);
|
|
137
|
+
|
|
138
|
+
// Extract effective patterns
|
|
139
|
+
const patterns = [];
|
|
140
|
+
for (const session of sessions) {
|
|
141
|
+
if (session.effectivePatterns) {
|
|
142
|
+
for (const pattern of session.effectivePatterns) {
|
|
143
|
+
patterns.push({
|
|
144
|
+
...pattern,
|
|
145
|
+
sessionId: session.sessionId,
|
|
146
|
+
sessionDate: session.startedAt,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Build context summary
|
|
153
|
+
const contexts = {
|
|
154
|
+
technologies: {},
|
|
155
|
+
complianceModes: {},
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
for (const session of sessions) {
|
|
159
|
+
const techs = session.context?.technologies || [];
|
|
160
|
+
for (const tech of techs) {
|
|
161
|
+
contexts.technologies[tech] = (contexts.technologies[tech] || 0) + 1;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const mode = session.context?.complianceMode || 'standard';
|
|
165
|
+
contexts.complianceModes[mode] = (contexts.complianceModes[mode] || 0) + 1;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return {
|
|
169
|
+
sessions,
|
|
170
|
+
corrections,
|
|
171
|
+
patterns,
|
|
172
|
+
contexts,
|
|
173
|
+
summary: {
|
|
174
|
+
sessionCount: sessions.length,
|
|
175
|
+
correctionCount: corrections.length,
|
|
176
|
+
patternCount: patterns.length,
|
|
177
|
+
dateRange: {
|
|
178
|
+
first: sessions[0]?.startedAt,
|
|
179
|
+
last: sessions[sessions.length - 1]?.startedAt,
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Detect patterns appearing across multiple sessions
|
|
187
|
+
* @param {number} threshold - Minimum sessions for a pattern (default: 3)
|
|
188
|
+
* @returns {object} { highConfidence, emerging, declining, all }
|
|
189
|
+
*/
|
|
190
|
+
function detectCrossSessionPatterns(threshold = THRESHOLDS.MIN_SESSIONS_FOR_PATTERN) {
|
|
191
|
+
const { sessions, corrections } = analyzeAllSessions();
|
|
192
|
+
|
|
193
|
+
if (sessions.length < THRESHOLDS.MIN_SESSIONS_FOR_ANALYSIS) {
|
|
194
|
+
return { highConfidence: [], emerging: [], declining: [], all: [] };
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Group corrections by signature (category + original behavior)
|
|
198
|
+
const patternMap = new Map();
|
|
199
|
+
|
|
200
|
+
for (const correction of corrections) {
|
|
201
|
+
const signature = `${correction.category}::${correction.original}`;
|
|
202
|
+
|
|
203
|
+
if (!patternMap.has(signature)) {
|
|
204
|
+
patternMap.set(signature, {
|
|
205
|
+
signature,
|
|
206
|
+
category: correction.category,
|
|
207
|
+
original: correction.original,
|
|
208
|
+
corrected: correction.corrected,
|
|
209
|
+
sessions: new Set(),
|
|
210
|
+
totalCount: 0,
|
|
211
|
+
occurrences: [],
|
|
212
|
+
technologies: new Set(),
|
|
213
|
+
complianceModes: new Set(),
|
|
214
|
+
firstSeen: correction.sessionDate,
|
|
215
|
+
lastSeen: correction.sessionDate,
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const pattern = patternMap.get(signature);
|
|
220
|
+
pattern.sessions.add(correction.sessionId);
|
|
221
|
+
pattern.totalCount += correction.count || 1;
|
|
222
|
+
pattern.occurrences.push({
|
|
223
|
+
sessionId: correction.sessionId,
|
|
224
|
+
date: correction.sessionDate,
|
|
225
|
+
count: correction.count || 1,
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
// Track contexts
|
|
229
|
+
for (const tech of correction.technologies) {
|
|
230
|
+
pattern.technologies.add(tech);
|
|
231
|
+
}
|
|
232
|
+
pattern.complianceModes.add(correction.complianceMode);
|
|
233
|
+
|
|
234
|
+
// Update date range
|
|
235
|
+
if (correction.sessionDate > pattern.lastSeen) {
|
|
236
|
+
pattern.lastSeen = correction.sessionDate;
|
|
237
|
+
}
|
|
238
|
+
if (correction.sessionDate < pattern.firstSeen) {
|
|
239
|
+
pattern.firstSeen = correction.sessionDate;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Convert to array and filter by threshold
|
|
244
|
+
const allPatterns = Array.from(patternMap.values()).map((p) => ({
|
|
245
|
+
...p,
|
|
246
|
+
sessionCount: p.sessions.size,
|
|
247
|
+
sessions: Array.from(p.sessions),
|
|
248
|
+
technologies: Array.from(p.technologies),
|
|
249
|
+
complianceModes: Array.from(p.complianceModes),
|
|
250
|
+
confidence: calculateConfidence(p, sessions.length),
|
|
251
|
+
}));
|
|
252
|
+
|
|
253
|
+
// Filter by session threshold
|
|
254
|
+
const significantPatterns = allPatterns.filter((p) => p.sessionCount >= threshold);
|
|
255
|
+
|
|
256
|
+
// Sort by session count (most frequent first)
|
|
257
|
+
significantPatterns.sort((a, b) => b.sessionCount - a.sessionCount);
|
|
258
|
+
|
|
259
|
+
// Categorize patterns
|
|
260
|
+
const now = new Date();
|
|
261
|
+
const thirtyDaysAgo = new Date(now - THRESHOLDS.DECLINING_DAYS * 24 * 60 * 60 * 1000);
|
|
262
|
+
|
|
263
|
+
const highConfidence = significantPatterns.filter(
|
|
264
|
+
(p) => p.confidence >= THRESHOLDS.HIGH_CONFIDENCE
|
|
265
|
+
);
|
|
266
|
+
|
|
267
|
+
const emerging = allPatterns.filter((p) => {
|
|
268
|
+
// Appeared in recent sessions but not yet at threshold
|
|
269
|
+
const lastSeenDate = new Date(p.lastSeen?.replace(' ', 'T') || 0);
|
|
270
|
+
return (
|
|
271
|
+
p.sessionCount >= THRESHOLDS.EMERGING_THRESHOLD &&
|
|
272
|
+
p.sessionCount < threshold &&
|
|
273
|
+
lastSeenDate > thirtyDaysAgo
|
|
274
|
+
);
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
const declining = significantPatterns.filter((p) => {
|
|
278
|
+
// Was significant but no recent occurrences
|
|
279
|
+
const lastSeenDate = new Date(p.lastSeen?.replace(' ', 'T') || 0);
|
|
280
|
+
return lastSeenDate < thirtyDaysAgo;
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
return {
|
|
284
|
+
highConfidence,
|
|
285
|
+
emerging,
|
|
286
|
+
declining,
|
|
287
|
+
all: significantPatterns,
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Calculate confidence score for a pattern
|
|
293
|
+
* @param {object} pattern - Pattern object
|
|
294
|
+
* @param {number} totalSessions - Total number of sessions
|
|
295
|
+
* @returns {number} Confidence score between 0 and 1
|
|
296
|
+
*/
|
|
297
|
+
function calculateConfidence(pattern, totalSessions) {
|
|
298
|
+
// Frequency component (how many sessions contain this pattern)
|
|
299
|
+
const frequencyScore = Math.min(pattern.sessions.size / totalSessions, 1);
|
|
300
|
+
|
|
301
|
+
// Recency component (how recent was the last occurrence)
|
|
302
|
+
const now = new Date();
|
|
303
|
+
const lastSeen = new Date(pattern.lastSeen?.replace(' ', 'T') || 0);
|
|
304
|
+
const daysSinceLastSeen = (now - lastSeen) / (1000 * 60 * 60 * 24);
|
|
305
|
+
const recencyScore = Math.max(0, 1 - daysSinceLastSeen / 90); // Decay over 90 days
|
|
306
|
+
|
|
307
|
+
// Category weight
|
|
308
|
+
const categoryWeight = CATEGORY_WEIGHTS[pattern.category] || 0.5;
|
|
309
|
+
|
|
310
|
+
// Count intensity (average occurrences per session)
|
|
311
|
+
const avgCount = pattern.totalCount / pattern.sessions.size;
|
|
312
|
+
const intensityScore = Math.min(avgCount / 3, 1); // Cap at 3 per session
|
|
313
|
+
|
|
314
|
+
// Weighted combination
|
|
315
|
+
const confidence =
|
|
316
|
+
frequencyScore * 0.35 + recencyScore * 0.25 + categoryWeight * 0.25 + intensityScore * 0.15;
|
|
317
|
+
|
|
318
|
+
return Math.round(confidence * 100) / 100;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Analyze patterns grouped by technology
|
|
323
|
+
* @returns {object} { [technology]: { corrections, topIssues, rate } }
|
|
324
|
+
*/
|
|
325
|
+
function analyzeByTechnology() {
|
|
326
|
+
const { sessions, corrections } = analyzeAllSessions();
|
|
327
|
+
|
|
328
|
+
if (sessions.length < THRESHOLDS.MIN_SESSIONS_FOR_ANALYSIS) {
|
|
329
|
+
return {};
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
const techMap = {};
|
|
333
|
+
|
|
334
|
+
for (const correction of corrections) {
|
|
335
|
+
for (const tech of correction.technologies) {
|
|
336
|
+
if (!techMap[tech]) {
|
|
337
|
+
techMap[tech] = {
|
|
338
|
+
technology: tech,
|
|
339
|
+
corrections: [],
|
|
340
|
+
sessionCount: 0,
|
|
341
|
+
sessions: new Set(),
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
techMap[tech].corrections.push(correction);
|
|
346
|
+
techMap[tech].sessions.add(correction.sessionId);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// Process each technology
|
|
351
|
+
const result = {};
|
|
352
|
+
|
|
353
|
+
for (const [tech, data] of Object.entries(techMap)) {
|
|
354
|
+
// Group corrections by type
|
|
355
|
+
const issueMap = {};
|
|
356
|
+
for (const c of data.corrections) {
|
|
357
|
+
const key = `${c.category}::${c.original}`;
|
|
358
|
+
if (!issueMap[key]) {
|
|
359
|
+
issueMap[key] = { category: c.category, original: c.original, count: 0 };
|
|
360
|
+
}
|
|
361
|
+
issueMap[key].count += c.count || 1;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
const issues = Object.values(issueMap).sort((a, b) => b.count - a.count);
|
|
365
|
+
|
|
366
|
+
result[tech] = {
|
|
367
|
+
technology: tech,
|
|
368
|
+
sessionCount: data.sessions.size,
|
|
369
|
+
correctionCount: data.corrections.length,
|
|
370
|
+
topIssues: issues.slice(0, 5),
|
|
371
|
+
correctionRate: data.corrections.length / data.sessions.size,
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
return result;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Analyze patterns by compliance mode
|
|
380
|
+
* @returns {object} { [mode]: { corrections, criticalPatterns } }
|
|
381
|
+
*/
|
|
382
|
+
function analyzeByComplianceMode() {
|
|
383
|
+
const { sessions, corrections } = analyzeAllSessions();
|
|
384
|
+
|
|
385
|
+
if (sessions.length < THRESHOLDS.MIN_SESSIONS_FOR_ANALYSIS) {
|
|
386
|
+
return {};
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
const modeMap = {};
|
|
390
|
+
|
|
391
|
+
for (const correction of corrections) {
|
|
392
|
+
const mode = correction.complianceMode || 'standard';
|
|
393
|
+
|
|
394
|
+
if (!modeMap[mode]) {
|
|
395
|
+
modeMap[mode] = {
|
|
396
|
+
mode,
|
|
397
|
+
corrections: [],
|
|
398
|
+
sessions: new Set(),
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
modeMap[mode].corrections.push(correction);
|
|
403
|
+
modeMap[mode].sessions.add(correction.sessionId);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// Process each mode
|
|
407
|
+
const result = {};
|
|
408
|
+
|
|
409
|
+
for (const [mode, data] of Object.entries(modeMap)) {
|
|
410
|
+
// Group corrections by type
|
|
411
|
+
const issueMap = {};
|
|
412
|
+
for (const c of data.corrections) {
|
|
413
|
+
const key = `${c.category}::${c.original}`;
|
|
414
|
+
if (!issueMap[key]) {
|
|
415
|
+
issueMap[key] = { category: c.category, original: c.original, count: 0 };
|
|
416
|
+
}
|
|
417
|
+
issueMap[key].count += c.count || 1;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
const issues = Object.values(issueMap).sort((a, b) => b.count - a.count);
|
|
421
|
+
|
|
422
|
+
// Critical patterns for compliance modes
|
|
423
|
+
const criticalPatterns = issues.filter(
|
|
424
|
+
(i) => i.category === 'approach' || (mode !== 'standard' && i.count >= 3)
|
|
425
|
+
);
|
|
426
|
+
|
|
427
|
+
result[mode] = {
|
|
428
|
+
mode,
|
|
429
|
+
sessionCount: data.sessions.size,
|
|
430
|
+
correctionCount: data.corrections.length,
|
|
431
|
+
topIssues: issues.slice(0, 5),
|
|
432
|
+
criticalPatterns: criticalPatterns.slice(0, 3),
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
return result;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Time-series trend analysis
|
|
441
|
+
* @param {number} windowDays - Analysis window in days (default: 30)
|
|
442
|
+
* @returns {object} { improving, worsening, stable, new }
|
|
443
|
+
*/
|
|
444
|
+
function analyzeTrends(windowDays = 30) {
|
|
445
|
+
const { sessions, corrections } = analyzeAllSessions();
|
|
446
|
+
|
|
447
|
+
if (sessions.length < THRESHOLDS.MIN_SESSIONS_FOR_ANALYSIS) {
|
|
448
|
+
return { improving: [], worsening: [], stable: [], new: [] };
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
const now = new Date();
|
|
452
|
+
const windowStart = new Date(now - windowDays * 24 * 60 * 60 * 1000);
|
|
453
|
+
const halfWindow = new Date(now - (windowDays / 2) * 24 * 60 * 60 * 1000);
|
|
454
|
+
|
|
455
|
+
// Group sessions by period (first half vs second half of window)
|
|
456
|
+
const firstHalf = { sessions: [], corrections: [] };
|
|
457
|
+
const secondHalf = { sessions: [], corrections: [] };
|
|
458
|
+
|
|
459
|
+
for (const session of sessions) {
|
|
460
|
+
const sessionDate = new Date(session.startedAt?.replace(' ', 'T') || 0);
|
|
461
|
+
|
|
462
|
+
if (sessionDate < windowStart) continue;
|
|
463
|
+
|
|
464
|
+
if (sessionDate < halfWindow) {
|
|
465
|
+
firstHalf.sessions.push(session);
|
|
466
|
+
} else {
|
|
467
|
+
secondHalf.sessions.push(session);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// Get corrections for each period
|
|
472
|
+
for (const correction of corrections) {
|
|
473
|
+
const correctionDate = new Date(correction.sessionDate?.replace(' ', 'T') || 0);
|
|
474
|
+
|
|
475
|
+
if (correctionDate < windowStart) continue;
|
|
476
|
+
|
|
477
|
+
if (correctionDate < halfWindow) {
|
|
478
|
+
firstHalf.corrections.push(correction);
|
|
479
|
+
} else {
|
|
480
|
+
secondHalf.corrections.push(correction);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// Count patterns in each period
|
|
485
|
+
function countPatterns(correctionList) {
|
|
486
|
+
const counts = {};
|
|
487
|
+
for (const c of correctionList) {
|
|
488
|
+
const key = `${c.category}::${c.original}`;
|
|
489
|
+
counts[key] = (counts[key] || 0) + (c.count || 1);
|
|
490
|
+
}
|
|
491
|
+
return counts;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
const firstCounts = countPatterns(firstHalf.corrections);
|
|
495
|
+
const secondCounts = countPatterns(secondHalf.corrections);
|
|
496
|
+
|
|
497
|
+
// Analyze trends
|
|
498
|
+
const allPatterns = new Set([...Object.keys(firstCounts), ...Object.keys(secondCounts)]);
|
|
499
|
+
|
|
500
|
+
const trends = {
|
|
501
|
+
improving: [],
|
|
502
|
+
worsening: [],
|
|
503
|
+
stable: [],
|
|
504
|
+
new: [],
|
|
505
|
+
};
|
|
506
|
+
|
|
507
|
+
for (const pattern of allPatterns) {
|
|
508
|
+
const first = firstCounts[pattern] || 0;
|
|
509
|
+
const second = secondCounts[pattern] || 0;
|
|
510
|
+
const [category, original] = pattern.split('::');
|
|
511
|
+
|
|
512
|
+
const change = second - first;
|
|
513
|
+
const percentChange = first > 0 ? ((second - first) / first) * 100 : second > 0 ? 100 : 0;
|
|
514
|
+
|
|
515
|
+
const trendData = {
|
|
516
|
+
pattern,
|
|
517
|
+
category,
|
|
518
|
+
original,
|
|
519
|
+
firstPeriod: first,
|
|
520
|
+
secondPeriod: second,
|
|
521
|
+
change,
|
|
522
|
+
percentChange: Math.round(percentChange),
|
|
523
|
+
};
|
|
524
|
+
|
|
525
|
+
if (first === 0 && second > 0) {
|
|
526
|
+
trends.new.push(trendData);
|
|
527
|
+
} else if (change < -1 || percentChange < -25) {
|
|
528
|
+
trends.improving.push(trendData);
|
|
529
|
+
} else if (change > 1 || percentChange > 25) {
|
|
530
|
+
trends.worsening.push(trendData);
|
|
531
|
+
} else {
|
|
532
|
+
trends.stable.push(trendData);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
// Sort each category
|
|
537
|
+
trends.improving.sort((a, b) => a.percentChange - b.percentChange);
|
|
538
|
+
trends.worsening.sort((a, b) => b.percentChange - a.percentChange);
|
|
539
|
+
trends.new.sort((a, b) => b.secondPeriod - a.secondPeriod);
|
|
540
|
+
|
|
541
|
+
return trends;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
/**
|
|
545
|
+
* Build skill-correction correlation matrix
|
|
546
|
+
* Links which skills help prevent which corrections
|
|
547
|
+
* @returns {object} { [skill]: { prevents: [corrections], rate } }
|
|
548
|
+
*/
|
|
549
|
+
function buildSkillCorrectionMatrix() {
|
|
550
|
+
// Load skill effectiveness data
|
|
551
|
+
const effectivenessFile = path.join(KNOWLEDGE_DIR, 'skill-effectiveness.json');
|
|
552
|
+
let skillData = { skills: {} };
|
|
553
|
+
|
|
554
|
+
try {
|
|
555
|
+
if (fs.existsSync(effectivenessFile)) {
|
|
556
|
+
skillData = JSON.parse(fs.readFileSync(effectivenessFile, 'utf8'));
|
|
557
|
+
}
|
|
558
|
+
} catch {
|
|
559
|
+
return {};
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
const { sessions, corrections } = analyzeAllSessions();
|
|
563
|
+
|
|
564
|
+
if (sessions.length < THRESHOLDS.MIN_SESSIONS_FOR_ANALYSIS) {
|
|
565
|
+
return {};
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
// For each skill, find sessions where it was applied
|
|
569
|
+
const matrix = {};
|
|
570
|
+
|
|
571
|
+
for (const [skillName, skill] of Object.entries(skillData.skills || {})) {
|
|
572
|
+
const skillContexts = skill.contexts || [];
|
|
573
|
+
const skillSessions = new Set(
|
|
574
|
+
skillContexts.map((c) => {
|
|
575
|
+
// Extract session from context (approximation based on timestamps)
|
|
576
|
+
return c.timestamp?.split(' ')[0]; // Date portion
|
|
577
|
+
})
|
|
578
|
+
);
|
|
579
|
+
|
|
580
|
+
// Find corrections in sessions where skill was applied vs not
|
|
581
|
+
const withSkill = { corrections: 0, sessions: 0 };
|
|
582
|
+
const withoutSkill = { corrections: 0, sessions: 0 };
|
|
583
|
+
|
|
584
|
+
for (const session of sessions) {
|
|
585
|
+
const sessionDate = session.startedAt?.split(' ')[0];
|
|
586
|
+
const sessionCorrections = (session.corrections || []).length;
|
|
587
|
+
|
|
588
|
+
if (skillSessions.has(sessionDate)) {
|
|
589
|
+
withSkill.corrections += sessionCorrections;
|
|
590
|
+
withSkill.sessions++;
|
|
591
|
+
} else {
|
|
592
|
+
withoutSkill.corrections += sessionCorrections;
|
|
593
|
+
withoutSkill.sessions++;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
// Calculate prevention rate
|
|
598
|
+
const rateWith = withSkill.sessions > 0 ? withSkill.corrections / withSkill.sessions : 0;
|
|
599
|
+
const rateWithout =
|
|
600
|
+
withoutSkill.sessions > 0 ? withoutSkill.corrections / withoutSkill.sessions : 0;
|
|
601
|
+
|
|
602
|
+
const preventionRate = rateWithout > 0 ? 1 - rateWith / rateWithout : 0;
|
|
603
|
+
|
|
604
|
+
if (skill.applications >= 3) {
|
|
605
|
+
matrix[skillName] = {
|
|
606
|
+
skill: skillName,
|
|
607
|
+
applications: skill.applications,
|
|
608
|
+
effectiveness: skill.effectiveness,
|
|
609
|
+
preventionRate: Math.round(preventionRate * 100) / 100,
|
|
610
|
+
withSkillRate: Math.round(rateWith * 100) / 100,
|
|
611
|
+
withoutSkillRate: Math.round(rateWithout * 100) / 100,
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
return matrix;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
/**
|
|
620
|
+
* Save aggregated data to disk
|
|
621
|
+
* @param {object} data - Aggregated data to save
|
|
622
|
+
*/
|
|
623
|
+
function saveAggregatedData(data) {
|
|
624
|
+
ensureDir(AGGREGATED_DIR);
|
|
625
|
+
|
|
626
|
+
const files = {
|
|
627
|
+
'pattern-library.json': data.patternLibrary,
|
|
628
|
+
'context-patterns.json': data.contextPatterns,
|
|
629
|
+
'trend-analysis.json': data.trendAnalysis,
|
|
630
|
+
'skill-correction-matrix.json': data.skillCorrectionMatrix,
|
|
631
|
+
'recommendations.json': data.recommendations,
|
|
632
|
+
};
|
|
633
|
+
|
|
634
|
+
for (const [filename, content] of Object.entries(files)) {
|
|
635
|
+
if (content) {
|
|
636
|
+
const filePath = path.join(AGGREGATED_DIR, filename);
|
|
637
|
+
writeFile(
|
|
638
|
+
filePath,
|
|
639
|
+
JSON.stringify(
|
|
640
|
+
{
|
|
641
|
+
lastUpdated: getDateTimeString(),
|
|
642
|
+
...content,
|
|
643
|
+
},
|
|
644
|
+
null,
|
|
645
|
+
2
|
|
646
|
+
)
|
|
647
|
+
);
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
// Save summary
|
|
652
|
+
const summaryPath = path.join(AGGREGATED_DIR, 'last-aggregation.json');
|
|
653
|
+
writeFile(
|
|
654
|
+
summaryPath,
|
|
655
|
+
JSON.stringify(
|
|
656
|
+
{
|
|
657
|
+
timestamp: getDateTimeString(),
|
|
658
|
+
patternCount: data.patternLibrary?.all?.length || 0,
|
|
659
|
+
recommendationCount: data.recommendations?.length || 0,
|
|
660
|
+
},
|
|
661
|
+
null,
|
|
662
|
+
2
|
|
663
|
+
)
|
|
664
|
+
);
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
/**
|
|
668
|
+
* Load previously aggregated data
|
|
669
|
+
* @returns {object} Previously aggregated data or null
|
|
670
|
+
*/
|
|
671
|
+
function loadAggregatedData() {
|
|
672
|
+
const files = [
|
|
673
|
+
'pattern-library.json',
|
|
674
|
+
'context-patterns.json',
|
|
675
|
+
'trend-analysis.json',
|
|
676
|
+
'skill-correction-matrix.json',
|
|
677
|
+
'recommendations.json',
|
|
678
|
+
];
|
|
679
|
+
|
|
680
|
+
const data = {};
|
|
681
|
+
|
|
682
|
+
for (const filename of files) {
|
|
683
|
+
const filePath = path.join(AGGREGATED_DIR, filename);
|
|
684
|
+
const content = readFile(filePath);
|
|
685
|
+
if (content) {
|
|
686
|
+
try {
|
|
687
|
+
data[filename.replace('.json', '').replace(/-/g, '_')] = JSON.parse(content);
|
|
688
|
+
} catch {
|
|
689
|
+
// Skip invalid files
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
return Object.keys(data).length > 0 ? data : null;
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
/**
|
|
698
|
+
* Get aggregation summary for quick checks
|
|
699
|
+
* @returns {object} { lastRun, patternCount, recommendationCount, needsUpdate }
|
|
700
|
+
*/
|
|
701
|
+
function getAggregationStatus() {
|
|
702
|
+
const summaryPath = path.join(AGGREGATED_DIR, 'last-aggregation.json');
|
|
703
|
+
const content = readFile(summaryPath);
|
|
704
|
+
|
|
705
|
+
if (!content) {
|
|
706
|
+
return { lastRun: null, patternCount: 0, recommendationCount: 0, needsUpdate: true };
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
try {
|
|
710
|
+
const summary = JSON.parse(content);
|
|
711
|
+
const lastRun = new Date(summary.timestamp?.replace(' ', 'T') || 0);
|
|
712
|
+
const hoursSinceLastRun = (Date.now() - lastRun) / (1000 * 60 * 60);
|
|
713
|
+
|
|
714
|
+
return {
|
|
715
|
+
lastRun: summary.timestamp,
|
|
716
|
+
patternCount: summary.patternCount,
|
|
717
|
+
recommendationCount: summary.recommendationCount,
|
|
718
|
+
needsUpdate: hoursSinceLastRun > 24, // Update if older than 24 hours
|
|
719
|
+
};
|
|
720
|
+
} catch {
|
|
721
|
+
return { lastRun: null, patternCount: 0, recommendationCount: 0, needsUpdate: true };
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
module.exports = {
|
|
726
|
+
// Core analysis functions
|
|
727
|
+
loadArchivedSessions,
|
|
728
|
+
analyzeAllSessions,
|
|
729
|
+
detectCrossSessionPatterns,
|
|
730
|
+
|
|
731
|
+
// Context analysis
|
|
732
|
+
analyzeByTechnology,
|
|
733
|
+
analyzeByComplianceMode,
|
|
734
|
+
|
|
735
|
+
// Trend analysis
|
|
736
|
+
analyzeTrends,
|
|
737
|
+
|
|
738
|
+
// Skill correlation
|
|
739
|
+
buildSkillCorrectionMatrix,
|
|
740
|
+
|
|
741
|
+
// Data persistence
|
|
742
|
+
saveAggregatedData,
|
|
743
|
+
loadAggregatedData,
|
|
744
|
+
getAggregationStatus,
|
|
745
|
+
|
|
746
|
+
// Utilities
|
|
747
|
+
calculateConfidence,
|
|
748
|
+
extractAllCorrections,
|
|
749
|
+
|
|
750
|
+
// Constants
|
|
751
|
+
THRESHOLDS,
|
|
752
|
+
CATEGORY_WEIGHTS,
|
|
753
|
+
AGGREGATED_DIR,
|
|
754
|
+
};
|