farming-code 2.2.14 → 2.2.17
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 -3
- package/README.zh_cn.md +3 -3
- package/THIRD_PARTY_NOTICES.md +17 -1
- package/backend/acp/packaged-codex-acp.js +13 -0
- package/backend/acp-runtime.js +413 -24
- package/backend/agent-manager.js +572 -557
- package/backend/agent-provider-session.js +15 -1
- package/backend/agent-runtime-binding.js +9 -55
- package/backend/chat-runtime.js +28 -0
- package/backend/codex-rollout-follower.js +83 -0
- package/backend/codex-session-archive.js +12 -1
- package/backend/codex-session-history.js +94 -0
- package/backend/codex-transcript.js +2 -1
- package/backend/config-manager.js +25 -17
- package/backend/control-api.js +3 -1
- package/backend/farming-app-cli.js +21 -0
- package/backend/farming-session-store.js +2 -1
- package/backend/native-pty-host-client.js +59 -2
- package/backend/npm-update-helper.js +65 -7
- package/backend/provider-adapters.js +123 -38
- package/backend/provider-session-service.js +138 -34
- package/backend/server.js +94 -105
- package/backend/storage-layout.js +5 -16
- package/backend/update-service.js +94 -5
- package/backend/usage-history-client.js +305 -0
- package/backend/usage-history-scanner.generated.js +2250 -0
- package/backend/usage-history-scanner.ts +2718 -0
- package/backend/usage-history-smoke.js +64 -0
- package/backend/usage-history-worker.js +34 -0
- package/backend/usage-monitor.js +188 -588
- package/backend/vendor/usage-parsers/CC_STATISTICS_LICENSE +21 -0
- package/backend/vendor/usage-parsers/CODEXBAR_LICENSE +21 -0
- package/backend/vendor/usage-parsers/VENDOR.json +45 -0
- package/dist/acp/LICENSE.codex-acp +190 -0
- package/dist/acp/codex-acp-1.1.4.js +30718 -0
- package/dist/assets/App-6yWdwzj8.js +210 -0
- package/dist/assets/{FileEditorMarkdownPreview-UlVd0O4D.js → FileEditorMarkdownPreview-R0jwwLME.js} +4 -4
- package/dist/assets/FileEditorPane-DNy3LAqS.js +2 -0
- package/dist/assets/{IconGlyphs-AU22gPDY.js → IconGlyphs-BsUfqpKN.js} +1 -1
- package/dist/assets/ProjectFilesSection-BhDEUVHA.js +12 -0
- package/dist/assets/{ReviewPage-CeDKDyZh.js → ReviewPage-ChtByBe3.js} +1 -1
- package/dist/assets/{abnfDiagram-VRR7QNED-BgawzDQT.js → abnfDiagram-VRR7QNED-nnglrXFi.js} +1 -1
- package/dist/assets/{architectureDiagram-ZJ3FMSHR-DUShwPg0.js → architectureDiagram-ZJ3FMSHR-BEXMaFfY.js} +1 -1
- package/dist/assets/{blockDiagram-677ZJIJ3-CeGZviXR.js → blockDiagram-677ZJIJ3-1mCezSBk.js} +1 -1
- package/dist/assets/{c4Diagram-LMCZKHZV-CLhYht6S.js → c4Diagram-LMCZKHZV-DhTiI6Uv.js} +1 -1
- package/dist/assets/channel-BVWNatUB.js +1 -0
- package/dist/assets/{chunk-32BRIVSS-LFYpT-Cu.js → chunk-32BRIVSS-CCdsKd73.js} +1 -1
- package/dist/assets/{chunk-52WLFC77-BH6jDw9J.js → chunk-52WLFC77-Gncjk4LF.js} +1 -1
- package/dist/assets/{chunk-C7G6YPKG-B_mIUlb7.js → chunk-C7G6YPKG-CiDVUP82.js} +1 -1
- package/dist/assets/{chunk-EX3LRPZG-C63hVuAJ.js → chunk-EX3LRPZG-z6gXP2_N.js} +1 -1
- package/dist/assets/{chunk-FWX5IMBZ-CboX-WF_.js → chunk-FWX5IMBZ-DMZBccQa.js} +2 -2
- package/dist/assets/{chunk-HOUHSVGY-BOgSd6Un.js → chunk-HOUHSVGY-D8tIeoPk.js} +1 -1
- package/dist/assets/{chunk-ICXQ74PX-C0K-pgZt.js → chunk-ICXQ74PX-b6oQ2Q17.js} +1 -1
- package/dist/assets/{chunk-MOJQB5TN-CVMfwN_7.js → chunk-MOJQB5TN-DAVH_p2a.js} +1 -1
- package/dist/assets/{chunk-OGEWGWER-DLT3pxyw.js → chunk-OGEWGWER-DxoiMCI-.js} +1 -1
- package/dist/assets/{chunk-PUDLZKDR-Cd079yIQ.js → chunk-PUDLZKDR-NsOWh7HM.js} +1 -1
- package/dist/assets/{chunk-Q4XR5HBZ-D0jHa6SO.js → chunk-Q4XR5HBZ-Di4H7L21.js} +1 -1
- package/dist/assets/{chunk-V7JOEXUC-CVDtR75H.js → chunk-V7JOEXUC-DttpZg9Y.js} +1 -1
- package/dist/assets/{chunk-VAUOI2AC-B-W2_9Ot.js → chunk-VAUOI2AC-UHNr_yhX.js} +1 -1
- package/dist/assets/{chunk-VR4S4FIN-FD3kWh32.js → chunk-VR4S4FIN-D-Fmtd4Z.js} +1 -1
- package/dist/assets/{chunk-WYO6CB5R-C2bGaS5r.js → chunk-WYO6CB5R-CUxMtfK2.js} +4 -4
- package/dist/assets/{chunk-ZGVPDNZ5-ymgts0zo.js → chunk-ZGVPDNZ5-CoV2QEl0.js} +1 -1
- package/dist/assets/classDiagram-OUVF2IWQ-Db0ib5iE.js +1 -0
- package/dist/assets/classDiagram-v2-EOCWNBFH-Bkf69XF9.js +1 -0
- package/dist/assets/code-dark-5esj0bRu.css +1 -0
- package/dist/assets/{cynefinDiagram-TSTJHNR4-CwpobXIl.js → cynefinDiagram-TSTJHNR4-0xPI92Lg.js} +1 -1
- package/dist/assets/{dagre-VKFMJZFB-Dkhlfjna.js → dagre-VKFMJZFB-DfuMG4gU.js} +1 -1
- package/dist/assets/{diagram-FQU43EPY-hA8dicp6.js → diagram-FQU43EPY-CT00bLZ6.js} +1 -1
- package/dist/assets/{diagram-G47NLZAW-BTY6JTzO.js → diagram-G47NLZAW-Xbh7zXUx.js} +1 -1
- package/dist/assets/{diagram-NH7WQ7WH-xkaHHX9M.js → diagram-NH7WQ7WH-SRDVPfn7.js} +1 -1
- package/dist/assets/{diagram-OA4YK3LP-gk_fg9UU.js → diagram-OA4YK3LP-CQRli4Np.js} +1 -1
- package/dist/assets/{diagram-WEI45ONY-BvC8xd6T.js → diagram-WEI45ONY-DMf17WQi.js} +1 -1
- package/dist/assets/{ebnfDiagram-CCIWWBDH-CR7RaNat.js → ebnfDiagram-CCIWWBDH-DhpFkgJ5.js} +1 -1
- package/dist/assets/{erDiagram-Q63AITRT-_M-JFPbj.js → erDiagram-Q63AITRT-1IwxWmJo.js} +1 -1
- package/dist/assets/file-icons-DpbrD5ZP.js +1 -0
- package/dist/assets/flowDiagram-23GEKE2U-DYFo2xmB.js +1 -0
- package/dist/assets/{ganttDiagram-NO4QXBWP-Bl8P1yf_.js → ganttDiagram-NO4QXBWP-BNCdfyr1.js} +1 -1
- package/dist/assets/{gitGraphDiagram-IHSO6WYX-DoHa5ysz.js → gitGraphDiagram-IHSO6WYX-pbyWZuiX.js} +1 -1
- package/dist/assets/{index-BA-iH2Kg.js → index-C8ZFKye1.js} +2 -2
- package/dist/assets/{infoDiagram-FWYZ7A6U-DSFcSuUs.js → infoDiagram-FWYZ7A6U-BcTOgDbe.js} +1 -1
- package/dist/assets/{ishikawaDiagram-FXEZZL3T-DdkqullI.js → ishikawaDiagram-FXEZZL3T-DCdvGKrn.js} +1 -1
- package/dist/assets/{journeyDiagram-5HDEW3XC-B4hRnQJr.js → journeyDiagram-5HDEW3XC-BZ-1q_IT.js} +1 -1
- package/dist/assets/{kanban-definition-HUTT4EX6-tm2FZB2E.js → kanban-definition-HUTT4EX6-BIgejCjj.js} +1 -1
- package/dist/assets/{line-CmsjK4kn.js → line-CfptFMmX.js} +1 -1
- package/dist/assets/main-DSO3i_Gs.css +1 -0
- package/dist/assets/{mermaid.core-C7UT_EEL.js → mermaid.core-gSpX30pV.js} +3 -3
- package/dist/assets/{mindmap-definition-LN4V7U3C-DplfjGms.js → mindmap-definition-LN4V7U3C-BKBaI4LW.js} +1 -1
- package/dist/assets/{pegDiagram-2B236MQR-lu3SdkQs.js → pegDiagram-2B236MQR-sBvDY3VX.js} +1 -1
- package/dist/assets/{pieDiagram-ENE6RG2P-3fHbmDf9.js → pieDiagram-ENE6RG2P-DWlWcu08.js} +1 -1
- package/dist/assets/{quadrantDiagram-ABIIQ3AL-a5qoWz-X.js → quadrantDiagram-ABIIQ3AL-DZutUd3J.js} +1 -1
- package/dist/assets/{railroadDiagram-RFXS5EU6-D2TOuXW9.js → railroadDiagram-RFXS5EU6-DQb3lXGM.js} +1 -1
- package/dist/assets/{requirementDiagram-TGXJPOKE-LQBWpUvd.js → requirementDiagram-TGXJPOKE-DqFGXu2e.js} +1 -1
- package/dist/assets/{sankeyDiagram-HTMAVEWB-B1ohYoyK.js → sankeyDiagram-HTMAVEWB-d7ECahnO.js} +1 -1
- package/dist/assets/{sequenceDiagram-DBY2YBRQ-C3vM-hMq.js → sequenceDiagram-DBY2YBRQ-DdsbKqct.js} +1 -1
- package/dist/assets/{stateDiagram-2N3HPSRC-BvFhOryI.js → stateDiagram-2N3HPSRC-P6iSrgwR.js} +1 -1
- package/dist/assets/stateDiagram-v2-6OUMAXLB-DIYSf_qh.js +1 -0
- package/dist/assets/{swimlanes-5IMT3BWC-DKF_b-2s.js → swimlanes-5IMT3BWC-BGnZJx1M.js} +1 -1
- package/dist/assets/swimlanesDiagram-G3AALYLV-BIkrlKrZ.js +8 -0
- package/dist/assets/{timeline-definition-FHXFAJF6-vAs11ux_.js → timeline-definition-FHXFAJF6-rA-r3aUR.js} +1 -1
- package/dist/assets/{vennDiagram-L72KCM5P-BybTX_9B.js → vennDiagram-L72KCM5P-DiVKUjA9.js} +1 -1
- package/dist/assets/{wardleyDiagram-EHGQE667-CicUmMBR.js → wardleyDiagram-EHGQE667-Cfxh7UOn.js} +1 -1
- package/dist/assets/workspace-editor-model-D0Im34S5.js +1 -0
- package/dist/assets/{workspace-editor-monaco-BICJESG0.js → workspace-editor-monaco-BIpqcWf1.js} +1 -1
- package/dist/assets/workspace-editor-monaco-DLlws5Ig.js +1 -0
- package/dist/assets/{workspace-view-state-DvYG_9PH.js → workspace-view-state-BpPINu84.js} +1 -1
- package/dist/assets/{xychartDiagram-FW5EYKEG-BhWDyCX-.js → xychartDiagram-FW5EYKEG--hmryQeL.js} +1 -1
- package/dist/crt-mermaid-renderer.js +313 -313
- package/dist/index.html +1 -1
- package/frontend/session-bridge.js +24 -2
- package/frontend/skins/crt/app.js +203 -85
- package/frontend/skins/crt/index.html +2 -11
- package/frontend/skins/crt/styles/effects.css +2 -34
- package/package.json +30 -12
- package/shared/backend-connection-status.d.ts +25 -0
- package/shared/backend-connection-status.js +40 -0
- package/shared/browser-protocol.js +3 -3
- package/backend/app-server-api.js +0 -917
- package/backend/codex-app-server-home.js +0 -39
- package/backend/codex-app-server-runtime.js +0 -901
- package/dist/assets/App-Bumi772v.js +0 -206
- package/dist/assets/FileEditorPane-Dxx4rKOg.js +0 -2
- package/dist/assets/ProjectFilesSection-DE7Nb9Jk.js +0 -12
- package/dist/assets/channel-Uw90AO0b.js +0 -1
- package/dist/assets/classDiagram-OUVF2IWQ-DKW_dtku.js +0 -1
- package/dist/assets/classDiagram-v2-EOCWNBFH-C8Fi7-yv.js +0 -1
- package/dist/assets/code-dark-DPiuyeSp.css +0 -1
- package/dist/assets/code-mobile-3C2Rr-CN.css +0 -1
- package/dist/assets/file-icons-Bw2qd5iT.js +0 -1
- package/dist/assets/flowDiagram-23GEKE2U-DAiS5Y7G.js +0 -1
- package/dist/assets/main-Bqtb5kuz.css +0 -1
- package/dist/assets/stateDiagram-v2-6OUMAXLB-WMrz4PNo.js +0 -1
- package/dist/assets/swimlanesDiagram-G3AALYLV-BGswC9oC.js +0 -8
- package/dist/assets/workspace-editor-model-BQol4qbA.js +0 -1
- package/dist/assets/workspace-editor-monaco-DRJ7IaXk.js +0 -1
- package/scripts/sync-ghostty-vendor.js +0 -66
- /package/dist/assets/{core-D0LFJkDt.js → core-B9MwRjDE.js} +0 -0
|
@@ -16,9 +16,13 @@ function emptyPlan(args) {
|
|
|
16
16
|
return {
|
|
17
17
|
provider: '',
|
|
18
18
|
id: '',
|
|
19
|
+
precreate: false,
|
|
19
20
|
temporary: false,
|
|
20
21
|
source: '',
|
|
21
22
|
forkedFromProviderSessionId: '',
|
|
23
|
+
identityWorkspace: '',
|
|
24
|
+
resumeInsertIndex: null,
|
|
25
|
+
error: '',
|
|
22
26
|
args,
|
|
23
27
|
};
|
|
24
28
|
}
|
|
@@ -44,13 +48,23 @@ function buildAgentProviderSessionPlan({ command, program, args, source } = {})
|
|
|
44
48
|
}
|
|
45
49
|
|
|
46
50
|
const plan = adapter.planSession(rawParts.slice(1), launchArgs);
|
|
47
|
-
if (
|
|
51
|
+
if (plan?.error) {
|
|
52
|
+
return {
|
|
53
|
+
...emptyPlan(launchArgs),
|
|
54
|
+
provider,
|
|
55
|
+
error: String(plan.error),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
if (!plan || (!plan.id && plan.precreate !== true)) return emptyPlan(launchArgs);
|
|
48
59
|
return {
|
|
49
60
|
provider,
|
|
50
61
|
id: plan.id,
|
|
62
|
+
precreate: plan.precreate === true,
|
|
51
63
|
temporary: plan.temporary === true,
|
|
52
64
|
source: plan.source || '',
|
|
53
65
|
forkedFromProviderSessionId: plan.forkedFromProviderSessionId || '',
|
|
66
|
+
identityWorkspace: plan.identityWorkspace || '',
|
|
67
|
+
resumeInsertIndex: Number.isInteger(plan.resumeInsertIndex) ? plan.resumeInsertIndex : null,
|
|
54
68
|
args: Array.isArray(plan.args) ? plan.args : launchArgs,
|
|
55
69
|
};
|
|
56
70
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const RUNTIME_KINDS = new Set(['terminal', 'acp', 'json'
|
|
1
|
+
const RUNTIME_KINDS = new Set(['terminal', 'acp', 'json']);
|
|
2
2
|
|
|
3
3
|
function terminalBinding() {
|
|
4
4
|
return { kind: 'terminal' };
|
|
@@ -10,6 +10,7 @@ function acpBinding(source = {}) {
|
|
|
10
10
|
state: source.state || source.acpState || '',
|
|
11
11
|
error: source.error || source.acpError || '',
|
|
12
12
|
stopReason: source.stopReason || source.acpStopReason || '',
|
|
13
|
+
supportsSteer: source.supportsSteer === true,
|
|
13
14
|
pendingPermission: source.pendingPermission || source.acpPendingPermission || null,
|
|
14
15
|
pendingPermissions: source.pendingPermissions || source.acpPendingPermissions || [],
|
|
15
16
|
pendingElicitation: source.pendingElicitation || source.acpPendingElicitation || null,
|
|
@@ -30,38 +31,24 @@ function jsonBinding(source = {}) {
|
|
|
30
31
|
};
|
|
31
32
|
}
|
|
32
33
|
|
|
33
|
-
function appServerBinding(source = {}) {
|
|
34
|
-
return {
|
|
35
|
-
kind: 'app-server',
|
|
36
|
-
state: source.state || source.codexAppServerState || '',
|
|
37
|
-
endpoint: source.endpoint || source.codexAppServerEndpoint || '',
|
|
38
|
-
threadId: source.threadId || source.codexAppServerThreadId || '',
|
|
39
|
-
turnId: source.turnId || source.codexAppServerTurnId || '',
|
|
40
|
-
error: source.error || source.codexAppServerError || '',
|
|
41
|
-
pendingRequestId: source.pendingRequestId || source.codexAppServerPendingRequestId || '',
|
|
42
|
-
pendingRequestMethod: source.pendingRequestMethod || source.codexAppServerPendingRequestMethod || '',
|
|
43
|
-
pendingRequest: source.pendingRequest || source.codexAppServerPendingRequest || null,
|
|
44
|
-
notice: source.notice || source.codexAppServerNotice || null,
|
|
45
|
-
goal: source.goal || source.codexAppServerGoal || null,
|
|
46
|
-
observerDeferred: source.observerDeferred === true || source.codexCliObserverDeferred === true,
|
|
47
|
-
homePath: source.homePath || source.codexAppServerHomePath || '',
|
|
48
|
-
transcriptUpdatedAt: source.transcriptUpdatedAt || source.codexAppServerTranscriptUpdatedAt || '',
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
|
|
52
34
|
function runtimeKind(agent) {
|
|
53
35
|
if (RUNTIME_KINDS.has(agent?.runtimeBinding?.kind)) return agent.runtimeBinding.kind;
|
|
36
|
+
// App Server was an experimental Codex runtime. Persisted records migrate to
|
|
37
|
+
// ACP because codex-acp uses the same Codex thread id as its session id.
|
|
38
|
+
if (agent?.runtimeBinding?.kind === 'app-server' || agent?.codexRuntimeMode === 'app-server') return 'acp';
|
|
54
39
|
if (agent?.agentRuntimeMode === 'acp') return 'acp';
|
|
55
40
|
if (agent?.agentRuntimeMode === 'json') return 'json';
|
|
56
|
-
return
|
|
41
|
+
return 'terminal';
|
|
57
42
|
}
|
|
58
43
|
|
|
59
44
|
function bindingFromLegacy(agent) {
|
|
60
45
|
if (RUNTIME_KINDS.has(agent?.runtimeBinding?.kind)) return agent.runtimeBinding;
|
|
46
|
+
if (agent?.runtimeBinding?.kind === 'app-server' || agent?.codexRuntimeMode === 'app-server') {
|
|
47
|
+
return acpBinding({ state: 'connecting' });
|
|
48
|
+
}
|
|
61
49
|
switch (runtimeKind(agent)) {
|
|
62
50
|
case 'acp': return acpBinding(agent);
|
|
63
51
|
case 'json': return jsonBinding(agent);
|
|
64
|
-
case 'app-server': return appServerBinding(agent);
|
|
65
52
|
default: return terminalBinding();
|
|
66
53
|
}
|
|
67
54
|
}
|
|
@@ -70,7 +57,6 @@ function runtimeBindingFor(kind, source = {}) {
|
|
|
70
57
|
switch (kind) {
|
|
71
58
|
case 'acp': return acpBinding(source);
|
|
72
59
|
case 'json': return jsonBinding(source);
|
|
73
|
-
case 'app-server': return appServerBinding(source);
|
|
74
60
|
default: return terminalBinding();
|
|
75
61
|
}
|
|
76
62
|
}
|
|
@@ -133,22 +119,6 @@ function publicRuntimeBinding(agent) {
|
|
|
133
119
|
transcriptUpdatedAt: binding.transcriptUpdatedAt,
|
|
134
120
|
};
|
|
135
121
|
}
|
|
136
|
-
if (binding.kind === 'app-server') {
|
|
137
|
-
return {
|
|
138
|
-
kind: 'app-server',
|
|
139
|
-
state: binding.state,
|
|
140
|
-
endpoint: binding.endpoint,
|
|
141
|
-
threadId: binding.threadId,
|
|
142
|
-
turnId: binding.turnId,
|
|
143
|
-
error: binding.error,
|
|
144
|
-
pendingRequestId: binding.pendingRequestId,
|
|
145
|
-
pendingRequestMethod: binding.pendingRequestMethod,
|
|
146
|
-
pendingRequest: binding.pendingRequest,
|
|
147
|
-
notice: binding.notice,
|
|
148
|
-
goal: binding.goal,
|
|
149
|
-
observerDeferred: binding.observerDeferred,
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
122
|
return { ...binding };
|
|
153
123
|
}
|
|
154
124
|
|
|
@@ -162,7 +132,6 @@ function runtimeState(agent) {
|
|
|
162
132
|
function legacyRuntimeMetadata(agent) {
|
|
163
133
|
const binding = bindingFromLegacy(agent);
|
|
164
134
|
const metadata = {
|
|
165
|
-
codexRuntimeMode: binding.kind === 'app-server' ? 'app-server' : 'cli',
|
|
166
135
|
agentRuntimeMode: ['acp', 'json'].includes(binding.kind) ? binding.kind : 'terminal',
|
|
167
136
|
};
|
|
168
137
|
if (binding.kind === 'acp') {
|
|
@@ -188,21 +157,6 @@ function legacyRuntimeMetadata(agent) {
|
|
|
188
157
|
jsonCliTranscriptUpdatedAt: binding.transcriptUpdatedAt,
|
|
189
158
|
};
|
|
190
159
|
}
|
|
191
|
-
if (binding.kind === 'app-server') {
|
|
192
|
-
return {
|
|
193
|
-
...metadata,
|
|
194
|
-
codexAppServerHomePath: binding.homePath,
|
|
195
|
-
codexAppServerState: binding.state,
|
|
196
|
-
codexAppServerEndpoint: binding.endpoint,
|
|
197
|
-
codexAppServerThreadId: binding.threadId,
|
|
198
|
-
codexAppServerTurnId: binding.turnId,
|
|
199
|
-
codexAppServerError: binding.error,
|
|
200
|
-
codexAppServerPendingRequestId: binding.pendingRequestId,
|
|
201
|
-
codexAppServerPendingRequestMethod: binding.pendingRequestMethod,
|
|
202
|
-
codexAppServerPendingRequest: binding.pendingRequest,
|
|
203
|
-
codexCliObserverDeferred: binding.observerDeferred,
|
|
204
|
-
};
|
|
205
|
-
}
|
|
206
160
|
return metadata;
|
|
207
161
|
}
|
|
208
162
|
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// Chat is a product-level intent. ACP is the single structured Chat runtime for
|
|
2
|
+
// every supported coding agent, including Codex.
|
|
3
|
+
const CHAT_MODE = 'chat';
|
|
4
|
+
|
|
5
|
+
function chatRuntimeForProvider() {
|
|
6
|
+
return 'acp';
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function isChatMode(mode) {
|
|
10
|
+
return mode === CHAT_MODE;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function chatCapabilitiesForProvider(provider) {
|
|
14
|
+
const runtime = chatRuntimeForProvider(provider);
|
|
15
|
+
return {
|
|
16
|
+
chatRuntime: runtime,
|
|
17
|
+
supportsChat: true,
|
|
18
|
+
// ACP does not currently define a turn-versioned steer operation.
|
|
19
|
+
supportsSteer: false,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
module.exports = {
|
|
24
|
+
CHAT_MODE,
|
|
25
|
+
chatRuntimeForProvider,
|
|
26
|
+
chatCapabilitiesForProvider,
|
|
27
|
+
isChatMode,
|
|
28
|
+
};
|
|
@@ -59,6 +59,88 @@ function findCodexRolloutFile(sessionId, options = {}) {
|
|
|
59
59
|
return '';
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
function recentSessionDirectories(root, now = new Date()) {
|
|
63
|
+
const directories = [];
|
|
64
|
+
for (const offsetDays of [-1, 0, 1]) {
|
|
65
|
+
const date = new Date(now.getTime() + offsetDays * 24 * 60 * 60 * 1000);
|
|
66
|
+
directories.push(
|
|
67
|
+
path.join(
|
|
68
|
+
root,
|
|
69
|
+
String(date.getFullYear()),
|
|
70
|
+
String(date.getMonth() + 1).padStart(2, '0'),
|
|
71
|
+
String(date.getDate()).padStart(2, '0'),
|
|
72
|
+
),
|
|
73
|
+
path.join(
|
|
74
|
+
root,
|
|
75
|
+
String(date.getUTCFullYear()),
|
|
76
|
+
String(date.getUTCMonth() + 1).padStart(2, '0'),
|
|
77
|
+
String(date.getUTCDate()).padStart(2, '0'),
|
|
78
|
+
),
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
return [...new Set(directories)];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async function findCodexRolloutFileAsync(sessionId, options = {}) {
|
|
85
|
+
const normalizedSessionId = String(sessionId || '').trim();
|
|
86
|
+
if (!normalizedSessionId) return '';
|
|
87
|
+
const codexHome = normalizePathValue(options.codexHome || path.join(os.homedir(), '.codex'));
|
|
88
|
+
const maxEntries = Number.isFinite(options.maxEntries)
|
|
89
|
+
? Math.max(1, Math.floor(options.maxEntries))
|
|
90
|
+
: 100_000;
|
|
91
|
+
const deadline = Number.isFinite(options.deadline)
|
|
92
|
+
? Number(options.deadline)
|
|
93
|
+
: Date.now() + 5_000;
|
|
94
|
+
const sessionsRoot = path.join(codexHome, 'sessions');
|
|
95
|
+
const archivedRoot = path.join(codexHome, 'archived_sessions');
|
|
96
|
+
const preferredDirectories = [
|
|
97
|
+
...recentSessionDirectories(sessionsRoot),
|
|
98
|
+
...(options.recentOnly === true ? [] : [archivedRoot]),
|
|
99
|
+
];
|
|
100
|
+
const visited = new Set();
|
|
101
|
+
let inspectedEntries = 0;
|
|
102
|
+
|
|
103
|
+
async function inspectDirectory(directory, descend) {
|
|
104
|
+
if (Date.now() > deadline || inspectedEntries >= maxEntries || visited.has(directory)) return '';
|
|
105
|
+
visited.add(directory);
|
|
106
|
+
let entries;
|
|
107
|
+
try {
|
|
108
|
+
entries = await fsp.readdir(directory, { withFileTypes: true });
|
|
109
|
+
} catch {
|
|
110
|
+
return '';
|
|
111
|
+
}
|
|
112
|
+
const subdirectories = [];
|
|
113
|
+
for (const entry of entries) {
|
|
114
|
+
inspectedEntries += 1;
|
|
115
|
+
if (Date.now() > deadline || inspectedEntries > maxEntries) return '';
|
|
116
|
+
const fullPath = path.join(directory, entry.name);
|
|
117
|
+
if (entry.isFile() && entry.name.endsWith('.jsonl') && sessionIdFromFilePath(fullPath) === normalizedSessionId) {
|
|
118
|
+
return fullPath;
|
|
119
|
+
}
|
|
120
|
+
if (descend && entry.isDirectory()) subdirectories.push(fullPath);
|
|
121
|
+
}
|
|
122
|
+
return subdirectories;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
for (const directory of preferredDirectories) {
|
|
126
|
+
const found = await inspectDirectory(directory, false);
|
|
127
|
+
if (typeof found === 'string' && found) return found;
|
|
128
|
+
}
|
|
129
|
+
if (options.recentOnly === true) return '';
|
|
130
|
+
|
|
131
|
+
const stack = [sessionsRoot, archivedRoot];
|
|
132
|
+
while (stack.length > 0 && Date.now() <= deadline && inspectedEntries < maxEntries) {
|
|
133
|
+
const directory = stack.pop();
|
|
134
|
+
const result = await inspectDirectory(directory, true);
|
|
135
|
+
if (typeof result === 'string') {
|
|
136
|
+
if (result) return result;
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
stack.push(...result);
|
|
140
|
+
}
|
|
141
|
+
return '';
|
|
142
|
+
}
|
|
143
|
+
|
|
62
144
|
function normalizePreviewText(value, maxLength = 400) {
|
|
63
145
|
return String(value || '')
|
|
64
146
|
.replace(/\r\n/g, '\n')
|
|
@@ -239,5 +321,6 @@ class CodexRolloutFollower extends EventEmitter {
|
|
|
239
321
|
module.exports = {
|
|
240
322
|
CodexRolloutFollower,
|
|
241
323
|
findCodexRolloutFile,
|
|
324
|
+
findCodexRolloutFileAsync,
|
|
242
325
|
formatCodexRolloutEvent,
|
|
243
326
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const { execFile } = require('child_process');
|
|
2
|
+
const fs = require('fs');
|
|
2
3
|
const os = require('os');
|
|
3
4
|
const { promisify } = require('util');
|
|
4
5
|
const { resolveCompatibleCodexExecutable } = require('./executable-discovery');
|
|
@@ -9,6 +10,13 @@ async function runCodexSessionArchiveCommand(action, sessionId, session = {}, op
|
|
|
9
10
|
const resolveExecutable = options.resolveCompatibleCodexExecutable || resolveCompatibleCodexExecutable;
|
|
10
11
|
const runExecFile = options.execFileAsync || execFileAsync;
|
|
11
12
|
const processEnv = options.processEnv || process.env;
|
|
13
|
+
const directoryExists = options.directoryExists || ((directory) => {
|
|
14
|
+
try {
|
|
15
|
+
return fs.statSync(directory).isDirectory();
|
|
16
|
+
} catch {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
});
|
|
12
20
|
const codexResolution = resolveExecutable(session.cliVersion || '', processEnv.PATH || '');
|
|
13
21
|
if (!codexResolution.compatible) {
|
|
14
22
|
return {
|
|
@@ -18,8 +26,11 @@ async function runCodexSessionArchiveCommand(action, sessionId, session = {}, op
|
|
|
18
26
|
}
|
|
19
27
|
|
|
20
28
|
try {
|
|
29
|
+
const sessionCwd = session.cwd || session.workspace || '';
|
|
21
30
|
await runExecFile(codexResolution.path || 'codex', [action, sessionId], {
|
|
22
|
-
cwd:
|
|
31
|
+
cwd: sessionCwd && directoryExists(sessionCwd)
|
|
32
|
+
? sessionCwd
|
|
33
|
+
: (processEnv.HOME || os.homedir()),
|
|
23
34
|
env: session.providerHomePath
|
|
24
35
|
? { ...processEnv, CODEX_HOME: session.providerHomePath }
|
|
25
36
|
: processEnv,
|
|
@@ -412,6 +412,98 @@ async function readSessionMetadata(filePath, maxLines = 80) {
|
|
|
412
412
|
return metadata.id ? metadata : null;
|
|
413
413
|
}
|
|
414
414
|
|
|
415
|
+
function codexSessionDateKeys(startedAt, windowMs) {
|
|
416
|
+
const center = Number(startedAt);
|
|
417
|
+
const radius = Math.max(0, Number(windowMs) || 0);
|
|
418
|
+
if (!Number.isFinite(center) || center <= 0) return [];
|
|
419
|
+
const cursor = new Date(center - radius);
|
|
420
|
+
cursor.setHours(0, 0, 0, 0);
|
|
421
|
+
const lastDay = new Date(center + radius);
|
|
422
|
+
lastDay.setHours(0, 0, 0, 0);
|
|
423
|
+
const keys = [];
|
|
424
|
+
while (cursor <= lastDay) {
|
|
425
|
+
keys.push([
|
|
426
|
+
cursor.getFullYear(),
|
|
427
|
+
String(cursor.getMonth() + 1).padStart(2, '0'),
|
|
428
|
+
String(cursor.getDate()).padStart(2, '0'),
|
|
429
|
+
].join('-'));
|
|
430
|
+
cursor.setDate(cursor.getDate() + 1);
|
|
431
|
+
}
|
|
432
|
+
return keys;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
async function readCodexSessionIdentity(filePath) {
|
|
436
|
+
let handle;
|
|
437
|
+
try {
|
|
438
|
+
handle = await fs.promises.open(filePath, 'r');
|
|
439
|
+
const chunk = Buffer.allocUnsafe(64 * 1024);
|
|
440
|
+
const chunks = [];
|
|
441
|
+
let bytesReadTotal = 0;
|
|
442
|
+
let lineEnd = -1;
|
|
443
|
+
while (bytesReadTotal < 1024 * 1024 && lineEnd < 0) {
|
|
444
|
+
const { bytesRead } = await handle.read(chunk, 0, chunk.length, bytesReadTotal);
|
|
445
|
+
if (bytesRead <= 0) break;
|
|
446
|
+
const current = Buffer.from(chunk.subarray(0, bytesRead));
|
|
447
|
+
chunks.push(current);
|
|
448
|
+
const newlineIndex = current.indexOf(0x0a);
|
|
449
|
+
if (newlineIndex >= 0) lineEnd = bytesReadTotal + newlineIndex;
|
|
450
|
+
bytesReadTotal += bytesRead;
|
|
451
|
+
}
|
|
452
|
+
const header = Buffer.concat(chunks);
|
|
453
|
+
const firstLine = header.subarray(0, lineEnd >= 0 ? lineEnd : header.length).toString('utf8').replace(/\r$/, '');
|
|
454
|
+
const fileSessionId = sessionIdFromFilePath(filePath);
|
|
455
|
+
const event = JSON.parse(firstLine);
|
|
456
|
+
if (event?.type !== 'session_meta') return null;
|
|
457
|
+
const payload = event.payload && typeof event.payload === 'object' ? event.payload : {};
|
|
458
|
+
const id = typeof payload.id === 'string' ? payload.id.trim() : '';
|
|
459
|
+
if (!id || (fileSessionId && id !== fileSessionId)) return null;
|
|
460
|
+
const cwd = typeof payload.cwd === 'string' ? normalizePathValue(payload.cwd) : '';
|
|
461
|
+
return {
|
|
462
|
+
id,
|
|
463
|
+
createdAt: typeof event.timestamp === 'string' ? event.timestamp : '',
|
|
464
|
+
cwd,
|
|
465
|
+
workspace: cwd,
|
|
466
|
+
};
|
|
467
|
+
} catch {
|
|
468
|
+
return null;
|
|
469
|
+
} finally {
|
|
470
|
+
await handle?.close().catch(() => {});
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
async function listCodexSessionIdentities(options = {}) {
|
|
475
|
+
const codexHome = options.codexHome || path.join(os.homedir(), '.codex');
|
|
476
|
+
const startedAt = Number(options.startedAt);
|
|
477
|
+
const windowMs = Math.max(0, Number(options.windowMs) || 0);
|
|
478
|
+
if (!Number.isFinite(startedAt) || startedAt <= 0) return [];
|
|
479
|
+
|
|
480
|
+
const files = [];
|
|
481
|
+
for (const dateKey of codexSessionDateKeys(startedAt, windowMs)) {
|
|
482
|
+
const [year, month, day] = dateKey.split('-');
|
|
483
|
+
const directory = path.join(codexHome, 'sessions', year, month, day);
|
|
484
|
+
let entries;
|
|
485
|
+
try {
|
|
486
|
+
entries = fs.readdirSync(directory, { withFileTypes: true });
|
|
487
|
+
} catch {
|
|
488
|
+
continue;
|
|
489
|
+
}
|
|
490
|
+
for (const entry of entries) {
|
|
491
|
+
if (!entry.isFile() || !entry.name.endsWith('.jsonl')) continue;
|
|
492
|
+
files.push(path.join(directory, entry.name));
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
const identities = [];
|
|
497
|
+
const batchSize = 32;
|
|
498
|
+
for (let offset = 0; offset < files.length; offset += batchSize) {
|
|
499
|
+
const batch = await Promise.all(
|
|
500
|
+
files.slice(offset, offset + batchSize).map(readCodexSessionIdentity)
|
|
501
|
+
);
|
|
502
|
+
identities.push(...batch.filter(Boolean));
|
|
503
|
+
}
|
|
504
|
+
return identities;
|
|
505
|
+
}
|
|
506
|
+
|
|
415
507
|
function getGlobalState(codexHome) {
|
|
416
508
|
const state = readJsonFile(path.join(codexHome, '.codex-global-state.json'), {});
|
|
417
509
|
const atom = state['electron-persisted-atom-state'] || {};
|
|
@@ -540,8 +632,10 @@ async function listCodexSessions(options = {}) {
|
|
|
540
632
|
}
|
|
541
633
|
|
|
542
634
|
module.exports = {
|
|
635
|
+
codexSessionDateKeys,
|
|
543
636
|
hasTemporaryWorkspaceReference,
|
|
544
637
|
isTemporaryWorkspace,
|
|
638
|
+
listCodexSessionIdentities,
|
|
545
639
|
listCodexSessions,
|
|
546
640
|
readSessionIndex,
|
|
547
641
|
readSessionMetadata,
|
|
@@ -12,7 +12,8 @@ const {
|
|
|
12
12
|
} = require('./codex-transcript-sanitizer');
|
|
13
13
|
|
|
14
14
|
// @deprecated `readCodexTranscript` below is the legacy JSONL file reader.
|
|
15
|
-
//
|
|
15
|
+
// The generic event-to-turn projection remains for JSON compatibility feeds;
|
|
16
|
+
// live structured Chat is reduced from ACP session updates instead.
|
|
16
17
|
const DEFAULT_MAX_READ_BYTES = 32 * 1024 * 1024;
|
|
17
18
|
const DEFAULT_MAX_TURNS = 240;
|
|
18
19
|
const USER_MESSAGE_BEGIN = '## My request for Codex:';
|
|
@@ -67,6 +67,7 @@ const MAX_SEARCH_TIMEOUT_MS = 180000;
|
|
|
67
67
|
const DEFAULT_CRT_TERMINAL_FONT_SIZE = 15;
|
|
68
68
|
const MIN_CRT_TERMINAL_FONT_SIZE = 10;
|
|
69
69
|
const MAX_CRT_TERMINAL_FONT_SIZE = 20;
|
|
70
|
+
const MAX_INSTANCE_NAME_LENGTH = 80;
|
|
70
71
|
|
|
71
72
|
const PERSISTED_SETTING_KEYS = new Set([
|
|
72
73
|
'workspace',
|
|
@@ -75,6 +76,7 @@ const PERSISTED_SETTING_KEYS = new Set([
|
|
|
75
76
|
'projectWorkspaces',
|
|
76
77
|
'pinnedProjectWorkspaces',
|
|
77
78
|
'projectNames',
|
|
79
|
+
'instanceName',
|
|
78
80
|
'theme',
|
|
79
81
|
'appearance',
|
|
80
82
|
'language',
|
|
@@ -88,7 +90,6 @@ const PERSISTED_SETTING_KEYS = new Set([
|
|
|
88
90
|
'agentHomes',
|
|
89
91
|
'updateUrl',
|
|
90
92
|
'searchTimeoutMs',
|
|
91
|
-
'codexRuntimeMode',
|
|
92
93
|
'codexApprovalMode',
|
|
93
94
|
'codexModel',
|
|
94
95
|
'codexReasoningEffort',
|
|
@@ -183,6 +184,19 @@ class ConfigManager {
|
|
|
183
184
|
return this.farmingDir;
|
|
184
185
|
}
|
|
185
186
|
|
|
187
|
+
normalizeInstanceName(value) {
|
|
188
|
+
if (typeof value !== 'string') return '';
|
|
189
|
+
return value
|
|
190
|
+
.replace(/[\x00-\x1f\x7f]/g, ' ')
|
|
191
|
+
.replace(/\s+/g, ' ')
|
|
192
|
+
.trim()
|
|
193
|
+
.slice(0, MAX_INSTANCE_NAME_LENGTH);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
getInstanceName() {
|
|
197
|
+
return this.settings?.instanceName || this.normalizeInstanceName(os.hostname()) || 'Farming';
|
|
198
|
+
}
|
|
199
|
+
|
|
186
200
|
normalizeWorkspaceHistory(history) {
|
|
187
201
|
const entries = Array.isArray(history) ? history : [];
|
|
188
202
|
const result = [];
|
|
@@ -290,8 +304,9 @@ class ConfigManager {
|
|
|
290
304
|
projectWorkspaces: [],
|
|
291
305
|
pinnedProjectWorkspaces: [],
|
|
292
306
|
projectNames: {},
|
|
307
|
+
instanceName: '',
|
|
293
308
|
theme: 'terminal',
|
|
294
|
-
appearance: '
|
|
309
|
+
appearance: 'system',
|
|
295
310
|
language: 'en',
|
|
296
311
|
heartbeatInterval: 1000,
|
|
297
312
|
dangerouslySkipAgentPermissionsByDefault: false,
|
|
@@ -306,7 +321,6 @@ class ConfigManager {
|
|
|
306
321
|
agentHomes: cloneAgentHomes(DEFAULT_AGENT_HOMES),
|
|
307
322
|
updateUrl: DEFAULT_UPDATE_URL,
|
|
308
323
|
searchTimeoutMs: DEFAULT_SEARCH_TIMEOUT_MS,
|
|
309
|
-
codexRuntimeMode: 'cli',
|
|
310
324
|
codexApprovalMode: 'approve',
|
|
311
325
|
codexModel: 'gpt-5.5',
|
|
312
326
|
codexReasoningEffort: 'xhigh',
|
|
@@ -326,8 +340,9 @@ class ConfigManager {
|
|
|
326
340
|
projectWorkspaces: [],
|
|
327
341
|
pinnedProjectWorkspaces: [],
|
|
328
342
|
projectNames: {},
|
|
343
|
+
instanceName: '',
|
|
329
344
|
theme: 'terminal',
|
|
330
|
-
appearance: '
|
|
345
|
+
appearance: 'system',
|
|
331
346
|
language: 'en',
|
|
332
347
|
heartbeatInterval: 1000,
|
|
333
348
|
dangerouslySkipAgentPermissionsByDefault: false,
|
|
@@ -342,7 +357,6 @@ class ConfigManager {
|
|
|
342
357
|
agentHomes: cloneAgentHomes(DEFAULT_AGENT_HOMES),
|
|
343
358
|
updateUrl: DEFAULT_UPDATE_URL,
|
|
344
359
|
searchTimeoutMs: DEFAULT_SEARCH_TIMEOUT_MS,
|
|
345
|
-
codexRuntimeMode: 'cli',
|
|
346
360
|
codexApprovalMode: 'approve',
|
|
347
361
|
codexModel: 'gpt-5.5',
|
|
348
362
|
codexReasoningEffort: 'xhigh',
|
|
@@ -376,13 +390,14 @@ class ConfigManager {
|
|
|
376
390
|
this.settings.projectWorkspaces = this.normalizeProjectWorkspaces(this.settings.projectWorkspaces);
|
|
377
391
|
this.settings.pinnedProjectWorkspaces = this.normalizeProjectWorkspaces(this.settings.pinnedProjectWorkspaces);
|
|
378
392
|
this.settings.projectNames = this.normalizeProjectNames(this.settings.projectNames);
|
|
393
|
+
this.settings.instanceName = this.normalizeInstanceName(this.settings.instanceName);
|
|
379
394
|
this.settings.agentHomes = this.normalizeAgentHomes(this.settings.agentHomes);
|
|
380
395
|
if (this.settings.updateUrl === LEGACY_DEFAULT_UPDATE_URL || this.settings.updateUrl === API_DEFAULT_UPDATE_URL) {
|
|
381
396
|
this.settings.updateUrl = DEFAULT_UPDATE_URL;
|
|
382
397
|
}
|
|
383
398
|
this.settings.updateUrl = this.normalizeUpdateUrl(this.settings.updateUrl);
|
|
384
399
|
this.settings.searchTimeoutMs = this.normalizeSearchTimeoutMs(this.settings.searchTimeoutMs);
|
|
385
|
-
|
|
400
|
+
delete this.settings.codexRuntimeMode;
|
|
386
401
|
const legacyMainPageSessionKeys = this.normalizeMainPageSessionKeys(this.settings.mainPageSessionKeys);
|
|
387
402
|
delete this.settings.mainPageSessionKeys;
|
|
388
403
|
this.sessionStore.init({ legacyMainPageSessionKeys });
|
|
@@ -483,7 +498,7 @@ class ConfigManager {
|
|
|
483
498
|
}
|
|
484
499
|
|
|
485
500
|
normalizeAppearance(appearance) {
|
|
486
|
-
return ['light', 'dark'].includes(appearance) ? appearance : '
|
|
501
|
+
return ['system', 'light', 'dark'].includes(appearance) ? appearance : 'system';
|
|
487
502
|
}
|
|
488
503
|
|
|
489
504
|
normalizeLanguage(language) {
|
|
@@ -517,10 +532,6 @@ class ConfigManager {
|
|
|
517
532
|
return ['ask', 'approve', 'full', 'custom'].includes(mode) ? mode : 'approve';
|
|
518
533
|
}
|
|
519
534
|
|
|
520
|
-
normalizeCodexRuntimeMode(mode) {
|
|
521
|
-
return mode === 'app-server' ? 'app-server' : 'cli';
|
|
522
|
-
}
|
|
523
|
-
|
|
524
535
|
normalizeCodexModelPreset(preset) {
|
|
525
536
|
if (preset === 'config') return preset;
|
|
526
537
|
if (typeof preset !== 'string') return 'gpt-5.5:xhigh';
|
|
@@ -676,11 +687,6 @@ class ConfigManager {
|
|
|
676
687
|
return this.getAgentLaunchProfile('codex').approvalMode;
|
|
677
688
|
}
|
|
678
689
|
|
|
679
|
-
getCodexRuntimeMode() {
|
|
680
|
-
if (!this.settings) return 'cli';
|
|
681
|
-
return this.normalizeCodexRuntimeMode(this.settings.codexRuntimeMode);
|
|
682
|
-
}
|
|
683
|
-
|
|
684
690
|
getCodexModelPreset() {
|
|
685
691
|
if (!this.settings) return 'gpt-5.5:xhigh';
|
|
686
692
|
return this.getAgentLaunchProfile('codex').modelPreset;
|
|
@@ -739,6 +745,7 @@ class ConfigManager {
|
|
|
739
745
|
getSettings() {
|
|
740
746
|
return {
|
|
741
747
|
...this.settings,
|
|
748
|
+
instanceName: this.getInstanceName(),
|
|
742
749
|
workspace: this.farmingDir,
|
|
743
750
|
mainPageSessionKeys: this.getMainPageSessionKeys(),
|
|
744
751
|
taskHistory: this.getTaskHistory(),
|
|
@@ -819,10 +826,11 @@ class ConfigManager {
|
|
|
819
826
|
this.settings.projectWorkspaces = this.normalizeProjectWorkspaces(this.settings.projectWorkspaces);
|
|
820
827
|
this.settings.pinnedProjectWorkspaces = this.normalizeProjectWorkspaces(this.settings.pinnedProjectWorkspaces);
|
|
821
828
|
this.settings.projectNames = this.normalizeProjectNames(this.settings.projectNames);
|
|
829
|
+
this.settings.instanceName = this.normalizeInstanceName(this.settings.instanceName);
|
|
822
830
|
this.settings.agentHomes = this.normalizeAgentHomes(this.settings.agentHomes);
|
|
823
831
|
this.settings.updateUrl = this.normalizeUpdateUrl(this.settings.updateUrl);
|
|
824
832
|
this.settings.searchTimeoutMs = this.normalizeSearchTimeoutMs(this.settings.searchTimeoutMs);
|
|
825
|
-
|
|
833
|
+
delete this.settings.codexRuntimeMode;
|
|
826
834
|
delete this.settings.mainPageSessionKeys;
|
|
827
835
|
delete this.settings.taskHistory;
|
|
828
836
|
if (incomingMainPageSessionKeys !== undefined) {
|
package/backend/control-api.js
CHANGED
|
@@ -219,9 +219,11 @@ function createControlRouter(agentManager, options = {}) {
|
|
|
219
219
|
parentAgentId: typeof body.parentAgentId === 'string' ? body.parentAgentId : '',
|
|
220
220
|
task,
|
|
221
221
|
source: 'control-cli',
|
|
222
|
-
agentRuntimeMode: ['json', 'acp'].includes(body.agentRuntimeMode) ? body.agentRuntimeMode : 'terminal',
|
|
222
|
+
agentRuntimeMode: ['json', 'acp', 'chat'].includes(body.agentRuntimeMode) ? body.agentRuntimeMode : 'terminal',
|
|
223
223
|
acpHistoryMode: body.acpHistoryMode === 'resume' ? 'resume' : 'load',
|
|
224
224
|
providerSessionTitle: typeof body.providerSessionTitle === 'string' ? body.providerSessionTitle : '',
|
|
225
|
+
...(Array.isArray(body.additionalDirectories) ? { additionalDirectories: body.additionalDirectories } : {}),
|
|
226
|
+
...(Array.isArray(body.mcpServers) ? { mcpServers: body.mcpServers } : {}),
|
|
225
227
|
dangerouslySkipPermissions: body.dangerouslySkipPermissions === true,
|
|
226
228
|
});
|
|
227
229
|
});
|
|
@@ -7,11 +7,13 @@ const path = require('path');
|
|
|
7
7
|
const { URLSearchParams } = require('url');
|
|
8
8
|
const { execFileSync, spawn } = require('child_process');
|
|
9
9
|
const { run: runControlCli } = require('./farming-cli');
|
|
10
|
+
const { PACKAGED_CODEX_ACP_ARG, runPackagedCodexAcp } = require('./acp/packaged-codex-acp');
|
|
10
11
|
const storageLayout = require('./storage-layout');
|
|
11
12
|
|
|
12
13
|
const SERVER_MODE_ARG = '--farming-server';
|
|
13
14
|
const SERVER_MODE_ENV = 'FARMING_RUN_SERVER';
|
|
14
15
|
const NATIVE_PTY_HOST_ARG = '--native-pty-host';
|
|
16
|
+
const USAGE_HISTORY_SMOKE_ARG = '--farming-usage-history-smoke';
|
|
15
17
|
const DEFAULT_PORT = '6694';
|
|
16
18
|
const DEFAULT_BASE_PATH = '/farming';
|
|
17
19
|
const DEFAULT_SERVER_START_TIMEOUT_MS = 30_000;
|
|
@@ -85,6 +87,13 @@ function appendNodeOption(existing, option) {
|
|
|
85
87
|
function buildServerEnv(overrides = {}, baseEnv = process.env) {
|
|
86
88
|
const env = { ...baseEnv, ...overrides };
|
|
87
89
|
delete env.PKG_EXECPATH;
|
|
90
|
+
if (!process.pkg && !env.FARMING_MANAGED_PACKAGE_ROOT) {
|
|
91
|
+
try {
|
|
92
|
+
env.FARMING_MANAGED_PACKAGE_ROOT = fs.realpathSync(path.join(__dirname, '..'));
|
|
93
|
+
} catch {
|
|
94
|
+
// npm update verification will remain unavailable when the package root cannot be proven.
|
|
95
|
+
}
|
|
96
|
+
}
|
|
88
97
|
const cliBinDir = process.pkg ? path.dirname(process.execPath) : path.join(__dirname, '..', 'bin');
|
|
89
98
|
env.PORT = String(env.FARMING_PORT || env.PORT || DEFAULT_PORT);
|
|
90
99
|
env.FARMING_BASE_PATH = env.FARMING_BASE_PATH || DEFAULT_BASE_PATH;
|
|
@@ -774,6 +783,18 @@ async function run(argv = process.argv.slice(2)) {
|
|
|
774
783
|
return 0;
|
|
775
784
|
}
|
|
776
785
|
|
|
786
|
+
if (argv[0] === PACKAGED_CODEX_ACP_ARG) {
|
|
787
|
+
runPackagedCodexAcp();
|
|
788
|
+
return 0;
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
if (argv[0] === USAGE_HISTORY_SMOKE_ARG) {
|
|
792
|
+
const { runUsageHistorySmoke } = require('./usage-history-smoke');
|
|
793
|
+
const result = await runUsageHistorySmoke();
|
|
794
|
+
console.log(JSON.stringify(result));
|
|
795
|
+
return 0;
|
|
796
|
+
}
|
|
797
|
+
|
|
777
798
|
if (argv[0] === NATIVE_PTY_HOST_ARG || process.env.FARMING_RUN_NATIVE_PTY_HOST === '1') {
|
|
778
799
|
runNativePtyHostInCurrentProcess();
|
|
779
800
|
return 0;
|
|
@@ -25,8 +25,9 @@ function safeSessionFileName(id) {
|
|
|
25
25
|
function atomicWriteJson(file, value) {
|
|
26
26
|
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
27
27
|
const tmpFile = `${file}.${process.pid}.${Date.now()}.tmp`;
|
|
28
|
-
fs.writeFileSync(tmpFile, JSON.stringify(value, null, 2));
|
|
28
|
+
fs.writeFileSync(tmpFile, JSON.stringify(value, null, 2), { mode: 0o600 });
|
|
29
29
|
fs.renameSync(tmpFile, file);
|
|
30
|
+
fs.chmodSync(file, 0o600);
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
function parseProviderSessionKey(key) {
|