gutterpress 0.10.10-alpha.1 → 0.10.10-alpha.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.
@@ -70,7 +70,7 @@ export { connectGenericHost, knownForgeTokenUrl, } from "../lib/remote-auth/gene
70
70
  export type { GenericTokenConnectInput, GenericAuthOptions, } from "../lib/remote-auth/generic-auth.ts";
71
71
  export { diagnoseProjectRemote, parseRemoteOrigin, forgeKindForHost, } from "../lib/remote-auth/diagnose.ts";
72
72
  export type { ProjectRemoteDiagnosis, DiagnoseProjectRemoteOptions, RemoteProtocol, RemoteGuidanceId, ForgeKind, } from "../lib/remote-auth/diagnose.ts";
73
- export { syncProject, SYNC_SNAPSHOT_MESSAGE, } from "../lib/remote-auth/sync.ts";
73
+ export { syncProject, refreshRemoteCopies, SYNC_SNAPSHOT_MESSAGE, } from "../lib/remote-auth/sync.ts";
74
74
  export type { SyncOutcome, SyncProjectOptions, KeptBothFile, } from "../lib/remote-auth/sync.ts";
75
75
  export type { SnapshotEntry, InitVersionHistoryOptions, SnapshotOptions, RestoreSnapshotOptions, RestoreVersionOptions, RestoreVersionResult, SourceProvider, } from "../lib/source-provider.ts";
76
76
  export { runPublish, resolvePublishRequest, resolvePublishFormat, } from "../lib/publish/run-publish.ts";
package/dist/api/index.js CHANGED
@@ -90,6 +90,7 @@ import {
90
90
  readManifestFields,
91
91
  readPublishSettings,
92
92
  readSnippet,
93
+ refreshRemoteCopies,
93
94
  removeExtension,
94
95
  reorderExtensions,
95
96
  requireGoogleClientCredentials,
@@ -123,7 +124,7 @@ import {
123
124
  syncProject,
124
125
  testRemoteAccess,
125
126
  validateProjectExtensions
126
- } from "../index-d4wrww4b.js";
127
+ } from "../index-ryjmpyq6.js";
127
128
  import {
128
129
  BuildError,
129
130
  DEFAULT_PRINT_OPTS,
@@ -140,7 +141,7 @@ import {
140
141
  resolveLogger,
141
142
  restoreVersionWithBackup,
142
143
  switchBranch
143
- } from "../index-f833dtg9.js";
144
+ } from "../index-y01v2fe0.js";
144
145
  import {
145
146
  capabilitiesFor,
146
147
  detectProjectSource,
@@ -188,6 +189,7 @@ export {
188
189
  repoRootForSource,
189
190
  reorderExtensions,
190
191
  removeExtension,
192
+ refreshRemoteCopies,
191
193
  readyProbeExpr,
192
194
  readSnippet,
193
195
  readPublishSettings,
@@ -1,20 +1,20 @@
1
1
  import {
2
2
  executeAndReport
3
- } from "./cli-5fqr02je.js";
3
+ } from "./cli-x4krgssg.js";
4
4
  import {
5
5
  log
6
- } from "./cli-12epgrva.js";
6
+ } from "./cli-d7k5ykyx.js";
7
7
  import {
8
8
  UsageError,
9
9
  rejectExtraPositionals,
10
10
  rejectUnknownFlags
11
- } from "./cli-tvpq2ht9.js";
11
+ } from "./cli-1prnz7c8.js";
12
12
  import"./cli-k8f9eb12.js";
13
13
  import"./cli-c41yr7he.js";
14
14
  import {
15
15
  EXIT_CODES
16
16
  } from "./cli-46ycxe6r.js";
17
- import"./cli-vje8g3w8.js";
17
+ import"./cli-4mtf9ajw.js";
18
18
  import"./cli-v5mp7a6q.js";
19
19
  import"./cli-37x76zdn.js";
20
20
 
@@ -1,23 +1,23 @@
1
1
  import {
2
2
  runBuild,
3
3
  splitOutPath
4
- } from "./cli-5fqr02je.js";
4
+ } from "./cli-x4krgssg.js";
5
5
  import {
6
6
  log
7
- } from "./cli-12epgrva.js";
7
+ } from "./cli-d7k5ykyx.js";
8
8
  import {
9
9
  UsageError,
10
10
  parseFormat,
11
11
  parsePdfxFlavor,
12
12
  rejectExtraPositionals,
13
13
  rejectUnknownFlags
14
- } from "./cli-tvpq2ht9.js";
14
+ } from "./cli-1prnz7c8.js";
15
15
  import"./cli-k8f9eb12.js";
16
16
  import"./cli-c41yr7he.js";
17
17
  import {
18
18
  BuildError
19
19
  } from "./cli-46ycxe6r.js";
20
- import"./cli-vje8g3w8.js";
20
+ import"./cli-4mtf9ajw.js";
21
21
  import"./cli-v5mp7a6q.js";
22
22
  import"./cli-37x76zdn.js";
23
23
 
@@ -4,7 +4,7 @@ import {
4
4
  // package.json
5
5
  var package_default = {
6
6
  name: "gutterpress",
7
- version: "0.10.10-alpha.1",
7
+ version: "0.10.10-alpha.3",
8
8
  description: "Markdown-to-PDF converter for professional print layout using a native Chromium print engine and Ghostscript.",
9
9
  author: "itlackey",
10
10
  license: "MPL-2.0",
@@ -509,13 +509,45 @@ async function listLocalBranches(dir) {
509
509
  if (source.type !== "local-git-folder")
510
510
  return null;
511
511
  const repoDir = gitScopeFor(source);
512
- const [branches, current] = await Promise.all([
512
+ const [local, current, remotes] = await Promise.all([
513
513
  git.listBranches({ fs: gitFs, dir: repoDir }),
514
514
  git.currentBranch({ fs: gitFs, dir: repoDir, fullname: false }).catch(() => {
515
515
  return;
516
- })
516
+ }),
517
+ git.listRemotes({ fs: gitFs, dir: repoDir }).catch(() => [])
517
518
  ]);
518
- return { current: current ?? null, branches };
519
+ const localNames = new Set(local);
520
+ const remoteOnly = new Set;
521
+ for (const { remote } of remotes) {
522
+ const names = await git.listBranches({ fs: gitFs, dir: repoDir, remote }).catch(() => []);
523
+ for (const name of names) {
524
+ if (name === "HEAD")
525
+ continue;
526
+ if (!localNames.has(name))
527
+ remoteOnly.add(name);
528
+ }
529
+ }
530
+ return {
531
+ current: current ?? null,
532
+ branches: [...localNames, ...remoteOnly].sort(),
533
+ remoteOnly: [...remoteOnly].sort()
534
+ };
535
+ }
536
+ async function resolveCopy(repoDir, branch) {
537
+ const local = await git.resolveRef({ fs: gitFs, dir: repoDir, ref: `refs/heads/${branch}` }).catch(() => {
538
+ return;
539
+ });
540
+ if (local)
541
+ return { oid: local };
542
+ const remotes = await git.listRemotes({ fs: gitFs, dir: repoDir }).catch(() => []);
543
+ for (const { remote } of remotes) {
544
+ const oid = await git.resolveRef({ fs: gitFs, dir: repoDir, ref: `refs/remotes/${remote}/${branch}` }).catch(() => {
545
+ return;
546
+ });
547
+ if (oid)
548
+ return { oid, remote };
549
+ }
550
+ throw new Error(`Couldn't find a copy named "${branch}" — it may have been renamed or deleted.`);
519
551
  }
520
552
  function isCheckoutConflictError(e) {
521
553
  return e?.code === "CheckoutConflictError";
@@ -574,9 +606,16 @@ async function switchBranch(options) {
574
606
  const fromOid = await git.resolveRef({ fs: gitFs, dir: repoDir, ref: "HEAD" }).catch(() => {
575
607
  return;
576
608
  });
577
- const toOid = await git.resolveRef({ fs: gitFs, dir: repoDir, ref: branch });
609
+ const { oid: toOid, remote } = await resolveCopy(repoDir, branch);
578
610
  try {
579
- await git.checkout({ fs: gitFs, dir: repoDir, cache, ref: branch, force: false });
611
+ await git.checkout({
612
+ fs: gitFs,
613
+ dir: repoDir,
614
+ cache,
615
+ ref: branch,
616
+ force: false,
617
+ ...remote ? { remote } : {}
618
+ });
580
619
  } catch (e) {
581
620
  if (isCheckoutConflictError(e)) {
582
621
  throw new Error("Couldn't switch copies — some files changed on disk right as the switch " + "started. Try again.", { cause: e });
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  package_default
3
- } from "./cli-tvpq2ht9.js";
3
+ } from "./cli-1prnz7c8.js";
4
4
  import {
5
5
  execCapture,
6
6
  findTool,
@@ -13,12 +13,12 @@ import {
13
13
  stampCreator,
14
14
  stripAnnotations,
15
15
  warn
16
- } from "./cli-12epgrva.js";
16
+ } from "./cli-d7k5ykyx.js";
17
17
  import {
18
18
  DEBOUNCE,
19
19
  UsageError,
20
20
  resolvePort
21
- } from "./cli-tvpq2ht9.js";
21
+ } from "./cli-1prnz7c8.js";
22
22
  import {
23
23
  MARGIN_BOX_IGNORED_PROPERTIES,
24
24
  RENDER_TIMEOUT_MS,
@@ -42,7 +42,7 @@ import {
42
42
  } from "./cli-46ycxe6r.js";
43
43
  import {
44
44
  hasUncommittedChanges
45
- } from "./cli-vje8g3w8.js";
45
+ } from "./cli-4mtf9ajw.js";
46
46
  import {
47
47
  detectProjectSource
48
48
  } from "./cli-v5mp7a6q.js";
@@ -11421,7 +11421,7 @@ async function scaffoldProject(options) {
11421
11421
  let versionHistoryError;
11422
11422
  if (requested === "local-git") {
11423
11423
  try {
11424
- const { providerFor } = await import("./source-provider-2cnc5hry.js");
11424
+ const { providerFor } = await import("./source-provider-51g6mt6y.js");
11425
11425
  const provider = providerFor({ type: "local-folder", path: projectDir });
11426
11426
  await provider.initVersionHistory({
11427
11427
  projectDir,
package/dist/cli.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  UsageError,
7
7
  package_default,
8
8
  rejectUnknownFlags
9
- } from "./cli-tvpq2ht9.js";
9
+ } from "./cli-1prnz7c8.js";
10
10
  import {
11
11
  EXIT_CODES
12
12
  } from "./cli-46ycxe6r.js";
@@ -18,16 +18,16 @@ import {
18
18
  import { defineCommand, parseArgs, runMain } from "citty";
19
19
  import { statSync } from "node:fs";
20
20
  var SUBCOMMANDS = {
21
- new: () => import("./new-qws45t02.js").then((m) => m.default),
22
- preview: () => import("./preview-4c3tcsn4.js").then((m) => m.default),
23
- build: () => import("./build-bxavfz3j.js").then((m) => m.default),
24
- publish: () => import("./publish-m6bme9a8.js").then((m) => m.default),
25
- lint: () => import("./lint-5vbq6yjb.js").then((m) => m.default),
26
- validate: () => import("./validate-avtb9drn.js").then((m) => m.default),
27
- audit: () => import("./audit-ek36tf4q.js").then((m) => m.default),
28
- preflight: () => import("./preflight-4ywt3399.js").then((m) => m.default),
29
- doctor: () => import("./doctor-tgmedr7g.js").then((m) => m.default),
30
- ext: () => import("./ext-jjzmafve.js").then((m) => m.default)
21
+ new: () => import("./new-wyhadpt4.js").then((m) => m.default),
22
+ preview: () => import("./preview-w9bp0fgf.js").then((m) => m.default),
23
+ build: () => import("./build-e54deg18.js").then((m) => m.default),
24
+ publish: () => import("./publish-9fn1hjmb.js").then((m) => m.default),
25
+ lint: () => import("./lint-2pgsfsp6.js").then((m) => m.default),
26
+ validate: () => import("./validate-v9abv9xs.js").then((m) => m.default),
27
+ audit: () => import("./audit-sb0abmqy.js").then((m) => m.default),
28
+ preflight: () => import("./preflight-wbfd5ma1.js").then((m) => m.default),
29
+ doctor: () => import("./doctor-es2cw92p.js").then((m) => m.default),
30
+ ext: () => import("./ext-06srzer2.js").then((m) => m.default)
31
31
  };
32
32
  var VERSION = package_default.version;
33
33
  var main = defineCommand({
@@ -52,7 +52,7 @@ async function preflightRequiredInvocations(rawArgs) {
52
52
  const [command, ...commandArgs] = rawArgs;
53
53
  try {
54
54
  if (command === "new") {
55
- const { newArgs } = await import("./new-qws45t02.js");
55
+ const { newArgs } = await import("./new-wyhadpt4.js");
56
56
  rejectUnknownFlags(commandArgs, newArgs, "new");
57
57
  const parsed = parseArgs(commandArgs, {
58
58
  ...newArgs,
@@ -64,7 +64,7 @@ async function preflightRequiredInvocations(rawArgs) {
64
64
  return;
65
65
  }
66
66
  if (command === "preflight") {
67
- const { preflightArgs } = await import("./preflight-4ywt3399.js");
67
+ const { preflightArgs } = await import("./preflight-wbfd5ma1.js");
68
68
  rejectUnknownFlags(commandArgs, preflightArgs, "preflight");
69
69
  const parsed = parseArgs(commandArgs, {
70
70
  ...preflightArgs,
@@ -84,7 +84,7 @@ async function preflightRequiredInvocations(rawArgs) {
84
84
  }
85
85
  if (subcommand.startsWith("-"))
86
86
  return;
87
- const { EXT_SUBCOMMANDS, extAddArgs, extRemoveArgs, extEnableArgs, extDisableArgs } = await import("./ext-jjzmafve.js");
87
+ const { EXT_SUBCOMMANDS, extAddArgs, extRemoveArgs, extEnableArgs, extDisableArgs } = await import("./ext-06srzer2.js");
88
88
  if (!EXT_SUBCOMMANDS.includes(subcommand)) {
89
89
  throw new UsageError(`gutterpress ext: unknown command "${subcommand}"`);
90
90
  }
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  getSystemDiagnostics,
3
3
  log
4
- } from "./cli-12epgrva.js";
4
+ } from "./cli-d7k5ykyx.js";
5
5
  import {
6
6
  UsageError,
7
7
  rejectExtraPositionals,
8
8
  rejectUnknownFlags
9
- } from "./cli-tvpq2ht9.js";
9
+ } from "./cli-1prnz7c8.js";
10
10
  import"./cli-c41yr7he.js";
11
11
  import"./cli-46ycxe6r.js";
12
12
  import"./cli-37x76zdn.js";
@@ -10,21 +10,21 @@ import {
10
10
  removeExtension,
11
11
  searchNpmExtensions,
12
12
  setExtensionEnabled
13
- } from "./cli-5fqr02je.js";
14
- import"./cli-12epgrva.js";
13
+ } from "./cli-x4krgssg.js";
14
+ import"./cli-d7k5ykyx.js";
15
15
  import {
16
16
  UsageError,
17
17
  exitForUsage,
18
18
  rejectExtraPositionals,
19
19
  rejectUnknownFlags,
20
20
  resolveProjectDir
21
- } from "./cli-tvpq2ht9.js";
21
+ } from "./cli-1prnz7c8.js";
22
22
  import"./cli-k8f9eb12.js";
23
23
  import"./cli-c41yr7he.js";
24
24
  import {
25
25
  EXIT_CODES
26
26
  } from "./cli-46ycxe6r.js";
27
- import"./cli-vje8g3w8.js";
27
+ import"./cli-4mtf9ajw.js";
28
28
  import"./cli-v5mp7a6q.js";
29
29
  import"./cli-37x76zdn.js";
30
30
 
@@ -29,7 +29,7 @@ import {
29
29
  snapshotStagingMarkerPath,
30
30
  snapshotWorkingTreeUnlocked,
31
31
  withRepoLock
32
- } from "./index-f833dtg9.js";
32
+ } from "./index-y01v2fe0.js";
33
33
  import {
34
34
  detectProjectSource,
35
35
  syncRemoteFor
@@ -4839,7 +4839,7 @@ import git from "isomorphic-git";
4839
4839
  // package.json
4840
4840
  var package_default = {
4841
4841
  name: "gutterpress",
4842
- version: "0.10.10-alpha.1",
4842
+ version: "0.10.10-alpha.3",
4843
4843
  description: "Markdown-to-PDF converter for professional print layout using a native Chromium print engine and Ghostscript.",
4844
4844
  author: "itlackey",
4845
4845
  license: "MPL-2.0",
@@ -12237,7 +12237,7 @@ async function scaffoldProject(options) {
12237
12237
  let versionHistoryError;
12238
12238
  if (requested === "local-git") {
12239
12239
  try {
12240
- const { providerFor } = await import("./source-provider-y1kscr1h.js");
12240
+ const { providerFor } = await import("./source-provider-jkppq9fc.js");
12241
12241
  const provider = providerFor({ type: "local-folder", path: projectDir });
12242
12242
  await provider.initVersionHistory({
12243
12243
  projectDir,
@@ -12334,7 +12334,7 @@ styles:
12334
12334
  let versionHistoryError;
12335
12335
  if (requested === "local-git") {
12336
12336
  try {
12337
- const { providerFor } = await import("./source-provider-y1kscr1h.js");
12337
+ const { providerFor } = await import("./source-provider-jkppq9fc.js");
12338
12338
  const provider = providerFor({ type: "local-folder", path: dir });
12339
12339
  await provider.initVersionHistory({
12340
12340
  projectDir: dir,
@@ -15066,6 +15066,37 @@ async function syncProject(options) {
15066
15066
  }
15067
15067
  });
15068
15068
  }
15069
+ async function refreshRemoteCopies(options) {
15070
+ const http3 = options.httpClient ?? defaultGitHttp;
15071
+ try {
15072
+ const dir = await repoDirFor(options.projectDir);
15073
+ const transport = await resolveTransport(dir, {
15074
+ ...options.credential ? { credential: options.credential } : {},
15075
+ ...options.tokenStore ? { tokenStore: options.tokenStore } : {}
15076
+ });
15077
+ await git6.fetch({
15078
+ fs: gitFs,
15079
+ http: http3,
15080
+ dir,
15081
+ remote: transport.remote,
15082
+ singleBranch: false,
15083
+ prune: true,
15084
+ tags: false,
15085
+ ...onAuthFor(transport.credential)
15086
+ });
15087
+ return { refreshed: true };
15088
+ } catch (e) {
15089
+ const message = e?.message ?? "";
15090
+ if (message === MSG_NO_REMOTE || message === MSG_SSH_REMOTE) {
15091
+ return { refreshed: false, reason: "no-remote" };
15092
+ }
15093
+ const status = e?.data?.statusCode;
15094
+ if (status === 401 || status === 403 || status === 404) {
15095
+ return { refreshed: false, reason: "auth" };
15096
+ }
15097
+ return { refreshed: false, reason: "offline" };
15098
+ }
15099
+ }
15069
15100
  // src/lib/publish/run-publish.ts
15070
15101
  import { readdir as readdir11, stat as stat11 } from "node:fs/promises";
15071
15102
  import path28 from "node:path";
@@ -16638,4 +16669,4 @@ async function setPublishProviderConfig(projectDir, providerId, values) {
16638
16669
  await writeManifestDoc(file, doc);
16639
16670
  return settingsFromDoc(doc);
16640
16671
  }
16641
- export { DEFAULT_NPM_REGISTRY, npmRegistryUrl, PLUGINS_DIR, BUNDLED_EXTENSIONS, isBundledExtension, isPathSpecifier, parseExtensionSpecifier, PRESET_IDS, PRESETS, TARGETS, TARGET_IDS, publishTargetFor, MANIFEST_FILENAMES, hasProjectManifest, loadManifest, loadManifestWithPath, resolveConfig, SYNC_SNAPSHOT_MESSAGE, log, resolveActiveStyles, listProjectStyles, EXTENSION_MANIFEST_FILENAME, readExtensionMeta, extensionStyleList, extensionEntry, extensionCarries, pathEscapesFolder, assertExtensionContained, resolveExtension, loadPluginsWithCss, formatReport, getChecks, getCheckById, resolveCheckSelectors, ruleRemoteUrls, ruleRiskyProps, ruleSyntax, rulePageContainment, checkCss, inspectImage, runChecks, checkToolAvailability, reportMissingTools, executeValidation, executeAndReport, splitOutPath, runBuild, openPath, startPreviewServer, defaultConfigDir, FileTokenStore, extractUrlCredential, getSystemDiagnostics, EXTENSIONS_DIR, RECOMMENDED_EXTENSIONS, BUILT_IN_STYLE_SET_IDS, sameExtension, listProjectExtensions, describeExtension, setExtensionEnabled, reorderExtensions, removeExtension, addExtension, listBuiltInStyleSets, addBuiltInStyleSet, validateProjectExtensions, readExtensionCss, slugifyProjectName, escapeYamlScalar, scaffoldProject, adoptFolder, EXTENSION_KINDS, RESERVED_PREFIX, resolveExtensionPrefix, scaffoldExtension, BUILT_IN_TEMPLATE_IDS, listBuiltInTemplates, saveProjectAsTemplate, listCustomTemplates, importTemplateFromFolder, SNIPPETS_DIR, extractVariables, substituteVariables, listSnippets, readSnippet, saveSnippet, deleteSnippet, listMergedSnippets, readExtensionSnippet, importExtensionFromFile, importExtensionFromUrl, MAX_SEARCH_BYTES, SEARCH_KEYWORDS, searchNpmExtensions, setManifestFields, readManifestFields, setActiveStyles, AUTO_SNAPSHOT_DEFAULT_MINUTES, AUTO_SYNC_MIN_MINUTES, AUTO_SYNC_MAX_MINUTES, AUTO_SYNC_DEFAULT_MINUTES, AUTO_SYNC_PUSH_INTERVAL_MINUTES, autoSnapshotDelayMs, autoSyncDelayMs, isGitInternalPath, resolveGitHubClientId, GITHUB_HOST, GitHubAuthProvider, GDRIVE_HOST, resolveGoogleClientId, resolveGoogleClientSecret, GOOGLE_NOT_CONFIGURED_MESSAGE, requireGoogleClientCredentials, pkceChallengeFromVerifier, GoogleAuthProvider, revokeGoogleCredential, publishCredentialKey, publishConnectionStatus, listPublishAccounts, connectGoogleDrive, listGitHubRepositories, listRepoBooks, listGitHubBranches, sanitizeCloneFolderName, cloneRepository, isSshRemoteUrl, testRemoteAccess, knownForgeTokenUrl, connectGenericHost, parseRemoteOrigin, forgeKindForHost, diagnoseProjectRemote, syncProject, listPublishProviders, publishProviderFor, resolvePublishFormat, resolvePublishRequest, runPublish, connectPublishProvider, disconnectPublishCredential, PublishSelectionsStore, readPublishSettings, setPublishProviderConfig };
16672
+ export { DEFAULT_NPM_REGISTRY, npmRegistryUrl, PLUGINS_DIR, BUNDLED_EXTENSIONS, isBundledExtension, isPathSpecifier, parseExtensionSpecifier, PRESET_IDS, PRESETS, TARGETS, TARGET_IDS, publishTargetFor, MANIFEST_FILENAMES, hasProjectManifest, loadManifest, loadManifestWithPath, resolveConfig, SYNC_SNAPSHOT_MESSAGE, log, resolveActiveStyles, listProjectStyles, EXTENSION_MANIFEST_FILENAME, readExtensionMeta, extensionStyleList, extensionEntry, extensionCarries, pathEscapesFolder, assertExtensionContained, resolveExtension, loadPluginsWithCss, formatReport, getChecks, getCheckById, resolveCheckSelectors, ruleRemoteUrls, ruleRiskyProps, ruleSyntax, rulePageContainment, checkCss, inspectImage, runChecks, checkToolAvailability, reportMissingTools, executeValidation, executeAndReport, splitOutPath, runBuild, openPath, startPreviewServer, defaultConfigDir, FileTokenStore, extractUrlCredential, getSystemDiagnostics, EXTENSIONS_DIR, RECOMMENDED_EXTENSIONS, BUILT_IN_STYLE_SET_IDS, sameExtension, listProjectExtensions, describeExtension, setExtensionEnabled, reorderExtensions, removeExtension, addExtension, listBuiltInStyleSets, addBuiltInStyleSet, validateProjectExtensions, readExtensionCss, slugifyProjectName, escapeYamlScalar, scaffoldProject, adoptFolder, EXTENSION_KINDS, RESERVED_PREFIX, resolveExtensionPrefix, scaffoldExtension, BUILT_IN_TEMPLATE_IDS, listBuiltInTemplates, saveProjectAsTemplate, listCustomTemplates, importTemplateFromFolder, SNIPPETS_DIR, extractVariables, substituteVariables, listSnippets, readSnippet, saveSnippet, deleteSnippet, listMergedSnippets, readExtensionSnippet, importExtensionFromFile, importExtensionFromUrl, MAX_SEARCH_BYTES, SEARCH_KEYWORDS, searchNpmExtensions, setManifestFields, readManifestFields, setActiveStyles, AUTO_SNAPSHOT_DEFAULT_MINUTES, AUTO_SYNC_MIN_MINUTES, AUTO_SYNC_MAX_MINUTES, AUTO_SYNC_DEFAULT_MINUTES, AUTO_SYNC_PUSH_INTERVAL_MINUTES, autoSnapshotDelayMs, autoSyncDelayMs, isGitInternalPath, resolveGitHubClientId, GITHUB_HOST, GitHubAuthProvider, GDRIVE_HOST, resolveGoogleClientId, resolveGoogleClientSecret, GOOGLE_NOT_CONFIGURED_MESSAGE, requireGoogleClientCredentials, pkceChallengeFromVerifier, GoogleAuthProvider, revokeGoogleCredential, publishCredentialKey, publishConnectionStatus, listPublishAccounts, connectGoogleDrive, listGitHubRepositories, listRepoBooks, listGitHubBranches, sanitizeCloneFolderName, cloneRepository, isSshRemoteUrl, testRemoteAccess, knownForgeTokenUrl, connectGenericHost, parseRemoteOrigin, forgeKindForHost, diagnoseProjectRemote, syncProject, refreshRemoteCopies, listPublishProviders, publishProviderFor, resolvePublishFormat, resolvePublishRequest, runPublish, connectPublishProvider, disconnectPublishCredential, PublishSelectionsStore, readPublishSettings, setPublishProviderConfig };
@@ -514,13 +514,45 @@ async function listLocalBranches(dir) {
514
514
  if (source.type !== "local-git-folder")
515
515
  return null;
516
516
  const repoDir = gitScopeFor(source);
517
- const [branches, current] = await Promise.all([
517
+ const [local, current, remotes] = await Promise.all([
518
518
  git.listBranches({ fs: gitFs, dir: repoDir }),
519
519
  git.currentBranch({ fs: gitFs, dir: repoDir, fullname: false }).catch(() => {
520
520
  return;
521
- })
521
+ }),
522
+ git.listRemotes({ fs: gitFs, dir: repoDir }).catch(() => [])
522
523
  ]);
523
- return { current: current ?? null, branches };
524
+ const localNames = new Set(local);
525
+ const remoteOnly = new Set;
526
+ for (const { remote } of remotes) {
527
+ const names = await git.listBranches({ fs: gitFs, dir: repoDir, remote }).catch(() => []);
528
+ for (const name of names) {
529
+ if (name === "HEAD")
530
+ continue;
531
+ if (!localNames.has(name))
532
+ remoteOnly.add(name);
533
+ }
534
+ }
535
+ return {
536
+ current: current ?? null,
537
+ branches: [...localNames, ...remoteOnly].sort(),
538
+ remoteOnly: [...remoteOnly].sort()
539
+ };
540
+ }
541
+ async function resolveCopy(repoDir, branch) {
542
+ const local = await git.resolveRef({ fs: gitFs, dir: repoDir, ref: `refs/heads/${branch}` }).catch(() => {
543
+ return;
544
+ });
545
+ if (local)
546
+ return { oid: local };
547
+ const remotes = await git.listRemotes({ fs: gitFs, dir: repoDir }).catch(() => []);
548
+ for (const { remote } of remotes) {
549
+ const oid = await git.resolveRef({ fs: gitFs, dir: repoDir, ref: `refs/remotes/${remote}/${branch}` }).catch(() => {
550
+ return;
551
+ });
552
+ if (oid)
553
+ return { oid, remote };
554
+ }
555
+ throw new Error(`Couldn't find a copy named "${branch}" — it may have been renamed or deleted.`);
524
556
  }
525
557
  function isCheckoutConflictError(e) {
526
558
  return e?.code === "CheckoutConflictError";
@@ -579,9 +611,16 @@ async function switchBranch(options) {
579
611
  const fromOid = await git.resolveRef({ fs: gitFs, dir: repoDir, ref: "HEAD" }).catch(() => {
580
612
  return;
581
613
  });
582
- const toOid = await git.resolveRef({ fs: gitFs, dir: repoDir, ref: branch });
614
+ const { oid: toOid, remote } = await resolveCopy(repoDir, branch);
583
615
  try {
584
- await git.checkout({ fs: gitFs, dir: repoDir, cache, ref: branch, force: false });
616
+ await git.checkout({
617
+ fs: gitFs,
618
+ dir: repoDir,
619
+ cache,
620
+ ref: branch,
621
+ force: false,
622
+ ...remote ? { remote } : {}
623
+ });
585
624
  } catch (e) {
586
625
  if (isCheckoutConflictError(e)) {
587
626
  throw new Error("Couldn't switch copies — some files changed on disk right as the switch " + "started. Try again.", { cause: e });
package/dist/index.js CHANGED
@@ -102,6 +102,7 @@ import {
102
102
  readManifestFields,
103
103
  readPublishSettings,
104
104
  readSnippet,
105
+ refreshRemoteCopies,
105
106
  removeExtension,
106
107
  reorderExtensions,
107
108
  reportMissingTools,
@@ -142,7 +143,7 @@ import {
142
143
  syncProject,
143
144
  testRemoteAccess,
144
145
  validateProjectExtensions
145
- } from "./index-d4wrww4b.js";
146
+ } from "./index-ryjmpyq6.js";
146
147
  import {
147
148
  BUILD_DIAGNOSTIC_CODES
148
149
  } from "./index-a0e2253t.js";
@@ -162,7 +163,7 @@ import {
162
163
  resolveLogger,
163
164
  restoreVersionWithBackup,
164
165
  switchBranch
165
- } from "./index-f833dtg9.js";
166
+ } from "./index-y01v2fe0.js";
166
167
  import {
167
168
  capabilitiesFor,
168
169
  detectProjectSource,
@@ -293,6 +294,7 @@ export {
293
294
  repoRootForSource,
294
295
  reorderExtensions,
295
296
  removeExtension,
297
+ refreshRemoteCopies,
296
298
  readyProbeExpr,
297
299
  readSnippet,
298
300
  readPublishSettings,
@@ -1,5 +1,7 @@
1
+ import { defaultGitHttp } from "./git-http.ts";
1
2
  import { onAuthFor } from "./transport.ts";
2
3
  import type { SyncOutcome, SyncProjectOptions } from "./sync-types.ts";
4
+ import type { HostCredential, TokenStore } from "./token-store.ts";
3
5
  export { onAuthFor };
4
6
  export { SYNC_SNAPSHOT_MESSAGE } from "./sync-messages.ts";
5
7
  export type { KeptBothFile, SyncOutcome, SyncProjectOptions, } from "./sync-types.ts";
@@ -26,3 +28,36 @@ export declare function isUnrelatedHistories(e: unknown): boolean;
26
28
  * outcomes — everything is reported through {@link SyncOutcome}.
27
29
  */
28
30
  export declare function syncProject(options: SyncProjectOptions): Promise<SyncOutcome>;
31
+ /**
32
+ * Fetch every branch the remote has, so the project's copy list reflects what
33
+ * exists online rather than only what this clone happened to fetch before.
34
+ *
35
+ * The copy picker reads refs off disk (`listLocalBranches`). That makes a
36
+ * branch pushed from anywhere else — another machine, the web UI, an agent
37
+ * opening a PR — invisible here until someone runs `git fetch` in a terminal,
38
+ * which is precisely the thing this app exists to avoid. So the picker calls
39
+ * this first.
40
+ *
41
+ * Unlike `fetchRemoteTip` this deliberately does NOT use `singleBranch`: the
42
+ * whole point is the branches we do not have yet. It only ever writes
43
+ * remote-tracking refs (`refs/remotes/<remote>/*`) — no local branch, no
44
+ * working-tree change, no merge — so it is safe to call on a dirty tree.
45
+ * `prune` drops tracking refs for branches deleted online, so the list cannot
46
+ * offer a copy that is gone.
47
+ *
48
+ * Best-effort by contract: offline, unauthenticated, or no remote at all
49
+ * resolves to `{ refreshed: false, reason }` rather than throwing. A stale
50
+ * list beats an error dialog over a control the author did not explicitly ask
51
+ * to sync — but it reports WHY, because a picker that silently omits copies
52
+ * is indistinguishable from a broken one, which is the bug this whole
53
+ * function exists to fix.
54
+ */
55
+ export declare function refreshRemoteCopies(options: {
56
+ projectDir: string;
57
+ credential?: HostCredential;
58
+ tokenStore?: TokenStore;
59
+ httpClient?: typeof defaultGitHttp;
60
+ }): Promise<{
61
+ refreshed: boolean;
62
+ reason?: "no-remote" | "auth" | "offline";
63
+ }>;
@@ -239,17 +239,26 @@ export declare const AUTO_SNAPSHOT_MESSAGE = "Automatic snapshot";
239
239
  * folder has no version history.
240
240
  */
241
241
  export declare function restoreVersionWithBackup(options: RestoreVersionOptions): Promise<RestoreVersionResult>;
242
- /** The project's local copies (git branches) and which one is currently open. */
242
+ /** The project's copies (git branches) and which one is currently open. */
243
243
  export interface LocalBranches {
244
244
  /** Name of the branch HEAD points to, or `null` on a detached/unborn HEAD. */
245
245
  current: string | null;
246
- /** Every local branch name (`refs/heads/*`), in no particular order. */
246
+ /**
247
+ * Every copy the project can switch to, sorted: local branches
248
+ * (`refs/heads/*`) plus copies that so far exist only on a remote.
249
+ */
247
250
  branches: string[];
251
+ /**
252
+ * The subset of {@link branches} with no local ref yet. Switching to one of
253
+ * these creates the local copy from the remote and tracks it; the UI uses
254
+ * this only to say so before it happens.
255
+ */
256
+ remoteOnly: string[];
248
257
  }
249
258
  /** Inputs for {@link switchBranch}. */
250
259
  export interface SwitchBranchOptions {
251
260
  projectDir: string;
252
- /** Local branch name to check out. */
261
+ /** Branch name to check out — local, or one that so far exists only on a remote. */
253
262
  branch: string;
254
263
  /** Identity recorded on the automatic pre-switch safety snapshot, if one is taken. */
255
264
  authorName?: string;
@@ -272,10 +281,14 @@ export interface SwitchBranchResult {
272
281
  /** Snapshot message for the safety snapshot {@link switchBranch} takes before checking out, when the working tree has changes. */
273
282
  export declare const SWITCH_BRANCH_SNAPSHOT_MESSAGE = "Saved before switching copy";
274
283
  /**
275
- * List the project's local copies (git branches) and which one is open, for a
284
+ * List the project's copies (git branches) and which one is open, for a
276
285
  * `local-git-folder` project. Returns `null` for any other source type —
277
286
  * there is nothing to switch between, and the caller (the Saving settings row)
278
287
  * hides the whole control on `null` rather than showing an error.
288
+ *
289
+ * Copies that exist only on a remote are included: they are as real to the
290
+ * author as the local ones, and {@link switchBranch} creates the local branch
291
+ * on the way in.
279
292
  */
280
293
  export declare function listLocalBranches(dir: string): Promise<LocalBranches | null>;
281
294
  /**
@@ -1,21 +1,21 @@
1
1
  import {
2
2
  MANIFEST_FILENAMES,
3
3
  runLint
4
- } from "./cli-5fqr02je.js";
4
+ } from "./cli-x4krgssg.js";
5
5
  import {
6
6
  log
7
- } from "./cli-12epgrva.js";
7
+ } from "./cli-d7k5ykyx.js";
8
8
  import {
9
9
  UsageError,
10
10
  rejectExtraPositionals,
11
11
  rejectUnknownFlags
12
- } from "./cli-tvpq2ht9.js";
12
+ } from "./cli-1prnz7c8.js";
13
13
  import"./cli-k8f9eb12.js";
14
14
  import"./cli-c41yr7he.js";
15
15
  import {
16
16
  EXIT_CODES
17
17
  } from "./cli-46ycxe6r.js";
18
- import"./cli-vje8g3w8.js";
18
+ import"./cli-4mtf9ajw.js";
19
19
  import"./cli-v5mp7a6q.js";
20
20
  import"./cli-37x76zdn.js";
21
21
 
@@ -7,15 +7,15 @@ import {
7
7
  TARGET_IDS,
8
8
  scaffoldExtension,
9
9
  scaffoldProject
10
- } from "./cli-5fqr02je.js";
10
+ } from "./cli-x4krgssg.js";
11
11
  import {
12
12
  resolveGhostscript
13
- } from "./cli-12epgrva.js";
13
+ } from "./cli-d7k5ykyx.js";
14
14
  import {
15
15
  UsageError,
16
16
  rejectExtraPositionals,
17
17
  rejectUnknownFlags
18
- } from "./cli-tvpq2ht9.js";
18
+ } from "./cli-1prnz7c8.js";
19
19
  import"./cli-k8f9eb12.js";
20
20
  import {
21
21
  isToolAvailable
@@ -23,7 +23,7 @@ import {
23
23
  import {
24
24
  EXIT_CODES
25
25
  } from "./cli-46ycxe6r.js";
26
- import"./cli-vje8g3w8.js";
26
+ import"./cli-4mtf9ajw.js";
27
27
  import"./cli-v5mp7a6q.js";
28
28
  import"./cli-37x76zdn.js";
29
29
 
@@ -2,21 +2,21 @@ import {
2
2
  executeValidation,
3
3
  publishTargetFor,
4
4
  reportMissingTools
5
- } from "./cli-5fqr02je.js";
5
+ } from "./cli-x4krgssg.js";
6
6
  import {
7
7
  log
8
- } from "./cli-12epgrva.js";
8
+ } from "./cli-d7k5ykyx.js";
9
9
  import {
10
10
  UsageError,
11
11
  rejectExtraPositionals,
12
12
  rejectUnknownFlags
13
- } from "./cli-tvpq2ht9.js";
13
+ } from "./cli-1prnz7c8.js";
14
14
  import"./cli-k8f9eb12.js";
15
15
  import"./cli-c41yr7he.js";
16
16
  import {
17
17
  EXIT_CODES
18
18
  } from "./cli-46ycxe6r.js";
19
- import"./cli-vje8g3w8.js";
19
+ import"./cli-4mtf9ajw.js";
20
20
  import"./cli-v5mp7a6q.js";
21
21
  import"./cli-37x76zdn.js";
22
22
 
@@ -6,10 +6,10 @@ import {
6
6
  runBuild,
7
7
  splitOutPath,
8
8
  startPreviewServer
9
- } from "./cli-5fqr02je.js";
9
+ } from "./cli-x4krgssg.js";
10
10
  import {
11
11
  log
12
- } from "./cli-12epgrva.js";
12
+ } from "./cli-d7k5ykyx.js";
13
13
  import {
14
14
  UsageError,
15
15
  parseFormat,
@@ -17,13 +17,13 @@ import {
17
17
  rejectExtraPositionals,
18
18
  rejectUnknownFlags,
19
19
  resolvePort
20
- } from "./cli-tvpq2ht9.js";
20
+ } from "./cli-1prnz7c8.js";
21
21
  import"./cli-k8f9eb12.js";
22
22
  import"./cli-c41yr7he.js";
23
23
  import {
24
24
  BuildError
25
25
  } from "./cli-46ycxe6r.js";
26
- import"./cli-vje8g3w8.js";
26
+ import"./cli-4mtf9ajw.js";
27
27
  import"./cli-v5mp7a6q.js";
28
28
  import"./cli-37x76zdn.js";
29
29
 
@@ -11,22 +11,22 @@ import {
11
11
  publishProviderFor,
12
12
  resolvePublishFormat,
13
13
  runPublish
14
- } from "./cli-5fqr02je.js";
14
+ } from "./cli-x4krgssg.js";
15
15
  import {
16
16
  FileTokenStore,
17
17
  log
18
- } from "./cli-12epgrva.js";
18
+ } from "./cli-d7k5ykyx.js";
19
19
  import {
20
20
  UsageError,
21
21
  rejectExtraPositionals,
22
22
  rejectUnknownFlags
23
- } from "./cli-tvpq2ht9.js";
23
+ } from "./cli-1prnz7c8.js";
24
24
  import"./cli-k8f9eb12.js";
25
25
  import"./cli-c41yr7he.js";
26
26
  import {
27
27
  EXIT_CODES
28
28
  } from "./cli-46ycxe6r.js";
29
- import"./cli-vje8g3w8.js";
29
+ import"./cli-4mtf9ajw.js";
30
30
  import"./cli-v5mp7a6q.js";
31
31
  import"./cli-37x76zdn.js";
32
32
 
@@ -19,7 +19,7 @@ import {
19
19
  stageChanges,
20
20
  switchBranch,
21
21
  withRepoLock
22
- } from "./cli-vje8g3w8.js";
22
+ } from "./cli-4mtf9ajw.js";
23
23
  import"./cli-v5mp7a6q.js";
24
24
  import"./cli-37x76zdn.js";
25
25
  export {
@@ -19,7 +19,7 @@ import {
19
19
  stageChanges,
20
20
  switchBranch,
21
21
  withRepoLock
22
- } from "./index-f833dtg9.js";
22
+ } from "./index-y01v2fe0.js";
23
23
  import"./index-v5mp7a6q.js";
24
24
  import"./index-37x76zdn.js";
25
25
  export {
@@ -1,20 +1,20 @@
1
1
  import {
2
2
  executeAndReport
3
- } from "./cli-5fqr02je.js";
3
+ } from "./cli-x4krgssg.js";
4
4
  import {
5
5
  log
6
- } from "./cli-12epgrva.js";
6
+ } from "./cli-d7k5ykyx.js";
7
7
  import {
8
8
  UsageError,
9
9
  rejectExtraPositionals,
10
10
  rejectUnknownFlags
11
- } from "./cli-tvpq2ht9.js";
11
+ } from "./cli-1prnz7c8.js";
12
12
  import"./cli-k8f9eb12.js";
13
13
  import"./cli-c41yr7he.js";
14
14
  import {
15
15
  EXIT_CODES
16
16
  } from "./cli-46ycxe6r.js";
17
- import"./cli-vje8g3w8.js";
17
+ import"./cli-4mtf9ajw.js";
18
18
  import"./cli-v5mp7a6q.js";
19
19
  import"./cli-37x76zdn.js";
20
20
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gutterpress",
3
- "version": "0.10.10-alpha.1",
3
+ "version": "0.10.10-alpha.3",
4
4
  "description": "Markdown-to-PDF converter for professional print layout using a native Chromium print engine and Ghostscript.",
5
5
  "author": "itlackey",
6
6
  "license": "MPL-2.0",