refactor: deduplicate toPosixPath, ZERO_USAGE, and shortenPath utilities

- toPosixPath: remove private copies in skills.ts and package-manager.ts,
  import from canonical utils/path-display.ts
- ZERO_USAGE: export from agent-loop.ts, replace inline zero-usage
  objects in agent.ts and proxy.ts
- shortenPath: extract to shared modes/interactive/utils/shorten-path.ts,
  import in tool-execution.ts and session-selector.ts
This commit is contained in:
frizynn 2026-03-19 14:55:30 -03:00
parent eaf0538150
commit 385d936689
8 changed files with 24 additions and 57 deletions

View file

@ -22,7 +22,7 @@ import type {
StreamFn,
} from "./types.js";
const ZERO_USAGE = {
export const ZERO_USAGE = {
input: 0,
output: 0,
cacheRead: 0,
@ -199,14 +199,7 @@ async function runLoop(
api: config.model.api,
provider: config.model.provider,
model: config.model.id,
usage: {
input: 0,
output: 0,
cacheRead: 0,
cacheWrite: 0,
totalTokens: 0,
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
},
usage: ZERO_USAGE,
stopReason: signal?.aborted ? "aborted" : "error",
errorMessage: errorText,
timestamp: Date.now(),

View file

@ -14,7 +14,7 @@ import {
type ThinkingBudgets,
type Transport,
} from "@gsd/pi-ai";
import { agentLoop, agentLoopContinue } from "./agent-loop.js";
import { agentLoop, agentLoopContinue, ZERO_USAGE } from "./agent-loop.js";
import type {
AgentContext,
AgentEvent,
@ -557,14 +557,7 @@ export class Agent {
api: model.api,
provider: model.provider,
model: model.id,
usage: {
input: 0,
output: 0,
cacheRead: 0,
cacheWrite: 0,
totalTokens: 0,
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
},
usage: ZERO_USAGE,
stopReason: this.abortController?.signal.aborted ? "aborted" : "error",
errorMessage: err?.message || String(err),
timestamp: Date.now(),

View file

@ -15,6 +15,7 @@ import {
type StopReason,
type ToolCall,
} from "@gsd/pi-ai";
import { ZERO_USAGE } from "./agent-loop.js";
// Create stream class matching ProxyMessageEventStream
class ProxyMessageEventStream extends EventStream<AssistantMessageEvent, AssistantMessage> {
@ -94,14 +95,7 @@ export function streamProxy(model: Model<any>, context: Context, options: ProxyS
api: model.api,
provider: model.provider,
model: model.id,
usage: {
input: 0,
output: 0,
cacheRead: 0,
cacheWrite: 0,
totalTokens: 0,
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
},
usage: { ...ZERO_USAGE, cost: { ...ZERO_USAGE.cost } },
timestamp: Date.now(),
};

View file

@ -7,6 +7,7 @@ import ignore from "ignore";
import { minimatch } from "minimatch";
import { CONFIG_DIR_NAME } from "../config.js";
import { type GitSource, parseGitUrl } from "../utils/git.js";
import { toPosixPath } from "../utils/path-display.js";
import type { PackageSource, SettingsManager } from "./settings-manager.js";
const NETWORK_TIMEOUT_MS = 10000;
@ -121,10 +122,6 @@ const IGNORE_FILE_NAMES = [".gitignore", ".ignore", ".fdignore"];
type IgnoreMatcher = ReturnType<typeof ignore>;
function toPosixPath(p: string): string {
return p.split(sep).join("/");
}
function prefixIgnorePattern(line: string, prefix: string): string | null {
const trimmed = line.trim();
if (!trimmed) return null;

View file

@ -4,6 +4,7 @@ import { homedir } from "os";
import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "path";
import { CONFIG_DIR_NAME, getAgentDir } from "../config.js";
import { parseFrontmatter } from "../utils/frontmatter.js";
import { toPosixPath } from "../utils/path-display.js";
import type { ResourceDiagnostic } from "./diagnostics.js";
/** Max name length per spec */
@ -16,10 +17,6 @@ const IGNORE_FILE_NAMES = [".gitignore", ".ignore", ".fdignore"];
type IgnoreMatcher = ReturnType<typeof ignore>;
function toPosixPath(p: string): string {
return p.split(sep).join("/");
}
function prefixIgnorePattern(line: string, prefix: string): string | null {
const trimmed = line.trim();
if (!trimmed) return null;

View file

@ -1,7 +1,6 @@
import { spawnSync } from "node:child_process";
import { existsSync } from "node:fs";
import { unlink } from "node:fs/promises";
import * as os from "node:os";
import {
type Component,
Container,
@ -17,21 +16,13 @@ import {
import { KeybindingsManager } from "../../../core/keybindings.js";
import type { SessionInfo, SessionListProgress } from "../../../core/session-manager.js";
import { theme } from "../theme/theme.js";
import { shortenPath } from "../utils/shorten-path.js";
import { DynamicBorder } from "./dynamic-border.js";
import { appKey, appKeyHint, keyHint } from "./keybinding-hints.js";
import { filterAndSortSessions, hasSessionName, type NameFilter, type SortMode } from "./session-selector-search.js";
type SessionScope = "current" | "all";
function shortenPath(path: string): string {
const home = os.homedir();
if (!path) return path;
if (path.startsWith(home)) {
return `~${path.slice(home.length)}`;
}
return path;
}
function formatSessionDate(date: Date): string {
const now = new Date();
const diffMs = now.getTime() - date.getTime();

View file

@ -1,4 +1,3 @@
import * as os from "node:os";
import {
Box,
Container,
@ -18,6 +17,7 @@ import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize } from "../../../core/
import { convertToPng } from "../../../utils/image-convert.js";
import { sanitizeBinaryOutput } from "../../../utils/shell.js";
import { getLanguageFromPath, highlightCode, theme } from "../theme/theme.js";
import { shortenPath } from "../utils/shorten-path.js";
import { renderDiff } from "./diff.js";
import { keyHint } from "./keybinding-hints.js";
import { truncateToVisualLines } from "./visual-truncate.js";
@ -28,18 +28,6 @@ const BASH_PREVIEW_LINES = 5;
// to keep multiline tokenization mostly correct without re-highlighting the full file.
const WRITE_PARTIAL_FULL_HIGHLIGHT_LINES = 50;
/**
* Convert absolute path to tilde notation if it's in home directory
*/
function shortenPath(path: unknown): string {
if (typeof path !== "string") return "";
const home = os.homedir();
if (path.startsWith(home)) {
return `~${path.slice(home.length)}`;
}
return path;
}
/**
* Replace tabs with spaces for consistent rendering
*/

View file

@ -0,0 +1,14 @@
import * as os from "node:os";
/**
* Convert absolute path to tilde notation if it's in home directory.
* Returns empty string for non-string or empty inputs.
*/
export function shortenPath(path: unknown): string {
if (typeof path !== "string" || !path) return "";
const home = os.homedir();
if (path.startsWith(home)) {
return `~${path.slice(home.length)}`;
}
return path;
}