farming-code 2.2.19 → 2.2.20

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/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-DQdtPfCk.js"></script>
18
+ <script type="module" crossorigin src="/farming/assets/index-DuMjesL2.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">
@@ -55,6 +55,9 @@ let billingRequestSequence = 0;
55
55
  let billingAbortController = null;
56
56
  let billingRefreshTimer = null;
57
57
  let billingLiveDayRefreshTimer = null;
58
+ let crtTokenRateRefreshTimer = null;
59
+ let crtTokenRateFirstLoadTimer = null;
60
+ let crtTokenRateAbortController = null;
58
61
  let billingCanvasFrame = null;
59
62
  let billingMode = 'days';
60
63
  let billingSelectedDate = '';
@@ -116,8 +119,10 @@ const CRT_AGENT_GRID_GAP = 15;
116
119
  const CRT_AGENT_GRID_PADDING = 20;
117
120
  const CRT_SEARCH_DEBOUNCE_MS = 180;
118
121
  const CRT_SEARCH_RESULT_LIMIT = 100;
119
- const CRT_BILLING_REFRESH_MS = 30_000;
122
+ const CRT_BILLING_REFRESH_MS = 15_000;
120
123
  const CRT_BILLING_LIVE_DAY_REFRESH_MS = 5_000;
124
+ const CRT_TOKEN_RATE_REFRESH_MS = 60_000;
125
+ const CRT_TOKEN_RATE_FIRST_LOAD_MS = 1_500;
121
126
  const CRT_BILLING_DAY_DETAIL_CACHE_MS = 30_000;
122
127
  const CRT_BILLING_TOTAL_ANIMATION_MS = 900;
123
128
  const CRT_BILLING_DAY_DETAIL_RETRY_MS = 750;
@@ -3159,6 +3164,7 @@ function setCrtMainView(view) {
3159
3164
  if (historySidebarItem) historySidebarItem.classList.toggle('active', crtMainView === 'history');
3160
3165
  if (searchSidebarItem) searchSidebarItem.classList.toggle('active', crtMainView === 'search');
3161
3166
  if (billingSidebarItem) billingSidebarItem.classList.toggle('active', crtMainView === 'billing');
3167
+ if (previousView !== 'agents' && crtMainView === 'agents') checkMainAgentStatus();
3162
3168
  }
3163
3169
 
3164
3170
  function getCrtSearchResults() {
@@ -4006,6 +4012,30 @@ function scrollCrtBillingSelectedDayIntoView() {
4006
4012
  else if (right > scroll.scrollLeft + scroll.clientWidth) scroll.scrollLeft = right - scroll.clientWidth;
4007
4013
  }
4008
4014
 
4015
+ function crtBillingDayArrowTargetIndex(points, index, key) {
4016
+ if (!Array.isArray(points) || index < 0 || index >= points.length) return -1;
4017
+ const firstDate = parseCrtBillingDate(points[0] && points[0].date);
4018
+ const leadingDays = firstDate ? (firstDate.getDay() + 6) % 7 : 0;
4019
+ const position = leadingDays + index;
4020
+ const weekdayRow = position % 7;
4021
+ let targetPosition = position;
4022
+ if (key === 'ArrowUp') {
4023
+ if (weekdayRow === 0) return -1;
4024
+ targetPosition -= 1;
4025
+ } else if (key === 'ArrowDown') {
4026
+ if (weekdayRow === 6) return -1;
4027
+ targetPosition += 1;
4028
+ } else if (key === 'ArrowLeft') {
4029
+ targetPosition -= 7;
4030
+ } else if (key === 'ArrowRight') {
4031
+ targetPosition += 7;
4032
+ } else {
4033
+ return -1;
4034
+ }
4035
+ const targetIndex = targetPosition - leadingDays;
4036
+ return targetIndex >= 0 && targetIndex < points.length ? targetIndex : -1;
4037
+ }
4038
+
4009
4039
  function selectCrtBillingDayByArrow(key) {
4010
4040
  if (crtMainView !== 'billing' || billingMode !== 'days') return false;
4011
4041
  const points = billingSummary && billingSummary.daily && Array.isArray(billingSummary.daily.points)
@@ -4014,8 +4044,8 @@ function selectCrtBillingDayByArrow(key) {
4014
4044
  if (points.length === 0) return false;
4015
4045
  let index = points.findIndex(point => point.date === billingSelectedDate);
4016
4046
  if (index < 0) index = points.length - 1;
4017
- const delta = key === 'ArrowLeft' ? -1 : key === 'ArrowRight' ? 1 : key === 'ArrowUp' ? -7 : 7;
4018
- const nextIndex = Math.max(0, Math.min(points.length - 1, index + delta));
4047
+ const nextIndex = crtBillingDayArrowTargetIndex(points, index, key);
4048
+ if (nextIndex < 0) return false;
4019
4049
  return selectCrtBillingDay(points[nextIndex].date, { focus: true });
4020
4050
  }
4021
4051
 
@@ -4156,11 +4186,35 @@ function setCrtBillingMode(mode) {
4156
4186
  }
4157
4187
  const status = document.getElementById('billing-status');
4158
4188
  if (status && billingSummary && !billingLoading && !billingError) {
4159
- status.textContent = billingMode === 'days' ? 'HISTORY READY' : 'SIGNAL LOCKED';
4189
+ status.textContent = crtBillingStatusText();
4160
4190
  }
4161
4191
  if (billingMode === 'live') window.requestAnimationFrame(() => drawCrtBillingScope());
4162
4192
  }
4163
4193
 
4194
+ function selectCrtBillingMode(mode) {
4195
+ setCrtBillingMode(mode);
4196
+ const selectedTab = document.getElementById(
4197
+ billingMode === 'live' ? 'billing-live-tab' : 'billing-days-tab',
4198
+ );
4199
+ if (selectedTab) setCrtNavigationSelection(selectedTab);
4200
+ if (billingMode === 'live' && !billingLoading) void loadCrtBilling();
4201
+ }
4202
+
4203
+ function crtBillingTimeline(summary = billingSummary) {
4204
+ return summary && summary.liveTimeline || summary && summary.timeline || null;
4205
+ }
4206
+
4207
+ function crtBillingStatusText(summary = billingSummary) {
4208
+ if (billingMode === 'days') return 'HISTORY READY';
4209
+ const sampledAt = Number(summary && summary.sampledAt);
4210
+ if (!Number.isFinite(sampledAt) || sampledAt <= 0) return 'LIVE';
4211
+ const sampled = new Date(sampledAt);
4212
+ const time = [sampled.getHours(), sampled.getMinutes(), sampled.getSeconds()]
4213
+ .map(value => String(value).padStart(2, '0'))
4214
+ .join(':');
4215
+ return `LIVE ${time}`;
4216
+ }
4217
+
4164
4218
  function formatCrtBillingWindow(windowMinutes) {
4165
4219
  const minutes = Number(windowMinutes);
4166
4220
  if (!Number.isFinite(minutes) || minutes <= 0) return 'WINDOW';
@@ -4214,6 +4268,13 @@ function crtBillingCurrentRate(summary = billingSummary) {
4214
4268
  return hasRate ? total : null;
4215
4269
  }
4216
4270
 
4271
+ function renderCrtTopBarTokenRate(summary = billingSummary) {
4272
+ const tokensPerMinute = document.getElementById('tokens-per-minute');
4273
+ if (tokensPerMinute) {
4274
+ tokensPerMinute.textContent = formatCrtTokenRate(crtBillingCurrentRate(summary));
4275
+ }
4276
+ }
4277
+
4217
4278
  function appendCrtBillingMessage(container, text, isError = false) {
4218
4279
  const message = document.createElement('div');
4219
4280
  message.className = `billing-message${isError ? ' is-error' : ''}`;
@@ -4314,7 +4375,7 @@ function drawCrtBillingScope(summary = billingSummary) {
4314
4375
  context.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
4315
4376
  context.clearRect(0, 0, rect.width, rect.height);
4316
4377
 
4317
- const timeline = summary && summary.timeline;
4378
+ const timeline = crtBillingTimeline(summary);
4318
4379
  const points = timeline && Array.isArray(timeline.points) ? timeline.points : [];
4319
4380
  const values = points.map(point => Math.max(0, Number(point.tokensPerMinute) || 0));
4320
4381
  const providerNames = points.length > 0 ? Object.keys(points[0].providers || {}) : [];
@@ -4392,7 +4453,7 @@ function renderCrtBilling() {
4392
4453
  const status = document.getElementById('billing-status');
4393
4454
  const refresh = document.getElementById('billing-refresh');
4394
4455
  const empty = document.getElementById('billing-scope-empty');
4395
- const timeline = billingSummary && billingSummary.timeline;
4456
+ const timeline = crtBillingTimeline();
4396
4457
  const hasSignal = Boolean(timeline && Number(timeline.totalTokens) > 0);
4397
4458
  if (status) {
4398
4459
  status.classList.toggle('is-busy', billingLoading);
@@ -4402,7 +4463,7 @@ function renderCrtBilling() {
4402
4463
  : billingLoading
4403
4464
  ? (billingSummary ? 'REFRESHING' : 'SCANNING LOGS')
4404
4465
  : billingSummary
4405
- ? (billingMode === 'days' ? 'HISTORY READY' : 'SIGNAL LOCKED')
4466
+ ? crtBillingStatusText()
4406
4467
  : 'STANDBY';
4407
4468
  }
4408
4469
  if (refresh) refresh.disabled = billingLoading;
@@ -4449,13 +4510,18 @@ async function loadCrtBilling({ fresh = false } = {}) {
4449
4510
  billingRequestSequence += 1;
4450
4511
  const requestSequence = billingRequestSequence;
4451
4512
  if (billingAbortController) billingAbortController.abort();
4513
+ if (crtTokenRateAbortController) {
4514
+ crtTokenRateAbortController.abort();
4515
+ crtTokenRateAbortController = null;
4516
+ }
4452
4517
  const controller = new window.AbortController();
4453
4518
  billingAbortController = controller;
4454
4519
  billingLoading = true;
4455
4520
  billingError = '';
4456
4521
  renderCrtBilling();
4457
4522
  try {
4458
- const response = await fetch(farmingApiPath(`/usage${fresh ? '?fresh=1' : ''}`), {
4523
+ const query = fresh ? '?fresh=1' : billingMode === 'live' ? '?live=1' : '';
4524
+ const response = await fetch(farmingApiPath(`/usage${query}`), {
4459
4525
  signal: controller.signal,
4460
4526
  cache: 'no-store',
4461
4527
  });
@@ -4463,6 +4529,7 @@ async function loadCrtBilling({ fresh = false } = {}) {
4463
4529
  if (!response.ok || !data || !data.usage) throw new Error(data && data.error ? data.error : `Usage request failed (${response.status})`);
4464
4530
  if (requestSequence !== billingRequestSequence) return;
4465
4531
  billingSummary = data.usage;
4532
+ renderCrtTopBarTokenRate();
4466
4533
  } catch (error) {
4467
4534
  if (controller.signal.aborted || requestSequence !== billingRequestSequence) return;
4468
4535
  billingError = error instanceof Error ? error.message : 'Failed to load token telemetry';
@@ -4481,6 +4548,58 @@ async function loadCrtBilling({ fresh = false } = {}) {
4481
4548
  }
4482
4549
  }
4483
4550
 
4551
+ async function loadCrtTopBarTokenRate() {
4552
+ if (billingLoading || crtTokenRateAbortController) return;
4553
+ const controller = new window.AbortController();
4554
+ crtTokenRateAbortController = controller;
4555
+ try {
4556
+ const response = await fetch(farmingApiPath('/usage'), {
4557
+ signal: controller.signal,
4558
+ cache: 'no-store',
4559
+ });
4560
+ const data = await response.json().catch(() => null);
4561
+ if (controller.signal.aborted) return;
4562
+ if (!response.ok || !data || !data.usage) {
4563
+ throw new Error(data && data.error ? data.error : `Usage request failed (${response.status})`);
4564
+ }
4565
+ renderCrtTopBarTokenRate(data.usage);
4566
+ } catch {
4567
+ if (!controller.signal.aborted) renderCrtTopBarTokenRate(null);
4568
+ } finally {
4569
+ if (crtTokenRateAbortController === controller) crtTokenRateAbortController = null;
4570
+ }
4571
+ }
4572
+
4573
+ function stopCrtTopBarTokenRateRefresh({ abort = false } = {}) {
4574
+ if (crtTokenRateFirstLoadTimer !== null) {
4575
+ clearTimeout(crtTokenRateFirstLoadTimer);
4576
+ crtTokenRateFirstLoadTimer = null;
4577
+ }
4578
+ if (crtTokenRateRefreshTimer !== null) {
4579
+ clearInterval(crtTokenRateRefreshTimer);
4580
+ crtTokenRateRefreshTimer = null;
4581
+ }
4582
+ if (abort && crtTokenRateAbortController) {
4583
+ crtTokenRateAbortController.abort();
4584
+ crtTokenRateAbortController = null;
4585
+ }
4586
+ }
4587
+
4588
+ function startCrtTopBarTokenRateRefresh({ immediate = false } = {}) {
4589
+ stopCrtTopBarTokenRateRefresh();
4590
+ if (immediate) {
4591
+ void loadCrtTopBarTokenRate();
4592
+ } else {
4593
+ crtTokenRateFirstLoadTimer = setTimeout(() => {
4594
+ crtTokenRateFirstLoadTimer = null;
4595
+ if (document.visibilityState !== 'hidden') void loadCrtTopBarTokenRate();
4596
+ }, CRT_TOKEN_RATE_FIRST_LOAD_MS);
4597
+ }
4598
+ crtTokenRateRefreshTimer = setInterval(() => {
4599
+ if (document.visibilityState !== 'hidden') void loadCrtTopBarTokenRate();
4600
+ }, CRT_TOKEN_RATE_REFRESH_MS);
4601
+ }
4602
+
4484
4603
  function stopCrtBillingRefresh({ abort = false } = {}) {
4485
4604
  if (billingRefreshTimer !== null) {
4486
4605
  clearInterval(billingRefreshTimer);
@@ -5485,7 +5604,7 @@ function connect() {
5485
5604
  else scheduleCrtPreviewCardRender(agent);
5486
5605
  }
5487
5606
  } else if (data.type === 'system-stats') {
5488
- updateSystemStats(data.stats, data.uptime, data.usageRate);
5607
+ updateSystemStats(data.stats, data.uptime);
5489
5608
  } else if (data.type === 'error') {
5490
5609
  waitingForAgent = false;
5491
5610
  if (workspaceDirectoryPrompt?.kind === 'creating') {
@@ -5532,6 +5651,7 @@ function connect() {
5532
5651
  function suspendCrtPageConnection() {
5533
5652
  document.body.classList.add('page-hidden');
5534
5653
  stopCrtBillingRefresh({ abort: true });
5654
+ stopCrtTopBarTokenRateRefresh({ abort: true });
5535
5655
  if (wsReconnectTimer) {
5536
5656
  clearTimeout(wsReconnectTimer);
5537
5657
  wsReconnectTimer = null;
@@ -5545,6 +5665,7 @@ function resumeCrtPageConnection() {
5545
5665
  if (document.visibilityState === 'hidden') return;
5546
5666
  document.body.classList.remove('page-hidden');
5547
5667
  connect();
5668
+ startCrtTopBarTokenRateRefresh({ immediate: true });
5548
5669
  if (crtMainView === 'billing') {
5549
5670
  startCrtBillingRefresh();
5550
5671
  void loadCrtBilling();
@@ -5554,15 +5675,33 @@ function resumeCrtPageConnection() {
5554
5675
  function checkMainAgentStatus() {
5555
5676
  if (!state) return;
5556
5677
 
5557
- const mainAgent = state.mainAgentId
5558
- ? state.agents.find(a => a.id === state.mainAgentId)
5559
- : null;
5560
-
5561
- if (!state.mainAgentId || !isCrtLiveAgent(mainAgent)) {
5678
+ const inputDialog = document.getElementById('input-dialog');
5679
+ const action = getCrtMainAgentDialogAction({
5680
+ currentState: state,
5681
+ mainView: crtMainView,
5682
+ dialogActive: Boolean(inputDialog && inputDialog.classList.contains('active')),
5683
+ pendingMainAgent: pendingMainAgentLaunch,
5684
+ });
5685
+ if (action === 'hide') {
5686
+ hideInputDialog();
5687
+ } else if (action === 'show') {
5562
5688
  showInputDialog();
5563
5689
  }
5564
5690
  }
5565
5691
 
5692
+ function getCrtMainAgentDialogAction({
5693
+ currentState,
5694
+ mainView = 'agents',
5695
+ dialogActive = false,
5696
+ pendingMainAgent = false,
5697
+ } = {}) {
5698
+ if (!needsMainAgent(currentState)) {
5699
+ return dialogActive && pendingMainAgent ? 'hide' : 'none';
5700
+ }
5701
+ if (mainView !== 'agents' || dialogActive) return 'none';
5702
+ return 'show';
5703
+ }
5704
+
5566
5705
  function formatSystemClock(timestamp, timeZone) {
5567
5706
  if (!Number.isFinite(timestamp)) return '--';
5568
5707
  try {
@@ -5582,21 +5721,22 @@ function formatSystemClock(timestamp, timeZone) {
5582
5721
  }
5583
5722
 
5584
5723
  function formatCrtTokenRate(value) {
5724
+ if (value === null || value === undefined || value === '') return '--';
5585
5725
  const rate = Number(value);
5586
5726
  if (!Number.isFinite(rate) || rate < 0) return '--';
5587
5727
  const rounded = rate < 10 ? Math.round(rate * 10) / 10 : Math.round(rate);
5588
5728
  if (rounded >= 1_000_000) {
5589
5729
  const compact = rounded / 1_000_000;
5590
- return `~${compact >= 10 ? Math.round(compact) : Math.round(compact * 10) / 10}M`;
5730
+ return `${compact >= 10 ? Math.round(compact) : Math.round(compact * 10) / 10}M`;
5591
5731
  }
5592
5732
  if (rounded >= 1_000) {
5593
5733
  const compact = rounded / 1_000;
5594
- return `~${compact >= 10 ? Math.round(compact) : Math.round(compact * 10) / 10}K`;
5734
+ return `${compact >= 10 ? Math.round(compact) : Math.round(compact * 10) / 10}K`;
5595
5735
  }
5596
- return `~${rounded}`;
5736
+ return String(rounded);
5597
5737
  }
5598
5738
 
5599
- function updateSystemStats(stats, uptime, usageRate) {
5739
+ function updateSystemStats(stats, uptime) {
5600
5740
  if (stats.cpu !== undefined) {
5601
5741
  document.getElementById('cpu-usage').textContent = stats.cpu;
5602
5742
  }
@@ -5613,11 +5753,6 @@ function updateSystemStats(stats, uptime, usageRate) {
5613
5753
  document.getElementById('system-time').textContent = formatSystemClock(stats.timestamp, stats.timeZone);
5614
5754
  }
5615
5755
 
5616
- const tokensPerMinute = document.getElementById('tokens-per-minute');
5617
- if (tokensPerMinute) {
5618
- tokensPerMinute.textContent = formatCrtTokenRate(usageRate && usageRate.estimatedTokensPerMinute);
5619
- }
5620
-
5621
5756
  if (uptime !== undefined) {
5622
5757
  const hours = Math.floor(uptime / 3600);
5623
5758
  const minutes = Math.floor((uptime % 3600) / 60);
@@ -7952,13 +8087,14 @@ if (typeof document !== 'undefined') {
7952
8087
 
7953
8088
  if (
7954
8089
  crtMainView === 'billing'
8090
+ && billingMode === 'days'
7955
8091
  && !sessionActive
7956
8092
  && !e.ctrlKey
7957
8093
  && !e.metaKey
7958
8094
  && !e.altKey
7959
8095
  && navigationArrow
7960
- && selectCrtBillingDayByArrow(e.key)
7961
8096
  ) {
8097
+ selectCrtBillingDayByArrow(e.key);
7962
8098
  e.preventDefault();
7963
8099
  return;
7964
8100
  }
@@ -8152,13 +8288,13 @@ if (typeof document !== 'undefined') {
8152
8288
  }
8153
8289
 
8154
8290
  if ((e.key === 'd' || e.key === 'D') && crtMainView === 'billing') {
8155
- setCrtBillingMode('days');
8291
+ selectCrtBillingMode('days');
8156
8292
  e.preventDefault();
8157
8293
  return;
8158
8294
  }
8159
8295
 
8160
8296
  if ((e.key === 'l' || e.key === 'L') && crtMainView === 'billing') {
8161
- setCrtBillingMode('live');
8297
+ selectCrtBillingMode('live');
8162
8298
  e.preventDefault();
8163
8299
  return;
8164
8300
  }
@@ -8329,7 +8465,9 @@ if (typeof module !== 'undefined' && module.exports) {
8329
8465
  crtAgentSessionKey,
8330
8466
  crtResumedSessionFromSource,
8331
8467
  crtDashboardStateSignature,
8468
+ crtBillingDayArrowTargetIndex,
8332
8469
  crtBillingTimelineLabels,
8470
+ crtBillingTimeline,
8333
8471
  crtBillingCurrentRate,
8334
8472
  findDefaultNewAgentIndex,
8335
8473
  findDirectionalNavigationIndex,
@@ -8354,6 +8492,7 @@ if (typeof module !== 'undefined' && module.exports) {
8354
8492
  getCrtAgentVerticalPageTarget,
8355
8493
  getCrtLiveAgents,
8356
8494
  getCrtRegularAgents,
8495
+ getCrtMainAgentDialogAction,
8357
8496
  getCrtAgentRemovalFallback,
8358
8497
  getAgentDisplayText,
8359
8498
  getCrtPreviewCellStyle,
@@ -8398,5 +8537,6 @@ if (typeof module !== 'undefined' && module.exports) {
8398
8537
  });
8399
8538
  window.addEventListener('pagehide', suspendCrtPageConnection);
8400
8539
  window.addEventListener('pageshow', resumeCrtPageConnection);
8540
+ startCrtTopBarTokenRateRefresh();
8401
8541
  connect();
8402
8542
  }
@@ -1475,7 +1475,7 @@
1475
1475
  <div class="top-bar">
1476
1476
  <div class="top-bar-item">AGENTS: <span id="active-agents">0</span>/<span id="total-agents">0</span></div>
1477
1477
  <div class="top-bar-item" id="agent-page-item" hidden>PAGE: <span id="agent-page-status">1/1</span></div>
1478
- <div class="top-bar-item" title="Estimated terminal output tokens per minute over the last 5 minutes">TOK/MIN: <span id="tokens-per-minute">--</span></div>
1478
+ <div class="top-bar-item" title="Provider-reported tokens per minute over the last 5 minutes">TOK/MIN: <span id="tokens-per-minute">--</span></div>
1479
1479
  <div class="top-bar-item">CPU: <span id="cpu-usage">--</span>%</div>
1480
1480
  <div class="top-bar-item">MEM: <span id="mem-percentage">--</span>%</div>
1481
1481
  <div class="top-bar-item" id="focus-region" style="display: none;">Focus: <span id="focus-region-name">--</span></div>
@@ -1545,8 +1545,8 @@
1545
1545
  <h2>Billing</h2>
1546
1546
  <div class="billing-header-actions">
1547
1547
  <div class="billing-view-switch" role="tablist" aria-label="Billing view">
1548
- <button type="button" id="billing-days-tab" class="active" role="tab" aria-selected="true" data-crt-nav-key="billing:days" tabindex="-1" onclick="setCrtBillingMode('days')">[D] DAYS</button>
1549
- <button type="button" id="billing-live-tab" role="tab" aria-selected="false" data-crt-nav-key="billing:live" tabindex="-1" onclick="setCrtBillingMode('live')">[L] LIVE</button>
1548
+ <button type="button" id="billing-days-tab" class="active" role="tab" aria-selected="true" data-crt-nav-key="billing:days" tabindex="-1" onclick="selectCrtBillingMode('days')">[D] DAYS</button>
1549
+ <button type="button" id="billing-live-tab" role="tab" aria-selected="false" data-crt-nav-key="billing:live" tabindex="-1" onclick="selectCrtBillingMode('live')">[L] LIVE</button>
1550
1550
  </div>
1551
1551
  <span class="billing-status" id="billing-status">STANDBY</span>
1552
1552
  </div>
@@ -1960,13 +1960,8 @@
1960
1960
  </div>
1961
1961
  </div>
1962
1962
 
1963
- <h3 style="margin: 30px 0 15px; color: #00ff00;">Session Engine</h3>
1964
- <div id="session-engine-settings">
1965
- <div class="settings-panel">
1966
- <label style="display: block; color: #00ff00; margin-bottom: 10px;">Coding Agent Engine</label>
1967
- <div class="settings-static-value">built-in</div>
1968
- <div style="color: #888; font-size: 12px; margin-top: 8px;">Uses Farming's built-in local session runtime.</div>
1969
- </div>
1963
+ <h3 style="margin: 30px 0 15px; color: #00ff00;">Agent Permissions</h3>
1964
+ <div id="agent-permission-settings">
1970
1965
  <div class="settings-panel">
1971
1966
  <label class="crt-checkbox-label" tabindex="-1" data-crt-nav-key="settings:skip-permissions">
1972
1967
  <input type="checkbox" id="skip-permission-check-by-default" class="crt-checkbox danger">
@@ -50,7 +50,12 @@
50
50
 
51
51
  #farming-crt .billing-view-switch button:hover,
52
52
  #farming-crt .billing-view-switch button:focus-visible,
53
- #farming-crt .billing-view-switch button.crt-nav-selected,
53
+ #farming-crt .billing-view-switch button.crt-nav-selected {
54
+ color: var(--crt-phosphor-bright);
55
+ border-color: rgba(85, 245, 155, 0.72);
56
+ outline: none;
57
+ }
58
+
54
59
  #farming-crt .billing-view-switch button.active {
55
60
  color: var(--crt-background);
56
61
  background: var(--crt-phosphor-bright);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "farming-code",
3
- "version": "2.2.19",
3
+ "version": "2.2.20",
4
4
  "description": "Remote browser workspace for supervising AI coding agents",
5
5
  "main": "backend/server.js",
6
6
  "bin": {