farming-code 2.2.20 → 2.2.22

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 (49) hide show
  1. package/README.md +5 -5
  2. package/README.zh_cn.md +5 -5
  3. package/THIRD_PARTY_NOTICES.md +5 -8
  4. package/backend/acp/client-services.js +37 -5
  5. package/backend/acp/patch-decisions.js +19 -3
  6. package/backend/acp-runtime.js +1201 -198
  7. package/backend/acp-transcript.js +66 -0
  8. package/backend/agent-lifecycle-journal.js +133 -0
  9. package/backend/agent-manager.js +2715 -354
  10. package/backend/agent-order.js +8 -4
  11. package/backend/agent-runtime-binding.js +1 -0
  12. package/backend/bundle-update-helper.js +5 -1
  13. package/backend/config-manager.js +16 -0
  14. package/backend/control-api.js +146 -20
  15. package/backend/farming-app-cli.js +335 -10
  16. package/backend/farming-session-store.js +283 -36
  17. package/backend/json-cli-runtime.js +120 -6
  18. package/backend/npm-update-helper.js +97 -18
  19. package/backend/provider-adapters.js +18 -6
  20. package/backend/review-session-service.js +31 -17
  21. package/backend/server.js +332 -102
  22. package/backend/storage-layout.js +10 -0
  23. package/backend/theme-manager.js +23 -5
  24. package/backend/update-service.js +239 -27
  25. package/backend/workspace-file-router.js +9 -3
  26. package/backend/workspace-file-service.js +292 -62
  27. package/dist/acp/codex-acp-1.1.4.js +32 -1
  28. package/dist/assets/App-CmZdNavW.js +210 -0
  29. package/dist/assets/{FileEditorMarkdownPreview-R0jwwLME.js → FileEditorMarkdownPreview-KbnE8VC8.js} +1 -1
  30. package/dist/assets/FileEditorPane-5_HUejjd.js +2 -0
  31. package/dist/assets/IconGlyphs-C2WFcoJS.js +1 -0
  32. package/dist/assets/ProjectFilesSection-C1RAJWOE.js +12 -0
  33. package/dist/assets/{ReviewPage-DBKNOWsJ.js → ReviewPage-L1vh1Ggs.js} +3 -3
  34. package/dist/assets/code-dark-BKtvf0Xc.css +1 -0
  35. package/dist/assets/file-icons-CHWt5nSy.js +1 -0
  36. package/dist/assets/{index-DuMjesL2.js → index-RvUiMpGP.js} +2 -2
  37. package/dist/assets/main-XMXgyJJt.css +1 -0
  38. package/dist/assets/workspace-view-state-BqB4HM7r.js +7 -0
  39. package/dist/index.html +1 -1
  40. package/frontend/skins/crt/app.js +199 -81
  41. package/package.json +9 -3
  42. package/dist/assets/App-BupehIbc.js +0 -210
  43. package/dist/assets/FileEditorPane-CJs6kfZO.js +0 -2
  44. package/dist/assets/IconGlyphs-CZzDr5o2.js +0 -1
  45. package/dist/assets/ProjectFilesSection-DWCV07lA.js +0 -12
  46. package/dist/assets/code-dark-BAt0Q_Op.css +0 -1
  47. package/dist/assets/file-icons-DpbrD5ZP.js +0 -1
  48. package/dist/assets/main-y2aK_56c.css +0 -1
  49. package/dist/assets/workspace-view-state-BpPINu84.js +0 -7
@@ -3,6 +3,10 @@ const { createTwoFilesPatch, diffLines } = require('diff');
3
3
  const MAX_RENDERED_DIFF_CHARS = 64 * 1024;
4
4
  const MAX_INLINE_TOOL_DETAIL_CHARS = 4 * 1024;
5
5
  const MAX_EMBEDDED_RESOURCE_TEXT_CHARS = 4 * 1024;
6
+ const MAX_COLLABORATION_AGENTS = 16;
7
+ const MAX_COLLABORATION_ID_CHARS = 160;
8
+ const MAX_COLLABORATION_PATH_CHARS = 512;
9
+ const MAX_COLLABORATION_MESSAGE_CHARS = 160;
6
10
 
7
11
  function diffBlocks(content) {
8
12
  return (Array.isArray(content) ? content : [])
@@ -232,6 +236,66 @@ function generatedMediaTool(entry) {
232
236
  || String(output.savedPath || '').includes('/generated_images/');
233
237
  }
234
238
 
239
+ function boundedCollaborationString(value, maxChars) {
240
+ return String(value || '').trim().slice(0, maxChars);
241
+ }
242
+
243
+ function boundedCollaborationIds(value) {
244
+ const seen = new Set();
245
+ return (Array.isArray(value) ? value : []).flatMap(item => {
246
+ const id = boundedCollaborationString(item, MAX_COLLABORATION_ID_CHARS);
247
+ if (!id || seen.has(id) || seen.size >= MAX_COLLABORATION_AGENTS) return [];
248
+ seen.add(id);
249
+ return [id];
250
+ });
251
+ }
252
+
253
+ function transcriptCodexToolMeta(entry) {
254
+ const codex = entry?._meta?.codex && typeof entry._meta.codex === 'object'
255
+ ? entry._meta.codex
256
+ : {};
257
+ const compact = {};
258
+ if (codex.collaboration && typeof codex.collaboration === 'object') {
259
+ const rawInput = entry?.rawInput && typeof entry.rawInput === 'object' && !Array.isArray(entry.rawInput)
260
+ ? entry.rawInput
261
+ : {};
262
+ const receiverThreadIds = boundedCollaborationIds(
263
+ codex.collaboration.receiverThreadIds || rawInput.receiverThreadIds
264
+ );
265
+ const rawStates = rawInput.agentsStates && typeof rawInput.agentsStates === 'object' && !Array.isArray(rawInput.agentsStates)
266
+ ? rawInput.agentsStates
267
+ : {};
268
+ const agentsStates = {};
269
+ const stateIds = boundedCollaborationIds([...receiverThreadIds, ...Object.keys(rawStates)]);
270
+ for (const threadId of stateIds) {
271
+ const state = rawStates[threadId] && typeof rawStates[threadId] === 'object'
272
+ ? rawStates[threadId]
273
+ : {};
274
+ agentsStates[threadId] = {
275
+ status: boundedCollaborationString(state.status, 32),
276
+ message: boundedCollaborationString(state.message, MAX_COLLABORATION_MESSAGE_CHARS),
277
+ };
278
+ }
279
+ compact.collaboration = {
280
+ tool: boundedCollaborationString(codex.collaboration.tool, 48),
281
+ senderThreadId: boundedCollaborationString(
282
+ codex.collaboration.senderThreadId || rawInput.senderThreadId,
283
+ MAX_COLLABORATION_ID_CHARS
284
+ ),
285
+ receiverThreadIds,
286
+ agentsStates,
287
+ };
288
+ }
289
+ if (codex.subagent && typeof codex.subagent === 'object') {
290
+ compact.subagent = {
291
+ threadId: boundedCollaborationString(codex.subagent.threadId, MAX_COLLABORATION_ID_CHARS),
292
+ path: boundedCollaborationString(codex.subagent.path, MAX_COLLABORATION_PATH_CHARS),
293
+ activity: boundedCollaborationString(codex.subagent.activity, 32),
294
+ };
295
+ }
296
+ return Object.keys(compact).length > 0 ? compact : null;
297
+ }
298
+
235
299
  function acpTranscriptToolEntry(entry) {
236
300
  if (!entry || entry.type !== 'tool') return entry;
237
301
  const detail = detailForTool(entry);
@@ -254,6 +318,8 @@ function acpTranscriptToolEntry(entry) {
254
318
  if (entry?._meta?.farming_patch_decisions) {
255
319
  meta.farming_patch_decisions = JSON.parse(JSON.stringify(entry._meta.farming_patch_decisions));
256
320
  }
321
+ const codexMeta = transcriptCodexToolMeta(entry);
322
+ if (codexMeta) meta.codex = codexMeta;
257
323
  return {
258
324
  id: String(entry.id || ''),
259
325
  type: 'tool',
@@ -0,0 +1,133 @@
1
+ const MAX_LIFECYCLE_OPERATIONS = 32;
2
+ const TERMINAL_OPERATION_STATES = new Set(['succeeded', 'failed', 'cancelled']);
3
+
4
+ function compactLifecycleEntries(entries) {
5
+ const recentIds = new Set(entries.slice(-MAX_LIFECYCLE_OPERATIONS).map(operation => operation.id));
6
+ return entries.filter(operation => (
7
+ recentIds.has(operation.id)
8
+ || operation.requestKey.startsWith('create-request:')
9
+ ));
10
+ }
11
+
12
+ function normalizeOperation(operation) {
13
+ if (!operation || typeof operation !== 'object') return null;
14
+ const id = String(operation.id || '').trim();
15
+ const type = String(operation.type || '').trim();
16
+ const state = String(operation.state || '').trim();
17
+ if (!id || !type || !state) return null;
18
+ return {
19
+ id,
20
+ type,
21
+ state,
22
+ requestKey: String(operation.requestKey || ''),
23
+ request: operation.request && typeof operation.request === 'object'
24
+ ? JSON.parse(JSON.stringify(operation.request))
25
+ : {},
26
+ result: operation.result && typeof operation.result === 'object'
27
+ ? JSON.parse(JSON.stringify(operation.result))
28
+ : null,
29
+ startedAt: Number(operation.startedAt) || 0,
30
+ updatedAt: Number(operation.updatedAt) || 0,
31
+ finishedAt: Number(operation.finishedAt) || null,
32
+ error: String(operation.error || ''),
33
+ };
34
+ }
35
+
36
+ function lifecycleJournal(source) {
37
+ const raw = source?.lifecycleJournal;
38
+ const entries = Array.isArray(raw?.entries)
39
+ ? compactLifecycleEntries(raw.entries.map(normalizeOperation).filter(Boolean))
40
+ : [];
41
+ return {
42
+ sequence: Math.max(0, Math.floor(Number(raw?.sequence) || 0)),
43
+ entries,
44
+ };
45
+ }
46
+
47
+ function activeLifecycleOperation(source) {
48
+ const journal = lifecycleJournal(source);
49
+ for (let index = journal.entries.length - 1; index >= 0; index -= 1) {
50
+ const operation = journal.entries[index];
51
+ if (!TERMINAL_OPERATION_STATES.has(operation.state)) return operation;
52
+ }
53
+ return null;
54
+ }
55
+
56
+ function latestLifecycleOperation(source) {
57
+ const entries = lifecycleJournal(source).entries;
58
+ return entries.length > 0 ? entries[entries.length - 1] : null;
59
+ }
60
+
61
+ function beginLifecycleOperation(source, type, requestKey, request = {}, now = Date.now()) {
62
+ const journal = lifecycleJournal(source);
63
+ const active = activeLifecycleOperation({ lifecycleJournal: journal });
64
+ if (active) {
65
+ if (active.type === type && active.requestKey === String(requestKey || '')) {
66
+ source.lifecycleJournal = journal;
67
+ return { operation: active, joined: true };
68
+ }
69
+ return { conflict: active };
70
+ }
71
+
72
+ journal.sequence += 1;
73
+ const operation = {
74
+ id: `aop_${journal.sequence}`,
75
+ type: String(type || ''),
76
+ state: 'pending',
77
+ requestKey: String(requestKey || ''),
78
+ request: request && typeof request === 'object' ? JSON.parse(JSON.stringify(request)) : {},
79
+ result: null,
80
+ startedAt: now,
81
+ updatedAt: now,
82
+ finishedAt: null,
83
+ error: '',
84
+ };
85
+ journal.entries.push(operation);
86
+ journal.entries = compactLifecycleEntries(journal.entries);
87
+ source.lifecycleJournal = journal;
88
+ return { operation, joined: false };
89
+ }
90
+
91
+ function transitionLifecycleOperation(source, operationId, state, error = '', now = Date.now()) {
92
+ const journal = lifecycleJournal(source);
93
+ const operation = journal.entries.find(candidate => candidate.id === operationId);
94
+ if (!operation) return null;
95
+ if (TERMINAL_OPERATION_STATES.has(operation.state)) return operation;
96
+ operation.state = String(state || operation.state);
97
+ operation.error = String(error || '');
98
+ operation.updatedAt = now;
99
+ operation.finishedAt = TERMINAL_OPERATION_STATES.has(operation.state) ? now : null;
100
+ if (
101
+ operation.type === 'create'
102
+ && operation.finishedAt !== null
103
+ && operation.request
104
+ && Object.prototype.hasOwnProperty.call(operation.request, 'previousState')
105
+ ) {
106
+ delete operation.request.previousState;
107
+ }
108
+ source.lifecycleJournal = journal;
109
+ return operation;
110
+ }
111
+
112
+ function setLifecycleOperationResult(source, operationId, result, now = Date.now()) {
113
+ const journal = lifecycleJournal(source);
114
+ const operation = journal.entries.find(candidate => candidate.id === operationId);
115
+ if (!operation) return null;
116
+ operation.result = result && typeof result === 'object'
117
+ ? JSON.parse(JSON.stringify(result))
118
+ : null;
119
+ operation.updatedAt = now;
120
+ source.lifecycleJournal = journal;
121
+ return operation;
122
+ }
123
+
124
+ module.exports = {
125
+ MAX_LIFECYCLE_OPERATIONS,
126
+ TERMINAL_OPERATION_STATES,
127
+ activeLifecycleOperation,
128
+ beginLifecycleOperation,
129
+ latestLifecycleOperation,
130
+ lifecycleJournal,
131
+ setLifecycleOperationResult,
132
+ transitionLifecycleOperation,
133
+ };