Files
backnotprop__plannotator/packages/review-editor/demoGuide.ts
Michael Ramos aa46dbb29a feat: guide per-file summaries + GitHub Copilot CLI agent engine (#997)
* feat(guide): per-file summary on guide diff refs

Each diffs[] entry now carries a required (schema-enforced) 1-2 sentence
summary of the semantic change in that file, written from the diff hunks
alone. Sanitizer passes it through when it's a non-blank string and omits
it otherwise -- a missing summary never drops the ref or fails the guide.
Rendered as a muted inline-markdown line above each diff in the guide;
marker-engine contract and demo data updated to match.

* fix(guide): repair prompt must not invent missing summaries

The guide schema now requires summary, so a schema-enforced repair of a
payload that lacks them (marker-engine output) would force the model to
fabricate captions with no diff in sight. Instruct it to fill missing
required fields with an empty string instead; the sanitizer already
renders nothing for blanks.

* feat(agents): GitHub Copilot CLI as a marker engine for review + guide jobs

Adds copilot as the fourth marker engine (no schema flag, so it uses the
nonce-tagged marker-block contract like Cursor/OpenCode/Pi):

- marker-review.ts: COPILOT_ENGINE — 'copilot --output-format json' JSONL
  stream (assistant.message carries the assembled text; deltas skipped),
  models discovered from 'copilot help config', live-log formatting for
  tool.execution_start/complete. Non-interactive posture: --no-ask-user
  auto-denies unallowed tools, --deny-tool=write, read-only-oriented shell
  allowlist (git/gh/glab/jj/wc), builtin MCPs and auto-update disabled.
- Exported MarkerEngineId and replaced every 'cursor'|'opencode'|'pi' cast
  with it (Bun server, Pi server mirror, guide-review) so the next engine
  is a two-edit change.
- agent-jobs (both runtimes): copilot in SERVER_BUILT_PROVIDERS; capability
  entry + model discovery come free from the MARKER_ENGINES loop.
- UI: copilot review/guide engine with per-surface model settings
  (useAgentSettings), AgentsTab launch + config rows, GuideEmptyState
  launcher, job-detail labels, CopilotIcon (currentColor, official mark).
- Tests: argv/read-only flags, help-config model parsing, stream reduction,
  full marker pipeline; profile-map expectations widened.

Verified live: composed review prompt through the real copilot binary,
marker block parsed, seeded bug found.

* fix(agents): structurally deny high-consequence verbs for Copilot jobs

git:*/gh:*/glab:* stay allowed for inspection ergonomics, but Copilot's
deny-precedence rules now block the verbs a prompt-injected background
job could abuse: git push/reset/clean/checkout/restore (local reviews run
in the user's real working tree), and PR/MR/issue comment/create/merge/
close/edit/review on gh and glab. Probe-verified: git log runs, git push
--dry-run is denied by the shell(git push) rule.

Addresses the one confirmed finding from the PR #997 review round; the
other two (untracked-file reads, git -C) were refuted by live probes.
2026-07-05 09:12:20 -07:00

65 lines
3.4 KiB
TypeScript

/**
* Demo guide data for development mode.
*
* Loaded by useGuideData when jobId === DEMO_GUIDE_ID, so the Guided Review
* screen renders with realistic content without needing an agent run. Section
* diffs reference the real file paths from demoData.ts's DEMO_DIFF so the
* per-section DiffViewers resolve against the actual demo files array instead
* of hitting the "outdated" chip.
*/
import type { CodeGuideData } from '@plannotator/shared/guide';
export const DEMO_GUIDE_ID = 'demo-guide';
export const DEMO_GUIDE: CodeGuideData = {
title: 'Typed API client, resilient auth, and a safer Button',
intent:
'Rewrites the auth hook against a typed request layer so login/refresh failures surface as real errors instead of silent nulls, and closes a long-standing bug where Button fired onClick while disabled.',
sections: [
{
title: 'Button respects disabled at both the prop and DOM level',
overview:
'The click handler now checks `disabled` before calling `onClick`, and the underlying `<button>` also gets the native `disabled` attribute via a new `variant` prop. Previously only the visual style hinted at disabled state; the handler still fired. This closes the gap that let a slow double-click submit a form twice. The handler is wrapped in `useCallback` so existing callsites that pass inline arrow functions don\'t cause extra re-renders.',
diffs: [
{
file: 'src/components/Button.tsx',
summary: 'Guards `onClick` behind the `disabled` prop and forwards native `disabled` to the DOM element.',
},
],
},
{
title: 'Auth hook rewritten against a typed request client',
overview:
'useAuth used to fake success/failure with untyped fetch calls; it now delegates to `api.auth.*`, a typed client with a proper `ApiError` class carrying status and code. `login`/`logout`/`refresh` are all `useCallback`-wrapped and the hook now tracks `error` in state so the UI can show why a login failed rather than just spinning. This is the change that made the Button fix visible in the first place: a disabled login button that silently still fired was masking failed-login retries.',
diffs: [
{
file: 'src/hooks/useAuth.ts',
summary: 'Replaces the untyped fetch calls with `api.auth.*` and adds `error` state so failed logins surface in the UI.',
},
{
file: 'src/services/api.ts',
summary: 'New typed request client with an `ApiError` class carrying HTTP status and error code.',
},
],
},
{
title: 'Formatting-only cleanup, no behavior change',
overview:
'settings.ts picked up a repo-wide indentation pass (2-space to 4-space in the config getters) with no logic changes beyond bumping the production pool max from 20 to a still-20 (no-op) — worth a glance only to confirm the diff really is whitespace. Modal.tsx is a new, self-contained portal-based dialog component added opportunistically; nothing in this changeset wires it up yet.',
diffs: [
{
file: 'src/config/settings.ts',
summary: 'Indentation-only reformat of the config getters; no behavior change.',
},
{
file: 'src/components/Modal.tsx',
summary: 'New portal-based dialog component; added but not yet wired up anywhere.',
},
],
},
],
unplacedFiles: ['src/utils/helpers.ts'],
reviewed: [],
};