farming-code 2.2.17 → 2.2.19

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-C8ZFKye1.js"></script>
18
+ <script type="module" crossorigin src="/farming/assets/index-DQdtPfCk.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">
@@ -3409,6 +3409,7 @@ function setupCrtSearchControls() {
3409
3409
  }
3410
3410
 
3411
3411
  function formatCrtUsageValue(value) {
3412
+ if (value === null || value === undefined || value === '') return '--';
3412
3413
  const numberValue = Number(value);
3413
3414
  if (!Number.isFinite(numberValue) || numberValue < 0) return '--';
3414
3415
  if (numberValue >= 1_000_000_000) {
@@ -4169,6 +4170,20 @@ function formatCrtBillingWindow(windowMinutes) {
4169
4170
  return `${Math.round(minutes)}M`;
4170
4171
  }
4171
4172
 
4173
+ function crtBillingTimelineLabels(timeline) {
4174
+ const windowMinutes = Number(timeline && timeline.windowMs) / 60_000;
4175
+ const windowLabel = formatCrtBillingWindow(windowMinutes);
4176
+ const midpointLabel = formatCrtBillingWindow(windowMinutes / 2);
4177
+ return {
4178
+ integral: `TOKENS · ${windowLabel}`,
4179
+ peak: `TOK/MIN · ${windowLabel}`,
4180
+ title: `TOKEN BURN // ${windowLabel}`,
4181
+ ariaLabel: `Token burn rate over the last ${windowLabel}`,
4182
+ start: `-${windowLabel}`,
4183
+ midpoint: `-${midpointLabel}`,
4184
+ };
4185
+ }
4186
+
4172
4187
  function formatCrtBillingReset(resetsAt, now = Date.now()) {
4173
4188
  const timestamp = Number(resetsAt);
4174
4189
  if (!Number.isFinite(timestamp) || timestamp <= 0) return 'RESET --';
@@ -4180,10 +4195,23 @@ function formatCrtBillingReset(resetsAt, now = Date.now()) {
4180
4195
 
4181
4196
  function crtBillingCurrentRate(summary = billingSummary) {
4182
4197
  const providers = summary && Array.isArray(summary.providers) ? summary.providers : [];
4183
- return providers.reduce((total, provider) => {
4184
- const rate = Number(provider && provider.tokenUsage && provider.tokenUsage.tokensPerMinute);
4185
- return total + (Number.isFinite(rate) ? Math.max(0, rate) : 0);
4186
- }, 0);
4198
+ let total = 0;
4199
+ let hasRate = false;
4200
+ providers.forEach((provider) => {
4201
+ const tokenUsage = provider && provider.tokenUsage;
4202
+ const rate = tokenUsage && tokenUsage.tokensPerMinute;
4203
+ if (
4204
+ tokenUsage
4205
+ && tokenUsage.available !== false
4206
+ && typeof rate === 'number'
4207
+ && Number.isFinite(rate)
4208
+ && rate >= 0
4209
+ ) {
4210
+ total += rate;
4211
+ hasRate = true;
4212
+ }
4213
+ });
4214
+ return hasRate ? total : null;
4187
4215
  }
4188
4216
 
4189
4217
  function appendCrtBillingMessage(container, text, isError = false) {
@@ -4384,11 +4412,24 @@ function renderCrtBilling() {
4384
4412
  const peakRate = document.getElementById('billing-peak-rate');
4385
4413
  const dutyCycle = document.getElementById('billing-duty-cycle');
4386
4414
  const scopeScale = document.getElementById('billing-scope-scale');
4415
+ const windowLabel = document.getElementById('billing-window-label');
4416
+ const peakLabel = document.getElementById('billing-peak-label');
4417
+ const scopeTitle = document.getElementById('billing-scope-title');
4418
+ const scope = document.getElementById('billing-scope');
4419
+ const scopeStart = document.getElementById('billing-scope-start');
4420
+ const scopeMidpoint = document.getElementById('billing-scope-midpoint');
4421
+ const timelineLabels = crtBillingTimelineLabels(timeline);
4387
4422
  if (currentRate) currentRate.textContent = formatCrtUsageValue(crtBillingCurrentRate());
4388
4423
  if (windowTotal) windowTotal.textContent = formatCrtUsageValue(timeline && timeline.totalTokens);
4389
4424
  if (peakRate) peakRate.textContent = formatCrtUsageValue(timeline && timeline.peakTokensPerMinute);
4390
4425
  if (dutyCycle) dutyCycle.textContent = timeline ? `${timeline.activeBucketCount}/${timeline.bucketCount}` : '--';
4391
4426
  if (scopeScale) scopeScale.textContent = `${formatCrtUsageValue(timeline && timeline.peakTokensPerMinute)} TOK/MIN PEAK`;
4427
+ if (windowLabel) windowLabel.textContent = timelineLabels.integral;
4428
+ if (peakLabel) peakLabel.textContent = timelineLabels.peak;
4429
+ if (scopeTitle) scopeTitle.textContent = timelineLabels.title;
4430
+ if (scope) scope.setAttribute('aria-label', timelineLabels.ariaLabel);
4431
+ if (scopeStart) scopeStart.textContent = timelineLabels.start;
4432
+ if (scopeMidpoint) scopeMidpoint.textContent = timelineLabels.midpoint;
4392
4433
  if (empty) {
4393
4434
  empty.classList.toggle('hidden', hasSignal);
4394
4435
  empty.textContent = billingError ? 'SIGNAL LOST' : billingLoading ? 'ACQUIRING SIGNAL' : 'NO TOKEN SIGNAL';
@@ -6130,10 +6171,45 @@ function flushStructuredComposerFollowUp(agent) {
6130
6171
  setTimeout(() => void refreshStructuredSession(agent.id, true), 160);
6131
6172
  }
6132
6173
 
6174
+ function structuredContextUsage(session) {
6175
+ const usage = session && session.usage;
6176
+ const usedTokens = usage && usage.used;
6177
+ const limitTokens = usage && usage.size;
6178
+ if (
6179
+ typeof usedTokens !== 'number'
6180
+ || !Number.isFinite(usedTokens)
6181
+ || usedTokens < 0
6182
+ || typeof limitTokens !== 'number'
6183
+ || !Number.isFinite(limitTokens)
6184
+ || limitTokens <= 0
6185
+ ) return null;
6186
+ const percentUsed = Math.max(0, Math.min(100, Math.round(usedTokens / limitTokens * 100)));
6187
+ return {
6188
+ usedTokens,
6189
+ limitTokens,
6190
+ percentUsed,
6191
+ percentLeft: 100 - percentUsed,
6192
+ };
6193
+ }
6194
+
6133
6195
  function formatStructuredUsage(session) {
6134
- const tokens = Number(session && session.usage && session.usage.totalTokens);
6135
- if (!Number.isFinite(tokens) || tokens <= 0) return '';
6136
- return `${Math.round(tokens / 1000)}K TOK`;
6196
+ const contextUsage = structuredContextUsage(session);
6197
+ if (!contextUsage) return '';
6198
+ return `${formatCrtUsageValue(contextUsage.usedTokens)} / ${formatCrtUsageValue(contextUsage.limitTokens)} TOK`;
6199
+ }
6200
+
6201
+ function updateStructuredUsageDisplay(element, session) {
6202
+ if (!element) return;
6203
+ const contextUsage = structuredContextUsage(session);
6204
+ element.textContent = formatStructuredUsage(session);
6205
+ if (!contextUsage) {
6206
+ element.removeAttribute('title');
6207
+ element.removeAttribute('aria-label');
6208
+ return;
6209
+ }
6210
+ const label = `Context window: ${contextUsage.percentUsed}% used (${contextUsage.percentLeft}% left)`;
6211
+ element.title = label;
6212
+ element.setAttribute('aria-label', label);
6137
6213
  }
6138
6214
 
6139
6215
  function structuredSelectOptions(option) {
@@ -6187,7 +6263,7 @@ function resetStructuredSessionControls() {
6187
6263
  if (commandButton) commandButton.hidden = true;
6188
6264
  if (modeButton) modeButton.hidden = true;
6189
6265
  if (configButton) configButton.hidden = true;
6190
- if (usage) usage.textContent = '';
6266
+ updateStructuredUsageDisplay(usage, null);
6191
6267
  }
6192
6268
 
6193
6269
  function setStructuredComposerMenu(menu, { focusFirst = false, opener = null } = {}) {
@@ -6429,7 +6505,7 @@ function renderStructuredSessionControls() {
6429
6505
  const currentMode = modes.find((mode) => mode.id === (session && (session.currentModeId || (session.modes && session.modes.currentModeId))));
6430
6506
  modeButton.textContent = `[MODE ${currentMode ? currentMode.name : ''}]`;
6431
6507
  configButton.textContent = `[${currentStructuredConfigLabel(session)}]`;
6432
- usage.textContent = formatStructuredUsage(session);
6508
+ updateStructuredUsageDisplay(usage, session);
6433
6509
  renderStructuredComposerMenu();
6434
6510
  }
6435
6511
 
@@ -8253,6 +8329,8 @@ if (typeof module !== 'undefined' && module.exports) {
8253
8329
  crtAgentSessionKey,
8254
8330
  crtResumedSessionFromSource,
8255
8331
  crtDashboardStateSignature,
8332
+ crtBillingTimelineLabels,
8333
+ crtBillingCurrentRate,
8256
8334
  findDefaultNewAgentIndex,
8257
8335
  findDirectionalNavigationIndex,
8258
8336
  isBrowserShortcut,
@@ -8269,6 +8347,8 @@ if (typeof module !== 'undefined' && module.exports) {
8269
8347
  formatCrtTokenRate,
8270
8348
  formatCrtHistoryAge,
8271
8349
  formatCrtCompactTotalValue,
8350
+ formatCrtUsageValue,
8351
+ formatStructuredUsage,
8272
8352
  getCrtHistoryPage,
8273
8353
  getCrtAgentPage,
8274
8354
  getCrtAgentVerticalPageTarget,
@@ -8290,6 +8370,8 @@ if (typeof module !== 'undefined' && module.exports) {
8290
8370
  hasCrtStructuredLocalEscapeAction,
8291
8371
  resolveCrtSessionKeyboardCommand,
8292
8372
  structuredComposerAction,
8373
+ structuredContextUsage,
8374
+ updateStructuredUsageDisplay,
8293
8375
  structuredTranscriptTurns,
8294
8376
  crtStructuredPreviewMessageLines,
8295
8377
  getCrtBrandPaneKey,
@@ -977,22 +977,15 @@
977
977
  margin-bottom: 20px;
978
978
  }
979
979
 
980
- .empty-state p {
981
- margin-bottom: 16px;
982
- }
983
-
984
- .empty-start-agent {
985
- padding: 8px 20px;
986
- border: 1px solid #00ff00;
987
- background: #1a1a1a;
988
- color: #00ff00;
989
- cursor: pointer;
990
- font: inherit;
980
+ .empty-state-shortcuts {
981
+ display: flex;
982
+ flex-direction: column;
983
+ align-items: flex-start;
984
+ gap: 10px;
991
985
  }
992
986
 
993
- .empty-start-agent:hover,
994
- .empty-start-agent:focus-visible {
995
- background: #3a3a3a;
987
+ .empty-state-shortcuts p {
988
+ margin: 0;
996
989
  }
997
990
 
998
991
  .modal.active {
@@ -1495,15 +1488,10 @@
1495
1488
  <div class="map-area" id="map-area">
1496
1489
  <div class="empty-state" id="empty-state">
1497
1490
  <h2>No Agents Running</h2>
1498
- <p>Press <strong>N</strong> to start a new agent</p>
1499
- <button
1500
- type="button"
1501
- class="empty-start-agent"
1502
- data-crt-nav-key="empty:new-agent"
1503
- data-crt-nav-default="true"
1504
- tabindex="-1"
1505
- onclick="showInputDialog()"
1506
- >[N] New Agent</button>
1491
+ <div class="empty-state-shortcuts">
1492
+ <p>Press <strong>[N]</strong> to start a new agent</p>
1493
+ <p>Press <strong>[H]</strong> to continue from history</p>
1494
+ </div>
1507
1495
  </div>
1508
1496
  </div>
1509
1497
 
@@ -1678,12 +1666,12 @@
1678
1666
  <div class="billing-meter">
1679
1667
  <span>INTEGRAL</span>
1680
1668
  <strong id="billing-window-total">--</strong>
1681
- <small>TOKENS · 60M</small>
1669
+ <small id="billing-window-label">TOKENS · WINDOW</small>
1682
1670
  </div>
1683
1671
  <div class="billing-meter">
1684
1672
  <span>PEAK</span>
1685
1673
  <strong id="billing-peak-rate">--</strong>
1686
- <small>TOK/MIN · 60M</small>
1674
+ <small id="billing-peak-label">TOK/MIN · WINDOW</small>
1687
1675
  </div>
1688
1676
  <div class="billing-meter">
1689
1677
  <span>DUTY</span>
@@ -1694,16 +1682,16 @@
1694
1682
 
1695
1683
  <section class="billing-scope-panel" aria-label="Token burn oscilloscope">
1696
1684
  <div class="billing-panel-heading">
1697
- <h3>TOKEN BURN // 60 MINUTES</h3>
1685
+ <h3 id="billing-scope-title">TOKEN BURN // WINDOW</h3>
1698
1686
  <span id="billing-scope-scale">-- TOK/MIN PEAK</span>
1699
1687
  </div>
1700
1688
  <div class="billing-scope-screen">
1701
- <canvas id="billing-scope" role="img" aria-label="Token burn rate over the last 60 minutes"></canvas>
1689
+ <canvas id="billing-scope" role="img" aria-label="Token burn rate for the reported window"></canvas>
1702
1690
  <div class="billing-scope-sweep" aria-hidden="true"></div>
1703
1691
  <div class="billing-scope-empty" id="billing-scope-empty">AWAITING SIGNAL</div>
1704
1692
  </div>
1705
1693
  <div class="billing-scope-axis" aria-hidden="true">
1706
- <span>-60M</span><span>-30M</span><span>NOW</span>
1694
+ <span id="billing-scope-start">-WINDOW</span><span id="billing-scope-midpoint">-MID</span><span>NOW</span>
1707
1695
  </div>
1708
1696
  </section>
1709
1697
  </div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "farming-code",
3
- "version": "2.2.17",
3
+ "version": "2.2.19",
4
4
  "description": "Remote browser workspace for supervising AI coding agents",
5
5
  "main": "backend/server.js",
6
6
  "bin": {