paperclip-github-plugin 0.4.0 → 0.4.1

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
@@ -2237,7 +2237,7 @@ async function hydrateRecoveredPaperclipIssueGitHubLink(ctx, issueId, fallbackLi
2237
2237
  }
2238
2238
  let octokit;
2239
2239
  try {
2240
- octokit = await createGitHubToolOctokit(ctx);
2240
+ octokit = await createGitHubToolOctokit(ctx, fallbackLink.companyId);
2241
2241
  } catch {
2242
2242
  return null;
2243
2243
  }
@@ -2412,8 +2412,8 @@ function extractGitHubLinksFromCommentBody(body) {
2412
2412
  async function buildToolbarSyncState(ctx, input) {
2413
2413
  const settings = await getActiveOrCurrentSyncState(ctx);
2414
2414
  const config = await getResolvedConfig(ctx);
2415
- const githubTokenConfigured = hasConfiguredGithubToken(settings, config);
2416
2415
  const companyId = typeof input.companyId === "string" && input.companyId.trim() ? input.companyId.trim() : void 0;
2416
+ const githubTokenConfigured = hasConfiguredGithubToken(settings, config, companyId);
2417
2417
  const entityId = typeof input.entityId === "string" && input.entityId.trim() ? input.entityId.trim() : void 0;
2418
2418
  const entityType = typeof input.entityType === "string" && input.entityType.trim() ? input.entityType.trim() : void 0;
2419
2419
  const savedMappingCount = companyId ? getSyncableMappingsForTarget(settings.mappings, {
@@ -2625,6 +2625,8 @@ function sanitizeSettingsForCurrentSetup(settings, setup) {
2625
2625
  }
2626
2626
  function getPublicSettings(settings) {
2627
2627
  const {
2628
+ githubTokenRefs: _githubTokenRefs,
2629
+ githubTokenLoginsByCompanyId: _githubTokenLoginsByCompanyId,
2628
2630
  githubTokenRef: _githubTokenRef,
2629
2631
  paperclipBoardApiTokenRefs: _paperclipBoardApiTokenRefs,
2630
2632
  paperclipBoardAccessIdentityByCompanyId: _paperclipBoardAccessIdentityByCompanyId,
@@ -2650,6 +2652,26 @@ function getPublicSettingsForScope(settings, companyId) {
2650
2652
  ...paperclipBoardAccessIdentity ? { paperclipBoardAccessIdentity } : {}
2651
2653
  };
2652
2654
  }
2655
+ function getSavedGitHubTokenRef(settings, companyId) {
2656
+ const normalizedCompanyId = normalizeCompanyId(companyId);
2657
+ if (normalizedCompanyId) {
2658
+ const scopedSecretRef = normalizeSecretRef(settings?.githubTokenRefs?.[normalizedCompanyId]);
2659
+ if (scopedSecretRef) {
2660
+ return scopedSecretRef;
2661
+ }
2662
+ }
2663
+ return normalizeGitHubTokenRef(settings?.githubTokenRef);
2664
+ }
2665
+ function getSavedGitHubTokenLogin(settings, companyId) {
2666
+ const normalizedCompanyId = normalizeCompanyId(companyId);
2667
+ if (normalizedCompanyId) {
2668
+ const scopedLogin = normalizeOptionalString2(settings?.githubTokenLoginsByCompanyId?.[normalizedCompanyId]);
2669
+ if (scopedLogin) {
2670
+ return scopedLogin;
2671
+ }
2672
+ }
2673
+ return normalizeOptionalString2(settings?.githubTokenLogin);
2674
+ }
2653
2675
  async function listAvailableAssignees(ctx, companyId) {
2654
2676
  try {
2655
2677
  const agents = await ctx.agents.list({
@@ -2953,11 +2975,13 @@ function normalizeConfig(value) {
2953
2975
  return {};
2954
2976
  }
2955
2977
  const record = value;
2978
+ const githubTokenRefs = normalizeGitHubTokenRefs(record.githubTokenRefs);
2956
2979
  const githubTokenRef = normalizeGitHubTokenRef(record.githubTokenRef);
2957
2980
  const githubToken = normalizeGitHubToken(record.githubToken);
2958
2981
  const paperclipBoardApiTokenRefs = normalizePaperclipBoardApiTokenRefs(record.paperclipBoardApiTokenRefs);
2959
2982
  const paperclipApiBaseUrl = normalizePaperclipApiBaseUrl(record.paperclipApiBaseUrl);
2960
2983
  return {
2984
+ ...githubTokenRefs ? { githubTokenRefs } : {},
2961
2985
  ...githubTokenRef ? { githubTokenRef } : {},
2962
2986
  ...githubToken ? { githubToken } : {},
2963
2987
  ...paperclipBoardApiTokenRefs ? { paperclipBoardApiTokenRefs } : {},
@@ -3036,6 +3060,12 @@ async function readExternalConfig(ctx) {
3036
3060
  }
3037
3061
  }
3038
3062
  function normalizePaperclipBoardApiTokenRefs(value) {
3063
+ return normalizeCompanySecretRefs(value);
3064
+ }
3065
+ function normalizeGitHubTokenRefs(value) {
3066
+ return normalizeCompanySecretRefs(value);
3067
+ }
3068
+ function normalizeCompanySecretRefs(value) {
3039
3069
  if (!value || typeof value !== "object") {
3040
3070
  return void 0;
3041
3071
  }
@@ -3049,6 +3079,20 @@ function normalizePaperclipBoardApiTokenRefs(value) {
3049
3079
  }
3050
3080
  return Object.fromEntries(entries);
3051
3081
  }
3082
+ function normalizeGitHubTokenLoginsByCompanyId(value) {
3083
+ if (!value || typeof value !== "object") {
3084
+ return void 0;
3085
+ }
3086
+ const entries = Object.entries(value).map(([companyId, login]) => {
3087
+ const normalizedCompanyId = normalizeCompanyId(companyId);
3088
+ const normalizedLogin = normalizeOptionalString2(login);
3089
+ return normalizedCompanyId && normalizedLogin ? [normalizedCompanyId, normalizedLogin] : null;
3090
+ }).filter((entry) => entry !== null);
3091
+ if (entries.length === 0) {
3092
+ return void 0;
3093
+ }
3094
+ return Object.fromEntries(entries);
3095
+ }
3052
3096
  function normalizePaperclipBoardAccessIdentityByCompanyId(value) {
3053
3097
  if (!value || typeof value !== "object") {
3054
3098
  return void 0;
@@ -3267,6 +3311,8 @@ function normalizeSettings(value) {
3267
3311
  }
3268
3312
  const record = value;
3269
3313
  const paperclipApiBaseUrl = resolvePaperclipApiBaseUrl(record.paperclipApiBaseUrl);
3314
+ const githubTokenRefs = normalizeGitHubTokenRefs(record.githubTokenRefs);
3315
+ const githubTokenLoginsByCompanyId = normalizeGitHubTokenLoginsByCompanyId(record.githubTokenLoginsByCompanyId);
3270
3316
  const githubTokenRef = normalizeGitHubTokenRef(record.githubTokenRef);
3271
3317
  const githubTokenLogin = normalizeOptionalString2(record.githubTokenLogin);
3272
3318
  const paperclipBoardApiTokenRefs = normalizePaperclipBoardApiTokenRefs(record.paperclipBoardApiTokenRefs);
@@ -3279,6 +3325,8 @@ function normalizeSettings(value) {
3279
3325
  syncState: normalizeSyncState(record.syncState),
3280
3326
  scheduleFrequencyMinutes: normalizeScheduleFrequencyMinutes(record.scheduleFrequencyMinutes),
3281
3327
  ...paperclipApiBaseUrl ? { paperclipApiBaseUrl } : {},
3328
+ ...githubTokenRefs ? { githubTokenRefs } : {},
3329
+ ...githubTokenLoginsByCompanyId ? { githubTokenLoginsByCompanyId } : {},
3282
3330
  ...githubTokenRef ? { githubTokenRef } : {},
3283
3331
  ...githubTokenLogin ? { githubTokenLogin } : {},
3284
3332
  ...paperclipBoardApiTokenRefs ? { paperclipBoardApiTokenRefs } : {},
@@ -6173,19 +6221,20 @@ async function getResolvedConfig(ctx) {
6173
6221
  ...normalizeConfig(savedConfig)
6174
6222
  };
6175
6223
  }
6176
- function getConfiguredGithubTokenSource(settings, config) {
6177
- const secretRef = normalizeGitHubTokenRef(config.githubTokenRef) ?? normalizeGitHubTokenRef(settings?.githubTokenRef);
6224
+ function getConfiguredGithubTokenSource(settings, config, companyId) {
6225
+ const normalizedCompanyId = normalizeCompanyId(companyId);
6226
+ const secretRef = (normalizedCompanyId ? normalizeSecretRef(config.githubTokenRefs?.[normalizedCompanyId]) ?? getSavedGitHubTokenRef(settings, normalizedCompanyId) : void 0) ?? normalizeGitHubTokenRef(config.githubTokenRef) ?? getSavedGitHubTokenRef(settings);
6178
6227
  if (secretRef) {
6179
6228
  return { secretRef };
6180
6229
  }
6181
6230
  const token = normalizeGitHubToken(config.githubToken);
6182
6231
  return token ? { token } : {};
6183
6232
  }
6184
- function getConfiguredGithubTokenRef(settings, config) {
6185
- return getConfiguredGithubTokenSource(settings, config).secretRef;
6233
+ function getConfiguredGithubTokenRef(settings, config, companyId) {
6234
+ return getConfiguredGithubTokenSource(settings, config, companyId).secretRef;
6186
6235
  }
6187
- function hasConfiguredGithubToken(settings, config) {
6188
- const configuredTokenSource = getConfiguredGithubTokenSource(settings, config);
6236
+ function hasConfiguredGithubToken(settings, config, companyId) {
6237
+ const configuredTokenSource = getConfiguredGithubTokenSource(settings, config, companyId);
6189
6238
  return Boolean(configuredTokenSource.secretRef ?? configuredTokenSource.token);
6190
6239
  }
6191
6240
  function getSavedPaperclipBoardApiTokenRef(settings, companyId) {
@@ -6269,7 +6318,7 @@ async function resolvePaperclipApiAuthTokens(ctx, settings, config, mappings) {
6269
6318
  async function resolveGithubToken(ctx, options = {}) {
6270
6319
  const settings = options.settings ?? normalizeSettings(await ctx.state.get(SETTINGS_SCOPE));
6271
6320
  const config = options.config ?? await getResolvedConfig(ctx);
6272
- const configuredTokenSource = getConfiguredGithubTokenSource(settings, config);
6321
+ const configuredTokenSource = getConfiguredGithubTokenSource(settings, config, options.companyId);
6273
6322
  if (configuredTokenSource.secretRef) {
6274
6323
  return ctx.secrets.resolve(configuredTokenSource.secretRef);
6275
6324
  }
@@ -6347,8 +6396,8 @@ async function executeGitHubTool(fn) {
6347
6396
  return buildToolErrorResult(error);
6348
6397
  }
6349
6398
  }
6350
- async function createGitHubToolOctokit(ctx) {
6351
- const token = (await resolveGithubToken(ctx)).trim();
6399
+ async function createGitHubToolOctokit(ctx, companyId) {
6400
+ const token = (await resolveGithubToken(ctx, { companyId })).trim();
6352
6401
  if (!token) {
6353
6402
  throw new Error(MISSING_GITHUB_TOKEN_SYNC_MESSAGE);
6354
6403
  }
@@ -7770,7 +7819,7 @@ async function getOrLoadCachedProjectPullRequestMetricsEntry(ctx, scope, octokit
7770
7819
  return inFlightMetrics;
7771
7820
  }
7772
7821
  const loadMetricsPromise = (async () => {
7773
- const resolvedOctokit = octokit ?? await createGitHubToolOctokit(ctx);
7822
+ const resolvedOctokit = octokit ?? await createGitHubToolOctokit(ctx, scope.companyId);
7774
7823
  const metrics = await listProjectPullRequestMetrics(resolvedOctokit, scope);
7775
7824
  return cacheProjectPullRequestMetricsEntry(scope, metrics);
7776
7825
  })();
@@ -7808,7 +7857,7 @@ async function getOrLoadCachedProjectPullRequestCount(ctx, scope, octokit) {
7808
7857
  return inFlightCount;
7809
7858
  }
7810
7859
  const loadCountPromise = (async () => {
7811
- const resolvedOctokit = octokit ?? await createGitHubToolOctokit(ctx);
7860
+ const resolvedOctokit = octokit ?? await createGitHubToolOctokit(ctx, scope.companyId);
7812
7861
  const totalOpenPullRequests = await listProjectPullRequestCount(resolvedOctokit, scope);
7813
7862
  return setCacheValue(
7814
7863
  activeProjectPullRequestCountCache,
@@ -7920,7 +7969,7 @@ async function getOrLoadProjectPullRequestSummaryRecordsForNumbers(ctx, scope, p
7920
7969
  }
7921
7970
  const missingPullRequestNumbers = normalizedPullRequestNumbers.filter((pullRequestNumber) => !recordsByNumber.has(pullRequestNumber));
7922
7971
  if (missingPullRequestNumbers.length > 0) {
7923
- const resolvedOctokit = octokit ?? await createGitHubToolOctokit(ctx);
7972
+ const resolvedOctokit = octokit ?? await createGitHubToolOctokit(ctx, scope.companyId);
7924
7973
  const loadedRecords = await listProjectPullRequestSummaryRecordsByNumbers(
7925
7974
  ctx,
7926
7975
  resolvedOctokit,
@@ -8030,7 +8079,7 @@ async function buildProjectPullRequestsPageData(ctx, input) {
8030
8079
  }
8031
8080
  const scope = await requireProjectPullRequestScope(ctx, input, projectMappings);
8032
8081
  const config = await getResolvedConfig(ctx);
8033
- if (!hasConfiguredGithubToken(settings, config)) {
8082
+ if (!hasConfiguredGithubToken(settings, config, companyId)) {
8034
8083
  return {
8035
8084
  status: "missing_token",
8036
8085
  projectId,
@@ -8049,7 +8098,7 @@ async function buildProjectPullRequestsPageData(ctx, input) {
8049
8098
  };
8050
8099
  }
8051
8100
  try {
8052
- const octokit = await createGitHubToolOctokit(ctx);
8101
+ const octokit = await createGitHubToolOctokit(ctx, companyId);
8053
8102
  const pageCacheKey = buildProjectPullRequestPageCacheKey(scope, filter, pageIndex, cursor);
8054
8103
  const cachedPage = getFreshCacheValue(activeProjectPullRequestPageCache, pageCacheKey);
8055
8104
  if (cachedPage) {
@@ -8221,7 +8270,7 @@ async function buildProjectPullRequestMetricsData(ctx, input) {
8221
8270
  };
8222
8271
  }
8223
8272
  const config = await getResolvedConfig(ctx);
8224
- if (!hasConfiguredGithubToken(settings, config)) {
8273
+ if (!hasConfiguredGithubToken(settings, config, companyId)) {
8225
8274
  return {
8226
8275
  status: "missing_token",
8227
8276
  projectId,
@@ -8270,7 +8319,7 @@ async function buildProjectPullRequestCountData(ctx, input) {
8270
8319
  };
8271
8320
  }
8272
8321
  const config = await getResolvedConfig(ctx);
8273
- if (!hasConfiguredGithubToken(settings, config)) {
8322
+ if (!hasConfiguredGithubToken(settings, config, companyId)) {
8274
8323
  return {
8275
8324
  status: "missing_token",
8276
8325
  projectId,
@@ -8307,7 +8356,7 @@ async function buildSettingsTokenPermissionAuditData(ctx, input) {
8307
8356
  }
8308
8357
  const settings = normalizeSettings(await ctx.state.get(SETTINGS_SCOPE));
8309
8358
  const config = await getResolvedConfig(ctx);
8310
- if (!hasConfiguredGithubToken(settings, config)) {
8359
+ if (!hasConfiguredGithubToken(settings, config, requestedCompanyId)) {
8311
8360
  return {
8312
8361
  status: "missing_token",
8313
8362
  allRequiredPermissionsGranted: false,
@@ -8328,7 +8377,7 @@ async function buildSettingsTokenPermissionAuditData(ctx, input) {
8328
8377
  };
8329
8378
  }
8330
8379
  try {
8331
- const octokit = await createGitHubToolOctokit(ctx);
8380
+ const octokit = await createGitHubToolOctokit(ctx, requestedCompanyId);
8332
8381
  const repositories = await Promise.all(
8333
8382
  [
8334
8383
  ...new Map(
@@ -8397,7 +8446,7 @@ async function buildProjectPullRequestDetailData(ctx, input) {
8397
8446
  buildProjectPullRequestSummaryRecordCacheKey(scope, pullRequestNumber)
8398
8447
  );
8399
8448
  const cachedLinkedIssue = cachedSummaryRecord ? getLinkedPaperclipIssueFromProjectPullRequestRecord(cachedSummaryRecord) : void 0;
8400
- const octokit = await createGitHubToolOctokit(ctx);
8449
+ const octokit = await createGitHubToolOctokit(ctx, scope.companyId);
8401
8450
  const response = await octokit.rest.pulls.get({
8402
8451
  owner: scope.repository.owner,
8403
8452
  repo: scope.repository.repo,
@@ -8528,7 +8577,7 @@ async function createProjectPullRequestPaperclipIssue(ctx, input) {
8528
8577
  throw new Error("This Paperclip runtime does not expose plugin issue creation yet.");
8529
8578
  }
8530
8579
  const scope = await requireProjectPullRequestScope(ctx, input);
8531
- const octokit = await createGitHubToolOctokit(ctx);
8580
+ const octokit = await createGitHubToolOctokit(ctx, scope.companyId);
8532
8581
  const pullRequestResponse = await octokit.rest.pulls.get({
8533
8582
  owner: scope.repository.owner,
8534
8583
  repo: scope.repository.repo,
@@ -8602,7 +8651,7 @@ async function updateProjectPullRequestBranch(ctx, input) {
8602
8651
  throw new Error("pullRequestNumber is required.");
8603
8652
  }
8604
8653
  const scope = await requireProjectPullRequestScope(ctx, input);
8605
- const octokit = await createGitHubToolOctokit(ctx);
8654
+ const octokit = await createGitHubToolOctokit(ctx, scope.companyId);
8606
8655
  const pullRequestResponse = await octokit.rest.pulls.get({
8607
8656
  owner: scope.repository.owner,
8608
8657
  repo: scope.repository.repo,
@@ -8665,7 +8714,7 @@ async function mergeProjectPullRequest(ctx, input) {
8665
8714
  throw new Error("pullRequestNumber is required.");
8666
8715
  }
8667
8716
  const scope = await requireProjectPullRequestScope(ctx, input);
8668
- const octokit = await createGitHubToolOctokit(ctx);
8717
+ const octokit = await createGitHubToolOctokit(ctx, scope.companyId);
8669
8718
  const response = await octokit.rest.pulls.merge({
8670
8719
  owner: scope.repository.owner,
8671
8720
  repo: scope.repository.repo,
@@ -8689,7 +8738,7 @@ async function closeProjectPullRequest(ctx, input) {
8689
8738
  throw new Error("pullRequestNumber is required.");
8690
8739
  }
8691
8740
  const scope = await requireProjectPullRequestScope(ctx, input);
8692
- const octokit = await createGitHubToolOctokit(ctx);
8741
+ const octokit = await createGitHubToolOctokit(ctx, scope.companyId);
8693
8742
  const response = await octokit.rest.pulls.update({
8694
8743
  owner: scope.repository.owner,
8695
8744
  repo: scope.repository.repo,
@@ -8718,7 +8767,7 @@ async function addProjectPullRequestComment(ctx, input) {
8718
8767
  throw new Error("Comment body cannot be empty.");
8719
8768
  }
8720
8769
  const scope = await requireProjectPullRequestScope(ctx, input);
8721
- const octokit = await createGitHubToolOctokit(ctx);
8770
+ const octokit = await createGitHubToolOctokit(ctx, scope.companyId);
8722
8771
  const response = await createProjectPullRequestGitHubComment(octokit, scope, pullRequestNumber, body);
8723
8772
  invalidateProjectPullRequestCaches(scope);
8724
8773
  return {
@@ -8775,7 +8824,7 @@ async function requestProjectPullRequestCopilotAction(ctx, input) {
8775
8824
  throw new Error('action must be one of "fix_ci", "rebase", "address_review_feedback", or "review".');
8776
8825
  }
8777
8826
  const scope = await requireProjectPullRequestScope(ctx, input);
8778
- const octokit = await createGitHubToolOctokit(ctx);
8827
+ const octokit = await createGitHubToolOctokit(ctx, scope.companyId);
8779
8828
  const pullRequestResponse = await octokit.rest.pulls.get({
8780
8829
  owner: scope.repository.owner,
8781
8830
  repo: scope.repository.repo,
@@ -8889,7 +8938,7 @@ async function reviewProjectPullRequest(ctx, input) {
8889
8938
  }
8890
8939
  const body = typeof input.body === "string" ? input.body.trim() : "";
8891
8940
  const scope = await requireProjectPullRequestScope(ctx, input);
8892
- const octokit = await createGitHubToolOctokit(ctx);
8941
+ const octokit = await createGitHubToolOctokit(ctx, scope.companyId);
8893
8942
  let response;
8894
8943
  try {
8895
8944
  response = await octokit.rest.pulls.createReview({
@@ -8936,7 +8985,7 @@ async function rerunProjectPullRequestCi(ctx, input) {
8936
8985
  throw new Error("pullRequestNumber is required.");
8937
8986
  }
8938
8987
  const scope = await requireProjectPullRequestScope(ctx, input);
8939
- const octokit = await createGitHubToolOctokit(ctx);
8988
+ const octokit = await createGitHubToolOctokit(ctx, scope.companyId);
8940
8989
  const pullRequestResponse = await octokit.rest.pulls.get({
8941
8990
  owner: scope.repository.owner,
8942
8991
  repo: scope.repository.repo,
@@ -9672,9 +9721,11 @@ async function startSync(ctx, trigger, options = {}) {
9672
9721
  getResolvedConfig(ctx),
9673
9722
  ctx.state.get(SETTINGS_SCOPE).then((value) => normalizeSettings(value))
9674
9723
  ]);
9724
+ const targetCompanyId = options.target?.companyId;
9675
9725
  const token = await resolveGithubToken(ctx, {
9676
9726
  config,
9677
- settings: persistedSettings
9727
+ settings: persistedSettings,
9728
+ companyId: targetCompanyId
9678
9729
  }).catch(() => "");
9679
9730
  let currentSettings = sanitizeSettingsForCurrentSetup(persistedSettings, {
9680
9731
  hasToken: Boolean(token.trim()),
@@ -9763,7 +9814,7 @@ function registerGitHubAgentTools(ctx) {
9763
9814
  getGitHubAgentToolDeclaration("search_repository_items"),
9764
9815
  async (params, runCtx) => executeGitHubTool(async () => {
9765
9816
  const input = getToolInputRecord(params);
9766
- const octokit = await createGitHubToolOctokit(ctx);
9817
+ const octokit = await createGitHubToolOctokit(ctx, runCtx.companyId);
9767
9818
  const repository = await resolveGitHubToolRepository(ctx, runCtx, input);
9768
9819
  const rawQuery = normalizeOptionalToolString(input.query);
9769
9820
  if (!rawQuery) {
@@ -9832,7 +9883,7 @@ function registerGitHubAgentTools(ctx) {
9832
9883
  async (params, runCtx) => executeGitHubTool(async () => {
9833
9884
  const input = getToolInputRecord(params);
9834
9885
  const target = await resolveGitHubIssueToolTarget(ctx, runCtx, input);
9835
- const octokit = await createGitHubToolOctokit(ctx);
9886
+ const octokit = await createGitHubToolOctokit(ctx, runCtx.companyId);
9836
9887
  const response = await octokit.rest.issues.get({
9837
9888
  owner: target.repository.owner,
9838
9889
  repo: target.repository.repo,
@@ -9879,7 +9930,7 @@ function registerGitHubAgentTools(ctx) {
9879
9930
  async (params, runCtx) => executeGitHubTool(async () => {
9880
9931
  const input = getToolInputRecord(params);
9881
9932
  const target = await resolveGitHubIssueToolTarget(ctx, runCtx, input);
9882
- const octokit = await createGitHubToolOctokit(ctx);
9933
+ const octokit = await createGitHubToolOctokit(ctx, runCtx.companyId);
9883
9934
  const comments = await listAllGitHubIssueComments(octokit, target.repository, target.issueNumber);
9884
9935
  return buildToolSuccessResult(
9885
9936
  `Loaded ${comments.length} GitHub ${comments.length === 1 ? "comment" : "comments"} from issue #${target.issueNumber}.`,
@@ -9897,7 +9948,7 @@ function registerGitHubAgentTools(ctx) {
9897
9948
  async (params, runCtx) => executeGitHubTool(async () => {
9898
9949
  const input = getToolInputRecord(params);
9899
9950
  const target = await resolveGitHubIssueToolTarget(ctx, runCtx, input);
9900
- const octokit = await createGitHubToolOctokit(ctx);
9951
+ const octokit = await createGitHubToolOctokit(ctx, runCtx.companyId);
9901
9952
  const currentResponse = await octokit.rest.issues.get({
9902
9953
  owner: target.repository.owner,
9903
9954
  repo: target.repository.repo,
@@ -9969,7 +10020,7 @@ function registerGitHubAgentTools(ctx) {
9969
10020
  async (params, runCtx) => executeGitHubTool(async () => {
9970
10021
  const input = getToolInputRecord(params);
9971
10022
  const target = await resolveGitHubIssueToolTarget(ctx, runCtx, input);
9972
- const octokit = await createGitHubToolOctokit(ctx);
10023
+ const octokit = await createGitHubToolOctokit(ctx, runCtx.companyId);
9973
10024
  const body = appendAiAuthorshipFooter(String(input.body ?? ""), normalizeOptionalToolString(input.llmModel) ?? "");
9974
10025
  const response = await octokit.rest.issues.createComment({
9975
10026
  owner: target.repository.owner,
@@ -10008,7 +10059,7 @@ function registerGitHubAgentTools(ctx) {
10008
10059
  if (!head || !base || !title) {
10009
10060
  throw new Error("head, base, and title are required.");
10010
10061
  }
10011
- const octokit = await createGitHubToolOctokit(ctx);
10062
+ const octokit = await createGitHubToolOctokit(ctx, runCtx.companyId);
10012
10063
  const response = await octokit.rest.pulls.create({
10013
10064
  owner: repository.owner,
10014
10065
  repo: repository.repo,
@@ -10045,7 +10096,7 @@ function registerGitHubAgentTools(ctx) {
10045
10096
  async (params, runCtx) => executeGitHubTool(async () => {
10046
10097
  const input = getToolInputRecord(params);
10047
10098
  const target = await resolveGitHubPullRequestToolTarget(ctx, runCtx, input);
10048
- const octokit = await createGitHubToolOctokit(ctx);
10099
+ const octokit = await createGitHubToolOctokit(ctx, runCtx.companyId);
10049
10100
  const response = await octokit.rest.pulls.get({
10050
10101
  owner: target.repository.owner,
10051
10102
  repo: target.repository.repo,
@@ -10093,7 +10144,7 @@ function registerGitHubAgentTools(ctx) {
10093
10144
  async (params, runCtx) => executeGitHubTool(async () => {
10094
10145
  const input = getToolInputRecord(params);
10095
10146
  const target = await resolveGitHubPullRequestToolTarget(ctx, runCtx, input);
10096
- const octokit = await createGitHubToolOctokit(ctx);
10147
+ const octokit = await createGitHubToolOctokit(ctx, runCtx.companyId);
10097
10148
  let currentResponse = await octokit.rest.pulls.get({
10098
10149
  owner: target.repository.owner,
10099
10150
  repo: target.repository.repo,
@@ -10158,7 +10209,7 @@ function registerGitHubAgentTools(ctx) {
10158
10209
  async (params, runCtx) => executeGitHubTool(async () => {
10159
10210
  const input = getToolInputRecord(params);
10160
10211
  const target = await resolveGitHubPullRequestToolTarget(ctx, runCtx, input);
10161
- const octokit = await createGitHubToolOctokit(ctx);
10212
+ const octokit = await createGitHubToolOctokit(ctx, runCtx.companyId);
10162
10213
  const files = await listAllPullRequestFiles(octokit, target.repository, target.pullRequestNumber);
10163
10214
  return buildToolSuccessResult(
10164
10215
  `Loaded ${files.length} changed ${files.length === 1 ? "file" : "files"} from pull request #${target.pullRequestNumber}.`,
@@ -10176,7 +10227,7 @@ function registerGitHubAgentTools(ctx) {
10176
10227
  async (params, runCtx) => executeGitHubTool(async () => {
10177
10228
  const input = getToolInputRecord(params);
10178
10229
  const target = await resolveGitHubPullRequestToolTarget(ctx, runCtx, input);
10179
- const octokit = await createGitHubToolOctokit(ctx);
10230
+ const octokit = await createGitHubToolOctokit(ctx, runCtx.companyId);
10180
10231
  const pullRequestResponse = await octokit.rest.pulls.get({
10181
10232
  owner: target.repository.owner,
10182
10233
  repo: target.repository.repo,
@@ -10274,7 +10325,7 @@ function registerGitHubAgentTools(ctx) {
10274
10325
  async (params, runCtx) => executeGitHubTool(async () => {
10275
10326
  const input = getToolInputRecord(params);
10276
10327
  const target = await resolveGitHubPullRequestToolTarget(ctx, runCtx, input);
10277
- const octokit = await createGitHubToolOctokit(ctx);
10328
+ const octokit = await createGitHubToolOctokit(ctx, runCtx.companyId);
10278
10329
  const threads = await listDetailedPullRequestReviewThreads(octokit, target.repository, target.pullRequestNumber);
10279
10330
  return buildToolSuccessResult(
10280
10331
  `Loaded ${threads.length} review ${threads.length === 1 ? "thread" : "threads"} from pull request #${target.pullRequestNumber}.`,
@@ -10289,14 +10340,14 @@ function registerGitHubAgentTools(ctx) {
10289
10340
  ctx.tools.register(
10290
10341
  "reply_to_review_thread",
10291
10342
  getGitHubAgentToolDeclaration("reply_to_review_thread"),
10292
- async (params) => executeGitHubTool(async () => {
10343
+ async (params, runCtx) => executeGitHubTool(async () => {
10293
10344
  const input = getToolInputRecord(params);
10294
10345
  const threadId = normalizeOptionalToolString(input.threadId);
10295
10346
  if (!threadId) {
10296
10347
  throw new Error("threadId is required.");
10297
10348
  }
10298
10349
  const body = appendAiAuthorshipFooter(String(input.body ?? ""), normalizeOptionalToolString(input.llmModel) ?? "");
10299
- const octokit = await createGitHubToolOctokit(ctx);
10350
+ const octokit = await createGitHubToolOctokit(ctx, runCtx.companyId);
10300
10351
  const response = await octokit.graphql(
10301
10352
  GITHUB_ADD_PULL_REQUEST_REVIEW_THREAD_REPLY_MUTATION,
10302
10353
  {
@@ -10325,13 +10376,13 @@ function registerGitHubAgentTools(ctx) {
10325
10376
  ctx.tools.register(
10326
10377
  "resolve_review_thread",
10327
10378
  getGitHubAgentToolDeclaration("resolve_review_thread"),
10328
- async (params) => executeGitHubTool(async () => {
10379
+ async (params, runCtx) => executeGitHubTool(async () => {
10329
10380
  const input = getToolInputRecord(params);
10330
10381
  const threadId = normalizeOptionalToolString(input.threadId);
10331
10382
  if (!threadId) {
10332
10383
  throw new Error("threadId is required.");
10333
10384
  }
10334
- const octokit = await createGitHubToolOctokit(ctx);
10385
+ const octokit = await createGitHubToolOctokit(ctx, runCtx.companyId);
10335
10386
  const response = await octokit.graphql(
10336
10387
  GITHUB_RESOLVE_REVIEW_THREAD_MUTATION,
10337
10388
  {
@@ -10356,13 +10407,13 @@ function registerGitHubAgentTools(ctx) {
10356
10407
  ctx.tools.register(
10357
10408
  "unresolve_review_thread",
10358
10409
  getGitHubAgentToolDeclaration("unresolve_review_thread"),
10359
- async (params) => executeGitHubTool(async () => {
10410
+ async (params, runCtx) => executeGitHubTool(async () => {
10360
10411
  const input = getToolInputRecord(params);
10361
10412
  const threadId = normalizeOptionalToolString(input.threadId);
10362
10413
  if (!threadId) {
10363
10414
  throw new Error("threadId is required.");
10364
10415
  }
10365
- const octokit = await createGitHubToolOctokit(ctx);
10416
+ const octokit = await createGitHubToolOctokit(ctx, runCtx.companyId);
10366
10417
  const response = await octokit.graphql(
10367
10418
  GITHUB_UNRESOLVE_REVIEW_THREAD_MUTATION,
10368
10419
  {
@@ -10395,7 +10446,7 @@ function registerGitHubAgentTools(ctx) {
10395
10446
  if (userReviewers.length === 0 && teamReviewers.length === 0) {
10396
10447
  throw new Error("Provide at least one user reviewer or team reviewer.");
10397
10448
  }
10398
- const octokit = await createGitHubToolOctokit(ctx);
10449
+ const octokit = await createGitHubToolOctokit(ctx, runCtx.companyId);
10399
10450
  const response = await octokit.rest.pulls.requestReviewers({
10400
10451
  owner: target.repository.owner,
10401
10452
  repo: target.repository.repo,
@@ -10420,13 +10471,13 @@ function registerGitHubAgentTools(ctx) {
10420
10471
  ctx.tools.register(
10421
10472
  "list_organization_projects",
10422
10473
  getGitHubAgentToolDeclaration("list_organization_projects"),
10423
- async (params) => executeGitHubTool(async () => {
10474
+ async (params, runCtx) => executeGitHubTool(async () => {
10424
10475
  const input = getToolInputRecord(params);
10425
10476
  const organization = normalizeOptionalToolString(input.organization);
10426
10477
  if (!organization) {
10427
10478
  throw new Error("organization is required.");
10428
10479
  }
10429
- const octokit = await createGitHubToolOctokit(ctx);
10480
+ const octokit = await createGitHubToolOctokit(ctx, runCtx.companyId);
10430
10481
  const projects = await listGitHubOrganizationProjects(octokit, organization, {
10431
10482
  includeClosed: input.includeClosed === true,
10432
10483
  query: normalizeOptionalToolString(input.query),
@@ -10447,7 +10498,7 @@ function registerGitHubAgentTools(ctx) {
10447
10498
  async (params, runCtx) => executeGitHubTool(async () => {
10448
10499
  const input = getToolInputRecord(params);
10449
10500
  const target = await resolveGitHubPullRequestToolTarget(ctx, runCtx, input);
10450
- const octokit = await createGitHubToolOctokit(ctx);
10501
+ const octokit = await createGitHubToolOctokit(ctx, runCtx.companyId);
10451
10502
  const projectTarget = await resolveGitHubProjectToolTarget(octokit, input);
10452
10503
  const pullRequest = await getGitHubPullRequestProjectItems(
10453
10504
  octokit,
@@ -10524,14 +10575,30 @@ var plugin = definePlugin({
10524
10575
  const importRegistry = normalizeImportRegistry(await ctx.state.get(IMPORT_REGISTRY_SCOPE));
10525
10576
  const normalizedSettings = normalizeSettings(saved);
10526
10577
  const config = await getResolvedConfig(ctx);
10527
- const githubTokenRef = getConfiguredGithubTokenRef(normalizedSettings, config);
10578
+ const configuredGitHubTokenRef = requestedCompanyId ? normalizeSecretRef(config.githubTokenRefs?.[requestedCompanyId]) : normalizeGitHubTokenRef(config.githubTokenRef);
10579
+ const savedGitHubTokenRef = getSavedGitHubTokenRef(normalizedSettings, requestedCompanyId);
10580
+ const githubTokenRef = getConfiguredGithubTokenRef(normalizedSettings, config, requestedCompanyId);
10581
+ const githubTokenLogin = getSavedGitHubTokenLogin(normalizedSettings, requestedCompanyId);
10528
10582
  const paperclipApiBaseUrl = getConfiguredPaperclipApiBaseUrl(normalizedSettings, config);
10529
- const githubTokenConfigured = hasConfiguredGithubToken(normalizedSettings, config);
10583
+ const githubTokenConfigured = hasConfiguredGithubToken(normalizedSettings, config, requestedCompanyId);
10530
10584
  const configuredBoardTokenRef = getConfiguredPaperclipBoardApiTokenRef(config, requestedCompanyId);
10531
10585
  const savedBoardTokenRef = getSavedPaperclipBoardApiTokenRef(normalizedSettings, requestedCompanyId);
10532
- const settingsWithResolvedToken = githubTokenRef === normalizedSettings.githubTokenRef && paperclipApiBaseUrl === normalizedSettings.paperclipApiBaseUrl ? normalizedSettings : {
10586
+ const settingsWithResolvedToken = githubTokenRef === getSavedGitHubTokenRef(normalizedSettings, requestedCompanyId) && githubTokenLogin === getSavedGitHubTokenLogin(normalizedSettings, requestedCompanyId) && paperclipApiBaseUrl === normalizedSettings.paperclipApiBaseUrl ? normalizedSettings : {
10533
10587
  ...normalizedSettings,
10534
- ...githubTokenRef ? { githubTokenRef } : {},
10588
+ ...requestedCompanyId && githubTokenRef ? {
10589
+ githubTokenRefs: {
10590
+ ...normalizedSettings.githubTokenRefs ?? {},
10591
+ [requestedCompanyId]: githubTokenRef
10592
+ }
10593
+ } : {},
10594
+ ...requestedCompanyId && githubTokenLogin ? {
10595
+ githubTokenLoginsByCompanyId: {
10596
+ ...normalizedSettings.githubTokenLoginsByCompanyId ?? {},
10597
+ [requestedCompanyId]: githubTokenLogin
10598
+ }
10599
+ } : {},
10600
+ ...!requestedCompanyId && githubTokenRef ? { githubTokenRef } : {},
10601
+ ...!requestedCompanyId && githubTokenLogin ? { githubTokenLogin } : {},
10535
10602
  ...paperclipApiBaseUrl ? { paperclipApiBaseUrl } : {}
10536
10603
  };
10537
10604
  const settingsForResponse = sanitizeSettingsForCurrentSetup(settingsWithResolvedToken, {
@@ -10548,6 +10615,9 @@ var plugin = definePlugin({
10548
10615
  ...includeAssignees ? { availableAssignees } : {},
10549
10616
  totalSyncedIssuesCount: countImportedIssuesForMappings(importRegistry, scopedMappings),
10550
10617
  githubTokenConfigured,
10618
+ ...githubTokenLogin ? { githubTokenLogin } : {},
10619
+ ...savedGitHubTokenRef ? { githubTokenConfigSyncRef: savedGitHubTokenRef } : {},
10620
+ githubTokenNeedsConfigSync: Boolean(requestedCompanyId && savedGitHubTokenRef && !configuredGitHubTokenRef),
10551
10621
  paperclipBoardAccessConfigured: requestedCompanyId ? hasConfiguredPaperclipBoardAccess(settingsForResponse, config, requestedCompanyId) : hasConfiguredPaperclipBoardAccessForMappings(settingsForResponse, config, scopedMappings),
10552
10622
  ...savedBoardTokenRef ? { paperclipBoardAccessConfigSyncRef: savedBoardTokenRef } : {},
10553
10623
  paperclipBoardAccessNeedsConfigSync: Boolean(savedBoardTokenRef && !configuredBoardTokenRef)
@@ -10600,12 +10670,32 @@ var plugin = definePlugin({
10600
10670
  const requestedCompanyId = normalizeCompanyId(record.companyId);
10601
10671
  const hasMappingsPatch = "mappings" in record;
10602
10672
  const hasAdvancedSettingsPatch = "advancedSettings" in record;
10603
- const githubTokenRef = "githubTokenRef" in record ? normalizeGitHubTokenRef(record.githubTokenRef) : normalizeGitHubTokenRef(previous.githubTokenRef) ?? normalizeGitHubTokenRef(config.githubTokenRef);
10604
- const githubTokenLogin = "githubTokenLogin" in record ? normalizeOptionalString2(record.githubTokenLogin) : previous.githubTokenLogin;
10673
+ const githubTokenRef = "githubTokenRef" in record ? normalizeGitHubTokenRef(record.githubTokenRef) : void 0;
10674
+ const githubTokenLogin = "githubTokenLogin" in record ? normalizeOptionalString2(record.githubTokenLogin) : void 0;
10605
10675
  const inputMappings = hasMappingsPatch ? normalizeMappings(record.mappings) : previous.mappings;
10676
+ const nextGitHubTokenRefs = {
10677
+ ...previous.githubTokenRefs ?? {}
10678
+ };
10679
+ const nextGitHubTokenLoginsByCompanyId = {
10680
+ ...previous.githubTokenLoginsByCompanyId ?? {}
10681
+ };
10606
10682
  const nextCompanyAdvancedSettingsByCompanyId = {
10607
10683
  ...previous.companyAdvancedSettingsByCompanyId ?? {}
10608
10684
  };
10685
+ if (requestedCompanyId && "githubTokenRef" in record) {
10686
+ if (githubTokenRef) {
10687
+ nextGitHubTokenRefs[requestedCompanyId] = githubTokenRef;
10688
+ } else {
10689
+ delete nextGitHubTokenRefs[requestedCompanyId];
10690
+ }
10691
+ }
10692
+ if (requestedCompanyId && "githubTokenLogin" in record) {
10693
+ if (githubTokenLogin) {
10694
+ nextGitHubTokenLoginsByCompanyId[requestedCompanyId] = githubTokenLogin;
10695
+ } else {
10696
+ delete nextGitHubTokenLoginsByCompanyId[requestedCompanyId];
10697
+ }
10698
+ }
10609
10699
  if (requestedCompanyId && hasAdvancedSettingsPatch) {
10610
10700
  nextCompanyAdvancedSettingsByCompanyId[requestedCompanyId] = normalizeAdvancedSettings(record.advancedSettings);
10611
10701
  }
@@ -10621,11 +10711,13 @@ var plugin = definePlugin({
10621
10711
  syncState: previous.syncState,
10622
10712
  scheduleFrequencyMinutes: "scheduleFrequencyMinutes" in record ? record.scheduleFrequencyMinutes : previous.scheduleFrequencyMinutes,
10623
10713
  paperclipApiBaseUrl: "paperclipApiBaseUrl" in record ? resolveTrustedPaperclipApiBaseUrlInput(record.paperclipApiBaseUrl, previous, config) : getConfiguredPaperclipApiBaseUrl(previous, config),
10624
- ...githubTokenLogin ? { githubTokenLogin } : {},
10714
+ ...Object.keys(nextGitHubTokenRefs).length > 0 ? { githubTokenRefs: nextGitHubTokenRefs } : {},
10715
+ ...Object.keys(nextGitHubTokenLoginsByCompanyId).length > 0 ? { githubTokenLoginsByCompanyId: nextGitHubTokenLoginsByCompanyId } : {},
10716
+ ...!requestedCompanyId ? githubTokenLogin ? { githubTokenLogin } : previous.githubTokenLogin ? { githubTokenLogin: previous.githubTokenLogin } : {} : {},
10625
10717
  paperclipBoardApiTokenRefs: previous.paperclipBoardApiTokenRefs,
10626
10718
  paperclipBoardAccessIdentityByCompanyId: previous.paperclipBoardAccessIdentityByCompanyId,
10627
10719
  ...Object.keys(nextCompanyAdvancedSettingsByCompanyId).length > 0 ? { companyAdvancedSettingsByCompanyId: nextCompanyAdvancedSettingsByCompanyId } : {},
10628
- ...githubTokenRef ? { githubTokenRef } : {}
10720
+ ...!requestedCompanyId ? githubTokenRef ? { githubTokenRef } : previous.githubTokenRef ? { githubTokenRef: previous.githubTokenRef } : {} : {}
10629
10721
  });
10630
10722
  const nextMappings = current.mappings.map((mapping, index) => ({
10631
10723
  id: mapping.id.trim() || createMappingId(index),
@@ -10639,21 +10731,25 @@ var plugin = definePlugin({
10639
10731
  syncState: previous.syncState,
10640
10732
  scheduleFrequencyMinutes: current.scheduleFrequencyMinutes,
10641
10733
  ...current.paperclipApiBaseUrl ? { paperclipApiBaseUrl: current.paperclipApiBaseUrl } : {},
10734
+ ...current.githubTokenRefs ? { githubTokenRefs: current.githubTokenRefs } : {},
10735
+ ...current.githubTokenLoginsByCompanyId ? { githubTokenLoginsByCompanyId: current.githubTokenLoginsByCompanyId } : {},
10642
10736
  ...current.githubTokenLogin ? { githubTokenLogin: current.githubTokenLogin } : {},
10643
10737
  ...current.paperclipBoardApiTokenRefs ? { paperclipBoardApiTokenRefs: current.paperclipBoardApiTokenRefs } : {},
10644
10738
  ...current.paperclipBoardAccessIdentityByCompanyId ? { paperclipBoardAccessIdentityByCompanyId: current.paperclipBoardAccessIdentityByCompanyId } : {},
10645
10739
  ...current.companyAdvancedSettingsByCompanyId ? { companyAdvancedSettingsByCompanyId: current.companyAdvancedSettingsByCompanyId } : {},
10646
- ...githubTokenRef ? { githubTokenRef } : {},
10740
+ ...current.githubTokenRef ? { githubTokenRef: current.githubTokenRef } : {},
10647
10741
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
10648
10742
  }, {
10649
- hasToken: hasConfiguredGithubToken({ githubTokenRef }, config),
10743
+ hasToken: hasConfiguredGithubToken(current, config, requestedCompanyId),
10650
10744
  hasMappings: getSyncableMappings(nextMappings).length > 0
10651
10745
  });
10652
10746
  await ctx.state.set(SETTINGS_SCOPE, next);
10653
10747
  await ctx.state.set(SYNC_STATE_SCOPE, next.syncState);
10654
10748
  clearGitHubRepositoryTokenCapabilityAudits();
10749
+ const scopedGitHubTokenLogin = getSavedGitHubTokenLogin(next, requestedCompanyId);
10655
10750
  return {
10656
10751
  ...getPublicSettingsForScope(next, requestedCompanyId),
10752
+ ...scopedGitHubTokenLogin ? { githubTokenLogin: scopedGitHubTokenLogin } : {},
10657
10753
  availableAssignees: requestedCompanyId ? await listAvailableAssignees(ctx, requestedCompanyId) : []
10658
10754
  };
10659
10755
  });
@@ -10697,7 +10793,7 @@ var plugin = definePlugin({
10697
10793
  ...Object.keys(nextPaperclipBoardAccessIdentityByCompanyId).length > 0 ? { paperclipBoardAccessIdentityByCompanyId: nextPaperclipBoardAccessIdentityByCompanyId } : {},
10698
10794
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
10699
10795
  }, {
10700
- hasToken: hasConfiguredGithubToken(previous, config),
10796
+ hasToken: hasConfiguredGithubToken(previous, config, companyId),
10701
10797
  hasMappings: getSyncableMappings(previous.mappings).length > 0
10702
10798
  });
10703
10799
  await ctx.state.set(SETTINGS_SCOPE, next);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "paperclip-github-plugin",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Paperclip plugin for synchronizing GitHub issues into Paperclip projects.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",