@buildinternet/uploads 0.43.0 → 0.45.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.d.ts CHANGED
@@ -305,6 +305,32 @@ export interface PromoteBranchAttachmentsResult {
305
305
  promoted: string[];
306
306
  skipped: PromoteSkip[];
307
307
  }
308
+ /**
309
+ * `POST /v1/workspaces/:workspace/github/attach` request/response (server
310
+ * contract, issue #702). `source` is a raw object key or an uploads.sh URL
311
+ * (storage host, embed host, or `/f/` page). Exactly one of `pr`/`issue` is
312
+ * required. Copy by default; `move: true` deletes the source object after a
313
+ * successful copy.
314
+ */
315
+ export interface AttachExistingOptions {
316
+ source: string;
317
+ repo: string;
318
+ pr?: number;
319
+ issue?: number;
320
+ move?: boolean;
321
+ filename?: string;
322
+ }
323
+ export interface AttachExistingResult {
324
+ key: string;
325
+ url: string | null;
326
+ embedUrl: string | null;
327
+ pageUrl?: string;
328
+ moved: boolean;
329
+ source: {
330
+ key: string;
331
+ };
332
+ comment: GithubCommentResult;
333
+ }
308
334
  /** `GET`/`POST /v1/workspaces/:workspace/github/link` result (server contract, phase 4b). */
309
335
  export interface GithubLinkResult {
310
336
  repo: string;
@@ -670,6 +696,15 @@ export declare function createUploadsClient(config: UploadsClientConfig): {
670
696
  * that doesn't have this route yet, as "nothing promoted").
671
697
  */
672
698
  promoteBranchAttachments(opts: PromoteBranchAttachmentsOptions): Promise<PromoteBranchAttachmentsResult>;
699
+ /**
700
+ * Attach an already-uploaded object to a PR/issue via a server-side copy
701
+ * (issue #702) — see `AttachExistingOptions`. Throws `UploadsError` on
702
+ * any failure (including a 404 from an older/self-hosted server without
703
+ * this route, or `source_not_found`) — unlike the degrade-safe promote/
704
+ * comment calls, this is the CLI's only way to move the object, so a
705
+ * failure must be visible, not silently swallowed.
706
+ */
707
+ attachExisting(opts: AttachExistingOptions): Promise<AttachExistingResult>;
673
708
  /** Current binding for `repo`, or `{ linked: false }` if unclaimed. Throws
674
709
  * `UploadsError` (status 404) on an older/self-hosted server without this
675
710
  * route — callers treat that as "bindings unsupported". */
package/dist/client.js CHANGED
@@ -582,6 +582,20 @@ export function createUploadsClient(config) {
582
582
  headers: { "Content-Type": "application/json" },
583
583
  });
584
584
  },
585
+ /**
586
+ * Attach an already-uploaded object to a PR/issue via a server-side copy
587
+ * (issue #702) — see `AttachExistingOptions`. Throws `UploadsError` on
588
+ * any failure (including a 404 from an older/self-hosted server without
589
+ * this route, or `source_not_found`) — unlike the degrade-safe promote/
590
+ * comment calls, this is the CLI's only way to move the object, so a
591
+ * failure must be visible, not silently swallowed.
592
+ */
593
+ async attachExisting(opts) {
594
+ return request("POST", `${config.apiUrl}/v1/workspaces/${encodeURIComponent(config.workspace)}/github/attach`, {
595
+ body: new TextEncoder().encode(JSON.stringify(opts)),
596
+ headers: { "Content-Type": "application/json" },
597
+ });
598
+ },
585
599
  /** Current binding for `repo`, or `{ linked: false }` if unclaimed. Throws
586
600
  * `UploadsError` (status 404) on an older/self-hosted server without this
587
601
  * route — callers treat that as "bindings unsupported". */
@@ -1,7 +1,11 @@
1
1
  /**
2
2
  * `uploads hook pre-pr-screenshot` — agent PreToolUse / beforeShellExecution
3
- * handler. When the shell command is `gh pr create`, the branch touches UI
4
- * files, and nothing is staged on uploads.sh, emit a non-blocking advisory.
3
+ * handler, triggered on `gh pr create`. Two advisories, mutually exclusive:
4
+ * - staged-but-unattached files exist for the branch (any reason they got
5
+ * there) → a promote suggestion (issue #700): `uploads attach --promote`
6
+ * once the PR this command is about to open exists.
7
+ * - nothing is staged, but the branch touches UI files → the original
8
+ * (issue #379) "consider staging screenshots" advisory.
5
9
  *
6
10
  * Always fail-open. Disable with UPLOADS_HOOK_DISABLE=1.
7
11
  */
@@ -1,7 +1,11 @@
1
1
  /**
2
2
  * `uploads hook pre-pr-screenshot` — agent PreToolUse / beforeShellExecution
3
- * handler. When the shell command is `gh pr create`, the branch touches UI
4
- * files, and nothing is staged on uploads.sh, emit a non-blocking advisory.
3
+ * handler, triggered on `gh pr create`. Two advisories, mutually exclusive:
4
+ * - staged-but-unattached files exist for the branch (any reason they got
5
+ * there) → a promote suggestion (issue #700): `uploads attach --promote`
6
+ * once the PR this command is about to open exists.
7
+ * - nothing is staged, but the branch touches UI files → the original
8
+ * (issue #379) "consider staging screenshots" advisory.
5
9
  *
6
10
  * Always fail-open. Disable with UPLOADS_HOOK_DISABLE=1.
7
11
  */
@@ -22,9 +26,12 @@ Invoked by Claude Code / Codex / Grok / Cursor hooks. Never blocks.
22
26
  Harness manifests no-op (exit 0, no output) when this binary is not on PATH.
23
27
 
24
28
  pre-pr-screenshot
25
- If the shell command is \`gh pr create\`, the branch touches UI files, and
26
- no screenshots are staged for the branch, emit an advisory to stage with
27
- \`uploads attach --branch\`.
29
+ If the shell command is \`gh pr create\`:
30
+ - staged-but-unattached files exist for the branch suggest promoting
31
+ them into the PR's managed comment once it exists (issue #700):
32
+ \`uploads attach --promote --pr <num>\`.
33
+ - otherwise, if the branch touches UI files → suggest staging with
34
+ \`uploads attach … --branch\`.
28
35
 
29
36
  Disable with UPLOADS_HOOK_DISABLE=1.
30
37
  `;
@@ -158,14 +165,29 @@ export async function runPrePrScreenshot(deps) {
158
165
  const branch = git.branch();
159
166
  if (!branch)
160
167
  return null;
168
+ const staged = await (deps.countStaged ?? defaultCountStaged)(branch);
169
+ if (staged === null)
170
+ return null; // error/unconfigured → fail open
171
+ // Promote suggestion (issue #700): staged-but-unattached files already
172
+ // exist for this branch right as its PR is about to open. The PR doesn't
173
+ // exist yet at this PreToolUse point, so its number isn't knowable here —
174
+ // the wording still gives the exact command shape, and a bare
175
+ // `attach --promote` (which infers the PR from the branch) works too.
176
+ if (staged > 0) {
177
+ const fork = (deps.isFork ?? (() => defaultIsFork(cwd)))();
178
+ const forkNote = fork === true
179
+ ? " Note: this looks like a fork branch, so staged screenshots won't auto-promote into the PR comment yet (see issue #317) — attach them manually if you use uploads."
180
+ : "";
181
+ const message = `${staged} file${staged === 1 ? "" : "s"} staged for branch '${branch}' on uploads.sh ` +
182
+ `${staged === 1 ? "isn't" : "aren't"} attached to a pull request yet. Once this PR opens, run ` +
183
+ "`uploads attach --promote --pr <num>` (or a bare `uploads attach --promote`, which infers " +
184
+ `the PR from the branch) to collect ${staged === 1 ? "it" : "them"} into the managed attachments comment.${forkNote}`;
185
+ return formatAdvisory(message, isCursorHookInput(raw));
186
+ }
161
187
  const testFiles = deps.testFiles ?? process.env.UPLOADS_HOOK_TEST_FILES;
162
188
  const changed = testFiles ? testFiles.split("\n").filter(Boolean) : git.changedFiles();
163
189
  if (!anyVisual(changed))
164
190
  return null;
165
- const staged = await (deps.countStaged ?? defaultCountStaged)(branch);
166
- // null = error/unconfigured → fail open; >0 = already staged
167
- if (staged === null || staged > 0)
168
- return null;
169
191
  const fork = (deps.isFork ?? (() => defaultIsFork(cwd)))();
170
192
  const forkNote = fork === true
171
193
  ? " Note: this looks like a fork branch, so staged screenshots won't auto-promote into the PR comment yet (see issue #317) — attach them manually if you use uploads."
@@ -2,7 +2,7 @@ import { readFileSync, writeFileSync } from "node:fs";
2
2
  import { basename } from "node:path";
3
3
  import { extractDashValue, flagBool, flagInt, flagString, flagValues, parseCommandArgs, UsageError, } from "../cli-args.js";
4
4
  import { writeCommandHelp } from "../cli-style.js";
5
- import { branchFromFlags, derivedMetaEnabled, frameOptionsFromFlags, ghTargetFromFlags, optimizeOptionsFromFlags, stateAppMetaFromFlags, warnNearMissMeta, syncAttachmentsComment, commentViaSuffix, uploadPreparedImage, resolvePutStagingTarget, putStagingNoteText, resolveStageBindingWarning, mergeStagingMeta, writeReplacedNote, resolveGhPrefixSafe, } from "../commands.js";
5
+ import { branchFromFlags, derivedMetaEnabled, frameOptionsFromFlags, ghTargetFromFlags, optimizeOptionsFromFlags, stateAppMetaFromFlags, warnNearMissMeta, syncAttachmentsComment, commentViaSuffix, uploadPreparedImage, resolvePutStagingTarget, putStagingNoteText, resolveStageBindingWarning, mergeStagingMeta, writeReplacedNote, resolveGhPrefixSafe, resolveAutoPrTarget, resolvePutNudgeContext, putNudgeText, autoPrNoteText, } from "../commands.js";
6
6
  import { resolvePutDefaults } from "../config.js";
7
7
  import { loadDefaultsRaw, resolveScreenshotDefaults } from "../config-file.js";
8
8
  import { resolvePutPrefix } from "../destinations.js";
@@ -44,9 +44,18 @@ sets the whole object key verbatim (no folding).
44
44
  After capture, screenshots share the put upload pipeline: optional --frame,
45
45
  optimize-by-default, --pr/--issue attachment + --comment, --gallery, --meta.
46
46
 
47
- Branch staging by default (pre-PR): with no --pr/--issue/--branch/--key/--ref/
48
- --prefix/--destination, a screenshot taken on a non-default git branch stages
49
- under gh/<owner>/<repo>/branch/<branch>/<name> instead of the dated
47
+ Auto-PR context (issue #700): with no --pr/--issue/--branch/--key/--ref/
48
+ --prefix/--destination, a screenshot taken on a branch that maps to exactly
49
+ one open PR behaves as if --pr <n> had been passed — stable gh/ key, managed
50
+ comment sync (with --comment) — instead of branch staging below. A one-line
51
+ note announces this. Opt out with --no-pr, UPLOADS_NO_AUTO_PR=1, or config
52
+ UPLOADS_NO_AUTO_PR=1; never fires outside a git repo, on the default branch,
53
+ with --no-git, or when no single open PR can be resolved.
54
+
55
+ Branch staging by default (pre-PR): when auto-PR above doesn't apply and none
56
+ of --pr/--issue/--branch/--key/--ref/--prefix/--destination is given, a
57
+ screenshot taken on a non-default git branch stages under
58
+ gh/<owner>/<repo>/branch/<branch>/<name> instead of the dated
50
59
  screenshots/<repo>/<date>/... layout — same key/metadata as an explicit
51
60
  --branch, carrying every derived fact (path/url/env/viewport, --state) along.
52
61
  Staged files auto-attach with full metadata the first time you attach to that
@@ -102,6 +111,7 @@ Options:
102
111
  --optimize-max-edge <px> Max long edge when optimizing (default: 2400)
103
112
  --optimize-quality <1-100> WebP quality (default: 85)
104
113
  --keep-exif Keep EXIF/XMP/ICC when optimizing
114
+ --no-pr Skip auto-PR context (or UPLOADS_NO_AUTO_PR=1) — see above
105
115
  --pr <num> Attach to a pull request (stable URL, no hash)
106
116
  --issue <num> Attach to an issue
107
117
  --branch [name] Stage against a branch, pre-PR (default: current git branch):
@@ -320,7 +330,32 @@ loadAnnotateModule = () => import("../annotate/index.js")) {
320
330
  }
321
331
  const putDefaults = resolvePutDefaults({ envFile: ctx.envFile }, rawDefaults);
322
332
  const noGit = flagBool(parsed.flags, "--no-git") || putDefaults.noGit === true;
333
+ if (parsed.flags.has("--no-pr") && typeof parsed.flags.get("--no-pr") === "string") {
334
+ throw new UsageError("--no-pr takes no value");
335
+ }
336
+ const noAutoPr = flagBool(parsed.flags, "--no-pr") || putDefaults.noAutoPr === true;
323
337
  const branchRepo = branchArg !== undefined ? resolveRepo(flagString(parsed.flags, "--repo"), run) : undefined;
338
+ // Auto-PR context (issue #700): when no --branch/--pr/--issue/--key/--ref/
339
+ // --prefix/--destination is given, git use isn't disabled, and --no-pr/
340
+ // UPLOADS_NO_AUTO_PR hasn't opted out, a screenshot taken on a branch that
341
+ // maps to exactly one open PR behaves as if --pr <n> had been passed —
342
+ // stable key + managed comment sync — instead of the #469 auto-staging
343
+ // default below. Mirrors put's #700 handling exactly (resolveAutoPrTarget).
344
+ const autoPrTarget = ghTarget || branchArg !== undefined
345
+ ? undefined
346
+ : resolveAutoPrTarget({
347
+ ghTarget,
348
+ keyHint,
349
+ refArg: flagString(parsed.flags, "--ref"),
350
+ prefixArg: prefixFlag,
351
+ destinationArg: destFlag,
352
+ branchArg,
353
+ noGit,
354
+ noAutoPr,
355
+ repoArg: flagString(parsed.flags, "--repo") ?? putDefaults.repo,
356
+ run,
357
+ });
358
+ const effectiveGhTarget = ghTarget ?? autoPrTarget;
324
359
  // Auto branch staging (issue #469 lever 1): mirrors bare `put`'s auto-staging
325
360
  // (issue #403). When no --branch/--pr/--issue/--key/--ref/--prefix/--destination
326
361
  // is given and git use isn't disabled, a screenshot taken on a non-default
@@ -329,10 +364,11 @@ loadAnnotateModule = () => import("../annotate/index.js")) {
329
364
  // `screenshots/<repo>/<date>/...` layout. This is what lets derived
330
365
  // metadata (path/url/env/viewport, --state) ride through to PR-open
331
366
  // promotion when the capture happens before the PR exists. Skipped
332
- // entirely when --branch was given explicitly (already handled above).
367
+ // entirely when --branch was given explicitly (already handled above), or
368
+ // when the #700 auto-PR match above already took over.
333
369
  const autoStagingTarget = branchArg === undefined
334
370
  ? resolvePutStagingTarget({
335
- ghTarget,
371
+ ghTarget: effectiveGhTarget,
336
372
  keyHint,
337
373
  refArg: flagString(parsed.flags, "--ref"),
338
374
  prefixArg: prefixFlag,
@@ -349,7 +385,7 @@ loadAnnotateModule = () => import("../annotate/index.js")) {
349
385
  destination: destFlag,
350
386
  prefix: prefixFlag,
351
387
  key: keyHint,
352
- ghAttachment: Boolean(ghTarget) || stagingTarget !== undefined,
388
+ ghAttachment: Boolean(effectiveGhTarget) || stagingTarget !== undefined,
353
389
  });
354
390
  }
355
391
  catch (err) {
@@ -379,8 +415,8 @@ loadAnnotateModule = () => import("../annotate/index.js")) {
379
415
  ...(repoSlug ? { repo: repoSlug } : {}),
380
416
  });
381
417
  let metadata = withFacts;
382
- if (ghTarget) {
383
- metadata = { ...withFacts, ...ghMetadataFromTargetWithTitle(ghTarget, run) };
418
+ if (effectiveGhTarget) {
419
+ metadata = { ...withFacts, ...ghMetadataFromTargetWithTitle(effectiveGhTarget, run) };
384
420
  validateMetaMap(metadata);
385
421
  }
386
422
  else if (stagingTarget !== undefined) {
@@ -475,10 +511,10 @@ loadAnnotateModule = () => import("../annotate/index.js")) {
475
511
  // Resolved once (issue #631), only when it's actually needed for the
476
512
  // upload about to happen (never for the noUpload/no-target bailouts
477
513
  // above) — never per file (screenshot only ever uploads one).
478
- const ghPrefix = ghTarget
514
+ const ghPrefix = effectiveGhTarget
479
515
  ? await resolveGhPrefixSafe(ctx.client, {
480
- repo: ghTarget.repo,
481
- target: { kind: ghTarget.kind, num: ghTarget.num },
516
+ repo: effectiveGhTarget.repo,
517
+ target: { kind: effectiveGhTarget.kind, num: effectiveGhTarget.num },
482
518
  })
483
519
  : stagingTarget !== undefined
484
520
  ? await resolveGhPrefixSafe(ctx.client, {
@@ -486,11 +522,29 @@ loadAnnotateModule = () => import("../annotate/index.js")) {
486
522
  branch: stagingTarget.branch,
487
523
  })
488
524
  : undefined;
525
+ // Bare-screenshot nudge context (issue #393/#700): only relevant when
526
+ // neither auto-PR nor staging took over — mirrors put's handling exactly.
527
+ // Resolved before upload; finished into text below once the key is known.
528
+ const nudgeContext = effectiveGhTarget || stagingTarget
529
+ ? undefined
530
+ : resolvePutNudgeContext({
531
+ quiet: ctx.quiet,
532
+ noNudge: putDefaults.noNudge === true,
533
+ ghTarget,
534
+ keyHint,
535
+ hasBranchFlag: branchArg !== undefined,
536
+ noGit,
537
+ repoArg: flagString(parsed.flags, "--repo") ?? putDefaults.repo,
538
+ run,
539
+ });
540
+ const autoPrNote = autoPrTarget && !ctx.quiet && !putDefaults.noNudge
541
+ ? autoPrNoteText(autoPrTarget.num)
542
+ : undefined;
489
543
  const alt = altFlag ?? basename(captured.filename);
490
544
  const { result, prepared, markdown } = await uploadPreparedImage(ctx.client, finalPng, captured.filename, {
491
545
  frame: frameOpts,
492
546
  optimize: optimizeOpts,
493
- ghTarget,
547
+ ghTarget: effectiveGhTarget,
494
548
  ghBranchTarget: stagingTarget,
495
549
  ghPrefix,
496
550
  key: keyHint,
@@ -532,11 +586,16 @@ loadAnnotateModule = () => import("../annotate/index.js")) {
532
586
  gallery = { id: galleryId, error: err instanceof Error ? err.message : String(err) };
533
587
  }
534
588
  }
589
+ // Concrete bare-screenshot nudge text (issue #700): built once the upload
590
+ // key exists, so the ready-made follow-up names it verbatim.
591
+ const nudge = nudgeContext
592
+ ? putNudgeText(nudgeContext.branch, nudgeContext.pr, [result.key])
593
+ : undefined;
535
594
  let comment;
536
595
  let commentError;
537
- if (wantComment && ghTarget) {
596
+ if (wantComment && effectiveGhTarget) {
538
597
  try {
539
- comment = await syncAttachmentsComment(ctx.client, ghTarget, run, ctx.config.workspace);
598
+ comment = await syncAttachmentsComment(ctx.client, effectiveGhTarget, run, ctx.config.workspace);
540
599
  if (logHuman)
541
600
  process.stderr.write(`>> attachments comment ${comment.action}${commentViaSuffix(comment.via)}\n`);
542
601
  }
@@ -564,6 +623,10 @@ loadAnnotateModule = () => import("../annotate/index.js")) {
564
623
  `(or run \`uploads attach --promote\` after opening)\n`);
565
624
  }
566
625
  }
626
+ if (autoPrNote)
627
+ process.stderr.write(`${autoPrNote}\n`);
628
+ if (nudge)
629
+ process.stderr.write(`${nudge}\n`);
567
630
  if (bindingWarning)
568
631
  process.stderr.write(`${bindingWarning}\n`);
569
632
  if (contextNudge)
@@ -573,16 +636,23 @@ loadAnnotateModule = () => import("../annotate/index.js")) {
573
636
  // One JSON `hint` slot (mirrors bare put): the clip note (issue #652) wins
574
637
  // first — it's about the just-captured image itself, more immediately
575
638
  // actionable than the other three, which are about upload/staging
576
- // mechanics. Then the binding warning, more actionable than the generic
577
- // staging note; a replaced-object note (issue #618) is lowest priority
578
- // it only surfaces when nothing else already claimed the slot. Since state
579
- // folds into the derived key, replaced + state means a same-side re-capture,
639
+ // mechanics. Then the auto-PR note and the #393/#700 nudge (issue #700),
640
+ // then the binding warning, more actionable than the generic staging note;
641
+ // a replaced-object note (issue #618) is lowest priority it only
642
+ // surfaces when nothing else already claimed the slot. Since state folds
643
+ // into the derived key, replaced + state means a same-side re-capture,
580
644
  // which is the intended replace-in-place flow — word it as informational,
581
645
  // not as a problem.
582
646
  const replacedHint = result.replaced && explicitMeta.state
583
647
  ? `re-capture replaced the previous state=${explicitMeta.state} object at ${result.key} — expected for repeat captures of the same URL + state`
584
648
  : undefined;
585
- const jsonHint = clipHint ?? bindingWarning ?? stagingNote ?? replacedHint ?? contextNudge;
649
+ const jsonHint = clipHint ??
650
+ autoPrNote ??
651
+ nudge ??
652
+ bindingWarning ??
653
+ stagingNote ??
654
+ replacedHint ??
655
+ contextNudge;
586
656
  switch (format) {
587
657
  case "json":
588
658
  await writeJson({
@@ -411,6 +411,82 @@ export declare function resolveStageBindingWarning(opts: {
411
411
  defaults: PutDefaults;
412
412
  repo: string;
413
413
  }): Promise<string | undefined>;
414
+ /**
415
+ * The bare-put nudge's wording (issue #393, made concrete by issue #700):
416
+ * teaches `--pr`/`attach --branch` as an upgrade from a targetless `put`.
417
+ * `pr` present → names the PR and, once upload `keys` are known, appends a
418
+ * ready-made follow-up command naming them verbatim (e.g. `uploads attach
419
+ * --pr 1250 f/abc123.webp`); otherwise a generic variant that still points
420
+ * at `--pr <num>`. Used verbatim for both the human-mode stderr line and the
421
+ * JSON `hint` field.
422
+ */
423
+ export declare function putNudgeText(branch: string, pr: number | undefined, keys?: string[]): string;
424
+ /**
425
+ * Auto-PR note (issue #700): announces at the moment it fires that a bare
426
+ * put/screenshot on this branch was auto-attached to `pr` — the default
427
+ * behavior change this issue introduces — and how to opt out.
428
+ */
429
+ export declare function autoPrNoteText(pr: number): string;
430
+ /**
431
+ * Best-effort bare-put/screenshot nudge context (issue #393): resolves the
432
+ * branch and, when detectable, the open PR for it — fires only when there is
433
+ * no targeting flag at all (`--pr`/`--issue`/`--key`; `--branch` too, though
434
+ * `put` doesn't currently accept it — defensive parity with `attach`), is
435
+ * inside a git repo (reusing `deriveRepoFromGit`, the same detection the
436
+ * default screenshot key's repo segment uses), and the current branch isn't
437
+ * the default one. Never throws — any failure (not a repo, detached HEAD,
438
+ * `gh` missing/unauthenticated/timed out) degrades to "no nudge" or, once a
439
+ * branch is already known, to a context with `pr: undefined` (the generic
440
+ * no-PR wording). Must never affect put's exit code, stdout, or upload
441
+ * behavior. Callers turn the result into text via `putNudgeText`, once any
442
+ * upload keys are known.
443
+ */
444
+ export declare function resolvePutNudgeContext(opts: {
445
+ quiet: boolean;
446
+ noNudge: boolean;
447
+ ghTarget: GhTarget | undefined;
448
+ keyHint: string | undefined;
449
+ /** True when an explicit `--branch`-style flag was given (CLI `attach`
450
+ * parity; `put`/MCP `put` don't accept one — pass false there). */
451
+ hasBranchFlag?: boolean;
452
+ noGit: boolean;
453
+ repoArg: string | undefined;
454
+ run: CommandRunner;
455
+ }): {
456
+ branch: string;
457
+ pr: number | undefined;
458
+ } | undefined;
459
+ /**
460
+ * Auto-PR context (issue #700): when a bare put/screenshot has no explicit
461
+ * destination flag at all (`--pr`/`--issue`/`--key`/`--ref`/`--prefix`/
462
+ * `--destination`, and for `screenshot` no explicit `--branch`) and runs on a
463
+ * branch that maps to exactly one open PR, this resolves that PR so the
464
+ * caller can behave as if `--pr <n>` had been passed — stable key + managed
465
+ * comment sync — instead of the #403/#469 staging default or the plain dated
466
+ * layout. `resolveCurrentPullRequest`'s `gh pr view <branch>` lookup is
467
+ * already the unambiguous case: it names the single open PR whose head is
468
+ * that branch, or fails (no open PR, or `gh` unavailable/unauthenticated) —
469
+ * there is no "ambiguous, more than one" state to further disambiguate.
470
+ * Opt-out: `noAutoPr` (the caller folds in `--no-pr` and
471
+ * `UPLOADS_NO_AUTO_PR=1`/config). Never fires outside a git checkout, on the
472
+ * default branch, or with `--no-git`; any failure (not a repo, detached
473
+ * HEAD, gh missing/unauthenticated/timed out, no open PR) degrades to
474
+ * undefined so the caller falls back to its normal staging/dated behavior.
475
+ */
476
+ export declare function resolveAutoPrTarget(opts: {
477
+ ghTarget: GhTarget | undefined;
478
+ keyHint: string | undefined;
479
+ refArg: string | undefined;
480
+ prefixArg: string | undefined;
481
+ destinationArg: string | undefined;
482
+ /** Explicit `--branch` (screenshot only) also opts out — put has no
483
+ * `--branch` flag today, so callers pass undefined there. */
484
+ branchArg?: string | undefined;
485
+ noGit: boolean;
486
+ noAutoPr: boolean;
487
+ repoArg: string | undefined;
488
+ run: CommandRunner;
489
+ }): GhTarget | undefined;
414
490
  /**
415
491
  * Bare-put branch-staging trigger (issue #403): put on a non-default git
416
492
  * branch stages to the branch prefix by default — the branch becomes the