Update files
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
type NullableString = string | null | undefined;
|
||||
|
||||
function trimNonEmpty(value: NullableString): string | null {
|
||||
if (typeof value !== "string") {
|
||||
return null;
|
||||
}
|
||||
const trimmed = value.trim();
|
||||
return trimmed.length > 0 ? trimmed : null;
|
||||
}
|
||||
|
||||
function encodeSegment(value: string): string {
|
||||
return encodeURIComponent(value);
|
||||
}
|
||||
|
||||
export function parseServerIdFromPathname(pathname: string): string | null {
|
||||
const match = pathname.match(/^\/h\/([^/]+)(?:\/|$)/);
|
||||
if (!match) {
|
||||
return null;
|
||||
}
|
||||
const raw = match[1];
|
||||
if (!raw) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return trimNonEmpty(decodeURIComponent(raw));
|
||||
} catch {
|
||||
return trimNonEmpty(raw);
|
||||
}
|
||||
}
|
||||
|
||||
export function parseHostAgentRouteFromPathname(
|
||||
pathname: string
|
||||
): { serverId: string; agentId: string } | null {
|
||||
const match = pathname.match(/^\/h\/([^/]+)\/agent\/([^/]+)(?:\/|$)/);
|
||||
if (!match) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const [, encodedServerId, encodedAgentId] = match;
|
||||
if (!encodedServerId || !encodedAgentId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const decode = (value: string) => {
|
||||
try {
|
||||
return decodeURIComponent(value);
|
||||
} catch {
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
const serverId = trimNonEmpty(decode(encodedServerId));
|
||||
const agentId = trimNonEmpty(decode(encodedAgentId));
|
||||
if (!serverId || !agentId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return { serverId, agentId };
|
||||
}
|
||||
|
||||
export function buildHostAgentDraftRoute(serverId: string): string {
|
||||
const normalized = trimNonEmpty(serverId);
|
||||
if (!normalized) {
|
||||
return "/";
|
||||
}
|
||||
return `/h/${encodeSegment(normalized)}/agent`;
|
||||
}
|
||||
|
||||
export function buildHostAgentDetailRoute(
|
||||
serverId: string,
|
||||
agentId: string
|
||||
): string {
|
||||
const normalizedServerId = trimNonEmpty(serverId);
|
||||
const normalizedAgentId = trimNonEmpty(agentId);
|
||||
if (!normalizedServerId || !normalizedAgentId) {
|
||||
return "/";
|
||||
}
|
||||
return `/h/${encodeSegment(normalizedServerId)}/agent/${encodeSegment(
|
||||
normalizedAgentId
|
||||
)}`;
|
||||
}
|
||||
|
||||
export function buildHostAgentsRoute(serverId: string): string {
|
||||
const normalized = trimNonEmpty(serverId);
|
||||
if (!normalized) {
|
||||
return "/";
|
||||
}
|
||||
return `/h/${encodeSegment(normalized)}/agents`;
|
||||
}
|
||||
|
||||
export function buildHostSettingsRoute(serverId: string): string {
|
||||
const normalized = trimNonEmpty(serverId);
|
||||
if (!normalized) {
|
||||
return "/";
|
||||
}
|
||||
return `/h/${encodeSegment(normalized)}/settings`;
|
||||
}
|
||||
|
||||
export function mapPathnameToServer(
|
||||
pathname: string,
|
||||
nextServerId: string
|
||||
): string {
|
||||
const normalized = trimNonEmpty(nextServerId);
|
||||
if (!normalized) {
|
||||
return "/";
|
||||
}
|
||||
|
||||
const suffix = pathname.replace(/^\/h\/[^/]+\/?/, "");
|
||||
const base = `/h/${encodeSegment(normalized)}`;
|
||||
if (suffix.startsWith("settings")) {
|
||||
return `${base}/settings`;
|
||||
}
|
||||
if (suffix.startsWith("agents")) {
|
||||
return `${base}/agents`;
|
||||
}
|
||||
return `${base}/agent`;
|
||||
}
|
||||
|
||||
@@ -7,14 +7,14 @@ import {
|
||||
} from "./new-agent-routing";
|
||||
|
||||
describe("buildNewAgentRoute", () => {
|
||||
it("falls back to /agent when no working directory is provided", () => {
|
||||
expect(buildNewAgentRoute(undefined)).toBe("/agent");
|
||||
expect(buildNewAgentRoute(" ")).toBe("/agent");
|
||||
it("falls back to host-scoped draft route when no working directory is provided", () => {
|
||||
expect(buildNewAgentRoute("srv-1", undefined)).toBe("/h/srv-1/agent");
|
||||
expect(buildNewAgentRoute("srv-1", " ")).toBe("/h/srv-1/agent");
|
||||
});
|
||||
|
||||
it("encodes the working directory query parameter", () => {
|
||||
expect(buildNewAgentRoute("/Users/me/dev/paseo")).toBe(
|
||||
"/agent?workingDir=%2FUsers%2Fme%2Fdev%2Fpaseo"
|
||||
expect(buildNewAgentRoute("srv-1", "/Users/me/dev/paseo")).toBe(
|
||||
"/h/srv-1/agent?workingDir=%2FUsers%2Fme%2Fdev%2Fpaseo"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { CheckoutStatusPayload } from "@/hooks/use-checkout-status-query";
|
||||
import { buildHostAgentDraftRoute } from "@/utils/host-routes";
|
||||
|
||||
export function resolveNewAgentWorkingDir(
|
||||
cwd: string,
|
||||
@@ -7,10 +8,17 @@ export function resolveNewAgentWorkingDir(
|
||||
return (checkout?.isPaseoOwnedWorktree ? checkout.mainRepoRoot : null) ?? cwd;
|
||||
}
|
||||
|
||||
export function buildNewAgentRoute(workingDir?: string | null): string {
|
||||
export function buildNewAgentRoute(
|
||||
serverId: string,
|
||||
workingDir?: string | null
|
||||
): string {
|
||||
const baseRoute = buildHostAgentDraftRoute(serverId);
|
||||
if (baseRoute === "/") {
|
||||
return baseRoute;
|
||||
}
|
||||
const trimmedWorkingDir = workingDir?.trim();
|
||||
if (!trimmedWorkingDir) {
|
||||
return "/agent";
|
||||
return baseRoute;
|
||||
}
|
||||
return `/agent?workingDir=${encodeURIComponent(trimmedWorkingDir)}`;
|
||||
return `${baseRoute}?workingDir=${encodeURIComponent(trimmedWorkingDir)}`;
|
||||
}
|
||||
|
||||
@@ -33,16 +33,17 @@ describe("resolveNotificationTarget", () => {
|
||||
describe("buildNotificationRoute", () => {
|
||||
it("routes directly to server-scoped agent path when both ids are present", () => {
|
||||
expect(buildNotificationRoute({ serverId: "srv-1", agentId: "agent-1" })).toBe(
|
||||
"/agent/srv-1/agent-1"
|
||||
"/h/srv-1/agent/agent-1"
|
||||
);
|
||||
});
|
||||
|
||||
it("falls back to legacy agent route when serverId is absent", () => {
|
||||
expect(buildNotificationRoute({ agentId: "agent-legacy" })).toBe("/agent/agent-legacy");
|
||||
it("falls back to host-scoped draft route when only serverId is present", () => {
|
||||
expect(buildNotificationRoute({ serverId: "srv-only" })).toBe("/h/srv-only/agent");
|
||||
});
|
||||
|
||||
it("falls back to agents list when no agent id is present", () => {
|
||||
expect(buildNotificationRoute({ serverId: "srv-only" })).toBe("/agents");
|
||||
it("falls back to root when no server id is present", () => {
|
||||
expect(buildNotificationRoute({ agentId: "agent-legacy" })).toBe("/");
|
||||
expect(buildNotificationRoute(undefined)).toBe("/");
|
||||
});
|
||||
|
||||
it("encodes path segments", () => {
|
||||
@@ -51,6 +52,6 @@ describe("buildNotificationRoute", () => {
|
||||
serverId: "srv/with/slash",
|
||||
agentId: "agent with space",
|
||||
})
|
||||
).toBe("/agent/srv%2Fwith%2Fslash/agent%20with%20space");
|
||||
).toBe("/h/srv%2Fwith%2Fslash/agent/agent%20with%20space");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
import {
|
||||
buildHostAgentDetailRoute,
|
||||
buildHostAgentDraftRoute,
|
||||
} from "@/utils/host-routes";
|
||||
|
||||
type NotificationData = Record<string, unknown> | null | undefined;
|
||||
|
||||
function readNonEmptyString(
|
||||
@@ -25,10 +30,10 @@ export function resolveNotificationTarget(data: NotificationData): {
|
||||
export function buildNotificationRoute(data: NotificationData): string {
|
||||
const { serverId, agentId } = resolveNotificationTarget(data);
|
||||
if (serverId && agentId) {
|
||||
return `/agent/${encodeURIComponent(serverId)}/${encodeURIComponent(agentId)}`;
|
||||
return buildHostAgentDetailRoute(serverId, agentId);
|
||||
}
|
||||
if (agentId) {
|
||||
return `/agent/${encodeURIComponent(agentId)}`;
|
||||
if (serverId) {
|
||||
return buildHostAgentDraftRoute(serverId);
|
||||
}
|
||||
return "/agents";
|
||||
return "/";
|
||||
}
|
||||
|
||||
@@ -161,6 +161,6 @@ describe("sendOsNotification", () => {
|
||||
expect(clicked.onclick).toBeTypeOf("function");
|
||||
clicked.onclick?.({} as Event);
|
||||
|
||||
expect(assign).toHaveBeenCalledWith("/agent/srv%20with%20space/agent%2F1");
|
||||
expect(assign).toHaveBeenCalledWith("/h/srv%20with%20space/agent/agent%2F1");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user