@quantiya/codevibe-claude-plugin 2.0.21 → 2.0.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/node_modules/@quantiya/codevibe-core/dist/diagnostics/shape-only.d.ts +11 -0
- package/node_modules/@quantiya/codevibe-core/dist/index.js +321 -282
- package/node_modules/@quantiya/codevibe-core/dist/local-executor/process-tree.d.ts +2 -0
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/__tests__/o5-diagnostics.test.d.ts +1 -0
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/cli.js +517 -115
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/quorum-loop.d.ts +8 -1
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/reducer.d.ts +4 -5
- package/node_modules/@quantiya/codevibe-core/dist/reviewer/provider.d.ts +7 -7
- package/node_modules/@quantiya/codevibe-core/dist/substrate/command-runner.d.ts +1 -0
- package/node_modules/@quantiya/codevibe-core/dist/substrate/sandbox-exec.d.ts +3 -2
- package/node_modules/@quantiya/codevibe-core/dist/substrate/types.d.ts +20 -0
- package/node_modules/@quantiya/codevibe-core/dist/substrate-launch/apikey-bootstrap.d.ts +32 -1
- package/node_modules/@quantiya/codevibe-core/dist/substrate-launch/engage-substrate.d.ts +2 -0
- package/node_modules/@quantiya/codevibe-core/dist/substrate-launch/sanitized-env.d.ts +6 -0
- package/node_modules/@quantiya/codevibe-core/package.json +1 -1
- package/node_modules/fs-ext/build/Makefile +1 -1
- package/node_modules/fs-ext/build/Release/fs_ext.node +0 -0
- package/node_modules/fs-ext/build/config.gypi +0 -2
- package/package.json +2 -2
|
@@ -8410,9 +8410,10 @@ function reduceSessionTaskTerminal(state, event) {
|
|
|
8410
8410
|
if (terminal === null) return state;
|
|
8411
8411
|
let taskId = "taskId" in event ? event.taskId : void 0;
|
|
8412
8412
|
if (!taskId) return state;
|
|
8413
|
-
let existing = state.sessionTasks.get(taskId), sessionTasks = new Map(state.sessionTasks);
|
|
8413
|
+
let runningTasks = new Map(state.runningTasks), evictedRunningTask = runningTasks.delete(taskId), existing = state.sessionTasks.get(taskId), sessionTasks = new Map(state.sessionTasks);
|
|
8414
8414
|
if (existing) {
|
|
8415
|
-
if (existing.origin !== "single" || existing.status !== "running")
|
|
8415
|
+
if (existing.origin !== "single" || existing.status !== "running")
|
|
8416
|
+
return evictedRunningTask ? { ...state, runningTasks } : state;
|
|
8416
8417
|
sessionTasks.set(taskId, { ...existing, status: terminal });
|
|
8417
8418
|
} else
|
|
8418
8419
|
sessionTasks.set(taskId, {
|
|
@@ -8421,7 +8422,7 @@ function reduceSessionTaskTerminal(state, event) {
|
|
|
8421
8422
|
status: terminal,
|
|
8422
8423
|
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
8423
8424
|
});
|
|
8424
|
-
return { ...state, sessionTasks };
|
|
8425
|
+
return { ...state, runningTasks, sessionTasks };
|
|
8425
8426
|
}
|
|
8426
8427
|
var REVIEWER_STATUS_PHASES = /* @__PURE__ */ new Set([
|
|
8427
8428
|
"reviewers_dispatched",
|
|
@@ -8724,9 +8725,9 @@ function reduceClarificationAnswered(state, answer) {
|
|
|
8724
8725
|
};
|
|
8725
8726
|
}
|
|
8726
8727
|
function reduceTaskLifecycle(state, task) {
|
|
8727
|
-
let next = new Map(state.runningTasks);
|
|
8728
|
-
|
|
8729
|
-
let history = new Map(state.sessionTasks)
|
|
8728
|
+
let existing = state.sessionTasks.get(task.taskId), existingIsTerminal = existing?.origin === "single" && (existing.status === "completed" || existing.status === "cancelled" || existing.status === "failed"), incomingIsTerminal = task.status === "completed" || task.status === "cancelled" || task.status === "failed", next = new Map(state.runningTasks);
|
|
8729
|
+
incomingIsTerminal || existingIsTerminal && !incomingIsTerminal ? next.delete(task.taskId) : next.set(task.taskId, task);
|
|
8730
|
+
let history = new Map(state.sessionTasks);
|
|
8730
8731
|
return history.set(task.taskId, {
|
|
8731
8732
|
taskId: task.taskId,
|
|
8732
8733
|
agentKind: task.agentKind,
|
|
@@ -20276,6 +20277,37 @@ async function bindWorkingDirectory(payload){
|
|
|
20276
20277
|
throw new Error('target cwd incarnation changed before launch');
|
|
20277
20278
|
}
|
|
20278
20279
|
}
|
|
20280
|
+
function holdLaunchPathAuthorities(payload){
|
|
20281
|
+
const authorities=payload.launchPathAuthorities;
|
|
20282
|
+
if(authorities===undefined)return [];
|
|
20283
|
+
if(!Array.isArray(authorities)||authorities.length>16)throw new Error('invalid launch path authorities');
|
|
20284
|
+
const held=[];
|
|
20285
|
+
try{
|
|
20286
|
+
for(const authority of authorities){
|
|
20287
|
+
if(!authority||authority.version!==1||
|
|
20288
|
+
typeof authority.canonicalPath!=='string'||!require('node:path').isAbsolute(authority.canonicalPath)||authority.canonicalPath.includes('\0')||
|
|
20289
|
+
typeof authority.dev!=='string'||typeof authority.ino!=='string'||
|
|
20290
|
+
typeof authority.birthtimeNs!=='string')throw new Error('invalid launch path authority');
|
|
20291
|
+
const flags=fs.constants.O_RDONLY|(fs.constants.O_DIRECTORY||0)|(fs.constants.O_NOFOLLOW||0);
|
|
20292
|
+
const fd=fs.openSync(authority.canonicalPath,flags);
|
|
20293
|
+
held.push(fd);
|
|
20294
|
+
const opened=fs.fstatSync(fd,{bigint:true});
|
|
20295
|
+
const live=fs.lstatSync(authority.canonicalPath,{bigint:true});
|
|
20296
|
+
const canonical=fs.realpathSync(authority.canonicalPath);
|
|
20297
|
+
if(!opened.isDirectory()||!live.isDirectory()||live.isSymbolicLink()||
|
|
20298
|
+
opened.dev.toString()!==authority.dev||opened.ino.toString()!==authority.ino||
|
|
20299
|
+
opened.birthtimeNs.toString()!==authority.birthtimeNs||
|
|
20300
|
+
live.dev.toString()!==authority.dev||live.ino.toString()!==authority.ino||
|
|
20301
|
+
live.birthtimeNs.toString()!==authority.birthtimeNs||canonical!==authority.canonicalPath){
|
|
20302
|
+
throw new Error('launch path authority changed before target spawn');
|
|
20303
|
+
}
|
|
20304
|
+
}
|
|
20305
|
+
return held;
|
|
20306
|
+
}catch(err){
|
|
20307
|
+
for(const fd of held){try{fs.closeSync(fd);}catch{}}
|
|
20308
|
+
throw err;
|
|
20309
|
+
}
|
|
20310
|
+
}
|
|
20279
20311
|
const hostPipe=fs.createReadStream(null,{fd:5,autoClose:false});
|
|
20280
20312
|
for(const event of ['end','close','error'])hostPipe.once(event,killOwnGroup);
|
|
20281
20313
|
for(const [signal] of [['SIGTERM'],['SIGINT'],['SIGHUP']])process.on(signal,killOwnGroup);
|
|
@@ -20284,9 +20316,17 @@ for(const [signal] of [['SIGTERM'],['SIGINT'],['SIGHUP']])process.on(signal,kill
|
|
|
20284
20316
|
const start=await readLine(4);
|
|
20285
20317
|
if(start!=='START')throw new Error('target start not authorized');
|
|
20286
20318
|
await bindWorkingDirectory(payload);
|
|
20319
|
+
// This is deliberately synchronous and immediately adjacent to cp.spawn:
|
|
20320
|
+
// keep exact directory descriptors open across native process creation so a
|
|
20321
|
+
// pathname replacement during durable-owner publication cannot be adopted.
|
|
20322
|
+
const launchPathFds=holdLaunchPathAuthorities(payload);
|
|
20287
20323
|
// No pathname cwd is passed here: the child inherits the wrapper's already-
|
|
20288
20324
|
// authenticated kernel cwd reference, so a later rename cannot redirect it.
|
|
20289
|
-
|
|
20325
|
+
try{
|
|
20326
|
+
target=cp.spawn(payload.command,payload.args,{env:payload.env,stdio:['inherit','inherit','inherit'],detached:false,windowsHide:true});
|
|
20327
|
+
}finally{
|
|
20328
|
+
for(const fd of launchPathFds){try{fs.closeSync(fd);}catch{}}
|
|
20329
|
+
}
|
|
20290
20330
|
target.once('error',err=>{send({type:'target-exit',code:127,error:String(err&&err.message||err)});});
|
|
20291
20331
|
target.once('exit',(code,signal)=>{send({type:'target-exit',code:Number.isInteger(code)?code:(signal?128:1)});});
|
|
20292
20332
|
// Remain the authenticated group/session leader until the outside host has
|
|
@@ -20386,6 +20426,7 @@ function spawnPosixOwnedProcess(command, args, options, seams = {}) {
|
|
|
20386
20426
|
args,
|
|
20387
20427
|
cwd: targetCwd,
|
|
20388
20428
|
cwdAuthority: seams.workingDirAuthority,
|
|
20429
|
+
launchPathAuthorities: seams.launchPathAuthorities,
|
|
20389
20430
|
env: options?.env ?? process.env,
|
|
20390
20431
|
...seams.cleanupTimeoutMs === void 0 ? {} : { cleanupTimeoutMs: seams.cleanupTimeoutMs }
|
|
20391
20432
|
}), "utf8");
|
|
@@ -26408,6 +26449,38 @@ var LocalGemmaPlannerAdapter = class {
|
|
|
26408
26449
|
// src/orchestration-shell/quorum-loop.ts
|
|
26409
26450
|
var import_node_fs24 = require("node:fs");
|
|
26410
26451
|
|
|
26452
|
+
// src/diagnostics/shape-only.ts
|
|
26453
|
+
function outputShapeOnly(raw) {
|
|
26454
|
+
if (typeof raw != "string" || raw.length === 0)
|
|
26455
|
+
return {
|
|
26456
|
+
bytes: 0,
|
|
26457
|
+
lines: 0,
|
|
26458
|
+
leadClass: "empty",
|
|
26459
|
+
fenceCount: 0,
|
|
26460
|
+
bulletLines: 0,
|
|
26461
|
+
blankLines: 0
|
|
26462
|
+
};
|
|
26463
|
+
let lines = raw.split(`
|
|
26464
|
+
`), trimmed = raw.trim(), leadClass;
|
|
26465
|
+
return trimmed.length === 0 ? leadClass = "empty" : trimmed.startsWith("{") || trimmed.startsWith("[") ? leadClass = "json-open" : trimmed.startsWith("```") ? leadClass = "fence" : /^#{1,6}\s/.test(trimmed) ? leadClass = "heading" : /^[-*+]\s/.test(trimmed) ? leadClass = "bullet" : /^\d+[.)]\s/.test(trimmed) ? leadClass = "ordinal" : /^[A-Za-z]/.test(trimmed) ? leadClass = "prose" : leadClass = "other", {
|
|
26466
|
+
bytes: Buffer.byteLength(raw, "utf8"),
|
|
26467
|
+
lines: lines.length,
|
|
26468
|
+
leadClass,
|
|
26469
|
+
fenceCount: (raw.match(/```/g) ?? []).length,
|
|
26470
|
+
bulletLines: lines.filter((line) => /^\s*[-*+]\s/.test(line)).length,
|
|
26471
|
+
blankLines: lines.filter((line) => line.trim().length === 0).length
|
|
26472
|
+
};
|
|
26473
|
+
}
|
|
26474
|
+
function errorShapeOnly(error) {
|
|
26475
|
+
let value = error, message = typeof value?.message == "string" ? value.message : "", causeCount = Array.isArray(value?.causes) ? value.causes.length : value?.cause !== void 0 ? 1 : 0;
|
|
26476
|
+
return {
|
|
26477
|
+
errorClass: error instanceof Error ? "error" : "non-error",
|
|
26478
|
+
messageBytes: Buffer.byteLength(message, "utf8"),
|
|
26479
|
+
hasCause: value?.cause !== void 0,
|
|
26480
|
+
causeCount
|
|
26481
|
+
};
|
|
26482
|
+
}
|
|
26483
|
+
|
|
26411
26484
|
// src/reduced-trust-notice.ts
|
|
26412
26485
|
var surfacedRationales = /* @__PURE__ */ new Set();
|
|
26413
26486
|
function noticeKey(sessionId, tier, reason) {
|
|
@@ -28103,7 +28176,8 @@ var ClassBConsumer = class {
|
|
|
28103
28176
|
};
|
|
28104
28177
|
|
|
28105
28178
|
// src/substrate-launch/apikey-bootstrap.ts
|
|
28106
|
-
var import_node_fs14 = require("node:fs"), os19 = __toESM(require("node:os")), path32 = __toESM(require("node:path"))
|
|
28179
|
+
var import_node_fs14 = require("node:fs"), os19 = __toESM(require("node:os")), path32 = __toESM(require("node:path"));
|
|
28180
|
+
var HELPER_SCRIPT_NAME = "broker-apikey-helper.sh", TOKEN_FILE_NAME = "broker-token", CLAUDE_SETTINGS_NAME = "settings.json", CODEX_CONFIG_NAME = "config.toml", SANDBOX_BOOTSTRAP_DIR = "/codevibe/agent", SANDBOX_AGENT_CONFIG_DIR = "/codevibe/agent-config", CODEX_PROVIDER_ID = "codevibe_broker";
|
|
28107
28181
|
function helperScriptSource(tokenFileAbsPathInSandbox) {
|
|
28108
28182
|
return `#!/bin/sh
|
|
28109
28183
|
# CP-7 apiKeyHelper \u2014 emits the current broker token (NEVER the vendor key).
|
|
@@ -28144,12 +28218,16 @@ function isInsideOrEqual(child, parent) {
|
|
|
28144
28218
|
return rel.length > 0 && !rel.startsWith("..") && !path32.isAbsolute(rel);
|
|
28145
28219
|
}
|
|
28146
28220
|
var ApiKeyBootstrap = class _ApiKeyBootstrap {
|
|
28147
|
-
constructor(hostDir, sandboxDir, configHostDir, configSandboxDir, tokenFileHostPath) {
|
|
28221
|
+
constructor(hostDir, sandboxDir, configHostDir, configSandboxDir, tokenFileHostPath, claudeScratchHostDir, claudeScratchSandboxDir, claudeScratchIdentity, beforeClaudeScratchCleanupCommit) {
|
|
28148
28222
|
this.hostDir = hostDir;
|
|
28149
28223
|
this.sandboxDir = sandboxDir;
|
|
28150
28224
|
this.configHostDir = configHostDir;
|
|
28151
28225
|
this.configSandboxDir = configSandboxDir;
|
|
28152
28226
|
this.tokenFileHostPath = tokenFileHostPath;
|
|
28227
|
+
this.claudeScratchHostDir = claudeScratchHostDir;
|
|
28228
|
+
this.claudeScratchSandboxDir = claudeScratchSandboxDir;
|
|
28229
|
+
this.claudeScratchIdentity = claudeScratchIdentity;
|
|
28230
|
+
this.beforeClaudeScratchCleanupCommit = beforeClaudeScratchCleanupCommit;
|
|
28153
28231
|
}
|
|
28154
28232
|
/**
|
|
28155
28233
|
* Materialize the bootstrap: create the host dir (0700), write the token file
|
|
@@ -28165,9 +28243,8 @@ var ApiKeyBootstrap = class _ApiKeyBootstrap {
|
|
|
28165
28243
|
);
|
|
28166
28244
|
await import_node_fs14.promises.chmod(rawConfigHostDir, 448).catch(() => {
|
|
28167
28245
|
});
|
|
28168
|
-
let hostDir = await import_node_fs14.promises.realpath(rawHostDir), configHostDir = await import_node_fs14.promises.realpath(rawConfigHostDir);
|
|
28246
|
+
let hostDir = await import_node_fs14.promises.realpath(rawHostDir), configHostDir = await import_node_fs14.promises.realpath(rawConfigHostDir), realWorkdir;
|
|
28169
28247
|
if (input.workdir !== void 0) {
|
|
28170
|
-
let realWorkdir;
|
|
28171
28248
|
try {
|
|
28172
28249
|
realWorkdir = await import_node_fs14.promises.realpath(input.workdir);
|
|
28173
28250
|
} catch {
|
|
@@ -28204,7 +28281,7 @@ var ApiKeyBootstrap = class _ApiKeyBootstrap {
|
|
|
28204
28281
|
"ApiKeyBootstrap.create: provide `sandboxConfigDir` or `configDirEqualsHostDir`"
|
|
28205
28282
|
);
|
|
28206
28283
|
let tokenInSandbox = path32.posix.join(sandboxDir, TOKEN_FILE_NAME), helperInSandbox = path32.posix.join(sandboxDir, HELPER_SCRIPT_NAME), tokenFileHostPath = path32.join(hostDir, TOKEN_FILE_NAME);
|
|
28207
|
-
|
|
28284
|
+
await import_node_fs14.promises.writeFile(tokenFileHostPath, input.initialToken, {
|
|
28208
28285
|
encoding: "utf8",
|
|
28209
28286
|
mode: 384
|
|
28210
28287
|
}), await import_node_fs14.promises.writeFile(
|
|
@@ -28219,12 +28296,107 @@ var ApiKeyBootstrap = class _ApiKeyBootstrap {
|
|
|
28219
28296
|
path32.join(configHostDir, CODEX_CONFIG_NAME),
|
|
28220
28297
|
codexConfig(input.sandboxBrokerUrl, helperInSandbox),
|
|
28221
28298
|
{ encoding: "utf8", mode: 384 }
|
|
28222
|
-
)
|
|
28299
|
+
);
|
|
28300
|
+
let claudeScratchHostDir = null, claudeScratchSandboxDir = null, claudeScratchIdentity = null;
|
|
28301
|
+
if (input.claudeScratchHostRoot !== void 0) {
|
|
28302
|
+
if (input.provider !== "anthropic" || !input.sandboxDirEqualsHostDir) {
|
|
28303
|
+
let primary = new Error(
|
|
28304
|
+
"ApiKeyBootstrap.create: a short Claude scratch root is valid only for the A5 anthropic path"
|
|
28305
|
+
), cleanupErrors = [];
|
|
28306
|
+
for (let directory of [hostDir, configHostDir])
|
|
28307
|
+
try {
|
|
28308
|
+
await import_node_fs14.promises.rm(directory, { recursive: !0, force: !0 });
|
|
28309
|
+
} catch (cleanupError) {
|
|
28310
|
+
cleanupErrors.push(cleanupError);
|
|
28311
|
+
}
|
|
28312
|
+
throw cleanupErrors.length > 0 ? Object.assign(
|
|
28313
|
+
new Error(
|
|
28314
|
+
"ApiKeyBootstrap.create: invalid scratch configuration and cleanup did not complete"
|
|
28315
|
+
),
|
|
28316
|
+
{ causes: [primary, ...cleanupErrors] }
|
|
28317
|
+
) : primary;
|
|
28318
|
+
}
|
|
28319
|
+
let rawScratchDir = null;
|
|
28320
|
+
try {
|
|
28321
|
+
let canonicalScratchRoot = await import_node_fs14.promises.realpath(
|
|
28322
|
+
input.claudeScratchHostRoot
|
|
28323
|
+
);
|
|
28324
|
+
rawScratchDir = await import_node_fs14.promises.mkdtemp(path32.join(canonicalScratchRoot, "cv"));
|
|
28325
|
+
let initial = await import_node_fs14.promises.lstat(rawScratchDir, { bigint: !0 });
|
|
28326
|
+
if (!initial.isDirectory() || initial.isSymbolicLink())
|
|
28327
|
+
throw new Error(
|
|
28328
|
+
"ApiKeyBootstrap.create: generated Claude scratch root is not a real directory"
|
|
28329
|
+
);
|
|
28330
|
+
await input.beforeClaudeScratchOpen?.(rawScratchDir);
|
|
28331
|
+
let scratchHandle = await import_node_fs14.promises.open(
|
|
28332
|
+
rawScratchDir,
|
|
28333
|
+
import_node_fs14.constants.O_RDONLY | import_node_fs14.constants.O_NOFOLLOW | (typeof import_node_fs14.constants.O_DIRECTORY == "number" ? import_node_fs14.constants.O_DIRECTORY : 0)
|
|
28334
|
+
);
|
|
28335
|
+
try {
|
|
28336
|
+
let opened = await scratchHandle.stat({ bigint: !0 });
|
|
28337
|
+
if (!opened.isDirectory() || opened.dev !== initial.dev || opened.ino !== initial.ino || opened.birthtimeNs !== initial.birthtimeNs)
|
|
28338
|
+
throw new Error(
|
|
28339
|
+
"ApiKeyBootstrap.create: Claude scratch root changed while binding its directory handle"
|
|
28340
|
+
);
|
|
28341
|
+
await scratchHandle.chmod(448);
|
|
28342
|
+
let sealed = await scratchHandle.stat({ bigint: !0 }), live = await import_node_fs14.promises.lstat(rawScratchDir, { bigint: !0 }), canonical = rawScratchDir, currentUid = process.getuid?.(), mode = sealed.mode & 0o777n;
|
|
28343
|
+
if (!sealed.isDirectory() || !live.isDirectory() || live.isSymbolicLink() || live.dev !== sealed.dev || live.ino !== sealed.ino || live.birthtimeNs !== sealed.birthtimeNs || currentUid === void 0 || sealed.uid !== BigInt(currentUid) || mode !== 0o700n)
|
|
28344
|
+
throw new Error(
|
|
28345
|
+
"ApiKeyBootstrap.create: generated Claude scratch root failed its descriptor-bound private-directory identity check"
|
|
28346
|
+
);
|
|
28347
|
+
claudeScratchHostDir = canonical, claudeScratchSandboxDir = rawScratchDir, claudeScratchIdentity = {
|
|
28348
|
+
version: 1,
|
|
28349
|
+
canonicalPath: canonical,
|
|
28350
|
+
dev: sealed.dev.toString(),
|
|
28351
|
+
ino: sealed.ino.toString(),
|
|
28352
|
+
birthtimeNs: sealed.birthtimeNs.toString()
|
|
28353
|
+
};
|
|
28354
|
+
} finally {
|
|
28355
|
+
await scratchHandle.close();
|
|
28356
|
+
}
|
|
28357
|
+
if (Buffer.byteLength(rawScratchDir, "utf8") > 30)
|
|
28358
|
+
throw new Error(
|
|
28359
|
+
"ApiKeyBootstrap.create: generated Claude scratch path exceeds the 30-byte A5 safety bound"
|
|
28360
|
+
);
|
|
28361
|
+
if (realWorkdir !== void 0 && isInsideOrEqual(claudeScratchHostDir, realWorkdir))
|
|
28362
|
+
throw new Error(
|
|
28363
|
+
"ApiKeyBootstrap.create: Claude scratch root is inside the agent workdir (fail-closed)"
|
|
28364
|
+
);
|
|
28365
|
+
} catch (error) {
|
|
28366
|
+
let cleanupErrors = [];
|
|
28367
|
+
if (claudeScratchIdentity !== null)
|
|
28368
|
+
try {
|
|
28369
|
+
await anchoredRemoveTree(
|
|
28370
|
+
claudeScratchIdentity.canonicalPath,
|
|
28371
|
+
claudeScratchIdentity
|
|
28372
|
+
);
|
|
28373
|
+
} catch (cleanupError) {
|
|
28374
|
+
cleanupErrors.push(cleanupError);
|
|
28375
|
+
}
|
|
28376
|
+
for (let directory of [hostDir, configHostDir])
|
|
28377
|
+
try {
|
|
28378
|
+
await import_node_fs14.promises.rm(directory, { recursive: !0, force: !0 });
|
|
28379
|
+
} catch (cleanupError) {
|
|
28380
|
+
cleanupErrors.push(cleanupError);
|
|
28381
|
+
}
|
|
28382
|
+
throw cleanupErrors.length > 0 ? Object.assign(
|
|
28383
|
+
new Error(
|
|
28384
|
+
"ApiKeyBootstrap.create: initialization failed and cleanup did not complete"
|
|
28385
|
+
),
|
|
28386
|
+
{ causes: [error, ...cleanupErrors] }
|
|
28387
|
+
) : error;
|
|
28388
|
+
}
|
|
28389
|
+
}
|
|
28390
|
+
return new _ApiKeyBootstrap(
|
|
28223
28391
|
hostDir,
|
|
28224
28392
|
sandboxDir,
|
|
28225
28393
|
configHostDir,
|
|
28226
28394
|
sandboxConfigDir,
|
|
28227
|
-
tokenFileHostPath
|
|
28395
|
+
tokenFileHostPath,
|
|
28396
|
+
claudeScratchHostDir,
|
|
28397
|
+
claudeScratchSandboxDir,
|
|
28398
|
+
claudeScratchIdentity,
|
|
28399
|
+
input.beforeClaudeScratchCleanupCommit
|
|
28228
28400
|
);
|
|
28229
28401
|
}
|
|
28230
28402
|
/** The `SubstrateSpec.agentBootstrap` value for this bootstrap. */
|
|
@@ -28235,6 +28407,14 @@ var ApiKeyBootstrap = class _ApiKeyBootstrap {
|
|
|
28235
28407
|
get configSpec() {
|
|
28236
28408
|
return { hostDir: this.configHostDir, sandboxDir: this.configSandboxDir };
|
|
28237
28409
|
}
|
|
28410
|
+
/** The unique writable Claude scratch grant, absent on Docker/Codex paths. */
|
|
28411
|
+
get claudeScratchSpec() {
|
|
28412
|
+
return this.claudeScratchHostDir === null || this.claudeScratchSandboxDir === null || this.claudeScratchIdentity === null ? null : {
|
|
28413
|
+
hostDir: this.claudeScratchHostDir,
|
|
28414
|
+
sandboxDir: this.claudeScratchSandboxDir,
|
|
28415
|
+
authority: this.claudeScratchIdentity
|
|
28416
|
+
};
|
|
28417
|
+
}
|
|
28238
28418
|
/**
|
|
28239
28419
|
* REFRESH the broker token (rotation / on a broker 401). Atomically rewrites
|
|
28240
28420
|
* the token file (write a temp + rename) so the agent never reads a partial
|
|
@@ -28245,15 +28425,41 @@ var ApiKeyBootstrap = class _ApiKeyBootstrap {
|
|
|
28245
28425
|
let tmp = `${this.tokenFileHostPath}.tmp-${process.pid}-${Date.now()}`;
|
|
28246
28426
|
await import_node_fs14.promises.writeFile(tmp, token, { encoding: "utf8", mode: 384 }), await import_node_fs14.promises.rename(tmp, this.tokenFileHostPath);
|
|
28247
28427
|
}
|
|
28248
|
-
/**
|
|
28428
|
+
/**
|
|
28429
|
+
* Remove the bootstrap, config, and unique Claude scratch dirs. Scratch
|
|
28430
|
+
* cleanup is identity-bound: a replaced pathname is retained and reported,
|
|
28431
|
+
* never recursively removed as though it still belonged to this seat.
|
|
28432
|
+
*/
|
|
28249
28433
|
async destroy() {
|
|
28250
|
-
|
|
28251
|
-
|
|
28434
|
+
let cleanupErrors = [];
|
|
28435
|
+
if (this.claudeScratchHostDir !== null && this.claudeScratchIdentity !== null)
|
|
28436
|
+
try {
|
|
28437
|
+
await anchoredRemoveTree(
|
|
28438
|
+
this.claudeScratchIdentity.canonicalPath,
|
|
28439
|
+
this.claudeScratchIdentity,
|
|
28440
|
+
{
|
|
28441
|
+
...this.beforeClaudeScratchCleanupCommit ? {
|
|
28442
|
+
beforeCommit: () => this.beforeClaudeScratchCleanupCommit(
|
|
28443
|
+
this.claudeScratchHostDir
|
|
28444
|
+
)
|
|
28445
|
+
} : {}
|
|
28446
|
+
}
|
|
28447
|
+
);
|
|
28448
|
+
} catch (error) {
|
|
28449
|
+
cleanupErrors.push(error);
|
|
28252
28450
|
}
|
|
28253
|
-
|
|
28254
|
-
|
|
28451
|
+
for (let directory of [this.hostDir, this.configHostDir])
|
|
28452
|
+
try {
|
|
28453
|
+
await import_node_fs14.promises.rm(directory, { recursive: !0, force: !0 });
|
|
28454
|
+
} catch (error) {
|
|
28455
|
+
cleanupErrors.push(error);
|
|
28255
28456
|
}
|
|
28256
|
-
);
|
|
28457
|
+
if (cleanupErrors.length === 1) throw cleanupErrors[0];
|
|
28458
|
+
if (cleanupErrors.length > 1)
|
|
28459
|
+
throw Object.assign(
|
|
28460
|
+
new Error("ApiKeyBootstrap.destroy: cleanup did not complete"),
|
|
28461
|
+
{ causes: cleanupErrors }
|
|
28462
|
+
);
|
|
28257
28463
|
}
|
|
28258
28464
|
};
|
|
28259
28465
|
|
|
@@ -42775,10 +42981,7 @@ var LocalExecutorImpl = class {
|
|
|
42775
42981
|
}).catch(() => {
|
|
42776
42982
|
}), {
|
|
42777
42983
|
args: { ...addClaudeSubstrateAuthArgs(args, result.agentConfigDir), substrate: result.substrateHandle },
|
|
42778
|
-
onExit:
|
|
42779
|
-
await result.teardown().catch(() => {
|
|
42780
|
-
});
|
|
42781
|
-
},
|
|
42984
|
+
onExit: () => result.teardown(),
|
|
42782
42985
|
// Stage-2 r3 Codex HIGH — the ONLY return that proves a real confining
|
|
42783
42986
|
// boundary (`result.mode === 'substrate'`, not reduced_trust / no-engager /
|
|
42784
42987
|
// pre-TaskAuthorized). The danger-sandbox authority keys on THIS boolean,
|
|
@@ -42870,7 +43073,11 @@ var LocalExecutorImpl = class {
|
|
|
42870
43073
|
}
|
|
42871
43074
|
}
|
|
42872
43075
|
async spawnWithLifecycle(args, spawnFn, onSubstrateExit) {
|
|
42873
|
-
let role = args.role, lifecycleAudit = args.lifecycleAudit ?? "active_task", lifecycleTaskId = args.taskId ?? this.taskId, lifecycleCtx = lifecycleTaskId ? { taskId: lifecycleTaskId, ...this.baseCtx } : null,
|
|
43076
|
+
let role = args.role, lifecycleAudit = args.lifecycleAudit ?? "active_task", lifecycleTaskId = args.taskId ?? this.taskId, lifecycleCtx = lifecycleTaskId ? { taskId: lifecycleTaskId, ...this.baseCtx } : null, substrateCleanupError, substrateCleanupPromise, cleanupSubstrate = async () => {
|
|
43077
|
+
onSubstrateExit && (substrateCleanupPromise || (substrateCleanupPromise = onSubstrateExit().catch((error) => {
|
|
43078
|
+
throw substrateCleanupError = error, error;
|
|
43079
|
+
})), await substrateCleanupPromise);
|
|
43080
|
+
}, full = {
|
|
42874
43081
|
...args,
|
|
42875
43082
|
agentKind: args.agentKind ?? this.adapter,
|
|
42876
43083
|
onProcessSpawned: async (info) => {
|
|
@@ -42884,35 +43091,51 @@ var LocalExecutorImpl = class {
|
|
|
42884
43091
|
});
|
|
42885
43092
|
},
|
|
42886
43093
|
onProcessExited: async (info) => {
|
|
42887
|
-
|
|
42888
|
-
|
|
42889
|
-
|
|
42890
|
-
|
|
42891
|
-
|
|
42892
|
-
|
|
42893
|
-
|
|
42894
|
-
|
|
43094
|
+
try {
|
|
43095
|
+
if (await args.onProcessExited?.(info), lifecycleAudit !== "none") {
|
|
43096
|
+
let ctx = lifecycleCtx;
|
|
43097
|
+
ctx !== null && await this.emitter.emitProcessExited(ctx, {
|
|
43098
|
+
pid: info.pid,
|
|
43099
|
+
exitCode: info.exitCode,
|
|
43100
|
+
failureClass: info.failureClass,
|
|
43101
|
+
occurredAt: info.exitedAt
|
|
43102
|
+
});
|
|
43103
|
+
}
|
|
43104
|
+
} catch {
|
|
42895
43105
|
}
|
|
42896
|
-
|
|
43106
|
+
await cleanupSubstrate().catch(() => {
|
|
42897
43107
|
});
|
|
42898
43108
|
}
|
|
42899
43109
|
};
|
|
42900
43110
|
try {
|
|
42901
|
-
|
|
43111
|
+
let handle = await spawnFn(full), done = handle.done.then((info) => {
|
|
43112
|
+
if (substrateCleanupError !== void 0)
|
|
43113
|
+
throw Object.assign(
|
|
43114
|
+
new Error("implementor substrate cleanup failed after process exit"),
|
|
43115
|
+
{ cause: substrateCleanupError }
|
|
43116
|
+
);
|
|
43117
|
+
return info;
|
|
43118
|
+
});
|
|
43119
|
+
return { ...handle, done };
|
|
42902
43120
|
} catch (err) {
|
|
42903
|
-
|
|
42904
|
-
})
|
|
43121
|
+
await cleanupSubstrate().catch(() => {
|
|
43122
|
+
});
|
|
43123
|
+
let primary = err;
|
|
43124
|
+
if (err instanceof AuthorityError) {
|
|
42905
43125
|
let safeArgv = redactAgyPrintArgv(args.argv), safeDetail = redactAgyPrintValuesFromText(err.refusal.detail, args.argv), safeError = new AuthorityError({
|
|
42906
43126
|
...err.refusal,
|
|
42907
43127
|
detail: safeDetail
|
|
42908
43128
|
});
|
|
42909
|
-
|
|
43129
|
+
await this.bridge.bridgeAuthorityRefusal(safeError, {
|
|
42910
43130
|
refusedMessageId: "spawn:" + role + ":" + Date.now(),
|
|
42911
43131
|
shellContent: `Refused spawn (${role}): ${safeDetail}`,
|
|
42912
43132
|
shellMetadata: { role, argv: safeArgv }
|
|
42913
|
-
}), safeError;
|
|
43133
|
+
}), primary = safeError;
|
|
42914
43134
|
}
|
|
42915
|
-
throw
|
|
43135
|
+
throw substrateCleanupError !== void 0 ? Object.assign(
|
|
43136
|
+
new Error("implementor spawn failed and substrate cleanup also failed"),
|
|
43137
|
+
{ causes: [primary, substrateCleanupError] }
|
|
43138
|
+
) : primary;
|
|
42916
43139
|
}
|
|
42917
43140
|
}
|
|
42918
43141
|
// --- Hook bridge surface ---------------------------------------------------
|
|
@@ -49034,10 +49257,11 @@ var ChildProcessCommandRunner = class {
|
|
|
49034
49257
|
signal: opts.signal,
|
|
49035
49258
|
...opts.env !== void 0 ? { env: opts.env } : {},
|
|
49036
49259
|
...opts.cwd !== void 0 ? { cwd: opts.cwd } : {}
|
|
49037
|
-
},
|
|
49038
|
-
workingDirAuthority: opts.cwdAuthority
|
|
49260
|
+
}, needsOwnedProcessHost = opts.cwdAuthority !== void 0 || (opts.launchPathAuthorities?.length ?? 0) > 0, proc = needsOwnedProcessHost ? spawnPosixOwnedProcess(argv[0], argv.slice(1), spawnOptions, {
|
|
49261
|
+
workingDirAuthority: opts.cwdAuthority,
|
|
49262
|
+
launchPathAuthorities: opts.launchPathAuthorities
|
|
49039
49263
|
}) : (0, import_node_child_process7.spawn)(argv[0], argv.slice(1), spawnOptions);
|
|
49040
|
-
return
|
|
49264
|
+
return needsOwnedProcessHost && Object.defineProperty(proc, "hostProcessTreeOwnership", {
|
|
49041
49265
|
value: "posix-host",
|
|
49042
49266
|
configurable: !1,
|
|
49043
49267
|
enumerable: !1,
|
|
@@ -49617,13 +49841,14 @@ async function resolveOnParentPath(cmd) {
|
|
|
49617
49841
|
return null;
|
|
49618
49842
|
}
|
|
49619
49843
|
var SandboxExecHandle = class {
|
|
49620
|
-
constructor(id, runner, profilePath, sanitizedEnv, workdir, workdirAuthority, auditDir = null) {
|
|
49844
|
+
constructor(id, runner, profilePath, sanitizedEnv, workdir, workdirAuthority, scratchAuthority, auditDir = null) {
|
|
49621
49845
|
this.id = id;
|
|
49622
49846
|
this.runner = runner;
|
|
49623
49847
|
this.profilePath = profilePath;
|
|
49624
49848
|
this.sanitizedEnv = sanitizedEnv;
|
|
49625
49849
|
this.workdir = workdir;
|
|
49626
49850
|
this.workdirAuthority = workdirAuthority;
|
|
49851
|
+
this.scratchAuthority = scratchAuthority;
|
|
49627
49852
|
this.auditDir = auditDir;
|
|
49628
49853
|
this.egressFidelity = "coarse";
|
|
49629
49854
|
this.tornDown = !1;
|
|
@@ -49659,13 +49884,18 @@ var SandboxExecHandle = class {
|
|
|
49659
49884
|
; exec-time agent-binary read allowance (argv0 resolution, 2026-07-03)
|
|
49660
49885
|
${allowLines}
|
|
49661
49886
|
`
|
|
49887
|
+
), this.scratchAuthority && await assertWorkspaceRootAuthority(
|
|
49888
|
+
this.scratchAuthority.canonicalPath,
|
|
49889
|
+
this.scratchAuthority,
|
|
49890
|
+
"sandbox-exec Claude scratch handoff"
|
|
49662
49891
|
);
|
|
49663
49892
|
let sbArgv = ["sandbox-exec", "-f", this.profilePath, resolvedArgv0, ...argv.slice(1)], proc = this.runner.spawnLong(sbArgv, {
|
|
49664
49893
|
stdinTty: opts.stdinTty,
|
|
49665
49894
|
signal: opts.signal,
|
|
49666
49895
|
env: this.sanitizedEnv,
|
|
49667
49896
|
cwd: this.workdir,
|
|
49668
|
-
...this.workdirAuthority ? { cwdAuthority: this.workdirAuthority } : {}
|
|
49897
|
+
...this.workdirAuthority ? { cwdAuthority: this.workdirAuthority } : {},
|
|
49898
|
+
...this.scratchAuthority ? { launchPathAuthorities: [this.scratchAuthority] } : {}
|
|
49669
49899
|
});
|
|
49670
49900
|
return this.proc = proc, proc;
|
|
49671
49901
|
}
|
|
@@ -49723,6 +49953,22 @@ ${allowLines}
|
|
|
49723
49953
|
}
|
|
49724
49954
|
extraWriteDirs.push(configDir);
|
|
49725
49955
|
}
|
|
49956
|
+
if (spec.agentScratch) {
|
|
49957
|
+
try {
|
|
49958
|
+
await assertWorkspaceRootAuthority(
|
|
49959
|
+
spec.agentScratch.hostDir,
|
|
49960
|
+
spec.agentScratch.authority,
|
|
49961
|
+
"sandbox-exec Claude scratch launch"
|
|
49962
|
+
);
|
|
49963
|
+
} catch (error) {
|
|
49964
|
+
throw new SubstrateLaunchError(
|
|
49965
|
+
"sandbox_exec",
|
|
49966
|
+
"Claude scratch grant target identity could not be verified (fail-closed)",
|
|
49967
|
+
error
|
|
49968
|
+
);
|
|
49969
|
+
}
|
|
49970
|
+
extraWriteDirs.push(spec.agentScratch.authority.canonicalPath);
|
|
49971
|
+
}
|
|
49726
49972
|
let resolvedAuditDir = null;
|
|
49727
49973
|
if (spec.auditDir) {
|
|
49728
49974
|
resolvedAuditDir = spec.auditDir;
|
|
@@ -49763,6 +50009,17 @@ ${allowLines}
|
|
|
49763
50009
|
throw await import_node_fs23.promises.rm(profilePath, { force: !0 }).catch(() => {
|
|
49764
50010
|
}), err;
|
|
49765
50011
|
}
|
|
50012
|
+
if (spec.agentScratch)
|
|
50013
|
+
try {
|
|
50014
|
+
await assertWorkspaceRootAuthority(
|
|
50015
|
+
spec.agentScratch.authority.canonicalPath,
|
|
50016
|
+
spec.agentScratch.authority,
|
|
50017
|
+
"sandbox-exec Claude scratch profile handoff"
|
|
50018
|
+
);
|
|
50019
|
+
} catch (err) {
|
|
50020
|
+
throw await import_node_fs23.promises.rm(profilePath, { force: !0 }).catch(() => {
|
|
50021
|
+
}), err;
|
|
50022
|
+
}
|
|
49766
50023
|
return new SandboxExecHandle(
|
|
49767
50024
|
id,
|
|
49768
50025
|
this.runner,
|
|
@@ -49770,6 +50027,7 @@ ${allowLines}
|
|
|
49770
50027
|
finalEnv,
|
|
49771
50028
|
canonicalWorkdir,
|
|
49772
50029
|
spec.workdirAuthority,
|
|
50030
|
+
spec.agentScratch?.authority,
|
|
49773
50031
|
resolvedAuditDir
|
|
49774
50032
|
);
|
|
49775
50033
|
}
|
|
@@ -50396,13 +50654,13 @@ function formatReviewerError(detail) {
|
|
|
50396
50654
|
case "timeout":
|
|
50397
50655
|
return `${detail.agent} reviewer timed out after ${detail.elapsed_ms}ms`;
|
|
50398
50656
|
case "spawn_failed":
|
|
50399
|
-
return `${detail.agent} reviewer spawn failed
|
|
50657
|
+
return `${detail.agent} reviewer spawn failed`;
|
|
50400
50658
|
case "parse_failure":
|
|
50401
50659
|
return `${detail.agent} reviewer output was unparseable`;
|
|
50402
50660
|
case "cancelled":
|
|
50403
50661
|
return "reviewer cancelled before completion";
|
|
50404
50662
|
case "internal_join_failure":
|
|
50405
|
-
return
|
|
50663
|
+
return "reviewer task internal join failure";
|
|
50406
50664
|
}
|
|
50407
50665
|
}
|
|
50408
50666
|
|
|
@@ -50944,22 +51202,25 @@ var CONTINUATION_EXPIRES_TTL_MS = 1440 * 60 * 1e3, ACTIVE_AGENT_KINDS = ["CLAUDE
|
|
|
50944
51202
|
function isActiveAgentKind2(agent) {
|
|
50945
51203
|
return agent === "CLAUDE" || agent === "CODEX" || agent === "ANTIGRAVITY";
|
|
50946
51204
|
}
|
|
50947
|
-
var IMPLEMENTOR_TICK_MS = 1e4, TICK_SCAN_MAX_TRACKED = 5e3, TICK_SCAN_TIMEOUT_MS = 1e3, BACKGROUND_RECOVERY_ABORTED = /* @__PURE__ */ Symbol("background-recovery-aborted")
|
|
51205
|
+
var IMPLEMENTOR_TICK_MS = 1e4, TICK_SCAN_MAX_TRACKED = 5e3, TICK_SCAN_TIMEOUT_MS = 1e3, BACKGROUND_RECOVERY_ABORTED = /* @__PURE__ */ Symbol("background-recovery-aborted");
|
|
50948
51206
|
function describeReviewerErrorDetail(detail) {
|
|
50949
51207
|
switch (detail.kind) {
|
|
50950
51208
|
case "timeout":
|
|
50951
51209
|
return { agent: detail.agent, elapsedMs: detail.elapsed_ms };
|
|
50952
51210
|
case "spawn_failed":
|
|
50953
|
-
return {
|
|
51211
|
+
return {
|
|
51212
|
+
agent: detail.agent,
|
|
51213
|
+
reasonBytes: Buffer.byteLength(detail.reason ?? "", "utf8")
|
|
51214
|
+
};
|
|
50954
51215
|
case "parse_failure":
|
|
50955
51216
|
return {
|
|
50956
51217
|
agent: detail.agent,
|
|
50957
|
-
|
|
51218
|
+
rawOutputShape: outputShapeOnly(detail.raw_output)
|
|
50958
51219
|
};
|
|
50959
51220
|
case "cancelled":
|
|
50960
51221
|
return {};
|
|
50961
51222
|
case "internal_join_failure":
|
|
50962
|
-
return {
|
|
51223
|
+
return { reasonBytes: Buffer.byteLength(detail.reason ?? "", "utf8") };
|
|
50963
51224
|
}
|
|
50964
51225
|
}
|
|
50965
51226
|
var REVIEWER_AGENT_DISPLAY_NAME = {
|
|
@@ -53273,8 +53534,8 @@ var QuorumLoop = class _QuorumLoop {
|
|
|
53273
53534
|
taskId: args.taskId,
|
|
53274
53535
|
trackIndex: args.validateDiffScope.trackIndex,
|
|
53275
53536
|
exitCode: exit.exitCode,
|
|
53276
|
-
|
|
53277
|
-
|
|
53537
|
+
stderrShape: outputShapeOnly(handle.stderr()),
|
|
53538
|
+
stdoutShape: outputShapeOnly(handle.stdout())
|
|
53278
53539
|
}
|
|
53279
53540
|
), await this.reportTeamTrackFailure(
|
|
53280
53541
|
args.taskId,
|
|
@@ -53296,8 +53557,8 @@ var QuorumLoop = class _QuorumLoop {
|
|
|
53296
53557
|
// exits 0 is still attributable from the log.
|
|
53297
53558
|
exitCode: exit.exitCode,
|
|
53298
53559
|
runtimeMs: exit.runtimeMs,
|
|
53299
|
-
|
|
53300
|
-
|
|
53560
|
+
stdoutShape: outputShapeOnly(handle.stdout()),
|
|
53561
|
+
stderrShape: outputShapeOnly(handle.stderr())
|
|
53301
53562
|
});
|
|
53302
53563
|
try {
|
|
53303
53564
|
let bundle = createSnapshotTrackBundle({
|
|
@@ -53374,8 +53635,8 @@ var QuorumLoop = class _QuorumLoop {
|
|
|
53374
53635
|
exitCode: exit.exitCode,
|
|
53375
53636
|
runtimeMs: exit.runtimeMs,
|
|
53376
53637
|
...files.length === 0 ? {
|
|
53377
|
-
|
|
53378
|
-
|
|
53638
|
+
stdoutShape: outputShapeOnly(handle.stdout()),
|
|
53639
|
+
stderrShape: outputShapeOnly(handle.stderr())
|
|
53379
53640
|
} : {}
|
|
53380
53641
|
}), this.surfaceHalt(reason), await this.discardShadow(args.taskId);
|
|
53381
53642
|
}
|
|
@@ -53390,15 +53651,20 @@ var QuorumLoop = class _QuorumLoop {
|
|
|
53390
53651
|
}
|
|
53391
53652
|
logger.warn("[QuorumLoop] implementor round failed", {
|
|
53392
53653
|
gateId,
|
|
53393
|
-
err
|
|
53654
|
+
...errorShapeOnly(err)
|
|
53394
53655
|
});
|
|
53395
53656
|
let reason = classifyImplementorRoundFailure(err);
|
|
53396
|
-
this.surfaceHalt(`The task could not proceed \u2014 ${reason}.`)
|
|
53397
|
-
{ phase: "round_failed", round: args.roundNumber, reason, taskId: args.taskId },
|
|
53398
|
-
originEpoch
|
|
53399
|
-
);
|
|
53657
|
+
this.surfaceHalt(`The task could not proceed \u2014 ${reason}.`);
|
|
53400
53658
|
let reviseFeedbackId = args.reviseFeedbackId, preserveResetForRetry = submissionStarted && args.reviewScopeReset === !0 && reviseFeedbackId !== void 0 && this.reviewScopeResetTasks.has(args.taskId);
|
|
53401
|
-
|
|
53659
|
+
this.emitProgress(
|
|
53660
|
+
{
|
|
53661
|
+
phase: "round_failed",
|
|
53662
|
+
round: args.roundNumber,
|
|
53663
|
+
reason,
|
|
53664
|
+
...preserveResetForRetry ? {} : { taskId: args.taskId }
|
|
53665
|
+
},
|
|
53666
|
+
originEpoch
|
|
53667
|
+
), preserveResetForRetry && this.seenReviseFeedbackIds.delete(reviseFeedbackId), await this.discardShadow(args.taskId, void 0, {
|
|
53402
53668
|
preserveReviseContext: preserveResetForRetry
|
|
53403
53669
|
});
|
|
53404
53670
|
} finally {
|
|
@@ -54464,7 +54730,7 @@ var QuorumLoop = class _QuorumLoop {
|
|
|
54464
54730
|
if (promptText === null) {
|
|
54465
54731
|
logger.warn("[QuorumLoop] getReviewerPrompt exhausted \u2014 ESCALATE", {
|
|
54466
54732
|
key,
|
|
54467
|
-
|
|
54733
|
+
...errorShapeOnly(lastErr),
|
|
54468
54734
|
audit: "synthesized ESCALATE (#C1F-8): prompt_fetch_failed"
|
|
54469
54735
|
}), await this.submitVerdict(args, this.synthesizeEscalate(args, DESKTOP_DISPATCH_ESCALATE_REASONING), sessionKey);
|
|
54470
54736
|
return;
|
|
@@ -54499,13 +54765,13 @@ var QuorumLoop = class _QuorumLoop {
|
|
|
54499
54765
|
failureReason,
|
|
54500
54766
|
audit: "synthesized ESCALATE (#C1F-8): reviewer_substrate_engage_failed",
|
|
54501
54767
|
...describeReviewerErrorDetail(engageErr.detail),
|
|
54502
|
-
|
|
54768
|
+
...errorShapeOnly(engageErr)
|
|
54503
54769
|
}), await this.submitVerdict(args, this.synthesizeEscalate(args, cleanReasoning), sessionKey);
|
|
54504
54770
|
return;
|
|
54505
54771
|
}
|
|
54506
54772
|
throw engageErr;
|
|
54507
54773
|
}
|
|
54508
|
-
let verdict;
|
|
54774
|
+
let verdict, evaluationError;
|
|
54509
54775
|
try {
|
|
54510
54776
|
verdict = await this.evaluateSeatWithTimeout(spec, args.gateId, seatSubstrate.handle);
|
|
54511
54777
|
} catch (err) {
|
|
@@ -54533,7 +54799,7 @@ var QuorumLoop = class _QuorumLoop {
|
|
|
54533
54799
|
// Audit prefix kept in LOGS only (#C1F-8) — never on the wire.
|
|
54534
54800
|
audit: `synthesized ESCALATE (#C1F-8): reviewer_error:${err.detail.kind}`,
|
|
54535
54801
|
...describeReviewerErrorDetail(err.detail),
|
|
54536
|
-
|
|
54802
|
+
...errorShapeOnly(err),
|
|
54537
54803
|
// 2026-08-22 (dogfood) — TIMEOUT DIAGNOSTICS, local log only.
|
|
54538
54804
|
//
|
|
54539
54805
|
// A live 5-minute reviewer timeout on a ONE-FILE deletion diff was
|
|
@@ -54550,16 +54816,51 @@ var QuorumLoop = class _QuorumLoop {
|
|
|
54550
54816
|
...this.describeReviewShapeForDiagnostics(args.gateId)
|
|
54551
54817
|
}), verdict = this.synthesizeEscalate(args, cleanReasoning);
|
|
54552
54818
|
} else
|
|
54553
|
-
|
|
54554
|
-
}
|
|
54555
|
-
|
|
54819
|
+
evaluationError = err;
|
|
54820
|
+
}
|
|
54821
|
+
let cleanupError;
|
|
54822
|
+
try {
|
|
54823
|
+
await seatSubstrate.teardown();
|
|
54824
|
+
} catch (error) {
|
|
54825
|
+
cleanupError = error, logger.warn("[QuorumLoop] reviewer substrate cleanup failed \u2014 forcing ESCALATE", {
|
|
54826
|
+
key,
|
|
54827
|
+
seatId: args.seatId,
|
|
54828
|
+
role: args.role,
|
|
54829
|
+
agentKind: args.agentKind,
|
|
54830
|
+
...errorShapeOnly(error),
|
|
54831
|
+
audit: "synthesized ESCALATE: reviewer_substrate_cleanup_failed"
|
|
54556
54832
|
});
|
|
54557
54833
|
}
|
|
54834
|
+
if (evaluationError !== void 0) {
|
|
54835
|
+
let terminalError = cleanupError !== void 0 ? Object.assign(
|
|
54836
|
+
new Error("reviewer evaluation failed and substrate cleanup also failed"),
|
|
54837
|
+
{ causes: [evaluationError, cleanupError] }
|
|
54838
|
+
) : Object.assign(
|
|
54839
|
+
new Error("reviewer evaluation failed unexpectedly"),
|
|
54840
|
+
{ cause: evaluationError }
|
|
54841
|
+
);
|
|
54842
|
+
logger.warn("[QuorumLoop] unexpected reviewer evaluation failure \u2014 forcing ESCALATE", {
|
|
54843
|
+
key,
|
|
54844
|
+
seatId: args.seatId,
|
|
54845
|
+
role: args.role,
|
|
54846
|
+
agentKind: args.agentKind,
|
|
54847
|
+
...errorShapeOnly(terminalError),
|
|
54848
|
+
audit: "synthesized ESCALATE: reviewer_evaluation_failed"
|
|
54849
|
+
}), verdict = this.synthesizeEscalate(
|
|
54850
|
+
args,
|
|
54851
|
+
DESKTOP_DISPATCH_ESCALATE_REASONING
|
|
54852
|
+
);
|
|
54853
|
+
}
|
|
54854
|
+
if (cleanupError !== void 0 && (verdict = this.synthesizeEscalate(
|
|
54855
|
+
args,
|
|
54856
|
+
DESKTOP_DISPATCH_ESCALATE_REASONING
|
|
54857
|
+
)), verdict === void 0)
|
|
54858
|
+
throw new Error("reviewer completed without a verdict");
|
|
54558
54859
|
reviewScope !== null && (verdict = enforceReviewRoundScope(verdict, reviewScope)), await this.submitVerdict(args, verdict, sessionKey);
|
|
54559
54860
|
} catch (err) {
|
|
54560
54861
|
logger.warn("[QuorumLoop] spawnOneSeat failed \u2014 dropped", {
|
|
54561
54862
|
key,
|
|
54562
|
-
err
|
|
54863
|
+
...errorShapeOnly(err)
|
|
54563
54864
|
});
|
|
54564
54865
|
} finally {
|
|
54565
54866
|
this.runningSeats.delete(key);
|
|
@@ -54652,19 +54953,18 @@ var QuorumLoop = class _QuorumLoop {
|
|
|
54652
54953
|
if (e.name === REVIEWER_CREDENTIAL_MISSING)
|
|
54653
54954
|
try {
|
|
54654
54955
|
this.surfaceHalt(
|
|
54655
|
-
`Reviewer (${seatLabel(args.agentKind, args.seatId)}) cannot start sandboxed:
|
|
54956
|
+
`Reviewer (${seatLabel(args.agentKind, args.seatId)}) cannot start sandboxed: the required provider credential is unavailable. Run \`codevibe vendor-key setup\`` + (args.agentKind === "codex" ? " (or `codevibe vendor-key import-codex` for a ChatGPT subscription)" : "") + ", or set CODEVIBE_SANDBOX_REVIEWERS=0 to opt out of reviewer sandboxing."
|
|
54656
54957
|
);
|
|
54657
54958
|
} catch {
|
|
54658
54959
|
}
|
|
54659
54960
|
throw new ReviewerErrorClass({
|
|
54660
54961
|
kind: "spawn_failed",
|
|
54661
54962
|
agent: args.agentKind,
|
|
54662
|
-
reason:
|
|
54963
|
+
reason: "CP-7: reviewer substrate engage failed for a Trusted agent \u2014 refusing the unsandboxed (ambient-cred) fallback (fail-closed)",
|
|
54663
54964
|
failureReason: "spawn_failed"
|
|
54664
54965
|
});
|
|
54665
54966
|
}
|
|
54666
|
-
return result.mode === "reduced_trust" ? (this.surfaceReviewerReducedTrust(args, result.reducedTrustReason), await result.teardown()
|
|
54667
|
-
}), NO_TEARDOWN) : (result.reducedTrust && this.surfaceReviewerReducedTrust(
|
|
54967
|
+
return result.mode === "reduced_trust" ? (this.surfaceReviewerReducedTrust(args, result.reducedTrustReason), await result.teardown(), NO_TEARDOWN) : (result.reducedTrust && this.surfaceReviewerReducedTrust(
|
|
54668
54968
|
args,
|
|
54669
54969
|
result.reducedTrustReason ?? "coarse egress (A5 sandbox-exec) \u2014 reviewer is sandboxed but loopback-only."
|
|
54670
54970
|
), {
|
|
@@ -54706,7 +55006,7 @@ var QuorumLoop = class _QuorumLoop {
|
|
|
54706
55006
|
reason
|
|
54707
55007
|
), logger.warn("[QuorumLoop] reduced-trust badge surfaceHalt threw (badge is best-effort) \u2014 continuing", {
|
|
54708
55008
|
seatId: args.seatId,
|
|
54709
|
-
|
|
55009
|
+
...errorShapeOnly(e)
|
|
54710
55010
|
});
|
|
54711
55011
|
}
|
|
54712
55012
|
}
|
|
@@ -54761,13 +55061,20 @@ var QuorumLoop = class _QuorumLoop {
|
|
|
54761
55061
|
});
|
|
54762
55062
|
if (result.mode === "substrate")
|
|
54763
55063
|
return { mode: "substrate", handle: result.substrateHandle, teardown: () => result.teardown() };
|
|
54764
|
-
|
|
54765
|
-
|
|
55064
|
+
try {
|
|
55065
|
+
await result.teardown();
|
|
55066
|
+
} catch (cleanupError) {
|
|
55067
|
+
return logger.warn("[QuorumLoop] Wave B reduced-trust cleanup failed \u2014 refusing fallback", {
|
|
55068
|
+
taskId,
|
|
55069
|
+
agent,
|
|
55070
|
+
...errorShapeOnly(cleanupError)
|
|
55071
|
+
}), { mode: "none" };
|
|
55072
|
+
}
|
|
54766
55073
|
} catch (e) {
|
|
54767
55074
|
logger.warn("[QuorumLoop] Wave B substrate engage failed \u2014 falling through to trusted-container/none", {
|
|
54768
55075
|
taskId,
|
|
54769
55076
|
agent,
|
|
54770
|
-
|
|
55077
|
+
...errorShapeOnly(e)
|
|
54771
55078
|
});
|
|
54772
55079
|
}
|
|
54773
55080
|
return isTrustedContainerBoundary() ? { mode: "trusted_container", teardown: async () => {
|
|
@@ -54798,9 +55105,11 @@ var QuorumLoop = class _QuorumLoop {
|
|
|
54798
55105
|
...substrate !== void 0 ? { substrate } : {}
|
|
54799
55106
|
});
|
|
54800
55107
|
if (!outcome.exit_success)
|
|
54801
|
-
throw
|
|
54802
|
-
|
|
54803
|
-
|
|
55108
|
+
throw logger.warn("[QuorumLoop] class-2 resolver model call exited non-zero", {
|
|
55109
|
+
ownerTaskId: args.ownerTaskId,
|
|
55110
|
+
stdoutShape: outputShapeOnly(outcome.stdout),
|
|
55111
|
+
stderrShape: outputShapeOnly(outcome.stderr)
|
|
55112
|
+
}), new Error("class-2 resolver model call exited non-zero");
|
|
54804
55113
|
return outcome.stdout;
|
|
54805
55114
|
};
|
|
54806
55115
|
return {
|
|
@@ -54844,7 +55153,7 @@ var QuorumLoop = class _QuorumLoop {
|
|
|
54844
55153
|
return { establishable: !0, via: "ladder_tier" };
|
|
54845
55154
|
} catch (err) {
|
|
54846
55155
|
logger.warn("[QuorumLoop] A1d resolver probe: ladder select failed \u2014 treating as no tier", {
|
|
54847
|
-
err
|
|
55156
|
+
...errorShapeOnly(err)
|
|
54848
55157
|
});
|
|
54849
55158
|
}
|
|
54850
55159
|
return (this.deps.resolverProbeDeps?.trustedContainer ?? isTrustedContainerBoundary)() ? { establishable: !0, via: "trusted_container" } : { establishable: !1 };
|
|
@@ -54975,8 +55284,8 @@ var QuorumLoop = class _QuorumLoop {
|
|
|
54975
55284
|
taskId: tid,
|
|
54976
55285
|
exitCode: exit.exitCode,
|
|
54977
55286
|
runtimeMs: exit.runtimeMs,
|
|
54978
|
-
|
|
54979
|
-
|
|
55287
|
+
stdoutShape: outputShapeOnly(handle.stdout()),
|
|
55288
|
+
stderrShape: outputShapeOnly(handle.stderr())
|
|
54980
55289
|
}), exit.failureClass !== null)
|
|
54981
55290
|
throw new Error(`agentic resolver implementor failed: ${exit.failureClass}`);
|
|
54982
55291
|
}
|
|
@@ -55039,6 +55348,7 @@ var QuorumLoop = class _QuorumLoop {
|
|
|
55039
55348
|
});
|
|
55040
55349
|
continue;
|
|
55041
55350
|
}
|
|
55351
|
+
let candidateError;
|
|
55042
55352
|
try {
|
|
55043
55353
|
let substrate = confinement.mode === "substrate" ? confinement.handle : void 0, spec = {
|
|
55044
55354
|
seat_id: 0,
|
|
@@ -55061,14 +55371,27 @@ var QuorumLoop = class _QuorumLoop {
|
|
|
55061
55371
|
...pass ? {} : { reason: `final-tip Tier-2 verdict: ${verdict.verdict}` }
|
|
55062
55372
|
};
|
|
55063
55373
|
} catch (e) {
|
|
55064
|
-
lastFailure = `final-tip Tier-2 reviewer
|
|
55374
|
+
candidateError = e, lastFailure = `final-tip Tier-2 reviewer ${agent} failed to produce a verdict`, logger.warn("[QuorumLoop] final-tip Tier-2 candidate failed \u2014 trying next", {
|
|
55065
55375
|
ownerTaskId: args.ownerTaskId,
|
|
55066
55376
|
agent,
|
|
55067
|
-
|
|
55377
|
+
...errorShapeOnly(e)
|
|
55068
55378
|
});
|
|
55069
55379
|
} finally {
|
|
55070
|
-
|
|
55071
|
-
|
|
55380
|
+
try {
|
|
55381
|
+
await confinement.teardown();
|
|
55382
|
+
} catch (cleanupError) {
|
|
55383
|
+
throw logger.warn("[QuorumLoop] final-tip Tier-2 substrate cleanup failed \u2014 failing closed", {
|
|
55384
|
+
ownerTaskId: args.ownerTaskId,
|
|
55385
|
+
agent,
|
|
55386
|
+
...errorShapeOnly(cleanupError)
|
|
55387
|
+
}), candidateError !== void 0 ? Object.assign(
|
|
55388
|
+
new Error("final-tip Tier-2 evaluation failed and substrate cleanup also failed"),
|
|
55389
|
+
{ causes: [candidateError, cleanupError] }
|
|
55390
|
+
) : Object.assign(
|
|
55391
|
+
new Error("final-tip Tier-2 substrate cleanup failed"),
|
|
55392
|
+
{ cause: cleanupError }
|
|
55393
|
+
);
|
|
55394
|
+
}
|
|
55072
55395
|
}
|
|
55073
55396
|
}
|
|
55074
55397
|
return {
|
|
@@ -65187,7 +65510,7 @@ function buildSanitizedBaseEnv(input) {
|
|
|
65187
65510
|
let v = safeSource[key];
|
|
65188
65511
|
typeof v == "string" && v.length > 0 && (env[key] = v);
|
|
65189
65512
|
}
|
|
65190
|
-
return input.provider === "anthropic" ? env.ANTHROPIC_BASE_URL = input.sandboxBrokerUrl : env.OPENAI_BASE_URL = `${input.sandboxBrokerUrl.replace(/\/+$/, "")}/v1`, input.provider === "anthropic" ? (env.CLAUDE_CONFIG_DIR = input.sandboxBootstrapDir, env.CLAUDE_CODE_TMPDIR = input.sandboxBootstrapDir) : env.CODEX_HOME = input.sandboxBootstrapDir, env;
|
|
65513
|
+
return input.provider === "anthropic" ? env.ANTHROPIC_BASE_URL = input.sandboxBrokerUrl : env.OPENAI_BASE_URL = `${input.sandboxBrokerUrl.replace(/\/+$/, "")}/v1`, input.provider === "anthropic" ? (env.CLAUDE_CONFIG_DIR = input.sandboxBootstrapDir, env.CLAUDE_CODE_TMPDIR = input.claudeScratchDir ?? input.sandboxBootstrapDir) : env.CODEX_HOME = input.sandboxBootstrapDir, env;
|
|
65191
65514
|
}
|
|
65192
65515
|
var FORBIDDEN_KEY_PATTERNS = [
|
|
65193
65516
|
/^ANTHROPIC_API_KEY$/i,
|
|
@@ -65313,16 +65636,36 @@ async function engageSubstrate(input) {
|
|
|
65313
65636
|
try {
|
|
65314
65637
|
({ hostBrokerAddr } = await broker.start());
|
|
65315
65638
|
} catch (e) {
|
|
65316
|
-
|
|
65317
|
-
|
|
65318
|
-
|
|
65639
|
+
let primary = Object.assign(
|
|
65640
|
+
new Error("CP-7: broker failed to start \u2014 refusing to launch the implementor (fail-closed)"),
|
|
65641
|
+
{ cause: e }
|
|
65319
65642
|
);
|
|
65643
|
+
try {
|
|
65644
|
+
await broker.stop();
|
|
65645
|
+
} catch (cleanupError) {
|
|
65646
|
+
throw Object.assign(
|
|
65647
|
+
new Error("CP-7: broker start failed and cleanup also failed"),
|
|
65648
|
+
{ causes: [primary, cleanupError] }
|
|
65649
|
+
);
|
|
65650
|
+
}
|
|
65651
|
+
throw primary;
|
|
65320
65652
|
}
|
|
65321
65653
|
let initialTokenObj = broker.currentBrokerToken();
|
|
65322
|
-
if (!initialTokenObj)
|
|
65323
|
-
|
|
65324
|
-
|
|
65325
|
-
|
|
65654
|
+
if (!initialTokenObj) {
|
|
65655
|
+
let primary = new Error(
|
|
65656
|
+
"CP-7: broker minted no token \u2014 refusing to launch (fail-closed)"
|
|
65657
|
+
);
|
|
65658
|
+
try {
|
|
65659
|
+
await broker.stop();
|
|
65660
|
+
} catch (cleanupError) {
|
|
65661
|
+
throw Object.assign(
|
|
65662
|
+
new Error("CP-7: broker minted no token and cleanup also failed"),
|
|
65663
|
+
{ causes: [primary, cleanupError] }
|
|
65664
|
+
);
|
|
65665
|
+
}
|
|
65666
|
+
throw primary;
|
|
65667
|
+
}
|
|
65668
|
+
let initialToken = initialTokenObj.value, sandboxBrokerUrl = selection.tier === "docker" ? `http://127.0.0.1:${RELAY_PORT}` : `http://${hostBrokerAddr}`, sandboxHome = selection.tier === "docker" ? CONTAINER_WORKDIR : input.workdir, sandboxBootstrapMount = selection.tier === "docker" ? SANDBOX_BOOTSTRAP_DIR : null, sandboxConfigMount = selection.tier === "docker" ? SANDBOX_AGENT_CONFIG_DIR : null, bootstrap, handle, activeTeardown;
|
|
65326
65669
|
try {
|
|
65327
65670
|
bootstrap = await ApiKeyBootstrap.create({
|
|
65328
65671
|
provider,
|
|
@@ -65333,6 +65676,7 @@ async function engageSubstrate(input) {
|
|
|
65333
65676
|
sandboxConfigDir: sandboxConfigMount ?? SANDBOX_AGENT_CONFIG_DIR
|
|
65334
65677
|
} : { sandboxDirEqualsHostDir: !0, configDirEqualsHostDir: !0 },
|
|
65335
65678
|
hostRoot: input.bootstrapHostRoot,
|
|
65679
|
+
...selection.tier === "sandbox_exec" && provider === "anthropic" ? { claudeScratchHostRoot: input.claudeScratchHostRoot ?? "/tmp" } : {},
|
|
65336
65680
|
// M-2 — fail closed if the bootstrap dir lands inside the agent's rw
|
|
65337
65681
|
// workdir mount (the token would leak through it).
|
|
65338
65682
|
workdir: input.workdir,
|
|
@@ -65344,11 +65688,12 @@ async function engageSubstrate(input) {
|
|
|
65344
65688
|
), agentConfigSpec = sandboxConfigMount !== null ? { hostDir: bootstrap.configHostDir, sandboxDir: sandboxConfigMount } : (
|
|
65345
65689
|
// A5: sandbox fs == host fs → config path equals the host dir.
|
|
65346
65690
|
{ hostDir: bootstrap.configHostDir, sandboxDir: bootstrap.configHostDir }
|
|
65347
|
-
), sanitizedBase = buildSanitizedBaseEnv({
|
|
65691
|
+
), agentScratchSpec = bootstrap.claudeScratchSpec, sanitizedBase = buildSanitizedBaseEnv({
|
|
65348
65692
|
provider,
|
|
65349
65693
|
sandboxBrokerUrl,
|
|
65350
65694
|
sandboxHome,
|
|
65351
65695
|
sandboxBootstrapDir: agentConfigSpec.sandboxDir,
|
|
65696
|
+
...agentScratchSpec !== null ? { claudeScratchDir: agentScratchSpec.sandboxDir } : {},
|
|
65352
65697
|
safeSource: input.localeSource
|
|
65353
65698
|
});
|
|
65354
65699
|
assertNoAmbientCreds(sanitizedBase);
|
|
@@ -65362,6 +65707,7 @@ async function engageSubstrate(input) {
|
|
|
65362
65707
|
sanitizedEnv: finalEnv,
|
|
65363
65708
|
agentBootstrap: agentBootstrapSpec,
|
|
65364
65709
|
agentConfig: agentConfigSpec,
|
|
65710
|
+
...agentScratchSpec !== null ? { agentScratch: agentScratchSpec } : {},
|
|
65365
65711
|
// CP-7 W3 — Stage-2 r1 HIGH. The resolved audit dir → A5 trailing deny.
|
|
65366
65712
|
// Undefined when a test injects its own in-memory sink (no real tree).
|
|
65367
65713
|
...resolvedAuditDir !== null ? { auditDir: resolvedAuditDir } : {}
|
|
@@ -65370,12 +65716,30 @@ async function engageSubstrate(input) {
|
|
|
65370
65716
|
`[CP-7] Substrate engaged (tier=${selection.tier}, egress=${handle.egressFidelity}) \u2014 agent is creditless, broker holds the key`,
|
|
65371
65717
|
{ taskId: input.taskId, agent: input.agentKind }
|
|
65372
65718
|
);
|
|
65373
|
-
let liveBootstrap = bootstrap, liveHandle = handle, liveBroker = broker, refreshTimer = null, teardown = async () => {
|
|
65374
|
-
refreshTimer && (clearInterval(refreshTimer), refreshTimer = null)
|
|
65375
|
-
|
|
65376
|
-
|
|
65377
|
-
|
|
65378
|
-
|
|
65719
|
+
let liveBootstrap = bootstrap, liveHandle = handle, liveBroker = broker, refreshTimer = null, teardownPromise, teardown = () => teardownPromise || (teardownPromise = (async () => {
|
|
65720
|
+
refreshTimer && (clearInterval(refreshTimer), refreshTimer = null);
|
|
65721
|
+
let failures = [];
|
|
65722
|
+
for (let cleanup of [
|
|
65723
|
+
() => liveHandle.teardown(),
|
|
65724
|
+
() => liveBroker.stop(),
|
|
65725
|
+
() => liveBootstrap.destroy()
|
|
65726
|
+
])
|
|
65727
|
+
try {
|
|
65728
|
+
await cleanup();
|
|
65729
|
+
} catch (error) {
|
|
65730
|
+
failures.push(error);
|
|
65731
|
+
}
|
|
65732
|
+
if (failures.length > 0)
|
|
65733
|
+
throw logger.warn("[CP-7] substrate cleanup failed \u2014 task cannot pass", {
|
|
65734
|
+
taskId: input.taskId,
|
|
65735
|
+
failureCount: failures.length,
|
|
65736
|
+
...errorShapeOnly(failures[0])
|
|
65737
|
+
}), failures.length === 1 ? failures[0] : Object.assign(new Error("CP-7 substrate cleanup failed"), {
|
|
65738
|
+
causes: failures
|
|
65739
|
+
});
|
|
65740
|
+
})(), teardownPromise);
|
|
65741
|
+
activeTeardown = teardown;
|
|
65742
|
+
let launchId = `launch-${input.taskId}-${Date.now()}`, denialReason = liveHandle.egressFidelity === "strict" ? "structural_deny_network_none" : "coarse_loopback_only", postureRes;
|
|
65379
65743
|
try {
|
|
65380
65744
|
postureRes = await auditSink.emit("egress_denied", {
|
|
65381
65745
|
destination: "*",
|
|
@@ -65384,13 +65748,16 @@ async function engageSubstrate(input) {
|
|
|
65384
65748
|
caller_event_id: launchId
|
|
65385
65749
|
});
|
|
65386
65750
|
} catch (e) {
|
|
65387
|
-
throw
|
|
65388
|
-
|
|
65751
|
+
throw Object.assign(
|
|
65752
|
+
new Error(
|
|
65753
|
+
"CP-7 W3: egress-posture audit emit failed \u2014 refusing to launch the creditless agent (audit-before-effect fail-closed)"
|
|
65754
|
+
),
|
|
65755
|
+
{ cause: e }
|
|
65389
65756
|
);
|
|
65390
65757
|
}
|
|
65391
65758
|
if (!("ack" in postureRes))
|
|
65392
|
-
throw
|
|
65393
|
-
|
|
65759
|
+
throw new Error(
|
|
65760
|
+
"CP-7 W3: egress-posture audit was rejected \u2014 refusing to launch the creditless agent (no durable egress posture \u2192 no agent)"
|
|
65394
65761
|
);
|
|
65395
65762
|
let refreshIntervalMs = input.tokenRefreshIntervalMs ?? 600 * 1e3, inFlightRefresh = null, doRefreshOnce = async () => {
|
|
65396
65763
|
if (!(typeof liveBroker.rotateBrokerToken == "function" && typeof liveBroker.commitBrokerTokenRotation == "function" && typeof liveBroker.rollbackBrokerTokenRotation == "function")) {
|
|
@@ -65403,10 +65770,23 @@ async function engageSubstrate(input) {
|
|
|
65403
65770
|
try {
|
|
65404
65771
|
await liveBootstrap.refresh(rotated.token.value), liveBroker.commitBrokerTokenRotation(rotated);
|
|
65405
65772
|
} catch (e) {
|
|
65406
|
-
|
|
65773
|
+
liveBroker.rollbackBrokerTokenRotation(rotated), logger.warn(
|
|
65407
65774
|
"[CP-7] broker-token refresh write FAILED \u2014 rolled back to the prior token and tearing down (fail-closed)",
|
|
65408
|
-
{ taskId: input.taskId,
|
|
65409
|
-
)
|
|
65775
|
+
{ taskId: input.taskId, ...errorShapeOnly(e) }
|
|
65776
|
+
);
|
|
65777
|
+
let refreshFailure = Object.assign(
|
|
65778
|
+
new Error("CP-7 broker-token refresh failed"),
|
|
65779
|
+
{ cause: e }
|
|
65780
|
+
);
|
|
65781
|
+
try {
|
|
65782
|
+
await teardown();
|
|
65783
|
+
} catch (cleanupError) {
|
|
65784
|
+
throw Object.assign(
|
|
65785
|
+
new Error("CP-7 broker-token refresh failed and cleanup also failed"),
|
|
65786
|
+
{ causes: [refreshFailure, cleanupError] }
|
|
65787
|
+
);
|
|
65788
|
+
}
|
|
65789
|
+
throw refreshFailure;
|
|
65410
65790
|
}
|
|
65411
65791
|
}, doRefresh = async () => {
|
|
65412
65792
|
let next = (inFlightRefresh ?? Promise.resolve()).catch(() => {
|
|
@@ -65433,10 +65813,32 @@ async function engageSubstrate(input) {
|
|
|
65433
65813
|
teardown
|
|
65434
65814
|
};
|
|
65435
65815
|
} catch (e) {
|
|
65436
|
-
|
|
65437
|
-
|
|
65438
|
-
|
|
65439
|
-
|
|
65816
|
+
let primary = e instanceof Error ? e : new Error("CP-7 substrate launch failed"), cleanupFailures = [];
|
|
65817
|
+
if (activeTeardown)
|
|
65818
|
+
try {
|
|
65819
|
+
await activeTeardown();
|
|
65820
|
+
} catch (cleanupError) {
|
|
65821
|
+
cleanupFailures.push(cleanupError);
|
|
65822
|
+
}
|
|
65823
|
+
else
|
|
65824
|
+
for (let cleanup of [
|
|
65825
|
+
...handle ? [() => handle.teardown()] : [],
|
|
65826
|
+
...bootstrap ? [() => bootstrap.destroy()] : [],
|
|
65827
|
+
() => broker.stop()
|
|
65828
|
+
])
|
|
65829
|
+
try {
|
|
65830
|
+
await cleanup();
|
|
65831
|
+
} catch (cleanupError) {
|
|
65832
|
+
cleanupFailures.push(cleanupError);
|
|
65833
|
+
}
|
|
65834
|
+
throw cleanupFailures.length > 0 ? (logger.warn("[CP-7] failed launch also failed cleanup", {
|
|
65835
|
+
taskId: input.taskId,
|
|
65836
|
+
failureCount: cleanupFailures.length,
|
|
65837
|
+
...errorShapeOnly(cleanupFailures[0])
|
|
65838
|
+
}), Object.assign(
|
|
65839
|
+
new Error("CP-7 substrate launch failed and cleanup also failed"),
|
|
65840
|
+
{ causes: [primary, ...cleanupFailures] }
|
|
65841
|
+
)) : primary;
|
|
65440
65842
|
}
|
|
65441
65843
|
}
|
|
65442
65844
|
var RESOLVER_AGENT_STATE_DIR_SEGMENTS = {
|