Compare commits

..
Author SHA1 Message Date
paseo-bot[bot]andLorenzo Fiore 3e172d18c4 test: retain real OMP ACP provider ID collision reproduction
Reproduce #3178 through configuration parsing, provider registry resolution, and real session creation. The unique omp-acp ID succeeds, while omp keeps the built-in RPC runtime despite extends: acp and times out. This is an opt-in diagnosis test, with no production behavior changes.

Co-authored-by: Lorenzo Fiore <fiorelorenzo.fl@gmail.com>
2026-10-11 23:55:40 +02:00
paseo-bot[bot]andX b3693b79d1 Find hidden agent plan files in workspace suggestions (#6641)
* fix(server): find hidden agent plan files in workspace suggestions

Workspace autocomplete skipped the editor's plan directory while traversing
other known agent directories. Include it in the existing discovery policy
and cover basename and partial-path queries through the daemon client.

Co-authored-by: X <X@16x.org>

* test(server): give plan suggestion queries explicit expectations

---------

Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
Co-authored-by: X <X@16x.org>
2026-10-11 21:54:46 +02:00
4 changed files with 96 additions and 74 deletions
@@ -0,0 +1,52 @@
import { mkdtemp, mkdir, rm } from "node:fs/promises";
import path from "node:path";
import { expect, test } from "vitest";
import { ProviderOverridesSchema } from "@getpaseo/protocol/provider-config";
import { createTestLogger } from "../../test-utils/test-logger.js";
import { buildProviderRegistry } from "./provider-registry.js";
import type { AgentSession } from "./agent-sdk-types.js";
// Retained reproduction for #3178, awaiting the built-in ID configuration decision.
// Requires OMP on PATH (or OMP_COMMAND). Uses no model calls or existing provider state.
const runReproduction = process.env.OMP_PROVIDER_COLLISION_REPRO === "1";
for (const providerId of ["omp-acp", "omp"]) {
test.skipIf(!runReproduction)(
`explicit ACP configuration creates an ACP session under '${providerId}'`,
async () => {
const cwd = await mkdtemp(path.join(process.cwd(), ".provider-collision-"));
const agentDir = path.join(cwd, "agent");
await mkdir(agentDir);
const providerOverrides = ProviderOverridesSchema.parse({
[providerId]: {
extends: "acp",
label: "Oh My Pi ACP",
command: [process.env.OMP_COMMAND ?? "omp", "acp"],
enabled: true,
env: {
PI_CODING_AGENT_DIR: agentDir,
OMP_PROFILE: "default",
PI_PROFILE: "default",
XDG_CONFIG_HOME: path.join(cwd, "config"),
XDG_DATA_HOME: path.join(cwd, "data"),
XDG_CACHE_HOME: path.join(cwd, "cache"),
XDG_STATE_HOME: path.join(cwd, "state"),
},
},
});
const logger = createTestLogger();
const registry = buildProviderRegistry(logger, { providerOverrides });
const client = registry[providerId]!.createClient(logger);
let session: AgentSession | undefined;
try {
session = await client.createSession({ provider: providerId, cwd });
expect(session.provider).toBe(providerId);
} finally {
await session?.close();
await client.shutdown?.();
await rm(cwd, { recursive: true, force: true });
}
},
30_000,
);
}
@@ -23,6 +23,49 @@ afterEach(async () => {
}, 60000);
describe("file explorer", () => {
test.each([
{
query: "implementation",
expectedPaths: [
".cursor/plans/implementation-plan.md",
".codex/plans/implementation-plan.md",
".claude/plans/implementation-plan.md",
],
},
{
query: ".cursor/plans/implementation",
expectedPaths: [".cursor/plans/implementation-plan.md"],
},
])(
"workspace suggestions find hidden agent plans for '$query'",
async ({ query, expectedPaths }) => {
const cwd = tmpCwd();
try {
for (const directory of [".cursor", ".codex", ".claude", ".hidden"]) {
mkdirSync(path.join(cwd, directory, "plans"), { recursive: true });
writeFileSync(path.join(cwd, directory, "plans", "implementation-plan.md"), "plan\n");
}
const response = await ctx.client.getDirectorySuggestions({
cwd,
query,
limit: 50,
includeFiles: true,
includeDirectories: true,
});
expect(response.error).toBeNull();
expect(response.entries).toHaveLength(expectedPaths.length);
expect(response.entries).toEqual(
expect.arrayContaining(
expectedPaths.map((entryPath) => ({ path: entryPath, kind: "file" })),
),
);
} finally {
rmSync(cwd, { recursive: true, force: true });
}
},
);
test.each(["..", "..."])("supports file operations on names starting with %s", async (prefix) => {
const cwd = tmpCwd();
const fileName = `${prefix}notes.txt`;
@@ -146,6 +146,7 @@ export const WORKSPACE_SEARCH_HIDDEN_DIRECTORIES = [
".agents",
".claude",
".codex",
".cursor",
".github",
".opencode",
".paseo",
@@ -1,74 +0,0 @@
import { execFileSync } from "node:child_process";
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { expect, it } from "vitest";
import { getCheckoutDiff } from "./checkout-git.js";
import { diffFileChangeKind } from "../../../app/src/git/file-header-presentation";
import { createGitMetadataGenerator } from "../server/session/checkout/git-metadata-generator.js";
it.each(["rename", "copy"])(
"preserves %s status for Changes and metadata prompts",
async (operation) => {
const cwd = mkdtempSync(join(tmpdir(), "paseo-rename-status-"));
const git = (...args: string[]) => execFileSync("git", args, { cwd, encoding: "utf8" });
try {
git("init", "-b", "main");
git("config", "user.name", "Test");
git("config", "user.email", "test@example.com");
const content = Array.from({ length: 30 }, (_, i) => `line ${i}`).join("\n") + "\n";
writeFileSync(join(cwd, "a.txt"), content);
git("add", "a.txt");
git("-c", "commit.gpgsign=false", "commit", "-m", "Initial");
git("checkout", "-b", "feature");
if (operation === "rename") git("mv", "a.txt", "b.txt");
else {
git("config", "diff.renames", "copies");
writeFileSync(join(cwd, "b.txt"), content);
writeFileSync(join(cwd, "a.txt"), content + "extra\n");
git("add", "a.txt", "b.txt");
}
const status = git("diff", "--cached", "--name-status");
expect(status).toContain(`${operation === "rename" ? "R" : "C"}100\ta.txt\tb.txt`);
for (const mode of ["uncommitted", "base"] as const) {
if (mode === "base") git("-c", "commit.gpgsign=false", "commit", "-m", operation);
const diff = await getCheckoutDiff(cwd, {
mode,
baseRef: mode === "base" ? "main" : undefined,
includeStructured: true,
});
const file = diff.structured!.find((file) => file.path === "b.txt")!;
let prompt = "";
const generator = createGitMetadataGenerator({
workspaceGitService: {
getCheckoutDiff: async () => diff,
resolveRepoRoot: async () => cwd,
},
generation: {
generate: async <T>(request: { prompt: string }): Promise<T> => {
prompt = request.prompt;
return { message: "Diagnostic", title: "Diagnostic", body: "Diagnostic" } as T;
},
},
});
if (mode === "base") await generator.generatePullRequestText(cwd, "main");
else await generator.generateCommitMessage(cwd);
console.log(
JSON.stringify({
operation,
mode,
status: status.trim(),
file,
changeKind: diffFileChangeKind(file),
fileList: prompt.split("\n").filter((line) => /^[ADMRC]\t/.test(line)),
}),
);
expect(file.oldPath).toBe("a.txt");
expect.soft(diffFileChangeKind(file)).toBe(operation === "rename" ? "renamed" : "copied");
expect.soft(prompt).toContain(`${operation === "rename" ? "R" : "C"}\ta.txt\tb.txt`);
}
} finally {
rmSync(cwd, { recursive: true, force: true });
}
},
);