diff --git a/packages/pi-agent-core/src/proxy.ts b/packages/pi-agent-core/src/proxy.ts index 07540ca7e..619521bda 100644 --- a/packages/pi-agent-core/src/proxy.ts +++ b/packages/pi-agent-core/src/proxy.ts @@ -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 { @@ -94,14 +95,7 @@ function streamProxy(model: Model, context: Context, options: ProxyStreamOp 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(), }; diff --git a/packages/pi-coding-agent/src/core/package-manager.ts b/packages/pi-coding-agent/src/core/package-manager.ts index 483758203..da19d3d94 100644 --- a/packages/pi-coding-agent/src/core/package-manager.ts +++ b/packages/pi-coding-agent/src/core/package-manager.ts @@ -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; -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; diff --git a/packages/pi-coding-agent/src/core/skills.ts b/packages/pi-coding-agent/src/core/skills.ts index 70e1aa647..aa39cf009 100644 --- a/packages/pi-coding-agent/src/core/skills.ts +++ b/packages/pi-coding-agent/src/core/skills.ts @@ -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; -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; diff --git a/packages/pi-coding-agent/src/modes/interactive/components/session-selector.ts b/packages/pi-coding-agent/src/modes/interactive/components/session-selector.ts index 0aee17361..ff37698e0 100644 --- a/packages/pi-coding-agent/src/modes/interactive/components/session-selector.ts +++ b/packages/pi-coding-agent/src/modes/interactive/components/session-selector.ts @@ -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,6 +16,7 @@ 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"; @@ -29,15 +29,6 @@ import { 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(); diff --git a/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts b/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts index 88514f3b0..80d25b0f0 100644 --- a/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +++ b/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts @@ -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 */ diff --git a/packages/pi-coding-agent/src/modes/interactive/utils/shorten-path.ts b/packages/pi-coding-agent/src/modes/interactive/utils/shorten-path.ts new file mode 100644 index 000000000..b82a39056 --- /dev/null +++ b/packages/pi-coding-agent/src/modes/interactive/utils/shorten-path.ts @@ -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; +}