@kody-ade/kody-engine 0.4.59 → 0.4.60
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 +249 -193
- package/dist/executables/goal-scheduler/scheduler.sh +0 -0
- package/dist/executables/release-deploy/deploy.sh +0 -0
- package/dist/executables/release-prepare/prepare.sh +0 -0
- package/dist/executables/release-publish/publish.sh +0 -0
- package/dist/executables/resolve/apply-prefer.sh +0 -0
- package/dist/executables/revert/revert.sh +0 -0
- package/dist/executables/types.ts +10 -0
- package/package.json +15 -14
package/dist/bin/kody.js
CHANGED
|
@@ -303,7 +303,7 @@ var init_verifyMcp = __esm({
|
|
|
303
303
|
// package.json
|
|
304
304
|
var package_default = {
|
|
305
305
|
name: "@kody-ade/kody-engine",
|
|
306
|
-
version: "0.4.
|
|
306
|
+
version: "0.4.60",
|
|
307
307
|
description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
|
|
308
308
|
license: "MIT",
|
|
309
309
|
type: "module",
|
|
@@ -353,8 +353,8 @@ var package_default = {
|
|
|
353
353
|
|
|
354
354
|
// src/chat-cli.ts
|
|
355
355
|
import { execFileSync as execFileSync31 } from "child_process";
|
|
356
|
-
import * as
|
|
357
|
-
import * as
|
|
356
|
+
import * as fs33 from "fs";
|
|
357
|
+
import * as path31 from "path";
|
|
358
358
|
|
|
359
359
|
// src/chat/events.ts
|
|
360
360
|
import * as fs from "fs";
|
|
@@ -1326,8 +1326,8 @@ async function emit2(sink, type, sessionId, suffix, payload) {
|
|
|
1326
1326
|
|
|
1327
1327
|
// src/kody-cli.ts
|
|
1328
1328
|
import { execFileSync as execFileSync30 } from "child_process";
|
|
1329
|
-
import * as
|
|
1330
|
-
import * as
|
|
1329
|
+
import * as fs32 from "fs";
|
|
1330
|
+
import * as path30 from "path";
|
|
1331
1331
|
|
|
1332
1332
|
// src/dispatch.ts
|
|
1333
1333
|
import * as fs8 from "fs";
|
|
@@ -1906,8 +1906,8 @@ function postPrReviewComment(prNumber, body, cwd) {
|
|
|
1906
1906
|
|
|
1907
1907
|
// src/executor.ts
|
|
1908
1908
|
import { execFileSync as execFileSync29, spawn as spawn5 } from "child_process";
|
|
1909
|
-
import * as
|
|
1910
|
-
import * as
|
|
1909
|
+
import * as fs31 from "fs";
|
|
1910
|
+
import * as path29 from "path";
|
|
1911
1911
|
init_events();
|
|
1912
1912
|
|
|
1913
1913
|
// src/profile.ts
|
|
@@ -1972,6 +1972,10 @@ function loadProfile(profilePath) {
|
|
|
1972
1972
|
inputArtifacts: parseInputArtifacts(profilePath, r.input),
|
|
1973
1973
|
outputArtifacts: parseOutputArtifacts(profilePath, r.output),
|
|
1974
1974
|
children,
|
|
1975
|
+
// Default true: preserves legacy bug-safe behaviour where each
|
|
1976
|
+
// container child sees a clean tracked tree (see executor.ts).
|
|
1977
|
+
// Containers opt out by setting `"resetBetweenChildren": false`.
|
|
1978
|
+
resetBetweenChildren: typeof r.resetBetweenChildren === "boolean" ? r.resetBetweenChildren : true,
|
|
1975
1979
|
dir: path8.dirname(profilePath)
|
|
1976
1980
|
};
|
|
1977
1981
|
return profile;
|
|
@@ -3230,13 +3234,36 @@ function defaultLabelMap() {
|
|
|
3230
3234
|
}
|
|
3231
3235
|
|
|
3232
3236
|
// src/scripts/commitAndPush.ts
|
|
3237
|
+
import * as fs14 from "fs";
|
|
3238
|
+
import * as path13 from "path";
|
|
3239
|
+
init_events();
|
|
3233
3240
|
var DEFAULT_COMMIT_MESSAGE = "chore: kody changes";
|
|
3234
|
-
|
|
3241
|
+
function sentinelPathForStage(cwd, profileName) {
|
|
3242
|
+
const runId = resolveRunId();
|
|
3243
|
+
return path13.join(cwd, ".kody", "runs", runId, `commit-${profileName}.lock`);
|
|
3244
|
+
}
|
|
3245
|
+
var commitAndPush2 = async (ctx, profile) => {
|
|
3235
3246
|
const branch = ctx.data.branch;
|
|
3236
3247
|
if (!branch) {
|
|
3237
3248
|
ctx.data.commitResult = { committed: false, pushed: false };
|
|
3238
3249
|
return;
|
|
3239
3250
|
}
|
|
3251
|
+
const idempotencyEnabled = process.env.KODY_COMMIT_IDEMPOTENCY !== "0";
|
|
3252
|
+
const sentinel = idempotencyEnabled ? sentinelPathForStage(ctx.cwd, profile.name) : null;
|
|
3253
|
+
if (sentinel && fs14.existsSync(sentinel)) {
|
|
3254
|
+
try {
|
|
3255
|
+
const replay = JSON.parse(fs14.readFileSync(sentinel, "utf-8"));
|
|
3256
|
+
ctx.data.commitResult = replay.commitResult ?? { committed: false, pushed: false };
|
|
3257
|
+
if (Array.isArray(replay.changedFiles)) ctx.data.changedFiles = replay.changedFiles;
|
|
3258
|
+
if (typeof replay.hasCommitsAhead === "boolean") ctx.data.hasCommitsAhead = replay.hasCommitsAhead;
|
|
3259
|
+
if (replay.salvagedFromMissingMarker) ctx.data.salvagedFromMissingMarker = true;
|
|
3260
|
+
ctx.data.commitIdempotencyReplay = true;
|
|
3261
|
+
process.stderr.write(`[kody commitAndPush] idempotency replay (sentinel ${sentinel})
|
|
3262
|
+
`);
|
|
3263
|
+
return;
|
|
3264
|
+
} catch {
|
|
3265
|
+
}
|
|
3266
|
+
}
|
|
3240
3267
|
const markerMissing = ctx.data.agentMarkerMissing === true;
|
|
3241
3268
|
if (ctx.data.agentDone === false && !markerMissing) {
|
|
3242
3269
|
ctx.data.commitResult = { committed: false, pushed: false, skippedReason: "agentDone=false" };
|
|
@@ -3248,12 +3275,12 @@ var commitAndPush2 = async (ctx) => {
|
|
|
3248
3275
|
}
|
|
3249
3276
|
const message = ctx.data.commitMessage || DEFAULT_COMMIT_MESSAGE;
|
|
3250
3277
|
try {
|
|
3251
|
-
const
|
|
3252
|
-
ctx.data.commitResult =
|
|
3253
|
-
const postCommitFiles =
|
|
3278
|
+
const result2 = commitAndPush(branch, message, ctx.cwd);
|
|
3279
|
+
ctx.data.commitResult = result2;
|
|
3280
|
+
const postCommitFiles = result2.committed ? listFilesInCommit("HEAD", ctx.cwd) : listChangedFiles(ctx.cwd);
|
|
3254
3281
|
ctx.data.changedFiles = postCommitFiles.filter((f) => !isForbiddenPath(f));
|
|
3255
|
-
if (
|
|
3256
|
-
const reason =
|
|
3282
|
+
if (result2.committed && !result2.pushed) {
|
|
3283
|
+
const reason = result2.pushError ?? "push failed (no error detail)";
|
|
3257
3284
|
ctx.data.commitCrash = reason;
|
|
3258
3285
|
if (ctx.output.exitCode === void 0 || ctx.output.exitCode === 0) {
|
|
3259
3286
|
ctx.output.exitCode = 4;
|
|
@@ -3270,15 +3297,36 @@ var commitAndPush2 = async (ctx) => {
|
|
|
3270
3297
|
`);
|
|
3271
3298
|
}
|
|
3272
3299
|
ctx.data.hasCommitsAhead = hasCommitsAhead(branch, ctx.config.git.defaultBranch, ctx.cwd);
|
|
3300
|
+
const result = ctx.data.commitResult;
|
|
3301
|
+
if (sentinel && result?.committed) {
|
|
3302
|
+
try {
|
|
3303
|
+
fs14.mkdirSync(path13.dirname(sentinel), { recursive: true });
|
|
3304
|
+
fs14.writeFileSync(
|
|
3305
|
+
sentinel,
|
|
3306
|
+
JSON.stringify(
|
|
3307
|
+
{
|
|
3308
|
+
commitResult: ctx.data.commitResult,
|
|
3309
|
+
changedFiles: ctx.data.changedFiles,
|
|
3310
|
+
hasCommitsAhead: ctx.data.hasCommitsAhead,
|
|
3311
|
+
salvagedFromMissingMarker: ctx.data.salvagedFromMissingMarker === true,
|
|
3312
|
+
writtenAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3313
|
+
},
|
|
3314
|
+
null,
|
|
3315
|
+
2
|
|
3316
|
+
)
|
|
3317
|
+
);
|
|
3318
|
+
} catch {
|
|
3319
|
+
}
|
|
3320
|
+
}
|
|
3273
3321
|
};
|
|
3274
3322
|
|
|
3275
3323
|
// src/scripts/commitGoalState.ts
|
|
3276
3324
|
import { execFileSync as execFileSync9 } from "child_process";
|
|
3277
|
-
import * as
|
|
3325
|
+
import * as path14 from "path";
|
|
3278
3326
|
var commitGoalState = async (ctx) => {
|
|
3279
3327
|
const goal = ctx.data.goal;
|
|
3280
3328
|
if (!goal) return;
|
|
3281
|
-
const stateRel =
|
|
3329
|
+
const stateRel = path14.posix.join(".kody", "goals", goal.id, "state.json");
|
|
3282
3330
|
try {
|
|
3283
3331
|
execFileSync9("git", ["add", stateRel], { cwd: ctx.cwd, stdio: "pipe" });
|
|
3284
3332
|
} catch (err) {
|
|
@@ -3322,20 +3370,20 @@ function describeCommitMessage(goal) {
|
|
|
3322
3370
|
}
|
|
3323
3371
|
|
|
3324
3372
|
// src/scripts/composePrompt.ts
|
|
3325
|
-
import * as
|
|
3326
|
-
import * as
|
|
3373
|
+
import * as fs15 from "fs";
|
|
3374
|
+
import * as path15 from "path";
|
|
3327
3375
|
var MUSTACHE = /\{\{\s*([a-zA-Z0-9_.-]+)\s*\}\}/g;
|
|
3328
3376
|
var composePrompt = async (ctx, profile) => {
|
|
3329
3377
|
const explicit = ctx.data.promptTemplate;
|
|
3330
3378
|
const mode = ctx.args.mode;
|
|
3331
3379
|
const candidates = [
|
|
3332
|
-
explicit ?
|
|
3333
|
-
mode ?
|
|
3334
|
-
|
|
3380
|
+
explicit ? path15.join(profile.dir, explicit) : null,
|
|
3381
|
+
mode ? path15.join(profile.dir, "prompts", `${mode}.md`) : null,
|
|
3382
|
+
path15.join(profile.dir, "prompt.md")
|
|
3335
3383
|
].filter(Boolean);
|
|
3336
3384
|
let templatePath = "";
|
|
3337
3385
|
for (const c of candidates) {
|
|
3338
|
-
if (
|
|
3386
|
+
if (fs15.existsSync(c)) {
|
|
3339
3387
|
templatePath = c;
|
|
3340
3388
|
break;
|
|
3341
3389
|
}
|
|
@@ -3343,7 +3391,7 @@ var composePrompt = async (ctx, profile) => {
|
|
|
3343
3391
|
if (!templatePath) {
|
|
3344
3392
|
throw new Error(`profile at ${profile.dir}: no prompt template found (tried ${candidates.join(", ")})`);
|
|
3345
3393
|
}
|
|
3346
|
-
const template =
|
|
3394
|
+
const template = fs15.readFileSync(templatePath, "utf-8");
|
|
3347
3395
|
const tokens = {
|
|
3348
3396
|
...stringifyAll(ctx.args, "args."),
|
|
3349
3397
|
...stringifyAll(ctx.data, ""),
|
|
@@ -3421,8 +3469,8 @@ function formatToolsUsage(profile) {
|
|
|
3421
3469
|
|
|
3422
3470
|
// src/scripts/createQaGoal.ts
|
|
3423
3471
|
import { execFileSync as execFileSync10 } from "child_process";
|
|
3424
|
-
import * as
|
|
3425
|
-
import * as
|
|
3472
|
+
import * as fs16 from "fs";
|
|
3473
|
+
import * as path16 from "path";
|
|
3426
3474
|
|
|
3427
3475
|
// src/scripts/postReviewResult.ts
|
|
3428
3476
|
function detectVerdict(body) {
|
|
@@ -3674,8 +3722,8 @@ function createOrUpdateManifestIssue(number, manifest, cwd) {
|
|
|
3674
3722
|
return { number: Number(m[1]), created: true };
|
|
3675
3723
|
}
|
|
3676
3724
|
function writeStateFile(cwd, goalId, lastDispatchedIssue) {
|
|
3677
|
-
const dir =
|
|
3678
|
-
|
|
3725
|
+
const dir = path16.join(cwd, ".kody", "goals", goalId);
|
|
3726
|
+
fs16.mkdirSync(dir, { recursive: true });
|
|
3679
3727
|
const state = {
|
|
3680
3728
|
version: 1,
|
|
3681
3729
|
state: "active",
|
|
@@ -3683,8 +3731,8 @@ function writeStateFile(cwd, goalId, lastDispatchedIssue) {
|
|
|
3683
3731
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3684
3732
|
...typeof lastDispatchedIssue === "number" ? { lastDispatchedIssue } : {}
|
|
3685
3733
|
};
|
|
3686
|
-
const filePath =
|
|
3687
|
-
|
|
3734
|
+
const filePath = path16.join(dir, "state.json");
|
|
3735
|
+
fs16.writeFileSync(filePath, `${JSON.stringify(state, null, 2)}
|
|
3688
3736
|
`);
|
|
3689
3737
|
return filePath;
|
|
3690
3738
|
}
|
|
@@ -4089,7 +4137,10 @@ function mergePrSquash(prNumber, cwd) {
|
|
|
4089
4137
|
}
|
|
4090
4138
|
function editPrBase(prNumber, baseBranch, cwd) {
|
|
4091
4139
|
try {
|
|
4092
|
-
gh(
|
|
4140
|
+
gh(
|
|
4141
|
+
["api", "--method", "PATCH", `repos/{owner}/{repo}/pulls/${prNumber}`, "-f", `base=${baseBranch}`],
|
|
4142
|
+
{ cwd }
|
|
4143
|
+
);
|
|
4093
4144
|
return { ok: true };
|
|
4094
4145
|
} catch (err) {
|
|
4095
4146
|
return fail(err);
|
|
@@ -4174,15 +4225,15 @@ function filterGoalTaskPrs(prs, taskIssueNumbers) {
|
|
|
4174
4225
|
|
|
4175
4226
|
// src/scripts/diagMcp.ts
|
|
4176
4227
|
import { execFileSync as execFileSync11 } from "child_process";
|
|
4177
|
-
import * as
|
|
4228
|
+
import * as fs17 from "fs";
|
|
4178
4229
|
import * as os3 from "os";
|
|
4179
|
-
import * as
|
|
4230
|
+
import * as path17 from "path";
|
|
4180
4231
|
var diagMcp = async (_ctx) => {
|
|
4181
4232
|
const home = os3.homedir();
|
|
4182
|
-
const cacheDir =
|
|
4233
|
+
const cacheDir = path17.join(home, ".cache", "ms-playwright");
|
|
4183
4234
|
let entries = [];
|
|
4184
4235
|
try {
|
|
4185
|
-
entries =
|
|
4236
|
+
entries = fs17.readdirSync(cacheDir);
|
|
4186
4237
|
} catch {
|
|
4187
4238
|
}
|
|
4188
4239
|
const hasChromium = entries.some((e) => e.startsWith("chromium"));
|
|
@@ -4208,17 +4259,17 @@ var diagMcp = async (_ctx) => {
|
|
|
4208
4259
|
};
|
|
4209
4260
|
|
|
4210
4261
|
// src/scripts/discoverQaContext.ts
|
|
4211
|
-
import * as
|
|
4212
|
-
import * as
|
|
4262
|
+
import * as fs19 from "fs";
|
|
4263
|
+
import * as path19 from "path";
|
|
4213
4264
|
|
|
4214
4265
|
// src/scripts/frameworkDetectors.ts
|
|
4215
|
-
import * as
|
|
4216
|
-
import * as
|
|
4266
|
+
import * as fs18 from "fs";
|
|
4267
|
+
import * as path18 from "path";
|
|
4217
4268
|
function detectFrameworks(cwd) {
|
|
4218
4269
|
const out = [];
|
|
4219
4270
|
let deps = {};
|
|
4220
4271
|
try {
|
|
4221
|
-
const pkg = JSON.parse(
|
|
4272
|
+
const pkg = JSON.parse(fs18.readFileSync(path18.join(cwd, "package.json"), "utf-8"));
|
|
4222
4273
|
deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
4223
4274
|
} catch {
|
|
4224
4275
|
return out;
|
|
@@ -4255,7 +4306,7 @@ function detectFrameworks(cwd) {
|
|
|
4255
4306
|
}
|
|
4256
4307
|
function findFile(cwd, candidates) {
|
|
4257
4308
|
for (const c of candidates) {
|
|
4258
|
-
if (
|
|
4309
|
+
if (fs18.existsSync(path18.join(cwd, c))) return c;
|
|
4259
4310
|
}
|
|
4260
4311
|
return null;
|
|
4261
4312
|
}
|
|
@@ -4268,18 +4319,18 @@ var COLLECTION_DIRS = [
|
|
|
4268
4319
|
function discoverPayloadCollections(cwd) {
|
|
4269
4320
|
const out = [];
|
|
4270
4321
|
for (const dir of COLLECTION_DIRS) {
|
|
4271
|
-
const full =
|
|
4272
|
-
if (!
|
|
4322
|
+
const full = path18.join(cwd, dir);
|
|
4323
|
+
if (!fs18.existsSync(full)) continue;
|
|
4273
4324
|
let files;
|
|
4274
4325
|
try {
|
|
4275
|
-
files =
|
|
4326
|
+
files = fs18.readdirSync(full).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
|
|
4276
4327
|
} catch {
|
|
4277
4328
|
continue;
|
|
4278
4329
|
}
|
|
4279
4330
|
for (const file of files) {
|
|
4280
4331
|
try {
|
|
4281
|
-
const filePath =
|
|
4282
|
-
const content =
|
|
4332
|
+
const filePath = path18.join(full, file);
|
|
4333
|
+
const content = fs18.readFileSync(filePath, "utf-8").slice(0, 1e4);
|
|
4283
4334
|
const slugMatch = content.match(/slug:\s*['"]([a-z0-9-]+)['"]/);
|
|
4284
4335
|
if (!slugMatch) continue;
|
|
4285
4336
|
const slug = slugMatch[1];
|
|
@@ -4293,7 +4344,7 @@ function discoverPayloadCollections(cwd) {
|
|
|
4293
4344
|
out.push({
|
|
4294
4345
|
name,
|
|
4295
4346
|
slug,
|
|
4296
|
-
filePath:
|
|
4347
|
+
filePath: path18.relative(cwd, filePath),
|
|
4297
4348
|
fields: fields.slice(0, 20),
|
|
4298
4349
|
hasAdmin
|
|
4299
4350
|
});
|
|
@@ -4307,28 +4358,28 @@ var ADMIN_COMPONENT_DIRS = ["src/ui/admin", "src/admin/components", "src/compone
|
|
|
4307
4358
|
function discoverAdminComponents(cwd, collections) {
|
|
4308
4359
|
const out = [];
|
|
4309
4360
|
for (const dir of ADMIN_COMPONENT_DIRS) {
|
|
4310
|
-
const full =
|
|
4311
|
-
if (!
|
|
4361
|
+
const full = path18.join(cwd, dir);
|
|
4362
|
+
if (!fs18.existsSync(full)) continue;
|
|
4312
4363
|
let entries;
|
|
4313
4364
|
try {
|
|
4314
|
-
entries =
|
|
4365
|
+
entries = fs18.readdirSync(full, { withFileTypes: true });
|
|
4315
4366
|
} catch {
|
|
4316
4367
|
continue;
|
|
4317
4368
|
}
|
|
4318
4369
|
for (const entry of entries) {
|
|
4319
|
-
const entryPath =
|
|
4370
|
+
const entryPath = path18.join(full, entry.name);
|
|
4320
4371
|
let name;
|
|
4321
4372
|
let filePath;
|
|
4322
4373
|
if (entry.isDirectory()) {
|
|
4323
4374
|
const indexFile = ["index.tsx", "index.ts", "index.jsx", "index.js"].find(
|
|
4324
|
-
(f) =>
|
|
4375
|
+
(f) => fs18.existsSync(path18.join(entryPath, f))
|
|
4325
4376
|
);
|
|
4326
4377
|
if (!indexFile) continue;
|
|
4327
4378
|
name = entry.name;
|
|
4328
|
-
filePath =
|
|
4379
|
+
filePath = path18.relative(cwd, path18.join(entryPath, indexFile));
|
|
4329
4380
|
} else if (/\.(tsx?|jsx?)$/.test(entry.name)) {
|
|
4330
4381
|
name = entry.name.replace(/\.(tsx?|jsx?)$/, "");
|
|
4331
|
-
filePath =
|
|
4382
|
+
filePath = path18.relative(cwd, entryPath);
|
|
4332
4383
|
} else {
|
|
4333
4384
|
continue;
|
|
4334
4385
|
}
|
|
@@ -4336,7 +4387,7 @@ function discoverAdminComponents(cwd, collections) {
|
|
|
4336
4387
|
if (collections) {
|
|
4337
4388
|
for (const col of collections) {
|
|
4338
4389
|
try {
|
|
4339
|
-
const colContent =
|
|
4390
|
+
const colContent = fs18.readFileSync(path18.join(cwd, col.filePath), "utf-8");
|
|
4340
4391
|
if (colContent.includes(name)) {
|
|
4341
4392
|
usedInCollection = col.slug;
|
|
4342
4393
|
break;
|
|
@@ -4355,8 +4406,8 @@ function scanApiRoutes(cwd) {
|
|
|
4355
4406
|
const out = [];
|
|
4356
4407
|
const appDirs = ["src/app", "app"];
|
|
4357
4408
|
for (const appDir of appDirs) {
|
|
4358
|
-
const apiDir =
|
|
4359
|
-
if (!
|
|
4409
|
+
const apiDir = path18.join(cwd, appDir, "api");
|
|
4410
|
+
if (!fs18.existsSync(apiDir)) continue;
|
|
4360
4411
|
walkApiRoutes(apiDir, "/api", cwd, out);
|
|
4361
4412
|
break;
|
|
4362
4413
|
}
|
|
@@ -4365,14 +4416,14 @@ function scanApiRoutes(cwd) {
|
|
|
4365
4416
|
function walkApiRoutes(dir, prefix, cwd, out) {
|
|
4366
4417
|
let entries;
|
|
4367
4418
|
try {
|
|
4368
|
-
entries =
|
|
4419
|
+
entries = fs18.readdirSync(dir, { withFileTypes: true });
|
|
4369
4420
|
} catch {
|
|
4370
4421
|
return;
|
|
4371
4422
|
}
|
|
4372
4423
|
const routeFile = entries.find((e) => e.isFile() && /^route\.(ts|js|tsx|jsx)$/.test(e.name));
|
|
4373
4424
|
if (routeFile) {
|
|
4374
4425
|
try {
|
|
4375
|
-
const content =
|
|
4426
|
+
const content = fs18.readFileSync(path18.join(dir, routeFile.name), "utf-8").slice(0, 5e3);
|
|
4376
4427
|
const methods = HTTP_METHODS.filter(
|
|
4377
4428
|
(m) => new RegExp(`export\\s+(?:async\\s+)?function\\s+${m}\\b`).test(content)
|
|
4378
4429
|
);
|
|
@@ -4380,7 +4431,7 @@ function walkApiRoutes(dir, prefix, cwd, out) {
|
|
|
4380
4431
|
out.push({
|
|
4381
4432
|
path: prefix,
|
|
4382
4433
|
methods,
|
|
4383
|
-
filePath:
|
|
4434
|
+
filePath: path18.relative(cwd, path18.join(dir, routeFile.name))
|
|
4384
4435
|
});
|
|
4385
4436
|
}
|
|
4386
4437
|
} catch {
|
|
@@ -4391,7 +4442,7 @@ function walkApiRoutes(dir, prefix, cwd, out) {
|
|
|
4391
4442
|
if (entry.name === "node_modules" || entry.name === ".next") continue;
|
|
4392
4443
|
let segment = entry.name;
|
|
4393
4444
|
if (segment.startsWith("(") && segment.endsWith(")")) {
|
|
4394
|
-
walkApiRoutes(
|
|
4445
|
+
walkApiRoutes(path18.join(dir, entry.name), prefix, cwd, out);
|
|
4395
4446
|
continue;
|
|
4396
4447
|
}
|
|
4397
4448
|
if (segment.startsWith("[[") && segment.endsWith("]]")) {
|
|
@@ -4399,7 +4450,7 @@ function walkApiRoutes(dir, prefix, cwd, out) {
|
|
|
4399
4450
|
} else if (segment.startsWith("[") && segment.endsWith("]")) {
|
|
4400
4451
|
segment = `:${segment.slice(1, -1)}`;
|
|
4401
4452
|
}
|
|
4402
|
-
walkApiRoutes(
|
|
4453
|
+
walkApiRoutes(path18.join(dir, entry.name), `${prefix}/${segment}`, cwd, out);
|
|
4403
4454
|
}
|
|
4404
4455
|
}
|
|
4405
4456
|
var BUILTIN_ENV_VARS = /* @__PURE__ */ new Set([
|
|
@@ -4419,10 +4470,10 @@ var BUILTIN_ENV_VARS = /* @__PURE__ */ new Set([
|
|
|
4419
4470
|
function scanEnvVars(cwd) {
|
|
4420
4471
|
const candidates = [".env.example", ".env.local.example", ".env.template"];
|
|
4421
4472
|
for (const envFile of candidates) {
|
|
4422
|
-
const envPath =
|
|
4423
|
-
if (!
|
|
4473
|
+
const envPath = path18.join(cwd, envFile);
|
|
4474
|
+
if (!fs18.existsSync(envPath)) continue;
|
|
4424
4475
|
try {
|
|
4425
|
-
const content =
|
|
4476
|
+
const content = fs18.readFileSync(envPath, "utf-8");
|
|
4426
4477
|
const vars = [];
|
|
4427
4478
|
for (const line of content.split("\n")) {
|
|
4428
4479
|
const trimmed = line.trim();
|
|
@@ -4470,9 +4521,9 @@ function runQaDiscovery(cwd) {
|
|
|
4470
4521
|
}
|
|
4471
4522
|
function detectDevServer(cwd, out) {
|
|
4472
4523
|
try {
|
|
4473
|
-
const pkg = JSON.parse(
|
|
4524
|
+
const pkg = JSON.parse(fs19.readFileSync(path19.join(cwd, "package.json"), "utf-8"));
|
|
4474
4525
|
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
4475
|
-
const pm =
|
|
4526
|
+
const pm = fs19.existsSync(path19.join(cwd, "pnpm-lock.yaml")) ? "pnpm" : fs19.existsSync(path19.join(cwd, "yarn.lock")) ? "yarn" : fs19.existsSync(path19.join(cwd, "bun.lockb")) ? "bun" : "npm";
|
|
4476
4527
|
if (pkg.scripts?.dev) out.devCommand = `${pm} dev`;
|
|
4477
4528
|
if (allDeps.next || allDeps.nuxt) out.devPort = 3e3;
|
|
4478
4529
|
else if (allDeps.vite) out.devPort = 5173;
|
|
@@ -4482,8 +4533,8 @@ function detectDevServer(cwd, out) {
|
|
|
4482
4533
|
function scanFrontendRoutes(cwd, out) {
|
|
4483
4534
|
const appDirs = ["src/app", "app"];
|
|
4484
4535
|
for (const appDir of appDirs) {
|
|
4485
|
-
const full =
|
|
4486
|
-
if (!
|
|
4536
|
+
const full = path19.join(cwd, appDir);
|
|
4537
|
+
if (!fs19.existsSync(full)) continue;
|
|
4487
4538
|
walkFrontendRoutes(full, "", out);
|
|
4488
4539
|
break;
|
|
4489
4540
|
}
|
|
@@ -4491,7 +4542,7 @@ function scanFrontendRoutes(cwd, out) {
|
|
|
4491
4542
|
function walkFrontendRoutes(dir, prefix, out) {
|
|
4492
4543
|
let entries;
|
|
4493
4544
|
try {
|
|
4494
|
-
entries =
|
|
4545
|
+
entries = fs19.readdirSync(dir, { withFileTypes: true });
|
|
4495
4546
|
} catch {
|
|
4496
4547
|
return;
|
|
4497
4548
|
}
|
|
@@ -4508,7 +4559,7 @@ function walkFrontendRoutes(dir, prefix, out) {
|
|
|
4508
4559
|
if (entry.name === "node_modules" || entry.name === ".next") continue;
|
|
4509
4560
|
let segment = entry.name;
|
|
4510
4561
|
if (segment.startsWith("(") && segment.endsWith(")")) {
|
|
4511
|
-
walkFrontendRoutes(
|
|
4562
|
+
walkFrontendRoutes(path19.join(dir, entry.name), prefix, out);
|
|
4512
4563
|
continue;
|
|
4513
4564
|
}
|
|
4514
4565
|
if (segment.startsWith("[[") && segment.endsWith("]]")) {
|
|
@@ -4516,7 +4567,7 @@ function walkFrontendRoutes(dir, prefix, out) {
|
|
|
4516
4567
|
} else if (segment.startsWith("[") && segment.endsWith("]")) {
|
|
4517
4568
|
segment = `:${segment.slice(1, -1)}`;
|
|
4518
4569
|
}
|
|
4519
|
-
walkFrontendRoutes(
|
|
4570
|
+
walkFrontendRoutes(path19.join(dir, entry.name), `${prefix}/${segment}`, out);
|
|
4520
4571
|
}
|
|
4521
4572
|
}
|
|
4522
4573
|
function detectAuthFiles(cwd, out) {
|
|
@@ -4533,23 +4584,23 @@ function detectAuthFiles(cwd, out) {
|
|
|
4533
4584
|
"src/app/api/oauth"
|
|
4534
4585
|
];
|
|
4535
4586
|
for (const c of candidates) {
|
|
4536
|
-
if (
|
|
4587
|
+
if (fs19.existsSync(path19.join(cwd, c))) out.authFiles.push(c);
|
|
4537
4588
|
}
|
|
4538
4589
|
}
|
|
4539
4590
|
function detectRoles(cwd, out) {
|
|
4540
4591
|
const rolePaths = ["src/types", "src/lib", "src/utils", "src/constants", "src/access", "src/collections"];
|
|
4541
4592
|
for (const rp of rolePaths) {
|
|
4542
|
-
const dir =
|
|
4543
|
-
if (!
|
|
4593
|
+
const dir = path19.join(cwd, rp);
|
|
4594
|
+
if (!fs19.existsSync(dir)) continue;
|
|
4544
4595
|
let files;
|
|
4545
4596
|
try {
|
|
4546
|
-
files =
|
|
4597
|
+
files = fs19.readdirSync(dir).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
|
|
4547
4598
|
} catch {
|
|
4548
4599
|
continue;
|
|
4549
4600
|
}
|
|
4550
4601
|
for (const f of files) {
|
|
4551
4602
|
try {
|
|
4552
|
-
const content =
|
|
4603
|
+
const content = fs19.readFileSync(path19.join(dir, f), "utf-8").slice(0, 5e3);
|
|
4553
4604
|
const roleMatches = content.match(/(?:role|Role|ROLE)\s*[=:]\s*['"](\w+)['"]/g);
|
|
4554
4605
|
if (roleMatches) {
|
|
4555
4606
|
for (const m of roleMatches) {
|
|
@@ -4782,8 +4833,8 @@ function failedAction3(reason) {
|
|
|
4782
4833
|
}
|
|
4783
4834
|
|
|
4784
4835
|
// src/scripts/dispatchJobFileTicks.ts
|
|
4785
|
-
import * as
|
|
4786
|
-
import * as
|
|
4836
|
+
import * as fs21 from "fs";
|
|
4837
|
+
import * as path21 from "path";
|
|
4787
4838
|
|
|
4788
4839
|
// src/scripts/jobFrontmatter.ts
|
|
4789
4840
|
var SCHEDULE_EVERY_VALUES = [
|
|
@@ -5034,8 +5085,8 @@ var ContentsApiBackend = class {
|
|
|
5034
5085
|
};
|
|
5035
5086
|
|
|
5036
5087
|
// src/scripts/jobState/localFileBackend.ts
|
|
5037
|
-
import * as
|
|
5038
|
-
import * as
|
|
5088
|
+
import * as fs20 from "fs";
|
|
5089
|
+
import * as path20 from "path";
|
|
5039
5090
|
var LocalFileBackend = class {
|
|
5040
5091
|
name = "local-file";
|
|
5041
5092
|
cwd;
|
|
@@ -5050,7 +5101,7 @@ var LocalFileBackend = class {
|
|
|
5050
5101
|
if (!opts.owner || !opts.repo) throw new Error("LocalFileBackend: owner and repo are required");
|
|
5051
5102
|
this.cwd = opts.cwd;
|
|
5052
5103
|
this.jobsDir = opts.jobsDir;
|
|
5053
|
-
this.absDir =
|
|
5104
|
+
this.absDir = path20.join(opts.cwd, opts.jobsDir);
|
|
5054
5105
|
this.owner = opts.owner;
|
|
5055
5106
|
this.repo = opts.repo;
|
|
5056
5107
|
this.cache = opts.cache ?? defaultCacheAdapter();
|
|
@@ -5065,7 +5116,7 @@ var LocalFileBackend = class {
|
|
|
5065
5116
|
`);
|
|
5066
5117
|
return;
|
|
5067
5118
|
}
|
|
5068
|
-
|
|
5119
|
+
fs20.mkdirSync(this.absDir, { recursive: true });
|
|
5069
5120
|
const prefix = this.cacheKeyPrefix();
|
|
5070
5121
|
const probeKey = `${prefix}probe-${Date.now()}`;
|
|
5071
5122
|
try {
|
|
@@ -5094,7 +5145,7 @@ var LocalFileBackend = class {
|
|
|
5094
5145
|
`);
|
|
5095
5146
|
return;
|
|
5096
5147
|
}
|
|
5097
|
-
if (!
|
|
5148
|
+
if (!fs20.existsSync(this.absDir)) {
|
|
5098
5149
|
return;
|
|
5099
5150
|
}
|
|
5100
5151
|
const key = `${this.cacheKeyPrefix()}${process.env.GITHUB_RUN_ID ?? "norunid"}-${Date.now()}`;
|
|
@@ -5110,11 +5161,11 @@ var LocalFileBackend = class {
|
|
|
5110
5161
|
}
|
|
5111
5162
|
load(slug) {
|
|
5112
5163
|
const relPath = stateFilePath(this.jobsDir, slug);
|
|
5113
|
-
const absPath =
|
|
5114
|
-
if (!
|
|
5164
|
+
const absPath = path20.join(this.cwd, relPath);
|
|
5165
|
+
if (!fs20.existsSync(absPath)) {
|
|
5115
5166
|
return { path: relPath, handle: null, state: initialStateEnvelope("seed"), created: true };
|
|
5116
5167
|
}
|
|
5117
|
-
const raw =
|
|
5168
|
+
const raw = fs20.readFileSync(absPath, "utf-8");
|
|
5118
5169
|
let parsed;
|
|
5119
5170
|
try {
|
|
5120
5171
|
parsed = JSON.parse(raw);
|
|
@@ -5131,10 +5182,10 @@ var LocalFileBackend = class {
|
|
|
5131
5182
|
if (!loaded.created && isStateUnchanged(loaded.state, next)) {
|
|
5132
5183
|
return false;
|
|
5133
5184
|
}
|
|
5134
|
-
const absPath =
|
|
5135
|
-
|
|
5185
|
+
const absPath = path20.join(this.cwd, loaded.path);
|
|
5186
|
+
fs20.mkdirSync(path20.dirname(absPath), { recursive: true });
|
|
5136
5187
|
const body = JSON.stringify(next, null, 2) + "\n";
|
|
5137
|
-
|
|
5188
|
+
fs20.writeFileSync(absPath, body, "utf-8");
|
|
5138
5189
|
return true;
|
|
5139
5190
|
}
|
|
5140
5191
|
cacheKeyPrefix() {
|
|
@@ -5211,7 +5262,7 @@ var dispatchJobFileTicks = async (ctx, _profile, args) => {
|
|
|
5211
5262
|
await backend.hydrate();
|
|
5212
5263
|
}
|
|
5213
5264
|
try {
|
|
5214
|
-
const slugs = listJobSlugs(
|
|
5265
|
+
const slugs = listJobSlugs(path21.join(ctx.cwd, jobsDir));
|
|
5215
5266
|
ctx.data.jobSlugCount = slugs.length;
|
|
5216
5267
|
if (slugs.length === 0) {
|
|
5217
5268
|
process.stdout.write(`[jobs] no job files in ${jobsDir}
|
|
@@ -5310,17 +5361,17 @@ function formatAgo(ms) {
|
|
|
5310
5361
|
}
|
|
5311
5362
|
function readJobFrontmatter(cwd, jobsDir, slug) {
|
|
5312
5363
|
try {
|
|
5313
|
-
const raw =
|
|
5364
|
+
const raw = fs21.readFileSync(path21.join(cwd, jobsDir, `${slug}.md`), "utf-8");
|
|
5314
5365
|
return splitFrontmatter(raw).frontmatter;
|
|
5315
5366
|
} catch {
|
|
5316
5367
|
return {};
|
|
5317
5368
|
}
|
|
5318
5369
|
}
|
|
5319
5370
|
function listJobSlugs(absDir) {
|
|
5320
|
-
if (!
|
|
5371
|
+
if (!fs21.existsSync(absDir)) return [];
|
|
5321
5372
|
let entries;
|
|
5322
5373
|
try {
|
|
5323
|
-
entries =
|
|
5374
|
+
entries = fs21.readdirSync(absDir, { withFileTypes: true });
|
|
5324
5375
|
} catch {
|
|
5325
5376
|
return [];
|
|
5326
5377
|
}
|
|
@@ -5965,7 +6016,7 @@ function ensureFeatureBranch(issueNumber, title, defaultBranch, cwd, baseBranch)
|
|
|
5965
6016
|
|
|
5966
6017
|
// src/gha.ts
|
|
5967
6018
|
import { execFileSync as execFileSync16 } from "child_process";
|
|
5968
|
-
import * as
|
|
6019
|
+
import * as fs22 from "fs";
|
|
5969
6020
|
function getRunUrl() {
|
|
5970
6021
|
const server = process.env.GITHUB_SERVER_URL;
|
|
5971
6022
|
const repo = process.env.GITHUB_REPOSITORY;
|
|
@@ -5976,10 +6027,10 @@ function getRunUrl() {
|
|
|
5976
6027
|
function reactToTriggerComment(cwd) {
|
|
5977
6028
|
if (process.env.GITHUB_EVENT_NAME !== "issue_comment") return;
|
|
5978
6029
|
const eventPath = process.env.GITHUB_EVENT_PATH;
|
|
5979
|
-
if (!eventPath || !
|
|
6030
|
+
if (!eventPath || !fs22.existsSync(eventPath)) return;
|
|
5980
6031
|
let event = null;
|
|
5981
6032
|
try {
|
|
5982
|
-
event = JSON.parse(
|
|
6033
|
+
event = JSON.parse(fs22.readFileSync(eventPath, "utf-8"));
|
|
5983
6034
|
} catch {
|
|
5984
6035
|
return;
|
|
5985
6036
|
}
|
|
@@ -6264,22 +6315,22 @@ var handleAbandonedGoal = async (ctx) => {
|
|
|
6264
6315
|
|
|
6265
6316
|
// src/scripts/initFlow.ts
|
|
6266
6317
|
import { execFileSync as execFileSync18 } from "child_process";
|
|
6267
|
-
import * as
|
|
6268
|
-
import * as
|
|
6318
|
+
import * as fs24 from "fs";
|
|
6319
|
+
import * as path23 from "path";
|
|
6269
6320
|
|
|
6270
6321
|
// src/scripts/loadQaGuide.ts
|
|
6271
|
-
import * as
|
|
6272
|
-
import * as
|
|
6322
|
+
import * as fs23 from "fs";
|
|
6323
|
+
import * as path22 from "path";
|
|
6273
6324
|
var QA_GUIDE_REL_PATH = ".kody/qa-guide.md";
|
|
6274
6325
|
var loadQaGuide = async (ctx) => {
|
|
6275
|
-
const full =
|
|
6276
|
-
if (!
|
|
6326
|
+
const full = path22.join(ctx.cwd, QA_GUIDE_REL_PATH);
|
|
6327
|
+
if (!fs23.existsSync(full)) {
|
|
6277
6328
|
ctx.data.qaGuide = "";
|
|
6278
6329
|
ctx.data.qaGuidePath = "";
|
|
6279
6330
|
return;
|
|
6280
6331
|
}
|
|
6281
6332
|
try {
|
|
6282
|
-
ctx.data.qaGuide =
|
|
6333
|
+
ctx.data.qaGuide = fs23.readFileSync(full, "utf-8");
|
|
6283
6334
|
ctx.data.qaGuidePath = QA_GUIDE_REL_PATH;
|
|
6284
6335
|
} catch {
|
|
6285
6336
|
ctx.data.qaGuide = "";
|
|
@@ -6289,9 +6340,9 @@ var loadQaGuide = async (ctx) => {
|
|
|
6289
6340
|
|
|
6290
6341
|
// src/scripts/initFlow.ts
|
|
6291
6342
|
function detectPackageManager(cwd) {
|
|
6292
|
-
if (
|
|
6293
|
-
if (
|
|
6294
|
-
if (
|
|
6343
|
+
if (fs24.existsSync(path23.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
6344
|
+
if (fs24.existsSync(path23.join(cwd, "yarn.lock"))) return "yarn";
|
|
6345
|
+
if (fs24.existsSync(path23.join(cwd, "bun.lockb"))) return "bun";
|
|
6295
6346
|
return "npm";
|
|
6296
6347
|
}
|
|
6297
6348
|
function qualityCommandsFor(pm) {
|
|
@@ -6413,48 +6464,48 @@ function performInit(cwd, force) {
|
|
|
6413
6464
|
const pm = detectPackageManager(cwd);
|
|
6414
6465
|
const ownerRepo = detectOwnerRepo(cwd);
|
|
6415
6466
|
const defaultBranch = defaultBranchFromGit(cwd);
|
|
6416
|
-
const configPath =
|
|
6417
|
-
if (
|
|
6467
|
+
const configPath = path23.join(cwd, "kody.config.json");
|
|
6468
|
+
if (fs24.existsSync(configPath) && !force) {
|
|
6418
6469
|
skipped.push("kody.config.json");
|
|
6419
6470
|
} else {
|
|
6420
6471
|
const cfg = makeConfig(pm, ownerRepo, defaultBranch);
|
|
6421
|
-
|
|
6472
|
+
fs24.writeFileSync(configPath, `${JSON.stringify(cfg, null, 2)}
|
|
6422
6473
|
`);
|
|
6423
6474
|
wrote.push("kody.config.json");
|
|
6424
6475
|
}
|
|
6425
|
-
const workflowDir =
|
|
6426
|
-
const workflowPath =
|
|
6427
|
-
if (
|
|
6476
|
+
const workflowDir = path23.join(cwd, ".github", "workflows");
|
|
6477
|
+
const workflowPath = path23.join(workflowDir, "kody.yml");
|
|
6478
|
+
if (fs24.existsSync(workflowPath) && !force) {
|
|
6428
6479
|
skipped.push(".github/workflows/kody.yml");
|
|
6429
6480
|
} else {
|
|
6430
|
-
|
|
6431
|
-
|
|
6481
|
+
fs24.mkdirSync(workflowDir, { recursive: true });
|
|
6482
|
+
fs24.writeFileSync(workflowPath, WORKFLOW_TEMPLATE);
|
|
6432
6483
|
wrote.push(".github/workflows/kody.yml");
|
|
6433
6484
|
}
|
|
6434
|
-
const hasUi =
|
|
6485
|
+
const hasUi = fs24.existsSync(path23.join(cwd, "src/app")) || fs24.existsSync(path23.join(cwd, "app")) || fs24.existsSync(path23.join(cwd, "pages"));
|
|
6435
6486
|
if (hasUi) {
|
|
6436
|
-
const qaGuidePath =
|
|
6437
|
-
if (
|
|
6487
|
+
const qaGuidePath = path23.join(cwd, QA_GUIDE_REL_PATH);
|
|
6488
|
+
if (fs24.existsSync(qaGuidePath) && !force) {
|
|
6438
6489
|
skipped.push(QA_GUIDE_REL_PATH);
|
|
6439
6490
|
} else {
|
|
6440
|
-
|
|
6491
|
+
fs24.mkdirSync(path23.dirname(qaGuidePath), { recursive: true });
|
|
6441
6492
|
const discovery = runQaDiscovery(cwd);
|
|
6442
|
-
|
|
6493
|
+
fs24.writeFileSync(qaGuidePath, generateQaGuideTemplate(discovery));
|
|
6443
6494
|
wrote.push(QA_GUIDE_REL_PATH);
|
|
6444
6495
|
}
|
|
6445
6496
|
}
|
|
6446
6497
|
const builtinJobs = listBuiltinJobs();
|
|
6447
6498
|
if (builtinJobs.length > 0) {
|
|
6448
|
-
const jobsDir =
|
|
6449
|
-
|
|
6499
|
+
const jobsDir = path23.join(cwd, ".kody", "jobs");
|
|
6500
|
+
fs24.mkdirSync(jobsDir, { recursive: true });
|
|
6450
6501
|
for (const job of builtinJobs) {
|
|
6451
|
-
const rel =
|
|
6452
|
-
const target =
|
|
6453
|
-
if (
|
|
6502
|
+
const rel = path23.join(".kody", "jobs", `${job.slug}.md`);
|
|
6503
|
+
const target = path23.join(cwd, rel);
|
|
6504
|
+
if (fs24.existsSync(target) && !force) {
|
|
6454
6505
|
skipped.push(rel);
|
|
6455
6506
|
continue;
|
|
6456
6507
|
}
|
|
6457
|
-
|
|
6508
|
+
fs24.writeFileSync(target, fs24.readFileSync(job.filePath, "utf-8"));
|
|
6458
6509
|
wrote.push(rel);
|
|
6459
6510
|
}
|
|
6460
6511
|
}
|
|
@@ -6466,12 +6517,12 @@ function performInit(cwd, force) {
|
|
|
6466
6517
|
continue;
|
|
6467
6518
|
}
|
|
6468
6519
|
if (profile.kind !== "scheduled" || !profile.schedule) continue;
|
|
6469
|
-
const target =
|
|
6470
|
-
if (
|
|
6520
|
+
const target = path23.join(workflowDir, `kody-${exe.name}.yml`);
|
|
6521
|
+
if (fs24.existsSync(target) && !force) {
|
|
6471
6522
|
skipped.push(`.github/workflows/kody-${exe.name}.yml`);
|
|
6472
6523
|
continue;
|
|
6473
6524
|
}
|
|
6474
|
-
|
|
6525
|
+
fs24.writeFileSync(target, renderScheduledWorkflow(exe.name, profile.schedule));
|
|
6475
6526
|
wrote.push(`.github/workflows/kody-${exe.name}.yml`);
|
|
6476
6527
|
}
|
|
6477
6528
|
let labels;
|
|
@@ -6560,14 +6611,14 @@ var loadCoverageRules = async (ctx) => {
|
|
|
6560
6611
|
};
|
|
6561
6612
|
|
|
6562
6613
|
// src/goal/state.ts
|
|
6563
|
-
import * as
|
|
6564
|
-
import * as
|
|
6614
|
+
import * as fs25 from "fs";
|
|
6615
|
+
import * as path24 from "path";
|
|
6565
6616
|
var VALID_STATES = /* @__PURE__ */ new Set(["active", "abandoned", "closed", "done"]);
|
|
6566
6617
|
var GoalStateError = class extends Error {
|
|
6567
|
-
constructor(
|
|
6568
|
-
super(`Invalid goal state at ${
|
|
6618
|
+
constructor(path32, message) {
|
|
6619
|
+
super(`Invalid goal state at ${path32}:
|
|
6569
6620
|
${message}`);
|
|
6570
|
-
this.path =
|
|
6621
|
+
this.path = path32;
|
|
6571
6622
|
this.name = "GoalStateError";
|
|
6572
6623
|
}
|
|
6573
6624
|
path;
|
|
@@ -6611,16 +6662,16 @@ function serializeGoalState(s) {
|
|
|
6611
6662
|
`;
|
|
6612
6663
|
}
|
|
6613
6664
|
function goalStatePath(cwd, goalId) {
|
|
6614
|
-
return
|
|
6665
|
+
return path24.join(cwd, ".kody", "goals", goalId, "state.json");
|
|
6615
6666
|
}
|
|
6616
6667
|
function readGoalState(cwd, goalId) {
|
|
6617
6668
|
const file = goalStatePath(cwd, goalId);
|
|
6618
|
-
if (!
|
|
6669
|
+
if (!fs25.existsSync(file)) {
|
|
6619
6670
|
throw new GoalStateError(file, "file not found");
|
|
6620
6671
|
}
|
|
6621
6672
|
let raw;
|
|
6622
6673
|
try {
|
|
6623
|
-
raw = JSON.parse(
|
|
6674
|
+
raw = JSON.parse(fs25.readFileSync(file, "utf-8"));
|
|
6624
6675
|
} catch (err) {
|
|
6625
6676
|
throw new GoalStateError(file, `invalid JSON: ${err instanceof Error ? err.message : String(err)}`);
|
|
6626
6677
|
}
|
|
@@ -6628,8 +6679,8 @@ function readGoalState(cwd, goalId) {
|
|
|
6628
6679
|
}
|
|
6629
6680
|
function writeGoalState(cwd, goalId, state) {
|
|
6630
6681
|
const file = goalStatePath(cwd, goalId);
|
|
6631
|
-
|
|
6632
|
-
|
|
6682
|
+
fs25.mkdirSync(path24.dirname(file), { recursive: true });
|
|
6683
|
+
fs25.writeFileSync(file, serializeGoalState(state), "utf-8");
|
|
6633
6684
|
}
|
|
6634
6685
|
function nowIso() {
|
|
6635
6686
|
return (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
@@ -6723,8 +6774,8 @@ var loadIssueStateComment = async (ctx, _profile, args) => {
|
|
|
6723
6774
|
};
|
|
6724
6775
|
|
|
6725
6776
|
// src/scripts/loadJobFromFile.ts
|
|
6726
|
-
import * as
|
|
6727
|
-
import * as
|
|
6777
|
+
import * as fs26 from "fs";
|
|
6778
|
+
import * as path25 from "path";
|
|
6728
6779
|
var loadJobFromFile = async (ctx, _profile, args) => {
|
|
6729
6780
|
const jobsDir = String(args?.jobsDir ?? ".kody/jobs");
|
|
6730
6781
|
const slugArg = String(args?.slugArg ?? "job");
|
|
@@ -6732,11 +6783,11 @@ var loadJobFromFile = async (ctx, _profile, args) => {
|
|
|
6732
6783
|
if (!slug) {
|
|
6733
6784
|
throw new Error(`loadJobFromFile: ctx.args.${slugArg} must be a non-empty slug`);
|
|
6734
6785
|
}
|
|
6735
|
-
const absPath =
|
|
6736
|
-
if (!
|
|
6786
|
+
const absPath = path25.join(ctx.cwd, jobsDir, `${slug}.md`);
|
|
6787
|
+
if (!fs26.existsSync(absPath)) {
|
|
6737
6788
|
throw new Error(`loadJobFromFile: job file not found: ${absPath}`);
|
|
6738
6789
|
}
|
|
6739
|
-
const raw =
|
|
6790
|
+
const raw = fs26.readFileSync(absPath, "utf-8");
|
|
6740
6791
|
const { title, body } = parseJobFile(raw, slug);
|
|
6741
6792
|
const backend = resolveBackend({ config: ctx.config, cwd: ctx.cwd, jobsDir });
|
|
6742
6793
|
const loaded = await backend.load(slug);
|
|
@@ -6768,16 +6819,16 @@ function humanizeSlug(slug) {
|
|
|
6768
6819
|
}
|
|
6769
6820
|
|
|
6770
6821
|
// src/scripts/loadMemoryContext.ts
|
|
6771
|
-
import * as
|
|
6772
|
-
import * as
|
|
6822
|
+
import * as fs27 from "fs";
|
|
6823
|
+
import * as path26 from "path";
|
|
6773
6824
|
var MEMORY_DIR_RELATIVE = ".kody/memory";
|
|
6774
6825
|
var MAX_PAGES = 8;
|
|
6775
6826
|
var PER_PAGE_MAX_BYTES = 4e3;
|
|
6776
6827
|
var TOTAL_MAX_BYTES = 24e3;
|
|
6777
6828
|
var TRUNCATED_SUFFIX = "\n\n\u2026 (truncated)";
|
|
6778
6829
|
var loadMemoryContext = async (ctx) => {
|
|
6779
|
-
const memoryAbs =
|
|
6780
|
-
if (!
|
|
6830
|
+
const memoryAbs = path26.join(ctx.cwd, MEMORY_DIR_RELATIVE);
|
|
6831
|
+
if (!fs27.existsSync(memoryAbs)) {
|
|
6781
6832
|
ctx.data.memoryContext = "";
|
|
6782
6833
|
return;
|
|
6783
6834
|
}
|
|
@@ -6802,21 +6853,21 @@ function collectPages(memoryAbs) {
|
|
|
6802
6853
|
walkMd(memoryAbs, (file) => {
|
|
6803
6854
|
let stat;
|
|
6804
6855
|
try {
|
|
6805
|
-
stat =
|
|
6856
|
+
stat = fs27.statSync(file);
|
|
6806
6857
|
} catch {
|
|
6807
6858
|
return;
|
|
6808
6859
|
}
|
|
6809
6860
|
let raw;
|
|
6810
6861
|
try {
|
|
6811
|
-
raw =
|
|
6862
|
+
raw = fs27.readFileSync(file, "utf-8");
|
|
6812
6863
|
} catch {
|
|
6813
6864
|
return;
|
|
6814
6865
|
}
|
|
6815
6866
|
const fm = raw.match(/^---\s*\n([\s\S]*?)\n---/);
|
|
6816
|
-
const title = fm?.[1]?.match(/^title:\s*(.+)$/m)?.[1]?.trim() ??
|
|
6867
|
+
const title = fm?.[1]?.match(/^title:\s*(.+)$/m)?.[1]?.trim() ?? path26.basename(file, ".md");
|
|
6817
6868
|
const updated = fm?.[1]?.match(/^updated:\s*([0-9T:.+\-Z]+)/m)?.[1]?.trim() ?? "";
|
|
6818
6869
|
out.push({
|
|
6819
|
-
relPath:
|
|
6870
|
+
relPath: path26.relative(memoryAbs, file),
|
|
6820
6871
|
title,
|
|
6821
6872
|
updated,
|
|
6822
6873
|
content: raw.length > PER_PAGE_MAX_BYTES ? raw.slice(0, PER_PAGE_MAX_BYTES) + TRUNCATED_SUFFIX : raw,
|
|
@@ -6884,16 +6935,16 @@ function walkMd(root, visit) {
|
|
|
6884
6935
|
const dir = stack.pop();
|
|
6885
6936
|
let names;
|
|
6886
6937
|
try {
|
|
6887
|
-
names =
|
|
6938
|
+
names = fs27.readdirSync(dir);
|
|
6888
6939
|
} catch {
|
|
6889
6940
|
continue;
|
|
6890
6941
|
}
|
|
6891
6942
|
for (const name of names) {
|
|
6892
6943
|
if (name.startsWith(".")) continue;
|
|
6893
|
-
const full =
|
|
6944
|
+
const full = path26.join(dir, name);
|
|
6894
6945
|
let stat;
|
|
6895
6946
|
try {
|
|
6896
|
-
stat =
|
|
6947
|
+
stat = fs27.statSync(full);
|
|
6897
6948
|
} catch {
|
|
6898
6949
|
continue;
|
|
6899
6950
|
}
|
|
@@ -7001,8 +7052,8 @@ function formatReviewComments(raw) {
|
|
|
7001
7052
|
init_events();
|
|
7002
7053
|
|
|
7003
7054
|
// src/taskContext.ts
|
|
7004
|
-
import * as
|
|
7005
|
-
import * as
|
|
7055
|
+
import * as fs28 from "fs";
|
|
7056
|
+
import * as path27 from "path";
|
|
7006
7057
|
var TASK_CONTEXT_SCHEMA_VERSION = 1;
|
|
7007
7058
|
function buildTaskContext(args) {
|
|
7008
7059
|
return {
|
|
@@ -7018,10 +7069,10 @@ function buildTaskContext(args) {
|
|
|
7018
7069
|
}
|
|
7019
7070
|
function persistTaskContext(cwd, ctx) {
|
|
7020
7071
|
try {
|
|
7021
|
-
const dir =
|
|
7022
|
-
|
|
7023
|
-
const file =
|
|
7024
|
-
|
|
7072
|
+
const dir = path27.join(cwd, ".kody", "runs", ctx.runId);
|
|
7073
|
+
fs28.mkdirSync(dir, { recursive: true });
|
|
7074
|
+
const file = path27.join(dir, "task-context.json");
|
|
7075
|
+
fs28.writeFileSync(file, `${JSON.stringify(ctx, null, 2)}
|
|
7025
7076
|
`);
|
|
7026
7077
|
return file;
|
|
7027
7078
|
} catch (err) {
|
|
@@ -8376,8 +8427,8 @@ function resolveBaseOverride(value) {
|
|
|
8376
8427
|
|
|
8377
8428
|
// src/scripts/runTickScript.ts
|
|
8378
8429
|
import { spawnSync } from "child_process";
|
|
8379
|
-
import * as
|
|
8380
|
-
import * as
|
|
8430
|
+
import * as fs29 from "fs";
|
|
8431
|
+
import * as path28 from "path";
|
|
8381
8432
|
var runTickScript = async (ctx, _profile, args) => {
|
|
8382
8433
|
ctx.skipAgent = true;
|
|
8383
8434
|
const jobsDir = String(args?.jobsDir ?? ".kody/jobs");
|
|
@@ -8389,13 +8440,13 @@ var runTickScript = async (ctx, _profile, args) => {
|
|
|
8389
8440
|
ctx.output.reason = `runTickScript: ctx.args.${slugArg} must be a non-empty slug`;
|
|
8390
8441
|
return;
|
|
8391
8442
|
}
|
|
8392
|
-
const jobPath =
|
|
8393
|
-
if (!
|
|
8443
|
+
const jobPath = path28.join(ctx.cwd, jobsDir, `${slug}.md`);
|
|
8444
|
+
if (!fs29.existsSync(jobPath)) {
|
|
8394
8445
|
ctx.output.exitCode = 99;
|
|
8395
8446
|
ctx.output.reason = `runTickScript: job file not found: ${jobPath}`;
|
|
8396
8447
|
return;
|
|
8397
8448
|
}
|
|
8398
|
-
const raw =
|
|
8449
|
+
const raw = fs29.readFileSync(jobPath, "utf-8");
|
|
8399
8450
|
const { frontmatter } = splitFrontmatter(raw);
|
|
8400
8451
|
const tickScript = frontmatter.tickScript;
|
|
8401
8452
|
if (!tickScript) {
|
|
@@ -8403,8 +8454,8 @@ var runTickScript = async (ctx, _profile, args) => {
|
|
|
8403
8454
|
ctx.output.reason = `runTickScript: job ${slug} has no \`tickScript:\` frontmatter \u2014 route via job-tick instead`;
|
|
8404
8455
|
return;
|
|
8405
8456
|
}
|
|
8406
|
-
const scriptPath =
|
|
8407
|
-
if (!
|
|
8457
|
+
const scriptPath = path28.isAbsolute(tickScript) ? tickScript : path28.join(ctx.cwd, tickScript);
|
|
8458
|
+
if (!fs29.existsSync(scriptPath)) {
|
|
8408
8459
|
ctx.output.exitCode = 99;
|
|
8409
8460
|
ctx.output.reason = `runTickScript: tickScript not found: ${scriptPath}`;
|
|
8410
8461
|
return;
|
|
@@ -9239,7 +9290,7 @@ var writeJobStateFile = async (ctx, _profile, _agentResult, args) => {
|
|
|
9239
9290
|
};
|
|
9240
9291
|
|
|
9241
9292
|
// src/scripts/writeRunSummary.ts
|
|
9242
|
-
import * as
|
|
9293
|
+
import * as fs30 from "fs";
|
|
9243
9294
|
var writeRunSummary = async (ctx, profile) => {
|
|
9244
9295
|
const summaryPath = process.env.GITHUB_STEP_SUMMARY;
|
|
9245
9296
|
if (!summaryPath) return;
|
|
@@ -9261,7 +9312,7 @@ var writeRunSummary = async (ctx, profile) => {
|
|
|
9261
9312
|
if (reason) lines.push(`- **Reason:** ${reason}`);
|
|
9262
9313
|
lines.push("");
|
|
9263
9314
|
try {
|
|
9264
|
-
|
|
9315
|
+
fs30.appendFileSync(summaryPath, `${lines.join("\n")}
|
|
9265
9316
|
`);
|
|
9266
9317
|
} catch {
|
|
9267
9318
|
}
|
|
@@ -9478,9 +9529,9 @@ async function runExecutable(profileName, input) {
|
|
|
9478
9529
|
data: {},
|
|
9479
9530
|
output: { exitCode: 0 }
|
|
9480
9531
|
};
|
|
9481
|
-
const ndjsonDir =
|
|
9532
|
+
const ndjsonDir = path29.join(input.cwd, ".kody");
|
|
9482
9533
|
const invokeAgent = async (prompt) => {
|
|
9483
|
-
const externalPlugins = (profile.claudeCode.plugins ?? []).map((p) =>
|
|
9534
|
+
const externalPlugins = (profile.claudeCode.plugins ?? []).map((p) => path29.isAbsolute(p) ? p : path29.resolve(profile.dir, p)).filter((p) => p.length > 0);
|
|
9484
9535
|
const syntheticPath = ctx.data.syntheticPluginPath;
|
|
9485
9536
|
const pluginPaths = [...externalPlugins, ...syntheticPath ? [syntheticPath] : []];
|
|
9486
9537
|
return runAgent({
|
|
@@ -9648,7 +9699,7 @@ function clearStampedLifecycleLabels(profile, ctx) {
|
|
|
9648
9699
|
function getProfileInputsForChild(profileName, _cwd) {
|
|
9649
9700
|
try {
|
|
9650
9701
|
const profilePath = resolveProfilePath(profileName);
|
|
9651
|
-
if (!
|
|
9702
|
+
if (!fs31.existsSync(profilePath)) return null;
|
|
9652
9703
|
return loadProfile(profilePath).inputs;
|
|
9653
9704
|
} catch {
|
|
9654
9705
|
return null;
|
|
@@ -9657,17 +9708,17 @@ function getProfileInputsForChild(profileName, _cwd) {
|
|
|
9657
9708
|
function resolveProfilePath(profileName) {
|
|
9658
9709
|
const found = resolveExecutable(profileName);
|
|
9659
9710
|
if (found) return found;
|
|
9660
|
-
const here =
|
|
9711
|
+
const here = path29.dirname(new URL(import.meta.url).pathname);
|
|
9661
9712
|
const candidates = [
|
|
9662
|
-
|
|
9713
|
+
path29.join(here, "executables", profileName, "profile.json"),
|
|
9663
9714
|
// same-dir sibling (dev)
|
|
9664
|
-
|
|
9715
|
+
path29.join(here, "..", "executables", profileName, "profile.json"),
|
|
9665
9716
|
// up one (prod: dist/bin → dist/executables)
|
|
9666
|
-
|
|
9717
|
+
path29.join(here, "..", "src", "executables", profileName, "profile.json")
|
|
9667
9718
|
// fallback
|
|
9668
9719
|
];
|
|
9669
9720
|
for (const c of candidates) {
|
|
9670
|
-
if (
|
|
9721
|
+
if (fs31.existsSync(c)) return c;
|
|
9671
9722
|
}
|
|
9672
9723
|
return candidates[0];
|
|
9673
9724
|
}
|
|
@@ -9764,8 +9815,8 @@ function resolveShellTimeoutMs(entry) {
|
|
|
9764
9815
|
var SIGKILL_GRACE_MS = 5e3;
|
|
9765
9816
|
async function runShellEntry(entry, ctx, profile) {
|
|
9766
9817
|
const shellName = entry.shell;
|
|
9767
|
-
const shellPath =
|
|
9768
|
-
if (!
|
|
9818
|
+
const shellPath = path29.join(profile.dir, shellName);
|
|
9819
|
+
if (!fs31.existsSync(shellPath)) {
|
|
9769
9820
|
ctx.skipAgent = true;
|
|
9770
9821
|
ctx.output.exitCode = 99;
|
|
9771
9822
|
ctx.output.reason = `shell script not found: ${shellName} (looked in ${profile.dir})`;
|
|
@@ -9900,7 +9951,12 @@ async function runContainerLoop(profile, ctx, input) {
|
|
|
9900
9951
|
const child = children[currentIdx];
|
|
9901
9952
|
process.stderr.write(`[kody container] step ${iteration}: invoking ${child.exec}
|
|
9902
9953
|
`);
|
|
9903
|
-
|
|
9954
|
+
if (profile.resetBetweenChildren !== false) {
|
|
9955
|
+
resetWorkingTree(input.cwd);
|
|
9956
|
+
} else {
|
|
9957
|
+
process.stderr.write(`[kody container] resetBetweenChildren=false; preserving tracked tree
|
|
9958
|
+
`);
|
|
9959
|
+
}
|
|
9904
9960
|
const priorState = readContainerState(ctx, child, reader);
|
|
9905
9961
|
if (priorState.core?.prUrl) knownPrUrl = priorState.core.prUrl;
|
|
9906
9962
|
const priorAction = priorState.executables?.[child.exec]?.lastAction;
|
|
@@ -10210,9 +10266,9 @@ function resolveAuthToken(env = process.env) {
|
|
|
10210
10266
|
return token;
|
|
10211
10267
|
}
|
|
10212
10268
|
function detectPackageManager2(cwd) {
|
|
10213
|
-
if (
|
|
10214
|
-
if (
|
|
10215
|
-
if (
|
|
10269
|
+
if (fs32.existsSync(path30.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
10270
|
+
if (fs32.existsSync(path30.join(cwd, "yarn.lock"))) return "yarn";
|
|
10271
|
+
if (fs32.existsSync(path30.join(cwd, "bun.lockb"))) return "bun";
|
|
10216
10272
|
return "npm";
|
|
10217
10273
|
}
|
|
10218
10274
|
function shellOut(cmd, args, cwd, stream = true) {
|
|
@@ -10299,11 +10355,11 @@ function configureGitIdentity(cwd) {
|
|
|
10299
10355
|
}
|
|
10300
10356
|
function postFailureTail(issueNumber, cwd, reason) {
|
|
10301
10357
|
if (!issueNumber) return;
|
|
10302
|
-
const logPath =
|
|
10358
|
+
const logPath = path30.join(cwd, ".kody", "last-run.jsonl");
|
|
10303
10359
|
let tail = "";
|
|
10304
10360
|
try {
|
|
10305
|
-
if (
|
|
10306
|
-
const content =
|
|
10361
|
+
if (fs32.existsSync(logPath)) {
|
|
10362
|
+
const content = fs32.readFileSync(logPath, "utf-8");
|
|
10307
10363
|
tail = content.slice(-3e3);
|
|
10308
10364
|
}
|
|
10309
10365
|
} catch {
|
|
@@ -10328,7 +10384,7 @@ async function runCi(argv) {
|
|
|
10328
10384
|
return 0;
|
|
10329
10385
|
}
|
|
10330
10386
|
const args = parseCiArgs(argv);
|
|
10331
|
-
const cwd = args.cwd ?
|
|
10387
|
+
const cwd = args.cwd ? path30.resolve(args.cwd) : process.cwd();
|
|
10332
10388
|
let earlyConfig;
|
|
10333
10389
|
try {
|
|
10334
10390
|
earlyConfig = loadConfig(cwd);
|
|
@@ -10338,9 +10394,9 @@ async function runCi(argv) {
|
|
|
10338
10394
|
const eventName = process.env.GITHUB_EVENT_NAME;
|
|
10339
10395
|
const dispatchEventPath = process.env.GITHUB_EVENT_PATH;
|
|
10340
10396
|
let manualWorkflowDispatch = false;
|
|
10341
|
-
if (!args.issueNumber && !autoFallback && eventName === "workflow_dispatch" && dispatchEventPath &&
|
|
10397
|
+
if (!args.issueNumber && !autoFallback && eventName === "workflow_dispatch" && dispatchEventPath && fs32.existsSync(dispatchEventPath)) {
|
|
10342
10398
|
try {
|
|
10343
|
-
const evt = JSON.parse(
|
|
10399
|
+
const evt = JSON.parse(fs32.readFileSync(dispatchEventPath, "utf-8"));
|
|
10344
10400
|
const issueInput = parseInt(String(evt?.inputs?.issue_number ?? ""), 10);
|
|
10345
10401
|
const sessionInput = String(evt?.inputs?.sessionId ?? "");
|
|
10346
10402
|
manualWorkflowDispatch = !sessionInput && !(Number.isFinite(issueInput) && issueInput > 0);
|
|
@@ -10599,9 +10655,9 @@ function parseChatArgs(argv, env = process.env) {
|
|
|
10599
10655
|
return result;
|
|
10600
10656
|
}
|
|
10601
10657
|
function commitChatFiles(cwd, sessionId, verbose) {
|
|
10602
|
-
const sessionFile =
|
|
10603
|
-
const eventsFile =
|
|
10604
|
-
const paths = [sessionFile, eventsFile].filter((p) =>
|
|
10658
|
+
const sessionFile = path31.relative(cwd, sessionFilePath(cwd, sessionId));
|
|
10659
|
+
const eventsFile = path31.relative(cwd, eventsFilePath(cwd, sessionId));
|
|
10660
|
+
const paths = [sessionFile, eventsFile].filter((p) => fs33.existsSync(path31.join(cwd, p)));
|
|
10605
10661
|
if (paths.length === 0) return;
|
|
10606
10662
|
const opts = { cwd, stdio: verbose ? "inherit" : "pipe" };
|
|
10607
10663
|
try {
|
|
@@ -10639,7 +10695,7 @@ async function runChat(argv) {
|
|
|
10639
10695
|
${CHAT_HELP}`);
|
|
10640
10696
|
return 64;
|
|
10641
10697
|
}
|
|
10642
|
-
const cwd = args.cwd ?
|
|
10698
|
+
const cwd = args.cwd ? path31.resolve(args.cwd) : process.cwd();
|
|
10643
10699
|
const sessionId = args.sessionId;
|
|
10644
10700
|
const unpackedSecrets = unpackAllSecrets();
|
|
10645
10701
|
if (unpackedSecrets > 0) {
|
|
@@ -10691,7 +10747,7 @@ ${CHAT_HELP}`);
|
|
|
10691
10747
|
const sink = buildSink(cwd, sessionId, args.dashboardUrl);
|
|
10692
10748
|
const meta = readMeta(sessionFile);
|
|
10693
10749
|
process.stdout.write(
|
|
10694
|
-
`\u2192 kody:chat: session file=${sessionFile} exists=${
|
|
10750
|
+
`\u2192 kody:chat: session file=${sessionFile} exists=${fs33.existsSync(sessionFile)} meta=${meta ? meta.mode : "none"}
|
|
10695
10751
|
`
|
|
10696
10752
|
);
|
|
10697
10753
|
try {
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -74,6 +74,16 @@ export interface Profile {
|
|
|
74
74
|
* Defines the in-process step sequence and routing map. See ContainerChild.
|
|
75
75
|
*/
|
|
76
76
|
children?: ContainerChild[]
|
|
77
|
+
/**
|
|
78
|
+
* Whether the container should `git reset --hard HEAD` between
|
|
79
|
+
* children to discard tracked-file modifications a prior child left
|
|
80
|
+
* behind. Default `true` (preserves the legacy bug-safe behaviour
|
|
81
|
+
* — see executor.ts:runContainerLoop notes). Set `false` for
|
|
82
|
+
* containers whose children are expected to share intermediate
|
|
83
|
+
* state (e.g. bug's `reproduce` writing a failing test that `run`
|
|
84
|
+
* then makes pass). Only honoured when `role === "container"`.
|
|
85
|
+
*/
|
|
86
|
+
resetBetweenChildren?: boolean
|
|
77
87
|
/** Absolute directory the profile was loaded from. Used to resolve prompt.md. */
|
|
78
88
|
dir: string
|
|
79
89
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kody-ade/kody-engine",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.60",
|
|
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",
|
|
@@ -12,6 +12,18 @@
|
|
|
12
12
|
"templates",
|
|
13
13
|
"kody.config.schema.json"
|
|
14
14
|
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"kody": "tsx bin/kody.ts",
|
|
17
|
+
"build": "tsup && node scripts/copy-assets.cjs",
|
|
18
|
+
"test": "vitest run tests/unit tests/int --no-coverage",
|
|
19
|
+
"test:e2e": "vitest run tests/e2e --no-coverage",
|
|
20
|
+
"test:all": "vitest run tests --no-coverage",
|
|
21
|
+
"typecheck": "tsc --noEmit",
|
|
22
|
+
"lint": "biome check",
|
|
23
|
+
"lint:fix": "biome check --write",
|
|
24
|
+
"format": "biome format --write",
|
|
25
|
+
"prepublishOnly": "pnpm build"
|
|
26
|
+
},
|
|
15
27
|
"dependencies": {
|
|
16
28
|
"@actions/cache": "^6.0.0",
|
|
17
29
|
"@anthropic-ai/claude-agent-sdk": "0.2.119",
|
|
@@ -33,16 +45,5 @@
|
|
|
33
45
|
"url": "git+https://github.com/aharonyaircohen/kody-engine.git"
|
|
34
46
|
},
|
|
35
47
|
"homepage": "https://github.com/aharonyaircohen/kody-engine",
|
|
36
|
-
"bugs": "https://github.com/aharonyaircohen/kody-engine/issues"
|
|
37
|
-
|
|
38
|
-
"kody": "tsx bin/kody.ts",
|
|
39
|
-
"build": "tsup && node scripts/copy-assets.cjs",
|
|
40
|
-
"test": "vitest run tests/unit tests/int --no-coverage",
|
|
41
|
-
"test:e2e": "vitest run tests/e2e --no-coverage",
|
|
42
|
-
"test:all": "vitest run tests --no-coverage",
|
|
43
|
-
"typecheck": "tsc --noEmit",
|
|
44
|
-
"lint": "biome check",
|
|
45
|
-
"lint:fix": "biome check --write",
|
|
46
|
-
"format": "biome format --write"
|
|
47
|
-
}
|
|
48
|
-
}
|
|
48
|
+
"bugs": "https://github.com/aharonyaircohen/kody-engine/issues"
|
|
49
|
+
}
|