From 4b705d4f98b3f1616ef79a741de479fd0e2c86ed Mon Sep 17 00:00:00 2001 From: Julien Fernandez Date: Thu, 12 Mar 2026 16:04:21 +0100 Subject: [PATCH 1/3] fix: strip @ prefix from file paths and add @plannotator/shared vite alias - resolve-file.ts: strip leading @ (coding agent file reference syntax) - pi-extension/index.ts: strip @ prefix + remove interactive file prompt - vite configs: add @plannotator/shared alias to fix build --- apps/hook/vite.config.ts | 1 + apps/pi-extension/index.ts | 10 +++------- apps/portal/vite.config.ts | 1 + apps/review/vite.config.ts | 1 + packages/server/resolve-file.test.ts | 20 ++++++++++++++++++++ packages/server/resolve-file.ts | 4 ++++ 6 files changed, 30 insertions(+), 7 deletions(-) diff --git a/apps/hook/vite.config.ts b/apps/hook/vite.config.ts index 5577f88e..2613522e 100644 --- a/apps/hook/vite.config.ts +++ b/apps/hook/vite.config.ts @@ -21,6 +21,7 @@ export default defineConfig({ '@plannotator/ui': path.resolve(__dirname, '../../packages/ui'), '@plannotator/editor/styles': path.resolve(__dirname, '../../packages/editor/index.css'), '@plannotator/editor': path.resolve(__dirname, '../../packages/editor/App.tsx'), + '@plannotator/shared': path.resolve(__dirname, '../../packages/shared'), } }, build: { diff --git a/apps/pi-extension/index.ts b/apps/pi-extension/index.ts index 1c8e724b..12c01f15 100644 --- a/apps/pi-extension/index.ts +++ b/apps/pi-extension/index.ts @@ -182,12 +182,6 @@ export default function plannotator(pi: ExtensionAPI): void { // Accept path as argument: /plannotator plans/auth.md let targetPath = args?.trim() || undefined; - // No arg — prompt for file path interactively - if (!targetPath && ctx.hasUI) { - targetPath = await ctx.ui.input("Plan file path", planFilePath); - if (targetPath === undefined) return; // cancelled - } - if (targetPath) planFilePath = targetPath; enterPlanning(ctx); }, @@ -275,7 +269,9 @@ export default function plannotator(pi: ExtensionAPI): void { return; } - const absolutePath = resolve(ctx.cwd, filePath); + // Strip leading @ (Pi file reference syntax) + const cleanPath = filePath.startsWith("@") ? filePath.slice(1) : filePath; + const absolutePath = resolve(ctx.cwd, cleanPath); if (!existsSync(absolutePath)) { ctx.ui.notify(`File not found: ${absolutePath}`, "error"); return; diff --git a/apps/portal/vite.config.ts b/apps/portal/vite.config.ts index 822b099c..56e58e99 100644 --- a/apps/portal/vite.config.ts +++ b/apps/portal/vite.config.ts @@ -19,6 +19,7 @@ export default defineConfig({ '@plannotator/ui': path.resolve(__dirname, '../../packages/ui'), '@plannotator/editor/styles': path.resolve(__dirname, '../../packages/editor/index.css'), '@plannotator/editor': path.resolve(__dirname, '../../packages/editor/App.tsx'), + '@plannotator/shared': path.resolve(__dirname, '../../packages/shared'), } }, build: { diff --git a/apps/review/vite.config.ts b/apps/review/vite.config.ts index 72bedcb6..a4984cd6 100644 --- a/apps/review/vite.config.ts +++ b/apps/review/vite.config.ts @@ -20,6 +20,7 @@ export default defineConfig({ '@plannotator/ui': path.resolve(__dirname, '../../packages/ui'), '@plannotator/review-editor/styles': path.resolve(__dirname, '../../packages/review-editor/index.css'), '@plannotator/review-editor': path.resolve(__dirname, '../../packages/review-editor/App.tsx'), + '@plannotator/shared': path.resolve(__dirname, '../../packages/shared'), } }, build: { diff --git a/packages/server/resolve-file.test.ts b/packages/server/resolve-file.test.ts index 0cbced96..95a117ee 100644 --- a/packages/server/resolve-file.test.ts +++ b/packages/server/resolve-file.test.ts @@ -182,6 +182,26 @@ describe("resolveMarkdownFile", () => { }); }); + // @ prefix stripping (coding agent file references) + + test("strips leading @ from relative path", async () => { + const root = createTempProject({ "docs/analyse.md": "# Analyse" }); + const result = await resolveMarkdownFile("@docs/analyse.md", root); + expect(result).toEqual({ + kind: "found", + path: resolve(root, "docs/analyse.md"), + }); + }); + + test("strips leading @ from bare filename", async () => { + const root = createTempProject({ "plan.md": "# Plan" }); + const result = await resolveMarkdownFile("@plan.md", root); + expect(result).toEqual({ + kind: "found", + path: resolve(root, "plan.md"), + }); + }); + // Edge cases test("returns not_found for nonexistent file", async () => { diff --git a/packages/server/resolve-file.ts b/packages/server/resolve-file.ts index c1aa1cb6..0f5e34f0 100644 --- a/packages/server/resolve-file.ts +++ b/packages/server/resolve-file.ts @@ -137,6 +137,10 @@ export async function resolveMarkdownFile( ): Promise { // Trim whitespace/CR that may leak from Windows shell pipelines input = input.trim(); + // Strip leading @ (coding agent file reference syntax, e.g. @docs/file.md) + if (input.startsWith("@")) { + input = input.slice(1); + } const normalizedInput = normalizeMarkdownPathInput(input); const searchInput = normalizeSeparators(normalizedInput); const isBareFilename = !searchInput.includes("/"); From ed830775ad9477ea903edfbb33a30467cd5bd457 Mon Sep 17 00:00:00 2001 From: Julien Fernandez Date: Thu, 12 Mar 2026 16:06:36 +0100 Subject: [PATCH 2/3] chore: update bun.lock after upstream merge --- bun.lock | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bun.lock b/bun.lock index 858d55ef..f6b18204 100644 --- a/bun.lock +++ b/bun.lock @@ -1,5 +1,6 @@ { "lockfileVersion": 1, + "configVersion": 0, "workspaces": { "": { "name": "plannotator", @@ -50,7 +51,7 @@ }, "apps/opencode-plugin": { "name": "@plannotator/opencode", - "version": "0.11.4", + "version": "0.12.0", "dependencies": { "@opencode-ai/plugin": "^1.1.10", }, @@ -71,7 +72,7 @@ }, "apps/pi-extension": { "name": "@plannotator/pi-extension", - "version": "0.11.4", + "version": "0.12.0", "peerDependencies": { "@mariozechner/pi-coding-agent": ">=0.53.0", }, @@ -151,7 +152,7 @@ }, "packages/server": { "name": "@plannotator/server", - "version": "0.11.4", + "version": "0.12.0", "dependencies": { "@plannotator/shared": "workspace:*", }, From 023c36d772e975b4b630cdc6dfc6a1ead852b835 Mon Sep 17 00:00:00 2001 From: Julien Fernandez Date: Thu, 12 Mar 2026 17:19:38 +0100 Subject: [PATCH 3/3] feat: merge Send Feedback and Approve into single adaptive button MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the two separate action buttons (Send Feedback + Approve) with a single button that adapts based on annotation count: - Has annotations → Send Feedback (accent color, chat icon on mobile) - No annotations → Approve (green/success, OK on mobile) This simplifies the UI by removing the need for users to choose between two actions. The approve warning dialog is no longer needed since Approve only appears when there are no annotations to lose. Removed: - showApproveWarning state - ConfirmDialog for approve-with-annotations warning - Separate Approve button with hover tooltip --- packages/review-editor/App.tsx | 86 +++++++++------------------------- 1 file changed, 23 insertions(+), 63 deletions(-) diff --git a/packages/review-editor/App.tsx b/packages/review-editor/App.tsx index ab7bad57..d656308b 100644 --- a/packages/review-editor/App.tsx +++ b/packages/review-editor/App.tsx @@ -147,7 +147,6 @@ const ReviewApp: React.FC = () => { const [isSendingFeedback, setIsSendingFeedback] = useState(false); const [isApproving, setIsApproving] = useState(false); const [submitted, setSubmitted] = useState<'approved' | 'feedback' | false>(false); - const [showApproveWarning, setShowApproveWarning] = useState(false); const [sharingEnabled, setSharingEnabled] = useState(true); const [repoInfo, setRepoInfo] = useState<{ display: string; branch?: string } | null>(null); @@ -554,7 +553,7 @@ const ReviewApp: React.FC = () => { const tag = (e.target as HTMLElement)?.tagName; if (tag === 'INPUT' || tag === 'TEXTAREA') return; - if (showExportModal || showNoAnnotationsDialog || showApproveWarning) return; + if (showExportModal || showNoAnnotationsDialog) return; if (submitted || isSendingFeedback || isApproving) return; if (!origin) return; // Demo mode @@ -571,7 +570,7 @@ const ReviewApp: React.FC = () => { window.addEventListener('keydown', handleKeyDown); return () => window.removeEventListener('keydown', handleKeyDown); }, [ - showExportModal, showNoAnnotationsDialog, showApproveWarning, + showExportModal, showNoAnnotationsDialog, submitted, isSendingFeedback, isApproving, origin, totalAnnotationCount, handleApprove, handleSendFeedback ]); @@ -682,56 +681,33 @@ const ReviewApp: React.FC = () => { {origin ? ( <> - {/* Send Feedback button - accent color, disabled if no annotations */} + {/* Single action button: Send Feedback (if annotations) or Approve (if none) */} - - {/* Approve button - green/success, dimmed if annotations exist */} -
- - {totalAnnotationCount > 0 && ( -
-
-
- Your {totalAnnotationCount} annotation{totalAnnotationCount !== 1 ? 's' : ''} won't be sent if you approve. -
+ {totalAnnotationCount > 0 ? ( + <> + + + + {isSendingFeedback ? 'Sending...' : 'Send Feedback'} + + ) : ( + <> + {isApproving ? '...' : 'OK'} + {isApproving ? 'Approving...' : 'Approve'} + )} -
+ ) : (