paperclip-github-plugin 0.8.9 → 0.8.11

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/worker.js CHANGED
@@ -1,4 +1,5 @@
1
1
  // src/worker.ts
2
+ import { Buffer } from "node:buffer";
2
3
  import { realpathSync } from "node:fs";
3
4
  import { readFile } from "node:fs/promises";
4
5
  import { homedir } from "node:os";
@@ -532,6 +533,58 @@ var GITHUB_AGENT_TOOLS = [
532
533
  }
533
534
  }
534
535
  },
536
+ {
537
+ name: "upload_pull_request_asset",
538
+ displayName: "Upload Pull Request Asset",
539
+ description: "Upload a PR-visible asset such as an image, PDF, log, archive, or report to a non-merge artifact branch and return durable markdown that can be embedded in the PR body.",
540
+ parametersSchema: {
541
+ type: "object",
542
+ additionalProperties: false,
543
+ required: ["fileName"],
544
+ allOf: [pullRequestTargetSchema],
545
+ anyOf: [
546
+ { required: ["contentBase64"] },
547
+ { required: ["dataUrl"] }
548
+ ],
549
+ properties: {
550
+ repository: repositoryProperty,
551
+ pullRequestNumber: pullRequestNumberProperty,
552
+ paperclipIssueId: paperclipIssueIdProperty,
553
+ fileName: {
554
+ type: "string",
555
+ description: "Asset filename. The plugin sanitizes it and preserves a safe extension."
556
+ },
557
+ label: {
558
+ type: "string",
559
+ description: "Human-readable link text for the returned Markdown. Defaults to the sanitized filename."
560
+ },
561
+ alt: {
562
+ type: "string",
563
+ description: "Backward-compatible alias for label, useful as image alt text."
564
+ },
565
+ caption: {
566
+ type: "string",
567
+ description: "Optional human-facing caption returned with the uploaded asset metadata."
568
+ },
569
+ contentBase64: {
570
+ type: "string",
571
+ description: "Base64-encoded asset bytes. Assets are limited to 10 MiB."
572
+ },
573
+ dataUrl: {
574
+ type: "string",
575
+ description: "Alternative base64 data URL input such as data:application/pdf;base64,... or data:image/png;base64,... ."
576
+ },
577
+ mimeType: {
578
+ type: "string",
579
+ description: "Optional MIME type such as application/pdf or image/png. If omitted, the plugin infers common types from fileName and otherwise uses application/octet-stream."
580
+ },
581
+ artifactBranch: {
582
+ type: "string",
583
+ description: "Optional artifact branch name. Defaults to paperclip-artifacts-pr-<pullRequestNumber>."
584
+ }
585
+ }
586
+ }
587
+ },
535
588
  {
536
589
  name: "link_github_item",
537
590
  displayName: "Link GitHub Item",
@@ -637,6 +690,9 @@ var COMPANY_METRIC_API_ROUTE_URL_PATH = `/api/plugins/${GITHUB_SYNC_PLUGIN_ID}/a
637
690
  var ISSUE_LINK_API_ROUTE_KEY = "link-github-item";
638
691
  var ISSUE_LINK_API_ROUTE_PATH = "/issue-link";
639
692
  var ISSUE_LINK_API_ROUTE_URL_PATH = `/api/plugins/${GITHUB_SYNC_PLUGIN_ID}/api${ISSUE_LINK_API_ROUTE_PATH}`;
693
+ var PULL_REQUEST_ASSET_API_ROUTE_KEY = "upload-pull-request-asset";
694
+ var PULL_REQUEST_ASSET_API_ROUTE_PATH = "/pull-request-assets";
695
+ var PULL_REQUEST_ASSET_API_ROUTE_URL_PATH = `/api/plugins/${GITHUB_SYNC_PLUGIN_ID}/api${PULL_REQUEST_ASSET_API_ROUTE_PATH}`;
640
696
 
641
697
  // src/paperclip-health.ts
642
698
  function normalizeOptionalString(value) {
@@ -739,6 +795,40 @@ var AI_AUTHORED_MARKDOWN_FOOTER_PATTERN = /\n\n---\n###### ✨ This (?:comment|i
739
795
  var HIDDEN_GITHUB_IMPORT_MARKER_PREFIX = "<!-- paperclip-github-plugin-imported-from: ";
740
796
  var HIDDEN_GITHUB_IMPORT_MARKER_SUFFIX = " -->";
741
797
  var EMPTY_GITHUB_ISSUE_DESCRIPTION_PLACEHOLDER = "_No description provided on GitHub._";
798
+ var MAX_PULL_REQUEST_ASSET_BYTES = 10 * 1024 * 1024;
799
+ var DEFAULT_PULL_REQUEST_ASSET_MIME_TYPE = "application/octet-stream";
800
+ var PULL_REQUEST_ASSET_MIME_TYPE_BY_EXTENSION = {
801
+ png: "image/png",
802
+ jpg: "image/jpeg",
803
+ jpeg: "image/jpeg",
804
+ webp: "image/webp",
805
+ gif: "image/gif",
806
+ pdf: "application/pdf",
807
+ txt: "text/plain",
808
+ md: "text/markdown",
809
+ markdown: "text/markdown",
810
+ json: "application/json",
811
+ csv: "text/csv",
812
+ xml: "application/xml",
813
+ zip: "application/zip",
814
+ gz: "application/gzip",
815
+ tgz: "application/gzip"
816
+ };
817
+ var PULL_REQUEST_ASSET_EXTENSION_BY_MIME_TYPE = {
818
+ "image/png": "png",
819
+ "image/jpeg": "jpg",
820
+ "image/webp": "webp",
821
+ "image/gif": "gif",
822
+ "application/pdf": "pdf",
823
+ "text/plain": "txt",
824
+ "text/markdown": "md",
825
+ "application/json": "json",
826
+ "text/csv": "csv",
827
+ "application/xml": "xml",
828
+ "application/zip": "zip",
829
+ "application/gzip": "gz",
830
+ "application/octet-stream": "bin"
831
+ };
742
832
  var pluginRuntimeContext = null;
743
833
  function normalizeCompanyId(value) {
744
834
  return typeof value === "string" && value.trim() ? value.trim() : void 0;
@@ -5816,8 +5906,13 @@ function isGitHubPullRequestActionRequiredForSync(pullRequest) {
5816
5906
  function isGitHubPullRequestPendingExternalWaitForSync(pullRequest) {
5817
5907
  return pullRequest.ciState === "unfinished" && !pullRequest.hasUnresolvedReviewThreads && pullRequest.mergeability !== "conflicting" && (pullRequest.mergeStateStatus === "blocked" || pullRequest.mergeStateStatus === "unstable");
5818
5908
  }
5909
+ function isGitHubPullRequestBlockedMaintainerApprovalWaitForSync(pullRequest) {
5910
+ return pullRequest.ciState === "green" && !pullRequest.hasUnresolvedReviewThreads && pullRequest.mergeability !== "conflicting" && pullRequest.mergeStateStatus === "blocked" && (pullRequest.reviewDecision === "unknown" || pullRequest.reviewDecision === "review_required");
5911
+ }
5819
5912
  function shouldPreserveBlockedExternalPullRequestWait(params) {
5820
- return params.currentStatus === "blocked" && params.linkedPullRequests.length > 0 && params.linkedPullRequests.every((pullRequest) => isGitHubPullRequestPendingExternalWaitForSync(pullRequest));
5913
+ return params.currentStatus === "blocked" && params.linkedPullRequests.length > 0 && params.linkedPullRequests.every(
5914
+ (pullRequest) => isGitHubPullRequestPendingExternalWaitForSync(pullRequest) || isGitHubPullRequestBlockedMaintainerApprovalWaitForSync(pullRequest)
5915
+ );
5821
5916
  }
5822
5917
  function isGitHubPullRequestTransientUnknownMergeabilityWait(pullRequest) {
5823
5918
  return pullRequest.ciState === "green" && !pullRequest.hasUnresolvedReviewThreads && pullRequest.mergeability !== "conflicting" && pullRequest.mergeStateStatus === "unknown";
@@ -10003,6 +10098,187 @@ function buildToolSuccessResult(content, data) {
10003
10098
  data
10004
10099
  };
10005
10100
  }
10101
+ function normalizePullRequestAssetMimeType(value) {
10102
+ if (typeof value !== "string") {
10103
+ return void 0;
10104
+ }
10105
+ const normalized = value.trim().toLowerCase();
10106
+ if (!/^[a-z0-9][a-z0-9!#$&^_.+-]*\/[a-z0-9][a-z0-9!#$&^_.+-]*(?:;\s*[a-z0-9!#$&^_.+-]+=[a-z0-9!#$&^_.+-]+)*$/.test(normalized)) {
10107
+ return void 0;
10108
+ }
10109
+ return normalized.split(";", 1)[0];
10110
+ }
10111
+ function getPullRequestAssetMimeTypeFromFileName(fileName) {
10112
+ const extensionMatch = fileName.trim().toLowerCase().match(/\.([a-z0-9]+)$/);
10113
+ if (!extensionMatch) {
10114
+ return void 0;
10115
+ }
10116
+ return PULL_REQUEST_ASSET_MIME_TYPE_BY_EXTENSION[extensionMatch[1]];
10117
+ }
10118
+ function getPullRequestAssetExtension(fileName) {
10119
+ const extensionMatch = fileName.trim().toLowerCase().match(/\.([a-z0-9]+)$/);
10120
+ return extensionMatch?.[1];
10121
+ }
10122
+ function sanitizePullRequestAssetFileName(fileNameInput, mimeType) {
10123
+ const inferredExtension = PULL_REQUEST_ASSET_EXTENSION_BY_MIME_TYPE[mimeType] ?? "bin";
10124
+ const fallbackBaseName = `asset.${inferredExtension}`;
10125
+ const rawFileName = normalizeOptionalString2(fileNameInput) ?? fallbackBaseName;
10126
+ const lastSegment = rawFileName.split(/[\\/]+/).filter(Boolean).at(-1) ?? fallbackBaseName;
10127
+ const extension = getPullRequestAssetExtension(lastSegment) ?? inferredExtension;
10128
+ const withoutExtension = lastSegment.replace(/\.[A-Za-z0-9]+$/, "");
10129
+ const sanitizedBaseName = withoutExtension.normalize("NFKD").replace(/[^A-Za-z0-9._-]+/g, "-").replace(/[-_.]+$/g, "").replace(/^[-_.]+/g, "").slice(0, 80) || "asset";
10130
+ return `${sanitizedBaseName}.${extension}`;
10131
+ }
10132
+ function sanitizePullRequestAssetLabel(value, fallbackFileName) {
10133
+ const normalized = normalizeOptionalString2(value);
10134
+ return (normalized ?? fallbackFileName.replace(/[-_.]+/g, " ")).slice(0, 200);
10135
+ }
10136
+ function sanitizePullRequestAssetArtifactBranch(value, pullRequestNumber) {
10137
+ const normalized = normalizeOptionalString2(value);
10138
+ const candidate = normalized ?? `paperclip-artifacts-pr-${pullRequestNumber}`;
10139
+ const sanitized = candidate.replace(/[^A-Za-z0-9._/-]+/g, "-").replace(/\.\.+/g, ".").replace(/\/{2,}/g, "/").replace(/^[-/.]+|[-/.]+$/g, "");
10140
+ if (!sanitized || sanitized.includes("..") || sanitized.startsWith("/") || sanitized.endsWith(".lock")) {
10141
+ throw new Error("artifactBranch must be a safe Git branch name.");
10142
+ }
10143
+ return sanitized;
10144
+ }
10145
+ function decodePullRequestAssetContent(payload) {
10146
+ const dataUrl = normalizeOptionalString2(payload.dataUrl);
10147
+ let contentBase64 = normalizeOptionalString2(payload.contentBase64);
10148
+ let mimeType = normalizePullRequestAssetMimeType(payload.mimeType);
10149
+ if (dataUrl) {
10150
+ const match = dataUrl.match(/^data:([^;,]+(?:;[^,]+)?);base64,(.+)$/is);
10151
+ if (!match) {
10152
+ throw new Error("dataUrl must be a base64 data URL.");
10153
+ }
10154
+ const dataUrlMimeType = normalizePullRequestAssetMimeType(match[1]);
10155
+ if (!dataUrlMimeType) {
10156
+ throw new Error("dataUrl MIME type must be a valid MIME type such as image/png or application/pdf.");
10157
+ }
10158
+ mimeType = dataUrlMimeType;
10159
+ contentBase64 = match[2].replace(/\s+/g, "");
10160
+ }
10161
+ if (!contentBase64) {
10162
+ throw new Error("contentBase64 or dataUrl is required.");
10163
+ }
10164
+ mimeType = mimeType ?? getPullRequestAssetMimeTypeFromFileName(normalizeOptionalString2(payload.fileName) ?? "") ?? DEFAULT_PULL_REQUEST_ASSET_MIME_TYPE;
10165
+ const normalizedBase64 = contentBase64.replace(/\s+/g, "");
10166
+ if (!/^[A-Za-z0-9+/]*={0,2}$/.test(normalizedBase64) || normalizedBase64.length % 4 === 1) {
10167
+ throw new Error("Asset content must be valid base64.");
10168
+ }
10169
+ const bytes = Buffer.from(normalizedBase64, "base64");
10170
+ if (bytes.length === 0) {
10171
+ throw new Error("Asset content must not be empty.");
10172
+ }
10173
+ if (bytes.length > MAX_PULL_REQUEST_ASSET_BYTES) {
10174
+ throw new Error(`Asset content exceeds the ${MAX_PULL_REQUEST_ASSET_BYTES} byte limit.`);
10175
+ }
10176
+ return {
10177
+ bytes,
10178
+ mimeType
10179
+ };
10180
+ }
10181
+ function buildPullRequestAssetMarkdown(label, rawUrl, mimeType) {
10182
+ const normalizedLabel = label.replace(/[\]\n\r]/g, " ").trim();
10183
+ if (mimeType.startsWith("image/")) {
10184
+ return `![${normalizedLabel}](${rawUrl})`;
10185
+ }
10186
+ return `[${normalizedLabel}](${rawUrl})`;
10187
+ }
10188
+ async function uploadPullRequestAssetArtifact(params) {
10189
+ const { bytes, mimeType } = decodePullRequestAssetContent(params.payload);
10190
+ const fileName = sanitizePullRequestAssetFileName(params.payload.fileName, mimeType);
10191
+ const label = sanitizePullRequestAssetLabel(params.payload.label ?? params.payload.alt, fileName);
10192
+ const caption = normalizeOptionalString2(params.payload.caption);
10193
+ const artifactBranch = sanitizePullRequestAssetArtifactBranch(params.payload.artifactBranch, params.pullRequestNumber);
10194
+ const pullRequestResponse = await params.octokit.rest.pulls.get({
10195
+ owner: params.repository.owner,
10196
+ repo: params.repository.repo,
10197
+ pull_number: params.pullRequestNumber,
10198
+ headers: {
10199
+ "X-GitHub-Api-Version": GITHUB_API_VERSION
10200
+ }
10201
+ });
10202
+ const headSha = pullRequestResponse.data.head.sha;
10203
+ const shortHeadSha = headSha.slice(0, 12);
10204
+ const contentPath = `assets/pr-${params.pullRequestNumber}/${shortHeadSha}/${fileName}`;
10205
+ let branchSha;
10206
+ try {
10207
+ const branchRefResponse = await params.octokit.rest.git.getRef({
10208
+ owner: params.repository.owner,
10209
+ repo: params.repository.repo,
10210
+ ref: `heads/${artifactBranch}`,
10211
+ headers: {
10212
+ "X-GitHub-Api-Version": GITHUB_API_VERSION
10213
+ }
10214
+ });
10215
+ branchSha = branchRefResponse.data.object.sha;
10216
+ } catch (error) {
10217
+ if (getErrorStatus(error) !== 404) {
10218
+ throw error;
10219
+ }
10220
+ }
10221
+ if (!branchSha) {
10222
+ await params.octokit.rest.git.createRef({
10223
+ owner: params.repository.owner,
10224
+ repo: params.repository.repo,
10225
+ ref: `refs/heads/${artifactBranch}`,
10226
+ sha: pullRequestResponse.data.base.sha,
10227
+ headers: {
10228
+ "X-GitHub-Api-Version": GITHUB_API_VERSION
10229
+ }
10230
+ });
10231
+ }
10232
+ let existingFileSha;
10233
+ try {
10234
+ const existingContentResponse = await params.octokit.rest.repos.getContent({
10235
+ owner: params.repository.owner,
10236
+ repo: params.repository.repo,
10237
+ path: contentPath,
10238
+ ref: artifactBranch,
10239
+ headers: {
10240
+ "X-GitHub-Api-Version": GITHUB_API_VERSION
10241
+ }
10242
+ });
10243
+ if (!Array.isArray(existingContentResponse.data) && existingContentResponse.data.type === "file") {
10244
+ existingFileSha = existingContentResponse.data.sha;
10245
+ }
10246
+ } catch (error) {
10247
+ if (getErrorStatus(error) !== 404) {
10248
+ throw error;
10249
+ }
10250
+ }
10251
+ const updateResponse = await params.octokit.rest.repos.createOrUpdateFileContents({
10252
+ owner: params.repository.owner,
10253
+ repo: params.repository.repo,
10254
+ path: contentPath,
10255
+ message: `Add asset for PR #${params.pullRequestNumber}`,
10256
+ content: bytes.toString("base64"),
10257
+ branch: artifactBranch,
10258
+ ...existingFileSha ? { sha: existingFileSha } : {},
10259
+ headers: {
10260
+ "X-GitHub-Api-Version": GITHUB_API_VERSION
10261
+ }
10262
+ });
10263
+ const commitSha = updateResponse.data.commit.sha;
10264
+ const rawUrl = `https://raw.githubusercontent.com/${params.repository.owner}/${params.repository.repo}/${commitSha}/${contentPath}`;
10265
+ const markdown = buildPullRequestAssetMarkdown(label, rawUrl, mimeType);
10266
+ return {
10267
+ repository: params.repository.url,
10268
+ pullRequestNumber: params.pullRequestNumber,
10269
+ artifactBranch,
10270
+ path: contentPath,
10271
+ fileName,
10272
+ mimeType,
10273
+ sizeBytes: bytes.length,
10274
+ commitSha,
10275
+ rawUrl,
10276
+ markdown,
10277
+ label,
10278
+ ...mimeType.startsWith("image/") ? { alt: label } : {},
10279
+ ...caption ? { caption } : {}
10280
+ };
10281
+ }
10006
10282
  function buildToolErrorResult(error) {
10007
10283
  const rateLimitPause = getGitHubRateLimitPauseDetails(error);
10008
10284
  if (rateLimitPause) {
@@ -10183,12 +10459,15 @@ async function handleCompanyMetricApiRoute(ctx, input) {
10183
10459
  }
10184
10460
  };
10185
10461
  }
10186
- function parseIssueLinkApiRouteBody(input) {
10462
+ function parsePluginApiRouteJsonObjectBody(input, routeLabel) {
10187
10463
  if (!input.body || typeof input.body !== "object" || Array.isArray(input.body)) {
10188
- throw new Error("Issue link route body must be a JSON object.");
10464
+ throw new Error(`${routeLabel} body must be a JSON object.`);
10189
10465
  }
10190
10466
  return input.body;
10191
10467
  }
10468
+ function parseIssueLinkApiRouteBody(input) {
10469
+ return parsePluginApiRouteJsonObjectBody(input, "Issue link route");
10470
+ }
10192
10471
  function normalizeIssueLinkApiRouteKind(payload) {
10193
10472
  const explicitKind = normalizeIssueGitHubLinkKind(payload.kind);
10194
10473
  if (explicitKind) {
@@ -10203,6 +10482,47 @@ function normalizeIssueLinkApiRouteKind(payload) {
10203
10482
  }
10204
10483
  return null;
10205
10484
  }
10485
+ async function handlePullRequestAssetApiRoute(ctx, input) {
10486
+ if (input.actor.actorType !== "agent") {
10487
+ throw new Error("Pull request assets must be uploaded by an authenticated Paperclip agent.");
10488
+ }
10489
+ const payload = parsePluginApiRouteJsonObjectBody(input, "Pull request asset route");
10490
+ const rawPullRequestUrl = normalizeOptionalString2(payload.pullRequestUrl);
10491
+ const pullRequestUrl = normalizeGitHubPullRequestHtmlUrl(rawPullRequestUrl);
10492
+ if (rawPullRequestUrl && !pullRequestUrl) {
10493
+ throw new Error("pullRequestUrl must be a valid GitHub pull request URL.");
10494
+ }
10495
+ const parsedPullRequestUrl = pullRequestUrl ? parseGitHubPullRequestHtmlUrl(pullRequestUrl) : void 0;
10496
+ const repositoryInput = normalizeOptionalString2(payload.repository) ?? parsedPullRequestUrl?.repositoryUrl;
10497
+ if (!repositoryInput) {
10498
+ throw new Error("repository is required unless pullRequestUrl is provided.");
10499
+ }
10500
+ const repository = requireRepositoryReference(repositoryInput);
10501
+ const pullRequestNumber = normalizeToolPositiveInteger(payload.pullRequestNumber) ?? parsedPullRequestUrl?.pullRequestNumber;
10502
+ if (!pullRequestNumber) {
10503
+ throw new Error("pullRequestNumber is required unless pullRequestUrl is provided.");
10504
+ }
10505
+ if (parsedPullRequestUrl && !areRepositoriesEqual(repository, requireRepositoryReference(parsedPullRequestUrl.repositoryUrl))) {
10506
+ throw new Error("repository must match pullRequestUrl.");
10507
+ }
10508
+ const octokit = await createGitHubToolOctokit(ctx, input.companyId, {
10509
+ toolName: PULL_REQUEST_ASSET_API_ROUTE_KEY,
10510
+ repositoryUrl: repository.url
10511
+ });
10512
+ const asset = await uploadPullRequestAssetArtifact({
10513
+ octokit,
10514
+ repository,
10515
+ pullRequestNumber,
10516
+ payload
10517
+ });
10518
+ return {
10519
+ status: 201,
10520
+ body: {
10521
+ status: "uploaded",
10522
+ asset
10523
+ }
10524
+ };
10525
+ }
10206
10526
  async function handleIssueLinkApiRoute(ctx, input) {
10207
10527
  if (input.actor.actorType !== "agent") {
10208
10528
  throw new Error("GitHub issue links must be recorded by an authenticated Paperclip agent.");
@@ -15085,6 +15405,27 @@ function registerGitHubAgentTools(ctx) {
15085
15405
  );
15086
15406
  })
15087
15407
  );
15408
+ ctx.tools.register(
15409
+ "upload_pull_request_asset",
15410
+ getGitHubAgentToolDeclaration("upload_pull_request_asset"),
15411
+ async (params, runCtx) => executeGitHubTool(async () => {
15412
+ const input = getToolInputRecord(params);
15413
+ const target = await resolveGitHubPullRequestToolTarget(ctx, runCtx, input);
15414
+ const octokit = await createAgentToolOctokit(runCtx, "upload_pull_request_asset", target.repository);
15415
+ const asset = await uploadPullRequestAssetArtifact({
15416
+ octokit,
15417
+ repository: target.repository,
15418
+ pullRequestNumber: target.pullRequestNumber,
15419
+ payload: input
15420
+ });
15421
+ return buildToolSuccessResult(
15422
+ `Uploaded asset ${asset.fileName} for pull request #${target.pullRequestNumber}.`,
15423
+ {
15424
+ asset
15425
+ }
15426
+ );
15427
+ })
15428
+ );
15088
15429
  ctx.tools.register(
15089
15430
  "link_github_item",
15090
15431
  getGitHubAgentToolDeclaration("link_github_item"),
@@ -15139,6 +15480,7 @@ var __testing = {
15139
15480
  formatPaperclipApiFetchErrorMessage,
15140
15481
  hasUnresolvedPaperclipIssueBlocker,
15141
15482
  isHealthyMaintainerWaitTransition,
15483
+ resolvePaperclipPullRequestIssueStatus,
15142
15484
  resolveSyncTransitionAssignee
15143
15485
  };
15144
15486
  var plugin = definePlugin({
@@ -15559,6 +15901,9 @@ var plugin = definePlugin({
15559
15901
  if (input.routeKey === ISSUE_LINK_API_ROUTE_KEY) {
15560
15902
  return handleIssueLinkApiRoute(pluginRuntimeContext, input);
15561
15903
  }
15904
+ if (input.routeKey === PULL_REQUEST_ASSET_API_ROUTE_KEY) {
15905
+ return handlePullRequestAssetApiRoute(pluginRuntimeContext, input);
15906
+ }
15562
15907
  return {
15563
15908
  status: 404,
15564
15909
  body: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "paperclip-github-plugin",
3
- "version": "0.8.9",
3
+ "version": "0.8.11",
4
4
  "description": "Paperclip plugin for synchronizing GitHub issues into Paperclip projects.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -42,14 +42,14 @@
42
42
  "dependencies": {
43
43
  "@octokit/rest": "^22.0.1",
44
44
  "@paperclipai/plugin-sdk": "^2026.428.0",
45
- "react": "^19.2.5",
45
+ "react": "^19.2.6",
46
46
  "react-markdown": "^10.1.0",
47
47
  "rehype-raw": "^7.0.0",
48
48
  "rehype-sanitize": "^6.0.0",
49
49
  "remark-gfm": "^4.0.1"
50
50
  },
51
51
  "devDependencies": {
52
- "@types/node": "24.12.2",
52
+ "@types/node": "24.12.3",
53
53
  "@types/react": "19.2.14",
54
54
  "esbuild": "0.28.0",
55
55
  "playwright": "1.59.1",