farming-code 2.2.7 → 2.2.11

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 (102) hide show
  1. package/README.md +110 -199
  2. package/README.zh_cn.md +106 -237
  3. package/THIRD_PARTY_NOTICES.md +11 -2
  4. package/backend/acp-checkpoint-store.js +198 -0
  5. package/backend/acp-runtime.js +306 -83
  6. package/backend/acp-session-state.js +202 -6
  7. package/backend/acp-transcript.js +112 -0
  8. package/backend/agent-activity.js +6 -157
  9. package/backend/agent-manager.js +1496 -737
  10. package/backend/agent-provider-session.js +17 -242
  11. package/backend/agent-runtime-binding.js +219 -0
  12. package/backend/agent-session-history.js +66 -1
  13. package/backend/auth.js +79 -6
  14. package/backend/codex-models.js +81 -84
  15. package/backend/codex-session-archive.js +45 -0
  16. package/backend/codex-terminal-profile.js +500 -0
  17. package/backend/codex-transcript-sanitizer.js +12 -0
  18. package/backend/codex-transcript.js +230 -8
  19. package/backend/config-manager.js +30 -0
  20. package/backend/control-api.js +192 -17
  21. package/backend/farming-net-pass.js +285 -0
  22. package/backend/farming-net-registry.js +112 -0
  23. package/backend/farming-net-server.js +298 -0
  24. package/backend/farming-session-store.js +5 -13
  25. package/backend/git-worktree-info.js +181 -0
  26. package/backend/local-session-engine.js +411 -186
  27. package/backend/main-page-session.js +5 -2
  28. package/backend/native-pty-controller-generation.js +106 -0
  29. package/backend/native-pty-host-client.js +275 -7
  30. package/backend/native-pty-host-identity.js +86 -0
  31. package/backend/native-pty-host.js +813 -114
  32. package/backend/native-session-engine.js +100 -28
  33. package/backend/packaged-node-pty.js +22 -2
  34. package/backend/provider-adapters.js +253 -0
  35. package/backend/provider-session-service.js +241 -0
  36. package/backend/runtime-observation.js +81 -0
  37. package/backend/server.js +294 -86
  38. package/backend/session-engine-bridge.js +21 -2
  39. package/backend/session-engine-router.js +1 -1
  40. package/backend/session-engine.js +1 -1
  41. package/backend/session-stream-protocol.js +185 -0
  42. package/backend/storage-layout.js +55 -0
  43. package/backend/terminal-attach-checkpoint.js +74 -0
  44. package/backend/terminal-exit-quiescence.js +39 -0
  45. package/backend/terminal-reducer-flow-control.js +97 -0
  46. package/backend/terminal-screen-state.js +11 -2
  47. package/backend/terminal-screen-worker-pool.js +59 -6
  48. package/backend/terminal-screen-worker-thread.js +97 -57
  49. package/backend/terminal-screen-worker.js +133 -51
  50. package/backend/terminal-state-serialization.js +127 -0
  51. package/backend/terminal-status.js +23 -4
  52. package/backend/usage-monitor.js +81 -4
  53. package/backend/workspace-directory.js +152 -0
  54. package/backend/workspace-file-router.js +182 -76
  55. package/backend/workspace-file-service.js +319 -4
  56. package/backend/workspace-root-registry.js +164 -0
  57. package/dist/assets/App-CHYpgECZ.js +208 -0
  58. package/dist/assets/{FileEditorMarkdownPreview-elKWc8Im.js → FileEditorMarkdownPreview--Cri80nQ.js} +92 -92
  59. package/dist/assets/FileEditorPane-DGJlEKdf.js +2 -0
  60. package/dist/assets/IconGlyphs-Cc14sepw.js +1 -0
  61. package/dist/assets/ProjectFilesSection-Cz1wG4NT.js +12 -0
  62. package/dist/assets/{ReviewPage-BaXu1ZdX.js → ReviewPage-LonRc6Fz.js} +1 -1
  63. package/dist/assets/code-dark-B1pAtO_P.css +1 -0
  64. package/dist/assets/file-icons-Bw2qd5iT.js +1 -0
  65. package/dist/assets/{index-B8SHldPE.js → index-miO2r9IZ.js} +3 -3
  66. package/dist/assets/main-DNe0jPw-.css +1 -0
  67. package/dist/assets/workspace-editor-model-BQol4qbA.js +1 -0
  68. package/dist/assets/workspace-editor-monaco-5gFbeDPF.js +1 -0
  69. package/dist/assets/workspace-editor-monaco-xPv8JzHH.js +4 -0
  70. package/dist/assets/workspace-view-state-DvYG_9PH.js +7 -0
  71. package/dist/assets/workspace-working-copy-D8-s_Sgh.js +1 -0
  72. package/dist/index.html +1 -1
  73. package/frontend/farming-net/app.css +625 -0
  74. package/frontend/farming-net/app.js +268 -0
  75. package/frontend/farming-net/index.html +86 -0
  76. package/frontend/reading-anchor.js +198 -0
  77. package/frontend/session-bridge.js +12 -3
  78. package/frontend/session-modal-bridge.js +5 -12
  79. package/frontend/skins/crt/app.js +1976 -793
  80. package/frontend/skins/crt/index.html +313 -23
  81. package/frontend/skins/crt/styles/billing.css +294 -223
  82. package/frontend/skins/crt/styles/monochrome-green.css +7 -2
  83. package/frontend/terminal-replay.js +372 -0
  84. package/package.json +10 -3
  85. package/shared/browser-protocol.d.ts +5 -0
  86. package/shared/browser-protocol.js +130 -0
  87. package/dist/assets/App-iA2BU9P6.js +0 -124
  88. package/dist/assets/FileEditorPane-RWiFD2cq.js +0 -5
  89. package/dist/assets/IconGlyphs-DfL0EBnj.js +0 -1
  90. package/dist/assets/ProjectFilesSection-Q4PDsWmM.js +0 -12
  91. package/dist/assets/code-dark-CDkOQAtK.css +0 -1
  92. package/dist/assets/file-icons-EFUGSSwf.js +0 -1
  93. package/dist/assets/main-DpYuBonn.css +0 -1
  94. package/dist/assets/qoder-C9LmmOSf.svg +0 -1
  95. package/dist/assets/qoder-Cf9gl0Y5.svg +0 -1
  96. package/dist/assets/qoder-gHCinseV.svg +0 -1
  97. package/dist/assets/workspace-view-state-CTyDzk2D.js +0 -1
  98. package/dist/assets/zsh-CLpveKlF.svg +0 -1
  99. package/dist/assets/zsh-FxSpMPbz.svg +0 -1
  100. /package/dist/assets/{api-D1lyBYIQ.js → api-D8nyOEbz.js} +0 -0
  101. /package/dist/assets/{core-ZlAPicox.js → core-D0LFJkDt.js} +0 -0
  102. /package/dist/assets/{useWorkspaceMenuKeyboard-CneKAZUJ.js → useWorkspaceMenuKeyboard-Brws6Ar9.js} +0 -0
@@ -0,0 +1,198 @@
1
+ const crypto = require('crypto');
2
+ const fs = require('fs/promises');
3
+ const path = require('path');
4
+ const { promisify } = require('util');
5
+ const zlib = require('zlib');
6
+ const storageLayout = require('./storage-layout');
7
+
8
+ const gzip = promisify(zlib.gzip);
9
+ const gunzip = promisify(zlib.gunzip);
10
+ const CHECKPOINT_VERSION = 1;
11
+ const DEFAULT_WRITE_DELAY_MS = 250;
12
+
13
+ async function durableWrite(file, data) {
14
+ const handle = await fs.open(file, 'w');
15
+ try {
16
+ await handle.writeFile(data);
17
+ await handle.sync();
18
+ } finally {
19
+ await handle.close();
20
+ }
21
+ }
22
+
23
+ async function syncDirectory(directory) {
24
+ const handle = await fs.open(directory, 'r');
25
+ try {
26
+ await handle.sync();
27
+ } finally {
28
+ await handle.close();
29
+ }
30
+ }
31
+
32
+ function normalizeIdentity(value = {}) {
33
+ return {
34
+ provider: String(value.provider || '').trim().toLowerCase(),
35
+ providerHomeId: String(value.providerHomeId || 'default').trim() || 'default',
36
+ sessionId: String(value.sessionId || '').trim(),
37
+ cwd: path.resolve(String(value.cwd || process.cwd())),
38
+ };
39
+ }
40
+
41
+ function checkpointKey(identity) {
42
+ return crypto.createHash('sha256')
43
+ .update(JSON.stringify(normalizeIdentity(identity)))
44
+ .digest('hex');
45
+ }
46
+
47
+ function sameIdentity(left, right) {
48
+ return JSON.stringify(normalizeIdentity(left)) === JSON.stringify(normalizeIdentity(right));
49
+ }
50
+
51
+ class AcpCheckpointStore {
52
+ constructor(configDir, options = {}) {
53
+ this.dir = storageLayout.acpCheckpointsDir(configDir);
54
+ this.writeDelayMs = Number.isFinite(Number(options.writeDelayMs))
55
+ ? Math.max(0, Math.floor(Number(options.writeDelayMs)))
56
+ : DEFAULT_WRITE_DELAY_MS;
57
+ this.pending = new Map();
58
+ this.writeChains = new Map();
59
+ }
60
+
61
+ paths(identity) {
62
+ const key = checkpointKey(identity);
63
+ return {
64
+ key,
65
+ checkpoint: path.join(this.dir, `${key}.json.gz`),
66
+ dirty: path.join(this.dir, `${key}.dirty`),
67
+ };
68
+ }
69
+
70
+ enqueue(key, operation) {
71
+ const previous = this.writeChains.get(key) || Promise.resolve();
72
+ const next = previous.catch(() => {}).then(operation);
73
+ this.writeChains.set(key, next);
74
+ void next.then(() => {
75
+ if (this.writeChains.get(key) === next) this.writeChains.delete(key);
76
+ }, () => {
77
+ if (this.writeChains.get(key) === next) this.writeChains.delete(key);
78
+ });
79
+ return next;
80
+ }
81
+
82
+ async load(identity, options = {}) {
83
+ const normalized = normalizeIdentity(identity);
84
+ if (!normalized.provider || !normalized.sessionId) return null;
85
+ const files = this.paths(normalized);
86
+ const inFlight = this.writeChains.get(files.key);
87
+ if (inFlight) await inFlight.catch(() => {});
88
+ try {
89
+ const [compressed, dirty] = await Promise.all([
90
+ fs.readFile(files.checkpoint),
91
+ fs.access(files.dirty).then(() => true).catch(() => false),
92
+ ]);
93
+ const payload = JSON.parse((await gunzip(compressed)).toString('utf8'));
94
+ if (
95
+ payload?.version !== CHECKPOINT_VERSION
96
+ || !sameIdentity(payload.identity, normalized)
97
+ || !payload.state
98
+ ) return null;
99
+ if (dirty && options.allowDirty !== true) return null;
100
+ return { state: payload.state, exact: !dirty, savedAt: Number(payload.savedAt || 0) };
101
+ } catch (error) {
102
+ if (error?.code !== 'ENOENT') {
103
+ console.warn('Failed to read ACP checkpoint:', error && (error.message || error));
104
+ }
105
+ return null;
106
+ }
107
+ }
108
+
109
+ async markDirty(identity) {
110
+ const normalized = normalizeIdentity(identity);
111
+ if (!normalized.provider || !normalized.sessionId) return;
112
+ const files = this.paths(normalized);
113
+ const pending = this.pending.get(files.key);
114
+ if (pending?.timer) clearTimeout(pending.timer);
115
+ this.pending.delete(files.key);
116
+ return this.enqueue(files.key, async () => {
117
+ await fs.mkdir(this.dir, { recursive: true });
118
+ await durableWrite(files.dirty, `${Date.now()}\n`);
119
+ await syncDirectory(this.dir);
120
+ });
121
+ }
122
+
123
+ schedule(identity, state, options = {}) {
124
+ const normalized = normalizeIdentity(identity);
125
+ if (!normalized.provider || !normalized.sessionId || !state) return;
126
+ const files = this.paths(normalized);
127
+ const previous = this.pending.get(files.key);
128
+ if (previous?.timer) clearTimeout(previous.timer);
129
+ const pending = {
130
+ identity: normalized,
131
+ state,
132
+ exact: options.exact === true,
133
+ timer: null,
134
+ };
135
+ pending.timer = setTimeout(() => {
136
+ this.pending.delete(files.key);
137
+ void this.write(pending.identity, pending.state, { exact: pending.exact });
138
+ }, this.writeDelayMs);
139
+ pending.timer.unref?.();
140
+ this.pending.set(files.key, pending);
141
+ }
142
+
143
+ async write(identity, state, options = {}) {
144
+ const normalized = normalizeIdentity(identity);
145
+ if (!normalized.provider || !normalized.sessionId || !state) return;
146
+ const files = this.paths(normalized);
147
+ const pending = this.pending.get(files.key);
148
+ if (pending?.timer) clearTimeout(pending.timer);
149
+ this.pending.delete(files.key);
150
+ return this.enqueue(files.key, async () => {
151
+ const payload = {
152
+ version: CHECKPOINT_VERSION,
153
+ savedAt: Date.now(),
154
+ identity: normalized,
155
+ state: state.exportCheckpoint(),
156
+ };
157
+ const compressed = await gzip(Buffer.from(JSON.stringify(payload)), { level: zlib.constants.Z_BEST_SPEED });
158
+ await fs.mkdir(this.dir, { recursive: true });
159
+ if (options.exact !== true) {
160
+ await durableWrite(files.dirty, `${Date.now()}\n`);
161
+ await syncDirectory(this.dir);
162
+ }
163
+ const temporary = `${files.checkpoint}.${process.pid}.${Date.now()}.tmp`;
164
+ try {
165
+ await durableWrite(temporary, compressed);
166
+ await fs.rename(temporary, files.checkpoint);
167
+ await syncDirectory(this.dir);
168
+ } finally {
169
+ await fs.rm(temporary, { force: true }).catch(() => {});
170
+ }
171
+ if (options.exact === true) {
172
+ await fs.rm(files.dirty, { force: true });
173
+ await syncDirectory(this.dir);
174
+ }
175
+ });
176
+ }
177
+
178
+ async flush() {
179
+ const pending = [...this.pending.values()];
180
+ this.pending.clear();
181
+ pending.forEach(item => {
182
+ if (item.timer) clearTimeout(item.timer);
183
+ });
184
+ await Promise.all(pending.map(item => this.write(item.identity, item.state, { exact: item.exact })));
185
+ await Promise.all([...this.writeChains.values()].map(write => write.catch(() => {})));
186
+ }
187
+
188
+ async dispose() {
189
+ await this.flush();
190
+ }
191
+ }
192
+
193
+ module.exports = {
194
+ AcpCheckpointStore,
195
+ CHECKPOINT_VERSION,
196
+ checkpointKey,
197
+ normalizeIdentity,
198
+ };