@stupify/cli 0.0.10 → 0.0.12
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/dist/analysis.js +27 -0
- package/dist/constants.d.ts +1 -1
- package/dist/constants.js +1 -1
- package/dist/render.js +51 -12
- package/dist/types.d.ts +1 -0
- package/package.json +1 -1
- package/src/analysis.ts +26 -0
- package/src/constants.ts +1 -1
- package/src/render.ts +55 -12
- package/src/types.ts +1 -0
package/dist/analysis.js
CHANGED
|
@@ -73,6 +73,7 @@ function uncheckedSearchMatches(value, contexts) {
|
|
|
73
73
|
patternId: context.checkId,
|
|
74
74
|
reason: match.reason ?? "",
|
|
75
75
|
proof: sourcePointer(context),
|
|
76
|
+
snapshot: sourceSnapshot(context),
|
|
76
77
|
}];
|
|
77
78
|
});
|
|
78
79
|
}
|
|
@@ -80,6 +81,32 @@ function sourcePointer(context) {
|
|
|
80
81
|
const file = context.filePath ?? "(unknown)";
|
|
81
82
|
return `${file}::${context.entityKind || "entity"}::${context.entityName || context.entityId}`;
|
|
82
83
|
}
|
|
84
|
+
function sourceSnapshot(context) {
|
|
85
|
+
try {
|
|
86
|
+
const parsed = JSON.parse(context.text);
|
|
87
|
+
const snapshot = stringSnapshot(parsed.after) ?? stringSnapshot(parsed.before);
|
|
88
|
+
return snapshot ? limitSnapshot(snapshot) : undefined;
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function stringSnapshot(value) {
|
|
95
|
+
if (typeof value !== "string")
|
|
96
|
+
return undefined;
|
|
97
|
+
const trimmed = value.trim();
|
|
98
|
+
if (!trimmed || trimmed === "(none)")
|
|
99
|
+
return undefined;
|
|
100
|
+
return trimmed;
|
|
101
|
+
}
|
|
102
|
+
function limitSnapshot(value) {
|
|
103
|
+
const lines = value.split(/\r?\n/);
|
|
104
|
+
const limit = 12;
|
|
105
|
+
if (lines.length <= limit)
|
|
106
|
+
return value;
|
|
107
|
+
return `${lines.slice(0, limit).join("\n")}
|
|
108
|
+
[stupify: snapshot shortened after ${limit} lines]`;
|
|
109
|
+
}
|
|
83
110
|
async function runJsonPrompt(model, prompt, schema, temperature) {
|
|
84
111
|
return cachedJson("model-json", fingerprint({
|
|
85
112
|
version: 1,
|
package/dist/constants.d.ts
CHANGED
package/dist/constants.js
CHANGED
package/dist/render.js
CHANGED
|
@@ -24,14 +24,19 @@ ${format.success("No search targets found.")}`;
|
|
|
24
24
|
${format.label("Patterns:")} ${run.patterns.join(", ")}
|
|
25
25
|
${format.success("No judgment-offload signals found.")}`;
|
|
26
26
|
}
|
|
27
|
-
return `${
|
|
28
|
-
${run
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
${
|
|
27
|
+
return `${slopHeading()}
|
|
28
|
+
${committerLabel(run)} (${sourceLabel(command)})
|
|
29
|
+
|
|
30
|
+
${run.matches.map((match, index) => `${index + 1}. ${format.label(match.patternId)}
|
|
31
|
+
${match.reason}
|
|
32
|
+
|
|
33
|
+
\`\`\`
|
|
34
|
+
${match.snapshot ?? match.proof}
|
|
35
|
+
\`\`\`
|
|
36
|
+
${format.muted(match.proof)}
|
|
37
|
+
|
|
38
|
+
${match.checkWhy ?? "This pattern may indicate judgment-offload."}`).join("\n\n")}
|
|
39
|
+
${format.muted(summaryLine(run))}`;
|
|
35
40
|
}
|
|
36
41
|
export function helpText() {
|
|
37
42
|
return `Stupify ${VERSION}
|
|
@@ -93,20 +98,54 @@ function sourceHint(command) {
|
|
|
93
98
|
}
|
|
94
99
|
function sourceLabel(command) {
|
|
95
100
|
if (command.kind === "staged")
|
|
96
|
-
return "staged
|
|
101
|
+
return "staged";
|
|
97
102
|
if (command.kind === "since")
|
|
98
|
-
return
|
|
103
|
+
return sinceLabel(command.since);
|
|
99
104
|
if (command.kind === "commit")
|
|
100
105
|
return `commit ${command.commit}`;
|
|
101
106
|
if (command.kind === "commits")
|
|
102
107
|
return `last ${command.count} commits`;
|
|
103
|
-
return "stdin
|
|
108
|
+
return "stdin";
|
|
104
109
|
}
|
|
105
110
|
function committerLabel(run) {
|
|
106
|
-
const committers = (run.stats.committers ?? []).
|
|
111
|
+
const committers = humanCommitters(run.stats.committers ?? []).map(committerDisplayName);
|
|
107
112
|
if (committers.length === 0)
|
|
108
113
|
return "unknown committer";
|
|
109
114
|
if (committers.length <= 3)
|
|
110
115
|
return committers.join(", ");
|
|
111
116
|
return `${committers.slice(0, 3).join(", ")} +${committers.length - 3} more`;
|
|
112
117
|
}
|
|
118
|
+
function humanCommitters(committers) {
|
|
119
|
+
const nonEmpty = committers.filter(Boolean);
|
|
120
|
+
const humans = nonEmpty.filter((committer) => !isBotCommitter(committer));
|
|
121
|
+
return humans.length > 0 ? humans : nonEmpty;
|
|
122
|
+
}
|
|
123
|
+
function isBotCommitter(value) {
|
|
124
|
+
return /(?:^|<)(?:github|dependabot|renovate)(?:\s|@|>)/i.test(value) ||
|
|
125
|
+
/(?:noreply@github\.com|bot@)/i.test(value);
|
|
126
|
+
}
|
|
127
|
+
function committerDisplayName(value) {
|
|
128
|
+
return value.replace(/\s*<[^>]+>\s*$/, "").trim() || value;
|
|
129
|
+
}
|
|
130
|
+
function slopHeading() {
|
|
131
|
+
const heading = "AI SLOP DETECTED";
|
|
132
|
+
return `${format.warn(format.heading(heading))}
|
|
133
|
+
${format.warn("=".repeat(heading.length))}`;
|
|
134
|
+
}
|
|
135
|
+
function sinceLabel(since) {
|
|
136
|
+
const value = since.trim().toLowerCase();
|
|
137
|
+
if (value === "yesterday" || value === "1 day ago")
|
|
138
|
+
return "yesterday";
|
|
139
|
+
const match = /^(\d+)\s+(day|week|month|year)s?\s+ago$/.exec(value);
|
|
140
|
+
if (!match)
|
|
141
|
+
return `since ${since}`;
|
|
142
|
+
const count = Number(match[1]);
|
|
143
|
+
const unit = match[2];
|
|
144
|
+
if (count === 1)
|
|
145
|
+
return `last ${unit}`;
|
|
146
|
+
return `last ${count} ${unit}s`;
|
|
147
|
+
}
|
|
148
|
+
function summaryLine(run) {
|
|
149
|
+
const noun = run.matches.length === 1 ? "signal" : "signals";
|
|
150
|
+
return `${run.matches.length} ${noun}. Warn-only. Nothing blocked.`;
|
|
151
|
+
}
|
package/dist/types.d.ts
CHANGED
package/package.json
CHANGED
package/src/analysis.ts
CHANGED
|
@@ -106,6 +106,7 @@ function uncheckedSearchMatches(value: unknown, contexts: readonly SemContext[])
|
|
|
106
106
|
patternId: context.checkId,
|
|
107
107
|
reason: match.reason ?? "",
|
|
108
108
|
proof: sourcePointer(context),
|
|
109
|
+
snapshot: sourceSnapshot(context),
|
|
109
110
|
}];
|
|
110
111
|
});
|
|
111
112
|
}
|
|
@@ -115,6 +116,31 @@ function sourcePointer(context: SemContext): string {
|
|
|
115
116
|
return `${file}::${context.entityKind || "entity"}::${context.entityName || context.entityId}`;
|
|
116
117
|
}
|
|
117
118
|
|
|
119
|
+
function sourceSnapshot(context: SemContext): string | undefined {
|
|
120
|
+
try {
|
|
121
|
+
const parsed = JSON.parse(context.text) as { after?: unknown; before?: unknown };
|
|
122
|
+
const snapshot = stringSnapshot(parsed.after) ?? stringSnapshot(parsed.before);
|
|
123
|
+
return snapshot ? limitSnapshot(snapshot) : undefined;
|
|
124
|
+
} catch {
|
|
125
|
+
return undefined;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function stringSnapshot(value: unknown): string | undefined {
|
|
130
|
+
if (typeof value !== "string") return undefined;
|
|
131
|
+
const trimmed = value.trim();
|
|
132
|
+
if (!trimmed || trimmed === "(none)") return undefined;
|
|
133
|
+
return trimmed;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function limitSnapshot(value: string): string {
|
|
137
|
+
const lines = value.split(/\r?\n/);
|
|
138
|
+
const limit = 12;
|
|
139
|
+
if (lines.length <= limit) return value;
|
|
140
|
+
return `${lines.slice(0, limit).join("\n")}
|
|
141
|
+
[stupify: snapshot shortened after ${limit} lines]`;
|
|
142
|
+
}
|
|
143
|
+
|
|
118
144
|
async function runJsonPrompt(
|
|
119
145
|
model: LocalModel,
|
|
120
146
|
prompt: string,
|
package/src/constants.ts
CHANGED
package/src/render.ts
CHANGED
|
@@ -29,14 +29,19 @@ ${format.label("Patterns:")} ${run.patterns.join(", ")}
|
|
|
29
29
|
${format.success("No judgment-offload signals found.")}`;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
return `${
|
|
33
|
-
${run
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
${
|
|
32
|
+
return `${slopHeading()}
|
|
33
|
+
${committerLabel(run)} (${sourceLabel(command)})
|
|
34
|
+
|
|
35
|
+
${run.matches.map((match, index) => `${index + 1}. ${format.label(match.patternId)}
|
|
36
|
+
${match.reason}
|
|
37
|
+
|
|
38
|
+
\`\`\`
|
|
39
|
+
${match.snapshot ?? match.proof}
|
|
40
|
+
\`\`\`
|
|
41
|
+
${format.muted(match.proof)}
|
|
42
|
+
|
|
43
|
+
${match.checkWhy ?? "This pattern may indicate judgment-offload."}`).join("\n\n")}
|
|
44
|
+
${format.muted(summaryLine(run))}`;
|
|
40
45
|
}
|
|
41
46
|
|
|
42
47
|
export function helpText(): string {
|
|
@@ -96,16 +101,54 @@ function sourceHint(command: SearchCommand): string {
|
|
|
96
101
|
}
|
|
97
102
|
|
|
98
103
|
function sourceLabel(command: SearchCommand): string {
|
|
99
|
-
if (command.kind === "staged") return "staged
|
|
100
|
-
if (command.kind === "since") return
|
|
104
|
+
if (command.kind === "staged") return "staged";
|
|
105
|
+
if (command.kind === "since") return sinceLabel(command.since);
|
|
101
106
|
if (command.kind === "commit") return `commit ${command.commit}`;
|
|
102
107
|
if (command.kind === "commits") return `last ${command.count} commits`;
|
|
103
|
-
return "stdin
|
|
108
|
+
return "stdin";
|
|
104
109
|
}
|
|
105
110
|
|
|
106
111
|
function committerLabel(run: SearchRunJson): string {
|
|
107
|
-
const committers = (run.stats.committers ?? []).
|
|
112
|
+
const committers = humanCommitters(run.stats.committers ?? []).map(committerDisplayName);
|
|
108
113
|
if (committers.length === 0) return "unknown committer";
|
|
109
114
|
if (committers.length <= 3) return committers.join(", ");
|
|
110
115
|
return `${committers.slice(0, 3).join(", ")} +${committers.length - 3} more`;
|
|
111
116
|
}
|
|
117
|
+
|
|
118
|
+
function humanCommitters(committers: readonly string[]): readonly string[] {
|
|
119
|
+
const nonEmpty = committers.filter(Boolean);
|
|
120
|
+
const humans = nonEmpty.filter((committer) => !isBotCommitter(committer));
|
|
121
|
+
return humans.length > 0 ? humans : nonEmpty;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function isBotCommitter(value: string): boolean {
|
|
125
|
+
return /(?:^|<)(?:github|dependabot|renovate)(?:\s|@|>)/i.test(value) ||
|
|
126
|
+
/(?:noreply@github\.com|bot@)/i.test(value);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function committerDisplayName(value: string): string {
|
|
130
|
+
return value.replace(/\s*<[^>]+>\s*$/, "").trim() || value;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function slopHeading(): string {
|
|
134
|
+
const heading = "AI SLOP DETECTED";
|
|
135
|
+
return `${format.warn(format.heading(heading))}
|
|
136
|
+
${format.warn("=".repeat(heading.length))}`;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function sinceLabel(since: string): string {
|
|
140
|
+
const value = since.trim().toLowerCase();
|
|
141
|
+
if (value === "yesterday" || value === "1 day ago") return "yesterday";
|
|
142
|
+
const match = /^(\d+)\s+(day|week|month|year)s?\s+ago$/.exec(value);
|
|
143
|
+
if (!match) return `since ${since}`;
|
|
144
|
+
|
|
145
|
+
const count = Number(match[1]);
|
|
146
|
+
const unit = match[2];
|
|
147
|
+
if (count === 1) return `last ${unit}`;
|
|
148
|
+
return `last ${count} ${unit}s`;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function summaryLine(run: SearchRunJson): string {
|
|
152
|
+
const noun = run.matches.length === 1 ? "signal" : "signals";
|
|
153
|
+
return `${run.matches.length} ${noun}. Warn-only. Nothing blocked.`;
|
|
154
|
+
}
|