@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.
Files changed (229) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/package.json +10 -9
  3. package/src/commands/codebase-command.ts +168 -0
  4. package/src/commands/flow-command.ts +1137 -0
  5. package/src/commands/flow-orchestrator.ts +296 -0
  6. package/src/commands/hook-command.ts +444 -0
  7. package/src/commands/init-command.ts +92 -0
  8. package/src/commands/init-core.ts +322 -0
  9. package/src/commands/knowledge-command.ts +161 -0
  10. package/src/commands/run-command.ts +120 -0
  11. package/src/components/benchmark-monitor.tsx +331 -0
  12. package/src/components/reindex-progress.tsx +261 -0
  13. package/src/composables/functional/index.ts +14 -0
  14. package/src/composables/functional/useEnvironment.ts +171 -0
  15. package/src/composables/functional/useFileSystem.ts +139 -0
  16. package/src/composables/index.ts +5 -0
  17. package/src/composables/useEnv.ts +13 -0
  18. package/src/composables/useRuntimeConfig.ts +27 -0
  19. package/src/composables/useTargetConfig.ts +45 -0
  20. package/src/config/ai-config.ts +376 -0
  21. package/src/config/constants.ts +35 -0
  22. package/src/config/index.ts +27 -0
  23. package/src/config/rules.ts +43 -0
  24. package/src/config/servers.ts +371 -0
  25. package/src/config/targets.ts +126 -0
  26. package/src/core/agent-loader.ts +141 -0
  27. package/src/core/agent-manager.ts +174 -0
  28. package/src/core/ai-sdk.ts +603 -0
  29. package/src/core/app-factory.ts +381 -0
  30. package/src/core/builtin-agents.ts +9 -0
  31. package/src/core/command-system.ts +550 -0
  32. package/src/core/config-system.ts +550 -0
  33. package/src/core/connection-pool.ts +390 -0
  34. package/src/core/di-container.ts +155 -0
  35. package/src/core/error-handling.ts +519 -0
  36. package/src/core/formatting/bytes.test.ts +115 -0
  37. package/src/core/formatting/bytes.ts +64 -0
  38. package/src/core/functional/async.ts +313 -0
  39. package/src/core/functional/either.ts +109 -0
  40. package/src/core/functional/error-handler.ts +135 -0
  41. package/src/core/functional/error-types.ts +311 -0
  42. package/src/core/functional/index.ts +19 -0
  43. package/src/core/functional/option.ts +142 -0
  44. package/src/core/functional/pipe.ts +189 -0
  45. package/src/core/functional/result.ts +204 -0
  46. package/src/core/functional/validation.ts +138 -0
  47. package/src/core/headless-display.ts +96 -0
  48. package/src/core/index.ts +6 -0
  49. package/src/core/installers/file-installer.ts +303 -0
  50. package/src/core/installers/mcp-installer.ts +213 -0
  51. package/src/core/interfaces/index.ts +22 -0
  52. package/src/core/interfaces/repository.interface.ts +91 -0
  53. package/src/core/interfaces/service.interface.ts +133 -0
  54. package/src/core/interfaces.ts +129 -0
  55. package/src/core/loop-controller.ts +200 -0
  56. package/src/core/result.ts +351 -0
  57. package/src/core/rule-loader.ts +147 -0
  58. package/src/core/rule-manager.ts +240 -0
  59. package/src/core/service-config.ts +252 -0
  60. package/src/core/session-service.ts +121 -0
  61. package/src/core/state-detector.ts +389 -0
  62. package/src/core/storage-factory.ts +115 -0
  63. package/src/core/stream-handler.ts +288 -0
  64. package/src/core/target-manager.ts +161 -0
  65. package/src/core/type-utils.ts +427 -0
  66. package/src/core/unified-storage.ts +456 -0
  67. package/src/core/upgrade-manager.ts +300 -0
  68. package/src/core/validation/limit.test.ts +155 -0
  69. package/src/core/validation/limit.ts +46 -0
  70. package/src/core/validation/query.test.ts +44 -0
  71. package/src/core/validation/query.ts +20 -0
  72. package/src/db/auto-migrate.ts +322 -0
  73. package/src/db/base-database-client.ts +144 -0
  74. package/src/db/cache-db.ts +218 -0
  75. package/src/db/cache-schema.ts +75 -0
  76. package/src/db/database.ts +70 -0
  77. package/src/db/index.ts +252 -0
  78. package/src/db/memory-db.ts +153 -0
  79. package/src/db/memory-schema.ts +29 -0
  80. package/src/db/schema.ts +289 -0
  81. package/src/db/session-repository.ts +733 -0
  82. package/src/domains/codebase/index.ts +5 -0
  83. package/src/domains/codebase/tools.ts +139 -0
  84. package/src/domains/index.ts +8 -0
  85. package/src/domains/knowledge/index.ts +10 -0
  86. package/src/domains/knowledge/resources.ts +537 -0
  87. package/src/domains/knowledge/tools.ts +174 -0
  88. package/src/domains/utilities/index.ts +6 -0
  89. package/src/domains/utilities/time/index.ts +5 -0
  90. package/src/domains/utilities/time/tools.ts +291 -0
  91. package/src/index.ts +211 -0
  92. package/src/services/agent-service.ts +273 -0
  93. package/src/services/claude-config-service.ts +252 -0
  94. package/src/services/config-service.ts +258 -0
  95. package/src/services/evaluation-service.ts +271 -0
  96. package/src/services/functional/evaluation-logic.ts +296 -0
  97. package/src/services/functional/file-processor.ts +273 -0
  98. package/src/services/functional/index.ts +12 -0
  99. package/src/services/index.ts +13 -0
  100. package/src/services/mcp-service.ts +432 -0
  101. package/src/services/memory.service.ts +476 -0
  102. package/src/services/search/base-indexer.ts +156 -0
  103. package/src/services/search/codebase-indexer-types.ts +38 -0
  104. package/src/services/search/codebase-indexer.ts +647 -0
  105. package/src/services/search/embeddings-provider.ts +455 -0
  106. package/src/services/search/embeddings.ts +316 -0
  107. package/src/services/search/functional-indexer.ts +323 -0
  108. package/src/services/search/index.ts +27 -0
  109. package/src/services/search/indexer.ts +380 -0
  110. package/src/services/search/knowledge-indexer.ts +422 -0
  111. package/src/services/search/semantic-search.ts +244 -0
  112. package/src/services/search/tfidf.ts +559 -0
  113. package/src/services/search/unified-search-service.ts +888 -0
  114. package/src/services/smart-config-service.ts +385 -0
  115. package/src/services/storage/cache-storage.ts +487 -0
  116. package/src/services/storage/drizzle-storage.ts +581 -0
  117. package/src/services/storage/index.ts +15 -0
  118. package/src/services/storage/lancedb-vector-storage.ts +494 -0
  119. package/src/services/storage/memory-storage.ts +268 -0
  120. package/src/services/storage/separated-storage.ts +467 -0
  121. package/src/services/storage/vector-storage.ts +13 -0
  122. package/src/shared/agents/index.ts +63 -0
  123. package/src/shared/files/index.ts +99 -0
  124. package/src/shared/index.ts +32 -0
  125. package/src/shared/logging/index.ts +24 -0
  126. package/src/shared/processing/index.ts +153 -0
  127. package/src/shared/types/index.ts +25 -0
  128. package/src/targets/claude-code.ts +574 -0
  129. package/src/targets/functional/claude-code-logic.ts +185 -0
  130. package/src/targets/functional/index.ts +6 -0
  131. package/src/targets/opencode.ts +529 -0
  132. package/src/types/agent.types.ts +32 -0
  133. package/src/types/api/batch.ts +108 -0
  134. package/src/types/api/errors.ts +118 -0
  135. package/src/types/api/index.ts +55 -0
  136. package/src/types/api/requests.ts +76 -0
  137. package/src/types/api/responses.ts +180 -0
  138. package/src/types/api/websockets.ts +85 -0
  139. package/src/types/api.types.ts +9 -0
  140. package/src/types/benchmark.ts +49 -0
  141. package/src/types/cli.types.ts +87 -0
  142. package/src/types/common.types.ts +35 -0
  143. package/src/types/database.types.ts +510 -0
  144. package/src/types/mcp-config.types.ts +448 -0
  145. package/src/types/mcp.types.ts +69 -0
  146. package/src/types/memory-types.ts +63 -0
  147. package/src/types/provider.types.ts +28 -0
  148. package/src/types/rule.types.ts +24 -0
  149. package/src/types/session.types.ts +214 -0
  150. package/src/types/target-config.types.ts +295 -0
  151. package/src/types/target.types.ts +140 -0
  152. package/src/types/todo.types.ts +25 -0
  153. package/src/types.ts +40 -0
  154. package/src/utils/advanced-tokenizer.ts +191 -0
  155. package/src/utils/agent-enhancer.ts +114 -0
  156. package/src/utils/ai-model-fetcher.ts +19 -0
  157. package/src/utils/async-file-operations.ts +516 -0
  158. package/src/utils/audio-player.ts +345 -0
  159. package/src/utils/cli-output.ts +266 -0
  160. package/src/utils/codebase-helpers.ts +211 -0
  161. package/src/utils/console-ui.ts +79 -0
  162. package/src/utils/database-errors.ts +140 -0
  163. package/src/utils/debug-logger.ts +49 -0
  164. package/src/utils/error-handler.ts +53 -0
  165. package/src/utils/file-operations.ts +310 -0
  166. package/src/utils/file-scanner.ts +259 -0
  167. package/src/utils/functional/array.ts +355 -0
  168. package/src/utils/functional/index.ts +15 -0
  169. package/src/utils/functional/object.ts +279 -0
  170. package/src/utils/functional/string.ts +281 -0
  171. package/src/utils/functional.ts +543 -0
  172. package/src/utils/help.ts +20 -0
  173. package/src/utils/immutable-cache.ts +106 -0
  174. package/src/utils/index.ts +78 -0
  175. package/src/utils/jsonc.ts +158 -0
  176. package/src/utils/logger.ts +396 -0
  177. package/src/utils/mcp-config.ts +249 -0
  178. package/src/utils/memory-tui.ts +414 -0
  179. package/src/utils/models-dev.ts +91 -0
  180. package/src/utils/notifications.ts +169 -0
  181. package/src/utils/object-utils.ts +51 -0
  182. package/src/utils/parallel-operations.ts +487 -0
  183. package/src/utils/paths.ts +143 -0
  184. package/src/utils/process-manager.ts +155 -0
  185. package/src/utils/prompts.ts +120 -0
  186. package/src/utils/search-tool-builder.ts +214 -0
  187. package/src/utils/secret-utils.ts +179 -0
  188. package/src/utils/security.ts +537 -0
  189. package/src/utils/session-manager.ts +168 -0
  190. package/src/utils/session-title.ts +87 -0
  191. package/src/utils/settings.ts +182 -0
  192. package/src/utils/simplified-errors.ts +410 -0
  193. package/src/utils/sync-utils.ts +159 -0
  194. package/src/utils/target-config.ts +570 -0
  195. package/src/utils/target-utils.ts +394 -0
  196. package/src/utils/template-engine.ts +94 -0
  197. package/src/utils/test-audio.ts +71 -0
  198. package/src/utils/todo-context.ts +46 -0
  199. package/src/utils/token-counter.ts +288 -0
  200. package/dist/index.d.ts +0 -10
  201. package/dist/index.js +0 -59554
  202. package/dist/lancedb.linux-x64-gnu-b7f0jgsz.node +0 -0
  203. package/dist/lancedb.linux-x64-musl-tgcv22rx.node +0 -0
  204. package/dist/shared/chunk-25dwp0dp.js +0 -89
  205. package/dist/shared/chunk-3pjb6063.js +0 -208
  206. package/dist/shared/chunk-4d6ydpw7.js +0 -2854
  207. package/dist/shared/chunk-4wjcadjk.js +0 -225
  208. package/dist/shared/chunk-5j4w74t6.js +0 -30
  209. package/dist/shared/chunk-5j8m3dh3.js +0 -58
  210. package/dist/shared/chunk-5thh3qem.js +0 -91
  211. package/dist/shared/chunk-6g9xy73m.js +0 -252
  212. package/dist/shared/chunk-7eq34c42.js +0 -23
  213. package/dist/shared/chunk-c2gwgx3r.js +0 -115
  214. package/dist/shared/chunk-cjd3mk4c.js +0 -1320
  215. package/dist/shared/chunk-g5cv6703.js +0 -368
  216. package/dist/shared/chunk-hpkhykhq.js +0 -574
  217. package/dist/shared/chunk-m2322pdk.js +0 -122
  218. package/dist/shared/chunk-nd5fdvaq.js +0 -26
  219. package/dist/shared/chunk-pgd3m6zf.js +0 -108
  220. package/dist/shared/chunk-qk8n91hw.js +0 -494
  221. package/dist/shared/chunk-rkkn8szp.js +0 -16855
  222. package/dist/shared/chunk-t16rfxh0.js +0 -61
  223. package/dist/shared/chunk-t4fbfa5v.js +0 -19
  224. package/dist/shared/chunk-t77h86w6.js +0 -276
  225. package/dist/shared/chunk-v0ez4aef.js +0 -71
  226. package/dist/shared/chunk-v29j2r3s.js +0 -32051
  227. package/dist/shared/chunk-vfbc6ew5.js +0 -765
  228. package/dist/shared/chunk-vmeqwm1c.js +0 -204
  229. package/dist/shared/chunk-x66eh37x.js +0 -137
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Centralized utility exports
3
+ * Provides both legacy organization and new feature-based organization
4
+ */
5
+
6
+ // ============================================================================
7
+ // FEATURE-BASED ORGANIZATION (Removed - migrated to domains/ and services/)
8
+ // ============================================================================
9
+ // Features now organized in:
10
+ // - src/domains/ for domain-specific logic
11
+ // - src/services/ for shared infrastructure
12
+
13
+ // ============================================================================
14
+ // LEGACY ORGANIZATION (Backward Compatibility)
15
+ // ============================================================================
16
+ // Direct exports for backward compatibility - @deprecated
17
+
18
+ export * from './cache-storage.js';
19
+ export * from './database-errors.js';
20
+ // Database utilities
21
+ export * from './drizzle-storage.js';
22
+ // Error handling
23
+ export * from './error-handler.js';
24
+ // File operations
25
+ export * from './file-operations.js';
26
+ // JSONC utilities
27
+ export * from './jsonc.js';
28
+ // Logger utilities
29
+ export * from './logger.js';
30
+ export * from './memory-storage.js';
31
+ // Path utilities
32
+ export * from './paths.js';
33
+ // Security utilities
34
+ export * from './security.js';
35
+ export * from './simplified-errors.js';
36
+ // Target configuration
37
+ export * from './target-config.js';
38
+
39
+ // Search and indexing - moved to services/search/
40
+
41
+ // Command builder
42
+ export * from './command-builder.js';
43
+ // Console UI utilities
44
+ export * from './console-ui.js';
45
+ // Prompt utilities
46
+ export * from './prompts.js';
47
+ // Secret utilities
48
+ export * from './secret-utils.js';
49
+ // Template engine
50
+ export * from './template-engine.js';
51
+
52
+ // Embeddings and TF-IDF - moved to services/search/
53
+
54
+ // Help utilities
55
+ export * from './help.js';
56
+
57
+ // Target utilities
58
+ export * from './target-utils.js';
59
+
60
+ // Migration examples - removed (obsolete)
61
+ // Test utilities - removed (obsolete)
62
+
63
+ // Shared utilities
64
+ export * from '../shared/index.js';
65
+
66
+ // Base indexer - moved to services/search/
67
+
68
+ // LanceDB vector storage
69
+ export * from './lancedb-vector-storage.js';
70
+ // Separated storage
71
+ export * from './separated-storage.js';
72
+ // Settings utilities
73
+ export * from './settings.js';
74
+
75
+ // Target config types
76
+ export * from './target-config.js';
77
+ // Vector storage
78
+ export * from './vector-storage.js';
@@ -0,0 +1,158 @@
1
+ /**
2
+ * JSONC (JSON with Comments) utilities
3
+ * Provides functions to parse and stringify JSONC files while preserving comments
4
+ */
5
+
6
+ import { readFile, writeFile } from 'node:fs/promises';
7
+
8
+ /**
9
+ * Parse JSONC content (JSON with Comments)
10
+ * @param content - The JSONC string to parse
11
+ * @returns The parsed JavaScript object
12
+ */
13
+ export function parseJSONC(content: string): unknown {
14
+ try {
15
+ // Remove single-line comments (//) but not inside strings
16
+ let cleaned = removeComments(content);
17
+
18
+ // Remove trailing commas before closing brackets/braces
19
+ cleaned = cleaned.replace(/,(\s*[}\]])/g, '$1');
20
+
21
+ return JSON.parse(cleaned);
22
+ } catch (error) {
23
+ throw new Error(
24
+ `Failed to parse JSONC: ${error instanceof Error ? error.message : 'Unknown error'}`
25
+ );
26
+ }
27
+ }
28
+
29
+ /**
30
+ * Remove comments from JSON content while preserving strings
31
+ */
32
+ function removeComments(content: string): string {
33
+ let result = '';
34
+ let inString = false;
35
+ let inSingleLineComment = false;
36
+ let inMultiLineComment = false;
37
+ let escapeNext = false;
38
+
39
+ for (let i = 0; i < content.length; i++) {
40
+ const char = content[i];
41
+ const nextChar = content[i + 1];
42
+
43
+ if (escapeNext) {
44
+ result += char;
45
+ escapeNext = false;
46
+ continue;
47
+ }
48
+
49
+ if (char === '\\' && inString) {
50
+ result += char;
51
+ escapeNext = true;
52
+ continue;
53
+ }
54
+
55
+ if (inString) {
56
+ if (char === '"') {
57
+ inString = false;
58
+ }
59
+ result += char;
60
+ continue;
61
+ }
62
+
63
+ if (inSingleLineComment) {
64
+ if (char === '\n') {
65
+ inSingleLineComment = false;
66
+ result += char;
67
+ }
68
+ continue;
69
+ }
70
+
71
+ if (inMultiLineComment) {
72
+ if (char === '*' && nextChar === '/') {
73
+ inMultiLineComment = false;
74
+ i++; // Skip the '/'
75
+ }
76
+ continue;
77
+ }
78
+
79
+ if (char === '"') {
80
+ inString = true;
81
+ result += char;
82
+ continue;
83
+ }
84
+
85
+ if (char === '/' && nextChar === '/') {
86
+ inSingleLineComment = true;
87
+ i++; // Skip the second '/'
88
+ continue;
89
+ }
90
+
91
+ if (char === '/' && nextChar === '*') {
92
+ inMultiLineComment = true;
93
+ i++; // Skip the '*'
94
+ continue;
95
+ }
96
+
97
+ result += char;
98
+ }
99
+
100
+ return result;
101
+ }
102
+
103
+ /**
104
+ * Stringify an object to JSON format with optional schema
105
+ * @param obj - The object to stringify
106
+ * @param schema - Optional schema URL to include
107
+ * @param indent - Indentation spaces (default: 2)
108
+ * @returns The formatted JSON string
109
+ */
110
+ export function stringifyJSONC(obj: Record<string, unknown>, schema?: string, indent = 2): string {
111
+ const config = { ...obj };
112
+
113
+ // Add schema if provided and not already present
114
+ if (schema && !config.$schema) {
115
+ config.$schema = schema;
116
+ }
117
+
118
+ const json = JSON.stringify(config, null, indent);
119
+
120
+ // Add helpful comments for MCP configuration
121
+ if (config.mcp && Object.keys(config.mcp).length > 0) {
122
+ return json.replace(
123
+ /(\s*)"mcp": {/,
124
+ `$1// MCP (Model Context Protocol) server configuration
125
+ $1// See https://modelcontextprotocol.io for more information
126
+ $1"mcp": {`
127
+ );
128
+ }
129
+
130
+ return json;
131
+ }
132
+
133
+ /**
134
+ * Read and parse a JSONC file
135
+ * @param filePath - Path to the JSONC file
136
+ * @returns The parsed object
137
+ */
138
+ export async function readJSONCFile(filePath: string): Promise<any> {
139
+ const content = await readFile(filePath, 'utf8');
140
+ return parseJSONC(content);
141
+ }
142
+
143
+ /**
144
+ * Write an object to a JSONC file
145
+ * @param filePath - Path to the JSONC file
146
+ * @param obj - The object to write
147
+ * @param schema - Optional schema URL
148
+ * @param indent - Indentation spaces
149
+ */
150
+ export async function writeJSONCFile(
151
+ filePath: string,
152
+ obj: Record<string, unknown>,
153
+ schema?: string,
154
+ indent = 2
155
+ ): Promise<void> {
156
+ const content = stringifyJSONC(obj, schema, indent);
157
+ await writeFile(filePath, content, 'utf8');
158
+ }
@@ -0,0 +1,396 @@
1
+ /**
2
+ * Centralized logging utility for Sylphx Flow
3
+ * Provides structured logging with different levels and output formats
4
+ */
5
+
6
+ import { randomUUID } from 'node:crypto';
7
+ import chalk from 'chalk';
8
+
9
+ export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
10
+
11
+ export interface LogEntry {
12
+ id: string;
13
+ timestamp: string;
14
+ level: LogLevel;
15
+ message: string;
16
+ context?: Record<string, unknown>;
17
+ error?: {
18
+ name: string;
19
+ message: string;
20
+ stack?: string;
21
+ code?: string;
22
+ };
23
+ module?: string;
24
+ function?: string;
25
+ }
26
+
27
+ export interface LoggerConfig {
28
+ level: LogLevel;
29
+ format: 'json' | 'pretty' | 'simple';
30
+ includeTimestamp: boolean;
31
+ includeContext: boolean;
32
+ colors: boolean;
33
+ module?: string;
34
+ }
35
+
36
+ const LEVEL_PRIORITY: Record<LogLevel, number> = {
37
+ debug: 0,
38
+ info: 1,
39
+ warn: 2,
40
+ error: 3,
41
+ };
42
+
43
+ const LEVEL_COLORS: Record<LogLevel, (text: string) => string> = {
44
+ debug: chalk.gray,
45
+ info: chalk.blue,
46
+ warn: chalk.yellow,
47
+ error: chalk.red,
48
+ };
49
+
50
+ const LEVEL_SYMBOLS: Record<LogLevel, string> = {
51
+ debug: '🔍',
52
+ info: 'ℹ',
53
+ warn: '⚠',
54
+ error: '✗',
55
+ };
56
+
57
+ /**
58
+ * Logger interface for dependency injection and testing
59
+ */
60
+ export interface Logger {
61
+ child(context: Record<string, unknown>): Logger;
62
+ module(moduleName: string): Logger;
63
+ setLevel(level: LogLevel): void;
64
+ updateConfig(config: Partial<LoggerConfig>): void;
65
+ debug(message: string, context?: Record<string, unknown>): void;
66
+ info(message: string, context?: Record<string, unknown>): void;
67
+ warn(message: string, context?: Record<string, unknown>): void;
68
+ error(message: string, error?: Error, context?: Record<string, unknown>): void;
69
+ time<T>(fn: () => Promise<T>, label: string, context?: Record<string, unknown>): Promise<T>;
70
+ timeSync<T>(fn: () => T, label: string, context?: Record<string, unknown>): T;
71
+ }
72
+
73
+ /**
74
+ * Internal state for logger instance
75
+ */
76
+ interface LoggerState {
77
+ config: LoggerConfig;
78
+ context?: Record<string, unknown>;
79
+ }
80
+
81
+ /**
82
+ * Options for creating a logger instance
83
+ */
84
+ interface CreateLoggerOptions {
85
+ config?: Partial<LoggerConfig>;
86
+ context?: Record<string, unknown>;
87
+ }
88
+
89
+ /**
90
+ * Create a logger instance with the specified configuration and context
91
+ */
92
+ export function createLogger(options: Partial<LoggerConfig> | CreateLoggerOptions = {}): Logger {
93
+ // Handle both old style (config object) and new style (options with config and context)
94
+ const isOptionsStyle = 'config' in options || 'context' in options;
95
+ const config = isOptionsStyle
96
+ ? (options as CreateLoggerOptions).config || {}
97
+ : (options as Partial<LoggerConfig>);
98
+ const initialContext = isOptionsStyle ? (options as CreateLoggerOptions).context : undefined;
99
+
100
+ const state: LoggerState = {
101
+ config: {
102
+ level: 'info',
103
+ format: 'pretty',
104
+ includeTimestamp: true,
105
+ includeContext: true,
106
+ colors: true,
107
+ ...config,
108
+ },
109
+ context: initialContext,
110
+ };
111
+
112
+ /**
113
+ * Check if a log level should be output
114
+ */
115
+ const shouldLog = (level: LogLevel): boolean => {
116
+ return LEVEL_PRIORITY[level] >= LEVEL_PRIORITY[state.config.level];
117
+ };
118
+
119
+ /**
120
+ * Create a log entry
121
+ */
122
+ const createLogEntry = (
123
+ level: LogLevel,
124
+ message: string,
125
+ error?: Error,
126
+ additionalContext?: Record<string, unknown>
127
+ ): LogEntry => {
128
+ const entry: LogEntry = {
129
+ id: randomUUID(),
130
+ timestamp: new Date().toISOString(),
131
+ level,
132
+ message,
133
+ module: state.context?.module,
134
+ function: state.context?.function,
135
+ };
136
+
137
+ // Merge contexts
138
+ if (state.config.includeContext) {
139
+ entry.context = { ...state.context, ...additionalContext };
140
+ }
141
+
142
+ // Add error information if provided
143
+ if (error) {
144
+ entry.error = {
145
+ name: error.name,
146
+ message: error.message,
147
+ stack: error.stack,
148
+ };
149
+
150
+ // Add error code if it's a CLIError
151
+ if ('code' in error && typeof error.code === 'string') {
152
+ entry.error.code = error.code;
153
+ }
154
+ }
155
+
156
+ return entry;
157
+ };
158
+
159
+ /**
160
+ * Format a log entry for output
161
+ */
162
+ const formatEntry = (entry: LogEntry): string => {
163
+ switch (state.config.format) {
164
+ case 'json':
165
+ return JSON.stringify(entry);
166
+
167
+ case 'simple': {
168
+ const levelStr = entry.level.toUpperCase().padEnd(5);
169
+ const moduleStr = entry.module ? `[${entry.module}] ` : '';
170
+ return `${levelStr} ${moduleStr}${entry.message}`;
171
+ }
172
+ default: {
173
+ const parts: string[] = [];
174
+
175
+ // Timestamp
176
+ if (state.config.includeTimestamp) {
177
+ const time = new Date(entry.timestamp).toLocaleTimeString();
178
+ parts.push(chalk.gray(time));
179
+ }
180
+
181
+ // Level symbol and name
182
+ const colorFn = state.config.colors ? LEVEL_COLORS[entry.level] : (s: string) => s;
183
+ parts.push(
184
+ `${colorFn(LEVEL_SYMBOLS[entry.level])} ${colorFn(entry.level.toUpperCase().padEnd(5))}`
185
+ );
186
+
187
+ // Module
188
+ if (entry.module) {
189
+ parts.push(chalk.cyan(`[${entry.module}]`));
190
+ }
191
+
192
+ // Function
193
+ if (entry.function) {
194
+ parts.push(chalk.gray(`${entry.function}()`));
195
+ }
196
+
197
+ // Message
198
+ parts.push(entry.message);
199
+
200
+ let result = parts.join(' ');
201
+
202
+ // Context
203
+ if (entry.context && Object.keys(entry.context).length > 0) {
204
+ const contextStr = JSON.stringify(entry.context, null, 2);
205
+ result += `\n${chalk.gray(' Context: ')}${chalk.gray(contextStr)}`;
206
+ }
207
+
208
+ // Error details
209
+ if (entry.error) {
210
+ result += `\n${chalk.red(' Error: ')}${chalk.red(entry.error.message)}`;
211
+ if (entry.error.code) {
212
+ result += `\n${chalk.red(' Code: ')}${chalk.red(entry.error.code)}`;
213
+ }
214
+ if (entry.error.stack) {
215
+ result += `\n${chalk.gray(entry.error.stack)}`;
216
+ }
217
+ }
218
+
219
+ return result;
220
+ }
221
+ }
222
+ };
223
+
224
+ /**
225
+ * Internal logging method
226
+ */
227
+ const logInternal = (
228
+ level: LogLevel,
229
+ message: string,
230
+ error?: Error,
231
+ additionalContext?: Record<string, any>
232
+ ): void => {
233
+ if (!shouldLog(level)) {
234
+ return;
235
+ }
236
+
237
+ const entry = createLogEntry(level, message, error, additionalContext);
238
+ const formatted = formatEntry(entry);
239
+
240
+ // Output to appropriate stream
241
+ if (level === 'error') {
242
+ console.error(formatted);
243
+ } else {
244
+ console.log(formatted);
245
+ }
246
+ };
247
+
248
+ /**
249
+ * Create a child logger with additional context
250
+ */
251
+ const child = (context: Record<string, unknown>): Logger => {
252
+ return createLogger({
253
+ config: state.config,
254
+ context: { ...state.context, ...context },
255
+ });
256
+ };
257
+
258
+ /**
259
+ * Create a logger for a specific module
260
+ */
261
+ const module = (moduleName: string): Logger => {
262
+ return child({ module: moduleName });
263
+ };
264
+
265
+ /**
266
+ * Set the log level
267
+ */
268
+ const setLevel = (level: LogLevel): void => {
269
+ state.config.level = level;
270
+ };
271
+
272
+ /**
273
+ * Update logger configuration
274
+ */
275
+ const updateConfig = (config: Partial<LoggerConfig>): void => {
276
+ state.config = { ...state.config, ...config };
277
+ };
278
+
279
+ /**
280
+ * Debug level logging
281
+ */
282
+ const debug = (message: string, context?: Record<string, unknown>): void => {
283
+ logInternal('debug', message, undefined, context);
284
+ };
285
+
286
+ /**
287
+ * Info level logging
288
+ */
289
+ const info = (message: string, context?: Record<string, unknown>): void => {
290
+ logInternal('info', message, undefined, context);
291
+ };
292
+
293
+ /**
294
+ * Warning level logging
295
+ */
296
+ const warn = (message: string, context?: Record<string, unknown>): void => {
297
+ logInternal('warn', message, undefined, context);
298
+ };
299
+
300
+ /**
301
+ * Error level logging
302
+ */
303
+ const error = (message: string, errorObj?: Error, context?: Record<string, unknown>): void => {
304
+ logInternal('error', message, errorObj, context);
305
+ };
306
+
307
+ /**
308
+ * Log function execution with timing
309
+ */
310
+ const time = async <T>(
311
+ fn: () => Promise<T>,
312
+ label: string,
313
+ context?: Record<string, unknown>
314
+ ): Promise<T> => {
315
+ const start = Date.now();
316
+ debug(`Starting ${label}`, context);
317
+
318
+ try {
319
+ const result = await fn();
320
+ const duration = Date.now() - start;
321
+ info(`Completed ${label}`, { ...context, duration: `${duration}ms` });
322
+ return result;
323
+ } catch (caughtError) {
324
+ const duration = Date.now() - start;
325
+ error(`Failed ${label}`, caughtError as Error, { ...context, duration: `${duration}ms` });
326
+ throw caughtError;
327
+ }
328
+ };
329
+
330
+ /**
331
+ * Log function execution (sync) with timing
332
+ */
333
+ const timeSync = <T>(fn: () => T, label: string, context?: Record<string, unknown>): T => {
334
+ const start = Date.now();
335
+ debug(`Starting ${label}`, context);
336
+
337
+ try {
338
+ const result = fn();
339
+ const duration = Date.now() - start;
340
+ info(`Completed ${label}`, { ...context, duration: `${duration}ms` });
341
+ return result;
342
+ } catch (caughtError) {
343
+ const duration = Date.now() - start;
344
+ error(`Failed ${label}`, caughtError as Error, { ...context, duration: `${duration}ms` });
345
+ throw caughtError;
346
+ }
347
+ };
348
+
349
+ return {
350
+ child,
351
+ module,
352
+ setLevel,
353
+ updateConfig,
354
+ debug,
355
+ info,
356
+ warn,
357
+ error,
358
+ time,
359
+ timeSync,
360
+ };
361
+ }
362
+
363
+ // Default logger instance
364
+ export const logger = createLogger();
365
+
366
+ // Environment-based configuration
367
+ if (process.env.NODE_ENV === 'production') {
368
+ logger.updateConfig({
369
+ level: 'info',
370
+ format: 'json',
371
+ colors: false,
372
+ });
373
+ } else if (process.env.DEBUG) {
374
+ logger.updateConfig({
375
+ level: 'debug',
376
+ });
377
+ }
378
+
379
+ // Export convenience functions
380
+ export const log = {
381
+ debug: (message: string, context?: Record<string, unknown>) => logger.debug(message, context),
382
+ info: (message: string, context?: Record<string, unknown>) => logger.info(message, context),
383
+ warn: (message: string, context?: Record<string, unknown>) => logger.warn(message, context),
384
+ error: (message: string, error?: Error, context?: Record<string, unknown>) =>
385
+ logger.error(message, error, context),
386
+ time: <T>(fn: () => Promise<T>, label: string, context?: Record<string, unknown>) =>
387
+ logger.time(fn, label, context),
388
+ timeSync: <T>(fn: () => T, label: string, context?: Record<string, unknown>) =>
389
+ logger.timeSync(fn, label, context),
390
+ child: (context: Record<string, unknown>) => logger.child(context),
391
+ module: (moduleName: string) => logger.module(moduleName),
392
+ setLevel: (level: LogLevel) => logger.setLevel(level),
393
+ updateConfig: (config: Partial<LoggerConfig>) => logger.updateConfig(config),
394
+ };
395
+
396
+ export default logger;