@kody-ade/kody-engine 0.4.255 → 0.4.256

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 +602 -152
  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.255",
18
+ version: "0.4.256",
19
19
  description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative agentAction profiles.",
20
20
  license: "MIT",
21
21
  type: "module",
@@ -3162,12 +3162,18 @@ function parseAgentResponsibilityResult(raw) {
3162
3162
  if (!facts) return null;
3163
3163
  const artifacts = parseArtifacts(obj.artifacts);
3164
3164
  if (!artifacts) return null;
3165
+ const missingEvidence = parseOptionalStringArray(obj.missingEvidence);
3166
+ if (!missingEvidence) return null;
3167
+ const blockers = parseOptionalStringArray(obj.blockers);
3168
+ if (!blockers) return null;
3165
3169
  return {
3166
3170
  version: 1,
3167
3171
  status: obj.status,
3168
3172
  summary,
3169
3173
  facts,
3170
- artifacts
3174
+ artifacts,
3175
+ missingEvidence,
3176
+ blockers
3171
3177
  };
3172
3178
  }
3173
3179
  function applyAgentResponsibilityResultToObjectiveState(state, result, evidenceOverride) {
@@ -3186,8 +3192,9 @@ function applyAgentResponsibilityResultToObjectiveState(state, result, evidenceO
3186
3192
  }
3187
3193
  }
3188
3194
  const blockers = parseStringArray(state.extra.blockers) ?? [];
3189
- if ((result.status === "fail" || result.status === "blocked") && !blockers.includes(result.summary)) {
3190
- blockers.push(result.summary);
3195
+ const resultBlockers = result.blockers.length > 0 || result.status !== "fail" && result.status !== "blocked" ? result.blockers : [result.summary];
3196
+ for (const blocker of resultBlockers) {
3197
+ if (!blockers.includes(blocker)) blockers.push(blocker);
3191
3198
  }
3192
3199
  return {
3193
3200
  ...state,
@@ -3199,7 +3206,9 @@ function applyAgentResponsibilityResultToObjectiveState(state, result, evidenceO
3199
3206
  status: result.status,
3200
3207
  summary: result.summary,
3201
3208
  facts: result.facts,
3202
- artifacts: result.artifacts
3209
+ artifacts: result.artifacts,
3210
+ missingEvidence: result.missingEvidence,
3211
+ blockers: result.blockers
3203
3212
  }
3204
3213
  }
3205
3214
  };
@@ -3227,6 +3236,10 @@ function parseStringArray(raw) {
3227
3236
  }
3228
3237
  return out;
3229
3238
  }
3239
+ function parseOptionalStringArray(raw) {
3240
+ if (raw === void 0) return [];
3241
+ return parseStringArray(raw);
3242
+ }
3230
3243
  function parseArtifacts(raw) {
3231
3244
  if (raw === void 0) return [];
3232
3245
  if (!Array.isArray(raw)) return null;
@@ -6180,6 +6193,7 @@ var init_state2 = __esm({
6180
6193
  });
6181
6194
 
6182
6195
  // src/goal/runLog.ts
6196
+ import * as fs25 from "fs";
6183
6197
  function stageGoalRunLogEvent(data, goalId, event, at = nowIso()) {
6184
6198
  const logs = goalRunLogs(data);
6185
6199
  const existing = logs[goalId];
@@ -6201,7 +6215,7 @@ function flushGoalRunLogEvents(config, cwd, data) {
6201
6215
  const logs = goalRunLogs(data);
6202
6216
  for (const [goalId, log2] of Object.entries(logs)) {
6203
6217
  if (log2.events.length === 0) continue;
6204
- const lines = `${log2.events.map((event) => JSON.stringify(event)).join("\n")}
6218
+ const lines = `${log2.events.map((event) => JSON.stringify(enrichGoalRunLogEvent(config, data, log2.path, event))).join("\n")}
6205
6219
  `;
6206
6220
  appendStateLine(config, cwd, log2.path, lines, `chore(goal-logs): append ${goalId}`);
6207
6221
  log2.events = [];
@@ -6212,6 +6226,55 @@ function goalRunLogPath(goalId, data) {
6212
6226
  const runId = goalRunId(data);
6213
6227
  return `logs/goals/${safePathSegment(goalId)}/runs/${startedAt}-${runId}.jsonl`;
6214
6228
  }
6229
+ function goalStateLogPath(goalId) {
6230
+ return `goals/instances/${safePathSegment(goalId)}/state.json`;
6231
+ }
6232
+ function goalRunLogSnapshot(goalId, goalState, goal) {
6233
+ const requiredEvidence = [...goal.destination.evidence];
6234
+ const pendingEvidence = typeof goal.facts.pendingEvidence === "string" ? goal.facts.pendingEvidence : void 0;
6235
+ return {
6236
+ id: goalId,
6237
+ type: goal.type,
6238
+ state: goalState,
6239
+ stage: goal.stage,
6240
+ outcome: goal.destination.outcome,
6241
+ requiredEvidence,
6242
+ satisfiedEvidence: requiredEvidence.filter((evidence) => goal.facts[evidence] === true),
6243
+ failedEvidence: requiredEvidence.filter((evidence) => goal.facts[evidence] === false),
6244
+ missingEvidence: requiredEvidence.filter((evidence) => goal.facts[evidence] !== true),
6245
+ pendingEvidence,
6246
+ agentResponsibilities: [...goal.agentResponsibilities],
6247
+ route: goal.route.map(routeStepForLog),
6248
+ schedule: goal.schedule,
6249
+ preferredRunTime: goal.preferredRunTime,
6250
+ loopTarget: goal.loopTarget,
6251
+ blockers: [...goal.blockers],
6252
+ facts: { ...goal.facts }
6253
+ };
6254
+ }
6255
+ function goalRunLogChange(before, after) {
6256
+ if (!before || !after) return void 0;
6257
+ const change = {};
6258
+ addScalarChange(change, "state", before.state, after.state);
6259
+ addScalarChange(change, "stage", before.stage, after.stage);
6260
+ addScalarChange(change, "pendingEvidence", before.pendingEvidence, after.pendingEvidence);
6261
+ const beforeFacts = recordValue2(before.facts);
6262
+ const afterFacts = recordValue2(after.facts);
6263
+ if (beforeFacts || afterFacts) change.facts = diffRecordKeys(beforeFacts ?? {}, afterFacts ?? {});
6264
+ const beforeBlockers = stringArrayValue(before.blockers);
6265
+ const afterBlockers = stringArrayValue(after.blockers);
6266
+ if (beforeBlockers || afterBlockers) {
6267
+ const blockers = diffStringArrays(beforeBlockers ?? [], afterBlockers ?? []);
6268
+ if (blockers.added.length > 0 || blockers.removed.length > 0) change.blockers = blockers;
6269
+ }
6270
+ const beforeSatisfied = stringArrayValue(before.satisfiedEvidence);
6271
+ const afterSatisfied = stringArrayValue(after.satisfiedEvidence);
6272
+ if (beforeSatisfied || afterSatisfied) {
6273
+ const evidence = diffStringArrays(beforeSatisfied ?? [], afterSatisfied ?? []);
6274
+ if (evidence.added.length > 0 || evidence.removed.length > 0) change.satisfiedEvidence = evidence;
6275
+ }
6276
+ return Object.keys(change).length > 0 ? change : void 0;
6277
+ }
6215
6278
  function goalRunLogs(data) {
6216
6279
  const existing = data[LOGS_KEY];
6217
6280
  if (existing && typeof existing === "object" && !Array.isArray(existing)) {
@@ -6242,6 +6305,176 @@ function githubRunId() {
6242
6305
  const attempt = process.env.GITHUB_RUN_ATTEMPT?.trim();
6243
6306
  return attempt ? `gh-${runId}-${attempt}` : `gh-${runId}`;
6244
6307
  }
6308
+ function enrichGoalRunLogEvent(config, data, logPath, event) {
6309
+ const stateRepo = stateRepoContext(config, event.goalId, logPath);
6310
+ return pruneUndefined({
6311
+ ...event,
6312
+ run: event.run ?? runContext(data),
6313
+ repo: event.repo ?? repoContext(config),
6314
+ stateRepo: event.stateRepo ?? stateRepo,
6315
+ trigger: event.trigger ?? triggerContext(),
6316
+ job: event.job ?? jobContext(data),
6317
+ links: event.links ?? linkContext(stateRepo)
6318
+ });
6319
+ }
6320
+ function runContext(data) {
6321
+ const runId = process.env.GITHUB_RUN_ID?.trim();
6322
+ const attempt = process.env.GITHUB_RUN_ATTEMPT?.trim();
6323
+ const repository = process.env.GITHUB_REPOSITORY?.trim();
6324
+ const server = process.env.GITHUB_SERVER_URL?.trim() || "https://github.com";
6325
+ return pruneUndefined({
6326
+ id: goalRunId(data),
6327
+ provider: runId ? "github-actions" : "local",
6328
+ githubRunId: runId || void 0,
6329
+ githubRunAttempt: attempt || void 0,
6330
+ workflow: process.env.GITHUB_WORKFLOW?.trim() || void 0,
6331
+ job: process.env.GITHUB_JOB?.trim() || void 0,
6332
+ url: runId && repository ? `${server}/${repository}/actions/runs/${runId}` : void 0,
6333
+ startedAt: data[LOG_STARTED_KEY]
6334
+ });
6335
+ }
6336
+ function repoContext(config) {
6337
+ const owner = config.github?.owner;
6338
+ const repo = config.github?.repo;
6339
+ return pruneUndefined({
6340
+ owner,
6341
+ repo,
6342
+ fullName: owner && repo ? `${owner}/${repo}` : process.env.GITHUB_REPOSITORY?.trim() || void 0,
6343
+ ref: process.env.GITHUB_REF?.trim() || void 0,
6344
+ sha: process.env.GITHUB_SHA?.trim() || void 0
6345
+ });
6346
+ }
6347
+ function stateRepoContext(config, goalId, logPath) {
6348
+ try {
6349
+ const state = resolveStateRepoConfig(config);
6350
+ return {
6351
+ repo: state.repo,
6352
+ path: state.path,
6353
+ goalStatePath: `${state.path}/${goalStateLogPath(goalId)}`,
6354
+ logPath: `${state.path}/${logPath}`
6355
+ };
6356
+ } catch {
6357
+ return void 0;
6358
+ }
6359
+ }
6360
+ function triggerContext() {
6361
+ const event = readGithubEvent();
6362
+ const inputs = recordValue2(event?.inputs);
6363
+ return pruneUndefined({
6364
+ eventName: process.env.GITHUB_EVENT_NAME?.trim() || void 0,
6365
+ actor: process.env.GITHUB_ACTOR?.trim() || void 0,
6366
+ eventPath: process.env.GITHUB_EVENT_PATH?.trim() || void 0,
6367
+ issue: numberValue(recordValue2(event?.issue)?.number),
6368
+ pullRequest: numberValue(recordValue2(event?.pull_request)?.number),
6369
+ comment: numberValue(recordValue2(event?.comment)?.id),
6370
+ schedule: stringValue(event?.schedule),
6371
+ inputs: inputs ? pickRecord(inputs, ["issue_number", "sessionId", "message", "model", "title", "agentAction", "base"]) : void 0
6372
+ });
6373
+ }
6374
+ function jobContext(data) {
6375
+ const job = pruneUndefined({
6376
+ id: stringValue(data.jobId),
6377
+ key: stringValue(data.jobKey),
6378
+ flavor: stringValue(data.jobFlavor),
6379
+ action: stringValue(data.jobAction),
6380
+ agentResponsibility: stringValue(data.jobAgentResponsibility),
6381
+ agentAction: stringValue(data.jobAgentAction),
6382
+ agent: stringValue(data.jobAgent),
6383
+ schedule: stringValue(data.jobSchedule),
6384
+ target: data.jobTarget,
6385
+ why: truncateString(stringValue(data.jobWhy), 1e3),
6386
+ saveReport: data.jobSaveReport === true ? true : void 0
6387
+ });
6388
+ return Object.keys(job).length > 0 ? job : void 0;
6389
+ }
6390
+ function linkContext(stateRepo) {
6391
+ const links = {};
6392
+ const runId = process.env.GITHUB_RUN_ID?.trim();
6393
+ const repository = process.env.GITHUB_REPOSITORY?.trim();
6394
+ const server = process.env.GITHUB_SERVER_URL?.trim() || "https://github.com";
6395
+ if (runId && repository) links.workflowRun = `${server}/${repository}/actions/runs/${runId}`;
6396
+ const repo = stringValue(stateRepo?.repo);
6397
+ const goalStatePath = stringValue(stateRepo?.goalStatePath);
6398
+ const logPath = stringValue(stateRepo?.logPath);
6399
+ if (repo && goalStatePath) links.goalState = githubBlobUrl(repo, goalStatePath);
6400
+ if (repo && logPath) links.log = githubBlobUrl(repo, logPath);
6401
+ return Object.keys(links).length > 0 ? links : void 0;
6402
+ }
6403
+ function githubBlobUrl(repo, filePath) {
6404
+ try {
6405
+ const parsed = parseStateRepoSlug(repo);
6406
+ return `https://github.com/${parsed.owner}/${parsed.repo}/blob/main/${filePath}`;
6407
+ } catch {
6408
+ return void 0;
6409
+ }
6410
+ }
6411
+ function routeStepForLog(step) {
6412
+ return pruneUndefined({
6413
+ evidence: step.evidence,
6414
+ stage: step.stage,
6415
+ agentResponsibility: step.agentResponsibility,
6416
+ agentAction: step.agentAction,
6417
+ args: step.args,
6418
+ saveReport: step.saveReport === true ? true : void 0
6419
+ });
6420
+ }
6421
+ function readGithubEvent() {
6422
+ const eventPath = process.env.GITHUB_EVENT_PATH;
6423
+ if (!eventPath) return null;
6424
+ try {
6425
+ if (!fs25.existsSync(eventPath)) return null;
6426
+ const parsed = JSON.parse(fs25.readFileSync(eventPath, "utf-8"));
6427
+ return recordValue2(parsed);
6428
+ } catch {
6429
+ return null;
6430
+ }
6431
+ }
6432
+ function addScalarChange(change, field, before, after) {
6433
+ if (before === after) return;
6434
+ change[field] = pruneUndefined({ from: before, to: after });
6435
+ }
6436
+ function diffRecordKeys(before, after) {
6437
+ const beforeKeys = new Set(Object.keys(before));
6438
+ const afterKeys = new Set(Object.keys(after));
6439
+ const added = [...afterKeys].filter((key) => !beforeKeys.has(key)).sort();
6440
+ const removed = [...beforeKeys].filter((key) => !afterKeys.has(key)).sort();
6441
+ const changed = [...afterKeys].filter((key) => beforeKeys.has(key) && JSON.stringify(before[key]) !== JSON.stringify(after[key])).sort();
6442
+ return { added, removed, changed };
6443
+ }
6444
+ function diffStringArrays(before, after) {
6445
+ const beforeSet = new Set(before);
6446
+ const afterSet = new Set(after);
6447
+ return {
6448
+ added: after.filter((item) => !beforeSet.has(item)).sort(),
6449
+ removed: before.filter((item) => !afterSet.has(item)).sort()
6450
+ };
6451
+ }
6452
+ function recordValue2(value) {
6453
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
6454
+ }
6455
+ function stringArrayValue(value) {
6456
+ return Array.isArray(value) && value.every((item) => typeof item === "string") ? [...value] : null;
6457
+ }
6458
+ function numberValue(value) {
6459
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
6460
+ }
6461
+ function pickRecord(input, keys) {
6462
+ const out = {};
6463
+ for (const key of keys) {
6464
+ if (input[key] !== void 0 && input[key] !== "") out[key] = input[key];
6465
+ }
6466
+ return out;
6467
+ }
6468
+ function pruneUndefined(input) {
6469
+ for (const key of Object.keys(input)) {
6470
+ if (input[key] === void 0) delete input[key];
6471
+ }
6472
+ return input;
6473
+ }
6474
+ function truncateString(value, max) {
6475
+ if (!value) return void 0;
6476
+ return value.length > max ? `${value.slice(0, max)}...` : value;
6477
+ }
6245
6478
  function stringValue(value) {
6246
6479
  return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
6247
6480
  }
@@ -6587,7 +6820,7 @@ var init_contentsApiBackend = __esm({
6587
6820
  });
6588
6821
 
6589
6822
  // src/scripts/jobState/localFileBackend.ts
6590
- import * as fs25 from "fs";
6823
+ import * as fs26 from "fs";
6591
6824
  import * as path24 from "path";
6592
6825
  function sanitizeKey(s) {
6593
6826
  return s.replace(/[^A-Za-z0-9._-]/g, "-");
@@ -6659,7 +6892,7 @@ var init_localFileBackend = __esm({
6659
6892
  `);
6660
6893
  return;
6661
6894
  }
6662
- fs25.mkdirSync(this.absDir, { recursive: true });
6895
+ fs26.mkdirSync(this.absDir, { recursive: true });
6663
6896
  const prefix = this.cacheKeyPrefix();
6664
6897
  const probeKey = `${prefix}probe-${Date.now()}`;
6665
6898
  try {
@@ -6688,7 +6921,7 @@ var init_localFileBackend = __esm({
6688
6921
  `);
6689
6922
  return;
6690
6923
  }
6691
- if (!fs25.existsSync(this.absDir)) {
6924
+ if (!fs26.existsSync(this.absDir)) {
6692
6925
  return;
6693
6926
  }
6694
6927
  const key = `${this.cacheKeyPrefix()}${process.env.GITHUB_RUN_ID ?? "norunid"}-${Date.now()}`;
@@ -6705,10 +6938,10 @@ var init_localFileBackend = __esm({
6705
6938
  load(slug2) {
6706
6939
  const relPath = stateFilePath(this.jobsDir, slug2);
6707
6940
  const absPath = path24.join(this.cwd, relPath);
6708
- if (!fs25.existsSync(absPath)) {
6941
+ if (!fs26.existsSync(absPath)) {
6709
6942
  return { path: relPath, handle: null, state: initialStateEnvelope("seed"), created: true };
6710
6943
  }
6711
- const raw = fs25.readFileSync(absPath, "utf-8");
6944
+ const raw = fs26.readFileSync(absPath, "utf-8");
6712
6945
  let parsed;
6713
6946
  try {
6714
6947
  parsed = JSON.parse(raw);
@@ -6726,12 +6959,12 @@ var init_localFileBackend = __esm({
6726
6959
  return false;
6727
6960
  }
6728
6961
  const absPath = path24.join(this.cwd, loaded.path);
6729
- fs25.mkdirSync(path24.dirname(absPath), { recursive: true });
6962
+ fs26.mkdirSync(path24.dirname(absPath), { recursive: true });
6730
6963
  const body = `${JSON.stringify(next, null, 2)}
6731
6964
  `;
6732
6965
  const tmpPath = `${absPath}.${process.pid}.tmp`;
6733
- fs25.writeFileSync(tmpPath, body, "utf-8");
6734
- fs25.renameSync(tmpPath, absPath);
6966
+ fs26.writeFileSync(tmpPath, body, "utf-8");
6967
+ fs26.renameSync(tmpPath, absPath);
6735
6968
  return true;
6736
6969
  }
6737
6970
  cacheKeyPrefix() {
@@ -7000,7 +7233,7 @@ var init_goalAgentResponsibilityScheduling = __esm({
7000
7233
  });
7001
7234
 
7002
7235
  // src/scripts/advanceManagedGoal.ts
7003
- function stageManagedGoalDecision(data, goalId, goal, goalState, decision) {
7236
+ function stageManagedGoalDecision(data, goalId, goal, goalState, decision, details) {
7004
7237
  if (decision.kind === "dispatch") {
7005
7238
  stageGoalRunLogEvent(data, goalId, {
7006
7239
  source: "goal-manager",
@@ -7014,7 +7247,18 @@ function stageManagedGoalDecision(data, goalId, goal, goalState, decision) {
7014
7247
  agentResponsibility: decision.agentResponsibility,
7015
7248
  agentAction: decision.agentAction,
7016
7249
  cliArgs: decision.cliArgs
7017
- }
7250
+ },
7251
+ goal: details.goalSnapshot,
7252
+ inspection: details.inspection,
7253
+ decision: {
7254
+ kind: decision.kind,
7255
+ evidence: decision.evidence,
7256
+ stage: decision.stage,
7257
+ agentResponsibility: decision.agentResponsibility,
7258
+ agentAction: decision.agentAction,
7259
+ cliArgs: decision.cliArgs
7260
+ },
7261
+ change: details.change
7018
7262
  });
7019
7263
  return;
7020
7264
  }
@@ -7026,7 +7270,11 @@ function stageManagedGoalDecision(data, goalId, goal, goalState, decision) {
7026
7270
  goalState: "done",
7027
7271
  stage: "done",
7028
7272
  status: decision.kind,
7029
- reason: "managed goal complete"
7273
+ reason: "managed goal complete",
7274
+ goal: details.goalSnapshot,
7275
+ inspection: details.inspection,
7276
+ decision: { kind: decision.kind, reason: "managed goal complete" },
7277
+ change: details.change
7030
7278
  });
7031
7279
  return;
7032
7280
  }
@@ -7038,7 +7286,11 @@ function stageManagedGoalDecision(data, goalId, goal, goalState, decision) {
7038
7286
  goalState,
7039
7287
  stage: goal.stage,
7040
7288
  status: decision.kind,
7041
- reason: decision.reason
7289
+ reason: decision.reason,
7290
+ goal: details.goalSnapshot,
7291
+ inspection: details.inspection,
7292
+ decision: { kind: decision.kind, reason: decision.reason },
7293
+ change: details.change
7042
7294
  });
7043
7295
  return;
7044
7296
  }
@@ -7050,7 +7302,16 @@ function stageManagedGoalDecision(data, goalId, goal, goalState, decision) {
7050
7302
  stage: decision.stage,
7051
7303
  evidence: decision.evidence,
7052
7304
  status: decision.kind,
7053
- reason: decision.reason
7305
+ reason: decision.reason,
7306
+ goal: details.goalSnapshot,
7307
+ inspection: details.inspection,
7308
+ decision: {
7309
+ kind: decision.kind,
7310
+ evidence: decision.evidence,
7311
+ stage: decision.stage,
7312
+ reason: decision.reason
7313
+ },
7314
+ change: details.change
7054
7315
  });
7055
7316
  }
7056
7317
  function readSimpleGoalTaskSummary(goalId, cwd) {
@@ -7139,16 +7400,25 @@ var init_advanceManagedGoal = __esm({
7139
7400
  ctx.output.reason = "goal has no managed-goal contract; nothing to advance";
7140
7401
  return;
7141
7402
  }
7403
+ const previousGoalIdFact = managed.facts.goalId;
7404
+ managed.facts.goalId = goal.id;
7405
+ const startSnapshot = goalRunLogSnapshot(goal.id, goal.state, managed);
7142
7406
  stageGoalRunLogEvent(ctx.data, goal.id, {
7143
7407
  source: "goal-manager",
7144
7408
  event: "goal.tick.start",
7145
7409
  goalType: managed.type,
7146
7410
  goalState: goal.state,
7147
7411
  stage: managed.stage,
7412
+ goal: startSnapshot,
7413
+ inspection: {
7414
+ requiredEvidence: startSnapshot.requiredEvidence,
7415
+ satisfiedEvidence: startSnapshot.satisfiedEvidence,
7416
+ missingEvidence: startSnapshot.missingEvidence,
7417
+ pendingEvidence: startSnapshot.pendingEvidence,
7418
+ blockers: startSnapshot.blockers
7419
+ },
7148
7420
  facts: managed.facts
7149
7421
  });
7150
- const previousGoalIdFact = managed.facts.goalId;
7151
- managed.facts.goalId = goal.id;
7152
7422
  const restoreGoalIdFact = () => {
7153
7423
  if (previousGoalIdFact === void 0) delete managed.facts.goalId;
7154
7424
  else managed.facts.goalId = previousGoalIdFact;
@@ -7161,6 +7431,7 @@ var init_advanceManagedGoal = __esm({
7161
7431
  if (!managed.blockers.includes(reason)) managed.blockers.push(reason);
7162
7432
  restoreGoalIdFact();
7163
7433
  goal.raw = writeManagedGoalToState({ ...goal.raw, state: goal.state }, managed);
7434
+ const blockedSnapshot = goalRunLogSnapshot(goal.id, goal.state, managed);
7164
7435
  stageGoalRunLogEvent(ctx.data, goal.id, {
7165
7436
  source: "goal-manager",
7166
7437
  event: "goal.tick.blocked",
@@ -7168,12 +7439,20 @@ var init_advanceManagedGoal = __esm({
7168
7439
  goalState: goal.state,
7169
7440
  stage: managed.stage,
7170
7441
  status: "blocked",
7171
- reason
7442
+ reason,
7443
+ goal: blockedSnapshot,
7444
+ inspection: {
7445
+ purpose: "prepare goal issue fact before dispatch",
7446
+ routeNeedsIssueFact: true
7447
+ },
7448
+ decision: { kind: "blocked", reason },
7449
+ change: goalRunLogChange(startSnapshot, blockedSnapshot)
7172
7450
  });
7173
7451
  ctx.output.reason = reason;
7174
7452
  return;
7175
7453
  }
7176
7454
  if (isGoalTargetLoop(managed)) {
7455
+ const beforeSnapshot = goalRunLogSnapshot(goal.id, goal.state, managed);
7177
7456
  const previousScheduleState = goal.raw.extra.scheduleState && typeof goal.raw.extra.scheduleState === "object" ? goal.raw.extra.scheduleState : void 0;
7178
7457
  const decision2 = planGoalTargetLoopSchedule({ goal: managed, previousScheduleState });
7179
7458
  restoreGoalIdFact();
@@ -7196,12 +7475,32 @@ var init_advanceManagedGoal = __esm({
7196
7475
  status: decision2.kind,
7197
7476
  reason: decision2.reason,
7198
7477
  target: decision2.dispatch?.cliArgs.goal && typeof decision2.dispatch.cliArgs.goal === "string" ? { type: "goal", id: decision2.dispatch.cliArgs.goal } : managed.loopTarget,
7199
- dispatch: decision2.dispatch
7478
+ dispatch: decision2.dispatch,
7479
+ goal: goalRunLogSnapshot(goal.id, goal.state, managed),
7480
+ inspection: {
7481
+ loopTarget: managed.loopTarget,
7482
+ preferredRunTime: managed.preferredRunTime,
7483
+ previousScheduleState,
7484
+ scheduleState: decision2.scheduleState
7485
+ },
7486
+ decision: {
7487
+ kind: decision2.kind,
7488
+ reason: decision2.reason,
7489
+ dispatch: decision2.dispatch
7490
+ },
7491
+ change: {
7492
+ ...goalRunLogChange(beforeSnapshot, goalRunLogSnapshot(goal.id, goal.state, managed)) ?? {},
7493
+ scheduleState: {
7494
+ previousDecision: previousScheduleState?.lastDecision,
7495
+ nextDecision: decision2.scheduleState.lastDecision
7496
+ }
7497
+ }
7200
7498
  });
7201
7499
  ctx.output.reason = decision2.reason;
7202
7500
  return;
7203
7501
  }
7204
7502
  if (isAgentResponsibilityCadenceGoal(managed, goal.raw.extra)) {
7503
+ const beforeSnapshot = goalRunLogSnapshot(goal.id, goal.state, managed);
7205
7504
  const previousScheduleState = goal.raw.extra.scheduleState && typeof goal.raw.extra.scheduleState === "object" ? goal.raw.extra.scheduleState : void 0;
7206
7505
  const decision2 = await planGoalAgentResponsibilitySchedule({
7207
7506
  goal: managed,
@@ -7229,22 +7528,55 @@ var init_advanceManagedGoal = __esm({
7229
7528
  stage: managed.stage,
7230
7529
  status: decision2.kind,
7231
7530
  reason: decision2.reason,
7232
- dispatch: decision2.dispatch
7531
+ dispatch: decision2.dispatch,
7532
+ goal: goalRunLogSnapshot(goal.id, goal.state, managed),
7533
+ inspection: {
7534
+ agentResponsibilities: decision2.scheduleState.agentResponsibilities,
7535
+ previousScheduleState,
7536
+ scheduleState: decision2.scheduleState
7537
+ },
7538
+ decision: {
7539
+ kind: decision2.kind,
7540
+ reason: decision2.reason,
7541
+ dispatch: decision2.dispatch
7542
+ },
7543
+ change: {
7544
+ ...goalRunLogChange(beforeSnapshot, goalRunLogSnapshot(goal.id, goal.state, managed)) ?? {},
7545
+ scheduleState: {
7546
+ previousDecision: previousScheduleState?.lastDecision,
7547
+ nextDecision: decision2.scheduleState.lastDecision
7548
+ }
7549
+ }
7233
7550
  });
7234
7551
  ctx.output.reason = decision2.reason;
7235
7552
  return;
7236
7553
  }
7554
+ let simpleTaskSummary;
7237
7555
  if (isSimpleGoal(managed)) {
7238
- applySimpleGoalTaskSummary(managed, readSimpleGoalTaskSummary(goal.id, ctx.cwd));
7556
+ simpleTaskSummary = readSimpleGoalTaskSummary(goal.id, ctx.cwd);
7557
+ applySimpleGoalTaskSummary(managed, simpleTaskSummary);
7239
7558
  }
7559
+ const beforeDecisionSnapshot = goalRunLogSnapshot(goal.id, goal.state, managed);
7240
7560
  const decision = planManagedGoalTick(managed);
7241
7561
  restoreGoalIdFact();
7242
7562
  ctx.data.managedGoalDecision = decision;
7243
- stageManagedGoalDecision(ctx.data, goal.id, managed, goal.state, decision);
7244
7563
  if (decision.kind === "done") {
7245
7564
  goal.state = "done";
7246
7565
  }
7247
7566
  goal.raw = writeManagedGoalToState({ ...goal.raw, state: goal.state }, managed);
7567
+ const afterDecisionSnapshot = goalRunLogSnapshot(goal.id, goal.state, managed);
7568
+ stageManagedGoalDecision(ctx.data, goal.id, managed, goal.state, decision, {
7569
+ goalSnapshot: afterDecisionSnapshot,
7570
+ inspection: {
7571
+ requiredEvidence: beforeDecisionSnapshot.requiredEvidence,
7572
+ satisfiedEvidence: beforeDecisionSnapshot.satisfiedEvidence,
7573
+ missingEvidence: beforeDecisionSnapshot.missingEvidence,
7574
+ pendingEvidence: beforeDecisionSnapshot.pendingEvidence,
7575
+ route: beforeDecisionSnapshot.route,
7576
+ simpleTaskSummary
7577
+ },
7578
+ change: goalRunLogChange(beforeDecisionSnapshot, afterDecisionSnapshot)
7579
+ });
7248
7580
  if (decision.kind === "blocked" || decision.kind === "wait" || decision.kind === "idle" || decision.kind === "done") {
7249
7581
  ctx.output.reason = decision.kind === "done" ? "managed goal complete" : decision.reason;
7250
7582
  return;
@@ -7842,6 +8174,76 @@ function completeSatisfiedManagedGoal(state) {
7842
8174
  if (decision.kind !== "done") return state;
7843
8175
  return writeManagedGoalToState({ ...state, state: "done" }, managed);
7844
8176
  }
8177
+ function snapshotFromState(goalId, state) {
8178
+ const managed = managedGoalFromState(state);
8179
+ return managed ? goalRunLogSnapshot(goalId, state.state, managed) : null;
8180
+ }
8181
+ function responsibilityReportOutput(report, goalAfter) {
8182
+ const evidence = report.evidence ?? {};
8183
+ const values = Object.values(evidence);
8184
+ const status = values.some((value) => value === false) ? "fail" : values.length > 0 || report.facts ? "changed" : "noop";
8185
+ return {
8186
+ kind: "report",
8187
+ status,
8188
+ summary: "responsibility reported goal evidence",
8189
+ evidence,
8190
+ facts: report.facts ?? {},
8191
+ artifacts: [],
8192
+ missingEvidence: stringArrayField(goalAfter, "missingEvidence"),
8193
+ blockers: stringArrayField(goalAfter, "blockers")
8194
+ };
8195
+ }
8196
+ function responsibilityResultOutput(result) {
8197
+ return {
8198
+ kind: "result",
8199
+ status: result.status,
8200
+ summary: result.summary,
8201
+ facts: result.facts,
8202
+ artifacts: result.artifacts,
8203
+ missingEvidence: result.missingEvidence,
8204
+ blockers: result.blockers
8205
+ };
8206
+ }
8207
+ function evidenceInspection(goalBefore, goalAfter, responsibilityOutput, explicitEvidence) {
8208
+ return {
8209
+ expectedEvidence: {
8210
+ required: goalBefore?.requiredEvidence,
8211
+ missingBefore: goalBefore?.missingEvidence,
8212
+ pendingBefore: goalBefore?.pendingEvidence,
8213
+ explicit: explicitEvidence
8214
+ },
8215
+ responsibilityOutput,
8216
+ actualGoalState: {
8217
+ satisfiedEvidence: goalAfter?.satisfiedEvidence,
8218
+ missingEvidence: goalAfter?.missingEvidence,
8219
+ pendingEvidence: goalAfter?.pendingEvidence,
8220
+ blockers: goalAfter?.blockers
8221
+ }
8222
+ };
8223
+ }
8224
+ function evidenceDecision(change, goalAfter, responsibilityOutput) {
8225
+ return {
8226
+ kind: change ? "accept-evidence" : "no-state-change",
8227
+ status: responsibilityOutput.status,
8228
+ nextStep: nextStepFromEvidence(goalAfter, responsibilityOutput),
8229
+ reason: responsibilityOutput.summary
8230
+ };
8231
+ }
8232
+ function nextStepFromEvidence(goalAfter, responsibilityOutput) {
8233
+ const status = typeof responsibilityOutput.status === "string" ? responsibilityOutput.status : "";
8234
+ const outputBlockers = stringArrayField(responsibilityOutput, "blockers");
8235
+ const goalBlockers = stringArrayField(goalAfter, "blockers");
8236
+ const missingEvidence = stringArrayField(goalAfter, "missingEvidence");
8237
+ if (goalAfter && missingEvidence.length === 0) return "done";
8238
+ if (status === "fail" || status === "blocked" || outputBlockers.length > 0) return "rescue";
8239
+ if (goalBlockers.length > 0) return "block";
8240
+ if (missingEvidence.length > 0 && status !== "noop") return "dispatch";
8241
+ return "wait";
8242
+ }
8243
+ function stringArrayField(record2, key) {
8244
+ const value = record2?.[key];
8245
+ return Array.isArray(value) && value.every((item) => typeof item === "string") ? value : [];
8246
+ }
7845
8247
  function describeMessage(goalId, reports, results) {
7846
8248
  const pieces = [];
7847
8249
  if (reports && reports.length > 0) pieces.push(`report=${reports.length}`);
@@ -7869,45 +8271,93 @@ var init_applyAgentResponsibilityReports = __esm({
7869
8271
  for (const goalId of goalIds) {
7870
8272
  const prior = fetchGoalState(ctx.config, goalId, ctx.cwd);
7871
8273
  if (!prior) {
8274
+ stageGoalRunLogEvent(ctx.data, goalId, {
8275
+ source: "goal-loop",
8276
+ event: "goal.evidence.rejected",
8277
+ status: "rejected",
8278
+ reason: "goal missing in state repo",
8279
+ inspection: {
8280
+ responsibilityOutput: {
8281
+ reports: reportsByGoal.get(goalId)?.length ?? 0,
8282
+ results: goalId === resultGoalId ? results.length : 0
8283
+ },
8284
+ missingEvidence: [],
8285
+ blockers: ["goal missing in state repo"]
8286
+ },
8287
+ decision: { kind: "reject-evidence", nextStep: "block", reason: "goal missing in state repo" }
8288
+ });
8289
+ flushLogs(ctx);
7872
8290
  process.stderr.write(`[kody agentResponsibility-report] goal ${goalId} missing in state repo; report skipped
7873
8291
  `);
7874
8292
  continue;
7875
8293
  }
7876
8294
  let next = prior;
7877
8295
  for (const report of reportsByGoal.get(goalId) ?? []) {
8296
+ const beforeSnapshot = snapshotFromState(goalId, next);
8297
+ next = applyAgentResponsibilityReportToGoalState(next, report);
8298
+ const afterSnapshot = snapshotFromState(goalId, next);
8299
+ const change = goalRunLogChange(beforeSnapshot, afterSnapshot);
8300
+ const output = responsibilityReportOutput(report, afterSnapshot);
7878
8301
  stageGoalRunLogEvent(ctx.data, goalId, {
7879
- source: "goal-report",
7880
- event: "goal.evidence.reported",
7881
- goalState: prior.state,
8302
+ source: "goal-loop",
8303
+ event: change ? "goal.evidence.applied" : "goal.evidence.unchanged",
8304
+ goalState: next.state,
7882
8305
  evidenceValues: report.evidence,
7883
- facts: report.facts
8306
+ facts: report.facts,
8307
+ goal: afterSnapshot ?? void 0,
8308
+ inspection: evidenceInspection(beforeSnapshot, afterSnapshot, output),
8309
+ decision: {
8310
+ ...evidenceDecision(change, afterSnapshot, output),
8311
+ evidence: report.evidence
8312
+ },
8313
+ change
7884
8314
  });
7885
- next = applyAgentResponsibilityReportToGoalState(next, report);
7886
8315
  }
7887
8316
  if (goalId === resultGoalId) {
7888
8317
  const evidence = typeof ctx.args.evidence === "string" && ctx.args.evidence.length > 0 ? ctx.args.evidence : void 0;
7889
8318
  for (const result of results) {
8319
+ const beforeSnapshot = snapshotFromState(goalId, next);
8320
+ next = applyAgentResponsibilityResultToObjectiveState(next, result, evidence);
8321
+ const afterSnapshot = snapshotFromState(goalId, next);
8322
+ const change = goalRunLogChange(beforeSnapshot, afterSnapshot);
8323
+ const output = responsibilityResultOutput(result);
7890
8324
  stageGoalRunLogEvent(ctx.data, goalId, {
7891
- source: "goal-report",
7892
- event: "goal.result.applied",
7893
- goalState: prior.state,
8325
+ source: "goal-loop",
8326
+ event: change ? "goal.evidence.applied" : "goal.evidence.unchanged",
8327
+ goalState: next.state,
7894
8328
  evidence,
7895
8329
  status: result.status,
7896
8330
  reason: result.summary,
7897
8331
  facts: result.facts,
7898
- artifacts: result.artifacts
8332
+ artifacts: result.artifacts,
8333
+ goal: afterSnapshot ?? beforeSnapshot ?? void 0,
8334
+ inspection: evidenceInspection(beforeSnapshot, afterSnapshot, output, evidence),
8335
+ decision: {
8336
+ ...evidenceDecision(change, afterSnapshot, output),
8337
+ evidence
8338
+ },
8339
+ change
7899
8340
  });
7900
- next = applyAgentResponsibilityResultToObjectiveState(next, result, evidence);
7901
8341
  }
7902
8342
  }
8343
+ const beforeCompletionSnapshot = snapshotFromState(goalId, next);
7903
8344
  next = completeSatisfiedManagedGoal(next);
8345
+ const afterCompletionSnapshot = snapshotFromState(goalId, next);
7904
8346
  if (prior.state !== "done" && next.state === "done") {
7905
8347
  stageGoalRunLogEvent(ctx.data, goalId, {
7906
- source: "goal-report",
7907
- event: "goal.completed",
8348
+ source: "goal-loop",
8349
+ event: "goal.decision.done",
7908
8350
  goalState: "done",
7909
8351
  status: "done",
7910
- reason: "destination evidence satisfied"
8352
+ reason: "destination evidence satisfied",
8353
+ goal: afterCompletionSnapshot ?? void 0,
8354
+ inspection: {
8355
+ requiredEvidence: beforeCompletionSnapshot?.requiredEvidence,
8356
+ satisfiedEvidence: beforeCompletionSnapshot?.satisfiedEvidence,
8357
+ missingEvidence: beforeCompletionSnapshot?.missingEvidence
8358
+ },
8359
+ decision: { kind: "done", nextStep: "done", reason: "destination evidence satisfied" },
8360
+ change: goalRunLogChange(beforeCompletionSnapshot, afterCompletionSnapshot)
7911
8361
  });
7912
8362
  }
7913
8363
  if (serializeGoalState(next) === serializeGoalState(prior)) {
@@ -8093,7 +8543,7 @@ var init_classifyByLabel = __esm({
8093
8543
  });
8094
8544
 
8095
8545
  // src/scripts/commitAndPush.ts
8096
- import * as fs26 from "fs";
8546
+ import * as fs27 from "fs";
8097
8547
  import * as path26 from "path";
8098
8548
  function sentinelPathForStage(cwd, profileName) {
8099
8549
  const runId = resolveRunId();
@@ -8115,9 +8565,9 @@ var init_commitAndPush = __esm({
8115
8565
  }
8116
8566
  const idempotencyEnabled = process.env.KODY_COMMIT_IDEMPOTENCY !== "0";
8117
8567
  const sentinel = idempotencyEnabled ? sentinelPathForStage(ctx.cwd, profile.name) : null;
8118
- if (sentinel && fs26.existsSync(sentinel)) {
8568
+ if (sentinel && fs27.existsSync(sentinel)) {
8119
8569
  try {
8120
- const replay = JSON.parse(fs26.readFileSync(sentinel, "utf-8"));
8570
+ const replay = JSON.parse(fs27.readFileSync(sentinel, "utf-8"));
8121
8571
  ctx.data.commitResult = replay.commitResult ?? { committed: false, pushed: false };
8122
8572
  if (Array.isArray(replay.changedFiles)) ctx.data.changedFiles = replay.changedFiles;
8123
8573
  if (typeof replay.hasCommitsAhead === "boolean") ctx.data.hasCommitsAhead = replay.hasCommitsAhead;
@@ -8170,8 +8620,8 @@ var init_commitAndPush = __esm({
8170
8620
  const result = ctx.data.commitResult;
8171
8621
  if (sentinel && result?.committed) {
8172
8622
  try {
8173
- fs26.mkdirSync(path26.dirname(sentinel), { recursive: true });
8174
- fs26.writeFileSync(
8623
+ fs27.mkdirSync(path26.dirname(sentinel), { recursive: true });
8624
+ fs27.writeFileSync(
8175
8625
  sentinel,
8176
8626
  JSON.stringify(
8177
8627
  {
@@ -8243,7 +8693,7 @@ var init_commitGoalState = __esm({
8243
8693
  });
8244
8694
 
8245
8695
  // src/scripts/composePrompt.ts
8246
- import * as fs27 from "fs";
8696
+ import * as fs28 from "fs";
8247
8697
  import * as path27 from "path";
8248
8698
  function fenceUntrusted(value) {
8249
8699
  if (value.trim().length === 0) return value;
@@ -8383,7 +8833,7 @@ var init_composePrompt = __esm({
8383
8833
  break;
8384
8834
  }
8385
8835
  try {
8386
- template = fs27.readFileSync(c, "utf-8");
8836
+ template = fs28.readFileSync(c, "utf-8");
8387
8837
  templatePath = c;
8388
8838
  break;
8389
8839
  } catch (err) {
@@ -8394,7 +8844,7 @@ var init_composePrompt = __esm({
8394
8844
  if (!templatePath) {
8395
8845
  let dirState;
8396
8846
  try {
8397
- dirState = `dir contents: [${fs27.readdirSync(profile.dir).join(", ")}]`;
8847
+ dirState = `dir contents: [${fs28.readdirSync(profile.dir).join(", ")}]`;
8398
8848
  } catch (err) {
8399
8849
  dirState = `readdir(${profile.dir}) failed: ${err?.code ?? String(err)}`;
8400
8850
  }
@@ -8966,7 +9416,7 @@ var init_deriveQaScopeFromIssue = __esm({
8966
9416
 
8967
9417
  // src/scripts/diagMcp.ts
8968
9418
  import { execFileSync as execFileSync10 } from "child_process";
8969
- import * as fs28 from "fs";
9419
+ import * as fs29 from "fs";
8970
9420
  import * as os6 from "os";
8971
9421
  import * as path28 from "path";
8972
9422
  var diagMcp;
@@ -8978,7 +9428,7 @@ var init_diagMcp = __esm({
8978
9428
  const cacheDir = path28.join(home, ".cache", "ms-playwright");
8979
9429
  let entries = [];
8980
9430
  try {
8981
- entries = fs28.readdirSync(cacheDir);
9431
+ entries = fs29.readdirSync(cacheDir);
8982
9432
  } catch {
8983
9433
  }
8984
9434
  const hasChromium = entries.some((e) => e.startsWith("chromium"));
@@ -9006,13 +9456,13 @@ var init_diagMcp = __esm({
9006
9456
  });
9007
9457
 
9008
9458
  // src/scripts/frameworkDetectors.ts
9009
- import * as fs29 from "fs";
9459
+ import * as fs30 from "fs";
9010
9460
  import * as path29 from "path";
9011
9461
  function detectFrameworks(cwd) {
9012
9462
  const out = [];
9013
9463
  let deps = {};
9014
9464
  try {
9015
- const pkg = JSON.parse(fs29.readFileSync(path29.join(cwd, "package.json"), "utf-8"));
9465
+ const pkg = JSON.parse(fs30.readFileSync(path29.join(cwd, "package.json"), "utf-8"));
9016
9466
  deps = { ...pkg.dependencies, ...pkg.devDependencies };
9017
9467
  } catch {
9018
9468
  return out;
@@ -9049,7 +9499,7 @@ function detectFrameworks(cwd) {
9049
9499
  }
9050
9500
  function findFile(cwd, candidates) {
9051
9501
  for (const c of candidates) {
9052
- if (fs29.existsSync(path29.join(cwd, c))) return c;
9502
+ if (fs30.existsSync(path29.join(cwd, c))) return c;
9053
9503
  }
9054
9504
  return null;
9055
9505
  }
@@ -9057,17 +9507,17 @@ function discoverPayloadCollections(cwd) {
9057
9507
  const out = [];
9058
9508
  for (const dir of COLLECTION_DIRS) {
9059
9509
  const full = path29.join(cwd, dir);
9060
- if (!fs29.existsSync(full)) continue;
9510
+ if (!fs30.existsSync(full)) continue;
9061
9511
  let files;
9062
9512
  try {
9063
- files = fs29.readdirSync(full).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
9513
+ files = fs30.readdirSync(full).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
9064
9514
  } catch {
9065
9515
  continue;
9066
9516
  }
9067
9517
  for (const file of files) {
9068
9518
  try {
9069
9519
  const filePath = path29.join(full, file);
9070
- const content = fs29.readFileSync(filePath, "utf-8").slice(0, 1e4);
9520
+ const content = fs30.readFileSync(filePath, "utf-8").slice(0, 1e4);
9071
9521
  const slugMatch = content.match(/slug:\s*['"]([a-z0-9-]+)['"]/);
9072
9522
  if (!slugMatch) continue;
9073
9523
  const slug2 = slugMatch[1];
@@ -9095,10 +9545,10 @@ function discoverAdminComponents(cwd, collections) {
9095
9545
  const out = [];
9096
9546
  for (const dir of ADMIN_COMPONENT_DIRS) {
9097
9547
  const full = path29.join(cwd, dir);
9098
- if (!fs29.existsSync(full)) continue;
9548
+ if (!fs30.existsSync(full)) continue;
9099
9549
  let entries;
9100
9550
  try {
9101
- entries = fs29.readdirSync(full, { withFileTypes: true });
9551
+ entries = fs30.readdirSync(full, { withFileTypes: true });
9102
9552
  } catch {
9103
9553
  continue;
9104
9554
  }
@@ -9108,7 +9558,7 @@ function discoverAdminComponents(cwd, collections) {
9108
9558
  let filePath;
9109
9559
  if (entry.isDirectory()) {
9110
9560
  const indexFile = ["index.tsx", "index.ts", "index.jsx", "index.js"].find(
9111
- (f) => fs29.existsSync(path29.join(entryPath, f))
9561
+ (f) => fs30.existsSync(path29.join(entryPath, f))
9112
9562
  );
9113
9563
  if (!indexFile) continue;
9114
9564
  name = entry.name;
@@ -9123,7 +9573,7 @@ function discoverAdminComponents(cwd, collections) {
9123
9573
  if (collections) {
9124
9574
  for (const col of collections) {
9125
9575
  try {
9126
- const colContent = fs29.readFileSync(path29.join(cwd, col.filePath), "utf-8");
9576
+ const colContent = fs30.readFileSync(path29.join(cwd, col.filePath), "utf-8");
9127
9577
  if (colContent.includes(name)) {
9128
9578
  usedInCollection = col.slug;
9129
9579
  break;
@@ -9142,7 +9592,7 @@ function scanApiRoutes(cwd) {
9142
9592
  const appDirs = ["src/app", "app"];
9143
9593
  for (const appDir of appDirs) {
9144
9594
  const apiDir = path29.join(cwd, appDir, "api");
9145
- if (!fs29.existsSync(apiDir)) continue;
9595
+ if (!fs30.existsSync(apiDir)) continue;
9146
9596
  walkApiRoutes(apiDir, "/api", cwd, out);
9147
9597
  break;
9148
9598
  }
@@ -9151,14 +9601,14 @@ function scanApiRoutes(cwd) {
9151
9601
  function walkApiRoutes(dir, prefix, cwd, out) {
9152
9602
  let entries;
9153
9603
  try {
9154
- entries = fs29.readdirSync(dir, { withFileTypes: true });
9604
+ entries = fs30.readdirSync(dir, { withFileTypes: true });
9155
9605
  } catch {
9156
9606
  return;
9157
9607
  }
9158
9608
  const routeFile = entries.find((e) => e.isFile() && /^route\.(ts|js|tsx|jsx)$/.test(e.name));
9159
9609
  if (routeFile) {
9160
9610
  try {
9161
- const content = fs29.readFileSync(path29.join(dir, routeFile.name), "utf-8").slice(0, 5e3);
9611
+ const content = fs30.readFileSync(path29.join(dir, routeFile.name), "utf-8").slice(0, 5e3);
9162
9612
  const methods = HTTP_METHODS.filter(
9163
9613
  (m) => new RegExp(`export\\s+(?:async\\s+)?function\\s+${m}\\b`).test(content)
9164
9614
  );
@@ -9192,9 +9642,9 @@ function scanEnvVars(cwd) {
9192
9642
  const candidates = [".env.example", ".env.local.example", ".env.template"];
9193
9643
  for (const envFile of candidates) {
9194
9644
  const envPath = path29.join(cwd, envFile);
9195
- if (!fs29.existsSync(envPath)) continue;
9645
+ if (!fs30.existsSync(envPath)) continue;
9196
9646
  try {
9197
- const content = fs29.readFileSync(envPath, "utf-8");
9647
+ const content = fs30.readFileSync(envPath, "utf-8");
9198
9648
  const vars = [];
9199
9649
  for (const line of content.split("\n")) {
9200
9650
  const trimmed = line.trim();
@@ -9239,7 +9689,7 @@ var init_frameworkDetectors = __esm({
9239
9689
  });
9240
9690
 
9241
9691
  // src/scripts/discoverQaContext.ts
9242
- import * as fs30 from "fs";
9692
+ import * as fs31 from "fs";
9243
9693
  import * as path30 from "path";
9244
9694
  function runQaDiscovery(cwd) {
9245
9695
  const out = {
@@ -9271,9 +9721,9 @@ function runQaDiscovery(cwd) {
9271
9721
  }
9272
9722
  function detectDevServer(cwd, out) {
9273
9723
  try {
9274
- const pkg = JSON.parse(fs30.readFileSync(path30.join(cwd, "package.json"), "utf-8"));
9724
+ const pkg = JSON.parse(fs31.readFileSync(path30.join(cwd, "package.json"), "utf-8"));
9275
9725
  const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
9276
- const pm = fs30.existsSync(path30.join(cwd, "pnpm-lock.yaml")) ? "pnpm" : fs30.existsSync(path30.join(cwd, "yarn.lock")) ? "yarn" : fs30.existsSync(path30.join(cwd, "bun.lockb")) ? "bun" : "npm";
9726
+ 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";
9277
9727
  if (pkg.scripts?.dev) out.devCommand = `${pm} dev`;
9278
9728
  if (allDeps.next || allDeps.nuxt) out.devPort = 3e3;
9279
9729
  else if (allDeps.vite) out.devPort = 5173;
@@ -9284,7 +9734,7 @@ function scanFrontendRoutes(cwd, out) {
9284
9734
  const appDirs = ["src/app", "app"];
9285
9735
  for (const appDir of appDirs) {
9286
9736
  const full = path30.join(cwd, appDir);
9287
- if (!fs30.existsSync(full)) continue;
9737
+ if (!fs31.existsSync(full)) continue;
9288
9738
  walkFrontendRoutes(full, "", out);
9289
9739
  break;
9290
9740
  }
@@ -9292,7 +9742,7 @@ function scanFrontendRoutes(cwd, out) {
9292
9742
  function walkFrontendRoutes(dir, prefix, out) {
9293
9743
  let entries;
9294
9744
  try {
9295
- entries = fs30.readdirSync(dir, { withFileTypes: true });
9745
+ entries = fs31.readdirSync(dir, { withFileTypes: true });
9296
9746
  } catch {
9297
9747
  return;
9298
9748
  }
@@ -9334,23 +9784,23 @@ function detectAuthFiles(cwd, out) {
9334
9784
  "src/app/api/oauth"
9335
9785
  ];
9336
9786
  for (const c of candidates) {
9337
- if (fs30.existsSync(path30.join(cwd, c))) out.authFiles.push(c);
9787
+ if (fs31.existsSync(path30.join(cwd, c))) out.authFiles.push(c);
9338
9788
  }
9339
9789
  }
9340
9790
  function detectRoles(cwd, out) {
9341
9791
  const rolePaths = ["src/types", "src/lib", "src/utils", "src/constants", "src/access", "src/collections"];
9342
9792
  for (const rp of rolePaths) {
9343
9793
  const dir = path30.join(cwd, rp);
9344
- if (!fs30.existsSync(dir)) continue;
9794
+ if (!fs31.existsSync(dir)) continue;
9345
9795
  let files;
9346
9796
  try {
9347
- files = fs30.readdirSync(dir).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
9797
+ files = fs31.readdirSync(dir).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
9348
9798
  } catch {
9349
9799
  continue;
9350
9800
  }
9351
9801
  for (const f of files) {
9352
9802
  try {
9353
- const content = fs30.readFileSync(path30.join(dir, f), "utf-8").slice(0, 5e3);
9803
+ const content = fs31.readFileSync(path30.join(dir, f), "utf-8").slice(0, 5e3);
9354
9804
  const roleMatches = content.match(/(?:role|Role|ROLE)\s*[=:]\s*['"](\w+)['"]/g);
9355
9805
  if (roleMatches) {
9356
9806
  for (const m of roleMatches) {
@@ -10564,12 +11014,12 @@ var init_fixFlow = __esm({
10564
11014
 
10565
11015
  // src/scripts/initFlow.ts
10566
11016
  import { execFileSync as execFileSync15 } from "child_process";
10567
- import * as fs31 from "fs";
11017
+ import * as fs32 from "fs";
10568
11018
  import * as path31 from "path";
10569
11019
  function detectPackageManager(cwd) {
10570
- if (fs31.existsSync(path31.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
10571
- if (fs31.existsSync(path31.join(cwd, "yarn.lock"))) return "yarn";
10572
- if (fs31.existsSync(path31.join(cwd, "bun.lockb"))) return "bun";
11020
+ if (fs32.existsSync(path31.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
11021
+ if (fs32.existsSync(path31.join(cwd, "yarn.lock"))) return "yarn";
11022
+ if (fs32.existsSync(path31.join(cwd, "bun.lockb"))) return "bun";
10573
11023
  return "npm";
10574
11024
  }
10575
11025
  function qualityCommandsFor(pm) {
@@ -10642,21 +11092,21 @@ function performInit(cwd, force) {
10642
11092
  const ownerRepo = detectOwnerRepo(cwd);
10643
11093
  const defaultBranch = defaultBranchFromGit(cwd);
10644
11094
  const configPath = path31.join(cwd, "kody.config.json");
10645
- if (fs31.existsSync(configPath) && !force) {
11095
+ if (fs32.existsSync(configPath) && !force) {
10646
11096
  skipped.push("kody.config.json");
10647
11097
  } else {
10648
11098
  const cfg = makeConfig(pm, ownerRepo, defaultBranch);
10649
- fs31.writeFileSync(configPath, `${JSON.stringify(cfg, null, 2)}
11099
+ fs32.writeFileSync(configPath, `${JSON.stringify(cfg, null, 2)}
10650
11100
  `);
10651
11101
  wrote.push("kody.config.json");
10652
11102
  }
10653
11103
  const workflowDir = path31.join(cwd, ".github", "workflows");
10654
11104
  const workflowPath = path31.join(workflowDir, "kody.yml");
10655
- if (fs31.existsSync(workflowPath) && !force) {
11105
+ if (fs32.existsSync(workflowPath) && !force) {
10656
11106
  skipped.push(".github/workflows/kody.yml");
10657
11107
  } else {
10658
- fs31.mkdirSync(workflowDir, { recursive: true });
10659
- fs31.writeFileSync(workflowPath, WORKFLOW_TEMPLATE);
11108
+ fs32.mkdirSync(workflowDir, { recursive: true });
11109
+ fs32.writeFileSync(workflowPath, WORKFLOW_TEMPLATE);
10660
11110
  wrote.push(".github/workflows/kody.yml");
10661
11111
  }
10662
11112
  for (const exe of listAgentActions()) {
@@ -10668,11 +11118,11 @@ function performInit(cwd, force) {
10668
11118
  }
10669
11119
  if (profile.kind !== "scheduled" || !profile.schedule) continue;
10670
11120
  const target = path31.join(workflowDir, `kody-${exe.name}.yml`);
10671
- if (fs31.existsSync(target) && !force) {
11121
+ if (fs32.existsSync(target) && !force) {
10672
11122
  skipped.push(`.github/workflows/kody-${exe.name}.yml`);
10673
11123
  continue;
10674
11124
  }
10675
- fs31.writeFileSync(target, renderScheduledWorkflow(exe.name, profile.schedule));
11125
+ fs32.writeFileSync(target, renderScheduledWorkflow(exe.name, profile.schedule));
10676
11126
  wrote.push(`.github/workflows/kody-${exe.name}.yml`);
10677
11127
  }
10678
11128
  let labels;
@@ -10825,7 +11275,7 @@ Nothing to do. All files already present. (Use --force to overwrite.)
10825
11275
  });
10826
11276
 
10827
11277
  // src/scripts/loadAgentAdhoc.ts
10828
- import * as fs32 from "fs";
11278
+ import * as fs33 from "fs";
10829
11279
  function resolveMessage(messageArg) {
10830
11280
  const fromComment = readCommentBody();
10831
11281
  if (fromComment) return stripDirective(fromComment);
@@ -10833,9 +11283,9 @@ function resolveMessage(messageArg) {
10833
11283
  }
10834
11284
  function readCommentBody() {
10835
11285
  const eventPath = process.env.GITHUB_EVENT_PATH;
10836
- if (!eventPath || !fs32.existsSync(eventPath)) return "";
11286
+ if (!eventPath || !fs33.existsSync(eventPath)) return "";
10837
11287
  try {
10838
- const event = JSON.parse(fs32.readFileSync(eventPath, "utf-8"));
11288
+ const event = JSON.parse(fs33.readFileSync(eventPath, "utf-8"));
10839
11289
  return String(event.comment?.body ?? "");
10840
11290
  } catch {
10841
11291
  return "";
@@ -10888,10 +11338,10 @@ var init_loadAgentAdhoc = __esm({
10888
11338
  throw new Error("loadAgentAdhoc: ctx.args.agent must be a non-empty slug");
10889
11339
  }
10890
11340
  const agentPath = resolveAgentFile(ctx.cwd, agentSlug, agentsDir);
10891
- if (!fs32.existsSync(agentPath)) {
11341
+ if (!fs33.existsSync(agentPath)) {
10892
11342
  throw new Error(`loadAgentAdhoc: agent identity not found: ${agentPath}`);
10893
11343
  }
10894
- const { title, body } = parseAgentFile(fs32.readFileSync(agentPath, "utf-8"), agentSlug);
11344
+ const { title, body } = parseAgentFile(fs33.readFileSync(agentPath, "utf-8"), agentSlug);
10895
11345
  const message = resolveMessage(ctx.args.message);
10896
11346
  if (!message) {
10897
11347
  throw new Error(
@@ -11129,7 +11579,7 @@ var init_loadIssueStateComment = __esm({
11129
11579
  });
11130
11580
 
11131
11581
  // src/scripts/loadJobFromFile.ts
11132
- import * as fs33 from "fs";
11582
+ import * as fs34 from "fs";
11133
11583
  import * as path32 from "path";
11134
11584
  function parseJobFile(raw, slug2) {
11135
11585
  let stripped = raw;
@@ -11181,12 +11631,12 @@ var init_loadJobFromFile = __esm({
11181
11631
  let agentIdentity = "";
11182
11632
  if (agentSlug) {
11183
11633
  const agentPath = resolveAgentFile(ctx.cwd, agentSlug, agentsDir);
11184
- if (!fs33.existsSync(agentPath)) {
11634
+ if (!fs34.existsSync(agentPath)) {
11185
11635
  throw new Error(
11186
11636
  `loadJobFromFile: agentResponsibility '${slug2}' declares agent '${agentSlug}' but ${agentPath} does not exist`
11187
11637
  );
11188
11638
  }
11189
- const agentRaw = fs33.readFileSync(agentPath, "utf-8");
11639
+ const agentRaw = fs34.readFileSync(agentPath, "utf-8");
11190
11640
  const parsed = parseJobFile(agentRaw, agentSlug);
11191
11641
  agentTitle = parsed.title;
11192
11642
  agentIdentity = parsed.body;
@@ -11260,13 +11710,13 @@ ${truncate(issue.body, FINDING_BODY_MAX_BYTES)}`;
11260
11710
  });
11261
11711
 
11262
11712
  // src/scripts/kodyVariables.ts
11263
- import * as fs34 from "fs";
11713
+ import * as fs35 from "fs";
11264
11714
  import * as path33 from "path";
11265
11715
  function readKodyVariables(cwd) {
11266
11716
  const full = path33.join(cwd, KODY_VARIABLES_REL_PATH);
11267
11717
  let raw;
11268
11718
  try {
11269
- raw = fs34.readFileSync(full, "utf-8");
11719
+ raw = fs35.readFileSync(full, "utf-8");
11270
11720
  } catch {
11271
11721
  return {};
11272
11722
  }
@@ -11291,7 +11741,7 @@ var init_kodyVariables = __esm({
11291
11741
  });
11292
11742
 
11293
11743
  // src/scripts/loadQaContext.ts
11294
- import * as fs35 from "fs";
11744
+ import * as fs36 from "fs";
11295
11745
  import * as path34 from "path";
11296
11746
  function parseSlugList(value) {
11297
11747
  const inner = value.startsWith("[") && value.endsWith("]") ? value.slice(1, -1) : value;
@@ -11322,17 +11772,17 @@ function readProfileAgents(raw) {
11322
11772
  }
11323
11773
  function readProfile(cwd) {
11324
11774
  const dir = path34.join(cwd, CONTEXT_DIR_REL_PATH);
11325
- if (!fs35.existsSync(dir)) return "";
11775
+ if (!fs36.existsSync(dir)) return "";
11326
11776
  let entries;
11327
11777
  try {
11328
- entries = fs35.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
11778
+ entries = fs36.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
11329
11779
  } catch {
11330
11780
  return "";
11331
11781
  }
11332
11782
  const blocks = [];
11333
11783
  for (const file of entries) {
11334
11784
  try {
11335
- const raw = fs35.readFileSync(path34.join(dir, file), "utf-8");
11785
+ const raw = fs36.readFileSync(path34.join(dir, file), "utf-8");
11336
11786
  const { agent, body } = readProfileAgents(raw);
11337
11787
  if (!agent.includes(QA_AGENT) && !agent.includes(ALL_AGENTS)) continue;
11338
11788
  blocks.push(`## ${file}
@@ -11378,7 +11828,7 @@ var init_loadQaContext = __esm({
11378
11828
  });
11379
11829
 
11380
11830
  // src/taskContext.ts
11381
- import * as fs36 from "fs";
11831
+ import * as fs37 from "fs";
11382
11832
  import * as path35 from "path";
11383
11833
  function buildTaskContext(args) {
11384
11834
  return {
@@ -11395,9 +11845,9 @@ function buildTaskContext(args) {
11395
11845
  function persistTaskContext(cwd, ctx) {
11396
11846
  try {
11397
11847
  const dir = runtimeStatePath(cwd, "agent-runs", ctx.runId);
11398
- fs36.mkdirSync(dir, { recursive: true });
11848
+ fs37.mkdirSync(dir, { recursive: true });
11399
11849
  const file = path35.join(dir, "task-context.json");
11400
- fs36.writeFileSync(file, `${JSON.stringify(ctx, null, 2)}
11850
+ fs37.writeFileSync(file, `${JSON.stringify(ctx, null, 2)}
11401
11851
  `);
11402
11852
  return file;
11403
11853
  } catch (err) {
@@ -13742,9 +14192,9 @@ fi
13742
14192
  });
13743
14193
 
13744
14194
  // src/stateRepoGithub.ts
13745
- import * as fs37 from "fs";
14195
+ import * as fs38 from "fs";
13746
14196
  import * as path36 from "path";
13747
- function recordValue2(value) {
14197
+ function recordValue3(value) {
13748
14198
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
13749
14199
  }
13750
14200
  function contentsUrl(owner, repo, filePath) {
@@ -13800,12 +14250,12 @@ async function loadGithubStateConfig(opts) {
13800
14250
  throw new Error(`kody.config.json is invalid JSON: ${err instanceof Error ? err.message : String(err)}`);
13801
14251
  }
13802
14252
  }
13803
- const githubRaw = recordValue2(raw.github) ?? {};
14253
+ const githubRaw = recordValue3(raw.github) ?? {};
13804
14254
  const github = {
13805
14255
  owner: typeof githubRaw.owner === "string" && githubRaw.owner.trim() ? githubRaw.owner.trim() : opts.owner,
13806
14256
  repo: typeof githubRaw.repo === "string" && githubRaw.repo.trim() ? githubRaw.repo.trim() : opts.repo
13807
14257
  };
13808
- const nestedState = recordValue2(raw.state) ?? {};
14258
+ const nestedState = recordValue3(raw.state) ?? {};
13809
14259
  const repoRaw = typeof raw.stateRepo === "string" ? raw.stateRepo : nestedState.repo;
13810
14260
  const pathRaw = typeof raw.statePath === "string" ? raw.statePath : nestedState.path;
13811
14261
  const stateRepo = typeof repoRaw === "string" && repoRaw.trim().length > 0 ? repoRaw.trim() : `https://github.com/${github.owner}/kody-state`;
@@ -13883,15 +14333,15 @@ function mergeJsonl(localText, remoteText) {
13883
14333
  async function syncJsonlFileFromGithubState(opts) {
13884
14334
  const remote = await readGithubStateTextWithConfig(opts);
13885
14335
  if (!remote) return;
13886
- const local = fs37.existsSync(opts.localPath) ? fs37.readFileSync(opts.localPath, "utf-8") : "";
14336
+ const local = fs38.existsSync(opts.localPath) ? fs38.readFileSync(opts.localPath, "utf-8") : "";
13887
14337
  const next = mergeJsonl(local, remote.content);
13888
14338
  if (next === local) return;
13889
- fs37.mkdirSync(path36.dirname(opts.localPath), { recursive: true });
13890
- fs37.writeFileSync(opts.localPath, next);
14339
+ fs38.mkdirSync(path36.dirname(opts.localPath), { recursive: true });
14340
+ fs38.writeFileSync(opts.localPath, next);
13891
14341
  }
13892
14342
  async function persistJsonlFileToGithubState(opts) {
13893
- if (!fs37.existsSync(opts.localPath)) return;
13894
- const localText = fs37.readFileSync(opts.localPath, "utf-8");
14343
+ if (!fs38.existsSync(opts.localPath)) return;
14344
+ const localText = fs38.readFileSync(opts.localPath, "utf-8");
13895
14345
  for (let attempt = 1; attempt <= 3; attempt += 1) {
13896
14346
  const remote = await readGithubStateTextWithConfig(opts);
13897
14347
  const body = mergeJsonl(localText, remote?.content ?? "");
@@ -14368,7 +14818,7 @@ var init_tickShellRunner = __esm({
14368
14818
  });
14369
14819
 
14370
14820
  // src/scripts/runScheduledAgentActionTick.ts
14371
- import * as fs38 from "fs";
14821
+ import * as fs39 from "fs";
14372
14822
  import * as path38 from "path";
14373
14823
  var runScheduledAgentActionTick;
14374
14824
  var init_runScheduledAgentActionTick = __esm({
@@ -14396,7 +14846,7 @@ var init_runScheduledAgentActionTick = __esm({
14396
14846
  return;
14397
14847
  }
14398
14848
  const shellPath = path38.join(profile.dir, shell);
14399
- if (!fs38.existsSync(shellPath)) {
14849
+ if (!fs39.existsSync(shellPath)) {
14400
14850
  ctx.output.exitCode = 99;
14401
14851
  ctx.output.reason = `runScheduledAgentActionTick: shell not found: ${shell} (looked in ${profile.dir})`;
14402
14852
  return;
@@ -14427,7 +14877,7 @@ var init_runScheduledAgentActionTick = __esm({
14427
14877
  });
14428
14878
 
14429
14879
  // src/scripts/runTickScript.ts
14430
- import * as fs39 from "fs";
14880
+ import * as fs40 from "fs";
14431
14881
  import * as path39 from "path";
14432
14882
  var runTickScript;
14433
14883
  var init_runTickScript = __esm({
@@ -14460,7 +14910,7 @@ var init_runTickScript = __esm({
14460
14910
  return;
14461
14911
  }
14462
14912
  const scriptPath = path39.isAbsolute(tickScript) ? tickScript : path39.join(ctx.cwd, tickScript);
14463
- if (!fs39.existsSync(scriptPath)) {
14913
+ if (!fs40.existsSync(scriptPath)) {
14464
14914
  ctx.output.exitCode = 99;
14465
14915
  ctx.output.reason = `runTickScript: tickScript not found: ${scriptPath}`;
14466
14916
  return;
@@ -15282,7 +15732,7 @@ var init_warmupMcp = __esm({
15282
15732
  });
15283
15733
 
15284
15734
  // src/scripts/writeAgentRunSummary.ts
15285
- import * as fs40 from "fs";
15735
+ import * as fs41 from "fs";
15286
15736
  var writeAgentRunSummary;
15287
15737
  var init_writeAgentRunSummary = __esm({
15288
15738
  "src/scripts/writeAgentRunSummary.ts"() {
@@ -15308,7 +15758,7 @@ var init_writeAgentRunSummary = __esm({
15308
15758
  if (reason) lines.push(`- **Reason:** ${reason}`);
15309
15759
  lines.push("");
15310
15760
  try {
15311
- fs40.appendFileSync(summaryPath, `${lines.join("\n")}
15761
+ fs41.appendFileSync(summaryPath, `${lines.join("\n")}
15312
15762
  `);
15313
15763
  } catch {
15314
15764
  }
@@ -15710,17 +16160,17 @@ var init_scripts = __esm({
15710
16160
  });
15711
16161
 
15712
16162
  // src/stateWorkspace.ts
15713
- import * as fs41 from "fs";
16163
+ import * as fs42 from "fs";
15714
16164
  import * as path40 from "path";
15715
16165
  function writeLocalFile(cwd, relativePath, content) {
15716
16166
  const fullPath = path40.join(cwd, relativePath);
15717
- fs41.mkdirSync(path40.dirname(fullPath), { recursive: true });
15718
- fs41.writeFileSync(fullPath, content);
16167
+ fs42.mkdirSync(path40.dirname(fullPath), { recursive: true });
16168
+ fs42.writeFileSync(fullPath, content);
15719
16169
  }
15720
16170
  function hydrateDirectory(config, cwd, stateDir, localDir) {
15721
16171
  const entries = listStateDirectory(config, cwd, stateDir);
15722
16172
  if (entries.length === 0) return;
15723
- fs41.rmSync(path40.join(cwd, localDir), { recursive: true, force: true });
16173
+ fs42.rmSync(path40.join(cwd, localDir), { recursive: true, force: true });
15724
16174
  for (const entry of entries) {
15725
16175
  if (!entry.name || !entry.type) continue;
15726
16176
  const childState = path40.posix.join(stateDir, entry.name);
@@ -15828,7 +16278,7 @@ var init_tools = __esm({
15828
16278
 
15829
16279
  // src/executor.ts
15830
16280
  import { spawn as spawn7 } from "child_process";
15831
- import * as fs42 from "fs";
16281
+ import * as fs43 from "fs";
15832
16282
  import * as path41 from "path";
15833
16283
  function isMutatingPostflight(scriptName) {
15834
16284
  return MUTATING_POSTFLIGHTS.has(scriptName ?? "");
@@ -16405,7 +16855,7 @@ function resolveProfilePath(profileName) {
16405
16855
  // fallback
16406
16856
  ];
16407
16857
  for (const c of candidates) {
16408
- if (fs42.existsSync(c)) return c;
16858
+ if (fs43.existsSync(c)) return c;
16409
16859
  }
16410
16860
  return candidates[0];
16411
16861
  }
@@ -16504,7 +16954,7 @@ function resolveShellTimeoutMs(entry) {
16504
16954
  async function runShellEntry(entry, ctx, profile) {
16505
16955
  const shellName = entry.shell;
16506
16956
  const shellPath = path41.join(profile.dir, shellName);
16507
- if (!fs42.existsSync(shellPath)) {
16957
+ if (!fs43.existsSync(shellPath)) {
16508
16958
  ctx.skipAgent = true;
16509
16959
  ctx.output.exitCode = 99;
16510
16960
  ctx.output.reason = `shell script not found: ${shellName} (looked in ${profile.dir})`;
@@ -16916,7 +17366,7 @@ function translateOpenAISseToBrain(opts) {
16916
17366
  }
16917
17367
 
16918
17368
  // src/servers/brain-serve.ts
16919
- import * as fs45 from "fs";
17369
+ import * as fs46 from "fs";
16920
17370
  import { createServer } from "http";
16921
17371
  import * as path45 from "path";
16922
17372
 
@@ -17478,7 +17928,7 @@ init_config();
17478
17928
 
17479
17929
  // src/kody-cli.ts
17480
17930
  import { execFileSync as execFileSync25 } from "child_process";
17481
- import * as fs43 from "fs";
17931
+ import * as fs44 from "fs";
17482
17932
  import * as path43 from "path";
17483
17933
 
17484
17934
  // src/app-auth.ts
@@ -18100,9 +18550,9 @@ async function resolveAuthToken(env = process.env) {
18100
18550
  return void 0;
18101
18551
  }
18102
18552
  function detectPackageManager2(cwd) {
18103
- if (fs43.existsSync(path43.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
18104
- if (fs43.existsSync(path43.join(cwd, "yarn.lock"))) return "yarn";
18105
- if (fs43.existsSync(path43.join(cwd, "bun.lockb"))) return "bun";
18553
+ if (fs44.existsSync(path43.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
18554
+ if (fs44.existsSync(path43.join(cwd, "yarn.lock"))) return "yarn";
18555
+ if (fs44.existsSync(path43.join(cwd, "bun.lockb"))) return "bun";
18106
18556
  return "npm";
18107
18557
  }
18108
18558
  function shouldChainScheduledWatch(match) {
@@ -18195,8 +18645,8 @@ function postFailureTail(issueNumber, cwd, reason) {
18195
18645
  const logPath = lastRunLogPath(cwd);
18196
18646
  let tail = "";
18197
18647
  try {
18198
- if (fs43.existsSync(logPath)) {
18199
- const content = fs43.readFileSync(logPath, "utf-8");
18648
+ if (fs44.existsSync(logPath)) {
18649
+ const content = fs44.readFileSync(logPath, "utf-8");
18200
18650
  tail = content.slice(-3e3);
18201
18651
  }
18202
18652
  } catch {
@@ -18236,9 +18686,9 @@ async function runCi(argv) {
18236
18686
  let manualWorkflowDispatch = false;
18237
18687
  let forceRunAction = null;
18238
18688
  let forceRunCliArgs = {};
18239
- if (!args.issueNumber && !autoFallback && eventName === "workflow_dispatch" && dispatchEventPath && fs43.existsSync(dispatchEventPath)) {
18689
+ if (!args.issueNumber && !autoFallback && eventName === "workflow_dispatch" && dispatchEventPath && fs44.existsSync(dispatchEventPath)) {
18240
18690
  try {
18241
- const evt = JSON.parse(fs43.readFileSync(dispatchEventPath, "utf-8"));
18691
+ const evt = JSON.parse(fs44.readFileSync(dispatchEventPath, "utf-8"));
18242
18692
  const issueInput = parseInt(String(evt?.inputs?.issue_number ?? ""), 10);
18243
18693
  const sessionInput = String(evt?.inputs?.sessionId ?? "");
18244
18694
  const dutyInput = String(evt?.inputs?.agentResponsibility ?? evt?.inputs?.agentAction ?? "").trim();
@@ -18570,7 +19020,7 @@ init_repoWorkspace();
18570
19020
 
18571
19021
  // src/scripts/brainTurnLog.ts
18572
19022
  init_runtimePaths();
18573
- import * as fs44 from "fs";
19023
+ import * as fs45 from "fs";
18574
19024
  import * as path44 from "path";
18575
19025
  import posixPath4 from "path/posix";
18576
19026
  var live = /* @__PURE__ */ new Map();
@@ -18582,8 +19032,8 @@ function brainEventsStatePath(chatId) {
18582
19032
  }
18583
19033
  function lastPersistedSeq(dir, chatId) {
18584
19034
  const p = brainEventsFilePath(dir, chatId);
18585
- if (!fs44.existsSync(p)) return 0;
18586
- const lines = fs44.readFileSync(p, "utf-8").split("\n").filter(Boolean);
19035
+ if (!fs45.existsSync(p)) return 0;
19036
+ const lines = fs45.readFileSync(p, "utf-8").split("\n").filter(Boolean);
18587
19037
  if (lines.length === 0) return 0;
18588
19038
  try {
18589
19039
  return JSON.parse(lines[lines.length - 1]).seq || 0;
@@ -18593,9 +19043,9 @@ function lastPersistedSeq(dir, chatId) {
18593
19043
  }
18594
19044
  function readSince(dir, chatId, since) {
18595
19045
  const p = brainEventsFilePath(dir, chatId);
18596
- if (!fs44.existsSync(p)) return [];
19046
+ if (!fs45.existsSync(p)) return [];
18597
19047
  const out = [];
18598
- for (const line of fs44.readFileSync(p, "utf-8").split("\n")) {
19048
+ for (const line of fs45.readFileSync(p, "utf-8").split("\n")) {
18599
19049
  if (!line) continue;
18600
19050
  try {
18601
19051
  const rec = JSON.parse(line);
@@ -18621,12 +19071,12 @@ function beginTurn(dir, chatId) {
18621
19071
  };
18622
19072
  live.set(chatId, state);
18623
19073
  const p = brainEventsFilePath(dir, chatId);
18624
- fs44.mkdirSync(path44.dirname(p), { recursive: true });
19074
+ fs45.mkdirSync(path44.dirname(p), { recursive: true });
18625
19075
  return (event) => {
18626
19076
  state.seq += 1;
18627
19077
  const rec = { seq: state.seq, turn, ts: Date.now(), event };
18628
19078
  try {
18629
- fs44.appendFileSync(p, `${JSON.stringify(rec)}
19079
+ fs45.appendFileSync(p, `${JSON.stringify(rec)}
18630
19080
  `);
18631
19081
  } catch (err) {
18632
19082
  process.stderr.write(
@@ -18665,7 +19115,7 @@ function endTurnIfUnterminated(dir, chatId, errMessage) {
18665
19115
  event: { type: "error", error: errMessage || "turn ended unexpectedly", chatId }
18666
19116
  };
18667
19117
  try {
18668
- fs44.appendFileSync(brainEventsFilePath(dir, chatId), `${JSON.stringify(rec)}
19118
+ fs45.appendFileSync(brainEventsFilePath(dir, chatId), `${JSON.stringify(rec)}
18669
19119
  `);
18670
19120
  } catch {
18671
19121
  }
@@ -18971,7 +19421,7 @@ async function handleChatTurn(req, res, chatId, opts) {
18971
19421
  );
18972
19422
  }
18973
19423
  }
18974
- fs45.mkdirSync(path45.dirname(sessionFile), { recursive: true });
19424
+ fs46.mkdirSync(path45.dirname(sessionFile), { recursive: true });
18975
19425
  appendTurn(sessionFile, {
18976
19426
  role: "user",
18977
19427
  content: message,
@@ -19631,7 +20081,7 @@ async function loadConfigSafe() {
19631
20081
  }
19632
20082
 
19633
20083
  // src/chat-cli.ts
19634
- import * as fs47 from "fs";
20084
+ import * as fs48 from "fs";
19635
20085
  import * as path47 from "path";
19636
20086
 
19637
20087
  // src/chat/inbox.ts
@@ -19704,7 +20154,7 @@ function currentBranch(cwd) {
19704
20154
 
19705
20155
  // src/chat/state-sync.ts
19706
20156
  init_stateRepo();
19707
- import * as fs46 from "fs";
20157
+ import * as fs47 from "fs";
19708
20158
  import * as path46 from "path";
19709
20159
  function jsonlLines2(text) {
19710
20160
  return text.split("\n").filter((line) => line.length > 0);
@@ -19722,15 +20172,15 @@ function mergeJsonl2(localText, remoteText) {
19722
20172
  function syncJsonlFileFromState(opts) {
19723
20173
  const remote = readStateText(opts.config, opts.cwd, opts.statePath);
19724
20174
  if (!remote) return;
19725
- const local = fs46.existsSync(opts.localPath) ? fs46.readFileSync(opts.localPath, "utf-8") : "";
20175
+ const local = fs47.existsSync(opts.localPath) ? fs47.readFileSync(opts.localPath, "utf-8") : "";
19726
20176
  const next = mergeJsonl2(local, remote.content);
19727
20177
  if (next === local) return;
19728
- fs46.mkdirSync(path46.dirname(opts.localPath), { recursive: true });
19729
- fs46.writeFileSync(opts.localPath, next);
20178
+ fs47.mkdirSync(path46.dirname(opts.localPath), { recursive: true });
20179
+ fs47.writeFileSync(opts.localPath, next);
19730
20180
  }
19731
20181
  function persistJsonlFileToState(opts) {
19732
- if (!fs46.existsSync(opts.localPath)) return;
19733
- const localText = fs46.readFileSync(opts.localPath, "utf-8");
20182
+ if (!fs47.existsSync(opts.localPath)) return;
20183
+ const localText = fs47.readFileSync(opts.localPath, "utf-8");
19734
20184
  for (let attempt = 1; attempt <= 3; attempt += 1) {
19735
20185
  const remote = readStateText(opts.config, opts.cwd, opts.statePath);
19736
20186
  const body = mergeJsonl2(localText, remote?.content ?? "");
@@ -20051,7 +20501,7 @@ ${CHAT_HELP}`);
20051
20501
  const sink = buildSink(cwd, sessionId, args.dashboardUrl);
20052
20502
  const meta = readMeta(sessionFile);
20053
20503
  process.stdout.write(
20054
- `\u2192 kody:chat: session file=${sessionFile} exists=${fs47.existsSync(sessionFile)} meta=${meta ? meta.mode : "none"}
20504
+ `\u2192 kody:chat: session file=${sessionFile} exists=${fs48.existsSync(sessionFile)} meta=${meta ? meta.mode : "none"}
20055
20505
  `
20056
20506
  );
20057
20507
  try {
@@ -20938,7 +21388,7 @@ async function poolServe() {
20938
21388
 
20939
21389
  // src/servers/runner-serve.ts
20940
21390
  import { spawn as spawn8 } from "child_process";
20941
- import * as fs48 from "fs";
21391
+ import * as fs49 from "fs";
20942
21392
  import { createServer as createServer5 } from "http";
20943
21393
  var DEFAULT_PORT2 = 8080;
20944
21394
  var DEFAULT_WORKDIR = "/workspace/repo";
@@ -21018,8 +21468,8 @@ async function defaultRunJob(job) {
21018
21468
  const workdir = process.env.RUNNER_WORKDIR ?? DEFAULT_WORKDIR;
21019
21469
  const branch = job.ref ?? "main";
21020
21470
  const authUrl = `https://x-access-token:${job.githubToken}@github.com/${job.repo}.git`;
21021
- fs48.rmSync(workdir, { recursive: true, force: true });
21022
- fs48.mkdirSync(workdir, { recursive: true });
21471
+ fs49.rmSync(workdir, { recursive: true, force: true });
21472
+ fs49.mkdirSync(workdir, { recursive: true });
21023
21473
  const allSecrets = typeof job.allSecrets === "string" ? job.allSecrets : JSON.stringify(job.allSecrets ?? {});
21024
21474
  const interactive = job.mode === "interactive";
21025
21475
  const scheduled = job.mode === "scheduled";