Skip to content

Commit 7f71857

Browse files
committed
fix(path): reject whitespace-only user paths and run vendor before typecheck
resolveUserPath() trims input, so whitespace-only customPath/vaultPath resolved to process.cwd(). Plans silently wrote into the repo root and Obsidian notes landed in <cwd>/plannotator/ instead of erroring. Guard at both call sites (getPlanDir, saveToObsidian — Bun + Pi copies). Also prepend vendor.sh to the root typecheck script so fresh-clone `bun run typecheck` works without a separate vendoring step. For provenance purposes, this commit was AI assisted.
1 parent 1cadd96 commit 7f71857

5 files changed

Lines changed: 15 additions & 2 deletions

File tree

apps/pi-extension/server/integrations.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ export async function saveToObsidian(
112112
): Promise<IntegrationResult> {
113113
try {
114114
const { vaultPath, folder, plan } = config;
115+
if (!vaultPath?.trim()) {
116+
return { success: false, error: "Vault path is required" };
117+
}
115118
const normalizedVault = resolveUserPath(vaultPath);
116119
if (!existsSync(normalizedVault))
117120
return {

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
"build:vscode": "bun run --cwd apps/vscode-extension build",
3131
"package:vscode": "bun run --cwd apps/vscode-extension package",
3232
"test": "bun test",
33-
"typecheck": "tsc --noEmit -p packages/shared/tsconfig.json && tsc --noEmit -p packages/ai/tsconfig.json && tsc --noEmit -p packages/server/tsconfig.json && tsc --noEmit -p apps/pi-extension/tsconfig.json"
33+
"typecheck": "bash apps/pi-extension/vendor.sh && tsc --noEmit -p packages/shared/tsconfig.json && tsc --noEmit -p packages/ai/tsconfig.json && tsc --noEmit -p packages/server/tsconfig.json && tsc --noEmit -p apps/pi-extension/tsconfig.json"
3434
},
3535
"dependencies": {
3636
"@anthropic-ai/claude-agent-sdk": "^0.2.92",

packages/server/integrations.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ export async function saveToObsidian(
9999
try {
100100
const { vaultPath, folder, plan } = config;
101101

102+
if (!vaultPath?.trim()) {
103+
return { success: false, error: "Vault path is required" };
104+
}
105+
102106
const normalizedVault = resolveUserPath(vaultPath);
103107

104108
// Validate vault path exists and is a directory

packages/server/storage.test.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,12 @@ describe("getPlanDir", () => {
7575
const result = getPlanDir(null);
7676
expect(result).toMatch(/\.plannotator\/plans$/);
7777
});
78+
79+
test("uses default for whitespace-only custom path", () => {
80+
const result = getPlanDir(" ");
81+
expect(result).toMatch(/\.plannotator\/plans$/);
82+
expect(result).not.toBe(process.cwd());
83+
});
7884
});
7985

8086
describe("savePlan", () => {

packages/shared/storage.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { resolveUserPath } from "./resolve-file";
2121
export function getPlanDir(customPath?: string | null): string {
2222
let planDir: string;
2323

24-
if (customPath) {
24+
if (customPath?.trim()) {
2525
planDir = resolveUserPath(customPath);
2626
} else {
2727
planDir = join(homedir(), ".plannotator", "plans");

0 commit comments

Comments
 (0)