@loicngr/kobo 2.1.2 → 2.1.5
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/CHANGELOG.md +12 -0
- package/CONFIGURATION.md +11 -3
- package/dist/server/index.js +24 -91
- package/dist/server/routes/git.js +6 -7
- package/dist/server/routes/settings.js +21 -11
- package/dist/server/routes/workspaces.js +82 -41
- package/dist/server/services/agent/engines/claude-code/engine.js +87 -20
- package/dist/server/services/agent/engines/claude-code/event-mapper.js +88 -22
- package/dist/server/services/agent/engines/claude-code/options-builder.js +1 -0
- package/dist/server/services/agent/engines/codex/engine.js +27 -5
- package/dist/server/services/agent/engines/codex/options-builder.js +1 -0
- package/dist/server/services/agent/integration-mcp.js +4 -3
- package/dist/server/services/agent/orchestrator.js +36 -1
- package/dist/server/services/agent/session-controller.js +12 -0
- package/dist/server/services/engine-handoff-service.js +120 -24
- package/dist/server/services/pr-checkout-service.js +90 -53
- package/dist/server/services/pr-watcher-service.js +13 -7
- package/dist/server/services/retention/worker.js +40 -0
- package/dist/server/services/review-service.js +8 -4
- package/dist/server/services/session-event-metrics.js +43 -0
- package/dist/server/services/session-handoff-service.js +6 -4
- package/dist/server/services/templates-service.js +67 -49
- package/dist/server/services/terminal-service.js +45 -14
- package/dist/server/services/terminal-websocket-service.js +143 -0
- package/dist/server/services/wakeup-service.js +23 -21
- package/dist/server/services/workspace-service.js +3 -44
- package/dist/server/services/workspace-template-service.js +16 -18
- package/dist/server/services/worktree-purge-service.js +1 -4
- package/dist/server/services/ws-events-retention-service.js +197 -104
- package/dist/server/services/ws-events-retention-worker-service.js +112 -0
- package/dist/server/utils/atomic-json-file.js +23 -0
- package/dist/server/utils/git-ops.js +262 -60
- package/dist/shared/codex-models.js +20 -3
- package/dist/shared/models.js +12 -0
- package/package.json +8 -8
- package/src/client/dist/pwa/assets/{ActivityFeed-DCmiJP-z.css → ActivityFeed-B4lTKMVE.css} +1 -1
- package/src/client/dist/pwa/assets/ActivityFeed-DXWXioW9.js +8 -0
- package/src/client/dist/pwa/assets/ChangelogPage-BL5Jh8-v.js +1 -0
- package/src/client/dist/pwa/assets/ChangelogPage-DVyx9ZjV.css +1 -0
- package/src/client/dist/pwa/assets/{ClosePopup-BikuzYle.js → ClosePopup-C1a82pL9.js} +1 -1
- package/src/client/dist/pwa/assets/ComparisonPanel-Bv2SZrVZ.js +2 -0
- package/src/client/dist/pwa/assets/ComparisonPanel-ByVbqYCs.css +1 -0
- package/src/client/dist/pwa/assets/CreatePage-CMyl2j8Z.css +1 -0
- package/src/client/dist/pwa/assets/CreatePage-d43ITOC1.js +2 -0
- package/src/client/dist/pwa/assets/DashboardPage-BEXXRguE.js +1 -0
- package/src/client/dist/pwa/assets/DashboardPage-CtaHaVdf.css +1 -0
- package/src/client/dist/pwa/assets/DiffViewer-B92w_jd7.js +8 -0
- package/src/client/dist/pwa/assets/DocumentsPanel-C9JXyqHg.js +1 -0
- package/src/client/dist/pwa/assets/{DrawerToggleButton-Dfvkaro0.js → DrawerToggleButton-Btx8QwHo.js} +1 -1
- package/src/client/dist/pwa/assets/{GitPanel-C4wOcZV2.css → GitPanel-C3blk_Pd.css} +1 -1
- package/src/client/dist/pwa/assets/GitPanel-Cgz9crLN.js +3 -0
- package/src/client/dist/pwa/assets/HealthPage-CDhgJQkL.js +1 -0
- package/src/client/dist/pwa/assets/HealthPage-DT8FGrKA.css +1 -0
- package/src/client/dist/pwa/assets/MainLayout-DTTtj9sq.js +2 -0
- package/src/client/dist/pwa/assets/{MainLayout-gHENJEFQ.css → MainLayout-knNNtkre.css} +1 -1
- package/src/client/dist/pwa/assets/QBadge-rGILsUYl.js +1 -0
- package/src/client/dist/pwa/assets/QBanner-7EWRdc4U.js +1 -0
- package/src/client/dist/pwa/assets/QBtn-b_baQtAt.js +1 -0
- package/src/client/dist/pwa/assets/QBtnDropdown-vjat4GZl.js +1 -0
- package/src/client/dist/pwa/assets/QBtnGroup-CUmAgBV8.js +1 -0
- package/src/client/dist/pwa/assets/QBtnToggle-COL46j6W.js +1 -0
- package/src/client/dist/pwa/assets/QChip-CG1kWhFm.js +1 -0
- package/src/client/dist/pwa/assets/QExpansionItem-BQuy89vv.js +1 -0
- package/src/client/dist/pwa/assets/QItemSection-BrVklYfM.js +1 -0
- package/src/client/dist/pwa/assets/QList-BVX-b8nc.js +1 -0
- package/src/client/dist/pwa/assets/QMarkupTable-B8_FKLvo.js +1 -0
- package/src/client/dist/pwa/assets/QPage-BCDXjfVj.js +1 -0
- package/src/client/dist/pwa/assets/QSelect-DBW_TZri.js +1 -0
- package/src/client/dist/pwa/assets/QSpinnerDots-BsKmccpX.js +1 -0
- package/src/client/dist/pwa/assets/QTooltip-DzYbguTR.js +1 -0
- package/src/client/dist/pwa/assets/SchedulePanel-BX6iKh6S.js +1 -0
- package/src/client/dist/pwa/assets/SchedulePanel-CBM_GpS3.css +1 -0
- package/src/client/dist/pwa/assets/SearchPage-_In2gH2P.js +1 -0
- package/src/client/dist/pwa/assets/SettingsPage-BqkNYzC5.js +9 -0
- package/src/client/dist/pwa/assets/{SettingsPage-BYdLXJEJ.css → SettingsPage-CpykRKq2.css} +1 -1
- package/src/client/dist/pwa/assets/SplitWorkspacePage-DRoXbSRP.js +1 -0
- package/src/client/dist/pwa/assets/{TerminalPanel-B9LDe7uG.js → TerminalPanel-CfqiuSuk.js} +2 -2
- package/src/client/dist/pwa/assets/{TerminalPanel-DbVZk0vD.css → TerminalPanel-Dz9EE-Ph.css} +1 -1
- package/src/client/dist/pwa/assets/TouchPan-DcOCRf7x.js +1 -0
- package/src/client/dist/pwa/assets/{TourReplayButton-Dtv_UDaY.js → TourReplayButton-gp7m6tSV.js} +1 -1
- package/src/client/dist/pwa/assets/WorkspaceAttentionLabels-DSw8Upcp.css +1 -0
- package/src/client/dist/pwa/assets/WorkspaceAttentionLabels-IcoMGkJh.js +1 -0
- package/src/client/dist/pwa/assets/{WorkspacePage--5HsnMQ1.css → WorkspacePage-BnW-gp3u.css} +1 -1
- package/src/client/dist/pwa/assets/WorkspacePage-CR2xAzW_.js +4 -0
- package/src/client/dist/pwa/assets/{browser-B15GGwtW.js → browser-BveHkbe-.js} +1 -1
- package/src/client/dist/pwa/assets/build-path-tree-Dtp7rlxS.js +1 -0
- package/src/client/dist/pwa/assets/custom-sounds-CBoWzJ85.js +1 -0
- package/src/client/dist/pwa/assets/de-BJsWkZro.js +17 -0
- package/src/client/dist/pwa/assets/defineProperty-BbfpZ9Tg.js +1 -0
- package/src/client/dist/pwa/assets/documents-sb2sQ4JC.js +1 -0
- package/src/client/dist/pwa/assets/{editor.api-DhaLhNl-.js → editor.api-CbkPxoJf.js} +1 -1
- package/src/client/dist/pwa/assets/efforts-BCli1Unj.js +9 -0
- package/src/client/dist/pwa/assets/es-tNYw7itB.js +17 -0
- package/src/client/dist/pwa/assets/expand-template-CfaEhb2f.js +1 -0
- package/src/client/dist/pwa/assets/{format-2JisC3s1.js → format-BRl2DUlm.js} +7 -7
- package/src/client/dist/pwa/assets/formatters-C5TjPSR_.js +1 -0
- package/src/client/dist/pwa/assets/fr-B5sFski4.js +17 -0
- package/src/client/dist/pwa/assets/{freemarker2-PYrDqU04.js → freemarker2-CDmvOQyn.js} +1 -1
- package/src/client/dist/pwa/assets/{handlebars-BuiY0fFf.js → handlebars-Bx_w8mx1.js} +1 -1
- package/src/client/dist/pwa/assets/{html-Du3cjdug.js → html-DVRfiRkS.js} +1 -1
- package/src/client/dist/pwa/assets/i18n-Bm-L4nW3.js +1 -0
- package/src/client/dist/pwa/assets/i18n-D21JKsVt.js +19 -0
- package/src/client/dist/pwa/assets/index-C7vFf6p2.js +2 -0
- package/src/client/dist/pwa/assets/index-C8zAZ-k-.css +1 -0
- package/src/client/dist/pwa/assets/it-Bc2FncM9.js +17 -0
- package/src/client/dist/pwa/assets/{javascript-Bb48hPli.js → javascript-CPvttU5J.js} +1 -1
- package/src/client/dist/pwa/assets/latest-request-CN4-B22z.js +1 -0
- package/src/client/dist/pwa/assets/{liquid-Be77iQe3.js → liquid-CI0gQddb.js} +1 -1
- package/src/client/dist/pwa/assets/{mdx-CfohNJja.js → mdx-BveBwYJH.js} +1 -1
- package/src/client/dist/pwa/assets/{monaco-contributions-CyM4wsIg.js → monaco-contributions-CHXFh4P2.js} +1 -1
- package/src/client/dist/pwa/assets/monaco.contribution-DOK8t_9B.js +2 -0
- package/src/client/dist/pwa/assets/network-auth-CItnNZDh.js +1 -0
- package/src/client/dist/pwa/assets/{notify-theme-DvvaSyg1.js → notify-theme-BO6r1Rd7.js} +1 -1
- package/src/client/dist/pwa/assets/pending-diff-open-DpS4iyDM.js +1 -0
- package/src/client/dist/pwa/assets/{permissionModes-B-ciuUbz.js → permissionModes-Cc5VaOdC.js} +1 -1
- package/src/client/dist/pwa/assets/preload-helper-BZ1Pz5am.js +1 -0
- package/src/client/dist/pwa/assets/{private.use-form-Bk8ti264.js → private.use-form-vxvbh_VN.js} +1 -1
- package/src/client/dist/pwa/assets/{project-color-Be0t12-n.js → project-color-Bnv02P9D.js} +1 -1
- package/src/client/dist/pwa/assets/{python-BNemmtx8.js → python-BesLCxpi.js} +1 -1
- package/src/client/dist/pwa/assets/{razor-3NM8iFVf.js → razor-Dv1PMxuY.js} +1 -1
- package/src/client/dist/pwa/assets/{reactivity.esm-bundler-Bo9anJjg.js → reactivity.esm-bundler-tuEvQ47f.js} +1 -1
- package/src/client/dist/pwa/assets/{render-chat-markdown-BWJNIDv3.js → render-chat-markdown-CafzCcmu.js} +1 -1
- package/src/client/dist/pwa/assets/runtime-core.esm-bundler-DOiZcasU.js +1 -0
- package/src/client/dist/pwa/assets/{typescript-DwyZ4CF7.js → typescript-26L2Xsu9.js} +1 -1
- package/src/client/dist/pwa/assets/use-checkbox-BLeif5-t.js +1 -0
- package/src/client/dist/pwa/assets/use-id-b4A2I8LB.js +1 -0
- package/src/client/dist/pwa/assets/use-is-mobile-DLIZxEo9.js +1 -0
- package/src/client/dist/pwa/assets/use-search-index-status-Mv3pIO6p.js +1 -0
- package/src/client/dist/pwa/assets/{use-slide-transition-CiaDm-tR.js → use-slide-transition-C5eDGOmu.js} +1 -1
- package/src/client/dist/pwa/assets/{use-tours-CjASQcG5.js → use-tours-B5uIqxRS.js} +2 -2
- package/src/client/dist/pwa/assets/use-worktree-restore-BBChALUM.js +1 -0
- package/src/client/dist/pwa/assets/workspace-templates-CDY-MiH2.js +1 -0
- package/src/client/dist/pwa/assets/{xml-B1UujXdS.js → xml-CkRojTcc.js} +1 -1
- package/src/client/dist/pwa/assets/{yaml-mHN8kNgU.js → yaml-DKkQHwew.js} +1 -1
- package/src/client/dist/pwa/index.html +12 -9
- package/src/client/dist/pwa/sw.js +1 -1
- package/src/client/dist/pwa/assets/ActivityFeed-CO5rOaa5.js +0 -8
- package/src/client/dist/pwa/assets/ChangelogPage-DKJkFiU_.css +0 -1
- package/src/client/dist/pwa/assets/ChangelogPage-DNRcPRtW.js +0 -1
- package/src/client/dist/pwa/assets/ComparisonPanel-CRRaDs2D.css +0 -1
- package/src/client/dist/pwa/assets/ComparisonPanel-DZoDqgJI.js +0 -2
- package/src/client/dist/pwa/assets/CreatePage-B9C9J9Pw.css +0 -1
- package/src/client/dist/pwa/assets/CreatePage-wNH35uTG.js +0 -2
- package/src/client/dist/pwa/assets/DashboardPage-DUyy4SzS.js +0 -1
- package/src/client/dist/pwa/assets/DashboardPage-XiCj24i2.css +0 -1
- package/src/client/dist/pwa/assets/DiffViewer-CZ5QwXqi.js +0 -8
- package/src/client/dist/pwa/assets/DocumentsPanel-sBatgKA-.js +0 -1
- package/src/client/dist/pwa/assets/GitPanel-B8e1olfm.js +0 -3
- package/src/client/dist/pwa/assets/HealthPage-BwXYpczh.js +0 -1
- package/src/client/dist/pwa/assets/HealthPage-CFZ-tdKK.css +0 -1
- package/src/client/dist/pwa/assets/MainLayout-DFXIS_wv.js +0 -2
- package/src/client/dist/pwa/assets/QBadge-CQF1smL-.js +0 -1
- package/src/client/dist/pwa/assets/QBanner-bdDA-A5g.js +0 -1
- package/src/client/dist/pwa/assets/QBtn-CcQQrYA_.js +0 -1
- package/src/client/dist/pwa/assets/QBtnDropdown-C-1EhO9J.js +0 -1
- package/src/client/dist/pwa/assets/QBtnGroup-wd5lKRXu.js +0 -1
- package/src/client/dist/pwa/assets/QBtnToggle-BnC8rTql.js +0 -1
- package/src/client/dist/pwa/assets/QChip-D75nKi-L.js +0 -1
- package/src/client/dist/pwa/assets/QExpansionItem-RpMPvfxX.js +0 -1
- package/src/client/dist/pwa/assets/QItemSection-Bt9H35JJ.js +0 -1
- package/src/client/dist/pwa/assets/QList-D5msNbSZ.js +0 -1
- package/src/client/dist/pwa/assets/QMarkupTable-D3REW6RC.js +0 -1
- package/src/client/dist/pwa/assets/QPage-HAaeQ-cv.js +0 -1
- package/src/client/dist/pwa/assets/QSelect-Dpru_T81.js +0 -1
- package/src/client/dist/pwa/assets/QSpinnerDots-DDsPDUH9.js +0 -1
- package/src/client/dist/pwa/assets/QTooltip-C31vXtse.js +0 -1
- package/src/client/dist/pwa/assets/SchedulePanel-BYKSFoFj.css +0 -1
- package/src/client/dist/pwa/assets/SchedulePanel-D6LTiRFg.js +0 -1
- package/src/client/dist/pwa/assets/SearchPage-Dj487BdP.js +0 -1
- package/src/client/dist/pwa/assets/SettingsPage-CJmgFiAa.js +0 -9
- package/src/client/dist/pwa/assets/SplitWorkspacePage-BGSDgGIO.js +0 -1
- package/src/client/dist/pwa/assets/TouchPan-DJqqxDBF.js +0 -1
- package/src/client/dist/pwa/assets/WorkspaceAttentionLabels-CrLP_I5S.css +0 -1
- package/src/client/dist/pwa/assets/WorkspaceAttentionLabels-VlJCIkwU.js +0 -1
- package/src/client/dist/pwa/assets/WorkspacePage-B_SlX8YB.js +0 -4
- package/src/client/dist/pwa/assets/build-path-tree-CU6uXunR.js +0 -1
- package/src/client/dist/pwa/assets/custom-sounds-CDJsgChY.js +0 -1
- package/src/client/dist/pwa/assets/de-B_Y4EArT.js +0 -17
- package/src/client/dist/pwa/assets/documents-Cf6nmu8Z.js +0 -1
- package/src/client/dist/pwa/assets/efforts-DoYZi0AZ.js +0 -9
- package/src/client/dist/pwa/assets/engineFeatures-C9XiCfvv.js +0 -1
- package/src/client/dist/pwa/assets/es-DtsTTShP.js +0 -17
- package/src/client/dist/pwa/assets/expand-template-LDLM-6iN.js +0 -1
- package/src/client/dist/pwa/assets/formatters-ZVNs2VOl.js +0 -1
- package/src/client/dist/pwa/assets/fr-C82MIVrA.js +0 -17
- package/src/client/dist/pwa/assets/i18n-BumeGGx_.js +0 -1
- package/src/client/dist/pwa/assets/index-DolbyIM4.js +0 -20
- package/src/client/dist/pwa/assets/index-VMFLfvp2.css +0 -1
- package/src/client/dist/pwa/assets/it-BJNuTcj2.js +0 -17
- package/src/client/dist/pwa/assets/monaco.contribution-BcIfN6Mi.js +0 -2
- package/src/client/dist/pwa/assets/network-auth-B1xAaHmx.js +0 -1
- package/src/client/dist/pwa/assets/pending-diff-open-B6N0vI5n.js +0 -1
- package/src/client/dist/pwa/assets/pinia-CTJ3OfP3.js +0 -1
- package/src/client/dist/pwa/assets/runtime-core.esm-bundler-CNFKm4ij.js +0 -1
- package/src/client/dist/pwa/assets/use-checkbox-2xzX4yYj.js +0 -1
- package/src/client/dist/pwa/assets/use-id-vOr8PRTG.js +0 -1
- package/src/client/dist/pwa/assets/use-is-mobile-CJfSpTHx.js +0 -1
- package/src/client/dist/pwa/assets/use-search-index-status-Bluf9L99.js +0 -1
- package/src/client/dist/pwa/assets/workspace-templates-BxYxJt3S.js +0 -1
- /package/src/client/dist/pwa/assets/{engineFeatures-B-9jHocY.css → use-worktree-restore-B-9jHocY.css} +0 -0
|
@@ -67,7 +67,7 @@ async function gitAsync(repoPath, args, timeout = READ_ONLY_GIT_TIMEOUT_MS) {
|
|
|
67
67
|
cwd: repoPath,
|
|
68
68
|
encoding: 'utf-8',
|
|
69
69
|
timeout,
|
|
70
|
-
maxBuffer:
|
|
70
|
+
maxBuffer: GIT_MAX_BUFFER_BYTES,
|
|
71
71
|
});
|
|
72
72
|
return stdout.trimEnd();
|
|
73
73
|
}
|
|
@@ -231,6 +231,26 @@ export function deleteRemoteBranch(repoPath, branchName, remote = 'origin') {
|
|
|
231
231
|
throw new Error(`Failed to delete remote branch '${remote}/${branchName}': ${message}`);
|
|
232
232
|
}
|
|
233
233
|
}
|
|
234
|
+
/** Non-blocking local deletion with the synchronous helper's error contract. */
|
|
235
|
+
export async function deleteLocalBranchAsync(repoPath, branchName) {
|
|
236
|
+
try {
|
|
237
|
+
await gitNetworkAsync(repoPath, ['branch', '-D', branchName]);
|
|
238
|
+
}
|
|
239
|
+
catch (error) {
|
|
240
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
241
|
+
throw new Error(`Failed to delete local branch '${branchName}': ${message}`);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
/** Non-blocking remote deletion; keeps credential prompts disabled and the network deadline. */
|
|
245
|
+
export async function deleteRemoteBranchAsync(repoPath, branchName, remote = 'origin') {
|
|
246
|
+
try {
|
|
247
|
+
await gitNetworkAsync(repoPath, ['push', remote, '--delete', branchName]);
|
|
248
|
+
}
|
|
249
|
+
catch (error) {
|
|
250
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
251
|
+
throw new Error(`Failed to delete remote branch '${remote}/${branchName}': ${message}`);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
234
254
|
/**
|
|
235
255
|
* Push a branch to the remote with upstream tracking (`git push -u`).
|
|
236
256
|
* When `options.force` is true, adds `--force-with-lease` (safer than `--force`:
|
|
@@ -341,18 +361,21 @@ export function getConflictedFiles(repoPath) {
|
|
|
341
361
|
return [];
|
|
342
362
|
}
|
|
343
363
|
}
|
|
364
|
+
function classifyOngoingGitOperation(dir) {
|
|
365
|
+
if (existsSync(join(dir, 'MERGE_HEAD')))
|
|
366
|
+
return 'merge';
|
|
367
|
+
if (existsSync(join(dir, 'rebase-merge')) || existsSync(join(dir, 'rebase-apply')))
|
|
368
|
+
return 'rebase';
|
|
369
|
+
if (existsSync(join(dir, 'CHERRY_PICK_HEAD')) || existsSync(join(dir, 'sequencer')))
|
|
370
|
+
return 'cherry-pick';
|
|
371
|
+
return null;
|
|
372
|
+
}
|
|
344
373
|
/** Detect whether a merge, rebase or cherry-pick is currently in progress in the worktree. */
|
|
345
374
|
export function getOngoingGitOperation(repoPath) {
|
|
346
375
|
try {
|
|
347
376
|
const gitDir = git(repoPath, ['rev-parse', '--git-dir']);
|
|
348
377
|
const dir = gitDir.startsWith('/') ? gitDir : join(repoPath, gitDir);
|
|
349
|
-
|
|
350
|
-
return 'merge';
|
|
351
|
-
if (existsSync(join(dir, 'rebase-merge')) || existsSync(join(dir, 'rebase-apply')))
|
|
352
|
-
return 'rebase';
|
|
353
|
-
if (existsSync(join(dir, 'CHERRY_PICK_HEAD')) || existsSync(join(dir, 'sequencer')))
|
|
354
|
-
return 'cherry-pick';
|
|
355
|
-
return null;
|
|
378
|
+
return classifyOngoingGitOperation(dir);
|
|
356
379
|
}
|
|
357
380
|
catch {
|
|
358
381
|
return null;
|
|
@@ -781,6 +804,19 @@ export function getCommitsBetween(repoPath, base, head) {
|
|
|
781
804
|
return '';
|
|
782
805
|
}
|
|
783
806
|
}
|
|
807
|
+
const COMMIT_LOG_FORMAT = '--pretty=format:%H%x00%h%x00%s%x00%an%x00%aI';
|
|
808
|
+
function parseCommitLog(raw) {
|
|
809
|
+
const commits = [];
|
|
810
|
+
for (const line of raw.split('\n')) {
|
|
811
|
+
if (!line)
|
|
812
|
+
continue;
|
|
813
|
+
const [sha, shortSha, subject, author, date] = line.split('\x00');
|
|
814
|
+
if (!sha)
|
|
815
|
+
continue;
|
|
816
|
+
commits.push({ sha, shortSha: shortSha ?? '', subject: subject ?? '', author: author ?? '', date: date ?? '' });
|
|
817
|
+
}
|
|
818
|
+
return commits;
|
|
819
|
+
}
|
|
784
820
|
/**
|
|
785
821
|
* List commits between the source branch and HEAD, each flagged with whether
|
|
786
822
|
* it's already present on `origin/<workingBranch>`. Used by the Git panel
|
|
@@ -791,10 +827,9 @@ export function listBranchCommits(repoPath, sourceBranch, workingBranch, limit =
|
|
|
791
827
|
const sourceRef = resolveBase(repoPath, sourceBranch);
|
|
792
828
|
const remoteRef = `${remote}/${workingBranch}`;
|
|
793
829
|
// NUL-delimited format: sha \0 shortSha \0 subject \0 author \0 iso date \n
|
|
794
|
-
const FORMAT = '--pretty=format:%H%x00%h%x00%s%x00%an%x00%aI';
|
|
795
830
|
let raw;
|
|
796
831
|
try {
|
|
797
|
-
raw = git(repoPath, ['log', `${sourceRef}..HEAD`, `--max-count=${limit}`,
|
|
832
|
+
raw = git(repoPath, ['log', `${sourceRef}..HEAD`, `--max-count=${limit}`, COMMIT_LOG_FORMAT]);
|
|
798
833
|
}
|
|
799
834
|
catch {
|
|
800
835
|
return [];
|
|
@@ -815,23 +850,7 @@ export function listBranchCommits(repoPath, sourceBranch, workingBranch, limit =
|
|
|
815
850
|
catch {
|
|
816
851
|
// remote ref unknown → leave pushedShas empty
|
|
817
852
|
}
|
|
818
|
-
|
|
819
|
-
for (const line of raw.split('\n')) {
|
|
820
|
-
if (!line)
|
|
821
|
-
continue;
|
|
822
|
-
const [sha, shortSha, subject, author, date] = line.split('\x00');
|
|
823
|
-
if (!sha)
|
|
824
|
-
continue;
|
|
825
|
-
commits.push({
|
|
826
|
-
sha,
|
|
827
|
-
shortSha: shortSha ?? '',
|
|
828
|
-
subject: subject ?? '',
|
|
829
|
-
author: author ?? '',
|
|
830
|
-
date: date ?? '',
|
|
831
|
-
isPushed: pushedShas.has(sha),
|
|
832
|
-
});
|
|
833
|
-
}
|
|
834
|
-
return commits;
|
|
853
|
+
return parseCommitLog(raw).map((commit) => ({ ...commit, isPushed: pushedShas.has(commit.sha) }));
|
|
835
854
|
}
|
|
836
855
|
/**
|
|
837
856
|
* List commits on `sourceBranch` that are NOT yet on `workingBranch` —
|
|
@@ -840,32 +859,16 @@ export function listBranchCommits(repoPath, sourceBranch, workingBranch, limit =
|
|
|
840
859
|
*/
|
|
841
860
|
export function listCommitsBehind(repoPath, sourceBranch, workingBranch, limit = 50) {
|
|
842
861
|
const sourceRef = resolveBase(repoPath, sourceBranch);
|
|
843
|
-
const FORMAT = '--pretty=format:%H%x00%h%x00%s%x00%an%x00%aI';
|
|
844
862
|
let raw;
|
|
845
863
|
try {
|
|
846
|
-
raw = git(repoPath, ['log', `${workingBranch}..${sourceRef}`, `--max-count=${limit}`,
|
|
864
|
+
raw = git(repoPath, ['log', `${workingBranch}..${sourceRef}`, `--max-count=${limit}`, COMMIT_LOG_FORMAT]);
|
|
847
865
|
}
|
|
848
866
|
catch {
|
|
849
867
|
return [];
|
|
850
868
|
}
|
|
851
869
|
if (!raw)
|
|
852
870
|
return [];
|
|
853
|
-
|
|
854
|
-
for (const line of raw.split('\n')) {
|
|
855
|
-
if (!line)
|
|
856
|
-
continue;
|
|
857
|
-
const [sha, shortSha, subject, author, date] = line.split('\x00');
|
|
858
|
-
if (!sha)
|
|
859
|
-
continue;
|
|
860
|
-
commits.push({
|
|
861
|
-
sha,
|
|
862
|
-
shortSha: shortSha ?? '',
|
|
863
|
-
subject: subject ?? '',
|
|
864
|
-
author: author ?? '',
|
|
865
|
-
date: date ?? '',
|
|
866
|
-
});
|
|
867
|
-
}
|
|
868
|
-
return commits;
|
|
871
|
+
return parseCommitLog(raw);
|
|
869
872
|
}
|
|
870
873
|
/**
|
|
871
874
|
* Rename a branch in-place (`git branch -m <old> <new>`). Must be run inside
|
|
@@ -960,6 +963,12 @@ function parseNameStatus(output) {
|
|
|
960
963
|
return files;
|
|
961
964
|
}
|
|
962
965
|
/** List files changed between base and HEAD (committed), plus working tree changes. */
|
|
966
|
+
function parseWorktreeFilenames(out, limit) {
|
|
967
|
+
if (!out)
|
|
968
|
+
return [];
|
|
969
|
+
const files = out.split('\0').filter((line) => line.length > 0);
|
|
970
|
+
return files.length > limit ? files.slice(0, limit) : files;
|
|
971
|
+
}
|
|
963
972
|
/**
|
|
964
973
|
* List the worktree's files — tracked plus untracked-but-not-git-ignored.
|
|
965
974
|
* Excludes `.git`, `node_modules`, and anything covered by `.gitignore`.
|
|
@@ -969,10 +978,7 @@ function parseNameStatus(output) {
|
|
|
969
978
|
export function listWorktreeFiles(worktreePath, limit = 5000) {
|
|
970
979
|
try {
|
|
971
980
|
const out = git(worktreePath, ['ls-files', '-z', '--cached', '--others', '--exclude-standard']);
|
|
972
|
-
|
|
973
|
-
return [];
|
|
974
|
-
const files = out.split('\0').filter((line) => line.length > 0);
|
|
975
|
-
return files.length > limit ? files.slice(0, limit) : files;
|
|
981
|
+
return parseWorktreeFilenames(out, limit);
|
|
976
982
|
}
|
|
977
983
|
catch {
|
|
978
984
|
return [];
|
|
@@ -1196,6 +1202,19 @@ function parseWorkingTreeStatus(output) {
|
|
|
1196
1202
|
}
|
|
1197
1203
|
return { staged, modified, untracked };
|
|
1198
1204
|
}
|
|
1205
|
+
function parseWorkingTreeFiles(output) {
|
|
1206
|
+
const files = [];
|
|
1207
|
+
for (const { path: filePath, x, y } of parsePorcelain(output)) {
|
|
1208
|
+
const untracked = x === '?' && y === '?';
|
|
1209
|
+
files.push({
|
|
1210
|
+
path: filePath,
|
|
1211
|
+
staged: !untracked && x !== ' ' && x !== '?',
|
|
1212
|
+
modified: !untracked && y !== ' ' && y !== '?',
|
|
1213
|
+
untracked,
|
|
1214
|
+
});
|
|
1215
|
+
}
|
|
1216
|
+
return files;
|
|
1217
|
+
}
|
|
1199
1218
|
/**
|
|
1200
1219
|
* List uncommitted working-tree files with their status, parsed from
|
|
1201
1220
|
* `git status --porcelain`. Same classification rule as getWorkingTreeStatus.
|
|
@@ -1204,17 +1223,7 @@ function parseWorkingTreeStatus(output) {
|
|
|
1204
1223
|
export function getWorkingTreeFiles(repoPath) {
|
|
1205
1224
|
try {
|
|
1206
1225
|
const output = git(repoPath, ['status', '--porcelain', '-z']);
|
|
1207
|
-
|
|
1208
|
-
for (const { path: filePath, x, y } of parsePorcelain(output)) {
|
|
1209
|
-
const untracked = x === '?' && y === '?';
|
|
1210
|
-
files.push({
|
|
1211
|
-
path: filePath,
|
|
1212
|
-
staged: !untracked && x !== ' ' && x !== '?',
|
|
1213
|
-
modified: !untracked && y !== ' ' && y !== '?',
|
|
1214
|
-
untracked,
|
|
1215
|
-
});
|
|
1216
|
-
}
|
|
1217
|
-
return files;
|
|
1226
|
+
return parseWorkingTreeFiles(output);
|
|
1218
1227
|
}
|
|
1219
1228
|
catch {
|
|
1220
1229
|
return [];
|
|
@@ -1348,6 +1357,121 @@ async function resolveBaseAsync(repoPath, base) {
|
|
|
1348
1357
|
return base;
|
|
1349
1358
|
}
|
|
1350
1359
|
}
|
|
1360
|
+
/** Non-blocking branch and file discovery for forms, autocomplete and PR diagnosis. */
|
|
1361
|
+
export async function listBranchesAsync(repoPath) {
|
|
1362
|
+
return (await gitAsync(repoPath, ['branch', '--format=%(refname:short)']))
|
|
1363
|
+
.split('\n')
|
|
1364
|
+
.map((branch) => branch.trim())
|
|
1365
|
+
.filter(Boolean);
|
|
1366
|
+
}
|
|
1367
|
+
export async function listRemoteBranchesAsync(repoPath) {
|
|
1368
|
+
try {
|
|
1369
|
+
return (await gitAsync(repoPath, ['branch', '-r', '--format=%(refname:short)']))
|
|
1370
|
+
.split('\n')
|
|
1371
|
+
.map((branch) => branch.trim())
|
|
1372
|
+
.filter(Boolean);
|
|
1373
|
+
}
|
|
1374
|
+
catch {
|
|
1375
|
+
return [];
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
export async function localBranchExistsAsync(repoPath, name) {
|
|
1379
|
+
try {
|
|
1380
|
+
await gitAsync(repoPath, ['rev-parse', '--verify', '--quiet', `refs/heads/${name}`]);
|
|
1381
|
+
return true;
|
|
1382
|
+
}
|
|
1383
|
+
catch {
|
|
1384
|
+
return false;
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
export async function getIndexLockPathAsync(repoPath) {
|
|
1388
|
+
try {
|
|
1389
|
+
const directory = await gitAsync(repoPath, ['rev-parse', '--absolute-git-dir']);
|
|
1390
|
+
const lockPath = join(directory, 'index.lock');
|
|
1391
|
+
return existsSync(lockPath) ? lockPath : null;
|
|
1392
|
+
}
|
|
1393
|
+
catch {
|
|
1394
|
+
return null;
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
export async function getOngoingGitOperationAsync(repoPath) {
|
|
1398
|
+
try {
|
|
1399
|
+
const gitDirectory = await gitAsync(repoPath, ['rev-parse', '--git-dir']);
|
|
1400
|
+
return classifyOngoingGitOperation(gitDirectory.startsWith('/') ? gitDirectory : join(repoPath, gitDirectory));
|
|
1401
|
+
}
|
|
1402
|
+
catch {
|
|
1403
|
+
return null;
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
export async function listWorktreeFilesAsync(worktreePath, limit = 5_000) {
|
|
1407
|
+
try {
|
|
1408
|
+
return parseWorktreeFilenames(await gitAsync(worktreePath, ['ls-files', '-z', '--cached', '--others', '--exclude-standard']), limit);
|
|
1409
|
+
}
|
|
1410
|
+
catch {
|
|
1411
|
+
return [];
|
|
1412
|
+
}
|
|
1413
|
+
}
|
|
1414
|
+
/** Non-blocking review-template commit list, preferring the remote base. */
|
|
1415
|
+
export async function getCommitsBetweenAsync(repoPath, base, head) {
|
|
1416
|
+
try {
|
|
1417
|
+
const ref = await resolveBaseAsync(repoPath, base);
|
|
1418
|
+
return await gitAsync(repoPath, ['log', `${ref}..${head}`, '--pretty=format:- %s (%h)', '--no-merges']);
|
|
1419
|
+
}
|
|
1420
|
+
catch {
|
|
1421
|
+
return '';
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
/** Keep the existing raw three-dot ref semantics of the shortstat helper. */
|
|
1425
|
+
export async function getDiffStatsBetweenAsync(repoPath, base, head) {
|
|
1426
|
+
try {
|
|
1427
|
+
return await gitAsync(repoPath, ['diff', '--shortstat', `${base}...${head}`]);
|
|
1428
|
+
}
|
|
1429
|
+
catch {
|
|
1430
|
+
return '';
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
export async function listBranchCommitsAsync(repoPath, sourceBranch, workingBranch, limit = 50, remote = 'origin') {
|
|
1434
|
+
const sourceRef = await resolveBaseAsync(repoPath, sourceBranch);
|
|
1435
|
+
const remoteRef = `${remote}/${workingBranch}`;
|
|
1436
|
+
let raw;
|
|
1437
|
+
try {
|
|
1438
|
+
raw = await gitAsync(repoPath, ['log', `${sourceRef}..HEAD`, `--max-count=${limit}`, COMMIT_LOG_FORMAT]);
|
|
1439
|
+
}
|
|
1440
|
+
catch {
|
|
1441
|
+
return [];
|
|
1442
|
+
}
|
|
1443
|
+
if (!raw)
|
|
1444
|
+
return [];
|
|
1445
|
+
const pushedShas = new Set();
|
|
1446
|
+
try {
|
|
1447
|
+
await gitAsync(repoPath, ['rev-parse', '--verify', remoteRef]);
|
|
1448
|
+
const pushed = await gitAsync(repoPath, ['log', `${sourceRef}..${remoteRef}`, '--pretty=format:%H']);
|
|
1449
|
+
for (const sha of pushed.split('\n'))
|
|
1450
|
+
if (sha)
|
|
1451
|
+
pushedShas.add(sha.trim());
|
|
1452
|
+
}
|
|
1453
|
+
catch {
|
|
1454
|
+
// A branch that has never been pushed has no remote ref.
|
|
1455
|
+
}
|
|
1456
|
+
return parseCommitLog(raw).map((commit) => ({ ...commit, isPushed: pushedShas.has(commit.sha) }));
|
|
1457
|
+
}
|
|
1458
|
+
export async function listCommitsBehindAsync(repoPath, sourceBranch, workingBranch, limit = 50) {
|
|
1459
|
+
try {
|
|
1460
|
+
const sourceRef = await resolveBaseAsync(repoPath, sourceBranch);
|
|
1461
|
+
return parseCommitLog(await gitAsync(repoPath, ['log', `${workingBranch}..${sourceRef}`, `--max-count=${limit}`, COMMIT_LOG_FORMAT]));
|
|
1462
|
+
}
|
|
1463
|
+
catch {
|
|
1464
|
+
return [];
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
export async function getWorkingTreeFilesAsync(repoPath) {
|
|
1468
|
+
try {
|
|
1469
|
+
return parseWorkingTreeFiles(await gitAsync(repoPath, ['status', '--porcelain', '-z']));
|
|
1470
|
+
}
|
|
1471
|
+
catch {
|
|
1472
|
+
return [];
|
|
1473
|
+
}
|
|
1474
|
+
}
|
|
1351
1475
|
/** Non-blocking commit count for request and polling hot paths. */
|
|
1352
1476
|
export async function getCommitCountAsync(repoPath, base, head) {
|
|
1353
1477
|
try {
|
|
@@ -1390,6 +1514,84 @@ export async function getWorkingTreeStatusAsync(repoPath) {
|
|
|
1390
1514
|
return { staged: 0, modified: 0, untracked: 0 };
|
|
1391
1515
|
}
|
|
1392
1516
|
}
|
|
1517
|
+
/** Raw handoff state. Failures must not be presented as a clean checkout. */
|
|
1518
|
+
export function getWorkingTreePorcelainAsync(repoPath) {
|
|
1519
|
+
return gitAsync(repoPath, ['status', '--short']);
|
|
1520
|
+
}
|
|
1521
|
+
export function getWorkingTreeDiffStatsAsync(repoPath) {
|
|
1522
|
+
return gitAsync(repoPath, ['diff', '--stat', 'HEAD']);
|
|
1523
|
+
}
|
|
1524
|
+
export async function commitExistsAsync(repoPath, ref) {
|
|
1525
|
+
try {
|
|
1526
|
+
await gitAsync(repoPath, ['rev-parse', '--verify', '--quiet', `${ref}^{commit}`]);
|
|
1527
|
+
return true;
|
|
1528
|
+
}
|
|
1529
|
+
catch {
|
|
1530
|
+
return false;
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
export async function getFileAtRefAsync(repoPath, ref, filePath) {
|
|
1534
|
+
const resolvedRef = await resolveBaseAsync(repoPath, ref);
|
|
1535
|
+
try {
|
|
1536
|
+
// File contents must retain their leading/trailing whitespace verbatim.
|
|
1537
|
+
const { stdout } = await execFileAsync('git', ['show', `${resolvedRef}:${filePath}`], {
|
|
1538
|
+
cwd: repoPath,
|
|
1539
|
+
encoding: 'utf-8',
|
|
1540
|
+
timeout: READ_ONLY_GIT_TIMEOUT_MS,
|
|
1541
|
+
maxBuffer: GIT_MAX_BUFFER_BYTES,
|
|
1542
|
+
env: NON_INTERACTIVE_GIT_ENV,
|
|
1543
|
+
});
|
|
1544
|
+
return stdout;
|
|
1545
|
+
}
|
|
1546
|
+
catch {
|
|
1547
|
+
return null;
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
export async function getChangedFilesBetweenAsync(repoPath, fromRef, toRef) {
|
|
1551
|
+
try {
|
|
1552
|
+
return parseNameStatus(await gitAsync(repoPath, ['diff', '--name-status', '-z', `${fromRef}..${toRef}`]));
|
|
1553
|
+
}
|
|
1554
|
+
catch {
|
|
1555
|
+
return [];
|
|
1556
|
+
}
|
|
1557
|
+
}
|
|
1558
|
+
export async function getUnpushedChangedFilesAsync(repoPath, branchName, remote = 'origin') {
|
|
1559
|
+
const ref = `${remote}/${branchName}`;
|
|
1560
|
+
try {
|
|
1561
|
+
await gitAsync(repoPath, ['rev-parse', '--verify', ref]);
|
|
1562
|
+
return parseNameStatus(await gitAsync(repoPath, ['diff', '--name-status', '-z', `${ref}..HEAD`]));
|
|
1563
|
+
}
|
|
1564
|
+
catch {
|
|
1565
|
+
return [];
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
export async function getChangedFilesAsync(repoPath, base, includeUntracked = false) {
|
|
1569
|
+
const ref = await resolveBaseAsync(repoPath, base);
|
|
1570
|
+
const [committed, working] = await Promise.allSettled([
|
|
1571
|
+
gitAsync(repoPath, ['diff', '--name-status', '-z', `${ref}...HEAD`]),
|
|
1572
|
+
gitAsync(repoPath, ['status', '--porcelain', '-z', includeUntracked ? '-uall' : '-uno']),
|
|
1573
|
+
]);
|
|
1574
|
+
const files = committed.status === 'fulfilled' ? parseNameStatus(committed.value) : [];
|
|
1575
|
+
const seen = new Set(files.map((file) => file.path));
|
|
1576
|
+
if (working.status === 'fulfilled') {
|
|
1577
|
+
for (const { path: filePath, x, y } of parsePorcelain(working.value)) {
|
|
1578
|
+
if (seen.has(filePath))
|
|
1579
|
+
continue;
|
|
1580
|
+
const status = x === '?' && y === '?'
|
|
1581
|
+
? 'untracked'
|
|
1582
|
+
: x === 'R' || y === 'R'
|
|
1583
|
+
? 'renamed'
|
|
1584
|
+
: x === 'A' || y === 'A'
|
|
1585
|
+
? 'added'
|
|
1586
|
+
: x === 'D' || y === 'D'
|
|
1587
|
+
? 'deleted'
|
|
1588
|
+
: 'modified';
|
|
1589
|
+
files.push({ path: filePath, status });
|
|
1590
|
+
seen.add(filePath);
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
return files;
|
|
1594
|
+
}
|
|
1393
1595
|
/**
|
|
1394
1596
|
* Async version of `getUnpushedCount`. Same `origin/<workingBranch>` semantic:
|
|
1395
1597
|
* returns `-1` when the remote ref does not exist (never pushed), `0` when
|
|
@@ -5,9 +5,8 @@
|
|
|
5
5
|
* editing the workspace `model` field directly. This list reflects the
|
|
6
6
|
* recommended set surfaced in the create-workspace selector.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* (Plus/Pro/Team/Enterprise). API-key auth is limited to `gpt-5.4` and below.
|
|
8
|
+
* Availability can vary by account and authentication method. The CLI owns
|
|
9
|
+
* the actual model resolution; the catalogue only offers named choices.
|
|
11
10
|
*/
|
|
12
11
|
export const CODEX_MODELS = [
|
|
13
12
|
{
|
|
@@ -16,12 +15,30 @@ export const CODEX_MODELS = [
|
|
|
16
15
|
i18nLabelKey: 'model.auto',
|
|
17
16
|
i18nDescriptionKey: 'model.autoDescription',
|
|
18
17
|
},
|
|
18
|
+
{
|
|
19
|
+
id: 'gpt-6.1-sol',
|
|
20
|
+
label: 'GPT-6.1 Sol',
|
|
21
|
+
i18nLabelKey: 'model.gpt61sol',
|
|
22
|
+
i18nDescriptionKey: 'model.gpt61solDescription',
|
|
23
|
+
},
|
|
19
24
|
{
|
|
20
25
|
id: 'gpt-6-astra',
|
|
21
26
|
label: 'GPT-6 Astra',
|
|
22
27
|
i18nLabelKey: 'model.gpt6astra',
|
|
23
28
|
i18nDescriptionKey: 'model.gpt6astraDescription',
|
|
24
29
|
},
|
|
30
|
+
{
|
|
31
|
+
id: 'gpt-6-sol',
|
|
32
|
+
label: 'GPT-6 Sol',
|
|
33
|
+
i18nLabelKey: 'model.gpt6sol',
|
|
34
|
+
i18nDescriptionKey: 'model.gpt6solDescription',
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
id: 'gpt-6-luna',
|
|
38
|
+
label: 'GPT-6 Luna',
|
|
39
|
+
i18nLabelKey: 'model.gpt6luna',
|
|
40
|
+
i18nDescriptionKey: 'model.gpt6lunaDescription',
|
|
41
|
+
},
|
|
25
42
|
{
|
|
26
43
|
id: 'gpt-5.6-sol',
|
|
27
44
|
label: 'GPT-5.6 Sol',
|
package/dist/shared/models.js
CHANGED
|
@@ -17,6 +17,12 @@ export const CLAUDE_MODELS = [
|
|
|
17
17
|
i18nLabelKey: 'model.mythos5',
|
|
18
18
|
i18nDescriptionKey: 'model.mythos5Description',
|
|
19
19
|
},
|
|
20
|
+
{
|
|
21
|
+
id: 'claude-opus-5-5',
|
|
22
|
+
label: 'Opus 5.5',
|
|
23
|
+
i18nLabelKey: 'model.opus55',
|
|
24
|
+
i18nDescriptionKey: 'model.opus55Description',
|
|
25
|
+
},
|
|
20
26
|
{
|
|
21
27
|
id: 'claude-opus-5',
|
|
22
28
|
label: 'Opus 5',
|
|
@@ -53,6 +59,12 @@ export const CLAUDE_MODELS = [
|
|
|
53
59
|
i18nLabelKey: 'model.opus1m',
|
|
54
60
|
i18nDescriptionKey: 'model.opus1mDescription',
|
|
55
61
|
},
|
|
62
|
+
{
|
|
63
|
+
id: 'claude-sonnet-5-5',
|
|
64
|
+
label: 'Sonnet 5.5',
|
|
65
|
+
i18nLabelKey: 'model.sonnet55',
|
|
66
|
+
i18nDescriptionKey: 'model.sonnet55Description',
|
|
67
|
+
},
|
|
56
68
|
{
|
|
57
69
|
id: 'claude-sonnet-5',
|
|
58
70
|
label: 'Sonnet 5',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@loicngr/kobo",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.5",
|
|
4
4
|
"description": "Kōbō — local multi-workspace orchestrator for Claude Code and OpenAI Codex, with isolated Git worktrees, live review and optional automation.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "GPL-3.0-or-later",
|
|
@@ -81,15 +81,15 @@
|
|
|
81
81
|
"security:scan": "node scripts/scan-secrets.mjs"
|
|
82
82
|
},
|
|
83
83
|
"dependencies": {
|
|
84
|
-
"@anthropic-ai/claude-agent-sdk": "^0.3.
|
|
84
|
+
"@anthropic-ai/claude-agent-sdk": "^0.3.285",
|
|
85
85
|
"@emnapi/core": "^1.11.3",
|
|
86
86
|
"@emnapi/runtime": "^1.11.3",
|
|
87
|
-
"@hono/node-server": "^2.1.
|
|
88
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
89
|
-
"@openai/codex": "^0.
|
|
87
|
+
"@hono/node-server": "^2.1.3",
|
|
88
|
+
"@modelcontextprotocol/sdk": "^1.31.0",
|
|
89
|
+
"@openai/codex": "^0.159.2",
|
|
90
90
|
"better-sqlite3": "^13.0.3",
|
|
91
91
|
"cron-parser": "^5.10.1",
|
|
92
|
-
"hono": "^4.13.
|
|
92
|
+
"hono": "^4.13.12",
|
|
93
93
|
"nanoid": "^6.0.1",
|
|
94
94
|
"node-pty": "^1.1.0",
|
|
95
95
|
"ws": "^8.22.0"
|
|
@@ -98,7 +98,7 @@
|
|
|
98
98
|
"@biomejs/biome": "2.5.14",
|
|
99
99
|
"@types/better-sqlite3": "^9.6.0",
|
|
100
100
|
"@types/node": "^26.6.3",
|
|
101
|
-
"@types/ws": "^8.18.
|
|
101
|
+
"@types/ws": "^8.18.2",
|
|
102
102
|
"@vitest/runner": "^4.1.11",
|
|
103
103
|
"concurrently": "^10.0.5",
|
|
104
104
|
"tsx": "^4.23.15",
|
|
@@ -106,7 +106,7 @@
|
|
|
106
106
|
"vitest": "^5.0.2"
|
|
107
107
|
},
|
|
108
108
|
"overrides": {
|
|
109
|
-
"@hono/node-server": "^2.1.
|
|
109
|
+
"@hono/node-server": "^2.1.3",
|
|
110
110
|
"shell-quote": "^1.10.0"
|
|
111
111
|
}
|
|
112
112
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
.agent-error-item[data-v-e98c3c02]{gap:var(--kobo-space-sm);padding:var(--kobo-space-sm) var(--kobo-space-md);border-left:2px solid var(--kobo-danger);background:var(--kobo-surface-2);border-radius:var(--kobo-radius-sm);align-items:flex-start;display:flex}.agent-error-item__icon[data-v-e98c3c02]{color:var(--kobo-danger);flex:none;margin-top:2px}.agent-error-item__body[data-v-e98c3c02]{min-width:0}.agent-error-item__title[data-v-e98c3c02]{color:var(--kobo-text);font-weight:600}.agent-error-item__message[data-v-e98c3c02]{color:var(--kobo-text-2);font-family:var(--kobo-font-mono);white-space:pre-wrap;word-break:break-word;font-size:12px}.markdown-message[data-v-99371035]{color:var(--kobo-text-2);word-break:break-word;overflow-wrap:anywhere;min-width:0;max-width:100%;font-size:13px;line-height:1.55}.markdown-message[data-v-99371035] *{max-width:100%}.markdown-message[data-v-99371035] p{margin:0 0 .5em}.markdown-message[data-v-99371035] p:last-child{margin-bottom:0}.markdown-message[data-v-99371035] pre{background:#00000059;border-radius:4px;margin:.5em 0;padding:.5em .75em;overflow-x:auto}.markdown-message[data-v-99371035] code{word-break:break-all;background:#0000004d;border-radius:3px;padding:.1em .3em;font-size:.9em}.markdown-message[data-v-99371035] pre code{background:0 0;padding:0}.markdown-message[data-v-99371035] ul,.markdown-message[data-v-99371035] ol{margin:.25em 0 .5em;padding-left:1.5em}.markdown-message[data-v-99371035] li{margin:.15em 0}.markdown-message[data-v-99371035] a{color:var(--kobo-text-2);text-decoration:underline}.markdown-message[data-v-99371035] .document-link{color:var(--kobo-text-2);cursor:pointer;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}.markdown-message[data-v-99371035] .document-link:hover{color:var(--kobo-text);-webkit-text-decoration:underline;text-decoration:underline}.markdown-message[data-v-99371035] h1,.markdown-message[data-v-99371035] h2,.markdown-message[data-v-99371035] h3,.markdown-message[data-v-99371035] h4,.markdown-message[data-v-99371035] h5,.markdown-message[data-v-99371035] h6{margin:.5em 0 .3em;font-weight:600;line-height:1.3}.markdown-message[data-v-99371035] h1{font-size:1.25em}.markdown-message[data-v-99371035] h2{font-size:1.15em}.markdown-message[data-v-99371035] h3{font-size:1.08em}.markdown-message[data-v-99371035] h4,.markdown-message[data-v-99371035] h5,.markdown-message[data-v-99371035] h6{font-size:1em}.markdown-message[data-v-99371035] blockquote{color:#ffffffb3;border-left:3px solid #fff3;margin:.5em 0;padding-left:.75em}.markdown-message[data-v-99371035] table{border-collapse:collapse;margin:.5em 0}.markdown-message[data-v-99371035] th,.markdown-message[data-v-99371035] td{border:1px solid #ffffff26;padding:.25em .5em}.tool-row[data-v-2482adfe]{border-radius:4px;margin:0;font-size:12px}.tool-header[data-v-2482adfe]{color:var(--kobo-text-2);cursor:default;align-items:center;gap:10px;min-width:0;padding:5px 10px;display:flex}.tool-row:not(.tool-row-generic) .tool-header[data-v-2482adfe],.tool-row--toggleable .tool-header[data-v-2482adfe]{cursor:pointer}.tool-row:has(.tool-diff) .tool-header[data-v-2482adfe]{cursor:pointer}.tool-row:not(.tool-row-generic) .tool-header[data-v-2482adfe]:hover,.tool-row--toggleable .tool-header[data-v-2482adfe]:hover{background:#ffffff08}.tool-icon[data-v-2482adfe]{color:var(--kobo-text-2);flex-shrink:0}.tool-name[data-v-2482adfe]{color:var(--kobo-text-2);flex-shrink:0;font-weight:600}.tool-arg[data-v-2482adfe],.tool-path[data-v-2482adfe]{color:var(--kobo-text-3);text-overflow:ellipsis;white-space:nowrap;min-width:0;max-width:100%;font-family:var(--kobo-font-mono);font-size:11.5px;overflow:hidden}.tool-open-diff[data-v-2482adfe]{flex-shrink:0}.tool-path[data-v-2482adfe],.tool-arg[data-v-2482adfe]{flex:1}.tool-stat-add[data-v-2482adfe]{color:var(--kobo-success);flex-shrink:0;font-size:11px;font-weight:600}.tool-stat-del[data-v-2482adfe]{color:var(--kobo-danger);flex-shrink:0;font-size:11px;font-weight:600}.tool-diff[data-v-2482adfe]{max-height:400px;font-family:var(--kobo-font-mono);background:#0003;border-radius:4px;margin-top:4px;padding:8px 0;font-size:11px;line-height:1.5;overflow:auto}.diff-line[data-v-2482adfe]{white-space:pre;color:var(--kobo-text-2);padding:0 12px}.diff-sign[data-v-2482adfe]{width:14px;color:var(--kobo-text-disabled);-webkit-user-select:none;user-select:none;display:inline-block}.diff-add[data-v-2482adfe]{color:var(--kobo-success);background:#66bb6a1a}.diff-add .diff-sign[data-v-2482adfe]{color:var(--kobo-success)}.diff-del[data-v-2482adfe]{color:var(--kobo-danger);background:#ef53501a}.diff-del .diff-sign[data-v-2482adfe]{color:var(--kobo-danger)}.tool-output[data-v-2482adfe]{color:var(--kobo-text-2);font-family:var(--kobo-font-mono);white-space:pre-wrap;background:#00000026;border-radius:4px;max-height:8em;margin-top:4px;padding:6px 10px;font-size:11px;overflow:auto}.markdown-message[data-v-db2fc622]{color:var(--kobo-text-2);word-break:break-word;overflow-wrap:anywhere;min-width:0;max-width:100%;font-size:13px;line-height:1.55}.markdown-message[data-v-db2fc622] *{max-width:100%}.markdown-message[data-v-db2fc622] img{-o-object-fit:contain;object-fit:contain;cursor:zoom-in;background:#0003;border-radius:4px;max-width:180px;max-height:100px;margin:.3em 0;display:block}.markdown-message[data-v-db2fc622] code{word-break:break-all}.markdown-message[data-v-db2fc622] p{margin:0 0 .4em}.markdown-message[data-v-db2fc622] p:last-child{margin-bottom:0}.markdown-message[data-v-db2fc622] code{background:#00000040;border-radius:3px;padding:.1em .3em}.markdown-message[data-v-db2fc622] h1,.markdown-message[data-v-db2fc622] h2,.markdown-message[data-v-db2fc622] h3,.markdown-message[data-v-db2fc622] h4,.markdown-message[data-v-db2fc622] h5,.markdown-message[data-v-db2fc622] h6{margin:.4em 0 .25em;font-weight:600;line-height:1.3}.markdown-message[data-v-db2fc622] h1{font-size:1.25em}.markdown-message[data-v-db2fc622] h2{font-size:1.15em}.markdown-message[data-v-db2fc622] h3{font-size:1.08em}.markdown-message[data-v-db2fc622] h4,.markdown-message[data-v-db2fc622] h5,.markdown-message[data-v-db2fc622] h6{font-size:1em}.markdown-user-prompt[data-v-db2fc622]{color:var(--kobo-text-2);font-size:12px;font-style:italic}.markdown-user-prompt[data-v-db2fc622] p{margin:0 0 .4em}.markdown-user-prompt[data-v-db2fc622] code{background:#ffffff14;border-radius:3px;padding:.1em .3em;font-style:normal}.image-lightbox-img{-o-object-fit:contain;object-fit:contain;cursor:zoom-out;background:#0000004d;border-radius:4px;max-width:92vw;max-height:92vh;display:block}.turn-card[data-v-c0e24cbd]{border:1px solid #ffffff14;border-left:3px solid var(--turn-accent);background:#ffffff05;border-radius:6px;min-width:0;max-width:100%;margin:14px 0;overflow:hidden}.turn-card--highlighted[data-v-c0e24cbd]{animation:1.8s ease-out search-highlight-c0e24cbd}@keyframes search-highlight-c0e24cbd{0%,45%{box-shadow:0 0 0 2px #818cf8f2,0 0 22px #818cf873}to{box-shadow:none}}.turn-header[data-v-c0e24cbd]{color:var(--kobo-text-3);background:#ffffff08;border-bottom:1px solid #ffffff0d;align-items:center;gap:8px;padding:8px 14px;font-size:11px;display:flex}.turn-badge[data-v-c0e24cbd]{letter-spacing:.3px;border-radius:3px;padding:2px 8px;font-size:11px;font-weight:700}.turn-badge-user[data-v-c0e24cbd]{color:var(--kobo-turn-user);background:#ce93d826}.turn-badge-agent[data-v-c0e24cbd]{color:var(--kobo-turn-agent);background:#7986cb26}.turn-badge-system[data-v-c0e24cbd]{color:var(--kobo-text-2);background:#75757533;font-style:italic}.turn-badge-session[data-v-c0e24cbd]{color:var(--kobo-text-3);background:#61616133}.turn-badge-script[data-v-c0e24cbd]{color:var(--kobo-success);background:#4db6ac26}.turn-time[data-v-c0e24cbd]{color:var(--kobo-text-disabled);font-family:var(--kobo-font-mono);font-size:11px}.turn-time-arrow[data-v-c0e24cbd]{opacity:.7;margin:0 -2px}.turn-time-updated[data-v-c0e24cbd]{color:var(--kobo-text-3)}.turn-actions[data-v-c0e24cbd]{color:var(--kobo-text-3);font-size:11px}.turn-body[data-v-c0e24cbd]{flex-direction:column;gap:12px;min-width:0;padding:14px 18px;display:flex}.turn-body[data-v-c0e24cbd]>*{min-width:0;max-width:100%}.turn-body[data-v-c0e24cbd] .tool-row+.tool-row{margin-top:-8px}.turn-scroll-top[data-v-c0e24cbd]{justify-content:flex-start;padding:0 8px 6px;display:flex}.turn-scroll-top-btn[data-v-c0e24cbd]{opacity:.5;transition:opacity .15s}.turn-scroll-top-btn[data-v-c0e24cbd]:hover{opacity:1}.activity-feed-wrap[data-v-028e8af5]{width:100%;height:100%;position:relative}.activity-feed-scroll[data-v-028e8af5]{width:100%;height:100%}.activity-feed-nav-cluster[data-v-028e8af5]{z-index:2;align-items:center;gap:8px;display:flex;position:absolute;bottom:14px;right:14px}.activity-feed-compacting[data-v-028e8af5]{z-index:3;background:var(--kobo-surface);border:1px solid var(--kobo-border);border-radius:6px;align-items:center;gap:8px;padding:6px 14px;display:flex;position:absolute;top:12px;left:50%;transform:translate(-50%);box-shadow:0 4px 16px #00000059}.fade-enter-active[data-v-028e8af5],.fade-leave-active[data-v-028e8af5]{transition:opacity .16s}.fade-enter-from[data-v-028e8af5],.fade-leave-to[data-v-028e8af5]{opacity:0}.activity-feed-nav-btn[data-v-028e8af5]{opacity:.8;transition:opacity .12s}.activity-feed-nav-btn[data-v-028e8af5]:hover{opacity:1}.activity-feed-scroll[data-v-028e8af5] .q-scrollarea__content{max-width:100%;overflow-x:hidden}.activity-feed-switching[data-v-028e8af5]{justify-content:center;align-items:center;width:100%;height:100%;display:flex}.activity-feed-empty[data-v-028e8af5]{align-items:center;gap:var(--kobo-space-sm);padding:var(--kobo-space-4xl) var(--kobo-space-xl);color:var(--kobo-text-3);text-align:center;flex-direction:column;display:flex}.activity-feed-empty__title[data-v-028e8af5]{font-family:var(--kobo-font-sans);color:var(--kobo-text-2);font-size:14px;font-weight:500}.activity-feed-empty__hint[data-v-028e8af5]{font-family:var(--kobo-font-sans);color:var(--kobo-text-3);max-width:380px;font-size:13px}
|
|
1
|
+
.agent-error-item[data-v-e98c3c02]{gap:var(--kobo-space-sm);padding:var(--kobo-space-sm) var(--kobo-space-md);border-left:2px solid var(--kobo-danger);background:var(--kobo-surface-2);border-radius:var(--kobo-radius-sm);align-items:flex-start;display:flex}.agent-error-item__icon[data-v-e98c3c02]{color:var(--kobo-danger);flex:none;margin-top:2px}.agent-error-item__body[data-v-e98c3c02]{min-width:0}.agent-error-item__title[data-v-e98c3c02]{color:var(--kobo-text);font-weight:600}.agent-error-item__message[data-v-e98c3c02]{color:var(--kobo-text-2);font-family:var(--kobo-font-mono);white-space:pre-wrap;word-break:break-word;font-size:12px}.markdown-message[data-v-99371035]{color:var(--kobo-text-2);word-break:break-word;overflow-wrap:anywhere;min-width:0;max-width:100%;font-size:13px;line-height:1.55}.markdown-message[data-v-99371035] *{max-width:100%}.markdown-message[data-v-99371035] p{margin:0 0 .5em}.markdown-message[data-v-99371035] p:last-child{margin-bottom:0}.markdown-message[data-v-99371035] pre{background:#00000059;border-radius:4px;margin:.5em 0;padding:.5em .75em;overflow-x:auto}.markdown-message[data-v-99371035] code{word-break:break-all;background:#0000004d;border-radius:3px;padding:.1em .3em;font-size:.9em}.markdown-message[data-v-99371035] pre code{background:0 0;padding:0}.markdown-message[data-v-99371035] ul,.markdown-message[data-v-99371035] ol{margin:.25em 0 .5em;padding-left:1.5em}.markdown-message[data-v-99371035] li{margin:.15em 0}.markdown-message[data-v-99371035] a{color:var(--kobo-text-2);text-decoration:underline}.markdown-message[data-v-99371035] .document-link{color:var(--kobo-text-2);cursor:pointer;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}.markdown-message[data-v-99371035] .document-link:hover{color:var(--kobo-text);-webkit-text-decoration:underline;text-decoration:underline}.markdown-message[data-v-99371035] h1,.markdown-message[data-v-99371035] h2,.markdown-message[data-v-99371035] h3,.markdown-message[data-v-99371035] h4,.markdown-message[data-v-99371035] h5,.markdown-message[data-v-99371035] h6{margin:.5em 0 .3em;font-weight:600;line-height:1.3}.markdown-message[data-v-99371035] h1{font-size:1.25em}.markdown-message[data-v-99371035] h2{font-size:1.15em}.markdown-message[data-v-99371035] h3{font-size:1.08em}.markdown-message[data-v-99371035] h4,.markdown-message[data-v-99371035] h5,.markdown-message[data-v-99371035] h6{font-size:1em}.markdown-message[data-v-99371035] blockquote{color:#ffffffb3;border-left:3px solid #fff3;margin:.5em 0;padding-left:.75em}.markdown-message[data-v-99371035] table{border-collapse:collapse;margin:.5em 0}.markdown-message[data-v-99371035] th,.markdown-message[data-v-99371035] td{border:1px solid #ffffff26;padding:.25em .5em}.tool-row[data-v-2482adfe]{border-radius:4px;margin:0;font-size:12px}.tool-header[data-v-2482adfe]{color:var(--kobo-text-2);cursor:default;align-items:center;gap:10px;min-width:0;padding:5px 10px;display:flex}.tool-row:not(.tool-row-generic) .tool-header[data-v-2482adfe],.tool-row--toggleable .tool-header[data-v-2482adfe]{cursor:pointer}.tool-row:has(.tool-diff) .tool-header[data-v-2482adfe]{cursor:pointer}.tool-row:not(.tool-row-generic) .tool-header[data-v-2482adfe]:hover,.tool-row--toggleable .tool-header[data-v-2482adfe]:hover{background:#ffffff08}.tool-icon[data-v-2482adfe]{color:var(--kobo-text-2);flex-shrink:0}.tool-name[data-v-2482adfe]{color:var(--kobo-text-2);flex-shrink:0;font-weight:600}.tool-arg[data-v-2482adfe],.tool-path[data-v-2482adfe]{color:var(--kobo-text-3);text-overflow:ellipsis;white-space:nowrap;min-width:0;max-width:100%;font-family:var(--kobo-font-mono);font-size:11.5px;overflow:hidden}.tool-open-diff[data-v-2482adfe]{flex-shrink:0}.tool-path[data-v-2482adfe],.tool-arg[data-v-2482adfe]{flex:1}.tool-stat-add[data-v-2482adfe]{color:var(--kobo-success);flex-shrink:0;font-size:11px;font-weight:600}.tool-stat-del[data-v-2482adfe]{color:var(--kobo-danger);flex-shrink:0;font-size:11px;font-weight:600}.tool-diff[data-v-2482adfe]{max-height:400px;font-family:var(--kobo-font-mono);background:#0003;border-radius:4px;margin-top:4px;padding:8px 0;font-size:11px;line-height:1.5;overflow:auto}.diff-line[data-v-2482adfe]{white-space:pre;color:var(--kobo-text-2);padding:0 12px}.diff-sign[data-v-2482adfe]{width:14px;color:var(--kobo-text-disabled);-webkit-user-select:none;user-select:none;display:inline-block}.diff-add[data-v-2482adfe]{color:var(--kobo-success);background:#66bb6a1a}.diff-add .diff-sign[data-v-2482adfe]{color:var(--kobo-success)}.diff-del[data-v-2482adfe]{color:var(--kobo-danger);background:#ef53501a}.diff-del .diff-sign[data-v-2482adfe]{color:var(--kobo-danger)}.tool-output[data-v-2482adfe]{color:var(--kobo-text-2);font-family:var(--kobo-font-mono);white-space:pre-wrap;background:#00000026;border-radius:4px;max-height:8em;margin-top:4px;padding:6px 10px;font-size:11px;overflow:auto}.markdown-message[data-v-db2fc622]{color:var(--kobo-text-2);word-break:break-word;overflow-wrap:anywhere;min-width:0;max-width:100%;font-size:13px;line-height:1.55}.markdown-message[data-v-db2fc622] *{max-width:100%}.markdown-message[data-v-db2fc622] img{-o-object-fit:contain;object-fit:contain;cursor:zoom-in;background:#0003;border-radius:4px;max-width:180px;max-height:100px;margin:.3em 0;display:block}.markdown-message[data-v-db2fc622] code{word-break:break-all}.markdown-message[data-v-db2fc622] p{margin:0 0 .4em}.markdown-message[data-v-db2fc622] p:last-child{margin-bottom:0}.markdown-message[data-v-db2fc622] code{background:#00000040;border-radius:3px;padding:.1em .3em}.markdown-message[data-v-db2fc622] h1,.markdown-message[data-v-db2fc622] h2,.markdown-message[data-v-db2fc622] h3,.markdown-message[data-v-db2fc622] h4,.markdown-message[data-v-db2fc622] h5,.markdown-message[data-v-db2fc622] h6{margin:.4em 0 .25em;font-weight:600;line-height:1.3}.markdown-message[data-v-db2fc622] h1{font-size:1.25em}.markdown-message[data-v-db2fc622] h2{font-size:1.15em}.markdown-message[data-v-db2fc622] h3{font-size:1.08em}.markdown-message[data-v-db2fc622] h4,.markdown-message[data-v-db2fc622] h5,.markdown-message[data-v-db2fc622] h6{font-size:1em}.markdown-user-prompt[data-v-db2fc622]{color:var(--kobo-text-2);font-size:12px;font-style:italic}.markdown-user-prompt[data-v-db2fc622] p{margin:0 0 .4em}.markdown-user-prompt[data-v-db2fc622] code{background:#ffffff14;border-radius:3px;padding:.1em .3em;font-style:normal}.image-lightbox-img{-o-object-fit:contain;object-fit:contain;cursor:zoom-out;background:#0000004d;border-radius:4px;max-width:92vw;max-height:92vh;display:block}.turn-card[data-v-c0e24cbd]{border:1px solid #ffffff14;border-left:3px solid var(--turn-accent);background:#ffffff05;border-radius:6px;min-width:0;max-width:100%;margin:14px 0;overflow:hidden}.turn-card--highlighted[data-v-c0e24cbd]{animation:1.8s ease-out search-highlight-c0e24cbd}@keyframes search-highlight-c0e24cbd{0%,45%{box-shadow:0 0 0 2px #818cf8f2,0 0 22px #818cf873}to{box-shadow:none}}.turn-header[data-v-c0e24cbd]{color:var(--kobo-text-3);background:#ffffff08;border-bottom:1px solid #ffffff0d;align-items:center;gap:8px;padding:8px 14px;font-size:11px;display:flex}.turn-badge[data-v-c0e24cbd]{letter-spacing:.3px;border-radius:3px;padding:2px 8px;font-size:11px;font-weight:700}.turn-badge-user[data-v-c0e24cbd]{color:var(--kobo-turn-user);background:#ce93d826}.turn-badge-agent[data-v-c0e24cbd]{color:var(--kobo-turn-agent);background:#7986cb26}.turn-badge-system[data-v-c0e24cbd]{color:var(--kobo-text-2);background:#75757533;font-style:italic}.turn-badge-session[data-v-c0e24cbd]{color:var(--kobo-text-3);background:#61616133}.turn-badge-script[data-v-c0e24cbd]{color:var(--kobo-success);background:#4db6ac26}.turn-time[data-v-c0e24cbd]{color:var(--kobo-text-disabled);font-family:var(--kobo-font-mono);font-size:11px}.turn-time-arrow[data-v-c0e24cbd]{opacity:.7;margin:0 -2px}.turn-time-updated[data-v-c0e24cbd]{color:var(--kobo-text-3)}.turn-actions[data-v-c0e24cbd]{color:var(--kobo-text-3);font-size:11px}.turn-body[data-v-c0e24cbd]{flex-direction:column;gap:12px;min-width:0;padding:14px 18px;display:flex}.turn-body[data-v-c0e24cbd]>*{min-width:0;max-width:100%}.turn-body[data-v-c0e24cbd] .tool-row+.tool-row{margin-top:-8px}.turn-scroll-top[data-v-c0e24cbd]{justify-content:flex-start;padding:0 8px 6px;display:flex}.turn-scroll-top-btn[data-v-c0e24cbd]{opacity:.5;transition:opacity .15s}.turn-scroll-top-btn[data-v-c0e24cbd]:hover{opacity:1}.activity-feed-wrap[data-v-f3878c46]{flex-direction:column;width:100%;height:100%;display:flex;position:relative}.activity-feed-scroll[data-v-f3878c46]{flex:1;width:100%;height:100%;min-height:0}.activity-feed-nav-cluster[data-v-f3878c46]{z-index:2;align-items:center;gap:8px;display:flex;position:absolute;bottom:14px;right:14px}.activity-feed-compacting[data-v-f3878c46]{z-index:3;background:var(--kobo-surface);border:1px solid var(--kobo-border);border-radius:6px;align-items:center;gap:8px;padding:6px 14px;display:flex;position:absolute;top:12px;left:50%;transform:translate(-50%);box-shadow:0 4px 16px #00000059}.fade-enter-active[data-v-f3878c46],.fade-leave-active[data-v-f3878c46]{transition:opacity .16s}.fade-enter-from[data-v-f3878c46],.fade-leave-to[data-v-f3878c46]{opacity:0}.activity-feed-nav-btn[data-v-f3878c46]{opacity:.8;transition:opacity .12s}.activity-feed-nav-btn[data-v-f3878c46]:hover{opacity:1}.activity-feed-scroll[data-v-f3878c46] .q-scrollarea__content{max-width:100%;overflow-x:hidden}.activity-feed-switching[data-v-f3878c46]{justify-content:center;align-items:center;width:100%;height:100%;display:flex}.activity-feed-empty[data-v-f3878c46]{align-items:center;gap:var(--kobo-space-sm);padding:var(--kobo-space-4xl) var(--kobo-space-xl);color:var(--kobo-text-3);text-align:center;flex-direction:column;display:flex}.activity-feed-empty__title[data-v-f3878c46]{font-family:var(--kobo-font-sans);color:var(--kobo-text-2);font-size:14px;font-weight:500}.activity-feed-empty__hint[data-v-f3878c46]{font-family:var(--kobo-font-sans);color:var(--kobo-text-3);max-width:380px;font-size:13px}
|