Skip to content

Commit 0933cb3

Browse files
committed
fix(artifacts L6): keep the exact pinned file name (Codex r4 QjVD)
Pin path resolution no longer trims the path: `.env ` and `.env` are different files, and trimming pinned and showed the sibling. A blank path is still refused. --- _Generated with `xum` • Model: `anthropic:claude-opus-5-5` • Thinking: `high` • Cost: `$158.12`_ <!-- mux-attribution: model=anthropic:claude-opus-5-5 thinking=high costs=158.12 -->
1 parent a7e46f2 commit 0933cb3

2 files changed

Lines changed: 22 additions & 2 deletions

File tree

‎src/node/services/pinnedArtifactFiles.test.ts‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,23 @@ describe("pinned workspace files", () => {
156156
).toEqual({ success: true, data: { path: "README.md" } });
157157
});
158158

159+
test("pins the exact file name, edge whitespace included", async () => {
160+
await fs.writeFile(path.join(checkout, ".env"), "plain");
161+
await fs.writeFile(path.join(checkout, ".env "), "trailing space");
162+
expect(await pinFile(context, { workspaceId: "ws", path: ".env " })).toEqual({
163+
success: true,
164+
data: { path: ".env " },
165+
});
166+
expect(await readPinnedFile(context, { workspaceId: "ws", path: ".env " })).toMatchObject({
167+
success: true,
168+
data: { status: "ok", content: "trailing space" },
169+
});
170+
// A blank path is still refused.
171+
expect(await pinFile(context, { workspaceId: "ws", path: " " })).toMatchObject({
172+
success: false,
173+
});
174+
});
175+
159176
test("multi-project workspaces have no pinned files", async () => {
160177
projects = [
161178
{ projectPath: "/a", projectName: "a" },

‎src/node/services/pinnedArtifactFiles.ts‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,9 @@ export function resolveCheckoutLocation(
8484
* checkout-relative POSIX path, or an error string.
8585
*/
8686
export function toPinnedRelativePath(root: string, inputPath: string): string | { error: string } {
87-
const trimmed = inputPath.trim();
87+
// The exact bytes: `.env ` and `.env` are different files (Review keeps edge whitespace).
88+
if (inputPath.trim().length === 0) return { error: "No file path given" };
89+
const trimmed = inputPath;
8890
const normalizedRoot = root.replace(/[\\/]+$/, "");
8991
let relPath = trimmed.replace(/\\/g, "/");
9092
if (path.isAbsolute(trimmed) || trimmed.startsWith("/")) {
@@ -218,7 +220,8 @@ function resolvePinInput(
218220
inputPath: string,
219221
relativeTo: "tool-cwd" | "checkout" | null | undefined
220222
): string {
221-
const trimmed = inputPath.trim();
223+
// Not trimmed: edge whitespace is part of the file name (see toPinnedRelativePath).
224+
const trimmed = inputPath;
222225
if (relativeTo !== "tool-cwd" || path.isAbsolute(trimmed) || trimmed.startsWith("/")) {
223226
return trimmed;
224227
}

0 commit comments

Comments
 (0)