Update files
This commit is contained in:
@@ -1131,8 +1131,11 @@ export class DaemonClientV2 {
|
||||
|
||||
async getCheckoutStatus(
|
||||
agentId: string,
|
||||
requestId?: string
|
||||
options?: { cwd?: string; requestId?: string }
|
||||
): Promise<CheckoutStatusPayload> {
|
||||
const requestId = options?.requestId;
|
||||
const cwd = options?.cwd;
|
||||
|
||||
if (!requestId) {
|
||||
const existing = this.checkoutStatusInFlight.get(agentId);
|
||||
if (existing) {
|
||||
@@ -1144,6 +1147,7 @@ export class DaemonClientV2 {
|
||||
const message = SessionInboundMessageSchema.parse({
|
||||
type: "checkout_status_request",
|
||||
agentId,
|
||||
cwd,
|
||||
requestId: resolvedRequestId,
|
||||
});
|
||||
|
||||
|
||||
@@ -2855,7 +2855,9 @@ export class Session {
|
||||
): Promise<void> {
|
||||
const { agentId, requestId } = msg;
|
||||
const agent = this.agentManager.getAgent(agentId);
|
||||
if (!agent) {
|
||||
// Use cwd from agent if found, otherwise fall back to cwd from message
|
||||
const cwd = agent?.cwd ?? msg.cwd;
|
||||
if (!cwd) {
|
||||
this.emit({
|
||||
type: "checkout_status_response",
|
||||
payload: {
|
||||
@@ -2870,7 +2872,7 @@ export class Session {
|
||||
hasRemote: false,
|
||||
remoteUrl: null,
|
||||
isPaseoOwnedWorktree: false,
|
||||
error: { code: "UNKNOWN", message: `Agent not found: ${agentId}` },
|
||||
error: { code: "UNKNOWN", message: `Agent not found and no cwd provided: ${agentId}` },
|
||||
requestId,
|
||||
},
|
||||
});
|
||||
@@ -2878,13 +2880,13 @@ export class Session {
|
||||
}
|
||||
|
||||
try {
|
||||
const status = await getCheckoutStatus(agent.cwd, { paseoHome: this.paseoHome });
|
||||
const status = await getCheckoutStatus(cwd, { paseoHome: this.paseoHome });
|
||||
if (!status.isGit) {
|
||||
this.emit({
|
||||
type: "checkout_status_response",
|
||||
payload: {
|
||||
agentId,
|
||||
cwd: agent.cwd,
|
||||
cwd,
|
||||
isGit: false,
|
||||
repoRoot: null,
|
||||
currentBranch: null,
|
||||
@@ -2906,7 +2908,7 @@ export class Session {
|
||||
type: "checkout_status_response",
|
||||
payload: {
|
||||
agentId,
|
||||
cwd: agent.cwd,
|
||||
cwd,
|
||||
isGit: true,
|
||||
repoRoot: status.repoRoot ?? null,
|
||||
currentBranch: status.currentBranch ?? null,
|
||||
@@ -2927,7 +2929,7 @@ export class Session {
|
||||
type: "checkout_status_response",
|
||||
payload: {
|
||||
agentId,
|
||||
cwd: agent.cwd,
|
||||
cwd,
|
||||
isGit: true,
|
||||
repoRoot: status.repoRoot ?? null,
|
||||
currentBranch: status.currentBranch ?? null,
|
||||
@@ -2946,7 +2948,7 @@ export class Session {
|
||||
type: "checkout_status_response",
|
||||
payload: {
|
||||
agentId,
|
||||
cwd: agent.cwd,
|
||||
cwd,
|
||||
isGit: false,
|
||||
repoRoot: null,
|
||||
currentBranch: null,
|
||||
|
||||
@@ -477,6 +477,8 @@ const CheckoutDiffCompareSchema = z.object({
|
||||
export const CheckoutStatusRequestSchema = z.object({
|
||||
type: z.literal("checkout_status_request"),
|
||||
agentId: z.string(),
|
||||
/** Optional cwd to use if the agent is not live in memory (e.g. from persisted agents.json) */
|
||||
cwd: z.string().optional(),
|
||||
requestId: z.string(),
|
||||
});
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
||||
import { mkdtempSync, rmSync, writeFileSync, mkdirSync, realpathSync } from "fs";
|
||||
import { join } from "path";
|
||||
import { tmpdir } from "os";
|
||||
import { findProjectIcon, getProjectIcon, ICON_PATTERNS, PRIORITY_DIRS, IGNORED_DIRS } from "./project-icon.js";
|
||||
import { findProjectIcon, getProjectIcon, ICON_PATTERNS, PRIORITY_DIRS, IGNORED_DIRS, MONOREPO_PACKAGE_DIRS } from "./project-icon.js";
|
||||
|
||||
function createTempDir(): string {
|
||||
return realpathSync(mkdtempSync(join(tmpdir(), "project-icon-test-")));
|
||||
@@ -55,6 +55,13 @@ describe("findProjectIcon", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("MONOREPO_PACKAGE_DIRS", () => {
|
||||
it("includes common monorepo package directories", () => {
|
||||
expect(MONOREPO_PACKAGE_DIRS).toContain("packages");
|
||||
expect(MONOREPO_PACKAGE_DIRS).toContain("apps");
|
||||
});
|
||||
});
|
||||
|
||||
it("returns null when no icon is found", async () => {
|
||||
const result = await findProjectIcon(tempDir);
|
||||
expect(result).toBeNull();
|
||||
@@ -175,6 +182,51 @@ describe("findProjectIcon", () => {
|
||||
// Should return the first one based on pattern order (favicon.ico comes first)
|
||||
expect(result).toBe(join(tempDir, "favicon.ico"));
|
||||
});
|
||||
|
||||
describe("monorepo package directories", () => {
|
||||
it("finds icon in packages/*/public directory", async () => {
|
||||
mkdirSync(join(tempDir, "packages", "app", "public"), { recursive: true });
|
||||
writeFileSync(join(tempDir, "packages", "app", "public", "favicon.ico"), "icon");
|
||||
|
||||
const result = await findProjectIcon(tempDir);
|
||||
expect(result).toBe(join(tempDir, "packages", "app", "public", "favicon.ico"));
|
||||
});
|
||||
|
||||
it("finds icon in apps/*/public directory", async () => {
|
||||
mkdirSync(join(tempDir, "apps", "web", "public"), { recursive: true });
|
||||
writeFileSync(join(tempDir, "apps", "web", "public", "favicon.png"), "icon");
|
||||
|
||||
const result = await findProjectIcon(tempDir);
|
||||
expect(result).toBe(join(tempDir, "apps", "web", "public", "favicon.png"));
|
||||
});
|
||||
|
||||
it("finds icon in packages/* root", async () => {
|
||||
mkdirSync(join(tempDir, "packages", "ui"), { recursive: true });
|
||||
writeFileSync(join(tempDir, "packages", "ui", "logo.svg"), "icon");
|
||||
|
||||
const result = await findProjectIcon(tempDir);
|
||||
expect(result).toBe(join(tempDir, "packages", "ui", "logo.svg"));
|
||||
});
|
||||
|
||||
it("prioritizes root priority dirs over monorepo dirs", async () => {
|
||||
mkdirSync(join(tempDir, "public"), { recursive: true });
|
||||
mkdirSync(join(tempDir, "packages", "app", "public"), { recursive: true });
|
||||
writeFileSync(join(tempDir, "public", "favicon.ico"), "root icon");
|
||||
writeFileSync(join(tempDir, "packages", "app", "public", "favicon.ico"), "package icon");
|
||||
|
||||
const result = await findProjectIcon(tempDir);
|
||||
expect(result).toBe(join(tempDir, "public", "favicon.ico"));
|
||||
});
|
||||
|
||||
it("prioritizes monorepo dirs over root dir (non-priority)", async () => {
|
||||
mkdirSync(join(tempDir, "packages", "app", "public"), { recursive: true });
|
||||
writeFileSync(join(tempDir, "logo.png"), "root icon");
|
||||
writeFileSync(join(tempDir, "packages", "app", "public", "favicon.ico"), "package icon");
|
||||
|
||||
const result = await findProjectIcon(tempDir);
|
||||
expect(result).toBe(join(tempDir, "packages", "app", "public", "favicon.ico"));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("getProjectIcon", () => {
|
||||
|
||||
@@ -9,6 +9,9 @@ export const ICON_PATTERNS = [
|
||||
"favicon.ico",
|
||||
"favicon.png",
|
||||
"favicon.svg",
|
||||
"favico.ico",
|
||||
"favico.png",
|
||||
"favico.svg",
|
||||
"icon.png",
|
||||
"icon.svg",
|
||||
"app-icon.png",
|
||||
@@ -24,6 +27,11 @@ export const ICON_PATTERNS = [
|
||||
*/
|
||||
export const PRIORITY_DIRS = ["public", "static", "assets", "images", "img"];
|
||||
|
||||
/**
|
||||
* Monorepo package directory patterns to scan (e.g., packages/app, apps/web).
|
||||
*/
|
||||
export const MONOREPO_PACKAGE_DIRS = ["packages", "apps"];
|
||||
|
||||
/**
|
||||
* Directories to ignore during search.
|
||||
*/
|
||||
@@ -306,6 +314,54 @@ export async function findProjectIcon(
|
||||
}
|
||||
}
|
||||
|
||||
// Then search monorepo package directories (packages/*, apps/*)
|
||||
for (const monoDir of MONOREPO_PACKAGE_DIRS) {
|
||||
const monoPath = join(projectDir, monoDir);
|
||||
let packageEntries: string[];
|
||||
try {
|
||||
packageEntries = await readdir(monoPath);
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const packageName of packageEntries) {
|
||||
const packagePath = join(monoPath, packageName);
|
||||
try {
|
||||
const packageStats = await stat(packagePath);
|
||||
if (!packageStats.isDirectory()) continue;
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Search priority dirs within the package
|
||||
for (const priorityDir of PRIORITY_DIRS) {
|
||||
const priorityPath = join(packagePath, priorityDir);
|
||||
try {
|
||||
const priorityStats = await stat(priorityPath);
|
||||
if (priorityStats.isDirectory()) {
|
||||
const result = await searchDirRecursively(
|
||||
priorityPath,
|
||||
ICON_PATTERNS,
|
||||
ignoredDirsSet,
|
||||
maxDepth - 1
|
||||
);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// Directory doesn't exist, continue
|
||||
}
|
||||
}
|
||||
|
||||
// Search package root
|
||||
const found = await findIconInDir(packagePath, ICON_PATTERNS);
|
||||
if (found) {
|
||||
return found;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Then search root and any other non-priority directories
|
||||
const found = await findDirRecursively(projectDir);
|
||||
if (found) {
|
||||
|
||||
Reference in New Issue
Block a user