botmux 2.76.1 → 2.78.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/core/command-handler.d.ts.map +1 -1
  2. package/dist/core/command-handler.js +2 -1
  3. package/dist/core/command-handler.js.map +1 -1
  4. package/dist/core/session-manager.d.ts.map +1 -1
  5. package/dist/core/session-manager.js +40 -38
  6. package/dist/core/session-manager.js.map +1 -1
  7. package/dist/core/worker-pool.d.ts +41 -0
  8. package/dist/core/worker-pool.d.ts.map +1 -1
  9. package/dist/core/worker-pool.js +94 -1
  10. package/dist/core/worker-pool.js.map +1 -1
  11. package/dist/daemon.d.ts.map +1 -1
  12. package/dist/daemon.js +12 -5
  13. package/dist/daemon.js.map +1 -1
  14. package/dist/dashboard/web/i18n.d.ts.map +1 -1
  15. package/dist/dashboard/web/i18n.js +10 -0
  16. package/dist/dashboard/web/i18n.js.map +1 -1
  17. package/dist/dashboard/web/settings.d.ts.map +1 -1
  18. package/dist/dashboard/web/settings.js +19 -0
  19. package/dist/dashboard/web/settings.js.map +1 -1
  20. package/dist/dashboard-web/app.js +111 -100
  21. package/dist/dashboard.js +11 -2
  22. package/dist/dashboard.js.map +1 -1
  23. package/dist/global-config.d.ts +11 -0
  24. package/dist/global-config.d.ts.map +1 -1
  25. package/dist/global-config.js +13 -0
  26. package/dist/global-config.js.map +1 -1
  27. package/dist/i18n/en.d.ts.map +1 -1
  28. package/dist/i18n/en.js +4 -1
  29. package/dist/i18n/en.js.map +1 -1
  30. package/dist/i18n/zh.d.ts.map +1 -1
  31. package/dist/i18n/zh.js +4 -1
  32. package/dist/i18n/zh.js.map +1 -1
  33. package/dist/im/lark/card-builder.d.ts.map +1 -1
  34. package/dist/im/lark/card-builder.js +91 -11
  35. package/dist/im/lark/card-builder.js.map +1 -1
  36. package/dist/im/lark/card-handler.d.ts.map +1 -1
  37. package/dist/im/lark/card-handler.js +156 -106
  38. package/dist/im/lark/card-handler.js.map +1 -1
  39. package/dist/im/lark/client.d.ts.map +1 -1
  40. package/dist/im/lark/client.js +19 -11
  41. package/dist/im/lark/client.js.map +1 -1
  42. package/dist/services/project-scanner.d.ts +5 -2
  43. package/dist/services/project-scanner.d.ts.map +1 -1
  44. package/dist/services/project-scanner.js +9 -6
  45. package/dist/services/project-scanner.js.map +1 -1
  46. package/dist/services/resumable-session-discovery.d.ts.map +1 -1
  47. package/dist/services/resumable-session-discovery.js +8 -4
  48. package/dist/services/resumable-session-discovery.js.map +1 -1
  49. package/package.json +1 -1
@@ -22,6 +22,7 @@ import { forkWorker, killWorker, scheduleCardPatch, parkStreamCard, clearUsageLi
22
22
  import { getSessionWorkingDir, buildNewTopicPrompt, getAvailableBots, persistStreamCardState, resumeSession, rememberLastCliInput } from '../../core/session-manager.js';
23
23
  import { publishAttentionPatch } from '../../core/session-activity.js';
24
24
  import { fallbackTurnId } from '../../core/reply-target.js';
25
+ import { validateWorkingDir } from '../../core/working-dir.js';
25
26
  import { sessionKey, sessionAnchorId, frozenDisplayMode } from '../../core/types.js';
26
27
  import { buildTerminalUrl } from '../../core/terminal-url.js';
27
28
  import { createRepoWorktree } from '../../services/git-worktree.js';
@@ -90,6 +91,125 @@ function validateCardCliBinding(ds, value) {
90
91
  `action=${value?.action ?? '?'} expected=${expected} actual=${actual}`);
91
92
  return false;
92
93
  }
94
+ /**
95
+ * Commit a resolved working directory onto a repo-select session: pin it, then
96
+ * either fork the pending CLI (first selection) or close + recreate the session
97
+ * (mid-session switch). Shared by the dropdown flow, the worktree flow (which
98
+ * funnels back in with the freshly created worktree path) and the manual
99
+ * directory-entry form. Extracted to module scope so the form-submit branch can
100
+ * reuse the exact same spawn/switch path instead of duplicating it.
101
+ */
102
+ async function commitRepoSelection(ctx, dirPath, dirLabel,
103
+ // The worktree flow already posted a precise "worktree 已创建:path 分支 …"
104
+ // line before funnelling in here — suppress the redundant "已选择/已切换"
105
+ // confirmation so the user sees a single message, not two.
106
+ opts) {
107
+ const { ds, rootId, cardMessageId, larkAppId, activeSessions, sessionReply } = ctx;
108
+ const locTarget = localeForBot(ds.larkAppId);
109
+ // `/close` deletes the active-map entry without touching sessionId or
110
+ // pendingRepo — identity against the map is the only tell that the session
111
+ // this flow captured is gone. Checked alongside the generation snapshots.
112
+ const repoSessionKey = larkAppId ? sessionKey(rootId, larkAppId) : rootId;
113
+ const sessionStillActive = () => activeSessions.get(repoSessionKey) === ds;
114
+ const commitGenSessionId = ds.session.sessionId;
115
+ ds.workingDir = dirPath;
116
+ ds.session.workingDir = dirPath;
117
+ sessionStore.updateSession(ds.session);
118
+ if (ds.pendingRepo) {
119
+ const selfBot = getBot(ds.larkAppId);
120
+ const botCfg = selfBot.config;
121
+ const effectiveCliId = sessionCliId(ds);
122
+ // First-time repo selection — now spawn CLI with the original prompt
123
+ ds.pendingRepo = false;
124
+ publishAttentionPatch(ds);
125
+ const pendingPrompt = ds.pendingPrompt ?? '';
126
+ const pendingRawInput = ds.pendingRawInput;
127
+ // Raw-input cold start still wraps any input buffered while the repo card
128
+ // was pending — see the skip_repo branch for the rationale.
129
+ const hasBufferedInput = pendingPrompt.trim().length > 0 ||
130
+ (ds.pendingAttachments?.length ?? 0) > 0 ||
131
+ (ds.pendingFollowUps?.length ?? 0) > 0;
132
+ const wrappedPrompt = (!pendingRawInput || hasBufferedInput)
133
+ ? buildNewTopicPrompt(pendingPrompt, ds.session.sessionId, effectiveCliId, botCfg.cliPathOverride, ds.pendingAttachments, ds.pendingMentions, await getAvailableBots(ds.larkAppId, ds.chatId), ds.pendingFollowUps, { name: selfBot.botName, openId: selfBot.botOpenId }, locTarget, ds.pendingSender, { larkAppId: ds.larkAppId, chatId: ds.chatId })
134
+ : '';
135
+ const prompt = pendingRawInput ? '' : wrappedPrompt;
136
+ // Last-line defence: prompt prep awaited above — if anything replaced
137
+ // OR closed the session in that window, forking now would clobber it
138
+ // (or resurrect a /close'd session).
139
+ if (!sessionStillActive() || ds.session.sessionId !== commitGenSessionId) {
140
+ logger.warn(`[${tag(ds)}] Session replaced or closed while preparing the pending-CLI prompt (${commitGenSessionId} → ${ds.session.sessionId}, active=${sessionStillActive()}) — aborting this fork`);
141
+ return;
142
+ }
143
+ if (pendingRawInput && hasBufferedInput) {
144
+ ds.pendingFollowUpInput = {
145
+ userPrompt: pendingPrompt || (ds.pendingFollowUps?.join('\n\n') ?? ''),
146
+ cliInput: wrappedPrompt,
147
+ };
148
+ }
149
+ rememberLastCliInput(ds, pendingRawInput ?? pendingPrompt, pendingRawInput ?? prompt);
150
+ ds.pendingPrompt = undefined;
151
+ ds.pendingAttachments = undefined;
152
+ ds.pendingMentions = undefined;
153
+ ds.pendingSender = undefined;
154
+ ds.pendingFollowUps = undefined;
155
+ forkWorker(ds, prompt);
156
+ // A card click has no turn of its own — anchor the confirmation to the
157
+ // session's current reply-target turn so a shared fold-back topic keeps
158
+ // it in-thread (same leak as the /repo command path).
159
+ if (!opts?.suppressConfirmReply) {
160
+ await sessionReply(rootId, t('cmd.repo.selected_in_pending', { name: dirLabel }, locTarget), undefined, fallbackTurnId(ds, undefined));
161
+ }
162
+ logger.info(`[${tag(ds)}] Repo selected: ${dirPath}, spawning CLI`);
163
+ }
164
+ else {
165
+ // Mid-session repo switch — close old session, start fresh.
166
+ killWorker(ds);
167
+ // Park the current card in `frozenCards` so the next POST under the new
168
+ // session sweeps it via recall. closeSession() wipes the on-disk
169
+ // frozen-cards file under the OLD sessionId, but the in-memory Map
170
+ // travels with `ds` into the new session and still carries the
171
+ // old messageId for deletion. If fork or POST fails, the parked card
172
+ // stays in the thread instead of vanishing prematurely.
173
+ parkStreamCard(ds);
174
+ sessionStore.closeSession(ds.session.sessionId);
175
+ const session = sessionStore.createSession(ds.chatId, rootId, dirLabel, ds.chatType);
176
+ ds.session = session;
177
+ ds.lastUserPrompt = undefined;
178
+ ds.lastCliInput = undefined;
179
+ // Pin workingDir + larkAppId onto the new session before forkWorker.
180
+ // Without this, a daemon restart restores the session with an empty
181
+ // workingDir and the worker spawns in the bot's default cwd, so
182
+ // `claude --resume` looks in the wrong .claude/projects/<hash>/ dir and
183
+ // exits code 0 immediately, crash-looping until the rate-limiter trips.
184
+ ds.session.workingDir = dirPath;
185
+ ds.session.larkAppId = ds.larkAppId;
186
+ sessionStore.updateSession(ds.session);
187
+ ds.hasHistory = false;
188
+ // Re-persist the parked card under the NEW sessionId so a daemon crash
189
+ // before the next POST doesn't strand it. closeSession() above wiped
190
+ // the on-disk file under the OLD sessionId; without this re-save, the
191
+ // in-memory Map only survives in process memory.
192
+ if (ds.frozenCards && ds.frozenCards.size > 0) {
193
+ saveFrozenCards(ds.session.sessionId, ds.frozenCards);
194
+ }
195
+ // Drop the old turn's streaming-card reference so worker_ready POSTs a
196
+ // fresh card for the new session instead of PATCHing the previous one.
197
+ ds.streamCardId = undefined;
198
+ ds.streamCardNonce = undefined;
199
+ ds.streamCardPending = undefined;
200
+ ds.lastScreenContent = undefined;
201
+ ds.lastScreenStatus = undefined;
202
+ forkWorker(ds, '', false);
203
+ if (!opts?.suppressConfirmReply) {
204
+ await sessionReply(rootId, t('cmd.repo.switched_to', { name: dirLabel }, locTarget));
205
+ }
206
+ logger.info(`[${tag(ds)}] Repo switched to ${dirPath}, new session created`);
207
+ }
208
+ // Withdraw the repo selection card
209
+ if (cardMessageId && larkAppId)
210
+ deleteMessage(larkAppId, cardMessageId);
211
+ ds.repoCardMessageId = undefined;
212
+ }
93
213
  // ─── Main handler ─────────────────────────────────────────────────────────
94
214
  export async function handleCardAction(data, deps, larkAppId) {
95
215
  const { activeSessions, lastRepoScan } = deps;
@@ -602,7 +722,7 @@ export async function handleCardAction(data, deps, larkAppId) {
602
722
  }
603
723
  return { toast: { type: 'success', content: t('card.relay.toast_success', undefined, loc) } };
604
724
  }
605
- const isSensitive = value?.action && ['restart', 'close', 'resume', 'skip_repo', 'retry_last_task', 'get_write_link', 'toggle_stream', 'toggle_display', 'export_text', 'term_action', 'refresh_screenshot', 'takeover', 'disconnect', 'tui_keys', 'tui_text_input', 'wf_approve', 'wf_reject', 'wf_cancel'].includes(value.action);
725
+ const isSensitive = value?.action && ['restart', 'close', 'resume', 'skip_repo', 'repo_manual_submit', 'retry_last_task', 'get_write_link', 'toggle_stream', 'toggle_display', 'export_text', 'term_action', 'refresh_screenshot', 'takeover', 'disconnect', 'tui_keys', 'tui_text_input', 'wf_approve', 'wf_reject', 'wf_cancel'].includes(value.action);
606
726
  if (isSensitive) {
607
727
  const rootId = value?.root_id;
608
728
  // activeSessions is keyed by sessionKey(anchor, larkAppId) — `${anchor}::${larkAppId}`
@@ -623,9 +743,9 @@ export async function handleCardAction(data, deps, larkAppId) {
623
743
  : undefined;
624
744
  const effectiveAppId = larkAppId ?? ds?.larkAppId ?? closedForCtx?.larkAppId;
625
745
  const chatId = ds?.chatId ?? closedForCtx?.chatId;
626
- // pendingRepo 阶段,会话发起人(含 chat-granted 用户)可以 skip_repo 起会话——
627
- // repo 下拉选择同款例外,否则被授权人连自己的首次会话都启动不了。
628
- const pendingRepoOwnerException = value.action === 'skip_repo' && !!ds?.pendingRepo &&
746
+ // pendingRepo 阶段,会话发起人(含 chat-granted 用户)可以 skip_repo / 手动填目录
747
+ // 起会话——与 repo 下拉选择同款例外,否则被授权人连自己的首次会话都启动不了。
748
+ const pendingRepoOwnerException = (value.action === 'skip_repo' || value.action === 'repo_manual_submit') && !!ds?.pendingRepo &&
629
749
  !!operatorOpenId && operatorOpenId === ds.session.ownerOpenId;
630
750
  if (effectiveAppId) {
631
751
  if (!pendingRepoOwnerException && !canOperate(effectiveAppId, chatId, operatorOpenId)) {
@@ -1201,6 +1321,30 @@ export async function handleCardAction(data, deps, larkAppId) {
1201
1321
  deleteMessage(larkAppId, cardMessageId);
1202
1322
  ds.repoCardMessageId = undefined;
1203
1323
  }
1324
+ // Manual working-directory entry from the repo card form. The project scan
1325
+ // may not surface every useful directory; this mirrors `/repo <path>` from
1326
+ // the card. Permission is gated at the top (isSensitive + pendingRepoOwner
1327
+ // exception), same as skip_repo. Always a plain commit — worktree creation
1328
+ // needs a scanned git repo root, not an arbitrary path.
1329
+ if (actionType === 'repo_manual_submit' && ds) {
1330
+ const locDs = localeForBot(ds.larkAppId);
1331
+ const rawPath = String(action?.form_value?.repo_manual_path ?? '').trim();
1332
+ if (!rawPath) {
1333
+ return { toast: { type: 'error', content: t('card.repo.manual_empty', undefined, locDs) } };
1334
+ }
1335
+ const validation = validateWorkingDir(rawPath, locDs);
1336
+ if (!validation.ok) {
1337
+ return { toast: { type: 'error', content: validation.error } };
1338
+ }
1339
+ // A worktree creation in flight holds the commit lock — a manual switch
1340
+ // interleaving there would double-fork (same guard as the plain switch).
1341
+ if (ds.worktreeCreating) {
1342
+ return { toast: { type: 'info', content: t('cmd.repo.worktree_in_progress', undefined, locDs) } };
1343
+ }
1344
+ const selectedPath = validation.resolvedPath;
1345
+ const displayName = pathBasename(selectedPath) || selectedPath;
1346
+ await commitRepoSelection({ ds, rootId, cardMessageId, larkAppId, activeSessions, sessionReply }, selectedPath, displayName);
1347
+ }
1204
1348
  return;
1205
1349
  }
1206
1350
  // Handle dropdown selections (option-based)
@@ -1398,106 +1542,10 @@ export async function handleCardAction(data, deps, larkAppId) {
1398
1542
  // this flow captured is gone. Checked alongside the generation snapshots.
1399
1543
  const repoSessionKey = sessionKey(rootId, larkAppId);
1400
1544
  const sessionStillActive = () => activeSessions.get(repoSessionKey) === targetDs;
1401
- // Shared commit path for a resolved directory: pin it on the session, then
1402
- // either fork the pending CLI (first selection) or close + recreate the
1403
- // session (mid-session switch). The worktree flow funnels back in here with
1404
- // the freshly created worktree path.
1405
- const commitSelection = async (dirPath, dirLabel) => {
1406
- const commitGenSessionId = targetDs.session.sessionId;
1407
- targetDs.workingDir = dirPath;
1408
- targetDs.session.workingDir = dirPath;
1409
- sessionStore.updateSession(targetDs.session);
1410
- if (targetDs.pendingRepo) {
1411
- const selfBot = getBot(targetDs.larkAppId);
1412
- const botCfg = selfBot.config;
1413
- const effectiveCliId = sessionCliId(targetDs);
1414
- // First-time repo selection — now spawn CLI with the original prompt
1415
- targetDs.pendingRepo = false;
1416
- publishAttentionPatch(targetDs);
1417
- const pendingPrompt = targetDs.pendingPrompt ?? '';
1418
- const pendingRawInput = targetDs.pendingRawInput;
1419
- // Raw-input cold start still wraps any input buffered while the repo card
1420
- // was pending — see the skip_repo branch above for the rationale.
1421
- const hasBufferedInput = pendingPrompt.trim().length > 0 ||
1422
- (targetDs.pendingAttachments?.length ?? 0) > 0 ||
1423
- (targetDs.pendingFollowUps?.length ?? 0) > 0;
1424
- const wrappedPrompt = (!pendingRawInput || hasBufferedInput)
1425
- ? buildNewTopicPrompt(pendingPrompt, targetDs.session.sessionId, effectiveCliId, botCfg.cliPathOverride, targetDs.pendingAttachments, targetDs.pendingMentions, await getAvailableBots(targetDs.larkAppId, targetDs.chatId), targetDs.pendingFollowUps, { name: selfBot.botName, openId: selfBot.botOpenId }, locTarget, targetDs.pendingSender, { larkAppId: targetDs.larkAppId, chatId: targetDs.chatId })
1426
- : '';
1427
- const prompt = pendingRawInput ? '' : wrappedPrompt;
1428
- // Last-line defence: prompt prep awaited above — if anything replaced
1429
- // OR closed the session in that window, forking now would clobber it
1430
- // (or resurrect a /close'd session).
1431
- if (!sessionStillActive() || targetDs.session.sessionId !== commitGenSessionId) {
1432
- logger.warn(`[${tag(targetDs)}] Session replaced or closed while preparing the pending-CLI prompt (${commitGenSessionId} → ${targetDs.session.sessionId}, active=${sessionStillActive()}) — aborting this fork`);
1433
- return;
1434
- }
1435
- if (pendingRawInput && hasBufferedInput) {
1436
- targetDs.pendingFollowUpInput = {
1437
- userPrompt: pendingPrompt || (targetDs.pendingFollowUps?.join('\n\n') ?? ''),
1438
- cliInput: wrappedPrompt,
1439
- };
1440
- }
1441
- rememberLastCliInput(targetDs, pendingRawInput ?? pendingPrompt, pendingRawInput ?? prompt);
1442
- targetDs.pendingPrompt = undefined;
1443
- targetDs.pendingAttachments = undefined;
1444
- targetDs.pendingMentions = undefined;
1445
- targetDs.pendingSender = undefined;
1446
- targetDs.pendingFollowUps = undefined;
1447
- forkWorker(targetDs, prompt);
1448
- // A card click has no turn of its own — anchor the confirmation to the
1449
- // session's current reply-target turn so a shared fold-back topic keeps
1450
- // it in-thread (same leak as the /repo command path).
1451
- await sessionReply(rootId, t('cmd.repo.selected_in_pending', { name: dirLabel }, locTarget), undefined, fallbackTurnId(targetDs, undefined));
1452
- logger.info(`[${tag(targetDs)}] Repo selected: ${dirPath}, spawning CLI`);
1453
- }
1454
- else {
1455
- // Mid-session repo switch — close old session, start fresh.
1456
- killWorker(targetDs);
1457
- // Park the current card in `frozenCards` so the next POST under the new
1458
- // session sweeps it via recall. closeSession() wipes the on-disk
1459
- // frozen-cards file under the OLD sessionId, but the in-memory Map
1460
- // travels with `targetDs` into the new session and still carries the
1461
- // old messageId for deletion. If fork or POST fails, the parked card
1462
- // stays in the thread instead of vanishing prematurely.
1463
- parkStreamCard(targetDs);
1464
- sessionStore.closeSession(targetDs.session.sessionId);
1465
- const session = sessionStore.createSession(targetDs.chatId, rootId, dirLabel, targetDs.chatType);
1466
- targetDs.session = session;
1467
- targetDs.lastUserPrompt = undefined;
1468
- targetDs.lastCliInput = undefined;
1469
- // Pin workingDir + larkAppId onto the new session before forkWorker.
1470
- // Without this, a daemon restart restores the session with an empty
1471
- // workingDir and the worker spawns in the bot's default cwd, so
1472
- // `claude --resume` looks in the wrong .claude/projects/<hash>/ dir and
1473
- // exits code 0 immediately, crash-looping until the rate-limiter trips.
1474
- targetDs.session.workingDir = dirPath;
1475
- targetDs.session.larkAppId = targetDs.larkAppId;
1476
- sessionStore.updateSession(targetDs.session);
1477
- targetDs.hasHistory = false;
1478
- // Re-persist the parked card under the NEW sessionId so a daemon crash
1479
- // before the next POST doesn't strand it. closeSession() above wiped
1480
- // the on-disk file under the OLD sessionId; without this re-save, the
1481
- // in-memory Map only survives in process memory.
1482
- if (targetDs.frozenCards && targetDs.frozenCards.size > 0) {
1483
- saveFrozenCards(targetDs.session.sessionId, targetDs.frozenCards);
1484
- }
1485
- // Drop the old turn's streaming-card reference so worker_ready POSTs a
1486
- // fresh card for the new session instead of PATCHing the previous one.
1487
- targetDs.streamCardId = undefined;
1488
- targetDs.streamCardNonce = undefined;
1489
- targetDs.streamCardPending = undefined;
1490
- targetDs.lastScreenContent = undefined;
1491
- targetDs.lastScreenStatus = undefined;
1492
- forkWorker(targetDs, '', false);
1493
- await sessionReply(rootId, t('cmd.repo.switched_to', { name: dirLabel }, locTarget));
1494
- logger.info(`[${tag(targetDs)}] Repo switched to ${dirPath}, new session created`);
1495
- }
1496
- // Withdraw the repo selection card
1497
- if (cardMessageId && larkAppId)
1498
- deleteMessage(larkAppId, cardMessageId);
1499
- targetDs.repoCardMessageId = undefined;
1500
- };
1545
+ // Shared commit context for a resolved directory funnels the dropdown,
1546
+ // worktree and manual-entry flows through the same module-level
1547
+ // commitRepoSelection (pin dir, then fork pending CLI or close+recreate).
1548
+ const commitCtx = { ds: targetDs, rootId, cardMessageId, larkAppId, activeSessions, sessionReply };
1501
1549
  if (isWorktreeOpen) {
1502
1550
  // Worktree creation involves a `git fetch` that can take many seconds —
1503
1551
  // ack the card action immediately with a toast and finish asynchronously.
@@ -1544,7 +1592,9 @@ export async function handleCardAction(data, deps, larkAppId) {
1544
1592
  if (sessionChanged())
1545
1593
  return notSwitched(creation, 'during reply');
1546
1594
  try {
1547
- await commitSelection(creation.path, `${pathBasename(creation.path)} (${creation.branch})`);
1595
+ // The "worktree 已创建:…" notice above already confirms the switch —
1596
+ // suppress commitRepoSelection's own "已选择/已切换" to avoid a dup.
1597
+ await commitRepoSelection(commitCtx, creation.path, `${pathBasename(creation.path)} (${creation.branch})`, { suppressConfirmReply: true });
1548
1598
  }
1549
1599
  catch (e) {
1550
1600
  // The worktree DOES exist at this point — only the switch failed.
@@ -1567,6 +1617,6 @@ export async function handleCardAction(data, deps, larkAppId) {
1567
1617
  if (targetDs.worktreeCreating) {
1568
1618
  return { toast: { type: 'info', content: t('cmd.repo.worktree_in_progress', undefined, locTarget) } };
1569
1619
  }
1570
- await commitSelection(selectedPath, displayName);
1620
+ await commitRepoSelection(commitCtx, selectedPath, displayName);
1571
1621
  }
1572
1622
  //# sourceMappingURL=card-handler.js.map