diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index f950ebe..8c06e85 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,8 @@ blank_issues_enabled: false contact_links: + - name: Question or workflow idea + url: https://github.com/aryamthecodebreaker/FixMap/discussions + about: Ask usage questions, share examples, or discuss workflow ideas. - name: Security vulnerability url: https://github.com/aryamthecodebreaker/FixMap/security/advisories/new about: Report security-sensitive issues privately. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2e532a7..730a69f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,18 +2,55 @@ name: CI on: push: + branches: [main] pull_request: +permissions: + contents: read + +concurrency: + group: ci-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: test: runs-on: ubuntu-latest + timeout-minutes: 45 steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: fetch-depth: 0 - - uses: actions/setup-node@v6 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6 with: node-version: 24 cache: npm - run: npm ci - run: npm run ci + + compatibility: + name: Node ${{ matrix.node }} on ${{ matrix.os }} + timeout-minutes: 30 + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-latest + node: "20.11" + - os: ubuntu-latest + node: "22" + - os: windows-latest + node: "24" + - os: macos-latest + node: "24" + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + with: + fetch-depth: 0 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6 + with: + node-version: ${{ matrix.node }} + cache: npm + - run: npm ci + - run: npm run typecheck + - run: npm test diff --git a/.github/workflows/external-eval.yml b/.github/workflows/external-eval.yml index 8d1ec67..ba2bd7f 100644 --- a/.github/workflows/external-eval.yml +++ b/.github/workflows/external-eval.yml @@ -10,11 +10,12 @@ permissions: jobs: evaluate: + if: github.event_name != 'schedule' || github.repository == 'aryamthecodebreaker/FixMap' runs-on: ubuntu-latest timeout-minutes: 20 steps: - - uses: actions/checkout@v7 - - uses: actions/setup-node@v6 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6 with: node-version: 24 cache: npm diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 459f163..cb83db7 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -14,8 +14,7 @@ on: workflow_dispatch: permissions: - contents: write - id-token: write + contents: read concurrency: group: fixmap-release @@ -28,6 +27,9 @@ env: jobs: publish: + permissions: + contents: write + id-token: write runs-on: ubuntu-latest timeout-minutes: 45 steps: @@ -42,7 +44,7 @@ jobs: fi echo "VERSION=${GITHUB_REF_NAME#v}" >> "$GITHUB_ENV" - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: fetch-depth: 0 @@ -176,7 +178,7 @@ jobs: exit "$STATUS" fi - - uses: actions/setup-node@v6 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6 with: node-version: 24 cache: npm diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e303e4..82299d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,47 @@ Accuracy figures inside a released entry are the numbers measured **at that rele left as written. The current numbers live on the [evidence page](https://usefixmap.vercel.app/evidence), which is generated from the recorded results rather than transcribed by hand. +## 0.8.9 - 2026-08-11 + +### Added + +- `fixmap setup` installs a discoverable `/fixmap` command for Claude Code, Cursor, GitHub Copilot, and Agent Skills; invoking it without a task opens the complete feature catalog. `fixmap features` exposes the same catalog directly. +- `fixmap validate ` checks the versioned report contract, while `--fail-on warning` and the Action's `fail-on: warning` provide an opt-in strict Verify gate. +- Plan, Explain, MCP, and the Action expose a visible fresh-scan path with `--no-cache`/`noCache`, and cache hits now report age with bounded expiry and eviction. + +### Fixed + +- Ranking, grounding, file mentions, definition detection, import proximity, clustering, confidence, risk vocabulary, diff evidence, exact literals, Unicode text, inflections, typographic quotes, and generated/backup/configuration heuristics were corrected across the complete #500-#627 issue sweep. +- Repository mapping now handles nested package-manager lockfiles, conflicting roots, Windows and absolute exclusion paths, large ignore lists, tracked dirty cache states, BOM-less UTF-16 task files, oversized diffs, more source extensions, and language/test routing for C#, Java, PHP, Ruby, Go, Rust, Python, and JavaScript ecosystems. +- Explain, Compare, Verify, Validate, Doctor, remote repository acquisition, CLI parsing/output, MCP schemas, and copy-paste commands now fail clearly and preserve safe paths instead of silently accepting ambiguous or malformed state. +- GitHub Action comments, outputs, and job summaries stay within platform limits; API errors, pagination, permissions, credentials, Markdown, temporary clones, and generated bundle/metadata drift are handled defensively. + +### Security and release engineering + +- CI is least-privilege, timeout-bounded, non-duplicating, immutable-action pinned, full-tree audited, non-mutating, and configured for Node 20.11/22 plus Windows and macOS compatibility coverage. +- The publish workflow scopes write/OIDC permission to the release job and verifies the exact main commit, version metadata, npm packages, clean global install, MCP Registry entry, and GitHub Release before succeeding. + +### Website and documentation + +- The website uses a restrained editorial product system with clearer navigation, evidence, metadata, copy feedback, visibility-safe motion, and an honest interactive demo instead of synthetic marketing presentation. +- README and the npm package documentation now contain the full FixMap feature catalog, `/fixmap` setup, exclusion syntax, cache/report compatibility, Action controls, and public evidence boundaries. + +### Evidence + +- The release ledger maps all 126 open GitHub issues in #500-#627 (excluding already-closed #542 and #599) plus every item in the attached 30-finding review to a resolution and verification source. +- External, held-out, adversarial, BM25/lexical/path baselines, savings, rendered examples, package smoke tests, and the 1,000-file scan gate were regenerated and checked. The held-out evidence continues to state plainly where BM25 leads FixMap. + +### Installation + +```bash +npm install --global @aryam/fixmap@0.8.9 +fixmap doctor +fixmap setup +fixmap features +``` + +The release is complete only when the exact main commit is tagged `v0.8.9`, npm and MCP Registry serve 0.8.9, the GitHub release and Action tag resolve to that commit, production serves the matching website, and every public smoke check passes. + ## 0.8.8 - 2026-08-08 ### Added diff --git a/README.md b/README.md index a3a7668..c8ac781 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,14 @@ For a one-off trial: npx -y @aryam/fixmap@latest plan --issue https://github.com/chalk/chalk/issues/624 ``` +Install a discoverable `/fixmap` command for Claude Code, Cursor, GitHub Copilot, and Agent Skills: + +```bash +fixmap setup +``` + +Type `/fixmap` with no task to see the full feature menu, or run `fixmap features` in a terminal. Use `fixmap setup --agent ` to install one integration, and `--force` only after reviewing an existing customized command. + FixMap fetches a public task, infers its repository, scans a temporary isolated checkout, and removes it when the report is complete. Local repository analysis never uploads source. ## Everyday workflow @@ -61,42 +69,56 @@ Verify the completed diff against the saved plan: fixmap verify --report plan.json --diff main...HEAD ``` -Use `--working-tree` for staged and unstaged tracked edits, `--include-untracked` when new files should count as changes, `--exclude` or `.fixmapignore` to focus the map, and `--no-cache` to force a fresh scan. Run `fixmap --help` for the complete command reference. +Validate a saved report before another tool consumes it: + +```bash +fixmap validate plan.json +``` + +Use `--working-tree` for staged and unstaged tracked edits, `--include-untracked` when new files should count as changes, `--exclude` or `.fixmapignore` to focus the map, and `--no-cache` to force a fresh scan. Add `--fail-on warning` to Verify when advisory findings must fail CI. Run `fixmap --help` for the complete command reference. ## Complete feature catalog ### Inputs and repository mapping -- Accepts a public GitHub issue or pull-request URL, plain task text, a UTF-8 `--issue-file`, or task text from stdin. +- Accepts a public GitHub issue or pull-request URL, plain task text, a UTF-8 or UTF-16 `--issue-file` (including common BOM-less Windows UTF-16 files), or task text from stdin. - Normalizes supported browser and GitHub API issue URLs, including `www`, query strings, and fragments, while rejecting credentials, lookalike hosts, ports, and unsafe encoded paths. - Scans the current checkout, another local path, a `file://` URL, or an isolated checkout of a public GitHub repository. - Maps `--diff `, `--base`/`--head`, or the current `--working-tree`; untracked changes remain opt-in with `--include-untracked`. -- Reuses repository scans only when the repository root, commit, status, and binary diff are identical. `cache-hit` reports reuse, `--no-cache` bypasses it, and `FIXMAP_CACHE_DIR` moves the OS cache. -- Detects npm, pnpm, Yarn, and Bun projects and reads the scripts declared by each workspace package. +- Reuses raw repository scans only when the repository root, commit, status, and binary diff are identical. Task text, `--limit`, and exclusion rules are applied after that scan, so changing them can safely reuse the same cached files while still producing a newly ranked and filtered report; Compare scans the current plan, while Verify validates its supplied report against a fresh or exact-state repository map. `cache-hit` reports reuse and scan age, entries expire after seven days, and `FIXMAP_CACHE_DIR` moves the OS cache. Force a fresh scan with CLI `--no-cache`, MCP `noCache: true`, or Action `no-cache: true`. +- Keeps the current `--issue-file`, `--compare`, `--report`, and `--output` artifacts out of repository ranking, change detection, and cache invalidation, so FixMap never recommends its own report as the fix site. +- Detects npm, pnpm, Yarn, and Bun projects and reads the scripts declared by each workspace package. When the root is silent it can infer an agreed nested lockfile, while conflicting root declarations produce a diagnostic instead of silently choosing. ### Plan and ranking -- Ranks source, test, configuration, documentation, and other files from path terms, source content, identifiers, quoted fragments, file mentions, and real diff content. +- Ranks source, test, configuration, documentation, and other files from path terms, source content, identifiers, quoted fragments (including smart quotes and guillemets), file mentions, and real diff content. - Recognizes JavaScript/TypeScript declaration tests, Go `_test.go`, Python `test_*.py` and `*_test.py`, common test directories, and framework single-file components. -- Deprioritizes lockfiles, backups, bundled output, examples, and generated counterparts when maintained source exists. -- Routes reachable test commands from real package scripts and pairs them with the nearest related test files. +- Deprioritizes lockfiles, sync-client backups, bundled output, examples, and generated counterparts when maintained source exists, while keeping ordinary modules such as `deep-copy.ts` and tracked first-party `vendor/` source rankable. +- Routes reachable test commands from real package scripts and pairs them with the nearest related test files. It warns when routed JavaScript, Python, Go, or Rust tests are skipped, ignored, conditional, or gated. - Reports six bounded risk areas: authentication, billing, automation, data, public API, and dependencies. - Explains task grounding, ranking shape, unresolved or partially matched identifiers, exclusions, scan limits, unread content, skipped submodules, empty diffs, and Git failures. -- Supports `--limit`, repeatable `--exclude`, and ordered `.fixmapignore` patterns with negation. +- Supports a strict decimal `--limit`, repeatable `--exclude`, and ordered `.fixmapignore` patterns with negation. Root-leading patterns are repository-relative, pasted absolute paths inside the repository are normalized, and patterns that match nothing produce a warning. Limits change only how many rows are shown, never confidence or ranking-shape analysis. + +### Exclusion pattern syntax + +`--exclude` and `.fixmapignore` use repository-relative gitignore-style patterns. `/docs/**` anchors at the repository root, `docs/**` matches the same root directory and nested occurrences, `!docs/keep.md` re-includes a path after an earlier exclusion, and trailing `/` targets a directory. `*`, `?`, and `**` are supported; brace groups such as `{src,test}` are literal text, not alternation. Pass repeated `--exclude` flags or put one pattern per `.fixmapignore` line so commas in literal names stay unambiguous. + - Produces Markdown for people or versioned JSON for tools, writes to `--output`, and gives one grounded next action. -### Explain, Compare, Verify, and Doctor +### Explain, Compare, Verify, Validate, and Doctor - **Explain** tells you whether a path ranked, fell below the cutoff, was excluded, resolves through a submodule, or was never scanned—and uses the same task and diff evidence as Plan. - **Compare** shows files that entered, left, moved, or changed confidence after the task was refined, plus changes in task grounding. -- **Verify** compares a saved JSON plan with a diff or working tree and flags generated edits, unmapped changes, an untouched leading file, source changes without tests, newly reached risk areas, and plan/repository mismatches. +- **Verify** compares a saved JSON plan with a diff or working tree and flags generated edits, unmapped changes, an untouched leading file, source changes without tests, newly reached risk areas, and plan/repository mismatches. It fails on errors by default; `--fail-on warning` and the Action's `fail-on: warning` turn advisory findings into an opt-in CI gate. +- **Validate** checks any saved JSON report with the structural compatibility validator shared by Compare, Verify, the Action, and MCP. - **Doctor** prints the running version and executable path and diagnoses project, global, PATH, and npm-exec version shadows. - `FIXMAP_PROGRESS` controls remote clone/scan progress, and `FIXMAP_VERBOSE_USAGE` restores full usage text after argument errors. ### Agent and automation interfaces +- `fixmap setup` installs `/fixmap` discovery for Claude Code, Cursor, GitHub Copilot prompt files, and the open Agent Skills layout; the no-argument command lists every FixMap workflow before making changes. - The MCP server exposes `fixmap_plan`, `fixmap_explain`, `fixmap_compare`, `fixmap_verify`, and `fixmap_doctor` over local stdio and is published in the official MCP Registry. -- The GitHub Action runs Plan or Verify on pull requests, writes a full job summary, and creates or updates one bounded FixMap comment instead of posting duplicates. +- The GitHub Action runs Plan or Verify on pull requests, appends within the job summary's remaining 1 MiB budget, bounds its report output and comment, and creates or updates one FixMap comment instead of posting duplicates. - The Action accepts explicit task input or pull-request context, uses the same report validator as the CLI and MCP server, and fails clearly when a requested diff cannot be resolved. - The browser demo runs the real core Plan, Explain, Compare, and Verify logic against a sample repository without uploading the task. @@ -165,12 +187,12 @@ jobs: - uses: actions/checkout@v7 with: fetch-depth: 0 - - uses: aryamthecodebreaker/FixMap@v0.8.8 + - uses: aryamthecodebreaker/FixMap@v0.8.9 with: github-token: ${{ secrets.GITHUB_TOKEN }} ``` -The Action writes the complete report to the job summary and maintains one pull-request comment. Its checked-in bundle and metadata are release-gated. +The Action writes a bounded report to the job summary and maintains one pull-request comment. If GitHub's limits require truncation, the notice points to a local `--output` plus artifact upload for the complete report. Set `no-cache: true` when a workflow must bypass the exact-state scan cache, or `fail-on: warning` when advisory Verify findings must fail the job. Its checked-in bundle and metadata are release-gated. ## JSON compatibility diff --git a/action.yml b/action.yml index eb771cb..93228f2 100644 --- a/action.yml +++ b/action.yml @@ -13,6 +13,12 @@ inputs: Verify mode only. Path to the JSON plan this change was made from, usually restored from an artifact saved by an earlier plan step. required: false + fail-on: + description: >- + Verify mode only. error (default) fails only on error findings; warning also fails + when verification raises advisory warnings such as no-test-changed. + required: false + default: error issue: description: >- Issue, prompt, or review context for FixMap. Accepts a public GitHub issue or pull @@ -46,6 +52,10 @@ inputs: description: With working-tree, include untracked files. required: false default: "false" + no-cache: + description: Bypass the exact-state repository scan cache and perform a fresh scan. + required: false + default: "false" format: description: >- Output format. JSON is posted as a fenced JSON pull-request comment, and the step @@ -60,7 +70,7 @@ inputs: required: false outputs: report: - description: The complete FixMap report, or verification, in the selected format. + description: The bounded FixMap report, or verification, in the selected format. context-count: description: Number of context files returned. Plan mode only. test-route-count: diff --git a/apps/web/app/_components/copy-command.tsx b/apps/web/app/_components/copy-command.tsx index 78c791c..6ac0c3e 100644 --- a/apps/web/app/_components/copy-command.tsx +++ b/apps/web/app/_components/copy-command.tsx @@ -1,23 +1,37 @@ "use client"; import { Check, Copy } from "@phosphor-icons/react"; -import { useState } from "react"; +import { useRef, useState } from "react"; export function CopyCommand({ command, label = "Copy command" }: { command: string; label?: string }) { - const [copied, setCopied] = useState(false); + const [state, setState] = useState<"idle" | "copied" | "manual">("idle"); + const codeRef = useRef(null); async function copy() { - await navigator.clipboard.writeText(command); - setCopied(true); - window.setTimeout(() => setCopied(false), 1800); + try { + if (!navigator.clipboard?.writeText) throw new Error("Clipboard API unavailable"); + await navigator.clipboard.writeText(command); + setState("copied"); + } catch { + const code = codeRef.current; + if (code) { + const selection = window.getSelection(); + const range = document.createRange(); + range.selectNodeContents(code); + selection?.removeAllRanges(); + selection?.addRange(range); + } + setState("manual"); + } + window.setTimeout(() => setState("idle"), 2400); } return (
- {command} + {command}
); diff --git a/apps/web/app/_components/interactive-map-stage.tsx b/apps/web/app/_components/interactive-map-stage.tsx index 25740ff..0b7240a 100644 --- a/apps/web/app/_components/interactive-map-stage.tsx +++ b/apps/web/app/_components/interactive-map-stage.tsx @@ -15,6 +15,7 @@ type StageKey = "files" | "checks" | "risks"; type Example = { label: string; issue: string; + keywords: string[]; files: [string, string, string]; checks: [string, string, string]; risks: [string, string, string]; @@ -24,6 +25,7 @@ const examples: Example[] = [ { label: "Expiring reset links", issue: "Password reset links expire too early", + keywords: ["auth", "email", "expire", "link", "password", "reset", "token"], files: ["src/features/auth/reset/request.ts", "src/features/auth/reset/token-service.ts", "src/lib/email/templates/reset.ts"], checks: ["Token expiration logic", "Reset token integration tests", "Email link TTL configuration"], risks: ["Clock and timezone boundary", "Cached authentication config", "Email client link prefetch"] @@ -31,6 +33,7 @@ const examples: Example[] = [ { label: "Wrong invoice time zone", issue: "Invoices show the wrong time after daylight saving changes", + keywords: ["date", "daylight", "dst", "invoice", "time", "timezone"], files: ["src/timezone/resolve.ts", "src/invoices/summary.ts", "src/timezone/index.ts"], checks: ["Timezone conversion tests", "DST boundary cases", "Invoice rendering path"], risks: ["Cached timezone offsets", "External API assumptions", "Off-by-one date handling"] @@ -38,6 +41,7 @@ const examples: Example[] = [ { label: "Duplicate webhook event", issue: "Payment webhooks sometimes create duplicate orders", + keywords: ["duplicate", "idempotency", "order", "payment", "retry", "webhook"], files: ["src/payments/webhook.ts", "src/orders/create-order.ts", "src/payments/idempotency.ts"], checks: ["Webhook replay test", "Order idempotency suite", "Concurrent insert handling"], risks: ["Retry timing window", "Missing unique constraint", "Out-of-order delivery"] @@ -45,6 +49,39 @@ const examples: Example[] = [ ]; const firstExample = examples[0]!; +const genericWords = new Set([ + "a", "an", "and", "are", "be", "because", "broken", "bug", "create", "does", "error", "failed", "fails", "failure", + "fix", "for", "from", "in", "is", "issue", "it", "of", "on", "or", "problem", "sometimes", "the", "to", "when", "with", "wrong" +]); + +function issueWords(issue: string): string[] { + return [...new Set(issue.toLowerCase().match(/[a-z0-9]+/g) ?? [])] + .filter((word) => word.length > 2 && !genericWords.has(word)); +} + +function customResult(issue: string): Example { + const words = issueWords(issue); + const area = words[0]?.slice(0, 32) ?? "feature"; + const behavior = words[1]?.slice(0, 32) ?? "behavior"; + const title = `${area} ${behavior}`; + return { + label: "Custom issue preview", + issue, + keywords: words, + files: [`src/${area}/${behavior}.ts`, `src/${area}/index.ts`, `test/${area}/${behavior}.test.ts`], + checks: [`${title} behavior`, `${area} integration path`, `Regression for the reported issue`], + risks: ["Existing behavior compatibility", "Uncovered input boundary", "Related integration assumptions"] + }; +} + +function resultForIssue(issue: string): { example: Example; index: number } { + const words = new Set(issueWords(issue)); + const ranked = examples + .map((example, index) => ({ example, index, score: example.keywords.filter((keyword) => words.has(keyword)).length })) + .sort((left, right) => right.score - left.score); + const match = ranked[0]; + return match && match.score > 0 ? match : { example: customResult(issue), index: -1 }; +} const stageMeta: Array<{ key: StageKey; label: string; hint: string }> = [ { key: "files", label: "Files", hint: "Finding relevant code" }, @@ -100,11 +137,11 @@ function OutputCard({ export function InteractiveMapStage() { const [exampleIndex, setExampleIndex] = useState(0); const [issue, setIssue] = useState(firstExample.issue); + const [result, setResult] = useState(firstExample); const [activeStage, setActiveStage] = useState("files"); const [readyCount, setReadyCount] = useState(3); const [isRunning, setIsRunning] = useState(false); const timers = useRef([]); - const example = examples[exampleIndex] ?? firstExample; const clearTimers = () => { timers.current.forEach(window.clearTimeout); @@ -114,12 +151,15 @@ export function InteractiveMapStage() { useEffect(() => clearTimers, []); const stageItems = useMemo( - () => ({ files: example.files, checks: example.checks, risks: example.risks }), - [example] + () => ({ files: result.files, checks: result.checks, risks: result.risks }), + [result] ); const runMap = () => { clearTimers(); + const next = resultForIssue(issue); + setExampleIndex(next.index); + setResult(next.example); setIsRunning(true); setReadyCount(0); setActiveStage("files"); @@ -137,23 +177,25 @@ export function InteractiveMapStage() { clearTimers(); setExampleIndex(index); setIssue(nextExample.issue); + setResult(nextExample); setReadyCount(3); setActiveStage("files"); setIsRunning(false); }; return ( -
+
FixMap - Local analysis + Local demo
@@ -171,7 +213,7 @@ export function InteractiveMapStage() {
-
+
{stageMeta.map((stage, index) => { const isReady = readyCount > index; return ( diff --git a/apps/web/app/_components/pixel-sink-surface.tsx b/apps/web/app/_components/pixel-sink-surface.tsx index b50ebb9..0912cf7 100644 --- a/apps/web/app/_components/pixel-sink-surface.tsx +++ b/apps/web/app/_components/pixel-sink-surface.tsx @@ -176,7 +176,10 @@ export function PixelSinkSurface() { const onVisibility = () => { if (document.visibilityState === "visible") schedule(); - else if (frame) cancelAnimationFrame(frame); + else if (frame) { + cancelAnimationFrame(frame); + frame = 0; + } }; const observer = new ResizeObserver(resize); @@ -187,7 +190,10 @@ export function PixelSinkSurface() { resize(); return () => { - if (frame) cancelAnimationFrame(frame); + if (frame) { + cancelAnimationFrame(frame); + frame = 0; + } observer.disconnect(); host.removeEventListener("pointermove", onPointerMove); host.removeEventListener("pointerleave", onPointerLeave); diff --git a/apps/web/app/_components/product-map.tsx b/apps/web/app/_components/product-map.tsx index 28157ee..390cbaf 100644 --- a/apps/web/app/_components/product-map.tsx +++ b/apps/web/app/_components/product-map.tsx @@ -25,7 +25,7 @@ const outputs = [ export function ProductMap({ compact = false }: { compact?: boolean }) { return ( -
+
1
@@ -45,7 +45,7 @@ export function ProductMap({ compact = false }: { compact?: boolean }) {
-

{title}

+

{title}

{items.map((item, index) =>

{index + 1}{item}

)}
diff --git a/apps/web/app/_components/site-header.tsx b/apps/web/app/_components/site-header.tsx index 803cdfd..5e2be49 100644 --- a/apps/web/app/_components/site-header.tsx +++ b/apps/web/app/_components/site-header.tsx @@ -46,7 +46,7 @@ export function SiteHeader() {
- + Navigation menu
diff --git a/apps/web/app/_lib/site-data.ts b/apps/web/app/_lib/site-data.ts index 4ec4766..0b90268 100644 --- a/apps/web/app/_lib/site-data.ts +++ b/apps/web/app/_lib/site-data.ts @@ -7,9 +7,10 @@ import adversarial from "../../../../benchmarks/adversarial/results.json"; import cli from "../../../../packages/cli/package.json"; type EvaluationCase = { - top1: boolean; - top3: boolean; + top1Hit: boolean; + top3Hit: boolean; top5Hit: boolean; + top5Paths: string[]; }; const hits = (results: EvaluationCase[], key: keyof EvaluationCase) => @@ -17,6 +18,12 @@ const hits = (results: EvaluationCase[], key: keyof EvaluationCase) => const heldoutResults = heldout.results as EvaluationCase[]; const regressionResults = regression.results as EvaluationCase[]; +const confidenceCalibration = (["high", "medium", "low"] as const).map((confidence) => { + const bands = [heldout, regression].flatMap((suite) => suite.calibration.filter((entry) => entry.confidence === confidence)); + const cases = bands.reduce((total, band) => total + band.cases, 0); + const correct = bands.reduce((total, band) => total + band.top1Correct, 0); + return { confidence, cases, correct, accuracy: cases === 0 ? null : correct / cases }; +}); export const repoUrl = "https://github.com/aryamthecodebreaker/FixMap"; export const npmUrl = "https://www.npmjs.com/package/@aryam/fixmap"; @@ -59,10 +66,11 @@ const baselineOf = (suite: BaselineSuite) => ({ export const siteStats = { version: cli.version, medianSeconds: (savings.performance.medianScanAndRankMs / 1000).toFixed(2), + confidenceCalibration, heldout: { cases: heldout.cases, - top1: hits(heldoutResults, "top1"), - top3: hits(heldoutResults, "top3"), + top1: hits(heldoutResults, "top1Hit"), + top3: hits(heldoutResults, "top3Hit"), top5: hits(heldoutResults, "top5Hit"), intervals95: heldout.intervals95, cohorts: cohortOf(heldout), @@ -70,8 +78,8 @@ export const siteStats = { }, regression: { cases: regression.cases, - top1: hits(regressionResults, "top1"), - top3: hits(regressionResults, "top3"), + top1: hits(regressionResults, "top1Hit"), + top3: hits(regressionResults, "top3Hit"), top5: hits(regressionResults, "top5Hit"), intervals95: regression.intervals95, cohorts: cohortOf(regression), @@ -95,5 +103,8 @@ export const commands = { localTask: "fixmap plan --issue \"password reset emails fail\"", diff: "fixmap plan --diff main...HEAD", verify: "fixmap verify --report plan.json --diff main...HEAD", + validate: "fixmap validate plan.json", + setup: "fixmap setup", + features: "fixmap features", mcp: "fixmap mcp" }; diff --git a/apps/web/app/changelog/page.tsx b/apps/web/app/changelog/page.tsx index 9f6b126..483d984 100644 --- a/apps/web/app/changelog/page.tsx +++ b/apps/web/app/changelog/page.tsx @@ -43,10 +43,47 @@ type Release = { }; const releases: Release[] = [ + { + version: "0.8.9", + date: "August 11, 2026", + label: "Latest release", + summary: "A complete reliability sweep across ranking, verification, agent discovery, workflows, evidence, and the public product surface.", + groups: [ + { + label: "Added", + items: [ + "Install /fixmap for supported coding agents and open the complete feature catalog without supplying a task.", + "Validate saved reports from the CLI and opt into warning-level Verify failures in the CLI or GitHub Action.", + "Control fresh scans consistently across CLI, MCP, and Action interfaces with visible cache diagnostics." + ] + }, + { + label: "Fixed", + items: [ + "Ranking, grounding, definitions, file mentions, diffs, Unicode text, workspace routing, exclusions, caching, and cross-language test detection now cover the full reviewed issue set.", + "Explain, Compare, Verify, Doctor, MCP, remote repositories, and the Action reject malformed or ambiguous state with actionable diagnostics.", + "GitHub output limits, permissions, API failures, credentials, temporary repositories, and generated metadata are handled defensively." + ] + }, + { + label: "Improved", + items: [ + "The website now uses a calmer editorial design, clearer product navigation, reliable copy feedback, visibility-safe motion, and complete metadata.", + "README, npm documentation, slash-command setup, release notes, and the post-release checklist cover every supported workflow." + ] + }, + { + label: "Evidence", + items: [ + "The release ledger maps 126 GitHub issues plus the complete attached 30-finding review to fixes and verification.", + "External, held-out, adversarial, baseline, savings, package, generated-output, and 1,000-file scan gates are recorded and reproducible." + ] + } + ] + }, { version: "0.8.8", date: "August 8, 2026", - label: "Latest release", summary: "Forty-six issues closed across scan correctness, workflow honesty, the Action, documentation, accessibility, and release proof.", groups: [ { @@ -242,7 +279,7 @@ export default function ChangelogPage() {

Product changelog

-

Every improvement.
Plainly recorded.

+

Every improvement.{" "}
Plainly recorded.

New features, important fixes, and the evidence behind each recent FixMap release.

Current package: v{siteStats.version} diff --git a/apps/web/app/demo.tsx b/apps/web/app/demo.tsx index 52ad303..f587dcd 100644 --- a/apps/web/app/demo.tsx +++ b/apps/web/app/demo.tsx @@ -1,7 +1,8 @@ "use client"; -import { useEffect, useMemo, useRef, useState } from "react"; -import { buildPathExcluder, buildReportFromRepo, compareReports, explainFile, verifyPlan } from "@aryam/fixmap-core/browser"; +import { useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react"; +import { buildPathExcluder, buildReportFromRepo, compareReports, explainFile, quoteCliValue, verifyPlan } from "@aryam/fixmap-core/browser"; +import type { CliShell } from "@aryam/fixmap-core/browser"; import { sampleRepo, sampleRepoWithChanges, samplePaths } from "./sample-repo"; type Stage = "plan" | "explain" | "compare" | "verify"; @@ -41,6 +42,18 @@ const scenarios = [ const explainTargets = samplePaths; +function subscribeToShell(): () => void { + return () => undefined; +} + +function browserShell(): CliShell { + return /Windows/i.test(navigator.userAgent) ? "powershell" : "posix"; +} + +function serverShell(): CliShell { + return "posix"; +} + export function Demo() { const [task, setTask] = useState(presets[0]!.label); const [stage, setStage] = useState("plan"); @@ -99,10 +112,11 @@ export function Demo() { `${limit === 8 ? "" : ` --limit ${limit}`}` + `${excludeBuild ? ' --exclude "dist/**"' : ""}` + `${workingTree ? " --working-tree" : ""}`; - const quotedTask = quoteCliValue(task); + const shell = useSyncExternalStore(subscribeToShell, browserShell, serverShell); + const quotedTask = quoteCliValue(task, shell); const command = { plan: `fixmap plan --issue ${quotedTask}${scanFlags} --format json --output plan.json`, - explain: `fixmap plan --issue ${quotedTask} --explain ${quoteCliValue(explainTarget)}${scanFlags}`, + explain: `fixmap plan --issue ${quotedTask} --explain ${quoteCliValue(explainTarget, shell)}${scanFlags}`, compare: `fixmap plan --issue ${quotedTask} --compare plan.json${scanFlags}`, verify: `fixmap verify --report plan.json ${workingTree ? "--working-tree" : "--diff main...HEAD"}` }[stage]; @@ -135,7 +149,7 @@ export function Demo() {