@sema-agent/core 5.41.0 → 5.43.0
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/CHANGELOG.md +95 -0
- package/dist/core/checkpoint-store.d.ts +15 -0
- package/dist/core/checkpoint-store.js +5 -1
- package/dist/core/memory-engine/file-backend.js +2 -2
- package/dist/core/memory-engine/layout.d.ts +5 -0
- package/dist/core/memory-engine/layout.js +6 -3
- package/dist/core/park-selfcheck.js +3 -1
- package/dist/core/runner/assemble-result.d.ts +3 -0
- package/dist/core/runner/assemble-result.js +4 -1
- package/dist/core/runner/prepare-hands-readface.d.ts +192 -0
- package/dist/core/runner/prepare-hands-readface.js +283 -0
- package/dist/core/runner/prepare-task.d.ts +3 -5
- package/dist/core/runner/prepare-task.js +22 -233
- package/dist/core/runner/runtask.js +6 -7
- package/dist/core/types.d.ts +23 -6
- package/dist/core/types.js +20 -0
- package/dist/engine/execution-env/node-execution-env.d.ts +8 -0
- package/dist/engine/execution-env/node-execution-env.js +41 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/tools/fs/fs-search-tools.d.ts +8 -0
- package/dist/tools/fs/fs-search-tools.js +70 -58
- package/dist/tools/fs/search.d.ts +42 -9
- package/dist/tools/fs/search.js +125 -77
- package/package.json +1 -1
- package/test/export-surface.snapshot.json +2 -1
|
@@ -56,7 +56,8 @@ import { prepareMemory } from "./prepare-memory.js";
|
|
|
56
56
|
import { limitConfigError, prepareConfigDoors } from "./prepare-config-doors.js";
|
|
57
57
|
import { NAMESPACED_NAME_SHAPES, prepareSafetyScan } from "./prepare-safety-scan.js";
|
|
58
58
|
import { prepareAcquireReconcile } from "./prepare-acquire-reconcile.js";
|
|
59
|
-
import {
|
|
59
|
+
import { prepareHandsMount, resolveHandsLessReadFace } from "./prepare-hands-readface.js";
|
|
60
|
+
import { prepareWorkspaceRestore, remoteEnvFailureNote, restoreWorkspaceWithRetry } from "./prepare-workspace-restore.js";
|
|
60
61
|
import { defaultPromptProvider, buildEnvironmentContext, formatLocalDate, isValidTimeZone, PROJECT_CONTEXT_FRAMING } from "../../prompts/default.js";
|
|
61
62
|
import { applyGitFrameGuard, probeGitStatusLane } from "./git-status-frame.js";
|
|
62
63
|
import { assemblePrompt } from "../../prompt-assembly/assemble.js";
|
|
@@ -76,7 +77,7 @@ import { hasBackgroundShell, sweepBackgroundShells } from "../background-shell.j
|
|
|
76
77
|
import { createTaskOutputTool, createTaskStopTool, defaultTaskRegistry } from "../task-registry.js";
|
|
77
78
|
import { createMonitorTool } from "../../tools/monitor.js";
|
|
78
79
|
import { createWorktreeTools } from "../../tools/worktree.js";
|
|
79
|
-
import { applyCompactionToReadFileState,
|
|
80
|
+
import { applyCompactionToReadFileState, isReadDedupStubResult, FULL_SHELL_CONTRACT_ID, HAND_TOOL_EFFECTS } from "../../tools/fs/index.js";
|
|
80
81
|
import { decodeTextBytes } from "../../tools/fs/encoding.js";
|
|
81
82
|
import { ASK_USER_QUESTION_TOOL_NAME, createAskUserQuestionTool, classifyQuestionOutcome, isLiveQuestionFace, validateAskQuestions, } from "../ask-question.js";
|
|
82
83
|
import { createSchedulerTools } from "../../tools/scheduler-tools.js";
|
|
@@ -86,8 +87,7 @@ import { createRunWorkflowTool, RUN_WORKFLOW_TOOL_NAME } from "../../orchestrati
|
|
|
86
87
|
import { resolveWorkflowSizeGuideline } from "../../orchestration/workflow-size-guideline.js";
|
|
87
88
|
import { createLspTool, gitCheckIgnoreFilter, resolveLspPath } from "../lsp.js";
|
|
88
89
|
import { resolveKey } from "../../tools/fs/safety.js";
|
|
89
|
-
import {
|
|
90
|
-
import { BINDING_CHECKPOINT_VERSION, mintCheckpointToken, ORG_ADMISSION_CHECKPOINT_VERSION, F012_CHECKPOINT_VERSION, FACE_CHECKPOINT_VERSION, REAL_APPROVAL_CHECKPOINT_VERSION, RESOURCE_CHECKPOINT_VERSION, TOKEN_CHECKPOINT_VERSION, buildRiskDescriptor, debitLedger, encodeAtFidelity, remainingBudgetMicroUsd, resolveCheckpointStore, resolveDeclaredFidelity, samePlainValue, } from "../checkpoint-store.js";
|
|
90
|
+
import { BINDING_CHECKPOINT_VERSION, mintCheckpointId, mintCheckpointToken, ORG_ADMISSION_CHECKPOINT_VERSION, F012_CHECKPOINT_VERSION, FACE_CHECKPOINT_VERSION, REAL_APPROVAL_CHECKPOINT_VERSION, RESOURCE_CHECKPOINT_VERSION, TOKEN_CHECKPOINT_VERSION, buildRiskDescriptor, debitLedger, encodeAtFidelity, remainingBudgetMicroUsd, resolveCheckpointStore, resolveDeclaredFidelity, samePlainValue, } from "../checkpoint-store.js";
|
|
91
91
|
import { boundInputHashOf } from "../canonical-json.js";
|
|
92
92
|
import { countElicitOptIns, deriveWiringManifest, resolveAskSeamForm, resolveDeclaredDurability, resolveElicitSeam, resolveQuestionSeam } from "../wiring-manifest.js";
|
|
93
93
|
import { durableParkGapFor } from "../park-selfcheck.js";
|
|
@@ -191,11 +191,7 @@ function announceToolModelGate(onNotice, modelId, gate) {
|
|
|
191
191
|
}
|
|
192
192
|
}
|
|
193
193
|
}
|
|
194
|
-
|
|
195
|
-
let readFaceClampConsoleAnnounced = false;
|
|
196
|
-
export function __resetReadFaceClampAnnouncement() {
|
|
197
|
-
readFaceClampConsoleAnnounced = false;
|
|
198
|
-
}
|
|
194
|
+
export { __resetReadFaceClampAnnouncement } from "./prepare-hands-readface.js";
|
|
199
195
|
const DEFAULT_MAX_SUSPENDS = 5;
|
|
200
196
|
const ULTRA_REASONING_TIERS = new Set(["xhigh", "max"]);
|
|
201
197
|
const DEFAULT_RESOURCE_TTL_MS = 30 * 24 * 60 * 60 * 1000;
|
|
@@ -1036,14 +1032,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1036
1032
|
resourceSpentMicroUsd: priorLedger?.spentMicroUsd ?? 0,
|
|
1037
1033
|
suspendCount: priorSuspendCount,
|
|
1038
1034
|
};
|
|
1039
|
-
let readFileStateForCheckpoint;
|
|
1040
|
-
let seedContextFiles;
|
|
1041
|
-
let handsCwdRef;
|
|
1042
|
-
let workspaceStateSettle;
|
|
1043
|
-
let wsSnapshot;
|
|
1044
|
-
let rebaseWsPath = (p) => p;
|
|
1045
1035
|
let worktreeSessionRef;
|
|
1046
|
-
let backgroundTaskToolsActive = false;
|
|
1047
1036
|
let suspendForResource;
|
|
1048
1037
|
let suspendForPlatformLimit;
|
|
1049
1038
|
let suspendForReview;
|
|
@@ -1209,219 +1198,14 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1209
1198
|
foldProtocolAxes(a2a.toolAxes, "A2A");
|
|
1210
1199
|
const callIssuedAtRef = {};
|
|
1211
1200
|
const memoryWriteGateRef = {};
|
|
1212
|
-
const
|
|
1213
|
-
const
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
attachmentRootCanonical = rootCanonical;
|
|
1221
|
-
const canonicalizeExtraDirs = async (dirs, field, sink) => {
|
|
1222
|
-
for (const dir of dirs ?? []) {
|
|
1223
|
-
if (!dir || !dir.trim())
|
|
1224
|
-
continue;
|
|
1225
|
-
const c = await executionEnv.canonicalPath(dir);
|
|
1226
|
-
if (c.ok) {
|
|
1227
|
-
sink.push(c.value);
|
|
1228
|
-
}
|
|
1229
|
-
else {
|
|
1230
|
-
deps.onError?.(new Error(`${field} entry skipped (cannot canonicalize): ${dir}`), {
|
|
1231
|
-
phase: "config",
|
|
1232
|
-
sessionId,
|
|
1233
|
-
});
|
|
1234
|
-
emitTrace(deps.tracer, () => ({
|
|
1235
|
-
kind: "config.additional_directory_skipped",
|
|
1236
|
-
version: 1,
|
|
1237
|
-
taskId: hostTaskId,
|
|
1238
|
-
entry: dir,
|
|
1239
|
-
...(field !== "additionalDirectories" ? { field } : {}),
|
|
1240
|
-
reason: `${c.error.code}: ${c.error.message}`,
|
|
1241
|
-
ts: Date.now(),
|
|
1242
|
-
}));
|
|
1243
|
-
}
|
|
1244
|
-
}
|
|
1245
|
-
};
|
|
1246
|
-
await canonicalizeExtraDirs(spec.additionalDirectories, "additionalDirectories", additionalRootsCanonical);
|
|
1247
|
-
await canonicalizeExtraDirs(spec.additionalReadDirectories, "additionalReadDirectories", additionalReadRootsCanonical);
|
|
1248
|
-
if (spec.envFacts?.scratchpadDir) {
|
|
1249
|
-
let c = await executionEnv.canonicalPath(spec.envFacts.scratchpadDir);
|
|
1250
|
-
if (!c.ok && c.error.code === "not_found") {
|
|
1251
|
-
const marker = await executionEnv.joinPath([spec.envFacts.scratchpadDir, ".sema-scratchpad"]);
|
|
1252
|
-
const exclusiveCreate = executionEnv.writeFileExclusive?.bind(executionEnv);
|
|
1253
|
-
if (marker.ok && exclusiveCreate) {
|
|
1254
|
-
const w = await exclusiveCreate(marker.value, "");
|
|
1255
|
-
if (w.ok || w.error.code === "already_exists")
|
|
1256
|
-
c = await executionEnv.canonicalPath(spec.envFacts.scratchpadDir);
|
|
1257
|
-
}
|
|
1258
|
-
}
|
|
1259
|
-
if (c.ok)
|
|
1260
|
-
additionalRootsCanonical.push(c.value);
|
|
1261
|
-
}
|
|
1262
|
-
for (const a of [additionalRootsCanonical, additionalReadRootsCanonical])
|
|
1263
|
-
a.splice(0, a.length, ...new Set(a));
|
|
1264
|
-
const readFileState = new Map((resume?.seed.readFileState ?? []).map(([k, v]) => [rebaseRestoredPath(k), v]));
|
|
1265
|
-
readFileStateForCheckpoint = readFileState;
|
|
1266
|
-
seedContextFiles = async (files) => {
|
|
1267
|
-
for (const f of files) {
|
|
1268
|
-
const rk = await resolveKey(executionEnv, rootCanonical, f.path, undefined, undefined, [...additionalRootsCanonical, ...additionalReadRootsCanonical], undefined, undefined, resolvedReadFace);
|
|
1269
|
-
if (rk.ok)
|
|
1270
|
-
seedReadFileStateFromContext(readFileState, rk.key, f.content);
|
|
1271
|
-
}
|
|
1272
|
-
};
|
|
1273
|
-
const handsIncludeShell = !(executionEnv instanceof StubExecutionEnv);
|
|
1274
|
-
const handsReadOnly = spec.handsReadOnly === true;
|
|
1275
|
-
backgroundTaskToolsActive = handsIncludeShell && !handsReadOnly && hasBackgroundShell(executionEnv);
|
|
1276
|
-
wsSnapshot = resume !== undefined || !(handsIncludeShell && !handsReadOnly) ? undefined : await session.getWorkspaceState().catch(() => undefined);
|
|
1277
|
-
rebaseWsPath = (p) => (wsSnapshot === undefined || wsSnapshot.taskRoot === rootCanonical ? p : rebaseWorkspacePath(p, wsSnapshot.taskRoot, rootCanonical));
|
|
1278
|
-
if (handsIncludeShell && !handsReadOnly) {
|
|
1279
|
-
handsCwdRef = { current: rootCanonical };
|
|
1280
|
-
if (resume?.seed.handsCwd !== undefined)
|
|
1281
|
-
handsCwdRef.current = rebaseRestoredPath(resume.seed.handsCwd);
|
|
1282
|
-
else if (wsSnapshot?.handsCwd !== undefined)
|
|
1283
|
-
handsCwdRef.current = rebaseWsPath(wsSnapshot.handsCwd);
|
|
1284
|
-
workspaceStateSettle = {
|
|
1285
|
-
rootCanonical,
|
|
1286
|
-
restoredHandsCwd: handsCwdRef.current !== rootCanonical ? handsCwdRef.current : undefined,
|
|
1287
|
-
...(resume !== undefined ? { baselineUnknown: true } : {}),
|
|
1288
|
-
};
|
|
1289
|
-
}
|
|
1290
|
-
const seedReadFaceSection = resume?.seed.readFace;
|
|
1291
|
-
const readDenyAdditions = [...(deps.readDenyPatterns ?? []), ...(spec.readDenyPatterns ?? []), ...(seedReadFaceSection?.denyEntries ?? [])];
|
|
1292
|
-
const readDenyBuiltinCfg = {
|
|
1293
|
-
...(deps.readDenyBuiltinTiers !== undefined ? { tiers: [...deps.readDenyBuiltinTiers] } : {}),
|
|
1294
|
-
...(deps.readDenyBuiltinExclude !== undefined ? { exclude: [...deps.readDenyBuiltinExclude] } : {}),
|
|
1295
|
-
};
|
|
1296
|
-
readDenyMatcher = compileReadDeny(readDenyAdditions, "readDenyPatterns", readDenyBuiltinCfg);
|
|
1297
|
-
readDenyAdditionsNormalized = compileReadDeny(readDenyAdditions, "readDenyPatterns", { tiers: [] }).entries;
|
|
1298
|
-
let liveReadFace = resolveReadFace({
|
|
1299
|
-
specReadFace: spec.readFace,
|
|
1300
|
-
depsReadFace: deps.readFace,
|
|
1301
|
-
readOnlyMount: handsReadOnly,
|
|
1302
|
-
orgGoverned: deps.permissionRuleOrg !== undefined,
|
|
1303
|
-
fullShellReachable,
|
|
1304
|
-
onDeploymentClamp: () => {
|
|
1305
|
-
const sink = deps.onNotice;
|
|
1306
|
-
if (typeof sink === "function") {
|
|
1307
|
-
if (readFaceClampAnnouncedSinks.has(sink))
|
|
1308
|
-
return;
|
|
1309
|
-
readFaceClampAnnouncedSinks.add(sink);
|
|
1310
|
-
}
|
|
1311
|
-
else {
|
|
1312
|
-
if (readFaceClampConsoleAnnounced)
|
|
1313
|
-
return;
|
|
1314
|
-
readFaceClampConsoleAnnounced = true;
|
|
1315
|
-
}
|
|
1316
|
-
deliverEngineNotice(sink, deploymentReadFaceClampNotice());
|
|
1317
|
-
},
|
|
1318
|
-
});
|
|
1319
|
-
if (resume !== undefined && (seedReadFaceSection === undefined || seedReadFaceSection.face === "roots"))
|
|
1320
|
-
liveReadFace = "roots";
|
|
1321
|
-
resolvedReadFace = liveReadFace;
|
|
1322
|
-
if (resume === undefined && spec.sessionId !== undefined) {
|
|
1323
|
-
const prior = await session.buildContext().catch(() => undefined);
|
|
1324
|
-
for (const rec of wholeFileRecordsFromTranscript(prior?.messages ?? [])) {
|
|
1325
|
-
const rk = await resolveKey(executionEnv, rootCanonical, rec.path, undefined, undefined, [...additionalRootsCanonical, ...additionalReadRootsCanonical], undefined, undefined, liveReadFace);
|
|
1326
|
-
if (rk.ok)
|
|
1327
|
-
seedReadFileStateFromTranscript(readFileState, rk.key, rec.content, rec.at);
|
|
1328
|
-
}
|
|
1329
|
-
}
|
|
1330
|
-
const band = createHandsToolkit(executionEnv, readFileState, rootCanonical, {
|
|
1331
|
-
...(additionalRootsCanonical.length > 0 ? { additionalRoots: additionalRootsCanonical } : {}),
|
|
1332
|
-
...(additionalReadRootsCanonical.length > 0 ? { additionalReadRoots: additionalReadRootsCanonical } : {}),
|
|
1333
|
-
...(readDenyAdditions.length > 0 ? { readDenyPatterns: readDenyAdditions } : {}),
|
|
1334
|
-
...(readDenyBuiltinCfg.tiers !== undefined ? { readDenyBuiltinTiers: readDenyBuiltinCfg.tiers } : {}),
|
|
1335
|
-
...(readDenyBuiltinCfg.exclude !== undefined ? { readDenyBuiltinExclude: readDenyBuiltinCfg.exclude } : {}),
|
|
1336
|
-
readFace: liveReadFace,
|
|
1337
|
-
includeShell: handsIncludeShell,
|
|
1338
|
-
readOnly: handsReadOnly,
|
|
1339
|
-
...(handsCwdRef ? { cwdRef: handsCwdRef } : {}),
|
|
1340
|
-
taskRegistry: defaultTaskRegistry,
|
|
1341
|
-
taskOwner: hostTaskId,
|
|
1342
|
-
taskScope,
|
|
1343
|
-
oneShot: spec.oneShot,
|
|
1344
|
-
...(sessionId !== undefined ? { sessionId } : {}),
|
|
1345
|
-
...(internals?.onTaskNotification !== undefined ? { taskNotification: internals.onTaskNotification } : {}),
|
|
1346
|
-
...(internals?.detachHub !== undefined ? { detachHub: internals.detachHub } : {}),
|
|
1347
|
-
...(deps.onNotice !== undefined ? { onNotice: deps.onNotice } : {}),
|
|
1348
|
-
pdfModelCapabilities: pdfModelCapabilitiesOf(model),
|
|
1349
|
-
...(deps.hands?.bashReadonlyAllow !== undefined ? { bashReadonlyAllow: deps.hands.bashReadonlyAllow } : {}),
|
|
1350
|
-
...(deps.hands?.commitCoAuthor !== undefined ? { commitCoAuthor: deps.hands.commitCoAuthor } : {}),
|
|
1351
|
-
...(deps.hands?.readImageDownsampler !== undefined ? { readImageDownsampler: deps.hands.readImageDownsampler } : {}),
|
|
1352
|
-
...(deps.hands?.autoBackgroundOnTimeout !== undefined ? { autoBackgroundOnTimeout: deps.hands.autoBackgroundOnTimeout } : {}),
|
|
1353
|
-
...(deps.hands?.readCyberReminder !== undefined ? { readCyberReminder: deps.hands.readCyberReminder } : {}),
|
|
1354
|
-
beforeWrite: async (w) => {
|
|
1355
|
-
const deploymentGate = deps.hands?.beforeWrite;
|
|
1356
|
-
if (deploymentGate) {
|
|
1357
|
-
const verdict = await deploymentGate(w);
|
|
1358
|
-
if (verdict !== undefined && verdict.ok === false)
|
|
1359
|
-
return verdict;
|
|
1360
|
-
}
|
|
1361
|
-
return memoryWriteGateRef.current?.(w);
|
|
1362
|
-
},
|
|
1363
|
-
mountBackgroundTaskTools: false,
|
|
1364
|
-
monitorToolActive: backgroundTaskToolsActive && !(toolFaceSnapshot.exclude?.includes("Monitor") ?? false),
|
|
1365
|
-
});
|
|
1366
|
-
{
|
|
1367
|
-
const bandNames = new Set(band.flatMap((t) => [t.name, ...(t.aliases ?? [])]));
|
|
1368
|
-
const shadowed = (spec.tools ?? []).filter((t) => [t.name, ...(t.aliases ?? [])].some((n) => bandNames.has(n)));
|
|
1369
|
-
if (shadowed.length > 0) {
|
|
1370
|
-
const names = shadowed.map((t) => `"${t.name}"`).join(", ");
|
|
1371
|
-
deps.onError?.(new Error(`spec.tools ${shadowed.length > 1 ? "entries" : "entry"} ${names} collide${shadowed.length > 1 ? "" : "s"} with the built-in hands tool band — the built-in wins (registered later; the harness tool Map is last-write-wins) and the caller tool never dispatches this task. Rename the caller tool, or don't inject executionEnv if you intend to replace the band.`), { phase: "config", sessionId });
|
|
1372
|
-
}
|
|
1373
|
-
}
|
|
1374
|
-
tools.push(...band.map((t) => firstPartyOffload(t)));
|
|
1375
|
-
const shellGate = effectiveShellGate;
|
|
1376
|
-
if (shellGate === "off" && !(executionEnv instanceof StubExecutionEnv) && spec.handsReadOnly !== true) {
|
|
1377
|
-
deps.onError?.(new Error(`shell gate doctrine is "off" while a real writable shell (Bash) is mounted — no shell safety-axis ` +
|
|
1378
|
-
`fold applies to this run (commands are adjudicated by the ordinary policy/hook chain only). ` +
|
|
1379
|
-
`Set spec.shellGate to "classify" or "always" if this deployment expects doctrine-gated shell behavior.`), { phase: "config", sessionId, classification: "shell-gate-off" });
|
|
1380
|
-
}
|
|
1381
|
-
if (shellGate !== "off" && !(executionEnv instanceof StubExecutionEnv) && spec.handsReadOnly !== true) {
|
|
1382
|
-
const bashTierBefore = irreversibilityTier.get("Bash");
|
|
1383
|
-
shellGatedBash = !egressTools.has("Bash") && bashTierBefore !== "always" && bashTierBefore !== "maybe";
|
|
1384
|
-
const bashEffectiveTier = shellGate === "always" || bashTierBefore === "always" ? "always" : "maybe";
|
|
1385
|
-
irreversibilityTier.set("Bash", bashEffectiveTier);
|
|
1386
|
-
irreversibleTools.add("Bash");
|
|
1387
|
-
const shellReadBoundary = () => ({
|
|
1388
|
-
roots: [rootCanonical, ...additionalRootsCanonical, ...additionalReadRootsCanonical],
|
|
1389
|
-
...(handsCwdRef?.current !== undefined ? { cwd: handsCwdRef.current } : {}),
|
|
1390
|
-
denyMatch: (p) => readDenyMatcher?.matchPath(p)?.pattern ?? null,
|
|
1391
|
-
...(resolvedReadFace !== undefined ? { face: resolvedReadFace } : {}),
|
|
1392
|
-
});
|
|
1393
|
-
if (shellGate === "classify" && shellGatedBash)
|
|
1394
|
-
reversibilityProbes.set("Bash", bashReversibilityProbe(undefined, shellReadBoundary));
|
|
1395
|
-
if (backgroundTaskToolsActive) {
|
|
1396
|
-
const monitorTierBefore = irreversibilityTier.get("Monitor");
|
|
1397
|
-
shellGatedMonitor = !egressTools.has("Monitor") && monitorTierBefore !== "always" && monitorTierBefore !== "maybe";
|
|
1398
|
-
const monitorEffectiveTier = shellGate === "always" || monitorTierBefore === "always" ? "always" : "maybe";
|
|
1399
|
-
irreversibilityTier.set("Monitor", monitorEffectiveTier);
|
|
1400
|
-
irreversibleTools.add("Monitor");
|
|
1401
|
-
if (shellGate === "classify" && shellGatedMonitor)
|
|
1402
|
-
reversibilityProbes.set("Monitor", bashReversibilityProbe(undefined, shellReadBoundary));
|
|
1403
|
-
}
|
|
1404
|
-
}
|
|
1405
|
-
}
|
|
1406
|
-
else {
|
|
1407
|
-
const liveFace = resolveReadFace({
|
|
1408
|
-
specReadFace: spec.readFace,
|
|
1409
|
-
depsReadFace: deps.readFace,
|
|
1410
|
-
readOnlyMount: spec.handsReadOnly === true,
|
|
1411
|
-
orgGoverned: deps.permissionRuleOrg !== undefined,
|
|
1412
|
-
fullShellReachable,
|
|
1413
|
-
});
|
|
1414
|
-
const seed = resume?.seed.readFace;
|
|
1415
|
-
handsLessResolvedFace = resume !== undefined && (seed === undefined || seed.face === "roots") ? "roots" : liveFace;
|
|
1416
|
-
const denyAdditions = [...(deps.readDenyPatterns ?? []), ...(spec.readDenyPatterns ?? []), ...(seed?.denyEntries ?? [])];
|
|
1417
|
-
resolveReadDenyBuiltins({
|
|
1418
|
-
...(deps.readDenyBuiltinTiers !== undefined ? { tiers: deps.readDenyBuiltinTiers } : {}),
|
|
1419
|
-
...(deps.readDenyBuiltinExclude !== undefined ? { exclude: deps.readDenyBuiltinExclude } : {}),
|
|
1420
|
-
});
|
|
1421
|
-
if (denyAdditions.length > 0) {
|
|
1422
|
-
readDenyAdditionsNormalized = compileReadDeny(denyAdditions, "readDenyPatterns", { tiers: [] }).entries;
|
|
1423
|
-
}
|
|
1424
|
-
}
|
|
1201
|
+
const handsReadFaceInput = { handsEnabled, executionEnv, taskRootFinal, rebaseRestoredPath, resume, session, sessionId, hostTaskId, taskScope, fullShellReachable, effectiveShellGate, toolFaceSnapshot, model, spec, deps, internals, memoryWriteGateRef, firstPartyOffload, tools, egressTools, irreversibilityTier, irreversibleTools, reversibilityProbes };
|
|
1202
|
+
const handsReadFace = handsEnabled ? await prepareHandsMount(handsReadFaceInput) : resolveHandsLessReadFace(handsReadFaceInput);
|
|
1203
|
+
const { readFileStateForCheckpoint, seedContextFiles, handsCwdRef, workspaceStateSettle, wsSnapshot, rebaseWsPath, backgroundTaskToolsActive, additionalRootsCanonical, additionalReadRootsCanonical, attachmentRootCanonical, readDenyMatcher } = handsReadFace;
|
|
1204
|
+
resolvedReadFace = handsReadFace.resolvedReadFace;
|
|
1205
|
+
readDenyAdditionsNormalized = handsReadFace.readDenyAdditionsNormalized;
|
|
1206
|
+
handsLessResolvedFace = handsReadFace.handsLessResolvedFace;
|
|
1207
|
+
shellGatedBash = handsReadFace.shellGatedBash;
|
|
1208
|
+
shellGatedMonitor = handsReadFace.shellGatedMonitor;
|
|
1425
1209
|
if (backgroundTaskToolsActive || workflowToolsActive) {
|
|
1426
1210
|
toolEffects.set("TaskOutput", "read");
|
|
1427
1211
|
toolEffects.set("TaskStop", "write");
|
|
@@ -3753,9 +3537,11 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
3753
3537
|
return { ok: false, reason };
|
|
3754
3538
|
}
|
|
3755
3539
|
};
|
|
3756
|
-
const publishCommittedSuspend = (token, gate, scope, remoteHandle) => {
|
|
3540
|
+
const publishCommittedSuspend = (token, gate, scope, remoteHandle, checkpointId) => {
|
|
3757
3541
|
const ref = gate.kind === "needs_review" || gate.kind === "plan_review" ? reviewRef : suspendRef;
|
|
3758
3542
|
ref.token = token;
|
|
3543
|
+
if (checkpointId !== undefined)
|
|
3544
|
+
ref.checkpointId = checkpointId;
|
|
3759
3545
|
ref.gate = gate;
|
|
3760
3546
|
if (remoteHandle !== undefined)
|
|
3761
3547
|
ref.restoreMode = remoteHandle.restoreMode === "park_only" ? "park_only" : "snapshot";
|
|
@@ -3821,6 +3607,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
3821
3607
|
const mintedAt = Date.now();
|
|
3822
3608
|
const cp = {
|
|
3823
3609
|
token,
|
|
3610
|
+
checkpointId: mintCheckpointId(),
|
|
3824
3611
|
version: faceCheckpointState() ? FACE_CHECKPOINT_VERSION : f012CheckpointState() ? F012_CHECKPOINT_VERSION : orgAdmissionCheckpointState() ? ORG_ADMISSION_CHECKPOINT_VERSION : resourceLedgerOut.totalTokens !== undefined ? TOKEN_CHECKPOINT_VERSION : RESOURCE_CHECKPOINT_VERSION,
|
|
3825
3612
|
scope,
|
|
3826
3613
|
sessionId,
|
|
@@ -3840,7 +3627,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
3840
3627
|
};
|
|
3841
3628
|
if (!(await commitSuspendSaga(token, cp, suspendableEnv, remoteHandle)).ok)
|
|
3842
3629
|
return false;
|
|
3843
|
-
publishCommittedSuspend(token, gate, scope, remoteHandle);
|
|
3630
|
+
publishCommittedSuspend(token, gate, scope, remoteHandle, cp.checkpointId);
|
|
3844
3631
|
try {
|
|
3845
3632
|
await sessions.pin?.(sessionId);
|
|
3846
3633
|
}
|
|
@@ -3903,6 +3690,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
3903
3690
|
const mintedAt = Date.now();
|
|
3904
3691
|
const cp = {
|
|
3905
3692
|
token,
|
|
3693
|
+
checkpointId: mintCheckpointId(),
|
|
3906
3694
|
version: faceCheckpointState() ? FACE_CHECKPOINT_VERSION : f012CheckpointState() ? F012_CHECKPOINT_VERSION : orgAdmissionCheckpointState() ? ORG_ADMISSION_CHECKPOINT_VERSION : reviewLedger.totalTokens !== undefined ? TOKEN_CHECKPOINT_VERSION : BINDING_CHECKPOINT_VERSION,
|
|
3907
3695
|
scope,
|
|
3908
3696
|
sessionId,
|
|
@@ -3925,7 +3713,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
3925
3713
|
};
|
|
3926
3714
|
if (!(await commitSuspendSaga(token, cp, suspendableEnv, remoteHandle)).ok)
|
|
3927
3715
|
return false;
|
|
3928
|
-
publishCommittedSuspend(token, gate, scope, remoteHandle);
|
|
3716
|
+
publishCommittedSuspend(token, gate, scope, remoteHandle, cp.checkpointId);
|
|
3929
3717
|
try {
|
|
3930
3718
|
await sessions.pin?.(sessionId);
|
|
3931
3719
|
}
|
|
@@ -4164,6 +3952,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
4164
3952
|
const mintedAt = Date.now();
|
|
4165
3953
|
cp = {
|
|
4166
3954
|
token,
|
|
3955
|
+
checkpointId: mintCheckpointId(),
|
|
4167
3956
|
version: faceCheckpointState() ? FACE_CHECKPOINT_VERSION : realApproval !== undefined ? REAL_APPROVAL_CHECKPOINT_VERSION : f012CheckpointState() ? F012_CHECKPOINT_VERSION : orgAdmissionCheckpointState() ? ORG_ADMISSION_CHECKPOINT_VERSION : approvalLedger.totalTokens !== undefined ? TOKEN_CHECKPOINT_VERSION : BINDING_CHECKPOINT_VERSION,
|
|
4168
3957
|
scope,
|
|
4169
3958
|
sessionId,
|
|
@@ -4219,7 +4008,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
4219
4008
|
if (!committed.ok) {
|
|
4220
4009
|
return committed.reason !== undefined ? { parkFailed: committed.reason } : undefined;
|
|
4221
4010
|
}
|
|
4222
|
-
publishCommittedSuspend(token, gate, cp.scope, remoteHandle);
|
|
4011
|
+
publishCommittedSuspend(token, gate, cp.scope, remoteHandle, cp.checkpointId);
|
|
4223
4012
|
try {
|
|
4224
4013
|
await sessions.pin?.(sessionId);
|
|
4225
4014
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { persistedReadDenyEntryProblem } from "../../tools/fs/read-deny.js";
|
|
2
2
|
import { createSafeNotifier, observeThenableRejection } from "../safe-notify.js";
|
|
3
|
-
import { deliverDelegationLifecycle, deliverEngineNotice } from "../types.js";
|
|
3
|
+
import { deliverDelegationLifecycle, deliverEngineNotice, undrainedUserInputNotices } from "../types.js";
|
|
4
4
|
import { AgentHarness, DEFAULT_COMPACTION_SETTINGS, uuidv7 } from "../../internal/harness.js";
|
|
5
5
|
import { snapshotActorAssertion } from "../../internal/llm.js";
|
|
6
6
|
import { CheckpointError, BINDING_CHECKPOINT_VERSION, checkpointVersionOf, F012_CHECKPOINT_VERSION, MAX_SUPPORTED_CHECKPOINT_VERSION, REAL_APPROVAL_CHECKPOINT_VERSION, FACE_CHECKPOINT_VERSION, remainingBudgetMicroUsd, readPendingSteerQueue, remainingTokens, LEGACY_PENDING_STEER_INPUT_ID, MAX_STEER_INPUT_ID_CHARS, validatePendingSteer, winnerFromOutcome, } from "../checkpoint-store.js";
|
|
@@ -2069,12 +2069,9 @@ export class Runner {
|
|
|
2069
2069
|
this.pendingSessionNotifications.pend(notificationSessionId, p);
|
|
2070
2070
|
};
|
|
2071
2071
|
prepared.harness.onUndrainedUserInputs = (counts) => {
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
`(${counts.steer} steer, ${counts.followUp} follow-up). They are NOT redelivered; re-send against a live run if still wanted.`,
|
|
2076
|
-
detail: { steer: counts.steer, followUp: counts.followUp, ...(spec.taskId !== undefined ? { taskId: spec.taskId } : {}) },
|
|
2077
|
-
});
|
|
2072
|
+
for (const notice of undrainedUserInputNotices(counts, spec.taskId)) {
|
|
2073
|
+
deliverEngineNotice(this.deps.onNotice, notice);
|
|
2074
|
+
}
|
|
2078
2075
|
};
|
|
2079
2076
|
prepared.harness.onEngineNoteConsumed = (p) => {
|
|
2080
2077
|
const peer = p?.peer;
|
|
@@ -3475,6 +3472,7 @@ export class Runner {
|
|
|
3475
3472
|
suspendRef: prepared.suspendRef.token !== undefined && prepared.suspendRef.gate !== undefined
|
|
3476
3473
|
? {
|
|
3477
3474
|
token: prepared.suspendRef.token,
|
|
3475
|
+
...(prepared.suspendRef.checkpointId !== undefined ? { checkpointId: prepared.suspendRef.checkpointId } : {}),
|
|
3478
3476
|
gate: prepared.suspendRef.gate,
|
|
3479
3477
|
...(prepared.suspendRef.restoreMode !== undefined ? { restoreMode: prepared.suspendRef.restoreMode } : {}),
|
|
3480
3478
|
}
|
|
@@ -3482,6 +3480,7 @@ export class Runner {
|
|
|
3482
3480
|
reviewRef: prepared.reviewRef.token !== undefined && prepared.reviewRef.gate !== undefined
|
|
3483
3481
|
? {
|
|
3484
3482
|
token: prepared.reviewRef.token,
|
|
3483
|
+
...(prepared.reviewRef.checkpointId !== undefined ? { checkpointId: prepared.reviewRef.checkpointId } : {}),
|
|
3485
3484
|
gate: prepared.reviewRef.gate,
|
|
3486
3485
|
...(prepared.reviewRef.restoreMode !== undefined ? { restoreMode: prepared.reviewRef.restoreMode } : {}),
|
|
3487
3486
|
}
|
package/dist/core/types.d.ts
CHANGED
|
@@ -2881,6 +2881,10 @@ export interface TaskResult {
|
|
|
2881
2881
|
* the resume capability, §6). Undefined for every other status.
|
|
2882
2882
|
*/
|
|
2883
2883
|
checkpointToken?: import("./checkpoint-store.js").CheckpointToken;
|
|
2884
|
+
/** The suspend's NON-SECRET stable identity ({@link import("./checkpoint-store.js").Checkpoint.checkpointId}),
|
|
2885
|
+
* set beside `checkpointToken` on the suspended/needs_review terminals — the display/correlation key a
|
|
2886
|
+
* consumer may log or render where the token must not travel. Absent on pre-identity checkpoints. */
|
|
2887
|
+
checkpointId?: string;
|
|
2884
2888
|
/** Set with `checkpointToken`: who/what must resume (e.g. `{kind:"human", reason, toolName}`), so the
|
|
2885
2889
|
* caller knows what decision the suspension is awaiting. */
|
|
2886
2890
|
checkpointGate?: import("./checkpoint-store.js").CheckpointGate;
|
|
@@ -4669,12 +4673,15 @@ export interface EngineNotice {
|
|
|
4669
4673
|
* value IS in force the prepare refuses with the same code as `TaskResult.errorCode` (one
|
|
4670
4674
|
* fact, one code, two loudness dialects); `detail: { raw }`.
|
|
4671
4675
|
*
|
|
4672
|
-
* - `"task.user_steer_undrained"` (#259) — user steers/
|
|
4673
|
-
* were still in
|
|
4674
|
-
*
|
|
4675
|
-
*
|
|
4676
|
-
*
|
|
4677
|
-
*
|
|
4676
|
+
* - `"task.user_steer_undrained"` / `"task.user_followup_undrained"` (#259) — user steers /
|
|
4677
|
+
* follow-ups whose receipts said "queued" were still in their queue at agent_end: the run
|
|
4678
|
+
* ended before any turn could drain them. One notice PER family (a consumer routing on `code`
|
|
4679
|
+
* alone must not mistake a stranded follow-up for a stranded steer — same split as the settled
|
|
4680
|
+
* frame's two count keys). They are NOT redelivered (a steer aimed at a finished run must not
|
|
4681
|
+
* fire at the next one — unlike ENGINE notes, which pend per session); the loud half of the
|
|
4682
|
+
* #257 contract's "accepted = enqueued, not consumed" sentence;
|
|
4683
|
+
* `detail: { steer, taskId? }` / `{ followUp, taskId? }`. Per-run, at most once per family
|
|
4684
|
+
* (the terminal sweep is a single site).
|
|
4678
4685
|
*
|
|
4679
4686
|
* Deliberately NOT a notice family: brain retry/reconnect liveness (a rate limit, a 5xx, a
|
|
4680
4687
|
* transient network failure being retried). Those are per-attempt liveness frames with their own
|
|
@@ -4709,6 +4716,16 @@ export declare function __resetMalformedNoticeSeatAnnouncement(): void;
|
|
|
4709
4716
|
* · an ABSENT seat prints the historic `console.warn` line verbatim (byte-compat loudness).
|
|
4710
4717
|
*/
|
|
4711
4718
|
export declare function deliverEngineNotice(onNotice: ((notice: EngineNotice) => void) | undefined, notice: EngineNotice): void;
|
|
4719
|
+
/**
|
|
4720
|
+
* #259 loud half, one notice PER FAMILY (`task.user_steer_undrained` / `task.user_followup_undrained`):
|
|
4721
|
+
* a consumer routing on `code` alone must never mistake a stranded follow-up for a stranded steer, so
|
|
4722
|
+
* the code carries exactly the semantics its name claims — the same two-key split the settled frame
|
|
4723
|
+
* uses. Pure (the terminal sweep race window is not constructible deterministically; this seam is).
|
|
4724
|
+
*/
|
|
4725
|
+
export declare function undrainedUserInputNotices(counts: {
|
|
4726
|
+
steer: number;
|
|
4727
|
+
followUp: number;
|
|
4728
|
+
}, taskId?: string): EngineNotice[];
|
|
4712
4729
|
/** Runtime dependencies shared across tasks. */
|
|
4713
4730
|
export interface RunnerDeps {
|
|
4714
4731
|
brain: Brain;
|
package/dist/core/types.js
CHANGED
|
@@ -49,3 +49,23 @@ export function deliverEngineNotice(onNotice, notice) {
|
|
|
49
49
|
}
|
|
50
50
|
console.warn(notice.message);
|
|
51
51
|
}
|
|
52
|
+
export function undrainedUserInputNotices(counts, taskId) {
|
|
53
|
+
const tid = taskId !== undefined ? { taskId } : {};
|
|
54
|
+
const tail = `accepted as "queued" were never consumed — the run ended first. They are NOT redelivered; re-send against a live run if still wanted.`;
|
|
55
|
+
const out = [];
|
|
56
|
+
if (counts.steer > 0) {
|
|
57
|
+
out.push({
|
|
58
|
+
code: "task.user_steer_undrained",
|
|
59
|
+
message: `${counts.steer} user steer(s) ${tail}`,
|
|
60
|
+
detail: { steer: counts.steer, ...tid },
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
if (counts.followUp > 0) {
|
|
64
|
+
out.push({
|
|
65
|
+
code: "task.user_followup_undrained",
|
|
66
|
+
message: `${counts.followUp} user follow-up(s) ${tail}`,
|
|
67
|
+
detail: { followUp: counts.followUp, ...tid },
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
return out;
|
|
71
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type ExecResult, type ExecutionEnv, ExecutionError, type ExecutionEnvExecOptions, FileError, type FileInfo, type Result } from "../harness/types.js";
|
|
2
|
+
import { type SecretEnvFinding } from "../../core/secret-env.js";
|
|
2
3
|
import type { BackgroundShellCapability, BackgroundShellId, BackgroundPoll, BackgroundSpawnOptions } from "../../core/background-shell.js";
|
|
3
4
|
import { BackgroundShellError } from "../../core/background-shell.js";
|
|
4
5
|
import type { SchedulerCapability, ScheduledIntent, SchedulerContext, ScheduledTaskId, ScheduledTaskSummary } from "../../core/scheduler.js";
|
|
@@ -18,6 +19,8 @@ export declare function getShellConfig(customShellPath?: string): Promise<Result
|
|
|
18
19
|
shell: string;
|
|
19
20
|
args: string[];
|
|
20
21
|
}, ExecutionError>>;
|
|
22
|
+
/** test seam (mirrors the notice-seat announce reset): the once-per-process fallback latches. */
|
|
23
|
+
export declare function __resetSecretScrubAnnouncement(): void;
|
|
21
24
|
/** RB-235 ([1937] BB2): the spool-reclaim decision, extracted PURE so every rule is unit-pinnable.
|
|
22
25
|
* Both reclaim sites (foreground `reclaimSpool`, background `syncSpool`) route through this one
|
|
23
26
|
* function so they cannot drift apart.
|
|
@@ -83,6 +86,7 @@ export declare class NodeExecutionEnv implements ExecutionEnv, BackgroundShellCa
|
|
|
83
86
|
private readonly bgShells;
|
|
84
87
|
private bgCounter;
|
|
85
88
|
private readonly retainBackgroundProcesses;
|
|
89
|
+
private readonly onSecretEnvScrub?;
|
|
86
90
|
/** design/128 T1-1: lazily-created env-owned spool dir (mkdtemp under os tmp — unpredictable, never the cwd). */
|
|
87
91
|
private bgSpoolDir?;
|
|
88
92
|
readonly backgroundCapabilities: BackgroundShellCapability["backgroundCapabilities"];
|
|
@@ -108,6 +112,10 @@ export declare class NodeExecutionEnv implements ExecutionEnv, BackgroundShellCa
|
|
|
108
112
|
* deployments (their pre-suspend dispose becomes a no-op too — do not combine).
|
|
109
113
|
*/
|
|
110
114
|
retainBackgroundProcesses?: boolean;
|
|
115
|
+
/** The D1 scrub decision's observation seat: called with every NON-EMPTY finding set the default
|
|
116
|
+
* "scrub" leg withholds from a shell child. Absent ⇒ a once-per-process console summary (loud
|
|
117
|
+
* enough to notice, quiet enough not to spam). Never called on the "all"/allowlist legs. */
|
|
118
|
+
onSecretEnvScrub?: (findings: readonly SecretEnvFinding[]) => void;
|
|
111
119
|
});
|
|
112
120
|
get schedulerCapabilities(): SchedulerCapability["schedulerCapabilities"];
|
|
113
121
|
schedule(intent: ScheduledIntent, ctx: SchedulerContext): Promise<Result<{
|
|
@@ -188,7 +188,13 @@ export async function getShellConfig(customShellPath) {
|
|
|
188
188
|
return ok({ shell: "sh", args: ["-c"] });
|
|
189
189
|
}
|
|
190
190
|
const EXEC_FORCE_SETTLE_GRACE_MS = 3000;
|
|
191
|
-
|
|
191
|
+
let secretScrubConsoleAnnounced = false;
|
|
192
|
+
let secretScrubSeatDefectAnnounced = false;
|
|
193
|
+
export function __resetSecretScrubAnnouncement() {
|
|
194
|
+
secretScrubConsoleAnnounced = false;
|
|
195
|
+
secretScrubSeatDefectAnnounced = false;
|
|
196
|
+
}
|
|
197
|
+
function getShellEnv(inheritEnv, baseEnv, extraEnv, onScrub) {
|
|
192
198
|
let inherited;
|
|
193
199
|
if (inheritEnv === "all") {
|
|
194
200
|
inherited = process.env;
|
|
@@ -200,7 +206,36 @@ function getShellEnv(inheritEnv, baseEnv, extraEnv) {
|
|
|
200
206
|
inherited[k] = process.env[k];
|
|
201
207
|
}
|
|
202
208
|
else {
|
|
203
|
-
|
|
209
|
+
const scrubbed = [];
|
|
210
|
+
inherited = scrubSecretEnv(process.env, scrubbed);
|
|
211
|
+
const findings = scrubbed.filter((f) => baseEnv?.[f.key] === undefined && extraEnv?.[f.key] === undefined);
|
|
212
|
+
if (findings.length > 0) {
|
|
213
|
+
if (typeof onScrub === "function") {
|
|
214
|
+
try {
|
|
215
|
+
const r = onScrub(findings);
|
|
216
|
+
if (typeof r?.then === "function") {
|
|
217
|
+
r.then(undefined, () => {
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
catch {
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
if (onScrub !== undefined && !secretScrubSeatDefectAnnounced) {
|
|
226
|
+
secretScrubSeatDefectAnnounced = true;
|
|
227
|
+
try {
|
|
228
|
+
console.warn(`onSecretEnvScrub seat holds ${onScrub === null ? "null" : typeof onScrub} — not a function; scrub findings fall back to the console summary (once per process)`);
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
if (!secretScrubConsoleAnnounced) {
|
|
234
|
+
secretScrubConsoleAnnounced = true;
|
|
235
|
+
console.warn(`secret_env_scrubbed: ${findings.length} env key(s) withheld from the shell child (${findings.map((f) => f.key).join(", ")}) — once per process; wire onSecretEnvScrub for per-exec telemetry`);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
204
239
|
}
|
|
205
240
|
return {
|
|
206
241
|
...inherited,
|
|
@@ -254,6 +289,7 @@ export class NodeExecutionEnv {
|
|
|
254
289
|
bgShells = new Map();
|
|
255
290
|
bgCounter = 0;
|
|
256
291
|
retainBackgroundProcesses;
|
|
292
|
+
onSecretEnvScrub;
|
|
257
293
|
bgSpoolDir;
|
|
258
294
|
backgroundCapabilities;
|
|
259
295
|
constructor(options) {
|
|
@@ -263,6 +299,7 @@ export class NodeExecutionEnv {
|
|
|
263
299
|
this.inheritEnv = options.inheritEnv ?? "scrub";
|
|
264
300
|
this.scheduler = options.scheduler;
|
|
265
301
|
this.retainBackgroundProcesses = options.retainBackgroundProcesses ?? false;
|
|
302
|
+
this.onSecretEnvScrub = options.onSecretEnvScrub;
|
|
266
303
|
this.backgroundCapabilities = {
|
|
267
304
|
supported: true,
|
|
268
305
|
maxConcurrent: 8,
|
|
@@ -420,7 +457,7 @@ export class NodeExecutionEnv {
|
|
|
420
457
|
child = spawn(shellConfig.value.shell, [...shellConfig.value.args, command], {
|
|
421
458
|
cwd,
|
|
422
459
|
detached: process.platform !== "win32",
|
|
423
|
-
env: getShellEnv(this.inheritEnv, this.shellEnv, options?.env),
|
|
460
|
+
env: getShellEnv(this.inheritEnv, this.shellEnv, options?.env, this.onSecretEnvScrub),
|
|
424
461
|
stdio: execSpoolFds ? ["ignore", execSpoolFds[0], execSpoolFds[1]] : ["ignore", "pipe", "pipe"],
|
|
425
462
|
windowsHide: true,
|
|
426
463
|
});
|
|
@@ -1114,7 +1151,7 @@ export class NodeExecutionEnv {
|
|
|
1114
1151
|
child = spawn(shellConfig.value.shell, [...shellConfig.value.args, command], {
|
|
1115
1152
|
cwd: options?.cwd ? resolvePath(this.cwd, options.cwd) : this.cwd,
|
|
1116
1153
|
detached: process.platform !== "win32",
|
|
1117
|
-
env: getShellEnv(this.inheritEnv, this.shellEnv, options?.env),
|
|
1154
|
+
env: getShellEnv(this.inheritEnv, this.shellEnv, options?.env, this.onSecretEnvScrub),
|
|
1118
1155
|
stdio: spoolFds ? ["ignore", spoolFds[0], spoolFds[1]] : ["ignore", "pipe", "pipe"],
|
|
1119
1156
|
windowsHide: true,
|
|
1120
1157
|
});
|
package/dist/index.d.ts
CHANGED
|
@@ -93,7 +93,7 @@ export { READ_FACE_DEFAULT_DENY_ENTRIES, READ_FACE_BUILTIN_DENY_TABLE, READ_DENY
|
|
|
93
93
|
export { deploymentReadFaceClampNotice, resolveReadFace, type ReadFace, type ReadFaceInputs } from "./tools/fs/index.js";
|
|
94
94
|
export { WRITE_PROTECTED_DEFAULT_TABLE, resolveWriteProtectedTable, compileWriteProtection, type WriteProtectedEntry, type WriteProtectedRow, type WriteProtectedKind, type WriteProtectedHit, type WriteProtectionMatcher, } from "./core/write-protect.js";
|
|
95
95
|
export { InMemoryToolResultStore, OFFLOAD_TOOL_NAME, DEFAULT_TOOL_RESULT_THRESHOLD_CHARS, assertSafeToolResultRef, buildToolResultRef, toolResultContentSegment, MAX_MINTED_TOOL_RESULT_REF_CHARS, type ToolResultProvenance, assertToolResultProvenanceMatch, normalizeToolResultProvenance, toolResultProvenanceOf, ToolResultRefConflictError, TOOL_RESULT_REF_CONFLICT_CODE, type ToolResultStore, type ToolResultSlice, type ToolResultDeletionReport, } from "./core/tool-result-store.js";
|
|
96
|
-
export { InMemoryCheckpointStore, CheckpointError, mintCheckpointToken, checkpointVersionOf, CURRENT_CHECKPOINT_VERSION, MAX_SUPPORTED_CHECKPOINT_VERSION, ORG_ADMISSION_CHECKPOINT_VERSION, F012_CHECKPOINT_VERSION, REAL_APPROVAL_CHECKPOINT_VERSION, RESOURCE_CHECKPOINT_VERSION, TOKEN_CHECKPOINT_VERSION, debitLedger, remainingBudgetMicroUsd, remainingTokens, winnerFromOutcome, validatePendingSteer, readPendingSteerQueue, appendPendingSteer, MAX_PENDING_STEER_CHARS, MAX_PENDING_STEER_ENTRIES, PENDING_STEER_QUEUE_BYTE_BUDGET_BYTES, PENDING_STEER_FROZEN_FIELDS, ACTOR_ASSERTION_FROZEN_FIELDS, MAX_ACTOR_FIELD_CHARS, MAX_STEER_INPUT_ID_CHARS, LEGACY_PENDING_STEER_INPUT_ID, type ActorAssertion, type PendingSteerEntry, type PendingSteerInput, riskSeverity, buildRiskDescriptor, summarizeCheckpoint, type RiskDescriptor, type ProbeCause, type ProbeCauseOperands, type CheckpointStore, type CheckpointSummary, type Checkpoint, type CheckpointToken, type CheckpointGate, type CheckpointState, type SerializedCheckpointState, type CheckpointFaultMode, type PendingAction, type ResumeOutcome, type ResolvedOutcome, type ReopenReason, type ResolveExpectation, type SafetyAxis, type RealApprovalGateBit, type ResourceLedger, type ResourceLimitReason, type PlatformLimitReason, } from "./core/checkpoint-store.js";
|
|
96
|
+
export { InMemoryCheckpointStore, CheckpointError, mintCheckpointId, mintCheckpointToken, checkpointVersionOf, CURRENT_CHECKPOINT_VERSION, MAX_SUPPORTED_CHECKPOINT_VERSION, ORG_ADMISSION_CHECKPOINT_VERSION, F012_CHECKPOINT_VERSION, REAL_APPROVAL_CHECKPOINT_VERSION, RESOURCE_CHECKPOINT_VERSION, TOKEN_CHECKPOINT_VERSION, debitLedger, remainingBudgetMicroUsd, remainingTokens, winnerFromOutcome, validatePendingSteer, readPendingSteerQueue, appendPendingSteer, MAX_PENDING_STEER_CHARS, MAX_PENDING_STEER_ENTRIES, PENDING_STEER_QUEUE_BYTE_BUDGET_BYTES, PENDING_STEER_FROZEN_FIELDS, ACTOR_ASSERTION_FROZEN_FIELDS, MAX_ACTOR_FIELD_CHARS, MAX_STEER_INPUT_ID_CHARS, LEGACY_PENDING_STEER_INPUT_ID, type ActorAssertion, type PendingSteerEntry, type PendingSteerInput, riskSeverity, buildRiskDescriptor, summarizeCheckpoint, type RiskDescriptor, type ProbeCause, type ProbeCauseOperands, type CheckpointStore, type CheckpointSummary, type Checkpoint, type CheckpointToken, type CheckpointGate, type CheckpointState, type SerializedCheckpointState, type CheckpointFaultMode, type PendingAction, type ResumeOutcome, type ResolvedOutcome, type ReopenReason, type ResolveExpectation, type SafetyAxis, type RealApprovalGateBit, type ResourceLedger, type ResourceLimitReason, type PlatformLimitReason, } from "./core/checkpoint-store.js";
|
|
97
97
|
export { InMemoryUsageWindowStore, GLOBAL_USAGE_KEY, EMPTY_USAGE_WINDOW_RECORD, chargeUsageRecord, readUsageRecord, usageRetryAfterMs, resolveUsageWindows, type UsageWindow, type UsageWindowStore, type UsageWindowReading, type UsageWindowRecord, type UsageSlot, type UsageBucketRow, } from "./core/usage-window-store.js";
|
|
98
98
|
export { FileUsageWindowStore } from "./stores/file/usage-window-store.js";
|
|
99
99
|
export { ENV_LIFETIME_SUSPEND_MARGIN_MS, USAGE_WINDOW_REAP_MARGIN_MS } from "./core/runner/prepare-task.js";
|
package/dist/index.js
CHANGED
|
@@ -73,7 +73,7 @@ export { READ_FACE_DEFAULT_DENY_ENTRIES, READ_FACE_BUILTIN_DENY_TABLE, READ_DENY
|
|
|
73
73
|
export { deploymentReadFaceClampNotice, resolveReadFace } from "./tools/fs/index.js";
|
|
74
74
|
export { WRITE_PROTECTED_DEFAULT_TABLE, resolveWriteProtectedTable, compileWriteProtection, } from "./core/write-protect.js";
|
|
75
75
|
export { InMemoryToolResultStore, OFFLOAD_TOOL_NAME, DEFAULT_TOOL_RESULT_THRESHOLD_CHARS, assertSafeToolResultRef, buildToolResultRef, toolResultContentSegment, MAX_MINTED_TOOL_RESULT_REF_CHARS, assertToolResultProvenanceMatch, normalizeToolResultProvenance, toolResultProvenanceOf, ToolResultRefConflictError, TOOL_RESULT_REF_CONFLICT_CODE, } from "./core/tool-result-store.js";
|
|
76
|
-
export { InMemoryCheckpointStore, CheckpointError, mintCheckpointToken, checkpointVersionOf, CURRENT_CHECKPOINT_VERSION, MAX_SUPPORTED_CHECKPOINT_VERSION, ORG_ADMISSION_CHECKPOINT_VERSION, F012_CHECKPOINT_VERSION, REAL_APPROVAL_CHECKPOINT_VERSION, RESOURCE_CHECKPOINT_VERSION, TOKEN_CHECKPOINT_VERSION, debitLedger, remainingBudgetMicroUsd, remainingTokens, winnerFromOutcome, validatePendingSteer, readPendingSteerQueue, appendPendingSteer, MAX_PENDING_STEER_CHARS, MAX_PENDING_STEER_ENTRIES, PENDING_STEER_QUEUE_BYTE_BUDGET_BYTES, PENDING_STEER_FROZEN_FIELDS, ACTOR_ASSERTION_FROZEN_FIELDS, MAX_ACTOR_FIELD_CHARS, MAX_STEER_INPUT_ID_CHARS, LEGACY_PENDING_STEER_INPUT_ID, riskSeverity, buildRiskDescriptor, summarizeCheckpoint, } from "./core/checkpoint-store.js";
|
|
76
|
+
export { InMemoryCheckpointStore, CheckpointError, mintCheckpointId, mintCheckpointToken, checkpointVersionOf, CURRENT_CHECKPOINT_VERSION, MAX_SUPPORTED_CHECKPOINT_VERSION, ORG_ADMISSION_CHECKPOINT_VERSION, F012_CHECKPOINT_VERSION, REAL_APPROVAL_CHECKPOINT_VERSION, RESOURCE_CHECKPOINT_VERSION, TOKEN_CHECKPOINT_VERSION, debitLedger, remainingBudgetMicroUsd, remainingTokens, winnerFromOutcome, validatePendingSteer, readPendingSteerQueue, appendPendingSteer, MAX_PENDING_STEER_CHARS, MAX_PENDING_STEER_ENTRIES, PENDING_STEER_QUEUE_BYTE_BUDGET_BYTES, PENDING_STEER_FROZEN_FIELDS, ACTOR_ASSERTION_FROZEN_FIELDS, MAX_ACTOR_FIELD_CHARS, MAX_STEER_INPUT_ID_CHARS, LEGACY_PENDING_STEER_INPUT_ID, riskSeverity, buildRiskDescriptor, summarizeCheckpoint, } from "./core/checkpoint-store.js";
|
|
77
77
|
export { InMemoryUsageWindowStore, GLOBAL_USAGE_KEY, EMPTY_USAGE_WINDOW_RECORD, chargeUsageRecord, readUsageRecord, usageRetryAfterMs, resolveUsageWindows, } from "./core/usage-window-store.js";
|
|
78
78
|
export { FileUsageWindowStore } from "./stores/file/usage-window-store.js";
|
|
79
79
|
export { ENV_LIFETIME_SUSPEND_MARGIN_MS, USAGE_WINDOW_REAP_MARGIN_MS } from "./core/runner/prepare-task.js";
|
|
@@ -2,6 +2,14 @@ import type { AgentTool, ExecutionEnv } from "../../internal/harness-types.js";
|
|
|
2
2
|
import type { ToolEffect } from "../../core/types.js";
|
|
3
3
|
import type { ReadDenyMatcher } from "./read-deny.js";
|
|
4
4
|
import type { ReadFace } from "./read-face.js";
|
|
5
|
+
/**
|
|
6
|
+
* The Grep card's details assembly, PURE over the engine text ({mode, offset} from the request) —
|
|
7
|
+
* exported so the text→structured mapping is pinnable with synthetic texts (the byte-truncation and
|
|
8
|
+
* fenced-partial shapes are impractical to construct through a live tool call). Follow-up #313 will
|
|
9
|
+
* replace the text parsing with structured rows from runGrep; until then this seam is the honesty
|
|
10
|
+
* boundary.
|
|
11
|
+
*/
|
|
12
|
+
export declare function grepDetailFields(text: string, mode: "files_with_matches" | "content" | "count", offset?: number, structuredRows?: readonly import("./search.js").GrepRow[]): Record<string, unknown>;
|
|
5
13
|
export declare function createGrepTool(env: ExecutionEnv, rootCanonical: string, additionalRoots?: readonly string[], readDeny?: ReadDenyMatcher, readFace?: ReadFace): AgentTool;
|
|
6
14
|
export declare function createGlobTool(env: ExecutionEnv, rootCanonical: string, additionalRoots?: readonly string[], readDeny?: ReadDenyMatcher, readFace?: ReadFace): AgentTool;
|
|
7
15
|
/** Static side-effect class of every hand tool, by name (design/44 §3). Used by prepare-task to (a) feed
|