{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// @self-review/types — Shared TypeScript type definitions.\n// Zero runtime dependencies. Used by @self-review/core, @self-review/react,\n// and the Electron app's src/shared/types.ts.\n\n// ===== Git Diff Types =====\n\nexport type ChangeType = 'added' | 'modified' | 'deleted' | 'renamed' | 'copied';\n\nexport type DiffLineType = 'context' | 'addition' | 'deletion';\n\nexport interface DiffLine {\n  type: DiffLineType;\n  oldLineNumber: number | null;\n  newLineNumber: number | null;\n  content: string;\n}\n\nexport interface DiffHunk {\n  header: string;\n  oldStart: number;\n  oldLines: number;\n  newStart: number;\n  newLines: number;\n  lines: DiffLine[];\n}\n\nexport interface DiffFile {\n  oldPath: string;\n  newPath: string;\n  changeType: ChangeType;\n  isBinary: boolean;\n  hunks: DiffHunk[];\n  isUntracked?: boolean;\n  contentLoaded?: boolean;\n  /** Set when a safety budget stopped the loader reading this file; `hunks` is then empty and this is shown instead. */\n  omittedReason?: string;\n}\n\n// ===== Diff Source Types =====\n\nexport type DiffSource =\n  | { type: 'git'; gitDiffArgs: string; repository: string }\n  | { type: 'directory'; sourcePath: string }\n  | { type: 'file'; sourcePath: string }\n  | { type: 'welcome' }\n  | { type: 'loading' };\n\n// ===== Review Source Identity =====\n\nexport type ReviewSourceMode = 'git' | 'directory' | 'file' | 'remote';\n\n/**\n * One side of a review's comparison, readable again later. A commit's SHA is resolved at load time.\n * `none` has no content; a read from `unknown` fails visibly rather than falling back to the working tree.\n */\nexport type ReviewSourceSide =\n  | { kind: 'working-tree' }\n  | { kind: 'index' }\n  | { kind: 'commit'; sha: string }\n  | { kind: 'directory' }\n  | { kind: 'file'; path: string }\n  | { kind: 'none' }\n  | { kind: 'unknown'; reason: string };\n\n/** What a session reviews, recorded once at commit. Reads and path authorization resolve against this, never the cwd. */\nexport interface ReviewSourceIdentity {\n  mode: ReviewSourceMode;\n  /** Physical directory (symlinks resolved) every reviewed path is relative to. */\n  sourceRoot: string;\n  invocationCwd: string;\n  gitDiffArgv: string[];\n  /** `/`-separated directory under `sourceRoot` that reviewed paths are relative to; empty except for `--relative` git reviews. */\n  pathPrefix: string;\n  oldSide: ReviewSourceSide;\n  newSide: ReviewSourceSide;\n}\n\n// ===== Review State Types =====\n\nexport interface Suggestion {\n  originalCode: string;\n  proposedCode: string;\n}\n\nexport interface Attachment {\n  id: string;\n  fileName: string;\n  mediaType: string;\n  data?: ArrayBuffer; // Present in-memory during session, stripped before XML serialization\n}\n\nexport interface LineRange {\n  side: 'old' | 'new';\n  start: number;\n  end: number;\n}\n\n/**\n * How consequential a finding is if it is real, most to least.\n * See SeverityEnum in self-review-v3.xsd for the semantics of each value.\n */\nexport type CommentSeverity = 'critical' | 'major' | 'minor' | 'info';\n\n/**\n * How sure the author is that a finding is real, most to least.\n * See ConfidenceEnum in self-review-v3.xsd for the semantics of each value.\n */\nexport type CommentConfidence = 'high' | 'medium' | 'low';\n\n/**\n * The forge hosting a remote pull/merge request.\n * See RemoteForgeEnum in self-review-v3.xsd.\n */\nexport type RemoteForge = 'github' | 'gitlab';\n\n/**\n * One turn in the conversation about a comment.\n *\n * A reply is deliberately thin. It carries no category, no severity, no\n * confidence and no suggestion: all four are properties of the finding, and\n * the finding is the root comment. A counter-proposal goes in `body` as a\n * fenced code block.\n *\n * Ordering is positional. The array order is the document order is the\n * conversation order, in all three directions. Nothing sorts replies.\n */\nexport interface Reply {\n  /**\n   * In-memory render key only. Like `ReviewComment.id`, this is regenerated\n   * on every parse and is never written to XML — the tree supplies parent\n   * linkage and document order supplies ordering, so nothing needs naming.\n   */\n  id: string;\n  body: string;\n  /** Absent means the human reviewer, present means a bot or LLM. */\n  author?: string;\n  attachments?: Attachment[];\n  /**\n   * Identifier of the remote comment this reply was fetched from, in the\n   * forge's own id space (see `ReviewState.remoteForge`). Undefined for\n   * replies authored locally. Never an ordering signal: array order stays\n   * conversation order.\n   */\n  remoteId?: string;\n}\n\nexport interface ReviewComment {\n  id: string;\n  filePath: string;\n  lineRange: LineRange | null; // null = file-level comment\n  body: string;\n  category: string;\n  suggestion: Suggestion | null;\n  author?: string;\n  // Thresholding signals. Undefined means the author took no position, and a\n  // consumer must treat that as below any floor it applies.\n  severity?: CommentSeverity;\n  confidence?: CommentConfidence;\n  orphaned?: boolean; // for --resume-from conflict handling\n  attachments?: Attachment[];\n  /** Ordered conversation turns on this comment. Undefined when there are none. */\n  replies?: Reply[];\n  /**\n   * Identifier of the remote discussion thread or comment this comment was\n   * fetched from, in the forge's own id space (see `ReviewState.remoteForge`).\n   * Undefined for comments authored locally.\n   */\n  remoteId?: string;\n}\n\nexport interface FileReviewState {\n  path: string;\n  changeType: ChangeType;\n  viewed: boolean;\n  comments: ReviewComment[];\n}\n\nexport interface ReviewState {\n  timestamp: string;\n  source: DiffSource;\n  files: FileReviewState[];\n  // Remote provenance. Set only for a review taken against a remote PR/MR;\n  // a purely local review carries none of these, and absent behaves like\n  // absent severity/confidence: the serializer omits the attribute and the\n  // parser leaves the field undefined.\n  /** URL of the remote pull/merge request under review. */\n  remoteUrl?: string;\n  /** Commit SHA the remote diff was computed from, for drift detection. */\n  remoteBaseSha?: string;\n  /** Commit SHA of the remote PR/MR head at fetch time, for drift detection. */\n  remoteHeadSha?: string;\n  /** Which forge hosts the remote PR/MR. Names the id space of remoteId values. */\n  remoteForge?: RemoteForge;\n}\n\n// ===== Remote PR/MR Session Types =====\n\n/**\n * Provenance and status of a remote PR/MR session, recorded at\n * materialization time. Rides on `DiffLoadPayload.remote` so the renderer\n * can display remote context; the main process injects the same provenance\n * into the submitted `ReviewState` before serialization, so the renderer\n * never needs to copy these fields back.\n */\nexport interface RemoteSessionInfo {\n  /** URL of the remote pull/merge request under review. */\n  remoteUrl: string;\n  /** Resolved SHA of the PR/MR base branch tip. */\n  remoteBaseSha: string;\n  /** Live SHA of the PR/MR head at materialization time. */\n  remoteHeadSha: string;\n  /** Which forge hosts the PR/MR. */\n  remoteForge: RemoteForge;\n  /**\n   * False when the forge CLI was unavailable and discussion threads could\n   * not be fetched; the review still opens fully (diff only).\n   */\n  threadSyncAvailable: boolean;\n  /**\n   * True when the diff was materialized into a temporary clone the app\n   * removes on exit, false when it reused a clone the user already owns.\n   *\n   * The distinction is a write boundary, not a detail: PRD Section 5.4.8\n   * bars applying a suggestion inside a temporary clone, so a front end\n   * branches on this to ask for a destination directory first.\n   */\n  temporaryClone: boolean;\n}\n\n/**\n * Drift comparison between a resumed document's recorded remote head SHA\n * and the live head SHA observed at materialization. Sent only when a\n * `--resume-from` document carries `remote-head-sha` in a remote session.\n */\nexport interface RemoteDriftInfo {\n  /** `remote-head-sha` recorded in the resumed document. */\n  recordedHeadSha: string;\n  /** Live head SHA from this session's materialization. */\n  liveHeadSha: string;\n  /** True when the two SHAs differ (the PR/MR moved since the review). */\n  drifted: boolean;\n}\n\n/**\n * Result of the `remote:open-url` channel (Renderer → Main, invoke).\n * On success the main process pushes `diff:load` (and `resume:load` when\n * threads were fetched) to the requesting window before resolving.\n */\nexport type RemoteOpenUrlResult = { ok: true } | { ok: false; error: string };\n\n// ===== Walkthrough Guide Types =====\n// The guide is a read-only sidecar (self-review-guide-v1.xsd) generated\n// before the review starts. It labels and orders files for orientation; it\n// can never hide them. See docs/intent/llm-review-guide.md.\n\n/**\n * One file inside a guide group. The path must match a diff file\n * (repository-relative, same convention as review.xml); entries whose path\n * matches nothing in the diff are silently dropped by the consumer.\n */\nexport interface GuideFileEntry {\n  /** File path relative to the repository root. For renames, the new path. */\n  path: string;\n  /** One-line description of the role this file plays in the change. */\n  description: string;\n}\n\n/**\n * A named set of related files in the walkthrough. Groups are labels for\n * orientation, never suppressions: every group and every file in it is\n * shown. Array position is reading order.\n */\nexport interface GuideGroup {\n  /** Short display name shown as the group heading, e.g. \"Core change\". */\n  name: string;\n  /** One line explaining why these files form a group and what to look for. */\n  rationale: string;\n  /** The files in this group, in reading order. At least one entry. */\n  files: GuideFileEntry[];\n}\n\n/**\n * A parsed walkthrough guide. Files in the diff that no group mentions are\n * presented by the consumer in an implicit trailing \"Everything else\"\n * group; that group is derived at render time and never part of this state.\n */\nexport interface ReviewGuide {\n  /**\n   * Review-level orientation prose shown before the first file. Markdown;\n   * may include a fenced code block labelled \"mermaid\" for a diagram.\n   * Absent when the guide has no overview.\n   */\n  overview?: string;\n  /** Ordered reading groups. Array position is reading order. */\n  groups: GuideGroup[];\n}\n\n/**\n * One file inside a resolved display group. Unlike {@link GuideFileEntry},\n * the description is optional: files swept into the implicit\n * \"Everything else\" group have no guide-authored one-liner.\n */\nexport interface ResolvedGuideFile {\n  /** File path relative to the repository root. For renames, the new path. */\n  path: string;\n  /** One-line description from the guide; absent for implicit-group files. */\n  description?: string;\n}\n\n/**\n * A display group produced by reconciling a {@link ReviewGuide} with the\n * actual diff file list. Guide entries missing from the diff are dropped,\n * duplicate references keep only their first group, and diff files the\n * guide never mentions land in a terminal implicit group (in diff order)\n * marked with `implicit: true` so the UI can label it.\n */\nexport interface ResolvedGuideGroup {\n  /** Display name for the group heading. */\n  name: string;\n  /** One-line rationale from the guide; absent for the implicit group. */\n  rationale?: string;\n  /** True only for the derived trailing \"Everything else\" group. */\n  implicit: boolean;\n  /** The files shown under this group, in display order. Never empty. */\n  files: ResolvedGuideFile[];\n}\n\n// ===== Configuration Types =====\n\nexport interface CategoryDef {\n  name: string;\n  description: string;\n  color: string;\n}\n\nexport interface AppConfig {\n  theme: 'light' | 'dark' | 'system';\n  diffView: 'split' | 'unified';\n  fontSize: number;\n  outputFormat: string;\n  outputFile: string;\n  ignore: string[];\n  categories: CategoryDef[];\n  defaultDiffArgs: string;\n  showUntracked: boolean;\n  showUntrackedExplicit: boolean;\n  wordWrap: boolean;\n  maxFiles: number;\n  maxTotalLines: number;\n  /**\n   * Path to the walkthrough guide sidecar (`guide-file` YAML key). When\n   * unset, the guide path is derived from the resolved output path as\n   * `<output-basename>.guide.xml`.\n   */\n  guideFile?: string;\n}\n\n// ===== IPC Payload Types =====\n\nexport interface DiffLoadPayload {\n  files: DiffFile[];\n  source: DiffSource;\n  isLargePayload?: boolean;\n  /** What the loader could not show faithfully, one message each. Diagnostics with no files is a failed load, not \"no changes\". */\n  diagnostics?: string[];\n  /**\n   * Present only for a remote PR/MR session. After materialization, remote\n   * mode is git mode: `source` stays `type: 'git'` with `repository` set to\n   * the materialized clone's root, and this field carries the remote\n   * provenance and thread-sync status alongside it.\n   */\n  remote?: RemoteSessionInfo;\n}\n\nexport interface ResumeLoadPayload {\n  /**\n   * Comments to restore. In a remote session this includes fetched forge\n   * threads mapped to `ReviewComment`s; review-level threads (no file\n   * anchor) keep the mapper's sentinel `filePath: ''`\n   * (REVIEW_LEVEL_FILE_PATH). The renderer surfaces those under a synthetic\n   * review-level entry and, on submit, keeps them in a `FileReviewState`\n   * with `path: ''` so the serializer emits a legal `<file path=\"\">`.\n   */\n  comments: ReviewComment[];\n  /** Paths the prior review marked as done. Absent when nothing was marked. */\n  viewedFiles?: string[];\n  /**\n   * Remote head drift, present only when a resumed document recorded a\n   * `remote-head-sha` in a remote session. See {@link RemoteDriftInfo}.\n   */\n  remoteDrift?: RemoteDriftInfo;\n  /** One line per resumed comment downgraded to file-level feedback (unusable anchor or unappliable suggestion). */\n  importDiagnostics?: string[];\n}\n\n/**\n * Payload for the `guide:load` channel (Main → Renderer). Sent only when a\n * valid walkthrough guide sidecar was discovered; carries display-ready\n * data — the overview plus groups already reconciled against the parsed\n * diff — so the renderer stays free of tolerance logic. Metadata only\n * (paths, names, descriptions): safe to send in large-payload mode.\n */\nexport interface GuideLoadPayload {\n  /** Review-level orientation prose (Markdown, optionally Mermaid). */\n  overview?: string;\n  /** Resolved display groups, in reading order. */\n  groups: ResolvedGuideGroup[];\n}\n\n// ===== Output Path Types =====\n\nexport interface OutputPathInfo {\n  resolvedOutputPath: string;\n  outputPathWritable: boolean;\n}\n\n// ===== Expand Context Types =====\n\nexport interface ExpandContextRequest {\n  filePath: string;\n  contextLines: number;\n}\n\nexport interface ExpandContextResponse {\n  hunks: DiffHunk[];\n  totalLines: number;\n}\n\n// ===== Find in Page Types =====\n\nexport interface FindInPageRequest {\n  text: string;\n  forward: boolean;\n  findNext: boolean;\n}\n\nexport interface FindInPageResult {\n  activeMatchOrdinal: number;\n  matches: number;\n  finalUpdate: boolean;\n}\n\n// ===== Version Update Types =====\n\nexport interface VersionUpdateInfo {\n  latestVersion: string;\n  releaseUrl: string;\n}\n\n// ===== Image Preview Types =====\n\nexport type ImageLoadResult = { dataUri: string } | { error: string };\n\n// ===== Payload Guard Types =====\n\nexport interface PayloadStats {\n  fileCount: number;\n  totalLines: number;\n  exceedsFiles: boolean;\n  exceedsLines: boolean;\n  exceedsAny: boolean;\n}\n\n// ===== Suggestion Apply Types =====\n//\n// The contract between the review UI and whatever host can write files.\n// It is deliberately narrower and looser than the apply engine's own result\n// type in @self-review/core. Narrower: the front end is handed no absolute\n// path, so the host projects the engine result onto this shape rather than\n// forwarding it. Looser: the UI never switches on a reason, it renders the\n// sentence the engine already wrote, and the host refuses for reasons the\n// engine cannot see, having no writable destination for one. So `reason` is\n// a plain string here rather than the engine's closed union.\n\n/** One apply attempt, as the UI knows it. The host names the destination. */\nexport interface SuggestionApplyRequest {\n  /** Path of the file to modify, relative to the review's source root. */\n  filePath: string;\n  /** The comment's anchor. `null` (file-level) is always refused. */\n  lineRange: LineRange | null;\n  suggestion: Suggestion;\n}\n\nexport interface SuggestionApplyApplied {\n  status: 'applied';\n  /** Echoed from the request, so a caller can attribute the result. */\n  filePath: string;\n  /** How many on-disk lines the proposal replaced. */\n  replacedLines: number;\n}\n\nexport interface SuggestionApplyRefused {\n  status: 'refused';\n  filePath: string;\n  /** Stable machine-readable reason, for logs and tests. Never file content. */\n  reason: string;\n  /** One sentence naming the refusal, safe to show to the reviewer. */\n  detail: string;\n}\n\nexport type SuggestionApplyOutcome = SuggestionApplyApplied | SuggestionApplyRefused;\n\n/**\n * The destination directory an apply writes into was named by the user.\n * Only a temporary-clone review needs one; every other review already has\n * a destination the user controls.\n */\nexport interface ApplyDestinationChosen {\n  status: 'chosen';\n  /** Absolute directory every later apply in this session resolves against. */\n  destinationRoot: string;\n}\n\n/** The user dismissed the picker. Nothing changed. */\nexport interface ApplyDestinationCancelled {\n  status: 'cancelled';\n}\n\n/** The picked directory cannot be written into. Nothing changed. */\nexport interface ApplyDestinationRejected {\n  status: 'rejected';\n  /** Stable machine-readable reason, for logs and tests. Never a file path. */\n  reason: string;\n  /** One sentence naming the rejection, safe to show to the reviewer. */\n  detail: string;\n}\n\nexport type ApplyDestinationOutcome =\n  | ApplyDestinationChosen\n  | ApplyDestinationCancelled\n  | ApplyDestinationRejected;\n"],"mappings":";;;;;;;;;;;;;;;;AAAA;AAAA;","names":[]}