@stupify/cli 0.0.8 → 0.0.9
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/constants.d.ts +1 -1
- package/dist/constants.js +1 -1
- package/dist/git.d.ts +1 -0
- package/dist/git.js +44 -1
- package/dist/render.js +26 -5
- package/dist/sem-provider.js +11 -7
- package/dist/stupify.js +4 -0
- package/dist/types.d.ts +3 -0
- package/package.json +1 -1
- package/src/constants.ts +1 -1
- package/src/git.ts +44 -1
- package/src/render.ts +22 -5
- package/src/sem-provider.ts +25 -11
- package/src/stupify.ts +4 -0
- package/src/types.ts +3 -0
package/dist/constants.d.ts
CHANGED
package/dist/constants.js
CHANGED
package/dist/git.d.ts
CHANGED
|
@@ -9,3 +9,4 @@ export declare function netDiffFromStdin(text: string): Promise<NetDiff>;
|
|
|
9
9
|
export declare function stagedDiff(): Promise<StagedDiff>;
|
|
10
10
|
export declare function gitRoot(): Promise<string>;
|
|
11
11
|
export declare function gitPath(pathspec: string): Promise<string>;
|
|
12
|
+
export declare function gitUserLabel(): Promise<string>;
|
package/dist/git.js
CHANGED
|
@@ -87,6 +87,15 @@ export async function gitPath(pathspec) {
|
|
|
87
87
|
throw new Error(`Could not resolve git path: ${pathspec}`);
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
|
+
export async function gitUserLabel() {
|
|
91
|
+
const [name, email] = await Promise.all([
|
|
92
|
+
gitConfig("user.name"),
|
|
93
|
+
gitConfig("user.email"),
|
|
94
|
+
]);
|
|
95
|
+
if (name && email)
|
|
96
|
+
return `${name} <${email}>`;
|
|
97
|
+
return name || email || "working tree";
|
|
98
|
+
}
|
|
90
99
|
async function netDiff(base, target, label, id) {
|
|
91
100
|
const [text, stats, shortBase, shortTarget] = await Promise.all([
|
|
92
101
|
diff(base, target),
|
|
@@ -104,19 +113,53 @@ async function netDiff(base, target, label, id) {
|
|
|
104
113
|
};
|
|
105
114
|
}
|
|
106
115
|
async function sourceRange(base, target, label, id) {
|
|
107
|
-
const [stats, shortBase, shortTarget] = await Promise.all([
|
|
116
|
+
const [stats, shortBase, shortTarget, committers] = await Promise.all([
|
|
108
117
|
diffStats(base, target),
|
|
109
118
|
shortCommit(base),
|
|
110
119
|
shortCommit(target),
|
|
120
|
+
committersForRange(base, target),
|
|
111
121
|
]);
|
|
112
122
|
return {
|
|
113
123
|
id: id ?? sourceId(`net:${shortBase}..${shortTarget}`),
|
|
114
124
|
label,
|
|
115
125
|
base,
|
|
116
126
|
target,
|
|
127
|
+
committers,
|
|
117
128
|
stats,
|
|
118
129
|
};
|
|
119
130
|
}
|
|
131
|
+
async function gitConfig(key) {
|
|
132
|
+
try {
|
|
133
|
+
const { stdout } = await execFileAsync("git", ["config", "--get", key]);
|
|
134
|
+
return stdout.trim();
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
return "";
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
async function committersForRange(base, target) {
|
|
141
|
+
try {
|
|
142
|
+
const { stdout } = await execFileAsync("git", ["log", "--format=%cn <%ce>", `${base}..${target}`], {
|
|
143
|
+
maxBuffer: 4 * 1024 * 1024,
|
|
144
|
+
});
|
|
145
|
+
return uniqueLines(stdout);
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
return [];
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
function uniqueLines(value) {
|
|
152
|
+
const seen = new Set();
|
|
153
|
+
const lines = [];
|
|
154
|
+
for (const line of value.split(/\r?\n/)) {
|
|
155
|
+
const trimmed = line.trim();
|
|
156
|
+
if (!trimmed || seen.has(trimmed))
|
|
157
|
+
continue;
|
|
158
|
+
seen.add(trimmed);
|
|
159
|
+
lines.push(trimmed);
|
|
160
|
+
}
|
|
161
|
+
return lines;
|
|
162
|
+
}
|
|
120
163
|
async function baseBefore(since) {
|
|
121
164
|
try {
|
|
122
165
|
const { stdout } = await execFileAsync("git", [
|
package/dist/render.js
CHANGED
|
@@ -27,11 +27,13 @@ Patterns: ${run.patterns.join(", ")}
|
|
|
27
27
|
No judgment-offload signals found.`;
|
|
28
28
|
}
|
|
29
29
|
return `🧙 stupify 🪄
|
|
30
|
-
|
|
31
|
-
${run.matches.map((match, index) => `${index + 1}.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
AI SLOP DETECTED
|
|
31
|
+
${run.matches.map((match, index) => `${index + 1}.
|
|
32
|
+
who: ${committerLabel(run)}
|
|
33
|
+
what: ${match.patternId} - ${match.reason}
|
|
34
|
+
when: ${sourceLabel(command)}
|
|
35
|
+
where: ${match.proof}
|
|
36
|
+
why: ${match.checkWhy ?? "This pattern may indicate judgment-offload."}`).join("\n")}
|
|
35
37
|
Search mode is warn-only.`;
|
|
36
38
|
}
|
|
37
39
|
export function helpText() {
|
|
@@ -92,3 +94,22 @@ function sourceHint(command) {
|
|
|
92
94
|
return `--commits ${command.count}`;
|
|
93
95
|
return "--stdin";
|
|
94
96
|
}
|
|
97
|
+
function sourceLabel(command) {
|
|
98
|
+
if (command.kind === "staged")
|
|
99
|
+
return "staged changes";
|
|
100
|
+
if (command.kind === "since")
|
|
101
|
+
return `since ${command.since}`;
|
|
102
|
+
if (command.kind === "commit")
|
|
103
|
+
return `commit ${command.commit}`;
|
|
104
|
+
if (command.kind === "commits")
|
|
105
|
+
return `last ${command.count} commits`;
|
|
106
|
+
return "stdin diff";
|
|
107
|
+
}
|
|
108
|
+
function committerLabel(run) {
|
|
109
|
+
const committers = (run.stats.committers ?? []).filter(Boolean);
|
|
110
|
+
if (committers.length === 0)
|
|
111
|
+
return "unknown committer";
|
|
112
|
+
if (committers.length <= 3)
|
|
113
|
+
return committers.join(", ");
|
|
114
|
+
return `${committers.slice(0, 3).join(", ")} +${committers.length - 3} more`;
|
|
115
|
+
}
|
package/dist/sem-provider.js
CHANGED
|
@@ -6,17 +6,18 @@ import path from "node:path";
|
|
|
6
6
|
import { promisify } from "node:util";
|
|
7
7
|
import { cachedJson, fingerprint } from "./cache.js";
|
|
8
8
|
import { readDiffFromStdin } from "./diff.js";
|
|
9
|
-
import { sourceRangeForCommit, sourceRangeForRecentCommits, sourceRangeSince, stagedDiff, } from "./git.js";
|
|
9
|
+
import { gitUserLabel, sourceRangeForCommit, sourceRangeForRecentCommits, sourceRangeSince, stagedDiff, } from "./git.js";
|
|
10
10
|
import { sourceId } from "./types.js";
|
|
11
11
|
const execFileAsync = promisify(execFile);
|
|
12
12
|
export async function semChangeSetForCommand(command) {
|
|
13
13
|
if (command.kind === "stdin")
|
|
14
|
-
return semChangeSetFromPatch(await readDiffFromStdin(), command.debugSem);
|
|
14
|
+
return semChangeSetFromPatch(await readDiffFromStdin(), command.debugSem, "stdin", ["stdin"]);
|
|
15
15
|
if (command.kind === "staged") {
|
|
16
|
-
const diff = await stagedDiff();
|
|
16
|
+
const [diff, committer] = await Promise.all([stagedDiff(), gitUserLabel()]);
|
|
17
|
+
const committers = [committer];
|
|
17
18
|
if (!diff.text.trim())
|
|
18
|
-
return emptyChangeSet("staged", diff.stats);
|
|
19
|
-
return semChangeSetFromPatch(diff.text, command.debugSem, "staged");
|
|
19
|
+
return emptyChangeSet("staged", diff.stats, committers);
|
|
20
|
+
return semChangeSetFromPatch(diff.text, command.debugSem, "staged", committers);
|
|
20
21
|
}
|
|
21
22
|
if (command.kind === "commit") {
|
|
22
23
|
const range = await sourceRangeForCommit(command.commit);
|
|
@@ -27,12 +28,13 @@ export async function semChangeSetForCommand(command) {
|
|
|
27
28
|
const raw = await cachedSemDiff(["diff", "--from", range.base, "--to", range.target, "--format", "json"], range, command.debugSem);
|
|
28
29
|
return withContextWorkspace(normalizeSemDiff(raw, range), command.debugSem);
|
|
29
30
|
}
|
|
30
|
-
function emptyChangeSet(label, stats) {
|
|
31
|
+
function emptyChangeSet(label, stats, committers) {
|
|
31
32
|
return {
|
|
32
33
|
id: sourceId(label),
|
|
33
34
|
label,
|
|
34
35
|
base: label,
|
|
35
36
|
target: label,
|
|
37
|
+
committers,
|
|
36
38
|
contextCwd: process.cwd(),
|
|
37
39
|
cleanup: async () => undefined,
|
|
38
40
|
changes: [],
|
|
@@ -56,7 +58,7 @@ async function semRangeForCommand(command) {
|
|
|
56
58
|
return sourceRangeForRecentCommits(command.count);
|
|
57
59
|
throw new Error("sem cannot resolve stdin as a git range.");
|
|
58
60
|
}
|
|
59
|
-
async function semChangeSetFromPatch(patch, debugSem, label = "stdin") {
|
|
61
|
+
async function semChangeSetFromPatch(patch, debugSem, label = "stdin", committers) {
|
|
60
62
|
if (!patch.trim())
|
|
61
63
|
throw new Error("No diff received on stdin.");
|
|
62
64
|
const raw = await cachedJson("sem-diff", fingerprint({
|
|
@@ -71,6 +73,7 @@ async function semChangeSetFromPatch(patch, debugSem, label = "stdin") {
|
|
|
71
73
|
label,
|
|
72
74
|
base: label,
|
|
73
75
|
target: label,
|
|
76
|
+
committers,
|
|
74
77
|
stats: { filesChanged: 0, additions: 0, deletions: 0 },
|
|
75
78
|
}),
|
|
76
79
|
contextCwd: process.cwd(),
|
|
@@ -194,6 +197,7 @@ function normalizeSemDiff(value, range) {
|
|
|
194
197
|
label: range.label,
|
|
195
198
|
base: range.base,
|
|
196
199
|
target: range.target,
|
|
200
|
+
committers: range.committers,
|
|
197
201
|
contextCwd: process.cwd(),
|
|
198
202
|
cleanup: async () => undefined,
|
|
199
203
|
changes,
|
package/dist/stupify.js
CHANGED
|
@@ -78,6 +78,7 @@ export async function runSearchCommand(command, startedAt) {
|
|
|
78
78
|
stats: {
|
|
79
79
|
elapsedMs: Date.now() - startedAt,
|
|
80
80
|
modelCalls: 0,
|
|
81
|
+
committers: changeSet.committers,
|
|
81
82
|
skipped: true,
|
|
82
83
|
skipReason: "no_candidates",
|
|
83
84
|
filesChanged: changeSet.summary.fileCount,
|
|
@@ -114,6 +115,7 @@ export async function runSearchCommand(command, startedAt) {
|
|
|
114
115
|
stats: {
|
|
115
116
|
elapsedMs: Date.now() - startedAt,
|
|
116
117
|
modelCalls: 0,
|
|
118
|
+
committers: changeSet.committers,
|
|
117
119
|
skipped: true,
|
|
118
120
|
skipReason: "no_candidates",
|
|
119
121
|
filesChanged: changeSet.summary.fileCount,
|
|
@@ -156,6 +158,7 @@ export async function runSearchCommand(command, startedAt) {
|
|
|
156
158
|
modelCalls: 0,
|
|
157
159
|
inputTokens: batches.estimatedInputTokens,
|
|
158
160
|
inputTokenCap: maxSearchInputTokens,
|
|
161
|
+
committers: changeSet.committers,
|
|
159
162
|
skipped: true,
|
|
160
163
|
skipReason: "input_too_large",
|
|
161
164
|
filesChanged: changeSet.summary.fileCount,
|
|
@@ -212,6 +215,7 @@ export async function runSearchCommand(command, startedAt) {
|
|
|
212
215
|
modelCalls,
|
|
213
216
|
inputTokens,
|
|
214
217
|
inputTokenCap: maxSearchInputTokens,
|
|
218
|
+
committers: changeSet.committers,
|
|
215
219
|
filesChanged: changeSet.summary.fileCount,
|
|
216
220
|
entitiesScanned: changeSet.summary.total,
|
|
217
221
|
candidates: contexts.length,
|
package/dist/types.d.ts
CHANGED
|
@@ -105,6 +105,7 @@ export type SourceRange = Readonly<{
|
|
|
105
105
|
label: string;
|
|
106
106
|
base: string;
|
|
107
107
|
target: string;
|
|
108
|
+
committers?: readonly string[];
|
|
108
109
|
stats: NetDiffStats;
|
|
109
110
|
}>;
|
|
110
111
|
export type SemChange = Readonly<{
|
|
@@ -130,6 +131,7 @@ export type SemChangeSet = Readonly<{
|
|
|
130
131
|
label: string;
|
|
131
132
|
base: string;
|
|
132
133
|
target: string;
|
|
134
|
+
committers?: readonly string[];
|
|
133
135
|
contextCwd: string;
|
|
134
136
|
cleanup: () => Promise<void>;
|
|
135
137
|
changes: readonly SemChange[];
|
|
@@ -214,6 +216,7 @@ export type SearchRunJson = Readonly<{
|
|
|
214
216
|
inputTokenCap?: number;
|
|
215
217
|
skipped?: boolean;
|
|
216
218
|
skipReason?: "input_too_large" | "no_candidates";
|
|
219
|
+
committers?: readonly string[];
|
|
217
220
|
filesChanged?: number;
|
|
218
221
|
entitiesScanned?: number;
|
|
219
222
|
candidates?: number;
|
package/package.json
CHANGED
package/src/constants.ts
CHANGED
package/src/git.ts
CHANGED
|
@@ -96,6 +96,15 @@ export async function gitPath(pathspec: string): Promise<string> {
|
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
+
export async function gitUserLabel(): Promise<string> {
|
|
100
|
+
const [name, email] = await Promise.all([
|
|
101
|
+
gitConfig("user.name"),
|
|
102
|
+
gitConfig("user.email"),
|
|
103
|
+
]);
|
|
104
|
+
if (name && email) return `${name} <${email}>`;
|
|
105
|
+
return name || email || "working tree";
|
|
106
|
+
}
|
|
107
|
+
|
|
99
108
|
async function netDiff(base: string, target: string, label: string, id?: NetDiff["id"]): Promise<NetDiff> {
|
|
100
109
|
const [text, stats, shortBase, shortTarget] = await Promise.all([
|
|
101
110
|
diff(base, target),
|
|
@@ -114,20 +123,54 @@ async function netDiff(base: string, target: string, label: string, id?: NetDiff
|
|
|
114
123
|
}
|
|
115
124
|
|
|
116
125
|
async function sourceRange(base: string, target: string, label: string, id?: SourceRange["id"]): Promise<SourceRange> {
|
|
117
|
-
const [stats, shortBase, shortTarget] = await Promise.all([
|
|
126
|
+
const [stats, shortBase, shortTarget, committers] = await Promise.all([
|
|
118
127
|
diffStats(base, target),
|
|
119
128
|
shortCommit(base),
|
|
120
129
|
shortCommit(target),
|
|
130
|
+
committersForRange(base, target),
|
|
121
131
|
]);
|
|
122
132
|
return {
|
|
123
133
|
id: id ?? sourceId(`net:${shortBase}..${shortTarget}`),
|
|
124
134
|
label,
|
|
125
135
|
base,
|
|
126
136
|
target,
|
|
137
|
+
committers,
|
|
127
138
|
stats,
|
|
128
139
|
};
|
|
129
140
|
}
|
|
130
141
|
|
|
142
|
+
async function gitConfig(key: string): Promise<string> {
|
|
143
|
+
try {
|
|
144
|
+
const { stdout } = await execFileAsync("git", ["config", "--get", key]);
|
|
145
|
+
return stdout.trim();
|
|
146
|
+
} catch {
|
|
147
|
+
return "";
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async function committersForRange(base: string, target: string): Promise<readonly string[]> {
|
|
152
|
+
try {
|
|
153
|
+
const { stdout } = await execFileAsync("git", ["log", "--format=%cn <%ce>", `${base}..${target}`], {
|
|
154
|
+
maxBuffer: 4 * 1024 * 1024,
|
|
155
|
+
});
|
|
156
|
+
return uniqueLines(stdout);
|
|
157
|
+
} catch {
|
|
158
|
+
return [];
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function uniqueLines(value: string): readonly string[] {
|
|
163
|
+
const seen = new Set<string>();
|
|
164
|
+
const lines: string[] = [];
|
|
165
|
+
for (const line of value.split(/\r?\n/)) {
|
|
166
|
+
const trimmed = line.trim();
|
|
167
|
+
if (!trimmed || seen.has(trimmed)) continue;
|
|
168
|
+
seen.add(trimmed);
|
|
169
|
+
lines.push(trimmed);
|
|
170
|
+
}
|
|
171
|
+
return lines;
|
|
172
|
+
}
|
|
173
|
+
|
|
131
174
|
async function baseBefore(since: string): Promise<string> {
|
|
132
175
|
try {
|
|
133
176
|
const { stdout } = await execFileAsync("git", [
|
package/src/render.ts
CHANGED
|
@@ -32,11 +32,13 @@ No judgment-offload signals found.`;
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
return `🧙 stupify 🪄
|
|
35
|
-
|
|
36
|
-
${run.matches.map((match, index) => `${index + 1}.
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
35
|
+
AI SLOP DETECTED
|
|
36
|
+
${run.matches.map((match, index) => `${index + 1}.
|
|
37
|
+
who: ${committerLabel(run)}
|
|
38
|
+
what: ${match.patternId} - ${match.reason}
|
|
39
|
+
when: ${sourceLabel(command)}
|
|
40
|
+
where: ${match.proof}
|
|
41
|
+
why: ${match.checkWhy ?? "This pattern may indicate judgment-offload."}`).join("\n")}
|
|
40
42
|
Search mode is warn-only.`;
|
|
41
43
|
}
|
|
42
44
|
|
|
@@ -95,3 +97,18 @@ function sourceHint(command: SearchCommand): string {
|
|
|
95
97
|
if (command.kind === "commits") return `--commits ${command.count}`;
|
|
96
98
|
return "--stdin";
|
|
97
99
|
}
|
|
100
|
+
|
|
101
|
+
function sourceLabel(command: SearchCommand): string {
|
|
102
|
+
if (command.kind === "staged") return "staged changes";
|
|
103
|
+
if (command.kind === "since") return `since ${command.since}`;
|
|
104
|
+
if (command.kind === "commit") return `commit ${command.commit}`;
|
|
105
|
+
if (command.kind === "commits") return `last ${command.count} commits`;
|
|
106
|
+
return "stdin diff";
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function committerLabel(run: SearchRunJson): string {
|
|
110
|
+
const committers = (run.stats.committers ?? []).filter(Boolean);
|
|
111
|
+
if (committers.length === 0) return "unknown committer";
|
|
112
|
+
if (committers.length <= 3) return committers.join(", ");
|
|
113
|
+
return `${committers.slice(0, 3).join(", ")} +${committers.length - 3} more`;
|
|
114
|
+
}
|
package/src/sem-provider.ts
CHANGED
|
@@ -7,6 +7,7 @@ import { promisify } from "node:util";
|
|
|
7
7
|
import { cachedJson, fingerprint } from "./cache.ts";
|
|
8
8
|
import { readDiffFromStdin } from "./diff.ts";
|
|
9
9
|
import {
|
|
10
|
+
gitUserLabel,
|
|
10
11
|
sourceRangeForCommit,
|
|
11
12
|
sourceRangeForRecentCommits,
|
|
12
13
|
sourceRangeSince,
|
|
@@ -26,11 +27,12 @@ const execFileAsync = promisify(execFile);
|
|
|
26
27
|
export async function semChangeSetForCommand(
|
|
27
28
|
command: SearchCommand,
|
|
28
29
|
): Promise<SemChangeSet> {
|
|
29
|
-
if (command.kind === "stdin") return semChangeSetFromPatch(await readDiffFromStdin(), command.debugSem);
|
|
30
|
+
if (command.kind === "stdin") return semChangeSetFromPatch(await readDiffFromStdin(), command.debugSem, "stdin", ["stdin"]);
|
|
30
31
|
if (command.kind === "staged") {
|
|
31
|
-
const diff = await stagedDiff();
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
const [diff, committer] = await Promise.all([stagedDiff(), gitUserLabel()]);
|
|
33
|
+
const committers = [committer];
|
|
34
|
+
if (!diff.text.trim()) return emptyChangeSet("staged", diff.stats, committers);
|
|
35
|
+
return semChangeSetFromPatch(diff.text, command.debugSem, "staged", committers);
|
|
34
36
|
}
|
|
35
37
|
if (command.kind === "commit") {
|
|
36
38
|
const range = await sourceRangeForCommit(command.commit);
|
|
@@ -51,12 +53,17 @@ export async function semChangeSetForCommand(
|
|
|
51
53
|
return withContextWorkspace(normalizeSemDiff(raw, range), command.debugSem);
|
|
52
54
|
}
|
|
53
55
|
|
|
54
|
-
function emptyChangeSet(
|
|
56
|
+
function emptyChangeSet(
|
|
57
|
+
label: string,
|
|
58
|
+
stats: SourceRange["stats"],
|
|
59
|
+
committers?: readonly string[],
|
|
60
|
+
): SemChangeSet {
|
|
55
61
|
return {
|
|
56
62
|
id: sourceId(label),
|
|
57
63
|
label,
|
|
58
64
|
base: label,
|
|
59
65
|
target: label,
|
|
66
|
+
committers,
|
|
60
67
|
contextCwd: process.cwd(),
|
|
61
68
|
cleanup: async () => undefined,
|
|
62
69
|
changes: [],
|
|
@@ -79,7 +86,12 @@ async function semRangeForCommand(command: SearchCommand): Promise<SourceRange>
|
|
|
79
86
|
throw new Error("sem cannot resolve stdin as a git range.");
|
|
80
87
|
}
|
|
81
88
|
|
|
82
|
-
async function semChangeSetFromPatch(
|
|
89
|
+
async function semChangeSetFromPatch(
|
|
90
|
+
patch: string,
|
|
91
|
+
debugSem: boolean,
|
|
92
|
+
label = "stdin",
|
|
93
|
+
committers?: readonly string[],
|
|
94
|
+
): Promise<SemChangeSet> {
|
|
83
95
|
if (!patch.trim()) throw new Error("No diff received on stdin.");
|
|
84
96
|
const raw = await cachedJson(
|
|
85
97
|
"sem-diff",
|
|
@@ -93,11 +105,12 @@ async function semChangeSetFromPatch(patch: string, debugSem: boolean, label = "
|
|
|
93
105
|
);
|
|
94
106
|
return {
|
|
95
107
|
...normalizeSemDiff(raw, {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
108
|
+
id: sourceId(label),
|
|
109
|
+
label,
|
|
110
|
+
base: label,
|
|
111
|
+
target: label,
|
|
112
|
+
committers,
|
|
113
|
+
stats: { filesChanged: 0, additions: 0, deletions: 0 },
|
|
101
114
|
}),
|
|
102
115
|
contextCwd: process.cwd(),
|
|
103
116
|
cleanup: async () => undefined,
|
|
@@ -225,6 +238,7 @@ function normalizeSemDiff(value: unknown, range: SourceRange): SemChangeSet {
|
|
|
225
238
|
label: range.label,
|
|
226
239
|
base: range.base,
|
|
227
240
|
target: range.target,
|
|
241
|
+
committers: range.committers,
|
|
228
242
|
contextCwd: process.cwd(),
|
|
229
243
|
cleanup: async () => undefined,
|
|
230
244
|
changes,
|
package/src/stupify.ts
CHANGED
|
@@ -93,6 +93,7 @@ export async function runSearchCommand(command: SearchCommand, startedAt: number
|
|
|
93
93
|
stats: {
|
|
94
94
|
elapsedMs: Date.now() - startedAt,
|
|
95
95
|
modelCalls: 0,
|
|
96
|
+
committers: changeSet.committers,
|
|
96
97
|
skipped: true,
|
|
97
98
|
skipReason: "no_candidates",
|
|
98
99
|
filesChanged: changeSet.summary.fileCount,
|
|
@@ -134,6 +135,7 @@ export async function runSearchCommand(command: SearchCommand, startedAt: number
|
|
|
134
135
|
stats: {
|
|
135
136
|
elapsedMs: Date.now() - startedAt,
|
|
136
137
|
modelCalls: 0,
|
|
138
|
+
committers: changeSet.committers,
|
|
137
139
|
skipped: true,
|
|
138
140
|
skipReason: "no_candidates",
|
|
139
141
|
filesChanged: changeSet.summary.fileCount,
|
|
@@ -177,6 +179,7 @@ export async function runSearchCommand(command: SearchCommand, startedAt: number
|
|
|
177
179
|
modelCalls: 0,
|
|
178
180
|
inputTokens: batches.estimatedInputTokens,
|
|
179
181
|
inputTokenCap: maxSearchInputTokens,
|
|
182
|
+
committers: changeSet.committers,
|
|
180
183
|
skipped: true,
|
|
181
184
|
skipReason: "input_too_large",
|
|
182
185
|
filesChanged: changeSet.summary.fileCount,
|
|
@@ -240,6 +243,7 @@ export async function runSearchCommand(command: SearchCommand, startedAt: number
|
|
|
240
243
|
modelCalls,
|
|
241
244
|
inputTokens,
|
|
242
245
|
inputTokenCap: maxSearchInputTokens,
|
|
246
|
+
committers: changeSet.committers,
|
|
243
247
|
filesChanged: changeSet.summary.fileCount,
|
|
244
248
|
entitiesScanned: changeSet.summary.total,
|
|
245
249
|
candidates: contexts.length,
|
package/src/types.ts
CHANGED
|
@@ -92,6 +92,7 @@ export type SourceRange = Readonly<{
|
|
|
92
92
|
label: string;
|
|
93
93
|
base: string;
|
|
94
94
|
target: string;
|
|
95
|
+
committers?: readonly string[];
|
|
95
96
|
stats: NetDiffStats;
|
|
96
97
|
}>;
|
|
97
98
|
|
|
@@ -120,6 +121,7 @@ export type SemChangeSet = Readonly<{
|
|
|
120
121
|
label: string;
|
|
121
122
|
base: string;
|
|
122
123
|
target: string;
|
|
124
|
+
committers?: readonly string[];
|
|
123
125
|
contextCwd: string;
|
|
124
126
|
cleanup: () => Promise<void>;
|
|
125
127
|
changes: readonly SemChange[];
|
|
@@ -211,6 +213,7 @@ export type SearchRunJson = Readonly<{
|
|
|
211
213
|
inputTokenCap?: number;
|
|
212
214
|
skipped?: boolean;
|
|
213
215
|
skipReason?: "input_too_large" | "no_candidates";
|
|
216
|
+
committers?: readonly string[];
|
|
214
217
|
filesChanged?: number;
|
|
215
218
|
entitiesScanned?: number;
|
|
216
219
|
candidates?: number;
|