@norman-else/dsh-claude 0.1.45 → 0.1.46

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/lib/client.js CHANGED
@@ -1958,6 +1958,17 @@ window.__ModuleLoader__.load({
1958
1958
  borderColor: "color-mix(in srgb, #a78bfa 35%, transparent)",
1959
1959
  background: "color-mix(in srgb, #a78bfa 5%, var(--dsw-alias-bg-layer-1))"
1960
1960
  };
1961
+ /** A checkout the session wrote into besides its own: lighter, dashed, and
1962
+ * stacked above the session bar so it reads as attached rather than primary. */
1963
+ const repositoryBarLinked = {
1964
+ marginBottom: 6,
1965
+ minHeight: 34,
1966
+ padding: "5px 11px",
1967
+ borderStyle: "dashed",
1968
+ background: "transparent",
1969
+ boxShadow: "none",
1970
+ color: "var(--dsw-alias-label-secondary)"
1971
+ };
1961
1972
  const repositoryPrIcon = {
1962
1973
  width: 20,
1963
1974
  height: 20,
@@ -3251,11 +3262,6 @@ window.__ModuleLoader__.load({
3251
3262
  fontWeight: 650,
3252
3263
  whiteSpace: "nowrap"
3253
3264
  };
3254
- const diffHeaderLabel = {
3255
- minWidth: 0,
3256
- overflow: "hidden",
3257
- textOverflow: "ellipsis"
3258
- };
3259
3265
  const diffHeaderActions = {
3260
3266
  flex: "none",
3261
3267
  display: "flex",
@@ -3296,11 +3302,68 @@ window.__ModuleLoader__.load({
3296
3302
  font: "inherit",
3297
3303
  cursor: "pointer"
3298
3304
  };
3299
- const diffHeaderBranch = {
3305
+ const diffRepositoryTriggerClass = "dshClaudeDiffRepositoryTrigger";
3306
+ /** The checkout switch: a quiet pill in the header's own type, lit on hover
3307
+ * and while its menu is open, with the chevron set off in a lighter tone. */
3308
+ const diffRepositoryCss = `
3309
+ .${diffRepositoryTriggerClass} {
3310
+ flex: none;
3311
+ display: inline-flex;
3312
+ align-items: center;
3313
+ gap: 4px;
3314
+ max-width: 220px;
3315
+ padding: 2px 5px 2px 8px;
3316
+ border: none;
3317
+ border-radius: 7px;
3318
+ background: var(--dsw-alias-interactive-bg-hover);
3319
+ color: inherit;
3320
+ font: inherit;
3321
+ cursor: pointer;
3322
+ transition: background .12s ease;
3323
+ }
3324
+ .${diffRepositoryTriggerClass}:hover,
3325
+ .${diffRepositoryTriggerClass}:focus-visible,
3326
+ .${diffRepositoryTriggerClass}[aria-expanded="true"] {
3327
+ background: var(--dsw-alias-interactive-bg-active);
3328
+ }
3329
+ .${diffRepositoryTriggerClass}:focus-visible { outline: none; }
3330
+ .${diffRepositoryTriggerClass} > span {
3331
+ min-width: 0;
3332
+ overflow: hidden;
3333
+ text-overflow: ellipsis;
3334
+ white-space: nowrap;
3335
+ }
3336
+ .${diffRepositoryTriggerClass} > svg {
3337
+ flex: none;
3338
+ color: var(--dsw-alias-label-tertiary);
3339
+ }
3340
+ `;
3341
+ /** A row of the checkout menu: name left, its counts right in tabular figures. */
3342
+ const diffRepositoryRow = {
3343
+ display: "flex",
3344
+ alignItems: "baseline",
3345
+ gap: 14,
3346
+ minWidth: 0
3347
+ };
3348
+ const diffRepositoryRowName = {
3349
+ minWidth: 0,
3350
+ flex: 1,
3300
3351
  overflow: "hidden",
3301
- color: "var(--dsw-alias-label-tertiary)",
3352
+ textOverflow: "ellipsis",
3353
+ whiteSpace: "nowrap"
3354
+ };
3355
+ const diffRepositoryRowCounts = {
3356
+ flex: "none",
3357
+ display: "inline-flex",
3358
+ gap: 6,
3302
3359
  fontSize: 12,
3303
- fontWeight: 500,
3360
+ fontVariantNumeric: "tabular-nums"
3361
+ };
3362
+ /** The branch is the panel's title: it inherits the header's primary weight
3363
+ * and colour, and only yields to an ellipsis once the actions need the room. */
3364
+ const diffHeaderBranch = {
3365
+ minWidth: 0,
3366
+ overflow: "hidden",
3304
3367
  textOverflow: "ellipsis",
3305
3368
  whiteSpace: "nowrap"
3306
3369
  };
@@ -4367,6 +4430,8 @@ window.__ModuleLoader__.load({
4367
4430
  const MAX_DIFF_CHARS = 262144;
4368
4431
  const MAX_CONFLICT_PATHS = 100;
4369
4432
  const MAX_REVIEW_COMMENTS = 50;
4433
+ /** Matches the server's cap on probed checkouts. */
4434
+ const MAX_REPOSITORIES = 8;
4370
4435
  const MAX_REVIEW_COMMENT_CHARS = 2e3;
4371
4436
  const MAX_TRANSCRIPT_CHARS = 64e3;
4372
4437
  function record$7(value) {
@@ -4434,6 +4499,7 @@ window.__ModuleLoader__.load({
4434
4499
  const tasks = input.tasks === void 0 ? void 0 : record$7(input.tasks);
4435
4500
  if (tasks !== void 0 && !Array.isArray(tasks.tasks)) throw new Error("invalid Claude tasks projection");
4436
4501
  if (input.repository !== void 0 && !validateRepository(input.repository)) throw new Error("invalid Claude repository projection");
4502
+ if (input.repositories !== void 0 && (!Array.isArray(input.repositories) || input.repositories.length > MAX_REPOSITORIES || !input.repositories.every(validateRepository))) throw new Error("invalid Claude repositories projection");
4437
4503
  if (input.reviewComments !== void 0) {
4438
4504
  if (!Array.isArray(input.reviewComments) || input.reviewComments.length > MAX_REVIEW_COMMENTS) throw new Error("invalid Claude review comment projection");
4439
4505
  for (const item of input.reviewComments) {
@@ -4500,6 +4566,7 @@ window.__ModuleLoader__.load({
4500
4566
  let contextUsage;
4501
4567
  let tasks;
4502
4568
  let repository;
4569
+ let repositories;
4503
4570
  let reviewComments;
4504
4571
  let rewind;
4505
4572
  const byStep = /* @__PURE__ */ new Map();
@@ -4580,6 +4647,7 @@ window.__ModuleLoader__.load({
4580
4647
  ...contextUsage === void 0 ? {} : { contextUsage },
4581
4648
  ...tasks === void 0 ? {} : { tasks },
4582
4649
  ...repository === void 0 ? {} : { repository },
4650
+ ...repositories === void 0 ? {} : { repositories },
4583
4651
  ...reviewComments === void 0 ? {} : { reviewComments },
4584
4652
  ...rewind === void 0 ? {} : { rewind },
4585
4653
  byStep: new Map(byStep)
@@ -4681,6 +4749,7 @@ window.__ModuleLoader__.load({
4681
4749
  contextUsage = next.contextUsage;
4682
4750
  tasks = next.tasks;
4683
4751
  repository = next.repository;
4752
+ repositories = next.repositories;
4684
4753
  reviewComments = next.reviewComments;
4685
4754
  rewind = next.rewind;
4686
4755
  reset(next.activities);
@@ -4713,11 +4782,13 @@ window.__ModuleLoader__.load({
4713
4782
  owned: event.owned,
4714
4783
  commands: event.commands,
4715
4784
  ...event.repository === void 0 ? {} : { repository: event.repository },
4785
+ ...event.repositories === void 0 ? {} : { repositories: event.repositories },
4716
4786
  ...event.reviewComments === void 0 ? {} : { reviewComments: event.reviewComments }
4717
4787
  });
4718
4788
  owned = event.owned;
4719
4789
  commands = event.commands;
4720
4790
  repository = event.repository;
4791
+ repositories = event.repositories;
4721
4792
  reviewComments = event.reviewComments;
4722
4793
  revision += 1;
4723
4794
  break;
@@ -5916,10 +5987,13 @@ window.__ModuleLoader__.load({
5916
5987
  function record$5(value) {
5917
5988
  return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
5918
5989
  }
5919
- function feedbackQuery(sessionId, pullNumber, extra) {
5990
+ /** `root` names another checkout the session wrote into; absent, the
5991
+ * session's own. The Host only honours roots it has vouched for. */
5992
+ function feedbackQuery(sessionId, pullNumber, root, extra) {
5920
5993
  return {
5921
5994
  sessionId,
5922
5995
  number: String(pullNumber),
5996
+ ...root === void 0 ? {} : { root },
5923
5997
  ...extra
5924
5998
  };
5925
5999
  }
@@ -5930,12 +6004,12 @@ window.__ModuleLoader__.load({
5930
6004
  }
5931
6005
  /** Every arm of this route shells out to `gh`, so reads and writes alike take
5932
6006
  * the remote budget. */
5933
- async function loadJson(path, sessionId, pullNumber, signal, extra) {
5934
- return answer(await pluginRead(`${CLAUDE_REPOSITORY_FEEDBACK_PATH}${path}`, "remote", signal, { query: feedbackQuery(sessionId, pullNumber, extra) }));
6007
+ async function loadJson(path, sessionId, pullNumber, signal, root, extra) {
6008
+ return answer(await pluginRead(`${CLAUDE_REPOSITORY_FEEDBACK_PATH}${path}`, "remote", signal, { query: feedbackQuery(sessionId, pullNumber, root, extra) }));
5935
6009
  }
5936
- async function postJson(path, sessionId, pullNumber, input) {
6010
+ async function postJson(path, sessionId, pullNumber, input, root) {
5937
6011
  return answer(await pluginWrite(`${CLAUDE_REPOSITORY_FEEDBACK_PATH}${path}`, "remote", void 0, {
5938
- query: feedbackQuery(sessionId, pullNumber),
6012
+ query: feedbackQuery(sessionId, pullNumber, root),
5939
6013
  json: input
5940
6014
  }));
5941
6015
  }
@@ -5944,8 +6018,8 @@ window.__ModuleLoader__.load({
5944
6018
  if (input === void 0 || typeof input.id !== "number" || typeof input.path !== "string" || typeof input.author !== "string" || typeof input.body !== "string" || typeof input.url !== "string" || input.avatarUrl !== void 0 && githubAvatarUrl(input.avatarUrl) === void 0 || input.side !== "new" && input.side !== "old" || input.line !== void 0 && typeof input.line !== "number" || input.createdAt !== void 0 && typeof input.createdAt !== "string" || input.bot !== void 0 && typeof input.bot !== "boolean") return void 0;
5945
6019
  return input;
5946
6020
  }
5947
- async function loadPullRequestThreads(sessionId, pullNumber, signal) {
5948
- const body = await loadJson("/comments", sessionId, pullNumber, signal);
6021
+ async function loadPullRequestThreads(sessionId, pullNumber, signal, root) {
6022
+ const body = await loadJson("/comments", sessionId, pullNumber, signal, root);
5949
6023
  if (!Array.isArray(body.threads)) throw new Error("Invalid pull request comments response.");
5950
6024
  const threads = [];
5951
6025
  for (const item of body.threads) {
@@ -5966,26 +6040,26 @@ window.__ModuleLoader__.load({
5966
6040
  return threads;
5967
6041
  }
5968
6042
  /** Post one reply into the thread that `commentId` belongs to. */
5969
- async function replyToReviewThread(sessionId, pullNumber, commentId, body) {
6043
+ async function replyToReviewThread(sessionId, pullNumber, commentId, body, root) {
5970
6044
  const comment = reviewComment((await postJson("/reply", sessionId, pullNumber, {
5971
6045
  commentId,
5972
6046
  body
5973
- })).comment);
6047
+ }, root)).comment);
5974
6048
  if (comment === void 0) throw new Error("Invalid pull request reply response.");
5975
6049
  return comment;
5976
6050
  }
5977
6051
  /** Resolve or reopen a thread; returns the state GitHub reports afterwards. */
5978
- async function setReviewThreadResolved(sessionId, pullNumber, threadId, resolved) {
6052
+ async function setReviewThreadResolved(sessionId, pullNumber, threadId, resolved, root) {
5979
6053
  const answer = await postJson("/resolve", sessionId, pullNumber, {
5980
6054
  threadId,
5981
6055
  resolved
5982
- });
6056
+ }, root);
5983
6057
  if (typeof answer.resolved !== "boolean") throw new Error("Invalid pull request resolve response.");
5984
6058
  return answer.resolved;
5985
6059
  }
5986
6060
  /** Logins GitHub would notify, for the reply composer's `@` completion. */
5987
- async function loadMentionableUsers(sessionId, pullNumber, query, signal) {
5988
- const body = await loadJson("/mentionables", sessionId, pullNumber, signal, { q: query });
6061
+ async function loadMentionableUsers(sessionId, pullNumber, query, signal, root) {
6062
+ const body = await loadJson("/mentionables", sessionId, pullNumber, signal, root, { q: query });
5989
6063
  if (!Array.isArray(body.users)) return [];
5990
6064
  const users = [];
5991
6065
  for (const item of body.users) {
@@ -6113,6 +6187,11 @@ window.__ModuleLoader__.load({
6113
6187
  if (repository.branch !== void 0) return repository.branch;
6114
6188
  return repository.detached === true ? t("repositoryDetached") : t("repositoryUnknownBranch");
6115
6189
  }
6190
+ /** The short name a checkout goes by: its GitHub repository, else the
6191
+ * directory it lives in. */
6192
+ function repositoryLabel(repository) {
6193
+ return repository.remote?.split("/").at(-1) ?? repository.root?.split(/[\\/]/u).filter((part) => part.length > 0).at(-1) ?? repository.cwd;
6194
+ }
6116
6195
  //#endregion
6117
6196
  //#region src/client/session-preset.ts
6118
6197
  /**
@@ -6167,6 +6246,42 @@ window.__ModuleLoader__.load({
6167
6246
  function repositoryName$1(remote) {
6168
6247
  return remote?.split("/").at(-1);
6169
6248
  }
6249
+ function PullRequestBadges({ pullRequest, t }) {
6250
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [pullRequest?.state === "open" && pullRequest.checks !== "none" ? /* @__PURE__ */ jsx(Badge, {
6251
+ label: t(`repositoryChecks_${pullRequest.checks}`),
6252
+ tone: pullRequest.checks === "passing" ? "success" : pullRequest.checks === "failing" ? "error" : "warning"
6253
+ }) : null, pullRequest?.state === "open" && pullRequest.review !== "none" ? /* @__PURE__ */ jsx(Badge, {
6254
+ label: t(`repositoryReview_${pullRequest.review}`),
6255
+ tone: pullRequest.review === "approved" ? "success" : pullRequest.review === "changes-requested" ? "error" : "neutral"
6256
+ }) : null] });
6257
+ }
6258
+ function PullRequestBadge({ pullRequest, t }) {
6259
+ return pullRequest === void 0 ? /* @__PURE__ */ jsx(Badge, { label: t("overviewNoPr") }) : /* @__PURE__ */ jsx(Badge, {
6260
+ label: `#${pullRequest.number} · ${t(`repositoryState_${pullRequest.state}`)}`,
6261
+ tone: pullRequest.state === "merged" ? "merged" : pullRequest.state === "open" ? "success" : "neutral"
6262
+ });
6263
+ }
6264
+ /** The other checkouts a session wrote into, one line each, under its row. */
6265
+ function OverviewOtherRepositories({ source, t }) {
6266
+ return /* @__PURE__ */ jsx(Fragment$1, { children: (useSyncExternalStore(source.subscribe, source.getSnapshot, source.getSnapshot).repositories ?? []).map((repository) => /* @__PURE__ */ jsxs("span", {
6267
+ style: overviewMeta,
6268
+ children: [
6269
+ /* @__PURE__ */ jsx("span", { children: repositoryLabel(repository) }),
6270
+ /* @__PURE__ */ jsx("span", {
6271
+ style: overviewBranch,
6272
+ children: branchLabel(repository, t)
6273
+ }),
6274
+ /* @__PURE__ */ jsx(PullRequestBadge, {
6275
+ pullRequest: repository.pullRequest,
6276
+ t
6277
+ }),
6278
+ /* @__PURE__ */ jsx(PullRequestBadges, {
6279
+ pullRequest: repository.pullRequest,
6280
+ t
6281
+ })
6282
+ ]
6283
+ }, repository.root ?? repository.cwd)) });
6284
+ }
6170
6285
  function OverviewAttention({ source, running, t }) {
6171
6286
  const snapshot = useSyncExternalStore(source.subscribe, source.getSnapshot, source.getSnapshot);
6172
6287
  const attention = running ? overviewAttention(snapshot.activities) : void 0;
@@ -6258,49 +6373,52 @@ window.__ModuleLoader__.load({
6258
6373
  onClick: () => {
6259
6374
  openSession(row.id);
6260
6375
  },
6261
- children: [/* @__PURE__ */ jsxs("span", {
6262
- style: overviewRowTop,
6263
- children: [
6264
- row.running === true ? /* @__PURE__ */ jsx("span", {
6265
- style: overviewRunningDot,
6266
- "aria-label": t("overviewRunning")
6267
- }) : null,
6268
- /* @__PURE__ */ jsx("span", {
6269
- style: overviewTitle,
6270
- children: row.displayTitle ?? row.id
6271
- }),
6272
- pullRequest === void 0 ? /* @__PURE__ */ jsx(Badge, { label: t("overviewNoPr") }) : /* @__PURE__ */ jsx(Badge, {
6273
- label: `#${pullRequest.number} · ${t(`repositoryState_${pullRequest.state}`)}`,
6274
- tone: pullRequest.state === "merged" ? "merged" : pullRequest.state === "open" ? "success" : "neutral"
6275
- })
6276
- ]
6277
- }), /* @__PURE__ */ jsxs("span", {
6278
- style: overviewMeta,
6279
- children: [
6280
- repositoryName$1(repository?.remote) === void 0 ? null : /* @__PURE__ */ jsx("span", { children: repositoryName$1(repository?.remote) }),
6281
- /* @__PURE__ */ jsx("span", {
6282
- style: overviewBranch,
6283
- children: branch
6284
- }),
6285
- pullRequest?.state === "open" && pullRequest.checks !== "none" ? /* @__PURE__ */ jsx(Badge, {
6286
- label: t(`repositoryChecks_${pullRequest.checks}`),
6287
- tone: pullRequest.checks === "passing" ? "success" : pullRequest.checks === "failing" ? "error" : "warning"
6288
- }) : null,
6289
- pullRequest?.state === "open" && pullRequest.review !== "none" ? /* @__PURE__ */ jsx(Badge, {
6290
- label: t(`repositoryReview_${pullRequest.review}`),
6291
- tone: pullRequest.review === "approved" ? "success" : pullRequest.review === "changes-requested" ? "error" : "neutral"
6292
- }) : null,
6293
- autoFixEnabled(row.id) ? /* @__PURE__ */ jsx(Badge, {
6294
- label: t("overviewAutoFix"),
6295
- tone: "success"
6296
- }) : null,
6297
- projectionFor === void 0 ? null : /* @__PURE__ */ jsx(OverviewAttention, {
6298
- source: projectionFor(row.id),
6299
- running: row.running === true,
6300
- t
6301
- })
6302
- ]
6303
- })]
6376
+ children: [
6377
+ /* @__PURE__ */ jsxs("span", {
6378
+ style: overviewRowTop,
6379
+ children: [
6380
+ row.running === true ? /* @__PURE__ */ jsx("span", {
6381
+ style: overviewRunningDot,
6382
+ "aria-label": t("overviewRunning")
6383
+ }) : null,
6384
+ /* @__PURE__ */ jsx("span", {
6385
+ style: overviewTitle,
6386
+ children: row.displayTitle ?? row.id
6387
+ }),
6388
+ /* @__PURE__ */ jsx(PullRequestBadge, {
6389
+ pullRequest,
6390
+ t
6391
+ })
6392
+ ]
6393
+ }),
6394
+ /* @__PURE__ */ jsxs("span", {
6395
+ style: overviewMeta,
6396
+ children: [
6397
+ repositoryName$1(repository?.remote) === void 0 ? null : /* @__PURE__ */ jsx("span", { children: repositoryName$1(repository?.remote) }),
6398
+ /* @__PURE__ */ jsx("span", {
6399
+ style: overviewBranch,
6400
+ children: branch
6401
+ }),
6402
+ /* @__PURE__ */ jsx(PullRequestBadges, {
6403
+ pullRequest,
6404
+ t
6405
+ }),
6406
+ autoFixEnabled(row.id) ? /* @__PURE__ */ jsx(Badge, {
6407
+ label: t("overviewAutoFix"),
6408
+ tone: "success"
6409
+ }) : null,
6410
+ projectionFor === void 0 ? null : /* @__PURE__ */ jsx(OverviewAttention, {
6411
+ source: projectionFor(row.id),
6412
+ running: row.running === true,
6413
+ t
6414
+ })
6415
+ ]
6416
+ }),
6417
+ projectionFor === void 0 ? null : /* @__PURE__ */ jsx(OverviewOtherRepositories, {
6418
+ source: projectionFor(row.id),
6419
+ t
6420
+ })
6421
+ ]
6304
6422
  }, row.id);
6305
6423
  })
6306
6424
  })
@@ -7951,18 +8069,26 @@ window.__ModuleLoader__.load({
7951
8069
  if (input === void 0 || typeof input.commit !== "string" || typeof input.pushed !== "boolean" || input.pullRequestUrl !== void 0 && typeof input.pullRequestUrl !== "string" || input.conflicts !== void 0 && (!Array.isArray(input.conflicts) || input.conflicts.some((item) => typeof item !== "string"))) throw new Error("Invalid repository action result.");
7952
8070
  return input;
7953
8071
  }
8072
+ /** `root` names another checkout the session wrote into; absent, the
8073
+ * session's own. The Host only honours roots it has vouched for. */
8074
+ function sessionQuery(sessionId, root) {
8075
+ return {
8076
+ sessionId,
8077
+ ...root === void 0 ? {} : { root }
8078
+ };
8079
+ }
7954
8080
  /** The preview only chains local Git; everything that writes may reach a remote. */
7955
- async function loadRepositoryActionPreview(sessionId, signal) {
8081
+ async function loadRepositoryActionPreview(sessionId, signal, root) {
7956
8082
  try {
7957
- return preview(await pluginRead(`${CLAUDE_REPOSITORY_ACTION_PATH}/preview`, "git", signal, { query: { sessionId } }));
8083
+ return preview(await pluginRead(`${CLAUDE_REPOSITORY_ACTION_PATH}/preview`, "git", signal, { query: sessionQuery(sessionId, root) }));
7958
8084
  } catch (error) {
7959
8085
  throw actionError(error);
7960
8086
  }
7961
8087
  }
7962
- async function generateCommitMessage(sessionId, fingerprint, signal) {
8088
+ async function generateCommitMessage(sessionId, fingerprint, signal, root) {
7963
8089
  try {
7964
8090
  const value = record$3(await pluginWrite(`${CLAUDE_REPOSITORY_ACTION_PATH}/message`, "remote", signal, {
7965
- query: { sessionId },
8091
+ query: sessionQuery(sessionId, root),
7966
8092
  json: { fingerprint }
7967
8093
  }));
7968
8094
  if (typeof value?.message !== "string") throw new Error("Invalid generated commit message.");
@@ -7971,10 +8097,10 @@ window.__ModuleLoader__.load({
7971
8097
  throw actionError(error);
7972
8098
  }
7973
8099
  }
7974
- async function executeRepositoryAction(sessionId, request) {
8100
+ async function executeRepositoryAction(sessionId, request, root) {
7975
8101
  try {
7976
8102
  return result(await pluginWrite(CLAUDE_REPOSITORY_ACTION_PATH, "remote", void 0, {
7977
- query: { sessionId },
8103
+ query: sessionQuery(sessionId, root),
7978
8104
  json: request
7979
8105
  }));
7980
8106
  } catch (error) {
@@ -9112,25 +9238,28 @@ window.__ModuleLoader__.load({
9112
9238
  setMenuOpen(false);
9113
9239
  setDialog({
9114
9240
  method,
9241
+ admin: false,
9115
9242
  loading: true,
9116
9243
  submitting: false
9117
9244
  });
9118
9245
  const aborter = new AbortController();
9119
9246
  controller.current = aborter;
9120
9247
  loadRepositoryActionPreview(sessionId, aborter.signal).then((preview) => {
9121
- setDialog({
9248
+ setDialog((current) => ({
9122
9249
  method,
9250
+ admin: current?.admin ?? false,
9123
9251
  loading: false,
9124
9252
  submitting: false,
9125
9253
  fingerprint: preview.fingerprint
9126
- });
9254
+ }));
9127
9255
  }, (error) => {
9128
- if (!aborter.signal.aborted) setDialog({
9256
+ if (!aborter.signal.aborted) setDialog((current) => ({
9129
9257
  method,
9258
+ admin: current?.admin ?? false,
9130
9259
  loading: false,
9131
9260
  submitting: false,
9132
9261
  error: error instanceof Error ? error.message : t("diffActionFailed")
9133
- });
9262
+ }));
9134
9263
  });
9135
9264
  };
9136
9265
  const closeDialog = () => {
@@ -9151,7 +9280,8 @@ window.__ModuleLoader__.load({
9151
9280
  fingerprint: dialog.fingerprint,
9152
9281
  message: "",
9153
9282
  includeUnstaged: false,
9154
- mergeMethod: dialog.method
9283
+ mergeMethod: dialog.method,
9284
+ ...dialog.admin ? { admin: true } : {}
9155
9285
  }).then(() => {
9156
9286
  report(t("diffMergeCompleted", { number: pullRequest.number }));
9157
9287
  setDialog(void 0);
@@ -9240,6 +9370,22 @@ window.__ModuleLoader__.load({
9240
9370
  style: diffModalStatus,
9241
9371
  children: pullRequest.title
9242
9372
  }),
9373
+ /* @__PURE__ */ jsxs("label", {
9374
+ style: diffModalCheckbox,
9375
+ children: [/* @__PURE__ */ jsx("input", {
9376
+ type: "checkbox",
9377
+ name: "dsh-claude-merge-admin",
9378
+ checked: dialog.admin,
9379
+ disabled: dialog.submitting,
9380
+ onChange: (event) => {
9381
+ const { checked } = event.currentTarget;
9382
+ setDialog((current) => current === void 0 ? current : {
9383
+ ...current,
9384
+ admin: checked
9385
+ });
9386
+ }
9387
+ }), t("diffMergeAdmin")]
9388
+ }),
9243
9389
  dialog.error === void 0 ? null : /* @__PURE__ */ jsx("p", {
9244
9390
  role: "alert",
9245
9391
  style: diffModalError,
@@ -9250,6 +9396,124 @@ window.__ModuleLoader__.load({
9250
9396
  })
9251
9397
  ] });
9252
9398
  }
9399
+ function LinkIcon() {
9400
+ return /* @__PURE__ */ jsxs("svg", {
9401
+ width: "16",
9402
+ height: "16",
9403
+ viewBox: "0 0 16 16",
9404
+ fill: "none",
9405
+ stroke: "currentColor",
9406
+ strokeWidth: "1.8",
9407
+ strokeLinecap: "round",
9408
+ strokeLinejoin: "round",
9409
+ "aria-hidden": "true",
9410
+ children: [/* @__PURE__ */ jsx("path", { d: "M6.8 9.2a3 3 0 0 0 4.2 0l2-2a3 3 0 0 0-4.2-4.2l-1 1" }), /* @__PURE__ */ jsx("path", { d: "M9.2 6.8a3 3 0 0 0-4.2 0l-2 2a3 3 0 0 0 4.2 4.2l1-1" })]
9411
+ });
9412
+ }
9413
+ /** A checkout the session wrote into besides its own, stacked above the
9414
+ * session bar so that one stays put next to the composer. The same readout
9415
+ * as the session bar, minus the controls that act on the session (auto-fix, update,
9416
+ * merge, cleanup), which live with the checkout the session was opened on. */
9417
+ function LinkedRepositoryBar({ repository, t, openDiff, report }) {
9418
+ const key = repository.root ?? repository.cwd;
9419
+ if (repository.status !== "ready") return /* @__PURE__ */ jsxs("div", {
9420
+ style: {
9421
+ ...repositoryBar,
9422
+ ...repositoryBarLinked
9423
+ },
9424
+ "data-dsh-claude-linked-repository": key,
9425
+ children: [/* @__PURE__ */ jsx(StatusGlyph, {
9426
+ label: t("repositoryLinked"),
9427
+ tone: "neutral",
9428
+ children: /* @__PURE__ */ jsx(LinkIcon, {})
9429
+ }), /* @__PURE__ */ jsxs("span", {
9430
+ style: repositoryPrimary,
9431
+ children: [
9432
+ repositoryLabel(repository),
9433
+ " · ",
9434
+ repository.status === "not-repository" ? t("repositoryNotGit") : t("repositoryUnavailable")
9435
+ ]
9436
+ })]
9437
+ });
9438
+ const branch = branchLabel(repository, t);
9439
+ const pullRequest = repository.pullRequest;
9440
+ const merged = pullRequest?.state === "merged";
9441
+ const hasDiff = repository.diff !== void 0 && (repository.diff.additions > 0 || repository.diff.deletions > 0);
9442
+ return /* @__PURE__ */ jsxs("div", {
9443
+ style: {
9444
+ ...repositoryBar,
9445
+ ...repositoryBarLinked,
9446
+ ...merged ? repositoryBarMerged : {}
9447
+ },
9448
+ "data-dsh-claude-linked-repository": key,
9449
+ children: [
9450
+ /* @__PURE__ */ jsx(StatusGlyph, {
9451
+ label: t("repositoryLinked"),
9452
+ tone: "neutral",
9453
+ children: /* @__PURE__ */ jsx(LinkIcon, {})
9454
+ }),
9455
+ /* @__PURE__ */ jsx(PullRequestLink, {
9456
+ repository,
9457
+ t
9458
+ }),
9459
+ /* @__PURE__ */ jsx("span", {
9460
+ style: repositoryRemote,
9461
+ children: repositoryLabel(repository)
9462
+ }),
9463
+ /* @__PURE__ */ jsx(Tooltip, {
9464
+ label: branch,
9465
+ side: "top",
9466
+ delayMs: 250,
9467
+ maxWidth: 420,
9468
+ children: /* @__PURE__ */ jsx("span", {
9469
+ style: repositoryBranch,
9470
+ children: branch
9471
+ })
9472
+ }),
9473
+ repository.worktree === true ? /* @__PURE__ */ jsx("span", {
9474
+ style: repositoryWorktree,
9475
+ children: t("repositoryWorktree")
9476
+ }) : null,
9477
+ /* @__PURE__ */ jsxs("span", {
9478
+ style: repositoryStatusItems,
9479
+ children: [hasDiff && repository.diff !== void 0 ? /* @__PURE__ */ jsxs("button", {
9480
+ type: "button",
9481
+ style: {
9482
+ ...diffTrigger,
9483
+ ...merged ? diffTriggerMuted : {}
9484
+ },
9485
+ onClick: () => openDiff(repository.root),
9486
+ "aria-label": t("diffOpen"),
9487
+ children: [/* @__PURE__ */ jsxs("span", {
9488
+ style: merged ? diffAddMuted : diffAdd,
9489
+ children: ["+", repository.diff.additions]
9490
+ }), /* @__PURE__ */ jsxs("span", {
9491
+ style: merged ? diffDeleteMuted : diffDelete,
9492
+ children: ["−", repository.diff.deletions]
9493
+ })]
9494
+ }) : null, pullRequest === void 0 ? null : merged ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("span", {
9495
+ style: repositoryMergedStatus,
9496
+ children: [/* @__PURE__ */ jsx("span", {
9497
+ style: repositoryMergedDot,
9498
+ "aria-hidden": "true"
9499
+ }), t("repositoryState_merged")]
9500
+ }), /* @__PURE__ */ jsx(CleanupControl, {
9501
+ repository,
9502
+ t,
9503
+ report
9504
+ })] }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [pullRequest.checks === "none" ? null : /* @__PURE__ */ jsx(StatusGlyph, {
9505
+ label: t(`repositoryChecks_${pullRequest.checks}`),
9506
+ tone: pullRequest.checks === "passing" ? "success" : pullRequest.checks === "failing" ? "error" : "warning",
9507
+ children: /* @__PURE__ */ jsx(ChecksGlyph, { state: pullRequest.checks })
9508
+ }), pullRequest.review === "none" ? null : /* @__PURE__ */ jsx(StatusGlyph, {
9509
+ label: t(`repositoryReview_${pullRequest.review}`),
9510
+ tone: pullRequest.review === "approved" ? "success" : pullRequest.review === "changes-requested" ? "error" : "neutral",
9511
+ children: /* @__PURE__ */ jsx(ReviewGlyph, {})
9512
+ })] })]
9513
+ })
9514
+ ]
9515
+ });
9516
+ }
9253
9517
  function ClaudeRepositoryStatus({ sessionId, useSessions, useClaudeProjection, t, openDiff, submitPrompt, openOverview, deleteWorkspace }) {
9254
9518
  const blank = useSessions((value) => value.byId[sessionId]?.blank === true);
9255
9519
  const running = useSessions((value) => value.byId[sessionId]?.running === true);
@@ -9264,10 +9528,16 @@ window.__ModuleLoader__.load({
9264
9528
  const aheadCount = repository.ahead ?? 0;
9265
9529
  const pushable = repository.remote !== void 0 && repository.detached !== true && (aheadCount > 0 || repository.upstream === false);
9266
9530
  const hasDiff = repository.diff !== void 0 && (repository.diff.additions > 0 || repository.diff.deletions > 0);
9267
- if (repository.status !== "ready") return /* @__PURE__ */ jsx("div", {
9531
+ const linked = (projection.repositories ?? []).map((item) => /* @__PURE__ */ jsx(LinkedRepositoryBar, {
9532
+ repository: item,
9533
+ t,
9534
+ openDiff,
9535
+ report
9536
+ }, item.root ?? item.cwd));
9537
+ if (repository.status !== "ready") return /* @__PURE__ */ jsxs("div", {
9268
9538
  style: repositoryBarFrame,
9269
9539
  [CLAUDE_COMPOSER_BAR_ATTRIBUTE]: "",
9270
- children: /* @__PURE__ */ jsxs("div", {
9540
+ children: [linked, /* @__PURE__ */ jsxs("div", {
9271
9541
  style: repositoryBar,
9272
9542
  children: [/* @__PURE__ */ jsx("span", {
9273
9543
  style: repositoryPrIcon,
@@ -9276,145 +9546,149 @@ window.__ModuleLoader__.load({
9276
9546
  style: repositoryPrimary,
9277
9547
  children: repository.status === "not-repository" ? t("repositoryNotGit") : t("repositoryUnavailable")
9278
9548
  })]
9279
- })
9549
+ })]
9280
9550
  });
9281
9551
  return /* @__PURE__ */ jsxs("div", {
9282
9552
  style: repositoryBarFrame,
9283
9553
  [CLAUDE_COMPOSER_BAR_ATTRIBUTE]: "",
9284
- children: [toast, /* @__PURE__ */ jsxs("div", {
9285
- style: {
9286
- ...repositoryBar,
9287
- ...merged ? repositoryBarMerged : {}
9288
- },
9289
- children: [
9290
- openOverview === void 0 ? /* @__PURE__ */ jsx("span", {
9291
- style: {
9292
- ...repositoryPrIcon,
9293
- ...merged ? repositoryPrIconMerged : {}
9294
- },
9295
- children: /* @__PURE__ */ jsx(PullRequestIcon, { merged })
9296
- }) : /* @__PURE__ */ jsx("button", {
9297
- type: "button",
9298
- style: {
9299
- ...repositoryPrIcon,
9300
- ...merged ? repositoryPrIconMerged : {},
9301
- ...repositoryPrIconButton
9302
- },
9303
- "aria-label": t("overviewOpen"),
9304
- title: t("overviewOpen"),
9305
- onClick: openOverview,
9306
- children: /* @__PURE__ */ jsx(PullRequestIcon, { merged })
9307
- }),
9308
- /* @__PURE__ */ jsx(PullRequestLink, {
9309
- repository,
9310
- t
9311
- }),
9312
- repository.remote === void 0 ? null : /* @__PURE__ */ jsx("span", {
9313
- style: repositoryRemote,
9314
- children: repositoryName(repository.remote)
9315
- }),
9316
- /* @__PURE__ */ jsx(Tooltip, {
9317
- label: branch,
9318
- side: "top",
9319
- delayMs: 250,
9320
- maxWidth: 420,
9321
- children: /* @__PURE__ */ jsx("span", {
9322
- style: repositoryBranch,
9323
- children: branch
9324
- })
9325
- }),
9326
- repository.worktree === true ? /* @__PURE__ */ jsx("span", {
9327
- style: repositoryWorktree,
9328
- children: t("repositoryWorktree")
9329
- }) : null,
9330
- /* @__PURE__ */ jsxs("span", {
9331
- style: repositoryStatusItems,
9332
- children: [
9333
- /* @__PURE__ */ jsx(ConflictControl, {
9334
- sessionId,
9335
- repository,
9336
- t,
9337
- report,
9338
- ...submitPrompt === void 0 ? {} : { submitPrompt }
9339
- }),
9340
- hasDiff || pushable ? /* @__PURE__ */ jsxs("button", {
9341
- type: "button",
9342
- style: {
9343
- ...diffTrigger,
9344
- ...merged ? diffTriggerMuted : {}
9345
- },
9346
- onClick: openDiff,
9347
- "aria-label": t("diffOpen"),
9348
- children: [hasDiff && repository.diff !== void 0 ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("span", {
9349
- style: merged ? diffAddMuted : diffAdd,
9350
- children: ["+", repository.diff.additions]
9351
- }), /* @__PURE__ */ jsxs("span", {
9352
- style: merged ? diffDeleteMuted : diffDelete,
9353
- children: ["−", repository.diff.deletions]
9354
- })] }) : null, pushable ? /* @__PURE__ */ jsxs("span", {
9355
- style: merged ? diffAheadMuted : diffAhead,
9356
- children: ["↑", aheadCount > 0 ? aheadCount : ""]
9357
- }) : null]
9358
- }) : null,
9359
- pullRequest === void 0 ? null : merged ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("span", {
9360
- style: repositoryMergedStatus,
9361
- children: [
9362
- /* @__PURE__ */ jsx("span", {
9363
- style: repositoryMergedDot,
9364
- "aria-hidden": "true"
9365
- }),
9366
- t("repositoryState_merged"),
9367
- mergedAge === void 0 ? null : /* @__PURE__ */ jsxs("span", {
9368
- style: repositoryMergedAge,
9369
- children: ["· ", t("repositoryMergedAgo", { age: mergedAge })]
9370
- })
9371
- ]
9372
- }), /* @__PURE__ */ jsx(CleanupControl, {
9373
- repository,
9374
- t,
9375
- report,
9376
- ...deleteWorkspace === void 0 ? {} : { deleteWorkspace }
9377
- })] }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
9378
- pullRequest.checks === "failing" ? /* @__PURE__ */ jsx(FailingChecksControl, {
9379
- sessionId,
9380
- pullNumber: pullRequest.number,
9381
- t,
9382
- ...submitPrompt === void 0 ? {} : { submitPrompt }
9383
- }) : pullRequest.checks === "none" ? null : /* @__PURE__ */ jsx(StatusGlyph, {
9384
- label: t(`repositoryChecks_${pullRequest.checks}`),
9385
- tone: pullRequest.checks === "passing" ? "success" : "warning",
9386
- children: /* @__PURE__ */ jsx(ChecksGlyph, { state: pullRequest.checks })
9387
- }),
9388
- pullRequest.review === "none" ? null : /* @__PURE__ */ jsx(StatusGlyph, {
9389
- label: t(`repositoryReview_${pullRequest.review}`),
9390
- tone: pullRequest.review === "approved" ? "success" : pullRequest.review === "changes-requested" ? "error" : "neutral",
9391
- children: /* @__PURE__ */ jsx(ReviewGlyph, {})
9392
- }),
9393
- /* @__PURE__ */ jsx(AutoFixControl, {
9394
- sessionId,
9395
- repository,
9396
- running,
9397
- t,
9398
- ...submitPrompt === void 0 ? {} : { submitPrompt }
9399
- }),
9400
- /* @__PURE__ */ jsx(UpdateBranchControl, {
9554
+ children: [
9555
+ toast,
9556
+ linked,
9557
+ /* @__PURE__ */ jsxs("div", {
9558
+ style: {
9559
+ ...repositoryBar,
9560
+ ...merged ? repositoryBarMerged : {}
9561
+ },
9562
+ children: [
9563
+ openOverview === void 0 ? /* @__PURE__ */ jsx("span", {
9564
+ style: {
9565
+ ...repositoryPrIcon,
9566
+ ...merged ? repositoryPrIconMerged : {}
9567
+ },
9568
+ children: /* @__PURE__ */ jsx(PullRequestIcon, { merged })
9569
+ }) : /* @__PURE__ */ jsx("button", {
9570
+ type: "button",
9571
+ style: {
9572
+ ...repositoryPrIcon,
9573
+ ...merged ? repositoryPrIconMerged : {},
9574
+ ...repositoryPrIconButton
9575
+ },
9576
+ "aria-label": t("overviewOpen"),
9577
+ title: t("overviewOpen"),
9578
+ onClick: openOverview,
9579
+ children: /* @__PURE__ */ jsx(PullRequestIcon, { merged })
9580
+ }),
9581
+ /* @__PURE__ */ jsx(PullRequestLink, {
9582
+ repository,
9583
+ t
9584
+ }),
9585
+ repository.remote === void 0 ? null : /* @__PURE__ */ jsx("span", {
9586
+ style: repositoryRemote,
9587
+ children: repositoryName(repository.remote)
9588
+ }),
9589
+ /* @__PURE__ */ jsx(Tooltip, {
9590
+ label: branch,
9591
+ side: "top",
9592
+ delayMs: 250,
9593
+ maxWidth: 420,
9594
+ children: /* @__PURE__ */ jsx("span", {
9595
+ style: repositoryBranch,
9596
+ children: branch
9597
+ })
9598
+ }),
9599
+ repository.worktree === true ? /* @__PURE__ */ jsx("span", {
9600
+ style: repositoryWorktree,
9601
+ children: t("repositoryWorktree")
9602
+ }) : null,
9603
+ /* @__PURE__ */ jsxs("span", {
9604
+ style: repositoryStatusItems,
9605
+ children: [
9606
+ /* @__PURE__ */ jsx(ConflictControl, {
9401
9607
  sessionId,
9402
9608
  repository,
9403
9609
  t,
9404
9610
  report,
9405
9611
  ...submitPrompt === void 0 ? {} : { submitPrompt }
9406
9612
  }),
9407
- /* @__PURE__ */ jsx(MergePullRequestControl, {
9408
- sessionId,
9613
+ hasDiff || pushable ? /* @__PURE__ */ jsxs("button", {
9614
+ type: "button",
9615
+ style: {
9616
+ ...diffTrigger,
9617
+ ...merged ? diffTriggerMuted : {}
9618
+ },
9619
+ onClick: () => openDiff(),
9620
+ "aria-label": t("diffOpen"),
9621
+ children: [hasDiff && repository.diff !== void 0 ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("span", {
9622
+ style: merged ? diffAddMuted : diffAdd,
9623
+ children: ["+", repository.diff.additions]
9624
+ }), /* @__PURE__ */ jsxs("span", {
9625
+ style: merged ? diffDeleteMuted : diffDelete,
9626
+ children: ["−", repository.diff.deletions]
9627
+ })] }) : null, pushable ? /* @__PURE__ */ jsxs("span", {
9628
+ style: merged ? diffAheadMuted : diffAhead,
9629
+ children: ["↑", aheadCount > 0 ? aheadCount : ""]
9630
+ }) : null]
9631
+ }) : null,
9632
+ pullRequest === void 0 ? null : merged ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("span", {
9633
+ style: repositoryMergedStatus,
9634
+ children: [
9635
+ /* @__PURE__ */ jsx("span", {
9636
+ style: repositoryMergedDot,
9637
+ "aria-hidden": "true"
9638
+ }),
9639
+ t("repositoryState_merged"),
9640
+ mergedAge === void 0 ? null : /* @__PURE__ */ jsxs("span", {
9641
+ style: repositoryMergedAge,
9642
+ children: ["· ", t("repositoryMergedAgo", { age: mergedAge })]
9643
+ })
9644
+ ]
9645
+ }), /* @__PURE__ */ jsx(CleanupControl, {
9409
9646
  repository,
9410
9647
  t,
9411
- report
9412
- })
9413
- ] })
9414
- ]
9415
- })
9416
- ]
9417
- })]
9648
+ report,
9649
+ ...deleteWorkspace === void 0 ? {} : { deleteWorkspace }
9650
+ })] }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
9651
+ pullRequest.checks === "failing" ? /* @__PURE__ */ jsx(FailingChecksControl, {
9652
+ sessionId,
9653
+ pullNumber: pullRequest.number,
9654
+ t,
9655
+ ...submitPrompt === void 0 ? {} : { submitPrompt }
9656
+ }) : pullRequest.checks === "none" ? null : /* @__PURE__ */ jsx(StatusGlyph, {
9657
+ label: t(`repositoryChecks_${pullRequest.checks}`),
9658
+ tone: pullRequest.checks === "passing" ? "success" : "warning",
9659
+ children: /* @__PURE__ */ jsx(ChecksGlyph, { state: pullRequest.checks })
9660
+ }),
9661
+ pullRequest.review === "none" ? null : /* @__PURE__ */ jsx(StatusGlyph, {
9662
+ label: t(`repositoryReview_${pullRequest.review}`),
9663
+ tone: pullRequest.review === "approved" ? "success" : pullRequest.review === "changes-requested" ? "error" : "neutral",
9664
+ children: /* @__PURE__ */ jsx(ReviewGlyph, {})
9665
+ }),
9666
+ /* @__PURE__ */ jsx(AutoFixControl, {
9667
+ sessionId,
9668
+ repository,
9669
+ running,
9670
+ t,
9671
+ ...submitPrompt === void 0 ? {} : { submitPrompt }
9672
+ }),
9673
+ /* @__PURE__ */ jsx(UpdateBranchControl, {
9674
+ sessionId,
9675
+ repository,
9676
+ t,
9677
+ report,
9678
+ ...submitPrompt === void 0 ? {} : { submitPrompt }
9679
+ }),
9680
+ /* @__PURE__ */ jsx(MergePullRequestControl, {
9681
+ sessionId,
9682
+ repository,
9683
+ t,
9684
+ report
9685
+ })
9686
+ ] })
9687
+ ]
9688
+ })
9689
+ ]
9690
+ })
9691
+ ]
9418
9692
  });
9419
9693
  }
9420
9694
  //#endregion
@@ -14644,12 +14918,50 @@ window.__ModuleLoader__.load({
14644
14918
  children: /* @__PURE__ */ jsx("path", { d: "M1.5 5h3V2h1.4v4.4H1.5V5Zm9.9-3h1.4v3h3v1.4h-4.4V2ZM1.5 9.6h4.4V14H4.5v-3h-3V9.6Zm9.9 0h4.4V11h-3v3h-1.4V9.6Z" })
14645
14919
  });
14646
14920
  }
14647
- function ClaudeDiffPanel({ useClaudeProjection, t, sessionId, maximized, closeDetails, toggleMaximized, submitPrompt }) {
14921
+ function hasChanges(repository) {
14922
+ return (repository?.diff?.additions ?? 0) > 0 || (repository?.diff?.deletions ?? 0) > 0;
14923
+ }
14924
+ /** The checkouts a session can show: its own first, then the ones it wrote into. */
14925
+ function panelRepositories(projection) {
14926
+ return [projection.repository, ...projection.repositories ?? []].filter((item) => item !== void 0);
14927
+ }
14928
+ function ClaudeDiffPanel({ useClaudeProjection, t, sessionId, maximized, closeDetails, toggleMaximized, submitPrompt, initialRoot }) {
14648
14929
  const projection = useClaudeProjection((value) => value);
14649
- const repository = projection.repository;
14930
+ const repositories = useMemo(() => panelRepositories(projection), [projection]);
14931
+ const [selectedRoot, setSelectedRoot] = useState(() => initialRoot ?? (hasChanges(projection.repository) ? void 0 : repositories.find(hasChanges)?.root));
14932
+ const repository = repositories.find((item) => item.root === selectedRoot) ?? projection.repository;
14933
+ const root = repository === projection.repository ? void 0 : repository?.root;
14650
14934
  const diff = repository?.diff;
14651
14935
  const files = useMemo(() => parseUnifiedDiff(diff?.patch ?? ""), [diff?.patch]);
14652
14936
  const [menuOpen, setMenuOpen] = useState(false);
14937
+ const [repositoryMenuOpen, setRepositoryMenuOpen] = useState(false);
14938
+ const repositoryItems = useMemo(() => repositories.map((item) => ({
14939
+ id: item.root ?? item.cwd,
14940
+ label: /* @__PURE__ */ jsxs("span", {
14941
+ style: diffRepositoryRow,
14942
+ children: [
14943
+ /* @__PURE__ */ jsx("span", {
14944
+ style: diffRepositoryRowName,
14945
+ children: repositoryLabel(item)
14946
+ }),
14947
+ " ",
14948
+ /* @__PURE__ */ jsxs("span", {
14949
+ style: diffRepositoryRowCounts,
14950
+ children: [
14951
+ /* @__PURE__ */ jsxs("span", {
14952
+ style: diffAdd,
14953
+ children: ["+", item.diff?.additions ?? 0]
14954
+ }),
14955
+ " ",
14956
+ /* @__PURE__ */ jsxs("span", {
14957
+ style: diffDelete,
14958
+ children: ["−", item.diff?.deletions ?? 0]
14959
+ })
14960
+ ]
14961
+ })
14962
+ ]
14963
+ })
14964
+ })), [repositories]);
14653
14965
  const { toast, report } = useActionToast();
14654
14966
  const [dialog, setDialog] = useState();
14655
14967
  const [message, setMessage] = useState("");
@@ -14672,14 +14984,18 @@ window.__ModuleLoader__.load({
14672
14984
  setGhThreads([]);
14673
14985
  if (pullNumber === void 0) return;
14674
14986
  const controller = new AbortController();
14675
- loadPullRequestThreads(sessionId, pullNumber, controller.signal).then((threads) => {
14987
+ loadPullRequestThreads(sessionId, pullNumber, controller.signal, root).then((threads) => {
14676
14988
  setGhThreads(threads);
14677
14989
  setThreadsLoadedAt(Date.now());
14678
14990
  }, () => void 0);
14679
14991
  return () => {
14680
14992
  controller.abort();
14681
14993
  };
14682
- }, [pullNumber, sessionId]);
14994
+ }, [
14995
+ pullNumber,
14996
+ root,
14997
+ sessionId
14998
+ ]);
14683
14999
  const openThreadCount = ghThreads.filter((thread) => !thread.resolved).length;
14684
15000
  const bodyRef = useRef(null);
14685
15001
  const [targetIndex, setTargetIndex] = useState(0);
@@ -14690,25 +15006,37 @@ window.__ModuleLoader__.load({
14690
15006
  const setFileOpen = useCallback((path, open) => {
14691
15007
  setOpenFiles((current) => new Map(current).set(path, open));
14692
15008
  }, []);
14693
- const suggestMention = useCallback(async (query) => pullNumber === void 0 ? [] : loadMentionableUsers(sessionId, pullNumber, query).catch(() => []), [pullNumber, sessionId]);
15009
+ const suggestMention = useCallback(async (query) => pullNumber === void 0 ? [] : loadMentionableUsers(sessionId, pullNumber, query, void 0, root).catch(() => []), [
15010
+ pullNumber,
15011
+ root,
15012
+ sessionId
15013
+ ]);
14694
15014
  const replyToThread = useCallback(async (thread, body) => {
14695
15015
  if (pullNumber === void 0) return;
14696
15016
  const anchor = thread.comments[0];
14697
15017
  if (anchor === void 0) return;
14698
- const posted = await replyToReviewThread(sessionId, pullNumber, anchor.id, body);
15018
+ const posted = await replyToReviewThread(sessionId, pullNumber, anchor.id, body, root);
14699
15019
  setGhThreads((list) => list.map((item) => item.id === thread.id ? {
14700
15020
  ...item,
14701
15021
  comments: [...item.comments, posted]
14702
15022
  } : item));
14703
- }, [pullNumber, sessionId]);
15023
+ }, [
15024
+ pullNumber,
15025
+ root,
15026
+ sessionId
15027
+ ]);
14704
15028
  const changeThreadResolved = useCallback(async (thread, resolved) => {
14705
15029
  if (pullNumber === void 0) return;
14706
- const state = await setReviewThreadResolved(sessionId, pullNumber, thread.id, resolved);
15030
+ const state = await setReviewThreadResolved(sessionId, pullNumber, thread.id, resolved, root);
14707
15031
  setGhThreads((list) => list.map((item) => item.id === thread.id ? {
14708
15032
  ...item,
14709
15033
  resolved: state
14710
15034
  } : item));
14711
- }, [pullNumber, sessionId]);
15035
+ }, [
15036
+ pullNumber,
15037
+ root,
15038
+ sessionId
15039
+ ]);
14712
15040
  const diffViewportObserver = useRef();
14713
15041
  const diffBodyRef = useCallback((element) => {
14714
15042
  diffViewportObserver.current?.disconnect();
@@ -14743,7 +15071,7 @@ window.__ModuleLoader__.load({
14743
15071
  setDraft(true);
14744
15072
  const controller = new AbortController();
14745
15073
  actionController.current = controller;
14746
- loadRepositoryActionPreview(sessionId, controller.signal).then(async (preview) => {
15074
+ loadRepositoryActionPreview(sessionId, controller.signal, root).then(async (preview) => {
14747
15075
  setIncludeUnstaged(preview.hasUnstaged || preview.hasUntracked);
14748
15076
  if (action === "push") {
14749
15077
  setDialog({
@@ -14760,7 +15088,7 @@ window.__ModuleLoader__.load({
14760
15088
  loading: true,
14761
15089
  submitting: false
14762
15090
  });
14763
- const generated = await generateCommitMessage(sessionId, preview.fingerprint, controller.signal);
15091
+ const generated = await generateCommitMessage(sessionId, preview.fingerprint, controller.signal, root);
14764
15092
  setMessage((current) => current.trim() === "" ? generated : current);
14765
15093
  setPrTitle((current) => current.trim() === "" ? generated : current);
14766
15094
  setPrBody((current) => current.trim() === "" ? `Summary: ${generated}\n\nChanges:\n- ${generated}` : current);
@@ -14776,7 +15104,11 @@ window.__ModuleLoader__.load({
14776
15104
  error: error instanceof Error ? error.message : t("diffActionFailed")
14777
15105
  });
14778
15106
  });
14779
- }, [sessionId, t]);
15107
+ }, [
15108
+ root,
15109
+ sessionId,
15110
+ t
15111
+ ]);
14780
15112
  const confirm = useCallback(async () => {
14781
15113
  if (dialog?.preview === void 0 || dialog.action !== "push" && message.trim().length === 0) return;
14782
15114
  const { error: _error, ...pending } = dialog;
@@ -14796,7 +15128,7 @@ window.__ModuleLoader__.load({
14796
15128
  ...baseBranch.trim() === "" ? {} : { baseBranch },
14797
15129
  draft
14798
15130
  } : {}
14799
- });
15131
+ }, root);
14800
15132
  report(result.pullRequestUrl === void 0 ? t(dialog.action === "push" ? "diffPushCompleted" : "diffCommitCompleted", { commit: result.commit.slice(0, 8) }) : t("diffPrCompleted"));
14801
15133
  setDialog(void 0);
14802
15134
  } catch (error) {
@@ -14817,6 +15149,7 @@ window.__ModuleLoader__.load({
14817
15149
  prBody,
14818
15150
  prTitle,
14819
15151
  report,
15152
+ root,
14820
15153
  sessionId,
14821
15154
  t
14822
15155
  ]);
@@ -15015,7 +15348,8 @@ window.__ModuleLoader__.load({
15015
15348
  diffModalCss,
15016
15349
  panelIconButtonCss,
15017
15350
  diffCommentCss,
15018
- diffCommentMarkdownCss
15351
+ diffCommentMarkdownCss,
15352
+ diffRepositoryCss
15019
15353
  ]
15020
15354
  }),
15021
15355
  /* @__PURE__ */ jsxs("div", {
@@ -15029,20 +15363,34 @@ window.__ModuleLoader__.load({
15029
15363
  style: diffHeader,
15030
15364
  children: [/* @__PURE__ */ jsxs("div", {
15031
15365
  style: diffHeaderTitle,
15032
- children: [
15033
- /* @__PURE__ */ jsx("span", {
15034
- style: diffHeaderBranch,
15035
- children: branch
15036
- }),
15037
- /* @__PURE__ */ jsx("span", {
15038
- "aria-hidden": "true",
15039
- children: "›"
15040
- }),
15041
- /* @__PURE__ */ jsx("span", {
15042
- style: diffHeaderLabel,
15043
- children: t("diffWorkingTree")
15366
+ children: [repositories.length < 2 ? null : /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Menu, {
15367
+ open: repositoryMenuOpen,
15368
+ items: repositoryItems,
15369
+ selectedId: repository.root ?? repository.cwd,
15370
+ onSelect: (id) => {
15371
+ setSelectedRoot(id);
15372
+ setRepositoryMenuOpen(false);
15373
+ },
15374
+ onClose: () => setRepositoryMenuOpen(false),
15375
+ portal: true,
15376
+ compact: true,
15377
+ anchor: /* @__PURE__ */ jsxs("button", {
15378
+ type: "button",
15379
+ className: diffRepositoryTriggerClass,
15380
+ "aria-label": t("diffRepository"),
15381
+ "aria-haspopup": "menu",
15382
+ "aria-expanded": repositoryMenuOpen,
15383
+ onClick: () => setRepositoryMenuOpen((value) => !value),
15384
+ children: [/* @__PURE__ */ jsx("span", { children: repositoryLabel(repository) }), /* @__PURE__ */ jsx(IconChevronDownOutline14, {})]
15044
15385
  })
15045
- ]
15386
+ }), /* @__PURE__ */ jsx("span", {
15387
+ "aria-hidden": "true",
15388
+ children: "›"
15389
+ })] }), /* @__PURE__ */ jsx("span", {
15390
+ style: diffHeaderBranch,
15391
+ title: branch,
15392
+ children: branch
15393
+ })]
15046
15394
  }), /* @__PURE__ */ jsxs("div", {
15047
15395
  style: diffHeaderActions,
15048
15396
  children: [
@@ -17589,10 +17937,13 @@ window.__ModuleLoader__.load({
17589
17937
  })
17590
17938
  });
17591
17939
  }
17940
+ function diffTotal(projection, key) {
17941
+ return [projection.repository, ...projection.repositories ?? []].reduce((sum, repository) => sum + (repository?.diff?.[key] ?? 0), 0);
17942
+ }
17592
17943
  function ClaudeDiffHeaderAction({ t, sessionId, toggleDiff, diffOpen, useClaudeProjection }) {
17593
17944
  const owned = useClaudeProjection((projection) => projection.owned);
17594
- const additions = useClaudeProjection((projection) => projection.repository?.diff?.additions ?? 0);
17595
- const deletions = useClaudeProjection((projection) => projection.repository?.diff?.deletions ?? 0);
17945
+ const additions = useClaudeProjection((projection) => diffTotal(projection, "additions"));
17946
+ const deletions = useClaudeProjection((projection) => diffTotal(projection, "deletions"));
17596
17947
  const open = useSyncExternalStore(diffOpen.subscribe, diffOpen.getSnapshot, diffOpen.getSnapshot);
17597
17948
  if (!owned) return null;
17598
17949
  ensureCss$2();
@@ -18939,7 +19290,8 @@ window.__ModuleLoader__.load({
18939
19290
  promptSaveExists: "已有同名提示词,换个名字。",
18940
19291
  promptSaveFailed: "保存失败:{message}",
18941
19292
  presetHeaderHint: "当前会话运行的 Agent 预设",
18942
- diffWorkingTree: "分支改动",
19293
+ diffRepository: "仓库",
19294
+ repositoryLinked: "关联仓库:本会话改动过",
18943
19295
  diffFiles: "{count} 个已修改文件",
18944
19296
  diffFilesShort: "{count} 个文件",
18945
19297
  diffTruncated: "Diff 超出安全显示上限。请在终端中查看完整内容。",
@@ -18990,6 +19342,7 @@ window.__ModuleLoader__.load({
18990
19342
  diffMerge_squash: "Squash 合并",
18991
19343
  diffMerge_rebase: "Rebase 合并",
18992
19344
  diffMergeDescription: "使用所选方式合并当前分支的 Pull Request。",
19345
+ diffMergeAdmin: "以管理员身份合并(绕过分支保护)",
18993
19346
  diffMergeCompleted: "已合并 PR #{number}",
18994
19347
  diffUpdateBranch: "Update branch…",
18995
19348
  repositoryUpdateBranch: "Update branch",
@@ -19381,7 +19734,8 @@ window.__ModuleLoader__.load({
19381
19734
  promptSaveExists: "A prompt with that name already exists. Try another.",
19382
19735
  promptSaveFailed: "Could not save: {message}",
19383
19736
  presetHeaderHint: "The agent preset this session runs",
19384
- diffWorkingTree: "Branch changes",
19737
+ diffRepository: "Repository",
19738
+ repositoryLinked: "Linked repository: changed by this session",
19385
19739
  diffFiles: "{count} modified file(s)",
19386
19740
  diffFilesShort: "{count} files",
19387
19741
  diffTruncated: "The diff exceeds the safe display limit. Use the terminal to inspect the complete content.",
@@ -19432,6 +19786,7 @@ window.__ModuleLoader__.load({
19432
19786
  diffMerge_squash: "Squash and merge",
19433
19787
  diffMerge_rebase: "Rebase and merge",
19434
19788
  diffMergeDescription: "Merge the pull request for this branch with the selected method.",
19789
+ diffMergeAdmin: "Merge as administrator (bypass branch protection)",
19435
19790
  diffMergeCompleted: "Merged PR #{number}",
19436
19791
  diffUpdateBranch: "Update branch…",
19437
19792
  repositoryUpdateBranch: "Update branch",
@@ -19594,7 +19949,7 @@ window.__ModuleLoader__.load({
19594
19949
  };
19595
19950
  //#endregion
19596
19951
  //#region src/client/index.tsx
19597
- function MaximizedDiff({ source, t, sessionId, closeDetails, restore, submitPrompt }) {
19952
+ function MaximizedDiff({ source, t, sessionId, closeDetails, restore, submitPrompt, initialRoot }) {
19598
19953
  const snapshot = useSyncExternalStore(source.subscribe, source.getSnapshot, source.getSnapshot);
19599
19954
  const useClaudeProjection = (selector) => selector(snapshot);
19600
19955
  return /* @__PURE__ */ jsx(ClaudePanelOverlay, {
@@ -19606,7 +19961,8 @@ window.__ModuleLoader__.load({
19606
19961
  maximized: true,
19607
19962
  closeDetails,
19608
19963
  toggleMaximized: restore,
19609
- ...submitPrompt === void 0 ? {} : { submitPrompt }
19964
+ ...submitPrompt === void 0 ? {} : { submitPrompt },
19965
+ ...initialRoot === void 0 ? {} : { initialRoot }
19610
19966
  })
19611
19967
  });
19612
19968
  }
@@ -19878,7 +20234,7 @@ window.__ModuleLoader__.load({
19878
20234
  layout?.openDetails();
19879
20235
  disposeExpandedDetailsResize = enableExpandedDetailsResize();
19880
20236
  };
19881
- const openDiffPanel = (sessionId) => {
20237
+ const openDiffPanel = (sessionId, initialRoot) => {
19882
20238
  closePluginDetails();
19883
20239
  detailsSessionId = sessionId;
19884
20240
  const submitPrompt = submitPromptFor(sessionId);
@@ -19894,7 +20250,8 @@ window.__ModuleLoader__.load({
19894
20250
  maximized: false,
19895
20251
  closeDetails: closePluginDetails,
19896
20252
  toggleMaximized: maximizeDiff,
19897
- ...submitPrompt === void 0 ? {} : { submitPrompt }
20253
+ ...submitPrompt === void 0 ? {} : { submitPrompt },
20254
+ ...initialRoot === void 0 ? {} : { initialRoot }
19898
20255
  })
19899
20256
  }, ClaudeDiffPanel);
19900
20257
  } catch {
@@ -19923,7 +20280,8 @@ window.__ModuleLoader__.load({
19923
20280
  sessionId,
19924
20281
  closeDetails: closePluginDetails,
19925
20282
  restore: restoreDiff,
19926
- ...submitPrompt === void 0 ? {} : { submitPrompt }
20283
+ ...submitPrompt === void 0 ? {} : { submitPrompt },
20284
+ ...initialRoot === void 0 ? {} : { initialRoot }
19927
20285
  }));
19928
20286
  } catch {
19929
20287
  disposeDiffOverlay = void 0;
@@ -20076,7 +20434,7 @@ window.__ModuleLoader__.load({
20076
20434
  const submitPrompt = submitPromptFor(sessionId);
20077
20435
  return {
20078
20436
  t,
20079
- openDiff: () => openDiffPanel(sessionId),
20437
+ openDiff: (root) => openDiffPanel(sessionId, root),
20080
20438
  ...submitPrompt === void 0 ? {} : { submitPrompt },
20081
20439
  ...sessions === void 0 ? {} : { openOverview: () => openOverviewPanel(sessionId) },
20082
20440
  ...workspaces === void 0 ? {} : { deleteWorkspace: async () => {