farming-code 2.2.13 → 2.2.16
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 +81 -105
- package/README.zh_cn.md +82 -106
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/backend/acp/packaged-codex-acp.js +13 -0
- package/backend/acp-runtime.js +192 -14
- package/backend/agent-manager.js +176 -510
- package/backend/agent-runtime-binding.js +9 -55
- package/backend/chat-runtime.js +28 -0
- package/backend/codex-transcript.js +2 -1
- package/backend/config-manager.js +22 -14
- package/backend/control-api.js +3 -1
- package/backend/farming-app-cli.js +13 -0
- package/backend/farming-session-store.js +2 -1
- package/backend/npm-update-helper.js +65 -7
- package/backend/provider-adapters.js +6 -2
- package/backend/server.js +89 -104
- package/backend/storage-layout.js +0 -16
- package/backend/update-service.js +94 -5
- package/dist/acp/LICENSE.codex-acp +190 -0
- package/dist/acp/codex-acp-1.1.4.js +30718 -0
- package/dist/assets/App-y6p2yRar.js +206 -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-DKBGxoPX.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-CYZKdoqi.js → index-iKBvPjWS.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-CdkLOXYl.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 +194 -82
- package/frontend/skins/crt/index.html +2 -11
- package/frontend/skins/crt/styles/effects.css +2 -34
- package/package.json +23 -9
- 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-xASd_Y0F.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
|
@@ -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
|
+
};
|
|
@@ -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,6 +304,7 @@ class ConfigManager {
|
|
|
290
304
|
projectWorkspaces: [],
|
|
291
305
|
pinnedProjectWorkspaces: [],
|
|
292
306
|
projectNames: {},
|
|
307
|
+
instanceName: '',
|
|
293
308
|
theme: 'terminal',
|
|
294
309
|
appearance: 'light',
|
|
295
310
|
language: 'en',
|
|
@@ -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,6 +340,7 @@ class ConfigManager {
|
|
|
326
340
|
projectWorkspaces: [],
|
|
327
341
|
pinnedProjectWorkspaces: [],
|
|
328
342
|
projectNames: {},
|
|
343
|
+
instanceName: '',
|
|
329
344
|
theme: 'terminal',
|
|
330
345
|
appearance: 'light',
|
|
331
346
|
language: 'en',
|
|
@@ -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 });
|
|
@@ -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,6 +7,7 @@ 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';
|
|
@@ -85,6 +86,13 @@ function appendNodeOption(existing, option) {
|
|
|
85
86
|
function buildServerEnv(overrides = {}, baseEnv = process.env) {
|
|
86
87
|
const env = { ...baseEnv, ...overrides };
|
|
87
88
|
delete env.PKG_EXECPATH;
|
|
89
|
+
if (!process.pkg && !env.FARMING_MANAGED_PACKAGE_ROOT) {
|
|
90
|
+
try {
|
|
91
|
+
env.FARMING_MANAGED_PACKAGE_ROOT = fs.realpathSync(path.join(__dirname, '..'));
|
|
92
|
+
} catch {
|
|
93
|
+
// npm update verification will remain unavailable when the package root cannot be proven.
|
|
94
|
+
}
|
|
95
|
+
}
|
|
88
96
|
const cliBinDir = process.pkg ? path.dirname(process.execPath) : path.join(__dirname, '..', 'bin');
|
|
89
97
|
env.PORT = String(env.FARMING_PORT || env.PORT || DEFAULT_PORT);
|
|
90
98
|
env.FARMING_BASE_PATH = env.FARMING_BASE_PATH || DEFAULT_BASE_PATH;
|
|
@@ -774,6 +782,11 @@ async function run(argv = process.argv.slice(2)) {
|
|
|
774
782
|
return 0;
|
|
775
783
|
}
|
|
776
784
|
|
|
785
|
+
if (argv[0] === PACKAGED_CODEX_ACP_ARG) {
|
|
786
|
+
runPackagedCodexAcp();
|
|
787
|
+
return 0;
|
|
788
|
+
}
|
|
789
|
+
|
|
777
790
|
if (argv[0] === NATIVE_PTY_HOST_ARG || process.env.FARMING_RUN_NATIVE_PTY_HOST === '1') {
|
|
778
791
|
runNativePtyHostInCurrentProcess();
|
|
779
792
|
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) {
|
|
@@ -64,12 +64,23 @@ function validatePayload(payload) {
|
|
|
64
64
|
if (!/^[A-Za-z0-9@/._-]+$/.test(String(payload.packageName || ''))) throw new Error('Invalid npm package name');
|
|
65
65
|
if (!/^[0-9A-Za-z.+-]+$/.test(String(payload.targetVersion || ''))) throw new Error('Invalid npm target version');
|
|
66
66
|
if (!/^[0-9A-Za-z.+-]+$/.test(String(payload.previousVersion || ''))) throw new Error('Invalid npm previous version');
|
|
67
|
-
for (const key of ['stateFile', 'logPath', 'cliPath', 'configDir']) {
|
|
67
|
+
for (const key of ['stateFile', 'logPath', 'cliPath', 'packageRoot', 'configDir']) {
|
|
68
68
|
if (!path.isAbsolute(String(payload[key] || ''))) throw new Error(`Invalid npm update ${key}`);
|
|
69
69
|
}
|
|
70
70
|
if (payload.npmPrefix && !path.isAbsolute(String(payload.npmPrefix))) {
|
|
71
71
|
throw new Error('Invalid npm update npmPrefix');
|
|
72
72
|
}
|
|
73
|
+
if (payload.npmFallbackRegistryUrl) {
|
|
74
|
+
let registry;
|
|
75
|
+
try {
|
|
76
|
+
registry = new URL(String(payload.npmFallbackRegistryUrl));
|
|
77
|
+
} catch {
|
|
78
|
+
throw new Error('Invalid npm update registry');
|
|
79
|
+
}
|
|
80
|
+
if (!['http:', 'https:'].includes(registry.protocol)) {
|
|
81
|
+
throw new Error('Invalid npm update registry');
|
|
82
|
+
}
|
|
83
|
+
}
|
|
73
84
|
return payload;
|
|
74
85
|
}
|
|
75
86
|
|
|
@@ -109,15 +120,59 @@ function commandEnvironment() {
|
|
|
109
120
|
|
|
110
121
|
async function installPackage(payload, version) {
|
|
111
122
|
const packageSpec = `${payload.packageName}@${version}`;
|
|
112
|
-
|
|
123
|
+
return installPackageFromRegistry(payload, packageSpec);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function verifyInstalledVersion(payload, expectedVersion) {
|
|
127
|
+
const packageJsonPath = path.join(payload.packageRoot, 'package.json');
|
|
128
|
+
let metadata;
|
|
129
|
+
try {
|
|
130
|
+
metadata = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
131
|
+
} catch (error) {
|
|
132
|
+
throw new Error(`Installed ${payload.packageName} package metadata is unreadable: ${error.message || String(error)}`, { cause: error });
|
|
133
|
+
}
|
|
134
|
+
const actualVersion = String(metadata && metadata.version || '');
|
|
135
|
+
if (actualVersion !== expectedVersion) {
|
|
136
|
+
throw new Error(`Installed ${payload.packageName} version mismatch: expected ${expectedVersion}, found ${actualVersion || 'missing'}`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function logSize(filePath) {
|
|
141
|
+
try {
|
|
142
|
+
return fs.statSync(filePath).size;
|
|
143
|
+
} catch {
|
|
144
|
+
return 0;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function logSince(filePath, offset) {
|
|
149
|
+
try {
|
|
150
|
+
return fs.readFileSync(filePath, 'utf8').slice(offset);
|
|
151
|
+
} catch {
|
|
152
|
+
return '';
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
async function installPackageFromRegistry(payload, packageSpec, registryUrl = '') {
|
|
157
|
+
appendLog(payload.logPath, `Installing ${packageSpec}${registryUrl ? ' from the update-status registry' : ''}`);
|
|
113
158
|
const args = ['install', '--global'];
|
|
114
159
|
if (payload.npmPrefix) args.push('--prefix', payload.npmPrefix);
|
|
160
|
+
if (registryUrl) args.push('--registry', registryUrl);
|
|
115
161
|
args.push(packageSpec, '--no-audit', '--no-fund');
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
162
|
+
const offset = logSize(payload.logPath);
|
|
163
|
+
try {
|
|
164
|
+
await runCommand(payload.npmCommand || 'npm', args, {
|
|
165
|
+
cwd: payload.configDir,
|
|
166
|
+
env: commandEnvironment(),
|
|
167
|
+
logPath: payload.logPath,
|
|
168
|
+
});
|
|
169
|
+
} catch (error) {
|
|
170
|
+
if (!registryUrl && payload.npmFallbackRegistryUrl && /(?:ETARGET|No matching version found)/.test(logSince(payload.logPath, offset))) {
|
|
171
|
+
appendLog(payload.logPath, `Configured npm registry has no ${packageSpec}; retrying from the update-status registry`);
|
|
172
|
+
return installPackageFromRegistry(payload, packageSpec, payload.npmFallbackRegistryUrl);
|
|
173
|
+
}
|
|
174
|
+
throw error;
|
|
175
|
+
}
|
|
121
176
|
}
|
|
122
177
|
|
|
123
178
|
async function startServer(payload, version = payload.targetVersion) {
|
|
@@ -134,6 +189,7 @@ async function runNpmUpdate(rawPayload) {
|
|
|
134
189
|
try {
|
|
135
190
|
writeJsonAtomic(payload.stateFile, stateFor(payload, 'installing'));
|
|
136
191
|
await installPackage(payload, payload.targetVersion);
|
|
192
|
+
verifyInstalledVersion(payload, payload.targetVersion);
|
|
137
193
|
|
|
138
194
|
writeJsonAtomic(payload.stateFile, stateFor(payload, 'restarting'));
|
|
139
195
|
await stopProcess(Number(payload.serverPid));
|
|
@@ -151,6 +207,7 @@ async function runNpmUpdate(rawPayload) {
|
|
|
151
207
|
try {
|
|
152
208
|
writeJsonAtomic(payload.stateFile, stateFor(payload, 'rolling-back', { error: message }));
|
|
153
209
|
await installPackage(payload, payload.previousVersion);
|
|
210
|
+
verifyInstalledVersion(payload, payload.previousVersion);
|
|
154
211
|
await startServer(payload, payload.previousVersion);
|
|
155
212
|
writeJsonAtomic(payload.stateFile, stateFor(payload, 'rolled-back', {
|
|
156
213
|
version: payload.previousVersion,
|
|
@@ -196,5 +253,6 @@ module.exports = {
|
|
|
196
253
|
runNpmUpdate,
|
|
197
254
|
stopProcess,
|
|
198
255
|
validatePayload,
|
|
256
|
+
verifyInstalledVersion,
|
|
199
257
|
writeJsonAtomic,
|
|
200
258
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const path = require('path');
|
|
2
|
+
const { chatCapabilitiesForProvider } = require('./chat-runtime');
|
|
2
3
|
const {
|
|
3
4
|
createProviderSessionId,
|
|
4
5
|
createTemporaryProviderSessionId,
|
|
@@ -145,11 +146,11 @@ const PROVIDER_ADAPTERS = Object.freeze([
|
|
|
145
146
|
interruptInput: '\x1b',
|
|
146
147
|
freshAcpSessionSources: ['codex-temporary'],
|
|
147
148
|
commands: ['codex'],
|
|
148
|
-
supportedRuntimes: ['terminal', 'acp', 'json'
|
|
149
|
+
supportedRuntimes: ['terminal', 'acp', 'json'],
|
|
149
150
|
planSession: codexSessionPlan,
|
|
150
151
|
acp: { packageName: '@agentclientprotocol/codex-acp', version: '1.1.4' },
|
|
151
152
|
prepareAcpEnvironment: codexAcpEnvironment,
|
|
152
|
-
capabilities: { runtimeSwitch: true, terminalProfile: true, goals:
|
|
153
|
+
capabilities: { runtimeSwitch: true, terminalProfile: true, goals: false },
|
|
153
154
|
},
|
|
154
155
|
{
|
|
155
156
|
id: 'claude',
|
|
@@ -225,6 +226,9 @@ function providerCapabilities(provider) {
|
|
|
225
226
|
runtimeSwitch: adapter?.capabilities?.runtimeSwitch === true,
|
|
226
227
|
terminalProfile: adapter?.capabilities?.terminalProfile === true,
|
|
227
228
|
goals: adapter?.capabilities?.goals === true,
|
|
229
|
+
...(adapter
|
|
230
|
+
? chatCapabilitiesForProvider(provider)
|
|
231
|
+
: { chatRuntime: '', supportsChat: false, supportsSteer: false }),
|
|
228
232
|
};
|
|
229
233
|
}
|
|
230
234
|
|