fix: handle Windows drive-letter paths across the codebase (#148)
* Add metrics collection and terminal performance tests
* fix: handle Windows drive-letter paths across the codebase
Windows paths like C:\Users\foo\project were broken in multiple places:
- agent-storage slugified D:\MyProject as D:-MyProject (illegal colon)
- terminal-manager rejected all non-/ paths as relative
- bootstrap parser misparsed drive colons as TCP host:port
- daemon/client connection helpers misclassified Windows paths
- CLI cwd filtering used hardcoded / separators
- checkout-git worktree detection used hardcoded / in path checks
- worktree archive used split("/").pop() instead of path.basename()
All path helpers now normalize separators and handle Windows
drive letters with case-insensitive comparison where needed.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import type { Command } from "commander";
|
||||
import { connectToDaemon, getDaemonHost } from "../../utils/client.js";
|
||||
import { isSameOrDescendantPath } from "../../utils/paths.js";
|
||||
|
||||
export function addDeleteOptions(cmd: Command): Command {
|
||||
return cmd
|
||||
@@ -69,12 +70,9 @@ export async function runDeleteCommand(
|
||||
if (options.all) {
|
||||
agents = agents.filter((a) => !a.archivedAt);
|
||||
} else if (options.cwd) {
|
||||
const filterCwd = options.cwd;
|
||||
agents = agents.filter((a) => {
|
||||
if (a.archivedAt) return false;
|
||||
const agentCwd = a.cwd.replace(/\/$/, "");
|
||||
const targetCwd = filterCwd.replace(/\/$/, "");
|
||||
return agentCwd === targetCwd || agentCwd.startsWith(targetCwd + "/");
|
||||
return isSameOrDescendantPath(options.cwd!, a.cwd);
|
||||
});
|
||||
} else if (id) {
|
||||
const fetchResult = await client.fetchAgent(id);
|
||||
|
||||
@@ -3,6 +3,7 @@ import type { AgentSnapshotPayload } from "@getpaseo/server";
|
||||
import { connectToDaemon, getDaemonHost } from "../../utils/client.js";
|
||||
import type { CommandOptions, ListResult, OutputSchema, CommandError } from "../../output/index.js";
|
||||
import { collectMultiple } from "../../utils/command-options.js";
|
||||
import { isSameOrDescendantPath } from "../../utils/paths.js";
|
||||
|
||||
export function addLsOptions(cmd: Command): Command {
|
||||
return cmd
|
||||
@@ -193,11 +194,7 @@ export async function runLsCommand(
|
||||
|
||||
// Optional cwd filter.
|
||||
if (options.cwd) {
|
||||
const targetCwd = options.cwd.replace(/\/$/, "");
|
||||
agents = agents.filter((a) => {
|
||||
const agentCwd = a.cwd.replace(/\/$/, "");
|
||||
return agentCwd === targetCwd || agentCwd.startsWith(targetCwd + "/");
|
||||
});
|
||||
agents = agents.filter((a) => isSameOrDescendantPath(options.cwd!, a.cwd));
|
||||
}
|
||||
|
||||
// Apply label filtering only when explicitly requested.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Command } from "commander";
|
||||
import { connectToDaemon, getDaemonHost } from "../../utils/client.js";
|
||||
import { isSameOrDescendantPath } from "../../utils/paths.js";
|
||||
import type {
|
||||
CommandOptions,
|
||||
SingleResult,
|
||||
@@ -75,12 +76,9 @@ export async function runStopCommand(
|
||||
agents = agents.filter((a) => !a.archivedAt);
|
||||
} else if (options.cwd) {
|
||||
// Stop agents in directory
|
||||
const filterCwd = options.cwd;
|
||||
agents = agents.filter((a) => {
|
||||
if (a.archivedAt) return false;
|
||||
const agentCwd = a.cwd.replace(/\/$/, "");
|
||||
const targetCwd = filterCwd.replace(/\/$/, "");
|
||||
return agentCwd === targetCwd || agentCwd.startsWith(targetCwd + "/");
|
||||
return isSameOrDescendantPath(options.cwd!, a.cwd);
|
||||
});
|
||||
} else if (id) {
|
||||
// Stop specific agent
|
||||
|
||||
@@ -294,7 +294,8 @@ export function resolveTcpHostFromListen(listen: string): string | null {
|
||||
normalized.startsWith("/") ||
|
||||
normalized.startsWith("unix://") ||
|
||||
normalized.startsWith("pipe://") ||
|
||||
normalized.startsWith("\\\\.\\pipe\\")
|
||||
normalized.startsWith("\\\\.\\pipe\\") ||
|
||||
/^[A-Za-z]:[/\\]/.test(normalized)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import path from "path";
|
||||
import type { Command } from "commander";
|
||||
import { connectToDaemon, getDaemonHost } from "../../utils/client.js";
|
||||
import type {
|
||||
@@ -77,7 +78,7 @@ export async function runArchiveCommand(
|
||||
|
||||
// Find the worktree by name or branch
|
||||
const worktree = listResponse.worktrees.find((wt) => {
|
||||
const name = wt.worktreePath.split("/").pop();
|
||||
const name = path.basename(wt.worktreePath);
|
||||
return name === nameArg || wt.branchName === nameArg;
|
||||
});
|
||||
|
||||
@@ -105,7 +106,7 @@ export async function runArchiveCommand(
|
||||
throw error;
|
||||
}
|
||||
|
||||
const worktreeName = worktree.worktreePath.split("/").pop() ?? nameArg;
|
||||
const worktreeName = path.basename(worktree.worktreePath) || nameArg;
|
||||
|
||||
return {
|
||||
type: "single",
|
||||
|
||||
Reference in New Issue
Block a user