@kody-ade/kody-engine 0.4.381 → 0.4.383
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 +262 -86
- package/package.json +24 -25
package/dist/bin/kody.js
CHANGED
|
@@ -15,7 +15,7 @@ var init_package = __esm({
|
|
|
15
15
|
"package.json"() {
|
|
16
16
|
package_default = {
|
|
17
17
|
name: "@kody-ade/kody-engine",
|
|
18
|
-
version: "0.4.
|
|
18
|
+
version: "0.4.383",
|
|
19
19
|
description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative implementation profiles.",
|
|
20
20
|
license: "MIT",
|
|
21
21
|
type: "module",
|
|
@@ -1271,13 +1271,32 @@ var init_events = __esm({
|
|
|
1271
1271
|
|
|
1272
1272
|
// src/verify.ts
|
|
1273
1273
|
import { spawn } from "child_process";
|
|
1274
|
+
function buildVerifyEnv(source = process.env) {
|
|
1275
|
+
const env = { ...source };
|
|
1276
|
+
const rawSecrets = env.ALL_SECRETS;
|
|
1277
|
+
delete env.ALL_SECRETS;
|
|
1278
|
+
if (rawSecrets) {
|
|
1279
|
+
try {
|
|
1280
|
+
const parsed = JSON.parse(rawSecrets);
|
|
1281
|
+
for (const key of Object.keys(parsed)) delete env[key];
|
|
1282
|
+
} catch {
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
for (const key of Object.keys(env)) {
|
|
1286
|
+
if (SENSITIVE_ENV_NAME.test(key)) delete env[key];
|
|
1287
|
+
}
|
|
1288
|
+
env.HUSKY = "0";
|
|
1289
|
+
env.SKIP_HOOKS = "1";
|
|
1290
|
+
env.CI = source.CI ?? "1";
|
|
1291
|
+
return env;
|
|
1292
|
+
}
|
|
1274
1293
|
function runCommand(command, cwd) {
|
|
1275
1294
|
return new Promise((resolve10) => {
|
|
1276
1295
|
const start = Date.now();
|
|
1277
1296
|
const child = spawn(command, {
|
|
1278
1297
|
cwd,
|
|
1279
1298
|
shell: true,
|
|
1280
|
-
env:
|
|
1299
|
+
env: buildVerifyEnv(),
|
|
1281
1300
|
stdio: ["ignore", "pipe", "pipe"]
|
|
1282
1301
|
});
|
|
1283
1302
|
const buffers = [];
|
|
@@ -1369,13 +1388,14 @@ function summarizeFailure(result) {
|
|
|
1369
1388
|
}
|
|
1370
1389
|
return lines.join("\n");
|
|
1371
1390
|
}
|
|
1372
|
-
var TAIL_CHARS, COMMAND_TIMEOUT_MS, DEFAULT_TEST_RETRIES, ANSI_RE;
|
|
1391
|
+
var TAIL_CHARS, COMMAND_TIMEOUT_MS, DEFAULT_TEST_RETRIES, SENSITIVE_ENV_NAME, ANSI_RE;
|
|
1373
1392
|
var init_verify = __esm({
|
|
1374
1393
|
"src/verify.ts"() {
|
|
1375
1394
|
"use strict";
|
|
1376
1395
|
TAIL_CHARS = 4e3;
|
|
1377
1396
|
COMMAND_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
1378
1397
|
DEFAULT_TEST_RETRIES = 2;
|
|
1398
|
+
SENSITIVE_ENV_NAME = /(?:^|_)(?:TOKEN|SECRET|PASSWORD|PASSWD|API_KEY|PRIVATE_KEY|SERVICE_KEY|MASTER_KEY|CREDENTIALS?)(?:_|$)/i;
|
|
1379
1399
|
ANSI_RE = /\x1B\[[0-?]*[ -/]*[@-~]/g;
|
|
1380
1400
|
}
|
|
1381
1401
|
});
|
|
@@ -3757,6 +3777,108 @@ var init_agents = __esm({
|
|
|
3757
3777
|
}
|
|
3758
3778
|
});
|
|
3759
3779
|
|
|
3780
|
+
// src/chat/convex-client.ts
|
|
3781
|
+
import { ConvexHttpClient } from "convex/browser";
|
|
3782
|
+
function isPlainObject2(value) {
|
|
3783
|
+
if (value === null || typeof value !== "object") return false;
|
|
3784
|
+
const proto = Object.getPrototypeOf(value);
|
|
3785
|
+
return proto === Object.prototype || proto === null;
|
|
3786
|
+
}
|
|
3787
|
+
function deepMapKeys(value, mapKey) {
|
|
3788
|
+
if (Array.isArray(value)) return value.map((item) => deepMapKeys(item, mapKey));
|
|
3789
|
+
if (isPlainObject2(value)) {
|
|
3790
|
+
return Object.fromEntries(Object.entries(value).map(([key, item]) => [mapKey(key), deepMapKeys(item, mapKey)]));
|
|
3791
|
+
}
|
|
3792
|
+
return value;
|
|
3793
|
+
}
|
|
3794
|
+
function deepEscapeKeys(value) {
|
|
3795
|
+
return deepMapKeys(value, (k) => NEEDS_ESCAPE.test(k) ? `${ESCAPE_CHAR}${k}` : k);
|
|
3796
|
+
}
|
|
3797
|
+
function deepUnescapeKeys(value) {
|
|
3798
|
+
return deepMapKeys(value, (k) => k.startsWith(ESCAPE_CHAR) ? k.slice(1) : k);
|
|
3799
|
+
}
|
|
3800
|
+
function injectServiceKey(args, serviceKey = process.env.KODY_SERVICE_KEY) {
|
|
3801
|
+
if (!serviceKey) return args;
|
|
3802
|
+
if (args === void 0) return { serviceKey };
|
|
3803
|
+
if (typeof args !== "object" || args === null || Array.isArray(args)) return args;
|
|
3804
|
+
return { ...args, serviceKey };
|
|
3805
|
+
}
|
|
3806
|
+
function withEscapedKeys(client, serviceKey = process.env.KODY_SERVICE_KEY) {
|
|
3807
|
+
return new Proxy(client, {
|
|
3808
|
+
get(target, prop, receiver) {
|
|
3809
|
+
if (CALL_METHODS.includes(prop)) {
|
|
3810
|
+
const method = Reflect.get(target, prop, target);
|
|
3811
|
+
return async (fn, args) => {
|
|
3812
|
+
const authed = injectServiceKey(args, serviceKey);
|
|
3813
|
+
const result = await method.call(target, fn, authed === void 0 ? void 0 : deepEscapeKeys(authed));
|
|
3814
|
+
return deepUnescapeKeys(result);
|
|
3815
|
+
};
|
|
3816
|
+
}
|
|
3817
|
+
const value = Reflect.get(target, prop, receiver);
|
|
3818
|
+
return typeof value === "function" ? value.bind(target) : value;
|
|
3819
|
+
}
|
|
3820
|
+
});
|
|
3821
|
+
}
|
|
3822
|
+
function createConvexClientFromEnv(env = process.env) {
|
|
3823
|
+
const url = env.CONVEX_URL?.trim();
|
|
3824
|
+
if (!url) return null;
|
|
3825
|
+
return withEscapedKeys(new ConvexHttpClient(url), env.KODY_SERVICE_KEY);
|
|
3826
|
+
}
|
|
3827
|
+
var ESCAPE_CHAR, NEEDS_ESCAPE, CALL_METHODS;
|
|
3828
|
+
var init_convex_client = __esm({
|
|
3829
|
+
"src/chat/convex-client.ts"() {
|
|
3830
|
+
"use strict";
|
|
3831
|
+
ESCAPE_CHAR = "~";
|
|
3832
|
+
NEEDS_ESCAPE = /^[$_~]/;
|
|
3833
|
+
CALL_METHODS = ["query", "mutation", "action"];
|
|
3834
|
+
}
|
|
3835
|
+
});
|
|
3836
|
+
|
|
3837
|
+
// src/state-backend.ts
|
|
3838
|
+
import { anyApi } from "convex/server";
|
|
3839
|
+
function requireTenant(tenantId) {
|
|
3840
|
+
const value = tenantId.trim();
|
|
3841
|
+
if (!/^[^/\s]+\/[^/\s]+$/.test(value)) throw new Error("tenantId must be an owner/repository pair");
|
|
3842
|
+
return value;
|
|
3843
|
+
}
|
|
3844
|
+
function requireNonEmpty(value, name) {
|
|
3845
|
+
const normalized = value.trim();
|
|
3846
|
+
if (!normalized) throw new Error(`${name} must not be empty`);
|
|
3847
|
+
return normalized;
|
|
3848
|
+
}
|
|
3849
|
+
function createStateBackendFromEnv(env = process.env, client) {
|
|
3850
|
+
const url = env.CONVEX_URL?.trim();
|
|
3851
|
+
const serviceKey = env.KODY_SERVICE_KEY?.trim();
|
|
3852
|
+
if (!url || !serviceKey) throw new Error("CONVEX_URL and KODY_SERVICE_KEY are required");
|
|
3853
|
+
const transport = client ?? createConvexClientFromEnv(env);
|
|
3854
|
+
return {
|
|
3855
|
+
async get(tenantId, taskKey, kind) {
|
|
3856
|
+
const result = await transport.query(anyApi.taskState.get, {
|
|
3857
|
+
tenantId: requireTenant(tenantId),
|
|
3858
|
+
taskKey: requireNonEmpty(taskKey, "taskKey"),
|
|
3859
|
+
kind: requireNonEmpty(kind, "kind")
|
|
3860
|
+
});
|
|
3861
|
+
return result ?? null;
|
|
3862
|
+
},
|
|
3863
|
+
async save(tenantId, taskKey, kind, doc, expectedUpdatedAt) {
|
|
3864
|
+
await transport.mutation(anyApi.taskState.save, {
|
|
3865
|
+
tenantId: requireTenant(tenantId),
|
|
3866
|
+
taskKey: requireNonEmpty(taskKey, "taskKey"),
|
|
3867
|
+
kind: requireNonEmpty(kind, "kind"),
|
|
3868
|
+
doc,
|
|
3869
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3870
|
+
...expectedUpdatedAt ? { expectedUpdatedAt } : {}
|
|
3871
|
+
});
|
|
3872
|
+
}
|
|
3873
|
+
};
|
|
3874
|
+
}
|
|
3875
|
+
var init_state_backend = __esm({
|
|
3876
|
+
"src/state-backend.ts"() {
|
|
3877
|
+
"use strict";
|
|
3878
|
+
init_convex_client();
|
|
3879
|
+
}
|
|
3880
|
+
});
|
|
3881
|
+
|
|
3760
3882
|
// src/task-artifacts.ts
|
|
3761
3883
|
import fs10 from "fs";
|
|
3762
3884
|
import path12 from "path";
|
|
@@ -3784,7 +3906,29 @@ function verifyTaskArtifacts(absDir) {
|
|
|
3784
3906
|
function taskArtifactStatePath(taskId, file) {
|
|
3785
3907
|
return posixPath.join("tasks", taskId, file);
|
|
3786
3908
|
}
|
|
3787
|
-
function persistTaskArtifactsToState(config, cwd, artifacts) {
|
|
3909
|
+
async function persistTaskArtifactsToState(config, cwd, artifacts) {
|
|
3910
|
+
const tenantId = config.github?.owner && config.github.repo ? `${config.github.owner}/${config.github.repo}` : process.env.GITHUB_REPOSITORY?.trim();
|
|
3911
|
+
if (process.env.CONVEX_URL && process.env.KODY_SERVICE_KEY && tenantId) {
|
|
3912
|
+
const backend = createStateBackendFromEnv();
|
|
3913
|
+
for (const file of TASK_ARTIFACT_FILES) {
|
|
3914
|
+
const full = path12.join(artifacts.absDir, file);
|
|
3915
|
+
if (!fs10.existsSync(full)) continue;
|
|
3916
|
+
const stat = fs10.statSync(full);
|
|
3917
|
+
if (!stat.isFile() || stat.size === 0) continue;
|
|
3918
|
+
const content = fs10.readFileSync(full, "utf-8");
|
|
3919
|
+
const kind = file.replace(/\.(json|md)$/, "");
|
|
3920
|
+
let doc = content;
|
|
3921
|
+
if (file.endsWith(".json")) {
|
|
3922
|
+
try {
|
|
3923
|
+
doc = JSON.parse(content);
|
|
3924
|
+
} catch (err) {
|
|
3925
|
+
throw new Error(`task artifact ${file} is not valid JSON: ${err instanceof Error ? err.message : String(err)}`);
|
|
3926
|
+
}
|
|
3927
|
+
}
|
|
3928
|
+
await backend.save(tenantId, artifacts.taskId, kind, doc);
|
|
3929
|
+
}
|
|
3930
|
+
return;
|
|
3931
|
+
}
|
|
3788
3932
|
for (const file of TASK_ARTIFACT_FILES) {
|
|
3789
3933
|
const full = path12.join(artifacts.absDir, file);
|
|
3790
3934
|
if (!fs10.existsSync(full)) continue;
|
|
@@ -3863,6 +4007,7 @@ var init_task_artifacts = __esm({
|
|
|
3863
4007
|
"src/task-artifacts.ts"() {
|
|
3864
4008
|
"use strict";
|
|
3865
4009
|
init_runtimePaths();
|
|
4010
|
+
init_state_backend();
|
|
3866
4011
|
init_stateRepo();
|
|
3867
4012
|
TASK_ARTIFACT_FILES = ["context.json", "memory-recs.json", "followups.json", "handoff-notes.md"];
|
|
3868
4013
|
}
|
|
@@ -4290,6 +4435,7 @@ function prBranchLifecycle(profile, profilePath) {
|
|
|
4290
4435
|
const tail = [
|
|
4291
4436
|
...verifyChain,
|
|
4292
4437
|
{ script: "commitAndPush" },
|
|
4438
|
+
{ script: "requireDeliveryArtifacts" },
|
|
4293
4439
|
{ script: "ensurePr" },
|
|
4294
4440
|
{ script: "postIssueComment" },
|
|
4295
4441
|
{ script: "writeAgentRunSummary" },
|
|
@@ -5477,7 +5623,7 @@ function renderStateComment(state) {
|
|
|
5477
5623
|
lines.push("</details>");
|
|
5478
5624
|
return lines.join("\n");
|
|
5479
5625
|
}
|
|
5480
|
-
function
|
|
5626
|
+
function readTaskStateLegacy(target, number, cwd, config) {
|
|
5481
5627
|
const stateConfig = taskStateConfig(cwd, config);
|
|
5482
5628
|
const loaded = readStateText(stateConfig, cwd, taskStatePath(target, number));
|
|
5483
5629
|
if (!loaded) return emptyState();
|
|
@@ -5491,13 +5637,34 @@ function readTaskState(target, number, cwd, config) {
|
|
|
5491
5637
|
}
|
|
5492
5638
|
return normalizeTaskState(parsed);
|
|
5493
5639
|
}
|
|
5640
|
+
function backendScope(config) {
|
|
5641
|
+
const tenantId = config?.github?.owner && config.github.repo ? `${config.github.owner}/${config.github.repo}` : process.env.GITHUB_REPOSITORY?.trim();
|
|
5642
|
+
if (!process.env.CONVEX_URL || !process.env.KODY_SERVICE_KEY || !tenantId) return null;
|
|
5643
|
+
return { tenantId };
|
|
5644
|
+
}
|
|
5645
|
+
async function readTaskState(target, number, cwd, config) {
|
|
5646
|
+
const scope = backendScope(config);
|
|
5647
|
+
if (!scope) return readTaskStateLegacy(target, number, cwd, config);
|
|
5648
|
+
const backend = createStateBackendFromEnv();
|
|
5649
|
+
const kind = "state";
|
|
5650
|
+
const taskKey = `${target === "issue" ? "issues" : "prs"}/${number}`;
|
|
5651
|
+
const record = await backend.get(scope.tenantId, taskKey, kind);
|
|
5652
|
+
if (!record) return emptyState();
|
|
5653
|
+
try {
|
|
5654
|
+
return normalizeTaskState(record.doc);
|
|
5655
|
+
} catch (err) {
|
|
5656
|
+
throw new CorruptStateError(
|
|
5657
|
+
`backend task state unparseable for ${taskKey}: ${err instanceof Error ? err.message : String(err)}`
|
|
5658
|
+
);
|
|
5659
|
+
}
|
|
5660
|
+
}
|
|
5494
5661
|
function setArtifact(state, name, artifact) {
|
|
5495
5662
|
return {
|
|
5496
5663
|
...state,
|
|
5497
5664
|
artifacts: { ...state.artifacts ?? {}, [name]: artifact }
|
|
5498
5665
|
};
|
|
5499
5666
|
}
|
|
5500
|
-
function
|
|
5667
|
+
function writeTaskStateLegacy(target, number, state, cwd, config) {
|
|
5501
5668
|
const stateConfig = taskStateConfig(cwd, config);
|
|
5502
5669
|
upsertStateText(
|
|
5503
5670
|
stateConfig,
|
|
@@ -5508,11 +5675,21 @@ function writeTaskState(target, number, state, cwd, config) {
|
|
|
5508
5675
|
`chore(tasks): update ${target} ${number} state`
|
|
5509
5676
|
);
|
|
5510
5677
|
}
|
|
5511
|
-
|
|
5678
|
+
async function writeTaskState(target, number, state, cwd, config) {
|
|
5679
|
+
const scope = backendScope(config);
|
|
5680
|
+
if (!scope) {
|
|
5681
|
+
writeTaskStateLegacy(target, number, state, cwd, config);
|
|
5682
|
+
return;
|
|
5683
|
+
}
|
|
5684
|
+
const backend = createStateBackendFromEnv();
|
|
5685
|
+
await backend.save(scope.tenantId, `${target === "issue" ? "issues" : "prs"}/${number}`, "state", state);
|
|
5686
|
+
}
|
|
5687
|
+
var STATE_BEGIN, STATE_END, HISTORY_MAX_ENTRIES, JOB_RUNS_MAX_ENTRIES, CorruptStateError, readTaskStateAsync;
|
|
5512
5688
|
var init_state = __esm({
|
|
5513
5689
|
"src/state.ts"() {
|
|
5514
5690
|
"use strict";
|
|
5515
5691
|
init_config();
|
|
5692
|
+
init_state_backend();
|
|
5516
5693
|
init_stateRepo();
|
|
5517
5694
|
STATE_BEGIN = "<!-- kody:state:v1:begin -->";
|
|
5518
5695
|
STATE_END = "<!-- kody:state:v1:end -->";
|
|
@@ -5524,6 +5701,7 @@ var init_state = __esm({
|
|
|
5524
5701
|
this.name = "CorruptStateError";
|
|
5525
5702
|
}
|
|
5526
5703
|
};
|
|
5704
|
+
readTaskStateAsync = readTaskState;
|
|
5527
5705
|
}
|
|
5528
5706
|
});
|
|
5529
5707
|
|
|
@@ -5958,7 +6136,7 @@ async function runContainerLoop(profile, ctx, input) {
|
|
|
5958
6136
|
return;
|
|
5959
6137
|
}
|
|
5960
6138
|
const runChild = input.__runChild ?? ((name, opts) => runImplementation(name, opts));
|
|
5961
|
-
const reader = input.__readTaskState ??
|
|
6139
|
+
const reader = input.__readTaskState ?? readTaskStateAsync;
|
|
5962
6140
|
const issueNumber = ctx.args.issue;
|
|
5963
6141
|
let preloadedSnapshot;
|
|
5964
6142
|
if (profile.preloadContext) {
|
|
@@ -6008,7 +6186,7 @@ async function runContainerLoop(profile, ctx, input) {
|
|
|
6008
6186
|
process.stderr.write(`[kody container] resetBetweenChildren=false; preserving tracked tree
|
|
6009
6187
|
`);
|
|
6010
6188
|
}
|
|
6011
|
-
const priorState = readContainerState(ctx, child, reader);
|
|
6189
|
+
const priorState = await readContainerState(ctx, child, reader);
|
|
6012
6190
|
if (priorState.core?.prUrl) knownPrUrl = priorState.core.prUrl;
|
|
6013
6191
|
const priorAction = priorState.implementations?.[child.implementation]?.lastAction;
|
|
6014
6192
|
let actionType2;
|
|
@@ -6102,7 +6280,7 @@ async function runContainerLoop(profile, ctx, input) {
|
|
|
6102
6280
|
else process.env.KODY_CONTAINER_PARENT = priorParent;
|
|
6103
6281
|
}
|
|
6104
6282
|
const priorAttempts = priorState.core?.attempts?.[child.implementation] ?? 0;
|
|
6105
|
-
const next = readContainerState(ctx, child, reader);
|
|
6283
|
+
const next = await readContainerState(ctx, child, reader);
|
|
6106
6284
|
if (next.core?.prUrl) knownPrUrl = next.core.prUrl;
|
|
6107
6285
|
const nextAttempts = next.core?.attempts?.[child.implementation] ?? 0;
|
|
6108
6286
|
const nextChildAction = next.implementations?.[child.implementation]?.lastAction;
|
|
@@ -6189,20 +6367,20 @@ function resetWorkingTree(cwd) {
|
|
|
6189
6367
|
`);
|
|
6190
6368
|
}
|
|
6191
6369
|
}
|
|
6192
|
-
function readContainerState(ctx, child, reader) {
|
|
6370
|
+
async function readContainerState(ctx, child, reader) {
|
|
6193
6371
|
const issueNumber = ctx.args.issue;
|
|
6194
6372
|
const cached2 = ctx.data.taskState;
|
|
6195
6373
|
const prUrl = cached2?.core?.prUrl;
|
|
6196
6374
|
const prNumber = prUrl ? parsePrNumber2(prUrl) : null;
|
|
6197
6375
|
if (child.target === "pr" && prNumber) {
|
|
6198
6376
|
try {
|
|
6199
|
-
return reader("pr", prNumber, ctx.cwd);
|
|
6377
|
+
return await reader("pr", prNumber, ctx.cwd);
|
|
6200
6378
|
} catch {
|
|
6201
6379
|
}
|
|
6202
6380
|
}
|
|
6203
6381
|
if (issueNumber !== void 0) {
|
|
6204
6382
|
try {
|
|
6205
|
-
return reader("issue", issueNumber, ctx.cwd);
|
|
6383
|
+
return await reader("issue", issueNumber, ctx.cwd);
|
|
6206
6384
|
} catch {
|
|
6207
6385
|
}
|
|
6208
6386
|
}
|
|
@@ -7360,7 +7538,7 @@ var init_saveTaskState = __esm({
|
|
|
7360
7538
|
if (ctx.output.prUrl) next.core.prUrl = ctx.output.prUrl;
|
|
7361
7539
|
if (typeof ctx.data.runUrl === "string") next.core.runUrl = ctx.data.runUrl;
|
|
7362
7540
|
applyStandaloneFinalState(next, ctx, profile);
|
|
7363
|
-
writeTaskState(target, number, next, ctx.cwd, ctx.config);
|
|
7541
|
+
await writeTaskState(target, number, next, ctx.cwd, ctx.config);
|
|
7364
7542
|
ctx.data.taskState = next;
|
|
7365
7543
|
ctx.data.taskStateRendered = renderStateComment(next);
|
|
7366
7544
|
};
|
|
@@ -7398,7 +7576,7 @@ var init_advanceFlow = __esm({
|
|
|
7398
7576
|
const curState = state;
|
|
7399
7577
|
let issueState;
|
|
7400
7578
|
try {
|
|
7401
|
-
issueState = readTaskState("issue", flow.issueNumber, ctx.cwd, ctx.config);
|
|
7579
|
+
issueState = await readTaskState("issue", flow.issueNumber, ctx.cwd, ctx.config);
|
|
7402
7580
|
} catch {
|
|
7403
7581
|
issueState = curState;
|
|
7404
7582
|
}
|
|
@@ -7414,7 +7592,7 @@ var init_advanceFlow = __esm({
|
|
|
7414
7592
|
if (hops > FLOW_HOP_CAP) {
|
|
7415
7593
|
nextIssueState.flow = void 0;
|
|
7416
7594
|
try {
|
|
7417
|
-
writeTaskState("issue", flow.issueNumber, nextIssueState, ctx.cwd, ctx.config);
|
|
7595
|
+
await writeTaskState("issue", flow.issueNumber, nextIssueState, ctx.cwd, ctx.config);
|
|
7418
7596
|
} catch (err) {
|
|
7419
7597
|
process.stderr.write(
|
|
7420
7598
|
`[kody advanceFlow] failed to clear looping flow on issue #${flow.issueNumber}: ${err instanceof Error ? err.message : String(err)}
|
|
@@ -7435,7 +7613,7 @@ var init_advanceFlow = __esm({
|
|
|
7435
7613
|
}
|
|
7436
7614
|
nextIssueState.flow = { ...flow, hops };
|
|
7437
7615
|
try {
|
|
7438
|
-
writeTaskState("issue", flow.issueNumber, nextIssueState, ctx.cwd, ctx.config);
|
|
7616
|
+
await writeTaskState("issue", flow.issueNumber, nextIssueState, ctx.cwd, ctx.config);
|
|
7439
7617
|
} catch (err) {
|
|
7440
7618
|
process.stderr.write(
|
|
7441
7619
|
`[kody advanceFlow] failed to persist hop count on issue #${flow.issueNumber}: ${err instanceof Error ? err.message : String(err)}
|
|
@@ -13147,7 +13325,7 @@ var init_dispatchClassified = __esm({
|
|
|
13147
13325
|
const nextState = reduce(state, "classify", action, void 0, profile.agent, jobMetaFromData(ctx.data));
|
|
13148
13326
|
ctx.data.taskState = nextState;
|
|
13149
13327
|
ctx.data.taskStateRendered = renderStateComment(nextState);
|
|
13150
|
-
writeTaskState("issue", issueNumber, nextState, ctx.cwd, ctx.config);
|
|
13328
|
+
await writeTaskState("issue", issueNumber, nextState, ctx.cwd, ctx.config);
|
|
13151
13329
|
const cliArgs = { issue: issueNumber };
|
|
13152
13330
|
if (base && getProfileInputs(classification)?.some((i) => i.name === "base")) {
|
|
13153
13331
|
cliArgs.base = base;
|
|
@@ -13553,7 +13731,7 @@ var init_ensurePr = __esm({
|
|
|
13553
13731
|
draft: isFailure,
|
|
13554
13732
|
failureReason: isFailure ? failureReason : void 0,
|
|
13555
13733
|
changedFiles,
|
|
13556
|
-
agentSummary: ctx.data.prSummary,
|
|
13734
|
+
agentSummary: ctx.data.prSummary || ctx.data.agentFallbackSummary,
|
|
13557
13735
|
baseBranch,
|
|
13558
13736
|
// No fresh commit this run → don't rebuild the body of an existing PR;
|
|
13559
13737
|
// it would replace the original agent summary with the empty fallback.
|
|
@@ -13660,7 +13838,7 @@ var init_finalizeTerminal = __esm({
|
|
|
13660
13838
|
if (prNumber && prNumber !== issueNumber) setKodyLabel(prNumber, spec, ctx.cwd);
|
|
13661
13839
|
if (!state) {
|
|
13662
13840
|
try {
|
|
13663
|
-
state = readTaskState(target, targetNumber, ctx.cwd, ctx.config);
|
|
13841
|
+
state = await readTaskState(target, targetNumber, ctx.cwd, ctx.config);
|
|
13664
13842
|
} catch {
|
|
13665
13843
|
state = void 0;
|
|
13666
13844
|
}
|
|
@@ -13679,7 +13857,7 @@ var init_finalizeTerminal = __esm({
|
|
|
13679
13857
|
};
|
|
13680
13858
|
ctx.data.taskState = next;
|
|
13681
13859
|
try {
|
|
13682
|
-
writeTaskState(target, targetNumber, next, ctx.cwd, ctx.config);
|
|
13860
|
+
await writeTaskState(target, targetNumber, next, ctx.cwd, ctx.config);
|
|
13683
13861
|
} catch (err) {
|
|
13684
13862
|
process.stderr.write(
|
|
13685
13863
|
`[kody finalizeTerminal] failed to write terminal state on ${target} #${targetNumber}: ${err instanceof Error ? err.message : String(err)}
|
|
@@ -13757,7 +13935,7 @@ var init_finishFlow = __esm({
|
|
|
13757
13935
|
const target = ctx.data.commentTargetType ?? "issue";
|
|
13758
13936
|
const targetNumber = ctx.data.commentTargetNumber ?? issueNumber;
|
|
13759
13937
|
try {
|
|
13760
|
-
writeTaskState(target, targetNumber, state, ctx.cwd, ctx.config);
|
|
13938
|
+
await writeTaskState(target, targetNumber, state, ctx.cwd, ctx.config);
|
|
13761
13939
|
} catch (err) {
|
|
13762
13940
|
process.stderr.write(
|
|
13763
13941
|
`[kody finishFlow] failed to update state mirror: ${err instanceof Error ? err.message : String(err)}
|
|
@@ -15561,7 +15739,7 @@ var init_loadTaskState = __esm({
|
|
|
15561
15739
|
return;
|
|
15562
15740
|
}
|
|
15563
15741
|
try {
|
|
15564
|
-
ctx.data.taskState = readTaskState(target, number, ctx.cwd, ctx.config);
|
|
15742
|
+
ctx.data.taskState = await readTaskState(target, number, ctx.cwd, ctx.config);
|
|
15565
15743
|
} catch (err) {
|
|
15566
15744
|
if (err instanceof CorruptStateError) {
|
|
15567
15745
|
process.stderr.write(
|
|
@@ -15569,7 +15747,7 @@ var init_loadTaskState = __esm({
|
|
|
15569
15747
|
`
|
|
15570
15748
|
);
|
|
15571
15749
|
try {
|
|
15572
|
-
writeTaskState(target, number, emptyState(), ctx.cwd, ctx.config);
|
|
15750
|
+
await writeTaskState(target, number, emptyState(), ctx.cwd, ctx.config);
|
|
15573
15751
|
} catch {
|
|
15574
15752
|
}
|
|
15575
15753
|
ctx.skipAgent = true;
|
|
@@ -15826,7 +16004,7 @@ var init_mirrorStateToPr = __esm({
|
|
|
15826
16004
|
if (!prNumber) return;
|
|
15827
16005
|
if (!state) {
|
|
15828
16006
|
try {
|
|
15829
|
-
state = readTaskState("issue", issueNumber, ctx.cwd, ctx.config);
|
|
16007
|
+
state = await readTaskState("issue", issueNumber, ctx.cwd, ctx.config);
|
|
15830
16008
|
} catch {
|
|
15831
16009
|
return;
|
|
15832
16010
|
}
|
|
@@ -15836,7 +16014,7 @@ var init_mirrorStateToPr = __esm({
|
|
|
15836
16014
|
ctx.data.taskState = state;
|
|
15837
16015
|
}
|
|
15838
16016
|
try {
|
|
15839
|
-
writeTaskState("pr", prNumber, state, ctx.cwd, ctx.config);
|
|
16017
|
+
await writeTaskState("pr", prNumber, state, ctx.cwd, ctx.config);
|
|
15840
16018
|
} catch (err) {
|
|
15841
16019
|
process.stderr.write(
|
|
15842
16020
|
`[kody mirrorStateToPr] failed to mirror state to PR #${prNumber}: ${err instanceof Error ? err.message : String(err)}
|
|
@@ -16285,6 +16463,7 @@ var init_parseAgentResult = __esm({
|
|
|
16285
16463
|
return;
|
|
16286
16464
|
}
|
|
16287
16465
|
const parsed = parseAgentResult(agentResult.finalText);
|
|
16466
|
+
ctx.data.agentFinalText = agentResult.finalText;
|
|
16288
16467
|
ctx.data.agentDone = parsed.done;
|
|
16289
16468
|
ctx.data.commitMessage = parsed.commitMessage;
|
|
16290
16469
|
ctx.data.prSummary = parsed.prSummary;
|
|
@@ -16598,7 +16777,7 @@ var init_persistFlowState = __esm({
|
|
|
16598
16777
|
const issueNumber = ctx.args.issue ?? state.flow?.issueNumber;
|
|
16599
16778
|
if (!issueNumber) return;
|
|
16600
16779
|
try {
|
|
16601
|
-
writeTaskState("issue", issueNumber, state, ctx.cwd, ctx.config);
|
|
16780
|
+
await writeTaskState("issue", issueNumber, state, ctx.cwd, ctx.config);
|
|
16602
16781
|
} catch (err) {
|
|
16603
16782
|
process.stderr.write(
|
|
16604
16783
|
`[kody persistFlowState] failed to write state on issue #${issueNumber}: ${err instanceof Error ? err.message : String(err)}
|
|
@@ -16718,7 +16897,7 @@ var init_planTaskJobs = __esm({
|
|
|
16718
16897
|
ctx.data.plannedTaskJobIds = planned.map((job) => job.id);
|
|
16719
16898
|
const target = ctx.data.commentTargetType;
|
|
16720
16899
|
const number = ctx.data.commentTargetNumber;
|
|
16721
|
-
if (target && number) writeTaskState(target, number, next, ctx.cwd, ctx.config);
|
|
16900
|
+
if (target && number) await writeTaskState(target, number, next, ctx.cwd, ctx.config);
|
|
16722
16901
|
};
|
|
16723
16902
|
}
|
|
16724
16903
|
});
|
|
@@ -17430,6 +17609,52 @@ var init_recordOutcome = __esm({
|
|
|
17430
17609
|
}
|
|
17431
17610
|
});
|
|
17432
17611
|
|
|
17612
|
+
// src/scripts/requireDeliveryArtifacts.ts
|
|
17613
|
+
function fallbackSummary(finalText) {
|
|
17614
|
+
const prose = finalText.split("\n").filter(
|
|
17615
|
+
(line) => !/^[\s>*_#`~-]*(?:DONE\b|COMMIT_MSG\s*:|PR_SUMMARY\s*:|PLAN_DEVIATIONS\s*:|FEEDBACK_ACTIONS\s*:)/i.test(line)
|
|
17616
|
+
).join("\n").trim();
|
|
17617
|
+
if (!prose) return "";
|
|
17618
|
+
if (prose.length <= FALLBACK_SUMMARY_MAX) return prose;
|
|
17619
|
+
return `${prose.slice(0, FALLBACK_SUMMARY_MAX - 1)}\u2026`;
|
|
17620
|
+
}
|
|
17621
|
+
var FALLBACK_SUMMARY_MAX, requireDeliveryArtifacts;
|
|
17622
|
+
var init_requireDeliveryArtifacts = __esm({
|
|
17623
|
+
"src/scripts/requireDeliveryArtifacts.ts"() {
|
|
17624
|
+
"use strict";
|
|
17625
|
+
FALLBACK_SUMMARY_MAX = 6e3;
|
|
17626
|
+
requireDeliveryArtifacts = async (ctx) => {
|
|
17627
|
+
if (ctx.data.agentDone !== true) return;
|
|
17628
|
+
const commitResult = ctx.data.commitResult;
|
|
17629
|
+
const hasCommits = ctx.data.hasCommitsAhead === true;
|
|
17630
|
+
if (!commitResult?.committed && !hasCommits) return;
|
|
17631
|
+
const commitMessage = String(ctx.data.commitMessage ?? "").trim();
|
|
17632
|
+
const prSummary = String(ctx.data.prSummary ?? "").trim();
|
|
17633
|
+
const missing = [];
|
|
17634
|
+
if (!commitMessage) missing.push("COMMIT_MSG");
|
|
17635
|
+
if (!prSummary) missing.push("PR_SUMMARY");
|
|
17636
|
+
if (missing.length === 0) return;
|
|
17637
|
+
const reason = `agent omitted required delivery artifacts: ${missing.join(", ")}`;
|
|
17638
|
+
ctx.data.agentDone = false;
|
|
17639
|
+
ctx.data.agentResultIncomplete = true;
|
|
17640
|
+
ctx.data.agentMissingArtifacts = missing;
|
|
17641
|
+
ctx.data.agentFailureReason = reason;
|
|
17642
|
+
if (!prSummary) {
|
|
17643
|
+
const fallback = fallbackSummary(String(ctx.data.agentFinalText ?? ""));
|
|
17644
|
+
if (fallback) ctx.data.agentFallbackSummary = fallback;
|
|
17645
|
+
}
|
|
17646
|
+
const action = ctx.data.action;
|
|
17647
|
+
if (action?.type.endsWith("_COMPLETED")) {
|
|
17648
|
+
ctx.data.action = {
|
|
17649
|
+
type: action.type.replace(/_COMPLETED$/, "_FAILED"),
|
|
17650
|
+
payload: { reason, downgradedFrom: action.type },
|
|
17651
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
17652
|
+
};
|
|
17653
|
+
}
|
|
17654
|
+
};
|
|
17655
|
+
}
|
|
17656
|
+
});
|
|
17657
|
+
|
|
17433
17658
|
// src/scripts/requireFeedbackActions.ts
|
|
17434
17659
|
function countActionItems(block) {
|
|
17435
17660
|
if (!block.trim()) return 0;
|
|
@@ -20174,6 +20399,7 @@ var init_scripts = __esm({
|
|
|
20174
20399
|
init_publishReport();
|
|
20175
20400
|
init_recordClassification();
|
|
20176
20401
|
init_recordOutcome();
|
|
20402
|
+
init_requireDeliveryArtifacts();
|
|
20177
20403
|
init_requireFeedbackActions();
|
|
20178
20404
|
init_requirePlanDeviations();
|
|
20179
20405
|
init_resolveArtifacts();
|
|
@@ -20265,6 +20491,7 @@ var init_scripts = __esm({
|
|
|
20265
20491
|
writeJobStateFile,
|
|
20266
20492
|
appendCompanyActivity,
|
|
20267
20493
|
requireFeedbackActions,
|
|
20494
|
+
requireDeliveryArtifacts,
|
|
20268
20495
|
requirePlanDeviations,
|
|
20269
20496
|
verify,
|
|
20270
20497
|
verifyWithRetry,
|
|
@@ -20993,7 +21220,7 @@ async function runImplementation(profileName, input) {
|
|
|
20993
21220
|
`);
|
|
20994
21221
|
}
|
|
20995
21222
|
if (!input.skipConfig && (config.state || config.github.owner && config.github.repo)) {
|
|
20996
|
-
persistTaskArtifactsToState(config, input.cwd, taskArtifacts);
|
|
21223
|
+
await persistTaskArtifactsToState(config, input.cwd, taskArtifacts);
|
|
20997
21224
|
}
|
|
20998
21225
|
} catch (err) {
|
|
20999
21226
|
process.stderr.write(
|
|
@@ -22465,59 +22692,8 @@ function makeRunId(sessionId, suffix) {
|
|
|
22465
22692
|
}
|
|
22466
22693
|
|
|
22467
22694
|
// src/chat/session-store.ts
|
|
22468
|
-
|
|
22469
|
-
|
|
22470
|
-
// src/chat/convex-client.ts
|
|
22471
|
-
import { ConvexHttpClient } from "convex/browser";
|
|
22472
|
-
var ESCAPE_CHAR = "~";
|
|
22473
|
-
var NEEDS_ESCAPE = /^[$_~]/;
|
|
22474
|
-
function isPlainObject2(value) {
|
|
22475
|
-
if (value === null || typeof value !== "object") return false;
|
|
22476
|
-
const proto = Object.getPrototypeOf(value);
|
|
22477
|
-
return proto === Object.prototype || proto === null;
|
|
22478
|
-
}
|
|
22479
|
-
function deepMapKeys(value, mapKey) {
|
|
22480
|
-
if (Array.isArray(value)) return value.map((item) => deepMapKeys(item, mapKey));
|
|
22481
|
-
if (isPlainObject2(value)) {
|
|
22482
|
-
return Object.fromEntries(Object.entries(value).map(([key, item]) => [mapKey(key), deepMapKeys(item, mapKey)]));
|
|
22483
|
-
}
|
|
22484
|
-
return value;
|
|
22485
|
-
}
|
|
22486
|
-
function deepEscapeKeys(value) {
|
|
22487
|
-
return deepMapKeys(value, (k) => NEEDS_ESCAPE.test(k) ? `${ESCAPE_CHAR}${k}` : k);
|
|
22488
|
-
}
|
|
22489
|
-
function deepUnescapeKeys(value) {
|
|
22490
|
-
return deepMapKeys(value, (k) => k.startsWith(ESCAPE_CHAR) ? k.slice(1) : k);
|
|
22491
|
-
}
|
|
22492
|
-
var CALL_METHODS = ["query", "mutation", "action"];
|
|
22493
|
-
function injectServiceKey(args) {
|
|
22494
|
-
const serviceKey = process.env.KODY_SERVICE_KEY;
|
|
22495
|
-
if (!serviceKey) return args;
|
|
22496
|
-
if (args === void 0) return { serviceKey };
|
|
22497
|
-
if (typeof args !== "object" || args === null || Array.isArray(args)) return args;
|
|
22498
|
-
return { ...args, serviceKey };
|
|
22499
|
-
}
|
|
22500
|
-
function withEscapedKeys(client) {
|
|
22501
|
-
return new Proxy(client, {
|
|
22502
|
-
get(target, prop, receiver) {
|
|
22503
|
-
if (CALL_METHODS.includes(prop)) {
|
|
22504
|
-
const method = Reflect.get(target, prop, target);
|
|
22505
|
-
return async (fn, args) => {
|
|
22506
|
-
const authed = injectServiceKey(args);
|
|
22507
|
-
const result = await method.call(target, fn, authed === void 0 ? void 0 : deepEscapeKeys(authed));
|
|
22508
|
-
return deepUnescapeKeys(result);
|
|
22509
|
-
};
|
|
22510
|
-
}
|
|
22511
|
-
const value = Reflect.get(target, prop, receiver);
|
|
22512
|
-
return typeof value === "function" ? value.bind(target) : value;
|
|
22513
|
-
}
|
|
22514
|
-
});
|
|
22515
|
-
}
|
|
22516
|
-
function createConvexClientFromEnv(env = process.env) {
|
|
22517
|
-
const url = env.CONVEX_URL?.trim();
|
|
22518
|
-
if (!url) return null;
|
|
22519
|
-
return withEscapedKeys(new ConvexHttpClient(url));
|
|
22520
|
-
}
|
|
22695
|
+
init_convex_client();
|
|
22696
|
+
import { anyApi as anyApi2 } from "convex/server";
|
|
22521
22697
|
|
|
22522
22698
|
// src/chat/session.ts
|
|
22523
22699
|
import * as fs13 from "fs";
|
|
@@ -22640,7 +22816,7 @@ function createConvexStore(args) {
|
|
|
22640
22816
|
if (!sessionUpserted) {
|
|
22641
22817
|
try {
|
|
22642
22818
|
const meta = readMeta(sessionFile) ?? { type: "meta", mode: "one-shot" };
|
|
22643
|
-
await client.mutation(
|
|
22819
|
+
await client.mutation(anyApi2.chatSessions.upsert, {
|
|
22644
22820
|
tenantId,
|
|
22645
22821
|
sessionId,
|
|
22646
22822
|
meta,
|
|
@@ -22651,12 +22827,12 @@ function createConvexStore(args) {
|
|
|
22651
22827
|
logger.warn(`session ${sessionId}: chatSessions.upsert failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
22652
22828
|
}
|
|
22653
22829
|
}
|
|
22654
|
-
await client.mutation(
|
|
22830
|
+
await client.mutation(anyApi2.chatTurns.append, { tenantId, sessionId, turn });
|
|
22655
22831
|
};
|
|
22656
22832
|
return {
|
|
22657
22833
|
backend: "convex",
|
|
22658
22834
|
readTurns: async () => {
|
|
22659
|
-
const docs = await client.query(
|
|
22835
|
+
const docs = await client.query(anyApi2.chatTurns.list, { tenantId, sessionId });
|
|
22660
22836
|
const convexTurns = [...docs].sort((a, b) => a.seq - b.seq).map((doc) => doc.turn).filter(isChatTurn);
|
|
22661
22837
|
const localTurns = readSession(sessionFile);
|
|
22662
22838
|
if (localTurns.length <= convexTurns.length) return convexTurns;
|
|
@@ -22975,7 +23151,7 @@ async function runChatTurn(opts) {
|
|
|
22975
23151
|
`
|
|
22976
23152
|
);
|
|
22977
23153
|
}
|
|
22978
|
-
if (opts.stateConfig) persistTaskArtifactsToState(opts.stateConfig, opts.cwd, taskArtifactsPaths);
|
|
23154
|
+
if (opts.stateConfig) await persistTaskArtifactsToState(opts.stateConfig, opts.cwd, taskArtifactsPaths);
|
|
22979
23155
|
} catch (err) {
|
|
22980
23156
|
process.stderr.write(
|
|
22981
23157
|
`[task-artifacts] chat session ${taskArtifactsPaths.taskId} persist failed: ${err instanceof Error ? err.message : String(err)}
|
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.383",
|
|
4
4
|
"description": "kody — autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative implementation profiles.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -12,28 +12,6 @@
|
|
|
12
12
|
"templates",
|
|
13
13
|
"kody.config.schema.json"
|
|
14
14
|
],
|
|
15
|
-
"scripts": {
|
|
16
|
-
"kody:run": "tsx bin/kody.ts",
|
|
17
|
-
"serve": "tsx bin/kody.ts serve",
|
|
18
|
-
"serve:vscode": "tsx bin/kody.ts serve vscode",
|
|
19
|
-
"serve:claude": "tsx bin/kody.ts serve claude",
|
|
20
|
-
"clean:dist": "node scripts/clean-dist.cjs",
|
|
21
|
-
"build": "pnpm clean:dist && tsup && node scripts/copy-assets.cjs",
|
|
22
|
-
"check:modularity": "tsx scripts/check-script-modularity.ts",
|
|
23
|
-
"pretest": "pnpm check:modularity",
|
|
24
|
-
"test": "vitest run tests/unit tests/int --coverage",
|
|
25
|
-
"posttest": "tsx scripts/check-coverage-floor.ts",
|
|
26
|
-
"test:smoke": "vitest run tests/smoke --no-coverage",
|
|
27
|
-
"test:e2e": "vitest run tests/e2e --no-coverage",
|
|
28
|
-
"test:all": "vitest run tests --no-coverage",
|
|
29
|
-
"typecheck": "tsc --noEmit",
|
|
30
|
-
"lint": "biome check",
|
|
31
|
-
"lint:fix": "biome check --write",
|
|
32
|
-
"format": "biome format --write",
|
|
33
|
-
"verify:package": "node scripts/verify-package-tarball.cjs",
|
|
34
|
-
"brain:publish": "docker buildx build --platform linux/amd64 -f runner/Dockerfile.brain -t ghcr.io/${KODY_BRAIN_GHCR_OWNER:-aharonyaircohen}/kody-brain:latest --push runner",
|
|
35
|
-
"prepublishOnly": "pnpm typecheck && vitest run tests/unit tests/int --no-coverage && pnpm build && pnpm verify:package"
|
|
36
|
-
},
|
|
37
15
|
"dependencies": {
|
|
38
16
|
"@actions/cache": "^6.0.0",
|
|
39
17
|
"@anthropic-ai/claude-agent-sdk": "0.2.119",
|
|
@@ -58,5 +36,26 @@
|
|
|
58
36
|
"url": "git+https://github.com/aharonyaircohen/kody-engine.git"
|
|
59
37
|
},
|
|
60
38
|
"homepage": "https://github.com/aharonyaircohen/kody-engine",
|
|
61
|
-
"bugs": "https://github.com/aharonyaircohen/kody-engine/issues"
|
|
62
|
-
|
|
39
|
+
"bugs": "https://github.com/aharonyaircohen/kody-engine/issues",
|
|
40
|
+
"scripts": {
|
|
41
|
+
"kody:run": "tsx bin/kody.ts",
|
|
42
|
+
"serve": "tsx bin/kody.ts serve",
|
|
43
|
+
"serve:vscode": "tsx bin/kody.ts serve vscode",
|
|
44
|
+
"serve:claude": "tsx bin/kody.ts serve claude",
|
|
45
|
+
"clean:dist": "node scripts/clean-dist.cjs",
|
|
46
|
+
"build": "pnpm clean:dist && tsup && node scripts/copy-assets.cjs",
|
|
47
|
+
"check:modularity": "tsx scripts/check-script-modularity.ts",
|
|
48
|
+
"pretest": "pnpm check:modularity",
|
|
49
|
+
"test": "vitest run tests/unit tests/int --coverage",
|
|
50
|
+
"posttest": "tsx scripts/check-coverage-floor.ts",
|
|
51
|
+
"test:smoke": "vitest run tests/smoke --no-coverage",
|
|
52
|
+
"test:e2e": "vitest run tests/e2e --no-coverage",
|
|
53
|
+
"test:all": "vitest run tests --no-coverage",
|
|
54
|
+
"typecheck": "tsc --noEmit",
|
|
55
|
+
"lint": "biome check",
|
|
56
|
+
"lint:fix": "biome check --write",
|
|
57
|
+
"format": "biome format --write",
|
|
58
|
+
"verify:package": "node scripts/verify-package-tarball.cjs",
|
|
59
|
+
"brain:publish": "docker buildx build --platform linux/amd64 -f runner/Dockerfile.brain -t ghcr.io/${KODY_BRAIN_GHCR_OWNER:-aharonyaircohen}/kody-brain:latest --push runner"
|
|
60
|
+
}
|
|
61
|
+
}
|