@ccpocket/bridge 1.71.0 → 1.72.1
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/codex-process.d.ts +5 -4
- package/dist/codex-process.js +187 -34
- package/dist/codex-process.js.map +1 -1
- package/dist/directory-listing.d.ts +2 -2
- package/dist/directory-listing.js +4 -3
- package/dist/directory-listing.js.map +1 -1
- package/dist/parser.d.ts +10 -0
- package/dist/parser.js +6 -1
- package/dist/parser.js.map +1 -1
- package/dist/push-relay.d.ts +2 -0
- package/dist/push-relay.js +1 -0
- package/dist/push-relay.js.map +1 -1
- package/dist/sdk-process.d.ts +4 -4
- package/dist/sdk-process.js +8 -4
- package/dist/sdk-process.js.map +1 -1
- package/dist/websocket.d.ts +10 -1
- package/dist/websocket.js +137 -41
- package/dist/websocket.js.map +1 -1
- package/package.json +1 -1
package/dist/codex-process.d.ts
CHANGED
|
@@ -284,10 +284,10 @@ export declare class CodexProcess extends EventEmitter<CodexProcessEvents> {
|
|
|
284
284
|
path: string;
|
|
285
285
|
}>;
|
|
286
286
|
}): Promise<void>;
|
|
287
|
-
approve(toolUseId?: string):
|
|
288
|
-
approveAlways(toolUseId?: string):
|
|
289
|
-
reject(toolUseId?: string, _message?: string):
|
|
290
|
-
answer(toolUseId: string, result: string):
|
|
287
|
+
approve(toolUseId?: string): boolean;
|
|
288
|
+
approveAlways(toolUseId?: string): boolean;
|
|
289
|
+
reject(toolUseId?: string, _message?: string): boolean;
|
|
290
|
+
answer(toolUseId: string, result: string): boolean;
|
|
291
291
|
/**
|
|
292
292
|
* Install a plugin or begin connector authentication proposed by Codex.
|
|
293
293
|
* The elicitation remains pending while external app authentication is
|
|
@@ -326,6 +326,7 @@ export declare class CodexProcess extends EventEmitter<CodexProcessEvents> {
|
|
|
326
326
|
private handlePlanRejected;
|
|
327
327
|
private bootstrap;
|
|
328
328
|
private resolveWritableRootsConfig;
|
|
329
|
+
private readConfigPermissions;
|
|
329
330
|
private initializeRpcConnection;
|
|
330
331
|
readProfileConfig(cwd?: string): Promise<CodexProfileConfig>;
|
|
331
332
|
readConfigRequirements(): Promise<CodexConfigRequirements>;
|
package/dist/codex-process.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { EventEmitter } from "node:events";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
|
+
import { realpathSync, statSync } from "node:fs";
|
|
3
4
|
import { tmpdir } from "node:os";
|
|
4
|
-
import { join } from "node:path";
|
|
5
|
+
import { dirname, join } from "node:path";
|
|
5
6
|
import { rm, writeFile } from "node:fs/promises";
|
|
6
7
|
import { createCodexTransport, buildCodexSpawnSpec, } from "./codex-transport.js";
|
|
7
8
|
import { codexCliJoinTarget } from "./codex-app-server-config.js";
|
|
@@ -144,7 +145,7 @@ export class CodexProcess extends EventEmitter {
|
|
|
144
145
|
return this.transport?.isRunning ?? false;
|
|
145
146
|
}
|
|
146
147
|
get approvalPolicy() {
|
|
147
|
-
return this._approvalPolicy
|
|
148
|
+
return approvalPolicyForClient(this._approvalPolicy);
|
|
148
149
|
}
|
|
149
150
|
get approvalsReviewer() {
|
|
150
151
|
return normalizeApprovalsReviewerForClient(this._approvalsReviewer);
|
|
@@ -595,73 +596,78 @@ export class CodexProcess extends EventEmitter {
|
|
|
595
596
|
if (this.pendingPlanCompletion &&
|
|
596
597
|
toolUseId === this.pendingPlanCompletion.toolUseId) {
|
|
597
598
|
this.handlePlanApproved();
|
|
598
|
-
return;
|
|
599
|
+
return true;
|
|
599
600
|
}
|
|
600
601
|
const pending = this.resolvePendingApproval(toolUseId);
|
|
601
602
|
if (!pending) {
|
|
602
603
|
// Fallback: McpElicitation lives in pendingUserInputs
|
|
603
604
|
if (this.approveUserInput(toolUseId, "Accept"))
|
|
604
|
-
return;
|
|
605
|
+
return true;
|
|
605
606
|
console.log("[codex-process] approve() called but no pending permission requests");
|
|
606
|
-
return;
|
|
607
|
+
return false;
|
|
607
608
|
}
|
|
608
609
|
this.pendingApprovals.delete(pending.toolUseId);
|
|
609
610
|
this.respondToServerRequest(pending.requestId, buildApprovalResponse(pending, "accept"));
|
|
610
|
-
this.emitToolResult(pending.toolUseId, "Approved");
|
|
611
|
+
this.emitToolResult(pending.toolUseId, "Approved", "approved");
|
|
611
612
|
if (this.pendingApprovals.size === 0) {
|
|
612
613
|
this.setStatus("running");
|
|
613
614
|
}
|
|
615
|
+
return true;
|
|
614
616
|
}
|
|
615
617
|
approveAlways(toolUseId) {
|
|
616
618
|
const pending = this.resolvePendingApproval(toolUseId);
|
|
617
619
|
if (!pending) {
|
|
618
620
|
// Fallback: McpElicitation lives in pendingUserInputs
|
|
619
|
-
if (this.approveUserInput(toolUseId, "Allow for this session"))
|
|
620
|
-
return;
|
|
621
|
+
if (this.approveUserInput(toolUseId, "Allow for this session")) {
|
|
622
|
+
return true;
|
|
623
|
+
}
|
|
621
624
|
console.log("[codex-process] approveAlways() called but no pending permission requests");
|
|
622
|
-
return;
|
|
625
|
+
return false;
|
|
623
626
|
}
|
|
624
627
|
this.pendingApprovals.delete(pending.toolUseId);
|
|
625
628
|
this.respondToServerRequest(pending.requestId, buildApprovalResponse(pending, "acceptForSession"));
|
|
626
|
-
this.emitToolResult(pending.toolUseId, "Approved (always)");
|
|
629
|
+
this.emitToolResult(pending.toolUseId, "Approved (always)", "approved_for_session");
|
|
627
630
|
if (this.pendingApprovals.size === 0) {
|
|
628
631
|
this.setStatus("running");
|
|
629
632
|
}
|
|
633
|
+
return true;
|
|
630
634
|
}
|
|
631
635
|
reject(toolUseId, _message) {
|
|
632
636
|
// Check if this is a plan completion rejection
|
|
633
637
|
if (this.pendingPlanCompletion &&
|
|
634
638
|
toolUseId === this.pendingPlanCompletion.toolUseId) {
|
|
635
639
|
this.handlePlanRejected(_message);
|
|
636
|
-
return;
|
|
640
|
+
return true;
|
|
637
641
|
}
|
|
638
642
|
const pending = this.resolvePendingApproval(toolUseId);
|
|
639
643
|
if (!pending) {
|
|
640
644
|
// Fallback: McpElicitation lives in pendingUserInputs
|
|
641
645
|
if (this.rejectUserInput(toolUseId, "Decline"))
|
|
642
|
-
return;
|
|
646
|
+
return true;
|
|
643
647
|
console.log("[codex-process] reject() called but no pending permission requests");
|
|
644
|
-
return;
|
|
648
|
+
return false;
|
|
645
649
|
}
|
|
646
650
|
this.pendingApprovals.delete(pending.toolUseId);
|
|
647
651
|
this.respondToServerRequest(pending.requestId, buildApprovalResponse(pending, resolveApprovalRejectDecision(pending)));
|
|
648
|
-
this.emitToolResult(pending.toolUseId, "Rejected");
|
|
652
|
+
this.emitToolResult(pending.toolUseId, "Rejected", "rejected");
|
|
649
653
|
if (this.pendingApprovals.size === 0) {
|
|
650
654
|
this.setStatus("running");
|
|
651
655
|
}
|
|
656
|
+
return true;
|
|
652
657
|
}
|
|
653
658
|
answer(toolUseId, result) {
|
|
654
659
|
const pending = this.resolvePendingUserInput(toolUseId);
|
|
655
660
|
if (!pending) {
|
|
656
661
|
console.log("[codex-process] answer() called but no pending AskUserQuestion");
|
|
657
|
-
return;
|
|
662
|
+
return false;
|
|
658
663
|
}
|
|
659
664
|
this.pendingUserInputs.delete(pending.toolUseId);
|
|
660
665
|
this.respondToServerRequest(pending.requestId, buildUserInputResponse(pending, result));
|
|
661
|
-
this.emitToolResult(pending.toolUseId, "Answered");
|
|
666
|
+
this.emitToolResult(pending.toolUseId, "Answered", "answered");
|
|
662
667
|
if (this.pendingApprovals.size === 0 && this.pendingUserInputs.size === 0) {
|
|
663
668
|
this.setStatus("running");
|
|
664
669
|
}
|
|
670
|
+
return true;
|
|
665
671
|
}
|
|
666
672
|
/**
|
|
667
673
|
* Install a plugin or begin connector authentication proposed by Codex.
|
|
@@ -780,11 +786,12 @@ export class CodexProcess extends EventEmitter {
|
|
|
780
786
|
};
|
|
781
787
|
}
|
|
782
788
|
/** Emit a synthetic tool_result so history replay can match it to a permission_request. */
|
|
783
|
-
emitToolResult(toolUseId, content) {
|
|
789
|
+
emitToolResult(toolUseId, content, permissionOutcome) {
|
|
784
790
|
this.emitMessage({
|
|
785
791
|
type: "tool_result",
|
|
786
792
|
toolUseId,
|
|
787
793
|
content,
|
|
794
|
+
...(permissionOutcome ? { permissionOutcome } : {}),
|
|
788
795
|
});
|
|
789
796
|
}
|
|
790
797
|
resolvePendingApproval(toolUseId) {
|
|
@@ -820,7 +827,9 @@ export class CodexProcess extends EventEmitter {
|
|
|
820
827
|
}
|
|
821
828
|
this.pendingUserInputs.delete(pending.toolUseId);
|
|
822
829
|
this.respondToServerRequest(pending.requestId, buildUserInputResponse(pending, result));
|
|
823
|
-
this.emitToolResult(pending.toolUseId, "Approved"
|
|
830
|
+
this.emitToolResult(pending.toolUseId, "Approved", result === "Allow for this session"
|
|
831
|
+
? "approved_for_session"
|
|
832
|
+
: "approved");
|
|
824
833
|
if (this.pendingApprovals.size === 0 && this.pendingUserInputs.size === 0) {
|
|
825
834
|
this.setStatus("running");
|
|
826
835
|
}
|
|
@@ -860,7 +869,7 @@ export class CodexProcess extends EventEmitter {
|
|
|
860
869
|
return false;
|
|
861
870
|
this.pendingUserInputs.delete(pending.toolUseId);
|
|
862
871
|
this.respondToServerRequest(pending.requestId, buildUserInputResponse(pending, resolveUserInputRejectResult(pending, result)));
|
|
863
|
-
this.emitToolResult(pending.toolUseId, "Rejected");
|
|
872
|
+
this.emitToolResult(pending.toolUseId, "Rejected", "rejected");
|
|
864
873
|
if (this.pendingApprovals.size === 0 && this.pendingUserInputs.size === 0) {
|
|
865
874
|
this.setStatus("running");
|
|
866
875
|
}
|
|
@@ -929,12 +938,21 @@ export class CodexProcess extends EventEmitter {
|
|
|
929
938
|
? (await this.readConfigRequirements()).autoReviewDisabled
|
|
930
939
|
: options?.autoReviewDisabledByPolicy === true;
|
|
931
940
|
this._autoReviewDisabledByPolicy = autoReviewDisabled;
|
|
932
|
-
const effectiveApprovalsReviewer = autoReviewDisabled
|
|
933
|
-
? "user"
|
|
934
|
-
: options?.approvalsReviewer;
|
|
935
941
|
const effectiveCodexPermissionsMode = autoReviewDisabled && options?.codexPermissionsMode === "autoReview"
|
|
936
942
|
? "default"
|
|
937
943
|
: options?.codexPermissionsMode;
|
|
944
|
+
// thread/resume preserves the thread's prior permission overrides when
|
|
945
|
+
// these fields are omitted. Custom mode and named profiles mean the
|
|
946
|
+
// current config.toml should win, so resolve it and pass the effective
|
|
947
|
+
// values explicitly on resume.
|
|
948
|
+
const configResumePermissions = options?.threadId &&
|
|
949
|
+
(effectiveCodexPermissionsMode === "custom" || options.profile)
|
|
950
|
+
? await this.readConfigPermissions(projectPath, options.profile)
|
|
951
|
+
: undefined;
|
|
952
|
+
const effectiveApprovalsReviewer = autoReviewDisabled
|
|
953
|
+
? "user"
|
|
954
|
+
: (configResumePermissions?.approvalsReviewer ??
|
|
955
|
+
options?.approvalsReviewer);
|
|
938
956
|
if (autoReviewDisabled) {
|
|
939
957
|
console.warn("[codex-process] Auto-review disabled by managed Browser Use policy");
|
|
940
958
|
}
|
|
@@ -943,15 +961,17 @@ export class CodexProcess extends EventEmitter {
|
|
|
943
961
|
? undefined
|
|
944
962
|
: normalizeApprovalsReviewerForAppServer(effectiveApprovalsReviewer);
|
|
945
963
|
this._codexPermissionsMode = effectiveCodexPermissionsMode;
|
|
946
|
-
const
|
|
947
|
-
|
|
964
|
+
const configuredApprovalPolicy = configResumePermissions?.approvalPolicy ?? options?.approvalPolicy;
|
|
965
|
+
const requestedApprovalPolicy = configuredApprovalPolicy
|
|
966
|
+
? normalizeApprovalPolicyForRpc(configuredApprovalPolicy)
|
|
948
967
|
: undefined;
|
|
949
968
|
const requestedApprovalsReviewer = effectiveApprovalsReviewer === undefined
|
|
950
969
|
? undefined
|
|
951
970
|
: normalizeApprovalsReviewerForAppServer(effectiveApprovalsReviewer);
|
|
952
971
|
const requestedClientApprovalsReviewer = normalizeApprovalsReviewerForClient(effectiveApprovalsReviewer);
|
|
953
|
-
const
|
|
954
|
-
|
|
972
|
+
const configuredSandboxMode = configResumePermissions?.sandboxMode ?? options?.sandboxMode;
|
|
973
|
+
const requestedSandboxMode = configuredSandboxMode
|
|
974
|
+
? normalizeSandboxMode(configuredSandboxMode)
|
|
955
975
|
: undefined;
|
|
956
976
|
const threadParams = {
|
|
957
977
|
cwd: projectPath,
|
|
@@ -1025,14 +1045,15 @@ export class CodexProcess extends EventEmitter {
|
|
|
1025
1045
|
this.startModel = thread.model;
|
|
1026
1046
|
}
|
|
1027
1047
|
const resolvedSettings = extractResolvedSettingsFromThreadResponse(response);
|
|
1048
|
+
const activeApprovalPolicy = resolvedSettings.approvalPolicy ?? requestedApprovalPolicy;
|
|
1028
1049
|
const resolvedApprovalsReviewer = autoReviewDisabled
|
|
1029
1050
|
? "user"
|
|
1030
1051
|
: resolvedSettings.approvalsReviewer;
|
|
1031
1052
|
if (resolvedSettings.model) {
|
|
1032
1053
|
this.startModel = resolvedSettings.model;
|
|
1033
1054
|
}
|
|
1034
|
-
if (
|
|
1035
|
-
this._approvalPolicy =
|
|
1055
|
+
if (activeApprovalPolicy) {
|
|
1056
|
+
this._approvalPolicy = activeApprovalPolicy;
|
|
1036
1057
|
}
|
|
1037
1058
|
if (resolvedApprovalsReviewer) {
|
|
1038
1059
|
this._approvalsReviewer = normalizeApprovalsReviewerForAppServer(resolvedApprovalsReviewer);
|
|
@@ -1049,9 +1070,9 @@ export class CodexProcess extends EventEmitter {
|
|
|
1049
1070
|
...(sanitizeCodexModel(this.startModel)
|
|
1050
1071
|
? { model: sanitizeCodexModel(this.startModel) }
|
|
1051
1072
|
: {}),
|
|
1052
|
-
...(
|
|
1073
|
+
...(activeApprovalPolicy
|
|
1053
1074
|
? {
|
|
1054
|
-
approvalPolicy:
|
|
1075
|
+
approvalPolicy: approvalPolicyForClient(activeApprovalPolicy),
|
|
1055
1076
|
}
|
|
1056
1077
|
: {}),
|
|
1057
1078
|
...(resolvedApprovalsReviewer ?? effectiveApprovalsReviewer
|
|
@@ -1121,6 +1142,14 @@ export class CodexProcess extends EventEmitter {
|
|
|
1121
1142
|
const configuredRoots = extractWritableRootsFromConfigRead(response);
|
|
1122
1143
|
return normalizeWritableRoots([...configuredRoots, ...normalizedAdditional], this.platform);
|
|
1123
1144
|
}
|
|
1145
|
+
async readConfigPermissions(projectPath, profile) {
|
|
1146
|
+
const projectLookupPaths = resolveConfigProjectLookupPaths(projectPath);
|
|
1147
|
+
const response = await this.request("config/read", {
|
|
1148
|
+
includeLayers: false,
|
|
1149
|
+
cwd: projectPath,
|
|
1150
|
+
});
|
|
1151
|
+
return extractPermissionsFromConfigRead(response, projectLookupPaths, this.platform, profile);
|
|
1152
|
+
}
|
|
1124
1153
|
async initializeRpcConnection() {
|
|
1125
1154
|
await this.request("initialize", {
|
|
1126
1155
|
clientInfo: {
|
|
@@ -1365,7 +1394,7 @@ export class CodexProcess extends EventEmitter {
|
|
|
1365
1394
|
input,
|
|
1366
1395
|
};
|
|
1367
1396
|
if (this._approvalPolicy) {
|
|
1368
|
-
params.approvalPolicy =
|
|
1397
|
+
params.approvalPolicy = normalizeApprovalPolicyForRpc(this._approvalPolicy);
|
|
1369
1398
|
}
|
|
1370
1399
|
if (this._approvalsReviewer) {
|
|
1371
1400
|
params.approvalsReviewer = normalizeApprovalsReviewerForAppServer(this._approvalsReviewer);
|
|
@@ -2591,6 +2620,122 @@ function extractWritableRootsFromConfigRead(response) {
|
|
|
2591
2620
|
return [];
|
|
2592
2621
|
return writableRoots.filter((root) => typeof root === "string");
|
|
2593
2622
|
}
|
|
2623
|
+
function extractPermissionsFromConfigRead(response, projectLookupPaths, platform, profile) {
|
|
2624
|
+
const config = asRecord(asRecord(response)?.config);
|
|
2625
|
+
const profiles = asRecord(config?.profiles);
|
|
2626
|
+
const configuredDefaultProfile = typeof config?.profile === "string" && config.profile.trim()
|
|
2627
|
+
? config.profile.trim()
|
|
2628
|
+
: undefined;
|
|
2629
|
+
const requestedProfile = profile?.trim() || undefined;
|
|
2630
|
+
const selectedProfile = requestedProfile ?? configuredDefaultProfile;
|
|
2631
|
+
const profileConfig = selectedProfile
|
|
2632
|
+
? asRecord(profiles?.[selectedProfile])
|
|
2633
|
+
: undefined;
|
|
2634
|
+
const configuredValue = (key) => profileConfig?.[key] ?? config?.[key];
|
|
2635
|
+
const projectTrust = findProjectTrust(config, projectLookupPaths, platform);
|
|
2636
|
+
return {
|
|
2637
|
+
approvalPolicy: parseConfigApprovalPolicy(configuredValue("approval_policy")) ??
|
|
2638
|
+
(projectTrust === "untrusted" ? "untrusted" : "on-request"),
|
|
2639
|
+
approvalsReviewer: parseConfigApprovalsReviewer(configuredValue("approvals_reviewer")) ??
|
|
2640
|
+
"user",
|
|
2641
|
+
sandboxMode: parseConfigSandboxMode(configuredValue("sandbox_mode")) ??
|
|
2642
|
+
(projectTrust !== undefined && platform !== "win32"
|
|
2643
|
+
? "workspace-write"
|
|
2644
|
+
: "read-only"),
|
|
2645
|
+
};
|
|
2646
|
+
}
|
|
2647
|
+
function findProjectTrust(config, projectLookupPaths, platform) {
|
|
2648
|
+
const projects = asRecord(config?.projects);
|
|
2649
|
+
if (!projects)
|
|
2650
|
+
return undefined;
|
|
2651
|
+
const projectEntries = Object.entries(projects);
|
|
2652
|
+
for (const lookupPath of projectLookupPaths) {
|
|
2653
|
+
const normalizedLookupPath = normalizeConfigPath(lookupPath, platform);
|
|
2654
|
+
for (const [configuredPath, rawProject] of projectEntries) {
|
|
2655
|
+
if (normalizeConfigPath(configuredPath, platform) !== normalizedLookupPath) {
|
|
2656
|
+
continue;
|
|
2657
|
+
}
|
|
2658
|
+
const trustLevel = asRecord(rawProject)?.trust_level;
|
|
2659
|
+
if (trustLevel === "trusted" || trustLevel === "untrusted") {
|
|
2660
|
+
return trustLevel;
|
|
2661
|
+
}
|
|
2662
|
+
}
|
|
2663
|
+
}
|
|
2664
|
+
return undefined;
|
|
2665
|
+
}
|
|
2666
|
+
function resolveConfigProjectLookupPaths(projectPath) {
|
|
2667
|
+
const lookupPaths = new Set();
|
|
2668
|
+
let canonicalPath;
|
|
2669
|
+
try {
|
|
2670
|
+
canonicalPath = realpathSync(projectPath);
|
|
2671
|
+
lookupPaths.add(canonicalPath);
|
|
2672
|
+
lookupPaths.add(projectPath);
|
|
2673
|
+
}
|
|
2674
|
+
catch {
|
|
2675
|
+
return [projectPath];
|
|
2676
|
+
}
|
|
2677
|
+
let candidate = canonicalPath;
|
|
2678
|
+
while (true) {
|
|
2679
|
+
try {
|
|
2680
|
+
statSync(join(candidate, ".git"));
|
|
2681
|
+
lookupPaths.add(candidate);
|
|
2682
|
+
break;
|
|
2683
|
+
}
|
|
2684
|
+
catch {
|
|
2685
|
+
const parent = dirname(candidate);
|
|
2686
|
+
if (parent === candidate)
|
|
2687
|
+
break;
|
|
2688
|
+
candidate = parent;
|
|
2689
|
+
}
|
|
2690
|
+
}
|
|
2691
|
+
return [...lookupPaths];
|
|
2692
|
+
}
|
|
2693
|
+
function normalizeConfigPath(value, platform) {
|
|
2694
|
+
const normalized = resolvePlatformPath(value, platform);
|
|
2695
|
+
return platform === "win32" ? normalized.toLowerCase() : normalized;
|
|
2696
|
+
}
|
|
2697
|
+
function parseConfigApprovalPolicy(value) {
|
|
2698
|
+
switch (value) {
|
|
2699
|
+
case "never":
|
|
2700
|
+
case "on-request":
|
|
2701
|
+
case "on-failure":
|
|
2702
|
+
case "untrusted":
|
|
2703
|
+
return value;
|
|
2704
|
+
default:
|
|
2705
|
+
return isGranularApprovalPolicy(value) ? { ...value } : undefined;
|
|
2706
|
+
}
|
|
2707
|
+
}
|
|
2708
|
+
function isGranularApprovalPolicy(value) {
|
|
2709
|
+
const granular = asRecord(asRecord(value)?.granular);
|
|
2710
|
+
return (granular !== undefined &&
|
|
2711
|
+
typeof granular.sandbox_approval === "boolean" &&
|
|
2712
|
+
typeof granular.rules === "boolean" &&
|
|
2713
|
+
typeof granular.mcp_elicitations === "boolean" &&
|
|
2714
|
+
(granular.skill_approval === undefined ||
|
|
2715
|
+
typeof granular.skill_approval === "boolean") &&
|
|
2716
|
+
(granular.request_permissions === undefined ||
|
|
2717
|
+
typeof granular.request_permissions === "boolean"));
|
|
2718
|
+
}
|
|
2719
|
+
function parseConfigApprovalsReviewer(value) {
|
|
2720
|
+
switch (value) {
|
|
2721
|
+
case "user":
|
|
2722
|
+
case "auto_review":
|
|
2723
|
+
case "guardian_subagent":
|
|
2724
|
+
return value;
|
|
2725
|
+
default:
|
|
2726
|
+
return undefined;
|
|
2727
|
+
}
|
|
2728
|
+
}
|
|
2729
|
+
function parseConfigSandboxMode(value) {
|
|
2730
|
+
switch (value) {
|
|
2731
|
+
case "read-only":
|
|
2732
|
+
case "workspace-write":
|
|
2733
|
+
case "danger-full-access":
|
|
2734
|
+
return value;
|
|
2735
|
+
default:
|
|
2736
|
+
return undefined;
|
|
2737
|
+
}
|
|
2738
|
+
}
|
|
2594
2739
|
function normalizeWritableRoots(roots, platform) {
|
|
2595
2740
|
const normalized = new Map();
|
|
2596
2741
|
for (const root of roots) {
|
|
@@ -2618,6 +2763,16 @@ function normalizeApprovalPolicy(value) {
|
|
|
2618
2763
|
return "never";
|
|
2619
2764
|
}
|
|
2620
2765
|
}
|
|
2766
|
+
function normalizeApprovalPolicyForRpc(value) {
|
|
2767
|
+
return typeof value === "string" ? normalizeApprovalPolicy(value) : value;
|
|
2768
|
+
}
|
|
2769
|
+
function approvalPolicyForClient(value) {
|
|
2770
|
+
// Mobile's legacy mode model cannot represent granular policies. They still
|
|
2771
|
+
// request approval conditionally, so on-request is the closest UI projection.
|
|
2772
|
+
return typeof value === "string"
|
|
2773
|
+
? value
|
|
2774
|
+
: "on-request";
|
|
2775
|
+
}
|
|
2621
2776
|
function normalizeApprovalsReviewerForAppServer(value) {
|
|
2622
2777
|
switch (value) {
|
|
2623
2778
|
case "auto_review":
|
|
@@ -2738,9 +2893,7 @@ function extractResolvedSettingsFromThreadResponse(response) {
|
|
|
2738
2893
|
return {
|
|
2739
2894
|
model: sanitizeCodexModel(response.model)
|
|
2740
2895
|
?? sanitizeCodexModel(thread?.model),
|
|
2741
|
-
approvalPolicy:
|
|
2742
|
-
? response.approvalPolicy
|
|
2743
|
-
: undefined,
|
|
2896
|
+
approvalPolicy: parseConfigApprovalPolicy(response.approvalPolicy),
|
|
2744
2897
|
approvalsReviewer: typeof response.approvalsReviewer === "string"
|
|
2745
2898
|
? response.approvalsReviewer
|
|
2746
2899
|
: undefined,
|