orbital-command 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +396 -0
- package/bin/orbital.js +362 -0
- package/dist/assets/WorkflowVisualizer-BZ21PIIF.js +84 -0
- package/dist/assets/WorkflowVisualizer-BZV40eAE.css +1 -0
- package/dist/assets/charts-D__PA1zp.js +72 -0
- package/dist/assets/index-D1G6i0nS.css +1 -0
- package/dist/assets/index-DpItvKpf.js +419 -0
- package/dist/assets/ui-BvF022GT.js +53 -0
- package/dist/assets/vendor-Dzv9lrRc.js +59 -0
- package/dist/index.html +19 -0
- package/dist/scanner-sweep.png +0 -0
- package/dist/server/server/adapters/index.js +34 -0
- package/dist/server/server/adapters/iterm2-adapter.js +29 -0
- package/dist/server/server/adapters/subprocess-adapter.js +21 -0
- package/dist/server/server/adapters/terminal-adapter.js +1 -0
- package/dist/server/server/config.js +156 -0
- package/dist/server/server/database.js +90 -0
- package/dist/server/server/index.js +372 -0
- package/dist/server/server/init.js +811 -0
- package/dist/server/server/parsers/event-parser.js +64 -0
- package/dist/server/server/parsers/scope-parser.js +188 -0
- package/dist/server/server/routes/config-routes.js +163 -0
- package/dist/server/server/routes/data-routes.js +461 -0
- package/dist/server/server/routes/dispatch-routes.js +215 -0
- package/dist/server/server/routes/git-routes.js +92 -0
- package/dist/server/server/routes/scope-routes.js +215 -0
- package/dist/server/server/routes/sprint-routes.js +116 -0
- package/dist/server/server/routes/version-routes.js +130 -0
- package/dist/server/server/routes/workflow-routes.js +185 -0
- package/dist/server/server/schema.js +90 -0
- package/dist/server/server/services/batch-orchestrator.js +253 -0
- package/dist/server/server/services/claude-session-service.js +352 -0
- package/dist/server/server/services/config-service.js +132 -0
- package/dist/server/server/services/deploy-service.js +51 -0
- package/dist/server/server/services/event-service.js +63 -0
- package/dist/server/server/services/gate-service.js +83 -0
- package/dist/server/server/services/git-service.js +309 -0
- package/dist/server/server/services/github-service.js +145 -0
- package/dist/server/server/services/readiness-service.js +184 -0
- package/dist/server/server/services/scope-cache.js +72 -0
- package/dist/server/server/services/scope-service.js +424 -0
- package/dist/server/server/services/sprint-orchestrator.js +312 -0
- package/dist/server/server/services/sprint-service.js +293 -0
- package/dist/server/server/services/workflow-service.js +397 -0
- package/dist/server/server/utils/cc-hooks-parser.js +49 -0
- package/dist/server/server/utils/dispatch-utils.js +305 -0
- package/dist/server/server/utils/logger.js +86 -0
- package/dist/server/server/utils/terminal-launcher.js +388 -0
- package/dist/server/server/utils/worktree-manager.js +98 -0
- package/dist/server/server/watchers/event-watcher.js +81 -0
- package/dist/server/server/watchers/scope-watcher.js +33 -0
- package/dist/server/shared/api-types.js +5 -0
- package/dist/server/shared/default-workflow.json +616 -0
- package/dist/server/shared/workflow-config.js +44 -0
- package/dist/server/shared/workflow-engine.js +353 -0
- package/index.html +15 -0
- package/package.json +110 -0
- package/postcss.config.js +6 -0
- package/schemas/orbital.config.schema.json +83 -0
- package/scripts/postinstall.js +24 -0
- package/scripts/start.sh +20 -0
- package/server/adapters/index.ts +41 -0
- package/server/adapters/iterm2-adapter.ts +37 -0
- package/server/adapters/subprocess-adapter.ts +25 -0
- package/server/adapters/terminal-adapter.ts +24 -0
- package/server/config.ts +234 -0
- package/server/database.ts +107 -0
- package/server/index.ts +452 -0
- package/server/init.ts +891 -0
- package/server/parsers/event-parser.ts +74 -0
- package/server/parsers/scope-parser.ts +240 -0
- package/server/routes/config-routes.ts +182 -0
- package/server/routes/data-routes.ts +548 -0
- package/server/routes/dispatch-routes.ts +275 -0
- package/server/routes/git-routes.ts +112 -0
- package/server/routes/scope-routes.ts +262 -0
- package/server/routes/sprint-routes.ts +142 -0
- package/server/routes/version-routes.ts +156 -0
- package/server/routes/workflow-routes.ts +198 -0
- package/server/schema.ts +90 -0
- package/server/services/batch-orchestrator.ts +286 -0
- package/server/services/claude-session-service.ts +441 -0
- package/server/services/config-service.ts +151 -0
- package/server/services/deploy-service.ts +98 -0
- package/server/services/event-service.ts +98 -0
- package/server/services/gate-service.ts +126 -0
- package/server/services/git-service.ts +391 -0
- package/server/services/github-service.ts +183 -0
- package/server/services/readiness-service.ts +250 -0
- package/server/services/scope-cache.ts +81 -0
- package/server/services/scope-service.ts +476 -0
- package/server/services/sprint-orchestrator.ts +361 -0
- package/server/services/sprint-service.ts +415 -0
- package/server/services/workflow-service.ts +461 -0
- package/server/utils/cc-hooks-parser.ts +70 -0
- package/server/utils/dispatch-utils.ts +395 -0
- package/server/utils/logger.ts +109 -0
- package/server/utils/terminal-launcher.ts +462 -0
- package/server/utils/worktree-manager.ts +104 -0
- package/server/watchers/event-watcher.ts +100 -0
- package/server/watchers/scope-watcher.ts +38 -0
- package/shared/api-types.ts +20 -0
- package/shared/default-workflow.json +616 -0
- package/shared/workflow-config.ts +170 -0
- package/shared/workflow-engine.ts +427 -0
- package/src/App.tsx +33 -0
- package/src/components/AgentBadge.tsx +40 -0
- package/src/components/BatchPreflightModal.tsx +115 -0
- package/src/components/CardDisplayToggle.tsx +74 -0
- package/src/components/ColumnHeaderActions.tsx +55 -0
- package/src/components/ColumnMenu.tsx +99 -0
- package/src/components/DeployHistory.tsx +141 -0
- package/src/components/DispatchModal.tsx +164 -0
- package/src/components/DispatchPopover.tsx +139 -0
- package/src/components/DragOverlay.tsx +25 -0
- package/src/components/DriftSidebar.tsx +140 -0
- package/src/components/EnvironmentStrip.tsx +88 -0
- package/src/components/ErrorBoundary.tsx +62 -0
- package/src/components/FilterChip.tsx +105 -0
- package/src/components/GateIndicator.tsx +33 -0
- package/src/components/IdeaDetailModal.tsx +190 -0
- package/src/components/IdeaFormDialog.tsx +113 -0
- package/src/components/KanbanColumn.tsx +201 -0
- package/src/components/MarkdownRenderer.tsx +114 -0
- package/src/components/NeonGrid.tsx +128 -0
- package/src/components/PromotionQueue.tsx +89 -0
- package/src/components/ScopeCard.tsx +234 -0
- package/src/components/ScopeDetailModal.tsx +255 -0
- package/src/components/ScopeFilterBar.tsx +152 -0
- package/src/components/SearchInput.tsx +102 -0
- package/src/components/SessionPanel.tsx +335 -0
- package/src/components/SprintContainer.tsx +303 -0
- package/src/components/SprintDependencyDialog.tsx +78 -0
- package/src/components/SprintPreflightModal.tsx +138 -0
- package/src/components/StatusBar.tsx +168 -0
- package/src/components/SwimCell.tsx +67 -0
- package/src/components/SwimLaneRow.tsx +94 -0
- package/src/components/SwimlaneBoardView.tsx +108 -0
- package/src/components/VersionBadge.tsx +139 -0
- package/src/components/ViewModeSelector.tsx +114 -0
- package/src/components/config/AgentChip.tsx +53 -0
- package/src/components/config/AgentCreateDialog.tsx +321 -0
- package/src/components/config/AgentEditor.tsx +175 -0
- package/src/components/config/DirectoryTree.tsx +582 -0
- package/src/components/config/FileEditor.tsx +550 -0
- package/src/components/config/HookChip.tsx +50 -0
- package/src/components/config/StageCard.tsx +198 -0
- package/src/components/config/TransitionZone.tsx +173 -0
- package/src/components/config/UnifiedWorkflowPipeline.tsx +216 -0
- package/src/components/config/WorkflowPipeline.tsx +161 -0
- package/src/components/source-control/BranchList.tsx +93 -0
- package/src/components/source-control/BranchPanel.tsx +105 -0
- package/src/components/source-control/CommitLog.tsx +100 -0
- package/src/components/source-control/CommitRow.tsx +47 -0
- package/src/components/source-control/GitHubPanel.tsx +110 -0
- package/src/components/source-control/GitHubSetupGuide.tsx +52 -0
- package/src/components/source-control/GitOverviewBar.tsx +101 -0
- package/src/components/source-control/PullRequestList.tsx +69 -0
- package/src/components/source-control/WorktreeList.tsx +80 -0
- package/src/components/ui/badge.tsx +41 -0
- package/src/components/ui/button.tsx +55 -0
- package/src/components/ui/card.tsx +78 -0
- package/src/components/ui/dialog.tsx +94 -0
- package/src/components/ui/popover.tsx +33 -0
- package/src/components/ui/scroll-area.tsx +54 -0
- package/src/components/ui/separator.tsx +28 -0
- package/src/components/ui/tabs.tsx +52 -0
- package/src/components/ui/toggle-switch.tsx +35 -0
- package/src/components/ui/tooltip.tsx +27 -0
- package/src/components/workflow/AddEdgeDialog.tsx +217 -0
- package/src/components/workflow/AddListDialog.tsx +201 -0
- package/src/components/workflow/ChecklistEditor.tsx +239 -0
- package/src/components/workflow/CommandPrefixManager.tsx +118 -0
- package/src/components/workflow/ConfigSettingsPanel.tsx +189 -0
- package/src/components/workflow/DirectionSelector.tsx +133 -0
- package/src/components/workflow/DispatchConfigPanel.tsx +180 -0
- package/src/components/workflow/EdgeDetailPanel.tsx +236 -0
- package/src/components/workflow/EdgePropertyEditor.tsx +251 -0
- package/src/components/workflow/EditToolbar.tsx +138 -0
- package/src/components/workflow/HookDetailPanel.tsx +250 -0
- package/src/components/workflow/HookExecutionLog.tsx +24 -0
- package/src/components/workflow/HookSourceModal.tsx +129 -0
- package/src/components/workflow/HooksDashboard.tsx +363 -0
- package/src/components/workflow/ListPropertyEditor.tsx +251 -0
- package/src/components/workflow/MigrationPreviewDialog.tsx +237 -0
- package/src/components/workflow/MovementRulesPanel.tsx +188 -0
- package/src/components/workflow/NodeDetailPanel.tsx +245 -0
- package/src/components/workflow/PresetSelector.tsx +414 -0
- package/src/components/workflow/SkillCommandBuilder.tsx +174 -0
- package/src/components/workflow/WorkflowEdgeComponent.tsx +145 -0
- package/src/components/workflow/WorkflowNode.tsx +147 -0
- package/src/components/workflow/graphLayout.ts +186 -0
- package/src/components/workflow/mergeHooks.ts +85 -0
- package/src/components/workflow/useEditHistory.ts +88 -0
- package/src/components/workflow/useWorkflowEditor.ts +262 -0
- package/src/components/workflow/validateConfig.ts +70 -0
- package/src/hooks/useActiveDispatches.ts +198 -0
- package/src/hooks/useBoardSettings.ts +170 -0
- package/src/hooks/useCardDisplay.ts +57 -0
- package/src/hooks/useCcHooks.ts +24 -0
- package/src/hooks/useConfigTree.ts +51 -0
- package/src/hooks/useEnforcementRules.ts +46 -0
- package/src/hooks/useEvents.ts +59 -0
- package/src/hooks/useFileEditor.ts +165 -0
- package/src/hooks/useGates.ts +57 -0
- package/src/hooks/useIdeaActions.ts +53 -0
- package/src/hooks/useKanbanDnd.ts +410 -0
- package/src/hooks/useOrbitalConfig.ts +54 -0
- package/src/hooks/usePipeline.ts +47 -0
- package/src/hooks/usePipelineData.ts +338 -0
- package/src/hooks/useReconnect.ts +25 -0
- package/src/hooks/useScopeFilters.ts +125 -0
- package/src/hooks/useScopeSessions.ts +44 -0
- package/src/hooks/useScopes.ts +67 -0
- package/src/hooks/useSearch.ts +67 -0
- package/src/hooks/useSettings.tsx +187 -0
- package/src/hooks/useSocket.ts +25 -0
- package/src/hooks/useSourceControl.ts +105 -0
- package/src/hooks/useSprintPreflight.ts +55 -0
- package/src/hooks/useSprints.ts +154 -0
- package/src/hooks/useStatusBarHighlight.ts +18 -0
- package/src/hooks/useSwimlaneBoardSettings.ts +104 -0
- package/src/hooks/useTheme.ts +9 -0
- package/src/hooks/useTransitionReadiness.ts +53 -0
- package/src/hooks/useVersion.ts +155 -0
- package/src/hooks/useViolations.ts +65 -0
- package/src/hooks/useWorkflow.tsx +125 -0
- package/src/hooks/useZoomModifier.ts +19 -0
- package/src/index.css +797 -0
- package/src/layouts/DashboardLayout.tsx +113 -0
- package/src/lib/collisionDetection.ts +20 -0
- package/src/lib/scope-fields.ts +61 -0
- package/src/lib/swimlane.ts +146 -0
- package/src/lib/utils.ts +15 -0
- package/src/main.tsx +19 -0
- package/src/socket.ts +11 -0
- package/src/types/index.ts +497 -0
- package/src/views/AgentFeed.tsx +339 -0
- package/src/views/DeployPipeline.tsx +59 -0
- package/src/views/EnforcementView.tsx +378 -0
- package/src/views/PrimitivesConfig.tsx +500 -0
- package/src/views/QualityGates.tsx +1012 -0
- package/src/views/ScopeBoard.tsx +454 -0
- package/src/views/SessionTimeline.tsx +516 -0
- package/src/views/Settings.tsx +183 -0
- package/src/views/SourceControl.tsx +95 -0
- package/src/views/WorkflowVisualizer.tsx +382 -0
- package/tailwind.config.js +161 -0
- package/templates/agents/AUTO-INVOKE.md +180 -0
- package/templates/agents/CONFLICT-RESOLUTION.md +128 -0
- package/templates/agents/QUICK-REFERENCE.md +122 -0
- package/templates/agents/README.md +188 -0
- package/templates/agents/SKILL-TRIGGERS.md +100 -0
- package/templates/agents/blue-team/frontend-designer.md +424 -0
- package/templates/agents/green-team/architect.md +526 -0
- package/templates/agents/green-team/rules-enforcer.md +131 -0
- package/templates/agents/red-team/attacker-learned.md +24 -0
- package/templates/agents/red-team/attacker.md +486 -0
- package/templates/agents/red-team/chaos.md +548 -0
- package/templates/agents/reference/component-registry.md +82 -0
- package/templates/agents/workflows/full-mode.md +218 -0
- package/templates/agents/workflows/quick-mode.md +118 -0
- package/templates/agents/workflows/security-mode.md +283 -0
- package/templates/anti-patterns/dangerous-shortcuts.md +427 -0
- package/templates/config/agent-triggers.json +92 -0
- package/templates/hooks/agent-team-gate.sh +31 -0
- package/templates/hooks/agent-trigger.sh +97 -0
- package/templates/hooks/block-push.sh +66 -0
- package/templates/hooks/block-workarounds.sh +61 -0
- package/templates/hooks/blocker-check.sh +28 -0
- package/templates/hooks/completion-checklist.sh +28 -0
- package/templates/hooks/decision-capture.sh +15 -0
- package/templates/hooks/dependency-check.sh +27 -0
- package/templates/hooks/end-session.sh +31 -0
- package/templates/hooks/exploration-logger.sh +37 -0
- package/templates/hooks/files-changed-summary.sh +37 -0
- package/templates/hooks/get-session-id.sh +49 -0
- package/templates/hooks/git-commit-guard.sh +34 -0
- package/templates/hooks/init-session.sh +93 -0
- package/templates/hooks/orbital-emit.sh +79 -0
- package/templates/hooks/orbital-report-deploy.sh +78 -0
- package/templates/hooks/orbital-report-gates.sh +40 -0
- package/templates/hooks/orbital-report-violation.sh +36 -0
- package/templates/hooks/orbital-scope-update.sh +53 -0
- package/templates/hooks/phase-verify-reminder.sh +26 -0
- package/templates/hooks/review-gate-check.sh +82 -0
- package/templates/hooks/scope-commit-logger.sh +37 -0
- package/templates/hooks/scope-create-cleanup.sh +36 -0
- package/templates/hooks/scope-create-gate.sh +80 -0
- package/templates/hooks/scope-create-tracker.sh +17 -0
- package/templates/hooks/scope-file-sync.sh +53 -0
- package/templates/hooks/scope-gate.sh +35 -0
- package/templates/hooks/scope-helpers.sh +188 -0
- package/templates/hooks/scope-lifecycle-gate.sh +139 -0
- package/templates/hooks/scope-prepare.sh +244 -0
- package/templates/hooks/scope-transition.sh +172 -0
- package/templates/hooks/session-enforcer.sh +143 -0
- package/templates/hooks/time-tracker.sh +33 -0
- package/templates/lessons-learned.md +15 -0
- package/templates/orbital.config.json +35 -0
- package/templates/presets/development.json +42 -0
- package/templates/presets/gitflow.json +712 -0
- package/templates/presets/minimal.json +23 -0
- package/templates/quick/rules.md +218 -0
- package/templates/scopes/_template.md +255 -0
- package/templates/settings-hooks.json +98 -0
- package/templates/skills/git-commit/SKILL.md +85 -0
- package/templates/skills/git-dev/SKILL.md +99 -0
- package/templates/skills/git-hotfix/SKILL.md +223 -0
- package/templates/skills/git-main/SKILL.md +84 -0
- package/templates/skills/git-production/SKILL.md +165 -0
- package/templates/skills/git-staging/SKILL.md +112 -0
- package/templates/skills/scope-create/SKILL.md +81 -0
- package/templates/skills/scope-fix-review/SKILL.md +168 -0
- package/templates/skills/scope-implement/SKILL.md +110 -0
- package/templates/skills/scope-post-review/SKILL.md +144 -0
- package/templates/skills/scope-pre-review/SKILL.md +211 -0
- package/templates/skills/scope-verify/SKILL.md +201 -0
- package/templates/skills/session-init/SKILL.md +62 -0
- package/templates/skills/session-resume/SKILL.md +201 -0
- package/templates/skills/test-checks/SKILL.md +171 -0
- package/templates/skills/test-code-review/SKILL.md +252 -0
- package/tsconfig.json +25 -0
- package/vite.config.ts +38 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { RefreshCw, Download, Check, AlertCircle, GitBranch, GitCommit, Loader2 } from 'lucide-react';
|
|
2
|
+
import { Badge } from '@/components/ui/badge';
|
|
3
|
+
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
|
|
4
|
+
import { useVersion } from '@/hooks/useVersion';
|
|
5
|
+
import { cn } from '@/lib/utils';
|
|
6
|
+
|
|
7
|
+
export function VersionBadge() {
|
|
8
|
+
const {
|
|
9
|
+
version,
|
|
10
|
+
updateAvailable,
|
|
11
|
+
behindCount,
|
|
12
|
+
updateStage,
|
|
13
|
+
updateError,
|
|
14
|
+
loading,
|
|
15
|
+
checkForUpdate,
|
|
16
|
+
performUpdate,
|
|
17
|
+
} = useVersion();
|
|
18
|
+
|
|
19
|
+
if (loading) return null;
|
|
20
|
+
if (!version) {
|
|
21
|
+
return (
|
|
22
|
+
<button className="version-badge flex items-center gap-1.5 rounded-lg px-2 py-1 text-[10px] font-mono text-muted-foreground/50">
|
|
23
|
+
<span>v?</span>
|
|
24
|
+
</button>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const isWorking = updateStage === 'checking' || updateStage === 'pulling' || updateStage === 'installing';
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<Popover>
|
|
32
|
+
<PopoverTrigger asChild>
|
|
33
|
+
<button className="relative cursor-pointer">
|
|
34
|
+
<Badge
|
|
35
|
+
variant={updateAvailable ? 'warning' : 'success'}
|
|
36
|
+
className="version-badge font-mono text-[10px] transition-colors"
|
|
37
|
+
>
|
|
38
|
+
v{version.version}
|
|
39
|
+
</Badge>
|
|
40
|
+
{updateAvailable && (
|
|
41
|
+
<span className="version-pulse-dot absolute -top-1 -right-1 h-2 w-2 rounded-full bg-emerald-400" />
|
|
42
|
+
)}
|
|
43
|
+
</button>
|
|
44
|
+
</PopoverTrigger>
|
|
45
|
+
|
|
46
|
+
<PopoverContent
|
|
47
|
+
side="top"
|
|
48
|
+
align="end"
|
|
49
|
+
sideOffset={8}
|
|
50
|
+
className="w-64 filter-popover-glass"
|
|
51
|
+
>
|
|
52
|
+
<div className="space-y-3">
|
|
53
|
+
{/* Version header */}
|
|
54
|
+
<div className="flex items-center justify-between">
|
|
55
|
+
<span className="text-xs font-medium text-foreground">Orbital Command</span>
|
|
56
|
+
<Badge variant="outline" className="font-mono text-[10px]">
|
|
57
|
+
v{version.version}
|
|
58
|
+
</Badge>
|
|
59
|
+
</div>
|
|
60
|
+
|
|
61
|
+
{/* Git info */}
|
|
62
|
+
<div className="space-y-1.5 text-[11px] text-muted-foreground">
|
|
63
|
+
<div className="flex items-center gap-1.5">
|
|
64
|
+
<GitCommit className="h-3 w-3" />
|
|
65
|
+
<span className="font-mono">{version.commitSha}</span>
|
|
66
|
+
</div>
|
|
67
|
+
<div className="flex items-center gap-1.5">
|
|
68
|
+
<GitBranch className="h-3 w-3" />
|
|
69
|
+
<span className="font-mono">{version.branch}</span>
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
|
|
73
|
+
{/* Update status */}
|
|
74
|
+
{updateAvailable && updateStage !== 'done' && (
|
|
75
|
+
<div className="rounded-md border border-emerald-500/20 bg-emerald-500/5 px-2 py-1.5 text-[11px] text-emerald-400">
|
|
76
|
+
{behindCount} commit{behindCount !== 1 ? 's' : ''} behind remote
|
|
77
|
+
</div>
|
|
78
|
+
)}
|
|
79
|
+
|
|
80
|
+
{updateStage === 'done' && (
|
|
81
|
+
<div className="flex items-center gap-1.5 rounded-md border border-emerald-500/20 bg-emerald-500/5 px-2 py-1.5 text-[11px] text-emerald-400">
|
|
82
|
+
<Check className="h-3 w-3" />
|
|
83
|
+
Updated. Restart server to apply.
|
|
84
|
+
</div>
|
|
85
|
+
)}
|
|
86
|
+
|
|
87
|
+
{updateStage === 'error' && (
|
|
88
|
+
<div className="flex items-start gap-1.5 rounded-md border border-destructive/20 bg-destructive/5 px-2 py-1.5 text-[11px] text-destructive">
|
|
89
|
+
<AlertCircle className="h-3 w-3 mt-0.5 shrink-0" />
|
|
90
|
+
<span>{updateError ?? 'An unknown error occurred'}</span>
|
|
91
|
+
</div>
|
|
92
|
+
)}
|
|
93
|
+
|
|
94
|
+
{isWorking && (
|
|
95
|
+
<div className="flex items-center gap-1.5 text-[11px] text-muted-foreground">
|
|
96
|
+
<Loader2 className="h-3 w-3 animate-spin" />
|
|
97
|
+
<span>
|
|
98
|
+
{updateStage === 'checking' && 'Checking for updates...'}
|
|
99
|
+
{updateStage === 'pulling' && 'Pulling latest changes...'}
|
|
100
|
+
{updateStage === 'installing' && 'Installing dependencies...'}
|
|
101
|
+
</span>
|
|
102
|
+
</div>
|
|
103
|
+
)}
|
|
104
|
+
|
|
105
|
+
{/* Actions */}
|
|
106
|
+
<div className="flex gap-2 pt-1">
|
|
107
|
+
<button
|
|
108
|
+
onClick={checkForUpdate}
|
|
109
|
+
disabled={isWorking}
|
|
110
|
+
className={cn(
|
|
111
|
+
'flex flex-1 items-center justify-center gap-1.5 rounded-md border border-border px-2 py-1 text-[11px]',
|
|
112
|
+
'text-muted-foreground hover:text-foreground hover:bg-surface-light transition-colors',
|
|
113
|
+
'disabled:opacity-40 disabled:cursor-not-allowed',
|
|
114
|
+
)}
|
|
115
|
+
>
|
|
116
|
+
<RefreshCw className={cn('h-3 w-3', updateStage === 'checking' && 'animate-spin')} />
|
|
117
|
+
Check
|
|
118
|
+
</button>
|
|
119
|
+
{updateAvailable && updateStage !== 'done' && (
|
|
120
|
+
<button
|
|
121
|
+
onClick={performUpdate}
|
|
122
|
+
disabled={isWorking}
|
|
123
|
+
className={cn(
|
|
124
|
+
'flex flex-1 items-center justify-center gap-1.5 rounded-md px-2 py-1 text-[11px]',
|
|
125
|
+
'bg-emerald-500/10 border border-emerald-500/20 text-emerald-400',
|
|
126
|
+
'hover:bg-emerald-500/20 transition-colors',
|
|
127
|
+
'disabled:opacity-40 disabled:cursor-not-allowed',
|
|
128
|
+
)}
|
|
129
|
+
>
|
|
130
|
+
<Download className="h-3 w-3" />
|
|
131
|
+
Update
|
|
132
|
+
</button>
|
|
133
|
+
)}
|
|
134
|
+
</div>
|
|
135
|
+
</div>
|
|
136
|
+
</PopoverContent>
|
|
137
|
+
</Popover>
|
|
138
|
+
);
|
|
139
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { Columns3, Rows3 } from 'lucide-react';
|
|
2
|
+
import { Popover, PopoverTrigger, PopoverContent } from '@/components/ui/popover';
|
|
3
|
+
import { Button } from '@/components/ui/button';
|
|
4
|
+
import { cn } from '@/lib/utils';
|
|
5
|
+
import type { ViewMode, SwimGroupField } from '@/types';
|
|
6
|
+
|
|
7
|
+
interface ViewModeSelectorProps {
|
|
8
|
+
viewMode: ViewMode;
|
|
9
|
+
groupField: SwimGroupField;
|
|
10
|
+
onViewModeChange: (mode: ViewMode) => void;
|
|
11
|
+
onGroupFieldChange: (field: SwimGroupField) => void;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const VIEW_MODES: { value: ViewMode; label: string; Icon: typeof Columns3 }[] = [
|
|
15
|
+
{ value: 'kanban', label: 'Kanban', Icon: Columns3 },
|
|
16
|
+
{ value: 'swimlane', label: 'Swimlane', Icon: Rows3 },
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
const GROUP_FIELDS: { value: SwimGroupField; label: string }[] = [
|
|
20
|
+
{ value: 'priority', label: 'Priority' },
|
|
21
|
+
{ value: 'category', label: 'Category' },
|
|
22
|
+
{ value: 'tags', label: 'Tags' },
|
|
23
|
+
{ value: 'effort', label: 'Effort' },
|
|
24
|
+
{ value: 'dependencies', label: 'Dependencies' },
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
export function ViewModeSelector({
|
|
28
|
+
viewMode,
|
|
29
|
+
groupField,
|
|
30
|
+
onViewModeChange,
|
|
31
|
+
onGroupFieldChange,
|
|
32
|
+
}: ViewModeSelectorProps) {
|
|
33
|
+
const ActiveIcon = viewMode === 'swimlane' ? Rows3 : Columns3;
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<Popover>
|
|
37
|
+
<PopoverTrigger asChild>
|
|
38
|
+
<Button
|
|
39
|
+
variant="outline"
|
|
40
|
+
size="sm"
|
|
41
|
+
className="gap-1.5 backdrop-blur-sm bg-white/[0.03] border-white/10"
|
|
42
|
+
aria-label="Toggle view mode"
|
|
43
|
+
>
|
|
44
|
+
<ActiveIcon className="h-3 w-3" />
|
|
45
|
+
{viewMode === 'swimlane' ? 'Swimlane' : 'Kanban'}
|
|
46
|
+
</Button>
|
|
47
|
+
</PopoverTrigger>
|
|
48
|
+
|
|
49
|
+
<PopoverContent align="end" className="filter-popover-glass !bg-transparent w-44">
|
|
50
|
+
{/* View mode selection */}
|
|
51
|
+
<div className="space-y-0.5">
|
|
52
|
+
<p className="px-2 pb-1 text-[10px] uppercase tracking-wider text-muted-foreground">View</p>
|
|
53
|
+
{VIEW_MODES.map(({ value, label, Icon }) => (
|
|
54
|
+
<button
|
|
55
|
+
key={value}
|
|
56
|
+
onClick={() => onViewModeChange(value)}
|
|
57
|
+
className={cn(
|
|
58
|
+
'flex w-full items-center gap-2 rounded px-2 py-1.5 text-xs transition-colors',
|
|
59
|
+
'hover:bg-white/[0.06]',
|
|
60
|
+
viewMode === value && 'bg-white/[0.06]',
|
|
61
|
+
)}
|
|
62
|
+
>
|
|
63
|
+
<span
|
|
64
|
+
className={cn(
|
|
65
|
+
'flex h-3.5 w-3.5 shrink-0 items-center justify-center rounded-full border',
|
|
66
|
+
viewMode === value ? 'border-primary bg-primary' : 'border-white/15',
|
|
67
|
+
)}
|
|
68
|
+
>
|
|
69
|
+
{viewMode === value && (
|
|
70
|
+
<span className="h-1.5 w-1.5 rounded-full bg-primary-foreground" />
|
|
71
|
+
)}
|
|
72
|
+
</span>
|
|
73
|
+
<Icon className="h-3 w-3 text-muted-foreground" />
|
|
74
|
+
<span className={cn(viewMode === value && 'text-foreground')}>{label}</span>
|
|
75
|
+
</button>
|
|
76
|
+
))}
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
{/* Group-by field — only visible in swimlane mode */}
|
|
80
|
+
{viewMode === 'swimlane' && (
|
|
81
|
+
<>
|
|
82
|
+
<div className="my-2 border-t border-white/[0.06]" />
|
|
83
|
+
<div className="space-y-0.5">
|
|
84
|
+
<p className="px-2 pb-1 text-[10px] uppercase tracking-wider text-muted-foreground">Group by</p>
|
|
85
|
+
{GROUP_FIELDS.map(({ value, label }) => (
|
|
86
|
+
<button
|
|
87
|
+
key={value}
|
|
88
|
+
onClick={() => onGroupFieldChange(value)}
|
|
89
|
+
className={cn(
|
|
90
|
+
'flex w-full items-center gap-2 rounded px-2 py-1.5 text-xs transition-colors',
|
|
91
|
+
'hover:bg-white/[0.06]',
|
|
92
|
+
groupField === value && 'bg-white/[0.06]',
|
|
93
|
+
)}
|
|
94
|
+
>
|
|
95
|
+
<span
|
|
96
|
+
className={cn(
|
|
97
|
+
'flex h-3.5 w-3.5 shrink-0 items-center justify-center rounded-full border',
|
|
98
|
+
groupField === value ? 'border-primary bg-primary' : 'border-white/15',
|
|
99
|
+
)}
|
|
100
|
+
>
|
|
101
|
+
{groupField === value && (
|
|
102
|
+
<span className="h-1.5 w-1.5 rounded-full bg-primary-foreground" />
|
|
103
|
+
)}
|
|
104
|
+
</span>
|
|
105
|
+
<span className={cn(groupField === value && 'text-foreground')}>{label}</span>
|
|
106
|
+
</button>
|
|
107
|
+
))}
|
|
108
|
+
</div>
|
|
109
|
+
</>
|
|
110
|
+
)}
|
|
111
|
+
</PopoverContent>
|
|
112
|
+
</Popover>
|
|
113
|
+
);
|
|
114
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Bot, X } from 'lucide-react';
|
|
2
|
+
import { cn } from '@/lib/utils';
|
|
3
|
+
import type { ResolvedAgent } from '@/types';
|
|
4
|
+
|
|
5
|
+
interface AgentChipProps {
|
|
6
|
+
agent: ResolvedAgent;
|
|
7
|
+
mode?: 'always-on' | 'review';
|
|
8
|
+
selected?: boolean;
|
|
9
|
+
onClick?: () => void;
|
|
10
|
+
onRemove?: () => void;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function AgentChip({ agent, mode, selected, onClick, onRemove }: AgentChipProps) {
|
|
14
|
+
const color = agent.color || '#8B5CF6';
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<button
|
|
18
|
+
type="button"
|
|
19
|
+
onClick={onClick}
|
|
20
|
+
data-pipeline-path={agent.filePath ?? undefined}
|
|
21
|
+
className={cn(
|
|
22
|
+
'inline-flex items-center gap-1.5 rounded-md border px-2 py-0.5 text-[11px] font-medium transition-colors',
|
|
23
|
+
'hover:brightness-125 cursor-pointer',
|
|
24
|
+
selected && 'glow-selected-pulse',
|
|
25
|
+
)}
|
|
26
|
+
style={{
|
|
27
|
+
color,
|
|
28
|
+
borderColor: `${color}4D`,
|
|
29
|
+
backgroundColor: `${color}1A`,
|
|
30
|
+
...(selected ? { '--glow-color': `${color}A0`, '--glow-color-wide': `${color}40` } as React.CSSProperties : {}),
|
|
31
|
+
}}
|
|
32
|
+
>
|
|
33
|
+
{agent.emoji ? (
|
|
34
|
+
<span className="text-xs">{agent.emoji}</span>
|
|
35
|
+
) : (
|
|
36
|
+
<Bot className="h-3 w-3 shrink-0" />
|
|
37
|
+
)}
|
|
38
|
+
<span className="truncate max-w-[100px]">{agent.label}</span>
|
|
39
|
+
{mode === 'always-on' && (
|
|
40
|
+
<span className="ml-0.5 h-1.5 w-1.5 rounded-full bg-green-500 shrink-0" title="Auto-invoke" />
|
|
41
|
+
)}
|
|
42
|
+
{onRemove && (
|
|
43
|
+
<span
|
|
44
|
+
role="button"
|
|
45
|
+
onClick={(e) => { e.stopPropagation(); onRemove(); }}
|
|
46
|
+
className="ml-0.5 rounded-full p-0.5 hover:bg-red-500/20"
|
|
47
|
+
>
|
|
48
|
+
<X className="h-2.5 w-2.5" />
|
|
49
|
+
</span>
|
|
50
|
+
)}
|
|
51
|
+
</button>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import { useState, useCallback } from 'react';
|
|
2
|
+
import { Plus, Bot, Shield, Eye, Wrench, Search, Sparkles } from 'lucide-react';
|
|
3
|
+
import { Button } from '@/components/ui/button';
|
|
4
|
+
import {
|
|
5
|
+
Dialog,
|
|
6
|
+
DialogContent,
|
|
7
|
+
DialogDescription,
|
|
8
|
+
DialogHeader,
|
|
9
|
+
DialogTitle,
|
|
10
|
+
DialogTrigger,
|
|
11
|
+
} from '@/components/ui/dialog';
|
|
12
|
+
import { Badge } from '@/components/ui/badge';
|
|
13
|
+
import { cn } from '@/lib/utils';
|
|
14
|
+
|
|
15
|
+
interface AgentCreateDialogProps {
|
|
16
|
+
onCreated: () => void;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface Template {
|
|
20
|
+
id: string;
|
|
21
|
+
label: string;
|
|
22
|
+
icon: typeof Shield;
|
|
23
|
+
description: string;
|
|
24
|
+
scaffold: string;
|
|
25
|
+
defaultFolder: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const TEMPLATES: Template[] = [
|
|
29
|
+
{
|
|
30
|
+
id: 'security',
|
|
31
|
+
label: 'Security',
|
|
32
|
+
icon: Shield,
|
|
33
|
+
description: 'Adversarial security review agent',
|
|
34
|
+
defaultFolder: 'red-team',
|
|
35
|
+
scaffold: `# {name}
|
|
36
|
+
|
|
37
|
+
{description}
|
|
38
|
+
|
|
39
|
+
## Role
|
|
40
|
+
|
|
41
|
+
You are a security-focused review agent. Your goal is to identify vulnerabilities, insecure patterns, and potential attack vectors in the code under review.
|
|
42
|
+
|
|
43
|
+
## Auto-triggered for:
|
|
44
|
+
- Security-sensitive file changes
|
|
45
|
+
- Authentication/authorization code
|
|
46
|
+
- Input handling and validation
|
|
47
|
+
|
|
48
|
+
## Review Checklist
|
|
49
|
+
- [ ] Input validation and sanitization
|
|
50
|
+
- [ ] Authentication/authorization checks
|
|
51
|
+
- [ ] Secrets and credential handling
|
|
52
|
+
- [ ] SQL/command injection risks
|
|
53
|
+
- [ ] XSS and CSRF protections
|
|
54
|
+
`,
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
id: 'reliability',
|
|
58
|
+
label: 'Reliability',
|
|
59
|
+
icon: Eye,
|
|
60
|
+
description: 'Production reliability review agent',
|
|
61
|
+
defaultFolder: 'blue-team',
|
|
62
|
+
scaffold: `# {name}
|
|
63
|
+
|
|
64
|
+
{description}
|
|
65
|
+
|
|
66
|
+
## Role
|
|
67
|
+
|
|
68
|
+
You are a reliability-focused review agent. Your goal is to ensure code changes are production-safe with proper error handling, observability, and graceful degradation.
|
|
69
|
+
|
|
70
|
+
## Auto-triggered for:
|
|
71
|
+
- Error handling changes
|
|
72
|
+
- Service boundary code
|
|
73
|
+
- Database operations
|
|
74
|
+
|
|
75
|
+
## Review Checklist
|
|
76
|
+
- [ ] Error handling completeness
|
|
77
|
+
- [ ] Timeout and retry logic
|
|
78
|
+
- [ ] Logging and observability
|
|
79
|
+
- [ ] Graceful degradation
|
|
80
|
+
`,
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
id: 'domain-expert',
|
|
84
|
+
label: 'Domain Expert',
|
|
85
|
+
icon: Search,
|
|
86
|
+
description: 'Domain-specific expertise agent',
|
|
87
|
+
defaultFolder: 'green-team',
|
|
88
|
+
scaffold: `# {name}
|
|
89
|
+
|
|
90
|
+
{description}
|
|
91
|
+
|
|
92
|
+
## Role
|
|
93
|
+
|
|
94
|
+
You are a domain expert review agent. Your goal is to ensure code changes correctly implement business logic and domain-specific requirements.
|
|
95
|
+
|
|
96
|
+
## Auto-triggered for:
|
|
97
|
+
- Business logic changes
|
|
98
|
+
- Domain model modifications
|
|
99
|
+
- API contract changes
|
|
100
|
+
|
|
101
|
+
## Review Checklist
|
|
102
|
+
- [ ] Business rule correctness
|
|
103
|
+
- [ ] Domain model integrity
|
|
104
|
+
- [ ] API contract compliance
|
|
105
|
+
`,
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
id: 'guardian',
|
|
109
|
+
label: 'Guardian',
|
|
110
|
+
icon: Wrench,
|
|
111
|
+
description: 'Code quality and standards agent',
|
|
112
|
+
defaultFolder: 'blue-team',
|
|
113
|
+
scaffold: `# {name}
|
|
114
|
+
|
|
115
|
+
{description}
|
|
116
|
+
|
|
117
|
+
## Role
|
|
118
|
+
|
|
119
|
+
You are a code quality guardian agent. Your goal is to ensure code follows project conventions, maintains consistency, and upholds quality standards.
|
|
120
|
+
|
|
121
|
+
## Auto-triggered for:
|
|
122
|
+
- All code changes
|
|
123
|
+
|
|
124
|
+
## Review Checklist
|
|
125
|
+
- [ ] Code style and conventions
|
|
126
|
+
- [ ] Test coverage
|
|
127
|
+
- [ ] Documentation completeness
|
|
128
|
+
- [ ] Performance implications
|
|
129
|
+
`,
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
id: 'custom',
|
|
133
|
+
label: 'Custom',
|
|
134
|
+
icon: Sparkles,
|
|
135
|
+
description: 'Start from a blank template',
|
|
136
|
+
defaultFolder: '',
|
|
137
|
+
scaffold: `# {name}
|
|
138
|
+
|
|
139
|
+
{description}
|
|
140
|
+
|
|
141
|
+
## Role
|
|
142
|
+
|
|
143
|
+
Describe this agent's role and responsibilities.
|
|
144
|
+
|
|
145
|
+
## Review Checklist
|
|
146
|
+
- [ ] Add review criteria here
|
|
147
|
+
`,
|
|
148
|
+
},
|
|
149
|
+
];
|
|
150
|
+
|
|
151
|
+
export function AgentCreateDialog({ onCreated }: AgentCreateDialogProps) {
|
|
152
|
+
const [open, setOpen] = useState(false);
|
|
153
|
+
const [selectedTemplate, setSelectedTemplate] = useState<string>('security');
|
|
154
|
+
const [name, setName] = useState('');
|
|
155
|
+
const [description, setDescription] = useState('');
|
|
156
|
+
const [folder, setFolder] = useState('');
|
|
157
|
+
const [creating, setCreating] = useState(false);
|
|
158
|
+
const [error, setError] = useState<string | null>(null);
|
|
159
|
+
|
|
160
|
+
const template = TEMPLATES.find(t => t.id === selectedTemplate) ?? TEMPLATES[0];
|
|
161
|
+
|
|
162
|
+
const handleCreate = useCallback(async () => {
|
|
163
|
+
if (!name.trim()) {
|
|
164
|
+
setError('Agent name is required');
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const slug = name.trim().toLowerCase().replace(/\s+/g, '-');
|
|
169
|
+
const folderPath = folder.trim() || template.defaultFolder;
|
|
170
|
+
const filePath = folderPath ? `${folderPath}/${slug}.md` : `${slug}.md`;
|
|
171
|
+
|
|
172
|
+
const content = `---\nname: ${name.trim()}\ndescription: ${description.trim() || template.description}\n---\n${template.scaffold
|
|
173
|
+
.replace(/\{name\}/g, name.trim())
|
|
174
|
+
.replace(/\{description\}/g, description.trim() || template.description)}`;
|
|
175
|
+
|
|
176
|
+
setCreating(true);
|
|
177
|
+
setError(null);
|
|
178
|
+
|
|
179
|
+
try {
|
|
180
|
+
const res = await fetch('/api/orbital/config/agents/file', {
|
|
181
|
+
method: 'POST',
|
|
182
|
+
headers: { 'Content-Type': 'application/json' },
|
|
183
|
+
body: JSON.stringify({ path: filePath, content }),
|
|
184
|
+
});
|
|
185
|
+
if (!res.ok) {
|
|
186
|
+
const json = await res.json().catch(() => ({ error: 'Create failed' }));
|
|
187
|
+
throw new Error(json.error ?? `HTTP ${res.status}`);
|
|
188
|
+
}
|
|
189
|
+
setOpen(false);
|
|
190
|
+
setName('');
|
|
191
|
+
setDescription('');
|
|
192
|
+
setFolder('');
|
|
193
|
+
onCreated();
|
|
194
|
+
} catch (err) {
|
|
195
|
+
setError(err instanceof Error ? err.message : 'Create failed');
|
|
196
|
+
} finally {
|
|
197
|
+
setCreating(false);
|
|
198
|
+
}
|
|
199
|
+
}, [name, description, folder, template, onCreated]);
|
|
200
|
+
|
|
201
|
+
return (
|
|
202
|
+
<Dialog open={open} onOpenChange={setOpen}>
|
|
203
|
+
<DialogTrigger asChild>
|
|
204
|
+
<Button variant="outline" size="sm" className="gap-1.5">
|
|
205
|
+
<Plus className="h-3.5 w-3.5" />
|
|
206
|
+
<Bot className="h-3.5 w-3.5" />
|
|
207
|
+
New Agent
|
|
208
|
+
</Button>
|
|
209
|
+
</DialogTrigger>
|
|
210
|
+
<DialogContent className="sm:max-w-[480px]">
|
|
211
|
+
<DialogHeader>
|
|
212
|
+
<DialogTitle className="flex items-center gap-2">
|
|
213
|
+
<Bot className="h-5 w-5" /> Create Agent
|
|
214
|
+
</DialogTitle>
|
|
215
|
+
<DialogDescription>
|
|
216
|
+
Choose a template and configure your new review agent.
|
|
217
|
+
</DialogDescription>
|
|
218
|
+
</DialogHeader>
|
|
219
|
+
|
|
220
|
+
<div className="space-y-4 py-2">
|
|
221
|
+
{/* Template selector */}
|
|
222
|
+
<div className="space-y-2">
|
|
223
|
+
<label className="text-xs font-medium text-muted-foreground">Template</label>
|
|
224
|
+
<div className="grid grid-cols-5 gap-1.5">
|
|
225
|
+
{TEMPLATES.map(t => {
|
|
226
|
+
const Icon = t.icon;
|
|
227
|
+
return (
|
|
228
|
+
<button
|
|
229
|
+
key={t.id}
|
|
230
|
+
type="button"
|
|
231
|
+
onClick={() => {
|
|
232
|
+
setSelectedTemplate(t.id);
|
|
233
|
+
setFolder(t.defaultFolder);
|
|
234
|
+
}}
|
|
235
|
+
className={cn(
|
|
236
|
+
'flex flex-col items-center gap-1 rounded-md border p-2 text-[10px] transition-colors',
|
|
237
|
+
selectedTemplate === t.id
|
|
238
|
+
? 'border-primary bg-primary/10 text-primary'
|
|
239
|
+
: 'border-border text-muted-foreground hover:border-muted-foreground/40',
|
|
240
|
+
)}
|
|
241
|
+
>
|
|
242
|
+
<Icon className="h-4 w-4" />
|
|
243
|
+
{t.label}
|
|
244
|
+
</button>
|
|
245
|
+
);
|
|
246
|
+
})}
|
|
247
|
+
</div>
|
|
248
|
+
</div>
|
|
249
|
+
|
|
250
|
+
{/* Name */}
|
|
251
|
+
<div className="space-y-1">
|
|
252
|
+
<label className="text-xs font-medium text-muted-foreground">Name</label>
|
|
253
|
+
<input
|
|
254
|
+
value={name}
|
|
255
|
+
onChange={(e) => setName(e.target.value)}
|
|
256
|
+
placeholder="e.g., API Security Reviewer"
|
|
257
|
+
className={cn(
|
|
258
|
+
'w-full rounded border border-border bg-surface px-2.5 py-1.5 text-sm text-foreground',
|
|
259
|
+
'outline-none focus:border-accent-blue/50 transition-colors',
|
|
260
|
+
)}
|
|
261
|
+
/>
|
|
262
|
+
</div>
|
|
263
|
+
|
|
264
|
+
{/* Description */}
|
|
265
|
+
<div className="space-y-1">
|
|
266
|
+
<label className="text-xs font-medium text-muted-foreground">Description</label>
|
|
267
|
+
<input
|
|
268
|
+
value={description}
|
|
269
|
+
onChange={(e) => setDescription(e.target.value)}
|
|
270
|
+
placeholder={template.description}
|
|
271
|
+
className={cn(
|
|
272
|
+
'w-full rounded border border-border bg-surface px-2.5 py-1.5 text-sm text-foreground',
|
|
273
|
+
'outline-none focus:border-accent-blue/50 transition-colors',
|
|
274
|
+
)}
|
|
275
|
+
/>
|
|
276
|
+
</div>
|
|
277
|
+
|
|
278
|
+
{/* Folder */}
|
|
279
|
+
<div className="space-y-1">
|
|
280
|
+
<label className="text-xs font-medium text-muted-foreground">
|
|
281
|
+
Team Folder
|
|
282
|
+
<span className="ml-1 text-muted-foreground/50">(optional)</span>
|
|
283
|
+
</label>
|
|
284
|
+
<input
|
|
285
|
+
value={folder}
|
|
286
|
+
onChange={(e) => setFolder(e.target.value)}
|
|
287
|
+
placeholder={template.defaultFolder || 'root'}
|
|
288
|
+
className={cn(
|
|
289
|
+
'w-full rounded border border-border bg-surface px-2.5 py-1.5 text-sm text-foreground font-mono',
|
|
290
|
+
'outline-none focus:border-accent-blue/50 transition-colors',
|
|
291
|
+
)}
|
|
292
|
+
/>
|
|
293
|
+
<div className="flex gap-1.5 mt-1">
|
|
294
|
+
{['red-team', 'blue-team', 'green-team'].map(f => (
|
|
295
|
+
<Badge
|
|
296
|
+
key={f}
|
|
297
|
+
variant={folder === f ? 'default' : 'secondary'}
|
|
298
|
+
className="text-[10px] cursor-pointer"
|
|
299
|
+
onClick={() => setFolder(f)}
|
|
300
|
+
>
|
|
301
|
+
{f}
|
|
302
|
+
</Badge>
|
|
303
|
+
))}
|
|
304
|
+
</div>
|
|
305
|
+
</div>
|
|
306
|
+
|
|
307
|
+
{error && (
|
|
308
|
+
<p className="text-xs text-destructive">{error}</p>
|
|
309
|
+
)}
|
|
310
|
+
</div>
|
|
311
|
+
|
|
312
|
+
<div className="flex justify-end gap-2 pt-2">
|
|
313
|
+
<Button variant="ghost" onClick={() => setOpen(false)}>Cancel</Button>
|
|
314
|
+
<Button onClick={handleCreate} disabled={creating}>
|
|
315
|
+
{creating ? 'Creating...' : 'Create Agent'}
|
|
316
|
+
</Button>
|
|
317
|
+
</div>
|
|
318
|
+
</DialogContent>
|
|
319
|
+
</Dialog>
|
|
320
|
+
);
|
|
321
|
+
}
|