@sylphx/flow 1.0.1 → 1.0.3
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/CHANGELOG.md +12 -0
- package/package.json +10 -9
- package/src/commands/codebase-command.ts +168 -0
- package/src/commands/flow-command.ts +1137 -0
- package/src/commands/flow-orchestrator.ts +296 -0
- package/src/commands/hook-command.ts +444 -0
- package/src/commands/init-command.ts +92 -0
- package/src/commands/init-core.ts +322 -0
- package/src/commands/knowledge-command.ts +161 -0
- package/src/commands/run-command.ts +120 -0
- package/src/components/benchmark-monitor.tsx +331 -0
- package/src/components/reindex-progress.tsx +261 -0
- package/src/composables/functional/index.ts +14 -0
- package/src/composables/functional/useEnvironment.ts +171 -0
- package/src/composables/functional/useFileSystem.ts +139 -0
- package/src/composables/index.ts +5 -0
- package/src/composables/useEnv.ts +13 -0
- package/src/composables/useRuntimeConfig.ts +27 -0
- package/src/composables/useTargetConfig.ts +45 -0
- package/src/config/ai-config.ts +376 -0
- package/src/config/constants.ts +35 -0
- package/src/config/index.ts +27 -0
- package/src/config/rules.ts +43 -0
- package/src/config/servers.ts +371 -0
- package/src/config/targets.ts +126 -0
- package/src/core/agent-loader.ts +141 -0
- package/src/core/agent-manager.ts +174 -0
- package/src/core/ai-sdk.ts +603 -0
- package/src/core/app-factory.ts +381 -0
- package/src/core/builtin-agents.ts +9 -0
- package/src/core/command-system.ts +550 -0
- package/src/core/config-system.ts +550 -0
- package/src/core/connection-pool.ts +390 -0
- package/src/core/di-container.ts +155 -0
- package/src/core/error-handling.ts +519 -0
- package/src/core/formatting/bytes.test.ts +115 -0
- package/src/core/formatting/bytes.ts +64 -0
- package/src/core/functional/async.ts +313 -0
- package/src/core/functional/either.ts +109 -0
- package/src/core/functional/error-handler.ts +135 -0
- package/src/core/functional/error-types.ts +311 -0
- package/src/core/functional/index.ts +19 -0
- package/src/core/functional/option.ts +142 -0
- package/src/core/functional/pipe.ts +189 -0
- package/src/core/functional/result.ts +204 -0
- package/src/core/functional/validation.ts +138 -0
- package/src/core/headless-display.ts +96 -0
- package/src/core/index.ts +6 -0
- package/src/core/installers/file-installer.ts +303 -0
- package/src/core/installers/mcp-installer.ts +213 -0
- package/src/core/interfaces/index.ts +22 -0
- package/src/core/interfaces/repository.interface.ts +91 -0
- package/src/core/interfaces/service.interface.ts +133 -0
- package/src/core/interfaces.ts +129 -0
- package/src/core/loop-controller.ts +200 -0
- package/src/core/result.ts +351 -0
- package/src/core/rule-loader.ts +147 -0
- package/src/core/rule-manager.ts +240 -0
- package/src/core/service-config.ts +252 -0
- package/src/core/session-service.ts +121 -0
- package/src/core/state-detector.ts +389 -0
- package/src/core/storage-factory.ts +115 -0
- package/src/core/stream-handler.ts +288 -0
- package/src/core/target-manager.ts +161 -0
- package/src/core/type-utils.ts +427 -0
- package/src/core/unified-storage.ts +456 -0
- package/src/core/upgrade-manager.ts +300 -0
- package/src/core/validation/limit.test.ts +155 -0
- package/src/core/validation/limit.ts +46 -0
- package/src/core/validation/query.test.ts +44 -0
- package/src/core/validation/query.ts +20 -0
- package/src/db/auto-migrate.ts +322 -0
- package/src/db/base-database-client.ts +144 -0
- package/src/db/cache-db.ts +218 -0
- package/src/db/cache-schema.ts +75 -0
- package/src/db/database.ts +70 -0
- package/src/db/index.ts +252 -0
- package/src/db/memory-db.ts +153 -0
- package/src/db/memory-schema.ts +29 -0
- package/src/db/schema.ts +289 -0
- package/src/db/session-repository.ts +733 -0
- package/src/domains/codebase/index.ts +5 -0
- package/src/domains/codebase/tools.ts +139 -0
- package/src/domains/index.ts +8 -0
- package/src/domains/knowledge/index.ts +10 -0
- package/src/domains/knowledge/resources.ts +537 -0
- package/src/domains/knowledge/tools.ts +174 -0
- package/src/domains/utilities/index.ts +6 -0
- package/src/domains/utilities/time/index.ts +5 -0
- package/src/domains/utilities/time/tools.ts +291 -0
- package/src/index.ts +211 -0
- package/src/services/agent-service.ts +273 -0
- package/src/services/claude-config-service.ts +252 -0
- package/src/services/config-service.ts +258 -0
- package/src/services/evaluation-service.ts +271 -0
- package/src/services/functional/evaluation-logic.ts +296 -0
- package/src/services/functional/file-processor.ts +273 -0
- package/src/services/functional/index.ts +12 -0
- package/src/services/index.ts +13 -0
- package/src/services/mcp-service.ts +432 -0
- package/src/services/memory.service.ts +476 -0
- package/src/services/search/base-indexer.ts +156 -0
- package/src/services/search/codebase-indexer-types.ts +38 -0
- package/src/services/search/codebase-indexer.ts +647 -0
- package/src/services/search/embeddings-provider.ts +455 -0
- package/src/services/search/embeddings.ts +316 -0
- package/src/services/search/functional-indexer.ts +323 -0
- package/src/services/search/index.ts +27 -0
- package/src/services/search/indexer.ts +380 -0
- package/src/services/search/knowledge-indexer.ts +422 -0
- package/src/services/search/semantic-search.ts +244 -0
- package/src/services/search/tfidf.ts +559 -0
- package/src/services/search/unified-search-service.ts +888 -0
- package/src/services/smart-config-service.ts +385 -0
- package/src/services/storage/cache-storage.ts +487 -0
- package/src/services/storage/drizzle-storage.ts +581 -0
- package/src/services/storage/index.ts +15 -0
- package/src/services/storage/lancedb-vector-storage.ts +494 -0
- package/src/services/storage/memory-storage.ts +268 -0
- package/src/services/storage/separated-storage.ts +467 -0
- package/src/services/storage/vector-storage.ts +13 -0
- package/src/shared/agents/index.ts +63 -0
- package/src/shared/files/index.ts +99 -0
- package/src/shared/index.ts +32 -0
- package/src/shared/logging/index.ts +24 -0
- package/src/shared/processing/index.ts +153 -0
- package/src/shared/types/index.ts +25 -0
- package/src/targets/claude-code.ts +574 -0
- package/src/targets/functional/claude-code-logic.ts +185 -0
- package/src/targets/functional/index.ts +6 -0
- package/src/targets/opencode.ts +529 -0
- package/src/types/agent.types.ts +32 -0
- package/src/types/api/batch.ts +108 -0
- package/src/types/api/errors.ts +118 -0
- package/src/types/api/index.ts +55 -0
- package/src/types/api/requests.ts +76 -0
- package/src/types/api/responses.ts +180 -0
- package/src/types/api/websockets.ts +85 -0
- package/src/types/api.types.ts +9 -0
- package/src/types/benchmark.ts +49 -0
- package/src/types/cli.types.ts +87 -0
- package/src/types/common.types.ts +35 -0
- package/src/types/database.types.ts +510 -0
- package/src/types/mcp-config.types.ts +448 -0
- package/src/types/mcp.types.ts +69 -0
- package/src/types/memory-types.ts +63 -0
- package/src/types/provider.types.ts +28 -0
- package/src/types/rule.types.ts +24 -0
- package/src/types/session.types.ts +214 -0
- package/src/types/target-config.types.ts +295 -0
- package/src/types/target.types.ts +140 -0
- package/src/types/todo.types.ts +25 -0
- package/src/types.ts +40 -0
- package/src/utils/advanced-tokenizer.ts +191 -0
- package/src/utils/agent-enhancer.ts +114 -0
- package/src/utils/ai-model-fetcher.ts +19 -0
- package/src/utils/async-file-operations.ts +516 -0
- package/src/utils/audio-player.ts +345 -0
- package/src/utils/cli-output.ts +266 -0
- package/src/utils/codebase-helpers.ts +211 -0
- package/src/utils/console-ui.ts +79 -0
- package/src/utils/database-errors.ts +140 -0
- package/src/utils/debug-logger.ts +49 -0
- package/src/utils/error-handler.ts +53 -0
- package/src/utils/file-operations.ts +310 -0
- package/src/utils/file-scanner.ts +259 -0
- package/src/utils/functional/array.ts +355 -0
- package/src/utils/functional/index.ts +15 -0
- package/src/utils/functional/object.ts +279 -0
- package/src/utils/functional/string.ts +281 -0
- package/src/utils/functional.ts +543 -0
- package/src/utils/help.ts +20 -0
- package/src/utils/immutable-cache.ts +106 -0
- package/src/utils/index.ts +78 -0
- package/src/utils/jsonc.ts +158 -0
- package/src/utils/logger.ts +396 -0
- package/src/utils/mcp-config.ts +249 -0
- package/src/utils/memory-tui.ts +414 -0
- package/src/utils/models-dev.ts +91 -0
- package/src/utils/notifications.ts +169 -0
- package/src/utils/object-utils.ts +51 -0
- package/src/utils/parallel-operations.ts +487 -0
- package/src/utils/paths.ts +143 -0
- package/src/utils/process-manager.ts +155 -0
- package/src/utils/prompts.ts +120 -0
- package/src/utils/search-tool-builder.ts +214 -0
- package/src/utils/secret-utils.ts +179 -0
- package/src/utils/security.ts +537 -0
- package/src/utils/session-manager.ts +168 -0
- package/src/utils/session-title.ts +87 -0
- package/src/utils/settings.ts +182 -0
- package/src/utils/simplified-errors.ts +410 -0
- package/src/utils/sync-utils.ts +159 -0
- package/src/utils/target-config.ts +570 -0
- package/src/utils/target-utils.ts +394 -0
- package/src/utils/template-engine.ts +94 -0
- package/src/utils/test-audio.ts +71 -0
- package/src/utils/todo-context.ts +46 -0
- package/src/utils/token-counter.ts +288 -0
- package/dist/index.d.ts +0 -10
- package/dist/index.js +0 -59554
- package/dist/lancedb.linux-x64-gnu-b7f0jgsz.node +0 -0
- package/dist/lancedb.linux-x64-musl-tgcv22rx.node +0 -0
- package/dist/shared/chunk-25dwp0dp.js +0 -89
- package/dist/shared/chunk-3pjb6063.js +0 -208
- package/dist/shared/chunk-4d6ydpw7.js +0 -2854
- package/dist/shared/chunk-4wjcadjk.js +0 -225
- package/dist/shared/chunk-5j4w74t6.js +0 -30
- package/dist/shared/chunk-5j8m3dh3.js +0 -58
- package/dist/shared/chunk-5thh3qem.js +0 -91
- package/dist/shared/chunk-6g9xy73m.js +0 -252
- package/dist/shared/chunk-7eq34c42.js +0 -23
- package/dist/shared/chunk-c2gwgx3r.js +0 -115
- package/dist/shared/chunk-cjd3mk4c.js +0 -1320
- package/dist/shared/chunk-g5cv6703.js +0 -368
- package/dist/shared/chunk-hpkhykhq.js +0 -574
- package/dist/shared/chunk-m2322pdk.js +0 -122
- package/dist/shared/chunk-nd5fdvaq.js +0 -26
- package/dist/shared/chunk-pgd3m6zf.js +0 -108
- package/dist/shared/chunk-qk8n91hw.js +0 -494
- package/dist/shared/chunk-rkkn8szp.js +0 -16855
- package/dist/shared/chunk-t16rfxh0.js +0 -61
- package/dist/shared/chunk-t4fbfa5v.js +0 -19
- package/dist/shared/chunk-t77h86w6.js +0 -276
- package/dist/shared/chunk-v0ez4aef.js +0 -71
- package/dist/shared/chunk-v29j2r3s.js +0 -32051
- package/dist/shared/chunk-vfbc6ew5.js +0 -765
- package/dist/shared/chunk-vmeqwm1c.js +0 -204
- package/dist/shared/chunk-x66eh37x.js +0 -137
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stream Handler
|
|
3
|
+
* Unified stream processing for both headless and TUI modes
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { StreamChunk } from './ai-sdk.js';
|
|
7
|
+
import type { MessagePart, TokenUsage } from '../types/session.types.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Callbacks for stream events
|
|
11
|
+
*/
|
|
12
|
+
export interface StreamCallbacks {
|
|
13
|
+
onTextStart?: () => void;
|
|
14
|
+
onTextDelta?: (text: string) => void;
|
|
15
|
+
onTextEnd?: () => void;
|
|
16
|
+
onReasoningStart?: () => void;
|
|
17
|
+
onReasoningDelta?: (text: string) => void;
|
|
18
|
+
onReasoningEnd?: (duration: number) => void;
|
|
19
|
+
onToolCall?: (toolCallId: string, toolName: string, args: unknown) => void;
|
|
20
|
+
onToolInputStart?: (toolCallId: string, toolName: string) => void;
|
|
21
|
+
onToolInputDelta?: (toolCallId: string, toolName: string, argsTextDelta: string) => void;
|
|
22
|
+
onToolInputEnd?: (toolCallId: string, toolName: string, args: unknown) => void;
|
|
23
|
+
onToolResult?: (toolCallId: string, toolName: string, result: unknown, duration: number) => void;
|
|
24
|
+
onToolError?: (toolCallId: string, toolName: string, error: string, duration: number) => void;
|
|
25
|
+
onAbort?: () => void;
|
|
26
|
+
onError?: (error: string) => void;
|
|
27
|
+
onFinish?: (usage: TokenUsage, finishReason: string) => void;
|
|
28
|
+
onComplete?: () => void;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Stream processing result
|
|
33
|
+
*/
|
|
34
|
+
export interface StreamResult {
|
|
35
|
+
fullResponse: string;
|
|
36
|
+
messageParts: MessagePart[];
|
|
37
|
+
usage?: TokenUsage;
|
|
38
|
+
finishReason?: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Process AI stream and collect response with parts
|
|
43
|
+
*/
|
|
44
|
+
export async function processStream(
|
|
45
|
+
stream: AsyncIterable<StreamChunk>,
|
|
46
|
+
callbacks: StreamCallbacks = {}
|
|
47
|
+
): Promise<StreamResult> {
|
|
48
|
+
const { onTextStart, onTextDelta, onTextEnd, onReasoningStart, onReasoningDelta, onReasoningEnd, onToolCall, onToolInputStart, onToolInputDelta, onToolInputEnd, onToolResult, onToolError, onAbort, onError, onFinish, onComplete } = callbacks;
|
|
49
|
+
|
|
50
|
+
let fullResponse = '';
|
|
51
|
+
const messageParts: MessagePart[] = [];
|
|
52
|
+
const activeTools = new Map<string, { name: string; startTime: number; args: unknown }>();
|
|
53
|
+
let currentTextContent = '';
|
|
54
|
+
let currentReasoningContent = '';
|
|
55
|
+
let reasoningStartTime: number | null = null;
|
|
56
|
+
let usage: TokenUsage | undefined;
|
|
57
|
+
let finishReason: string | undefined;
|
|
58
|
+
|
|
59
|
+
for await (const chunk of stream) {
|
|
60
|
+
switch (chunk.type) {
|
|
61
|
+
case 'text-start': {
|
|
62
|
+
// Text generation started - notify immediately
|
|
63
|
+
onTextStart?.();
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
case 'text-delta': {
|
|
68
|
+
fullResponse += chunk.textDelta;
|
|
69
|
+
currentTextContent += chunk.textDelta;
|
|
70
|
+
onTextDelta?.(chunk.textDelta);
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
case 'text-end': {
|
|
75
|
+
// Text generation finished - save text part if any
|
|
76
|
+
if (currentTextContent) {
|
|
77
|
+
messageParts.push({ type: 'text', content: currentTextContent, status: 'completed' });
|
|
78
|
+
currentTextContent = '';
|
|
79
|
+
}
|
|
80
|
+
onTextEnd?.();
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
case 'reasoning-start': {
|
|
85
|
+
// Save current text part if any
|
|
86
|
+
if (currentTextContent) {
|
|
87
|
+
messageParts.push({ type: 'text', content: currentTextContent, status: 'completed' });
|
|
88
|
+
currentTextContent = '';
|
|
89
|
+
}
|
|
90
|
+
reasoningStartTime = Date.now();
|
|
91
|
+
onReasoningStart?.();
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
case 'reasoning-delta': {
|
|
96
|
+
currentReasoningContent += chunk.textDelta;
|
|
97
|
+
onReasoningDelta?.(chunk.textDelta);
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
case 'reasoning-end': {
|
|
102
|
+
// Save reasoning part with duration
|
|
103
|
+
const duration = reasoningStartTime ? Date.now() - reasoningStartTime : 0;
|
|
104
|
+
if (currentReasoningContent || reasoningStartTime) {
|
|
105
|
+
messageParts.push({
|
|
106
|
+
type: 'reasoning',
|
|
107
|
+
content: currentReasoningContent,
|
|
108
|
+
status: 'completed', // All saved parts are completed
|
|
109
|
+
duration
|
|
110
|
+
});
|
|
111
|
+
currentReasoningContent = '';
|
|
112
|
+
reasoningStartTime = null;
|
|
113
|
+
}
|
|
114
|
+
// Pass duration to callback so UI can display it
|
|
115
|
+
onReasoningEnd?.(duration);
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
case 'tool-call': {
|
|
120
|
+
// Save current text part if any
|
|
121
|
+
if (currentTextContent) {
|
|
122
|
+
messageParts.push({ type: 'text', content: currentTextContent, status: 'completed' });
|
|
123
|
+
currentTextContent = '';
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Add tool part (may not have complete args yet if streaming)
|
|
127
|
+
messageParts.push({
|
|
128
|
+
type: 'tool',
|
|
129
|
+
toolId: chunk.toolCallId,
|
|
130
|
+
name: chunk.toolName,
|
|
131
|
+
status: 'active', // Match MessagePart type
|
|
132
|
+
args: chunk.args,
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// Track tool start time
|
|
136
|
+
activeTools.set(chunk.toolCallId, {
|
|
137
|
+
name: chunk.toolName,
|
|
138
|
+
startTime: Date.now(),
|
|
139
|
+
args: chunk.args,
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
onToolCall?.(chunk.toolCallId, chunk.toolName, chunk.args);
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
case 'tool-input-start': {
|
|
147
|
+
// Tool input streaming started - notify callback
|
|
148
|
+
onToolInputStart?.(chunk.toolCallId, chunk.toolName);
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
case 'tool-input-delta': {
|
|
153
|
+
// Update tool args as they stream in
|
|
154
|
+
// Find the active tool part and update its args
|
|
155
|
+
const toolPart = messageParts.find(
|
|
156
|
+
(p) => p.type === 'tool' && p.name === chunk.toolName && p.status === 'active'
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
if (toolPart && toolPart.type === 'tool') {
|
|
160
|
+
// Append args delta (args are streaming as JSON text)
|
|
161
|
+
const currentArgsText = typeof toolPart.args === 'string' ? toolPart.args : '';
|
|
162
|
+
toolPart.args = currentArgsText + chunk.argsTextDelta;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Notify callback for real-time UI update
|
|
166
|
+
onToolInputDelta?.(chunk.toolCallId, chunk.toolName, chunk.argsTextDelta);
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
case 'tool-input-end': {
|
|
171
|
+
// Tool input streaming complete - args are ready
|
|
172
|
+
// Find tool part to get final args
|
|
173
|
+
const toolPart = messageParts.find(
|
|
174
|
+
(p) => p.type === 'tool' && p.name === chunk.toolName && p.status === 'active'
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
if (toolPart && toolPart.type === 'tool') {
|
|
178
|
+
onToolInputEnd?.(chunk.toolCallId, chunk.toolName, toolPart.args);
|
|
179
|
+
}
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
case 'tool-result': {
|
|
184
|
+
const tool = activeTools.get(chunk.toolCallId);
|
|
185
|
+
if (tool) {
|
|
186
|
+
const duration = Date.now() - tool.startTime;
|
|
187
|
+
activeTools.delete(chunk.toolCallId);
|
|
188
|
+
|
|
189
|
+
// Update tool part status and result
|
|
190
|
+
const toolPart = messageParts.find(
|
|
191
|
+
(p) => p.type === 'tool' && p.name === chunk.toolName && p.status === 'active'
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
if (toolPart && toolPart.type === 'tool') {
|
|
195
|
+
toolPart.status = 'completed';
|
|
196
|
+
toolPart.duration = duration;
|
|
197
|
+
toolPart.result = chunk.result;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
onToolResult?.(chunk.toolCallId, chunk.toolName, chunk.result, duration);
|
|
201
|
+
}
|
|
202
|
+
break;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
case 'tool-error': {
|
|
206
|
+
// Save current text part if any
|
|
207
|
+
if (currentTextContent) {
|
|
208
|
+
messageParts.push({ type: 'text', content: currentTextContent, status: 'completed' });
|
|
209
|
+
currentTextContent = '';
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const tool = activeTools.get(chunk.toolCallId);
|
|
213
|
+
if (tool) {
|
|
214
|
+
const duration = Date.now() - tool.startTime;
|
|
215
|
+
activeTools.delete(chunk.toolCallId);
|
|
216
|
+
|
|
217
|
+
// Update tool part status and error
|
|
218
|
+
const toolPart = messageParts.find(
|
|
219
|
+
(p) => p.type === 'tool' && p.name === chunk.toolName && p.status === 'active'
|
|
220
|
+
);
|
|
221
|
+
|
|
222
|
+
if (toolPart && toolPart.type === 'tool') {
|
|
223
|
+
toolPart.status = 'error';
|
|
224
|
+
toolPart.duration = duration;
|
|
225
|
+
toolPart.error = chunk.error;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Notify callback
|
|
229
|
+
onToolError?.(chunk.toolCallId, chunk.toolName, chunk.error, duration);
|
|
230
|
+
}
|
|
231
|
+
break;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
case 'abort': {
|
|
235
|
+
// Save current text part if any
|
|
236
|
+
if (currentTextContent) {
|
|
237
|
+
messageParts.push({ type: 'text', content: currentTextContent, status: 'completed' });
|
|
238
|
+
currentTextContent = '';
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Mark all active parts as 'abort'
|
|
242
|
+
messageParts.forEach(part => {
|
|
243
|
+
if (part.status === 'active') {
|
|
244
|
+
part.status = 'abort';
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
// Notify callback
|
|
249
|
+
onAbort?.();
|
|
250
|
+
break;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
case 'error': {
|
|
254
|
+
// Save current text part if any
|
|
255
|
+
if (currentTextContent) {
|
|
256
|
+
messageParts.push({ type: 'text', content: currentTextContent, status: 'completed' });
|
|
257
|
+
currentTextContent = '';
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Add error part
|
|
261
|
+
messageParts.push({ type: 'error', error: chunk.error, status: 'completed' });
|
|
262
|
+
|
|
263
|
+
// Notify callback
|
|
264
|
+
onError?.(chunk.error);
|
|
265
|
+
break;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
case 'finish': {
|
|
269
|
+
usage = chunk.usage;
|
|
270
|
+
finishReason = chunk.finishReason;
|
|
271
|
+
onFinish?.(chunk.usage, chunk.finishReason);
|
|
272
|
+
break;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Save final text part if any
|
|
278
|
+
if (currentTextContent) {
|
|
279
|
+
messageParts.push({ type: 'text', content: currentTextContent, status: 'completed' });
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
return {
|
|
283
|
+
fullResponse,
|
|
284
|
+
messageParts,
|
|
285
|
+
usage,
|
|
286
|
+
finishReason,
|
|
287
|
+
};
|
|
288
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import inquirer from 'inquirer';
|
|
2
|
+
import {
|
|
3
|
+
getAllTargetIDs,
|
|
4
|
+
getAllTargets,
|
|
5
|
+
getDefaultTargetUnsafe,
|
|
6
|
+
getImplementedTargetIDs,
|
|
7
|
+
getImplementedTargets,
|
|
8
|
+
getTarget,
|
|
9
|
+
getTargetsWithMCPSupport,
|
|
10
|
+
isTargetImplemented,
|
|
11
|
+
} from '../config/targets.js';
|
|
12
|
+
import { getOrElse, isSome } from '../core/functional/option.js';
|
|
13
|
+
import { projectSettings } from '../utils/settings.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Target Manager interface
|
|
17
|
+
*/
|
|
18
|
+
export interface TargetManager {
|
|
19
|
+
getAllTargets(): ReturnType<typeof getAllTargets>;
|
|
20
|
+
getImplementedTargets(): ReturnType<typeof getImplementedTargets>;
|
|
21
|
+
getTarget(id: string): ReturnType<typeof getTarget>;
|
|
22
|
+
promptForTargetSelection(): Promise<string>;
|
|
23
|
+
resolveTarget(options: { target?: string; allowSelection?: boolean }): Promise<string>;
|
|
24
|
+
isTargetImplemented(targetId: string): boolean;
|
|
25
|
+
getTargetsWithMCPSupport(): ReturnType<typeof getTargetsWithMCPSupport>;
|
|
26
|
+
getImplementedTargetIDs(): ReturnType<typeof getImplementedTargetIDs>;
|
|
27
|
+
getAllTargetIDs(): ReturnType<typeof getAllTargetIDs>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Create a target manager instance
|
|
32
|
+
*/
|
|
33
|
+
export function createTargetManager(): TargetManager {
|
|
34
|
+
/**
|
|
35
|
+
* Detect target from current environment
|
|
36
|
+
*/
|
|
37
|
+
const detectTargetFromEnvironment = (): string | null => {
|
|
38
|
+
try {
|
|
39
|
+
const implementedTargets = getImplementedTargets();
|
|
40
|
+
|
|
41
|
+
// Prioritize non-default targets for detection
|
|
42
|
+
const nonDefaultTargets = implementedTargets.filter((target) => !target.isDefault);
|
|
43
|
+
const defaultTargets = implementedTargets.filter((target) => target.isDefault);
|
|
44
|
+
|
|
45
|
+
// Check non-default targets first
|
|
46
|
+
for (const target of nonDefaultTargets) {
|
|
47
|
+
const detected = target.detectFromEnvironment?.();
|
|
48
|
+
if (detected) {
|
|
49
|
+
return target.id;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Then check default targets
|
|
54
|
+
for (const target of defaultTargets) {
|
|
55
|
+
const detected = target.detectFromEnvironment?.();
|
|
56
|
+
if (detected) {
|
|
57
|
+
return target.id;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return null;
|
|
62
|
+
} catch {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Prompt user to select a target platform
|
|
69
|
+
*/
|
|
70
|
+
const promptForTargetSelection = async (): Promise<string> => {
|
|
71
|
+
const availableTargets = getImplementedTargetIDs();
|
|
72
|
+
|
|
73
|
+
// Try to get saved default target for default selection
|
|
74
|
+
let defaultTarget = getDefaultTargetUnsafe().id;
|
|
75
|
+
try {
|
|
76
|
+
const savedDefaultTarget = await projectSettings.getDefaultTarget();
|
|
77
|
+
if (savedDefaultTarget && isSome(getTarget(savedDefaultTarget))) {
|
|
78
|
+
defaultTarget = savedDefaultTarget;
|
|
79
|
+
}
|
|
80
|
+
} catch {
|
|
81
|
+
// Silently ignore errors reading project settings
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const answer = await inquirer.prompt([
|
|
85
|
+
{
|
|
86
|
+
type: 'list',
|
|
87
|
+
name: 'target',
|
|
88
|
+
message: 'Select target platform:',
|
|
89
|
+
choices: availableTargets.map((id) => {
|
|
90
|
+
const targetOption = getTarget(id);
|
|
91
|
+
const target = getOrElse({ id, name: id } as any)(targetOption);
|
|
92
|
+
return {
|
|
93
|
+
name: target.name || id,
|
|
94
|
+
value: id,
|
|
95
|
+
};
|
|
96
|
+
}),
|
|
97
|
+
default: defaultTarget,
|
|
98
|
+
},
|
|
99
|
+
]);
|
|
100
|
+
|
|
101
|
+
return answer.target;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Resolve target with fallback to default and detection
|
|
106
|
+
*/
|
|
107
|
+
const resolveTarget = async (options: {
|
|
108
|
+
target?: string;
|
|
109
|
+
allowSelection?: boolean;
|
|
110
|
+
}): Promise<string> => {
|
|
111
|
+
// If target is explicitly specified, use it
|
|
112
|
+
if (options.target) {
|
|
113
|
+
if (!isSome(getTarget(options.target))) {
|
|
114
|
+
throw new Error(
|
|
115
|
+
`Unknown target: ${options.target}. Available targets: ${getAllTargetIDs().join(', ')}`
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
return options.target;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Try to use saved project default target first
|
|
122
|
+
try {
|
|
123
|
+
const savedDefaultTarget = await projectSettings.getDefaultTarget();
|
|
124
|
+
if (savedDefaultTarget && isSome(getTarget(savedDefaultTarget))) {
|
|
125
|
+
return savedDefaultTarget;
|
|
126
|
+
}
|
|
127
|
+
} catch (_error) {
|
|
128
|
+
// Silently ignore errors reading project settings
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Try to detect target from environment
|
|
132
|
+
const detectedTarget = detectTargetFromEnvironment();
|
|
133
|
+
if (detectedTarget) {
|
|
134
|
+
return detectedTarget;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// If selection is allowed and no target found, prompt user
|
|
138
|
+
if (options.allowSelection) {
|
|
139
|
+
return await promptForTargetSelection();
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Fall back to system default target
|
|
143
|
+
const defaultTarget = getDefaultTargetUnsafe();
|
|
144
|
+
return defaultTarget.id;
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
getAllTargets: () => getAllTargets(),
|
|
149
|
+
getImplementedTargets: () => getImplementedTargets(),
|
|
150
|
+
getTarget: (id: string) => getTarget(id),
|
|
151
|
+
promptForTargetSelection,
|
|
152
|
+
resolveTarget,
|
|
153
|
+
isTargetImplemented: (targetId: string) => isTargetImplemented(targetId),
|
|
154
|
+
getTargetsWithMCPSupport: () => getTargetsWithMCPSupport(),
|
|
155
|
+
getImplementedTargetIDs: () => getImplementedTargetIDs(),
|
|
156
|
+
getAllTargetIDs: () => getAllTargetIDs(),
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Singleton instance
|
|
161
|
+
export const targetManager = createTargetManager();
|