@obversa/surface-diff opens a Git diff for review in a browser and returns
a decision with comments anchored to lines. Its obversa-review command
writes the result as framed JSON on stdout, with diagnostics on stderr, so a
script or an agent reads a person’s review without a screen. The guide is
Review a diff in a host pane; this page is the package.
Install
@obversa/obversa. You need Git.
Quickstart
Parse a unified diff and read the changed lines with their numbers:examples/surface-diff.ts
parseUnifiedDiff returns the files, each with its hunks and lines, each
line typed add, del or context with its old and new numbers. Run it
with npx tsx surface-diff.ts; it opens no browser:
Output
Review a diff
Run the command from the repository you want to review:Terminal
--staged the index, --range
the named Git range. --no-open prints the review URL instead of placing
the page. The result frame starts with <<<REVIEW_RESULT_V1>>> and ends
with <<<END_REVIEW_RESULT_V1>>>; --app <name> changes the app name and
so the markers. Exit 0 means the reviewer returned, a decision that
requests changes included; 1 means the session didn’t complete or the
command failed; 2 means the arguments were invalid.
Call it from code
reviewDiff(options) is the command’s function: it computes the diff,
builds the page, launches a surface and returns the framed result.
diffArgs builds the Git arguments for a mode and computeDiff runs them
and returns the text, buildIndexHtml builds the page, and
buildSurfaceRequest the request the session opens with, copying
surfaceId and gateId so a consumer routes the result.
validateAnnotation and normalizeResult check a submission against the
contract, and appendToThread(annotation, entry) adds a reply to an
annotation’s thread without changing the one you pass in. The bounds are
constants: MAX_ANNOTATIONS (500), MAX_BODY (4000 characters),
MAX_THREAD (100), with DECISIONS, SIDES, AUTHOR_KINDS, FAMILIES
and TRANSPORTS naming the allowed values.
Options
mode and range
mode is worktree (default), staged or range; range needs
range: 'A..B'. Naming two modes is a usage error.
The rest
Errors
TypeErrorfromreviewDiffwhenlaunchSurfaceorclientKitSourceis missing.- A conflicted diff is refused whole with a message naming the path.
- A repository that changes during capture stops after three attempts
with
The repository changed while the review was being captured; retry when it is quiet. - A submission whose decision disagrees with its annotations is refused and the page stays open.
API
reviewDiff(options): the review as a function. Call it from code.parseUnifiedDiff,computeDiff,diffArgs: the diff. Quickstart.buildIndexHtml,buildSurfaceRequest,isSurfaceRequest,isGateBinding,isTransport,ASSETS_DIR: the page and its request.validateAnnotation,normalizeResult,appendToThread,anchorKey,buildAnchorSet,outputAnchors: the result contract.- Constants:
MAX_ANNOTATIONS,MAX_BODY,MAX_THREAD,DECISIONS,SIDES,AUTHOR_KINDS,FAMILIES,TRANSPORTS. @obversa/surface-diff/bin: the command file, for a host to resolve and run under Node.@obversa/surface-diff/testing:highlightModel,contextModel,navModel,createHighlightRegistry,registryToCss,listTrackedFiles.
Next steps
- Review a diff in a host pane: the page, the result shape and the flags in full.
- Surface: the session and framing underneath.