@davmash/bygone 0.8.0 → 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.
package/out/changeTour.js CHANGED
@@ -1515,7 +1515,11 @@ function applySource(source, defaultScenes, repoRoot) {
1515
1515
  continue;
1516
1516
  }
1517
1517
  if (authoredScene.kind === "stacked-diff") {
1518
- const stackedScene = buildStackedScene(repoRoot, authoredScene);
1518
+ const stackedScene = buildStackedScene(
1519
+ repoRoot,
1520
+ authoredScene,
1521
+ [...available.keys()]
1522
+ );
1519
1523
  scenes.push(stackedScene);
1520
1524
  sceneIds.push(stackedScene.id);
1521
1525
  continue;
@@ -1623,8 +1627,7 @@ function buildDeconstructedManifestScene(repoRoot, source, baseRef, targetRef) {
1623
1627
  }))
1624
1628
  };
1625
1629
  }
1626
- function buildStackedScene(repoRoot, source) {
1627
- var _a;
1630
+ function buildStackedScene(repoRoot, source, availableFilePaths) {
1628
1631
  const stack = source.stack.map((entry) => ({
1629
1632
  id: entry.id,
1630
1633
  ref: entry.ref,
@@ -1644,15 +1647,18 @@ function buildStackedScene(repoRoot, source) {
1644
1647
  maxBuffer: 16 * 1024 * 1024,
1645
1648
  stdio: ["ignore", "pipe", "pipe"]
1646
1649
  })));
1647
- const renamedPreviousPaths = new Set(adjacentChanges.flatMap((changes) => changes.map((change) => change.previousPath).filter((candidate) => Boolean(candidate))));
1648
- const changedFiles = [...new Set(adjacentChanges.flatMap((changes) => changes.map((change) => change.path)))].filter((filePath) => !renamedPreviousPaths.has(filePath)).sort();
1649
- const filePaths = ((_a = source.files) == null ? void 0 : _a.length) ? [...new Set(source.files)] : changedFiles;
1650
- for (const step of source.steps) {
1651
- if (!filePaths.includes(step.file)) throw new Error(`Stacked step ${step.id} references undeclared file ${step.file}.`);
1652
- }
1650
+ const filePaths = [.../* @__PURE__ */ new Set([
1651
+ ...availableFilePaths,
1652
+ ...source.files || [],
1653
+ ...source.steps.map((step) => step.file)
1654
+ ])].sort();
1653
1655
  if (filePaths.length === 0) throw new Error(`Stacked scene ${source.id} has no changed files.`);
1656
+ const requiredFilePaths = /* @__PURE__ */ new Set([
1657
+ ...source.files || [],
1658
+ ...source.steps.map((step) => step.file)
1659
+ ]);
1654
1660
  let totalContentBytes = 0;
1655
- const files = filePaths.map((filePath) => {
1661
+ const files = filePaths.flatMap((filePath) => {
1656
1662
  const aliases = /* @__PURE__ */ new Set([filePath]);
1657
1663
  for (const changes of adjacentChanges) {
1658
1664
  for (const change of changes) {
@@ -1662,26 +1668,35 @@ function buildStackedScene(repoRoot, source) {
1662
1668
  }
1663
1669
  }
1664
1670
  }
1665
- const panels = stack.map((entry) => {
1671
+ let fileContentBytes = 0;
1672
+ const panels = [];
1673
+ for (const entry of stack) {
1666
1674
  const resolvedPath = [...aliases].find((candidate) => gitBlobExists(repoRoot, entry.oid, candidate));
1667
1675
  if (!resolvedPath) {
1668
- return { id: entry.id, label: `${entry.label} / ${filePath} (missing)`, content: "", exists: false };
1676
+ panels.push({ id: entry.id, label: `${entry.label} / ${filePath} (missing)`, content: "", exists: false });
1677
+ continue;
1669
1678
  }
1670
1679
  const content = readGitText2(repoRoot, entry.oid, resolvedPath, DEFAULT_MAX_TOUR_FILE_BYTES, DEFAULT_MAX_TOUR_LINE_BYTES);
1671
- if (content.kind !== "text") throw new Error(`Stacked tour file is binary or too large: ${resolvedPath}`);
1672
- totalContentBytes += Buffer.byteLength(content.content);
1673
- if (totalContentBytes > DEFAULT_MAX_STACK_CONTENT_BYTES) {
1674
- throw new Error(`Stacked tour content exceeds ${DEFAULT_MAX_STACK_CONTENT_BYTES} bytes.`);
1680
+ if (content.kind !== "text") {
1681
+ if (requiredFilePaths.has(filePath)) {
1682
+ throw new Error(`Stacked tour file is binary or too large: ${resolvedPath}`);
1683
+ }
1684
+ return [];
1675
1685
  }
1676
- return {
1686
+ fileContentBytes += Buffer.byteLength(content.content);
1687
+ panels.push({
1677
1688
  id: entry.id,
1678
1689
  label: `${entry.label} / ${resolvedPath}`,
1679
1690
  path: resolvedPath,
1680
1691
  content: content.content,
1681
1692
  exists: true
1682
- };
1683
- });
1684
- return { path: filePath, panels };
1693
+ });
1694
+ }
1695
+ totalContentBytes += fileContentBytes;
1696
+ if (totalContentBytes > DEFAULT_MAX_STACK_CONTENT_BYTES) {
1697
+ throw new Error(`Stacked tour content exceeds ${DEFAULT_MAX_STACK_CONTENT_BYTES} bytes.`);
1698
+ }
1699
+ return [{ path: filePath, panels }];
1685
1700
  });
1686
1701
  const stackIds = stack.map((entry) => entry.id);
1687
1702
  return {
@@ -1695,7 +1710,7 @@ function buildStackedScene(repoRoot, source) {
1695
1710
  stack,
1696
1711
  files,
1697
1712
  steps: source.steps.map((step) => {
1698
- var _a2, _b;
1713
+ var _a, _b;
1699
1714
  return {
1700
1715
  id: step.id,
1701
1716
  title: step.title,
@@ -1703,7 +1718,7 @@ function buildStackedScene(repoRoot, source) {
1703
1718
  file: step.file,
1704
1719
  pairIndex: stackIds.indexOf(step.pair[0]),
1705
1720
  side: step.side || "right",
1706
- startLine: (_a2 = step.lines) == null ? void 0 : _a2[0],
1721
+ startLine: (_a = step.lines) == null ? void 0 : _a[0],
1707
1722
  endLine: (_b = step.lines) == null ? void 0 : _b[1]
1708
1723
  };
1709
1724
  })
@@ -3092,6 +3092,7 @@ var require_commandSpec = __commonJS({
3092
3092
  "bygone --history <path>",
3093
3093
  "bygone --git-diff <ref1> <ref2> [<ref3>...]",
3094
3094
  "bygone review [<head>] [--base <base>]",
3095
+ "bygone -C <directory> <command-or-path> [...]",
3095
3096
  "bygone present [<head>] [--base <base>] [--tour <file.bygone>]",
3096
3097
  "bygone tour validate <file.bygone> [--json]",
3097
3098
  "bygone tour compile <file.bygone> [--output <tour.json>]",
@@ -3187,6 +3188,13 @@ var require_commandSpec = __commonJS({
3187
3188
  description: "Use an authored .bygone presentation",
3188
3189
  argument: "path"
3189
3190
  },
3191
+ {
3192
+ id: "directory",
3193
+ kind: "global",
3194
+ tokens: ["-C"],
3195
+ description: "Run as if Bygone started in this directory",
3196
+ argument: "path"
3197
+ },
3190
3198
  {
3191
3199
  id: "branch",
3192
3200
  kind: "option",
@@ -3219,6 +3227,7 @@ var require_commandSpec = __commonJS({
3219
3227
  "`--git-diff` accepts branches, tags, SHAs, HEAD~1, stash@{0}, INDEX, and WORKTREE.",
3220
3228
  "`review` compares merge-base(BASE,HEAD) with HEAD and detects the default base when omitted.",
3221
3229
  "`present` turns the same range into an app-hosted, ordered change tour.",
3230
+ "`-C <directory>` resolves relative paths and Git refs from that directory without changing the shell working directory.",
3222
3231
  "`tour validate` resolves every authored anchor; add `--json` for agent-readable output.",
3223
3232
  "`tour compile` writes a portable manifest to stdout or `--output`; `tour schema` prints its source schema.",
3224
3233
  "`tour context` emits compact, structured Git evidence for an LLM without invoking a model.",
@@ -5068,7 +5077,11 @@ var require_changeTour = __commonJS({
5068
5077
  continue;
5069
5078
  }
5070
5079
  if (authoredScene.kind === "stacked-diff") {
5071
- const stackedScene = buildStackedScene(repoRoot, authoredScene);
5080
+ const stackedScene = buildStackedScene(
5081
+ repoRoot,
5082
+ authoredScene,
5083
+ [...available.keys()]
5084
+ );
5072
5085
  scenes.push(stackedScene);
5073
5086
  sceneIds.push(stackedScene.id);
5074
5087
  continue;
@@ -5176,8 +5189,7 @@ var require_changeTour = __commonJS({
5176
5189
  }))
5177
5190
  };
5178
5191
  }
5179
- function buildStackedScene(repoRoot, source) {
5180
- var _a;
5192
+ function buildStackedScene(repoRoot, source, availableFilePaths) {
5181
5193
  const stack = source.stack.map((entry) => ({
5182
5194
  id: entry.id,
5183
5195
  ref: entry.ref,
@@ -5197,15 +5209,18 @@ var require_changeTour = __commonJS({
5197
5209
  maxBuffer: 16 * 1024 * 1024,
5198
5210
  stdio: ["ignore", "pipe", "pipe"]
5199
5211
  })));
5200
- const renamedPreviousPaths = new Set(adjacentChanges.flatMap((changes) => changes.map((change) => change.previousPath).filter((candidate) => Boolean(candidate))));
5201
- const changedFiles = [...new Set(adjacentChanges.flatMap((changes) => changes.map((change) => change.path)))].filter((filePath) => !renamedPreviousPaths.has(filePath)).sort();
5202
- const filePaths = ((_a = source.files) == null ? void 0 : _a.length) ? [...new Set(source.files)] : changedFiles;
5203
- for (const step of source.steps) {
5204
- if (!filePaths.includes(step.file)) throw new Error(`Stacked step ${step.id} references undeclared file ${step.file}.`);
5205
- }
5212
+ const filePaths = [.../* @__PURE__ */ new Set([
5213
+ ...availableFilePaths,
5214
+ ...source.files || [],
5215
+ ...source.steps.map((step) => step.file)
5216
+ ])].sort();
5206
5217
  if (filePaths.length === 0) throw new Error(`Stacked scene ${source.id} has no changed files.`);
5218
+ const requiredFilePaths = /* @__PURE__ */ new Set([
5219
+ ...source.files || [],
5220
+ ...source.steps.map((step) => step.file)
5221
+ ]);
5207
5222
  let totalContentBytes = 0;
5208
- const files = filePaths.map((filePath) => {
5223
+ const files = filePaths.flatMap((filePath) => {
5209
5224
  const aliases = /* @__PURE__ */ new Set([filePath]);
5210
5225
  for (const changes of adjacentChanges) {
5211
5226
  for (const change of changes) {
@@ -5215,26 +5230,35 @@ var require_changeTour = __commonJS({
5215
5230
  }
5216
5231
  }
5217
5232
  }
5218
- const panels = stack.map((entry) => {
5233
+ let fileContentBytes = 0;
5234
+ const panels = [];
5235
+ for (const entry of stack) {
5219
5236
  const resolvedPath = [...aliases].find((candidate) => gitBlobExists(repoRoot, entry.oid, candidate));
5220
5237
  if (!resolvedPath) {
5221
- return { id: entry.id, label: `${entry.label} / ${filePath} (missing)`, content: "", exists: false };
5238
+ panels.push({ id: entry.id, label: `${entry.label} / ${filePath} (missing)`, content: "", exists: false });
5239
+ continue;
5222
5240
  }
5223
5241
  const content = readGitText2(repoRoot, entry.oid, resolvedPath, DEFAULT_MAX_TOUR_FILE_BYTES, DEFAULT_MAX_TOUR_LINE_BYTES);
5224
- if (content.kind !== "text") throw new Error(`Stacked tour file is binary or too large: ${resolvedPath}`);
5225
- totalContentBytes += Buffer.byteLength(content.content);
5226
- if (totalContentBytes > DEFAULT_MAX_STACK_CONTENT_BYTES) {
5227
- throw new Error(`Stacked tour content exceeds ${DEFAULT_MAX_STACK_CONTENT_BYTES} bytes.`);
5242
+ if (content.kind !== "text") {
5243
+ if (requiredFilePaths.has(filePath)) {
5244
+ throw new Error(`Stacked tour file is binary or too large: ${resolvedPath}`);
5245
+ }
5246
+ return [];
5228
5247
  }
5229
- return {
5248
+ fileContentBytes += Buffer.byteLength(content.content);
5249
+ panels.push({
5230
5250
  id: entry.id,
5231
5251
  label: `${entry.label} / ${resolvedPath}`,
5232
5252
  path: resolvedPath,
5233
5253
  content: content.content,
5234
5254
  exists: true
5235
- };
5236
- });
5237
- return { path: filePath, panels };
5255
+ });
5256
+ }
5257
+ totalContentBytes += fileContentBytes;
5258
+ if (totalContentBytes > DEFAULT_MAX_STACK_CONTENT_BYTES) {
5259
+ throw new Error(`Stacked tour content exceeds ${DEFAULT_MAX_STACK_CONTENT_BYTES} bytes.`);
5260
+ }
5261
+ return [{ path: filePath, panels }];
5238
5262
  });
5239
5263
  const stackIds = stack.map((entry) => entry.id);
5240
5264
  return {
@@ -5248,7 +5272,7 @@ var require_changeTour = __commonJS({
5248
5272
  stack,
5249
5273
  files,
5250
5274
  steps: source.steps.map((step) => {
5251
- var _a2, _b;
5275
+ var _a, _b;
5252
5276
  return {
5253
5277
  id: step.id,
5254
5278
  title: step.title,
@@ -5256,7 +5280,7 @@ var require_changeTour = __commonJS({
5256
5280
  file: step.file,
5257
5281
  pairIndex: stackIds.indexOf(step.pair[0]),
5258
5282
  side: step.side || "right",
5259
- startLine: (_a2 = step.lines) == null ? void 0 : _a2[0],
5283
+ startLine: (_a = step.lines) == null ? void 0 : _a[0],
5260
5284
  endLine: (_b = step.lines) == null ? void 0 : _b[1]
5261
5285
  };
5262
5286
  })
@@ -8722,6 +8746,28 @@ var require_present = __commonJS({
8722
8746
  }
8723
8747
  });
8724
8748
 
8749
+ // cli/workingDirectory.js
8750
+ var require_workingDirectory = __commonJS({
8751
+ "cli/workingDirectory.js"(exports2, module2) {
8752
+ "use strict";
8753
+ var path9 = require("path");
8754
+ function resolveWorkingDirectory2(args, initialCwd) {
8755
+ const remainingArgs = [...args];
8756
+ let cwd = path9.resolve(initialCwd);
8757
+ while (remainingArgs[0] === "-C") {
8758
+ const directory = remainingArgs[1];
8759
+ if (!directory) {
8760
+ throw new Error("-C requires a directory.");
8761
+ }
8762
+ cwd = path9.resolve(cwd, directory);
8763
+ remainingArgs.splice(0, 2);
8764
+ }
8765
+ return { args: remainingArgs, cwd };
8766
+ }
8767
+ module2.exports = { resolveWorkingDirectory: resolveWorkingDirectory2 };
8768
+ }
8769
+ });
8770
+
8725
8771
  // standalone/launchArgs.js
8726
8772
  var require_launchArgs = __commonJS({
8727
8773
  "standalone/launchArgs.js"(exports2, module2) {
@@ -8752,7 +8798,7 @@ var require_package = __commonJS({
8752
8798
  displayName: "Bygone",
8753
8799
  desktopName: "com.davidmashburn.bygone.desktop",
8754
8800
  description: "See how change happened. Visual diff and file history for VS Code.",
8755
- version: "0.8.0",
8801
+ version: "0.8.3",
8756
8802
  author: "David Mashburn",
8757
8803
  license: "MIT",
8758
8804
  private: false,
@@ -8977,6 +9023,7 @@ var require_package = __commonJS({
8977
9023
  "media/webview.css",
8978
9024
  "media/webview.js",
8979
9025
  "media/editor.worker.js",
9026
+ "media/diff.worker.js",
8980
9027
  "media/icon.png",
8981
9028
  "standalone/**",
8982
9029
  "web/**",
@@ -8995,7 +9042,8 @@ var require_package = __commonJS({
8995
9042
  main: "out/standalone-main.js"
8996
9043
  },
8997
9044
  asarUnpack: [
8998
- "media/editor.worker.js"
9045
+ "media/editor.worker.js",
9046
+ "media/diff.worker.js"
8999
9047
  ],
9000
9048
  mac: {
9001
9049
  target: [
@@ -21990,6 +22038,7 @@ var {
21990
22038
  var { generateCompletion, SUPPORTED_SHELLS } = require_completions();
21991
22039
  var { tokenMatches, tokensFor } = require_commandSpec();
21992
22040
  var { startPresentation } = require_present();
22041
+ var { resolveWorkingDirectory } = require_workingDirectory();
21993
22042
  var { getCliArgsFromArgv, getForwardedLaunchArgs } = require_launchArgs();
21994
22043
  var APP_NAME = "Bygone";
21995
22044
  var APP_VERSION = require_package().version;
@@ -22477,6 +22526,21 @@ ${HELP_URL}`,
22477
22526
  { role: "pasteAndMatchStyle" },
22478
22527
  { role: "delete" },
22479
22528
  { role: "selectAll" },
22529
+ {
22530
+ label: "Selection",
22531
+ enabled: canFind,
22532
+ submenu: [
22533
+ editorActionItem("Add Cursor Above", "editor.action.insertCursorAbove"),
22534
+ editorActionItem("Add Cursor Below", "editor.action.insertCursorBelow"),
22535
+ { type: "separator" },
22536
+ editorActionItem("Add Next Occurrence", "editor.action.addSelectionToNextFindMatch"),
22537
+ editorActionItem("Add Previous Occurrence", "editor.action.addSelectionToPreviousFindMatch"),
22538
+ editorActionItem("Select All Occurrences", "editor.action.selectHighlights"),
22539
+ { type: "separator" },
22540
+ editorActionItem("Expand Selection", "editor.action.smartSelect.expand"),
22541
+ editorActionItem("Shrink Selection", "editor.action.smartSelect.shrink")
22542
+ ]
22543
+ },
22480
22544
  { type: "separator" },
22481
22545
  {
22482
22546
  label: "Find",
@@ -22521,6 +22585,29 @@ ${HELP_URL}`,
22521
22585
  accelerator: "CmdOrCtrl+Alt+Enter",
22522
22586
  enabled: canReplace,
22523
22587
  click: () => postFindCommand("replaceAll")
22588
+ },
22589
+ { type: "separator" },
22590
+ {
22591
+ label: "Lines",
22592
+ enabled: canFind,
22593
+ submenu: [
22594
+ editorActionItem("Move Line Up", "editor.action.moveLinesUpAction"),
22595
+ editorActionItem("Move Line Down", "editor.action.moveLinesDownAction"),
22596
+ editorActionItem("Copy Line Up", "editor.action.copyLinesUpAction"),
22597
+ editorActionItem("Copy Line Down", "editor.action.copyLinesDownAction"),
22598
+ editorActionItem("Delete Line", "editor.action.deleteLines"),
22599
+ editorActionItem("Insert Line Above", "editor.action.insertLineBefore"),
22600
+ editorActionItem("Insert Line Below", "editor.action.insertLineAfter"),
22601
+ editorActionItem("Join Lines", "editor.action.joinLines"),
22602
+ editorActionItem("Transpose Characters", "editor.action.transpose"),
22603
+ { type: "separator" },
22604
+ editorActionItem("Indent Lines", "editor.action.indentLines"),
22605
+ editorActionItem("Outdent Lines", "editor.action.outdentLines"),
22606
+ editorActionItem("Reindent Lines", "editor.action.reindentlines"),
22607
+ { type: "separator" },
22608
+ editorActionItem("Toggle Line Comment", "editor.action.commentLine"),
22609
+ editorActionItem("Toggle Block Comment", "editor.action.blockComment")
22610
+ ]
22524
22611
  }
22525
22612
  ]
22526
22613
  },
@@ -22580,6 +22667,19 @@ ${HELP_URL}`,
22580
22667
  {
22581
22668
  label: "Navigate",
22582
22669
  submenu: [
22670
+ {
22671
+ label: "Next Change",
22672
+ accelerator: "F7",
22673
+ enabled: canFind,
22674
+ click: () => postToRenderer({ type: "navigateChange", direction: 1 })
22675
+ },
22676
+ {
22677
+ label: "Previous Change",
22678
+ accelerator: "Shift+F7",
22679
+ enabled: canFind,
22680
+ click: () => postToRenderer({ type: "navigateChange", direction: -1 })
22681
+ },
22682
+ { type: "separator" },
22583
22683
  {
22584
22684
  label: "Back to Directory",
22585
22685
  accelerator: "CmdOrCtrl+[",
@@ -22752,6 +22852,12 @@ function postFindCommand(command) {
22752
22852
  }
22753
22853
  postToRenderer({ type: "find", command });
22754
22854
  }
22855
+ function editorActionItem(label, actionId) {
22856
+ return {
22857
+ label,
22858
+ click: () => postToRenderer({ type: "editorAction", actionId })
22859
+ };
22860
+ }
22755
22861
  function postVisibleSearchCommand() {
22756
22862
  if (!getMenuCapabilities(session).canSearchComparison) return;
22757
22863
  postToRenderer({ type: "visibleSearch" });
@@ -23175,7 +23281,8 @@ function normalizeLaunchArgs(args) {
23175
23281
  cwd = path8.resolve(launchArgs[cwdIndex + 1]);
23176
23282
  launchArgs.splice(cwdIndex, 2);
23177
23283
  }
23178
- return { cwd, launchArgs };
23284
+ const resolved = resolveWorkingDirectory(launchArgs, cwd);
23285
+ return { cwd: resolved.cwd, launchArgs: resolved.args };
23179
23286
  }
23180
23287
  function resolveLaunchPath(candidate, cwd) {
23181
23288
  return path8.isAbsolute(candidate) ? candidate : path8.resolve(cwd, candidate);
@@ -24048,6 +24155,7 @@ async function sendCurrentDirectoryHistoryEntry() {
24048
24155
  return {
24049
24156
  id: `dir-hist-col-${colIdx}`,
24050
24157
  label: `${displayedLabels2[colIdx]} / ${relativePath}${exists ? "" : " (missing)"}`,
24158
+ path: relativePath,
24051
24159
  content,
24052
24160
  editable: false,
24053
24161
  dirty: false,
@@ -25235,6 +25343,7 @@ async function sendCurrentMultiDiff() {
25235
25343
  return {
25236
25344
  id: file.id,
25237
25345
  label: file.label,
25346
+ path: file.path || file.label,
25238
25347
  content: file.content,
25239
25348
  editable: file.editable !== false,
25240
25349
  dirty: Boolean(file.dirty),
@@ -25391,6 +25500,10 @@ async function sendCurrentDiff() {
25391
25500
  comparisonId: `${session.left.path}\0${session.right.path}`,
25392
25501
  leftContent: session.left.content,
25393
25502
  rightContent: session.right.content,
25503
+ sourceInfo: {
25504
+ leftPath: session.left.path || session.left.label,
25505
+ rightPath: session.right.path || session.right.label
25506
+ },
25394
25507
  diffModel,
25395
25508
  history: null,
25396
25509
  fileNavigation: buildStandaloneFileNavigationState(),
@@ -25471,6 +25584,10 @@ async function sendCurrentHistoryEntry() {
25471
25584
  comparisonId: `${session.history.filePath}\0${entry.commit}`,
25472
25585
  leftContent: entry.leftContent,
25473
25586
  rightContent: entry.rightContent,
25587
+ sourceInfo: {
25588
+ leftPath: session.history.filePath,
25589
+ rightPath: session.history.filePath
25590
+ },
25474
25591
  diffModel,
25475
25592
  editableSides: buildHistoryEditableSides(entry),
25476
25593
  history: {
@@ -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,6 +1,6 @@
1
1
  {
2
2
  "name": "@davmash/bygone",
3
- "version": "0.8.0",
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",
@@ -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"