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