@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,351 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified Result Type - 統一結果類型
|
|
3
|
+
* Single source of truth for Result<T, E> across the entire project
|
|
4
|
+
*
|
|
5
|
+
* This replaces all conflicting Result type definitions:
|
|
6
|
+
* - src/core/type-utils.ts
|
|
7
|
+
* - src/core/functional/result.ts
|
|
8
|
+
* - src/utils/functional.ts
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// ============================================================================
|
|
12
|
+
// CORE RESULT TYPE
|
|
13
|
+
// ============================================================================
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Result type for functional error handling
|
|
17
|
+
* Represents success or failure without exceptions
|
|
18
|
+
*/
|
|
19
|
+
export type Result<T, E = Error> =
|
|
20
|
+
| { success: true; data: T }
|
|
21
|
+
| { success: false; error: E };
|
|
22
|
+
|
|
23
|
+
// ============================================================================
|
|
24
|
+
// CONSTRUCTORS
|
|
25
|
+
// ============================================================================
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Create a successful result
|
|
29
|
+
*/
|
|
30
|
+
export const ok = <T>(data: T): Result<T> => ({ success: true, data });
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Create an error result
|
|
34
|
+
*/
|
|
35
|
+
export const err = <E>(error: E): Result<never, E> => ({ success: false, error });
|
|
36
|
+
|
|
37
|
+
// ============================================================================
|
|
38
|
+
// TYPE GUARDS
|
|
39
|
+
// ============================================================================
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Check if result is successful
|
|
43
|
+
*/
|
|
44
|
+
export const isOk = <T, E>(result: Result<T, E>): result is { success: true; data: T } =>
|
|
45
|
+
result.success;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Check if result is an error
|
|
49
|
+
*/
|
|
50
|
+
export const isErr = <T, E>(result: Result<T, E>): result is { success: false; error: E } =>
|
|
51
|
+
!result.success;
|
|
52
|
+
|
|
53
|
+
// ============================================================================
|
|
54
|
+
// TRANSFORMATIONS
|
|
55
|
+
// ============================================================================
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Transform the success value
|
|
59
|
+
* Error propagates unchanged
|
|
60
|
+
*/
|
|
61
|
+
export const map =
|
|
62
|
+
<T, U, E>(fn: (data: T) => U) =>
|
|
63
|
+
(result: Result<T, E>): Result<U, E> => {
|
|
64
|
+
if (isOk(result)) {
|
|
65
|
+
return ok(fn(result.data));
|
|
66
|
+
}
|
|
67
|
+
return result;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Transform the success value with a function that returns a Result
|
|
72
|
+
* Enables chaining operations that can fail
|
|
73
|
+
* Error propagates unchanged
|
|
74
|
+
*/
|
|
75
|
+
export const flatMap =
|
|
76
|
+
<T, U, E>(fn: (data: T) => Result<U, E>) =>
|
|
77
|
+
(result: Result<T, E>): Result<U, E> => {
|
|
78
|
+
if (isOk(result)) {
|
|
79
|
+
return fn(result.data);
|
|
80
|
+
}
|
|
81
|
+
return result;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Transform the error
|
|
86
|
+
* Success propagates unchanged
|
|
87
|
+
*/
|
|
88
|
+
export const mapError =
|
|
89
|
+
<T, E, F>(fn: (error: E) => F) =>
|
|
90
|
+
(result: Result<T, E>): Result<T, F> => {
|
|
91
|
+
if (isErr(result)) {
|
|
92
|
+
return err(fn(result.error));
|
|
93
|
+
}
|
|
94
|
+
return result;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Extract value or provide default
|
|
99
|
+
*/
|
|
100
|
+
export const getOrElse =
|
|
101
|
+
<T>(defaultValue: T) =>
|
|
102
|
+
<E>(result: Result<T, E>): T => {
|
|
103
|
+
if (isOk(result)) {
|
|
104
|
+
return result.data;
|
|
105
|
+
}
|
|
106
|
+
return defaultValue;
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Extract value or compute default
|
|
111
|
+
*/
|
|
112
|
+
export const getOrElseLazy =
|
|
113
|
+
<T>(fn: () => T) =>
|
|
114
|
+
<E>(result: Result<T, E>): T => {
|
|
115
|
+
if (isOk(result)) {
|
|
116
|
+
return result.data;
|
|
117
|
+
}
|
|
118
|
+
return fn();
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Pattern matching
|
|
123
|
+
*/
|
|
124
|
+
export const match =
|
|
125
|
+
<T, E, U>(onSuccess: (data: T) => U, onError: (error: E) => U) =>
|
|
126
|
+
(result: Result<T, E>): U => {
|
|
127
|
+
if (isOk(result)) {
|
|
128
|
+
return onSuccess(result.data);
|
|
129
|
+
}
|
|
130
|
+
return onError(result.error);
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Extract value or throw error
|
|
135
|
+
* Use only when you're certain the result is successful
|
|
136
|
+
*/
|
|
137
|
+
export const unwrap = <T, E>(result: Result<T, E>): T => {
|
|
138
|
+
if (isOk(result)) {
|
|
139
|
+
return result.data;
|
|
140
|
+
}
|
|
141
|
+
throw result.error;
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Extract error or throw
|
|
146
|
+
* Use only when you're certain the result is an error
|
|
147
|
+
*/
|
|
148
|
+
export const unwrapError = <T, E>(result: Result<T, E>): E => {
|
|
149
|
+
if (isErr(result)) {
|
|
150
|
+
return result.error;
|
|
151
|
+
}
|
|
152
|
+
throw new Error('Expected error but got success');
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
// ============================================================================
|
|
156
|
+
// ASYNC SUPPORT
|
|
157
|
+
// ============================================================================
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Async result type
|
|
161
|
+
*/
|
|
162
|
+
export type AsyncResult<T, E = Error> = Promise<Result<T, E>>;
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Convert thrown exception to Result
|
|
166
|
+
*/
|
|
167
|
+
export const tryCatch = <T, E = Error>(
|
|
168
|
+
fn: () => T,
|
|
169
|
+
onError: (error: unknown) => E = (error: unknown) => error as E
|
|
170
|
+
): Result<T, E> => {
|
|
171
|
+
try {
|
|
172
|
+
return ok(fn());
|
|
173
|
+
} catch (error) {
|
|
174
|
+
return err(onError(error));
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Convert Promise to Result
|
|
180
|
+
*/
|
|
181
|
+
export const tryCatchAsync = async <T, E = Error>(
|
|
182
|
+
fn: () => Promise<T>,
|
|
183
|
+
onError: (error: unknown) => E = (error: unknown) => error as E
|
|
184
|
+
): Promise<Result<T, E>> => {
|
|
185
|
+
try {
|
|
186
|
+
const data = await fn();
|
|
187
|
+
return ok(data);
|
|
188
|
+
} catch (error) {
|
|
189
|
+
return err(onError(error));
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Safe async function wrapper
|
|
195
|
+
*/
|
|
196
|
+
export const safeAsync = async <T, E = Error>(
|
|
197
|
+
fn: () => Promise<T>,
|
|
198
|
+
errorFn?: (error: unknown) => E
|
|
199
|
+
): Promise<Result<T, E>> => {
|
|
200
|
+
return tryCatchAsync(fn, errorFn);
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Safe sync function wrapper
|
|
205
|
+
*/
|
|
206
|
+
export const safeSync = <T, E = Error>(
|
|
207
|
+
fn: () => T,
|
|
208
|
+
errorFn?: (error: unknown) => E
|
|
209
|
+
): Result<T, E> => {
|
|
210
|
+
return tryCatch(fn, errorFn);
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
// ============================================================================
|
|
214
|
+
// COMBINATORS
|
|
215
|
+
// ============================================================================
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Combine multiple Results into a single Result containing an array
|
|
219
|
+
* Fails if any Result is an error (short-circuits on first error)
|
|
220
|
+
*/
|
|
221
|
+
export const all = <T, E>(results: Result<T, E>[]): Result<T[], E> => {
|
|
222
|
+
const values: T[] = [];
|
|
223
|
+
|
|
224
|
+
for (const result of results) {
|
|
225
|
+
if (isErr(result)) {
|
|
226
|
+
return result;
|
|
227
|
+
}
|
|
228
|
+
values.push(result.data);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return ok(values);
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Combine multiple Results into a single Result containing an array
|
|
236
|
+
* Collects all errors instead of short-circuiting
|
|
237
|
+
*/
|
|
238
|
+
export const allWithErrors = <T, E>(results: Result<T, E>[]): Result<T[], E[]> => {
|
|
239
|
+
const values: T[] = [];
|
|
240
|
+
const errors: E[] = [];
|
|
241
|
+
|
|
242
|
+
for (const result of results) {
|
|
243
|
+
if (isOk(result)) {
|
|
244
|
+
values.push(result.data);
|
|
245
|
+
} else {
|
|
246
|
+
errors.push(result.error);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
return errors.length > 0 ? err(errors) : ok(values);
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Combine multiple AsyncResults
|
|
255
|
+
*/
|
|
256
|
+
export const allAsync = async <T, E>(results: AsyncResult<T, E>[]): Promise<Result<T[], E>> => {
|
|
257
|
+
const settled = await Promise.all(results);
|
|
258
|
+
return all(settled);
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Race multiple AsyncResults - returns first successful result
|
|
263
|
+
*/
|
|
264
|
+
export const raceAsync = async <T, E>(results: AsyncResult<T, E>[]): Promise<Result<T, E>> => {
|
|
265
|
+
try {
|
|
266
|
+
return await Promise.race(results);
|
|
267
|
+
} catch (error) {
|
|
268
|
+
return err(error as E);
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
// ============================================================================
|
|
273
|
+
// SIDE EFFECTS
|
|
274
|
+
// ============================================================================
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Run side effect for success case
|
|
278
|
+
*/
|
|
279
|
+
export const tap =
|
|
280
|
+
<T, E>(fn: (data: T) => void) =>
|
|
281
|
+
(result: Result<T, E>): Result<T, E> => {
|
|
282
|
+
if (isOk(result)) {
|
|
283
|
+
fn(result.data);
|
|
284
|
+
}
|
|
285
|
+
return result;
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Run side effect for error case
|
|
290
|
+
*/
|
|
291
|
+
export const tapError =
|
|
292
|
+
<T, E>(fn: (error: E) => void) =>
|
|
293
|
+
(result: Result<T, E>): Result<T, E> => {
|
|
294
|
+
if (isErr(result)) {
|
|
295
|
+
fn(result.error);
|
|
296
|
+
}
|
|
297
|
+
return result;
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Run side effect for both cases
|
|
302
|
+
*/
|
|
303
|
+
export const tapBoth =
|
|
304
|
+
<T, E>(onSuccess: (data: T) => void, onError: (error: E) => void) =>
|
|
305
|
+
(result: Result<T, E>): Result<T, E> => {
|
|
306
|
+
if (isOk(result)) {
|
|
307
|
+
onSuccess(result.data);
|
|
308
|
+
} else {
|
|
309
|
+
onError(result.error);
|
|
310
|
+
}
|
|
311
|
+
return result;
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
// ============================================================================
|
|
315
|
+
// LEGACY COMPATIBILITY
|
|
316
|
+
// ============================================================================
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Legacy compatibility aliases
|
|
320
|
+
* These help migrate from old Result implementations
|
|
321
|
+
*/
|
|
322
|
+
|
|
323
|
+
// For src/core/functional/result.ts users
|
|
324
|
+
export const success = ok;
|
|
325
|
+
export const failure = err;
|
|
326
|
+
export const isSuccess = isOk;
|
|
327
|
+
export const isFailure = isErr;
|
|
328
|
+
|
|
329
|
+
// For src/utils/functional.ts users
|
|
330
|
+
export const unwrapResult = unwrap;
|
|
331
|
+
export const mapResult = map;
|
|
332
|
+
|
|
333
|
+
// ============================================================================
|
|
334
|
+
// TYPE INFERENCE HELPERS
|
|
335
|
+
// ============================================================================
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Helper to infer the success type from a Result
|
|
339
|
+
*/
|
|
340
|
+
export type SuccessType<T> = T extends Result<infer U, any> ? U : never;
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Helper to infer the error type from a Result
|
|
344
|
+
*/
|
|
345
|
+
export type ErrorType<T> = T extends Result<any, infer E> ? E : never;
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Create a type-safe Result from a function that might throw
|
|
349
|
+
*/
|
|
350
|
+
export type SafeResult<T extends (...args: any[]) => any> =
|
|
351
|
+
Result<ReturnType<T>, Error>;
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule Loader
|
|
3
|
+
* Loads rule definitions from markdown files with front matter
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { readFile, readdir, access } from 'node:fs/promises';
|
|
7
|
+
import { join, parse, relative, dirname } from 'node:path';
|
|
8
|
+
import { homedir } from 'node:os';
|
|
9
|
+
import { fileURLToPath } from 'node:url';
|
|
10
|
+
import matter from 'gray-matter';
|
|
11
|
+
import type { Rule, RuleMetadata } from '../types/rule.types.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Load a single rule from a markdown file
|
|
15
|
+
*/
|
|
16
|
+
export async function loadRuleFromFile(
|
|
17
|
+
filePath: string,
|
|
18
|
+
isBuiltin: boolean = false,
|
|
19
|
+
ruleId?: string
|
|
20
|
+
): Promise<Rule | null> {
|
|
21
|
+
try {
|
|
22
|
+
const fileContent = await readFile(filePath, 'utf-8');
|
|
23
|
+
const { data, content } = matter(fileContent);
|
|
24
|
+
|
|
25
|
+
// Validate front matter
|
|
26
|
+
if (!data.name || typeof data.name !== 'string') {
|
|
27
|
+
console.error(`Rule file ${filePath} missing required 'name' field`);
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const metadata: RuleMetadata = {
|
|
32
|
+
name: data.name,
|
|
33
|
+
description: data.description || '',
|
|
34
|
+
enabled: data.enabled !== undefined ? Boolean(data.enabled) : true,
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// Get rule ID from parameter or filename
|
|
38
|
+
const id = ruleId || parse(filePath).name;
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
id,
|
|
42
|
+
metadata,
|
|
43
|
+
content: content.trim(),
|
|
44
|
+
isBuiltin,
|
|
45
|
+
filePath,
|
|
46
|
+
};
|
|
47
|
+
} catch (error) {
|
|
48
|
+
console.error(`Failed to load rule from ${filePath}:`, error);
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Load all rules from a directory (recursively)
|
|
55
|
+
*/
|
|
56
|
+
export async function loadRulesFromDirectory(dirPath: string, isBuiltin: boolean = false): Promise<Rule[]> {
|
|
57
|
+
try {
|
|
58
|
+
// Read directory recursively to support subdirectories
|
|
59
|
+
const files = await readdir(dirPath, { recursive: true, withFileTypes: true });
|
|
60
|
+
|
|
61
|
+
// Filter for .md files and calculate rule IDs from relative paths
|
|
62
|
+
const ruleFiles = files
|
|
63
|
+
.filter((f) => f.isFile() && f.name.endsWith('.md'))
|
|
64
|
+
.map((f) => {
|
|
65
|
+
const fullPath = join(f.parentPath || f.path, f.name);
|
|
66
|
+
// Calculate relative path from dirPath and remove .md extension
|
|
67
|
+
const relativePath = relative(dirPath, fullPath).replace(/\.md$/, '');
|
|
68
|
+
return { fullPath, ruleId: relativePath };
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const rules = await Promise.all(
|
|
72
|
+
ruleFiles.map(({ fullPath, ruleId }) => loadRuleFromFile(fullPath, isBuiltin, ruleId))
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
return rules.filter((rule): rule is Rule => rule !== null);
|
|
76
|
+
} catch (error) {
|
|
77
|
+
// Directory doesn't exist or can't be read
|
|
78
|
+
return [];
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Get system rules path (bundled with the app)
|
|
84
|
+
*/
|
|
85
|
+
export async function getSystemRulesPath(): Promise<string> {
|
|
86
|
+
// Get the directory of the current module (cross-platform)
|
|
87
|
+
const currentFile = fileURLToPath(import.meta.url);
|
|
88
|
+
const currentDir = dirname(currentFile);
|
|
89
|
+
|
|
90
|
+
// In production (dist), assets are at dist/assets/rules
|
|
91
|
+
// In development (src), go up to project root: src/core -> project root
|
|
92
|
+
const distPath = join(currentDir, '..', 'assets', 'rules');
|
|
93
|
+
const devPath = join(currentDir, '..', '..', 'assets', 'rules');
|
|
94
|
+
|
|
95
|
+
// Check which one exists (try dist first, then dev)
|
|
96
|
+
try {
|
|
97
|
+
await access(distPath);
|
|
98
|
+
return distPath;
|
|
99
|
+
} catch {
|
|
100
|
+
return devPath;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Get all rule search paths
|
|
106
|
+
*/
|
|
107
|
+
export function getRuleSearchPaths(cwd: string): string[] {
|
|
108
|
+
const globalPath = join(homedir(), '.sylphx-flow', 'rules');
|
|
109
|
+
const projectPath = join(cwd, '.sylphx-flow', 'rules');
|
|
110
|
+
|
|
111
|
+
return [globalPath, projectPath];
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Load all available rules from all sources
|
|
116
|
+
*/
|
|
117
|
+
export async function loadAllRules(cwd: string): Promise<Rule[]> {
|
|
118
|
+
const systemPath = await getSystemRulesPath();
|
|
119
|
+
const [globalPath, projectPath] = getRuleSearchPaths(cwd);
|
|
120
|
+
|
|
121
|
+
const [systemRules, globalRules, projectRules] = await Promise.all([
|
|
122
|
+
loadRulesFromDirectory(systemPath, true), // System rules are marked as builtin
|
|
123
|
+
loadRulesFromDirectory(globalPath, false),
|
|
124
|
+
loadRulesFromDirectory(projectPath, false),
|
|
125
|
+
]);
|
|
126
|
+
|
|
127
|
+
// Priority: system < global < project
|
|
128
|
+
// Use Map to deduplicate by ID (later entries override earlier ones)
|
|
129
|
+
const ruleMap = new Map<string, Rule>();
|
|
130
|
+
|
|
131
|
+
// Add system rules first (lowest priority)
|
|
132
|
+
for (const rule of systemRules) {
|
|
133
|
+
ruleMap.set(rule.id, rule);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Add global rules (override system)
|
|
137
|
+
for (const rule of globalRules) {
|
|
138
|
+
ruleMap.set(rule.id, rule);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Add project rules (override globals and system)
|
|
142
|
+
for (const rule of projectRules) {
|
|
143
|
+
ruleMap.set(rule.id, rule);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return Array.from(ruleMap.values());
|
|
147
|
+
}
|