conductor-oss 0.2.5 → 0.2.6
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/README.md +29 -6
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +3 -0
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/setup.d.ts +30 -0
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +131 -29
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/start.d.ts +3 -0
- package/dist/commands/start.d.ts.map +1 -1
- package/dist/commands/start.js +209 -15
- package/dist/commands/start.js.map +1 -1
- package/dist/index.js +1 -1
- package/node_modules/@conductor-oss/core/dist/config.d.ts +1 -1
- package/node_modules/@conductor-oss/core/dist/config.d.ts.map +1 -1
- package/node_modules/@conductor-oss/core/dist/config.js +34 -0
- package/node_modules/@conductor-oss/core/dist/config.js.map +1 -1
- package/node_modules/@conductor-oss/core/dist/scaffold.d.ts +14 -0
- package/node_modules/@conductor-oss/core/dist/scaffold.d.ts.map +1 -1
- package/node_modules/@conductor-oss/core/dist/scaffold.js +27 -4
- package/node_modules/@conductor-oss/core/dist/scaffold.js.map +1 -1
- package/node_modules/@conductor-oss/core/dist/types.d.ts +71 -0
- package/node_modules/@conductor-oss/core/dist/types.d.ts.map +1 -1
- package/node_modules/@conductor-oss/core/dist/types.js +244 -0
- package/node_modules/@conductor-oss/core/dist/types.js.map +1 -1
- package/node_modules/@conductor-oss/core/package.json +1 -1
- package/node_modules/@conductor-oss/plugin-agent-amp/dist/index.js +1 -1
- package/node_modules/@conductor-oss/plugin-agent-amp/package.json +2 -2
- package/node_modules/@conductor-oss/plugin-agent-ccr/dist/index.js +1 -1
- package/node_modules/@conductor-oss/plugin-agent-ccr/package.json +2 -2
- package/node_modules/@conductor-oss/plugin-agent-claude-code/dist/index.js +1 -1
- package/node_modules/@conductor-oss/plugin-agent-claude-code/package.json +2 -2
- package/node_modules/@conductor-oss/plugin-agent-codex/dist/index.js +1 -1
- package/node_modules/@conductor-oss/plugin-agent-codex/package.json +2 -2
- package/node_modules/@conductor-oss/plugin-agent-cursor-cli/dist/index.js +1 -1
- package/node_modules/@conductor-oss/plugin-agent-cursor-cli/package.json +2 -2
- package/node_modules/@conductor-oss/plugin-agent-droid/dist/index.js +1 -1
- package/node_modules/@conductor-oss/plugin-agent-droid/package.json +2 -2
- package/node_modules/@conductor-oss/plugin-agent-gemini/dist/index.js +1 -1
- package/node_modules/@conductor-oss/plugin-agent-gemini/package.json +2 -2
- package/node_modules/@conductor-oss/plugin-agent-github-copilot/dist/index.js +1 -1
- package/node_modules/@conductor-oss/plugin-agent-github-copilot/package.json +2 -2
- package/node_modules/@conductor-oss/plugin-agent-opencode/dist/index.js +1 -1
- package/node_modules/@conductor-oss/plugin-agent-opencode/package.json +2 -2
- package/node_modules/@conductor-oss/plugin-agent-qwen-code/dist/index.js +10 -6
- package/node_modules/@conductor-oss/plugin-agent-qwen-code/package.json +2 -2
- package/node_modules/@conductor-oss/plugin-mcp-server/dist/index.js +1 -1
- package/node_modules/@conductor-oss/plugin-mcp-server/package.json +2 -2
- package/node_modules/@conductor-oss/plugin-notifier-desktop/dist/index.js +1 -1
- package/node_modules/@conductor-oss/plugin-notifier-desktop/package.json +2 -2
- package/node_modules/@conductor-oss/plugin-notifier-discord/dist/index.js +1 -1
- package/node_modules/@conductor-oss/plugin-notifier-discord/package.json +2 -2
- package/node_modules/@conductor-oss/plugin-runtime-tmux/dist/index.js +1 -1
- package/node_modules/@conductor-oss/plugin-runtime-tmux/package.json +2 -2
- package/node_modules/@conductor-oss/plugin-scm-github/dist/index.js +1 -1
- package/node_modules/@conductor-oss/plugin-scm-github/package.json +2 -2
- package/node_modules/@conductor-oss/plugin-terminal-web/dist/index.js +1 -1
- package/node_modules/@conductor-oss/plugin-terminal-web/package.json +2 -2
- package/node_modules/@conductor-oss/plugin-tracker-github/dist/index.js +1 -1
- package/node_modules/@conductor-oss/plugin-tracker-github/package.json +2 -2
- package/node_modules/@conductor-oss/plugin-webhook/package.json +2 -2
- package/node_modules/@conductor-oss/plugin-workspace-worktree/dist/index.js +1 -1
- package/node_modules/@conductor-oss/plugin-workspace-worktree/package.json +2 -2
- package/package.json +22 -21
- package/web/.next/standalone/packages/web/.next/BUILD_ID +1 -1
- package/web/.next/standalone/packages/web/.next/app-path-routes-manifest.json +5 -1
- package/web/.next/standalone/packages/web/.next/build-manifest.json +4 -4
- package/web/.next/standalone/packages/web/.next/routes-manifest.json +24 -0
- package/web/.next/standalone/packages/web/.next/server/app/_global-error/page/build-manifest.json +2 -2
- package/web/.next/standalone/packages/web/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/_global-error.html +2 -2
- package/web/.next/standalone/packages/web/.next/server/app/_global-error.rsc +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/_not-found/page/build-manifest.json +2 -2
- package/web/.next/standalone/packages/web/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/_not-found.html +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/_not-found.rsc +9 -9
- package/web/.next/standalone/packages/web/.next/server/app/_not-found.segments/_full.segment.rsc +9 -9
- package/web/.next/standalone/packages/web/.next/server/app/_not-found.segments/_head.segment.rsc +3 -3
- package/web/.next/standalone/packages/web/.next/server/app/_not-found.segments/_index.segment.rsc +5 -5
- package/web/.next/standalone/packages/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/web/.next/standalone/packages/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
- package/web/.next/standalone/packages/web/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/web/.next/standalone/packages/web/.next/server/app/api/access/route/app-paths-manifest.json +3 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/access/route/build-manifest.json +11 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/access/route/server-reference-manifest.json +4 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/access/route.js +11 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/access/route.js.map +5 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/access/route.js.nft.json +1 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/access/route_client-reference-manifest.js +2 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/agents/route.js +5 -3
- package/web/.next/standalone/packages/web/.next/server/app/api/agents/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/attachments/route.js +4 -2
- package/web/.next/standalone/packages/web/.next/server/app/api/attachments/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/auth/session/route/app-paths-manifest.json +3 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/auth/session/route/build-manifest.json +11 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/auth/session/route/server-reference-manifest.json +4 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/auth/session/route.js +8 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/auth/session/route.js.map +5 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/auth/session/route.js.nft.json +1 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/auth/session/route_client-reference-manifest.js +2 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/boards/route.js +5 -3
- package/web/.next/standalone/packages/web/.next/server/app/api/boards/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/config/route.js +4 -2
- package/web/.next/standalone/packages/web/.next/server/app/api/config/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/context-files/route.js +3 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/context-files/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/events/route.js +4 -2
- package/web/.next/standalone/packages/web/.next/server/app/api/events/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/filesystem/directory/route.js +3 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/filesystem/directory/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/github/repos/route.js +4 -2
- package/web/.next/standalone/packages/web/.next/server/app/api/github/repos/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/health/boards/route.js +3 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/health/boards/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/preferences/route.js +5 -3
- package/web/.next/standalone/packages/web/.next/server/app/api/preferences/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/repositories/route.js +5 -3
- package/web/.next/standalone/packages/web/.next/server/app/api/repositories/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/checks/route.js +4 -2
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/checks/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/diff/route.js +4 -2
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/diff/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/feedback/route.js +4 -2
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/feedback/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/files/route.js +3 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/files/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/keys/route.js +3 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/keys/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/kill/route.js +4 -2
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/kill/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/output/route.js +4 -2
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/output/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/output/stream/route.js +4 -2
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/output/stream/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/restore/route.js +4 -2
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/restore/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/route.js +3 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/send/route.js +4 -2
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/send/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/route.js +3 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/spawn/route.js +5 -3
- package/web/.next/standalone/packages/web/.next/server/app/api/spawn/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/workspaces/branches/route.js +3 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/workspaces/branches/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/workspaces/route.js +5 -3
- package/web/.next/standalone/packages/web/.next/server/app/api/workspaces/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/auth/grant/route/app-paths-manifest.json +3 -0
- package/web/.next/standalone/packages/web/.next/server/app/auth/grant/route/build-manifest.json +11 -0
- package/web/.next/standalone/packages/web/.next/server/app/auth/grant/route/server-reference-manifest.json +4 -0
- package/web/.next/standalone/packages/web/.next/server/app/auth/grant/route.js +8 -0
- package/web/.next/standalone/packages/web/.next/server/app/auth/grant/route.js.map +5 -0
- package/web/.next/standalone/packages/web/.next/server/app/auth/grant/route.js.nft.json +1 -0
- package/web/.next/standalone/packages/web/.next/server/app/auth/grant/route_client-reference-manifest.js +2 -0
- package/web/.next/standalone/packages/web/.next/server/app/index.html +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/index.rsc +4 -4
- package/web/.next/standalone/packages/web/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/web/.next/standalone/packages/web/.next/server/app/index.segments/_full.segment.rsc +4 -4
- package/web/.next/standalone/packages/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/index.segments/_index.segment.rsc +3 -3
- package/web/.next/standalone/packages/web/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/web/.next/standalone/packages/web/.next/server/app/page/build-manifest.json +2 -2
- package/web/.next/standalone/packages/web/.next/server/app/page.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/sessions/[id]/page/build-manifest.json +2 -2
- package/web/.next/standalone/packages/web/.next/server/app/sessions/[id]/page.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/sessions/[id]/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/sign-in/[[...sign-in]]/page/build-manifest.json +2 -2
- package/web/.next/standalone/packages/web/.next/server/app/sign-in/[[...sign-in]]/page.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/sign-in/[[...sign-in]]/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/unlock/page/app-paths-manifest.json +3 -0
- package/web/.next/standalone/packages/web/.next/server/app/unlock/page/build-manifest.json +18 -0
- package/web/.next/standalone/packages/web/.next/server/app/unlock/page/next-font-manifest.json +14 -0
- package/web/.next/standalone/packages/web/.next/server/app/unlock/page/react-loadable-manifest.json +1 -0
- package/web/.next/standalone/packages/web/.next/server/app/unlock/page/server-reference-manifest.json +110 -0
- package/web/.next/standalone/packages/web/.next/server/app/unlock/page.js +19 -0
- package/web/.next/standalone/packages/web/.next/server/app/unlock/page.js.map +5 -0
- package/web/.next/standalone/packages/web/.next/server/app/unlock/page.js.nft.json +1 -0
- package/web/.next/standalone/packages/web/.next/server/app/unlock/page_client-reference-manifest.js +2 -0
- package/web/.next/standalone/packages/web/.next/server/app-paths-manifest.json +5 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/1bc17_next_dist_esm_build_templates_app-route_1651710d.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/1bc17_next_dist_esm_build_templates_app-route_34b04c2b.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/1bc17_next_dist_esm_build_templates_app-route_9c655a1d.js +3 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/1bc17_next_dist_esm_build_templates_app-route_b41c4976.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/1bc17_next_dist_esm_build_templates_app-route_f4104ae4.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__005aa909._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__03ff76ee._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__07ec6d5c._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__0a0f0f01._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__0ad3545b._.js +5 -5
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__04d7f8e9._.js → [root-of-the-server]__0c65150d._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__39e2947e._.js → [root-of-the-server]__0d615ef4._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__13ad088c._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__14b1d4a3._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__000a39bb._.js → [root-of-the-server]__14d277b3._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__1741fb8a._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__17d81825._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__4266ed21._.js → [root-of-the-server]__1b7c6a55._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__1e288076._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__1f626a16._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__1f712b77._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__2062aaab._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__206c3d8a._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__9469f247._.js → [root-of-the-server]__230d54da._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__24d8e6fc._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__2556a816._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__2af6c2e0._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__2d57abda._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__30b0f109._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__30c75561._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__31c39bd9._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__7e505454._.js → [root-of-the-server]__341657dd._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__34a19860._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__3fde7043._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__40c8037e._.js +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__41ee872a._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__44606e04._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__44d59fd0._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__459839a6._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__46a8e776._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__48875cbb._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__b3f4ff98._.js → [root-of-the-server]__488ab4b2._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__4ac9d639._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__4c3fb752._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__4dab6a6a._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__544326ac._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__5494c5a2._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__54a218f0._.js +3 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__54a76cd2._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__5661ca72._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__568f0a6e._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__5cd49624._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__5d76c5af._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__5e0533de._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__5f628cf2._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__62608541._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__6d62709d._.js +5 -5
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__6e4e09be._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__70258e45._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__917adaec._.js → [root-of-the-server]__711dc459._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__720136dd._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__749331b0._.js +3 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__755c7e10._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__778e46a1._.js +5 -5
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__7e6ea46e._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__7f023a04._.js +4 -4
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__7f2ed2cd._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__7fa52da6._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__82171aa3._.js +9 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__84362910._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__848eb266._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__8596d782._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__85c5cb36._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__878fbacc._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__881858fa._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__885e3a00._.js +3 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__893f6b3b._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__8ac30f97._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__8c519453._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__919845e0._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__9b62b450._.js → [root-of-the-server]__927b9bce._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__93b3582e._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__964f4e89._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__96633022._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__98697e45._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__997ebfca._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__9c930222._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__9f36b7ec._.js +5 -5
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__a44f91a4._.js +3 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__1bc4f8f5._.js → [root-of-the-server]__a5d13971._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__a6c7bd91._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__ae580a1a._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__af533b5e._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__afa79f55._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__b057f7b2._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__b59abfbd._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__bd8ace80._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__be0f2c29._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__bea07e07._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__c8618cb1._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__caf8e7cb._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__cb112606._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__cb51f2e3._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__cba32afb._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__cc74ea40._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__cd3692a0._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__cf3cdecd._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__d09e7a99._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__d538c110._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__d93447b9._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__d9c80b18._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__dc0959da._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__dda8eac1._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__df2c6efe._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__e113f6df._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__e2573a77._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__e2d60274._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__e308bb89._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__e345a443._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__e80a520f._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__ea0bb124._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__ef773ea6._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__f0d15920._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__b029d2c1._.js → [root-of-the-server]__f2f30c04._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__f47a2a9e._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__f48eb2d4._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__f6a8bbd9._.js +12 -12
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__faceea9b._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__fb6ab669._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__fcf96768._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__fdaa8058._.js +7 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__ff2b205d._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/packages_core_dist_index_cdd30418.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/packages_plugins_agent-amp_dist_index_bf3d8239.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/packages_plugins_agent-ccr_dist_index_69cbf726.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/packages_plugins_agent-claude-code_dist_index_31314e43.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/packages_plugins_agent-cursor-cli_dist_index_8d5cc426.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/packages_plugins_agent-droid_dist_index_f731227a.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/packages_plugins_agent-gemini_dist_index_b2d219e8.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/packages_plugins_agent-github-copilot_dist_index_9f80cb45.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/packages_plugins_agent-opencode_dist_index_7c7015da.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/packages_plugins_agent-qwen-code_dist_index_46dd8653.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/packages_plugins_notifier-desktop_dist_index_ef3473f0.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/packages_plugins_notifier-discord_dist_index_34257226.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/packages_plugins_scm-github_dist_index_3b5a621e.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/packages_plugins_terminal-web_dist_index_1e0706d3.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/packages_plugins_tracker-github_dist_index_2d7af62f.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/packages_web__next-internal_server_app_api_access_route_actions_06740e99.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/packages_web__next-internal_server_app_api_auth_session_route_actions_078c0ee4.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/packages_web__next-internal_server_app_auth_grant_route_actions_13ba4421.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/packages_web_src_lib_13fee5eb._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/packages_web_src_lib_d64596cc._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/{[root-of-the-server]__1ddf22db._.js → [root-of-the-server]__1012a4c8._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/{[root-of-the-server]__ed81e796._.js → [root-of-the-server]__81affb12._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/[root-of-the-server]__95e85d3d._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/{[root-of-the-server]__f577d85a._.js → [root-of-the-server]__9d698773._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/[root-of-the-server]__a38f483b._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/{[root-of-the-server]__3bf3fbfb._.js → [root-of-the-server]__c09a0c60._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/[root-of-the-server]__d9dde485._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/{[root-of-the-server]__d5970f3e._.js → [root-of-the-server]__dd435d80._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/{[root-of-the-server]__469db3c3._.js → [root-of-the-server]__e78955d0._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/_14a33487._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/_34d55bf1._.js +4 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/{node_modules__pnpm_c636dc22._.js → node_modules__pnpm_597c265e._.js} +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/packages_web_src_app_page_tsx_cd282e82._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/packages_web_src_app_unlock_UnlockForm_tsx_ce3149a7._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/middleware-build-manifest.js +2 -2
- package/web/.next/standalone/packages/web/.next/server/middleware.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/next-font-manifest.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/next-font-manifest.json +7 -0
- package/web/.next/standalone/packages/web/.next/server/pages/404.html +1 -1
- package/web/.next/standalone/packages/web/.next/server/pages/500.html +2 -2
- package/web/.next/standalone/packages/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/server-reference-manifest.json +56 -7
- package/web/.next/{static/chunks/9b799cd7eb9a34ff.js → standalone/packages/web/.next/static/chunks/1c4c14af475ada00.js} +1 -1
- package/web/.next/standalone/packages/web/.next/static/chunks/ba68284a3401d670.css +3 -0
- package/web/.next/standalone/packages/web/.next/static/chunks/{4372fb4d7779cd64.js → d00ddc86d1af3b6d.js} +1 -1
- package/web/.next/standalone/packages/web/.next/static/chunks/d8f4bf59132f70fd.js +1 -0
- package/web/.next/standalone/packages/web/.next/static/chunks/f355d4d60f0ec80e.js +1 -0
- package/web/.next/standalone/packages/web/.next/static/chunks/{turbopack-c3449aaab622f98c.js → turbopack-dc658d17ee981623.js} +1 -1
- package/web/.next/standalone/packages/web/package.json +1 -0
- package/web/.next/standalone/packages/web/src/app/api/access/route.ts +214 -0
- package/web/.next/standalone/packages/web/src/app/api/agents/route.ts +2 -2
- package/web/.next/standalone/packages/web/src/app/api/attachments/route.ts +1 -1
- package/web/.next/standalone/packages/web/src/app/api/auth/session/route.ts +54 -0
- package/web/.next/standalone/packages/web/src/app/api/boards/route.ts +2 -2
- package/web/.next/standalone/packages/web/src/app/api/config/route.ts +2 -1
- package/web/.next/standalone/packages/web/src/app/api/context-files/route.ts +1 -1
- package/web/.next/standalone/packages/web/src/app/api/events/route.ts +1 -1
- package/web/.next/standalone/packages/web/src/app/api/filesystem/directory/route.ts +1 -1
- package/web/.next/standalone/packages/web/src/app/api/github/repos/route.ts +1 -1
- package/web/.next/standalone/packages/web/src/app/api/health/boards/route.ts +1 -1
- package/web/.next/standalone/packages/web/src/app/api/preferences/route.ts +9 -2
- package/web/.next/standalone/packages/web/src/app/api/repositories/route.ts +19 -2
- package/web/.next/standalone/packages/web/src/app/api/sessions/[id]/checks/route.ts +1 -1
- package/web/.next/standalone/packages/web/src/app/api/sessions/[id]/diff/route.ts +1 -1
- package/web/.next/standalone/packages/web/src/app/api/sessions/[id]/feedback/route.ts +1 -1
- package/web/.next/standalone/packages/web/src/app/api/sessions/[id]/files/route.ts +1 -1
- package/web/.next/standalone/packages/web/src/app/api/sessions/[id]/keys/route.ts +1 -1
- package/web/.next/standalone/packages/web/src/app/api/sessions/[id]/kill/route.ts +1 -1
- package/web/.next/standalone/packages/web/src/app/api/sessions/[id]/output/route.ts +1 -1
- package/web/.next/standalone/packages/web/src/app/api/sessions/[id]/output/stream/route.ts +1 -1
- package/web/.next/standalone/packages/web/src/app/api/sessions/[id]/restore/route.ts +1 -1
- package/web/.next/standalone/packages/web/src/app/api/sessions/[id]/route.ts +1 -1
- package/web/.next/standalone/packages/web/src/app/api/sessions/[id]/send/route.ts +1 -1
- package/web/.next/standalone/packages/web/src/app/api/sessions/route.ts +1 -1
- package/web/.next/standalone/packages/web/src/app/api/spawn/route.ts +1 -1
- package/web/.next/standalone/packages/web/src/app/api/workspaces/branches/route.ts +1 -1
- package/web/.next/standalone/packages/web/src/app/api/workspaces/route.ts +9 -2
- package/web/.next/standalone/packages/web/src/app/auth/grant/route.ts +37 -0
- package/web/.next/standalone/packages/web/src/app/page.tsx +763 -9
- package/web/.next/standalone/packages/web/src/app/unlock/UnlockForm.tsx +77 -0
- package/web/.next/standalone/packages/web/src/app/unlock/page.tsx +41 -0
- package/web/.next/standalone/packages/web/src/components/Dashboard.tsx +11 -125
- package/web/.next/standalone/packages/web/src/hooks/useConfig.ts +4 -0
- package/web/.next/standalone/packages/web/src/lib/accessControl.test.ts +46 -0
- package/web/.next/standalone/packages/web/src/lib/accessControl.ts +115 -0
- package/web/.next/standalone/packages/web/src/lib/auth.ts +294 -53
- package/web/.next/standalone/packages/web/src/lib/edgeAuth.test.ts +91 -0
- package/web/.next/standalone/packages/web/src/lib/edgeAuth.ts +205 -0
- package/web/.next/standalone/packages/web/src/lib/modelAccess.ts +40 -0
- package/web/.next/standalone/packages/web/src/lib/projectConfigSync.ts +2 -0
- package/web/.next/standalone/packages/web/src/lib/remoteAuth.ts +104 -0
- package/web/.next/standalone/packages/web/src/proxy.ts +64 -0
- package/web/.next/standalone/packages/web/tsconfig.tsbuildinfo +1 -1
- package/web/.next/{standalone/packages/web/.next/static/chunks/9b799cd7eb9a34ff.js → static/chunks/1c4c14af475ada00.js} +1 -1
- package/web/.next/static/chunks/ba68284a3401d670.css +3 -0
- package/web/.next/static/chunks/{4372fb4d7779cd64.js → d00ddc86d1af3b6d.js} +1 -1
- package/web/.next/static/chunks/d8f4bf59132f70fd.js +1 -0
- package/web/.next/static/chunks/f355d4d60f0ec80e.js +1 -0
- package/web/.next/static/chunks/{turbopack-c3449aaab622f98c.js → turbopack-dc658d17ee981623.js} +1 -1
- package/node_modules/@conductor-oss/core/dist/__tests__/board-parser.test.d.ts +0 -2
- package/node_modules/@conductor-oss/core/dist/__tests__/board-parser.test.d.ts.map +0 -1
- package/node_modules/@conductor-oss/core/dist/__tests__/board-parser.test.js +0 -67
- package/node_modules/@conductor-oss/core/dist/__tests__/board-parser.test.js.map +0 -1
- package/node_modules/@conductor-oss/core/dist/__tests__/board-watcher-support-files.test.d.ts +0 -2
- package/node_modules/@conductor-oss/core/dist/__tests__/board-watcher-support-files.test.d.ts.map +0 -1
- package/node_modules/@conductor-oss/core/dist/__tests__/board-watcher-support-files.test.js +0 -122
- package/node_modules/@conductor-oss/core/dist/__tests__/board-watcher-support-files.test.js.map +0 -1
- package/node_modules/@conductor-oss/core/dist/__tests__/project-paths.test.d.ts +0 -2
- package/node_modules/@conductor-oss/core/dist/__tests__/project-paths.test.d.ts.map +0 -1
- package/node_modules/@conductor-oss/core/dist/__tests__/project-paths.test.js +0 -48
- package/node_modules/@conductor-oss/core/dist/__tests__/project-paths.test.js.map +0 -1
- package/node_modules/@conductor-oss/core/dist/agent-cli-runtime.d.ts +0 -20
- package/node_modules/@conductor-oss/core/dist/agent-cli-runtime.d.ts.map +0 -1
- package/node_modules/@conductor-oss/core/dist/agent-cli-runtime.js +0 -192
- package/node_modules/@conductor-oss/core/dist/agent-cli-runtime.js.map +0 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__019d9c90._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__08a3e108._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__0b0ab434._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__0e59a166._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__16fb4c3e._.js +0 -9
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__2ff87bed._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__3c1772ab._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__5093c7e0._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__53970b23._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__5a67f1f9._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__5cf55740._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__5d124f64._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__6cad94c3._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__6d28affc._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__6f6826fa._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__6f84fa49._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__70c9c405._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__711294a3._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__7791414d._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__7fb2ee11._.js +0 -7
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__86646048._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__a15b5527._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__a4a89ac9._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__a8a53d4a._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__a93c59df._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__abf6274f._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__b091b8bc._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__b87de88e._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__bc304d71._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__be52402d._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__be74f171._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__c03aa571._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__c2850420._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__c82b8934._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__deafbc7a._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__e18c8e77._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__e1f610fb._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__e4976f6d._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__ec21c9a4._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__ec256a62._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__edc8e5a5._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__f2c28004._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__f7c743c0._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__f95f5172._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__fc292e1c._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__ffbf3faf._.js +0 -3
- package/web/.next/standalone/packages/web/.next/static/chunks/687bc713618f6993.js +0 -1
- package/web/.next/standalone/packages/web/.next/static/chunks/e7bb96d7efad8e32.css +0 -3
- package/web/.next/static/chunks/687bc713618f6993.js +0 -1
- package/web/.next/static/chunks/e7bb96d7efad8e32.css +0 -3
- /package/web/.next/standalone/packages/web/.next/static/{2lp61OU9Asm88Hx_JCL5e → tV9IvZT_f540bpw2KonCu}/_buildManifest.js +0 -0
- /package/web/.next/standalone/packages/web/.next/static/{2lp61OU9Asm88Hx_JCL5e → tV9IvZT_f540bpw2KonCu}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/standalone/packages/web/.next/static/{2lp61OU9Asm88Hx_JCL5e → tV9IvZT_f540bpw2KonCu}/_ssgManifest.js +0 -0
- /package/web/.next/static/{2lp61OU9Asm88Hx_JCL5e → tV9IvZT_f540bpw2KonCu}/_buildManifest.js +0 -0
- /package/web/.next/static/{2lp61OU9Asm88Hx_JCL5e → tV9IvZT_f540bpw2KonCu}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{2lp61OU9Asm88Hx_JCL5e → tV9IvZT_f540bpw2KonCu}/_ssgManifest.js +0 -0
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
import { type FormEvent, useEffect, useMemo, useState } from "react";
|
|
4
4
|
import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
|
|
5
|
+
import {
|
|
6
|
+
getAgentModelCatalog,
|
|
7
|
+
getAvailableAgentModels,
|
|
8
|
+
getDefaultAgentModel,
|
|
9
|
+
resolveAgentModelAccess,
|
|
10
|
+
supportsAgentModelSelection,
|
|
11
|
+
type AgentModelCatalog,
|
|
12
|
+
type AgentModelOption,
|
|
13
|
+
type DashboardRole,
|
|
14
|
+
type ModelAccessPreferences,
|
|
15
|
+
type TrustedHeaderAccessProvider,
|
|
16
|
+
} from "@conductor-oss/core/types";
|
|
5
17
|
import type { IconType } from "react-icons";
|
|
6
18
|
import { SiNotion, SiObsidian } from "react-icons/si";
|
|
7
19
|
import { VscVscode } from "react-icons/vsc";
|
|
@@ -37,6 +49,7 @@ import { SessionDetail } from "@/components/sessions/SessionDetail";
|
|
|
37
49
|
import { AgentTileIcon } from "@/components/AgentTileIcon";
|
|
38
50
|
import { WorkspaceSidebarPanel } from "@/components/layout/WorkspaceSidebarPanel";
|
|
39
51
|
import { WorkspaceKanban } from "@/components/board/WorkspaceKanban";
|
|
52
|
+
import { normalizeModelAccessPreferences } from "@/lib/modelAccess";
|
|
40
53
|
|
|
41
54
|
const EXECUTOR_ORDER = [
|
|
42
55
|
"codex",
|
|
@@ -112,12 +125,42 @@ type PreferencesPayload = {
|
|
|
112
125
|
remoteSshHost: string;
|
|
113
126
|
remoteSshUser: string;
|
|
114
127
|
markdownEditor: string;
|
|
128
|
+
modelAccess: ModelAccessPreferences;
|
|
115
129
|
notifications: {
|
|
116
130
|
soundEnabled: boolean;
|
|
117
131
|
soundFile: string | null;
|
|
118
132
|
};
|
|
119
133
|
};
|
|
120
134
|
|
|
135
|
+
type AccessIdentitySummary = {
|
|
136
|
+
authenticated: boolean;
|
|
137
|
+
role: DashboardRole | null;
|
|
138
|
+
email: string | null;
|
|
139
|
+
provider: string | null;
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
type AccessSettingsPayload = {
|
|
143
|
+
requireAuth: boolean;
|
|
144
|
+
defaultRole: DashboardRole;
|
|
145
|
+
trustedHeaders: {
|
|
146
|
+
enabled: boolean;
|
|
147
|
+
provider: TrustedHeaderAccessProvider;
|
|
148
|
+
emailHeader: string;
|
|
149
|
+
jwtHeader: string;
|
|
150
|
+
teamDomain: string;
|
|
151
|
+
audience: string;
|
|
152
|
+
};
|
|
153
|
+
roles: {
|
|
154
|
+
viewers: string;
|
|
155
|
+
operators: string;
|
|
156
|
+
admins: string;
|
|
157
|
+
viewerDomains: string;
|
|
158
|
+
operatorDomains: string;
|
|
159
|
+
adminDomains: string;
|
|
160
|
+
};
|
|
161
|
+
current: AccessIdentitySummary;
|
|
162
|
+
};
|
|
163
|
+
|
|
121
164
|
type RepositoryPathHealth = {
|
|
122
165
|
exists: boolean;
|
|
123
166
|
isGitRepository: boolean;
|
|
@@ -130,6 +173,7 @@ type RepositorySettingsPayload = {
|
|
|
130
173
|
repo: string;
|
|
131
174
|
path: string;
|
|
132
175
|
agent: string;
|
|
176
|
+
agentModel: string;
|
|
133
177
|
workspaceMode: string;
|
|
134
178
|
runtimeMode: string;
|
|
135
179
|
scmMode: string;
|
|
@@ -144,6 +188,11 @@ type RepositorySettingsPayload = {
|
|
|
144
188
|
pathHealth: RepositoryPathHealth;
|
|
145
189
|
};
|
|
146
190
|
|
|
191
|
+
type ModelSelectionState = {
|
|
192
|
+
catalogModel: string;
|
|
193
|
+
customModel: string;
|
|
194
|
+
};
|
|
195
|
+
|
|
147
196
|
type PreferencesDialogMode = "onboarding" | "settings";
|
|
148
197
|
type SettingsTabId =
|
|
149
198
|
| "general"
|
|
@@ -164,7 +213,7 @@ type SettingsTab = {
|
|
|
164
213
|
const SETTINGS_TABS: SettingsTab[] = [
|
|
165
214
|
{ id: "general", label: "General", icon: Settings2, implemented: false },
|
|
166
215
|
{ id: "repositories", label: "Repositories", icon: FolderGit2, implemented: true },
|
|
167
|
-
{ id: "organization", label: "Organization Settings", icon: Building2, implemented:
|
|
216
|
+
{ id: "organization", label: "Organization Settings", icon: Building2, implemented: true },
|
|
168
217
|
{ id: "projects", label: "Projects", icon: FolderKanban, implemented: false },
|
|
169
218
|
{ id: "agents", label: "Agents", icon: Bot, implemented: false },
|
|
170
219
|
{ id: "mcp", label: "MCP Servers", icon: PlugZap, implemented: false },
|
|
@@ -239,6 +288,7 @@ function normalizePreferences(value: unknown, fallbackAgent: string): Preference
|
|
|
239
288
|
remoteSshHost,
|
|
240
289
|
remoteSshUser,
|
|
241
290
|
markdownEditor,
|
|
291
|
+
modelAccess: normalizeModelAccessPreferences(payload["modelAccess"]),
|
|
242
292
|
notifications: {
|
|
243
293
|
soundEnabled: notifications["soundEnabled"] !== false,
|
|
244
294
|
soundFile: soundFileRaw === null
|
|
@@ -250,6 +300,131 @@ function normalizePreferences(value: unknown, fallbackAgent: string): Preference
|
|
|
250
300
|
};
|
|
251
301
|
}
|
|
252
302
|
|
|
303
|
+
function normalizeMultilineList(value: unknown): string {
|
|
304
|
+
if (Array.isArray(value)) {
|
|
305
|
+
return value
|
|
306
|
+
.filter((item): item is string => typeof item === "string")
|
|
307
|
+
.map((item) => item.trim())
|
|
308
|
+
.filter(Boolean)
|
|
309
|
+
.join("\n");
|
|
310
|
+
}
|
|
311
|
+
if (typeof value !== "string") return "";
|
|
312
|
+
return value
|
|
313
|
+
.split(/[\n,]+/g)
|
|
314
|
+
.map((item) => item.trim())
|
|
315
|
+
.filter(Boolean)
|
|
316
|
+
.join("\n");
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function normalizeAccessSettings(value: unknown, summary?: unknown): AccessSettingsPayload {
|
|
320
|
+
const payload = toObject(value);
|
|
321
|
+
const trustedHeaders = toObject(payload["trustedHeaders"]);
|
|
322
|
+
const roles = toObject(payload["roles"]);
|
|
323
|
+
const current = toObject(summary);
|
|
324
|
+
const defaultRoleRaw = payload["defaultRole"];
|
|
325
|
+
const defaultRole: DashboardRole =
|
|
326
|
+
defaultRoleRaw === "viewer" || defaultRoleRaw === "admin" || defaultRoleRaw === "operator"
|
|
327
|
+
? defaultRoleRaw
|
|
328
|
+
: "operator";
|
|
329
|
+
const currentRoleRaw = current["role"];
|
|
330
|
+
|
|
331
|
+
return {
|
|
332
|
+
requireAuth: payload["requireAuth"] === true,
|
|
333
|
+
defaultRole,
|
|
334
|
+
trustedHeaders: {
|
|
335
|
+
enabled: trustedHeaders["enabled"] === true,
|
|
336
|
+
provider: trustedHeaders["provider"] === "generic" ? "generic" : "cloudflare-access",
|
|
337
|
+
emailHeader: typeof trustedHeaders["emailHeader"] === "string" && trustedHeaders["emailHeader"].trim().length > 0
|
|
338
|
+
? trustedHeaders["emailHeader"].trim()
|
|
339
|
+
: "Cf-Access-Authenticated-User-Email",
|
|
340
|
+
jwtHeader: typeof trustedHeaders["jwtHeader"] === "string" && trustedHeaders["jwtHeader"].trim().length > 0
|
|
341
|
+
? trustedHeaders["jwtHeader"].trim()
|
|
342
|
+
: "Cf-Access-Jwt-Assertion",
|
|
343
|
+
teamDomain: typeof trustedHeaders["teamDomain"] === "string" && trustedHeaders["teamDomain"].trim().length > 0
|
|
344
|
+
? trustedHeaders["teamDomain"].trim()
|
|
345
|
+
: "",
|
|
346
|
+
audience: typeof trustedHeaders["audience"] === "string" && trustedHeaders["audience"].trim().length > 0
|
|
347
|
+
? trustedHeaders["audience"].trim()
|
|
348
|
+
: "",
|
|
349
|
+
},
|
|
350
|
+
roles: {
|
|
351
|
+
viewers: normalizeMultilineList(roles["viewers"]),
|
|
352
|
+
operators: normalizeMultilineList(roles["operators"]),
|
|
353
|
+
admins: normalizeMultilineList(roles["admins"]),
|
|
354
|
+
viewerDomains: normalizeMultilineList(roles["viewerDomains"]),
|
|
355
|
+
operatorDomains: normalizeMultilineList(roles["operatorDomains"]),
|
|
356
|
+
adminDomains: normalizeMultilineList(roles["adminDomains"]),
|
|
357
|
+
},
|
|
358
|
+
current: {
|
|
359
|
+
authenticated: current["authenticated"] === true,
|
|
360
|
+
role: currentRoleRaw === "viewer" || currentRoleRaw === "operator" || currentRoleRaw === "admin"
|
|
361
|
+
? currentRoleRaw
|
|
362
|
+
: null,
|
|
363
|
+
email: typeof current["email"] === "string" && current["email"].trim().length > 0
|
|
364
|
+
? current["email"].trim()
|
|
365
|
+
: null,
|
|
366
|
+
provider: typeof current["provider"] === "string" && current["provider"].trim().length > 0
|
|
367
|
+
? current["provider"].trim()
|
|
368
|
+
: null,
|
|
369
|
+
},
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
function emptyModelSelection(): ModelSelectionState {
|
|
374
|
+
return {
|
|
375
|
+
catalogModel: "",
|
|
376
|
+
customModel: "",
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
function buildModelSelection(
|
|
381
|
+
agent: string,
|
|
382
|
+
modelAccess: ModelAccessPreferences,
|
|
383
|
+
preferredModel?: string | null,
|
|
384
|
+
): ModelSelectionState {
|
|
385
|
+
if (!supportsAgentModelSelection(agent)) {
|
|
386
|
+
return emptyModelSelection();
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
const trimmedPreferred = preferredModel?.trim() ?? "";
|
|
390
|
+
const availableModels = getAvailableAgentModels(agent, modelAccess);
|
|
391
|
+
const defaultModel = getDefaultAgentModel(agent, modelAccess) ?? "";
|
|
392
|
+
|
|
393
|
+
if (trimmedPreferred.length > 0) {
|
|
394
|
+
if (availableModels.some((model) => model.id === trimmedPreferred)) {
|
|
395
|
+
return {
|
|
396
|
+
catalogModel: trimmedPreferred,
|
|
397
|
+
customModel: "",
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
return {
|
|
402
|
+
catalogModel: defaultModel,
|
|
403
|
+
customModel: trimmedPreferred,
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
return {
|
|
408
|
+
catalogModel: defaultModel,
|
|
409
|
+
customModel: "",
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
function resolveModelSelectionValue(selection: ModelSelectionState): string | undefined {
|
|
414
|
+
const custom = selection.customModel.trim();
|
|
415
|
+
if (custom.length > 0) return custom;
|
|
416
|
+
const catalog = selection.catalogModel.trim();
|
|
417
|
+
return catalog.length > 0 ? catalog : undefined;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
function getAgentModelAccessLabel(agent: string, modelAccess: ModelAccessPreferences): string | null {
|
|
421
|
+
const catalog = getAgentModelCatalog(agent);
|
|
422
|
+
const access = resolveAgentModelAccess(agent, modelAccess);
|
|
423
|
+
if (!catalog || !access) return null;
|
|
424
|
+
|
|
425
|
+
return catalog.accessOptions.find((option) => option.id === access)?.label ?? null;
|
|
426
|
+
}
|
|
427
|
+
|
|
253
428
|
const MARKDOWN_EDITOR_ICON_CLASS = "block h-4 w-4 shrink-0";
|
|
254
429
|
const CODE_EDITOR_ICON_CLASS = "block h-4 w-4 shrink-0 object-contain";
|
|
255
430
|
|
|
@@ -306,6 +481,9 @@ function buildRepositoryBootstrapCommand(
|
|
|
306
481
|
if (repository.defaultBranch.trim().length > 0) {
|
|
307
482
|
initArgs.push(`--default-branch ${shellQuote(repository.defaultBranch.trim())}`);
|
|
308
483
|
}
|
|
484
|
+
if (repository.agentModel.trim().length > 0) {
|
|
485
|
+
initArgs.push(`--model ${shellQuote(repository.agentModel.trim())}`);
|
|
486
|
+
}
|
|
309
487
|
if (repository.defaultWorkingDirectory.trim().length > 0) {
|
|
310
488
|
initArgs.push(`--default-working-directory ${shellQuote(repository.defaultWorkingDirectory.trim())}`);
|
|
311
489
|
}
|
|
@@ -342,6 +520,75 @@ function MarkdownEditorIcon({ editorId }: { editorId: string }) {
|
|
|
342
520
|
return <Icon className={iconSpec.className} />;
|
|
343
521
|
}
|
|
344
522
|
|
|
523
|
+
function AgentModelSelector({
|
|
524
|
+
agent,
|
|
525
|
+
modelAccess,
|
|
526
|
+
selection,
|
|
527
|
+
onChange,
|
|
528
|
+
compact = false,
|
|
529
|
+
}: {
|
|
530
|
+
agent: string;
|
|
531
|
+
modelAccess: ModelAccessPreferences;
|
|
532
|
+
selection: ModelSelectionState;
|
|
533
|
+
onChange: (next: ModelSelectionState) => void;
|
|
534
|
+
compact?: boolean;
|
|
535
|
+
}) {
|
|
536
|
+
if (!supportsAgentModelSelection(agent)) return null;
|
|
537
|
+
|
|
538
|
+
const catalog = getAgentModelCatalog(agent);
|
|
539
|
+
const availableModels = getAvailableAgentModels(agent, modelAccess);
|
|
540
|
+
const accessLabel = getAgentModelAccessLabel(agent, modelAccess);
|
|
541
|
+
|
|
542
|
+
if (!catalog) return null;
|
|
543
|
+
|
|
544
|
+
return (
|
|
545
|
+
<div className={compact ? "grid gap-3 md:grid-cols-2" : "space-y-3"}>
|
|
546
|
+
<label className="block">
|
|
547
|
+
<span className="mb-1.5 block text-[12px] text-[var(--vk-text-muted)]">Model</span>
|
|
548
|
+
<select
|
|
549
|
+
value={selection.catalogModel}
|
|
550
|
+
onChange={(event) => {
|
|
551
|
+
onChange({
|
|
552
|
+
...selection,
|
|
553
|
+
catalogModel: event.target.value,
|
|
554
|
+
});
|
|
555
|
+
}}
|
|
556
|
+
className="h-9 w-full rounded-[4px] border border-[var(--vk-border)] bg-[var(--vk-bg-panel)] px-2 text-[14px] text-[var(--vk-text-normal)] outline-none focus:border-[var(--vk-orange)]"
|
|
557
|
+
>
|
|
558
|
+
{availableModels.map((model) => (
|
|
559
|
+
<option key={model.id} value={model.id}>
|
|
560
|
+
{model.label}
|
|
561
|
+
</option>
|
|
562
|
+
))}
|
|
563
|
+
</select>
|
|
564
|
+
<p className="mt-1 text-[11px] text-[var(--vk-text-muted)]">
|
|
565
|
+
{accessLabel
|
|
566
|
+
? `Filtered for ${accessLabel}.`
|
|
567
|
+
: "Filtered for your current access preference."} Leave custom override blank to use this selection.
|
|
568
|
+
</p>
|
|
569
|
+
</label>
|
|
570
|
+
|
|
571
|
+
<label className="block">
|
|
572
|
+
<span className="mb-1.5 block text-[12px] text-[var(--vk-text-muted)]">Custom Model Override</span>
|
|
573
|
+
<input
|
|
574
|
+
value={selection.customModel}
|
|
575
|
+
onChange={(event) => {
|
|
576
|
+
onChange({
|
|
577
|
+
...selection,
|
|
578
|
+
customModel: event.target.value,
|
|
579
|
+
});
|
|
580
|
+
}}
|
|
581
|
+
placeholder={catalog.customModelPlaceholder}
|
|
582
|
+
className="h-9 w-full rounded-[4px] border border-[var(--vk-border)] bg-transparent px-2 text-[14px] text-[var(--vk-text-normal)] outline-none focus:border-[var(--vk-orange)]"
|
|
583
|
+
/>
|
|
584
|
+
<p className="mt-1 text-[11px] text-[var(--vk-text-muted)]">
|
|
585
|
+
Optional. Use this if your provider exposes a newer model before Conductor updates its catalog.
|
|
586
|
+
</p>
|
|
587
|
+
</label>
|
|
588
|
+
</div>
|
|
589
|
+
);
|
|
590
|
+
}
|
|
591
|
+
|
|
345
592
|
export default function Home() {
|
|
346
593
|
const [selectedProjectId, setSelectedProjectId] = useState<string | null>(null);
|
|
347
594
|
const { sessions, error: sessionsError, refresh: refreshSessions } = useSessions(selectedProjectId);
|
|
@@ -353,6 +600,7 @@ export default function Home() {
|
|
|
353
600
|
|
|
354
601
|
const [prompt, setPrompt] = useState("");
|
|
355
602
|
const [selectedAgent, setSelectedAgent] = useState("");
|
|
603
|
+
const [launchModelSelection, setLaunchModelSelection] = useState<ModelSelectionState>(emptyModelSelection());
|
|
356
604
|
const [creating, setCreating] = useState(false);
|
|
357
605
|
const [createError, setCreateError] = useState<string | null>(null);
|
|
358
606
|
const [newWorkspaceOpen, setNewWorkspaceOpen] = useState(false);
|
|
@@ -398,6 +646,10 @@ export default function Home() {
|
|
|
398
646
|
() => dashboardSessions.find((s) => s.id === selectedSessionId) ?? null,
|
|
399
647
|
[dashboardSessions, selectedSessionId],
|
|
400
648
|
);
|
|
649
|
+
const selectedProject = useMemo(
|
|
650
|
+
() => projects.find((project) => project.id === selectedProjectId) ?? null,
|
|
651
|
+
[projects, selectedProjectId],
|
|
652
|
+
);
|
|
401
653
|
|
|
402
654
|
const agentOptions = useMemo(() => {
|
|
403
655
|
const safeAgents = Array.isArray(agents) ? agents : [];
|
|
@@ -477,6 +729,21 @@ export default function Home() {
|
|
|
477
729
|
}
|
|
478
730
|
}, [agentOptions, selectedAgent]);
|
|
479
731
|
|
|
732
|
+
useEffect(() => {
|
|
733
|
+
const effectiveAgent = selectedAgent || selectedProject?.agent || preferences?.codingAgent || "qwen-code";
|
|
734
|
+
const preferredModel = selectedProject && normalizeAgentName(selectedProject.agent) === normalizeAgentName(effectiveAgent)
|
|
735
|
+
? selectedProject.agentModel
|
|
736
|
+
: null;
|
|
737
|
+
|
|
738
|
+
setLaunchModelSelection(
|
|
739
|
+
buildModelSelection(
|
|
740
|
+
effectiveAgent,
|
|
741
|
+
preferences?.modelAccess ?? normalizeModelAccessPreferences(null),
|
|
742
|
+
preferredModel,
|
|
743
|
+
),
|
|
744
|
+
);
|
|
745
|
+
}, [preferences?.modelAccess, preferences?.codingAgent, selectedAgent, selectedProject]);
|
|
746
|
+
|
|
480
747
|
async function handleSavePreferences(
|
|
481
748
|
next: PreferencesPayload,
|
|
482
749
|
options?: { closeDialog?: boolean },
|
|
@@ -540,6 +807,7 @@ export default function Home() {
|
|
|
540
807
|
async function handleCreateSession() {
|
|
541
808
|
const trimmedPrompt = prompt.trim();
|
|
542
809
|
if (!trimmedPrompt) return;
|
|
810
|
+
const resolvedModel = resolveModelSelectionValue(launchModelSelection);
|
|
543
811
|
|
|
544
812
|
const projectId = selectedProjectId ?? projects[0]?.id;
|
|
545
813
|
if (!projectId) {
|
|
@@ -558,6 +826,7 @@ export default function Home() {
|
|
|
558
826
|
projectId,
|
|
559
827
|
prompt: trimmedPrompt,
|
|
560
828
|
agent: selectedAgent || "qwen-code",
|
|
829
|
+
...(resolvedModel ? { model: resolvedModel } : {}),
|
|
561
830
|
}),
|
|
562
831
|
});
|
|
563
832
|
|
|
@@ -703,6 +972,9 @@ export default function Home() {
|
|
|
703
972
|
setPrompt={setPrompt}
|
|
704
973
|
selectedAgent={selectedAgent || resolvedPreferences.codingAgent || "qwen-code"}
|
|
705
974
|
setSelectedAgent={setSelectedAgent}
|
|
975
|
+
modelSelection={launchModelSelection}
|
|
976
|
+
setModelSelection={setLaunchModelSelection}
|
|
977
|
+
modelAccess={resolvedPreferences.modelAccess}
|
|
706
978
|
agentOptions={agentOptions}
|
|
707
979
|
projectLabel={selectedProjectId ?? "No project selected"}
|
|
708
980
|
hasProject={Boolean(selectedProjectId)}
|
|
@@ -1533,6 +1805,9 @@ function CreateWorkspacePanel({
|
|
|
1533
1805
|
setPrompt,
|
|
1534
1806
|
selectedAgent,
|
|
1535
1807
|
setSelectedAgent,
|
|
1808
|
+
modelSelection,
|
|
1809
|
+
setModelSelection,
|
|
1810
|
+
modelAccess,
|
|
1536
1811
|
agentOptions,
|
|
1537
1812
|
projectLabel,
|
|
1538
1813
|
hasProject,
|
|
@@ -1545,6 +1820,9 @@ function CreateWorkspacePanel({
|
|
|
1545
1820
|
setPrompt: (value: string) => void;
|
|
1546
1821
|
selectedAgent: string;
|
|
1547
1822
|
setSelectedAgent: (value: string) => void;
|
|
1823
|
+
modelSelection: ModelSelectionState;
|
|
1824
|
+
setModelSelection: (next: ModelSelectionState) => void;
|
|
1825
|
+
modelAccess: ModelAccessPreferences;
|
|
1548
1826
|
agentOptions: string[];
|
|
1549
1827
|
projectLabel: string;
|
|
1550
1828
|
hasProject: boolean;
|
|
@@ -1628,6 +1906,18 @@ function CreateWorkspacePanel({
|
|
|
1628
1906
|
/>
|
|
1629
1907
|
</div>
|
|
1630
1908
|
|
|
1909
|
+
{supportsAgentModelSelection(selectedAgent) && (
|
|
1910
|
+
<div className="border-t border-[var(--vk-border)] px-2 py-2">
|
|
1911
|
+
<AgentModelSelector
|
|
1912
|
+
agent={selectedAgent}
|
|
1913
|
+
modelAccess={modelAccess}
|
|
1914
|
+
selection={modelSelection}
|
|
1915
|
+
onChange={setModelSelection}
|
|
1916
|
+
compact
|
|
1917
|
+
/>
|
|
1918
|
+
</div>
|
|
1919
|
+
)}
|
|
1920
|
+
|
|
1631
1921
|
<div className="flex flex-col gap-2 border-t border-[var(--vk-border)] px-2 py-2 sm:flex-row sm:items-center sm:justify-between">
|
|
1632
1922
|
<div className="flex min-w-0 items-center text-[14px] text-[var(--vk-text-normal)]">
|
|
1633
1923
|
<span className="truncate">{projectLabel}</span>
|
|
@@ -1719,6 +2009,7 @@ function SettingsDialog({
|
|
|
1719
2009
|
const [remoteSshHost, setRemoteSshHost] = useState(current.remoteSshHost);
|
|
1720
2010
|
const [remoteSshUser, setRemoteSshUser] = useState(current.remoteSshUser);
|
|
1721
2011
|
const [markdownEditor, setMarkdownEditor] = useState(current.markdownEditor);
|
|
2012
|
+
const [modelAccess, setModelAccess] = useState<ModelAccessPreferences>(current.modelAccess);
|
|
1722
2013
|
const [soundEnabled, setSoundEnabled] = useState(current.notifications.soundEnabled);
|
|
1723
2014
|
const [soundFile, setSoundFile] = useState<string | null>(current.notifications.soundFile);
|
|
1724
2015
|
const [repositories, setRepositories] = useState<RepositorySettingsPayload[]>([]);
|
|
@@ -1727,12 +2018,17 @@ function SettingsDialog({
|
|
|
1727
2018
|
const [repositoriesError, setRepositoriesError] = useState<string | null>(null);
|
|
1728
2019
|
const [selectedRepositoryId, setSelectedRepositoryId] = useState("");
|
|
1729
2020
|
const [repositoryDraft, setRepositoryDraft] = useState<RepositorySettingsPayload | null>(null);
|
|
2021
|
+
const [repositoryModelSelection, setRepositoryModelSelection] = useState<ModelSelectionState>(emptyModelSelection());
|
|
1730
2022
|
const [repositoryBranchOptions, setRepositoryBranchOptions] = useState<string[]>([]);
|
|
1731
2023
|
const [repositoryBranchesLoading, setRepositoryBranchesLoading] = useState(false);
|
|
1732
2024
|
const [repositoryBranchesError, setRepositoryBranchesError] = useState<string | null>(null);
|
|
1733
2025
|
const [repositoryFolderPickerOpen, setRepositoryFolderPickerOpen] = useState(false);
|
|
2026
|
+
const [accessSettings, setAccessSettings] = useState<AccessSettingsPayload>(() => normalizeAccessSettings(null));
|
|
2027
|
+
const [accessLoading, setAccessLoading] = useState(false);
|
|
2028
|
+
const [accessSaving, setAccessSaving] = useState(false);
|
|
2029
|
+
const [accessError, setAccessError] = useState<string | null>(null);
|
|
1734
2030
|
|
|
1735
|
-
const isBusy = creating || repositoriesSaving;
|
|
2031
|
+
const isBusy = creating || repositoriesSaving || accessSaving;
|
|
1736
2032
|
|
|
1737
2033
|
function hydrateRepositoryDraft(value: RepositorySettingsPayload): RepositorySettingsPayload {
|
|
1738
2034
|
return {
|
|
@@ -1745,6 +2041,13 @@ function SettingsDialog({
|
|
|
1745
2041
|
};
|
|
1746
2042
|
}
|
|
1747
2043
|
|
|
2044
|
+
function parseMultilineRoleList(value: string): string[] {
|
|
2045
|
+
return value
|
|
2046
|
+
.split(/\n+/g)
|
|
2047
|
+
.map((item) => item.trim())
|
|
2048
|
+
.filter(Boolean);
|
|
2049
|
+
}
|
|
2050
|
+
|
|
1748
2051
|
async function loadRepositories(preferredRepositoryId?: string): Promise<void> {
|
|
1749
2052
|
setRepositoriesLoading(true);
|
|
1750
2053
|
setRepositoriesError(null);
|
|
@@ -1771,6 +2074,7 @@ function SettingsDialog({
|
|
|
1771
2074
|
setRepositories([]);
|
|
1772
2075
|
setSelectedRepositoryId("");
|
|
1773
2076
|
setRepositoryDraft(null);
|
|
2077
|
+
setRepositoryModelSelection(emptyModelSelection());
|
|
1774
2078
|
setRepositoriesError(err instanceof Error ? err.message : "Failed to load repositories");
|
|
1775
2079
|
} finally {
|
|
1776
2080
|
setRepositoriesLoading(false);
|
|
@@ -1840,6 +2144,7 @@ function SettingsDialog({
|
|
|
1840
2144
|
repo: repositoryDraft.repo,
|
|
1841
2145
|
path: repositoryDraft.path,
|
|
1842
2146
|
agent: repositoryDraft.agent,
|
|
2147
|
+
agentModel: resolveModelSelectionValue(repositoryModelSelection) ?? "",
|
|
1843
2148
|
defaultWorkingDirectory: repositoryDraft.defaultWorkingDirectory,
|
|
1844
2149
|
defaultBranch: repositoryDraft.defaultBranch,
|
|
1845
2150
|
devServerScript: repositoryDraft.devServerScript,
|
|
@@ -1882,6 +2187,73 @@ function SettingsDialog({
|
|
|
1882
2187
|
}
|
|
1883
2188
|
}
|
|
1884
2189
|
|
|
2190
|
+
async function loadAccessSettings(): Promise<void> {
|
|
2191
|
+
setAccessLoading(true);
|
|
2192
|
+
setAccessError(null);
|
|
2193
|
+
try {
|
|
2194
|
+
const res = await fetch("/api/access");
|
|
2195
|
+
const data = (await res.json().catch(() => null)) as
|
|
2196
|
+
| { access?: unknown; current?: unknown; error?: string }
|
|
2197
|
+
| null;
|
|
2198
|
+
if (!res.ok) {
|
|
2199
|
+
throw new Error(data?.error ?? `Failed to load organization settings (${res.status})`);
|
|
2200
|
+
}
|
|
2201
|
+
setAccessSettings(normalizeAccessSettings(data?.access, data?.current));
|
|
2202
|
+
} catch (err) {
|
|
2203
|
+
setAccessSettings(normalizeAccessSettings(null));
|
|
2204
|
+
setAccessError(err instanceof Error ? err.message : "Failed to load organization settings");
|
|
2205
|
+
} finally {
|
|
2206
|
+
setAccessLoading(false);
|
|
2207
|
+
}
|
|
2208
|
+
}
|
|
2209
|
+
|
|
2210
|
+
async function handleSaveAccess(): Promise<boolean> {
|
|
2211
|
+
if (accessSaving) return false;
|
|
2212
|
+
|
|
2213
|
+
setAccessSaving(true);
|
|
2214
|
+
setAccessError(null);
|
|
2215
|
+
try {
|
|
2216
|
+
const res = await fetch("/api/access", {
|
|
2217
|
+
method: "PUT",
|
|
2218
|
+
headers: { "Content-Type": "application/json" },
|
|
2219
|
+
body: JSON.stringify({
|
|
2220
|
+
requireAuth: accessSettings.requireAuth,
|
|
2221
|
+
defaultRole: accessSettings.defaultRole,
|
|
2222
|
+
trustedHeaders: {
|
|
2223
|
+
enabled: accessSettings.trustedHeaders.enabled,
|
|
2224
|
+
provider: accessSettings.trustedHeaders.provider,
|
|
2225
|
+
emailHeader: accessSettings.trustedHeaders.emailHeader,
|
|
2226
|
+
jwtHeader: accessSettings.trustedHeaders.jwtHeader,
|
|
2227
|
+
teamDomain: accessSettings.trustedHeaders.teamDomain,
|
|
2228
|
+
audience: accessSettings.trustedHeaders.audience,
|
|
2229
|
+
},
|
|
2230
|
+
roles: {
|
|
2231
|
+
viewers: parseMultilineRoleList(accessSettings.roles.viewers),
|
|
2232
|
+
operators: parseMultilineRoleList(accessSettings.roles.operators),
|
|
2233
|
+
admins: parseMultilineRoleList(accessSettings.roles.admins),
|
|
2234
|
+
viewerDomains: parseMultilineRoleList(accessSettings.roles.viewerDomains),
|
|
2235
|
+
operatorDomains: parseMultilineRoleList(accessSettings.roles.operatorDomains),
|
|
2236
|
+
adminDomains: parseMultilineRoleList(accessSettings.roles.adminDomains),
|
|
2237
|
+
},
|
|
2238
|
+
}),
|
|
2239
|
+
});
|
|
2240
|
+
const data = (await res.json().catch(() => null)) as
|
|
2241
|
+
| { access?: unknown; current?: unknown; error?: string }
|
|
2242
|
+
| null;
|
|
2243
|
+
if (!res.ok) {
|
|
2244
|
+
throw new Error(data?.error ?? `Failed to save organization settings (${res.status})`);
|
|
2245
|
+
}
|
|
2246
|
+
|
|
2247
|
+
setAccessSettings(normalizeAccessSettings(data?.access, data?.current));
|
|
2248
|
+
return true;
|
|
2249
|
+
} catch (err) {
|
|
2250
|
+
setAccessError(err instanceof Error ? err.message : "Failed to save organization settings");
|
|
2251
|
+
return false;
|
|
2252
|
+
} finally {
|
|
2253
|
+
setAccessSaving(false);
|
|
2254
|
+
}
|
|
2255
|
+
}
|
|
2256
|
+
|
|
1885
2257
|
useEffect(() => {
|
|
1886
2258
|
if (!open) return;
|
|
1887
2259
|
setActiveTab("preferences");
|
|
@@ -1890,10 +2262,13 @@ function SettingsDialog({
|
|
|
1890
2262
|
setRemoteSshHost(current.remoteSshHost);
|
|
1891
2263
|
setRemoteSshUser(current.remoteSshUser);
|
|
1892
2264
|
setMarkdownEditor(current.markdownEditor);
|
|
2265
|
+
setModelAccess(current.modelAccess);
|
|
1893
2266
|
setSoundEnabled(current.notifications.soundEnabled);
|
|
1894
2267
|
setSoundFile(current.notifications.soundFile);
|
|
1895
2268
|
setRepositoryBranchOptions([]);
|
|
1896
2269
|
setRepositoryBranchesError(null);
|
|
2270
|
+
setRepositoryModelSelection(emptyModelSelection());
|
|
2271
|
+
setAccessError(null);
|
|
1897
2272
|
}, [open]);
|
|
1898
2273
|
|
|
1899
2274
|
useEffect(() => {
|
|
@@ -1902,22 +2277,32 @@ function SettingsDialog({
|
|
|
1902
2277
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1903
2278
|
}, [open]);
|
|
1904
2279
|
|
|
2280
|
+
useEffect(() => {
|
|
2281
|
+
if (!open || mode === "onboarding") return;
|
|
2282
|
+
void loadAccessSettings();
|
|
2283
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2284
|
+
}, [mode, open]);
|
|
2285
|
+
|
|
1905
2286
|
useEffect(() => {
|
|
1906
2287
|
if (!open) return;
|
|
1907
2288
|
if (!selectedRepositoryId) {
|
|
1908
2289
|
setRepositoryDraft(null);
|
|
2290
|
+
setRepositoryModelSelection(emptyModelSelection());
|
|
1909
2291
|
return;
|
|
1910
2292
|
}
|
|
1911
2293
|
const selected = repositories.find((item) => item.id === selectedRepositoryId);
|
|
1912
2294
|
if (!selected) return;
|
|
1913
2295
|
setRepositoryDraft(hydrateRepositoryDraft(selected));
|
|
2296
|
+
setRepositoryModelSelection(
|
|
2297
|
+
buildModelSelection(selected.agent, modelAccess, selected.agentModel),
|
|
2298
|
+
);
|
|
1914
2299
|
setRepositoryBranchOptions([]);
|
|
1915
2300
|
setRepositoryBranchesError(null);
|
|
1916
2301
|
if (selected.path.trim().length > 0) {
|
|
1917
2302
|
void detectRepositoryBranches(selected.path, selected.defaultBranch);
|
|
1918
2303
|
}
|
|
1919
2304
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1920
|
-
}, [open, repositories, selectedRepositoryId]);
|
|
2305
|
+
}, [modelAccess, open, repositories, selectedRepositoryId]);
|
|
1921
2306
|
|
|
1922
2307
|
const onboardingShouldShowRepositoryStep = mode === "onboarding"
|
|
1923
2308
|
&& (repositoriesLoading || repositories.length > 0);
|
|
@@ -1935,8 +2320,10 @@ function SettingsDialog({
|
|
|
1935
2320
|
const isOnboarding = mode === "onboarding";
|
|
1936
2321
|
const isPreferencesTab = activeTabItem.id === "preferences";
|
|
1937
2322
|
const isRepositoriesTab = activeTabItem.id === "repositories";
|
|
2323
|
+
const isOrganizationTab = activeTabItem.id === "organization";
|
|
1938
2324
|
const onboardingStepIndex = visibleTabs.findIndex((tab) => tab.id === activeTabItem.id) + 1;
|
|
1939
2325
|
const onboardingHasRepositoryStep = visibleTabs.some((tab) => tab.id === "repositories");
|
|
2326
|
+
const accessCanEdit = accessSettings.current.role === "admin";
|
|
1940
2327
|
|
|
1941
2328
|
const orderedAgentOptions = useMemo(() => {
|
|
1942
2329
|
const opts = new Set(agentOptions);
|
|
@@ -1955,6 +2342,16 @@ function SettingsDialog({
|
|
|
1955
2342
|
});
|
|
1956
2343
|
}, [agentOptions, codingAgent]);
|
|
1957
2344
|
|
|
2345
|
+
function handleModelAccessChange(agent: string, nextAccess: string) {
|
|
2346
|
+
const catalog = getAgentModelCatalog(agent);
|
|
2347
|
+
if (!catalog) return;
|
|
2348
|
+
|
|
2349
|
+
setModelAccess((prev) => ({
|
|
2350
|
+
...prev,
|
|
2351
|
+
[catalog.accessKey]: nextAccess,
|
|
2352
|
+
} as ModelAccessPreferences));
|
|
2353
|
+
}
|
|
2354
|
+
|
|
1958
2355
|
if (!open) return null;
|
|
1959
2356
|
|
|
1960
2357
|
const canSubmitPreferences = codingAgent.trim().length > 0
|
|
@@ -1965,8 +2362,32 @@ function SettingsDialog({
|
|
|
1965
2362
|
&& repositoryDraft.repo.trim().length > 0
|
|
1966
2363
|
&& repositoryDraft.path.trim().length > 0
|
|
1967
2364
|
&& repositoryDraft.defaultBranch.trim().length > 0;
|
|
2365
|
+
const canSaveAccess = accessCanEdit && !accessLoading && (
|
|
2366
|
+
!accessSettings.trustedHeaders.enabled
|
|
2367
|
+
|| accessSettings.trustedHeaders.provider === "generic"
|
|
2368
|
+
|| (
|
|
2369
|
+
accessSettings.trustedHeaders.teamDomain.trim().length > 0
|
|
2370
|
+
&& accessSettings.trustedHeaders.audience.trim().length > 0
|
|
2371
|
+
)
|
|
2372
|
+
);
|
|
2373
|
+
const dialogError = isRepositoriesTab ? repositoriesError : isOrganizationTab ? accessError : error;
|
|
2374
|
+
const accessRoleFields: Array<{
|
|
2375
|
+
label: string;
|
|
2376
|
+
key: keyof AccessSettingsPayload["roles"];
|
|
2377
|
+
placeholder: string;
|
|
2378
|
+
}> = [
|
|
2379
|
+
{ label: "Viewer Emails", key: "viewers", placeholder: "alice@example.com" },
|
|
2380
|
+
{ label: "Operator Emails", key: "operators", placeholder: "builder@example.com" },
|
|
2381
|
+
{ label: "Admin Emails", key: "admins", placeholder: "owner@example.com" },
|
|
2382
|
+
{ label: "Viewer Domains", key: "viewerDomains", placeholder: "guests.example.com" },
|
|
2383
|
+
{ label: "Operator Domains", key: "operatorDomains", placeholder: "eng.example.com" },
|
|
2384
|
+
{ label: "Admin Domains", key: "adminDomains", placeholder: "admins.example.com" },
|
|
2385
|
+
];
|
|
1968
2386
|
const repositoryBootstrapCommand = repositoryDraft
|
|
1969
|
-
? buildRepositoryBootstrapCommand(
|
|
2387
|
+
? buildRepositoryBootstrapCommand({
|
|
2388
|
+
...repositoryDraft,
|
|
2389
|
+
agentModel: resolveModelSelectionValue(repositoryModelSelection) ?? "",
|
|
2390
|
+
}, {
|
|
1970
2391
|
ide,
|
|
1971
2392
|
markdownEditor,
|
|
1972
2393
|
})
|
|
@@ -1984,6 +2405,7 @@ function SettingsDialog({
|
|
|
1984
2405
|
remoteSshHost: remoteSshHost.trim(),
|
|
1985
2406
|
remoteSshUser: remoteSshUser.trim(),
|
|
1986
2407
|
markdownEditor: markdownEditor.trim(),
|
|
2408
|
+
modelAccess,
|
|
1987
2409
|
notifications: {
|
|
1988
2410
|
soundEnabled,
|
|
1989
2411
|
soundFile: resolvedSoundFile,
|
|
@@ -2130,6 +2552,44 @@ function SettingsDialog({
|
|
|
2130
2552
|
</div>
|
|
2131
2553
|
</section>
|
|
2132
2554
|
|
|
2555
|
+
<section className="space-y-3">
|
|
2556
|
+
<div className="space-y-1">
|
|
2557
|
+
<h4 className="text-[15px] font-medium text-[var(--vk-text-strong)]">Model Access</h4>
|
|
2558
|
+
<p className="text-[12px] text-[var(--vk-text-muted)]">
|
|
2559
|
+
Tell Conductor which account mode each agent is using so the model dropdown only shows options
|
|
2560
|
+
that make sense for that login path.
|
|
2561
|
+
</p>
|
|
2562
|
+
</div>
|
|
2563
|
+
<div className="grid gap-3">
|
|
2564
|
+
{orderedAgentOptions.filter((agent) => supportsAgentModelSelection(agent)).map((agent) => {
|
|
2565
|
+
const catalog = getAgentModelCatalog(agent);
|
|
2566
|
+
if (!catalog) return null;
|
|
2567
|
+
const selectedAccess = resolveAgentModelAccess(agent, modelAccess) ?? catalog.defaultAccess;
|
|
2568
|
+
return (
|
|
2569
|
+
<label key={agent} className="block rounded-[4px] border border-[var(--vk-border)] px-3 py-3">
|
|
2570
|
+
<span className="mb-1 block text-[13px] font-medium text-[var(--vk-text-normal)]">
|
|
2571
|
+
{catalog.label}
|
|
2572
|
+
</span>
|
|
2573
|
+
<select
|
|
2574
|
+
value={selectedAccess}
|
|
2575
|
+
onChange={(event) => handleModelAccessChange(agent, event.target.value)}
|
|
2576
|
+
className="h-9 w-full rounded-[4px] border border-[var(--vk-border)] bg-[var(--vk-bg-panel)] px-2 text-[13px] text-[var(--vk-text-normal)] outline-none focus:border-[var(--vk-orange)]"
|
|
2577
|
+
>
|
|
2578
|
+
{catalog.accessOptions.map((option) => (
|
|
2579
|
+
<option key={option.id} value={option.id}>
|
|
2580
|
+
{option.label}
|
|
2581
|
+
</option>
|
|
2582
|
+
))}
|
|
2583
|
+
</select>
|
|
2584
|
+
<p className="mt-1.5 text-[11px] text-[var(--vk-text-muted)]">
|
|
2585
|
+
{catalog.accessOptions.find((option) => option.id === selectedAccess)?.description}
|
|
2586
|
+
</p>
|
|
2587
|
+
</label>
|
|
2588
|
+
);
|
|
2589
|
+
})}
|
|
2590
|
+
</div>
|
|
2591
|
+
</section>
|
|
2592
|
+
|
|
2133
2593
|
<section className="space-y-2">
|
|
2134
2594
|
<h4 className="text-[15px] font-medium text-[var(--vk-text-strong)]">Choose Your Code Editor</h4>
|
|
2135
2595
|
<p className="text-[12px] text-[var(--vk-text-muted)]">This editor will be used when opening attempts and files.</p>
|
|
@@ -2383,7 +2843,11 @@ function SettingsDialog({
|
|
|
2383
2843
|
<span className="mb-1.5 block text-[12px] font-medium text-[var(--vk-text-normal)]">Default Agent</span>
|
|
2384
2844
|
<select
|
|
2385
2845
|
value={repositoryDraft.agent}
|
|
2386
|
-
onChange={(event) =>
|
|
2846
|
+
onChange={(event) => {
|
|
2847
|
+
const nextAgent = event.target.value;
|
|
2848
|
+
setRepositoryDraft((prev) => prev ? { ...prev, agent: nextAgent } : prev);
|
|
2849
|
+
setRepositoryModelSelection(buildModelSelection(nextAgent, modelAccess, null));
|
|
2850
|
+
}}
|
|
2387
2851
|
className="h-9 w-full rounded-[4px] border border-[var(--vk-border)] bg-[var(--vk-bg-panel)] px-2 text-[13px] text-[var(--vk-text-normal)] outline-none focus:border-[var(--vk-orange)]"
|
|
2388
2852
|
>
|
|
2389
2853
|
{orderedAgentOptions.map((agent) => (
|
|
@@ -2395,6 +2859,17 @@ function SettingsDialog({
|
|
|
2395
2859
|
<p className="mt-1 text-[12px] text-[var(--vk-text-muted)]">Used by the one-line bootstrap and as the project default when tasks dispatch.</p>
|
|
2396
2860
|
</label>
|
|
2397
2861
|
|
|
2862
|
+
{supportsAgentModelSelection(repositoryDraft.agent) && (
|
|
2863
|
+
<div className="rounded-[4px] border border-[var(--vk-border)] px-3 py-3">
|
|
2864
|
+
<AgentModelSelector
|
|
2865
|
+
agent={repositoryDraft.agent}
|
|
2866
|
+
modelAccess={modelAccess}
|
|
2867
|
+
selection={repositoryModelSelection}
|
|
2868
|
+
onChange={setRepositoryModelSelection}
|
|
2869
|
+
/>
|
|
2870
|
+
</div>
|
|
2871
|
+
)}
|
|
2872
|
+
|
|
2398
2873
|
<label className="block">
|
|
2399
2874
|
<span className="mb-1.5 block text-[12px] font-medium text-[var(--vk-text-normal)]">Repository Path</span>
|
|
2400
2875
|
<div className="flex items-center gap-2">
|
|
@@ -2586,6 +3061,262 @@ function SettingsDialog({
|
|
|
2586
3061
|
</>
|
|
2587
3062
|
)}
|
|
2588
3063
|
</div>
|
|
3064
|
+
) : isOrganizationTab ? (
|
|
3065
|
+
<div className="space-y-5">
|
|
3066
|
+
<section className="rounded-[6px] border border-[var(--vk-border)] bg-[rgba(234,122,42,0.06)] px-4 py-3">
|
|
3067
|
+
<h4 className="text-[15px] font-medium text-[var(--vk-text-strong)]">Security-First Remote Access</h4>
|
|
3068
|
+
<p className="mt-1 text-[12px] leading-5 text-[var(--vk-text-muted)]">
|
|
3069
|
+
The dashboard stays bound to localhost. For phone and team access, put a verified edge
|
|
3070
|
+
identity layer like Cloudflare Access in front of it, then map authenticated users into
|
|
3071
|
+
viewer, operator, or admin roles here.
|
|
3072
|
+
</p>
|
|
3073
|
+
</section>
|
|
3074
|
+
|
|
3075
|
+
{accessLoading ? (
|
|
3076
|
+
<section className="flex items-center gap-2 rounded-[6px] border border-[var(--vk-border)] px-4 py-4 text-[13px] text-[var(--vk-text-muted)]">
|
|
3077
|
+
<Loader2 className="h-4 w-4 animate-spin" />
|
|
3078
|
+
Loading organization access settings...
|
|
3079
|
+
</section>
|
|
3080
|
+
) : (
|
|
3081
|
+
<>
|
|
3082
|
+
<section className="grid gap-3 lg:grid-cols-3">
|
|
3083
|
+
<div className="rounded-[6px] border border-[var(--vk-border)] px-4 py-3">
|
|
3084
|
+
<span className="text-[11px] uppercase tracking-[0.12em] text-[var(--vk-text-muted)]">
|
|
3085
|
+
Current Identity
|
|
3086
|
+
</span>
|
|
3087
|
+
<p className="mt-2 text-[14px] text-[var(--vk-text-normal)]">
|
|
3088
|
+
{accessSettings.current.email ?? "Anonymous local session"}
|
|
3089
|
+
</p>
|
|
3090
|
+
</div>
|
|
3091
|
+
<div className="rounded-[6px] border border-[var(--vk-border)] px-4 py-3">
|
|
3092
|
+
<span className="text-[11px] uppercase tracking-[0.12em] text-[var(--vk-text-muted)]">
|
|
3093
|
+
Effective Role
|
|
3094
|
+
</span>
|
|
3095
|
+
<p className="mt-2 text-[14px] text-[var(--vk-text-normal)]">
|
|
3096
|
+
{accessSettings.current.role ?? "No access"}
|
|
3097
|
+
</p>
|
|
3098
|
+
</div>
|
|
3099
|
+
<div className="rounded-[6px] border border-[var(--vk-border)] px-4 py-3">
|
|
3100
|
+
<span className="text-[11px] uppercase tracking-[0.12em] text-[var(--vk-text-muted)]">
|
|
3101
|
+
Auth Provider
|
|
3102
|
+
</span>
|
|
3103
|
+
<p className="mt-2 text-[14px] text-[var(--vk-text-normal)]">
|
|
3104
|
+
{accessSettings.current.provider ?? "Local only"}
|
|
3105
|
+
</p>
|
|
3106
|
+
</div>
|
|
3107
|
+
</section>
|
|
3108
|
+
|
|
3109
|
+
{!accessCanEdit && (
|
|
3110
|
+
<section className="rounded-[6px] border border-[var(--vk-border)] bg-[rgba(80,80,80,0.18)] px-4 py-3">
|
|
3111
|
+
<p className="text-[12px] leading-5 text-[var(--vk-text-muted)]">
|
|
3112
|
+
You can review organization security here, but only an admin session can save changes.
|
|
3113
|
+
Use the built-in unlock link, a local admin session, or an admin identity from your edge
|
|
3114
|
+
auth provider to modify access rules.
|
|
3115
|
+
</p>
|
|
3116
|
+
</section>
|
|
3117
|
+
)}
|
|
3118
|
+
|
|
3119
|
+
<section className="space-y-3 rounded-[6px] border border-[var(--vk-border)] px-4 py-4">
|
|
3120
|
+
<div className="space-y-1">
|
|
3121
|
+
<h5 className="text-[18px] leading-[20px] text-[var(--vk-text-strong)]">Baseline Access Rules</h5>
|
|
3122
|
+
<p className="text-[12px] text-[var(--vk-text-muted)]">
|
|
3123
|
+
Require authentication for every dashboard request and decide what authenticated users get
|
|
3124
|
+
by default before explicit role bindings are applied.
|
|
3125
|
+
</p>
|
|
3126
|
+
</div>
|
|
3127
|
+
|
|
3128
|
+
<label className="flex items-start gap-2 rounded-[4px] border border-[var(--vk-border)] px-3 py-2 text-[13px] text-[var(--vk-text-normal)]">
|
|
3129
|
+
<input
|
|
3130
|
+
type="checkbox"
|
|
3131
|
+
checked={accessSettings.requireAuth}
|
|
3132
|
+
onChange={(event) => setAccessSettings((prev) => ({
|
|
3133
|
+
...prev,
|
|
3134
|
+
requireAuth: event.target.checked,
|
|
3135
|
+
}))}
|
|
3136
|
+
disabled={!accessCanEdit || accessSaving}
|
|
3137
|
+
className="mt-0.5 h-4 w-4 rounded border border-[var(--vk-border)] bg-transparent accent-[var(--vk-orange)]"
|
|
3138
|
+
/>
|
|
3139
|
+
<span>Require authentication even on localhost</span>
|
|
3140
|
+
</label>
|
|
3141
|
+
|
|
3142
|
+
<label className="block">
|
|
3143
|
+
<span className="mb-1.5 block text-[12px] font-medium text-[var(--vk-text-normal)]">Default Role</span>
|
|
3144
|
+
<select
|
|
3145
|
+
value={accessSettings.defaultRole}
|
|
3146
|
+
onChange={(event) => setAccessSettings((prev) => ({
|
|
3147
|
+
...prev,
|
|
3148
|
+
defaultRole: event.target.value as DashboardRole,
|
|
3149
|
+
}))}
|
|
3150
|
+
disabled={!accessCanEdit || accessSaving}
|
|
3151
|
+
className="h-9 w-full rounded-[4px] border border-[var(--vk-border)] bg-[var(--vk-bg-panel)] px-2 text-[13px] text-[var(--vk-text-normal)] outline-none focus:border-[var(--vk-orange)] disabled:opacity-60"
|
|
3152
|
+
>
|
|
3153
|
+
<option value="viewer">Viewer</option>
|
|
3154
|
+
<option value="operator">Operator</option>
|
|
3155
|
+
<option value="admin">Admin</option>
|
|
3156
|
+
</select>
|
|
3157
|
+
<p className="mt-1 text-[12px] text-[var(--vk-text-muted)]">
|
|
3158
|
+
This applies after identity verification when no explicit email or domain binding matches.
|
|
3159
|
+
</p>
|
|
3160
|
+
</label>
|
|
3161
|
+
</section>
|
|
3162
|
+
|
|
3163
|
+
<section className="space-y-3 rounded-[6px] border border-[var(--vk-border)] px-4 py-4">
|
|
3164
|
+
<div className="space-y-1">
|
|
3165
|
+
<h5 className="text-[18px] leading-[20px] text-[var(--vk-text-strong)]">Verified Edge Auth</h5>
|
|
3166
|
+
<p className="text-[12px] text-[var(--vk-text-muted)]">
|
|
3167
|
+
Recommended for secure public phone access and free team collaboration. Conductor verifies
|
|
3168
|
+
the Cloudflare Access JWT instead of trusting a raw email header.
|
|
3169
|
+
</p>
|
|
3170
|
+
</div>
|
|
3171
|
+
|
|
3172
|
+
<label className="flex items-start gap-2 rounded-[4px] border border-[var(--vk-border)] px-3 py-2 text-[13px] text-[var(--vk-text-normal)]">
|
|
3173
|
+
<input
|
|
3174
|
+
type="checkbox"
|
|
3175
|
+
checked={accessSettings.trustedHeaders.enabled}
|
|
3176
|
+
onChange={(event) => setAccessSettings((prev) => ({
|
|
3177
|
+
...prev,
|
|
3178
|
+
trustedHeaders: {
|
|
3179
|
+
...prev.trustedHeaders,
|
|
3180
|
+
enabled: event.target.checked,
|
|
3181
|
+
},
|
|
3182
|
+
}))}
|
|
3183
|
+
disabled={!accessCanEdit || accessSaving}
|
|
3184
|
+
className="mt-0.5 h-4 w-4 rounded border border-[var(--vk-border)] bg-transparent accent-[var(--vk-orange)]"
|
|
3185
|
+
/>
|
|
3186
|
+
<span>Enable verified Cloudflare Access authentication</span>
|
|
3187
|
+
</label>
|
|
3188
|
+
|
|
3189
|
+
<div className="grid gap-3 lg:grid-cols-2">
|
|
3190
|
+
<label className="block">
|
|
3191
|
+
<span className="mb-1.5 block text-[12px] font-medium text-[var(--vk-text-normal)]">Provider</span>
|
|
3192
|
+
<select
|
|
3193
|
+
value={accessSettings.trustedHeaders.provider}
|
|
3194
|
+
onChange={(event) => setAccessSettings((prev) => ({
|
|
3195
|
+
...prev,
|
|
3196
|
+
trustedHeaders: {
|
|
3197
|
+
...prev.trustedHeaders,
|
|
3198
|
+
provider: event.target.value as TrustedHeaderAccessProvider,
|
|
3199
|
+
},
|
|
3200
|
+
}))}
|
|
3201
|
+
disabled={!accessCanEdit || accessSaving}
|
|
3202
|
+
className="h-9 w-full rounded-[4px] border border-[var(--vk-border)] bg-[var(--vk-bg-panel)] px-2 text-[13px] text-[var(--vk-text-normal)] outline-none focus:border-[var(--vk-orange)] disabled:opacity-60"
|
|
3203
|
+
>
|
|
3204
|
+
<option value="cloudflare-access">Cloudflare Access (verified JWT)</option>
|
|
3205
|
+
<option value="generic">Generic header passthrough (advanced)</option>
|
|
3206
|
+
</select>
|
|
3207
|
+
</label>
|
|
3208
|
+
|
|
3209
|
+
<label className="block">
|
|
3210
|
+
<span className="mb-1.5 block text-[12px] font-medium text-[var(--vk-text-normal)]">Identity Email Header</span>
|
|
3211
|
+
<input
|
|
3212
|
+
value={accessSettings.trustedHeaders.emailHeader}
|
|
3213
|
+
onChange={(event) => setAccessSettings((prev) => ({
|
|
3214
|
+
...prev,
|
|
3215
|
+
trustedHeaders: {
|
|
3216
|
+
...prev.trustedHeaders,
|
|
3217
|
+
emailHeader: event.target.value,
|
|
3218
|
+
},
|
|
3219
|
+
}))}
|
|
3220
|
+
disabled={!accessCanEdit || accessSaving}
|
|
3221
|
+
className="h-9 w-full rounded-[4px] border border-[var(--vk-border)] bg-transparent px-2 text-[13px] text-[var(--vk-text-normal)] outline-none focus:border-[var(--vk-orange)] disabled:opacity-60"
|
|
3222
|
+
/>
|
|
3223
|
+
</label>
|
|
3224
|
+
|
|
3225
|
+
<label className="block">
|
|
3226
|
+
<span className="mb-1.5 block text-[12px] font-medium text-[var(--vk-text-normal)]">JWT Assertion Header</span>
|
|
3227
|
+
<input
|
|
3228
|
+
value={accessSettings.trustedHeaders.jwtHeader}
|
|
3229
|
+
onChange={(event) => setAccessSettings((prev) => ({
|
|
3230
|
+
...prev,
|
|
3231
|
+
trustedHeaders: {
|
|
3232
|
+
...prev.trustedHeaders,
|
|
3233
|
+
jwtHeader: event.target.value,
|
|
3234
|
+
},
|
|
3235
|
+
}))}
|
|
3236
|
+
disabled={!accessCanEdit || accessSaving}
|
|
3237
|
+
className="h-9 w-full rounded-[4px] border border-[var(--vk-border)] bg-transparent px-2 text-[13px] text-[var(--vk-text-normal)] outline-none focus:border-[var(--vk-orange)] disabled:opacity-60"
|
|
3238
|
+
/>
|
|
3239
|
+
</label>
|
|
3240
|
+
|
|
3241
|
+
<label className="block">
|
|
3242
|
+
<span className="mb-1.5 block text-[12px] font-medium text-[var(--vk-text-normal)]">Cloudflare Team Domain</span>
|
|
3243
|
+
<input
|
|
3244
|
+
value={accessSettings.trustedHeaders.teamDomain}
|
|
3245
|
+
onChange={(event) => setAccessSettings((prev) => ({
|
|
3246
|
+
...prev,
|
|
3247
|
+
trustedHeaders: {
|
|
3248
|
+
...prev.trustedHeaders,
|
|
3249
|
+
teamDomain: event.target.value,
|
|
3250
|
+
},
|
|
3251
|
+
}))}
|
|
3252
|
+
disabled={!accessCanEdit || accessSaving}
|
|
3253
|
+
placeholder="your-team.cloudflareaccess.com"
|
|
3254
|
+
className="h-9 w-full rounded-[4px] border border-[var(--vk-border)] bg-transparent px-2 text-[13px] text-[var(--vk-text-normal)] outline-none focus:border-[var(--vk-orange)] disabled:opacity-60"
|
|
3255
|
+
/>
|
|
3256
|
+
</label>
|
|
3257
|
+
|
|
3258
|
+
<label className="block lg:col-span-2">
|
|
3259
|
+
<span className="mb-1.5 block text-[12px] font-medium text-[var(--vk-text-normal)]">Cloudflare Access Audience</span>
|
|
3260
|
+
<input
|
|
3261
|
+
value={accessSettings.trustedHeaders.audience}
|
|
3262
|
+
onChange={(event) => setAccessSettings((prev) => ({
|
|
3263
|
+
...prev,
|
|
3264
|
+
trustedHeaders: {
|
|
3265
|
+
...prev.trustedHeaders,
|
|
3266
|
+
audience: event.target.value,
|
|
3267
|
+
},
|
|
3268
|
+
}))}
|
|
3269
|
+
disabled={!accessCanEdit || accessSaving}
|
|
3270
|
+
placeholder="Copy the AUD value from your Cloudflare Access application"
|
|
3271
|
+
className="h-9 w-full rounded-[4px] border border-[var(--vk-border)] bg-transparent px-2 text-[13px] text-[var(--vk-text-normal)] outline-none focus:border-[var(--vk-orange)] disabled:opacity-60"
|
|
3272
|
+
/>
|
|
3273
|
+
</label>
|
|
3274
|
+
</div>
|
|
3275
|
+
|
|
3276
|
+
{accessSettings.trustedHeaders.provider === "generic" && (
|
|
3277
|
+
<p className="rounded-[4px] border border-[var(--vk-red)]/35 bg-[var(--vk-red)]/10 px-3 py-2 text-[12px] leading-5 text-[var(--vk-red)]">
|
|
3278
|
+
Generic header passthrough is only safe when your reverse proxy strips user-supplied headers
|
|
3279
|
+
and injects identity itself. Conductor blocks this mode by default unless
|
|
3280
|
+
`CONDUCTOR_ALLOW_INSECURE_TRUSTED_HEADERS=true` is also set.
|
|
3281
|
+
</p>
|
|
3282
|
+
)}
|
|
3283
|
+
</section>
|
|
3284
|
+
|
|
3285
|
+
<section className="space-y-3 rounded-[6px] border border-[var(--vk-border)] px-4 py-4">
|
|
3286
|
+
<div className="space-y-1">
|
|
3287
|
+
<h5 className="text-[18px] leading-[20px] text-[var(--vk-text-strong)]">Role Bindings</h5>
|
|
3288
|
+
<p className="text-[12px] text-[var(--vk-text-muted)]">
|
|
3289
|
+
Map verified team identities into least-privilege roles. `viewer` can inspect work, `operator`
|
|
3290
|
+
can control agents, and `admin` can change global settings.
|
|
3291
|
+
</p>
|
|
3292
|
+
</div>
|
|
3293
|
+
|
|
3294
|
+
<div className="grid gap-3 lg:grid-cols-2">
|
|
3295
|
+
{accessRoleFields.map(({ label, key, placeholder }) => (
|
|
3296
|
+
<label key={key} className="block">
|
|
3297
|
+
<span className="mb-1.5 block text-[12px] font-medium text-[var(--vk-text-normal)]">{label}</span>
|
|
3298
|
+
<textarea
|
|
3299
|
+
rows={4}
|
|
3300
|
+
value={accessSettings.roles[key]}
|
|
3301
|
+
onChange={(event) => setAccessSettings((prev) => ({
|
|
3302
|
+
...prev,
|
|
3303
|
+
roles: {
|
|
3304
|
+
...prev.roles,
|
|
3305
|
+
[key]: event.target.value,
|
|
3306
|
+
},
|
|
3307
|
+
}))}
|
|
3308
|
+
disabled={!accessCanEdit || accessSaving}
|
|
3309
|
+
placeholder={placeholder}
|
|
3310
|
+
className="w-full rounded-[4px] border border-[var(--vk-border)] bg-transparent px-2 py-2 text-[13px] text-[var(--vk-text-normal)] outline-none focus:border-[var(--vk-orange)] disabled:opacity-60"
|
|
3311
|
+
/>
|
|
3312
|
+
<p className="mt-1 text-[11px] text-[var(--vk-text-muted)]">One entry per line.</p>
|
|
3313
|
+
</label>
|
|
3314
|
+
))}
|
|
3315
|
+
</div>
|
|
3316
|
+
</section>
|
|
3317
|
+
</>
|
|
3318
|
+
)}
|
|
3319
|
+
</div>
|
|
2589
3320
|
) : (
|
|
2590
3321
|
<section className="space-y-3">
|
|
2591
3322
|
<h4 className="text-[16px] font-medium text-[var(--vk-text-strong)]">{activeTabItem.label}</h4>
|
|
@@ -2605,25 +3336,31 @@ function SettingsDialog({
|
|
|
2605
3336
|
|
|
2606
3337
|
<footer className="flex flex-col gap-3 border-t border-[var(--vk-border)] px-4 py-3 sm:flex-row sm:items-center sm:justify-between sm:gap-2">
|
|
2607
3338
|
<div className="min-w-0">
|
|
2608
|
-
{
|
|
3339
|
+
{dialogError && (
|
|
2609
3340
|
<p className="truncate rounded-[4px] border border-[var(--vk-red)]/35 bg-[var(--vk-red)]/10 px-2 py-1 text-[12px] text-[var(--vk-red)]">
|
|
2610
|
-
{
|
|
3341
|
+
{dialogError}
|
|
2611
3342
|
</p>
|
|
2612
3343
|
)}
|
|
2613
|
-
{!
|
|
3344
|
+
{!dialogError && isPreferencesTab && (
|
|
2614
3345
|
<p className="text-[11px] text-[var(--vk-text-muted)]">
|
|
2615
3346
|
{isOnboarding
|
|
2616
3347
|
? "Finish setup once here. You can change these preferences any time from Settings."
|
|
2617
3348
|
: "Preferences are saved to your conductor config and applied immediately."}
|
|
2618
3349
|
</p>
|
|
2619
3350
|
)}
|
|
2620
|
-
{!
|
|
3351
|
+
{!dialogError && isRepositoriesTab && (
|
|
2621
3352
|
<p className="text-[11px] text-[var(--vk-text-muted)]">
|
|
2622
3353
|
{isOnboarding
|
|
2623
3354
|
? "These defaults will be used the first time workspaces and tasks are created for this repo."
|
|
2624
3355
|
: "Repository settings are saved to your conductor config and used for future workspaces."}
|
|
2625
3356
|
</p>
|
|
2626
3357
|
)}
|
|
3358
|
+
{!dialogError && isOrganizationTab && (
|
|
3359
|
+
<p className="text-[11px] text-[var(--vk-text-muted)]">
|
|
3360
|
+
Organization access settings are written into `conductor.yaml`. Use admin role bindings for full
|
|
3361
|
+
control, operator bindings for day-to-day agent usage, and viewer bindings for read-only access.
|
|
3362
|
+
</p>
|
|
3363
|
+
)}
|
|
2627
3364
|
</div>
|
|
2628
3365
|
<div className="flex w-full flex-wrap items-center justify-end gap-2 sm:w-auto">
|
|
2629
3366
|
{!isOnboarding && (
|
|
@@ -2680,6 +3417,23 @@ function SettingsDialog({
|
|
|
2680
3417
|
) : "Save Repository"}
|
|
2681
3418
|
</button>
|
|
2682
3419
|
)}
|
|
3420
|
+
{isOrganizationTab && !isOnboarding && (
|
|
3421
|
+
<button
|
|
3422
|
+
type="button"
|
|
3423
|
+
onClick={() => {
|
|
3424
|
+
void handleSaveAccess();
|
|
3425
|
+
}}
|
|
3426
|
+
disabled={!canSaveAccess || accessSaving}
|
|
3427
|
+
className="inline-flex h-9 items-center rounded-[4px] bg-[var(--vk-bg-active)] px-3 text-[13px] text-[var(--vk-text-strong)] hover:bg-[var(--vk-bg-hover)] disabled:opacity-50"
|
|
3428
|
+
>
|
|
3429
|
+
{accessSaving ? (
|
|
3430
|
+
<>
|
|
3431
|
+
<Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin" />
|
|
3432
|
+
Saving...
|
|
3433
|
+
</>
|
|
3434
|
+
) : "Save Access"}
|
|
3435
|
+
</button>
|
|
3436
|
+
)}
|
|
2683
3437
|
{isOnboarding && (
|
|
2684
3438
|
<button
|
|
2685
3439
|
type="button"
|