@loicngr/kobo 2.1.28 → 2.1.30

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 (207) hide show
  1. package/AGENTS.md +60 -11
  2. package/CHANGELOG.md +20 -1
  3. package/CONFIGURATION.md +140 -35
  4. package/CONTRIBUTING.md +2 -2
  5. package/DESIGN.md +1 -1
  6. package/README.md +12 -9
  7. package/SECURITY.md +7 -2
  8. package/dist/server/db/memory-schema.js +5 -5
  9. package/dist/server/db/migrations.js +2 -0
  10. package/dist/server/db/mistral-memory-migration.js +40 -0
  11. package/dist/server/routes/engines.js +14 -0
  12. package/dist/server/routes/environment.js +1 -1
  13. package/dist/server/routes/health.js +14 -3
  14. package/dist/server/routes/settings.js +7 -1
  15. package/dist/server/routes/workspaces.js +116 -9
  16. package/dist/server/services/agent/engines/claude-code/capabilities.js +2 -0
  17. package/dist/server/services/agent/engines/claude-code/engine.js +3 -0
  18. package/dist/server/services/agent/engines/claude-code/resolve-binary.js +1 -1
  19. package/dist/server/services/agent/engines/codex/capabilities.js +2 -0
  20. package/dist/server/services/agent/engines/codex/engine.js +3 -0
  21. package/dist/server/services/agent/engines/configuration.js +14 -0
  22. package/dist/server/services/agent/engines/mistral-vibe/capabilities.js +13 -0
  23. package/dist/server/services/agent/engines/mistral-vibe/client.js +64 -0
  24. package/dist/server/services/agent/engines/mistral-vibe/configuration.js +76 -0
  25. package/dist/server/services/agent/engines/mistral-vibe/engine.js +361 -0
  26. package/dist/server/services/agent/engines/mistral-vibe/event-mapper.js +297 -0
  27. package/dist/server/services/agent/engines/mistral-vibe/options-builder.js +35 -0
  28. package/dist/server/services/agent/engines/mistral-vibe/server-requests.js +278 -0
  29. package/dist/server/services/agent/engines/mistral-vibe/spawn.js +176 -0
  30. package/dist/server/services/agent/engines/registry.js +2 -0
  31. package/dist/server/services/agent/engines/types.js +6 -0
  32. package/dist/server/services/agent/orchestrator.js +88 -25
  33. package/dist/server/services/agent/session-controller.js +5 -0
  34. package/dist/server/services/auto-loop-final-review-service.js +10 -3
  35. package/dist/server/services/dev-server-service.js +68 -4
  36. package/dist/server/services/environment-check-service.js +9 -3
  37. package/dist/server/services/memory-service.js +1 -1
  38. package/dist/server/services/mistral-options-service.js +145 -0
  39. package/dist/server/services/pr-watcher-service.js +40 -11
  40. package/dist/server/services/review-service.js +33 -9
  41. package/dist/server/services/session-handoff-service.js +28 -2
  42. package/dist/server/services/settings-defaults.js +1 -0
  43. package/dist/server/services/settings-service.js +19 -1
  44. package/dist/server/services/workspace-creation-mcp-service.js +50 -8
  45. package/dist/server/services/workspace-dialogue-service.js +2 -0
  46. package/dist/server/services/workspace-message-service.js +19 -1
  47. package/dist/server/services/workspace-permission-policy-service.js +24 -0
  48. package/dist/server/utils/bounded-process.js +1 -1
  49. package/dist/shared/launch-instructions.js +18 -7
  50. package/dist/shared/memory.js +1 -1
  51. package/dist/shared/mistral-models.js +9 -0
  52. package/dist/shared/mistral-options.js +1 -0
  53. package/dist/shared/question-selections.js +16 -0
  54. package/dist/shared/workspace-creation-tools.js +8 -2
  55. package/dist/shared/workspace-dialogue-tools.js +15 -4
  56. package/docs/deployment-vps.md +10 -3
  57. package/docs/getting-started.md +4 -3
  58. package/docs/troubleshooting.md +2 -2
  59. package/package.json +20 -14
  60. package/src/client/dist/pwa/assets/ActivityFeed-C5stmHXP.js +2 -0
  61. package/src/client/dist/pwa/assets/AutoLoopFinalReviewSettings-CIDSX32d.css +1 -0
  62. package/src/client/dist/pwa/assets/AutoLoopFinalReviewSettings-DG32W_0G.js +1 -0
  63. package/src/client/dist/pwa/assets/{ChangelogPage-CAAUEn5X.js → ChangelogPage-_vItY8vA.js} +1 -1
  64. package/src/client/dist/pwa/assets/{ClosePopup-CRV2hxHS.js → ClosePopup-rU8Bm-mC.js} +1 -1
  65. package/src/client/dist/pwa/assets/{ComparisonPanel-BCb7vB5E.js → ComparisonPanel-B3BMzQH0.js} +2 -2
  66. package/src/client/dist/pwa/assets/CreatePage-FlGrfmjX.js +2 -0
  67. package/src/client/dist/pwa/assets/CreatePage-oh8ihVC4.css +1 -0
  68. package/src/client/dist/pwa/assets/{DashboardPage-XE52EABP.js → DashboardPage-lJGwWQYQ.js} +1 -1
  69. package/src/client/dist/pwa/assets/DiffViewer-DIaQH3lA.js +8 -0
  70. package/src/client/dist/pwa/assets/{DocumentsPanel-L4pbQfz1.js → DocumentsPanel-Ct-nm4fX.js} +1 -1
  71. package/src/client/dist/pwa/assets/{DrawerToggleButton-DiOJm5he.js → DrawerToggleButton-M5qv4Io-.js} +1 -1
  72. package/src/client/dist/pwa/assets/GitPanel-BaHCgb3p.js +3 -0
  73. package/src/client/dist/pwa/assets/GitPanel-C8vw2qvW.css +1 -0
  74. package/src/client/dist/pwa/assets/HealthPage-DR3wa6iD.js +1 -0
  75. package/src/client/dist/pwa/assets/HealthPage-Dbn4J_DT.css +1 -0
  76. package/src/client/dist/pwa/assets/{MainLayout-DoAEgANU.css → MainLayout-CHi8qP1D.css} +1 -1
  77. package/src/client/dist/pwa/assets/MainLayout-WJabICsA.js +2 -0
  78. package/src/client/dist/pwa/assets/{MemoryPanel-DtEvh_b7.js → MemoryPanel-CRpWdfc0.js} +1 -1
  79. package/src/client/dist/pwa/assets/MemoryProposalList-DGz3lDbL.js +1 -0
  80. package/src/client/dist/pwa/assets/{QBadge-CW3Lw-kL.js → QBadge-DiwbRpte.js} +1 -1
  81. package/src/client/dist/pwa/assets/{QBanner-BT2ZemYu.js → QBanner-Cw89HSjk.js} +1 -1
  82. package/src/client/dist/pwa/assets/QBtn-kfhHFy7Q.js +1 -0
  83. package/src/client/dist/pwa/assets/{QBtnDropdown-CWPIugs8.js → QBtnDropdown-tt8rUNNR.js} +1 -1
  84. package/src/client/dist/pwa/assets/{QBtnGroup-CnM4vSJA.js → QBtnGroup-Bioxjp9q.js} +1 -1
  85. package/src/client/dist/pwa/assets/{QBtnToggle-DccOOtbh.js → QBtnToggle-Bod-x9im.js} +1 -1
  86. package/src/client/dist/pwa/assets/{QChip-Be16M4Ig.js → QChip-DvhtPv_L.js} +1 -1
  87. package/src/client/dist/pwa/assets/{QExpansionItem-D-EGL2b3.js → QExpansionItem-BkrI3UPL.js} +1 -1
  88. package/src/client/dist/pwa/assets/{QItemSection-MdJ1_ZK7.js → QItemSection-ahqRK4JF.js} +1 -1
  89. package/src/client/dist/pwa/assets/{QList-Cx1UfaUm.js → QList-CAUl0v66.js} +1 -1
  90. package/src/client/dist/pwa/assets/{QMarkupTable-UhP7fVUp.js → QMarkupTable-B4LLAly-.js} +1 -1
  91. package/src/client/dist/pwa/assets/{QPage-CqkGHokx.js → QPage-DIy_mRoT.js} +1 -1
  92. package/src/client/dist/pwa/assets/{QScrollArea-BMrqK-xd.js → QScrollArea-BvgnY-oA.js} +1 -1
  93. package/src/client/dist/pwa/assets/QSelect-BtZB1wrB.js +1 -0
  94. package/src/client/dist/pwa/assets/{QSpinnerDots-xdWyaE1i.js → QSpinnerDots-Bea6hAuJ.js} +1 -1
  95. package/src/client/dist/pwa/assets/{QTooltip-Bk8dLUtU.js → QTooltip-CDH6p745.js} +1 -1
  96. package/src/client/dist/pwa/assets/{SchedulePanel-CuxmxCKi.js → SchedulePanel-C2rWlh7l.js} +1 -1
  97. package/src/client/dist/pwa/assets/{SearchPage-DKnQPUqY.js → SearchPage-BFd4NQwJ.js} +1 -1
  98. package/src/client/dist/pwa/assets/{SettingsPage-B4rmd2WX.css → SettingsPage-Bm0TcarK.css} +1 -1
  99. package/src/client/dist/pwa/assets/SettingsPage-DDQCgnjL.js +9 -0
  100. package/src/client/dist/pwa/assets/{SplitWorkspacePage-WhQyX8fn.js → SplitWorkspacePage-DKCtOZO4.js} +1 -1
  101. package/src/client/dist/pwa/assets/TerminalPanel-BE_MSZF0.js +16 -0
  102. package/src/client/dist/pwa/assets/{ToolCallItem-DYubi-J0.js → ToolCallItem-BEYaOtgh.js} +4 -4
  103. package/src/client/dist/pwa/assets/{TouchPan-DDotyYLN.js → TouchPan-DeYoOjX5.js} +1 -1
  104. package/src/client/dist/pwa/assets/{TourReplayButton-kAnEMcy2.js → TourReplayButton-D5lMwIKt.js} +1 -1
  105. package/src/client/dist/pwa/assets/WorkspaceAttentionLabels-BHEAsIoo.js +1 -0
  106. package/src/client/dist/pwa/assets/WorkspaceAttentionLabels-v7ein__H.css +1 -0
  107. package/src/client/dist/pwa/assets/WorkspacePage-5_wsJPaJ.js +4 -0
  108. package/src/client/dist/pwa/assets/WorkspacePage-CtUXz0Cq.css +1 -0
  109. package/src/client/dist/pwa/assets/{browser-DVYLH8vl.js → browser-ogy_9LVv.js} +2 -2
  110. package/src/client/dist/pwa/assets/build-path-tree-CRXxaYkA.js +1 -0
  111. package/src/client/dist/pwa/assets/custom-sounds-iLTkCd_i.js +1 -0
  112. package/src/client/dist/pwa/assets/de-BqDU7iZH.js +17 -0
  113. package/src/client/dist/pwa/assets/detached-fullscreen-CHqMxB-8.js +1 -0
  114. package/src/client/dist/pwa/assets/dom-CRPVbmiy.js +2 -0
  115. package/src/client/dist/pwa/assets/ecl-94qehhXe.js +1 -0
  116. package/src/client/dist/pwa/assets/{editor.api-BC38eXAS.js → editor.api-Dx6TbfZG.js} +9 -9
  117. package/src/client/dist/pwa/assets/editor.worker-xrHNhPSq.js +33 -0
  118. package/src/client/dist/pwa/assets/efforts-DnJh2fW_.js +9 -0
  119. package/src/client/dist/pwa/assets/es-D4VMXQRk.js +17 -0
  120. package/src/client/dist/pwa/assets/expand-template-PUEVWny3.js +1 -0
  121. package/src/client/dist/pwa/assets/{format-OwxXBnDJ.js → format-yf9XM3dV.js} +48 -48
  122. package/src/client/dist/pwa/assets/{formatters-YgaCZcwJ.js → formatters-D0sXu9Oe.js} +1 -1
  123. package/src/client/dist/pwa/assets/fr-DIyaCFB3.js +17 -0
  124. package/src/client/dist/pwa/assets/{freemarker2-l7R42fI2.js → freemarker2-l_xIHxRf.js} +1 -1
  125. package/src/client/dist/pwa/assets/{handlebars-DFmPrgjH.js → handlebars-CYgq99yQ.js} +1 -1
  126. package/src/client/dist/pwa/assets/{html-CERIAlPM.js → html-C28GatN_.js} +1 -1
  127. package/src/client/dist/pwa/assets/i18n-2AmHIUy0.js +1 -0
  128. package/src/client/dist/pwa/assets/index-C0MApoXN.css +1 -0
  129. package/src/client/dist/pwa/assets/index-MMYMztJ_.js +20 -0
  130. package/src/client/dist/pwa/assets/it-CF6_4OS0.js +17 -0
  131. package/src/client/dist/pwa/assets/{javascript-BBYncplF.js → javascript-YCSueyyk.js} +1 -1
  132. package/src/client/dist/pwa/assets/{liquid-C1HqYyYU.js → liquid-CUBn90Gs.js} +1 -1
  133. package/src/client/dist/pwa/assets/{mdx-E74dsP22.js → mdx-C5WOHShJ.js} +1 -1
  134. package/src/client/dist/pwa/assets/monaco-contributions-DYwqbh7m.js +53 -0
  135. package/src/client/dist/pwa/assets/{monaco.contribution-DYdn9CwR.js → monaco.contribution-CoFzrPQl.js} +2 -2
  136. package/src/client/dist/pwa/assets/network-auth-BpJ6Noax.js +1 -0
  137. package/src/client/dist/pwa/assets/notify-theme-NPq4-Tup.js +1 -0
  138. package/src/client/dist/pwa/assets/permissionModes-Bbl901Hx.js +36 -0
  139. package/src/client/dist/pwa/assets/{private.use-form-DY1BkePL.js → private.use-form-BcspuzM9.js} +1 -1
  140. package/src/client/dist/pwa/assets/{project-color-_snXWYUp.js → project-color-gNyhKJlV.js} +1 -1
  141. package/src/client/dist/pwa/assets/{python-DNAAGBcX.js → python-lhKUZdPj.js} +1 -1
  142. package/src/client/dist/pwa/assets/{razor-CB3g5p_T.js → razor-Chi44rEL.js} +1 -1
  143. package/src/client/dist/pwa/assets/reactivity.esm-bundler-Dplx1ILy.js +1 -0
  144. package/src/client/dist/pwa/assets/render-chat-markdown-C9ihAYBt.js +67 -0
  145. package/src/client/dist/pwa/assets/runtime-core.esm-bundler-BAUgNzMK.js +1 -0
  146. package/src/client/dist/pwa/assets/{typescript-0kpz8bqP.js → typescript-CU2TXVm6.js} +1 -1
  147. package/src/client/dist/pwa/assets/{use-checkbox-v4aAbE6K.js → use-checkbox-DUxgXR4e.js} +1 -1
  148. package/src/client/dist/pwa/assets/{use-id-BrdYXce0.js → use-id-B7ieAx2m.js} +1 -1
  149. package/src/client/dist/pwa/assets/use-is-mobile-CHmaewI1.js +1 -0
  150. package/src/client/dist/pwa/assets/{use-search-index-status-D38yFOD_.js → use-search-index-status-CQ9S05G7.js} +1 -1
  151. package/src/client/dist/pwa/assets/use-slide-transition-BJh9xGMa.js +1 -0
  152. package/src/client/dist/pwa/assets/use-tours-BmrZbHjz.js +2 -0
  153. package/src/client/dist/pwa/assets/use-tours-CU5oA7cz.css +1 -0
  154. package/src/client/dist/pwa/assets/use-worktree-restore-DcucRlLh.js +1 -0
  155. package/src/client/dist/pwa/assets/{workspace-templates-D-lPJQ4G.js → workspace-templates-DaG42EEt.js} +1 -1
  156. package/src/client/dist/pwa/assets/{xml-BbOuqdUe.js → xml-CPO5LI6F.js} +1 -1
  157. package/src/client/dist/pwa/assets/{yaml-gasFQtfk.js → yaml-CoYs82jI.js} +1 -1
  158. package/src/client/dist/pwa/index.html +10 -10
  159. package/src/client/dist/pwa/sw.js +1 -1
  160. package/src/mcp-server/README.md +18 -6
  161. package/src/client/dist/pwa/assets/ActivityFeed-D58VS9o2.js +0 -2
  162. package/src/client/dist/pwa/assets/AutoLoopFinalReviewSettings-CK3r_fVB.js +0 -1
  163. package/src/client/dist/pwa/assets/AutoLoopFinalReviewSettings-Q-OlSQ1c.css +0 -1
  164. package/src/client/dist/pwa/assets/CreatePage-DasH1Uk4.js +0 -2
  165. package/src/client/dist/pwa/assets/CreatePage-DxOes_cF.css +0 -1
  166. package/src/client/dist/pwa/assets/DiffViewer-CncKlXne.js +0 -8
  167. package/src/client/dist/pwa/assets/GitPanel-WJlzy2VJ.js +0 -3
  168. package/src/client/dist/pwa/assets/GitPanel-yHvU38dp.css +0 -1
  169. package/src/client/dist/pwa/assets/HealthPage-Cnlhrn--.css +0 -1
  170. package/src/client/dist/pwa/assets/HealthPage-hJY5MurK.js +0 -1
  171. package/src/client/dist/pwa/assets/MainLayout-DgWElK7w.js +0 -2
  172. package/src/client/dist/pwa/assets/MemoryProposalList-kgFCm9zz.js +0 -1
  173. package/src/client/dist/pwa/assets/QBtn-BUSdPaf4.js +0 -1
  174. package/src/client/dist/pwa/assets/QSelect-DFWyDWCE.js +0 -1
  175. package/src/client/dist/pwa/assets/SettingsPage-CO3vIpPd.js +0 -9
  176. package/src/client/dist/pwa/assets/TerminalPanel-BY0lPq6k.js +0 -16
  177. package/src/client/dist/pwa/assets/WorkspaceAttentionLabels-B9LE8HtU.css +0 -1
  178. package/src/client/dist/pwa/assets/WorkspaceAttentionLabels-DiYt3rP3.js +0 -1
  179. package/src/client/dist/pwa/assets/WorkspacePage-BEBwwr81.css +0 -1
  180. package/src/client/dist/pwa/assets/WorkspacePage-K-1ce50d.js +0 -4
  181. package/src/client/dist/pwa/assets/build-path-tree-DEuOdIIk.js +0 -1
  182. package/src/client/dist/pwa/assets/custom-sounds-Ggw6V9iF.js +0 -1
  183. package/src/client/dist/pwa/assets/de-Bk3zQrin.js +0 -17
  184. package/src/client/dist/pwa/assets/detached-fullscreen-Du3TcYdX.js +0 -1
  185. package/src/client/dist/pwa/assets/dom-BtYTvLeN.js +0 -2
  186. package/src/client/dist/pwa/assets/ecl-D05T4iGw.js +0 -1
  187. package/src/client/dist/pwa/assets/editor.worker-BLJF_oQx.js +0 -33
  188. package/src/client/dist/pwa/assets/efforts-TGacUPcJ.js +0 -9
  189. package/src/client/dist/pwa/assets/es-f3xuAWA9.js +0 -17
  190. package/src/client/dist/pwa/assets/expand-template-DM8gq3Mo.js +0 -1
  191. package/src/client/dist/pwa/assets/fr-B6c21SG3.js +0 -17
  192. package/src/client/dist/pwa/assets/i18n-WaE4cZK9.js +0 -1
  193. package/src/client/dist/pwa/assets/index-C8zAZ-k-.css +0 -1
  194. package/src/client/dist/pwa/assets/index-CpWBGKdM.js +0 -20
  195. package/src/client/dist/pwa/assets/it-DUstDpC2.js +0 -17
  196. package/src/client/dist/pwa/assets/monaco-contributions-DHvm-kp5.js +0 -53
  197. package/src/client/dist/pwa/assets/network-auth-DTZUKbny.js +0 -1
  198. package/src/client/dist/pwa/assets/notify-theme-FuTL7HuS.js +0 -1
  199. package/src/client/dist/pwa/assets/permissionModes-D-Nexnoo.js +0 -36
  200. package/src/client/dist/pwa/assets/reactivity.esm-bundler-DY1JkAEA.js +0 -1
  201. package/src/client/dist/pwa/assets/render-chat-markdown-CafzCcmu.js +0 -69
  202. package/src/client/dist/pwa/assets/runtime-core.esm-bundler-Bqg71Vll.js +0 -1
  203. package/src/client/dist/pwa/assets/use-is-mobile-CDB_rzM9.js +0 -1
  204. package/src/client/dist/pwa/assets/use-slide-transition-B_Nu6u-t.js +0 -1
  205. package/src/client/dist/pwa/assets/use-tours-BWkHp34X.js +0 -2
  206. package/src/client/dist/pwa/assets/use-tours-CTZuBZOi.css +0 -1
  207. package/src/client/dist/pwa/assets/use-worktree-restore-DUjZr44N.js +0 -1
@@ -1019,6 +1019,24 @@ const settingsMigrations = [
1019
1019
  global.forceImmediateMessages = false;
1020
1020
  },
1021
1021
  },
1022
+ {
1023
+ version: 68,
1024
+ name: 'mistral-native-defaults',
1025
+ migrate: ({ global }) => {
1026
+ for (const [key, value] of [
1027
+ ['defaultModelByEngine', 'auto'],
1028
+ ['defaultPermissionModeByEngine', 'interactive'],
1029
+ ]) {
1030
+ const map = global[key];
1031
+ // Missing maps inherit the full fresh-install defaults when settings are read.
1032
+ if (map && typeof map === 'object' && !Array.isArray(map)) {
1033
+ const defaults = map;
1034
+ if (typeof defaults['mistral-vibe'] !== 'string')
1035
+ defaults['mistral-vibe'] = value;
1036
+ }
1037
+ }
1038
+ },
1039
+ },
1022
1040
  ];
1023
1041
  /** Current settings schema version — always equals the highest migration version. */
1024
1042
  export const SETTINGS_SCHEMA_VERSION = settingsMigrations.length > 0 ? settingsMigrations[settingsMigrations.length - 1].version : 0;
@@ -1127,7 +1145,7 @@ function defaultSettings() {
1127
1145
  notionInProgressStatus: '',
1128
1146
  notionAssigneeProperty: '',
1129
1147
  notionUserId: '',
1130
- defaultPermissionModeByEngine: { 'claude-code': 'plan', codex: 'plan' },
1148
+ defaultPermissionModeByEngine: { 'claude-code': 'plan', codex: 'plan', 'mistral-vibe': 'interactive' },
1131
1149
  notionMcpKey: '',
1132
1150
  sentryMcpKey: '',
1133
1151
  notionEnabled: false,
@@ -1,8 +1,11 @@
1
1
  import { checkoutDecisionError, deriveSteps } from '../../shared/pr-checkout-steps.js';
2
2
  import { validateWorkspaceCreationArguments } from '../../shared/workspace-creation-tools.js';
3
- import { CLAUDE_CODE_CAPABILITIES } from './agent/engines/claude-code/capabilities.js';
4
- import { CODEX_CAPABILITIES } from './agent/engines/codex/capabilities.js';
3
+ import { assertEngineConfigurationSupported } from './agent/engines/configuration.js';
4
+ import { resolveEngine } from './agent/engines/registry.js';
5
+ import { parseFinalReviewConfiguration } from './auto-loop-final-review-service.js';
6
+ import { preflightMistralConfiguration } from './mistral-options-service.js';
5
7
  import { rollbackCreatedPrCheckout } from './pr-checkout-rollback-service.js';
8
+ import { getGlobalSettings } from './settings-service.js';
6
9
  import { beginWorkspaceCreation } from './update-maintenance-service.js';
7
10
  export class WorkspaceCreationMcpError extends Error {
8
11
  status;
@@ -102,13 +105,52 @@ async function executeCreation(name, raw, dispatch) {
102
105
  catch (error) {
103
106
  throw new WorkspaceCreationMcpError(error instanceof Error ? error.message : 'Invalid arguments', 400, 'validate');
104
107
  }
105
- const config = input.auto_loop_final_review;
106
- if (config) {
107
- const capabilities = config.engine === 'codex' ? CODEX_CAPABILITIES : CLAUDE_CODE_CAPABILITIES;
108
- if (!capabilities.effortLevels?.some((effort) => effort.id === config.reasoning_effort))
109
- throw new WorkspaceCreationMcpError('Unsupported review reasoning effort', 400, 'validate');
110
- }
111
108
  const body = mapInput(input);
109
+ try {
110
+ if (name === 'create_workspace') {
111
+ const engine = resolveEngine(input.engine ?? 'claude-code');
112
+ const savedMode = engine.id === 'mistral-vibe' ? getGlobalSettings().defaultPermissionModeByEngine?.[engine.id] : undefined;
113
+ const defaultMode = savedMode === 'plan' || engine.capabilities.permissionModes.some((mode) => mode === savedMode)
114
+ ? savedMode
115
+ : undefined;
116
+ if (engine.id === 'mistral-vibe')
117
+ body.agentPermissionMode = input.agent_permission_mode ?? defaultMode ?? 'interactive';
118
+ assertEngineConfigurationSupported(engine, {
119
+ model: input.model,
120
+ reasoningEffort: input.reasoning_effort,
121
+ agentPermissionMode: body.agentPermissionMode,
122
+ });
123
+ await preflightMistralConfiguration(engine.id, { projectPath: input.project_path }, {
124
+ model: input.model,
125
+ reasoningEffort: input.reasoning_effort,
126
+ agentPermissionMode: body.agentPermissionMode,
127
+ });
128
+ assertEngineConfigurationSupported(engine, {
129
+ model: input.brainstorm_model,
130
+ reasoningEffort: input.brainstorm_reasoning_effort,
131
+ });
132
+ await preflightMistralConfiguration(engine.id, { projectPath: input.project_path }, {
133
+ model: input.brainstorm_model ?? input.model,
134
+ reasoningEffort: input.brainstorm_reasoning_effort ?? input.reasoning_effort,
135
+ agentPermissionMode: body.agentPermissionMode,
136
+ });
137
+ }
138
+ }
139
+ catch (error) {
140
+ throw new WorkspaceCreationMcpError(error instanceof Error ? error.message : 'Invalid engine configuration', 400, 'validate');
141
+ }
142
+ if (body.autoLoopFinalReview) {
143
+ try {
144
+ const config = parseFinalReviewConfiguration(body.autoLoopFinalReview);
145
+ await preflightMistralConfiguration(config.engine, { projectPath: input.project_path }, {
146
+ ...config,
147
+ agentPermissionMode: 'interactive',
148
+ });
149
+ }
150
+ catch (error) {
151
+ throw new WorkspaceCreationMcpError(error instanceof Error ? error.message : 'Invalid final review configuration', 400, 'validate');
152
+ }
153
+ }
112
154
  let resolvedCheckout;
113
155
  if (input.pr_url) {
114
156
  const supplied = prIdentity(input.pr_url);
@@ -1,4 +1,5 @@
1
1
  import { nanoid } from 'nanoid';
2
+ import { parseQuestionSelections } from '../../shared/question-selections.js';
2
3
  import { validateDialogueArguments } from '../../shared/workspace-dialogue-tools.js';
3
4
  import { parseMessageSource } from '../../shared/workspace-message-types.js';
4
5
  import { getDb } from '../db/index.js';
@@ -79,6 +80,7 @@ export async function executeWorkspaceDialogueTool(name, input, source = createM
79
80
  throw new Error('The requested question is not the current pending question');
80
81
  await answerPendingQuestion(workspaceId, args.answers, args.tool_call_id, {
81
82
  source,
83
+ ...(args.selections !== undefined ? { selections: parseQuestionSelections(args.selections) } : {}),
82
84
  });
83
85
  return { accepted: true };
84
86
  }
@@ -1,10 +1,13 @@
1
1
  import { validateMcpAttachments } from '../../shared/mcp-attachments.js';
2
2
  import { assertWorkspaceLifecycleAvailable, withWorkspaceLifecycleGuard } from '../utils/workspace-lifecycle-guard.js';
3
- import { isAgentUnavailableError, isShuttingDown, sendMessage, startAgent } from './agent/orchestrator.js';
3
+ import { assertEngineConfigurationSupported } from './agent/engines/configuration.js';
4
+ import { resolveEngine } from './agent/engines/registry.js';
5
+ import { assertImmediateMessageSupported, isAgentUnavailableError, isShuttingDown, sendMessage, startAgent, } from './agent/orchestrator.js';
4
6
  import { attachmentReference, removeAttachments, saveAttachments } from './attachment-service.js';
5
7
  import { hasLoopMessage } from './auto-loop-message-service.js';
6
8
  import * as autoLoop from './auto-loop-service.js';
7
9
  import { createChatReceipt } from './chat-receipt-service.js';
10
+ import { preflightMistralConfiguration } from './mistral-options-service.js';
8
11
  import { emitEphemeral } from './websocket-service.js';
9
12
  import { getActiveSession, getWorkspace, updateWorkspaceStatus } from './workspace-service.js';
10
13
  /** Shared delivery for WebSocket chat and external MCP clients. */
@@ -67,6 +70,21 @@ export async function deliverWorkspaceMessage(workspaceId, message, hooks) {
67
70
  reason = 'awaiting-user';
68
71
  throw new Error('Answer the pending question or permission request before sending a chat message');
69
72
  }
73
+ if (workspace.engine === 'mistral-vibe') {
74
+ assertEngineConfigurationSupported(resolveEngine(workspace.engine), {
75
+ model: workspace.model,
76
+ reasoningEffort: workspace.reasoningEffort,
77
+ agentPermissionMode: message.agentPermissionModeOverride ?? workspace.agentPermissionMode,
78
+ });
79
+ }
80
+ assertImmediateMessageSupported(workspaceId);
81
+ if (workspace.engine === 'mistral-vibe') {
82
+ await preflightMistralConfiguration(workspace.engine, { workspaceId }, {
83
+ model: workspace.model,
84
+ reasoningEffort: workspace.reasoningEffort,
85
+ agentPermissionMode: message.agentPermissionModeOverride ?? workspace.agentPermissionMode,
86
+ }, true);
87
+ }
70
88
  if (attachments.length) {
71
89
  attachmentWorktree = workspace.worktreePath;
72
90
  await withWorkspaceLifecycleGuard(workspaceId, async () => {
@@ -1,4 +1,5 @@
1
1
  import { createHash } from 'node:crypto';
2
+ import { isAbsolute } from 'node:path';
2
3
  import { nanoid } from 'nanoid';
3
4
  import { getDb } from '../db/index.js';
4
5
  const turnRules = new Map();
@@ -29,6 +30,26 @@ export function permissionFingerprint(payload) {
29
30
  }
30
31
  const CODEX_EDIT_FINGERPRINT_PREFIX = 'codex-edit-v2:';
31
32
  function operationFingerprint(request) {
33
+ if (request.engine === 'mistral-vibe') {
34
+ const payload = request.payload;
35
+ const input = payload?.rawInput;
36
+ if (!input || typeof input !== 'object' || Array.isArray(input) || payload?.operationApprovalAvailable === false)
37
+ return null;
38
+ const shell = request.toolName === 'bash' &&
39
+ payload?.effectKind === 'shell' &&
40
+ payload.kind === 'execute' &&
41
+ typeof input.command === 'string' &&
42
+ input.command.trim().length > 0;
43
+ const write = request.toolName === 'write_file' &&
44
+ payload?.effectKind === 'file_write' &&
45
+ payload.kind === 'edit' &&
46
+ typeof input.filePath === 'string' &&
47
+ isAbsolute(input.filePath) &&
48
+ typeof input.content === 'string';
49
+ if (!shell && !write)
50
+ return null;
51
+ return `mistral-vibe-operation-v1:${permissionFingerprint({ rawInput: input, effectKind: payload?.effectKind, kind: payload?.kind })}`;
52
+ }
32
53
  if (request.engine !== 'codex' || request.toolName !== 'Edit')
33
54
  return permissionFingerprint(request.payload);
34
55
  const payload = request.payload;
@@ -48,6 +69,9 @@ function operationFingerprint(request) {
48
69
  grantRoot: payload.grantRoot ?? null,
49
70
  }));
50
71
  }
72
+ export function isOperationApprovalAvailable(request) {
73
+ return operationFingerprint(request) !== null;
74
+ }
51
75
  function toRule(row) {
52
76
  return {
53
77
  active: !(row.scope === 'operation' &&
@@ -2,7 +2,7 @@ import { execFile, spawn } from 'node:child_process';
2
2
  import { promisify } from 'node:util';
3
3
  const execFileAsync = promisify(execFile);
4
4
  /** A zombie cannot mutate a checkout, even before its parent reaps it. */
5
- async function groupIsLive(pid) {
5
+ export async function groupIsLive(pid) {
6
6
  try {
7
7
  process.kill(-pid, 0);
8
8
  }
@@ -5,20 +5,29 @@ export function getKoboPromptCapabilities(env) {
5
5
  handoff: Boolean(env?.KOBO_HANDOFF_ID && env.KOBO_HANDOFF_TOKEN),
6
6
  finalReview: Boolean(env?.KOBO_FINAL_REVIEW_SESSION_ID && env.KOBO_FINAL_REVIEW_TOKEN),
7
7
  progressReporting: Boolean(env?.KOBO_PROGRESS_SESSION_TOKEN),
8
+ reviewOnly: env?.KOBO_REVIEW_ONLY === '1',
8
9
  };
9
10
  }
10
11
  export function buildKoboLaunchInstructions(context) {
11
- const restricted = context.readOnly || context.handoff || context.finalReview;
12
+ const restricted = context.readOnly || context.handoff || context.finalReview || context.reviewOnly;
12
13
  const canWrite = context.permissionMode !== 'plan' && !restricted;
13
14
  const lines = [
14
- '[Kōbō MCP] Start by consulting the descriptions and schemas of the available tools from the managed `kobo-tasks` server. Prefer relevant Kōbō tools for operations managed by Kōbō (tasks, development services, shared memory, workspace messages and state) over reimplementing them through shell commands or HTTP. Check each tool result before treating an operation as completed. Discover tools as needed; do not call every tool or poll for activity. Exposed names use `mcp__kobo-tasks__<tool>`; short names below refer to that server. Availability does not grant permission.',
15
+ '[Kōbō MCP] Start by consulting the descriptions and schemas of the available tools from the managed `kobo-tasks` server. Prefer relevant Kōbō tools for operations managed by Kōbō (tasks, development services, shared memory, workspace messages and state) over reimplementing them through shell commands or HTTP. Check each tool result before treating an operation as completed. Discover tools as needed; do not call every tool or poll for activity. ' +
16
+ (context.engine === 'mistral-vibe'
17
+ ? 'Discover schemas with `search_tool_functions`, then call `tools.mcp_kobo_tasks.<tool>` through `run_typescript`; short names below refer to that server. '
18
+ : 'Exposed names use `mcp__kobo-tasks__<tool>`; short names below refer to that server. ') +
19
+ 'Availability does not grant permission.',
15
20
  '## Current permissions',
16
21
  canWrite
17
22
  ? `Permission mode: ${context.permissionMode}. Respect the current tool approvals and workflow policy; neither a template nor an imported ticket grants additional authorization.`
18
- : 'Read-only launch. Do not write files or mutate tasks, workspace state, memory, or other MCP data. Approving a plan does not change these permissions; continue only after Kōbō explicitly changes the launch permissions. Provide analysis and plans in the conversation.',
23
+ : context.engine === 'mistral-vibe' && restricted
24
+ ? `Report-only review under native ${context.permissionMode} permissions, without guaranteed filesystem read-only enforcement. Do not modify, create or delete files, commit, push, or mutate tasks, workspace state, memory or other MCP data. Kōbō tools permit only reads and explicitly scoped reports. Review instructions forbid all modifications even when native permissions allow them. Provide findings and recommended fixes only.`
25
+ : 'Read-only launch. Do not write files or mutate tasks, workspace state, memory, or other MCP data. Approving a plan does not change these permissions; continue only after Kōbō explicitly changes the launch permissions. Provide analysis and plans in the conversation.',
19
26
  ];
20
27
  if (restricted) {
21
- lines.push('Do not ask the user or wait for input. Report missing information and blockers in your final response, then finish so Kōbō can return to the source session.');
28
+ lines.push(context.engine === 'mistral-vibe'
29
+ ? 'Respect native approval requests and wait for user approval when required; never bypass or auto-approve them. Report missing information and blockers in your final response, then finish.'
30
+ : 'Do not ask the user or wait for input. Report missing information and blockers in your final response, then finish so Kōbō can return to the source session.');
22
31
  if (context.handoff)
23
32
  lines.push('Submit the handoff report with the available `submit_session_handoff` tool according to its schema, then finish.');
24
33
  else if (context.finalReview)
@@ -36,7 +45,7 @@ export function buildKoboLaunchInstructions(context) {
36
45
  }
37
46
  lines.push('## Development services', 'Kōbō manages the workspace dev server and its Docker services. Before tests or app checks that need those services (backend, frontend, integration or E2E), use `get_dev_server_status` and reuse the existing instance. Missing host dependencies are not a reason to launch another stack. Use the returned URL and container names, not guessed ports or names.', 'Read the project Makefile, scripts and relevant documentation to select the intended test command and runtime. Distinguish the Kōbō agent environment from the project service containers: if tests belong in a project container, run them there under current permissions. A PHP extension or other dependency missing in the agent environment alone is not evidence that the project is misconfigured, nor a reason to install global packages.', canWrite
38
47
  ? 'When an authorized task needs these services and their status is stopped, use `start_dev_server`. For an explicitly requested stop or a necessary authorized restart, use `stop_dev_server`. Do not run lifecycle commands such as `make dev-docker`, `sh/dev-docker.sh`, `docker compose up/down` or `npm run dev` directly; Kōbō runs the configured commands and tracks their processes.'
39
- : 'This read-only launch must not start, stop or restart services. Inspect available status/logs and report any unavailable test environment in the final response.', 'Use `get_dev_server_logs` to diagnose startup/runtime failures. If the tools are unavailable, the server is not_configured, or startup fails, report the blocker; do not bypass Kōbō with a shell launch. Test commands inside an existing container remain subject to the current permissions.', 'A running process or container is not proof that the service is ready or that tests passed. Before dependent tests, use the documented health check or a non-mutating request to the appropriate service URL. Bound readiness checks with a timeout and limited retries; if readiness remains unconfirmed, inspect logs and report the blocker rather than restarting repeatedly. Missing application readiness does not invalidate independent unit tests.');
48
+ : 'This restricted launch must not start, stop or restart services. Inspect available status/logs and report any unavailable test environment in the final response.', 'Use `get_dev_server_logs` to diagnose startup/runtime failures. If the tools are unavailable, the server is not_configured, or startup fails, report the blocker; do not bypass Kōbō with a shell launch. Test commands inside an existing container remain subject to the current permissions.', 'A running process or container is not proof that the service is ready or that tests passed. Before dependent tests, use the documented health check or a non-mutating request to the appropriate service URL. Bound readiness checks with a timeout and limited retries; if readiness remains unconfirmed, inspect logs and report the blocker rather than restarting repeatedly. Missing application readiness does not invalidate independent unit tests.');
40
49
  lines.push('## Delegation and reporting', 'Only one agent edits the worktree at a time. Parallel read-only analysis is allowed; wait for an editing subagent to finish before editing or running tests yourself. Give each delegate its objective, exact worktree path, relevant user constraints, current permissions, intended test runtime and applicable Kōbō tools and reporting rules. Do not assume it inherits this context. A delegate without the required managed tools must ask its parent to coordinate the operation within the same permissions, not bypass Kōbō.');
41
50
  if (context.progressReporting)
42
51
  lines.push(PROGRESS_BAR_PROMPT);
@@ -53,9 +62,11 @@ export function buildKoboLaunchInstructions(context) {
53
62
  else {
54
63
  continuation.push('This launch cannot schedule follow-up work. Use available completion notifications for tracked work; report unfinished work or blockers honestly and finish the requested analysis/report.');
55
64
  }
65
+ if (context.engine === 'mistral-vibe')
66
+ continuation.push('Use native `tools.process` tracked jobs for long-running commands; do not use raw redirected Bash backgrounding to detach work from native ownership.');
56
67
  const continuationText = continuation.join('\n');
57
- // Claude supports a durable application append; Codex receives the same rules in its input.
58
- if (context.engine === 'codex')
68
+ // Claude supports a durable application append; other engines receive these rules in their input.
69
+ if (context.engine !== 'claude-code')
59
70
  lines.push(continuationText);
60
71
  return { promptPrefix: lines.join('\n\n'), systemAppend: context.engine === 'claude-code' ? continuationText : '' };
61
72
  }
@@ -31,7 +31,7 @@ export function deriveMemoryActor(source, _callerActor) {
31
31
  if (source.kind === 'internal-agent') {
32
32
  if (!isNonEmptyString(source.workspaceId) ||
33
33
  !isNonEmptyString(source.sessionId) ||
34
- (source.engine !== 'claude-code' && source.engine !== 'codex')) {
34
+ (source.engine !== 'claude-code' && source.engine !== 'codex' && source.engine !== 'mistral-vibe')) {
35
35
  throw new TypeError('Invalid internal memory actor source');
36
36
  }
37
37
  return Object.freeze({
@@ -0,0 +1,9 @@
1
+ /** Static fallback only; contextual native ACP discovery supplies explicit aliases. */
2
+ export const MISTRAL_MODELS = [
3
+ {
4
+ id: 'auto',
5
+ label: 'Auto',
6
+ i18nLabelKey: 'model.auto',
7
+ i18nDescriptionKey: 'model.mistralAutoDescription',
8
+ },
9
+ ];
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,16 @@
1
+ /** Native multi-select values travel separately from legacy human-readable answers. */
2
+ export function parseQuestionSelections(value) {
3
+ if (value === undefined)
4
+ return undefined;
5
+ if (!value || typeof value !== 'object' || Array.isArray(value))
6
+ throw new Error('selections must be an object of string arrays');
7
+ const entries = Object.entries(value);
8
+ if (entries.length > 20 ||
9
+ entries.some(([key, values]) => !key ||
10
+ key.length > 200 ||
11
+ !Array.isArray(values) ||
12
+ values.length > 32 ||
13
+ values.some((item) => typeof item !== 'string' || item.length > 2000)))
14
+ throw new Error('selections exceed their field, choice or string limits');
15
+ return value;
16
+ }
@@ -9,8 +9,8 @@ const object = (properties, required = []) => ({
9
9
  required,
10
10
  additionalProperties: false,
11
11
  });
12
- const effort = choice('auto', 'none', 'low', 'medium', 'high', 'xhigh', 'max');
13
- const engine = choice('claude-code', 'codex');
12
+ const effort = choice('auto', 'off', 'none', 'low', 'medium', 'high', 'xhigh', 'max');
13
+ const engine = choice('claude-code', 'codex', 'mistral-vibe');
14
14
  const path = string(4096);
15
15
  const url = string(4096);
16
16
  const titles = { type: 'array', items: string(20_000), maxItems: 500 };
@@ -144,6 +144,12 @@ export function validateWorkspaceCreationArguments(name, input) {
144
144
  }
145
145
  }
146
146
  if (name === 'create_workspace') {
147
+ if (value.engine !== 'mistral-vibe' &&
148
+ (value.reasoning_effort === 'off' || value.brainstorm_reasoning_effort === 'off'))
149
+ throw new Error('off is a native Mistral Vibe thinking value');
150
+ const review = value.auto_loop_final_review;
151
+ if (review && review.engine !== 'mistral-vibe' && review.reasoning_effort === 'off')
152
+ throw new Error('off is a native Mistral Vibe thinking value');
147
153
  const { attachments: _attachments, ...metadataFields } = value;
148
154
  // Keep room for multipart file headers within the downstream 1 MiB allowance.
149
155
  if (new TextEncoder().encode(JSON.stringify(metadataFields)).byteLength > 960 * 1024)
@@ -1,4 +1,5 @@
1
1
  import { MCP_ATTACHMENTS_SCHEMA, validateMcpAttachments } from './mcp-attachments.js';
2
+ import { parseQuestionSelections } from './question-selections.js';
2
3
  const workspace = { type: 'string', minLength: 1, maxLength: 200, description: 'Workspace ID from list_workspaces.' };
3
4
  const session = {
4
5
  type: 'string',
@@ -41,10 +42,16 @@ export const WORKSPACE_DIALOGUE_TOOLS = [
41
42
  },
42
43
  }, ['workspace_id'], false),
43
44
  tool('get_workspace_questions', 'Read pending questions and whether a human tool approval is blocking the workspace.', { workspace_id: workspace }, ['workspace_id']),
44
- tool('answer_workspace_question', 'Answer the current pending question using its exact tool_call_id. Answer keys are question IDs for Codex, question text for Claude. Tool permission requests require human approval in Kōbō.', {
45
+ tool('answer_workspace_question', 'Answer the current pending question using its exact tool_call_id. Answer keys are question IDs for Codex/Mistral Vibe, question text for Claude. Native multiple-choice arrays use selections; never split comma-joined display answers. Tool permission requests require human approval in Kōbō.', {
45
46
  workspace_id: workspace,
46
47
  tool_call_id: { type: 'string', minLength: 1, maxLength: 200 },
47
- answers: { type: 'object', minProperties: 1, additionalProperties: { type: 'string' } },
48
+ answers: { type: 'object', additionalProperties: { type: 'string' } },
49
+ selections: {
50
+ type: 'object',
51
+ maxProperties: 20,
52
+ propertyNames: { minLength: 1, maxLength: 200 },
53
+ additionalProperties: { type: 'array', maxItems: 32, items: { type: 'string', maxLength: 2000 } },
54
+ },
48
55
  }, ['workspace_id', 'tool_call_id', 'answers'], false),
49
56
  ];
50
57
  export const EXTERNAL_MCP_TOOLS = [WORKSPACE_DISCOVERY_TOOL, ...WORKSPACE_DIALOGUE_TOOLS];
@@ -60,6 +67,8 @@ export function validateDialogueArguments(name, value) {
60
67
  for (const key of definition.inputSchema.required ?? [])
61
68
  if (!Object.hasOwn(args, key))
62
69
  throw new Error(`${key} is required`);
70
+ if (name === 'answer_workspace_question')
71
+ parseQuestionSelections(args.selections);
63
72
  for (const [key, input] of Object.entries(args)) {
64
73
  const property = properties[key];
65
74
  if (!Object.hasOwn(properties, key))
@@ -67,6 +76,9 @@ export function validateDialogueArguments(name, value) {
67
76
  if (key === 'attachments') {
68
77
  validateMcpAttachments(input);
69
78
  }
79
+ else if (key === 'selections') {
80
+ // Validated above; native forms may omit all optional fields.
81
+ }
70
82
  else if (property.type === 'string') {
71
83
  if (typeof input !== 'string' ||
72
84
  (property.minLength !== 0 && !input.trim()) ||
@@ -87,9 +99,8 @@ export function validateDialogueArguments(name, value) {
87
99
  else if (!input ||
88
100
  typeof input !== 'object' ||
89
101
  Array.isArray(input) ||
90
- Object.keys(input).length === 0 ||
91
102
  Object.values(input).some((answer) => typeof answer !== 'string' || answer.length > 100_000)) {
92
- throw new Error(`${key} must be a non-empty object of string answers`);
103
+ throw new Error(`${key} must be an object of string answers`);
93
104
  }
94
105
  }
95
106
  if (name === 'send_workspace_message') {
@@ -97,7 +97,7 @@ these checks.
97
97
 
98
98
  After installation, continue with [opening Kōbō](#2-start-and-open-kōbō) and
99
99
  [authenticating agent engines](#3-authenticate-and-choose-a-project). The installer
100
- does not log you into Claude or Codex. Obtain the Kōbō browser token through the
100
+ does not log you into Claude Code, Codex or Mistral Vibe. Obtain the Kōbō browser token through the
101
101
  existing startup-log command below. For installer-managed deployments, invoke the
102
102
  updater as `/opt/kobo/bin/kobo-update --directory /opt/kobo`; the `./kobo-update`
103
103
  examples later in this guide describe the manual installation layout.
@@ -312,6 +312,11 @@ and login requirements can vary; `claude auth login --help` and `codex login --h
312
312
  show the supported options. You can also configure your own provider API key.
313
313
  No paid agent turn is needed for these setup commands.
314
314
 
315
+ For **Mistral Vibe**, install Vibe separately in the image/container and authenticate
316
+ as the same agent user. The server must be able to run `vibe-acp`. Follow
317
+ [Use Mistral Vibe inside the container](./vps-projects-and-skills.md#use-mistral-vibe-inside-the-container);
318
+ an installation or login on the host is insufficient.
319
+
315
320
  For a personal GitHub account, complete the CLI's browser login flow from your PC,
316
321
  then connect Git HTTPS credentials to it:
317
322
 
@@ -337,7 +342,9 @@ In the first-run form, **Local project directory** means
337
342
  nor a folder on the PC running the browser. Then follow [your first mission](./getting-started.md#create-a-mission).
338
343
 
339
344
  The named `kobo-home` volume covers `/root`: it preserves Kōbō's database/settings,
340
- Claude/Codex state and Git/forge configuration across container replacement.
345
+ Claude/Codex state, Vibe state stored under that home, and Git/forge configuration
346
+ across container replacement. A custom `VIBE_HOME` outside the volume needs its own
347
+ persistence.
341
348
  Do not run `docker compose down -v`. Authentication performed only on the host is
342
349
  not automatically available inside a container. See [Docker volume persistence](https://docs.docker.com/reference/compose-file/volumes/).
343
350
 
@@ -616,7 +623,7 @@ the reservation deliberately has no expiry that could reopen the race. Follow
616
623
  container and confirm its exit before restarting it. Restart clears the in-memory
617
624
  reservation. Never release it while a Docker stop could still be in progress.
618
625
 
619
- Claude/Codex configuration and credentials, skills/plugins, caches, browser
626
+ Claude Code/Codex/Mistral Vibe configuration and credentials, skills/plugins, caches, browser
620
627
  downloads, repositories/worktrees, bind-mounted App keys/scripts and project
621
628
  database volumes are **not included** in `kobo.tar.gz`. Files outside the Kōbō
622
629
  directory remain in the existing volume; the updater neither archives nor deletes
@@ -1,10 +1,11 @@
1
1
  # Your first Kōbō workspace
2
2
 
3
- Kōbō is a local, single-user application that runs Claude Code or OpenAI Codex in Git worktrees. Each user installs their own instance and supplies their own provider account. A shared network token is not a multi-user account system.
3
+ Kōbō is a local, single-user application that runs Claude Code, OpenAI Codex or Mistral Vibe in Git worktrees. Each user installs their own instance and supplies their own provider account. A shared network token is not a multi-user account system.
4
4
 
5
5
  ## Requirements
6
6
 
7
- - Node.js 24.15 or later, Git and Bash, with a writable local Git repository containing at least one commit.
7
+ - Node.js 26.12.1 or later, Git and Bash, with a writable local Git repository containing at least one commit.
8
+ - For Mistral Vibe, install and authenticate Vibe separately as the Kōbō server user; `vibe-acp` must be on its PATH. See [Mistral Vibe setup](../CONFIGURATION.md#mistral-vibe).
8
9
  - A working login or API credential for the engine you choose. Kōbō ships neither credentials nor a provider subscription. Provider usage can incur charges.
9
10
  - Linux is the locally exercised platform for this readiness change. CI is configured to exercise Linux and macOS; a configured job is not a completed compatibility test. Windows users need a Linux environment such as WSL; native Windows and WSL have not been validated in this release rehearsal.
10
11
 
@@ -36,7 +37,7 @@ Open <http://localhost:3000>. The server binds to loopback by default. Do not ex
36
37
  1. In the first-run panel, choose an engine and the path of your local Git repository.
37
38
  2. Run **Check environment**. Resolve missing Git, Bash, runtime, or write access before continuing. Authentication and model availability remain **unverified**: diagnostics do not contact a paid model or read your credentials.
38
39
  3. Continue to the creation form. Name the mission and describe a small change, including its acceptance criteria.
39
- 4. Keep **Standard** and **Plan** for the first review. Standard requires no external skill suite. Plan does not silently become unrestricted when you prepare or enable auto-loop.
40
+ 4. Keep **Standard** for a first mission. Use **Plan** with Claude Code/Codex, or **Interactive** with Mistral Vibe. Vibe has no Plan mode: review prompts forbid modifications, but native permissions do not guarantee filesystem read-only access. Standard requires no external skill suite. Plan does not silently become unrestricted when you prepare or enable auto-loop.
40
41
  5. Review the plan, explicitly select an execution permission mode when you are ready, and send the implementation instruction. Review the resulting diff before committing or publishing.
41
42
 
42
43
  New installations use manual commit, push and PR/MR publication preferences, disable audio and optional ticket integrations, and admit at most two concurrent unattended starts. Manual sessions can exceed that threshold. Agent workflow preferences are instructions; the engine permission mode supplies the actual sandbox and approval behavior.
@@ -6,11 +6,11 @@ Open the first-run setup from Help and run the check again after changing the se
6
6
 
7
7
  | Check | Action |
8
8
  |---|---|
9
- | Node | Use Node 24.15 or later; contributors should use `.nvmrc`. |
9
+ | Node | Use Node 26.12.1 or later; contributors should use `.nvmrc`. |
10
10
  | Git / Bash | Install the missing executable and make it available on the server's `PATH`. |
11
11
  | Project | Select a writable Git repository containing at least one commit. |
12
12
  | Storage / worktrees | Check permissions on `KOBO_HOME`, the project and configured worktree root. |
13
- | Engine executable | Reinstall the package dependencies and check the chosen runtime installation. |
13
+ | Engine executable | Check the chosen runtime installation. Claude Code/Codex runtimes come from package dependencies; Mistral Vibe must be installed separately, with `vibe-acp` on the server user’s PATH (inside the container for Docker). See [Vibe setup](../CONFIGURATION.md#mistral-vibe). |
14
14
  | Authentication / model: unknown | Authenticate with the selected provider, select a model available to that account, then run a small mission. The diagnostic deliberately makes no provider request. |
15
15
 
16
16
  ## Native dependency installation fails
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loicngr/kobo",
3
- "version": "2.1.28",
3
+ "version": "2.1.30",
4
4
  "description": "Kōbō — local multi-workspace orchestrator for Claude Code and OpenAI Codex, with isolated Git worktrees, live review and optional automation.",
5
5
  "type": "module",
6
6
  "license": "GPL-3.0-or-later",
@@ -61,7 +61,7 @@
61
61
  "quasar"
62
62
  ],
63
63
  "engines": {
64
- "node": ">=24.15.0"
64
+ "node": ">=26.12.1"
65
65
  },
66
66
  "scripts": {
67
67
  "dev": "KOBO_ENFORCE_LOCAL_HOME=1 KOBO_HOME=./data PORT=3300 KOBO_DEV_CLIENT_ORIGIN=http://localhost:8080 tsx watch src/server/index.ts",
@@ -88,32 +88,38 @@
88
88
  "security:scan": "node scripts/scan-secrets.mjs"
89
89
  },
90
90
  "dependencies": {
91
- "@anthropic-ai/claude-agent-sdk": "^0.3.287",
91
+ "@agentclientprotocol/sdk": "2.0.1",
92
+ "@anthropic-ai/claude-agent-sdk": "^0.3.308",
92
93
  "@emnapi/core": "^1.11.3",
93
94
  "@emnapi/runtime": "^1.11.3",
94
- "@hono/node-server": "^2.1.3",
95
- "@modelcontextprotocol/sdk": "^1.31.0",
96
- "@openai/codex": "^0.159.3",
95
+ "@hono/node-server": "^2.1.5",
96
+ "@modelcontextprotocol/sdk": "^1.32.1",
97
+ "@openai/codex": "^0.163.0",
97
98
  "better-sqlite3": "^13.0.3",
98
- "cron-parser": "^5.10.1",
99
- "hono": "^4.13.12",
100
- "nanoid": "^6.0.1",
99
+ "cron-parser": "^5.10.2",
100
+ "hono": "^4.13.13",
101
+ "nanoid": "^6.0.2",
101
102
  "node-pty": "^1.1.0",
102
103
  "ws": "^8.22.0"
103
104
  },
104
105
  "devDependencies": {
105
106
  "@biomejs/biome": "2.5.14",
106
107
  "@types/better-sqlite3": "^9.6.0",
107
- "@types/node": "^26.6.4",
108
+ "@types/node": "^26.6.5",
108
109
  "@types/ws": "^8.18.2",
109
110
  "@vitest/runner": "^4.1.11",
110
- "concurrently": "^10.0.5",
111
+ "concurrently": "^10.0.6",
111
112
  "tsx": "^4.23.15",
112
113
  "typescript": "^7.0.2",
113
- "vitest": "^5.0.3"
114
+ "vitest": "^5.0.5"
114
115
  },
115
116
  "overrides": {
116
- "@hono/node-server": "^2.1.3",
117
- "shell-quote": "^1.11.0"
117
+ "@hono/node-server": "^2.1.5",
118
+ "shell-quote": "^1.12.0"
119
+ },
120
+ "allowScripts": {
121
+ "better-sqlite3@13.0.3": true,
122
+ "esbuild@0.28.2": true,
123
+ "node-pty@1.1.0": true
118
124
  }
119
125
  }