@fitlab-ai/agent-infra 0.11.12 → 0.11.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/internal-cli.js +2 -7
- package/dist/lib/agent-clients/adapter.js +0 -3
- package/dist/lib/agent-clients/adapters/codex-lifecycle/app-server.js +5 -9
- package/dist/lib/agent-clients/adapters/codex-lifecycle/cli.js +1 -5
- package/dist/lib/agent-clients/adapters/codex-lifecycle/recovery.js +1 -5
- package/dist/lib/agent-clients/adapters/codex-lifecycle/store.js +11 -25
- package/dist/lib/agent-clients/adapters/codex-orchestration.js +1 -3
- package/dist/lib/agent-clients/adapters/codex.js +0 -2
- package/dist/lib/internal/cli-route-inventory.js +0 -1
- package/dist/lib/internal/sandbox-control.js +1 -81
- package/dist/lib/internal/task-finalization.js +29 -20
- package/dist/lib/internal/task-lifecycle.js +4 -2
- package/dist/lib/internal/task-operation-registry.js +1 -3
- package/dist/lib/internal/task-validate.js +14 -124
- package/dist/lib/platform/github-client.js +33 -3
- package/dist/lib/platform/release-notes.js +2 -2
- package/dist/lib/sandbox/commands/control-status.js +0 -1
- package/dist/lib/sandbox/commands/create.js +11 -6
- package/dist/lib/sandbox/commands/ls.js +4 -5
- package/dist/lib/sandbox/commands/rm.js +1 -1
- package/dist/lib/sandbox/config.js +12 -0
- package/dist/lib/sandbox/control/audit.js +1 -2
- package/dist/lib/sandbox/control/client.js +15 -110
- package/dist/lib/sandbox/control/executor.js +9 -59
- package/dist/lib/sandbox/control/host-recovery.js +89 -27
- package/dist/lib/sandbox/control/lifecycle.js +75 -9
- package/dist/lib/sandbox/control/protocol.js +11 -50
- package/dist/lib/sandbox/control/server.js +203 -253
- package/dist/lib/sandbox/control/task-view.js +0 -13
- package/dist/lib/sandbox/environment.js +7 -8
- package/dist/lib/sandbox/mounts.js +71 -52
- package/dist/lib/sandbox/recovery.js +30 -12
- package/dist/lib/sandbox/removal.js +37 -3
- package/dist/lib/sandbox/workspace-identity.js +18 -6
- package/dist/lib/sandbox/workspace-view.js +89 -6
- package/dist/lib/task/commands/ls.js +3 -3
- package/dist/lib/task/control-authority.js +41 -17
- package/dist/lib/task/control-recovery.js +2 -4
- package/dist/lib/task/finalization.js +27 -2
- package/dist/lib/task/lifecycle.js +294 -63
- package/dist/lib/task/orchestration.js +26 -72
- package/dist/lib/task/short-id.js +37 -27
- package/dist/lib/task/verification-engine.js +4 -11
- package/dist/lifecycle-build-manifest.json +3 -3
- package/lib/agent-clients/adapter.ts +0 -27
- package/lib/agent-clients/adapters/codex-lifecycle/app-server.ts +6 -12
- package/lib/agent-clients/adapters/codex-lifecycle/cli.ts +1 -5
- package/lib/agent-clients/adapters/codex-lifecycle/manifest-files.json +0 -7
- package/lib/agent-clients/adapters/codex-lifecycle/recovery.ts +1 -5
- package/lib/agent-clients/adapters/codex-lifecycle/store.ts +21 -27
- package/lib/agent-clients/adapters/codex-orchestration.ts +1 -3
- package/lib/agent-clients/adapters/codex.ts +0 -2
- package/lib/internal/cli-route-inventory.ts +0 -1
- package/lib/internal/sandbox-control.ts +0 -97
- package/lib/internal/task-finalization.ts +33 -19
- package/lib/internal/task-lifecycle.ts +4 -2
- package/lib/internal/task-operation-registry.ts +1 -3
- package/lib/internal/task-validate.ts +13 -127
- package/lib/platform/github-client.ts +34 -3
- package/lib/platform/release-notes.ts +2 -2
- package/lib/sandbox/commands/control-status.ts +0 -1
- package/lib/sandbox/commands/create.ts +11 -5
- package/lib/sandbox/commands/ls.ts +4 -5
- package/lib/sandbox/commands/rm.ts +1 -1
- package/lib/sandbox/config.ts +13 -0
- package/lib/sandbox/control/audit.ts +1 -2
- package/lib/sandbox/control/client.ts +17 -138
- package/lib/sandbox/control/executor.ts +8 -65
- package/lib/sandbox/control/host-recovery.ts +94 -21
- package/lib/sandbox/control/lifecycle.ts +75 -10
- package/lib/sandbox/control/protocol.ts +12 -62
- package/lib/sandbox/control/server.ts +11 -61
- package/lib/sandbox/control/task-view.ts +0 -19
- package/lib/sandbox/environment.ts +7 -8
- package/lib/sandbox/mounts.ts +93 -68
- package/lib/sandbox/recovery.ts +37 -19
- package/lib/sandbox/removal.ts +36 -5
- package/lib/sandbox/workspace-identity.ts +16 -6
- package/lib/sandbox/workspace-view.ts +81 -7
- package/lib/task/commands/ls.ts +3 -3
- package/lib/task/control-authority.ts +41 -26
- package/lib/task/control-recovery.ts +3 -5
- package/lib/task/finalization.ts +29 -2
- package/lib/task/lifecycle.ts +282 -57
- package/lib/task/orchestration.ts +30 -68
- package/lib/task/short-id.ts +33 -40
- package/lib/task/verification-engine.ts +3 -9
- package/package.json +1 -1
- package/templates/.agents/rules/README.en.md +1 -0
- package/templates/.agents/rules/README.zh-CN.md +1 -0
- package/templates/.agents/rules/lifecycle-orchestration.en.md +3 -4
- package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +3 -4
- package/templates/.agents/rules/strategy-pattern.en.md +25 -0
- package/templates/.agents/rules/strategy-pattern.zh-CN.md +25 -0
- package/templates/.agents/rules/task-short-id.en.md +18 -12
- package/templates/.agents/rules/task-short-id.zh-CN.md +12 -7
- package/templates/.agents/skills/code-task/reference/code-rules.en.md +4 -0
- package/templates/.agents/skills/code-task/reference/code-rules.zh-CN.md +4 -0
- package/templates/.agents/skills/complete-task/SKILL.en.md +5 -26
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +5 -23
- package/templates/.agents/skills/create-release-note/SKILL.en.md +3 -1
- package/templates/.agents/skills/create-release-note/SKILL.zh-CN.md +3 -1
- package/templates/.agents/skills/plan-task/SKILL.en.md +7 -4
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +7 -4
- package/templates/.agents/skills/run-task/SKILL.en.md +2 -2
- package/templates/.agents/skills/run-task/SKILL.zh-CN.md +2 -2
- package/dist/lib/agent-clients/adapters/codex-lifecycle/controller-client.js +0 -130
- package/dist/lib/agent-clients/adapters/codex-lifecycle/controller-context.js +0 -127
- package/dist/lib/agent-clients/adapters/codex-lifecycle/controller-operation.js +0 -131
- package/dist/lib/agent-clients/adapters/codex-lifecycle/controller-registration.js +0 -275
- package/dist/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller-cli.js +0 -106
- package/dist/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.js +0 -345
- package/dist/lib/sandbox/control/agent-operation.js +0 -34
- package/lib/agent-clients/adapters/codex-lifecycle/controller-client.ts +0 -158
- package/lib/agent-clients/adapters/codex-lifecycle/controller-context.ts +0 -163
- package/lib/agent-clients/adapters/codex-lifecycle/controller-operation.ts +0 -151
- package/lib/agent-clients/adapters/codex-lifecycle/controller-registration.ts +0 -352
- package/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller-cli.ts +0 -109
- package/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.ts +0 -437
- package/lib/sandbox/control/agent-operation.ts +0 -49
|
@@ -18,49 +18,15 @@ import { inspectSandboxControlContainer } from './container-identity.js';
|
|
|
18
18
|
import { acquireSandboxControlBrokerStartup, garbageCollectSandboxControlRoot, isSandboxControlRootQuiescing, readSandboxControlManifest } from './lifecycle.js';
|
|
19
19
|
import { nextSandboxControlBackoff } from './timing.js';
|
|
20
20
|
import { readTaskFinalizationReceipt } from '../../task/finalization.js';
|
|
21
|
-
import { recoverAgentClientOperation, validateAgentClientOperation } from './agent-operation.js';
|
|
22
21
|
import { validateSandboxControlIdentity } from './identity-sentinel.js';
|
|
23
|
-
import { mergeSandboxTaskView,
|
|
22
|
+
import { mergeSandboxTaskView, taskViewForManifest } from './task-view.js';
|
|
24
23
|
import { taskCreateOutputUnavailableResult } from '../../task/create-service.js';
|
|
25
|
-
async function taskViewForFinalizationResult(manifest, request, result) {
|
|
26
|
-
if (request.family !== 'task-finalization' || result?.exitCode !== 0 || !manifest.taskId)
|
|
27
|
-
return null;
|
|
28
|
-
let receipt = null;
|
|
29
|
-
for (let attempt = 0; attempt < 100 && !receipt; attempt += 1) {
|
|
30
|
-
try {
|
|
31
|
-
receipt = readTaskFinalizationReceipt(manifest.repoRoot, manifest.taskId);
|
|
32
|
-
}
|
|
33
|
-
catch {
|
|
34
|
-
// A missing or temporarily moving task directory is retried before publishing completion.
|
|
35
|
-
}
|
|
36
|
-
if (!receipt)
|
|
37
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
38
|
-
}
|
|
39
|
-
const finalized = taskViewAfterFinalization({
|
|
40
|
-
taskId: manifest.taskId,
|
|
41
|
-
generation: manifest.generation,
|
|
42
|
-
requestId: request.id,
|
|
43
|
-
receipt
|
|
44
|
-
});
|
|
45
|
-
if (finalized.state === 'unknown')
|
|
46
|
-
return finalized;
|
|
47
|
-
const canonical = taskViewForManifest({ ...manifest, receipt });
|
|
48
|
-
return canonical.state === 'current' && canonical.observedSource === 'completed'
|
|
49
|
-
? canonical
|
|
50
|
-
: finalized;
|
|
51
|
-
}
|
|
52
24
|
function appendBrokerAudit(manifest, event, fields = {}) {
|
|
53
25
|
appendDiagnosticAudit(manifest, event, { source: 'broker', ...fields });
|
|
54
26
|
}
|
|
55
27
|
function operationKey(request) {
|
|
56
|
-
if (request.family === 'task-finalization')
|
|
57
|
-
return request.operation;
|
|
58
28
|
if (request.family === 'task-create')
|
|
59
29
|
return 'create';
|
|
60
|
-
if (request.family === 'agent-client')
|
|
61
|
-
return request.operation;
|
|
62
|
-
if (request.family !== 'task-lifecycle')
|
|
63
|
-
return null;
|
|
64
30
|
try {
|
|
65
31
|
const operation = parseTaskControlOperation(request.family, request.args);
|
|
66
32
|
return operation.family === 'task-lifecycle' ? operation.request.intent : null;
|
|
@@ -220,11 +186,9 @@ function taskCreateDomainEvidence(manifest, output) {
|
|
|
220
186
|
async function readRecoveryDomain(manifest, manifestPath, request, operation, terminalResult, payloadOutput) {
|
|
221
187
|
if (!operation)
|
|
222
188
|
return { domain: null };
|
|
223
|
-
const taskRef = request.
|
|
224
|
-
? manifest.taskId
|
|
225
|
-
: 'args' in request ? request.args[0] ?? null : manifest.taskId;
|
|
189
|
+
const taskRef = 'args' in request ? request.args[0] ?? null : manifest.taskId;
|
|
226
190
|
const output = parseControlOutput(payloadOutput);
|
|
227
|
-
if (!taskRef && operation.family !== 'task-create'
|
|
191
|
+
if (!taskRef && operation.family !== 'task-create') {
|
|
228
192
|
return { domain: null };
|
|
229
193
|
}
|
|
230
194
|
if (operation.family === 'task-lifecycle') {
|
|
@@ -252,14 +216,6 @@ async function readRecoveryDomain(manifest, manifestPath, request, operation, te
|
|
|
252
216
|
if (operation.family === 'task-create') {
|
|
253
217
|
return { domain: taskCreateDomainEvidence(manifest, output) };
|
|
254
218
|
}
|
|
255
|
-
if (operation.family === 'agent-client' && request.family === 'agent-client') {
|
|
256
|
-
return { domain: recoverAgentClientOperation({
|
|
257
|
-
request,
|
|
258
|
-
manifest,
|
|
259
|
-
manifestPath,
|
|
260
|
-
stdout: payloadOutput
|
|
261
|
-
}) };
|
|
262
|
-
}
|
|
263
219
|
return { domain: null };
|
|
264
220
|
}
|
|
265
221
|
function readCommittedCriticalPhases(manifest, requestId) {
|
|
@@ -474,11 +430,7 @@ async function recoverProcessing(manifest, manifestPath, broker, brokerOwns) {
|
|
|
474
430
|
let terminalReconciled = false;
|
|
475
431
|
try {
|
|
476
432
|
const rawRequest = JSON.parse(fs.readFileSync(path.join(processingDirectory, 'request.json'), 'utf8'));
|
|
477
|
-
request = validateSandboxControlRequest(rawRequest, manifest
|
|
478
|
-
now: typeof rawRequest.issuedAt === 'number' ? rawRequest.issuedAt : undefined
|
|
479
|
-
});
|
|
480
|
-
if (request.family === 'agent-client')
|
|
481
|
-
validateAgentClientOperation(request, manifest);
|
|
433
|
+
request = validateSandboxControlRequest(rawRequest, manifest);
|
|
482
434
|
}
|
|
483
435
|
catch {
|
|
484
436
|
// Missing or malformed request evidence remains fail-closed below.
|
|
@@ -730,6 +682,8 @@ export async function serveSandboxControl(manifestPath, signal = new AbortContro
|
|
|
730
682
|
try {
|
|
731
683
|
if (!brokerOwns())
|
|
732
684
|
return;
|
|
685
|
+
if (isSandboxControlRootQuiescing(root))
|
|
686
|
+
return;
|
|
733
687
|
if (taskView.state === 'current' && taskView.observedSource === 'completed') {
|
|
734
688
|
// Recheck durable re-entry evidence before publishing a trusted startup view.
|
|
735
689
|
const unverified = { ...taskView, state: 'unknown',
|
|
@@ -836,11 +790,6 @@ export async function serveSandboxControl(manifestPath, signal = new AbortContro
|
|
|
836
790
|
settledExecution = active;
|
|
837
791
|
active = null;
|
|
838
792
|
}
|
|
839
|
-
const finalizationView = settledExecution
|
|
840
|
-
? await taskViewForFinalizationResult(manifest, settledExecution.request, settledExecution.result)
|
|
841
|
-
: null;
|
|
842
|
-
if (finalizationView)
|
|
843
|
-
taskView = finalizationView;
|
|
844
793
|
let reasonCode = null;
|
|
845
794
|
try {
|
|
846
795
|
if (!brokerOwns())
|
|
@@ -918,224 +867,230 @@ export async function serveSandboxControl(manifestPath, signal = new AbortContro
|
|
|
918
867
|
fs.rmSync(path.join(manifest.processingDir, settledExecution.request.id), { recursive: true, force: true });
|
|
919
868
|
}
|
|
920
869
|
let retiring = false;
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
const
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
executionPath: executionPath(manifest, request.id)
|
|
1003
|
-
});
|
|
1004
|
-
const execution = {
|
|
1005
|
-
request, prepared: preparedExecution, result: null,
|
|
1006
|
-
resultEvidenceWritten: false, failure: null, settled: false
|
|
1007
|
-
};
|
|
1008
|
-
active = execution;
|
|
1009
|
-
preparedExecution.completion.then((result) => {
|
|
1010
|
-
execution.result = sanitizeSandboxControlResult(manifest, result);
|
|
1011
|
-
appendBrokerAudit(manifest, 'executor-completed', {
|
|
870
|
+
const quiescing = isSandboxControlRootQuiescing(root);
|
|
871
|
+
if (quiescing && !active)
|
|
872
|
+
break;
|
|
873
|
+
if (!quiescing)
|
|
874
|
+
for (const name of fs.readdirSync(requestsDir).sort()) {
|
|
875
|
+
if (!/^[a-f0-9-]{16,64}\.json$/.test(name))
|
|
876
|
+
continue;
|
|
877
|
+
const id = name.slice(0, -5);
|
|
878
|
+
const source = path.join(requestsDir, name);
|
|
879
|
+
let claimed = null;
|
|
880
|
+
let validatedRequest = null;
|
|
881
|
+
let prepared = null;
|
|
882
|
+
try {
|
|
883
|
+
if (isSandboxControlRootQuiescing(root)) {
|
|
884
|
+
retiring = true;
|
|
885
|
+
break;
|
|
886
|
+
}
|
|
887
|
+
if (!brokerOwns()) {
|
|
888
|
+
retiring = true;
|
|
889
|
+
break;
|
|
890
|
+
}
|
|
891
|
+
claimed = claimRequest(manifest, source, id);
|
|
892
|
+
appendBrokerAudit(manifest, 'request-claimed', {
|
|
893
|
+
requestId: id,
|
|
894
|
+
requestSourcePath: source,
|
|
895
|
+
requestClaimedPath: claimed,
|
|
896
|
+
requestProcessingDir: path.dirname(claimed)
|
|
897
|
+
});
|
|
898
|
+
if (!brokerOwns()) {
|
|
899
|
+
retiring = true;
|
|
900
|
+
break;
|
|
901
|
+
}
|
|
902
|
+
consumeRequest(consumedDir, id);
|
|
903
|
+
if (!brokerOwns()) {
|
|
904
|
+
retiring = true;
|
|
905
|
+
break;
|
|
906
|
+
}
|
|
907
|
+
if (reasonCode)
|
|
908
|
+
throw new Error(reasonCode);
|
|
909
|
+
if (active)
|
|
910
|
+
throw new Error('SANDBOX_CONTROL_BUSY');
|
|
911
|
+
const request = validateSandboxControlRequest(JSON.parse(fs.readFileSync(claimed, 'utf8')), manifest);
|
|
912
|
+
validatedRequest = request;
|
|
913
|
+
criticalRequestPhase(manifest, request, 'validated', 'in-progress');
|
|
914
|
+
appendBrokerAudit(manifest, 'request-validated', {
|
|
915
|
+
...requestAuditFields(manifest, request),
|
|
916
|
+
requestPath: claimed
|
|
917
|
+
});
|
|
918
|
+
if (bindingCheck(manifest))
|
|
919
|
+
throw new Error('SANDBOX_WORKTREE_BINDING_LOST');
|
|
920
|
+
if (readActiveLease(manifest))
|
|
921
|
+
throw new Error('SANDBOX_CONTROL_HANDOFF_ACTIVE');
|
|
922
|
+
criticalRequestPhase(manifest, request, 'gated', 'in-progress');
|
|
923
|
+
appendBrokerAudit(manifest, 'request-gates-passed', {
|
|
924
|
+
...requestAuditFields(manifest, request),
|
|
925
|
+
requestPath: claimed,
|
|
926
|
+
bindingChecked: true,
|
|
927
|
+
handoffLeaseChecked: true
|
|
928
|
+
});
|
|
929
|
+
criticalRequestPhase(manifest, request, 'reserved', 'in-progress');
|
|
930
|
+
writeSandboxControlReservation(manifest, request.id, sandboxControlGenerationUsage(manifest));
|
|
931
|
+
appendBrokerAudit(manifest, 'executor-reservation-written', {
|
|
932
|
+
...requestAuditFields(manifest, request),
|
|
933
|
+
requestPath: claimed,
|
|
934
|
+
executionPath: executionPath(manifest, request.id)
|
|
935
|
+
});
|
|
936
|
+
appendBrokerAudit(manifest, 'executor-prepare-start', {
|
|
937
|
+
...requestAuditFields(manifest, request),
|
|
938
|
+
requestPath: claimed,
|
|
939
|
+
executorCwd: manifest.repoRoot,
|
|
940
|
+
executorEntry: options.internalCliPath ?? process.argv[1] ?? null
|
|
941
|
+
});
|
|
942
|
+
prepared = await prepareExecution({
|
|
943
|
+
manifest, manifestPath, request, requestPath: claimed,
|
|
944
|
+
internalCliPath: options.internalCliPath ?? process.argv[1]
|
|
945
|
+
});
|
|
946
|
+
const preparedExecution = prepared;
|
|
947
|
+
if (!preparedExecution)
|
|
948
|
+
throw new Error('SANDBOX_CONTROL_EXECUTION_PREPARE_INVALID');
|
|
949
|
+
criticalRequestPhase(manifest, request, 'prepared', 'in-progress', `${preparedExecution.execution.child.pid}`);
|
|
950
|
+
appendBrokerAudit(manifest, 'executor-prepared', {
|
|
1012
951
|
...requestAuditFields(manifest, request),
|
|
1013
|
-
|
|
952
|
+
requestPath: claimed,
|
|
953
|
+
executorCwd: manifest.repoRoot,
|
|
1014
954
|
childPid: preparedExecution.execution.child.pid,
|
|
1015
|
-
childStartTime: preparedExecution.execution.child.startTime
|
|
955
|
+
childStartTime: preparedExecution.execution.child.startTime,
|
|
956
|
+
childProcessGroupId: preparedExecution.execution.child.processGroupId,
|
|
957
|
+
executionPath: executionPath(manifest, request.id)
|
|
1016
958
|
});
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
959
|
+
const execution = {
|
|
960
|
+
request, prepared: preparedExecution, result: null,
|
|
961
|
+
resultEvidenceWritten: false, failure: null, settled: false
|
|
962
|
+
};
|
|
963
|
+
active = execution;
|
|
964
|
+
preparedExecution.completion.then((result) => {
|
|
965
|
+
execution.result = sanitizeSandboxControlResult(manifest, result);
|
|
966
|
+
appendBrokerAudit(manifest, 'executor-completed', {
|
|
1022
967
|
...requestAuditFields(manifest, request),
|
|
1023
|
-
|
|
1024
|
-
|
|
968
|
+
...resultAuditFields(execution.result),
|
|
969
|
+
childPid: preparedExecution.execution.child.pid,
|
|
970
|
+
childStartTime: preparedExecution.execution.child.startTime
|
|
1025
971
|
});
|
|
1026
|
-
|
|
1027
|
-
|
|
972
|
+
try {
|
|
973
|
+
writeSandboxControlResultEvidence(manifest, request.id, execution.result);
|
|
974
|
+
execution.resultEvidenceWritten = true;
|
|
975
|
+
execution.settled = true;
|
|
976
|
+
appendBrokerAudit(manifest, 'executor-result-evidence-written', {
|
|
977
|
+
...requestAuditFields(manifest, request),
|
|
978
|
+
resultPath: path.join(manifest.processingDir, request.id, 'result.json'),
|
|
979
|
+
...resultAuditFields(execution.result)
|
|
980
|
+
});
|
|
981
|
+
}
|
|
982
|
+
catch (error) {
|
|
983
|
+
execution.failure = error;
|
|
984
|
+
appendBrokerAudit(manifest, 'executor-result-evidence-failed', {
|
|
985
|
+
...requestAuditFields(manifest, request),
|
|
986
|
+
errorType: error instanceof Error ? error.name : typeof error,
|
|
987
|
+
});
|
|
988
|
+
}
|
|
989
|
+
}, (error) => {
|
|
1028
990
|
execution.failure = error;
|
|
1029
|
-
|
|
991
|
+
execution.settled = true;
|
|
992
|
+
appendBrokerAudit(manifest, 'executor-failed', {
|
|
1030
993
|
...requestAuditFields(manifest, request),
|
|
994
|
+
childPid: preparedExecution.execution.child.pid,
|
|
995
|
+
childStartTime: preparedExecution.execution.child.startTime,
|
|
1031
996
|
errorType: error instanceof Error ? error.name : typeof error,
|
|
1032
997
|
});
|
|
1033
|
-
}
|
|
1034
|
-
}, (error) => {
|
|
1035
|
-
execution.failure = error;
|
|
1036
|
-
execution.settled = true;
|
|
1037
|
-
appendBrokerAudit(manifest, 'executor-failed', {
|
|
1038
|
-
...requestAuditFields(manifest, request),
|
|
1039
|
-
childPid: preparedExecution.execution.child.pid,
|
|
1040
|
-
childStartTime: preparedExecution.execution.child.startTime,
|
|
1041
|
-
errorType: error instanceof Error ? error.name : typeof error,
|
|
1042
998
|
});
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
version: 2, id, phase: 'accepted', exitCode: null, stdout: '', stderr: '', error: null
|
|
1053
|
-
});
|
|
1054
|
-
writeSandboxControlTransition(manifest, { requestId: request.id, phase: 'accepted-committed' });
|
|
1055
|
-
appendBrokerAudit(manifest, 'request-accepted', {
|
|
1056
|
-
...requestAuditFields(manifest, request),
|
|
1057
|
-
acceptedPath: acceptedResponsePath(manifest, id),
|
|
1058
|
-
executionPhase: 'prepared'
|
|
1059
|
-
});
|
|
1060
|
-
if (!brokerOwns()) {
|
|
1061
|
-
prepared.terminate(false);
|
|
1062
|
-
active = null;
|
|
1063
|
-
retiring = true;
|
|
1064
|
-
break;
|
|
1065
|
-
}
|
|
1066
|
-
try {
|
|
1067
|
-
criticalRequestPhase(manifest, request, 'start-authorized', 'in-progress', `${prepared.execution.child.pid}`);
|
|
1068
|
-
appendBrokerAudit(manifest, 'executor-start', {
|
|
1069
|
-
...requestAuditFields(manifest, request),
|
|
1070
|
-
childPid: prepared.execution.child.pid,
|
|
1071
|
-
childStartTime: prepared.execution.child.startTime,
|
|
1072
|
-
executionPath: executionPath(manifest, request.id)
|
|
999
|
+
if (!brokerOwns()) {
|
|
1000
|
+
prepared.terminate(false);
|
|
1001
|
+
active = null;
|
|
1002
|
+
retiring = true;
|
|
1003
|
+
continue;
|
|
1004
|
+
}
|
|
1005
|
+
criticalRequestPhase(manifest, request, 'accepted-authorized', 'in-progress');
|
|
1006
|
+
writeAcceptedResponse(manifest, {
|
|
1007
|
+
version: 2, id, phase: 'accepted', exitCode: null, stdout: '', stderr: '', error: null
|
|
1073
1008
|
});
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
catch (error) {
|
|
1077
|
-
appendBrokerAudit(manifest, 'executor-start-failed', {
|
|
1009
|
+
writeSandboxControlTransition(manifest, { requestId: request.id, phase: 'accepted-committed' });
|
|
1010
|
+
appendBrokerAudit(manifest, 'request-accepted', {
|
|
1078
1011
|
...requestAuditFields(manifest, request),
|
|
1079
|
-
|
|
1012
|
+
acceptedPath: acceptedResponsePath(manifest, id),
|
|
1013
|
+
executionPhase: 'prepared'
|
|
1080
1014
|
});
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
if (!owned || !brokerOwns()) {
|
|
1015
|
+
if (!brokerOwns()) {
|
|
1016
|
+
prepared.terminate(false);
|
|
1084
1017
|
active = null;
|
|
1085
1018
|
retiring = true;
|
|
1086
1019
|
break;
|
|
1087
1020
|
}
|
|
1088
|
-
|
|
1089
|
-
|
|
1021
|
+
try {
|
|
1022
|
+
criticalRequestPhase(manifest, request, 'start-authorized', 'in-progress', `${prepared.execution.child.pid}`);
|
|
1023
|
+
appendBrokerAudit(manifest, 'executor-start', {
|
|
1024
|
+
...requestAuditFields(manifest, request),
|
|
1025
|
+
childPid: prepared.execution.child.pid,
|
|
1026
|
+
childStartTime: prepared.execution.child.startTime,
|
|
1027
|
+
executionPath: executionPath(manifest, request.id)
|
|
1028
|
+
});
|
|
1029
|
+
prepared.start(brokerOwns);
|
|
1030
|
+
}
|
|
1031
|
+
catch (error) {
|
|
1032
|
+
appendBrokerAudit(manifest, 'executor-start-failed', {
|
|
1033
|
+
...requestAuditFields(manifest, request),
|
|
1034
|
+
errorType: error instanceof Error ? error.name : typeof error,
|
|
1035
|
+
});
|
|
1036
|
+
const owned = brokerOwns();
|
|
1037
|
+
prepared.terminate(owned);
|
|
1038
|
+
if (!owned || !brokerOwns()) {
|
|
1039
|
+
active = null;
|
|
1040
|
+
retiring = true;
|
|
1041
|
+
break;
|
|
1042
|
+
}
|
|
1043
|
+
writeSandboxControlResponse(manifest, unknown(id));
|
|
1044
|
+
if (!brokerOwns()) {
|
|
1045
|
+
active = null;
|
|
1046
|
+
retiring = true;
|
|
1047
|
+
break;
|
|
1048
|
+
}
|
|
1049
|
+
removeAcceptedResponse(manifest, id);
|
|
1050
|
+
fs.rmSync(path.join(manifest.processingDir, id), { recursive: true, force: true });
|
|
1051
|
+
active = null;
|
|
1052
|
+
claimed = null;
|
|
1053
|
+
if (!brokerOwns()) {
|
|
1054
|
+
retiring = true;
|
|
1055
|
+
break;
|
|
1056
|
+
}
|
|
1057
|
+
appendBrokerAudit(manifest, 'executor-gate-failed', { requestId: id });
|
|
1058
|
+
continue;
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
catch (error) {
|
|
1062
|
+
if (prepared) {
|
|
1063
|
+
try {
|
|
1064
|
+
prepared.terminate(brokerOwns());
|
|
1065
|
+
}
|
|
1066
|
+
catch { /* cleanup is best effort after a failed admission */ }
|
|
1067
|
+
prepared = null;
|
|
1090
1068
|
active = null;
|
|
1069
|
+
}
|
|
1070
|
+
if (!brokerOwns()) {
|
|
1091
1071
|
retiring = true;
|
|
1092
1072
|
break;
|
|
1093
1073
|
}
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1074
|
+
const detail = controlError(error);
|
|
1075
|
+
appendBrokerAudit(manifest, 'request-rejected', {
|
|
1076
|
+
requestId: id,
|
|
1077
|
+
requestFamily: validatedRequest?.family ?? null,
|
|
1078
|
+
sandboxTaskId: manifest.taskId,
|
|
1079
|
+
requestPath: claimed,
|
|
1080
|
+
errorCode: detail.code,
|
|
1081
|
+
errorRetryable: detail.retryable,
|
|
1082
|
+
errorType: error instanceof Error ? error.name : typeof error,
|
|
1083
|
+
});
|
|
1084
|
+
writeSandboxControlResponse(manifest, rejected(id, error));
|
|
1098
1085
|
if (!brokerOwns()) {
|
|
1099
1086
|
retiring = true;
|
|
1100
1087
|
break;
|
|
1101
1088
|
}
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
}
|
|
1106
|
-
catch (error) {
|
|
1107
|
-
if (prepared) {
|
|
1108
|
-
try {
|
|
1109
|
-
prepared.terminate(brokerOwns());
|
|
1110
|
-
}
|
|
1111
|
-
catch { /* cleanup is best effort after a failed admission */ }
|
|
1112
|
-
prepared = null;
|
|
1113
|
-
active = null;
|
|
1114
|
-
}
|
|
1115
|
-
if (!brokerOwns()) {
|
|
1116
|
-
retiring = true;
|
|
1117
|
-
break;
|
|
1118
|
-
}
|
|
1119
|
-
const detail = controlError(error);
|
|
1120
|
-
appendBrokerAudit(manifest, 'request-rejected', {
|
|
1121
|
-
requestId: id,
|
|
1122
|
-
requestFamily: validatedRequest?.family ?? null,
|
|
1123
|
-
sandboxTaskId: manifest.taskId,
|
|
1124
|
-
requestPath: claimed,
|
|
1125
|
-
errorCode: detail.code,
|
|
1126
|
-
errorRetryable: detail.retryable,
|
|
1127
|
-
errorType: error instanceof Error ? error.name : typeof error,
|
|
1128
|
-
});
|
|
1129
|
-
writeSandboxControlResponse(manifest, rejected(id, error));
|
|
1130
|
-
if (!brokerOwns()) {
|
|
1131
|
-
retiring = true;
|
|
1132
|
-
break;
|
|
1089
|
+
removeAcceptedResponse(manifest, id);
|
|
1090
|
+
if (claimed)
|
|
1091
|
+
fs.rmSync(path.dirname(claimed), { recursive: true, force: true });
|
|
1133
1092
|
}
|
|
1134
|
-
removeAcceptedResponse(manifest, id);
|
|
1135
|
-
if (claimed)
|
|
1136
|
-
fs.rmSync(path.dirname(claimed), { recursive: true, force: true });
|
|
1137
1093
|
}
|
|
1138
|
-
}
|
|
1139
1094
|
if (retiring || !brokerOwns())
|
|
1140
1095
|
break;
|
|
1141
1096
|
await delay(timing.controlTickMs);
|
|
@@ -1157,11 +1112,6 @@ export async function serveSandboxControl(manifestPath, signal = new AbortContro
|
|
|
1157
1112
|
}
|
|
1158
1113
|
}
|
|
1159
1114
|
if (owned && active.result && active.resultEvidenceWritten) {
|
|
1160
|
-
const finalizationView = await taskViewForFinalizationResult(manifest, active.request, active.result);
|
|
1161
|
-
if (finalizationView) {
|
|
1162
|
-
taskView = finalizationView;
|
|
1163
|
-
writeSandboxControlStatus(manifest, broker, 'healthy', null, null, Date.now(), taskView);
|
|
1164
|
-
}
|
|
1165
1115
|
if (publishExecutionResult(manifest, active.request, active.result, brokerOwns)) {
|
|
1166
1116
|
if (brokerOwns()) {
|
|
1167
1117
|
removeAcceptedResponse(manifest, active.request.id);
|
|
@@ -130,19 +130,6 @@ export function projectSandboxTaskView(input) {
|
|
|
130
130
|
reasonCode: receipt ? 'SANDBOX_TASK_VIEW_SOURCE_UNCONFIRMED' : 'SANDBOX_TASK_VIEW_EVIDENCE_UNAVAILABLE'
|
|
131
131
|
};
|
|
132
132
|
}
|
|
133
|
-
export function taskViewAfterFinalization(params) {
|
|
134
|
-
const receipt = receiptIdentity(params.receipt, params.generation, params.requestId);
|
|
135
|
-
if (!receipt) {
|
|
136
|
-
return {
|
|
137
|
-
state: 'unknown', taskId: params.taskId, observedSource: 'unknown', receipt: null,
|
|
138
|
-
reasonCode: 'SANDBOX_TASK_VIEW_RECEIPT_INVALID'
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
return {
|
|
142
|
-
state: 'finalized-stale', taskId: params.taskId, observedSource: 'active', receipt,
|
|
143
|
-
reasonCode: 'SANDBOX_TASK_VIEW_FINALIZED'
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
133
|
export function mergeSandboxTaskView(canonical, previous) {
|
|
147
134
|
if (previous.state !== 'finalized-stale' && previous.state !== 'unknown')
|
|
148
135
|
return canonical;
|
|
@@ -5,14 +5,13 @@ export const SANDBOX_CONTROL_STATUS_MOUNT = '/run/agent-infra/control-status';
|
|
|
5
5
|
const TASK_MARKER_KEYS = [
|
|
6
6
|
'AGENT_INFRA_SANDBOX',
|
|
7
7
|
'AGENT_INFRA_TASK_ID',
|
|
8
|
-
'AGENT_INFRA_CONTROL_TOKEN',
|
|
9
8
|
'AGENT_INFRA_CONTROL_GENERATION',
|
|
10
9
|
'AGENT_INFRA_CONTROL_DIR',
|
|
10
|
+
'AGENT_INFRA_CONTROL_ROOT_DIR',
|
|
11
11
|
'AGENT_INFRA_CONTROL_STATUS_DIR',
|
|
12
12
|
'AGENT_INFRA_RUNTIME_DIR'
|
|
13
13
|
];
|
|
14
14
|
const TASK_CONTROL_MARKER_KEYS = [
|
|
15
|
-
'AGENT_INFRA_CONTROL_TOKEN',
|
|
16
15
|
'AGENT_INFRA_CONTROL_GENERATION',
|
|
17
16
|
'AGENT_INFRA_CONTROL_DIR',
|
|
18
17
|
'AGENT_INFRA_CONTROL_STATUS_DIR'
|
|
@@ -77,7 +76,6 @@ export function hasSandboxControlMarker(env = process.env) {
|
|
|
77
76
|
export function resolveSandboxControlTransport(env = process.env, options = {}) {
|
|
78
77
|
const markerState = sandboxTaskMarkerState(env);
|
|
79
78
|
const hasAnyMarker = markerState !== 'none'
|
|
80
|
-
|| Boolean(env.AGENT_INFRA_CONTROL_CONTROLLER_BINDING)
|
|
81
79
|
|| Boolean(env.AGENT_INFRA_EXECUTOR_MANIFEST);
|
|
82
80
|
const fixedStatusDir = options.statusMountPath ?? SANDBOX_CONTROL_STATUS_MOUNT;
|
|
83
81
|
const fixedStatusProbe = path.isAbsolute(fixedStatusDir)
|
|
@@ -98,6 +96,10 @@ export function resolveSandboxControlTransport(env = process.env, options = {})
|
|
|
98
96
|
if (!hasCompleteConfig) {
|
|
99
97
|
return { kind: 'fail-closed', reasonCode: 'SANDBOX_CONTROL_CONFIGURATION_INCOMPLETE' };
|
|
100
98
|
}
|
|
99
|
+
if (markerState === 'task-bound'
|
|
100
|
+
&& (!env.AGENT_INFRA_CONTROL_ROOT_DIR || !path.isAbsolute(env.AGENT_INFRA_CONTROL_ROOT_DIR))) {
|
|
101
|
+
return { kind: 'fail-closed', reasonCode: 'SANDBOX_CONTROL_CONFIGURATION_INCOMPLETE' };
|
|
102
|
+
}
|
|
101
103
|
const configuredStatusDir = env.AGENT_INFRA_CONTROL_STATUS_DIR;
|
|
102
104
|
const configuredStatusProbe = configuredStatusDir && path.isAbsolute(configuredStatusDir)
|
|
103
105
|
? nativeDirectoryProbe(configuredStatusDir) : 'absent';
|
|
@@ -108,7 +110,7 @@ export function resolveSandboxControlTransport(env = process.env, options = {})
|
|
|
108
110
|
? configuredStatusProbe === 'present' ? configuredStatusDir : null
|
|
109
111
|
: fixedStatusMounted ? fixedStatusDir : null;
|
|
110
112
|
const statusMounted = statusDir !== null;
|
|
111
|
-
if (env.AGENT_INFRA_EXECUTOR_MANIFEST
|
|
113
|
+
if (env.AGENT_INFRA_EXECUTOR_MANIFEST) {
|
|
112
114
|
return { kind: 'fail-closed', reasonCode: 'TASK_CONTROL_TRANSPORT_INVALID' };
|
|
113
115
|
}
|
|
114
116
|
const taskBound = Boolean(env.AGENT_INFRA_TASK_ID);
|
|
@@ -124,9 +126,6 @@ export function resolveSandboxControlTransport(env = process.env, options = {})
|
|
|
124
126
|
? 'SANDBOX_CONTROL_IDENTITY_MISSING'
|
|
125
127
|
: 'SANDBOX_CONTROL_IDENTITY_MALFORMED' };
|
|
126
128
|
}
|
|
127
|
-
if (sentinel.generation !== env.AGENT_INFRA_CONTROL_GENERATION) {
|
|
128
|
-
return { kind: 'fail-closed', reasonCode: 'SANDBOX_CONTROL_IDENTITY_GENERATION_MISMATCH' };
|
|
129
|
-
}
|
|
130
129
|
if (sentinel.controlRootId !== env.AGENT_INFRA_CONTROL_ROOT_ID) {
|
|
131
130
|
return { kind: 'fail-closed', reasonCode: 'SANDBOX_CONTROL_IDENTITY_ROOT_ID_MISMATCH' };
|
|
132
131
|
}
|
|
@@ -134,7 +133,7 @@ export function resolveSandboxControlTransport(env = process.env, options = {})
|
|
|
134
133
|
&& (sentinel.taskId !== env.AGENT_INFRA_TASK_ID || !runtime)) {
|
|
135
134
|
return { kind: 'fail-closed', reasonCode: 'SANDBOX_CONTROL_IDENTITY_TOPOLOGY_MISMATCH' };
|
|
136
135
|
}
|
|
137
|
-
if (sentinel.mode === 'branch-only' && (taskBound || runtime)) {
|
|
136
|
+
if (sentinel.mode === 'branch-only' && (taskBound || runtime || Boolean(env.AGENT_INFRA_CONTROL_ROOT_DIR))) {
|
|
138
137
|
return { kind: 'fail-closed', reasonCode: 'SANDBOX_CONTROL_IDENTITY_TOPOLOGY_MISMATCH' };
|
|
139
138
|
}
|
|
140
139
|
return { kind: options.localWorkflow ? 'sandbox-local' : 'broker-client', reasonCode: null };
|