neuronlayer 0.1.8 → 0.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.
- package/README.md +95 -269
- package/dist/index.js +478 -126
- package/dist/index.js.map +7 -0
- package/package.json +7 -2
- package/esbuild.config.js +0 -26
- package/src/cli/commands.ts +0 -518
- package/src/core/adr-exporter.ts +0 -253
- package/src/core/architecture/architecture-enforcement.ts +0 -228
- package/src/core/architecture/duplicate-detector.ts +0 -288
- package/src/core/architecture/index.ts +0 -6
- package/src/core/architecture/pattern-learner.ts +0 -306
- package/src/core/architecture/pattern-library.ts +0 -403
- package/src/core/architecture/pattern-validator.ts +0 -324
- package/src/core/change-intelligence/bug-correlator.ts +0 -544
- package/src/core/change-intelligence/change-intelligence.ts +0 -264
- package/src/core/change-intelligence/change-tracker.ts +0 -334
- package/src/core/change-intelligence/fix-suggester.ts +0 -340
- package/src/core/change-intelligence/index.ts +0 -5
- package/src/core/code-verifier.ts +0 -843
- package/src/core/confidence/confidence-scorer.ts +0 -251
- package/src/core/confidence/conflict-checker.ts +0 -289
- package/src/core/confidence/index.ts +0 -5
- package/src/core/confidence/source-tracker.ts +0 -263
- package/src/core/confidence/warning-detector.ts +0 -241
- package/src/core/context-rot/compaction.ts +0 -284
- package/src/core/context-rot/context-health.ts +0 -243
- package/src/core/context-rot/context-rot-prevention.ts +0 -213
- package/src/core/context-rot/critical-context.ts +0 -221
- package/src/core/context-rot/drift-detector.ts +0 -255
- package/src/core/context-rot/index.ts +0 -7
- package/src/core/context.ts +0 -263
- package/src/core/decision-extractor.ts +0 -339
- package/src/core/decisions.ts +0 -69
- package/src/core/deja-vu.ts +0 -421
- package/src/core/engine.ts +0 -1646
- package/src/core/feature-context.ts +0 -726
- package/src/core/ghost-mode.ts +0 -465
- package/src/core/learning.ts +0 -519
- package/src/core/living-docs/activity-tracker.ts +0 -296
- package/src/core/living-docs/architecture-generator.ts +0 -428
- package/src/core/living-docs/changelog-generator.ts +0 -348
- package/src/core/living-docs/component-generator.ts +0 -230
- package/src/core/living-docs/doc-engine.ts +0 -134
- package/src/core/living-docs/doc-validator.ts +0 -282
- package/src/core/living-docs/index.ts +0 -8
- package/src/core/project-manager.ts +0 -301
- package/src/core/refresh/activity-gate.ts +0 -256
- package/src/core/refresh/git-staleness-checker.ts +0 -108
- package/src/core/refresh/index.ts +0 -27
- package/src/core/summarizer.ts +0 -290
- package/src/core/test-awareness/change-validator.ts +0 -499
- package/src/core/test-awareness/index.ts +0 -5
- package/src/index.ts +0 -49
- package/src/indexing/ast.ts +0 -868
- package/src/indexing/embeddings.ts +0 -85
- package/src/indexing/indexer.ts +0 -270
- package/src/indexing/watcher.ts +0 -78
- package/src/server/gateways/aggregator.ts +0 -374
- package/src/server/gateways/index.ts +0 -473
- package/src/server/gateways/memory-ghost.ts +0 -343
- package/src/server/gateways/memory-query.ts +0 -452
- package/src/server/gateways/memory-record.ts +0 -346
- package/src/server/gateways/memory-review.ts +0 -410
- package/src/server/gateways/memory-status.ts +0 -517
- package/src/server/gateways/memory-verify.ts +0 -392
- package/src/server/gateways/router.ts +0 -434
- package/src/server/gateways/types.ts +0 -610
- package/src/server/mcp.ts +0 -154
- package/src/server/resources.ts +0 -85
- package/src/server/tools.ts +0 -2460
- package/src/storage/database.ts +0 -271
- package/src/storage/tier1.ts +0 -135
- package/src/storage/tier2.ts +0 -972
- package/src/storage/tier3.ts +0 -123
- package/src/types/documentation.ts +0 -619
- package/src/types/index.ts +0 -222
- package/src/utils/config.ts +0 -193
- package/src/utils/files.ts +0 -117
- package/src/utils/time.ts +0 -37
- package/src/utils/tokens.ts +0 -52
|
@@ -1,434 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Intent Detection and Query Routing
|
|
3
|
-
*
|
|
4
|
-
* Provides auto-detection of user intent to route to appropriate internal tools.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type {
|
|
8
|
-
MemoryQueryInput,
|
|
9
|
-
MemoryQueryAction,
|
|
10
|
-
MemoryRecordInput,
|
|
11
|
-
MemoryRecordType,
|
|
12
|
-
MemoryReviewInput,
|
|
13
|
-
MemoryReviewAction,
|
|
14
|
-
MemoryStatusInput,
|
|
15
|
-
MemoryStatusAction,
|
|
16
|
-
} from './types.js';
|
|
17
|
-
|
|
18
|
-
// ============================================================================
|
|
19
|
-
// Pattern Detection
|
|
20
|
-
// ============================================================================
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Detects if a string looks like a file path
|
|
24
|
-
*/
|
|
25
|
-
export function isFilePath(str: string): boolean {
|
|
26
|
-
// Common file path patterns
|
|
27
|
-
const filePatterns = [
|
|
28
|
-
/^\.?\/?[\w-]+(?:\/[\w-]+)*\.\w+$/, // src/foo/bar.ts
|
|
29
|
-
/^[a-zA-Z]:\\/, // Windows absolute path
|
|
30
|
-
/^\//, // Unix absolute path
|
|
31
|
-
/\.(ts|js|tsx|jsx|py|go|rs|java|cpp|c|h|md|json|yaml|yml|toml)$/i, // File extensions
|
|
32
|
-
];
|
|
33
|
-
return filePatterns.some(pattern => pattern.test(str));
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Detects if a string looks like a symbol name (function, class, etc.)
|
|
38
|
-
*/
|
|
39
|
-
export function isSymbolName(str: string): boolean {
|
|
40
|
-
// PascalCase or camelCase identifiers without spaces
|
|
41
|
-
const symbolPattern = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
42
|
-
// Should not be a common word
|
|
43
|
-
const commonWords = ['the', 'and', 'for', 'with', 'how', 'what', 'why', 'when', 'where', 'is', 'are', 'was', 'were'];
|
|
44
|
-
return symbolPattern.test(str) && !commonWords.includes(str.toLowerCase()) && str.length > 1;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Detects if a string contains code
|
|
49
|
-
*/
|
|
50
|
-
export function containsCode(str: string): boolean {
|
|
51
|
-
// Look for code-like patterns
|
|
52
|
-
const codePatterns = [
|
|
53
|
-
/function\s+\w+\s*\(/, // function declarations
|
|
54
|
-
/const\s+\w+\s*=/, // const declarations
|
|
55
|
-
/let\s+\w+\s*=/, // let declarations
|
|
56
|
-
/class\s+\w+/, // class declarations
|
|
57
|
-
/interface\s+\w+/, // interface declarations
|
|
58
|
-
/=>/, // arrow functions
|
|
59
|
-
/\{\s*\n/, // code blocks
|
|
60
|
-
/import\s+.*from/, // imports
|
|
61
|
-
/export\s+(default\s+)?/, // exports
|
|
62
|
-
/if\s*\(.+\)\s*\{/, // if statements
|
|
63
|
-
/for\s*\(.+\)\s*\{/, // for loops
|
|
64
|
-
/async\s+function/, // async functions
|
|
65
|
-
/await\s+/, // await expressions
|
|
66
|
-
/try\s*\{/, // try blocks
|
|
67
|
-
/catch\s*\(/, // catch blocks
|
|
68
|
-
/return\s+/, // return statements
|
|
69
|
-
];
|
|
70
|
-
return codePatterns.some(pattern => pattern.test(str));
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Detects if a string looks like an error message
|
|
75
|
-
*/
|
|
76
|
-
export function isErrorMessage(str: string): boolean {
|
|
77
|
-
const errorPatterns = [
|
|
78
|
-
/error:/i,
|
|
79
|
-
/exception:/i,
|
|
80
|
-
/failed:/i,
|
|
81
|
-
/cannot\s+/i,
|
|
82
|
-
/unable\s+to/i,
|
|
83
|
-
/TypeError/i,
|
|
84
|
-
/ReferenceError/i,
|
|
85
|
-
/SyntaxError/i,
|
|
86
|
-
/undefined\s+is\s+not/i,
|
|
87
|
-
/is\s+not\s+defined/i,
|
|
88
|
-
/not\s+a\s+function/i,
|
|
89
|
-
/cannot\s+read\s+property/i,
|
|
90
|
-
];
|
|
91
|
-
return errorPatterns.some(pattern => pattern.test(str));
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// ============================================================================
|
|
95
|
-
// Query Router
|
|
96
|
-
// ============================================================================
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Auto-detect the best action for a memory query
|
|
100
|
-
*/
|
|
101
|
-
export function detectQueryAction(input: MemoryQueryInput): MemoryQueryAction {
|
|
102
|
-
// Explicit action takes priority
|
|
103
|
-
if (input.action) return input.action;
|
|
104
|
-
|
|
105
|
-
// Code provided → confidence/sources/existing check
|
|
106
|
-
if (input.code && input.code.length > 20) {
|
|
107
|
-
if (containsCode(input.code)) {
|
|
108
|
-
return 'confidence';
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// File path provided → file context
|
|
113
|
-
if (input.file && isFilePath(input.file)) {
|
|
114
|
-
return 'file';
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// Symbol name provided → symbol lookup
|
|
118
|
-
if (input.symbol && isSymbolName(input.symbol)) {
|
|
119
|
-
return 'symbol';
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Query looks like a file path → file context
|
|
123
|
-
if (isFilePath(input.query)) {
|
|
124
|
-
return 'file';
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Query is a single symbol-like word → symbol lookup
|
|
128
|
-
if (isSymbolName(input.query) && !input.query.includes(' ')) {
|
|
129
|
-
return 'symbol';
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// Default: combined context + search
|
|
133
|
-
return 'context';
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Parse the query to extract file paths, symbols, and search terms
|
|
138
|
-
*/
|
|
139
|
-
export function parseQuery(query: string): {
|
|
140
|
-
files: string[];
|
|
141
|
-
symbols: string[];
|
|
142
|
-
searchTerms: string;
|
|
143
|
-
} {
|
|
144
|
-
const words = query.split(/\s+/);
|
|
145
|
-
const files: string[] = [];
|
|
146
|
-
const symbols: string[] = [];
|
|
147
|
-
const searchTerms: string[] = [];
|
|
148
|
-
|
|
149
|
-
for (const word of words) {
|
|
150
|
-
if (isFilePath(word)) {
|
|
151
|
-
files.push(word);
|
|
152
|
-
} else if (isSymbolName(word) && word.length > 3) {
|
|
153
|
-
// Longer identifiers are likely symbols
|
|
154
|
-
symbols.push(word);
|
|
155
|
-
searchTerms.push(word); // Also include as search term
|
|
156
|
-
} else {
|
|
157
|
-
searchTerms.push(word);
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
return {
|
|
162
|
-
files,
|
|
163
|
-
symbols,
|
|
164
|
-
searchTerms: searchTerms.join(' '),
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// ============================================================================
|
|
169
|
-
// Record Router
|
|
170
|
-
// ============================================================================
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Auto-detect the type of record to create
|
|
174
|
-
*/
|
|
175
|
-
export function detectRecordType(input: MemoryRecordInput): MemoryRecordType {
|
|
176
|
-
// Explicit type/action takes priority
|
|
177
|
-
if (input.type) return input.type;
|
|
178
|
-
if (input.action) return input.action;
|
|
179
|
-
|
|
180
|
-
// Pattern-related inputs
|
|
181
|
-
if (input.pattern_id && input.code) {
|
|
182
|
-
return 'example';
|
|
183
|
-
}
|
|
184
|
-
if (input.pattern_name || (input.code && input.category)) {
|
|
185
|
-
return 'pattern';
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// Feedback input
|
|
189
|
-
if (input.query !== undefined && input.was_useful !== undefined) {
|
|
190
|
-
return 'feedback';
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// Critical content
|
|
194
|
-
if (input.critical_type || input.reason) {
|
|
195
|
-
return 'critical';
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
// Feature context (content is a feature name, no title)
|
|
199
|
-
if (!input.title && input.content && input.content.length < 50 && !input.code) {
|
|
200
|
-
return 'feature';
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
// Default to decision
|
|
204
|
-
return 'decision';
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* Validate record input has required fields for the detected type
|
|
209
|
-
*/
|
|
210
|
-
export function validateRecordInput(input: MemoryRecordInput): {
|
|
211
|
-
valid: boolean;
|
|
212
|
-
error?: string;
|
|
213
|
-
type: MemoryRecordType;
|
|
214
|
-
} {
|
|
215
|
-
const type = detectRecordType(input);
|
|
216
|
-
|
|
217
|
-
switch (type) {
|
|
218
|
-
case 'decision':
|
|
219
|
-
if (!input.title) {
|
|
220
|
-
return { valid: false, error: 'Decision requires a title', type };
|
|
221
|
-
}
|
|
222
|
-
if (!input.content) {
|
|
223
|
-
return { valid: false, error: 'Decision requires content/description', type };
|
|
224
|
-
}
|
|
225
|
-
break;
|
|
226
|
-
|
|
227
|
-
case 'pattern':
|
|
228
|
-
if (!input.code) {
|
|
229
|
-
return { valid: false, error: 'Pattern requires code example', type };
|
|
230
|
-
}
|
|
231
|
-
if (!input.pattern_name && !input.title) {
|
|
232
|
-
return { valid: false, error: 'Pattern requires a name', type };
|
|
233
|
-
}
|
|
234
|
-
break;
|
|
235
|
-
|
|
236
|
-
case 'example':
|
|
237
|
-
if (!input.pattern_id) {
|
|
238
|
-
return { valid: false, error: 'Example requires pattern_id', type };
|
|
239
|
-
}
|
|
240
|
-
if (!input.code) {
|
|
241
|
-
return { valid: false, error: 'Example requires code', type };
|
|
242
|
-
}
|
|
243
|
-
if (!input.explanation && !input.content) {
|
|
244
|
-
return { valid: false, error: 'Example requires explanation', type };
|
|
245
|
-
}
|
|
246
|
-
break;
|
|
247
|
-
|
|
248
|
-
case 'feedback':
|
|
249
|
-
if (input.was_useful === undefined) {
|
|
250
|
-
return { valid: false, error: 'Feedback requires was_useful boolean', type };
|
|
251
|
-
}
|
|
252
|
-
break;
|
|
253
|
-
|
|
254
|
-
case 'feature':
|
|
255
|
-
if (!input.content) {
|
|
256
|
-
return { valid: false, error: 'Feature requires a name (in content field)', type };
|
|
257
|
-
}
|
|
258
|
-
break;
|
|
259
|
-
|
|
260
|
-
case 'critical':
|
|
261
|
-
if (!input.content) {
|
|
262
|
-
return { valid: false, error: 'Critical content requires content', type };
|
|
263
|
-
}
|
|
264
|
-
break;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
return { valid: true, type };
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
// ============================================================================
|
|
271
|
-
// Review Router
|
|
272
|
-
// ============================================================================
|
|
273
|
-
|
|
274
|
-
/**
|
|
275
|
-
* Auto-detect the best action for a memory review
|
|
276
|
-
*/
|
|
277
|
-
export function detectReviewAction(input: MemoryReviewInput): MemoryReviewAction {
|
|
278
|
-
// Explicit action takes priority
|
|
279
|
-
if (input.action) return input.action;
|
|
280
|
-
|
|
281
|
-
// Error message provided → bug search
|
|
282
|
-
if (input.error && isErrorMessage(input.error)) {
|
|
283
|
-
return 'bugs';
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
// File provided with code → full review including tests
|
|
287
|
-
if (input.file && input.code) {
|
|
288
|
-
return 'full';
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
// Just code → pattern validation + conflicts
|
|
292
|
-
if (input.code && !input.file) {
|
|
293
|
-
return 'pattern';
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
// Default to full review
|
|
297
|
-
return 'full';
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
/**
|
|
301
|
-
* Determine which checks to run for a review
|
|
302
|
-
*/
|
|
303
|
-
export function getReviewChecks(input: MemoryReviewInput): {
|
|
304
|
-
runPatterns: boolean;
|
|
305
|
-
runConflicts: boolean;
|
|
306
|
-
runConfidence: boolean;
|
|
307
|
-
runExisting: boolean;
|
|
308
|
-
runTests: boolean;
|
|
309
|
-
runBugs: boolean;
|
|
310
|
-
runCoverage: boolean;
|
|
311
|
-
} {
|
|
312
|
-
const action = detectReviewAction(input);
|
|
313
|
-
|
|
314
|
-
// Full review runs everything applicable
|
|
315
|
-
if (action === 'full') {
|
|
316
|
-
return {
|
|
317
|
-
runPatterns: input.include_patterns !== false,
|
|
318
|
-
runConflicts: true,
|
|
319
|
-
runConfidence: true,
|
|
320
|
-
runExisting: !!input.intent,
|
|
321
|
-
runTests: !!input.file && input.include_tests !== false,
|
|
322
|
-
runBugs: !!input.error,
|
|
323
|
-
runCoverage: false, // Only on explicit request
|
|
324
|
-
};
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
// Specific actions
|
|
328
|
-
return {
|
|
329
|
-
runPatterns: action === 'pattern',
|
|
330
|
-
runConflicts: action === 'conflicts',
|
|
331
|
-
runConfidence: action === 'confidence',
|
|
332
|
-
runExisting: false,
|
|
333
|
-
runTests: action === 'tests',
|
|
334
|
-
runBugs: action === 'bugs',
|
|
335
|
-
runCoverage: action === 'coverage',
|
|
336
|
-
};
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
// ============================================================================
|
|
340
|
-
// Status Router
|
|
341
|
-
// ============================================================================
|
|
342
|
-
|
|
343
|
-
/**
|
|
344
|
-
* Auto-detect the best action for a memory status query
|
|
345
|
-
*/
|
|
346
|
-
export function detectStatusAction(input: MemoryStatusInput): MemoryStatusAction {
|
|
347
|
-
// Explicit action takes priority
|
|
348
|
-
if (input.action) return input.action;
|
|
349
|
-
|
|
350
|
-
// Time-based queries
|
|
351
|
-
if (input.since) {
|
|
352
|
-
if (input.author || input.file) {
|
|
353
|
-
return 'changed';
|
|
354
|
-
}
|
|
355
|
-
return 'happened';
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
// Category provided → patterns
|
|
359
|
-
if (input.category) {
|
|
360
|
-
return 'patterns';
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
// History requested → health
|
|
364
|
-
if (input.include_history) {
|
|
365
|
-
return 'health';
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
// Scope-based routing
|
|
369
|
-
switch (input.scope) {
|
|
370
|
-
case 'architecture':
|
|
371
|
-
return 'architecture';
|
|
372
|
-
case 'changes':
|
|
373
|
-
return 'changed';
|
|
374
|
-
case 'docs':
|
|
375
|
-
return 'undocumented';
|
|
376
|
-
case 'health':
|
|
377
|
-
return 'health';
|
|
378
|
-
case 'patterns':
|
|
379
|
-
return 'patterns';
|
|
380
|
-
default:
|
|
381
|
-
return 'summary';
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
/**
|
|
386
|
-
* Determine which status information to gather
|
|
387
|
-
*/
|
|
388
|
-
export function getStatusGathers(input: MemoryStatusInput): {
|
|
389
|
-
gatherProject: boolean;
|
|
390
|
-
gatherArchitecture: boolean;
|
|
391
|
-
gatherChanges: boolean;
|
|
392
|
-
gatherActivity: boolean;
|
|
393
|
-
gatherDocs: boolean;
|
|
394
|
-
gatherHealth: boolean;
|
|
395
|
-
gatherPatterns: boolean;
|
|
396
|
-
gatherStats: boolean;
|
|
397
|
-
gatherCritical: boolean;
|
|
398
|
-
gatherLearning: boolean;
|
|
399
|
-
gatherUndocumented: boolean;
|
|
400
|
-
} {
|
|
401
|
-
const scope = input.scope || 'project';
|
|
402
|
-
|
|
403
|
-
// 'all' scope gathers everything
|
|
404
|
-
if (scope === 'all') {
|
|
405
|
-
return {
|
|
406
|
-
gatherProject: true,
|
|
407
|
-
gatherArchitecture: true,
|
|
408
|
-
gatherChanges: !!input.since,
|
|
409
|
-
gatherActivity: !!input.since,
|
|
410
|
-
gatherDocs: true,
|
|
411
|
-
gatherHealth: true,
|
|
412
|
-
gatherPatterns: true,
|
|
413
|
-
gatherStats: true,
|
|
414
|
-
gatherCritical: true,
|
|
415
|
-
gatherLearning: true,
|
|
416
|
-
gatherUndocumented: false, // Can be large, skip for 'all'
|
|
417
|
-
};
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
// Scope-specific gathering
|
|
421
|
-
return {
|
|
422
|
-
gatherProject: scope === 'project',
|
|
423
|
-
gatherArchitecture: scope === 'architecture',
|
|
424
|
-
gatherChanges: scope === 'changes',
|
|
425
|
-
gatherActivity: scope === 'changes' && !!input.since,
|
|
426
|
-
gatherDocs: scope === 'docs',
|
|
427
|
-
gatherHealth: scope === 'health',
|
|
428
|
-
gatherPatterns: scope === 'patterns',
|
|
429
|
-
gatherStats: scope === 'architecture',
|
|
430
|
-
gatherCritical: scope === 'health',
|
|
431
|
-
gatherLearning: scope === 'project',
|
|
432
|
-
gatherUndocumented: scope === 'docs',
|
|
433
|
-
};
|
|
434
|
-
}
|