@kody-ade/kody-engine 0.4.254 → 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 +819 -131
  2. package/package.json +22 -23
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.254",
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;
@@ -6179,6 +6192,308 @@ var init_state2 = __esm({
6179
6192
  }
6180
6193
  });
6181
6194
 
6195
+ // src/goal/runLog.ts
6196
+ import * as fs25 from "fs";
6197
+ function stageGoalRunLogEvent(data, goalId, event, at = nowIso()) {
6198
+ const logs = goalRunLogs(data);
6199
+ const existing = logs[goalId];
6200
+ const path48 = existing?.path ?? goalRunLogPath(goalId, data);
6201
+ logs[goalId] = {
6202
+ path: path48,
6203
+ events: [
6204
+ ...existing?.events ?? [],
6205
+ {
6206
+ version: 1,
6207
+ time: at,
6208
+ goalId,
6209
+ ...event
6210
+ }
6211
+ ]
6212
+ };
6213
+ }
6214
+ function flushGoalRunLogEvents(config, cwd, data) {
6215
+ const logs = goalRunLogs(data);
6216
+ for (const [goalId, log2] of Object.entries(logs)) {
6217
+ if (log2.events.length === 0) continue;
6218
+ const lines = `${log2.events.map((event) => JSON.stringify(enrichGoalRunLogEvent(config, data, log2.path, event))).join("\n")}
6219
+ `;
6220
+ appendStateLine(config, cwd, log2.path, lines, `chore(goal-logs): append ${goalId}`);
6221
+ log2.events = [];
6222
+ }
6223
+ }
6224
+ function goalRunLogPath(goalId, data) {
6225
+ const startedAt = goalRunStartedAt(data);
6226
+ const runId = goalRunId(data);
6227
+ return `logs/goals/${safePathSegment(goalId)}/runs/${startedAt}-${runId}.jsonl`;
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
+ }
6278
+ function goalRunLogs(data) {
6279
+ const existing = data[LOGS_KEY];
6280
+ if (existing && typeof existing === "object" && !Array.isArray(existing)) {
6281
+ return existing;
6282
+ }
6283
+ const logs = {};
6284
+ data[LOGS_KEY] = logs;
6285
+ return logs;
6286
+ }
6287
+ function goalRunStartedAt(data) {
6288
+ const existing = data[LOG_STARTED_KEY];
6289
+ if (typeof existing === "string" && existing.length > 0) return existing;
6290
+ const stamp = nowIso().replace(/[:.]/g, "-");
6291
+ data[LOG_STARTED_KEY] = stamp;
6292
+ return stamp;
6293
+ }
6294
+ function goalRunId(data) {
6295
+ const existing = data[LOG_RUN_KEY];
6296
+ if (typeof existing === "string" && existing.length > 0) return existing;
6297
+ const raw = stringValue(data.jobId) ?? githubRunId() ?? `local-${process.pid}-${Date.now()}`;
6298
+ const safe = safePathSegment(raw);
6299
+ data[LOG_RUN_KEY] = safe;
6300
+ return safe;
6301
+ }
6302
+ function githubRunId() {
6303
+ const runId = process.env.GITHUB_RUN_ID?.trim();
6304
+ if (!runId) return null;
6305
+ const attempt = process.env.GITHUB_RUN_ATTEMPT?.trim();
6306
+ return attempt ? `gh-${runId}-${attempt}` : `gh-${runId}`;
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
+ }
6478
+ function stringValue(value) {
6479
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
6480
+ }
6481
+ function safePathSegment(value) {
6482
+ const safe = value.trim().replace(/[^A-Za-z0-9_.-]+/g, "-").replace(/^-+|-+$/g, "");
6483
+ return safe || "unknown";
6484
+ }
6485
+ var LOGS_KEY, LOG_RUN_KEY, LOG_STARTED_KEY;
6486
+ var init_runLog = __esm({
6487
+ "src/goal/runLog.ts"() {
6488
+ "use strict";
6489
+ init_stateRepo();
6490
+ init_state2();
6491
+ LOGS_KEY = "__goalRunLogs";
6492
+ LOG_RUN_KEY = "__goalRunLogRunId";
6493
+ LOG_STARTED_KEY = "__goalRunLogStartedAt";
6494
+ }
6495
+ });
6496
+
6182
6497
  // src/goal/typeDefinitions.ts
6183
6498
  function cloneRoute(route) {
6184
6499
  return route.map((step) => ({
@@ -6505,7 +6820,7 @@ var init_contentsApiBackend = __esm({
6505
6820
  });
6506
6821
 
6507
6822
  // src/scripts/jobState/localFileBackend.ts
6508
- import * as fs25 from "fs";
6823
+ import * as fs26 from "fs";
6509
6824
  import * as path24 from "path";
6510
6825
  function sanitizeKey(s) {
6511
6826
  return s.replace(/[^A-Za-z0-9._-]/g, "-");
@@ -6577,7 +6892,7 @@ var init_localFileBackend = __esm({
6577
6892
  `);
6578
6893
  return;
6579
6894
  }
6580
- fs25.mkdirSync(this.absDir, { recursive: true });
6895
+ fs26.mkdirSync(this.absDir, { recursive: true });
6581
6896
  const prefix = this.cacheKeyPrefix();
6582
6897
  const probeKey = `${prefix}probe-${Date.now()}`;
6583
6898
  try {
@@ -6606,7 +6921,7 @@ var init_localFileBackend = __esm({
6606
6921
  `);
6607
6922
  return;
6608
6923
  }
6609
- if (!fs25.existsSync(this.absDir)) {
6924
+ if (!fs26.existsSync(this.absDir)) {
6610
6925
  return;
6611
6926
  }
6612
6927
  const key = `${this.cacheKeyPrefix()}${process.env.GITHUB_RUN_ID ?? "norunid"}-${Date.now()}`;
@@ -6623,10 +6938,10 @@ var init_localFileBackend = __esm({
6623
6938
  load(slug2) {
6624
6939
  const relPath = stateFilePath(this.jobsDir, slug2);
6625
6940
  const absPath = path24.join(this.cwd, relPath);
6626
- if (!fs25.existsSync(absPath)) {
6941
+ if (!fs26.existsSync(absPath)) {
6627
6942
  return { path: relPath, handle: null, state: initialStateEnvelope("seed"), created: true };
6628
6943
  }
6629
- const raw = fs25.readFileSync(absPath, "utf-8");
6944
+ const raw = fs26.readFileSync(absPath, "utf-8");
6630
6945
  let parsed;
6631
6946
  try {
6632
6947
  parsed = JSON.parse(raw);
@@ -6644,12 +6959,12 @@ var init_localFileBackend = __esm({
6644
6959
  return false;
6645
6960
  }
6646
6961
  const absPath = path24.join(this.cwd, loaded.path);
6647
- fs25.mkdirSync(path24.dirname(absPath), { recursive: true });
6962
+ fs26.mkdirSync(path24.dirname(absPath), { recursive: true });
6648
6963
  const body = `${JSON.stringify(next, null, 2)}
6649
6964
  `;
6650
6965
  const tmpPath = `${absPath}.${process.pid}.tmp`;
6651
- fs25.writeFileSync(tmpPath, body, "utf-8");
6652
- fs25.renameSync(tmpPath, absPath);
6966
+ fs26.writeFileSync(tmpPath, body, "utf-8");
6967
+ fs26.renameSync(tmpPath, absPath);
6653
6968
  return true;
6654
6969
  }
6655
6970
  cacheKeyPrefix() {
@@ -6918,6 +7233,87 @@ var init_goalAgentResponsibilityScheduling = __esm({
6918
7233
  });
6919
7234
 
6920
7235
  // src/scripts/advanceManagedGoal.ts
7236
+ function stageManagedGoalDecision(data, goalId, goal, goalState, decision, details) {
7237
+ if (decision.kind === "dispatch") {
7238
+ stageGoalRunLogEvent(data, goalId, {
7239
+ source: "goal-manager",
7240
+ event: "goal.tick.dispatch",
7241
+ goalType: goal.type,
7242
+ goalState,
7243
+ stage: decision.stage,
7244
+ evidence: decision.evidence,
7245
+ status: decision.kind,
7246
+ dispatch: {
7247
+ agentResponsibility: decision.agentResponsibility,
7248
+ agentAction: decision.agentAction,
7249
+ cliArgs: decision.cliArgs
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
7262
+ });
7263
+ return;
7264
+ }
7265
+ if (decision.kind === "done") {
7266
+ stageGoalRunLogEvent(data, goalId, {
7267
+ source: "goal-manager",
7268
+ event: "goal.tick.done",
7269
+ goalType: goal.type,
7270
+ goalState: "done",
7271
+ stage: "done",
7272
+ status: decision.kind,
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
7278
+ });
7279
+ return;
7280
+ }
7281
+ if (decision.kind === "idle") {
7282
+ stageGoalRunLogEvent(data, goalId, {
7283
+ source: "goal-manager",
7284
+ event: "goal.tick.idle",
7285
+ goalType: goal.type,
7286
+ goalState,
7287
+ stage: goal.stage,
7288
+ status: decision.kind,
7289
+ reason: decision.reason,
7290
+ goal: details.goalSnapshot,
7291
+ inspection: details.inspection,
7292
+ decision: { kind: decision.kind, reason: decision.reason },
7293
+ change: details.change
7294
+ });
7295
+ return;
7296
+ }
7297
+ stageGoalRunLogEvent(data, goalId, {
7298
+ source: "goal-manager",
7299
+ event: `goal.tick.${decision.kind}`,
7300
+ goalType: goal.type,
7301
+ goalState,
7302
+ stage: decision.stage,
7303
+ evidence: decision.evidence,
7304
+ status: decision.kind,
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
7315
+ });
7316
+ }
6921
7317
  function readSimpleGoalTaskSummary(goalId, cwd) {
6922
7318
  const raw = gh(
6923
7319
  ["issue", "list", "--state", "all", "--label", `goal:${goalId}`, "--limit", "1000", "--json", "number,state"],
@@ -6984,6 +7380,7 @@ var init_advanceManagedGoal = __esm({
6984
7380
  "src/scripts/advanceManagedGoal.ts"() {
6985
7381
  "use strict";
6986
7382
  init_manager();
7383
+ init_runLog();
6987
7384
  init_state2();
6988
7385
  init_typeDefinitions();
6989
7386
  init_issue();
@@ -7005,6 +7402,23 @@ var init_advanceManagedGoal = __esm({
7005
7402
  }
7006
7403
  const previousGoalIdFact = managed.facts.goalId;
7007
7404
  managed.facts.goalId = goal.id;
7405
+ const startSnapshot = goalRunLogSnapshot(goal.id, goal.state, managed);
7406
+ stageGoalRunLogEvent(ctx.data, goal.id, {
7407
+ source: "goal-manager",
7408
+ event: "goal.tick.start",
7409
+ goalType: managed.type,
7410
+ goalState: goal.state,
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
+ },
7420
+ facts: managed.facts
7421
+ });
7008
7422
  const restoreGoalIdFact = () => {
7009
7423
  if (previousGoalIdFact === void 0) delete managed.facts.goalId;
7010
7424
  else managed.facts.goalId = previousGoalIdFact;
@@ -7017,10 +7431,28 @@ var init_advanceManagedGoal = __esm({
7017
7431
  if (!managed.blockers.includes(reason)) managed.blockers.push(reason);
7018
7432
  restoreGoalIdFact();
7019
7433
  goal.raw = writeManagedGoalToState({ ...goal.raw, state: goal.state }, managed);
7434
+ const blockedSnapshot = goalRunLogSnapshot(goal.id, goal.state, managed);
7435
+ stageGoalRunLogEvent(ctx.data, goal.id, {
7436
+ source: "goal-manager",
7437
+ event: "goal.tick.blocked",
7438
+ goalType: managed.type,
7439
+ goalState: goal.state,
7440
+ stage: managed.stage,
7441
+ status: "blocked",
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)
7450
+ });
7020
7451
  ctx.output.reason = reason;
7021
7452
  return;
7022
7453
  }
7023
7454
  if (isGoalTargetLoop(managed)) {
7455
+ const beforeSnapshot = goalRunLogSnapshot(goal.id, goal.state, managed);
7024
7456
  const previousScheduleState = goal.raw.extra.scheduleState && typeof goal.raw.extra.scheduleState === "object" ? goal.raw.extra.scheduleState : void 0;
7025
7457
  const decision2 = planGoalTargetLoopSchedule({ goal: managed, previousScheduleState });
7026
7458
  restoreGoalIdFact();
@@ -7034,10 +7466,41 @@ var init_advanceManagedGoal = __esm({
7034
7466
  cliArgs: decision2.dispatch.cliArgs
7035
7467
  };
7036
7468
  }
7469
+ stageGoalRunLogEvent(ctx.data, goal.id, {
7470
+ source: "goal-manager",
7471
+ event: decision2.kind === "dispatch" ? "loop.tick.dispatch" : `loop.tick.${decision2.kind}`,
7472
+ goalType: managed.type,
7473
+ goalState: goal.state,
7474
+ stage: managed.stage,
7475
+ status: decision2.kind,
7476
+ reason: decision2.reason,
7477
+ target: decision2.dispatch?.cliArgs.goal && typeof decision2.dispatch.cliArgs.goal === "string" ? { type: "goal", id: decision2.dispatch.cliArgs.goal } : managed.loopTarget,
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
+ }
7498
+ });
7037
7499
  ctx.output.reason = decision2.reason;
7038
7500
  return;
7039
7501
  }
7040
7502
  if (isAgentResponsibilityCadenceGoal(managed, goal.raw.extra)) {
7503
+ const beforeSnapshot = goalRunLogSnapshot(goal.id, goal.state, managed);
7041
7504
  const previousScheduleState = goal.raw.extra.scheduleState && typeof goal.raw.extra.scheduleState === "object" ? goal.raw.extra.scheduleState : void 0;
7042
7505
  const decision2 = await planGoalAgentResponsibilitySchedule({
7043
7506
  goal: managed,
@@ -7057,12 +7520,43 @@ var init_advanceManagedGoal = __esm({
7057
7520
  ...goal.raw.extra.saveReport === true ? { saveReport: true } : {}
7058
7521
  };
7059
7522
  }
7523
+ stageGoalRunLogEvent(ctx.data, goal.id, {
7524
+ source: "goal-manager",
7525
+ event: decision2.kind === "dispatch" ? "loop.tick.dispatch" : `loop.tick.${decision2.kind}`,
7526
+ goalType: managed.type,
7527
+ goalState: goal.state,
7528
+ stage: managed.stage,
7529
+ status: decision2.kind,
7530
+ reason: decision2.reason,
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
+ }
7550
+ });
7060
7551
  ctx.output.reason = decision2.reason;
7061
7552
  return;
7062
7553
  }
7554
+ let simpleTaskSummary;
7063
7555
  if (isSimpleGoal(managed)) {
7064
- applySimpleGoalTaskSummary(managed, readSimpleGoalTaskSummary(goal.id, ctx.cwd));
7556
+ simpleTaskSummary = readSimpleGoalTaskSummary(goal.id, ctx.cwd);
7557
+ applySimpleGoalTaskSummary(managed, simpleTaskSummary);
7065
7558
  }
7559
+ const beforeDecisionSnapshot = goalRunLogSnapshot(goal.id, goal.state, managed);
7066
7560
  const decision = planManagedGoalTick(managed);
7067
7561
  restoreGoalIdFact();
7068
7562
  ctx.data.managedGoalDecision = decision;
@@ -7070,6 +7564,19 @@ var init_advanceManagedGoal = __esm({
7070
7564
  goal.state = "done";
7071
7565
  }
7072
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
+ });
7073
7580
  if (decision.kind === "blocked" || decision.kind === "wait" || decision.kind === "idle" || decision.kind === "done") {
7074
7581
  ctx.output.reason = decision.kind === "done" ? "managed goal complete" : decision.reason;
7075
7582
  return;
@@ -7616,6 +8123,16 @@ var init_appendCompanyIntentDecision = __esm({
7616
8123
  });
7617
8124
 
7618
8125
  // src/scripts/applyAgentResponsibilityReports.ts
8126
+ function flushLogs(ctx) {
8127
+ try {
8128
+ flushGoalRunLogEvents(ctx.config, ctx.cwd, ctx.data);
8129
+ } catch (err) {
8130
+ process.stderr.write(
8131
+ `[kody agentResponsibility-report] goal log persist failed (${err instanceof Error ? err.message : String(err)})
8132
+ `
8133
+ );
8134
+ }
8135
+ }
7619
8136
  function collectReports(raw, agentResult) {
7620
8137
  const out = [];
7621
8138
  if (Array.isArray(raw)) {
@@ -7657,6 +8174,76 @@ function completeSatisfiedManagedGoal(state) {
7657
8174
  if (decision.kind !== "done") return state;
7658
8175
  return writeManagedGoalToState({ ...state, state: "done" }, managed);
7659
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
+ }
7660
8247
  function describeMessage(goalId, reports, results) {
7661
8248
  const pieces = [];
7662
8249
  if (reports && reports.length > 0) pieces.push(`report=${reports.length}`);
@@ -7670,6 +8257,7 @@ var init_applyAgentResponsibilityReports = __esm({
7670
8257
  init_agent_responsibilityReport();
7671
8258
  init_agent_responsibilityResult();
7672
8259
  init_manager();
8260
+ init_runLog();
7673
8261
  init_state2();
7674
8262
  init_stateStore();
7675
8263
  applyAgentResponsibilityReports = async (ctx, _profile, agentResult) => {
@@ -7683,22 +8271,99 @@ var init_applyAgentResponsibilityReports = __esm({
7683
8271
  for (const goalId of goalIds) {
7684
8272
  const prior = fetchGoalState(ctx.config, goalId, ctx.cwd);
7685
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);
7686
8290
  process.stderr.write(`[kody agentResponsibility-report] goal ${goalId} missing in state repo; report skipped
7687
8291
  `);
7688
8292
  continue;
7689
8293
  }
7690
8294
  let next = prior;
7691
8295
  for (const report of reportsByGoal.get(goalId) ?? []) {
8296
+ const beforeSnapshot = snapshotFromState(goalId, next);
7692
8297
  next = applyAgentResponsibilityReportToGoalState(next, report);
8298
+ const afterSnapshot = snapshotFromState(goalId, next);
8299
+ const change = goalRunLogChange(beforeSnapshot, afterSnapshot);
8300
+ const output = responsibilityReportOutput(report, afterSnapshot);
8301
+ stageGoalRunLogEvent(ctx.data, goalId, {
8302
+ source: "goal-loop",
8303
+ event: change ? "goal.evidence.applied" : "goal.evidence.unchanged",
8304
+ goalState: next.state,
8305
+ evidenceValues: report.evidence,
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
8314
+ });
7693
8315
  }
7694
8316
  if (goalId === resultGoalId) {
7695
8317
  const evidence = typeof ctx.args.evidence === "string" && ctx.args.evidence.length > 0 ? ctx.args.evidence : void 0;
7696
8318
  for (const result of results) {
8319
+ const beforeSnapshot = snapshotFromState(goalId, next);
7697
8320
  next = applyAgentResponsibilityResultToObjectiveState(next, result, evidence);
8321
+ const afterSnapshot = snapshotFromState(goalId, next);
8322
+ const change = goalRunLogChange(beforeSnapshot, afterSnapshot);
8323
+ const output = responsibilityResultOutput(result);
8324
+ stageGoalRunLogEvent(ctx.data, goalId, {
8325
+ source: "goal-loop",
8326
+ event: change ? "goal.evidence.applied" : "goal.evidence.unchanged",
8327
+ goalState: next.state,
8328
+ evidence,
8329
+ status: result.status,
8330
+ reason: result.summary,
8331
+ facts: result.facts,
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
8340
+ });
7698
8341
  }
7699
8342
  }
8343
+ const beforeCompletionSnapshot = snapshotFromState(goalId, next);
7700
8344
  next = completeSatisfiedManagedGoal(next);
7701
- if (serializeGoalState(next) === serializeGoalState(prior)) continue;
8345
+ const afterCompletionSnapshot = snapshotFromState(goalId, next);
8346
+ if (prior.state !== "done" && next.state === "done") {
8347
+ stageGoalRunLogEvent(ctx.data, goalId, {
8348
+ source: "goal-loop",
8349
+ event: "goal.decision.done",
8350
+ goalState: "done",
8351
+ status: "done",
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)
8361
+ });
8362
+ }
8363
+ if (serializeGoalState(next) === serializeGoalState(prior)) {
8364
+ flushLogs(ctx);
8365
+ continue;
8366
+ }
7702
8367
  putGoalState(
7703
8368
  ctx.config,
7704
8369
  goalId,
@@ -7706,6 +8371,7 @@ var init_applyAgentResponsibilityReports = __esm({
7706
8371
  describeMessage(goalId, reportsByGoal.get(goalId), results),
7707
8372
  ctx.cwd
7708
8373
  );
8374
+ flushLogs(ctx);
7709
8375
  }
7710
8376
  };
7711
8377
  }
@@ -7877,7 +8543,7 @@ var init_classifyByLabel = __esm({
7877
8543
  });
7878
8544
 
7879
8545
  // src/scripts/commitAndPush.ts
7880
- import * as fs26 from "fs";
8546
+ import * as fs27 from "fs";
7881
8547
  import * as path26 from "path";
7882
8548
  function sentinelPathForStage(cwd, profileName) {
7883
8549
  const runId = resolveRunId();
@@ -7899,9 +8565,9 @@ var init_commitAndPush = __esm({
7899
8565
  }
7900
8566
  const idempotencyEnabled = process.env.KODY_COMMIT_IDEMPOTENCY !== "0";
7901
8567
  const sentinel = idempotencyEnabled ? sentinelPathForStage(ctx.cwd, profile.name) : null;
7902
- if (sentinel && fs26.existsSync(sentinel)) {
8568
+ if (sentinel && fs27.existsSync(sentinel)) {
7903
8569
  try {
7904
- const replay = JSON.parse(fs26.readFileSync(sentinel, "utf-8"));
8570
+ const replay = JSON.parse(fs27.readFileSync(sentinel, "utf-8"));
7905
8571
  ctx.data.commitResult = replay.commitResult ?? { committed: false, pushed: false };
7906
8572
  if (Array.isArray(replay.changedFiles)) ctx.data.changedFiles = replay.changedFiles;
7907
8573
  if (typeof replay.hasCommitsAhead === "boolean") ctx.data.hasCommitsAhead = replay.hasCommitsAhead;
@@ -7954,8 +8620,8 @@ var init_commitAndPush = __esm({
7954
8620
  const result = ctx.data.commitResult;
7955
8621
  if (sentinel && result?.committed) {
7956
8622
  try {
7957
- fs26.mkdirSync(path26.dirname(sentinel), { recursive: true });
7958
- fs26.writeFileSync(
8623
+ fs27.mkdirSync(path26.dirname(sentinel), { recursive: true });
8624
+ fs27.writeFileSync(
7959
8625
  sentinel,
7960
8626
  JSON.stringify(
7961
8627
  {
@@ -7977,6 +8643,16 @@ var init_commitAndPush = __esm({
7977
8643
  });
7978
8644
 
7979
8645
  // src/scripts/commitGoalState.ts
8646
+ function flushLogs2(ctx) {
8647
+ try {
8648
+ flushGoalRunLogEvents(ctx.config, ctx.cwd, ctx.data);
8649
+ } catch (err) {
8650
+ process.stderr.write(
8651
+ `[goal-manager] goal log persist failed (${err instanceof Error ? err.message : String(err)})
8652
+ `
8653
+ );
8654
+ }
8655
+ }
7980
8656
  function describeCommitMessage(goal) {
7981
8657
  if (goal.state === "done") return `chore(goals): complete ${goal.id}`;
7982
8658
  return `chore(goals): update ${goal.id}`;
@@ -7985,13 +8661,23 @@ var commitGoalState;
7985
8661
  var init_commitGoalState = __esm({
7986
8662
  "src/scripts/commitGoalState.ts"() {
7987
8663
  "use strict";
8664
+ init_runLog();
7988
8665
  init_stateStore();
7989
8666
  commitGoalState = async (ctx) => {
7990
8667
  const goal = ctx.data.goal;
7991
- if (!goal) return;
7992
- if (ctx.data.goalPersistChanged !== true) return;
8668
+ if (!goal) {
8669
+ flushLogs2(ctx);
8670
+ return;
8671
+ }
8672
+ if (ctx.data.goalPersistChanged !== true) {
8673
+ flushLogs2(ctx);
8674
+ return;
8675
+ }
7993
8676
  const updated = ctx.data.goalPersistState;
7994
- if (!updated) return;
8677
+ if (!updated) {
8678
+ flushLogs2(ctx);
8679
+ return;
8680
+ }
7995
8681
  try {
7996
8682
  putGoalState(ctx.config, goal.id, updated, describeCommitMessage(goal), ctx.cwd);
7997
8683
  } catch (err) {
@@ -7999,13 +8685,15 @@ var init_commitGoalState = __esm({
7999
8685
  `[goal-manager] commitGoalState: persist to state repo failed (${err instanceof Error ? err.message : String(err)}); will retry next tick
8000
8686
  `
8001
8687
  );
8688
+ } finally {
8689
+ flushLogs2(ctx);
8002
8690
  }
8003
8691
  };
8004
8692
  }
8005
8693
  });
8006
8694
 
8007
8695
  // src/scripts/composePrompt.ts
8008
- import * as fs27 from "fs";
8696
+ import * as fs28 from "fs";
8009
8697
  import * as path27 from "path";
8010
8698
  function fenceUntrusted(value) {
8011
8699
  if (value.trim().length === 0) return value;
@@ -8145,7 +8833,7 @@ var init_composePrompt = __esm({
8145
8833
  break;
8146
8834
  }
8147
8835
  try {
8148
- template = fs27.readFileSync(c, "utf-8");
8836
+ template = fs28.readFileSync(c, "utf-8");
8149
8837
  templatePath = c;
8150
8838
  break;
8151
8839
  } catch (err) {
@@ -8156,7 +8844,7 @@ var init_composePrompt = __esm({
8156
8844
  if (!templatePath) {
8157
8845
  let dirState;
8158
8846
  try {
8159
- dirState = `dir contents: [${fs27.readdirSync(profile.dir).join(", ")}]`;
8847
+ dirState = `dir contents: [${fs28.readdirSync(profile.dir).join(", ")}]`;
8160
8848
  } catch (err) {
8161
8849
  dirState = `readdir(${profile.dir}) failed: ${err?.code ?? String(err)}`;
8162
8850
  }
@@ -8728,7 +9416,7 @@ var init_deriveQaScopeFromIssue = __esm({
8728
9416
 
8729
9417
  // src/scripts/diagMcp.ts
8730
9418
  import { execFileSync as execFileSync10 } from "child_process";
8731
- import * as fs28 from "fs";
9419
+ import * as fs29 from "fs";
8732
9420
  import * as os6 from "os";
8733
9421
  import * as path28 from "path";
8734
9422
  var diagMcp;
@@ -8740,7 +9428,7 @@ var init_diagMcp = __esm({
8740
9428
  const cacheDir = path28.join(home, ".cache", "ms-playwright");
8741
9429
  let entries = [];
8742
9430
  try {
8743
- entries = fs28.readdirSync(cacheDir);
9431
+ entries = fs29.readdirSync(cacheDir);
8744
9432
  } catch {
8745
9433
  }
8746
9434
  const hasChromium = entries.some((e) => e.startsWith("chromium"));
@@ -8768,13 +9456,13 @@ var init_diagMcp = __esm({
8768
9456
  });
8769
9457
 
8770
9458
  // src/scripts/frameworkDetectors.ts
8771
- import * as fs29 from "fs";
9459
+ import * as fs30 from "fs";
8772
9460
  import * as path29 from "path";
8773
9461
  function detectFrameworks(cwd) {
8774
9462
  const out = [];
8775
9463
  let deps = {};
8776
9464
  try {
8777
- 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"));
8778
9466
  deps = { ...pkg.dependencies, ...pkg.devDependencies };
8779
9467
  } catch {
8780
9468
  return out;
@@ -8811,7 +9499,7 @@ function detectFrameworks(cwd) {
8811
9499
  }
8812
9500
  function findFile(cwd, candidates) {
8813
9501
  for (const c of candidates) {
8814
- if (fs29.existsSync(path29.join(cwd, c))) return c;
9502
+ if (fs30.existsSync(path29.join(cwd, c))) return c;
8815
9503
  }
8816
9504
  return null;
8817
9505
  }
@@ -8819,17 +9507,17 @@ function discoverPayloadCollections(cwd) {
8819
9507
  const out = [];
8820
9508
  for (const dir of COLLECTION_DIRS) {
8821
9509
  const full = path29.join(cwd, dir);
8822
- if (!fs29.existsSync(full)) continue;
9510
+ if (!fs30.existsSync(full)) continue;
8823
9511
  let files;
8824
9512
  try {
8825
- 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"));
8826
9514
  } catch {
8827
9515
  continue;
8828
9516
  }
8829
9517
  for (const file of files) {
8830
9518
  try {
8831
9519
  const filePath = path29.join(full, file);
8832
- const content = fs29.readFileSync(filePath, "utf-8").slice(0, 1e4);
9520
+ const content = fs30.readFileSync(filePath, "utf-8").slice(0, 1e4);
8833
9521
  const slugMatch = content.match(/slug:\s*['"]([a-z0-9-]+)['"]/);
8834
9522
  if (!slugMatch) continue;
8835
9523
  const slug2 = slugMatch[1];
@@ -8857,10 +9545,10 @@ function discoverAdminComponents(cwd, collections) {
8857
9545
  const out = [];
8858
9546
  for (const dir of ADMIN_COMPONENT_DIRS) {
8859
9547
  const full = path29.join(cwd, dir);
8860
- if (!fs29.existsSync(full)) continue;
9548
+ if (!fs30.existsSync(full)) continue;
8861
9549
  let entries;
8862
9550
  try {
8863
- entries = fs29.readdirSync(full, { withFileTypes: true });
9551
+ entries = fs30.readdirSync(full, { withFileTypes: true });
8864
9552
  } catch {
8865
9553
  continue;
8866
9554
  }
@@ -8870,7 +9558,7 @@ function discoverAdminComponents(cwd, collections) {
8870
9558
  let filePath;
8871
9559
  if (entry.isDirectory()) {
8872
9560
  const indexFile = ["index.tsx", "index.ts", "index.jsx", "index.js"].find(
8873
- (f) => fs29.existsSync(path29.join(entryPath, f))
9561
+ (f) => fs30.existsSync(path29.join(entryPath, f))
8874
9562
  );
8875
9563
  if (!indexFile) continue;
8876
9564
  name = entry.name;
@@ -8885,7 +9573,7 @@ function discoverAdminComponents(cwd, collections) {
8885
9573
  if (collections) {
8886
9574
  for (const col of collections) {
8887
9575
  try {
8888
- const colContent = fs29.readFileSync(path29.join(cwd, col.filePath), "utf-8");
9576
+ const colContent = fs30.readFileSync(path29.join(cwd, col.filePath), "utf-8");
8889
9577
  if (colContent.includes(name)) {
8890
9578
  usedInCollection = col.slug;
8891
9579
  break;
@@ -8904,7 +9592,7 @@ function scanApiRoutes(cwd) {
8904
9592
  const appDirs = ["src/app", "app"];
8905
9593
  for (const appDir of appDirs) {
8906
9594
  const apiDir = path29.join(cwd, appDir, "api");
8907
- if (!fs29.existsSync(apiDir)) continue;
9595
+ if (!fs30.existsSync(apiDir)) continue;
8908
9596
  walkApiRoutes(apiDir, "/api", cwd, out);
8909
9597
  break;
8910
9598
  }
@@ -8913,14 +9601,14 @@ function scanApiRoutes(cwd) {
8913
9601
  function walkApiRoutes(dir, prefix, cwd, out) {
8914
9602
  let entries;
8915
9603
  try {
8916
- entries = fs29.readdirSync(dir, { withFileTypes: true });
9604
+ entries = fs30.readdirSync(dir, { withFileTypes: true });
8917
9605
  } catch {
8918
9606
  return;
8919
9607
  }
8920
9608
  const routeFile = entries.find((e) => e.isFile() && /^route\.(ts|js|tsx|jsx)$/.test(e.name));
8921
9609
  if (routeFile) {
8922
9610
  try {
8923
- 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);
8924
9612
  const methods = HTTP_METHODS.filter(
8925
9613
  (m) => new RegExp(`export\\s+(?:async\\s+)?function\\s+${m}\\b`).test(content)
8926
9614
  );
@@ -8954,9 +9642,9 @@ function scanEnvVars(cwd) {
8954
9642
  const candidates = [".env.example", ".env.local.example", ".env.template"];
8955
9643
  for (const envFile of candidates) {
8956
9644
  const envPath = path29.join(cwd, envFile);
8957
- if (!fs29.existsSync(envPath)) continue;
9645
+ if (!fs30.existsSync(envPath)) continue;
8958
9646
  try {
8959
- const content = fs29.readFileSync(envPath, "utf-8");
9647
+ const content = fs30.readFileSync(envPath, "utf-8");
8960
9648
  const vars = [];
8961
9649
  for (const line of content.split("\n")) {
8962
9650
  const trimmed = line.trim();
@@ -9001,7 +9689,7 @@ var init_frameworkDetectors = __esm({
9001
9689
  });
9002
9690
 
9003
9691
  // src/scripts/discoverQaContext.ts
9004
- import * as fs30 from "fs";
9692
+ import * as fs31 from "fs";
9005
9693
  import * as path30 from "path";
9006
9694
  function runQaDiscovery(cwd) {
9007
9695
  const out = {
@@ -9033,9 +9721,9 @@ function runQaDiscovery(cwd) {
9033
9721
  }
9034
9722
  function detectDevServer(cwd, out) {
9035
9723
  try {
9036
- 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"));
9037
9725
  const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
9038
- 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";
9039
9727
  if (pkg.scripts?.dev) out.devCommand = `${pm} dev`;
9040
9728
  if (allDeps.next || allDeps.nuxt) out.devPort = 3e3;
9041
9729
  else if (allDeps.vite) out.devPort = 5173;
@@ -9046,7 +9734,7 @@ function scanFrontendRoutes(cwd, out) {
9046
9734
  const appDirs = ["src/app", "app"];
9047
9735
  for (const appDir of appDirs) {
9048
9736
  const full = path30.join(cwd, appDir);
9049
- if (!fs30.existsSync(full)) continue;
9737
+ if (!fs31.existsSync(full)) continue;
9050
9738
  walkFrontendRoutes(full, "", out);
9051
9739
  break;
9052
9740
  }
@@ -9054,7 +9742,7 @@ function scanFrontendRoutes(cwd, out) {
9054
9742
  function walkFrontendRoutes(dir, prefix, out) {
9055
9743
  let entries;
9056
9744
  try {
9057
- entries = fs30.readdirSync(dir, { withFileTypes: true });
9745
+ entries = fs31.readdirSync(dir, { withFileTypes: true });
9058
9746
  } catch {
9059
9747
  return;
9060
9748
  }
@@ -9096,23 +9784,23 @@ function detectAuthFiles(cwd, out) {
9096
9784
  "src/app/api/oauth"
9097
9785
  ];
9098
9786
  for (const c of candidates) {
9099
- if (fs30.existsSync(path30.join(cwd, c))) out.authFiles.push(c);
9787
+ if (fs31.existsSync(path30.join(cwd, c))) out.authFiles.push(c);
9100
9788
  }
9101
9789
  }
9102
9790
  function detectRoles(cwd, out) {
9103
9791
  const rolePaths = ["src/types", "src/lib", "src/utils", "src/constants", "src/access", "src/collections"];
9104
9792
  for (const rp of rolePaths) {
9105
9793
  const dir = path30.join(cwd, rp);
9106
- if (!fs30.existsSync(dir)) continue;
9794
+ if (!fs31.existsSync(dir)) continue;
9107
9795
  let files;
9108
9796
  try {
9109
- 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"));
9110
9798
  } catch {
9111
9799
  continue;
9112
9800
  }
9113
9801
  for (const f of files) {
9114
9802
  try {
9115
- 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);
9116
9804
  const roleMatches = content.match(/(?:role|Role|ROLE)\s*[=:]\s*['"](\w+)['"]/g);
9117
9805
  if (roleMatches) {
9118
9806
  for (const m of roleMatches) {
@@ -10326,12 +11014,12 @@ var init_fixFlow = __esm({
10326
11014
 
10327
11015
  // src/scripts/initFlow.ts
10328
11016
  import { execFileSync as execFileSync15 } from "child_process";
10329
- import * as fs31 from "fs";
11017
+ import * as fs32 from "fs";
10330
11018
  import * as path31 from "path";
10331
11019
  function detectPackageManager(cwd) {
10332
- if (fs31.existsSync(path31.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
10333
- if (fs31.existsSync(path31.join(cwd, "yarn.lock"))) return "yarn";
10334
- 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";
10335
11023
  return "npm";
10336
11024
  }
10337
11025
  function qualityCommandsFor(pm) {
@@ -10404,21 +11092,21 @@ function performInit(cwd, force) {
10404
11092
  const ownerRepo = detectOwnerRepo(cwd);
10405
11093
  const defaultBranch = defaultBranchFromGit(cwd);
10406
11094
  const configPath = path31.join(cwd, "kody.config.json");
10407
- if (fs31.existsSync(configPath) && !force) {
11095
+ if (fs32.existsSync(configPath) && !force) {
10408
11096
  skipped.push("kody.config.json");
10409
11097
  } else {
10410
11098
  const cfg = makeConfig(pm, ownerRepo, defaultBranch);
10411
- fs31.writeFileSync(configPath, `${JSON.stringify(cfg, null, 2)}
11099
+ fs32.writeFileSync(configPath, `${JSON.stringify(cfg, null, 2)}
10412
11100
  `);
10413
11101
  wrote.push("kody.config.json");
10414
11102
  }
10415
11103
  const workflowDir = path31.join(cwd, ".github", "workflows");
10416
11104
  const workflowPath = path31.join(workflowDir, "kody.yml");
10417
- if (fs31.existsSync(workflowPath) && !force) {
11105
+ if (fs32.existsSync(workflowPath) && !force) {
10418
11106
  skipped.push(".github/workflows/kody.yml");
10419
11107
  } else {
10420
- fs31.mkdirSync(workflowDir, { recursive: true });
10421
- fs31.writeFileSync(workflowPath, WORKFLOW_TEMPLATE);
11108
+ fs32.mkdirSync(workflowDir, { recursive: true });
11109
+ fs32.writeFileSync(workflowPath, WORKFLOW_TEMPLATE);
10422
11110
  wrote.push(".github/workflows/kody.yml");
10423
11111
  }
10424
11112
  for (const exe of listAgentActions()) {
@@ -10430,11 +11118,11 @@ function performInit(cwd, force) {
10430
11118
  }
10431
11119
  if (profile.kind !== "scheduled" || !profile.schedule) continue;
10432
11120
  const target = path31.join(workflowDir, `kody-${exe.name}.yml`);
10433
- if (fs31.existsSync(target) && !force) {
11121
+ if (fs32.existsSync(target) && !force) {
10434
11122
  skipped.push(`.github/workflows/kody-${exe.name}.yml`);
10435
11123
  continue;
10436
11124
  }
10437
- fs31.writeFileSync(target, renderScheduledWorkflow(exe.name, profile.schedule));
11125
+ fs32.writeFileSync(target, renderScheduledWorkflow(exe.name, profile.schedule));
10438
11126
  wrote.push(`.github/workflows/kody-${exe.name}.yml`);
10439
11127
  }
10440
11128
  let labels;
@@ -10587,7 +11275,7 @@ Nothing to do. All files already present. (Use --force to overwrite.)
10587
11275
  });
10588
11276
 
10589
11277
  // src/scripts/loadAgentAdhoc.ts
10590
- import * as fs32 from "fs";
11278
+ import * as fs33 from "fs";
10591
11279
  function resolveMessage(messageArg) {
10592
11280
  const fromComment = readCommentBody();
10593
11281
  if (fromComment) return stripDirective(fromComment);
@@ -10595,9 +11283,9 @@ function resolveMessage(messageArg) {
10595
11283
  }
10596
11284
  function readCommentBody() {
10597
11285
  const eventPath = process.env.GITHUB_EVENT_PATH;
10598
- if (!eventPath || !fs32.existsSync(eventPath)) return "";
11286
+ if (!eventPath || !fs33.existsSync(eventPath)) return "";
10599
11287
  try {
10600
- const event = JSON.parse(fs32.readFileSync(eventPath, "utf-8"));
11288
+ const event = JSON.parse(fs33.readFileSync(eventPath, "utf-8"));
10601
11289
  return String(event.comment?.body ?? "");
10602
11290
  } catch {
10603
11291
  return "";
@@ -10650,10 +11338,10 @@ var init_loadAgentAdhoc = __esm({
10650
11338
  throw new Error("loadAgentAdhoc: ctx.args.agent must be a non-empty slug");
10651
11339
  }
10652
11340
  const agentPath = resolveAgentFile(ctx.cwd, agentSlug, agentsDir);
10653
- if (!fs32.existsSync(agentPath)) {
11341
+ if (!fs33.existsSync(agentPath)) {
10654
11342
  throw new Error(`loadAgentAdhoc: agent identity not found: ${agentPath}`);
10655
11343
  }
10656
- const { title, body } = parseAgentFile(fs32.readFileSync(agentPath, "utf-8"), agentSlug);
11344
+ const { title, body } = parseAgentFile(fs33.readFileSync(agentPath, "utf-8"), agentSlug);
10657
11345
  const message = resolveMessage(ctx.args.message);
10658
11346
  if (!message) {
10659
11347
  throw new Error(
@@ -10891,7 +11579,7 @@ var init_loadIssueStateComment = __esm({
10891
11579
  });
10892
11580
 
10893
11581
  // src/scripts/loadJobFromFile.ts
10894
- import * as fs33 from "fs";
11582
+ import * as fs34 from "fs";
10895
11583
  import * as path32 from "path";
10896
11584
  function parseJobFile(raw, slug2) {
10897
11585
  let stripped = raw;
@@ -10943,12 +11631,12 @@ var init_loadJobFromFile = __esm({
10943
11631
  let agentIdentity = "";
10944
11632
  if (agentSlug) {
10945
11633
  const agentPath = resolveAgentFile(ctx.cwd, agentSlug, agentsDir);
10946
- if (!fs33.existsSync(agentPath)) {
11634
+ if (!fs34.existsSync(agentPath)) {
10947
11635
  throw new Error(
10948
11636
  `loadJobFromFile: agentResponsibility '${slug2}' declares agent '${agentSlug}' but ${agentPath} does not exist`
10949
11637
  );
10950
11638
  }
10951
- const agentRaw = fs33.readFileSync(agentPath, "utf-8");
11639
+ const agentRaw = fs34.readFileSync(agentPath, "utf-8");
10952
11640
  const parsed = parseJobFile(agentRaw, agentSlug);
10953
11641
  agentTitle = parsed.title;
10954
11642
  agentIdentity = parsed.body;
@@ -11022,13 +11710,13 @@ ${truncate(issue.body, FINDING_BODY_MAX_BYTES)}`;
11022
11710
  });
11023
11711
 
11024
11712
  // src/scripts/kodyVariables.ts
11025
- import * as fs34 from "fs";
11713
+ import * as fs35 from "fs";
11026
11714
  import * as path33 from "path";
11027
11715
  function readKodyVariables(cwd) {
11028
11716
  const full = path33.join(cwd, KODY_VARIABLES_REL_PATH);
11029
11717
  let raw;
11030
11718
  try {
11031
- raw = fs34.readFileSync(full, "utf-8");
11719
+ raw = fs35.readFileSync(full, "utf-8");
11032
11720
  } catch {
11033
11721
  return {};
11034
11722
  }
@@ -11053,7 +11741,7 @@ var init_kodyVariables = __esm({
11053
11741
  });
11054
11742
 
11055
11743
  // src/scripts/loadQaContext.ts
11056
- import * as fs35 from "fs";
11744
+ import * as fs36 from "fs";
11057
11745
  import * as path34 from "path";
11058
11746
  function parseSlugList(value) {
11059
11747
  const inner = value.startsWith("[") && value.endsWith("]") ? value.slice(1, -1) : value;
@@ -11084,17 +11772,17 @@ function readProfileAgents(raw) {
11084
11772
  }
11085
11773
  function readProfile(cwd) {
11086
11774
  const dir = path34.join(cwd, CONTEXT_DIR_REL_PATH);
11087
- if (!fs35.existsSync(dir)) return "";
11775
+ if (!fs36.existsSync(dir)) return "";
11088
11776
  let entries;
11089
11777
  try {
11090
- entries = fs35.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
11778
+ entries = fs36.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
11091
11779
  } catch {
11092
11780
  return "";
11093
11781
  }
11094
11782
  const blocks = [];
11095
11783
  for (const file of entries) {
11096
11784
  try {
11097
- const raw = fs35.readFileSync(path34.join(dir, file), "utf-8");
11785
+ const raw = fs36.readFileSync(path34.join(dir, file), "utf-8");
11098
11786
  const { agent, body } = readProfileAgents(raw);
11099
11787
  if (!agent.includes(QA_AGENT) && !agent.includes(ALL_AGENTS)) continue;
11100
11788
  blocks.push(`## ${file}
@@ -11140,7 +11828,7 @@ var init_loadQaContext = __esm({
11140
11828
  });
11141
11829
 
11142
11830
  // src/taskContext.ts
11143
- import * as fs36 from "fs";
11831
+ import * as fs37 from "fs";
11144
11832
  import * as path35 from "path";
11145
11833
  function buildTaskContext(args) {
11146
11834
  return {
@@ -11157,9 +11845,9 @@ function buildTaskContext(args) {
11157
11845
  function persistTaskContext(cwd, ctx) {
11158
11846
  try {
11159
11847
  const dir = runtimeStatePath(cwd, "agent-runs", ctx.runId);
11160
- fs36.mkdirSync(dir, { recursive: true });
11848
+ fs37.mkdirSync(dir, { recursive: true });
11161
11849
  const file = path35.join(dir, "task-context.json");
11162
- fs36.writeFileSync(file, `${JSON.stringify(ctx, null, 2)}
11850
+ fs37.writeFileSync(file, `${JSON.stringify(ctx, null, 2)}
11163
11851
  `);
11164
11852
  return file;
11165
11853
  } catch (err) {
@@ -13504,9 +14192,9 @@ fi
13504
14192
  });
13505
14193
 
13506
14194
  // src/stateRepoGithub.ts
13507
- import * as fs37 from "fs";
14195
+ import * as fs38 from "fs";
13508
14196
  import * as path36 from "path";
13509
- function recordValue2(value) {
14197
+ function recordValue3(value) {
13510
14198
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
13511
14199
  }
13512
14200
  function contentsUrl(owner, repo, filePath) {
@@ -13562,12 +14250,12 @@ async function loadGithubStateConfig(opts) {
13562
14250
  throw new Error(`kody.config.json is invalid JSON: ${err instanceof Error ? err.message : String(err)}`);
13563
14251
  }
13564
14252
  }
13565
- const githubRaw = recordValue2(raw.github) ?? {};
14253
+ const githubRaw = recordValue3(raw.github) ?? {};
13566
14254
  const github = {
13567
14255
  owner: typeof githubRaw.owner === "string" && githubRaw.owner.trim() ? githubRaw.owner.trim() : opts.owner,
13568
14256
  repo: typeof githubRaw.repo === "string" && githubRaw.repo.trim() ? githubRaw.repo.trim() : opts.repo
13569
14257
  };
13570
- const nestedState = recordValue2(raw.state) ?? {};
14258
+ const nestedState = recordValue3(raw.state) ?? {};
13571
14259
  const repoRaw = typeof raw.stateRepo === "string" ? raw.stateRepo : nestedState.repo;
13572
14260
  const pathRaw = typeof raw.statePath === "string" ? raw.statePath : nestedState.path;
13573
14261
  const stateRepo = typeof repoRaw === "string" && repoRaw.trim().length > 0 ? repoRaw.trim() : `https://github.com/${github.owner}/kody-state`;
@@ -13645,15 +14333,15 @@ function mergeJsonl(localText, remoteText) {
13645
14333
  async function syncJsonlFileFromGithubState(opts) {
13646
14334
  const remote = await readGithubStateTextWithConfig(opts);
13647
14335
  if (!remote) return;
13648
- 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") : "";
13649
14337
  const next = mergeJsonl(local, remote.content);
13650
14338
  if (next === local) return;
13651
- fs37.mkdirSync(path36.dirname(opts.localPath), { recursive: true });
13652
- fs37.writeFileSync(opts.localPath, next);
14339
+ fs38.mkdirSync(path36.dirname(opts.localPath), { recursive: true });
14340
+ fs38.writeFileSync(opts.localPath, next);
13653
14341
  }
13654
14342
  async function persistJsonlFileToGithubState(opts) {
13655
- if (!fs37.existsSync(opts.localPath)) return;
13656
- const localText = fs37.readFileSync(opts.localPath, "utf-8");
14343
+ if (!fs38.existsSync(opts.localPath)) return;
14344
+ const localText = fs38.readFileSync(opts.localPath, "utf-8");
13657
14345
  for (let attempt = 1; attempt <= 3; attempt += 1) {
13658
14346
  const remote = await readGithubStateTextWithConfig(opts);
13659
14347
  const body = mergeJsonl(localText, remote?.content ?? "");
@@ -14130,7 +14818,7 @@ var init_tickShellRunner = __esm({
14130
14818
  });
14131
14819
 
14132
14820
  // src/scripts/runScheduledAgentActionTick.ts
14133
- import * as fs38 from "fs";
14821
+ import * as fs39 from "fs";
14134
14822
  import * as path38 from "path";
14135
14823
  var runScheduledAgentActionTick;
14136
14824
  var init_runScheduledAgentActionTick = __esm({
@@ -14158,7 +14846,7 @@ var init_runScheduledAgentActionTick = __esm({
14158
14846
  return;
14159
14847
  }
14160
14848
  const shellPath = path38.join(profile.dir, shell);
14161
- if (!fs38.existsSync(shellPath)) {
14849
+ if (!fs39.existsSync(shellPath)) {
14162
14850
  ctx.output.exitCode = 99;
14163
14851
  ctx.output.reason = `runScheduledAgentActionTick: shell not found: ${shell} (looked in ${profile.dir})`;
14164
14852
  return;
@@ -14189,7 +14877,7 @@ var init_runScheduledAgentActionTick = __esm({
14189
14877
  });
14190
14878
 
14191
14879
  // src/scripts/runTickScript.ts
14192
- import * as fs39 from "fs";
14880
+ import * as fs40 from "fs";
14193
14881
  import * as path39 from "path";
14194
14882
  var runTickScript;
14195
14883
  var init_runTickScript = __esm({
@@ -14222,7 +14910,7 @@ var init_runTickScript = __esm({
14222
14910
  return;
14223
14911
  }
14224
14912
  const scriptPath = path39.isAbsolute(tickScript) ? tickScript : path39.join(ctx.cwd, tickScript);
14225
- if (!fs39.existsSync(scriptPath)) {
14913
+ if (!fs40.existsSync(scriptPath)) {
14226
14914
  ctx.output.exitCode = 99;
14227
14915
  ctx.output.reason = `runTickScript: tickScript not found: ${scriptPath}`;
14228
14916
  return;
@@ -15044,7 +15732,7 @@ var init_warmupMcp = __esm({
15044
15732
  });
15045
15733
 
15046
15734
  // src/scripts/writeAgentRunSummary.ts
15047
- import * as fs40 from "fs";
15735
+ import * as fs41 from "fs";
15048
15736
  var writeAgentRunSummary;
15049
15737
  var init_writeAgentRunSummary = __esm({
15050
15738
  "src/scripts/writeAgentRunSummary.ts"() {
@@ -15070,7 +15758,7 @@ var init_writeAgentRunSummary = __esm({
15070
15758
  if (reason) lines.push(`- **Reason:** ${reason}`);
15071
15759
  lines.push("");
15072
15760
  try {
15073
- fs40.appendFileSync(summaryPath, `${lines.join("\n")}
15761
+ fs41.appendFileSync(summaryPath, `${lines.join("\n")}
15074
15762
  `);
15075
15763
  } catch {
15076
15764
  }
@@ -15472,17 +16160,17 @@ var init_scripts = __esm({
15472
16160
  });
15473
16161
 
15474
16162
  // src/stateWorkspace.ts
15475
- import * as fs41 from "fs";
16163
+ import * as fs42 from "fs";
15476
16164
  import * as path40 from "path";
15477
16165
  function writeLocalFile(cwd, relativePath, content) {
15478
16166
  const fullPath = path40.join(cwd, relativePath);
15479
- fs41.mkdirSync(path40.dirname(fullPath), { recursive: true });
15480
- fs41.writeFileSync(fullPath, content);
16167
+ fs42.mkdirSync(path40.dirname(fullPath), { recursive: true });
16168
+ fs42.writeFileSync(fullPath, content);
15481
16169
  }
15482
16170
  function hydrateDirectory(config, cwd, stateDir, localDir) {
15483
16171
  const entries = listStateDirectory(config, cwd, stateDir);
15484
16172
  if (entries.length === 0) return;
15485
- fs41.rmSync(path40.join(cwd, localDir), { recursive: true, force: true });
16173
+ fs42.rmSync(path40.join(cwd, localDir), { recursive: true, force: true });
15486
16174
  for (const entry of entries) {
15487
16175
  if (!entry.name || !entry.type) continue;
15488
16176
  const childState = path40.posix.join(stateDir, entry.name);
@@ -15590,7 +16278,7 @@ var init_tools = __esm({
15590
16278
 
15591
16279
  // src/executor.ts
15592
16280
  import { spawn as spawn7 } from "child_process";
15593
- import * as fs42 from "fs";
16281
+ import * as fs43 from "fs";
15594
16282
  import * as path41 from "path";
15595
16283
  function isMutatingPostflight(scriptName) {
15596
16284
  return MUTATING_POSTFLIGHTS.has(scriptName ?? "");
@@ -16167,7 +16855,7 @@ function resolveProfilePath(profileName) {
16167
16855
  // fallback
16168
16856
  ];
16169
16857
  for (const c of candidates) {
16170
- if (fs42.existsSync(c)) return c;
16858
+ if (fs43.existsSync(c)) return c;
16171
16859
  }
16172
16860
  return candidates[0];
16173
16861
  }
@@ -16266,7 +16954,7 @@ function resolveShellTimeoutMs(entry) {
16266
16954
  async function runShellEntry(entry, ctx, profile) {
16267
16955
  const shellName = entry.shell;
16268
16956
  const shellPath = path41.join(profile.dir, shellName);
16269
- if (!fs42.existsSync(shellPath)) {
16957
+ if (!fs43.existsSync(shellPath)) {
16270
16958
  ctx.skipAgent = true;
16271
16959
  ctx.output.exitCode = 99;
16272
16960
  ctx.output.reason = `shell script not found: ${shellName} (looked in ${profile.dir})`;
@@ -16678,7 +17366,7 @@ function translateOpenAISseToBrain(opts) {
16678
17366
  }
16679
17367
 
16680
17368
  // src/servers/brain-serve.ts
16681
- import * as fs45 from "fs";
17369
+ import * as fs46 from "fs";
16682
17370
  import { createServer } from "http";
16683
17371
  import * as path45 from "path";
16684
17372
 
@@ -17240,7 +17928,7 @@ init_config();
17240
17928
 
17241
17929
  // src/kody-cli.ts
17242
17930
  import { execFileSync as execFileSync25 } from "child_process";
17243
- import * as fs43 from "fs";
17931
+ import * as fs44 from "fs";
17244
17932
  import * as path43 from "path";
17245
17933
 
17246
17934
  // src/app-auth.ts
@@ -17862,9 +18550,9 @@ async function resolveAuthToken(env = process.env) {
17862
18550
  return void 0;
17863
18551
  }
17864
18552
  function detectPackageManager2(cwd) {
17865
- if (fs43.existsSync(path43.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
17866
- if (fs43.existsSync(path43.join(cwd, "yarn.lock"))) return "yarn";
17867
- 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";
17868
18556
  return "npm";
17869
18557
  }
17870
18558
  function shouldChainScheduledWatch(match) {
@@ -17957,8 +18645,8 @@ function postFailureTail(issueNumber, cwd, reason) {
17957
18645
  const logPath = lastRunLogPath(cwd);
17958
18646
  let tail = "";
17959
18647
  try {
17960
- if (fs43.existsSync(logPath)) {
17961
- const content = fs43.readFileSync(logPath, "utf-8");
18648
+ if (fs44.existsSync(logPath)) {
18649
+ const content = fs44.readFileSync(logPath, "utf-8");
17962
18650
  tail = content.slice(-3e3);
17963
18651
  }
17964
18652
  } catch {
@@ -17998,9 +18686,9 @@ async function runCi(argv) {
17998
18686
  let manualWorkflowDispatch = false;
17999
18687
  let forceRunAction = null;
18000
18688
  let forceRunCliArgs = {};
18001
- if (!args.issueNumber && !autoFallback && eventName === "workflow_dispatch" && dispatchEventPath && fs43.existsSync(dispatchEventPath)) {
18689
+ if (!args.issueNumber && !autoFallback && eventName === "workflow_dispatch" && dispatchEventPath && fs44.existsSync(dispatchEventPath)) {
18002
18690
  try {
18003
- const evt = JSON.parse(fs43.readFileSync(dispatchEventPath, "utf-8"));
18691
+ const evt = JSON.parse(fs44.readFileSync(dispatchEventPath, "utf-8"));
18004
18692
  const issueInput = parseInt(String(evt?.inputs?.issue_number ?? ""), 10);
18005
18693
  const sessionInput = String(evt?.inputs?.sessionId ?? "");
18006
18694
  const dutyInput = String(evt?.inputs?.agentResponsibility ?? evt?.inputs?.agentAction ?? "").trim();
@@ -18332,7 +19020,7 @@ init_repoWorkspace();
18332
19020
 
18333
19021
  // src/scripts/brainTurnLog.ts
18334
19022
  init_runtimePaths();
18335
- import * as fs44 from "fs";
19023
+ import * as fs45 from "fs";
18336
19024
  import * as path44 from "path";
18337
19025
  import posixPath4 from "path/posix";
18338
19026
  var live = /* @__PURE__ */ new Map();
@@ -18344,8 +19032,8 @@ function brainEventsStatePath(chatId) {
18344
19032
  }
18345
19033
  function lastPersistedSeq(dir, chatId) {
18346
19034
  const p = brainEventsFilePath(dir, chatId);
18347
- if (!fs44.existsSync(p)) return 0;
18348
- 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);
18349
19037
  if (lines.length === 0) return 0;
18350
19038
  try {
18351
19039
  return JSON.parse(lines[lines.length - 1]).seq || 0;
@@ -18355,9 +19043,9 @@ function lastPersistedSeq(dir, chatId) {
18355
19043
  }
18356
19044
  function readSince(dir, chatId, since) {
18357
19045
  const p = brainEventsFilePath(dir, chatId);
18358
- if (!fs44.existsSync(p)) return [];
19046
+ if (!fs45.existsSync(p)) return [];
18359
19047
  const out = [];
18360
- for (const line of fs44.readFileSync(p, "utf-8").split("\n")) {
19048
+ for (const line of fs45.readFileSync(p, "utf-8").split("\n")) {
18361
19049
  if (!line) continue;
18362
19050
  try {
18363
19051
  const rec = JSON.parse(line);
@@ -18383,12 +19071,12 @@ function beginTurn(dir, chatId) {
18383
19071
  };
18384
19072
  live.set(chatId, state);
18385
19073
  const p = brainEventsFilePath(dir, chatId);
18386
- fs44.mkdirSync(path44.dirname(p), { recursive: true });
19074
+ fs45.mkdirSync(path44.dirname(p), { recursive: true });
18387
19075
  return (event) => {
18388
19076
  state.seq += 1;
18389
19077
  const rec = { seq: state.seq, turn, ts: Date.now(), event };
18390
19078
  try {
18391
- fs44.appendFileSync(p, `${JSON.stringify(rec)}
19079
+ fs45.appendFileSync(p, `${JSON.stringify(rec)}
18392
19080
  `);
18393
19081
  } catch (err) {
18394
19082
  process.stderr.write(
@@ -18427,7 +19115,7 @@ function endTurnIfUnterminated(dir, chatId, errMessage) {
18427
19115
  event: { type: "error", error: errMessage || "turn ended unexpectedly", chatId }
18428
19116
  };
18429
19117
  try {
18430
- fs44.appendFileSync(brainEventsFilePath(dir, chatId), `${JSON.stringify(rec)}
19118
+ fs45.appendFileSync(brainEventsFilePath(dir, chatId), `${JSON.stringify(rec)}
18431
19119
  `);
18432
19120
  } catch {
18433
19121
  }
@@ -18733,7 +19421,7 @@ async function handleChatTurn(req, res, chatId, opts) {
18733
19421
  );
18734
19422
  }
18735
19423
  }
18736
- fs45.mkdirSync(path45.dirname(sessionFile), { recursive: true });
19424
+ fs46.mkdirSync(path45.dirname(sessionFile), { recursive: true });
18737
19425
  appendTurn(sessionFile, {
18738
19426
  role: "user",
18739
19427
  content: message,
@@ -19393,7 +20081,7 @@ async function loadConfigSafe() {
19393
20081
  }
19394
20082
 
19395
20083
  // src/chat-cli.ts
19396
- import * as fs47 from "fs";
20084
+ import * as fs48 from "fs";
19397
20085
  import * as path47 from "path";
19398
20086
 
19399
20087
  // src/chat/inbox.ts
@@ -19466,7 +20154,7 @@ function currentBranch(cwd) {
19466
20154
 
19467
20155
  // src/chat/state-sync.ts
19468
20156
  init_stateRepo();
19469
- import * as fs46 from "fs";
20157
+ import * as fs47 from "fs";
19470
20158
  import * as path46 from "path";
19471
20159
  function jsonlLines2(text) {
19472
20160
  return text.split("\n").filter((line) => line.length > 0);
@@ -19484,15 +20172,15 @@ function mergeJsonl2(localText, remoteText) {
19484
20172
  function syncJsonlFileFromState(opts) {
19485
20173
  const remote = readStateText(opts.config, opts.cwd, opts.statePath);
19486
20174
  if (!remote) return;
19487
- 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") : "";
19488
20176
  const next = mergeJsonl2(local, remote.content);
19489
20177
  if (next === local) return;
19490
- fs46.mkdirSync(path46.dirname(opts.localPath), { recursive: true });
19491
- fs46.writeFileSync(opts.localPath, next);
20178
+ fs47.mkdirSync(path46.dirname(opts.localPath), { recursive: true });
20179
+ fs47.writeFileSync(opts.localPath, next);
19492
20180
  }
19493
20181
  function persistJsonlFileToState(opts) {
19494
- if (!fs46.existsSync(opts.localPath)) return;
19495
- const localText = fs46.readFileSync(opts.localPath, "utf-8");
20182
+ if (!fs47.existsSync(opts.localPath)) return;
20183
+ const localText = fs47.readFileSync(opts.localPath, "utf-8");
19496
20184
  for (let attempt = 1; attempt <= 3; attempt += 1) {
19497
20185
  const remote = readStateText(opts.config, opts.cwd, opts.statePath);
19498
20186
  const body = mergeJsonl2(localText, remote?.content ?? "");
@@ -19813,7 +20501,7 @@ ${CHAT_HELP}`);
19813
20501
  const sink = buildSink(cwd, sessionId, args.dashboardUrl);
19814
20502
  const meta = readMeta(sessionFile);
19815
20503
  process.stdout.write(
19816
- `\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"}
19817
20505
  `
19818
20506
  );
19819
20507
  try {
@@ -20700,7 +21388,7 @@ async function poolServe() {
20700
21388
 
20701
21389
  // src/servers/runner-serve.ts
20702
21390
  import { spawn as spawn8 } from "child_process";
20703
- import * as fs48 from "fs";
21391
+ import * as fs49 from "fs";
20704
21392
  import { createServer as createServer5 } from "http";
20705
21393
  var DEFAULT_PORT2 = 8080;
20706
21394
  var DEFAULT_WORKDIR = "/workspace/repo";
@@ -20780,8 +21468,8 @@ async function defaultRunJob(job) {
20780
21468
  const workdir = process.env.RUNNER_WORKDIR ?? DEFAULT_WORKDIR;
20781
21469
  const branch = job.ref ?? "main";
20782
21470
  const authUrl = `https://x-access-token:${job.githubToken}@github.com/${job.repo}.git`;
20783
- fs48.rmSync(workdir, { recursive: true, force: true });
20784
- fs48.mkdirSync(workdir, { recursive: true });
21471
+ fs49.rmSync(workdir, { recursive: true, force: true });
21472
+ fs49.mkdirSync(workdir, { recursive: true });
20785
21473
  const allSecrets = typeof job.allSecrets === "string" ? job.allSecrets : JSON.stringify(job.allSecrets ?? {});
20786
21474
  const interactive = job.mode === "interactive";
20787
21475
  const scheduled = job.mode === "scheduled";