codiedev 0.7.1 → 0.7.3
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/commands/reverseTicket.js +63 -8
- package/dist/mcp.js +87 -9
- package/package.json +1 -1
|
@@ -211,19 +211,73 @@ async function runBranchMode(opts) {
|
|
|
211
211
|
}
|
|
212
212
|
const baseSha = git(`merge-base HEAD ${baseRef}`);
|
|
213
213
|
const headSha = git("rev-parse HEAD");
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
214
|
+
// Filter generated/lockfile noise from the diff body. The --stat (collected
|
|
215
|
+
// separately) still includes every file untouched, so excluded files still
|
|
216
|
+
// surface in the ticket's "Other files touched" section.
|
|
217
|
+
const isNoise = (p) => /(^|\/)(node_modules|dist|build|\.next|\.turbo|coverage|out)\//.test(p) ||
|
|
218
|
+
/(^|\/)package-lock\.json$/.test(p) ||
|
|
219
|
+
/(^|\/)yarn\.lock$/.test(p) ||
|
|
220
|
+
/(^|\/)pnpm-lock\.yaml$/.test(p) ||
|
|
221
|
+
/(^|\/)bun\.lock(b)?$/.test(p) ||
|
|
222
|
+
/(^|\/)Cargo\.lock$/.test(p) ||
|
|
223
|
+
/(^|\/)Gemfile\.lock$/.test(p) ||
|
|
224
|
+
/(^|\/)poetry\.lock$/.test(p) ||
|
|
225
|
+
/(^|\/)go\.sum$/.test(p);
|
|
226
|
+
const shellTolerant = (cmd) => {
|
|
227
|
+
try {
|
|
228
|
+
return (0, child_process_1.execSync)(`${cmd} || true`, {
|
|
229
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
230
|
+
maxBuffer: 32 * 1024 * 1024,
|
|
231
|
+
})
|
|
232
|
+
.toString("utf8")
|
|
233
|
+
.trim();
|
|
234
|
+
}
|
|
235
|
+
catch {
|
|
236
|
+
return "";
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
const shQuote = (s) => `'${s.replace(/'/g, "'\\''")}'`;
|
|
240
|
+
// Capture all work relative to the base ref: committed + uncommitted-tracked
|
|
241
|
+
// + new untracked. Matches "ticket my current changes" intent.
|
|
242
|
+
const trackedRaw = git(`diff --name-only ${baseSha}`);
|
|
243
|
+
const trackedFiles = trackedRaw ? trackedRaw.split("\n").filter(Boolean) : [];
|
|
244
|
+
const untrackedRaw = safeGit(() => git("ls-files --others --exclude-standard"));
|
|
245
|
+
const untrackedFiles = untrackedRaw
|
|
246
|
+
? untrackedRaw.split("\n").filter(Boolean)
|
|
247
|
+
: [];
|
|
248
|
+
const filesChanged = Array.from(new Set([...trackedFiles, ...untrackedFiles]));
|
|
220
249
|
if (filesChanged.length === 0) {
|
|
221
|
-
console.error(`No
|
|
250
|
+
console.error(`No changes detected between ${baseRef} and your working tree on ${branch}.`);
|
|
222
251
|
process.exit(1);
|
|
223
252
|
}
|
|
253
|
+
let stat = "";
|
|
254
|
+
try {
|
|
255
|
+
const trackedStat = git(`diff --stat=200 ${baseSha}`);
|
|
256
|
+
const untrackedStatLines = untrackedFiles.map((f) => {
|
|
257
|
+
const wc = shellTolerant(`wc -l < ${shQuote(f)}`);
|
|
258
|
+
const n = parseInt(wc.split(/\s+/)[0] || "0", 10) || 0;
|
|
259
|
+
return ` ${f} | ${n} ++++++++++ (new file)`;
|
|
260
|
+
});
|
|
261
|
+
stat = [trackedStat, ...untrackedStatLines]
|
|
262
|
+
.filter(Boolean)
|
|
263
|
+
.join("\n")
|
|
264
|
+
.slice(0, 8_000);
|
|
265
|
+
}
|
|
266
|
+
catch {
|
|
267
|
+
// best effort
|
|
268
|
+
}
|
|
224
269
|
let diff = "";
|
|
225
270
|
try {
|
|
226
|
-
|
|
271
|
+
const sourceTracked = trackedFiles.filter((f) => !isNoise(f));
|
|
272
|
+
const trackedDiff = sourceTracked.length > 0
|
|
273
|
+
? git(`diff ${baseSha} -- ${sourceTracked.map(shQuote).join(" ")}`)
|
|
274
|
+
: git(`diff ${baseSha}`);
|
|
275
|
+
const sourceUntracked = untrackedFiles.filter((f) => !isNoise(f));
|
|
276
|
+
const untrackedDiffs = sourceUntracked.map((f) => shellTolerant(`git diff --no-index --no-color -- /dev/null ${shQuote(f)}`));
|
|
277
|
+
diff = [trackedDiff, ...untrackedDiffs]
|
|
278
|
+
.filter(Boolean)
|
|
279
|
+
.join("\n")
|
|
280
|
+
.slice(0, 40_000);
|
|
227
281
|
}
|
|
228
282
|
catch {
|
|
229
283
|
// best effort
|
|
@@ -266,6 +320,7 @@ async function runBranchMode(opts) {
|
|
|
266
320
|
authorEmail,
|
|
267
321
|
filesChanged,
|
|
268
322
|
diff: diff || undefined,
|
|
323
|
+
stat: stat || undefined,
|
|
269
324
|
},
|
|
270
325
|
forcedArtifactKey: opts.forcedKey,
|
|
271
326
|
},
|
package/dist/mcp.js
CHANGED
|
@@ -52,7 +52,17 @@ const path = __importStar(require("path"));
|
|
|
52
52
|
const utils_1 = require("./utils");
|
|
53
53
|
const shared_1 = require("./commands/shared");
|
|
54
54
|
const PKG_NAME = "codiedev";
|
|
55
|
-
|
|
55
|
+
// Read version from the bundled package.json so the startup log + tool reports
|
|
56
|
+
// always reflect the actually-installed version, rather than a stale constant.
|
|
57
|
+
const PKG_VERSION = (() => {
|
|
58
|
+
try {
|
|
59
|
+
const pkgPath = path.resolve(__dirname, "..", "package.json");
|
|
60
|
+
return JSON.parse(fs.readFileSync(pkgPath, "utf8")).version ?? "unknown";
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return "unknown";
|
|
64
|
+
}
|
|
65
|
+
})();
|
|
56
66
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
57
67
|
// Tool definitions — descriptions tuned so Claude/Codex resolve natural-language
|
|
58
68
|
// requests into the right tool without manual steering.
|
|
@@ -1086,18 +1096,85 @@ async function handleReverseTicket(args, config) {
|
|
|
1086
1096
|
}
|
|
1087
1097
|
const baseSha = git(`merge-base HEAD ${baseRef}`);
|
|
1088
1098
|
const headSha = git("rev-parse HEAD");
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
const
|
|
1099
|
+
// Filter generated/lockfile noise so the LLM's diff budget gets spent on
|
|
1100
|
+
// real source. The --stat block (collected separately below) still includes
|
|
1101
|
+
// every file untouched, so excluded files still appear in the ticket's
|
|
1102
|
+
// "Other files touched" section if relevant.
|
|
1103
|
+
const isNoise = (p) => /(^|\/)(node_modules|dist|build|\.next|\.turbo|coverage|out)\//.test(p) ||
|
|
1104
|
+
/(^|\/)package-lock\.json$/.test(p) ||
|
|
1105
|
+
/(^|\/)yarn\.lock$/.test(p) ||
|
|
1106
|
+
/(^|\/)pnpm-lock\.yaml$/.test(p) ||
|
|
1107
|
+
/(^|\/)bun\.lock(b)?$/.test(p) ||
|
|
1108
|
+
/(^|\/)Cargo\.lock$/.test(p) ||
|
|
1109
|
+
/(^|\/)Gemfile\.lock$/.test(p) ||
|
|
1110
|
+
/(^|\/)poetry\.lock$/.test(p) ||
|
|
1111
|
+
/(^|\/)go\.sum$/.test(p);
|
|
1112
|
+
// Helper: run a shell command tolerating non-zero exit codes (git diff
|
|
1113
|
+
// --no-index exits 1 when files differ, which is the normal case).
|
|
1114
|
+
// Reuses the execSync already imported above for the git() helper.
|
|
1115
|
+
const shellTolerant = (cmd) => {
|
|
1116
|
+
try {
|
|
1117
|
+
return execSync(`${cmd} || true`, {
|
|
1118
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
1119
|
+
maxBuffer: 32 * 1024 * 1024,
|
|
1120
|
+
})
|
|
1121
|
+
.toString("utf8")
|
|
1122
|
+
.trim();
|
|
1123
|
+
}
|
|
1124
|
+
catch {
|
|
1125
|
+
return "";
|
|
1126
|
+
}
|
|
1127
|
+
};
|
|
1128
|
+
const shQuote = (s) => `'${s.replace(/'/g, "'\\''")}'`;
|
|
1129
|
+
// Capture all work the developer has done relative to the base ref:
|
|
1130
|
+
// - committed changes between base and HEAD
|
|
1131
|
+
// - uncommitted modifications to tracked files
|
|
1132
|
+
// - new untracked files (path listed + content via synthetic diff)
|
|
1133
|
+
// Matches the user's intent ("ticket my current changes") rather than the
|
|
1134
|
+
// narrower "only what's been committed" interpretation.
|
|
1135
|
+
const trackedRaw = git(`diff --name-only ${baseSha}`);
|
|
1136
|
+
const trackedFiles = trackedRaw ? trackedRaw.split("\n").filter(Boolean) : [];
|
|
1137
|
+
const untrackedRaw = safeGit(() => git("ls-files --others --exclude-standard"));
|
|
1138
|
+
const untrackedFiles = untrackedRaw
|
|
1139
|
+
? untrackedRaw.split("\n").filter(Boolean)
|
|
1140
|
+
: [];
|
|
1141
|
+
const filesChanged = Array.from(new Set([...trackedFiles, ...untrackedFiles]));
|
|
1094
1142
|
if (filesChanged.length === 0) {
|
|
1095
|
-
throw new Error(`No
|
|
1143
|
+
throw new Error(`No changes detected between ${baseRef} and your working tree on ${branch}.`);
|
|
1144
|
+
}
|
|
1145
|
+
// --stat block: compact ground truth for "every file touched". Tracked
|
|
1146
|
+
// changes from `git diff --stat baseSha`; untracked files appended as
|
|
1147
|
+
// synthesized stat rows so the LLM sees them with line counts.
|
|
1148
|
+
let stat = "";
|
|
1149
|
+
try {
|
|
1150
|
+
const trackedStat = git(`diff --stat=200 ${baseSha}`);
|
|
1151
|
+
const untrackedStatLines = untrackedFiles.map((f) => {
|
|
1152
|
+
const wc = shellTolerant(`wc -l < ${shQuote(f)}`);
|
|
1153
|
+
const n = parseInt(wc.split(/\s+/)[0] || "0", 10) || 0;
|
|
1154
|
+
return ` ${f} | ${n} ++++++++++ (new file)`;
|
|
1155
|
+
});
|
|
1156
|
+
stat = [trackedStat, ...untrackedStatLines]
|
|
1157
|
+
.filter(Boolean)
|
|
1158
|
+
.join("\n")
|
|
1159
|
+
.slice(0, 8_000);
|
|
1160
|
+
}
|
|
1161
|
+
catch {
|
|
1162
|
+
// Best effort.
|
|
1096
1163
|
}
|
|
1097
|
-
//
|
|
1164
|
+
// Diff body: 40k cap, noise-filtered. Tracked changes via `git diff baseSha`,
|
|
1165
|
+
// plus synthetic add-only diffs for untracked files via `git diff --no-index`.
|
|
1098
1166
|
let diff = "";
|
|
1099
1167
|
try {
|
|
1100
|
-
|
|
1168
|
+
const sourceTracked = trackedFiles.filter((f) => !isNoise(f));
|
|
1169
|
+
const trackedDiff = sourceTracked.length > 0
|
|
1170
|
+
? git(`diff ${baseSha} -- ${sourceTracked.map(shQuote).join(" ")}`)
|
|
1171
|
+
: git(`diff ${baseSha}`);
|
|
1172
|
+
const sourceUntracked = untrackedFiles.filter((f) => !isNoise(f));
|
|
1173
|
+
const untrackedDiffs = sourceUntracked.map((f) => shellTolerant(`git diff --no-index --no-color -- /dev/null ${shQuote(f)}`));
|
|
1174
|
+
diff = [trackedDiff, ...untrackedDiffs]
|
|
1175
|
+
.filter(Boolean)
|
|
1176
|
+
.join("\n")
|
|
1177
|
+
.slice(0, 40_000);
|
|
1101
1178
|
}
|
|
1102
1179
|
catch {
|
|
1103
1180
|
// Best effort.
|
|
@@ -1132,6 +1209,7 @@ async function handleReverseTicket(args, config) {
|
|
|
1132
1209
|
authorEmail,
|
|
1133
1210
|
filesChanged,
|
|
1134
1211
|
diff: diff || undefined,
|
|
1212
|
+
stat: stat || undefined,
|
|
1135
1213
|
},
|
|
1136
1214
|
forcedArtifactKey: forcedKey,
|
|
1137
1215
|
},
|
package/package.json
CHANGED