@mrpatronz/nexusflow 0.2.18 → 0.2.19

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 (73) hide show
  1. package/dist/commands/sync.d.ts.map +1 -1
  2. package/dist/commands/sync.js +37 -50
  3. package/dist/commands/sync.js.map +1 -1
  4. package/dist/core/sync.d.ts +44 -0
  5. package/dist/core/sync.d.ts.map +1 -0
  6. package/dist/core/sync.js +82 -0
  7. package/dist/core/sync.js.map +1 -0
  8. package/dist/core/workspace-state.d.ts +51 -0
  9. package/dist/core/workspace-state.d.ts.map +1 -0
  10. package/dist/core/workspace-state.js +108 -0
  11. package/dist/core/workspace-state.js.map +1 -0
  12. package/dist/core/workspace-state.test.d.ts +2 -0
  13. package/dist/core/workspace-state.test.d.ts.map +1 -0
  14. package/dist/core/workspace-state.test.js +84 -0
  15. package/dist/core/workspace-state.test.js.map +1 -0
  16. package/dist/gui/assets/index-Bdbld6yY.css +1 -0
  17. package/dist/gui/assets/index-D8iJPvnk.js +26 -0
  18. package/dist/gui/index.html +2 -2
  19. package/dist/mcp/server.d.ts.map +1 -1
  20. package/dist/mcp/server.js +42 -0
  21. package/dist/mcp/server.js.map +1 -1
  22. package/dist/server.d.ts.map +1 -1
  23. package/dist/server.js +94 -13
  24. package/dist/server.js.map +1 -1
  25. package/dist/types.d.ts +31 -0
  26. package/dist/types.d.ts.map +1 -1
  27. package/dist/utils/multi-git.d.ts +33 -8
  28. package/dist/utils/multi-git.d.ts.map +1 -1
  29. package/dist/utils/multi-git.js +91 -19
  30. package/dist/utils/multi-git.js.map +1 -1
  31. package/dist/utils/multi-git.test.d.ts +2 -0
  32. package/dist/utils/multi-git.test.d.ts.map +1 -0
  33. package/dist/utils/multi-git.test.js +125 -0
  34. package/dist/utils/multi-git.test.js.map +1 -0
  35. package/gui/e2e/dashboard.spec.ts +61 -0
  36. package/gui/e2e/wizard.spec.ts +2 -2
  37. package/gui/package-lock.json +62 -4
  38. package/gui/package.json +2 -1
  39. package/gui/src/App.tsx +168 -227
  40. package/gui/src/app/AppSidebar.tsx +69 -0
  41. package/gui/src/components/AddRepoPicker.tsx +81 -0
  42. package/gui/src/components/ui/Button.tsx +40 -0
  43. package/gui/src/components/ui/Card.tsx +6 -0
  44. package/gui/src/components/ui/EmptyState.tsx +22 -0
  45. package/gui/src/components/ui/Input.tsx +21 -0
  46. package/gui/src/components/ui/Menu.tsx +71 -0
  47. package/gui/src/components/ui/Modal.tsx +39 -0
  48. package/gui/src/components/ui/PageHeader.tsx +21 -0
  49. package/gui/src/components/ui/RepoStatusStrip.tsx +33 -0
  50. package/gui/src/components/ui/Skeleton.tsx +5 -0
  51. package/gui/src/components/ui/StatusPill.tsx +36 -0
  52. package/gui/src/components/ui/Tabs.tsx +40 -0
  53. package/gui/src/components/ui/cn.ts +4 -0
  54. package/gui/src/components/ui/index.ts +16 -0
  55. package/gui/src/features/services/ServiceConsole.tsx +4 -39
  56. package/gui/src/index.css +140 -125
  57. package/gui/src/lib/status.ts +24 -0
  58. package/gui/src/pages/DashboardPage.tsx +129 -0
  59. package/gui/src/pages/WorkspacesPage.tsx +352 -0
  60. package/gui/src/types.ts +19 -0
  61. package/package.json +1 -1
  62. package/src/commands/sync.ts +36 -58
  63. package/src/core/sync.ts +121 -0
  64. package/src/core/workspace-state.test.ts +108 -0
  65. package/src/core/workspace-state.ts +130 -0
  66. package/src/mcp/server.ts +44 -0
  67. package/src/server.ts +103 -15
  68. package/src/types.ts +36 -0
  69. package/src/utils/multi-git.test.ts +158 -0
  70. package/src/utils/multi-git.ts +117 -25
  71. package/dist/gui/assets/index-CB-jWded.css +0 -1
  72. package/dist/gui/assets/index-DDXpZZu3.js +0 -25
  73. package/gui/src/features/workspace/WorkspaceList.tsx +0 -666
package/gui/src/App.tsx CHANGED
@@ -1,7 +1,6 @@
1
1
  import { useState, useEffect, useRef } from 'react';
2
2
  import {
3
3
  PlusCircle,
4
- FolderGit2,
5
4
  Settings as SettingsIcon,
6
5
  Terminal,
7
6
  Play,
@@ -17,12 +16,14 @@ import {
17
16
  Copy,
18
17
  X,
19
18
  Cpu,
20
- Workflow,
21
19
  Trash2,
22
20
  CheckCircle,
23
21
  } from 'lucide-react';
24
22
  import './App.css';
25
- import { WorkspaceList } from './features/workspace/WorkspaceList.js';
23
+ import { HashRouter, useLocation, useNavigate } from 'react-router-dom';
24
+ import { AppSidebar } from './app/AppSidebar.js';
25
+ import { DashboardPage } from './pages/DashboardPage.js';
26
+ import { WorkspacesPage } from './pages/WorkspacesPage.js';
26
27
 
27
28
 
28
29
  // Types matched with src/types.ts
@@ -115,12 +116,26 @@ interface RunningService {
115
116
  startedAt: string;
116
117
  }
117
118
 
119
+ type SyncStatus = 'up-to-date' | 'rebased' | 'conflict' | 'stash-conflict' | 'error';
120
+
121
+ interface WorkspaceStatus {
122
+ id: string;
123
+ branchName: string;
124
+ changedFiles: number;
125
+ dirtyRepos: number;
126
+ runningServices: number;
127
+ syncStatus: SyncStatus | 'unknown';
128
+ pendingValidation: boolean;
129
+ }
130
+
118
131
  const API_BASE = (import.meta.env.DEV || (typeof window !== 'undefined' && (window as any).Neutralino)) ? 'http://localhost:3000' : '';
119
132
  const isVsCode = new URLSearchParams(window.location.search).get('env') === 'vscode';
120
133
  let toastIdCounter = 0;
121
134
 
122
- export default function App() {
123
- const [view, setView] = useState<'guide' | 'create' | 'workspaces' | 'settings' | 'workflows'>('guide');
135
+ function AppInner() {
136
+ const navigate = useNavigate();
137
+ const location = useLocation();
138
+ const [view, setView] = useState<'dashboard' | 'guide' | 'create' | 'workspaces' | 'settings' | 'workflows'>('dashboard');
124
139
 
125
140
  // Toast State
126
141
  interface Toast {
@@ -233,6 +248,9 @@ export default function App() {
233
248
  // Workspaces List
234
249
  const [workspaces, setWorkspaces] = useState<Feature[]>([]);
235
250
  const [workspacesLoading, setWorkspacesLoading] = useState(false);
251
+ // At-a-glance status per workspace (keyed by branchName), for the listing overview.
252
+ const [workspaceStatuses, setWorkspaceStatuses] = useState<Record<string, WorkspaceStatus>>({});
253
+ const [statusesLoading, setStatusesLoading] = useState(false);
236
254
 
237
255
  // Active Workspace Services / Orchestration Details
238
256
  const [activeWsId, setActiveWsId] = useState<string | null>(null);
@@ -550,6 +568,8 @@ export default function App() {
550
568
  const res = await fetch(`${API_BASE}/api/workspaces`);
551
569
  const data = await res.json();
552
570
  setWorkspaces(Array.isArray(data) ? data : []);
571
+ // Refresh at-a-glance status alongside the list (independent endpoint).
572
+ void fetchWorkspaceStatuses();
553
573
  } catch (e) {
554
574
  console.error(e);
555
575
  } finally {
@@ -557,6 +577,19 @@ export default function App() {
557
577
  }
558
578
  };
559
579
 
580
+ const fetchWorkspaceStatuses = async () => {
581
+ setStatusesLoading(true);
582
+ try {
583
+ const res = await fetch(`${API_BASE}/api/workspaces/status`);
584
+ const data = await res.json();
585
+ setWorkspaceStatuses(data && typeof data === 'object' && !Array.isArray(data) ? data : {});
586
+ } catch (e) {
587
+ console.error(e);
588
+ } finally {
589
+ setStatusesLoading(false);
590
+ }
591
+ };
592
+
560
593
  const fetchWorkflowTemplates = async () => {
561
594
  try {
562
595
  const res = await fetch(`${API_BASE}/api/workflows/templates`);
@@ -1093,11 +1126,27 @@ export default function App() {
1093
1126
  const queryParams = new URLSearchParams(window.location.search);
1094
1127
  const queryWsId = queryParams.get('workspaceId');
1095
1128
  if (queryWsId) {
1096
- setActiveWsId(queryWsId);
1097
- setView('workspaces');
1129
+ navigate(`/workspaces/${encodeURIComponent(queryWsId)}`);
1098
1130
  }
1099
1131
  }, []);
1100
1132
 
1133
+ // Keep the legacy `view` + workspace selection (and their data-loading effects) in sync with the route.
1134
+ useEffect(() => {
1135
+ const p = location.pathname;
1136
+ if (p.startsWith('/workspaces')) {
1137
+ setView('workspaces');
1138
+ const parts = p.split('/').filter(Boolean); // ['workspaces', id?, tab?]
1139
+ setActiveWsId(parts[1] ? decodeURIComponent(parts[1]) : null);
1140
+ const tab = parts[2];
1141
+ const valid = ['overview', 'sessions', 'services', 'changes', 'knowledge', 'plan'];
1142
+ setSubTab((tab && valid.includes(tab) ? tab : 'overview') as typeof subTab);
1143
+ } else if (p.startsWith('/new')) setView('create');
1144
+ else if (p.startsWith('/strategies')) setView('workflows');
1145
+ else if (p.startsWith('/settings')) setView('settings');
1146
+ else if (p.startsWith('/guide')) setView('guide');
1147
+ else setView('dashboard');
1148
+ }, [location.pathname]);
1149
+
1101
1150
  // Load tool updates status and LLM recommendations when settings view is open
1102
1151
  useEffect(() => {
1103
1152
  if (view === 'settings') {
@@ -1120,9 +1169,9 @@ export default function App() {
1120
1169
  };
1121
1170
  }, [activeWsId]);
1122
1171
 
1123
- // Load git changes when tab switches to 'changes' or active workspace changes
1172
+ // Load git changes for the Changes tab and the Overview (per-repo topology panel)
1124
1173
  useEffect(() => {
1125
- if (activeWsId && subTab === 'changes') {
1174
+ if (activeWsId && (subTab === 'changes' || subTab === 'overview')) {
1126
1175
  fetchGitChanges(activeWsId);
1127
1176
  }
1128
1177
  }, [activeWsId, subTab]);
@@ -1180,12 +1229,12 @@ Workspace Metadata:
1180
1229
  - Mapped Repositories: ${repoNames}
1181
1230
 
1182
1231
  Core Instructions:
1183
- 1. Always inspect and update "session.md" (session state handover memo) and "plan.md" (tasks checklist) at the workspace root as you progress.
1232
+ 1. Always read and append to "nexusflow-knowledge.md" (persistent workspace memory & decisions) as you progress, and follow the phased order in "nexusflow-plan.md".
1184
1233
  2. Read "WORKSPACE.md" at the root for a detailed index of repository relationships, tech stacks, and listening ports.
1185
1234
  3. Follow all project-specific rules in "CLAUDE.md", ".cursorrules", or "AGENTS.md" in sub-repositories.
1186
1235
  `;
1187
1236
  navigator.clipboard.writeText(prompt);
1188
- showToast('Universal AI briefing prompt copied to clipboard!', 'success');
1237
+ showToast('AI context prompt copied to clipboard!', 'success');
1189
1238
  };
1190
1239
 
1191
1240
  const handleDeleteWorkspace = async (wsName: string) => {
@@ -1508,7 +1557,7 @@ Core Instructions:
1508
1557
  return (
1509
1558
  <div className="flex flex-col h-screen w-full bg-[#060813] text-[#d1d5db] font-mono text-[11px] overflow-hidden select-none border-t border-gray-800">
1510
1559
  {/* Terminal Header */}
1511
- <div className="flex items-center justify-between px-3 py-2 bg-[#0b0f19] border-b border-gray-800 shrink-0 text-[10px]">
1560
+ <div className="flex items-center justify-between px-3 py-2 bg-surface border-b border-gray-800 shrink-0 text-[10px]">
1512
1561
  <div className="flex items-center gap-2">
1513
1562
  <span className="font-bold text-indigo-400">NEXUSFLOW_SHELL</span>
1514
1563
  <span className="text-gray-700">|</span>
@@ -1707,122 +1756,24 @@ Core Instructions:
1707
1756
  }
1708
1757
 
1709
1758
  return (
1710
- <div className="flex min-h-screen bg-[#05070c] text-slate-300 font-mono crt-screen">
1711
- {/* Sidebar Navigation */}
1712
- <aside className="w-64 bg-[#05070c] border-r border-slate-900 flex flex-col p-6 shrink-0 relative z-10 neon-border">
1713
- <div className="flex items-center gap-3 mb-10 px-2">
1714
- <div className="w-9 h-9 bg-gradient-to-tr from-cyan-500 to-violet-600 rounded-lg flex items-center justify-center font-bold text-white shadow-lg shadow-cyan-500/10 text-lg select-none">
1715
- NF
1716
- </div>
1717
- <div>
1718
- <span className="text-sm font-bold tracking-wider text-white">
1719
- NexusFlow
1720
- </span>
1721
- <span className="block text-[8px] text-cyan-400 font-semibold tracking-widest uppercase mt-0.5">COMMAND_CENTER</span>
1722
- </div>
1723
- </div>
1724
- <nav className="flex-1">
1725
- <ul className="flex flex-col gap-2">
1726
- <li>
1727
- <button
1728
- className={`w-full flex items-center gap-3 p-3 rounded-lg text-xs font-bold transition-all cursor-pointer border relative overflow-hidden group ${
1729
- view === 'guide'
1730
- ? 'text-cyan-400 bg-cyan-950/30 border-cyan-900/60 shadow-[0_0_15px_rgba(6,182,212,0.15)]'
1731
- : 'text-slate-400 border-transparent hover:text-white hover:bg-slate-900/40'
1732
- }`}
1733
- onClick={() => {
1734
- setView('guide');
1735
- }}
1736
- >
1737
- <Sparkles size={16} className="text-cyan-400 group-hover:scale-110 transition-transform" />
1738
- Getting Started
1739
- </button>
1740
- </li>
1741
- <li>
1742
- <button
1743
- className={`w-full flex items-center gap-3 p-3 rounded-lg text-xs font-bold transition-all cursor-pointer border relative overflow-hidden group ${
1744
- view === 'create'
1745
- ? 'text-cyan-400 bg-cyan-950/30 border-cyan-900/60 shadow-[0_0_15px_rgba(6,182,212,0.15)]'
1746
- : 'text-slate-400 border-transparent hover:text-white hover:bg-slate-900/40'
1747
- }`}
1748
- onClick={() => {
1749
- setView('create');
1750
- setActiveStep(0);
1751
- setCreatedWorkspace(null);
1752
- setBranchName('');
1753
- setDescription('');
1754
- setSelectedRepos([]);
1755
- setLocalLlmEnabled(config?.localLlm?.enabled || false);
1756
- }}
1757
- >
1758
- <PlusCircle size={16} className="text-cyan-400 group-hover:scale-110 transition-transform" />
1759
- New Workspace
1760
- </button>
1761
- </li>
1762
- <li>
1763
- <button
1764
- className={`w-full flex items-center gap-3 p-3 rounded-lg text-xs font-bold transition-all cursor-pointer border relative overflow-hidden group ${
1765
- view === 'workspaces'
1766
- ? 'text-cyan-400 bg-cyan-950/30 border-cyan-900/60 shadow-[0_0_15px_rgba(6,182,212,0.15)]'
1767
- : 'text-slate-400 border-transparent hover:text-white hover:bg-slate-900/40'
1768
- }`}
1769
- onClick={() => {
1770
- setView('workspaces');
1771
- fetchWorkspaces();
1772
- }}
1773
- >
1774
- <FolderGit2 size={16} className="text-cyan-400 group-hover:scale-110 transition-transform" />
1775
- Active Workspaces
1776
- </button>
1777
- </li>
1778
- <li>
1779
- <button
1780
- className={`w-full flex items-center gap-3 p-3 rounded-lg text-xs font-bold transition-all cursor-pointer border relative overflow-hidden group ${
1781
- view === 'workflows'
1782
- ? 'text-cyan-400 bg-cyan-950/30 border-cyan-900/60 shadow-[0_0_15px_rgba(6,182,212,0.15)]'
1783
- : 'text-slate-400 border-transparent hover:text-white hover:bg-slate-900/40'
1784
- }`}
1785
- onClick={() => {
1786
- setView('workflows');
1787
- fetchWorkflowTemplates();
1788
- if (workflowTemplates.length > 0) {
1789
- const first = workflowTemplates[0];
1790
- setSelectedMgtTemplateId(first.id);
1791
- setMgtTemplateName(first.name);
1792
- setMgtTemplateContent(first.content);
1793
- }
1794
- setAnalysisResult(null);
1795
- }}
1796
- >
1797
- <Workflow size={16} className="text-cyan-400 group-hover:scale-110 transition-transform" />
1798
- Team Strategies
1799
- </button>
1800
- </li>
1801
- <li>
1802
- <button
1803
- className={`w-full flex items-center gap-3 p-3 rounded-lg text-xs font-bold transition-all cursor-pointer border relative overflow-hidden group ${
1804
- view === 'settings'
1805
- ? 'text-cyan-400 bg-cyan-950/30 border-cyan-900/60 shadow-[0_0_15px_rgba(6,182,212,0.15)]'
1806
- : 'text-slate-400 border-transparent hover:text-white hover:bg-slate-900/40'
1807
- }`}
1808
- onClick={() => {
1809
- setView('settings');
1810
- fetchConfig();
1811
- }}
1812
- >
1813
- <SettingsIcon size={16} className="text-cyan-400 group-hover:scale-110 transition-transform" />
1814
- Settings
1815
- </button>
1816
- </li>
1817
- </ul>
1818
- </nav>
1819
- <div className="pt-6 border-t border-slate-900 text-[10px] text-slate-500 text-center tracking-wider font-semibold uppercase">
1820
- SYSTEM_UI: ONLINE v{appVersion}
1821
- </div>
1822
- </aside>
1759
+ <div className="flex min-h-screen bg-base text-content">
1760
+ <AppSidebar
1761
+ pathname={location.pathname}
1762
+ appVersion={appVersion}
1763
+ onNavigate={navigate}
1764
+ onNewWorkspace={() => {
1765
+ setActiveStep(0);
1766
+ setCreatedWorkspace(null);
1767
+ setBranchName('');
1768
+ setDescription('');
1769
+ setSelectedRepos([]);
1770
+ setLocalLlmEnabled(config?.localLlm?.enabled || false);
1771
+ navigate('/new');
1772
+ }}
1773
+ />
1823
1774
 
1824
1775
  {/* Main Content Area */}
1825
- <main className="flex-1 p-8 overflow-y-auto max-w-7xl w-full mx-auto">
1776
+ <main className="flex-1 overflow-y-auto p-6 sm:p-8">
1826
1777
  {configLoading ? (
1827
1778
  <div className="flex flex-col items-center justify-center py-40 gap-4 text-gray-400">
1828
1779
  <RefreshCw className="animate-spin text-indigo-400" size={32} />
@@ -1882,6 +1833,26 @@ Core Instructions:
1882
1833
  </div>
1883
1834
  )}
1884
1835
 
1836
+ {/* View: Dashboard (Overview) */}
1837
+ {view === 'dashboard' && config && (
1838
+ <DashboardPage
1839
+ workspaces={workspaces}
1840
+ workspaceStatuses={workspaceStatuses}
1841
+ workspacesLoading={workspacesLoading}
1842
+ statusesLoading={statusesLoading}
1843
+ onOpenWorkspace={(id) => navigate(`/workspaces/${encodeURIComponent(id)}`)}
1844
+ onNewWorkspace={() => {
1845
+ setActiveStep(0);
1846
+ setCreatedWorkspace(null);
1847
+ setBranchName('');
1848
+ setDescription('');
1849
+ setSelectedRepos([]);
1850
+ setLocalLlmEnabled(config?.localLlm?.enabled || false);
1851
+ navigate('/new');
1852
+ }}
1853
+ />
1854
+ )}
1855
+
1885
1856
  {/* View 0: Getting Started Guide */}
1886
1857
  {view === 'guide' && config && (
1887
1858
  <div className="max-w-4xl mx-auto">
@@ -1899,7 +1870,7 @@ Core Instructions:
1899
1870
 
1900
1871
  <div className="grid grid-cols-1 md:grid-cols-2 gap-8 mb-10">
1901
1872
  {/* Left: Interactive Stepper */}
1902
- <div className="bg-[#111827]/40 border border-gray-800/80 rounded-xl p-6 shadow-xl backdrop-blur-sm space-y-6">
1873
+ <div className="bg-surface/40 border border-gray-800/80 rounded-xl p-6 shadow-xl backdrop-blur-sm space-y-6">
1903
1874
  <h2 className="text-lg font-bold text-white mb-4">NexusFlow Workflows</h2>
1904
1875
 
1905
1876
  <div className="flex gap-4">
@@ -1943,7 +1914,7 @@ Core Instructions:
1943
1914
  </div>
1944
1915
 
1945
1916
  {/* Right: Quick actions and Telemetry info */}
1946
- <div className="bg-[#111827]/40 border border-gray-800/80 rounded-xl p-6 shadow-xl backdrop-blur-sm flex flex-col justify-between">
1917
+ <div className="bg-surface/40 border border-gray-800/80 rounded-xl p-6 shadow-xl backdrop-blur-sm flex flex-col justify-between">
1947
1918
  <div>
1948
1919
  <h2 className="text-lg font-bold text-white mb-4">Current Configuration</h2>
1949
1920
  <div className="space-y-3 text-xs">
@@ -1969,13 +1940,13 @@ Core Instructions:
1969
1940
  <div className="pt-6 border-t border-gray-800/60 flex flex-col gap-2">
1970
1941
  <button
1971
1942
  className="w-full inline-flex items-center justify-center gap-2 px-4 py-2.5 rounded-lg text-xs font-semibold bg-gradient-to-r from-indigo-500 to-indigo-600 hover:from-indigo-600 hover:to-indigo-700 text-white shadow-md shadow-indigo-500/10 hover:-translate-y-0.5 active:translate-y-0 transition-all cursor-pointer"
1972
- onClick={() => setView('create')}
1943
+ onClick={() => navigate('/new')}
1973
1944
  >
1974
1945
  <PlusCircle size={14} /> Create a Workspace
1975
1946
  </button>
1976
1947
  <button
1977
1948
  className="w-full inline-flex items-center justify-center gap-2 px-4 py-2.5 rounded-lg text-xs font-semibold bg-gray-900 border border-gray-800 hover:bg-gray-800 hover:border-gray-700 text-white transition-all cursor-pointer"
1978
- onClick={() => setView('settings')}
1949
+ onClick={() => navigate('/settings')}
1979
1950
  >
1980
1951
  <SettingsIcon size={14} className="text-gray-500" /> Modify Settings
1981
1952
  </button>
@@ -1984,7 +1955,7 @@ Core Instructions:
1984
1955
  </div>
1985
1956
 
1986
1957
  {/* Compare dashboard at the bottom */}
1987
- <div className="bg-[#111827]/20 border border-gray-800/80 rounded-xl p-6 shadow-md">
1958
+ <div className="bg-surface/20 border border-gray-800/80 rounded-xl p-6 shadow-md">
1988
1959
  <h4 className="text-xs font-semibold uppercase tracking-wider text-gray-500 mb-3">Industry Comparison</h4>
1989
1960
  <div className="overflow-x-auto">
1990
1961
  <table className="w-full text-[10px] text-gray-400 text-left border-collapse">
@@ -2047,7 +2018,7 @@ Core Instructions:
2047
2018
  ></div>
2048
2019
  <div className="flex flex-col items-center gap-2">
2049
2020
  <div className={`w-8 h-8 rounded-full border-2 flex items-center justify-center font-bold text-xs transition-all ${
2050
- activeStep > 0 ? 'bg-emerald-500 border-emerald-500 text-white' : activeStep === 0 ? 'border-indigo-500 bg-[#0b0f19] text-white shadow-lg shadow-indigo-500/20' : 'border-gray-800 bg-gray-900 text-gray-500'
2021
+ activeStep > 0 ? 'bg-emerald-500 border-emerald-500 text-white' : activeStep === 0 ? 'border-indigo-500 bg-surface text-white shadow-lg shadow-indigo-500/20' : 'border-gray-800 bg-gray-900 text-gray-500'
2051
2022
  }`}>
2052
2023
  {activeStep > 0 ? <Check size={14} /> : '1'}
2053
2024
  </div>
@@ -2055,7 +2026,7 @@ Core Instructions:
2055
2026
  </div>
2056
2027
  <div className="flex flex-col items-center gap-2">
2057
2028
  <div className={`w-8 h-8 rounded-full border-2 flex items-center justify-center font-bold text-xs transition-all ${
2058
- activeStep > 1 ? 'bg-emerald-500 border-emerald-500 text-white' : activeStep === 1 ? 'border-indigo-500 bg-[#0b0f19] text-white shadow-lg shadow-indigo-500/20' : 'border-gray-800 bg-gray-900 text-gray-500'
2029
+ activeStep > 1 ? 'bg-emerald-500 border-emerald-500 text-white' : activeStep === 1 ? 'border-indigo-500 bg-surface text-white shadow-lg shadow-indigo-500/20' : 'border-gray-800 bg-gray-900 text-gray-500'
2059
2030
  }`}>
2060
2031
  {activeStep > 1 ? <Check size={14} /> : '2'}
2061
2032
  </div>
@@ -2063,7 +2034,7 @@ Core Instructions:
2063
2034
  </div>
2064
2035
  <div className="flex flex-col items-center gap-2">
2065
2036
  <div className={`w-8 h-8 rounded-full border-2 flex items-center justify-center font-bold text-xs transition-all ${
2066
- activeStep > 2 ? 'bg-emerald-500 border-emerald-500 text-white' : activeStep === 2 ? 'border-indigo-500 bg-[#0b0f19] text-white shadow-lg shadow-indigo-500/20' : 'border-gray-800 bg-gray-900 text-gray-500'
2037
+ activeStep > 2 ? 'bg-emerald-500 border-emerald-500 text-white' : activeStep === 2 ? 'border-indigo-500 bg-surface text-white shadow-lg shadow-indigo-500/20' : 'border-gray-800 bg-gray-900 text-gray-500'
2067
2038
  }`}>
2068
2039
  {activeStep > 2 ? <Check size={14} /> : '3'}
2069
2040
  </div>
@@ -2071,7 +2042,7 @@ Core Instructions:
2071
2042
  </div>
2072
2043
  <div className="flex flex-col items-center gap-2">
2073
2044
  <div className={`w-8 h-8 rounded-full border-2 flex items-center justify-center font-bold text-xs transition-all ${
2074
- activeStep > 3 ? 'bg-emerald-500 border-emerald-500 text-white' : activeStep === 3 ? 'border-indigo-500 bg-[#0b0f19] text-white shadow-lg shadow-indigo-500/20' : 'border-gray-800 bg-gray-900 text-gray-500'
2045
+ activeStep > 3 ? 'bg-emerald-500 border-emerald-500 text-white' : activeStep === 3 ? 'border-indigo-500 bg-surface text-white shadow-lg shadow-indigo-500/20' : 'border-gray-800 bg-gray-900 text-gray-500'
2075
2046
  }`}>
2076
2047
  {activeStep > 3 ? <Check size={14} /> : '4'}
2077
2048
  </div>
@@ -2079,7 +2050,7 @@ Core Instructions:
2079
2050
  </div>
2080
2051
  <div className="flex flex-col items-center gap-2">
2081
2052
  <div className={`w-8 h-8 rounded-full border-2 flex items-center justify-center font-bold text-xs transition-all ${
2082
- activeStep === 4 ? 'border-emerald-500 bg-[#0b0f19] text-emerald-400 shadow-lg shadow-emerald-500/20' : 'border-gray-800 bg-gray-900 text-gray-500'
2053
+ activeStep === 4 ? 'border-emerald-500 bg-surface text-emerald-400 shadow-lg shadow-emerald-500/20' : 'border-gray-800 bg-gray-900 text-gray-500'
2083
2054
  }`}>
2084
2055
  5
2085
2056
  </div>
@@ -2089,12 +2060,12 @@ Core Instructions:
2089
2060
 
2090
2061
  {/* Step 0: Name & Description */}
2091
2062
  {activeStep === 0 && (
2092
- <div className="bg-[#111827]/40 border border-gray-800/80 rounded-xl p-8 shadow-xl backdrop-blur-sm">
2063
+ <div className="bg-surface/40 border border-gray-800/80 rounded-xl p-8 shadow-xl backdrop-blur-sm">
2093
2064
  <div className="mb-6">
2094
2065
  <label className="block text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2">Feature Branch Name</label>
2095
2066
  <input
2096
2067
  type="text"
2097
- className="w-full bg-[#111827] border border-gray-800 focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 rounded-lg px-4 py-3 text-white placeholder-gray-600 transition-all outline-none text-sm shadow-inner"
2068
+ className="w-full bg-surface border border-gray-800 focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 rounded-lg px-4 py-3 text-white placeholder-gray-600 transition-all outline-none text-sm shadow-inner"
2098
2069
  placeholder="e.g., feature/oauth-authentication-flow"
2099
2070
  value={branchName}
2100
2071
  onChange={(e) => setBranchName(e.target.value)}
@@ -2103,7 +2074,7 @@ Core Instructions:
2103
2074
  <div className="mb-8">
2104
2075
  <label className="block text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2">Feature Purpose & Context</label>
2105
2076
  <textarea
2106
- className="w-full bg-[#111827] border border-gray-800 focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 rounded-lg px-4 py-3 text-white placeholder-gray-600 transition-all outline-none text-sm min-h-[140px] resize-y shadow-inner"
2077
+ className="w-full bg-surface border border-gray-800 focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 rounded-lg px-4 py-3 text-white placeholder-gray-600 transition-all outline-none text-sm min-h-[140px] resize-y shadow-inner"
2107
2078
  placeholder="Describe what you want to build. This helps AI assistants analyze context and produce matching plans."
2108
2079
  value={description}
2109
2080
  onChange={(e) => setDescription(e.target.value)}
@@ -2123,14 +2094,14 @@ Core Instructions:
2123
2094
 
2124
2095
  {/* Step 1: Repo Selector */}
2125
2096
  {activeStep === 1 && (
2126
- <div className="bg-[#111827]/40 border border-gray-800/80 rounded-xl p-8 shadow-xl backdrop-blur-sm">
2097
+ <div className="bg-surface/40 border border-gray-800/80 rounded-xl p-8 shadow-xl backdrop-blur-sm">
2127
2098
  <div className="flex justify-between items-center mb-6">
2128
2099
  <label className="block text-xs font-semibold text-gray-400 uppercase tracking-wider">Select Repositories</label>
2129
2100
  <div className="relative w-64">
2130
2101
  <Search size={14} className="absolute left-3 top-3 text-gray-500" />
2131
2102
  <input
2132
2103
  type="text"
2133
- className="w-full bg-[#111827] border border-gray-800 focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 rounded-lg pl-9 pr-4 py-2 text-white placeholder-gray-600 transition-all outline-none text-xs"
2104
+ className="w-full bg-surface border border-gray-800 focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 rounded-lg pl-9 pr-4 py-2 text-white placeholder-gray-600 transition-all outline-none text-xs"
2134
2105
  placeholder="Search repo name..."
2135
2106
  value={repoSearch}
2136
2107
  onChange={(e) => setRepoSearch(e.target.value)}
@@ -2150,7 +2121,7 @@ Core Instructions:
2150
2121
  return (
2151
2122
  <div
2152
2123
  key={repo.path}
2153
- className={`bg-[#111827]/60 border rounded-xl p-4 flex items-start gap-3 cursor-pointer hover:bg-gray-800/20 hover:border-gray-700 transition-all ${
2124
+ className={`bg-surface/60 border rounded-xl p-4 flex items-start gap-3 cursor-pointer hover:bg-gray-800/20 hover:border-gray-700 transition-all ${
2154
2125
  isSelected ? 'border-indigo-500 bg-indigo-500/5' : 'border-gray-800/80'
2155
2126
  }`}
2156
2127
  onClick={() => handleToggleRepo(repo)}
@@ -2192,7 +2163,7 @@ Core Instructions:
2192
2163
 
2193
2164
  {/* Step 2: AI & Editor Settings */}
2194
2165
  {activeStep === 2 && (
2195
- <div className="bg-[#111827]/40 border border-gray-800/80 rounded-xl p-8 shadow-xl backdrop-blur-sm">
2166
+ <div className="bg-surface/40 border border-gray-800/80 rounded-xl p-8 shadow-xl backdrop-blur-sm">
2196
2167
  {creating ? (
2197
2168
  <div className="flex flex-col items-center py-6">
2198
2169
  <h3 className="text-lg font-bold text-white mb-2 flex items-center gap-2.5">
@@ -2292,7 +2263,7 @@ Core Instructions:
2292
2263
  return (
2293
2264
  <div
2294
2265
  key={ai.name}
2295
- className={`bg-[#111827]/60 border rounded-xl p-4 flex flex-col gap-3 cursor-pointer hover:border-gray-700 transition-all ${
2266
+ className={`bg-surface/60 border rounded-xl p-4 flex flex-col gap-3 cursor-pointer hover:border-gray-700 transition-all ${
2296
2267
  isSelected ? 'border-indigo-500 bg-indigo-500/5' : 'border-gray-800/80'
2297
2268
  }`}
2298
2269
  onClick={() => handleToggleAI(ai.name)}
@@ -2326,7 +2297,7 @@ Core Instructions:
2326
2297
  return (
2327
2298
  <div
2328
2299
  key={ed.command}
2329
- className={`bg-[#111827]/60 border rounded-xl p-4 flex flex-col cursor-pointer hover:border-gray-700 transition-all ${
2300
+ className={`bg-surface/60 border rounded-xl p-4 flex flex-col cursor-pointer hover:border-gray-700 transition-all ${
2330
2301
  isSelected ? 'border-indigo-500 bg-indigo-500/5' : 'border-gray-800/80'
2331
2302
  }`}
2332
2303
  onClick={() => {
@@ -2348,7 +2319,7 @@ Core Instructions:
2348
2319
  );
2349
2320
  })}
2350
2321
  <div
2351
- className={`bg-[#111827]/60 border rounded-xl p-4 flex flex-col cursor-pointer hover:border-gray-700 transition-all ${
2322
+ className={`bg-surface/60 border rounded-xl p-4 flex flex-col cursor-pointer hover:border-gray-700 transition-all ${
2352
2323
  selectedEditor === null ? 'border-indigo-500 bg-indigo-500/5' : 'border-gray-800/80'
2353
2324
  }`}
2354
2325
  onClick={() => {
@@ -2459,7 +2430,7 @@ Core Instructions:
2459
2430
 
2460
2431
  {/* Step 3: Team Strategy */}
2461
2432
  {activeStep === 3 && (
2462
- <div className="bg-[#111827]/40 border border-gray-800/80 rounded-xl p-8 shadow-xl backdrop-blur-sm">
2433
+ <div className="bg-surface/40 border border-gray-800/80 rounded-xl p-8 shadow-xl backdrop-blur-sm">
2463
2434
  {creating ? (
2464
2435
  <div className="flex flex-col items-center py-6">
2465
2436
  <h3 className="text-lg font-bold text-white mb-2 flex items-center gap-2.5">
@@ -2590,7 +2561,7 @@ Core Instructions:
2590
2561
  return (
2591
2562
  <div
2592
2563
  key={template.id}
2593
- className={`bg-[#111827]/60 border rounded-xl p-4 flex flex-col gap-2 cursor-pointer hover:border-gray-700 transition-all ${
2564
+ className={`bg-surface/60 border rounded-xl p-4 flex flex-col gap-2 cursor-pointer hover:border-gray-700 transition-all ${
2594
2565
  isSelected ? 'border-indigo-500 bg-indigo-500/5' : 'border-gray-800/80'
2595
2566
  }`}
2596
2567
  onClick={() => {
@@ -2614,7 +2585,7 @@ Core Instructions:
2614
2585
  You can customize these instructions directly. They will be saved in the workspace context.
2615
2586
  </p>
2616
2587
  <textarea
2617
- className="w-full bg-[#111827] border border-gray-850 focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 rounded-lg px-4 py-3 text-white placeholder-gray-605 transition-all outline-none text-xs font-mono min-h-[220px] resize-y shadow-inner leading-relaxed"
2588
+ className="w-full bg-surface border border-gray-850 focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 rounded-lg px-4 py-3 text-white placeholder-gray-605 transition-all outline-none text-xs font-mono min-h-[220px] resize-y shadow-inner leading-relaxed"
2618
2589
  value={customTeamworkInstructions}
2619
2590
  onChange={(e) => setCustomTeamworkInstructions(e.target.value)}
2620
2591
  placeholder="Enter custom instructions for how the AI agents should coordinate..."
@@ -2651,7 +2622,7 @@ Core Instructions:
2651
2622
 
2652
2623
  {/* Step 4: Success Screen */}
2653
2624
  {activeStep === 4 && createdWorkspace && (
2654
- <div className="bg-[#111827]/40 border border-gray-800/80 rounded-xl p-10 text-center shadow-xl backdrop-blur-sm">
2625
+ <div className="bg-surface/40 border border-gray-800/80 rounded-xl p-10 text-center shadow-xl backdrop-blur-sm">
2655
2626
  <div className="inline-flex items-center justify-center p-3 rounded-full bg-emerald-500/10 border border-emerald-500/20 text-emerald-400 mb-6">
2656
2627
  <Check size={36} />
2657
2628
  </div>
@@ -2675,9 +2646,8 @@ Core Instructions:
2675
2646
  <button
2676
2647
  className="inline-flex items-center justify-center gap-2 px-5 py-3 rounded-lg text-sm font-semibold bg-gray-900 border border-gray-800 hover:bg-gray-800 hover:border-gray-700 text-white transition-all cursor-pointer"
2677
2648
  onClick={() => {
2678
- setView('workspaces');
2679
2649
  fetchWorkspaces();
2680
- setActiveWsId(branchName);
2650
+ navigate(`/workspaces/${encodeURIComponent(branchName)}`);
2681
2651
  }}
2682
2652
  >
2683
2653
  <Terminal size={14} className="text-cyan-400" /> Manage Services
@@ -2694,69 +2664,32 @@ Core Instructions:
2694
2664
  </div>
2695
2665
  )}
2696
2666
 
2697
- {/* View 2: Active Workspaces Panel */}
2667
+ {/* View 2: Active Workspaces (master-detail) */}
2698
2668
  {view === 'workspaces' && (
2699
- <WorkspaceList
2700
- workspacesLoading={workspacesLoading}
2669
+ <WorkspacesPage
2701
2670
  workspaces={workspaces}
2702
- activeWsId={activeWsId}
2703
- setActiveWsId={setActiveWsId}
2671
+ workspaceStatuses={workspaceStatuses}
2672
+ statusesLoading={statusesLoading}
2673
+ workspacesLoading={workspacesLoading}
2674
+ fetchWorkspaces={fetchWorkspaces}
2675
+ selectedId={activeWsId}
2676
+ subTab={subTab}
2677
+ onSelect={(id) => navigate(`/workspaces/${encodeURIComponent(id)}`)}
2678
+ onSelectTab={(id, tab) => navigate(`/workspaces/${encodeURIComponent(id)}/${tab}`)}
2704
2679
  resumingWs={resumingWs}
2705
2680
  handleResumeSession={handleResumeSession}
2706
2681
  handleCopyPrompt={handleCopyPrompt}
2707
2682
  handleOpenInEditor={handleOpenInEditor}
2708
- fetchWorkspaces={fetchWorkspaces}
2709
- aiAssistants={aiAssistants}
2710
- repos={repos}
2683
+ handleDeleteWorkspace={handleDeleteWorkspace}
2711
2684
  deleteWsLoading={deleteWsLoading}
2685
+ repos={repos}
2712
2686
  addRepoLoading={addRepoLoading}
2713
- handleDeleteWorkspace={handleDeleteWorkspace}
2714
2687
  handleAddRepo={handleAddRepo}
2715
- services={services}
2716
- runningServices={runningServices}
2717
- selectedLogService={selectedLogService}
2718
- serviceLogs={serviceLogs}
2719
- logsEndRef={logsEndRef}
2720
- setSelectedLogService={setSelectedLogService}
2721
- handleStartServices={handleStartServices}
2722
- handleStopServices={handleStopServices}
2723
- orchTools={orchTools}
2724
- servicesLoading={servicesLoading}
2725
- gitChanges={gitChanges}
2726
- gitChangesLoading={gitChangesLoading}
2727
- syncLoading={syncLoading}
2728
- syncResults={syncResults}
2729
- commitMessage={commitMessage}
2730
- showCommitModal={showCommitModal}
2731
- commitLoading={commitLoading}
2732
- commitResults={commitResults}
2733
- setSyncResults={setSyncResults}
2734
- setCommitResults={setCommitResults}
2735
- setCommitMessage={setCommitMessage}
2736
- setShowCommitModal={setShowCommitModal}
2737
- fetchGitChanges={fetchGitChanges}
2738
- handleSyncAll={handleSyncAll}
2739
- handleCommitAll={handleCommitAll}
2740
- knowledgeContent={knowledgeContent}
2741
- knowledgeLoading={knowledgeLoading}
2742
- isEditingKnowledge={isEditingKnowledge}
2743
- editedKnowledge={editedKnowledge}
2744
- saveKnowledgeLoading={saveKnowledgeLoading}
2745
- setEditedKnowledge={setEditedKnowledge}
2746
- setIsEditingKnowledge={setIsEditingKnowledge}
2747
- handleSaveKnowledge={handleSaveKnowledge}
2748
- planContent={planContent}
2749
- planLoading={planLoading}
2750
- sessions={sessions}
2751
- sessionsLoading={sessionsLoading}
2752
- activeSession={activeSession}
2753
- transcript={transcript}
2754
- transcriptLoading={transcriptLoading}
2755
- setActiveSession={setActiveSession}
2756
- setTranscript={setTranscript}
2757
- fetchSessionTranscript={fetchSessionTranscript}
2758
- subTab={subTab}
2759
- setSubTab={setSubTab}
2688
+ sessionProps={{ sessions, sessionsLoading, activeSession, transcript, transcriptLoading, workspaces, setActiveSession, setTranscript, fetchSessionTranscript, handleResumeSession }}
2689
+ serviceProps={{ services, runningServices, selectedLogService, serviceLogs, logsEndRef, setSelectedLogService, handleStartServices, handleStopServices, orchTools, servicesLoading }}
2690
+ changesProps={{ gitChanges, gitChangesLoading, syncLoading, syncResults, commitMessage, showCommitModal, commitLoading, commitResults, setSyncResults, setCommitResults, setCommitMessage, setShowCommitModal, fetchGitChanges, handleSyncAll, handleCommitAll }}
2691
+ knowledgeProps={{ knowledgeContent, knowledgeLoading, isEditingKnowledge, editedKnowledge, saveKnowledgeLoading, setEditedKnowledge, setIsEditingKnowledge, handleSaveKnowledge }}
2692
+ planProps={{ planContent, planLoading }}
2760
2693
  />
2761
2694
  )}
2762
2695
 
@@ -2771,7 +2704,7 @@ Core Instructions:
2771
2704
  <div className="grid grid-cols-1 lg:grid-cols-12 gap-8 text-left">
2772
2705
  {/* Left sidebar: Strategy List */}
2773
2706
  <div className="lg:col-span-4 flex flex-col gap-4">
2774
- <div className="bg-[#111827]/40 border border-gray-800/80 rounded-xl p-5 shadow-md flex flex-col gap-4">
2707
+ <div className="bg-surface/40 border border-gray-800/80 rounded-xl p-5 shadow-md flex flex-col gap-4">
2775
2708
  <div className="flex justify-between items-center">
2776
2709
  <h3 className="text-xs font-semibold uppercase tracking-wider text-gray-500">Strategies</h3>
2777
2710
  <button
@@ -2834,7 +2767,7 @@ Core Instructions:
2834
2767
  {/* Right side: Strategy Detail / Edit Panel */}
2835
2768
  <div className="lg:col-span-8 flex flex-col gap-6">
2836
2769
  {(selectedMgtTemplateId || isEditingTemplate) ? (
2837
- <div className="bg-[#111827]/40 border border-gray-800/80 rounded-xl p-6 shadow-md flex flex-col gap-5">
2770
+ <div className="bg-surface/40 border border-gray-800/80 rounded-xl p-6 shadow-md flex flex-col gap-5">
2838
2771
  <div className="flex justify-between items-start gap-4">
2839
2772
  <div className="flex-1">
2840
2773
  {isEditingTemplate ? (
@@ -2842,7 +2775,7 @@ Core Instructions:
2842
2775
  <label className="text-xs font-semibold text-gray-400 uppercase tracking-wider">Strategy Name</label>
2843
2776
  <input
2844
2777
  type="text"
2845
- className="w-full bg-[#111827] border border-gray-850 focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 rounded-lg px-4 py-2 text-white text-sm outline-none transition-all"
2778
+ className="w-full bg-surface border border-gray-850 focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 rounded-lg px-4 py-2 text-white text-sm outline-none transition-all"
2846
2779
  value={mgtTemplateName}
2847
2780
  onChange={(e) => setMgtTemplateName(e.target.value)}
2848
2781
  placeholder="e.g. Test-Driven Development"
@@ -2940,7 +2873,7 @@ Core Instructions:
2940
2873
  <div className="flex flex-col gap-2">
2941
2874
  <label className="text-xs font-semibold text-gray-400 uppercase tracking-wider">Guidelines Markdown</label>
2942
2875
  <textarea
2943
- className="w-full bg-[#111827] border border-gray-850 focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 rounded-lg px-4 py-3 text-white placeholder-gray-600 transition-all outline-none text-xs font-mono min-h-[250px] resize-y shadow-inner leading-relaxed"
2876
+ className="w-full bg-surface border border-gray-850 focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 rounded-lg px-4 py-3 text-white placeholder-gray-600 transition-all outline-none text-xs font-mono min-h-[250px] resize-y shadow-inner leading-relaxed"
2944
2877
  value={mgtTemplateContent}
2945
2878
  onChange={(e) => setMgtTemplateContent(e.target.value)}
2946
2879
  disabled={!isEditingTemplate}
@@ -3003,7 +2936,7 @@ Core Instructions:
3003
2936
  <div className="flex flex-col gap-2">
3004
2937
  <label className="text-[10px] font-semibold text-gray-400 uppercase tracking-wider text-left">Evaluation Focus / Instructions (Optional)</label>
3005
2938
  <textarea
3006
- className="w-full bg-[#111827]/40 border border-gray-850 focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 rounded-lg px-4 py-2 text-white placeholder-gray-600 transition-all outline-none text-xs min-h-[60px] resize-y leading-relaxed font-sans"
2939
+ className="w-full bg-surface/40 border border-gray-850 focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 rounded-lg px-4 py-2 text-white placeholder-gray-600 transition-all outline-none text-xs min-h-[60px] resize-y leading-relaxed font-sans"
3007
2940
  value={mgtAnalysisComment}
3008
2941
  onChange={(e) => setMgtAnalysisComment(e.target.value)}
3009
2942
  placeholder="e.g. Focus on checking if timeouts are handled well, check subagent roles coordination..."
@@ -3039,7 +2972,7 @@ Core Instructions:
3039
2972
  )}
3040
2973
  </div>
3041
2974
  ) : (
3042
- <div className="h-[400px] bg-[#111827]/10 border border-gray-800/60 border-dashed rounded-xl flex flex-col items-center justify-center text-center p-6">
2975
+ <div className="h-[400px] bg-surface/10 border border-gray-800/60 border-dashed rounded-xl flex flex-col items-center justify-center text-center p-6">
3043
2976
  <FolderOpen size={36} className="text-gray-600 mb-3" />
3044
2977
  <span className="text-sm font-semibold text-gray-400">No strategy template selected</span>
3045
2978
  <p className="text-xs text-gray-500 mt-1 max-w-sm font-sans">
@@ -3071,12 +3004,12 @@ Core Instructions:
3071
3004
  </div>
3072
3005
  )}
3073
3006
 
3074
- <div className="grid grid-cols-1 md:grid-cols-2 gap-6 bg-[#111827]/40 border border-gray-800/80 rounded-xl p-8 shadow-xl backdrop-blur-sm mb-6">
3007
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-6 bg-surface/40 border border-gray-800/80 rounded-xl p-8 shadow-xl backdrop-blur-sm mb-6">
3075
3008
  <div className="flex flex-col">
3076
3009
  <label className="block text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2">Development Directory</label>
3077
3010
  <input
3078
3011
  type="text"
3079
- className="w-full bg-[#111827] border border-gray-800 focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 rounded-lg px-4 py-3 text-white placeholder-gray-600 transition-all outline-none text-sm shadow-inner"
3012
+ className="w-full bg-surface border border-gray-800 focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 rounded-lg px-4 py-3 text-white placeholder-gray-600 transition-all outline-none text-sm shadow-inner"
3080
3013
  value={config.devDir}
3081
3014
  onChange={(e) => setConfig({ ...config, devDir: e.target.value })}
3082
3015
  />
@@ -3087,7 +3020,7 @@ Core Instructions:
3087
3020
  <label className="block text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2">Workspaces Directory</label>
3088
3021
  <input
3089
3022
  type="text"
3090
- className="w-full bg-[#111827] border border-gray-800 focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 rounded-lg px-4 py-3 text-white placeholder-gray-600 transition-all outline-none text-sm shadow-inner"
3023
+ className="w-full bg-surface border border-gray-800 focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 rounded-lg px-4 py-3 text-white placeholder-gray-600 transition-all outline-none text-sm shadow-inner"
3091
3024
  value={config.workspacesDir}
3092
3025
  onChange={(e) => setConfig({ ...config, workspacesDir: e.target.value })}
3093
3026
  />
@@ -3098,7 +3031,7 @@ Core Instructions:
3098
3031
  <label className="block text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2">Repo Search Depth</label>
3099
3032
  <input
3100
3033
  type="number"
3101
- className="w-full bg-[#111827] border border-gray-800 focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 rounded-lg px-4 py-3 text-white placeholder-gray-600 transition-all outline-none text-sm shadow-inner"
3034
+ className="w-full bg-surface border border-gray-800 focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 rounded-lg px-4 py-3 text-white placeholder-gray-600 transition-all outline-none text-sm shadow-inner"
3102
3035
  min={1}
3103
3036
  max={5}
3104
3037
  value={config.scanDepth}
@@ -3110,7 +3043,7 @@ Core Instructions:
3110
3043
  <div className="flex flex-col">
3111
3044
  <label className="block text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2">Default Assistant</label>
3112
3045
  <select
3113
- className="w-full bg-[#111827] border border-gray-800 focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 rounded-lg px-4 py-3 text-white transition-all outline-none text-sm shadow-inner cursor-pointer"
3046
+ className="w-full bg-surface border border-gray-800 focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 rounded-lg px-4 py-3 text-white transition-all outline-none text-sm shadow-inner cursor-pointer"
3114
3047
  value={config.defaultAssistant || ''}
3115
3048
  onChange={(e) => setConfig({ ...config, defaultAssistant: e.target.value || null })}
3116
3049
  >
@@ -3127,7 +3060,7 @@ Core Instructions:
3127
3060
  <div className="flex flex-col">
3128
3061
  <label className="block text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2">Default Editor</label>
3129
3062
  <select
3130
- className="w-full bg-[#111827] border border-gray-800 focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 rounded-lg px-4 py-3 text-white transition-all outline-none text-sm shadow-inner cursor-pointer"
3063
+ className="w-full bg-surface border border-gray-800 focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 rounded-lg px-4 py-3 text-white transition-all outline-none text-sm shadow-inner cursor-pointer"
3131
3064
  value={config.defaultEditor || ''}
3132
3065
  onChange={(e) => setConfig({ ...config, defaultEditor: e.target.value || null })}
3133
3066
  >
@@ -3149,7 +3082,7 @@ Core Instructions:
3149
3082
  </label>
3150
3083
  <select
3151
3084
  id="storageProvider"
3152
- className="w-full max-w-md text-xs bg-[#111827] border border-gray-800 rounded-lg p-2 text-white focus:outline-none focus:border-indigo-500"
3085
+ className="w-full max-w-md text-xs bg-surface border border-gray-800 rounded-lg p-2 text-white focus:outline-none focus:border-indigo-500"
3153
3086
  value={config.storageProvider || 'local'}
3154
3087
  onChange={(e) => {
3155
3088
  const val = e.target.value;
@@ -3255,7 +3188,7 @@ Core Instructions:
3255
3188
  </div>
3256
3189
 
3257
3190
  {/* Local AI Co-Processor Settings */}
3258
- <div className="bg-[#111827]/40 border border-gray-800/80 rounded-xl p-8 shadow-xl backdrop-blur-sm mb-6 mt-6">
3191
+ <div className="bg-surface/40 border border-gray-800/80 rounded-xl p-8 shadow-xl backdrop-blur-sm mb-6 mt-6">
3259
3192
  <h3 className="text-lg font-bold text-white mb-2">Local AI Co-Processor Settings</h3>
3260
3193
  <p className="text-xs text-gray-450 mb-6 font-semibold">Enable a local LLM to handle simple tasks like log analysis, git diff summaries, and boilerplate code generation without using remote tokens.</p>
3261
3194
 
@@ -3274,7 +3207,7 @@ Core Instructions:
3274
3207
  <input
3275
3208
  type="checkbox"
3276
3209
  id="localLlmEnabled"
3277
- className="w-4 h-4 rounded border-gray-800 bg-[#111827] text-indigo-600 focus:ring-indigo-500 cursor-pointer"
3210
+ className="w-4 h-4 rounded border-gray-800 bg-surface text-indigo-600 focus:ring-indigo-500 cursor-pointer"
3278
3211
  checked={config.localLlm?.enabled || false}
3279
3212
  onChange={(e) => {
3280
3213
  const defaultLlm = { enabled: e.target.checked, provider: 'ollama' as const, endpoint: 'http://localhost:11434', model: recommendation?.recommendedModel || 'qwen2.5-coder:1.5b' };
@@ -3295,7 +3228,7 @@ Core Instructions:
3295
3228
  <div className="flex flex-col">
3296
3229
  <label className="block text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2">Local Provider</label>
3297
3230
  <select
3298
- className="w-full bg-[#111827] border border-gray-800 focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 rounded-lg px-4 py-3 text-white transition-all outline-none text-sm shadow-inner cursor-pointer"
3231
+ className="w-full bg-surface border border-gray-800 focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 rounded-lg px-4 py-3 text-white transition-all outline-none text-sm shadow-inner cursor-pointer"
3299
3232
  value={config.localLlm.provider}
3300
3233
  onChange={(e) => setConfig({
3301
3234
  ...config,
@@ -3312,7 +3245,7 @@ Core Instructions:
3312
3245
  <label className="block text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2">Endpoint URL</label>
3313
3246
  <input
3314
3247
  type="text"
3315
- className={`w-full bg-[#111827] border focus:ring-1 rounded-lg px-4 py-3 text-white placeholder-gray-600 transition-all outline-none text-sm shadow-inner ${
3248
+ className={`w-full bg-surface border focus:ring-1 rounded-lg px-4 py-3 text-white placeholder-gray-600 transition-all outline-none text-sm shadow-inner ${
3316
3249
  config.localLlm.endpoint && !config.localLlm.endpoint.trim().startsWith('http://') && !config.localLlm.endpoint.trim().startsWith('https://')
3317
3250
  ? 'border-rose-500/60 focus:border-rose-500 focus:ring-rose-500'
3318
3251
  : 'border-gray-800 focus:border-indigo-500 focus:ring-indigo-500'
@@ -3333,7 +3266,7 @@ Core Instructions:
3333
3266
  <label className="block text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2">Model Name</label>
3334
3267
  <input
3335
3268
  type="text"
3336
- className="w-full bg-[#111827] border border-gray-800 focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 rounded-lg px-4 py-3 text-white placeholder-gray-600 transition-all outline-none text-sm shadow-inner"
3269
+ className="w-full bg-surface border border-gray-800 focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 rounded-lg px-4 py-3 text-white placeholder-gray-600 transition-all outline-none text-sm shadow-inner"
3337
3270
  value={config.localLlm.model}
3338
3271
  onChange={(e) => setConfig({
3339
3272
  ...config,
@@ -3348,7 +3281,7 @@ Core Instructions:
3348
3281
  <label className="block text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2">API Key (Optional)</label>
3349
3282
  <input
3350
3283
  type="password"
3351
- className="w-full bg-[#111827] border border-gray-800 focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 rounded-lg px-4 py-3 text-white placeholder-gray-605 transition-all outline-none text-sm shadow-inner"
3284
+ className="w-full bg-surface border border-gray-800 focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 rounded-lg px-4 py-3 text-white placeholder-gray-605 transition-all outline-none text-sm shadow-inner"
3352
3285
  value={config.localLlm.apiKey || ''}
3353
3286
  placeholder="sk-..."
3354
3287
  onChange={(e) => setConfig({
@@ -3396,7 +3329,7 @@ Core Instructions:
3396
3329
  </div>
3397
3330
 
3398
3331
  {/* Toolchain Updates Section */}
3399
- <div className="bg-[#111827]/40 border border-gray-800/80 rounded-xl p-8 shadow-xl backdrop-blur-sm mt-6">
3332
+ <div className="bg-surface/40 border border-gray-800/80 rounded-xl p-8 shadow-xl backdrop-blur-sm mt-6">
3400
3333
  <div className="flex justify-between items-center mb-6">
3401
3334
  <div>
3402
3335
  <h3 className="text-lg font-bold text-white mb-1">AI Toolchain Updates</h3>
@@ -3505,7 +3438,7 @@ Core Instructions:
3505
3438
  {/* Transcript Modal Overlay */}
3506
3439
  {activeSession && (
3507
3440
  <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/75 backdrop-blur-sm p-4">
3508
- <div className="bg-[#0b0f19] border border-gray-800 rounded-2xl w-full max-w-4xl h-[80vh] flex flex-col shadow-2xl overflow-hidden animate-fadeIn">
3441
+ <div className="bg-surface border border-gray-800 rounded-2xl w-full max-w-4xl h-[80vh] flex flex-col shadow-2xl overflow-hidden animate-fadeIn">
3509
3442
  {/* Modal Header */}
3510
3443
  <div className="flex items-center justify-between px-6 py-4 border-b border-gray-800 bg-gray-950/40">
3511
3444
  <div>
@@ -3630,3 +3563,11 @@ Core Instructions:
3630
3563
  </div>
3631
3564
  );
3632
3565
  }
3566
+
3567
+ export default function App() {
3568
+ return (
3569
+ <HashRouter>
3570
+ <AppInner />
3571
+ </HashRouter>
3572
+ );
3573
+ }