@stupify/cli 0.0.3 → 0.0.4

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 (59) hide show
  1. package/README.md +26 -31
  2. package/dist/analysis.d.ts +11 -9
  3. package/dist/analysis.js +30 -173
  4. package/dist/checks.d.ts +1 -0
  5. package/dist/checks.js +89 -2
  6. package/dist/command.js +55 -91
  7. package/dist/constants.d.ts +1 -1
  8. package/dist/constants.js +1 -1
  9. package/dist/counter-scout.js +70 -8
  10. package/dist/doctor.d.ts +4 -0
  11. package/dist/doctor.js +131 -0
  12. package/dist/git.d.ts +4 -1
  13. package/dist/git.js +34 -0
  14. package/dist/hooks.d.ts +3 -0
  15. package/dist/hooks.js +117 -0
  16. package/dist/model.d.ts +1 -15
  17. package/dist/model.js +37 -21
  18. package/dist/prompts.d.ts +8 -5
  19. package/dist/prompts.js +58 -168
  20. package/dist/render.d.ts +2 -2
  21. package/dist/render.js +70 -78
  22. package/dist/repomix-provider.d.ts +10 -2
  23. package/dist/repomix-provider.js +62 -11
  24. package/dist/search-bench.d.ts +1 -0
  25. package/dist/search-bench.js +675 -0
  26. package/dist/search-profile.d.ts +6 -0
  27. package/dist/search-profile.js +73 -0
  28. package/dist/sem-provider.d.ts +2 -2
  29. package/dist/sem-provider.js +33 -7
  30. package/dist/stupify.d.ts +2 -0
  31. package/dist/stupify.js +183 -333
  32. package/dist/types.d.ts +193 -109
  33. package/package.json +1 -1
  34. package/src/analysis.ts +48 -268
  35. package/src/checks.ts +91 -2
  36. package/src/command.ts +62 -107
  37. package/src/constants.ts +1 -1
  38. package/src/counter-scout.ts +63 -7
  39. package/src/doctor.ts +140 -0
  40. package/src/git.ts +35 -1
  41. package/src/hooks.ts +134 -0
  42. package/src/model.ts +39 -26
  43. package/src/prompts.ts +66 -202
  44. package/src/render.ts +68 -79
  45. package/src/repomix-provider.ts +66 -10
  46. package/src/search-bench.ts +783 -0
  47. package/src/search-profile.ts +89 -0
  48. package/src/sem-provider.ts +36 -9
  49. package/src/stupify.ts +213 -526
  50. package/src/types.ts +195 -119
  51. package/dist/batcher.d.ts +0 -3
  52. package/dist/batcher.js +0 -142
  53. package/dist/candidate-context.d.ts +0 -2
  54. package/dist/candidate-context.js +0 -40
  55. package/dist/experiment.d.ts +0 -1
  56. package/dist/experiment.js +0 -225
  57. package/src/batcher.ts +0 -198
  58. package/src/candidate-context.ts +0 -43
  59. package/src/experiment.ts +0 -317
package/src/types.ts CHANGED
@@ -13,40 +13,39 @@ export function checkId(value: string): CheckId {
13
13
  return value as CheckId;
14
14
  }
15
15
 
16
- export type Engine = "raw-diff" | "sem";
17
- export type ScoutMode = "llm" | "counter";
18
- export type AuditContextMode = "none" | "repomix";
19
- export type AuditPromptName = "strict" | "high_bar";
16
+ export type SearchMode = "warn" | "off";
17
+ export type HookAction = "install" | "uninstall" | "status";
18
+ export type SearchSource = "since" | "stdin" | "commit" | "commits" | "staged";
20
19
 
21
- type AnalyzeOptions = Readonly<{
20
+ type SearchOptions = Readonly<{
22
21
  checkIds: readonly string[] | null;
23
22
  json: boolean;
24
23
  model: ModelId;
25
- engine: Engine;
26
- scout: ScoutMode;
27
- auditContext: AuditContextMode;
28
- auditPrompt: AuditPromptName;
29
24
  debugSem: boolean;
30
- debugTargets: boolean;
31
25
  maxCandidates: number;
32
- auditBatchSize: number;
33
- maxAuditInputTokens: number;
34
- auditConcurrency: number;
26
+ maxSearchInputTokens: number;
27
+ searchProfilePath: string | null;
28
+ includeCounterReasonInPrompt: boolean;
35
29
  }>;
36
30
 
37
31
  export type Command =
38
32
  | Readonly<{ kind: "help" }>
39
- | Readonly<{ kind: "experiment"; configPath: string }>
40
- | (Readonly<{ kind: "since"; since: string }> & AnalyzeOptions)
41
- | (Readonly<{ kind: "stdin" }> & AnalyzeOptions)
42
- | (Readonly<{ kind: "commit"; commit: string }> & AnalyzeOptions)
43
- | (Readonly<{ kind: "commits"; count: number }> & AnalyzeOptions);
44
-
45
- type ControlCommand =
33
+ | Readonly<{ kind: "hook"; action: HookAction }>
34
+ | Readonly<{ kind: "doctor" }>
35
+ | Readonly<{ kind: "bench-search"; configPath: string }>
36
+ | (Readonly<{ kind: "since"; since: string; mode: "search"; source: "since" }> & SearchOptions)
37
+ | (Readonly<{ kind: "stdin"; mode: "search"; source: "stdin" }> & SearchOptions)
38
+ | (Readonly<{ kind: "commit"; commit: string; mode: "search"; source: "commit" }> & SearchOptions)
39
+ | (Readonly<{ kind: "commits"; count: number; mode: "search"; source: "commits" }> & SearchOptions)
40
+ | (Readonly<{ kind: "staged"; mode: "search"; source: "staged" }> & SearchOptions);
41
+
42
+ export type SearchCommand = Exclude<
43
+ Command,
46
44
  | Readonly<{ kind: "help" }>
47
- | Readonly<{ kind: "experiment"; configPath: string }>;
48
-
49
- export type AnalyzeCommand = Exclude<Command, ControlCommand>;
45
+ | Readonly<{ kind: "hook"; action: HookAction }>
46
+ | Readonly<{ kind: "doctor" }>
47
+ | Readonly<{ kind: "bench-search"; configPath: string }>
48
+ >;
50
49
 
51
50
  export type StupifyCheck = Readonly<{
52
51
  id: CheckId;
@@ -55,48 +54,29 @@ export type StupifyCheck = Readonly<{
55
54
  lookFor: readonly string[];
56
55
  ignoreWhen: readonly string[];
57
56
  enabledByDefault?: boolean;
57
+ hookMode?: SearchMode;
58
+ searchPrompt?: string;
59
+ searchExamples?: Readonly<{
60
+ match: readonly string[];
61
+ nonMatch: readonly string[];
62
+ }>;
58
63
  examples?: Readonly<{
59
64
  match?: readonly string[];
60
65
  noMatch?: readonly string[];
61
66
  }>;
62
67
  }>;
63
68
 
64
- export type FindingCandidate = Readonly<{
65
- checkId: string;
66
- why: string;
67
- proof: string;
68
- }>;
69
-
70
- export type Finding = Readonly<{
71
- sourceId: SourceId;
72
- checkId: CheckId;
73
- why: string;
74
- proof: string;
75
- }>;
76
-
77
- export type FindingsResult = Readonly<{
78
- findings: readonly Finding[];
79
- summary?: string;
80
- }>;
81
-
82
- export type AuditReviewStats = Readonly<{
83
- totalTargets: number;
84
- finding: number;
85
- clean: number;
86
- uncertain: number;
87
- invalid: number;
88
- }>;
89
-
90
- export type AuditReviewResult = FindingsResult & Readonly<{
91
- stats: AuditReviewStats;
92
- }>;
93
-
94
69
  export type NetDiffStats = Readonly<{
95
70
  filesChanged: number;
96
71
  additions: number;
97
72
  deletions: number;
98
73
  }>;
99
74
 
75
+ export type StagedDiff = Readonly<{
76
+ text: string;
77
+ stats: NetDiffStats;
78
+ }>;
79
+
100
80
  export type NetDiff = Readonly<{
101
81
  id: SourceId;
102
82
  label: string;
@@ -114,27 +94,6 @@ export type SourceRange = Readonly<{
114
94
  stats: NetDiffStats;
115
95
  }>;
116
96
 
117
- export type DiffHunk = Readonly<{
118
- pointer: string;
119
- batchId: string;
120
- fileId: string;
121
- hunkId: string;
122
- filePath: string;
123
- lineCount: number;
124
- text: string;
125
- }>;
126
-
127
- export type DiffBatch = Readonly<{
128
- id: string;
129
- hunks: readonly DiffHunk[];
130
- text: string;
131
- }>;
132
-
133
- export type CandidateContext = Readonly<{
134
- pointer: string;
135
- text: string;
136
- }>;
137
-
138
97
  export type SemChange = Readonly<{
139
98
  entityId: string;
140
99
  entityName: string;
@@ -186,66 +145,176 @@ export type SemContext = Readonly<{
186
145
  text: string;
187
146
  }>;
188
147
 
189
- export type DebugTarget = Readonly<{
190
- targetId: string;
191
- checkId: CheckId;
192
- entityId: string;
193
- entityKind?: string;
194
- changeKind?: string;
195
- scoutReason?: string;
196
- sourceLabel?: string;
197
- }>;
198
-
199
148
  export type SemContextPack = Readonly<{
200
149
  provider: "repomix";
201
150
  filePaths: readonly string[];
202
151
  totalCharacters: number;
203
152
  totalTokens: number;
204
153
  text: string;
154
+ config: RepomixSearchConfig;
205
155
  }>;
206
156
 
207
- export type AnalysisRun = Readonly<{
208
- engine: Engine;
209
- auditContext: AuditContextMode;
210
- auditPrompt: AuditPromptName;
211
- mode: AnalyzeCommand["kind"];
212
- modelId: ModelId;
213
- checkIds: readonly CheckId[];
214
- sourceId: SourceId;
215
- label: string;
216
- stats: NetDiffStats;
217
- batchesScanned: number;
218
- candidateCount: number;
219
- targetsByCheck?: Readonly<Record<string, number>>;
220
- entitiesScanned: number;
221
- auditedCandidateCount: number;
222
- scoutModelCalls: number;
223
- auditModelCalls: number;
224
- timingsMs: Readonly<{
225
- diff: number;
226
- modelLoad: number;
227
- search: number;
228
- audit: number;
229
- total: number;
157
+ export type RepomixSearchConfig = Readonly<{
158
+ compress: boolean;
159
+ showLineNumbers: boolean;
160
+ removeEmptyLines: boolean;
161
+ maxFileSizeBytes: number;
162
+ maxTotalSizeBytes: number;
163
+ ignorePatterns: readonly string[];
164
+ }>;
165
+
166
+ export type SearchProfileRepomixConfig = Readonly<{
167
+ compress?: boolean;
168
+ showLineNumbers?: boolean;
169
+ removeEmptyLines?: boolean;
170
+ maxFileBytes?: number;
171
+ maxTotalBytes?: number;
172
+ ignorePatterns?: readonly string[];
173
+ }>;
174
+
175
+ export type SearchProfilePattern = Readonly<{
176
+ enabled?: boolean;
177
+ searchPrompt?: string;
178
+ matchExamples?: readonly string[];
179
+ nonMatchExamples?: readonly string[];
180
+ }>;
181
+
182
+ export type SearchProfile = Readonly<{
183
+ id: string;
184
+ context?: "repomix" | "sem";
185
+ maxCandidates?: number;
186
+ maxSearchInputTokens?: number;
187
+ includeCounterReasonInPrompt?: boolean;
188
+ repomix?: SearchProfileRepomixConfig;
189
+ patterns?: Readonly<Record<string, SearchProfilePattern>>;
190
+ }>;
191
+
192
+ export type SearchMatch = Readonly<{
193
+ targetId: string;
194
+ patternId: CheckId;
195
+ reason: string;
196
+ proof: string;
197
+ }>;
198
+
199
+ export type SearchRunJson = Readonly<{
200
+ schemaVersion: "search.v1";
201
+ mode: "search";
202
+ source: SearchSource;
203
+ model: Readonly<{ id: ModelId }>;
204
+ patterns: readonly CheckId[];
205
+ stats: Readonly<{
206
+ elapsedMs: number;
207
+ modelCalls: number;
208
+ inputTokens?: number;
209
+ inputTokenCap?: number;
210
+ skipped?: boolean;
211
+ skipReason?: "input_too_large" | "no_candidates";
212
+ filesChanged?: number;
213
+ entitiesScanned?: number;
214
+ candidates?: number;
215
+ repomixFiles?: number;
216
+ repomixTokens?: number;
217
+ repomixConfig?: RepomixSearchConfig;
218
+ searchTargets?: number;
219
+ profileId?: string;
220
+ targetsByPattern?: Readonly<Record<string, number>>;
221
+ targetsPreview?: readonly SearchTargetPreview[];
230
222
  }>;
231
- warnings: readonly string[];
232
- auditStats?: AuditReviewStats;
233
- debugTargets?: readonly DebugTarget[];
234
- traceEvents?: readonly TraceEvent[];
223
+ matches: readonly SearchMatch[];
235
224
  }>;
236
225
 
237
- export type TraceEvent = Readonly<{
226
+ export type SearchTargetPreview = Readonly<{
227
+ targetId: string;
228
+ patternId: CheckId;
229
+ entityKind?: string;
230
+ sourceKind?: string;
231
+ }>;
232
+
233
+ export type SearchBenchConfig = Readonly<{
238
234
  name: string;
239
- ms: number;
240
- count?: number;
241
- detail?: string;
235
+ profiles: readonly string[];
236
+ fixtures: string;
237
+ realSmokeRuns?: readonly SearchBenchSmokeRun[];
238
+ realCommitReplay?: readonly SearchBenchCommitReplay[];
242
239
  }>;
243
240
 
244
- export type AnalysisReport = Readonly<{
245
- run: AnalysisRun;
246
- result: FindingsResult;
241
+ export type SearchBenchSmokeRun = Readonly<{
242
+ id: string;
243
+ cwd?: string;
244
+ args: readonly string[];
247
245
  }>;
248
246
 
247
+ export type SearchBenchCommitReplay = Readonly<{
248
+ id: string;
249
+ repoEnv?: string;
250
+ cwd?: string;
251
+ limit: number;
252
+ since?: string;
253
+ nonMerge?: boolean;
254
+ profiles: readonly string[];
255
+ }>;
256
+
257
+ export type SearchFixture = Readonly<{
258
+ id: string;
259
+ description: string;
260
+ stagedPatch: string;
261
+ checks: readonly string[];
262
+ expected: readonly SearchFixtureExpectation[];
263
+ }>;
264
+
265
+ export type SearchFixtureExpectation = Readonly<{
266
+ patternId: string;
267
+ shouldMatch: boolean;
268
+ }>;
269
+
270
+ export type SearchBenchRun = Readonly<{
271
+ profileId: string;
272
+ fixtureId?: string;
273
+ smokeId?: string;
274
+ elapsedMs: number;
275
+ modelCalls: number;
276
+ patterns: readonly CheckId[];
277
+ targets: number;
278
+ targetsByPattern: Readonly<Record<string, number>>;
279
+ inputTokens: number;
280
+ repomixPackedTokens?: number;
281
+ skipped: boolean;
282
+ skipReason?: string;
283
+ matches: readonly SearchMatch[];
284
+ expected?: readonly SearchFixtureExpectation[];
285
+ score?: number;
286
+ targetsPreview: readonly SearchTargetPreview[];
287
+ matchesUsingCounterReasonAsProof: number;
288
+ error?: string;
289
+ }>;
290
+
291
+ export type SearchBenchReplayRun = Readonly<{
292
+ profileId: string;
293
+ replayId: string;
294
+ commitId: string;
295
+ outcome: SearchReplayOutcome;
296
+ changedFiles: number;
297
+ addedLines: number;
298
+ deletedLines: number;
299
+ elapsedMs: number;
300
+ skipped: boolean;
301
+ skipReason?: string;
302
+ targets: number;
303
+ inputTokens: number;
304
+ repomixPackedTokens?: number;
305
+ modelCalls: number;
306
+ matches: readonly SearchMatch[];
307
+ matchesByPattern: Readonly<Record<string, number>>;
308
+ error?: string;
309
+ }>;
310
+
311
+ export type SearchReplayOutcome =
312
+ | "no_candidates"
313
+ | "ran_no_matches"
314
+ | "ran_with_matches"
315
+ | "skipped_input_too_large"
316
+ | "error";
317
+
249
318
  export type ModelId =
250
319
  | "gemma-4-e2b"
251
320
  | "gemma-4-e4b"
@@ -258,7 +327,14 @@ export type ModelId =
258
327
  export type ModelConfig = Readonly<{
259
328
  id: ModelId;
260
329
  name: string;
261
- size: string;
262
330
  file: string;
263
331
  url: string;
332
+ size: string;
333
+ }>;
334
+
335
+ export type TraceEvent = Readonly<{
336
+ name: string;
337
+ ms: number;
338
+ count?: number;
339
+ detail?: string;
264
340
  }>;
package/dist/batcher.d.ts DELETED
@@ -1,3 +0,0 @@
1
- import type { DiffBatch, DiffHunk } from "./types.ts";
2
- export declare function batchDiff(diff: string, linesPerBatch?: number): readonly DiffBatch[];
3
- export declare function allHunks(batches: readonly DiffBatch[]): readonly DiffHunk[];
package/dist/batcher.js DELETED
@@ -1,142 +0,0 @@
1
- const DEFAULT_BATCH_LINES = 1_000;
2
- export function batchDiff(diff, linesPerBatch = DEFAULT_BATCH_LINES) {
3
- const hunks = parseHunks(diff).flatMap((item) => splitLargeHunk(item, linesPerBatch));
4
- const initialState = {
5
- batches: [],
6
- current: [],
7
- currentLines: 0,
8
- batchNumber: 1,
9
- };
10
- const finalized = hunks.reduce((state, hunk) => {
11
- const needsFlush = state.current.length > 0 &&
12
- state.currentLines + hunk.lineCount > linesPerBatch;
13
- const flushed = needsFlush ? flush(state) : state;
14
- return {
15
- ...flushed,
16
- current: [...flushed.current, toDiffHunk(hunk, flushed.batchNumber)],
17
- currentLines: flushed.currentLines + hunk.lineCount,
18
- };
19
- }, initialState);
20
- return finalized.current.length > 0
21
- ? [...finalized.batches, toBatch(finalized.batchNumber, finalized.current)]
22
- : finalized.batches;
23
- function flush(state) {
24
- return {
25
- batches: [...state.batches, toBatch(state.batchNumber, state.current)],
26
- current: [],
27
- currentLines: 0,
28
- batchNumber: state.batchNumber + 1,
29
- };
30
- }
31
- }
32
- export function allHunks(batches) {
33
- return batches.flatMap((batch) => batch.hunks);
34
- }
35
- function parseHunks(diff) {
36
- const lines = diff.split(/\r?\n/);
37
- const initialState = {
38
- hunks: [],
39
- filePath: "unknown",
40
- fileIndex: 0,
41
- hunkIndex: 0,
42
- fileHeader: [],
43
- hunkLines: null,
44
- };
45
- const finalState = lines.reduce((state, line) => {
46
- const fileMatch = /^diff --git a\/.+ b\/(.+)$/.exec(line);
47
- if (fileMatch) {
48
- const flushed = flush(state);
49
- return {
50
- ...flushed,
51
- fileIndex: flushed.fileIndex + 1,
52
- hunkIndex: 0,
53
- filePath: fileMatch[1],
54
- fileHeader: [line],
55
- hunkLines: null,
56
- };
57
- }
58
- if (line.startsWith("@@ ")) {
59
- const flushed = flush(state);
60
- return {
61
- ...flushed,
62
- hunkIndex: flushed.hunkIndex + 1,
63
- hunkLines: [...flushed.fileHeader, line],
64
- };
65
- }
66
- if (state.hunkLines)
67
- return { ...state, hunkLines: [...state.hunkLines, line] };
68
- if (state.fileHeader.length > 0)
69
- return { ...state, fileHeader: [...state.fileHeader, line] };
70
- return state;
71
- }, initialState);
72
- return flush(finalState).hunks;
73
- function flush(state) {
74
- if (!state.hunkLines)
75
- return state;
76
- const fileId = `file-${pad(state.fileIndex)}`;
77
- const hunkId = `hunk-${pad(state.hunkIndex)}`;
78
- const text = state.hunkLines.join("\n").trimEnd();
79
- const nextHunk = {
80
- fileId,
81
- hunkId,
82
- filePath: state.filePath,
83
- text,
84
- lineCount: countLines(text),
85
- };
86
- return { ...state, hunks: [...state.hunks, nextHunk], hunkLines: null };
87
- }
88
- }
89
- function splitLargeHunk(hunk, linesPerBatch) {
90
- if (hunk.lineCount <= linesPerBatch)
91
- return [hunk];
92
- const lines = hunk.text.split(/\r?\n/);
93
- const chunkCount = Math.ceil(lines.length / linesPerBatch);
94
- return Array.from({ length: chunkCount }, (_, chunkIndex) => {
95
- const start = chunkIndex * linesPerBatch;
96
- const text = lines.slice(start, start + linesPerBatch).join("\n");
97
- return {
98
- ...hunk,
99
- hunkId: `${hunk.hunkId}-part-${pad(chunkIndex + 1)}`,
100
- text,
101
- lineCount: countLines(text),
102
- };
103
- });
104
- }
105
- function toDiffHunk(hunk, batchNumber) {
106
- const batchId = `batch-${pad(batchNumber)}`;
107
- return {
108
- ...hunk,
109
- batchId,
110
- pointer: `${batchId}:${hunk.fileId}:${hunk.hunkId}`,
111
- };
112
- }
113
- function toBatch(batchNumber, hunks) {
114
- const id = `batch-${pad(batchNumber)}`;
115
- return {
116
- id,
117
- hunks,
118
- text: hunks.map(formatHunkForSearch).join("\n\n"),
119
- };
120
- }
121
- function formatHunkForSearch(hunk) {
122
- return `POINTER ${hunk.pointer}
123
- FILE ${hunk.fileId}
124
- PATH ${hunk.filePath}
125
- ${searchView(hunk.text)}`;
126
- }
127
- function searchView(text) {
128
- return text
129
- .split(/\r?\n/)
130
- .filter((line) => line.startsWith("diff --git ") ||
131
- line.startsWith("--- ") ||
132
- line.startsWith("+++ ") ||
133
- line.startsWith("@@ ") ||
134
- (line.startsWith("+") && !line.startsWith("+++")))
135
- .join("\n");
136
- }
137
- function countLines(value) {
138
- return value.length === 0 ? 0 : value.split(/\r?\n/).length;
139
- }
140
- function pad(value) {
141
- return String(value).padStart(3, "0");
142
- }
@@ -1,2 +0,0 @@
1
- import type { CandidateContext, DiffBatch } from "./types.ts";
2
- export declare function candidateContexts(batches: readonly DiffBatch[], candidatePointers: readonly string[]): readonly CandidateContext[];
@@ -1,40 +0,0 @@
1
- import { allHunks } from "./batcher.js";
2
- const MAX_CONTEXT_LINES = 80;
3
- export function candidateContexts(batches, candidatePointers) {
4
- const hunks = allHunks(batches);
5
- const byPointer = new Map(hunks.map((hunk) => [hunk.pointer, hunk]));
6
- const uniquePointers = [...new Set(candidatePointers)]
7
- .sort((left, right) => hunkPriority(byPointer.get(right)) - hunkPriority(byPointer.get(left)));
8
- return uniquePointers.flatMap((pointer) => {
9
- const hunk = byPointer.get(pointer);
10
- if (!hunk)
11
- return [];
12
- return [{ pointer, text: formatHunk(hunk) }];
13
- });
14
- }
15
- function formatHunk(hunk) {
16
- return `PATH ${hunk.filePath}
17
- ${shorten(hunk.text)}`;
18
- }
19
- function shorten(text) {
20
- const lines = text.split(/\r?\n/);
21
- if (lines.length <= MAX_CONTEXT_LINES)
22
- return text;
23
- return `${lines.slice(0, MAX_CONTEXT_LINES).join("\n")}
24
- [stupify: hunk shortened after ${MAX_CONTEXT_LINES} lines]`;
25
- }
26
- function hunkPriority(hunk) {
27
- if (!hunk)
28
- return 0;
29
- const text = hunk.text;
30
- let priority = 0;
31
- if (/^\+export\s+type\s|\+export\s+interface\s|\+type\s|\+interface\s/m.test(text))
32
- priority += 3;
33
- if (/^\+export\s+function\s|\+function\s/m.test(text))
34
- priority += 2;
35
- if (/\.map\(|=>\s*\(\{|=>\s*\{/m.test(text))
36
- priority += 2;
37
- if (/payload|schema|dto|response|result/i.test(text))
38
- priority += 1;
39
- return priority;
40
- }
@@ -1 +0,0 @@
1
- export declare function runExperiment(configPath: string): Promise<string>;