@kernlang/agon 0.1.5 → 0.1.7

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 (56) hide show
  1. package/dist/{chunk-SOUF7XTW.js → chunk-45YTXJWJ.js} +3 -2
  2. package/dist/chunk-45YTXJWJ.js.map +1 -0
  3. package/dist/{chunk-GPYWJO2Q.js → chunk-6WWOJXG4.js} +108 -50
  4. package/dist/chunk-6WWOJXG4.js.map +1 -0
  5. package/dist/{chunk-4NTH3EAR.js → chunk-AONHRJRW.js} +240 -27
  6. package/dist/chunk-AONHRJRW.js.map +1 -0
  7. package/dist/{chunk-HAJIKZGU.js → chunk-BPKY4OF2.js} +479 -68
  8. package/dist/chunk-BPKY4OF2.js.map +1 -0
  9. package/dist/{chunk-DGTU4UWQ.js → chunk-I2PMSXJ3.js} +2 -2
  10. package/dist/chunk-I2PMSXJ3.js.map +1 -0
  11. package/dist/{chunk-46WNYE4R.js → chunk-RKXVKX25.js} +69 -35
  12. package/dist/chunk-RKXVKX25.js.map +1 -0
  13. package/dist/{chunk-HSPQEDHX.js → chunk-SUT2HDOY.js} +1 -1
  14. package/dist/chunk-SUT2HDOY.js.map +1 -0
  15. package/dist/{chunk-73ETZFDH.js → chunk-WDT5NJOA.js} +4 -4
  16. package/dist/chunk-WDT5NJOA.js.map +1 -0
  17. package/dist/{dispatch-XHLJ44TF.js → dispatch-J4RSWLXM.js} +2 -2
  18. package/dist/dispatch-J4RSWLXM.js.map +1 -0
  19. package/dist/engines/codex.json +3 -0
  20. package/dist/{forge-ZI7NE73F.js → forge-O2SJ5JIQ.js} +6 -6
  21. package/dist/forge-O2SJ5JIQ.js.map +1 -0
  22. package/dist/index.js +396 -60
  23. package/dist/index.js.map +1 -1
  24. package/dist/mcp/engines/agy.json +43 -0
  25. package/dist/mcp/engines/aider.json +40 -0
  26. package/dist/mcp/engines/claude.json +79 -0
  27. package/dist/mcp/engines/codex.json +77 -0
  28. package/dist/mcp/engines/minimax-coding-plan-minimax-m3.json +27 -0
  29. package/dist/mcp/engines/mistral.json +44 -0
  30. package/dist/mcp/engines/ollama.json +35 -0
  31. package/dist/mcp/engines/opencode.json +55 -0
  32. package/dist/mcp/engines/openrouter.json +54 -0
  33. package/dist/mcp/engines/qwen.json +40 -0
  34. package/dist/mcp/index.js +464 -0
  35. package/dist/mcp/index.js.map +1 -0
  36. package/dist/plan-mode-PFLUPGSY.js +17 -0
  37. package/dist/plan-mode-PFLUPGSY.js.map +1 -0
  38. package/dist/{src-4A5FVACG.js → src-253BUXEF.js} +11 -3
  39. package/dist/src-253BUXEF.js.map +1 -0
  40. package/dist/{update-DLPMYTF3.js → update-ODAAXWOD.js} +6 -6
  41. package/dist/update-ODAAXWOD.js.map +1 -0
  42. package/package.json +2 -2
  43. package/dist/chunk-46WNYE4R.js.map +0 -1
  44. package/dist/chunk-4NTH3EAR.js.map +0 -1
  45. package/dist/chunk-73ETZFDH.js.map +0 -1
  46. package/dist/chunk-DGTU4UWQ.js.map +0 -1
  47. package/dist/chunk-GPYWJO2Q.js.map +0 -1
  48. package/dist/chunk-HAJIKZGU.js.map +0 -1
  49. package/dist/chunk-HSPQEDHX.js.map +0 -1
  50. package/dist/chunk-SOUF7XTW.js.map +0 -1
  51. package/dist/dispatch-XHLJ44TF.js.map +0 -1
  52. package/dist/forge-ZI7NE73F.js.map +0 -1
  53. package/dist/plan-mode-KIXDKD63.js +0 -17
  54. package/dist/plan-mode-KIXDKD63.js.map +0 -1
  55. package/dist/src-4A5FVACG.js.map +0 -1
  56. package/dist/update-DLPMYTF3.js.map +0 -1
@@ -5,7 +5,7 @@ import {
5
5
  __require,
6
6
  __toCommonJS,
7
7
  apiStreamDispatchWithHistory
8
- } from "./chunk-SOUF7XTW.js";
8
+ } from "./chunk-45YTXJWJ.js";
9
9
 
10
10
  // ../core/src/generated/signals/glicko.ts
11
11
  var glicko_exports = {};
@@ -387,6 +387,7 @@ var DEFAULT_AGON_CONFIG = {
387
387
  isolationMigrationNotified: false,
388
388
  terminalMode: "native",
389
389
  iconTheme: "roman",
390
+ narrationFold: "safe",
390
391
  autoReviewAfterForge: true,
391
392
  autoReviewAfterImpl: true,
392
393
  buddyTimeout: 420,
@@ -1108,10 +1109,61 @@ function hydrateWorktreeBuildArtifacts(repoDir, worktreePath) {
1108
1109
  console.warn(`[agon] worktree artifact hydration failed for ${worktreePath}: ${err instanceof Error ? err.message : String(err)}`);
1109
1110
  }
1110
1111
  }
1112
+ var activeWorktrees = (() => {
1113
+ const g = globalThis;
1114
+ if (!g.__agonActiveWorktrees) {
1115
+ g.__agonActiveWorktrees = /* @__PURE__ */ new Map();
1116
+ }
1117
+ return g.__agonActiveWorktrees;
1118
+ })();
1119
+ function registerExitHooks() {
1120
+ const g = globalThis;
1121
+ if (g.__agonExitHooksRegistered) return;
1122
+ g.__agonExitHooksRegistered = true;
1123
+ const cleanup = () => {
1124
+ if (activeWorktrees.size === 0) return;
1125
+ process.stderr.write(`
1126
+ [agon] Cleaning up active git worktrees...
1127
+ `);
1128
+ const repoDirs = new Set(activeWorktrees.values());
1129
+ for (const [wtPath, repoDir] of activeWorktrees.entries()) {
1130
+ try {
1131
+ execFileSync("git", ["worktree", "remove", wtPath, "--force"], { cwd: repoDir, stdio: "ignore" });
1132
+ activeWorktrees.delete(wtPath);
1133
+ } catch {
1134
+ }
1135
+ }
1136
+ for (const repoDir of repoDirs) {
1137
+ try {
1138
+ execFileSync("git", ["worktree", "prune"], { cwd: repoDir, stdio: "ignore" });
1139
+ } catch {
1140
+ }
1141
+ }
1142
+ };
1143
+ process.on("exit", () => {
1144
+ cleanup();
1145
+ });
1146
+ const handleSigInt = () => {
1147
+ cleanup();
1148
+ if (process.listenerCount("SIGINT") <= 1) {
1149
+ process.exit(130);
1150
+ }
1151
+ };
1152
+ const handleSigTerm = () => {
1153
+ cleanup();
1154
+ if (process.listenerCount("SIGTERM") <= 1) {
1155
+ process.exit(143);
1156
+ }
1157
+ };
1158
+ process.on("SIGINT", handleSigInt);
1159
+ process.on("SIGTERM", handleSigTerm);
1160
+ }
1111
1161
  function worktreeCreate(repoDir, worktreePath, sha) {
1162
+ registerExitHooks();
1112
1163
  worktreePrune(repoDir);
1113
1164
  try {
1114
1165
  git(["worktree", "add", "--detach", worktreePath, sha], repoDir);
1166
+ activeWorktrees.set(worktreePath, repoDir);
1115
1167
  linkWorktreeNodeModules(repoDir, worktreePath);
1116
1168
  hydrateWorktreeBuildArtifacts(repoDir, worktreePath);
1117
1169
  return worktreePath;
@@ -1157,6 +1209,7 @@ function worktreeRemove(repoDir, worktreePath) {
1157
1209
  for (let attempt = 0; attempt < 2; attempt++) {
1158
1210
  try {
1159
1211
  git(["worktree", "remove", worktreePath, "--force"], repoDir);
1212
+ activeWorktrees.delete(worktreePath);
1160
1213
  return;
1161
1214
  } catch (err) {
1162
1215
  lastErr = err;
@@ -1223,6 +1276,23 @@ function worktreePruneAll(repoDir, olderThanMs) {
1223
1276
  } catch {
1224
1277
  }
1225
1278
  }
1279
+ function worktreePruneOrphaned(repoDir) {
1280
+ try {
1281
+ const output = git(["worktree", "list", "--porcelain"], repoDir);
1282
+ const lines = output.split("\n");
1283
+ for (const line of lines) {
1284
+ if (line.startsWith("worktree ")) {
1285
+ const wtPath = line.slice(9).trim();
1286
+ const isAgentWt = wtPath.includes(".agon/agent-worktrees") || wtPath.includes(".agon/speculate-worktrees") || wtPath.includes(".agon/runs") || wtPath.includes(".agon/goals");
1287
+ if (isAgentWt) {
1288
+ worktreeRemoveBestEffort(repoDir, wtPath);
1289
+ }
1290
+ }
1291
+ }
1292
+ } catch (err) {
1293
+ console.warn(`[agon] worktreePruneOrphaned failed: ${err instanceof Error ? err.message : String(err)}`);
1294
+ }
1295
+ }
1226
1296
  function worktreeChangedDiff(cwd, baseSha) {
1227
1297
  try {
1228
1298
  const trackedDiff = gitRaw(["diff", baseSha, "--"], cwd);
@@ -20018,10 +20088,10 @@ function createBashTool() {
20018
20088
  const readRedirect = tryRedirectToRead(command);
20019
20089
  if (readRedirect) {
20020
20090
  try {
20021
- const { readFileSync: readFileSync36 } = await import("fs");
20091
+ const { readFileSync: readFileSync38 } = await import("fs");
20022
20092
  const { resolve: resolve28 } = await import("path");
20023
20093
  const filePath = resolve28(ctx.cwd, readRedirect.file);
20024
- const content = readFileSync36(filePath, "utf-8");
20094
+ const content = readFileSync38(filePath, "utf-8");
20025
20095
  const lines = content.split("\n");
20026
20096
  const offset = readRedirect.offset ?? 0;
20027
20097
  const limit = readRedirect.limit ?? lines.length;
@@ -22065,6 +22135,8 @@ function cesarPlanMarkdownPath(planId) {
22065
22135
  }
22066
22136
  return full;
22067
22137
  }
22138
+ var CESAR_STEP_TYPE_TABLE = { self: true, forge: true, teamforge: true, delegate: true, brainstorm: true, campfire: true, tribunal: true, pipeline: true, review: true, agent: true, "team-agent": true };
22139
+ var CESAR_STEP_TYPES = Object.keys(CESAR_STEP_TYPE_TABLE);
22068
22140
  function createCesarPlan(intent, steps) {
22069
22141
  const id = `cplan-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
22070
22142
  const initializedSteps = steps.map((s) => Object.assign({}, s, { state: s.dependsOn && s.dependsOn.length > 0 ? "blocked" : "pending" }));
@@ -22080,10 +22152,11 @@ function advanceCesarStep(plan, stepId, result) {
22080
22152
  const stepIdx = plan.steps.findIndex((s) => s.id === stepId);
22081
22153
  if (stepIdx === -1) return plan;
22082
22154
  const isSuccess = result.status === "success";
22083
- const stepState = isSuccess ? "done" : "failed";
22155
+ const isPaused = result.status === "paused";
22156
+ const stepState = isSuccess ? "done" : isPaused ? "pending" : "failed";
22084
22157
  const now = (/* @__PURE__ */ new Date()).toISOString();
22085
22158
  let newSteps = plan.steps.map(
22086
- (s, i) => i === stepIdx ? { ...s, state: stepState, result, completedAt: now } : s
22159
+ (s, i) => i === stepIdx ? { ...s, state: stepState, result: isPaused ? void 0 : result, completedAt: isPaused ? void 0 : now } : s
22087
22160
  );
22088
22161
  if (isSuccess) {
22089
22162
  newSteps = newSteps.map((s) => {
@@ -22723,13 +22796,16 @@ function latestChatSession() {
22723
22796
  }
22724
22797
 
22725
22798
  // ../core/src/generated/blocks/image.ts
22726
- import { existsSync as existsSync19 } from "fs";
22799
+ import { existsSync as existsSync19, readFileSync as readFileSync23, statSync as statSync16 } from "fs";
22727
22800
  import { resolve as resolve19, basename as basename4, extname as extname2 } from "path";
22728
22801
  import { homedir as homedir11 } from "os";
22729
22802
  import { fileURLToPath as fileURLToPath3 } from "url";
22730
22803
  var IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([".png", ".jpg", ".jpeg", ".gif", ".webp", ".svg", ".bmp"]);
22731
22804
  var MIME_MAP = { ".png": "image/png", ".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".gif": "image/gif", ".webp": "image/webp", ".svg": "image/svg+xml", ".bmp": "image/bmp" };
22732
22805
  var IMG_CMD_REGEX = /^\/img\s+(.+)$/i;
22806
+ var MAX_DISPATCH_IMAGE_BYTES = 5 * 1024 * 1024;
22807
+ var MAX_DISPATCH_IMAGES = 4;
22808
+ var DISPATCH_VISION_MIME = /* @__PURE__ */ new Set(["image/png", "image/jpeg", "image/webp", "image/gif"]);
22733
22809
  function isImagePath(filePath) {
22734
22810
  const ext = extname2(filePath).toLowerCase();
22735
22811
  return IMAGE_EXTENSIONS.has(ext);
@@ -22816,9 +22892,55 @@ function extractImagesFromInput(input, cwd) {
22816
22892
  text = text.replace(/\s{2,}/g, " ").trim();
22817
22893
  return { text, images };
22818
22894
  }
22895
+ function encodeImagesRaw(paths, maxBytes, maxImages) {
22896
+ const lim = maxBytes ?? MAX_DISPATCH_IMAGE_BYTES;
22897
+ const cap = maxImages ?? MAX_DISPATCH_IMAGES;
22898
+ const images = [];
22899
+ const skipped = [];
22900
+ const kb = (n) => `${Math.round(n / 1024)}KB`;
22901
+ for (const p of paths) {
22902
+ const name = basename4(p);
22903
+ if (images.length >= cap) {
22904
+ skipped.push(`${name} (exceeds ${cap}-image limit)`);
22905
+ continue;
22906
+ }
22907
+ try {
22908
+ if (!existsSync19(p)) {
22909
+ skipped.push(`${name} (not found)`);
22910
+ continue;
22911
+ }
22912
+ const mediaType = mimeFromExt(p);
22913
+ if (!DISPATCH_VISION_MIME.has(mediaType)) {
22914
+ skipped.push(`${name} (unsupported type ${mediaType})`);
22915
+ continue;
22916
+ }
22917
+ const st = statSync16(p);
22918
+ if (!st.isFile()) {
22919
+ skipped.push(`${name} (not a regular file)`);
22920
+ continue;
22921
+ }
22922
+ if (st.size > lim) {
22923
+ skipped.push(`${name} (${kb(st.size)} over ${kb(lim)} limit)`);
22924
+ continue;
22925
+ }
22926
+ const data = readFileSync23(p).toString("base64");
22927
+ images.push({ data, mediaType });
22928
+ } catch {
22929
+ skipped.push(`${name} (read error)`);
22930
+ }
22931
+ }
22932
+ return { images, skipped };
22933
+ }
22934
+ function encodeImagesForDispatch(paths, maxBytes, maxImages) {
22935
+ const { images, skipped } = encodeImagesRaw(paths, maxBytes, maxImages);
22936
+ return {
22937
+ parts: images.map((i) => ({ type: "image", image: `data:${i.mediaType};base64,${i.data}`, mediaType: i.mediaType })),
22938
+ skipped
22939
+ };
22940
+ }
22819
22941
 
22820
22942
  // ../core/src/generated/rooms/store.ts
22821
- import { mkdirSync as mkdirSync18, existsSync as existsSync20, readFileSync as readFileSync23, writeFileSync as writeFileSync19, appendFileSync as appendFileSync2, readdirSync as readdirSync14, openSync, closeSync, unlinkSync as unlinkSync9, statSync as statSync16 } from "fs";
22943
+ import { mkdirSync as mkdirSync18, existsSync as existsSync20, readFileSync as readFileSync24, writeFileSync as writeFileSync19, appendFileSync as appendFileSync2, readdirSync as readdirSync14, openSync, closeSync, unlinkSync as unlinkSync9, statSync as statSync17 } from "fs";
22822
22944
  import { join as join22 } from "path";
22823
22945
  var LOCK_TIMEOUT_MS = 2e3;
22824
22946
  var LOCK_STALE_MS = 5e3;
@@ -22843,7 +22965,7 @@ function roomExists(roomId) {
22843
22965
  }
22844
22966
  function readMeta(roomId) {
22845
22967
  try {
22846
- return JSON.parse(readFileSync23(metaPath(roomId), "utf-8"));
22968
+ return JSON.parse(readFileSync24(metaPath(roomId), "utf-8"));
22847
22969
  } catch {
22848
22970
  return null;
22849
22971
  }
@@ -22904,7 +23026,7 @@ function withRoomLock(roomId, work) {
22904
23026
  } catch (err) {
22905
23027
  if (err?.code !== "EEXIST") throw err;
22906
23028
  try {
22907
- const st = statSync16(lock);
23029
+ const st = statSync17(lock);
22908
23030
  if (Date.now() - st.mtimeMs > LOCK_STALE_MS) {
22909
23031
  unlinkSync9(lock);
22910
23032
  continue;
@@ -22960,7 +23082,7 @@ function appendEvent(roomId, input) {
22960
23082
  function readEvents(roomId, sinceSeq, limit) {
22961
23083
  let raw;
22962
23084
  try {
22963
- raw = readFileSync23(eventsPath(roomId), "utf-8");
23085
+ raw = readFileSync24(eventsPath(roomId), "utf-8");
22964
23086
  } catch {
22965
23087
  return [];
22966
23088
  }
@@ -22988,7 +23110,7 @@ function isRoomClosed(roomId) {
22988
23110
  }
22989
23111
 
22990
23112
  // ../core/src/generated/rooms/presence.ts
22991
- import { mkdirSync as mkdirSync19, readFileSync as readFileSync24, writeFileSync as writeFileSync20 } from "fs";
23113
+ import { mkdirSync as mkdirSync19, readFileSync as readFileSync25, writeFileSync as writeFileSync20 } from "fs";
22992
23114
  import { join as join23 } from "path";
22993
23115
  var PRESENCE_TTL_MS = 9e4;
22994
23116
  function presencePath(roomId) {
@@ -22996,7 +23118,7 @@ function presencePath(roomId) {
22996
23118
  }
22997
23119
  function readPresenceRaw(roomId) {
22998
23120
  try {
22999
- return JSON.parse(readFileSync24(presencePath(roomId), "utf-8"));
23121
+ return JSON.parse(readFileSync25(presencePath(roomId), "utf-8"));
23000
23122
  } catch {
23001
23123
  return {};
23002
23124
  }
@@ -23039,14 +23161,14 @@ function listPresence(roomId) {
23039
23161
  }
23040
23162
 
23041
23163
  // ../core/src/generated/rooms/leases.ts
23042
- import { readFileSync as readFileSync25, writeFileSync as writeFileSync21 } from "fs";
23164
+ import { readFileSync as readFileSync26, writeFileSync as writeFileSync21 } from "fs";
23043
23165
  import { join as join24 } from "path";
23044
23166
  function leasesPath(roomId) {
23045
23167
  return join24(roomDir(roomId), "leases.json");
23046
23168
  }
23047
23169
  function readActiveLease(roomId) {
23048
23170
  try {
23049
- const raw = JSON.parse(readFileSync25(leasesPath(roomId), "utf-8"));
23171
+ const raw = JSON.parse(readFileSync26(leasesPath(roomId), "utf-8"));
23050
23172
  if (!raw || !raw.leaseId) return null;
23051
23173
  if (Date.now() >= new Date(raw.expiresAt).getTime()) return null;
23052
23174
  return raw;
@@ -23129,7 +23251,7 @@ function evaluateStop(state, config2, events) {
23129
23251
  }
23130
23252
 
23131
23253
  // ../core/src/generated/signals/flow.ts
23132
- import { readFileSync as readFileSync26, writeFileSync as writeFileSync22, mkdirSync as mkdirSync20, readdirSync as readdirSync15 } from "fs";
23254
+ import { readFileSync as readFileSync27, writeFileSync as writeFileSync22, mkdirSync as mkdirSync20, readdirSync as readdirSync15 } from "fs";
23133
23255
  import { join as join25, resolve as resolve20 } from "path";
23134
23256
  import { homedir as homedir12 } from "os";
23135
23257
  function getFlowsDir() {
@@ -23162,7 +23284,7 @@ function readFlows(limit) {
23162
23284
  const records = [];
23163
23285
  for (const file2 of files) {
23164
23286
  try {
23165
- const data = JSON.parse(readFileSync26(join25(getFlowsDir(), file2), "utf-8"));
23287
+ const data = JSON.parse(readFileSync27(join25(getFlowsDir(), file2), "utf-8"));
23166
23288
  records.push(data);
23167
23289
  } catch (err) {
23168
23290
  console.warn(`[agon] skipping malformed flow record ${file2}: ${err instanceof Error ? err.message : String(err)}`);
@@ -23591,7 +23713,7 @@ async function companionDispatch(opts) {
23591
23713
  }
23592
23714
 
23593
23715
  // ../core/src/generated/signals/models-registry.ts
23594
- import { readFileSync as readFileSync27, writeFileSync as writeFileSync23, mkdirSync as mkdirSync21, existsSync as existsSync22, statSync as statSync17 } from "fs";
23716
+ import { readFileSync as readFileSync28, writeFileSync as writeFileSync23, mkdirSync as mkdirSync21, existsSync as existsSync22, statSync as statSync18 } from "fs";
23595
23717
  import { join as join26 } from "path";
23596
23718
  var CACHE_TTL_MS = 36e5;
23597
23719
  var MODELS_DEV_URL = "https://models.dev/api.json";
@@ -23600,10 +23722,10 @@ async function fetchModelsRegistry() {
23600
23722
  const cacheFile = join26(cacheDir, "models-dev.json");
23601
23723
  if (existsSync22(cacheFile)) {
23602
23724
  try {
23603
- const stat = statSync17(cacheFile);
23725
+ const stat = statSync18(cacheFile);
23604
23726
  const age = Date.now() - stat.mtimeMs;
23605
23727
  if (age < CACHE_TTL_MS) {
23606
- return JSON.parse(readFileSync27(cacheFile, "utf-8"));
23728
+ return JSON.parse(readFileSync28(cacheFile, "utf-8"));
23607
23729
  }
23608
23730
  } catch (_e) {
23609
23731
  console.warn(`[agon] models-registry: cache read failed, refetching: ${_e instanceof Error ? _e.message : String(_e)}`);
@@ -23612,7 +23734,7 @@ async function fetchModelsRegistry() {
23612
23734
  const response = await fetch(MODELS_DEV_URL);
23613
23735
  if (!response.ok) {
23614
23736
  if (existsSync22(cacheFile)) {
23615
- return JSON.parse(readFileSync27(cacheFile, "utf-8"));
23737
+ return JSON.parse(readFileSync28(cacheFile, "utf-8"));
23616
23738
  }
23617
23739
  throw new Error(`Failed to fetch models registry: ${response.status}`);
23618
23740
  }
@@ -23739,7 +23861,7 @@ function modelEntryToEngineDef(entry) {
23739
23861
 
23740
23862
  // ../core/src/generated/signals/cli-models-registry.ts
23741
23863
  import { execSync as execSync4 } from "child_process";
23742
- import { readFileSync as readFileSync28, writeFileSync as writeFileSync24, mkdirSync as mkdirSync22, existsSync as existsSync23, statSync as statSync18 } from "fs";
23864
+ import { readFileSync as readFileSync29, writeFileSync as writeFileSync24, mkdirSync as mkdirSync22, existsSync as existsSync23, statSync as statSync19 } from "fs";
23743
23865
  import { join as join27 } from "path";
23744
23866
  import { homedir as homedir13 } from "os";
23745
23867
  import { createRequire as createRequire4 } from "module";
@@ -23754,9 +23876,9 @@ function readProbedCliModels(engineId, ttlMs) {
23754
23876
  try {
23755
23877
  const file2 = probedModelsCacheFile(engineId);
23756
23878
  if (!existsSync23(file2)) return null;
23757
- const age = Date.now() - statSync18(file2).mtimeMs;
23879
+ const age = Date.now() - statSync19(file2).mtimeMs;
23758
23880
  if (age > (ttlMs ?? PROBE_TTL_MS)) return null;
23759
- const data = JSON.parse(readFileSync28(file2, "utf-8"));
23881
+ const data = JSON.parse(readFileSync29(file2, "utf-8"));
23760
23882
  const raw = Array.isArray(data?.models) ? data.models : [];
23761
23883
  const models = raw.map((m) => ({ id: String(m.id ?? ""), name: String(m.name ?? m.id ?? ""), current: !!m.current })).filter((m) => m.name);
23762
23884
  return models.length > 0 ? models : null;
@@ -23991,6 +24113,7 @@ async function discoverCliModelsAsync() {
23991
24113
  // ../core/src/generated/sessions/session-companion.ts
23992
24114
  import { spawn as spawn3 } from "child_process";
23993
24115
  import { createInterface as createInterface2 } from "readline";
24116
+ import { existsSync as existsSync24 } from "fs";
23994
24117
  function createCompanionSession(config2) {
23995
24118
  let proc = null;
23996
24119
  let alive = false;
@@ -24296,9 +24419,37 @@ ${config2.systemPrompt}
24296
24419
  ${message}`;
24297
24420
  }
24298
24421
  firstTurn = false;
24422
+ const input = [{ type: "text", text: message, text_elements: [] }];
24423
+ if (opts.images?.length) {
24424
+ if (config2.engine.capabilities?.includes("vision")) {
24425
+ let attached = 0;
24426
+ const skipped = [];
24427
+ for (const p of opts.images) {
24428
+ if (attached >= MAX_DISPATCH_IMAGES) {
24429
+ skipped.push(`${p} (exceeds ${MAX_DISPATCH_IMAGES}-image limit)`);
24430
+ continue;
24431
+ }
24432
+ if (!existsSync24(p) || !isImagePath(p)) {
24433
+ skipped.push(`${p} (not found or not an image)`);
24434
+ continue;
24435
+ }
24436
+ if (!DISPATCH_VISION_MIME.has(mimeFromExt(p))) {
24437
+ skipped.push(`${p} (unsupported type ${mimeFromExt(p)})`);
24438
+ continue;
24439
+ }
24440
+ input.push({ type: "localImage", path: p });
24441
+ attached++;
24442
+ }
24443
+ if (skipped.length) {
24444
+ chunks.push({ type: "status", content: `image(s) not sent: ${skipped.join("; ")}` });
24445
+ }
24446
+ } else {
24447
+ chunks.push({ type: "status", content: `${config2.engine.id} has no vision capability \u2014 ${opts.images.length} image(s) not sent to the model` });
24448
+ }
24449
+ }
24299
24450
  await sendRpc("turn/start", {
24300
24451
  threadId,
24301
- input: [{ type: "text", text: message, text_elements: [] }]
24452
+ input
24302
24453
  });
24303
24454
  while (!turnDone) {
24304
24455
  if (chunks.length > 0) {
@@ -25031,7 +25182,41 @@ function createResumeSession(config2) {
25031
25182
  }
25032
25183
  firstTurn = false;
25033
25184
  }
25034
- messageHistory.push({ role: "user", content: opts.message });
25185
+ const hasVision = !!config2.engine.capabilities?.includes("vision");
25186
+ let turnImageParts = [];
25187
+ if (opts.images?.length) {
25188
+ if (hasVision) {
25189
+ const enc = encodeImagesForDispatch(opts.images);
25190
+ turnImageParts = enc.parts;
25191
+ if (enc.skipped.length) {
25192
+ yield { type: "status", content: `image(s) not sent: ${enc.skipped.join("; ")}` };
25193
+ }
25194
+ } else {
25195
+ yield { type: "status", content: `${config2.engine.id} has no vision capability \u2014 ${opts.images.length} image(s) not sent to the model` };
25196
+ }
25197
+ }
25198
+ const userTurnMsg = { role: "user", content: opts.message };
25199
+ messageHistory.push(userTurnMsg);
25200
+ const withImages = (history) => {
25201
+ if (!turnImageParts.length) return history;
25202
+ let idx = history.indexOf(userTurnMsg);
25203
+ if (idx < 0) {
25204
+ for (let i = history.length - 1; i >= 0; i--) {
25205
+ const m = history[i];
25206
+ if (m?.role === "user" && typeof m.content === "string" && m.content === userTurnMsg.content) {
25207
+ idx = i;
25208
+ break;
25209
+ }
25210
+ }
25211
+ }
25212
+ if (idx < 0) return history;
25213
+ const base = history[idx];
25214
+ const text = typeof base.content === "string" ? base.content : "";
25215
+ const content = text.trim() ? [{ type: "text", text }, ...turnImageParts] : [...turnImageParts];
25216
+ const cloned = history.slice();
25217
+ cloned[idx] = { ...base, content };
25218
+ return cloned;
25219
+ };
25035
25220
  const estimateSingle = (m) => {
25036
25221
  if (typeof m.content === "string") return Math.ceil(m.content.length / 3.5);
25037
25222
  if (m.content === null && m.tool_calls) {
@@ -25190,7 +25375,7 @@ ${newSummary.decisions.map((d) => ` - ${d}`).join("\n")}` : "",
25190
25375
  const tier3CompactionEnabled = process.env.AGON_DISABLE_TIER3_COMPACTION !== "1";
25191
25376
  if (tier3CompactionEnabled && afterTier2 > CONTEXT_LIMIT - COMPACTION_BUFFER && config2.engine.api) {
25192
25377
  try {
25193
- const { apiDispatch: apiDispatch2 } = await import("./dispatch-XHLJ44TF.js");
25378
+ const { apiDispatch: apiDispatch2 } = await import("./dispatch-J4RSWLXM.js");
25194
25379
  const compactionPrompt = `Summarize this conversation context into a concise briefing. Preserve: the user's goal, key discoveries, files read/modified, important decisions, and current progress. Drop: verbose tool outputs, repeated attempts, and pleasantries.
25195
25380
 
25196
25381
  CONTEXT TO SUMMARIZE:
@@ -25325,7 +25510,7 @@ ${compactionResult.stdout}` },
25325
25510
  } else {
25326
25511
  yield { type: "status", content: `tool loop turn ${step}/${budget}\u2026` };
25327
25512
  }
25328
- const gen = apiStreamDispatchWithHistory(config2.engine.api, messageHistory, config2.engine.timeout ?? 180, opts.signal, effectiveTools);
25513
+ const gen = apiStreamDispatchWithHistory(config2.engine.api, withImages(messageHistory), config2.engine.timeout ?? 180, opts.signal, effectiveTools);
25329
25514
  try {
25330
25515
  while (true) {
25331
25516
  const { value, done: done2 } = await gen.next();
@@ -25866,6 +26051,191 @@ ${compactionResult.stdout}` },
25866
26051
  return session;
25867
26052
  }
25868
26053
 
26054
+ // ../core/src/generated/sessions/session-pty.ts
26055
+ import { existsSync as existsSync25, readFileSync as readFileSync30, rmSync as rmSync5 } from "fs";
26056
+ function createPtySession(config2) {
26057
+ let claudeSession = null;
26058
+ let alive = false;
26059
+ let firstTurn = true;
26060
+ let turnActive = false;
26061
+ let pendingDrain = null;
26062
+ const TURN_TIMEOUT_MS = 15 * 60 * 1e3;
26063
+ function buildExtraArgv() {
26064
+ const args = [];
26065
+ if (config2.mcpServers && config2.mcpServers.length > 0) {
26066
+ const mcpConfig = JSON.stringify({
26067
+ mcpServers: Object.fromEntries(
26068
+ config2.mcpServers.map((s) => [s.name ?? s.command ?? "mcp", s])
26069
+ )
26070
+ });
26071
+ args.push("--mcp-config", mcpConfig, "--strict-mcp-config");
26072
+ }
26073
+ args.push("--disallowedTools", "Bash Edit Write MultiEdit NotebookEdit");
26074
+ args.push("--allowedTools", "Read Grep Glob mcp__agon-orchestration");
26075
+ if (config2.claudePtyLaunchArgs && config2.claudePtyLaunchArgs.length > 0) {
26076
+ args.push(...config2.claudePtyLaunchArgs);
26077
+ }
26078
+ return args;
26079
+ }
26080
+ function readAnswer() {
26081
+ const p = config2.answerChannelPath;
26082
+ if (!p) return null;
26083
+ try {
26084
+ if (!existsSync25(p)) return null;
26085
+ const parsed = JSON.parse(readFileSync30(p, "utf-8"));
26086
+ const t = parsed?.text;
26087
+ return typeof t === "string" ? t : null;
26088
+ } catch {
26089
+ return null;
26090
+ }
26091
+ }
26092
+ function clearAnswer() {
26093
+ const p = config2.answerChannelPath;
26094
+ if (!p) return;
26095
+ try {
26096
+ rmSync5(p, { force: true });
26097
+ } catch {
26098
+ }
26099
+ }
26100
+ const session = {
26101
+ get alive() {
26102
+ return alive;
26103
+ },
26104
+ sessionId: null,
26105
+ engineId: config2.engine.id,
26106
+ get pid() {
26107
+ return null;
26108
+ },
26109
+ async start() {
26110
+ if (alive) return;
26111
+ const mod = await import("@kernlang/agon-engines/cli/claude.js");
26112
+ claudeSession = await mod.ClaudeCliSession.spawn({
26113
+ mode: "agent",
26114
+ cwd: config2.cwd,
26115
+ extraArgv: buildExtraArgv(),
26116
+ daemonTimeoutMs: 6e4
26117
+ });
26118
+ alive = true;
26119
+ firstTurn = true;
26120
+ },
26121
+ async *send(opts) {
26122
+ if (turnActive) {
26123
+ yield { type: "error", content: "claude PTY session busy (concurrent turn rejected)" };
26124
+ return;
26125
+ }
26126
+ turnActive = true;
26127
+ try {
26128
+ if (pendingDrain) {
26129
+ try {
26130
+ await pendingDrain;
26131
+ } catch {
26132
+ }
26133
+ pendingDrain = null;
26134
+ }
26135
+ if (!alive || !claudeSession) {
26136
+ try {
26137
+ await session.start();
26138
+ } catch (e) {
26139
+ yield { type: "error", content: `claude PTY session not alive: ${e instanceof Error ? e.message : String(e)}` };
26140
+ return;
26141
+ }
26142
+ }
26143
+ if (opts.signal?.aborted) {
26144
+ yield { type: "done", content: "cancelled" };
26145
+ return;
26146
+ }
26147
+ clearAnswer();
26148
+ const sys = firstTurn ? opts.systemPrompt ?? config2.systemPrompt : void 0;
26149
+ firstTurn = false;
26150
+ const composed = sys ? `[System Instructions]
26151
+ ${sys}
26152
+
26153
+ [User Message]
26154
+ ${opts.message}` : opts.message;
26155
+ let aborted2 = false;
26156
+ const onAbort = () => {
26157
+ aborted2 = true;
26158
+ try {
26159
+ claudeSession?.close?.();
26160
+ } catch {
26161
+ }
26162
+ claudeSession = null;
26163
+ alive = false;
26164
+ };
26165
+ opts.signal?.addEventListener("abort", onAbort, { once: true });
26166
+ let scrapedFinal = "";
26167
+ let driverError = null;
26168
+ const it = claudeSession.askStream(composed, TURN_TIMEOUT_MS);
26169
+ const driver = (async () => {
26170
+ try {
26171
+ let res = await it.next();
26172
+ while (!res.done) {
26173
+ res = await it.next();
26174
+ }
26175
+ scrapedFinal = typeof res.value === "string" ? res.value : "";
26176
+ } catch (e) {
26177
+ driverError = e;
26178
+ }
26179
+ })();
26180
+ pendingDrain = driver;
26181
+ let driverDone = false;
26182
+ void driver.then(() => {
26183
+ driverDone = true;
26184
+ });
26185
+ await new Promise((resolve28) => {
26186
+ const tick = setInterval(() => {
26187
+ if (driverDone || readAnswer() !== null) {
26188
+ clearInterval(tick);
26189
+ resolve28();
26190
+ }
26191
+ }, 100);
26192
+ void driver.finally(() => {
26193
+ clearInterval(tick);
26194
+ resolve28();
26195
+ });
26196
+ });
26197
+ opts.signal?.removeEventListener("abort", onAbort);
26198
+ if (aborted2) {
26199
+ yield { type: "done", content: "cancelled" };
26200
+ return;
26201
+ }
26202
+ const answer = readAnswer();
26203
+ if (answer !== null && answer.length > 0) {
26204
+ yield { type: "text", content: answer };
26205
+ yield { type: "done", content: "end_turn" };
26206
+ return;
26207
+ }
26208
+ await driver;
26209
+ pendingDrain = null;
26210
+ if (driverError) {
26211
+ alive = false;
26212
+ claudeSession = null;
26213
+ yield { type: "error", content: `claude PTY turn failed: ${driverError instanceof Error ? driverError.message : String(driverError)}` };
26214
+ return;
26215
+ }
26216
+ if (scrapedFinal && scrapedFinal.trim()) {
26217
+ yield { type: "text", content: scrapedFinal };
26218
+ }
26219
+ yield { type: "done", content: "end_turn" };
26220
+ } finally {
26221
+ turnActive = false;
26222
+ }
26223
+ },
26224
+ close() {
26225
+ try {
26226
+ claudeSession?.close?.();
26227
+ } catch {
26228
+ }
26229
+ claudeSession = null;
26230
+ alive = false;
26231
+ },
26232
+ getMessageHistory() {
26233
+ return [];
26234
+ }
26235
+ };
26236
+ return session;
26237
+ }
26238
+
25869
26239
  // ../core/src/generated/sessions/persistent-session.ts
25870
26240
  function createPersistentSession(config2) {
25871
26241
  const engine = config2.engine;
@@ -25873,7 +26243,11 @@ function createPersistentSession(config2) {
25873
26243
  return createResumeSession(config2);
25874
26244
  }
25875
26245
  if ((engine.companion?.protocol === "stream-json" || engine.id === "claude" || engine.binary === "claude") && config2.binaryPath) {
25876
- return createStreamJsonSession(config2);
26246
+ const printOptOut = process.env.AGON_CLAUDE_PRINT;
26247
+ if (printOptOut === "1" || printOptOut === "true") {
26248
+ return createStreamJsonSession(config2);
26249
+ }
26250
+ return createPtySession(config2);
25877
26251
  }
25878
26252
  if (engine.companion && engine.companion.protocol === "acp") {
25879
26253
  return createAcpSession(config2);
@@ -25968,7 +26342,7 @@ function createStreamBridge(dispatch, opts) {
25968
26342
  }
25969
26343
 
25970
26344
  // ../core/src/generated/forge/virtual-fs.ts
25971
- import { readFileSync as readFileSync29, existsSync as existsSync24, readdirSync as readdirSync16, statSync as statSync19 } from "fs";
26345
+ import { readFileSync as readFileSync31, existsSync as existsSync26, readdirSync as readdirSync16, statSync as statSync20 } from "fs";
25972
26346
  import { join as join28, resolve as resolve21, relative as relative8, dirname as dirname12 } from "path";
25973
26347
  import { createHash as createHash5 } from "crypto";
25974
26348
  function createFileSnapshot(rootDir) {
@@ -25985,16 +26359,16 @@ function snapshotRead(snap, absPath) {
25985
26359
  return snap.cache.get(key) ?? null;
25986
26360
  }
25987
26361
  try {
25988
- if (!existsSync24(key)) {
26362
+ if (!existsSync26(key)) {
25989
26363
  snap.cache.set(key, null);
25990
26364
  return null;
25991
26365
  }
25992
- const st = statSync19(key);
26366
+ const st = statSync20(key);
25993
26367
  if (!st.isFile()) {
25994
26368
  snap.cache.set(key, null);
25995
26369
  return null;
25996
26370
  }
25997
- const content = readFileSync29(key, "utf-8");
26371
+ const content = readFileSync31(key, "utf-8");
25998
26372
  snap.cache.set(key, content);
25999
26373
  return content;
26000
26374
  } catch (e) {
@@ -26007,7 +26381,7 @@ function snapshotList(snap, absDir) {
26007
26381
  try {
26008
26382
  return readdirSync16(dir).filter((f) => {
26009
26383
  try {
26010
- return statSync19(join28(dir, f)).isFile();
26384
+ return statSync20(join28(dir, f)).isFile();
26011
26385
  } catch {
26012
26386
  return false;
26013
26387
  }
@@ -26421,7 +26795,7 @@ ${sessionLines.join("\n")}`);
26421
26795
  }
26422
26796
 
26423
26797
  // ../core/src/generated/cesar/context-thread.ts
26424
- import { readFileSync as readFileSync30, writeFileSync as writeFileSync25, mkdirSync as mkdirSync23, renameSync as renameSync11, existsSync as existsSync25, readdirSync as readdirSync17, unlinkSync as unlinkSync10, statSync as statSync20, chmodSync as chmodSync2, openSync as openSync2, fsyncSync, closeSync as closeSync2, appendFileSync as appendFileSync3 } from "fs";
26798
+ import { readFileSync as readFileSync32, writeFileSync as writeFileSync25, mkdirSync as mkdirSync23, renameSync as renameSync11, existsSync as existsSync27, readdirSync as readdirSync17, unlinkSync as unlinkSync10, statSync as statSync21, chmodSync as chmodSync2, openSync as openSync2, fsyncSync, closeSync as closeSync2, appendFileSync as appendFileSync3 } from "fs";
26425
26799
  import { join as join30, resolve as resolve23, basename as basename6 } from "path";
26426
26800
  import { randomUUID as randomUUID5, createHash as createHash6 } from "crypto";
26427
26801
  import { homedir as homedir14 } from "os";
@@ -26646,14 +27020,14 @@ var ContextThread = class {
26646
27020
  const now = Date.now();
26647
27021
  if (config2.threadId) {
26648
27022
  const candidatePath = threadFilePath(this.projectPath, config2.threadId);
26649
- if (existsSync25(candidatePath)) {
27023
+ if (existsSync27(candidatePath)) {
26650
27024
  try {
26651
- const stat = statSync20(candidatePath);
27025
+ const stat = statSync21(candidatePath);
26652
27026
  if (stat.size > MAX_THREAD_FILE_BYTES) {
26653
27027
  console.warn(`[agon] context-thread: ${candidatePath} is ${stat.size} bytes (> ${MAX_THREAD_FILE_BYTES}), refusing to load. Run /thread compact or /thread fork.`);
26654
27028
  throw new Error("thread file too large");
26655
27029
  }
26656
- const raw = readFileSync30(candidatePath, "utf-8");
27030
+ const raw = readFileSync32(candidatePath, "utf-8");
26657
27031
  const snap = JSON.parse(raw);
26658
27032
  if (snap && typeof snap === "object" && Array.isArray(snap.messages)) {
26659
27033
  const filteredMessages = (snap.messages ?? []).filter((m) => m && m.role !== "system");
@@ -26671,9 +27045,9 @@ var ContextThread = class {
26671
27045
  this.fileTouches = snap.fileTouches ?? {};
26672
27046
  this.hydrated = true;
26673
27047
  const jPathOnLoad = threadFilePath(this.projectPath, this.threadId).replace(/\.json$/, ".journal.jsonl");
26674
- if (existsSync25(jPathOnLoad)) {
27048
+ if (existsSync27(jPathOnLoad)) {
26675
27049
  try {
26676
- const journalLines = readFileSync30(jPathOnLoad, "utf-8").split("\n").filter(Boolean);
27050
+ const journalLines = readFileSync32(jPathOnLoad, "utf-8").split("\n").filter(Boolean);
26677
27051
  const knownOnLoad = new Set(this.messages.map((m) => m.id));
26678
27052
  let merged = false;
26679
27053
  for (const line of journalLines) {
@@ -26943,8 +27317,8 @@ ${msg.content}` };
26943
27317
  let bytes = 0;
26944
27318
  try {
26945
27319
  const path = threadFilePath(this.projectPath, this.threadId);
26946
- if (existsSync25(path)) {
26947
- bytes = readFileSync30(path, "utf-8").length;
27320
+ if (existsSync27(path)) {
27321
+ bytes = readFileSync32(path, "utf-8").length;
26948
27322
  }
26949
27323
  } catch {
26950
27324
  }
@@ -26993,7 +27367,7 @@ ${msg.content}` };
26993
27367
  this.dirty = false;
26994
27368
  this.hydrated = true;
26995
27369
  const jPath = threadJournalPath(this.projectPath, this.threadId);
26996
- if (existsSync25(jPath)) unlinkSync10(jPath);
27370
+ if (existsSync27(jPath)) unlinkSync10(jPath);
26997
27371
  this.journaledIds.clear();
26998
27372
  } catch {
26999
27373
  }
@@ -27025,9 +27399,9 @@ ${msg.content}` };
27025
27399
  }
27026
27400
  try {
27027
27401
  const jPath = threadJournalPath(this.projectPath, this.threadId);
27028
- if (existsSync25(jPath)) {
27402
+ if (existsSync27(jPath)) {
27029
27403
  try {
27030
- const journalLines = readFileSync30(jPath, "utf-8").split("\n").filter(Boolean);
27404
+ const journalLines = readFileSync32(jPath, "utf-8").split("\n").filter(Boolean);
27031
27405
  const known = new Set(this.messages.map((m) => m.id));
27032
27406
  for (const line of journalLines) {
27033
27407
  try {
@@ -27046,11 +27420,11 @@ ${msg.content}` };
27046
27420
  console.warn(`[agon] context-thread: journal merge failed (will overwrite): ${err instanceof Error ? err.message : String(err)}`);
27047
27421
  }
27048
27422
  }
27049
- if (existsSync25(target)) {
27423
+ if (existsSync27(target)) {
27050
27424
  try {
27051
- const stat = statSync20(target);
27425
+ const stat = statSync21(target);
27052
27426
  if (stat.size <= MAX_THREAD_FILE_BYTES) {
27053
- const raw = readFileSync30(target, "utf-8");
27427
+ const raw = readFileSync32(target, "utf-8");
27054
27428
  const onDisk = JSON.parse(raw);
27055
27429
  if (onDisk && Array.isArray(onDisk.messages)) {
27056
27430
  const known = new Set(this.messages.map((m) => m.id));
@@ -27108,7 +27482,7 @@ ${msg.content}` };
27108
27482
  this.dirty = false;
27109
27483
  this.hydrated = true;
27110
27484
  try {
27111
- if (existsSync25(jPath)) unlinkSync10(jPath);
27485
+ if (existsSync27(jPath)) unlinkSync10(jPath);
27112
27486
  this.journaledIds.clear();
27113
27487
  } catch {
27114
27488
  }
@@ -27129,8 +27503,8 @@ ${msg.content}` };
27129
27503
  function loadActivePointer() {
27130
27504
  try {
27131
27505
  const path = activePointerPath();
27132
- if (existsSync25(path)) {
27133
- const raw = readFileSync30(path, "utf-8");
27506
+ if (existsSync27(path)) {
27507
+ const raw = readFileSync32(path, "utf-8");
27134
27508
  const parsed = JSON.parse(raw);
27135
27509
  if (parsed && typeof parsed === "object" && parsed.byProject) {
27136
27510
  return parsed;
@@ -27202,7 +27576,7 @@ async function forkActiveThread(projectPath, systemPrompt) {
27202
27576
  }
27203
27577
  function listThreadsForProject(projectPath) {
27204
27578
  const dir = threadDirFor(projectPath);
27205
- if (!existsSync25(dir)) return [];
27579
+ if (!existsSync27(dir)) return [];
27206
27580
  try {
27207
27581
  return readdirSync17(dir).filter((f) => f.endsWith(".json")).map((f) => f.slice(0, -5));
27208
27582
  } catch (err) {
@@ -27260,6 +27634,39 @@ var PlanCostEstimator = class {
27260
27634
  };
27261
27635
  var planCostEstimator = new PlanCostEstimator();
27262
27636
 
27637
+ // ../core/src/generated/cesar/plan-validation.ts
27638
+ var VALID_STEP_TYPES = new Set(CESAR_STEP_TYPES);
27639
+ function sanitizePlanSteps(rawSteps) {
27640
+ const SAFE_ID = /^[a-z0-9_-]{1,64}$/;
27641
+ const sanitizeId = (raw, fallback) => {
27642
+ if (typeof raw === "string" && SAFE_ID.test(raw)) return raw;
27643
+ return fallback;
27644
+ };
27645
+ const input = Array.isArray(rawSteps) ? rawSteps : [];
27646
+ const steps = input.filter((s) => s && VALID_STEP_TYPES.has(s.type)).map((s, i) => {
27647
+ const est = planCostEstimator.estimate(s.type, s.engines ?? []);
27648
+ return {
27649
+ id: sanitizeId(s.id, `step-${i}-${Math.random().toString(36).slice(2, 8)}`),
27650
+ type: s.type,
27651
+ description: typeof s.description === "string" && s.description.trim().length > 0 ? s.description : "(no description)",
27652
+ engines: s.engines,
27653
+ engine: s.engine,
27654
+ fitnessCmd: s.fitnessCmd,
27655
+ tribunalMode: s.tribunalMode,
27656
+ parallel: s.parallel ?? false,
27657
+ dependsOn: s.dependsOn,
27658
+ exports: typeof s.exports === "string" ? [s.exports] : s.exports,
27659
+ imports: typeof s.imports === "string" ? [s.imports] : s.imports,
27660
+ estimatedTokens: est.tokens,
27661
+ estimatedCostUsd: est.costUsd,
27662
+ rationale: s.rationale,
27663
+ verifyCmd: s.verifyCmd
27664
+ };
27665
+ });
27666
+ const dropped = input.length - steps.length;
27667
+ return { steps, dropped };
27668
+ }
27669
+
27263
27670
  // ../core/src/generated/cesar/plan-executor.ts
27264
27671
  function getReadySteps(plan) {
27265
27672
  return plan.steps.filter((s) => s.state === "pending");
@@ -28653,7 +29060,7 @@ function hooksOutput(results) {
28653
29060
  }
28654
29061
 
28655
29062
  // ../core/src/generated/blocks/skill-loader.ts
28656
- import { readFileSync as readFileSync31, readdirSync as readdirSync18, existsSync as existsSync26 } from "fs";
29063
+ import { readFileSync as readFileSync33, readdirSync as readdirSync18, existsSync as existsSync28 } from "fs";
28657
29064
  import { join as join32, dirname as dirname13, resolve as resolve24 } from "path";
28658
29065
  import { homedir as homedir15 } from "os";
28659
29066
  import { fileURLToPath as fileURLToPath4 } from "url";
@@ -28675,7 +29082,7 @@ function parseFrontmatter(content) {
28675
29082
  }
28676
29083
  function loadSkillFile(filePath) {
28677
29084
  try {
28678
- const content = readFileSync31(filePath, "utf-8");
29085
+ const content = readFileSync33(filePath, "utf-8");
28679
29086
  const { meta: meta3, body } = parseFrontmatter(content);
28680
29087
  if (!meta3.name || !meta3.trigger) return null;
28681
29088
  return {
@@ -28693,7 +29100,7 @@ function loadSkillFile(filePath) {
28693
29100
  }
28694
29101
  function loadSkillsFromDir(dir, source) {
28695
29102
  const skills = [];
28696
- if (!existsSync26(dir)) return skills;
29103
+ if (!existsSync28(dir)) return skills;
28697
29104
  try {
28698
29105
  const files = readdirSync18(dir).filter((f) => f.endsWith(".md"));
28699
29106
  for (const file2 of files) {
@@ -28733,7 +29140,7 @@ function renderSkillPrompt(skill, input) {
28733
29140
  }
28734
29141
 
28735
29142
  // ../core/src/generated/blocks/engine-memory.ts
28736
- import { readFileSync as readFileSync32, writeFileSync as writeFileSync26, mkdirSync as mkdirSync24, renameSync as renameSync12 } from "fs";
29143
+ import { readFileSync as readFileSync34, writeFileSync as writeFileSync26, mkdirSync as mkdirSync24, renameSync as renameSync12 } from "fs";
28737
29144
  import { join as join33, resolve as resolve25 } from "path";
28738
29145
  import { homedir as homedir16 } from "os";
28739
29146
  function memoryPath() {
@@ -28743,7 +29150,7 @@ function memoryPath() {
28743
29150
  }
28744
29151
  function loadEngineMemory() {
28745
29152
  try {
28746
- return JSON.parse(readFileSync32(memoryPath(), "utf-8"));
29153
+ return JSON.parse(readFileSync34(memoryPath(), "utf-8"));
28747
29154
  } catch (err) {
28748
29155
  if (err.code !== "ENOENT") {
28749
29156
  console.warn(`[agon] failed to load engine memory: ${err instanceof Error ? err.message : String(err)}`);
@@ -29021,12 +29428,12 @@ function createSidechainLogger(opts) {
29021
29428
  }
29022
29429
 
29023
29430
  // ../core/src/generated/blocks/provenance.ts
29024
- import { readFileSync as readFileSync33, writeFileSync as writeFileSync27, mkdirSync as mkdirSync26 } from "fs";
29431
+ import { readFileSync as readFileSync35, writeFileSync as writeFileSync27, mkdirSync as mkdirSync26 } from "fs";
29025
29432
  import { join as join35, resolve as resolve26 } from "path";
29026
29433
  import { createHash as createHash7 } from "crypto";
29027
29434
  function sha256OfFile(path) {
29028
29435
  try {
29029
- return "sha256:" + createHash7("sha256").update(readFileSync33(path)).digest("hex");
29436
+ return "sha256:" + createHash7("sha256").update(readFileSync35(path)).digest("hex");
29030
29437
  } catch (e) {
29031
29438
  console.warn(`[agon] provenance: could not hash ${path}: ${e instanceof Error ? e.message : String(e)}`);
29032
29439
  return "unavailable";
@@ -29304,7 +29711,7 @@ var CommandRegistry = class {
29304
29711
 
29305
29712
  // ../core/src/generated/blocks/extension-loader.ts
29306
29713
  import { join as join36, resolve as resolve27 } from "path";
29307
- import { readdirSync as readdirSync19, readFileSync as readFileSync34, existsSync as existsSync27 } from "fs";
29714
+ import { readdirSync as readdirSync19, readFileSync as readFileSync36, existsSync as existsSync29 } from "fs";
29308
29715
  import { homedir as homedir17 } from "os";
29309
29716
 
29310
29717
  // ../core/src/generated/signals/event-bus.ts
@@ -29397,13 +29804,13 @@ function discoverExtensionDirs(cwd) {
29397
29804
  const override = process.env.AGON_HOME?.trim();
29398
29805
  const home = override ? resolve27(override) : join36(homedir17(), ".agon");
29399
29806
  const userDir = join36(home, "extensions");
29400
- if (existsSync27(userDir)) {
29807
+ if (existsSync29(userDir)) {
29401
29808
  try {
29402
29809
  const entries = readdirSync19(userDir, { withFileTypes: true });
29403
29810
  for (const entry of entries) {
29404
29811
  if (entry.isDirectory()) {
29405
29812
  const manifestPath = join36(userDir, entry.name, "manifest.json");
29406
- if (existsSync27(manifestPath)) {
29813
+ if (existsSync29(manifestPath)) {
29407
29814
  results.push({ dir: join36(userDir, entry.name), source: "user" });
29408
29815
  }
29409
29816
  }
@@ -29412,13 +29819,13 @@ function discoverExtensionDirs(cwd) {
29412
29819
  }
29413
29820
  }
29414
29821
  const repoDir = join36(cwd, ".agon", "extensions");
29415
- if (existsSync27(repoDir)) {
29822
+ if (existsSync29(repoDir)) {
29416
29823
  try {
29417
29824
  const entries = readdirSync19(repoDir, { withFileTypes: true });
29418
29825
  for (const entry of entries) {
29419
29826
  if (entry.isDirectory()) {
29420
29827
  const manifestPath = join36(repoDir, entry.name, "manifest.json");
29421
- if (existsSync27(manifestPath)) {
29828
+ if (existsSync29(manifestPath)) {
29422
29829
  results.push({ dir: join36(repoDir, entry.name), source: "repo" });
29423
29830
  }
29424
29831
  }
@@ -29431,7 +29838,7 @@ function discoverExtensionDirs(cwd) {
29431
29838
  function loadExtensionManifest(dir, source) {
29432
29839
  const manifestPath = join36(dir, "manifest.json");
29433
29840
  try {
29434
- const raw = JSON.parse(readFileSync34(manifestPath, "utf-8"));
29841
+ const raw = JSON.parse(readFileSync36(manifestPath, "utf-8"));
29435
29842
  const result = validateManifest(raw, manifestPath);
29436
29843
  if (!result.ok || !result.data) {
29437
29844
  console.warn(`[agon] skipping extension ${dir}: ${result.error}`);
@@ -29500,7 +29907,7 @@ function registerExtensionEngines(ext, engineRegistry) {
29500
29907
  for (const enginePath of enginePaths) {
29501
29908
  try {
29502
29909
  const fullPath = resolve27(ext.dir, enginePath);
29503
- const raw = JSON.parse(readFileSync34(fullPath, "utf-8"));
29910
+ const raw = JSON.parse(readFileSync36(fullPath, "utf-8"));
29504
29911
  if (raw.id) {
29505
29912
  engineRegistry.register(raw);
29506
29913
  registered.push(raw.id);
@@ -29915,7 +30322,7 @@ function computeContributionWeights(team, trace) {
29915
30322
  }
29916
30323
 
29917
30324
  // ../core/src/generated/teams/team-elo.ts
29918
- import { readFileSync as readFileSync35, writeFileSync as writeFileSync28, mkdirSync as mkdirSync27, renameSync as renameSync13 } from "fs";
30325
+ import { readFileSync as readFileSync37, writeFileSync as writeFileSync28, mkdirSync as mkdirSync27, renameSync as renameSync13 } from "fs";
29919
30326
  import { dirname as dirname14 } from "path";
29920
30327
  function defaultCompositionRating(lineupKey2) {
29921
30328
  return { lineupKey: lineupKey2, rating: 1500, wins: 0, losses: 0, draws: 0, matches: 0 };
@@ -29925,7 +30332,7 @@ function defaultRoleRating(engineId, role) {
29925
30332
  }
29926
30333
  function loadTeamElo() {
29927
30334
  try {
29928
- return JSON.parse(readFileSync35(TEAM_ELO_PATH, "utf-8"));
30335
+ return JSON.parse(readFileSync37(TEAM_ELO_PATH, "utf-8"));
29929
30336
  } catch (err) {
29930
30337
  if (err.code !== "ENOENT") {
29931
30338
  console.warn(`[agon] failed to load team ELO: ${err instanceof Error ? err.message : String(err)}`);
@@ -30083,6 +30490,7 @@ export {
30083
30490
  worktreeRemove,
30084
30491
  worktreeRemoveBestEffort,
30085
30492
  worktreePruneAll,
30493
+ worktreePruneOrphaned,
30086
30494
  worktreeChangedDiff,
30087
30495
  worktreeChangedShortstat,
30088
30496
  stashSnapshot,
@@ -30272,6 +30680,7 @@ export {
30272
30680
  getCesarPlansDir,
30273
30681
  cesarPlanJsonPath,
30274
30682
  cesarPlanMarkdownPath,
30683
+ CESAR_STEP_TYPES,
30275
30684
  createCesarPlan,
30276
30685
  approveCesarPlan,
30277
30686
  advanceCesarStep,
@@ -30303,6 +30712,7 @@ export {
30303
30712
  buildImageAttachment,
30304
30713
  normalizeDroppedPath,
30305
30714
  extractImagesFromInput,
30715
+ encodeImagesForDispatch,
30306
30716
  roomsDir,
30307
30717
  roomDir,
30308
30718
  slugifyRoomId,
@@ -30371,6 +30781,7 @@ export {
30371
30781
  listThreadsForProject,
30372
30782
  deleteThread,
30373
30783
  planCostEstimator,
30784
+ sanitizePlanSteps,
30374
30785
  getReadySteps,
30375
30786
  executePlan,
30376
30787
  makeAssistantChunk,
@@ -30456,4 +30867,4 @@ export {
30456
30867
  predictTeamRating,
30457
30868
  updateTeamElo
30458
30869
  };
30459
- //# sourceMappingURL=chunk-HAJIKZGU.js.map
30870
+ //# sourceMappingURL=chunk-BPKY4OF2.js.map