@stupify/cli 0.0.16 → 0.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.
Files changed (74) hide show
  1. package/.review/CORPUS.md +73 -0
  2. package/.review/REVIEW-PROMPT.md +52 -0
  3. package/.review/RUBRIC.md +46 -0
  4. package/LICENSE +1 -1
  5. package/README.md +41 -39
  6. package/package.json +24 -25
  7. package/src/cli.ts +358 -0
  8. package/src/review-sweep.ts +492 -0
  9. package/dist/analysis.d.ts +0 -16
  10. package/dist/analysis.js +0 -168
  11. package/dist/cache.d.ts +0 -2
  12. package/dist/cache.js +0 -57
  13. package/dist/checks.d.ts +0 -4
  14. package/dist/checks.js +0 -228
  15. package/dist/command.d.ts +0 -2
  16. package/dist/command.js +0 -147
  17. package/dist/constants.d.ts +0 -4
  18. package/dist/constants.js +0 -53
  19. package/dist/counter-scout.d.ts +0 -21
  20. package/dist/counter-scout.js +0 -167
  21. package/dist/diff.d.ts +0 -1
  22. package/dist/diff.js +0 -10
  23. package/dist/doctor.d.ts +0 -16
  24. package/dist/doctor.js +0 -143
  25. package/dist/git.d.ts +0 -17
  26. package/dist/git.js +0 -368
  27. package/dist/hooks.d.ts +0 -5
  28. package/dist/hooks.js +0 -135
  29. package/dist/index.d.ts +0 -1
  30. package/dist/index.js +0 -1
  31. package/dist/model.d.ts +0 -11
  32. package/dist/model.js +0 -296
  33. package/dist/prompts.d.ts +0 -8
  34. package/dist/prompts.js +0 -89
  35. package/dist/render.d.ts +0 -6
  36. package/dist/render.js +0 -295
  37. package/dist/repomix-provider.d.ts +0 -12
  38. package/dist/repomix-provider.js +0 -196
  39. package/dist/search-bench.d.ts +0 -1
  40. package/dist/search-bench.js +0 -677
  41. package/dist/search-profile.d.ts +0 -6
  42. package/dist/search-profile.js +0 -73
  43. package/dist/sem-provider.d.ts +0 -2
  44. package/dist/sem-provider.js +0 -255
  45. package/dist/stupify.d.ts +0 -38
  46. package/dist/stupify.js +0 -505
  47. package/dist/trace.d.ts +0 -31
  48. package/dist/trace.js +0 -86
  49. package/dist/types.d.ts +0 -341
  50. package/dist/types.js +0 -6
  51. package/dist/ui.d.ts +0 -34
  52. package/dist/ui.js +0 -143
  53. package/src/analysis.ts +0 -223
  54. package/src/cache.ts +0 -63
  55. package/src/checks.ts +0 -231
  56. package/src/command.ts +0 -173
  57. package/src/constants.ts +0 -56
  58. package/src/counter-scout.ts +0 -195
  59. package/src/diff.ts +0 -9
  60. package/src/doctor.ts +0 -166
  61. package/src/git.ts +0 -380
  62. package/src/hooks.ts +0 -151
  63. package/src/index.ts +0 -1
  64. package/src/model.ts +0 -367
  65. package/src/prompts.ts +0 -100
  66. package/src/render.ts +0 -328
  67. package/src/repomix-provider.ts +0 -219
  68. package/src/search-bench.ts +0 -783
  69. package/src/search-profile.ts +0 -89
  70. package/src/sem-provider.ts +0 -300
  71. package/src/stupify.ts +0 -604
  72. package/src/trace.ts +0 -126
  73. package/src/types.ts +0 -362
  74. package/src/ui.ts +0 -187
package/dist/types.d.ts DELETED
@@ -1,341 +0,0 @@
1
- declare const brand: unique symbol;
2
- type Brand<Value, Name extends string> = Value & {
3
- readonly [brand]: Name;
4
- };
5
- export type SourceId = Brand<string, "SourceId">;
6
- export type CheckId = Brand<string, "CheckId">;
7
- export declare function sourceId(value: string): SourceId;
8
- export declare function checkId(value: string): CheckId;
9
- export type SearchMode = "warn" | "off";
10
- export type HookAction = "install" | "uninstall" | "status";
11
- export type SearchSource = "since" | "stdin" | "commit" | "commits" | "staged";
12
- type SearchOptions = Readonly<{
13
- checkIds: readonly string[] | null;
14
- json: boolean;
15
- model: ModelId;
16
- debugSem: boolean;
17
- maxCandidates: number;
18
- maxSearchInputTokens: number;
19
- searchProfilePath: string | null;
20
- includeCounterReasonInPrompt: boolean;
21
- }>;
22
- export type Command = Readonly<{
23
- kind: "help";
24
- }> | Readonly<{
25
- kind: "hook";
26
- action: HookAction;
27
- }> | Readonly<{
28
- kind: "doctor";
29
- }> | Readonly<{
30
- kind: "bench-search";
31
- configPath: string;
32
- }> | (Readonly<{
33
- kind: "since";
34
- since: string;
35
- mode: "search";
36
- source: "since";
37
- }> & SearchOptions) | (Readonly<{
38
- kind: "stdin";
39
- mode: "search";
40
- source: "stdin";
41
- }> & SearchOptions) | (Readonly<{
42
- kind: "commit";
43
- commit: string;
44
- mode: "search";
45
- source: "commit";
46
- }> & SearchOptions) | (Readonly<{
47
- kind: "commits";
48
- count: number;
49
- mode: "search";
50
- source: "commits";
51
- }> & SearchOptions) | (Readonly<{
52
- kind: "staged";
53
- mode: "search";
54
- source: "staged";
55
- }> & SearchOptions);
56
- export type SearchCommand = Exclude<Command, Readonly<{
57
- kind: "help";
58
- }> | Readonly<{
59
- kind: "hook";
60
- action: HookAction;
61
- }> | Readonly<{
62
- kind: "doctor";
63
- }> | Readonly<{
64
- kind: "bench-search";
65
- configPath: string;
66
- }>>;
67
- export type StupifyCheck = Readonly<{
68
- id: CheckId;
69
- name: string;
70
- question: string;
71
- why: string;
72
- lookFor: readonly string[];
73
- ignoreWhen: readonly string[];
74
- enabledByDefault?: boolean;
75
- hookMode?: SearchMode;
76
- searchPrompt?: string;
77
- searchExamples?: Readonly<{
78
- match: readonly string[];
79
- nonMatch: readonly string[];
80
- }>;
81
- examples?: Readonly<{
82
- match?: readonly string[];
83
- noMatch?: readonly string[];
84
- }>;
85
- }>;
86
- export type NetDiffStats = Readonly<{
87
- filesChanged: number;
88
- additions: number;
89
- deletions: number;
90
- }>;
91
- export type StagedDiff = Readonly<{
92
- text: string;
93
- stats: NetDiffStats;
94
- }>;
95
- export type BlameSummary = Readonly<{
96
- commit: string;
97
- author: string;
98
- subject: string;
99
- }>;
100
- export type NetDiff = Readonly<{
101
- id: SourceId;
102
- label: string;
103
- base: string;
104
- target: string;
105
- text: string;
106
- stats: NetDiffStats;
107
- }>;
108
- export type SourceRange = Readonly<{
109
- id: SourceId;
110
- label: string;
111
- base: string;
112
- target: string;
113
- committers?: readonly string[];
114
- commitSubjects?: readonly string[];
115
- stats: NetDiffStats;
116
- }>;
117
- export type SemChange = Readonly<{
118
- entityId: string;
119
- entityName: string;
120
- entityType: string;
121
- filePath: string;
122
- changeType: string;
123
- beforeContent: string | null;
124
- afterContent: string | null;
125
- }>;
126
- export type SemChangeSummary = Readonly<{
127
- added: number;
128
- deleted: number;
129
- modified: number;
130
- moved: number;
131
- renamed: number;
132
- fileCount: number;
133
- total: number;
134
- }>;
135
- export type SemChangeSet = Readonly<{
136
- id: SourceId;
137
- label: string;
138
- base: string;
139
- target: string;
140
- committers?: readonly string[];
141
- commitSubjects?: readonly string[];
142
- contextCwd: string;
143
- cleanup: () => Promise<void>;
144
- changes: readonly SemChange[];
145
- summary: SemChangeSummary;
146
- }>;
147
- export type SemCandidate = Readonly<{
148
- sourceId: SourceId;
149
- targetId: string;
150
- entityId: string;
151
- checkId: CheckId;
152
- reason: string;
153
- }>;
154
- export type SemContext = Readonly<{
155
- targetId: string;
156
- entityId: string;
157
- entityName: string;
158
- entityKind: string;
159
- changeKind: string;
160
- checkId: CheckId;
161
- reason: string;
162
- filePath?: string;
163
- text: string;
164
- }>;
165
- export type SemContextPack = Readonly<{
166
- provider: "repomix";
167
- filePaths: readonly string[];
168
- totalCharacters: number;
169
- totalTokens: number;
170
- text: string;
171
- config: RepomixSearchConfig;
172
- }>;
173
- export type RepomixSearchConfig = Readonly<{
174
- compress: boolean;
175
- showLineNumbers: boolean;
176
- removeEmptyLines: boolean;
177
- maxFileSizeBytes: number;
178
- maxTotalSizeBytes: number;
179
- ignorePatterns: readonly string[];
180
- }>;
181
- export type SearchProfileRepomixConfig = Readonly<{
182
- compress?: boolean;
183
- showLineNumbers?: boolean;
184
- removeEmptyLines?: boolean;
185
- maxFileBytes?: number;
186
- maxTotalBytes?: number;
187
- ignorePatterns?: readonly string[];
188
- }>;
189
- export type SearchProfilePattern = Readonly<{
190
- enabled?: boolean;
191
- searchPrompt?: string;
192
- matchExamples?: readonly string[];
193
- nonMatchExamples?: readonly string[];
194
- }>;
195
- export type SearchProfile = Readonly<{
196
- id: string;
197
- context?: "repomix" | "sem";
198
- maxCandidates?: number;
199
- maxSearchInputTokens?: number;
200
- includeCounterReasonInPrompt?: boolean;
201
- repomix?: SearchProfileRepomixConfig;
202
- patterns?: Readonly<Record<string, SearchProfilePattern>>;
203
- }>;
204
- export type SearchMatch = Readonly<{
205
- targetId: string;
206
- patternId: CheckId;
207
- patternName?: string;
208
- checkWhy?: string;
209
- reason: string;
210
- proof: string;
211
- snapshot?: string;
212
- filePath?: string;
213
- entityName?: string;
214
- entityKind?: string;
215
- blame?: BlameSummary;
216
- }>;
217
- export type SearchRunJson = Readonly<{
218
- schemaVersion: "search.v1";
219
- mode: "search";
220
- source: SearchSource;
221
- model: Readonly<{
222
- id: ModelId;
223
- }>;
224
- patterns: readonly CheckId[];
225
- stats: Readonly<{
226
- elapsedMs: number;
227
- modelCalls: number;
228
- inputTokens?: number;
229
- inputTokenCap?: number;
230
- skipped?: boolean;
231
- skipReason?: "input_too_large" | "no_candidates";
232
- committers?: readonly string[];
233
- commitSubjects?: readonly string[];
234
- filesChanged?: number;
235
- entitiesScanned?: number;
236
- candidates?: number;
237
- repomixFiles?: number;
238
- repomixTokens?: number;
239
- repomixConfig?: RepomixSearchConfig;
240
- searchTargets?: number;
241
- searchBatches?: number;
242
- skippedTargets?: number;
243
- profileId?: string;
244
- targetsByPattern?: Readonly<Record<string, number>>;
245
- targetsPreview?: readonly SearchTargetPreview[];
246
- }>;
247
- matches: readonly SearchMatch[];
248
- }>;
249
- export type SearchTargetPreview = Readonly<{
250
- targetId: string;
251
- patternId: CheckId;
252
- entityKind?: string;
253
- sourceKind?: string;
254
- }>;
255
- export type SearchBenchConfig = Readonly<{
256
- name: string;
257
- profiles: readonly string[];
258
- fixtures: string;
259
- realSmokeRuns?: readonly SearchBenchSmokeRun[];
260
- realCommitReplay?: readonly SearchBenchCommitReplay[];
261
- }>;
262
- export type SearchBenchSmokeRun = Readonly<{
263
- id: string;
264
- cwd?: string;
265
- args: readonly string[];
266
- }>;
267
- export type SearchBenchCommitReplay = Readonly<{
268
- id: string;
269
- repoEnv?: string;
270
- cwd?: string;
271
- limit: number;
272
- since?: string;
273
- nonMerge?: boolean;
274
- profiles: readonly string[];
275
- }>;
276
- export type SearchFixture = Readonly<{
277
- id: string;
278
- description: string;
279
- stagedPatch: string;
280
- checks: readonly string[];
281
- expected: readonly SearchFixtureExpectation[];
282
- }>;
283
- export type SearchFixtureExpectation = Readonly<{
284
- patternId: string;
285
- shouldMatch: boolean;
286
- }>;
287
- export type SearchBenchRun = Readonly<{
288
- profileId: string;
289
- fixtureId?: string;
290
- smokeId?: string;
291
- elapsedMs: number;
292
- modelCalls: number;
293
- patterns: readonly CheckId[];
294
- targets: number;
295
- targetsByPattern: Readonly<Record<string, number>>;
296
- inputTokens: number;
297
- repomixPackedTokens?: number;
298
- skipped: boolean;
299
- skipReason?: string;
300
- matches: readonly SearchMatch[];
301
- expected?: readonly SearchFixtureExpectation[];
302
- score?: number;
303
- targetsPreview: readonly SearchTargetPreview[];
304
- matchesUsingCounterReasonAsProof: number;
305
- error?: string;
306
- }>;
307
- export type SearchBenchReplayRun = Readonly<{
308
- profileId: string;
309
- replayId: string;
310
- commitId: string;
311
- outcome: SearchReplayOutcome;
312
- changedFiles: number;
313
- addedLines: number;
314
- deletedLines: number;
315
- elapsedMs: number;
316
- skipped: boolean;
317
- skipReason?: string;
318
- targets: number;
319
- inputTokens: number;
320
- repomixPackedTokens?: number;
321
- modelCalls: number;
322
- matches: readonly SearchMatch[];
323
- matchesByPattern: Readonly<Record<string, number>>;
324
- error?: string;
325
- }>;
326
- export type SearchReplayOutcome = "no_candidates" | "ran_no_matches" | "ran_with_matches" | "skipped_input_too_large" | "error";
327
- export type ModelId = "gemma-4-e2b" | "gemma-4-e4b" | "gemma-4-26b-a4b" | "qwen3-4b-magicquant" | "qwen2.5-coder-1.5b" | "qwen2.5-coder-7b" | "qwen2.5-coder-32b";
328
- export type ModelConfig = Readonly<{
329
- id: ModelId;
330
- name: string;
331
- file: string;
332
- url: string;
333
- size: string;
334
- }>;
335
- export type TraceEvent = Readonly<{
336
- name: string;
337
- ms: number;
338
- count?: number;
339
- detail?: string;
340
- }>;
341
- export {};
package/dist/types.js DELETED
@@ -1,6 +0,0 @@
1
- export function sourceId(value) {
2
- return value;
3
- }
4
- export function checkId(value) {
5
- return value;
6
- }
package/dist/ui.d.ts DELETED
@@ -1,34 +0,0 @@
1
- import { type SpinnerResult } from "@clack/prompts";
2
- export type CliUi = ReturnType<typeof createCliUi>;
3
- export type CliUiOptions = Readonly<{
4
- quiet?: boolean;
5
- }>;
6
- type LogOptions = Readonly<{
7
- force?: boolean;
8
- }>;
9
- export declare function createCliUi(options?: CliUiOptions): {
10
- intro(title: string, logOptions?: LogOptions): void;
11
- outro(message: string, logOptions?: LogOptions): void;
12
- note(message: string, title?: string, logOptions?: LogOptions): void;
13
- info(message: string, logOptions?: LogOptions): void;
14
- step(message: string, logOptions?: LogOptions): void;
15
- success(message: string, logOptions?: LogOptions): void;
16
- warn(message: string, logOptions?: LogOptions): void;
17
- error(message: string, logOptions?: LogOptions): void;
18
- debug(message: string): void;
19
- confirm(message: string): Promise<boolean>;
20
- spinner(message: string, logOptions?: LogOptions): SpinnerResult;
21
- progress(message: string, max: number, logOptions?: LogOptions): import("@clack/prompts").ProgressResult;
22
- writeStdout(text: string): void;
23
- };
24
- export declare const format: {
25
- heading: (value: string) => string;
26
- label: (value: string) => string;
27
- muted: (value: string) => string;
28
- success: (value: string) => string;
29
- warn: (value: string) => string;
30
- error: (value: string) => string;
31
- };
32
- export declare function diagnostic(message: string): void;
33
- export declare function diagnosticError(message: string): void;
34
- export {};
package/dist/ui.js DELETED
@@ -1,143 +0,0 @@
1
- import { confirm as clackConfirm, intro as clackIntro, isCancel, log, note, outro as clackOutro, progress, spinner, } from "@clack/prompts";
2
- import { createReadStream, createWriteStream } from "node:fs";
3
- import { platform } from "node:os";
4
- import { stdin, stderr, stdout } from "node:process";
5
- import pc from "picocolors";
6
- export function createCliUi(options = {}) {
7
- const quiet = options.quiet ?? false;
8
- const output = stderr;
9
- function shouldWrite(logOptions) {
10
- return logOptions?.force === true || !quiet;
11
- }
12
- function withPromptIo(run) {
13
- const io = promptIo();
14
- return run(io).finally(() => io.close());
15
- }
16
- return {
17
- intro(title, logOptions) {
18
- if (shouldWrite(logOptions))
19
- clackIntro(title, { output });
20
- },
21
- outro(message, logOptions) {
22
- if (shouldWrite(logOptions))
23
- clackOutro(message, { output });
24
- },
25
- note(message, title, logOptions) {
26
- if (shouldWrite(logOptions))
27
- note(message, title, { output });
28
- },
29
- info(message, logOptions) {
30
- if (shouldWrite(logOptions))
31
- log.info(message, { output });
32
- },
33
- step(message, logOptions) {
34
- if (shouldWrite(logOptions))
35
- log.step(message, { output });
36
- },
37
- success(message, logOptions) {
38
- if (shouldWrite(logOptions))
39
- log.success(message, { output });
40
- },
41
- warn(message, logOptions) {
42
- if (shouldWrite(logOptions))
43
- log.warn(message, { output });
44
- },
45
- error(message, logOptions) {
46
- if (shouldWrite(logOptions))
47
- log.error(message, { output });
48
- },
49
- debug(message) {
50
- if (!quiet)
51
- log.message(message, { output, symbol: pc.dim("trace") });
52
- },
53
- async confirm(message) {
54
- return withPromptIo(async (io) => {
55
- const result = await clackConfirm({
56
- message,
57
- active: "Yes",
58
- inactive: "No",
59
- initialValue: false,
60
- input: io.input,
61
- output: io.output,
62
- });
63
- if (isCancel(result))
64
- return false;
65
- return result;
66
- });
67
- },
68
- spinner(message, logOptions) {
69
- if (!shouldWrite(logOptions))
70
- return silentSpinner();
71
- const active = spinner({ output });
72
- active.start(message);
73
- return active;
74
- },
75
- progress(message, max, logOptions) {
76
- if (!shouldWrite(logOptions))
77
- return silentProgress();
78
- const active = progress({ output, max });
79
- active.start(message);
80
- return active;
81
- },
82
- writeStdout(text) {
83
- stdout.write(text.endsWith("\n") ? text : `${text}\n`);
84
- },
85
- };
86
- }
87
- export const format = {
88
- heading: (value) => pc.bold(value),
89
- label: (value) => pc.cyan(value),
90
- muted: (value) => pc.dim(value),
91
- success: (value) => pc.green(value),
92
- warn: (value) => pc.yellow(value),
93
- error: (value) => pc.red(value),
94
- };
95
- export function diagnostic(message) {
96
- log.message(message, {
97
- output: stderr,
98
- symbol: pc.dim("·"),
99
- spacing: 0,
100
- withGuide: false,
101
- });
102
- }
103
- export function diagnosticError(message) {
104
- log.error(message, { output: stderr, spacing: 0, withGuide: false });
105
- }
106
- function promptIo() {
107
- if (stdin.isTTY && stderr.isTTY) {
108
- return { input: stdin, output: stderr, close: () => undefined };
109
- }
110
- if (platform() === "win32") {
111
- throw new Error("No interactive terminal found. Run `stupify` once in an interactive terminal to set up the model.");
112
- }
113
- const input = createReadStream("/dev/tty");
114
- const output = createWriteStream("/dev/tty");
115
- return {
116
- input,
117
- output,
118
- close: () => closePromptIo(input, output),
119
- };
120
- }
121
- function closePromptIo(input, output) {
122
- input.destroy();
123
- output.end();
124
- }
125
- function silentSpinner() {
126
- return {
127
- start: () => undefined,
128
- stop: () => undefined,
129
- cancel: () => undefined,
130
- error: () => undefined,
131
- message: () => undefined,
132
- clear: () => undefined,
133
- get isCancelled() {
134
- return false;
135
- },
136
- };
137
- }
138
- function silentProgress() {
139
- return {
140
- ...silentSpinner(),
141
- advance: () => undefined,
142
- };
143
- }