Skip to content

Commit 691bc46

Browse files
author
buihongduc132
committed
Merge upstream/main into main — 142 upstream commits + 42 local commits
Integrates upstream features: - Kiro CLI integration (backnotprop#837) - Amp plugin (backnotprop#803) - Droid slash-command (backnotprop#787) - Ask AI for plan/annotate reviews (backnotprop#763) - PLANNOTATOR_DATA_DIR env var (backnotprop#795) - Queue plan approval continuation (backnotprop#805) - Mermaid block sizing/zoom fixes (backnotprop#819) - Safari copy fix (backnotprop#785) - Update notification with toast (backnotprop#838+) - Versions 0.19.18 → 0.19.26 Preserves local fork work: - Multi-session server parity - SPA routing fixes - PLANNOTATOR_SERVER_URL support - 404 guard endpoints - plannotator-last-message command - Test coverage improvements
2 parents f7f2ab7 + a6fb2f5 commit 691bc46

161 files changed

Lines changed: 8673 additions & 1483 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.factory-plugin/marketplace.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"name": "plannotator",
3+
"description": "Plannotator slash commands for Droid.",
4+
"owner": {
5+
"name": "backnotprop"
6+
},
7+
"plugins": [
8+
{
9+
"name": "plannotator",
10+
"source": "./apps/droid-plugin",
11+
"description": "Interactive code review and annotation slash commands for Droid. No plan-mode integration."
12+
}
13+
]
14+
}

.github/workflows/deploy.yml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ on:
88
- 'apps/marketing/**'
99
- 'apps/portal/**'
1010
- 'apps/paste-service/**'
11+
- 'apps/waitlist-service/**'
1112
- 'packages/**'
1213
workflow_dispatch:
1314
inputs:
@@ -21,6 +22,7 @@ on:
2122
- marketing
2223
- portal
2324
- paste
25+
- waitlist
2426

2527
permissions:
2628
contents: read
@@ -32,6 +34,7 @@ jobs:
3234
marketing: ${{ steps.changes.outputs.marketing }}
3335
portal: ${{ steps.changes.outputs.portal }}
3436
paste: ${{ steps.changes.outputs.paste }}
37+
waitlist: ${{ steps.changes.outputs.waitlist }}
3538
steps:
3639
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
3740

@@ -54,13 +57,19 @@ jobs:
5457
else
5558
echo "paste=false" >> $GITHUB_OUTPUT
5659
fi
60+
if [[ "${{ inputs.target }}" == "all" || "${{ inputs.target }}" == "waitlist" ]]; then
61+
echo "waitlist=true" >> $GITHUB_OUTPUT
62+
else
63+
echo "waitlist=false" >> $GITHUB_OUTPUT
64+
fi
5765
else
5866
# For push events, check what changed
5967
git fetch origin ${{ github.event.before }} --depth=1 2>/dev/null || true
6068
6169
MARKETING_CHANGED=$(git diff --name-only ${{ github.event.before }} ${{ github.sha }} 2>/dev/null | grep -E '^(apps/marketing/|packages/)' || true)
6270
PORTAL_CHANGED=$(git diff --name-only ${{ github.event.before }} ${{ github.sha }} 2>/dev/null | grep -E '^(apps/portal/|packages/)' || true)
6371
PASTE_CHANGED=$(git diff --name-only ${{ github.event.before }} ${{ github.sha }} 2>/dev/null | grep -E '^apps/paste-service/' || true)
72+
WAITLIST_CHANGED=$(git diff --name-only ${{ github.event.before }} ${{ github.sha }} 2>/dev/null | grep -E '^apps/waitlist-service/' || true)
6473
6574
if [[ -n "$MARKETING_CHANGED" ]]; then
6675
echo "marketing=true" >> $GITHUB_OUTPUT
@@ -79,6 +88,12 @@ jobs:
7988
else
8089
echo "paste=false" >> $GITHUB_OUTPUT
8190
fi
91+
92+
if [[ -n "$WAITLIST_CHANGED" ]]; then
93+
echo "waitlist=true" >> $GITHUB_OUTPUT
94+
else
95+
echo "waitlist=false" >> $GITHUB_OUTPUT
96+
fi
8297
fi
8398
8499
deploy-marketing:
@@ -178,3 +193,27 @@ jobs:
178193
env:
179194
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
180195
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
196+
197+
deploy-waitlist:
198+
needs: detect-changes
199+
if: needs.detect-changes.outputs.waitlist == 'true'
200+
runs-on: ubuntu-latest
201+
permissions:
202+
contents: read
203+
environment: production
204+
steps:
205+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
206+
207+
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
208+
with:
209+
bun-version: latest
210+
211+
- name: Install dependencies
212+
run: bun install
213+
214+
- name: Deploy to Cloudflare
215+
working-directory: apps/waitlist-service
216+
run: npx wrangler deploy
217+
env:
218+
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
219+
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}

.github/workflows/release.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,37 @@ jobs:
305305
# 3. annotate: exercises annotate server startup with a real file.
306306
Test-PlannotatorServer "plannotator annotate" "19501" "/api/plan" @("annotate", "README.md")
307307
308+
pi-extension-ai-runtime-windows:
309+
needs: test
310+
# Exercises the Pi extension's Node/jiti server mirror on Windows with an
311+
# npm-style `pi` shim pair. The binary smoke above covers the compiled Bun
312+
# CLI, but the published Pi extension uses this separate Node path.
313+
name: Pi extension AI runtime (Windows)
314+
runs-on: windows-latest
315+
steps:
316+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
317+
318+
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
319+
with:
320+
bun-version: 1.3.11
321+
322+
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
323+
with:
324+
node-version: 24
325+
326+
- name: Install dependencies
327+
run: bun install
328+
329+
- name: Generate Pi extension shared copies
330+
shell: bash
331+
run: bash apps/pi-extension/vendor.sh
332+
333+
- name: Build Pi AI runtime smoke
334+
run: bun build scripts/smoke-pi-extension-ai-runtime.ts --target=node --outfile "$env:RUNNER_TEMP/pi-ai-runtime-smoke.mjs"
335+
336+
- name: Run Pi AI runtime smoke
337+
run: node "$env:RUNNER_TEMP/pi-ai-runtime-smoke.mjs"
338+
308339
install-script-smoke:
309340
needs: build
310341
runs-on: ${{ matrix.os }}
@@ -461,6 +492,7 @@ jobs:
461492
needs:
462493
- build
463494
- smoke-binaries
495+
- pi-extension-ai-runtime-windows
464496
- install-script-smoke
465497
if: startsWith(github.ref, 'refs/tags/')
466498
runs-on: ubuntu-latest
@@ -527,6 +559,7 @@ jobs:
527559
needs:
528560
- build
529561
- smoke-binaries
562+
- pi-extension-ai-runtime-windows
530563
- install-script-smoke
531564
runs-on: ubuntu-latest
532565
permissions:

.github/workflows/test.yml

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,37 @@ jobs:
3131
- name: Run tests
3232
run: bun test
3333

34+
pi-extension-ai-runtime-windows:
35+
# Exercises the Pi extension's Node/jiti server mirror on Windows with an
36+
# npm-style `pi` shim pair. This catches regressions where `where pi`
37+
# resolves the extensionless shim before pi.cmd and the Ask AI provider
38+
# crashes before the plan review UI opens.
39+
name: Pi extension AI runtime (Windows)
40+
runs-on: windows-latest
41+
steps:
42+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
43+
44+
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
45+
with:
46+
bun-version: latest
47+
48+
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
49+
with:
50+
node-version: 24
51+
52+
- name: Install dependencies
53+
run: bun install
54+
55+
- name: Generate Pi extension shared copies
56+
shell: bash
57+
run: bash apps/pi-extension/vendor.sh
58+
59+
- name: Build Pi AI runtime smoke
60+
run: bun build scripts/smoke-pi-extension-ai-runtime.ts --target=node --outfile "$env:RUNNER_TEMP/pi-ai-runtime-smoke.mjs"
61+
62+
- name: Run Pi AI runtime smoke
63+
run: node "$env:RUNNER_TEMP/pi-ai-runtime-smoke.mjs"
64+
3465
install-cmd-windows:
3566
# End-to-end integration test for scripts/install.cmd on real cmd.exe.
3667
# The unit tests in scripts/install.test.ts are file-content string checks
@@ -297,3 +328,57 @@ jobs:
297328
throw "install.cmd exited $($p.ExitCode) but not via the unknown-flag guard. Expected 'Unknown option:' in stderr but got: $stderr"
298329
}
299330
Write-Host "✓ Unknown flag rejected with exit code $($p.ExitCode) via the unknown-flag guard"
331+
332+
install-ps1-windows:
333+
# End-to-end integration test for scripts/install.ps1 on real PowerShell.
334+
# This specifically covers PLANNOTATOR_DATA_DIR tilde expansion because
335+
# installer config lookup happens before any shared runtime code is loaded.
336+
name: install.ps1 (Windows integration)
337+
runs-on: windows-latest
338+
steps:
339+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
340+
341+
- name: Run install.ps1 end-to-end
342+
shell: pwsh
343+
run: .\scripts\install.ps1 v0.17.1 -SkipAttestation
344+
345+
- name: Config opt-in resolves PLANNOTATOR_DATA_DIR tilde paths
346+
shell: pwsh
347+
run: |
348+
$configDir = Join-Path $env:USERPROFILE "plannotator-ci-config"
349+
New-Item -ItemType Directory -Force -Path $configDir | Out-Null
350+
Set-Content -Path (Join-Path $configDir "config.json") -Value '{ "verifyAttestation": true }' -NoNewline
351+
352+
$installedBinary = "$env:LOCALAPPDATA\plannotator\plannotator.exe"
353+
if (-not (Test-Path $installedBinary)) {
354+
throw "Expected $installedBinary to exist from the earlier install.ps1 step, but it's missing."
355+
}
356+
$baselineHash = (Get-FileHash $installedBinary -Algorithm SHA256).Hash
357+
$baselineWriteTime = (Get-Item $installedBinary).LastWriteTime
358+
359+
$env:PLANNOTATOR_DATA_DIR = '~\plannotator-ci-config'
360+
$stderrFile = New-TemporaryFile
361+
$p = Start-Process -Wait -PassThru -NoNewWindow pwsh `
362+
-ArgumentList '-NoProfile','-ExecutionPolicy','Bypass','-File','.\scripts\install.ps1','v0.17.1' `
363+
-RedirectStandardError $stderrFile.FullName
364+
$stderr = Get-Content $stderrFile.FullName -Raw -ErrorAction SilentlyContinue
365+
Remove-Item $stderrFile.FullName -ErrorAction SilentlyContinue
366+
367+
if ($p.ExitCode -eq 0) {
368+
throw "install.ps1 should have found config.json via PLANNOTATOR_DATA_DIR=~\plannotator-ci-config and rejected v0.17.1, but exited 0."
369+
}
370+
if ($stderr -notmatch 'predates') {
371+
throw "install.ps1 exited $($p.ExitCode), but not via the expected attestation pre-flight. Expected 'predates' in stderr, got: $stderr"
372+
}
373+
374+
$postHash = (Get-FileHash $installedBinary -Algorithm SHA256).Hash
375+
$postWriteTime = (Get-Item $installedBinary).LastWriteTime
376+
if ($postHash -ne $baselineHash) {
377+
throw "Binary at $installedBinary was overwritten during the rejected config-driven verifyAttestation run."
378+
}
379+
if ($postWriteTime -ne $baselineWriteTime) {
380+
throw "Binary at $installedBinary had its LastWriteTime modified during the rejected config-driven verifyAttestation run."
381+
}
382+
383+
Write-Host "✓ PLANNOTATOR_DATA_DIR tilde expansion found config.json"
384+
Write-Host "✓ Config-driven verifyAttestation rejected before download/install"

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ opencode.json
5252
plannotator-local
5353
# Local research/reference docs (not for repo)
5454
/reference/
55+
/Plannotator Waitlist Signup/
5556
# Local goal setup packages generated by the setup-goal skill.
5657
/goals/
5758
*.bun-build

AGENTS.md

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,18 @@ plannotator/
1818
│ │ ├── index.ts # Plugin entry with submit_plan tool + review/annotate event handlers
1919
│ │ ├── plannotator.html # Built plan review app
2020
│ │ └── review-editor.html # Built code review app
21+
│ ├── amp-plugin/ # Amp plugin
22+
│ │ ├── plannotator.ts # Native Amp command-palette integration
23+
│ │ └── README.md # Install and local development notes
24+
│ ├── droid-plugin/ # Droid plugin
25+
│ │ ├── .factory-plugin/plugin.json
26+
│ │ ├── commands/ # Slash command entrypoints
27+
│ │ └── lib/ # Shared command wrapper helpers
2128
│ ├── marketing/ # Marketing site, docs, and blog (plannotator.ai)
2229
│ │ └── astro.config.mjs # Astro 5 static site with content collections
30+
│ ├── kiro-cli/ # Kiro CLI integration source (consumed by scripts/install.sh; auto-detected via ~/.kiro)
31+
│ │ ├── agents/plannotator.json # Example Kiro custom agent
32+
│ │ └── skills/ # Kiro-specific skill packages (review, annotate, archive); setup-goal + visual-explainer install from apps/skills
2333
│ ├── paste-service/ # Paste service for short URL sharing
2434
│ │ ├── core/ # Platform-agnostic logic (handler, storage interface, cors)
2535
│ │ ├── stores/ # Storage backends (fs, kv, s3)
@@ -121,9 +131,10 @@ claude --plugin-dir ./apps/hook
121131
| `PLANNOTATOR_SHARE` | Set to `disabled` to turn off URL sharing entirely. Default: enabled. |
122132
| `PLANNOTATOR_SHARE_URL` | Custom base URL for share links (self-hosted portal). Default: `https://share.plannotator.ai`. |
123133
| `PLANNOTATOR_PASTE_URL` | Base URL of the paste service API for short URL sharing. Default: `https://plannotator-paste.plannotator.workers.dev`. |
124-
| `PLANNOTATOR_ORIGIN` | Explicit agent-origin override at the top of the detection chain. Valid values: `claude-code`, `opencode`, `codex`, `copilot-cli`, `gemini-cli`. Invalid values silently fall through to env-based detection. Unset by default. |
134+
| `PLANNOTATOR_ORIGIN` | Explicit agent-origin override at the top of the detection chain. Valid values: `claude-code`, `amp`, `droid`, `opencode`, `codex`, `copilot-cli`, `gemini-cli`, `kiro-cli`, `pi`. Invalid values silently fall through to env-based detection. Unset by default. |
125135
| `PLANNOTATOR_JINA` | Set to `0` / `false` to disable Jina Reader for URL annotation, or `1` / `true` to enable. Default: enabled. Can also be set via `~/.plannotator/config.json` (`{ "jina": false }`) or per-invocation via `--no-jina`. |
126136
| `JINA_API_KEY` | Optional Jina Reader API key for higher rate limits (500 RPM vs 20 RPM unauthenticated). Free keys include 10M tokens. |
137+
| `PLANNOTATOR_DATA_DIR` | Override the base data directory. Supports `~` expansion. Default: `~/.plannotator`. All data (plans, history, drafts, config, hooks, sessions, debug logs, IPC registry) is stored under this directory. |
127138
| `PLANNOTATOR_VERIFY_ATTESTATION` | **Read by the install scripts only**, not by the runtime binary. Set to `1` / `true` to have `scripts/install.sh` / `install.ps1` / `install.cmd` run `gh attestation verify` on every install. Off by default. Can also be set persistently via `~/.plannotator/config.json` (`{ "verifyAttestation": true }`) or per-invocation via `--verify-attestation`. Requires `gh` installed and authenticated. |
128139

129140
**Config-only settings (`~/.plannotator/config.json`)**: Some settings have no env-var equivalent and are toggled by editing the config file directly:
@@ -173,6 +184,23 @@ Send Feedback → feedback sent to agent session
173184
Approve → "LGTM" sent to agent session
174185
```
175186

187+
## Ask AI Provider Defaults
188+
189+
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`:
190+
191+
| Origin | Preferred Ask AI provider |
192+
|--------|---------------------------|
193+
| `claude-code` | `claude-agent-sdk` |
194+
| `amp` | no dedicated provider; fallback to saved/server default |
195+
| `droid` | no dedicated provider; fallback to saved/server default |
196+
| `codex` | `codex-sdk` |
197+
| `opencode` | `opencode-sdk` |
198+
| `pi` | `pi-sdk` |
199+
| `copilot-cli` | no dedicated provider; fallback to saved/server default |
200+
| `gemini-cli` | no dedicated provider; fallback to saved/server default |
201+
202+
Per-origin choices are persisted in cookies, so a user can override the automatic match for one agent without changing the default for another.
203+
176204
## Annotate Flow
177205

178206
```
@@ -235,6 +263,12 @@ During normal plan review, an Archive sidebar tab provides the same browsing via
235263
| `/api/draft` | GET/POST/DELETE | Auto-save annotation drafts to survive server crashes |
236264
| `/api/editor-annotations` | GET | List editor annotations (VS Code only) |
237265
| `/api/editor-annotation` | POST/DELETE | Add or remove an editor annotation (VS Code only) |
266+
| `/api/ai/capabilities` | GET | Check if AI features are available |
267+
| `/api/ai/session` | POST | Create or fork an AI session |
268+
| `/api/ai/query` | POST | Send a message and stream the response (SSE) |
269+
| `/api/ai/abort` | POST | Abort the current query |
270+
| `/api/ai/permission` | POST | Respond to a permission request |
271+
| `/api/ai/sessions` | GET | List active sessions |
238272
| `/api/external-annotations/stream` | GET | SSE stream for real-time external annotations |
239273
| `/api/external-annotations` | GET | Snapshot of external annotations (polling fallback, `?since=N` for version gating) |
240274
| `/api/external-annotations` | POST | Add external annotations (single or batch `{ annotations: [...] }`) |
@@ -293,6 +327,12 @@ During normal plan review, an Archive sidebar tab provides the same browsing via
293327
| `/api/doc` | GET | Serve linked .md/.mdx/.html file or code file (`?path=<path>&base=<dir>`) |
294328
| `/api/doc/exists` | POST | Batch-validate code-file paths (body: `{ paths: string[], base?: string }`) |
295329
| `/api/draft` | GET/POST/DELETE | Auto-save annotation drafts to survive server crashes |
330+
| `/api/ai/capabilities` | GET | Check if AI features are available |
331+
| `/api/ai/session` | POST | Create or fork an AI session |
332+
| `/api/ai/query` | POST | Send a message and stream the response (SSE) |
333+
| `/api/ai/abort` | POST | Abort the current query |
334+
| `/api/ai/permission` | POST | Respond to a permission request |
335+
| `/api/ai/sessions` | GET | List active sessions |
296336
| `/api/external-annotations/stream` | GET | SSE stream for real-time external annotations |
297337
| `/api/external-annotations` | GET | Snapshot of external annotations (polling fallback, `?since=N` for version gating) |
298338
| `/api/external-annotations` | POST | Add external annotations (single or batch `{ annotations: [...] }`) |

0 commit comments

Comments
 (0)