@evolve.labs/devflow 0.8.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.
Files changed (106) hide show
  1. package/.claude/commands/agents/architect.md +1162 -0
  2. package/.claude/commands/agents/architect.meta.yaml +124 -0
  3. package/.claude/commands/agents/builder.md +1432 -0
  4. package/.claude/commands/agents/builder.meta.yaml +117 -0
  5. package/.claude/commands/agents/chronicler.md +633 -0
  6. package/.claude/commands/agents/chronicler.meta.yaml +217 -0
  7. package/.claude/commands/agents/guardian.md +456 -0
  8. package/.claude/commands/agents/guardian.meta.yaml +127 -0
  9. package/.claude/commands/agents/strategist.md +483 -0
  10. package/.claude/commands/agents/strategist.meta.yaml +158 -0
  11. package/.claude/commands/agents/system-designer.md +1137 -0
  12. package/.claude/commands/agents/system-designer.meta.yaml +156 -0
  13. package/.claude/commands/devflow-help.md +93 -0
  14. package/.claude/commands/devflow-status.md +60 -0
  15. package/.claude/commands/quick/create-adr.md +82 -0
  16. package/.claude/commands/quick/new-feature.md +57 -0
  17. package/.claude/commands/quick/security-check.md +54 -0
  18. package/.claude/commands/quick/system-design.md +58 -0
  19. package/.claude_project +52 -0
  20. package/.devflow/agents/architect.meta.yaml +122 -0
  21. package/.devflow/agents/builder.meta.yaml +116 -0
  22. package/.devflow/agents/chronicler.meta.yaml +222 -0
  23. package/.devflow/agents/guardian.meta.yaml +127 -0
  24. package/.devflow/agents/strategist.meta.yaml +158 -0
  25. package/.devflow/agents/system-designer.meta.yaml +265 -0
  26. package/.devflow/project.yaml +242 -0
  27. package/.gitignore-template +84 -0
  28. package/LICENSE +21 -0
  29. package/README.md +249 -0
  30. package/bin/devflow.js +54 -0
  31. package/lib/autopilot.js +235 -0
  32. package/lib/autopilotConstants.js +213 -0
  33. package/lib/constants.js +95 -0
  34. package/lib/init.js +200 -0
  35. package/lib/update.js +181 -0
  36. package/lib/utils.js +157 -0
  37. package/lib/web.js +119 -0
  38. package/package.json +57 -0
  39. package/web/CHANGELOG.md +192 -0
  40. package/web/README.md +156 -0
  41. package/web/app/api/autopilot/execute/route.ts +102 -0
  42. package/web/app/api/autopilot/terminal-execute/route.ts +124 -0
  43. package/web/app/api/files/route.ts +280 -0
  44. package/web/app/api/files/tree/route.ts +160 -0
  45. package/web/app/api/git/route.ts +201 -0
  46. package/web/app/api/health/route.ts +94 -0
  47. package/web/app/api/project/open/route.ts +134 -0
  48. package/web/app/api/search/route.ts +247 -0
  49. package/web/app/api/specs/route.ts +405 -0
  50. package/web/app/api/terminal/route.ts +222 -0
  51. package/web/app/globals.css +160 -0
  52. package/web/app/ide/layout.tsx +43 -0
  53. package/web/app/ide/page.tsx +216 -0
  54. package/web/app/layout.tsx +34 -0
  55. package/web/app/page.tsx +303 -0
  56. package/web/components/agents/AgentIcons.tsx +281 -0
  57. package/web/components/autopilot/AutopilotConfigModal.tsx +245 -0
  58. package/web/components/autopilot/AutopilotPanel.tsx +299 -0
  59. package/web/components/dashboard/DashboardPanel.tsx +393 -0
  60. package/web/components/editor/Breadcrumbs.tsx +134 -0
  61. package/web/components/editor/EditorPanel.tsx +120 -0
  62. package/web/components/editor/EditorTabs.tsx +229 -0
  63. package/web/components/editor/MarkdownPreview.tsx +154 -0
  64. package/web/components/editor/MermaidDiagram.tsx +113 -0
  65. package/web/components/editor/MonacoEditor.tsx +177 -0
  66. package/web/components/editor/TabContextMenu.tsx +207 -0
  67. package/web/components/git/GitPanel.tsx +534 -0
  68. package/web/components/layout/Shell.tsx +15 -0
  69. package/web/components/layout/StatusBar.tsx +100 -0
  70. package/web/components/modals/CommandPalette.tsx +393 -0
  71. package/web/components/modals/GlobalSearch.tsx +348 -0
  72. package/web/components/modals/QuickOpen.tsx +241 -0
  73. package/web/components/modals/RecentFiles.tsx +208 -0
  74. package/web/components/projects/ProjectSelector.tsx +147 -0
  75. package/web/components/settings/SettingItem.tsx +150 -0
  76. package/web/components/settings/SettingsPanel.tsx +323 -0
  77. package/web/components/specs/SpecsPanel.tsx +1091 -0
  78. package/web/components/terminal/TerminalPanel.tsx +683 -0
  79. package/web/components/ui/ContextMenu.tsx +182 -0
  80. package/web/components/ui/LoadingSpinner.tsx +66 -0
  81. package/web/components/ui/ResizeHandle.tsx +110 -0
  82. package/web/components/ui/Skeleton.tsx +108 -0
  83. package/web/components/ui/SkipLinks.tsx +37 -0
  84. package/web/components/ui/Toaster.tsx +57 -0
  85. package/web/hooks/useFocusTrap.ts +141 -0
  86. package/web/hooks/useKeyboardShortcuts.ts +169 -0
  87. package/web/hooks/useListNavigation.ts +237 -0
  88. package/web/lib/autopilotConstants.ts +213 -0
  89. package/web/lib/constants/agents.ts +67 -0
  90. package/web/lib/git.ts +339 -0
  91. package/web/lib/ptyManager.ts +191 -0
  92. package/web/lib/specsParser.ts +299 -0
  93. package/web/lib/stores/autopilotStore.ts +288 -0
  94. package/web/lib/stores/fileStore.ts +550 -0
  95. package/web/lib/stores/gitStore.ts +386 -0
  96. package/web/lib/stores/projectStore.ts +196 -0
  97. package/web/lib/stores/settingsStore.ts +126 -0
  98. package/web/lib/stores/specsStore.ts +297 -0
  99. package/web/lib/stores/uiStore.ts +175 -0
  100. package/web/lib/types/index.ts +177 -0
  101. package/web/lib/utils.ts +98 -0
  102. package/web/next.config.js +50 -0
  103. package/web/package.json +54 -0
  104. package/web/postcss.config.js +6 -0
  105. package/web/tailwind.config.ts +68 -0
  106. package/web/tsconfig.json +41 -0
@@ -0,0 +1,207 @@
1
+ 'use client';
2
+
3
+ import { useEffect, useRef } from 'react';
4
+ import {
5
+ X,
6
+ XCircle,
7
+ Pin,
8
+ PinOff,
9
+ Copy,
10
+ ChevronRight,
11
+ Trash2,
12
+ } from 'lucide-react';
13
+ import { cn } from '@/lib/utils';
14
+ import { useFileStore } from '@/lib/stores/fileStore';
15
+ import { useFocusTrap } from '@/hooks/useFocusTrap';
16
+ import { useListNavigation } from '@/hooks/useListNavigation';
17
+
18
+ interface TabContextMenuProps {
19
+ path: string;
20
+ position: { x: number; y: number };
21
+ onClose: () => void;
22
+ }
23
+
24
+ interface MenuItem {
25
+ id: string;
26
+ label: string;
27
+ icon: React.ComponentType<{ className?: string }>;
28
+ action: () => void;
29
+ disabled?: boolean;
30
+ danger?: boolean;
31
+ divider?: boolean;
32
+ }
33
+
34
+ /**
35
+ * Context menu for editor tabs.
36
+ * Provides actions like close, pin, copy path, etc.
37
+ */
38
+ export function TabContextMenu({ path, position, onClose }: TabContextMenuProps) {
39
+ const menuRef = useRef<HTMLDivElement>(null);
40
+ const {
41
+ closeFile,
42
+ closeOtherTabs,
43
+ closeTabsToRight,
44
+ closeAllTabs,
45
+ togglePinned,
46
+ isPinned,
47
+ copyPath,
48
+ openFiles,
49
+ } = useFileStore();
50
+
51
+ const pinned = isPinned(path);
52
+ const tabIndex = openFiles.findIndex((f) => f.path === path);
53
+ const hasTabsToRight = tabIndex < openFiles.length - 1;
54
+ const hasOtherTabs = openFiles.length > 1;
55
+
56
+ const menuItems: MenuItem[] = [
57
+ {
58
+ id: 'close',
59
+ label: 'Close',
60
+ icon: X,
61
+ action: () => {
62
+ closeFile(path);
63
+ onClose();
64
+ },
65
+ },
66
+ {
67
+ id: 'close-others',
68
+ label: 'Close Others',
69
+ icon: XCircle,
70
+ action: () => {
71
+ closeOtherTabs(path);
72
+ onClose();
73
+ },
74
+ disabled: !hasOtherTabs,
75
+ },
76
+ {
77
+ id: 'close-right',
78
+ label: 'Close to the Right',
79
+ icon: ChevronRight,
80
+ action: () => {
81
+ closeTabsToRight(path);
82
+ onClose();
83
+ },
84
+ disabled: !hasTabsToRight,
85
+ },
86
+ {
87
+ id: 'close-all',
88
+ label: 'Close All',
89
+ icon: Trash2,
90
+ action: () => {
91
+ closeAllTabs();
92
+ onClose();
93
+ },
94
+ danger: true,
95
+ divider: true,
96
+ },
97
+ {
98
+ id: 'pin',
99
+ label: pinned ? 'Unpin Tab' : 'Pin Tab',
100
+ icon: pinned ? PinOff : Pin,
101
+ action: () => {
102
+ togglePinned(path);
103
+ onClose();
104
+ },
105
+ divider: true,
106
+ },
107
+ {
108
+ id: 'copy-path',
109
+ label: 'Copy Path',
110
+ icon: Copy,
111
+ action: () => {
112
+ copyPath(path);
113
+ onClose();
114
+ },
115
+ },
116
+ ];
117
+
118
+ // Focus trap for accessibility
119
+ useFocusTrap(menuRef, true, {
120
+ onEscape: onClose,
121
+ });
122
+
123
+ // Keyboard navigation
124
+ const { selectedIndex, handleKeyDown, isSelected } = useListNavigation({
125
+ items: menuItems.filter((item) => !item.disabled),
126
+ onSelect: (item) => item.action(),
127
+ onEscape: onClose,
128
+ });
129
+
130
+ // Close on outside click
131
+ useEffect(() => {
132
+ const handleClickOutside = (event: MouseEvent) => {
133
+ if (menuRef.current && !menuRef.current.contains(event.target as Node)) {
134
+ onClose();
135
+ }
136
+ };
137
+
138
+ // Use capture to get the event before other handlers
139
+ document.addEventListener('mousedown', handleClickOutside, true);
140
+ return () => document.removeEventListener('mousedown', handleClickOutside, true);
141
+ }, [onClose]);
142
+
143
+ // Adjust position to stay within viewport
144
+ const adjustedPosition = {
145
+ x: Math.min(position.x, window.innerWidth - 200),
146
+ y: Math.min(position.y, window.innerHeight - 300),
147
+ };
148
+
149
+ return (
150
+ <div
151
+ ref={menuRef}
152
+ className={cn(
153
+ 'fixed z-50 min-w-[180px] py-1',
154
+ 'bg-[#1a1a24] border border-white/10 rounded-lg shadow-xl',
155
+ 'animate-in fade-in-0 zoom-in-95 duration-100'
156
+ )}
157
+ style={{
158
+ left: adjustedPosition.x,
159
+ top: adjustedPosition.y,
160
+ }}
161
+ role="menu"
162
+ aria-label="Tab actions"
163
+ onKeyDown={handleKeyDown}
164
+ >
165
+ {menuItems.map((item, index) => {
166
+ const Icon = item.icon;
167
+ const enabledIndex = menuItems
168
+ .filter((i) => !i.disabled)
169
+ .findIndex((i) => i.id === item.id);
170
+
171
+ return (
172
+ <div key={item.id}>
173
+ {item.divider && index > 0 && (
174
+ <div className="my-1 border-t border-white/10" role="separator" />
175
+ )}
176
+ <button
177
+ className={cn(
178
+ 'w-full flex items-center gap-3 px-3 py-2 text-sm text-left',
179
+ 'transition-colors',
180
+ item.disabled
181
+ ? 'text-gray-600 cursor-not-allowed'
182
+ : item.danger
183
+ ? 'text-red-400 hover:bg-red-500/10'
184
+ : 'text-gray-300 hover:bg-white/5 hover:text-white',
185
+ isSelected(enabledIndex) && !item.disabled && 'bg-white/5 text-white'
186
+ )}
187
+ onClick={item.action}
188
+ disabled={item.disabled}
189
+ role="menuitem"
190
+ tabIndex={item.disabled ? -1 : 0}
191
+ aria-disabled={item.disabled}
192
+ >
193
+ <Icon
194
+ className={cn(
195
+ 'w-4 h-4 flex-shrink-0',
196
+ item.disabled ? 'text-gray-600' : item.danger ? 'text-red-400' : 'text-gray-500'
197
+ )}
198
+ aria-hidden="true"
199
+ />
200
+ <span>{item.label}</span>
201
+ </button>
202
+ </div>
203
+ );
204
+ })}
205
+ </div>
206
+ );
207
+ }