@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 +35 -0
- package/dist/client.js +14 -0
- package/dist/commands/hook.d.ts +6 -2
- package/dist/commands/hook.js +31 -9
- package/dist/commands/screenshot.js +90 -20
- package/dist/commands.d.ts +76 -0
- package/dist/commands.js +378 -79
- package/dist/comment-config.generated.d.ts +3 -0
- package/dist/comment-config.generated.js +13 -0
- package/dist/comment-render.generated.d.ts +4 -1
- package/dist/comment-render.generated.js +15 -2
- package/dist/config-file.d.ts +4 -1
- package/dist/config-file.js +10 -0
- package/dist/github-gh.d.ts +27 -0
- package/dist/github-gh.js +66 -0
- package/dist/mcp/output-schemas.js +24 -1
- package/dist/mcp/tools.js +132 -27
- package/package.json +1 -1
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". */
|
package/dist/commands/hook.d.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `uploads hook pre-pr-screenshot` — agent PreToolUse / beforeShellExecution
|
|
3
|
-
* handler
|
|
4
|
-
* files
|
|
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
|
*/
|
package/dist/commands/hook.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `uploads hook pre-pr-screenshot` — agent PreToolUse / beforeShellExecution
|
|
3
|
-
* handler
|
|
4
|
-
* files
|
|
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
|
|
26
|
-
|
|
27
|
-
|
|
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
|
-
|
|
48
|
-
--prefix/--destination, a screenshot taken on a
|
|
49
|
-
|
|
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(
|
|
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 (
|
|
383
|
-
metadata = { ...withFacts, ...ghMetadataFromTargetWithTitle(
|
|
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 =
|
|
514
|
+
const ghPrefix = effectiveGhTarget
|
|
479
515
|
? await resolveGhPrefixSafe(ctx.client, {
|
|
480
|
-
repo:
|
|
481
|
-
target: { kind:
|
|
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 &&
|
|
596
|
+
if (wantComment && effectiveGhTarget) {
|
|
538
597
|
try {
|
|
539
|
-
comment = await syncAttachmentsComment(ctx.client,
|
|
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
|
|
577
|
-
//
|
|
578
|
-
//
|
|
579
|
-
//
|
|
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 ??
|
|
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({
|
package/dist/commands.d.ts
CHANGED
|
@@ -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
|