farming-code 2.2.28 → 2.2.30

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 (83) hide show
  1. package/README.md +27 -90
  2. package/README.zh_cn.md +17 -90
  3. package/THIRD_PARTY_NOTICES.md +25 -6
  4. package/backend/acp/packaged-claude-acp.js +13 -0
  5. package/backend/acp/packaged-codex-acp.js +2 -2
  6. package/backend/acp-runtime.js +38 -17
  7. package/backend/acp-session-state.js +78 -88
  8. package/backend/acp-transcript.js +174 -9
  9. package/backend/agent-manager.js +27 -2
  10. package/backend/agent-session-history.js +45 -12
  11. package/backend/codex-session-history.js +1 -1
  12. package/backend/codex-transcript.js +0 -202
  13. package/backend/config-manager.js +44 -16
  14. package/backend/data/LICENSE.agent-browser +201 -0
  15. package/backend/data/runtime-dependency-manifest.json +199 -0
  16. package/backend/data/runtime-dependency-sources.json +5 -0
  17. package/backend/executable-discovery.js +7 -0
  18. package/backend/farming-agent-bootstrap.zh_cn.md +4 -2
  19. package/backend/farming-app-cli.js +161 -65
  20. package/backend/farming-cli.js +7 -59
  21. package/backend/index-html.js +31 -0
  22. package/backend/main-agent-skills.js +7 -28
  23. package/backend/npm-update-helper.js +43 -6
  24. package/backend/provider-adapters.js +10 -0
  25. package/backend/runtime-dependency-manager.js +759 -0
  26. package/backend/runtime-executable-invocation.js +20 -0
  27. package/backend/server-process-identity.js +47 -0
  28. package/backend/server.js +145 -204
  29. package/backend/slash-command-discovery.js +138 -1
  30. package/backend/storage-layout.js +30 -0
  31. package/backend/update-service.js +60 -914
  32. package/config/farming.deploy.env.example +1 -1
  33. package/config/farming.install.env.example +5 -1
  34. package/dist/acp/LICENSE.claude-agent-acp +191 -0
  35. package/dist/acp/LICENSE.claude-agent-sdk +1 -0
  36. package/dist/acp/claude-agent-acp-0.59.0.mjs +41606 -0
  37. package/dist/acp/{codex-acp-1.1.4.js → codex-acp-1.1.4.mjs} +387 -7
  38. package/dist/assets/{App-CM7Cy-l4.css → App-BKNUILuL.css} +1 -1
  39. package/dist/assets/App-Z1N7T0eM.js +695 -0
  40. package/dist/assets/{FileEditorMarkdownPreview-DYOMm-b1.js → FileEditorMarkdownPreview-Cs9cLv8a.js} +1 -1
  41. package/dist/assets/FileEditorPane-CNtuGjQ3.js +2 -0
  42. package/dist/assets/IconGlyphs-BClgag6E.js +1 -0
  43. package/dist/assets/ProjectFilesSection-K3GHuQ4U.js +12 -0
  44. package/dist/assets/ReviewPage-BRuxFaH5.js +3 -0
  45. package/dist/assets/code-dark-kLsQLvpf.css +1 -0
  46. package/dist/assets/{index-BzQO3pUr.js → index-D-zetSol.js} +2 -2
  47. package/dist/assets/main-DUTz-Rd2.css +1 -0
  48. package/dist/assets/{workspace-editor-monaco-tXA-udGx.js → workspace-editor-monaco-CJNwbpCy.js} +1 -1
  49. package/dist/assets/workspace-editor-monaco-CO9w8YV0.js +1 -0
  50. package/dist/assets/workspace-view-state-BjKPYp0E.js +7 -0
  51. package/dist/index.html +33 -3
  52. package/extensions/browser/backend/agent-browser-runtime.js +1041 -0
  53. package/extensions/browser/backend/browser-mcp-server.js +352 -0
  54. package/extensions/browser/backend/browser-resource-manager.js +921 -114
  55. package/extensions/browser/backend/browser-resource-store.js +47 -6
  56. package/extensions/browser/backend/browser-router.js +15 -2
  57. package/extensions/browser/backend/executable-discovery.js +164 -17
  58. package/extensions/browser/backend/managed-chromium-installer.js +593 -0
  59. package/extensions/browser/bin/farming-browser +384 -30
  60. package/extensions/browser/frontend/BrowserSidebarPortals.tsx +17 -19
  61. package/extensions/browser/frontend/BrowserViewer.tsx +217 -46
  62. package/extensions/browser/frontend/browser.css +68 -17
  63. package/extensions/browser/frontend/types.ts +13 -0
  64. package/extensions/browser/frontend/useBrowserResources.ts +18 -3
  65. package/index.html +32 -2
  66. package/package.json +10 -6
  67. package/shared/backend-connection-status.d.ts +12 -0
  68. package/shared/backend-connection-status.js +35 -4
  69. package/backend/agent-activity.js +0 -35
  70. package/backend/agent-memory-report.js +0 -583
  71. package/backend/bundle-update-helper.js +0 -113
  72. package/backend/codex-rollout-follower.js +0 -326
  73. package/dist/assets/App-CPG4WcjO.js +0 -658
  74. package/dist/assets/FileEditorPane-DXXq82aM.js +0 -2
  75. package/dist/assets/IconGlyphs-DrdPjYXr.js +0 -1
  76. package/dist/assets/ProjectFilesSection-CP66XVPl.js +0 -12
  77. package/dist/assets/ReviewPage-w21MEPD6.js +0 -3
  78. package/dist/assets/code-dark-BDjwj7Um.css +0 -1
  79. package/dist/assets/main-BlVUXfxa.css +0 -1
  80. package/dist/assets/workspace-editor-monaco-CFEfFNcA.js +0 -1
  81. package/dist/assets/workspace-view-state-BS_V8JVs.js +0 -7
  82. package/extensions/browser/backend/cdp-browser-runtime.js +0 -648
  83. package/extensions/browser/backend/cdp-client.js +0 -167
@@ -23366,6 +23366,9 @@ function createAgentTextThoughtChunk(text, messageId, meta3) {
23366
23366
  var LEGACY_SET_SESSION_MODEL_METHOD = "session/set_model";
23367
23367
  var GOAL_CONTROL_METHOD = "_codex/session/goal_control";
23368
23368
  var STEER_METHOD = "_codex/session/steer";
23369
+ var SUBAGENT_STATE_VERSION = 1;
23370
+ var MAX_SUBAGENT_THREADS = 128;
23371
+ var SUBAGENT_READ_CONCURRENCY = 8;
23369
23372
  function isExtMethodRequest(request) {
23370
23373
  return request.method === "authentication/status" || request.method === "authentication/logout" || request.method === LEGACY_SET_SESSION_MODEL_METHOD || request.method === GOAL_CONTROL_METHOD || request.method === STEER_METHOD;
23371
23374
  }
@@ -26124,6 +26127,54 @@ var CodexAcpClient = class {
26124
26127
  const response = await this.codexClient.threadGoalGet({ threadId: sessionId });
26125
26128
  return response?.goal ?? null;
26126
26129
  }
26130
+ onClientTransportEvent(callback) {
26131
+ this.codexClient.onClientTransportEvent(callback);
26132
+ }
26133
+ async listSubagentThreads(rootThreadId) {
26134
+ const threads = [];
26135
+ let cursor = null;
26136
+ do {
26137
+ const response = await this.codexClient.threadList({
26138
+ cursor,
26139
+ limit: Math.min(100, MAX_SUBAGENT_THREADS - threads.length),
26140
+ sortKey: "created_at",
26141
+ sortDirection: "asc",
26142
+ useStateDbOnly: true,
26143
+ ancestorThreadId: rootThreadId
26144
+ });
26145
+ threads.push(...response.data.slice(0, MAX_SUBAGENT_THREADS - threads.length));
26146
+ cursor = threads.length < MAX_SUBAGENT_THREADS ? response.nextCursor ?? null : null;
26147
+ } while (cursor);
26148
+ let nextIndex = 0;
26149
+ const resolved = new Array(threads.length);
26150
+ const worker = async () => {
26151
+ while (nextIndex < threads.length) {
26152
+ const index = nextIndex++;
26153
+ const thread = threads[index];
26154
+ const runtimeStatus = thread?.status?.type;
26155
+ if (runtimeStatus === "active" || runtimeStatus === "systemError") {
26156
+ resolved[index] = thread;
26157
+ continue;
26158
+ }
26159
+ try {
26160
+ const response = await this.codexClient.threadRead({
26161
+ threadId: thread.id,
26162
+ includeTurns: true
26163
+ });
26164
+ resolved[index] = response.thread;
26165
+ } catch {
26166
+ resolved[index] = thread;
26167
+ }
26168
+ }
26169
+ };
26170
+ await Promise.all(
26171
+ Array.from(
26172
+ { length: Math.min(SUBAGENT_READ_CONCURRENCY, threads.length) },
26173
+ () => worker()
26174
+ )
26175
+ );
26176
+ return resolved.filter(Boolean);
26177
+ }
26127
26178
  async setGoal(sessionId, objective, onTurnStarted) {
26128
26179
  return await this.codexClient.runGoalSet({
26129
26180
  threadId: sessionId,
@@ -27372,6 +27423,53 @@ function imageBlocks(images) {
27372
27423
  return path6 ? [{ type: "text", text: `[@image](${path6})` }] : [];
27373
27424
  });
27374
27425
  }
27426
+ var MAX_HISTORY_IMAGE_BYTES = 5 * 1024 * 1024;
27427
+ var HISTORY_IMAGE_MIME_BY_EXT = /* @__PURE__ */ new Map([
27428
+ [".gif", "image/gif"],
27429
+ [".jpeg", "image/jpeg"],
27430
+ [".jpg", "image/jpeg"],
27431
+ [".png", "image/png"],
27432
+ [".svg", "image/svg+xml"],
27433
+ [".webp", "image/webp"]
27434
+ ]);
27435
+ function historyImageBlockFromDataUrl(value) {
27436
+ const match = String(value ?? "").match(/^data:(image\/(?:gif|jpe?g|png|svg\+xml|webp));base64,([a-z0-9+/=]+)$/i);
27437
+ if (!match || Math.ceil(match[2].length * 3 / 4) > MAX_HISTORY_IMAGE_BYTES) {
27438
+ return null;
27439
+ }
27440
+ return {
27441
+ type: "image",
27442
+ mimeType: match[1].toLowerCase(),
27443
+ data: match[2]
27444
+ };
27445
+ }
27446
+ async function historyImageBlockFromLocalPath(value) {
27447
+ let filePath = String(value ?? "");
27448
+ if (filePath.startsWith("file://")) {
27449
+ try {
27450
+ filePath = fileURLToPath(filePath);
27451
+ } catch {
27452
+ return null;
27453
+ }
27454
+ }
27455
+ const mimeType = HISTORY_IMAGE_MIME_BY_EXT.get(path5.extname(filePath).toLowerCase());
27456
+ if (!mimeType) {
27457
+ return null;
27458
+ }
27459
+ try {
27460
+ const data = await readFile2(filePath);
27461
+ if (data.length === 0 || data.length > MAX_HISTORY_IMAGE_BYTES) {
27462
+ return null;
27463
+ }
27464
+ return {
27465
+ type: "image",
27466
+ mimeType,
27467
+ data: Buffer2.from(data).toString("base64")
27468
+ };
27469
+ } catch {
27470
+ return null;
27471
+ }
27472
+ }
27375
27473
  function contentBlocksFromResponseContent(content) {
27376
27474
  if (!Array.isArray(content)) {
27377
27475
  return [];
@@ -28171,6 +28269,13 @@ var CodexAcpServer = class _CodexAcpServer {
28171
28269
  closingSessions;
28172
28270
  sessionGenerations;
28173
28271
  sessionOpenGenerations;
28272
+ subagentSnapshots;
28273
+ subagentRootByThreadId;
28274
+ subagentRefreshTokens;
28275
+ subagentPublishQueues;
28276
+ subagentPublishDirty;
28277
+ subagentRecoveryTimers;
28278
+ subagentRecoveryAttempts;
28174
28279
  constructor(connection, codexAcpClient, defaultAuthRequest, getExitCode, getRecentStderr) {
28175
28280
  this.sessions = /* @__PURE__ */ new Map();
28176
28281
  this.pendingMcpStartupSessions = /* @__PURE__ */ new Map();
@@ -28179,6 +28284,13 @@ var CodexAcpServer = class _CodexAcpServer {
28179
28284
  this.closingSessions = /* @__PURE__ */ new Map();
28180
28285
  this.sessionGenerations = /* @__PURE__ */ new Map();
28181
28286
  this.sessionOpenGenerations = /* @__PURE__ */ new Map();
28287
+ this.subagentSnapshots = /* @__PURE__ */ new Map();
28288
+ this.subagentRootByThreadId = /* @__PURE__ */ new Map();
28289
+ this.subagentRefreshTokens = /* @__PURE__ */ new Map();
28290
+ this.subagentPublishQueues = /* @__PURE__ */ new Map();
28291
+ this.subagentPublishDirty = /* @__PURE__ */ new Set();
28292
+ this.subagentRecoveryTimers = /* @__PURE__ */ new Map();
28293
+ this.subagentRecoveryAttempts = /* @__PURE__ */ new Map();
28182
28294
  this.connection = connection;
28183
28295
  this.codexAcpClient = codexAcpClient;
28184
28296
  this.defaultAuthRequest = defaultAuthRequest ?? null;
@@ -28194,6 +28306,9 @@ var CodexAcpServer = class _CodexAcpServer {
28194
28306
  (operation) => this.runWithProcessCheck(operation),
28195
28307
  () => this.refreshSessionsAuthState(null)
28196
28308
  );
28309
+ this.codexAcpClient.onClientTransportEvent((event) => {
28310
+ this.handleSubagentTransportEvent(event);
28311
+ });
28197
28312
  }
28198
28313
  async initialize(_params) {
28199
28314
  logger.log("Initialize request received");
@@ -28234,7 +28349,8 @@ var CodexAcpServer = class _CodexAcpServer {
28234
28349
  },
28235
28350
  _meta: {
28236
28351
  codex: {
28237
- steer: { method: STEER_METHOD, version: 1 }
28352
+ steer: { method: STEER_METHOD, version: 1 },
28353
+ subagents: { version: SUBAGENT_STATE_VERSION }
28238
28354
  }
28239
28355
  }
28240
28356
  },
@@ -28513,6 +28629,7 @@ You have been logged out. Please try again.`);
28513
28629
  thread
28514
28630
  } = await this.getOrCreateSessionWithHistory(params);
28515
28631
  await this.streamThreadHistory(sessionId, thread);
28632
+ this.refreshSubagentSnapshotAsync(sessionId);
28516
28633
  logger.log("Session loaded", {
28517
28634
  sessionId,
28518
28635
  modelId: modelState.currentModelId,
@@ -28548,6 +28665,7 @@ You have been logged out. Please try again.`);
28548
28665
  modelId: modelState.currentModelId,
28549
28666
  availableModelCount: modelState.availableModels.length
28550
28667
  });
28668
+ this.refreshSubagentSnapshotAsync(sessionId);
28551
28669
  return {
28552
28670
  models: modelState,
28553
28671
  modes: modeState,
@@ -28589,6 +28707,7 @@ You have been logged out. Please try again.`);
28589
28707
  await activePrompt.completion;
28590
28708
  }
28591
28709
  await this.runWithProcessCheck(() => this.codexAcpClient.closeSession(params.sessionId));
28710
+ this.clearSubagentSnapshot(params.sessionId);
28592
28711
  logger.log("Session closed", { sessionId: params.sessionId });
28593
28712
  } finally {
28594
28713
  if (this.getSessionGeneration(params.sessionId) === closeGeneration) {
@@ -28601,6 +28720,256 @@ You have been logged out. Please try again.`);
28601
28720
  }
28602
28721
  return {};
28603
28722
  }
28723
+ clearSubagentSnapshot(rootThreadId) {
28724
+ const snapshot = this.subagentSnapshots.get(rootThreadId);
28725
+ for (const threadId of snapshot?.agents.keys() ?? []) {
28726
+ if (this.subagentRootByThreadId.get(threadId) === rootThreadId) {
28727
+ this.subagentRootByThreadId.delete(threadId);
28728
+ }
28729
+ }
28730
+ this.subagentSnapshots.delete(rootThreadId);
28731
+ this.subagentRefreshTokens.delete(rootThreadId);
28732
+ this.subagentPublishQueues.delete(rootThreadId);
28733
+ this.subagentPublishDirty.delete(rootThreadId);
28734
+ const recoveryTimer = this.subagentRecoveryTimers.get(rootThreadId);
28735
+ if (recoveryTimer) clearTimeout(recoveryTimer);
28736
+ this.subagentRecoveryTimers.delete(rootThreadId);
28737
+ this.subagentRecoveryAttempts.delete(rootThreadId);
28738
+ }
28739
+ rootThreadIdForSubagent(threadId) {
28740
+ if (this.sessions.has(threadId)) return threadId;
28741
+ return this.subagentRootByThreadId.get(threadId) ?? null;
28742
+ }
28743
+ subagentStatusFromThread(thread) {
28744
+ const runtimeStatus = thread?.status?.type;
28745
+ if (runtimeStatus === "active") return "running";
28746
+ if (runtimeStatus === "systemError") return "errored";
28747
+ const lastTurn = Array.isArray(thread?.turns) ? thread.turns.at(-1) : null;
28748
+ switch (lastTurn?.status) {
28749
+ case "completed":
28750
+ return "completed";
28751
+ case "interrupted":
28752
+ return "interrupted";
28753
+ case "failed":
28754
+ return "errored";
28755
+ case "inProgress":
28756
+ return "running";
28757
+ default:
28758
+ return "pendingInit";
28759
+ }
28760
+ }
28761
+ subagentSnapshotEntry(thread) {
28762
+ return {
28763
+ threadId: String(thread.id),
28764
+ parentThreadId: typeof thread.parentThreadId === "string" ? thread.parentThreadId : null,
28765
+ name: typeof thread.agentNickname === "string" && thread.agentNickname.trim()
28766
+ ? thread.agentNickname.trim()
28767
+ : typeof thread.agentRole === "string" && thread.agentRole.trim()
28768
+ ? thread.agentRole.trim()
28769
+ : "",
28770
+ status: this.subagentStatusFromThread(thread)
28771
+ };
28772
+ }
28773
+ refreshSubagentSnapshotAsync(rootThreadId) {
28774
+ const refreshToken = this.subagentRefreshTokens.get(rootThreadId) ?? 0;
28775
+ void this.runWithProcessCheck(() => this.codexAcpClient.listSubagentThreads(rootThreadId)).then((threads) => {
28776
+ if (!this.sessions.has(rootThreadId)) return;
28777
+ if ((this.subagentRefreshTokens.get(rootThreadId) ?? 0) !== refreshToken) {
28778
+ this.refreshSubagentSnapshotAsync(rootThreadId);
28779
+ return;
28780
+ }
28781
+ const previous = this.subagentSnapshots.get(rootThreadId);
28782
+ const agents = new Map(
28783
+ threads.map((thread) => {
28784
+ const entry = this.subagentSnapshotEntry(thread);
28785
+ return [entry.threadId, entry];
28786
+ })
28787
+ );
28788
+ for (const threadId of previous?.agents.keys() ?? []) {
28789
+ if (!agents.has(threadId) && this.subagentRootByThreadId.get(threadId) === rootThreadId) {
28790
+ this.subagentRootByThreadId.delete(threadId);
28791
+ }
28792
+ }
28793
+ for (const threadId of agents.keys()) {
28794
+ this.subagentRootByThreadId.set(threadId, rootThreadId);
28795
+ }
28796
+ const snapshot = {
28797
+ revision: (previous?.revision ?? 0) + 1,
28798
+ agents
28799
+ };
28800
+ this.subagentSnapshots.set(rootThreadId, snapshot);
28801
+ this.publishSubagentUpdate(rootThreadId, "snapshot", [...agents.values()], snapshot.revision);
28802
+ }).catch((error51) => {
28803
+ logger.error(`Failed to reconcile Codex subagents for session ${rootThreadId}`, error51);
28804
+ });
28805
+ }
28806
+ publishSubagentUpdate(rootThreadId, kind, agents, revision) {
28807
+ if (!this.sessions.has(rootThreadId)) return;
28808
+ const run = async () => {
28809
+ const dirty = this.subagentPublishDirty.has(rootThreadId);
28810
+ const current = this.subagentSnapshots.get(rootThreadId);
28811
+ const updateKind = dirty ? "snapshot" : kind;
28812
+ const updateAgents = dirty && current ? [...current.agents.values()] : agents;
28813
+ const updateRevision = dirty && current ? current.revision : revision;
28814
+ const session = new ACPSessionConnection(this.connection, rootThreadId);
28815
+ await session.update({
28816
+ sessionUpdate: "session_info_update",
28817
+ _meta: {
28818
+ codex: {
28819
+ subagents: {
28820
+ version: SUBAGENT_STATE_VERSION,
28821
+ rootThreadId,
28822
+ revision: updateRevision,
28823
+ kind: updateKind,
28824
+ agents: updateAgents
28825
+ }
28826
+ }
28827
+ }
28828
+ });
28829
+ this.subagentPublishDirty.delete(rootThreadId);
28830
+ this.subagentRecoveryAttempts.delete(rootThreadId);
28831
+ const recoveryTimer = this.subagentRecoveryTimers.get(rootThreadId);
28832
+ if (recoveryTimer) clearTimeout(recoveryTimer);
28833
+ this.subagentRecoveryTimers.delete(rootThreadId);
28834
+ };
28835
+ const previous = this.subagentPublishQueues.get(rootThreadId);
28836
+ const next = (previous ? previous.then(run, run) : run()).catch((error51) => {
28837
+ logger.error(`Failed to publish Codex subagent state for session ${rootThreadId}`, error51);
28838
+ this.subagentPublishDirty.add(rootThreadId);
28839
+ this.scheduleSubagentRecovery(rootThreadId);
28840
+ });
28841
+ this.subagentPublishQueues.set(rootThreadId, next);
28842
+ void next.finally(() => {
28843
+ if (this.subagentPublishQueues.get(rootThreadId) === next) {
28844
+ this.subagentPublishQueues.delete(rootThreadId);
28845
+ }
28846
+ });
28847
+ }
28848
+ scheduleSubagentRecovery(rootThreadId) {
28849
+ if (!this.sessions.has(rootThreadId) || this.subagentRecoveryTimers.has(rootThreadId)) return;
28850
+ const attempt = this.subagentRecoveryAttempts.get(rootThreadId) ?? 0;
28851
+ if (attempt >= 3) return;
28852
+ const delays = [100, 500, 1e3];
28853
+ const timer = setTimeout(() => {
28854
+ this.subagentRecoveryTimers.delete(rootThreadId);
28855
+ if (!this.sessions.has(rootThreadId)) {
28856
+ this.subagentPublishDirty.delete(rootThreadId);
28857
+ this.subagentRecoveryAttempts.delete(rootThreadId);
28858
+ return;
28859
+ }
28860
+ if (!this.subagentPublishDirty.has(rootThreadId)) return;
28861
+ this.subagentRecoveryAttempts.set(rootThreadId, attempt + 1);
28862
+ const current = this.subagentSnapshots.get(rootThreadId);
28863
+ if (!current) return;
28864
+ this.publishSubagentUpdate(
28865
+ rootThreadId,
28866
+ "snapshot",
28867
+ [...current.agents.values()],
28868
+ current.revision
28869
+ );
28870
+ }, delays[attempt]);
28871
+ this.subagentRecoveryTimers.set(rootThreadId, timer);
28872
+ }
28873
+ updateSubagent(rootThreadId, entry) {
28874
+ if (!rootThreadId || !entry?.threadId || !this.sessions.has(rootThreadId)) return;
28875
+ const previous = this.subagentSnapshots.get(rootThreadId) ?? {
28876
+ revision: 0,
28877
+ agents: /* @__PURE__ */ new Map()
28878
+ };
28879
+ const existing = previous.agents.get(entry.threadId);
28880
+ const nextEntry = {
28881
+ threadId: entry.threadId,
28882
+ parentThreadId: entry.parentThreadId ?? existing?.parentThreadId ?? null,
28883
+ name: entry.name ?? existing?.name ?? "",
28884
+ status: entry.status ?? existing?.status ?? "pendingInit"
28885
+ };
28886
+ if (
28887
+ existing
28888
+ && existing.parentThreadId === nextEntry.parentThreadId
28889
+ && existing.name === nextEntry.name
28890
+ && existing.status === nextEntry.status
28891
+ ) {
28892
+ return;
28893
+ }
28894
+ const next = {
28895
+ revision: previous.revision + 1,
28896
+ agents: new Map(previous.agents)
28897
+ };
28898
+ next.agents.set(nextEntry.threadId, nextEntry);
28899
+ this.subagentSnapshots.set(rootThreadId, next);
28900
+ this.subagentRootByThreadId.set(nextEntry.threadId, rootThreadId);
28901
+ this.subagentRefreshTokens.set(
28902
+ rootThreadId,
28903
+ (this.subagentRefreshTokens.get(rootThreadId) ?? 0) + 1
28904
+ );
28905
+ this.publishSubagentUpdate(rootThreadId, "delta", [nextEntry], next.revision);
28906
+ }
28907
+ handleSubagentTransportEvent(event) {
28908
+ if (event?.eventType !== "notification") return;
28909
+ const params = event.params ?? {};
28910
+ const method = event.method;
28911
+ if (method === "thread/started") {
28912
+ const thread = params.thread;
28913
+ const parentThreadId = thread?.parentThreadId;
28914
+ const rootThreadId = typeof parentThreadId === "string"
28915
+ ? this.rootThreadIdForSubagent(parentThreadId)
28916
+ : null;
28917
+ if (rootThreadId && thread?.id) {
28918
+ this.updateSubagent(rootThreadId, this.subagentSnapshotEntry(thread));
28919
+ }
28920
+ return;
28921
+ }
28922
+ if (
28923
+ (method === "item/started" || method === "item/completed")
28924
+ && params.item?.type === "subAgentActivity"
28925
+ ) {
28926
+ const parentThreadId = typeof params.threadId === "string" ? params.threadId : "";
28927
+ const rootThreadId = this.rootThreadIdForSubagent(parentThreadId);
28928
+ const childThreadId = params.item.threadId;
28929
+ if (rootThreadId && typeof childThreadId === "string") {
28930
+ this.updateSubagent(rootThreadId, {
28931
+ threadId: childThreadId,
28932
+ parentThreadId,
28933
+ status: "pendingInit"
28934
+ });
28935
+ }
28936
+ return;
28937
+ }
28938
+ const threadId = typeof params.threadId === "string" ? params.threadId : "";
28939
+ const rootThreadId = this.rootThreadIdForSubagent(threadId);
28940
+ if (!rootThreadId || rootThreadId === threadId) return;
28941
+ if (method === "turn/started") {
28942
+ this.updateSubagent(rootThreadId, { threadId, status: "running" });
28943
+ return;
28944
+ }
28945
+ if (method === "turn/completed") {
28946
+ const status = params.turn?.status;
28947
+ this.updateSubagent(rootThreadId, {
28948
+ threadId,
28949
+ status: status === "completed"
28950
+ ? "completed"
28951
+ : status === "interrupted"
28952
+ ? "interrupted"
28953
+ : status === "failed"
28954
+ ? "errored"
28955
+ : "running"
28956
+ });
28957
+ return;
28958
+ }
28959
+ if (method === "thread/status/changed") {
28960
+ const status = params.status?.type;
28961
+ if (status === "active" || status === "systemError") {
28962
+ this.updateSubagent(rootThreadId, {
28963
+ threadId,
28964
+ status: status === "active" ? "running" : "errored"
28965
+ });
28966
+ }
28967
+ return;
28968
+ }
28969
+ if (method === "thread/closed") {
28970
+ this.updateSubagent(rootThreadId, { threadId, status: "shutdown" });
28971
+ }
28972
+ }
28604
28973
  async deleteSession(params) {
28605
28974
  logger.log("Deleting session...", { sessionId: params.sessionId });
28606
28975
  const sessionId = params.sessionId;
@@ -29107,11 +29476,11 @@ You have been logged out. Please try again.`);
29107
29476
  return [this.createPlanUpdate(item)];
29108
29477
  }
29109
29478
  }
29110
- createUserMessageUpdates(item) {
29479
+ async createUserMessageUpdates(item) {
29111
29480
  const updates = [];
29112
29481
  const messageId = item.id;
29113
29482
  for (const input of item.content) {
29114
- const blocks = this.userInputToContentBlocks(input);
29483
+ const blocks = await this.userInputToContentBlocks(input);
29115
29484
  for (const block of blocks) {
29116
29485
  updates.push(createUserMessageChunk(block, messageId));
29117
29486
  }
@@ -29155,15 +29524,26 @@ ${item.text}`
29155
29524
  }
29156
29525
  };
29157
29526
  }
29158
- userInputToContentBlocks(input) {
29527
+ async userInputToContentBlocks(input) {
29159
29528
  switch (input.type) {
29160
29529
  case "text":
29161
29530
  return input.text.length > 0 ? [{ type: "text", text: input.text }] : [];
29162
- case "image":
29163
- return [{ type: "text", text: this.formatUriAsLink("image", input.url) }];
29531
+ case "image": {
29532
+ const image = historyImageBlockFromDataUrl(input.url);
29533
+ return image ? [image] : [{
29534
+ type: "resource_link",
29535
+ uri: input.url,
29536
+ name: "image"
29537
+ }];
29538
+ }
29164
29539
  case "localImage": {
29165
29540
  const uri = input.path.startsWith("file://") ? input.path : `file://${input.path}`;
29166
- return [{ type: "text", text: this.formatUriAsLink(null, uri) }];
29541
+ const image = await historyImageBlockFromLocalPath(input.path);
29542
+ return image ? [image] : [{
29543
+ type: "resource_link",
29544
+ uri,
29545
+ name: path5.basename(input.path) || "image"
29546
+ }];
29167
29547
  }
29168
29548
  case "skill":
29169
29549
  return [{ type: "text", text: `skill:${input.name} (${input.path})` }];
@@ -1 +1 @@
1
- .xterm{cursor:text;-webkit-user-select:none;user-select:none;position:relative}.xterm.focus,.xterm:focus{outline:none}.xterm .xterm-helpers{z-index:5;position:absolute;top:0}.xterm .xterm-helper-textarea{opacity:0;z-index:-5;white-space:nowrap;resize:none;border:0;width:0;height:0;margin:0;padding:0;position:absolute;top:0;left:-9999em;overflow:hidden}.xterm .composition-view{color:#fff;white-space:nowrap;z-index:1;background:#000;display:none;position:absolute}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{cursor:default;background-color:#000;position:absolute;inset:0;overflow-y:scroll}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;top:0;left:0}.xterm-char-measure-element{visibility:hidden;line-height:normal;display:inline-block;position:absolute;top:0;left:-9999em}.xterm.enable-mouse-events{cursor:default}.xterm.xterm-cursor-pointer,.xterm .xterm-cursor-pointer{cursor:pointer}.xterm.column-select.focus{cursor:crosshair}.xterm .xterm-accessibility:not(.debug),.xterm .xterm-message{z-index:10;color:#0000;pointer-events:none;position:absolute;inset:0}.xterm .xterm-accessibility-tree:not(.debug) ::selection{color:#0000}.xterm .xterm-accessibility-tree{-webkit-user-select:text;user-select:text;white-space:pre;font-family:monospace}.xterm .xterm-accessibility-tree>div{transform-origin:0;width:fit-content}.xterm .live-region{width:1px;height:1px;position:absolute;left:-9999px;overflow:hidden}.xterm-dim{opacity:1!important}.xterm-underline-1{text-decoration:underline}.xterm-underline-2{-webkit-text-decoration:underline double;text-decoration:underline double}.xterm-underline-3{-webkit-text-decoration:underline wavy;text-decoration:underline wavy}.xterm-underline-4{-webkit-text-decoration:underline dotted;text-decoration:underline dotted}.xterm-underline-5{-webkit-text-decoration:underline dashed;text-decoration:underline dashed}.xterm-overline{text-decoration:overline}.xterm-overline.xterm-underline-1{text-decoration:underline overline}.xterm-overline.xterm-underline-2{-webkit-text-decoration:overline double underline;text-decoration:overline double underline}.xterm-overline.xterm-underline-3{-webkit-text-decoration:overline wavy underline;text-decoration:overline wavy underline}.xterm-overline.xterm-underline-4{-webkit-text-decoration:overline dotted underline;text-decoration:overline dotted underline}.xterm-overline.xterm-underline-5{-webkit-text-decoration:overline dashed underline;text-decoration:overline dashed underline}.xterm-strikethrough{text-decoration:line-through}.xterm-screen .xterm-decoration-container .xterm-decoration{z-index:6;position:absolute}.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer{z-index:7}.xterm-decoration-overview-ruler{z-index:8;pointer-events:none;position:absolute;top:0;right:0}.xterm-decoration-top{z-index:2;position:relative}.xterm .xterm-scrollable-element>.scrollbar{cursor:default}.xterm .xterm-scrollable-element>.scrollbar>.scra{cursor:pointer;font-size:11px!important}.xterm .xterm-scrollable-element>.visible{opacity:1;z-index:11;background:0 0;transition:opacity .1s linear}.xterm .xterm-scrollable-element>.invisible{opacity:0;pointer-events:none}.xterm .xterm-scrollable-element>.invisible.fade{transition:opacity .8s linear}.xterm .xterm-scrollable-element>.shadow{display:none;position:absolute}.xterm .xterm-scrollable-element>.shadow.top{width:100%;height:3px;box-shadow:var(--vscode-scrollbar-shadow,#000) 0 6px 6px -6px inset;display:block;top:0;left:3px}.xterm .xterm-scrollable-element>.shadow.left{width:3px;height:100%;box-shadow:var(--vscode-scrollbar-shadow,#000) 6px 0 6px -6px inset;display:block;top:3px;left:0}.xterm .xterm-scrollable-element>.shadow.top-left-corner{width:3px;height:3px;display:block;top:0;left:0}.xterm .xterm-scrollable-element>.shadow.top.left{box-shadow:var(--vscode-scrollbar-shadow,#000) 6px 0 6px -6px inset}.farming-browser-section{color:#343a34;min-width:0;margin-top:2px;margin-left:14px}.code-settings-browser-row .code-settings-row-copy small{text-overflow:clip;white-space:normal;overflow:visible}.code-settings-browser-unavailable{color:#747b72;white-space:nowrap;font-size:12px;line-height:18px}.farming-browser-section>header{min-height:var(--code-files-header-height,25px);color:#5f675e;letter-spacing:0;text-transform:uppercase;background:#f6f7f3;align-items:center;gap:8px;padding:2px 6px 1px 0;font-size:13px;font-weight:500;display:flex}.farming-browser-section-toggle{min-width:0;min-height:22px;color:inherit;cursor:pointer;font:inherit;letter-spacing:inherit;text-align:left;text-transform:inherit;background:0 0;border:0;border-radius:4px;flex:0 auto;align-items:center;gap:5px;padding:0 4px 0 2px;display:inline-flex}.farming-browser-section-toggle:hover,.farming-browser-section-toggle:focus-visible{color:#30372f;outline:0}.farming-browser-section-chevron{color:#6b7368;flex:0 0 14px;justify-content:center;align-items:center;width:14px;height:14px;display:inline-flex}.farming-browser-section-chevron svg,.farming-browser-new svg,.farming-browser-row-actions svg{fill:currentColor;width:14px;height:14px;display:block}.farming-browser-section-toggle small{color:#8a9188;font-size:11px;font-weight:450}.farming-browser-new,.farming-browser-row-actions button{color:#6b7368;cursor:pointer;background:0 0;border:0;border-radius:4px;flex:0 0 22px;justify-content:center;align-items:center;width:22px;height:22px;padding:0;display:inline-flex}.farming-browser-new:hover,.farming-browser-new:focus-visible,.farming-browser-row-actions button:hover,.farming-browser-row-actions button:focus-visible{color:#30372f;background:#1f23280d;outline:0}.farming-browser-new:disabled,.farming-browser-row-actions button:disabled{cursor:default;opacity:.38}.farming-browser-list{min-width:0}.farming-browser-row{color:#535a52;cursor:default;border-radius:5px;grid-template-columns:8px minmax(0,1fr) auto;align-items:center;gap:7px;min-width:0;min-height:32px;margin:0 4px 0 0;padding:3px 4px 3px 5px;font-size:13px;line-height:16px;display:grid;position:relative}.farming-browser-row:hover,.farming-browser-row.active{color:#30372f;background:#1f23280e}.farming-browser-row:focus-visible{outline-offset:-2px;outline:2px solid #52638747}.farming-browser-status{background:#9aa198;border-radius:999px;width:7px;height:7px}.farming-browser-status.running{background:#2da44e}.farming-browser-status.failed{background:#cf4a4a}.farming-browser-status.starting,.farming-browser-status.stopping{background:#bf8700}.farming-browser-row-copy{gap:0;min-width:0;display:grid}.farming-browser-row-name,.farming-browser-row-detail{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.farming-browser-row-name{color:inherit;font-size:13px;font-weight:450}.farming-browser-row-detail{color:#81887f;font-size:11px;line-height:14px}.farming-browser-row-copy input{box-sizing:border-box;color:#343a34;width:100%;min-width:0;height:22px;font:inherit;background:#fff;border:1px solid #5263874d;border-radius:4px;outline:0;padding:0 5px}.farming-browser-row-actions{opacity:0;pointer-events:none;align-items:center;display:flex}.farming-browser-row:hover .farming-browser-row-actions,.farming-browser-row:focus-within .farming-browser-row-actions{opacity:1;pointer-events:auto}.farming-browser-empty{color:#7a8178;cursor:pointer;min-height:28px;font:inherit;text-align:left;background:0 0;border:0;border-radius:5px;align-items:center;gap:6px;margin:0 4px 2px 0;padding:3px 7px;font-size:12px;display:inline-flex}.farming-browser-empty svg{fill:currentColor;width:13px;height:13px}.farming-browser-empty:hover,.farming-browser-empty:focus-visible{color:#4e564d;background:#1f23280d;outline:0}.farming-browser-viewer{color:#343a34;background:#fff;grid-template-rows:auto minmax(0,1fr) auto;width:100%;height:100%;min-height:0;font-family:-apple-system,BlinkMacSystemFont,SF Pro Text,Segoe UI,sans-serif;display:grid}.farming-browser-toolbar{background:#f6f7f3;border-bottom:1px solid #24292f14;align-items:center;gap:4px;min-height:40px;padding:4px 8px;display:flex}.farming-browser-toolbar button,.farming-browser-placeholder button{color:#5f675e;cursor:pointer;min-height:28px;font:inherit;background:0 0;border:0;border-radius:5px;justify-content:center;align-items:center;gap:5px;padding:0 8px;font-size:12px;font-weight:500;display:inline-flex}.farming-browser-toolbar button:hover:not(:disabled),.farming-browser-toolbar button:focus-visible,.farming-browser-placeholder button:hover,.farming-browser-placeholder button:focus-visible{color:#30372f;background:#1f23280f;outline:0}.farming-browser-toolbar button:disabled{cursor:default;opacity:.38}.farming-browser-toolbar button svg,.farming-browser-placeholder button svg{fill:currentColor;width:14px;height:14px}.farming-browser-toolbar-icon{flex:0 0 28px;width:28px;padding:0!important}.farming-browser-toolbar form{flex:auto;min-width:90px;display:flex}.farming-browser-toolbar input{box-sizing:border-box;color:#343a34;width:100%;min-width:0;height:28px;font:inherit;background:#ffffffbd;border:1px solid #52638729;border-radius:6px;outline:0;padding:0 9px;font-size:12px}.farming-browser-toolbar input:focus{background:#fff;border-color:#5263875c}.farming-browser-connection{background:#9aa198;border-radius:999px;flex:0 0 7px;width:7px;height:7px;margin:0 3px}.farming-browser-connection.connected{background:#2da44e}.farming-browser-viewport{background:#e9ebe6;justify-content:center;align-items:center;min-height:0;display:flex;position:relative;overflow:hidden}.farming-browser-viewport canvas{cursor:default;background:#fff;outline:none;max-width:100%;max-height:100%;display:block;box-shadow:0 1px 6px #1f23281a}.farming-browser-text-input-proxy{opacity:.01;pointer-events:none;resize:none;border:0;width:1px;height:1px;padding:0;font-size:16px;position:absolute;bottom:0;left:50%}.farming-browser-placeholder{color:#747b72;text-align:center;justify-items:center;gap:7px;max-width:420px;padding:24px;display:grid}.farming-browser-placeholder strong{color:#4e564d;font-size:14px;font-weight:600}.farming-browser-placeholder p{margin:0;font-size:13px;line-height:19px}.farming-browser-placeholder button{background:#f6f7f3;border:1px solid #5263872e;margin-top:3px}.farming-browser-viewer-error{color:#b4232d;background:#cf222e14;padding:6px 10px;font-size:12px;line-height:16px}body.code-mode[data-appearance=dark] .farming-browser-section,body.code-mode[data-appearance=dark] .farming-browser-row{color:#c9d1d9}body.code-mode[data-appearance=dark] .farming-browser-section>header{color:#9da7b1;background:#0d1117}body.code-mode[data-appearance=dark] .farming-browser-section-toggle:hover,body.code-mode[data-appearance=dark] .farming-browser-section-toggle:focus-visible,body.code-mode[data-appearance=dark] .farming-browser-new:hover,body.code-mode[data-appearance=dark] .farming-browser-new:focus-visible,body.code-mode[data-appearance=dark] .farming-browser-row-actions button:hover,body.code-mode[data-appearance=dark] .farming-browser-row-actions button:focus-visible{color:#f0f6fc}body.code-mode[data-appearance=dark] .farming-browser-row:hover,body.code-mode[data-appearance=dark] .farming-browser-row.active,body.code-mode[data-appearance=dark] .farming-browser-empty:hover,body.code-mode[data-appearance=dark] .farming-browser-empty:focus-visible{background:#b1bac41a}body.code-mode[data-appearance=dark] .farming-browser-row-detail,body.code-mode[data-appearance=dark] .farming-browser-empty{color:#8b949e}body.code-mode[data-appearance=dark] .farming-browser-row-copy input,body.code-mode[data-appearance=dark] .farming-browser-toolbar input{color:#e6edf3;background:#161b22;border-color:#30363d}body.code-mode[data-appearance=dark] .farming-browser-viewer{color:#c9d1d9;background:#0d1117}body.code-mode[data-appearance=dark] .farming-browser-toolbar{background:#161b22;border-color:#21262d}body.code-mode[data-appearance=dark] .farming-browser-toolbar button,body.code-mode[data-appearance=dark] .farming-browser-placeholder button{color:#9da7b1}body.code-mode[data-appearance=dark] .farming-browser-toolbar button:hover:not(:disabled),body.code-mode[data-appearance=dark] .farming-browser-toolbar button:focus-visible,body.code-mode[data-appearance=dark] .farming-browser-placeholder button:hover,body.code-mode[data-appearance=dark] .farming-browser-placeholder button:focus-visible{color:#f0f6fc;background:#21262d}body.code-mode[data-appearance=dark] .farming-browser-viewport{background:#010409}body.code-mode[data-appearance=dark] .farming-browser-placeholder{color:#8b949e}body.code-mode[data-appearance=dark] .farming-browser-placeholder strong{color:#c9d1d9}body.code-mode[data-appearance=dark] .farming-browser-placeholder button{background:#161b22;border-color:#30363d}@media (width<=700px){.farming-browser-toolbar{padding-inline:5px}.farming-browser-toolbar-action span{display:none}.farming-browser-copy-link{display:none!important}}
1
+ .xterm{cursor:text;-webkit-user-select:none;user-select:none;position:relative}.xterm.focus,.xterm:focus{outline:none}.xterm .xterm-helpers{z-index:5;position:absolute;top:0}.xterm .xterm-helper-textarea{opacity:0;z-index:-5;white-space:nowrap;resize:none;border:0;width:0;height:0;margin:0;padding:0;position:absolute;top:0;left:-9999em;overflow:hidden}.xterm .composition-view{color:#fff;white-space:nowrap;z-index:1;background:#000;display:none;position:absolute}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{cursor:default;background-color:#000;position:absolute;inset:0;overflow-y:scroll}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;top:0;left:0}.xterm-char-measure-element{visibility:hidden;line-height:normal;display:inline-block;position:absolute;top:0;left:-9999em}.xterm.enable-mouse-events{cursor:default}.xterm.xterm-cursor-pointer,.xterm .xterm-cursor-pointer{cursor:pointer}.xterm.column-select.focus{cursor:crosshair}.xterm .xterm-accessibility:not(.debug),.xterm .xterm-message{z-index:10;color:#0000;pointer-events:none;position:absolute;inset:0}.xterm .xterm-accessibility-tree:not(.debug) ::selection{color:#0000}.xterm .xterm-accessibility-tree{-webkit-user-select:text;user-select:text;white-space:pre;font-family:monospace}.xterm .xterm-accessibility-tree>div{transform-origin:0;width:fit-content}.xterm .live-region{width:1px;height:1px;position:absolute;left:-9999px;overflow:hidden}.xterm-dim{opacity:1!important}.xterm-underline-1{text-decoration:underline}.xterm-underline-2{-webkit-text-decoration:underline double;text-decoration:underline double}.xterm-underline-3{-webkit-text-decoration:underline wavy;text-decoration:underline wavy}.xterm-underline-4{-webkit-text-decoration:underline dotted;text-decoration:underline dotted}.xterm-underline-5{-webkit-text-decoration:underline dashed;text-decoration:underline dashed}.xterm-overline{text-decoration:overline}.xterm-overline.xterm-underline-1{text-decoration:underline overline}.xterm-overline.xterm-underline-2{-webkit-text-decoration:overline double underline;text-decoration:overline double underline}.xterm-overline.xterm-underline-3{-webkit-text-decoration:overline wavy underline;text-decoration:overline wavy underline}.xterm-overline.xterm-underline-4{-webkit-text-decoration:overline dotted underline;text-decoration:overline dotted underline}.xterm-overline.xterm-underline-5{-webkit-text-decoration:overline dashed underline;text-decoration:overline dashed underline}.xterm-strikethrough{text-decoration:line-through}.xterm-screen .xterm-decoration-container .xterm-decoration{z-index:6;position:absolute}.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer{z-index:7}.xterm-decoration-overview-ruler{z-index:8;pointer-events:none;position:absolute;top:0;right:0}.xterm-decoration-top{z-index:2;position:relative}.xterm .xterm-scrollable-element>.scrollbar{cursor:default}.xterm .xterm-scrollable-element>.scrollbar>.scra{cursor:pointer;font-size:11px!important}.xterm .xterm-scrollable-element>.visible{opacity:1;z-index:11;background:0 0;transition:opacity .1s linear}.xterm .xterm-scrollable-element>.invisible{opacity:0;pointer-events:none}.xterm .xterm-scrollable-element>.invisible.fade{transition:opacity .8s linear}.xterm .xterm-scrollable-element>.shadow{display:none;position:absolute}.xterm .xterm-scrollable-element>.shadow.top{width:100%;height:3px;box-shadow:var(--vscode-scrollbar-shadow,#000) 0 6px 6px -6px inset;display:block;top:0;left:3px}.xterm .xterm-scrollable-element>.shadow.left{width:3px;height:100%;box-shadow:var(--vscode-scrollbar-shadow,#000) 6px 0 6px -6px inset;display:block;top:3px;left:0}.xterm .xterm-scrollable-element>.shadow.top-left-corner{width:3px;height:3px;display:block;top:0;left:0}.xterm .xterm-scrollable-element>.shadow.top.left{box-shadow:var(--vscode-scrollbar-shadow,#000) 6px 0 6px -6px inset}.farming-browser-section{color:#343a34;min-width:0;margin-top:2px;margin-left:14px}.code-settings-browser-row .code-settings-row-copy small{text-overflow:clip;white-space:normal;overflow:visible}.code-settings-browser-unavailable{color:#747b72;white-space:nowrap;font-size:12px;line-height:18px}.farming-browser-section>header{min-height:var(--code-files-header-height,25px);color:#5f675e;letter-spacing:0;text-transform:uppercase;background:#f6f7f3;align-items:center;gap:8px;padding:2px 6px 1px 0;font-size:13px;font-weight:500;display:flex}.farming-browser-section-toggle{min-width:0;min-height:22px;color:inherit;cursor:pointer;font:inherit;letter-spacing:inherit;text-align:left;text-transform:inherit;background:0 0;border:0;border-radius:4px;flex:0 auto;align-items:center;gap:5px;padding:0 4px 0 2px;display:inline-flex}.farming-browser-section-toggle:hover,.farming-browser-section-toggle:focus-visible{color:#30372f;outline:0}.farming-browser-section-chevron{color:#6b7368;flex:0 0 14px;justify-content:center;align-items:center;width:14px;height:14px;display:inline-flex}.farming-browser-section-chevron svg,.farming-browser-new svg,.farming-browser-row-actions svg{fill:currentColor;width:14px;height:14px;display:block}.farming-browser-section-toggle small{color:#8a9188;font-size:11px;font-weight:450}.farming-browser-new,.farming-browser-row-actions button{color:#6b7368;cursor:pointer;background:0 0;border:0;border-radius:4px;flex:0 0 22px;justify-content:center;align-items:center;width:22px;height:22px;padding:0;display:inline-flex}.farming-browser-new:hover,.farming-browser-new:focus-visible,.farming-browser-row-actions button:hover,.farming-browser-row-actions button:focus-visible{color:#30372f;background:#1f23280d;outline:0}.farming-browser-new:disabled,.farming-browser-row-actions button:disabled{cursor:default;opacity:.38}.farming-browser-list{min-width:0}.farming-browser-row{color:#535a52;cursor:default;border-radius:5px;grid-template-columns:8px minmax(0,1fr) auto;align-items:center;gap:7px;min-width:0;min-height:32px;margin:0 4px 0 0;padding:3px 4px 3px 5px;font-size:13px;line-height:16px;display:grid;position:relative}.farming-browser-row:hover,.farming-browser-row.active{color:#30372f;background:#1f23280e}.farming-browser-row:focus-visible{outline-offset:-2px;outline:2px solid #52638747}.farming-browser-status{background:#9aa198;border-radius:999px;width:7px;height:7px}.farming-browser-status.running{background:#2da44e}.farming-browser-status.failed{background:#cf4a4a}.farming-browser-status.starting,.farming-browser-status.stopping{background:#bf8700}.farming-browser-row-copy{gap:0;min-width:0;display:grid}.farming-browser-row-name,.farming-browser-row-detail{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.farming-browser-row-name{color:inherit;font-size:13px;font-weight:450}.farming-browser-row-detail{color:#81887f;font-size:11px;line-height:14px}.farming-browser-row-copy input{box-sizing:border-box;color:#343a34;width:100%;min-width:0;height:22px;font:inherit;background:#fff;border:1px solid #5263874d;border-radius:4px;outline:0;padding:0 5px}.farming-browser-row-actions{opacity:0;pointer-events:none;align-items:center;display:flex}.farming-browser-row:hover .farming-browser-row-actions,.farming-browser-row:focus-within .farming-browser-row-actions{opacity:1;pointer-events:auto}.farming-browser-empty{color:#7a8178;cursor:pointer;min-height:28px;font:inherit;text-align:left;background:0 0;border:0;border-radius:5px;align-items:center;gap:6px;margin:0 4px 2px 0;padding:3px 7px;font-size:12px;display:inline-flex}.farming-browser-empty svg{fill:currentColor;width:13px;height:13px}.farming-browser-empty:hover,.farming-browser-empty:focus-visible{color:#4e564d;background:#1f23280d;outline:0}.farming-browser-viewer{color:#343a34;background:#fff;grid-template-rows:auto minmax(0,1fr) auto;width:100%;height:100%;min-height:0;font-family:-apple-system,BlinkMacSystemFont,SF Pro Text,Segoe UI,sans-serif;display:grid}.farming-browser-toolbar{background:#fff;border-bottom:1px solid #24292f14;align-items:center;gap:2px;min-height:38px;padding:4px 6px;display:flex}.farming-browser-toolbar button,.farming-browser-placeholder button{color:#5f675e;cursor:pointer;min-height:28px;font:inherit;background:0 0;border:0;border-radius:5px;justify-content:center;align-items:center;gap:5px;padding:0 8px;font-size:12px;font-weight:500;display:inline-flex}.farming-browser-toolbar button:hover:not(:disabled),.farming-browser-toolbar button:focus-visible,.farming-browser-placeholder button:hover,.farming-browser-placeholder button:focus-visible{color:#30372f;background:#1f23280f;outline:0}.farming-browser-toolbar button:disabled{cursor:default;opacity:.38}.farming-browser-toolbar button svg,.farming-browser-placeholder button svg{fill:currentColor;width:14px;height:14px}.farming-browser-toolbar-icon{flex:0 0 28px;width:28px;padding:0!important}.farming-browser-toolbar .farming-browser-agent-return{color:#454d44}.farming-browser-toolbar-separator{background:#24292f1a;flex:0 0 1px;width:1px;height:18px;margin:0 4px 0 2px}.farming-browser-toolbar form{flex:auto;min-width:90px;margin-left:3px;display:flex;position:relative}.farming-browser-toolbar input{box-sizing:border-box;color:#343a34;width:100%;min-width:0;height:28px;font:inherit;background:#f1f3ef;border:1px solid #0000;border-radius:7px;outline:0;padding:0 25px 0 10px;font-size:12px}.farming-browser-toolbar input:focus{background:#fff;border-color:#5263875c}.farming-browser-connection{background:#9aa198;border-radius:999px;flex:0 0 7px;width:7px;height:7px;margin-top:-3.5px;position:absolute;top:50%;right:9px}.farming-browser-connection.connected{background:#2da44e}.farming-browser-connection.navigating{background:#d29922}.farming-browser-viewport{background:#fff;justify-content:center;align-items:center;min-height:0;display:flex;position:relative;overflow:hidden}.farming-browser-viewport canvas{cursor:default;background:#fff;outline:none;max-width:100%;max-height:100%;display:block}.farming-browser-more-wrap{flex:none;position:relative}.farming-browser-more-menu{z-index:30;background:#fff;border:1px solid #d8dbd2;border-radius:8px;width:168px;padding:5px;position:absolute;top:calc(100% + 5px);right:0;box-shadow:0 14px 36px #1f232829}.farming-browser-more-menu button{justify-content:flex-start;width:100%;min-height:30px;padding:0 9px}.farming-browser-text-input-proxy{opacity:.01;pointer-events:none;resize:none;border:0;width:1px;height:1px;padding:0;font-size:16px;position:absolute;bottom:0;left:50%}.farming-browser-placeholder{color:#747b72;text-align:center;justify-items:center;gap:7px;max-width:420px;padding:24px;display:grid}.farming-browser-placeholder strong{color:#4e564d;font-size:14px;font-weight:600}.farming-browser-placeholder p{margin:0;font-size:13px;line-height:19px}.farming-browser-placeholder button{background:#f6f7f3;border:1px solid #5263872e;margin-top:3px}.farming-browser-viewer-error{color:#b4232d;background:#cf222e14;padding:6px 10px;font-size:12px;line-height:16px}body.code-mode[data-appearance=dark] .farming-browser-section,body.code-mode[data-appearance=dark] .farming-browser-row{color:#c9d1d9}body.code-mode[data-appearance=dark] .farming-browser-section>header{color:#9da7b1;background:#0d1117}body.code-mode[data-appearance=dark] .farming-browser-section-toggle:hover,body.code-mode[data-appearance=dark] .farming-browser-section-toggle:focus-visible,body.code-mode[data-appearance=dark] .farming-browser-new:hover,body.code-mode[data-appearance=dark] .farming-browser-new:focus-visible,body.code-mode[data-appearance=dark] .farming-browser-row-actions button:hover,body.code-mode[data-appearance=dark] .farming-browser-row-actions button:focus-visible{color:#f0f6fc}body.code-mode[data-appearance=dark] .farming-browser-row:hover,body.code-mode[data-appearance=dark] .farming-browser-row.active,body.code-mode[data-appearance=dark] .farming-browser-empty:hover,body.code-mode[data-appearance=dark] .farming-browser-empty:focus-visible{background:#b1bac41a}body.code-mode[data-appearance=dark] .farming-browser-row-detail,body.code-mode[data-appearance=dark] .farming-browser-empty{color:#8b949e}body.code-mode[data-appearance=dark] .farming-browser-row-copy input,body.code-mode[data-appearance=dark] .farming-browser-toolbar input{color:#e6edf3;background:#161b22;border-color:#30363d}body.code-mode[data-appearance=dark] .farming-browser-viewer{color:#c9d1d9;background:#0d1117}body.code-mode[data-appearance=dark] .farming-browser-toolbar{background:#0d1117;border-color:#21262d}body.code-mode[data-appearance=dark] .farming-browser-toolbar-separator{background:#30363d}body.code-mode[data-appearance=dark] .farming-browser-toolbar button,body.code-mode[data-appearance=dark] .farming-browser-placeholder button{color:#9da7b1}body.code-mode[data-appearance=dark] .farming-browser-toolbar button:hover:not(:disabled),body.code-mode[data-appearance=dark] .farming-browser-toolbar button:focus-visible,body.code-mode[data-appearance=dark] .farming-browser-placeholder button:hover,body.code-mode[data-appearance=dark] .farming-browser-placeholder button:focus-visible{color:#f0f6fc;background:#21262d}body.code-mode[data-appearance=dark] .farming-browser-viewport{background:#010409}body.code-mode[data-appearance=dark] .farming-browser-more-menu{background:#161b22;border-color:#30363d}body.code-mode[data-appearance=dark] .farming-browser-placeholder{color:#8b949e}body.code-mode[data-appearance=dark] .farming-browser-placeholder strong{color:#c9d1d9}body.code-mode[data-appearance=dark] .farming-browser-placeholder button{background:#161b22;border-color:#30363d}@media (width<=700px){.farming-browser-toolbar{padding-inline:5px}.farming-browser-toolbar form{margin-left:1px}}