🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@askalf/dario

Package Overview
Dependencies
Maintainers
1
Versions
413
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@askalf/dario - npm Package Compare versions

Comparing version
5.4.6
to
5.4.7
+8
-1
dist/tui/layout.js

@@ -22,3 +22,10 @@ /**

const dashWidth = Math.max(0, width - visibleWidth(left) - visibleWidth(right) - 2);
return BOX.topLeft + left + BOX.horizontal.repeat(dashWidth) + right + BOX.topRight;
const full = BOX.topLeft + left + BOX.horizontal.repeat(dashWidth) + right + BOX.topRight;
if (visibleWidth(full) <= width)
return full;
// Too narrow for brand + status: `dashWidth` clamps at 0 but both ends
// still render full-length, so the row would overflow and wrap. Drop
// the status (the proxy URL — also on the Status tab) before clipping
// the brand, which is this row's only identity.
return truncate(BOX.topLeft + left + BOX.topRight, width);
}

@@ -25,0 +32,0 @@ /**

+9
-3

@@ -184,5 +184,11 @@ /**

const empty = opts.empty ?? '░';
const clamped = Math.max(0, Math.min(1, value));
const cells = Math.round(clamped * width);
return filled.repeat(cells) + empty.repeat(width - cells);
// Callers derive the bar width by subtracting label columns from the
// terminal width, so a narrow terminal hands us a NEGATIVE width —
// String.repeat() throws RangeError on that, which took the whole TUI
// down rather than degrading. Collapse to an empty bar instead; the
// surrounding row still renders.
const w = Number.isFinite(width) ? Math.max(0, Math.floor(width)) : 0;
const clamped = Number.isFinite(value) ? Math.max(0, Math.min(1, value)) : 0;
const cells = Math.round(clamped * w);
return filled.repeat(cells) + empty.repeat(w - cells);
}

@@ -189,0 +195,0 @@ /**

@@ -27,3 +27,3 @@ /**

*/
import { fg, dim, brand, pad } from '../render.js';
import { fg, dim, brand, pad, truncate } from '../render.js';
import { renderKvRow } from '../layout.js';

@@ -61,17 +61,23 @@ export const AccountsTab = {

const w = dimv.cols;
lines.push(' ' + brand('Accounts'));
// Bound every row at the push site rather than at each call site. The
// column header (68 wide) and the disk-fallback path (which
// interpolates `~/.dario/accounts/<alias>.json`, unbounded by alias
// length) both overflowed; hand-auditing 15 separate pushes is how
// that got missed.
const push = (s) => lines.push(truncate(s, w));
push(' ' + brand('Accounts'));
if (state.loading && state.accounts.length === 0) {
lines.push('');
lines.push(' ' + dim('Loading accounts…'));
push('');
push(' ' + dim('Loading accounts…'));
return lines.join('\n');
}
if (state.accounts.length === 0) {
lines.push('');
push('');
if (state.source === 'single-account') {
lines.push(' ' + dim('Single-account mode (`dario login`) — no pool.'));
lines.push(' ' + 'Start a pool: ' + fg('cyan', 'dario accounts add <alias>'));
push(' ' + dim('Single-account mode (`dario login`) — no pool.'));
push(' ' + 'Start a pool: ' + fg('cyan', 'dario accounts add <alias>'));
}
else {
lines.push(' ' + dim('No accounts in the pool.'));
lines.push(' ' + 'Add one: ' + fg('cyan', 'dario accounts add <alias>'));
push(' ' + dim('No accounts in the pool.'));
push(' ' + 'Add one: ' + fg('cyan', 'dario accounts add <alias>'));
}

@@ -84,9 +90,9 @@ return lines.join('\n');

if (state.source === 'disk') {
lines.push(' ' + fg('yellow', 'proxy unreachable — showing on-disk accounts (may be stale)'));
push(' ' + fg('yellow', 'proxy unreachable — showing on-disk accounts (may be stale)'));
}
// Header row
lines.push(' ' + dim(hasUtil
push(' ' + dim(hasUtil
? pad('alias', 20) + pad('expires', 14) + pad('util5h', 9) + pad('util7d', 9) + pad('status', 14)
: pad('alias', 20) + pad('expires', 16) + pad('source', 24)));
lines.push(' ' + dim('─'.repeat(Math.min(w - 4, 66))));
push(' ' + dim('─'.repeat(Math.min(w - 4, 66))));
for (const acc of state.accounts) {

@@ -100,3 +106,3 @@ const aliasCol = pad(acc.alias, 20);

const statusFg = statusCol === 'auth-cooldown' ? fg('yellow', statusCol) : dim(statusCol);
lines.push(' ' + aliasCol + expiresCol + u5 + u7 + statusFg);
push(' ' + aliasCol + expiresCol + u5 + u7 + statusFg);
}

@@ -106,13 +112,13 @@ else {

const sourceCol = '~/.dario/accounts/' + acc.alias + '.json';
lines.push(' ' + aliasCol + expiresCol + dim(sourceCol));
push(' ' + aliasCol + expiresCol + dim(sourceCol));
}
}
lines.push('');
lines.push(' ' + dim('Mutations via CLI:'));
lines.push(' ' + fg('cyan', 'dario accounts add <alias>'));
lines.push(' ' + fg('cyan', 'dario accounts remove <alias>'));
push('');
push(' ' + dim('Mutations via CLI:'));
push(' ' + fg('cyan', 'dario accounts add <alias>'));
push(' ' + fg('cyan', 'dario accounts remove <alias>'));
// Refresh hint
lines.push('');
lines.push(' ' + renderKvRow('', '', w - 2)); // spacer
lines.push(' ' + dim(`Press ${fg('cyan', 'r')} to refresh.`));
push('');
push(' ' + renderKvRow('', '', w - 2)); // spacer
push(' ' + dim(`Press ${fg('cyan', 'r')} to refresh.`));
return lines.join('\n');

@@ -119,0 +125,0 @@ },

@@ -142,3 +142,4 @@ /**

// Red banner header — this is the loud surface when halted
lines.push(' ' + fg('red', '⚠ HALTED') + ' ' + dim(`${s.request.claim} detected ${formatAgo(s.since)} ago`));
// formatAgo() already ends in "ago" — don't append a second one.
lines.push(' ' + fg('red', '⚠ HALTED') + ' ' + dim(`${s.request.claim} detected ${formatAgo(s.since)}`));
lines.push(' ' + renderKvRow('Request', `${s.request.model} ${dim('account=' + s.request.account)}`, w - 4));

@@ -145,0 +146,0 @@ lines.push(' ' + renderKvRow('Cause', `representative-claim = ${fg('red', s.request.claim)}`, w - 4));

@@ -42,1 +42,10 @@ /**

export declare function startTuiApp(opts: TuiAppOpts): Promise<void>;
/**
* Compose one full frame: header, tab strip, rule, active tab body,
* footer. Exported for tests — the frame-height invariant (never more
* physical rows than the terminal has) is asserted against this.
*/
export declare function renderTui(state: TuiState, dim_: {
cols: number;
rows: number;
}, version: string, proxyUrl: string): string;

@@ -13,3 +13,3 @@ /**

import { ProxyClient } from './proxy-client.js';
import { fg, dim } from './render.js';
import { fg, dim, truncate } from './render.js';
import { renderFooter, renderHeader, renderTabStrip } from './layout.js';

@@ -184,3 +184,8 @@ import { StatusTab } from './tabs/status.js';

// ── Rendering ───────────────────────────────────────────────────
function renderTui(state, dim_, version, proxyUrl) {
/**
* Compose one full frame: header, tab strip, rule, active tab body,
* footer. Exported for tests — the frame-height invariant (never more
* physical rows than the terminal has) is asserted against this.
*/
export function renderTui(state, dim_, version, proxyUrl) {
const cols = dim_.cols;

@@ -196,7 +201,25 @@ const rows = dim_.rows;

// Body — passed (cols, rows-5) so the tab knows it has rows 4..rows-2
const bodyRows = rows - 5;
const bodyRows = Math.max(1, rows - 5);
const tab = TABS[state.activeTab];
const slice = stateOf(state, state.activeTab);
const body = tab.render(slice, { cols, rows: bodyRows });
out.push(body);
const bodyLineArr = body.split('\n');
// A tab that renders past its row budget used to push the header and
// tab strip off the top of the alt-screen: App.redraw writes the frame
// from row 1 with no scrollback, so the overflow costs the chrome the
// user needs most — including which tab is even active. Clip the tail
// instead, and say how much was dropped so the loss isn't silent.
//
// This is a floor, not a substitute for a tab budgeting its own
// content: a tab that overflows here is still choosing what to drop by
// accident of ordering. Config and Hits size themselves; the rest do
// not yet.
if (bodyLineArr.length > bodyRows) {
const hidden = bodyLineArr.length - bodyRows + 1;
const note = ` … ${hidden} more row${hidden === 1 ? '' : 's'} — resize for the rest`;
out.push(bodyLineArr.slice(0, bodyRows - 1).concat(truncate(dim(note), cols)).join('\n'));
}
else {
out.push(body);
}
// Footer — fixed key hints (tab-cycling stays universal; per-tab

@@ -212,3 +235,3 @@ // hints are inside each tab body to keep the global footer stable).

// depends on each tab's content).
const bodyLines = body.split('\n').length;
const bodyLines = bodyLineArr.length;
if (bodyLines < bodyRows) {

@@ -220,3 +243,5 @@ out.push(''.padEnd(bodyRows - bodyLines, '\n'));

void fg; // silence unused if neither tab uses it through this module
return out.join('\n');
// Absolute floor — whatever a tab did, never hand the terminal more
// physical rows than it has.
return out.join('\n').split('\n').slice(0, rows).join('\n');
}
{
"name": "@askalf/dario",
"version": "5.4.6",
"version": "5.4.7",
"description": "Use your Claude Pro/Max subscription in any tool — Cursor, Cline, Aider, the Agent SDK, your scripts — at subscription pricing, not per-token API bills. One local Anthropic + OpenAI-compatible endpoint.",

@@ -5,0 +5,0 @@ "type": "module",