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
|
@@ -174,7 +174,7 @@
|
|
|
174
174
|
inset: 3px 0 0;
|
|
175
175
|
display: flex;
|
|
176
176
|
flex-direction: column;
|
|
177
|
-
justify-content: flex-
|
|
177
|
+
justify-content: flex-start;
|
|
178
178
|
gap: 5px;
|
|
179
179
|
min-height: 0;
|
|
180
180
|
padding: 0 4px 2px 12px;
|
|
@@ -209,7 +209,7 @@
|
|
|
209
209
|
display: flex;
|
|
210
210
|
flex: 0 1 auto;
|
|
211
211
|
flex-direction: column;
|
|
212
|
-
justify-content: flex-
|
|
212
|
+
justify-content: flex-start;
|
|
213
213
|
gap: 5px;
|
|
214
214
|
min-height: 0;
|
|
215
215
|
overflow: hidden;
|
|
@@ -300,20 +300,11 @@
|
|
|
300
300
|
opacity: 0.58;
|
|
301
301
|
}
|
|
302
302
|
|
|
303
|
-
.agent-block.working .agent-output:not(.structured-preview) {
|
|
304
|
-
animation: blink 0.5s infinite;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
303
|
@keyframes crt-chat-signal {
|
|
308
304
|
0%, 100% { opacity: 0.45; transform: scale(0.82); }
|
|
309
305
|
50% { opacity: 1; transform: scale(1); }
|
|
310
306
|
}
|
|
311
307
|
|
|
312
|
-
@keyframes blink {
|
|
313
|
-
0%, 100% { opacity: 1; }
|
|
314
|
-
50% { opacity: 0.8; }
|
|
315
|
-
}
|
|
316
|
-
|
|
317
308
|
.sidebar {
|
|
318
309
|
width: 200px;
|
|
319
310
|
background: #2a2a2a;
|
|
@@ -86,8 +86,7 @@
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
#farming-crt.no-crt .crt-phosphor-noise,
|
|
89
|
-
#farming-crt.no-crt .crt-scan-beam
|
|
90
|
-
#farming-crt.no-crt .agent-output-afterimage {
|
|
89
|
+
#farming-crt.no-crt .crt-scan-beam {
|
|
91
90
|
display: none;
|
|
92
91
|
}
|
|
93
92
|
|
|
@@ -112,15 +111,6 @@
|
|
|
112
111
|
}
|
|
113
112
|
}
|
|
114
113
|
|
|
115
|
-
#farming-crt .agent-output-afterimage {
|
|
116
|
-
pointer-events: none;
|
|
117
|
-
user-select: none;
|
|
118
|
-
opacity: 0.34;
|
|
119
|
-
filter: blur(0.35px);
|
|
120
|
-
mix-blend-mode: screen;
|
|
121
|
-
animation: crt-content-afterimage 620ms cubic-bezier(0.16, 0.72, 0.28, 1) forwards;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
114
|
#farming-crt .xterm-screen {
|
|
125
115
|
position: relative;
|
|
126
116
|
}
|
|
@@ -150,30 +140,8 @@
|
|
|
150
140
|
color: #b98282;
|
|
151
141
|
}
|
|
152
142
|
|
|
153
|
-
#farming-crt .agent-output-afterimage {
|
|
154
|
-
position: absolute;
|
|
155
|
-
inset: 0;
|
|
156
|
-
z-index: 2;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
@keyframes crt-content-afterimage {
|
|
160
|
-
0% {
|
|
161
|
-
opacity: 0.34;
|
|
162
|
-
filter: blur(0.25px) brightness(1.08);
|
|
163
|
-
}
|
|
164
|
-
45% {
|
|
165
|
-
opacity: 0.13;
|
|
166
|
-
filter: blur(0.65px) brightness(0.94);
|
|
167
|
-
}
|
|
168
|
-
100% {
|
|
169
|
-
opacity: 0;
|
|
170
|
-
filter: blur(1.2px) brightness(0.72);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
143
|
@media (prefers-reduced-motion: reduce) {
|
|
175
|
-
#farming-crt .crt-scan-beam
|
|
176
|
-
#farming-crt .agent-output-afterimage {
|
|
144
|
+
#farming-crt .crt-scan-beam {
|
|
177
145
|
display: none;
|
|
178
146
|
}
|
|
179
147
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "farming-code",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.17",
|
|
4
4
|
"description": "Remote browser workspace for supervising AI coding agents",
|
|
5
5
|
"main": "backend/server.js",
|
|
6
6
|
"bin": {
|
|
@@ -8,8 +8,10 @@
|
|
|
8
8
|
},
|
|
9
9
|
"files": [
|
|
10
10
|
"backend/*.js",
|
|
11
|
+
"backend/usage-history-scanner.ts",
|
|
11
12
|
"backend/acp/",
|
|
12
13
|
"backend/data/",
|
|
14
|
+
"backend/vendor/usage-parsers/",
|
|
13
15
|
"bin/",
|
|
14
16
|
"config/*.example",
|
|
15
17
|
"dist/",
|
|
@@ -19,7 +21,6 @@
|
|
|
19
21
|
"frontend/themes/",
|
|
20
22
|
"frontend/vendor/ghostty-web/",
|
|
21
23
|
"shared/",
|
|
22
|
-
"scripts/sync-ghostty-vendor.js",
|
|
23
24
|
"LICENSE",
|
|
24
25
|
"README.md",
|
|
25
26
|
"README.zh_cn.md",
|
|
@@ -29,18 +30,21 @@
|
|
|
29
30
|
],
|
|
30
31
|
"scripts": {
|
|
31
32
|
"sync:ghostty-vendor": "node scripts/sync-ghostty-vendor.js",
|
|
32
|
-
"
|
|
33
|
+
"prepare:acp-vendor": "node scripts/prepare-codex-acp-vendor.js --copy",
|
|
34
|
+
"build:usage-history": "node scripts/build-usage-history-scanner.js",
|
|
35
|
+
"prebuild": "node scripts/build-usage-history-scanner.js && node scripts/sync-ghostty-vendor.js && node scripts/prepare-codex-acp-vendor.js",
|
|
33
36
|
"prepack": "FARMING_BASE_PATH=/farming npm run build",
|
|
37
|
+
"pretest": "npm run prepare:acp-vendor && npm run build:usage-history",
|
|
34
38
|
"start": "npm run build && node backend/server.js",
|
|
35
39
|
"start:net": "node backend/farming-net-server.js",
|
|
36
40
|
"start:no-auth": "FARMING_DISABLE_AUTH=1 npm start",
|
|
37
|
-
"predev:backend": "npm run build:crt-markdown",
|
|
41
|
+
"predev:backend": "npm run prepare:acp-vendor && npm run build:usage-history && npm run build:crt-markdown",
|
|
38
42
|
"dev:backend": "node backend/server.js",
|
|
39
43
|
"dev:frontend": "vite",
|
|
40
|
-
"predev": "npm run build:crt-markdown",
|
|
44
|
+
"predev": "npm run prepare:acp-vendor && npm run build:usage-history && npm run build:crt-markdown",
|
|
41
45
|
"dev": "node backend/server.js & vite --open & wait",
|
|
42
46
|
"build:crt-markdown": "node -e \"require('fs').rmSync('dist/crt-markdown-assets',{recursive:true,force:true})\" && esbuild src/crt-markdown-renderer.tsx --bundle --outdir=dist --entry-names=crt-markdown-renderer --asset-names=crt-markdown-assets/[name]-[hash] --platform=browser --format=iife --target=es2022 --loader:.woff=file --loader:.woff2=file --loader:.ttf=file --minify && esbuild src/crt-mermaid-runtime.ts --bundle --outfile=dist/crt-mermaid-renderer.js --platform=browser --format=iife --target=es2022 --minify",
|
|
43
|
-
"build": "vite build && npm run build:crt-markdown",
|
|
47
|
+
"build": "vite build && npm run build:crt-markdown && npm run prepare:acp-vendor",
|
|
44
48
|
"deploy:remote": "./scripts/deploy.sh up",
|
|
45
49
|
"deploy:remote:no-auth": "./scripts/deploy.sh up --disable-auth",
|
|
46
50
|
"release:cli": "./scripts/package-cli-release.sh",
|
|
@@ -55,7 +59,6 @@
|
|
|
55
59
|
"release:remote:linux-compat": "./scripts/install-remote-linux-compat-release.sh",
|
|
56
60
|
"docs:product:screenshots": "node scripts/capture-product-screenshots.js",
|
|
57
61
|
"test": "node scripts/run-tests.js",
|
|
58
|
-
"test:codex-app-server:real": "FARMING_REAL_CODEX_APP_SERVER_SMOKE=1 node scripts/smoke-codex-app-server.js",
|
|
59
62
|
"test:pre-release:codex-ui": "FARMING_REAL_CODEX_BIN=\"$(command -v codex)\" FARMING_CODEX_BIN=\"$PWD/tests/e2e/fixtures/real-codex-no-update\" FARMING_REAL_CODEX_RELEASE_CASE=1 FARMING_E2E_REAL_CODEX=1 FARMING_PLAYWRIGHT_INTERNAL=1 playwright test tests/e2e/internal/real-codex-release-case.spec.ts --project=chromium --workers=1 --retries=0 --trace=retain-on-failure",
|
|
60
63
|
"test:pre-release:terminal-input": "playwright test tests/e2e/terminal-input-performance.spec.ts --project=chromium --workers=1 --retries=0 --trace=retain-on-failure",
|
|
61
64
|
"test:performance:audit": "node tests/performance/agent-usage-hotpath.js && FARMING_PLAYWRIGHT_INTERNAL=1 playwright test tests/e2e/internal/performance-bottlenecks.spec.ts --project=chromium --workers=1 --retries=0 --trace=retain-on-failure",
|
|
@@ -68,10 +71,11 @@
|
|
|
68
71
|
"test:e2e:local": "FARMING_BASE_PATH=/farming npm run build && node scripts/e2e.js local",
|
|
69
72
|
"test:e2e:remote": "FARMING_BASE_PATH=/farming npm run build && node scripts/e2e.js remote",
|
|
70
73
|
"test:remote-terminal:smoke": "node scripts/smoke-remote-terminal.js",
|
|
74
|
+
"test:remote-terminal:chaos": "node scripts/smoke-remote-terminal-chaos.js",
|
|
71
75
|
"test:e2e:workspaces:local": "FARMING_BASE_PATH=/farming npm run build && node scripts/e2e-workspaces.js local",
|
|
72
76
|
"test:e2e:workspaces:remote": "FARMING_BASE_PATH=/farming npm run build && node scripts/e2e-workspaces.js remote",
|
|
73
|
-
"typecheck": "tsc --noEmit",
|
|
74
|
-
"lint": "eslint --max-warnings=0 \"backend/**/*.js\" \"frontend/**/*.js\" \"scripts/**/*.js\" bin/farming --ignore-pattern \"frontend/vendor/**\" --ignore-pattern \"frontend/themes/**\"",
|
|
77
|
+
"typecheck": "tsc --noEmit && tsc -p tsconfig.usage.json",
|
|
78
|
+
"lint": "eslint --max-warnings=0 \"backend/**/*.js\" \"frontend/**/*.js\" \"scripts/**/*.js\" bin/farming --ignore-pattern \"backend/usage-history-scanner.generated.js\" --ignore-pattern \"frontend/vendor/**\" --ignore-pattern \"frontend/themes/**\"",
|
|
75
79
|
"check": "npm run typecheck && npm run lint && npm test"
|
|
76
80
|
},
|
|
77
81
|
"keywords": [
|
|
@@ -96,7 +100,7 @@
|
|
|
96
100
|
"access": "public"
|
|
97
101
|
},
|
|
98
102
|
"engines": {
|
|
99
|
-
"node": ">=
|
|
103
|
+
"node": "^22.13.0 || >=24.0.0"
|
|
100
104
|
},
|
|
101
105
|
"dependencies": {
|
|
102
106
|
"@agentclientprotocol/claude-agent-acp": "0.59.0",
|
|
@@ -112,7 +116,7 @@
|
|
|
112
116
|
"ansi-to-html": "^0.7.2",
|
|
113
117
|
"chokidar": "^5.0.0",
|
|
114
118
|
"diff": "^9.0.0",
|
|
115
|
-
"express": "^4.
|
|
119
|
+
"express": "^4.22.2",
|
|
116
120
|
"ghostty-web": "^0.4.0",
|
|
117
121
|
"highlight.js": "^11.11.1",
|
|
118
122
|
"katex": "^0.17.0",
|
|
@@ -136,19 +140,33 @@
|
|
|
136
140
|
"devDependencies": {
|
|
137
141
|
"@eslint/js": "^10.0.1",
|
|
138
142
|
"@playwright/test": "^1.59.1",
|
|
143
|
+
"@types/node": "^26.1.1",
|
|
139
144
|
"@types/react": "^19.2.14",
|
|
140
145
|
"@types/react-dom": "^19.2.3",
|
|
141
146
|
"@vitejs/plugin-react": "^6.0.1",
|
|
142
147
|
"@yao-pkg/pkg": "6.20.0",
|
|
143
148
|
"esbuild": "^0.27.7",
|
|
144
149
|
"eslint": "^10.2.0",
|
|
150
|
+
"patch-package": "8.0.1",
|
|
145
151
|
"puppeteer": "^24.40.0",
|
|
146
152
|
"tsx": "^4.21.0",
|
|
147
153
|
"typescript": "^6.0.2",
|
|
148
154
|
"vite": "^8.0.3"
|
|
149
155
|
},
|
|
150
156
|
"overrides": {
|
|
157
|
+
"@hono/node-server": "2.0.11",
|
|
158
|
+
"express@^4.22.2": {
|
|
159
|
+
".": "$express",
|
|
160
|
+
"body-parser": "1.20.6"
|
|
161
|
+
},
|
|
151
162
|
"qs": "6.15.3",
|
|
152
|
-
"dompurify": "3.4.
|
|
163
|
+
"dompurify": "3.4.12"
|
|
164
|
+
},
|
|
165
|
+
"allowScripts": {
|
|
166
|
+
"esbuild@0.27.7": true,
|
|
167
|
+
"esbuild@0.28.1": true,
|
|
168
|
+
"node-pty@1.2.0-beta.12": true,
|
|
169
|
+
"fsevents": false,
|
|
170
|
+
"puppeteer": false
|
|
153
171
|
}
|
|
154
172
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export const BACKEND_INITIAL_CONNECT_GRACE_MS: number
|
|
2
|
+
export const BACKEND_HEARTBEAT_STALE_MS: number
|
|
3
|
+
|
|
4
|
+
export type BackendConnectionState = 'connecting' | 'lost' | 'stale' | null
|
|
5
|
+
export interface PageVisibilitySnapshot {
|
|
6
|
+
visible: boolean
|
|
7
|
+
visibleSince: number
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function classifyBackendConnection(input: {
|
|
11
|
+
connected: boolean
|
|
12
|
+
everConnected: boolean
|
|
13
|
+
lastMessageAt: number
|
|
14
|
+
visibleSince: number
|
|
15
|
+
now: number
|
|
16
|
+
}): BackendConnectionState
|
|
17
|
+
|
|
18
|
+
export function reducePageVisibilitySnapshot(
|
|
19
|
+
current: PageVisibilitySnapshot,
|
|
20
|
+
event: {
|
|
21
|
+
eventType: string
|
|
22
|
+
documentVisible: boolean
|
|
23
|
+
changedAt: number
|
|
24
|
+
},
|
|
25
|
+
): PageVisibilitySnapshot
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
const BACKEND_INITIAL_CONNECT_GRACE_MS = 3000;
|
|
2
|
+
const BACKEND_HEARTBEAT_STALE_MS = 6000;
|
|
3
|
+
|
|
4
|
+
function classifyBackendConnection({
|
|
5
|
+
connected,
|
|
6
|
+
everConnected,
|
|
7
|
+
lastMessageAt,
|
|
8
|
+
visibleSince,
|
|
9
|
+
now,
|
|
10
|
+
}) {
|
|
11
|
+
const observationStartedAt = Math.max(lastMessageAt, visibleSince);
|
|
12
|
+
const elapsed = Math.max(0, now - observationStartedAt);
|
|
13
|
+
if (!connected && everConnected) return 'lost';
|
|
14
|
+
if (!connected && elapsed >= BACKEND_INITIAL_CONNECT_GRACE_MS) return 'connecting';
|
|
15
|
+
if (connected && elapsed >= BACKEND_HEARTBEAT_STALE_MS) return 'stale';
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function reducePageVisibilitySnapshot(current, {
|
|
20
|
+
eventType,
|
|
21
|
+
documentVisible,
|
|
22
|
+
changedAt,
|
|
23
|
+
}) {
|
|
24
|
+
const visible = eventType === 'pagehide' ? false : documentVisible;
|
|
25
|
+
if (visible === current.visible) {
|
|
26
|
+
if (!visible || eventType !== 'pageshow') return current;
|
|
27
|
+
return { visible: true, visibleSince: changedAt };
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
visible,
|
|
31
|
+
visibleSince: visible ? changedAt : current.visibleSince,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
module.exports = {
|
|
36
|
+
BACKEND_INITIAL_CONNECT_GRACE_MS,
|
|
37
|
+
BACKEND_HEARTBEAT_STALE_MS,
|
|
38
|
+
classifyBackendConnection,
|
|
39
|
+
reducePageVisibilitySnapshot,
|
|
40
|
+
};
|
|
@@ -6,7 +6,6 @@ const CLIENT_MESSAGE_TYPES = new Set([
|
|
|
6
6
|
'start-agent',
|
|
7
7
|
'input',
|
|
8
8
|
'composer-input',
|
|
9
|
-
'app-server-request-response',
|
|
10
9
|
'acp-permission-response',
|
|
11
10
|
'interrupt-agent',
|
|
12
11
|
'focus-agent',
|
|
@@ -24,6 +23,7 @@ const SERVER_MESSAGE_TYPES = new Set([
|
|
|
24
23
|
'command-ack',
|
|
25
24
|
'state',
|
|
26
25
|
'error',
|
|
26
|
+
'composer-input-result',
|
|
27
27
|
'agent-started',
|
|
28
28
|
'session-output',
|
|
29
29
|
'session-preview',
|
|
@@ -80,8 +80,7 @@ function validateClientMessage(value) {
|
|
|
80
80
|
case 'protocol-hello': valid = Number.isInteger(value.protocolVersion); break;
|
|
81
81
|
case 'start-agent': valid = stringField(value, 'command'); break;
|
|
82
82
|
case 'input': valid = stringField(value, 'agentId', true) && (typeof value.input === 'string' || Array.isArray(value.inputParts)); break;
|
|
83
|
-
case 'composer-input': valid = stringField(value, 'message') && stringField(value, 'agentId', true); break;
|
|
84
|
-
case 'app-server-request-response':
|
|
83
|
+
case 'composer-input': valid = stringField(value, 'message') && stringField(value, 'agentId', true) && stringField(value, 'requestId', true); break;
|
|
85
84
|
case 'acp-permission-response': valid = stringField(value, 'agentId') && stringField(value, 'requestId'); break;
|
|
86
85
|
case 'focus-agent': valid = value.agentId === null || stringField(value, 'agentId'); break;
|
|
87
86
|
case 'resize-agent': valid = stringField(value, 'agentId') && finiteField(value, 'cols') && finiteField(value, 'rows'); break;
|
|
@@ -102,6 +101,7 @@ function validateServerMessage(value) {
|
|
|
102
101
|
case 'error': valid = stringField(value, 'message'); break;
|
|
103
102
|
case 'command-ack': valid = stringField(value, 'requestId') && stringField(value, 'command'); break;
|
|
104
103
|
case 'state': valid = objectMessage(value.state) && Array.isArray(value.state.agents); break;
|
|
104
|
+
case 'composer-input-result': valid = stringField(value, 'requestId') && stringField(value, 'agentId') && typeof value.accepted === 'boolean' && stringField(value, 'message', true); break;
|
|
105
105
|
case 'agent-started': valid = stringField(value, 'agentId'); break;
|
|
106
106
|
case 'session-output': valid = objectMessage(value.stream) && stringField(value.stream, 'agentId'); break;
|
|
107
107
|
case 'session-preview': valid = objectMessage(value.preview) && stringField(value.preview, 'agentId'); break;
|