@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.
Files changed (2) hide show
  1. package/dist/bin/kody.js +472 -261
  2. 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.272",
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, path49, init = {}) {
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}${path49}`, {
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(path49, message) {
6434
- super(`Invalid goal state at ${path49}:
6433
+ constructor(path50, message) {
6434
+ super(`Invalid goal state at ${path50}:
6435
6435
  ${message}`);
6436
- this.path = path49;
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 path49 = existing?.path ?? goalRunLogPath(goalId, data);
6449
+ const path50 = existing?.path ?? goalRunLogPath(goalId, data);
6450
6450
  logs[goalId] = {
6451
- path: path49,
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 fs26 from "fs";
7140
- import * as path24 from "path";
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 = path24.join(opts.cwd, opts.jobsDir);
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
- fs26.mkdirSync(this.absDir, { recursive: true });
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 (!fs26.existsSync(this.absDir)) {
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 = path24.join(this.cwd, relPath);
7257
- if (!fs26.existsSync(absPath)) {
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 = fs26.readFileSync(absPath, "utf-8");
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 = path24.join(this.cwd, loaded.path);
7278
- fs26.mkdirSync(path24.dirname(absPath), { recursive: true });
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
- fs26.writeFileSync(tmpPath, body, "utf-8");
7283
- fs26.renameSync(tmpPath, absPath);
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 path25 from "path";
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 dispatch2 = target.type === "goal" ? { action: "goal-manager", executable: "goal-manager", cliArgs: { goal: targetId } } : { workflow: targetId, cliArgs: {} };
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 = path25.join(opts.cwd, jobsDir);
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 decision2 = planTargetLoopSchedule({ goal: managed, previousScheduleState });
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(path49, raw) {
8353
+ function normalizeCompanyIntent(path50, raw) {
8158
8354
  if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
8159
- throw new Error(`${path49}: intent must be JSON object`);
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(`${path49}: invalid intent id`);
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 path49 = companyIntentPath(entry.name);
8203
- const file = readStateText(config, cwd, path49);
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 path49 = companyIntentPath(id);
8215
- const file = readStateText(config, cwd, path49);
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 fs27 from "fs";
9270
- import * as path26 from "path";
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 && fs27.existsSync(sentinel)) {
9466
+ if (sentinel && fs28.existsSync(sentinel)) {
9292
9467
  try {
9293
- const replay = JSON.parse(fs27.readFileSync(sentinel, "utf-8"));
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
- fs27.mkdirSync(path26.dirname(sentinel), { recursive: true });
9347
- fs27.writeFileSync(
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 fs28 from "fs";
9439
- import * as path27 from "path";
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 ? path27.join(profile.dir, explicit) : null,
9563
- mode ? path27.join(profile.dir, "prompts", `${mode}.md`) : null,
9564
- path27.join(profile.dir, "prompt.md"),
9565
- path27.join(profile.dir, "capability.md")
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 = fs28.readFileSync(c, "utf-8");
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: [${fs28.readdirSync(profile.dir).join(", ")}]`;
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 fs29 from "fs";
10364
+ import * as fs30 from "fs";
10190
10365
  import * as os6 from "os";
10191
- import * as path28 from "path";
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 = path28.join(home, ".cache", "ms-playwright");
10373
+ const cacheDir = path29.join(home, ".cache", "ms-playwright");
10199
10374
  let entries = [];
10200
10375
  try {
10201
- entries = fs29.readdirSync(cacheDir);
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 fs30 from "fs";
10230
- import * as path29 from "path";
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(fs30.readFileSync(path29.join(cwd, "package.json"), "utf-8"));
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 (fs30.existsSync(path29.join(cwd, c))) return c;
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 = path29.join(cwd, dir);
10280
- if (!fs30.existsSync(full)) continue;
10454
+ const full = path30.join(cwd, dir);
10455
+ if (!fs31.existsSync(full)) continue;
10281
10456
  let files;
10282
10457
  try {
10283
- files = fs30.readdirSync(full).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
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 = path29.join(full, file);
10290
- const content = fs30.readFileSync(filePath, "utf-8").slice(0, 1e4);
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: path29.relative(cwd, 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 = path29.join(cwd, dir);
10318
- if (!fs30.existsSync(full)) continue;
10492
+ const full = path30.join(cwd, dir);
10493
+ if (!fs31.existsSync(full)) continue;
10319
10494
  let entries;
10320
10495
  try {
10321
- entries = fs30.readdirSync(full, { withFileTypes: true });
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 = path29.join(full, entry.name);
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) => fs30.existsSync(path29.join(entryPath, f))
10506
+ (f) => fs31.existsSync(path30.join(entryPath, f))
10332
10507
  );
10333
10508
  if (!indexFile) continue;
10334
10509
  name = entry.name;
10335
- filePath = path29.relative(cwd, path29.join(entryPath, indexFile));
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 = path29.relative(cwd, entryPath);
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 = fs30.readFileSync(path29.join(cwd, col.filePath), "utf-8");
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 = path29.join(cwd, appDir, "api");
10365
- if (!fs30.existsSync(apiDir)) continue;
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 = fs30.readdirSync(dir, { withFileTypes: true });
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 = fs30.readFileSync(path29.join(dir, routeFile.name), "utf-8").slice(0, 5e3);
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: path29.relative(cwd, path29.join(dir, routeFile.name))
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(path29.join(dir, entry.name), prefix, cwd, out);
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(path29.join(dir, entry.name), `${prefix}/${segment}`, cwd, out);
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 = path29.join(cwd, envFile);
10415
- if (!fs30.existsSync(envPath)) continue;
10589
+ const envPath = path30.join(cwd, envFile);
10590
+ if (!fs31.existsSync(envPath)) continue;
10416
10591
  try {
10417
- const content = fs30.readFileSync(envPath, "utf-8");
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 fs31 from "fs";
10463
- import * as path30 from "path";
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(fs31.readFileSync(path30.join(cwd, "package.json"), "utf-8"));
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 = fs31.existsSync(path30.join(cwd, "pnpm-lock.yaml")) ? "pnpm" : fs31.existsSync(path30.join(cwd, "yarn.lock")) ? "yarn" : fs31.existsSync(path30.join(cwd, "bun.lockb")) ? "bun" : "npm";
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 = path30.join(cwd, appDir);
10507
- if (!fs31.existsSync(full)) continue;
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 = fs31.readdirSync(dir, { withFileTypes: true });
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(path30.join(dir, entry.name), prefix, out);
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(path30.join(dir, entry.name), `${prefix}/${segment}`, out);
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 (fs31.existsSync(path30.join(cwd, c))) out.authFiles.push(c);
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 = path30.join(cwd, rp);
10564
- if (!fs31.existsSync(dir)) continue;
10738
+ const dir = path31.join(cwd, rp);
10739
+ if (!fs32.existsSync(dir)) continue;
10565
10740
  let files;
10566
10741
  try {
10567
- files = fs31.readdirSync(dir).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
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 = fs31.readFileSync(path30.join(dir, f), "utf-8").slice(0, 5e3);
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 fs32 from "fs";
11793
- import * as path31 from "path";
11967
+ import * as fs33 from "fs";
11968
+ import * as path32 from "path";
11794
11969
  function detectPackageManager(cwd) {
11795
- if (fs32.existsSync(path31.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
11796
- if (fs32.existsSync(path31.join(cwd, "yarn.lock"))) return "yarn";
11797
- if (fs32.existsSync(path31.join(cwd, "bun.lockb"))) return "bun";
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 = path31.join(cwd, "kody.config.json");
11870
- if (fs32.existsSync(configPath) && !force) {
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
- fs32.writeFileSync(configPath, `${JSON.stringify(cfg, null, 2)}
12049
+ fs33.writeFileSync(configPath, `${JSON.stringify(cfg, null, 2)}
11875
12050
  `);
11876
12051
  wrote.push("kody.config.json");
11877
12052
  }
11878
- const workflowDir = path31.join(cwd, ".github", "workflows");
11879
- const workflowPath = path31.join(workflowDir, "kody.yml");
11880
- if (fs32.existsSync(workflowPath) && !force) {
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
- fs32.mkdirSync(workflowDir, { recursive: true });
11884
- fs32.writeFileSync(workflowPath, WORKFLOW_TEMPLATE);
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 = path31.join(workflowDir, `kody-${exe.name}.yml`);
11896
- if (fs32.existsSync(target) && !force) {
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
- fs32.writeFileSync(target, renderScheduledWorkflow(exe.name, profile.schedule));
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 fs33 from "fs";
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 || !fs33.existsSync(eventPath)) return "";
12236
+ if (!eventPath || !fs34.existsSync(eventPath)) return "";
12062
12237
  try {
12063
- const event = JSON.parse(fs33.readFileSync(eventPath, "utf-8"));
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 (!fs33.existsSync(agentPath)) {
12291
+ if (!fs34.existsSync(agentPath)) {
12117
12292
  throw new Error(`loadAgentAdhoc: agent identity not found: ${agentPath}`);
12118
12293
  }
12119
- const { title, body } = parseAgentFile(fs33.readFileSync(agentPath, "utf-8"), agentSlug);
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 fs34 from "fs";
12358
- import * as path32 from "path";
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, path32.join(ctx.cwd, jobsDir));
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: ${path32.join(ctx.cwd, jobsDir, slug2)}`
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 (!fs34.existsSync(agentPath)) {
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 = fs34.readFileSync(agentPath, "utf-8");
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 fs35 from "fs";
12489
- import * as path33 from "path";
12663
+ import * as fs36 from "fs";
12664
+ import * as path34 from "path";
12490
12665
  function readKodyVariables(cwd) {
12491
- const full = path33.join(cwd, KODY_VARIABLES_REL_PATH);
12666
+ const full = path34.join(cwd, KODY_VARIABLES_REL_PATH);
12492
12667
  let raw;
12493
12668
  try {
12494
- raw = fs35.readFileSync(full, "utf-8");
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 fs36 from "fs";
12520
- import * as path34 from "path";
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 = path34.join(cwd, CONTEXT_DIR_REL_PATH);
12550
- if (!fs36.existsSync(dir)) return "";
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 = fs36.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
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 = fs36.readFileSync(path34.join(dir, file), "utf-8");
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 fs37 from "fs";
12607
- import * as path35 from "path";
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
- fs37.mkdirSync(dir, { recursive: true });
12624
- const file = path35.join(dir, "task-context.json");
12625
- fs37.writeFileSync(file, `${JSON.stringify(ctx, null, 2)}
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 fs38 from "fs";
14971
- import * as path36 from "path";
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 = fs38.existsSync(opts.localPath) ? fs38.readFileSync(opts.localPath, "utf-8") : "";
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
- fs38.mkdirSync(path36.dirname(opts.localPath), { recursive: true });
15115
- fs38.writeFileSync(opts.localPath, next);
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 (!fs38.existsSync(opts.localPath)) return;
15119
- const localText = fs38.readFileSync(opts.localPath, "utf-8");
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 path37 from "path";
15328
+ import * as path38 from "path";
15154
15329
  import { fileURLToPath } from "url";
15155
15330
  function bundledDockerfilePath(mode) {
15156
- const here = path37.dirname(fileURLToPath(import.meta.url));
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 path37.join(here, "preview-build-templates", file);
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(path37.join(ctx.cwd, ".env.production.local"), `${lines.join("\n")}
15584
+ await writeFile(path38.join(ctx.cwd, ".env.production.local"), `${lines.join("\n")}
15410
15585
  `, "utf8");
15411
15586
  }
15412
- const consumerDockerfile = path37.join(ctx.cwd, "Dockerfile.preview");
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 fs39 from "fs";
15597
- import * as path38 from "path";
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, path38.join(ctx.cwd, jobsDir));
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 = path38.join(profile.dir, shell);
15624
- if (!fs39.existsSync(shellPath)) {
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 fs40 from "fs";
15656
- import * as path39 from "path";
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(path39.join(ctx.cwd, jobsDir), slug2);
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: ${path39.join(ctx.cwd, jobsDir, slug2)}`;
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 = path39.isAbsolute(tickScript) ? tickScript : path39.join(ctx.cwd, tickScript);
15688
- if (!fs40.existsSync(scriptPath)) {
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 fs41 from "fs";
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
- fs41.appendFileSync(summaryPath, `${lines.join("\n")}
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 fs42 from "fs";
16857
- import * as path40 from "path";
17031
+ import * as fs43 from "fs";
17032
+ import * as path41 from "path";
16858
17033
  function writeLocalFile(cwd, relativePath, content) {
16859
- const fullPath = path40.join(cwd, relativePath);
16860
- fs42.mkdirSync(path40.dirname(fullPath), { recursive: true });
16861
- fs42.writeFileSync(fullPath, content);
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 = path40.posix.join(stateDir, entry.name);
16869
- const childLocal = path40.join(localDir, entry.name);
17043
+ const childState = path41.posix.join(stateDir, entry.name);
17044
+ const childLocal = path41.join(localDir, entry.name);
16870
17045
  if (entry.type === "dir") {
16871
- fs42.rmSync(path40.join(cwd, childLocal), { recursive: true, force: true });
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: path40.join(".kody", "executables") },
16895
- { stateDir: "capabilities", localDir: path40.join(".kody", "capabilities") },
16896
- { stateDir: "agents", localDir: path40.join(".kody", "agents") },
16897
- { stateDir: "context", localDir: path40.join(".kody", "context") },
16898
- { stateDir: "memory", localDir: path40.join(".kody", "memory") }
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: path40.join(".kody", "instructions.md") },
16902
- { statePath: "variables.json", localPath: path40.join(".kody", "variables.json") },
16903
- { statePath: "secrets.enc", localPath: path40.join(".kody", "secrets.enc") }
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 fs43 from "fs";
16975
- import * as path41 from "path";
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) => path41.isAbsolute(p) ? p : path41.resolve(profile.dir, p)).filter((p) => p.length > 0);
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 = path41.dirname(new URL(import.meta.url).pathname);
17720
+ const here = path42.dirname(new URL(import.meta.url).pathname);
17546
17721
  const candidates = [
17547
- path41.join(here, "executables", profileName, "profile.json"),
17722
+ path42.join(here, "executables", profileName, "profile.json"),
17548
17723
  // same-dir sibling (dev)
17549
- path41.join(here, "..", "executables", profileName, "profile.json"),
17724
+ path42.join(here, "..", "executables", profileName, "profile.json"),
17550
17725
  // up one (prod: dist/bin → dist/executables)
17551
- path41.join(here, "..", "src", "executables", profileName, "profile.json")
17726
+ path42.join(here, "..", "src", "executables", profileName, "profile.json")
17552
17727
  // fallback
17553
17728
  ];
17554
17729
  for (const c of candidates) {
17555
- if (fs43.existsSync(c)) return c;
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 = path41.join(profile.dir, shellName);
17654
- if (!fs43.existsSync(shellPath)) {
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 fs44 from "fs";
17805
- import * as path42 from "path";
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: path42.dirname(source),
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 = path42.join(root, id, "workflow.json");
17875
- if (!fs44.existsSync(filePath)) return null;
17876
- return parseWorkflowDefinition(fs44.readFileSync(filePath, "utf8"));
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 path43 from "path";
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 = path43.join(base.cwd, ".kody", "capabilities");
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
- ([path49, expected]) => valueMatches(resolveDottedPath2(context, path49), expected)
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, path43.join(cwd, ".kody", "capabilities"));
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 fs47 from "fs";
18533
+ import * as fs48 from "fs";
18359
18534
  import { createServer } from "http";
18360
- import * as path46 from "path";
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 fs45 from "fs";
18921
- import * as path44 from "path";
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 (fs45.existsSync(path44.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
19543
- if (fs45.existsSync(path44.join(cwd, "yarn.lock"))) return "yarn";
19544
- if (fs45.existsSync(path44.join(cwd, "bun.lockb"))) return "bun";
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 (fs45.existsSync(logPath)) {
19638
- const content = fs45.readFileSync(logPath, "utf-8");
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 ? path44.resolve(args.cwd) : process.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
- if (!args.issueNumber && !autoFallback && eventName === "workflow_dispatch" && dispatchEventPath && fs45.existsSync(dispatchEventPath)) {
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(fs45.readFileSync(dispatchEventPath, "utf-8"));
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 fs46 from "fs";
20013
- import * as path45 from "path";
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 (!fs46.existsSync(p)) return 0;
20025
- const lines = fs46.readFileSync(p, "utf-8").split("\n").filter(Boolean);
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 (!fs46.existsSync(p)) return [];
20218
+ if (!fs47.existsSync(p)) return [];
20036
20219
  const out = [];
20037
- for (const line of fs46.readFileSync(p, "utf-8").split("\n")) {
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
- fs46.mkdirSync(path45.dirname(p), { recursive: true });
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
- fs46.appendFileSync(p, `${JSON.stringify(rec)}
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
- fs46.appendFileSync(brainEventsFilePath(dir, chatId), `${JSON.stringify(rec)}
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
- fs47.mkdirSync(path46.dirname(sessionFile), { recursive: true });
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 ?? path46.join(path46.dirname(path46.resolve(opts.cwd)), "repos");
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 fs49 from "fs";
21074
- import * as path48 from "path";
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 fs48 from "fs";
21147
- import * as path47 from "path";
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 = fs48.existsSync(opts.localPath) ? fs48.readFileSync(opts.localPath, "utf-8") : "";
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
- fs48.mkdirSync(path47.dirname(opts.localPath), { recursive: true });
21168
- fs48.writeFileSync(opts.localPath, next);
21350
+ fs49.mkdirSync(path48.dirname(opts.localPath), { recursive: true });
21351
+ fs49.writeFileSync(opts.localPath, next);
21169
21352
  }
21170
21353
  function persistJsonlFileToState(opts) {
21171
- if (!fs48.existsSync(opts.localPath)) return;
21172
- const localText = fs48.readFileSync(opts.localPath, "utf-8");
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 ? path48.resolve(args.cwd) : process.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=${fs49.existsSync(sessionFile)} meta=${meta ? meta.mode : "none"}
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(path49, init = {}) {
21654
- const res = await this.fetch(`${FLY_API_BASE}${path49}`, {
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 ${path49}: ${text.slice(0, 200) || res.statusText}`);
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 fs50 from "fs";
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
- fs50.rmSync(workdir, { recursive: true, force: true });
22461
- fs50.mkdirSync(workdir, { recursive: true });
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 bakes ISSUE_NUMBER `kody run --issue N`. Interactive mode
22481
- // leaves it empty and sets SESSION_ID so the engine boots a chat session.
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", runArgs, workdir);
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;