@odla-ai/cli 0.43.0 → 0.43.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -452,10 +452,10 @@ function isManagedDevVar(line2) {
452
452
  const match = line2.match(/^\s*(?:export\s+)?([A-Z][A-Z0-9_]*)\s*=/);
453
453
  return !!match?.[1] && MANAGED_DEV_VARS.has(match[1]);
454
454
  }
455
- function writePrivateText(path, text3) {
455
+ function writePrivateText(path, text4) {
456
456
  (0, import_node_fs4.mkdirSync)((0, import_node_path4.dirname)(path), { recursive: true });
457
457
  const temporary = `${path}.tmp-${process.pid}-${Date.now()}`;
458
- (0, import_node_fs4.writeFileSync)(temporary, text3, { mode: 384 });
458
+ (0, import_node_fs4.writeFileSync)(temporary, text4, { mode: 384 });
459
459
  (0, import_node_fs4.chmodSync)(temporary, 384);
460
460
  (0, import_node_fs4.renameSync)(temporary, path);
461
461
  }
@@ -895,12 +895,12 @@ async function readAdminAiAudit(request3) {
895
895
  }
896
896
  }
897
897
  async function responseBody(response2) {
898
- const text3 = await response2.text();
899
- if (!text3) return {};
898
+ const text4 = await response2.text();
899
+ if (!text4) return {};
900
900
  try {
901
- return JSON.parse(text3);
901
+ return JSON.parse(text4);
902
902
  } catch {
903
- return { message: text3.slice(0, 300) };
903
+ return { message: text4.slice(0, 300) };
904
904
  }
905
905
  }
906
906
  function apiError(status, body) {
@@ -1002,12 +1002,12 @@ function timestamp2(value2) {
1002
1002
  return Number.isFinite(date.valueOf()) ? date.toISOString() : "";
1003
1003
  }
1004
1004
  async function responseBody2(res) {
1005
- const text3 = await res.text();
1006
- if (!text3) return {};
1005
+ const text4 = await res.text();
1006
+ if (!text4) return {};
1007
1007
  try {
1008
- return JSON.parse(text3);
1008
+ return JSON.parse(text4);
1009
1009
  } catch {
1010
- return { message: text3.slice(0, 300) };
1010
+ return { message: text4.slice(0, 300) };
1011
1011
  }
1012
1012
  }
1013
1013
  function apiError2(action2, status, body) {
@@ -1183,12 +1183,12 @@ function catalogModels(body) {
1183
1183
  return body.catalog.models.filter((value2) => isRecord3(value2) && typeof value2.id === "string" && typeof value2.provider === "string");
1184
1184
  }
1185
1185
  async function responseBody3(res) {
1186
- const text3 = await res.text();
1187
- if (!text3) return {};
1186
+ const text4 = await res.text();
1187
+ if (!text4) return {};
1188
1188
  try {
1189
- return JSON.parse(text3);
1189
+ return JSON.parse(text4);
1190
1190
  } catch {
1191
- return { message: text3.slice(0, 300) };
1191
+ return { message: text4.slice(0, 300) };
1192
1192
  }
1193
1193
  }
1194
1194
  function apiError3(action2, status, body) {
@@ -2557,8 +2557,8 @@ async function appImport(options) {
2557
2557
  const out = options.stdout ?? console;
2558
2558
  const say = options.json ? (line2) => out.error(line2) : (line2) => out.log(line2);
2559
2559
  const { tenant } = resolveTenant(cfg, options.env);
2560
- const text3 = options.file === "-" ? (options.readStdin ?? (() => (0, import_node_fs9.readFileSync)(0, "utf8")))() : (0, import_node_fs9.readFileSync)(options.file, "utf8");
2561
- const { format, sources } = (0, import_import.parseImport)(text3, options.ns);
2560
+ const text4 = options.file === "-" ? (options.readStdin ?? (() => (0, import_node_fs9.readFileSync)(0, "utf8")))() : (0, import_node_fs9.readFileSync)(options.file, "utf8");
2561
+ const { format, sources } = (0, import_import.parseImport)(text4, options.ns);
2562
2562
  if (format === "namespace-map" && options.ns) {
2563
2563
  throw new Error("--ns cannot be combined with a {namespace: rows} file \u2014 the file already names each namespace");
2564
2564
  }
@@ -2769,7 +2769,7 @@ var EXTENSIONS = {
2769
2769
  "text/html": "html",
2770
2770
  "application/json": "json"
2771
2771
  };
2772
- var encode = (text3) => new TextEncoder().encode(text3);
2772
+ var encode = (text4) => new TextEncoder().encode(text4);
2773
2773
  function assetFileName(uuid, mime) {
2774
2774
  const ext = EXTENSIONS[mime.split(";")[0].trim().toLowerCase()] ?? "bin";
2775
2775
  return `${uuid.replace(/[^a-zA-Z0-9._-]/g, "_")}.${ext}`;
@@ -3679,9 +3679,9 @@ async function assertTenantAdminAccess(doFetch, cfg, env, token) {
3679
3679
  }
3680
3680
  throw new Error(`${env}: tenant access preflight (${tenantId}) failed: ${res.status} ${await safeText5(res)}`);
3681
3681
  }
3682
- function errorCode(text3) {
3682
+ function errorCode(text4) {
3683
3683
  try {
3684
- const body = JSON.parse(text3);
3684
+ const body = JSON.parse(text4);
3685
3685
  return typeof body.error?.code === "string" ? body.error.code : null;
3686
3686
  } catch {
3687
3687
  return null;
@@ -4416,15 +4416,15 @@ function readWranglerConfig(path) {
4416
4416
  return null;
4417
4417
  }
4418
4418
  }
4419
- function stripJsonComments(text3) {
4419
+ function stripJsonComments(text4) {
4420
4420
  let result = "";
4421
4421
  let inString = false;
4422
- for (let i = 0; i < text3.length; i++) {
4423
- const ch = text3[i];
4422
+ for (let i = 0; i < text4.length; i++) {
4423
+ const ch = text4[i];
4424
4424
  if (inString) {
4425
4425
  result += ch;
4426
4426
  if (ch === "\\") {
4427
- result += text3[i + 1] ?? "";
4427
+ result += text4[i + 1] ?? "";
4428
4428
  i++;
4429
4429
  } else if (ch === '"') {
4430
4430
  inString = false;
@@ -4436,14 +4436,14 @@ function stripJsonComments(text3) {
4436
4436
  result += ch;
4437
4437
  continue;
4438
4438
  }
4439
- if (ch === "/" && text3[i + 1] === "/") {
4440
- while (i < text3.length && text3[i] !== "\n") i++;
4439
+ if (ch === "/" && text4[i + 1] === "/") {
4440
+ while (i < text4.length && text4[i] !== "\n") i++;
4441
4441
  result += "\n";
4442
4442
  continue;
4443
4443
  }
4444
- if (ch === "/" && text3[i + 1] === "*") {
4444
+ if (ch === "/" && text4[i + 1] === "*") {
4445
4445
  i += 2;
4446
- while (i < text3.length && !(text3[i] === "*" && text3[i + 1] === "/")) i++;
4446
+ while (i < text4.length && !(text4[i] === "*" && text4[i + 1] === "/")) i++;
4447
4447
  i++;
4448
4448
  continue;
4449
4449
  }
@@ -4957,9 +4957,9 @@ function initProject(options) {
4957
4957
  out.log("created src/odla/schema.mjs and src/odla/rules.mjs");
4958
4958
  out.log("updated .gitignore for local odla credentials");
4959
4959
  }
4960
- function writeIfMissing(path, text3) {
4960
+ function writeIfMissing(path, text4) {
4961
4961
  if ((0, import_node_fs14.existsSync)(path)) return;
4962
- (0, import_node_fs14.writeFileSync)(path, text3);
4962
+ (0, import_node_fs14.writeFileSync)(path, text4);
4963
4963
  }
4964
4964
  function configTemplate(input) {
4965
4965
  const calendar = input.services.includes("calendar") ? ` calendar: {
@@ -5171,13 +5171,13 @@ async function secretsSetClerkKey(options) {
5171
5171
  body: JSON.stringify({ value: value2 })
5172
5172
  });
5173
5173
  if (!res.ok) {
5174
- const text3 = scrubValue((await res.text().catch(() => "")).slice(0, 300), value2);
5175
- throw new Error(`store Clerk secret key failed (${res.status}): ${text3 || "request failed"}`);
5174
+ const text4 = scrubValue((await res.text().catch(() => "")).slice(0, 300), value2);
5175
+ throw new Error(`store Clerk secret key failed (${res.status}): ${text4 || "request failed"}`);
5176
5176
  }
5177
5177
  out.log(`Clerk secret key stored for ${tenantId} ($clerk_secret, reserved + write-only; the value was never echoed)`);
5178
5178
  }
5179
- function scrubValue(text3, value2) {
5180
- return redactSecrets(text3).split(value2).join("[value redacted]");
5179
+ function scrubValue(text4, value2) {
5180
+ return redactSecrets(text4).split(value2).join("[value redacted]");
5181
5181
  }
5182
5182
  async function resolveVaultWrite(options) {
5183
5183
  const out = options.stdout ?? console;
@@ -5469,8 +5469,8 @@ ${conflicts.map((f) => ` - ${f}`).join("\n")}`
5469
5469
  harnesses: installations
5470
5470
  };
5471
5471
  }
5472
- function pathsUnder(root, paths) {
5473
- return [...paths].map((path) => (0, import_node_path15.relative)(root, path)).filter((path) => path !== ".." && !path.startsWith(`..${import_node_path15.sep}`) && !(0, import_node_path15.isAbsolute)(path)).sort();
5472
+ function pathsUnder(root, paths2) {
5473
+ return [...paths2].map((path) => (0, import_node_path15.relative)(root, path)).filter((path) => path !== ".." && !path.startsWith(`..${import_node_path15.sep}`) && !(0, import_node_path15.isAbsolute)(path)).sort();
5474
5474
  }
5475
5475
  function normalizeHarnesses(values, global) {
5476
5476
  const requested = values?.length ? values : ["claude"];
@@ -5899,10 +5899,10 @@ var import_node_fs16 = require("fs");
5899
5899
  var import_node_os5 = require("os");
5900
5900
  var import_node_path16 = require("path");
5901
5901
 
5902
- // ../harness/dist/chunk-LNQNFGQC.js
5902
+ // ../harness/dist/chunk-RXNHCGWE.js
5903
5903
  var HARNESS_PROTOCOL_VERSION = 1;
5904
5904
 
5905
- // ../harness/dist/chunk-K76I2TCQ.js
5905
+ // ../harness/dist/chunk-CR6RE3A2.js
5906
5906
  var import_child_process = require("child_process");
5907
5907
  var import_fs = require("fs");
5908
5908
  var import_promises2 = require("fs/promises");
@@ -6154,12 +6154,12 @@ async function gitSourceFiles(sourceDir, maxFiles, maxBytes) {
6154
6154
  });
6155
6155
  if (outputBytes > 8 * 1024 * 1024) throw new Error("git file inventory exceeds 8 MiB");
6156
6156
  if (code !== 0) throw new Error(`git file inventory failed: ${Buffer.concat(stderr2).toString("utf8").slice(0, 1e3)}`);
6157
- const paths = Buffer.concat(stdout).toString("utf8").split("\0").filter(Boolean).sort();
6158
- if (paths.length > maxFiles) throw new Error(`workspace exceeds ${maxFiles} files`);
6157
+ const paths2 = Buffer.concat(stdout).toString("utf8").split("\0").filter(Boolean).sort();
6158
+ if (paths2.length > maxFiles) throw new Error(`workspace exceeds ${maxFiles} files`);
6159
6159
  const root = (0, import_path4.resolve)(sourceDir);
6160
6160
  const files = [];
6161
6161
  let bytes = 0;
6162
- for (const relativePath of paths) {
6162
+ for (const relativePath of paths2) {
6163
6163
  if (!allowedWorkspacePath(relativePath)) continue;
6164
6164
  const source = (0, import_path4.resolve)(root, relativePath);
6165
6165
  if (!source.startsWith(`${root}${import_path4.sep}`)) throw new TypeError("git file path escapes workspace");
@@ -6275,7 +6275,7 @@ async function stageWorkspacePair(baselineSource, workspaceSource, options = {})
6275
6275
  }
6276
6276
  }
6277
6277
 
6278
- // ../harness/dist/chunk-GYWQM76X.js
6278
+ // ../harness/dist/chunk-ISR434K7.js
6279
6279
  var import_crypto = require("crypto");
6280
6280
  var import_promises5 = require("fs/promises");
6281
6281
  var import_path5 = require("path");
@@ -6598,13 +6598,13 @@ function validateSnapshot(snapshot, limits) {
6598
6598
  if (!Number.isSafeInteger(limits.maximumFiles) || limits.maximumFiles < 1 || !Number.isSafeInteger(limits.maximumBytes) || limits.maximumBytes < 1 || snapshot.files.length > limits.maximumFiles) {
6599
6599
  throw new CamelError("limit_exceeded", "Code snapshot exceeds its registered limits.");
6600
6600
  }
6601
- const paths = /* @__PURE__ */ new Set();
6601
+ const paths2 = /* @__PURE__ */ new Set();
6602
6602
  let bytes = 0;
6603
6603
  for (const file of snapshot.files) {
6604
- if (!file.path || file.path.startsWith("/") || file.path.includes("\\") || file.path.split("/").some((part) => !part || part === "." || part === "..") || paths.has(file.path) || typeof file.content !== "string") {
6604
+ if (!file.path || file.path.startsWith("/") || file.path.includes("\\") || file.path.split("/").some((part) => !part || part === "." || part === "..") || paths2.has(file.path) || typeof file.content !== "string") {
6605
6605
  throw new CamelError("state_conflict", "Code snapshot contains an invalid or duplicate path.");
6606
6606
  }
6607
- paths.add(file.path);
6607
+ paths2.add(file.path);
6608
6608
  bytes += utf8Length(file.path) + utf8Length(file.content);
6609
6609
  }
6610
6610
  if (bytes > limits.maximumBytes) {
@@ -6612,7 +6612,7 @@ function validateSnapshot(snapshot, limits) {
6612
6612
  }
6613
6613
  }
6614
6614
 
6615
- // ../harness/dist/chunk-GYWQM76X.js
6615
+ // ../harness/dist/chunk-ISR434K7.js
6616
6616
  var import_child_process4 = require("child_process");
6617
6617
  var import_promises6 = require("fs/promises");
6618
6618
  var import_path6 = require("path");
@@ -6755,8 +6755,8 @@ function boundedInteger(value2, spec) {
6755
6755
  }
6756
6756
  function boundedNumber(value2, spec) {
6757
6757
  if (spec.kind !== "finite_number" || typeof value2 !== "number" || !Number.isFinite(value2) || value2 < spec.minimum || value2 > spec.maximum) throw new CamelError("conversion_rejected", "Finite-number conversion rejected the structured value.");
6758
- const text3 = String(value2);
6759
- if (/e/i.test(text3) || (text3.split(".")[1]?.length ?? 0) > spec.maximumDecimalPlaces) throw new CamelError("conversion_rejected", "Finite-number conversion rejected a non-canonical decimal.");
6758
+ const text4 = String(value2);
6759
+ if (/e/i.test(text4) || (text4.split(".")[1]?.length ?? 0) > spec.maximumDecimalPlaces) throw new CamelError("conversion_rejected", "Finite-number conversion rejected a non-canonical decimal.");
6760
6760
  return value2;
6761
6761
  }
6762
6762
  function enumMember(value2, spec) {
@@ -6912,11 +6912,11 @@ function validateUnsafeSelector(path, value2, tool) {
6912
6912
  return void 0;
6913
6913
  }
6914
6914
  function looksLikeDestination(value2) {
6915
- const text3 = value2.trim();
6916
- return /^(?:[a-z][a-z0-9+.-]*:\/\/|\/|\\\\)/i.test(text3) || /^[\w.-]+\.[a-z]{2,}(?:[/:]|$)/i.test(text3);
6915
+ const text4 = value2.trim();
6916
+ return /^(?:[a-z][a-z0-9+.-]*:\/\/|\/|\\\\)/i.test(text4) || /^[\w.-]+\.[a-z]{2,}(?:[/:]|$)/i.test(text4);
6917
6917
  }
6918
6918
 
6919
- // ../harness/dist/chunk-GYWQM76X.js
6919
+ // ../harness/dist/chunk-ISR434K7.js
6920
6920
  var import_promises10 = require("fs/promises");
6921
6921
  var import_promises11 = require("fs/promises");
6922
6922
  var import_path10 = require("path");
@@ -7081,9 +7081,9 @@ async function extractImports(builder, input) {
7081
7081
  const sources = input.paths.filter(isSourcePath);
7082
7082
  const known = new Set(sources);
7083
7083
  for (const path of sources) {
7084
- let text3;
7084
+ let text4;
7085
7085
  try {
7086
- text3 = await input.read(path);
7086
+ text4 = await input.read(path);
7087
7087
  } catch {
7088
7088
  continue;
7089
7089
  }
@@ -7091,13 +7091,13 @@ async function extractImports(builder, input) {
7091
7091
  const file = builder.node(FILE, path, pkg ? { pkg } : void 0);
7092
7092
  if (pkg) builder.edge(builder.node(PACKAGE, pkg), CONTAINS, file);
7093
7093
  const specifiers = /* @__PURE__ */ new Set();
7094
- for (const match of text3.matchAll(IMPORT_FROM)) specifiers.add(match[1]);
7095
- for (const match of text3.matchAll(BARE_IMPORT)) specifiers.add(match[1]);
7094
+ for (const match of text4.matchAll(IMPORT_FROM)) specifiers.add(match[1]);
7095
+ for (const match of text4.matchAll(BARE_IMPORT)) specifiers.add(match[1]);
7096
7096
  for (const specifier of specifiers) {
7097
7097
  const resolved = resolveImport(path, specifier, known);
7098
7098
  if (resolved) builder.edge(file, IMPORTS, nodeId(FILE, resolved));
7099
7099
  }
7100
- for (const name of exportedNames(text3)) {
7100
+ for (const name of exportedNames(text4)) {
7101
7101
  builder.edge(file, EXPORTS, builder.node(SYMBOL, name));
7102
7102
  }
7103
7103
  }
@@ -7138,16 +7138,16 @@ async function extractData(builder, input) {
7138
7138
  };
7139
7139
  for (const path of input.paths) {
7140
7140
  if (!SOURCE_FILE.test(path) || input.ignore?.(path)) continue;
7141
- let text3;
7141
+ let text4;
7142
7142
  try {
7143
- text3 = await input.read(path);
7143
+ text4 = await input.read(path);
7144
7144
  } catch {
7145
7145
  continue;
7146
7146
  }
7147
- for (const statement of text3.matchAll(STATEMENT)) {
7147
+ for (const statement of text4.matchAll(STATEMENT)) {
7148
7148
  const verb = statement[1].toUpperCase().replace(/\s+/g, " ");
7149
7149
  const start = statement.index ?? 0;
7150
- const rest = text3.slice(start + statement[0].length, start + STATEMENT_WINDOW);
7150
+ const rest = text4.slice(start + statement[0].length, start + STATEMENT_WINDOW);
7151
7151
  if (verb === "SELECT") {
7152
7152
  for (const read3 of rest.matchAll(READ_TABLES)) touch(path, read3[1].toLowerCase(), TABLE, READS);
7153
7153
  continue;
@@ -7163,16 +7163,16 @@ async function extractData(builder, input) {
7163
7163
  for (const read3 of rest.matchAll(READ_TABLES)) touch(path, read3[1].toLowerCase(), TABLE, READS);
7164
7164
  }
7165
7165
  }
7166
- for (const match of text3.matchAll(NS_CONST)) {
7167
- touch(path, `${match[1]}.${match[2]}`, NAMESPACE, accessFor(text3, match.index ?? 0));
7166
+ for (const match of text4.matchAll(NS_CONST)) {
7167
+ touch(path, `${match[1]}.${match[2]}`, NAMESPACE, accessFor(text4, match.index ?? 0));
7168
7168
  }
7169
- for (const match of text3.matchAll(NS_LITERAL)) {
7170
- touch(path, match[1], NAMESPACE, accessFor(text3, match.index ?? 0));
7169
+ for (const match of text4.matchAll(NS_LITERAL)) {
7170
+ touch(path, match[1], NAMESPACE, accessFor(text4, match.index ?? 0));
7171
7171
  }
7172
7172
  }
7173
7173
  }
7174
- function accessFor(text3, index) {
7175
- const window = text3.slice(Math.max(0, index - 160), index + 40);
7174
+ function accessFor(text4, index) {
7175
+ const window = text4.slice(Math.max(0, index - 160), index + 40);
7176
7176
  return /\b(?:transact|update|delete|create|insert|Ops)\b/.test(window) ? WRITES : READS;
7177
7177
  }
7178
7178
  async function buildCodeGraph(input) {
@@ -7184,7 +7184,7 @@ async function buildCodeGraph(input) {
7184
7184
  return builder.build();
7185
7185
  }
7186
7186
 
7187
- // ../harness/dist/chunk-GYWQM76X.js
7187
+ // ../harness/dist/chunk-ISR434K7.js
7188
7188
  var import_crypto4 = require("crypto");
7189
7189
  async function digestStagedWorkspace(root, limits) {
7190
7190
  const files = [];
@@ -7512,7 +7512,7 @@ function validateCodePatch(rawPatch, maxBytes) {
7512
7512
  if (FORBIDDEN.test(patch2) || /(?:old|new)(?: file)? mode 120000/.test(patch2)) {
7513
7513
  throw new TypeError("patch uses a forbidden binary, link, mode, rename, or copy operation");
7514
7514
  }
7515
- const paths = [];
7515
+ const paths2 = [];
7516
7516
  const lines = patch2.split("\n");
7517
7517
  for (let index = 0; index < lines.length; index += 1) {
7518
7518
  const line2 = lines[index];
@@ -7528,10 +7528,10 @@ function validateCodePatch(rawPatch, maxBytes) {
7528
7528
  if (!validHeaderPath(oldPath, path, "a") || !validHeaderPath(newPath, path, "b")) {
7529
7529
  throw new TypeError("patch file headers do not match the declared path");
7530
7530
  }
7531
- paths.push(path);
7531
+ paths2.push(path);
7532
7532
  }
7533
- if (!paths.length || new Set(paths).size !== paths.length) throw new TypeError("patch has no diffs or repeats a path");
7534
- return paths;
7533
+ if (!paths2.length || new Set(paths2).size !== paths2.length) throw new TypeError("patch has no diffs or repeats a path");
7534
+ return paths2;
7535
7535
  }
7536
7536
  function validHeaderPath(value2, path, prefix) {
7537
7537
  return value2 === "/dev/null" || value2 === `${prefix}/${path}`;
@@ -7556,11 +7556,11 @@ function describePatchFailure(patch2, detail) {
7556
7556
  const hint = hunks.length > 0 && contextless ? " A hunk has no context lines; include at least one unchanged line above or below each change." : "";
7557
7557
  return `patch did not apply: ${detail}${hint}`;
7558
7558
  }
7559
- async function applyCodePatch(workspaceDir, rawPatch, paths) {
7559
+ async function applyCodePatch(workspaceDir, rawPatch, paths2) {
7560
7560
  const patch2 = stripPatchEnvelope(rawPatch);
7561
7561
  await gitApply(workspaceDir, patch2, true);
7562
7562
  await gitApply(workspaceDir, patch2, false);
7563
- for (const path of paths) {
7563
+ for (const path of paths2) {
7564
7564
  try {
7565
7565
  const info = await (0, import_promises6.lstat)(resolveCodePath(workspaceDir, path));
7566
7566
  if (info.isSymbolicLink() || !info.isFile() && !info.isDirectory()) {
@@ -7582,8 +7582,8 @@ function gitApply(cwd, patch2, check) {
7582
7582
  });
7583
7583
  let stderr2 = "";
7584
7584
  child.stderr.setEncoding("utf8");
7585
- child.stderr.on("data", (text3) => {
7586
- if (stderr2.length < 4e3) stderr2 += text3.slice(0, 4e3);
7585
+ child.stderr.on("data", (text22) => {
7586
+ if (stderr2.length < 4e3) stderr2 += text22.slice(0, 4e3);
7587
7587
  });
7588
7588
  child.once("error", reject);
7589
7589
  child.once("exit", (code) => code === 0 ? accept() : reject(new TypeError(describePatchFailure(patch2, stderr2.trim().slice(0, 500)))));
@@ -7607,8 +7607,8 @@ async function restoreCodeWorkspaceCheckpoint(input) {
7607
7607
  const workspace = await stageWorkspace(input.trustedBaseDir, input.stage);
7608
7608
  try {
7609
7609
  if (checkpoint.patch) {
7610
- const paths = validateCodePatch(checkpoint.patch, 256 * 1024);
7611
- await applyCodePatch(workspace.workspaceDir, checkpoint.patch, paths);
7610
+ const paths2 = validateCodePatch(checkpoint.patch, 256 * 1024);
7611
+ await applyCodePatch(workspace.workspaceDir, checkpoint.patch, paths2);
7612
7612
  }
7613
7613
  return { workspace, checkpoint };
7614
7614
  } catch (error) {
@@ -7757,8 +7757,8 @@ async function verifyCodeCandidate(input) {
7757
7757
  try {
7758
7758
  const baseDigest = await digestStagedWorkspace(staged.workspaceDir, limits);
7759
7759
  if (baseDigest !== input.trustedBaseDigest) throw new TypeError("trusted base does not match its registered digest");
7760
- const paths = validateCodePatch(input.candidatePatch, policy.maximumPatchBytes);
7761
- await applyCodePatch(staged.workspaceDir, input.candidatePatch, paths);
7760
+ const paths2 = validateCodePatch(input.candidatePatch, policy.maximumPatchBytes);
7761
+ await applyCodePatch(staged.workspaceDir, input.candidatePatch, paths2);
7762
7762
  const sourceDigest = await digestStagedWorkspace(staged.workspaceDir, limits);
7763
7763
  const policyDigest = digestPolicy(policy);
7764
7764
  const patchDigest = digestBytes(input.candidatePatch);
@@ -7767,7 +7767,7 @@ async function verifyCodeCandidate(input) {
7767
7767
  trustedBaseDigest: input.trustedBaseDigest,
7768
7768
  patchDigest
7769
7769
  });
7770
- const changedTests = changedTestPaths(paths, policy);
7770
+ const changedTests = changedTestPaths(paths2, policy);
7771
7771
  if (changedTests.length > policy.maximumChangedTests) throw new TypeError("candidate changes too many test files");
7772
7772
  const recipes = [];
7773
7773
  const logs = [];
@@ -7834,8 +7834,8 @@ function validate2(input) {
7834
7834
  }
7835
7835
  return result;
7836
7836
  }
7837
- function changedTestPaths(paths, policy) {
7838
- return paths.filter((path) => policy.testPathSuffixes.some((suffix) => path.endsWith(suffix)) || policy.testPathPrefixes.some((prefix) => path.startsWith(prefix) || path.includes(`/${prefix}`))).sort();
7837
+ function changedTestPaths(paths2, policy) {
7838
+ return paths2.filter((path) => policy.testPathSuffixes.some((suffix) => path.endsWith(suffix)) || policy.testPathPrefixes.some((prefix) => path.startsWith(prefix) || path.includes(`/${prefix}`))).sort();
7839
7839
  }
7840
7840
  function recipeReceipt(recipe2, result, artifacts) {
7841
7841
  const status = result.timedOut ? "timed_out" : result.outputLimitExceeded ? "output_limited" : result.exitCode === 0 && artifacts.every((item) => item.status === "verified") ? "passed" : "failed";
@@ -8566,7 +8566,7 @@ function createWorkspaceFileRegistry(limit = DEFAULT_MAX_FILES, enumerate = regi
8566
8566
  files(root) {
8567
8567
  const existing = cache2.get(root);
8568
8568
  if (existing) return existing;
8569
- const pending = enumerate(root, limit).then((paths) => Object.freeze(paths));
8569
+ const pending = enumerate(root, limit).then((paths2) => Object.freeze(paths2));
8570
8570
  cache2.set(root, pending);
8571
8571
  void pending.catch(() => {
8572
8572
  if (cache2.get(root) === pending) cache2.delete(root);
@@ -8579,7 +8579,7 @@ function createWorkspaceFileRegistry(limit = DEFAULT_MAX_FILES, enumerate = regi
8579
8579
  };
8580
8580
  }
8581
8581
  async function registeredFiles(root, limit = DEFAULT_MAX_FILES) {
8582
- const paths = [];
8582
+ const paths2 = [];
8583
8583
  const walk = async (directory) => {
8584
8584
  for (const entry of await (0, import_promises9.readdir)(directory, { withFileTypes: true })) {
8585
8585
  if (SKIP_WORKSPACE_DIRS.has(entry.name)) continue;
@@ -8593,26 +8593,26 @@ async function registeredFiles(root, limit = DEFAULT_MAX_FILES) {
8593
8593
  } catch {
8594
8594
  continue;
8595
8595
  }
8596
- paths.push(path);
8597
- if (paths.length > limit) throw new TypeError("workspace file registry exceeds its bound");
8596
+ paths2.push(path);
8597
+ if (paths2.length > limit) throw new TypeError("workspace file registry exceeds its bound");
8598
8598
  }
8599
8599
  }
8600
8600
  };
8601
8601
  await walk((0, import_path9.resolve)(root));
8602
- return paths.sort();
8602
+ return paths2.sort();
8603
8603
  }
8604
- function listWorkspace(paths, options = {}) {
8604
+ function listWorkspace(paths2, options = {}) {
8605
8605
  const max = options.maxEntries ?? 1e3;
8606
8606
  const prefix = options.prefix?.replace(/\/+$/, "");
8607
- const scoped = prefix ? paths.filter((path) => path === prefix || path.startsWith(`${prefix}/`)) : [...paths];
8607
+ const scoped = prefix ? paths2.filter((path) => path === prefix || path.startsWith(`${prefix}/`)) : [...paths2];
8608
8608
  return scoped.slice(0, max);
8609
8609
  }
8610
- async function searchWorkspace(root, paths, options) {
8610
+ async function searchWorkspace(root, paths2, options) {
8611
8611
  options.signal?.throwIfAborted();
8612
8612
  if (!options.query) throw new TypeError("search query must be a non-empty string");
8613
8613
  const maxResults = options.maxResults ?? DEFAULT_MAX_RESULTS;
8614
8614
  const maxFileBytes = options.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES;
8615
- const scoped = listWorkspace(paths, { ...options.prefix ? { prefix: options.prefix } : {}, maxEntries: paths.length });
8615
+ const scoped = listWorkspace(paths2, { ...options.prefix ? { prefix: options.prefix } : {}, maxEntries: paths2.length });
8616
8616
  if (scoped.length === 0) return [];
8617
8617
  try {
8618
8618
  return await nativeSearch(root, scoped, { ...options, maxResults, maxFileBytes });
@@ -8622,11 +8622,11 @@ async function searchWorkspace(root, paths, options) {
8622
8622
  }
8623
8623
  }
8624
8624
  var MAX_NATIVE_ARG_BYTES = 96 * 1024;
8625
- async function nativeSearch(root, paths, options) {
8625
+ async function nativeSearch(root, paths2, options) {
8626
8626
  const batches = [];
8627
8627
  let batch = [];
8628
8628
  let bytes = 0;
8629
- for (const path of paths) {
8629
+ for (const path of paths2) {
8630
8630
  const size = Buffer.byteLength(path) + 1;
8631
8631
  if (batch.length > 0 && bytes + size > MAX_NATIVE_ARG_BYTES) {
8632
8632
  batches.push(batch);
@@ -8645,7 +8645,7 @@ async function nativeSearch(root, paths, options) {
8645
8645
  }
8646
8646
  return matches;
8647
8647
  }
8648
- function nativeSearchBatch(root, paths, options, remaining) {
8648
+ function nativeSearchBatch(root, paths2, options, remaining) {
8649
8649
  return new Promise((resolveMatches, reject) => {
8650
8650
  const args = [
8651
8651
  "--fixed-strings",
@@ -8658,7 +8658,7 @@ function nativeSearchBatch(root, paths, options, remaining) {
8658
8658
  options.caseSensitive === false ? "--ignore-case" : "--case-sensitive",
8659
8659
  "--",
8660
8660
  options.query,
8661
- ...paths
8661
+ ...paths2
8662
8662
  ];
8663
8663
  const child = (0, import_child_process6.spawn)("rg", args, {
8664
8664
  cwd: root,
@@ -8844,16 +8844,16 @@ function createCodePolicyGate(options) {
8844
8844
  }
8845
8845
  };
8846
8846
  }
8847
- function directoryPrefixes(paths) {
8847
+ function directoryPrefixes(paths2) {
8848
8848
  const prefixes = /* @__PURE__ */ new Set(["."]);
8849
- for (const path of paths) {
8849
+ for (const path of paths2) {
8850
8850
  const parts = path.split("/");
8851
8851
  for (let index = 1; index < parts.length; index += 1) prefixes.add(parts.slice(0, index).join("/"));
8852
8852
  }
8853
8853
  return [...prefixes].sort();
8854
8854
  }
8855
- async function safePrefix(base, paths, prefix) {
8856
- const prefixes = directoryPrefixes(paths);
8855
+ async function safePrefix(base, paths2, prefix) {
8856
+ const prefixes = directoryPrefixes(paths2);
8857
8857
  const conversions = await conversionRegistry(
8858
8858
  [await registeredPolicy("code.prefix.v1", "code.prefixes.v1", prefixes)],
8859
8859
  { "code.prefixes.v1": prefixes }
@@ -8965,7 +8965,7 @@ function response(request3, ok, content2, details) {
8965
8965
  return { requestId: request3.requestId, ok, content: content2, ...details ? { details } : {} };
8966
8966
  }
8967
8967
  var cache = /* @__PURE__ */ new Map();
8968
- function workspaceGraphs(workspaceDir, paths) {
8968
+ function workspaceGraphs(workspaceDir, paths2) {
8969
8969
  const existing = cache.get(workspaceDir);
8970
8970
  if (existing) return existing;
8971
8971
  const read22 = (path) => (0, import_promises11.readFile)((0, import_path10.join)(workspaceDir, path), "utf8");
@@ -8973,7 +8973,7 @@ function workspaceGraphs(workspaceDir, paths) {
8973
8973
  // No knownTables: a staged workspace may not carry migrations, and a filter
8974
8974
  // that silently drops every table is worse than an unfiltered one. Callers
8975
8975
  // with ground truth should build the graph themselves.
8976
- graph: await buildCodeGraph({ paths, read: read22, data: { ignore: (path) => path.includes(".generated.") } })
8976
+ graph: await buildCodeGraph({ paths: paths2, read: read22, data: { ignore: (path) => path.includes(".generated.") } })
8977
8977
  }))();
8978
8978
  cache.set(workspaceDir, built);
8979
8979
  return built;
@@ -9033,11 +9033,11 @@ async function read(context, request3, options, policy, registry) {
9033
9033
  if (endLine < startLine || endLine - startLine + 1 > (options.maxReadLines ?? 2e3)) {
9034
9034
  throw new TypeError("requested line range exceeds its bound");
9035
9035
  }
9036
- const paths = await registry.files(context.workspaceDir);
9037
- if (!paths.includes(path)) {
9036
+ const paths2 = await registry.files(context.workspaceDir);
9037
+ if (!paths2.includes(path)) {
9038
9038
  throw new TypeError(`no such file in the staged workspace: "${path}". Use sandbox.overview, sandbox.where_is or sandbox.search to find the correct path.`);
9039
9039
  }
9040
- const allowed = await policy.read(policyContext(context, request3, options, { paths, path, startLine, endLine }));
9040
+ const allowed = await policy.read(policyContext(context, request3, options, { paths: paths2, path, startLine, endLine }));
9041
9041
  if (!allowed) return response(request3, false, "tool denied by CaMeL policy");
9042
9042
  const target = resolveCodePath(context.workspaceDir, path);
9043
9043
  const info = await (0, import_promises10.stat)(target);
@@ -9059,16 +9059,16 @@ async function list(context, request3, options, policy, registry) {
9059
9059
  const prefix = typeof raw === "string" && raw.length > 0 ? raw : void 0;
9060
9060
  const maxEntries = optionalInteger(request3.input.maxEntries) ?? 1e3;
9061
9061
  if (maxEntries > 5e3) throw new TypeError("maxEntries exceeds its bound");
9062
- const paths = await registry.files(context.workspaceDir);
9063
- const allowed = await policy.list(policyContext(context, request3, options, { paths, ...prefix ? { prefix } : {} }));
9062
+ const paths2 = await registry.files(context.workspaceDir);
9063
+ const allowed = await policy.list(policyContext(context, request3, options, { paths: paths2, ...prefix ? { prefix } : {} }));
9064
9064
  if (!allowed) return response(request3, false, "tool denied by CaMeL policy");
9065
- const entries = listWorkspace(paths, { ...prefix ? { prefix } : {}, maxEntries });
9065
+ const entries = listWorkspace(paths2, { ...prefix ? { prefix } : {}, maxEntries });
9066
9066
  if (!entries.length) {
9067
9067
  return response(request3, true, prefix ? `No files under "${prefix}".` : "Workspace is empty.", { count: 0 });
9068
9068
  }
9069
- const truncated = entries.length < paths.length && entries.length === maxEntries;
9070
- const hint = !prefix && paths.length > 500 ? `
9071
- \u2026 ${paths.length} files total. sandbox.overview is far cheaper for orientation; use a prefix here once you know the area.` : "";
9069
+ const truncated = entries.length < paths2.length && entries.length === maxEntries;
9070
+ const hint = !prefix && paths2.length > 500 ? `
9071
+ \u2026 ${paths2.length} files total. sandbox.overview is far cheaper for orientation; use a prefix here once you know the area.` : "";
9072
9072
  return response(
9073
9073
  request3,
9074
9074
  true,
@@ -9086,10 +9086,10 @@ async function search(context, request3, options, policy, registry) {
9086
9086
  const maxResults = optionalInteger(request3.input.maxResults) ?? 100;
9087
9087
  if (maxResults > 500) throw new TypeError("maxResults exceeds its bound");
9088
9088
  const caseSensitive = request3.input.caseSensitive === void 0 ? true : request3.input.caseSensitive === true;
9089
- const paths = await registry.files(context.workspaceDir);
9090
- const allowed = await policy.search(policyContext(context, request3, options, { paths, query, ...prefix ? { prefix } : {} }));
9089
+ const paths2 = await registry.files(context.workspaceDir);
9090
+ const allowed = await policy.search(policyContext(context, request3, options, { paths: paths2, query, ...prefix ? { prefix } : {} }));
9091
9091
  if (!allowed) return response(request3, false, "tool denied by CaMeL policy");
9092
- const matches = await searchWorkspace(context.workspaceDir, paths, {
9092
+ const matches = await searchWorkspace(context.workspaceDir, paths2, {
9093
9093
  query,
9094
9094
  maxResults,
9095
9095
  caseSensitive,
@@ -9111,8 +9111,8 @@ async function graphQuery(context, request3, options, policy, registry) {
9111
9111
  selector: query
9112
9112
  }));
9113
9113
  if (!allowed) return response(request3, false, "tool denied by CaMeL policy");
9114
- const paths = await registry.files(context.workspaceDir);
9115
- const graphs = await workspaceGraphs(context.workspaceDir, paths);
9114
+ const paths2 = await registry.files(context.workspaceDir);
9115
+ const graphs = await workspaceGraphs(context.workspaceDir, paths2);
9116
9116
  if (request3.tool === "sandbox.overview") {
9117
9117
  return response(request3, true, renderOverview(graphs, query || void 0));
9118
9118
  }
@@ -9174,16 +9174,16 @@ function toolFailureMessage(reason) {
9174
9174
  async function patch(context, request3, options, policy, registry) {
9175
9175
  exactKeys(request3.input, ["patch"]);
9176
9176
  const value2 = stringField(request3.input, "patch");
9177
- const paths = validateCodePatch(value2, options.maxPatchBytes ?? 256 * 1024);
9178
- if (paths.some((path) => options.readOnlyPrefixes?.some((prefix) => path === prefix || path.startsWith(`${prefix}/`)))) {
9177
+ const paths2 = validateCodePatch(value2, options.maxPatchBytes ?? 256 * 1024);
9178
+ if (paths2.some((path) => options.readOnlyPrefixes?.some((prefix) => path === prefix || path.startsWith(`${prefix}/`)))) {
9179
9179
  throw new TypeError("patch targets a read-only reference source");
9180
9180
  }
9181
9181
  const allowed = await policy.patch(policyContext(context, request3, options, { patch: value2 }));
9182
9182
  if (!allowed) return response(request3, false, "tool denied by CaMeL policy");
9183
- await applyCodePatch(context.workspaceDir, value2, paths);
9183
+ await applyCodePatch(context.workspaceDir, value2, paths2);
9184
9184
  registry.invalidate(context.workspaceDir);
9185
9185
  forgetWorkspaceGraphs(context.workspaceDir);
9186
- return response(request3, true, `Applied patch to ${paths.length} file(s).`, { paths });
9186
+ return response(request3, true, `Applied patch to ${paths2.length} file(s).`, { paths: paths2 });
9187
9187
  }
9188
9188
  async function recipe(context, request3, options, recipes, policy) {
9189
9189
  exactKeys(request3.input, ["recipeId"]);
@@ -9532,11 +9532,126 @@ async function startGoalPursuit(input) {
9532
9532
  async function appendCodeRuntimeEvent(control, command, event, refs) {
9533
9533
  const eventId = `${command.commandId.slice(0, 45)}:${refs.length + 1}`;
9534
9534
  refs.push(eventId);
9535
- const bounded = event.type === "message" ? { ...event, body: event.body.trim().slice(0, 2e4) || `${event.actor} event` } : event;
9535
+ const attributed = { ...event, interactionId: command.commandId };
9536
+ const bounded = attributed.type === "message" ? { ...attributed, body: attributed.body.trim().slice(0, 2e4) || `${attributed.actor} event` } : attributed;
9536
9537
  await control.appendSessionEvent(command.sessionId, eventId, bounded);
9537
9538
  }
9538
9539
  var digestRuntimeValue = (value2) => `sha256:${(0, import_crypto4.createHash)("sha256").update(value2).digest("hex")}`;
9539
9540
  var runtimeErrorMessage = (value2) => value2 instanceof Error ? value2.message : String(value2);
9541
+ var text3 = (value2, maximum) => {
9542
+ if (typeof value2 !== "string") return void 0;
9543
+ const bounded = value2.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g, " ").trim();
9544
+ return bounded ? bounded.slice(0, maximum) : void 0;
9545
+ };
9546
+ var integer2 = (value2) => Number.isSafeInteger(value2) && Number(value2) >= 0 ? Number(value2) : void 0;
9547
+ var record32 = (value2) => value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : void 0;
9548
+ var excerpt = (value2, tail = false) => {
9549
+ if (typeof value2 !== "string") return void 0;
9550
+ const safe = value2.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g, " ");
9551
+ const source = (tail ? safe.slice(-1e4) : safe.slice(0, 1e4)).trim();
9552
+ if (!source) return void 0;
9553
+ const lines = source.split("\n").filter((line2) => line2.trim()).map((line2) => line2.slice(0, 240));
9554
+ const selected = tail ? lines.slice(-10) : lines.slice(0, 10);
9555
+ return text3(selected.join("\n"), 2400);
9556
+ };
9557
+ var paths = (value2) => {
9558
+ if (!Array.isArray(value2)) return void 0;
9559
+ const items = value2.flatMap((item) => {
9560
+ const path = text3(item, 1024);
9561
+ return path ? [path] : [];
9562
+ }).slice(0, 12);
9563
+ return items.length ? items : void 0;
9564
+ };
9565
+ function patchStats(value2) {
9566
+ if (typeof value2 !== "string") return {};
9567
+ let additions = 0;
9568
+ let deletions = 0;
9569
+ for (const line2 of value2.slice(0, 262144).split("\n")) {
9570
+ if (line2.startsWith("+++") || line2.startsWith("---")) continue;
9571
+ if (line2.startsWith("+")) additions += 1;
9572
+ else if (line2.startsWith("-")) deletions += 1;
9573
+ }
9574
+ return { ...additions ? { additions } : {}, ...deletions ? { deletions } : {} };
9575
+ }
9576
+ function searchResults(value2) {
9577
+ if (typeof value2 !== "string") return void 0;
9578
+ const results = value2.split("\n").flatMap((line2) => {
9579
+ const match = /^([^:\n]{1,1024}):(\d+):\s?(.*)$/.exec(line2);
9580
+ if (!match) return [];
9581
+ const lineNumber = Number(match[2]);
9582
+ const itemText = text3(match[3], 240);
9583
+ if (!Number.isSafeInteger(lineNumber) || lineNumber < 1) return [];
9584
+ return [{ path: match[1], line: lineNumber, ...itemText ? { text: itemText } : {} }];
9585
+ }).slice(0, 5);
9586
+ return results.length ? results : void 0;
9587
+ }
9588
+ function codeToolRequestPresentation(request3) {
9589
+ const input = request3.input;
9590
+ if (request3.tool === "sandbox.read") {
9591
+ const path = text3(input.path, 1024);
9592
+ if (!path) return void 0;
9593
+ const startLine = integer2(input.startLine);
9594
+ const endLine = integer2(input.endLine);
9595
+ return { kind: "read", path, ...startLine ? { startLine } : {}, ...endLine ? { endLine } : {} };
9596
+ }
9597
+ if (request3.tool === "sandbox.list") {
9598
+ const scope = text3(input.prefix, 1024);
9599
+ return { kind: "list", ...scope ? { scope } : {} };
9600
+ }
9601
+ if (request3.tool === "sandbox.search" || request3.tool === "sandbox.overview" || request3.tool === "sandbox.where_is" || request3.tool === "sandbox.who_imports" || request3.tool === "sandbox.who_touches") {
9602
+ const query = text3(input.query, 512);
9603
+ const scope = request3.tool === "sandbox.search" ? text3(input.prefix, 1024) : void 0;
9604
+ if (request3.tool === "sandbox.search" && !query) return void 0;
9605
+ return { kind: "query", ...query ? { query } : {}, ...scope ? { scope } : {} };
9606
+ }
9607
+ if (request3.tool === "sandbox.apply_patch") {
9608
+ return { kind: "patch", ...patchStats(input.patch) };
9609
+ }
9610
+ const recipeId = text3(input.recipeId, 120);
9611
+ return recipeId ? { kind: "recipe", recipeId } : void 0;
9612
+ }
9613
+ function codeToolResultPresentation(request3, response2) {
9614
+ const started = codeToolRequestPresentation(request3);
9615
+ if (!started || !response2.ok) return started;
9616
+ const details = record32(response2.details);
9617
+ if (started.kind === "read") {
9618
+ return {
9619
+ ...started,
9620
+ ...integer2(details?.startLine) ? { startLine: integer2(details?.startLine) } : {},
9621
+ ...integer2(details?.endLine) ? { endLine: integer2(details?.endLine) } : {},
9622
+ ...excerpt(response2.content) ? { excerpt: excerpt(response2.content) } : {}
9623
+ };
9624
+ }
9625
+ if (started.kind === "list") {
9626
+ const listed = response2.content.split("\n").filter((line2) => line2 && !line2.startsWith("\u2026") && !line2.startsWith("Workspace ")).map((line2) => text3(line2, 1024)).filter((line2) => Boolean(line2)).slice(0, 8);
9627
+ return {
9628
+ ...started,
9629
+ ...integer2(details?.count) !== void 0 ? { count: integer2(details?.count) } : {},
9630
+ ...listed.length ? { paths: listed } : {}
9631
+ };
9632
+ }
9633
+ if (started.kind === "query") {
9634
+ const results = request3.tool === "sandbox.search" ? searchResults(response2.content) : void 0;
9635
+ const resultExcerpt = request3.tool === "sandbox.search" ? void 0 : excerpt(response2.content);
9636
+ return {
9637
+ ...started,
9638
+ ...integer2(details?.count) !== void 0 ? { count: integer2(details?.count) } : {},
9639
+ ...results ? { results } : {},
9640
+ ...resultExcerpt ? { excerpt: resultExcerpt } : {}
9641
+ };
9642
+ }
9643
+ if (started.kind === "patch") {
9644
+ return { ...started, ...paths(details?.paths) ? { paths: paths(details?.paths) } : {} };
9645
+ }
9646
+ const output = response2.content.replace(/^Recipe [^\n]*\.?\s*/u, "");
9647
+ return {
9648
+ ...started,
9649
+ ...integer2(details?.exitCode) !== void 0 ? { exitCode: integer2(details?.exitCode) } : {},
9650
+ ...typeof details?.timedOut === "boolean" ? { timedOut: details.timedOut } : {},
9651
+ ...typeof details?.outputLimitExceeded === "boolean" ? { outputLimitExceeded: details.outputLimitExceeded } : {},
9652
+ ...excerpt(output, true) ? { excerpt: excerpt(output, true) } : {}
9653
+ };
9654
+ }
9540
9655
  var TheseusRuntimeEngine = class {
9541
9656
  constructor(options) {
9542
9657
  this.options = options;
@@ -9770,18 +9885,29 @@ var TheseusRuntimeEngine = class {
9770
9885
  return {
9771
9886
  execute: async (context, request3) => {
9772
9887
  const startedAt = Date.now();
9888
+ const operationId = digestRuntimeValue(`${command.commandId}:${request3.requestId}`);
9889
+ const startedPresentation = codeToolRequestPresentation(request3);
9773
9890
  await this.#event(
9774
9891
  command,
9775
- { type: "tool", phase: "started", tool: request3.tool },
9892
+ {
9893
+ type: "tool",
9894
+ phase: "started",
9895
+ tool: request3.tool,
9896
+ operationId,
9897
+ ...startedPresentation ? { presentation: startedPresentation } : {}
9898
+ },
9776
9899
  active.conversationRefs
9777
9900
  ).catch(() => void 0);
9778
9901
  const response2 = await broker.execute(context, request3);
9902
+ const completedPresentation = codeToolResultPresentation(request3, response2);
9779
9903
  await this.#event(command, {
9780
9904
  type: "tool",
9781
9905
  phase: "completed",
9782
9906
  tool: request3.tool,
9783
9907
  ok: response2.ok,
9784
- durationMs: Date.now() - startedAt
9908
+ durationMs: Date.now() - startedAt,
9909
+ operationId,
9910
+ ...completedPresentation ? { presentation: completedPresentation } : {}
9785
9911
  }, active.conversationRefs).catch(() => void 0);
9786
9912
  return response2;
9787
9913
  }
@@ -11815,8 +11941,8 @@ function collectFields(parsed, allowClear) {
11815
11941
  if (allowClear) out[spec.key] = null;
11816
11942
  continue;
11817
11943
  }
11818
- const text3 = stringOpt(value2);
11819
- out[spec.key] = spec.num ? Number(text3) : text3;
11944
+ const text4 = stringOpt(value2);
11945
+ out[spec.key] = spec.num ? Number(text4) : text4;
11820
11946
  }
11821
11947
  return out;
11822
11948
  }
@@ -13228,14 +13354,14 @@ function statusMinutes(value2) {
13228
13354
  }
13229
13355
  async function read2(url, headers, doFetch) {
13230
13356
  const response2 = await doFetch(url, { headers });
13231
- const text3 = await response2.text();
13357
+ const text4 = await response2.text();
13232
13358
  let body = {};
13233
- if (text3) {
13359
+ if (text4) {
13234
13360
  try {
13235
- const value2 = JSON.parse(text3);
13361
+ const value2 = JSON.parse(text4);
13236
13362
  body = value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : { value: value2 };
13237
13363
  } catch {
13238
- body = { message: text3.slice(0, 300) };
13364
+ body = { message: text4.slice(0, 300) };
13239
13365
  }
13240
13366
  }
13241
13367
  return { httpStatus: response2.status, body };
@@ -13465,13 +13591,13 @@ async function monitorCommand(parsed, deps = {}) {
13465
13591
  }
13466
13592
  async function request2(url, init, doFetch) {
13467
13593
  const response2 = await doFetch(url, init);
13468
- const text3 = await response2.text();
13594
+ const text4 = await response2.text();
13469
13595
  let body = {};
13470
13596
  try {
13471
- const parsed = text3 ? JSON.parse(text3) : {};
13597
+ const parsed = text4 ? JSON.parse(text4) : {};
13472
13598
  body = record10(parsed) ? parsed : { value: parsed };
13473
13599
  } catch {
13474
- body = { message: text3.slice(0, 500) };
13600
+ body = { message: text4.slice(0, 500) };
13475
13601
  }
13476
13602
  if (!response2.ok) {
13477
13603
  const error = record10(body.error) ? body.error : body;
@@ -13674,8 +13800,8 @@ function runtimeUrl(cfg, suffix = "") {
13674
13800
  return `${cfg.platformUrl}/registry/apps/${encodeURIComponent(cfg.app.id)}/runtime-credentials${suffix}`;
13675
13801
  }
13676
13802
  async function safeError(response2) {
13677
- const text3 = await response2.text();
13678
- return redactSecrets(text3.slice(0, 1e3));
13803
+ const text4 = await response2.text();
13804
+ return redactSecrets(text4.slice(0, 1e3));
13679
13805
  }
13680
13806
  async function finish(doFetch, cfg, token, sessionId, method) {
13681
13807
  return doFetch(runtimeUrl(cfg, `/${encodeURIComponent(sessionId)}`), {
@@ -14094,6 +14220,7 @@ var COMMAND_SURFACE = {
14094
14220
  project: { list: {}, add: {}, create: {}, use: {} },
14095
14221
  handoff: {},
14096
14222
  next: {},
14223
+ start: {},
14097
14224
  watch: {}
14098
14225
  },
14099
14226
  provision: {},
@@ -14168,13 +14295,13 @@ function invocationPath(words2) {
14168
14295
  return path;
14169
14296
  }
14170
14297
  function surfacePaths(node = COMMAND_SURFACE, prefix = []) {
14171
- const paths = [];
14298
+ const paths2 = [];
14172
14299
  for (const [word, child] of Object.entries(node)) {
14173
14300
  const path = [...prefix, word];
14174
- paths.push(path);
14175
- paths.push(...surfacePaths(child, path));
14301
+ paths2.push(path);
14302
+ paths2.push(...surfacePaths(child, path));
14176
14303
  }
14177
- return paths;
14304
+ return paths2;
14178
14305
  }
14179
14306
 
14180
14307
  // src/record.ts
@@ -14232,10 +14359,10 @@ var DAY_MS = 24 * 60 * 60 * 1e3;
14232
14359
  var UNITS = { d: DAY_MS, w: 7 * DAY_MS, y: 365 * DAY_MS };
14233
14360
  function parseDeviceTtl(raw) {
14234
14361
  if (raw === void 0 || raw === true) return void 0;
14235
- const text3 = String(raw).trim().toLowerCase();
14236
- if (!text3) return void 0;
14237
- if (text3 === "forever" || text3 === "never") return 100 * 365 * DAY_MS;
14238
- const match = /^(\d+)\s*([dwy])$/.exec(text3);
14362
+ const text4 = String(raw).trim().toLowerCase();
14363
+ if (!text4) return void 0;
14364
+ if (text4 === "forever" || text4 === "never") return 100 * 365 * DAY_MS;
14365
+ const match = /^(\d+)\s*([dwy])$/.exec(text4);
14239
14366
  if (!match) {
14240
14367
  throw new Error(
14241
14368
  `--device-ttl expects a duration like 30d, 6w, 2y, or "forever" (got "${raw}")`
@@ -14617,12 +14744,12 @@ async function runbookRemove(ctx, slug) {
14617
14744
  // src/runbook-import.ts
14618
14745
  var import_node_fs21 = require("fs");
14619
14746
  var import_node_path19 = require("path");
14620
- function parseRunbook(text3, slug) {
14621
- let rest = text3;
14747
+ function parseRunbook(text4, slug) {
14748
+ let rest = text4;
14622
14749
  const meta = {};
14623
- const fm = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/.exec(text3);
14750
+ const fm = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/.exec(text4);
14624
14751
  if (fm) {
14625
- rest = text3.slice(fm[0].length);
14752
+ rest = text4.slice(fm[0].length);
14626
14753
  for (const line2 of fm[1].split(/\r?\n/)) {
14627
14754
  const pair = /^(\w+)\s*:\s*(.+)$/.exec(line2.trim());
14628
14755
  if (!pair) continue;