@kody-ade/kody-engine 0.4.272 → 0.4.274
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 +472 -261
- package/package.json +1 -1
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.274",
|
|
19
19
|
description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
|
|
20
20
|
license: "MIT",
|
|
21
21
|
type: "module",
|
|
@@ -2217,7 +2217,7 @@ function cmsHeaders(opts) {
|
|
|
2217
2217
|
}
|
|
2218
2218
|
};
|
|
2219
2219
|
}
|
|
2220
|
-
async function callDashboardCms(opts,
|
|
2220
|
+
async function callDashboardCms(opts, path50, init = {}) {
|
|
2221
2221
|
const baseUrl = dashboardBaseUrl();
|
|
2222
2222
|
if (!baseUrl) {
|
|
2223
2223
|
return {
|
|
@@ -2229,7 +2229,7 @@ async function callDashboardCms(opts, path49, init = {}) {
|
|
|
2229
2229
|
const headerResult = cmsHeaders(opts);
|
|
2230
2230
|
if (!headerResult.ok) return headerResult;
|
|
2231
2231
|
try {
|
|
2232
|
-
const res = await fetch(`${baseUrl}${
|
|
2232
|
+
const res = await fetch(`${baseUrl}${path50}`, {
|
|
2233
2233
|
...init,
|
|
2234
2234
|
headers: {
|
|
2235
2235
|
...headerResult.headers,
|
|
@@ -6430,10 +6430,10 @@ var init_state2 = __esm({
|
|
|
6430
6430
|
"use strict";
|
|
6431
6431
|
VALID_STATES = /* @__PURE__ */ new Set(["active", "abandoned", "closed", "done"]);
|
|
6432
6432
|
GoalStateError = class extends Error {
|
|
6433
|
-
constructor(
|
|
6434
|
-
super(`Invalid goal state at ${
|
|
6433
|
+
constructor(path50, message) {
|
|
6434
|
+
super(`Invalid goal state at ${path50}:
|
|
6435
6435
|
${message}`);
|
|
6436
|
-
this.path =
|
|
6436
|
+
this.path = path50;
|
|
6437
6437
|
this.name = "GoalStateError";
|
|
6438
6438
|
}
|
|
6439
6439
|
path;
|
|
@@ -6446,9 +6446,9 @@ import * as fs25 from "fs";
|
|
|
6446
6446
|
function stageGoalRunLogEvent(data, goalId, event, at = nowIso()) {
|
|
6447
6447
|
const logs = goalRunLogs(data);
|
|
6448
6448
|
const existing = logs[goalId];
|
|
6449
|
-
const
|
|
6449
|
+
const path50 = existing?.path ?? goalRunLogPath(goalId, data);
|
|
6450
6450
|
logs[goalId] = {
|
|
6451
|
-
path:
|
|
6451
|
+
path: path50,
|
|
6452
6452
|
events: [
|
|
6453
6453
|
...existing?.events ?? [],
|
|
6454
6454
|
buildGoalRunLogEvent(data, goalId, event, at)
|
|
@@ -6810,6 +6810,188 @@ var init_runLog = __esm({
|
|
|
6810
6810
|
}
|
|
6811
6811
|
});
|
|
6812
6812
|
|
|
6813
|
+
// src/goal/stateStore.ts
|
|
6814
|
+
function statePath(goalId) {
|
|
6815
|
+
return `goals/instances/${goalId}/state.json`;
|
|
6816
|
+
}
|
|
6817
|
+
function fetchGoalState(config, goalId, cwd) {
|
|
6818
|
+
const filePath = statePath(goalId);
|
|
6819
|
+
const loaded = readStateText(config, cwd, filePath);
|
|
6820
|
+
if (!loaded) return null;
|
|
6821
|
+
return parseGoalState(loaded.path, JSON.parse(loaded.content));
|
|
6822
|
+
}
|
|
6823
|
+
function putGoalState(config, goalId, state, message = `chore(goals): update ${goalId}`, cwd) {
|
|
6824
|
+
upsertStateText(config, cwd, statePath(goalId), serializeGoalState(state), message);
|
|
6825
|
+
}
|
|
6826
|
+
var init_stateStore = __esm({
|
|
6827
|
+
"src/goal/stateStore.ts"() {
|
|
6828
|
+
"use strict";
|
|
6829
|
+
init_stateRepo();
|
|
6830
|
+
init_state2();
|
|
6831
|
+
}
|
|
6832
|
+
});
|
|
6833
|
+
|
|
6834
|
+
// src/goal/targetLoopResolution.ts
|
|
6835
|
+
import * as fs26 from "fs";
|
|
6836
|
+
import * as path24 from "path";
|
|
6837
|
+
function resolveGoalLoopTarget(config, cwd, loopGoalId, loopGoal, now) {
|
|
6838
|
+
const targetId = loopGoal.loopTarget?.id.trim() ?? "";
|
|
6839
|
+
assertSafeGoalId(targetId, "loop target");
|
|
6840
|
+
if (!hasExplicitStateRepo(config)) {
|
|
6841
|
+
return { targetId, templateId: targetId, reason: "literal target; state repo not configured" };
|
|
6842
|
+
}
|
|
6843
|
+
const activeInstance = findActiveTargetInstance(config, cwd, loopGoalId, targetId);
|
|
6844
|
+
if (activeInstance) {
|
|
6845
|
+
return {
|
|
6846
|
+
targetId: activeInstance.id,
|
|
6847
|
+
templateId: targetId,
|
|
6848
|
+
reason: "active target instance"
|
|
6849
|
+
};
|
|
6850
|
+
}
|
|
6851
|
+
const directTarget = fetchGoalState(config, targetId, cwd);
|
|
6852
|
+
if (directTarget?.state === "active") {
|
|
6853
|
+
return { targetId, templateId: targetId, reason: "active target goal" };
|
|
6854
|
+
}
|
|
6855
|
+
const template = loadGoalTemplate(cwd, targetId);
|
|
6856
|
+
if (!template) {
|
|
6857
|
+
if (directTarget) {
|
|
6858
|
+
throw new Error(`goal target ${targetId} is ${directTarget.state}; no active instance or template found`);
|
|
6859
|
+
}
|
|
6860
|
+
return { targetId, templateId: targetId, reason: "literal target; no target state or template found" };
|
|
6861
|
+
}
|
|
6862
|
+
const instanceId = chooseTargetInstanceId(config, cwd, targetId, loopGoal.preferredRunTime?.timezone, now);
|
|
6863
|
+
const instance = buildGoalTargetInstance(template, targetId, now);
|
|
6864
|
+
putGoalState(config, instanceId, instance, `chore(goals): create ${instanceId}`, cwd);
|
|
6865
|
+
return {
|
|
6866
|
+
targetId: instanceId,
|
|
6867
|
+
templateId: targetId,
|
|
6868
|
+
reason: "created target instance from template",
|
|
6869
|
+
created: true
|
|
6870
|
+
};
|
|
6871
|
+
}
|
|
6872
|
+
function goalLoopNow() {
|
|
6873
|
+
const value = process.env.KODY_GOAL_LOOP_NOW?.trim();
|
|
6874
|
+
if (value) {
|
|
6875
|
+
const date = new Date(value);
|
|
6876
|
+
if (!Number.isNaN(date.getTime())) return date;
|
|
6877
|
+
}
|
|
6878
|
+
return /* @__PURE__ */ new Date();
|
|
6879
|
+
}
|
|
6880
|
+
function hasExplicitStateRepo(config) {
|
|
6881
|
+
const state = config.state;
|
|
6882
|
+
return !!state && typeof state.repo === "string" && state.repo.trim().length > 0 && typeof state.path === "string" && state.path.trim().length > 0;
|
|
6883
|
+
}
|
|
6884
|
+
function findActiveTargetInstance(config, cwd, loopGoalId, targetId) {
|
|
6885
|
+
const entries = listStateDirectory(config, cwd, "goals/instances");
|
|
6886
|
+
const candidates = [];
|
|
6887
|
+
for (const entry of entries) {
|
|
6888
|
+
const id = typeof entry.name === "string" ? entry.name.trim() : "";
|
|
6889
|
+
if (!id || id === loopGoalId || id === targetId || !id.startsWith(`${targetId}-`)) continue;
|
|
6890
|
+
assertSafeGoalId(id, "goal instance");
|
|
6891
|
+
const state = fetchGoalState(config, id, cwd);
|
|
6892
|
+
if (!state || state.state !== "active") continue;
|
|
6893
|
+
if (!isTargetInstanceState(id, state, targetId)) continue;
|
|
6894
|
+
candidates.push({ id, state });
|
|
6895
|
+
}
|
|
6896
|
+
candidates.sort(compareGoalInstanceAge);
|
|
6897
|
+
return candidates[0] ?? null;
|
|
6898
|
+
}
|
|
6899
|
+
function isTargetInstanceState(id, state, targetId) {
|
|
6900
|
+
if (id.startsWith(`${targetId}-`)) return true;
|
|
6901
|
+
return ["template", "sourceTemplate", "templateId", "type"].some((key) => state.extra[key] === targetId);
|
|
6902
|
+
}
|
|
6903
|
+
function compareGoalInstanceAge(a, b) {
|
|
6904
|
+
const byTime = goalInstanceTime(a.state) - goalInstanceTime(b.state);
|
|
6905
|
+
return byTime === 0 ? a.id.localeCompare(b.id) : byTime;
|
|
6906
|
+
}
|
|
6907
|
+
function goalInstanceTime(state) {
|
|
6908
|
+
const value = state.createdAt ?? state.startedAt ?? state.updatedAt;
|
|
6909
|
+
if (!value) return 0;
|
|
6910
|
+
const parsed = Date.parse(value);
|
|
6911
|
+
return Number.isNaN(parsed) ? 0 : parsed;
|
|
6912
|
+
}
|
|
6913
|
+
function loadGoalTemplate(cwd, targetId) {
|
|
6914
|
+
const local = path24.join(cwd, ".kody", "goals", "templates", targetId, "state.json");
|
|
6915
|
+
const localTemplate = readJsonObject(local);
|
|
6916
|
+
if (localTemplate) return localTemplate;
|
|
6917
|
+
const storeGoalRoot = getCompanyStoreAssetRoot("goals");
|
|
6918
|
+
if (!storeGoalRoot) return null;
|
|
6919
|
+
return readJsonObject(path24.join(storeGoalRoot, "templates", targetId, "state.json"));
|
|
6920
|
+
}
|
|
6921
|
+
function readJsonObject(filePath) {
|
|
6922
|
+
if (!fs26.existsSync(filePath)) return null;
|
|
6923
|
+
const parsed = JSON.parse(fs26.readFileSync(filePath, "utf8"));
|
|
6924
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
6925
|
+
throw new Error(`goal template ${filePath} must be a JSON object`);
|
|
6926
|
+
}
|
|
6927
|
+
return parsed;
|
|
6928
|
+
}
|
|
6929
|
+
function chooseTargetInstanceId(config, cwd, targetId, timezone, now) {
|
|
6930
|
+
const base = `${targetId}-${zonedDate(now, timezone ?? "UTC")}`;
|
|
6931
|
+
for (let index = 1; index <= 20; index += 1) {
|
|
6932
|
+
const id = index === 1 ? base : `${base}-${index}`;
|
|
6933
|
+
assertSafeGoalId(id, "goal instance");
|
|
6934
|
+
const existing = fetchGoalState(config, id, cwd);
|
|
6935
|
+
if (!existing || existing.state === "active") return id;
|
|
6936
|
+
}
|
|
6937
|
+
throw new Error(`could not allocate goal target instance id for ${targetId}`);
|
|
6938
|
+
}
|
|
6939
|
+
function buildGoalTargetInstance(template, targetId, now) {
|
|
6940
|
+
const extra = { ...template };
|
|
6941
|
+
for (const key of ["state", "createdAt", "updatedAt", "startedAt"]) {
|
|
6942
|
+
delete extra[key];
|
|
6943
|
+
}
|
|
6944
|
+
extra.kind = "instance";
|
|
6945
|
+
extra.template = targetId;
|
|
6946
|
+
extra.sourceTemplate = targetId;
|
|
6947
|
+
extra.templateId = targetId;
|
|
6948
|
+
if (!isPlainObject2(extra.facts)) extra.facts = {};
|
|
6949
|
+
if (!Array.isArray(extra.blockers)) extra.blockers = [];
|
|
6950
|
+
const at = isoNoMs(now);
|
|
6951
|
+
return {
|
|
6952
|
+
state: "active",
|
|
6953
|
+
createdAt: at,
|
|
6954
|
+
updatedAt: at,
|
|
6955
|
+
extra
|
|
6956
|
+
};
|
|
6957
|
+
}
|
|
6958
|
+
function isPlainObject2(value) {
|
|
6959
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
6960
|
+
}
|
|
6961
|
+
function assertSafeGoalId(value, label) {
|
|
6962
|
+
if (!/^[A-Za-z0-9_.-]+$/.test(value)) {
|
|
6963
|
+
throw new Error(`${label} id must contain only letters, numbers, dot, underscore, or dash: ${value}`);
|
|
6964
|
+
}
|
|
6965
|
+
}
|
|
6966
|
+
function zonedDate(date, timezone) {
|
|
6967
|
+
try {
|
|
6968
|
+
const parts = new Intl.DateTimeFormat("en-CA", {
|
|
6969
|
+
timeZone: timezone,
|
|
6970
|
+
year: "numeric",
|
|
6971
|
+
month: "2-digit",
|
|
6972
|
+
day: "2-digit"
|
|
6973
|
+
}).formatToParts(date);
|
|
6974
|
+
const get = (type) => parts.find((part) => part.type === type)?.value;
|
|
6975
|
+
const year = get("year");
|
|
6976
|
+
const month = get("month");
|
|
6977
|
+
const day = get("day");
|
|
6978
|
+
if (year && month && day) return `${year}-${month}-${day}`;
|
|
6979
|
+
} catch {
|
|
6980
|
+
}
|
|
6981
|
+
return date.toISOString().slice(0, 10);
|
|
6982
|
+
}
|
|
6983
|
+
function isoNoMs(date) {
|
|
6984
|
+
return date.toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
6985
|
+
}
|
|
6986
|
+
var init_targetLoopResolution = __esm({
|
|
6987
|
+
"src/goal/targetLoopResolution.ts"() {
|
|
6988
|
+
"use strict";
|
|
6989
|
+
init_companyStore();
|
|
6990
|
+
init_stateRepo();
|
|
6991
|
+
init_stateStore();
|
|
6992
|
+
}
|
|
6993
|
+
});
|
|
6994
|
+
|
|
6813
6995
|
// src/goal/typeDefinitions.ts
|
|
6814
6996
|
function cloneRoute(route) {
|
|
6815
6997
|
return route.map((step) => ({
|
|
@@ -7136,8 +7318,8 @@ var init_contentsApiBackend = __esm({
|
|
|
7136
7318
|
});
|
|
7137
7319
|
|
|
7138
7320
|
// src/scripts/jobState/localFileBackend.ts
|
|
7139
|
-
import * as
|
|
7140
|
-
import * as
|
|
7321
|
+
import * as fs27 from "fs";
|
|
7322
|
+
import * as path25 from "path";
|
|
7141
7323
|
function sanitizeKey(s) {
|
|
7142
7324
|
return s.replace(/[^A-Za-z0-9._-]/g, "-");
|
|
7143
7325
|
}
|
|
@@ -7193,7 +7375,7 @@ var init_localFileBackend = __esm({
|
|
|
7193
7375
|
if (!opts.owner || !opts.repo) throw new Error("LocalFileBackend: owner and repo are required");
|
|
7194
7376
|
this.cwd = opts.cwd;
|
|
7195
7377
|
this.jobsDir = opts.jobsDir;
|
|
7196
|
-
this.absDir =
|
|
7378
|
+
this.absDir = path25.join(opts.cwd, opts.jobsDir);
|
|
7197
7379
|
this.owner = opts.owner;
|
|
7198
7380
|
this.repo = opts.repo;
|
|
7199
7381
|
this.cache = opts.cache ?? defaultCacheAdapter();
|
|
@@ -7208,7 +7390,7 @@ var init_localFileBackend = __esm({
|
|
|
7208
7390
|
`);
|
|
7209
7391
|
return;
|
|
7210
7392
|
}
|
|
7211
|
-
|
|
7393
|
+
fs27.mkdirSync(this.absDir, { recursive: true });
|
|
7212
7394
|
const prefix = this.cacheKeyPrefix();
|
|
7213
7395
|
const probeKey = `${prefix}probe-${Date.now()}`;
|
|
7214
7396
|
try {
|
|
@@ -7237,7 +7419,7 @@ var init_localFileBackend = __esm({
|
|
|
7237
7419
|
`);
|
|
7238
7420
|
return;
|
|
7239
7421
|
}
|
|
7240
|
-
if (!
|
|
7422
|
+
if (!fs27.existsSync(this.absDir)) {
|
|
7241
7423
|
return;
|
|
7242
7424
|
}
|
|
7243
7425
|
const key = `${this.cacheKeyPrefix()}${process.env.GITHUB_RUN_ID ?? "norunid"}-${Date.now()}`;
|
|
@@ -7253,11 +7435,11 @@ var init_localFileBackend = __esm({
|
|
|
7253
7435
|
}
|
|
7254
7436
|
load(slug2) {
|
|
7255
7437
|
const relPath = stateFilePath(this.jobsDir, slug2);
|
|
7256
|
-
const absPath =
|
|
7257
|
-
if (!
|
|
7438
|
+
const absPath = path25.join(this.cwd, relPath);
|
|
7439
|
+
if (!fs27.existsSync(absPath)) {
|
|
7258
7440
|
return { path: relPath, handle: null, state: initialStateEnvelope("seed"), created: true };
|
|
7259
7441
|
}
|
|
7260
|
-
const raw =
|
|
7442
|
+
const raw = fs27.readFileSync(absPath, "utf-8");
|
|
7261
7443
|
let parsed;
|
|
7262
7444
|
try {
|
|
7263
7445
|
parsed = JSON.parse(raw);
|
|
@@ -7274,13 +7456,13 @@ var init_localFileBackend = __esm({
|
|
|
7274
7456
|
if (!loaded.created && isStateUnchanged(loaded.state, next)) {
|
|
7275
7457
|
return false;
|
|
7276
7458
|
}
|
|
7277
|
-
const absPath =
|
|
7278
|
-
|
|
7459
|
+
const absPath = path25.join(this.cwd, loaded.path);
|
|
7460
|
+
fs27.mkdirSync(path25.dirname(absPath), { recursive: true });
|
|
7279
7461
|
const body = `${JSON.stringify(next, null, 2)}
|
|
7280
7462
|
`;
|
|
7281
7463
|
const tmpPath = `${absPath}.${process.pid}.tmp`;
|
|
7282
|
-
|
|
7283
|
-
|
|
7464
|
+
fs27.writeFileSync(tmpPath, body, "utf-8");
|
|
7465
|
+
fs27.renameSync(tmpPath, absPath);
|
|
7284
7466
|
return true;
|
|
7285
7467
|
}
|
|
7286
7468
|
cacheKeyPrefix() {
|
|
@@ -7320,7 +7502,7 @@ var init_jobState = __esm({
|
|
|
7320
7502
|
});
|
|
7321
7503
|
|
|
7322
7504
|
// src/scripts/goalCapabilityScheduling.ts
|
|
7323
|
-
import * as
|
|
7505
|
+
import * as path26 from "path";
|
|
7324
7506
|
function isCapabilityCadenceGoal(goal, extra) {
|
|
7325
7507
|
return extra.scheduleMode === "agentLoop" || extra.scheduler === "agentLoop" || goal.type === "standing" && goal.capabilities.length > 0;
|
|
7326
7508
|
}
|
|
@@ -7348,10 +7530,11 @@ function planTargetLoopSchedule(opts) {
|
|
|
7348
7530
|
const gate = preferredRunTimeGate(preferred, now, opts.previousScheduleState);
|
|
7349
7531
|
if (!gate.ok) return targetLoopDecision("idle", gate.reason, at);
|
|
7350
7532
|
}
|
|
7351
|
-
const
|
|
7533
|
+
const dispatchTargetId = target.type === "goal" && opts.resolvedGoalTargetId?.trim() ? opts.resolvedGoalTargetId.trim() : targetId;
|
|
7534
|
+
const dispatch2 = target.type === "goal" ? { action: "goal-manager", executable: "goal-manager", cliArgs: { goal: dispatchTargetId } } : { workflow: targetId, cliArgs: {} };
|
|
7352
7535
|
return {
|
|
7353
7536
|
kind: "dispatch",
|
|
7354
|
-
reason: `dispatch ${target.type} ${targetId}`,
|
|
7537
|
+
reason: `dispatch ${target.type} ${target.type === "goal" ? dispatchTargetId : targetId}`,
|
|
7355
7538
|
dispatch: dispatch2,
|
|
7356
7539
|
scheduleState: {
|
|
7357
7540
|
mode: "agentLoop",
|
|
@@ -7359,7 +7542,7 @@ function planTargetLoopSchedule(opts) {
|
|
|
7359
7542
|
lastDecision: {
|
|
7360
7543
|
kind: "dispatch",
|
|
7361
7544
|
targetType: target.type,
|
|
7362
|
-
targetId,
|
|
7545
|
+
targetId: target.type === "goal" ? dispatchTargetId : targetId,
|
|
7363
7546
|
...dispatch2.action ? { action: dispatch2.action } : {},
|
|
7364
7547
|
...dispatch2.capability ? { capability: dispatch2.capability } : {},
|
|
7365
7548
|
...dispatch2.workflow ? { workflow: dispatch2.workflow } : {},
|
|
@@ -7373,7 +7556,7 @@ function planTargetLoopSchedule(opts) {
|
|
|
7373
7556
|
}
|
|
7374
7557
|
async function planGoalCapabilitySchedule(opts) {
|
|
7375
7558
|
const jobsDir = opts.jobsDir ?? ".kody/capabilities";
|
|
7376
|
-
const jobsRoot =
|
|
7559
|
+
const jobsRoot = path26.join(opts.cwd, jobsDir);
|
|
7377
7560
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
7378
7561
|
const at = now.toISOString();
|
|
7379
7562
|
const backend = resolveBackend({ config: opts.config, cwd: opts.cwd, jobsDir });
|
|
@@ -7710,6 +7893,7 @@ var init_advanceManagedGoal = __esm({
|
|
|
7710
7893
|
init_manager();
|
|
7711
7894
|
init_runLog();
|
|
7712
7895
|
init_state2();
|
|
7896
|
+
init_targetLoopResolution();
|
|
7713
7897
|
init_typeDefinitions();
|
|
7714
7898
|
init_issue();
|
|
7715
7899
|
init_goalCapabilityScheduling();
|
|
@@ -7782,7 +7966,18 @@ var init_advanceManagedGoal = __esm({
|
|
|
7782
7966
|
if (isGoalTargetLoop(managed) || isWorkflowTargetLoop(managed)) {
|
|
7783
7967
|
const beforeSnapshot = goalRunLogSnapshot(goal.id, goal.state, managed);
|
|
7784
7968
|
const previousScheduleState = goal.raw.extra.scheduleState && typeof goal.raw.extra.scheduleState === "object" ? goal.raw.extra.scheduleState : void 0;
|
|
7785
|
-
const
|
|
7969
|
+
const now = goalLoopNow();
|
|
7970
|
+
let decision2 = planTargetLoopSchedule({ goal: managed, previousScheduleState, now });
|
|
7971
|
+
let targetResolution;
|
|
7972
|
+
if (decision2.kind === "dispatch" && decision2.dispatch && isGoalTargetLoop(managed)) {
|
|
7973
|
+
targetResolution = resolveGoalLoopTarget(ctx.config, ctx.cwd, goal.id, managed, now);
|
|
7974
|
+
decision2 = planTargetLoopSchedule({
|
|
7975
|
+
goal: managed,
|
|
7976
|
+
previousScheduleState,
|
|
7977
|
+
now,
|
|
7978
|
+
resolvedGoalTargetId: targetResolution.targetId
|
|
7979
|
+
});
|
|
7980
|
+
}
|
|
7786
7981
|
restoreGoalIdFact();
|
|
7787
7982
|
goal.raw = writeManagedGoalToState({ ...goal.raw, state: goal.state }, managed);
|
|
7788
7983
|
goal.raw.extra.scheduleState = decision2.scheduleState;
|
|
@@ -7809,6 +8004,7 @@ var init_advanceManagedGoal = __esm({
|
|
|
7809
8004
|
goal: goalRunLogSnapshot(goal.id, goal.state, managed),
|
|
7810
8005
|
inspection: {
|
|
7811
8006
|
loopTarget: managed.loopTarget,
|
|
8007
|
+
...targetResolution ? { targetResolution } : {},
|
|
7812
8008
|
preferredRunTime: managed.preferredRunTime,
|
|
7813
8009
|
previousScheduleState,
|
|
7814
8010
|
scheduleState: decision2.scheduleState
|
|
@@ -8154,13 +8350,13 @@ function companyIntentPath(id) {
|
|
|
8154
8350
|
assertIntentId(id);
|
|
8155
8351
|
return `intents/${id}/intent.json`;
|
|
8156
8352
|
}
|
|
8157
|
-
function normalizeCompanyIntent(
|
|
8353
|
+
function normalizeCompanyIntent(path50, raw) {
|
|
8158
8354
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
8159
|
-
throw new Error(`${
|
|
8355
|
+
throw new Error(`${path50}: intent must be JSON object`);
|
|
8160
8356
|
}
|
|
8161
8357
|
const input = raw;
|
|
8162
8358
|
const id = stringField2(input.id);
|
|
8163
|
-
if (!id || !isCompanyIntentId(id)) throw new Error(`${
|
|
8359
|
+
if (!id || !isCompanyIntentId(id)) throw new Error(`${path50}: invalid intent id`);
|
|
8164
8360
|
const createdAt = stringField2(input.createdAt) || nowIso();
|
|
8165
8361
|
const updatedAt = stringField2(input.updatedAt) || createdAt;
|
|
8166
8362
|
return {
|
|
@@ -8199,8 +8395,8 @@ function listCompanyIntents(config, cwd) {
|
|
|
8199
8395
|
const records = [];
|
|
8200
8396
|
for (const entry of entries) {
|
|
8201
8397
|
if (entry.type !== "dir" || !entry.name || !isCompanyIntentId(entry.name)) continue;
|
|
8202
|
-
const
|
|
8203
|
-
const file = readStateText(config, cwd,
|
|
8398
|
+
const path50 = companyIntentPath(entry.name);
|
|
8399
|
+
const file = readStateText(config, cwd, path50);
|
|
8204
8400
|
if (!file) continue;
|
|
8205
8401
|
records.push({
|
|
8206
8402
|
id: entry.name,
|
|
@@ -8211,8 +8407,8 @@ function listCompanyIntents(config, cwd) {
|
|
|
8211
8407
|
return records.sort((a, b) => a.intent.priority - b.intent.priority || a.id.localeCompare(b.id));
|
|
8212
8408
|
}
|
|
8213
8409
|
function readCompanyIntent(config, cwd, id) {
|
|
8214
|
-
const
|
|
8215
|
-
const file = readStateText(config, cwd,
|
|
8410
|
+
const path50 = companyIntentPath(id);
|
|
8411
|
+
const file = readStateText(config, cwd, path50);
|
|
8216
8412
|
if (!file) return null;
|
|
8217
8413
|
return { id, path: file.path, intent: normalizeCompanyIntent(file.path, JSON.parse(file.content)) };
|
|
8218
8414
|
}
|
|
@@ -8304,27 +8500,6 @@ var init_companyIntent = __esm({
|
|
|
8304
8500
|
}
|
|
8305
8501
|
});
|
|
8306
8502
|
|
|
8307
|
-
// src/goal/stateStore.ts
|
|
8308
|
-
function statePath(goalId) {
|
|
8309
|
-
return `goals/instances/${goalId}/state.json`;
|
|
8310
|
-
}
|
|
8311
|
-
function fetchGoalState(config, goalId, cwd) {
|
|
8312
|
-
const filePath = statePath(goalId);
|
|
8313
|
-
const loaded = readStateText(config, cwd, filePath);
|
|
8314
|
-
if (!loaded) return null;
|
|
8315
|
-
return parseGoalState(loaded.path, JSON.parse(loaded.content));
|
|
8316
|
-
}
|
|
8317
|
-
function putGoalState(config, goalId, state, message = `chore(goals): update ${goalId}`, cwd) {
|
|
8318
|
-
upsertStateText(config, cwd, statePath(goalId), serializeGoalState(state), message);
|
|
8319
|
-
}
|
|
8320
|
-
var init_stateStore = __esm({
|
|
8321
|
-
"src/goal/stateStore.ts"() {
|
|
8322
|
-
"use strict";
|
|
8323
|
-
init_stateRepo();
|
|
8324
|
-
init_state2();
|
|
8325
|
-
}
|
|
8326
|
-
});
|
|
8327
|
-
|
|
8328
8503
|
// src/scripts/applyCompanyManagerDecision.ts
|
|
8329
8504
|
function applyAction(config, cwd, action) {
|
|
8330
8505
|
if (action.kind === "createManagedGoal") {
|
|
@@ -9266,8 +9441,8 @@ var init_classifyByLabel = __esm({
|
|
|
9266
9441
|
});
|
|
9267
9442
|
|
|
9268
9443
|
// src/scripts/commitAndPush.ts
|
|
9269
|
-
import * as
|
|
9270
|
-
import * as
|
|
9444
|
+
import * as fs28 from "fs";
|
|
9445
|
+
import * as path27 from "path";
|
|
9271
9446
|
function sentinelPathForStage(cwd, profileName) {
|
|
9272
9447
|
const runId = resolveRunId();
|
|
9273
9448
|
return runtimeStatePath(cwd, "agent-runs", runId, `commit-${profileName}.lock`);
|
|
@@ -9288,9 +9463,9 @@ var init_commitAndPush = __esm({
|
|
|
9288
9463
|
}
|
|
9289
9464
|
const idempotencyEnabled = process.env.KODY_COMMIT_IDEMPOTENCY !== "0";
|
|
9290
9465
|
const sentinel = idempotencyEnabled ? sentinelPathForStage(ctx.cwd, profile.name) : null;
|
|
9291
|
-
if (sentinel &&
|
|
9466
|
+
if (sentinel && fs28.existsSync(sentinel)) {
|
|
9292
9467
|
try {
|
|
9293
|
-
const replay = JSON.parse(
|
|
9468
|
+
const replay = JSON.parse(fs28.readFileSync(sentinel, "utf-8"));
|
|
9294
9469
|
ctx.data.commitResult = replay.commitResult ?? { committed: false, pushed: false };
|
|
9295
9470
|
if (Array.isArray(replay.changedFiles)) ctx.data.changedFiles = replay.changedFiles;
|
|
9296
9471
|
if (typeof replay.hasCommitsAhead === "boolean") ctx.data.hasCommitsAhead = replay.hasCommitsAhead;
|
|
@@ -9343,8 +9518,8 @@ var init_commitAndPush = __esm({
|
|
|
9343
9518
|
const result = ctx.data.commitResult;
|
|
9344
9519
|
if (sentinel && result?.committed) {
|
|
9345
9520
|
try {
|
|
9346
|
-
|
|
9347
|
-
|
|
9521
|
+
fs28.mkdirSync(path27.dirname(sentinel), { recursive: true });
|
|
9522
|
+
fs28.writeFileSync(
|
|
9348
9523
|
sentinel,
|
|
9349
9524
|
JSON.stringify(
|
|
9350
9525
|
{
|
|
@@ -9435,8 +9610,8 @@ var init_commitGoalState = __esm({
|
|
|
9435
9610
|
});
|
|
9436
9611
|
|
|
9437
9612
|
// src/scripts/composePrompt.ts
|
|
9438
|
-
import * as
|
|
9439
|
-
import * as
|
|
9613
|
+
import * as fs29 from "fs";
|
|
9614
|
+
import * as path28 from "path";
|
|
9440
9615
|
function fenceUntrusted(value) {
|
|
9441
9616
|
if (value.trim().length === 0) return value;
|
|
9442
9617
|
const safe = value.replace(/-{3,}\s*END UNTRUSTED INPUT\s*-{3,}/gi, "[END UNTRUSTED INPUT]");
|
|
@@ -9559,10 +9734,10 @@ var init_composePrompt = __esm({
|
|
|
9559
9734
|
const explicit = ctx.data.promptTemplate;
|
|
9560
9735
|
const mode = ctx.args.mode;
|
|
9561
9736
|
const candidates = [
|
|
9562
|
-
explicit ?
|
|
9563
|
-
mode ?
|
|
9564
|
-
|
|
9565
|
-
|
|
9737
|
+
explicit ? path28.join(profile.dir, explicit) : null,
|
|
9738
|
+
mode ? path28.join(profile.dir, "prompts", `${mode}.md`) : null,
|
|
9739
|
+
path28.join(profile.dir, "prompt.md"),
|
|
9740
|
+
path28.join(profile.dir, "capability.md")
|
|
9566
9741
|
].filter(Boolean);
|
|
9567
9742
|
let templatePath = "";
|
|
9568
9743
|
let template = "";
|
|
@@ -9575,7 +9750,7 @@ var init_composePrompt = __esm({
|
|
|
9575
9750
|
break;
|
|
9576
9751
|
}
|
|
9577
9752
|
try {
|
|
9578
|
-
template =
|
|
9753
|
+
template = fs29.readFileSync(c, "utf-8");
|
|
9579
9754
|
templatePath = c;
|
|
9580
9755
|
break;
|
|
9581
9756
|
} catch (err) {
|
|
@@ -9586,7 +9761,7 @@ var init_composePrompt = __esm({
|
|
|
9586
9761
|
if (!templatePath) {
|
|
9587
9762
|
let dirState;
|
|
9588
9763
|
try {
|
|
9589
|
-
dirState = `dir contents: [${
|
|
9764
|
+
dirState = `dir contents: [${fs29.readdirSync(profile.dir).join(", ")}]`;
|
|
9590
9765
|
} catch (err) {
|
|
9591
9766
|
dirState = `readdir(${profile.dir}) failed: ${err?.code ?? String(err)}`;
|
|
9592
9767
|
}
|
|
@@ -10186,19 +10361,19 @@ var init_deriveQaScopeFromIssue = __esm({
|
|
|
10186
10361
|
|
|
10187
10362
|
// src/scripts/diagMcp.ts
|
|
10188
10363
|
import { execFileSync as execFileSync10 } from "child_process";
|
|
10189
|
-
import * as
|
|
10364
|
+
import * as fs30 from "fs";
|
|
10190
10365
|
import * as os6 from "os";
|
|
10191
|
-
import * as
|
|
10366
|
+
import * as path29 from "path";
|
|
10192
10367
|
var diagMcp;
|
|
10193
10368
|
var init_diagMcp = __esm({
|
|
10194
10369
|
"src/scripts/diagMcp.ts"() {
|
|
10195
10370
|
"use strict";
|
|
10196
10371
|
diagMcp = async (_ctx) => {
|
|
10197
10372
|
const home = os6.homedir();
|
|
10198
|
-
const cacheDir =
|
|
10373
|
+
const cacheDir = path29.join(home, ".cache", "ms-playwright");
|
|
10199
10374
|
let entries = [];
|
|
10200
10375
|
try {
|
|
10201
|
-
entries =
|
|
10376
|
+
entries = fs30.readdirSync(cacheDir);
|
|
10202
10377
|
} catch {
|
|
10203
10378
|
}
|
|
10204
10379
|
const hasChromium = entries.some((e) => e.startsWith("chromium"));
|
|
@@ -10226,13 +10401,13 @@ var init_diagMcp = __esm({
|
|
|
10226
10401
|
});
|
|
10227
10402
|
|
|
10228
10403
|
// src/scripts/frameworkDetectors.ts
|
|
10229
|
-
import * as
|
|
10230
|
-
import * as
|
|
10404
|
+
import * as fs31 from "fs";
|
|
10405
|
+
import * as path30 from "path";
|
|
10231
10406
|
function detectFrameworks(cwd) {
|
|
10232
10407
|
const out = [];
|
|
10233
10408
|
let deps = {};
|
|
10234
10409
|
try {
|
|
10235
|
-
const pkg = JSON.parse(
|
|
10410
|
+
const pkg = JSON.parse(fs31.readFileSync(path30.join(cwd, "package.json"), "utf-8"));
|
|
10236
10411
|
deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
10237
10412
|
} catch {
|
|
10238
10413
|
return out;
|
|
@@ -10269,25 +10444,25 @@ function detectFrameworks(cwd) {
|
|
|
10269
10444
|
}
|
|
10270
10445
|
function findFile(cwd, candidates) {
|
|
10271
10446
|
for (const c of candidates) {
|
|
10272
|
-
if (
|
|
10447
|
+
if (fs31.existsSync(path30.join(cwd, c))) return c;
|
|
10273
10448
|
}
|
|
10274
10449
|
return null;
|
|
10275
10450
|
}
|
|
10276
10451
|
function discoverPayloadCollections(cwd) {
|
|
10277
10452
|
const out = [];
|
|
10278
10453
|
for (const dir of COLLECTION_DIRS) {
|
|
10279
|
-
const full =
|
|
10280
|
-
if (!
|
|
10454
|
+
const full = path30.join(cwd, dir);
|
|
10455
|
+
if (!fs31.existsSync(full)) continue;
|
|
10281
10456
|
let files;
|
|
10282
10457
|
try {
|
|
10283
|
-
files =
|
|
10458
|
+
files = fs31.readdirSync(full).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
|
|
10284
10459
|
} catch {
|
|
10285
10460
|
continue;
|
|
10286
10461
|
}
|
|
10287
10462
|
for (const file of files) {
|
|
10288
10463
|
try {
|
|
10289
|
-
const filePath =
|
|
10290
|
-
const content =
|
|
10464
|
+
const filePath = path30.join(full, file);
|
|
10465
|
+
const content = fs31.readFileSync(filePath, "utf-8").slice(0, 1e4);
|
|
10291
10466
|
const slugMatch = content.match(/slug:\s*['"]([a-z0-9-]+)['"]/);
|
|
10292
10467
|
if (!slugMatch) continue;
|
|
10293
10468
|
const slug2 = slugMatch[1];
|
|
@@ -10301,7 +10476,7 @@ function discoverPayloadCollections(cwd) {
|
|
|
10301
10476
|
out.push({
|
|
10302
10477
|
name,
|
|
10303
10478
|
slug: slug2,
|
|
10304
|
-
filePath:
|
|
10479
|
+
filePath: path30.relative(cwd, filePath),
|
|
10305
10480
|
fields: fields.slice(0, 20),
|
|
10306
10481
|
hasAdmin
|
|
10307
10482
|
});
|
|
@@ -10314,28 +10489,28 @@ function discoverPayloadCollections(cwd) {
|
|
|
10314
10489
|
function discoverAdminComponents(cwd, collections) {
|
|
10315
10490
|
const out = [];
|
|
10316
10491
|
for (const dir of ADMIN_COMPONENT_DIRS) {
|
|
10317
|
-
const full =
|
|
10318
|
-
if (!
|
|
10492
|
+
const full = path30.join(cwd, dir);
|
|
10493
|
+
if (!fs31.existsSync(full)) continue;
|
|
10319
10494
|
let entries;
|
|
10320
10495
|
try {
|
|
10321
|
-
entries =
|
|
10496
|
+
entries = fs31.readdirSync(full, { withFileTypes: true });
|
|
10322
10497
|
} catch {
|
|
10323
10498
|
continue;
|
|
10324
10499
|
}
|
|
10325
10500
|
for (const entry of entries) {
|
|
10326
|
-
const entryPath =
|
|
10501
|
+
const entryPath = path30.join(full, entry.name);
|
|
10327
10502
|
let name;
|
|
10328
10503
|
let filePath;
|
|
10329
10504
|
if (entry.isDirectory()) {
|
|
10330
10505
|
const indexFile = ["index.tsx", "index.ts", "index.jsx", "index.js"].find(
|
|
10331
|
-
(f) =>
|
|
10506
|
+
(f) => fs31.existsSync(path30.join(entryPath, f))
|
|
10332
10507
|
);
|
|
10333
10508
|
if (!indexFile) continue;
|
|
10334
10509
|
name = entry.name;
|
|
10335
|
-
filePath =
|
|
10510
|
+
filePath = path30.relative(cwd, path30.join(entryPath, indexFile));
|
|
10336
10511
|
} else if (/\.(tsx?|jsx?)$/.test(entry.name)) {
|
|
10337
10512
|
name = entry.name.replace(/\.(tsx?|jsx?)$/, "");
|
|
10338
|
-
filePath =
|
|
10513
|
+
filePath = path30.relative(cwd, entryPath);
|
|
10339
10514
|
} else {
|
|
10340
10515
|
continue;
|
|
10341
10516
|
}
|
|
@@ -10343,7 +10518,7 @@ function discoverAdminComponents(cwd, collections) {
|
|
|
10343
10518
|
if (collections) {
|
|
10344
10519
|
for (const col of collections) {
|
|
10345
10520
|
try {
|
|
10346
|
-
const colContent =
|
|
10521
|
+
const colContent = fs31.readFileSync(path30.join(cwd, col.filePath), "utf-8");
|
|
10347
10522
|
if (colContent.includes(name)) {
|
|
10348
10523
|
usedInCollection = col.slug;
|
|
10349
10524
|
break;
|
|
@@ -10361,8 +10536,8 @@ function scanApiRoutes(cwd) {
|
|
|
10361
10536
|
const out = [];
|
|
10362
10537
|
const appDirs = ["src/app", "app"];
|
|
10363
10538
|
for (const appDir of appDirs) {
|
|
10364
|
-
const apiDir =
|
|
10365
|
-
if (!
|
|
10539
|
+
const apiDir = path30.join(cwd, appDir, "api");
|
|
10540
|
+
if (!fs31.existsSync(apiDir)) continue;
|
|
10366
10541
|
walkApiRoutes(apiDir, "/api", cwd, out);
|
|
10367
10542
|
break;
|
|
10368
10543
|
}
|
|
@@ -10371,14 +10546,14 @@ function scanApiRoutes(cwd) {
|
|
|
10371
10546
|
function walkApiRoutes(dir, prefix, cwd, out) {
|
|
10372
10547
|
let entries;
|
|
10373
10548
|
try {
|
|
10374
|
-
entries =
|
|
10549
|
+
entries = fs31.readdirSync(dir, { withFileTypes: true });
|
|
10375
10550
|
} catch {
|
|
10376
10551
|
return;
|
|
10377
10552
|
}
|
|
10378
10553
|
const routeFile = entries.find((e) => e.isFile() && /^route\.(ts|js|tsx|jsx)$/.test(e.name));
|
|
10379
10554
|
if (routeFile) {
|
|
10380
10555
|
try {
|
|
10381
|
-
const content =
|
|
10556
|
+
const content = fs31.readFileSync(path30.join(dir, routeFile.name), "utf-8").slice(0, 5e3);
|
|
10382
10557
|
const methods = HTTP_METHODS.filter(
|
|
10383
10558
|
(m) => new RegExp(`export\\s+(?:async\\s+)?function\\s+${m}\\b`).test(content)
|
|
10384
10559
|
);
|
|
@@ -10386,7 +10561,7 @@ function walkApiRoutes(dir, prefix, cwd, out) {
|
|
|
10386
10561
|
out.push({
|
|
10387
10562
|
path: prefix,
|
|
10388
10563
|
methods,
|
|
10389
|
-
filePath:
|
|
10564
|
+
filePath: path30.relative(cwd, path30.join(dir, routeFile.name))
|
|
10390
10565
|
});
|
|
10391
10566
|
}
|
|
10392
10567
|
} catch {
|
|
@@ -10397,7 +10572,7 @@ function walkApiRoutes(dir, prefix, cwd, out) {
|
|
|
10397
10572
|
if (entry.name === "node_modules" || entry.name === ".next") continue;
|
|
10398
10573
|
let segment = entry.name;
|
|
10399
10574
|
if (segment.startsWith("(") && segment.endsWith(")")) {
|
|
10400
|
-
walkApiRoutes(
|
|
10575
|
+
walkApiRoutes(path30.join(dir, entry.name), prefix, cwd, out);
|
|
10401
10576
|
continue;
|
|
10402
10577
|
}
|
|
10403
10578
|
if (segment.startsWith("[[") && segment.endsWith("]]")) {
|
|
@@ -10405,16 +10580,16 @@ function walkApiRoutes(dir, prefix, cwd, out) {
|
|
|
10405
10580
|
} else if (segment.startsWith("[") && segment.endsWith("]")) {
|
|
10406
10581
|
segment = `:${segment.slice(1, -1)}`;
|
|
10407
10582
|
}
|
|
10408
|
-
walkApiRoutes(
|
|
10583
|
+
walkApiRoutes(path30.join(dir, entry.name), `${prefix}/${segment}`, cwd, out);
|
|
10409
10584
|
}
|
|
10410
10585
|
}
|
|
10411
10586
|
function scanEnvVars(cwd) {
|
|
10412
10587
|
const candidates = [".env.example", ".env.local.example", ".env.template"];
|
|
10413
10588
|
for (const envFile of candidates) {
|
|
10414
|
-
const envPath =
|
|
10415
|
-
if (!
|
|
10589
|
+
const envPath = path30.join(cwd, envFile);
|
|
10590
|
+
if (!fs31.existsSync(envPath)) continue;
|
|
10416
10591
|
try {
|
|
10417
|
-
const content =
|
|
10592
|
+
const content = fs31.readFileSync(envPath, "utf-8");
|
|
10418
10593
|
const vars = [];
|
|
10419
10594
|
for (const line of content.split("\n")) {
|
|
10420
10595
|
const trimmed = line.trim();
|
|
@@ -10459,8 +10634,8 @@ var init_frameworkDetectors = __esm({
|
|
|
10459
10634
|
});
|
|
10460
10635
|
|
|
10461
10636
|
// src/scripts/discoverQaContext.ts
|
|
10462
|
-
import * as
|
|
10463
|
-
import * as
|
|
10637
|
+
import * as fs32 from "fs";
|
|
10638
|
+
import * as path31 from "path";
|
|
10464
10639
|
function runQaDiscovery(cwd) {
|
|
10465
10640
|
const out = {
|
|
10466
10641
|
routes: [],
|
|
@@ -10491,9 +10666,9 @@ function runQaDiscovery(cwd) {
|
|
|
10491
10666
|
}
|
|
10492
10667
|
function detectDevServer(cwd, out) {
|
|
10493
10668
|
try {
|
|
10494
|
-
const pkg = JSON.parse(
|
|
10669
|
+
const pkg = JSON.parse(fs32.readFileSync(path31.join(cwd, "package.json"), "utf-8"));
|
|
10495
10670
|
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
10496
|
-
const pm =
|
|
10671
|
+
const pm = fs32.existsSync(path31.join(cwd, "pnpm-lock.yaml")) ? "pnpm" : fs32.existsSync(path31.join(cwd, "yarn.lock")) ? "yarn" : fs32.existsSync(path31.join(cwd, "bun.lockb")) ? "bun" : "npm";
|
|
10497
10672
|
if (pkg.scripts?.dev) out.devCommand = `${pm} dev`;
|
|
10498
10673
|
if (allDeps.next || allDeps.nuxt) out.devPort = 3e3;
|
|
10499
10674
|
else if (allDeps.vite) out.devPort = 5173;
|
|
@@ -10503,8 +10678,8 @@ function detectDevServer(cwd, out) {
|
|
|
10503
10678
|
function scanFrontendRoutes(cwd, out) {
|
|
10504
10679
|
const appDirs = ["src/app", "app"];
|
|
10505
10680
|
for (const appDir of appDirs) {
|
|
10506
|
-
const full =
|
|
10507
|
-
if (!
|
|
10681
|
+
const full = path31.join(cwd, appDir);
|
|
10682
|
+
if (!fs32.existsSync(full)) continue;
|
|
10508
10683
|
walkFrontendRoutes(full, "", out);
|
|
10509
10684
|
break;
|
|
10510
10685
|
}
|
|
@@ -10512,7 +10687,7 @@ function scanFrontendRoutes(cwd, out) {
|
|
|
10512
10687
|
function walkFrontendRoutes(dir, prefix, out) {
|
|
10513
10688
|
let entries;
|
|
10514
10689
|
try {
|
|
10515
|
-
entries =
|
|
10690
|
+
entries = fs32.readdirSync(dir, { withFileTypes: true });
|
|
10516
10691
|
} catch {
|
|
10517
10692
|
return;
|
|
10518
10693
|
}
|
|
@@ -10529,7 +10704,7 @@ function walkFrontendRoutes(dir, prefix, out) {
|
|
|
10529
10704
|
if (entry.name === "node_modules" || entry.name === ".next") continue;
|
|
10530
10705
|
let segment = entry.name;
|
|
10531
10706
|
if (segment.startsWith("(") && segment.endsWith(")")) {
|
|
10532
|
-
walkFrontendRoutes(
|
|
10707
|
+
walkFrontendRoutes(path31.join(dir, entry.name), prefix, out);
|
|
10533
10708
|
continue;
|
|
10534
10709
|
}
|
|
10535
10710
|
if (segment.startsWith("[[") && segment.endsWith("]]")) {
|
|
@@ -10537,7 +10712,7 @@ function walkFrontendRoutes(dir, prefix, out) {
|
|
|
10537
10712
|
} else if (segment.startsWith("[") && segment.endsWith("]")) {
|
|
10538
10713
|
segment = `:${segment.slice(1, -1)}`;
|
|
10539
10714
|
}
|
|
10540
|
-
walkFrontendRoutes(
|
|
10715
|
+
walkFrontendRoutes(path31.join(dir, entry.name), `${prefix}/${segment}`, out);
|
|
10541
10716
|
}
|
|
10542
10717
|
}
|
|
10543
10718
|
function detectAuthFiles(cwd, out) {
|
|
@@ -10554,23 +10729,23 @@ function detectAuthFiles(cwd, out) {
|
|
|
10554
10729
|
"src/app/api/oauth"
|
|
10555
10730
|
];
|
|
10556
10731
|
for (const c of candidates) {
|
|
10557
|
-
if (
|
|
10732
|
+
if (fs32.existsSync(path31.join(cwd, c))) out.authFiles.push(c);
|
|
10558
10733
|
}
|
|
10559
10734
|
}
|
|
10560
10735
|
function detectRoles(cwd, out) {
|
|
10561
10736
|
const rolePaths = ["src/types", "src/lib", "src/utils", "src/constants", "src/access", "src/collections"];
|
|
10562
10737
|
for (const rp of rolePaths) {
|
|
10563
|
-
const dir =
|
|
10564
|
-
if (!
|
|
10738
|
+
const dir = path31.join(cwd, rp);
|
|
10739
|
+
if (!fs32.existsSync(dir)) continue;
|
|
10565
10740
|
let files;
|
|
10566
10741
|
try {
|
|
10567
|
-
files =
|
|
10742
|
+
files = fs32.readdirSync(dir).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
|
|
10568
10743
|
} catch {
|
|
10569
10744
|
continue;
|
|
10570
10745
|
}
|
|
10571
10746
|
for (const f of files) {
|
|
10572
10747
|
try {
|
|
10573
|
-
const content =
|
|
10748
|
+
const content = fs32.readFileSync(path31.join(dir, f), "utf-8").slice(0, 5e3);
|
|
10574
10749
|
const roleMatches = content.match(/(?:role|Role|ROLE)\s*[=:]\s*['"](\w+)['"]/g);
|
|
10575
10750
|
if (roleMatches) {
|
|
10576
10751
|
for (const m of roleMatches) {
|
|
@@ -11789,12 +11964,12 @@ var init_fixFlow = __esm({
|
|
|
11789
11964
|
|
|
11790
11965
|
// src/scripts/initFlow.ts
|
|
11791
11966
|
import { execFileSync as execFileSync15 } from "child_process";
|
|
11792
|
-
import * as
|
|
11793
|
-
import * as
|
|
11967
|
+
import * as fs33 from "fs";
|
|
11968
|
+
import * as path32 from "path";
|
|
11794
11969
|
function detectPackageManager(cwd) {
|
|
11795
|
-
if (
|
|
11796
|
-
if (
|
|
11797
|
-
if (
|
|
11970
|
+
if (fs33.existsSync(path32.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
11971
|
+
if (fs33.existsSync(path32.join(cwd, "yarn.lock"))) return "yarn";
|
|
11972
|
+
if (fs33.existsSync(path32.join(cwd, "bun.lockb"))) return "bun";
|
|
11798
11973
|
return "npm";
|
|
11799
11974
|
}
|
|
11800
11975
|
function qualityCommandsFor(pm) {
|
|
@@ -11866,22 +12041,22 @@ function performInit(cwd, force) {
|
|
|
11866
12041
|
const pm = detectPackageManager(cwd);
|
|
11867
12042
|
const ownerRepo = detectOwnerRepo(cwd);
|
|
11868
12043
|
const defaultBranch = defaultBranchFromGit(cwd);
|
|
11869
|
-
const configPath =
|
|
11870
|
-
if (
|
|
12044
|
+
const configPath = path32.join(cwd, "kody.config.json");
|
|
12045
|
+
if (fs33.existsSync(configPath) && !force) {
|
|
11871
12046
|
skipped.push("kody.config.json");
|
|
11872
12047
|
} else {
|
|
11873
12048
|
const cfg = makeConfig(pm, ownerRepo, defaultBranch);
|
|
11874
|
-
|
|
12049
|
+
fs33.writeFileSync(configPath, `${JSON.stringify(cfg, null, 2)}
|
|
11875
12050
|
`);
|
|
11876
12051
|
wrote.push("kody.config.json");
|
|
11877
12052
|
}
|
|
11878
|
-
const workflowDir =
|
|
11879
|
-
const workflowPath =
|
|
11880
|
-
if (
|
|
12053
|
+
const workflowDir = path32.join(cwd, ".github", "workflows");
|
|
12054
|
+
const workflowPath = path32.join(workflowDir, "kody.yml");
|
|
12055
|
+
if (fs33.existsSync(workflowPath) && !force) {
|
|
11881
12056
|
skipped.push(".github/workflows/kody.yml");
|
|
11882
12057
|
} else {
|
|
11883
|
-
|
|
11884
|
-
|
|
12058
|
+
fs33.mkdirSync(workflowDir, { recursive: true });
|
|
12059
|
+
fs33.writeFileSync(workflowPath, WORKFLOW_TEMPLATE);
|
|
11885
12060
|
wrote.push(".github/workflows/kody.yml");
|
|
11886
12061
|
}
|
|
11887
12062
|
for (const exe of listExecutables()) {
|
|
@@ -11892,12 +12067,12 @@ function performInit(cwd, force) {
|
|
|
11892
12067
|
continue;
|
|
11893
12068
|
}
|
|
11894
12069
|
if (profile.kind !== "scheduled" || !profile.schedule) continue;
|
|
11895
|
-
const target =
|
|
11896
|
-
if (
|
|
12070
|
+
const target = path32.join(workflowDir, `kody-${exe.name}.yml`);
|
|
12071
|
+
if (fs33.existsSync(target) && !force) {
|
|
11897
12072
|
skipped.push(`.github/workflows/kody-${exe.name}.yml`);
|
|
11898
12073
|
continue;
|
|
11899
12074
|
}
|
|
11900
|
-
|
|
12075
|
+
fs33.writeFileSync(target, renderScheduledWorkflow(exe.name, profile.schedule));
|
|
11901
12076
|
wrote.push(`.github/workflows/kody-${exe.name}.yml`);
|
|
11902
12077
|
}
|
|
11903
12078
|
let labels;
|
|
@@ -12050,7 +12225,7 @@ Nothing to do. All files already present. (Use --force to overwrite.)
|
|
|
12050
12225
|
});
|
|
12051
12226
|
|
|
12052
12227
|
// src/scripts/loadAgentAdhoc.ts
|
|
12053
|
-
import * as
|
|
12228
|
+
import * as fs34 from "fs";
|
|
12054
12229
|
function resolveMessage(messageArg) {
|
|
12055
12230
|
const fromComment = readCommentBody();
|
|
12056
12231
|
if (fromComment) return stripDirective(fromComment);
|
|
@@ -12058,9 +12233,9 @@ function resolveMessage(messageArg) {
|
|
|
12058
12233
|
}
|
|
12059
12234
|
function readCommentBody() {
|
|
12060
12235
|
const eventPath = process.env.GITHUB_EVENT_PATH;
|
|
12061
|
-
if (!eventPath || !
|
|
12236
|
+
if (!eventPath || !fs34.existsSync(eventPath)) return "";
|
|
12062
12237
|
try {
|
|
12063
|
-
const event = JSON.parse(
|
|
12238
|
+
const event = JSON.parse(fs34.readFileSync(eventPath, "utf-8"));
|
|
12064
12239
|
return String(event.comment?.body ?? "");
|
|
12065
12240
|
} catch {
|
|
12066
12241
|
return "";
|
|
@@ -12113,10 +12288,10 @@ var init_loadAgentAdhoc = __esm({
|
|
|
12113
12288
|
throw new Error("loadAgentAdhoc: ctx.args.agent must be a non-empty slug");
|
|
12114
12289
|
}
|
|
12115
12290
|
const agentPath = resolveAgentFile(ctx.cwd, agentSlug, agentsDir);
|
|
12116
|
-
if (!
|
|
12291
|
+
if (!fs34.existsSync(agentPath)) {
|
|
12117
12292
|
throw new Error(`loadAgentAdhoc: agent identity not found: ${agentPath}`);
|
|
12118
12293
|
}
|
|
12119
|
-
const { title, body } = parseAgentFile(
|
|
12294
|
+
const { title, body } = parseAgentFile(fs34.readFileSync(agentPath, "utf-8"), agentSlug);
|
|
12120
12295
|
const message = resolveMessage(ctx.args.message);
|
|
12121
12296
|
if (!message) {
|
|
12122
12297
|
throw new Error(
|
|
@@ -12354,8 +12529,8 @@ var init_loadIssueStateComment = __esm({
|
|
|
12354
12529
|
});
|
|
12355
12530
|
|
|
12356
12531
|
// src/scripts/loadJobFromFile.ts
|
|
12357
|
-
import * as
|
|
12358
|
-
import * as
|
|
12532
|
+
import * as fs35 from "fs";
|
|
12533
|
+
import * as path33 from "path";
|
|
12359
12534
|
function parseJobFile(raw, slug2) {
|
|
12360
12535
|
let stripped = raw;
|
|
12361
12536
|
if (stripped.startsWith("---\n")) {
|
|
@@ -12393,10 +12568,10 @@ var init_loadJobFromFile = __esm({
|
|
|
12393
12568
|
if (!slug2) {
|
|
12394
12569
|
throw new Error(`loadJobFromFile: ctx.args.${slugArg} must be a non-empty slug`);
|
|
12395
12570
|
}
|
|
12396
|
-
const capability = resolveCapabilityFolder(slug2,
|
|
12571
|
+
const capability = resolveCapabilityFolder(slug2, path33.join(ctx.cwd, jobsDir));
|
|
12397
12572
|
if (!capability) {
|
|
12398
12573
|
throw new Error(
|
|
12399
|
-
`loadJobFromFile: capability folder not found or incomplete: ${
|
|
12574
|
+
`loadJobFromFile: capability folder not found or incomplete: ${path33.join(ctx.cwd, jobsDir, slug2)}`
|
|
12400
12575
|
);
|
|
12401
12576
|
}
|
|
12402
12577
|
const { title, body, config } = capability;
|
|
@@ -12406,12 +12581,12 @@ var init_loadJobFromFile = __esm({
|
|
|
12406
12581
|
let agentIdentity = "";
|
|
12407
12582
|
if (agentSlug) {
|
|
12408
12583
|
const agentPath = resolveAgentFile(ctx.cwd, agentSlug, agentsDir);
|
|
12409
|
-
if (!
|
|
12584
|
+
if (!fs35.existsSync(agentPath)) {
|
|
12410
12585
|
throw new Error(
|
|
12411
12586
|
`loadJobFromFile: capability '${slug2}' declares agent '${agentSlug}' but ${agentPath} does not exist`
|
|
12412
12587
|
);
|
|
12413
12588
|
}
|
|
12414
|
-
const agentRaw =
|
|
12589
|
+
const agentRaw = fs35.readFileSync(agentPath, "utf-8");
|
|
12415
12590
|
const parsed = parseJobFile(agentRaw, agentSlug);
|
|
12416
12591
|
agentTitle = parsed.title;
|
|
12417
12592
|
agentIdentity = parsed.body;
|
|
@@ -12485,13 +12660,13 @@ ${truncate(issue.body, FINDING_BODY_MAX_BYTES)}`;
|
|
|
12485
12660
|
});
|
|
12486
12661
|
|
|
12487
12662
|
// src/scripts/kodyVariables.ts
|
|
12488
|
-
import * as
|
|
12489
|
-
import * as
|
|
12663
|
+
import * as fs36 from "fs";
|
|
12664
|
+
import * as path34 from "path";
|
|
12490
12665
|
function readKodyVariables(cwd) {
|
|
12491
|
-
const full =
|
|
12666
|
+
const full = path34.join(cwd, KODY_VARIABLES_REL_PATH);
|
|
12492
12667
|
let raw;
|
|
12493
12668
|
try {
|
|
12494
|
-
raw =
|
|
12669
|
+
raw = fs36.readFileSync(full, "utf-8");
|
|
12495
12670
|
} catch {
|
|
12496
12671
|
return {};
|
|
12497
12672
|
}
|
|
@@ -12516,8 +12691,8 @@ var init_kodyVariables = __esm({
|
|
|
12516
12691
|
});
|
|
12517
12692
|
|
|
12518
12693
|
// src/scripts/loadQaContext.ts
|
|
12519
|
-
import * as
|
|
12520
|
-
import * as
|
|
12694
|
+
import * as fs37 from "fs";
|
|
12695
|
+
import * as path35 from "path";
|
|
12521
12696
|
function parseSlugList(value) {
|
|
12522
12697
|
const inner = value.startsWith("[") && value.endsWith("]") ? value.slice(1, -1) : value;
|
|
12523
12698
|
return inner.split(",").map(
|
|
@@ -12546,18 +12721,18 @@ function readProfileAgents(raw) {
|
|
|
12546
12721
|
return { agent: agent ?? legacy ?? ["kody"], body };
|
|
12547
12722
|
}
|
|
12548
12723
|
function readProfile(cwd) {
|
|
12549
|
-
const dir =
|
|
12550
|
-
if (!
|
|
12724
|
+
const dir = path35.join(cwd, CONTEXT_DIR_REL_PATH);
|
|
12725
|
+
if (!fs37.existsSync(dir)) return "";
|
|
12551
12726
|
let entries;
|
|
12552
12727
|
try {
|
|
12553
|
-
entries =
|
|
12728
|
+
entries = fs37.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
|
|
12554
12729
|
} catch {
|
|
12555
12730
|
return "";
|
|
12556
12731
|
}
|
|
12557
12732
|
const blocks = [];
|
|
12558
12733
|
for (const file of entries) {
|
|
12559
12734
|
try {
|
|
12560
|
-
const raw =
|
|
12735
|
+
const raw = fs37.readFileSync(path35.join(dir, file), "utf-8");
|
|
12561
12736
|
const { agent, body } = readProfileAgents(raw);
|
|
12562
12737
|
if (!agent.includes(QA_AGENT) && !agent.includes(ALL_AGENTS)) continue;
|
|
12563
12738
|
blocks.push(`## ${file}
|
|
@@ -12603,8 +12778,8 @@ var init_loadQaContext = __esm({
|
|
|
12603
12778
|
});
|
|
12604
12779
|
|
|
12605
12780
|
// src/taskContext.ts
|
|
12606
|
-
import * as
|
|
12607
|
-
import * as
|
|
12781
|
+
import * as fs38 from "fs";
|
|
12782
|
+
import * as path36 from "path";
|
|
12608
12783
|
function buildTaskContext(args) {
|
|
12609
12784
|
return {
|
|
12610
12785
|
schemaVersion: TASK_CONTEXT_SCHEMA_VERSION,
|
|
@@ -12620,9 +12795,9 @@ function buildTaskContext(args) {
|
|
|
12620
12795
|
function persistTaskContext(cwd, ctx) {
|
|
12621
12796
|
try {
|
|
12622
12797
|
const dir = runtimeStatePath(cwd, "agent-runs", ctx.runId);
|
|
12623
|
-
|
|
12624
|
-
const file =
|
|
12625
|
-
|
|
12798
|
+
fs38.mkdirSync(dir, { recursive: true });
|
|
12799
|
+
const file = path36.join(dir, "task-context.json");
|
|
12800
|
+
fs38.writeFileSync(file, `${JSON.stringify(ctx, null, 2)}
|
|
12626
12801
|
`);
|
|
12627
12802
|
return file;
|
|
12628
12803
|
} catch (err) {
|
|
@@ -14967,8 +15142,8 @@ fi
|
|
|
14967
15142
|
});
|
|
14968
15143
|
|
|
14969
15144
|
// src/stateRepoGithub.ts
|
|
14970
|
-
import * as
|
|
14971
|
-
import * as
|
|
15145
|
+
import * as fs39 from "fs";
|
|
15146
|
+
import * as path37 from "path";
|
|
14972
15147
|
function recordValue3(value) {
|
|
14973
15148
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
14974
15149
|
}
|
|
@@ -15108,15 +15283,15 @@ function mergeJsonl(localText, remoteText) {
|
|
|
15108
15283
|
async function syncJsonlFileFromGithubState(opts) {
|
|
15109
15284
|
const remote = await readGithubStateTextWithConfig(opts);
|
|
15110
15285
|
if (!remote) return;
|
|
15111
|
-
const local =
|
|
15286
|
+
const local = fs39.existsSync(opts.localPath) ? fs39.readFileSync(opts.localPath, "utf-8") : "";
|
|
15112
15287
|
const next = mergeJsonl(local, remote.content);
|
|
15113
15288
|
if (next === local) return;
|
|
15114
|
-
|
|
15115
|
-
|
|
15289
|
+
fs39.mkdirSync(path37.dirname(opts.localPath), { recursive: true });
|
|
15290
|
+
fs39.writeFileSync(opts.localPath, next);
|
|
15116
15291
|
}
|
|
15117
15292
|
async function persistJsonlFileToGithubState(opts) {
|
|
15118
|
-
if (!
|
|
15119
|
-
const localText =
|
|
15293
|
+
if (!fs39.existsSync(opts.localPath)) return;
|
|
15294
|
+
const localText = fs39.readFileSync(opts.localPath, "utf-8");
|
|
15120
15295
|
for (let attempt = 1; attempt <= 3; attempt += 1) {
|
|
15121
15296
|
const remote = await readGithubStateTextWithConfig(opts);
|
|
15122
15297
|
const body = mergeJsonl(localText, remote?.content ?? "");
|
|
@@ -15150,12 +15325,12 @@ var init_stateRepoGithub = __esm({
|
|
|
15150
15325
|
|
|
15151
15326
|
// src/scripts/runPreviewBuild.ts
|
|
15152
15327
|
import { copyFile, writeFile } from "fs/promises";
|
|
15153
|
-
import * as
|
|
15328
|
+
import * as path38 from "path";
|
|
15154
15329
|
import { fileURLToPath } from "url";
|
|
15155
15330
|
function bundledDockerfilePath(mode) {
|
|
15156
|
-
const here =
|
|
15331
|
+
const here = path38.dirname(fileURLToPath(import.meta.url));
|
|
15157
15332
|
const file = mode === "dev" ? "default-Dockerfile.preview.dev" : "default-Dockerfile.preview.prod";
|
|
15158
|
-
return
|
|
15333
|
+
return path38.join(here, "preview-build-templates", file);
|
|
15159
15334
|
}
|
|
15160
15335
|
function required(name) {
|
|
15161
15336
|
const v = (process.env[name] ?? "").trim();
|
|
@@ -15406,10 +15581,10 @@ var init_runPreviewBuild = __esm({
|
|
|
15406
15581
|
console.log(`[preview-build] vault: ${Object.keys(buildEnv).length} secrets, mode=${buildMode}`);
|
|
15407
15582
|
if (Object.keys(buildEnv).length > 0) {
|
|
15408
15583
|
const lines = Object.entries(buildEnv).map(([k, v]) => `${k}=${JSON.stringify(v)}`);
|
|
15409
|
-
await writeFile(
|
|
15584
|
+
await writeFile(path38.join(ctx.cwd, ".env.production.local"), `${lines.join("\n")}
|
|
15410
15585
|
`, "utf8");
|
|
15411
15586
|
}
|
|
15412
|
-
const consumerDockerfile =
|
|
15587
|
+
const consumerDockerfile = path38.join(ctx.cwd, "Dockerfile.preview");
|
|
15413
15588
|
const { stat } = await import("fs/promises");
|
|
15414
15589
|
let hasConsumerDockerfile = false;
|
|
15415
15590
|
try {
|
|
@@ -15593,8 +15768,8 @@ var init_tickShellRunner = __esm({
|
|
|
15593
15768
|
});
|
|
15594
15769
|
|
|
15595
15770
|
// src/scripts/runScheduledExecutableTick.ts
|
|
15596
|
-
import * as
|
|
15597
|
-
import * as
|
|
15771
|
+
import * as fs40 from "fs";
|
|
15772
|
+
import * as path39 from "path";
|
|
15598
15773
|
var runScheduledExecutableTick;
|
|
15599
15774
|
var init_runScheduledExecutableTick = __esm({
|
|
15600
15775
|
"src/scripts/runScheduledExecutableTick.ts"() {
|
|
@@ -15614,14 +15789,14 @@ var init_runScheduledExecutableTick = __esm({
|
|
|
15614
15789
|
ctx.output.reason = `runScheduledExecutableTick: args.slug or ctx.args.${slugArg} must be non-empty capability slug`;
|
|
15615
15790
|
return;
|
|
15616
15791
|
}
|
|
15617
|
-
const capability = resolveCapabilityFolder(slug2,
|
|
15792
|
+
const capability = resolveCapabilityFolder(slug2, path39.join(ctx.cwd, jobsDir));
|
|
15618
15793
|
if (!capability) {
|
|
15619
15794
|
ctx.output.exitCode = 99;
|
|
15620
15795
|
ctx.output.reason = `runScheduledExecutableTick: capability folder not found or incomplete: ${slug2} (searched ${jobsDir} and company store)`;
|
|
15621
15796
|
return;
|
|
15622
15797
|
}
|
|
15623
|
-
const shellPath =
|
|
15624
|
-
if (!
|
|
15798
|
+
const shellPath = path39.join(profile.dir, shell);
|
|
15799
|
+
if (!fs40.existsSync(shellPath)) {
|
|
15625
15800
|
ctx.output.exitCode = 99;
|
|
15626
15801
|
ctx.output.reason = `runScheduledExecutableTick: shell not found: ${shell} (looked in ${profile.dir})`;
|
|
15627
15802
|
return;
|
|
@@ -15652,8 +15827,8 @@ var init_runScheduledExecutableTick = __esm({
|
|
|
15652
15827
|
});
|
|
15653
15828
|
|
|
15654
15829
|
// src/scripts/runTickScript.ts
|
|
15655
|
-
import * as
|
|
15656
|
-
import * as
|
|
15830
|
+
import * as fs41 from "fs";
|
|
15831
|
+
import * as path40 from "path";
|
|
15657
15832
|
var runTickScript;
|
|
15658
15833
|
var init_runTickScript = __esm({
|
|
15659
15834
|
"src/scripts/runTickScript.ts"() {
|
|
@@ -15672,10 +15847,10 @@ var init_runTickScript = __esm({
|
|
|
15672
15847
|
ctx.output.reason = `runTickScript: ctx.args.${slugArg} must be a non-empty slug`;
|
|
15673
15848
|
return;
|
|
15674
15849
|
}
|
|
15675
|
-
const capability = readCapabilityFolder(
|
|
15850
|
+
const capability = readCapabilityFolder(path40.join(ctx.cwd, jobsDir), slug2);
|
|
15676
15851
|
if (!capability) {
|
|
15677
15852
|
ctx.output.exitCode = 99;
|
|
15678
|
-
ctx.output.reason = `runTickScript: capability folder not found or incomplete: ${
|
|
15853
|
+
ctx.output.reason = `runTickScript: capability folder not found or incomplete: ${path40.join(ctx.cwd, jobsDir, slug2)}`;
|
|
15679
15854
|
return;
|
|
15680
15855
|
}
|
|
15681
15856
|
const tickScript = capability.config.tickScript;
|
|
@@ -15684,8 +15859,8 @@ var init_runTickScript = __esm({
|
|
|
15684
15859
|
ctx.output.reason = `runTickScript: capability ${slug2} has no \`tickScript\` in profile.json \u2014 route via capability-tick instead`;
|
|
15685
15860
|
return;
|
|
15686
15861
|
}
|
|
15687
|
-
const scriptPath =
|
|
15688
|
-
if (!
|
|
15862
|
+
const scriptPath = path40.isAbsolute(tickScript) ? tickScript : path40.join(ctx.cwd, tickScript);
|
|
15863
|
+
if (!fs41.existsSync(scriptPath)) {
|
|
15689
15864
|
ctx.output.exitCode = 99;
|
|
15690
15865
|
ctx.output.reason = `runTickScript: tickScript not found: ${scriptPath}`;
|
|
15691
15866
|
return;
|
|
@@ -16507,7 +16682,7 @@ var init_warmupMcp = __esm({
|
|
|
16507
16682
|
});
|
|
16508
16683
|
|
|
16509
16684
|
// src/scripts/writeAgentRunSummary.ts
|
|
16510
|
-
import * as
|
|
16685
|
+
import * as fs42 from "fs";
|
|
16511
16686
|
var writeAgentRunSummary;
|
|
16512
16687
|
var init_writeAgentRunSummary = __esm({
|
|
16513
16688
|
"src/scripts/writeAgentRunSummary.ts"() {
|
|
@@ -16533,7 +16708,7 @@ var init_writeAgentRunSummary = __esm({
|
|
|
16533
16708
|
if (reason) lines.push(`- **Reason:** ${reason}`);
|
|
16534
16709
|
lines.push("");
|
|
16535
16710
|
try {
|
|
16536
|
-
|
|
16711
|
+
fs42.appendFileSync(summaryPath, `${lines.join("\n")}
|
|
16537
16712
|
`);
|
|
16538
16713
|
} catch {
|
|
16539
16714
|
}
|
|
@@ -16853,22 +17028,22 @@ var init_scripts = __esm({
|
|
|
16853
17028
|
});
|
|
16854
17029
|
|
|
16855
17030
|
// src/stateWorkspace.ts
|
|
16856
|
-
import * as
|
|
16857
|
-
import * as
|
|
17031
|
+
import * as fs43 from "fs";
|
|
17032
|
+
import * as path41 from "path";
|
|
16858
17033
|
function writeLocalFile(cwd, relativePath, content) {
|
|
16859
|
-
const fullPath =
|
|
16860
|
-
|
|
16861
|
-
|
|
17034
|
+
const fullPath = path41.join(cwd, relativePath);
|
|
17035
|
+
fs43.mkdirSync(path41.dirname(fullPath), { recursive: true });
|
|
17036
|
+
fs43.writeFileSync(fullPath, content);
|
|
16862
17037
|
}
|
|
16863
17038
|
function hydrateDirectory(config, cwd, stateDir, localDir) {
|
|
16864
17039
|
const entries = listStateDirectory(config, cwd, stateDir);
|
|
16865
17040
|
if (entries.length === 0) return;
|
|
16866
17041
|
for (const entry of entries) {
|
|
16867
17042
|
if (!entry.name || !entry.type) continue;
|
|
16868
|
-
const childState =
|
|
16869
|
-
const childLocal =
|
|
17043
|
+
const childState = path41.posix.join(stateDir, entry.name);
|
|
17044
|
+
const childLocal = path41.join(localDir, entry.name);
|
|
16870
17045
|
if (entry.type === "dir") {
|
|
16871
|
-
|
|
17046
|
+
fs43.rmSync(path41.join(cwd, childLocal), { recursive: true, force: true });
|
|
16872
17047
|
hydrateDirectory(config, cwd, childState, childLocal);
|
|
16873
17048
|
} else if (entry.type === "file") {
|
|
16874
17049
|
const file = readStateText(config, cwd, childState);
|
|
@@ -16891,16 +17066,16 @@ var init_stateWorkspace = __esm({
|
|
|
16891
17066
|
"use strict";
|
|
16892
17067
|
init_stateRepo();
|
|
16893
17068
|
DIR_MAPPINGS = [
|
|
16894
|
-
{ stateDir: "executables", localDir:
|
|
16895
|
-
{ stateDir: "capabilities", localDir:
|
|
16896
|
-
{ stateDir: "agents", localDir:
|
|
16897
|
-
{ stateDir: "context", localDir:
|
|
16898
|
-
{ stateDir: "memory", localDir:
|
|
17069
|
+
{ stateDir: "executables", localDir: path41.join(".kody", "executables") },
|
|
17070
|
+
{ stateDir: "capabilities", localDir: path41.join(".kody", "capabilities") },
|
|
17071
|
+
{ stateDir: "agents", localDir: path41.join(".kody", "agents") },
|
|
17072
|
+
{ stateDir: "context", localDir: path41.join(".kody", "context") },
|
|
17073
|
+
{ stateDir: "memory", localDir: path41.join(".kody", "memory") }
|
|
16899
17074
|
];
|
|
16900
17075
|
FILE_MAPPINGS = [
|
|
16901
|
-
{ statePath: "instructions.md", localPath:
|
|
16902
|
-
{ statePath: "variables.json", localPath:
|
|
16903
|
-
{ statePath: "secrets.enc", localPath:
|
|
17076
|
+
{ statePath: "instructions.md", localPath: path41.join(".kody", "instructions.md") },
|
|
17077
|
+
{ statePath: "variables.json", localPath: path41.join(".kody", "variables.json") },
|
|
17078
|
+
{ statePath: "secrets.enc", localPath: path41.join(".kody", "secrets.enc") }
|
|
16904
17079
|
];
|
|
16905
17080
|
}
|
|
16906
17081
|
});
|
|
@@ -16971,8 +17146,8 @@ var init_tools = __esm({
|
|
|
16971
17146
|
|
|
16972
17147
|
// src/executor.ts
|
|
16973
17148
|
import { spawn as spawn7 } from "child_process";
|
|
16974
|
-
import * as
|
|
16975
|
-
import * as
|
|
17149
|
+
import * as fs44 from "fs";
|
|
17150
|
+
import * as path42 from "path";
|
|
16976
17151
|
function isMutatingPostflight(scriptName) {
|
|
16977
17152
|
return MUTATING_POSTFLIGHTS.has(scriptName ?? "");
|
|
16978
17153
|
}
|
|
@@ -17150,7 +17325,7 @@ async function runExecutable(profileName, input) {
|
|
|
17150
17325
|
const jobWhyBlock = typeof ctx.data.jobWhy === "string" ? operatorRequestBlock(ctx.data.jobWhy) : null;
|
|
17151
17326
|
const jobRefBlock = jobReferenceBlock(profileName, profile, ctx.data);
|
|
17152
17327
|
const invokeAgent = async (prompt) => {
|
|
17153
|
-
const externalPlugins = (profile.claudeCode.plugins ?? []).map((p) =>
|
|
17328
|
+
const externalPlugins = (profile.claudeCode.plugins ?? []).map((p) => path42.isAbsolute(p) ? p : path42.resolve(profile.dir, p)).filter((p) => p.length > 0);
|
|
17154
17329
|
const syntheticPath = ctx.data.syntheticPluginPath;
|
|
17155
17330
|
const pluginPaths = [...externalPlugins, ...syntheticPath ? [syntheticPath] : []];
|
|
17156
17331
|
const agents = loadSubagents(profile);
|
|
@@ -17542,17 +17717,17 @@ function clearStampedLifecycleLabels(profile, ctx) {
|
|
|
17542
17717
|
function resolveProfilePath(profileName) {
|
|
17543
17718
|
const found = resolveExecutable(profileName);
|
|
17544
17719
|
if (found) return found;
|
|
17545
|
-
const here =
|
|
17720
|
+
const here = path42.dirname(new URL(import.meta.url).pathname);
|
|
17546
17721
|
const candidates = [
|
|
17547
|
-
|
|
17722
|
+
path42.join(here, "executables", profileName, "profile.json"),
|
|
17548
17723
|
// same-dir sibling (dev)
|
|
17549
|
-
|
|
17724
|
+
path42.join(here, "..", "executables", profileName, "profile.json"),
|
|
17550
17725
|
// up one (prod: dist/bin → dist/executables)
|
|
17551
|
-
|
|
17726
|
+
path42.join(here, "..", "src", "executables", profileName, "profile.json")
|
|
17552
17727
|
// fallback
|
|
17553
17728
|
];
|
|
17554
17729
|
for (const c of candidates) {
|
|
17555
|
-
if (
|
|
17730
|
+
if (fs44.existsSync(c)) return c;
|
|
17556
17731
|
}
|
|
17557
17732
|
return candidates[0];
|
|
17558
17733
|
}
|
|
@@ -17650,8 +17825,8 @@ function resolveShellTimeoutMs(entry) {
|
|
|
17650
17825
|
}
|
|
17651
17826
|
async function runShellEntry(entry, ctx, profile) {
|
|
17652
17827
|
const shellName = entry.shell;
|
|
17653
|
-
const shellPath =
|
|
17654
|
-
if (!
|
|
17828
|
+
const shellPath = path42.join(profile.dir, shellName);
|
|
17829
|
+
if (!fs44.existsSync(shellPath)) {
|
|
17655
17830
|
ctx.skipAgent = true;
|
|
17656
17831
|
ctx.output.exitCode = 99;
|
|
17657
17832
|
ctx.output.reason = `shell script not found: ${shellName} (looked in ${profile.dir})`;
|
|
@@ -17801,8 +17976,8 @@ var init_executor = __esm({
|
|
|
17801
17976
|
});
|
|
17802
17977
|
|
|
17803
17978
|
// src/workflowDefinitions.ts
|
|
17804
|
-
import * as
|
|
17805
|
-
import * as
|
|
17979
|
+
import * as fs45 from "fs";
|
|
17980
|
+
import * as path43 from "path";
|
|
17806
17981
|
function isWorkflowDefinitionId(value) {
|
|
17807
17982
|
return WORKFLOW_ID_PATTERN.test(value);
|
|
17808
17983
|
}
|
|
@@ -17836,7 +18011,7 @@ function readWorkflowDefinition(config, cwd, id) {
|
|
|
17836
18011
|
function workflowDefinitionToCapabilityFolder(id, workflow, source = workflowDefinitionPath(id)) {
|
|
17837
18012
|
return {
|
|
17838
18013
|
slug: id,
|
|
17839
|
-
dir:
|
|
18014
|
+
dir: path43.dirname(source),
|
|
17840
18015
|
profilePath: source,
|
|
17841
18016
|
bodyPath: source,
|
|
17842
18017
|
title: workflow.name,
|
|
@@ -17871,9 +18046,9 @@ function workflowDefinitionToConfig(workflow) {
|
|
|
17871
18046
|
function readCompanyStoreWorkflowDefinition(id) {
|
|
17872
18047
|
const root = getCompanyStoreAssetRoot("workflows");
|
|
17873
18048
|
if (!root) return null;
|
|
17874
|
-
const filePath =
|
|
17875
|
-
if (!
|
|
17876
|
-
return parseWorkflowDefinition(
|
|
18049
|
+
const filePath = path43.join(root, id, "workflow.json");
|
|
18050
|
+
if (!fs45.existsSync(filePath)) return null;
|
|
18051
|
+
return parseWorkflowDefinition(fs45.readFileSync(filePath, "utf8"));
|
|
17877
18052
|
}
|
|
17878
18053
|
function parseWorkflowDefinition(content) {
|
|
17879
18054
|
try {
|
|
@@ -17905,7 +18080,7 @@ __export(job_exports, {
|
|
|
17905
18080
|
stableJobKey: () => stableJobKey,
|
|
17906
18081
|
validateJob: () => validateJob
|
|
17907
18082
|
});
|
|
17908
|
-
import * as
|
|
18083
|
+
import * as path44 from "path";
|
|
17909
18084
|
function newJobId(flavor) {
|
|
17910
18085
|
localJobSeq += 1;
|
|
17911
18086
|
const runId = process.env.GITHUB_RUN_ID;
|
|
@@ -17944,7 +18119,7 @@ function validateJob(input) {
|
|
|
17944
18119
|
async function runJob(job, base) {
|
|
17945
18120
|
const valid = validateJob(job);
|
|
17946
18121
|
const action = valid.action ?? valid.capability;
|
|
17947
|
-
const projectCapabilitiesRoot =
|
|
18122
|
+
const projectCapabilitiesRoot = path44.join(base.cwd, ".kody", "capabilities");
|
|
17948
18123
|
const resolvedCapability = !valid.workflow && action ? resolveCapabilityAction(action, projectCapabilitiesRoot) : null;
|
|
17949
18124
|
const capabilityIdentity = valid.capability ?? resolvedCapability?.capability;
|
|
17950
18125
|
const capabilityContext = valid.workflow ? null : loadCapabilityContext(capabilityIdentity, base.cwd);
|
|
@@ -18127,7 +18302,7 @@ function shouldRunWorkflowStep(step, data) {
|
|
|
18127
18302
|
if (!step.runWhen) return true;
|
|
18128
18303
|
const context = workflowConditionContext(data);
|
|
18129
18304
|
return Object.entries(step.runWhen).every(
|
|
18130
|
-
([
|
|
18305
|
+
([path50, expected]) => valueMatches(resolveDottedPath2(context, path50), expected)
|
|
18131
18306
|
);
|
|
18132
18307
|
}
|
|
18133
18308
|
function canContinueWorkflow(step, outcome) {
|
|
@@ -18197,7 +18372,7 @@ function composeStepWhy(parentWhy, step) {
|
|
|
18197
18372
|
}
|
|
18198
18373
|
function loadCapabilityContext(slug2, cwd) {
|
|
18199
18374
|
if (!slug2) return null;
|
|
18200
|
-
return resolveCapabilityFolder(slug2,
|
|
18375
|
+
return resolveCapabilityFolder(slug2, path44.join(cwd, ".kody", "capabilities"));
|
|
18201
18376
|
}
|
|
18202
18377
|
function loadWorkflowContext(slug2, base) {
|
|
18203
18378
|
if (!slug2 || !base.config || !isWorkflowDefinitionId(slug2)) return null;
|
|
@@ -18355,9 +18530,9 @@ function translateOpenAISseToBrain(opts) {
|
|
|
18355
18530
|
}
|
|
18356
18531
|
|
|
18357
18532
|
// src/servers/brain-serve.ts
|
|
18358
|
-
import * as
|
|
18533
|
+
import * as fs48 from "fs";
|
|
18359
18534
|
import { createServer } from "http";
|
|
18360
|
-
import * as
|
|
18535
|
+
import * as path47 from "path";
|
|
18361
18536
|
|
|
18362
18537
|
// src/chat/loop.ts
|
|
18363
18538
|
init_agent();
|
|
@@ -18917,8 +19092,8 @@ init_config();
|
|
|
18917
19092
|
|
|
18918
19093
|
// src/kody-cli.ts
|
|
18919
19094
|
import { execFileSync as execFileSync25 } from "child_process";
|
|
18920
|
-
import * as
|
|
18921
|
-
import * as
|
|
19095
|
+
import * as fs46 from "fs";
|
|
19096
|
+
import * as path45 from "path";
|
|
18922
19097
|
|
|
18923
19098
|
// src/app-auth.ts
|
|
18924
19099
|
import { createSign } from "crypto";
|
|
@@ -19539,9 +19714,9 @@ async function resolveAuthToken(env = process.env) {
|
|
|
19539
19714
|
return void 0;
|
|
19540
19715
|
}
|
|
19541
19716
|
function detectPackageManager2(cwd) {
|
|
19542
|
-
if (
|
|
19543
|
-
if (
|
|
19544
|
-
if (
|
|
19717
|
+
if (fs46.existsSync(path45.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
19718
|
+
if (fs46.existsSync(path45.join(cwd, "yarn.lock"))) return "yarn";
|
|
19719
|
+
if (fs46.existsSync(path45.join(cwd, "bun.lockb"))) return "bun";
|
|
19545
19720
|
return "npm";
|
|
19546
19721
|
}
|
|
19547
19722
|
function shouldChainScheduledWatch(match) {
|
|
@@ -19634,8 +19809,8 @@ function postFailureTail(issueNumber, cwd, reason) {
|
|
|
19634
19809
|
const logPath = lastRunLogPath(cwd);
|
|
19635
19810
|
let tail = "";
|
|
19636
19811
|
try {
|
|
19637
|
-
if (
|
|
19638
|
-
const content =
|
|
19812
|
+
if (fs46.existsSync(logPath)) {
|
|
19813
|
+
const content = fs46.readFileSync(logPath, "utf-8");
|
|
19639
19814
|
tail = content.slice(-3e3);
|
|
19640
19815
|
}
|
|
19641
19816
|
} catch {
|
|
@@ -19660,7 +19835,7 @@ async function runCi(argv) {
|
|
|
19660
19835
|
return 0;
|
|
19661
19836
|
}
|
|
19662
19837
|
const args = parseCiArgs(argv);
|
|
19663
|
-
const cwd = args.cwd ?
|
|
19838
|
+
const cwd = args.cwd ? path45.resolve(args.cwd) : process.cwd();
|
|
19664
19839
|
let earlyConfig;
|
|
19665
19840
|
let earlyConfigError;
|
|
19666
19841
|
try {
|
|
@@ -19675,9 +19850,17 @@ async function runCi(argv) {
|
|
|
19675
19850
|
let manualWorkflowDispatch = false;
|
|
19676
19851
|
let forceRunAction = null;
|
|
19677
19852
|
let forceRunCliArgs = {};
|
|
19678
|
-
|
|
19853
|
+
const envForceAction = (process.env.KODY_FORCE_ACTION ?? "").trim();
|
|
19854
|
+
const envForceMessage = (process.env.KODY_FORCE_MESSAGE ?? "").trim();
|
|
19855
|
+
if (!args.issueNumber && !autoFallback && envForceAction) {
|
|
19856
|
+
forceRunAction = envForceAction;
|
|
19857
|
+
if (envForceAction === "goal-manager" && envForceMessage) {
|
|
19858
|
+
forceRunCliArgs = { goal: envForceMessage };
|
|
19859
|
+
}
|
|
19860
|
+
}
|
|
19861
|
+
if (!args.issueNumber && !autoFallback && !forceRunAction && eventName === "workflow_dispatch" && dispatchEventPath && fs46.existsSync(dispatchEventPath)) {
|
|
19679
19862
|
try {
|
|
19680
|
-
const evt = JSON.parse(
|
|
19863
|
+
const evt = JSON.parse(fs46.readFileSync(dispatchEventPath, "utf-8"));
|
|
19681
19864
|
const issueInput = parseInt(String(evt?.inputs?.issue_number ?? ""), 10);
|
|
19682
19865
|
const sessionInput = String(evt?.inputs?.sessionId ?? "");
|
|
19683
19866
|
const dutyInput = String(evt?.inputs?.capability ?? evt?.inputs?.executable ?? "").trim();
|
|
@@ -20009,8 +20192,8 @@ init_repoWorkspace();
|
|
|
20009
20192
|
|
|
20010
20193
|
// src/scripts/brainTurnLog.ts
|
|
20011
20194
|
init_runtimePaths();
|
|
20012
|
-
import * as
|
|
20013
|
-
import * as
|
|
20195
|
+
import * as fs47 from "fs";
|
|
20196
|
+
import * as path46 from "path";
|
|
20014
20197
|
import posixPath4 from "path/posix";
|
|
20015
20198
|
var live = /* @__PURE__ */ new Map();
|
|
20016
20199
|
function brainEventsFilePath(dir, chatId) {
|
|
@@ -20021,8 +20204,8 @@ function brainEventsStatePath(chatId) {
|
|
|
20021
20204
|
}
|
|
20022
20205
|
function lastPersistedSeq(dir, chatId) {
|
|
20023
20206
|
const p = brainEventsFilePath(dir, chatId);
|
|
20024
|
-
if (!
|
|
20025
|
-
const lines =
|
|
20207
|
+
if (!fs47.existsSync(p)) return 0;
|
|
20208
|
+
const lines = fs47.readFileSync(p, "utf-8").split("\n").filter(Boolean);
|
|
20026
20209
|
if (lines.length === 0) return 0;
|
|
20027
20210
|
try {
|
|
20028
20211
|
return JSON.parse(lines[lines.length - 1]).seq || 0;
|
|
@@ -20032,9 +20215,9 @@ function lastPersistedSeq(dir, chatId) {
|
|
|
20032
20215
|
}
|
|
20033
20216
|
function readSince(dir, chatId, since) {
|
|
20034
20217
|
const p = brainEventsFilePath(dir, chatId);
|
|
20035
|
-
if (!
|
|
20218
|
+
if (!fs47.existsSync(p)) return [];
|
|
20036
20219
|
const out = [];
|
|
20037
|
-
for (const line of
|
|
20220
|
+
for (const line of fs47.readFileSync(p, "utf-8").split("\n")) {
|
|
20038
20221
|
if (!line) continue;
|
|
20039
20222
|
try {
|
|
20040
20223
|
const rec = JSON.parse(line);
|
|
@@ -20060,12 +20243,12 @@ function beginTurn(dir, chatId) {
|
|
|
20060
20243
|
};
|
|
20061
20244
|
live.set(chatId, state);
|
|
20062
20245
|
const p = brainEventsFilePath(dir, chatId);
|
|
20063
|
-
|
|
20246
|
+
fs47.mkdirSync(path46.dirname(p), { recursive: true });
|
|
20064
20247
|
return (event) => {
|
|
20065
20248
|
state.seq += 1;
|
|
20066
20249
|
const rec = { seq: state.seq, turn, ts: Date.now(), event };
|
|
20067
20250
|
try {
|
|
20068
|
-
|
|
20251
|
+
fs47.appendFileSync(p, `${JSON.stringify(rec)}
|
|
20069
20252
|
`);
|
|
20070
20253
|
} catch (err) {
|
|
20071
20254
|
process.stderr.write(
|
|
@@ -20104,7 +20287,7 @@ function endTurnIfUnterminated(dir, chatId, errMessage) {
|
|
|
20104
20287
|
event: { type: "error", error: errMessage || "turn ended unexpectedly", chatId }
|
|
20105
20288
|
};
|
|
20106
20289
|
try {
|
|
20107
|
-
|
|
20290
|
+
fs47.appendFileSync(brainEventsFilePath(dir, chatId), `${JSON.stringify(rec)}
|
|
20108
20291
|
`);
|
|
20109
20292
|
} catch {
|
|
20110
20293
|
}
|
|
@@ -20410,7 +20593,7 @@ async function handleChatTurn(req, res, chatId, opts) {
|
|
|
20410
20593
|
);
|
|
20411
20594
|
}
|
|
20412
20595
|
}
|
|
20413
|
-
|
|
20596
|
+
fs48.mkdirSync(path47.dirname(sessionFile), { recursive: true });
|
|
20414
20597
|
appendTurn(sessionFile, {
|
|
20415
20598
|
role: "user",
|
|
20416
20599
|
content: message,
|
|
@@ -20475,7 +20658,7 @@ async function handleChatTurn(req, res, chatId, opts) {
|
|
|
20475
20658
|
function buildServer(opts) {
|
|
20476
20659
|
const runTurn = opts.runTurn ?? runChatTurn;
|
|
20477
20660
|
const cloneRepo = opts.cloneRepo ?? defaultCloneRepo;
|
|
20478
|
-
const reposRoot = opts.reposRoot ??
|
|
20661
|
+
const reposRoot = opts.reposRoot ?? path47.join(path47.dirname(path47.resolve(opts.cwd)), "repos");
|
|
20479
20662
|
return createServer(async (req, res) => {
|
|
20480
20663
|
if (!req.method || !req.url) {
|
|
20481
20664
|
sendJson(res, 400, { error: "bad request" });
|
|
@@ -21070,8 +21253,8 @@ async function loadConfigSafe() {
|
|
|
21070
21253
|
}
|
|
21071
21254
|
|
|
21072
21255
|
// src/chat-cli.ts
|
|
21073
|
-
import * as
|
|
21074
|
-
import * as
|
|
21256
|
+
import * as fs50 from "fs";
|
|
21257
|
+
import * as path49 from "path";
|
|
21075
21258
|
|
|
21076
21259
|
// src/chat/inbox.ts
|
|
21077
21260
|
import { execFileSync as execFileSync26 } from "child_process";
|
|
@@ -21143,8 +21326,8 @@ function currentBranch(cwd) {
|
|
|
21143
21326
|
|
|
21144
21327
|
// src/chat/state-sync.ts
|
|
21145
21328
|
init_stateRepo();
|
|
21146
|
-
import * as
|
|
21147
|
-
import * as
|
|
21329
|
+
import * as fs49 from "fs";
|
|
21330
|
+
import * as path48 from "path";
|
|
21148
21331
|
function jsonlLines2(text) {
|
|
21149
21332
|
return text.split("\n").filter((line) => line.length > 0);
|
|
21150
21333
|
}
|
|
@@ -21161,15 +21344,15 @@ function mergeJsonl2(localText, remoteText) {
|
|
|
21161
21344
|
function syncJsonlFileFromState(opts) {
|
|
21162
21345
|
const remote = readStateText(opts.config, opts.cwd, opts.statePath);
|
|
21163
21346
|
if (!remote) return;
|
|
21164
|
-
const local =
|
|
21347
|
+
const local = fs49.existsSync(opts.localPath) ? fs49.readFileSync(opts.localPath, "utf-8") : "";
|
|
21165
21348
|
const next = mergeJsonl2(local, remote.content);
|
|
21166
21349
|
if (next === local) return;
|
|
21167
|
-
|
|
21168
|
-
|
|
21350
|
+
fs49.mkdirSync(path48.dirname(opts.localPath), { recursive: true });
|
|
21351
|
+
fs49.writeFileSync(opts.localPath, next);
|
|
21169
21352
|
}
|
|
21170
21353
|
function persistJsonlFileToState(opts) {
|
|
21171
|
-
if (!
|
|
21172
|
-
const localText =
|
|
21354
|
+
if (!fs49.existsSync(opts.localPath)) return;
|
|
21355
|
+
const localText = fs49.readFileSync(opts.localPath, "utf-8");
|
|
21173
21356
|
for (let attempt = 1; attempt <= 3; attempt += 1) {
|
|
21174
21357
|
const remote = readStateText(opts.config, opts.cwd, opts.statePath);
|
|
21175
21358
|
const body = mergeJsonl2(localText, remote?.content ?? "");
|
|
@@ -21429,7 +21612,7 @@ async function runChat(argv) {
|
|
|
21429
21612
|
${CHAT_HELP}`);
|
|
21430
21613
|
return 64;
|
|
21431
21614
|
}
|
|
21432
|
-
const cwd = args.cwd ?
|
|
21615
|
+
const cwd = args.cwd ? path49.resolve(args.cwd) : process.cwd();
|
|
21433
21616
|
const sessionId = args.sessionId;
|
|
21434
21617
|
const unpackedSecrets = unpackAllSecrets();
|
|
21435
21618
|
if (unpackedSecrets > 0) {
|
|
@@ -21490,7 +21673,7 @@ ${CHAT_HELP}`);
|
|
|
21490
21673
|
const sink = buildSink(cwd, sessionId, args.dashboardUrl);
|
|
21491
21674
|
const meta = readMeta(sessionFile);
|
|
21492
21675
|
process.stdout.write(
|
|
21493
|
-
`\u2192 kody:chat: session file=${sessionFile} exists=${
|
|
21676
|
+
`\u2192 kody:chat: session file=${sessionFile} exists=${fs50.existsSync(sessionFile)} meta=${meta ? meta.mode : "none"}
|
|
21494
21677
|
`
|
|
21495
21678
|
);
|
|
21496
21679
|
try {
|
|
@@ -21650,8 +21833,8 @@ var FlyClient = class {
|
|
|
21650
21833
|
get fetch() {
|
|
21651
21834
|
return this.opts.fetchImpl ?? fetch;
|
|
21652
21835
|
}
|
|
21653
|
-
async call(
|
|
21654
|
-
const res = await this.fetch(`${FLY_API_BASE}${
|
|
21836
|
+
async call(path50, init = {}) {
|
|
21837
|
+
const res = await this.fetch(`${FLY_API_BASE}${path50}`, {
|
|
21655
21838
|
method: init.method ?? "GET",
|
|
21656
21839
|
headers: {
|
|
21657
21840
|
Authorization: `Bearer ${this.opts.token}`,
|
|
@@ -21662,7 +21845,7 @@ var FlyClient = class {
|
|
|
21662
21845
|
if (res.status === 404 && init.allow404) return null;
|
|
21663
21846
|
if (!res.ok) {
|
|
21664
21847
|
const text = await res.text().catch(() => "");
|
|
21665
|
-
throw new Error(`Fly API ${res.status} on ${
|
|
21848
|
+
throw new Error(`Fly API ${res.status} on ${path50}: ${text.slice(0, 200) || res.statusText}`);
|
|
21666
21849
|
}
|
|
21667
21850
|
if (res.status === 204) return null;
|
|
21668
21851
|
const raw = await res.text();
|
|
@@ -22377,7 +22560,7 @@ async function poolServe() {
|
|
|
22377
22560
|
|
|
22378
22561
|
// src/servers/runner-serve.ts
|
|
22379
22562
|
import { spawn as spawn8 } from "child_process";
|
|
22380
|
-
import * as
|
|
22563
|
+
import * as fs51 from "fs";
|
|
22381
22564
|
import { createServer as createServer5 } from "http";
|
|
22382
22565
|
var DEFAULT_PORT2 = 8080;
|
|
22383
22566
|
var DEFAULT_WORKDIR = "/workspace/repo";
|
|
@@ -22446,6 +22629,9 @@ function parseJob(body) {
|
|
|
22446
22629
|
}
|
|
22447
22630
|
if (typeof b.ref === "string" && b.ref.trim()) job.ref = b.ref.trim();
|
|
22448
22631
|
if (typeof b.model === "string" && b.model.trim()) job.model = b.model.trim();
|
|
22632
|
+
if (typeof b.reasoningEffort === "string" && b.reasoningEffort.trim()) job.reasoningEffort = b.reasoningEffort.trim();
|
|
22633
|
+
if (typeof b.action === "string" && b.action.trim()) job.action = b.action.trim();
|
|
22634
|
+
if (typeof b.message === "string" && b.message.trim()) job.message = b.message.trim();
|
|
22449
22635
|
if (typeof b.sessionId === "string" && b.sessionId.trim()) job.sessionId = b.sessionId.trim();
|
|
22450
22636
|
if (typeof b.dashboardUrl === "string" && b.dashboardUrl.trim()) job.dashboardUrl = b.dashboardUrl.trim();
|
|
22451
22637
|
if (b.allSecrets && (typeof b.allSecrets === "object" || typeof b.allSecrets === "string")) {
|
|
@@ -22457,19 +22643,23 @@ async function defaultRunJob(job) {
|
|
|
22457
22643
|
const workdir = process.env.RUNNER_WORKDIR ?? DEFAULT_WORKDIR;
|
|
22458
22644
|
const branch = job.ref ?? "main";
|
|
22459
22645
|
const authUrl = `https://x-access-token:${job.githubToken}@github.com/${job.repo}.git`;
|
|
22460
|
-
|
|
22461
|
-
|
|
22646
|
+
fs51.rmSync(workdir, { recursive: true, force: true });
|
|
22647
|
+
fs51.mkdirSync(workdir, { recursive: true });
|
|
22462
22648
|
const allSecrets = typeof job.allSecrets === "string" ? job.allSecrets : JSON.stringify(job.allSecrets ?? {});
|
|
22463
22649
|
const interactive = job.mode === "interactive";
|
|
22464
22650
|
const scheduled = job.mode === "scheduled";
|
|
22651
|
+
const runMode = interactive ? "interactive" : scheduled ? "scheduled" : "issue";
|
|
22465
22652
|
const childEnv = {
|
|
22466
22653
|
...process.env,
|
|
22467
22654
|
REPO: job.repo,
|
|
22468
22655
|
REF: branch,
|
|
22469
22656
|
GITHUB_TOKEN: job.githubToken,
|
|
22657
|
+
KODY_RUN_MODE: runMode,
|
|
22470
22658
|
// Scheduled mode drives the engine down the same path GitHub Actions' cron
|
|
22471
22659
|
// takes (runScheduledFanOut → due capabilities/goals). Bare `kody` routes on this.
|
|
22472
22660
|
...scheduled ? { GITHUB_EVENT_NAME: "schedule" } : {},
|
|
22661
|
+
...job.action ? { KODY_FORCE_ACTION: job.action } : {},
|
|
22662
|
+
...job.message ? { KODY_FORCE_MESSAGE: job.message } : {},
|
|
22473
22663
|
// GITHUB_REPOSITORY + GH_TOKEN are normally injected by GitHub Actions.
|
|
22474
22664
|
// The engine's interactive mode needs GITHUB_REPOSITORY to resolve the
|
|
22475
22665
|
// configured state repo and persist chat.ready / events (the durable signal
|
|
@@ -22477,13 +22667,14 @@ async function defaultRunJob(job) {
|
|
|
22477
22667
|
// and the session never appears "ready". GH_TOKEN auths the `gh` CLI.
|
|
22478
22668
|
GITHUB_REPOSITORY: job.repo,
|
|
22479
22669
|
GH_TOKEN: job.githubToken,
|
|
22480
|
-
// Issue mode
|
|
22481
|
-
//
|
|
22670
|
+
// Issue mode carries ISSUE_NUMBER. Interactive mode leaves it empty and
|
|
22671
|
+
// sets SESSION_ID so the engine boots a chat session.
|
|
22482
22672
|
ISSUE_NUMBER: interactive || scheduled ? "" : String(job.issueNumber),
|
|
22483
22673
|
ALL_SECRETS: allSecrets,
|
|
22484
22674
|
SESSION_ID: job.sessionId ?? "",
|
|
22485
22675
|
DASHBOARD_URL: job.dashboardUrl ?? "",
|
|
22486
22676
|
MODEL: job.model ?? "",
|
|
22677
|
+
REASONING_EFFORT: job.reasoningEffort ?? "",
|
|
22487
22678
|
...interactive && job.idleExitMs ? { KODY_IDLE_EXIT_MS: String(job.idleExitMs) } : {},
|
|
22488
22679
|
...interactive && job.hardCapMs ? { KODY_HARD_CAP_MS: String(job.hardCapMs) } : {}
|
|
22489
22680
|
};
|
|
@@ -22509,11 +22700,10 @@ async function defaultRunJob(job) {
|
|
|
22509
22700
|
const authorEmail = process.env.GIT_AUTHOR_EMAIL ?? "kody-bot@users.noreply.github.com";
|
|
22510
22701
|
await run("git", ["config", "user.name", authorName], workdir);
|
|
22511
22702
|
await run("git", ["config", "user.email", authorEmail], workdir);
|
|
22512
|
-
const runArgs = interactive || scheduled ? [] : ["run", "--issue", String(job.issueNumber)];
|
|
22513
22703
|
const jobDesc = interactive ? `interactive session ${job.sessionId}` : scheduled ? "scheduled fan-out" : `running issue #${job.issueNumber}`;
|
|
22514
22704
|
process.stdout.write(`[runner-serve] job ${job.jobId}: ${jobDesc}
|
|
22515
22705
|
`);
|
|
22516
|
-
const runCode = await run("kody",
|
|
22706
|
+
const runCode = await run("kody", [], workdir);
|
|
22517
22707
|
process.stdout.write(`[runner-serve] job ${job.jobId}: finished (exit ${runCode})
|
|
22518
22708
|
`);
|
|
22519
22709
|
process.exit(runCode);
|
|
@@ -22903,6 +23093,25 @@ function formatMs(ms) {
|
|
|
22903
23093
|
}
|
|
22904
23094
|
|
|
22905
23095
|
// src/entry.ts
|
|
23096
|
+
function envRunMode(env = process.env) {
|
|
23097
|
+
const result = { command: "help", errors: [] };
|
|
23098
|
+
const mode = (env.KODY_RUN_MODE ?? "").trim().toLowerCase();
|
|
23099
|
+
if (!mode) return null;
|
|
23100
|
+
if (mode === "chat" || mode === "interactive") {
|
|
23101
|
+
return { ...result, command: "chat", chatArgv: [] };
|
|
23102
|
+
}
|
|
23103
|
+
if (mode === "ci" || mode === "scheduled" || mode === "manual") {
|
|
23104
|
+
return { ...result, command: "ci", ciArgv: [] };
|
|
23105
|
+
}
|
|
23106
|
+
if (mode === "issue") {
|
|
23107
|
+
const issue = (env.ISSUE_NUMBER ?? "").trim();
|
|
23108
|
+
if (!issue) {
|
|
23109
|
+
return { ...result, errors: ["KODY_RUN_MODE=issue requires ISSUE_NUMBER"] };
|
|
23110
|
+
}
|
|
23111
|
+
return { ...result, command: "ci", ciArgv: ["--issue", issue] };
|
|
23112
|
+
}
|
|
23113
|
+
return { ...result, errors: [`unknown KODY_RUN_MODE: ${mode}`] };
|
|
23114
|
+
}
|
|
22906
23115
|
var HELP_TEXT = `kody-engine \u2014 single-session autonomous engineer
|
|
22907
23116
|
|
|
22908
23117
|
Usage:
|
|
@@ -22939,6 +23148,8 @@ Exit codes:
|
|
|
22939
23148
|
function parseArgs(argv) {
|
|
22940
23149
|
const result = { command: "help", errors: [] };
|
|
22941
23150
|
if (argv.length === 0) {
|
|
23151
|
+
const mode = envRunMode();
|
|
23152
|
+
if (mode) return mode;
|
|
22942
23153
|
if (process.env.SESSION_ID) return { ...result, command: "chat", chatArgv: [] };
|
|
22943
23154
|
if (process.env.GITHUB_EVENT_NAME) return { ...result, command: "ci", ciArgv: [] };
|
|
22944
23155
|
return result;
|