vibepulse 0.2.2 → 0.3.1-beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/BUILD_ID +1 -1
- package/.next/app-path-routes-manifest.json +1 -0
- package/.next/build-manifest.json +2 -2
- package/.next/cache/.previewinfo +1 -1
- package/.next/cache/.rscinfo +1 -1
- package/.next/cache/.tsbuildinfo +1 -1
- package/.next/cache/config.json +3 -3
- package/.next/fallback-build-manifest.json +2 -2
- package/.next/prerender-manifest.json +3 -3
- package/.next/routes-manifest.json +8 -0
- package/.next/server/app/_global-error/page.js +1 -1
- package/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/.next/server/app/_global-error.html +2 -2
- package/.next/server/app/_global-error.rsc +1 -1
- package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/_not-found/page.js +1 -1
- package/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_not-found.html +1 -1
- package/.next/server/app/_not-found.rsc +2 -2
- package/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- package/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
- package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/api/node/events/route.js +2 -2
- package/.next/server/app/api/node/events/route.js.nft.json +1 -1
- package/.next/server/app/api/node/sessions/[id]/delete/route.js +2 -2
- package/.next/server/app/api/node/sessions/[id]/delete/route.js.nft.json +1 -1
- package/.next/server/app/api/node/sessions/[id]/open-editor/route.js +2 -2
- package/.next/server/app/api/node/sessions/[id]/open-editor/route.js.nft.json +1 -1
- package/.next/server/app/api/node/sessions/route.js +6 -4
- package/.next/server/app/api/node/sessions/route.js.nft.json +1 -1
- package/.next/server/app/api/nodes/route.js +2 -2
- package/.next/server/app/api/nodes/route.js.nft.json +1 -1
- package/.next/server/app/api/opencode-config/route.js +2 -2
- package/.next/server/app/api/opencode-config/route.js.nft.json +1 -1
- package/.next/server/app/api/opencode-config/status/route.js +2 -2
- package/.next/server/app/api/opencode-config/status/route.js.nft.json +1 -1
- package/.next/server/app/api/opencode-events/route.js +3 -3
- package/.next/server/app/api/opencode-events/route.js.nft.json +1 -1
- package/.next/server/app/api/profiles/[id]/apply/route.js +2 -2
- package/.next/server/app/api/profiles/[id]/apply/route.js.nft.json +1 -1
- package/.next/server/app/api/profiles/[id]/export/route.js +2 -2
- package/.next/server/app/api/profiles/[id]/export/route.js.nft.json +1 -1
- package/.next/server/app/api/profiles/[id]/route.js +2 -2
- package/.next/server/app/api/profiles/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/profiles/import/route.js +2 -2
- package/.next/server/app/api/profiles/import/route.js.nft.json +1 -1
- package/.next/server/app/api/profiles/route.js +2 -2
- package/.next/server/app/api/profiles/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/[id]/archive/route.js +3 -2
- package/.next/server/app/api/sessions/[id]/archive/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/[id]/delete/route.js +4 -3
- package/.next/server/app/api/sessions/[id]/delete/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/[id]/open-editor/route.js +2 -2
- package/.next/server/app/api/sessions/[id]/open-editor/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/[id]/restore/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/sessions/[id]/restore/route/build-manifest.json +11 -0
- package/.next/server/app/api/sessions/[id]/restore/route/server-reference-manifest.json +4 -0
- package/.next/server/app/api/sessions/[id]/restore/route.js +8 -0
- package/.next/server/app/api/sessions/[id]/restore/route.js.map +5 -0
- package/.next/server/app/api/sessions/[id]/restore/route.js.nft.json +1 -0
- package/.next/server/app/api/sessions/[id]/restore/route_client-reference-manifest.js +2 -0
- package/.next/server/app/api/sessions/[id]/route.js +2 -2
- package/.next/server/app/api/sessions/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/route.js +5 -3
- package/.next/server/app/api/sessions/route.js.nft.json +1 -1
- package/.next/server/app/index.html +1 -1
- package/.next/server/app/index.rsc +3 -3
- package/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/index.segments/_full.segment.rsc +3 -3
- package/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/.next/server/app/index.segments/_index.segment.rsc +2 -2
- package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app-paths-manifest.json +1 -0
- package/.next/server/chunks/[root-of-the-server]__005eb0c5._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__005eb0c5._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__09e90d57._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__09e90d57._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__18dd0ce9._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__18dd0ce9._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__19468536._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__19468536._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__1b87ec42._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__1b87ec42._.js.map +1 -1
- package/.next/server/chunks/[root-of-the-server]__2b912935._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__2b912935._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__303d3bac._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__303d3bac._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__3fac2b91._.js +5 -0
- package/.next/server/chunks/[root-of-the-server]__3fac2b91._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__43440b8d._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__43440b8d._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__438f8bbe._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__438f8bbe._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__4a0bfb55._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__4a0bfb55._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__534c3949._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__534c3949._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__59160266._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__59160266._.js.map +1 -1
- package/.next/server/chunks/[root-of-the-server]__6f812da0._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__6f812da0._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__71aac504._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__71aac504._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__907a8bf2._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__907a8bf2._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__92089220._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__92089220._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__9b7bc2d0._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__9b7bc2d0._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__b2640944._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__b2640944._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__c2267cf1._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__c2267cf1._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__d7f7e6dd._.js +3 -0
- package/.next/server/chunks/{[root-of-the-server]__6924c09d._.js.map → [root-of-the-server]__d7f7e6dd._.js.map} +1 -1
- package/.next/server/chunks/[root-of-the-server]__d8e61048._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__d8e61048._.js.map +1 -1
- package/.next/server/chunks/[root-of-the-server]__f6d0d488._.js +3 -0
- package/.next/server/chunks/{[root-of-the-server]__192ed2f4._.js.map → [root-of-the-server]__f6d0d488._.js.map} +1 -1
- package/.next/server/chunks/[root-of-the-server]__fa559e1e._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__fa559e1e._.js.map +1 -0
- package/.next/server/chunks/_next-internal_server_app_api_sessions_[id]_restore_route_actions_af7d6b6c.js +3 -0
- package/.next/server/chunks/_next-internal_server_app_api_sessions_[id]_restore_route_actions_af7d6b6c.js.map +1 -0
- package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_7e181e75.js +1 -1
- package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_7e181e75.js.map +1 -1
- package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_aca45402.js +1 -1
- package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_aca45402.js.map +1 -1
- package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_b054aff3.js +1 -1
- package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_b054aff3.js.map +1 -1
- package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_fa835ac3.js +2 -2
- package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_fa835ac3.js.map +1 -1
- package/.next/server/chunks/src_lib_opencodeConfig_ts_8e209941._.js +3 -0
- package/.next/server/chunks/src_lib_opencodeConfig_ts_8e209941._.js.map +1 -0
- package/.next/server/chunks/src_lib_session-providers_claudeCode_ts_0f9590ed._.js +3 -0
- package/.next/server/chunks/src_lib_session-providers_claudeCode_ts_0f9590ed._.js.map +1 -0
- package/.next/server/chunks/ssr/{[root-of-the-server]__631e12d0._.js → [root-of-the-server]__c91a8380._.js} +2 -2
- package/.next/server/chunks/ssr/{[root-of-the-server]__631e12d0._.js.map → [root-of-the-server]__c91a8380._.js.map} +1 -1
- package/.next/server/chunks/ssr/src_app_page_tsx_a7111f3e._.js +3 -3
- package/.next/server/chunks/ssr/src_app_page_tsx_a7111f3e._.js.map +1 -1
- package/.next/server/pages/404.html +1 -1
- package/.next/server/pages/500.html +2 -2
- package/.next/server/server-reference-manifest.js +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/app-path-routes-manifest.json +1 -0
- package/.next/standalone/.next/build-manifest.json +2 -2
- package/.next/standalone/.next/prerender-manifest.json +3 -3
- package/.next/standalone/.next/routes-manifest.json +8 -0
- package/.next/standalone/.next/server/app/_global-error/page.js +1 -1
- package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_global-error.html +2 -2
- package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page.js +1 -1
- package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +1 -1
- package/.next/standalone/.next/server/app/_not-found.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/api/node/events/route.js +2 -2
- package/.next/standalone/.next/server/app/api/node/events/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/node/sessions/[id]/delete/route.js +2 -2
- package/.next/standalone/.next/server/app/api/node/sessions/[id]/delete/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/node/sessions/[id]/open-editor/route.js +2 -2
- package/.next/standalone/.next/server/app/api/node/sessions/[id]/open-editor/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/node/sessions/route.js +6 -4
- package/.next/standalone/.next/server/app/api/node/sessions/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/nodes/route.js +2 -2
- package/.next/standalone/.next/server/app/api/nodes/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/opencode-config/route.js +2 -2
- package/.next/standalone/.next/server/app/api/opencode-config/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/opencode-config/status/route.js +2 -2
- package/.next/standalone/.next/server/app/api/opencode-config/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/opencode-events/route.js +3 -3
- package/.next/standalone/.next/server/app/api/opencode-events/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/profiles/[id]/apply/route.js +2 -2
- package/.next/standalone/.next/server/app/api/profiles/[id]/apply/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/profiles/[id]/export/route.js +2 -2
- package/.next/standalone/.next/server/app/api/profiles/[id]/export/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/profiles/[id]/route.js +2 -2
- package/.next/standalone/.next/server/app/api/profiles/[id]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/profiles/import/route.js +2 -2
- package/.next/standalone/.next/server/app/api/profiles/import/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/profiles/route.js +2 -2
- package/.next/standalone/.next/server/app/api/profiles/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/sessions/[id]/archive/route.js +3 -2
- package/.next/standalone/.next/server/app/api/sessions/[id]/archive/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/sessions/[id]/delete/route.js +4 -3
- package/.next/standalone/.next/server/app/api/sessions/[id]/delete/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/sessions/[id]/open-editor/route.js +2 -2
- package/.next/standalone/.next/server/app/api/sessions/[id]/open-editor/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/sessions/[id]/restore/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/sessions/[id]/restore/route/build-manifest.json +11 -0
- package/.next/standalone/.next/server/app/api/sessions/[id]/restore/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/sessions/[id]/restore/route.js +8 -0
- package/.next/standalone/.next/server/app/api/sessions/[id]/restore/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/sessions/[id]/restore/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/sessions/[id]/restore/route_client-reference-manifest.js +2 -0
- package/.next/standalone/.next/server/app/api/sessions/[id]/route.js +2 -2
- package/.next/standalone/.next/server/app/api/sessions/[id]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/sessions/route.js +5 -3
- package/.next/standalone/.next/server/app/api/sessions/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +3 -3
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app-paths-manifest.json +1 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__005eb0c5._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__09e90d57._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__18dd0ce9._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__19468536._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1b87ec42._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__2b912935._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__303d3bac._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__3fac2b91._.js +5 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__43440b8d._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__438f8bbe._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__4a0bfb55._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__534c3949._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__59160266._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__6f812da0._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__71aac504._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__907a8bf2._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__92089220._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__9b7bc2d0._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__b2640944._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__c2267cf1._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__d7f7e6dd._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__d8e61048._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__f6d0d488._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__fa559e1e._.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_sessions_[id]_restore_route_actions_af7d6b6c.js +3 -0
- package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_7e181e75.js +1 -1
- package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_aca45402.js +1 -1
- package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_b054aff3.js +1 -1
- package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_fa835ac3.js +2 -2
- package/.next/standalone/.next/server/chunks/src_lib_opencodeConfig_ts_8e209941._.js +3 -0
- package/.next/standalone/.next/server/chunks/src_lib_session-providers_claudeCode_ts_0f9590ed._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__631e12d0._.js → [root-of-the-server]__c91a8380._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/src_app_page_tsx_a7111f3e._.js +3 -3
- package/.next/standalone/.next/server/pages/404.html +1 -1
- package/.next/standalone/.next/server/pages/500.html +2 -2
- package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/static/chunks/9e790b67c80f853c.js +13 -0
- package/.next/standalone/.next/static/chunks/c3dc8cd80979c971.css +3 -0
- package/.next/standalone/AGENTS.md +4 -0
- package/.next/standalone/README.md +54 -5
- package/.next/standalone/check-hsql.mjs +1 -1
- package/.next/standalone/docs/session-status-detection.md +36 -0
- package/.next/standalone/docs/superpowers/specs/2026-04-09-claude-capability-alignment-design.md +39 -0
- package/.next/standalone/eslint.config.mjs +1 -0
- package/.next/standalone/package-lock.json +74 -13
- package/.next/standalone/package.json +2 -2
- package/.next/standalone/src/app/api/node/events/route.ts +3 -3
- package/.next/standalone/src/app/api/node/sessions/[id]/archive/route.test.ts +60 -1
- package/.next/standalone/src/app/api/node/sessions/[id]/archive/route.ts +77 -22
- package/.next/standalone/src/app/api/node/sessions/[id]/delete/route.ts +6 -5
- package/.next/standalone/src/app/api/node/sessions/[id]/open-editor/route.ts +6 -5
- package/.next/standalone/src/app/api/node/sessions/route.test.ts +282 -0
- package/.next/standalone/src/app/api/node/sessions/route.ts +156 -30
- package/.next/standalone/src/app/api/opencode-config/route.test.ts +613 -0
- package/.next/standalone/src/app/api/opencode-config/route.ts +336 -185
- package/.next/standalone/src/app/api/opencode-events/route.test.ts +77 -1
- package/.next/standalone/src/app/api/opencode-events/route.ts +3 -3
- package/.next/standalone/src/app/api/opencode-models/route.test.ts +19 -0
- package/.next/standalone/src/app/api/opencode-models/route.ts +4 -1
- package/.next/standalone/src/app/api/profiles/[id]/apply/route.test.ts +227 -0
- package/.next/standalone/src/app/api/profiles/[id]/apply/route.ts +13 -9
- package/.next/standalone/src/app/api/sessions/[id]/archive/route.test.ts +126 -0
- package/.next/standalone/src/app/api/sessions/[id]/archive/route.ts +47 -12
- package/.next/standalone/src/app/api/sessions/[id]/delete/route.test.ts +140 -0
- package/.next/standalone/src/app/api/sessions/[id]/delete/route.ts +51 -16
- package/.next/standalone/src/app/api/sessions/[id]/open-editor/route.test.ts +74 -0
- package/.next/standalone/src/app/api/sessions/[id]/open-editor/route.ts +22 -2
- package/.next/standalone/src/app/api/sessions/[id]/restore/route.test.ts +186 -0
- package/.next/standalone/src/app/api/sessions/[id]/restore/route.ts +184 -0
- package/.next/standalone/src/app/api/sessions/[id]/route.ts +3 -3
- package/.next/standalone/src/app/api/sessions/route.test.ts +1955 -100
- package/.next/standalone/src/app/api/sessions/route.ts +361 -986
- package/.next/standalone/src/components/KanbanBoard.test.tsx +307 -1
- package/.next/standalone/src/components/KanbanBoard.tsx +106 -19
- package/.next/standalone/src/components/ProjectCard.test.tsx +420 -6
- package/.next/standalone/src/components/ProjectCard.tsx +238 -86
- package/.next/standalone/src/components/SessionCard.test.tsx +259 -8
- package/.next/standalone/src/components/SessionCard.tsx +182 -76
- package/.next/standalone/src/components/opencode-config/AgentConfigForm.test.tsx +141 -1
- package/.next/standalone/src/components/opencode-config/AgentConfigForm.tsx +99 -7
- package/.next/standalone/src/components/opencode-config/GeneralSettingsForm.test.tsx +11 -0
- package/.next/standalone/src/components/opencode-config/GeneralSettingsForm.tsx +41 -2
- package/.next/standalone/src/components/opencode-config/categories/CategoriesManager.tsx +3 -1
- package/.next/standalone/src/components/opencode-config/categories/CategoryConfigForm.test.tsx +106 -8
- package/.next/standalone/src/components/opencode-config/categories/CategoryConfigForm.tsx +82 -5
- package/.next/standalone/src/hooks/useHostSources.test.ts +0 -41
- package/.next/standalone/src/hooks/useOpencodeSync.test.ts +321 -1
- package/.next/standalone/src/hooks/useOpencodeSync.ts +16 -12
- package/.next/standalone/src/lib/claudeSessionOverrides.test.ts +75 -0
- package/.next/standalone/src/lib/claudeSessionOverrides.ts +169 -0
- package/.next/standalone/src/lib/fixtures/opencode-config/oh-my-openagent.v4.jsonc +70 -0
- package/.next/standalone/src/lib/fixtures/opencode-config/oh-my-openagent.v4.secret-like.jsonc +21 -0
- package/.next/standalone/src/lib/fixtures/opencode-config/oh-my-opencode.v3.jsonc +17 -0
- package/.next/standalone/src/lib/opencodeConfig.test.ts +430 -3
- package/.next/standalone/src/lib/opencodeConfig.ts +157 -4
- package/.next/standalone/src/lib/opencodeDiscovery.test.ts +241 -0
- package/.next/standalone/src/lib/opencodeDiscovery.ts +164 -9
- package/.next/standalone/src/lib/profiles/share.test.ts +92 -0
- package/.next/standalone/src/lib/profiles/share.ts +1 -0
- package/.next/standalone/src/lib/profiles/storage.test.ts +77 -1
- package/.next/standalone/src/lib/profiles/storage.ts +10 -9
- package/.next/standalone/src/lib/session-providers/claudeCode.test.ts +2288 -0
- package/.next/standalone/src/lib/session-providers/claudeCode.ts +1083 -0
- package/.next/standalone/src/lib/session-providers/localAggregator.test.ts +322 -0
- package/.next/standalone/src/lib/session-providers/localAggregator.ts +302 -0
- package/.next/standalone/src/lib/session-providers/opencodeProvider.test.ts +170 -0
- package/.next/standalone/src/lib/session-providers/opencodeProvider.ts +721 -0
- package/.next/standalone/src/lib/session-providers/opencodeSdkCompat.ts +92 -0
- package/.next/standalone/src/lib/session-providers/providerIds.test.ts +337 -0
- package/.next/standalone/src/lib/session-providers/providerIds.ts +176 -0
- package/.next/standalone/src/lib/session-providers/types.ts +131 -0
- package/.next/standalone/src/lib/transform.test.ts +253 -0
- package/.next/standalone/src/lib/transform.ts +96 -37
- package/.next/standalone/src/types/index.ts +23 -17
- package/.next/standalone/src/types/opencodeConfig.ts +55 -0
- package/.next/static/chunks/9e790b67c80f853c.js +13 -0
- package/.next/static/chunks/c3dc8cd80979c971.css +3 -0
- package/.next/trace +1 -1
- package/.next/trace-build +1 -1
- package/.next/types/routes.d.ts +2 -1
- package/.next/types/validator.ts +9 -0
- package/README.md +54 -5
- package/package.json +2 -2
- package/.next/server/chunks/[root-of-the-server]__1211da38._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__1211da38._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__192ed2f4._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__2b526e7a._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__2b526e7a._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__2f981540._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__2f981540._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__3745b314._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__3745b314._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__56690af0._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__56690af0._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__56f5f249._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__56f5f249._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__59175de4._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__59175de4._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__64fffc02._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__64fffc02._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__6924c09d._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__6c428a24._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__6c428a24._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__73a00b88._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__73a00b88._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__7e757f50._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__7e757f50._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__89c5eeab._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__89c5eeab._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__8da6c5a8._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__8da6c5a8._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__b796d06c._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__b796d06c._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__c2ce5c0f._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__c2ce5c0f._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__db285678._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__db285678._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__e00a9200._.js +0 -5
- package/.next/server/chunks/[root-of-the-server]__e00a9200._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__e5df5e5f._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__e5df5e5f._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__edbc8d9e._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__edbc8d9e._.js.map +0 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1211da38._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__192ed2f4._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__2b526e7a._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__2f981540._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__3745b314._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__56690af0._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__56f5f249._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__59175de4._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__64fffc02._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__6924c09d._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__6c428a24._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__73a00b88._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__7e757f50._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__89c5eeab._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__8da6c5a8._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__b796d06c._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__c2ce5c0f._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__db285678._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__e00a9200._.js +0 -5
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__e5df5e5f._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__edbc8d9e._.js +0 -3
- package/.next/standalone/.next/static/chunks/65d5354ba0add961.js +0 -13
- package/.next/standalone/.next/static/chunks/f42202943f6742e5.css +0 -3
- package/.next/static/chunks/65d5354ba0add961.js +0 -13
- package/.next/static/chunks/f42202943f6742e5.css +0 -3
- /package/.next/standalone/.next/static/{5kq9DtuBFVxu4jsgmL5Q- → 0WaQ6UjiNBgvh531pJVh0}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{5kq9DtuBFVxu4jsgmL5Q- → 0WaQ6UjiNBgvh531pJVh0}/_clientMiddlewareManifest.json +0 -0
- /package/.next/standalone/.next/static/{5kq9DtuBFVxu4jsgmL5Q- → 0WaQ6UjiNBgvh531pJVh0}/_ssgManifest.js +0 -0
- /package/.next/static/{5kq9DtuBFVxu4jsgmL5Q- → 0WaQ6UjiNBgvh531pJVh0}/_buildManifest.js +0 -0
- /package/.next/static/{5kq9DtuBFVxu4jsgmL5Q- → 0WaQ6UjiNBgvh531pJVh0}/_clientMiddlewareManifest.json +0 -0
- /package/.next/static/{5kq9DtuBFVxu4jsgmL5Q- → 0WaQ6UjiNBgvh531pJVh0}/_ssgManifest.js +0 -0
|
@@ -12,6 +12,8 @@ interface AgentConfig {
|
|
|
12
12
|
top_p?: number;
|
|
13
13
|
variant?: string;
|
|
14
14
|
prompt_append?: string;
|
|
15
|
+
reasoningEffort?: string;
|
|
16
|
+
fallback_models?: unknown;
|
|
15
17
|
}
|
|
16
18
|
|
|
17
19
|
interface CategoryConfig {
|
|
@@ -47,6 +49,9 @@ interface AgentConfigFormData {
|
|
|
47
49
|
top_p: number;
|
|
48
50
|
variant: string;
|
|
49
51
|
prompt_append: string;
|
|
52
|
+
reasoningEffort: string;
|
|
53
|
+
fallbackModelsObj?: unknown;
|
|
54
|
+
fallback_models: string;
|
|
50
55
|
}
|
|
51
56
|
|
|
52
57
|
interface AgentConfigFormProps {
|
|
@@ -99,6 +104,9 @@ export function AgentConfigForm({
|
|
|
99
104
|
top_p: 1,
|
|
100
105
|
variant: '',
|
|
101
106
|
prompt_append: '',
|
|
107
|
+
reasoningEffort: '',
|
|
108
|
+
fallbackModelsObj: undefined,
|
|
109
|
+
fallback_models: '',
|
|
102
110
|
},
|
|
103
111
|
});
|
|
104
112
|
|
|
@@ -149,6 +157,11 @@ export function AgentConfigForm({
|
|
|
149
157
|
top_p: currentAgentConfig.top_p ?? 1,
|
|
150
158
|
variant: currentAgentConfig.variant || '',
|
|
151
159
|
prompt_append: currentAgentConfig.prompt_append || '',
|
|
160
|
+
reasoningEffort: currentAgentConfig.reasoningEffort || '',
|
|
161
|
+
fallbackModelsObj: currentAgentConfig.fallback_models,
|
|
162
|
+
fallback_models: currentAgentConfig.fallback_models
|
|
163
|
+
? JSON.stringify(currentAgentConfig.fallback_models, null, 2)
|
|
164
|
+
: '',
|
|
152
165
|
});
|
|
153
166
|
}
|
|
154
167
|
}, [config, agentName, reset]);
|
|
@@ -161,13 +174,13 @@ export function AgentConfigForm({
|
|
|
161
174
|
}, [toast]);
|
|
162
175
|
|
|
163
176
|
const saveMutation = useMutation({
|
|
164
|
-
mutationFn: async (
|
|
177
|
+
mutationFn: async (payloadData: AgentConfig) => {
|
|
165
178
|
const res = await fetch('/api/opencode-config', {
|
|
166
179
|
method: 'POST',
|
|
167
180
|
headers: { 'Content-Type': 'application/json' },
|
|
168
181
|
body: JSON.stringify({
|
|
169
182
|
agents: {
|
|
170
|
-
[agentName]:
|
|
183
|
+
[agentName]: payloadData,
|
|
171
184
|
},
|
|
172
185
|
}),
|
|
173
186
|
});
|
|
@@ -190,7 +203,35 @@ export function AgentConfigForm({
|
|
|
190
203
|
});
|
|
191
204
|
|
|
192
205
|
const onSubmit = (data: AgentConfigFormData) => {
|
|
193
|
-
|
|
206
|
+
let parsedFallback = undefined;
|
|
207
|
+
if (data.fallback_models.trim() !== '') {
|
|
208
|
+
try {
|
|
209
|
+
parsedFallback = JSON.parse(data.fallback_models);
|
|
210
|
+
} catch {
|
|
211
|
+
setToast({ type: 'error', message: 'Invalid JSON in fallback_models' });
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
type AgentConfigPayload = Omit<AgentConfig, 'reasoningEffort' | 'fallback_models'> & {
|
|
217
|
+
reasoningEffort?: AgentConfig['reasoningEffort'] | null;
|
|
218
|
+
fallback_models?: AgentConfig['fallback_models'] | null;
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
const payload: AgentConfigPayload = {
|
|
222
|
+
model: data.model,
|
|
223
|
+
temperature: data.temperature,
|
|
224
|
+
top_p: data.top_p,
|
|
225
|
+
variant: data.variant,
|
|
226
|
+
prompt_append: data.prompt_append,
|
|
227
|
+
};
|
|
228
|
+
if (data.reasoningEffort) payload.reasoningEffort = data.reasoningEffort as AgentConfig['reasoningEffort'];
|
|
229
|
+
else payload.reasoningEffort = null;
|
|
230
|
+
|
|
231
|
+
if (parsedFallback !== undefined) payload.fallback_models = parsedFallback;
|
|
232
|
+
else payload.fallback_models = null;
|
|
233
|
+
|
|
234
|
+
saveMutation.mutate(payload as AgentConfig);
|
|
194
235
|
};
|
|
195
236
|
|
|
196
237
|
const currentAgentConfig = config?.agents?.[agentName];
|
|
@@ -284,22 +325,23 @@ export function AgentConfigForm({
|
|
|
284
325
|
name="model"
|
|
285
326
|
control={control}
|
|
286
327
|
rules={{ required: 'Please select a model' }}
|
|
287
|
-
render={({ field, fieldState }) =>
|
|
328
|
+
render={({ field, fieldState }) => {
|
|
329
|
+
return (
|
|
288
330
|
<>
|
|
289
331
|
<div id="model-selector">
|
|
290
332
|
<AgentModelSelector
|
|
291
333
|
value={field.value}
|
|
292
|
-
onValueChange={field.onChange}
|
|
334
|
+
onValueChange={(val) => { field.onChange(val); }}
|
|
293
335
|
placeholder="Select a model..."
|
|
294
336
|
/>
|
|
295
337
|
</div>
|
|
296
338
|
{fieldState.error && (
|
|
297
|
-
<p className="text-xs text-red-600 dark:text-red-400"
|
|
339
|
+
<p role="alert" className="text-xs text-red-600 dark:text-red-400">
|
|
298
340
|
{fieldState.error.message}
|
|
299
341
|
</p>
|
|
300
342
|
)}
|
|
301
343
|
</>
|
|
302
|
-
)}
|
|
344
|
+
)}}
|
|
303
345
|
/>
|
|
304
346
|
<p className="text-xs text-zinc-500 dark:text-zinc-400">
|
|
305
347
|
The AI model used for this agent.
|
|
@@ -334,6 +376,33 @@ export function AgentConfigForm({
|
|
|
334
376
|
</p>
|
|
335
377
|
</div>
|
|
336
378
|
|
|
379
|
+
<div className="space-y-2">
|
|
380
|
+
<label htmlFor="reasoning-effort-selector" className="text-sm font-medium text-zinc-900 dark:text-zinc-100">
|
|
381
|
+
Reasoning Effort
|
|
382
|
+
</label>
|
|
383
|
+
<Controller
|
|
384
|
+
name="reasoningEffort"
|
|
385
|
+
control={control}
|
|
386
|
+
render={({ field }) => (
|
|
387
|
+
<select
|
|
388
|
+
id="reasoning-effort-selector"
|
|
389
|
+
value={field.value}
|
|
390
|
+
onChange={(e) => field.onChange(e.target.value)}
|
|
391
|
+
className="w-full rounded-lg border border-zinc-200 bg-white px-3 py-2 text-sm dark:border-zinc-800 dark:bg-zinc-950"
|
|
392
|
+
>
|
|
393
|
+
<option value="">Not set</option>
|
|
394
|
+
<option value="high">high</option>
|
|
395
|
+
<option value="medium">medium</option>
|
|
396
|
+
<option value="low">low</option>
|
|
397
|
+
<option value="max">max</option>
|
|
398
|
+
</select>
|
|
399
|
+
)}
|
|
400
|
+
/>
|
|
401
|
+
<p className="text-xs text-zinc-500 dark:text-zinc-400">
|
|
402
|
+
Controls the reasoning effort for compatible models like o1 or o3-mini.
|
|
403
|
+
</p>
|
|
404
|
+
</div>
|
|
405
|
+
|
|
337
406
|
<div className="space-y-3">
|
|
338
407
|
<div className="flex items-center justify-between">
|
|
339
408
|
<label htmlFor="temperature-slider" className="text-sm font-medium text-zinc-900 dark:text-zinc-100">
|
|
@@ -464,6 +533,29 @@ export function AgentConfigForm({
|
|
|
464
533
|
</p>
|
|
465
534
|
</div>
|
|
466
535
|
|
|
536
|
+
<div className="space-y-2">
|
|
537
|
+
<label htmlFor="fallback-models" className="text-sm font-medium text-zinc-900 dark:text-zinc-100">
|
|
538
|
+
Fallback Models (JSON)
|
|
539
|
+
</label>
|
|
540
|
+
<Controller
|
|
541
|
+
name="fallback_models"
|
|
542
|
+
control={control}
|
|
543
|
+
render={({ field }) => (
|
|
544
|
+
<textarea
|
|
545
|
+
id="fallback-models"
|
|
546
|
+
value={field.value}
|
|
547
|
+
onChange={(e) => field.onChange(e.target.value)}
|
|
548
|
+
rows={4}
|
|
549
|
+
className="w-full rounded-lg border border-zinc-200 bg-white px-3 py-2 text-sm font-mono resize-none dark:border-zinc-800 dark:bg-zinc-950"
|
|
550
|
+
placeholder='["claude-3-opus-20240229", "gpt-4-turbo"]'
|
|
551
|
+
/>
|
|
552
|
+
)}
|
|
553
|
+
/>
|
|
554
|
+
<p className="text-xs text-zinc-500 dark:text-zinc-400">
|
|
555
|
+
Supply a JSON array of model names or an object with rich fallback parameters to use when the primary model fails.
|
|
556
|
+
</p>
|
|
557
|
+
</div>
|
|
558
|
+
|
|
467
559
|
<div className="flex items-center justify-end gap-3 pt-2">
|
|
468
560
|
<button
|
|
469
561
|
type="submit"
|
|
@@ -51,6 +51,10 @@ describe('GeneralSettingsForm', () => {
|
|
|
51
51
|
sessionsRefreshIntervalMs: 5000,
|
|
52
52
|
openEditorTargetMode: 'remote',
|
|
53
53
|
},
|
|
54
|
+
team_mode: {
|
|
55
|
+
enabled: false,
|
|
56
|
+
other_field: 'unmodified',
|
|
57
|
+
}
|
|
54
58
|
}), {
|
|
55
59
|
status: 200,
|
|
56
60
|
headers: { 'Content-Type': 'application/json' },
|
|
@@ -69,6 +73,9 @@ describe('GeneralSettingsForm', () => {
|
|
|
69
73
|
|
|
70
74
|
const select = await screen.findByLabelText('Remote open target');
|
|
71
75
|
await user.selectOptions(select, 'hub');
|
|
76
|
+
const toggle = await screen.findByRole('checkbox', { name: /enable team mode/i });
|
|
77
|
+
await user.click(toggle);
|
|
78
|
+
|
|
72
79
|
await user.click(screen.getByRole('button', { name: /save settings/i }));
|
|
73
80
|
|
|
74
81
|
await waitFor(() => {
|
|
@@ -86,6 +93,10 @@ describe('GeneralSettingsForm', () => {
|
|
|
86
93
|
sessionsRefreshIntervalMs: 5000,
|
|
87
94
|
openEditorTargetMode: 'hub',
|
|
88
95
|
},
|
|
96
|
+
team_mode: {
|
|
97
|
+
enabled: true,
|
|
98
|
+
other_field: 'unmodified',
|
|
99
|
+
}
|
|
89
100
|
});
|
|
90
101
|
});
|
|
91
102
|
});
|
|
@@ -10,6 +10,7 @@ interface GeneralSettingsFormData {
|
|
|
10
10
|
stickyBusyDelaySeconds: number;
|
|
11
11
|
sessionsRefreshIntervalSeconds: number;
|
|
12
12
|
openEditorTargetMode: OpenEditorTargetMode;
|
|
13
|
+
teamModeEnabled: boolean;
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
interface VibepulseConfig {
|
|
@@ -18,8 +19,14 @@ interface VibepulseConfig {
|
|
|
18
19
|
openEditorTargetMode?: OpenEditorTargetMode;
|
|
19
20
|
}
|
|
20
21
|
|
|
22
|
+
interface TeamModeConfig {
|
|
23
|
+
enabled?: boolean;
|
|
24
|
+
[key: string]: unknown;
|
|
25
|
+
}
|
|
26
|
+
|
|
21
27
|
interface ConfigResponse {
|
|
22
28
|
vibepulse?: VibepulseConfig;
|
|
29
|
+
team_mode?: TeamModeConfig;
|
|
23
30
|
[key: string]: unknown;
|
|
24
31
|
}
|
|
25
32
|
|
|
@@ -48,7 +55,8 @@ export function GeneralSettingsForm() {
|
|
|
48
55
|
defaultValues: {
|
|
49
56
|
stickyBusyDelaySeconds: 1,
|
|
50
57
|
sessionsRefreshIntervalSeconds: 5,
|
|
51
|
-
openEditorTargetMode: 'remote'
|
|
58
|
+
openEditorTargetMode: 'remote',
|
|
59
|
+
teamModeEnabled: false,
|
|
52
60
|
}
|
|
53
61
|
});
|
|
54
62
|
|
|
@@ -61,7 +69,8 @@ export function GeneralSettingsForm() {
|
|
|
61
69
|
sessionsRefreshIntervalSeconds: typeof config.vibepulse?.sessionsRefreshIntervalMs === 'number'
|
|
62
70
|
? Math.round(config.vibepulse.sessionsRefreshIntervalMs / 1000)
|
|
63
71
|
: 5,
|
|
64
|
-
openEditorTargetMode: config.vibepulse?.openEditorTargetMode === 'hub' ? 'hub' : 'remote'
|
|
72
|
+
openEditorTargetMode: config.vibepulse?.openEditorTargetMode === 'hub' ? 'hub' : 'remote',
|
|
73
|
+
teamModeEnabled: config.team_mode?.enabled ?? false,
|
|
65
74
|
});
|
|
66
75
|
}
|
|
67
76
|
}, [config, reset]);
|
|
@@ -80,9 +89,14 @@ export function GeneralSettingsForm() {
|
|
|
80
89
|
headers: { 'Content-Type': 'application/json' },
|
|
81
90
|
body: JSON.stringify({
|
|
82
91
|
vibepulse: {
|
|
92
|
+
...config?.vibepulse,
|
|
83
93
|
stickyBusyDelayMs: data.stickyBusyDelaySeconds * 1000,
|
|
84
94
|
sessionsRefreshIntervalMs: data.sessionsRefreshIntervalSeconds * 1000,
|
|
85
95
|
openEditorTargetMode: data.openEditorTargetMode
|
|
96
|
+
},
|
|
97
|
+
team_mode: {
|
|
98
|
+
...(config?.team_mode ?? {}),
|
|
99
|
+
enabled: data.teamModeEnabled
|
|
86
100
|
}
|
|
87
101
|
})
|
|
88
102
|
});
|
|
@@ -266,6 +280,31 @@ export function GeneralSettingsForm() {
|
|
|
266
280
|
How often the board polls the server for session updates. Lower values provide more real-time feedback but increase server load. Default is 5 seconds.
|
|
267
281
|
</p>
|
|
268
282
|
</div>
|
|
283
|
+
|
|
284
|
+
<div className="space-y-3 border-t border-zinc-100 pt-6 dark:border-zinc-800">
|
|
285
|
+
<div className="flex items-center gap-3">
|
|
286
|
+
<Controller
|
|
287
|
+
name="teamModeEnabled"
|
|
288
|
+
control={control}
|
|
289
|
+
render={({ field }) => (
|
|
290
|
+
<input
|
|
291
|
+
id="team-mode-enabled"
|
|
292
|
+
type="checkbox"
|
|
293
|
+
checked={field.value}
|
|
294
|
+
onChange={(e) => field.onChange(e.target.checked)}
|
|
295
|
+
className="h-4 w-4 rounded border-zinc-300 text-blue-600 focus:ring-blue-500 dark:border-zinc-700 dark:bg-zinc-900 dark:focus:ring-blue-600 dark:focus:ring-offset-zinc-900"
|
|
296
|
+
aria-label="Enable Team Mode"
|
|
297
|
+
/>
|
|
298
|
+
)}
|
|
299
|
+
/>
|
|
300
|
+
<label htmlFor="team-mode-enabled" className="text-sm font-medium text-zinc-900 dark:text-zinc-100">
|
|
301
|
+
Enable Team Mode
|
|
302
|
+
</label>
|
|
303
|
+
</div>
|
|
304
|
+
<p className="text-xs text-zinc-500 dark:text-zinc-400 pl-7">
|
|
305
|
+
When enabled, team mode allows multiple developers to collaborate via shared agents and a combined workflow inbox. (Requires oh-my-opencode v4.0.0+)
|
|
306
|
+
</p>
|
|
307
|
+
</div>
|
|
269
308
|
</div>
|
|
270
309
|
|
|
271
310
|
<div className="mt-8 flex justify-end border-t border-zinc-100 pt-6 dark:border-zinc-800">
|
|
@@ -98,7 +98,9 @@ export function CategoriesManager({ onSaveSuccess }: CategoriesManagerProps) {
|
|
|
98
98
|
|
|
99
99
|
const handleDeleteCategory = (categoryKey: string) => {
|
|
100
100
|
const currentCategories = config?.categories || {};
|
|
101
|
-
const
|
|
101
|
+
const updatedCategories = Object.fromEntries(
|
|
102
|
+
Object.entries(currentCategories).filter(([key]) => key !== categoryKey)
|
|
103
|
+
);
|
|
102
104
|
saveMutation.mutate(updatedCategories);
|
|
103
105
|
};
|
|
104
106
|
|
package/.next/standalone/src/components/opencode-config/categories/CategoryConfigForm.test.tsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
-
import { render, screen, waitFor } from '@testing-library/react';
|
|
3
|
-
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, beforeAll, afterAll } from 'vitest';
|
|
2
|
+
import { render, screen, waitFor, fireEvent } from '@testing-library/react';
|
|
4
3
|
import { CategoryConfigForm } from './CategoryConfigForm';
|
|
4
|
+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
5
5
|
|
|
6
6
|
const mockFetch = vi.fn<typeof fetch>();
|
|
7
7
|
global.fetch = mockFetch;
|
|
@@ -14,6 +14,16 @@ function jsonResponse(data: unknown): Response {
|
|
|
14
14
|
} as Response;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
beforeAll(() => {
|
|
18
|
+
window.HTMLElement.prototype.hasPointerCapture = vi.fn();
|
|
19
|
+
window.HTMLElement.prototype.scrollIntoView = vi.fn();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
afterAll(() => {
|
|
23
|
+
delete (window.HTMLElement.prototype as any).hasPointerCapture;
|
|
24
|
+
delete (window.HTMLElement.prototype as any).scrollIntoView;
|
|
25
|
+
});
|
|
26
|
+
|
|
17
27
|
describe('CategoryConfigForm', () => {
|
|
18
28
|
let queryClient: QueryClient;
|
|
19
29
|
|
|
@@ -26,6 +36,14 @@ describe('CategoryConfigForm', () => {
|
|
|
26
36
|
vi.clearAllMocks();
|
|
27
37
|
});
|
|
28
38
|
|
|
39
|
+
const renderForm = (props: any = {}) => {
|
|
40
|
+
return render(
|
|
41
|
+
<QueryClientProvider client={queryClient}>
|
|
42
|
+
<CategoryConfigForm categoryName="quick" onSave={() => {}} onCancel={() => {}} {...props} />
|
|
43
|
+
</QueryClientProvider>
|
|
44
|
+
);
|
|
45
|
+
};
|
|
46
|
+
|
|
29
47
|
it('shows the upstream quick fallback chain when no model is configured', async () => {
|
|
30
48
|
mockFetch.mockResolvedValueOnce(
|
|
31
49
|
jsonResponse({
|
|
@@ -34,11 +52,7 @@ describe('CategoryConfigForm', () => {
|
|
|
34
52
|
})
|
|
35
53
|
);
|
|
36
54
|
|
|
37
|
-
|
|
38
|
-
<QueryClientProvider client={queryClient}>
|
|
39
|
-
<CategoryConfigForm categoryName="quick" onSave={() => {}} onCancel={() => {}} />
|
|
40
|
-
</QueryClientProvider>
|
|
41
|
-
);
|
|
55
|
+
renderForm();
|
|
42
56
|
|
|
43
57
|
await waitFor(() => {
|
|
44
58
|
expect(screen.getByText(/using built-in fallback chain/i)).toBeInTheDocument();
|
|
@@ -46,4 +60,88 @@ describe('CategoryConfigForm', () => {
|
|
|
46
60
|
|
|
47
61
|
expect(screen.getByText('openai/gpt-5.4-mini')).toBeInTheDocument();
|
|
48
62
|
});
|
|
63
|
+
|
|
64
|
+
it('allows saving new reasoningEffort and fallback_models', async () => {
|
|
65
|
+
mockFetch.mockResolvedValueOnce(
|
|
66
|
+
jsonResponse({
|
|
67
|
+
models: ['test-model'],
|
|
68
|
+
source: 'test',
|
|
69
|
+
})
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
const handleSave = vi.fn();
|
|
73
|
+
renderForm({ onSave: handleSave });
|
|
74
|
+
|
|
75
|
+
const effortSelect = screen.getByLabelText(/reasoning effort/i);
|
|
76
|
+
fireEvent.change(effortSelect, { target: { value: 'high' } });
|
|
77
|
+
|
|
78
|
+
const fallbackArea = screen.getByLabelText(/fallback models \(json\)/i);
|
|
79
|
+
fireEvent.change(fallbackArea, { target: { value: '["test-backup"]' } });
|
|
80
|
+
|
|
81
|
+
const submitBtn = screen.getByText(/save changes/i);
|
|
82
|
+
fireEvent.click(submitBtn);
|
|
83
|
+
|
|
84
|
+
await waitFor(() => {
|
|
85
|
+
expect(handleSave).toHaveBeenCalledWith(expect.objectContaining({
|
|
86
|
+
reasoningEffort: 'high',
|
|
87
|
+
fallback_models: ['test-backup']
|
|
88
|
+
}));
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('sends explicit null when fallback_models is cleared and reasoningEffort is not set', async () => {
|
|
93
|
+
mockFetch.mockResolvedValueOnce(jsonResponse({
|
|
94
|
+
models: ['test-model'],
|
|
95
|
+
source: 'test'
|
|
96
|
+
}));
|
|
97
|
+
|
|
98
|
+
const handleSave = vi.fn();
|
|
99
|
+
renderForm({
|
|
100
|
+
onSave: handleSave,
|
|
101
|
+
initialConfig: {
|
|
102
|
+
reasoningEffort: 'high',
|
|
103
|
+
fallback_models: ['test-backup']
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
const fallbackArea = screen.getByLabelText(/fallback models \(json\)/i);
|
|
108
|
+
fireEvent.change(fallbackArea, { target: { value: '' } });
|
|
109
|
+
|
|
110
|
+
const effortSelect = screen.getByLabelText(/reasoning effort/i);
|
|
111
|
+
fireEvent.change(effortSelect, { target: { value: '' } });
|
|
112
|
+
|
|
113
|
+
const submitBtn = screen.getByText(/save changes/i);
|
|
114
|
+
fireEvent.click(submitBtn);
|
|
115
|
+
|
|
116
|
+
await waitFor(() => {
|
|
117
|
+
expect(handleSave).toHaveBeenCalledWith(expect.objectContaining({
|
|
118
|
+
reasoningEffort: null,
|
|
119
|
+
fallback_models: null
|
|
120
|
+
}));
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('shows error toast on invalid JSON in fallback_models', async () => {
|
|
125
|
+
mockFetch.mockResolvedValueOnce(
|
|
126
|
+
jsonResponse({
|
|
127
|
+
models: ['test-model'],
|
|
128
|
+
source: 'test',
|
|
129
|
+
})
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
const handleSave = vi.fn();
|
|
133
|
+
renderForm({ onSave: handleSave });
|
|
134
|
+
|
|
135
|
+
const fallbackArea = screen.getByLabelText(/fallback models \(json\)/i);
|
|
136
|
+
fireEvent.change(fallbackArea, { target: { value: '["missing-bracket' } });
|
|
137
|
+
|
|
138
|
+
const submitBtn = screen.getByText(/save changes/i);
|
|
139
|
+
fireEvent.click(submitBtn);
|
|
140
|
+
|
|
141
|
+
await waitFor(() => {
|
|
142
|
+
expect(screen.getByText(/invalid json in fallback_models/i)).toBeInTheDocument();
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
expect(handleSave).not.toHaveBeenCalled();
|
|
146
|
+
});
|
|
49
147
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import * as React from 'react';
|
|
4
|
-
import { useForm, Controller } from 'react-hook-form';
|
|
4
|
+
import { useForm, Controller, useWatch } from 'react-hook-form';
|
|
5
5
|
import { Check, AlertCircle, Loader2, AlertTriangle } from 'lucide-react';
|
|
6
6
|
import { useQuery } from '@tanstack/react-query';
|
|
7
7
|
import { AgentModelSelector } from '../AgentModelSelector';
|
|
@@ -25,6 +25,9 @@ interface CategoryConfigFormData {
|
|
|
25
25
|
temperature: number;
|
|
26
26
|
top_p: number;
|
|
27
27
|
prompt_append: string;
|
|
28
|
+
reasoningEffort: string;
|
|
29
|
+
fallbackModelsObj?: unknown;
|
|
30
|
+
fallback_models: string;
|
|
28
31
|
}
|
|
29
32
|
|
|
30
33
|
interface CategoryConfigFormProps {
|
|
@@ -59,7 +62,6 @@ export function CategoryConfigForm({
|
|
|
59
62
|
const {
|
|
60
63
|
control,
|
|
61
64
|
handleSubmit,
|
|
62
|
-
watch,
|
|
63
65
|
formState: { isSubmitting },
|
|
64
66
|
} = useForm<CategoryConfigFormData>({
|
|
65
67
|
defaultValues: {
|
|
@@ -68,6 +70,11 @@ export function CategoryConfigForm({
|
|
|
68
70
|
temperature: initialConfig?.temperature ?? 0.7,
|
|
69
71
|
top_p: initialConfig?.top_p ?? 1,
|
|
70
72
|
prompt_append: initialConfig?.prompt_append || '',
|
|
73
|
+
reasoningEffort: initialConfig?.reasoningEffort || '',
|
|
74
|
+
fallbackModelsObj: initialConfig?.fallback_models,
|
|
75
|
+
fallback_models: initialConfig?.fallback_models
|
|
76
|
+
? JSON.stringify(initialConfig.fallback_models, null, 2)
|
|
77
|
+
: '',
|
|
71
78
|
},
|
|
72
79
|
});
|
|
73
80
|
|
|
@@ -109,7 +116,7 @@ export function CategoryConfigForm({
|
|
|
109
116
|
[modelsData]
|
|
110
117
|
);
|
|
111
118
|
|
|
112
|
-
const watchedModel =
|
|
119
|
+
const watchedModel = useWatch({ control, name: 'model' });
|
|
113
120
|
const isModelInvalid = watchedModel && availableModels.size > 0 && !availableModels.has(watchedModel);
|
|
114
121
|
const isModelMissing = !watchedModel;
|
|
115
122
|
const fallbackChain = CATEGORY_FALLBACK_CHAINS[categoryName];
|
|
@@ -125,15 +132,35 @@ export function CategoryConfigForm({
|
|
|
125
132
|
const temperature = Math.max(0, Math.min(2, data.temperature));
|
|
126
133
|
const top_p = Math.max(0, Math.min(1, data.top_p));
|
|
127
134
|
|
|
128
|
-
|
|
135
|
+
let parsedFallback = undefined;
|
|
136
|
+
if (data.fallback_models.trim() !== '') {
|
|
137
|
+
try {
|
|
138
|
+
parsedFallback = JSON.parse(data.fallback_models);
|
|
139
|
+
} catch {
|
|
140
|
+
setToast({ type: 'error', message: 'Invalid JSON in fallback_models' });
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
type CategoryConfigPayload = Omit<CategoryConfig, 'reasoningEffort' | 'fallback_models'> & {
|
|
146
|
+
reasoningEffort?: CategoryConfig['reasoningEffort'] | null;
|
|
147
|
+
fallback_models?: CategoryConfig['fallback_models'] | null;
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
const config: CategoryConfigPayload = {
|
|
129
151
|
model: data.model || undefined,
|
|
130
152
|
variant: data.variant || undefined,
|
|
131
153
|
temperature,
|
|
132
154
|
top_p,
|
|
133
155
|
prompt_append: data.prompt_append || undefined,
|
|
134
156
|
};
|
|
157
|
+
if (data.reasoningEffort) config.reasoningEffort = data.reasoningEffort as CategoryConfig['reasoningEffort'];
|
|
158
|
+
else config.reasoningEffort = null;
|
|
159
|
+
|
|
160
|
+
if (parsedFallback !== undefined) config.fallback_models = parsedFallback;
|
|
161
|
+
else config.fallback_models = null;
|
|
135
162
|
|
|
136
|
-
onSave(config);
|
|
163
|
+
onSave(config as CategoryConfig);
|
|
137
164
|
setToast({ type: 'success', message: 'Configuration saved successfully' });
|
|
138
165
|
};
|
|
139
166
|
|
|
@@ -267,6 +294,33 @@ export function CategoryConfigForm({
|
|
|
267
294
|
</p>
|
|
268
295
|
</div>
|
|
269
296
|
|
|
297
|
+
<div className="space-y-2">
|
|
298
|
+
<label htmlFor="reasoning-effort-selector" className="text-sm font-medium text-zinc-900 dark:text-zinc-100">
|
|
299
|
+
Reasoning Effort
|
|
300
|
+
</label>
|
|
301
|
+
<Controller
|
|
302
|
+
name="reasoningEffort"
|
|
303
|
+
control={control}
|
|
304
|
+
render={({ field }) => (
|
|
305
|
+
<select
|
|
306
|
+
id="reasoning-effort-selector"
|
|
307
|
+
value={field.value}
|
|
308
|
+
onChange={(e) => field.onChange(e.target.value)}
|
|
309
|
+
className="w-full rounded-lg border border-zinc-200 bg-white px-3 py-2 text-sm dark:border-zinc-800 dark:bg-zinc-950"
|
|
310
|
+
>
|
|
311
|
+
<option value="">Not set</option>
|
|
312
|
+
<option value="high">high</option>
|
|
313
|
+
<option value="medium">medium</option>
|
|
314
|
+
<option value="low">low</option>
|
|
315
|
+
<option value="max">max</option>
|
|
316
|
+
</select>
|
|
317
|
+
)}
|
|
318
|
+
/>
|
|
319
|
+
<p className="text-xs text-zinc-500 dark:text-zinc-400">
|
|
320
|
+
Controls the reasoning effort for compatible models like o1 or o3-mini.
|
|
321
|
+
</p>
|
|
322
|
+
</div>
|
|
323
|
+
|
|
270
324
|
<div className="space-y-3">
|
|
271
325
|
<div className="flex items-center justify-between">
|
|
272
326
|
<label htmlFor="temperature-slider" className="text-sm font-medium text-zinc-900 dark:text-zinc-100">
|
|
@@ -427,6 +481,29 @@ export function CategoryConfigForm({
|
|
|
427
481
|
</p>
|
|
428
482
|
</div>
|
|
429
483
|
|
|
484
|
+
<div className="space-y-2">
|
|
485
|
+
<label htmlFor="fallback-models" className="text-sm font-medium text-zinc-900 dark:text-zinc-100">
|
|
486
|
+
Fallback Models (JSON)
|
|
487
|
+
</label>
|
|
488
|
+
<Controller
|
|
489
|
+
name="fallback_models"
|
|
490
|
+
control={control}
|
|
491
|
+
render={({ field }) => (
|
|
492
|
+
<textarea
|
|
493
|
+
id="fallback-models"
|
|
494
|
+
value={field.value}
|
|
495
|
+
onChange={(e) => field.onChange(e.target.value)}
|
|
496
|
+
rows={4}
|
|
497
|
+
className="w-full rounded-lg border border-zinc-200 bg-white px-3 py-2 text-sm font-mono resize-none dark:border-zinc-800 dark:bg-zinc-950"
|
|
498
|
+
placeholder='["claude-3-opus-20240229", "gpt-4-turbo"]'
|
|
499
|
+
/>
|
|
500
|
+
)}
|
|
501
|
+
/>
|
|
502
|
+
<p className="text-xs text-zinc-500 dark:text-zinc-400">
|
|
503
|
+
Supply a JSON array of model names or an object with rich fallback parameters to use when the primary model fails.
|
|
504
|
+
</p>
|
|
505
|
+
</div>
|
|
506
|
+
|
|
430
507
|
<div className="flex items-center justify-end gap-3 pt-2">
|
|
431
508
|
<button
|
|
432
509
|
type="button"
|
|
@@ -145,47 +145,6 @@ describe('useHostSources', () => {
|
|
|
145
145
|
return { getCurrentValue, rerenderRuntimeRole };
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
-
function renderPairedUseHostSources() {
|
|
149
|
-
let firstValue: ReturnType<typeof useHostSources> | null = null;
|
|
150
|
-
let secondValue: ReturnType<typeof useHostSources> | null = null;
|
|
151
|
-
const render = getRender();
|
|
152
|
-
|
|
153
|
-
render(createElement(
|
|
154
|
-
QueryClientProvider,
|
|
155
|
-
{ client: queryClient },
|
|
156
|
-
createElement('div', null,
|
|
157
|
-
createElement(HookProbe, {
|
|
158
|
-
onChange: (value) => {
|
|
159
|
-
firstValue = value;
|
|
160
|
-
},
|
|
161
|
-
}),
|
|
162
|
-
createElement(HookProbe, {
|
|
163
|
-
onChange: (value) => {
|
|
164
|
-
secondValue = value;
|
|
165
|
-
},
|
|
166
|
-
})
|
|
167
|
-
)
|
|
168
|
-
));
|
|
169
|
-
|
|
170
|
-
const getFirstValue = () => {
|
|
171
|
-
if (!firstValue) {
|
|
172
|
-
throw new Error('First hook value not ready');
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
return firstValue;
|
|
176
|
-
};
|
|
177
|
-
|
|
178
|
-
const getSecondValue = () => {
|
|
179
|
-
if (!secondValue) {
|
|
180
|
-
throw new Error('Second hook value not ready');
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
return secondValue;
|
|
184
|
-
};
|
|
185
|
-
|
|
186
|
-
return { getFirstValue, getSecondValue };
|
|
187
|
-
}
|
|
188
|
-
|
|
189
148
|
it('always includes Local first', async () => {
|
|
190
149
|
mockFetch.mockResolvedValueOnce({
|
|
191
150
|
ok: true,
|