@buildinternet/uploads 0.14.0 → 0.16.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/README.md +11 -0
- package/dist/cli-catalog.js +10 -0
- package/dist/cli.js +6 -2
- package/dist/client.d.ts +89 -2
- package/dist/client.js +49 -0
- package/dist/commands/screenshot.js +34 -5
- package/dist/commands.d.ts +55 -1
- package/dist/commands.js +507 -22
- package/dist/github-gh.d.ts +9 -1
- package/dist/github-gh.js +35 -3
- package/dist/github.d.ts +35 -1
- package/dist/github.js +88 -7
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/mcp/tools.js +11 -11
- package/package.json +1 -1
package/dist/github-gh.d.ts
CHANGED
|
@@ -9,6 +9,8 @@ export declare const execRunner: CommandRunner;
|
|
|
9
9
|
export declare function resolveRepo(explicit: string | undefined, run?: CommandRunner): string;
|
|
10
10
|
/** Resolve the pull request associated with the current branch. */
|
|
11
11
|
export declare function resolveCurrentPullRequest(repo: string, run?: CommandRunner): GhTarget;
|
|
12
|
+
/** Resolve the current git branch (`--branch` with no value). Throws UsageError on detached HEAD or outside a git repo. */
|
|
13
|
+
export declare function resolveCurrentBranch(run?: CommandRunner): string;
|
|
12
14
|
/**
|
|
13
15
|
* Classify a bare PR/issue number via the GitHub API so the default `put`
|
|
14
16
|
* path can stamp the right `gh.kind`. Returns undefined on any failure (gh
|
|
@@ -39,7 +41,13 @@ export declare function ghMetadataFromTargetWithTitle(target: GhTarget, run?: Co
|
|
|
39
41
|
* Create the managed attachments comment, or edit it in place if it already
|
|
40
42
|
* exists. Never touches any other comment. Body is passed via stdin
|
|
41
43
|
* (`-F body=@-`) so it is never shell-interpolated.
|
|
44
|
+
*
|
|
45
|
+
* `marker` identifies which comment to hunt for (see `findManagedComment`);
|
|
46
|
+
* `body` is expected to already carry that same marker as its first line
|
|
47
|
+
* (built via `attachmentsCommentBody(items, galleries, marker)`), so patching
|
|
48
|
+
* an adopted legacy comment migrates it to the namespaced marker in place.
|
|
49
|
+
* Defaults to the shared legacy marker for backward compatibility.
|
|
42
50
|
*/
|
|
43
|
-
export declare function upsertAttachmentsComment(target: GhTarget, body: string, run?: CommandRunner): {
|
|
51
|
+
export declare function upsertAttachmentsComment(target: GhTarget, body: string, run?: CommandRunner, marker?: string): {
|
|
44
52
|
created: boolean;
|
|
45
53
|
};
|
package/dist/github-gh.js
CHANGED
|
@@ -68,6 +68,20 @@ export function resolveCurrentPullRequest(repo, run = execRunner) {
|
|
|
68
68
|
}
|
|
69
69
|
throw new UsageError("could not infer a pull request for the current branch — pass --pr <num> or --issue <num>");
|
|
70
70
|
}
|
|
71
|
+
/** Resolve the current git branch (`--branch` with no value). Throws UsageError on detached HEAD or outside a git repo. */
|
|
72
|
+
export function resolveCurrentBranch(run = execRunner) {
|
|
73
|
+
let branch;
|
|
74
|
+
try {
|
|
75
|
+
branch = run("git", ["rev-parse", "--abbrev-ref", "HEAD"]).trim();
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
throw new UsageError("could not determine the current git branch — pass --branch <name> or run inside a git repo");
|
|
79
|
+
}
|
|
80
|
+
if (branch === "" || branch === "HEAD") {
|
|
81
|
+
throw new UsageError("could not determine the current branch (detached HEAD) — pass --branch <name>");
|
|
82
|
+
}
|
|
83
|
+
return branch;
|
|
84
|
+
}
|
|
71
85
|
/**
|
|
72
86
|
* Classify a bare PR/issue number via the GitHub API so the default `put`
|
|
73
87
|
* path can stamp the right `gh.kind`. Returns undefined on any failure (gh
|
|
@@ -141,23 +155,41 @@ export function ghMetadataFromTargetWithTitle(target, run = execRunner) {
|
|
|
141
155
|
* PR comments live on the issues endpoint, so one path covers PRs and issues.
|
|
142
156
|
* `--paginate` follows Link headers and merges every page into one array, so the
|
|
143
157
|
* marker comment is found even on threads past 100 comments.
|
|
158
|
+
*
|
|
159
|
+
* Hunts for `marker` (the namespaced, per-workspace marker) first; when none
|
|
160
|
+
* is found, falls back to a comment carrying the shared legacy
|
|
161
|
+
* `ATTACHMENTS_MARKER` (pre-4b, unnamespaced) so it can be adopted and
|
|
162
|
+
* migrated in place. When `marker` IS the legacy marker (no workspace to
|
|
163
|
+
* namespace with) this collapses to a single hunt, unchanged from pre-4b
|
|
164
|
+
* behavior.
|
|
144
165
|
*/
|
|
145
|
-
function findManagedComment(target, run) {
|
|
166
|
+
function findManagedComment(target, run, marker) {
|
|
146
167
|
const raw = run("gh", [
|
|
147
168
|
"api",
|
|
148
169
|
`repos/${target.repo}/issues/${target.num}/comments?per_page=100`,
|
|
149
170
|
"--paginate",
|
|
150
171
|
]);
|
|
151
172
|
const comments = JSON.parse(raw);
|
|
173
|
+
const namespacedHit = comments.find((c) => typeof c.body === "string" && c.body.includes(marker));
|
|
174
|
+
if (namespacedHit)
|
|
175
|
+
return namespacedHit;
|
|
176
|
+
if (marker === ATTACHMENTS_MARKER)
|
|
177
|
+
return undefined;
|
|
152
178
|
return comments.find((c) => typeof c.body === "string" && c.body.includes(ATTACHMENTS_MARKER));
|
|
153
179
|
}
|
|
154
180
|
/**
|
|
155
181
|
* Create the managed attachments comment, or edit it in place if it already
|
|
156
182
|
* exists. Never touches any other comment. Body is passed via stdin
|
|
157
183
|
* (`-F body=@-`) so it is never shell-interpolated.
|
|
184
|
+
*
|
|
185
|
+
* `marker` identifies which comment to hunt for (see `findManagedComment`);
|
|
186
|
+
* `body` is expected to already carry that same marker as its first line
|
|
187
|
+
* (built via `attachmentsCommentBody(items, galleries, marker)`), so patching
|
|
188
|
+
* an adopted legacy comment migrates it to the namespaced marker in place.
|
|
189
|
+
* Defaults to the shared legacy marker for backward compatibility.
|
|
158
190
|
*/
|
|
159
|
-
export function upsertAttachmentsComment(target, body, run = execRunner) {
|
|
160
|
-
const existing = findManagedComment(target, run);
|
|
191
|
+
export function upsertAttachmentsComment(target, body, run = execRunner, marker = ATTACHMENTS_MARKER) {
|
|
192
|
+
const existing = findManagedComment(target, run, marker);
|
|
161
193
|
if (existing) {
|
|
162
194
|
run("gh", [
|
|
163
195
|
"api",
|
package/dist/github.d.ts
CHANGED
|
@@ -22,6 +22,26 @@ export declare function ghKeyPrefix(target: GhTarget): string;
|
|
|
22
22
|
* (unlike buildScreenshotKey).
|
|
23
23
|
*/
|
|
24
24
|
export declare function ghAttachmentKey(target: GhTarget, filename: string): string;
|
|
25
|
+
/**
|
|
26
|
+
* Branch-staged attachment key prefix: `gh/<owner>/<repo>/branch/<branch>/`.
|
|
27
|
+
* Pre-PR staging (Phase 1 of branch-staged attachments) — no PR/issue number
|
|
28
|
+
* exists yet. `branch` goes through `sanitizeKeySegment` like every other key
|
|
29
|
+
* segment, so e.g. `feature/x` becomes `feature-x`.
|
|
30
|
+
*/
|
|
31
|
+
export declare function ghBranchKeyPrefix(repo: string, branch: string): string;
|
|
32
|
+
/** Branch-staged attachment key: `ghBranchKeyPrefix` + the sanitized filename. */
|
|
33
|
+
export declare function ghBranchAttachmentKey(repo: string, branch: string, filename: string): string;
|
|
34
|
+
/**
|
|
35
|
+
* `gh.*` metadata for a branch-staged attach: `gh.repo`, `gh.kind=branch`,
|
|
36
|
+
* `gh.branch` (lowercased), and `gh.staged-at` (ISO 8601 UTC, no fractional
|
|
37
|
+
* seconds). No `gh.number`/`gh.ref`/`gh.title` — there is no PR/issue yet.
|
|
38
|
+
* Throws `UsageError` when the lowercased branch name fails the metadata
|
|
39
|
+
* value rule (printable ASCII, 1-512 chars) — unlike `gh.title`'s best-effort
|
|
40
|
+
* degrade, a branch name the caller explicitly chose (via `--branch` or the
|
|
41
|
+
* current git branch) is worth failing loudly on rather than silently
|
|
42
|
+
* dropping from the metadata set.
|
|
43
|
+
*/
|
|
44
|
+
export declare function ghMetadataForBranch(repo: string, branch: string, now?: Date): Record<string, string>;
|
|
25
45
|
/**
|
|
26
46
|
* The four `gh.*` queryable-metadata pairs `uploads attach` writes
|
|
27
47
|
* automatically (`.context/2026-07-13-file-metadata-design.md`). `gh.kind`
|
|
@@ -36,11 +56,25 @@ export declare function ghAttachmentKey(target: GhTarget, filename: string): str
|
|
|
36
56
|
export declare function ghMetadataFromTarget(target: GhTarget): Record<string, string>;
|
|
37
57
|
/** Hidden marker identifying the one comment this CLI manages. Never change it — existing comments are found by exact match. */
|
|
38
58
|
export declare const ATTACHMENTS_MARKER = "<!-- uploads.sh:attachments -->";
|
|
59
|
+
/**
|
|
60
|
+
* Per-workspace marker (`<!-- uploads.sh:attachments ws=<workspace> -->`) so
|
|
61
|
+
* two workspaces managing the same repo don't clobber each other's comment.
|
|
62
|
+
* Falls back to the shared legacy marker when `workspace` is missing or does
|
|
63
|
+
* not look like a safe slug — degrade, don't guess or risk breaking the
|
|
64
|
+
* comment's HTML.
|
|
65
|
+
*/
|
|
66
|
+
export declare function attachmentsMarker(workspace?: string): string;
|
|
67
|
+
/** Max attachments embedded as inline `<img>` tags before the rest collapse
|
|
68
|
+
* into a `<details>` link list. Keeps very large threads from becoming a wall
|
|
69
|
+
* of images. */
|
|
70
|
+
export declare const MAX_INLINE_ATTACHMENT_IMAGES = 16;
|
|
39
71
|
export interface AttachmentItem {
|
|
40
72
|
key: string;
|
|
41
73
|
url: string | null;
|
|
42
74
|
/** Prefer for `<img src>` on GitHub (Camo-friendly host). Falls back to `url`. */
|
|
43
75
|
embedUrl?: string | null;
|
|
76
|
+
/** Canonical `/f/` file-page URL (server-computed). Preferred click-through target; falls back to `url`. */
|
|
77
|
+
pageUrl?: string | null;
|
|
44
78
|
}
|
|
45
79
|
/** A public gallery linked to the PR or issue whose managed comment is syncing. */
|
|
46
80
|
export interface GalleryCommentItem {
|
|
@@ -70,4 +104,4 @@ export declare function attachmentImageWidth(filename: string): number;
|
|
|
70
104
|
* Render the one marker-owned GitHub comment. When there are no galleries this
|
|
71
105
|
* intentionally preserves the legacy attachment-only body byte-for-byte.
|
|
72
106
|
*/
|
|
73
|
-
export declare function attachmentsCommentBody(items: AttachmentItem[], galleries?: GalleryCommentItem[]): string;
|
|
107
|
+
export declare function attachmentsCommentBody(items: AttachmentItem[], galleries?: GalleryCommentItem[], marker?: string): string;
|
package/dist/github.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { inferContentType } from "./embed.js";
|
|
2
2
|
import { sanitizeKeySegment } from "./keys.js";
|
|
3
|
+
import { UsageError } from "./cli-args.js";
|
|
4
|
+
import { isMetaValueSafe } from "./metadata.js";
|
|
3
5
|
const REPO_RE = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/;
|
|
4
6
|
export function isValidRepo(repo) {
|
|
5
7
|
return REPO_RE.test(repo);
|
|
@@ -63,6 +65,42 @@ export function ghKeyPrefix(target) {
|
|
|
63
65
|
export function ghAttachmentKey(target, filename) {
|
|
64
66
|
return `${ghKeyPrefix(target)}${sanitizeKeySegment(filename)}`;
|
|
65
67
|
}
|
|
68
|
+
/**
|
|
69
|
+
* Branch-staged attachment key prefix: `gh/<owner>/<repo>/branch/<branch>/`.
|
|
70
|
+
* Pre-PR staging (Phase 1 of branch-staged attachments) — no PR/issue number
|
|
71
|
+
* exists yet. `branch` goes through `sanitizeKeySegment` like every other key
|
|
72
|
+
* segment, so e.g. `feature/x` becomes `feature-x`.
|
|
73
|
+
*/
|
|
74
|
+
export function ghBranchKeyPrefix(repo, branch) {
|
|
75
|
+
const [owner, name] = repo.split("/");
|
|
76
|
+
return `gh/${sanitizeKeySegment(owner)}/${sanitizeKeySegment(name)}/branch/${sanitizeKeySegment(branch)}/`;
|
|
77
|
+
}
|
|
78
|
+
/** Branch-staged attachment key: `ghBranchKeyPrefix` + the sanitized filename. */
|
|
79
|
+
export function ghBranchAttachmentKey(repo, branch, filename) {
|
|
80
|
+
return `${ghBranchKeyPrefix(repo, branch)}${sanitizeKeySegment(filename)}`;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* `gh.*` metadata for a branch-staged attach: `gh.repo`, `gh.kind=branch`,
|
|
84
|
+
* `gh.branch` (lowercased), and `gh.staged-at` (ISO 8601 UTC, no fractional
|
|
85
|
+
* seconds). No `gh.number`/`gh.ref`/`gh.title` — there is no PR/issue yet.
|
|
86
|
+
* Throws `UsageError` when the lowercased branch name fails the metadata
|
|
87
|
+
* value rule (printable ASCII, 1-512 chars) — unlike `gh.title`'s best-effort
|
|
88
|
+
* degrade, a branch name the caller explicitly chose (via `--branch` or the
|
|
89
|
+
* current git branch) is worth failing loudly on rather than silently
|
|
90
|
+
* dropping from the metadata set.
|
|
91
|
+
*/
|
|
92
|
+
export function ghMetadataForBranch(repo, branch, now = new Date()) {
|
|
93
|
+
const branchLower = branch.toLowerCase();
|
|
94
|
+
if (!isMetaValueSafe(branchLower)) {
|
|
95
|
+
throw new UsageError(`invalid --branch: "${branch}" must be printable ASCII to stage as gh.branch metadata`);
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
"gh.repo": repo.toLowerCase(),
|
|
99
|
+
"gh.kind": "branch",
|
|
100
|
+
"gh.branch": branchLower,
|
|
101
|
+
"gh.staged-at": now.toISOString().replace(/\.\d{3}Z$/, "Z"),
|
|
102
|
+
};
|
|
103
|
+
}
|
|
66
104
|
/**
|
|
67
105
|
* The four `gh.*` queryable-metadata pairs `uploads attach` writes
|
|
68
106
|
* automatically (`.context/2026-07-13-file-metadata-design.md`). `gh.kind`
|
|
@@ -85,6 +123,28 @@ export function ghMetadataFromTarget(target) {
|
|
|
85
123
|
}
|
|
86
124
|
/** Hidden marker identifying the one comment this CLI manages. Never change it — existing comments are found by exact match. */
|
|
87
125
|
export const ATTACHMENTS_MARKER = "<!-- uploads.sh:attachments -->";
|
|
126
|
+
/** Workspace slugs are `[a-z0-9-]`-ish; only markers built from a slug matching
|
|
127
|
+
* this are trusted as a distinct namespace — anything else (empty, unsafe
|
|
128
|
+
* chars) degrades to the shared legacy marker rather than emitting untrusted
|
|
129
|
+
* text into comment HTML. */
|
|
130
|
+
const WORKSPACE_SLUG_RE = /^[a-z0-9-]{1,64}$/;
|
|
131
|
+
/**
|
|
132
|
+
* Per-workspace marker (`<!-- uploads.sh:attachments ws=<workspace> -->`) so
|
|
133
|
+
* two workspaces managing the same repo don't clobber each other's comment.
|
|
134
|
+
* Falls back to the shared legacy marker when `workspace` is missing or does
|
|
135
|
+
* not look like a safe slug — degrade, don't guess or risk breaking the
|
|
136
|
+
* comment's HTML.
|
|
137
|
+
*/
|
|
138
|
+
export function attachmentsMarker(workspace) {
|
|
139
|
+
if (workspace && WORKSPACE_SLUG_RE.test(workspace)) {
|
|
140
|
+
return `<!-- uploads.sh:attachments ws=${workspace} -->`;
|
|
141
|
+
}
|
|
142
|
+
return ATTACHMENTS_MARKER;
|
|
143
|
+
}
|
|
144
|
+
/** Max attachments embedded as inline `<img>` tags before the rest collapse
|
|
145
|
+
* into a `<details>` link list. Keeps very large threads from becoming a wall
|
|
146
|
+
* of images. */
|
|
147
|
+
export const MAX_INLINE_ATTACHMENT_IMAGES = 16;
|
|
88
148
|
/** Default max width for images in the managed attachments comment (HTML img). */
|
|
89
149
|
export const ATTACHMENT_IMAGE_WIDTH_DEFAULT = 400;
|
|
90
150
|
/** Portrait / device mockups — keep phones readable, not full-column. */
|
|
@@ -116,10 +176,10 @@ function escapeHtmlText(s) {
|
|
|
116
176
|
* Render the one marker-owned GitHub comment. When there are no galleries this
|
|
117
177
|
* intentionally preserves the legacy attachment-only body byte-for-byte.
|
|
118
178
|
*/
|
|
119
|
-
export function attachmentsCommentBody(items, galleries = []) {
|
|
179
|
+
export function attachmentsCommentBody(items, galleries = [], marker = ATTACHMENTS_MARKER) {
|
|
120
180
|
const sorted = items.toSorted((a, b) => a.key.localeCompare(b.key));
|
|
121
181
|
const sortedGalleries = galleries.toSorted((a, b) => a.title.localeCompare(b.title) || a.url.localeCompare(b.url));
|
|
122
|
-
const lines = [
|
|
182
|
+
const lines = [marker];
|
|
123
183
|
if (sortedGalleries.length > 0) {
|
|
124
184
|
lines.push("### 🖼️ Galleries", "");
|
|
125
185
|
for (const gallery of sortedGalleries) {
|
|
@@ -136,27 +196,48 @@ export function attachmentsCommentBody(items, galleries = []) {
|
|
|
136
196
|
}
|
|
137
197
|
if (sorted.length > 0 || sortedGalleries.length === 0)
|
|
138
198
|
lines.push("### 📎 Attachments", "");
|
|
199
|
+
let inlinedImages = 0;
|
|
200
|
+
const overflowImages = [];
|
|
139
201
|
for (const item of sorted) {
|
|
140
202
|
const name = item.key.slice(item.key.lastIndexOf("/") + 1);
|
|
141
203
|
const stable = item.url;
|
|
142
204
|
const src = item.embedUrl ?? item.url;
|
|
143
|
-
|
|
205
|
+
const link = item.pageUrl ?? stable; // click-through: file page when known, else raw
|
|
206
|
+
const isImage = Boolean(src) && inferContentType(name).startsWith("image/");
|
|
207
|
+
if (isImage && inlinedImages >= MAX_INLINE_ATTACHMENT_IMAGES) {
|
|
208
|
+
// Cap hit — defer to the collapsed overflow list below rather than
|
|
209
|
+
// embedding every remaining image inline.
|
|
210
|
+
overflowImages.push(item);
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
if (isImage) {
|
|
214
|
+
inlinedImages++;
|
|
144
215
|
// Markdown ![]() has no width control — phone frames become full-column giants.
|
|
145
|
-
// img src uses embed host when available (Camo revalidates); click-through
|
|
216
|
+
// img src uses embed host when available (Camo revalidates); click-through prefers the file page.
|
|
146
217
|
const w = attachmentImageWidth(name);
|
|
147
218
|
const alt = escapeHtmlAttr(name);
|
|
148
|
-
const href = escapeHtmlAttr(
|
|
219
|
+
const href = escapeHtmlAttr(link ?? src);
|
|
149
220
|
const imgSrc = escapeHtmlAttr(src);
|
|
150
221
|
lines.push(`<a href="${href}"><img width="${w}" alt="${alt}" src="${imgSrc}"></a>`);
|
|
151
222
|
lines.push("");
|
|
152
223
|
}
|
|
153
|
-
else if (
|
|
154
|
-
lines.push(`- [${name}](${
|
|
224
|
+
else if (link) {
|
|
225
|
+
lines.push(`- [${name}](${link})`);
|
|
155
226
|
}
|
|
156
227
|
else {
|
|
157
228
|
lines.push(`- ${name}`);
|
|
158
229
|
}
|
|
159
230
|
}
|
|
231
|
+
if (overflowImages.length > 0) {
|
|
232
|
+
const n = overflowImages.length;
|
|
233
|
+
lines.push(`<details><summary>${n} more attachment${n === 1 ? "" : "s"}</summary>`, "");
|
|
234
|
+
for (const item of overflowImages) {
|
|
235
|
+
const name = item.key.slice(item.key.lastIndexOf("/") + 1);
|
|
236
|
+
const link = item.pageUrl ?? item.url;
|
|
237
|
+
lines.push(link ? `- [${name}](${link})` : `- ${name}`);
|
|
238
|
+
}
|
|
239
|
+
lines.push("", "</details>", "");
|
|
240
|
+
}
|
|
160
241
|
lines.push('<sub>Maintained by <a href="https://uploads.sh">uploads.sh</a> — re-uploading a file with the same name updates it everywhere it is embedded.</sub>');
|
|
161
242
|
return lines.join("\n");
|
|
162
243
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export { UploadsError, type UploadsErrorCode } from "./errors.js";
|
|
|
7
7
|
export { createUploadsClient, type UploadsClient, type PutOptions, type ProvenanceInput, type ListOptions, type PutResult, type ListItem, type ListResult, type HeadResult, type DeleteResult, type GalleryItem, type Gallery, type GallerySummary, type GalleryListOptions, type GalleryListResult, type CreateGalleryOptions, type AddGalleryItemOptions, type DeleteGalleryOptions, type HealthResult, type UsageResult, type ReconcileResult, type PurgeExpiredResult, type PurgeExpiredResponse, type FindFilesOptions, type FindFilesItem, type FindFilesResult, type GetMetadataResult, type PatchMetadataOptions, } from "./client.js";
|
|
8
8
|
export { buildCliProvenance } from "./provenance.js";
|
|
9
9
|
export { META_KEY_RE, META_VALUE_MAX, META_MAX_KEYS, META_MAX_TOTAL_BYTES, validateMetaEntry, parseMetaPair, parseMetaFlags, } from "./metadata.js";
|
|
10
|
-
export { ATTACHMENTS_MARKER, attachmentsCommentBody, ghAttachmentKey, ghKeyPrefix, ghMetadataFromTarget, isValidRepo, parseRepoFromRemoteUrl, type AttachmentItem, type GhTarget, type GhTargetKind, } from "./github.js";
|
|
10
|
+
export { ATTACHMENTS_MARKER, attachmentsCommentBody, ghAttachmentKey, ghKeyPrefix, ghMetadataFromTarget, ghBranchAttachmentKey, ghBranchKeyPrefix, ghMetadataForBranch, isValidRepo, parseRepoFromRemoteUrl, type AttachmentItem, type GhTarget, type GhTargetKind, } from "./github.js";
|
|
11
11
|
export { DEFAULT_OPTIMIZE_MAX_EDGE, DEFAULT_OPTIMIZE_QUALITY, optimizeImageForUpload, rewriteKeyExtension, withImageExtension, type OptimizeImageOptions, type OptimizeImageResult, type OptimizeOutputFormat, } from "./optimize.js";
|
|
12
12
|
export { FRAME_PRESETS, applyFrame, listFramePresets, resolveFrameId, type FrameFit, type FrameOptions, type FrameResult, } from "./frame.js";
|
|
13
13
|
export { execRunner, resolveRepo, upsertAttachmentsComment, type CommandRunner, } from "./github-gh.js";
|
package/dist/index.js
CHANGED
|
@@ -7,7 +7,7 @@ export { UploadsError } from "./errors.js";
|
|
|
7
7
|
export { createUploadsClient, } from "./client.js";
|
|
8
8
|
export { buildCliProvenance } from "./provenance.js";
|
|
9
9
|
export { META_KEY_RE, META_VALUE_MAX, META_MAX_KEYS, META_MAX_TOTAL_BYTES, validateMetaEntry, parseMetaPair, parseMetaFlags, } from "./metadata.js";
|
|
10
|
-
export { ATTACHMENTS_MARKER, attachmentsCommentBody, ghAttachmentKey, ghKeyPrefix, ghMetadataFromTarget, isValidRepo, parseRepoFromRemoteUrl, } from "./github.js";
|
|
10
|
+
export { ATTACHMENTS_MARKER, attachmentsCommentBody, ghAttachmentKey, ghKeyPrefix, ghMetadataFromTarget, ghBranchAttachmentKey, ghBranchKeyPrefix, ghMetadataForBranch, isValidRepo, parseRepoFromRemoteUrl, } from "./github.js";
|
|
11
11
|
export { DEFAULT_OPTIMIZE_MAX_EDGE, DEFAULT_OPTIMIZE_QUALITY, optimizeImageForUpload, rewriteKeyExtension, withImageExtension, } from "./optimize.js";
|
|
12
12
|
export { FRAME_PRESETS, applyFrame, listFramePresets, resolveFrameId, } from "./frame.js";
|
|
13
13
|
export { execRunner, resolveRepo, upsertAttachmentsComment, } from "./github-gh.js";
|
package/dist/mcp/tools.js
CHANGED
|
@@ -123,11 +123,11 @@ export function createUploadsMcpTools(opts) {
|
|
|
123
123
|
});
|
|
124
124
|
return { config, client: clientFactory(config) };
|
|
125
125
|
}
|
|
126
|
-
const syncComment = async (client, target) => {
|
|
126
|
+
const syncComment = async (client, target, workspace) => {
|
|
127
127
|
let comment;
|
|
128
128
|
let commentError;
|
|
129
129
|
try {
|
|
130
|
-
comment = await syncAttachmentsComment(client, target, run);
|
|
130
|
+
comment = await syncAttachmentsComment(client, target, run, workspace);
|
|
131
131
|
}
|
|
132
132
|
catch (err) {
|
|
133
133
|
// Uploads already succeeded; the comment is best-effort by design.
|
|
@@ -402,7 +402,7 @@ export function createUploadsMcpTools(opts) {
|
|
|
402
402
|
catch (err) {
|
|
403
403
|
usage(err instanceof Error ? err.message : String(err));
|
|
404
404
|
}
|
|
405
|
-
const { client } = clientFor(args);
|
|
405
|
+
const { config, client } = clientFor(args);
|
|
406
406
|
const defaults = resolvePutDefaults({ envFile: globals.envFile });
|
|
407
407
|
const frameOpts = mcpFrameOptions(args);
|
|
408
408
|
const optimizeOpts = mcpOptimizeOptions(args, defaults);
|
|
@@ -436,7 +436,7 @@ export function createUploadsMcpTools(opts) {
|
|
|
436
436
|
throw new ToolBatchError(batchFailureMessage(failures), { uploads, failures });
|
|
437
437
|
}
|
|
438
438
|
if (wantComment && target && uploads.length > 0) {
|
|
439
|
-
const { comment, commentError } = await syncComment(client, target);
|
|
439
|
+
const { comment, commentError } = await syncComment(client, target, config.workspace);
|
|
440
440
|
return { uploads, failures, comment, commentError };
|
|
441
441
|
}
|
|
442
442
|
return { uploads, failures };
|
|
@@ -469,7 +469,7 @@ export function createUploadsMcpTools(opts) {
|
|
|
469
469
|
filename: prepared.filename,
|
|
470
470
|
};
|
|
471
471
|
if (wantComment && target) {
|
|
472
|
-
const { comment, commentError } = await syncComment(client, target);
|
|
472
|
+
const { comment, commentError } = await syncComment(client, target, config.workspace);
|
|
473
473
|
return { ...result, markdown, optimize, frame: prepared.frame, comment, commentError };
|
|
474
474
|
}
|
|
475
475
|
return {
|
|
@@ -504,7 +504,7 @@ export function createUploadsMcpTools(opts) {
|
|
|
504
504
|
...(dryRun ? { dryRun: true } : {}),
|
|
505
505
|
};
|
|
506
506
|
if (wantComment && target) {
|
|
507
|
-
const { comment, commentError } = await syncComment(client, target);
|
|
507
|
+
const { comment, commentError } = await syncComment(client, target, config.workspace);
|
|
508
508
|
return { ...flat, comment, commentError };
|
|
509
509
|
}
|
|
510
510
|
return flat;
|
|
@@ -761,7 +761,7 @@ export function createUploadsMcpTools(opts) {
|
|
|
761
761
|
...(dryRun ? { dryRun: true } : {}),
|
|
762
762
|
};
|
|
763
763
|
if (wantComment && target) {
|
|
764
|
-
const { comment, commentError } = await syncComment(client, target);
|
|
764
|
+
const { comment, commentError } = await syncComment(client, target, config.workspace);
|
|
765
765
|
return { ...flat, comment, commentError };
|
|
766
766
|
}
|
|
767
767
|
return flat;
|
|
@@ -821,7 +821,7 @@ export function createUploadsMcpTools(opts) {
|
|
|
821
821
|
const explicitTarget = ghTargetFromArgs(args, run);
|
|
822
822
|
const target = explicitTarget ??
|
|
823
823
|
resolveCurrentPullRequest(resolveRepo(optString(args, "repo"), run), run);
|
|
824
|
-
const { client } = clientFor(args);
|
|
824
|
+
const { config, client } = clientFor(args);
|
|
825
825
|
const contentType = optString(args, "contentType");
|
|
826
826
|
const defaults = resolvePutDefaults({ envFile: globals.envFile });
|
|
827
827
|
const frameOpts = mcpFrameOptions(args);
|
|
@@ -856,7 +856,7 @@ export function createUploadsMcpTools(opts) {
|
|
|
856
856
|
}
|
|
857
857
|
if (optBool(args, "noComment"))
|
|
858
858
|
return { target, uploads, failures };
|
|
859
|
-
const { comment, commentError } = await syncComment(client, target);
|
|
859
|
+
const { comment, commentError } = await syncComment(client, target, config.workspace);
|
|
860
860
|
return { target, uploads, failures, comment, commentError };
|
|
861
861
|
},
|
|
862
862
|
},
|
|
@@ -1062,8 +1062,8 @@ export function createUploadsMcpTools(opts) {
|
|
|
1062
1062
|
const target = ghTargetFromArgs(args, run);
|
|
1063
1063
|
if (!target)
|
|
1064
1064
|
usage("comment requires pr or issue");
|
|
1065
|
-
const { client } = clientFor(args);
|
|
1066
|
-
const result = await syncAttachmentsComment(client, target, run);
|
|
1065
|
+
const { config, client } = clientFor(args);
|
|
1066
|
+
const result = await syncAttachmentsComment(client, target, run, config.workspace);
|
|
1067
1067
|
return { ...target, ...result };
|
|
1068
1068
|
},
|
|
1069
1069
|
},
|