vibepulse 0.2.1 → 0.3.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/sessions/[id]/open-editor/route.js.nft.json +1 -1
- package/.next/server/app/api/node/sessions/route.js +5 -3
- package/.next/server/app/api/node/sessions/route.js.nft.json +1 -1
- package/.next/server/app/api/opencode-config/route.js.nft.json +1 -1
- package/.next/server/app/api/opencode-config/status/route.js.nft.json +1 -1
- package/.next/server/app/api/profiles/[id]/apply/route.js.nft.json +1 -1
- package/.next/server/app/api/profiles/[id]/export/route.js.nft.json +1 -1
- package/.next/server/app/api/profiles/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/profiles/import/route.js.nft.json +1 -1
- 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 +3 -2
- 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 +1 -1
- 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/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]__31d19c5c._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__31d19c5c._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__56690af0._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__56690af0._.js.map +1 -1
- package/.next/server/chunks/[root-of-the-server]__56f5f249._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__56f5f249._.js.map +1 -1
- package/.next/server/chunks/[root-of-the-server]__59175de4._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__59175de4._.js.map +1 -1
- package/.next/server/chunks/[root-of-the-server]__5e0a0e38._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__5e0a0e38._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__64fffc02._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__64fffc02._.js.map +1 -1
- package/.next/server/chunks/[root-of-the-server]__89c5eeab._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__89c5eeab._.js.map +1 -1
- package/.next/server/chunks/[root-of-the-server]__8da6c5a8._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__8da6c5a8._.js.map +1 -1
- package/.next/server/chunks/[root-of-the-server]__98073dd6._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__98073dd6._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__b796d06c._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__b796d06c._.js.map +1 -1
- package/.next/server/chunks/[root-of-the-server]__b7b717eb._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__b7b717eb._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__c2ce5c0f._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__c2ce5c0f._.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]__f441109e._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__f441109e._.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_2edc9589.js +3 -0
- package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_2edc9589.js.map +1 -0
- package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_7f178d4a.js +3 -0
- package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_7f178d4a.js.map +1 -0
- 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_d0c0f338.js +3 -0
- package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_d0c0f338.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 +4 -4
- 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/sessions/[id]/open-editor/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/node/sessions/route.js +5 -3
- package/.next/standalone/.next/server/app/api/node/sessions/route.js.nft.json +1 -1
- 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.nft.json +1 -1
- 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.nft.json +1 -1
- 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.nft.json +1 -1
- 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 +3 -2
- 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 +1 -1
- 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/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]__31d19c5c._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__56690af0._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__56f5f249._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__59175de4._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__5e0a0e38._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__64fffc02._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__89c5eeab._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__8da6c5a8._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__98073dd6._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__b796d06c._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__b7b717eb._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__c2ce5c0f._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__d8e61048._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__f441109e._.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_2edc9589.js +3 -0
- package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_7f178d4a.js +3 -0
- 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_d0c0f338.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 +4 -4
- 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/b3bc362202331708.css +3 -0
- package/.next/standalone/.next/static/chunks/c1294e057d8d4681.js +13 -0
- package/.next/standalone/AGENTS.md +2 -2
- package/.next/standalone/README.md +30 -7
- package/.next/standalone/docs/session-status-detection.md +36 -0
- package/.next/standalone/docs/superpowers/plans/2026-04-05-oh-my-openagent-migration.md +57 -0
- package/.next/standalone/docs/superpowers/specs/2026-04-09-claude-capability-alignment-design.md +39 -0
- package/.next/standalone/package-lock.json +2 -2
- package/.next/standalone/package.json +1 -1
- package/.next/standalone/src/app/api/AGENTS.md +2 -2
- 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/route.test.ts +282 -0
- package/.next/standalone/src/app/api/node/sessions/route.ts +141 -17
- package/.next/standalone/src/app/api/opencode-config/status/route.ts +6 -7
- package/.next/standalone/src/app/api/opencode-events/route.test.ts +3 -1
- package/.next/standalone/src/app/api/sessions/[id]/archive/route.test.ts +101 -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 +92 -0
- package/.next/standalone/src/app/api/sessions/[id]/delete/route.ts +45 -10
- 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/route.test.ts +1889 -107
- package/.next/standalone/src/app/api/sessions/route.ts +365 -981
- package/.next/standalone/src/components/AGENTS.md +2 -2
- package/.next/standalone/src/components/KanbanBoard.test.tsx +307 -1
- package/.next/standalone/src/components/KanbanBoard.tsx +105 -18
- package/.next/standalone/src/components/ProjectCard.test.tsx +416 -2
- package/.next/standalone/src/components/ProjectCard.tsx +238 -86
- package/.next/standalone/src/components/SessionCard.test.tsx +253 -2
- package/.next/standalone/src/components/SessionCard.tsx +182 -76
- package/.next/standalone/src/components/opencode-config/AgentConfigForm.test.tsx +28 -0
- package/.next/standalone/src/components/opencode-config/AgentConfigForm.tsx +9 -9
- package/.next/standalone/src/components/opencode-config/ConfigButton.tsx +4 -4
- package/.next/standalone/src/components/opencode-config/categories/CategoriesList.tsx +10 -8
- package/.next/standalone/src/components/opencode-config/categories/CategoriesManager.test.tsx +29 -1
- package/.next/standalone/src/components/opencode-config/categories/CategoryConfigForm.test.tsx +49 -0
- package/.next/standalone/src/components/opencode-config/categories/CategoryConfigForm.tsx +6 -6
- package/.next/standalone/src/hooks/useOpencodeSync.test.ts +321 -1
- package/.next/standalone/src/hooks/useOpencodeSync.ts +16 -12
- package/.next/standalone/src/index.ts +1 -1
- package/.next/standalone/src/lib/claudeSessionOverrides.test.ts +75 -0
- package/.next/standalone/src/lib/claudeSessionOverrides.ts +169 -0
- package/.next/standalone/src/lib/opencodeConfig.test.ts +53 -4
- package/.next/standalone/src/lib/opencodeConfig.ts +24 -12
- package/.next/standalone/src/lib/profiles/storage.test.ts +38 -1
- package/.next/standalone/src/lib/profiles/storage.ts +17 -17
- 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.ts +723 -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 +1 -9
- package/.next/static/chunks/b3bc362202331708.css +3 -0
- package/.next/static/chunks/c1294e057d8d4681.js +13 -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 +30 -7
- package/package.json +1 -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]__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]__db285678._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__db285678._.js.map +0 -1
- 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]__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]__db285678._.js +0 -3
- package/.next/standalone/.next/static/chunks/7ac19aaef01f4a03.js +0 -13
- package/.next/standalone/.next/static/chunks/f42202943f6742e5.css +0 -3
- package/.next/static/chunks/7ac19aaef01f4a03.js +0 -13
- package/.next/static/chunks/f42202943f6742e5.css +0 -3
- /package/.next/standalone/.next/static/{Fw2R3y-fHX4B2SWxNy_4X → bsWNvgDS7Zp38Yt9q0DUg}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{Fw2R3y-fHX4B2SWxNy_4X → bsWNvgDS7Zp38Yt9q0DUg}/_clientMiddlewareManifest.json +0 -0
- /package/.next/standalone/.next/static/{Fw2R3y-fHX4B2SWxNy_4X → bsWNvgDS7Zp38Yt9q0DUg}/_ssgManifest.js +0 -0
- /package/.next/static/{Fw2R3y-fHX4B2SWxNy_4X → bsWNvgDS7Zp38Yt9q0DUg}/_buildManifest.js +0 -0
- /package/.next/static/{Fw2R3y-fHX4B2SWxNy_4X → bsWNvgDS7Zp38Yt9q0DUg}/_clientMiddlewareManifest.json +0 -0
- /package/.next/static/{Fw2R3y-fHX4B2SWxNy_4X → bsWNvgDS7Zp38Yt9q0DUg}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it } from 'vitest';
|
|
2
|
+
import { mkdtemp, readFile, rm } from 'fs/promises';
|
|
3
|
+
import { tmpdir } from 'os';
|
|
4
|
+
import { join } from 'path';
|
|
5
|
+
|
|
6
|
+
async function withTempHome<T>(fn: (homeDir: string) => Promise<T>): Promise<T> {
|
|
7
|
+
const homeDir = await mkdtemp(join(tmpdir(), 'vibepulse-claude-overrides-'));
|
|
8
|
+
const originalHome = process.env.HOME;
|
|
9
|
+
process.env.HOME = homeDir;
|
|
10
|
+
try {
|
|
11
|
+
return await fn(homeDir);
|
|
12
|
+
} finally {
|
|
13
|
+
if (originalHome === undefined) delete process.env.HOME;
|
|
14
|
+
else process.env.HOME = originalHome;
|
|
15
|
+
await rm(homeDir, { recursive: true, force: true });
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
describe('claudeSessionOverrides', () => {
|
|
20
|
+
it('persists archived and deleted Claude overrides to the local registry file', async () => {
|
|
21
|
+
await withTempHome(async (homeDir) => {
|
|
22
|
+
const mod = await import('./claudeSessionOverrides');
|
|
23
|
+
await mod.markClaudeSessionArchived('session-a', 100);
|
|
24
|
+
await mod.markClaudeSessionDeleted('session-b', 200);
|
|
25
|
+
|
|
26
|
+
const entries = await mod.listClaudeSessionOverrides();
|
|
27
|
+
expect(entries).toEqual(expect.arrayContaining([
|
|
28
|
+
expect.objectContaining({ sessionId: 'session-a', archivedAt: 100 }),
|
|
29
|
+
expect.objectContaining({ sessionId: 'session-b', deletedAt: 200 }),
|
|
30
|
+
]));
|
|
31
|
+
|
|
32
|
+
const content = await readFile(join(homeDir, '.config', 'vibepulse', 'claude-session-overrides.jsonc'), 'utf-8');
|
|
33
|
+
expect(content).toContain('session-a');
|
|
34
|
+
expect(content).toContain('session-b');
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('preserves all entries under concurrent override writes', async () => {
|
|
39
|
+
await withTempHome(async () => {
|
|
40
|
+
const mod = await import('./claudeSessionOverrides');
|
|
41
|
+
|
|
42
|
+
await Promise.all([
|
|
43
|
+
mod.markClaudeSessionArchived('session-a', 100),
|
|
44
|
+
mod.markClaudeSessionDeleted('session-b', 200),
|
|
45
|
+
mod.markClaudeSessionArchived('session-c', 300),
|
|
46
|
+
]);
|
|
47
|
+
|
|
48
|
+
const entries = await mod.listClaudeSessionOverrides();
|
|
49
|
+
expect(entries).toEqual(expect.arrayContaining([
|
|
50
|
+
expect.objectContaining({ sessionId: 'session-a', archivedAt: 100 }),
|
|
51
|
+
expect.objectContaining({ sessionId: 'session-b', deletedAt: 200 }),
|
|
52
|
+
expect.objectContaining({ sessionId: 'session-c', archivedAt: 300 }),
|
|
53
|
+
]));
|
|
54
|
+
expect(entries).toHaveLength(3);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('can clear archived state while preserving deleted state when restoring a Claude session', async () => {
|
|
59
|
+
await withTempHome(async () => {
|
|
60
|
+
const mod = await import('./claudeSessionOverrides');
|
|
61
|
+
await mod.markClaudeSessionArchived('session-a', 100);
|
|
62
|
+
await mod.markClaudeSessionDeleted('session-b', 200);
|
|
63
|
+
await mod.clearClaudeSessionArchived('session-a');
|
|
64
|
+
await mod.clearClaudeSessionArchived('session-b');
|
|
65
|
+
|
|
66
|
+
const entries = await mod.listClaudeSessionOverrides();
|
|
67
|
+
expect(entries).toEqual(expect.arrayContaining([
|
|
68
|
+
expect.objectContaining({ sessionId: 'session-b', deletedAt: 200, restoredAt: expect.any(Number) }),
|
|
69
|
+
]));
|
|
70
|
+
expect(entries).toEqual(expect.arrayContaining([
|
|
71
|
+
expect.objectContaining({ sessionId: 'session-a', restoredAt: expect.any(Number) }),
|
|
72
|
+
]));
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
});
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { existsSync, mkdirSync } from 'fs';
|
|
2
|
+
import { readFile, rename, writeFile } from 'fs/promises';
|
|
3
|
+
import { homedir } from 'os';
|
|
4
|
+
import { join } from 'path';
|
|
5
|
+
import { parse, stringify } from 'comment-json';
|
|
6
|
+
|
|
7
|
+
export const VIBEPULSE_CONFIG_DIR = join(homedir(), '.config', 'vibepulse');
|
|
8
|
+
export const CLAUDE_SESSION_OVERRIDES_PATH = join(VIBEPULSE_CONFIG_DIR, 'claude-session-overrides.jsonc');
|
|
9
|
+
|
|
10
|
+
export interface ClaudeSessionOverrideEntry {
|
|
11
|
+
sessionId: string;
|
|
12
|
+
archivedAt?: number;
|
|
13
|
+
deletedAt?: number;
|
|
14
|
+
restoredAt?: number;
|
|
15
|
+
updatedAt: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface ClaudeSessionOverridesFile {
|
|
19
|
+
version: number;
|
|
20
|
+
sessions: ClaudeSessionOverrideEntry[];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
let claudeOverrideWriteQueue: Promise<void> = Promise.resolve();
|
|
24
|
+
|
|
25
|
+
function ensureConfigDir(): void {
|
|
26
|
+
if (!existsSync(VIBEPULSE_CONFIG_DIR)) {
|
|
27
|
+
mkdirSync(VIBEPULSE_CONFIG_DIR, { recursive: true });
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function defaultOverrides(): ClaudeSessionOverridesFile {
|
|
32
|
+
return {
|
|
33
|
+
version: 1,
|
|
34
|
+
sessions: [],
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function normalizeEntry(entry: unknown): ClaudeSessionOverrideEntry | null {
|
|
39
|
+
if (!entry || typeof entry !== 'object') return null;
|
|
40
|
+
const candidate = entry as Record<string, unknown>;
|
|
41
|
+
if (typeof candidate.sessionId !== 'string' || typeof candidate.updatedAt !== 'number') return null;
|
|
42
|
+
if (candidate.archivedAt !== undefined && typeof candidate.archivedAt !== 'number') return null;
|
|
43
|
+
if (candidate.deletedAt !== undefined && typeof candidate.deletedAt !== 'number') return null;
|
|
44
|
+
if (candidate.restoredAt !== undefined && typeof candidate.restoredAt !== 'number') return null;
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
sessionId: candidate.sessionId,
|
|
48
|
+
updatedAt: candidate.updatedAt,
|
|
49
|
+
...(typeof candidate.archivedAt === 'number' ? { archivedAt: candidate.archivedAt } : {}),
|
|
50
|
+
...(typeof candidate.deletedAt === 'number' ? { deletedAt: candidate.deletedAt } : {}),
|
|
51
|
+
...(typeof candidate.restoredAt === 'number' ? { restoredAt: candidate.restoredAt } : {}),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async function readOverridesFile(): Promise<ClaudeSessionOverridesFile> {
|
|
56
|
+
try {
|
|
57
|
+
ensureConfigDir();
|
|
58
|
+
if (!existsSync(CLAUDE_SESSION_OVERRIDES_PATH)) {
|
|
59
|
+
const initial = defaultOverrides();
|
|
60
|
+
await writeOverridesFile(initial);
|
|
61
|
+
return initial;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const raw = await readFile(CLAUDE_SESSION_OVERRIDES_PATH, 'utf-8');
|
|
65
|
+
const parsed = parse(raw, null, false) as unknown;
|
|
66
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
67
|
+
return defaultOverrides();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const file = parsed as Record<string, unknown>;
|
|
71
|
+
const sessions = Array.isArray(file.sessions)
|
|
72
|
+
? file.sessions.map(normalizeEntry).filter((entry): entry is ClaudeSessionOverrideEntry => entry !== null)
|
|
73
|
+
: [];
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
version: typeof file.version === 'number' ? file.version : 1,
|
|
77
|
+
sessions,
|
|
78
|
+
};
|
|
79
|
+
} catch {
|
|
80
|
+
return defaultOverrides();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async function writeOverridesFile(file: ClaudeSessionOverridesFile): Promise<void> {
|
|
85
|
+
ensureConfigDir();
|
|
86
|
+
const tempPath = `${CLAUDE_SESSION_OVERRIDES_PATH}.tmp`;
|
|
87
|
+
await writeFile(tempPath, stringify(file, null, 2), 'utf-8');
|
|
88
|
+
await rename(tempPath, CLAUDE_SESSION_OVERRIDES_PATH);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export async function listClaudeSessionOverrides(): Promise<ClaudeSessionOverrideEntry[]> {
|
|
92
|
+
const file = await readOverridesFile();
|
|
93
|
+
return file.sessions;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export async function getClaudeSessionOverride(sessionId: string): Promise<ClaudeSessionOverrideEntry | null> {
|
|
97
|
+
const file = await readOverridesFile();
|
|
98
|
+
return file.sessions.find((entry) => entry.sessionId === sessionId) ?? null;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async function upsertClaudeSessionOverride(
|
|
102
|
+
sessionId: string,
|
|
103
|
+
mutate: (current: ClaudeSessionOverrideEntry | null, now: number) => ClaudeSessionOverrideEntry | null,
|
|
104
|
+
): Promise<void> {
|
|
105
|
+
const run = async () => {
|
|
106
|
+
const file = await readOverridesFile();
|
|
107
|
+
const now = Date.now();
|
|
108
|
+
const current = file.sessions.find((entry) => entry.sessionId === sessionId) ?? null;
|
|
109
|
+
const next = mutate(current, now);
|
|
110
|
+
const withoutCurrent = file.sessions.filter((entry) => entry.sessionId !== sessionId);
|
|
111
|
+
file.sessions = next ? [...withoutCurrent, next] : withoutCurrent;
|
|
112
|
+
await writeOverridesFile(file);
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const queued = claudeOverrideWriteQueue.then(run, run);
|
|
116
|
+
claudeOverrideWriteQueue = queued.then(() => undefined, () => undefined);
|
|
117
|
+
await queued;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export async function markClaudeSessionArchived(sessionId: string, archivedAt: number = Date.now()): Promise<void> {
|
|
121
|
+
await upsertClaudeSessionOverride(sessionId, (current, now) => ({
|
|
122
|
+
sessionId,
|
|
123
|
+
archivedAt,
|
|
124
|
+
deletedAt: current?.deletedAt,
|
|
125
|
+
restoredAt: undefined,
|
|
126
|
+
updatedAt: now,
|
|
127
|
+
}));
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export async function markClaudeSessionDeleted(sessionId: string, deletedAt: number = Date.now()): Promise<void> {
|
|
131
|
+
await upsertClaudeSessionOverride(sessionId, (_current, now) => ({
|
|
132
|
+
sessionId,
|
|
133
|
+
deletedAt,
|
|
134
|
+
restoredAt: undefined,
|
|
135
|
+
updatedAt: now,
|
|
136
|
+
}));
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export async function clearClaudeSessionDeleted(sessionId: string): Promise<void> {
|
|
140
|
+
await upsertClaudeSessionOverride(sessionId, (current, now) => {
|
|
141
|
+
if (!current) return null;
|
|
142
|
+
if (current.archivedAt === undefined) return null;
|
|
143
|
+
return {
|
|
144
|
+
sessionId,
|
|
145
|
+
archivedAt: current.archivedAt,
|
|
146
|
+
restoredAt: current.restoredAt,
|
|
147
|
+
updatedAt: now,
|
|
148
|
+
};
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export async function clearClaudeSessionArchived(sessionId: string): Promise<void> {
|
|
153
|
+
await upsertClaudeSessionOverride(sessionId, (current, now) => {
|
|
154
|
+
if (!current) return null;
|
|
155
|
+
if (current.deletedAt !== undefined) {
|
|
156
|
+
return {
|
|
157
|
+
sessionId,
|
|
158
|
+
deletedAt: current.deletedAt,
|
|
159
|
+
restoredAt: now,
|
|
160
|
+
updatedAt: now,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
return {
|
|
164
|
+
sessionId,
|
|
165
|
+
restoredAt: now,
|
|
166
|
+
updatedAt: now,
|
|
167
|
+
};
|
|
168
|
+
});
|
|
169
|
+
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
-
import { normalizeVibePulseConfig, readConfig, writeConfig } from './opencodeConfig';
|
|
3
|
-
import { writeFile, unlink, mkdir } from 'fs/promises';
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
2
|
+
import { OH_MY_OPENAGENT_CONFIG_SCHEMA, normalizeVibePulseConfig, readConfig, writeConfig } from './opencodeConfig';
|
|
3
|
+
import { writeFile, unlink, mkdir, mkdtemp, rm } from 'fs/promises';
|
|
4
4
|
import { existsSync } from 'fs';
|
|
5
5
|
import { join } from 'path';
|
|
6
6
|
import { tmpdir } from 'os';
|
|
7
7
|
|
|
8
8
|
const TEST_CONFIG_DIR = join(tmpdir(), 'vibepulse-test-' + Date.now());
|
|
9
|
-
const TEST_CONFIG_PATH = join(TEST_CONFIG_DIR, 'oh-my-
|
|
9
|
+
const TEST_CONFIG_PATH = join(TEST_CONFIG_DIR, 'oh-my-openagent.jsonc');
|
|
10
10
|
|
|
11
11
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
12
12
|
return typeof value === 'object' && value !== null;
|
|
@@ -96,5 +96,54 @@ describe('opencodeConfig', () => {
|
|
|
96
96
|
openEditorTargetMode: 'hub',
|
|
97
97
|
});
|
|
98
98
|
});
|
|
99
|
+
|
|
100
|
+
it('injects the canonical schema when writing the default config path', async () => {
|
|
101
|
+
vi.resetModules();
|
|
102
|
+
const testHomeDir = await mkdtemp(join(tmpdir(), 'vibepulse-home-'));
|
|
103
|
+
const originalHome = process.env.HOME;
|
|
104
|
+
|
|
105
|
+
process.env.HOME = testHomeDir;
|
|
106
|
+
|
|
107
|
+
try {
|
|
108
|
+
const { CONFIG_PATH: defaultConfigPath, readConfig: readDefaultConfig, writeConfig: writeDefaultConfig } = await import('./opencodeConfig');
|
|
109
|
+
|
|
110
|
+
await writeDefaultConfig({ agents: { sisyphus: { model: 'claude' } } });
|
|
111
|
+
|
|
112
|
+
const persisted = await readDefaultConfig(defaultConfigPath);
|
|
113
|
+
|
|
114
|
+
expect(persisted.$schema).toBe(OH_MY_OPENAGENT_CONFIG_SCHEMA);
|
|
115
|
+
} finally {
|
|
116
|
+
process.env.HOME = originalHome;
|
|
117
|
+
await rm(testHomeDir, { recursive: true, force: true });
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('detects and reads the legacy default config when the new file is absent', async () => {
|
|
122
|
+
vi.resetModules();
|
|
123
|
+
const testHomeDir = await mkdtemp(join(tmpdir(), 'vibepulse-home-'));
|
|
124
|
+
const originalHome = process.env.HOME;
|
|
125
|
+
|
|
126
|
+
process.env.HOME = testHomeDir;
|
|
127
|
+
|
|
128
|
+
try {
|
|
129
|
+
const {
|
|
130
|
+
LEGACY_CONFIG_PATH: legacyConfigPath,
|
|
131
|
+
detectConfig: detectDefaultConfig,
|
|
132
|
+
readConfig: readDefaultConfig,
|
|
133
|
+
} = await import('./opencodeConfig');
|
|
134
|
+
|
|
135
|
+
await mkdir(join(testHomeDir, '.config', 'opencode'), { recursive: true });
|
|
136
|
+
await writeFile(legacyConfigPath, '{"agents":{"sisyphus":{"model":"claude"}}}');
|
|
137
|
+
|
|
138
|
+
expect(detectDefaultConfig()).toBe(true);
|
|
139
|
+
|
|
140
|
+
const config = await readDefaultConfig();
|
|
141
|
+
|
|
142
|
+
expect(config.agents?.sisyphus).toEqual({ model: 'claude' });
|
|
143
|
+
} finally {
|
|
144
|
+
process.env.HOME = originalHome;
|
|
145
|
+
await rm(testHomeDir, { recursive: true, force: true });
|
|
146
|
+
}
|
|
147
|
+
});
|
|
99
148
|
});
|
|
100
149
|
});
|
|
@@ -3,19 +3,15 @@ import { existsSync, mkdirSync } from 'fs';
|
|
|
3
3
|
import { join } from 'path';
|
|
4
4
|
import { homedir } from 'os';
|
|
5
5
|
import { parse, stringify } from 'comment-json';
|
|
6
|
-
import type { OpenEditorTargetMode, VibePulseConfig } from '@/types/opencodeConfig';
|
|
6
|
+
import type { OhMyOpenAgentConfig, OpenEditorTargetMode, VibePulseConfig } from '@/types/opencodeConfig';
|
|
7
7
|
|
|
8
8
|
export const CONFIG_DIR = join(homedir(), '.config', 'opencode');
|
|
9
|
-
export const CONFIG_PATH = join(CONFIG_DIR, 'oh-my-
|
|
10
|
-
export const
|
|
9
|
+
export const CONFIG_PATH = join(CONFIG_DIR, 'oh-my-openagent.jsonc');
|
|
10
|
+
export const LEGACY_CONFIG_PATH = join(CONFIG_DIR, 'oh-my-opencode.jsonc');
|
|
11
|
+
export const OH_MY_OPENAGENT_CONFIG_SCHEMA = 'https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/v3.15.2/assets/oh-my-opencode.schema.json';
|
|
11
12
|
export const DEFAULT_OPEN_EDITOR_TARGET_MODE: OpenEditorTargetMode = 'remote';
|
|
12
13
|
|
|
13
|
-
export type OpenCodeConfig =
|
|
14
|
-
$schema?: string;
|
|
15
|
-
agents?: Record<string, unknown>;
|
|
16
|
-
vibepulse?: VibePulseConfig;
|
|
17
|
-
[key: string]: unknown;
|
|
18
|
-
};
|
|
14
|
+
export type OpenCodeConfig = OhMyOpenAgentConfig;
|
|
19
15
|
|
|
20
16
|
export function normalizeOpenEditorTargetMode(value: unknown): OpenEditorTargetMode {
|
|
21
17
|
return value === 'hub' ? 'hub' : DEFAULT_OPEN_EDITOR_TARGET_MODE;
|
|
@@ -32,9 +28,25 @@ export function normalizeVibePulseConfig(value: unknown): VibePulseConfig {
|
|
|
32
28
|
};
|
|
33
29
|
}
|
|
34
30
|
|
|
31
|
+
export function resolveConfigPath(configPath: string = CONFIG_PATH): string {
|
|
32
|
+
if (configPath !== CONFIG_PATH) {
|
|
33
|
+
return configPath;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (existsSync(CONFIG_PATH)) {
|
|
37
|
+
return CONFIG_PATH;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (existsSync(LEGACY_CONFIG_PATH)) {
|
|
41
|
+
return LEGACY_CONFIG_PATH;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return CONFIG_PATH;
|
|
45
|
+
}
|
|
46
|
+
|
|
35
47
|
export function detectConfig(configPath: string = CONFIG_PATH): boolean {
|
|
36
48
|
try {
|
|
37
|
-
return existsSync(configPath);
|
|
49
|
+
return existsSync(resolveConfigPath(configPath));
|
|
38
50
|
} catch {
|
|
39
51
|
return false;
|
|
40
52
|
}
|
|
@@ -42,7 +54,7 @@ export function detectConfig(configPath: string = CONFIG_PATH): boolean {
|
|
|
42
54
|
|
|
43
55
|
export async function readConfig(configPath: string = CONFIG_PATH): Promise<OpenCodeConfig> {
|
|
44
56
|
try {
|
|
45
|
-
const content = await readFile(configPath, 'utf-8');
|
|
57
|
+
const content = await readFile(resolveConfigPath(configPath), 'utf-8');
|
|
46
58
|
const config = parse(content, null, false) as OpenCodeConfig;
|
|
47
59
|
return config;
|
|
48
60
|
} catch {
|
|
@@ -64,7 +76,7 @@ export async function writeConfig(
|
|
|
64
76
|
const configWithSchema: OpenCodeConfig = shouldEnforceSchema
|
|
65
77
|
? {
|
|
66
78
|
...config,
|
|
67
|
-
$schema: config.$schema ||
|
|
79
|
+
$schema: config.$schema || OH_MY_OPENAGENT_CONFIG_SCHEMA,
|
|
68
80
|
}
|
|
69
81
|
: config;
|
|
70
82
|
|
|
@@ -4,7 +4,7 @@ import { tmpdir } from 'os';
|
|
|
4
4
|
import { join } from 'path';
|
|
5
5
|
import { parse } from 'comment-json';
|
|
6
6
|
|
|
7
|
-
const SCHEMA_URL = 'https://
|
|
7
|
+
const SCHEMA_URL = 'https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/v3.15.2/assets/oh-my-opencode.schema.json';
|
|
8
8
|
|
|
9
9
|
describe('profile storage schema handling', () => {
|
|
10
10
|
let testHomeDir: string;
|
|
@@ -105,4 +105,41 @@ describe('profile storage schema handling', () => {
|
|
|
105
105
|
await chmod(configPath, 0o600);
|
|
106
106
|
}
|
|
107
107
|
});
|
|
108
|
+
|
|
109
|
+
it('creates the built-in balanced profile with upstream-aligned defaults', async () => {
|
|
110
|
+
await storage.readProfileIndex();
|
|
111
|
+
|
|
112
|
+
const balanced = await storage.readProfileConfig('balanced');
|
|
113
|
+
|
|
114
|
+
expect(balanced.agents.hephaestus).toMatchObject({
|
|
115
|
+
model: 'openai/gpt-5.4',
|
|
116
|
+
variant: 'medium',
|
|
117
|
+
});
|
|
118
|
+
expect((balanced.agents as Record<string, unknown>).hepheastus).toBeUndefined();
|
|
119
|
+
expect(balanced.agents.librarian).toMatchObject({
|
|
120
|
+
model: 'minimax-m2.7',
|
|
121
|
+
});
|
|
122
|
+
expect(balanced.agents.explore).toMatchObject({
|
|
123
|
+
model: 'grok-code-fast-1',
|
|
124
|
+
});
|
|
125
|
+
expect(balanced.agents['multimodal-looker']).toMatchObject({
|
|
126
|
+
model: 'openai/gpt-5.4',
|
|
127
|
+
variant: 'medium',
|
|
128
|
+
});
|
|
129
|
+
expect(balanced.categories?.quick).toMatchObject({
|
|
130
|
+
model: 'openai/gpt-5.4-mini',
|
|
131
|
+
});
|
|
132
|
+
expect(balanced.categories?.ultrabrain).toMatchObject({
|
|
133
|
+
model: 'openai/gpt-5.4',
|
|
134
|
+
variant: 'xhigh',
|
|
135
|
+
});
|
|
136
|
+
expect(balanced.categories?.deep).toMatchObject({
|
|
137
|
+
model: 'openai/gpt-5.4',
|
|
138
|
+
variant: 'medium',
|
|
139
|
+
});
|
|
140
|
+
expect(balanced.categories?.['unspecified-high']).toMatchObject({
|
|
141
|
+
model: 'anthropic/claude-opus-4-6',
|
|
142
|
+
variant: 'max',
|
|
143
|
+
});
|
|
144
|
+
});
|
|
108
145
|
});
|
|
@@ -3,7 +3,7 @@ import { existsSync, mkdirSync } from 'fs';
|
|
|
3
3
|
import { join } from 'path';
|
|
4
4
|
import { homedir } from 'os';
|
|
5
5
|
import { parse, stringify } from 'comment-json';
|
|
6
|
-
import {
|
|
6
|
+
import { OH_MY_OPENAGENT_CONFIG_SCHEMA } from '../opencodeConfig';
|
|
7
7
|
import type { AgentConfig, CategoryConfig } from '@/types/opencodeConfig';
|
|
8
8
|
|
|
9
9
|
export const PROFILES_DIR = join(homedir(), '.config', 'opencode', 'profiles');
|
|
@@ -83,25 +83,25 @@ const BUILTIN_PROFILE_CONFIGS: Record<string, ProfileConfig> = {
|
|
|
83
83
|
temperature: 0.2,
|
|
84
84
|
top_p: 0.9,
|
|
85
85
|
},
|
|
86
|
-
|
|
87
|
-
model: 'openai/gpt-5.
|
|
88
|
-
variant: '
|
|
86
|
+
hephaestus: {
|
|
87
|
+
model: 'openai/gpt-5.4',
|
|
88
|
+
variant: 'medium',
|
|
89
89
|
temperature: 0.2,
|
|
90
90
|
top_p: 0.9,
|
|
91
91
|
},
|
|
92
92
|
librarian: {
|
|
93
|
-
model: '
|
|
93
|
+
model: 'minimax-m2.7',
|
|
94
94
|
temperature: 0.3,
|
|
95
95
|
top_p: 0.9,
|
|
96
96
|
},
|
|
97
97
|
explore: {
|
|
98
|
-
model: '
|
|
98
|
+
model: 'grok-code-fast-1',
|
|
99
99
|
temperature: 0.1,
|
|
100
100
|
top_p: 0.9,
|
|
101
101
|
},
|
|
102
102
|
'multimodal-looker': {
|
|
103
|
-
model: '
|
|
104
|
-
variant: '
|
|
103
|
+
model: 'openai/gpt-5.4',
|
|
104
|
+
variant: 'medium',
|
|
105
105
|
temperature: 0.2,
|
|
106
106
|
top_p: 0.9,
|
|
107
107
|
},
|
|
@@ -118,11 +118,11 @@ const BUILTIN_PROFILE_CONFIGS: Record<string, ProfileConfig> = {
|
|
|
118
118
|
variant: 'high',
|
|
119
119
|
},
|
|
120
120
|
ultrabrain: {
|
|
121
|
-
model: 'openai/gpt-5.
|
|
121
|
+
model: 'openai/gpt-5.4',
|
|
122
122
|
variant: 'xhigh',
|
|
123
123
|
},
|
|
124
124
|
deep: {
|
|
125
|
-
model: 'openai/gpt-5.
|
|
125
|
+
model: 'openai/gpt-5.4',
|
|
126
126
|
variant: 'medium',
|
|
127
127
|
},
|
|
128
128
|
artistry: {
|
|
@@ -130,7 +130,7 @@ const BUILTIN_PROFILE_CONFIGS: Record<string, ProfileConfig> = {
|
|
|
130
130
|
variant: 'high',
|
|
131
131
|
},
|
|
132
132
|
quick: {
|
|
133
|
-
model: '
|
|
133
|
+
model: 'openai/gpt-5.4-mini',
|
|
134
134
|
temperature: 0.1,
|
|
135
135
|
},
|
|
136
136
|
'unspecified-low': {
|
|
@@ -138,8 +138,8 @@ const BUILTIN_PROFILE_CONFIGS: Record<string, ProfileConfig> = {
|
|
|
138
138
|
temperature: 0.2,
|
|
139
139
|
},
|
|
140
140
|
'unspecified-high': {
|
|
141
|
-
model: '
|
|
142
|
-
variant: '
|
|
141
|
+
model: 'anthropic/claude-opus-4-6',
|
|
142
|
+
variant: 'max',
|
|
143
143
|
temperature: 0.2,
|
|
144
144
|
},
|
|
145
145
|
writing: {
|
|
@@ -163,7 +163,7 @@ function getProfileConfigPath(id: string): string {
|
|
|
163
163
|
function normalizeProfileConfig(config: unknown): ProfileConfig {
|
|
164
164
|
if (!config || typeof config !== 'object') {
|
|
165
165
|
return {
|
|
166
|
-
$schema:
|
|
166
|
+
$schema: OH_MY_OPENAGENT_CONFIG_SCHEMA,
|
|
167
167
|
agents: {},
|
|
168
168
|
};
|
|
169
169
|
}
|
|
@@ -182,7 +182,7 @@ function normalizeProfileConfig(config: unknown): ProfileConfig {
|
|
|
182
182
|
const schema =
|
|
183
183
|
typeof candidate.$schema === 'string' && candidate.$schema.trim().length > 0
|
|
184
184
|
? candidate.$schema
|
|
185
|
-
:
|
|
185
|
+
: OH_MY_OPENAGENT_CONFIG_SCHEMA;
|
|
186
186
|
|
|
187
187
|
return {
|
|
188
188
|
$schema: schema,
|
|
@@ -291,7 +291,7 @@ export async function readProfileConfig(id: string): Promise<ProfileConfig> {
|
|
|
291
291
|
|
|
292
292
|
if (!existsSync(configPath)) {
|
|
293
293
|
return {
|
|
294
|
-
$schema:
|
|
294
|
+
$schema: OH_MY_OPENAGENT_CONFIG_SCHEMA,
|
|
295
295
|
agents: {},
|
|
296
296
|
};
|
|
297
297
|
}
|
|
@@ -315,7 +315,7 @@ export async function readProfileConfig(id: string): Promise<ProfileConfig> {
|
|
|
315
315
|
return normalizedConfig;
|
|
316
316
|
} catch {
|
|
317
317
|
return {
|
|
318
|
-
|
|
318
|
+
$schema: OH_MY_OPENAGENT_CONFIG_SCHEMA,
|
|
319
319
|
agents: {},
|
|
320
320
|
};
|
|
321
321
|
}
|