farming-code 2.2.16 → 2.2.18

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.
Files changed (37) hide show
  1. package/README.md +2 -2
  2. package/README.zh_cn.md +2 -2
  3. package/THIRD_PARTY_NOTICES.md +16 -0
  4. package/backend/acp-runtime.js +221 -10
  5. package/backend/agent-manager.js +477 -54
  6. package/backend/agent-provider-session.js +15 -1
  7. package/backend/codex-rollout-follower.js +83 -0
  8. package/backend/codex-session-archive.js +12 -1
  9. package/backend/codex-session-history.js +94 -0
  10. package/backend/config-manager.js +3 -3
  11. package/backend/farming-app-cli.js +8 -0
  12. package/backend/native-pty-host-client.js +59 -2
  13. package/backend/provider-adapters.js +117 -36
  14. package/backend/provider-session-service.js +138 -34
  15. package/backend/server.js +5 -1
  16. package/backend/storage-layout.js +5 -0
  17. package/backend/usage-history-client.js +305 -0
  18. package/backend/usage-history-scanner.generated.js +2250 -0
  19. package/backend/usage-history-scanner.ts +2718 -0
  20. package/backend/usage-history-smoke.js +64 -0
  21. package/backend/usage-history-worker.js +34 -0
  22. package/backend/usage-monitor.js +188 -588
  23. package/backend/vendor/usage-parsers/CC_STATISTICS_LICENSE +21 -0
  24. package/backend/vendor/usage-parsers/CODEXBAR_LICENSE +21 -0
  25. package/backend/vendor/usage-parsers/VENDOR.json +45 -0
  26. package/dist/assets/App-DTAQilnX.js +210 -0
  27. package/dist/assets/code-dark-5esj0bRu.css +1 -0
  28. package/dist/assets/{index-iKBvPjWS.js → index-fp8VhOes.js} +2 -2
  29. package/dist/assets/main-DSO3i_Gs.css +1 -0
  30. package/dist/index.html +1 -1
  31. package/frontend/skins/crt/app.js +9 -3
  32. package/package.json +12 -8
  33. package/shared/backend-connection-status.d.ts +25 -0
  34. package/shared/backend-connection-status.js +40 -0
  35. package/dist/assets/App-y6p2yRar.js +0 -206
  36. package/dist/assets/code-dark-DKBGxoPX.css +0 -1
  37. package/dist/assets/main-CdkLOXYl.css +0 -1
package/dist/index.html CHANGED
@@ -15,7 +15,7 @@
15
15
  <link rel="apple-touch-icon" sizes="180x180" href="/farming/farming-2/app-icon-v2-180.png" />
16
16
  <link rel="manifest" href="/farming/farming-2/site.webmanifest" />
17
17
  <title>Farming 2</title>
18
- <script type="module" crossorigin src="/farming/assets/index-iKBvPjWS.js"></script>
18
+ <script type="module" crossorigin src="/farming/assets/index-fp8VhOes.js"></script>
19
19
  <link rel="modulepreload" crossorigin href="/farming/assets/chunk-DECur_0Z.js">
20
20
  <link rel="modulepreload" crossorigin href="/farming/assets/preload-helper-mJowh_hw.js">
21
21
  <link rel="modulepreload" crossorigin href="/farming/assets/jsx-runtime-BthL93pI.js">
@@ -3856,11 +3856,17 @@ function renderCrtBillingSelectedDay({ preferSummary = false } = {}) {
3856
3856
  updateCrtBillingExactMetric('billing-day-cache-read', displayPoint && displayPoint.cacheReadTokens, { date: selectedDate, live: isToday });
3857
3857
  updateCrtBillingExactMetric('billing-day-cache-write', displayPoint && displayPoint.cacheWriteTokens, { date: selectedDate, live: isToday });
3858
3858
  if (providers) {
3859
- const providerTotals = displayProviders ? Object.entries(displayProviders) : [];
3860
- providers.textContent = providerTotals
3859
+ const providerTotals = displayProviders
3860
+ ? Object.entries(displayProviders).filter(([, usage]) => (
3861
+ Math.max(0, Number(usage && usage.totalTokens) || 0) > 0
3862
+ ))
3863
+ : [];
3864
+ providers.textContent = providerTotals.length > 0
3865
+ ? `${providerTotals.length} ${providerTotals.length === 1 ? 'SOURCE' : 'SOURCES'}`
3866
+ : '--';
3867
+ providers.title = providerTotals
3861
3868
  .map(([provider, usage]) => `${provider.toUpperCase()} ${formatCrtExactUsageValue(usage && usage.totalTokens)}`)
3862
3869
  .join(' · ') || '--';
3863
- providers.title = providers.textContent;
3864
3870
  }
3865
3871
  if (stateLabel) {
3866
3872
  const notes = isToday ? ['LIVE 5S', 'PARTIAL DAY', 'INCL CACHE'] : ['COMPLETE DAY', 'INCL CACHE'];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "farming-code",
3
- "version": "2.2.16",
3
+ "version": "2.2.18",
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/",
@@ -29,16 +31,17 @@
29
31
  "scripts": {
30
32
  "sync:ghostty-vendor": "node scripts/sync-ghostty-vendor.js",
31
33
  "prepare:acp-vendor": "node scripts/prepare-codex-acp-vendor.js --copy",
32
- "prebuild": "node scripts/sync-ghostty-vendor.js && node scripts/prepare-codex-acp-vendor.js",
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",
34
- "pretest": "npm run prepare:acp-vendor",
37
+ "pretest": "npm run prepare:acp-vendor && npm run build:usage-history",
35
38
  "start": "npm run build && node backend/server.js",
36
39
  "start:net": "node backend/farming-net-server.js",
37
40
  "start:no-auth": "FARMING_DISABLE_AUTH=1 npm start",
38
- "predev:backend": "npm run prepare:acp-vendor && npm run build:crt-markdown",
41
+ "predev:backend": "npm run prepare:acp-vendor && npm run build:usage-history && npm run build:crt-markdown",
39
42
  "dev:backend": "node backend/server.js",
40
43
  "dev:frontend": "vite",
41
- "predev": "npm run prepare:acp-vendor && npm run build:crt-markdown",
44
+ "predev": "npm run prepare:acp-vendor && npm run build:usage-history && npm run build:crt-markdown",
42
45
  "dev": "node backend/server.js & vite --open & wait",
43
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",
44
47
  "build": "vite build && npm run build:crt-markdown && npm run prepare:acp-vendor",
@@ -71,8 +74,8 @@
71
74
  "test:remote-terminal:chaos": "node scripts/smoke-remote-terminal-chaos.js",
72
75
  "test:e2e:workspaces:local": "FARMING_BASE_PATH=/farming npm run build && node scripts/e2e-workspaces.js local",
73
76
  "test:e2e:workspaces:remote": "FARMING_BASE_PATH=/farming npm run build && node scripts/e2e-workspaces.js remote",
74
- "typecheck": "tsc --noEmit",
75
- "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/**\"",
76
79
  "check": "npm run typecheck && npm run lint && npm test"
77
80
  },
78
81
  "keywords": [
@@ -97,7 +100,7 @@
97
100
  "access": "public"
98
101
  },
99
102
  "engines": {
100
- "node": ">=22"
103
+ "node": "^22.13.0 || >=24.0.0"
101
104
  },
102
105
  "dependencies": {
103
106
  "@agentclientprotocol/claude-agent-acp": "0.59.0",
@@ -137,6 +140,7 @@
137
140
  "devDependencies": {
138
141
  "@eslint/js": "^10.0.1",
139
142
  "@playwright/test": "^1.59.1",
143
+ "@types/node": "^26.1.1",
140
144
  "@types/react": "^19.2.14",
141
145
  "@types/react-dom": "^19.2.3",
142
146
  "@vitejs/plugin-react": "^6.0.1",
@@ -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
+ };