@davmash/bygone 0.7.1 → 0.8.3

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.
@@ -1292,7 +1292,11 @@ function applySource(source, defaultScenes, repoRoot) {
1292
1292
  continue;
1293
1293
  }
1294
1294
  if (authoredScene.kind === "stacked-diff") {
1295
- const stackedScene = buildStackedScene(repoRoot, authoredScene);
1295
+ const stackedScene = buildStackedScene(
1296
+ repoRoot,
1297
+ authoredScene,
1298
+ [...available.keys()]
1299
+ );
1296
1300
  scenes.push(stackedScene);
1297
1301
  sceneIds.push(stackedScene.id);
1298
1302
  continue;
@@ -1400,8 +1404,7 @@ function buildDeconstructedManifestScene(repoRoot, source, baseRef, targetRef) {
1400
1404
  }))
1401
1405
  };
1402
1406
  }
1403
- function buildStackedScene(repoRoot, source) {
1404
- var _a;
1407
+ function buildStackedScene(repoRoot, source, availableFilePaths) {
1405
1408
  const stack = source.stack.map((entry) => ({
1406
1409
  id: entry.id,
1407
1410
  ref: entry.ref,
@@ -1421,15 +1424,18 @@ function buildStackedScene(repoRoot, source) {
1421
1424
  maxBuffer: 16 * 1024 * 1024,
1422
1425
  stdio: ["ignore", "pipe", "pipe"]
1423
1426
  })));
1424
- const renamedPreviousPaths = new Set(adjacentChanges.flatMap((changes) => changes.map((change) => change.previousPath).filter((candidate) => Boolean(candidate))));
1425
- const changedFiles = [...new Set(adjacentChanges.flatMap((changes) => changes.map((change) => change.path)))].filter((filePath) => !renamedPreviousPaths.has(filePath)).sort();
1426
- const filePaths = ((_a = source.files) == null ? void 0 : _a.length) ? [...new Set(source.files)] : changedFiles;
1427
- for (const step of source.steps) {
1428
- if (!filePaths.includes(step.file)) throw new Error(`Stacked step ${step.id} references undeclared file ${step.file}.`);
1429
- }
1427
+ const filePaths = [.../* @__PURE__ */ new Set([
1428
+ ...availableFilePaths,
1429
+ ...source.files || [],
1430
+ ...source.steps.map((step) => step.file)
1431
+ ])].sort();
1430
1432
  if (filePaths.length === 0) throw new Error(`Stacked scene ${source.id} has no changed files.`);
1433
+ const requiredFilePaths = /* @__PURE__ */ new Set([
1434
+ ...source.files || [],
1435
+ ...source.steps.map((step) => step.file)
1436
+ ]);
1431
1437
  let totalContentBytes = 0;
1432
- const files = filePaths.map((filePath) => {
1438
+ const files = filePaths.flatMap((filePath) => {
1433
1439
  const aliases = /* @__PURE__ */ new Set([filePath]);
1434
1440
  for (const changes of adjacentChanges) {
1435
1441
  for (const change of changes) {
@@ -1439,26 +1445,35 @@ function buildStackedScene(repoRoot, source) {
1439
1445
  }
1440
1446
  }
1441
1447
  }
1442
- const panels = stack.map((entry) => {
1448
+ let fileContentBytes = 0;
1449
+ const panels = [];
1450
+ for (const entry of stack) {
1443
1451
  const resolvedPath = [...aliases].find((candidate) => gitBlobExists(repoRoot, entry.oid, candidate));
1444
1452
  if (!resolvedPath) {
1445
- return { id: entry.id, label: `${entry.label} / ${filePath} (missing)`, content: "", exists: false };
1453
+ panels.push({ id: entry.id, label: `${entry.label} / ${filePath} (missing)`, content: "", exists: false });
1454
+ continue;
1446
1455
  }
1447
1456
  const content = readGitText(repoRoot, entry.oid, resolvedPath, DEFAULT_MAX_TOUR_FILE_BYTES, DEFAULT_MAX_TOUR_LINE_BYTES);
1448
- if (content.kind !== "text") throw new Error(`Stacked tour file is binary or too large: ${resolvedPath}`);
1449
- totalContentBytes += Buffer.byteLength(content.content);
1450
- if (totalContentBytes > DEFAULT_MAX_STACK_CONTENT_BYTES) {
1451
- throw new Error(`Stacked tour content exceeds ${DEFAULT_MAX_STACK_CONTENT_BYTES} bytes.`);
1457
+ if (content.kind !== "text") {
1458
+ if (requiredFilePaths.has(filePath)) {
1459
+ throw new Error(`Stacked tour file is binary or too large: ${resolvedPath}`);
1460
+ }
1461
+ return [];
1452
1462
  }
1453
- return {
1463
+ fileContentBytes += Buffer.byteLength(content.content);
1464
+ panels.push({
1454
1465
  id: entry.id,
1455
1466
  label: `${entry.label} / ${resolvedPath}`,
1456
1467
  path: resolvedPath,
1457
1468
  content: content.content,
1458
1469
  exists: true
1459
- };
1460
- });
1461
- return { path: filePath, panels };
1470
+ });
1471
+ }
1472
+ totalContentBytes += fileContentBytes;
1473
+ if (totalContentBytes > DEFAULT_MAX_STACK_CONTENT_BYTES) {
1474
+ throw new Error(`Stacked tour content exceeds ${DEFAULT_MAX_STACK_CONTENT_BYTES} bytes.`);
1475
+ }
1476
+ return [{ path: filePath, panels }];
1462
1477
  });
1463
1478
  const stackIds = stack.map((entry) => entry.id);
1464
1479
  return {
@@ -1472,7 +1487,7 @@ function buildStackedScene(repoRoot, source) {
1472
1487
  stack,
1473
1488
  files,
1474
1489
  steps: source.steps.map((step) => {
1475
- var _a2, _b;
1490
+ var _a, _b;
1476
1491
  return {
1477
1492
  id: step.id,
1478
1493
  title: step.title,
@@ -1480,7 +1495,7 @@ function buildStackedScene(repoRoot, source) {
1480
1495
  file: step.file,
1481
1496
  pairIndex: stackIds.indexOf(step.pair[0]),
1482
1497
  side: step.side || "right",
1483
- startLine: (_a2 = step.lines) == null ? void 0 : _a2[0],
1498
+ startLine: (_a = step.lines) == null ? void 0 : _a[0],
1484
1499
  endLine: (_b = step.lines) == null ? void 0 : _b[1]
1485
1500
  };
1486
1501
  })
package/package.json CHANGED
@@ -1,19 +1,19 @@
1
1
  {
2
2
  "name": "@davmash/bygone",
3
- "version": "0.7.1",
3
+ "version": "0.8.3",
4
4
  "description": "See how change happened. Visual diff and file history.",
5
5
  "author": "David Mashburn",
6
6
  "license": "MIT",
7
7
  "homepage": "https://github.com/davidmashburn/bygone",
8
8
  "repository": {
9
9
  "type": "git",
10
- "url": "https://github.com/davidmashburn/bygone.git"
10
+ "url": "git+https://github.com/davidmashburn/bygone.git"
11
11
  },
12
12
  "bugs": {
13
13
  "url": "https://github.com/davidmashburn/bygone/issues"
14
14
  },
15
15
  "bin": {
16
- "bygone": "./bin/bygone.js"
16
+ "bygone": "bin/bygone.js"
17
17
  },
18
18
  "main": "./out/standalone-main.js",
19
19
  "files": [
@@ -27,6 +27,7 @@
27
27
  "docs/",
28
28
  "examples/",
29
29
  "schemas/",
30
+ "skills/",
30
31
  "README.md",
31
32
  "LICENSE.txt",
32
33
  "CHANGELOG.md"
@@ -0,0 +1,238 @@
1
+ ---
2
+ name: pr-tour-guide
3
+ description: Act as a PR Tour Guide by generating, validating, compiling, and presenting evidence-grounded Bygone code-change tours from Git ranges. Use for requests such as "Tour this commit for me," or whenever an AI coding agent should explain a pull request, branch, commit, or code change as a guided walkthrough; create or repair a .bygone file; produce an LLM-ready Bygone change context; connect narrative claims to exact source evidence; or turn a diff into a browser-presentable review or demo. Always print the exact `bygone` CLI command to open the resulting diff, review, tour, or history view.
4
+ ---
5
+
6
+ # PR Tour Guide
7
+
8
+ Use Bygone as the deterministic evidence and rendering layer. Treat the language model as the narrative planner, never as the authority on Git ranges or source locations.
9
+
10
+ ## Install this skill
11
+
12
+ For Cursor, Codex, Claude Code, and other agents supported by the skills CLI:
13
+
14
+ ```sh
15
+ npx skills add davidmashburn/bygone -s pr-tour-guide -g -y
16
+ ```
17
+
18
+ List without installing:
19
+
20
+ ```sh
21
+ npx skills add davidmashburn/bygone --list
22
+ ```
23
+
24
+ From a Bygone source checkout, install the local copy instead:
25
+
26
+ ```sh
27
+ npx skills add ./skills/pr-tour-guide -g -y
28
+ ```
29
+
30
+ ## Install Bygone
31
+
32
+ This skill requires the `bygone` CLI with `tour context`, `tour schema`, `tour validate`, and `tour compile`. Install only when the user asks or when the task cannot proceed without it.
33
+
34
+ **macOS (desktop app + CLI, recommended):**
35
+
36
+ ```sh
37
+ brew tap davidmashburn/bygone
38
+ brew install --cask bygone-desktop
39
+ ```
40
+
41
+ First install may require `brew trust davidmashburn/bygone`.
42
+
43
+ **CLI only (Node.js required):**
44
+
45
+ ```sh
46
+ npm install -g @davmash/bygone
47
+ ```
48
+
49
+ **macOS without Homebrew:** download the DMG from [GitHub Releases](https://github.com/davidmashburn/bygone/releases), then choose **Help → Install Command Line Tools…** in the app.
50
+
51
+ **From a Bygone source checkout:**
52
+
53
+ ```sh
54
+ npm install
55
+ npm run dev:sync
56
+ ```
57
+
58
+ ## Locate and verify Bygone
59
+
60
+ Run `bygone --help`. In a Bygone source checkout whose installed command is stale, use `node ./bin/bygone.js` instead.
61
+
62
+ Verify tour support before authoring:
63
+
64
+ ```sh
65
+ bygone tour schema >/dev/null
66
+ ```
67
+
68
+ If neither `bygone` nor `node ./bin/bygone.js` exposes the `tour` subcommands, stop, share the install commands above, and report that the toolchain is unavailable rather than guessing.
69
+
70
+ Do not rebuild, commit, push, publish, or open a browser unless the user requests it or the surrounding task clearly requires it.
71
+
72
+ ## Build the evidence context
73
+
74
+ Determine the intended head and base from the request and repository state. Prefer an explicit base; do not guess when different bases would materially change the explanation.
75
+
76
+ For a hosted review, resolve both immutable endpoint OIDs from provider metadata. Never assume the current checkout is the requested review head. For GitHub:
77
+
78
+ ```sh
79
+ PR_JSON="$(gh pr view <n> --json baseRefOid,headRefOid)"
80
+ BASE_OID="$(jq -r .baseRefOid <<<"$PR_JSON")"
81
+ HEAD_OID="$(jq -r .headRefOid <<<"$PR_JSON")"
82
+ test -n "$BASE_OID" && test "$BASE_OID" != null
83
+ test -n "$HEAD_OID" && test "$HEAD_OID" != null
84
+ bygone tour context "$HEAD_OID" --base "$BASE_OID" --output /tmp/change-context.json
85
+ ```
86
+
87
+ Use the equivalent API or CLI fields for other providers. If you are not reviewing a hosted change, compute the merge-base against the intended integration branch and pass that exact base OID or ref. Keep the existing preference for explicit endpoints and do not guess.
88
+
89
+ Use immutable commit IDs in the eventual tour. Dirty working-tree changes are reported but excluded from committed-range context.
90
+
91
+ Inspect progressively instead of loading every patch immediately:
92
+
93
+ ```sh
94
+ jq '{range,summary,commits,files:[.files[]|{path,previousPath,changeKind,role,additions,deletions,binary,patchOmittedReason,symbolHints}]}' /tmp/change-context.json
95
+ ```
96
+
97
+ Then read patches only for likely narrative-bearing files. Account explicitly for every `patchOmittedReason`; never claim to understand omitted binary or oversized evidence.
98
+
99
+ Compiled tours and context dossiers are large because they embed source snapshots. Inspect them progressively and do not load every patch unless the narrative really needs it.
100
+
101
+ ## Plan the explanation
102
+
103
+ Identify the smallest set of reviewer questions that makes the change understandable. Organize by conceptual dependency rather than filename order. Usually move through:
104
+
105
+ 1. motivation, contract, or invariant;
106
+ 2. core implementation;
107
+ 3. integration or side effects;
108
+ 4. failure behavior and proof.
109
+
110
+ Keep secondary, generated, dependency, and mechanical files in Bygone's complete Files rail unless they alter a reviewer conclusion.
111
+
112
+ Let the change determine the hierarchy. A chapter is a named conceptual arc containing one or more related scenes; a scene answers one reviewer question or advances one thesis. Do not target a fixed chapter count, and do not create a chapter merely to wrap each scene. Repeated one-scene chapters usually indicate that headings are being generated from a template instead of the change's actual structure.
113
+
114
+ Scale the structure proportionally:
115
+
116
+ - A small commit may need one chapter and one scene.
117
+ - A normal pull request often needs one to three chapters with one or more scenes in each.
118
+ - A broad release or long-lived branch may need several chapters, but each boundary must mark a real conceptual transition.
119
+ - Prefer merging adjacent chapters when their scenes form one argument; split a chapter only when its scenes answer materially different reviewer questions.
120
+
121
+ These are pacing heuristics, not quotas. Preserve asymmetry when one capability deserves substantially more explanation than another.
122
+
123
+ Use these narrative constraints:
124
+
125
+ - State one reviewer question or thesis per scene.
126
+ - Give every chapter a coherent multi-scene arc when the material supports one; allow a single-scene chapter only when that scene is independently substantial.
127
+ - Decompose scenes by conceptual need, not a fixed template; do not force every scene to use the same step count.
128
+ - Prefer three to seven steps per scene.
129
+ - Explain why focused code matters instead of paraphrasing syntax.
130
+ - Keep summaries, bullets, annotations, and takeaways distinct; bullets that merely restate the summary are a defect.
131
+ - Avoid intent, safety, performance, or runtime claims unsupported by the evidence.
132
+ - Do not imply that the authored tour exhaustively reviews every changed file.
133
+
134
+ ## Author the source
135
+
136
+ Retrieve the current contract:
137
+
138
+ ```sh
139
+ bygone tour schema > /tmp/change-tour-source.schema.json
140
+ ```
141
+
142
+ Write a `.bygone` file. The legacy `.bygone.yaml` spelling remains valid when
143
+ generic YAML tooling requires it. Treat either authored source as Git-backed,
144
+ not portable: pin `range.base` and `range.head` to the exact OIDs from the
145
+ context, and keep the file within the corresponding repository so Bygone can
146
+ resolve those objects. Use a compiled `.tour.json` only when a portable
147
+ snapshot is required.
148
+
149
+ For every step:
150
+
151
+ - make one concise explanatory claim;
152
+ - focus an anchor in `base` or `head` evidence;
153
+ - prefer changed lines, using unchanged context only when it establishes a required boundary;
154
+ - use the shortest snippet that is unique within that file and revision;
155
+ - connect behavior to tests, error handling, or other concrete proof;
156
+ - add a connection only when the relationship between two locations materially improves understanding.
157
+
158
+ Never emit generated line numbers or hunk indexes. Verify candidate snippets against the pinned object when uncertain:
159
+
160
+ ```sh
161
+ git show HEAD_OID:path/to/file | rg -F -n 'exact snippet'
162
+ ```
163
+
164
+ Use `occurrence` only when repetition is intentional and stable. Treat rename identity as evidence rather than describing a rename as unrelated deletion and addition.
165
+
166
+ ## Validate and repair
167
+
168
+ Always run validation before presenting or handing off:
169
+
170
+ ```sh
171
+ bygone tour validate review.bygone --json
172
+ ```
173
+
174
+ Repair every error. Do not weaken, delete, or redirect an anchor merely to make validation pass. If evidence no longer exists, revise the claim or report the broken premise.
175
+
176
+ After structural validation, check that:
177
+
178
+ Treat this as a required self-audit, not a claim the validator can prove. For each item, cite concrete evidence you actually opened or mark it not applicable; the hand-off must distinguish verified findings from interpretation.
179
+
180
+ - the first step establishes enough context for later steps;
181
+ - chapter boundaries follow conceptual transitions rather than a fixed count or one-scene-per-chapter pattern;
182
+ - important production behavior is not hidden in the complete Files rail;
183
+ - tests are connected to the behavior they prove;
184
+ - connections express causal, contractual, data-flow, ordering, or proof relationships;
185
+ - binary files and omitted patches are surfaced explicitly;
186
+ - the final step supplies proof or a clear reviewer conclusion.
187
+
188
+ ## Always print the open command
189
+
190
+ Whenever you create, validate, compile, recommend, or open a diff, review, tour, history view, or Git comparison, **always** print the exact one-line `bygone` command the user can paste to open it in the desktop app.
191
+
192
+ Do this even when you also run the command yourself, when presentation was not requested, and when handing off artifacts. Use the real paths and refs from the work; prefer absolute paths when a tour or file lives outside the current directory.
193
+
194
+ | Goal | Command template |
195
+ | --- | --- |
196
+ | Authored tour | `bygone -C <repository> present --tour <path/to/review.bygone>` |
197
+ | Branch review (change set) | `bygone review <head> --base <base>` |
198
+ | App-hosted range tour (no authored file) | `bygone present <head> --base <base>` |
199
+ | Two-way file or directory compare | `bygone <left> <right>` |
200
+ | Explicit diff mode | `bygone --diff <left> <right>` |
201
+ | Multi-panel compare | `bygone <path1> <path2> <path3> [...]` |
202
+ | Git refs compare | `bygone --git-diff <ref1> <ref2> [<ref3>...]` |
203
+ | File or directory history | `bygone --history <path>` |
204
+ | Repo directory history | `bygone` (from inside the Git repo) |
205
+
206
+ Tour tooling that does not open the app (`tour context`, `tour validate`, `tour compile`, `tour coverage`) still warrants the matching open command when a human should inspect the result visually.
207
+
208
+ ## Compile or present
209
+
210
+ Compile a portable manifest when the user needs an artifact:
211
+
212
+ ```sh
213
+ bygone tour compile review.bygone --output review.tour.json
214
+ ```
215
+
216
+ Open the interactive browser only when requested or useful for verifying the result:
217
+
218
+ ```sh
219
+ bygone -C /absolute/path/to/repository present --tour review.bygone
220
+ ```
221
+
222
+ Always print that same command with the real repository and tour paths, even if you do not run it. `-C` gives Bygone an explicit working directory without changing the user's shell directory.
223
+
224
+ Compiled manifests contain source snapshots. Do not publish or upload them without explicit authorization.
225
+
226
+ ## Hand off
227
+
228
+ Report:
229
+
230
+ - the exact base and head OIDs;
231
+ - the **open command** for the primary artifact (`bygone present --tour …`, `bygone review …`, `bygone --git-diff …`, etc.);
232
+ - the source and compiled artifact paths;
233
+ - authored chapter, scene, and step counts, plus compiled counts when the generated complete-change appendix changes them;
234
+ - omitted or unread evidence;
235
+ - validation and visual verification performed;
236
+ - whether generated files are temporary, uncommitted, committed, or pushed.
237
+
238
+ Distinguish syntactic grounding from interpretive correctness: Bygone proves that cited evidence exists at the pinned revision, not that the narrative's interpretation is unquestionably correct.
@@ -30,13 +30,13 @@
30
30
  <div id="change-toolbar" class="change-toolbar header-align-diff" hidden>
31
31
  <div class="change-toolbar-main">
32
32
  <div class="change-toolbar-nav">
33
- <button id="previous-file" class="change-button icon-button" type="button" title="Previous file" aria-label="Previous file">
33
+ <button id="previous-file" class="change-button icon-button" type="button" title="Open previous file" aria-label="Previous file">
34
34
  <svg viewBox="0 0 24 24" aria-hidden="true">
35
35
  <path d="M17 11l-5-5-5 5"></path>
36
36
  <path d="M17 18l-5-5-5 5" opacity="0.7"></path>
37
37
  </svg>
38
38
  </button>
39
- <button id="next-file" class="change-button change-button-primary icon-button" type="button" title="Next file" aria-label="Next file">
39
+ <button id="next-file" class="change-button change-button-primary icon-button" type="button" title="Open next file" aria-label="Next file">
40
40
  <svg viewBox="0 0 24 24" aria-hidden="true">
41
41
  <path d="M7 13l5 5 5-5"></path>
42
42
  <path d="M7 6l5 5 5-5" opacity="0.7"></path>
@@ -44,7 +44,7 @@
44
44
  </button>
45
45
  </div>
46
46
  <div class="change-toolbar-center">
47
- <button id="previous-change" class="change-button icon-button" type="button" title="Previous difference (Cmd/Ctrl+Alt+Up)" aria-label="Previous difference">
47
+ <button id="previous-change" class="change-button icon-button" type="button" title="Previous difference (Shift+F7 or Cmd/Ctrl+Shift+Up)" aria-label="Previous difference">
48
48
  <svg viewBox="0 0 24 24" aria-hidden="true">
49
49
  <path d="M12 19V5"></path>
50
50
  <path d="M6 11l6-6 6 6"></path>
@@ -65,7 +65,7 @@
65
65
  <path d="M5 5v14"></path>
66
66
  </svg>
67
67
  </button>
68
- <button id="next-change" class="change-button change-button-primary icon-button" type="button" title="Next difference (Cmd/Ctrl+Alt+Down)" aria-label="Next difference">
68
+ <button id="next-change" class="change-button change-button-primary icon-button" type="button" title="Next difference (F7 or Cmd/Ctrl+Shift+Down)" aria-label="Next difference">
69
69
  <svg viewBox="0 0 24 24" aria-hidden="true">
70
70
  <path d="M12 5v14"></path>
71
71
  <path d="M6 13l6 6 6-6"></path>
@@ -86,7 +86,7 @@
86
86
  </svg>
87
87
  </button>
88
88
  </div>
89
- <div class="change-hint">Cmd/Ctrl+Alt+Up/Down to jump.</div>
89
+ <div class="change-hint">F7 / Shift+F7 · Cmd/Ctrl+Shift+Up/Down to jump.</div>
90
90
  </div>
91
91
  <div id="history-toolbar" class="history-toolbar header-align-diff" hidden>
92
92
  <div class="history-side history-side-left">
@@ -94,14 +94,14 @@
94
94
  <div id="history-left-time" class="history-time"></div>
95
95
  </div>
96
96
  <div class="history-nav">
97
- <button id="history-back" class="history-button icon-button" type="button" title="Older commit" aria-label="Older commit">
97
+ <button id="history-back" class="history-button icon-button" type="button" title="Open older commit (Alt+Left)" aria-label="Older commit">
98
98
  <svg viewBox="0 0 24 24" aria-hidden="true">
99
99
  <path d="M15 18l-6-6 6-6"></path>
100
100
  <path d="M10 18l-6-6 6-6" opacity="0.7"></path>
101
101
  </svg>
102
102
  </button>
103
103
  <div id="history-position" class="history-position" role="status" aria-live="polite" aria-atomic="true"></div>
104
- <button id="history-forward" class="history-button icon-button" type="button" title="Newer commit" aria-label="Newer commit">
104
+ <button id="history-forward" class="history-button icon-button" type="button" title="Open newer commit (Alt+Right)" aria-label="Newer commit">
105
105
  <svg viewBox="0 0 24 24" aria-hidden="true">
106
106
  <path d="M9 18l6-6-6-6"></path>
107
107
  <path d="M14 18l6-6-6-6" opacity="0.7"></path>
package/web/index.html CHANGED
@@ -18,6 +18,18 @@
18
18
  <div id="tour-stats" class="tour-stats"></div>
19
19
  </div>
20
20
  </header>
21
+ <section class="tour-search" aria-label="Search tour">
22
+ <div class="tour-search-controls">
23
+ <input id="tour-search-input" type="search" placeholder="Search tour" aria-label="Search tour narrative and code">
24
+ <select id="tour-search-scope" aria-label="Tour search scope" title="Tour search scope">
25
+ <option value="all">Narrative + code</option>
26
+ <option value="narrative">Narrative</option>
27
+ <option value="code">Code</option>
28
+ </select>
29
+ </div>
30
+ <div id="tour-search-status" class="tour-search-status" role="status" aria-live="polite"></div>
31
+ <div id="tour-search-results" class="tour-search-results" role="listbox"></div>
32
+ </section>
21
33
  <div class="tour-rail-sections">
22
34
  <section class="tour-rail-section">
23
35
  <header class="tour-rail-heading">
@@ -39,7 +51,7 @@
39
51
  <summary id="tour-commits-summary">0 commits</summary>
40
52
  <ol id="tour-commits" class="tour-commits"></ol>
41
53
  </details>
42
- <div id="tour-sidebar-resizer" class="tour-sidebar-resizer" role="separator" aria-label="Resize tour sidebar" aria-orientation="vertical" aria-valuemin="240" aria-valuemax="600" tabindex="0"></div>
54
+ <div id="tour-sidebar-resizer" class="tour-sidebar-resizer" role="separator" aria-label="Resize tour sidebar" title="Resize tour sidebar (Left/Right; Home/End)" aria-orientation="vertical" aria-valuemin="240" aria-valuemax="600" tabindex="0"></div>
43
55
  </aside>
44
56
  <button id="tour-sidebar-show" class="tour-sidebar-show" type="button" title="Show tour sidebar" aria-label="Show tour sidebar" hidden>›</button>
45
57
  <section id="tour-narrative" class="tour-narrative" hidden>
@@ -66,6 +78,7 @@
66
78
  </div>
67
79
  </div>
68
80
  </section>
81
+ <div id="tour-narrative-resizer" class="tour-narrative-resizer" role="separator" aria-label="Resize tour header" title="Resize tour header (Up/Down; Home/End)" aria-orientation="horizontal" aria-valuemin="180" tabindex="0"></div>
69
82
  <div class="web-toolbar">
70
83
  <div class="web-toolbar-group">
71
84
  <button id="web-compare-test" type="button" title="Compare sample files">Compare Test Files</button>
@@ -100,13 +113,13 @@
100
113
  <div id="change-toolbar" class="change-toolbar header-align-diff" hidden>
101
114
  <div class="change-toolbar-main">
102
115
  <div class="change-toolbar-nav">
103
- <button id="previous-file" class="change-button icon-button" type="button" title="Previous file" aria-label="Previous file">
116
+ <button id="previous-file" class="change-button icon-button" type="button" title="Open previous file" aria-label="Previous file">
104
117
  <svg viewBox="0 0 24 24" aria-hidden="true">
105
118
  <path d="M17 11l-5-5-5 5"></path>
106
119
  <path d="M17 18l-5-5-5 5"></path>
107
120
  </svg>
108
121
  </button>
109
- <button id="next-file" class="change-button icon-button" type="button" title="Next file" aria-label="Next file">
122
+ <button id="next-file" class="change-button icon-button" type="button" title="Open next file" aria-label="Next file">
110
123
  <svg viewBox="0 0 24 24" aria-hidden="true">
111
124
  <path d="M7 13l5 5 5-5"></path>
112
125
  <path d="M7 6l5 5 5-5"></path>
@@ -114,7 +127,7 @@
114
127
  </button>
115
128
  </div>
116
129
  <div class="change-toolbar-center">
117
- <button id="previous-change" class="change-button icon-button" type="button" title="Previous difference (Cmd/Ctrl+Alt+Up)" aria-label="Previous difference">
130
+ <button id="previous-change" class="change-button icon-button" type="button" title="Previous difference (Shift+F7 or Cmd/Ctrl+Shift+Up)" aria-label="Previous difference">
118
131
  <svg viewBox="0 0 24 24" aria-hidden="true">
119
132
  <path d="M12 19V5"></path>
120
133
  <path d="M6 11l6-6 6 6"></path>
@@ -135,7 +148,7 @@
135
148
  <path d="M5 5v14"></path>
136
149
  </svg>
137
150
  </button>
138
- <button id="next-change" class="change-button change-button-primary icon-button" type="button" title="Next difference (Cmd/Ctrl+Alt+Down)" aria-label="Next difference">
151
+ <button id="next-change" class="change-button change-button-primary icon-button" type="button" title="Next difference (F7 or Cmd/Ctrl+Shift+Down)" aria-label="Next difference">
139
152
  <svg viewBox="0 0 24 24" aria-hidden="true">
140
153
  <path d="M12 5v14"></path>
141
154
  <path d="M6 13l6 6 6-6"></path>
@@ -156,7 +169,7 @@
156
169
  </svg>
157
170
  </button>
158
171
  </div>
159
- <div class="change-hint">Cmd/Ctrl+Alt+Up/Down to jump.</div>
172
+ <div class="change-hint">F7 / Shift+F7 · Cmd/Ctrl+Shift+Up/Down to jump.</div>
160
173
  </div>
161
174
  <div id="history-toolbar" class="history-toolbar header-align-diff" hidden>
162
175
  <div class="history-side history-side-left">
@@ -164,14 +177,14 @@
164
177
  <div id="history-left-time" class="history-time"></div>
165
178
  </div>
166
179
  <div class="history-nav">
167
- <button id="history-back" class="history-button icon-button" type="button" title="Older commit" aria-label="Older commit">
180
+ <button id="history-back" class="history-button icon-button" type="button" title="Open older commit" aria-label="Older commit">
168
181
  <svg viewBox="0 0 24 24" aria-hidden="true">
169
182
  <path d="M15 18l-6-6 6-6"></path>
170
183
  <path d="M10 18l-6-6 6-6" opacity="0.7"></path>
171
184
  </svg>
172
185
  </button>
173
186
  <div id="history-position" class="history-position" role="status" aria-live="polite" aria-atomic="true"></div>
174
- <button id="history-forward" class="history-button icon-button" type="button" title="Newer commit" aria-label="Newer commit">
187
+ <button id="history-forward" class="history-button icon-button" type="button" title="Open newer commit" aria-label="Newer commit">
175
188
  <svg viewBox="0 0 24 24" aria-hidden="true">
176
189
  <path d="M9 18l6-6-6-6"></path>
177
190
  <path d="M14 18l6-6-6-6" opacity="0.7"></path>