Annotate and review coding agent plans and code diffs visually, share with your team, send feedback to agents with one click.
This report summarizes scanner evidence for backnotprop/plannotator, a TypeScript project with 9,792 GitHub stars. SynthScan examined 961,175 lines of code across 3886 source files, recording 1516 pattern matches distributed across 18 syntactic categories. The legacy adjusted pattern signal is 2.2 (Low pattern signal); it is not an authorship estimate.
Use the findings to ask whether maintainers can explain intent, verify dependencies, simplify unnecessary scaffolding, and focus review effort. Risk Payload v1 adds ownership, supply-chain, over-engineering, and review-effort vectors when available. These are prompts for human verification, not probabilities, security findings, or measured maintenance costs.
Use each vector to guide manual verification of the underlying findings.
Payload schema: 1.0.0 · Engine: 2.0.0 · Scoring: heuristic-density-v1 · Scan date: 2026-10-31.
Can maintainers explain intent, assumptions, and trade-offs? 1288 finding(s).
Are imports declared and package/API names verified? 37 finding(s).
Are wrappers, guards, and repeated structures necessary? 1077 finding(s).
Which changes need focused human review? 1516 finding(s).
This chart tracks the legacy adjusted pattern score across scan runs. Changes can reflect source changes, scan coverage, or detector/scoring versions; they do not measure AI adoption or prove that a team refactored code. Compare runs only when their scoring versions are compatible. The dashed line tracks the raw pattern-hit count.
Groups findings by configured severity weight. Severity is not a confidence estimate, security rating, or proof that a package is missing. Verify imports against the project's manifests and inspect each finding in its local design context.
This horizontal bar chart shows where configured pattern scores accumulate across directories. Treat the bars as locations to inspect, not as evidence of authorship or code quality. Use the file-level findings to decide whether a directory needs a focused ownership, dependency, complexity, or review check.
The scanner identified 1516 distinct pattern matches across 18 syntactic categories. Each entry below represents a discrete location in the source code where the engine recorded a detector match to inspect in context. Expand any category row to inspect the individual file paths, line numbers, code snippets, and the lexical context (CODE, COMMENT, or STRING) in which each match was detected.
Reading the findings table: The Severity column indicates the configured finding weight (CRITICAL / HIGH / MEDIUM / LOW). The Context column identifies whether the match occurred inside executable code, an inline comment, or a string literal — legacy comment-context matches receive a ×1.5 score weight. The ⚡ bolt icon marks clustered matches: three or more patterns within a 10-line window, each receiving an additional ×1.5 density multiplier under the legacy scoring model.
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/e2e/plan-lazy-chunk-failure.spec.ts | 129 | async function expectAppKeptWithFallback(page: Page, pageErrors: string[], message: string, action: string): Promise<voi | CODE |
| LOW | tests/e2e/inbox-compose-skill-picker.spec.ts | 226 | async function expectEscapeClosesPickerFirst(page: Page): Promise<void> { | CODE |
| LOW | tests/helpers/app-html.ts | 45 | export async function expectUncompressedLocalPage(pageUrl: string, html: string): Promise<void> { | CODE |
| LOW | scripts/install.test.ts | 4268 | function extractCmdClaudePluginCommand(): string { | CODE |
| LOW | scripts/install.test.ts | 4306 | function runWindowsClaudePluginUpdate( | CODE |
| LOW | scripts/install.sh | 1532 | function isManagedPlannotatorCommand(value) { | CODE |
| LOW | packages/t3-code/reviews.ts | 24 | export function lastFinishedAssistantMessage(snapshot: T3ThreadRead, threadId: string): T3ThreadRead["items"][number] | | CODE |
| LOW | packages/ui/webmcp/preference.ts | 41 | export function subscribeWebMcpToolsEnabled(listener: () => void): () => void { | CODE |
| LOW | packages/ui/test-setup/commentSubmitKeys.ts | 60 | export function describeCommentSubmitKeys( | CODE |
| LOW | packages/ui/test-setup/diagramSvg.ts | 34 | export function installInertDiagramSvgParser(): () => void { | CODE |
| LOW | packages/ui/test-setup/bandIntersectionObserver.ts | 75 | export function installBandIntersectionObserver(): () => void { | CODE |
| LOW | packages/ui/config/reviewView.ts | 72 | export function getPersistedReviewPanelView(): 'sections' | 'tree' | undefined { | CODE |
| LOW | packages/ui/config/reviewView.ts | 104 | export function getProviderReviewDefaultDiffType( | CODE |
| LOW | packages/ui/config/reviewView.ts | 114 | export function setProviderReviewDefaultDiffType( | CODE |
| LOW | packages/ui/utils/vimHud.ts | 191 | export function isVimHudLegendGroupActive( | CODE |
| LOW⚡ | packages/ui/utils/lookAndFeelAnnouncement.ts | 86 | export function planLookAnsweredElsewhere(): boolean | null { | CODE |
| LOW⚡ | packages/ui/utils/lookAndFeelAnnouncement.ts | 91 | export function needsLookAndFeelAnnouncement(): boolean { | CODE |
| LOW⚡ | packages/ui/utils/lookAndFeelAnnouncement.ts | 95 | export function markLookAndFeelChoiceResolved(): void { | CODE |
| LOW | packages/ui/utils/serverSession.ts | 45 | export async function noteServerSessionMismatch(res: Response): Promise<boolean> { | CODE |
| LOW | packages/ui/utils/serverSession.ts | 58 | export function markServerSessionReplaced(): void { | CODE |
| LOW | packages/ui/utils/reviewAgentInstructions.ts | 14 | export function buildReviewAgentInstructions(origin: string): string { | CODE |
| LOW | packages/ui/utils/skillCatalog.ts | 69 | export function resetSkillCatalogTransport(): void { | CODE |
| LOW | packages/ui/utils/skillCatalog.ts | 91 | export function setSkillCatalogExportRegistration(on: boolean): void { | CODE |
| LOW | packages/ui/utils/skillCatalog.ts | 187 | export function resetSkillContentTransport(): void { | CODE |
| LOW | packages/ui/utils/skillCatalog.ts | 227 | export async function primeSkillContentsForExport( | CODE |
| LOW | packages/ui/utils/mermaidTheme.ts | 427 | export function buildMermaidThemeVariables( | CODE |
| LOW | packages/ui/utils/permissionMode.ts | 54 | export function getPermissionModeSettings(): PermissionModeSettings { | CODE |
| LOW | packages/ui/utils/permissionMode.ts | 67 | export function savePermissionModeSettings(mode: PermissionMode): void { | CODE |
| LOW | packages/ui/utils/annotateAgentInstructions.ts | 87 | export function buildAnnotateAgentInstructions( | CODE |
| LOW | packages/ui/utils/annotateAgentInstructions.ts | 151 | export function resolveAnnotateInstructionsSurface(input: { | CODE |
| LOW | packages/ui/utils/vimNavigation.ts | 89 | export function createInitialVimSelectionState(): { readonly phase: 'inactive' } { | CODE |
| LOW | packages/ui/utils/vimNavigation.ts | 111 | function getPositionAtBlockBoundary( | CODE |
| LOW | packages/ui/utils/vimNavigation.ts | 269 | export function createRangeBetweenTextPositions( | CODE |
| LOW | packages/ui/utils/terminalToolsAnnouncement.ts | 15 | export function needsTerminalToolsAnnouncement(): boolean { | CODE |
| LOW | packages/ui/utils/terminalToolsAnnouncement.ts | 19 | export function markTerminalToolsAnnouncementSeen(): void { | CODE |
| LOW | packages/ui/utils/terminalToolsAnnouncement.ts | 66 | export function terminalToolsAnnouncementCanShow( | CODE |
| LOW | packages/ui/utils/domSelection.ts | 61 | export function isDocumentKeyboardControl(target: EventTarget | null): boolean { | CODE |
| LOW | packages/ui/utils/diagram-anchor.ts | 198 | function sequenceTargetFromElement(svg: Element, el: Element): DiagramTarget | null { | CODE |
| LOW | packages/ui/utils/diagram-anchor-graphviz.ts | 71 | export function graphvizTargetFromElement(_svg: Element, el: Element): DiagramTarget | null { | CODE |
| LOW | packages/ui/utils/annotationScope.ts | 23 | export function getAnnotationScopePreference(): AnnotationScope | null { | CODE |
| LOW | packages/ui/utils/annotationScope.ts | 28 | export function setAnnotationScopePreference(scope: AnnotationScope): void { | CODE |
| LOW | packages/ui/utils/annotationScope.ts | 86 | export function groupAnnotationsByDocument( | CODE |
| LOW | packages/ui/utils/annotationScope.ts | 134 | export function buildAnnotationDocumentGroups(input: { | CODE |
| LOW | packages/ui/utils/annotationScope.ts | 164 | export function resolveInitialAnnotationScope(input: { | CODE |
| LOW | packages/ui/utils/inboxAnnouncement.ts | 23 | export function markInboxAnnouncementSeen(): void { | CODE |
| LOW | packages/ui/utils/inboxAnnouncement.ts | 69 | export function inboxAnnouncementEligible(state: InboxAnnouncementGateState): boolean { | CODE |
| LOW | packages/ui/utils/annotationHelpers.ts | 7 | export function getAnnotationCountBySection( | CODE |
| LOW | packages/ui/utils/planDiffEngine.ts | 267 | function substituteQuotedFenceRuns( | CODE |
| LOW | packages/ui/utils/aiProvider.ts | 46 | export function hasNonInterruptibleSession(providers: readonly { sessionBridge?: SessionBridgeInfo }[]): boolean { | CODE |
| LOW | packages/ui/utils/aiProvider.ts | 86 | export function originHasDedicatedAIProvider(origin: Origin | null | undefined): boolean { | CODE |
| LOW | packages/ui/utils/aiProvider.ts | 172 | export function resolveAIModelForProvider( | CODE |
| LOW | packages/ui/utils/aiProvider.ts | 185 | export function resolveAIProviderSelection(options: { | CODE |
| LOW | packages/ui/utils/blockTargeting.ts | 388 | export function createSemanticTargetRange(target: SemanticTarget): Range | null { | CODE |
| LOW | packages/ui/utils/blockTargeting.ts | 395 | export function getSemanticTargetChildren( | CODE |
| LOW | packages/ui/utils/blockTargeting.ts | 421 | export function findInitialSemanticTarget( | CODE |
| LOW | packages/ui/utils/blockTargeting.ts | 500 | export function resolveSemanticTargetAtPoint( | CODE |
| LOW | packages/ui/utils/askSessionAnnouncement.ts | 23 | export function needsAskSessionAnnouncement(): boolean { | CODE |
| LOW | packages/ui/utils/askSessionAnnouncement.ts | 27 | export function markAskSessionAnnouncementSeen(): void { | CODE |
| LOW | packages/ui/utils/askSessionAnnouncement.ts | 38 | export function askSessionAnnouncementPendingThisLoad(): boolean { | CODE |
| LOW | packages/ui/utils/askSessionAnnouncement.ts | 97 | export function askSessionAnnouncementEligible(state: AskSessionAnnouncementGateState): boolean { | CODE |
| 826 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | tests/never-touch-the-real-inbox.test.ts | 42 | // ── 1. The source scan ─────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/never-touch-the-real-inbox.test.ts | 153 | // ── 2. The guards ──────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/bench-startup.sh | 22 | # ── Helpers ────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/bench-startup.sh | 88 | # ── Main ───────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/bench-startup.sh | 97 | # ── Scenario 1: No plugin (baseline) ───────────────────────────────── | COMMENT |
| MEDIUM | tests/bench-startup.sh | 116 | # ── Scenario 2: Published npm plugin ───────────────────────────────── | COMMENT |
| MEDIUM | tests/bench-startup.sh | 135 | # ── Scenario 3: Local optimized plugin ─────────────────────────────── | COMMENT |
| MEDIUM | tests/bench-startup.sh | 158 | # ── Summary ────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM⚡ | tests/manual/local/test-sessions.sh | 101 | # ------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/manual/local/test-sessions.sh | 103 | # ------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/manual/local/test-sessions.sh | 118 | # ------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/manual/local/test-sessions.sh | 120 | # ------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/manual/local/test-sessions.sh | 127 | # ------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/manual/local/test-sessions.sh | 129 | # ------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/manual/local/test-sessions.sh | 168 | # ------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/manual/local/test-sessions.sh | 170 | # ------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/manual/local/test-sessions.sh | 197 | # ------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/manual/local/test-sessions.sh | 199 | # ------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/manual/local/test-sessions.sh | 226 | # ------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/manual/local/test-sessions.sh | 228 | # ------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/manual/local/test-sessions.sh | 261 | # ------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/manual/local/test-sessions.sh | 263 | # ------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/manual/local/test-sessions.sh | 324 | # ------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/manual/local/test-sessions.sh | 326 | # ------------------------------------------------------- | COMMENT |
| MEDIUM | tests/manual/local/sandbox-opencode.sh | 1019 | # ============================================================================= | COMMENT |
| MEDIUM | tests/manual/local/sandbox-opencode.sh | 1021 | # ============================================================================= | COMMENT |
| MEDIUM⚡ | tests/manual/path-detection/setup.sh | 59 | # ─────────────────────────────────────────────────── | COMMENT |
| MEDIUM⚡ | tests/manual/path-detection/setup.sh | 61 | # ─────────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/manual/path-detection/setup.sh | 115 | # ─────────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/manual/path-detection/setup.sh | 117 | # ─────────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/manual/path-detection/setup.sh | 141 | # ─────────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/manual/path-detection/setup.sh | 143 | # ─────────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/manual/path-detection/setup.sh | 268 | # ─────────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/manual/path-detection/setup.sh | 270 | # ─────────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/manual/path-detection/setup.sh | 351 | # ─────────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/manual/path-detection/setup.sh | 354 | # ─────────────────────────────────────────────────── | COMMENT |
| MEDIUM | packages/ui/utils/questionAnswers.ts | 99 | // ─────────────────────────── Panel + progress ─────────────────────────── | COMMENT |
| MEDIUM | packages/inbox/App.tsx | 3358 | // ── The onboarding tour (approval "inbox-onboarding-tour") ────────────── | COMMENT |
| MEDIUM | packages/inbox/decisionMode.test.tsx | 562 | // ─────────────────────────────── Review round ─────────────────────────────── | COMMENT |
| MEDIUM | packages/inbox/decisionMode.test.tsx | 831 | // ─────────────────────────────── Re-review ─────────────────────────────── | COMMENT |
| MEDIUM | packages/inbox/soundSettings.test.tsx | 181 | // ───────────────────────────── The hook, against a recording AudioContext ───────────────────────────── | COMMENT |
| MEDIUM | packages/inbox/sound.ts | 25 | // ───────────────────────────── The sound ───────────────────────────── | COMMENT |
| MEDIUM | packages/inbox/sound.ts | 111 | // ───────────────────────────── When it rings ───────────────────────────── | COMMENT |
| MEDIUM | packages/inbox/sound.ts | 145 | // ───────────────────────────── Several tabs ───────────────────────────── | COMMENT |
| MEDIUM | packages/inbox/sound.ts | 222 | // ───────────────────────────── The hook ───────────────────────────── | COMMENT |
| MEDIUM | packages/inbox/decisions/model.ts | 309 | // ─────────────────────────────── Chips ─────────────────────────────── | COMMENT |
| MEDIUM | packages/inbox/decisions/model.ts | 408 | // ─────────────────────────────── Answers ─────────────────────────────── | COMMENT |
| MEDIUM | packages/inbox/components/AttachmentPane.tsx | 426 | // ── Stepping (design record "inbox-attachment-stepping", v2) ────────────── | COMMENT |
| MEDIUM | packages/inbox/components/AttachmentPane.tsx | 549 | // ── Full screen (approval "inbox-one-fullscreen", Drawer) ───────────────── | COMMENT |
| MEDIUM | packages/inbox/components/AttachmentPane.tsx | 1107 | // ── Links inside an attached document (htmlLinks.ts) ───────────────────── | COMMENT |
| MEDIUM | packages/inbox/components/Updates.tsx | 47 | // ───────────────────────────── The sidebar button ───────────────────────────── | COMMENT |
| MEDIUM | packages/inbox/components/Updates.tsx | 126 | // ───────────────────────────── Dialogs ───────────────────────────── | COMMENT |
| MEDIUM | packages/inbox/components/Updates.tsx | 502 | // ───────────────────────────── What's new ───────────────────────────── | COMMENT |
| MEDIUM | packages/inbox/components/Updates.tsx | 740 | // ──────────────────────── Checking for updates is failing ──────────────────────── | COMMENT |
| MEDIUM | packages/inbox/components/Updates.tsx | 817 | // ───────────────────────────── Settings → General ───────────────────────────── | COMMENT |
| MEDIUM | packages/inbox/components/Updates.tsx | 948 | // ───────────────────────────── Settings → About ───────────────────────────── | COMMENT |
| MEDIUM | packages/inbox/components/Thread.tsx | 693 | // ── Comments on the text (approval "inbox-message-comments") ────────────── | COMMENT |
| MEDIUM | packages/inbox/components/Thread.tsx | 1378 | // ── Folding (design record "Land", not in this repo) ────────────────────── | COMMENT |
| MEDIUM | packages/inbox/tour/Tour.tsx | 84 | // ─────────────────────────── Loading the fixture ─────────────────────────── | COMMENT |
| MEDIUM | packages/inbox/tour/Tour.tsx | 225 | // ─────────────────────────── The tour bar ─────────────────────────── | COMMENT |
| 129 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | bunfig.toml | 1 | [install] | COMMENT |
| LOW | .gitleaks.toml | 21 | # world-readable, so their #key= fragments are not leaked secrets. The regex is | COMMENT |
| LOW | tests/bunfig.toml | 1 | # Bun reads only the bunfig.toml in the directory `bun test` runs from, so the | COMMENT |
| LOW | tests/entry-assets.test.ts | 81 | }, | COMMENT |
| LOW | tests/entry-assets.test.ts | 161 | expect(read('packages/ui/components/DiagramBlock.tsx')).not.toMatch(staticImport('@viz-js/viz')); | COMMENT |
| LOW | tests/entry-assets.test.ts | 221 | const eager = [...walk('packages/inbox'), ...walk('apps/inbox')].filter((path) => palette.test(read(path))); | COMMENT |
| LOW | tests/entry-assets.test.ts | 241 | // 12 the plan editor loads the runtime lazily by policy, and an eager | COMMENT |
| LOW | tests/entry-assets.test.ts | 341 | // could reach the same inlined blob through a different import specifier and | COMMENT |
| LOW | tests/bench-startup.sh | 1 | #!/usr/bin/env bash | COMMENT |
| LOW | tests/setup/feedback-archive-off.ts | 41 | // The Inbox publishes itself over the tailnet when this is on: a contributor | COMMENT |
| LOW | tests/setup/feedback-archive-off.ts | 61 | // dropped by hand. A closed loopback port refuses at once ("Couldn't send | COMMENT |
| LOW | tests/manual/local/test-binary.sh | 1 | #!/bin/bash | COMMENT |
| LOW | tests/manual/local/test-sessions.sh | 1 | #!/bin/bash | COMMENT |
| LOW | tests/manual/local/test-jj-review.sh | 1 | #!/bin/bash | COMMENT |
| LOW | tests/manual/local/sandbox-opencode-isolated.sh | 1 | #!/bin/bash | COMMENT |
| LOW | tests/manual/local/test-worktree-review.sh | 1 | #!/bin/bash | COMMENT |
| LOW | tests/manual/local/test-bulk-plans.sh | 1 | #!/bin/bash | COMMENT |
| LOW | tests/manual/local/sandbox-opencode.sh | 1 | #!/bin/bash | COMMENT |
| LOW | tests/manual/local/sandbox-opencode.sh | 21 | # --no-git Don't initialize git repo (tests non-git fallback) | COMMENT |
| LOW | tests/manual/local/sandbox-gemini.sh | 1 | #!/bin/bash | COMMENT |
| LOW | tests/manual/local/test-hook.sh | 1 | #!/bin/bash | COMMENT |
| LOW | tests/manual/local/sandbox-pi.sh | 1 | #!/bin/bash | COMMENT |
| LOW | tests/manual/local/test-opencode-review.sh | 1 | #!/bin/bash | COMMENT |
| LOW | tests/manual/local/test-external-annotations.sh | 1 | #!/bin/bash | COMMENT |
| LOW | tests/manual/local/sandbox-codex.sh | 1 | #!/bin/bash | COMMENT |
| LOW | tests/manual/local/test-codex-plan-review-e2e.sh | 1 | #!/bin/bash | COMMENT |
| LOW | tests/manual/local/test-hook-2.sh | 1 | #!/bin/bash | COMMENT |
| LOW | tests/manual/path-detection/setup.sh | 1 | #!/bin/bash | COMMENT |
| LOW | tests/manual/path-detection/setup.sh | 21 | # │ ├── app/ | COMMENT |
| LOW | tests/manual/path-detection/run-plan.sh | 1 | #!/bin/bash | COMMENT |
| LOW | tests/manual/path-detection/run-annotate-out-of-tree.sh | 1 | #!/bin/bash | COMMENT |
| LOW | spec/simulate.sh | 1 | #!/usr/bin/env bash | COMMENT |
| LOW | scripts/install.test.ts | 421 | // Config layer (M2): the skipInstall OBJECT is extracted first (awk, | COMMENT |
| LOW | scripts/install.test.ts | 581 | test("install.ps1 selects native arm64 binary on ARM64 Windows", () => { | COMMENT |
| LOW | scripts/install.test.ts | 1241 | COMMENT | |
| LOW | scripts/install.test.ts | 1501 | // install.cmd | COMMENT |
| LOW | scripts/install.test.ts | 1621 | expect(cmdScript).toContain('set "MIN_NUM=!MIN_ATTESTED_VERSION:~1!"'); | COMMENT |
| LOW | scripts/install.test.ts | 1641 | expect(cmdScript).toContain('if not "!TAG_NUM!"=="!TAG_NUM:-=!"'); | COMMENT |
| LOW | scripts/install.test.ts | 1681 | // to release.yml have no attestations. Running `gh attestation verify` | COMMENT |
| LOW | scripts/install.test.ts | 1901 | test("all installers authenticate the api.github.com version-resolution call", () => { | COMMENT |
| LOW | scripts/install.test.ts | 1981 | COMMENT | |
| LOW | scripts/install.test.ts | 2141 | // redirecting a native command's stderr under | COMMENT |
| LOW | scripts/install.test.ts | 2201 | // stubbed curl/gh/git PATH. No network, no real agent CLI reachable. These | COMMENT |
| LOW | scripts/install.test.ts | 3561 | // clone of this repo; installing or updating the plugin copies apps/hook from | COMMENT |
| LOW | scripts/install.test.ts | 4481 | }, | COMMENT |
| LOW | scripts/install.sh | 1 | #!/bin/bash | COMMENT |
| LOW | scripts/install.sh | 41 | *.*.*.*) return 1 ;; | COMMENT |
| LOW | scripts/install.sh | 61 | WITH_CALL_FLOW_FLAG=-1 | COMMENT |
| LOW | scripts/install.sh | 81 | # writes nothing to that agent's home; it never removes an integration a | COMMENT |
| LOW | scripts/install.sh | 461 | COMMENT | |
| LOW | scripts/install.sh | 481 | # dotfiles, direnv) gets a 401 here and would break an install that | COMMENT |
| LOW | scripts/install.sh | 921 | # Sigstore bundle anonymously and hand it to gh via --bundle. The | COMMENT |
| LOW | scripts/install.sh | 1601 | fi | COMMENT |
| LOW | scripts/install.sh | 1641 | fi | COMMENT |
| LOW | scripts/install.sh | 1881 | rmdir "$OPENCODE_CACHE_DIR/npm/@plannotator" 2>/dev/null || true | COMMENT |
| LOW | scripts/install.sh | 2021 | } | COMMENT |
| LOW | scripts/install.sh | 2121 | run_wizard=1 | COMMENT |
| LOW | scripts/install.sh | 2361 | echo "Qwen Code ${qwen_version} is older than ${QWEN_MIN_VERSION}, so nothing was installed for it. Update Qwen | COMMENT |
| LOW | scripts/install.sh | 2381 | # it as `if ! ( ... ); then` suppresses -e the same way. So the fetch | COMMENT |
| LOW | scripts/install.sh | 2401 | # real error is surfaced below so incompatibilities self-diagnose instead | COMMENT |
| 255 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| CRITICAL | tests/e2e/surface.spec.ts | 125 | try { window.top.webkit.messageHandlers.plannotatorSurface.postMessage({ v: 1, type: 'link', href: 'https://evil.examp | CODE |
| CRITICAL | apps/opencode-plugin/commands.test.ts | 148 | const logged = deps.client.app.log.mock.calls.map((c: any[]) => c[0]?.message ?? "").join("\n"); | CODE |
| CRITICAL⚡ | apps/opencode-plugin/commands.test.ts | 185 | expect(deps.client.app.log.mock.calls.map((call: any[]) => call[0].message).join("\n")).toContain("does not exist"); | CODE |
| CRITICAL⚡ | apps/opencode-plugin/commands.test.ts | 187 | expect(deps.client.tui.showToast.mock.calls.map((call: any[]) => call[0].body.message).join("\n")).toContain("does n | CODE |
| CRITICAL⚡ | apps/opencode-plugin/commands.test.ts | 195 | expect(deps.client.app.log.mock.calls.map((call: any[]) => call[0].message).join("\n")).toContain("please review my | CODE |
| CRITICAL | apps/opencode-plugin/commands.test.ts | 320 | const logged = deps.client.app.log.mock.calls.map(([entry]: [{ message: string }]) => entry.message).join("\n"); | CODE |
| CRITICAL | apps/opencode-plugin/commands.test.ts | 634 | return deps.client.tui.showToast.mock.calls.map((call: any[]) => call[0].body.message); | CODE |
| CRITICAL | apps/opencode-plugin/cli-bridge.test.ts | 48 | const toasts = () => client.tui.showToast.mock.calls.map(([entry]) => entry.body.message).join("\n"); | CODE |
| CRITICAL | apps/opencode-plugin/cli-bridge.test.ts | 54 | expect(client.app.log.mock.calls.map(([entry]) => entry.message).join("\n")).toContain("Update the Plannotator CLI | CODE |
| CRITICAL | apps/opencode-plugin/cli-bridge.test.ts | 67 | expect(client.app.log.mock.calls.map(([entry]) => entry.message).join("\n")).toContain("Update the Plannotator CLI | CODE |
| CRITICAL | apps/opencode-plugin/cli-bridge.test.ts | 133 | expect(client.app.log.mock.calls.map(([entry]) => entry.message).join("\n")).toContain("update Plannotator to open | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW⚡ | tests/manual/local/test-sessions.sh | 102 | # Step 0: Build | COMMENT |
| LOW⚡ | tests/manual/local/test-sessions.sh | 119 | # Step 1: Clean slate | COMMENT |
| LOW⚡ | tests/manual/local/test-sessions.sh | 128 | # Step 2: Launch plan server, validate session file content | COMMENT |
| LOW⚡ | tests/manual/local/test-sessions.sh | 169 | # Step 3: Launch review server, validate session file content | COMMENT |
| LOW⚡ | tests/manual/local/test-sessions.sh | 198 | # Step 4: Test `plannotator sessions` listing | COMMENT |
| LOW⚡ | tests/manual/local/test-sessions.sh | 227 | # Step 5: Test `sessions --open` | COMMENT |
| LOW⚡ | tests/manual/local/test-sessions.sh | 262 | # Step 6: Test stale session cleanup (auto + --clean) | COMMENT |
| LOW⚡ | tests/manual/local/test-sessions.sh | 325 | # Step 7: Approve/submit servers, verify session cleanup on exit | COMMENT |
| LOW | .agents/skills/release/SKILL.md | 14 | ### Step 1: Determine scope | COMMENT |
| LOW | .agents/skills/release/SKILL.md | 23 | ### Step 2: Research contributors | COMMENT |
| LOW | .agents/skills/release/SKILL.md | 46 | ### Step 3: Write the release notes | COMMENT |
| LOW | .agents/skills/release/SKILL.md | 112 | ### Step 4: Present for review | COMMENT |
| LOW | packages/inbox/api.ts | 1157 | // Step 2: attachments (by id only), annotations, deleting. | COMMENT |
| LOW | packages/inbox/api.ts | 1182 | // Step 8: New message to a live session of the thread's project. | COMMENT |
| LOW | packages/core/crypto.test.ts | 37 | p: "# Implementation Plan\n\n## Step 1: Add authentication\n\nWe'll use JWT tokens stored in httpOnly cookies.\n\n## S | CODE |
| LOW | packages/server/inbox.ts | 2166 | // Step 8: a polling session is live (New message can reach it) while its poll is held. | COMMENT |
| LOW | packages/server/inbox.ts | 3368 | // Step 8: the live sessions of a thread's project, and New message. | COMMENT |
| LOW | packages/server/inbox.ts | 3384 | // Step 2: attachments by id, annotations, the HTML asset route, delete | COMMENT |
| LOW⚡ | apps/hook/server/index.ts | 1333 | // Step 1: Fast skeleton clone (no checkout, depth 1 — minimal data transfer) | COMMENT |
| LOW⚡ | apps/hook/server/index.ts | 1339 | // Step 2: Fetch only the PR head ref (targeted, much faster than full fetch) | COMMENT |
| LOW⚡ | apps/hook/server/index.ts | 1346 | // Step 3: Checkout PR head (critical — if this fails, worktree is empty) | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/manual/local/test-binary.sh | 4 | # Usage: | COMMENT |
| LOW | tests/manual/local/test-sessions.sh | 4 | # Usage: | COMMENT |
| LOW | tests/manual/local/test-jj-review.sh | 4 | # Usage: | COMMENT |
| LOW | tests/manual/local/test-loose-list.sh | 5 | # Usage: | COMMENT |
| LOW | tests/manual/local/sandbox-opencode-isolated.sh | 4 | # Usage: | COMMENT |
| LOW | tests/manual/local/test-worktree-review.sh | 4 | # Usage: | COMMENT |
| LOW | tests/manual/local/test-bulk-plans.sh | 4 | # Usage: | COMMENT |
| LOW | tests/manual/local/sandbox-opencode.sh | 4 | # Usage: | COMMENT |
| LOW | tests/manual/local/sandbox-gemini.sh | 4 | # Usage: | COMMENT |
| LOW | tests/manual/local/test-hook.sh | 4 | # Usage: | COMMENT |
| LOW | tests/manual/local/sandbox-pi.sh | 4 | # Usage: | COMMENT |
| LOW | tests/manual/local/test-opencode-review.sh | 4 | # Usage: | COMMENT |
| LOW | tests/manual/local/test-external-annotations.sh | 4 | # Usage: | COMMENT |
| LOW | tests/manual/local/sandbox-codex.sh | 4 | # Usage: | COMMENT |
| LOW | tests/manual/local/test-codex-plan-review-e2e.sh | 8 | # Usage: | COMMENT |
| LOW | tests/manual/local/test-hook-2.sh | 4 | # Usage: | COMMENT |
| LOW | tests/manual/path-detection/setup.sh | 4 | # Usage: | COMMENT |
| LOW | tests/manual/path-detection/run-plan.sh | 4 | # Usage: | COMMENT |
| LOW | tests/manual/path-detection/run-annotate-out-of-tree.sh | 4 | # Usage: | COMMENT |
| LOW | tests/manual/path-detection/run-annotate-in-tree.sh | 4 | # Usage: | COMMENT |
| LOW | scripts/opencode2-native-commands-smoke.sh | 12 | # Usage: | COMMENT |
| LOW | scripts/bitbucket-live-smoke.sh | 27 | # Usage: | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/setup/gh-tripwire.ts | 20 | * absolute path, is caught only by that config and fake-token scrub, not by | COMMENT |
| LOW | tests/setup/gh-tripwire.ts | 49 | * verified for Bun's spawn. There only the config and fake-token scrub protect | COMMENT |
| LOW | tests/setup/gh-tripwire.ts | 118 | export const GH_FAKE_TOKEN = "plannotator-test-fake-token"; | CODE |
| LOW⚡ | tests/manual/path-detection/setup.sh | 66 | git config user.email "test@test.com" | CODE |
| LOW | tests/e2e/inbox-fullscreen-composer.spec.ts | 211 | await expect(replyField()).toHaveAttribute('placeholder', 'Reply to Claude Code…'); | CODE |
| LOW | tests/e2e/inbox-actions.spec.ts | 296 | await expect(note).toHaveAttribute('placeholder', 'Add a note for Claude Code'); | CODE |
| LOW | docs/agent-guides/project-and-development.md | 197 | - **Tests never run the real GitHub CLI.** The first bun test preload (`tests/setup/gh-tripwire.ts`, in every bunfig) pu | CODE |
| LOW⚡ | packages/ui/utils/identity.seam.test.ts | 48 | getIdentity: () => 'user@example.com', | CODE |
| LOW⚡ | packages/ui/utils/identity.seam.test.ts | 51 | return author === 'user@example.com'; | CODE |
| LOW⚡ | packages/ui/utils/identity.seam.test.ts | 57 | expect(isCurrentUser('user@example.com')).toBe(true); | CODE |
| LOW⚡ | packages/ui/utils/identity.seam.test.ts | 59 | expect(checked).toEqual(['user@example.com', 'other@example.com']); | CODE |
| LOW | packages/ui/components/ComposerTokenTextarea.tsx | 208 | 'value' | 'onChange' | 'onKeyDown' | 'onSelect' | 'onScroll' | 'className' | 'placeholder' | CODE |
| LOW | …i/components/html-viewer/htmlPinpointProtocol.test.tsx | 1824 | tag: 'input', attrs: [['value', 'hunter2'], ['onfocus', 'steal()'], ['style', 'x'], ['placeholder', 'Password'], [ | CODE |
| LOW | …i/components/html-viewer/htmlPinpointProtocol.test.tsx | 1827 | expect(context.attrs).toEqual([['placeholder', 'Password']]); | CODE |
| LOW | packages/ui/components/html-viewer/bridge-script.ts | 3141 | var CONTEXT_ATTRS = ['href', 'src', 'alt', 'title', 'type', 'name', 'role', 'placeholder', 'for', 'target', 'rel', | CODE |
| LOW | packages/inbox/feedbackDialog.test.tsx | 220 | expect(dialog.contact().getAttribute('placeholder')).toBe('Email (optional)'); | CODE |
| LOW | packages/core/html-anchor.ts | 127 | "href", "src", "alt", "title", "type", "name", "role", "placeholder", "for", "target", "rel", | CODE |
| LOW | packages/shared/pr-bitbucket.test.ts | 32 | const TOKEN = "fake-token-never-real-1234567890"; | CODE |
| LOW | packages/shared/inbox/search-text.test.ts | 95 | const text = `${'Lorem ipsum dolor sit amet, consectetur adipiscing elit. '.repeat(3)}The relay rate limit is 20 a m | CODE |
| LOW | packages/shared/inbox/search-text.test.ts | 95 | const text = `${'Lorem ipsum dolor sit amet, consectetur adipiscing elit. '.repeat(3)}The relay rate limit is 20 a m | CODE |
| LOW | apps/pi-extension/serverReview-bitbucket.test.ts | 30 | fake = startFakeBitbucket({ email: 'ada@example.invalid', token: 'pi-fake-token' }); | CODE |
| LOW | apps/pi-extension/serverReview-bitbucket.test.ts | 37 | process.env.PLANNOTATOR_BITBUCKET_TOKEN = 'pi-fake-token'; | CODE |
| LOW | apps/hook/server/bitbucket-review-cli.test.ts | 22 | const TOKEN = "fake-token-for-cli-test-0987654321"; | CODE |
| LOW | apps/hook/server/scrubbed-env-cli.test.ts | 146 | GH_TOKEN: "plannotator-test-fake-token", | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | bunfig.toml | 8 | # The Claude Code mod's engine-harness tests run under `claude plugin test` | COMMENT |
| MEDIUM | tests/manual/local/test-codex-plan-review-e2e.sh | 2 | # End-to-end Codex Stop-hook test harness for Plannotator. | COMMENT |
| MEDIUM | scripts/test-claude-code-mod.sh | 2 | # Run the Claude Code mod's engine-harness tests (`claude plugin test`, Claude | COMMENT |
| MEDIUM | scripts/test-claude-code-mod.sh | 6 | # apps/hook also holds the CLI and its bun tests, which the harness cannot load. | COMMENT |
| MEDIUM | packages/server/review.ts | 3066 | // Snapshot arg: robust against a future await sneaking in | COMMENT |
| MEDIUM | packages/server/review.ts | 3245 | // Snapshot args: robust against a future await sneaking in | COMMENT |
| MEDIUM | apps/pi-extension/server/serverReview.ts | 3025 | // Snapshot arg: robust against a future await sneaking in | COMMENT |
| MEDIUM | apps/pi-extension/server/serverReview.ts | 3185 | // Snapshot args: robust against a future await sneaking in | COMMENT |
| MEDIUM | apps/hook/bunfig.toml | 7 | # The mod's `claude plugin test` harness tests (see the root bunfig.toml). | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW⚡ | tests/manual/local/test-sessions.sh | 102 | # Step 0: Build | COMMENT |
| LOW⚡ | tests/manual/local/test-sessions.sh | 119 | # Step 1: Clean slate | COMMENT |
| LOW⚡ | tests/manual/local/test-sessions.sh | 128 | # Step 2: Launch plan server, validate session file content | COMMENT |
| LOW⚡ | tests/manual/local/test-sessions.sh | 169 | # Step 3: Launch review server, validate session file content | COMMENT |
| LOW⚡ | tests/manual/local/test-sessions.sh | 198 | # Step 4: Test `plannotator sessions` listing | COMMENT |
| LOW⚡ | tests/manual/local/test-sessions.sh | 227 | # Step 5: Test `sessions --open` | COMMENT |
| LOW⚡ | tests/manual/local/test-sessions.sh | 262 | # Step 6: Test stale session cleanup (auto + --clean) | COMMENT |
| LOW⚡ | tests/manual/local/test-sessions.sh | 325 | # Step 7: Approve/submit servers, verify session cleanup on exit | COMMENT |
| LOW | packages/inbox/api.ts | 1157 | // Step 2: attachments (by id only), annotations, deleting. | COMMENT |
| LOW | packages/inbox/api.ts | 1182 | // Step 8: New message to a live session of the thread's project. | COMMENT |
| LOW | packages/core/crypto.test.ts | 37 | p: "# Implementation Plan\n\n## Step 1: Add authentication\n\nWe'll use JWT tokens stored in httpOnly cookies.\n\n## S | CODE |
| LOW | packages/server/inbox.ts | 2166 | // Step 8: a polling session is live (New message can reach it) while its poll is held. | COMMENT |
| LOW | packages/server/inbox.ts | 3368 | // Step 8: the live sessions of a thread's project, and New message. | COMMENT |
| LOW | packages/server/inbox.ts | 3384 | // Step 2: attachments by id, annotations, the HTML asset route, delete | COMMENT |
| LOW⚡ | apps/hook/server/index.ts | 1333 | // Step 1: Fast skeleton clone (no checkout, depth 1 — minimal data transfer) | COMMENT |
| LOW⚡ | apps/hook/server/index.ts | 1339 | // Step 2: Fetch only the PR head ref (targeted, much faster than full fetch) | COMMENT |
| LOW⚡ | apps/hook/server/index.ts | 1346 | // Step 3: Checkout PR head (critical — if this fails, worktree is empty) | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | tests/e2e/inbox-guides.spec.ts | 176 | await expect(viewer.getByText(/2 sections · 1\/2 reviewed · generated by Claude · sonnet/)).toBeVisible(); | CODE |
| HIGH | tests/e2e/inbox-guides.spec.ts | 242 | await expect(viewer.getByText(/generated by Claude Code · claude-opus-5/)).toBeVisible(); | CODE |
| HIGH | docs/agent-guides/guides-and-shared-ui.md | 171 | *Security.* Embedded pages are untrusted author HTML served from the Plannotator server's origin. Inside the annotate su | COMMENT |
| HIGH | packages/server/html-assets.ts | 184 | // The host's own rule (the Inbox), judged as requested and by where the | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | tests/manual/local/enter-codex-plan-review-sandbox.sh | 2 | # Create a fresh isolated Codex + Plannotator sandbox and open a shell inside it. | COMMENT |
| MEDIUM | tests/manual/local/sandbox-opencode.sh | 1837 | # Create a loader file that re-exports from the source. | COMMENT |
| MEDIUM | tests/manual/local/sandbox-gemini.sh | 99 | # Create a temp plan file | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | docs/agent-guides/code-review.md | 667 | **One chat per session, documents named by path (#1001).** In the plan/annotate editor, Ask AI is ONE chat for the whole | CODE |
| MEDIUM | packages/ui/HANDOFF.md | 2578 | ## The law (guardrails for anyone editing `@plannotator/ui`) | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | packages/server/auto-update.ts | 877 | elif [ "$code" -eq 113 ]; then | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | packages/shared/code-nav.test.ts | 40 | expect(classifyMatch("export function handleRequest(", "handleRequest", lang)).toBe("definition"); | CODE |
| LOW | packages/shared/code-nav.test.ts | 96 | expect(classifyMatch("def handle_request(self, req):", "handle_request", lang)).toBe("definition"); | CODE |
| LOW | apps/paste-service/core/handler.ts | 90 | export async function handleRequest( | CODE |
| LOW | apps/waitlist-service/core/handler.ts | 29 | export async function handleRequest( | CODE |
| LOW | apps/feedback-service/core/handler.ts | 80 | export async function handleRequest(request: Request, deps: HandlerDeps): Promise<Response> { | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | …or-compound/scripts/extract_exit_plan_mode_outcomes.py | 199 | CODE | |
| LOW | …or-compound/scripts/extract_exit_plan_mode_outcomes.py | 368 | CODE | |
| LOW | …or-compound/scripts/extract_exit_plan_mode_outcomes.py | 464 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | scripts/install.sh | 981 | except Exception: | CODE |
| LOW | apps/marketing/public/install.sh | 981 | except Exception: | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/manual/local/test-binary.sh | 22 | # Check if plannotator is installed | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | …or-compound/scripts/extract_exit_plan_mode_outcomes.py | 29 | CODE |