@loicngr/kobo 1.11.30 → 1.11.32

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 (164) hide show
  1. package/AGENTS.md +6 -1
  2. package/CHANGELOG.md +9 -0
  3. package/dist/server/routes/workspaces.js +46 -10
  4. package/dist/server/services/forge/bitbucket/provider.js +2 -1
  5. package/dist/server/services/forge/github/provider.js +3 -2
  6. package/dist/server/services/forge/gitlab/provider.js +2 -1
  7. package/dist/server/services/forge/types.js +10 -0
  8. package/dist/server/services/git-stats-service.js +2 -0
  9. package/dist/server/utils/git-ops.js +38 -4
  10. package/package.json +1 -1
  11. package/src/client/dist/pwa/assets/{ActivityFeed-C6XSxdJ0.css → ActivityFeed-Bakgvay6.css} +1 -1
  12. package/src/client/dist/pwa/assets/ActivityFeed-C7tG4Cgq.js +8 -0
  13. package/src/client/dist/pwa/assets/ChangelogPage-DKJkFiU_.css +1 -0
  14. package/src/client/dist/pwa/assets/ChangelogPage-FYve4efm.js +1 -0
  15. package/src/client/dist/pwa/assets/ClosePopup-DLm_uRNv.js +1 -0
  16. package/src/client/dist/pwa/assets/ComparisonPanel-DRzYHcWf.js +2 -0
  17. package/src/client/dist/pwa/assets/CreatePage-CT10FMyq.js +2 -0
  18. package/src/client/dist/pwa/assets/CreatePage-DxOyY65u.css +1 -0
  19. package/src/client/dist/pwa/assets/DashboardPage-CT3XzDaz.js +1 -0
  20. package/src/client/dist/pwa/assets/DashboardPage-DsWn5cWl.css +1 -0
  21. package/src/client/dist/pwa/assets/DiffViewer-CIY7UOt6.js +8 -0
  22. package/src/client/dist/pwa/assets/DocumentsPanel-D2IlwigV.js +1 -0
  23. package/src/client/dist/pwa/assets/DrawerToggleButton-0fKZjElk.js +1 -0
  24. package/src/client/dist/pwa/assets/{GitPanel-DVs5BCU-.css → GitPanel-De5_E4NA.css} +1 -1
  25. package/src/client/dist/pwa/assets/GitPanel-DjG7-AsO.js +3 -0
  26. package/src/client/dist/pwa/assets/HealthPage-BJKRSg5I.js +1 -0
  27. package/src/client/dist/pwa/assets/HealthPage-CFZ-tdKK.css +1 -0
  28. package/src/client/dist/pwa/assets/MainLayout-BSHKEpzs.js +2 -0
  29. package/src/client/dist/pwa/assets/{MainLayout-DxYQV-Ni.css → MainLayout-BUTz2ks4.css} +1 -1
  30. package/src/client/dist/pwa/assets/QBadge-CWEaKfKi.js +1 -0
  31. package/src/client/dist/pwa/assets/QBanner-DRiFK0GP.js +1 -0
  32. package/src/client/dist/pwa/assets/QBtn-DqZryKOh.js +1 -0
  33. package/src/client/dist/pwa/assets/QBtnDropdown-Bqa7KhX7.js +1 -0
  34. package/src/client/dist/pwa/assets/QBtnGroup-BY6XqeTJ.js +1 -0
  35. package/src/client/dist/pwa/assets/QBtnToggle-CCgwqSgg.js +1 -0
  36. package/src/client/dist/pwa/assets/QChip-CJ6WmvGE.js +1 -0
  37. package/src/client/dist/pwa/assets/QDrawer-DinZbnyn.js +1 -0
  38. package/src/client/dist/pwa/assets/QItemSection-CjrpcdN_.js +1 -0
  39. package/src/client/dist/pwa/assets/QMarkupTable-MxPL53nz.js +1 -0
  40. package/src/client/dist/pwa/assets/QSpinnerDots-6v3Yl0T6.js +1 -0
  41. package/src/client/dist/pwa/assets/SchedulePanel-BDmDDRMX.js +1 -0
  42. package/src/client/dist/pwa/assets/SearchPage-BdisvUwr.js +1 -0
  43. package/src/client/dist/pwa/assets/SearchPage-CVgRa025.css +1 -0
  44. package/src/client/dist/pwa/assets/{SettingsPage-DHFMKY_1.css → SettingsPage-CDA54yPx.css} +1 -1
  45. package/src/client/dist/pwa/assets/SettingsPage-DCJgxm6J.js +9 -0
  46. package/src/client/dist/pwa/assets/TerminalPanel-DBnSOJ3B.js +16 -0
  47. package/src/client/dist/pwa/assets/TouchPan-D77wzGyc.js +1 -0
  48. package/src/client/dist/pwa/assets/TourReplayButton-DU2PItj-.js +1 -0
  49. package/src/client/dist/pwa/assets/WorkspaceAttentionLabels-CRVNJtmB.js +1 -0
  50. package/src/client/dist/pwa/assets/{WorkspacePage-3rwxkeew.css → WorkspacePage-D3-AEaPN.css} +1 -1
  51. package/src/client/dist/pwa/assets/WorkspacePage-Dv3ED-Bt.js +4 -0
  52. package/src/client/dist/pwa/assets/{browser-Bg25_sDh.js → browser-sSy6JmeQ.js} +2 -2
  53. package/src/client/dist/pwa/assets/build-path-tree-B2-SsE87.js +1 -0
  54. package/src/client/dist/pwa/assets/de-D_OhjWJx.js +17 -0
  55. package/src/client/dist/pwa/assets/documents-D4BcPyOF.js +1 -0
  56. package/src/client/dist/pwa/assets/editor.api-NH9tSUby.js +413 -0
  57. package/src/client/dist/pwa/assets/editor.worker-CwQAd_xr.js +30 -0
  58. package/src/client/dist/pwa/assets/efforts-BdCfujEx.js +9 -0
  59. package/src/client/dist/pwa/assets/engineFeatures-6ikmzzfp.js +1 -0
  60. package/src/client/dist/pwa/assets/es-kxJ0xgkc.js +17 -0
  61. package/src/client/dist/pwa/assets/expand-template-3E9x3FGS.js +1 -0
  62. package/src/client/dist/pwa/assets/{format-DSh3Ghaw.js → format-CR20Lbwg.js} +30 -30
  63. package/src/client/dist/pwa/assets/formatters-TuKWWdWq.js +1 -0
  64. package/src/client/dist/pwa/assets/fr-BgQGh90C.js +17 -0
  65. package/src/client/dist/pwa/assets/{freemarker2-BdMCo-ui.js → freemarker2-F7dLhXbU.js} +1 -1
  66. package/src/client/dist/pwa/assets/{handlebars-CVUpmZRG.js → handlebars-hXFhj5eh.js} +1 -1
  67. package/src/client/dist/pwa/assets/{html-B9nx87id.js → html-7nsVC4pO.js} +1 -1
  68. package/src/client/dist/pwa/assets/{i18n-B_ietr0X.js → i18n-Djnp5xDA.js} +1 -1
  69. package/src/client/dist/pwa/assets/index-CUoUy6tH.css +1 -0
  70. package/src/client/dist/pwa/assets/index-DztjpQfb.js +20 -0
  71. package/src/client/dist/pwa/assets/it-BmzSIMv5.js +17 -0
  72. package/src/client/dist/pwa/assets/{javascript-B0F3ZRYP.js → javascript-59rTAWws.js} +1 -1
  73. package/src/client/dist/pwa/assets/{liquid-C2jkK9Te.js → liquid-BP6Awnwy.js} +1 -1
  74. package/src/client/dist/pwa/assets/{mdx-B9CyGsGZ.js → mdx-CiCpqnQ4.js} +1 -1
  75. package/src/client/dist/pwa/assets/monaco-contributions-DzI5nDgU.js +51 -0
  76. package/src/client/dist/pwa/assets/monaco.contribution-9uLUIE5c.js +2 -0
  77. package/src/client/dist/pwa/assets/{network-auth-CXNehcyv.js → network-auth--GlWvRqv.js} +1 -1
  78. package/src/client/dist/pwa/assets/{notify-theme-DzIPRvEu.js → notify-theme-DQ_bPMUo.js} +1 -1
  79. package/src/client/dist/pwa/assets/pending-diff-open-CK20L_pt.js +1 -0
  80. package/src/client/dist/pwa/assets/permissionModes-DORv0Hwo.js +36 -0
  81. package/src/client/dist/pwa/assets/pinia-jcytgarH.js +1 -0
  82. package/src/client/dist/pwa/assets/private.use-form-DVqJLg-9.js +1 -0
  83. package/src/client/dist/pwa/assets/{project-color-D8UVi4-G.js → project-color-DrojOIC6.js} +1 -1
  84. package/src/client/dist/pwa/assets/{python-D6494OxU.js → python-BfVlMXCp.js} +1 -1
  85. package/src/client/dist/pwa/assets/{razor-uuwEcrBe.js → razor-CxyOPnW7.js} +1 -1
  86. package/src/client/dist/pwa/assets/reactivity.esm-bundler-DEJj9cFv.js +1 -0
  87. package/src/client/dist/pwa/assets/render-chat-markdown-nZGk_TRQ.js +67 -0
  88. package/src/client/dist/pwa/assets/runtime-core.esm-bundler-CS0xkoG_.js +1 -0
  89. package/src/client/dist/pwa/assets/{typescript-umL7JrOg.js → typescript-Bke62OsW.js} +1 -1
  90. package/src/client/dist/pwa/assets/use-checkbox-DDRAnhSJ.js +1 -0
  91. package/src/client/dist/pwa/assets/use-is-mobile-ClPMtqZc.js +1 -0
  92. package/src/client/dist/pwa/assets/use-tours-BEdbVcQS.js +2 -0
  93. package/src/client/dist/pwa/assets/{workspace-templates-CkKJmfTo.js → workspace-templates-1zUtbH31.js} +1 -1
  94. package/src/client/dist/pwa/assets/{xml-Nu9IP_9Z.js → xml-Cg47p-KM.js} +1 -1
  95. package/src/client/dist/pwa/assets/{yaml-D_Py0JsF.js → yaml-Dj1MTjr-.js} +1 -1
  96. package/src/client/dist/pwa/index.html +8 -11
  97. package/src/client/dist/pwa/sw.js +1 -1
  98. package/src/client/dist/pwa/assets/ActivityFeed-Cx1rS3ci.js +0 -8
  99. package/src/client/dist/pwa/assets/ChangelogPage-2OaGEKe9.js +0 -1
  100. package/src/client/dist/pwa/assets/ChangelogPage-D_WOVByV.css +0 -1
  101. package/src/client/dist/pwa/assets/ClosePopup-CvV-0nzX.js +0 -1
  102. package/src/client/dist/pwa/assets/ComparisonPanel-BmUrmK4m.js +0 -2
  103. package/src/client/dist/pwa/assets/CreatePage-C0uUaDXT.css +0 -1
  104. package/src/client/dist/pwa/assets/CreatePage-Hp3O5al9.js +0 -2
  105. package/src/client/dist/pwa/assets/DashboardPage-BqgK4lAf.css +0 -1
  106. package/src/client/dist/pwa/assets/DashboardPage-Mgx1FG2b.js +0 -1
  107. package/src/client/dist/pwa/assets/DiffViewer-aMjhTpVF.js +0 -8
  108. package/src/client/dist/pwa/assets/DocumentsPanel-Cdr5b21_.js +0 -1
  109. package/src/client/dist/pwa/assets/DrawerToggleButton-VEVxQ39S.js +0 -1
  110. package/src/client/dist/pwa/assets/GitPanel-DUJ15ikk.js +0 -3
  111. package/src/client/dist/pwa/assets/HealthPage-BbqLoFQj.css +0 -1
  112. package/src/client/dist/pwa/assets/HealthPage-v_jKOByf.js +0 -1
  113. package/src/client/dist/pwa/assets/MainLayout-jRXQQzPm.js +0 -2
  114. package/src/client/dist/pwa/assets/QBadge-BgS0-MXB.js +0 -1
  115. package/src/client/dist/pwa/assets/QBanner-CDiXUya7.js +0 -1
  116. package/src/client/dist/pwa/assets/QBtn-B7WFdfmy.js +0 -1
  117. package/src/client/dist/pwa/assets/QBtnDropdown-pyNCwmSZ.js +0 -1
  118. package/src/client/dist/pwa/assets/QBtnGroup-BMQlX2YS.js +0 -1
  119. package/src/client/dist/pwa/assets/QBtnToggle-eMu_yinY.js +0 -1
  120. package/src/client/dist/pwa/assets/QChip-DpUYTCOJ.js +0 -1
  121. package/src/client/dist/pwa/assets/QItemSection-CEUi4Tz0.js +0 -1
  122. package/src/client/dist/pwa/assets/QMarkupTable-DcoQpjPu.js +0 -1
  123. package/src/client/dist/pwa/assets/QPage-RpDxx5ah.js +0 -1
  124. package/src/client/dist/pwa/assets/QSpace-D3PNLwa4.js +0 -1
  125. package/src/client/dist/pwa/assets/QSpinnerDots-DWOFEezR.js +0 -1
  126. package/src/client/dist/pwa/assets/SchedulePanel-DBc1j1k3.js +0 -1
  127. package/src/client/dist/pwa/assets/SearchPage-CWca6d5o.js +0 -1
  128. package/src/client/dist/pwa/assets/SearchPage-DdWM01rq.css +0 -1
  129. package/src/client/dist/pwa/assets/SettingsPage-qKa3e6W-.js +0 -10
  130. package/src/client/dist/pwa/assets/TerminalPanel-Dv_1sNtU.js +0 -18
  131. package/src/client/dist/pwa/assets/TouchPan-DPBRkGyO.js +0 -1
  132. package/src/client/dist/pwa/assets/WorkspaceAttentionLabels-CevQAXwk.js +0 -1
  133. package/src/client/dist/pwa/assets/WorkspacePage-CEwILZ6V.js +0 -4
  134. package/src/client/dist/pwa/assets/build-path-tree-Cx5bCcQs.js +0 -1
  135. package/src/client/dist/pwa/assets/de-BUPxnXau.js +0 -17
  136. package/src/client/dist/pwa/assets/debounce-CDIE7CV6.js +0 -1
  137. package/src/client/dist/pwa/assets/documents-CN6TlZH7.js +0 -1
  138. package/src/client/dist/pwa/assets/editor.api-vup96nzB.js +0 -413
  139. package/src/client/dist/pwa/assets/editor.worker-D-m8IBMa.js +0 -30
  140. package/src/client/dist/pwa/assets/efforts-BcV6XR1p.js +0 -9
  141. package/src/client/dist/pwa/assets/engineFeatures-D9IQa3bt.js +0 -1
  142. package/src/client/dist/pwa/assets/es-DMnEKZ17.js +0 -17
  143. package/src/client/dist/pwa/assets/expand-template-Cxl3iYaV.js +0 -1
  144. package/src/client/dist/pwa/assets/formatters-CQ90Icr4.js +0 -1
  145. package/src/client/dist/pwa/assets/fr-BTolHkCj.js +0 -17
  146. package/src/client/dist/pwa/assets/index-6H3m6vH7.css +0 -1
  147. package/src/client/dist/pwa/assets/index-BePGTdV0.js +0 -18
  148. package/src/client/dist/pwa/assets/it-BPFSv6Pp.js +0 -17
  149. package/src/client/dist/pwa/assets/layout-DE4C3CX3.js +0 -1
  150. package/src/client/dist/pwa/assets/monaco-contributions-BZH2_u8S.js +0 -51
  151. package/src/client/dist/pwa/assets/monaco.contribution--NRhv52L.js +0 -2
  152. package/src/client/dist/pwa/assets/pending-diff-open-DoKaz8uO.js +0 -1
  153. package/src/client/dist/pwa/assets/permissionModes-D58HKBN0.js +0 -36
  154. package/src/client/dist/pwa/assets/pinia-ClsyLh3i.js +0 -1
  155. package/src/client/dist/pwa/assets/private.use-form-D8Yuc3aU.js +0 -1
  156. package/src/client/dist/pwa/assets/reactivity.esm-bundler-DtSZKRQB.js +0 -1
  157. package/src/client/dist/pwa/assets/render-chat-markdown-BTcSOgEc.js +0 -67
  158. package/src/client/dist/pwa/assets/rolldown-runtime-hePW80VL.js +0 -1
  159. package/src/client/dist/pwa/assets/runtime-dom.esm-bundler-DgevF6KV.js +0 -4
  160. package/src/client/dist/pwa/assets/use-checkbox-3io6bTPe.js +0 -1
  161. package/src/client/dist/pwa/assets/use-onboarding-BE2bb17E.js +0 -2
  162. package/src/client/dist/pwa/assets/use-quasar-0nZoDKhp.js +0 -1
  163. package/src/client/dist/pwa/assets/vue-i18n-DtajJy_8.js +0 -3
  164. /package/src/client/dist/pwa/assets/{use-onboarding-CTZuBZOi.css → use-tours-CTZuBZOi.css} +0 -0
package/AGENTS.md CHANGED
@@ -91,8 +91,9 @@ src/
91
91
  ├── client/ # Vue 3 + Quasar PWA
92
92
  │ └── src/
93
93
  │ ├── stores/ # pinia: workspace, websocket, settings, dev-server, templates
94
- │ ├── components/ # WorkspaceList, NotionPanel, AcceptancePanel, ChatInput, GitPanel, PlansPanel, WorkspaceAttentionLabels…
94
+ │ ├── components/ # WorkspaceList, NotionPanel, AcceptancePanel, ChatInput, GitPanel, PlansPanel, WorkspaceAttentionLabels, HelpMenu…
95
95
  │ ├── utils/ # expand-template, formatters, workspace-attention (CI failure / changes-requested derivation)…
96
+ │ ├── tours/ # declarative onboarding tours, one file per zone + registry
96
97
  │ ├── pages/ # WorkspacePage, CreatePage, SettingsPage
97
98
  │ └── router/
98
99
  ├── mcp-server/ # standalone MCP server spawned per workspace
@@ -250,6 +251,10 @@ One task, two engines, two sibling worktrees. `POST /api/workspaces` accepts a `
250
251
 
251
252
  `workspace-template-service.ts` persists named presets of the create form in `<KOBO_HOME>/workspace-templates.json` (same JSON pattern as `templates.json`, no SQLite migration). `sanitizePreset` keeps known keys with the right type and drops the rest, so a hand-edited file degrades to unset fields rather than errors. `presetFromWorkspace(id)` derives the same shape from an existing workspace (tasks as titles, statuses dropped); `GET /api/workspaces/:id/preset` exposes it read-only and "Duplicate" opens `/create?from=<id>` with it. On the client, `utils/workspace-preset.ts` (`capturePreset` / `applyPreset`, pure, round-trip tested) is the single bridge between the form and a preset; the create page applies the engine first and waits a tick so its engine watchers normalise model / effort / permission mode before the preset's values land. See [CONFIGURATION.md → Workspace templates and duplication](CONFIGURATION.md#workspace-templates-and-duplication).
252
253
 
254
+ ### Onboarding tours
255
+
256
+ `src/client/src/tours/` declares one driver.js tour per zone (home, create, workspace, git-pr, settings, dashboard, health, search, changelog) as data, one file per zone plus `registry.ts` whose order is the Help menu order: each step carries a stable id, a `data-tour` anchor, an i18n key prefix and optionally `when` (a run-time gate, `anchorPresent` from `dom.ts` for the steps whose anchor is rendered conditionally), `beforeShow` (open a tab, then the engine waits for the anchor to be visible) and `clickTarget` (the anchor `beforeShow` clicks). `composables/use-tours.ts` owns the single driver instance and the seen-state (`localStorage['kobo:tours']`, step ids per tour, marked as each step is shown so leaving mid-way only replays the rest); `migrateLegacyFlag` turns the pre-tours boolean flag into a fully seen home tour. `autoRun` shows unseen steps only, never stacks over a running tour and never navigates - it bails unless the current route is the tour's route - so the main layout and the pages arm it through `scheduleAutoRun`, which delays it past their first render and clears the timer on unmount; a run refused because another tour is running is queued and replayed in registry order, and a run refused because a dialog is open is retried once. `runTour`, used by the Help menu in the sidebar (which lists every tour with its status and can reset them all) and by the per-screen replay buttons, is the only path that navigates to the tour's route first. `waitForVisible` in `dom.ts` waits until the anchor intersects the viewport, not merely until it exists in the DOM; when an anchor never shows up the engine skips that step with a console warning and does not mark it seen, so it replays next time. `SETTINGS_GROUPS` in `tours/settings.ts` groups the Settings tabs into one step each. `tours-registry.test.ts` is a drift guard with a deliberately narrow scope: it fails when a step's anchor or `clickTarget` has no matching `data-tour` attribute in a Vue source, when an i18n key is missing in one of the five locales, when a Settings tab is not in exactly one group, or when a step id listed in its hand-maintained list of gated steps has lost its `when`. It does not detect a newly conditional anchor on its own - adding a `v-if` around an anchor means adding the step id to that list. A feature that adds a screen or a Settings tab adds its step or group; step ids are never renamed once shipped.
257
+
253
258
  ### Worktree purge
254
259
 
255
260
  `src/server/services/worktree-purge-service.ts` removes a workspace's worktree from disk while preserving the chat history and PR metadata. Triggered manually via `POST /api/workspaces/:id/purge-worktree` from the workspace context menu, or automatically by the pr-watcher when a PR transitions to MERGED **and** `global.autoPurgeOnPrMerged` is enabled (Settings → Worktrees toggle, settings migration v36).
package/CHANGELOG.md CHANGED
@@ -4,6 +4,15 @@ All notable changes to Kōbō are documented here. The format is based on
4
4
  [Keep a Changelog](https://keepachangelog.com/). Each release is an `## <version>`
5
5
  section — the in-app "What's new" dialog reads this file.
6
6
 
7
+ ## 1.11.32
8
+
9
+ - chore(deps): npm update in the server and client trees
10
+ - fix(git): refuse push during a rebase and prefill workspaces from a PR
11
+
12
+ ## 1.11.31
13
+
14
+ - feat(onboarding): per-zone guided tours with a help menu
15
+
7
16
  ## 1.11.30
8
17
 
9
18
  - feat: workspace templates, duplication and per-engine default models
@@ -3564,16 +3564,26 @@ app.post('/:id/push', async (c) => {
3564
3564
  const body = await c.req.json().catch(() => ({}));
3565
3565
  const force = body?.force === true;
3566
3566
  const worktreePath = workspace.worktreePath;
3567
+ // While a rebase / merge / cherry-pick is in flight the local branch ref
3568
+ // has not moved yet, so `git push` would exit 0 with "Everything
3569
+ // up-to-date" and the user would see nothing happen. Refuse instead.
3570
+ const ongoing = gitOps.getOngoingGitOperation(worktreePath);
3571
+ if (ongoing) {
3572
+ return c.json({
3573
+ error: `Cannot push while a ${ongoing} is in progress on branch '${workspace.workingBranch}'. Finish or abort it first.`,
3574
+ code: 'operation_in_progress',
3575
+ operation: ongoing,
3576
+ }, 409);
3577
+ }
3578
+ let upToDate;
3567
3579
  try {
3568
3580
  // Only pass an options arg when force is requested — keeps the
3569
3581
  // no-options call shape identical to before for callers/tests that
3570
3582
  // assert on argument count.
3571
- if (force) {
3572
- await gitOps.pushBranchAsync(worktreePath, workspace.workingBranch, { force: true });
3573
- }
3574
- else {
3575
- await gitOps.pushBranchAsync(worktreePath, workspace.workingBranch);
3576
- }
3583
+ const result = force
3584
+ ? await gitOps.pushBranchAsync(worktreePath, workspace.workingBranch, { force: true })
3585
+ : await gitOps.pushBranchAsync(worktreePath, workspace.workingBranch);
3586
+ upToDate = result.upToDate;
3577
3587
  }
3578
3588
  catch (err) {
3579
3589
  const message = err instanceof Error ? err.message : String(err);
@@ -3581,8 +3591,13 @@ app.post('/:id/push', async (c) => {
3581
3591
  }
3582
3592
  // Emit a trace into the chat feed so the user sees the action
3583
3593
  const session = workspaceService.getActiveSession(id);
3584
- wsService.emit(id, 'user:message', { content: `Pushed branch ${workspace.workingBranch} to origin`, sender: 'system-prompt' }, session?.id ?? undefined);
3585
- return c.json({ ok: true, branch: workspace.workingBranch });
3594
+ wsService.emit(id, 'user:message', {
3595
+ content: upToDate
3596
+ ? `Nothing to push: branch ${workspace.workingBranch} is already up to date on origin`
3597
+ : `Pushed branch ${workspace.workingBranch} to origin`,
3598
+ sender: 'system-prompt',
3599
+ }, session?.id ?? undefined);
3600
+ return c.json({ ok: true, branch: workspace.workingBranch, upToDate });
3586
3601
  }
3587
3602
  catch (err) {
3588
3603
  const message = err instanceof Error ? err.message : String(err);
@@ -4041,8 +4056,29 @@ app.post('/:id/force-push', async (c) => {
4041
4056
  const workspace = workspaceService.getWorkspace(id);
4042
4057
  if (!workspace)
4043
4058
  return c.json({ error: `Workspace '${id}' not found` }, 404);
4044
- await gitOps.pushBranchAsync(workspace.worktreePath, workspace.workingBranch, { force: true });
4045
- return c.json({ success: true });
4059
+ // Same guard as /push: mid-rebase the branch ref has not moved, so the
4060
+ // force push would be a silent "Everything up-to-date" no-op.
4061
+ const ongoing = gitOps.getOngoingGitOperation(workspace.worktreePath);
4062
+ if (ongoing) {
4063
+ return c.json({
4064
+ error: `Cannot force push while a ${ongoing} is in progress on branch '${workspace.workingBranch}'. Finish or abort it first.`,
4065
+ code: 'operation_in_progress',
4066
+ operation: ongoing,
4067
+ }, 409);
4068
+ }
4069
+ const { upToDate } = await gitOps.pushBranchAsync(workspace.worktreePath, workspace.workingBranch, {
4070
+ force: true,
4071
+ });
4072
+ if (upToDate) {
4073
+ // This route never traced its pushes; only the surprising no-op case is
4074
+ // worth a line in the chat, so the user knows why nothing changed.
4075
+ const session = workspaceService.getActiveSession(id);
4076
+ wsService.emit(id, 'user:message', {
4077
+ content: `Nothing to push: branch ${workspace.workingBranch} is already up to date on origin`,
4078
+ sender: 'system-prompt',
4079
+ }, session?.id ?? undefined);
4080
+ }
4081
+ return c.json({ success: true, upToDate });
4046
4082
  }
4047
4083
  catch (err) {
4048
4084
  const message = err instanceof Error ? err.message : String(err);
@@ -2,7 +2,7 @@ import { execFile } from 'node:child_process';
2
2
  import { promisify } from 'node:util';
3
3
  import { getGlobalSettings } from '../../settings-service.js';
4
4
  import { parseCliJson } from '../parse-cli-json.js';
5
- import { deriveReadyToMerge } from '../types.js';
5
+ import { deriveReadyToMerge, truncatePrBody } from '../types.js';
6
6
  const execFileAsync = promisify(execFile);
7
7
  function record(value) {
8
8
  return value !== null && typeof value === 'object' ? value : {};
@@ -141,6 +141,7 @@ export function mapBitbucketPage(raw) {
141
141
  isFork: Boolean(sourceId) && Boolean(destId) && sourceId !== destId,
142
142
  isDraft: pr.draft === true,
143
143
  updatedAt: typeof updated === 'string' ? updated : typeof updated === 'number' ? new Date(updated).toISOString() : '',
144
+ body: truncatePrBody(pr.description),
144
145
  // `bkt pr list` doesn't expose CI/review status in list output; avoiding a per-row lookup call here.
145
146
  ci: null,
146
147
  reviewDecision: null,
@@ -2,7 +2,7 @@
2
2
  import { execFile } from 'node:child_process';
3
3
  import { promisify } from 'node:util';
4
4
  import { parseCliJson } from '../parse-cli-json.js';
5
- import { deriveReadyToMerge } from '../types.js';
5
+ import { deriveReadyToMerge, truncatePrBody } from '../types.js';
6
6
  const execFileAsync = promisify(execFile);
7
7
  const CLI_TIMEOUT_MS = 30_000;
8
8
  function cliOptions(repoPath) {
@@ -93,7 +93,7 @@ query($q:String!,$first:Int!,$after:String){
93
93
  pageInfo{ hasNextPage endCursor }
94
94
  nodes{
95
95
  ... on PullRequest {
96
- number title url isDraft updatedAt
96
+ number title url isDraft updatedAt body
97
97
  author{ login }
98
98
  headRefName baseRefName isCrossRepository reviewDecision
99
99
  commits(last:1){ nodes{ commit{ statusCheckRollup{ state } } } }
@@ -133,6 +133,7 @@ export function mapGithubSearchPage(raw) {
133
133
  isFork: pr.isCrossRepository === true,
134
134
  isDraft: pr.isDraft === true,
135
135
  updatedAt: typeof pr.updatedAt === 'string' ? pr.updatedAt : '',
136
+ body: truncatePrBody(pr.body),
136
137
  ci: typeof rollup === 'string' ? rollup : null,
137
138
  reviewDecision: typeof decision === 'string' ? decision : null,
138
139
  };
@@ -2,7 +2,7 @@
2
2
  import { execFile } from 'node:child_process';
3
3
  import { promisify } from 'node:util';
4
4
  import { parseCliJson } from '../parse-cli-json.js';
5
- import { deriveReadyToMerge } from '../types.js';
5
+ import { deriveReadyToMerge, truncatePrBody } from '../types.js';
6
6
  const execFileAsync = promisify(execFile);
7
7
  const CLI_TIMEOUT_MS = 30_000;
8
8
  function cliOptions(repoPath) {
@@ -148,6 +148,7 @@ export function mapGitlabPage(raw, opts) {
148
148
  isFork: mr.source_project_id !== mr.target_project_id,
149
149
  isDraft: mr.draft === true || mr.work_in_progress === true,
150
150
  updatedAt: typeof mr.updated_at === 'string' ? mr.updated_at : '',
151
+ body: truncatePrBody(mr.description),
151
152
  // `glab mr list` carries no pipeline status; the picker shows no CI pill
152
153
  // for GitLab rather than paying one `glab ci get` per row.
153
154
  ci: null,
@@ -18,6 +18,16 @@ export function deriveReadyToMerge(s) {
18
18
  const noConflict = s.mergeable === 'MERGEABLE' || s.mergeable === null;
19
19
  return s.state === 'OPEN' && ciOk && !blocked && noConflict;
20
20
  }
21
+ /**
22
+ * Cap on `PullRequestSummary.body`. The picker lists up to a page of PRs at a
23
+ * time and the create form only needs enough to prefill a description, so a
24
+ * multi-megabyte body would be pure transfer cost.
25
+ */
26
+ export const PR_BODY_MAX_CHARS = 4000;
27
+ /** Normalise a raw CLI body into `PullRequestSummary.body`. */
28
+ export function truncatePrBody(value) {
29
+ return typeof value === 'string' ? value.slice(0, PR_BODY_MAX_CHARS) : '';
30
+ }
21
31
  /** Thrown by write operations when the forge cannot service them. */
22
32
  export class ForgeUnavailableError extends Error {
23
33
  code = 'forge_unavailable';
@@ -29,6 +29,8 @@ export async function computeGitStats(workspace, prSnapshot) {
29
29
  prState: prSnapshot?.state ?? null,
30
30
  unpushedCount,
31
31
  workingTree,
32
+ // Sync and local (a few stat calls); not worth a slot in the Promise.all.
33
+ ongoingOperation: gitOps.getOngoingGitOperation(worktreePath),
32
34
  forge: { id: forgeProvider.id, capabilities: forgeProvider.capabilities, availability },
33
35
  computedAt: Date.now(),
34
36
  };
@@ -27,6 +27,10 @@ export function buildNonInteractiveGitEnv() {
27
27
  ...process.env,
28
28
  GIT_TERMINAL_PROMPT: '0',
29
29
  GIT_ASKPASS: 'echo',
30
+ // Several callers parse git's human-readable output ("Everything
31
+ // up-to-date", "already exists", "N files changed"). Pin the C locale so a
32
+ // translated git never silently defeats those checks.
33
+ LC_ALL: 'C',
30
34
  // `GIT_ASKPASS` only covers HTTP(S) credential prompts. A passphrase-
31
35
  // protected SSH key with no running agent still blocks `ssh` on
32
36
  // `/dev/tty`; `BatchMode=yes` makes that interactive auth fail in ~1s
@@ -80,14 +84,23 @@ async function gitAsync(repoPath, args, timeout = READ_ONLY_GIT_TIMEOUT_MS) {
80
84
  * over a slow link froze the entire app for up to a minute, heartbeat included.
81
85
  */
82
86
  async function gitNetworkAsync(repoPath, args) {
83
- const { stdout } = await execFileAsync('git', args, {
87
+ const { stdout } = await gitNetworkAsyncFull(repoPath, args);
88
+ return stdout;
89
+ }
90
+ /**
91
+ * Same as `gitNetworkAsync` but also hands back stderr: git prints push
92
+ * progress and the "Everything up-to-date" notice there, not on stdout, and a
93
+ * caller that wants to distinguish a no-op push from a real one needs it.
94
+ */
95
+ async function gitNetworkAsyncFull(repoPath, args) {
96
+ const { stdout, stderr } = await execFileAsync('git', args, {
84
97
  cwd: repoPath,
85
98
  encoding: 'utf-8',
86
99
  timeout: SYNC_GIT_TIMEOUT_MS,
87
100
  maxBuffer: GIT_MAX_BUFFER_BYTES,
88
101
  env: NON_INTERACTIVE_GIT_ENV,
89
102
  });
90
- return stdout.trimEnd();
103
+ return { stdout: stdout.trimEnd(), stderr: stderr.trimEnd() };
91
104
  }
92
105
  /** Raised when a stale `index.lock` blocks every write on a worktree. */
93
106
  export class GitIndexLockError extends Error {
@@ -407,6 +420,22 @@ export function mergeBranch(repoPath, baseBranch, opts) {
407
420
  throw new Error(`Merge of 'origin/${baseBranch}' failed: ${message}`);
408
421
  }
409
422
  }
423
+ /**
424
+ * Read `git push --porcelain` stdout. Each ref line is `<flag>\t<from>:<to>\t<summary>`
425
+ * where the flag is `=` (up to date), ` ` (fast-forward), `+` (forced), `*`
426
+ * (new ref), `-` (deleted) or `!` (rejected). Returns `true` when every ref is
427
+ * up to date, `false` when at least one moved, `null` when there is no ref
428
+ * line at all so the caller can fall back to another signal. Exported for tests.
429
+ */
430
+ export function parsePushPorcelain(stdout) {
431
+ const flags = stdout
432
+ .split('\n')
433
+ .filter((line) => /^[=+*\-! ]\t/.test(line))
434
+ .map((line) => line[0]);
435
+ if (flags.length === 0)
436
+ return null;
437
+ return flags.every((flag) => flag === '=');
438
+ }
410
439
  /**
411
440
  * Async variants of the network operations, for the HTTP handlers.
412
441
  *
@@ -418,12 +447,17 @@ export function mergeBranch(repoPath, baseBranch, opts) {
418
447
  */
419
448
  export async function pushBranchAsync(repoPath, branchName, options = {}) {
420
449
  const remote = options.remote ?? 'origin';
421
- const args = ['push', '-u'];
450
+ const args = ['push', '-u', '--porcelain'];
422
451
  if (options.force)
423
452
  args.push('--force-with-lease');
424
453
  args.push(remote, branchName);
425
454
  try {
426
- await gitNetworkAsync(repoPath, args);
455
+ const { stdout, stderr } = await gitNetworkAsyncFull(repoPath, args);
456
+ // `git push` exits 0 either way. `--porcelain` gives a locale-independent
457
+ // per-ref status line on stdout; the stderr notice is only a fallback for
458
+ // a git old enough to print nothing parseable.
459
+ const upToDate = parsePushPorcelain(stdout) ?? stderr.includes('Everything up-to-date');
460
+ return { upToDate };
427
461
  }
428
462
  catch (err) {
429
463
  const message = err instanceof Error ? err.message : String(err);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loicngr/kobo",
3
- "version": "1.11.30",
3
+ "version": "1.11.32",
4
4
  "description": "Kōbō — multi-workspace agent manager for Claude Code. Orchestrates isolated git worktrees with dev servers, Notion integration, and MCP tools.",
5
5
  "type": "module",
6
6
  "license": "GPL-3.0-or-later",
@@ -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-7687eb7e]{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-7687eb7e] *{max-width:100%}.markdown-message[data-v-7687eb7e] 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-7687eb7e] code{word-break:break-all}.markdown-message[data-v-7687eb7e] p{margin:0 0 .4em}.markdown-message[data-v-7687eb7e] p:last-child{margin-bottom:0}.markdown-message[data-v-7687eb7e] code{background:#00000040;border-radius:3px;padding:.1em .3em}.markdown-message[data-v-7687eb7e] h1,.markdown-message[data-v-7687eb7e] h2,.markdown-message[data-v-7687eb7e] h3,.markdown-message[data-v-7687eb7e] h4,.markdown-message[data-v-7687eb7e] h5,.markdown-message[data-v-7687eb7e] h6{margin:.4em 0 .25em;font-weight:600;line-height:1.3}.markdown-message[data-v-7687eb7e] h1{font-size:1.25em}.markdown-message[data-v-7687eb7e] h2{font-size:1.15em}.markdown-message[data-v-7687eb7e] h3{font-size:1.08em}.markdown-message[data-v-7687eb7e] h4,.markdown-message[data-v-7687eb7e] h5,.markdown-message[data-v-7687eb7e] h6{font-size:1em}.markdown-user-prompt[data-v-7687eb7e]{color:var(--kobo-text-2);font-size:12px;font-style:italic}.markdown-user-prompt[data-v-7687eb7e] p{margin:0 0 .4em}.markdown-user-prompt[data-v-7687eb7e] 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-6e61835e]{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-6e61835e]{animation:1.8s ease-out search-highlight-6e61835e}@keyframes search-highlight-6e61835e{0%,45%{box-shadow:0 0 0 2px #818cf8f2,0 0 22px #818cf873}to{box-shadow:none}}.turn-header[data-v-6e61835e]{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-6e61835e]{letter-spacing:.3px;border-radius:3px;padding:2px 8px;font-size:11px;font-weight:700}.turn-badge-user[data-v-6e61835e]{color:var(--kobo-turn-user);background:#ce93d826}.turn-badge-agent[data-v-6e61835e]{color:var(--kobo-turn-agent);background:#7986cb26}.turn-badge-system[data-v-6e61835e]{color:var(--kobo-text-2);background:#75757533;font-style:italic}.turn-badge-session[data-v-6e61835e]{color:var(--kobo-text-3);background:#61616133}.turn-badge-script[data-v-6e61835e]{color:var(--kobo-success);background:#4db6ac26}.turn-time[data-v-6e61835e]{color:var(--kobo-text-disabled);font-family:var(--kobo-font-mono);font-size:11px}.turn-time-arrow[data-v-6e61835e]{opacity:.7;margin:0 -2px}.turn-time-updated[data-v-6e61835e]{color:var(--kobo-text-3)}.turn-actions[data-v-6e61835e]{color:var(--kobo-text-3);font-size:11px}.turn-body[data-v-6e61835e]{flex-direction:column;gap:12px;min-width:0;padding:14px 18px;display:flex}.turn-body[data-v-6e61835e]>*{min-width:0;max-width:100%}.turn-body[data-v-6e61835e] .tool-row+.tool-row{margin-top:-8px}.turn-scroll-top[data-v-6e61835e]{justify-content:flex-start;padding:0 8px 6px;display:flex}.turn-scroll-top-btn[data-v-6e61835e]{opacity:.5;transition:opacity .15s}.turn-scroll-top-btn[data-v-6e61835e]:hover{opacity:1}.activity-feed-wrap[data-v-03fed8f2]{width:100%;height:100%;position:relative}.activity-feed-scroll[data-v-03fed8f2]{width:100%;height:100%}.activity-feed-nav-cluster[data-v-03fed8f2]{z-index:2;align-items:center;gap:8px;display:flex;position:absolute;bottom:14px;right:14px}.activity-feed-compacting[data-v-03fed8f2]{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-03fed8f2],.fade-leave-active[data-v-03fed8f2]{transition:opacity .16s}.fade-enter-from[data-v-03fed8f2],.fade-leave-to[data-v-03fed8f2]{opacity:0}.activity-feed-nav-btn[data-v-03fed8f2]{opacity:.8;transition:opacity .12s}.activity-feed-nav-btn[data-v-03fed8f2]:hover{opacity:1}.activity-feed-scroll[data-v-03fed8f2] .q-scrollarea__content{max-width:100%;overflow-x:hidden}.activity-feed-switching[data-v-03fed8f2]{justify-content:center;align-items:center;width:100%;height:100%;display:flex}.activity-feed-empty[data-v-03fed8f2]{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-03fed8f2]{font-family:var(--kobo-font-sans);color:var(--kobo-text-2);font-size:14px;font-weight:500}.activity-feed-empty__hint[data-v-03fed8f2]{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-7687eb7e]{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-7687eb7e] *{max-width:100%}.markdown-message[data-v-7687eb7e] 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-7687eb7e] code{word-break:break-all}.markdown-message[data-v-7687eb7e] p{margin:0 0 .4em}.markdown-message[data-v-7687eb7e] p:last-child{margin-bottom:0}.markdown-message[data-v-7687eb7e] code{background:#00000040;border-radius:3px;padding:.1em .3em}.markdown-message[data-v-7687eb7e] h1,.markdown-message[data-v-7687eb7e] h2,.markdown-message[data-v-7687eb7e] h3,.markdown-message[data-v-7687eb7e] h4,.markdown-message[data-v-7687eb7e] h5,.markdown-message[data-v-7687eb7e] h6{margin:.4em 0 .25em;font-weight:600;line-height:1.3}.markdown-message[data-v-7687eb7e] h1{font-size:1.25em}.markdown-message[data-v-7687eb7e] h2{font-size:1.15em}.markdown-message[data-v-7687eb7e] h3{font-size:1.08em}.markdown-message[data-v-7687eb7e] h4,.markdown-message[data-v-7687eb7e] h5,.markdown-message[data-v-7687eb7e] h6{font-size:1em}.markdown-user-prompt[data-v-7687eb7e]{color:var(--kobo-text-2);font-size:12px;font-style:italic}.markdown-user-prompt[data-v-7687eb7e] p{margin:0 0 .4em}.markdown-user-prompt[data-v-7687eb7e] 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-6e61835e]{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-6e61835e]{animation:1.8s ease-out search-highlight-6e61835e}@keyframes search-highlight-6e61835e{0%,45%{box-shadow:0 0 0 2px #818cf8f2,0 0 22px #818cf873}to{box-shadow:none}}.turn-header[data-v-6e61835e]{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-6e61835e]{letter-spacing:.3px;border-radius:3px;padding:2px 8px;font-size:11px;font-weight:700}.turn-badge-user[data-v-6e61835e]{color:var(--kobo-turn-user);background:#ce93d826}.turn-badge-agent[data-v-6e61835e]{color:var(--kobo-turn-agent);background:#7986cb26}.turn-badge-system[data-v-6e61835e]{color:var(--kobo-text-2);background:#75757533;font-style:italic}.turn-badge-session[data-v-6e61835e]{color:var(--kobo-text-3);background:#61616133}.turn-badge-script[data-v-6e61835e]{color:var(--kobo-success);background:#4db6ac26}.turn-time[data-v-6e61835e]{color:var(--kobo-text-disabled);font-family:var(--kobo-font-mono);font-size:11px}.turn-time-arrow[data-v-6e61835e]{opacity:.7;margin:0 -2px}.turn-time-updated[data-v-6e61835e]{color:var(--kobo-text-3)}.turn-actions[data-v-6e61835e]{color:var(--kobo-text-3);font-size:11px}.turn-body[data-v-6e61835e]{flex-direction:column;gap:12px;min-width:0;padding:14px 18px;display:flex}.turn-body[data-v-6e61835e]>*{min-width:0;max-width:100%}.turn-body[data-v-6e61835e] .tool-row+.tool-row{margin-top:-8px}.turn-scroll-top[data-v-6e61835e]{justify-content:flex-start;padding:0 8px 6px;display:flex}.turn-scroll-top-btn[data-v-6e61835e]{opacity:.5;transition:opacity .15s}.turn-scroll-top-btn[data-v-6e61835e]:hover{opacity:1}.activity-feed-wrap[data-v-01cd9f2a]{width:100%;height:100%;position:relative}.activity-feed-scroll[data-v-01cd9f2a]{width:100%;height:100%}.activity-feed-nav-cluster[data-v-01cd9f2a]{z-index:2;align-items:center;gap:8px;display:flex;position:absolute;bottom:14px;right:14px}.activity-feed-compacting[data-v-01cd9f2a]{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-01cd9f2a],.fade-leave-active[data-v-01cd9f2a]{transition:opacity .16s}.fade-enter-from[data-v-01cd9f2a],.fade-leave-to[data-v-01cd9f2a]{opacity:0}.activity-feed-nav-btn[data-v-01cd9f2a]{opacity:.8;transition:opacity .12s}.activity-feed-nav-btn[data-v-01cd9f2a]:hover{opacity:1}.activity-feed-scroll[data-v-01cd9f2a] .q-scrollarea__content{max-width:100%;overflow-x:hidden}.activity-feed-switching[data-v-01cd9f2a]{justify-content:center;align-items:center;width:100%;height:100%;display:flex}.activity-feed-empty[data-v-01cd9f2a]{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-01cd9f2a]{font-family:var(--kobo-font-sans);color:var(--kobo-text-2);font-size:14px;font-weight:500}.activity-feed-empty__hint[data-v-01cd9f2a]{font-family:var(--kobo-font-sans);color:var(--kobo-text-3);max-width:380px;font-size:13px}
@@ -0,0 +1,8 @@
1
+ import{S as e,ct as t,j as n,ot as r,ut as i,v as a}from"./reactivity.esm-bundler-DEJj9cFv.js";import{C as o,F as s,K as c,L as l,N as u,O as d,P as f,_ as p,d as m,f as h,g,j as _,k as v,l as y,p as b,q as x,r as S,u as C,y as w,z as T}from"./runtime-core.esm-bundler-CS0xkoG_.js";import{J as E,b as D,ct as O,l as k,pt as A,t as ee,tt as j,w as M,y as te}from"./QBtn-DqZryKOh.js";import{C as N,H as ne,It as re,Nt as P,T as F,bt as ie,m as ae,p as oe,vt as I,w as se}from"./index-DztjpQfb.js";import{t as ce}from"./QSpinnerDots-6v3Yl0T6.js";import{r as le}from"./QItemSection-CjrpcdN_.js";import{t as L}from"./QMarkupTable-MxPL53nz.js";import{_ as ue,b as R,x as z}from"./permissionModes-DORv0Hwo.js";import{r as de,t as B}from"./pending-diff-open-CK20L_pt.js";import{t as V}from"./documents-D4BcPyOF.js";import{a as H,o as U}from"./use-tours-BEdbVcQS.js";import{i as fe,n as W,o as pe,r as me,t as he}from"./render-chat-markdown-nZGk_TRQ.js";import{a as ge,i as _e,n as G,o as ve,r as ye,s as be}from"./WorkspacePage-Dv3ED-Bt.js";function xe(e,t){return o(`div`,e,[o(`table`,{class:`q-table`},t)])}var K={list:le,table:L},q=[`list`,`table`,`__qtable`],Se=j({name:`QVirtualScroll`,props:{...z,type:{type:String,default:`list`,validator:e=>q.includes(e)},items:{type:Array,default:()=>[]},itemsFn:Function,itemsSize:Number,scrollTarget:re},setup(t,{slots:n,attrs:r}){let i,a=e(null),s=y(()=>t.itemsSize>=0&&t.itemsFn!==void 0?Number.parseInt(t.itemsSize,10):Array.isArray(t.items)?t.items.length:0),{virtualScrollSliceRange:l,localResetVirtualScroll:d,padVirtualScroll:p,onVirtualScrollEvt:m}=R({virtualScrollLength:s,getVirtualScrollTarget:S,getVirtualScrollEl:x}),h=y(()=>{if(s.value===0)return[];let e=(e,t)=>({index:l.value.from+t,item:e});return t.itemsFn===void 0?t.items.slice(l.value.from,l.value.to).map(e):t.itemsFn(l.value.from,l.value.to-l.value.from).map(e)}),g=y(()=>`q-virtual-scroll q-virtual-scroll`+(t.virtualScrollHorizontal?`--horizontal`:`--vertical`)+(t.scrollTarget===void 0?` scroll`:``)),b=y(()=>t.scrollTarget===void 0?{tabindex:0}:{});c(s,()=>{d()}),c(()=>t.scrollTarget,()=>{w(),C()});function x(){let e=a.value;return e===null?null:e.$el||e}function S(){return i}function C(){let e=x();e!==null&&(i=P(e,t.scrollTarget),i.addEventListener(`scroll`,m,E.passive))}function w(){i!==void 0&&(i.removeEventListener(`scroll`,m,E.passive),i=void 0)}function T(){let e=p(t.type===`list`?`div`:`tbody`,h.value.map(n.default));return n.before!==void 0&&(e=n.before().concat(e)),D(n.after,e)}return d(),f(()=>{C()}),v(()=>{C()}),u(()=>{w()}),_(()=>{w()}),()=>{if(n.default===void 0){console.error(`QVirtualScroll: default scoped slot is required for rendering`);return}return t.type===`__qtable`?xe({ref:a,class:`q-table__middle `+g.value,tabindex:0},T()):o(K[t.type],{...r,ref:a,class:[r.class,g.value],...b.value},T)}}}),Ce=new Set([`setup`,`cleanup`,`archive`]);function we(e){switch(e.type){case`user`:return e.sender===`system-prompt`?`system-prompt`:Ce.has(e.sender)||N(e.sender)?`script`:`user`;case`session`:return`session`;default:return`agent`}}function Te(e){let t=[],n=null,r=null;for(let i of e){let e=we(i),a=e===`session`||e===`system-prompt`,o=e===`script`&&i.type===`user`?`script:${i.sender}`:e;!n||r!==o||a?(n={speaker:e,ts:i.ts,items:[i]},r=o,t.push(n),a&&(n=null)):n.items.push(i)}return t}function Ee(e){switch(e.type){case`text`:return`text:${e.messageId}`;case`thinking`:return`thinking:${e.messageId}:${e.eventIds?.[0]??e.ts??``}`;case`tool`:return`tool:${e.toolCallId}`;case`session`:return`session:${e.kind}:${e.eventIds?.[0]??e.ts??``}`;case`user`:return`user:${e.eventIds?.[0]??`${e.sender}:${e.ts??``}`}`;case`error`:return`error:${e.eventIds?.[0]??`${e.category}:${e.ts??``}`}`}}function De(e){let t=e.items[0];return`${e.speaker}:${t?Ee(t):`empty`}`}function Oe(e,t){let n=Math.min(t,e.length)-1;for(let t=n;t>=0;t--)if(e[t]?.speaker===`user`)return t;return-1}function ke(e,t,n){return new Promise(r=>{let i=!1,a=null,o=null,s=e=>{i||(i=!0,a!==null&&clearTimeout(a),a=null,o?.(),r(e))};if(o=c(e,e=>{t(e)&&s(!0)},{immediate:!0}),i){o();return}a=setTimeout(()=>s(!1),n)})}var Ae={class:`agent-error-item`},je={class:`agent-error-item__body`},Me={class:`agent-error-item__title`},Ne={class:`agent-error-item__message`},J=H(w({__name:`AgentErrorItem`,props:{item:{}},setup(e){let t=e,{te:n}=I(),r=y(()=>{let e=`agent.error.${t.item.category}`;return n(e)?e:`agent.error.other`});return(t,n)=>(l(),b(`div`,Ae,[p(k,{name:`error_outline`,size:`16px`,class:`agent-error-item__icon`}),C(`div`,je,[C(`div`,Me,i(t.$t(r.value)),1),C(`div`,Ne,i(e.item.message),1)])]))}}),[[`__scopeId`,`data-v-e98c3c02`]]),Pe={class:`text-caption text-kobo-3`},Y=w({__name:`SessionEventItem`,props:{item:{}},setup(e){let t=e,n=y(()=>{switch(t.item.kind){case`started`:return`session.started`;case`ended`:return be(t.item.detail);case`compacted`:return`session.compacted`;default:return`session.started`}});return(e,t)=>(l(),b(`span`,Pe,i(e.$t(n.value)),1))}});function Fe(e,t){if(t.length===0||e.length===0)return e;let n=[...t].sort((e,t)=>t.length-e.length),r=new DOMParser().parseFromString(`<div>${e}</div>`,`text/html`),i=r.body.firstChild;if(!i)return e;function a(e){if(e.nodeType===Node.TEXT_NODE){X(e,n,r);return}if(e.nodeName===`A`)return;let t=Array.from(e.childNodes);for(let e of t)a(e)}return a(i),i.innerHTML}function X(e,t,n){let r=e.textContent??``;if(!t.some(e=>r.includes(e)))return;let i=n.createDocumentFragment(),a=0;for(;a<r.length;){let e=Z(r,a,t);if(!e){i.appendChild(n.createTextNode(r.slice(a)));break}e.index>a&&i.appendChild(n.createTextNode(r.slice(a,e.index)));let o=n.createElement(`a`);o.className=`document-link`,o.setAttribute(`data-document-path`,e.path),o.setAttribute(`href`,`#`),o.textContent=e.path,i.appendChild(o),a=e.index+e.path.length}e.parentNode?.replaceChild(i,e)}function Z(e,t,n){let r=null;for(let i of n){let n=e.indexOf(i,t);n<0||(!r||n<r.index||n===r.index&&i.length>r.path.length)&&(r={index:n,path:i})}return r}var Ie=[`innerHTML`],Le=H(w({__name:`TextMessageItem`,props:{item:{}},setup(e){let t=e,n=V(),r=oe(),i=te(),{t:a}=I(),o=y(()=>{let e=r.selectedWorkspaceId;return e?n.documentsFor(e).map(e=>e.path):[]}),s=y(()=>{let e=t.item;if(e.streaming)return he(e.text);let n=o.value;return me(`${e.messageId}|${n.join(`,`)}`,e.text,e=>{let t=Fe(pe.parse(e,{async:!1,breaks:!0,gfm:!0}),n);return fe(t,{addAttr:[`data-document-path`]})})});function c(e){let t=e.target?.closest(`.document-link`);if(!t)return;e.preventDefault();let o=t.getAttribute(`data-document-path`),s=r.selectedWorkspaceId;o&&s&&n.openDocumentByPath(s,o).catch(e=>{console.error(`[TextMessageItem] openDocumentByPath failed:`,e),i.notify({type:`negative`,message:a(`documents.loadFailed`),position:`top`})})}return(t,n)=>(l(),b(`div`,{class:`markdown-message`,onClick:c},[C(`div`,{innerHTML:s.value},null,8,Ie),e.item.streaming?(l(),m(M,{key:0,size:`xs`,class:`q-ml-xs`})):h(``,!0)]))}}),[[`__scopeId`,`data-v-99371035`]]);function Q(e,t){let n=e.split(`
2
+ `),r=t.split(`
3
+ `),i=0;for(;i<n.length&&i<r.length&&n[i]===r[i];)i++;let a=n.length,o=r.length;for(;a>i&&o>i&&n[a-1]===r[o-1];)a--,o--;let s=n.slice(0,i).map(e=>({type:`context`,content:e})),c=n.slice(a).map(e=>({type:`context`,content:e})),l=n.slice(i,a),u=r.slice(i,o);return l.length>800||u.length>800?[...s,...l.map(e=>({type:`del`,content:e})),...u.map(e=>({type:`add`,content:e})),...c]:[...s,...Re(l,u),...c]}function Re(e,t){let n=e.length,r=t.length;if(n===0&&r===0)return[];if(n===0)return t.map(e=>({type:`add`,content:e}));if(r===0)return e.map(e=>({type:`del`,content:e}));let i=r+1,a=new Int32Array((n+1)*i);for(let o=n-1;o>=0;o--)for(let n=r-1;n>=0;n--)a[o*i+n]=e[o]===t[n]?a[(o+1)*i+(n+1)]+1:Math.max(a[(o+1)*i+n],a[o*i+(n+1)]);let o=[],s=0,c=0;for(;s<n&&c<r;)e[s]===t[c]?(o.push({type:`context`,content:e[s]}),s++,c++):a[(s+1)*i+c]>=a[s*i+(c+1)]?(o.push({type:`del`,content:e[s]}),s++):(o.push({type:`add`,content:t[c]}),c++);for(;s<n;)o.push({type:`del`,content:e[s++]});for(;c<r;)o.push({type:`add`,content:t[c++]});return o}function ze(e){let t=e.split(`
4
+ `),n=[],r=!1;for(let e of t){if(e.startsWith(`@@`)){r=!0;continue}(r||!e.startsWith(`+++`)&&!e.startsWith(`---`))&&(e.startsWith(`+`)?n.push({type:`add`,content:e.slice(1)}):e.startsWith(`-`)?n.push({type:`del`,content:e.slice(1)}):e.startsWith(` `)?n.push({type:`context`,content:e.slice(1)}):e.length>0&&n.push({type:`context`,content:e}))}return n}function Be(e,t){if(!t||typeof t!=`object`)return null;let n=t;if(e===`Edit`){let e=n.file_path;if(!e)return null;let t=n.old_string??``,r=n.new_string??``,i=typeof n.diff==`string`?n.diff:``;if(!t&&!r&&i.length>0){let t=ze(i);return{toolName:`Edit`,filePath:e,additions:t.filter(e=>e.type===`add`).length,deletions:t.filter(e=>e.type===`del`).length,diffLines:t}}return{toolName:`Edit`,filePath:e,oldString:t,newString:r,replaceAll:n.replace_all??!1,additions:r?r.split(`
5
+ `).length:0,deletions:t?t.split(`
6
+ `).length:0}}if(e===`Write`){let e=n.file_path;if(!e)return null;let t=n.content??``;return{toolName:`Write`,filePath:e,content:t,additions:t?t.split(`
7
+ `).length:0,deletions:0}}if(e===`Bash`){let e=(n.command??``).match(/^\s*rm\s+(?:-[a-zA-Z]*\s+)*(.+)/);if(e)return{toolName:`Bash:rm`,filePath:e[1].trim().replace(/["']/g,``),additions:0,deletions:1}}return null}function $(e,t){if(!e||!t?.projectPath)return e;let n=t.worktreePath;if(n){let t=Ve(e,n);if(t!==e)return t}let r=Ve(e,`${t.projectPath}/${F}/${t.workingBranch}`);return r===e?Ve(e,t.projectPath):r}function Ve(e,t){if(!t)return e;let n=He(t);return n?e.replace(RegExp(`${n}[\\\\/]+`,`g`),``).replace(RegExp(`${n}(?=\\s|$|["'\`])`,`g`),`.`):e}function He(e){let t=e.replace(/[\\/]+$/,``);return t?`${/^[\\/]+/.test(t)?`[\\\\/]+`:``}${t.split(/[\\/]+/).filter(Boolean).map(Ue).join(`[\\\\/]+`)}`:``}function Ue(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}var We={class:`tool-name`},Ge=[`title`],Ke={key:0,class:`tool-stat-add`},qe={key:1,class:`tool-stat-del`},Je={class:`diff-sign`},Ye={class:`tool-name`},Xe=[`title`],Ze=H(w({__name:`ToolCallItem`,props:{item:{}},setup(e){let t=e,o=a(!1),s=oe(),{t:u}=I(),d=y(()=>Be(t.item.name,t.item.input)),f=y(()=>d.value?$(d.value.filePath,s.selectedWorkspace):``),_={Bash:`terminal`,Read:`description`,Edit:`edit`,Write:`edit_note`,MultiEdit:`edit`,Glob:`folder_open`,Grep:`manage_search`,LS:`list`,Skill:`auto_awesome`,Task:`hub`,Agent:`hub`,TodoWrite:`checklist`,TodoRead:`checklist`,TaskCreate:`add_task`,TaskUpdate:`checklist`,TaskGet:`checklist`,TaskList:`checklist`,ToolSearch:`search`,WebFetch:`public`,WebSearch:`travel_explore`,NotebookRead:`book`,NotebookEdit:`edit_note`,SendMessage:`send`,ExitPlanMode:`check_circle_outline`,KillShell:`stop_circle`,BashOutput:`terminal`},v=y(()=>_[t.item.name]??`build`),w=y(()=>{if(d.value)return``;let e=t.item.input,n=E(e);return n?$(n,s.selectedWorkspace):``});function E(e){if(!e||typeof e!=`object`)return typeof e==`string`?e:``;let t=e;for(let e of[`file_path`,`path`,`command`,`pattern`,`query`,`url`,`skill`,`description`,`subject`,`prompt`]){let n=t[e];if(typeof n==`string`&&n.length>0)return n}for(let e of Object.values(t))if(typeof e==`string`&&e.length>0)return e;return``}let D=y(()=>{let e=d.value;return e?e.diffLines?e.diffLines:e.toolName===`Edit`&&e.oldString!==void 0&&e.newString!==void 0?Q(e.oldString,e.newString):e.toolName===`Write`&&e.content!==void 0?e.content.split(`
8
+ `).map(e=>({type:`add`,content:e})):e.toolName===`Bash:rm`?[{type:`del`,content:`File deleted`}]:null:null}),O=y(()=>{let e=t.item.result;if(!e)return``;if(typeof e.output==`string`)return e.output;try{return JSON.stringify(e.output)}catch{return String(e.output)}}),j=new Set([`Read`]),M=y(()=>!!(t.item.result&&O.value)&&(!j.has(t.item.name)||t.item.result?.isError===!0));function te(){o.value=!o.value}function N(){let e=d.value?.filePath,t=s.selectedWorkspace,n=t?.id,r=e?$(e,t):``;r&&!/^(?:[A-Za-z]:)?[\\/]/.test(r)&&n&&(B(n,r),window.dispatchEvent(new CustomEvent(`kobo:open-diff`,{detail:{workspaceId:n,path:r}})))}return c(()=>t.item.result?.isError===!0,e=>{e&&(o.value=!0)},{immediate:!0}),(t,a)=>d.value?(l(),b(`div`,{key:0,class:r([`tool-row`,{"tool-row-expanded":o.value}])},[C(`div`,{class:`tool-header`,onClick:te},[p(k,{name:v.value,size:`14px`,class:`tool-icon`},null,8,[`name`]),C(`span`,We,i(d.value.toolName===`Bash:rm`?`Bash`:d.value.toolName),1),C(`span`,{class:`tool-path`,title:d.value.filePath},i(f.value),9,Ge),p(ee,{flat:``,dense:``,round:``,size:`xs`,icon:`open_in_new`,class:`tool-open-diff`,onClick:A(N,[`stop`])},{default:x(()=>[p(U,null,{default:x(()=>[g(i(n(u)(`chat.openInGitDiff`)),1)]),_:1})]),_:1}),d.value.additions>0?(l(),b(`span`,Ke,`+`+i(d.value.additions),1)):h(``,!0),d.value.deletions>0?(l(),b(`span`,qe,`-`+i(d.value.deletions),1)):h(``,!0),e.item.result?.isError?(l(),m(k,{key:2,name:`error_outline`,color:`negative`,size:`xs`,class:`q-ml-xs`})):e.item.result?(l(),m(k,{key:3,name:`check`,color:`positive`,size:`xs`,class:`q-ml-xs`})):h(``,!0),p(k,{name:o.value?`expand_less`:`expand_more`,size:`xs`,class:`q-ml-auto text-kobo-3`},null,8,[`name`])]),o.value&&D.value?(l(),b(`div`,{key:0,class:`tool-diff`,onClick:a[0]||=A(()=>{},[`stop`])},[(l(!0),b(S,null,T(D.value,(e,t)=>(l(),b(`div`,{key:t,class:r([`diff-line`,{"diff-del":e.type===`del`,"diff-add":e.type===`add`,"diff-context":e.type===`context`}])},[C(`span`,Je,i(e.type===`del`?`-`:e.type===`add`?`+`:` `),1),g(i(e.content),1)],2))),128))])):h(``,!0)],2)):(l(),b(`div`,{key:1,class:r([`tool-row tool-row-generic`,{"tool-row-expanded":o.value,"tool-row--toggleable":M.value}])},[C(`div`,{class:`tool-header`,onClick:a[1]||=e=>M.value&&te()},[p(k,{name:v.value,size:`14px`,class:`tool-icon`},null,8,[`name`]),C(`span`,Ye,i(e.item.name),1),w.value?(l(),b(`span`,{key:0,class:`tool-arg`,title:E(e.item.input)||w.value},i(w.value),9,Xe)):h(``,!0),e.item.result?.isError?(l(),m(k,{key:1,name:`error_outline`,color:`negative`,size:`xs`,class:`q-ml-auto`})):e.item.result?(l(),m(k,{key:2,name:`check`,color:`positive`,size:`xs`,class:`q-ml-auto`})):h(``,!0),M.value?(l(),m(k,{key:3,name:o.value?`expand_less`:`expand_more`,size:`xs`,class:`q-ml-xs text-kobo-3`},null,8,[`name`])):h(``,!0)]),o.value&&M.value?(l(),b(`div`,{key:0,class:`tool-output`,onClick:a[2]||=A(()=>{},[`stop`])},i(O.value),1)):h(``,!0)],2))}}),[[`__scopeId`,`data-v-2482adfe`]]);function Qe(e,t){return t?e.replace(/\[image:\s+([^\]]+)\]/g,(e,n)=>{let r=String(n).trim();return/^(\.ai\/images\/|images\/)/.test(r)?`![${r}](${`/api/workspaces/${encodeURIComponent(t)}/images/file?path=${encodeURIComponent(r)}`})`:e}):e}var $e=[`innerHTML`],et=[`innerHTML`],tt=[`src`],nt=H(w({__name:`UserMessageItem`,props:{item:{}},setup(e){let t=e,n=oe(),r=y(()=>t.item.sender===`system-prompt`),i=y(()=>{let e=Qe(t.item.content,n.selectedWorkspaceId??``);return W(e)}),o=a(null),s=a(!1);function c(e){let t=e.target;if(t?.tagName!==`IMG`)return;let n=t;n.src&&(o.value=n.src,s.value=!0)}return(e,t)=>(l(),b(S,null,[r.value?(l(),m(ue,{key:0,dense:``,"dense-toggle":``,label:e.$t(`chat.systemPrompt`),"header-class":`text-kobo-2 text-caption`},{default:x(()=>[C(`div`,{class:`q-py-xs markdown-user-prompt`,innerHTML:i.value},null,8,$e)]),_:1},8,[`label`])):(l(),b(`div`,{key:1,class:`markdown-message`,onClick:c},[C(`div`,{innerHTML:i.value},null,8,et)])),p(ie,{modelValue:s.value,"onUpdate:modelValue":t[1]||=e=>s.value=e},{default:x(()=>[o.value?(l(),b(`img`,{key:0,src:o.value,alt:``,class:`image-lightbox-img`,onClick:t[0]||=e=>s.value=!1},null,8,tt)):h(``,!0)]),_:1},8,[`modelValue`])],64))}}),[[`__scopeId`,`data-v-7687eb7e`]]),rt=[`data-event-ids`],it={class:`turn-header`},at={key:0,class:`turn-time`},ot={class:`turn-time turn-time-updated`},st={key:2,class:`turn-actions`},ct={class:`turn-body`},lt={key:0,class:`turn-scroll-top`},ut=H(w({__name:`TurnCard`,props:{turn:{},highlighted:{type:Boolean}},emits:[`scrollTo`],setup(e,{emit:o}){let s=e,c=o,{t:u}=I(),d=a(null);function f(){let e=d.value;if(!e)return;let t=e.closest(`.q-scrollarea`)?.querySelector(`.q-scrollarea__content`);if(!t){e.scrollIntoView({behavior:`smooth`,block:`start`});return}let n=e.getBoundingClientRect().top-t.getBoundingClientRect().top;c(`scrollTo`,Math.max(0,n-8))}let _=y(()=>{switch(s.turn.speaker){case`user`:return{label:u(`chat.you`),accent:`var(--kobo-turn-user)`,badgeClass:`turn-badge-user`};case`agent`:return{label:u(`chat.agent`),accent:`var(--kobo-turn-agent)`,badgeClass:`turn-badge-agent`};case`system-prompt`:return{label:u(`chat.systemPrompt`),accent:`var(--kobo-text-3)`,badgeClass:`turn-badge-system`};case`session`:return{label:u(`chat.session`),accent:`var(--kobo-text-3)`,badgeClass:`turn-badge-session`};case`script`:{let e=s.turn.items[0],t=e?.type===`user`?e.sender:``;return{label:N(t)?u(`chat.hookScript`,{event:t.slice(5)}):u(t===`archive`?`chat.archiveScript`:t===`setup`?`chat.setupScript`:`chat.cleanupScript`),accent:`var(--kobo-success)`,badgeClass:`turn-badge-script`}}}});function v(e,t=!1){if(!e)return``;let n=new Date(e);return Number.isNaN(n.getTime())?``:n.toLocaleTimeString(void 0,t?{hour:`2-digit`,minute:`2-digit`,second:`2-digit`}:{hour:`2-digit`,minute:`2-digit`})}let w=y(()=>v(s.turn.ts)),E=y(()=>s.turn.items.flatMap(e=>e.eventIds??[]).join(` `)),D=y(()=>{let e=s.turn.items;if(e.length===0)return null;for(let t=e.length-1;t>=0;t--){let n=e[t].ts;if(n)return n}return null}),O=y(()=>{let e=s.turn.ts,t=D.value;if(!t||!e||t===e)return``;let n=new Date(e).getTime(),r=new Date(t).getTime();return Number.isNaN(n)||Number.isNaN(r)||r<=n?``:v(t,r-n<6e4)}),A=y(()=>O.value!==``),j=y(()=>s.turn.items.filter(e=>e.type===`tool`).length);return(a,o)=>(l(),b(`div`,{ref_key:`cardEl`,ref:d,class:r([`turn-card`,{"turn-card--user":e.turn.speaker===`user`,"turn-card--highlighted":e.highlighted}]),"data-event-ids":E.value,style:t({"--turn-accent":_.value.accent})},[C(`div`,it,[C(`span`,{class:r([`turn-badge`,_.value.badgeClass])},i(_.value.label),3),w.value?(l(),b(`span`,at,i(w.value),1)):h(``,!0),A.value?(l(),b(S,{key:1},[p(k,{name:`arrow_forward`,size:`10px`,color:`kobo-3`,class:`turn-time-arrow`}),C(`span`,ot,[g(i(O.value)+` `,1),p(U,null,{default:x(()=>[g(i(n(u)(`chat.lastUpdatedAt`,{time:O.value})),1)]),_:1})])],64)):h(``,!0),j.value>0?(l(),b(`span`,st,` · `+i(n(u)(`chat.nActions`,{n:j.value})),1)):h(``,!0)]),C(`div`,ct,[(l(!0),b(S,null,T(e.turn.items,e=>(l(),b(S,{key:n(Ee)(e)},[e.type===`text`?(l(),m(Le,{key:0,item:e},null,8,[`item`])):e.type===`thinking`?(l(),m(G,{key:1,item:e},null,8,[`item`])):e.type===`tool`?(l(),m(Ze,{key:2,item:e},null,8,[`item`])):e.type===`user`?(l(),m(nt,{key:3,item:e},null,8,[`item`])):e.type===`session`?(l(),m(Y,{key:4,item:e},null,8,[`item`])):e.type===`error`?(l(),m(J,{key:5,item:e},null,8,[`item`])):h(``,!0)],64))),128))]),e.turn.items.length>4?(l(),b(`div`,lt,[p(ee,{flat:``,round:``,dense:``,size:`xs`,icon:`arrow_upward`,color:`kobo-3`,class:`turn-scroll-top-btn`,onClick:f},{default:x(()=>[p(U,null,{default:x(()=>[g(i(n(u)(`chat.scrollToTurnTop`)),1)]),_:1})]),_:1})])):h(``,!0)],14,rt))}}),[[`__scopeId`,`data-v-6e61835e`]]),dt={key:0,class:`activity-feed-switching`},ft={key:1,class:`activity-feed-wrap`,"data-tour":`ws-chat`},pt=[`aria-label`],mt={key:0,class:`activity-feed-compacting`},ht={class:`text-caption text-kobo-2`},gt={key:0,class:`text-center q-py-sm text-caption text-kobo-3`},_t={key:1,class:`activity-feed-empty q-pa-md`},vt={class:`activity-feed-empty__title`},yt={class:`activity-feed-empty__hint`},bt={key:2,class:`q-px-md q-pb-md`},xt={class:`activity-feed-nav-cluster`},St=300,Ct=60,wt=200,Tt=200,Et=400,Dt=200,Ot=180,kt=1200,At=H(w({__name:`ActivityFeed`,props:{workspaceId:{}},setup(e){let{t}=I(),r=e,o=ne(),u=se(),_=oe(),v=y(()=>o.isCompacting(r.workspaceId)),w=y(()=>_.selectedSessionId),E=y(()=>_.sessions.find(e=>e.id===w.value)?.engineSessionId??null),D=y(()=>{let e=_.sessions;return e.length!==0&&w.value===e[e.length-1].id});function A(e){return w.value?e?e===w.value||e===E.value:D.value:!0}let j=y(()=>(_.activityFeeds[r.workspaceId]??[]).filter(e=>e.type===`text`&&typeof e.content==`string`&&A(e.sessionId)).map(e=>({content:e.content,sender:e.meta?.sender??`user`,ts:e.timestamp,sessionId:e.sessionId,eventIds:[e.id]}))),te=y(()=>{let e=_.workspaces.find(e=>e.id===r.workspaceId);return ae(e?.status)}),N=ye(),re=``,P=y(()=>{let e=o.eventsFor(r.workspaceId),t=o.timestampsFor(r.workspaceId),n=o.sessionIdsFor(r.workspaceId),i=o.eventIdsFor(r.workspaceId),a=[],s=[],c=[];for(let r=0;r<e.length;r++)A(n[r])&&(a.push(e[r]),s.push(t[r]),c.push(i[r]??null));let l=`${r.workspaceId}::${w.value??`*`}`;l!==re&&(N=ye(),re=l);let d=_e(N,a,s,te.value,c);return Te(ve(d,j.value).filter(e=>e.type===`thinking`?!1:e.type===`session`?e.kind===`ended`?u.showVerboseSystemMessages||!ge(e.detail):u.showVerboseSystemMessages:!0))}),F=y(()=>u.showVerboseSystemMessages?o.eventsFor(r.workspaceId).filter(e=>e.kind===`message:raw`).map(e=>e.content):[]),ie=y(()=>{for(let e=P.value.length-1;e>=0;e--){let n=P.value[e]?.items??[];for(let e=n.length-1;e>=0;e--){let r=n[e];if(r){if(r.type===`text`&&!r.streaming)return{key:`text:${r.messageId}`,text:r.text};if(r.type===`tool`)return r.result?{key:`tool:${r.toolCallId}:end`,text:r.result.isError?t(`activity.a11y.toolFailed`,{name:r.name}):t(`activity.a11y.toolFinished`,{name:r.name})}:{key:`tool:${r.toolCallId}:start`,text:t(`activity.a11y.toolStarted`,{name:r.name})}}}}return null}),le=a(``);c(ie,(e,n)=>{if(!e||e.key===n?.key)return;let r=e.key.startsWith(`text:`)?t(`activity.a11y.agentSaid`,{text:e.text.slice(0,St)}):e.text;le.value=r});let L=a(null),R=a(!0),z=a(!1),B=a(null),V=!1,H=a(!0),U=a(new Map);function fe(e){let t=e.verticalSize-e.verticalPosition-e.verticalContainerSize;R.value=t<=Ct,V&&e.verticalPosition<=wt&&!z.value&&pe()&&be()}function W(e,t){return`${e}:${t}`}function pe(){let e=w.value;return e?U.value.get(W(r.workspaceId,e))??!0:o.hasMoreOlderFor(r.workspaceId)}function me(e,t,n){U.value.set(W(e,t),n)}function he(e){if(!w.value)return o.oldestIdFor(e);let t=o.eventIdsFor(e),n=o.sessionIdsFor(e);for(let e=0;e<t.length;e++){if(!A(n[e]))continue;let r=t[e];if(r)return r}}let G=null;function be(){return G||(G=xe().finally(()=>{G=null}),G)}async function xe(){let e=r.workspaceId,t=w.value,n=he(e);if(!n)return;z.value=!0;let i=Date.now();try{let r=L.value;await d();let i=r?.getScroll().verticalSize??0,a=r?.getScroll().verticalPosition??0,s=new URLSearchParams({before:n,limit:`200`});t&&s.set(`session`,t);let c=fetch(`/api/workspaces/${e}/events?${s.toString()}`),l=new Promise(e=>setTimeout(e,Tt)),[u]=await Promise.all([c,l]);if(!u.ok){t?me(e,t,!1):o.prepend(e,[],[],{oldestId:n,hasMoreOlder:!1});return}let f=await u.json(),p=f.events??[],m=p.filter(t=>t.type===`agent:event`&&t.workspaceId===e),h=p.filter(t=>t.type===`user:message`&&t.workspaceId===e),g=m.map(e=>e.payload),v=m.map(e=>e.createdAt),y=m.map(e=>e.sessionId??null),b=m.map(e=>e.id),x=p.length>0?p[0].id:n;t&&me(e,t,f.hasMore),o.prepend(e,g,v,{oldestId:x,hasMoreOlder:t?o.hasMoreOlderFor(e):f.hasMore,sessionIds:y,eventIds:b});for(let t of h){let n=t.payload;typeof n.content==`string`&&_.addActivityItem(e,{id:t.id,type:`text`,content:n.content,timestamp:t.createdAt,sessionId:t.sessionId??void 0,meta:{sender:n.sender??`user`}})}if(await d(),r){let e=r.getScroll().verticalSize-i;if(e>0){let t=Math.max(a+e,250);r.setScrollPosition(`vertical`,t,0)}}}catch(e){console.error(`[ActivityFeed] failed to load older events:`,e)}finally{let e=Date.now()-i,t=Math.max(0,Tt-e);await new Promise(e=>setTimeout(e,t+Et)),z.value=!1}}async function K(e=0){await d();let t=L.value;if(!t)return;let n=t.getScroll();t.setScrollPosition(`vertical`,n.verticalSize,e)}let q=null,Ce=0;function we(){if(q!=null)return;let e=performance.now()-Ce<Ot;q=requestAnimationFrame(()=>{q=null,Ce=performance.now(),K(e?0:180)})}function Ee(e){let t=L.value;t&&t.setScrollPosition(`vertical`,Math.max(0,e),250)}function Ae(){let e=window.location.hash,t=e.indexOf(`?`);if(t===-1||!new URLSearchParams(e.slice(t+1)).has(`eventId`))return;let n=e.slice(0,t);window.history.replaceState(window.history.state,``,`${window.location.pathname}${window.location.search}${n}`)}async function je(e){let t=e.detail;if(t?.workspaceId===r.workspaceId&&t.eventId)try{let e=new URLSearchParams({around:t.eventId,limit:`200`});t.sessionId&&e.set(`session`,t.sessionId);let n=await fetch(`/api/workspaces/${r.workspaceId}/events?${e}`);if(!n.ok)return;let i=await n.json(),a=i.events??[],s=a.filter(e=>e.type===`agent:event`&&e.workspaceId===r.workspaceId),c=a.filter(e=>e.type===`user:message`&&e.workspaceId===r.workspaceId);o.reset(r.workspaceId,s.map(e=>e.payload),s.map(e=>e.createdAt),{oldestId:a[0]?.id,hasMoreOlder:i.hasMore??!1,sessionIds:s.map(e=>e.sessionId),eventIds:s.map(e=>e.id)});for(let e of c){let t=e.payload;typeof t.content==`string`&&_.addActivityItem(r.workspaceId,{id:e.id,type:`text`,content:t.content,timestamp:e.createdAt,sessionId:e.sessionId??void 0,meta:{sender:t.sender??`user`}})}await ke(H,e=>!e,5e3),await d(),await new Promise(e=>requestAnimationFrame(()=>requestAnimationFrame(()=>e())));let l=P.value.findIndex(e=>e.items.some(e=>e.eventIds?.includes(t.eventId)??!1));if(l<0)return;B.value=t.eventId,Me.value?.scrollTo(l,`center`),J.value=l,window.setTimeout(()=>{B.value===t.eventId&&(B.value=null)},1800)}catch(e){console.error(`[ActivityFeed] failed to focus history event:`,e)}}let Me=a(null),Ne=a(null),J=a(0);function Pe(e){J.value=e.index}let Y=a(!1);async function Fe(){if(Y.value)return;Y.value=!0;let e=r.workspaceId;try{let t=Oe(P.value,J.value);if(t<0)for(let n=0;n<15;n++){if(e!==r.workspaceId)return;if(!pe())break;let n=P.value.length;if(await be(),await d(),e!==r.workspaceId)return;if(J.value+=P.value.length-n,t=Oe(P.value,J.value),t>=0)break}t>=0&&e===r.workspaceId&&(Me.value?.scrollTo(t,`start`),J.value=t)}finally{Y.value=!1}}async function X(){V=!1,await d(),await K(0),await new Promise(e=>requestAnimationFrame(()=>requestAnimationFrame(()=>e()))),await K(0),V=!0}let Z=y(()=>{let e=o.sessionIdsFor(r.workspaceId);if(!w.value)return e.length;let t=0;for(let n of e)A(n)&&t++;return t}),Ie=y(()=>o.eventsFor(r.workspaceId).length);async function Le(){H.value=!0;let e=Date.now();await new Promise(e=>setTimeout(e,Dt));let t=Math.max(0,e+kt-Date.now());await ke(Ie,e=>e>0,t),H.value=!1}c(H,async e=>{!e&&Z.value>0&&await X(),!e&&Z.value===0&&w.value&&ze(),e||d(()=>{Ne.value=L.value?.getScrollTarget()??null})}),f(()=>{window.addEventListener(`kobo:focus-history-event`,je),d(()=>{Ne.value=L.value?.getScrollTarget()??null}),Le(),Z.value>0&&X(),w.value&&ze();let e=new URLSearchParams(window.location.hash.split(`?`)[1]??``).get(`eventId`);e&&(je(new CustomEvent(`kobo:focus-history-event`,{detail:{workspaceId:r.workspaceId,sessionId:w.value,eventId:e}})),Ae())});let Q=Z.value>0;c(Z,async(e,t)=>{if(!z.value){if(!Q&&e>0){Q=!0,await X();return}e>t&&R.value&&!z.value&&we()}}),s(()=>{window.removeEventListener(`kobo:focus-history-event`,je),q!=null&&(cancelAnimationFrame(q),q=null)}),c(()=>r.workspaceId,()=>{R.value=!0,Q=Z.value>0,V=!1,Le(),Z.value>0&&X()}),c(()=>_.selectedSessionId,async()=>{R.value=!0,V=!1,await X(),ze()});let Re=new Set;async function ze(){let e=w.value;if(!e||Z.value>0)return;let t=W(r.workspaceId,e);if(!Re.has(t)){Re.add(t);try{let t=await fetch(`/api/workspaces/${r.workspaceId}/events?session=${encodeURIComponent(e)}&limit=500`);if(!t.ok)return;let n=await t.json(),i=n.events??[];if(i.length===0)return;let a=i.filter(e=>e.type===`agent:event`&&e.workspaceId===r.workspaceId),s=i.filter(e=>e.type===`user:message`&&e.workspaceId===r.workspaceId),c=a.map(e=>e.payload),l=a.map(e=>e.createdAt),u=a.map(e=>e.sessionId??null),f=a.map(e=>e.id);me(r.workspaceId,e,n.hasMore),c.length>0&&o.prepend(r.workspaceId,c,l,{oldestId:i[0].id,hasMoreOlder:o.hasMoreOlderFor(r.workspaceId),sessionIds:u,eventIds:f});for(let e of s){let t=e.payload;typeof t.content==`string`&&_.addActivityItem(r.workspaceId,{id:e.id,type:`text`,content:t.content,timestamp:e.createdAt,sessionId:e.sessionId??void 0,meta:{sender:t.sender??`user`}})}await d(),await K(0)}catch(e){console.error(`[ActivityFeed] fetchSessionIfMissing failed:`,e),Re.delete(t)}}}let Be=y(()=>j.value.filter(e=>e.sender!==`system-prompt`).length);c(Be,async(e,t)=>{e>t&&(R.value=!0,await K(180))});async function $(){R.value=!0,await K(250)}return(e,t)=>H.value?(l(),b(`div`,dt,[p(ce,{size:`40px`,color:`primary`})])):(l(),b(`div`,ft,[C(`div`,{"data-testid":`activity-live-region`,class:`sr-only`,role:`log`,"aria-live":`polite`,"aria-atomic":`true`,"aria-label":e.$t(`activity.a11y.region`)},i(le.value),9,pt),p(O,{name:`fade`},{default:x(()=>[v.value?(l(),b(`div`,mt,[p(ce,{size:`18px`,color:`primary`}),C(`span`,ht,i(e.$t(`activity.compacting`)),1)])):h(``,!0)]),_:1}),p(de,{ref_key:`scrollRef`,ref:L,class:`activity-feed-scroll`,onScroll:fe},{default:x(()=>[z.value?(l(),b(`div`,gt,[p(M,{size:`sm`}),g(` `+i(e.$t(`activity.loading_older`)),1)])):h(``,!0),p(Se,{ref_key:`virtualScrollRef`,ref:Me,class:`q-pa-md`,items:P.value,"scroll-target":Ne.value??void 0,"virtual-scroll-item-size":160,"virtual-scroll-slice-size":20,onVirtualScroll:Pe},{default:x(({item:e,index:t})=>[(l(),m(ut,{key:n(De)(e),turn:e,"data-turn-index":t,highlighted:e.items.some(e=>e.eventIds?.includes(B.value??``)??!1),onScrollTo:Ee},null,8,[`turn`,`data-turn-index`,`highlighted`]))]),_:1},8,[`items`,`scroll-target`]),P.value.length===0&&F.value.length===0&&!z.value?(l(),b(`div`,_t,[p(k,{name:`forum`,size:`28px`}),C(`div`,vt,i(e.$t(`activity.empty`)),1),C(`div`,yt,i(e.$t(`activity.emptyHint`)),1)])):h(``,!0),F.value.length?(l(),b(`div`,bt,[p(ue,{label:e.$t(`activity.raw_lines`,{n:F.value.length}),dense:``},{default:x(()=>[(l(!0),b(S,null,T(F.value,(e,t)=>(l(),b(`div`,{key:t,class:`text-caption text-kobo-3 q-pa-xs`},i(e),1))),128))]),_:1},8,[`label`])])):h(``,!0)]),_:1},512),C(`div`,xt,[R.value?h(``,!0):(l(),m(ee,{key:0,round:``,dense:``,unelevated:``,color:`kobo-surface-2`,"text-color":`kobo-1`,icon:`arrow_downward`,size:`sm`,class:`activity-feed-nav-btn`,title:e.$t(`activity.scroll_to_bottom`),"aria-label":e.$t(`activity.scroll_to_bottom`),onClick:$},null,8,[`title`,`aria-label`])),p(ee,{round:``,dense:``,unelevated:``,color:`kobo-surface-2`,"text-color":`kobo-1`,icon:`arrow_upward`,size:`sm`,class:`activity-feed-nav-btn`,title:e.$t(`activity.prev_user_message`),"aria-label":e.$t(`activity.prev_user_message`),loading:Y.value,disable:Y.value,onClick:Fe},null,8,[`title`,`aria-label`,`loading`,`disable`])])]))}}),[[`__scopeId`,`data-v-01cd9f2a`]]);export{At as default};
@@ -0,0 +1 @@
1
+ .changelog-notes[data-v-6137cb7c]{color:var(--kobo-text-2);font-size:13px;line-height:1.55}.changelog-notes[data-v-6137cb7c] h3{color:var(--kobo-text);margin:.8em 0 .3em;font-size:14px;font-weight:600}.changelog-notes[data-v-6137cb7c] ul{margin:0;padding-left:1.2em}.changelog-notes[data-v-6137cb7c] li{margin:.2em 0}.changelog-notes[data-v-6137cb7c] code{background:#00000040;border-radius:3px;padding:.1em .3em;font-size:12px}.changelog-notes[data-v-6137cb7c] a{color:var(--kobo-text-2)}
@@ -0,0 +1 @@
1
+ import{j as e,ut as t,v as n}from"./reactivity.esm-bundler-DEJj9cFv.js";import{L as r,P as i,_ as a,d as o,f as s,p as c,q as l,r as u,u as d,y as f,z as p}from"./runtime-core.esm-bundler-CS0xkoG_.js";import{t as m}from"./QBtn-DqZryKOh.js";import{en as h,n as g,nn as _}from"./index-DztjpQfb.js";import{a as v,i as y,n as b}from"./use-tours-BEdbVcQS.js";import{n as x}from"./render-chat-markdown-nZGk_TRQ.js";import{t as S}from"./QChip-CJ6WmvGE.js";import{n as C,t as w}from"./TourReplayButton-DU2PItj-.js";import{t as T}from"./DrawerToggleButton-0fKZjElk.js";var E={class:`row items-center q-mb-md`},D={class:`text-h6 q-ml-sm`},O={key:0,class:`text-kobo-3 text-center q-pa-lg`},k={key:1,class:`text-negative text-center q-pa-lg`},A={key:2,class:`text-kobo-3 text-center q-pa-lg`},j={key:3,class:`column q-gutter-md`,"data-tour":`changelog-list`},M={key:0,class:`text-caption text-kobo-3`},N={class:`row items-center q-mb-sm`},P={class:`text-subtitle1 text-kobo-2`,style:{"font-family":`var(--kobo-font-mono, monospace)`}},F=[`innerHTML`],I=v(f({__name:`ChangelogPage`,setup(f){let v=g(),{scheduleAutoRun:I}=b(),L=n([]),R=n(``),z=n(!1),B=n(null);function V(e){return x(e)}async function H(){z.value=!0,B.value=null;try{let e=await fetch(`/api/changelog`);if(!e.ok)throw Error(`HTTP ${e.status}`);let t=await e.json();R.value=t.currentVersion??``,L.value=t.versions??[]}catch(e){B.value=e instanceof Error?e.message:String(e)}finally{z.value=!1}}return i(()=>{H(),I(`changelog`)}),(n,i)=>(r(),o(C,{class:`q-pa-md`,style:{"max-width":`900px`,margin:`0 auto`}},{default:l(()=>[d(`div`,E,[a(T,{class:`q-mr-xs`}),a(m,{flat:``,dense:``,round:``,icon:`arrow_back`,onClick:i[0]||=t=>e(v).back()}),d(`div`,D,t(n.$t(`changelog.title`)),1),a(y),a(m,{flat:``,dense:``,icon:`refresh`,loading:z.value,label:n.$t(`common.refresh`),onClick:H},null,8,[`loading`,`label`]),a(w,{"tour-id":`changelog`,class:`q-ml-xs`})]),z.value&&L.value.length===0?(r(),c(`div`,O,t(n.$t(`common.loading`)),1)):B.value?(r(),c(`div`,k,t(B.value),1)):L.value.length===0?(r(),c(`div`,A,t(n.$t(`changelog.empty`)),1)):(r(),c(`div`,j,[R.value?(r(),c(`div`,M,t(n.$t(`changelog.currentVersion`,{version:R.value})),1)):s(``,!0),(r(!0),c(u,null,p(L.value,e=>(r(),o(h,{key:e.version,dark:``,flat:``,bordered:``},{default:l(()=>[a(_,null,{default:l(()=>[d(`div`,N,[d(`div`,P,` v`+t(e.version),1),e.version===R.value?(r(),o(S,{key:0,dense:``,size:`sm`,color:`primary`,"text-color":`kobo-1`,label:n.$t(`changelog.current`),class:`q-ml-sm`},null,8,[`label`])):s(``,!0)]),d(`div`,{class:`changelog-notes`,innerHTML:V(e.notes)},null,8,F)]),_:2},1024)]),_:2},1024))),128))]))]),_:1}))}}),[[`__scopeId`,`data-v-6137cb7c`]]);export{I as default};
@@ -0,0 +1 @@
1
+ import{V as e,nt as t}from"./QBtn-DqZryKOh.js";import{Ht as n,Ut as r}from"./index-DztjpQfb.js";function i(e){return e===!1?0:e===!0||e===void 0?1:Number.parseInt(e,10)||0}function a(e){let t=e.currentTarget,i=t.__qclosepopup;i!==0&&setTimeout(()=>{let a=r(t);a!==void 0&&n(a,e,i)},0)}function o(t){e(t,13)&&a(t)}var s=t({name:`close-popup`,beforeMount(e,{value:t}){e.__qclosepopup=i(t),e.addEventListener(`click`,a),e.addEventListener(`keyup`,o)},updated(e,{value:t,oldValue:n}){t!==n&&e.__qclosepopup!==void 0&&(e.__qclosepopup=i(t))},beforeUnmount(e){e.__qclosepopup!==void 0&&(e.removeEventListener(`click`,a),e.removeEventListener(`keyup`,o),e.__qclosepopup=void 0)}});export{s as t};
@@ -0,0 +1,2 @@
1
+ import{ot as e,ut as t,v as n}from"./reactivity.esm-bundler-DEJj9cFv.js";import{K as r,L as i,P as ee,_ as a,d as o,f as s,g as te,l as ne,p as c,q as l,r as u,u as d,y as f,z as re}from"./runtime-core.esm-bundler-CS0xkoG_.js";import{t as p}from"./QBtn-DqZryKOh.js";import{n as ie,p as ae,vt as oe}from"./index-DztjpQfb.js";import{t as se}from"./QMarkupTable-MxPL53nz.js";import{a as m,i as h}from"./use-tours-BEdbVcQS.js";var g=[`workspace`,`engine`,`model`,`status`,`branch`,`tasks_done`,`tasks_total`,`commits`,`files_changed`,`insertions`,`deletions`,`agent_messages`,`user_messages`,`injected_prompts`,`questions`,`tool_calls`,`errors`,`input_tokens`,`output_tokens`,`sessions`,`duration_seconds`];function _(e){if(e==null)return``;let t=String(e);return/[",\r\n]/.test(t)?`"${t.replace(/"/g,`""`)}"`:t}function v(e){let t=e.map(e=>{let t=e.gitStats,n=e.activity;return[e.workspace.name,e.workspace.engine,e.workspace.model,e.workspace.status,e.workspace.workingBranch,e.tasks.done,e.tasks.total,t?.commitCount??null,t?.filesChanged??null,t?.insertions??null,t?.deletions??null,n.agentMessages,n.userMessages,n.injectedPrompts,n.questions,n.toolCalls,n.errors,n.inputTokens,n.outputTokens,n.sessions,Math.round(n.durationMs/1e3)].map(_).join(`,`)});return`${[g.join(`,`),...t].join(`\r
2
+ `)}`}var y={key:0,class:`comparison-panel q-pa-md`},b={class:`row items-center q-mb-sm`},x={class:`text-subtitle2`},S={class:`text-caption text-kobo-3 q-mb-sm`},C={class:`text-left`},w={class:`text-left`},T={class:`text-right`},E={class:`text-right`},D={class:`text-right`},O={class:`text-right`},k={class:`text-right`},A={class:`text-right`},j={class:`text-right`},M={class:`text-right`},N={class:`text-right`},P={class:`text-right`},F={class:`text-right`},I={class:`text-caption text-kobo-3 comparison-mono`},L={key:0,class:`text-caption text-kobo-3`},R={class:`text-right comparison-mono`},z={class:`text-right`},B={class:`text-right`},V={class:`text-right`},ce={key:0,class:`comparison-mono`},H={class:`text-kobo-success`},U={class:`text-kobo-danger q-ml-xs`},W={key:1,class:`text-kobo-3`},G={class:`text-right comparison-mono`},le=[`title`],ue={class:`text-right`},de={class:`text-right`},fe={class:`text-right comparison-mono`},pe=[`title`],me={class:`text-right`},he={class:`text-right comparison-mono`},ge={class:`text-right`},_e={key:1,class:`text-caption text-kobo-3`},ve={key:0,class:`text-caption text-kobo-warning q-mt-sm`},K=m(f({__name:`ComparisonPanel`,props:{workspaceId:{}},setup(f){let m=f;function g(e){return e<1e3?String(e):e<1e6?`${(e/1e3).toFixed(+(e<1e4))}k`:`${(e/1e6).toFixed(1)}M`}function _(e){if(e<=0)return`-`;let t=Math.round(e/1e3);if(t<60)return q(`reliability.durationSeconds`,{s:t});let n=Math.floor(t/60);return n<60?q(`reliability.durationMinutes`,{m:n,s:t%60}):q(`reliability.durationHours`,{h:Math.floor(n/60),m:n%60})}let K=ie(),ye=ae(),{t:q}=oe(),J=n([]),Y=n(!1),be={created:`workspaceStatus.created`,extracting:`workspaceStatus.extracting`,brainstorming:`workspaceStatus.brainstorming`,executing:`workspaceStatus.executing`,"awaiting-user":`workspaceStatus.awaitingUser`,completed:`workspaceStatus.completed`,idle:`workspaceStatus.idle`,error:`workspaceStatus.error`,quota:`workspaceStatus.quota`,retrying:`workspaceStatus.retrying`},X=n({});function xe(e){return X.value[e]??e}async function Se(){try{let e=await fetch(`/api/engines`);if(!e.ok)return;let t=await e.json();X.value=Object.fromEntries(t.map(e=>[e.id,e.displayName]))}catch{}}function Z(e){let t=be[e];return t?q(t):e}let Ce=ne(()=>m.workspaceId);function Q(e){return e.workspace.id===Ce.value}function we(e){ye.selectWorkspace(e),K.push({name:`workspace`,params:{id:e}})}function Te(){let e=v(J.value),t=new Blob([e],{type:`text/csv;charset=utf-8`}),n=URL.createObjectURL(t),r=document.createElement(`a`);r.href=n,r.download=`kobo-comparison-${J.value[0]?.workspace.comparisonId??`comparison`}.csv`,r.click(),URL.revokeObjectURL(n)}async function $(){Y.value=!0;try{let e=await fetch(`/api/workspaces/${m.workspaceId}/comparison`);if(!e.ok){J.value=[];return}let t=await e.json();J.value=t.members??[]}catch{J.value=[]}finally{Y.value=!1}}return ee(()=>{Se(),$()}),r(()=>m.workspaceId,$),(n,r)=>J.value.length>0?(i(),c(`div`,y,[d(`div`,b,[d(`div`,x,t(n.$t(`comparison.title`)),1),a(h),a(p,{flat:``,dense:``,round:``,size:`sm`,icon:`download`,title:n.$t(`comparison.exportCsv`),onClick:Te},null,8,[`title`]),a(p,{flat:``,dense:``,round:``,size:`sm`,icon:`refresh`,loading:Y.value,onClick:$},null,8,[`loading`])]),d(`div`,S,t(n.$t(`comparison.hint`)),1),a(se,{flat:``,dense:``,dark:``,class:`comparison-table`},{default:l(()=>[d(`thead`,null,[d(`tr`,null,[d(`th`,C,t(n.$t(`comparison.engine`)),1),d(`th`,w,t(n.$t(`comparison.status`)),1),d(`th`,T,t(n.$t(`comparison.tasks`)),1),d(`th`,E,t(n.$t(`comparison.commits`)),1),d(`th`,D,t(n.$t(`comparison.files`)),1),d(`th`,O,t(n.$t(`comparison.diff`)),1),d(`th`,k,t(n.$t(`comparison.messages`)),1),d(`th`,A,t(n.$t(`comparison.questions`)),1),d(`th`,j,t(n.$t(`comparison.tools`)),1),d(`th`,M,t(n.$t(`comparison.errors`)),1),d(`th`,N,t(n.$t(`comparison.tokens`)),1),d(`th`,P,t(n.$t(`comparison.sessions`)),1),d(`th`,F,t(n.$t(`comparison.duration`)),1),r[0]||=d(`th`,null,null,-1)])]),d(`tbody`,null,[(i(!0),c(u,null,re(J.value,r=>(i(),c(`tr`,{key:r.workspace.id,class:e({"comparison-current":Q(r)})},[d(`td`,null,[d(`div`,null,t(xe(r.workspace.engine)),1),d(`div`,I,t(r.workspace.model),1)]),d(`td`,null,[te(t(Z(r.workspace.status))+` `,1),r.workspace.archivedAt?(i(),c(`span`,L,` · `+t(n.$t(`comparison.archived`)),1)):s(``,!0)]),d(`td`,R,t(r.tasks.done)+`/`+t(r.tasks.total),1),d(`td`,z,t(r.gitStats?.commitCount??`-`),1),d(`td`,B,t(r.gitStats?.filesChanged??`-`),1),d(`td`,V,[r.gitStats?(i(),c(`span`,ce,[d(`span`,H,`+`+t(r.gitStats.insertions),1),d(`span`,U,`-`+t(r.gitStats.deletions),1)])):(i(),c(`span`,W,`-`))]),d(`td`,G,[d(`span`,{title:n.$t(`comparison.messagesTitle`)},t(r.activity.agentMessages)+` / `+t(r.activity.userMessages),9,le)]),d(`td`,ue,t(r.activity.questions),1),d(`td`,de,t(r.activity.toolCalls),1),d(`td`,{class:e([`text-right`,r.activity.errors>0?`text-kobo-danger`:``])},t(r.activity.errors),3),d(`td`,fe,[d(`span`,{title:n.$t(`comparison.tokensTitle`)},t(g(r.activity.inputTokens))+` / `+t(g(r.activity.outputTokens)),9,pe)]),d(`td`,me,t(r.activity.sessions),1),d(`td`,he,t(_(r.activity.durationMs)),1),d(`td`,ge,[Q(r)?(i(),c(`span`,_e,t(n.$t(`comparison.current`)),1)):(i(),o(p,{key:0,flat:``,dense:``,"no-caps":``,size:`sm`,label:n.$t(`comparison.open`),onClick:e=>we(r.workspace.id)},null,8,[`label`,`onClick`]))])],2))),128))])]),_:1}),J.value.length<2?(i(),c(`div`,ve,t(n.$t(`comparison.incomplete`)),1)):s(``,!0)])):s(``,!0)}}),[[`__scopeId`,`data-v-95e8c6b5`]]);export{K as default};