@quantiya/codevibe-core 2.0.75 → 2.0.77

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.
@@ -749,10 +749,10 @@ ${yaml}---
749
749
 
750
750
  ${prose}`;
751
751
  }
752
- function getTaskDirectoryPath(taskId, homeDir = os38.homedir()) {
752
+ function getTaskDirectoryPath(taskId, homeDir = os39.homedir()) {
753
753
  return path66.join(homeDir, ".codevibe", "tasks", taskId);
754
754
  }
755
- function getPacketFilePath(taskId, homeDir = os38.homedir()) {
755
+ function getPacketFilePath(taskId, homeDir = os39.homedir()) {
756
756
  return path66.join(getTaskDirectoryPath(taskId, homeDir), "CONTINUATION.md");
757
757
  }
758
758
  async function atomicWritePacket(taskDir, finalPath, bytes, pid, ts, randHex) {
@@ -802,7 +802,7 @@ async function atomicWritePacket(taskDir, finalPath, bytes, pid, ts, randHex) {
802
802
  }
803
803
  }
804
804
  function createContinuationPacketWriter(deps) {
805
- let perTaskMutex = /* @__PURE__ */ new Map(), homeDir = deps.homeDir ?? os38.homedir(), clock = deps.clock ?? Date.now, randomHex = deps.randomHex ?? defaultRandomHex, collector = deps.dirtyStateCollector ?? {
805
+ let perTaskMutex = /* @__PURE__ */ new Map(), homeDir = deps.homeDir ?? os39.homedir(), clock = deps.clock ?? Date.now, randomHex = deps.randomHex ?? defaultRandomHex, collector = deps.dirtyStateCollector ?? {
806
806
  collect: async () => collectRepoStates(deps.authority, [], {}).catch(() => [])
807
807
  }, getMutex = (taskId) => {
808
808
  let m = perTaskMutex.get(taskId);
@@ -871,10 +871,10 @@ function createContinuationPacketWriter(deps) {
871
871
  }
872
872
  };
873
873
  }
874
- var import_node_fs28, path66, os38, crypto26, import_json_freeze15, import_yaml, Mutex, WORK_NOT_ENUMERATED_SENTINEL, VERIFICATION_NOT_RECORDED_SENTINEL, init_packet_writer = __esm({
874
+ var import_node_fs28, path66, os39, crypto26, import_json_freeze15, import_yaml, Mutex, WORK_NOT_ENUMERATED_SENTINEL, VERIFICATION_NOT_RECORDED_SENTINEL, init_packet_writer = __esm({
875
875
  "src/continuation/packet-writer.ts"() {
876
876
  "use strict";
877
- import_node_fs28 = require("node:fs"), path66 = __toESM(require("node:path")), os38 = __toESM(require("node:os")), crypto26 = __toESM(require("node:crypto")), import_json_freeze15 = require("json-freeze"), import_yaml = require("yaml");
877
+ import_node_fs28 = require("node:fs"), path66 = __toESM(require("node:path")), os39 = __toESM(require("node:os")), crypto26 = __toESM(require("node:crypto")), import_json_freeze15 = require("json-freeze"), import_yaml = require("yaml");
878
878
  init_types();
879
879
  init_dirty_state_collector();
880
880
  Mutex = class {
@@ -943,7 +943,7 @@ var init_resolve_agent = __esm({
943
943
 
944
944
  // src/companion-mode/persist-preference.ts
945
945
  function resolveHome11() {
946
- return (process.env.VITEST === "true" || process.env.NODE_ENV === "test") && process.env.CODEVIBE_HOME_OVERRIDE ? process.env.CODEVIBE_HOME_OVERRIDE : os51.homedir();
946
+ return (process.env.VITEST === "true" || process.env.NODE_ENV === "test") && process.env.CODEVIBE_HOME_OVERRIDE ? process.env.CODEVIBE_HOME_OVERRIDE : os52.homedir();
947
947
  }
948
948
  function companionPreferenceFilePath() {
949
949
  return path84.join(resolveHome11(), ".codevibe", "companion-preference.json");
@@ -991,10 +991,10 @@ async function persistCompanionPreference(pref) {
991
991
  } catch {
992
992
  }
993
993
  }
994
- var fs63, path84, os51, import_zod16, CompanionPreferenceSchema, init_persist_preference = __esm({
994
+ var fs63, path84, os52, import_zod16, CompanionPreferenceSchema, init_persist_preference = __esm({
995
995
  "src/companion-mode/persist-preference.ts"() {
996
996
  "use strict";
997
- fs63 = __toESM(require("fs/promises")), path84 = __toESM(require("path")), os51 = __toESM(require("os")), import_zod16 = require("zod");
997
+ fs63 = __toESM(require("fs/promises")), path84 = __toESM(require("path")), os52 = __toESM(require("os")), import_zod16 = require("zod");
998
998
  init_logger2();
999
999
  CompanionPreferenceSchema = import_zod16.z.object({
1000
1000
  lastAgent: import_zod16.z.union([
@@ -4319,15 +4319,15 @@ async function probeWorkspaceTreeFingerprint(workspaceRoot, options = {}) {
4319
4319
  ), fields = stdout.split("\0").filter((field2) => field2.length > 0), parts = [];
4320
4320
  for (let i = 0; i < fields.length; i++) {
4321
4321
  if (remaining() <= 0) return failed();
4322
- let xy = fields[i].slice(0, 2), relative22 = fields[i].slice(3);
4322
+ let xy = fields[i].slice(0, 2), relative23 = fields[i].slice(3);
4323
4323
  /[RC]/.test(xy) && (i += 1);
4324
4324
  let stat13 = "absent";
4325
4325
  try {
4326
- let st = await fs10.lstat(path13.join(root, relative22));
4326
+ let st = await fs10.lstat(path13.join(root, relative23));
4327
4327
  stat13 = `${st.size}:${st.mtimeMs}`;
4328
4328
  } catch {
4329
4329
  }
4330
- parts.push(`${xy} ${relative22} ${stat13}`);
4330
+ parts.push(`${xy} ${relative23} ${stat13}`);
4331
4331
  }
4332
4332
  return remaining() <= 0 ? failed() : {
4333
4333
  kind: "fingerprint",
@@ -10294,7 +10294,7 @@ var SyncJournalError = class extends Error {
10294
10294
  this.code = code;
10295
10295
  this.name = "SyncJournalError";
10296
10296
  }
10297
- }, UUID8 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i, MAX_RECORD_BYTES = 1024 * 1024, MAX_ENVELOPE_BYTES = 2 * MAX_RECORD_BYTES, MAX_FILES = 256, MAX_STORE_BYTES = 32 * 1024 * 1024, MAX_RETIREMENT_INTENTS = 16, MAX_RETIREMENT_BYTES = 32 * 1024, invalid7 = () => {
10297
+ }, UUID8 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i, MAX_RECORD_BYTES = 1024 * 1024, MAX_ENVELOPE_BYTES = 2 * MAX_RECORD_BYTES, MAX_FILES = 256, MAX_STORE_BYTES = 32 * 1024 * 1024, MAX_RETIREMENT_INTENTS = 16, MAX_RETIREMENT_BYTES = 32 * 1024, MAX_INVENTORY_FILES = MAX_FILES * 4 + MAX_RETIREMENT_INTENTS * 2 + 8, MAX_DIRECTORY_ENTRIES = MAX_INVENTORY_FILES * 4 + MAX_FILES + MAX_RETIREMENT_INTENTS * 2 + 8, invalid7 = () => {
10298
10298
  throw new SyncJournalError("SYNC_JOURNAL_INVALID");
10299
10299
  }, errorCode = (error) => error?.code;
10300
10300
  function operationId(value) {
@@ -10487,7 +10487,7 @@ var sourceCursorId = (scope, stream) => stableUuid("codevibe-sync-source-cursor-
10487
10487
  }) : (this.options.assertAccount(), []);
10488
10488
  }
10489
10489
  /** One encrypted intent/credential record per original desktop incarnation.
10490
- * This uses the account journal's existing 256-file / 32-MiB total bound. */
10490
+ * Bookkeeping shares the 32-MiB bound, but not outbound-operation slots. */
10491
10491
  desktopRegistration(register, now = Date.now) {
10492
10492
  let scope = this.sessionScope;
10493
10493
  if (!scope || typeof register != "function") return invalid7();
@@ -11123,6 +11123,14 @@ var sourceCursorId = (scope, stream) => stableUuid("codevibe-sync-source-cursor-
11123
11123
  let plan = await this.withStore((key) => this.retiredSourcePlan(key, input.expectedSessionKeyGen));
11124
11124
  if (!plan.sources.length) return { sourcesRemoved: 0, operationsRemoved: 0 };
11125
11125
  parseSyncSessionRetirementReceipt(await confirm(input), input), this.options.assertAccount();
11126
+ let total = { sourcesRemoved: 0, operationsRemoved: 0 };
11127
+ for (let page = 0; page < MAX_INVENTORY_FILES; page++) {
11128
+ let removed = await this.removeRetiredSourceBatch(plan, input.expectedSessionKeyGen);
11129
+ if (total.sourcesRemoved += removed.sourcesRemoved, total.operationsRemoved += removed.operationsRemoved, plan = await this.withStore((key) => this.retiredSourcePlan(key, input.expectedSessionKeyGen)), !plan.sources.length) return total;
11130
+ }
11131
+ throw new SyncJournalError("SYNC_OPERATION_PENDING");
11132
+ }
11133
+ async removeRetiredSourceBatch(plan, expectedSessionKeyGen) {
11126
11134
  let owners = [], fence = async () => {
11127
11135
  this.options.assertAccount();
11128
11136
  for (let owner of owners) if (!await owner.reassertOwnership()) throw new SyncJournalError("SYNC_JOURNAL_LOCK_LOST");
@@ -11137,7 +11145,7 @@ var sourceCursorId = (scope, stream) => stableUuid("codevibe-sync-source-cursor-
11137
11145
  if (owners.push(owner), this.options.assertAccount(), !await owner.reassertOwnership()) throw new SyncJournalError("SYNC_JOURNAL_LOCK_LOST");
11138
11146
  }
11139
11147
  return await this.withStore(async (key, storeFence) => {
11140
- let current = await this.retiredSourcePlan(key, input.expectedSessionKeyGen);
11148
+ let current = await this.retiredSourcePlan(key, expectedSessionKeyGen);
11141
11149
  if (current.digest !== plan.digest) throw new SyncJournalError("SYNC_OPERATION_PENDING");
11142
11150
  await fence();
11143
11151
  for (let name of current.operations)
@@ -11196,15 +11204,20 @@ var sourceCursorId = (scope, stream) => stableUuid("codevibe-sync-source-cursor-
11196
11204
  }
11197
11205
  async retiredSourcePlan(key, expectedSessionKeyGen) {
11198
11206
  if (!this.sessionScope) return invalid7();
11199
- let sources = [], operations = [], images = [], linked = /* @__PURE__ */ new Set(), outer = /* @__PURE__ */ new Set(), inner = /* @__PURE__ */ new Set(), expectedInputs = /* @__PURE__ */ new Map(), bind = (value) => {
11207
+ let sources = [], operations = [], images = [], linked = /* @__PURE__ */ new Set(), outer = /* @__PURE__ */ new Set(), inner = /* @__PURE__ */ new Set(), selectedLinks = /* @__PURE__ */ new Set(), sourceCount = 0, linkedOperationCount = 0, expectedInputs = /* @__PURE__ */ new Map(), bind = (value) => {
11200
11208
  let input = request2("CREATE_EVENT", value), digest2 = fingerprint("CREATE_EVENT", input), prior = expectedInputs.get(input.clientOperationId);
11201
11209
  if (prior !== void 0 && prior !== digest2) return invalid7();
11202
11210
  expectedInputs.set(input.clientOperationId, digest2);
11203
11211
  }, add = (name, row3, links, locks, innerLocks = []) => {
11204
- if (this.matchesScope(row3)) {
11205
- sources.push(name), images.push([name, row3]);
11206
- for (let id5 of links) linked.add(id5);
11207
- if (sources.length > MAX_FILES || linked.size > MAX_FILES) throw new SyncJournalError("SYNC_JOURNAL_FULL");
11212
+ if (!this.matchesScope(row3)) return;
11213
+ sourceCount++, images.push([name, row3]);
11214
+ for (let id5 of links) linked.add(id5);
11215
+ if (sourceCount > MAX_INVENTORY_FILES || linked.size > MAX_INVENTORY_FILES * MAX_FILES)
11216
+ throw new SyncJournalError("SYNC_JOURNAL_FULL");
11217
+ let additionalLinks = links.filter((id5) => !selectedLinks.has(id5));
11218
+ if (!(sources.length >= MAX_FILES || selectedLinks.size + additionalLinks.length > MAX_FILES)) {
11219
+ sources.push(name);
11220
+ for (let id5 of links) selectedLinks.add(id5);
11208
11221
  for (let lock of locks) outer.add(lock);
11209
11222
  for (let lock of innerLocks) inner.add(lock);
11210
11223
  }
@@ -11255,16 +11268,16 @@ var sourceCursorId = (scope, stream) => stableUuid("codevibe-sync-source-cursor-
11255
11268
  let row3 = await this.read(id5, key);
11256
11269
  if (row3) {
11257
11270
  if (this.requireScope(row3), row3.action !== "CREATE_EVENT" || row3.state === "PENDING" && row3.input.expectedSessionKeyGen !== expectedSessionKeyGen || expectedInputs.has(id5) && expectedInputs.get(id5) !== row3.fingerprint) return invalid7();
11258
- operations.push(id5 + ".json"), images.push([id5 + ".json", row3]);
11271
+ linkedOperationCount++, images.push([id5 + ".json", row3]), selectedLinks.has(id5) && operations.push(id5 + ".json");
11259
11272
  }
11260
11273
  }
11261
- if (sources.length + operations.length > MAX_FILES) throw new SyncJournalError("SYNC_JOURNAL_FULL");
11274
+ if (linkedOperationCount > MAX_FILES) throw new SyncJournalError("SYNC_JOURNAL_FULL");
11262
11275
  return {
11263
11276
  sources: sources.sort(),
11264
11277
  operations,
11265
11278
  // Even a missing operation may retain its dead sender/GC lock after an
11266
11279
  // interrupted unlink. The source's complete link set owns reclamation.
11267
- locks: [...[...outer].sort(), ...[...inner].sort(), ...[...linked].sort().map((id5) => `send-${id5}.lockdir`)],
11280
+ locks: [...[...outer].sort(), ...[...inner].sort(), ...[...selectedLinks].sort().map((id5) => `send-${id5}.lockdir`)],
11268
11281
  digest: (0, import_node_crypto14.createHash)("sha256").update((0, import_json_freeze12.canonicalize)(images)).digest("hex")
11269
11282
  };
11270
11283
  }
@@ -11523,21 +11536,21 @@ var sourceCursorId = (scope, stream) => stableUuid("codevibe-sync-source-cursor-
11523
11536
  async recordNames(suffix = ".json") {
11524
11537
  let names = [], entries = 0, directory = await import_node_fs5.promises.opendir(this.directory);
11525
11538
  for await (let entry5 of directory) {
11526
- if (++entries > MAX_FILES * 4 + MAX_RETIREMENT_INTENTS * 2 + 8) throw new SyncJournalError("SYNC_JOURNAL_FULL");
11527
- if (entry5.name.endsWith(suffix) && ((!entry5.isFile() || !UUID8.test(entry5.name.slice(0, -suffix.length))) && invalid7(), names.push(entry5.name), names.length > MAX_FILES))
11539
+ if (++entries > MAX_DIRECTORY_ENTRIES) throw new SyncJournalError("SYNC_JOURNAL_FULL");
11540
+ if (entry5.name.endsWith(suffix) && ((!entry5.isFile() || !UUID8.test(entry5.name.slice(0, -suffix.length))) && invalid7(), names.push(entry5.name), names.length > (suffix === ".json" ? MAX_FILES : MAX_INVENTORY_FILES)))
11528
11541
  throw new SyncJournalError("SYNC_JOURNAL_FULL");
11529
11542
  }
11530
11543
  return names;
11531
11544
  }
11532
11545
  async checkCapacity(additionalBytes, replacedName, retirement = !1) {
11533
- let count4 = 0, bytes = additionalBytes, entries = 0, retirements = 0, directory = await import_node_fs5.promises.opendir(this.directory);
11546
+ let operations = 0, bookkeeping = 0, bytes = additionalBytes, entries = 0, retirements = 0, allocatesOperation = replacedName === void 0 || replacedName.endsWith(".json"), directory = await import_node_fs5.promises.opendir(this.directory);
11534
11547
  for await (let entry5 of directory)
11535
- if ((++entries > MAX_FILES * 4 + MAX_RETIREMENT_INTENTS * 2 + 8 || entry5.isSymbolicLink()) && invalid7(), entry5.isFile()) {
11548
+ if ((++entries > MAX_DIRECTORY_ENTRIES || entry5.isSymbolicLink()) && invalid7(), entry5.isFile()) {
11536
11549
  let stat13 = await import_node_fs5.promises.lstat(path18.join(this.directory, entry5.name));
11537
11550
  if ((!stat13.isFile() || stat13.nlink !== 1) && invalid7(), entry5.name === replacedName) continue;
11538
- entry5.name.endsWith(".retirement") && retirements++, bytes += stat13.size, count4++;
11551
+ bytes += stat13.size, entry5.name.endsWith(".json") ? operations++ : entry5.name.endsWith(".retirement") ? retirements++ : bookkeeping++;
11539
11552
  }
11540
- if (count4 >= MAX_FILES + (retirement ? MAX_RETIREMENT_INTENTS : 0) || bytes > MAX_STORE_BYTES + (retirement ? MAX_RETIREMENT_INTENTS * MAX_RETIREMENT_BYTES : 0) || retirement && retirements >= MAX_RETIREMENT_INTENTS) throw new SyncJournalError("SYNC_JOURNAL_FULL");
11553
+ if (allocatesOperation && operations >= MAX_FILES || !allocatesOperation && !retirement && bookkeeping >= MAX_INVENTORY_FILES || bytes > MAX_STORE_BYTES + (retirement ? MAX_RETIREMENT_INTENTS * MAX_RETIREMENT_BYTES : 0) || retirement && retirements >= MAX_RETIREMENT_INTENTS) throw new SyncJournalError("SYNC_JOURNAL_FULL");
11541
11554
  }
11542
11555
  async ensureDirectory() {
11543
11556
  let current = path18.parse(this.directory).root;
@@ -13138,10 +13151,10 @@ var DecisionAttemptReceiptStore = class _DecisionAttemptReceiptStore {
13138
13151
  }
13139
13152
  }
13140
13153
  async assertNoSymlinkComponents(target2) {
13141
- let relative22 = path22.relative(this.rootDir, target2);
13142
- if (relative22.startsWith("..") || path22.isAbsolute(relative22))
13154
+ let relative23 = path22.relative(this.rootDir, target2);
13155
+ if (relative23.startsWith("..") || path22.isAbsolute(relative23))
13143
13156
  throw new Error("DecisionAttemptReceiptStore: path escaped receipt root");
13144
- let components = relative22 ? relative22.split(path22.sep) : [], current = this.rootDir;
13157
+ let components = relative23 ? relative23.split(path22.sep) : [], current = this.rootDir;
13145
13158
  for (let index = -1; index < components.length; index += 1) {
13146
13159
  index >= 0 && (current = path22.join(current, components[index]));
13147
13160
  try {
@@ -21231,9 +21244,9 @@ init_logger2();
21231
21244
  function truncate(s, max) {
21232
21245
  return max <= 0 ? "" : s.length <= max ? s : max === 1 ? "\u2026" : s.slice(0, max - 1) + "\u2026";
21233
21246
  }
21234
- function formatProjectPath(projectPath, homedir40, maxCols) {
21247
+ function formatProjectPath(projectPath, homedir41, maxCols) {
21235
21248
  let p = projectPath ?? "";
21236
- if (homedir40 && (p === homedir40 || p.startsWith(homedir40 + "/")) && (p = "~" + p.slice(homedir40.length)), p.length > maxCols) {
21249
+ if (homedir41 && (p === homedir41 || p.startsWith(homedir41 + "/")) && (p = "~" + p.slice(homedir41.length)), p.length > maxCols) {
21237
21250
  if (maxCols <= 0) return "";
21238
21251
  if (maxCols === 1) return "\u2026";
21239
21252
  p = "\u2026" + p.slice(p.length - (maxCols - 1));
@@ -21250,7 +21263,7 @@ function plannerBadge(kind, label) {
21250
21263
  return kind === "local_gemma_qat" ? { text: `${(label ?? "").trim() || "local model"} \xB7 local` } : kind === "local_unavailable" ? { text: `\u26A0 ${(label ?? "").trim() || "local model"} offline \u2014 NL disabled`, color: "yellow" } : kind === "hosted" ? { text: "Gemma \xB7 hosted" } : null;
21251
21264
  }
21252
21265
  function computeStatusLayout(args) {
21253
- let { tier, homedir: homedir40, columns, badge } = args, SEP = " \xB7 ", badgeText = badge ? truncate(badge.text, Math.max(0, columns - SEP.length - tier.length - 2)) : "", rightWidth = badgeText ? badgeText.length + 1 : 0, cwdMax = Math.max(0, columns - rightWidth - SEP.length - tier.length), cwd = formatProjectPath(args.cwd, homedir40, cwdMax), leftFull = cwd ? `${cwd}${SEP}${tier}` : tier;
21266
+ let { tier, homedir: homedir41, columns, badge } = args, SEP = " \xB7 ", badgeText = badge ? truncate(badge.text, Math.max(0, columns - SEP.length - tier.length - 2)) : "", rightWidth = badgeText ? badgeText.length + 1 : 0, cwdMax = Math.max(0, columns - rightWidth - SEP.length - tier.length), cwd = formatProjectPath(args.cwd, homedir41, cwdMax), leftFull = cwd ? `${cwd}${SEP}${tier}` : tier;
21254
21267
  return { leftText: truncate(leftFull, Math.max(0, columns - rightWidth)), badgeText };
21255
21268
  }
21256
21269
 
@@ -21461,7 +21474,7 @@ async function clearRetiredPlannerCache(userId, cacheRoot = process.env.CODEVIBE
21461
21474
  }
21462
21475
 
21463
21476
  // src/orchestration-shell/index.ts
21464
- var path78 = __toESM(require("path")), os47 = __toESM(require("os")), import_promises = require("node:fs/promises"), import_node_fs37 = require("node:fs"), import_node_child_process10 = require("node:child_process"), import_node_util3 = require("node:util"), import_node_async_hooks = require("node:async_hooks");
21477
+ var path78 = __toESM(require("path")), os48 = __toESM(require("os")), import_promises = require("node:fs/promises"), import_node_fs37 = require("node:fs"), import_node_child_process10 = require("node:child_process"), import_node_util3 = require("node:util"), import_node_async_hooks = require("node:async_hooks");
21465
21478
 
21466
21479
  // src/orchestration-shell/web/sanitize.ts
21467
21480
  function sanitizeForTerminal(input) {
@@ -32818,17 +32831,17 @@ function sniffImageMime(head) {
32818
32831
  return null;
32819
32832
  }
32820
32833
  var IMAGE_EXT_RE = /\.(png|jpe?g|gif|webp|bmp)$/i;
32821
- function unescapeToken(raw, homedir40) {
32834
+ function unescapeToken(raw, homedir41) {
32822
32835
  let s = raw.trim(), wasQuoted = !1;
32823
32836
  if ((s.startsWith("'") && s.endsWith("'") || s.startsWith('"') && s.endsWith('"')) && (s = s.slice(1, -1), wasQuoted = !0), s.startsWith("file://"))
32824
32837
  try {
32825
32838
  return (0, import_node_url.fileURLToPath)(s);
32826
32839
  } catch {
32827
32840
  }
32828
- return wasQuoted || (s = s.replace(/\\(.)/g, "$1")), expandHome(s, homedir40);
32841
+ return wasQuoted || (s = s.replace(/\\(.)/g, "$1")), expandHome(s, homedir41);
32829
32842
  }
32830
- function expandHome(p, homedir40) {
32831
- return p === "~" ? homedir40 : p.startsWith("~/") ? path33.join(homedir40, p.slice(2)) : p;
32843
+ function expandHome(p, homedir41) {
32844
+ return p === "~" ? homedir41 : p.startsWith("~/") ? path33.join(homedir41, p.slice(2)) : p;
32832
32845
  }
32833
32846
  function extractImagePathSpans(text2) {
32834
32847
  let spans = [], quoted = /'[^']*\.(?:png|jpe?g|gif|webp|bmp)'|"[^"]*\.(?:png|jpe?g|gif|webp|bmp)"/gi, m, masked = text2.split("");
@@ -34583,7 +34596,7 @@ function collapsedReducedTrustLine(actor) {
34583
34596
  }
34584
34597
 
34585
34598
  // src/orchestration-shell/quorum-loop.ts
34586
- var path71 = __toESM(require("node:path")), os42 = __toESM(require("node:os")), nodeCrypto = __toESM(require("node:crypto")), import_uuid12 = require("uuid"), import_ulid4 = require("ulid");
34599
+ var path71 = __toESM(require("node:path")), os43 = __toESM(require("node:os")), nodeCrypto = __toESM(require("node:crypto")), import_uuid12 = require("uuid"), import_ulid4 = require("ulid");
34587
34600
 
34588
34601
  // src/audit-keys/index.ts
34589
34602
  var import_node_crypto26 = require("node:crypto");
@@ -36477,6 +36490,255 @@ function enforceNetwork(scope) {
36477
36490
  function redactSensitiveTokens(cmd) {
36478
36491
  return cmd.replace(/--token\s+[0-9a-fA-F]+/g, "--token [REDACTED]").replace(/mcp_servers\.codevibe_web\.args=\S+/g, "mcp_servers.codevibe_web.args=[REDACTED]");
36479
36492
  }
36493
+ function normalizeArgv(argv) {
36494
+ if (!Array.isArray(argv)) return [];
36495
+ let normalized = [];
36496
+ for (let token4 of argv)
36497
+ if (typeof token4 == "string")
36498
+ if (token4.startsWith("--") && token4.includes("=")) {
36499
+ let eqIdx = token4.indexOf("="), rawKey = token4.slice(0, eqIdx), val = token4.slice(eqIdx + 1), key = normalizeFlagName(rawKey);
36500
+ normalized.push(key, val);
36501
+ } else if (token4.startsWith("--"))
36502
+ normalized.push(normalizeFlagName(token4));
36503
+ else if (token4.startsWith("-s") && token4.length > 2) {
36504
+ let val = token4[2] === "=" ? token4.slice(3) : token4.slice(2);
36505
+ normalized.push("--sandbox", val);
36506
+ } else if (token4 === "-s")
36507
+ normalized.push("--sandbox");
36508
+ else if (token4.startsWith("-c") && token4.length > 2 && !token4.startsWith("--")) {
36509
+ let val = token4[2] === "=" ? token4.slice(3) : token4.slice(2);
36510
+ normalized.push("-c", val);
36511
+ } else
36512
+ normalized.push(token4);
36513
+ return normalized;
36514
+ }
36515
+ function normalizeFlagName(flag) {
36516
+ return flag.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
36517
+ }
36518
+ function parseToolRuleM8(rule) {
36519
+ let trimmed = rule.trim();
36520
+ if (trimmed.length === 0) return null;
36521
+ let firstParen = trimmed.indexOf("("), lastParen = trimmed.lastIndexOf(")");
36522
+ if (firstParen === -1 && lastParen === -1)
36523
+ return /^[A-Za-z0-9_]+$/.test(trimmed) ? { toolName: trimmed } : null;
36524
+ if (firstParen === -1 || lastParen <= firstParen || lastParen !== trimmed.length - 1)
36525
+ return null;
36526
+ let toolName = trimmed.substring(0, firstParen);
36527
+ if (!/^[A-Za-z0-9_]+$/.test(toolName)) return null;
36528
+ let rawContent = trimmed.substring(firstParen + 1, lastParen);
36529
+ return { toolName, rawContent };
36530
+ }
36531
+ function vendorBu(e) {
36532
+ let n = [];
36533
+ for (let t of e) {
36534
+ if (!t) continue;
36535
+ let r = "", o = !1;
36536
+ for (let s of t)
36537
+ switch (s) {
36538
+ case "(":
36539
+ o = !0, r += s;
36540
+ break;
36541
+ case ")":
36542
+ o = !1, r += s;
36543
+ break;
36544
+ case ",":
36545
+ o ? r += s : (r.trim() && n.push(r.trim()), r = "");
36546
+ break;
36547
+ case " ":
36548
+ o ? r += s : r.trim() && (n.push(r.trim()), r = "");
36549
+ break;
36550
+ default:
36551
+ (r || s.trim()) && (r += s);
36552
+ }
36553
+ r.trim() && n.push(r.trim());
36554
+ }
36555
+ return n;
36556
+ }
36557
+ function parseAllowedToolsRules(value) {
36558
+ let arr = Array.isArray(value) ? value : [value], rules = vendorBu(arr);
36559
+ return rules.length > 0 ? rules : null;
36560
+ }
36561
+ var ADVISORY_FORBIDDEN_TOOLS = /* @__PURE__ */ new Set([
36562
+ "Write",
36563
+ "Edit",
36564
+ "Bash",
36565
+ "NotebookEditCell",
36566
+ "KillShell"
36567
+ ]), ADVISORY_PERMITTED_TOOLS = /* @__PURE__ */ new Set(["Read", "Grep", "Glob"]);
36568
+ function isStrictReadOnlyAdvisoryClaude(argv) {
36569
+ if (!Array.isArray(argv) || argv.length === 0) return !1;
36570
+ let norm = normalizeArgv(argv);
36571
+ if (norm.length === 0) return !1;
36572
+ let baseExe = path38.basename(norm[0] || "");
36573
+ if (baseExe !== "claude" && baseExe !== "claude.exe" || norm.some(
36574
+ (arg) => arg.startsWith("--dangerously") || arg.startsWith("--allow-dangerously") || arg === "--yolo" || arg === "--full-auto" || arg === "--approve-for-me" || arg === "--permission-mode" || arg.startsWith("--permission-mode=") || arg === "--plugin-dir" || arg.startsWith("--plugin-dir=") || arg === "--plugin-dir-no-mcp" || arg.startsWith("--plugin-dir-no-mcp=") || arg === "--plugin-url" || arg.startsWith("--plugin-url=") || arg === "--plugin" || arg.startsWith("--plugin=") || arg === "--plugins" || arg.startsWith("--plugins=") || arg === "--system-prompt" || arg.startsWith("--system-prompt=") || arg === "--append-system-prompt" || arg.startsWith("--append-system-prompt=") || arg === "--exec" || arg.startsWith("--exec=")
36575
+ ) || norm.includes("--mcp-config") || norm.filter((a) => a === "--strict-mcp-config").length !== 1)
36576
+ return !1;
36577
+ let settingSourcesIndices = [];
36578
+ for (let i = 0; i < norm.length; i++)
36579
+ norm[i] === "--setting-sources" && settingSourcesIndices.push(i);
36580
+ if (settingSourcesIndices.length !== 1)
36581
+ return !1;
36582
+ let ssIdx = settingSourcesIndices[0];
36583
+ if (norm[ssIdx + 1] !== "user" || norm.filter((a) => a === "--tools").length !== 1 || norm.filter((a) => a === "--allowed-tools").length !== 1 || norm.filter((a) => a === "--settings").length !== 1) return !1;
36584
+ let settingsIdx = norm.indexOf("--settings"), settingsRaw = norm[settingsIdx + 1];
36585
+ if (!settingsRaw || !settingsRaw.startsWith("{")) return !1;
36586
+ let settingsObj;
36587
+ try {
36588
+ settingsObj = JSON.parse(settingsRaw);
36589
+ } catch {
36590
+ return !1;
36591
+ }
36592
+ if (!settingsObj || typeof settingsObj != "object" || Array.isArray(settingsObj))
36593
+ return !1;
36594
+ let topKeys = Object.keys(settingsObj);
36595
+ if (topKeys.length !== 1 || topKeys[0] !== "permissions")
36596
+ return !1;
36597
+ let permissionsObj = settingsObj.permissions;
36598
+ if (!permissionsObj || typeof permissionsObj != "object" || Array.isArray(permissionsObj))
36599
+ return !1;
36600
+ for (let pk of Object.keys(permissionsObj))
36601
+ if (pk !== "defaultMode" && pk !== "allow")
36602
+ return !1;
36603
+ if (permissionsObj.defaultMode !== "dontAsk" || !Array.isArray(permissionsObj.allow))
36604
+ return !1;
36605
+ let toolsIdx = norm.indexOf("--tools"), toolTokens = [];
36606
+ for (let i = toolsIdx + 1; i < norm.length && !norm[i].startsWith("-"); i++)
36607
+ toolTokens.push(norm[i]);
36608
+ if (toolTokens.length === 0) return !1;
36609
+ let firstTool = toolTokens[0], allowedToolsIdx = norm.indexOf("--allowed-tools");
36610
+ if (allowedToolsIdx === -1) return !1;
36611
+ let allowedToolsTokens = [];
36612
+ for (let i = allowedToolsIdx + 1; i < norm.length && !norm[i].startsWith("-"); i++)
36613
+ allowedToolsTokens.push(norm[i]);
36614
+ if (firstTool === "")
36615
+ return !(toolTokens.length !== 1 || allowedToolsTokens.length !== 1 || allowedToolsTokens[0] !== "" || permissionsObj.allow.length !== 0);
36616
+ let allToolNames = toolTokens.flatMap((t) => t.split(/[\s,]+/)).map((t) => t.trim()).filter(Boolean);
36617
+ if (allToolNames.length === 0) return !1;
36618
+ for (let t of allToolNames)
36619
+ if (!ADVISORY_PERMITTED_TOOLS.has(t) || ADVISORY_FORBIDDEN_TOOLS.has(t)) return !1;
36620
+ if (allowedToolsTokens.length === 0) return !1;
36621
+ let parsedAllowedRules = parseAllowedToolsRules(allowedToolsTokens);
36622
+ if (!parsedAllowedRules || parsedAllowedRules.length === 0) return !1;
36623
+ for (let rule of parsedAllowedRules) {
36624
+ let parsed = parseToolRuleM8(rule);
36625
+ if (!parsed || !ADVISORY_PERMITTED_TOOLS.has(parsed.toolName) || ADVISORY_FORBIDDEN_TOOLS.has(parsed.toolName) || parsed.rawContent === void 0) return !1;
36626
+ let p = parsed.rawContent;
36627
+ if (p === "/*" || p === "*" || !p.startsWith("//") || p === "//" || p === "//*" || p === "//**" || /[\r\n\0]/.test(p)) return !1;
36628
+ }
36629
+ if (permissionsObj.allow.length === 0) return !1;
36630
+ for (let rule of permissionsObj.allow) {
36631
+ if (typeof rule != "string") return !1;
36632
+ let parsed = parseToolRuleM8(rule);
36633
+ if (!parsed || !ADVISORY_PERMITTED_TOOLS.has(parsed.toolName) || ADVISORY_FORBIDDEN_TOOLS.has(parsed.toolName) || parsed.rawContent === void 0) return !1;
36634
+ let p = parsed.rawContent;
36635
+ if (p === "/*" || p === "*" || !p.startsWith("//") || p === "//" || p === "//*" || p === "//**" || /[\r\n\0]/.test(p)) return !1;
36636
+ }
36637
+ return !0;
36638
+ }
36639
+ var CODEX_LONG_OPTIONS_WITH_VALUE = /* @__PURE__ */ new Set([
36640
+ "config",
36641
+ "enable",
36642
+ "disable",
36643
+ "image",
36644
+ "model",
36645
+ "local-provider",
36646
+ "profile",
36647
+ "sandbox",
36648
+ "cd",
36649
+ "add-dir",
36650
+ "thread-source",
36651
+ "cyber-access-program",
36652
+ "output-schema",
36653
+ "color",
36654
+ "output-last-message"
36655
+ ]), CODEX_SHORT_OPTIONS_WITH_VALUE = /* @__PURE__ */ new Set([
36656
+ "c",
36657
+ "i",
36658
+ "m",
36659
+ "p",
36660
+ "s",
36661
+ "C",
36662
+ "o"
36663
+ ]);
36664
+ function extractConfigKey(cfg) {
36665
+ let s = (cfg || "").trim();
36666
+ s = s.replace(/^['"]|['"]$/g, "").trim(), s = s.replace(/^=+/, "").trim(), s = s.replace(/^['"]|['"]$/g, "").trim();
36667
+ let eqIdx = s.indexOf("=");
36668
+ return (eqIdx !== -1 ? s.slice(0, eqIdx) : s).replace(/^['"]|['"]$/g, "").trim().toLowerCase();
36669
+ }
36670
+ function isProtectedCodexConfigKey(key) {
36671
+ return key.startsWith("sandbox") || key.includes("sandbox") || key.startsWith("permissions") || key.includes("permission") || key.startsWith("shell_environment_policy") || key.includes("shell_environment") || key.startsWith("approval_policy") || key.includes("approval");
36672
+ }
36673
+ function isStrictReadOnlyAdvisoryCodex(argv) {
36674
+ if (!Array.isArray(argv) || argv.length === 0) return !1;
36675
+ let baseExe = path38.basename(argv[0] || "");
36676
+ if (baseExe !== "codex" && baseExe !== "codex.exe" || argv.some(
36677
+ (arg) => typeof arg == "string" && (arg.includes("workspace-write") || arg.includes("danger-full-access"))
36678
+ ))
36679
+ return !1;
36680
+ let delimiterFound = !1, waitingForOption = null, structuredOptions = [], positionalBeforeDelimiter = [], positionalAfterDelimiter = [];
36681
+ for (let i = 1; i < argv.length; i++) {
36682
+ let rawToken = argv[i];
36683
+ if (typeof rawToken == "string") {
36684
+ if (delimiterFound) {
36685
+ positionalAfterDelimiter.push(rawToken);
36686
+ continue;
36687
+ }
36688
+ if (waitingForOption !== null) {
36689
+ waitingForOption.value = rawToken, waitingForOption = null;
36690
+ continue;
36691
+ }
36692
+ if (rawToken === "--") {
36693
+ delimiterFound = !0;
36694
+ continue;
36695
+ }
36696
+ if (rawToken.startsWith("--"))
36697
+ if (rawToken.includes("=")) {
36698
+ let eqIdx = rawToken.indexOf("="), flagName = normalizeFlagName(rawToken.slice(0, eqIdx)), flagVal = rawToken.slice(eqIdx + 1);
36699
+ structuredOptions.push({ name: flagName, value: flagVal });
36700
+ } else {
36701
+ let flagName = normalizeFlagName(rawToken), bareName = flagName.slice(2), optObj = { name: flagName };
36702
+ structuredOptions.push(optObj), CODEX_LONG_OPTIONS_WITH_VALUE.has(bareName) && (waitingForOption = optObj);
36703
+ }
36704
+ else if (rawToken.startsWith("-") && rawToken.length > 1) {
36705
+ let optChar = rawToken[1];
36706
+ if (CODEX_SHORT_OPTIONS_WITH_VALUE.has(optChar)) {
36707
+ let normOpt = optChar === "s" ? "--sandbox" : optChar === "c" ? "-c" : optChar === "C" ? "-C" : optChar === "m" ? "-m" : optChar === "o" ? "-o" : optChar === "i" ? "-i" : optChar === "p" ? "-p" : `-${optChar}`;
36708
+ if (rawToken.length > 2) {
36709
+ let val = rawToken[2] === "=" ? rawToken.slice(3) : rawToken.slice(2);
36710
+ structuredOptions.push({ name: normOpt, value: val });
36711
+ } else {
36712
+ let optObj = { name: normOpt };
36713
+ structuredOptions.push(optObj), waitingForOption = optObj;
36714
+ }
36715
+ } else
36716
+ structuredOptions.push({ name: rawToken });
36717
+ } else
36718
+ positionalBeforeDelimiter.push(rawToken);
36719
+ }
36720
+ }
36721
+ let isBypassFlag = (s) => s.startsWith("--dangerously") || s === "--yolo" || s === "--full-auto" || s === "--approve-for-me" || s === "--add-dir" || s === "-a" || s === "--ask-for-approval";
36722
+ if (structuredOptions.some((opt) => isBypassFlag(opt.name)) || positionalBeforeDelimiter.some(isBypassFlag) || positionalAfterDelimiter.some(isBypassFlag) || positionalBeforeDelimiter.length > 0 && positionalBeforeDelimiter[0] !== "exec")
36723
+ return !1;
36724
+ for (let opt of structuredOptions) {
36725
+ if (opt.name === "-c" || opt.name === "--config") {
36726
+ let cfgVal = opt.value || "", cfgKey = extractConfigKey(cfgVal);
36727
+ if (isProtectedCodexConfigKey(cfgKey))
36728
+ return !1;
36729
+ }
36730
+ if (opt.name === "--enable" || opt.name === "--disable") {
36731
+ let featVal = (opt.value || "").toLowerCase();
36732
+ if (isProtectedCodexConfigKey(featVal))
36733
+ return !1;
36734
+ }
36735
+ }
36736
+ let sandboxOptions = structuredOptions.filter((opt) => opt.name === "--sandbox");
36737
+ if (sandboxOptions.length === 0) return !1;
36738
+ for (let sOpt of sandboxOptions)
36739
+ if (sOpt.value !== "read-only") return !1;
36740
+ return !0;
36741
+ }
36480
36742
  function enforceCommand(scope, argv) {
36481
36743
  for (let entry5 of scope.commandAllowlist) {
36482
36744
  let isTemplate = entry5.endsWith(" *"), containsSpace = entry5.includes(" ");
@@ -36505,6 +36767,96 @@ function enforceCommand(scope, argv) {
36505
36767
  let expectedSessionsDir = path38.join(os25.homedir(), ".codevibe", "sessions");
36506
36768
  return !!path38.resolve(remainder).startsWith(expectedSessionsDir + path38.sep);
36507
36769
  }
36770
+ if (entry5.includes("--allowed-tools *")) {
36771
+ if (argv.includes("--mcp-config") || !argv.includes("--strict-mcp-config") || argv.includes("--dangerously-skip-permissions"))
36772
+ return !1;
36773
+ let allowedToolsIndex = argv.indexOf("--allowed-tools");
36774
+ if (allowedToolsIndex === -1 || allowedToolsIndex + 1 >= argv.length)
36775
+ return !1;
36776
+ let allowedToolsTokens = [];
36777
+ for (let i2 = allowedToolsIndex + 1; i2 < argv.length && !argv[i2].startsWith("-"); i2++)
36778
+ allowedToolsTokens.push(argv[i2]);
36779
+ if (allowedToolsTokens.length === 0) return !1;
36780
+ let parsedRules = parseAllowedToolsRules(allowedToolsTokens);
36781
+ if (!parsedRules || parsedRules.length === 0)
36782
+ return !1;
36783
+ let parsedRuleSet = /* @__PURE__ */ new Set();
36784
+ for (let rule of parsedRules) {
36785
+ let parsed = parseToolRuleM8(rule);
36786
+ if (!parsed || !ADVISORY_PERMITTED_TOOLS.has(parsed.toolName) || ADVISORY_FORBIDDEN_TOOLS.has(parsed.toolName) || parsed.rawContent === void 0)
36787
+ return !1;
36788
+ let pattern = parsed.rawContent;
36789
+ if (pattern === "/*" || pattern === "*" || !pattern.startsWith("//") || pattern === "//" || pattern === "//*" || pattern === "//**" || /[\r\n\0]/.test(pattern))
36790
+ return !1;
36791
+ parsedRuleSet.add(rule);
36792
+ }
36793
+ let settingsTokenIdx = remainderTokens.indexOf("--settings");
36794
+ if (settingsTokenIdx !== -1 && settingsTokenIdx + 1 < remainderTokens.length)
36795
+ try {
36796
+ let s = JSON.parse(remainderTokens[settingsTokenIdx + 1]);
36797
+ if (Array.isArray(s?.permissions?.allow))
36798
+ for (let rule of s.permissions.allow) {
36799
+ if (typeof rule != "string") return !1;
36800
+ let parsed = parseToolRuleM8(rule);
36801
+ if (!parsed || !ADVISORY_PERMITTED_TOOLS.has(parsed.toolName) || ADVISORY_FORBIDDEN_TOOLS.has(parsed.toolName) || parsed.rawContent === void 0) return !1;
36802
+ let pattern = parsed.rawContent;
36803
+ if (pattern === "/*" || pattern === "*" || !pattern.startsWith("//") || pattern === "//" || pattern === "//*" || pattern === "//**" || /[\r\n\0]/.test(pattern)) return !1;
36804
+ }
36805
+ } catch {
36806
+ return !1;
36807
+ }
36808
+ let seenStrictMcp = !1, seenSettings = !1, seenSettingSources = !1, i = 1;
36809
+ for (; i < remainderTokens.length; ) {
36810
+ let token4 = remainderTokens[i];
36811
+ if (token4 === "--strict-mcp-config") {
36812
+ if (seenStrictMcp) return !1;
36813
+ seenStrictMcp = !0, i += 1;
36814
+ } else if (token4 === "--setting-sources") {
36815
+ if (seenSettingSources || i + 1 >= remainderTokens.length || remainderTokens[i + 1] !== "user") return !1;
36816
+ seenSettingSources = !0, i += 2;
36817
+ } else if (token4 === "--settings") {
36818
+ if (seenSettings || i + 1 >= remainderTokens.length) return !1;
36819
+ let settingsRaw = remainderTokens[i + 1];
36820
+ if (!settingsRaw.startsWith("{"))
36821
+ return !1;
36822
+ let settingsObj;
36823
+ try {
36824
+ settingsObj = JSON.parse(settingsRaw);
36825
+ } catch {
36826
+ return !1;
36827
+ }
36828
+ if (!settingsObj || typeof settingsObj != "object" || Array.isArray(settingsObj))
36829
+ return !1;
36830
+ let topKeys = Object.keys(settingsObj);
36831
+ if (topKeys.length !== 1 || topKeys[0] !== "permissions")
36832
+ return !1;
36833
+ let permissionsObj = settingsObj.permissions;
36834
+ if (!permissionsObj || typeof permissionsObj != "object" || Array.isArray(permissionsObj))
36835
+ return !1;
36836
+ let permKeys = Object.keys(permissionsObj);
36837
+ for (let pk of permKeys)
36838
+ if (pk !== "defaultMode" && pk !== "allow")
36839
+ return !1;
36840
+ if (permissionsObj.defaultMode !== "dontAsk" || !Array.isArray(permissionsObj.allow))
36841
+ return !1;
36842
+ let allowList = permissionsObj.allow;
36843
+ if (allowList.length !== parsedRuleSet.size)
36844
+ return !1;
36845
+ for (let r of allowList)
36846
+ if (typeof r != "string" || !parsedRuleSet.has(r))
36847
+ return !1;
36848
+ seenSettings = !0, i += 2;
36849
+ } else if (token4 === "--add-dir") {
36850
+ if (i + 1 >= remainderTokens.length) return !1;
36851
+ let addDirVal = remainderTokens[i + 1];
36852
+ if (typeof addDirVal != "string" || addDirVal.length === 0 || addDirVal.startsWith("-"))
36853
+ return !1;
36854
+ i += 2;
36855
+ } else
36856
+ return !1;
36857
+ }
36858
+ return !(!seenStrictMcp || !seenSettings || !seenSettingSources);
36859
+ }
36508
36860
  if (entry5.includes('mcp_servers.codevibe_web.command="node" *')) {
36509
36861
  if (remainderTokens.length !== 5 || remainderTokens[0] !== "-c" || !remainderTokens[1]?.startsWith("mcp_servers.codevibe_web.args=") || remainderTokens[2] !== "--output-last-message" || !remainderTokens[3] || remainderTokens[3].startsWith("-") || remainderTokens[4] !== "-")
36510
36862
  return !1;
@@ -37069,8 +37421,8 @@ async function readDirectoryBounded(dirPath, budget, label, relativePrefix = "",
37069
37421
  }
37070
37422
  if (value.type !== "entry" || typeof value.name != "string" || value.name.length === 0 || value.name === "." || value.name === ".." || value.name.includes("/") || value.name.includes("\\") || value.name.includes("\0") || !Number.isSafeInteger(value.kind))
37071
37423
  throw new Error(`${label} helper returned an invalid entry`);
37072
- let relative22 = relativePrefix ? path39.join(relativePrefix, value.name) : value.name;
37073
- consumeMetadataPath(budget, relative22, label);
37424
+ let relative23 = relativePrefix ? path39.join(relativePrefix, value.name) : value.name;
37425
+ consumeMetadataPath(budget, relative23, label);
37074
37426
  let stat13;
37075
37427
  if (opts.includeStats === !0) {
37076
37428
  let raw = value.stat;
@@ -38680,6 +39032,86 @@ function buildClaudeNoToolsPlanArgv() {
38680
39032
  capture: { kind: "stdout" }
38681
39033
  };
38682
39034
  }
39035
+ function escapeClaudePathGlob(p) {
39036
+ return (process.platform === "win32" ? p.replace(/\\/g, "/") : p).replace(/\[/g, "\\[").replace(/\]/g, "\\]").replace(/\*/g, "\\*").replace(/\?/g, "\\?");
39037
+ }
39038
+ function formatClaudePermissionPath(p) {
39039
+ return p.startsWith("//") ? p : p.startsWith("/") ? "/" + p : p;
39040
+ }
39041
+ function buildClaudeReadOnlyAdvisoryPlanArgv(workdir, attachments) {
39042
+ let rulesList = [], argv = ["claude", "--print", "--output-format", "json"], addDirs = [];
39043
+ if (workdir) {
39044
+ let resolvedWorkdir = import_node_path.default.resolve(workdir);
39045
+ addDirs.push(resolvedWorkdir);
39046
+ let realWorkdir = null;
39047
+ try {
39048
+ realWorkdir = (0, import_node_fs19.realpathSync)(resolvedWorkdir);
39049
+ } catch {
39050
+ }
39051
+ let targetPatterns = /* @__PURE__ */ new Set(), escapedWorkdir = escapeClaudePathGlob(resolvedWorkdir);
39052
+ if (targetPatterns.add(formatClaudePermissionPath(`${escapedWorkdir}/**`)), realWorkdir && realWorkdir !== resolvedWorkdir) {
39053
+ let escapedRealWorkdir = escapeClaudePathGlob(realWorkdir);
39054
+ targetPatterns.add(formatClaudePermissionPath(`${escapedRealWorkdir}/**`));
39055
+ }
39056
+ if (attachments && attachments.length > 0)
39057
+ for (let att of attachments) {
39058
+ let resolvedAtt = import_node_path.default.resolve(att), stat13 = null;
39059
+ try {
39060
+ stat13 = (0, import_node_fs19.statSync)(resolvedAtt);
39061
+ } catch {
39062
+ }
39063
+ let isDir = !!stat13?.isDirectory(), escapedAtt = escapeClaudePathGlob(resolvedAtt);
39064
+ isDir ? (targetPatterns.add(formatClaudePermissionPath(`${escapedAtt}/**`)), addDirs.push(resolvedAtt)) : targetPatterns.add(formatClaudePermissionPath(escapedAtt));
39065
+ try {
39066
+ let realAtt = (0, import_node_fs19.realpathSync)(resolvedAtt);
39067
+ if (realAtt !== resolvedAtt) {
39068
+ let escapedRealAtt = escapeClaudePathGlob(realAtt);
39069
+ isDir ? targetPatterns.add(formatClaudePermissionPath(`${escapedRealAtt}/**`)) : targetPatterns.add(formatClaudePermissionPath(escapedRealAtt));
39070
+ }
39071
+ } catch {
39072
+ }
39073
+ }
39074
+ let readRules = Array.from(targetPatterns).map((p) => `Read(${p})`), grepRules = Array.from(targetPatterns).map((p) => `Grep(${p})`), globRules = Array.from(targetPatterns).map((p) => `Glob(${p})`);
39075
+ rulesList.push(...readRules, ...grepRules, ...globRules);
39076
+ }
39077
+ let hasRules = rulesList.length > 0, toolsValue = hasRules ? "Read,Grep,Glob" : "", allowedToolsValue = hasRules ? rulesList.join(",") : "";
39078
+ if (hasRules) {
39079
+ let parsedVendor = vendorBu([allowedToolsValue]);
39080
+ if (parsedVendor.length !== rulesList.length)
39081
+ throw new Error(
39082
+ `Ambiguous Claude allowed-tools path serialization: vendor tokenizer split ${rulesList.length} rules into ${parsedVendor.length} tokens for path: ${workdir}`
39083
+ );
39084
+ for (let token4 of parsedVendor) {
39085
+ let parsed = parseToolRuleM8(token4);
39086
+ if (!parsed || parsed.rawContent === void 0)
39087
+ throw new Error(
39088
+ `Ambiguous Claude allowed-tools path serialization: vendor tokenizer produced bare tool rule '${token4}' for path: ${workdir}`
39089
+ );
39090
+ }
39091
+ }
39092
+ argv.push(
39093
+ "--tools",
39094
+ toolsValue,
39095
+ "--allowed-tools",
39096
+ allowedToolsValue,
39097
+ "--settings",
39098
+ JSON.stringify({
39099
+ permissions: {
39100
+ defaultMode: "dontAsk",
39101
+ allow: rulesList
39102
+ }
39103
+ }),
39104
+ "--setting-sources",
39105
+ "user",
39106
+ "--strict-mcp-config"
39107
+ );
39108
+ for (let d of addDirs)
39109
+ argv.push("--add-dir", d);
39110
+ return {
39111
+ argv,
39112
+ capture: { kind: "stdout" }
39113
+ };
39114
+ }
38683
39115
  var AGY_MODEL_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_.:/-]*$/;
38684
39116
  function resolveAgyModel(env = process.env) {
38685
39117
  let raw = env.CODEVIBE_AGY_MODEL;
@@ -38692,15 +39124,8 @@ function resolveAgyModel(env = process.env) {
38692
39124
  }
38693
39125
  var AGY_IMPLEMENTOR_PRINT_TIMEOUT = "3600s";
38694
39126
  function agyImplementorArgvPrefix(mode) {
38695
- let model = resolveAgyModel();
38696
- return [
38697
- "agy",
38698
- ...mode === "plan" ? ["--sandbox"] : ["--dangerously-skip-permissions"],
38699
- ...model !== null ? ["--model", model] : [],
38700
- "--print-timeout",
38701
- AGY_IMPLEMENTOR_PRINT_TIMEOUT,
38702
- "--add-dir"
38703
- ];
39127
+ let model = resolveAgyModel(), argv = ["agy"];
39128
+ return mode === "plan" ? argv.push("--mode", "plan", "--sandbox") : argv.push("--dangerously-skip-permissions"), model !== null && argv.push("--model", model), argv.push("--print-timeout", AGY_IMPLEMENTOR_PRINT_TIMEOUT, "--add-dir"), argv;
38704
39129
  }
38705
39130
  function agyImplementorAllowlistEntries() {
38706
39131
  return [
@@ -38948,6 +39373,8 @@ var IMPLEMENTOR_COMMAND_ALLOWLIST = [
38948
39373
  // is part of the fixed argv → mirrored here or the drift test fails.
38949
39374
  "claude --print --output-format json --allowed-tools Read,Grep,Glob",
38950
39375
  buildClaudeNoToolsPlanArgv().argv.join(" "),
39376
+ buildClaudeReadOnlyAdvisoryPlanArgv().argv.join(" "),
39377
+ "claude --print --output-format json --tools Read,Grep,Glob --allowed-tools *",
38951
39378
  "claude --print --bare --output-format json --allowed-tools Read,Grep,Glob --settings *",
38952
39379
  "claude --print --output-format json --allowed-tools Read,Grep,Glob,Edit,Write,Bash",
38953
39380
  // Agent web access allowlist templates (Phase 1 Claude Code)
@@ -39254,8 +39681,7 @@ var HookBridge = class {
39254
39681
  };
39255
39682
 
39256
39683
  // src/local-executor/local-executor-impl.ts
39257
- var import_node_crypto34 = require("node:crypto"), syncFs = __toESM(require("node:fs"));
39258
- var path60 = __toESM(require("node:path"));
39684
+ var import_node_crypto34 = require("node:crypto"), syncFs = __toESM(require("node:fs")), os37 = __toESM(require("node:os")), path60 = __toESM(require("node:path"));
39259
39685
 
39260
39686
  // src/local-executor/class-a-emit.ts
39261
39687
  var import_node_fs20 = require("node:fs"), import_ulid3 = require("ulid");
@@ -39484,17 +39910,17 @@ function pick(obj, camel, snake) {
39484
39910
  }
39485
39911
  function normalizeTrackAssignedWire(raw) {
39486
39912
  if (!raw || typeof raw != "object") return {};
39487
- let o = raw, osRaw = pick(o, "ownershipScope", "ownership_scope"), os52 = osRaw && typeof osRaw == "object" ? osRaw : {}, sharedContracts = pick(os52, "sharedContracts", "shared_contracts"), ccRaw = pick(o, "conflictContext", "conflict_context"), conflictContext = ccRaw && typeof ccRaw == "object" ? normalizeConflictContext(ccRaw) : void 0;
39913
+ let o = raw, osRaw = pick(o, "ownershipScope", "ownership_scope"), os53 = osRaw && typeof osRaw == "object" ? osRaw : {}, sharedContracts = pick(os53, "sharedContracts", "shared_contracts"), ccRaw = pick(o, "conflictContext", "conflict_context"), conflictContext = ccRaw && typeof ccRaw == "object" ? normalizeConflictContext(ccRaw) : void 0;
39488
39914
  return {
39489
39915
  task_group_id: pick(o, "taskGroupId", "task_group_id"),
39490
39916
  track_index: pick(o, "trackIndex", "track_index"),
39491
39917
  task_id: pick(o, "taskId", "task_id"),
39492
39918
  implementor_agent: upperAgentKind(pick(o, "implementorAgent", "implementor_agent")),
39493
39919
  ownership_scope: {
39494
- write_paths: pick(os52, "writePaths", "write_paths"),
39920
+ write_paths: pick(os53, "writePaths", "write_paths"),
39495
39921
  shared_contracts: sharedContracts,
39496
- test_surfaces: pick(os52, "testSurfaces", "test_surfaces"),
39497
- auto_modified_files: pick(os52, "autoModifiedFiles", "auto_modified_files")
39922
+ test_surfaces: pick(os53, "testSurfaces", "test_surfaces"),
39923
+ auto_modified_files: pick(os53, "autoModifiedFiles", "auto_modified_files")
39498
39924
  },
39499
39925
  is_shared_test_owner: pick(o, "isSharedTestOwner", "is_shared_test_owner"),
39500
39926
  state_dir: pick(o, "stateDir", "state_dir"),
@@ -39600,8 +40026,8 @@ function isU32(value) {
39600
40026
  }
39601
40027
  function isValidTrackAssignedPayload(payload) {
39602
40028
  if (!payload || typeof payload != "object" || typeof payload.task_group_id != "string" || payload.task_group_id.length === 0 || typeof payload.task_id != "string" || payload.task_id.length === 0 || typeof payload.state_dir != "string" || payload.state_dir.length === 0 || typeof payload.dispatch_id != "string" || payload.dispatch_id.length === 0 || !isU32(payload.track_index) || !isU32(payload.dispatch_generation) || typeof payload.implementor_agent != "string" || !VALID_IMPLEMENTOR_AGENTS.has(payload.implementor_agent) || typeof payload.is_shared_test_owner != "boolean") return !1;
39603
- let os52 = payload.ownership_scope;
39604
- return !(!os52 || typeof os52 != "object" || !Array.isArray(os52.write_paths) || !Array.isArray(os52.auto_modified_files) || !Array.isArray(os52.shared_contracts) || !Array.isArray(os52.test_surfaces) || !os52.write_paths.every((p) => typeof p == "string") || !os52.auto_modified_files.every((p) => typeof p == "string") || !os52.test_surfaces.every((p) => typeof p == "string"));
40029
+ let os53 = payload.ownership_scope;
40030
+ return !(!os53 || typeof os53 != "object" || !Array.isArray(os53.write_paths) || !Array.isArray(os53.auto_modified_files) || !Array.isArray(os53.shared_contracts) || !Array.isArray(os53.test_surfaces) || !os53.write_paths.every((p) => typeof p == "string") || !os53.auto_modified_files.every((p) => typeof p == "string") || !os53.test_surfaces.every((p) => typeof p == "string"));
39605
40031
  }
39606
40032
  function isValidMergeGateDispatchPayload(payload) {
39607
40033
  if (!payload || typeof payload != "object" || typeof payload.task_group_id != "string" || payload.task_group_id.length === 0 || typeof payload.merge_gate_id != "string" || payload.merge_gate_id.length === 0 || typeof payload.dispatch_id != "string" || payload.dispatch_id.length === 0 || payload.integration_check_spec === void 0 || payload.integration_check_spec === null || !isU32(payload.owner_track_index) || !isU32(payload.dispatch_generation) || payload.decision_protocol_version !== void 0 && payload.decision_protocol_version !== 1 && payload.decision_protocol_version !== 2) return !1;
@@ -41554,9 +41980,9 @@ async function main(){
41554
41980
  main().catch(err=>{process.stderr.write(String(err&&err.stack?err.stack:err));process.exitCode=1;});
41555
41981
  `;
41556
41982
  function safeRelative(root, candidate) {
41557
- let relative22 = path45.relative(root, path45.resolve(candidate));
41558
- if (relative22.length === 0 || path45.isAbsolute(relative22) || relative22 === ".." || relative22.startsWith(`..${path45.sep}`) || relative22.includes("\0") || relative22.split(path45.sep).some((part) => part.length === 0 || part === "." || part === "..")) throw new Error("workspace materializer path escaped its root");
41559
- return relative22;
41983
+ let relative23 = path45.relative(root, path45.resolve(candidate));
41984
+ if (relative23.length === 0 || path45.isAbsolute(relative23) || relative23 === ".." || relative23.startsWith(`..${path45.sep}`) || relative23.includes("\0") || relative23.split(path45.sep).some((part) => part.length === 0 || part === "." || part === "..")) throw new Error("workspace materializer path escaped its root");
41985
+ return relative23;
41560
41986
  }
41561
41987
  function createWorkspaceMaterializerSession(opts) {
41562
41988
  assertWorkspaceRootAuthoritySchema(opts.sourceRoot), assertWorkspaceRootAuthoritySchema(opts.destinationRoot);
@@ -44171,29 +44597,29 @@ async function sealSnapshotTreeDurably(snapshotRoot, snapshotRootAuthority, env)
44171
44597
  }
44172
44598
  );
44173
44599
  for (let entry5 of entries) {
44174
- let relative22 = current.relative ? path48.join(current.relative, entry5.name) : entry5.name, absolute = path48.join(snapshotRoot, relative22), stat13 = await fs39.lstat(absolute, { bigint: !0 });
44600
+ let relative23 = current.relative ? path48.join(current.relative, entry5.name) : entry5.name, absolute = path48.join(snapshotRoot, relative23), stat13 = await fs39.lstat(absolute, { bigint: !0 });
44175
44601
  if (stat13.isDirectory() && !stat13.isSymbolicLink()) {
44176
44602
  let enumerated = boundedDirectoryStat(entry5);
44177
44603
  if (!enumerated || enumerated.dev !== stat13.dev.toString() || enumerated.ino !== stat13.ino.toString())
44178
- throw new Error(`snapshot directory changed after enumeration: ${relative22}`);
44179
- pending2.push({ absolute, relative: relative22, identity: enumerated });
44604
+ throw new Error(`snapshot directory changed after enumeration: ${relative23}`);
44605
+ pending2.push({ absolute, relative: relative23, identity: enumerated });
44180
44606
  continue;
44181
44607
  }
44182
44608
  if (stat13.isSymbolicLink())
44183
44609
  continue;
44184
44610
  if (!stat13.isFile())
44185
- throw new Error(`snapshot durability seal refuses special file: ${relative22}`);
44611
+ throw new Error(`snapshot durability seal refuses special file: ${relative23}`);
44186
44612
  let handle = await fs39.open(absolute, import_node_fs23.constants.O_RDONLY | import_node_fs23.constants.O_NOFOLLOW);
44187
44613
  try {
44188
44614
  let before = await handle.stat({ bigint: !0 });
44189
44615
  if (!before.isFile() || before.dev !== stat13.dev || before.ino !== stat13.ino)
44190
- throw new Error(`snapshot file changed before durability sync: ${relative22}`);
44616
+ throw new Error(`snapshot file changed before durability sync: ${relative23}`);
44191
44617
  await env.beforeSnapshotDurabilitySync?.("file", absolute), await handle.sync();
44192
44618
  let [after, live] = await Promise.all([
44193
44619
  handle.stat({ bigint: !0 }),
44194
44620
  fs39.lstat(absolute, { bigint: !0 })
44195
44621
  ]);
44196
- if (!after.isFile() || !live.isFile() || live.isSymbolicLink() || after.dev !== before.dev || after.ino !== before.ino || live.dev !== before.dev || live.ino !== before.ino || after.size !== before.size || after.mtimeNs !== before.mtimeNs || after.ctimeNs !== before.ctimeNs) throw new Error(`snapshot file changed during durability sync: ${relative22}`);
44622
+ if (!after.isFile() || !live.isFile() || live.isSymbolicLink() || after.dev !== before.dev || after.ino !== before.ino || live.dev !== before.dev || live.ino !== before.ino || after.size !== before.size || after.mtimeNs !== before.mtimeNs || after.ctimeNs !== before.ctimeNs) throw new Error(`snapshot file changed during durability sync: ${relative23}`);
44197
44623
  } finally {
44198
44624
  await handle.close().catch(() => {
44199
44625
  });
@@ -44702,12 +45128,12 @@ function assertStateMarkerLifecycleCapacity(marker, maxBytes) {
44702
45128
  }, maxBytes);
44703
45129
  }
44704
45130
  async function retireFailedCreateStateMarker(stateFile, taskId, stateRootAuthority, maxBytes) {
44705
- let relative22 = path48.relative(stateRootAuthority.canonicalPath, stateFile), parts = relative22.split(path48.sep);
44706
- if (parts.length !== 2 || parts[0] !== taskId || path48.isAbsolute(relative22) || parts.some((part) => part === ".."))
45131
+ let relative23 = path48.relative(stateRootAuthority.canonicalPath, stateFile), parts = relative23.split(path48.sep);
45132
+ if (parts.length !== 2 || parts[0] !== taskId || path48.isAbsolute(relative23) || parts.some((part) => part === ".."))
44707
45133
  throw new Error("failed-create marker is outside its state-root authority");
44708
45134
  let read = await anchoredReadFileWithinRoot(
44709
45135
  stateRootAuthority.canonicalPath,
44710
- relative22,
45136
+ relative23,
44711
45137
  {
44712
45138
  maxBytes,
44713
45139
  expectedRoot: stateRootAuthority,
@@ -55716,14 +56142,14 @@ var LocalExecutorImpl = class {
55716
56142
  deps.deviceSigningKey
55717
56143
  )), this.bridge = new HookBridge({
55718
56144
  emitter: this.emitter,
55719
- emitShellEvent: this.emitShellEvent,
56145
+ emitShellEvent: this.emitShellEvent ?? (async () => ({ kind: "dropped", reason: "unwired" })),
55720
56146
  getAuthorityScope: () => this.baseScope,
55721
56147
  getCurrentTaskId: () => null,
55722
56148
  getContextWithoutTask: () => this.baseCtx,
55723
56149
  adapter: this.adapter
55724
56150
  }), this.classBConsumer = new ClassBConsumer({
55725
56151
  emitter: this.emitter,
55726
- emitShellEvent: this.emitShellEvent,
56152
+ emitShellEvent: this.emitShellEvent ?? (async () => ({ kind: "dropped", reason: "unwired" })),
55727
56153
  getContext: () => this.contextOrFallback(),
55728
56154
  advanceAuthorityScope: (newScope, taskId) => {
55729
56155
  this.scopeByTask.set(taskId, mergeAuthorityScope(this.baseScope, newScope));
@@ -55933,7 +56359,56 @@ var LocalExecutorImpl = class {
55933
56359
  args: launchArgs,
55934
56360
  onExit,
55935
56361
  substrateEngaged
55936
- } = await this.engageSubstrateForSpawn(promptBoundArgs, spawnTaskScope), outerBoundaryConfines = substrateEngaged || isTrustedContainerBoundary(), finalArgs = {
56362
+ } = await this.engageSubstrateForSpawn(promptBoundArgs, spawnTaskScope), outerBoundaryConfines = substrateEngaged || isTrustedContainerBoundary(), claudeIsolatedConfigDir = null, claudeSecureStorageConfigDir = null, cleanupClaudeConfig = null;
56363
+ if ((launchArgs.agentKind ?? this.adapter) === "CLAUDE" && launchArgs.role === "implementor" && launchArgs.lifecycleAudit === "none" && isStrictReadOnlyAdvisoryClaude(launchArgs.argv) && !launchArgs.envOverrides?.CLAUDE_CONFIG_DIR && !outerBoundaryConfines) {
56364
+ claudeIsolatedConfigDir = syncFs.mkdtempSync(
56365
+ path60.join(os37.tmpdir(), `cv-claude-cfg-${process.pid}-${(0, import_node_crypto34.randomUUID)().slice(0, 8)}-`)
56366
+ );
56367
+ let ambientClaudeDir = process.env.CLAUDE_CONFIG_DIR || path60.join(os37.homedir(), ".claude");
56368
+ claudeSecureStorageConfigDir = process.env.CLAUDE_SECURESTORAGE_CONFIG_DIR !== void 0 ? process.env.CLAUDE_SECURESTORAGE_CONFIG_DIR : process.env.CLAUDE_CONFIG_DIR !== void 0 ? process.env.CLAUDE_CONFIG_DIR : "";
56369
+ try {
56370
+ let authFiles = [".credentials.json", "credentials.json", "config.json", "auth.json"];
56371
+ for (let f of authFiles) {
56372
+ let src = path60.join(ambientClaudeDir, f);
56373
+ if (syncFs.existsSync(src)) {
56374
+ let dest = path60.join(claudeIsolatedConfigDir, f);
56375
+ try {
56376
+ syncFs.copyFileSync(src, dest), syncFs.chmodSync(dest, 384);
56377
+ } catch (copyErr) {
56378
+ throw new Error(
56379
+ `failed to copy Claude credential file ${f}: ${copyErr?.message}`
56380
+ );
56381
+ }
56382
+ }
56383
+ }
56384
+ let settingsIdx = launchArgs.argv.indexOf("--settings"), settingsPayload = settingsIdx !== -1 && settingsIdx + 1 < launchArgs.argv.length ? launchArgs.argv[settingsIdx + 1] : "{}";
56385
+ syncFs.writeFileSync(
56386
+ path60.join(claudeIsolatedConfigDir, "settings.json"),
56387
+ settingsPayload,
56388
+ { mode: 384 }
56389
+ );
56390
+ } catch (setupErr) {
56391
+ let cleanupErr = null;
56392
+ try {
56393
+ syncFs.rmSync(claudeIsolatedConfigDir, { recursive: !0, force: !0 }), syncFs.existsSync(claudeIsolatedConfigDir) && (cleanupErr = new Error(`setup cleanup failed: ${claudeIsolatedConfigDir} still exists`));
56394
+ } catch (err) {
56395
+ cleanupErr = err;
56396
+ }
56397
+ throw cleanupErr ? Object.assign(
56398
+ new Error(
56399
+ `ephemeral Claude config setup failed (${setupErr?.message}) and cleanup also failed (${cleanupErr?.message})`
56400
+ ),
56401
+ { cause: setupErr, cleanupCause: cleanupErr }
56402
+ ) : setupErr;
56403
+ }
56404
+ cleanupClaudeConfig = async () => {
56405
+ if (claudeIsolatedConfigDir && syncFs.existsSync(claudeIsolatedConfigDir) && (syncFs.rmSync(claudeIsolatedConfigDir, { recursive: !0, force: !0 }), syncFs.existsSync(claudeIsolatedConfigDir)))
56406
+ throw new Error(
56407
+ `failed to cleanup ephemeral Claude config directory: ${claudeIsolatedConfigDir} still exists`
56408
+ );
56409
+ };
56410
+ }
56411
+ let finalArgs = {
55937
56412
  ...launchArgs,
55938
56413
  argv: applyOuterBoundarySandbox(
55939
56414
  relocateCodexLastMessageForSubstrate(
@@ -55943,11 +56418,24 @@ var LocalExecutorImpl = class {
55943
56418
  ),
55944
56419
  launchArgs.agentKind ?? this.adapter,
55945
56420
  outerBoundaryConfines
55946
- )
55947
- }, spawnScope = outerBoundaryConfines ? withBoundaryConfinedCommandAuthority(spawnTaskScope) : spawnTaskScope, handle = await this.spawnWithLifecycle(
56421
+ ),
56422
+ ...claudeIsolatedConfigDir ? {
56423
+ envOverrides: {
56424
+ ...launchArgs.envOverrides,
56425
+ CLAUDE_CONFIG_DIR: claudeIsolatedConfigDir,
56426
+ ...claudeSecureStorageConfigDir !== null ? { CLAUDE_SECURESTORAGE_CONFIG_DIR: claudeSecureStorageConfigDir } : {}
56427
+ }
56428
+ } : {}
56429
+ }, spawnScope = outerBoundaryConfines ? withBoundaryConfinedCommandAuthority(spawnTaskScope) : spawnTaskScope, combinedOnExit = async () => {
56430
+ try {
56431
+ cleanupClaudeConfig && await cleanupClaudeConfig();
56432
+ } finally {
56433
+ onExit && await onExit();
56434
+ }
56435
+ }, handle = await this.spawnWithLifecycle(
55948
56436
  finalArgs,
55949
56437
  (a) => spawnImplementor(spawnScope, a),
55950
- onExit
56438
+ combinedOnExit
55951
56439
  );
55952
56440
  return advisoryAdmission && this.bindAdvisorySpawn(advisoryAdmission, handle), handle;
55953
56441
  } catch (error) {
@@ -56050,19 +56538,59 @@ var LocalExecutorImpl = class {
56050
56538
  * takes the legacy path.
56051
56539
  */
56052
56540
  async engageSubstrateForSpawn(args, scope) {
56541
+ let agentKind = args.agentKind ?? this.adapter;
56053
56542
  if (args.role !== "implementor" || this.substrateEngager === void 0) {
56054
- if (args.requireConfined)
56543
+ if (args.requireConfined) {
56544
+ if (args.lifecycleAudit === "none") {
56545
+ if (agentKind === "CLAUDE" && isStrictReadOnlyAdvisoryClaude(args.argv))
56546
+ return { args, substrateEngaged: !1 };
56547
+ if (agentKind === "CODEX" && isStrictReadOnlyAdvisoryCodex(args.argv))
56548
+ return { args, substrateEngaged: !1 };
56549
+ }
56055
56550
  throw new SpawnConfinementUnavailable(
56056
56551
  "requireConfined implementor spawn but no substrate engager is wired \u2014 fail closed"
56057
56552
  );
56553
+ }
56058
56554
  return { args, substrateEngaged: !1 };
56059
56555
  }
56060
- let agentKind = args.agentKind ?? this.adapter;
56061
56556
  if (args.lifecycleAudit === "none") {
56062
- if (args.requireConfined)
56557
+ if (agentKind === "ANTIGRAVITY") {
56558
+ if (args.requireConfined) {
56559
+ if (!this.substrateEngager)
56560
+ throw new SpawnConfinementUnavailable(
56561
+ "requireConfined advisory spawn for ANTIGRAVITY but no substrate engager is wired \u2014 fail closed"
56562
+ );
56563
+ let result2 = await this.substrateEngager({
56564
+ taskId: args.taskId ?? "advisory",
56565
+ agentKind,
56566
+ workdir: args.workingDir,
56567
+ role: args.role,
56568
+ requireConfined: !0,
56569
+ writableWorkdir: !1,
56570
+ ...args.processTreeId ? { processTreeId: args.processTreeId } : {}
56571
+ });
56572
+ if (result2.mode === "substrate")
56573
+ return {
56574
+ args: { ...args, substrate: result2.substrateHandle },
56575
+ onExit: () => result2.teardown(),
56576
+ substrateEngaged: !0
56577
+ };
56578
+ throw await result2.teardown().catch(() => {
56579
+ }), new SpawnConfinementUnavailable(
56580
+ `requireConfined advisory spawn for ${agentKind} but substrate engaged reduced_trust (${result2.reducedTrustReason}) \u2014 fail closed`
56581
+ );
56582
+ }
56583
+ return { args, substrateEngaged: !1 };
56584
+ }
56585
+ if (args.requireConfined) {
56586
+ if (agentKind === "CLAUDE" && isStrictReadOnlyAdvisoryClaude(args.argv))
56587
+ return { args, substrateEngaged: !1 };
56588
+ if (agentKind === "CODEX" && isStrictReadOnlyAdvisoryCodex(args.argv))
56589
+ return { args, substrateEngaged: !1 };
56063
56590
  throw new SpawnConfinementUnavailable(
56064
- "requireConfined implementor spawn cannot opt out of lifecycle audit/substrate \u2014 fail closed"
56591
+ `requireConfined advisory spawn for ${agentKind} requires a strictly validated read-only invocation \u2014 fail closed`
56065
56592
  );
56593
+ }
56066
56594
  return { args, substrateEngaged: !1 };
56067
56595
  }
56068
56596
  let effectiveTaskId = args.taskId ?? null;
@@ -58155,7 +58683,7 @@ var NO_OP_PASS = Object.freeze({
58155
58683
  });
58156
58684
 
58157
58685
  // src/local-executor/durable-store.ts
58158
- var crypto24 = __toESM(require("node:crypto")), os37 = __toESM(require("node:os")), path64 = __toESM(require("node:path"));
58686
+ var crypto24 = __toESM(require("node:crypto")), os38 = __toESM(require("node:os")), path64 = __toESM(require("node:path"));
58159
58687
  init_logger2();
58160
58688
  var DIR_MODE8 = 448, FILE_MODE10 = 384, MAX_STORE_JSON_BYTES = 64 * 1024 * 1024, MAX_PREIMAGE_BYTES = MAX_REVIEW_FILE_BYTES, MAX_PREIMAGE_AGGREGATE_BYTES = MAX_PROMOTION_PREIMAGE_AGGREGATE_BYTES, REVERT_MANIFEST_VERSION = 1, ABSENT_PREIMAGE = "ABSENT", ORPHAN_TTL_MS = 2880 * 60 * 1e3, MANIFEST_FILE = "manifest.json", JOURNAL_FILE = "journal.json", PREIMAGE_DIR = "preimages", TRACK_TIPS_FILE = "track-tips.json", TRACK_TIPS_VERSION = 1, TRACK_BUNDLES_FILE = "track-bundles.json", TRACK_BUNDLES_VERSION = 1, OWNER_LEASE_RE = /^\.codevibe-owner-[0-9a-f]{64}\.json$/, STORE_HELPER_SOURCE_ENV = "CODEVIBE_STORE_HELPER_SOURCE_B64", STORE_HELPER_BOOTSTRAP = `const k=${JSON.stringify(STORE_HELPER_SOURCE_ENV)};const s=process.env[k];delete process.env[k];if(!s)throw new Error('missing store helper source');Function(Buffer.from(s,'base64').toString('utf8'))();`, STORE_HELPER_SOURCE = String.raw`
58161
58689
  const fs = require('node:fs');
@@ -58367,7 +58895,7 @@ function validateTrackBundlesRecord(value, taskGroupId, limits = {
58367
58895
  return value;
58368
58896
  }
58369
58897
  function defaultRoot4() {
58370
- return path64.join(os37.homedir(), ".codevibe", "revert-state");
58898
+ return path64.join(os38.homedir(), ".codevibe", "revert-state");
58371
58899
  }
58372
58900
  function hashContent2(content) {
58373
58901
  return crypto24.createHash("sha256").update(Buffer.from(content, "utf8")).digest("hex");
@@ -58628,7 +59156,7 @@ var RevertManifestStore = class {
58628
59156
  if (!this.rootDirectoryPromise) {
58629
59157
  let creation = (async () => {
58630
59158
  let durable = await ensureDurableDirectoryTree(root, {
58631
- anchorPath: root === path64.resolve(os37.homedir()) || root.startsWith(`${path64.resolve(os37.homedir())}${path64.sep}`) ? path64.resolve(os37.homedir()) : path64.dirname(root),
59159
+ anchorPath: root === path64.resolve(os38.homedir()) || root.startsWith(`${path64.resolve(os38.homedir())}${path64.sep}`) ? path64.resolve(os38.homedir()) : path64.dirname(root),
58632
59160
  mode: DIR_MODE8,
58633
59161
  enforceTargetMode: !0,
58634
59162
  helperTimeoutMs: this.helperTimeoutMs,
@@ -61623,7 +62151,7 @@ function withImplementorCredentialPreflight(engage, store) {
61623
62151
  }
61624
62152
 
61625
62153
  // src/substrate/docker.ts
61626
- var import_node_fs30 = require("node:fs"), os39 = __toESM(require("node:os")), path67 = __toESM(require("node:path"));
62154
+ var import_node_fs30 = require("node:fs"), os40 = __toESM(require("node:os")), path67 = __toESM(require("node:path"));
61627
62155
 
61628
62156
  // src/substrate/command-runner.ts
61629
62157
  var import_node_child_process9 = require("node:child_process");
@@ -61926,7 +62454,7 @@ var DockerHandle = class {
61926
62454
  }
61927
62455
  }, DockerSubstrate = class {
61928
62456
  constructor(deps = {}) {
61929
- this.runner = deps.runner ?? new ChildProcessCommandRunner(), this.forwarderFactory = deps.forwarderFactory ?? defaultForwarderFactory, this.onEgressDenied = deps.onEgressDenied ?? NOOP_EGRESS_HOOK, this.image = deps.image ?? DEFAULT_IMAGE, this.sessionRoot = deps.sessionRoot ?? os39.tmpdir(), this.acquireWorkdirLease = deps.acquireWorkdirLease ?? acquireWorkspaceRootLease;
62457
+ this.runner = deps.runner ?? new ChildProcessCommandRunner(), this.forwarderFactory = deps.forwarderFactory ?? defaultForwarderFactory, this.onEgressDenied = deps.onEgressDenied ?? NOOP_EGRESS_HOOK, this.image = deps.image ?? DEFAULT_IMAGE, this.sessionRoot = deps.sessionRoot ?? os40.tmpdir(), this.acquireWorkdirLease = deps.acquireWorkdirLease ?? acquireWorkspaceRootLease;
61930
62458
  }
61931
62459
  async launch(spec) {
61932
62460
  await this.assertDockerAvailable();
@@ -62057,7 +62585,7 @@ function randomId() {
62057
62585
  }
62058
62586
 
62059
62587
  // src/substrate/sandbox-exec.ts
62060
- var import_node_fs31 = require("node:fs"), os40 = __toESM(require("node:os")), path68 = __toESM(require("node:path"));
62588
+ var import_node_fs31 = require("node:fs"), os41 = __toESM(require("node:os")), path68 = __toESM(require("node:path"));
62061
62589
  var import_node_path2 = require("node:path");
62062
62590
  var NODE_PREFIXES = ["/opt/homebrew", "/usr/local", "/opt/local"], FILE_KEYCHAIN_DIR_NAME = ".codevibe", SYSCTL_READ_ALLOW = [
62063
62591
  '(sysctl-name-prefix "hw.")',
@@ -62096,7 +62624,12 @@ function nodeReadDirs(execPath) {
62096
62624
  }
62097
62625
  return [...dirs];
62098
62626
  }
62099
- function buildSeatbeltProfile(workdir, execPath = process.execPath, extraReadDirs = [], homedir40 = os40.homedir(), auditDir = null, extraWriteDirs = [], networkPosture = "loopback") {
62627
+ function isInsideOrEqual2(child, parent) {
62628
+ if (child === parent) return !0;
62629
+ let rel = path68.relative(parent, child);
62630
+ return rel.length > 0 && !rel.startsWith("..") && !path68.isAbsolute(rel);
62631
+ }
62632
+ function buildSeatbeltProfile(workdir, execPath = process.execPath, extraReadDirs = [], homedir41 = os41.homedir(), auditDir = null, extraWriteDirs = [], networkPosture = "loopback", writableWorkdir = !0) {
62100
62633
  let esc = (s) => s.replace(/"/g, '\\"'), wd = esc(workdir), lines = [
62101
62634
  "(version 1)",
62102
62635
  "(deny default)",
@@ -62208,7 +62741,14 @@ function buildSeatbeltProfile(workdir, execPath = process.execPath, extraReadDir
62208
62741
  for (let dir of extraWriteDirs) subpathReadGrants.push(dir);
62209
62742
  for (let dir of subpathReadGrants)
62210
62743
  lines.push(`(allow file-read* (subpath "${esc(dir)}"))`);
62211
- lines.push(`(allow file-write* (subpath "${wd}"))`);
62744
+ if (!writableWorkdir) {
62745
+ for (let dir of extraWriteDirs)
62746
+ if (isInsideOrEqual2(dir, wd))
62747
+ throw new Error(
62748
+ `writable runtime grant "${dir}" is inside read-only workdir "${wd}" \u2014 conflicting boundary`
62749
+ );
62750
+ }
62751
+ writableWorkdir && lines.push(`(allow file-write* (subpath "${wd}"))`);
62212
62752
  for (let dir of extraWriteDirs)
62213
62753
  lines.push(`(allow file-write* (subpath "${esc(dir)}"))`);
62214
62754
  let litReads = /* @__PURE__ */ new Set();
@@ -62220,11 +62760,11 @@ function buildSeatbeltProfile(workdir, execPath = process.execPath, extraReadDir
62220
62760
  `(deny file-read* (subpath "${wd}/.git"))`,
62221
62761
  `(deny file-write* (subpath "${wd}/.git"))`
62222
62762
  );
62223
- let fileKeychainDir = esc(path68.join(homedir40, FILE_KEYCHAIN_DIR_NAME));
62763
+ let fileKeychainDir = esc(path68.join(homedir41, FILE_KEYCHAIN_DIR_NAME));
62224
62764
  if (lines.push(
62225
62765
  `(deny file-read* (subpath "${fileKeychainDir}"))`,
62226
62766
  `(deny file-write* (subpath "${fileKeychainDir}"))`
62227
- ), auditDir !== null) {
62767
+ ), writableWorkdir || lines.push(`(deny file-write* (subpath "${wd}"))`), auditDir !== null) {
62228
62768
  let ad = esc(auditDir);
62229
62769
  lines.push(
62230
62770
  `(deny file-read* (subpath "${ad}"))`,
@@ -62233,12 +62773,12 @@ function buildSeatbeltProfile(workdir, execPath = process.execPath, extraReadDir
62233
62773
  }
62234
62774
  return networkPosture === "open" ? lines.push(
62235
62775
  // A1d resolver-confinement row: deny all network, then re-allow ALL
62236
- // OUTBOUND (inbound stays denied). The broker-less reduced-trust agent
62237
- // (agy/gemini) dials its vendor directly with its own file-based auth —
62238
- // egress is NOT pinned on this row (the engage result badges it); the
62239
- // row's confinement objective is the FS-write fence above.
62776
+ // OUTBOUND (external inbound stays denied). Loopback bind/inbound is permitted
62777
+ // for local IPC (e.g. Antigravity local RPC daemon on 127.0.0.1).
62240
62778
  "(deny network*)",
62241
62779
  "(allow network-outbound)",
62780
+ '(allow network-bind (local ip "localhost:*"))',
62781
+ '(allow network-inbound (local ip "localhost:*"))',
62242
62782
  ""
62243
62783
  ) : lines.push(
62244
62784
  // Network: deny all, then re-allow loopback ONLY (the coarse tier).
@@ -62285,12 +62825,12 @@ var SandboxExecHandle = class {
62285
62825
  `agent binary '${argv[0]}' not found on the host PATH \u2014 cannot exec in the sandbox`
62286
62826
  );
62287
62827
  let realArgv0 = await import_node_fs31.promises.realpath(resolvedArgv0).catch(() => resolvedArgv0), deniedRoots = [
62288
- path68.join(os40.homedir(), ".codevibe"),
62828
+ path68.join(os41.homedir(), ".codevibe"),
62289
62829
  path68.join(this.workdir, ".git"),
62290
62830
  ...this.auditDir !== null ? [this.auditDir] : []
62291
62831
  ], overlapsDeniedRoot = (d) => deniedRoots.some(
62292
62832
  (root) => d === root || d.startsWith(root + path68.sep) || root.startsWith(d + path68.sep)
62293
- ), broadRoots = /* @__PURE__ */ new Set(["/", "/Users", "/home", os40.homedir()]), binDirs = /* @__PURE__ */ new Set([path68.dirname(resolvedArgv0), path68.dirname(realArgv0)]);
62833
+ ), broadRoots = /* @__PURE__ */ new Set(["/", "/Users", "/home", os41.homedir()]), binDirs = /* @__PURE__ */ new Set([path68.dirname(resolvedArgv0), path68.dirname(realArgv0)]);
62294
62834
  for (let d of binDirs)
62295
62835
  if (overlapsDeniedRoot(d) || broadRoots.has(d))
62296
62836
  throw new SubstrateLaunchError(
@@ -62337,7 +62877,7 @@ ${allowLines}
62337
62877
  }
62338
62878
  }, SandboxExecSubstrate = class {
62339
62879
  constructor(deps = {}) {
62340
- this.runner = deps.runner ?? new ChildProcessCommandRunner(), this.profileRoot = deps.profileRoot ?? os40.tmpdir(), this.platform = deps.platform ?? process.platform;
62880
+ this.runner = deps.runner ?? new ChildProcessCommandRunner(), this.profileRoot = deps.profileRoot ?? os41.tmpdir(), this.platform = deps.platform ?? process.platform;
62341
62881
  }
62342
62882
  async launch(spec) {
62343
62883
  if (this.platform !== "darwin")
@@ -62403,12 +62943,13 @@ ${allowLines}
62403
62943
  canonicalWorkdir,
62404
62944
  process.execPath,
62405
62945
  extraReadDirs,
62406
- os40.homedir(),
62946
+ os41.homedir(),
62407
62947
  resolvedAuditDir,
62408
62948
  extraWriteDirs,
62409
62949
  // A1d — the resolver-confinement row threads `'open'`; absent → loopback
62410
62950
  // (the CP-7 broker tier, byte-identical profile).
62411
- spec.networkPosture ?? "loopback"
62951
+ spec.networkPosture ?? "loopback",
62952
+ spec.writableWorkdir !== !1
62412
62953
  ), profilePath = path68.join(this.profileRoot, `codevibe-seatbelt-${id5}.sb`);
62413
62954
  try {
62414
62955
  await import_node_fs31.promises.writeFile(profilePath, profile, { encoding: "utf8", mode: 384 });
@@ -63089,7 +63630,7 @@ function formatReviewerError(detail) {
63089
63630
  }
63090
63631
 
63091
63632
  // src/reviewer/providers/codex.ts
63092
- var fs51 = __toESM(require("fs")), os41 = __toESM(require("os")), path70 = __toESM(require("path")), import_uuid11 = require("uuid");
63633
+ var fs51 = __toESM(require("fs")), os42 = __toESM(require("os")), path70 = __toESM(require("path")), import_uuid11 = require("uuid");
63093
63634
 
63094
63635
  // src/reviewer/output-parser.ts
63095
63636
  var RESIDUAL_OBSERVATIONS_HEADING = "RESIDUAL OBSERVATIONS:";
@@ -63324,7 +63865,7 @@ function trimEnd(s) {
63324
63865
  var FAILURE_EVENT_TYPES = /* @__PURE__ */ new Set([
63325
63866
  "error",
63326
63867
  "turn.failed"
63327
- ]), USAGE_LIMIT_RE = /usage limit|purchase more credits|try again at|rate.?limit/i, AUTH_FAILED_RE = /unauthorized|not logged in|authenticat|invalid api key|\b401\b/i;
63868
+ ]), USAGE_LIMIT_RE = /(?:usage|weekly|daily|monthly|rate).?limit|purchase more credits|try again at/i, AUTH_FAILED_RE = /unauthorized|not logged in|authenticat|invalid api key|\b401\b/i;
63328
63869
  function classifyFailureMessage(message2) {
63329
63870
  return USAGE_LIMIT_RE.test(message2) ? "usage_limit" : AUTH_FAILED_RE.test(message2) ? "auth_failed" : null;
63330
63871
  }
@@ -63599,7 +64140,7 @@ function extractCodexUsageSnapshot(stdout, elapsedMs) {
63599
64140
  }) : unavailableUsageSnapshot("usage_not_reported", elapsedMs);
63600
64141
  }
63601
64142
  function makeLastMessagePath() {
63602
- return path70.join(os41.tmpdir(), `quorum-codex-last-${process.pid}-${(0, import_uuid11.v4)()}.txt`);
64143
+ return path70.join(os42.tmpdir(), `quorum-codex-last-${process.pid}-${(0, import_uuid11.v4)()}.txt`);
63603
64144
  }
63604
64145
  function makeLastMessageBasename() {
63605
64146
  return `quorum-codex-last-${process.pid}-${(0, import_uuid11.v4)()}.txt`;
@@ -63944,7 +64485,7 @@ function classifyImplementorQuotaFailure(exitCode, text2) {
63944
64485
  function defaultOutageNotificationRoot() {
63945
64486
  if (process.env.CODEVIBE_OUTAGE_NOTIFICATION_ROOT)
63946
64487
  return process.env.CODEVIBE_OUTAGE_NOTIFICATION_ROOT;
63947
- let baseHome = process.env.CODEVIBE_HOME_OVERRIDE || os42.homedir();
64488
+ let baseHome = process.env.CODEVIBE_HOME_OVERRIDE || os43.homedir();
63948
64489
  return path71.join(baseHome, ".codevibe", "outage-notifications");
63949
64490
  }
63950
64491
  function cleanDirectorySafely(dir) {
@@ -69927,7 +70468,7 @@ ${section}`);
69927
70468
  oursCommit,
69928
70469
  theirsCommit,
69929
70470
  baseSha
69930
- }), parentDir = await import_node_fs32.promises.mkdtemp(path71.join(os42.tmpdir(), "codevibe-wb2-resolve-"));
70471
+ }), parentDir = await import_node_fs32.promises.mkdtemp(path71.join(os43.tmpdir(), "codevibe-wb2-resolve-"));
69931
70472
  return resolveAgenticSlot({
69932
70473
  realRepoDir: this.deps.workingDir,
69933
70474
  // canonical loop workdir == repo root
@@ -75150,10 +75691,10 @@ function destructiveConfirmationQuestion(text2) {
75150
75691
  }
75151
75692
 
75152
75693
  // src/orchestration-shell/advisory-attachment-journal.ts
75153
- var import_node_crypto37 = require("node:crypto"), os43 = __toESM(require("node:os")), path72 = __toESM(require("node:path")), import_node_fs33 = require("node:fs");
75694
+ var import_node_crypto37 = require("node:crypto"), os44 = __toESM(require("node:os")), path72 = __toESM(require("node:path")), import_node_fs33 = require("node:fs");
75154
75695
  var JOURNAL_DIR_NAME = "advisory-attachment-authority", JOURNAL_MAX_RECORD_BYTES = 32 * 1024, JOURNAL_MAX_ENTRIES = 1e4, JOURNAL_MAX_METADATA_BYTES = 16 * 1024 * 1024, BATCH_NAME_RE = /^batch-([0-9a-f]{64})\.json$/, ATTACHMENT_NAME_RE = /^attachment-([0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})\.json$/i, PROCESS_NAME_RE = /^process-([0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})\.json$/i, RETIREMENT_NAME_RE = /^\.codevibe-retire-([0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})$/i, UUID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i, SHA256_RE = /^[0-9a-f]{64}$/;
75155
75696
  function resolveHome10() {
75156
- return (process.env.VITEST === "true" || process.env.NODE_ENV === "test") && process.env.CODEVIBE_HOME_OVERRIDE ? process.env.CODEVIBE_HOME_OVERRIDE : os43.homedir();
75697
+ return (process.env.VITEST === "true" || process.env.NODE_ENV === "test") && process.env.CODEVIBE_HOME_OVERRIDE ? process.env.CODEVIBE_HOME_OVERRIDE : os44.homedir();
75157
75698
  }
75158
75699
  function advisoryAttachmentJournalRoot(home = resolveHome10()) {
75159
75700
  return path72.join(home, ".codevibe", JOURNAL_DIR_NAME);
@@ -75340,8 +75881,8 @@ var AdvisoryAttachmentJournal = class {
75340
75881
  opts.anchorPath ?? (opts.rootDir ? path72.dirname(this.rootPath) : resolveHome10())
75341
75882
  ), this.currentOwner = opts.currentProcessIdentityFn ?? currentProcessIdentity, this.ownerIsAlive = opts.isProcessIdentityAliveFn ?? isProcessIdentityAlive, this.retryProcessOwner = opts.retryProcessCleanupOwnerFn ?? retryProcessCleanupOwner, this.mintId = opts.newId ?? import_node_crypto37.randomUUID, this.now = opts.now ?? Date.now, this.retirementSettleMs = opts.retirementSettleMs ?? 1e3, !Number.isSafeInteger(this.retirementSettleMs) || this.retirementSettleMs < 0 || this.retirementSettleMs > 1e4)
75342
75883
  throw new Error("invalid advisory attachment retirement settle window");
75343
- let relative22 = path72.relative(this.anchorPath, this.rootPath);
75344
- if (relative22 === ".." || relative22.startsWith(`..${path72.sep}`) || path72.isAbsolute(relative22))
75884
+ let relative23 = path72.relative(this.anchorPath, this.rootPath);
75885
+ if (relative23 === ".." || relative23.startsWith(`..${path72.sep}`) || path72.isAbsolute(relative23))
75345
75886
  throw new Error("advisory attachment journal root escaped its private anchor");
75346
75887
  }
75347
75888
  async openRoot(create) {
@@ -76145,7 +76686,7 @@ function classifyDurableWorkspaceOutcome(event, displayedSessionId, decryptedMet
76145
76686
  }
76146
76687
 
76147
76688
  // src/orchestration-shell/workspace-terminal-coordinator.ts
76148
- var crypto29 = __toESM(require("node:crypto")), import_node_fs34 = require("node:fs"), os44 = __toESM(require("node:os")), path73 = __toESM(require("node:path"));
76689
+ var crypto29 = __toESM(require("node:crypto")), import_node_fs34 = require("node:fs"), os45 = __toESM(require("node:os")), path73 = __toESM(require("node:path"));
76149
76690
  init_logger2();
76150
76691
 
76151
76692
  // src/orchestration-shell/emit-shell-event.ts
@@ -76768,7 +77309,7 @@ var WorkspaceTerminalCoordinator = class {
76768
77309
  this.operationChain = Promise.resolve();
76769
77310
  if (!options.session.sessionGenerationId || !UUID_RE5.test(options.session.sessionGenerationId))
76770
77311
  throw new Error("WorkspaceTerminalCoordinator: session generation is unavailable");
76771
- this.session = options.session, this.appsyncClient = options.appsyncClient, this.getSessionKey = options.getSessionKey, this.rootDir = options.rootDir ?? path73.join(os44.homedir(), ".codevibe"), this.now = options.now ?? (() => /* @__PURE__ */ new Date()), this.onSyncIssue = options.onSyncIssue;
77312
+ this.session = options.session, this.appsyncClient = options.appsyncClient, this.getSessionKey = options.getSessionKey, this.rootDir = options.rootDir ?? path73.join(os45.homedir(), ".codevibe"), this.now = options.now ?? (() => /* @__PURE__ */ new Date()), this.onSyncIssue = options.onSyncIssue;
76772
77313
  }
76773
77314
  generation() {
76774
77315
  return this.session.sessionGenerationId;
@@ -77330,7 +77871,7 @@ var WorkspaceTerminalCoordinator = class {
77330
77871
  };
77331
77872
 
77332
77873
  // src/orchestration-shell/decision-effect.ts
77333
- var crypto30 = __toESM(require("node:crypto")), fs55 = __toESM(require("node:fs/promises")), import_node_fs35 = require("node:fs"), os45 = __toESM(require("node:os")), path74 = __toESM(require("node:path"));
77874
+ var crypto30 = __toESM(require("node:crypto")), fs55 = __toESM(require("node:fs/promises")), import_node_fs35 = require("node:fs"), os46 = __toESM(require("node:os")), path74 = __toESM(require("node:path"));
77334
77875
  var RECEIPT_VERSION = 1, DIRECTORY_MODE2 = 448, FILE_MODE11 = 384, MAX_RECEIPT_BYTES2 = 64 * 1024, MAX_SESSION_RECEIPTS2 = 64, KNOWN_DECISIONS2 = /* @__PURE__ */ new Set([
77335
77876
  "APPROVE",
77336
77877
  "CANCEL",
@@ -77345,7 +77886,7 @@ function opaque(value) {
77345
77886
  return crypto30.createHash("sha256").update(value, "utf8").digest("hex");
77346
77887
  }
77347
77888
  function defaultRoot5() {
77348
- return path74.join(os45.homedir(), ".codevibe", "decision-effects");
77889
+ return path74.join(os46.homedir(), ".codevibe", "decision-effects");
77349
77890
  }
77350
77891
  function durableResolutionDescriptorHash(resolution) {
77351
77892
  return crypto30.createHash("sha256").update(JSON.stringify({
@@ -77387,10 +77928,10 @@ var DecisionEffectReceiptStore = class {
77387
77928
  return path74.join(this.rootDir, opaque(sessionId), `${opaque(decisionClaimId)}.json`);
77388
77929
  }
77389
77930
  async assertNoSymlinkComponents(target2) {
77390
- let relative22 = path74.relative(this.rootDir, target2);
77391
- if (relative22.startsWith("..") || path74.isAbsolute(relative22))
77931
+ let relative23 = path74.relative(this.rootDir, target2);
77932
+ if (relative23.startsWith("..") || path74.isAbsolute(relative23))
77392
77933
  throw new Error("DecisionEffectReceiptStore: path escaped root");
77393
- let components = relative22 ? relative22.split(path74.sep) : [], current = this.rootDir;
77934
+ let components = relative23 ? relative23.split(path74.sep) : [], current = this.rootDir;
77394
77935
  for (let index = -1; index < components.length; index += 1) {
77395
77936
  index >= 0 && (current = path74.join(current, components[index]));
77396
77937
  try {
@@ -79435,7 +79976,7 @@ ${notFoundMsg}`), fallbackSection && sections.push(fallbackSection);
79435
79976
  }
79436
79977
 
79437
79978
  // src/continuation/packet-reader.ts
79438
- var import_node_fs36 = require("node:fs"), path76 = __toESM(require("node:path")), os46 = __toESM(require("node:os")), import_yaml2 = require("yaml");
79979
+ var import_node_fs36 = require("node:fs"), path76 = __toESM(require("node:path")), os47 = __toESM(require("node:os")), import_yaml2 = require("yaml");
79439
79980
  init_types();
79440
79981
  init_packet_writer();
79441
79982
  init_packet_writer();
@@ -79506,7 +80047,7 @@ async function packetHashIsInAudit(appsync, packet, packetHash) {
79506
80047
  }
79507
80048
  }
79508
80049
  function createContinuationPacketReader(deps) {
79509
- let homeDir = deps.homeDir ?? os46.homedir();
80050
+ let homeDir = deps.homeDir ?? os47.homedir();
79510
80051
  return {
79511
80052
  async read(taskId, expectedHash) {
79512
80053
  let filePath = getPacketFilePath(taskId, homeDir), stat13;
@@ -83969,12 +84510,11 @@ function readOnlyAgentPrompt(args) {
83969
84510
  `);
83970
84511
  return args.agent === "ANTIGRAVITY" && args.allowRepositoryTools ? `${agyReadOnlyWorkdirPreamble(args.workingDir)}${body}` : body;
83971
84512
  }
83972
- function readOnlyAdvisoryAllowsRepositoryTools(input) {
83973
- let text2 = input.toLowerCase(), concreteRepositoryTarget = /\b(repo|repository|codebase|workspace|source tree|working tree|pending diff|diff|files?|folders?|directories|logs?|tests?)\b/.test(text2) || /(?:^|\s)(?:\.{1,2}\/|\/|~\/)/.test(text2) || /\b[a-z0-9_-]+\.(?:ts|tsx|js|jsx|swift|kt|java|rs|py|md|json|ya?ml|toml|gradle|xml)\b/i.test(input), inspectionIntent = /\b(read|inspect|check|look at|look into|review|summarize|analyze|investigate|scan|search|find|trace|debug)\b/.test(text2) || /\bpending diff\b/.test(text2) || /\brun tests?\b/.test(text2);
83974
- return concreteRepositoryTarget && inspectionIntent;
84513
+ function readOnlyAdvisoryAllowsRepositoryTools(_input) {
84514
+ return !0;
83975
84515
  }
83976
- function applyReadOnlyAdvisoryToolPolicy(agent, plan, allowRepositoryTools) {
83977
- return allowRepositoryTools || agent !== "CLAUDE" ? plan : buildClaudeNoToolsPlanArgv();
84516
+ function applyReadOnlyAdvisoryToolPolicy(agent, plan, allowRepositoryTools, workingDir, attachments) {
84517
+ return agent !== "CLAUDE" ? plan : allowRepositoryTools ? buildClaudeReadOnlyAdvisoryPlanArgv(workingDir, attachments) : buildClaudeNoToolsPlanArgv();
83978
84518
  }
83979
84519
  async function readPlanModeOutput(args) {
83980
84520
  try {
@@ -84028,7 +84568,11 @@ function syntheticReadOnlyAdvisoryTaskId() {
84028
84568
  return (0, import_uuid15.v4)();
84029
84569
  }
84030
84570
  function classifyClaudeResultStdoutQuota(stdout) {
84031
- let result = firstResultEnvelope(stdout)?.result;
84571
+ let env = firstResultEnvelope(stdout);
84572
+ if (!env) return !1;
84573
+ if (env.api_error === "usage_limit_reached" || env.api_error_status === 429 || typeof env.api_error == "string" && classifyFailureMessage(env.api_error) === "usage_limit")
84574
+ return !0;
84575
+ let result = env.result;
84032
84576
  return typeof result == "string" && result.length > 0 && classifyFailureMessage(result) === "usage_limit";
84033
84577
  }
84034
84578
  function extractReadOnlyAdvisoryUsage(args) {
@@ -84080,10 +84624,14 @@ async function runReadOnlyAgentAdvisoryResult(args) {
84080
84624
  args.attachmentBatch,
84081
84625
  args.workingDir
84082
84626
  ) : await attachmentJournal.assertWorkspaceSafe(args.workingDir);
84083
- let allowRepositoryTools = readOnlyAdvisoryAllowsRepositoryTools(args.advisoryBrief), plan = applyReadOnlyAdvisoryToolPolicy(
84627
+ let allowRepositoryTools = readOnlyAdvisoryAllowsRepositoryTools(args.advisoryBrief), attachmentPaths = [];
84628
+ args.attachmentBatch?.value.directory.canonicalPath && attachmentPaths.push(args.attachmentBatch.value.directory.canonicalPath);
84629
+ let plan = applyReadOnlyAdvisoryToolPolicy(
84084
84630
  args.agent,
84085
84631
  buildImplementorArgv(args.agent, "plan", args.workingDir),
84086
- allowRepositoryTools
84632
+ allowRepositoryTools,
84633
+ args.workingDir,
84634
+ attachmentPaths
84087
84635
  ), processAuthority = null, bindProcessOwner = args.attachmentBatch ? async (owner) => {
84088
84636
  if (processAuthority)
84089
84637
  throw new Error("advisory process authority was already bound");
@@ -84096,13 +84644,27 @@ async function runReadOnlyAgentAdvisoryResult(args) {
84096
84644
  throw new Error("advisory process retirement has no durable authority");
84097
84645
  let authority = processAuthority;
84098
84646
  await attachmentJournal.retireProcess(authority, owner), processAuthority = null;
84099
- } : void 0, advisoryTaskId = syntheticReadOnlyAdvisoryTaskId(), handle = await args.shellArgs.localExecutor.spawnImplementor({
84647
+ } : void 0, advisoryTaskId = syntheticReadOnlyAdvisoryTaskId(), treeBefore = await probeWorkspaceTreeFingerprint(args.workingDir);
84648
+ if (treeBefore.kind !== "fingerprint")
84649
+ return logger.error("[orchestration-shell] workspace fingerprint unavailable before read-only advisory turn \u2014 failing closed", {
84650
+ agent: args.agent,
84651
+ workingDir: args.workingDir
84652
+ }), plan.capture.kind === "file" && await (0, import_promises.unlink)(plan.capture.path).catch(() => {
84653
+ }), {
84654
+ ok: !1,
84655
+ text: readOnlyRouteFallback({ agent: args.agent }),
84656
+ quotaWalled: !1,
84657
+ timedOut: !1,
84658
+ usage: unavailableUsageSnapshot("workspace_verification_unavailable")
84659
+ };
84660
+ let handle = await args.shellArgs.localExecutor.spawnImplementor({
84100
84661
  argv: plan.argv,
84101
84662
  workingDir: args.workingDir,
84102
84663
  role: "implementor",
84103
84664
  agentKind: args.agent,
84104
84665
  taskId: advisoryTaskId,
84105
84666
  lifecycleAudit: "none",
84667
+ requireConfined: !0,
84106
84668
  timeoutMs: args.timeoutMs ?? READ_ONLY_ADVISORY_TIMEOUT_MS,
84107
84669
  stdinTty: !0,
84108
84670
  stdinPayload: readOnlyAgentPrompt({
@@ -84115,7 +84677,24 @@ async function runReadOnlyAgentAdvisoryResult(args) {
84115
84677
  }),
84116
84678
  ...bindProcessOwner ? { onCleanupOwnerReady: bindProcessOwner } : {},
84117
84679
  ...retireProcessOwner ? { onCleanupOwnerRetired: retireProcessOwner } : {}
84118
- }), exit = await handle.done, output = await readPlanModeOutput({
84680
+ }), exit = await handle.done, treeAfter = await probeWorkspaceTreeFingerprint(args.workingDir);
84681
+ if (treeAfter.kind !== "fingerprint" || treeAfter.value !== treeBefore.value)
84682
+ return logger.error("[orchestration-shell] workspace mutation or verification failure detected during read-only advisory turn", {
84683
+ agent: args.agent,
84684
+ workingDir: args.workingDir,
84685
+ before: treeBefore.value,
84686
+ after: treeAfter.kind === "fingerprint" ? treeAfter.value : "probe-failed"
84687
+ }), plan.capture.kind === "file" && await (0, import_promises.unlink)(plan.capture.path).catch(() => {
84688
+ }), {
84689
+ ok: !1,
84690
+ text: readOnlyRouteFallback({ agent: args.agent }),
84691
+ quotaWalled: !1,
84692
+ timedOut: !1,
84693
+ usage: unavailableUsageSnapshot(
84694
+ treeAfter.kind === "fingerprint" ? "workspace_mutation_detected" : "workspace_verification_unavailable"
84695
+ )
84696
+ };
84697
+ let output = await readPlanModeOutput({
84119
84698
  agent: args.agent,
84120
84699
  plan,
84121
84700
  handle,
@@ -86230,21 +86809,21 @@ async function handleShellUserInput(deps) {
86230
86809
  store.getState().session.sessionId
86231
86810
  ), store.dispatch({ type: "CLEAR_PENDING_PLANNER_OFFER" });
86232
86811
  }
86233
- let pendingForIngest = store.getState().pendingClarification, isAnsweringPending = !!pendingForIngest && pendingForIngest.rounds.length > 0 && pendingForIngest.rounds[pendingForIngest.rounds.length - 1].answer === void 0, existingAttachments = !slashCommandText.startsWith("/") && isAnsweringPending ? pendingForIngest.attachments : void 0, cwd = args.cwd ?? process.cwd(), homedir40 = os47.homedir(), runAttachmentIngest = (existing) => {
86812
+ let pendingForIngest = store.getState().pendingClarification, isAnsweringPending = !!pendingForIngest && pendingForIngest.rounds.length > 0 && pendingForIngest.rounds[pendingForIngest.rounds.length - 1].answer === void 0, existingAttachments = !slashCommandText.startsWith("/") && isAnsweringPending ? pendingForIngest.attachments : void 0, cwd = args.cwd ?? process.cwd(), homedir41 = os48.homedir(), runAttachmentIngest = (existing) => {
86234
86813
  if (deps.images && deps.images.length > 0) {
86235
86814
  let carried = attachmentsFromPaths(
86236
86815
  deps.images,
86237
86816
  existing && existing.length ? { existing } : void 0
86238
86817
  ), fromText = detectImageAttachments(text2.replace(/\[Image #\d+\]/g, " "), {
86239
86818
  cwd,
86240
- homedir: homedir40,
86819
+ homedir: homedir41,
86241
86820
  existing: carried.attachments
86242
86821
  });
86243
86822
  return { attachments: fromText.attachments, rejects: [...carried.rejects, ...fromText.rejects] };
86244
86823
  }
86245
86824
  return detectImageAttachments(text2, {
86246
86825
  cwd,
86247
- homedir: homedir40,
86826
+ homedir: homedir41,
86248
86827
  ...existing && existing.length ? { existing } : {}
86249
86828
  });
86250
86829
  }, ingest = runAttachmentIngest(existingAttachments), turnAttachments = ingest.attachments, currentTurnIngest = existingAttachments && existingAttachments.length > 0 ? runAttachmentIngest() : ingest, currentTurnAttachments = currentTurnIngest.attachments, turnImagePaths = (deps.images ?? []).map((p) => path78.resolve(p)), teamDurableStore = typeof args.quorumLoop?.getDurableStore == "function" ? args.quorumLoop.getDurableStore() : void 0, ingestRejectsSurfaced = !1, surfaceIngestRejects = (result) => {
@@ -88127,7 +88706,7 @@ async function runStructuralSummarySessionStart(deps) {
88127
88706
  try {
88128
88707
  let optIn = await readOptIn(args.tier), discovery = await discoverRepositoryRoots({ launchDir: process.cwd() }), summary = await generator.generate({
88129
88708
  rootPaths: discovery.rootPaths,
88130
- ignoreFile: path78.join(os47.homedir(), ".codevibe", "structural-summary.ignore"),
88709
+ ignoreFile: path78.join(os48.homedir(), ".codevibe", "structural-summary.ignore"),
88131
88710
  includeBodies: optIn?.bodyInclusionPaths ?? [],
88132
88711
  userId: args.session.userId,
88133
88712
  tier: args.tier
@@ -89495,7 +90074,7 @@ ${colors.green}\u2713${colors.reset} Cleared ${clearable.length} entr${clearable
89495
90074
  }
89496
90075
 
89497
90076
  // src/substrate-launch/engage-substrate.ts
89498
- var import_node_fs38 = require("node:fs"), os48 = __toESM(require("node:os")), path80 = __toESM(require("node:path"));
90077
+ var import_node_fs38 = require("node:fs"), os49 = __toESM(require("node:os")), path80 = __toESM(require("node:path"));
89499
90078
 
89500
90079
  // src/credential-broker/types.ts
89501
90080
  var BROKER_ROUTES = [
@@ -91478,7 +92057,7 @@ function providerForAgent(agentKind) {
91478
92057
  return agentKind === "CLAUDE" ? "anthropic" : agentKind === "CODEX" ? "openai" : null;
91479
92058
  }
91480
92059
  var AUDIT_SEGMENT = "audit", STATE_SEGMENT = "state", CODEVIBE_DIR = ".codevibe", AUDIT_FILE_NAME = "audit.jsonl";
91481
- function isInsideOrEqual2(child, parent) {
92060
+ function isInsideOrEqual3(child, parent) {
91482
92061
  if (child === parent) return !0;
91483
92062
  let rel = path80.relative(parent, child);
91484
92063
  return rel.length > 0 && !rel.startsWith("..") && !path80.isAbsolute(rel);
@@ -91527,7 +92106,7 @@ async function assertAuditOutsideWorkdir(auditPath, workdir) {
91527
92106
  `CP-7 W3: audit leaf "${resolvedAuditPath}" is a symlink that does not resolve (dangling) \u2014 refusing to launch (fail-closed). The audit file must be a regular file in the sibling .codevibe/audit/ tree.`
91528
92107
  );
91529
92108
  }
91530
- if (isInsideOrEqual2(realAuditDir, realWorkdir) || isInsideOrEqual2(resolvedAuditPath, realWorkdir) || isInsideOrEqual2(resolvedLeafTarget, realWorkdir))
92109
+ if (isInsideOrEqual3(realAuditDir, realWorkdir) || isInsideOrEqual3(resolvedAuditPath, realWorkdir) || isInsideOrEqual3(resolvedLeafTarget, realWorkdir))
91531
92110
  throw new Error(
91532
92111
  `CP-7 W3: audit path "${resolvedAuditPath}" (resolved target "${resolvedLeafTarget}") is inside the agent workdir "${realWorkdir}" \u2014 the agent could truncate/forge the forensic record (Stage-1 r1 HIGH fail-closed). The audit MUST live in the sibling .codevibe/audit/ tree, never under .codevibe/state/<group>/<track>/.`
91533
92112
  );
@@ -91653,7 +92232,8 @@ async function engageSubstrate(input) {
91653
92232
  ...agentScratchSpec !== null ? { agentScratch: agentScratchSpec } : {},
91654
92233
  // CP-7 W3 — Stage-2 r1 HIGH. The resolved audit dir → A5 trailing deny.
91655
92234
  // Undefined when a test injects its own in-memory sink (no real tree).
91656
- ...resolvedAuditDir !== null ? { auditDir: resolvedAuditDir } : {}
92235
+ ...resolvedAuditDir !== null ? { auditDir: resolvedAuditDir } : {},
92236
+ ...input.writableWorkdir !== void 0 ? { writableWorkdir: input.writableWorkdir } : {}
91657
92237
  };
91658
92238
  handle = await selection.substrate.launch(spec), logger.info(
91659
92239
  `[CP-7] Substrate engaged (tier=${selection.tier}, egress=${handle.egressFidelity}) \u2014 agent is creditless, broker holds the key`,
@@ -91786,7 +92366,7 @@ async function engageSubstrate(input) {
91786
92366
  }
91787
92367
  var RESOLVER_AGENT_STATE_DIR_SEGMENTS = {
91788
92368
  GEMINI: [".gemini"],
91789
- ANTIGRAVITY: [".gemini", "antigravity-cli"]
92369
+ ANTIGRAVITY: [".gemini"]
91790
92370
  };
91791
92371
  async function engageWriteConfinedResolverSandbox(input) {
91792
92372
  let agentKind = input.agentKind;
@@ -91811,14 +92391,14 @@ async function engageWriteConfinedResolverSandbox(input) {
91811
92391
  teardown: async () => {
91812
92392
  }
91813
92393
  };
91814
- let homedir40 = os48.homedir(), stateDir = path80.join(
91815
- homedir40,
92394
+ let homedir41 = os49.homedir(), stateDir = path80.join(
92395
+ homedir41,
91816
92396
  ...RESOLVER_AGENT_STATE_DIR_SEGMENTS[agentKind]
91817
92397
  );
91818
92398
  await import_node_fs38.promises.mkdir(stateDir, { recursive: !0 }).catch(() => {
91819
92399
  });
91820
92400
  let env = {}, nodeDir = process.execPath.slice(0, process.execPath.lastIndexOf("/"));
91821
- env.PATH = `${SANDBOX_DEFAULT_PATH}:${nodeDir}`, env.HOME = homedir40;
92401
+ env.PATH = `${SANDBOX_DEFAULT_PATH}:${nodeDir}`, env.HOME = homedir41;
91822
92402
  let safeSource = input.localeSource ?? {};
91823
92403
  for (let key of SAFE_ENV_ALLOWLIST) {
91824
92404
  let v = safeSource[key];
@@ -91838,7 +92418,8 @@ async function engageWriteConfinedResolverSandbox(input) {
91838
92418
  // The agent's own auth/state home — writable, read-granted (A5: sandbox fs
91839
92419
  // == host fs, so sandboxDir == hostDir).
91840
92420
  agentConfig: { hostDir: stateDir, sandboxDir: stateDir },
91841
- networkPosture: "open"
92421
+ networkPosture: "open",
92422
+ writableWorkdir: input.writableWorkdir !== !1
91842
92423
  }, handle = await selection.substrate.launch(spec);
91843
92424
  return logger.info(
91844
92425
  `[A1d] Resolver-confinement row engaged (tier=sandbox_exec, egress=open) \u2014 writes fenced to the disposable workspace; ${agentKind} runs on its own file-based auth (no broker)`,
@@ -92513,8 +93094,8 @@ function isLocalModelEntitled(entitlement) {
92513
93094
  }
92514
93095
  function localModelArtifactPath(config) {
92515
93096
  if (!config.artifactId || !isSafeArtifactId(config.artifactId)) return null;
92516
- let cacheRoot = import_path5.default.resolve(config.cacheDir), artifactPath = import_path5.default.resolve(cacheRoot, config.artifactId), relative22 = import_path5.default.relative(cacheRoot, artifactPath);
92517
- return !relative22 || relative22.startsWith("..") || import_path5.default.isAbsolute(relative22) ? null : artifactPath;
93097
+ let cacheRoot = import_path5.default.resolve(config.cacheDir), artifactPath = import_path5.default.resolve(cacheRoot, config.artifactId), relative23 = import_path5.default.relative(cacheRoot, artifactPath);
93098
+ return !relative23 || relative23.startsWith("..") || import_path5.default.isAbsolute(relative23) ? null : artifactPath;
92518
93099
  }
92519
93100
  function isSafeArtifactId(artifactId) {
92520
93101
  return artifactId === import_path5.default.basename(artifactId) && artifactId !== "." && artifactId !== ".." && !import_path5.default.isAbsolute(artifactId);