Harden read-only thread handling and refresh Android releases

This commit is contained in:
kris
2026-04-06 13:26:48 +08:00
parent 9d7d2f4d17
commit 3564aeaf2e
18 changed files with 346 additions and 27 deletions

View File

@@ -10,6 +10,24 @@ function trimToDefined(value) {
return trimmed ? trimmed : undefined;
}
function parseSandboxPolicyType(value) {
const raw = trimToDefined(value);
if (!raw) {
return undefined;
}
try {
const parsed = JSON.parse(raw);
return trimToDefined(parsed?.type) || raw;
} catch {
return raw;
}
}
function isReadOnlySandboxPolicy(value) {
return parseSandboxPolicyType(value) === "read-only";
}
function resolveResumeTarget(config, task) {
const targetThreadRef = trimToDefined(task?.targetCodexThreadRef || task?.targetThreadId);
const targetFolderRef = trimToDefined(
@@ -74,7 +92,7 @@ function inspectCodexThreadBinding(config, targetThreadRef, targetFolderRef) {
const db = new DatabaseSync(stateDbPath, { readonly: true });
try {
const row = db
.prepare("SELECT id, cwd, archived FROM threads WHERE id = ? LIMIT 1")
.prepare("SELECT id, cwd, archived, sandbox_policy FROM threads WHERE id = ? LIMIT 1")
.get(targetThreadRef);
if (!row || row.archived) {
return {
@@ -82,6 +100,14 @@ function inspectCodexThreadBinding(config, targetThreadRef, targetFolderRef) {
};
}
const sandboxPolicyType = parseSandboxPolicyType(row.sandbox_policy);
if (isReadOnlySandboxPolicy(row.sandbox_policy)) {
return {
status: "read_only",
sandboxPolicyType,
};
}
const workspaceHints = loadThreadWorkspaceHints(
trimToDefined(config?.codexGlobalStatePath || defaultCodexPath(".codex-global-state.json")),
);
@@ -148,6 +174,21 @@ export async function prepareCodexTaskExecution(config, task, outputFile) {
};
}
if (bindingInspection.status === "read_only") {
return {
ok: false,
error: buildStructuredTaskBindingError(
"LOCAL_AGENT_CODEX_THREAD_READ_ONLY",
`LOCAL_AGENT_CODEX_THREAD_READ_ONLY: 目标线程当前是只读会话,已拒绝 codex exec resume。thread=${targetThreadRef} sandbox=${bindingInspection.sandboxPolicyType ?? "read-only"}`,
{
targetThreadRef,
targetCodexFolderRef: resumeTarget.targetFolderRef,
sandboxPolicyType: bindingInspection.sandboxPolicyType,
},
),
};
}
try {
const folderStat = await stat(resumeTarget.cwd);
if (!folderStat.isDirectory()) {