@sylphx/flow 1.7.0 → 1.8.1

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 (131) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/assets/agents/coder.md +72 -119
  3. package/assets/agents/orchestrator.md +26 -90
  4. package/assets/agents/reviewer.md +76 -47
  5. package/assets/agents/writer.md +82 -63
  6. package/assets/output-styles/silent.md +141 -8
  7. package/assets/rules/code-standards.md +9 -33
  8. package/assets/rules/core.md +67 -59
  9. package/package.json +2 -12
  10. package/src/commands/flow/execute.ts +470 -0
  11. package/src/commands/flow/index.ts +11 -0
  12. package/src/commands/flow/prompt.ts +35 -0
  13. package/src/commands/flow/setup.ts +312 -0
  14. package/src/commands/flow/targets.ts +18 -0
  15. package/src/commands/flow/types.ts +47 -0
  16. package/src/commands/flow-command.ts +18 -967
  17. package/src/commands/flow-orchestrator.ts +14 -5
  18. package/src/commands/hook-command.ts +1 -1
  19. package/src/commands/init-core.ts +12 -3
  20. package/src/commands/run-command.ts +1 -1
  21. package/src/config/rules.ts +1 -1
  22. package/src/core/error-handling.ts +1 -1
  23. package/src/core/loop-controller.ts +1 -1
  24. package/src/core/state-detector.ts +1 -1
  25. package/src/core/target-manager.ts +1 -1
  26. package/src/index.ts +1 -1
  27. package/src/shared/files/index.ts +1 -1
  28. package/src/shared/processing/index.ts +1 -1
  29. package/src/targets/claude-code.ts +3 -3
  30. package/src/targets/opencode.ts +3 -3
  31. package/src/utils/agent-enhancer.ts +2 -2
  32. package/src/utils/{mcp-config.ts → config/mcp-config.ts} +4 -4
  33. package/src/utils/{paths.ts → config/paths.ts} +1 -1
  34. package/src/utils/{settings.ts → config/settings.ts} +1 -1
  35. package/src/utils/{target-config.ts → config/target-config.ts} +5 -5
  36. package/src/utils/{target-utils.ts → config/target-utils.ts} +3 -3
  37. package/src/utils/display/banner.ts +25 -0
  38. package/src/utils/display/status.ts +55 -0
  39. package/src/utils/{file-operations.ts → files/file-operations.ts} +2 -2
  40. package/src/utils/files/jsonc.ts +36 -0
  41. package/src/utils/{sync-utils.ts → files/sync-utils.ts} +3 -3
  42. package/src/utils/index.ts +42 -61
  43. package/src/utils/version.ts +47 -0
  44. package/src/components/benchmark-monitor.tsx +0 -331
  45. package/src/components/reindex-progress.tsx +0 -261
  46. package/src/composables/functional/index.ts +0 -14
  47. package/src/composables/functional/useEnvironment.ts +0 -171
  48. package/src/composables/functional/useFileSystem.ts +0 -139
  49. package/src/composables/index.ts +0 -4
  50. package/src/composables/useEnv.ts +0 -13
  51. package/src/composables/useRuntimeConfig.ts +0 -27
  52. package/src/core/ai-sdk.ts +0 -603
  53. package/src/core/app-factory.ts +0 -381
  54. package/src/core/builtin-agents.ts +0 -9
  55. package/src/core/command-system.ts +0 -550
  56. package/src/core/config-system.ts +0 -550
  57. package/src/core/connection-pool.ts +0 -390
  58. package/src/core/di-container.ts +0 -155
  59. package/src/core/headless-display.ts +0 -96
  60. package/src/core/interfaces/index.ts +0 -22
  61. package/src/core/interfaces/repository.interface.ts +0 -91
  62. package/src/core/interfaces/service.interface.ts +0 -133
  63. package/src/core/interfaces.ts +0 -96
  64. package/src/core/result.ts +0 -351
  65. package/src/core/service-config.ts +0 -252
  66. package/src/core/session-service.ts +0 -121
  67. package/src/core/storage-factory.ts +0 -115
  68. package/src/core/stream-handler.ts +0 -288
  69. package/src/core/type-utils.ts +0 -427
  70. package/src/core/unified-storage.ts +0 -456
  71. package/src/core/validation/limit.ts +0 -46
  72. package/src/core/validation/query.ts +0 -20
  73. package/src/db/auto-migrate.ts +0 -322
  74. package/src/db/base-database-client.ts +0 -144
  75. package/src/db/cache-db.ts +0 -218
  76. package/src/db/cache-schema.ts +0 -75
  77. package/src/db/database.ts +0 -70
  78. package/src/db/index.ts +0 -252
  79. package/src/db/memory-db.ts +0 -153
  80. package/src/db/memory-schema.ts +0 -29
  81. package/src/db/schema.ts +0 -289
  82. package/src/db/session-repository.ts +0 -733
  83. package/src/domains/index.ts +0 -6
  84. package/src/domains/utilities/index.ts +0 -6
  85. package/src/domains/utilities/time/index.ts +0 -5
  86. package/src/domains/utilities/time/tools.ts +0 -291
  87. package/src/services/agent-service.ts +0 -273
  88. package/src/services/evaluation-service.ts +0 -271
  89. package/src/services/functional/evaluation-logic.ts +0 -296
  90. package/src/services/functional/file-processor.ts +0 -273
  91. package/src/services/functional/index.ts +0 -12
  92. package/src/services/memory.service.ts +0 -476
  93. package/src/types/api/batch.ts +0 -108
  94. package/src/types/api/errors.ts +0 -118
  95. package/src/types/api/index.ts +0 -55
  96. package/src/types/api/requests.ts +0 -76
  97. package/src/types/api/responses.ts +0 -180
  98. package/src/types/api/websockets.ts +0 -85
  99. package/src/types/benchmark.ts +0 -49
  100. package/src/types/database.types.ts +0 -510
  101. package/src/types/memory-types.ts +0 -63
  102. package/src/utils/advanced-tokenizer.ts +0 -191
  103. package/src/utils/ai-model-fetcher.ts +0 -19
  104. package/src/utils/async-file-operations.ts +0 -516
  105. package/src/utils/audio-player.ts +0 -345
  106. package/src/utils/codebase-helpers.ts +0 -211
  107. package/src/utils/console-ui.ts +0 -79
  108. package/src/utils/database-errors.ts +0 -140
  109. package/src/utils/debug-logger.ts +0 -49
  110. package/src/utils/file-scanner.ts +0 -259
  111. package/src/utils/help.ts +0 -20
  112. package/src/utils/immutable-cache.ts +0 -106
  113. package/src/utils/jsonc.ts +0 -158
  114. package/src/utils/memory-tui.ts +0 -414
  115. package/src/utils/models-dev.ts +0 -91
  116. package/src/utils/parallel-operations.ts +0 -487
  117. package/src/utils/process-manager.ts +0 -155
  118. package/src/utils/prompts.ts +0 -120
  119. package/src/utils/search-tool-builder.ts +0 -214
  120. package/src/utils/session-manager.ts +0 -168
  121. package/src/utils/session-title.ts +0 -87
  122. package/src/utils/simplified-errors.ts +0 -410
  123. package/src/utils/template-engine.ts +0 -94
  124. package/src/utils/test-audio.ts +0 -71
  125. package/src/utils/todo-context.ts +0 -46
  126. package/src/utils/token-counter.ts +0 -288
  127. /package/src/utils/{cli-output.ts → display/cli-output.ts} +0 -0
  128. /package/src/utils/{logger.ts → display/logger.ts} +0 -0
  129. /package/src/utils/{notifications.ts → display/notifications.ts} +0 -0
  130. /package/src/utils/{secret-utils.ts → security/secret-utils.ts} +0 -0
  131. /package/src/utils/{security.ts → security/security.ts} +0 -0
@@ -1,331 +0,0 @@
1
- import path from 'node:path';
2
- import { Box, render, Text, useApp } from 'ink';
3
- import React from 'react';
4
- import type { AgentData, InitialInfo } from '../types/benchmark.js';
5
-
6
- export interface InkMonitorProps {
7
- monitor: InkMonitor;
8
- onComplete: () => void;
9
- }
10
-
11
- export class InkMonitor {
12
- private agents: Map<string, AgentData> = new Map();
13
- private isRunning = false;
14
- private workspaceDirs: string[] = [];
15
- private uiInstance?: any;
16
- private listeners = new Set<() => void>();
17
- private initialInfo: InitialInfo;
18
-
19
- constructor(initialInfo: InitialInfo) {
20
- this.initialInfo = initialInfo;
21
- this.setupSignalHandlers();
22
- }
23
-
24
- // Subscribe to changes - proper React pattern
25
- subscribe(listener: () => void) {
26
- this.listeners.add(listener);
27
- return () => {
28
- this.listeners.delete(listener);
29
- };
30
- }
31
-
32
- private triggerUpdate() {
33
- for (const listener of this.listeners) {
34
- listener();
35
- }
36
- }
37
-
38
- // Getters for React component
39
- getAgents() {
40
- return this.agents;
41
- }
42
-
43
- getWorkspaceDirs() {
44
- return this.workspaceDirs;
45
- }
46
-
47
- getInitialInfo() {
48
- return this.initialInfo;
49
- }
50
-
51
- start() {
52
- this.isRunning = true;
53
-
54
- // Force Ink to work by ensuring proper terminal detection
55
- process.stdout.isTTY = true;
56
- process.stderr.isTTY = true;
57
-
58
- const uiInstance = render(
59
- <BenchmarkMonitor
60
- monitor={this}
61
- onComplete={() => {
62
- this.stop();
63
- }}
64
- />,
65
- {
66
- // Enable Ink's full-screen mode with proper terminal control
67
- debug: false,
68
- patchConsole: true, // Let Ink control console output
69
- exitOnCtrlC: false, // We'll handle CtrlC ourselves
70
- }
71
- );
72
-
73
- this.uiInstance = uiInstance;
74
- }
75
-
76
- setWorkspaceDirs(dirs: string[]) {
77
- this.workspaceDirs = dirs;
78
- }
79
-
80
- addAgent(name: string) {
81
- this.agents.set(name, {
82
- status: 'idle',
83
- output: [],
84
- startTime: undefined,
85
- });
86
- }
87
-
88
- updateAgentStatus(name: string, status: AgentData['status']) {
89
- const agent = this.agents.get(name);
90
- if (agent) {
91
- agent.status = status;
92
- if (status === 'running' && !agent.startTime) {
93
- agent.startTime = Date.now();
94
- } else if (status === 'completed' || status === 'error') {
95
- agent.endTime = Date.now();
96
- }
97
- // Trigger UI update through subscriber pattern
98
- this.triggerUpdate();
99
- }
100
- }
101
-
102
- setAgentPid(name: string, pid: number) {
103
- const agent = this.agents.get(name);
104
- if (agent) {
105
- agent.pid = pid;
106
- this.triggerUpdate();
107
- }
108
- }
109
-
110
- addAgentOutput(name: string, output: string) {
111
- const agent = this.agents.get(name);
112
- if (agent) {
113
- // Remove ANSI escape sequences that interfere with Ink
114
- const cleanedOutput = output.replace(/\x1b\[[0-9;]*[A-Za-z]/g, '');
115
- const lines = cleanedOutput.split('\n').filter((line) => line.trim());
116
- agent.output = [...agent.output.slice(-20), ...lines]; // Keep last 20 lines
117
- // Trigger UI update through subscriber pattern
118
- this.triggerUpdate();
119
- }
120
- }
121
-
122
- stop() {
123
- this.isRunning = false;
124
- if (this.uiInstance) {
125
- this.uiInstance.unmount();
126
- this.uiInstance = undefined;
127
- }
128
- }
129
-
130
- private setupSignalHandlers() {
131
- const shutdown = async (_signal: string) => {
132
- if (!this.isRunning) {
133
- return;
134
- }
135
-
136
- this.stop();
137
- process.exit(0);
138
- };
139
-
140
- process.on('SIGINT', () => shutdown('SIGINT'));
141
- process.on('SIGTERM', () => shutdown('SIGTERM'));
142
- process.on('SIGHUP', () => shutdown('SIGHUP'));
143
- }
144
- }
145
-
146
- // React Ink component for efficient real-time monitoring
147
- const BenchmarkMonitor: React.FC<InkMonitorProps> = ({ monitor, onComplete }) => {
148
- const { exit } = useApp();
149
-
150
- // Subscribe to monitor changes using proper React state
151
- const [_updateTrigger, setUpdateTrigger] = React.useState(0);
152
- const [flashState, setFlashState] = React.useState(true);
153
-
154
- React.useEffect(() => {
155
- // Subscribe to the monitor's change notifications
156
- const unsubscribe = monitor.subscribe(() => {
157
- setUpdateTrigger((prev) => prev + 1);
158
- });
159
-
160
- return unsubscribe;
161
- }, [monitor]);
162
-
163
- // Flashing effect for running status + force frequent updates for real-time output
164
- React.useEffect(() => {
165
- const interval = setInterval(() => {
166
- setFlashState((prev) => !prev);
167
- setUpdateTrigger((prev) => prev + 1); // Force update every 800ms to refresh output display
168
- }, 800); // Flash every 800ms for slow flashing
169
-
170
- return () => clearInterval(interval);
171
- }, []);
172
-
173
- // Auto-exit when all agents complete
174
- React.useEffect(() => {
175
- const agents = monitor.getAgents();
176
- const allCompleted = Array.from(agents.values()).every(
177
- (agent) => agent.status === 'completed' || agent.status === 'error'
178
- );
179
-
180
- if (allCompleted && agents.size > 0) {
181
- onComplete();
182
- exit();
183
- }
184
- }, [monitor, onComplete, exit]);
185
-
186
- const status = React.useMemo(() => {
187
- const agents = monitor.getAgents();
188
- return Array.from(agents.entries()).map(([name, agent]) => {
189
- let runtime = 0;
190
- if (agent.startTime) {
191
- if (agent.endTime) {
192
- runtime = Math.floor((agent.endTime - agent.startTime) / 1000);
193
- } else if (agent.status === 'running') {
194
- // Don't calculate runtime dynamically - store it in the agent data
195
- runtime = agent.startTime ? Math.floor((Date.now() - agent.startTime) / 1000) : 0;
196
- }
197
- }
198
-
199
- // Determine status display with flashing green dot for running
200
- let statusDisplay = '';
201
- let statusColor = '';
202
-
203
- if (agent.status === 'running') {
204
- statusDisplay = flashState ? '●' : ' ';
205
- statusColor = 'green';
206
- } else if (agent.status === 'completed') {
207
- statusDisplay = '✓';
208
- statusColor = 'green';
209
- } else if (agent.status === 'error') {
210
- statusDisplay = '✗';
211
- statusColor = 'red';
212
- } else {
213
- statusDisplay = '◯';
214
- statusColor = 'gray';
215
- }
216
-
217
- // Show actual runtime for agents
218
- let runtimeText = '';
219
- if (agent.startTime && agent.status === 'running') {
220
- runtimeText = `${runtime}s`;
221
- } else if (agent.startTime) {
222
- runtimeText = `${runtime}s`;
223
- }
224
-
225
- // Get last output lines (show up to 5 most recent lines)
226
- let lastOutputLines: string[] = [];
227
- if (agent.output.length > 0) {
228
- // Get the last 5 lines - simpler filtering to ensure real-time output shows
229
- const recentLines = agent.output.slice(-5);
230
- lastOutputLines = recentLines
231
- .filter((line) => line && line.trim().length > 0)
232
- .map((line) => {
233
- const cleanLine = line.trim();
234
- return cleanLine.length > 150 ? `${cleanLine.substring(0, 150)}...` : cleanLine;
235
- });
236
- }
237
-
238
- // Show placeholder text only if no actual output exists
239
- if (lastOutputLines.length === 0) {
240
- if (agent.status === 'running') {
241
- lastOutputLines.push('(working...)');
242
- } else if (agent.status === 'idle') {
243
- lastOutputLines.push('(waiting to start...)');
244
- }
245
- }
246
-
247
- return {
248
- name,
249
- statusDisplay,
250
- statusColor,
251
- status: agent.status.toUpperCase(),
252
- runtime: runtimeText,
253
- lastOutput: lastOutputLines,
254
- pid: agent.pid,
255
- };
256
- });
257
- }, [monitor, flashState]);
258
-
259
- const workspaceDirs = monitor.getWorkspaceDirs();
260
- const initialInfo = monitor.getInitialInfo();
261
-
262
- // Create a mapping from agent name to workspace directory
263
- const agentWorkspaceMap = new Map<string, string>();
264
- for (const dir of workspaceDirs) {
265
- const agentName = path.basename(dir);
266
- agentWorkspaceMap.set(agentName, dir);
267
- }
268
-
269
- return (
270
- <Box flexDirection="column" padding={1}>
271
- {/* Initial Information Section */}
272
- <Box marginBottom={1} flexDirection="column">
273
- <Text bold>Agent Benchmark Monitor</Text>
274
- {initialInfo?.initialInfo && (
275
- <>
276
- <Text color="gray">Output: {initialInfo.initialInfo.outputDir}</Text>
277
- <Text color="gray">
278
- Task:{' '}
279
- {initialInfo.initialInfo.taskFile
280
- ? path.basename(initialInfo.initialInfo.taskFile)
281
- : 'Unknown'}
282
- </Text>
283
- <Text color="gray">Agents: {initialInfo.initialInfo.agentCount}</Text>
284
- <Text color="gray">
285
- Concurrency: {initialInfo.initialInfo.concurrency}, Delay:{' '}
286
- {initialInfo.initialInfo.delay}s
287
- </Text>
288
- </>
289
- )}
290
- {(!initialInfo || !initialInfo.initialInfo) && (
291
- <Text color="gray">Initializing benchmark...</Text>
292
- )}
293
- </Box>
294
-
295
- <Box flexDirection="column">
296
- {status.map((agent) => (
297
- <Box key={agent.name} marginBottom={1} flexDirection="column">
298
- <Box>
299
- <Text bold>
300
- <Text color={agent.statusColor}>{agent.statusDisplay}</Text> {agent.name}
301
- {agent.runtime ? ` ${agent.runtime}` : ''}
302
- {agent.pid ? <Text color="gray"> (pid: {agent.pid})</Text> : ''}
303
- </Text>
304
- </Box>
305
-
306
- {/* Show workspace directory under each agent */}
307
- {agentWorkspaceMap.has(agent.name) && (
308
- <Box paddingLeft={2}>
309
- <Text color="gray">{agentWorkspaceMap.get(agent.name)}</Text>
310
- </Box>
311
- )}
312
-
313
- {agent.lastOutput && agent.lastOutput.length > 0 && (
314
- <Box paddingLeft={4} flexDirection="column" paddingBottom={1} marginTop={1}>
315
- {agent.lastOutput.map((line, index) => (
316
- <Text key={index} color="gray">
317
- {line}
318
- </Text>
319
- ))}
320
- </Box>
321
- )}
322
- </Box>
323
- ))}
324
- </Box>
325
-
326
- <Box marginTop={1}>
327
- <Text color="gray">Press Ctrl+C to exit</Text>
328
- </Box>
329
- </Box>
330
- );
331
- };
@@ -1,261 +0,0 @@
1
- import { Box, render, Text, useApp } from 'ink';
2
- import React from 'react';
3
-
4
- export interface ReindexProgressData {
5
- current: number;
6
- total: number;
7
- fileName: string;
8
- status: 'processing' | 'completed' | 'skipped';
9
- phase: 'tokenizing' | 'calculating' | 'completed';
10
- mode?: 'tfidf-only' | 'semantic';
11
- stats?: {
12
- documentsProcessed: number;
13
- uniqueTerms: number;
14
- };
15
- }
16
-
17
- export class ReindexMonitor {
18
- private progress: ReindexProgressData = {
19
- current: 0,
20
- total: 0,
21
- fileName: '',
22
- status: 'processing',
23
- phase: 'tokenizing',
24
- };
25
- private uiInstance?: any;
26
- private listeners = new Set<() => void>();
27
- private startTime = Date.now();
28
- private lastPercentage = -1; // Track last rendered percentage
29
-
30
- subscribe(listener: () => void) {
31
- this.listeners.add(listener);
32
- return () => {
33
- this.listeners.delete(listener);
34
- };
35
- }
36
-
37
- private triggerUpdate() {
38
- for (const listener of this.listeners) {
39
- listener();
40
- }
41
- }
42
-
43
- getProgress() {
44
- return this.progress;
45
- }
46
-
47
- getElapsedTime() {
48
- return Math.floor((Date.now() - this.startTime) / 1000);
49
- }
50
-
51
- updateProgress(data: Partial<ReindexProgressData>) {
52
- this.progress = { ...this.progress, ...data };
53
-
54
- // Only trigger UI update when percentage changes (to reduce render overhead)
55
- const currentPercentage =
56
- this.progress.total > 0 ? Math.floor((this.progress.current / this.progress.total) * 100) : 0;
57
-
58
- // Always trigger on phase change or when percentage actually changes
59
- if (data.phase || currentPercentage !== this.lastPercentage) {
60
- this.lastPercentage = currentPercentage;
61
- this.triggerUpdate();
62
- }
63
- }
64
-
65
- start(total: number) {
66
- this.progress = {
67
- current: 0,
68
- total,
69
- fileName: '',
70
- status: 'processing',
71
- phase: 'tokenizing',
72
- };
73
- this.startTime = Date.now();
74
-
75
- // Force Ink to work by ensuring proper terminal detection
76
- process.stdout.isTTY = true;
77
- process.stderr.isTTY = true;
78
-
79
- const uiInstance = render(<ReindexProgress monitor={this} />, {
80
- debug: false,
81
- patchConsole: false, // Don't patch console to allow direct stderr output
82
- exitOnCtrlC: false,
83
- });
84
-
85
- this.uiInstance = uiInstance;
86
- }
87
-
88
- stop() {
89
- if (this.uiInstance) {
90
- this.uiInstance.unmount();
91
- this.uiInstance = undefined;
92
- }
93
- }
94
- }
95
-
96
- interface ReindexProgressProps {
97
- monitor: ReindexMonitor;
98
- }
99
-
100
- const ReindexProgress: React.FC<ReindexProgressProps> = ({ monitor }) => {
101
- const { exit } = useApp();
102
- // Use React state instead of reading from monitor directly
103
- const [progress, setProgress] = React.useState<ReindexProgressData>(monitor.getProgress());
104
- const [elapsedTime, setElapsedTime] = React.useState(0);
105
-
106
- // Subscribe to progress updates and update React state
107
- React.useEffect(() => {
108
- const unsubscribe = monitor.subscribe(() => {
109
- const newProgress = monitor.getProgress();
110
- setProgress(newProgress);
111
- setElapsedTime(monitor.getElapsedTime());
112
-
113
- // Show progress updates (Ink UI is too slow to render, so we use console.error for immediate feedback)
114
- if (newProgress.current % 20 === 0) {
115
- const percentage = Math.floor((newProgress.current / newProgress.total) * 100);
116
- console.error(`📦 ${newProgress.current}/${newProgress.total} files (${percentage}%)`);
117
- }
118
- });
119
- return unsubscribe;
120
- }, [monitor]);
121
-
122
- // Update elapsed time every second (not every 100ms)
123
- React.useEffect(() => {
124
- const interval = setInterval(() => {
125
- setElapsedTime(monitor.getElapsedTime());
126
- }, 1000); // Every 1 second instead of 100ms
127
- return () => clearInterval(interval);
128
- }, [monitor]);
129
- const percentage = progress.total > 0 ? Math.floor((progress.current / progress.total) * 100) : 0;
130
-
131
- // Calculate estimated time remaining
132
- const avgTimePerFile = progress.current > 0 ? elapsedTime / progress.current : 0;
133
- const remainingFiles = progress.total - progress.current;
134
- const estimatedRemaining = Math.ceil(avgTimePerFile * remainingFiles);
135
-
136
- // Build progress bar
137
- const barWidth = 40;
138
- const filledWidth = Math.floor((percentage / 100) * barWidth);
139
- const progressBar = '█'.repeat(filledWidth) + '░'.repeat(barWidth - filledWidth);
140
-
141
- // Auto-exit when completed
142
- React.useEffect(() => {
143
- if (progress.phase === 'completed') {
144
- setTimeout(() => {
145
- exit();
146
- }, 1000);
147
- }
148
- }, [progress.phase, exit]);
149
-
150
- return (
151
- <Box flexDirection="column" padding={1}>
152
- {/* Header */}
153
- <Box marginBottom={1}>
154
- <Text bold color="cyan">
155
- 🔤 Reindexing Codebase
156
- </Text>
157
- {progress.mode === 'tfidf-only' && (
158
- <Text color="yellow" dimColor>
159
- {' '}
160
- (TF-IDF mode - no API key)
161
- </Text>
162
- )}
163
- {progress.mode === 'semantic' && (
164
- <Text color="green" dimColor>
165
- {' '}
166
- (Semantic search enabled)
167
- </Text>
168
- )}
169
- </Box>
170
-
171
- {/* API key hint */}
172
- {progress.mode === 'tfidf-only' && progress.phase === 'tokenizing' && (
173
- <Box marginBottom={1}>
174
- <Text color="gray" dimColor>
175
- 💡 Tip: Set OPENAI_API_KEY for semantic search with embeddings
176
- </Text>
177
- </Box>
178
- )}
179
-
180
- {/* Progress bar */}
181
- <Box marginBottom={1}>
182
- <Box width={barWidth + 2} marginRight={2}>
183
- <Text color="blue">{progressBar}</Text>
184
- </Box>
185
- <Text color="cyan" bold>
186
- {percentage}%
187
- </Text>
188
- </Box>
189
-
190
- {/* Current file and stats */}
191
- <Box flexDirection="column" marginBottom={1}>
192
- <Box>
193
- <Text color="gray">Progress: </Text>
194
- <Text color="white">
195
- {progress.current}/{progress.total} files
196
- </Text>
197
- </Box>
198
-
199
- {progress.phase === 'tokenizing' && progress.fileName && (
200
- <Box>
201
- <Text color="gray">Current: </Text>
202
- <Text color="yellow">{progress.fileName}</Text>
203
- </Box>
204
- )}
205
-
206
- {progress.phase === 'calculating' && (
207
- <Box>
208
- <Text color="cyan">⚡ Calculating TF-IDF scores...</Text>
209
- </Box>
210
- )}
211
- </Box>
212
-
213
- {/* Timing info */}
214
- <Box flexDirection="column" marginBottom={1}>
215
- <Box>
216
- <Text color="gray">Elapsed: </Text>
217
- <Text color="white">{formatTime(elapsedTime)}</Text>
218
- </Box>
219
-
220
- {progress.phase === 'tokenizing' && remainingFiles > 0 && (
221
- <Box>
222
- <Text color="gray">Estimated: </Text>
223
- <Text color="white">{formatTime(estimatedRemaining)} remaining</Text>
224
- </Box>
225
- )}
226
- </Box>
227
-
228
- {/* Final stats when completed */}
229
- {progress.phase === 'completed' && progress.stats && (
230
- <Box flexDirection="column" marginTop={1}>
231
- <Text color="green" bold>
232
- ✓ Indexing Complete!
233
- </Text>
234
- <Box marginTop={1}>
235
- <Text color="gray">Documents: </Text>
236
- <Text color="white">{progress.stats.documentsProcessed}</Text>
237
- </Box>
238
- <Box>
239
- <Text color="gray">Unique terms: </Text>
240
- <Text color="white">{progress.stats.uniqueTerms.toLocaleString()}</Text>
241
- </Box>
242
- <Box>
243
- <Text color="gray">Total time: </Text>
244
- <Text color="white">{formatTime(elapsedTime)}</Text>
245
- </Box>
246
- </Box>
247
- )}
248
- </Box>
249
- );
250
- };
251
-
252
- function formatTime(seconds: number): string {
253
- if (seconds < 60) {
254
- return `${seconds}s`;
255
- }
256
- const minutes = Math.floor(seconds / 60);
257
- const secs = seconds % 60;
258
- return `${minutes}m ${secs}s`;
259
- }
260
-
261
- export { ReindexProgress };
@@ -1,14 +0,0 @@
1
- /**
2
- * Functional composables
3
- * Reusable abstractions following functional principles
4
- *
5
- * DESIGN RATIONALE:
6
- * - Pure functions where possible
7
- * - Side effects isolated and explicit
8
- * - Result/Option types for error handling
9
- * - Type-safe operations
10
- * - Composable utilities
11
- */
12
-
13
- export * from './useEnvironment.js';
14
- export * from './useFileSystem.js';