- replace Ink implementation with opentui + React 19 (old version kept at cli/legacy-ink-src/ for field reference) - all traffic goes through Gateway host Bearer token; workspace bound via X-Astrion-Workspace-Id header - auto-spawn server only when no instance is alive (never kill/restart running ones); stale server without token is detected - astrion launcher (bin/astrion, symlink-aware, --version/--help fast-exit) - slash menu panels (session/model/mode/permission/path/context/approvals...) with shared selector component - backend: host workspace list/create dual-channel endpoints, host token generated at startup - i18n reads OS locale at startup (zh/en) Co-authored-by: Astrion powered by Kimi-K3 <astrion-agent@users.noreply.github.com>
30 lines
954 B
TypeScript
30 lines
954 B
TypeScript
import { homedir } from 'node:os';
|
|
|
|
export function shortPath(path: string): string {
|
|
const home = homedir();
|
|
return path.startsWith(home) ? `~${path.slice(home.length)}` : path;
|
|
}
|
|
|
|
export function formatContext(used: number, limit: number): string {
|
|
if (!limit || limit <= 0) return formatTokens(used);
|
|
const left = Math.max(0, limit - used);
|
|
const pct = limit > 0 ? Math.round((left / limit) * 100) : 0;
|
|
return `${pct}% left ${formatTokens(used)} / ${formatTokens(limit)}`;
|
|
}
|
|
|
|
export function formatTokens(value: number): string {
|
|
if (value >= 1000) {
|
|
const rounded = Math.round((value / 1000) * 10) / 10;
|
|
return `${rounded}K`;
|
|
}
|
|
return String(value);
|
|
}
|
|
|
|
export function nowSessionId(): string {
|
|
return globalThis.crypto?.randomUUID?.() || `${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
}
|
|
|
|
export function lastLines(lines: string[], limit = 5): string[] {
|
|
return lines.slice(Math.max(0, lines.length - limit));
|
|
}
|