@a9n-shoji/rvw 0.4.0-beta.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,24 @@
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [0.4.0] - 2026-09-01
9
+
10
+ ### Added
11
+
12
+ - 一つの具体的なbehavior / processing flowをsource-anchored origin、stable Node / Edge ID、exact source
13
+ anchorで提示し、1/2-hop / All、focus、pan / zoom / dragから探索できるproduction `Structure` document
14
+ - Structureのpublish / get / whole-value update / confirmation付きdeleteを行うCLI、Agent socket capability、
15
+ SQLite migration、HTTP API、Codex / Claude Code共通の`rvw-structure` Skill
16
+ - 変更表示の原文と行番号を保ちながら、追加・削除fileを除く空白だけの変更を`…`メニューから非表示にする
17
+ `Hide Whitespace`設定
18
+
19
+ ### Changed
20
+
21
+ - 固定サイズのStructure Node内をscroll可能にし、表記ごとの余白、canvasのpan / zoom感度、source anchorの
22
+ fallback、stale判定、明示的な再解決を改善
23
+ - light / dark themeのdiff canvas、文字、追加・削除行、gutter、inline emphasisの配色をGitHubへ合わせる
24
+ - Hide Whitespace切替時に現在のsource lineをviewportへ保持し、空白差分がすべて隠れた場合は解除方法を表示
25
+
8
26
  ## [0.4.0-beta.0] - 2026-08-31
9
27
 
10
28
  ### Added
package/dist/cli.mjs CHANGED
@@ -20187,7 +20187,7 @@ import path5 from "node:path";
20187
20187
  import { TextDecoder as TextDecoder2 } from "node:util";
20188
20188
 
20189
20189
  // src/shared/constants.ts
20190
- var APP_VERSION = "0.4.0-beta.0";
20190
+ var APP_VERSION = "0.4.0";
20191
20191
  var PROTOCOL_VERSION = 4;
20192
20192
  var VIEWER_ID_HEADER = "x-rvw-viewer-id";
20193
20193
  var VIEWER_OPEN_LEASE_HEADER = "x-rvw-viewer-open-lease";
@@ -28466,10 +28466,17 @@ function placeMutableDocumentComment(anchor, currentText) {
28466
28466
  return range ? { outdated: false, range } : { outdated: true, range: null };
28467
28467
  }
28468
28468
 
28469
- // src/domain/walkthrough-reference.ts
28470
- function walkthroughReferenceFingerprint(sourceOid, reference) {
28469
+ // src/domain/source-reference.ts
28470
+ function sourceAnchorFingerprint(sourceOid, reference) {
28471
28471
  return JSON.stringify([sourceOid, reference.path, reference.startLine, reference.endLine]);
28472
28472
  }
28473
+ function structureSourceAnchor(structure, locator) {
28474
+ if (locator.kind === "node") {
28475
+ return structure.nodes.find((node2) => node2.id === locator.nodeId)?.anchor ?? null;
28476
+ }
28477
+ const edge = structure.edges.find((candidate) => candidate.id === locator.edgeId);
28478
+ return edge?.anchors[locator.anchorIndex] ?? null;
28479
+ }
28473
28480
 
28474
28481
  // src/domain/source-excerpt.ts
28475
28482
  var SOURCE_EXCERPT_CONTEXT_LINES = 20;
@@ -42796,7 +42803,7 @@ var RvwService = class {
42796
42803
  }
42797
42804
  return walkthrough;
42798
42805
  }
42799
- async walkthroughReferenceFallbackTarget(pullRequest, sourceOid, filePath) {
42806
+ async sourceReferenceFallbackTarget(pullRequest, sourceOid, filePath) {
42800
42807
  const diffBaseOid = await this.git.firstParent(pullRequest.localRepositoryPath, sourceOid);
42801
42808
  if (!diffBaseOid) {
42802
42809
  return {
@@ -42827,22 +42834,47 @@ var RvwService = class {
42827
42834
  status: 404
42828
42835
  });
42829
42836
  }
42830
- const referenceFingerprint = walkthroughReferenceFingerprint(walkthrough.sourceOid, reference);
42837
+ const referenceFingerprint = sourceAnchorFingerprint(walkthrough.sourceOid, reference);
42838
+ return await this.resolveSourceAnchor(
42839
+ pullRequest,
42840
+ walkthrough.sourceOid,
42841
+ reference,
42842
+ referenceFingerprint
42843
+ );
42844
+ }
42845
+ async resolveStructureSource(pullRequestId, structureId, locator) {
42846
+ const pullRequest = this.getPullRequest(pullRequestId);
42847
+ const structure = this.getStructure(pullRequestId, structureId);
42848
+ const anchor = structureSourceAnchor(structure, locator);
42849
+ if (!anchor) {
42850
+ throw new RvwError("NOT_FOUND", "Structure\u306E\u53C2\u7167\u5143claim\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3002", {
42851
+ status: 404
42852
+ });
42853
+ }
42854
+ const resolution = await this.resolveSourceAnchor(
42855
+ pullRequest,
42856
+ structure.sourceOid,
42857
+ anchor,
42858
+ sourceAnchorFingerprint(structure.sourceOid, anchor)
42859
+ );
42860
+ return { ...resolution, resolvedAnchor: anchor };
42861
+ }
42862
+ async resolveSourceAnchor(pullRequest, sourceOid, reference, referenceFingerprint) {
42831
42863
  const sourceDocument = await this.getDocument({
42832
42864
  kind: "repository-file",
42833
- pullRequestId,
42834
- sourceOid: walkthrough.sourceOid,
42865
+ pullRequestId: pullRequest.id,
42866
+ sourceOid,
42835
42867
  path: reference.path
42836
42868
  });
42837
42869
  const latestHeadOid = pullRequest.latestHeadOid;
42838
42870
  let latestPath = reference.path;
42839
42871
  let latestDocument;
42840
- if (walkthrough.sourceOid === latestHeadOid) {
42872
+ if (sourceOid === latestHeadOid) {
42841
42873
  latestDocument = sourceDocument;
42842
42874
  } else {
42843
42875
  latestDocument = await this.getDocument({
42844
42876
  kind: "repository-file",
42845
- pullRequestId,
42877
+ pullRequestId: pullRequest.id,
42846
42878
  sourceOid: latestHeadOid,
42847
42879
  path: reference.path
42848
42880
  });
@@ -42851,7 +42883,7 @@ var RvwService = class {
42851
42883
  ...new Set(
42852
42884
  (await this.git.changedFilesWithCopies(
42853
42885
  pullRequest.localRepositoryPath,
42854
- walkthrough.sourceOid,
42886
+ sourceOid,
42855
42887
  latestHeadOid
42856
42888
  )).filter(
42857
42889
  (candidate) => (candidate.status.startsWith("R") || candidate.status.startsWith("C")) && candidate.oldPath === reference.path && candidate.newPath !== null
@@ -42861,7 +42893,7 @@ var RvwService = class {
42861
42893
  latestPath = successorPaths.length === 1 ? successorPaths[0] : null;
42862
42894
  latestDocument = latestPath === null ? null : await this.getDocument({
42863
42895
  kind: "repository-file",
42864
- pullRequestId,
42896
+ pullRequestId: pullRequest.id,
42865
42897
  sourceOid: latestHeadOid,
42866
42898
  path: latestPath
42867
42899
  });
@@ -42879,7 +42911,7 @@ var RvwService = class {
42879
42911
  if (resolvedToLatest && latestPath !== null && latestDocument !== null) {
42880
42912
  return {
42881
42913
  outcome: "latest",
42882
- anchorSourceOid: walkthrough.sourceOid,
42914
+ anchorSourceOid: sourceOid,
42883
42915
  latestHeadOid,
42884
42916
  referenceFingerprint,
42885
42917
  target: {
@@ -42896,9 +42928,9 @@ var RvwService = class {
42896
42928
  document: latestDocument
42897
42929
  };
42898
42930
  }
42899
- const targetFile = await this.walkthroughReferenceFallbackTarget(
42931
+ const targetFile = await this.sourceReferenceFallbackTarget(
42900
42932
  pullRequest,
42901
- walkthrough.sourceOid,
42933
+ sourceOid,
42902
42934
  reference.path
42903
42935
  );
42904
42936
  const latestFile = latestFileExists && latestPath !== null ? {
@@ -42911,7 +42943,7 @@ var RvwService = class {
42911
42943
  } : null;
42912
42944
  return {
42913
42945
  outcome: "source-fallback",
42914
- anchorSourceOid: walkthrough.sourceOid,
42946
+ anchorSourceOid: sourceOid,
42915
42947
  latestHeadOid,
42916
42948
  referenceFingerprint,
42917
42949
  target: {
@@ -47567,6 +47599,7 @@ var editCommentPostSchema = external_exports.object({
47567
47599
 
47568
47600
  // src/server/app.ts
47569
47601
  var oidSchema = external_exports.string().regex(GIT_OBJECT_ID_PATTERN);
47602
+ var nonnegativeIndexSchema = external_exports.coerce.number().int().nonnegative();
47570
47603
  var svgAssetContentSecurityPolicy = "default-src 'none'; style-src 'unsafe-inline'; base-uri 'none'; form-action 'none'; sandbox";
47571
47604
  function requiredQuery(value, name) {
47572
47605
  if (!value) throw new RvwError("INVALID_INPUT", `${name} query\u304C\u5FC5\u8981\u3067\u3059\u3002`);
@@ -47575,6 +47608,23 @@ function requiredQuery(value, name) {
47575
47608
  function oidQuery(value, name) {
47576
47609
  return oidSchema.parse(requiredQuery(value, name));
47577
47610
  }
47611
+ function structureSourceLocator(query) {
47612
+ if (query.locatorKind === "node") {
47613
+ return { kind: "node", nodeId: requiredQuery(query.nodeId, "nodeId") };
47614
+ }
47615
+ if (query.locatorKind === "edge") {
47616
+ const anchorIndex = nonnegativeIndexSchema.safeParse(query.anchorIndex);
47617
+ if (!anchorIndex.success) {
47618
+ throw new RvwError("INVALID_INPUT", "anchorIndex query\u306F0\u4EE5\u4E0A\u306E\u6574\u6570\u306B\u3057\u3066\u304F\u3060\u3055\u3044\u3002");
47619
+ }
47620
+ return {
47621
+ kind: "edge",
47622
+ edgeId: requiredQuery(query.edgeId, "edgeId"),
47623
+ anchorIndex: anchorIndex.data
47624
+ };
47625
+ }
47626
+ throw new RvwError("INVALID_INPUT", "locatorKind query\u306Fnode\u307E\u305F\u306Fedge\u306B\u3057\u3066\u304F\u3060\u3055\u3044\u3002");
47627
+ }
47578
47628
  function isWriteMethod(method) {
47579
47629
  return method === "POST" || method === "PUT" || method === "PATCH" || method === "DELETE";
47580
47630
  }
@@ -47873,6 +47923,21 @@ function createApp(service, options) {
47873
47923
  structure: service.getStructure(context.req.param("id"), context.req.param("structureId"))
47874
47924
  })
47875
47925
  );
47926
+ app.get("/api/pull-requests/:id/structures/:structureId/anchors/resolve", async (context) => {
47927
+ return context.json({
47928
+ ok: true,
47929
+ resolution: await service.resolveStructureSource(
47930
+ context.req.param("id"),
47931
+ context.req.param("structureId"),
47932
+ structureSourceLocator({
47933
+ locatorKind: context.req.query("locatorKind"),
47934
+ nodeId: context.req.query("nodeId"),
47935
+ edgeId: context.req.query("edgeId"),
47936
+ anchorIndex: context.req.query("anchorIndex")
47937
+ })
47938
+ )
47939
+ });
47940
+ });
47876
47941
  app.delete("/api/pull-requests/:id/structures/:structureId", async (context) => {
47877
47942
  const input = structureDeleteSchema.parse(await context.req.json());
47878
47943
  return context.json({