@mrpatronz/nexusflow 0.2.17 → 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.
- package/.agents/skills/ccc/SKILL.md +71 -0
- package/.agents/skills/ccc/references/management.md +110 -0
- package/.agents/skills/ccc/references/settings.md +126 -0
- package/.github/dependabot.yml +52 -52
- package/.github/workflows/ci.yml +44 -0
- package/.github/workflows/dependabot-merge.yml +53 -53
- package/.github/workflows/release-desktop.yml +67 -0
- package/.github/workflows/release-npm.yml +65 -0
- package/.github/workflows/release-vscode.yml +61 -0
- package/.vscode/launch.json +17 -17
- package/.vscode/tasks.json +17 -17
- package/GETTING_STARTED.md +114 -114
- package/README.md +364 -336
- package/desktop/build-installer.js +228 -228
- package/desktop/build.js +118 -118
- package/desktop/installer/nexusflow.iss +35 -35
- package/desktop/neutralino.config.json +38 -38
- package/desktop/package-lock.json +1060 -1060
- package/desktop/package.json +14 -14
- package/dist/commands/adapter.d.ts +27 -0
- package/dist/commands/adapter.d.ts.map +1 -0
- package/dist/commands/adapter.js +318 -0
- package/dist/commands/adapter.js.map +1 -0
- package/dist/commands/add-repo.d.ts.map +1 -1
- package/dist/commands/add-repo.js +0 -1
- package/dist/commands/add-repo.js.map +1 -1
- package/dist/commands/commands.test.js +2 -2
- package/dist/commands/commands.test.js.map +1 -1
- package/dist/commands/config.d.ts +22 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +50 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/create.d.ts.map +1 -1
- package/dist/commands/create.js +14 -17
- package/dist/commands/create.js.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +11 -0
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/refresh.d.ts +1 -0
- package/dist/commands/refresh.d.ts.map +1 -1
- package/dist/commands/refresh.js +2 -14
- package/dist/commands/refresh.js.map +1 -1
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +36 -54
- package/dist/commands/sync.js.map +1 -1
- package/dist/commands/tui.d.ts.map +1 -1
- package/dist/commands/tui.js +63 -10
- package/dist/commands/tui.js.map +1 -1
- package/dist/core/adapters/local-storage.d.ts +14 -0
- package/dist/core/adapters/local-storage.d.ts.map +1 -0
- package/dist/core/adapters/local-storage.js +58 -0
- package/dist/core/adapters/local-storage.js.map +1 -0
- package/dist/core/adapters/obsidian-storage.d.ts +28 -0
- package/dist/core/adapters/obsidian-storage.d.ts.map +1 -0
- package/dist/core/adapters/obsidian-storage.js +135 -0
- package/dist/core/adapters/obsidian-storage.js.map +1 -0
- package/dist/core/adapters/registry.d.ts +8 -0
- package/dist/core/adapters/registry.d.ts.map +1 -0
- package/dist/core/adapters/registry.js +37 -0
- package/dist/core/adapters/registry.js.map +1 -0
- package/dist/core/adapters/storage.test.d.ts +2 -0
- package/dist/core/adapters/storage.test.d.ts.map +1 -0
- package/dist/core/adapters/storage.test.js +106 -0
- package/dist/core/adapters/storage.test.js.map +1 -0
- package/dist/core/adapters/vault-storage.d.ts +16 -0
- package/dist/core/adapters/vault-storage.d.ts.map +1 -0
- package/dist/core/adapters/vault-storage.js +77 -0
- package/dist/core/adapters/vault-storage.js.map +1 -0
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +28 -4
- package/dist/core/config.js.map +1 -1
- package/dist/core/plugins/index.d.ts +14 -0
- package/dist/core/plugins/index.d.ts.map +1 -0
- package/dist/core/plugins/index.js +2 -0
- package/dist/core/plugins/index.js.map +1 -0
- package/dist/core/plugins/loader.d.ts +2 -0
- package/dist/core/plugins/loader.d.ts.map +1 -0
- package/dist/core/plugins/loader.js +34 -0
- package/dist/core/plugins/loader.js.map +1 -0
- package/dist/core/ports/storage.d.ts +59 -0
- package/dist/core/ports/storage.d.ts.map +1 -0
- package/dist/core/ports/storage.js +10 -0
- package/dist/core/ports/storage.js.map +1 -0
- package/dist/core/storage.d.ts +10 -0
- package/dist/core/storage.d.ts.map +1 -0
- package/dist/core/storage.js +29 -0
- package/dist/core/storage.js.map +1 -0
- package/dist/core/sync.d.ts +44 -0
- package/dist/core/sync.d.ts.map +1 -0
- package/dist/core/sync.js +82 -0
- package/dist/core/sync.js.map +1 -0
- package/dist/core/workspace-state.d.ts +51 -0
- package/dist/core/workspace-state.d.ts.map +1 -0
- package/dist/core/workspace-state.js +108 -0
- package/dist/core/workspace-state.js.map +1 -0
- package/dist/core/workspace-state.test.d.ts +2 -0
- package/dist/core/workspace-state.test.d.ts.map +1 -0
- package/dist/core/workspace-state.test.js +84 -0
- package/dist/core/workspace-state.test.js.map +1 -0
- package/dist/core/workspace.d.ts.map +1 -1
- package/dist/core/workspace.js +110 -16
- package/dist/core/workspace.js.map +1 -1
- package/dist/generators/base.d.ts.map +1 -1
- package/dist/generators/base.js +80 -79
- package/dist/generators/base.js.map +1 -1
- package/dist/generators/codex.js +11 -11
- package/dist/generators/copilot.js +17 -17
- package/dist/generators/cursor.js +5 -5
- package/dist/generators/diff-context.d.ts +6 -0
- package/dist/generators/diff-context.d.ts.map +1 -0
- package/dist/generators/diff-context.js +68 -0
- package/dist/generators/diff-context.js.map +1 -0
- package/dist/generators/index.d.ts +1 -1
- package/dist/generators/index.d.ts.map +1 -1
- package/dist/generators/index.js +125 -68
- package/dist/generators/index.js.map +1 -1
- package/dist/generators/map-generator.d.ts.map +1 -1
- package/dist/generators/map-generator.js +21 -25
- package/dist/generators/map-generator.js.map +1 -1
- package/dist/generators/plan-generator.d.ts.map +1 -1
- package/dist/generators/plan-generator.js +3 -5
- package/dist/generators/plan-generator.js.map +1 -1
- package/dist/generators/skills-generator.js +28 -28
- package/dist/gui/assets/index-Bdbld6yY.css +1 -0
- package/dist/gui/assets/index-D8iJPvnk.js +26 -0
- package/dist/gui/icons.svg +24 -24
- package/dist/gui/index.html +18 -18
- package/dist/index.js +131 -20
- package/dist/index.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +42 -0
- package/dist/mcp/server.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +140 -56
- package/dist/server.js.map +1 -1
- package/dist/server.test.js +105 -48
- package/dist/server.test.js.map +1 -1
- package/dist/types.d.ts +38 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/local-ai.d.ts.map +1 -1
- package/dist/utils/local-ai.js +7 -3
- package/dist/utils/local-ai.js.map +1 -1
- package/dist/utils/multi-git.d.ts +33 -8
- package/dist/utils/multi-git.d.ts.map +1 -1
- package/dist/utils/multi-git.js +91 -19
- package/dist/utils/multi-git.js.map +1 -1
- package/dist/utils/multi-git.test.d.ts +2 -0
- package/dist/utils/multi-git.test.d.ts.map +1 -0
- package/dist/utils/multi-git.test.js +125 -0
- package/dist/utils/multi-git.test.js.map +1 -0
- package/dist/utils/update-check.d.ts.map +1 -1
- package/dist/utils/update-check.js +0 -28
- package/dist/utils/update-check.js.map +1 -1
- package/dist/utils/workflow-advisor.d.ts +16 -0
- package/dist/utils/workflow-advisor.d.ts.map +1 -0
- package/dist/utils/workflow-advisor.js +100 -0
- package/dist/utils/workflow-advisor.js.map +1 -0
- package/extension/package-lock.json +6044 -2673
- package/extension/package.json +117 -108
- package/extension/src/extension.ts +653 -631
- package/extension/tsconfig.json +21 -21
- package/gui/README.md +73 -73
- package/gui/e2e/dashboard.spec.ts +61 -0
- package/gui/e2e/wizard.spec.ts +346 -346
- package/gui/eslint.config.js +26 -26
- package/gui/index.html +17 -17
- package/gui/package-lock.json +3137 -3079
- package/gui/package.json +37 -36
- package/gui/playwright.config.ts +41 -41
- package/gui/public/icons.svg +24 -24
- package/gui/src/App.css +1 -1
- package/gui/src/App.tsx +3573 -3407
- package/gui/src/app/AppSidebar.tsx +69 -0
- package/gui/src/assets/vite.svg +1 -1
- package/gui/src/components/AddRepoPicker.tsx +81 -0
- package/gui/src/components/ui/Button.tsx +40 -0
- package/gui/src/components/ui/Card.tsx +6 -0
- package/gui/src/components/ui/EmptyState.tsx +22 -0
- package/gui/src/components/ui/Input.tsx +21 -0
- package/gui/src/components/ui/Menu.tsx +71 -0
- package/gui/src/components/ui/Modal.tsx +39 -0
- package/gui/src/components/ui/PageHeader.tsx +21 -0
- package/gui/src/components/ui/RepoStatusStrip.tsx +33 -0
- package/gui/src/components/ui/Skeleton.tsx +5 -0
- package/gui/src/components/ui/StatusPill.tsx +36 -0
- package/gui/src/components/ui/Tabs.tsx +40 -0
- package/gui/src/components/ui/cn.ts +4 -0
- package/gui/src/components/ui/index.ts +16 -0
- package/gui/src/features/changes/ChangesViewer.tsx +388 -388
- package/gui/src/features/knowledge/KnowledgeBase.tsx +84 -84
- package/gui/src/features/onboarding/OnboardingWizard.tsx +230 -230
- package/gui/src/features/plan/ImplementationPlan.tsx +32 -32
- package/gui/src/features/services/ServiceConsole.tsx +215 -250
- package/gui/src/features/sessions/SessionHistory.tsx +195 -195
- package/gui/src/index.css +167 -152
- package/gui/src/lib/status.ts +24 -0
- package/gui/src/main.tsx +94 -94
- package/gui/src/pages/DashboardPage.tsx +129 -0
- package/gui/src/pages/WorkspacesPage.tsx +352 -0
- package/gui/src/types.ts +81 -62
- package/gui/tsconfig.app.json +25 -25
- package/gui/tsconfig.json +7 -7
- package/gui/tsconfig.node.json +24 -24
- package/gui/vite.config.ts +12 -12
- package/package.json +55 -56
- package/resources/workflows/plan-implement-review.md +8 -8
- package/resources/workflows/research-verify.md +6 -6
- package/resources/workflows/solo-developer.md +3 -3
- package/scripts/simulate-workspaces.ts +55 -55
- package/skills-lock.json +11 -0
- package/src/analyzers/detect-apis.ts +290 -290
- package/src/analyzers/detect-deps.ts +315 -315
- package/src/analyzers/detect-existing.ts +74 -74
- package/src/analyzers/detect-ports.ts +110 -110
- package/src/analyzers/index.ts +97 -97
- package/src/analyzers/messaging-analyzer.ts +254 -254
- package/src/analyzers/readme-summarizer.ts +102 -102
- package/src/analyzers/run-analyzer.ts +269 -269
- package/src/analyzers/tech-stack.ts +283 -283
- package/src/commands/adapter.ts +348 -0
- package/src/commands/add-repo.ts +156 -157
- package/src/commands/commands.test.ts +156 -155
- package/src/commands/commit.ts +131 -131
- package/src/commands/config.ts +52 -0
- package/src/commands/create.ts +204 -207
- package/src/commands/desktop.ts +128 -128
- package/src/commands/diff.ts +125 -125
- package/src/commands/doctor.ts +370 -357
- package/src/commands/handoff.ts +266 -266
- package/src/commands/init.ts +134 -134
- package/src/commands/list.ts +46 -46
- package/src/commands/logs.ts +63 -63
- package/src/commands/mcp.ts +94 -92
- package/src/commands/open.ts +129 -129
- package/src/commands/refresh.ts +137 -147
- package/src/commands/remove.ts +98 -98
- package/src/commands/start.ts +117 -117
- package/src/commands/status.ts +54 -54
- package/src/commands/stop.ts +55 -55
- package/src/commands/sync.ts +125 -151
- package/src/commands/tui.ts +484 -424
- package/src/commands/ui.ts +111 -111
- package/src/core/adapters/local-storage.ts +66 -0
- package/src/core/adapters/obsidian-storage.ts +151 -0
- package/src/core/adapters/registry.ts +44 -0
- package/src/core/adapters/storage.test.ts +174 -0
- package/src/core/adapters/vault-storage.ts +86 -0
- package/src/core/config.test.ts +96 -96
- package/src/core/config.ts +140 -115
- package/src/core/graph.ts +344 -344
- package/src/core/plugins/index.ts +17 -0
- package/src/core/plugins/loader.ts +36 -0
- package/src/core/ports/storage.ts +71 -0
- package/src/core/scanner.test.ts +61 -61
- package/src/core/scanner.ts +91 -91
- package/src/core/storage.ts +37 -0
- package/src/core/sync.ts +121 -0
- package/src/core/workspace-state.test.ts +108 -0
- package/src/core/workspace-state.ts +130 -0
- package/src/core/workspace.ts +487 -380
- package/src/core/worktree.ts +120 -120
- package/src/generators/antigravity.ts +32 -32
- package/src/generators/base.ts +243 -240
- package/src/generators/claude.ts +34 -34
- package/src/generators/codex.ts +48 -48
- package/src/generators/copilot.ts +56 -56
- package/src/generators/cursor.ts +44 -44
- package/src/generators/diff-context.ts +75 -0
- package/src/generators/index.ts +322 -250
- package/src/generators/map-generator.test.ts +159 -159
- package/src/generators/map-generator.ts +539 -542
- package/src/generators/plan-generator.ts +483 -481
- package/src/generators/skills-generator.ts +259 -259
- package/src/index.ts +539 -426
- package/src/mcp/server.ts +338 -294
- package/src/orchestration/detect.ts +313 -313
- package/src/orchestration/index.ts +7 -7
- package/src/orchestration/runner.ts +283 -283
- package/src/server.test.ts +618 -555
- package/src/server.ts +1402 -1308
- package/src/types.ts +451 -408
- package/src/utils/detect-ai.test.ts +44 -44
- package/src/utils/detect-ai.ts +84 -84
- package/src/utils/detect-editors.test.ts +48 -48
- package/src/utils/detect-editors.ts +57 -57
- package/src/utils/git.test.ts +74 -74
- package/src/utils/git.ts +117 -117
- package/src/utils/local-ai.test.ts +130 -130
- package/src/utils/local-ai.ts +116 -111
- package/src/utils/multi-git.test.ts +158 -0
- package/src/utils/multi-git.ts +405 -313
- package/src/utils/prompts.ts +209 -209
- package/src/utils/session-finder.ts +483 -483
- package/src/utils/system-scanner.test.ts +89 -89
- package/src/utils/system-scanner.ts +96 -96
- package/src/utils/update-check.ts +286 -309
- package/src/utils/workflow-advisor.ts +118 -0
- package/src/utils/workflows.test.ts +114 -114
- package/src/utils/workflows.ts +178 -178
- package/tsconfig.json +19 -19
- package/vitest.config.ts +14 -14
- package/.github/workflows/release.yml +0 -112
- package/dist/commands/pack.d.ts +0 -7
- package/dist/commands/pack.d.ts.map +0 -1
- package/dist/commands/pack.js +0 -64
- package/dist/commands/pack.js.map +0 -1
- package/dist/core/packer.d.ts +0 -14
- package/dist/core/packer.d.ts.map +0 -1
- package/dist/core/packer.js +0 -87
- package/dist/core/packer.js.map +0 -1
- package/dist/core/packer.test.d.ts +0 -2
- package/dist/core/packer.test.d.ts.map +0 -1
- package/dist/core/packer.test.js +0 -82
- package/dist/core/packer.test.js.map +0 -1
- package/dist/gui/assets/index-Ct3qq-X4.js +0 -25
- package/dist/gui/assets/index-P_ZrgHXg.css +0 -1
- package/gui/src/features/workspace/WorkspaceList.tsx +0 -666
- package/src/commands/pack.ts +0 -73
- package/src/core/packer.test.ts +0 -99
- package/src/core/packer.ts +0 -107
|
@@ -1,666 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { Play, RefreshCw, FolderGit2, Sparkles, ExternalLink, Trash2, Terminal, Cpu, Layers, Copy, Check } from 'lucide-react';
|
|
3
|
-
import type { Feature, RunningService, ServiceConfig, OrchestrationDetection, RepoInfo, DetectedAI } from '../../types.js';
|
|
4
|
-
|
|
5
|
-
// Feature subcomponents
|
|
6
|
-
import { SessionHistory } from '../sessions/SessionHistory.js';
|
|
7
|
-
import { ServiceConsole } from '../services/ServiceConsole.js';
|
|
8
|
-
import { ChangesViewer } from '../changes/ChangesViewer.js';
|
|
9
|
-
import { KnowledgeBase } from '../knowledge/KnowledgeBase.js';
|
|
10
|
-
import { ImplementationPlan } from '../plan/ImplementationPlan.js';
|
|
11
|
-
|
|
12
|
-
interface WorkspaceListProps {
|
|
13
|
-
workspacesLoading: boolean;
|
|
14
|
-
workspaces: Feature[];
|
|
15
|
-
activeWsId: string | null;
|
|
16
|
-
setActiveWsId: (id: string | null) => void;
|
|
17
|
-
resumingWs: string | null;
|
|
18
|
-
handleResumeSession: (ws: Feature, sessionId?: string, assistant?: string) => Promise<void>;
|
|
19
|
-
handleCopyPrompt: (ws: Feature) => void;
|
|
20
|
-
handleOpenInEditor: (workspacePath: string) => Promise<void>;
|
|
21
|
-
fetchWorkspaces: () => Promise<void>;
|
|
22
|
-
|
|
23
|
-
// Deletion and repo addition props
|
|
24
|
-
repos: RepoInfo[];
|
|
25
|
-
deleteWsLoading: string | null;
|
|
26
|
-
addRepoLoading: boolean;
|
|
27
|
-
handleDeleteWorkspace: (wsName: string) => Promise<void>;
|
|
28
|
-
handleAddRepo: (wsName: string, repoPath: string) => Promise<void>;
|
|
29
|
-
|
|
30
|
-
// ServiceConsole props
|
|
31
|
-
services: ServiceConfig[];
|
|
32
|
-
runningServices: RunningService[];
|
|
33
|
-
selectedLogService: string | null;
|
|
34
|
-
serviceLogs: string;
|
|
35
|
-
logsEndRef: React.RefObject<HTMLDivElement | null>;
|
|
36
|
-
setSelectedLogService: (val: string | null) => void;
|
|
37
|
-
handleStartServices: (wsId: string) => Promise<void>;
|
|
38
|
-
handleStopServices: (wsId: string) => Promise<void>;
|
|
39
|
-
orchTools: OrchestrationDetection[];
|
|
40
|
-
servicesLoading: boolean;
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
// ChangesViewer props
|
|
44
|
-
gitChanges: any[];
|
|
45
|
-
gitChangesLoading: boolean;
|
|
46
|
-
syncLoading: boolean;
|
|
47
|
-
syncResults: any[] | null;
|
|
48
|
-
commitMessage: string;
|
|
49
|
-
showCommitModal: boolean;
|
|
50
|
-
commitLoading: boolean;
|
|
51
|
-
commitResults: any[] | null;
|
|
52
|
-
setSyncResults: (val: any[] | null) => void;
|
|
53
|
-
setCommitResults: (val: any[] | null) => void;
|
|
54
|
-
setCommitMessage: (val: string) => void;
|
|
55
|
-
setShowCommitModal: (val: boolean) => void;
|
|
56
|
-
fetchGitChanges: (wsId: string) => Promise<void>;
|
|
57
|
-
handleSyncAll: (wsId: string) => Promise<void>;
|
|
58
|
-
handleCommitAll: (wsId: string) => Promise<void>;
|
|
59
|
-
|
|
60
|
-
// KnowledgeBase props
|
|
61
|
-
knowledgeContent: string;
|
|
62
|
-
knowledgeLoading: boolean;
|
|
63
|
-
isEditingKnowledge: boolean;
|
|
64
|
-
editedKnowledge: string;
|
|
65
|
-
saveKnowledgeLoading: boolean;
|
|
66
|
-
setEditedKnowledge: (val: string) => void;
|
|
67
|
-
setIsEditingKnowledge: (val: boolean) => void;
|
|
68
|
-
handleSaveKnowledge: (wsId: string) => Promise<void>;
|
|
69
|
-
|
|
70
|
-
// ImplementationPlan props
|
|
71
|
-
planContent: string;
|
|
72
|
-
planLoading: boolean;
|
|
73
|
-
|
|
74
|
-
// SessionHistory props
|
|
75
|
-
sessions: any[];
|
|
76
|
-
sessionsLoading: boolean;
|
|
77
|
-
activeSession: any | null;
|
|
78
|
-
transcript: any[];
|
|
79
|
-
transcriptLoading: boolean;
|
|
80
|
-
setActiveSession: (val: any | null) => void;
|
|
81
|
-
setTranscript: (val: any[]) => void;
|
|
82
|
-
fetchSessionTranscript: (assistant: string, sessionId: string) => Promise<void>;
|
|
83
|
-
|
|
84
|
-
// Navigation tab states
|
|
85
|
-
subTab: 'overview' | 'sessions' | 'services' | 'changes' | 'knowledge' | 'plan';
|
|
86
|
-
setSubTab: (tab: 'overview' | 'sessions' | 'services' | 'changes' | 'knowledge' | 'plan') => void;
|
|
87
|
-
aiAssistants: DetectedAI[];
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const parseInlineStyles = (text: string): React.ReactNode => {
|
|
91
|
-
const tokenRegex = /(\*\*.*?\*\*|`.*?`|\*.*?\*)/g;
|
|
92
|
-
const parts = text.split(tokenRegex);
|
|
93
|
-
|
|
94
|
-
return parts.map((part, index) => {
|
|
95
|
-
if (part.startsWith('**') && part.endsWith('**')) {
|
|
96
|
-
return <strong key={index} className="font-bold text-gray-200">{part.slice(2, -2)}</strong>;
|
|
97
|
-
}
|
|
98
|
-
if (part.startsWith('`') && part.endsWith('`')) {
|
|
99
|
-
return <code key={index} className="px-1.5 py-0.5 bg-gray-900 border border-gray-800 text-cyan-400 rounded font-mono text-[10px]">{part.slice(1, -1)}</code>;
|
|
100
|
-
}
|
|
101
|
-
if (part.startsWith('*') && part.endsWith('*')) {
|
|
102
|
-
return <em key={index} className="italic text-gray-300">{part.slice(1, -1)}</em>;
|
|
103
|
-
}
|
|
104
|
-
return part;
|
|
105
|
-
});
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
const renderFormattedDescription = (text: string) => {
|
|
109
|
-
if (!text) return null;
|
|
110
|
-
|
|
111
|
-
const lines = text.split('\n');
|
|
112
|
-
const elements: React.ReactNode[] = [];
|
|
113
|
-
let currentList: { type: 'ul' | 'ol'; items: string[] } | null = null;
|
|
114
|
-
|
|
115
|
-
const flushList = (key: number) => {
|
|
116
|
-
if (currentList) {
|
|
117
|
-
const ListTag = currentList.type;
|
|
118
|
-
elements.push(
|
|
119
|
-
<ListTag key={`list-${key}`} className={currentList.type === 'ul' ? 'list-disc pl-5 my-1.5 space-y-1' : 'list-decimal pl-5 my-1.5 space-y-1'}>
|
|
120
|
-
{currentList.items.map((item, idx) => (
|
|
121
|
-
<li key={`item-${idx}`} className="leading-relaxed">{parseInlineStyles(item)}</li>
|
|
122
|
-
))}
|
|
123
|
-
</ListTag>
|
|
124
|
-
);
|
|
125
|
-
currentList = null;
|
|
126
|
-
}
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
lines.forEach((line, idx) => {
|
|
130
|
-
const trimmed = line.trim();
|
|
131
|
-
|
|
132
|
-
// Check for bullet list item
|
|
133
|
-
const bulletMatch = line.match(/^(\s*)[-*+]\s+(.*)/);
|
|
134
|
-
if (bulletMatch) {
|
|
135
|
-
if (!currentList || currentList.type !== 'ul') {
|
|
136
|
-
flushList(idx);
|
|
137
|
-
currentList = { type: 'ul', items: [] };
|
|
138
|
-
}
|
|
139
|
-
currentList.items.push(bulletMatch[2]);
|
|
140
|
-
return;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// Check for numbered list item
|
|
144
|
-
const numberMatch = line.match(/^(\s*)\d+\.\s+(.*)/);
|
|
145
|
-
if (numberMatch) {
|
|
146
|
-
if (!currentList || currentList.type !== 'ol') {
|
|
147
|
-
flushList(idx);
|
|
148
|
-
currentList = { type: 'ol', items: [] };
|
|
149
|
-
}
|
|
150
|
-
currentList.items.push(numberMatch[2]);
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// If not a list item, flush any active list first
|
|
155
|
-
flushList(idx);
|
|
156
|
-
|
|
157
|
-
if (trimmed === '') {
|
|
158
|
-
elements.push(<div key={`empty-${idx}`} className="h-2" />);
|
|
159
|
-
} else {
|
|
160
|
-
elements.push(
|
|
161
|
-
<div key={`line-${idx}`} className="leading-relaxed">
|
|
162
|
-
{parseInlineStyles(line)}
|
|
163
|
-
</div>
|
|
164
|
-
);
|
|
165
|
-
}
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
flushList(lines.length);
|
|
169
|
-
return <div className="space-y-1">{elements}</div>;
|
|
170
|
-
};
|
|
171
|
-
|
|
172
|
-
export const WorkspaceList: React.FC<WorkspaceListProps> = ({
|
|
173
|
-
workspacesLoading,
|
|
174
|
-
workspaces,
|
|
175
|
-
activeWsId,
|
|
176
|
-
setActiveWsId,
|
|
177
|
-
resumingWs,
|
|
178
|
-
handleResumeSession,
|
|
179
|
-
handleCopyPrompt,
|
|
180
|
-
handleOpenInEditor,
|
|
181
|
-
fetchWorkspaces,
|
|
182
|
-
repos,
|
|
183
|
-
deleteWsLoading,
|
|
184
|
-
addRepoLoading,
|
|
185
|
-
handleDeleteWorkspace,
|
|
186
|
-
handleAddRepo,
|
|
187
|
-
|
|
188
|
-
// ServiceConsole
|
|
189
|
-
services,
|
|
190
|
-
runningServices,
|
|
191
|
-
selectedLogService,
|
|
192
|
-
serviceLogs,
|
|
193
|
-
logsEndRef,
|
|
194
|
-
setSelectedLogService,
|
|
195
|
-
handleStartServices,
|
|
196
|
-
handleStopServices,
|
|
197
|
-
orchTools,
|
|
198
|
-
servicesLoading,
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
// ChangesViewer
|
|
202
|
-
gitChanges,
|
|
203
|
-
gitChangesLoading,
|
|
204
|
-
syncLoading,
|
|
205
|
-
syncResults,
|
|
206
|
-
commitMessage,
|
|
207
|
-
showCommitModal,
|
|
208
|
-
commitLoading,
|
|
209
|
-
commitResults,
|
|
210
|
-
setSyncResults,
|
|
211
|
-
setCommitResults,
|
|
212
|
-
setCommitMessage,
|
|
213
|
-
setShowCommitModal,
|
|
214
|
-
fetchGitChanges,
|
|
215
|
-
handleSyncAll,
|
|
216
|
-
handleCommitAll,
|
|
217
|
-
|
|
218
|
-
// KnowledgeBase
|
|
219
|
-
knowledgeContent,
|
|
220
|
-
knowledgeLoading,
|
|
221
|
-
isEditingKnowledge,
|
|
222
|
-
editedKnowledge,
|
|
223
|
-
saveKnowledgeLoading,
|
|
224
|
-
setEditedKnowledge,
|
|
225
|
-
setIsEditingKnowledge,
|
|
226
|
-
handleSaveKnowledge,
|
|
227
|
-
|
|
228
|
-
// ImplementationPlan
|
|
229
|
-
planContent,
|
|
230
|
-
planLoading,
|
|
231
|
-
|
|
232
|
-
// SessionHistory
|
|
233
|
-
sessions,
|
|
234
|
-
sessionsLoading,
|
|
235
|
-
activeSession,
|
|
236
|
-
transcript,
|
|
237
|
-
transcriptLoading,
|
|
238
|
-
setActiveSession,
|
|
239
|
-
setTranscript,
|
|
240
|
-
fetchSessionTranscript,
|
|
241
|
-
|
|
242
|
-
// Tabs
|
|
243
|
-
subTab,
|
|
244
|
-
setSubTab,
|
|
245
|
-
aiAssistants,
|
|
246
|
-
}) => {
|
|
247
|
-
const [copiedText, setCopiedText] = React.useState<string | null>(null);
|
|
248
|
-
const handleCopy = (text: string) => {
|
|
249
|
-
navigator.clipboard.writeText(text);
|
|
250
|
-
setCopiedText(text);
|
|
251
|
-
setTimeout(() => setCopiedText(null), 2000);
|
|
252
|
-
};
|
|
253
|
-
|
|
254
|
-
return (
|
|
255
|
-
<div className="max-w-5xl mx-auto">
|
|
256
|
-
<header className="flex justify-between items-center mb-8">
|
|
257
|
-
<div>
|
|
258
|
-
<h1 className="text-3xl font-extrabold tracking-tight text-white mb-2">Active Workspaces</h1>
|
|
259
|
-
<p className="text-sm text-gray-400">Monitor running servers, libraries, and processes on your development branches.</p>
|
|
260
|
-
</div>
|
|
261
|
-
<button
|
|
262
|
-
className="inline-flex items-center justify-center gap-2 px-4 py-2 bg-gray-900 border border-gray-800 hover:bg-gray-800 hover:border-gray-700 rounded-lg text-xs font-semibold transition-all cursor-pointer"
|
|
263
|
-
onClick={fetchWorkspaces}
|
|
264
|
-
disabled={workspacesLoading}
|
|
265
|
-
>
|
|
266
|
-
<RefreshCw size={14} className={workspacesLoading ? 'animate-spin text-cyan-400' : ''} /> Refresh
|
|
267
|
-
</button>
|
|
268
|
-
</header>
|
|
269
|
-
|
|
270
|
-
{workspacesLoading ? (
|
|
271
|
-
<div className="flex flex-col items-center py-40 gap-4 text-gray-400">
|
|
272
|
-
<RefreshCw className="animate-spin text-cyan-400" size={32} />
|
|
273
|
-
<span className="text-sm">Fetching workspace details...</span>
|
|
274
|
-
</div>
|
|
275
|
-
) : workspaces.length === 0 ? (
|
|
276
|
-
<div className="flex flex-col items-center justify-center py-24 bg-[#111827]/20 border border-gray-800/80 rounded-xl text-center">
|
|
277
|
-
<FolderGit2 size={44} className="text-gray-600 mb-4" />
|
|
278
|
-
<h3 className="text-lg font-bold text-white">No Active Workspaces</h3>
|
|
279
|
-
<p className="text-xs text-gray-505 max-w-sm mt-1">
|
|
280
|
-
No feature workspaces were detected in your development folder. Create a workspace to start.
|
|
281
|
-
</p>
|
|
282
|
-
</div>
|
|
283
|
-
) : (
|
|
284
|
-
<div className="flex flex-col gap-6">
|
|
285
|
-
{workspaces.map((ws) => {
|
|
286
|
-
const isExpanded = activeWsId === ws.branchName;
|
|
287
|
-
return (
|
|
288
|
-
<div key={ws.id} className="glass-card p-8 rounded-2xl shadow-xl hover:shadow-2xl border border-slate-800/40 relative overflow-hidden transition-all duration-300 before:absolute before:inset-x-0 before:top-0 before:h-[1px] before:bg-gradient-to-r before:from-cyan-500/10 via-violet-500/10 to-transparent">
|
|
289
|
-
<div className="flex justify-between items-start gap-4 mb-4">
|
|
290
|
-
<div>
|
|
291
|
-
<h3 className="text-lg font-bold text-white hover:text-cyan-400 transition-colors">{ws.branchName}</h3>
|
|
292
|
-
<div className="flex items-center gap-3 text-xs text-slate-500 mt-1">
|
|
293
|
-
<span>Created: {new Date(ws.createdAt).toLocaleDateString()}</span>
|
|
294
|
-
<span className="h-1 w-1 rounded-full bg-slate-850"></span>
|
|
295
|
-
<span>{ws.repos.length} repos</span>
|
|
296
|
-
</div>
|
|
297
|
-
</div>
|
|
298
|
-
<div className="flex gap-2">
|
|
299
|
-
<button
|
|
300
|
-
className="inline-flex items-center justify-center gap-1.5 px-3.5 py-2.5 bg-emerald-650 hover:bg-emerald-600 text-white rounded-xl text-xs font-semibold transition-all cursor-pointer shadow-md shadow-emerald-600/10 disabled:opacity-40 disabled:cursor-not-allowed"
|
|
301
|
-
onClick={() => handleResumeSession(ws)}
|
|
302
|
-
disabled={resumingWs === ws.branchName}
|
|
303
|
-
>
|
|
304
|
-
<Play size={12} className={resumingWs === ws.branchName ? 'animate-spin' : ''} />
|
|
305
|
-
{resumingWs === ws.branchName ? 'Resuming...' : 'Resume Session'}
|
|
306
|
-
</button>
|
|
307
|
-
<button
|
|
308
|
-
className="inline-flex items-center justify-center gap-1.5 px-3.5 py-2.5 bg-slate-900 border border-slate-800/80 hover:bg-slate-800 hover:border-slate-700 rounded-xl text-xs font-semibold transition-all cursor-pointer text-slate-350 hover:text-white"
|
|
309
|
-
onClick={() => handleCopyPrompt(ws)}
|
|
310
|
-
>
|
|
311
|
-
<Sparkles size={12} className="text-cyan-400" /> Copy Prompt
|
|
312
|
-
</button>
|
|
313
|
-
<button
|
|
314
|
-
className="inline-flex items-center justify-center gap-1.5 px-3.5 py-2.5 bg-slate-900 border border-slate-800/80 hover:bg-slate-800 hover:border-slate-700 rounded-xl text-xs font-semibold transition-all cursor-pointer text-slate-350 hover:text-white"
|
|
315
|
-
onClick={() => handleOpenInEditor(ws.workspacePath)}
|
|
316
|
-
>
|
|
317
|
-
<ExternalLink size={12} /> Open
|
|
318
|
-
</button>
|
|
319
|
-
<button
|
|
320
|
-
className="inline-flex items-center justify-center gap-1.5 px-3.5 py-2.5 bg-cyan-600 hover:bg-cyan-500 text-white rounded-xl text-xs font-semibold transition-all cursor-pointer shadow-md shadow-cyan-650/10"
|
|
321
|
-
onClick={() => {
|
|
322
|
-
if (isExpanded) {
|
|
323
|
-
setActiveWsId(null);
|
|
324
|
-
} else {
|
|
325
|
-
setActiveWsId(ws.branchName);
|
|
326
|
-
}
|
|
327
|
-
}}
|
|
328
|
-
>
|
|
329
|
-
{isExpanded ? 'Hide Runner' : 'Orchestrate'}
|
|
330
|
-
</button>
|
|
331
|
-
<button
|
|
332
|
-
className="inline-flex items-center justify-center gap-1.5 px-3.5 py-2.5 bg-red-950/40 border border-red-900/60 hover:bg-red-900/60 hover:border-red-800 rounded-xl text-xs font-semibold text-red-200 transition-all cursor-pointer disabled:opacity-40 disabled:cursor-not-allowed animate-fade-in"
|
|
333
|
-
onClick={() => handleDeleteWorkspace(ws.branchName)}
|
|
334
|
-
disabled={deleteWsLoading === ws.branchName}
|
|
335
|
-
>
|
|
336
|
-
<Trash2 size={12} className={deleteWsLoading === ws.branchName ? 'animate-spin' : ''} />
|
|
337
|
-
{deleteWsLoading === ws.branchName ? 'Deleting...' : 'Delete'}
|
|
338
|
-
</button>
|
|
339
|
-
</div>
|
|
340
|
-
</div>
|
|
341
|
-
|
|
342
|
-
<div className="text-xs text-slate-350 bg-slate-950/60 border-l-2 border-cyan-500/80 rounded-r-xl px-5 py-3.5 mb-5 font-normal leading-relaxed relative overflow-hidden before:absolute before:inset-y-0 before:right-0 before:w-12 before:bg-gradient-to-r before:from-transparent before:to-cyan-500/2">
|
|
343
|
-
{renderFormattedDescription(ws.description)}
|
|
344
|
-
</div>
|
|
345
|
-
|
|
346
|
-
<div className="flex items-center gap-3 mb-4">
|
|
347
|
-
<div className="flex flex-wrap gap-2">
|
|
348
|
-
{ws.repos.map((repoPath) => (
|
|
349
|
-
<span key={repoPath} className="text-[10px] px-2.5 py-1.5 bg-slate-950/60 border border-slate-850 text-slate-300 rounded-lg font-semibold select-all">
|
|
350
|
-
{repoPath.split(/[\\/]/).pop()}
|
|
351
|
-
</span>
|
|
352
|
-
))}
|
|
353
|
-
</div>
|
|
354
|
-
|
|
355
|
-
{repos.filter((r) => !ws.repos.includes(r.path)).length > 0 && (
|
|
356
|
-
<div className="flex items-center gap-1.5 ml-auto">
|
|
357
|
-
<select
|
|
358
|
-
id={`add-repo-select-feature-${ws.branchName}`}
|
|
359
|
-
className="bg-slate-905 border border-slate-800 text-slate-300 rounded-lg text-[10px] px-3 py-1.5 font-semibold outline-none focus:border-cyan-500 disabled:opacity-50 disabled:cursor-not-allowed cursor-pointer transition-all hover:border-slate-700"
|
|
360
|
-
defaultValue=""
|
|
361
|
-
onChange={async (e) => {
|
|
362
|
-
const val = e.target.value;
|
|
363
|
-
if (val) {
|
|
364
|
-
if (window.confirm(`Are you sure you want to add repository "${val.split(/[\\/]/).pop()}" to this workspace?\nThis will create a new git worktree and re-run analysis.`)) {
|
|
365
|
-
await handleAddRepo(ws.branchName, val);
|
|
366
|
-
}
|
|
367
|
-
e.target.value = "";
|
|
368
|
-
}
|
|
369
|
-
}}
|
|
370
|
-
disabled={addRepoLoading}
|
|
371
|
-
>
|
|
372
|
-
<option value="" disabled>+ Add Repository</option>
|
|
373
|
-
{repos
|
|
374
|
-
.filter((r) => !ws.repos.includes(r.path))
|
|
375
|
-
.map((r) => (
|
|
376
|
-
<option key={r.path} value={r.path}>{r.name}</option>
|
|
377
|
-
))
|
|
378
|
-
}
|
|
379
|
-
</select>
|
|
380
|
-
</div>
|
|
381
|
-
)}
|
|
382
|
-
</div>
|
|
383
|
-
|
|
384
|
-
{/* Expansion: Process management console */}
|
|
385
|
-
{isExpanded && (
|
|
386
|
-
<div className="mt-6 pt-6 border-t border-slate-850/80">
|
|
387
|
-
{/* Sub-tab Navigation */}
|
|
388
|
-
<div className="flex flex-wrap items-center gap-1.5 p-1 bg-slate-950/60 rounded-xl border border-slate-900/60 mb-6 w-max max-w-full overflow-x-auto">
|
|
389
|
-
<button
|
|
390
|
-
className={`px-4 py-2 rounded-lg text-xs font-bold transition-all cursor-pointer select-none ${
|
|
391
|
-
subTab === 'overview'
|
|
392
|
-
? 'bg-cyan-950/30 border border-cyan-900/60 text-cyan-400 shadow-[0_0_15px_rgba(6,182,212,0.1)]'
|
|
393
|
-
: 'text-slate-500 hover:text-slate-300 hover:bg-slate-900/40 border border-transparent'
|
|
394
|
-
}`}
|
|
395
|
-
onClick={() => setSubTab('overview')}
|
|
396
|
-
>
|
|
397
|
-
Harness & Capabilities
|
|
398
|
-
</button>
|
|
399
|
-
<button
|
|
400
|
-
className={`px-4 py-2 rounded-lg text-xs font-bold transition-all cursor-pointer select-none ${
|
|
401
|
-
subTab === 'sessions'
|
|
402
|
-
? 'bg-cyan-950/30 border border-cyan-900/60 text-cyan-400 shadow-[0_0_15px_rgba(6,182,212,0.1)]'
|
|
403
|
-
: 'text-slate-500 hover:text-slate-300 hover:bg-slate-900/40 border border-transparent'
|
|
404
|
-
}`}
|
|
405
|
-
onClick={() => setSubTab('sessions')}
|
|
406
|
-
>
|
|
407
|
-
AI Session History
|
|
408
|
-
</button>
|
|
409
|
-
<button
|
|
410
|
-
className={`px-4 py-2 rounded-lg text-xs font-bold transition-all cursor-pointer select-none ${
|
|
411
|
-
subTab === 'services'
|
|
412
|
-
? 'bg-cyan-950/30 border border-cyan-900/60 text-cyan-400 shadow-[0_0_15px_rgba(6,182,212,0.1)]'
|
|
413
|
-
: 'text-slate-500 hover:text-slate-300 hover:bg-slate-900/40 border border-transparent'
|
|
414
|
-
}`}
|
|
415
|
-
onClick={() => setSubTab('services')}
|
|
416
|
-
>
|
|
417
|
-
Orchestrated Services
|
|
418
|
-
</button>
|
|
419
|
-
<button
|
|
420
|
-
className={`px-4 py-2 rounded-lg text-xs font-bold transition-all cursor-pointer select-none ${
|
|
421
|
-
subTab === 'changes'
|
|
422
|
-
? 'bg-cyan-950/30 border border-cyan-900/60 text-cyan-400 shadow-[0_0_15px_rgba(6,182,212,0.1)]'
|
|
423
|
-
: 'text-slate-500 hover:text-slate-300 hover:bg-slate-900/40 border border-transparent'
|
|
424
|
-
}`}
|
|
425
|
-
onClick={() => setSubTab('changes')}
|
|
426
|
-
>
|
|
427
|
-
Active Changes (AI Diffs)
|
|
428
|
-
</button>
|
|
429
|
-
<button
|
|
430
|
-
className={`px-4 py-2 rounded-lg text-xs font-bold transition-all cursor-pointer select-none ${
|
|
431
|
-
subTab === 'knowledge'
|
|
432
|
-
? 'bg-cyan-950/30 border border-cyan-900/60 text-cyan-400 shadow-[0_0_15px_rgba(6,182,212,0.1)]'
|
|
433
|
-
: 'text-slate-500 hover:text-slate-300 hover:bg-slate-900/40 border border-transparent'
|
|
434
|
-
}`}
|
|
435
|
-
onClick={() => setSubTab('knowledge')}
|
|
436
|
-
>
|
|
437
|
-
Knowledge Base
|
|
438
|
-
</button>
|
|
439
|
-
<button
|
|
440
|
-
className={`px-4 py-2 rounded-lg text-xs font-bold transition-all cursor-pointer select-none ${
|
|
441
|
-
subTab === 'plan'
|
|
442
|
-
? 'bg-cyan-950/30 border border-cyan-900/60 text-cyan-400 shadow-[0_0_15px_rgba(6,182,212,0.1)]'
|
|
443
|
-
: 'text-slate-500 hover:text-slate-300 hover:bg-slate-900/40 border border-transparent'
|
|
444
|
-
}`}
|
|
445
|
-
onClick={() => setSubTab('plan')}
|
|
446
|
-
>
|
|
447
|
-
Implementation Plan
|
|
448
|
-
</button>
|
|
449
|
-
</div>
|
|
450
|
-
|
|
451
|
-
{subTab === 'overview' && (
|
|
452
|
-
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 text-sm text-gray-300 animate-fade-in">
|
|
453
|
-
{/* Section 1: AI Assistant Harnesses */}
|
|
454
|
-
<div className="bg-gray-950/20 border border-gray-800/80 rounded-xl p-5">
|
|
455
|
-
<div className="flex items-center gap-2 mb-4 border-b border-gray-800/80 pb-3">
|
|
456
|
-
<Cpu size={18} className="text-cyan-400" />
|
|
457
|
-
<h4 className="font-bold text-white">AI Assistant Harnesses</h4>
|
|
458
|
-
</div>
|
|
459
|
-
<p className="text-xs text-gray-400 mb-4">
|
|
460
|
-
These coding assistants are configured to run contextually inside this workspace. Select an assistant to see its setup.
|
|
461
|
-
</p>
|
|
462
|
-
<div className="flex flex-col gap-3">
|
|
463
|
-
{['antigravity', 'claude', 'copilot', 'cursor', 'codex'].map((name) => {
|
|
464
|
-
const isConfigured = ws.assistants.includes(name as any);
|
|
465
|
-
const isDetected = aiAssistants.find((a) => a.name === name)?.detected;
|
|
466
|
-
let displayName = name.charAt(0).toUpperCase() + name.slice(1);
|
|
467
|
-
if (name === 'antigravity') displayName = 'Antigravity (Ollama/Gemini)';
|
|
468
|
-
else if (name === 'codex') displayName = 'OpenAI Codex';
|
|
469
|
-
else if (name === 'copilot') displayName = 'GitHub Copilot';
|
|
470
|
-
else if (name === 'claude') displayName = 'Claude Code';
|
|
471
|
-
|
|
472
|
-
let resumeCmd = '';
|
|
473
|
-
if (name === 'antigravity') resumeCmd = 'agy --continue';
|
|
474
|
-
else if (name === 'claude') resumeCmd = 'claude --resume';
|
|
475
|
-
else if (name === 'codex') resumeCmd = 'codex resume';
|
|
476
|
-
else if (name === 'copilot') resumeCmd = 'copilot --resume';
|
|
477
|
-
|
|
478
|
-
return (
|
|
479
|
-
<div key={name} className="flex flex-col p-3 bg-gray-900/40 border border-gray-800/60 rounded-lg">
|
|
480
|
-
<div className="flex items-center justify-between gap-2">
|
|
481
|
-
<div className="flex items-center gap-2">
|
|
482
|
-
<span className={`h-2 w-2 rounded-full ${isConfigured ? 'bg-cyan-500 shadow-sm' : 'bg-gray-700'}`}></span>
|
|
483
|
-
<span className="font-semibold text-xs text-gray-200">{displayName}</span>
|
|
484
|
-
</div>
|
|
485
|
-
<div className="flex items-center gap-1.5 text-[10px] font-medium">
|
|
486
|
-
{isConfigured && <span className="text-cyan-400 bg-cyan-950/20 px-2 py-0.5 rounded border border-cyan-900/40 text-[9px] font-bold uppercase tracking-wider">Active</span>}
|
|
487
|
-
{isDetected ? (
|
|
488
|
-
<span className="text-emerald-400 bg-emerald-500/10 px-2 py-0.5 rounded border border-emerald-500/20 text-[9px] font-bold uppercase tracking-wider">Installed</span>
|
|
489
|
-
) : (
|
|
490
|
-
<span className="text-gray-500 bg-gray-950 px-2 py-0.5 rounded border border-gray-800/60 text-[9px] font-bold uppercase tracking-wider">Not Probed</span>
|
|
491
|
-
)}
|
|
492
|
-
</div>
|
|
493
|
-
</div>
|
|
494
|
-
{isConfigured && resumeCmd && (
|
|
495
|
-
<div className="mt-2.5 flex items-center justify-between gap-2 bg-gray-950/80 px-2.5 py-1.5 rounded border border-gray-800/60 font-mono text-[10px]">
|
|
496
|
-
<span className="text-cyan-400 truncate">{resumeCmd}</span>
|
|
497
|
-
<button
|
|
498
|
-
onClick={() => handleCopy(resumeCmd)}
|
|
499
|
-
className="text-gray-400 hover:text-white transition-colors cursor-pointer"
|
|
500
|
-
title="Copy Resume Command"
|
|
501
|
-
>
|
|
502
|
-
{copiedText === resumeCmd ? <Check size={11} className="text-emerald-400" /> : <Copy size={11} />}
|
|
503
|
-
</button>
|
|
504
|
-
</div>
|
|
505
|
-
)}
|
|
506
|
-
</div>
|
|
507
|
-
);
|
|
508
|
-
})}
|
|
509
|
-
</div>
|
|
510
|
-
</div>
|
|
511
|
-
|
|
512
|
-
{/* Section 2: Model Context Protocol (MCP) */}
|
|
513
|
-
<div className="flex flex-col gap-6">
|
|
514
|
-
<div className="bg-gray-950/20 border border-gray-800/80 rounded-xl p-5">
|
|
515
|
-
<div className="flex items-center gap-2 mb-4 border-b border-gray-800/80 pb-3">
|
|
516
|
-
<Layers size={18} className="text-cyan-400" />
|
|
517
|
-
<h4 className="font-bold text-white">Local MCP Server (Tools)</h4>
|
|
518
|
-
</div>
|
|
519
|
-
<p className="text-xs text-gray-400 mb-4">
|
|
520
|
-
NexusFlow runs a Model Context Protocol (MCP) server that exposes local workspace-scoped tools to your AI agents.
|
|
521
|
-
</p>
|
|
522
|
-
<div className="flex flex-col gap-3.5">
|
|
523
|
-
<div className="flex flex-col gap-1">
|
|
524
|
-
<div className="flex items-center gap-2 text-xs font-semibold text-cyan-455">
|
|
525
|
-
<code>search_workspace</code>
|
|
526
|
-
</div>
|
|
527
|
-
<span className="text-[11px] text-gray-400">
|
|
528
|
-
Extremely fast query/regex search across all microservices and repos in the workspace.
|
|
529
|
-
</span>
|
|
530
|
-
</div>
|
|
531
|
-
<div className="flex flex-col gap-1 border-t border-gray-800/40 pt-2.5">
|
|
532
|
-
<div className="flex items-center gap-2 text-xs font-semibold text-cyan-455">
|
|
533
|
-
<code>get_service_logs</code>
|
|
534
|
-
</div>
|
|
535
|
-
<span className="text-[11px] text-gray-400">
|
|
536
|
-
Fetch and parse recent stdout/stderr output from any background service running in the workspace.
|
|
537
|
-
</span>
|
|
538
|
-
</div>
|
|
539
|
-
<div className="flex flex-col gap-1 border-t border-gray-800/40 pt-2.5">
|
|
540
|
-
<div className="flex items-center gap-2 text-xs font-semibold text-cyan-455">
|
|
541
|
-
<code>delegate_to_local_agent</code>
|
|
542
|
-
</div>
|
|
543
|
-
<span className="text-[11px] text-gray-400">
|
|
544
|
-
Delegate sub-tasks or log analysis to a lightweight LLM running locally to optimize remote token usage.
|
|
545
|
-
</span>
|
|
546
|
-
</div>
|
|
547
|
-
</div>
|
|
548
|
-
</div>
|
|
549
|
-
|
|
550
|
-
{/* CLI shortcuts */}
|
|
551
|
-
<div className="bg-gray-950/20 border border-gray-800/80 rounded-xl p-5">
|
|
552
|
-
<div className="flex items-center gap-2 mb-4 border-b border-gray-800/80 pb-3">
|
|
553
|
-
<Terminal size={18} className="text-cyan-400" />
|
|
554
|
-
<h4 className="font-bold text-white">Workspace CLI Shortcuts</h4>
|
|
555
|
-
</div>
|
|
556
|
-
<div className="flex flex-col gap-2.5">
|
|
557
|
-
{[
|
|
558
|
-
{ cmd: 'nexusflow start', desc: 'Spin up detected backend/frontend services' },
|
|
559
|
-
{ cmd: 'nexusflow sync', desc: 'Rebase worktrees with upstream defaults' },
|
|
560
|
-
{ cmd: 'nexusflow commit -m "update"', desc: 'Stage and commit changes across repos' },
|
|
561
|
-
{ cmd: 'nexusflow diff', desc: 'Unified codebase diff across repos' },
|
|
562
|
-
{ cmd: 'nexusflow handoff', desc: 'Generate resume context file' }
|
|
563
|
-
].map(({ cmd, desc }) => (
|
|
564
|
-
<div key={cmd} className="flex flex-col gap-1">
|
|
565
|
-
<div className="flex items-center justify-between gap-2">
|
|
566
|
-
<code className="text-xs text-cyan-400">{cmd}</code>
|
|
567
|
-
<button
|
|
568
|
-
onClick={() => handleCopy(cmd)}
|
|
569
|
-
className="text-gray-400 hover:text-white transition-colors cursor-pointer"
|
|
570
|
-
title="Copy Command"
|
|
571
|
-
>
|
|
572
|
-
{copiedText === cmd ? <Check size={11} className="text-emerald-400" /> : <Copy size={11} />}
|
|
573
|
-
</button>
|
|
574
|
-
</div>
|
|
575
|
-
<span className="text-[11px] text-gray-550">{desc}</span>
|
|
576
|
-
</div>
|
|
577
|
-
))}
|
|
578
|
-
</div>
|
|
579
|
-
</div>
|
|
580
|
-
</div>
|
|
581
|
-
</div>
|
|
582
|
-
)}
|
|
583
|
-
|
|
584
|
-
{subTab === 'sessions' && (
|
|
585
|
-
<SessionHistory
|
|
586
|
-
ws={ws}
|
|
587
|
-
sessions={sessions}
|
|
588
|
-
sessionsLoading={sessionsLoading}
|
|
589
|
-
activeSession={activeSession}
|
|
590
|
-
transcript={transcript}
|
|
591
|
-
transcriptLoading={transcriptLoading}
|
|
592
|
-
workspaces={workspaces}
|
|
593
|
-
setActiveSession={setActiveSession}
|
|
594
|
-
setTranscript={setTranscript}
|
|
595
|
-
fetchSessionTranscript={fetchSessionTranscript}
|
|
596
|
-
handleResumeSession={handleResumeSession}
|
|
597
|
-
/>
|
|
598
|
-
)}
|
|
599
|
-
|
|
600
|
-
{subTab === 'services' && (
|
|
601
|
-
<ServiceConsole
|
|
602
|
-
ws={ws}
|
|
603
|
-
services={services}
|
|
604
|
-
runningServices={runningServices}
|
|
605
|
-
selectedLogService={selectedLogService}
|
|
606
|
-
serviceLogs={serviceLogs}
|
|
607
|
-
logsEndRef={logsEndRef}
|
|
608
|
-
setSelectedLogService={setSelectedLogService}
|
|
609
|
-
handleStartServices={handleStartServices}
|
|
610
|
-
handleStopServices={handleStopServices}
|
|
611
|
-
orchTools={orchTools}
|
|
612
|
-
servicesLoading={servicesLoading}
|
|
613
|
-
/>
|
|
614
|
-
)}
|
|
615
|
-
|
|
616
|
-
{subTab === 'changes' && (
|
|
617
|
-
<ChangesViewer
|
|
618
|
-
ws={ws}
|
|
619
|
-
gitChanges={gitChanges}
|
|
620
|
-
gitChangesLoading={gitChangesLoading}
|
|
621
|
-
syncLoading={syncLoading}
|
|
622
|
-
syncResults={syncResults}
|
|
623
|
-
commitMessage={commitMessage}
|
|
624
|
-
showCommitModal={showCommitModal}
|
|
625
|
-
commitLoading={commitLoading}
|
|
626
|
-
commitResults={commitResults}
|
|
627
|
-
setSyncResults={setSyncResults}
|
|
628
|
-
setCommitResults={setCommitResults}
|
|
629
|
-
setCommitMessage={setCommitMessage}
|
|
630
|
-
setShowCommitModal={setShowCommitModal}
|
|
631
|
-
fetchGitChanges={fetchGitChanges}
|
|
632
|
-
handleSyncAll={handleSyncAll}
|
|
633
|
-
handleCommitAll={handleCommitAll}
|
|
634
|
-
/>
|
|
635
|
-
)}
|
|
636
|
-
|
|
637
|
-
{subTab === 'knowledge' && (
|
|
638
|
-
<KnowledgeBase
|
|
639
|
-
ws={ws}
|
|
640
|
-
knowledgeContent={knowledgeContent}
|
|
641
|
-
knowledgeLoading={knowledgeLoading}
|
|
642
|
-
isEditingKnowledge={isEditingKnowledge}
|
|
643
|
-
editedKnowledge={editedKnowledge}
|
|
644
|
-
saveKnowledgeLoading={saveKnowledgeLoading}
|
|
645
|
-
setEditedKnowledge={setEditedKnowledge}
|
|
646
|
-
setIsEditingKnowledge={setIsEditingKnowledge}
|
|
647
|
-
handleSaveKnowledge={handleSaveKnowledge}
|
|
648
|
-
/>
|
|
649
|
-
)}
|
|
650
|
-
|
|
651
|
-
{subTab === 'plan' && (
|
|
652
|
-
<ImplementationPlan
|
|
653
|
-
planContent={planContent}
|
|
654
|
-
planLoading={planLoading}
|
|
655
|
-
/>
|
|
656
|
-
)}
|
|
657
|
-
</div>
|
|
658
|
-
)}
|
|
659
|
-
</div>
|
|
660
|
-
);
|
|
661
|
-
})}
|
|
662
|
-
</div>
|
|
663
|
-
)}
|
|
664
|
-
</div>
|
|
665
|
-
);
|
|
666
|
-
};
|