@kidlat-dakila/flightplan 0.1.5 → 0.1.6

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.
Files changed (55) hide show
  1. package/backend/main.js +286 -53
  2. package/frontend/assets/_branchId-CPb8-qBw.js +1 -0
  3. package/frontend/assets/{_branchId-BctD9BVI.js → _branchId-LiwHskkW.js} +1 -1
  4. package/frontend/assets/{_id-DS2_k7mD.js → _id-BDFgPH36.js} +1 -1
  5. package/frontend/assets/_id-DlHylI1F.js +1 -0
  6. package/frontend/assets/agents-BGNiGYQQ.js +1 -0
  7. package/frontend/assets/{agents-Cg-w99VB.js → agents-DBPulyWi.js} +1 -1
  8. package/frontend/assets/configuration-C8ZTSPna.js +1 -0
  9. package/frontend/assets/{configuration-B1tYKnw1.js → configuration-DBU-Fvop.js} +1 -1
  10. package/frontend/assets/{create-BXn1thks.js → create-BWsYjEs5.js} +1 -1
  11. package/frontend/assets/{create-DQsVrUIP.js → create-DBNC2wSp.js} +1 -1
  12. package/frontend/assets/{create-CNT_ktA4.js → create-DBv4ZLt7.js} +1 -1
  13. package/frontend/assets/create-DXgFUVIW.js +1 -0
  14. package/frontend/assets/{download-BsAZZo3P.js → download-BnmEn_Ca.js} +1 -1
  15. package/frontend/assets/{forges-ChElPpOV.js → forges-BOWrvfZl.js} +1 -1
  16. package/frontend/assets/forges-DwSiwqas.js +1 -0
  17. package/frontend/assets/{index-eMdhkBjo.js → index-B1Rm0SQ5.js} +1 -1
  18. package/frontend/assets/index-BKKD-dvv.js +1 -0
  19. package/frontend/assets/{index-C8gx27Rr.js → index-BaflOxvR.js} +1 -1
  20. package/frontend/assets/{index-h6dRc3tV.js → index-CR5UGYQN.js} +1 -1
  21. package/frontend/assets/{index-Dfzoepph.js → index-CSoB1eP_.js} +1 -1
  22. package/frontend/assets/{index-DgodP5aC.js → index-CUqlioqL.js} +1 -1
  23. package/frontend/assets/{index-Baaegu29.js → index-CZN7BV83.js} +1 -1
  24. package/frontend/assets/index-CeY9TXPf.js +1 -0
  25. package/frontend/assets/{index-9KbVyMz4.js → index-CydhSU9g.js} +1 -1
  26. package/frontend/assets/index-D-k5POv5.js +1 -0
  27. package/frontend/assets/{index-B7lg0P4V.js → index-DCCyA67N.js} +1 -1
  28. package/frontend/assets/{index-CX9sF5Fh.js → index-DfRj4oZV.js} +3 -3
  29. package/frontend/assets/index-Dn9qaXzX.js +1 -0
  30. package/frontend/assets/{index-DzSYBwXV.js → index-Dw5NpM9d.js} +1 -1
  31. package/frontend/assets/{index-CPyhbNqS.js → index-DyfuBbIJ.js} +1 -1
  32. package/frontend/assets/{index-CIReAhWD.js → index-PzkXPYSX.js} +1 -1
  33. package/frontend/assets/{index-xoWXUJLW.js → index-QabB0_Qw.js} +1 -1
  34. package/frontend/assets/{index-Ccx_zqhL.js → index-V8tnJR9v.js} +1 -1
  35. package/frontend/assets/{index-BYtgetD4.js → index-XcYy-NBi.js} +1 -1
  36. package/frontend/assets/{index-BsRx8Pzi.js → index-efpZ6EEe.js} +1 -1
  37. package/frontend/assets/{index-BWM8kiQ0.js → index-s14Wy6CE.js} +1 -1
  38. package/frontend/assets/index-zxLaxo8R.js +1 -0
  39. package/frontend/assets/repositories-BLLfYDjf.js +1 -0
  40. package/frontend/assets/{repositories-DdOEWFoL.js → repositories-of9BXUjW.js} +1 -1
  41. package/frontend/assets/{route-qbVbAxtx.js → route-X94hglR1.js} +1 -1
  42. package/frontend/index.html +1 -1
  43. package/package.json +1 -1
  44. package/frontend/assets/_branchId--sAXSZ0Z.js +0 -1
  45. package/frontend/assets/_id-ZvG2tACL.js +0 -1
  46. package/frontend/assets/agents-DbSvvIcf.js +0 -1
  47. package/frontend/assets/configuration-PLwRj92u.js +0 -1
  48. package/frontend/assets/create-CGIYQfn-.js +0 -1
  49. package/frontend/assets/forges-D5lw6fYh.js +0 -1
  50. package/frontend/assets/index-BBbL0wfM.js +0 -1
  51. package/frontend/assets/index-BCEvS2zI.js +0 -1
  52. package/frontend/assets/index-D3gI7yfx.js +0 -1
  53. package/frontend/assets/index-D6S4PGCc.js +0 -1
  54. package/frontend/assets/index-DvVl2gWR.js +0 -1
  55. package/frontend/assets/repositories-Di8qfiyD.js +0 -1
package/backend/main.js CHANGED
@@ -137579,8 +137579,10 @@ var deriveBranchStatus = (pullRequest, viewerLogin) => {
137579
137579
 
137580
137580
  // apps/backend/src/procedures/list-repositories/utils/target-id.ts
137581
137581
  var BRANCH_ID_PREFIX = "branch-";
137582
+ var PULL_REQUEST_ID_PREFIX = "pr-";
137582
137583
  var branchTargetIdOf = (branchName) => `${BRANCH_ID_PREFIX}${branchName}`;
137583
- var targetIdOf = (target) => target.kind === "pull-request" ? `pr-${String(target.number)}` : branchTargetIdOf(target.name);
137584
+ var pullRequestTargetIdOf = (number4) => `${PULL_REQUEST_ID_PREFIX}${String(number4)}`;
137585
+ var targetIdOf = (target) => target.kind === "pull-request" ? pullRequestTargetIdOf(target.number) : branchTargetIdOf(target.name);
137584
137586
  var branchNameOfTargetId = (targetId) => {
137585
137587
  const branchName = targetId.startsWith(BRANCH_ID_PREFIX) ? targetId.slice(BRANCH_ID_PREFIX.length) : "";
137586
137588
  return branchName === "" ? null : branchName;
@@ -137588,22 +137590,47 @@ var branchNameOfTargetId = (targetId) => {
137588
137590
 
137589
137591
  // apps/backend/src/procedures/list-repositories/utils/target-memory.ts
137590
137592
  var JSON_INDENT = 2;
137593
+ var addedTargetSchema = external_exports.discriminatedUnion("kind", [
137594
+ external_exports.strictObject({ kind: external_exports.literal("branch"), name: external_exports.string().min(1) }),
137595
+ external_exports.strictObject({ kind: external_exports.literal("pull-request"), number: external_exports.number().int().positive(), author: external_exports.string() })
137596
+ ]);
137591
137597
  var targetMemorySchema = external_exports.strictObject({
137592
137598
  baselineAt: external_exports.iso.datetime(),
137593
- dismissedTargetIds: external_exports.array(external_exports.string())
137594
- });
137595
- var startTargetMemory = (baselineAt) => ({ baselineAt, dismissedTargetIds: [] });
137596
- var isNewTarget = (memory2, facts) => facts.branchStatus === "no-review" && facts.startedAt.getTime() > memory2.baselineAt.getTime() && !memory2.dismissedTargetIds.includes(facts.targetId);
137599
+ dismissedTargetIds: external_exports.array(external_exports.string()),
137600
+ addedTargets: external_exports.array(addedTargetSchema).default([])
137601
+ });
137602
+ var startTargetMemory = (baselineAt) => ({ baselineAt, dismissedTargetIds: [], addedTargets: [] });
137603
+ var addedTargetIdOf = (target) => target.kind === "branch" ? branchTargetIdOf(target.name) : pullRequestTargetIdOf(target.number);
137604
+ var toAddedTarget = (target) => target.kind === "branch" ? { kind: "branch", name: target.name } : { kind: "pull-request", number: target.number, author: target.author };
137605
+ var isAddedTarget = (memory2, targetId) => memory2.addedTargets.some((target) => addedTargetIdOf(target) === targetId);
137606
+ var addedBranchNamesOf = (memory2) => memory2.addedTargets.flatMap((target) => target.kind === "branch" ? [target.name] : []);
137607
+ var addedPullRequestAuthorsOf = (memory2) => [
137608
+ ...new Set(memory2.addedTargets.flatMap((target) => target.kind === "pull-request" ? [target.author] : []))
137609
+ ];
137610
+ var isNewTarget = (memory2, facts) => facts.branchStatus === "no-review" && facts.startedAt.getTime() > memory2.baselineAt.getTime() && !memory2.dismissedTargetIds.includes(facts.targetId) && !isAddedTarget(memory2, facts.targetId);
137597
137611
  var withDismissedTarget = (memory2, targetId) => memory2.dismissedTargetIds.includes(targetId) ? memory2 : { ...memory2, dismissedTargetIds: [...memory2.dismissedTargetIds, targetId] };
137612
+ var withAddedTarget = (memory2, target) => isAddedTarget(memory2, addedTargetIdOf(target)) ? memory2 : { ...memory2, addedTargets: [...memory2.addedTargets, target] };
137598
137613
  var parseTargetMemory = (text2) => {
137599
137614
  try {
137600
137615
  const memory2 = targetMemorySchema.safeParse(JSON.parse(text2));
137601
- return memory2.success ? { baselineAt: new Date(memory2.data.baselineAt), dismissedTargetIds: memory2.data.dismissedTargetIds } : null;
137616
+ return memory2.success ? {
137617
+ baselineAt: new Date(memory2.data.baselineAt),
137618
+ dismissedTargetIds: memory2.data.dismissedTargetIds,
137619
+ addedTargets: memory2.data.addedTargets
137620
+ } : null;
137602
137621
  } catch {
137603
137622
  return null;
137604
137623
  }
137605
137624
  };
137606
- var formatTargetMemory = (memory2) => `${JSON.stringify({ baselineAt: memory2.baselineAt.toISOString(), dismissedTargetIds: memory2.dismissedTargetIds }, null, JSON_INDENT)}
137625
+ var formatTargetMemory = (memory2) => `${JSON.stringify(
137626
+ {
137627
+ baselineAt: memory2.baselineAt.toISOString(),
137628
+ dismissedTargetIds: memory2.dismissedTargetIds,
137629
+ addedTargets: memory2.addedTargets
137630
+ },
137631
+ null,
137632
+ JSON_INDENT
137633
+ )}
137607
137634
  `;
137608
137635
 
137609
137636
  // apps/backend/src/procedures/list-repositories/utils/build-review-targets.ts
@@ -137611,6 +137638,7 @@ var AUTHOR_HANDLE_PREFIX = "@";
137611
137638
  var LOCAL_BRANCH_STATUS = "no-review";
137612
137639
  var normalizeLogin = (login) => login.replace(AUTHOR_HANDLE_PREFIX, "").toLowerCase();
137613
137640
  var isTrackedPullRequest = (pullRequest, trackedLogins) => trackedLogins.includes(normalizeLogin(pullRequest.author.login));
137641
+ var isListedPullRequest = (pullRequest, trackedLogins, memory2) => isTrackedPullRequest(pullRequest, trackedLogins) || isAddedTarget(memory2, pullRequestTargetIdOf(pullRequest.number));
137614
137642
  var toPullRequestTarget = (pullRequest, viewerLogin, memory2) => {
137615
137643
  const branchStatus = deriveBranchStatus(pullRequest, viewerLogin);
137616
137644
  const target = {
@@ -137631,7 +137659,7 @@ var toPullRequestTarget = (pullRequest, viewerLogin, memory2) => {
137631
137659
  };
137632
137660
  var toPullRequestTargets = (snapshot, trackedAuthorIds, memory2) => {
137633
137661
  const trackedLogins = [...trackedAuthorIds, snapshot.viewerLogin].map(normalizeLogin);
137634
- return snapshot.pullRequests.filter((pullRequest) => isTrackedPullRequest(pullRequest, trackedLogins)).map((pullRequest) => toPullRequestTarget(pullRequest, snapshot.viewerLogin, memory2));
137662
+ return snapshot.pullRequests.filter((pullRequest) => isListedPullRequest(pullRequest, trackedLogins, memory2)).map((pullRequest) => toPullRequestTarget(pullRequest, snapshot.viewerLogin, memory2));
137635
137663
  };
137636
137664
  var toBranchTarget = (branch, memory2) => {
137637
137665
  const target = {
@@ -137815,11 +137843,11 @@ var DETAIL_SEPARATOR = " \u2022 ";
137815
137843
  var TAKEN_LABEL = "Has a Flight Plan";
137816
137844
  var NOTHING_OPEN_MESSAGE = "No open pull requests or branches.";
137817
137845
  var NO_MATCH_MESSAGE = "No pull request or branch matches.";
137818
- var detailOf = (target, now) => target.kind === "pull-request" ? [`#${String(target.number)}`, target.branch].join(DETAIL_SEPARATOR) : ["Branch", formatRelativeTime(target.updatedAt, now)].join(DETAIL_SEPARATOR);
137846
+ var targetDetailOf = (target, now) => target.kind === "pull-request" ? [`#${String(target.number)}`, target.branch].join(DETAIL_SEPARATOR) : ["Branch", formatRelativeTime(target.updatedAt, now)].join(DETAIL_SEPARATOR);
137819
137847
  var toTargetOption = ({ target, hasFlightPlan }, now) => ({
137820
137848
  id: targetIdOf(target),
137821
137849
  label: target.kind === "pull-request" ? target.title : target.name,
137822
- detail: detailOf(target, now),
137850
+ detail: targetDetailOf(target, now),
137823
137851
  stateLabel: hasFlightPlan ? TAKEN_LABEL : null,
137824
137852
  isDisabled: hasFlightPlan
137825
137853
  });
@@ -141525,7 +141553,7 @@ var createMockRepositories = (now) => [
141525
141553
  path: "/Users/dev/projects/ledger-api",
141526
141554
  forge: "gitlab",
141527
141555
  forgeSlug: "acme/ledger-api",
141528
- problem: "auth",
141556
+ problem: { kind: "auth", detail: "GitLab answered 401 to GET /api/v4/user: 401 Unauthorized" },
141529
141557
  hasFollowedAuthors: true,
141530
141558
  targets: []
141531
141559
  },
@@ -141552,6 +141580,7 @@ var dismissNewTarget = (repositories, repositoryName, targetId) => {
141552
141580
  // apps/backend/src/procedures/list-repositories/utils/repository-store.ts
141553
141581
  var NO_AUTHORS = { selfAuthor: null, trackedAuthors: [] };
141554
141582
  var hasFollowedAuthors = (authors) => authors.selfAuthor !== null || authors.trackedAuthors.length > 0;
141583
+ var withListedTarget = (repository, target) => repository.targets.some((listed) => targetIdOf(listed) === targetIdOf(target)) ? repository : { ...repository, targets: [...repository.targets, { ...target, isNew: false }] };
141555
141584
  var InMemoryRepositoryStore = class {
141556
141585
  notice;
141557
141586
  viewerLogin;
@@ -141598,6 +141627,13 @@ var InMemoryRepositoryStore = class {
141598
141627
  }
141599
141628
  return await Promise.resolve(repository);
141600
141629
  };
141630
+ addTarget = async (repositoryName, target) => {
141631
+ const repository = this.repositories.find((stored) => stored.name === repositoryName);
141632
+ if (repository === void 0) return await Promise.resolve(null);
141633
+ const withTarget = withListedTarget(repository, target);
141634
+ this.repositories = this.repositories.map((stored) => stored.name === repositoryName ? withTarget : stored);
141635
+ return await Promise.resolve(withTarget);
141636
+ };
141601
141637
  };
141602
141638
 
141603
141639
  // apps/backend/src/procedures/publish-artifact/utils/published-page-writer.ts
@@ -143951,6 +143987,7 @@ var MS_PER_SECOND = 1e3;
143951
143987
  var BASE_RETRY_WAIT_MS = 500;
143952
143988
  var RETRY_BACKOFF_FACTOR = 2;
143953
143989
  var MAX_ERROR_DETAIL_LENGTH = 400;
143990
+ var DEFAULT_METHOD = "GET";
143954
143991
  var MAX_RETRY_WAIT_MS = 3e4;
143955
143992
  function problemFor(status) {
143956
143993
  if (status === HTTP_UNAUTHORIZED2 || status === HTTP_FORBIDDEN2) return "auth";
@@ -143994,19 +144031,21 @@ function createRest(config3) {
143994
144031
  throw new GitAdapterError(`${config3.name} could not be reached: ${String(cause)}`, "network");
143995
144032
  }
143996
144033
  };
143997
- const failure = async (response) => {
144034
+ const failure = async (response, target, init) => {
143998
144035
  const detail = await response.text().catch(() => "");
143999
144036
  const trimmed = detail.trim().slice(0, MAX_ERROR_DETAIL_LENGTH);
144037
+ const request = `${(init?.method ?? DEFAULT_METHOD).toUpperCase()} ${new URL(target).pathname}`;
144000
144038
  return new GitAdapterError(
144001
- `${config3.name} answered ${String(response.status)}${trimmed === "" ? "" : `: ${trimmed}`}`,
144039
+ `${config3.name} answered ${String(response.status)} to ${request}${trimmed === "" ? "" : `: ${trimmed}`}`,
144002
144040
  problemFor(response.status)
144003
144041
  );
144004
144042
  };
144005
144043
  const send = async (path9, init, attempt) => {
144006
- const response = await attemptRequest(url2(path9), init);
144044
+ const target = url2(path9);
144045
+ const response = await attemptRequest(target, init);
144007
144046
  if (response.ok) return response;
144008
144047
  const wait = retryAfter(response, attempt);
144009
- if (wait === null) throw await failure(response);
144048
+ if (wait === null) throw await failure(response, target, init);
144010
144049
  await sleep(wait);
144011
144050
  return await send(path9, init, attempt + 1);
144012
144051
  };
@@ -144101,6 +144140,7 @@ function toTarget(raw, reason) {
144101
144140
  url: raw.links?.html?.href ?? "",
144102
144141
  updatedAt: raw.updated_on ?? "",
144103
144142
  isDraft: raw.draft ?? false,
144143
+ ...raw.source?.branch?.name === void 0 ? {} : { headBranch: raw.source.branch.name },
144104
144144
  ...destination?.branch?.name === void 0 ? {} : { baseRef: destination.branch.name },
144105
144145
  ...destination?.commit?.hash === void 0 ? {} : { baseSha: destination.commit.hash },
144106
144146
  reason
@@ -144291,7 +144331,7 @@ var BitbucketAdapter = class extends BaseGitAdapter {
144291
144331
  perPage: limit
144292
144332
  })
144293
144333
  );
144294
- const rows = page.items.map((item) => pullRequestItemToTarget(item, "review-requested"));
144334
+ const rows = page.items.map((item) => ({ ...pullRequestItemToTarget(item, "review-requested"), headBranch: item.sourceBranch }));
144295
144335
  const pinnedTargets = (await pinned).filter((row) => row !== null);
144296
144336
  return mergeTargets([rows], pinnedTargets);
144297
144337
  }
@@ -144539,6 +144579,8 @@ var MAX_PAGES = 5;
144539
144579
  var AVATAR_SIZE = 64;
144540
144580
  var AUTHOR_ROLE = "AUTHOR";
144541
144581
  var JSON_HEADERS2 = { "content-type": "application/json" };
144582
+ var APPLICATION_PROPERTIES_PATH = "application-properties";
144583
+ var SIGNED_IN_USER_HEADER = "x-ausername";
144542
144584
  var slugOf = (user) => (user?.slug ?? user?.name ?? "").toLowerCase();
144543
144585
  var isAuthoredBy = (pullRequest, authorSlug) => authorSlug === void 0 || slugOf(pullRequest.author?.user) === authorSlug.toLowerCase();
144544
144586
  var BitbucketDataCenterClient = class {
@@ -144549,7 +144591,9 @@ var BitbucketDataCenterClient = class {
144549
144591
  this.webRoot = webRoot;
144550
144592
  }
144551
144593
  readViewer = async () => {
144552
- const slug = (await this.rest.text(`${this.webRoot}/plugins/servlet/applinks/whoami`)).trim();
144594
+ const answer = await this.rest.request(APPLICATION_PROPERTIES_PATH);
144595
+ const slug = (answer.headers.get(SIGNED_IN_USER_HEADER) ?? "").trim();
144596
+ await answer.body?.cancel();
144553
144597
  if (slug === "") throw new GitAdapterError("Bitbucket Data Center does not know who is signed in.", "auth");
144554
144598
  return parseResponse(
144555
144599
  dataCenterUserSchema,
@@ -144752,6 +144796,7 @@ function toTarget2(raw, reason) {
144752
144796
  url: raw.links?.self?.at(0)?.href ?? "",
144753
144797
  updatedAt: isoOf(raw.updatedDate),
144754
144798
  isDraft: raw.draft ?? false,
144799
+ ...raw.fromRef?.displayId === void 0 ? {} : { headBranch: raw.fromRef.displayId },
144755
144800
  ...raw.toRef?.displayId === void 0 ? {} : { baseRef: raw.toRef.displayId },
144756
144801
  ...raw.toRef?.latestCommit === void 0 ? {} : { baseSha: raw.toRef.latestCommit },
144757
144802
  reason
@@ -145251,6 +145296,7 @@ var githubPullRequestSchema = external_exports.object({
145251
145296
  updated_at: external_exports.string(),
145252
145297
  draft: external_exports.boolean().optional(),
145253
145298
  state: external_exports.string().optional(),
145299
+ head: external_exports.object({ ref: external_exports.string().optional() }).optional(),
145254
145300
  base: external_exports.object({ ref: external_exports.string().optional(), sha: external_exports.string().optional() }).optional()
145255
145301
  });
145256
145302
  var pullRequestAuthorSchema = external_exports.object({ user: githubUserSchema.optional() });
@@ -145729,6 +145775,7 @@ function toTarget3(raw, reason) {
145729
145775
  url: raw.html_url,
145730
145776
  updatedAt: raw.updated_at,
145731
145777
  isDraft: raw.draft ?? false,
145778
+ ...raw.head?.ref === void 0 ? {} : { headBranch: raw.head.ref },
145732
145779
  ...raw.base?.ref === void 0 ? {} : { baseRef: raw.base.ref },
145733
145780
  ...raw.base?.sha === void 0 ? {} : { baseSha: raw.base.sha },
145734
145781
  reason
@@ -146474,6 +146521,7 @@ function toTarget4(raw, reason) {
146474
146521
  url: raw.web_url,
146475
146522
  updatedAt: raw.updated_at,
146476
146523
  isDraft: raw.draft ?? raw.work_in_progress ?? false,
146524
+ ...raw.source_branch === void 0 ? {} : { headBranch: raw.source_branch },
146477
146525
  ...raw.target_branch === void 0 ? {} : { baseRef: raw.target_branch },
146478
146526
  ...raw.diff_refs?.base_sha === void 0 ? {} : { baseSha: raw.diff_refs.base_sha },
146479
146527
  reason
@@ -147180,6 +147228,10 @@ var selectForge = (forges, remote) => {
147180
147228
  // apps/backend/src/utils/repository-adapter-opener/index.ts
147181
147229
  var FORGES_WITHOUT_CREDENTIAL = ["git", "gh", "glab"];
147182
147230
  var problemOf = (error61) => error61 instanceof GitAdapterError ? error61.problem : "unknown";
147231
+ var repositoryProblemOf = (error61) => ({
147232
+ kind: problemOf(error61),
147233
+ detail: error61 instanceof Error ? error61.message : null
147234
+ });
147183
147235
  var createRepositoryAdapterOpener = (dependencies) => async (path9, forges) => {
147184
147236
  const remote = await dependencies.readRemote(path9);
147185
147237
  const choice = selectForge(forges, remote);
@@ -151006,9 +151058,13 @@ var withRepository = (setup, repository) => ({
151006
151058
  });
151007
151059
 
151008
151060
  // apps/backend/src/procedures/list-repositories/utils/build-repository.ts
151061
+ var withoutPullRequestBranches = (branches, pullRequests) => branches.filter((branch) => !pullRequests.some((pullRequest) => pullRequest.branch === branch.name));
151009
151062
  var targetsOf = (registered, inspection, memory2) => {
151010
151063
  if (inspection.problem !== null) return [];
151011
- return inspection.snapshot === null ? toBranchTargets(inspection.branches, memory2) : toPullRequestTargets(inspection.snapshot, registered.trackedAuthors.map((author2) => author2.id), memory2);
151064
+ const branches = toBranchTargets(inspection.branches, memory2);
151065
+ if (inspection.snapshot === null) return branches;
151066
+ const pullRequests = toPullRequestTargets(inspection.snapshot, registered.trackedAuthors.map((author2) => author2.id), memory2);
151067
+ return [...pullRequests, ...withoutPullRequestBranches(branches, pullRequests)];
151012
151068
  };
151013
151069
  var buildRepository = (registered, inspection, memory2) => ({
151014
151070
  name: registered.name,
@@ -151079,7 +151135,8 @@ var LiveRepositoryStore = class {
151079
151135
  const setup = await this.dependencies.setupStore.read();
151080
151136
  const registered = setup.repositories.find((listed) => listed.name === repositoryName);
151081
151137
  if (registered === void 0) return null;
151082
- return (await this.inspect(registered, setup.forges)).snapshot?.viewerLogin ?? null;
151138
+ const memory2 = await this.dependencies.targetMemory.ensure(registered.name, this.dependencies.now());
151139
+ return (await this.inspect(registered, setup.forges, memory2)).snapshot?.viewerLogin ?? null;
151083
151140
  };
151084
151141
  refresh = async (repositoryName) => {
151085
151142
  const setup = await this.dependencies.setupStore.read();
@@ -151104,18 +151161,25 @@ var LiveRepositoryStore = class {
151104
151161
  await this.dependencies.targetMemory.dismiss(repositoryName, targetId, this.dependencies.now());
151105
151162
  return (await this.list()).find((listed) => listed.name === repositoryName) ?? null;
151106
151163
  };
151164
+ addTarget = async (repositoryName, target) => {
151165
+ const setup = await this.dependencies.setupStore.read();
151166
+ const registered = setup.repositories.find((listed) => listed.name === repositoryName);
151167
+ if (registered === void 0) return null;
151168
+ await this.dependencies.targetMemory.add(repositoryName, toAddedTarget(target), this.dependencies.now());
151169
+ this.dependencies.inspector.forget(registered.path);
151170
+ return await this.describe(registered, setup.forges);
151171
+ };
151107
151172
  describe = async (registered, forges) => {
151108
- const [inspection, memory2] = await Promise.all([
151109
- this.inspect(registered, forges),
151110
- this.dependencies.targetMemory.ensure(registered.name, this.dependencies.now())
151111
- ]);
151112
- return buildRepository(registered, inspection, memory2);
151173
+ const memory2 = await this.dependencies.targetMemory.ensure(registered.name, this.dependencies.now());
151174
+ return buildRepository(registered, await this.inspect(registered, forges, memory2), memory2);
151113
151175
  };
151114
- inspect = async (registered, forges) => await this.dependencies.inspector.inspect({
151176
+ inspect = async (registered, forges, memory2) => await this.dependencies.inspector.inspect({
151115
151177
  path: registered.path,
151116
151178
  forges,
151117
151179
  trackedAuthorIds: registered.trackedAuthors.map((author2) => author2.id),
151118
- selfAuthorId: registered.selfAuthor?.id ?? null
151180
+ selfAuthorId: registered.selfAuthor?.id ?? null,
151181
+ addedBranchNames: addedBranchNamesOf(memory2),
151182
+ addedPullRequestAuthors: addedPullRequestAuthorsOf(memory2)
151119
151183
  });
151120
151184
  };
151121
151185
 
@@ -151363,6 +151427,8 @@ var toLocalBranch = (tip, startedAt) => ({
151363
151427
  // apps/backend/src/utils/repository-inspector/index.ts
151364
151428
  var FORGE_CACHE_MS = 12e4;
151365
151429
  var FETCH_INTERVAL_MS = 3e5;
151430
+ var isListedBranch = (tip, trackedAuthorIds, addedBranchNames) => isTrackedBranch(tip, trackedAuthorIds) || addedBranchNames.includes(tip.name);
151431
+ var UNSUPPORTED_PROBLEM = { kind: "unsupported", detail: null };
151366
151432
  var failedInspection = (base, problem) => ({
151367
151433
  ...base,
151368
151434
  problem,
@@ -151381,7 +151447,7 @@ var RepositoryInspector = class {
151381
151447
  inspect = async (request) => {
151382
151448
  const opened = await this.openRepository(request.path, request.forges);
151383
151449
  const base = { forge: opened.adapterName, forgeSlug: opened.forgeSlug };
151384
- if (!opened.resolved.ok) return failedInspection(base, opened.resolved.error.problem);
151450
+ if (!opened.resolved.ok) return failedInspection(base, repositoryProblemOf(opened.resolved.error));
151385
151451
  return base.forge === "git" ? await this.inspectBranches(opened.resolved.gitAdapter, base, request) : await this.inspectForge(opened.resolved.gitAdapter, base, request, opened.forge);
151386
151452
  };
151387
151453
  forget = (path9) => {
@@ -151391,20 +151457,32 @@ var RepositoryInspector = class {
151391
151457
  this.fetchInBackgroundWhenDue(adapter, request.path);
151392
151458
  try {
151393
151459
  const trackedAuthorIds = request.selfAuthorId === null ? request.trackedAuthorIds : [...request.trackedAuthorIds, request.selfAuthorId];
151394
- const tips = (await adapter.listBranches()).filter((tip) => isTrackedBranch(tip, trackedAuthorIds));
151460
+ const tips = (await adapter.listBranches()).filter((tip) => isListedBranch(tip, trackedAuthorIds, request.addedBranchNames));
151395
151461
  const starts = await Promise.all(tips.map(async (tip) => await adapter.branchStart(tip.name)));
151396
151462
  const branches = tips.map((tip, position) => toLocalBranch(tip, starts[position] ?? null));
151397
151463
  return { ...base, problem: null, snapshot: null, branches };
151398
151464
  } catch (error61) {
151399
- return failedInspection(base, problemOf(error61));
151465
+ return failedInspection(base, repositoryProblemOf(error61));
151400
151466
  }
151401
151467
  };
151402
151468
  inspectForge = async (adapter, base, request, forge) => {
151403
- const outcome = await this.cachedForgeOutcome(adapter, request, forge);
151404
- return outcome.kind === "failed" ? failedInspection(base, outcome.problem) : { ...base, problem: null, snapshot: outcome.snapshot, branches: [] };
151469
+ const [outcome, branches] = await Promise.all([
151470
+ this.cachedForgeOutcome(adapter, request, forge),
151471
+ this.readAddedBranches(adapter, request.addedBranchNames)
151472
+ ]);
151473
+ return outcome.kind === "failed" ? failedInspection(base, outcome.problem) : { ...base, problem: null, snapshot: outcome.snapshot, branches };
151474
+ };
151475
+ readAddedBranches = async (adapter, addedBranchNames) => {
151476
+ if (addedBranchNames.length === 0) return [];
151477
+ try {
151478
+ const tips = await adapter.listBranches();
151479
+ return tips.filter((tip) => addedBranchNames.includes(tip.name)).map((tip) => toLocalBranch(tip, null));
151480
+ } catch {
151481
+ return [];
151482
+ }
151405
151483
  };
151406
151484
  cachedForgeOutcome = async (adapter, request, forge) => {
151407
- const key = [request.path, forge, ...[...request.trackedAuthorIds].sort()].join("\n");
151485
+ const key = [request.path, forge, ...[...request.trackedAuthorIds, ...request.addedPullRequestAuthors].sort()].join("\n");
151408
151486
  const now = this.dependencies.now().getTime();
151409
151487
  const cached2 = this.cachedOutcomes.get(key);
151410
151488
  if (cached2 !== void 0 && now - cached2.fetchedAt < FORGE_CACHE_MS) return await cached2.outcome;
@@ -151413,16 +151491,16 @@ var RepositoryInspector = class {
151413
151491
  return await outcome;
151414
151492
  };
151415
151493
  fetchForge = async (adapter, request) => {
151416
- if (!adapter.supports("history")) return { kind: "failed", problem: "unsupported" };
151494
+ if (!adapter.supports("history")) return { kind: "failed", problem: UNSUPPORTED_PROBLEM };
151417
151495
  try {
151418
151496
  const viewer = await adapter.viewer();
151419
151497
  const histories = await adapter.listPullRequests({
151420
- authors: [viewer.login, ...request.trackedAuthorIds],
151498
+ authors: [.../* @__PURE__ */ new Set([viewer.login, ...request.trackedAuthorIds, ...request.addedPullRequestAuthors])],
151421
151499
  limit: PULL_REQUESTS_PER_AUTHOR
151422
151500
  });
151423
151501
  return { kind: "fetched", snapshot: { viewerLogin: viewer.login, pullRequests: histories.map(toForgePullRequest) } };
151424
151502
  } catch (error61) {
151425
- return { kind: "failed", problem: problemOf(error61) };
151503
+ return { kind: "failed", problem: repositoryProblemOf(error61) };
151426
151504
  }
151427
151505
  };
151428
151506
  fetchInBackgroundWhenDue = (adapter, path9) => {
@@ -151461,6 +151539,7 @@ var repositoryLineContentSchema = external_exports.discriminatedUnion("kind", [
151461
151539
  external_exports.strictObject({
151462
151540
  kind: external_exports.literal("problem"),
151463
151541
  message: external_exports.string(),
151542
+ detail: external_exports.string().nullable(),
151464
151543
  actionLabel: external_exports.string(),
151465
151544
  actionHref: external_exports.string()
151466
151545
  })
@@ -151483,6 +151562,7 @@ var repositoryLineSchema = external_exports.strictObject({
151483
151562
  createReviewHref: external_exports.string(),
151484
151563
  configurationHref: external_exports.string(),
151485
151564
  configurationLabel: external_exports.string(),
151565
+ addTargetLabel: external_exports.string(),
151486
151566
  newTargets: external_exports.array(newTargetPromptSchema),
151487
151567
  content: repositoryLineContentSchema
151488
151568
  });
@@ -152336,6 +152416,11 @@ var FileTargetMemoryStore = class {
152336
152416
  const memory2 = await this.ensure(repositoryName, now);
152337
152417
  await writeText(this.pathOf(repositoryName), formatTargetMemory(withDismissedTarget(memory2, targetId)));
152338
152418
  };
152419
+ add = async (repositoryName, target, now) => {
152420
+ if (!isSafeName(repositoryName)) return;
152421
+ const memory2 = await this.ensure(repositoryName, now);
152422
+ await writeText(this.pathOf(repositoryName), formatTargetMemory(withAddedTarget(memory2, target)));
152423
+ };
152339
152424
  pathOf = (repositoryName) => (0, import_node_path16.join)(this.dataPath, repositoryName, MEMORY_FILE_NAME);
152340
152425
  };
152341
152426
 
@@ -156184,6 +156269,93 @@ var addRepositoryRoute = publicProcedure.input(addRepositoryInputSchema).output(
156184
156269
  return { name: addition.repository.name };
156185
156270
  });
156186
156271
 
156272
+ // apps/backend/src/procedures/search-addable-targets/utils/select-addable-targets.ts
156273
+ var toBranchTarget4 = (tip) => ({
156274
+ kind: "branch",
156275
+ name: tip.name,
156276
+ branchStatus: "no-review",
156277
+ isNew: false,
156278
+ updatedAt: new Date(tip.updatedAt)
156279
+ });
156280
+ var toPullRequestTarget3 = (pullRequest, number4, branch) => ({
156281
+ kind: "pull-request",
156282
+ number: number4,
156283
+ title: pullRequest.title,
156284
+ branch,
156285
+ author: pullRequest.author,
156286
+ authorAvatarUrl: null,
156287
+ branchStatus: pullRequest.isDraft ? "draft" : "no-review",
156288
+ isNew: false,
156289
+ updatedAt: new Date(pullRequest.updatedAt)
156290
+ });
156291
+ var pullRequestFrom = (branchName, openPullRequests) => {
156292
+ const pullRequest = openPullRequests.find((candidate) => candidate.headBranch === branchName);
156293
+ return pullRequest?.ref.kind === "pr" ? toPullRequestTarget3(pullRequest, pullRequest.ref.number, branchName) : null;
156294
+ };
156295
+ var toAddableTarget = (tip, openPullRequests) => pullRequestFrom(tip.name, openPullRequests) ?? toBranchTarget4(tip);
156296
+ var isFirstOfItsId = (target, position, targets) => targets.findIndex((other) => targetIdOf(other) === targetIdOf(target)) === position;
156297
+ var byLatestUpdate2 = (first, second) => second.updatedAt.getTime() - first.updatedAt.getTime();
156298
+ var selectAddableTargets = ({ branchTips, openPullRequests }) => branchTips.map((tip) => toAddableTarget(tip, openPullRequests)).filter(isFirstOfItsId).sort(byLatestUpdate2);
156299
+ var isFromBranch = (target, branchName) => target.kind === "pull-request" && target.branch === branchName;
156300
+ var findAddableTarget = (targets, targetId) => {
156301
+ const branchName = branchNameOfTargetId(targetId);
156302
+ return targets.find((target) => targetIdOf(target) === targetId) ?? targets.find((target) => isFromBranch(target, branchName)) ?? null;
156303
+ };
156304
+
156305
+ // apps/backend/src/procedures/search-addable-targets/utils/read-addable-targets.ts
156306
+ var OPEN_PULL_REQUEST_LIMIT = 100;
156307
+ var readOpenPullRequests = async (adapter) => {
156308
+ try {
156309
+ return await adapter.listTargets({ includeMine: false, limit: OPEN_PULL_REQUEST_LIMIT });
156310
+ } catch (error61) {
156311
+ if (error61 instanceof GitAdapterError) return [];
156312
+ throw error61;
156313
+ }
156314
+ };
156315
+ var readFromAdapter = async (adapter) => {
156316
+ try {
156317
+ const [branchTips, openPullRequests] = await Promise.all([adapter.listBranches(), readOpenPullRequests(adapter)]);
156318
+ return { kind: "read", targets: selectAddableTargets({ branchTips, openPullRequests }) };
156319
+ } catch (error61) {
156320
+ if (error61 instanceof GitAdapterError) return { kind: "unreadable", message: error61.message };
156321
+ throw error61;
156322
+ }
156323
+ };
156324
+ var readAddableTargets = async (repositoryPath, forges, openRepository) => {
156325
+ const opened = await openRepository(repositoryPath, forges);
156326
+ return opened.resolved.ok ? await readFromAdapter(opened.resolved.gitAdapter) : { kind: "unreadable", message: opened.resolved.error.message };
156327
+ };
156328
+
156329
+ // apps/backend/src/procedures/add-review-target/index.ts
156330
+ var GONE_TARGET_MESSAGE = "This branch is no longer in the repository.";
156331
+ var addReviewTarget = async (input2, context) => {
156332
+ const [registered, setup] = await Promise.all([context.repositoryStore.listRegistered(), context.setupStore.read()]);
156333
+ const repository = registered.find((candidate) => candidate.name === input2.repositoryName);
156334
+ if (repository === void 0) return null;
156335
+ const reading = await readAddableTargets(repository.path, setup.forges, context.openRepository);
156336
+ if (reading.kind === "unreadable") return { kind: "unavailable", message: reading.message };
156337
+ const target = findAddableTarget(reading.targets, input2.targetId);
156338
+ if (target === null) return { kind: "unavailable", message: GONE_TARGET_MESSAGE };
156339
+ const updated = await context.repositoryStore.addTarget(repository.name, target);
156340
+ return updated === null ? null : { kind: "added", targetId: targetIdOf(target) };
156341
+ };
156342
+
156343
+ // apps/backend/src/procedures/add-review-target/utils/schemas.ts
156344
+ var addReviewTargetInputSchema = external_exports.strictObject({
156345
+ repositoryName: external_exports.string(),
156346
+ targetId: external_exports.string()
156347
+ });
156348
+ var addedReviewTargetSchema = external_exports.strictObject({ targetId: external_exports.string() });
156349
+
156350
+ // apps/backend/src/server/trpc/routes/add-review-target/index.ts
156351
+ var MISSING_REPOSITORY_MESSAGE = "This repository is no longer listed.";
156352
+ var addReviewTargetRoute = publicProcedure.input(addReviewTargetInputSchema).output(addedReviewTargetSchema).mutation(async ({ ctx, input: input2 }) => {
156353
+ const addition = await addReviewTarget(input2, ctx);
156354
+ if (addition === null) throw new TRPCError({ code: "NOT_FOUND", message: MISSING_REPOSITORY_MESSAGE });
156355
+ if (addition.kind === "unavailable") throw new TRPCError({ code: "BAD_REQUEST", message: addition.message });
156356
+ return { targetId: addition.targetId };
156357
+ });
156358
+
156187
156359
  // apps/backend/src/procedures/get-setup/utils/setup-progress.ts
156188
156360
  var EARLIER_STEPS_MESSAGE = "Finish the earlier steps of the setup first.";
156189
156361
  var SAVED_CHECKS = {
@@ -158568,10 +158740,10 @@ var creationFormSchema = external_exports.strictObject({
158568
158740
  });
158569
158741
 
158570
158742
  // apps/backend/src/server/trpc/routes/get-creation-form/index.ts
158571
- var MISSING_REPOSITORY_MESSAGE = "This repository is no longer listed.";
158743
+ var MISSING_REPOSITORY_MESSAGE2 = "This repository is no longer listed.";
158572
158744
  var getCreationFormRoute = publicProcedure.input(getCreationFormInputSchema).output(creationFormSchema).query(async ({ ctx, input: input2 }) => {
158573
158745
  const form = await getCreationForm(input2, ctx);
158574
- if (form === null) throw new TRPCError({ code: "NOT_FOUND", message: MISSING_REPOSITORY_MESSAGE });
158746
+ if (form === null) throw new TRPCError({ code: "NOT_FOUND", message: MISSING_REPOSITORY_MESSAGE2 });
158575
158747
  return form;
158576
158748
  });
158577
158749
 
@@ -159199,7 +159371,7 @@ var code2 = (text2) => ({ text: text2, kind: "code" });
159199
159371
  var targetTitle = (target) => target.kind === "pull-request" ? plain4(target.title) : code2(target.name);
159200
159372
  var targetDetails = (target) => target.kind === "pull-request" ? [plain4(`#${String(target.number)}`), code2(target.branch)] : [plain4("Local branch")];
159201
159373
  var targetAuthor = (target) => target.kind === "pull-request" ? { name: target.author, avatarUrl: target.authorAvatarUrl, monogram: monogramOf(target.author) } : null;
159202
- var byLatestUpdate2 = (first, second) => second.updatedAt.getTime() - first.updatedAt.getTime();
159374
+ var byLatestUpdate3 = (first, second) => second.updatedAt.getTime() - first.updatedAt.getTime();
159203
159375
  var toReviewTargetStop = (repository, target, now) => ({
159204
159376
  id: targetIdOf(target),
159205
159377
  title: targetTitle(target),
@@ -159223,7 +159395,7 @@ var toNewTargetPrompt = (repository, target, now) => ({
159223
159395
  updatedLabel: formatRelativeTime(target.updatedAt, now),
159224
159396
  createReviewHref: `${repositoryHref(repository)}/${encodeURIComponent(targetIdOf(target))}`
159225
159397
  });
159226
- var newTargetPrompts = (repository, now) => repository.targets.filter((target) => target.isNew).sort(byLatestUpdate2).map((target) => toNewTargetPrompt(repository, target, now));
159398
+ var newTargetPrompts = (repository, now) => repository.targets.filter((target) => target.isNew).sort(byLatestUpdate3).map((target) => toNewTargetPrompt(repository, target, now));
159227
159399
  var NO_FOLLOWED_AUTHORS_MESSAGE = "Nobody is tracked here, so no branches are listed. Track an author in this repository's configuration.";
159228
159400
  var emptyMessage = (repository) => {
159229
159401
  if (repository.forge !== "git") return "No open pull requests.";
@@ -159234,7 +159406,8 @@ var toLineContent = ({ repository, visibleTargets }, now) => {
159234
159406
  if (repository.problem !== null) {
159235
159407
  return {
159236
159408
  kind: "problem",
159237
- message: FORGE_PROBLEM_MESSAGES[repository.problem],
159409
+ message: FORGE_PROBLEM_MESSAGES[repository.problem.kind],
159410
+ detail: repository.problem.detail,
159238
159411
  actionLabel: "Open forge configuration",
159239
159412
  actionHref: FORGE_CONFIGURATION_HREF2
159240
159413
  };
@@ -159243,7 +159416,7 @@ var toLineContent = ({ repository, visibleTargets }, now) => {
159243
159416
  if (visibleTargets.length === 0) return { kind: "empty", message: hiddenMessage(repository.targets.length) };
159244
159417
  return {
159245
159418
  kind: "targets",
159246
- targets: [...visibleTargets].sort(byLatestUpdate2).map((target) => toReviewTargetStop(repository, target, now))
159419
+ targets: [...visibleTargets].sort(byLatestUpdate3).map((target) => toReviewTargetStop(repository, target, now))
159247
159420
  };
159248
159421
  };
159249
159422
  var sourceSegments = (repository) => [
@@ -159264,6 +159437,7 @@ var toRepositoryLine = (entry, now) => ({
159264
159437
  createReviewHref: `${repositoryHref(entry.repository)}/create`,
159265
159438
  configurationHref: `${repositoryHref(entry.repository)}/configurations`,
159266
159439
  configurationLabel: `Configure ${entry.repository.name}`,
159440
+ addTargetLabel: `Add a branch to ${entry.repository.name}`,
159267
159441
  newTargets: newTargetPrompts(entry.repository, now),
159268
159442
  content: toLineContent(entry, now)
159269
159443
  });
@@ -159655,14 +159829,14 @@ var unlistedBranchNamesOf = (repository, reviewedTargetIds) => {
159655
159829
  const listedTargetIds = repository.targets.map(targetIdOf);
159656
159830
  return reviewedTargetIds.filter((targetId) => !listedTargetIds.includes(targetId)).map(branchNameOfTargetId).filter((branchName) => branchName !== null);
159657
159831
  };
159658
- var toBranchTarget4 = ({ name, requestedAt }) => ({
159832
+ var toBranchTarget5 = ({ name, requestedAt }) => ({
159659
159833
  kind: "branch",
159660
159834
  name,
159661
159835
  branchStatus: "no-review",
159662
159836
  isNew: false,
159663
159837
  updatedAt: requestedAt
159664
159838
  });
159665
- var withReviewedBranches = (repository, branches) => branches.length === 0 ? repository : { ...repository, targets: [...repository.targets, ...branches.map(toBranchTarget4)] };
159839
+ var withReviewedBranches = (repository, branches) => branches.length === 0 ? repository : { ...repository, targets: [...repository.targets, ...branches.map(toBranchTarget5)] };
159666
159840
 
159667
159841
  // apps/backend/src/procedures/list-repositories/index.ts
159668
159842
  var readFixtures = async (input2, context) => {
@@ -160114,10 +160288,10 @@ var removeSetupRepositoryInputSchema = external_exports.strictObject({ name: ext
160114
160288
  var removedSetupRepositorySchema = external_exports.strictObject({ name: external_exports.string() });
160115
160289
 
160116
160290
  // apps/backend/src/server/trpc/routes/remove-setup-repository/index.ts
160117
- var MISSING_REPOSITORY_MESSAGE2 = "This repository is no longer in the setup.";
160291
+ var MISSING_REPOSITORY_MESSAGE3 = "This repository is no longer in the setup.";
160118
160292
  var removeSetupRepositoryRoute = publicProcedure.input(removeSetupRepositoryInputSchema).output(removedSetupRepositorySchema).mutation(async ({ ctx, input: input2 }) => {
160119
160293
  const setup = await removeSetupRepository(input2, ctx);
160120
- if (setup === null) throw new TRPCError({ code: "NOT_FOUND", message: MISSING_REPOSITORY_MESSAGE2 });
160294
+ if (setup === null) throw new TRPCError({ code: "NOT_FOUND", message: MISSING_REPOSITORY_MESSAGE3 });
160121
160295
  return { name: input2.name };
160122
160296
  });
160123
160297
 
@@ -160542,6 +160716,63 @@ var saveSettingsRoute = publicProcedure.input(saveSettingsInputSchema).output(se
160542
160716
  // apps/backend/src/server/trpc/routes/save-setup-step/index.ts
160543
160717
  var saveSetupStepRoute = publicProcedure.input(saveSetupStepInputSchema).output(stepSavingSchema).mutation(async ({ ctx, input: input2 }) => saveSetupStep(input2, ctx));
160544
160718
 
160719
+ // apps/backend/src/procedures/search-addable-targets/utils/build-addable-suggestions.ts
160720
+ var LISTED_LABEL = "Already listed";
160721
+ var NOTHING_TO_ADD_MESSAGE = "No branches to add.";
160722
+ var NO_MATCH_MESSAGE2 = "No branch or pull request matches.";
160723
+ var toAddableOption = (target, listedTargetIds, now) => {
160724
+ const isListed = listedTargetIds.includes(targetIdOf(target));
160725
+ return {
160726
+ id: targetIdOf(target),
160727
+ label: target.kind === "pull-request" ? target.title : target.name,
160728
+ detail: targetDetailOf(target, now),
160729
+ stateLabel: isListed ? LISTED_LABEL : null,
160730
+ isDisabled: isListed
160731
+ };
160732
+ };
160733
+ var emptyMessageOf3 = (query) => query.trim() === "" ? NOTHING_TO_ADD_MESSAGE : NO_MATCH_MESSAGE2;
160734
+ var buildAddableSuggestions = (targets, listedTargetIds, query, now) => ({
160735
+ options: targets.map((target) => toAddableOption(target, listedTargetIds, now)),
160736
+ message: targets.length === 0 ? emptyMessageOf3(query) : null
160737
+ });
160738
+
160739
+ // apps/backend/src/procedures/search-addable-targets/utils/rank-addable-targets.ts
160740
+ var DEFAULT_TARGET_COUNT = 5;
160741
+ var MATCHED_TARGET_LIMIT = 10;
160742
+ var loadFzf = async () => await Promise.resolve().then(() => (init_fzf_es(), fzf_es_exports));
160743
+ var searchTextOf2 = (target) => target.kind === "pull-request" ? `${target.branch} ${target.title} #${String(target.number)}` : target.name;
160744
+ var rankAddableTargets = async (targets, query) => {
160745
+ const trimmedQuery = query.trim();
160746
+ if (trimmedQuery === "") return targets.slice(0, DEFAULT_TARGET_COUNT);
160747
+ const { Fzf: Fzf2 } = await loadFzf();
160748
+ return new Fzf2(targets, { selector: searchTextOf2, casing: "case-insensitive", limit: MATCHED_TARGET_LIMIT }).find(trimmedQuery).map((match2) => match2.item);
160749
+ };
160750
+
160751
+ // apps/backend/src/procedures/search-addable-targets/index.ts
160752
+ var searchAddableTargets = async (input2, context) => {
160753
+ const [repositories, setup] = await Promise.all([context.repositoryStore.list(), context.setupStore.read()]);
160754
+ const repository = repositories.find((candidate) => candidate.name === input2.repositoryName);
160755
+ if (repository === void 0) return null;
160756
+ const reading = await readAddableTargets(repository.path, setup.forges, context.openRepository);
160757
+ if (reading.kind === "unreadable") return { options: [], message: reading.message };
160758
+ const ranked = await rankAddableTargets(reading.targets, input2.query);
160759
+ return buildAddableSuggestions(ranked, repository.targets.map(targetIdOf), input2.query, context.now());
160760
+ };
160761
+
160762
+ // apps/backend/src/procedures/search-addable-targets/utils/schemas.ts
160763
+ var searchAddableTargetsInputSchema = external_exports.strictObject({
160764
+ repositoryName: external_exports.string(),
160765
+ query: external_exports.string()
160766
+ });
160767
+
160768
+ // apps/backend/src/server/trpc/routes/search-addable-targets/index.ts
160769
+ var MISSING_REPOSITORY_MESSAGE4 = "This repository is no longer listed.";
160770
+ var searchAddableTargetsRoute = publicProcedure.input(searchAddableTargetsInputSchema).output(targetSuggestionsSchema).query(async ({ ctx, input: input2 }) => {
160771
+ const suggestions = await searchAddableTargets(input2, ctx);
160772
+ if (suggestions === null) throw new TRPCError({ code: "NOT_FOUND", message: MISSING_REPOSITORY_MESSAGE4 });
160773
+ return suggestions;
160774
+ });
160775
+
160545
160776
  // apps/backend/src/procedures/get-setup/utils/suggestion-limit.ts
160546
160777
  var MAX_SUGGESTIONS = 5;
160547
160778
 
@@ -160642,10 +160873,10 @@ var searchAdditionAuthorsInputSchema = external_exports.strictObject({
160642
160873
  var searchAdditionAuthorsRoute = publicProcedure.input(searchAdditionAuthorsInputSchema).output(authorSuggestionsSchema).query(async ({ ctx, input: input2 }) => await searchAdditionAuthors(input2, ctx));
160643
160874
 
160644
160875
  // apps/backend/src/server/trpc/routes/search-creation-targets/index.ts
160645
- var MISSING_REPOSITORY_MESSAGE3 = "This repository is no longer listed.";
160876
+ var MISSING_REPOSITORY_MESSAGE5 = "This repository is no longer listed.";
160646
160877
  var searchCreationTargetsRoute = publicProcedure.input(searchCreationTargetsInputSchema).output(targetSuggestionsSchema).query(async ({ ctx, input: input2 }) => {
160647
160878
  const suggestions = await searchCreationTargets(input2, ctx);
160648
- if (suggestions === null) throw new TRPCError({ code: "NOT_FOUND", message: MISSING_REPOSITORY_MESSAGE3 });
160879
+ if (suggestions === null) throw new TRPCError({ code: "NOT_FOUND", message: MISSING_REPOSITORY_MESSAGE5 });
160649
160880
  return suggestions;
160650
160881
  });
160651
160882
 
@@ -160688,7 +160919,7 @@ var fuzzyScoreOf = (query, path9) => {
160688
160919
 
160689
160920
  // apps/backend/src/procedures/search-files/utils/select-files.ts
160690
160921
  var CHANGED_LABEL = "Changed";
160691
- var NO_MATCH_MESSAGE2 = "No file matches.";
160922
+ var NO_MATCH_MESSAGE3 = "No file matches.";
160692
160923
  var NO_CHANGED_FILES_MESSAGE = "This Flight Plan has no changed files.";
160693
160924
  var scorePath = (query, path9) => {
160694
160925
  const score = fuzzyScoreOf(query, path9);
@@ -160703,7 +160934,7 @@ var selectFiles = ({ changedPaths, unchangedPaths, query, limit }) => {
160703
160934
  ...changed.map((path9) => ({ path: path9, stateLabel: CHANGED_LABEL })),
160704
160935
  ...unchanged.map((path9) => ({ path: path9, stateLabel: null }))
160705
160936
  ];
160706
- const emptyMessage2 = isBrowsing ? NO_CHANGED_FILES_MESSAGE : NO_MATCH_MESSAGE2;
160937
+ const emptyMessage2 = isBrowsing ? NO_CHANGED_FILES_MESSAGE : NO_MATCH_MESSAGE3;
160707
160938
  return {
160708
160939
  options: isBrowsing ? options : options.slice(0, limit),
160709
160940
  message: options.length === 0 ? emptyMessage2 : null
@@ -160773,10 +161004,10 @@ var searchRepositoryAuthors = async (input2, context) => {
160773
161004
  };
160774
161005
 
160775
161006
  // apps/backend/src/server/trpc/routes/search-repository-authors/index.ts
160776
- var MISSING_REPOSITORY_MESSAGE4 = "This repository is no longer in the setup.";
161007
+ var MISSING_REPOSITORY_MESSAGE6 = "This repository is no longer in the setup.";
160777
161008
  var searchRepositoryAuthorsRoute = publicProcedure.input(searchRepositoryAuthorsInputSchema).output(authorSuggestionsSchema).query(async ({ ctx, input: input2 }) => {
160778
161009
  const suggestions = await searchRepositoryAuthors(input2, ctx);
160779
- if (suggestions === null) throw new TRPCError({ code: "NOT_FOUND", message: MISSING_REPOSITORY_MESSAGE4 });
161010
+ if (suggestions === null) throw new TRPCError({ code: "NOT_FOUND", message: MISSING_REPOSITORY_MESSAGE6 });
160780
161011
  return suggestions;
160781
161012
  });
160782
161013
 
@@ -160814,9 +161045,9 @@ var matchedLettersInFolderName = (folderPath, matchedPositions) => {
160814
161045
  return [...matchedPositions].filter((position) => position >= folderNameStart).length;
160815
161046
  };
160816
161047
  var byMostLettersInFolderName = (first, second, selector) => matchedLettersInFolderName(selector(second.item), second.positions) - matchedLettersInFolderName(selector(first.item), first.positions);
160817
- var loadFzf = async () => await Promise.resolve().then(() => (init_fzf_es(), fzf_es_exports));
161048
+ var loadFzf2 = async () => await Promise.resolve().then(() => (init_fzf_es(), fzf_es_exports));
160818
161049
  var rankRepositoryFolders = async (paths, query, rootPath) => {
160819
- const { Fzf: Fzf2 } = await loadFzf();
161050
+ const { Fzf: Fzf2 } = await loadFzf2();
160820
161051
  return new Fzf2(paths, {
160821
161052
  selector: (path9) => pathBelowRoot(path9, rootPath),
160822
161053
  casing: "case-insensitive",
@@ -161127,6 +161358,8 @@ var appRouter = createRouter({
161127
161358
  repository: createRouter({
161128
161359
  list: listRepositoriesRoute,
161129
161360
  dismissNewTarget: dismissNewTargetRoute,
161361
+ searchTargets: searchAddableTargetsRoute,
161362
+ addTarget: addReviewTargetRoute,
161130
161363
  add: addRepositoryRoute,
161131
161364
  authorForm: getAuthorFormRoute,
161132
161365
  searchAuthors: searchAdditionAuthorsRoute,