@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,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Result type for functional error handling
|
|
3
|
+
* Represents success or failure without exceptions
|
|
4
|
+
*
|
|
5
|
+
* DESIGN RATIONALE:
|
|
6
|
+
* - Explicit error handling at type level
|
|
7
|
+
* - Composable through map/flatMap
|
|
8
|
+
* - Forces caller to handle errors
|
|
9
|
+
* - No hidden control flow (no thrown exceptions)
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
export type Result<T, E = Error> = Success<T> | Failure<E>;
|
|
13
|
+
|
|
14
|
+
export interface Success<T> {
|
|
15
|
+
readonly _tag: 'Success';
|
|
16
|
+
readonly value: T;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface Failure<E> {
|
|
20
|
+
readonly _tag: 'Failure';
|
|
21
|
+
readonly error: E;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Constructors
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
export const success = <T>(value: T): Success<T> => ({
|
|
29
|
+
_tag: 'Success',
|
|
30
|
+
value,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
export const failure = <E>(error: E): Failure<E> => ({
|
|
34
|
+
_tag: 'Failure',
|
|
35
|
+
error,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Type guards
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
export const isSuccess = <T, E>(result: Result<T, E>): result is Success<T> =>
|
|
43
|
+
result._tag === 'Success';
|
|
44
|
+
|
|
45
|
+
export const isFailure = <T, E>(result: Result<T, E>): result is Failure<E> =>
|
|
46
|
+
result._tag === 'Failure';
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Transformations
|
|
50
|
+
*/
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Transform the success value
|
|
54
|
+
* Failure propagates unchanged
|
|
55
|
+
*/
|
|
56
|
+
export const map =
|
|
57
|
+
<T, U, E>(fn: (value: T) => U) =>
|
|
58
|
+
(result: Result<T, E>): Result<U, E> => {
|
|
59
|
+
if (isSuccess(result)) {
|
|
60
|
+
return success(fn(result.value));
|
|
61
|
+
}
|
|
62
|
+
return result;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Transform the success value with a function that returns a Result
|
|
67
|
+
* Enables chaining operations that can fail
|
|
68
|
+
* Failure propagates unchanged
|
|
69
|
+
*/
|
|
70
|
+
export const flatMap =
|
|
71
|
+
<T, U, E>(fn: (value: T) => Result<U, E>) =>
|
|
72
|
+
(result: Result<T, E>): Result<U, E> => {
|
|
73
|
+
if (isSuccess(result)) {
|
|
74
|
+
return fn(result.value);
|
|
75
|
+
}
|
|
76
|
+
return result;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Transform the error
|
|
81
|
+
* Success propagates unchanged
|
|
82
|
+
*/
|
|
83
|
+
export const mapError =
|
|
84
|
+
<T, E, F>(fn: (error: E) => F) =>
|
|
85
|
+
(result: Result<T, E>): Result<T, F> => {
|
|
86
|
+
if (isFailure(result)) {
|
|
87
|
+
return failure(fn(result.error));
|
|
88
|
+
}
|
|
89
|
+
return result;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Extract value or provide default
|
|
94
|
+
*/
|
|
95
|
+
export const getOrElse =
|
|
96
|
+
<T>(defaultValue: T) =>
|
|
97
|
+
<E>(result: Result<T, E>): T => {
|
|
98
|
+
if (isSuccess(result)) {
|
|
99
|
+
return result.value;
|
|
100
|
+
}
|
|
101
|
+
return defaultValue;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Extract value or compute default
|
|
106
|
+
*/
|
|
107
|
+
export const getOrElseLazy =
|
|
108
|
+
<T>(fn: () => T) =>
|
|
109
|
+
<E>(result: Result<T, E>): T => {
|
|
110
|
+
if (isSuccess(result)) {
|
|
111
|
+
return result.value;
|
|
112
|
+
}
|
|
113
|
+
return fn();
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Pattern matching
|
|
118
|
+
*/
|
|
119
|
+
export const match =
|
|
120
|
+
<T, E, U>(onSuccess: (value: T) => U, onFailure: (error: E) => U) =>
|
|
121
|
+
(result: Result<T, E>): U => {
|
|
122
|
+
if (isSuccess(result)) {
|
|
123
|
+
return onSuccess(result.value);
|
|
124
|
+
}
|
|
125
|
+
return onFailure(result.error);
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Convert thrown exception to Result
|
|
130
|
+
*/
|
|
131
|
+
export const tryCatch = <T, E = Error>(
|
|
132
|
+
fn: () => T,
|
|
133
|
+
onError: (error: unknown) => E = (error: unknown) => error as E
|
|
134
|
+
): Result<T, E> => {
|
|
135
|
+
try {
|
|
136
|
+
return success(fn());
|
|
137
|
+
} catch (error) {
|
|
138
|
+
return failure(onError(error));
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Convert Promise to Result
|
|
144
|
+
*/
|
|
145
|
+
export const tryCatchAsync = async <T, E = Error>(
|
|
146
|
+
fn: () => Promise<T>,
|
|
147
|
+
onError: (error: unknown) => E = (error: unknown) => error as E
|
|
148
|
+
): Promise<Result<T, E>> => {
|
|
149
|
+
try {
|
|
150
|
+
const value = await fn();
|
|
151
|
+
return success(value);
|
|
152
|
+
} catch (error) {
|
|
153
|
+
return failure(onError(error));
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Combine multiple Results into a single Result containing an array
|
|
159
|
+
* Fails if any Result is a Failure (short-circuits on first failure)
|
|
160
|
+
*/
|
|
161
|
+
export const all = <T, E>(results: Result<T, E>[]): Result<T[], E> => {
|
|
162
|
+
const values: T[] = [];
|
|
163
|
+
|
|
164
|
+
for (const result of results) {
|
|
165
|
+
if (isFailure(result)) {
|
|
166
|
+
return result;
|
|
167
|
+
}
|
|
168
|
+
values.push(result.value);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return success(values);
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Run side effect for success case
|
|
176
|
+
*/
|
|
177
|
+
export const tap =
|
|
178
|
+
<T, E>(fn: (value: T) => void) =>
|
|
179
|
+
(result: Result<T, E>): Result<T, E> => {
|
|
180
|
+
if (isSuccess(result)) {
|
|
181
|
+
fn(result.value);
|
|
182
|
+
}
|
|
183
|
+
return result;
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Run side effect for failure case
|
|
188
|
+
*/
|
|
189
|
+
export const tapError =
|
|
190
|
+
<T, E>(fn: (error: E) => void) =>
|
|
191
|
+
(result: Result<T, E>): Result<T, E> => {
|
|
192
|
+
if (isFailure(result)) {
|
|
193
|
+
fn(result.error);
|
|
194
|
+
}
|
|
195
|
+
return result;
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Functional pipe for composing Result transformations
|
|
200
|
+
*/
|
|
201
|
+
export const pipe =
|
|
202
|
+
<T, E>(result: Result<T, E>) =>
|
|
203
|
+
<U>(fn: (result: Result<T, E>) => U): U =>
|
|
204
|
+
fn(result);
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validation utilities for accumulating errors
|
|
3
|
+
* Unlike Result which short-circuits on first error,
|
|
4
|
+
* Validation accumulates all errors
|
|
5
|
+
*
|
|
6
|
+
* DESIGN RATIONALE:
|
|
7
|
+
* - Form validation needs all errors, not just first
|
|
8
|
+
* - Applicative functor for combining validations
|
|
9
|
+
* - Errors accumulated in array
|
|
10
|
+
* - Success only if all validations pass
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type { Result } from './result.js';
|
|
14
|
+
import { failure, isSuccess, success } from './result.js';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Validation result with accumulated errors
|
|
18
|
+
*/
|
|
19
|
+
export type Validation<T, E = string> = Result<T, E[]>;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Create a successful validation
|
|
23
|
+
*/
|
|
24
|
+
export const valid = <T, E = string>(value: T): Validation<T, E> => success(value);
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Create a failed validation with one or more errors
|
|
28
|
+
*/
|
|
29
|
+
export const invalid = <T, E = string>(...errors: E[]): Validation<T, E> => failure(errors);
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Combine multiple validations
|
|
33
|
+
* Collects all errors if any validation fails
|
|
34
|
+
*/
|
|
35
|
+
export const combine = <T, E = string>(validations: Validation<T, E>[]): Validation<T[], E> => {
|
|
36
|
+
const values: T[] = [];
|
|
37
|
+
const errors: E[] = [];
|
|
38
|
+
|
|
39
|
+
for (const validation of validations) {
|
|
40
|
+
if (isSuccess(validation)) {
|
|
41
|
+
values.push(validation.value);
|
|
42
|
+
} else {
|
|
43
|
+
errors.push(...validation.error);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (errors.length > 0) {
|
|
48
|
+
return invalid(...errors);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return valid(values);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Validate a value against multiple validators
|
|
56
|
+
* Returns first error or success
|
|
57
|
+
*/
|
|
58
|
+
export const validateAll =
|
|
59
|
+
<T, E = string>(...validators: Array<(value: T) => Validation<T, E>>) =>
|
|
60
|
+
(value: T): Validation<T, E> => {
|
|
61
|
+
const errors: E[] = [];
|
|
62
|
+
|
|
63
|
+
for (const validator of validators) {
|
|
64
|
+
const result = validator(value);
|
|
65
|
+
if (!isSuccess(result)) {
|
|
66
|
+
errors.push(...result.error);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (errors.length > 0) {
|
|
71
|
+
return invalid(...errors);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return valid(value);
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Common validators
|
|
79
|
+
*/
|
|
80
|
+
|
|
81
|
+
export const nonEmpty =
|
|
82
|
+
(message: string) =>
|
|
83
|
+
(value: string): Validation<string, string> => {
|
|
84
|
+
if (value.trim().length === 0) {
|
|
85
|
+
return invalid(message);
|
|
86
|
+
}
|
|
87
|
+
return valid(value);
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
export const minLength =
|
|
91
|
+
(min: number, message: string) =>
|
|
92
|
+
(value: string): Validation<string, string> => {
|
|
93
|
+
if (value.length < min) {
|
|
94
|
+
return invalid(message);
|
|
95
|
+
}
|
|
96
|
+
return valid(value);
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
export const maxLength =
|
|
100
|
+
(max: number, message: string) =>
|
|
101
|
+
(value: string): Validation<string, string> => {
|
|
102
|
+
if (value.length > max) {
|
|
103
|
+
return invalid(message);
|
|
104
|
+
}
|
|
105
|
+
return valid(value);
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
export const matches =
|
|
109
|
+
(pattern: RegExp, message: string) =>
|
|
110
|
+
(value: string): Validation<string, string> => {
|
|
111
|
+
if (!pattern.test(value)) {
|
|
112
|
+
return invalid(message);
|
|
113
|
+
}
|
|
114
|
+
return valid(value);
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
export const isEmail = (message: string) => matches(/^[^\s@]+@[^\s@]+\.[^\s@]+$/, message);
|
|
118
|
+
|
|
119
|
+
export const isUrl = (message: string) => matches(/^https?:\/\/.+/, message);
|
|
120
|
+
|
|
121
|
+
export const isNumber =
|
|
122
|
+
(message: string) =>
|
|
123
|
+
(value: string): Validation<number, string> => {
|
|
124
|
+
const num = Number(value);
|
|
125
|
+
if (Number.isNaN(num)) {
|
|
126
|
+
return invalid(message);
|
|
127
|
+
}
|
|
128
|
+
return valid(num);
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
export const range =
|
|
132
|
+
(min: number, max: number, message: string) =>
|
|
133
|
+
(value: number): Validation<number, string> => {
|
|
134
|
+
if (value < min || value > max) {
|
|
135
|
+
return invalid(message);
|
|
136
|
+
}
|
|
137
|
+
return valid(value);
|
|
138
|
+
};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Headless Display
|
|
3
|
+
* Formatting and display logic for headless mode (non-TUI)
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Format tool arguments for display
|
|
10
|
+
*/
|
|
11
|
+
function formatArgs(args: unknown): string {
|
|
12
|
+
if (!args || typeof args !== 'object') {
|
|
13
|
+
return '';
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const argsStr = Object.keys(args).length === 0
|
|
17
|
+
? ''
|
|
18
|
+
: JSON.stringify(args, null, 2);
|
|
19
|
+
|
|
20
|
+
if (!argsStr) {
|
|
21
|
+
return '';
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const lines = argsStr.split('\n');
|
|
25
|
+
const truncated = lines.length > 5
|
|
26
|
+
? lines.slice(0, 5).join('\n') + chalk.dim('\n … +' + (lines.length - 5) + ' lines')
|
|
27
|
+
: argsStr;
|
|
28
|
+
|
|
29
|
+
return truncated;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Format tool result for display
|
|
34
|
+
*/
|
|
35
|
+
function formatResult(result: unknown): string {
|
|
36
|
+
const resultStr = JSON.stringify(result, null, 2);
|
|
37
|
+
const lines = resultStr.split('\n');
|
|
38
|
+
const truncated = lines.length > 5
|
|
39
|
+
? lines.slice(0, 5).join('\n') + chalk.dim('\n … +' + (lines.length - 5) + ' lines')
|
|
40
|
+
: resultStr;
|
|
41
|
+
|
|
42
|
+
return truncated;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Display callbacks for headless mode
|
|
47
|
+
*/
|
|
48
|
+
export function createHeadlessDisplay(quiet: boolean) {
|
|
49
|
+
let hasOutput = false;
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
onToolCall: (toolName: string, args: unknown) => {
|
|
53
|
+
if (quiet) return;
|
|
54
|
+
|
|
55
|
+
// Flush stdout to ensure proper ordering
|
|
56
|
+
if (hasOutput) {
|
|
57
|
+
process.stdout.write('\n');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const argsStr = formatArgs(args);
|
|
61
|
+
if (argsStr) {
|
|
62
|
+
process.stderr.write(`\n${chalk.green('⏺')} ${chalk.bold(toolName)}\n`);
|
|
63
|
+
process.stderr.write(chalk.dim(` ⎿ ${argsStr.split('\n').join('\n ')}\n`));
|
|
64
|
+
} else {
|
|
65
|
+
process.stderr.write(`\n${chalk.green('⏺')} ${chalk.bold(toolName)}\n`);
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
onToolResult: (toolName: string, result: unknown, duration: number) => {
|
|
70
|
+
if (quiet) return;
|
|
71
|
+
|
|
72
|
+
const resultStr = formatResult(result);
|
|
73
|
+
process.stderr.write(`${chalk.green('●')} ${chalk.bold(toolName)} ${chalk.dim(`(${duration}ms)`)}\n`);
|
|
74
|
+
process.stderr.write(chalk.dim(` ⎿ ${resultStr.split('\n').join('\n ')}\n\n`));
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
onTextDelta: (text: string) => {
|
|
78
|
+
if (!hasOutput) {
|
|
79
|
+
hasOutput = true;
|
|
80
|
+
// Add newline before first text output if we're not in quiet mode
|
|
81
|
+
if (!quiet) {
|
|
82
|
+
process.stdout.write('\n');
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
process.stdout.write(text);
|
|
86
|
+
},
|
|
87
|
+
|
|
88
|
+
onComplete: () => {
|
|
89
|
+
if (hasOutput) {
|
|
90
|
+
process.stdout.write('\n\n');
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
|
|
94
|
+
hasOutput: () => hasOutput,
|
|
95
|
+
};
|
|
96
|
+
}
|