gutterpress 0.11.23-alpha.5 → 0.11.23-alpha.6

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.
Files changed (40) hide show
  1. package/README.md +1 -1
  2. package/dist/api/index.d.ts +4 -2
  3. package/dist/api/index.js +14 -6
  4. package/dist/{build-4qv9wvrx.js → build-py643c5a.js} +7 -7
  5. package/dist/{cli-pth362d8.js → cli-09jj8w5g.js} +18 -16
  6. package/dist/{cli-a35w7wzg.js → cli-31anr0r9.js} +107 -56
  7. package/dist/{cli-w97xcpag.js → cli-55br530w.js} +4 -4
  8. package/dist/{cli-nk0efg2x.js → cli-bnf7eb38.js} +1 -1
  9. package/dist/{cli-yxfznmsq.js → cli-qzkq9em8.js} +1 -1
  10. package/dist/{cli-2t3krcfy.js → cli-tf9tw6at.js} +1 -1
  11. package/dist/{cli-de8ydmm7.js → cli-x777v272.js} +3 -3
  12. package/dist/cli.js +12 -12
  13. package/dist/{doctor-5nh3t346.js → doctor-tyrzqphh.js} +3 -3
  14. package/dist/{ext-nhcep6h6.js → ext-70kt3eft.js} +7 -7
  15. package/dist/{extension-restore-x3mtn844.js → extension-restore-fjfn1hrk.js} +4 -4
  16. package/dist/{extension-restore-55kp0ksq.js → extension-restore-whag4sm0.js} +2 -2
  17. package/dist/{index-9ye22m7r.js → index-1zqkfzcd.js} +3 -3
  18. package/dist/{index-t3jkavdz.js → index-cmakyf43.js} +3 -3
  19. package/dist/{index-h6yk5tjx.js → index-cw03e9p4.js} +107 -56
  20. package/dist/{index-agrkfbkv.js → index-ejbfetdn.js} +241 -69
  21. package/dist/index.js +14 -6
  22. package/dist/lib/remote-auth/repair.d.ts +2 -2
  23. package/dist/lib/remote-auth/revisions.d.ts +60 -0
  24. package/dist/lib/remote-auth/scorched-earth.d.ts +2 -2
  25. package/dist/lib/remote-auth/sync-messages.d.ts +28 -27
  26. package/dist/lib/remote-auth/sync-types.d.ts +3 -0
  27. package/dist/lib/remote-auth/sync.d.ts +7 -8
  28. package/dist/lib/remote-auth/transport.d.ts +8 -1
  29. package/dist/lib/source-provider.d.ts +80 -35
  30. package/dist/{new-5a4w2vkh.js → new-b27kyr02.js} +10 -10
  31. package/dist/{plugins-mm8270tn.js → plugins-racab3cj.js} +1 -1
  32. package/dist/{plugins-cfzf26b8.js → plugins-vpx7c53c.js} +3 -3
  33. package/dist/{preflight-jma71n0j.js → preflight-akdqz9v8.js} +7 -7
  34. package/dist/{preview-kmx4h7gv.js → preview-bck9f88w.js} +7 -7
  35. package/dist/{publish-62843020.js → publish-keyp8rh4.js} +7 -7
  36. package/dist/render.js +2 -2
  37. package/dist/{source-provider-knmcam50.js → source-provider-n7vehh6t.js} +15 -3
  38. package/dist/{source-provider-98k5deda.js → source-provider-tgzet3j5.js} +15 -3
  39. package/dist/{validate-vvmrd85g.js → validate-z28cvr5x.js} +7 -7
  40. package/package.json +1 -1
package/README.md CHANGED
@@ -162,7 +162,7 @@ gutterpress new <name> [--kind <id>] [options]
162
162
  --targets <ids> Publish targets recorded in the manifest (comma-separated: dtrpg, itch; or "none") — default: the preset's
163
163
  --page-width <pt> Trim width in points, 72pt = 1in (required with --preset custom; optional override otherwise)
164
164
  --page-height <pt> Trim height in points, 72pt = 1in (required with --preset custom; optional override otherwise)
165
- --git Initialise local version history (default: true; use --no-git to skip)
165
+ --git Keep version history on this computer (default: true; use --no-git to skip)
166
166
  --no-git
167
167
  ```
168
168
 
@@ -53,8 +53,8 @@ export { readManifestFields, setManifestFields, setActiveStyles, } from "../lib/
53
53
  export type { ProjectConfigFields } from "../lib/manifest-config.ts";
54
54
  export { readPageSetup, setPageSetup } from "../lib/page-size.ts";
55
55
  export type { PageMargin, PageSetup, PageSetupChange, PageSizeChoice, PageSizePoints } from "../lib/page-size.ts";
56
- export { providerFor, restoreVersionWithBackup, isNoChangesError, countUnversionedChanges, whenGitIdle, AUTO_SNAPSHOT_MESSAGE, RESTORE_BACKUP_MESSAGE, HISTORY_PAGE_LIMIT, listLocalBranches, switchBranch, SWITCH_BRANCH_SNAPSHOT_MESSAGE, } from "../lib/source-provider.ts";
57
- export type { ListHistoryOptions, HistoryPage, UnversionedChanges, LocalBranches, SwitchBranchOptions, SwitchBranchResult, } from "../lib/source-provider.ts";
56
+ export { providerFor, restoreVersionWithBackup, isNoChangesError, countUnversionedChanges, whenGitIdle, AUTO_SNAPSHOT_MESSAGE, RESTORE_BACKUP_MESSAGE, HISTORY_PAGE_LIMIT, listRevisions, createRevision, revisionNameFrom, switchBranch, SWITCH_BRANCH_SNAPSHOT_MESSAGE, } from "../lib/source-provider.ts";
57
+ export type { ListHistoryOptions, HistoryPage, UnversionedChanges, Revision, RevisionList, CreateRevisionOptions, SwitchBranchOptions, SwitchBranchResult, } from "../lib/source-provider.ts";
58
58
  export { describeVersions, listOnlineVersions, compareVersionFile, exportVersionTree, VERSION_CHANGES_SHOWN, } from "../lib/version-changes.ts";
59
59
  export type { VersionEntry, VersionFileChange, CompareRow } from "../lib/version-changes.ts";
60
60
  export { autoSnapshotDelayMs, autoSyncDelayMs, isGitInternalPath, AUTO_SNAPSHOT_DEFAULT_MINUTES, AUTO_SYNC_MIN_MINUTES, AUTO_SYNC_MAX_MINUTES, AUTO_SYNC_DEFAULT_MINUTES, AUTO_SYNC_PUSH_INTERVAL_MINUTES, } from "../lib/host-policy.ts";
@@ -80,6 +80,8 @@ export type { GenericTokenConnectInput, GenericAuthOptions, } from "../lib/remot
80
80
  export { diagnoseProjectRemote, parseRemoteOrigin, forgeKindForHost, } from "../lib/remote-auth/diagnose.ts";
81
81
  export type { ProjectRemoteDiagnosis, DiagnoseProjectRemoteOptions, RemoteProtocol, RemoteGuidanceId, ForgeKind, } from "../lib/remote-auth/diagnose.ts";
82
82
  export { syncProject, refreshRemoteCopies, checkRemoteUpdates, SYNC_SNAPSHOT_MESSAGE, } from "../lib/remote-auth/sync.ts";
83
+ export { renameRevision, deleteRevision } from "../lib/remote-auth/revisions.ts";
84
+ export type { RenameRevisionOptions, DeleteRevisionOptions } from "../lib/remote-auth/revisions.ts";
83
85
  export { repairOnlineBackup, REPAIR_SNAPSHOT_MESSAGE, type RepairOnlineBackupOptions, type RepairOnlineBackupResult, } from "../lib/remote-auth/repair.ts";
84
86
  export { scorchedEarth, type ScorchedEarthOptions, type ScorchedEarthResult, } from "../lib/remote-auth/scorched-earth.ts";
85
87
  export type { SyncOutcome, SyncProjectOptions, KeptBothFile, } from "../lib/remote-auth/sync.ts";
package/dist/api/index.js CHANGED
@@ -30,6 +30,7 @@ import {
30
30
  connectGoogleDrive,
31
31
  connectPublishProvider,
32
32
  defaultConfigDir,
33
+ deleteRevision,
33
34
  deleteSnippet,
34
35
  describeVersions,
35
36
  diagnoseProjectRemote,
@@ -70,6 +71,7 @@ import {
70
71
  readPageSetup,
71
72
  readPublishSettings,
72
73
  refreshRemoteCopies,
74
+ renameRevision,
73
75
  repairOnlineBackup,
74
76
  requireGoogleClientCredentials,
75
77
  resolveActiveStyles,
@@ -102,7 +104,7 @@ import {
102
104
  substituteVariables,
103
105
  syncProject,
104
106
  testRemoteAccess
105
- } from "../index-agrkfbkv.js";
107
+ } from "../index-ejbfetdn.js";
106
108
  import {
107
109
  DEFAULT_NPM_REGISTRY,
108
110
  MANIFEST_FILENAMES,
@@ -131,7 +133,7 @@ import {
131
133
  setExtensionEnabled,
132
134
  updateExtensions,
133
135
  validateProjectExtensions
134
- } from "../index-t3jkavdz.js";
136
+ } from "../index-cmakyf43.js";
135
137
  import {
136
138
  BUNDLED_EXTENSIONS,
137
139
  EXTENSION_MANIFEST_FILENAME,
@@ -146,7 +148,7 @@ import {
146
148
  pathEscapesFolder,
147
149
  readExtensionMeta,
148
150
  resolveExtension
149
- } from "../index-9ye22m7r.js";
151
+ } from "../index-1zqkfzcd.js";
150
152
  import"../index-ht1bcqdd.js";
151
153
  import"../index-2vxzxyyj.js";
152
154
  import {
@@ -164,14 +166,16 @@ import {
164
166
  RESTORE_BACKUP_MESSAGE,
165
167
  SWITCH_BRANCH_SNAPSHOT_MESSAGE,
166
168
  countUnversionedChanges,
169
+ createRevision,
167
170
  isNoChangesError,
168
- listLocalBranches,
171
+ listRevisions,
169
172
  providerFor,
170
173
  resolveLogger,
171
174
  restoreVersionWithBackup,
175
+ revisionNameFrom,
172
176
  switchBranch,
173
177
  whenGitIdle
174
- } from "../index-h6yk5tjx.js";
178
+ } from "../index-cw03e9p4.js";
175
179
  import {
176
180
  EXTENSIONS_DIR
177
181
  } from "../index-5x42amh8.js";
@@ -212,6 +216,7 @@ export {
212
216
  runPublish,
213
217
  runBuild,
214
218
  revokeGoogleCredential,
219
+ revisionNameFrom,
215
220
  restoreVersionWithBackup,
216
221
  restorePinnedExtensions,
217
222
  restoreFailureMessage,
@@ -231,6 +236,7 @@ export {
231
236
  repoRootForSource,
232
237
  repairOnlineBackup,
233
238
  reorderExtensions,
239
+ renameRevision,
234
240
  removeExtension,
235
241
  refreshRemoteCopies,
236
242
  readyProbeExpr,
@@ -251,6 +257,7 @@ export {
251
257
  npmRegistryUrl,
252
258
  loadManifestWithPath,
253
259
  listSnippets,
260
+ listRevisions,
254
261
  listRepoBooks,
255
262
  listPublishProviders,
256
263
  listPublishAccounts,
@@ -261,7 +268,6 @@ export {
261
268
  listMergedSnippets,
262
269
  listMarkerComponents,
263
270
  listLocationVariants,
264
- listLocalBranches,
265
271
  listGitHubRepositories,
266
272
  listGitHubBranches,
267
273
  listCustomTemplates,
@@ -296,7 +302,9 @@ export {
296
302
  describeVersions,
297
303
  describeExtension,
298
304
  deleteSnippet,
305
+ deleteRevision,
299
306
  defaultConfigDir,
307
+ createRevision,
300
308
  countUnversionedChanges,
301
309
  connectPublishProvider,
302
310
  connectGoogleDrive,
@@ -1,20 +1,20 @@
1
1
  import {
2
2
  runBuild,
3
3
  splitOutPath
4
- } from "./cli-pth362d8.js";
5
- import"./cli-nk0efg2x.js";
4
+ } from "./cli-09jj8w5g.js";
5
+ import"./cli-bnf7eb38.js";
6
6
  import"./cli-ht1bcqdd.js";
7
7
  import"./cli-58fsk6d7.js";
8
8
  import"./cli-5crpmz42.js";
9
9
  import"./cli-eyyggect.js";
10
10
  import"./cli-asap4t1z.js";
11
- import"./cli-a35w7wzg.js";
11
+ import"./cli-31anr0r9.js";
12
12
  import"./cli-v5mp7a6q.js";
13
- import"./cli-w97xcpag.js";
14
- import"./cli-de8ydmm7.js";
13
+ import"./cli-55br530w.js";
14
+ import"./cli-x777v272.js";
15
15
  import {
16
16
  log
17
- } from "./cli-2t3krcfy.js";
17
+ } from "./cli-tf9tw6at.js";
18
18
  import {
19
19
  UsageError,
20
20
  parseFormat,
@@ -22,7 +22,7 @@ import {
22
22
  rejectExtraPositionals,
23
23
  rejectUnknownFlags
24
24
  } from "./cli-d8xjns66.js";
25
- import"./cli-yxfznmsq.js";
25
+ import"./cli-qzkq9em8.js";
26
26
  import {
27
27
  BuildError
28
28
  } from "./cli-46ycxe6r.js";
@@ -8,7 +8,7 @@ import {
8
8
  stampCreator,
9
9
  stripAnnotations,
10
10
  transparentPages
11
- } from "./cli-nk0efg2x.js";
11
+ } from "./cli-bnf7eb38.js";
12
12
  import {
13
13
  blackTextToGray
14
14
  } from "./cli-ht1bcqdd.js";
@@ -42,7 +42,7 @@ import {
42
42
  import {
43
43
  hasUncommittedChanges,
44
44
  listWorkdirChanges
45
- } from "./cli-a35w7wzg.js";
45
+ } from "./cli-31anr0r9.js";
46
46
  import {
47
47
  detectProjectSource,
48
48
  repoSubPath
@@ -75,7 +75,7 @@ import {
75
75
  uniqueExtensionId,
76
76
  withFetchTimeout,
77
77
  writeManifestDoc
78
- } from "./cli-w97xcpag.js";
78
+ } from "./cli-55br530w.js";
79
79
  import {
80
80
  EXTENSION_MANIFEST_FILENAME,
81
81
  GUTTERPRESS_CSS,
@@ -96,7 +96,7 @@ import {
96
96
  readExtensionMeta,
97
97
  resolveDeclaredStyles,
98
98
  slugify
99
- } from "./cli-de8ydmm7.js";
99
+ } from "./cli-x777v272.js";
100
100
  import {
101
101
  PACKAGE_META,
102
102
  PACKAGE_VERSION,
@@ -106,7 +106,7 @@ import {
106
106
  log,
107
107
  setLogLevel,
108
108
  warn
109
- } from "./cli-2t3krcfy.js";
109
+ } from "./cli-tf9tw6at.js";
110
110
  import {
111
111
  DEBOUNCE,
112
112
  UsageError,
@@ -3024,8 +3024,8 @@ function withoutOnlineTag(relPath) {
3024
3024
  }
3025
3025
  var check27 = {
3026
3026
  id: "source.sync.merge-markers",
3027
- name: "Combined Versions",
3028
- description: "Finds passages and files still holding two versions (yours and the online version) after a sync",
3027
+ name: "Combined Takes",
3028
+ description: "Finds passages and files still holding two takes (yours and the online copy's) after getting the latest changes",
3029
3029
  category: "source",
3030
3030
  phase: "pre-build",
3031
3031
  async run(ctx) {
@@ -3051,7 +3051,7 @@ var check27 = {
3051
3051
  results.push(finding(check27.id, {
3052
3052
  severity: "error",
3053
3053
  code: "two-versions-passage",
3054
- message: "This passage has two versions — yours and the online version. Choose one in the editor's Two versions panel, or keep the text you want and delete the marker lines.",
3054
+ message: "This passage has two takes — yours and the online copy's. Choose one in the editor's Two takes panel, or keep the text you want and delete the marker lines.",
3055
3055
  file,
3056
3056
  line: i + 1
3057
3057
  }));
@@ -3060,7 +3060,7 @@ var check27 = {
3060
3060
  results.push(finding(check27.id, {
3061
3061
  severity: "error",
3062
3062
  code: "leftover-version-marker",
3063
- message: "This marker line is left over from combining two versions — delete it.",
3063
+ message: "This marker line is left over from combining two takes — delete it.",
3064
3064
  file,
3065
3065
  line: i + 1
3066
3066
  }));
@@ -3081,7 +3081,7 @@ var check27 = {
3081
3081
  results.push(finding(check27.id, {
3082
3082
  severity: "warning",
3083
3083
  code: "kept-both-versions",
3084
- message: `Two versions of ${withoutOnlineTag(rel)} are in your book — keep the one you want, then delete the other.`,
3084
+ message: `Two takes of ${withoutOnlineTag(rel)} are in your book — keep the one you want, then delete the other.`,
3085
3085
  file: sibling
3086
3086
  }));
3087
3087
  }
@@ -6524,7 +6524,7 @@ async function scaffoldProject(options) {
6524
6524
  let versionHistoryError;
6525
6525
  if (requested === "local-git") {
6526
6526
  try {
6527
- const { providerFor } = await import("./source-provider-knmcam50.js");
6527
+ const { providerFor } = await import("./source-provider-n7vehh6t.js");
6528
6528
  const provider = providerFor({ type: "local-folder", path: projectDir });
6529
6529
  await provider.initVersionHistory({
6530
6530
  projectDir,
@@ -6536,7 +6536,7 @@ async function scaffoldProject(options) {
6536
6536
  versionHistory = "none";
6537
6537
  const { findEnclosingRepoDir } = await import("./project-source-ekcyp63q.js");
6538
6538
  const enclosingRepoDir = await findEnclosingRepoDir(projectDir);
6539
- versionHistoryError = enclosingRepoDir ? `This book was added to ${path12.basename(enclosingRepoDir)}'s shared version history; save a snapshot to record it.` : e instanceof Error ? e.message : String(e);
6539
+ versionHistoryError = enclosingRepoDir ? `This book was added to ${path12.basename(enclosingRepoDir)}'s shared version history; save a version to record it.` : e instanceof Error ? e.message : String(e);
6540
6540
  }
6541
6541
  }
6542
6542
  const result = {
@@ -8878,7 +8878,7 @@ async function resolvePublishProvider(id, book) {
8878
8878
  const ext = await bookExtensions(book);
8879
8879
  const npmEntry = ext.extensions.some((c) => !c.path && c.name === id);
8880
8880
  if (npmEntry) {
8881
- const { restoreForCommand: restoreForCommand2 } = await import("./extension-restore-x3mtn844.js");
8881
+ const { restoreForCommand: restoreForCommand2 } = await import("./extension-restore-fjfn1hrk.js");
8882
8882
  await restoreForCommand2(book.projectDir, { manifestPath: book.manifestPath, failFast: true });
8883
8883
  }
8884
8884
  const publishers = await discover(ext);
@@ -8916,7 +8916,7 @@ function infoFor(p) {
8916
8916
  }
8917
8917
  function pluginProvider(p) {
8918
8918
  let loading;
8919
- const load = () => loading ??= import("./plugins-cfzf26b8.js").then((m) => m.loadPublishFunction(p));
8919
+ const load = () => loading ??= import("./plugins-vpx7c53c.js").then((m) => m.loadPublishFunction(p));
8920
8920
  return {
8921
8921
  info: infoFor(p),
8922
8922
  async authenticate() {
@@ -9321,10 +9321,12 @@ import git7 from "isomorphic-git";
9321
9321
  // src/lib/remote-auth/test-access.ts
9322
9322
  import git8 from "isomorphic-git";
9323
9323
  import httpNode2 from "isomorphic-git/http/node";
9324
- // src/lib/remote-auth/repair.ts
9324
+ // src/lib/remote-auth/revisions.ts
9325
9325
  import git9 from "isomorphic-git";
9326
- // src/lib/remote-auth/scorched-earth.ts
9326
+ // src/lib/remote-auth/repair.ts
9327
9327
  import git10 from "isomorphic-git";
9328
+ // src/lib/remote-auth/scorched-earth.ts
9329
+ import git11 from "isomorphic-git";
9328
9330
  // src/lib/publish/selections.ts
9329
9331
  import { chmod as chmod2, mkdir as mkdir10, readFile as readFile26, writeFile as writeFile11 } from "node:fs/promises";
9330
9332
  import path21 from "node:path";
@@ -1,7 +1,8 @@
1
1
  import {
2
2
  capabilitiesFor,
3
3
  detectProjectSource,
4
- findEnclosingRepoDir
4
+ findEnclosingRepoDir,
5
+ syncRemoteFor
5
6
  } from "./cli-v5mp7a6q.js";
6
7
  import {
7
8
  EXTENSIONS_DIR,
@@ -163,6 +164,7 @@ function gitScopeFor(source) {
163
164
  return source.repoRoot || source.path;
164
165
  }
165
166
  var HISTORY_PAGE_LIMIT = 100;
167
+ var NO_VERSION_HISTORY = "This book isn't keeping version history yet. Turn on version history first.";
166
168
  var DEFAULT_AUTHOR = "gutterpress";
167
169
  var DEFAULT_EMAIL = "noreply@gutterpress.local";
168
170
  var DEFAULT_BRANCH = "main";
@@ -334,7 +336,7 @@ class LocalFolderSourceProvider {
334
336
  async initVersionHistory(options) {
335
337
  const dir = options.projectDir;
336
338
  if (await findEnclosingRepoDir(dir) !== undefined) {
337
- throw new Error("This folder is already inside a versioned book, so gutterpress " + "won't create a separate history here.");
339
+ throw new Error("This folder is already inside a book that keeps version history, so " + "Gutterpress won't start a separate one here.");
338
340
  }
339
341
  return withRepoLock(dir, async () => {
340
342
  const cache = {};
@@ -358,7 +360,7 @@ class LocalFolderSourceProvider {
358
360
  });
359
361
  }
360
362
  snapshot() {
361
- return Promise.reject(new Error("This book has no version history yet. Enable version history first."));
363
+ return Promise.reject(new Error(NO_VERSION_HISTORY));
362
364
  }
363
365
  listHistory() {
364
366
  return Promise.resolve([]);
@@ -367,7 +369,7 @@ class LocalFolderSourceProvider {
367
369
  return Promise.resolve({ entries: [], hasMore: false });
368
370
  }
369
371
  restore() {
370
- return Promise.reject(new Error("This book has no version history yet. Enable version history first."));
372
+ return Promise.reject(new Error(NO_VERSION_HISTORY));
371
373
  }
372
374
  }
373
375
 
@@ -466,7 +468,7 @@ async function snapshotWorkingTreeUnlocked(options) {
466
468
  const workdirClean = changes.adds.length === 0 && changes.removes.length === 0;
467
469
  if (workdirClean && !staleStaging) {
468
470
  logger.debug("snapshot", "no changes — skipping");
469
- throw new Error("No changes since the last snapshot — there is nothing new to save.");
471
+ throw new Error("Nothing new to save — your last version already has everything.");
470
472
  }
471
473
  if (workdirClean && staleStaging && await stageMatchesHead(dir, cache)) {
472
474
  logger.debug("snapshot", "stale marker outlived a completed commit — clearing, not recommitting");
@@ -504,7 +506,7 @@ async function snapshotWorkingTreeUnlocked(options) {
504
506
  };
505
507
  }
506
508
  function isNoChangesError(e) {
507
- return e instanceof Error && /no changes since the last snapshot/i.test(e.message);
509
+ return e instanceof Error && /nothing new to save/i.test(e.message);
508
510
  }
509
511
  async function countUnversionedChanges(projectDir) {
510
512
  const source = await detectProjectSource(projectDir);
@@ -535,14 +537,13 @@ function gitDirFor(projectDir) {
535
537
  function snapshotStagingMarkerPath(projectDir) {
536
538
  return path2.join(gitDirFor(projectDir), SNAPSHOT_STAGING_MARKER);
537
539
  }
538
- var RESTORE_BACKUP_MESSAGE = "Automatic backup before restoring an earlier version";
539
- var AUTO_SNAPSHOT_MESSAGE = "Automatic snapshot";
540
+ var RESTORE_BACKUP_MESSAGE = "Automatic version before restoring";
541
+ var AUTO_SNAPSHOT_MESSAGE = "Automatic version";
540
542
  async function restoreVersionWithBackup(options) {
541
543
  const { projectDir, id, authorName, authorEmail } = options;
542
544
  const source = await detectProjectSource(projectDir);
543
- if (source.type !== "local-git-folder") {
544
- throw new Error("This book has no version history yet. Enable version history first.");
545
- }
545
+ if (source.type !== "local-git-folder")
546
+ throw new Error(NO_VERSION_HISTORY);
546
547
  const provider = new LocalGitSourceProvider(source);
547
548
  const repoDir = gitScopeFor(source);
548
549
  return withRepoLock(repoDir, async () => {
@@ -559,42 +560,105 @@ async function restoreVersionWithBackup(options) {
559
560
  try {
560
561
  await provider.restoreUnlocked({ projectDir, id });
561
562
  } catch (cause) {
562
- throw new Error(backupId ? "The restore could not be completed, but your work is safe — it was " + `automatically saved as a backup snapshot (${backupId.slice(0, 7)}) ` + "and appears in your version history." : "The restore could not be completed. Your book files were not changed.", { cause });
563
+ throw new Error(backupId ? "Going back to that version didn't finish, but your work is safe — it was " + "saved as an automatic version and appears in your version history." : "Going back to that version didn't finish. Your book files were not changed.", { cause });
563
564
  }
564
565
  return { restoredId: id, backupId };
565
566
  });
566
567
  }
567
- var SWITCH_BRANCH_SNAPSHOT_MESSAGE = "Saved before switching copy";
568
- async function listLocalBranches(dir) {
569
- const source = await detectProjectSource(dir);
570
- if (source.type !== "local-git-folder")
571
- return null;
572
- const repoDir = gitScopeFor(source);
573
- const [local, current, remotes] = await Promise.all([
574
- git.listBranches({ fs: gitFs, dir: repoDir }),
575
- git.currentBranch({ fs: gitFs, dir: repoDir, fullname: false }).catch(() => {
568
+ var SWITCH_BRANCH_SNAPSHOT_MESSAGE = "Saved before switching revision";
569
+ async function readRevisionRefs(dir) {
570
+ const [names, current, remote] = await Promise.all([
571
+ git.listBranches({ fs: gitFs, dir }),
572
+ git.currentBranch({ fs: gitFs, dir, fullname: false }).catch(() => {
576
573
  return;
577
574
  }),
578
- git.listRemotes({ fs: gitFs, dir: repoDir }).catch(() => [])
575
+ syncRemoteFor(dir)
579
576
  ]);
580
- const localNames = new Set(local);
581
- const remoteOnly = new Set;
582
- for (const { remote } of remotes) {
583
- const names = await git.listBranches({ fs: gitFs, dir: repoDir, remote }).catch(() => []);
584
- for (const name of names) {
585
- if (name === "HEAD")
586
- continue;
587
- if (!localNames.has(name))
588
- remoteOnly.add(name);
589
- }
590
- }
577
+ const tips = async (branches, prefix) => new Map(await Promise.all(branches.map(async (name) => [name, await git.resolveRef({ fs: gitFs, dir, ref: `${prefix}${name}` })])));
578
+ const onlineNames = remote ? (await git.listBranches({ fs: gitFs, dir, remote: remote.remote }).catch(() => [])).filter((name) => name !== "HEAD") : [];
591
579
  return {
592
580
  current: current ?? null,
593
- branches: [...localNames, ...remoteOnly].sort(),
594
- remoteOnly: [...remoteOnly].sort()
581
+ local: await tips(names, "refs/heads/"),
582
+ online: await tips(onlineNames, `refs/remotes/${remote?.remote}/`)
595
583
  };
596
584
  }
597
- async function resolveCopy(repoDir, branch) {
585
+ var ANCESTRY_DEPTH = 1000;
586
+ async function isContained(dir, tip, inTip, cache) {
587
+ if (tip === inTip)
588
+ return true;
589
+ return git.isDescendent({ fs: gitFs, dir, cache, oid: inTip, ancestor: tip, depth: ANCESTRY_DEPTH }).catch(() => false);
590
+ }
591
+ async function listRevisions(dir) {
592
+ const source = await detectProjectSource(dir);
593
+ if (source.type !== "local-git-folder")
594
+ return null;
595
+ const repoDir = gitScopeFor(source);
596
+ const { current, local, online } = await readRevisionRefs(repoDir);
597
+ const cache = {};
598
+ const names = [...new Set([...local.keys(), ...online.keys()])].sort((a, b) => a.localeCompare(b));
599
+ const revisions = await Promise.all(names.map(async (name) => {
600
+ const here = local.get(name);
601
+ const there = online.get(name);
602
+ return {
603
+ name,
604
+ current: name === current,
605
+ where: here && there ? "online" : here ? "this-computer" : "online-only",
606
+ notBackedUp: Boolean(here && there && !await isContained(repoDir, here, there, cache))
607
+ };
608
+ }));
609
+ return { current, revisions };
610
+ }
611
+ function revisionNameFrom(input) {
612
+ return input.trim().replace(/\s+/g, "-");
613
+ }
614
+ var UNUSABLE_REVISION_NAME = /[\u0000- \u007f~^:?*[\\/<>"|]|\.\.|@\{|^[-.]|\.$|\.lock$|^@$/;
615
+ var REVISION_NAME_MAX = 100;
616
+ async function assertFreeRevisionName(repoDir, name) {
617
+ if (!name)
618
+ throw new Error("Give the revision a name.");
619
+ if (name.length > REVISION_NAME_MAX || UNUSABLE_REVISION_NAME.test(name)) {
620
+ throw new Error(`"${name}" can't be a revision name. Use plain words, numbers and dashes, up to ${REVISION_NAME_MAX} characters.`);
621
+ }
622
+ const { local, online } = await readRevisionRefs(repoDir);
623
+ const taken = (names) => [...names].find((n) => n.toLowerCase() === name.toLowerCase());
624
+ const here = taken(local.keys());
625
+ if (here)
626
+ throw new Error(`There's already a revision called "${here}". Pick a different name.`);
627
+ const there = taken(online.keys());
628
+ if (there) {
629
+ throw new Error(`"${there}" is already a revision in the online copy. Switch to it, or pick a different name.`);
630
+ }
631
+ }
632
+ async function saveUnsavedWork(options, cache) {
633
+ try {
634
+ await snapshotWorkingTreeUnlocked({
635
+ projectDir: options.projectDir,
636
+ repoRoot: options.repoDir,
637
+ message: SWITCH_BRANCH_SNAPSHOT_MESSAGE,
638
+ authorName: options.authorName,
639
+ authorEmail: options.authorEmail,
640
+ cache
641
+ });
642
+ } catch (e) {
643
+ if (!isNoChangesError(e))
644
+ throw e;
645
+ }
646
+ }
647
+ async function createRevision(options) {
648
+ const { projectDir, authorName, authorEmail } = options;
649
+ const source = await detectProjectSource(projectDir);
650
+ if (source.type !== "local-git-folder")
651
+ throw new Error(NO_VERSION_HISTORY);
652
+ const repoDir = gitScopeFor(source);
653
+ const name = revisionNameFrom(options.name);
654
+ return withRepoLock(repoDir, async () => {
655
+ await assertFreeRevisionName(repoDir, name);
656
+ await saveUnsavedWork({ projectDir, repoDir, authorName, authorEmail }, {});
657
+ await git.branch({ fs: gitFs, dir: repoDir, ref: name, checkout: true });
658
+ return { current: name };
659
+ });
660
+ }
661
+ async function resolveRevision(repoDir, branch) {
598
662
  const local = await git.resolveRef({ fs: gitFs, dir: repoDir, ref: `refs/heads/${branch}` }).catch(() => {
599
663
  return;
600
664
  });
@@ -608,7 +672,7 @@ async function resolveCopy(repoDir, branch) {
608
672
  if (oid)
609
673
  return { oid, remote };
610
674
  }
611
- throw new Error(`Couldn't find a copy named "${branch}" — it may have been renamed or deleted.`);
675
+ throw new Error(`Couldn't find a revision named "${branch}" — it may have been renamed or deleted.`);
612
676
  }
613
677
  function isCheckoutConflictError(e) {
614
678
  return e?.code === "CheckoutConflictError";
@@ -645,29 +709,16 @@ async function diffCommitPaths(dir, fromOid, toOid, cache) {
645
709
  async function switchBranch(options) {
646
710
  const { projectDir, branch, authorName, authorEmail } = options;
647
711
  const source = await detectProjectSource(projectDir);
648
- if (source.type !== "local-git-folder") {
649
- throw new Error("This book has no version history yet. Enable version history first.");
650
- }
712
+ if (source.type !== "local-git-folder")
713
+ throw new Error(NO_VERSION_HISTORY);
651
714
  const repoDir = gitScopeFor(source);
652
715
  return withRepoLock(repoDir, async () => {
653
716
  const cache = {};
654
- try {
655
- await snapshotWorkingTreeUnlocked({
656
- projectDir,
657
- repoRoot: repoDir,
658
- message: SWITCH_BRANCH_SNAPSHOT_MESSAGE,
659
- authorName,
660
- authorEmail,
661
- cache
662
- });
663
- } catch (e) {
664
- if (!isNoChangesError(e))
665
- throw e;
666
- }
717
+ await saveUnsavedWork({ projectDir, repoDir, authorName, authorEmail }, cache);
667
718
  const fromOid = await git.resolveRef({ fs: gitFs, dir: repoDir, ref: "HEAD" }).catch(() => {
668
719
  return;
669
720
  });
670
- const { oid: toOid, remote } = await resolveCopy(repoDir, branch);
721
+ const { oid: toOid, remote } = await resolveRevision(repoDir, branch);
671
722
  try {
672
723
  await git.checkout({
673
724
  fs: gitFs,
@@ -679,7 +730,7 @@ async function switchBranch(options) {
679
730
  });
680
731
  } catch (e) {
681
732
  if (isCheckoutConflictError(e)) {
682
- throw new Error("Couldn't switch copies — some files changed on disk right as the switch " + "started. Try again.", { cause: e });
733
+ throw new Error("Couldn't switch revisions — some files changed on disk right as the switch " + "started. Try again.", { cause: e });
683
734
  }
684
735
  throw e;
685
736
  }
@@ -691,4 +742,4 @@ async function switchBranch(options) {
691
742
  });
692
743
  }
693
744
 
694
- export { gitScopeFor, HISTORY_PAGE_LIMIT, withRepoLock, whenGitIdle, __repoLockQueueSizeForTests, resolveGitAuthor, listWorkdirChanges, stageChanges, hasPendingChanges, hasUncommittedChanges, snapshotWorkingTreeUnlocked, isNoChangesError, countUnversionedChanges, providerFor, gitDirFor, snapshotStagingMarkerPath, RESTORE_BACKUP_MESSAGE, AUTO_SNAPSHOT_MESSAGE, restoreVersionWithBackup, SWITCH_BRANCH_SNAPSHOT_MESSAGE, listLocalBranches, switchBranch };
745
+ export { gitScopeFor, HISTORY_PAGE_LIMIT, NO_VERSION_HISTORY, withRepoLock, whenGitIdle, __repoLockQueueSizeForTests, resolveGitAuthor, listWorkdirChanges, stageChanges, hasPendingChanges, hasUncommittedChanges, snapshotWorkingTreeUnlocked, isNoChangesError, countUnversionedChanges, providerFor, gitDirFor, snapshotStagingMarkerPath, RESTORE_BACKUP_MESSAGE, AUTO_SNAPSHOT_MESSAGE, restoreVersionWithBackup, SWITCH_BRANCH_SNAPSHOT_MESSAGE, readRevisionRefs, isContained, listRevisions, revisionNameFrom, assertFreeRevisionName, createRevision, switchBranch };
@@ -11,10 +11,10 @@ import {
11
11
  prettify,
12
12
  readExtensionMeta,
13
13
  slugify
14
- } from "./cli-de8ydmm7.js";
14
+ } from "./cli-x777v272.js";
15
15
  import {
16
16
  log
17
- } from "./cli-2t3krcfy.js";
17
+ } from "./cli-tf9tw6at.js";
18
18
  import {
19
19
  UsageError
20
20
  } from "./cli-d8xjns66.js";
@@ -562,7 +562,7 @@ async function loadManifestWithPath(pathOrDir, opts) {
562
562
  if (existsSync(p) && statSync(p).isFile()) {
563
563
  const raw = await readFile(p, "utf8");
564
564
  if (raw.split(/\r?\n/).includes(TWO_VERSIONS_OPEN)) {
565
- throw new UsageError(`"${p}" has two versions of a setting — yours and the online version — left by a sync. Open it, keep the one you want and delete the marker lines.`);
565
+ throw new UsageError(`"${p}" has two takes of a setting — yours and the online copy's — left by getting the latest changes. Open it, keep the one you want and delete the marker lines.`);
566
566
  }
567
567
  try {
568
568
  const parsed = parseYaml(raw) ?? {};
@@ -1916,7 +1916,7 @@ async function vendorNpmExtension(projectDir, input, exportName, options, commit
1916
1916
  }
1917
1917
  const warnings = [...installed.warnings];
1918
1918
  await finalizeNpmPluginInstall(installed).catch((error) => {
1919
- warnings.push(`The extension was installed, but an old backup could not be removed: ` + `${error instanceof Error ? error.message : String(error)}`);
1919
+ warnings.push(`The extension was installed, but an old download could not be removed: ` + `${error instanceof Error ? error.message : String(error)}`);
1920
1920
  });
1921
1921
  warnings.push(...await retireLegacyCopies(projectDir, installed.name));
1922
1922
  try {
@@ -14,7 +14,7 @@ import {
14
14
  import {
15
15
  PACKAGE_VERSION,
16
16
  log
17
- } from "./cli-2t3krcfy.js";
17
+ } from "./cli-tf9tw6at.js";
18
18
  import {
19
19
  __require
20
20
  } from "./cli-37x76zdn.js";
@@ -1,7 +1,7 @@
1
1
  // package.json
2
2
  var package_default = {
3
3
  name: "gutterpress",
4
- version: "0.11.23-alpha.5",
4
+ version: "0.11.23-alpha.6",
5
5
  description: "Markdown-to-PDF converter for professional print layout using a native Chromium print engine and Ghostscript.",
6
6
  author: "itlackey",
7
7
  license: "MPL-2.0",
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  package_default
3
- } from "./cli-yxfznmsq.js";
3
+ } from "./cli-qzkq9em8.js";
4
4
 
5
5
  // src/utils/logger.ts
6
6
  var currentLevel = "INFO";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  PACKAGE_VERSION,
3
3
  debug
4
- } from "./cli-2t3krcfy.js";
4
+ } from "./cli-tf9tw6at.js";
5
5
  import {
6
6
  isExactNpmVersion,
7
7
  isValidNpmPackageName,
@@ -2691,8 +2691,8 @@ function twoVersions(state, startLine, endLine, silent) {
2691
2691
  open.attrSet("class", "gp-two-versions");
2692
2692
  open.map = [startLine, closer + 1];
2693
2693
  open.block = true;
2694
- pushVersion(state, "yours", "Your version", startLine + 1, separator);
2695
- pushVersion(state, "online", "Online version", separator + 1, closer);
2694
+ pushVersion(state, "yours", "Your take", startLine + 1, separator);
2695
+ pushVersion(state, "online", "Online take", separator + 1, closer);
2696
2696
  const close = state.push("two_versions_close", "div", -1);
2697
2697
  close.block = true;
2698
2698
  state.parentType = oldParent;