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.
Files changed (492) hide show
  1. package/README.md +29 -6
  2. package/dist/commands/init.d.ts +2 -0
  3. package/dist/commands/init.d.ts.map +1 -1
  4. package/dist/commands/init.js +3 -0
  5. package/dist/commands/init.js.map +1 -1
  6. package/dist/commands/setup.d.ts +30 -0
  7. package/dist/commands/setup.d.ts.map +1 -1
  8. package/dist/commands/setup.js +131 -29
  9. package/dist/commands/setup.js.map +1 -1
  10. package/dist/commands/start.d.ts +3 -0
  11. package/dist/commands/start.d.ts.map +1 -1
  12. package/dist/commands/start.js +209 -15
  13. package/dist/commands/start.js.map +1 -1
  14. package/dist/index.js +1 -1
  15. package/node_modules/@conductor-oss/core/dist/config.d.ts +1 -1
  16. package/node_modules/@conductor-oss/core/dist/config.d.ts.map +1 -1
  17. package/node_modules/@conductor-oss/core/dist/config.js +34 -0
  18. package/node_modules/@conductor-oss/core/dist/config.js.map +1 -1
  19. package/node_modules/@conductor-oss/core/dist/scaffold.d.ts +14 -0
  20. package/node_modules/@conductor-oss/core/dist/scaffold.d.ts.map +1 -1
  21. package/node_modules/@conductor-oss/core/dist/scaffold.js +27 -4
  22. package/node_modules/@conductor-oss/core/dist/scaffold.js.map +1 -1
  23. package/node_modules/@conductor-oss/core/dist/types.d.ts +71 -0
  24. package/node_modules/@conductor-oss/core/dist/types.d.ts.map +1 -1
  25. package/node_modules/@conductor-oss/core/dist/types.js +244 -0
  26. package/node_modules/@conductor-oss/core/dist/types.js.map +1 -1
  27. package/node_modules/@conductor-oss/core/package.json +1 -1
  28. package/node_modules/@conductor-oss/plugin-agent-amp/dist/index.js +1 -1
  29. package/node_modules/@conductor-oss/plugin-agent-amp/package.json +2 -2
  30. package/node_modules/@conductor-oss/plugin-agent-ccr/dist/index.js +1 -1
  31. package/node_modules/@conductor-oss/plugin-agent-ccr/package.json +2 -2
  32. package/node_modules/@conductor-oss/plugin-agent-claude-code/dist/index.js +1 -1
  33. package/node_modules/@conductor-oss/plugin-agent-claude-code/package.json +2 -2
  34. package/node_modules/@conductor-oss/plugin-agent-codex/dist/index.js +1 -1
  35. package/node_modules/@conductor-oss/plugin-agent-codex/package.json +2 -2
  36. package/node_modules/@conductor-oss/plugin-agent-cursor-cli/dist/index.js +1 -1
  37. package/node_modules/@conductor-oss/plugin-agent-cursor-cli/package.json +2 -2
  38. package/node_modules/@conductor-oss/plugin-agent-droid/dist/index.js +1 -1
  39. package/node_modules/@conductor-oss/plugin-agent-droid/package.json +2 -2
  40. package/node_modules/@conductor-oss/plugin-agent-gemini/dist/index.js +1 -1
  41. package/node_modules/@conductor-oss/plugin-agent-gemini/package.json +2 -2
  42. package/node_modules/@conductor-oss/plugin-agent-github-copilot/dist/index.js +1 -1
  43. package/node_modules/@conductor-oss/plugin-agent-github-copilot/package.json +2 -2
  44. package/node_modules/@conductor-oss/plugin-agent-opencode/dist/index.js +1 -1
  45. package/node_modules/@conductor-oss/plugin-agent-opencode/package.json +2 -2
  46. package/node_modules/@conductor-oss/plugin-agent-qwen-code/dist/index.js +10 -6
  47. package/node_modules/@conductor-oss/plugin-agent-qwen-code/package.json +2 -2
  48. package/node_modules/@conductor-oss/plugin-mcp-server/dist/index.js +1 -1
  49. package/node_modules/@conductor-oss/plugin-mcp-server/package.json +2 -2
  50. package/node_modules/@conductor-oss/plugin-notifier-desktop/dist/index.js +1 -1
  51. package/node_modules/@conductor-oss/plugin-notifier-desktop/package.json +2 -2
  52. package/node_modules/@conductor-oss/plugin-notifier-discord/dist/index.js +1 -1
  53. package/node_modules/@conductor-oss/plugin-notifier-discord/package.json +2 -2
  54. package/node_modules/@conductor-oss/plugin-runtime-tmux/dist/index.js +1 -1
  55. package/node_modules/@conductor-oss/plugin-runtime-tmux/package.json +2 -2
  56. package/node_modules/@conductor-oss/plugin-scm-github/dist/index.js +1 -1
  57. package/node_modules/@conductor-oss/plugin-scm-github/package.json +2 -2
  58. package/node_modules/@conductor-oss/plugin-terminal-web/dist/index.js +1 -1
  59. package/node_modules/@conductor-oss/plugin-terminal-web/package.json +2 -2
  60. package/node_modules/@conductor-oss/plugin-tracker-github/dist/index.js +1 -1
  61. package/node_modules/@conductor-oss/plugin-tracker-github/package.json +2 -2
  62. package/node_modules/@conductor-oss/plugin-webhook/package.json +2 -2
  63. package/node_modules/@conductor-oss/plugin-workspace-worktree/dist/index.js +1 -1
  64. package/node_modules/@conductor-oss/plugin-workspace-worktree/package.json +2 -2
  65. package/package.json +22 -21
  66. package/web/.next/standalone/packages/web/.next/BUILD_ID +1 -1
  67. package/web/.next/standalone/packages/web/.next/app-path-routes-manifest.json +5 -1
  68. package/web/.next/standalone/packages/web/.next/build-manifest.json +4 -4
  69. package/web/.next/standalone/packages/web/.next/routes-manifest.json +24 -0
  70. package/web/.next/standalone/packages/web/.next/server/app/_global-error/page/build-manifest.json +2 -2
  71. package/web/.next/standalone/packages/web/.next/server/app/_global-error/page.js.nft.json +1 -1
  72. package/web/.next/standalone/packages/web/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  73. package/web/.next/standalone/packages/web/.next/server/app/_global-error.html +2 -2
  74. package/web/.next/standalone/packages/web/.next/server/app/_global-error.rsc +1 -1
  75. package/web/.next/standalone/packages/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  76. package/web/.next/standalone/packages/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  77. package/web/.next/standalone/packages/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  78. package/web/.next/standalone/packages/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  79. package/web/.next/standalone/packages/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  80. package/web/.next/standalone/packages/web/.next/server/app/_not-found/page/build-manifest.json +2 -2
  81. package/web/.next/standalone/packages/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  82. package/web/.next/standalone/packages/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  83. package/web/.next/standalone/packages/web/.next/server/app/_not-found.html +1 -1
  84. package/web/.next/standalone/packages/web/.next/server/app/_not-found.rsc +9 -9
  85. package/web/.next/standalone/packages/web/.next/server/app/_not-found.segments/_full.segment.rsc +9 -9
  86. package/web/.next/standalone/packages/web/.next/server/app/_not-found.segments/_head.segment.rsc +3 -3
  87. package/web/.next/standalone/packages/web/.next/server/app/_not-found.segments/_index.segment.rsc +5 -5
  88. package/web/.next/standalone/packages/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  89. package/web/.next/standalone/packages/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  90. package/web/.next/standalone/packages/web/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  91. package/web/.next/standalone/packages/web/.next/server/app/api/access/route/app-paths-manifest.json +3 -0
  92. package/web/.next/standalone/packages/web/.next/server/app/api/access/route/build-manifest.json +11 -0
  93. package/web/.next/standalone/packages/web/.next/server/app/api/access/route/server-reference-manifest.json +4 -0
  94. package/web/.next/standalone/packages/web/.next/server/app/api/access/route.js +11 -0
  95. package/web/.next/standalone/packages/web/.next/server/app/api/access/route.js.map +5 -0
  96. package/web/.next/standalone/packages/web/.next/server/app/api/access/route.js.nft.json +1 -0
  97. package/web/.next/standalone/packages/web/.next/server/app/api/access/route_client-reference-manifest.js +2 -0
  98. package/web/.next/standalone/packages/web/.next/server/app/api/agents/route.js +5 -3
  99. package/web/.next/standalone/packages/web/.next/server/app/api/agents/route.js.nft.json +1 -1
  100. package/web/.next/standalone/packages/web/.next/server/app/api/attachments/route.js +4 -2
  101. package/web/.next/standalone/packages/web/.next/server/app/api/attachments/route.js.nft.json +1 -1
  102. package/web/.next/standalone/packages/web/.next/server/app/api/auth/session/route/app-paths-manifest.json +3 -0
  103. package/web/.next/standalone/packages/web/.next/server/app/api/auth/session/route/build-manifest.json +11 -0
  104. package/web/.next/standalone/packages/web/.next/server/app/api/auth/session/route/server-reference-manifest.json +4 -0
  105. package/web/.next/standalone/packages/web/.next/server/app/api/auth/session/route.js +8 -0
  106. package/web/.next/standalone/packages/web/.next/server/app/api/auth/session/route.js.map +5 -0
  107. package/web/.next/standalone/packages/web/.next/server/app/api/auth/session/route.js.nft.json +1 -0
  108. package/web/.next/standalone/packages/web/.next/server/app/api/auth/session/route_client-reference-manifest.js +2 -0
  109. package/web/.next/standalone/packages/web/.next/server/app/api/boards/route.js +5 -3
  110. package/web/.next/standalone/packages/web/.next/server/app/api/boards/route.js.nft.json +1 -1
  111. package/web/.next/standalone/packages/web/.next/server/app/api/config/route.js +4 -2
  112. package/web/.next/standalone/packages/web/.next/server/app/api/config/route.js.nft.json +1 -1
  113. package/web/.next/standalone/packages/web/.next/server/app/api/context-files/route.js +3 -1
  114. package/web/.next/standalone/packages/web/.next/server/app/api/context-files/route.js.nft.json +1 -1
  115. package/web/.next/standalone/packages/web/.next/server/app/api/events/route.js +4 -2
  116. package/web/.next/standalone/packages/web/.next/server/app/api/events/route.js.nft.json +1 -1
  117. package/web/.next/standalone/packages/web/.next/server/app/api/filesystem/directory/route.js +3 -1
  118. package/web/.next/standalone/packages/web/.next/server/app/api/filesystem/directory/route.js.nft.json +1 -1
  119. package/web/.next/standalone/packages/web/.next/server/app/api/github/repos/route.js +4 -2
  120. package/web/.next/standalone/packages/web/.next/server/app/api/github/repos/route.js.nft.json +1 -1
  121. package/web/.next/standalone/packages/web/.next/server/app/api/health/boards/route.js +3 -1
  122. package/web/.next/standalone/packages/web/.next/server/app/api/health/boards/route.js.nft.json +1 -1
  123. package/web/.next/standalone/packages/web/.next/server/app/api/preferences/route.js +5 -3
  124. package/web/.next/standalone/packages/web/.next/server/app/api/preferences/route.js.nft.json +1 -1
  125. package/web/.next/standalone/packages/web/.next/server/app/api/repositories/route.js +5 -3
  126. package/web/.next/standalone/packages/web/.next/server/app/api/repositories/route.js.nft.json +1 -1
  127. package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/checks/route.js +4 -2
  128. package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/checks/route.js.nft.json +1 -1
  129. package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/diff/route.js +4 -2
  130. package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/diff/route.js.nft.json +1 -1
  131. package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/feedback/route.js +4 -2
  132. package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/feedback/route.js.nft.json +1 -1
  133. package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/files/route.js +3 -1
  134. package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/files/route.js.nft.json +1 -1
  135. package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/keys/route.js +3 -1
  136. package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/keys/route.js.nft.json +1 -1
  137. package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/kill/route.js +4 -2
  138. package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/kill/route.js.nft.json +1 -1
  139. package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/output/route.js +4 -2
  140. package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/output/route.js.nft.json +1 -1
  141. package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/output/stream/route.js +4 -2
  142. package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/output/stream/route.js.nft.json +1 -1
  143. package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/restore/route.js +4 -2
  144. package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/restore/route.js.nft.json +1 -1
  145. package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/route.js +3 -1
  146. package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/route.js.nft.json +1 -1
  147. package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/send/route.js +4 -2
  148. package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/send/route.js.nft.json +1 -1
  149. package/web/.next/standalone/packages/web/.next/server/app/api/sessions/route.js +3 -1
  150. package/web/.next/standalone/packages/web/.next/server/app/api/sessions/route.js.nft.json +1 -1
  151. package/web/.next/standalone/packages/web/.next/server/app/api/spawn/route.js +5 -3
  152. package/web/.next/standalone/packages/web/.next/server/app/api/spawn/route.js.nft.json +1 -1
  153. package/web/.next/standalone/packages/web/.next/server/app/api/workspaces/branches/route.js +3 -1
  154. package/web/.next/standalone/packages/web/.next/server/app/api/workspaces/branches/route.js.nft.json +1 -1
  155. package/web/.next/standalone/packages/web/.next/server/app/api/workspaces/route.js +5 -3
  156. package/web/.next/standalone/packages/web/.next/server/app/api/workspaces/route.js.nft.json +1 -1
  157. package/web/.next/standalone/packages/web/.next/server/app/auth/grant/route/app-paths-manifest.json +3 -0
  158. package/web/.next/standalone/packages/web/.next/server/app/auth/grant/route/build-manifest.json +11 -0
  159. package/web/.next/standalone/packages/web/.next/server/app/auth/grant/route/server-reference-manifest.json +4 -0
  160. package/web/.next/standalone/packages/web/.next/server/app/auth/grant/route.js +8 -0
  161. package/web/.next/standalone/packages/web/.next/server/app/auth/grant/route.js.map +5 -0
  162. package/web/.next/standalone/packages/web/.next/server/app/auth/grant/route.js.nft.json +1 -0
  163. package/web/.next/standalone/packages/web/.next/server/app/auth/grant/route_client-reference-manifest.js +2 -0
  164. package/web/.next/standalone/packages/web/.next/server/app/index.html +1 -1
  165. package/web/.next/standalone/packages/web/.next/server/app/index.rsc +4 -4
  166. package/web/.next/standalone/packages/web/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  167. package/web/.next/standalone/packages/web/.next/server/app/index.segments/_full.segment.rsc +4 -4
  168. package/web/.next/standalone/packages/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
  169. package/web/.next/standalone/packages/web/.next/server/app/index.segments/_index.segment.rsc +3 -3
  170. package/web/.next/standalone/packages/web/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  171. package/web/.next/standalone/packages/web/.next/server/app/page/build-manifest.json +2 -2
  172. package/web/.next/standalone/packages/web/.next/server/app/page.js.nft.json +1 -1
  173. package/web/.next/standalone/packages/web/.next/server/app/page_client-reference-manifest.js +1 -1
  174. package/web/.next/standalone/packages/web/.next/server/app/sessions/[id]/page/build-manifest.json +2 -2
  175. package/web/.next/standalone/packages/web/.next/server/app/sessions/[id]/page.js.nft.json +1 -1
  176. package/web/.next/standalone/packages/web/.next/server/app/sessions/[id]/page_client-reference-manifest.js +1 -1
  177. package/web/.next/standalone/packages/web/.next/server/app/sign-in/[[...sign-in]]/page/build-manifest.json +2 -2
  178. package/web/.next/standalone/packages/web/.next/server/app/sign-in/[[...sign-in]]/page.js.nft.json +1 -1
  179. package/web/.next/standalone/packages/web/.next/server/app/sign-in/[[...sign-in]]/page_client-reference-manifest.js +1 -1
  180. package/web/.next/standalone/packages/web/.next/server/app/unlock/page/app-paths-manifest.json +3 -0
  181. package/web/.next/standalone/packages/web/.next/server/app/unlock/page/build-manifest.json +18 -0
  182. package/web/.next/standalone/packages/web/.next/server/app/unlock/page/next-font-manifest.json +14 -0
  183. package/web/.next/standalone/packages/web/.next/server/app/unlock/page/react-loadable-manifest.json +1 -0
  184. package/web/.next/standalone/packages/web/.next/server/app/unlock/page/server-reference-manifest.json +110 -0
  185. package/web/.next/standalone/packages/web/.next/server/app/unlock/page.js +19 -0
  186. package/web/.next/standalone/packages/web/.next/server/app/unlock/page.js.map +5 -0
  187. package/web/.next/standalone/packages/web/.next/server/app/unlock/page.js.nft.json +1 -0
  188. package/web/.next/standalone/packages/web/.next/server/app/unlock/page_client-reference-manifest.js +2 -0
  189. package/web/.next/standalone/packages/web/.next/server/app-paths-manifest.json +5 -1
  190. package/web/.next/standalone/packages/web/.next/server/chunks/1bc17_next_dist_esm_build_templates_app-route_1651710d.js +1 -1
  191. package/web/.next/standalone/packages/web/.next/server/chunks/1bc17_next_dist_esm_build_templates_app-route_34b04c2b.js +1 -1
  192. package/web/.next/standalone/packages/web/.next/server/chunks/1bc17_next_dist_esm_build_templates_app-route_9c655a1d.js +3 -3
  193. package/web/.next/standalone/packages/web/.next/server/chunks/1bc17_next_dist_esm_build_templates_app-route_b41c4976.js +1 -1
  194. package/web/.next/standalone/packages/web/.next/server/chunks/1bc17_next_dist_esm_build_templates_app-route_f4104ae4.js +1 -1
  195. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__005aa909._.js +1 -1
  196. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__03ff76ee._.js +1 -1
  197. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__07ec6d5c._.js +1 -1
  198. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__0a0f0f01._.js +1 -1
  199. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__0ad3545b._.js +5 -5
  200. package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__04d7f8e9._.js → [root-of-the-server]__0c65150d._.js} +2 -2
  201. package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__39e2947e._.js → [root-of-the-server]__0d615ef4._.js} +2 -2
  202. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__13ad088c._.js +1 -1
  203. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__14b1d4a3._.js +1 -1
  204. package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__000a39bb._.js → [root-of-the-server]__14d277b3._.js} +2 -2
  205. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__1741fb8a._.js +1 -1
  206. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__17d81825._.js +3 -0
  207. package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__4266ed21._.js → [root-of-the-server]__1b7c6a55._.js} +2 -2
  208. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__1e288076._.js +3 -0
  209. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__1f626a16._.js +1 -1
  210. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__1f712b77._.js +3 -0
  211. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__2062aaab._.js +1 -1
  212. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__206c3d8a._.js +1 -1
  213. package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__9469f247._.js → [root-of-the-server]__230d54da._.js} +2 -2
  214. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__24d8e6fc._.js +3 -0
  215. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__2556a816._.js +1 -1
  216. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__2af6c2e0._.js +3 -0
  217. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__2d57abda._.js +3 -0
  218. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__30b0f109._.js +3 -0
  219. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__30c75561._.js +3 -0
  220. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__31c39bd9._.js +3 -0
  221. package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__7e505454._.js → [root-of-the-server]__341657dd._.js} +2 -2
  222. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__34a19860._.js +3 -0
  223. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__3fde7043._.js +1 -1
  224. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__40c8037e._.js +2 -2
  225. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__41ee872a._.js +3 -0
  226. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__44606e04._.js +1 -1
  227. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__44d59fd0._.js +1 -1
  228. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__459839a6._.js +3 -0
  229. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__46a8e776._.js +3 -0
  230. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__48875cbb._.js +1 -1
  231. package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__b3f4ff98._.js → [root-of-the-server]__488ab4b2._.js} +2 -2
  232. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__4ac9d639._.js +1 -1
  233. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__4c3fb752._.js +1 -1
  234. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__4dab6a6a._.js +1 -1
  235. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__544326ac._.js +1 -1
  236. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__5494c5a2._.js +3 -0
  237. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__54a218f0._.js +3 -3
  238. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__54a76cd2._.js +1 -1
  239. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__5661ca72._.js +1 -1
  240. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__568f0a6e._.js +3 -0
  241. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__5cd49624._.js +1 -1
  242. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__5d76c5af._.js +3 -0
  243. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__5e0533de._.js +1 -1
  244. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__5f628cf2._.js +3 -0
  245. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__62608541._.js +1 -1
  246. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__6d62709d._.js +5 -5
  247. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__6e4e09be._.js +3 -0
  248. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__70258e45._.js +3 -0
  249. package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__917adaec._.js → [root-of-the-server]__711dc459._.js} +2 -2
  250. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__720136dd._.js +3 -0
  251. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__749331b0._.js +3 -3
  252. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__755c7e10._.js +3 -0
  253. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__778e46a1._.js +5 -5
  254. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__7e6ea46e._.js +1 -1
  255. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__7f023a04._.js +4 -4
  256. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__7f2ed2cd._.js +3 -0
  257. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__7fa52da6._.js +1 -1
  258. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__82171aa3._.js +9 -0
  259. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__84362910._.js +1 -1
  260. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__848eb266._.js +1 -1
  261. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__8596d782._.js +1 -1
  262. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__85c5cb36._.js +3 -0
  263. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__878fbacc._.js +3 -0
  264. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__881858fa._.js +1 -1
  265. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__885e3a00._.js +3 -3
  266. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__893f6b3b._.js +1 -1
  267. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__8ac30f97._.js +3 -0
  268. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__8c519453._.js +1 -1
  269. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__919845e0._.js +3 -0
  270. package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__9b62b450._.js → [root-of-the-server]__927b9bce._.js} +2 -2
  271. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__93b3582e._.js +3 -0
  272. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__964f4e89._.js +3 -0
  273. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__96633022._.js +1 -1
  274. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__98697e45._.js +1 -1
  275. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__997ebfca._.js +3 -0
  276. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__9c930222._.js +3 -0
  277. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__9f36b7ec._.js +5 -5
  278. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__a44f91a4._.js +3 -3
  279. package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__1bc4f8f5._.js → [root-of-the-server]__a5d13971._.js} +2 -2
  280. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__a6c7bd91._.js +3 -0
  281. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__ae580a1a._.js +3 -0
  282. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__af533b5e._.js +3 -0
  283. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__afa79f55._.js +1 -1
  284. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__b057f7b2._.js +1 -1
  285. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__b59abfbd._.js +1 -1
  286. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__bd8ace80._.js +3 -0
  287. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__be0f2c29._.js +3 -0
  288. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__bea07e07._.js +1 -1
  289. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__c8618cb1._.js +1 -1
  290. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__caf8e7cb._.js +1 -1
  291. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__cb112606._.js +1 -1
  292. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__cb51f2e3._.js +3 -0
  293. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__cba32afb._.js +3 -0
  294. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__cc74ea40._.js +1 -1
  295. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__cd3692a0._.js +1 -1
  296. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__cf3cdecd._.js +1 -1
  297. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__d09e7a99._.js +1 -1
  298. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__d538c110._.js +1 -1
  299. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__d93447b9._.js +1 -1
  300. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__d9c80b18._.js +3 -0
  301. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__dc0959da._.js +3 -0
  302. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__dda8eac1._.js +1 -1
  303. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__df2c6efe._.js +3 -0
  304. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__e113f6df._.js +1 -1
  305. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__e2573a77._.js +1 -1
  306. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__e2d60274._.js +3 -0
  307. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__e308bb89._.js +1 -1
  308. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__e345a443._.js +3 -0
  309. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__e80a520f._.js +3 -0
  310. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__ea0bb124._.js +3 -0
  311. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__ef773ea6._.js +1 -1
  312. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__f0d15920._.js +1 -1
  313. package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__b029d2c1._.js → [root-of-the-server]__f2f30c04._.js} +2 -2
  314. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__f47a2a9e._.js +1 -1
  315. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__f48eb2d4._.js +1 -1
  316. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__f6a8bbd9._.js +12 -12
  317. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__faceea9b._.js +1 -1
  318. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__fb6ab669._.js +1 -1
  319. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__fcf96768._.js +3 -0
  320. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__fdaa8058._.js +7 -0
  321. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__ff2b205d._.js +3 -0
  322. package/web/.next/standalone/packages/web/.next/server/chunks/packages_core_dist_index_cdd30418.js +1 -1
  323. package/web/.next/standalone/packages/web/.next/server/chunks/packages_plugins_agent-amp_dist_index_bf3d8239.js +1 -1
  324. package/web/.next/standalone/packages/web/.next/server/chunks/packages_plugins_agent-ccr_dist_index_69cbf726.js +1 -1
  325. package/web/.next/standalone/packages/web/.next/server/chunks/packages_plugins_agent-claude-code_dist_index_31314e43.js +1 -1
  326. package/web/.next/standalone/packages/web/.next/server/chunks/packages_plugins_agent-cursor-cli_dist_index_8d5cc426.js +1 -1
  327. package/web/.next/standalone/packages/web/.next/server/chunks/packages_plugins_agent-droid_dist_index_f731227a.js +1 -1
  328. package/web/.next/standalone/packages/web/.next/server/chunks/packages_plugins_agent-gemini_dist_index_b2d219e8.js +1 -1
  329. package/web/.next/standalone/packages/web/.next/server/chunks/packages_plugins_agent-github-copilot_dist_index_9f80cb45.js +1 -1
  330. package/web/.next/standalone/packages/web/.next/server/chunks/packages_plugins_agent-opencode_dist_index_7c7015da.js +1 -1
  331. package/web/.next/standalone/packages/web/.next/server/chunks/packages_plugins_agent-qwen-code_dist_index_46dd8653.js +1 -1
  332. package/web/.next/standalone/packages/web/.next/server/chunks/packages_plugins_notifier-desktop_dist_index_ef3473f0.js +1 -1
  333. package/web/.next/standalone/packages/web/.next/server/chunks/packages_plugins_notifier-discord_dist_index_34257226.js +1 -1
  334. package/web/.next/standalone/packages/web/.next/server/chunks/packages_plugins_scm-github_dist_index_3b5a621e.js +1 -1
  335. package/web/.next/standalone/packages/web/.next/server/chunks/packages_plugins_terminal-web_dist_index_1e0706d3.js +1 -1
  336. package/web/.next/standalone/packages/web/.next/server/chunks/packages_plugins_tracker-github_dist_index_2d7af62f.js +1 -1
  337. package/web/.next/standalone/packages/web/.next/server/chunks/packages_web__next-internal_server_app_api_access_route_actions_06740e99.js +3 -0
  338. package/web/.next/standalone/packages/web/.next/server/chunks/packages_web__next-internal_server_app_api_auth_session_route_actions_078c0ee4.js +3 -0
  339. package/web/.next/standalone/packages/web/.next/server/chunks/packages_web__next-internal_server_app_auth_grant_route_actions_13ba4421.js +3 -0
  340. package/web/.next/standalone/packages/web/.next/server/chunks/packages_web_src_lib_13fee5eb._.js +3 -0
  341. package/web/.next/standalone/packages/web/.next/server/chunks/packages_web_src_lib_d64596cc._.js +3 -0
  342. package/web/.next/standalone/packages/web/.next/server/chunks/ssr/{[root-of-the-server]__1ddf22db._.js → [root-of-the-server]__1012a4c8._.js} +2 -2
  343. package/web/.next/standalone/packages/web/.next/server/chunks/ssr/{[root-of-the-server]__ed81e796._.js → [root-of-the-server]__81affb12._.js} +2 -2
  344. package/web/.next/standalone/packages/web/.next/server/chunks/ssr/[root-of-the-server]__95e85d3d._.js +3 -0
  345. package/web/.next/standalone/packages/web/.next/server/chunks/ssr/{[root-of-the-server]__f577d85a._.js → [root-of-the-server]__9d698773._.js} +2 -2
  346. package/web/.next/standalone/packages/web/.next/server/chunks/ssr/[root-of-the-server]__a38f483b._.js +1 -1
  347. package/web/.next/standalone/packages/web/.next/server/chunks/ssr/{[root-of-the-server]__3bf3fbfb._.js → [root-of-the-server]__c09a0c60._.js} +2 -2
  348. package/web/.next/standalone/packages/web/.next/server/chunks/ssr/[root-of-the-server]__d9dde485._.js +1 -1
  349. package/web/.next/standalone/packages/web/.next/server/chunks/ssr/{[root-of-the-server]__d5970f3e._.js → [root-of-the-server]__dd435d80._.js} +2 -2
  350. package/web/.next/standalone/packages/web/.next/server/chunks/ssr/{[root-of-the-server]__469db3c3._.js → [root-of-the-server]__e78955d0._.js} +2 -2
  351. package/web/.next/standalone/packages/web/.next/server/chunks/ssr/_14a33487._.js +3 -0
  352. package/web/.next/standalone/packages/web/.next/server/chunks/ssr/_34d55bf1._.js +4 -0
  353. package/web/.next/standalone/packages/web/.next/server/chunks/ssr/{node_modules__pnpm_c636dc22._.js → node_modules__pnpm_597c265e._.js} +1 -1
  354. package/web/.next/standalone/packages/web/.next/server/chunks/ssr/packages_web_src_app_page_tsx_cd282e82._.js +1 -1
  355. package/web/.next/standalone/packages/web/.next/server/chunks/ssr/packages_web_src_app_unlock_UnlockForm_tsx_ce3149a7._.js +3 -0
  356. package/web/.next/standalone/packages/web/.next/server/middleware-build-manifest.js +2 -2
  357. package/web/.next/standalone/packages/web/.next/server/middleware.js +1 -1
  358. package/web/.next/standalone/packages/web/.next/server/next-font-manifest.js +1 -1
  359. package/web/.next/standalone/packages/web/.next/server/next-font-manifest.json +7 -0
  360. package/web/.next/standalone/packages/web/.next/server/pages/404.html +1 -1
  361. package/web/.next/standalone/packages/web/.next/server/pages/500.html +2 -2
  362. package/web/.next/standalone/packages/web/.next/server/server-reference-manifest.js +1 -1
  363. package/web/.next/standalone/packages/web/.next/server/server-reference-manifest.json +56 -7
  364. package/web/.next/{static/chunks/9b799cd7eb9a34ff.js → standalone/packages/web/.next/static/chunks/1c4c14af475ada00.js} +1 -1
  365. package/web/.next/standalone/packages/web/.next/static/chunks/ba68284a3401d670.css +3 -0
  366. package/web/.next/standalone/packages/web/.next/static/chunks/{4372fb4d7779cd64.js → d00ddc86d1af3b6d.js} +1 -1
  367. package/web/.next/standalone/packages/web/.next/static/chunks/d8f4bf59132f70fd.js +1 -0
  368. package/web/.next/standalone/packages/web/.next/static/chunks/f355d4d60f0ec80e.js +1 -0
  369. package/web/.next/standalone/packages/web/.next/static/chunks/{turbopack-c3449aaab622f98c.js → turbopack-dc658d17ee981623.js} +1 -1
  370. package/web/.next/standalone/packages/web/package.json +1 -0
  371. package/web/.next/standalone/packages/web/src/app/api/access/route.ts +214 -0
  372. package/web/.next/standalone/packages/web/src/app/api/agents/route.ts +2 -2
  373. package/web/.next/standalone/packages/web/src/app/api/attachments/route.ts +1 -1
  374. package/web/.next/standalone/packages/web/src/app/api/auth/session/route.ts +54 -0
  375. package/web/.next/standalone/packages/web/src/app/api/boards/route.ts +2 -2
  376. package/web/.next/standalone/packages/web/src/app/api/config/route.ts +2 -1
  377. package/web/.next/standalone/packages/web/src/app/api/context-files/route.ts +1 -1
  378. package/web/.next/standalone/packages/web/src/app/api/events/route.ts +1 -1
  379. package/web/.next/standalone/packages/web/src/app/api/filesystem/directory/route.ts +1 -1
  380. package/web/.next/standalone/packages/web/src/app/api/github/repos/route.ts +1 -1
  381. package/web/.next/standalone/packages/web/src/app/api/health/boards/route.ts +1 -1
  382. package/web/.next/standalone/packages/web/src/app/api/preferences/route.ts +9 -2
  383. package/web/.next/standalone/packages/web/src/app/api/repositories/route.ts +19 -2
  384. package/web/.next/standalone/packages/web/src/app/api/sessions/[id]/checks/route.ts +1 -1
  385. package/web/.next/standalone/packages/web/src/app/api/sessions/[id]/diff/route.ts +1 -1
  386. package/web/.next/standalone/packages/web/src/app/api/sessions/[id]/feedback/route.ts +1 -1
  387. package/web/.next/standalone/packages/web/src/app/api/sessions/[id]/files/route.ts +1 -1
  388. package/web/.next/standalone/packages/web/src/app/api/sessions/[id]/keys/route.ts +1 -1
  389. package/web/.next/standalone/packages/web/src/app/api/sessions/[id]/kill/route.ts +1 -1
  390. package/web/.next/standalone/packages/web/src/app/api/sessions/[id]/output/route.ts +1 -1
  391. package/web/.next/standalone/packages/web/src/app/api/sessions/[id]/output/stream/route.ts +1 -1
  392. package/web/.next/standalone/packages/web/src/app/api/sessions/[id]/restore/route.ts +1 -1
  393. package/web/.next/standalone/packages/web/src/app/api/sessions/[id]/route.ts +1 -1
  394. package/web/.next/standalone/packages/web/src/app/api/sessions/[id]/send/route.ts +1 -1
  395. package/web/.next/standalone/packages/web/src/app/api/sessions/route.ts +1 -1
  396. package/web/.next/standalone/packages/web/src/app/api/spawn/route.ts +1 -1
  397. package/web/.next/standalone/packages/web/src/app/api/workspaces/branches/route.ts +1 -1
  398. package/web/.next/standalone/packages/web/src/app/api/workspaces/route.ts +9 -2
  399. package/web/.next/standalone/packages/web/src/app/auth/grant/route.ts +37 -0
  400. package/web/.next/standalone/packages/web/src/app/page.tsx +763 -9
  401. package/web/.next/standalone/packages/web/src/app/unlock/UnlockForm.tsx +77 -0
  402. package/web/.next/standalone/packages/web/src/app/unlock/page.tsx +41 -0
  403. package/web/.next/standalone/packages/web/src/components/Dashboard.tsx +11 -125
  404. package/web/.next/standalone/packages/web/src/hooks/useConfig.ts +4 -0
  405. package/web/.next/standalone/packages/web/src/lib/accessControl.test.ts +46 -0
  406. package/web/.next/standalone/packages/web/src/lib/accessControl.ts +115 -0
  407. package/web/.next/standalone/packages/web/src/lib/auth.ts +294 -53
  408. package/web/.next/standalone/packages/web/src/lib/edgeAuth.test.ts +91 -0
  409. package/web/.next/standalone/packages/web/src/lib/edgeAuth.ts +205 -0
  410. package/web/.next/standalone/packages/web/src/lib/modelAccess.ts +40 -0
  411. package/web/.next/standalone/packages/web/src/lib/projectConfigSync.ts +2 -0
  412. package/web/.next/standalone/packages/web/src/lib/remoteAuth.ts +104 -0
  413. package/web/.next/standalone/packages/web/src/proxy.ts +64 -0
  414. package/web/.next/standalone/packages/web/tsconfig.tsbuildinfo +1 -1
  415. package/web/.next/{standalone/packages/web/.next/static/chunks/9b799cd7eb9a34ff.js → static/chunks/1c4c14af475ada00.js} +1 -1
  416. package/web/.next/static/chunks/ba68284a3401d670.css +3 -0
  417. package/web/.next/static/chunks/{4372fb4d7779cd64.js → d00ddc86d1af3b6d.js} +1 -1
  418. package/web/.next/static/chunks/d8f4bf59132f70fd.js +1 -0
  419. package/web/.next/static/chunks/f355d4d60f0ec80e.js +1 -0
  420. package/web/.next/static/chunks/{turbopack-c3449aaab622f98c.js → turbopack-dc658d17ee981623.js} +1 -1
  421. package/node_modules/@conductor-oss/core/dist/__tests__/board-parser.test.d.ts +0 -2
  422. package/node_modules/@conductor-oss/core/dist/__tests__/board-parser.test.d.ts.map +0 -1
  423. package/node_modules/@conductor-oss/core/dist/__tests__/board-parser.test.js +0 -67
  424. package/node_modules/@conductor-oss/core/dist/__tests__/board-parser.test.js.map +0 -1
  425. package/node_modules/@conductor-oss/core/dist/__tests__/board-watcher-support-files.test.d.ts +0 -2
  426. package/node_modules/@conductor-oss/core/dist/__tests__/board-watcher-support-files.test.d.ts.map +0 -1
  427. package/node_modules/@conductor-oss/core/dist/__tests__/board-watcher-support-files.test.js +0 -122
  428. package/node_modules/@conductor-oss/core/dist/__tests__/board-watcher-support-files.test.js.map +0 -1
  429. package/node_modules/@conductor-oss/core/dist/__tests__/project-paths.test.d.ts +0 -2
  430. package/node_modules/@conductor-oss/core/dist/__tests__/project-paths.test.d.ts.map +0 -1
  431. package/node_modules/@conductor-oss/core/dist/__tests__/project-paths.test.js +0 -48
  432. package/node_modules/@conductor-oss/core/dist/__tests__/project-paths.test.js.map +0 -1
  433. package/node_modules/@conductor-oss/core/dist/agent-cli-runtime.d.ts +0 -20
  434. package/node_modules/@conductor-oss/core/dist/agent-cli-runtime.d.ts.map +0 -1
  435. package/node_modules/@conductor-oss/core/dist/agent-cli-runtime.js +0 -192
  436. package/node_modules/@conductor-oss/core/dist/agent-cli-runtime.js.map +0 -1
  437. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__019d9c90._.js +0 -3
  438. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__08a3e108._.js +0 -3
  439. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__0b0ab434._.js +0 -3
  440. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__0e59a166._.js +0 -3
  441. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__16fb4c3e._.js +0 -9
  442. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__2ff87bed._.js +0 -3
  443. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__3c1772ab._.js +0 -3
  444. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__5093c7e0._.js +0 -3
  445. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__53970b23._.js +0 -3
  446. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__5a67f1f9._.js +0 -3
  447. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__5cf55740._.js +0 -3
  448. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__5d124f64._.js +0 -3
  449. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__6cad94c3._.js +0 -3
  450. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__6d28affc._.js +0 -3
  451. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__6f6826fa._.js +0 -3
  452. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__6f84fa49._.js +0 -3
  453. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__70c9c405._.js +0 -3
  454. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__711294a3._.js +0 -3
  455. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__7791414d._.js +0 -3
  456. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__7fb2ee11._.js +0 -7
  457. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__86646048._.js +0 -3
  458. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__a15b5527._.js +0 -3
  459. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__a4a89ac9._.js +0 -3
  460. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__a8a53d4a._.js +0 -3
  461. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__a93c59df._.js +0 -3
  462. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__abf6274f._.js +0 -3
  463. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__b091b8bc._.js +0 -3
  464. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__b87de88e._.js +0 -3
  465. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__bc304d71._.js +0 -3
  466. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__be52402d._.js +0 -3
  467. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__be74f171._.js +0 -3
  468. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__c03aa571._.js +0 -3
  469. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__c2850420._.js +0 -3
  470. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__c82b8934._.js +0 -3
  471. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__deafbc7a._.js +0 -3
  472. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__e18c8e77._.js +0 -3
  473. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__e1f610fb._.js +0 -3
  474. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__e4976f6d._.js +0 -3
  475. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__ec21c9a4._.js +0 -3
  476. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__ec256a62._.js +0 -3
  477. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__edc8e5a5._.js +0 -3
  478. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__f2c28004._.js +0 -3
  479. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__f7c743c0._.js +0 -3
  480. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__f95f5172._.js +0 -3
  481. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__fc292e1c._.js +0 -3
  482. package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__ffbf3faf._.js +0 -3
  483. package/web/.next/standalone/packages/web/.next/static/chunks/687bc713618f6993.js +0 -1
  484. package/web/.next/standalone/packages/web/.next/static/chunks/e7bb96d7efad8e32.css +0 -3
  485. package/web/.next/static/chunks/687bc713618f6993.js +0 -1
  486. package/web/.next/static/chunks/e7bb96d7efad8e32.css +0 -3
  487. /package/web/.next/standalone/packages/web/.next/static/{2lp61OU9Asm88Hx_JCL5e → tV9IvZT_f540bpw2KonCu}/_buildManifest.js +0 -0
  488. /package/web/.next/standalone/packages/web/.next/static/{2lp61OU9Asm88Hx_JCL5e → tV9IvZT_f540bpw2KonCu}/_clientMiddlewareManifest.json +0 -0
  489. /package/web/.next/standalone/packages/web/.next/static/{2lp61OU9Asm88Hx_JCL5e → tV9IvZT_f540bpw2KonCu}/_ssgManifest.js +0 -0
  490. /package/web/.next/static/{2lp61OU9Asm88Hx_JCL5e → tV9IvZT_f540bpw2KonCu}/_buildManifest.js +0 -0
  491. /package/web/.next/static/{2lp61OU9Asm88Hx_JCL5e → tV9IvZT_f540bpw2KonCu}/_clientMiddlewareManifest.json +0 -0
  492. /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: false },
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(repositoryDraft, {
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) => setRepositoryDraft((prev) => prev ? { ...prev, agent: event.target.value } : prev)}
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
- {(isRepositoriesTab ? repositoriesError : error) && (
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
- {isRepositoriesTab ? repositoriesError : error}
3341
+ {dialogError}
2611
3342
  </p>
2612
3343
  )}
2613
- {!error && !repositoriesError && isPreferencesTab && (
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
- {!error && !repositoriesError && isRepositoriesTab && (
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"