2026-01-06 14:25:19 -08:00
|
|
|
{
|
|
|
|
|
"name": "@plannotator/server",
|
2026-07-30 03:15:51 -07:00
|
|
|
"version": "0.25.1",
|
2026-01-06 14:25:19 -08:00
|
|
|
"private": true,
|
|
|
|
|
"description": "Shared server implementation for Plannotator plugins",
|
|
|
|
|
"main": "index.ts",
|
|
|
|
|
"types": "index.ts",
|
2026-01-12 19:36:09 -08:00
|
|
|
"exports": {
|
|
|
|
|
".": "./index.ts",
|
|
|
|
|
"./review": "./review.ts",
|
feat: named image references and annotate command (#147)
* feat: named image references and annotate command (#67, #109)
Add human-readable names to image attachments throughout the annotation
pipeline, and add a new `plannotator annotate <file.md>` command for
annotating arbitrary markdown files.
Image names: ImageAttachment type replaces plain string paths, upload
endpoints return originalName, editable name inputs under thumbnails,
[name] path format in exported feedback, backward-compatible sharing.
Annotate command: new server module reusing plan editor HTML with
mode:"annotate", CLI subcommand, slash commands for Claude Code and
OpenCode, annotate mode UI (hides Approve, shows Send Annotations).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: move image name input to ImageAnnotator screen
The name input now appears on the full-screen annotator modal that opens
immediately when uploading/pasting an image, pre-populated from the
filename. Removes the disruptive inline name editing from thumbnails.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: stale closure in paste handler, update CLAUDE.md for new features
Fix race condition where globalAttachments was captured as empty array
in the paste event listener (missing dependency). Also update CLAUDE.md
to document ImageAttachment type, annotate server/flow, updated sharing
format with image support, and new slash commands.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 20:23:49 -08:00
|
|
|
"./annotate": "./annotate.ts",
|
2026-01-12 19:36:09 -08:00
|
|
|
"./remote": "./remote.ts",
|
|
|
|
|
"./browser": "./browser.ts",
|
2026-05-18 08:39:29 -07:00
|
|
|
"./goal-setup": "./goal-setup.ts",
|
2026-01-12 19:36:09 -08:00
|
|
|
"./storage": "./storage.ts",
|
2026-01-28 10:29:52 -08:00
|
|
|
"./git": "./git.ts",
|
feat: add Perforce (P4) pending changelist diff support (#472)
* feat: add Perforce pending changelist diff support for code review
Introduce P4 support alongside existing Git backend via a VCS dispatch
layer (vcs.ts). Detects Git vs Perforce workspace automatically and
routes diff/file-content operations to the appropriate backend.
- Add p4-default and p4-changelist:<N> DiffType variants
- Add P4 runtime (p4.ts): workspace detection with TTL cache, changelist
context, unified diff conversion, binary file exclusion, batch p4 where
- Add VCS dispatch layer (vcs.ts): auto-detect Git/P4, unified API
- Update review server and CLI entry point to use VCS dispatch
- Filter empty changelists from dropdown, disable staging for P4
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: introduce VcsProvider interface for extensible VCS support
Replace hardcoded Git/P4 dispatch with a provider-based architecture.
Each VCS implements VcsProvider interface and registers in a providers
array — adding a new VCS only requires implementing the interface.
- Define VcsProvider with detect, ownsDiffType, getContext, runDiff,
getFileContents, and optional stageFile/unstageFile/resolveCwd
- Create gitProvider and p4Provider as concrete implementations
- Replace isP4DiffType/gitAddFile/gitResetFile in review.ts with
provider-based canStageFiles/stageFile/unstageFile/resolveVcsCwd
- Remove VCS-specific branching from review server endpoints
Note: GitContext interface is not renamed to VcsContext in this commit.
The rename touches too many files across the codebase (Pi extension,
OpenCode plugin, shared types, tests) and should be handled as a
separate pull request to keep the diff reviewable.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: rtsummit <rtsummit@abutton.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 02:49:24 +09:00
|
|
|
"./p4": "./p4.ts",
|
|
|
|
|
"./vcs": "./vcs.ts",
|
Add short URL sharing via paste service to fix URL truncation (#188)
* Add short URL sharing via paste service to fix URL truncation on Slack/messaging apps
Share URLs for large plans can be 10-40KB+ because the entire plan + annotations
are compressed into the URL hash. Services like Slack, WhatsApp, and Twitter
truncate these URLs, making shared plans unviewable (related: #142).
This adds an optional paste-service backend that stores compressed payloads and
returns short ~60-char URLs (e.g. share.plannotator.ai/p/aBcDeFgH).
Changes:
- Add Cloudflare Worker paste service (apps/paste-worker/) with KV storage
and 90-day TTL for stored plans
- Add createShortShareUrl() and loadFromPasteId() to sharing utils
- Update useSharing hook to auto-generate short URLs with 1s debounce
- Update ExportModal to show short URL as primary copy target with
full hash URL as backup
- Portal automatically supports /p/<id> paths via useSharing hook
- Fully backward compatible: hash-based URLs continue to work unchanged
- Graceful degradation: falls back to hash URLs if paste service is unavailable
* Fix critical bugs found during code review of short URL feature
- Worker: return only { id } so client constructs URL with its own
shareBaseUrl (fixes self-hosted deployments)
- importFromShareUrl: handle /p/<id> short URLs in addition to hash
URLs (fixes teammate import via short links)
- Anchor /p/<id> regex with ^ to prevent false matches on nested paths
- Pass shareBaseUrl to loadFromPasteId (was always defaulting)
- replaceState preserves base path instead of hardcoding /
- Clear stale shortShareUrl immediately on debounce to prevent showing
outdated link during the 1s delay
- Add shareBaseUrl to dependency arrays for loadFromHash and
importFromShareUrl callbacks
- Remove unused url field fallback from paste API response parsing
* Fix pasteApiUrl/shareBaseUrl confusion and add remote session share URLs
Bug fix (addresses @backnotprop's code review):
- useSharing hook now accepts separate `pasteApiUrl` parameter instead of
incorrectly passing `shareBaseUrl` to `loadFromPasteId`. These are
different domains (share portal vs paste backend). When omitted, the
default `https://paste.plannotator.ai` is used correctly.
- Fixed in all three call sites: loadFromHash, importFromShareUrl, and
generateShortUrl (via createShortShareUrl options).
Remote session share URLs (implements #192):
- When running on a remote instance (SSH, devcontainer), Plannotator now
generates a share.plannotator.ai URL and prints it to stderr so the
user can open the plan review in their local browser.
- Works for all three modes: plan review, code review, and annotate.
- Uses the same deflate-raw + base64url encoding as the client.
- Fails silently if URL generation fails — port forwarding still works.
- New server utility: packages/server/share-url.ts
* Address code review findings: fix spread limit, CORS, deps array
- share-url.ts: Replace btoa(String.fromCharCode(...compressed)) with
a loop to avoid RangeError on plans >65K compressed bytes
- share-url.ts: Add cross-reference comment noting the server-side
SharePayload is an intentional subset of the canonical UI type
- paste-worker: Only return CORS headers for allowed origins; disallowed
origins get no CORS headers instead of misleading partial headers
- useSharing.ts: Remove unused shareBaseUrl from loadFromHash dependency
array (loadFromHash only uses pasteApiUrl, not shareBaseUrl)
* Restructure paste service with pluggable storage, fix consent flow and security issues
Replaces monolithic paste-worker with multi-target paste-service architecture:
- Core logic (handler, storage interface, CORS) separated from deployment targets
- Filesystem store (self-hosted), KV store (Cloudflare), S3 stub (future)
- Bun binary target + Cloudflare Worker target
- Fix auto-upload removed: short URLs only created on explicit user click
- Clear stale short URL state when content changes
- Fix require('fs') in ESM module, add path-traversal guard in FsPasteStore
- Return 400 (not 500) for malformed JSON in both targets
- Fix compress() spread limit for large plans
- Updated docs: self-hosting guide, sharing guide, env vars, API endpoints
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Simplify paste service: extract shared router, remove TOCTOU patterns
- Extract duplicated HTTP routing from bun.ts and cloudflare.ts into
handleRequest() in core/handler.ts — targets are now thin wrappers
- Move ID_PATTERN regex to core (was duplicated in both targets)
- Remove existsSync guard before mkdirSync({recursive:true}) in fs.ts
- Remove file.exists() check before file.json() in fs.ts get() — the
try/catch already handles missing files
- Extract DEFAULT_SHARE_BASE constant in sharing.ts (was hardcoded twice)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Deduplicate compression, image parsing, and remote share URL logic
- Create packages/shared/ with compress/decompress (single source of truth)
— both @plannotator/server and @plannotator/ui import from here
- Export parseShareableImages from sharing.ts, remove duplicate
parseGlobalAttachments from useSharing.ts
- Extract writeRemoteShareLink() helper in share-url.ts, replace 3
near-identical blocks in apps/hook/server/index.ts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix modulo bias in paste ID generation and remove nonexistent doc artifacts
- Use rejection sampling in generateId() to eliminate modulo bias
(bytes >= 248 discarded, uniform distribution over 62 chars)
- Remove references to install-paste.sh and Docker image that don't
exist yet; point self-hosting docs to GitHub Releases binaries
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Michael Ramos <mdramos8@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 12:25:55 +05:30
|
|
|
"./repo": "./repo.ts",
|
2026-06-05 18:29:38 -03:00
|
|
|
"./review-workspace": "./review-workspace.ts",
|
2026-06-19 09:04:15 -07:00
|
|
|
"./agent-terminal-runtime": "./agent-terminal-runtime.ts",
|
2026-08-01 10:26:42 -07:00
|
|
|
"./uninstall": "./uninstall.ts",
|
2026-03-07 17:09:57 +01:00
|
|
|
"./share-url": "./share-url.ts",
|
2026-03-07 09:45:33 -08:00
|
|
|
"./sessions": "./sessions.ts",
|
feat: PR review support via GitHub URL (#324)
* feat(review): add runtime-agnostic PR provider
Introduces `packages/shared/pr-provider.ts` with a `PRRuntime` interface
(same pattern as ReviewGitRuntime in review-core.ts) and GitHub PR
operations: URL parsing, auth check, diff/metadata fetching, and file
content retrieval via `gh` CLI.
`packages/server/pr.ts` is the Bun wrapper that pre-binds the runtime,
matching the git.ts pattern.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(review): add PR mode to review server
When `prMetadata` is provided to `startReviewServer`, the server enters
PR mode: `/api/diff` includes PR metadata and omits gitContext,
`/api/diff/switch` and `/api/git-add` return 400 (not applicable),
and `/api/file-content` fetches from GitHub API using base/head SHAs
instead of local git.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(review): PR review flow for Claude Code and OpenCode
Detects URL argument in `/plannotator-review` command. When a GitHub PR
URL is provided, fetches diff and metadata via `gh` CLI and starts the
review server in PR mode. Local review mode is unchanged when no URL
is passed.
Updates slash command definitions to pass $ARGUMENTS through.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(review): PR metadata display in review UI
Shows "PR Review" badge, PR title with link, and owner/repo in the
header when reviewing a pull request. Diff switcher and staging
controls auto-hide since gitContext is omitted in PR mode.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(review): contextualized PR feedback for agent
In PR mode, the feedback markdown now includes PR metadata (repo,
number, title, branches, URL) so the agent has full context about
the remote PR being reviewed. Removes the aggressive "address all
of them" instruction in PR mode since the content is self-explanatory.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor(review): extract exportReviewFeedback + add tests
Moves the pure feedback construction function from App.tsx to
utils/exportFeedback.ts so it can be unit tested. Drops the unused
`files` parameter. 11 tests covering local/PR headers, annotation
grouping, sorting, file-scope ordering, and suggested code rendering.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* test(review): strengthen PR/local boundary tests
Replaces shallow header checks with comprehensive boundary assertions:
local mode must never contain PR-specific content (repo, URL, branches),
PR mode must include all context fields and exclude the generic header.
Covers null/undefined prMetadata edge cases.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* test(review): remove redundant empty-annotations test
Covered by the "no annotations: returns generic empty regardless of
prMetadata" test which checks all three cases (no arg, null, PR mode).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(review): guard fetchPR, fix UTF-8 decoding, correct useCallback deps
- Wrap fetchPR() in try/catch in both hook and OpenCode entry points
so network/auth errors show a clean message instead of a stack trace
- Replace atob() with Buffer.from() for UTF-8 correct base64 decoding
of PR file content from GitHub API
- Fix stale useCallback deps in handleCopyFeedback (files → prMetadata)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(install): add $ARGUMENTS to review command for PR URL support
Install scripts were writing the review slash command without
$ARGUMENTS, so PR URLs passed to /plannotator-review were silently
dropped. Also switches PS1 heredoc to single-quoted to prevent
$ARGUMENTS from being expanded as a PowerShell variable.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* docs: add PR review support to docs and READMEs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 06:01:40 -07:00
|
|
|
"./project": "./project.ts",
|
2026-06-16 16:16:05 -07:00
|
|
|
"./pr": "./pr.ts",
|
|
|
|
|
"./html-assets": "./html-assets.ts"
|
2026-01-12 19:36:09 -08:00
|
|
|
},
|
2026-01-06 14:25:19 -08:00
|
|
|
"files": [
|
2026-06-19 09:04:15 -07:00
|
|
|
"*.ts",
|
|
|
|
|
"*.mjs"
|
2026-01-06 14:25:19 -08:00
|
|
|
],
|
Add short URL sharing via paste service to fix URL truncation (#188)
* Add short URL sharing via paste service to fix URL truncation on Slack/messaging apps
Share URLs for large plans can be 10-40KB+ because the entire plan + annotations
are compressed into the URL hash. Services like Slack, WhatsApp, and Twitter
truncate these URLs, making shared plans unviewable (related: #142).
This adds an optional paste-service backend that stores compressed payloads and
returns short ~60-char URLs (e.g. share.plannotator.ai/p/aBcDeFgH).
Changes:
- Add Cloudflare Worker paste service (apps/paste-worker/) with KV storage
and 90-day TTL for stored plans
- Add createShortShareUrl() and loadFromPasteId() to sharing utils
- Update useSharing hook to auto-generate short URLs with 1s debounce
- Update ExportModal to show short URL as primary copy target with
full hash URL as backup
- Portal automatically supports /p/<id> paths via useSharing hook
- Fully backward compatible: hash-based URLs continue to work unchanged
- Graceful degradation: falls back to hash URLs if paste service is unavailable
* Fix critical bugs found during code review of short URL feature
- Worker: return only { id } so client constructs URL with its own
shareBaseUrl (fixes self-hosted deployments)
- importFromShareUrl: handle /p/<id> short URLs in addition to hash
URLs (fixes teammate import via short links)
- Anchor /p/<id> regex with ^ to prevent false matches on nested paths
- Pass shareBaseUrl to loadFromPasteId (was always defaulting)
- replaceState preserves base path instead of hardcoding /
- Clear stale shortShareUrl immediately on debounce to prevent showing
outdated link during the 1s delay
- Add shareBaseUrl to dependency arrays for loadFromHash and
importFromShareUrl callbacks
- Remove unused url field fallback from paste API response parsing
* Fix pasteApiUrl/shareBaseUrl confusion and add remote session share URLs
Bug fix (addresses @backnotprop's code review):
- useSharing hook now accepts separate `pasteApiUrl` parameter instead of
incorrectly passing `shareBaseUrl` to `loadFromPasteId`. These are
different domains (share portal vs paste backend). When omitted, the
default `https://paste.plannotator.ai` is used correctly.
- Fixed in all three call sites: loadFromHash, importFromShareUrl, and
generateShortUrl (via createShortShareUrl options).
Remote session share URLs (implements #192):
- When running on a remote instance (SSH, devcontainer), Plannotator now
generates a share.plannotator.ai URL and prints it to stderr so the
user can open the plan review in their local browser.
- Works for all three modes: plan review, code review, and annotate.
- Uses the same deflate-raw + base64url encoding as the client.
- Fails silently if URL generation fails — port forwarding still works.
- New server utility: packages/server/share-url.ts
* Address code review findings: fix spread limit, CORS, deps array
- share-url.ts: Replace btoa(String.fromCharCode(...compressed)) with
a loop to avoid RangeError on plans >65K compressed bytes
- share-url.ts: Add cross-reference comment noting the server-side
SharePayload is an intentional subset of the canonical UI type
- paste-worker: Only return CORS headers for allowed origins; disallowed
origins get no CORS headers instead of misleading partial headers
- useSharing.ts: Remove unused shareBaseUrl from loadFromHash dependency
array (loadFromHash only uses pasteApiUrl, not shareBaseUrl)
* Restructure paste service with pluggable storage, fix consent flow and security issues
Replaces monolithic paste-worker with multi-target paste-service architecture:
- Core logic (handler, storage interface, CORS) separated from deployment targets
- Filesystem store (self-hosted), KV store (Cloudflare), S3 stub (future)
- Bun binary target + Cloudflare Worker target
- Fix auto-upload removed: short URLs only created on explicit user click
- Clear stale short URL state when content changes
- Fix require('fs') in ESM module, add path-traversal guard in FsPasteStore
- Return 400 (not 500) for malformed JSON in both targets
- Fix compress() spread limit for large plans
- Updated docs: self-hosting guide, sharing guide, env vars, API endpoints
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Simplify paste service: extract shared router, remove TOCTOU patterns
- Extract duplicated HTTP routing from bun.ts and cloudflare.ts into
handleRequest() in core/handler.ts — targets are now thin wrappers
- Move ID_PATTERN regex to core (was duplicated in both targets)
- Remove existsSync guard before mkdirSync({recursive:true}) in fs.ts
- Remove file.exists() check before file.json() in fs.ts get() — the
try/catch already handles missing files
- Extract DEFAULT_SHARE_BASE constant in sharing.ts (was hardcoded twice)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Deduplicate compression, image parsing, and remote share URL logic
- Create packages/shared/ with compress/decompress (single source of truth)
— both @plannotator/server and @plannotator/ui import from here
- Export parseShareableImages from sharing.ts, remove duplicate
parseGlobalAttachments from useSharing.ts
- Extract writeRemoteShareLink() helper in share-url.ts, replace 3
near-identical blocks in apps/hook/server/index.ts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix modulo bias in paste ID generation and remove nonexistent doc artifacts
- Use rejection sampling in generateId() to eliminate modulo bias
(bytes >= 248 discarded, uniform distribution over 62 chars)
- Remove references to install-paste.sh and Docker image that don't
exist yet; point self-hosting docs to GitHub Releases binaries
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Michael Ramos <mdramos8@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 12:25:55 +05:30
|
|
|
"dependencies": {
|
2026-08-03 19:37:06 -07:00
|
|
|
"@pierre/diffs": "1.3.1",
|
2026-06-03 21:17:11 +02:00
|
|
|
"@plannotator/ai": "workspace:*",
|
2026-06-19 09:04:15 -07:00
|
|
|
"@plannotator/shared": "workspace:*",
|
2026-08-01 10:26:42 -07:00
|
|
|
"@plannotator/webtui": "0.1.0",
|
|
|
|
|
"chokidar": "^5.0.0",
|
|
|
|
|
"jsonc-parser": "^3.3.1"
|
Add short URL sharing via paste service to fix URL truncation (#188)
* Add short URL sharing via paste service to fix URL truncation on Slack/messaging apps
Share URLs for large plans can be 10-40KB+ because the entire plan + annotations
are compressed into the URL hash. Services like Slack, WhatsApp, and Twitter
truncate these URLs, making shared plans unviewable (related: #142).
This adds an optional paste-service backend that stores compressed payloads and
returns short ~60-char URLs (e.g. share.plannotator.ai/p/aBcDeFgH).
Changes:
- Add Cloudflare Worker paste service (apps/paste-worker/) with KV storage
and 90-day TTL for stored plans
- Add createShortShareUrl() and loadFromPasteId() to sharing utils
- Update useSharing hook to auto-generate short URLs with 1s debounce
- Update ExportModal to show short URL as primary copy target with
full hash URL as backup
- Portal automatically supports /p/<id> paths via useSharing hook
- Fully backward compatible: hash-based URLs continue to work unchanged
- Graceful degradation: falls back to hash URLs if paste service is unavailable
* Fix critical bugs found during code review of short URL feature
- Worker: return only { id } so client constructs URL with its own
shareBaseUrl (fixes self-hosted deployments)
- importFromShareUrl: handle /p/<id> short URLs in addition to hash
URLs (fixes teammate import via short links)
- Anchor /p/<id> regex with ^ to prevent false matches on nested paths
- Pass shareBaseUrl to loadFromPasteId (was always defaulting)
- replaceState preserves base path instead of hardcoding /
- Clear stale shortShareUrl immediately on debounce to prevent showing
outdated link during the 1s delay
- Add shareBaseUrl to dependency arrays for loadFromHash and
importFromShareUrl callbacks
- Remove unused url field fallback from paste API response parsing
* Fix pasteApiUrl/shareBaseUrl confusion and add remote session share URLs
Bug fix (addresses @backnotprop's code review):
- useSharing hook now accepts separate `pasteApiUrl` parameter instead of
incorrectly passing `shareBaseUrl` to `loadFromPasteId`. These are
different domains (share portal vs paste backend). When omitted, the
default `https://paste.plannotator.ai` is used correctly.
- Fixed in all three call sites: loadFromHash, importFromShareUrl, and
generateShortUrl (via createShortShareUrl options).
Remote session share URLs (implements #192):
- When running on a remote instance (SSH, devcontainer), Plannotator now
generates a share.plannotator.ai URL and prints it to stderr so the
user can open the plan review in their local browser.
- Works for all three modes: plan review, code review, and annotate.
- Uses the same deflate-raw + base64url encoding as the client.
- Fails silently if URL generation fails — port forwarding still works.
- New server utility: packages/server/share-url.ts
* Address code review findings: fix spread limit, CORS, deps array
- share-url.ts: Replace btoa(String.fromCharCode(...compressed)) with
a loop to avoid RangeError on plans >65K compressed bytes
- share-url.ts: Add cross-reference comment noting the server-side
SharePayload is an intentional subset of the canonical UI type
- paste-worker: Only return CORS headers for allowed origins; disallowed
origins get no CORS headers instead of misleading partial headers
- useSharing.ts: Remove unused shareBaseUrl from loadFromHash dependency
array (loadFromHash only uses pasteApiUrl, not shareBaseUrl)
* Restructure paste service with pluggable storage, fix consent flow and security issues
Replaces monolithic paste-worker with multi-target paste-service architecture:
- Core logic (handler, storage interface, CORS) separated from deployment targets
- Filesystem store (self-hosted), KV store (Cloudflare), S3 stub (future)
- Bun binary target + Cloudflare Worker target
- Fix auto-upload removed: short URLs only created on explicit user click
- Clear stale short URL state when content changes
- Fix require('fs') in ESM module, add path-traversal guard in FsPasteStore
- Return 400 (not 500) for malformed JSON in both targets
- Fix compress() spread limit for large plans
- Updated docs: self-hosting guide, sharing guide, env vars, API endpoints
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Simplify paste service: extract shared router, remove TOCTOU patterns
- Extract duplicated HTTP routing from bun.ts and cloudflare.ts into
handleRequest() in core/handler.ts — targets are now thin wrappers
- Move ID_PATTERN regex to core (was duplicated in both targets)
- Remove existsSync guard before mkdirSync({recursive:true}) in fs.ts
- Remove file.exists() check before file.json() in fs.ts get() — the
try/catch already handles missing files
- Extract DEFAULT_SHARE_BASE constant in sharing.ts (was hardcoded twice)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Deduplicate compression, image parsing, and remote share URL logic
- Create packages/shared/ with compress/decompress (single source of truth)
— both @plannotator/server and @plannotator/ui import from here
- Export parseShareableImages from sharing.ts, remove duplicate
parseGlobalAttachments from useSharing.ts
- Extract writeRemoteShareLink() helper in share-url.ts, replace 3
near-identical blocks in apps/hook/server/index.ts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix modulo bias in paste ID generation and remove nonexistent doc artifacts
- Use rejection sampling in generateId() to eliminate modulo bias
(bytes >= 248 discarded, uniform distribution over 62 chars)
- Remove references to install-paste.sh and Docker image that don't
exist yet; point self-hosting docs to GitHub Releases binaries
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Michael Ramos <mdramos8@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 12:25:55 +05:30
|
|
|
},
|
2026-01-06 14:25:19 -08:00
|
|
|
"peerDependencies": {
|
|
|
|
|
"bun": ">=1.0.0"
|
Single-source skills (core/extra), replace Claude Code commands with skills, de-hardcode installers (#850)
* feat: single-source skills into core/extra, replace Claude commands with skills, de-hardcode installers
- apps/skills/core/{review,annotate,last,archive}: single authoritative
source for the always-installed skills (archive is new); all carry
disable-model-invocation + agents/openai.yaml sidecars
- apps/skills/extra/{compound,setup-goal,visual-explainer}: no longer
default-installed (except Kiro); installers print an
`npx skills add backnotprop/plannotator/apps/skills/extra` suggestion
- Claude Code: apps/hook/commands/ deleted, command heredocs removed;
core skills in ~/.claude/skills are the slash commands now
- Installers: OpenCode/Gemini command files copied from an extended
sparse checkout instead of heredocs; install.cmd gains the previously
missing OpenCode command install; aggressive cleanup of legacy
~/.claude/commands and ~/.codex/skills artifacts
- Codex: core skills install to ~/.agents/skills (official path);
~/.codex/skills install removed
- Pi: extension no longer bundles skills; #670 settings filter removed
* fix: review findings — old-tag soft guards, cmd replace-not-merge, plugin-update hint, frontmatter test
- install.sh: a --version tag predating apps/skills/core no longer aborts
the whole copy subshell (which also skipped OpenCode/Gemini commands);
core skills now soft-skip with an accurate message, matching ps1/cmd
- install.sh: subshell failure message no longer claims "git required"
when git was present (clone/network errors get their own wording)
- install.cmd: pre-remove skill dirs before xcopy so upgrades replace
rather than merge (stale files from renamed/deleted skill files no
longer linger; parity with sh/ps1)
- all installers + docs: tell upgraders to run /plugin marketplace update
so the plugin's old namespaced plannotator:* commands disappear (#817)
- install.test.ts: assert every core SKILL.md sets
disable-model-invocation: true — the load-bearing line that keeps core
skills out of Pi's system prompt (#842 regression guard)
* test: pin old-tag soft-guard behavior, dedupe core-skill list in tests
* fix: interrogation review findings — cross-installer diagnostic parity
- install.ps1/install.cmd: emit the "predates the core/extra skill
layout" diagnostic on old pinned tags instead of silently skipping
core skills (parity with install.sh)
- install.ps1: clone/network failure no longer claims "git required"
(git was already verified present); the outer catch now reports the
actual exception
- install.sh: "Installed OpenCode/Gemini commands" echoes are guarded
on the copy actually having a source, so old pinned tags don't print
false success (ps1/cmd already gated this way)
- AGENTS.md: opencode-plugin commands/ comment now reflects all four
command stubs
- install.test.ts: shared test asserts the soft-skip diagnostic exists
in all three installers and pins ps1's honest failure wording
* fix: respect CODEX_HOME for Codex home directory (#852)
Codex stores config and state under $CODEX_HOME when set, falling back
to ~/.codex (developers.openai.com/codex/config-advanced). Plannotator
hardcoded ~/.codex in two places:
- runtime: codex-session.ts scanned ~/.codex/sessions for rollout
files, so `plannotator last` failed with "No rendered assistant
message found" when CODEX_HOME pointed elsewhere. Now resolved the
same way copilot-session.ts handles COPILOT_HOME and session-log.ts
handles CLAUDE_CONFIG_DIR.
- installers: detection, config.toml/hooks.json paths, manual-setup
instructions, and the stale-skills cleanup now derive from
CODEX_HOME in all three scripts.
Tests: codex-session.test.ts covers rollout discovery under a
CODEX_HOME temp dir; install.test.ts asserts all three installers
respect the variable and that the fallback is the only hardcoded
~/.codex path left in install.sh.
* fix: hard-fail skill install, guard command cleanup, one-time extras migration
External review triage on PR #850 surfaced two real installer issues:
P1 — commands deleted before replacement: the Claude command cleanup
ran before the git-gated skill install, so a missing git, a failed
clone, or an old pinned tag deleted the user's slash commands and
installed nothing (a regression — the old installer needed no git).
Now:
- missing git is a hard failure before anything is touched ("install
git, then run this installer again")
- a failed fetch is a hard failure ("something went wrong — run the
installer again") instead of a silent skip
- the legacy command cleanup runs AFTER the install and only removes a
command file when its same-name replacement skill exists on disk
- old pinned tags keep the soft-skip (no deletion happens, commands
survive, CI e2e against old tags stays green)
P2 — recurring extras deletion: the extras cleanup ran on every
invocation, deleting copies users reinstalled via the suggested
`npx skills add` (the copies are byte-identical, so only provenance
can tell them apart). The cleanup is now a one-time migration recorded
in a migrations ledger under the Plannotator data dir
(<PLANNOTATOR_DATA_DIR|~/.plannotator>/migrations/), the same
record-what-you-did pattern package managers use.
All three installers (sh/ps1/cmd) updated in parity; tests pin the
guard condition, the ledger gating, and the hard-fail messages.
* test: tripwire — install.cmd must never contain /dev/null redirects
* fix: every skill sets disable-model-invocation — no exceptions
Maintainer rule: all Plannotator skills are user-invoked, never
model-auto-invoked. setup-goal (missing since #665) and the three Kiro
skills now carry the flag. The frontmatter test scans every SKILL.md in
apps/skills/core, apps/skills/extra, and apps/kiro-cli/skills
dynamically — with a floor of 10 — so a future skill cannot ship
without it.
* docs: git is a hard installer requirement; clarify post-gate sections complete on re-run
* docs: align ps1/cmd comments with hard-fail semantics
* feat: guided install — extras opt-in via skills CLI, model-invocation picker
Interactive terminals get a two-question wizard on first run:
1. Install the extra skills? Yes delegates to `npx skills add
backnotprop/plannotator/apps/skills/extra` (its UI picks the agents),
wired to /dev/tty so piped curl|bash installs still work. Skipped
when extras already exist on disk.
2. Make any skills callable by the model? Yes opens a space-toggle
checkbox (sh/ps1) or numbered toggles (cmd), listing all skills if
extras were chosen, core-only otherwise. Chosen skills get
disable-model-invocation stripped from their INSTALLED copies and the
Codex sidecar's allow_implicit_invocation flipped — re-applied every
run since installs replace skill folders. Repo sources stay locked.
Answers persist to <data dir>/install-prefs (shared format across all
three installers) and re-runs reuse them silently; --reconfigure
re-opens the wizard. Automation is untouched: no terminal means no
prompts and today's defaults; --extras/--no-extras/--model-invocable/
--non-interactive give scripts explicit control.
* fix: self-review of guided install — cmd pipe expansion bug, flag/wizard interplay
- install.cmd: the checkbox preselection used `echo !var! | findstr` —
each side of a cmd pipe runs in a child WITHOUT delayed expansion, so
the saved choices passed through as literal !var! text and
preselection never matched. Replaced with a substring-replace
containment test (no pipe).
- all three: a wizard question whose answer was already provided by a
CLI flag (--extras/--no-extras/--model-invocable) is no longer asked
and then silently overridden — the flag pre-answers it.
- install.cmd: unknown-option usage line now lists the wizard flags.
* feat: guided install question 3 — install Glimpse (native window)
glimpseui (third-party npm package, PR #840) gives Plannotator a native
WebView window instead of a browser tab; the runtime already
auto-detects it on PATH, so a global install is all that's needed.
- Wizard asks "Install Glimpse?" (default yes) after the skills
questions; skipped when glimpseui is already on PATH
- Yes runs `npm install -g glimpseui` (bun fallback on sh/ps1; printed
instruction when neither exists) — wizard or explicit flag only,
silent re-runs never install software
- --glimpse / --no-glimpse flags for automation; choice persisted to
install-prefs like the others
- docs + tests updated (glimpse detection, install command, flags, and
persist-condition assertions across all three installers)
* fix: self-review of Glimpse question — cmd bun fallback, stale usage text
* fix: merge-window hardening — guard Codex cleanup, remove old-installer junk dirs
plannotator.ai serves install.sh live from main (public/ symlink,
deployed on push), while the script fetches repo files at the LATEST
RELEASE TAG. Between merging the core/extra restructure and cutting the
release that ships it, the live script runs against the old-layout tag.
Two hazards in that window:
1. The Codex stale-skill cleanup removed working ~/.codex/skills with
no successor installed (core skills soft-skip on old tags). Now the
cleanup runs AFTER the install and removes a core skill only once
its replacement exists in ~/.agents/skills — same guard the Claude
command cleanup uses. The compound/setup-goal stale copies stay
unconditional (never Codex's to begin with).
2. The reverse combo (cached OLD script + NEW release tag) wholesale-
copies apps/skills/* and leaves junk core/ and extra/ directory
copies in ~/.claude/skills. Never valid skill names — all three
installers now remove them on every run.
* fix: glimpseui is a devDependency — consumers never use it from node_modules
PR #840 added glimpseui to dependencies in @plannotator/server and
@plannotator/pi-extension, but nothing imports it: both runtimes detect
the CLI on PATH (Bun.which / a manual PATH walk) and spawn it. The dep
only ever mattered in repo development, where `bun run` prepends
node_modules/.bin to PATH. For consumers it was inert download weight —
OpenCode plugin installs and `pi install` pulled a third-party package
that could never be detected (Pi's loader does not expose
node_modules/.bin; verified). Moved to devDependencies in both: dev
flows keep working, published packages stop shipping it. The sanctioned
end-user path is the guided installer's global `npm install -g
glimpseui`.
* fix: clean stale plugin command files from the installed plugin checkout (#817)
The installer already manages hooks.json inside
~/.claude/plugins/marketplaces/plannotator/apps/hook/, so the earlier
"don't reach into plugin storage" rationale for leaving the old
namespaced plannotator:* command files there was inconsistent. All
three installers now remove them — same replacement-skill guard as the
bare ~/.claude/commands cleanup — making the #817 duplicate menu
entries die on a single installer run + restart instead of waiting for
/plugin marketplace update. Hints/docs reworded accordingly.
* Revert "fix: clean stale plugin command files from the installed plugin checkout (#817)"
This reverts commit 3df37da92cdf26b1673b0ab1a5930fdcef8fc202.
* fix: Windows CI — assert the new no-commands contract; gate cmd wizard on a real console
The cmd e2e CI step still asserted the OLD contract (installer writes
~/.claude/commands/plannotator-*.md with the ! prefix). Commands are
dead; the step now guards the NEW contract: a fresh install must write
NO plannotator command files. The Gemini TOML assertions stay — they
now verify the verbatim checkout copy delivers intact files (the tag
the e2e pins, v0.17.1, contains apps/gemini/commands).
The failure also exposed that install.cmd ran the wizard on redirected
stdin (set /p falls through to defaults at EOF) — and Q3's default
being yes meant CI silently ran `npm install -g glimpseui`. cmd now
probes for a real console via `timeout /t 0` (errors when stdin is
redirected), matching sh's /dev/tty and ps1's IsInputRedirected gates:
no console, no wizard, no wizard-only installs.
2026-06-05 09:23:45 -07:00
|
|
|
},
|
|
|
|
|
"devDependencies": {
|
|
|
|
|
"glimpseui": "^0.8.0"
|
2026-01-06 14:25:19 -08:00
|
|
|
}
|
|
|
|
|
}
|