@kody-ade/kody-engine 0.4.273 → 0.4.275

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 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.273",
18
+ version: "0.4.275",
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") {
@@ -8633,7 +8808,7 @@ function refreshGoalDashboardReport(input) {
8633
8808
  if (!REPORT_SLUG_RE.test(input.goalId)) {
8634
8809
  throw new Error(`goal report: invalid goal id "${input.goalId}"`);
8635
8810
  }
8636
- const filePath = `reports/${input.goalId}.md`;
8811
+ const filePath = goalDashboardReportRunPath(input.goalId);
8637
8812
  const body = goalReportBody(
8638
8813
  input.goalId,
8639
8814
  input.state,
@@ -8641,17 +8816,15 @@ function refreshGoalDashboardReport(input) {
8641
8816
  latestGoalRunLogEvent(input.data, input.goalId),
8642
8817
  evidenceItems
8643
8818
  );
8644
- const current = readStateText(input.config, input.cwd, filePath);
8645
- if (current?.content === body) {
8646
- const report2 = { slug: input.goalId, path: current.path, changed: false };
8647
- recordGoalReport(input.data, report2);
8648
- return report2;
8649
- }
8650
- upsertStateText(input.config, input.cwd, filePath, body, `chore(reports): refresh ${input.goalId}`);
8819
+ writeStateText(input.config, input.cwd, filePath, body, `chore(reports): add ${input.goalId} run`);
8651
8820
  const report = { slug: input.goalId, path: filePath, changed: true };
8652
8821
  recordGoalReport(input.data, report);
8653
8822
  return report;
8654
8823
  }
8824
+ function goalDashboardReportRunPath(goalId, now = /* @__PURE__ */ new Date()) {
8825
+ const runId = now.toISOString().replace(/\.\d{3}Z$/, "Z").replace(/:/g, "-");
8826
+ return `reports/${goalId}/runs/${runId}.md`;
8827
+ }
8655
8828
  function capabilityEvidenceOutput(evidence) {
8656
8829
  return {
8657
8830
  kind: "capability-evidence",
@@ -9266,8 +9439,8 @@ var init_classifyByLabel = __esm({
9266
9439
  });
9267
9440
 
9268
9441
  // src/scripts/commitAndPush.ts
9269
- import * as fs27 from "fs";
9270
- import * as path26 from "path";
9442
+ import * as fs28 from "fs";
9443
+ import * as path27 from "path";
9271
9444
  function sentinelPathForStage(cwd, profileName) {
9272
9445
  const runId = resolveRunId();
9273
9446
  return runtimeStatePath(cwd, "agent-runs", runId, `commit-${profileName}.lock`);
@@ -9288,9 +9461,9 @@ var init_commitAndPush = __esm({
9288
9461
  }
9289
9462
  const idempotencyEnabled = process.env.KODY_COMMIT_IDEMPOTENCY !== "0";
9290
9463
  const sentinel = idempotencyEnabled ? sentinelPathForStage(ctx.cwd, profile.name) : null;
9291
- if (sentinel && fs27.existsSync(sentinel)) {
9464
+ if (sentinel && fs28.existsSync(sentinel)) {
9292
9465
  try {
9293
- const replay = JSON.parse(fs27.readFileSync(sentinel, "utf-8"));
9466
+ const replay = JSON.parse(fs28.readFileSync(sentinel, "utf-8"));
9294
9467
  ctx.data.commitResult = replay.commitResult ?? { committed: false, pushed: false };
9295
9468
  if (Array.isArray(replay.changedFiles)) ctx.data.changedFiles = replay.changedFiles;
9296
9469
  if (typeof replay.hasCommitsAhead === "boolean") ctx.data.hasCommitsAhead = replay.hasCommitsAhead;
@@ -9343,8 +9516,8 @@ var init_commitAndPush = __esm({
9343
9516
  const result = ctx.data.commitResult;
9344
9517
  if (sentinel && result?.committed) {
9345
9518
  try {
9346
- fs27.mkdirSync(path26.dirname(sentinel), { recursive: true });
9347
- fs27.writeFileSync(
9519
+ fs28.mkdirSync(path27.dirname(sentinel), { recursive: true });
9520
+ fs28.writeFileSync(
9348
9521
  sentinel,
9349
9522
  JSON.stringify(
9350
9523
  {
@@ -9435,8 +9608,8 @@ var init_commitGoalState = __esm({
9435
9608
  });
9436
9609
 
9437
9610
  // src/scripts/composePrompt.ts
9438
- import * as fs28 from "fs";
9439
- import * as path27 from "path";
9611
+ import * as fs29 from "fs";
9612
+ import * as path28 from "path";
9440
9613
  function fenceUntrusted(value) {
9441
9614
  if (value.trim().length === 0) return value;
9442
9615
  const safe = value.replace(/-{3,}\s*END UNTRUSTED INPUT\s*-{3,}/gi, "[END UNTRUSTED INPUT]");
@@ -9559,10 +9732,10 @@ var init_composePrompt = __esm({
9559
9732
  const explicit = ctx.data.promptTemplate;
9560
9733
  const mode = ctx.args.mode;
9561
9734
  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")
9735
+ explicit ? path28.join(profile.dir, explicit) : null,
9736
+ mode ? path28.join(profile.dir, "prompts", `${mode}.md`) : null,
9737
+ path28.join(profile.dir, "prompt.md"),
9738
+ path28.join(profile.dir, "capability.md")
9566
9739
  ].filter(Boolean);
9567
9740
  let templatePath = "";
9568
9741
  let template = "";
@@ -9575,7 +9748,7 @@ var init_composePrompt = __esm({
9575
9748
  break;
9576
9749
  }
9577
9750
  try {
9578
- template = fs28.readFileSync(c, "utf-8");
9751
+ template = fs29.readFileSync(c, "utf-8");
9579
9752
  templatePath = c;
9580
9753
  break;
9581
9754
  } catch (err) {
@@ -9586,7 +9759,7 @@ var init_composePrompt = __esm({
9586
9759
  if (!templatePath) {
9587
9760
  let dirState;
9588
9761
  try {
9589
- dirState = `dir contents: [${fs28.readdirSync(profile.dir).join(", ")}]`;
9762
+ dirState = `dir contents: [${fs29.readdirSync(profile.dir).join(", ")}]`;
9590
9763
  } catch (err) {
9591
9764
  dirState = `readdir(${profile.dir}) failed: ${err?.code ?? String(err)}`;
9592
9765
  }
@@ -10186,19 +10359,19 @@ var init_deriveQaScopeFromIssue = __esm({
10186
10359
 
10187
10360
  // src/scripts/diagMcp.ts
10188
10361
  import { execFileSync as execFileSync10 } from "child_process";
10189
- import * as fs29 from "fs";
10362
+ import * as fs30 from "fs";
10190
10363
  import * as os6 from "os";
10191
- import * as path28 from "path";
10364
+ import * as path29 from "path";
10192
10365
  var diagMcp;
10193
10366
  var init_diagMcp = __esm({
10194
10367
  "src/scripts/diagMcp.ts"() {
10195
10368
  "use strict";
10196
10369
  diagMcp = async (_ctx) => {
10197
10370
  const home = os6.homedir();
10198
- const cacheDir = path28.join(home, ".cache", "ms-playwright");
10371
+ const cacheDir = path29.join(home, ".cache", "ms-playwright");
10199
10372
  let entries = [];
10200
10373
  try {
10201
- entries = fs29.readdirSync(cacheDir);
10374
+ entries = fs30.readdirSync(cacheDir);
10202
10375
  } catch {
10203
10376
  }
10204
10377
  const hasChromium = entries.some((e) => e.startsWith("chromium"));
@@ -10226,13 +10399,13 @@ var init_diagMcp = __esm({
10226
10399
  });
10227
10400
 
10228
10401
  // src/scripts/frameworkDetectors.ts
10229
- import * as fs30 from "fs";
10230
- import * as path29 from "path";
10402
+ import * as fs31 from "fs";
10403
+ import * as path30 from "path";
10231
10404
  function detectFrameworks(cwd) {
10232
10405
  const out = [];
10233
10406
  let deps = {};
10234
10407
  try {
10235
- const pkg = JSON.parse(fs30.readFileSync(path29.join(cwd, "package.json"), "utf-8"));
10408
+ const pkg = JSON.parse(fs31.readFileSync(path30.join(cwd, "package.json"), "utf-8"));
10236
10409
  deps = { ...pkg.dependencies, ...pkg.devDependencies };
10237
10410
  } catch {
10238
10411
  return out;
@@ -10269,25 +10442,25 @@ function detectFrameworks(cwd) {
10269
10442
  }
10270
10443
  function findFile(cwd, candidates) {
10271
10444
  for (const c of candidates) {
10272
- if (fs30.existsSync(path29.join(cwd, c))) return c;
10445
+ if (fs31.existsSync(path30.join(cwd, c))) return c;
10273
10446
  }
10274
10447
  return null;
10275
10448
  }
10276
10449
  function discoverPayloadCollections(cwd) {
10277
10450
  const out = [];
10278
10451
  for (const dir of COLLECTION_DIRS) {
10279
- const full = path29.join(cwd, dir);
10280
- if (!fs30.existsSync(full)) continue;
10452
+ const full = path30.join(cwd, dir);
10453
+ if (!fs31.existsSync(full)) continue;
10281
10454
  let files;
10282
10455
  try {
10283
- files = fs30.readdirSync(full).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
10456
+ files = fs31.readdirSync(full).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
10284
10457
  } catch {
10285
10458
  continue;
10286
10459
  }
10287
10460
  for (const file of files) {
10288
10461
  try {
10289
- const filePath = path29.join(full, file);
10290
- const content = fs30.readFileSync(filePath, "utf-8").slice(0, 1e4);
10462
+ const filePath = path30.join(full, file);
10463
+ const content = fs31.readFileSync(filePath, "utf-8").slice(0, 1e4);
10291
10464
  const slugMatch = content.match(/slug:\s*['"]([a-z0-9-]+)['"]/);
10292
10465
  if (!slugMatch) continue;
10293
10466
  const slug2 = slugMatch[1];
@@ -10301,7 +10474,7 @@ function discoverPayloadCollections(cwd) {
10301
10474
  out.push({
10302
10475
  name,
10303
10476
  slug: slug2,
10304
- filePath: path29.relative(cwd, filePath),
10477
+ filePath: path30.relative(cwd, filePath),
10305
10478
  fields: fields.slice(0, 20),
10306
10479
  hasAdmin
10307
10480
  });
@@ -10314,28 +10487,28 @@ function discoverPayloadCollections(cwd) {
10314
10487
  function discoverAdminComponents(cwd, collections) {
10315
10488
  const out = [];
10316
10489
  for (const dir of ADMIN_COMPONENT_DIRS) {
10317
- const full = path29.join(cwd, dir);
10318
- if (!fs30.existsSync(full)) continue;
10490
+ const full = path30.join(cwd, dir);
10491
+ if (!fs31.existsSync(full)) continue;
10319
10492
  let entries;
10320
10493
  try {
10321
- entries = fs30.readdirSync(full, { withFileTypes: true });
10494
+ entries = fs31.readdirSync(full, { withFileTypes: true });
10322
10495
  } catch {
10323
10496
  continue;
10324
10497
  }
10325
10498
  for (const entry of entries) {
10326
- const entryPath = path29.join(full, entry.name);
10499
+ const entryPath = path30.join(full, entry.name);
10327
10500
  let name;
10328
10501
  let filePath;
10329
10502
  if (entry.isDirectory()) {
10330
10503
  const indexFile = ["index.tsx", "index.ts", "index.jsx", "index.js"].find(
10331
- (f) => fs30.existsSync(path29.join(entryPath, f))
10504
+ (f) => fs31.existsSync(path30.join(entryPath, f))
10332
10505
  );
10333
10506
  if (!indexFile) continue;
10334
10507
  name = entry.name;
10335
- filePath = path29.relative(cwd, path29.join(entryPath, indexFile));
10508
+ filePath = path30.relative(cwd, path30.join(entryPath, indexFile));
10336
10509
  } else if (/\.(tsx?|jsx?)$/.test(entry.name)) {
10337
10510
  name = entry.name.replace(/\.(tsx?|jsx?)$/, "");
10338
- filePath = path29.relative(cwd, entryPath);
10511
+ filePath = path30.relative(cwd, entryPath);
10339
10512
  } else {
10340
10513
  continue;
10341
10514
  }
@@ -10343,7 +10516,7 @@ function discoverAdminComponents(cwd, collections) {
10343
10516
  if (collections) {
10344
10517
  for (const col of collections) {
10345
10518
  try {
10346
- const colContent = fs30.readFileSync(path29.join(cwd, col.filePath), "utf-8");
10519
+ const colContent = fs31.readFileSync(path30.join(cwd, col.filePath), "utf-8");
10347
10520
  if (colContent.includes(name)) {
10348
10521
  usedInCollection = col.slug;
10349
10522
  break;
@@ -10361,8 +10534,8 @@ function scanApiRoutes(cwd) {
10361
10534
  const out = [];
10362
10535
  const appDirs = ["src/app", "app"];
10363
10536
  for (const appDir of appDirs) {
10364
- const apiDir = path29.join(cwd, appDir, "api");
10365
- if (!fs30.existsSync(apiDir)) continue;
10537
+ const apiDir = path30.join(cwd, appDir, "api");
10538
+ if (!fs31.existsSync(apiDir)) continue;
10366
10539
  walkApiRoutes(apiDir, "/api", cwd, out);
10367
10540
  break;
10368
10541
  }
@@ -10371,14 +10544,14 @@ function scanApiRoutes(cwd) {
10371
10544
  function walkApiRoutes(dir, prefix, cwd, out) {
10372
10545
  let entries;
10373
10546
  try {
10374
- entries = fs30.readdirSync(dir, { withFileTypes: true });
10547
+ entries = fs31.readdirSync(dir, { withFileTypes: true });
10375
10548
  } catch {
10376
10549
  return;
10377
10550
  }
10378
10551
  const routeFile = entries.find((e) => e.isFile() && /^route\.(ts|js|tsx|jsx)$/.test(e.name));
10379
10552
  if (routeFile) {
10380
10553
  try {
10381
- const content = fs30.readFileSync(path29.join(dir, routeFile.name), "utf-8").slice(0, 5e3);
10554
+ const content = fs31.readFileSync(path30.join(dir, routeFile.name), "utf-8").slice(0, 5e3);
10382
10555
  const methods = HTTP_METHODS.filter(
10383
10556
  (m) => new RegExp(`export\\s+(?:async\\s+)?function\\s+${m}\\b`).test(content)
10384
10557
  );
@@ -10386,7 +10559,7 @@ function walkApiRoutes(dir, prefix, cwd, out) {
10386
10559
  out.push({
10387
10560
  path: prefix,
10388
10561
  methods,
10389
- filePath: path29.relative(cwd, path29.join(dir, routeFile.name))
10562
+ filePath: path30.relative(cwd, path30.join(dir, routeFile.name))
10390
10563
  });
10391
10564
  }
10392
10565
  } catch {
@@ -10397,7 +10570,7 @@ function walkApiRoutes(dir, prefix, cwd, out) {
10397
10570
  if (entry.name === "node_modules" || entry.name === ".next") continue;
10398
10571
  let segment = entry.name;
10399
10572
  if (segment.startsWith("(") && segment.endsWith(")")) {
10400
- walkApiRoutes(path29.join(dir, entry.name), prefix, cwd, out);
10573
+ walkApiRoutes(path30.join(dir, entry.name), prefix, cwd, out);
10401
10574
  continue;
10402
10575
  }
10403
10576
  if (segment.startsWith("[[") && segment.endsWith("]]")) {
@@ -10405,16 +10578,16 @@ function walkApiRoutes(dir, prefix, cwd, out) {
10405
10578
  } else if (segment.startsWith("[") && segment.endsWith("]")) {
10406
10579
  segment = `:${segment.slice(1, -1)}`;
10407
10580
  }
10408
- walkApiRoutes(path29.join(dir, entry.name), `${prefix}/${segment}`, cwd, out);
10581
+ walkApiRoutes(path30.join(dir, entry.name), `${prefix}/${segment}`, cwd, out);
10409
10582
  }
10410
10583
  }
10411
10584
  function scanEnvVars(cwd) {
10412
10585
  const candidates = [".env.example", ".env.local.example", ".env.template"];
10413
10586
  for (const envFile of candidates) {
10414
- const envPath = path29.join(cwd, envFile);
10415
- if (!fs30.existsSync(envPath)) continue;
10587
+ const envPath = path30.join(cwd, envFile);
10588
+ if (!fs31.existsSync(envPath)) continue;
10416
10589
  try {
10417
- const content = fs30.readFileSync(envPath, "utf-8");
10590
+ const content = fs31.readFileSync(envPath, "utf-8");
10418
10591
  const vars = [];
10419
10592
  for (const line of content.split("\n")) {
10420
10593
  const trimmed = line.trim();
@@ -10459,8 +10632,8 @@ var init_frameworkDetectors = __esm({
10459
10632
  });
10460
10633
 
10461
10634
  // src/scripts/discoverQaContext.ts
10462
- import * as fs31 from "fs";
10463
- import * as path30 from "path";
10635
+ import * as fs32 from "fs";
10636
+ import * as path31 from "path";
10464
10637
  function runQaDiscovery(cwd) {
10465
10638
  const out = {
10466
10639
  routes: [],
@@ -10491,9 +10664,9 @@ function runQaDiscovery(cwd) {
10491
10664
  }
10492
10665
  function detectDevServer(cwd, out) {
10493
10666
  try {
10494
- const pkg = JSON.parse(fs31.readFileSync(path30.join(cwd, "package.json"), "utf-8"));
10667
+ const pkg = JSON.parse(fs32.readFileSync(path31.join(cwd, "package.json"), "utf-8"));
10495
10668
  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";
10669
+ 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
10670
  if (pkg.scripts?.dev) out.devCommand = `${pm} dev`;
10498
10671
  if (allDeps.next || allDeps.nuxt) out.devPort = 3e3;
10499
10672
  else if (allDeps.vite) out.devPort = 5173;
@@ -10503,8 +10676,8 @@ function detectDevServer(cwd, out) {
10503
10676
  function scanFrontendRoutes(cwd, out) {
10504
10677
  const appDirs = ["src/app", "app"];
10505
10678
  for (const appDir of appDirs) {
10506
- const full = path30.join(cwd, appDir);
10507
- if (!fs31.existsSync(full)) continue;
10679
+ const full = path31.join(cwd, appDir);
10680
+ if (!fs32.existsSync(full)) continue;
10508
10681
  walkFrontendRoutes(full, "", out);
10509
10682
  break;
10510
10683
  }
@@ -10512,7 +10685,7 @@ function scanFrontendRoutes(cwd, out) {
10512
10685
  function walkFrontendRoutes(dir, prefix, out) {
10513
10686
  let entries;
10514
10687
  try {
10515
- entries = fs31.readdirSync(dir, { withFileTypes: true });
10688
+ entries = fs32.readdirSync(dir, { withFileTypes: true });
10516
10689
  } catch {
10517
10690
  return;
10518
10691
  }
@@ -10529,7 +10702,7 @@ function walkFrontendRoutes(dir, prefix, out) {
10529
10702
  if (entry.name === "node_modules" || entry.name === ".next") continue;
10530
10703
  let segment = entry.name;
10531
10704
  if (segment.startsWith("(") && segment.endsWith(")")) {
10532
- walkFrontendRoutes(path30.join(dir, entry.name), prefix, out);
10705
+ walkFrontendRoutes(path31.join(dir, entry.name), prefix, out);
10533
10706
  continue;
10534
10707
  }
10535
10708
  if (segment.startsWith("[[") && segment.endsWith("]]")) {
@@ -10537,7 +10710,7 @@ function walkFrontendRoutes(dir, prefix, out) {
10537
10710
  } else if (segment.startsWith("[") && segment.endsWith("]")) {
10538
10711
  segment = `:${segment.slice(1, -1)}`;
10539
10712
  }
10540
- walkFrontendRoutes(path30.join(dir, entry.name), `${prefix}/${segment}`, out);
10713
+ walkFrontendRoutes(path31.join(dir, entry.name), `${prefix}/${segment}`, out);
10541
10714
  }
10542
10715
  }
10543
10716
  function detectAuthFiles(cwd, out) {
@@ -10554,23 +10727,23 @@ function detectAuthFiles(cwd, out) {
10554
10727
  "src/app/api/oauth"
10555
10728
  ];
10556
10729
  for (const c of candidates) {
10557
- if (fs31.existsSync(path30.join(cwd, c))) out.authFiles.push(c);
10730
+ if (fs32.existsSync(path31.join(cwd, c))) out.authFiles.push(c);
10558
10731
  }
10559
10732
  }
10560
10733
  function detectRoles(cwd, out) {
10561
10734
  const rolePaths = ["src/types", "src/lib", "src/utils", "src/constants", "src/access", "src/collections"];
10562
10735
  for (const rp of rolePaths) {
10563
- const dir = path30.join(cwd, rp);
10564
- if (!fs31.existsSync(dir)) continue;
10736
+ const dir = path31.join(cwd, rp);
10737
+ if (!fs32.existsSync(dir)) continue;
10565
10738
  let files;
10566
10739
  try {
10567
- files = fs31.readdirSync(dir).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
10740
+ files = fs32.readdirSync(dir).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
10568
10741
  } catch {
10569
10742
  continue;
10570
10743
  }
10571
10744
  for (const f of files) {
10572
10745
  try {
10573
- const content = fs31.readFileSync(path30.join(dir, f), "utf-8").slice(0, 5e3);
10746
+ const content = fs32.readFileSync(path31.join(dir, f), "utf-8").slice(0, 5e3);
10574
10747
  const roleMatches = content.match(/(?:role|Role|ROLE)\s*[=:]\s*['"](\w+)['"]/g);
10575
10748
  if (roleMatches) {
10576
10749
  for (const m of roleMatches) {
@@ -11789,12 +11962,12 @@ var init_fixFlow = __esm({
11789
11962
 
11790
11963
  // src/scripts/initFlow.ts
11791
11964
  import { execFileSync as execFileSync15 } from "child_process";
11792
- import * as fs32 from "fs";
11793
- import * as path31 from "path";
11965
+ import * as fs33 from "fs";
11966
+ import * as path32 from "path";
11794
11967
  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";
11968
+ if (fs33.existsSync(path32.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
11969
+ if (fs33.existsSync(path32.join(cwd, "yarn.lock"))) return "yarn";
11970
+ if (fs33.existsSync(path32.join(cwd, "bun.lockb"))) return "bun";
11798
11971
  return "npm";
11799
11972
  }
11800
11973
  function qualityCommandsFor(pm) {
@@ -11866,22 +12039,22 @@ function performInit(cwd, force) {
11866
12039
  const pm = detectPackageManager(cwd);
11867
12040
  const ownerRepo = detectOwnerRepo(cwd);
11868
12041
  const defaultBranch = defaultBranchFromGit(cwd);
11869
- const configPath = path31.join(cwd, "kody.config.json");
11870
- if (fs32.existsSync(configPath) && !force) {
12042
+ const configPath = path32.join(cwd, "kody.config.json");
12043
+ if (fs33.existsSync(configPath) && !force) {
11871
12044
  skipped.push("kody.config.json");
11872
12045
  } else {
11873
12046
  const cfg = makeConfig(pm, ownerRepo, defaultBranch);
11874
- fs32.writeFileSync(configPath, `${JSON.stringify(cfg, null, 2)}
12047
+ fs33.writeFileSync(configPath, `${JSON.stringify(cfg, null, 2)}
11875
12048
  `);
11876
12049
  wrote.push("kody.config.json");
11877
12050
  }
11878
- const workflowDir = path31.join(cwd, ".github", "workflows");
11879
- const workflowPath = path31.join(workflowDir, "kody.yml");
11880
- if (fs32.existsSync(workflowPath) && !force) {
12051
+ const workflowDir = path32.join(cwd, ".github", "workflows");
12052
+ const workflowPath = path32.join(workflowDir, "kody.yml");
12053
+ if (fs33.existsSync(workflowPath) && !force) {
11881
12054
  skipped.push(".github/workflows/kody.yml");
11882
12055
  } else {
11883
- fs32.mkdirSync(workflowDir, { recursive: true });
11884
- fs32.writeFileSync(workflowPath, WORKFLOW_TEMPLATE);
12056
+ fs33.mkdirSync(workflowDir, { recursive: true });
12057
+ fs33.writeFileSync(workflowPath, WORKFLOW_TEMPLATE);
11885
12058
  wrote.push(".github/workflows/kody.yml");
11886
12059
  }
11887
12060
  for (const exe of listExecutables()) {
@@ -11892,12 +12065,12 @@ function performInit(cwd, force) {
11892
12065
  continue;
11893
12066
  }
11894
12067
  if (profile.kind !== "scheduled" || !profile.schedule) continue;
11895
- const target = path31.join(workflowDir, `kody-${exe.name}.yml`);
11896
- if (fs32.existsSync(target) && !force) {
12068
+ const target = path32.join(workflowDir, `kody-${exe.name}.yml`);
12069
+ if (fs33.existsSync(target) && !force) {
11897
12070
  skipped.push(`.github/workflows/kody-${exe.name}.yml`);
11898
12071
  continue;
11899
12072
  }
11900
- fs32.writeFileSync(target, renderScheduledWorkflow(exe.name, profile.schedule));
12073
+ fs33.writeFileSync(target, renderScheduledWorkflow(exe.name, profile.schedule));
11901
12074
  wrote.push(`.github/workflows/kody-${exe.name}.yml`);
11902
12075
  }
11903
12076
  let labels;
@@ -12050,7 +12223,7 @@ Nothing to do. All files already present. (Use --force to overwrite.)
12050
12223
  });
12051
12224
 
12052
12225
  // src/scripts/loadAgentAdhoc.ts
12053
- import * as fs33 from "fs";
12226
+ import * as fs34 from "fs";
12054
12227
  function resolveMessage(messageArg) {
12055
12228
  const fromComment = readCommentBody();
12056
12229
  if (fromComment) return stripDirective(fromComment);
@@ -12058,9 +12231,9 @@ function resolveMessage(messageArg) {
12058
12231
  }
12059
12232
  function readCommentBody() {
12060
12233
  const eventPath = process.env.GITHUB_EVENT_PATH;
12061
- if (!eventPath || !fs33.existsSync(eventPath)) return "";
12234
+ if (!eventPath || !fs34.existsSync(eventPath)) return "";
12062
12235
  try {
12063
- const event = JSON.parse(fs33.readFileSync(eventPath, "utf-8"));
12236
+ const event = JSON.parse(fs34.readFileSync(eventPath, "utf-8"));
12064
12237
  return String(event.comment?.body ?? "");
12065
12238
  } catch {
12066
12239
  return "";
@@ -12113,10 +12286,10 @@ var init_loadAgentAdhoc = __esm({
12113
12286
  throw new Error("loadAgentAdhoc: ctx.args.agent must be a non-empty slug");
12114
12287
  }
12115
12288
  const agentPath = resolveAgentFile(ctx.cwd, agentSlug, agentsDir);
12116
- if (!fs33.existsSync(agentPath)) {
12289
+ if (!fs34.existsSync(agentPath)) {
12117
12290
  throw new Error(`loadAgentAdhoc: agent identity not found: ${agentPath}`);
12118
12291
  }
12119
- const { title, body } = parseAgentFile(fs33.readFileSync(agentPath, "utf-8"), agentSlug);
12292
+ const { title, body } = parseAgentFile(fs34.readFileSync(agentPath, "utf-8"), agentSlug);
12120
12293
  const message = resolveMessage(ctx.args.message);
12121
12294
  if (!message) {
12122
12295
  throw new Error(
@@ -12354,8 +12527,8 @@ var init_loadIssueStateComment = __esm({
12354
12527
  });
12355
12528
 
12356
12529
  // src/scripts/loadJobFromFile.ts
12357
- import * as fs34 from "fs";
12358
- import * as path32 from "path";
12530
+ import * as fs35 from "fs";
12531
+ import * as path33 from "path";
12359
12532
  function parseJobFile(raw, slug2) {
12360
12533
  let stripped = raw;
12361
12534
  if (stripped.startsWith("---\n")) {
@@ -12393,10 +12566,10 @@ var init_loadJobFromFile = __esm({
12393
12566
  if (!slug2) {
12394
12567
  throw new Error(`loadJobFromFile: ctx.args.${slugArg} must be a non-empty slug`);
12395
12568
  }
12396
- const capability = resolveCapabilityFolder(slug2, path32.join(ctx.cwd, jobsDir));
12569
+ const capability = resolveCapabilityFolder(slug2, path33.join(ctx.cwd, jobsDir));
12397
12570
  if (!capability) {
12398
12571
  throw new Error(
12399
- `loadJobFromFile: capability folder not found or incomplete: ${path32.join(ctx.cwd, jobsDir, slug2)}`
12572
+ `loadJobFromFile: capability folder not found or incomplete: ${path33.join(ctx.cwd, jobsDir, slug2)}`
12400
12573
  );
12401
12574
  }
12402
12575
  const { title, body, config } = capability;
@@ -12406,12 +12579,12 @@ var init_loadJobFromFile = __esm({
12406
12579
  let agentIdentity = "";
12407
12580
  if (agentSlug) {
12408
12581
  const agentPath = resolveAgentFile(ctx.cwd, agentSlug, agentsDir);
12409
- if (!fs34.existsSync(agentPath)) {
12582
+ if (!fs35.existsSync(agentPath)) {
12410
12583
  throw new Error(
12411
12584
  `loadJobFromFile: capability '${slug2}' declares agent '${agentSlug}' but ${agentPath} does not exist`
12412
12585
  );
12413
12586
  }
12414
- const agentRaw = fs34.readFileSync(agentPath, "utf-8");
12587
+ const agentRaw = fs35.readFileSync(agentPath, "utf-8");
12415
12588
  const parsed = parseJobFile(agentRaw, agentSlug);
12416
12589
  agentTitle = parsed.title;
12417
12590
  agentIdentity = parsed.body;
@@ -12485,13 +12658,13 @@ ${truncate(issue.body, FINDING_BODY_MAX_BYTES)}`;
12485
12658
  });
12486
12659
 
12487
12660
  // src/scripts/kodyVariables.ts
12488
- import * as fs35 from "fs";
12489
- import * as path33 from "path";
12661
+ import * as fs36 from "fs";
12662
+ import * as path34 from "path";
12490
12663
  function readKodyVariables(cwd) {
12491
- const full = path33.join(cwd, KODY_VARIABLES_REL_PATH);
12664
+ const full = path34.join(cwd, KODY_VARIABLES_REL_PATH);
12492
12665
  let raw;
12493
12666
  try {
12494
- raw = fs35.readFileSync(full, "utf-8");
12667
+ raw = fs36.readFileSync(full, "utf-8");
12495
12668
  } catch {
12496
12669
  return {};
12497
12670
  }
@@ -12516,8 +12689,8 @@ var init_kodyVariables = __esm({
12516
12689
  });
12517
12690
 
12518
12691
  // src/scripts/loadQaContext.ts
12519
- import * as fs36 from "fs";
12520
- import * as path34 from "path";
12692
+ import * as fs37 from "fs";
12693
+ import * as path35 from "path";
12521
12694
  function parseSlugList(value) {
12522
12695
  const inner = value.startsWith("[") && value.endsWith("]") ? value.slice(1, -1) : value;
12523
12696
  return inner.split(",").map(
@@ -12546,18 +12719,18 @@ function readProfileAgents(raw) {
12546
12719
  return { agent: agent ?? legacy ?? ["kody"], body };
12547
12720
  }
12548
12721
  function readProfile(cwd) {
12549
- const dir = path34.join(cwd, CONTEXT_DIR_REL_PATH);
12550
- if (!fs36.existsSync(dir)) return "";
12722
+ const dir = path35.join(cwd, CONTEXT_DIR_REL_PATH);
12723
+ if (!fs37.existsSync(dir)) return "";
12551
12724
  let entries;
12552
12725
  try {
12553
- entries = fs36.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
12726
+ entries = fs37.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
12554
12727
  } catch {
12555
12728
  return "";
12556
12729
  }
12557
12730
  const blocks = [];
12558
12731
  for (const file of entries) {
12559
12732
  try {
12560
- const raw = fs36.readFileSync(path34.join(dir, file), "utf-8");
12733
+ const raw = fs37.readFileSync(path35.join(dir, file), "utf-8");
12561
12734
  const { agent, body } = readProfileAgents(raw);
12562
12735
  if (!agent.includes(QA_AGENT) && !agent.includes(ALL_AGENTS)) continue;
12563
12736
  blocks.push(`## ${file}
@@ -12603,8 +12776,8 @@ var init_loadQaContext = __esm({
12603
12776
  });
12604
12777
 
12605
12778
  // src/taskContext.ts
12606
- import * as fs37 from "fs";
12607
- import * as path35 from "path";
12779
+ import * as fs38 from "fs";
12780
+ import * as path36 from "path";
12608
12781
  function buildTaskContext(args) {
12609
12782
  return {
12610
12783
  schemaVersion: TASK_CONTEXT_SCHEMA_VERSION,
@@ -12620,9 +12793,9 @@ function buildTaskContext(args) {
12620
12793
  function persistTaskContext(cwd, ctx) {
12621
12794
  try {
12622
12795
  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)}
12796
+ fs38.mkdirSync(dir, { recursive: true });
12797
+ const file = path36.join(dir, "task-context.json");
12798
+ fs38.writeFileSync(file, `${JSON.stringify(ctx, null, 2)}
12626
12799
  `);
12627
12800
  return file;
12628
12801
  } catch (err) {
@@ -14967,8 +15140,8 @@ fi
14967
15140
  });
14968
15141
 
14969
15142
  // src/stateRepoGithub.ts
14970
- import * as fs38 from "fs";
14971
- import * as path36 from "path";
15143
+ import * as fs39 from "fs";
15144
+ import * as path37 from "path";
14972
15145
  function recordValue3(value) {
14973
15146
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
14974
15147
  }
@@ -15108,15 +15281,15 @@ function mergeJsonl(localText, remoteText) {
15108
15281
  async function syncJsonlFileFromGithubState(opts) {
15109
15282
  const remote = await readGithubStateTextWithConfig(opts);
15110
15283
  if (!remote) return;
15111
- const local = fs38.existsSync(opts.localPath) ? fs38.readFileSync(opts.localPath, "utf-8") : "";
15284
+ const local = fs39.existsSync(opts.localPath) ? fs39.readFileSync(opts.localPath, "utf-8") : "";
15112
15285
  const next = mergeJsonl(local, remote.content);
15113
15286
  if (next === local) return;
15114
- fs38.mkdirSync(path36.dirname(opts.localPath), { recursive: true });
15115
- fs38.writeFileSync(opts.localPath, next);
15287
+ fs39.mkdirSync(path37.dirname(opts.localPath), { recursive: true });
15288
+ fs39.writeFileSync(opts.localPath, next);
15116
15289
  }
15117
15290
  async function persistJsonlFileToGithubState(opts) {
15118
- if (!fs38.existsSync(opts.localPath)) return;
15119
- const localText = fs38.readFileSync(opts.localPath, "utf-8");
15291
+ if (!fs39.existsSync(opts.localPath)) return;
15292
+ const localText = fs39.readFileSync(opts.localPath, "utf-8");
15120
15293
  for (let attempt = 1; attempt <= 3; attempt += 1) {
15121
15294
  const remote = await readGithubStateTextWithConfig(opts);
15122
15295
  const body = mergeJsonl(localText, remote?.content ?? "");
@@ -15150,12 +15323,12 @@ var init_stateRepoGithub = __esm({
15150
15323
 
15151
15324
  // src/scripts/runPreviewBuild.ts
15152
15325
  import { copyFile, writeFile } from "fs/promises";
15153
- import * as path37 from "path";
15326
+ import * as path38 from "path";
15154
15327
  import { fileURLToPath } from "url";
15155
15328
  function bundledDockerfilePath(mode) {
15156
- const here = path37.dirname(fileURLToPath(import.meta.url));
15329
+ const here = path38.dirname(fileURLToPath(import.meta.url));
15157
15330
  const file = mode === "dev" ? "default-Dockerfile.preview.dev" : "default-Dockerfile.preview.prod";
15158
- return path37.join(here, "preview-build-templates", file);
15331
+ return path38.join(here, "preview-build-templates", file);
15159
15332
  }
15160
15333
  function required(name) {
15161
15334
  const v = (process.env[name] ?? "").trim();
@@ -15406,10 +15579,10 @@ var init_runPreviewBuild = __esm({
15406
15579
  console.log(`[preview-build] vault: ${Object.keys(buildEnv).length} secrets, mode=${buildMode}`);
15407
15580
  if (Object.keys(buildEnv).length > 0) {
15408
15581
  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")}
15582
+ await writeFile(path38.join(ctx.cwd, ".env.production.local"), `${lines.join("\n")}
15410
15583
  `, "utf8");
15411
15584
  }
15412
- const consumerDockerfile = path37.join(ctx.cwd, "Dockerfile.preview");
15585
+ const consumerDockerfile = path38.join(ctx.cwd, "Dockerfile.preview");
15413
15586
  const { stat } = await import("fs/promises");
15414
15587
  let hasConsumerDockerfile = false;
15415
15588
  try {
@@ -15593,8 +15766,8 @@ var init_tickShellRunner = __esm({
15593
15766
  });
15594
15767
 
15595
15768
  // src/scripts/runScheduledExecutableTick.ts
15596
- import * as fs39 from "fs";
15597
- import * as path38 from "path";
15769
+ import * as fs40 from "fs";
15770
+ import * as path39 from "path";
15598
15771
  var runScheduledExecutableTick;
15599
15772
  var init_runScheduledExecutableTick = __esm({
15600
15773
  "src/scripts/runScheduledExecutableTick.ts"() {
@@ -15614,14 +15787,14 @@ var init_runScheduledExecutableTick = __esm({
15614
15787
  ctx.output.reason = `runScheduledExecutableTick: args.slug or ctx.args.${slugArg} must be non-empty capability slug`;
15615
15788
  return;
15616
15789
  }
15617
- const capability = resolveCapabilityFolder(slug2, path38.join(ctx.cwd, jobsDir));
15790
+ const capability = resolveCapabilityFolder(slug2, path39.join(ctx.cwd, jobsDir));
15618
15791
  if (!capability) {
15619
15792
  ctx.output.exitCode = 99;
15620
15793
  ctx.output.reason = `runScheduledExecutableTick: capability folder not found or incomplete: ${slug2} (searched ${jobsDir} and company store)`;
15621
15794
  return;
15622
15795
  }
15623
- const shellPath = path38.join(profile.dir, shell);
15624
- if (!fs39.existsSync(shellPath)) {
15796
+ const shellPath = path39.join(profile.dir, shell);
15797
+ if (!fs40.existsSync(shellPath)) {
15625
15798
  ctx.output.exitCode = 99;
15626
15799
  ctx.output.reason = `runScheduledExecutableTick: shell not found: ${shell} (looked in ${profile.dir})`;
15627
15800
  return;
@@ -15652,8 +15825,8 @@ var init_runScheduledExecutableTick = __esm({
15652
15825
  });
15653
15826
 
15654
15827
  // src/scripts/runTickScript.ts
15655
- import * as fs40 from "fs";
15656
- import * as path39 from "path";
15828
+ import * as fs41 from "fs";
15829
+ import * as path40 from "path";
15657
15830
  var runTickScript;
15658
15831
  var init_runTickScript = __esm({
15659
15832
  "src/scripts/runTickScript.ts"() {
@@ -15672,10 +15845,10 @@ var init_runTickScript = __esm({
15672
15845
  ctx.output.reason = `runTickScript: ctx.args.${slugArg} must be a non-empty slug`;
15673
15846
  return;
15674
15847
  }
15675
- const capability = readCapabilityFolder(path39.join(ctx.cwd, jobsDir), slug2);
15848
+ const capability = readCapabilityFolder(path40.join(ctx.cwd, jobsDir), slug2);
15676
15849
  if (!capability) {
15677
15850
  ctx.output.exitCode = 99;
15678
- ctx.output.reason = `runTickScript: capability folder not found or incomplete: ${path39.join(ctx.cwd, jobsDir, slug2)}`;
15851
+ ctx.output.reason = `runTickScript: capability folder not found or incomplete: ${path40.join(ctx.cwd, jobsDir, slug2)}`;
15679
15852
  return;
15680
15853
  }
15681
15854
  const tickScript = capability.config.tickScript;
@@ -15684,8 +15857,8 @@ var init_runTickScript = __esm({
15684
15857
  ctx.output.reason = `runTickScript: capability ${slug2} has no \`tickScript\` in profile.json \u2014 route via capability-tick instead`;
15685
15858
  return;
15686
15859
  }
15687
- const scriptPath = path39.isAbsolute(tickScript) ? tickScript : path39.join(ctx.cwd, tickScript);
15688
- if (!fs40.existsSync(scriptPath)) {
15860
+ const scriptPath = path40.isAbsolute(tickScript) ? tickScript : path40.join(ctx.cwd, tickScript);
15861
+ if (!fs41.existsSync(scriptPath)) {
15689
15862
  ctx.output.exitCode = 99;
15690
15863
  ctx.output.reason = `runTickScript: tickScript not found: ${scriptPath}`;
15691
15864
  return;
@@ -16507,7 +16680,7 @@ var init_warmupMcp = __esm({
16507
16680
  });
16508
16681
 
16509
16682
  // src/scripts/writeAgentRunSummary.ts
16510
- import * as fs41 from "fs";
16683
+ import * as fs42 from "fs";
16511
16684
  var writeAgentRunSummary;
16512
16685
  var init_writeAgentRunSummary = __esm({
16513
16686
  "src/scripts/writeAgentRunSummary.ts"() {
@@ -16533,7 +16706,7 @@ var init_writeAgentRunSummary = __esm({
16533
16706
  if (reason) lines.push(`- **Reason:** ${reason}`);
16534
16707
  lines.push("");
16535
16708
  try {
16536
- fs41.appendFileSync(summaryPath, `${lines.join("\n")}
16709
+ fs42.appendFileSync(summaryPath, `${lines.join("\n")}
16537
16710
  `);
16538
16711
  } catch {
16539
16712
  }
@@ -16853,22 +17026,22 @@ var init_scripts = __esm({
16853
17026
  });
16854
17027
 
16855
17028
  // src/stateWorkspace.ts
16856
- import * as fs42 from "fs";
16857
- import * as path40 from "path";
17029
+ import * as fs43 from "fs";
17030
+ import * as path41 from "path";
16858
17031
  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);
17032
+ const fullPath = path41.join(cwd, relativePath);
17033
+ fs43.mkdirSync(path41.dirname(fullPath), { recursive: true });
17034
+ fs43.writeFileSync(fullPath, content);
16862
17035
  }
16863
17036
  function hydrateDirectory(config, cwd, stateDir, localDir) {
16864
17037
  const entries = listStateDirectory(config, cwd, stateDir);
16865
17038
  if (entries.length === 0) return;
16866
17039
  for (const entry of entries) {
16867
17040
  if (!entry.name || !entry.type) continue;
16868
- const childState = path40.posix.join(stateDir, entry.name);
16869
- const childLocal = path40.join(localDir, entry.name);
17041
+ const childState = path41.posix.join(stateDir, entry.name);
17042
+ const childLocal = path41.join(localDir, entry.name);
16870
17043
  if (entry.type === "dir") {
16871
- fs42.rmSync(path40.join(cwd, childLocal), { recursive: true, force: true });
17044
+ fs43.rmSync(path41.join(cwd, childLocal), { recursive: true, force: true });
16872
17045
  hydrateDirectory(config, cwd, childState, childLocal);
16873
17046
  } else if (entry.type === "file") {
16874
17047
  const file = readStateText(config, cwd, childState);
@@ -16891,16 +17064,16 @@ var init_stateWorkspace = __esm({
16891
17064
  "use strict";
16892
17065
  init_stateRepo();
16893
17066
  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") }
17067
+ { stateDir: "executables", localDir: path41.join(".kody", "executables") },
17068
+ { stateDir: "capabilities", localDir: path41.join(".kody", "capabilities") },
17069
+ { stateDir: "agents", localDir: path41.join(".kody", "agents") },
17070
+ { stateDir: "context", localDir: path41.join(".kody", "context") },
17071
+ { stateDir: "memory", localDir: path41.join(".kody", "memory") }
16899
17072
  ];
16900
17073
  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") }
17074
+ { statePath: "instructions.md", localPath: path41.join(".kody", "instructions.md") },
17075
+ { statePath: "variables.json", localPath: path41.join(".kody", "variables.json") },
17076
+ { statePath: "secrets.enc", localPath: path41.join(".kody", "secrets.enc") }
16904
17077
  ];
16905
17078
  }
16906
17079
  });
@@ -16971,8 +17144,8 @@ var init_tools = __esm({
16971
17144
 
16972
17145
  // src/executor.ts
16973
17146
  import { spawn as spawn7 } from "child_process";
16974
- import * as fs43 from "fs";
16975
- import * as path41 from "path";
17147
+ import * as fs44 from "fs";
17148
+ import * as path42 from "path";
16976
17149
  function isMutatingPostflight(scriptName) {
16977
17150
  return MUTATING_POSTFLIGHTS.has(scriptName ?? "");
16978
17151
  }
@@ -17150,7 +17323,7 @@ async function runExecutable(profileName, input) {
17150
17323
  const jobWhyBlock = typeof ctx.data.jobWhy === "string" ? operatorRequestBlock(ctx.data.jobWhy) : null;
17151
17324
  const jobRefBlock = jobReferenceBlock(profileName, profile, ctx.data);
17152
17325
  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);
17326
+ const externalPlugins = (profile.claudeCode.plugins ?? []).map((p) => path42.isAbsolute(p) ? p : path42.resolve(profile.dir, p)).filter((p) => p.length > 0);
17154
17327
  const syntheticPath = ctx.data.syntheticPluginPath;
17155
17328
  const pluginPaths = [...externalPlugins, ...syntheticPath ? [syntheticPath] : []];
17156
17329
  const agents = loadSubagents(profile);
@@ -17542,17 +17715,17 @@ function clearStampedLifecycleLabels(profile, ctx) {
17542
17715
  function resolveProfilePath(profileName) {
17543
17716
  const found = resolveExecutable(profileName);
17544
17717
  if (found) return found;
17545
- const here = path41.dirname(new URL(import.meta.url).pathname);
17718
+ const here = path42.dirname(new URL(import.meta.url).pathname);
17546
17719
  const candidates = [
17547
- path41.join(here, "executables", profileName, "profile.json"),
17720
+ path42.join(here, "executables", profileName, "profile.json"),
17548
17721
  // same-dir sibling (dev)
17549
- path41.join(here, "..", "executables", profileName, "profile.json"),
17722
+ path42.join(here, "..", "executables", profileName, "profile.json"),
17550
17723
  // up one (prod: dist/bin → dist/executables)
17551
- path41.join(here, "..", "src", "executables", profileName, "profile.json")
17724
+ path42.join(here, "..", "src", "executables", profileName, "profile.json")
17552
17725
  // fallback
17553
17726
  ];
17554
17727
  for (const c of candidates) {
17555
- if (fs43.existsSync(c)) return c;
17728
+ if (fs44.existsSync(c)) return c;
17556
17729
  }
17557
17730
  return candidates[0];
17558
17731
  }
@@ -17650,8 +17823,8 @@ function resolveShellTimeoutMs(entry) {
17650
17823
  }
17651
17824
  async function runShellEntry(entry, ctx, profile) {
17652
17825
  const shellName = entry.shell;
17653
- const shellPath = path41.join(profile.dir, shellName);
17654
- if (!fs43.existsSync(shellPath)) {
17826
+ const shellPath = path42.join(profile.dir, shellName);
17827
+ if (!fs44.existsSync(shellPath)) {
17655
17828
  ctx.skipAgent = true;
17656
17829
  ctx.output.exitCode = 99;
17657
17830
  ctx.output.reason = `shell script not found: ${shellName} (looked in ${profile.dir})`;
@@ -17801,8 +17974,8 @@ var init_executor = __esm({
17801
17974
  });
17802
17975
 
17803
17976
  // src/workflowDefinitions.ts
17804
- import * as fs44 from "fs";
17805
- import * as path42 from "path";
17977
+ import * as fs45 from "fs";
17978
+ import * as path43 from "path";
17806
17979
  function isWorkflowDefinitionId(value) {
17807
17980
  return WORKFLOW_ID_PATTERN.test(value);
17808
17981
  }
@@ -17836,7 +18009,7 @@ function readWorkflowDefinition(config, cwd, id) {
17836
18009
  function workflowDefinitionToCapabilityFolder(id, workflow, source = workflowDefinitionPath(id)) {
17837
18010
  return {
17838
18011
  slug: id,
17839
- dir: path42.dirname(source),
18012
+ dir: path43.dirname(source),
17840
18013
  profilePath: source,
17841
18014
  bodyPath: source,
17842
18015
  title: workflow.name,
@@ -17871,9 +18044,9 @@ function workflowDefinitionToConfig(workflow) {
17871
18044
  function readCompanyStoreWorkflowDefinition(id) {
17872
18045
  const root = getCompanyStoreAssetRoot("workflows");
17873
18046
  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"));
18047
+ const filePath = path43.join(root, id, "workflow.json");
18048
+ if (!fs45.existsSync(filePath)) return null;
18049
+ return parseWorkflowDefinition(fs45.readFileSync(filePath, "utf8"));
17877
18050
  }
17878
18051
  function parseWorkflowDefinition(content) {
17879
18052
  try {
@@ -17905,7 +18078,7 @@ __export(job_exports, {
17905
18078
  stableJobKey: () => stableJobKey,
17906
18079
  validateJob: () => validateJob
17907
18080
  });
17908
- import * as path43 from "path";
18081
+ import * as path44 from "path";
17909
18082
  function newJobId(flavor) {
17910
18083
  localJobSeq += 1;
17911
18084
  const runId = process.env.GITHUB_RUN_ID;
@@ -17944,7 +18117,7 @@ function validateJob(input) {
17944
18117
  async function runJob(job, base) {
17945
18118
  const valid = validateJob(job);
17946
18119
  const action = valid.action ?? valid.capability;
17947
- const projectCapabilitiesRoot = path43.join(base.cwd, ".kody", "capabilities");
18120
+ const projectCapabilitiesRoot = path44.join(base.cwd, ".kody", "capabilities");
17948
18121
  const resolvedCapability = !valid.workflow && action ? resolveCapabilityAction(action, projectCapabilitiesRoot) : null;
17949
18122
  const capabilityIdentity = valid.capability ?? resolvedCapability?.capability;
17950
18123
  const capabilityContext = valid.workflow ? null : loadCapabilityContext(capabilityIdentity, base.cwd);
@@ -18127,7 +18300,7 @@ function shouldRunWorkflowStep(step, data) {
18127
18300
  if (!step.runWhen) return true;
18128
18301
  const context = workflowConditionContext(data);
18129
18302
  return Object.entries(step.runWhen).every(
18130
- ([path49, expected]) => valueMatches(resolveDottedPath2(context, path49), expected)
18303
+ ([path50, expected]) => valueMatches(resolveDottedPath2(context, path50), expected)
18131
18304
  );
18132
18305
  }
18133
18306
  function canContinueWorkflow(step, outcome) {
@@ -18197,7 +18370,7 @@ function composeStepWhy(parentWhy, step) {
18197
18370
  }
18198
18371
  function loadCapabilityContext(slug2, cwd) {
18199
18372
  if (!slug2) return null;
18200
- return resolveCapabilityFolder(slug2, path43.join(cwd, ".kody", "capabilities"));
18373
+ return resolveCapabilityFolder(slug2, path44.join(cwd, ".kody", "capabilities"));
18201
18374
  }
18202
18375
  function loadWorkflowContext(slug2, base) {
18203
18376
  if (!slug2 || !base.config || !isWorkflowDefinitionId(slug2)) return null;
@@ -18355,9 +18528,9 @@ function translateOpenAISseToBrain(opts) {
18355
18528
  }
18356
18529
 
18357
18530
  // src/servers/brain-serve.ts
18358
- import * as fs47 from "fs";
18531
+ import * as fs48 from "fs";
18359
18532
  import { createServer } from "http";
18360
- import * as path46 from "path";
18533
+ import * as path47 from "path";
18361
18534
 
18362
18535
  // src/chat/loop.ts
18363
18536
  init_agent();
@@ -18917,8 +19090,8 @@ init_config();
18917
19090
 
18918
19091
  // src/kody-cli.ts
18919
19092
  import { execFileSync as execFileSync25 } from "child_process";
18920
- import * as fs45 from "fs";
18921
- import * as path44 from "path";
19093
+ import * as fs46 from "fs";
19094
+ import * as path45 from "path";
18922
19095
 
18923
19096
  // src/app-auth.ts
18924
19097
  import { createSign } from "crypto";
@@ -19539,9 +19712,9 @@ async function resolveAuthToken(env = process.env) {
19539
19712
  return void 0;
19540
19713
  }
19541
19714
  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";
19715
+ if (fs46.existsSync(path45.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
19716
+ if (fs46.existsSync(path45.join(cwd, "yarn.lock"))) return "yarn";
19717
+ if (fs46.existsSync(path45.join(cwd, "bun.lockb"))) return "bun";
19545
19718
  return "npm";
19546
19719
  }
19547
19720
  function shouldChainScheduledWatch(match) {
@@ -19634,8 +19807,8 @@ function postFailureTail(issueNumber, cwd, reason) {
19634
19807
  const logPath = lastRunLogPath(cwd);
19635
19808
  let tail = "";
19636
19809
  try {
19637
- if (fs45.existsSync(logPath)) {
19638
- const content = fs45.readFileSync(logPath, "utf-8");
19810
+ if (fs46.existsSync(logPath)) {
19811
+ const content = fs46.readFileSync(logPath, "utf-8");
19639
19812
  tail = content.slice(-3e3);
19640
19813
  }
19641
19814
  } catch {
@@ -19660,7 +19833,7 @@ async function runCi(argv) {
19660
19833
  return 0;
19661
19834
  }
19662
19835
  const args = parseCiArgs(argv);
19663
- const cwd = args.cwd ? path44.resolve(args.cwd) : process.cwd();
19836
+ const cwd = args.cwd ? path45.resolve(args.cwd) : process.cwd();
19664
19837
  let earlyConfig;
19665
19838
  let earlyConfigError;
19666
19839
  try {
@@ -19683,9 +19856,9 @@ async function runCi(argv) {
19683
19856
  forceRunCliArgs = { goal: envForceMessage };
19684
19857
  }
19685
19858
  }
19686
- if (!args.issueNumber && !autoFallback && !forceRunAction && eventName === "workflow_dispatch" && dispatchEventPath && fs45.existsSync(dispatchEventPath)) {
19859
+ if (!args.issueNumber && !autoFallback && !forceRunAction && eventName === "workflow_dispatch" && dispatchEventPath && fs46.existsSync(dispatchEventPath)) {
19687
19860
  try {
19688
- const evt = JSON.parse(fs45.readFileSync(dispatchEventPath, "utf-8"));
19861
+ const evt = JSON.parse(fs46.readFileSync(dispatchEventPath, "utf-8"));
19689
19862
  const issueInput = parseInt(String(evt?.inputs?.issue_number ?? ""), 10);
19690
19863
  const sessionInput = String(evt?.inputs?.sessionId ?? "");
19691
19864
  const dutyInput = String(evt?.inputs?.capability ?? evt?.inputs?.executable ?? "").trim();
@@ -20017,8 +20190,8 @@ init_repoWorkspace();
20017
20190
 
20018
20191
  // src/scripts/brainTurnLog.ts
20019
20192
  init_runtimePaths();
20020
- import * as fs46 from "fs";
20021
- import * as path45 from "path";
20193
+ import * as fs47 from "fs";
20194
+ import * as path46 from "path";
20022
20195
  import posixPath4 from "path/posix";
20023
20196
  var live = /* @__PURE__ */ new Map();
20024
20197
  function brainEventsFilePath(dir, chatId) {
@@ -20029,8 +20202,8 @@ function brainEventsStatePath(chatId) {
20029
20202
  }
20030
20203
  function lastPersistedSeq(dir, chatId) {
20031
20204
  const p = brainEventsFilePath(dir, chatId);
20032
- if (!fs46.existsSync(p)) return 0;
20033
- const lines = fs46.readFileSync(p, "utf-8").split("\n").filter(Boolean);
20205
+ if (!fs47.existsSync(p)) return 0;
20206
+ const lines = fs47.readFileSync(p, "utf-8").split("\n").filter(Boolean);
20034
20207
  if (lines.length === 0) return 0;
20035
20208
  try {
20036
20209
  return JSON.parse(lines[lines.length - 1]).seq || 0;
@@ -20040,9 +20213,9 @@ function lastPersistedSeq(dir, chatId) {
20040
20213
  }
20041
20214
  function readSince(dir, chatId, since) {
20042
20215
  const p = brainEventsFilePath(dir, chatId);
20043
- if (!fs46.existsSync(p)) return [];
20216
+ if (!fs47.existsSync(p)) return [];
20044
20217
  const out = [];
20045
- for (const line of fs46.readFileSync(p, "utf-8").split("\n")) {
20218
+ for (const line of fs47.readFileSync(p, "utf-8").split("\n")) {
20046
20219
  if (!line) continue;
20047
20220
  try {
20048
20221
  const rec = JSON.parse(line);
@@ -20068,12 +20241,12 @@ function beginTurn(dir, chatId) {
20068
20241
  };
20069
20242
  live.set(chatId, state);
20070
20243
  const p = brainEventsFilePath(dir, chatId);
20071
- fs46.mkdirSync(path45.dirname(p), { recursive: true });
20244
+ fs47.mkdirSync(path46.dirname(p), { recursive: true });
20072
20245
  return (event) => {
20073
20246
  state.seq += 1;
20074
20247
  const rec = { seq: state.seq, turn, ts: Date.now(), event };
20075
20248
  try {
20076
- fs46.appendFileSync(p, `${JSON.stringify(rec)}
20249
+ fs47.appendFileSync(p, `${JSON.stringify(rec)}
20077
20250
  `);
20078
20251
  } catch (err) {
20079
20252
  process.stderr.write(
@@ -20112,7 +20285,7 @@ function endTurnIfUnterminated(dir, chatId, errMessage) {
20112
20285
  event: { type: "error", error: errMessage || "turn ended unexpectedly", chatId }
20113
20286
  };
20114
20287
  try {
20115
- fs46.appendFileSync(brainEventsFilePath(dir, chatId), `${JSON.stringify(rec)}
20288
+ fs47.appendFileSync(brainEventsFilePath(dir, chatId), `${JSON.stringify(rec)}
20116
20289
  `);
20117
20290
  } catch {
20118
20291
  }
@@ -20418,7 +20591,7 @@ async function handleChatTurn(req, res, chatId, opts) {
20418
20591
  );
20419
20592
  }
20420
20593
  }
20421
- fs47.mkdirSync(path46.dirname(sessionFile), { recursive: true });
20594
+ fs48.mkdirSync(path47.dirname(sessionFile), { recursive: true });
20422
20595
  appendTurn(sessionFile, {
20423
20596
  role: "user",
20424
20597
  content: message,
@@ -20483,7 +20656,7 @@ async function handleChatTurn(req, res, chatId, opts) {
20483
20656
  function buildServer(opts) {
20484
20657
  const runTurn = opts.runTurn ?? runChatTurn;
20485
20658
  const cloneRepo = opts.cloneRepo ?? defaultCloneRepo;
20486
- const reposRoot = opts.reposRoot ?? path46.join(path46.dirname(path46.resolve(opts.cwd)), "repos");
20659
+ const reposRoot = opts.reposRoot ?? path47.join(path47.dirname(path47.resolve(opts.cwd)), "repos");
20487
20660
  return createServer(async (req, res) => {
20488
20661
  if (!req.method || !req.url) {
20489
20662
  sendJson(res, 400, { error: "bad request" });
@@ -21078,8 +21251,8 @@ async function loadConfigSafe() {
21078
21251
  }
21079
21252
 
21080
21253
  // src/chat-cli.ts
21081
- import * as fs49 from "fs";
21082
- import * as path48 from "path";
21254
+ import * as fs50 from "fs";
21255
+ import * as path49 from "path";
21083
21256
 
21084
21257
  // src/chat/inbox.ts
21085
21258
  import { execFileSync as execFileSync26 } from "child_process";
@@ -21151,8 +21324,8 @@ function currentBranch(cwd) {
21151
21324
 
21152
21325
  // src/chat/state-sync.ts
21153
21326
  init_stateRepo();
21154
- import * as fs48 from "fs";
21155
- import * as path47 from "path";
21327
+ import * as fs49 from "fs";
21328
+ import * as path48 from "path";
21156
21329
  function jsonlLines2(text) {
21157
21330
  return text.split("\n").filter((line) => line.length > 0);
21158
21331
  }
@@ -21169,15 +21342,15 @@ function mergeJsonl2(localText, remoteText) {
21169
21342
  function syncJsonlFileFromState(opts) {
21170
21343
  const remote = readStateText(opts.config, opts.cwd, opts.statePath);
21171
21344
  if (!remote) return;
21172
- const local = fs48.existsSync(opts.localPath) ? fs48.readFileSync(opts.localPath, "utf-8") : "";
21345
+ const local = fs49.existsSync(opts.localPath) ? fs49.readFileSync(opts.localPath, "utf-8") : "";
21173
21346
  const next = mergeJsonl2(local, remote.content);
21174
21347
  if (next === local) return;
21175
- fs48.mkdirSync(path47.dirname(opts.localPath), { recursive: true });
21176
- fs48.writeFileSync(opts.localPath, next);
21348
+ fs49.mkdirSync(path48.dirname(opts.localPath), { recursive: true });
21349
+ fs49.writeFileSync(opts.localPath, next);
21177
21350
  }
21178
21351
  function persistJsonlFileToState(opts) {
21179
- if (!fs48.existsSync(opts.localPath)) return;
21180
- const localText = fs48.readFileSync(opts.localPath, "utf-8");
21352
+ if (!fs49.existsSync(opts.localPath)) return;
21353
+ const localText = fs49.readFileSync(opts.localPath, "utf-8");
21181
21354
  for (let attempt = 1; attempt <= 3; attempt += 1) {
21182
21355
  const remote = readStateText(opts.config, opts.cwd, opts.statePath);
21183
21356
  const body = mergeJsonl2(localText, remote?.content ?? "");
@@ -21437,7 +21610,7 @@ async function runChat(argv) {
21437
21610
  ${CHAT_HELP}`);
21438
21611
  return 64;
21439
21612
  }
21440
- const cwd = args.cwd ? path48.resolve(args.cwd) : process.cwd();
21613
+ const cwd = args.cwd ? path49.resolve(args.cwd) : process.cwd();
21441
21614
  const sessionId = args.sessionId;
21442
21615
  const unpackedSecrets = unpackAllSecrets();
21443
21616
  if (unpackedSecrets > 0) {
@@ -21498,7 +21671,7 @@ ${CHAT_HELP}`);
21498
21671
  const sink = buildSink(cwd, sessionId, args.dashboardUrl);
21499
21672
  const meta = readMeta(sessionFile);
21500
21673
  process.stdout.write(
21501
- `\u2192 kody:chat: session file=${sessionFile} exists=${fs49.existsSync(sessionFile)} meta=${meta ? meta.mode : "none"}
21674
+ `\u2192 kody:chat: session file=${sessionFile} exists=${fs50.existsSync(sessionFile)} meta=${meta ? meta.mode : "none"}
21502
21675
  `
21503
21676
  );
21504
21677
  try {
@@ -21658,8 +21831,8 @@ var FlyClient = class {
21658
21831
  get fetch() {
21659
21832
  return this.opts.fetchImpl ?? fetch;
21660
21833
  }
21661
- async call(path49, init = {}) {
21662
- const res = await this.fetch(`${FLY_API_BASE}${path49}`, {
21834
+ async call(path50, init = {}) {
21835
+ const res = await this.fetch(`${FLY_API_BASE}${path50}`, {
21663
21836
  method: init.method ?? "GET",
21664
21837
  headers: {
21665
21838
  Authorization: `Bearer ${this.opts.token}`,
@@ -21670,7 +21843,7 @@ var FlyClient = class {
21670
21843
  if (res.status === 404 && init.allow404) return null;
21671
21844
  if (!res.ok) {
21672
21845
  const text = await res.text().catch(() => "");
21673
- throw new Error(`Fly API ${res.status} on ${path49}: ${text.slice(0, 200) || res.statusText}`);
21846
+ throw new Error(`Fly API ${res.status} on ${path50}: ${text.slice(0, 200) || res.statusText}`);
21674
21847
  }
21675
21848
  if (res.status === 204) return null;
21676
21849
  const raw = await res.text();
@@ -22385,7 +22558,7 @@ async function poolServe() {
22385
22558
 
22386
22559
  // src/servers/runner-serve.ts
22387
22560
  import { spawn as spawn8 } from "child_process";
22388
- import * as fs50 from "fs";
22561
+ import * as fs51 from "fs";
22389
22562
  import { createServer as createServer5 } from "http";
22390
22563
  var DEFAULT_PORT2 = 8080;
22391
22564
  var DEFAULT_WORKDIR = "/workspace/repo";
@@ -22468,8 +22641,8 @@ async function defaultRunJob(job) {
22468
22641
  const workdir = process.env.RUNNER_WORKDIR ?? DEFAULT_WORKDIR;
22469
22642
  const branch = job.ref ?? "main";
22470
22643
  const authUrl = `https://x-access-token:${job.githubToken}@github.com/${job.repo}.git`;
22471
- fs50.rmSync(workdir, { recursive: true, force: true });
22472
- fs50.mkdirSync(workdir, { recursive: true });
22644
+ fs51.rmSync(workdir, { recursive: true, force: true });
22645
+ fs51.mkdirSync(workdir, { recursive: true });
22473
22646
  const allSecrets = typeof job.allSecrets === "string" ? job.allSecrets : JSON.stringify(job.allSecrets ?? {});
22474
22647
  const interactive = job.mode === "interactive";
22475
22648
  const scheduled = job.mode === "scheduled";