@covro/covro 0.4.1-dev.3 → 0.4.1-dev.5
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/README.md +3 -1
- package/README.zh-CN.md +3 -1
- package/dist/codex/adapter.js.map +1 -1
- package/dist/codex/mapping.js.map +1 -1
- package/dist/codex/permissions.js.map +1 -1
- package/dist/codex/thread-title-policy.js.map +1 -1
- package/dist/codex/thread-titles.js.map +1 -1
- package/dist/web/assets/{abnfDiagram-WEYOIA3C-QVWC3R6I.js → abnfDiagram-WEYOIA3C-DHDQMgtn.js} +1 -1
- package/dist/web/assets/{arc-DEyELhY2.js → arc-DBsjx_Bn.js} +1 -1
- package/dist/web/assets/{architecture-WOLXFQ4H-DET_LAKO.js → architecture-WOLXFQ4H-DboXGiPf.js} +1 -1
- package/dist/web/assets/{architectureDiagram-ZHVYKT53-BSnhJlXx.js → architectureDiagram-ZHVYKT53-6zaTZR00.js} +1 -1
- package/dist/web/assets/{blockDiagram-RJAE7QA3-6T1OkNkF.js → blockDiagram-RJAE7QA3-DJpVBTJP.js} +1 -1
- package/dist/web/assets/{c4Diagram-XDPPPE54-hZ5xW1AR.js → c4Diagram-XDPPPE54-D5LqlgQv.js} +1 -1
- package/dist/web/assets/channel-orSWAKpM.js +1 -0
- package/dist/web/assets/{chunk-2E7WHVMD-ChY3GfHi.js → chunk-2E7WHVMD-B3IGJNdw.js} +1 -1
- package/dist/web/assets/{chunk-4EMNKR2T-ae1N30q6.js → chunk-4EMNKR2T-BgjUgjkP.js} +1 -1
- package/dist/web/assets/{chunk-55XCU76K-I9ntMYEM.js → chunk-55XCU76K-CHhQ4xeY.js} +1 -1
- package/dist/web/assets/{chunk-7S6XSTFO-D5pnCqzw.js → chunk-7S6XSTFO-DEDigQhX.js} +1 -1
- package/dist/web/assets/{chunk-AQDTSKZB-CcdxrEat.js → chunk-AQDTSKZB-BwuU2cDy.js} +1 -1
- package/dist/web/assets/{chunk-DSNLSHJZ-B-94-Xxe.js → chunk-DSNLSHJZ-DB7XInhk.js} +1 -1
- package/dist/web/assets/{chunk-HAGFOTED-BYCU9_9c.js → chunk-HAGFOTED-2Cr41Af7.js} +1 -1
- package/dist/web/assets/{chunk-HNE4Q36P-e9Xqfxg6.js → chunk-HNE4Q36P-CvzyvtoB.js} +1 -1
- package/dist/web/assets/{chunk-NQOKRVIF-C8AJH7Ht.js → chunk-NQOKRVIF-CGQ1-ATq.js} +1 -1
- package/dist/web/assets/{chunk-UHW7PFBP-DTfKrVGJ.js → chunk-UHW7PFBP-CoG6Kb83.js} +1 -1
- package/dist/web/assets/{chunk-VQ5W62QI-DByjAD7l.js → chunk-VQ5W62QI-BNOV4R-O.js} +1 -1
- package/dist/web/assets/{chunk-WQQL4CDK-CV_DXH9P.js → chunk-WQQL4CDK-CtxTw3mr.js} +1 -1
- package/dist/web/assets/{chunk-XXDRQBXY-C4u34ejs.js → chunk-XXDRQBXY-EWt6CctM.js} +1 -1
- package/dist/web/assets/{chunk-YZO67HFG-BsLEA5oP.js → chunk-YZO67HFG-CQ8iDSEo.js} +1 -1
- package/dist/web/assets/{chunk-ZAUX2LTX-bfHb-tcf.js → chunk-ZAUX2LTX-CPEAUGD-.js} +1 -1
- package/dist/web/assets/{chunk-ZCHMQSOR-BVpIuO5Y.js → chunk-ZCHMQSOR-19krpltl.js} +1 -1
- package/dist/web/assets/{classDiagram-v2-4MYWR3UA-BxvQ2Bmn.js → classDiagram-v2-4MYWR3UA-uIMIqNSn.js} +1 -1
- package/dist/web/assets/{cose-bilkent-JH36ORCC-CMf6uIxX.js → cose-bilkent-JH36ORCC-CBKC8uDS.js} +1 -1
- package/dist/web/assets/{cynefin-EF2NZ3EQ-AKV4fL93.js → cynefin-EF2NZ3EQ-oaKF32Qm.js} +1 -1
- package/dist/web/assets/{cynefinDiagram-WF24UDRP-DMiersRd.js → cynefinDiagram-WF24UDRP-DikhEODc.js} +1 -1
- package/dist/web/assets/{dagre-NK4GIZVX-64J_VOoC.js → dagre-NK4GIZVX-Dewaf2C2.js} +1 -1
- package/dist/web/assets/{diagram-CBK3MWTC-D48MsHcE.js → diagram-CBK3MWTC-BjVtFJGq.js} +1 -1
- package/dist/web/assets/{diagram-I5XIIV2D-DfutAGKo.js → diagram-I5XIIV2D-DhAVVwn3.js} +1 -1
- package/dist/web/assets/{diagram-ODIL2UCW-D3yUJXNy.js → diagram-ODIL2UCW-Bkq6qdoF.js} +1 -1
- package/dist/web/assets/{diagram-PFBEJUXE-YnNFuUYc.js → diagram-PFBEJUXE-D6zn-7Q5.js} +1 -1
- package/dist/web/assets/{diagram-RJA3I4VV-CD97PZ76.js → diagram-RJA3I4VV-DxhiuTXT.js} +1 -1
- package/dist/web/assets/{diagram-TYUNFSNR-z5Qd2vMN.js → diagram-TYUNFSNR-usUcGTk1.js} +1 -1
- package/dist/web/assets/{dist-CGQW_b40.js → dist-DmllBUmo.js} +1 -1
- package/dist/web/assets/{ebnfDiagram-V4P3TTPT-DeSXJa9e.js → ebnfDiagram-V4P3TTPT-DkWP0CoH.js} +1 -1
- package/dist/web/assets/{elk-QONTBCTQ-CZAeOmqm.js → elk-QONTBCTQ-CtqZSgXk.js} +1 -1
- package/dist/web/assets/{erDiagram-KYQIGQAA-C8-6xFVe.js → erDiagram-KYQIGQAA-B6Gb27sC.js} +1 -1
- package/dist/web/assets/{eventmodeling-K75KTNOO-BilNqLgY.js → eventmodeling-K75KTNOO-uVzgkY_P.js} +1 -1
- package/dist/web/assets/flowDiagram-IUGLLWBU-BdBVZhFW.js +1 -0
- package/dist/web/assets/{ganttDiagram-R7GPNTJY-CTDIA-3U.js → ganttDiagram-R7GPNTJY-CjjSaj_8.js} +1 -1
- package/dist/web/assets/{gitGraph-VSP46ZUC-9Ueqob_y.js → gitGraph-VSP46ZUC-C9_56PZI.js} +1 -1
- package/dist/web/assets/{gitGraphDiagram-PDYL7XHY-DjCqE70U.js → gitGraphDiagram-PDYL7XHY-BAoozuuI.js} +1 -1
- package/dist/web/assets/{index-DoTWeRSs.js → index-nALUOGLw.js} +44 -44
- package/dist/web/assets/{info-OHQRW6UA-4QgD83Oz.js → info-OHQRW6UA-Cpmq_I2I.js} +1 -1
- package/dist/web/assets/{infoDiagram-MVDRKAX5-CYxTnNkJ.js → infoDiagram-MVDRKAX5-B0ltS8y6.js} +1 -1
- package/dist/web/assets/{ishikawaDiagram-HPEHV2GE-BZccj2qa.js → ishikawaDiagram-HPEHV2GE-BLd6uzyw.js} +1 -1
- package/dist/web/assets/{journeyDiagram-BOSHW7O7-bfPy2_av.js → journeyDiagram-BOSHW7O7-BW8TLGd2.js} +1 -1
- package/dist/web/assets/{kanban-definition-FNSA4HC5-CxR39mmA.js → kanban-definition-FNSA4HC5-CMP4hD9I.js} +1 -1
- package/dist/web/assets/{line-H5auS6_Y.js → line-GU6Y0sVQ.js} +1 -1
- package/dist/web/assets/{linear-BL-z18Hj.js → linear-sJWCfLK9.js} +1 -1
- package/dist/web/assets/{mermaid-parser.core-B_W4biCD.js → mermaid-parser.core-B1hkQTG_.js} +3 -3
- package/dist/web/assets/{mermaid.core-Beepgkjs.js → mermaid.core-CfGoqGMS.js} +4 -4
- package/dist/web/assets/{mindmap-definition-6OY57UG3-BZ5gpP0y.js → mindmap-definition-6OY57UG3-CqZBW-e4.js} +1 -1
- package/dist/web/assets/{packet-JDAUHWVQ-CxxUCe3A.js → packet-JDAUHWVQ-C__ugQog.js} +1 -1
- package/dist/web/assets/{pegDiagram-ECIUJNBX-K-9r1J3a.js → pegDiagram-ECIUJNBX-CweRsMeQ.js} +1 -1
- package/dist/web/assets/{pie-XZMESJXO-B883_yo5.js → pie-XZMESJXO-uG4onBei.js} +1 -1
- package/dist/web/assets/{pieDiagram-GNMPY74T-BUYVxsL2.js → pieDiagram-GNMPY74T-wxPHT7V2.js} +1 -1
- package/dist/web/assets/{quadrantDiagram-D57K4MC3-A3GUwIAH.js → quadrantDiagram-D57K4MC3-B_OXXhgG.js} +1 -1
- package/dist/web/assets/{radar-ABXABTNO-CHY-Np5u.js → radar-ABXABTNO-xD7Zm3YV.js} +1 -1
- package/dist/web/assets/{railroad-I3PHUGI6-DvPAVo9W.js → railroad-I3PHUGI6-BlQbtB7w.js} +1 -1
- package/dist/web/assets/{railroad-abnf-LNEFI6M7-D8XWiCnb.js → railroad-abnf-LNEFI6M7-Jo8sYA0L.js} +1 -1
- package/dist/web/assets/{railroad-ebnf-DWYD2UWJ-CFZxRf68.js → railroad-ebnf-DWYD2UWJ-DM45xslI.js} +1 -1
- package/dist/web/assets/{railroad-peg-JR7BVNR7-Bq8U-uCa.js → railroad-peg-JR7BVNR7-ByjPCS62.js} +1 -1
- package/dist/web/assets/{railroadDiagram-Y72NRBL7-DqdRB-OO.js → railroadDiagram-Y72NRBL7-70L-z2Rp.js} +1 -1
- package/dist/web/assets/{requirementDiagram-EQYSW5RA-DNyLGlaQ.js → requirementDiagram-EQYSW5RA-DS2ZSobv.js} +1 -1
- package/dist/web/assets/{sankeyDiagram-SY24JHO5-Cc9NdpvU.js → sankeyDiagram-SY24JHO5-D45kBwmB.js} +1 -1
- package/dist/web/assets/{sequenceDiagram-BLEHNHQU-B6s4LYzw.js → sequenceDiagram-BLEHNHQU-GcUSbwA3.js} +1 -1
- package/dist/web/assets/{src-Daamro2k.js → src-DngSB9yt.js} +1 -1
- package/dist/web/assets/{stateDiagram-v2-A6IESKWZ-DZsC7I6h.js → stateDiagram-v2-A6IESKWZ-nE9gEmGS.js} +1 -1
- package/dist/web/assets/{swimlanes-B3ENRKFQ-e5gLbjgX.js → swimlanes-B3ENRKFQ-DI8yBa_2.js} +1 -1
- package/dist/web/assets/swimlanesDiagram-AYQRV4AK-B0WPcCve.js +8 -0
- package/dist/web/assets/{timeline-definition-JXYKGLGB-KK-zQtkG.js → timeline-definition-JXYKGLGB-vp4cb0bp.js} +1 -1
- package/dist/web/assets/{treeView-D4JQ5SDB-CavUsZDU.js → treeView-D4JQ5SDB-CjvXaBJ6.js} +1 -1
- package/dist/web/assets/{treemap-SAJKECNS-7IxwlEJd.js → treemap-SAJKECNS-BtoPti-I.js} +1 -1
- package/dist/web/assets/{usecaseDiagram-WPOLBNNX-DBvINExh.js → usecaseDiagram-WPOLBNNX-CIksWRVE.js} +1 -1
- package/dist/web/assets/{vennDiagram-Q3Y3IDCW-Bux3q39c.js → vennDiagram-Q3Y3IDCW-BAYP4OrS.js} +1 -1
- package/dist/web/assets/{wardley-7MLQ67FV-CxVAZqU7.js → wardley-7MLQ67FV-4crbdNDq.js} +1 -1
- package/dist/web/assets/{wardleyDiagram-IVAIDKWA-Ba6Zh13C.js → wardleyDiagram-IVAIDKWA-BeWIvnug.js} +1 -1
- package/dist/web/assets/{xychartDiagram-4URNHDU4-R2FtAY0N.js → xychartDiagram-4URNHDU4-KshyMIqI.js} +1 -1
- package/dist/web/index.html +1 -1
- package/package.json +5 -5
- package/dist/web/assets/channel-K7c4OCK9.js +0 -1
- package/dist/web/assets/flowDiagram-IUGLLWBU-D_J2KWPh.js +0 -1
- package/dist/web/assets/swimlanesDiagram-AYQRV4AK-DUdGCmdr.js +0 -8
package/README.md
CHANGED
|
@@ -36,6 +36,8 @@
|
|
|
36
36
|
|
|
37
37
|
See the [usage guide · 中文](docs/usage.zh-CN.md) for workflow details and controls.
|
|
38
38
|
|
|
39
|
+
Start a new conversation in the current workspace with **⌘ + Option + N** on macOS or **Ctrl + Alt + N** on Windows/Linux. The message box receives focus and existing drafts stay available.
|
|
40
|
+
|
|
39
41
|
<details>
|
|
40
42
|
<summary><strong>📱 A workspace that fits your phone</strong></summary>
|
|
41
43
|
<img src="docs/assets/workspace-mobile.png" alt="Covro conversation on a phone-sized screen" width="320" />
|
|
@@ -49,7 +51,7 @@ You need **Node.js 24.19 or later in the 24.x line** and an installed, signed-in
|
|
|
49
51
|
|
|
50
52
|
<!-- codex-compatibility:start -->
|
|
51
53
|
|
|
52
|
-
Recommended Codex CLI: **0.
|
|
54
|
+
Recommended Codex CLI: **0.164.0**. Verified versions: `0.164.0`.
|
|
53
55
|
|
|
54
56
|
<!-- codex-compatibility:end -->
|
|
55
57
|
|
package/README.zh-CN.md
CHANGED
|
@@ -36,6 +36,8 @@
|
|
|
36
36
|
|
|
37
37
|
操作方式与使用细节见[使用指南](docs/usage.zh-CN.md)。
|
|
38
38
|
|
|
39
|
+
在当前工作区新建会话:macOS 按 **⌘ + Option + N**,Windows/Linux 按 **Ctrl + Alt + N**。输入框会自动获得焦点,已有草稿继续保留。
|
|
40
|
+
|
|
39
41
|
<details>
|
|
40
42
|
<summary><strong>📱 手机上也能舒服地使用</strong></summary>
|
|
41
43
|
<img src="docs/assets/workspace-mobile.png" alt="手机屏幕上的 Covro 会话" width="320" />
|
|
@@ -49,7 +51,7 @@
|
|
|
49
51
|
|
|
50
52
|
<!-- codex-compatibility:start -->
|
|
51
53
|
|
|
52
|
-
推荐 Codex CLI:**0.
|
|
54
|
+
推荐 Codex CLI:**0.164.0**。已验证版本:`0.164.0`。
|
|
53
55
|
|
|
54
56
|
<!-- codex-compatibility:end -->
|
|
55
57
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/codex/adapter.ts"],
|
|
4
|
-
"sourcesContent": ["import { CODEX_COMPATIBILITY } from './compatibility.js';\nimport { SHELL_TIMEOUT_MS, SHELL_OUTPUT_BYTES } from '../shared/shell.js';\nimport type { CommandExecResponse } from './generated/v2/CommandExecResponse.js';\nimport type { CommandExecTerminateResponse } from './generated/v2/CommandExecTerminateResponse.js';\nimport { spawn, execFile, type ChildProcessWithoutNullStreams } from 'node:child_process';\nimport { randomUUID } from 'node:crypto';\nimport { promisify } from 'node:util';\nimport { ThreadTitles } from './thread-titles.js';\nimport { TurnTokenUsage } from './turn-token-usage.js';\nimport { AppError } from '../shared/errors.js';\nimport { threadNameError } from '../shared/thread-name.js';\nimport { permissionModeUnavailable, permissionReviewerUnavailable } from '../shared/permissions.js';\nimport {\n permissionCapabilities,\n type PermissionRequirements,\n type ProfileProvenance,\n} from './permissions.js';\nimport { mapAutoReview } from './auto-review.js';\nimport {\n normalizeElicitationRequest,\n validateElicitationResolution,\n validatePermissionResolution,\n} from '../shared/elicitation.js';\nimport type {\n ActionResolution,\n PermissionCapabilities,\n RuntimeSettings,\n PendingAction,\n Settings,\n ModelDefaults,\n ModelDefaultsResult,\n ThreadPage,\n ThreadView,\n TurnView,\n} from '../shared/types.js';\nimport type { ClientRequest } from './generated/ClientRequest.js';\nimport type { ServerNotification } from './generated/ServerNotification.js';\nimport type { ServerRequest } from './generated/ServerRequest.js';\nimport type { InitializeResponse } from './generated/InitializeResponse.js';\nimport type { GetAccountResponse } from './generated/v2/GetAccountResponse.js';\nimport type { ModelListResponse } from './generated/v2/ModelListResponse.js';\nimport type { ConfigReadResponse } from './generated/v2/ConfigReadResponse.js';\nimport type { ConfigWriteResponse } from './generated/v2/ConfigWriteResponse.js';\nimport type { ConfigRequirementsReadResponse } from './generated/v2/ConfigRequirementsReadResponse.js';\nimport type { ExperimentalFeatureListResponse } from './generated/v2/ExperimentalFeatureListResponse.js';\nimport type { Thread } from './generated/v2/Thread.js';\nimport type { ThreadArchiveResponse } from './generated/v2/ThreadArchiveResponse.js';\nimport type { ThreadSetNameResponse } from './generated/v2/ThreadSetNameResponse.js';\nimport type { ThreadUnarchiveResponse } from './generated/v2/ThreadUnarchiveResponse.js';\nimport type { ThreadLoadedListResponse } from './generated/v2/ThreadLoadedListResponse.js';\nimport type { ThreadListResponse } from './generated/v2/ThreadListResponse.js';\nimport type { ThreadReadResponse } from './generated/v2/ThreadReadResponse.js';\nimport type { ThreadStartResponse } from './generated/v2/ThreadStartResponse.js';\nimport type { ThreadForkResponse } from './generated/v2/ThreadForkResponse.js';\nimport type { ThreadResumeResponse } from './generated/v2/ThreadResumeResponse.js';\nimport type { ThreadTurnsListResponse } from './generated/v2/ThreadTurnsListResponse.js';\nimport type { ThreadItemsListResponse } from './generated/v2/ThreadItemsListResponse.js';\nimport type { TurnStartResponse } from './generated/v2/TurnStartResponse.js';\nimport type { ReviewStartResponse } from './generated/v2/ReviewStartResponse.js';\nimport type { TurnSteerResponse } from './generated/v2/TurnSteerResponse.js';\nimport type { TurnInterruptResponse } from './generated/v2/TurnInterruptResponse.js';\nimport type { CommandExecutionApprovalDecision } from './generated/v2/CommandExecutionApprovalDecision.js';\nimport type { CommandExecutionRequestApprovalResponse } from './generated/v2/CommandExecutionRequestApprovalResponse.js';\nimport type { FileChangeRequestApprovalResponse } from './generated/v2/FileChangeRequestApprovalResponse.js';\nimport type { ToolRequestUserInputResponse } from './generated/v2/ToolRequestUserInputResponse.js';\nimport type { PermissionsRequestApprovalResponse } from './generated/v2/PermissionsRequestApprovalResponse.js';\nimport type { McpServerElicitationRequestResponse } from './generated/v2/McpServerElicitationRequestResponse.js';\nimport type { FileSystemPath } from './generated/v2/FileSystemPath.js';\nimport {\n mapItem,\n mapThread,\n mapTurn,\n permissionSettings,\n serviceTierSettings,\n threadSettings,\n threadStatus,\n turnSettings,\n taskInput,\n} from './mapping.js';\nimport {\n asCodexError,\n CodexError,\n isRecord,\n RpcTransport,\n type RpcId,\n type RpcNotification,\n type RpcServerRequest,\n} from './transport.js';\nimport type { CodexClient, CodexDiagnostics, CodexEvent } from './types.js';\nimport type { ThreadCompactStartResponse } from './generated/v2/ThreadCompactStartResponse.js';\nexport type {\n CodexClient,\n CodexDiagnostics,\n CodexEvent,\n CodexEvent as AdapterEvent,\n} from './types.js';\nexport { CodexError } from './transport.js';\n\nexport const VERIFIED_CODEX_VERSION = CODEX_COMPATIBILITY.recommended;\nconst CAPABILITIES = [\n 'command/exec',\n 'command/exec/terminate',\n 'thread/name/set',\n 'thread/start',\n 'thread/fork',\n 'thread/read',\n 'thread/list',\n 'thread/resume',\n 'thread/archive',\n 'thread/loaded/list',\n 'thread/unarchive',\n 'thread/compact/start',\n 'thread/turns/list',\n 'thread/items/list',\n 'turn/start',\n 'review/start',\n 'turn/steer',\n 'turn/interrupt',\n 'model/list',\n 'config/read',\n 'config/batchWrite',\n 'configRequirements/read',\n 'experimentalFeature/list',\n 'account/read',\n];\ntype Responses = {\n 'command/exec': CommandExecResponse;\n 'command/exec/terminate': CommandExecTerminateResponse;\n 'thread/name/set': ThreadSetNameResponse;\n initialize: InitializeResponse;\n 'account/read': GetAccountResponse;\n 'model/list': ModelListResponse;\n 'config/read': ConfigReadResponse;\n 'config/batchWrite': ConfigWriteResponse;\n 'configRequirements/read': ConfigRequirementsReadResponse;\n 'experimentalFeature/list': ExperimentalFeatureListResponse;\n 'thread/list': ThreadListResponse;\n 'thread/read': ThreadReadResponse;\n 'thread/start': ThreadStartResponse;\n 'thread/fork': ThreadForkResponse;\n 'thread/resume': ThreadResumeResponse;\n 'thread/loaded/list': ThreadLoadedListResponse;\n 'thread/archive': ThreadArchiveResponse;\n 'thread/unarchive': ThreadUnarchiveResponse;\n 'thread/compact/start': ThreadCompactStartResponse;\n 'thread/turns/list': ThreadTurnsListResponse;\n 'thread/items/list': ThreadItemsListResponse;\n 'turn/start': TurnStartResponse;\n 'review/start': ReviewStartResponse;\n 'turn/steer': TurnSteerResponse;\n 'turn/interrupt': TurnInterruptResponse;\n};\nexport interface CodexAdapterOptions {\n binary: string;\n home?: string;\n /** Explicit argument override for the test simulator; production leaves this unset. */\n args?: string[];\n requestTimeoutMs?: number;\n titleTimeoutMs?: number;\n maxLineBytes?: number;\n maxStderrBytes?: number;\n}\ntype ActionContext = {\n action: PendingAction;\n request: ServerRequest;\n decisions: Map<string, CommandExecutionApprovalDecision>;\n responding: boolean;\n};\n\nfunction permissionPathLabel(path: FileSystemPath): string {\n if (path.type === 'path') return path.path;\n if (path.type === 'glob_pattern') return `\u5339\u914D\uFF1A${path.pattern}`;\n const special = path.value;\n const subpath =\n 'subpath' in special && special.subpath !== null ? `\uFF08\u5B50\u8DEF\u5F84\uFF1A${special.subpath}\uFF09` : '';\n switch (special.kind) {\n case 'root':\n return '\u6574\u4E2A\u6587\u4EF6\u7CFB\u7EDF\uFF08/\uFF09';\n case 'minimal':\n return '\u7CFB\u7EDF\u57FA\u7840\u8FD0\u884C\u76EE\u5F55';\n case 'project_roots':\n return `\u9879\u76EE\u6839\u76EE\u5F55${subpath}`;\n case 'tmpdir':\n return '\u7CFB\u7EDF\u4E34\u65F6\u76EE\u5F55\uFF08TMPDIR\uFF09';\n case 'slash_tmp':\n return '/tmp';\n case 'unknown':\n return `\u7279\u6B8A\u8DEF\u5F84\uFF1A${special.path}${subpath}`;\n }\n}\n\nexport class CodexAdapter implements CodexClient {\n private readonly commandOutputs = new Map<\n string,\n Parameters<NonNullable<CodexClient['executeCommand']>>[3]\n >();\n epoch = randomUUID();\n private child?: ChildProcessWithoutNullStreams;\n private rpc?: RpcTransport;\n private stopped = true;\n private starting?: Promise<void>;\n private recovering?: Promise<void>;\n private restartTimer?: NodeJS.Timeout;\n private restartAttempt = 0;\n private titles?: ThreadTitles;\n private readonly tokenUsage = new TurnTokenUsage();\n // Ordering only. Persisted archive state belongs exclusively to Codex.\n private archiveSequence = 0;\n private readonly archives = new Map<string, { archived: boolean; sequence: number }>();\n private listeners = new Set<(event: CodexEvent) => void>();\n private actions = new Map<string, ActionContext>();\n private actionIds = new Map<RpcId, string>();\n private stderrTail = Buffer.alloc(0);\n private disabled = new Set<string>();\n private permissionState = new Map<string, RuntimeSettings>();\n private state: CodexDiagnostics = {\n ready: false,\n connection: 'starting',\n codexVersion: null,\n verifiedVersion: VERIFIED_CODEX_VERSION,\n compatibility: 'unavailable',\n codexEpoch: this.epoch,\n authenticated: null,\n models: [],\n capabilities: [],\n };\n constructor(private readonly options: CodexAdapterOptions) {}\n get pid(): number | undefined {\n return this.child?.pid;\n }\n get ready(): boolean {\n return this.state.ready;\n }\n diagnostics(): CodexDiagnostics {\n return structuredClone(this.state);\n }\n onEvent(listener: (event: CodexEvent) => void): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n private emit(event: CodexEvent): void {\n for (const listener of this.listeners) listener(event);\n }\n private publishRuntime(): void {\n this.emit({ type: 'runtime', diagnostics: this.diagnostics() });\n }\n\n async start(): Promise<void> {\n if (this.starting) return this.starting;\n this.stopped = false;\n this.starting = this.startProcess();\n try {\n await this.starting;\n } finally {\n this.starting = undefined;\n }\n }\n private async startProcess(): Promise<void> {\n if (this.child) throw new CodexError('CODEX_BUSY', 'Codex app-server is already started');\n this.epoch = randomUUID();\n this.disabled.clear();\n this.archives.clear();\n this.state = {\n ...this.state,\n codexEpoch: this.epoch,\n ready: false,\n connection: 'starting',\n error: undefined,\n capabilities: [],\n };\n this.publishRuntime();\n try {\n const env = {\n ...process.env,\n ...(this.options.home === undefined ? {} : { CODEX_HOME: this.options.home }),\n };\n const { stdout } = await promisify(execFile)(this.options.binary, ['--version'], {\n env,\n timeout: 5000,\n maxBuffer: 64 * 1024,\n });\n const version = stdout.trim().replace(/^codex-cli\\s+/, '');\n this.state.codexVersion = version;\n this.permissionState.clear();\n this.state.compatibility = CODEX_COMPATIBILITY.verified.includes(version)\n ? 'verified'\n : 'unverified';\n const child = spawn(\n this.options.binary,\n this.options.args ?? ['app-server', '--listen', 'stdio://'],\n { env, stdio: ['pipe', 'pipe', 'pipe'], shell: false },\n );\n this.child = child;\n const rpc = new RpcTransport(child.stdin, child.stdout, {\n timeoutMs: this.options.requestTimeoutMs,\n maxLineBytes: this.options.maxLineBytes,\n });\n this.rpc = rpc;\n this.titles = new ThreadTitles(rpc, this.options.titleTimeoutMs);\n child.stderr.on('data', (chunk: Buffer) => {\n const max = this.options.maxStderrBytes ?? 64 * 1024;\n this.stderrTail = Buffer.concat([this.stderrTail, chunk.subarray(-max)]).subarray(-max);\n });\n child.on('error', (error) =>\n rpc.fail(new CodexError('CODEX_UNAVAILABLE', `Cannot start Codex: ${error.message}`, true)),\n );\n child.on('exit', (code, signal) => {\n rpc.fail(\n new CodexError(\n 'CODEX_UNAVAILABLE',\n `Codex exited (${signal ?? code ?? 'unknown'})`,\n true,\n ),\n );\n if (this.child === child) this.child = undefined;\n });\n rpc.on('notification', (message: RpcNotification) => {\n try {\n this.notification(message);\n } catch (error) {\n rpc.fail(asCodexError(error));\n }\n });\n rpc.on('request', (message: RpcServerRequest) => {\n void this.serverRequest(message).catch((error: unknown) => rpc.fail(asCodexError(error)));\n });\n rpc.on('failure', (error: CodexError) => {\n if (this.rpc !== rpc) return;\n const wasReady = this.ready;\n this.state.ready = false;\n this.tokenUsage.clear();\n this.state.connection = 'unavailable';\n this.state.error = error.message;\n this.expireActions();\n this.publishRuntime();\n if (!child.killed) child.kill('SIGTERM');\n const kill = setTimeout(() => {\n if (child.exitCode === null && child.signalCode === null) child.kill('SIGKILL');\n }, 2500);\n kill.unref();\n child.once('exit', () => clearTimeout(kill));\n if (wasReady && !this.stopped) {\n // Only metadata is logged: never RPC params, results, or session contents.\n console.error('Codex transport failed', {\n code: error.code,\n ...(error.details as object),\n });\n this.scheduleRestart();\n }\n });\n const initialized = await this.call(\n 'initialize',\n {\n clientInfo: { name: 'codex_web_ui', title: 'Codex Web UI', version: '0.1.0' },\n capabilities: {\n experimentalApi: true,\n requestAttestation: false,\n explicitGatewayOauth: true,\n },\n },\n true,\n );\n if (!isRecord(initialized) || typeof initialized.userAgent !== 'string')\n throw new CodexError(\n 'PROTOCOL_INCOMPATIBLE',\n 'Codex initialize returned a malformed result',\n true,\n );\n await rpc.notify('initialized');\n const [account, models] = await Promise.all([\n this.call('account/read', { refreshToken: false }, true),\n this.call('model/list', { limit: 100 }, true),\n ]);\n if (\n !isRecord(account) ||\n !Object.hasOwn(account, 'account') ||\n typeof account.requiresOpenaiAuth !== 'boolean'\n )\n throw new CodexError(\n 'PROTOCOL_INCOMPATIBLE',\n 'Codex account/read returned a malformed result',\n true,\n );\n this.state.authenticated = account.account !== null || !account.requiresOpenaiAuth;\n this.state.models = models.data.map((model) => ({\n id: model.model,\n name: model.displayName,\n description: model.description,\n reasoningEfforts: model.supportedReasoningEfforts.map((effort) => effort.reasoningEffort),\n defaultReasoningEffort: model.defaultReasoningEffort,\n serviceTiers:\n model.serviceTiers?.map((tier) => (tier.id === 'priority' ? 'fast' : tier.id)) ??\n model.additionalSpeedTiers,\n }));\n let cursor = models.nextCursor;\n const seen = new Set<string>();\n while (cursor) {\n if (seen.has(cursor) || seen.size >= 100)\n throw new CodexError('PROTOCOL_INCOMPATIBLE', 'Invalid model pagination');\n seen.add(cursor);\n const page = await this.call('model/list', { limit: 100, cursor }, true);\n this.state.models.push(\n ...page.data.map((model) => ({\n id: model.model,\n name: model.displayName,\n description: model.description,\n reasoningEfforts: model.supportedReasoningEfforts.map(\n (effort) => effort.reasoningEffort,\n ),\n defaultReasoningEffort: model.defaultReasoningEffort,\n serviceTiers:\n model.serviceTiers?.map((tier) => (tier.id === 'priority' ? 'fast' : tier.id)) ??\n model.additionalSpeedTiers,\n })),\n );\n cursor = page.nextCursor;\n }\n this.titles?.configure(\n account.account?.type === 'chatgpt',\n this.state.models.map((model) => model.id),\n );\n this.state.ready = true;\n this.state.connection = 'ready';\n this.state.capabilities = CAPABILITIES.filter((method) => !this.disabled.has(method));\n this.publishRuntime();\n } catch (error) {\n const failure = asCodexError(error);\n this.state.ready = false;\n this.state.connection = 'unavailable';\n this.state.error = failure.message;\n this.publishRuntime();\n await this.stopProcess(failure);\n this.scheduleRestart();\n throw failure;\n }\n }\n async stop(): Promise<void> {\n this.stopped = true;\n clearTimeout(this.restartTimer);\n this.restartTimer = undefined;\n await this.starting?.catch(() => {});\n await this.recovering;\n await this.stopProcess();\n }\n private scheduleRestart(): void {\n if (this.stopped || this.restartTimer) return;\n const delay = Math.min(1000 * 2 ** Math.min(this.restartAttempt++, 5), 30_000);\n this.restartTimer = setTimeout(() => {\n this.restartTimer = undefined;\n this.recovering = (async () => {\n await this.stopProcess();\n if (this.stopped) return;\n try {\n await this.start();\n this.restartAttempt = 0;\n } catch {\n this.scheduleRestart();\n }\n })();\n void this.recovering.finally(() => {\n this.recovering = undefined;\n });\n }, delay);\n this.restartTimer.unref();\n }\n private async stopProcess(\n reason = new CodexError('CODEX_UNAVAILABLE', 'Codex connection closed by this service', true),\n ): Promise<void> {\n const child = this.child;\n this.state.ready = false;\n this.state.connection = 'unavailable';\n this.expireActions();\n this.rpc?.fail(reason);\n if (!child || child.exitCode !== null || child.signalCode !== null) return;\n child.stdin.end();\n await new Promise<void>((resolve) => {\n const term = setTimeout(() => child.kill('SIGTERM'), 1000);\n const kill = setTimeout(() => child.kill('SIGKILL'), 2500);\n const done = setTimeout(() => {\n cleanup();\n resolve();\n }, 3500);\n const cleanup = () => {\n clearTimeout(term);\n clearTimeout(kill);\n clearTimeout(done);\n };\n child.once('exit', () => {\n cleanup();\n resolve();\n });\n });\n if (this.child === child) this.child = undefined;\n }\n private async call<M extends keyof Responses>(\n method: M,\n params: Extract<ClientRequest, { method: M }>['params'],\n initializing = false,\n timeoutMs?: number,\n ): Promise<Responses[M]> {\n if (!this.rpc || (!initializing && !this.ready))\n throw new CodexError('CODEX_UNAVAILABLE', 'Codex is not ready');\n if (this.disabled.has(method))\n throw new CodexError('PROTOCOL_INCOMPATIBLE', `Codex does not support ${method}`);\n try {\n return await this.rpc.request<Responses[M]>(method, params, undefined, timeoutMs);\n } catch (error) {\n // Concurrent startup calls can inherit the same error when cleanup fails the transport.\n if (!initializing && error instanceof CodexError && error.rpcCode === -32601) {\n this.disabled.add(method);\n this.state.capabilities = this.state.capabilities.filter((name) => name !== method);\n this.state.error = `\u5F53\u524D Codex \u7F3A\u5C11 ${method} \u80FD\u529B`;\n this.publishRuntime();\n }\n throw error;\n }\n }\n private validateSettings(settings: Settings = {}): void {\n const model =\n settings.model === undefined\n ? undefined\n : this.state.models.find((entry) => entry.id === settings.model);\n if (settings.model !== undefined && !model)\n throw new AppError('VALIDATION_ERROR', '\u6A21\u578B\u4E0D\u5728\u5F53\u524D Codex \u6A21\u578B\u5217\u8868\u4E2D');\n if (\n settings.reasoningEffort !== undefined &&\n !(\n model?.reasoningEfforts ?? this.state.models.flatMap((entry) => entry.reasoningEfforts)\n ).includes(settings.reasoningEffort)\n )\n throw new AppError('VALIDATION_ERROR', '\u6240\u9009\u63A8\u7406\u5F3A\u5EA6\u4E0D\u53D7\u5F53\u524D\u6A21\u578B\u652F\u6301');\n }\n async listThreads(\n cwd: string | string[],\n cursor?: string,\n archived = false,\n ): Promise<ThreadPage> {\n const sequence = ++this.archiveSequence;\n const result = await this.call('thread/list', {\n cwd,\n cursor,\n limit: 30,\n archived,\n sourceKinds: ['cli', 'appServer', 'vscode'],\n sortKey: 'updated_at',\n sortDirection: 'desc',\n });\n return {\n data: result.data.map((thread) => ({\n ...mapThread(thread),\n archived: this.observeArchive(thread.id, archived, sequence),\n })),\n nextCursor: result.nextCursor,\n };\n }\n\n private observeArchive(id: string, archived: boolean, sequence: number): boolean {\n const current = this.archives.get(id);\n if (current && current.sequence > sequence) return current.archived;\n this.archives.set(id, { archived, sequence });\n return archived;\n }\n\n private archiveChanged(id: string, archived: boolean): void {\n this.observeArchive(id, archived, ++this.archiveSequence);\n this.emit({ type: 'threadArchive', threadId: id, archived });\n }\n\n /** thread/read has no archive field. Query the native index, including paginated history,\n * instead of guessing from the unstable rollout path or maintaining a second database. */\n private async storedThread(thread: Thread, sequence: number): Promise<ThreadView> {\n let cursor: string | null = null;\n const seen = new Set<string>();\n let archived = false;\n do {\n const page: ThreadListResponse = await this.call('thread/list', {\n archived: true,\n cwd: thread.cwd,\n cursor,\n limit: 100,\n sourceKinds: [\n 'cli',\n 'vscode',\n 'exec',\n 'appServer',\n 'subAgent',\n 'subAgentReview',\n 'subAgentCompact',\n 'subAgentThreadSpawn',\n 'subAgentOther',\n 'unknown',\n ],\n });\n if (page.data.some((entry) => entry.id === thread.id)) {\n archived = true;\n break;\n }\n cursor = page.nextCursor;\n if (cursor && (seen.has(cursor) || seen.size >= 1000))\n throw new CodexError('PROTOCOL_INCOMPATIBLE', 'Invalid archive pagination');\n if (cursor) seen.add(cursor);\n } while (cursor);\n return { ...mapThread(thread), archived: this.observeArchive(thread.id, archived, sequence) };\n }\n\n /** Native archive also shuts down spawned descendants, even already-archived ones. */\n private async assertArchiveIdle(rootId: string): Promise<void> {\n const threads = new Map<string, Thread>();\n const read = async (id: string): Promise<Thread> => {\n let thread = threads.get(id);\n if (!thread) {\n thread = (await this.call('thread/read', { threadId: id, includeTurns: false })).thread;\n threads.set(id, thread);\n }\n return thread;\n };\n let cursor: string | null = null;\n const seen = new Set<string>();\n do {\n const page: ThreadLoadedListResponse = await this.call('thread/loaded/list', {\n cursor,\n limit: 100,\n });\n for (const id of page.data) {\n let thread: Thread;\n try {\n thread = await read(id);\n } catch (error) {\n // A completed helper can unload after the loaded-thread snapshot.\n if (\n error instanceof CodexError &&\n error.rpcCode === -32600 &&\n error.message === `thread not loaded: ${id}`\n )\n continue;\n throw error;\n }\n if (thread.status.type !== 'active') continue;\n const ancestors = new Set<string>();\n for (;;) {\n if (thread.id === rootId)\n throw new AppError('THREAD_BUSY', '\u4F1A\u8BDD\u6216\u5176\u5B50\u4EFB\u52A1\u4ECD\u5728\u8FD0\u884C\uFF0C\u7ED3\u675F\u540E\u624D\u80FD\u5F52\u6863', 409);\n if (!thread.parentThreadId) break;\n if (ancestors.has(thread.id))\n throw new CodexError('PROTOCOL_INCOMPATIBLE', 'Invalid thread ancestry');\n ancestors.add(thread.id);\n thread = await read(thread.parentThreadId);\n }\n }\n cursor = page.nextCursor;\n if (cursor && (seen.has(cursor) || seen.size >= 1000))\n throw new CodexError('PROTOCOL_INCOMPATIBLE', 'Invalid loaded thread pagination');\n if (cursor) seen.add(cursor);\n } while (cursor);\n }\n\n async renameThread(id: string, name: string): Promise<void> {\n const problem = threadNameError(name);\n if (problem) throw new AppError('VALIDATION_ERROR', problem);\n const epoch = this.epoch;\n // A generated name may already be on the wire. Finish it before the explicit write.\n await this.titles?.prepareManualName(id);\n if (this.epoch !== epoch || !this.ready)\n throw new CodexError(\n 'CODEX_UNAVAILABLE',\n '\u91CD\u547D\u540D\u7B49\u5F85\u671F\u95F4 Codex \u5B9E\u4F8B\u5DF2\u53D8\u5316\uFF0C\u8BF7\u6838\u5BF9\u540D\u79F0',\n true,\n );\n await this.call('thread/name/set', { threadId: id, name: name.trim() });\n }\n\n async archiveThread(id: string): Promise<void> {\n await this.assertArchiveIdle(id);\n await this.call('thread/archive', { threadId: id });\n this.archiveChanged(id, true);\n }\n\n async unarchiveThread(id: string): Promise<ThreadView> {\n const { thread } = await this.call('thread/unarchive', { threadId: id });\n this.archiveChanged(id, false);\n return { ...mapThread(thread), archived: false };\n }\n private async readThreadHeader(id: string): Promise<Thread> {\n try {\n return (await this.call('thread/read', { threadId: id, includeTurns: false })).thread;\n } catch (error) {\n if (\n error instanceof CodexError &&\n error.rpcCode === -32600 &&\n error.message === `thread not loaded: ${id}`\n )\n throw new AppError('THREAD_NOT_FOUND', '\u4F1A\u8BDD\u5C1A\u672A\u4FDD\u5B58\u6216\u5DF2\u4E0D\u5B58\u5728', 404, { threadId: id });\n throw error;\n }\n }\n\n async readThreadMetadata(id: string): Promise<ThreadView> {\n const sequence = ++this.archiveSequence;\n return this.storedThread(await this.readThreadHeader(id), sequence);\n }\n async readThreadPage(id: string, continuation?: string): Promise<ThreadView> {\n const epoch = this.epoch;\n let cursor: string | null = null;\n if (continuation) {\n try {\n const decoded = JSON.parse(Buffer.from(continuation, 'base64url').toString('utf8'));\n if (\n decoded.threadId !== id ||\n decoded.epoch !== epoch ||\n typeof decoded.cursor !== 'string'\n )\n throw new Error('Invalid cursor');\n cursor = decoded.cursor;\n } catch {\n throw new AppError('HISTORY_CURSOR_EXPIRED', '\u5386\u53F2\u5206\u9875\u5DF2\u5931\u6548\uFF0C\u8BF7\u91CD\u65B0\u540C\u6B65\u4F1A\u8BDD\u3002', 409);\n }\n }\n const sequence = ++this.archiveSequence;\n const header = await this.readThreadHeader(id);\n // Legacy rollout files expose no paging protocol. Keep the compatibility path explicit.\n if (header.historyMode !== 'paginated') return this.readThread(id);\n const page = await this.call('thread/turns/list', {\n threadId: id,\n cursor,\n limit: 12,\n sortDirection: 'desc',\n itemsView: 'summary',\n });\n if (page.nextCursor && page.nextCursor === cursor)\n throw new CodexError('PROTOCOL_INCOMPATIBLE', 'Invalid turn pagination');\n await this.hydrateTurns(id, page.data);\n if (this.epoch !== epoch)\n throw new AppError('HISTORY_CURSOR_EXPIRED', '\u8BFB\u53D6\u671F\u95F4 Codex \u5DF2\u91CD\u542F\uFF0C\u8BF7\u91CD\u65B0\u540C\u6B65\u4F1A\u8BDD\u3002', 409);\n const view = await this.storedThread(\n { ...header, turns: page.data.slice().reverse() },\n sequence,\n );\n return {\n ...view,\n history: {\n olderCursor: page.nextCursor\n ? Buffer.from(\n JSON.stringify({\n threadId: id,\n epoch,\n cursor: page.nextCursor,\n }),\n ).toString('base64url')\n : null,\n },\n };\n }\n\n private async hydrateTurns(id: string, turns: Thread['turns']): Promise<void> {\n for (const turn of turns) {\n if (turn.itemsView === 'full') continue;\n let cursor: string | null = null;\n const seen = new Set<string>();\n turn.items = [];\n do {\n const page: ThreadItemsListResponse = await this.call('thread/items/list', {\n threadId: id,\n turnId: turn.id,\n cursor,\n limit: 20,\n sortDirection: 'asc',\n });\n turn.items.push(...page.data.map((entry) => entry.item));\n cursor = page.nextCursor;\n if (cursor && (seen.has(cursor) || seen.size >= 1000))\n throw new CodexError('PROTOCOL_INCOMPATIBLE', 'Invalid item pagination');\n if (cursor) seen.add(cursor);\n } while (cursor);\n }\n }\n\n async readThread(id: string): Promise<ThreadView> {\n const sequence = ++this.archiveSequence;\n const thread = await this.readThreadHeader(id);\n if (thread.historyMode !== 'paginated')\n return this.storedThread(\n (await this.call('thread/read', { threadId: id, includeTurns: true })).thread,\n sequence,\n );\n let cursor: string | null = null;\n const seen = new Set<string>();\n thread.turns = [];\n do {\n const page: ThreadTurnsListResponse = await this.call('thread/turns/list', {\n threadId: id,\n cursor,\n limit: 100,\n sortDirection: 'asc',\n itemsView: 'summary',\n });\n for (const turn of page.data) {\n if (turn.itemsView !== 'full') {\n let itemCursor: string | null = null;\n const itemSeen = new Set<string>();\n turn.items = [];\n do {\n const items: ThreadItemsListResponse = await this.call('thread/items/list', {\n threadId: id,\n turnId: turn.id,\n cursor: itemCursor,\n limit: 20,\n sortDirection: 'asc',\n });\n turn.items.push(...items.data.map((entry) => entry.item));\n itemCursor = items.nextCursor;\n if (itemCursor && (itemSeen.has(itemCursor) || itemSeen.size >= 1000))\n throw new CodexError('PROTOCOL_INCOMPATIBLE', 'Invalid item pagination');\n if (itemCursor) itemSeen.add(itemCursor);\n } while (itemCursor);\n }\n }\n thread.turns.push(...page.data);\n cursor = page.nextCursor;\n if (cursor && (seen.has(cursor) || seen.size >= 1000))\n throw new CodexError('PROTOCOL_INCOMPATIBLE', 'Invalid turn pagination');\n if (cursor) seen.add(cursor);\n } while (cursor);\n return this.storedThread(thread, sequence);\n }\n async createThread(cwd: string, settings?: Settings): Promise<ThreadView> {\n this.validateSettings(settings);\n await this.validatePermissionSettings(cwd, settings);\n const titles = this.titles;\n const result = await this.call('thread/start', { cwd, ...threadSettings(settings) });\n this.tokenUsage.created(result.thread.id);\n titles?.register(result);\n return {\n ...mapThread(result.thread),\n runtimeSettings: await this.responseRuntimeSettings(result),\n };\n }\n async saveModelDefaults(settings: ModelDefaults): Promise<ModelDefaultsResult> {\n this.validateSettings({\n model: settings.model,\n ...(settings.reasoningEffort === null ? {} : { reasoningEffort: settings.reasoningEffort }),\n });\n // Match the CLI picker: write a complete pair to the owning server's user/profile config.\n // No file path or permission fields can be supplied by the browser.\n const result = await this.call('config/batchWrite', {\n edits: [\n { keyPath: 'model', value: settings.model, mergeStrategy: 'replace' },\n {\n keyPath: 'model_reasoning_effort',\n value: settings.reasoningEffort,\n mergeStrategy: 'replace',\n },\n ],\n reloadUserConfig: true,\n });\n return { status: result.status };\n }\n async readRuntimeSettings(cwd: string): Promise<RuntimeSettings> {\n const { config } = await this.call('config/read', { cwd, includeLayers: false });\n // Config can contain credentials and instructions. Only displayable fields cross the gateway.\n return {\n model: typeof config.model === 'string' ? config.model : null,\n reasoningEffort:\n typeof config.model_reasoning_effort === 'string' ? config.model_reasoning_effort : null,\n ...serviceTierSettings(config.service_tier),\n sandbox: config.sandbox_mode ?? null,\n approvalPolicy:\n typeof config.approval_policy === 'string'\n ? config.approval_policy\n : config.approval_policy\n ? 'granular'\n : null,\n approvalReviewer: config.approvals_reviewer ?? null,\n networkAccess:\n config.sandbox_mode === 'workspace-write'\n ? (config.sandbox_workspace_write?.network_access ?? null)\n : null,\n permissionMode:\n typeof config.default_permissions === 'string' &&\n ![':workspace', ':read-only', ':danger-full-access'].includes(config.default_permissions)\n ? 'custom'\n : null,\n permissionProfile:\n typeof config.default_permissions === 'string'\n ? { id: config.default_permissions, extends: null }\n : null,\n writableRoots: config.sandbox_workspace_write?.writable_roots ?? null,\n excludeTmpdirEnvVar: config.sandbox_workspace_write?.exclude_tmpdir_env_var ?? null,\n excludeSlashTmp: config.sandbox_workspace_write?.exclude_slash_tmp ?? null,\n permissionCapabilities: await this.readPermissionCapabilities(undefined, config),\n };\n }\n private async readPermissionCapabilities(\n threadId?: string,\n config?: ConfigReadResponse['config'],\n ): Promise<PermissionCapabilities> {\n if (!CODEX_COMPATIBILITY.verified.includes(this.state.codexVersion ?? ''))\n return permissionCapabilities(\n null,\n false,\n `\u6743\u9650\u6A21\u5F0F\u4EC5\u6838\u9A8C\u8FC7 Codex ${VERIFIED_CODEX_VERSION}\uFF1B\u5F53\u524D\u7248\u672C ${this.state.codexVersion ?? '\u672A\u77E5'}`,\n );\n try {\n const [requirements, first] = await Promise.all([\n this.call('configRequirements/read', undefined),\n this.call('experimentalFeature/list', { limit: 200, ...(threadId ? { threadId } : {}) }),\n ]);\n if (!Object.hasOwn(requirements, 'requirements') || !Array.isArray(first.data))\n throw new Error('Permission capability response is incomplete');\n const features = [...first.data];\n let cursor = first.nextCursor;\n const seen = new Set<string>();\n while (cursor) {\n if (seen.has(cursor) || seen.size >= 100) throw new Error('Invalid feature pagination');\n seen.add(cursor);\n const page = await this.call('experimentalFeature/list', {\n limit: 200,\n cursor,\n ...(threadId ? { threadId } : {}),\n });\n features.push(...page.data);\n cursor = page.nextCursor;\n }\n const configFeatures = config?.features;\n const explicit = isRecord(configFeatures) ? configFeatures.guardian_approval : undefined;\n const autoReview =\n typeof explicit === 'boolean'\n ? explicit\n : features.find((entry) => entry.name === 'guardian_approval')?.enabled === true;\n return permissionCapabilities(\n requirements.requirements as PermissionRequirements | null,\n autoReview,\n );\n } catch {\n return permissionCapabilities(\n null,\n false,\n '\u65E0\u6CD5\u6838\u5B9E\u5F53\u524D Codex \u7684\u529F\u80FD\u548C\u53D7\u7BA1\u8981\u6C42\uFF0C\u8BF7\u91CD\u8BD5\u6216\u68C0\u67E5\u7248\u672C\u652F\u6301',\n );\n }\n }\n private async validatePermissionSettings(\n cwd: string,\n settings?: Settings,\n threadId?: string,\n ): Promise<void> {\n if (!settings?.permissionMode && settings?.approvalReviewer === undefined) return;\n const epoch = this.epoch;\n const defaults =\n !threadId || !this.permissionState.has(threadId)\n ? await this.readRuntimeSettings(cwd)\n : undefined;\n const capabilities = defaults\n ? defaults.permissionCapabilities\n : await this.readPermissionCapabilities(threadId);\n if (epoch !== this.epoch)\n throw new AppError('CODEX_UNAVAILABLE', 'Codex \u8FD0\u884C\u5B9E\u4F8B\u5DF2\u53D8\u5316\uFF0C\u8BF7\u91CD\u8BD5');\n const model =\n settings.model ??\n (threadId ? this.permissionState.get(threadId)?.model : undefined) ??\n defaults?.model;\n const reason = settings.permissionMode\n ? permissionModeUnavailable(settings.permissionMode, capabilities, model)\n : permissionReviewerUnavailable(settings.approvalReviewer!, capabilities, model);\n if (reason) throw new AppError('PERMISSION_MODE_UNAVAILABLE', reason);\n }\n private async responseRuntimeSettings(result: ThreadStartResponse): Promise<RuntimeSettings> {\n const previous = this.permissionState.get(result.thread.id);\n const settings: RuntimeSettings = {\n model: result.model ?? result.thread.model ?? null,\n reasoningEffort: result.reasoningEffort ?? null,\n ...serviceTierSettings(result.serviceTier),\n ...permissionSettings(\n result.sandbox,\n result.approvalPolicy,\n result.approvalsReviewer,\n (result as ThreadStartResponse & ProfileProvenance).activePermissionProfile,\n result.cwd,\n ),\n permissionCapabilities: await this.readPermissionCapabilities(result.thread.id),\n };\n const latest = this.permissionState.get(result.thread.id);\n const confirmed =\n latest && latest !== previous\n ? { ...latest, permissionCapabilities: settings.permissionCapabilities }\n : settings;\n this.permissionState.set(result.thread.id, confirmed);\n // The service correctly keeps a newer settings notification over a lifecycle response.\n // Publish availability alongside that newer state so the delayed capability read is not lost.\n if (confirmed !== settings)\n this.emit({ type: 'threadSettings', threadId: result.thread.id, settings: confirmed });\n return settings;\n }\n async resumeThread(id: string, cwd: string, settings?: Settings): Promise<ThreadView> {\n this.validateSettings(settings);\n await this.validatePermissionSettings(cwd, settings, id);\n const titles = this.titles;\n let result: ThreadResumeResponse;\n try {\n result = await this.call('thread/resume', {\n threadId: id,\n cwd,\n ...threadSettings(settings),\n excludeTurns: true,\n });\n } catch (error) {\n // Verified with two 0.163.0 processes, for both legacy and paginated histories.\n // -32600 alone covers many failures; match this thread's writer conflict exactly.\n if (\n error instanceof CodexError &&\n error.rpcCode === -32600 &&\n error.message === `thread ${id} already has an active writer`\n )\n throw new AppError('THREAD_IN_USE', '\u6B64\u4F1A\u8BDD\u6B63\u88AB\u5176\u4ED6\u8FDB\u7A0B\u4F7F\u7528', 409, { threadId: id });\n throw error;\n }\n titles?.register(result);\n const view = await this.readThreadPage(result.thread.id);\n return { ...view, runtimeSettings: await this.responseRuntimeSettings(result) };\n }\n async forkThread(id: string, cwd: string, settings?: Settings): Promise<ThreadView> {\n this.validateSettings(settings);\n await this.validatePermissionSettings(cwd, settings, id);\n const titles = this.titles;\n const result = await this.call('thread/fork', {\n threadId: id,\n cwd,\n ...threadSettings(settings),\n // Omitting lastTurnId copies the persisted history, including an active turn's\n // interruption marker in the fork. The source is never resumed or interrupted.\n excludeTurns: true,\n });\n let forkedId: string | undefined;\n try {\n if (isRecord(result) && isRecord(result.thread) && typeof result.thread.id === 'string')\n forkedId = result.thread.id === id ? undefined : result.thread.id;\n const metadata = mapThread(result.thread);\n if (metadata.id === id)\n throw new CodexError('PROTOCOL_INCOMPATIBLE', 'Codex fork returned the source thread ID');\n forkedId = metadata.id;\n const thread = await this.readThread(forkedId);\n if (thread.id !== forkedId)\n throw new CodexError('PROTOCOL_INCOMPATIBLE', 'Codex returned a different fork thread ID');\n titles?.register(result);\n return { ...thread, runtimeSettings: await this.responseRuntimeSettings(result) };\n } catch (error) {\n const failure = asCodexError(error);\n // The mutating RPC already succeeded. A read failure cannot make a retry safe.\n throw new CodexError(\n failure.code,\n forkedId\n ? `\u5DF2\u521B\u5EFA\u5206\u652F\u4F1A\u8BDD ${forkedId}\uFF0C\u4F46\u65E0\u6CD5\u52A0\u8F7D\u5386\u53F2\uFF1B\u8BF7\u4ECE\u4F1A\u8BDD\u5217\u8868\u91CD\u65B0\u6253\u5F00\uFF0C\u4E0D\u8981\u91CD\u590D fork\u3002${failure.message}`\n : `Codex fork \u5DF2\u8FD4\u56DE\u7ED3\u679C\uFF0C\u4F46\u65E0\u6CD5\u786E\u8BA4\u65B0\u4F1A\u8BDD\uFF1B\u8BF7\u68C0\u67E5\u4F1A\u8BDD\u5217\u8868\uFF0C\u4E0D\u8981\u91CD\u590D fork\u3002${failure.message}`,\n true,\n failure.rpcCode,\n );\n }\n }\n async startTurn(\n id: string,\n cwd: string,\n text: string,\n settings?: Settings,\n images?: string[],\n ): Promise<TurnView> {\n this.validateSettings(settings);\n await this.validatePermissionSettings(cwd, settings, id);\n const turn = mapTurn(\n id,\n (\n await this.call('turn/start', {\n threadId: id,\n cwd,\n input: taskInput(text, images),\n ...turnSettings(cwd, settings),\n })\n ).turn,\n );\n return turn;\n }\n async startReview(id: string): Promise<TurnView> {\n const result = await this.call('review/start', {\n threadId: id,\n target: { type: 'uncommittedChanges' },\n delivery: 'inline',\n });\n if (!isRecord(result) || result.reviewThreadId !== id)\n throw new CodexError(\n 'PROTOCOL_INCOMPATIBLE',\n 'Codex review returned a different thread; review result needs reconciliation',\n true,\n );\n return mapTurn(id, result.turn);\n }\n steerTurn(\n id: string,\n turnId: string,\n text: string,\n images?: string[],\n ): Promise<TurnSteerResponse> {\n return this.call('turn/steer', {\n threadId: id,\n expectedTurnId: turnId,\n input: taskInput(text, images),\n });\n }\n async interruptTurn(id: string, turnId: string): Promise<void> {\n await this.call('turn/interrupt', { threadId: id, turnId });\n }\n\n async compactThread(id: string): Promise<void> {\n // The empty response acknowledges dispatch, not completion. Turn notifications\n // carry the compaction's identity and final outcome.\n await this.call('thread/compact/start', { threadId: id });\n }\n\n async executeCommand(\n processId: string,\n cwd: string,\n command: string,\n output: Parameters<NonNullable<CodexClient['executeCommand']>>[3],\n ) {\n this.commandOutputs.set(processId, output);\n try {\n return await this.call(\n 'command/exec',\n {\n processId,\n cwd,\n command:\n process.platform === 'win32'\n ? ['cmd.exe', '/d', '/s', '/c', command]\n : ['/bin/sh', '-c', command],\n streamStdoutStderr: true,\n streamStdin: false,\n tty: false,\n timeoutMs: SHELL_TIMEOUT_MS,\n outputBytesCap: SHELL_OUTPUT_BYTES / 2,\n // Omit sandboxPolicy: preserve the server's configured permission policy.\n },\n false,\n SHELL_TIMEOUT_MS + 5000,\n );\n } finally {\n this.commandOutputs.delete(processId);\n }\n }\n async terminateCommand(processId: string): Promise<void> {\n await this.call('command/exec/terminate', { processId });\n }\n\n private notification(message: RpcNotification): void {\n if (this.titles?.notification(message)) return;\n const event = message as ServerNotification;\n const p = event.params;\n switch (event.method) {\n case 'command/exec/outputDelta': {\n const { processId, stream, deltaBase64, capReached } = event.params;\n this.commandOutputs.get(processId)?.(\n stream,\n Buffer.from(deltaBase64, 'base64'),\n capReached,\n );\n break;\n }\n case 'thread/settings/updated':\n {\n const observed: RuntimeSettings = {\n model: event.params.threadSettings.model ?? null,\n reasoningEffort: event.params.threadSettings.effort ?? null,\n ...serviceTierSettings(event.params.threadSettings.serviceTier),\n ...permissionSettings(\n event.params.threadSettings.sandboxPolicy,\n event.params.threadSettings.approvalPolicy,\n event.params.threadSettings.approvalsReviewer,\n event.params.threadSettings.activePermissionProfile,\n event.params.threadSettings.cwd,\n ),\n permissionCapabilities: this.permissionState.get(event.params.threadId)\n ?.permissionCapabilities,\n };\n this.permissionState.set(event.params.threadId, observed);\n this.emit({\n type: 'threadSettings',\n threadId: event.params.threadId,\n settings: observed,\n });\n }\n break;\n case 'item/autoApprovalReview/started':\n case 'item/autoApprovalReview/completed':\n this.emit({\n type: 'autoReview',\n threadId: event.params.threadId,\n turnId: event.params.turnId,\n review: mapAutoReview(event.params),\n });\n break;\n case 'thread/started':\n this.emit({ type: 'thread', thread: mapThread(event.params.thread) });\n break;\n case 'thread/archived':\n this.archiveChanged(event.params.threadId, true);\n break;\n case 'thread/unarchived':\n this.archiveChanged(event.params.threadId, false);\n break;\n case 'thread/name/updated':\n this.emit({\n type: 'threadName',\n threadId: event.params.threadId,\n name: event.params.threadName,\n });\n break;\n case 'thread/status/changed':\n this.emit({\n type: 'threadStatus',\n threadId: event.params.threadId,\n status: threadStatus(event.params.status),\n });\n break;\n case 'turn/started':\n case 'turn/completed': {\n const { threadId, turn } = event.params;\n if (event.method === 'turn/started') this.tokenUsage.started(threadId, turn.id);\n const outputTokens =\n event.method === 'turn/completed'\n ? this.tokenUsage.completed(threadId, turn.id)\n : undefined;\n this.emit({\n type: 'turn',\n threadId,\n turn: {\n ...mapTurn(threadId, turn),\n ...(outputTokens !== undefined ? { outputTokens } : {}),\n },\n });\n if (event.method === 'turn/completed')\n this.expireActions(event.params.threadId, event.params.turn.id);\n break;\n }\n case 'thread/tokenUsage/updated':\n this.tokenUsage.updated(\n event.params.threadId,\n event.params.turnId,\n event.params.tokenUsage?.total?.outputTokens,\n );\n break;\n case 'thread/compacted':\n this.tokenUsage.compacted(event.params.threadId, event.params.turnId);\n this.emit({ type: 'compactionCompleted', ...event.params });\n break;\n case 'item/started':\n case 'item/completed':\n if (event.params.item.type === 'contextCompaction')\n this.tokenUsage.compacted(event.params.threadId, event.params.turnId);\n if (['agentMessage', 'plan', 'reasoning'].includes(event.params.item.type))\n this.emit({\n type: 'turnProgress',\n threadId: event.params.threadId,\n turnId: event.params.turnId,\n });\n this.emit({\n type: 'item',\n threadId: event.params.threadId,\n turnId: event.params.turnId,\n item: {\n ...mapItem(event.params.item),\n ...(event.params.item.type === 'contextCompaction'\n ? { status: event.method === 'item/started' ? 'inProgress' : 'completed' }\n : {}),\n },\n });\n break;\n case 'item/agentMessage/delta':\n case 'item/plan/delta':\n case 'item/reasoning/summaryTextDelta':\n case 'item/reasoning/textDelta':\n case 'item/commandExecution/outputDelta':\n case 'item/fileChange/outputDelta':\n // Background tool output can continue while the model stream is retrying.\n // Only model content proves that this turn's upstream stream resumed.\n if (!event.method.includes('outputDelta'))\n this.emit({\n type: 'turnProgress',\n threadId: event.params.threadId,\n turnId: event.params.turnId,\n });\n this.emit({\n type: 'delta',\n threadId: event.params.threadId,\n turnId: event.params.turnId,\n itemId: event.params.itemId,\n field: event.method.includes('outputDelta') ? 'output' : 'text',\n delta: event.params.delta,\n itemType: event.method.split('/')[1]!,\n });\n break;\n case 'item/reasoning/summaryPartAdded':\n case 'rawResponse/completed':\n this.emit({\n type: 'turnProgress',\n threadId: event.params.threadId,\n turnId: event.params.turnId,\n });\n break;\n case 'turn/diff/updated':\n this.emit({\n type: 'diff',\n threadId: event.params.threadId,\n turnId: event.params.turnId,\n diff: event.params.diff,\n });\n break;\n case 'item/fileChange/patchUpdated':\n this.emit({\n type: 'item',\n threadId: event.params.threadId,\n turnId: event.params.turnId,\n item: mapItem({\n type: 'fileChange',\n id: event.params.itemId,\n changes: event.params.changes,\n status: 'inProgress',\n }),\n });\n break;\n case 'serverRequest/resolved': {\n const actionId = this.actionIds.get(event.params.requestId);\n if (actionId) {\n this.emit({ type: 'actionResolved', actionId });\n this.actions.delete(actionId);\n this.actionIds.delete(event.params.requestId);\n }\n break;\n }\n case 'error':\n // Upstream retries/failures belong to a turn, not to the app-server process.\n this.emit({\n type: 'turnError',\n threadId: event.params.threadId,\n turnId: event.params.turnId,\n message: event.params.error.message,\n willRetry: event.params.willRetry,\n });\n break;\n default: // Unknown noninteractive notifications cannot authorize any action.\n if (!isRecord(p)) break;\n }\n }\n private async serverRequest(message: RpcServerRequest): Promise<void> {\n if (isRecord(message.params) && this.titles?.isInternal(message.params.threadId)) {\n await this.rpc?.reject(\n message.id,\n -32601,\n 'Interactive tools are disabled for title generation',\n );\n return;\n }\n const request = message as ServerRequest;\n const params: Record<string, unknown> = isRecord(message.params) ? message.params : {};\n const action: PendingAction = {\n actionId: randomUUID(),\n codexEpoch: this.epoch,\n rpcId: message.id,\n kind: 'unsupported',\n status: 'pending',\n title: '\u4E0D\u652F\u6301\u7684 Codex \u4EA4\u4E92\u8BF7\u6C42',\n options: [],\n ...(typeof params.threadId === 'string' ? { threadId: params.threadId } : {}),\n ...(typeof params.turnId === 'string' ? { turnId: params.turnId } : {}),\n };\n const decisions = new Map<string, CommandExecutionApprovalDecision>();\n if (\n request.method === 'item/commandExecution/requestApproval' ||\n request.method === 'item/fileChange/requestApproval'\n ) {\n for (const [id, label] of [\n ['accept', '\u5141\u8BB8\u672C\u6B21'],\n ['acceptForSession', '\u672C\u4F1A\u8BDD\u5141\u8BB8'],\n ['decline', '\u62D2\u7EDD'],\n ['cancel', '\u53D6\u6D88\u5F53\u524D\u4EFB\u52A1'],\n ] as const) {\n action.options.push({ id, label });\n decisions.set(id, id);\n }\n action.reason = request.params.reason ?? undefined;\n if (request.method === 'item/commandExecution/requestApproval') {\n const p = request.params;\n action.kind = p.networkApprovalContext ? 'network' : 'command';\n action.title = p.networkApprovalContext\n ? `\u7F51\u7EDC\u6743\u9650\uFF1A${p.networkApprovalContext.protocol}://${p.networkApprovalContext.host}`\n : '\u547D\u4EE4\u5BA1\u6279';\n action.command = p.command ?? undefined;\n action.cwd = p.cwd ?? undefined;\n action.details = {\n kind: p.kind,\n network: p.networkApprovalContext,\n commandActions: p.commandActions,\n };\n if (p.proposedExecpolicyAmendment) {\n action.options.push({\n id: 'acceptWithRule',\n label: `\u5141\u8BB8\u5E76\u8BB0\u4F4F\u547D\u4EE4\u89C4\u5219\uFF1A${p.proposedExecpolicyAmendment.join(' ')}`,\n });\n decisions.set('acceptWithRule', {\n acceptWithExecpolicyAmendment: { execpolicy_amendment: p.proposedExecpolicyAmendment },\n });\n }\n p.proposedNetworkPolicyAmendments?.forEach((amendment, index) => {\n const id = `networkRule:${index}`;\n action.options.push({ id, label: `\u5E94\u7528\u7F51\u7EDC\u89C4\u5219\uFF1A${JSON.stringify(amendment)}` });\n decisions.set(id, {\n applyNetworkPolicyAmendment: { network_policy_amendment: amendment },\n });\n });\n } else {\n action.kind = 'file';\n action.title = '\u6587\u4EF6\u53D8\u66F4\u5BA1\u6279';\n action.details = { itemId: request.params.itemId, grantRoot: request.params.grantRoot };\n }\n } else if (request.method === 'item/permissions/requestApproval') {\n const p = request.params;\n action.kind = 'permissions';\n action.title = '\u989D\u5916\u6743\u9650\u5BA1\u6279';\n action.reason = p.reason ?? undefined;\n action.cwd = p.cwd;\n action.options = [\n { id: 'accept', label: '\u5F53\u524D\u4EFB\u52A1\u5141\u8BB8' },\n { id: 'acceptForSession', label: '\u672C\u4F1A\u8BDD\u5141\u8BB8' },\n { id: 'decline', label: '\u62D2\u7EDD' },\n ];\n action.permissionRequest = {\n ...(p.permissions.network === null ? {} : { network: p.permissions.network.enabled }),\n ...(p.permissions.fileSystem === null\n ? {}\n : {\n fileSystem: {\n read: p.permissions.fileSystem.read ?? [],\n write: p.permissions.fileSystem.write ?? [],\n entries: (p.permissions.fileSystem.entries ?? []).map((entry) => ({\n path: permissionPathLabel(entry.path),\n access: entry.access,\n })),\n ...(p.permissions.fileSystem.globScanMaxDepth === undefined\n ? {}\n : {\n globScanMaxDepth: p.permissions.fileSystem.globScanMaxDepth,\n }),\n },\n }),\n };\n action.details = {\n itemId: p.itemId,\n environmentId: p.environmentId,\n permissions: p.permissions,\n };\n } else if (request.method === 'mcpServer/elicitation/request') {\n action.kind = 'elicitation';\n action.reason = request.params.message;\n action.elicitation = normalizeElicitationRequest(params);\n action.title = `${action.elicitation.approval ? 'MCP \u5DE5\u5177\u5BA1\u6279' : 'MCP \u4EA4\u4E92'}\uFF1A${request.params.serverName}`;\n action.options = [\n {\n id: 'accept',\n label: action.elicitation.approval\n ? '\u5141\u8BB8\u672C\u6B21'\n : action.elicitation.mode === 'url'\n ? '\u5DF2\u5B8C\u6210\uFF0C\u7EE7\u7EED'\n : '\u63D0\u4EA4',\n },\n ...(action.elicitation.approval?.allowSession\n ? [{ id: 'acceptSession', label: '\u672C\u4F1A\u8BDD\u5141\u8BB8' }]\n : []),\n { id: 'decline', label: '\u62D2\u7EDD' },\n { id: 'cancel', label: '\u53D6\u6D88' },\n ];\n // Keep an unsupported schema reviewable while allowing an explicit decline/cancel.\n if (action.elicitation.schemaError)\n action.details = { requestedSchema: params.requestedSchema, mode: params.mode };\n } else if (request.method === 'item/tool/requestUserInput') {\n action.kind = 'questions';\n action.title = '\u9700\u8981\u4F60\u7684\u56DE\u7B54';\n action.blocking = request.params.isBlocking;\n action.questions = request.params.questions.map((question) => ({\n ...question,\n options: question.options ?? [],\n }));\n } else {\n action.status = 'expired';\n action.reason = `\u5F53\u524D Web UI \u5C1A\u672A\u5B9E\u73B0 ${message.method}`;\n this.emit({ type: 'action', action });\n this.state.error = action.reason;\n this.publishRuntime();\n await this.rpc!.reject(\n message.id,\n -32601,\n `Unsupported interactive request: ${message.method}`,\n );\n return;\n }\n this.actions.set(action.actionId, { action, request, decisions, responding: false });\n this.actionIds.set(message.id, action.actionId);\n this.emit({ type: 'action', action: structuredClone(action) });\n }\n async respond(actionId: string, resolution: ActionResolution): Promise<void> {\n const context = this.actions.get(actionId);\n if (!context || context.action.codexEpoch !== this.epoch || !this.ready)\n throw new AppError('ACTION_EXPIRED', '\u6B64\u4EBA\u5DE5\u8BF7\u6C42\u5DF2\u5931\u6548', 409);\n if (context.responding) throw new AppError('ACTION_CONFLICT', '\u6B64\u4EBA\u5DE5\u8BF7\u6C42\u5DF2\u63D0\u4EA4\u56DE\u7B54', 409);\n let response:\n | ToolRequestUserInputResponse\n | CommandExecutionRequestApprovalResponse\n | FileChangeRequestApprovalResponse\n | PermissionsRequestApprovalResponse\n | McpServerElicitationRequestResponse;\n if (context.request.method === 'item/permissions/requestApproval') {\n const decision = validatePermissionResolution(resolution);\n const requested = context.request.params.permissions;\n response = {\n permissions:\n decision === 'decline'\n ? {}\n : structuredClone({\n ...(requested.network === null ? {} : { network: requested.network }),\n ...(requested.fileSystem === null ? {} : { fileSystem: requested.fileSystem }),\n }),\n scope: decision === 'acceptForSession' ? 'session' : 'turn',\n };\n } else if (context.request.method === 'mcpServer/elicitation/request') {\n const content = validateElicitationResolution(\n normalizeElicitationRequest({ ...context.request.params }),\n resolution,\n );\n response = {\n action: (resolution as { decision: 'accept' | 'decline' | 'cancel' }).decision,\n content,\n _meta:\n 'decision' in resolution && resolution.persist === 'session'\n ? { persist: 'session' }\n : null,\n };\n } else if (context.request.method === 'item/tool/requestUserInput') {\n if (!('answers' in resolution))\n throw new AppError('VALIDATION_ERROR', '\u6B64\u8BF7\u6C42\u9700\u8981\u7ED3\u6784\u5316\u56DE\u7B54');\n const questions = context.request.params.questions;\n const ids = new Set(questions.map((question) => question.id));\n if (Object.keys(resolution.answers).some((id) => !ids.has(id)))\n throw new AppError('VALIDATION_ERROR', '\u56DE\u7B54\u5305\u542B\u672A\u77E5\u9898\u76EE');\n const answers: ToolRequestUserInputResponse['answers'] = {};\n for (const question of questions) {\n const values = resolution.answers[question.id];\n if (\n !Array.isArray(values) ||\n !values.length ||\n values.some((value) => typeof value !== 'string' || !value.trim())\n )\n throw new AppError('VALIDATION_ERROR', `\u8BF7\u56DE\u7B54 ${question.header}`);\n if (\n question.options?.length &&\n !question.isOther &&\n values.some((value) => !question.options!.some((option) => option.label === value))\n )\n throw new AppError('VALIDATION_ERROR', `\u9898\u76EE ${question.header} \u53EA\u63A5\u53D7\u6240\u5217\u9009\u9879`);\n answers[question.id] = { answers: values };\n }\n response = { answers };\n } else {\n if (\n !('decision' in resolution) ||\n 'content' in resolution ||\n 'persist' in resolution ||\n !context.decisions.has(resolution.decision)\n )\n throw new AppError('VALIDATION_ERROR', '\u6B64\u8BF7\u6C42\u4E0D\u652F\u6301\u6240\u63D0\u4EA4\u7684\u51B3\u5B9A');\n response = { decision: context.decisions.get(resolution.decision)! };\n }\n context.responding = true;\n try {\n await this.rpc!.respond(context.action.rpcId, response);\n } catch (error) {\n if (error instanceof CodexError && !error.uncertain) context.responding = false;\n throw error;\n }\n }\n private expireActions(threadId?: string, turnId?: string): void {\n for (const [id, context] of this.actions) {\n if (threadId && context.action.threadId !== threadId) continue;\n if (turnId && context.action.turnId !== turnId) continue;\n this.emit({ type: 'action', action: { ...context.action, status: 'expired' } });\n this.actions.delete(id);\n this.actionIds.delete(context.action.rpcId);\n }\n }\n}\n"],
|
|
4
|
+
"sourcesContent": ["import { CODEX_COMPATIBILITY } from './compatibility.js';\nimport { SHELL_TIMEOUT_MS, SHELL_OUTPUT_BYTES } from '../shared/shell.js';\nimport type { CommandExecResponse } from './generated/v2/CommandExecResponse.js';\nimport type { CommandExecTerminateResponse } from './generated/v2/CommandExecTerminateResponse.js';\nimport { spawn, execFile, type ChildProcessWithoutNullStreams } from 'node:child_process';\nimport { randomUUID } from 'node:crypto';\nimport { promisify } from 'node:util';\nimport { ThreadTitles } from './thread-titles.js';\nimport { TurnTokenUsage } from './turn-token-usage.js';\nimport { AppError } from '../shared/errors.js';\nimport { threadNameError } from '../shared/thread-name.js';\nimport { permissionModeUnavailable, permissionReviewerUnavailable } from '../shared/permissions.js';\nimport {\n permissionCapabilities,\n type PermissionRequirements,\n type ProfileProvenance,\n} from './permissions.js';\nimport { mapAutoReview } from './auto-review.js';\nimport {\n normalizeElicitationRequest,\n validateElicitationResolution,\n validatePermissionResolution,\n} from '../shared/elicitation.js';\nimport type {\n ActionResolution,\n PermissionCapabilities,\n RuntimeSettings,\n PendingAction,\n Settings,\n ModelDefaults,\n ModelDefaultsResult,\n ThreadPage,\n ThreadView,\n TurnView,\n} from '../shared/types.js';\nimport type { ClientRequest } from './generated/ClientRequest.js';\nimport type { ServerNotification } from './generated/ServerNotification.js';\nimport type { ServerRequest } from './generated/ServerRequest.js';\nimport type { InitializeResponse } from './generated/InitializeResponse.js';\nimport type { GetAccountResponse } from './generated/v2/GetAccountResponse.js';\nimport type { ModelListResponse } from './generated/v2/ModelListResponse.js';\nimport type { ConfigReadResponse } from './generated/v2/ConfigReadResponse.js';\nimport type { ConfigWriteResponse } from './generated/v2/ConfigWriteResponse.js';\nimport type { ConfigRequirementsReadResponse } from './generated/v2/ConfigRequirementsReadResponse.js';\nimport type { ExperimentalFeatureListResponse } from './generated/v2/ExperimentalFeatureListResponse.js';\nimport type { Thread } from './generated/v2/Thread.js';\nimport type { ThreadArchiveResponse } from './generated/v2/ThreadArchiveResponse.js';\nimport type { ThreadSetNameResponse } from './generated/v2/ThreadSetNameResponse.js';\nimport type { ThreadUnarchiveResponse } from './generated/v2/ThreadUnarchiveResponse.js';\nimport type { ThreadLoadedListResponse } from './generated/v2/ThreadLoadedListResponse.js';\nimport type { ThreadListResponse } from './generated/v2/ThreadListResponse.js';\nimport type { ThreadReadResponse } from './generated/v2/ThreadReadResponse.js';\nimport type { ThreadStartResponse } from './generated/v2/ThreadStartResponse.js';\nimport type { ThreadForkResponse } from './generated/v2/ThreadForkResponse.js';\nimport type { ThreadResumeResponse } from './generated/v2/ThreadResumeResponse.js';\nimport type { ThreadTurnsListResponse } from './generated/v2/ThreadTurnsListResponse.js';\nimport type { ThreadItemsListResponse } from './generated/v2/ThreadItemsListResponse.js';\nimport type { TurnStartResponse } from './generated/v2/TurnStartResponse.js';\nimport type { ReviewStartResponse } from './generated/v2/ReviewStartResponse.js';\nimport type { TurnSteerResponse } from './generated/v2/TurnSteerResponse.js';\nimport type { TurnInterruptResponse } from './generated/v2/TurnInterruptResponse.js';\nimport type { CommandExecutionApprovalDecision } from './generated/v2/CommandExecutionApprovalDecision.js';\nimport type { CommandExecutionRequestApprovalResponse } from './generated/v2/CommandExecutionRequestApprovalResponse.js';\nimport type { FileChangeRequestApprovalResponse } from './generated/v2/FileChangeRequestApprovalResponse.js';\nimport type { ToolRequestUserInputResponse } from './generated/v2/ToolRequestUserInputResponse.js';\nimport type { PermissionsRequestApprovalResponse } from './generated/v2/PermissionsRequestApprovalResponse.js';\nimport type { McpServerElicitationRequestResponse } from './generated/v2/McpServerElicitationRequestResponse.js';\nimport type { FileSystemPath } from './generated/v2/FileSystemPath.js';\nimport {\n mapItem,\n mapThread,\n mapTurn,\n permissionSettings,\n serviceTierSettings,\n threadSettings,\n threadStatus,\n turnSettings,\n taskInput,\n} from './mapping.js';\nimport {\n asCodexError,\n CodexError,\n isRecord,\n RpcTransport,\n type RpcId,\n type RpcNotification,\n type RpcServerRequest,\n} from './transport.js';\nimport type { CodexClient, CodexDiagnostics, CodexEvent } from './types.js';\nimport type { ThreadCompactStartResponse } from './generated/v2/ThreadCompactStartResponse.js';\nexport type {\n CodexClient,\n CodexDiagnostics,\n CodexEvent,\n CodexEvent as AdapterEvent,\n} from './types.js';\nexport { CodexError } from './transport.js';\n\nexport const VERIFIED_CODEX_VERSION = CODEX_COMPATIBILITY.recommended;\nconst CAPABILITIES = [\n 'command/exec',\n 'command/exec/terminate',\n 'thread/name/set',\n 'thread/start',\n 'thread/fork',\n 'thread/read',\n 'thread/list',\n 'thread/resume',\n 'thread/archive',\n 'thread/loaded/list',\n 'thread/unarchive',\n 'thread/compact/start',\n 'thread/turns/list',\n 'thread/items/list',\n 'turn/start',\n 'review/start',\n 'turn/steer',\n 'turn/interrupt',\n 'model/list',\n 'config/read',\n 'config/batchWrite',\n 'configRequirements/read',\n 'experimentalFeature/list',\n 'account/read',\n];\ntype Responses = {\n 'command/exec': CommandExecResponse;\n 'command/exec/terminate': CommandExecTerminateResponse;\n 'thread/name/set': ThreadSetNameResponse;\n initialize: InitializeResponse;\n 'account/read': GetAccountResponse;\n 'model/list': ModelListResponse;\n 'config/read': ConfigReadResponse;\n 'config/batchWrite': ConfigWriteResponse;\n 'configRequirements/read': ConfigRequirementsReadResponse;\n 'experimentalFeature/list': ExperimentalFeatureListResponse;\n 'thread/list': ThreadListResponse;\n 'thread/read': ThreadReadResponse;\n 'thread/start': ThreadStartResponse;\n 'thread/fork': ThreadForkResponse;\n 'thread/resume': ThreadResumeResponse;\n 'thread/loaded/list': ThreadLoadedListResponse;\n 'thread/archive': ThreadArchiveResponse;\n 'thread/unarchive': ThreadUnarchiveResponse;\n 'thread/compact/start': ThreadCompactStartResponse;\n 'thread/turns/list': ThreadTurnsListResponse;\n 'thread/items/list': ThreadItemsListResponse;\n 'turn/start': TurnStartResponse;\n 'review/start': ReviewStartResponse;\n 'turn/steer': TurnSteerResponse;\n 'turn/interrupt': TurnInterruptResponse;\n};\nexport interface CodexAdapterOptions {\n binary: string;\n home?: string;\n /** Explicit argument override for the test simulator; production leaves this unset. */\n args?: string[];\n requestTimeoutMs?: number;\n titleTimeoutMs?: number;\n maxLineBytes?: number;\n maxStderrBytes?: number;\n}\ntype ActionContext = {\n action: PendingAction;\n request: ServerRequest;\n decisions: Map<string, CommandExecutionApprovalDecision>;\n responding: boolean;\n};\n\nfunction permissionPathLabel(path: FileSystemPath): string {\n if (path.type === 'path') return path.path;\n if (path.type === 'glob_pattern') return `\u5339\u914D\uFF1A${path.pattern}`;\n const special = path.value;\n const subpath =\n 'subpath' in special && special.subpath !== null ? `\uFF08\u5B50\u8DEF\u5F84\uFF1A${special.subpath}\uFF09` : '';\n switch (special.kind) {\n case 'root':\n return '\u6574\u4E2A\u6587\u4EF6\u7CFB\u7EDF\uFF08/\uFF09';\n case 'minimal':\n return '\u7CFB\u7EDF\u57FA\u7840\u8FD0\u884C\u76EE\u5F55';\n case 'project_roots':\n return `\u9879\u76EE\u6839\u76EE\u5F55${subpath}`;\n case 'tmpdir':\n return '\u7CFB\u7EDF\u4E34\u65F6\u76EE\u5F55\uFF08TMPDIR\uFF09';\n case 'slash_tmp':\n return '/tmp';\n case 'unknown':\n return `\u7279\u6B8A\u8DEF\u5F84\uFF1A${special.path}${subpath}`;\n }\n}\n\nexport class CodexAdapter implements CodexClient {\n private readonly commandOutputs = new Map<\n string,\n Parameters<NonNullable<CodexClient['executeCommand']>>[3]\n >();\n epoch = randomUUID();\n private child?: ChildProcessWithoutNullStreams;\n private rpc?: RpcTransport;\n private stopped = true;\n private starting?: Promise<void>;\n private recovering?: Promise<void>;\n private restartTimer?: NodeJS.Timeout;\n private restartAttempt = 0;\n private titles?: ThreadTitles;\n private readonly tokenUsage = new TurnTokenUsage();\n // Ordering only. Persisted archive state belongs exclusively to Codex.\n private archiveSequence = 0;\n private readonly archives = new Map<string, { archived: boolean; sequence: number }>();\n private listeners = new Set<(event: CodexEvent) => void>();\n private actions = new Map<string, ActionContext>();\n private actionIds = new Map<RpcId, string>();\n private stderrTail = Buffer.alloc(0);\n private disabled = new Set<string>();\n private permissionState = new Map<string, RuntimeSettings>();\n private state: CodexDiagnostics = {\n ready: false,\n connection: 'starting',\n codexVersion: null,\n verifiedVersion: VERIFIED_CODEX_VERSION,\n compatibility: 'unavailable',\n codexEpoch: this.epoch,\n authenticated: null,\n models: [],\n capabilities: [],\n };\n constructor(private readonly options: CodexAdapterOptions) {}\n get pid(): number | undefined {\n return this.child?.pid;\n }\n get ready(): boolean {\n return this.state.ready;\n }\n diagnostics(): CodexDiagnostics {\n return structuredClone(this.state);\n }\n onEvent(listener: (event: CodexEvent) => void): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n private emit(event: CodexEvent): void {\n for (const listener of this.listeners) listener(event);\n }\n private publishRuntime(): void {\n this.emit({ type: 'runtime', diagnostics: this.diagnostics() });\n }\n\n async start(): Promise<void> {\n if (this.starting) return this.starting;\n this.stopped = false;\n this.starting = this.startProcess();\n try {\n await this.starting;\n } finally {\n this.starting = undefined;\n }\n }\n private async startProcess(): Promise<void> {\n if (this.child) throw new CodexError('CODEX_BUSY', 'Codex app-server is already started');\n this.epoch = randomUUID();\n this.disabled.clear();\n this.archives.clear();\n this.state = {\n ...this.state,\n codexEpoch: this.epoch,\n ready: false,\n connection: 'starting',\n error: undefined,\n capabilities: [],\n };\n this.publishRuntime();\n try {\n const env = {\n ...process.env,\n ...(this.options.home === undefined ? {} : { CODEX_HOME: this.options.home }),\n };\n const { stdout } = await promisify(execFile)(this.options.binary, ['--version'], {\n env,\n timeout: 5000,\n maxBuffer: 64 * 1024,\n });\n const version = stdout.trim().replace(/^codex-cli\\s+/, '');\n this.state.codexVersion = version;\n this.permissionState.clear();\n this.state.compatibility = CODEX_COMPATIBILITY.verified.includes(version)\n ? 'verified'\n : 'unverified';\n const child = spawn(\n this.options.binary,\n this.options.args ?? ['app-server', '--listen', 'stdio://'],\n { env, stdio: ['pipe', 'pipe', 'pipe'], shell: false },\n );\n this.child = child;\n const rpc = new RpcTransport(child.stdin, child.stdout, {\n timeoutMs: this.options.requestTimeoutMs,\n maxLineBytes: this.options.maxLineBytes,\n });\n this.rpc = rpc;\n this.titles = new ThreadTitles(rpc, this.options.titleTimeoutMs);\n child.stderr.on('data', (chunk: Buffer) => {\n const max = this.options.maxStderrBytes ?? 64 * 1024;\n this.stderrTail = Buffer.concat([this.stderrTail, chunk.subarray(-max)]).subarray(-max);\n });\n child.on('error', (error) =>\n rpc.fail(new CodexError('CODEX_UNAVAILABLE', `Cannot start Codex: ${error.message}`, true)),\n );\n child.on('exit', (code, signal) => {\n rpc.fail(\n new CodexError(\n 'CODEX_UNAVAILABLE',\n `Codex exited (${signal ?? code ?? 'unknown'})`,\n true,\n ),\n );\n if (this.child === child) this.child = undefined;\n });\n rpc.on('notification', (message: RpcNotification) => {\n try {\n this.notification(message);\n } catch (error) {\n rpc.fail(asCodexError(error));\n }\n });\n rpc.on('request', (message: RpcServerRequest) => {\n void this.serverRequest(message).catch((error: unknown) => rpc.fail(asCodexError(error)));\n });\n rpc.on('failure', (error: CodexError) => {\n if (this.rpc !== rpc) return;\n const wasReady = this.ready;\n this.state.ready = false;\n this.tokenUsage.clear();\n this.state.connection = 'unavailable';\n this.state.error = error.message;\n this.expireActions();\n this.publishRuntime();\n if (!child.killed) child.kill('SIGTERM');\n const kill = setTimeout(() => {\n if (child.exitCode === null && child.signalCode === null) child.kill('SIGKILL');\n }, 2500);\n kill.unref();\n child.once('exit', () => clearTimeout(kill));\n if (wasReady && !this.stopped) {\n // Only metadata is logged: never RPC params, results, or session contents.\n console.error('Codex transport failed', {\n code: error.code,\n ...(error.details as object),\n });\n this.scheduleRestart();\n }\n });\n const initialized = await this.call(\n 'initialize',\n {\n clientInfo: { name: 'codex_web_ui', title: 'Codex Web UI', version: '0.1.0' },\n capabilities: {\n experimentalApi: true,\n requestAttestation: false,\n explicitGatewayOauth: true,\n },\n },\n true,\n );\n if (!isRecord(initialized) || typeof initialized.userAgent !== 'string')\n throw new CodexError(\n 'PROTOCOL_INCOMPATIBLE',\n 'Codex initialize returned a malformed result',\n true,\n );\n await rpc.notify('initialized');\n const [account, models] = await Promise.all([\n this.call('account/read', { refreshToken: false }, true),\n this.call('model/list', { limit: 100 }, true),\n ]);\n if (\n !isRecord(account) ||\n !Object.hasOwn(account, 'account') ||\n typeof account.requiresOpenaiAuth !== 'boolean'\n )\n throw new CodexError(\n 'PROTOCOL_INCOMPATIBLE',\n 'Codex account/read returned a malformed result',\n true,\n );\n this.state.authenticated = account.account !== null || !account.requiresOpenaiAuth;\n this.state.models = models.data.map((model) => ({\n id: model.model,\n name: model.displayName,\n description: model.description,\n reasoningEfforts: model.supportedReasoningEfforts.map((effort) => effort.reasoningEffort),\n defaultReasoningEffort: model.defaultReasoningEffort,\n serviceTiers:\n model.serviceTiers?.map((tier) => (tier.id === 'priority' ? 'fast' : tier.id)) ??\n model.additionalSpeedTiers,\n }));\n let cursor = models.nextCursor;\n const seen = new Set<string>();\n while (cursor) {\n if (seen.has(cursor) || seen.size >= 100)\n throw new CodexError('PROTOCOL_INCOMPATIBLE', 'Invalid model pagination');\n seen.add(cursor);\n const page = await this.call('model/list', { limit: 100, cursor }, true);\n this.state.models.push(\n ...page.data.map((model) => ({\n id: model.model,\n name: model.displayName,\n description: model.description,\n reasoningEfforts: model.supportedReasoningEfforts.map(\n (effort) => effort.reasoningEffort,\n ),\n defaultReasoningEffort: model.defaultReasoningEffort,\n serviceTiers:\n model.serviceTiers?.map((tier) => (tier.id === 'priority' ? 'fast' : tier.id)) ??\n model.additionalSpeedTiers,\n })),\n );\n cursor = page.nextCursor;\n }\n this.titles?.configure(\n account.account?.type === 'chatgpt',\n this.state.models.map((model) => model.id),\n );\n this.state.ready = true;\n this.state.connection = 'ready';\n this.state.capabilities = CAPABILITIES.filter((method) => !this.disabled.has(method));\n this.publishRuntime();\n } catch (error) {\n const failure = asCodexError(error);\n this.state.ready = false;\n this.state.connection = 'unavailable';\n this.state.error = failure.message;\n this.publishRuntime();\n await this.stopProcess(failure);\n this.scheduleRestart();\n throw failure;\n }\n }\n async stop(): Promise<void> {\n this.stopped = true;\n clearTimeout(this.restartTimer);\n this.restartTimer = undefined;\n await this.starting?.catch(() => {});\n await this.recovering;\n await this.stopProcess();\n }\n private scheduleRestart(): void {\n if (this.stopped || this.restartTimer) return;\n const delay = Math.min(1000 * 2 ** Math.min(this.restartAttempt++, 5), 30_000);\n this.restartTimer = setTimeout(() => {\n this.restartTimer = undefined;\n this.recovering = (async () => {\n await this.stopProcess();\n if (this.stopped) return;\n try {\n await this.start();\n this.restartAttempt = 0;\n } catch {\n this.scheduleRestart();\n }\n })();\n void this.recovering.finally(() => {\n this.recovering = undefined;\n });\n }, delay);\n this.restartTimer.unref();\n }\n private async stopProcess(\n reason = new CodexError('CODEX_UNAVAILABLE', 'Codex connection closed by this service', true),\n ): Promise<void> {\n const child = this.child;\n this.state.ready = false;\n this.state.connection = 'unavailable';\n this.expireActions();\n this.rpc?.fail(reason);\n if (!child || child.exitCode !== null || child.signalCode !== null) return;\n child.stdin.end();\n await new Promise<void>((resolve) => {\n const term = setTimeout(() => child.kill('SIGTERM'), 1000);\n const kill = setTimeout(() => child.kill('SIGKILL'), 2500);\n const done = setTimeout(() => {\n cleanup();\n resolve();\n }, 3500);\n const cleanup = () => {\n clearTimeout(term);\n clearTimeout(kill);\n clearTimeout(done);\n };\n child.once('exit', () => {\n cleanup();\n resolve();\n });\n });\n if (this.child === child) this.child = undefined;\n }\n private async call<M extends keyof Responses>(\n method: M,\n params: Extract<ClientRequest, { method: M }>['params'],\n initializing = false,\n timeoutMs?: number,\n ): Promise<Responses[M]> {\n if (!this.rpc || (!initializing && !this.ready))\n throw new CodexError('CODEX_UNAVAILABLE', 'Codex is not ready');\n if (this.disabled.has(method))\n throw new CodexError('PROTOCOL_INCOMPATIBLE', `Codex does not support ${method}`);\n try {\n return await this.rpc.request<Responses[M]>(method, params, undefined, timeoutMs);\n } catch (error) {\n // Concurrent startup calls can inherit the same error when cleanup fails the transport.\n if (!initializing && error instanceof CodexError && error.rpcCode === -32601) {\n this.disabled.add(method);\n this.state.capabilities = this.state.capabilities.filter((name) => name !== method);\n this.state.error = `\u5F53\u524D Codex \u7F3A\u5C11 ${method} \u80FD\u529B`;\n this.publishRuntime();\n }\n throw error;\n }\n }\n private validateSettings(settings: Settings = {}): void {\n const model =\n settings.model === undefined\n ? undefined\n : this.state.models.find((entry) => entry.id === settings.model);\n if (settings.model !== undefined && !model)\n throw new AppError('VALIDATION_ERROR', '\u6A21\u578B\u4E0D\u5728\u5F53\u524D Codex \u6A21\u578B\u5217\u8868\u4E2D');\n if (\n settings.reasoningEffort !== undefined &&\n !(\n model?.reasoningEfforts ?? this.state.models.flatMap((entry) => entry.reasoningEfforts)\n ).includes(settings.reasoningEffort)\n )\n throw new AppError('VALIDATION_ERROR', '\u6240\u9009\u63A8\u7406\u5F3A\u5EA6\u4E0D\u53D7\u5F53\u524D\u6A21\u578B\u652F\u6301');\n }\n async listThreads(\n cwd: string | string[],\n cursor?: string,\n archived = false,\n ): Promise<ThreadPage> {\n const sequence = ++this.archiveSequence;\n const result = await this.call('thread/list', {\n cwd,\n cursor,\n limit: 30,\n archived,\n sourceKinds: ['cli', 'appServer', 'vscode'],\n sortKey: 'updated_at',\n sortDirection: 'desc',\n });\n return {\n data: result.data.map((thread) => ({\n ...mapThread(thread),\n archived: this.observeArchive(thread.id, archived, sequence),\n })),\n nextCursor: result.nextCursor,\n };\n }\n\n private observeArchive(id: string, archived: boolean, sequence: number): boolean {\n const current = this.archives.get(id);\n if (current && current.sequence > sequence) return current.archived;\n this.archives.set(id, { archived, sequence });\n return archived;\n }\n\n private archiveChanged(id: string, archived: boolean): void {\n this.observeArchive(id, archived, ++this.archiveSequence);\n this.emit({ type: 'threadArchive', threadId: id, archived });\n }\n\n /** thread/read has no archive field. Query the native index, including paginated history,\n * instead of guessing from the unstable rollout path or maintaining a second database. */\n private async storedThread(thread: Thread, sequence: number): Promise<ThreadView> {\n let cursor: string | null = null;\n const seen = new Set<string>();\n let archived = false;\n do {\n const page: ThreadListResponse = await this.call('thread/list', {\n archived: true,\n cwd: thread.cwd,\n cursor,\n limit: 100,\n sourceKinds: [\n 'cli',\n 'vscode',\n 'exec',\n 'appServer',\n 'subAgent',\n 'subAgentReview',\n 'subAgentCompact',\n 'subAgentThreadSpawn',\n 'subAgentOther',\n 'unknown',\n ],\n });\n if (page.data.some((entry) => entry.id === thread.id)) {\n archived = true;\n break;\n }\n cursor = page.nextCursor;\n if (cursor && (seen.has(cursor) || seen.size >= 1000))\n throw new CodexError('PROTOCOL_INCOMPATIBLE', 'Invalid archive pagination');\n if (cursor) seen.add(cursor);\n } while (cursor);\n return { ...mapThread(thread), archived: this.observeArchive(thread.id, archived, sequence) };\n }\n\n /** Native archive also shuts down spawned descendants, even already-archived ones. */\n private async assertArchiveIdle(rootId: string): Promise<void> {\n const threads = new Map<string, Thread>();\n const read = async (id: string): Promise<Thread> => {\n let thread = threads.get(id);\n if (!thread) {\n thread = (await this.call('thread/read', { threadId: id, includeTurns: false })).thread;\n threads.set(id, thread);\n }\n return thread;\n };\n let cursor: string | null = null;\n const seen = new Set<string>();\n do {\n const page: ThreadLoadedListResponse = await this.call('thread/loaded/list', {\n cursor,\n limit: 100,\n });\n for (const id of page.data) {\n let thread: Thread;\n try {\n thread = await read(id);\n } catch (error) {\n // A completed helper can unload after the loaded-thread snapshot.\n if (\n error instanceof CodexError &&\n error.rpcCode === -32600 &&\n error.message === `thread not loaded: ${id}`\n )\n continue;\n throw error;\n }\n if (thread.status.type !== 'active') continue;\n const ancestors = new Set<string>();\n for (;;) {\n if (thread.id === rootId)\n throw new AppError('THREAD_BUSY', '\u4F1A\u8BDD\u6216\u5176\u5B50\u4EFB\u52A1\u4ECD\u5728\u8FD0\u884C\uFF0C\u7ED3\u675F\u540E\u624D\u80FD\u5F52\u6863', 409);\n if (!thread.parentThreadId) break;\n if (ancestors.has(thread.id))\n throw new CodexError('PROTOCOL_INCOMPATIBLE', 'Invalid thread ancestry');\n ancestors.add(thread.id);\n thread = await read(thread.parentThreadId);\n }\n }\n cursor = page.nextCursor;\n if (cursor && (seen.has(cursor) || seen.size >= 1000))\n throw new CodexError('PROTOCOL_INCOMPATIBLE', 'Invalid loaded thread pagination');\n if (cursor) seen.add(cursor);\n } while (cursor);\n }\n\n async renameThread(id: string, name: string): Promise<void> {\n const problem = threadNameError(name);\n if (problem) throw new AppError('VALIDATION_ERROR', problem);\n const epoch = this.epoch;\n // A generated name may already be on the wire. Finish it before the explicit write.\n await this.titles?.prepareManualName(id);\n if (this.epoch !== epoch || !this.ready)\n throw new CodexError(\n 'CODEX_UNAVAILABLE',\n '\u91CD\u547D\u540D\u7B49\u5F85\u671F\u95F4 Codex \u5B9E\u4F8B\u5DF2\u53D8\u5316\uFF0C\u8BF7\u6838\u5BF9\u540D\u79F0',\n true,\n );\n await this.call('thread/name/set', { threadId: id, name: name.trim() });\n }\n\n async archiveThread(id: string): Promise<void> {\n await this.assertArchiveIdle(id);\n await this.call('thread/archive', { threadId: id });\n this.archiveChanged(id, true);\n }\n\n async unarchiveThread(id: string): Promise<ThreadView> {\n const { thread } = await this.call('thread/unarchive', { threadId: id });\n this.archiveChanged(id, false);\n return { ...mapThread(thread), archived: false };\n }\n private async readThreadHeader(id: string): Promise<Thread> {\n try {\n return (await this.call('thread/read', { threadId: id, includeTurns: false })).thread;\n } catch (error) {\n if (\n error instanceof CodexError &&\n error.rpcCode === -32600 &&\n error.message === `thread not loaded: ${id}`\n )\n throw new AppError('THREAD_NOT_FOUND', '\u4F1A\u8BDD\u5C1A\u672A\u4FDD\u5B58\u6216\u5DF2\u4E0D\u5B58\u5728', 404, { threadId: id });\n throw error;\n }\n }\n\n async readThreadMetadata(id: string): Promise<ThreadView> {\n const sequence = ++this.archiveSequence;\n return this.storedThread(await this.readThreadHeader(id), sequence);\n }\n async readThreadPage(id: string, continuation?: string): Promise<ThreadView> {\n const epoch = this.epoch;\n let cursor: string | null = null;\n if (continuation) {\n try {\n const decoded = JSON.parse(Buffer.from(continuation, 'base64url').toString('utf8'));\n if (\n decoded.threadId !== id ||\n decoded.epoch !== epoch ||\n typeof decoded.cursor !== 'string'\n )\n throw new Error('Invalid cursor');\n cursor = decoded.cursor;\n } catch {\n throw new AppError('HISTORY_CURSOR_EXPIRED', '\u5386\u53F2\u5206\u9875\u5DF2\u5931\u6548\uFF0C\u8BF7\u91CD\u65B0\u540C\u6B65\u4F1A\u8BDD\u3002', 409);\n }\n }\n const sequence = ++this.archiveSequence;\n const header = await this.readThreadHeader(id);\n // Legacy rollout files expose no paging protocol. Keep the compatibility path explicit.\n if (header.historyMode !== 'paginated') return this.readThread(id);\n const page = await this.call('thread/turns/list', {\n threadId: id,\n cursor,\n limit: 12,\n sortDirection: 'desc',\n itemsView: 'summary',\n });\n if (page.nextCursor && page.nextCursor === cursor)\n throw new CodexError('PROTOCOL_INCOMPATIBLE', 'Invalid turn pagination');\n await this.hydrateTurns(id, page.data);\n if (this.epoch !== epoch)\n throw new AppError('HISTORY_CURSOR_EXPIRED', '\u8BFB\u53D6\u671F\u95F4 Codex \u5DF2\u91CD\u542F\uFF0C\u8BF7\u91CD\u65B0\u540C\u6B65\u4F1A\u8BDD\u3002', 409);\n const view = await this.storedThread(\n { ...header, turns: page.data.slice().reverse() },\n sequence,\n );\n return {\n ...view,\n history: {\n olderCursor: page.nextCursor\n ? Buffer.from(\n JSON.stringify({\n threadId: id,\n epoch,\n cursor: page.nextCursor,\n }),\n ).toString('base64url')\n : null,\n },\n };\n }\n\n private async hydrateTurns(id: string, turns: Thread['turns']): Promise<void> {\n for (const turn of turns) {\n if (turn.itemsView === 'full') continue;\n let cursor: string | null = null;\n const seen = new Set<string>();\n turn.items = [];\n do {\n const page: ThreadItemsListResponse = await this.call('thread/items/list', {\n threadId: id,\n turnId: turn.id,\n cursor,\n limit: 20,\n sortDirection: 'asc',\n });\n turn.items.push(...page.data.map((entry) => entry.item));\n cursor = page.nextCursor;\n if (cursor && (seen.has(cursor) || seen.size >= 1000))\n throw new CodexError('PROTOCOL_INCOMPATIBLE', 'Invalid item pagination');\n if (cursor) seen.add(cursor);\n } while (cursor);\n }\n }\n\n async readThread(id: string): Promise<ThreadView> {\n const sequence = ++this.archiveSequence;\n const thread = await this.readThreadHeader(id);\n if (thread.historyMode !== 'paginated')\n return this.storedThread(\n (await this.call('thread/read', { threadId: id, includeTurns: true })).thread,\n sequence,\n );\n let cursor: string | null = null;\n const seen = new Set<string>();\n thread.turns = [];\n do {\n const page: ThreadTurnsListResponse = await this.call('thread/turns/list', {\n threadId: id,\n cursor,\n limit: 100,\n sortDirection: 'asc',\n itemsView: 'summary',\n });\n for (const turn of page.data) {\n if (turn.itemsView !== 'full') {\n let itemCursor: string | null = null;\n const itemSeen = new Set<string>();\n turn.items = [];\n do {\n const items: ThreadItemsListResponse = await this.call('thread/items/list', {\n threadId: id,\n turnId: turn.id,\n cursor: itemCursor,\n limit: 20,\n sortDirection: 'asc',\n });\n turn.items.push(...items.data.map((entry) => entry.item));\n itemCursor = items.nextCursor;\n if (itemCursor && (itemSeen.has(itemCursor) || itemSeen.size >= 1000))\n throw new CodexError('PROTOCOL_INCOMPATIBLE', 'Invalid item pagination');\n if (itemCursor) itemSeen.add(itemCursor);\n } while (itemCursor);\n }\n }\n thread.turns.push(...page.data);\n cursor = page.nextCursor;\n if (cursor && (seen.has(cursor) || seen.size >= 1000))\n throw new CodexError('PROTOCOL_INCOMPATIBLE', 'Invalid turn pagination');\n if (cursor) seen.add(cursor);\n } while (cursor);\n return this.storedThread(thread, sequence);\n }\n async createThread(cwd: string, settings?: Settings): Promise<ThreadView> {\n this.validateSettings(settings);\n await this.validatePermissionSettings(cwd, settings);\n const titles = this.titles;\n const result = await this.call('thread/start', { cwd, ...threadSettings(settings) });\n this.tokenUsage.created(result.thread.id);\n titles?.register(result);\n return {\n ...mapThread(result.thread),\n runtimeSettings: await this.responseRuntimeSettings(result),\n };\n }\n async saveModelDefaults(settings: ModelDefaults): Promise<ModelDefaultsResult> {\n this.validateSettings({\n model: settings.model,\n ...(settings.reasoningEffort === null ? {} : { reasoningEffort: settings.reasoningEffort }),\n });\n // Match the CLI picker: write a complete pair to the owning server's user/profile config.\n // No file path or permission fields can be supplied by the browser.\n const result = await this.call('config/batchWrite', {\n edits: [\n { keyPath: 'model', value: settings.model, mergeStrategy: 'replace' },\n {\n keyPath: 'model_reasoning_effort',\n value: settings.reasoningEffort,\n mergeStrategy: 'replace',\n },\n ],\n reloadUserConfig: true,\n });\n return { status: result.status };\n }\n async readRuntimeSettings(cwd: string): Promise<RuntimeSettings> {\n const { config } = await this.call('config/read', { cwd, includeLayers: false });\n // Config can contain credentials and instructions. Only displayable fields cross the gateway.\n return {\n model: typeof config.model === 'string' ? config.model : null,\n reasoningEffort:\n typeof config.model_reasoning_effort === 'string' ? config.model_reasoning_effort : null,\n ...serviceTierSettings(config.service_tier),\n sandbox: config.sandbox_mode ?? null,\n approvalPolicy:\n typeof config.approval_policy === 'string'\n ? config.approval_policy\n : config.approval_policy\n ? 'granular'\n : null,\n approvalReviewer: config.approvals_reviewer ?? null,\n networkAccess:\n config.sandbox_mode === 'workspace-write'\n ? (config.sandbox_workspace_write?.network_access ?? null)\n : null,\n permissionMode:\n typeof config.default_permissions === 'string' &&\n ![':workspace', ':read-only', ':danger-full-access'].includes(config.default_permissions)\n ? 'custom'\n : null,\n permissionProfile:\n typeof config.default_permissions === 'string'\n ? { id: config.default_permissions, extends: null }\n : null,\n writableRoots: config.sandbox_workspace_write?.writable_roots ?? null,\n excludeTmpdirEnvVar: config.sandbox_workspace_write?.exclude_tmpdir_env_var ?? null,\n excludeSlashTmp: config.sandbox_workspace_write?.exclude_slash_tmp ?? null,\n permissionCapabilities: await this.readPermissionCapabilities(undefined, config),\n };\n }\n private async readPermissionCapabilities(\n threadId?: string,\n config?: ConfigReadResponse['config'],\n ): Promise<PermissionCapabilities> {\n if (!CODEX_COMPATIBILITY.verified.includes(this.state.codexVersion ?? ''))\n return permissionCapabilities(\n null,\n false,\n `\u6743\u9650\u6A21\u5F0F\u4EC5\u6838\u9A8C\u8FC7 Codex ${VERIFIED_CODEX_VERSION}\uFF1B\u5F53\u524D\u7248\u672C ${this.state.codexVersion ?? '\u672A\u77E5'}`,\n );\n try {\n const [requirements, first] = await Promise.all([\n this.call('configRequirements/read', undefined),\n this.call('experimentalFeature/list', { limit: 200, ...(threadId ? { threadId } : {}) }),\n ]);\n if (!Object.hasOwn(requirements, 'requirements') || !Array.isArray(first.data))\n throw new Error('Permission capability response is incomplete');\n const features = [...first.data];\n let cursor = first.nextCursor;\n const seen = new Set<string>();\n while (cursor) {\n if (seen.has(cursor) || seen.size >= 100) throw new Error('Invalid feature pagination');\n seen.add(cursor);\n const page = await this.call('experimentalFeature/list', {\n limit: 200,\n cursor,\n ...(threadId ? { threadId } : {}),\n });\n features.push(...page.data);\n cursor = page.nextCursor;\n }\n const configFeatures = config?.features;\n const explicit = isRecord(configFeatures) ? configFeatures.guardian_approval : undefined;\n const autoReview =\n typeof explicit === 'boolean'\n ? explicit\n : features.find((entry) => entry.name === 'guardian_approval')?.enabled === true;\n return permissionCapabilities(\n requirements.requirements as PermissionRequirements | null,\n autoReview,\n );\n } catch {\n return permissionCapabilities(\n null,\n false,\n '\u65E0\u6CD5\u6838\u5B9E\u5F53\u524D Codex \u7684\u529F\u80FD\u548C\u53D7\u7BA1\u8981\u6C42\uFF0C\u8BF7\u91CD\u8BD5\u6216\u68C0\u67E5\u7248\u672C\u652F\u6301',\n );\n }\n }\n private async validatePermissionSettings(\n cwd: string,\n settings?: Settings,\n threadId?: string,\n ): Promise<void> {\n if (!settings?.permissionMode && settings?.approvalReviewer === undefined) return;\n const epoch = this.epoch;\n const defaults =\n !threadId || !this.permissionState.has(threadId)\n ? await this.readRuntimeSettings(cwd)\n : undefined;\n const capabilities = defaults\n ? defaults.permissionCapabilities\n : await this.readPermissionCapabilities(threadId);\n if (epoch !== this.epoch)\n throw new AppError('CODEX_UNAVAILABLE', 'Codex \u8FD0\u884C\u5B9E\u4F8B\u5DF2\u53D8\u5316\uFF0C\u8BF7\u91CD\u8BD5');\n const model =\n settings.model ??\n (threadId ? this.permissionState.get(threadId)?.model : undefined) ??\n defaults?.model;\n const reason = settings.permissionMode\n ? permissionModeUnavailable(settings.permissionMode, capabilities, model)\n : permissionReviewerUnavailable(settings.approvalReviewer!, capabilities, model);\n if (reason) throw new AppError('PERMISSION_MODE_UNAVAILABLE', reason);\n }\n private async responseRuntimeSettings(result: ThreadStartResponse): Promise<RuntimeSettings> {\n const previous = this.permissionState.get(result.thread.id);\n const settings: RuntimeSettings = {\n model: result.model ?? result.thread.model ?? null,\n reasoningEffort: result.reasoningEffort ?? null,\n ...serviceTierSettings(result.serviceTier),\n ...permissionSettings(\n result.sandbox,\n result.approvalPolicy,\n result.approvalsReviewer,\n (result as ThreadStartResponse & ProfileProvenance).activePermissionProfile,\n result.cwd,\n ),\n permissionCapabilities: await this.readPermissionCapabilities(result.thread.id),\n };\n const latest = this.permissionState.get(result.thread.id);\n const confirmed =\n latest && latest !== previous\n ? { ...latest, permissionCapabilities: settings.permissionCapabilities }\n : settings;\n this.permissionState.set(result.thread.id, confirmed);\n // The service correctly keeps a newer settings notification over a lifecycle response.\n // Publish availability alongside that newer state so the delayed capability read is not lost.\n if (confirmed !== settings)\n this.emit({ type: 'threadSettings', threadId: result.thread.id, settings: confirmed });\n return settings;\n }\n async resumeThread(id: string, cwd: string, settings?: Settings): Promise<ThreadView> {\n this.validateSettings(settings);\n await this.validatePermissionSettings(cwd, settings, id);\n const titles = this.titles;\n let result: ThreadResumeResponse;\n try {\n result = await this.call('thread/resume', {\n threadId: id,\n cwd,\n ...threadSettings(settings),\n excludeTurns: true,\n });\n } catch (error) {\n // Verified with two 0.164.0 processes, for both legacy and paginated histories.\n // -32600 alone covers many failures; match this thread's writer conflict exactly.\n if (\n error instanceof CodexError &&\n error.rpcCode === -32600 &&\n error.message === `thread ${id} already has an active writer`\n )\n throw new AppError('THREAD_IN_USE', '\u6B64\u4F1A\u8BDD\u6B63\u88AB\u5176\u4ED6\u8FDB\u7A0B\u4F7F\u7528', 409, { threadId: id });\n throw error;\n }\n titles?.register(result);\n const view = await this.readThreadPage(result.thread.id);\n return { ...view, runtimeSettings: await this.responseRuntimeSettings(result) };\n }\n async forkThread(id: string, cwd: string, settings?: Settings): Promise<ThreadView> {\n this.validateSettings(settings);\n await this.validatePermissionSettings(cwd, settings, id);\n const titles = this.titles;\n const result = await this.call('thread/fork', {\n threadId: id,\n cwd,\n ...threadSettings(settings),\n // Omitting lastTurnId copies the persisted history, including an active turn's\n // interruption marker in the fork. The source is never resumed or interrupted.\n excludeTurns: true,\n });\n let forkedId: string | undefined;\n try {\n if (isRecord(result) && isRecord(result.thread) && typeof result.thread.id === 'string')\n forkedId = result.thread.id === id ? undefined : result.thread.id;\n const metadata = mapThread(result.thread);\n if (metadata.id === id)\n throw new CodexError('PROTOCOL_INCOMPATIBLE', 'Codex fork returned the source thread ID');\n forkedId = metadata.id;\n const thread = await this.readThread(forkedId);\n if (thread.id !== forkedId)\n throw new CodexError('PROTOCOL_INCOMPATIBLE', 'Codex returned a different fork thread ID');\n titles?.register(result);\n return { ...thread, runtimeSettings: await this.responseRuntimeSettings(result) };\n } catch (error) {\n const failure = asCodexError(error);\n // The mutating RPC already succeeded. A read failure cannot make a retry safe.\n throw new CodexError(\n failure.code,\n forkedId\n ? `\u5DF2\u521B\u5EFA\u5206\u652F\u4F1A\u8BDD ${forkedId}\uFF0C\u4F46\u65E0\u6CD5\u52A0\u8F7D\u5386\u53F2\uFF1B\u8BF7\u4ECE\u4F1A\u8BDD\u5217\u8868\u91CD\u65B0\u6253\u5F00\uFF0C\u4E0D\u8981\u91CD\u590D fork\u3002${failure.message}`\n : `Codex fork \u5DF2\u8FD4\u56DE\u7ED3\u679C\uFF0C\u4F46\u65E0\u6CD5\u786E\u8BA4\u65B0\u4F1A\u8BDD\uFF1B\u8BF7\u68C0\u67E5\u4F1A\u8BDD\u5217\u8868\uFF0C\u4E0D\u8981\u91CD\u590D fork\u3002${failure.message}`,\n true,\n failure.rpcCode,\n );\n }\n }\n async startTurn(\n id: string,\n cwd: string,\n text: string,\n settings?: Settings,\n images?: string[],\n ): Promise<TurnView> {\n this.validateSettings(settings);\n await this.validatePermissionSettings(cwd, settings, id);\n const turn = mapTurn(\n id,\n (\n await this.call('turn/start', {\n threadId: id,\n cwd,\n input: taskInput(text, images),\n ...turnSettings(cwd, settings),\n })\n ).turn,\n );\n return turn;\n }\n async startReview(id: string): Promise<TurnView> {\n const result = await this.call('review/start', {\n threadId: id,\n target: { type: 'uncommittedChanges' },\n delivery: 'inline',\n });\n if (!isRecord(result) || result.reviewThreadId !== id)\n throw new CodexError(\n 'PROTOCOL_INCOMPATIBLE',\n 'Codex review returned a different thread; review result needs reconciliation',\n true,\n );\n return mapTurn(id, result.turn);\n }\n steerTurn(\n id: string,\n turnId: string,\n text: string,\n images?: string[],\n ): Promise<TurnSteerResponse> {\n return this.call('turn/steer', {\n threadId: id,\n expectedTurnId: turnId,\n input: taskInput(text, images),\n });\n }\n async interruptTurn(id: string, turnId: string): Promise<void> {\n await this.call('turn/interrupt', { threadId: id, turnId });\n }\n\n async compactThread(id: string): Promise<void> {\n // The empty response acknowledges dispatch, not completion. Turn notifications\n // carry the compaction's identity and final outcome.\n await this.call('thread/compact/start', { threadId: id });\n }\n\n async executeCommand(\n processId: string,\n cwd: string,\n command: string,\n output: Parameters<NonNullable<CodexClient['executeCommand']>>[3],\n ) {\n this.commandOutputs.set(processId, output);\n try {\n return await this.call(\n 'command/exec',\n {\n processId,\n cwd,\n command:\n process.platform === 'win32'\n ? ['cmd.exe', '/d', '/s', '/c', command]\n : ['/bin/sh', '-c', command],\n streamStdoutStderr: true,\n streamStdin: false,\n tty: false,\n timeoutMs: SHELL_TIMEOUT_MS,\n outputBytesCap: SHELL_OUTPUT_BYTES / 2,\n // Omit sandboxPolicy: preserve the server's configured permission policy.\n },\n false,\n SHELL_TIMEOUT_MS + 5000,\n );\n } finally {\n this.commandOutputs.delete(processId);\n }\n }\n async terminateCommand(processId: string): Promise<void> {\n await this.call('command/exec/terminate', { processId });\n }\n\n private notification(message: RpcNotification): void {\n if (this.titles?.notification(message)) return;\n const event = message as ServerNotification;\n const p = event.params;\n switch (event.method) {\n case 'command/exec/outputDelta': {\n const { processId, stream, deltaBase64, capReached } = event.params;\n this.commandOutputs.get(processId)?.(\n stream,\n Buffer.from(deltaBase64, 'base64'),\n capReached,\n );\n break;\n }\n case 'thread/settings/updated':\n {\n const observed: RuntimeSettings = {\n model: event.params.threadSettings.model ?? null,\n reasoningEffort: event.params.threadSettings.effort ?? null,\n ...serviceTierSettings(event.params.threadSettings.serviceTier),\n ...permissionSettings(\n event.params.threadSettings.sandboxPolicy,\n event.params.threadSettings.approvalPolicy,\n event.params.threadSettings.approvalsReviewer,\n event.params.threadSettings.activePermissionProfile,\n event.params.threadSettings.cwd,\n ),\n permissionCapabilities: this.permissionState.get(event.params.threadId)\n ?.permissionCapabilities,\n };\n this.permissionState.set(event.params.threadId, observed);\n this.emit({\n type: 'threadSettings',\n threadId: event.params.threadId,\n settings: observed,\n });\n }\n break;\n case 'item/autoApprovalReview/started':\n case 'item/autoApprovalReview/completed':\n this.emit({\n type: 'autoReview',\n threadId: event.params.threadId,\n turnId: event.params.turnId,\n review: mapAutoReview(event.params),\n });\n break;\n case 'thread/started':\n this.emit({ type: 'thread', thread: mapThread(event.params.thread) });\n break;\n case 'thread/archived':\n this.archiveChanged(event.params.threadId, true);\n break;\n case 'thread/unarchived':\n this.archiveChanged(event.params.threadId, false);\n break;\n case 'thread/name/updated':\n this.emit({\n type: 'threadName',\n threadId: event.params.threadId,\n name: event.params.threadName,\n });\n break;\n case 'thread/status/changed':\n this.emit({\n type: 'threadStatus',\n threadId: event.params.threadId,\n status: threadStatus(event.params.status),\n });\n break;\n case 'turn/started':\n case 'turn/completed': {\n const { threadId, turn } = event.params;\n if (event.method === 'turn/started') this.tokenUsage.started(threadId, turn.id);\n const outputTokens =\n event.method === 'turn/completed'\n ? this.tokenUsage.completed(threadId, turn.id)\n : undefined;\n this.emit({\n type: 'turn',\n threadId,\n turn: {\n ...mapTurn(threadId, turn),\n ...(outputTokens !== undefined ? { outputTokens } : {}),\n },\n });\n if (event.method === 'turn/completed')\n this.expireActions(event.params.threadId, event.params.turn.id);\n break;\n }\n case 'thread/tokenUsage/updated':\n this.tokenUsage.updated(\n event.params.threadId,\n event.params.turnId,\n event.params.tokenUsage?.total?.outputTokens,\n );\n break;\n case 'thread/compacted':\n this.tokenUsage.compacted(event.params.threadId, event.params.turnId);\n this.emit({ type: 'compactionCompleted', ...event.params });\n break;\n case 'item/started':\n case 'item/completed':\n if (event.params.item.type === 'contextCompaction')\n this.tokenUsage.compacted(event.params.threadId, event.params.turnId);\n if (['agentMessage', 'plan', 'reasoning'].includes(event.params.item.type))\n this.emit({\n type: 'turnProgress',\n threadId: event.params.threadId,\n turnId: event.params.turnId,\n });\n this.emit({\n type: 'item',\n threadId: event.params.threadId,\n turnId: event.params.turnId,\n item: {\n ...mapItem(event.params.item),\n ...(event.params.item.type === 'contextCompaction'\n ? { status: event.method === 'item/started' ? 'inProgress' : 'completed' }\n : {}),\n },\n });\n break;\n case 'item/agentMessage/delta':\n case 'item/plan/delta':\n case 'item/reasoning/summaryTextDelta':\n case 'item/reasoning/textDelta':\n case 'item/commandExecution/outputDelta':\n case 'item/fileChange/outputDelta':\n // Background tool output can continue while the model stream is retrying.\n // Only model content proves that this turn's upstream stream resumed.\n if (!event.method.includes('outputDelta'))\n this.emit({\n type: 'turnProgress',\n threadId: event.params.threadId,\n turnId: event.params.turnId,\n });\n this.emit({\n type: 'delta',\n threadId: event.params.threadId,\n turnId: event.params.turnId,\n itemId: event.params.itemId,\n field: event.method.includes('outputDelta') ? 'output' : 'text',\n delta: event.params.delta,\n itemType: event.method.split('/')[1]!,\n });\n break;\n case 'item/reasoning/summaryPartAdded':\n case 'rawResponse/completed':\n this.emit({\n type: 'turnProgress',\n threadId: event.params.threadId,\n turnId: event.params.turnId,\n });\n break;\n case 'turn/diff/updated':\n this.emit({\n type: 'diff',\n threadId: event.params.threadId,\n turnId: event.params.turnId,\n diff: event.params.diff,\n });\n break;\n case 'item/fileChange/patchUpdated':\n this.emit({\n type: 'item',\n threadId: event.params.threadId,\n turnId: event.params.turnId,\n item: mapItem({\n type: 'fileChange',\n id: event.params.itemId,\n changes: event.params.changes,\n status: 'inProgress',\n }),\n });\n break;\n case 'serverRequest/resolved': {\n const actionId = this.actionIds.get(event.params.requestId);\n if (actionId) {\n this.emit({ type: 'actionResolved', actionId });\n this.actions.delete(actionId);\n this.actionIds.delete(event.params.requestId);\n }\n break;\n }\n case 'error':\n // Upstream retries/failures belong to a turn, not to the app-server process.\n this.emit({\n type: 'turnError',\n threadId: event.params.threadId,\n turnId: event.params.turnId,\n message: event.params.error.message,\n willRetry: event.params.willRetry,\n });\n break;\n default: // Unknown noninteractive notifications cannot authorize any action.\n if (!isRecord(p)) break;\n }\n }\n private async serverRequest(message: RpcServerRequest): Promise<void> {\n if (isRecord(message.params) && this.titles?.isInternal(message.params.threadId)) {\n await this.rpc?.reject(\n message.id,\n -32601,\n 'Interactive tools are disabled for title generation',\n );\n return;\n }\n const request = message as ServerRequest;\n const params: Record<string, unknown> = isRecord(message.params) ? message.params : {};\n const action: PendingAction = {\n actionId: randomUUID(),\n codexEpoch: this.epoch,\n rpcId: message.id,\n kind: 'unsupported',\n status: 'pending',\n title: '\u4E0D\u652F\u6301\u7684 Codex \u4EA4\u4E92\u8BF7\u6C42',\n options: [],\n ...(typeof params.threadId === 'string' ? { threadId: params.threadId } : {}),\n ...(typeof params.turnId === 'string' ? { turnId: params.turnId } : {}),\n };\n const decisions = new Map<string, CommandExecutionApprovalDecision>();\n if (\n request.method === 'item/commandExecution/requestApproval' ||\n request.method === 'item/fileChange/requestApproval'\n ) {\n for (const [id, label] of [\n ['accept', '\u5141\u8BB8\u672C\u6B21'],\n ['acceptForSession', '\u672C\u4F1A\u8BDD\u5141\u8BB8'],\n ['decline', '\u62D2\u7EDD'],\n ['cancel', '\u53D6\u6D88\u5F53\u524D\u4EFB\u52A1'],\n ] as const) {\n action.options.push({ id, label });\n decisions.set(id, id);\n }\n action.reason = request.params.reason ?? undefined;\n if (request.method === 'item/commandExecution/requestApproval') {\n const p = request.params;\n action.kind = p.networkApprovalContext ? 'network' : 'command';\n action.title = p.networkApprovalContext\n ? `\u7F51\u7EDC\u6743\u9650\uFF1A${p.networkApprovalContext.protocol}://${p.networkApprovalContext.host}`\n : '\u547D\u4EE4\u5BA1\u6279';\n action.command = p.command ?? undefined;\n action.cwd = p.cwd ?? undefined;\n action.details = {\n kind: p.kind,\n network: p.networkApprovalContext,\n commandActions: p.commandActions,\n };\n if (p.proposedExecpolicyAmendment) {\n action.options.push({\n id: 'acceptWithRule',\n label: `\u5141\u8BB8\u5E76\u8BB0\u4F4F\u547D\u4EE4\u89C4\u5219\uFF1A${p.proposedExecpolicyAmendment.join(' ')}`,\n });\n decisions.set('acceptWithRule', {\n acceptWithExecpolicyAmendment: { execpolicy_amendment: p.proposedExecpolicyAmendment },\n });\n }\n p.proposedNetworkPolicyAmendments?.forEach((amendment, index) => {\n const id = `networkRule:${index}`;\n action.options.push({ id, label: `\u5E94\u7528\u7F51\u7EDC\u89C4\u5219\uFF1A${JSON.stringify(amendment)}` });\n decisions.set(id, {\n applyNetworkPolicyAmendment: { network_policy_amendment: amendment },\n });\n });\n } else {\n action.kind = 'file';\n action.title = '\u6587\u4EF6\u53D8\u66F4\u5BA1\u6279';\n action.details = { itemId: request.params.itemId, grantRoot: request.params.grantRoot };\n }\n } else if (request.method === 'item/permissions/requestApproval') {\n const p = request.params;\n action.kind = 'permissions';\n action.title = '\u989D\u5916\u6743\u9650\u5BA1\u6279';\n action.reason = p.reason ?? undefined;\n action.cwd = p.cwd;\n action.options = [\n { id: 'accept', label: '\u5F53\u524D\u4EFB\u52A1\u5141\u8BB8' },\n { id: 'acceptForSession', label: '\u672C\u4F1A\u8BDD\u5141\u8BB8' },\n { id: 'decline', label: '\u62D2\u7EDD' },\n ];\n action.permissionRequest = {\n ...(p.permissions.network === null ? {} : { network: p.permissions.network.enabled }),\n ...(p.permissions.fileSystem === null\n ? {}\n : {\n fileSystem: {\n read: p.permissions.fileSystem.read ?? [],\n write: p.permissions.fileSystem.write ?? [],\n entries: (p.permissions.fileSystem.entries ?? []).map((entry) => ({\n path: permissionPathLabel(entry.path),\n access: entry.access,\n })),\n ...(p.permissions.fileSystem.globScanMaxDepth === undefined\n ? {}\n : {\n globScanMaxDepth: p.permissions.fileSystem.globScanMaxDepth,\n }),\n },\n }),\n };\n action.details = {\n itemId: p.itemId,\n environmentId: p.environmentId,\n permissions: p.permissions,\n };\n } else if (request.method === 'mcpServer/elicitation/request') {\n action.kind = 'elicitation';\n action.reason = request.params.message;\n action.elicitation = normalizeElicitationRequest(params);\n action.title = `${action.elicitation.approval ? 'MCP \u5DE5\u5177\u5BA1\u6279' : 'MCP \u4EA4\u4E92'}\uFF1A${request.params.serverName}`;\n action.options = [\n {\n id: 'accept',\n label: action.elicitation.approval\n ? '\u5141\u8BB8\u672C\u6B21'\n : action.elicitation.mode === 'url'\n ? '\u5DF2\u5B8C\u6210\uFF0C\u7EE7\u7EED'\n : '\u63D0\u4EA4',\n },\n ...(action.elicitation.approval?.allowSession\n ? [{ id: 'acceptSession', label: '\u672C\u4F1A\u8BDD\u5141\u8BB8' }]\n : []),\n { id: 'decline', label: '\u62D2\u7EDD' },\n { id: 'cancel', label: '\u53D6\u6D88' },\n ];\n // Keep an unsupported schema reviewable while allowing an explicit decline/cancel.\n if (action.elicitation.schemaError)\n action.details = { requestedSchema: params.requestedSchema, mode: params.mode };\n } else if (request.method === 'item/tool/requestUserInput') {\n action.kind = 'questions';\n action.title = '\u9700\u8981\u4F60\u7684\u56DE\u7B54';\n action.blocking = request.params.isBlocking;\n action.questions = request.params.questions.map((question) => ({\n ...question,\n options: question.options ?? [],\n }));\n } else {\n action.status = 'expired';\n action.reason = `\u5F53\u524D Web UI \u5C1A\u672A\u5B9E\u73B0 ${message.method}`;\n this.emit({ type: 'action', action });\n this.state.error = action.reason;\n this.publishRuntime();\n await this.rpc!.reject(\n message.id,\n -32601,\n `Unsupported interactive request: ${message.method}`,\n );\n return;\n }\n this.actions.set(action.actionId, { action, request, decisions, responding: false });\n this.actionIds.set(message.id, action.actionId);\n this.emit({ type: 'action', action: structuredClone(action) });\n }\n async respond(actionId: string, resolution: ActionResolution): Promise<void> {\n const context = this.actions.get(actionId);\n if (!context || context.action.codexEpoch !== this.epoch || !this.ready)\n throw new AppError('ACTION_EXPIRED', '\u6B64\u4EBA\u5DE5\u8BF7\u6C42\u5DF2\u5931\u6548', 409);\n if (context.responding) throw new AppError('ACTION_CONFLICT', '\u6B64\u4EBA\u5DE5\u8BF7\u6C42\u5DF2\u63D0\u4EA4\u56DE\u7B54', 409);\n let response:\n | ToolRequestUserInputResponse\n | CommandExecutionRequestApprovalResponse\n | FileChangeRequestApprovalResponse\n | PermissionsRequestApprovalResponse\n | McpServerElicitationRequestResponse;\n if (context.request.method === 'item/permissions/requestApproval') {\n const decision = validatePermissionResolution(resolution);\n const requested = context.request.params.permissions;\n response = {\n permissions:\n decision === 'decline'\n ? {}\n : structuredClone({\n ...(requested.network === null ? {} : { network: requested.network }),\n ...(requested.fileSystem === null ? {} : { fileSystem: requested.fileSystem }),\n }),\n scope: decision === 'acceptForSession' ? 'session' : 'turn',\n };\n } else if (context.request.method === 'mcpServer/elicitation/request') {\n const content = validateElicitationResolution(\n normalizeElicitationRequest({ ...context.request.params }),\n resolution,\n );\n response = {\n action: (resolution as { decision: 'accept' | 'decline' | 'cancel' }).decision,\n content,\n _meta:\n 'decision' in resolution && resolution.persist === 'session'\n ? { persist: 'session' }\n : null,\n };\n } else if (context.request.method === 'item/tool/requestUserInput') {\n if (!('answers' in resolution))\n throw new AppError('VALIDATION_ERROR', '\u6B64\u8BF7\u6C42\u9700\u8981\u7ED3\u6784\u5316\u56DE\u7B54');\n const questions = context.request.params.questions;\n const ids = new Set(questions.map((question) => question.id));\n if (Object.keys(resolution.answers).some((id) => !ids.has(id)))\n throw new AppError('VALIDATION_ERROR', '\u56DE\u7B54\u5305\u542B\u672A\u77E5\u9898\u76EE');\n const answers: ToolRequestUserInputResponse['answers'] = {};\n for (const question of questions) {\n const values = resolution.answers[question.id];\n if (\n !Array.isArray(values) ||\n !values.length ||\n values.some((value) => typeof value !== 'string' || !value.trim())\n )\n throw new AppError('VALIDATION_ERROR', `\u8BF7\u56DE\u7B54 ${question.header}`);\n if (\n question.options?.length &&\n !question.isOther &&\n values.some((value) => !question.options!.some((option) => option.label === value))\n )\n throw new AppError('VALIDATION_ERROR', `\u9898\u76EE ${question.header} \u53EA\u63A5\u53D7\u6240\u5217\u9009\u9879`);\n answers[question.id] = { answers: values };\n }\n response = { answers };\n } else {\n if (\n !('decision' in resolution) ||\n 'content' in resolution ||\n 'persist' in resolution ||\n !context.decisions.has(resolution.decision)\n )\n throw new AppError('VALIDATION_ERROR', '\u6B64\u8BF7\u6C42\u4E0D\u652F\u6301\u6240\u63D0\u4EA4\u7684\u51B3\u5B9A');\n response = { decision: context.decisions.get(resolution.decision)! };\n }\n context.responding = true;\n try {\n await this.rpc!.respond(context.action.rpcId, response);\n } catch (error) {\n if (error instanceof CodexError && !error.uncertain) context.responding = false;\n throw error;\n }\n }\n private expireActions(threadId?: string, turnId?: string): void {\n for (const [id, context] of this.actions) {\n if (threadId && context.action.threadId !== threadId) continue;\n if (turnId && context.action.turnId !== turnId) continue;\n this.emit({ type: 'action', action: { ...context.action, status: 'expired' } });\n this.actions.delete(id);\n this.actionIds.delete(context.action.rpcId);\n }\n }\n}\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": ["CodexError"]
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/codex/mapping.ts"],
|
|
4
|
-
"sourcesContent": ["import type {\n ItemView,\n RunStatus,\n RuntimeSettings,\n Settings,\n ThreadView,\n TurnView,\n} from '../shared/types.js';\nimport { permissionModes } from '../shared/permissions.js';\nimport type { PermissionSelection } from './permissions.js';\nexport { permissionSettings } from './permissions.js';\nimport type { Thread } from './generated/v2/Thread.js';\nimport type { ThreadItem } from './generated/v2/ThreadItem.js';\nimport type { ThreadStatus } from './generated/v2/ThreadStatus.js';\nimport type { Turn } from './generated/v2/Turn.js';\nimport type { ThreadStartParams } from './generated/v2/ThreadStartParams.js';\nimport type { TurnStartParams } from './generated/v2/TurnStartParams.js';\nimport type { ReasoningEffort } from './generated/ReasoningEffort.js';\nimport type { UserInput } from './generated/v2/UserInput.js';\nimport { parseQuestionReplies } from '../shared/async-questions.js';\nimport { imageDataBytes, MAX_IMAGES, MAX_IMAGE_BYTES } from '../shared/images.js';\nimport { CodexError, isRecord } from './transport.js';\n\nexport function taskInput(text: string, images: string[] = []): UserInput[] {\n return [\n ...(text ? [{ type: 'text' as const, text, text_elements: [] }] : []),\n ...images.map((url) => ({ type: 'image' as const, url })),\n ];\n}\n\n/** Codex 0.163.0 reports Fast as priority and standard speed as default. */\nexport function serviceTierSettings(\n tier: string | null | undefined,\n): Pick<RuntimeSettings, 'serviceTier'> {\n if (tier === undefined) return {};\n return { serviceTier: tier === 'priority' ? 'fast' : tier === 'default' ? null : tier };\n}\n\nexport function threadStatus(status: ThreadStatus): RunStatus {\n if (!isRecord(status))\n throw new CodexError('PROTOCOL_INCOMPATIBLE', 'Codex thread status is malformed', true);\n if (status.type === 'notLoaded') return 'unknown';\n if (status.type === 'idle') return 'idle';\n if (status.type === 'systemError') return 'failed';\n if (status.type !== 'active' || !Array.isArray(status.activeFlags))\n throw new CodexError('PROTOCOL_INCOMPATIBLE', 'Codex thread status is not supported', true);\n if (status.activeFlags.includes('waitingOnApproval')) return 'waitingApproval';\n if (status.activeFlags.includes('waitingOnUserInput')) return 'waitingInput';\n return 'running';\n}\nexport function mapThread(thread: Thread): ThreadView {\n assertObjectId(thread, 'thread');\n if (typeof thread.cwd !== 'string' || !Array.isArray(thread.turns) || !isRecord(thread.status))\n throw new CodexError(\n 'PROTOCOL_INCOMPATIBLE',\n 'Codex thread response is missing required fields',\n true,\n );\n const turns = thread.turns.map((turn) => mapTurn(thread.id, turn));\n let status = threadStatus(thread.status);\n // Persisted history is normally notLoaded after a restart, even when every turn\n // finished. Keep unfinished history uncertain; the gateway separately overlays\n // durable execution markers, including dispatches without a known turn ID.\n if (thread.status.type === 'notLoaded' && !turns.some((turn) => turn.status === 'running'))\n status = turns.at(-1)?.status ?? 'idle';\n return {\n id: thread.id,\n ...(typeof thread.forkedFromId === 'string' ? { forkedFromId: thread.forkedFromId } : {}),\n projectId: '',\n cwd: thread.cwd,\n source: typeof thread.source === 'string' ? thread.source : JSON.stringify(thread.source),\n originator: typeof thread.originator === 'string' ? thread.originator : null,\n title: thread.name || thread.preview || '\u65B0\u4F1A\u8BDD',\n // List/metadata responses omit turns. The native preview is history evidence.\n hasMessages: Boolean(thread.preview) || thread.turns.length > 0,\n status,\n turns,\n managed: false,\n runtimeSettings: {\n model: thread.model ?? null,\n reasoningEffort: thread.reasoningEffort ?? null,\n },\n updatedAt: thread.updatedAt * 1000,\n actions: [],\n };\n}\nexport function mapTurn(threadId: string, turn: Turn): TurnView {\n assertObjectId(turn, 'turn');\n if (!['inProgress', 'completed', 'failed', 'interrupted'].includes(turn.status))\n throw new CodexError('PROTOCOL_INCOMPATIBLE', 'Codex turn status is not supported', true);\n if (!Array.isArray(turn.items))\n throw new CodexError('PROTOCOL_INCOMPATIBLE', 'Codex turn response is missing items', true);\n return {\n id: turn.id,\n threadId,\n status: turn.status === 'inProgress' ? 'running' : turn.status,\n ...(validTiming(turn.startedAt) ? { startedAt: turn.startedAt * 1000 } : {}),\n ...(validTiming(turn.completedAt) ? { completedAt: turn.completedAt * 1000 } : {}),\n ...(validTiming(turn.durationMs) ? { durationMs: turn.durationMs } : {}),\n items: turn.items.map(mapItem),\n ...(turn.error ? { error: turn.error.message } : {}),\n };\n}\nfunction validTiming(value: unknown): value is number {\n return typeof value === 'number' && Number.isFinite(value) && value >= 0;\n}\nexport function mapItem(item: ThreadItem): ItemView {\n assertObjectId(item, 'item');\n if (typeof item.type !== 'string')\n throw new CodexError('PROTOCOL_INCOMPATIBLE', 'Codex item has no type', true);\n switch (item.type) {\n case 'userMessage': {\n const content = item.content.filter((input) => !['skill', 'mention'].includes(input.type));\n const replies =\n content.length === 1 && content[0]?.type === 'text'\n ? parseQuestionReplies(content[0].text)\n : undefined;\n const imageInputs = item.content.filter(\n (input) => input.type === 'image' || input.type === 'localImage',\n );\n let bytes = 0;\n const images = imageInputs.slice(0, MAX_IMAGES).flatMap((input) => {\n if (input.type !== 'image' || !('url' in input)) return [];\n const size = imageDataBytes(input.url);\n if (size === undefined || bytes + size > MAX_IMAGE_BYTES) return [];\n bytes += size;\n return [input.url];\n });\n return {\n id: item.id,\n type: item.type,\n text: replies\n ? replies.map((reply) => `${reply.question}\\n${reply.answer}`).join('\\n\\n')\n : item.content\n .filter((input) => input.type !== 'image' && input.type !== 'localImage')\n .map((input) => (input.type === 'text' ? input.text : `[${input.type}]`))\n .join('\\n'),\n ...(replies ? { questionReplies: replies } : {}),\n ...(imageInputs.length ? { images, imageCount: imageInputs.length } : {}),\n };\n }\n case 'agentMessage':\n return {\n id: item.id,\n type: item.type,\n text: item.text,\n ...(item.delivery ? { delivery: item.delivery } : {}),\n ...(item.questions?.length ? { questions: structuredClone(item.questions) } : {}),\n };\n case 'reasoning':\n return { id: item.id, type: item.type, text: [...item.summary, ...item.content].join('\\n') };\n case 'plan':\n return { id: item.id, type: item.type, text: item.text };\n case 'contextCompaction':\n // Lifecycle is carried by notifications, not the persisted item body.\n return { id: item.id, type: item.type };\n case 'enteredReviewMode':\n case 'exitedReviewMode':\n return { id: item.id, type: item.type, text: item.review };\n case 'commandExecution':\n return {\n id: item.id,\n type: item.type,\n status: item.status,\n command: item.command,\n cwd: item.cwd,\n output: item.aggregatedOutput ?? '',\n ...(item.exitCode !== null && item.exitCode !== 0\n ? { error: `\u9000\u51FA\u4EE3\u7801 ${item.exitCode}` }\n : {}),\n };\n case 'fileChange':\n return {\n id: item.id,\n type: item.type,\n status: item.status,\n changes: item.changes.map((change) => ({\n path: change.path,\n kind: change.kind.type,\n diff: change.diff,\n })),\n };\n default:\n return {\n id: item.id,\n type: item.type,\n ...('status' in item ? { status: String(item.status) } : {}),\n details: item,\n };\n }\n}\nexport function threadSettings(\n settings: Settings = {},\n): Pick<\n ThreadStartParams,\n 'model' | 'serviceTier' | 'approvalPolicy' | 'approvalsReviewer' | 'sandbox' | 'config'\n> &\n PermissionSelection {\n const preset = settings.permissionMode && permissionModes[settings.permissionMode];\n return {\n ...(settings.model === undefined ? {} : { model: settings.model }),\n ...(settings.serviceTier === undefined ? {} : { serviceTier: settings.serviceTier }),\n ...(settings.approvalPolicy === undefined ? {} : { approvalPolicy: settings.approvalPolicy }),\n ...(settings.approvalReviewer === undefined\n ? {}\n : { approvalsReviewer: settings.approvalReviewer }),\n ...(settings.sandbox === undefined ? {} : { sandbox: settings.sandbox }),\n ...(preset\n ? {\n permissions: preset.profile,\n approvalPolicy: preset.approvalPolicy,\n approvalsReviewer: preset.approvalReviewer,\n }\n : {}),\n ...(settings.reasoningEffort === undefined\n ? {}\n : { config: { model_reasoning_effort: settings.reasoningEffort } }),\n };\n}\nexport function turnSettings(\n cwd: string,\n settings: Settings = {},\n): Pick<\n TurnStartParams,\n 'model' | 'serviceTier' | 'approvalPolicy' | 'approvalsReviewer' | 'sandboxPolicy' | 'effort'\n> &\n PermissionSelection {\n const preset = settings.permissionMode && permissionModes[settings.permissionMode];\n const sandboxPolicy: TurnStartParams['sandboxPolicy'] =\n settings.sandbox === 'read-only'\n ? { type: 'readOnly', networkAccess: false }\n : settings.sandbox === 'workspace-write'\n ? {\n type: 'workspaceWrite',\n writableRoots: [cwd],\n networkAccess: false,\n excludeTmpdirEnvVar: false,\n excludeSlashTmp: false,\n }\n : settings.sandbox === 'danger-full-access'\n ? { type: 'dangerFullAccess' }\n : undefined;\n return {\n ...(settings.model === undefined ? {} : { model: settings.model }),\n ...(settings.serviceTier === undefined ? {} : { serviceTier: settings.serviceTier }),\n ...(settings.approvalPolicy === undefined ? {} : { approvalPolicy: settings.approvalPolicy }),\n ...(settings.approvalReviewer === undefined\n ? {}\n : { approvalsReviewer: settings.approvalReviewer }),\n ...(sandboxPolicy === undefined ? {} : { sandboxPolicy }),\n ...(preset\n ? {\n permissions: preset.profile,\n approvalPolicy: preset.approvalPolicy,\n approvalsReviewer: preset.approvalReviewer,\n }\n : {}),\n ...(settings.reasoningEffort === undefined\n ? {}\n : { effort: settings.reasoningEffort as ReasoningEffort }),\n };\n}\nfunction assertObjectId(value: unknown, kind: string): void {\n if (!isRecord(value) || typeof value.id !== 'string')\n throw new CodexError('PROTOCOL_INCOMPATIBLE', `Codex ${kind} has no stable id`, true);\n}\n"],
|
|
4
|
+
"sourcesContent": ["import type {\n ItemView,\n RunStatus,\n RuntimeSettings,\n Settings,\n ThreadView,\n TurnView,\n} from '../shared/types.js';\nimport { permissionModes } from '../shared/permissions.js';\nimport type { PermissionSelection } from './permissions.js';\nexport { permissionSettings } from './permissions.js';\nimport type { Thread } from './generated/v2/Thread.js';\nimport type { ThreadItem } from './generated/v2/ThreadItem.js';\nimport type { ThreadStatus } from './generated/v2/ThreadStatus.js';\nimport type { Turn } from './generated/v2/Turn.js';\nimport type { ThreadStartParams } from './generated/v2/ThreadStartParams.js';\nimport type { TurnStartParams } from './generated/v2/TurnStartParams.js';\nimport type { ReasoningEffort } from './generated/ReasoningEffort.js';\nimport type { UserInput } from './generated/v2/UserInput.js';\nimport { parseQuestionReplies } from '../shared/async-questions.js';\nimport { imageDataBytes, MAX_IMAGES, MAX_IMAGE_BYTES } from '../shared/images.js';\nimport { CodexError, isRecord } from './transport.js';\n\nexport function taskInput(text: string, images: string[] = []): UserInput[] {\n return [\n ...(text ? [{ type: 'text' as const, text, text_elements: [] }] : []),\n ...images.map((url) => ({ type: 'image' as const, url })),\n ];\n}\n\n/** Codex 0.164.0 reports Fast as priority and standard speed as default. */\nexport function serviceTierSettings(\n tier: string | null | undefined,\n): Pick<RuntimeSettings, 'serviceTier'> {\n if (tier === undefined) return {};\n return { serviceTier: tier === 'priority' ? 'fast' : tier === 'default' ? null : tier };\n}\n\nexport function threadStatus(status: ThreadStatus): RunStatus {\n if (!isRecord(status))\n throw new CodexError('PROTOCOL_INCOMPATIBLE', 'Codex thread status is malformed', true);\n if (status.type === 'notLoaded') return 'unknown';\n if (status.type === 'idle') return 'idle';\n if (status.type === 'systemError') return 'failed';\n if (status.type !== 'active' || !Array.isArray(status.activeFlags))\n throw new CodexError('PROTOCOL_INCOMPATIBLE', 'Codex thread status is not supported', true);\n if (status.activeFlags.includes('waitingOnApproval')) return 'waitingApproval';\n if (status.activeFlags.includes('waitingOnUserInput')) return 'waitingInput';\n return 'running';\n}\nexport function mapThread(thread: Thread): ThreadView {\n assertObjectId(thread, 'thread');\n if (typeof thread.cwd !== 'string' || !Array.isArray(thread.turns) || !isRecord(thread.status))\n throw new CodexError(\n 'PROTOCOL_INCOMPATIBLE',\n 'Codex thread response is missing required fields',\n true,\n );\n const turns = thread.turns.map((turn) => mapTurn(thread.id, turn));\n let status = threadStatus(thread.status);\n // Persisted history is normally notLoaded after a restart, even when every turn\n // finished. Keep unfinished history uncertain; the gateway separately overlays\n // durable execution markers, including dispatches without a known turn ID.\n if (thread.status.type === 'notLoaded' && !turns.some((turn) => turn.status === 'running'))\n status = turns.at(-1)?.status ?? 'idle';\n return {\n id: thread.id,\n ...(typeof thread.forkedFromId === 'string' ? { forkedFromId: thread.forkedFromId } : {}),\n projectId: '',\n cwd: thread.cwd,\n source: typeof thread.source === 'string' ? thread.source : JSON.stringify(thread.source),\n originator: typeof thread.originator === 'string' ? thread.originator : null,\n title: thread.name || thread.preview || '\u65B0\u4F1A\u8BDD',\n // List/metadata responses omit turns. The native preview is history evidence.\n hasMessages: Boolean(thread.preview) || thread.turns.length > 0,\n status,\n turns,\n managed: false,\n runtimeSettings: {\n model: thread.model ?? null,\n reasoningEffort: thread.reasoningEffort ?? null,\n },\n updatedAt: thread.updatedAt * 1000,\n actions: [],\n };\n}\nexport function mapTurn(threadId: string, turn: Turn): TurnView {\n assertObjectId(turn, 'turn');\n if (!['inProgress', 'completed', 'failed', 'interrupted'].includes(turn.status))\n throw new CodexError('PROTOCOL_INCOMPATIBLE', 'Codex turn status is not supported', true);\n if (!Array.isArray(turn.items))\n throw new CodexError('PROTOCOL_INCOMPATIBLE', 'Codex turn response is missing items', true);\n return {\n id: turn.id,\n threadId,\n status: turn.status === 'inProgress' ? 'running' : turn.status,\n ...(validTiming(turn.startedAt) ? { startedAt: turn.startedAt * 1000 } : {}),\n ...(validTiming(turn.completedAt) ? { completedAt: turn.completedAt * 1000 } : {}),\n ...(validTiming(turn.durationMs) ? { durationMs: turn.durationMs } : {}),\n items: turn.items.map(mapItem),\n ...(turn.error ? { error: turn.error.message } : {}),\n };\n}\nfunction validTiming(value: unknown): value is number {\n return typeof value === 'number' && Number.isFinite(value) && value >= 0;\n}\nexport function mapItem(item: ThreadItem): ItemView {\n assertObjectId(item, 'item');\n if (typeof item.type !== 'string')\n throw new CodexError('PROTOCOL_INCOMPATIBLE', 'Codex item has no type', true);\n switch (item.type) {\n case 'userMessage': {\n const content = item.content.filter((input) => !['skill', 'mention'].includes(input.type));\n const replies =\n content.length === 1 && content[0]?.type === 'text'\n ? parseQuestionReplies(content[0].text)\n : undefined;\n const imageInputs = item.content.filter(\n (input) => input.type === 'image' || input.type === 'localImage',\n );\n let bytes = 0;\n const images = imageInputs.slice(0, MAX_IMAGES).flatMap((input) => {\n if (input.type !== 'image' || !('url' in input)) return [];\n const size = imageDataBytes(input.url);\n if (size === undefined || bytes + size > MAX_IMAGE_BYTES) return [];\n bytes += size;\n return [input.url];\n });\n return {\n id: item.id,\n type: item.type,\n text: replies\n ? replies.map((reply) => `${reply.question}\\n${reply.answer}`).join('\\n\\n')\n : item.content\n .filter((input) => input.type !== 'image' && input.type !== 'localImage')\n .map((input) => (input.type === 'text' ? input.text : `[${input.type}]`))\n .join('\\n'),\n ...(replies ? { questionReplies: replies } : {}),\n ...(imageInputs.length ? { images, imageCount: imageInputs.length } : {}),\n };\n }\n case 'agentMessage':\n return {\n id: item.id,\n type: item.type,\n text: item.text,\n ...(item.delivery ? { delivery: item.delivery } : {}),\n ...(item.questions?.length ? { questions: structuredClone(item.questions) } : {}),\n };\n case 'reasoning':\n return { id: item.id, type: item.type, text: [...item.summary, ...item.content].join('\\n') };\n case 'plan':\n return { id: item.id, type: item.type, text: item.text };\n case 'contextCompaction':\n // Lifecycle is carried by notifications, not the persisted item body.\n return { id: item.id, type: item.type };\n case 'enteredReviewMode':\n case 'exitedReviewMode':\n return { id: item.id, type: item.type, text: item.review };\n case 'commandExecution':\n return {\n id: item.id,\n type: item.type,\n status: item.status,\n command: item.command,\n cwd: item.cwd,\n output: item.aggregatedOutput ?? '',\n ...(item.exitCode !== null && item.exitCode !== 0\n ? { error: `\u9000\u51FA\u4EE3\u7801 ${item.exitCode}` }\n : {}),\n };\n case 'fileChange':\n return {\n id: item.id,\n type: item.type,\n status: item.status,\n changes: item.changes.map((change) => ({\n path: change.path,\n kind: change.kind.type,\n diff: change.diff,\n })),\n };\n default:\n return {\n id: item.id,\n type: item.type,\n ...('status' in item ? { status: String(item.status) } : {}),\n details: item,\n };\n }\n}\nexport function threadSettings(\n settings: Settings = {},\n): Pick<\n ThreadStartParams,\n 'model' | 'serviceTier' | 'approvalPolicy' | 'approvalsReviewer' | 'sandbox' | 'config'\n> &\n PermissionSelection {\n const preset = settings.permissionMode && permissionModes[settings.permissionMode];\n return {\n ...(settings.model === undefined ? {} : { model: settings.model }),\n ...(settings.serviceTier === undefined ? {} : { serviceTier: settings.serviceTier }),\n ...(settings.approvalPolicy === undefined ? {} : { approvalPolicy: settings.approvalPolicy }),\n ...(settings.approvalReviewer === undefined\n ? {}\n : { approvalsReviewer: settings.approvalReviewer }),\n ...(settings.sandbox === undefined ? {} : { sandbox: settings.sandbox }),\n ...(preset\n ? {\n permissions: preset.profile,\n approvalPolicy: preset.approvalPolicy,\n approvalsReviewer: preset.approvalReviewer,\n }\n : {}),\n ...(settings.reasoningEffort === undefined\n ? {}\n : { config: { model_reasoning_effort: settings.reasoningEffort } }),\n };\n}\nexport function turnSettings(\n cwd: string,\n settings: Settings = {},\n): Pick<\n TurnStartParams,\n 'model' | 'serviceTier' | 'approvalPolicy' | 'approvalsReviewer' | 'sandboxPolicy' | 'effort'\n> &\n PermissionSelection {\n const preset = settings.permissionMode && permissionModes[settings.permissionMode];\n const sandboxPolicy: TurnStartParams['sandboxPolicy'] =\n settings.sandbox === 'read-only'\n ? { type: 'readOnly', networkAccess: false }\n : settings.sandbox === 'workspace-write'\n ? {\n type: 'workspaceWrite',\n writableRoots: [cwd],\n networkAccess: false,\n excludeTmpdirEnvVar: false,\n excludeSlashTmp: false,\n }\n : settings.sandbox === 'danger-full-access'\n ? { type: 'dangerFullAccess' }\n : undefined;\n return {\n ...(settings.model === undefined ? {} : { model: settings.model }),\n ...(settings.serviceTier === undefined ? {} : { serviceTier: settings.serviceTier }),\n ...(settings.approvalPolicy === undefined ? {} : { approvalPolicy: settings.approvalPolicy }),\n ...(settings.approvalReviewer === undefined\n ? {}\n : { approvalsReviewer: settings.approvalReviewer }),\n ...(sandboxPolicy === undefined ? {} : { sandboxPolicy }),\n ...(preset\n ? {\n permissions: preset.profile,\n approvalPolicy: preset.approvalPolicy,\n approvalsReviewer: preset.approvalReviewer,\n }\n : {}),\n ...(settings.reasoningEffort === undefined\n ? {}\n : { effort: settings.reasoningEffort as ReasoningEffort }),\n };\n}\nfunction assertObjectId(value: unknown, kind: string): void {\n if (!isRecord(value) || typeof value.id !== 'string')\n throw new CodexError('PROTOCOL_INCOMPATIBLE', `Codex ${kind} has no stable id`, true);\n}\n"],
|
|
5
5
|
"mappings": "AAQA,SAAS,uBAAuB;AAEhC,SAAS,0BAA0B;AASnC,SAAS,4BAA4B;AACrC,SAAS,gBAAgB,YAAY,uBAAuB;AAC5D,SAAS,YAAY,gBAAgB;AAE9B,SAAS,UAAU,MAAc,SAAmB,CAAC,GAAgB;AAC1E,SAAO;AAAA,IACL,GAAI,OAAO,CAAC,EAAE,MAAM,QAAiB,MAAM,eAAe,CAAC,EAAE,CAAC,IAAI,CAAC;AAAA,IACnE,GAAG,OAAO,IAAI,CAAC,SAAS,EAAE,MAAM,SAAkB,IAAI,EAAE;AAAA,EAC1D;AACF;AAGO,SAAS,oBACd,MACsC;AACtC,MAAI,SAAS,OAAW,QAAO,CAAC;AAChC,SAAO,EAAE,aAAa,SAAS,aAAa,SAAS,SAAS,YAAY,OAAO,KAAK;AACxF;AAEO,SAAS,aAAa,QAAiC;AAC5D,MAAI,CAAC,SAAS,MAAM;AAClB,UAAM,IAAI,WAAW,yBAAyB,oCAAoC,IAAI;AACxF,MAAI,OAAO,SAAS,YAAa,QAAO;AACxC,MAAI,OAAO,SAAS,OAAQ,QAAO;AACnC,MAAI,OAAO,SAAS,cAAe,QAAO;AAC1C,MAAI,OAAO,SAAS,YAAY,CAAC,MAAM,QAAQ,OAAO,WAAW;AAC/D,UAAM,IAAI,WAAW,yBAAyB,wCAAwC,IAAI;AAC5F,MAAI,OAAO,YAAY,SAAS,mBAAmB,EAAG,QAAO;AAC7D,MAAI,OAAO,YAAY,SAAS,oBAAoB,EAAG,QAAO;AAC9D,SAAO;AACT;AACO,SAAS,UAAU,QAA4B;AACpD,iBAAe,QAAQ,QAAQ;AAC/B,MAAI,OAAO,OAAO,QAAQ,YAAY,CAAC,MAAM,QAAQ,OAAO,KAAK,KAAK,CAAC,SAAS,OAAO,MAAM;AAC3F,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACF,QAAM,QAAQ,OAAO,MAAM,IAAI,CAAC,SAAS,QAAQ,OAAO,IAAI,IAAI,CAAC;AACjE,MAAI,SAAS,aAAa,OAAO,MAAM;AAIvC,MAAI,OAAO,OAAO,SAAS,eAAe,CAAC,MAAM,KAAK,CAAC,SAAS,KAAK,WAAW,SAAS;AACvF,aAAS,MAAM,GAAG,EAAE,GAAG,UAAU;AACnC,SAAO;AAAA,IACL,IAAI,OAAO;AAAA,IACX,GAAI,OAAO,OAAO,iBAAiB,WAAW,EAAE,cAAc,OAAO,aAAa,IAAI,CAAC;AAAA,IACvF,WAAW;AAAA,IACX,KAAK,OAAO;AAAA,IACZ,QAAQ,OAAO,OAAO,WAAW,WAAW,OAAO,SAAS,KAAK,UAAU,OAAO,MAAM;AAAA,IACxF,YAAY,OAAO,OAAO,eAAe,WAAW,OAAO,aAAa;AAAA,IACxE,OAAO,OAAO,QAAQ,OAAO,WAAW;AAAA;AAAA,IAExC,aAAa,QAAQ,OAAO,OAAO,KAAK,OAAO,MAAM,SAAS;AAAA,IAC9D;AAAA,IACA;AAAA,IACA,SAAS;AAAA,IACT,iBAAiB;AAAA,MACf,OAAO,OAAO,SAAS;AAAA,MACvB,iBAAiB,OAAO,mBAAmB;AAAA,IAC7C;AAAA,IACA,WAAW,OAAO,YAAY;AAAA,IAC9B,SAAS,CAAC;AAAA,EACZ;AACF;AACO,SAAS,QAAQ,UAAkB,MAAsB;AAC9D,iBAAe,MAAM,MAAM;AAC3B,MAAI,CAAC,CAAC,cAAc,aAAa,UAAU,aAAa,EAAE,SAAS,KAAK,MAAM;AAC5E,UAAM,IAAI,WAAW,yBAAyB,sCAAsC,IAAI;AAC1F,MAAI,CAAC,MAAM,QAAQ,KAAK,KAAK;AAC3B,UAAM,IAAI,WAAW,yBAAyB,wCAAwC,IAAI;AAC5F,SAAO;AAAA,IACL,IAAI,KAAK;AAAA,IACT;AAAA,IACA,QAAQ,KAAK,WAAW,eAAe,YAAY,KAAK;AAAA,IACxD,GAAI,YAAY,KAAK,SAAS,IAAI,EAAE,WAAW,KAAK,YAAY,IAAK,IAAI,CAAC;AAAA,IAC1E,GAAI,YAAY,KAAK,WAAW,IAAI,EAAE,aAAa,KAAK,cAAc,IAAK,IAAI,CAAC;AAAA,IAChF,GAAI,YAAY,KAAK,UAAU,IAAI,EAAE,YAAY,KAAK,WAAW,IAAI,CAAC;AAAA,IACtE,OAAO,KAAK,MAAM,IAAI,OAAO;AAAA,IAC7B,GAAI,KAAK,QAAQ,EAAE,OAAO,KAAK,MAAM,QAAQ,IAAI,CAAC;AAAA,EACpD;AACF;AACA,SAAS,YAAY,OAAiC;AACpD,SAAO,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,KAAK,SAAS;AACzE;AACO,SAAS,QAAQ,MAA4B;AAClD,iBAAe,MAAM,MAAM;AAC3B,MAAI,OAAO,KAAK,SAAS;AACvB,UAAM,IAAI,WAAW,yBAAyB,0BAA0B,IAAI;AAC9E,UAAQ,KAAK,MAAM;AAAA,IACjB,KAAK,eAAe;AAClB,YAAM,UAAU,KAAK,QAAQ,OAAO,CAAC,UAAU,CAAC,CAAC,SAAS,SAAS,EAAE,SAAS,MAAM,IAAI,CAAC;AACzF,YAAM,UACJ,QAAQ,WAAW,KAAK,QAAQ,CAAC,GAAG,SAAS,SACzC,qBAAqB,QAAQ,CAAC,EAAE,IAAI,IACpC;AACN,YAAM,cAAc,KAAK,QAAQ;AAAA,QAC/B,CAAC,UAAU,MAAM,SAAS,WAAW,MAAM,SAAS;AAAA,MACtD;AACA,UAAI,QAAQ;AACZ,YAAM,SAAS,YAAY,MAAM,GAAG,UAAU,EAAE,QAAQ,CAAC,UAAU;AACjE,YAAI,MAAM,SAAS,WAAW,EAAE,SAAS,OAAQ,QAAO,CAAC;AACzD,cAAM,OAAO,eAAe,MAAM,GAAG;AACrC,YAAI,SAAS,UAAa,QAAQ,OAAO,gBAAiB,QAAO,CAAC;AAClE,iBAAS;AACT,eAAO,CAAC,MAAM,GAAG;AAAA,MACnB,CAAC;AACD,aAAO;AAAA,QACL,IAAI,KAAK;AAAA,QACT,MAAM,KAAK;AAAA,QACX,MAAM,UACF,QAAQ,IAAI,CAAC,UAAU,GAAG,MAAM,QAAQ;AAAA,EAAK,MAAM,MAAM,EAAE,EAAE,KAAK,MAAM,IACxE,KAAK,QACF,OAAO,CAAC,UAAU,MAAM,SAAS,WAAW,MAAM,SAAS,YAAY,EACvE,IAAI,CAAC,UAAW,MAAM,SAAS,SAAS,MAAM,OAAO,IAAI,MAAM,IAAI,GAAI,EACvE,KAAK,IAAI;AAAA,QAChB,GAAI,UAAU,EAAE,iBAAiB,QAAQ,IAAI,CAAC;AAAA,QAC9C,GAAI,YAAY,SAAS,EAAE,QAAQ,YAAY,YAAY,OAAO,IAAI,CAAC;AAAA,MACzE;AAAA,IACF;AAAA,IACA,KAAK;AACH,aAAO;AAAA,QACL,IAAI,KAAK;AAAA,QACT,MAAM,KAAK;AAAA,QACX,MAAM,KAAK;AAAA,QACX,GAAI,KAAK,WAAW,EAAE,UAAU,KAAK,SAAS,IAAI,CAAC;AAAA,QACnD,GAAI,KAAK,WAAW,SAAS,EAAE,WAAW,gBAAgB,KAAK,SAAS,EAAE,IAAI,CAAC;AAAA,MACjF;AAAA,IACF,KAAK;AACH,aAAO,EAAE,IAAI,KAAK,IAAI,MAAM,KAAK,MAAM,MAAM,CAAC,GAAG,KAAK,SAAS,GAAG,KAAK,OAAO,EAAE,KAAK,IAAI,EAAE;AAAA,IAC7F,KAAK;AACH,aAAO,EAAE,IAAI,KAAK,IAAI,MAAM,KAAK,MAAM,MAAM,KAAK,KAAK;AAAA,IACzD,KAAK;AAEH,aAAO,EAAE,IAAI,KAAK,IAAI,MAAM,KAAK,KAAK;AAAA,IACxC,KAAK;AAAA,IACL,KAAK;AACH,aAAO,EAAE,IAAI,KAAK,IAAI,MAAM,KAAK,MAAM,MAAM,KAAK,OAAO;AAAA,IAC3D,KAAK;AACH,aAAO;AAAA,QACL,IAAI,KAAK;AAAA,QACT,MAAM,KAAK;AAAA,QACX,QAAQ,KAAK;AAAA,QACb,SAAS,KAAK;AAAA,QACd,KAAK,KAAK;AAAA,QACV,QAAQ,KAAK,oBAAoB;AAAA,QACjC,GAAI,KAAK,aAAa,QAAQ,KAAK,aAAa,IAC5C,EAAE,OAAO,4BAAQ,KAAK,QAAQ,GAAG,IACjC,CAAC;AAAA,MACP;AAAA,IACF,KAAK;AACH,aAAO;AAAA,QACL,IAAI,KAAK;AAAA,QACT,MAAM,KAAK;AAAA,QACX,QAAQ,KAAK;AAAA,QACb,SAAS,KAAK,QAAQ,IAAI,CAAC,YAAY;AAAA,UACrC,MAAM,OAAO;AAAA,UACb,MAAM,OAAO,KAAK;AAAA,UAClB,MAAM,OAAO;AAAA,QACf,EAAE;AAAA,MACJ;AAAA,IACF;AACE,aAAO;AAAA,QACL,IAAI,KAAK;AAAA,QACT,MAAM,KAAK;AAAA,QACX,GAAI,YAAY,OAAO,EAAE,QAAQ,OAAO,KAAK,MAAM,EAAE,IAAI,CAAC;AAAA,QAC1D,SAAS;AAAA,MACX;AAAA,EACJ;AACF;AACO,SAAS,eACd,WAAqB,CAAC,GAKF;AACpB,QAAM,SAAS,SAAS,kBAAkB,gBAAgB,SAAS,cAAc;AACjF,SAAO;AAAA,IACL,GAAI,SAAS,UAAU,SAAY,CAAC,IAAI,EAAE,OAAO,SAAS,MAAM;AAAA,IAChE,GAAI,SAAS,gBAAgB,SAAY,CAAC,IAAI,EAAE,aAAa,SAAS,YAAY;AAAA,IAClF,GAAI,SAAS,mBAAmB,SAAY,CAAC,IAAI,EAAE,gBAAgB,SAAS,eAAe;AAAA,IAC3F,GAAI,SAAS,qBAAqB,SAC9B,CAAC,IACD,EAAE,mBAAmB,SAAS,iBAAiB;AAAA,IACnD,GAAI,SAAS,YAAY,SAAY,CAAC,IAAI,EAAE,SAAS,SAAS,QAAQ;AAAA,IACtE,GAAI,SACA;AAAA,MACE,aAAa,OAAO;AAAA,MACpB,gBAAgB,OAAO;AAAA,MACvB,mBAAmB,OAAO;AAAA,IAC5B,IACA,CAAC;AAAA,IACL,GAAI,SAAS,oBAAoB,SAC7B,CAAC,IACD,EAAE,QAAQ,EAAE,wBAAwB,SAAS,gBAAgB,EAAE;AAAA,EACrE;AACF;AACO,SAAS,aACd,KACA,WAAqB,CAAC,GAKF;AACpB,QAAM,SAAS,SAAS,kBAAkB,gBAAgB,SAAS,cAAc;AACjF,QAAM,gBACJ,SAAS,YAAY,cACjB,EAAE,MAAM,YAAY,eAAe,MAAM,IACzC,SAAS,YAAY,oBACnB;AAAA,IACE,MAAM;AAAA,IACN,eAAe,CAAC,GAAG;AAAA,IACnB,eAAe;AAAA,IACf,qBAAqB;AAAA,IACrB,iBAAiB;AAAA,EACnB,IACA,SAAS,YAAY,uBACnB,EAAE,MAAM,mBAAmB,IAC3B;AACV,SAAO;AAAA,IACL,GAAI,SAAS,UAAU,SAAY,CAAC,IAAI,EAAE,OAAO,SAAS,MAAM;AAAA,IAChE,GAAI,SAAS,gBAAgB,SAAY,CAAC,IAAI,EAAE,aAAa,SAAS,YAAY;AAAA,IAClF,GAAI,SAAS,mBAAmB,SAAY,CAAC,IAAI,EAAE,gBAAgB,SAAS,eAAe;AAAA,IAC3F,GAAI,SAAS,qBAAqB,SAC9B,CAAC,IACD,EAAE,mBAAmB,SAAS,iBAAiB;AAAA,IACnD,GAAI,kBAAkB,SAAY,CAAC,IAAI,EAAE,cAAc;AAAA,IACvD,GAAI,SACA;AAAA,MACE,aAAa,OAAO;AAAA,MACpB,gBAAgB,OAAO;AAAA,MACvB,mBAAmB,OAAO;AAAA,IAC5B,IACA,CAAC;AAAA,IACL,GAAI,SAAS,oBAAoB,SAC7B,CAAC,IACD,EAAE,QAAQ,SAAS,gBAAmC;AAAA,EAC5D;AACF;AACA,SAAS,eAAe,OAAgB,MAAoB;AAC1D,MAAI,CAAC,SAAS,KAAK,KAAK,OAAO,MAAM,OAAO;AAC1C,UAAM,IAAI,WAAW,yBAAyB,SAAS,IAAI,qBAAqB,IAAI;AACxF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/codex/permissions.ts"],
|
|
4
|
-
"sourcesContent": ["import { permissionModes } from '../shared/permissions.js';\nimport type { PermissionCapabilities, PermissionMode, RuntimeSettings } from '../shared/types.js';\nimport type { ActivePermissionProfile } from './generated/v2/ActivePermissionProfile.js';\nimport type { AskForApproval } from './generated/v2/AskForApproval.js';\nimport type { ConfigRequirements } from './generated/v2/ConfigRequirements.js';\nimport type { SandboxPolicy } from './generated/v2/SandboxPolicy.js';\n\n/** 0.
|
|
4
|
+
"sourcesContent": ["import { permissionModes } from '../shared/permissions.js';\nimport type { PermissionCapabilities, PermissionMode, RuntimeSettings } from '../shared/types.js';\nimport type { ActivePermissionProfile } from './generated/v2/ActivePermissionProfile.js';\nimport type { AskForApproval } from './generated/v2/AskForApproval.js';\nimport type { ConfigRequirements } from './generated/v2/ConfigRequirements.js';\nimport type { SandboxPolicy } from './generated/v2/SandboxPolicy.js';\n\n/** 0.164.0 experimental wire fields omitted by generate-ts without --experimental.\n * initialize.experimentalApi is already enabled. Keep these extensions at the adapter boundary.\n */\nexport type PermissionSelection = { permissions?: string };\nexport type ProfileProvenance = { activePermissionProfile?: ActivePermissionProfile | null };\nexport type PermissionRequirements = ConfigRequirements & {\n allowedApprovalsReviewers?: string[] | null;\n};\n\n/** Only classify after seeing the actual boundary, reviewer and profile provenance. */\nexport function permissionSettings(\n sandbox?: SandboxPolicy,\n approvalPolicy?: AskForApproval | null,\n reviewer?: string | null,\n profile?: ActivePermissionProfile | null,\n cwd?: string,\n): Omit<RuntimeSettings, 'model' | 'reasoningEffort' | 'permissionCapabilities'> {\n const result: ReturnType<typeof permissionSettings> = {\n sandbox: sandbox\n ? (\n {\n dangerFullAccess: 'danger-full-access',\n readOnly: 'read-only',\n workspaceWrite: 'workspace-write',\n externalSandbox: 'external-sandbox',\n } as const\n )[sandbox.type]\n : null,\n approvalPolicy:\n typeof approvalPolicy === 'string' ? approvalPolicy : approvalPolicy ? 'granular' : null,\n approvalReviewer: reviewer ?? null,\n networkAccess: !sandbox\n ? null\n : sandbox.type === 'dangerFullAccess'\n ? true\n : sandbox.type === 'externalSandbox'\n ? sandbox.networkAccess === 'enabled'\n : sandbox.networkAccess,\n permissionProfile: profile ?? null,\n writableRoots: sandbox?.type === 'workspaceWrite' ? sandbox.writableRoots : null,\n excludeTmpdirEnvVar: sandbox?.type === 'workspaceWrite' ? sandbox.excludeTmpdirEnvVar : null,\n excludeSlashTmp: sandbox?.type === 'workspaceWrite' ? sandbox.excludeSlashTmp : null,\n permissionMode: null,\n };\n const builtins: string[] = [':workspace', ':read-only', ':danger-full-access'];\n if (\n (profile && (profile.extends !== null || !builtins.includes(profile.id))) ||\n sandbox?.type === 'externalSandbox' ||\n result.approvalPolicy === 'granular'\n ) {\n result.permissionMode = 'custom';\n return result;\n }\n if (!sandbox || !approvalPolicy || !reviewer || profile === undefined) return result;\n const standardBoundary =\n sandbox.type === 'workspaceWrite'\n ? !sandbox.networkAccess &&\n !sandbox.excludeTmpdirEnvVar &&\n !sandbox.excludeSlashTmp &&\n sandbox.writableRoots.every((root) => root === cwd)\n : sandbox.type === 'readOnly'\n ? !sandbox.networkAccess\n : sandbox.type === 'dangerFullAccess';\n result.permissionMode =\n (Object.keys(permissionModes) as PermissionMode[]).find((mode) => {\n const preset = permissionModes[mode];\n return (\n standardBoundary &&\n result.sandbox === preset.sandbox &&\n approvalPolicy === preset.approvalPolicy &&\n reviewer === preset.approvalReviewer &&\n (!profile || profile.id === preset.profile)\n );\n }) ?? 'custom';\n return result;\n}\n\nexport function permissionCapabilities(\n requirements: PermissionRequirements | null,\n autoReview: boolean,\n unavailableReason?: string,\n): PermissionCapabilities {\n return {\n ...(unavailableReason ? { unavailableReason } : {}),\n autoReview: autoReview && requirements?.featureRequirements?.guardian_approval !== false,\n allowedSandboxModes: requirements?.allowedSandboxModes ?? null,\n allowedApprovalPolicies:\n requirements?.allowedApprovalPolicies?.filter(\n (policy): policy is string & AskForApproval => typeof policy === 'string',\n ) ?? null,\n allowedReviewers: requirements?.allowedApprovalsReviewers ?? null,\n allowedProfiles: requirements?.allowedPermissionProfiles\n ? Object.keys(requirements.allowedPermissionProfiles).filter(\n (id) => requirements.allowedPermissionProfiles?.[id] === true,\n )\n : null,\n autoReviewRequiredModels: requirements?.autoReview?.requiredOnModels ?? [],\n };\n}\n"],
|
|
5
5
|
"mappings": "AAAA,SAAS,uBAAuB;AAiBzB,SAAS,mBACd,SACA,gBACA,UACA,SACA,KAC+E;AAC/E,QAAM,SAAgD;AAAA,IACpD,SAAS,UAEH;AAAA,MACE,kBAAkB;AAAA,MAClB,UAAU;AAAA,MACV,gBAAgB;AAAA,MAChB,iBAAiB;AAAA,IACnB,EACA,QAAQ,IAAI,IACd;AAAA,IACJ,gBACE,OAAO,mBAAmB,WAAW,iBAAiB,iBAAiB,aAAa;AAAA,IACtF,kBAAkB,YAAY;AAAA,IAC9B,eAAe,CAAC,UACZ,OACA,QAAQ,SAAS,qBACf,OACA,QAAQ,SAAS,oBACf,QAAQ,kBAAkB,YAC1B,QAAQ;AAAA,IAChB,mBAAmB,WAAW;AAAA,IAC9B,eAAe,SAAS,SAAS,mBAAmB,QAAQ,gBAAgB;AAAA,IAC5E,qBAAqB,SAAS,SAAS,mBAAmB,QAAQ,sBAAsB;AAAA,IACxF,iBAAiB,SAAS,SAAS,mBAAmB,QAAQ,kBAAkB;AAAA,IAChF,gBAAgB;AAAA,EAClB;AACA,QAAM,WAAqB,CAAC,cAAc,cAAc,qBAAqB;AAC7E,MACG,YAAY,QAAQ,YAAY,QAAQ,CAAC,SAAS,SAAS,QAAQ,EAAE,MACtE,SAAS,SAAS,qBAClB,OAAO,mBAAmB,YAC1B;AACA,WAAO,iBAAiB;AACxB,WAAO;AAAA,EACT;AACA,MAAI,CAAC,WAAW,CAAC,kBAAkB,CAAC,YAAY,YAAY,OAAW,QAAO;AAC9E,QAAM,mBACJ,QAAQ,SAAS,mBACb,CAAC,QAAQ,iBACT,CAAC,QAAQ,uBACT,CAAC,QAAQ,mBACT,QAAQ,cAAc,MAAM,CAAC,SAAS,SAAS,GAAG,IAClD,QAAQ,SAAS,aACf,CAAC,QAAQ,gBACT,QAAQ,SAAS;AACzB,SAAO,iBACJ,OAAO,KAAK,eAAe,EAAuB,KAAK,CAAC,SAAS;AAChE,UAAM,SAAS,gBAAgB,IAAI;AACnC,WACE,oBACA,OAAO,YAAY,OAAO,WAC1B,mBAAmB,OAAO,kBAC1B,aAAa,OAAO,qBACnB,CAAC,WAAW,QAAQ,OAAO,OAAO;AAAA,EAEvC,CAAC,KAAK;AACR,SAAO;AACT;AAEO,SAAS,uBACd,cACA,YACA,mBACwB;AACxB,SAAO;AAAA,IACL,GAAI,oBAAoB,EAAE,kBAAkB,IAAI,CAAC;AAAA,IACjD,YAAY,cAAc,cAAc,qBAAqB,sBAAsB;AAAA,IACnF,qBAAqB,cAAc,uBAAuB;AAAA,IAC1D,yBACE,cAAc,yBAAyB;AAAA,MACrC,CAAC,WAA8C,OAAO,WAAW;AAAA,IACnE,KAAK;AAAA,IACP,kBAAkB,cAAc,6BAA6B;AAAA,IAC7D,iBAAiB,cAAc,4BAC3B,OAAO,KAAK,aAAa,yBAAyB,EAAE;AAAA,MAClD,CAAC,OAAO,aAAa,4BAA4B,EAAE,MAAM;AAAA,IAC3D,IACA;AAAA,IACJ,0BAA0B,cAAc,YAAY,oBAAoB,CAAC;AAAA,EAC3E;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/codex/thread-title-policy.ts"],
|
|
4
|
-
"sourcesContent": ["import { isRecord } from './transport.js';\n\n// Keep in sync with codex-rs/tui/src/app/thread_title.rs (rust-v0.
|
|
4
|
+
"sourcesContent": ["import { isRecord } from './transport.js';\n\n// Keep in sync with codex-rs/tui/src/app/thread_title.rs (rust-v0.164.0).\nexport const TITLE_MODEL = 'gpt-5.6-luna';\nexport const TITLE_MAX_CHARS = 36;\nconst PROMPT_MAX_BYTES = 960;\nexport const TITLE_RESPONSE_MAX_BYTES = 8 * 1024;\nexport const titleOutputSchema = {\n type: 'object',\n properties: { title: { type: 'string', minLength: 1, maxLength: TITLE_MAX_CHARS } },\n required: ['title'],\n additionalProperties: false,\n};\nconst instructions =\n 'Generate a concise, single-line task title of at most 36 characters and under five words where possible. ' +\n 'Start with an imperative verb. Capitalize only the first word unless the ' +\n \"user's language, proper nouns, acronyms, or code terms require otherwise. \" +\n \"Preserve ticket references exactly. Write in the user's language. \" +\n 'Do not use quotes, markdown, or trailing punctuation. Do not answer the request.';\n\nexport function titlePrompt(message: string): string {\n const prefix = `${instructions}\\n\\nUser prompt:\\n`;\n let remaining = PROMPT_MAX_BYTES - Buffer.byteLength(prefix);\n let text = '';\n for (const character of message.trim()) {\n remaining -= Buffer.byteLength(character);\n if (remaining < 0) break;\n text += character;\n }\n return prefix + text;\n}\n\nexport function parseTitle(response: string): string | undefined {\n if (Buffer.byteLength(response) > TITLE_RESPONSE_MAX_BYTES) return;\n let value: unknown;\n try {\n value = JSON.parse(response);\n } catch {\n return;\n }\n if (!isRecord(value) || Object.keys(value).length !== 1 || typeof value.title !== 'string')\n return;\n const title = value.title\n .trim()\n .replace(/^[\"'`\u201C\u201D\u2018\u2019]+|[\"'`\u201C\u201D\u2018\u2019]+$/gu, '')\n .replace(/\\s+/gu, ' ')\n .trim()\n .replace(/[.?!]+$/u, '')\n .trimEnd();\n return title ? [...title].slice(0, TITLE_MAX_CHARS).join('') : undefined;\n}\n\nexport function selectTitleModel(\n currentModel: string,\n provider: string,\n hasChatgptAccount: boolean,\n models: readonly string[],\n): string {\n return provider === 'openai' && hasChatgptAccount && models.includes(TITLE_MODEL)\n ? TITLE_MODEL\n : currentModel;\n}\n"],
|
|
5
5
|
"mappings": "AAAA,SAAS,gBAAgB;AAGlB,MAAM,cAAc;AACpB,MAAM,kBAAkB;AAC/B,MAAM,mBAAmB;AAClB,MAAM,2BAA2B,IAAI;AACrC,MAAM,oBAAoB;AAAA,EAC/B,MAAM;AAAA,EACN,YAAY,EAAE,OAAO,EAAE,MAAM,UAAU,WAAW,GAAG,WAAW,gBAAgB,EAAE;AAAA,EAClF,UAAU,CAAC,OAAO;AAAA,EAClB,sBAAsB;AACxB;AACA,MAAM,eACJ;AAMK,SAAS,YAAY,SAAyB;AACnD,QAAM,SAAS,GAAG,YAAY;AAAA;AAAA;AAAA;AAC9B,MAAI,YAAY,mBAAmB,OAAO,WAAW,MAAM;AAC3D,MAAI,OAAO;AACX,aAAW,aAAa,QAAQ,KAAK,GAAG;AACtC,iBAAa,OAAO,WAAW,SAAS;AACxC,QAAI,YAAY,EAAG;AACnB,YAAQ;AAAA,EACV;AACA,SAAO,SAAS;AAClB;AAEO,SAAS,WAAW,UAAsC;AAC/D,MAAI,OAAO,WAAW,QAAQ,IAAI,yBAA0B;AAC5D,MAAI;AACJ,MAAI;AACF,YAAQ,KAAK,MAAM,QAAQ;AAAA,EAC7B,QAAQ;AACN;AAAA,EACF;AACA,MAAI,CAAC,SAAS,KAAK,KAAK,OAAO,KAAK,KAAK,EAAE,WAAW,KAAK,OAAO,MAAM,UAAU;AAChF;AACF,QAAM,QAAQ,MAAM,MACjB,KAAK,EACL,QAAQ,6BAA6B,EAAE,EACvC,QAAQ,SAAS,GAAG,EACpB,KAAK,EACL,QAAQ,YAAY,EAAE,EACtB,QAAQ;AACX,SAAO,QAAQ,CAAC,GAAG,KAAK,EAAE,MAAM,GAAG,eAAe,EAAE,KAAK,EAAE,IAAI;AACjE;AAEO,SAAS,iBACd,cACA,UACA,mBACA,QACQ;AACR,SAAO,aAAa,YAAY,qBAAqB,OAAO,SAAS,WAAW,IAC5E,cACA;AACN;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|