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:
parent
eaf0538150
commit
385d936689
8 changed files with 24 additions and 57 deletions
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue