@cloudstreamsoftware/claude-tools 1.0.0 → 1.2.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.
Files changed (190) hide show
  1. package/README.md +152 -37
  2. package/agents/INDEX.md +183 -0
  3. package/agents/architect.md +247 -0
  4. package/agents/build-error-resolver.md +555 -0
  5. package/agents/catalyst-deployer.md +132 -0
  6. package/agents/code-reviewer.md +121 -0
  7. package/agents/compliance-auditor.md +148 -0
  8. package/agents/creator-architect.md +395 -0
  9. package/agents/deluge-reviewer.md +98 -0
  10. package/agents/doc-updater.md +471 -0
  11. package/agents/e2e-runner.md +711 -0
  12. package/agents/planner.md +122 -0
  13. package/agents/refactor-cleaner.md +309 -0
  14. package/agents/security-reviewer.md +582 -0
  15. package/agents/tdd-guide.md +302 -0
  16. package/bin/cloudstream-setup.js +16 -6
  17. package/config/versions.json +63 -0
  18. package/dist/hooks/hooks.json +209 -0
  19. package/dist/index.js +47 -0
  20. package/dist/lib/asset-value.js +609 -0
  21. package/dist/lib/client-manager.js +300 -0
  22. package/dist/lib/command-matcher.js +242 -0
  23. package/dist/lib/cross-session-patterns.js +754 -0
  24. package/dist/lib/intent-classifier.js +1075 -0
  25. package/dist/lib/package-manager.js +374 -0
  26. package/dist/lib/recommendation-engine.js +597 -0
  27. package/dist/lib/session-memory.js +489 -0
  28. package/dist/lib/skill-effectiveness.js +486 -0
  29. package/dist/lib/skill-matcher.js +595 -0
  30. package/dist/lib/tutorial-metrics.js +242 -0
  31. package/dist/lib/tutorial-progress.js +209 -0
  32. package/dist/lib/tutorial-renderer.js +431 -0
  33. package/dist/lib/utils.js +380 -0
  34. package/dist/lib/verify-formatter.js +143 -0
  35. package/dist/lib/workflow-state.js +249 -0
  36. package/hooks/hooks.json +209 -0
  37. package/package.json +5 -1
  38. package/scripts/aggregate-sessions.js +290 -0
  39. package/scripts/branch-name-validator.js +291 -0
  40. package/scripts/build.js +101 -0
  41. package/scripts/commands/client-switch.js +231 -0
  42. package/scripts/deprecate-skill.js +610 -0
  43. package/scripts/diagnose.js +324 -0
  44. package/scripts/doc-freshness.js +168 -0
  45. package/scripts/generate-weekly-digest.js +393 -0
  46. package/scripts/health-check.js +270 -0
  47. package/scripts/hooks/credential-check.js +101 -0
  48. package/scripts/hooks/evaluate-session.js +81 -0
  49. package/scripts/hooks/pre-compact.js +66 -0
  50. package/scripts/hooks/prompt-analyzer.js +276 -0
  51. package/scripts/hooks/prompt-router.js +422 -0
  52. package/scripts/hooks/quality-gate-enforcer.js +371 -0
  53. package/scripts/hooks/session-end.js +156 -0
  54. package/scripts/hooks/session-start.js +195 -0
  55. package/scripts/hooks/skill-injector.js +333 -0
  56. package/scripts/hooks/suggest-compact.js +58 -0
  57. package/scripts/lib/asset-value.js +609 -0
  58. package/scripts/lib/client-manager.js +300 -0
  59. package/scripts/lib/command-matcher.js +242 -0
  60. package/scripts/lib/cross-session-patterns.js +754 -0
  61. package/scripts/lib/intent-classifier.js +1075 -0
  62. package/scripts/lib/package-manager.js +374 -0
  63. package/scripts/lib/recommendation-engine.js +597 -0
  64. package/scripts/lib/session-memory.js +489 -0
  65. package/scripts/lib/skill-effectiveness.js +486 -0
  66. package/scripts/lib/skill-matcher.js +595 -0
  67. package/scripts/lib/tutorial-metrics.js +242 -0
  68. package/scripts/lib/tutorial-progress.js +209 -0
  69. package/scripts/lib/tutorial-renderer.js +431 -0
  70. package/scripts/lib/utils.js +380 -0
  71. package/scripts/lib/verify-formatter.js +143 -0
  72. package/scripts/lib/workflow-state.js +249 -0
  73. package/scripts/onboard.js +363 -0
  74. package/scripts/quarterly-report.js +692 -0
  75. package/scripts/setup-package-manager.js +204 -0
  76. package/scripts/sync-upstream.js +391 -0
  77. package/scripts/test.js +108 -0
  78. package/scripts/tutorial-runner.js +351 -0
  79. package/scripts/validate-all.js +201 -0
  80. package/scripts/verifiers/agents.js +245 -0
  81. package/scripts/verifiers/config.js +186 -0
  82. package/scripts/verifiers/environment.js +123 -0
  83. package/scripts/verifiers/hooks.js +188 -0
  84. package/scripts/verifiers/index.js +38 -0
  85. package/scripts/verifiers/persistence.js +140 -0
  86. package/scripts/verifiers/plugin.js +215 -0
  87. package/scripts/verifiers/skills.js +209 -0
  88. package/scripts/verify-setup.js +164 -0
  89. package/skills/INDEX.md +157 -0
  90. package/skills/backend-patterns/SKILL.md +586 -0
  91. package/skills/backend-patterns/catalyst-patterns.md +128 -0
  92. package/skills/bigquery-patterns/SKILL.md +27 -0
  93. package/skills/bigquery-patterns/performance-optimization.md +518 -0
  94. package/skills/bigquery-patterns/query-patterns.md +372 -0
  95. package/skills/bigquery-patterns/schema-design.md +78 -0
  96. package/skills/cloudstream-project-template/SKILL.md +20 -0
  97. package/skills/cloudstream-project-template/structure.md +65 -0
  98. package/skills/coding-standards/SKILL.md +524 -0
  99. package/skills/coding-standards/deluge-standards.md +83 -0
  100. package/skills/compliance-patterns/SKILL.md +28 -0
  101. package/skills/compliance-patterns/hipaa/audit-requirements.md +251 -0
  102. package/skills/compliance-patterns/hipaa/baa-process.md +298 -0
  103. package/skills/compliance-patterns/hipaa/data-archival-strategy.md +387 -0
  104. package/skills/compliance-patterns/hipaa/phi-handling.md +52 -0
  105. package/skills/compliance-patterns/pci-dss/saq-a-requirements.md +307 -0
  106. package/skills/compliance-patterns/pci-dss/tokenization-patterns.md +382 -0
  107. package/skills/compliance-patterns/pci-dss/zoho-checkout-patterns.md +56 -0
  108. package/skills/compliance-patterns/soc2/access-controls.md +344 -0
  109. package/skills/compliance-patterns/soc2/audit-logging.md +458 -0
  110. package/skills/compliance-patterns/soc2/change-management.md +403 -0
  111. package/skills/compliance-patterns/soc2/deluge-execution-logging.md +407 -0
  112. package/skills/consultancy-workflows/SKILL.md +19 -0
  113. package/skills/consultancy-workflows/client-isolation.md +21 -0
  114. package/skills/consultancy-workflows/documentation-automation.md +454 -0
  115. package/skills/consultancy-workflows/handoff-procedures.md +257 -0
  116. package/skills/consultancy-workflows/knowledge-capture.md +513 -0
  117. package/skills/consultancy-workflows/time-tracking.md +26 -0
  118. package/skills/continuous-learning/SKILL.md +84 -0
  119. package/skills/continuous-learning/config.json +18 -0
  120. package/skills/continuous-learning/evaluate-session.sh +60 -0
  121. package/skills/continuous-learning-v2/SKILL.md +126 -0
  122. package/skills/continuous-learning-v2/config.json +61 -0
  123. package/skills/frontend-patterns/SKILL.md +635 -0
  124. package/skills/frontend-patterns/zoho-widget-patterns.md +103 -0
  125. package/skills/gcp-data-engineering/SKILL.md +36 -0
  126. package/skills/gcp-data-engineering/bigquery/performance-optimization.md +337 -0
  127. package/skills/gcp-data-engineering/dataflow/error-handling.md +496 -0
  128. package/skills/gcp-data-engineering/dataflow/pipeline-patterns.md +444 -0
  129. package/skills/gcp-data-engineering/dbt/model-organization.md +63 -0
  130. package/skills/gcp-data-engineering/dbt/testing-patterns.md +503 -0
  131. package/skills/gcp-data-engineering/medallion-architecture/bronze-layer.md +60 -0
  132. package/skills/gcp-data-engineering/medallion-architecture/gold-layer.md +311 -0
  133. package/skills/gcp-data-engineering/medallion-architecture/layer-transitions.md +517 -0
  134. package/skills/gcp-data-engineering/medallion-architecture/silver-layer.md +305 -0
  135. package/skills/gcp-data-engineering/zoho-to-gcp/data-extraction.md +543 -0
  136. package/skills/gcp-data-engineering/zoho-to-gcp/real-time-vs-batch.md +337 -0
  137. package/skills/security-review/SKILL.md +498 -0
  138. package/skills/security-review/compliance-checklist.md +53 -0
  139. package/skills/strategic-compact/SKILL.md +67 -0
  140. package/skills/tdd-workflow/SKILL.md +413 -0
  141. package/skills/tdd-workflow/zoho-testing.md +124 -0
  142. package/skills/tutorial/SKILL.md +249 -0
  143. package/skills/tutorial/docs/ACCESSIBILITY.md +169 -0
  144. package/skills/tutorial/lessons/00-philosophy-and-workflow.md +198 -0
  145. package/skills/tutorial/lessons/01-basics.md +81 -0
  146. package/skills/tutorial/lessons/02-training.md +86 -0
  147. package/skills/tutorial/lessons/03-commands.md +109 -0
  148. package/skills/tutorial/lessons/04-workflows.md +115 -0
  149. package/skills/tutorial/lessons/05-compliance.md +116 -0
  150. package/skills/tutorial/lessons/06-zoho.md +121 -0
  151. package/skills/tutorial/lessons/07-hooks-system.md +277 -0
  152. package/skills/tutorial/lessons/08-mcp-servers.md +316 -0
  153. package/skills/tutorial/lessons/09-client-management.md +215 -0
  154. package/skills/tutorial/lessons/10-testing-e2e.md +260 -0
  155. package/skills/tutorial/lessons/11-skills-deep-dive.md +272 -0
  156. package/skills/tutorial/lessons/12-rules-system.md +326 -0
  157. package/skills/tutorial/lessons/13-golden-standard-graduation.md +213 -0
  158. package/skills/tutorial/lessons/14-fork-setup-and-sync.md +312 -0
  159. package/skills/tutorial/lessons/15-living-examples-system.md +221 -0
  160. package/skills/tutorial/tracks/accelerated/README.md +134 -0
  161. package/skills/tutorial/tracks/accelerated/assessment/checkpoint-1.md +161 -0
  162. package/skills/tutorial/tracks/accelerated/assessment/checkpoint-2.md +175 -0
  163. package/skills/tutorial/tracks/accelerated/day-1-core-concepts.md +234 -0
  164. package/skills/tutorial/tracks/accelerated/day-2-essential-commands.md +270 -0
  165. package/skills/tutorial/tracks/accelerated/day-3-workflow-mastery.md +305 -0
  166. package/skills/tutorial/tracks/accelerated/day-4-compliance-zoho.md +304 -0
  167. package/skills/tutorial/tracks/accelerated/day-5-hooks-skills.md +344 -0
  168. package/skills/tutorial/tracks/accelerated/day-6-client-testing.md +386 -0
  169. package/skills/tutorial/tracks/accelerated/day-7-graduation.md +369 -0
  170. package/skills/zoho-patterns/CHANGELOG.md +108 -0
  171. package/skills/zoho-patterns/SKILL.md +446 -0
  172. package/skills/zoho-patterns/analytics/dashboard-patterns.md +352 -0
  173. package/skills/zoho-patterns/analytics/zoho-to-bigquery-pipeline.md +427 -0
  174. package/skills/zoho-patterns/catalyst/appsail-deployment.md +349 -0
  175. package/skills/zoho-patterns/catalyst/context-close-patterns.md +354 -0
  176. package/skills/zoho-patterns/catalyst/cron-batch-processing.md +374 -0
  177. package/skills/zoho-patterns/catalyst/function-patterns.md +439 -0
  178. package/skills/zoho-patterns/creator/form-design.md +304 -0
  179. package/skills/zoho-patterns/creator/publish-api-patterns.md +313 -0
  180. package/skills/zoho-patterns/creator/widget-integration.md +306 -0
  181. package/skills/zoho-patterns/creator/workflow-automation.md +253 -0
  182. package/skills/zoho-patterns/deluge/api-patterns.md +468 -0
  183. package/skills/zoho-patterns/deluge/batch-processing.md +403 -0
  184. package/skills/zoho-patterns/deluge/cross-app-integration.md +356 -0
  185. package/skills/zoho-patterns/deluge/error-handling.md +423 -0
  186. package/skills/zoho-patterns/deluge/syntax-reference.md +65 -0
  187. package/skills/zoho-patterns/integration/cors-proxy-architecture.md +426 -0
  188. package/skills/zoho-patterns/integration/crm-books-native-sync.md +277 -0
  189. package/skills/zoho-patterns/integration/oauth-token-management.md +461 -0
  190. 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
+ };