Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
0216494
docs(adr): revert failed document-ui cutover, add ADR 004 with correc…
backnotprop Jun 23, 2026
69e0640
docs(adr): add verified document-ui extraction plan, supersede draft …
backnotprop Jun 23, 2026
a79e8c7
docs(adr): add document-ui extraction roadmap + parity checklist
backnotprop Jun 23, 2026
fec125e
build(ui): packaging unblock for external install (Phase 1) — no runt…
backnotprop Jun 23, 2026
a0e2051
feat(ui): make image URL resolution host-overridable (Phase 2, seam 1)
backnotprop Jun 23, 2026
fa81cb8
feat(ui): make settings storage backend host-overridable (Phase 2, se…
backnotprop Jun 23, 2026
ce46899
feat(ui): make MarkdownEditor theme mode host-supplyable (Phase 3)
backnotprop Jun 23, 2026
3f255d2
feat(ui): allow hosts to opt out of code-path validation (Phase 3)
backnotprop Jun 23, 2026
a38ba07
feat(ui): make code-file hover preview fetch host-overridable (Phase 3)
backnotprop Jun 23, 2026
da9ee4e
feat(ui): ship ScrollViewportProvider with the library (Phase 3 scroll)
backnotprop Jun 23, 2026
3d42972
fix(ui): disabled code-path validation should keep links clickable (s…
backnotprop Jun 23, 2026
ba21aea
feat(ui): make file-tree backend host-overridable (Phase 4)
backnotprop Jun 23, 2026
cfbdc37
docs(adr): research + synthesis + spec for Phase 5 (comments/annotati…
backnotprop Jun 23, 2026
162cf1d
docs(adr): accept ADR 005 — make comments/annotations/drafts host-ove…
backnotprop Jun 23, 2026
d31677d
feat(ui): make annotation identity host-overridable (Phase 5 seam 1)
backnotprop Jun 23, 2026
8555f15
feat(ui): make draft persistence transport host-overridable (Phase 5 …
backnotprop Jun 23, 2026
ba0e14e
feat(ui): make external-annotation transport host-overridable (Phase …
backnotprop Jun 23, 2026
fe39ccc
docs(adr): research + synthesis + spec for Phase 6 (versions, setting…
backnotprop Jun 23, 2026
8ddd951
docs(adr): accept ADR 006 — make extras (versions/settings/sharing/AI…
backnotprop Jun 23, 2026
47e2831
feat(ui): make version fetchers + vscode-diff host-overridable; move …
backnotprop Jun 23, 2026
228aa37
feat(ui): make config write-back + obsidian-detect host-overridable (…
backnotprop Jun 23, 2026
2b5f779
feat(ui): make save-to-notes host-overridable (Phase 6 sharing)
backnotprop Jun 23, 2026
387b127
feat(ui): make Ask AI transport host-overridable (Phase 6 ai)
backnotprop Jun 23, 2026
db94b7e
docs(adr): log Phase 6 completion (4 seams + diff CSS move)
backnotprop Jun 23, 2026
e74cc0b
docs(adr): research + synthesis + spec for Phase 7 (carve @plannotato…
backnotprop Jun 23, 2026
4589281
docs(adr): fold configurePlannotatorUI() front door + precompiled CSS…
backnotprop Jun 23, 2026
c312f16
docs(adr): lock Phase 7 publish decisions + carry over review fixes
backnotprop Jun 23, 2026
b413d05
docs(adr): ADR 007 — carve @plannotator/core, complete settings provi…
backnotprop Jun 23, 2026
64beb6e
fix(ui): make external-annotation transport reads consistent + reset …
backnotprop Jun 23, 2026
ec6fc90
docs(adr): align Phase 7 spec with ADR 007 (version 0.21.0 lockstep, …
backnotprop Jun 23, 2026
f5cf35e
feat(core): carve @plannotator/core — move pure modules, extract node…
backnotprop Jun 23, 2026
6323392
feat(ui): depend only on @plannotator/core — re-point all shared/ai i…
backnotprop Jun 23, 2026
d5760b3
refactor(ui): relocate wideMode helper to @plannotator/ui/utils (Phas…
backnotprop Jun 23, 2026
5c422d8
feat(ui): add loadFromBackend settings rehydration + configurePlannot…
backnotprop Jun 23, 2026
c9a0fe8
build(ui): precompiled styles.css CSS build + madge circular-dep chec…
backnotprop Jun 23, 2026
6b13715
test(ui): per-seam override tests + configure routing test (Phase 7 s…
backnotprop Jun 23, 2026
6130bad
fix(ui): apply Phase 7 review findings — version lockstep + seam cons…
backnotprop Jun 23, 2026
23df902
docs(adr): Phase 7 implementation plan (workflow-generated, durable a…
backnotprop Jun 23, 2026
2f673b1
fix(ui): reconcile #948 with the draft-transport seam + lockstep 0.21.1
backnotprop Jun 24, 2026
c7cc073
fix(ui): address review nits — host-path robustness + cleanups
backnotprop Jun 24, 2026
de00839
docs: collapse 29 ADR process docs into one packages/ui/README.md
backnotprop Jun 24, 2026
9359b5c
docs(ui): add packages/ui/AGENTS.md guardrail + CLAUDE.md symlink
backnotprop Jun 24, 2026
0fc3fcd
build: remove madge circular-dep check (unmaintained)
backnotprop Jun 24, 2026
98fdf09
fix(ui): address review — TDZ guard, html-viewer export, doc corrections
backnotprop Jun 24, 2026
ea01b34
build(ui): don't bundle fonts in published styles.css — app loads fon…
backnotprop Jun 24, 2026
701c0fd
fix(ui): build styles.css on prepack, not prepublishOnly (review #4)
backnotprop Jun 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,7 @@ plannotator-local

# Local Pi state/memory (not upstream)
/.pi/

# @plannotator/ui CSS build artifacts (generated by prepublishOnly — not committed)
packages/ui/styles.css
packages/ui/styles.js
7 changes: 5 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

A plan review UI for Claude Code that intercepts `ExitPlanMode` via hooks, letting users approve or request changes with annotated feedback. Also provides code review for git diffs and annotation of arbitrary markdown files.

> **Reusing the document UI (theme / markdown / editor / settings / comments / layout) in the commercial Workspaces app? Read `packages/ui/README.md` FIRST.** It explains the published `@plannotator/ui` + `@plannotator/core` packages and the host-override seams a host plugs its own backend into via `configurePlannotatorUI()`. A prior from-scratch reimplementation of this UI broke the app and was reverted — do **not** rebuild it or recreate `packages/document-ui`. Add a seam to `@plannotator/ui` instead, keep Plannotator's app unchanged, and never delete working code until a human confirms parity in the browser.

## Project Structure

```
Expand Down Expand Up @@ -81,7 +83,8 @@ plannotator/
│ │ ├── hooks/ # useAnnotationHighlighter.ts, useSharing.ts, usePlanDiff.ts, useSidebar.ts, useLinkedDoc.ts, useAnnotationDraft.ts, useCodeAnnotationDraft.ts, useArchive.ts
│ │ └── types.ts
│ ├── ai/ # Provider-agnostic AI backbone (providers, sessions, endpoints)
│ ├── shared/ # Shared types, utilities, and cross-runtime logic
│ ├── core/ # @plannotator/core — browser-safe, zero-dep universal slice (pure utils + types) shared by ui + shared; published so @plannotator/ui can be installed standalone. `shared` re-exports the moved modules via one-line shims so Plannotator is unchanged.
│ ├── shared/ # Node/git/server logic + cross-runtime types (re-exports browser-safe modules from @plannotator/core)
│ │ ├── storage.ts # Plan saving, version history, archive listing (node:fs only)
│ │ ├── draft.ts # Annotation draft persistence (node:fs only)
│ │ └── project.ts # Pure string helpers (sanitizeTag, extractRepoName, extractDirName)
Expand Down Expand Up @@ -194,7 +197,7 @@ Approve → "LGTM" sent to agent session

## Ask AI Provider Defaults

Ask AI providers are detected independently from installed/authenticated local CLIs, then the UI picks a default from the detected Plannotator origin. The mapping lives in `packages/shared/agents.ts` and is applied by `packages/ui/utils/aiProvider.ts`:
Ask AI providers are detected independently from installed/authenticated local CLIs, then the UI picks a default from the detected Plannotator origin. The mapping lives in `packages/core/agents.ts` (re-exported via the `packages/shared/agents.ts` shim) and is applied by `packages/ui/utils/aiProvider.ts`:

| Origin | Preferred Ask AI provider |
|--------|---------------------------|
Expand Down
32 changes: 30 additions & 2 deletions apps/pi-extension/vendor.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,29 @@ cd "$(dirname "$0")"
rm -rf generated
mkdir -p generated generated/ai/providers

for f in feedback-templates prompts review-core diff-paths cli-pagination jj-core vcs-core review-args storage draft project pr-types pr-provider pr-stack pr-github pr-gitlab checklist integrations-common repo reference-common favicon code-file resolve-file annotate-reference-roots-node config external-annotation agent-jobs agent-terminal worktree worktree-pool html-to-markdown html-assets html-assets-node url-to-markdown tour annotate-args at-reference review-workspace-node review-workspace pfm-reminder improvement-hooks code-nav data-dir semantic-diff-types semantic-diff source-save source-save-node workspace-status open-in-apps review-profiles; do
# Modules that MOVED to @plannotator/core — vendor the real impl from core.
for f in feedback-templates project favicon code-file external-annotation agent-jobs agent-terminal source-save open-in-apps; do
src="../../packages/core/$f.ts"
printf '// @generated — DO NOT EDIT. Source: packages/core/%s.ts\n' "$f" | cat - "$src" > "generated/$f.ts"
done

# Node-bound shared modules that now import types from @plannotator/core/*-types —
# vendor from shared, rewrite the bare core specifier to the flat relative path.
for f in config storage workspace-status; do
src="../../packages/shared/$f.ts"
printf '// @generated — DO NOT EDIT. Source: packages/shared/%s.ts\n' "$f" | cat - "$src" \
| sed "s|from ['\"]@plannotator/core/\\([^'\"]*\\)-types['\"]|from './\\1-types.js'|g" \
> "generated/$f.ts"
done

# Extracted type files those node-bound modules now depend on — vendor from core.
for f in config-types storage-types workspace-status-types; do
src="../../packages/core/$f.ts"
printf '// @generated — DO NOT EDIT. Source: packages/core/%s.ts\n' "$f" | cat - "$src" > "generated/$f.ts"
done

# Everything else in the original flat list stays sourced from packages/shared.
for f in prompts review-core diff-paths cli-pagination jj-core vcs-core review-args draft pr-types pr-provider pr-stack pr-github pr-gitlab checklist integrations-common repo reference-common resolve-file annotate-reference-roots-node worktree worktree-pool html-to-markdown html-assets html-assets-node url-to-markdown tour annotate-args at-reference review-workspace-node review-workspace pfm-reminder improvement-hooks code-nav data-dir semantic-diff-types semantic-diff source-save-node review-profiles; do
src="../../packages/shared/$f.ts"
printf '// @generated — DO NOT EDIT. Source: packages/shared/%s.ts\n' "$f" | cat - "$src" > "generated/$f.ts"
done
Expand Down Expand Up @@ -40,9 +62,15 @@ for f in tour-review; do
> "generated/$f.ts"
done

# Vendor the moved AI context types from core into generated/ai/.
printf '// @generated — DO NOT EDIT. Source: packages/core/ai-context.ts\n' \
| cat - "../../packages/core/ai-context.ts" > "generated/ai/ai-context.ts"

for f in index types provider session-manager endpoints context base-session; do
src="../../packages/ai/$f.ts"
printf '// @generated — DO NOT EDIT. Source: packages/ai/%s.ts\n' "$f" | cat - "$src" > "generated/ai/$f.ts"
printf '// @generated — DO NOT EDIT. Source: packages/ai/%s.ts\n' "$f" | cat - "$src" \
| sed "s|from ['\"]@plannotator/core/ai-context['\"]|from './ai-context.js'|g" \
> "generated/ai/$f.ts"
done

for f in claude-agent-sdk codex-sdk opencode-sdk command-path pi-sdk pi-sdk-node pi-events; do
Expand Down
37 changes: 29 additions & 8 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@
"build:vscode": "bun run --cwd apps/vscode-extension build",
"package:vscode": "bun run --cwd apps/vscode-extension package",
"test": "bun test",
"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 packages/ui/tsconfig.json && tsc --noEmit -p apps/pi-extension/tsconfig.json"
"typecheck": "bash apps/pi-extension/vendor.sh && tsc --noEmit -p packages/core/tsconfig.json && tsc --noEmit -p packages/shared/tsconfig.json && tsc --noEmit -p packages/ai/tsconfig.json && tsc --noEmit -p packages/server/tsconfig.json && tsc --noEmit -p packages/ui/tsconfig.json && tsc --noEmit -p apps/pi-extension/tsconfig.json",
"build:ui-css": "bun run --cwd packages/ui build:css"
},
"dependencies": {
"@anthropic-ai/claude-agent-sdk": "^0.2.92",
Expand Down
4 changes: 3 additions & 1 deletion packages/ai/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,7 @@
"./providers/opencode-sdk": "./providers/opencode-sdk.ts",
"./providers/pi-sdk-node": "./providers/pi-sdk-node.ts"
},
"dependencies": {}
"dependencies": {
"@plannotator/core": "workspace:*"
}
}
78 changes: 2 additions & 76 deletions packages/ai/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,82 +10,8 @@
// Context — what the AI session knows about
// ---------------------------------------------------------------------------

/** The surface the user is interacting with when they invoke AI. */
export type AIContextMode = "plan-review" | "code-review" | "annotate";

/**
* Describes the parent agent session that originally produced the plan or diff.
* Used to fork conversations with full history.
*/
export interface ParentSession {
/** Session ID from the host agent (e.g. Claude Code session UUID). */
sessionId: string;
/** Working directory the parent session was running in. */
cwd: string;
}

/**
* Snapshot of plan-review-specific context.
* Passed when AIContextMode is "plan-review".
*/
export interface PlanContext {
/** The full plan markdown as submitted by the agent. */
plan: string;
/** Previous plan version (if this is a resubmission). */
previousPlan?: string;
/** The version number in the plan's history. */
version?: number;
/** Total number of versions in the plan's history. */
totalVersions?: number;
/** Project/repository label used for plan history. */
project?: string;
/** Annotations the user has made so far (serialised for the prompt). */
annotations?: string;
}

/**
* Snapshot of code-review-specific context.
* Passed when AIContextMode is "code-review".
*/
export interface CodeReviewContext {
/** The unified diff patch. */
patch: string;
/** The specific file being discussed (if scoped). */
filePath?: string;
/** The line range being discussed (if scoped). */
lineRange?: { start: number; end: number; side: "old" | "new" };
/** The code snippet being discussed (if scoped). */
selectedCode?: string;
/** Summary of annotations the user has made. */
annotations?: string;
}

/**
* Snapshot of annotate-mode context.
* Passed when AIContextMode is "annotate".
*/
export interface AnnotateContext {
/** The markdown file content being annotated. */
content: string;
/** Path to the file on disk. */
filePath: string;
/** Source attribution shown in the UI, such as an original URL or filename. */
sourceInfo?: string;
/** True when the document was converted from HTML or a remote reader result. */
sourceConverted?: boolean;
/** Render mode for the annotated content. */
renderAs?: "markdown" | "html";
/** Summary of annotations the user has made. */
annotations?: string;
}

/**
* Union of mode-specific contexts, discriminated by `mode`.
*/
export type AIContext =
| { mode: "plan-review"; plan: PlanContext; parent?: ParentSession }
| { mode: "code-review"; review: CodeReviewContext; parent?: ParentSession }
| { mode: "annotate"; annotate: AnnotateContext; parent?: ParentSession };
import type { AIContext, AIContextMode, PlanContext, CodeReviewContext, AnnotateContext, ParentSession } from '@plannotator/core/ai-context';
export type { AIContext, AIContextMode, PlanContext, CodeReviewContext, AnnotateContext, ParentSession };

// ---------------------------------------------------------------------------
// Messages — what streams back from the AI
Expand Down
Loading