evolcore 0.0.28 → 0.0.29
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 +12 -0
- package/bin/ec-safe-output.js +270 -54
- package/dist/agents/baseagent-availability.js +37 -1
- package/dist/agents/baseagent.js +19 -9
- package/dist/agents/claude-runner.js +171 -13
- package/dist/agents/codex/app-server-client.js +6 -2
- package/dist/agents/codex/diagnostics.js +4 -3
- package/dist/agents/codex-runner.js +396 -95
- package/dist/agents/gemini-runner.js +35 -17
- package/dist/aun/group/history.js +130 -90
- package/dist/aun/group/operations.js +1 -3
- package/dist/aun/menu/transport.js +5 -3
- package/dist/aun/msg/managed-operation.js +70 -0
- package/dist/aun/msg/p2p.js +1 -3
- package/dist/aun/msg/upload.js +2 -2
- package/dist/aun/outbox.js +1 -37
- package/dist/channels/aun.js +249 -89
- package/dist/channels/daemon.js +18 -1
- package/dist/channels/feishu.js +1 -2
- package/dist/cli/agent-command.js +23 -3
- package/dist/cli/agent-create.js +68 -2
- package/dist/cli/agent.js +12 -2
- package/dist/cli/aun-commands.js +87 -13
- package/dist/cli/cli-argv.js +26 -0
- package/dist/cli/daemon-commands.js +40 -10
- package/dist/cli/data-command.js +4 -4
- package/dist/cli/handoff-command.js +2 -0
- package/dist/cli/index.js +18 -1
- package/dist/cli/managed-command-guard.js +10 -0
- package/dist/cli/memory-command.js +441 -0
- package/dist/cli/restart-monitor.js +62 -6
- package/dist/cli/skill-command.js +41 -0
- package/dist/cli/task-context.js +2 -23
- package/dist/cli/trigger-command.js +9 -1
- package/dist/cli/watch-msg-diag.js +209 -0
- package/dist/config/config-field-policy.js +52 -3
- package/dist/config/config-manager.js +17 -4
- package/dist/config/contact-book-store.js +2 -2
- package/dist/config/mention-mode.js +7 -2
- package/dist/config/merge.js +28 -9
- package/dist/config/resolved-config-op.js +1 -1
- package/dist/config/runtime-env.js +137 -0
- package/dist/config/schema-registry.js +11 -1
- package/dist/config-store.js +10 -10
- package/dist/core/audit/event-key.js +3 -1
- package/dist/core/audit/log-integrity.js +4 -0
- package/dist/core/auth/agent-delegation.js +2 -1
- package/dist/core/auth/auth-gateway.js +13 -6
- package/dist/core/auth/authorization-audit.js +54 -19
- package/dist/core/auth/operation-authorizer.js +17 -0
- package/dist/core/auth/operation-catalog.js +9 -0
- package/dist/core/causation/context.js +5 -1
- package/dist/core/command/agent-control.js +1 -2
- package/dist/core/command/command-handler.js +51 -23
- package/dist/core/command/memory-slash.js +270 -0
- package/dist/core/command/menu-catalog.js +1 -0
- package/dist/core/command/menu-handler.js +315 -60
- package/dist/core/command/menu-protocol.js +42 -4
- package/dist/core/command/slash-gate.js +10 -10
- package/dist/core/command/slash-handler.js +206 -64
- package/dist/core/data-migration.js +282 -505
- package/dist/core/event-catalog.js +26 -0
- package/dist/core/evolagent-registry.js +6 -0
- package/dist/core/evolagent.js +0 -10
- package/dist/core/handoff/store.js +1 -20
- package/dist/core/inference/text-inference.js +57 -1
- package/dist/core/memory/consolidation-context.js +505 -0
- package/dist/core/memory/consolidation-ops-records.js +124 -0
- package/dist/core/memory/consolidation-trigger.js +394 -0
- package/dist/core/memory/index-manager.js +308 -0
- package/dist/core/memory/launch-consolidation.js +395 -0
- package/dist/core/memory/memory-admin.js +234 -0
- package/dist/core/memory/memory-document.js +100 -0
- package/dist/core/memory/memory-session-policy.js +41 -0
- package/dist/core/memory/memory-signature.js +257 -0
- package/dist/core/memory/memory-writer.js +432 -0
- package/dist/core/memory/staleness.js +117 -0
- package/dist/core/message/auto-mention-gate.js +454 -0
- package/dist/core/message/im-renderer.js +69 -16
- package/dist/core/message/message-bridge.js +287 -21
- package/dist/core/message/message-log.js +1 -0
- package/dist/core/message/message-queue.js +114 -27
- package/dist/core/message/pending-hints.js +329 -161
- package/dist/core/message/response-engine.js +567 -80
- package/dist/core/permission/ec-command-parser.js +1029 -80
- package/dist/core/permission/protected-paths.js +376 -126
- package/dist/core/permission/sandbox-runtime.js +40 -12
- package/dist/core/permission/tool-error-code.js +96 -13
- package/dist/core/permission/tool-policy.js +276 -23
- package/dist/core/role/runtime-policy.js +3 -7
- package/dist/core/session/{runner-task-history.js → runner-event-summary.js} +1 -1
- package/dist/core/session/session-fs-store.js +0 -76
- package/dist/core/session/session-idle-monitor.js +355 -0
- package/dist/core/session/session-manager.js +478 -17
- package/dist/core/session/session-mapper.js +33 -16
- package/dist/core/session/session-renew.js +217 -155
- package/dist/core/session/{session-turns.js → session-transcript.js} +35 -6
- package/dist/core/skill/global-watcher.js +282 -0
- package/dist/core/skill/index-generator.js +84 -0
- package/dist/core/skill/startup.js +73 -0
- package/dist/core/skill/switch-resolver.js +115 -0
- package/dist/core/task/task-activity-store.js +219 -0
- package/dist/eck/kit-renderer.js +30 -3
- package/dist/eck/manifest-engine.js +26 -4
- package/dist/index.js +708 -18
- package/dist/ipc.js +564 -2
- package/dist/paths.js +30 -9
- package/dist/response-system/engines/v1/proactive-flow.js +116 -15
- package/dist/response-system/modes/single-session/index.js +3 -0
- package/dist/trigger/feedback.js +1 -0
- package/dist/trigger/manager.js +0 -10
- package/dist/trigger/scheduler.js +11 -0
- package/dist/trigger/validation.js +22 -0
- package/dist/utils/avatar-upload.js +59 -18
- package/dist/utils/error-dict.json +6 -3
- package/dist/utils/error-utils.js +27 -0
- package/dist/utils/logger.js +32 -10
- package/dist/utils/media-cache.js +84 -0
- package/dist/utils/msg-diag.js +97 -0
- package/dist/utils/welcome.js +37 -8
- package/kits/docs/AUTHORING.md +314 -0
- package/kits/docs/GUIDE.md +2 -0
- package/kits/docs/INDEX.md +2 -0
- package/kits/docs/aun/CHEATSHEET.md +4 -0
- package/kits/docs/aun/SDK.md +60 -0
- package/kits/docs/context-assembly.md +10 -6
- package/kits/docs/evolcore/INDEX.md +17 -3
- package/kits/docs/evolcore/agent-create.md +24 -0
- package/kits/docs/evolcore/agent.md +5 -2
- package/kits/docs/evolcore/config.md +1 -1
- package/kits/docs/evolcore/ec-capabilities.md +364 -0
- package/kits/docs/evolcore/group.md +34 -18
- package/kits/docs/evolcore/memory-architecture.md +78 -0
- package/kits/docs/evolcore/memory-consolidation-batches.md +133 -0
- package/kits/docs/evolcore/memory-consolidation.md +263 -0
- package/kits/docs/evolcore/memory-tags.md +63 -0
- package/kits/docs/evolcore/memory.md +110 -0
- package/kits/docs/evolcore/menu-client.md +27 -11
- package/kits/{schemas → docs/evolcore}/menu-exec-schema-commands.md +12 -6
- package/kits/docs/evolcore/menu-protocol.md +213 -0
- package/kits/docs/evolcore/msg.md +2 -0
- package/kits/docs/evolcore/trigger.md +7 -5
- package/kits/docs/path-registry.md +6 -8
- package/kits/docs/prompt-loading-architecture.md +5 -3
- package/kits/docs/venues/group.md +5 -4
- package/kits/eck_manifest.json +294 -88
- package/kits/eck_manifest.memory.json +257 -0
- package/kits/rules/03-identity.md +8 -8
- package/kits/rules/05-venue.md +4 -2
- package/kits/rules/06-channel.md +1 -1
- package/kits/schemas/_meta.json +276 -47
- package/kits/schemas/agent-config.schema.12.json +38 -2
- package/kits/schemas/agent-config.schema.13.json +591 -0
- package/kits/schemas/daemon.schema.6.json +9 -9
- package/kits/schemas/defaults.schema.5.json +29 -0
- package/kits/schemas/relation-config.schema.8.json +14 -1
- package/kits/schemas/relation-config.schema.9.json +129 -0
- package/kits/schemas/role-config.schema.1.json +3 -3
- package/kits/skills/.switches.json +3 -0
- package/kits/skills/ec-skill/SKILL.md +217 -0
- package/kits/skills/ec-skill/scripts/cli.mjs +128 -0
- package/kits/skills/ec-skill/scripts/deps.mjs +107 -0
- package/kits/skills/ec-skill/scripts/frontmatter.mjs +104 -0
- package/kits/skills/ec-skill/scripts/skill.mjs +629 -0
- package/kits/skills/ec-skill/scripts/template/SKILL.md.tmpl +30 -0
- package/kits/templates/decision/auto-mention.md +25 -0
- package/kits/templates/decision/session-renew.md +22 -0
- package/kits/templates/memory-consolidation/forget.md +104 -0
- package/kits/templates/memory-consolidation/generalize.md +76 -0
- package/kits/templates/memory-consolidation/notes.md +133 -0
- package/kits/templates/memory-consolidation/profile.md +58 -0
- package/kits/templates/memory-consolidation/promote.md +72 -0
- package/kits/templates/memory-consolidation/workflow.md +75 -0
- package/kits/templates/system-fragments/bootstrap.md +14 -5
- package/kits/templates/system-fragments/commands.md +1 -0
- package/kits/templates/system-fragments/group-history.md +6 -0
- package/kits/templates/system-fragments/identity.md +0 -3
- package/kits/templates/system-fragments/memory.md +79 -0
- package/kits/templates/system-fragments/reply.md +1 -0
- package/kits/templates/system-fragments/venue.md +1 -1
- package/package.json +4 -6
- package/dist/trigger/legacy-session-history.js +0 -19
- package/kits/templates/system-fragments/group-unread-history.md +0 -7
|
@@ -5,7 +5,7 @@ import { formatAsyncQuestionAnswer, hasTrustedFullAccessContext, parseAsyncUserQ
|
|
|
5
5
|
import { requestDangerousCommandPermission } from '../core/permission/approval-gateway.js';
|
|
6
6
|
import { checkReadonly, checkDangerousCommand, evaluateToolPreflight } from '../core/permission/tool-policy.js';
|
|
7
7
|
import { normalizeExecutionPermissionMode, normalizePermissionMode, resolvePhaseOneExecutionSandbox } from '../core/permission/mode.js';
|
|
8
|
-
import { assertWindowsCodexFilesystemRuleBudget, buildCodexProtectedFilesystemRules, isSameOrDescendant, resolveProtectedCandidate, } from '../core/permission/protected-paths.js';
|
|
8
|
+
import { assertWindowsCodexFilesystemRuleBudget, buildCodexProtectedFilesystemRules, getExistingRelationAttachmentDirs, isSameOrDescendant, resolveProtectedCandidate, } from '../core/permission/protected-paths.js';
|
|
9
9
|
import { CODEX_THREAD_ACTIVE_WRITER, CodexAppServerClient, } from './codex/app-server-client.js';
|
|
10
10
|
import { resolveOpenaiConfig, resolveCodexCliPath, resolveCodexPowerShellShimPath, } from './baseagent.js';
|
|
11
11
|
import { logger } from '../utils/logger.js';
|
|
@@ -17,26 +17,20 @@ import { buildEnvelope, isInteractionSendAccepted, sendInteractionPayload } from
|
|
|
17
17
|
import { resolveCodexCapabilityThreadConfigForProject } from '../core/capability/capability-manager.js';
|
|
18
18
|
import { AGENT_DELEGATION_TOKEN_ENV, CODEX_SESSION_TOKEN_ENV, hashDelegatedCommandArgv } from '../core/auth/agent-delegation.js';
|
|
19
19
|
import { sanitizeShellExecutionEnvironment } from '../core/permission/shell-environment.js';
|
|
20
|
-
import { classifyEvolcoreShellCommand, containsLiteralManagedTmpDirOutsideSendContent, hasCodexCmdCarrierEcIntent, hasPowerShellCredentialAssignment, normalizeEvolcoreCommandArgv, parseCodexToolCommand, parseCodexCarrierCommand, parseLiteralShellCommand, parseCodexShellCommandArgv, resolveCodexShellCarrierArgv, } from '../core/permission/ec-command-parser.js';
|
|
20
|
+
import { classifyEvolcoreShellCommand, containsLiteralManagedTmpDirOutsideSendContent, containsUnresolvedManagedTmpDirReference, hasCodexCmdCarrierEcIntent, hasPowerShellCredentialAssignment, normalizeEvolcoreCommandArgv, canonicalizeEvolcoreCommandArgv, parseCodexToolCommand, parseCodexCarrierCommand, parseLiteralShellCommand, parseCodexShellCommandArgv, resolveCodexShellCarrierArgv, parseShellApplyPatchInvocation, } from '../core/permission/ec-command-parser.js';
|
|
21
21
|
import { compareVersions } from '../utils/npm-ops.js';
|
|
22
|
-
import {
|
|
22
|
+
import { agentCodexTokenPath, resolvePaths, resolveRoot } from '../paths.js';
|
|
23
23
|
import { ensureSessionRuntimeDir, getManagedTaskTempDir } from '../cli/task-context.js';
|
|
24
|
-
import {
|
|
24
|
+
import { buildTranscriptTurns } from '../core/session/session-transcript.js';
|
|
25
25
|
import { CodexSessionFileAdapter } from '../core/session/adapters/codex-session-file-adapter.js';
|
|
26
26
|
import { execFileSync } from 'child_process';
|
|
27
27
|
import { probeCli, probeCliSync } from '../utils/cross-platform.js';
|
|
28
28
|
import { createHash, randomBytes } from 'crypto';
|
|
29
29
|
import { buildModelRequestHeaders } from './request-identity.js';
|
|
30
|
+
import { normalizeToolErrorClassification, normalizeToolErrorCode, normalizeToolErrorDetailCode, } from '../core/permission/tool-error-code.js';
|
|
30
31
|
import fs from 'fs';
|
|
31
32
|
import path from 'path';
|
|
32
33
|
import os from 'os';
|
|
33
|
-
// ── MIME → 扩展名映射 ──
|
|
34
|
-
const MIME_EXT = {
|
|
35
|
-
'image/png': '.png',
|
|
36
|
-
'image/jpeg': '.jpg',
|
|
37
|
-
'image/gif': '.gif',
|
|
38
|
-
'image/webp': '.webp',
|
|
39
|
-
};
|
|
40
34
|
const APPROVAL_LOG_SUMMARY_MAX_LENGTH = 256;
|
|
41
35
|
const CODEX_INTERRUPT_TIMEOUT_MS = 5_000;
|
|
42
36
|
function toAgentErrorType(message) {
|
|
@@ -92,7 +86,7 @@ class AsyncEventQueue {
|
|
|
92
86
|
}
|
|
93
87
|
}
|
|
94
88
|
}
|
|
95
|
-
function
|
|
89
|
+
function fallbackErrorCodeForToolDenial(decisionSource, policyCode) {
|
|
96
90
|
if (decisionSource === 'policy')
|
|
97
91
|
return 'POLICY_DENIED';
|
|
98
92
|
if (decisionSource === 'approval')
|
|
@@ -103,6 +97,35 @@ function errorCodeForToolDenial(decisionSource, policyCode) {
|
|
|
103
97
|
return 'INVALID_ARGUMENT';
|
|
104
98
|
return 'EXECUTION_FAILED';
|
|
105
99
|
}
|
|
100
|
+
function errorCodeForToolDenial(decisionSource, policyCode) {
|
|
101
|
+
return normalizeToolErrorClassification({
|
|
102
|
+
errorCode: fallbackErrorCodeForToolDenial(decisionSource, policyCode),
|
|
103
|
+
decisionSource,
|
|
104
|
+
policyCode,
|
|
105
|
+
executed: false,
|
|
106
|
+
executionState: 'blocked',
|
|
107
|
+
}).errorCode;
|
|
108
|
+
}
|
|
109
|
+
function errorDetailCodeForToolDenial(decisionSource, policyCode, errorDetailCode) {
|
|
110
|
+
return normalizeToolErrorClassification({
|
|
111
|
+
errorCode: fallbackErrorCodeForToolDenial(decisionSource, policyCode),
|
|
112
|
+
errorDetailCode,
|
|
113
|
+
decisionSource,
|
|
114
|
+
policyCode,
|
|
115
|
+
executed: false,
|
|
116
|
+
executionState: 'blocked',
|
|
117
|
+
}).errorDetailCode;
|
|
118
|
+
}
|
|
119
|
+
function codexItemErrorFields(item) {
|
|
120
|
+
const rawCode = item?.error?.code ?? item?.error?.errorCode;
|
|
121
|
+
if (typeof rawCode !== 'string' || !rawCode.trim())
|
|
122
|
+
return {};
|
|
123
|
+
const errorCode = normalizeToolErrorCode(rawCode);
|
|
124
|
+
if (errorCode)
|
|
125
|
+
return { errorCode };
|
|
126
|
+
const errorDetailCode = normalizeToolErrorDetailCode(rawCode);
|
|
127
|
+
return errorDetailCode ? { errorDetailCode } : {};
|
|
128
|
+
}
|
|
106
129
|
function isCodexReasoningNotification(method) {
|
|
107
130
|
return method === 'item/reasoning/textDelta'
|
|
108
131
|
|| method === 'item/reasoning/summaryTextDelta'
|
|
@@ -429,6 +452,7 @@ export class CodexRunner {
|
|
|
429
452
|
enableRequestUserInput: this.resolvedConfig.enableRequestUserInput,
|
|
430
453
|
approvalsReviewer: 'user',
|
|
431
454
|
protectEvolcoreFilesystem: !fullAccess,
|
|
455
|
+
selfAid: this.resolvedConfig.agentAid,
|
|
432
456
|
// A completed turn is explicitly unsubscribed below. This is only an
|
|
433
457
|
// optimization on newer Codex versions; old versions retain the thread
|
|
434
458
|
// until the cross-client archive fallback runs.
|
|
@@ -613,6 +637,13 @@ export class CodexRunner {
|
|
|
613
637
|
this.threadSubscriptions.set(threadId, { client: targetClient, state: 'subscribed' });
|
|
614
638
|
}
|
|
615
639
|
approvedLiteralEvolcoreCommand(command, managedTempDir, dialect = 'posix', expectedCredentialToken, executable) {
|
|
640
|
+
if (/\\\$(?:TMPDIR|\{TMPDIR\})/i.test(command)
|
|
641
|
+
&& /\bec\s+fs\s+(?:cp|ls|stat|find|cat|mkdir|rm|mv|upload)\b/i.test(command)) {
|
|
642
|
+
return { parseFailure: {
|
|
643
|
+
issue: 'unsafe-expansion', offset: 0, tokenIndex: 0,
|
|
644
|
+
dialect, inputLength: command.length,
|
|
645
|
+
} };
|
|
646
|
+
}
|
|
616
647
|
const parseOptions = {
|
|
617
648
|
allowManagedTmpDir: true,
|
|
618
649
|
dialect,
|
|
@@ -644,11 +675,21 @@ export class CodexRunner {
|
|
|
644
675
|
} };
|
|
645
676
|
}
|
|
646
677
|
return {
|
|
647
|
-
argv:
|
|
678
|
+
argv: canonicalizeEvolcoreCommandArgv(parsed.argv),
|
|
648
679
|
...(parsed.credentialToken ? { credentialToken: parsed.credentialToken } : {}),
|
|
649
680
|
};
|
|
650
681
|
}
|
|
651
682
|
resolveCanonicalEcApproval(toolInput, managedTempDir, expectedCredentialToken) {
|
|
683
|
+
const rawCommand = typeof toolInput.command === 'string' ? toolInput.command : '';
|
|
684
|
+
if (/\\\$(?:TMPDIR|\{TMPDIR\})/i.test(rawCommand)
|
|
685
|
+
&& /\bec\s+fs\s+(?:cp|ls|stat|find|cat|mkdir|rm|mv|upload)\b/i.test(rawCommand)
|
|
686
|
+
&& !/\bec\s+(?:msg|group)\s+send\b/i.test(rawCommand)
|
|
687
|
+
&& !/\bec\s+trigger\s+(?:create|set|update)\b/i.test(rawCommand)) {
|
|
688
|
+
return { parseFailure: {
|
|
689
|
+
issue: 'unsafe-expansion', offset: 0, tokenIndex: 0,
|
|
690
|
+
dialect: 'posix', inputLength: rawCommand.length,
|
|
691
|
+
} };
|
|
692
|
+
}
|
|
652
693
|
const explicitArgv = Array.isArray(toolInput.commandArgv)
|
|
653
694
|
&& toolInput.commandArgv.every(value => typeof value === 'string')
|
|
654
695
|
? toolInput.commandArgv
|
|
@@ -661,9 +702,9 @@ export class CodexRunner {
|
|
|
661
702
|
dialect: 'posix', inputLength: 0,
|
|
662
703
|
} };
|
|
663
704
|
}
|
|
664
|
-
return containsLiteralManagedTmpDirOutsideSendContent(explicitArgv)
|
|
705
|
+
return containsLiteralManagedTmpDirOutsideSendContent(explicitArgv) || containsUnresolvedManagedTmpDirReference(explicitArgv)
|
|
665
706
|
? { parseFailure: { issue: 'unsafe-expansion', offset: 0, tokenIndex: 0, dialect: 'posix', inputLength: 0 } }
|
|
666
|
-
: { argv:
|
|
707
|
+
: { argv: canonicalizeEvolcoreCommandArgv(explicitArgv) };
|
|
667
708
|
}
|
|
668
709
|
const explicitCarrier = explicitArgv
|
|
669
710
|
? resolveCodexShellCarrierArgv(explicitArgv)
|
|
@@ -671,6 +712,21 @@ export class CodexRunner {
|
|
|
671
712
|
if (explicitCarrier !== undefined) {
|
|
672
713
|
return this.approvedLiteralEvolcoreCommand(explicitCarrier.command, managedTempDir, explicitCarrier.dialect, expectedCredentialToken, explicitCarrier.executable);
|
|
673
714
|
}
|
|
715
|
+
if (explicitArgv?.length === 1 && typeof explicitArgv[0] === 'string') {
|
|
716
|
+
const parsed = parseCodexToolCommand({ commandArgv: explicitArgv }, {
|
|
717
|
+
allowManagedTmpDir: true,
|
|
718
|
+
verifyShellExecutable: process.platform === 'win32',
|
|
719
|
+
...(managedTempDir ? { managedTempDir } : {}),
|
|
720
|
+
...(expectedCredentialToken !== undefined ? { expectedCredentialToken } : {}),
|
|
721
|
+
});
|
|
722
|
+
if (parsed.ok && parsed.argv[0] === 'ec') {
|
|
723
|
+
return containsLiteralManagedTmpDirOutsideSendContent(parsed.argv) || containsUnresolvedManagedTmpDirReference(parsed.argv)
|
|
724
|
+
? { parseFailure: { issue: 'unsafe-expansion', offset: 0, tokenIndex: 0, dialect: 'powershell', inputLength: explicitArgv[0].length } }
|
|
725
|
+
: { argv: canonicalizeEvolcoreCommandArgv(parsed.argv) };
|
|
726
|
+
}
|
|
727
|
+
if (!parsed.ok)
|
|
728
|
+
return { parseFailure: parsed };
|
|
729
|
+
}
|
|
674
730
|
if (hasCodexCmdCarrierEcIntent(toolInput)) {
|
|
675
731
|
const parsed = parseCodexToolCommand(toolInput, {
|
|
676
732
|
verifyShellExecutable: process.platform === 'win32',
|
|
@@ -679,13 +735,13 @@ export class CodexRunner {
|
|
|
679
735
|
if (!parsed.ok)
|
|
680
736
|
return { parseFailure: parsed };
|
|
681
737
|
if (parsed.argv[0] === 'ec') {
|
|
682
|
-
return containsLiteralManagedTmpDirOutsideSendContent(parsed.argv)
|
|
738
|
+
return containsLiteralManagedTmpDirOutsideSendContent(parsed.argv) || containsUnresolvedManagedTmpDirReference(parsed.argv)
|
|
683
739
|
? { parseFailure: {
|
|
684
740
|
issue: 'unsafe-expansion', offset: 0, tokenIndex: 0,
|
|
685
741
|
dialect: 'cmd', inputLength: 0,
|
|
686
742
|
} }
|
|
687
743
|
: {
|
|
688
|
-
argv:
|
|
744
|
+
argv: canonicalizeEvolcoreCommandArgv(parsed.argv),
|
|
689
745
|
...(parsed.credentialToken ? { credentialToken: parsed.credentialToken } : {}),
|
|
690
746
|
};
|
|
691
747
|
}
|
|
@@ -709,7 +765,7 @@ export class CodexRunner {
|
|
|
709
765
|
...(expectedCredentialToken !== undefined ? { expectedCredentialToken } : {}),
|
|
710
766
|
});
|
|
711
767
|
if (canonicalCommand?.[0] === 'ec') {
|
|
712
|
-
return containsLiteralManagedTmpDirOutsideSendContent(canonicalCommand)
|
|
768
|
+
return containsLiteralManagedTmpDirOutsideSendContent(canonicalCommand) || containsUnresolvedManagedTmpDirReference(canonicalCommand)
|
|
713
769
|
? { parseFailure: {
|
|
714
770
|
issue: 'unsafe-expansion',
|
|
715
771
|
offset: 0,
|
|
@@ -717,7 +773,7 @@ export class CodexRunner {
|
|
|
717
773
|
dialect: 'posix',
|
|
718
774
|
inputLength: command.length,
|
|
719
775
|
} }
|
|
720
|
-
: { argv: canonicalCommand };
|
|
776
|
+
: { argv: canonicalizeEvolcoreCommandArgv(canonicalCommand) };
|
|
721
777
|
}
|
|
722
778
|
const outer = parseLiteralShellCommand(command, {
|
|
723
779
|
allowManagedTmpDir: true,
|
|
@@ -747,6 +803,10 @@ export class CodexRunner {
|
|
|
747
803
|
|| shellCarrier !== undefined
|
|
748
804
|
&& classifyEvolcoreShellCommand(shellCarrier.command, {
|
|
749
805
|
dialect: shellCarrier.dialect,
|
|
806
|
+
}).kind !== 'none'
|
|
807
|
+
|| rawArgv.length === 1
|
|
808
|
+
&& classifyEvolcoreShellCommand(rawArgv[0], {
|
|
809
|
+
dialect: 'powershell',
|
|
750
810
|
}).kind !== 'none';
|
|
751
811
|
}
|
|
752
812
|
const command = typeof toolInput.command === 'string' ? toolInput.command : '';
|
|
@@ -1218,8 +1278,15 @@ export class CodexRunner {
|
|
|
1218
1278
|
enabled: true,
|
|
1219
1279
|
unix_sockets: { [resolvePaths().instanceSocket]: 'allow' },
|
|
1220
1280
|
};
|
|
1281
|
+
const relationAttachmentDenies = {};
|
|
1282
|
+
for (const directory of getExistingRelationAttachmentDirs(resolveRoot(), {
|
|
1283
|
+
selfAid: this.resolvedConfig.agentAid,
|
|
1284
|
+
onlyOtherAgents: true,
|
|
1285
|
+
}))
|
|
1286
|
+
relationAttachmentDenies[directory] = 'deny';
|
|
1221
1287
|
const filesystem = {
|
|
1222
1288
|
...buildCodexProtectedFilesystemRules(resolveRoot(), {
|
|
1289
|
+
selfAid: this.resolvedConfig.agentAid,
|
|
1223
1290
|
denyLClassRead: mode === 'readonly',
|
|
1224
1291
|
// The app-server itself is launched behind EvolCore's Linux
|
|
1225
1292
|
// H-class guard, which already mounts every L-class directory
|
|
@@ -1235,6 +1302,7 @@ export class CodexRunner {
|
|
|
1235
1302
|
...(personalMdPath ? {
|
|
1236
1303
|
[path.resolve(personalMdPath)]: mode === 'readonly' ? 'read' : 'write',
|
|
1237
1304
|
} : {}),
|
|
1305
|
+
...relationAttachmentDenies,
|
|
1238
1306
|
...(mode !== 'readonly' && managedTempDir ? {
|
|
1239
1307
|
[managedTempDir]: 'write',
|
|
1240
1308
|
[managedTempDir + '/**']: 'write',
|
|
@@ -1395,6 +1463,7 @@ export class CodexRunner {
|
|
|
1395
1463
|
const normalizedInput = toolInput && typeof toolInput === 'object' && !Array.isArray(toolInput)
|
|
1396
1464
|
? toolInput
|
|
1397
1465
|
: {};
|
|
1466
|
+
const isShellTool = toolName === 'Bash' || toolName === 'Shell' || toolName === 'exec_command';
|
|
1398
1467
|
const recordPreToolUseDenial = async (policyCode, reason) => {
|
|
1399
1468
|
const summary = summarizeToolInputForAudit(toolName, normalizedInput).slice(0, 512);
|
|
1400
1469
|
auditToolPreflightDenial({
|
|
@@ -1469,6 +1538,28 @@ export class CodexRunner {
|
|
|
1469
1538
|
await recordPreToolUseDenial('fullaccess_context_untrusted', reason);
|
|
1470
1539
|
return { ok: false, applicable: true, decision: 'deny', reason };
|
|
1471
1540
|
}
|
|
1541
|
+
const preflightProjectPath = this.threadProjectPaths.get(threadId)
|
|
1542
|
+
?? (activeThread ? this.threadProjectPaths.get(activeThread) : undefined)
|
|
1543
|
+
?? process.cwd();
|
|
1544
|
+
const preflight = evaluateToolPreflight(isShellTool ? 'Bash' : toolName, normalizedInput, {
|
|
1545
|
+
sessionId: sessionKey,
|
|
1546
|
+
managedTempDir: context.managedTempDir ?? this.getManagedTempDir(sessionKey) ?? '',
|
|
1547
|
+
sessionCredential: sessionToken,
|
|
1548
|
+
allowProtectedMetadata: false,
|
|
1549
|
+
selfAid: context.selfAid,
|
|
1550
|
+
channel: context.channel,
|
|
1551
|
+
userId: context.userId,
|
|
1552
|
+
role: context.role,
|
|
1553
|
+
permissionMode: normalizeExecutionPermissionMode(this.chatModes.get(sessionKey) ?? this.currentMode),
|
|
1554
|
+
allowReadonlySourceDiagnostics: context.allowReadonlySourceDiagnostics === true,
|
|
1555
|
+
projectPath: preflightProjectPath,
|
|
1556
|
+
workspacePath: preflightProjectPath,
|
|
1557
|
+
});
|
|
1558
|
+
if (preflight.behavior === 'deny') {
|
|
1559
|
+
const reason = preflight.message ?? 'tool preflight denied';
|
|
1560
|
+
await recordPreToolUseDenial(preflight.policyCode ?? 'tool_preflight_denied', reason);
|
|
1561
|
+
return { ok: true, applicable: true, decision: 'deny', reason };
|
|
1562
|
+
}
|
|
1472
1563
|
// A tracked interactive thread still needs an authenticated, explicit
|
|
1473
1564
|
// allow so the managed hook can fail closed when no runner matches.
|
|
1474
1565
|
if (!context.preToolUsePolicyHook)
|
|
@@ -1710,7 +1801,7 @@ export class CodexRunner {
|
|
|
1710
1801
|
}
|
|
1711
1802
|
this.chatModes.set(sessionId, callMode);
|
|
1712
1803
|
const callApprovalPolicy = this.toApprovalPolicy(callMode);
|
|
1713
|
-
const executionSandbox = this.buildExecutionSandboxOptions(sessionId, callMode, projectPath, modelOverride?.bootstrapAgentMdPath, modelOverride?.personalMdPath);
|
|
1804
|
+
const executionSandbox = this.buildExecutionSandboxOptions(sessionId, callMode, projectPath, modelOverride?.bootstrapAgentMdPath, modelOverride?.personalMdPath, undefined);
|
|
1714
1805
|
const appServer = this.getAppServerClient(callMode === 'fullaccess');
|
|
1715
1806
|
this.dropExpiredPendingInterrupt(sessionId);
|
|
1716
1807
|
const effectiveApprovalPolicy = callApprovalPolicy;
|
|
@@ -1839,12 +1930,11 @@ export class CodexRunner {
|
|
|
1839
1930
|
this.bindExternalToolBoundary(threadId, externalToolConfig);
|
|
1840
1931
|
const controller = new AbortController();
|
|
1841
1932
|
this.activeAbortControllers.set(sessionId, controller);
|
|
1842
|
-
const tempFiles = [];
|
|
1843
1933
|
const answer = modelOverride?.asyncQuestionAnswer;
|
|
1844
1934
|
if (answer && answer.providerThreadId !== threadId) {
|
|
1845
1935
|
throw new Error('Async question reply cannot resume a different Codex thread');
|
|
1846
1936
|
}
|
|
1847
|
-
const input = this.buildAppServerInput(answer ? formatAsyncQuestionAnswer(answer) : prompt, images
|
|
1937
|
+
const input = this.buildAppServerInput(answer ? formatAsyncQuestionAnswer(answer) : prompt, images);
|
|
1848
1938
|
const queue = new AsyncEventQueue();
|
|
1849
1939
|
controller.signal.addEventListener('abort', () => queue.end(), { once: true });
|
|
1850
1940
|
const state = {
|
|
@@ -1931,7 +2021,7 @@ export class CodexRunner {
|
|
|
1931
2021
|
if (!resumingThread)
|
|
1932
2022
|
this.cleanupProvisionalThread(sessionId, threadId);
|
|
1933
2023
|
logger.info(`[CodexRunner] Applied pending interrupt before turn start: ${sessionId}`);
|
|
1934
|
-
return this.transformAppServerStream(queue, sessionId, state, controller, unsubscribe, appServer
|
|
2024
|
+
return this.transformAppServerStream(queue, sessionId, state, controller, unsubscribe, appServer);
|
|
1935
2025
|
}
|
|
1936
2026
|
try {
|
|
1937
2027
|
const turnResponse = await appServer.turnStart(threadId, input, {
|
|
@@ -2013,12 +2103,11 @@ export class CodexRunner {
|
|
|
2013
2103
|
this.activeAbortControllers.delete(sessionId);
|
|
2014
2104
|
this.activeTurns.delete(sessionId);
|
|
2015
2105
|
this.pendingInterrupts.delete(sessionId);
|
|
2016
|
-
this.cleanupTempFiles(tempFiles);
|
|
2017
2106
|
if (!resumingThread)
|
|
2018
2107
|
this.cleanupProvisionalThread(sessionId, threadId);
|
|
2019
2108
|
throw error;
|
|
2020
2109
|
}
|
|
2021
|
-
return this.transformAppServerStream(queue, sessionId, state, controller, unsubscribe, appServer
|
|
2110
|
+
return this.transformAppServerStream(queue, sessionId, state, controller, unsubscribe, appServer);
|
|
2022
2111
|
}
|
|
2023
2112
|
// ── Interrupt ──
|
|
2024
2113
|
async interrupt(sessionKey) {
|
|
@@ -2467,15 +2556,9 @@ export class CodexRunner {
|
|
|
2467
2556
|
// They follow the thread (not the daemon process) so a daemon restart does
|
|
2468
2557
|
// not strand a resumable thread: the token file is re-read on resume, and
|
|
2469
2558
|
// it is removed lazily once the rollout file itself disappears.
|
|
2470
|
-
threadCredentialsDir() {
|
|
2471
|
-
const aid = this.resolvedConfig.agentAid;
|
|
2472
|
-
if (!aid)
|
|
2473
|
-
return undefined;
|
|
2474
|
-
return path.join(agentSessionsDir(aid), 'codex-tokens');
|
|
2475
|
-
}
|
|
2476
2559
|
threadCredentialPath(threadId) {
|
|
2477
|
-
const
|
|
2478
|
-
return
|
|
2560
|
+
const aid = this.resolvedConfig.agentAid;
|
|
2561
|
+
return aid ? agentCodexTokenPath(aid, threadId) : undefined;
|
|
2479
2562
|
}
|
|
2480
2563
|
createThreadCredential() {
|
|
2481
2564
|
return randomBytes(32).toString('hex');
|
|
@@ -2615,7 +2698,7 @@ export class CodexRunner {
|
|
|
2615
2698
|
const appServer = this.getAppServerClient();
|
|
2616
2699
|
const history = await this.readForkHistory(appServer, agentSessionId);
|
|
2617
2700
|
const messages = this.mapThreadToSessionMessages(history, agentSessionId);
|
|
2618
|
-
const turns =
|
|
2701
|
+
const turns = buildTranscriptTurns(messages);
|
|
2619
2702
|
const targetIndex = turns.findIndex(turn => turn.assistantUuid === assistantMessageId);
|
|
2620
2703
|
if (targetIndex < 0)
|
|
2621
2704
|
throw new Error('fork point not found');
|
|
@@ -2633,7 +2716,7 @@ export class CodexRunner {
|
|
|
2633
2716
|
if (typeof turn.id !== 'string' || !turn.id)
|
|
2634
2717
|
continue;
|
|
2635
2718
|
for (const item of this.getTurnItems(turn)) {
|
|
2636
|
-
if (item.
|
|
2719
|
+
if (item.id === assistantMessageId)
|
|
2637
2720
|
return turn.id;
|
|
2638
2721
|
}
|
|
2639
2722
|
// Older app-server histories may omit item ids; the mapper then uses the
|
|
@@ -3039,7 +3122,7 @@ export class CodexRunner {
|
|
|
3039
3122
|
? this.resolveCanonicalEcApproval(toolInput, this.getManagedTempDir(sessionKey), sessionCredential)
|
|
3040
3123
|
: undefined;
|
|
3041
3124
|
const approvedCommand = canonicalEcApproval?.argv;
|
|
3042
|
-
const denyInfrastructure = async (policyCode, message) => {
|
|
3125
|
+
const denyInfrastructure = async (policyCode, message, errorDetailCode) => {
|
|
3043
3126
|
logger.warn(`[CodexRunner] ${message}: session=${sessionKey} requestId=${request.id ?? '<missing>'}`);
|
|
3044
3127
|
try {
|
|
3045
3128
|
await permissionContext?.recordExecutionAnomaly?.({
|
|
@@ -3067,6 +3150,7 @@ export class CodexRunner {
|
|
|
3067
3150
|
decision: 'deny',
|
|
3068
3151
|
decisionSource: 'infrastructure',
|
|
3069
3152
|
policyCode,
|
|
3153
|
+
...(errorDetailCode ? { errorDetailCode } : {}),
|
|
3070
3154
|
reason: message,
|
|
3071
3155
|
});
|
|
3072
3156
|
this.logAppServerApprovalAudit(request, sessionKey, toolName, 'deny', 'infrastructure', policyCode, message, canonicalEcApproval?.parseFailure);
|
|
@@ -3077,18 +3161,28 @@ export class CodexRunner {
|
|
|
3077
3161
|
if (canonicalEcApproval?.parseFailure?.issue === 'untrusted-shell') {
|
|
3078
3162
|
return await denyInfrastructure('ec_shell_untrusted_executable', 'EC command approval denied because the shell executable failed Windows Authenticode trust validation');
|
|
3079
3163
|
}
|
|
3164
|
+
if (canonicalEcApproval?.parseFailure?.issue === 'unsupported-escape') {
|
|
3165
|
+
return await denyInfrastructure('ec_shell_unsupported_escape', 'EC inline text does not support PowerShell `n. Use literal \\n in the argument instead.');
|
|
3166
|
+
}
|
|
3167
|
+
if (canonicalEcApproval?.parseFailure?.issue === 'lossy-cmd-shim') {
|
|
3168
|
+
return await denyInfrastructure('ec_shell_lossy_cmd_shim', 'PowerShell cannot pass physical multiline EC arguments through ec.cmd intact. Use ec ... via the PowerShell-native shim instead.');
|
|
3169
|
+
}
|
|
3080
3170
|
return await denyInfrastructure('ec_command_not_canonical', canonicalEcApproval?.parseFailure
|
|
3081
3171
|
? `EC command approval denied because canonical argv parsing failed (${canonicalEcApproval.parseFailure.issue})`
|
|
3082
3172
|
+ (canonicalEcApproval.parseFailure.dialect === 'powershell' && canonicalEcApproval.parseFailure.issue === 'invalid-quote'
|
|
3083
3173
|
? '. PowerShell treats smart quotes as delimiters too; escape quotes for PowerShell or use --text-from-file for message text.'
|
|
3084
3174
|
: '')
|
|
3085
|
-
: 'EC command approval denied because no canonical argv could be derived');
|
|
3175
|
+
: 'EC command approval denied because no canonical argv could be derived', canonicalEcApproval?.parseFailure?.issue === 'invalid-quote' ? 'INVALID_QUOTE' : undefined);
|
|
3086
3176
|
}
|
|
3087
3177
|
try {
|
|
3088
3178
|
const resolution = await this.resolvePermissionDecision(sessionKey, toolName, toolInput, summary, reason, workspacePath, operationCwd, request.id, typeof params.itemId === 'string' ? params.itemId : typeof params.item_id === 'string' ? params.item_id : undefined);
|
|
3089
3179
|
const decision = typeof resolution === 'string' ? resolution : resolution.decision;
|
|
3090
3180
|
const resolutionMeta = typeof resolution === 'string' ? undefined : resolution;
|
|
3091
3181
|
if (decision !== 'deny' && managedEcIntent && approvedCommand) {
|
|
3182
|
+
if (containsLiteralManagedTmpDirOutsideSendContent(approvedCommand)
|
|
3183
|
+
|| containsUnresolvedManagedTmpDirReference(approvedCommand)) {
|
|
3184
|
+
return await denyInfrastructure('ec_command_unsafe_tmpdir_reference', 'EC command contains an unresolved or unsafe managed TMPDIR reference');
|
|
3185
|
+
}
|
|
3092
3186
|
const credentialThreadIds = [
|
|
3093
3187
|
this.activeSessions.get(sessionKey),
|
|
3094
3188
|
this.provisionalSessions.get(sessionKey),
|
|
@@ -3123,6 +3217,7 @@ export class CodexRunner {
|
|
|
3123
3217
|
decision: 'deny',
|
|
3124
3218
|
decisionSource,
|
|
3125
3219
|
...(policyCode ? { policyCode } : {}),
|
|
3220
|
+
...(resolutionMeta?.errorDetailCode ? { errorDetailCode: resolutionMeta.errorDetailCode } : {}),
|
|
3126
3221
|
reason: denialReason,
|
|
3127
3222
|
});
|
|
3128
3223
|
setImmediate(() => this.steerPolicyReason(sessionKey, policyCode, denialReason));
|
|
@@ -3166,6 +3261,7 @@ export class CodexRunner {
|
|
|
3166
3261
|
decision,
|
|
3167
3262
|
decisionSource,
|
|
3168
3263
|
policyCode,
|
|
3264
|
+
...(parseFailure?.issue === 'invalid-quote' ? { errorDetailCode: 'INVALID_QUOTE' } : {}),
|
|
3169
3265
|
permissionMode: normalizeExecutionPermissionMode(this.chatModes.get(sessionKey) ?? this.currentMode),
|
|
3170
3266
|
role: context?.role,
|
|
3171
3267
|
taskId: context?.taskId,
|
|
@@ -3687,6 +3783,7 @@ export class CodexRunner {
|
|
|
3687
3783
|
channel: permCtx?.channel,
|
|
3688
3784
|
peerId: permCtx?.userId,
|
|
3689
3785
|
role: permCtx?.role,
|
|
3786
|
+
selfAid: permCtx?.selfAid ?? this.resolvedConfig.agentAid,
|
|
3690
3787
|
allowProtectedMetadata: false,
|
|
3691
3788
|
// Revalidate ownership, mode, and parent containment at the final
|
|
3692
3789
|
// readonly decision. The map entry alone is stale if the directory was
|
|
@@ -3795,9 +3892,17 @@ export class CodexRunner {
|
|
|
3795
3892
|
&& this.hasNetworkPermissionRequest(toolInput);
|
|
3796
3893
|
const hasUnknownPermissions = (toolName === 'Bash' || toolName === 'PermissionGrant')
|
|
3797
3894
|
&& this.hasUnknownPermissionRequest(toolInput);
|
|
3895
|
+
const applyPatch = (toolName === 'Bash' || toolName === 'Shell' || toolName === 'exec_command')
|
|
3896
|
+
? parseShellApplyPatchInvocation(toolInput)
|
|
3897
|
+
: { kind: 'not-apply-patch' };
|
|
3898
|
+
const applyPatchFileChanges = applyPatch.kind === 'file-change' ? applyPatch.fileChanges : undefined;
|
|
3899
|
+
const applyPatchInput = applyPatchFileChanges
|
|
3900
|
+
? { ...toolInput, fileChanges: applyPatchFileChanges }
|
|
3901
|
+
: toolInput;
|
|
3798
3902
|
const hasPermissionExpansion = hasFilesystemPermissions || hasNetworkPermissions || hasUnknownPermissions;
|
|
3799
3903
|
const hasFileChangeExpansion = toolName === 'FileChange'
|
|
3800
|
-
|
|
3904
|
+
? this.fileChangeRequiresExpansion(toolInput, workspacePath, sessionKey)
|
|
3905
|
+
: !!applyPatchFileChanges && this.fileChangeRequiresExpansion(applyPatchInput, workspacePath, sessionKey);
|
|
3801
3906
|
// per-session 权限模式(runQuery 写入);缺省回落实例级 currentMode(兼容无 runQuery 上下文的调用)
|
|
3802
3907
|
const rawMode = this.chatModes.get(sessionKey) ?? this.currentMode;
|
|
3803
3908
|
const mode = normalizeExecutionPermissionMode(rawMode);
|
|
@@ -3876,12 +3981,17 @@ export class CodexRunner {
|
|
|
3876
3981
|
decision: 'deny',
|
|
3877
3982
|
decisionSource: 'policy',
|
|
3878
3983
|
policyCode: preflight.policyCode ?? 'tool_preflight_denied',
|
|
3984
|
+
...(preflight.errorDetailCode ? { errorDetailCode: preflight.errorDetailCode } : {}),
|
|
3879
3985
|
reason: preflight.message ?? 'tool preflight denied',
|
|
3880
3986
|
};
|
|
3881
3987
|
}
|
|
3882
3988
|
if (preflight.behavior === 'allow')
|
|
3883
3989
|
return 'allow';
|
|
3884
3990
|
const checkedInput = preflight.input;
|
|
3991
|
+
const policyInput = applyPatchFileChanges
|
|
3992
|
+
? { ...checkedInput, fileChanges: applyPatchFileChanges }
|
|
3993
|
+
: checkedInput;
|
|
3994
|
+
const policyToolName = applyPatchFileChanges ? 'FileChange' : toolName;
|
|
3885
3995
|
if (toolName === 'FileChange') {
|
|
3886
3996
|
const hasGrantRoot = typeof checkedInput.grantRoot === 'string'
|
|
3887
3997
|
&& checkedInput.grantRoot.length > 0;
|
|
@@ -3901,9 +4011,9 @@ export class CodexRunner {
|
|
|
3901
4011
|
return 'deny';
|
|
3902
4012
|
const grantScope = `codex:${this.permissionProfileName(sessionKey)}:${mode}`;
|
|
3903
4013
|
if (mode === 'readonly') {
|
|
3904
|
-
const readonly = this.checkCodexReadonly(
|
|
4014
|
+
const readonly = this.checkCodexReadonly(policyToolName, policyInput, operationCwd, sessionKey);
|
|
3905
4015
|
if (readonly.behavior === 'deny') {
|
|
3906
|
-
await recordBlockedOperation(readonly.policyCode ?? 'readonly_mode',
|
|
4016
|
+
await recordBlockedOperation(readonly.policyCode ?? 'readonly_mode', policyInput, readonly.message);
|
|
3907
4017
|
return 'deny';
|
|
3908
4018
|
}
|
|
3909
4019
|
return 'allow';
|
|
@@ -3914,7 +4024,7 @@ export class CodexRunner {
|
|
|
3914
4024
|
// auto 模式下检查危险命令,危险命令自动拒绝
|
|
3915
4025
|
if (mode === 'auto') {
|
|
3916
4026
|
if (hasFileChangeExpansion || hasFilesystemPermissions || hasUnknownPermissions) {
|
|
3917
|
-
await recordBlockedOperation('auto_permission_expansion',
|
|
4027
|
+
await recordBlockedOperation('auto_permission_expansion', policyInput);
|
|
3918
4028
|
return 'deny';
|
|
3919
4029
|
}
|
|
3920
4030
|
if (toolName === 'PermissionGrant' && !hasNetworkPermissions) {
|
|
@@ -3934,8 +4044,8 @@ export class CodexRunner {
|
|
|
3934
4044
|
if (requiresSandboxExpansionApproval) {
|
|
3935
4045
|
if (!this.permissionGateway || !permissionPrompt)
|
|
3936
4046
|
return 'deny';
|
|
3937
|
-
if (
|
|
3938
|
-
return this.permissionGateway.requestPermission(sessionKey,
|
|
4047
|
+
if (policyToolName === 'FileChange') {
|
|
4048
|
+
return this.permissionGateway.requestPermission(sessionKey, policyToolName, policyInput, permissionPrompt, this.permissionContexts.get(sessionKey), summary, reason || 'Codex 请求扩大当前命令或 turn 的文件系统权限', grantScope, undefined, { fileChangeCwd: workspacePath });
|
|
3939
4049
|
}
|
|
3940
4050
|
return this.permissionGateway.requestPermission(sessionKey, toolName, checkedInput, permissionPrompt, this.permissionContexts.get(sessionKey), summary, reason || 'Codex 请求扩大当前命令或 turn 的文件系统权限', grantScope);
|
|
3941
4051
|
}
|
|
@@ -3980,20 +4090,80 @@ export class CodexRunner {
|
|
|
3980
4090
|
}
|
|
3981
4091
|
throw new Error('Unsupported Codex app-server request: ' + method);
|
|
3982
4092
|
}
|
|
3983
|
-
async rollbackSessionTurns(agentSessionId,
|
|
3984
|
-
const release = await this.acquireThreadOperation(this.threadOperationKey(agentSessionId), 'rollback');
|
|
4093
|
+
async rollbackSessionTurns(agentSessionId, projectPath, numTurns, targetAssistantMessageId) {
|
|
4094
|
+
const release = await this.acquireThreadOperation(this.threadOperationKey(agentSessionId), 'resume+rollback');
|
|
3985
4095
|
try {
|
|
3986
|
-
return await this.rollbackSessionTurnsLocked(agentSessionId, numTurns);
|
|
4096
|
+
return await this.rollbackSessionTurnsLocked(agentSessionId, projectPath, numTurns, targetAssistantMessageId);
|
|
3987
4097
|
}
|
|
3988
4098
|
finally {
|
|
3989
4099
|
release();
|
|
3990
4100
|
}
|
|
3991
4101
|
}
|
|
3992
|
-
async rollbackSessionTurnsLocked(agentSessionId, numTurns) {
|
|
4102
|
+
async rollbackSessionTurnsLocked(agentSessionId, projectPath, numTurns, targetAssistantMessageId) {
|
|
3993
4103
|
if (numTurns < 1)
|
|
3994
4104
|
return true;
|
|
3995
|
-
const
|
|
3996
|
-
|
|
4105
|
+
const appServer = this.getAppServerClientForThread(agentSessionId);
|
|
4106
|
+
const previousAppServer = await this.prepareThreadSubscription(appServer, agentSessionId);
|
|
4107
|
+
let resumed = false;
|
|
4108
|
+
try {
|
|
4109
|
+
let resumeResponse;
|
|
4110
|
+
try {
|
|
4111
|
+
resumeResponse = await appServer.threadResume(agentSessionId, projectPath);
|
|
4112
|
+
}
|
|
4113
|
+
catch (error) {
|
|
4114
|
+
if (isCodexActiveWriterError(error) && previousAppServer && previousAppServer !== appServer) {
|
|
4115
|
+
await this.archiveThreadForHandoff(previousAppServer, appServer, agentSessionId);
|
|
4116
|
+
resumeResponse = await appServer.threadResume(agentSessionId, projectPath);
|
|
4117
|
+
}
|
|
4118
|
+
else {
|
|
4119
|
+
throw error;
|
|
4120
|
+
}
|
|
4121
|
+
}
|
|
4122
|
+
this.markThreadSubscribed(appServer, agentSessionId);
|
|
4123
|
+
this.threadProjectPaths.set(agentSessionId, path.resolve(projectPath));
|
|
4124
|
+
resumed = true;
|
|
4125
|
+
if (resumeResponse.thread?.historyMode === 'paginated') {
|
|
4126
|
+
const beforeTurnId = await this.findPaginatedRewindTurnId(appServer, agentSessionId, numTurns, targetAssistantMessageId);
|
|
4127
|
+
const response = await appServer.threadRevert(agentSessionId, beforeTurnId);
|
|
4128
|
+
return !!response.thread;
|
|
4129
|
+
}
|
|
4130
|
+
const response = await appServer.threadRollback(agentSessionId, numTurns);
|
|
4131
|
+
return !!response.thread;
|
|
4132
|
+
}
|
|
4133
|
+
finally {
|
|
4134
|
+
if (resumed) {
|
|
4135
|
+
await this.releaseThreadSubscription(appServer, agentSessionId, 'rollback-finished');
|
|
4136
|
+
}
|
|
4137
|
+
}
|
|
4138
|
+
}
|
|
4139
|
+
async findPaginatedRewindTurnId(appServer, threadId, numTurns, targetAssistantMessageId) {
|
|
4140
|
+
if (targetAssistantMessageId) {
|
|
4141
|
+
const history = await this.readForkHistory(appServer, threadId);
|
|
4142
|
+
const targetTurnId = this.findTurnIdForAssistantMessage(history, targetAssistantMessageId);
|
|
4143
|
+
if (!targetTurnId)
|
|
4144
|
+
throw new Error('Codex paginated rewind target turn not found');
|
|
4145
|
+
return targetTurnId;
|
|
4146
|
+
}
|
|
4147
|
+
let cursor;
|
|
4148
|
+
let seenCursor;
|
|
4149
|
+
let seenTurns = 0;
|
|
4150
|
+
do {
|
|
4151
|
+
const page = await appServer.threadTurnsList(threadId, 100, cursor);
|
|
4152
|
+
for (const turn of page.data ?? []) {
|
|
4153
|
+
if (seenTurns === numTurns - 1) {
|
|
4154
|
+
if (typeof turn.id !== 'string' || !turn.id)
|
|
4155
|
+
throw new Error('Codex paginated thread rewind target has no turn id');
|
|
4156
|
+
return turn.id;
|
|
4157
|
+
}
|
|
4158
|
+
seenTurns++;
|
|
4159
|
+
}
|
|
4160
|
+
const nextCursor = typeof page.nextCursor === 'string' && page.nextCursor ? page.nextCursor : undefined;
|
|
4161
|
+
if (!nextCursor || nextCursor === seenCursor)
|
|
4162
|
+
break;
|
|
4163
|
+
seenCursor = nextCursor;
|
|
4164
|
+
cursor = nextCursor;
|
|
4165
|
+
} while (true);
|
|
4166
|
+
throw new Error('Codex paginated thread has fewer than ' + numTurns + ' turns');
|
|
3997
4167
|
}
|
|
3998
4168
|
async rewindFiles(agentSessionId, projectPath, userMessageId) {
|
|
3999
4169
|
const messages = await this.getSessionMessages(agentSessionId, projectPath);
|
|
@@ -4062,6 +4232,26 @@ export class CodexRunner {
|
|
|
4062
4232
|
parent_tool_use_id: null,
|
|
4063
4233
|
});
|
|
4064
4234
|
}
|
|
4235
|
+
else if (item.id && [
|
|
4236
|
+
'commandExecution', 'mcpToolCall', 'dynamicToolCall', 'fileChange',
|
|
4237
|
+
'webSearch', 'collabAgentToolCall', 'imageView', 'sleep', 'imageGeneration',
|
|
4238
|
+
].includes(item.type || '')) {
|
|
4239
|
+
messages.push({
|
|
4240
|
+
type: 'assistant',
|
|
4241
|
+
uuid: item.id,
|
|
4242
|
+
session_id: threadId,
|
|
4243
|
+
message: { role: 'assistant', content: this.mapCodexToolItemToContent(item) },
|
|
4244
|
+
parent_tool_use_id: null,
|
|
4245
|
+
});
|
|
4246
|
+
if (item.type === 'fileChange')
|
|
4247
|
+
messages.push({
|
|
4248
|
+
type: 'system',
|
|
4249
|
+
uuid: `${item.id}-file-change`,
|
|
4250
|
+
session_id: threadId,
|
|
4251
|
+
message: { role: 'system', content: this.mapFileChangeToContent(item) },
|
|
4252
|
+
parent_tool_use_id: null,
|
|
4253
|
+
});
|
|
4254
|
+
}
|
|
4065
4255
|
else if (item.type === 'file_change') {
|
|
4066
4256
|
messages.push({
|
|
4067
4257
|
type: 'system',
|
|
@@ -4075,6 +4265,86 @@ export class CodexRunner {
|
|
|
4075
4265
|
}
|
|
4076
4266
|
return messages;
|
|
4077
4267
|
}
|
|
4268
|
+
/** Preserve the same bounded display data that live tool cards receive. */
|
|
4269
|
+
mapCodexToolItemToContent(item) {
|
|
4270
|
+
const id = typeof item.id === 'string' ? item.id : undefined;
|
|
4271
|
+
const type = item.type || 'tool';
|
|
4272
|
+
let name = type;
|
|
4273
|
+
let input;
|
|
4274
|
+
let result;
|
|
4275
|
+
let isError = false;
|
|
4276
|
+
switch (type) {
|
|
4277
|
+
case 'commandExecution':
|
|
4278
|
+
name = 'Shell';
|
|
4279
|
+
input = { command: item.command, cwd: item.cwd };
|
|
4280
|
+
result = item.aggregatedOutput ?? item.output ?? '';
|
|
4281
|
+
isError = item.exitCode != null
|
|
4282
|
+
? Number(item.exitCode) !== 0
|
|
4283
|
+
: item.status === 'failed' || item.status === 'declined';
|
|
4284
|
+
break;
|
|
4285
|
+
case 'mcpToolCall':
|
|
4286
|
+
name = `MCP:${item.server}/${item.tool}`;
|
|
4287
|
+
input = item.arguments;
|
|
4288
|
+
result = item.result ?? item.contentItems;
|
|
4289
|
+
isError = item.status === 'failed';
|
|
4290
|
+
break;
|
|
4291
|
+
case 'dynamicToolCall':
|
|
4292
|
+
name = item.namespace ? `${item.namespace}:${item.tool}` : String(item.tool || 'tool');
|
|
4293
|
+
input = item.arguments;
|
|
4294
|
+
result = item.result ?? item.contentItems;
|
|
4295
|
+
isError = item.success === false || item.status === 'failed';
|
|
4296
|
+
break;
|
|
4297
|
+
case 'fileChange':
|
|
4298
|
+
name = 'FileChange';
|
|
4299
|
+
input = { changes: item.changes };
|
|
4300
|
+
result = item.changes;
|
|
4301
|
+
isError = item.status === 'failed';
|
|
4302
|
+
break;
|
|
4303
|
+
case 'webSearch':
|
|
4304
|
+
name = 'WebSearch';
|
|
4305
|
+
input = { query: item.query, ...(item.action != null ? { action: item.action } : {}) };
|
|
4306
|
+
result = input;
|
|
4307
|
+
break;
|
|
4308
|
+
case 'collabAgentToolCall':
|
|
4309
|
+
name = `Collab:${item.tool}`;
|
|
4310
|
+
input = {
|
|
4311
|
+
receiverThreadIds: item.receiverThreadIds,
|
|
4312
|
+
...(item.prompt != null ? { prompt: item.prompt } : {}),
|
|
4313
|
+
...(item.model != null ? { model: item.model } : {}),
|
|
4314
|
+
...(item.reasoningEffort != null ? { reasoningEffort: item.reasoningEffort } : {}),
|
|
4315
|
+
};
|
|
4316
|
+
result = item.contentItems ?? { receiverThreadIds: item.receiverThreadIds, agentsStates: item.agentsStates };
|
|
4317
|
+
isError = item.status === 'failed';
|
|
4318
|
+
break;
|
|
4319
|
+
case 'imageView':
|
|
4320
|
+
name = 'ViewImage';
|
|
4321
|
+
input = { path: item.path };
|
|
4322
|
+
result = input;
|
|
4323
|
+
break;
|
|
4324
|
+
case 'sleep':
|
|
4325
|
+
name = 'Sleep';
|
|
4326
|
+
input = { durationMs: item.durationMs };
|
|
4327
|
+
result = input;
|
|
4328
|
+
break;
|
|
4329
|
+
case 'imageGeneration':
|
|
4330
|
+
name = 'ImageGeneration';
|
|
4331
|
+
input = item.revisedPrompt != null ? { prompt: item.revisedPrompt } : {};
|
|
4332
|
+
result = item.result ?? item.output;
|
|
4333
|
+
break;
|
|
4334
|
+
default:
|
|
4335
|
+
input = item.input;
|
|
4336
|
+
result = item.result ?? item.output;
|
|
4337
|
+
}
|
|
4338
|
+
return [
|
|
4339
|
+
{ type: 'tool_use', id, name, input },
|
|
4340
|
+
{
|
|
4341
|
+
type: 'tool_result',
|
|
4342
|
+
...(id ? { tool_use_id: id } : {}),
|
|
4343
|
+
content: result,
|
|
4344
|
+
is_error: isError,
|
|
4345
|
+
},
|
|
4346
|
+
];
|
|
4347
|
+
}
|
|
4078
4348
|
getTurnItems(turn) {
|
|
4079
4349
|
const items = Array.isArray(turn?.items) ? turn.items : [];
|
|
4080
4350
|
const input = Array.isArray(turn?.input) ? turn.input : [];
|
|
@@ -4143,36 +4413,18 @@ export class CodexRunner {
|
|
|
4143
4413
|
this.onCompactStart = callback;
|
|
4144
4414
|
}
|
|
4145
4415
|
// ── Event stream transformation ──
|
|
4146
|
-
buildAppServerInput(prompt, images
|
|
4416
|
+
buildAppServerInput(prompt, images) {
|
|
4147
4417
|
const input = [{ type: 'text', text: prompt, text_elements: [] }];
|
|
4148
4418
|
if (!images?.length)
|
|
4149
4419
|
return input;
|
|
4150
|
-
const
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
|
|
4154
|
-
|
|
4155
|
-
throw new Error('managed TMPDIR is unset or not absolute');
|
|
4156
|
-
for (let i = 0; i < images.length; i++) {
|
|
4157
|
-
const img = images[i];
|
|
4158
|
-
const ext = MIME_EXT[img.mimeType || ''] || '.jpg';
|
|
4159
|
-
const tmpPath = path.join(tmpDir, `evolcore-img-${Date.now()}-${i}${ext}`);
|
|
4160
|
-
fs.writeFileSync(tmpPath, Buffer.from(img.data, 'base64'));
|
|
4161
|
-
tempFiles.push(tmpPath);
|
|
4162
|
-
input.push({ type: 'localImage', path: tmpPath });
|
|
4163
|
-
}
|
|
4164
|
-
logger.info(`[CodexRunner] Attached ${images.length} image(s) as localImage`);
|
|
4165
|
-
return input;
|
|
4166
|
-
}
|
|
4167
|
-
cleanupTempFiles(tempFiles) {
|
|
4168
|
-
if (!tempFiles?.length)
|
|
4169
|
-
return;
|
|
4170
|
-
for (const tempFile of tempFiles) {
|
|
4171
|
-
try {
|
|
4172
|
-
fs.unlinkSync(tempFile);
|
|
4173
|
-
}
|
|
4174
|
-
catch { /* ignore */ }
|
|
4420
|
+
for (const image of images) {
|
|
4421
|
+
input.push({
|
|
4422
|
+
type: 'image',
|
|
4423
|
+
url: `data:${image.mimeType || 'image/png'};base64,${image.data}`,
|
|
4424
|
+
});
|
|
4175
4425
|
}
|
|
4426
|
+
logger.info(`[CodexRunner] Attached ${images.length} image(s) as base64 data URL`);
|
|
4427
|
+
return input;
|
|
4176
4428
|
}
|
|
4177
4429
|
extractTurnId(notification) {
|
|
4178
4430
|
const params = notification.params || {};
|
|
@@ -4293,7 +4545,7 @@ export class CodexRunner {
|
|
|
4293
4545
|
}
|
|
4294
4546
|
queue.end();
|
|
4295
4547
|
}
|
|
4296
|
-
async *transformAppServerStream(notifications, sessionId, state, controller, unsubscribe, appServer
|
|
4548
|
+
async *transformAppServerStream(notifications, sessionId, state, controller, unsubscribe, appServer) {
|
|
4297
4549
|
try {
|
|
4298
4550
|
let sessionIdEmitted = state.committed;
|
|
4299
4551
|
if (sessionIdEmitted)
|
|
@@ -4347,7 +4599,6 @@ export class CodexRunner {
|
|
|
4347
4599
|
for (const childThreadId of state.activeSubagentThreads)
|
|
4348
4600
|
this.unregisterChildThread(childThreadId);
|
|
4349
4601
|
state.activeSubagentThreads.clear();
|
|
4350
|
-
this.cleanupTempFiles(tempFiles);
|
|
4351
4602
|
}
|
|
4352
4603
|
}
|
|
4353
4604
|
*mapAppServerNotification(notification, sessionId, state) {
|
|
@@ -4365,7 +4616,8 @@ export class CodexRunner {
|
|
|
4365
4616
|
case 'item/started': {
|
|
4366
4617
|
for (const event of this.mapAppServerItemStarted(params.item, state)) {
|
|
4367
4618
|
this.trackAppServerToolLifecycle(event, state);
|
|
4368
|
-
yield event
|
|
4619
|
+
yield event.type === 'tool_use' && params.item?.id
|
|
4620
|
+
? { ...event, assistantUuid: params.item.id } : event;
|
|
4369
4621
|
}
|
|
4370
4622
|
break;
|
|
4371
4623
|
}
|
|
@@ -4397,7 +4649,8 @@ export class CodexRunner {
|
|
|
4397
4649
|
state.completedItemIds.add(item.id);
|
|
4398
4650
|
for (const event of this.mapAppServerItemCompleted(item, state)) {
|
|
4399
4651
|
this.trackAppServerToolLifecycle(event, state);
|
|
4400
|
-
yield event
|
|
4652
|
+
yield event.type === 'tool_result' && item?.id
|
|
4653
|
+
? { ...event, assistantUuid: item.id } : event;
|
|
4401
4654
|
}
|
|
4402
4655
|
break;
|
|
4403
4656
|
}
|
|
@@ -4629,6 +4882,9 @@ export class CodexRunner {
|
|
|
4629
4882
|
isError: true,
|
|
4630
4883
|
error: denial.reason,
|
|
4631
4884
|
errorCode: errorCodeForToolDenial(denial.decisionSource, denial.policyCode),
|
|
4885
|
+
...(errorDetailCodeForToolDenial(denial.decisionSource, denial.policyCode, denial.errorDetailCode)
|
|
4886
|
+
? { errorDetailCode: errorDetailCodeForToolDenial(denial.decisionSource, denial.policyCode, denial.errorDetailCode) }
|
|
4887
|
+
: {}),
|
|
4632
4888
|
decision: 'deny',
|
|
4633
4889
|
decisionSource: denial.decisionSource,
|
|
4634
4890
|
policyCode: denial.policyCode,
|
|
@@ -4655,6 +4911,9 @@ export class CodexRunner {
|
|
|
4655
4911
|
isError: true,
|
|
4656
4912
|
error: managedHookDenial.reason,
|
|
4657
4913
|
errorCode: 'POLICY_DENIED',
|
|
4914
|
+
...(errorDetailCodeForToolDenial('policy', managedHookDenial.policyCode, managedHookDenial.errorDetailCode)
|
|
4915
|
+
? { errorDetailCode: errorDetailCodeForToolDenial('policy', managedHookDenial.policyCode, managedHookDenial.errorDetailCode) }
|
|
4916
|
+
: {}),
|
|
4658
4917
|
decision: 'deny',
|
|
4659
4918
|
decisionSource: 'policy',
|
|
4660
4919
|
policyCode: managedHookDenial.policyCode,
|
|
@@ -4716,17 +4975,29 @@ export class CodexRunner {
|
|
|
4716
4975
|
}
|
|
4717
4976
|
break;
|
|
4718
4977
|
case 'commandExecution':
|
|
4719
|
-
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
4729
|
-
|
|
4978
|
+
{
|
|
4979
|
+
const exitCode = typeof item.exitCode === 'number' && Number.isInteger(item.exitCode)
|
|
4980
|
+
? item.exitCode
|
|
4981
|
+
: undefined;
|
|
4982
|
+
const isError = exitCode !== undefined
|
|
4983
|
+
? exitCode !== 0
|
|
4984
|
+
: item.status === 'failed' || item.status === 'declined';
|
|
4985
|
+
yield {
|
|
4986
|
+
type: 'tool_result',
|
|
4987
|
+
name: 'Shell',
|
|
4988
|
+
result: item.aggregatedOutput ?? '',
|
|
4989
|
+
...(blockedFields ?? {
|
|
4990
|
+
isError,
|
|
4991
|
+
...codexItemErrorFields(item),
|
|
4992
|
+
executed: true,
|
|
4993
|
+
executionState: isError ? 'failed' : 'completed',
|
|
4994
|
+
...(exitCode !== undefined ? { exitCode } : {}),
|
|
4995
|
+
}),
|
|
4996
|
+
...(blockedFields ? {} : exitCode !== undefined ? { exitCode } : {}),
|
|
4997
|
+
callId: item.id,
|
|
4998
|
+
durationMs: typeof item.durationMs === 'number' ? item.durationMs : undefined,
|
|
4999
|
+
};
|
|
5000
|
+
}
|
|
4730
5001
|
break;
|
|
4731
5002
|
case 'mcpToolCall':
|
|
4732
5003
|
yield {
|
|
@@ -4735,7 +5006,11 @@ export class CodexRunner {
|
|
|
4735
5006
|
result: item.result,
|
|
4736
5007
|
...(blockedFields ?? { isError: item.status === 'failed' }),
|
|
4737
5008
|
...(blockedFields ? {} : { error: item.error?.message }),
|
|
4738
|
-
...(
|
|
5009
|
+
...(blockedFields ? {} : codexItemErrorFields(item)),
|
|
5010
|
+
...(blockedFields ?? {
|
|
5011
|
+
executed: true,
|
|
5012
|
+
executionState: item.status === 'failed' ? 'failed' : 'completed',
|
|
5013
|
+
}),
|
|
4739
5014
|
callId: item.id,
|
|
4740
5015
|
durationMs: typeof item.durationMs === 'number' ? item.durationMs : undefined,
|
|
4741
5016
|
};
|
|
@@ -4746,7 +5021,11 @@ export class CodexRunner {
|
|
|
4746
5021
|
name: item.namespace ? `${item.namespace}:${item.tool}` : item.tool,
|
|
4747
5022
|
result: item.contentItems,
|
|
4748
5023
|
...(blockedFields ?? { isError: item.success === false || item.status === 'failed' }),
|
|
4749
|
-
...(
|
|
5024
|
+
...(blockedFields ? {} : codexItemErrorFields(item)),
|
|
5025
|
+
...(blockedFields ?? {
|
|
5026
|
+
executed: true,
|
|
5027
|
+
executionState: item.success === false || item.status === 'failed' ? 'failed' : 'completed',
|
|
5028
|
+
}),
|
|
4750
5029
|
callId: item.id,
|
|
4751
5030
|
durationMs: typeof item.durationMs === 'number' ? item.durationMs : undefined,
|
|
4752
5031
|
};
|
|
@@ -4760,12 +5039,34 @@ export class CodexRunner {
|
|
|
4760
5039
|
yield editEvent;
|
|
4761
5040
|
}
|
|
4762
5041
|
}
|
|
4763
|
-
yield {
|
|
5042
|
+
yield {
|
|
5043
|
+
type: 'tool_result',
|
|
5044
|
+
name: 'Edit',
|
|
5045
|
+
result: item.changes,
|
|
5046
|
+
...(blockedFields ?? {
|
|
5047
|
+
isError: item.status === 'failed',
|
|
5048
|
+
executed: true,
|
|
5049
|
+
executionState: item.status === 'failed' ? 'failed' : 'completed',
|
|
5050
|
+
...codexItemErrorFields(item),
|
|
5051
|
+
}),
|
|
5052
|
+
callId: item.id,
|
|
5053
|
+
};
|
|
4764
5054
|
}
|
|
4765
5055
|
else {
|
|
4766
5056
|
const desc = this.normalizeFileChanges(item.changes).map((change) => this.describeFileChange(change)).join(', ');
|
|
4767
5057
|
yield { type: 'tool_use', name: 'FileChange', input: { description: desc }, callId: item.id };
|
|
4768
|
-
yield {
|
|
5058
|
+
yield {
|
|
5059
|
+
type: 'tool_result',
|
|
5060
|
+
name: 'FileChange',
|
|
5061
|
+
result: item.changes,
|
|
5062
|
+
...(blockedFields ?? {
|
|
5063
|
+
isError: item.status === 'failed',
|
|
5064
|
+
executed: true,
|
|
5065
|
+
executionState: item.status === 'failed' ? 'failed' : 'completed',
|
|
5066
|
+
...codexItemErrorFields(item),
|
|
5067
|
+
}),
|
|
5068
|
+
callId: item.id,
|
|
5069
|
+
};
|
|
4769
5070
|
}
|
|
4770
5071
|
break;
|
|
4771
5072
|
case 'webSearch':
|
|
@@ -4970,7 +5271,7 @@ export class CodexRunner {
|
|
|
4970
5271
|
const managedTempDir = ensureSessionRuntimeDir(sessionId);
|
|
4971
5272
|
if (!managedTempDir)
|
|
4972
5273
|
return undefined;
|
|
4973
|
-
return `临时文件必须使用环境变量 \`$TMPDIR\`。当前值是 \`${managedTempDir}\`,它是当前 EvolCore 会话唯一允许的临时工作区;不要直接使用 \`/tmp\`,也不要使用其他会话的临时目录。该目录随 EvolCore sessionId 保持稳定;若文件不存在,请先在当前 \`$TMPDIR\` 重新创建,再继续执行后续 \`ec\`
|
|
5274
|
+
return `临时文件必须使用环境变量 \`$TMPDIR\`。当前值是 \`${managedTempDir}\`,它是当前 EvolCore 会话唯一允许的临时工作区;不要直接使用 \`/tmp\`,也不要使用其他会话的临时目录。该目录随 EvolCore sessionId 保持稳定;若文件不存在,请先在当前 \`$TMPDIR\` 重新创建,再继续执行后续 \`ec\` 命令。文件修改优先使用 Codex 原生 FileChange/Edit;若当前 Codex 版本未暴露该工具,可使用独立且可解析的 \`apply_patch\` patch。不得把 patch 与其它命令拼接、放入管道或使用任意重定向;目标文件仍受 workspace、H/L 路径和当前权限模式限制。`;
|
|
4974
5275
|
}
|
|
4975
5276
|
buildEvolcoreShellEnvironmentConfig(sessionId, sessionToken, taskDelegationToken) {
|
|
4976
5277
|
const managedTempDir = ensureSessionRuntimeDir(sessionId);
|