@kody-ade/kody-engine 0.3.6 → 0.3.7
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/bin/kody.js +207 -163
- package/dist/executables/research/profile.json +3 -0
- package/package.json +1 -1
package/dist/bin/kody.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// package.json
|
|
4
4
|
var package_default = {
|
|
5
5
|
name: "@kody-ade/kody-engine",
|
|
6
|
-
version: "0.3.
|
|
6
|
+
version: "0.3.7",
|
|
7
7
|
description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
|
|
8
8
|
license: "MIT",
|
|
9
9
|
type: "module",
|
|
@@ -50,9 +50,9 @@ var package_default = {
|
|
|
50
50
|
};
|
|
51
51
|
|
|
52
52
|
// src/chat-cli.ts
|
|
53
|
-
import { execFileSync as
|
|
54
|
-
import * as
|
|
55
|
-
import * as
|
|
53
|
+
import { execFileSync as execFileSync22 } from "child_process";
|
|
54
|
+
import * as fs23 from "fs";
|
|
55
|
+
import * as path20 from "path";
|
|
56
56
|
|
|
57
57
|
// src/chat/events.ts
|
|
58
58
|
import * as fs from "fs";
|
|
@@ -263,7 +263,7 @@ function renderEvent(msg, opts = {}) {
|
|
|
263
263
|
}
|
|
264
264
|
switch (msg.type) {
|
|
265
265
|
case "system":
|
|
266
|
-
return
|
|
266
|
+
return formatSystemEvent(msg);
|
|
267
267
|
case "assistant":
|
|
268
268
|
return formatAssistant(msg, opts);
|
|
269
269
|
case "user":
|
|
@@ -309,6 +309,14 @@ ${truncate(text, 4e3)}`);
|
|
|
309
309
|
}
|
|
310
310
|
return lines.length > 0 ? lines.join("\n") : null;
|
|
311
311
|
}
|
|
312
|
+
function formatSystemEvent(msg) {
|
|
313
|
+
if (msg.subtype !== "init") return null;
|
|
314
|
+
const servers = msg.mcp_servers ?? [];
|
|
315
|
+
if (servers.length === 0) return null;
|
|
316
|
+
const lines = servers.map((s) => ` - ${s.name}: ${s.status ?? "unknown"}`);
|
|
317
|
+
return `[mcp servers]
|
|
318
|
+
${lines.join("\n")}`;
|
|
319
|
+
}
|
|
312
320
|
function formatResult(msg) {
|
|
313
321
|
const ok = msg.subtype === "success";
|
|
314
322
|
const tag = ok ? "SESSION ok" : `SESSION failed (${msg.subtype ?? "unknown"})`;
|
|
@@ -568,9 +576,9 @@ async function emit(sink, type, sessionId, suffix, payload) {
|
|
|
568
576
|
}
|
|
569
577
|
|
|
570
578
|
// src/kody-cli.ts
|
|
571
|
-
import { execFileSync as
|
|
572
|
-
import * as
|
|
573
|
-
import * as
|
|
579
|
+
import { execFileSync as execFileSync21 } from "child_process";
|
|
580
|
+
import * as fs22 from "fs";
|
|
581
|
+
import * as path19 from "path";
|
|
574
582
|
|
|
575
583
|
// src/dispatch.ts
|
|
576
584
|
import * as fs6 from "fs";
|
|
@@ -787,8 +795,8 @@ function coerceBare(spec, value) {
|
|
|
787
795
|
}
|
|
788
796
|
|
|
789
797
|
// src/executor.ts
|
|
790
|
-
import * as
|
|
791
|
-
import * as
|
|
798
|
+
import * as fs21 from "fs";
|
|
799
|
+
import * as path18 from "path";
|
|
792
800
|
|
|
793
801
|
// src/litellm.ts
|
|
794
802
|
import { execFileSync, spawn } from "child_process";
|
|
@@ -2036,18 +2044,53 @@ function formatToolsUsage(profile) {
|
|
|
2036
2044
|
return lines.join("\n");
|
|
2037
2045
|
}
|
|
2038
2046
|
|
|
2047
|
+
// src/scripts/diagMcp.ts
|
|
2048
|
+
import { execFileSync as execFileSync7 } from "child_process";
|
|
2049
|
+
import * as fs13 from "fs";
|
|
2050
|
+
import * as os3 from "os";
|
|
2051
|
+
import * as path12 from "path";
|
|
2052
|
+
var diagMcp = async (_ctx) => {
|
|
2053
|
+
const home = os3.homedir();
|
|
2054
|
+
const cacheDir = path12.join(home, ".cache", "ms-playwright");
|
|
2055
|
+
let entries = [];
|
|
2056
|
+
try {
|
|
2057
|
+
entries = fs13.readdirSync(cacheDir);
|
|
2058
|
+
} catch {
|
|
2059
|
+
}
|
|
2060
|
+
const hasChromium = entries.some((e) => e.startsWith("chromium"));
|
|
2061
|
+
process.stderr.write(
|
|
2062
|
+
`[kody diag] ms-playwright cache: ${entries.length === 0 ? "EMPTY (or missing)" : entries.join(", ")}
|
|
2063
|
+
`
|
|
2064
|
+
);
|
|
2065
|
+
process.stderr.write(`[kody diag] chromium present: ${hasChromium ? "yes" : "no"}
|
|
2066
|
+
`);
|
|
2067
|
+
try {
|
|
2068
|
+
const v = execFileSync7("npx", ["-y", "@playwright/mcp@latest", "--version"], {
|
|
2069
|
+
stdio: "pipe",
|
|
2070
|
+
timeout: 6e4,
|
|
2071
|
+
encoding: "utf8"
|
|
2072
|
+
}).trim();
|
|
2073
|
+
process.stderr.write(`[kody diag] @playwright/mcp version: ${v}
|
|
2074
|
+
`);
|
|
2075
|
+
} catch (e) {
|
|
2076
|
+
const err = e instanceof Error ? e.message : String(e);
|
|
2077
|
+
process.stderr.write(`[kody diag] @playwright/mcp spawn FAILED: ${err}
|
|
2078
|
+
`);
|
|
2079
|
+
}
|
|
2080
|
+
};
|
|
2081
|
+
|
|
2039
2082
|
// src/scripts/discoverQaContext.ts
|
|
2040
|
-
import * as
|
|
2041
|
-
import * as
|
|
2083
|
+
import * as fs15 from "fs";
|
|
2084
|
+
import * as path14 from "path";
|
|
2042
2085
|
|
|
2043
2086
|
// src/scripts/frameworkDetectors.ts
|
|
2044
|
-
import * as
|
|
2045
|
-
import * as
|
|
2087
|
+
import * as fs14 from "fs";
|
|
2088
|
+
import * as path13 from "path";
|
|
2046
2089
|
function detectFrameworks(cwd) {
|
|
2047
2090
|
const out = [];
|
|
2048
2091
|
let deps = {};
|
|
2049
2092
|
try {
|
|
2050
|
-
const pkg = JSON.parse(
|
|
2093
|
+
const pkg = JSON.parse(fs14.readFileSync(path13.join(cwd, "package.json"), "utf-8"));
|
|
2051
2094
|
deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
2052
2095
|
} catch {
|
|
2053
2096
|
return out;
|
|
@@ -2084,7 +2127,7 @@ function detectFrameworks(cwd) {
|
|
|
2084
2127
|
}
|
|
2085
2128
|
function findFile(cwd, candidates) {
|
|
2086
2129
|
for (const c of candidates) {
|
|
2087
|
-
if (
|
|
2130
|
+
if (fs14.existsSync(path13.join(cwd, c))) return c;
|
|
2088
2131
|
}
|
|
2089
2132
|
return null;
|
|
2090
2133
|
}
|
|
@@ -2097,18 +2140,18 @@ var COLLECTION_DIRS = [
|
|
|
2097
2140
|
function discoverPayloadCollections(cwd) {
|
|
2098
2141
|
const out = [];
|
|
2099
2142
|
for (const dir of COLLECTION_DIRS) {
|
|
2100
|
-
const full =
|
|
2101
|
-
if (!
|
|
2143
|
+
const full = path13.join(cwd, dir);
|
|
2144
|
+
if (!fs14.existsSync(full)) continue;
|
|
2102
2145
|
let files;
|
|
2103
2146
|
try {
|
|
2104
|
-
files =
|
|
2147
|
+
files = fs14.readdirSync(full).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
|
|
2105
2148
|
} catch {
|
|
2106
2149
|
continue;
|
|
2107
2150
|
}
|
|
2108
2151
|
for (const file of files) {
|
|
2109
2152
|
try {
|
|
2110
|
-
const filePath =
|
|
2111
|
-
const content =
|
|
2153
|
+
const filePath = path13.join(full, file);
|
|
2154
|
+
const content = fs14.readFileSync(filePath, "utf-8").slice(0, 1e4);
|
|
2112
2155
|
const slugMatch = content.match(/slug:\s*['"]([a-z0-9-]+)['"]/);
|
|
2113
2156
|
if (!slugMatch) continue;
|
|
2114
2157
|
const slug = slugMatch[1];
|
|
@@ -2122,7 +2165,7 @@ function discoverPayloadCollections(cwd) {
|
|
|
2122
2165
|
out.push({
|
|
2123
2166
|
name,
|
|
2124
2167
|
slug,
|
|
2125
|
-
filePath:
|
|
2168
|
+
filePath: path13.relative(cwd, filePath),
|
|
2126
2169
|
fields: fields.slice(0, 20),
|
|
2127
2170
|
hasAdmin
|
|
2128
2171
|
});
|
|
@@ -2136,28 +2179,28 @@ var ADMIN_COMPONENT_DIRS = ["src/ui/admin", "src/admin/components", "src/compone
|
|
|
2136
2179
|
function discoverAdminComponents(cwd, collections) {
|
|
2137
2180
|
const out = [];
|
|
2138
2181
|
for (const dir of ADMIN_COMPONENT_DIRS) {
|
|
2139
|
-
const full =
|
|
2140
|
-
if (!
|
|
2182
|
+
const full = path13.join(cwd, dir);
|
|
2183
|
+
if (!fs14.existsSync(full)) continue;
|
|
2141
2184
|
let entries;
|
|
2142
2185
|
try {
|
|
2143
|
-
entries =
|
|
2186
|
+
entries = fs14.readdirSync(full, { withFileTypes: true });
|
|
2144
2187
|
} catch {
|
|
2145
2188
|
continue;
|
|
2146
2189
|
}
|
|
2147
2190
|
for (const entry of entries) {
|
|
2148
|
-
const entryPath =
|
|
2191
|
+
const entryPath = path13.join(full, entry.name);
|
|
2149
2192
|
let name;
|
|
2150
2193
|
let filePath;
|
|
2151
2194
|
if (entry.isDirectory()) {
|
|
2152
2195
|
const indexFile = ["index.tsx", "index.ts", "index.jsx", "index.js"].find(
|
|
2153
|
-
(f) =>
|
|
2196
|
+
(f) => fs14.existsSync(path13.join(entryPath, f))
|
|
2154
2197
|
);
|
|
2155
2198
|
if (!indexFile) continue;
|
|
2156
2199
|
name = entry.name;
|
|
2157
|
-
filePath =
|
|
2200
|
+
filePath = path13.relative(cwd, path13.join(entryPath, indexFile));
|
|
2158
2201
|
} else if (/\.(tsx?|jsx?)$/.test(entry.name)) {
|
|
2159
2202
|
name = entry.name.replace(/\.(tsx?|jsx?)$/, "");
|
|
2160
|
-
filePath =
|
|
2203
|
+
filePath = path13.relative(cwd, entryPath);
|
|
2161
2204
|
} else {
|
|
2162
2205
|
continue;
|
|
2163
2206
|
}
|
|
@@ -2165,7 +2208,7 @@ function discoverAdminComponents(cwd, collections) {
|
|
|
2165
2208
|
if (collections) {
|
|
2166
2209
|
for (const col of collections) {
|
|
2167
2210
|
try {
|
|
2168
|
-
const colContent =
|
|
2211
|
+
const colContent = fs14.readFileSync(path13.join(cwd, col.filePath), "utf-8");
|
|
2169
2212
|
if (colContent.includes(name)) {
|
|
2170
2213
|
usedInCollection = col.slug;
|
|
2171
2214
|
break;
|
|
@@ -2184,8 +2227,8 @@ function scanApiRoutes(cwd) {
|
|
|
2184
2227
|
const out = [];
|
|
2185
2228
|
const appDirs = ["src/app", "app"];
|
|
2186
2229
|
for (const appDir of appDirs) {
|
|
2187
|
-
const apiDir =
|
|
2188
|
-
if (!
|
|
2230
|
+
const apiDir = path13.join(cwd, appDir, "api");
|
|
2231
|
+
if (!fs14.existsSync(apiDir)) continue;
|
|
2189
2232
|
walkApiRoutes(apiDir, "/api", cwd, out);
|
|
2190
2233
|
break;
|
|
2191
2234
|
}
|
|
@@ -2194,20 +2237,20 @@ function scanApiRoutes(cwd) {
|
|
|
2194
2237
|
function walkApiRoutes(dir, prefix, cwd, out) {
|
|
2195
2238
|
let entries;
|
|
2196
2239
|
try {
|
|
2197
|
-
entries =
|
|
2240
|
+
entries = fs14.readdirSync(dir, { withFileTypes: true });
|
|
2198
2241
|
} catch {
|
|
2199
2242
|
return;
|
|
2200
2243
|
}
|
|
2201
2244
|
const routeFile = entries.find((e) => e.isFile() && /^route\.(ts|js|tsx|jsx)$/.test(e.name));
|
|
2202
2245
|
if (routeFile) {
|
|
2203
2246
|
try {
|
|
2204
|
-
const content =
|
|
2247
|
+
const content = fs14.readFileSync(path13.join(dir, routeFile.name), "utf-8").slice(0, 5e3);
|
|
2205
2248
|
const methods = HTTP_METHODS.filter((m) => new RegExp(`export\\s+(?:async\\s+)?function\\s+${m}\\b`).test(content));
|
|
2206
2249
|
if (methods.length > 0) {
|
|
2207
2250
|
out.push({
|
|
2208
2251
|
path: prefix,
|
|
2209
2252
|
methods,
|
|
2210
|
-
filePath:
|
|
2253
|
+
filePath: path13.relative(cwd, path13.join(dir, routeFile.name))
|
|
2211
2254
|
});
|
|
2212
2255
|
}
|
|
2213
2256
|
} catch {
|
|
@@ -2218,7 +2261,7 @@ function walkApiRoutes(dir, prefix, cwd, out) {
|
|
|
2218
2261
|
if (entry.name === "node_modules" || entry.name === ".next") continue;
|
|
2219
2262
|
let segment = entry.name;
|
|
2220
2263
|
if (segment.startsWith("(") && segment.endsWith(")")) {
|
|
2221
|
-
walkApiRoutes(
|
|
2264
|
+
walkApiRoutes(path13.join(dir, entry.name), prefix, cwd, out);
|
|
2222
2265
|
continue;
|
|
2223
2266
|
}
|
|
2224
2267
|
if (segment.startsWith("[[") && segment.endsWith("]]")) {
|
|
@@ -2226,7 +2269,7 @@ function walkApiRoutes(dir, prefix, cwd, out) {
|
|
|
2226
2269
|
} else if (segment.startsWith("[") && segment.endsWith("]")) {
|
|
2227
2270
|
segment = `:${segment.slice(1, -1)}`;
|
|
2228
2271
|
}
|
|
2229
|
-
walkApiRoutes(
|
|
2272
|
+
walkApiRoutes(path13.join(dir, entry.name), `${prefix}/${segment}`, cwd, out);
|
|
2230
2273
|
}
|
|
2231
2274
|
}
|
|
2232
2275
|
var BUILTIN_ENV_VARS = /* @__PURE__ */ new Set([
|
|
@@ -2246,10 +2289,10 @@ var BUILTIN_ENV_VARS = /* @__PURE__ */ new Set([
|
|
|
2246
2289
|
function scanEnvVars(cwd) {
|
|
2247
2290
|
const candidates = [".env.example", ".env.local.example", ".env.template"];
|
|
2248
2291
|
for (const envFile of candidates) {
|
|
2249
|
-
const envPath =
|
|
2250
|
-
if (!
|
|
2292
|
+
const envPath = path13.join(cwd, envFile);
|
|
2293
|
+
if (!fs14.existsSync(envPath)) continue;
|
|
2251
2294
|
try {
|
|
2252
|
-
const content =
|
|
2295
|
+
const content = fs14.readFileSync(envPath, "utf-8");
|
|
2253
2296
|
const vars = [];
|
|
2254
2297
|
for (const line of content.split("\n")) {
|
|
2255
2298
|
const trimmed = line.trim();
|
|
@@ -2297,9 +2340,9 @@ function runQaDiscovery(cwd) {
|
|
|
2297
2340
|
}
|
|
2298
2341
|
function detectDevServer(cwd, out) {
|
|
2299
2342
|
try {
|
|
2300
|
-
const pkg = JSON.parse(
|
|
2343
|
+
const pkg = JSON.parse(fs15.readFileSync(path14.join(cwd, "package.json"), "utf-8"));
|
|
2301
2344
|
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
2302
|
-
const pm =
|
|
2345
|
+
const pm = fs15.existsSync(path14.join(cwd, "pnpm-lock.yaml")) ? "pnpm" : fs15.existsSync(path14.join(cwd, "yarn.lock")) ? "yarn" : fs15.existsSync(path14.join(cwd, "bun.lockb")) ? "bun" : "npm";
|
|
2303
2346
|
if (pkg.scripts?.dev) out.devCommand = `${pm} dev`;
|
|
2304
2347
|
if (allDeps.next || allDeps.nuxt) out.devPort = 3e3;
|
|
2305
2348
|
else if (allDeps.vite) out.devPort = 5173;
|
|
@@ -2309,8 +2352,8 @@ function detectDevServer(cwd, out) {
|
|
|
2309
2352
|
function scanFrontendRoutes(cwd, out) {
|
|
2310
2353
|
const appDirs = ["src/app", "app"];
|
|
2311
2354
|
for (const appDir of appDirs) {
|
|
2312
|
-
const full =
|
|
2313
|
-
if (!
|
|
2355
|
+
const full = path14.join(cwd, appDir);
|
|
2356
|
+
if (!fs15.existsSync(full)) continue;
|
|
2314
2357
|
walkFrontendRoutes(full, "", out);
|
|
2315
2358
|
break;
|
|
2316
2359
|
}
|
|
@@ -2318,7 +2361,7 @@ function scanFrontendRoutes(cwd, out) {
|
|
|
2318
2361
|
function walkFrontendRoutes(dir, prefix, out) {
|
|
2319
2362
|
let entries;
|
|
2320
2363
|
try {
|
|
2321
|
-
entries =
|
|
2364
|
+
entries = fs15.readdirSync(dir, { withFileTypes: true });
|
|
2322
2365
|
} catch {
|
|
2323
2366
|
return;
|
|
2324
2367
|
}
|
|
@@ -2335,7 +2378,7 @@ function walkFrontendRoutes(dir, prefix, out) {
|
|
|
2335
2378
|
if (entry.name === "node_modules" || entry.name === ".next") continue;
|
|
2336
2379
|
let segment = entry.name;
|
|
2337
2380
|
if (segment.startsWith("(") && segment.endsWith(")")) {
|
|
2338
|
-
walkFrontendRoutes(
|
|
2381
|
+
walkFrontendRoutes(path14.join(dir, entry.name), prefix, out);
|
|
2339
2382
|
continue;
|
|
2340
2383
|
}
|
|
2341
2384
|
if (segment.startsWith("[[") && segment.endsWith("]]")) {
|
|
@@ -2343,7 +2386,7 @@ function walkFrontendRoutes(dir, prefix, out) {
|
|
|
2343
2386
|
} else if (segment.startsWith("[") && segment.endsWith("]")) {
|
|
2344
2387
|
segment = `:${segment.slice(1, -1)}`;
|
|
2345
2388
|
}
|
|
2346
|
-
walkFrontendRoutes(
|
|
2389
|
+
walkFrontendRoutes(path14.join(dir, entry.name), `${prefix}/${segment}`, out);
|
|
2347
2390
|
}
|
|
2348
2391
|
}
|
|
2349
2392
|
function detectAuthFiles(cwd, out) {
|
|
@@ -2360,23 +2403,23 @@ function detectAuthFiles(cwd, out) {
|
|
|
2360
2403
|
"src/app/api/oauth"
|
|
2361
2404
|
];
|
|
2362
2405
|
for (const c of candidates) {
|
|
2363
|
-
if (
|
|
2406
|
+
if (fs15.existsSync(path14.join(cwd, c))) out.authFiles.push(c);
|
|
2364
2407
|
}
|
|
2365
2408
|
}
|
|
2366
2409
|
function detectRoles(cwd, out) {
|
|
2367
2410
|
const rolePaths = ["src/types", "src/lib", "src/utils", "src/constants", "src/access", "src/collections"];
|
|
2368
2411
|
for (const rp of rolePaths) {
|
|
2369
|
-
const dir =
|
|
2370
|
-
if (!
|
|
2412
|
+
const dir = path14.join(cwd, rp);
|
|
2413
|
+
if (!fs15.existsSync(dir)) continue;
|
|
2371
2414
|
let files;
|
|
2372
2415
|
try {
|
|
2373
|
-
files =
|
|
2416
|
+
files = fs15.readdirSync(dir).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
|
|
2374
2417
|
} catch {
|
|
2375
2418
|
continue;
|
|
2376
2419
|
}
|
|
2377
2420
|
for (const f of files) {
|
|
2378
2421
|
try {
|
|
2379
|
-
const content =
|
|
2422
|
+
const content = fs15.readFileSync(path14.join(dir, f), "utf-8").slice(0, 5e3);
|
|
2380
2423
|
const roleMatches = content.match(/(?:role|Role|ROLE)\s*[=:]\s*['"](\w+)['"]/g);
|
|
2381
2424
|
if (roleMatches) {
|
|
2382
2425
|
for (const m of roleMatches) {
|
|
@@ -2522,7 +2565,7 @@ var discoverQaContext = async (ctx) => {
|
|
|
2522
2565
|
};
|
|
2523
2566
|
|
|
2524
2567
|
// src/scripts/dispatch.ts
|
|
2525
|
-
import { execFileSync as
|
|
2568
|
+
import { execFileSync as execFileSync8 } from "child_process";
|
|
2526
2569
|
var API_TIMEOUT_MS3 = 3e4;
|
|
2527
2570
|
var dispatch = async (ctx, _profile, _agentResult, args) => {
|
|
2528
2571
|
const next = args?.next;
|
|
@@ -2545,7 +2588,7 @@ var dispatch = async (ctx, _profile, _agentResult, args) => {
|
|
|
2545
2588
|
const sub = usePr ? "pr" : "issue";
|
|
2546
2589
|
const body = `@kody ${next}`;
|
|
2547
2590
|
try {
|
|
2548
|
-
|
|
2591
|
+
execFileSync8("gh", [sub, "comment", String(targetNumber), "--body", body], {
|
|
2549
2592
|
timeout: API_TIMEOUT_MS3,
|
|
2550
2593
|
cwd: ctx.cwd,
|
|
2551
2594
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -2565,7 +2608,7 @@ function parsePr(url) {
|
|
|
2565
2608
|
}
|
|
2566
2609
|
|
|
2567
2610
|
// src/issue.ts
|
|
2568
|
-
import { execFileSync as
|
|
2611
|
+
import { execFileSync as execFileSync9 } from "child_process";
|
|
2569
2612
|
var API_TIMEOUT_MS4 = 3e4;
|
|
2570
2613
|
function ghToken2() {
|
|
2571
2614
|
return process.env.GH_PAT?.trim() || process.env.GH_TOKEN;
|
|
@@ -2573,7 +2616,7 @@ function ghToken2() {
|
|
|
2573
2616
|
function gh2(args, options) {
|
|
2574
2617
|
const token = ghToken2();
|
|
2575
2618
|
const env = token ? { ...process.env, GH_TOKEN: token } : { ...process.env };
|
|
2576
|
-
return
|
|
2619
|
+
return execFileSync9("gh", args, {
|
|
2577
2620
|
encoding: "utf-8",
|
|
2578
2621
|
timeout: API_TIMEOUT_MS4,
|
|
2579
2622
|
cwd: options?.cwd,
|
|
@@ -2861,7 +2904,7 @@ function computeFailureReason(ctx) {
|
|
|
2861
2904
|
}
|
|
2862
2905
|
|
|
2863
2906
|
// src/scripts/finishFlow.ts
|
|
2864
|
-
import { execFileSync as
|
|
2907
|
+
import { execFileSync as execFileSync10 } from "child_process";
|
|
2865
2908
|
|
|
2866
2909
|
// src/lifecycleLabels.ts
|
|
2867
2910
|
var KODY_NAMESPACE = "kody";
|
|
@@ -3020,7 +3063,7 @@ var finishFlow = async (ctx, _profile, _agentResult, args) => {
|
|
|
3020
3063
|
**PR:** ${state.core.prUrl}` : "";
|
|
3021
3064
|
const body = `${icon} kody flow \`${flowName}\` finished \u2014 \`${reason}\`${prSuffix}`;
|
|
3022
3065
|
try {
|
|
3023
|
-
|
|
3066
|
+
execFileSync10("gh", ["issue", "comment", String(issueNumber), "--body", body], {
|
|
3024
3067
|
timeout: API_TIMEOUT_MS5,
|
|
3025
3068
|
cwd: ctx.cwd,
|
|
3026
3069
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -3034,7 +3077,7 @@ var finishFlow = async (ctx, _profile, _agentResult, args) => {
|
|
|
3034
3077
|
};
|
|
3035
3078
|
|
|
3036
3079
|
// src/branch.ts
|
|
3037
|
-
import { execFileSync as
|
|
3080
|
+
import { execFileSync as execFileSync11 } from "child_process";
|
|
3038
3081
|
var UncommittedChangesError = class extends Error {
|
|
3039
3082
|
constructor(branch) {
|
|
3040
3083
|
super(`Uncommitted changes on branch '${branch}' \u2014 refusing to run to protect work in progress`);
|
|
@@ -3044,7 +3087,7 @@ var UncommittedChangesError = class extends Error {
|
|
|
3044
3087
|
branch;
|
|
3045
3088
|
};
|
|
3046
3089
|
function git2(args, cwd) {
|
|
3047
|
-
return
|
|
3090
|
+
return execFileSync11("git", args, {
|
|
3048
3091
|
encoding: "utf-8",
|
|
3049
3092
|
timeout: 3e4,
|
|
3050
3093
|
cwd,
|
|
@@ -3069,7 +3112,7 @@ function checkoutPrBranch(prNumber, cwd) {
|
|
|
3069
3112
|
SKIP_HOOKS: "1",
|
|
3070
3113
|
GH_TOKEN: process.env.GH_PAT?.trim() || process.env.GH_TOKEN || ""
|
|
3071
3114
|
};
|
|
3072
|
-
|
|
3115
|
+
execFileSync11("gh", ["pr", "checkout", String(prNumber)], {
|
|
3073
3116
|
cwd,
|
|
3074
3117
|
env,
|
|
3075
3118
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -3136,8 +3179,8 @@ function ensureFeatureBranch(issueNumber, title, defaultBranch, cwd) {
|
|
|
3136
3179
|
}
|
|
3137
3180
|
|
|
3138
3181
|
// src/gha.ts
|
|
3139
|
-
import { execFileSync as
|
|
3140
|
-
import * as
|
|
3182
|
+
import { execFileSync as execFileSync12 } from "child_process";
|
|
3183
|
+
import * as fs16 from "fs";
|
|
3141
3184
|
function getRunUrl() {
|
|
3142
3185
|
const server = process.env.GITHUB_SERVER_URL;
|
|
3143
3186
|
const repo = process.env.GITHUB_REPOSITORY;
|
|
@@ -3148,10 +3191,10 @@ function getRunUrl() {
|
|
|
3148
3191
|
function reactToTriggerComment(cwd) {
|
|
3149
3192
|
if (process.env.GITHUB_EVENT_NAME !== "issue_comment") return;
|
|
3150
3193
|
const eventPath = process.env.GITHUB_EVENT_PATH;
|
|
3151
|
-
if (!eventPath || !
|
|
3194
|
+
if (!eventPath || !fs16.existsSync(eventPath)) return;
|
|
3152
3195
|
let event = null;
|
|
3153
3196
|
try {
|
|
3154
|
-
event = JSON.parse(
|
|
3197
|
+
event = JSON.parse(fs16.readFileSync(eventPath, "utf-8"));
|
|
3155
3198
|
} catch {
|
|
3156
3199
|
return;
|
|
3157
3200
|
}
|
|
@@ -3179,7 +3222,7 @@ function reactToTriggerComment(cwd) {
|
|
|
3179
3222
|
for (let attempt = 0; attempt < 3; attempt++) {
|
|
3180
3223
|
if (attempt > 0) sleepMs(attempt === 1 ? 500 : 1500);
|
|
3181
3224
|
try {
|
|
3182
|
-
|
|
3225
|
+
execFileSync12("gh", args, opts);
|
|
3183
3226
|
return;
|
|
3184
3227
|
} catch (err) {
|
|
3185
3228
|
lastErr = err;
|
|
@@ -3192,13 +3235,13 @@ function reactToTriggerComment(cwd) {
|
|
|
3192
3235
|
}
|
|
3193
3236
|
function sleepMs(ms) {
|
|
3194
3237
|
try {
|
|
3195
|
-
|
|
3238
|
+
execFileSync12("sleep", [(ms / 1e3).toString()], { stdio: "ignore", timeout: ms + 1e3 });
|
|
3196
3239
|
} catch {
|
|
3197
3240
|
}
|
|
3198
3241
|
}
|
|
3199
3242
|
|
|
3200
3243
|
// src/workflow.ts
|
|
3201
|
-
import { execFileSync as
|
|
3244
|
+
import { execFileSync as execFileSync13 } from "child_process";
|
|
3202
3245
|
var GH_TIMEOUT_MS = 3e4;
|
|
3203
3246
|
function ghToken3() {
|
|
3204
3247
|
return process.env.GH_PAT?.trim() || process.env.GH_TOKEN;
|
|
@@ -3206,7 +3249,7 @@ function ghToken3() {
|
|
|
3206
3249
|
function gh3(args, cwd) {
|
|
3207
3250
|
const token = ghToken3();
|
|
3208
3251
|
const env = token ? { ...process.env, GH_TOKEN: token } : { ...process.env };
|
|
3209
|
-
return
|
|
3252
|
+
return execFileSync13("gh", args, {
|
|
3210
3253
|
encoding: "utf-8",
|
|
3211
3254
|
timeout: GH_TIMEOUT_MS,
|
|
3212
3255
|
cwd,
|
|
@@ -3390,23 +3433,23 @@ function tryPostPr2(prNumber, body, cwd) {
|
|
|
3390
3433
|
}
|
|
3391
3434
|
|
|
3392
3435
|
// src/scripts/initFlow.ts
|
|
3393
|
-
import { execFileSync as
|
|
3394
|
-
import * as
|
|
3395
|
-
import * as
|
|
3436
|
+
import { execFileSync as execFileSync14 } from "child_process";
|
|
3437
|
+
import * as fs18 from "fs";
|
|
3438
|
+
import * as path16 from "path";
|
|
3396
3439
|
|
|
3397
3440
|
// src/scripts/loadQaGuide.ts
|
|
3398
|
-
import * as
|
|
3399
|
-
import * as
|
|
3441
|
+
import * as fs17 from "fs";
|
|
3442
|
+
import * as path15 from "path";
|
|
3400
3443
|
var QA_GUIDE_REL_PATH = ".kody/qa-guide.md";
|
|
3401
3444
|
var loadQaGuide = async (ctx) => {
|
|
3402
|
-
const full =
|
|
3403
|
-
if (!
|
|
3445
|
+
const full = path15.join(ctx.cwd, QA_GUIDE_REL_PATH);
|
|
3446
|
+
if (!fs17.existsSync(full)) {
|
|
3404
3447
|
ctx.data.qaGuide = "";
|
|
3405
3448
|
ctx.data.qaGuidePath = "";
|
|
3406
3449
|
return;
|
|
3407
3450
|
}
|
|
3408
3451
|
try {
|
|
3409
|
-
ctx.data.qaGuide =
|
|
3452
|
+
ctx.data.qaGuide = fs17.readFileSync(full, "utf-8");
|
|
3410
3453
|
ctx.data.qaGuidePath = QA_GUIDE_REL_PATH;
|
|
3411
3454
|
} catch {
|
|
3412
3455
|
ctx.data.qaGuide = "";
|
|
@@ -3416,9 +3459,9 @@ var loadQaGuide = async (ctx) => {
|
|
|
3416
3459
|
|
|
3417
3460
|
// src/scripts/initFlow.ts
|
|
3418
3461
|
function detectPackageManager(cwd) {
|
|
3419
|
-
if (
|
|
3420
|
-
if (
|
|
3421
|
-
if (
|
|
3462
|
+
if (fs18.existsSync(path16.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
3463
|
+
if (fs18.existsSync(path16.join(cwd, "yarn.lock"))) return "yarn";
|
|
3464
|
+
if (fs18.existsSync(path16.join(cwd, "bun.lockb"))) return "bun";
|
|
3422
3465
|
return "npm";
|
|
3423
3466
|
}
|
|
3424
3467
|
function qualityCommandsFor(pm) {
|
|
@@ -3431,7 +3474,7 @@ function qualityCommandsFor(pm) {
|
|
|
3431
3474
|
function detectOwnerRepo(cwd) {
|
|
3432
3475
|
let url;
|
|
3433
3476
|
try {
|
|
3434
|
-
url =
|
|
3477
|
+
url = execFileSync14("git", ["remote", "get-url", "origin"], {
|
|
3435
3478
|
cwd,
|
|
3436
3479
|
encoding: "utf-8",
|
|
3437
3480
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -3515,7 +3558,7 @@ jobs:
|
|
|
3515
3558
|
`;
|
|
3516
3559
|
function defaultBranchFromGit(cwd) {
|
|
3517
3560
|
try {
|
|
3518
|
-
const ref =
|
|
3561
|
+
const ref = execFileSync14("git", ["symbolic-ref", "refs/remotes/origin/HEAD"], {
|
|
3519
3562
|
cwd,
|
|
3520
3563
|
encoding: "utf-8",
|
|
3521
3564
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -3523,7 +3566,7 @@ function defaultBranchFromGit(cwd) {
|
|
|
3523
3566
|
return ref.replace("refs/remotes/origin/", "");
|
|
3524
3567
|
} catch {
|
|
3525
3568
|
try {
|
|
3526
|
-
return
|
|
3569
|
+
return execFileSync14("git", ["branch", "--show-current"], {
|
|
3527
3570
|
cwd,
|
|
3528
3571
|
encoding: "utf-8",
|
|
3529
3572
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -3539,33 +3582,33 @@ function performInit(cwd, force) {
|
|
|
3539
3582
|
const pm = detectPackageManager(cwd);
|
|
3540
3583
|
const ownerRepo = detectOwnerRepo(cwd);
|
|
3541
3584
|
const defaultBranch = defaultBranchFromGit(cwd);
|
|
3542
|
-
const configPath =
|
|
3543
|
-
if (
|
|
3585
|
+
const configPath = path16.join(cwd, "kody.config.json");
|
|
3586
|
+
if (fs18.existsSync(configPath) && !force) {
|
|
3544
3587
|
skipped.push("kody.config.json");
|
|
3545
3588
|
} else {
|
|
3546
3589
|
const cfg = makeConfig(pm, ownerRepo, defaultBranch);
|
|
3547
|
-
|
|
3590
|
+
fs18.writeFileSync(configPath, `${JSON.stringify(cfg, null, 2)}
|
|
3548
3591
|
`);
|
|
3549
3592
|
wrote.push("kody.config.json");
|
|
3550
3593
|
}
|
|
3551
|
-
const workflowDir =
|
|
3552
|
-
const workflowPath =
|
|
3553
|
-
if (
|
|
3594
|
+
const workflowDir = path16.join(cwd, ".github", "workflows");
|
|
3595
|
+
const workflowPath = path16.join(workflowDir, "kody.yml");
|
|
3596
|
+
if (fs18.existsSync(workflowPath) && !force) {
|
|
3554
3597
|
skipped.push(".github/workflows/kody.yml");
|
|
3555
3598
|
} else {
|
|
3556
|
-
|
|
3557
|
-
|
|
3599
|
+
fs18.mkdirSync(workflowDir, { recursive: true });
|
|
3600
|
+
fs18.writeFileSync(workflowPath, WORKFLOW_TEMPLATE);
|
|
3558
3601
|
wrote.push(".github/workflows/kody.yml");
|
|
3559
3602
|
}
|
|
3560
|
-
const hasUi =
|
|
3603
|
+
const hasUi = fs18.existsSync(path16.join(cwd, "src/app")) || fs18.existsSync(path16.join(cwd, "app")) || fs18.existsSync(path16.join(cwd, "pages"));
|
|
3561
3604
|
if (hasUi) {
|
|
3562
|
-
const qaGuidePath =
|
|
3563
|
-
if (
|
|
3605
|
+
const qaGuidePath = path16.join(cwd, QA_GUIDE_REL_PATH);
|
|
3606
|
+
if (fs18.existsSync(qaGuidePath) && !force) {
|
|
3564
3607
|
skipped.push(QA_GUIDE_REL_PATH);
|
|
3565
3608
|
} else {
|
|
3566
|
-
|
|
3609
|
+
fs18.mkdirSync(path16.dirname(qaGuidePath), { recursive: true });
|
|
3567
3610
|
const discovery = runQaDiscovery(cwd);
|
|
3568
|
-
|
|
3611
|
+
fs18.writeFileSync(qaGuidePath, generateQaGuideTemplate(discovery));
|
|
3569
3612
|
wrote.push(QA_GUIDE_REL_PATH);
|
|
3570
3613
|
}
|
|
3571
3614
|
}
|
|
@@ -3577,12 +3620,12 @@ function performInit(cwd, force) {
|
|
|
3577
3620
|
continue;
|
|
3578
3621
|
}
|
|
3579
3622
|
if (profile.kind !== "scheduled" || !profile.schedule) continue;
|
|
3580
|
-
const target =
|
|
3581
|
-
if (
|
|
3623
|
+
const target = path16.join(workflowDir, `kody-${exe.name}.yml`);
|
|
3624
|
+
if (fs18.existsSync(target) && !force) {
|
|
3582
3625
|
skipped.push(`.github/workflows/kody-${exe.name}.yml`);
|
|
3583
3626
|
continue;
|
|
3584
3627
|
}
|
|
3585
|
-
|
|
3628
|
+
fs18.writeFileSync(target, renderScheduledWorkflow(exe.name, profile.schedule));
|
|
3586
3629
|
wrote.push(`.github/workflows/kody-${exe.name}.yml`);
|
|
3587
3630
|
}
|
|
3588
3631
|
let labels;
|
|
@@ -3908,7 +3951,7 @@ var persistFlowState = async (ctx) => {
|
|
|
3908
3951
|
};
|
|
3909
3952
|
|
|
3910
3953
|
// src/scripts/postClassification.ts
|
|
3911
|
-
import { execFileSync as
|
|
3954
|
+
import { execFileSync as execFileSync15 } from "child_process";
|
|
3912
3955
|
var API_TIMEOUT_MS6 = 3e4;
|
|
3913
3956
|
var VALID_CLASSES2 = /* @__PURE__ */ new Set(["feature", "bug", "spec", "chore"]);
|
|
3914
3957
|
var postClassification = async (ctx) => {
|
|
@@ -3938,7 +3981,7 @@ var postClassification = async (ctx) => {
|
|
|
3938
3981
|
ctx.cwd
|
|
3939
3982
|
);
|
|
3940
3983
|
try {
|
|
3941
|
-
|
|
3984
|
+
execFileSync15("gh", ["issue", "comment", String(issueNumber), "--body", `@kody ${classification}`], {
|
|
3942
3985
|
cwd: ctx.cwd,
|
|
3943
3986
|
timeout: API_TIMEOUT_MS6,
|
|
3944
3987
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -3972,7 +4015,7 @@ function parseClassification(prSummary) {
|
|
|
3972
4015
|
}
|
|
3973
4016
|
function tryAuditComment(issueNumber, body, cwd) {
|
|
3974
4017
|
try {
|
|
3975
|
-
|
|
4018
|
+
execFileSync15("gh", ["issue", "comment", String(issueNumber), "--body", body], {
|
|
3976
4019
|
cwd,
|
|
3977
4020
|
timeout: API_TIMEOUT_MS6,
|
|
3978
4021
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -4156,9 +4199,9 @@ REVIEW_POSTED=https://github.com/${ctx.config.github.owner}/${ctx.config.github.
|
|
|
4156
4199
|
};
|
|
4157
4200
|
|
|
4158
4201
|
// src/scripts/releaseFlow.ts
|
|
4159
|
-
import { execFileSync as
|
|
4160
|
-
import * as
|
|
4161
|
-
import * as
|
|
4202
|
+
import { execFileSync as execFileSync16, spawnSync } from "child_process";
|
|
4203
|
+
import * as fs19 from "fs";
|
|
4204
|
+
import * as path17 from "path";
|
|
4162
4205
|
function notifyIssue(issueNumber, body, cwd) {
|
|
4163
4206
|
if (!issueNumber || issueNumber <= 0) return;
|
|
4164
4207
|
try {
|
|
@@ -4181,12 +4224,12 @@ function bumpVersion(current, bump) {
|
|
|
4181
4224
|
return `${major}.${minor}.${patch}`;
|
|
4182
4225
|
}
|
|
4183
4226
|
function updateVersionInFile(file, newVersion, cwd) {
|
|
4184
|
-
const abs =
|
|
4185
|
-
if (!
|
|
4186
|
-
const content =
|
|
4227
|
+
const abs = path17.join(cwd, file);
|
|
4228
|
+
if (!fs19.existsSync(abs)) return false;
|
|
4229
|
+
const content = fs19.readFileSync(abs, "utf-8");
|
|
4187
4230
|
const updated = content.replace(/"version"\s*:\s*"[^"]+"/, `"version": "${newVersion}"`);
|
|
4188
4231
|
if (updated === content) return false;
|
|
4189
|
-
|
|
4232
|
+
fs19.writeFileSync(abs, updated);
|
|
4190
4233
|
return true;
|
|
4191
4234
|
}
|
|
4192
4235
|
var FIRST_RELEASE_COMMIT_CAP = 100;
|
|
@@ -4196,7 +4239,7 @@ function generateChangelog(cwd, newVersion, lastTag) {
|
|
|
4196
4239
|
else logArgs.splice(1, 0, `-n${FIRST_RELEASE_COMMIT_CAP}`, "HEAD");
|
|
4197
4240
|
let log = "";
|
|
4198
4241
|
try {
|
|
4199
|
-
log =
|
|
4242
|
+
log = execFileSync16("git", logArgs, {
|
|
4200
4243
|
cwd,
|
|
4201
4244
|
encoding: "utf-8",
|
|
4202
4245
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -4237,23 +4280,23 @@ function generateChangelog(cwd, newVersion, lastTag) {
|
|
|
4237
4280
|
return parts.join("\n");
|
|
4238
4281
|
}
|
|
4239
4282
|
function prependChangelog(cwd, entry) {
|
|
4240
|
-
const p =
|
|
4283
|
+
const p = path17.join(cwd, "CHANGELOG.md");
|
|
4241
4284
|
const header = "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\n";
|
|
4242
|
-
if (
|
|
4243
|
-
const prior =
|
|
4285
|
+
if (fs19.existsSync(p)) {
|
|
4286
|
+
const prior = fs19.readFileSync(p, "utf-8");
|
|
4244
4287
|
if (/^#\s*Changelog\b/m.test(prior)) {
|
|
4245
4288
|
const idx = prior.indexOf("\n", prior.indexOf("# Changelog"));
|
|
4246
|
-
|
|
4289
|
+
fs19.writeFileSync(p, `${prior.slice(0, idx + 1)}
|
|
4247
4290
|
${entry}${prior.slice(idx + 1)}`);
|
|
4248
4291
|
} else {
|
|
4249
|
-
|
|
4292
|
+
fs19.writeFileSync(p, `${header}${entry}${prior}`);
|
|
4250
4293
|
}
|
|
4251
4294
|
} else {
|
|
4252
|
-
|
|
4295
|
+
fs19.writeFileSync(p, `${header}${entry}`);
|
|
4253
4296
|
}
|
|
4254
4297
|
}
|
|
4255
4298
|
function git3(args, cwd, timeout = 6e4) {
|
|
4256
|
-
return
|
|
4299
|
+
return execFileSync16("git", args, {
|
|
4257
4300
|
encoding: "utf-8",
|
|
4258
4301
|
timeout,
|
|
4259
4302
|
cwd,
|
|
@@ -4320,13 +4363,13 @@ function buildIssueNotice(mode, dryRun, ctx) {
|
|
|
4320
4363
|
}
|
|
4321
4364
|
async function runPrepare(args) {
|
|
4322
4365
|
const { cwd, bump, dryRun, versionFiles, ctx } = args;
|
|
4323
|
-
const pkgPath =
|
|
4324
|
-
if (!
|
|
4366
|
+
const pkgPath = path17.join(cwd, "package.json");
|
|
4367
|
+
if (!fs19.existsSync(pkgPath)) {
|
|
4325
4368
|
ctx.output.exitCode = 99;
|
|
4326
4369
|
ctx.output.reason = "release prepare: package.json not found";
|
|
4327
4370
|
return;
|
|
4328
4371
|
}
|
|
4329
|
-
const pkg = JSON.parse(
|
|
4372
|
+
const pkg = JSON.parse(fs19.readFileSync(pkgPath, "utf-8"));
|
|
4330
4373
|
if (typeof pkg.version !== "string") {
|
|
4331
4374
|
ctx.output.exitCode = 99;
|
|
4332
4375
|
ctx.output.reason = "release prepare: package.json has no version";
|
|
@@ -4401,8 +4444,8 @@ Merge this and then run \`kody release --mode finalize\`.`;
|
|
|
4401
4444
|
}
|
|
4402
4445
|
async function runFinalize(args) {
|
|
4403
4446
|
const { cwd, dryRun, timeoutMs, releaseCfg, ctx } = args;
|
|
4404
|
-
const pkgPath =
|
|
4405
|
-
const pkg = JSON.parse(
|
|
4447
|
+
const pkgPath = path17.join(cwd, "package.json");
|
|
4448
|
+
const pkg = JSON.parse(fs19.readFileSync(pkgPath, "utf-8"));
|
|
4406
4449
|
if (typeof pkg.version !== "string") {
|
|
4407
4450
|
ctx.output.exitCode = 99;
|
|
4408
4451
|
ctx.output.reason = "release finalize: package.json has no version";
|
|
@@ -4580,7 +4623,7 @@ var resolveArtifacts = async (ctx, profile) => {
|
|
|
4580
4623
|
};
|
|
4581
4624
|
|
|
4582
4625
|
// src/scripts/resolveFlow.ts
|
|
4583
|
-
import { execFileSync as
|
|
4626
|
+
import { execFileSync as execFileSync17 } from "child_process";
|
|
4584
4627
|
var CONFLICT_DIFF_MAX_BYTES = 4e4;
|
|
4585
4628
|
var resolveFlow = async (ctx) => {
|
|
4586
4629
|
const prNumber = ctx.args.pr;
|
|
@@ -4632,7 +4675,7 @@ var resolveFlow = async (ctx) => {
|
|
|
4632
4675
|
};
|
|
4633
4676
|
function getConflictedFiles(cwd) {
|
|
4634
4677
|
try {
|
|
4635
|
-
const out =
|
|
4678
|
+
const out = execFileSync17("git", ["diff", "--name-only", "--diff-filter=U"], {
|
|
4636
4679
|
encoding: "utf-8",
|
|
4637
4680
|
cwd,
|
|
4638
4681
|
env: { ...process.env, HUSKY: "0" }
|
|
@@ -4647,7 +4690,7 @@ function getConflictMarkersPreview(files, cwd, maxBytes = CONFLICT_DIFF_MAX_BYTE
|
|
|
4647
4690
|
let total = 0;
|
|
4648
4691
|
for (const f of files) {
|
|
4649
4692
|
try {
|
|
4650
|
-
const content =
|
|
4693
|
+
const content = execFileSync17("cat", [f], { encoding: "utf-8", cwd }).toString();
|
|
4651
4694
|
const snippet = `### ${f}
|
|
4652
4695
|
|
|
4653
4696
|
\`\`\`
|
|
@@ -4811,7 +4854,7 @@ var skipAgent = async (ctx) => {
|
|
|
4811
4854
|
};
|
|
4812
4855
|
|
|
4813
4856
|
// src/scripts/startFlow.ts
|
|
4814
|
-
import { execFileSync as
|
|
4857
|
+
import { execFileSync as execFileSync18 } from "child_process";
|
|
4815
4858
|
var API_TIMEOUT_MS7 = 3e4;
|
|
4816
4859
|
var startFlow = async (ctx, profile, _agentResult, args) => {
|
|
4817
4860
|
const entry = args?.entry;
|
|
@@ -4845,7 +4888,7 @@ function postKodyComment(target, issueNumber, state, next, cwd) {
|
|
|
4845
4888
|
const sub = target === "pr" && state?.core.prUrl ? "pr" : "issue";
|
|
4846
4889
|
const body = `@kody ${next}`;
|
|
4847
4890
|
try {
|
|
4848
|
-
|
|
4891
|
+
execFileSync18("gh", [sub, "comment", String(targetNumber), "--body", body], {
|
|
4849
4892
|
timeout: API_TIMEOUT_MS7,
|
|
4850
4893
|
cwd,
|
|
4851
4894
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -4865,7 +4908,7 @@ function parsePr2(url) {
|
|
|
4865
4908
|
}
|
|
4866
4909
|
|
|
4867
4910
|
// src/scripts/syncFlow.ts
|
|
4868
|
-
import { execFileSync as
|
|
4911
|
+
import { execFileSync as execFileSync19 } from "child_process";
|
|
4869
4912
|
var syncFlow = async (ctx) => {
|
|
4870
4913
|
ctx.skipAgent = true;
|
|
4871
4914
|
const prNumber = ctx.args.pr;
|
|
@@ -4924,7 +4967,7 @@ function bail2(ctx, prNumber, reason) {
|
|
|
4924
4967
|
}
|
|
4925
4968
|
function revParseHead(cwd) {
|
|
4926
4969
|
try {
|
|
4927
|
-
return
|
|
4970
|
+
return execFileSync19("git", ["rev-parse", "HEAD"], { cwd, encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] }).toString().trim();
|
|
4928
4971
|
} catch {
|
|
4929
4972
|
return "";
|
|
4930
4973
|
}
|
|
@@ -4932,9 +4975,9 @@ function revParseHead(cwd) {
|
|
|
4932
4975
|
function pushBranch(branch, cwd) {
|
|
4933
4976
|
const env = { ...process.env, HUSKY: "0", SKIP_HOOKS: "1" };
|
|
4934
4977
|
try {
|
|
4935
|
-
|
|
4978
|
+
execFileSync19("git", ["push", "-u", "origin", branch], { cwd, env, stdio: ["ignore", "pipe", "pipe"] });
|
|
4936
4979
|
} catch {
|
|
4937
|
-
|
|
4980
|
+
execFileSync19("git", ["push", "--force-with-lease", "-u", "origin", branch], {
|
|
4938
4981
|
cwd,
|
|
4939
4982
|
env,
|
|
4940
4983
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -5102,7 +5145,7 @@ var watchStalePrsFlow = async (ctx) => {
|
|
|
5102
5145
|
};
|
|
5103
5146
|
|
|
5104
5147
|
// src/scripts/writeRunSummary.ts
|
|
5105
|
-
import * as
|
|
5148
|
+
import * as fs20 from "fs";
|
|
5106
5149
|
var writeRunSummary = async (ctx, profile) => {
|
|
5107
5150
|
const summaryPath = process.env.GITHUB_STEP_SUMMARY;
|
|
5108
5151
|
if (!summaryPath) return;
|
|
@@ -5124,7 +5167,7 @@ var writeRunSummary = async (ctx, profile) => {
|
|
|
5124
5167
|
if (reason) lines.push(`- **Reason:** ${reason}`);
|
|
5125
5168
|
lines.push("");
|
|
5126
5169
|
try {
|
|
5127
|
-
|
|
5170
|
+
fs20.appendFileSync(summaryPath, `${lines.join("\n")}
|
|
5128
5171
|
`);
|
|
5129
5172
|
} catch {
|
|
5130
5173
|
}
|
|
@@ -5154,7 +5197,8 @@ var preflightScripts = {
|
|
|
5154
5197
|
composePrompt,
|
|
5155
5198
|
setLifecycleLabel,
|
|
5156
5199
|
skipAgent,
|
|
5157
|
-
classifyByLabel
|
|
5200
|
+
classifyByLabel,
|
|
5201
|
+
diagMcp
|
|
5158
5202
|
};
|
|
5159
5203
|
var postflightScripts = {
|
|
5160
5204
|
parseAgentResult: parseAgentResult2,
|
|
@@ -5185,7 +5229,7 @@ var allScriptNames = /* @__PURE__ */ new Set([
|
|
|
5185
5229
|
]);
|
|
5186
5230
|
|
|
5187
5231
|
// src/tools.ts
|
|
5188
|
-
import { execFileSync as
|
|
5232
|
+
import { execFileSync as execFileSync20 } from "child_process";
|
|
5189
5233
|
function verifyCliTools(tools, cwd) {
|
|
5190
5234
|
const out = [];
|
|
5191
5235
|
for (const t of tools) out.push(verifyOne(t, cwd));
|
|
@@ -5218,7 +5262,7 @@ function verifyOne(tool, cwd) {
|
|
|
5218
5262
|
}
|
|
5219
5263
|
function runShell2(cmd, cwd, timeoutMs = 3e4) {
|
|
5220
5264
|
try {
|
|
5221
|
-
|
|
5265
|
+
execFileSync20("sh", ["-c", cmd], { cwd, stdio: "pipe", timeout: timeoutMs });
|
|
5222
5266
|
return true;
|
|
5223
5267
|
} catch {
|
|
5224
5268
|
return false;
|
|
@@ -5286,9 +5330,9 @@ async function runExecutable(profileName, input) {
|
|
|
5286
5330
|
data: {},
|
|
5287
5331
|
output: { exitCode: 0 }
|
|
5288
5332
|
};
|
|
5289
|
-
const ndjsonDir =
|
|
5333
|
+
const ndjsonDir = path18.join(input.cwd, ".kody");
|
|
5290
5334
|
const invokeAgent = async (prompt) => {
|
|
5291
|
-
const externalPlugins = (profile.claudeCode.plugins ?? []).map((p) =>
|
|
5335
|
+
const externalPlugins = (profile.claudeCode.plugins ?? []).map((p) => path18.isAbsolute(p) ? p : path18.resolve(profile.dir, p)).filter((p) => p.length > 0);
|
|
5292
5336
|
const syntheticPath = ctx.data.syntheticPluginPath;
|
|
5293
5337
|
const pluginPaths = [...externalPlugins, ...syntheticPath ? [syntheticPath] : []];
|
|
5294
5338
|
return runAgent({
|
|
@@ -5355,17 +5399,17 @@ async function runExecutable(profileName, input) {
|
|
|
5355
5399
|
}
|
|
5356
5400
|
}
|
|
5357
5401
|
function resolveProfilePath(profileName) {
|
|
5358
|
-
const here =
|
|
5402
|
+
const here = path18.dirname(new URL(import.meta.url).pathname);
|
|
5359
5403
|
const candidates = [
|
|
5360
|
-
|
|
5404
|
+
path18.join(here, "executables", profileName, "profile.json"),
|
|
5361
5405
|
// same-dir sibling (dev)
|
|
5362
|
-
|
|
5406
|
+
path18.join(here, "..", "executables", profileName, "profile.json"),
|
|
5363
5407
|
// up one (prod: dist/bin → dist/executables)
|
|
5364
|
-
|
|
5408
|
+
path18.join(here, "..", "src", "executables", profileName, "profile.json")
|
|
5365
5409
|
// fallback
|
|
5366
5410
|
];
|
|
5367
5411
|
for (const c of candidates) {
|
|
5368
|
-
if (
|
|
5412
|
+
if (fs21.existsSync(c)) return c;
|
|
5369
5413
|
}
|
|
5370
5414
|
return candidates[0];
|
|
5371
5415
|
}
|
|
@@ -5541,14 +5585,14 @@ function resolveAuthToken(env = process.env) {
|
|
|
5541
5585
|
return token;
|
|
5542
5586
|
}
|
|
5543
5587
|
function detectPackageManager2(cwd) {
|
|
5544
|
-
if (
|
|
5545
|
-
if (
|
|
5546
|
-
if (
|
|
5588
|
+
if (fs22.existsSync(path19.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
5589
|
+
if (fs22.existsSync(path19.join(cwd, "yarn.lock"))) return "yarn";
|
|
5590
|
+
if (fs22.existsSync(path19.join(cwd, "bun.lockb"))) return "bun";
|
|
5547
5591
|
return "npm";
|
|
5548
5592
|
}
|
|
5549
5593
|
function shellOut(cmd, args, cwd, stream = true) {
|
|
5550
5594
|
try {
|
|
5551
|
-
|
|
5595
|
+
execFileSync21(cmd, args, {
|
|
5552
5596
|
cwd,
|
|
5553
5597
|
stdio: stream ? "inherit" : "pipe",
|
|
5554
5598
|
env: { ...process.env, HUSKY: "0", SKIP_HOOKS: "1", CI: process.env.CI ?? "1" }
|
|
@@ -5561,7 +5605,7 @@ function shellOut(cmd, args, cwd, stream = true) {
|
|
|
5561
5605
|
}
|
|
5562
5606
|
function isOnPath(bin) {
|
|
5563
5607
|
try {
|
|
5564
|
-
|
|
5608
|
+
execFileSync21("which", [bin], { stdio: "pipe" });
|
|
5565
5609
|
return true;
|
|
5566
5610
|
} catch {
|
|
5567
5611
|
return false;
|
|
@@ -5595,7 +5639,7 @@ function installLitellmIfNeeded(cwd) {
|
|
|
5595
5639
|
} catch {
|
|
5596
5640
|
}
|
|
5597
5641
|
try {
|
|
5598
|
-
|
|
5642
|
+
execFileSync21("python3", ["-c", "import litellm"], { stdio: "pipe" });
|
|
5599
5643
|
process.stdout.write("\u2192 kody: litellm already installed\n");
|
|
5600
5644
|
return 0;
|
|
5601
5645
|
} catch {
|
|
@@ -5605,16 +5649,16 @@ function installLitellmIfNeeded(cwd) {
|
|
|
5605
5649
|
}
|
|
5606
5650
|
function configureGitIdentity(cwd) {
|
|
5607
5651
|
try {
|
|
5608
|
-
const name =
|
|
5652
|
+
const name = execFileSync21("git", ["config", "user.name"], { cwd, stdio: "pipe", encoding: "utf-8" }).trim();
|
|
5609
5653
|
if (name) return;
|
|
5610
5654
|
} catch {
|
|
5611
5655
|
}
|
|
5612
5656
|
try {
|
|
5613
|
-
|
|
5657
|
+
execFileSync21("git", ["config", "user.name", "github-actions[bot]"], { cwd, stdio: "pipe" });
|
|
5614
5658
|
} catch {
|
|
5615
5659
|
}
|
|
5616
5660
|
try {
|
|
5617
|
-
|
|
5661
|
+
execFileSync21("git", ["config", "user.email", "41898282+github-actions[bot]@users.noreply.github.com"], {
|
|
5618
5662
|
cwd,
|
|
5619
5663
|
stdio: "pipe"
|
|
5620
5664
|
});
|
|
@@ -5623,11 +5667,11 @@ function configureGitIdentity(cwd) {
|
|
|
5623
5667
|
}
|
|
5624
5668
|
function postFailureTail(issueNumber, cwd, reason) {
|
|
5625
5669
|
if (!issueNumber) return;
|
|
5626
|
-
const logPath =
|
|
5670
|
+
const logPath = path19.join(cwd, ".kody", "last-run.jsonl");
|
|
5627
5671
|
let tail = "";
|
|
5628
5672
|
try {
|
|
5629
|
-
if (
|
|
5630
|
-
const content =
|
|
5673
|
+
if (fs22.existsSync(logPath)) {
|
|
5674
|
+
const content = fs22.readFileSync(logPath, "utf-8");
|
|
5631
5675
|
tail = content.slice(-3e3);
|
|
5632
5676
|
}
|
|
5633
5677
|
} catch {
|
|
@@ -5652,7 +5696,7 @@ async function runCi(argv) {
|
|
|
5652
5696
|
return 0;
|
|
5653
5697
|
}
|
|
5654
5698
|
const args = parseCiArgs(argv);
|
|
5655
|
-
const cwd = args.cwd ?
|
|
5699
|
+
const cwd = args.cwd ? path19.resolve(args.cwd) : process.cwd();
|
|
5656
5700
|
let earlyConfig;
|
|
5657
5701
|
try {
|
|
5658
5702
|
earlyConfig = loadConfig(cwd);
|
|
@@ -5785,15 +5829,15 @@ function parseChatArgs(argv, env = process.env) {
|
|
|
5785
5829
|
return result;
|
|
5786
5830
|
}
|
|
5787
5831
|
function commitChatFiles(cwd, sessionId, verbose) {
|
|
5788
|
-
const sessionFile =
|
|
5789
|
-
const eventsFile =
|
|
5790
|
-
const paths = [sessionFile, eventsFile].filter((p) =>
|
|
5832
|
+
const sessionFile = path20.relative(cwd, sessionFilePath(cwd, sessionId));
|
|
5833
|
+
const eventsFile = path20.relative(cwd, eventsFilePath(cwd, sessionId));
|
|
5834
|
+
const paths = [sessionFile, eventsFile].filter((p) => fs23.existsSync(path20.join(cwd, p)));
|
|
5791
5835
|
if (paths.length === 0) return;
|
|
5792
5836
|
const opts = { cwd, stdio: verbose ? "inherit" : "pipe" };
|
|
5793
5837
|
try {
|
|
5794
|
-
|
|
5795
|
-
|
|
5796
|
-
|
|
5838
|
+
execFileSync22("git", ["add", ...paths], opts);
|
|
5839
|
+
execFileSync22("git", ["commit", "--quiet", "-m", `chat: reply for ${sessionId}`], opts);
|
|
5840
|
+
execFileSync22("git", ["push", "--quiet", "origin", "HEAD"], opts);
|
|
5797
5841
|
} catch (err) {
|
|
5798
5842
|
const msg = err instanceof Error ? err.message : String(err);
|
|
5799
5843
|
process.stderr.write(`[kody:chat] commit/push skipped: ${msg}
|
|
@@ -5825,7 +5869,7 @@ async function runChat(argv) {
|
|
|
5825
5869
|
${CHAT_HELP}`);
|
|
5826
5870
|
return 64;
|
|
5827
5871
|
}
|
|
5828
|
-
const cwd = args.cwd ?
|
|
5872
|
+
const cwd = args.cwd ? path20.resolve(args.cwd) : process.cwd();
|
|
5829
5873
|
const sessionId = args.sessionId;
|
|
5830
5874
|
const unpackedSecrets = unpackAllSecrets();
|
|
5831
5875
|
if (unpackedSecrets > 0) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kody-ade/kody-engine",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.7",
|
|
4
4
|
"description": "kody — autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|