@kb-labs/core-sys 1.0.0

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/README.md ADDED
@@ -0,0 +1,109 @@
1
+ # @kb-labs/core-sys
2
+
3
+ > **Core system utilities for KB Labs, including output utilities, file system operations, and repository utilities.** Provides foundational system-level functionality used across all KB Labs packages.
4
+
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
6
+ [![Node.js](https://img.shields.io/badge/Node.js-18.18.0+-green.svg)](https://nodejs.org/)
7
+ [![pnpm](https://img.shields.io/badge/pnpm-9.0.0+-orange.svg)](https://pnpm.io/)
8
+
9
+ ## 🎯 Vision & Purpose
10
+
11
+ **@kb-labs/core-sys** provides core system utilities for KB Labs packages. It includes output utilities, file system operations, repository utilities, and type definitions. This package is the foundation for system-level operations across the KB Labs ecosystem.
12
+
13
+ ## 🏗️ Architecture
14
+
15
+ ### Core Components
16
+
17
+ #### Output System
18
+
19
+ - **Purpose**: Unified output interface for CLI/runtime layers
20
+ - **Responsibilities**: User-facing messages, formatting, verbosity handling
21
+ - **Dependencies**: None (pure TypeScript)
22
+
23
+ #### File System Utilities
24
+
25
+ - **Purpose**: File system operations and path resolution
26
+ - **Responsibilities**: Absolute path resolution, file operations
27
+ - **Dependencies**: `node:fs`, `node:path`
28
+
29
+ #### Repository Utilities
30
+
31
+ - **Purpose**: Git repository operations
32
+ - **Responsibilities**: Repository root detection
33
+ - **Dependencies**: `node:fs`, `node:path`
34
+
35
+ ### Design Patterns
36
+
37
+ - **Factory Pattern**: Output creation
38
+ - **Strategy Pattern**: Different output/verbosity strategies
39
+
40
+ ### Data Flow
41
+
42
+ ```
43
+ createOutput(config)
44
+
45
+ ├──► Resolve mode/verbosity
46
+ ├──► Prepare output helpers
47
+ └──► return Output
48
+ ```
49
+
50
+ ## 🚀 Quick Start
51
+
52
+ ### Installation
53
+
54
+ ```bash
55
+ pnpm add @kb-labs/core-sys
56
+ ```
57
+
58
+ ### Basic Usage
59
+
60
+ ```typescript
61
+ import { createOutput } from '@kb-labs/core-sys/output';
62
+ import { toAbsolute } from '@kb-labs/core-sys/fs';
63
+ import { findRepoRoot } from '@kb-labs/core-sys/repo';
64
+
65
+ // Output
66
+ const out = createOutput({ verbosity: 'normal' });
67
+ out.success('Hello world');
68
+
69
+ // File System
70
+ const absPath = toAbsolute('/base', './relative');
71
+
72
+ // Repository
73
+ const repoRoot = await findRepoRoot();
74
+ ```
75
+
76
+ ## ✨ Features
77
+
78
+ ### Output
79
+
80
+ - **Unified Interface**: One Output API for CLI/runtime surfaces
81
+ - **Verbosity Modes**: quiet, normal, verbose, debug, inspect
82
+ - **Structured JSON Output**: optional machine-readable output mode
83
+
84
+ ### File System
85
+
86
+ - **Path Resolution**: Convert relative to absolute paths
87
+ - **File Operations**: File system utilities
88
+
89
+ ### Repository
90
+
91
+ - **Repository Detection**: Find Git repository root
92
+
93
+ ## 🔧 Configuration
94
+
95
+ ### Output Configuration
96
+
97
+ Configure output via verbosity/mode flags and runtime settings.
98
+
99
+ ### Environment Variables
100
+
101
+ - `KB_LOG_LEVEL`: Used by runtime/platform logger adapters (outside `core-sys`)
102
+
103
+ ## 🤝 Contributing
104
+
105
+ See [CONTRIBUTING.md](../../CONTRIBUTING.md) for development guidelines.
106
+
107
+ ## 📄 License
108
+
109
+ KB Public License v1.1 © KB Labs
package/dist/index.cjs ADDED
@@ -0,0 +1,356 @@
1
+ 'use strict';
2
+
3
+ var sharedCliUi = require('@kb-labs/shared-cli-ui');
4
+ var table = require('@kb-labs/shared-cli-ui/table');
5
+ var path2 = require('path');
6
+ var fs = require('fs');
7
+
8
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
9
+
10
+ var path2__default = /*#__PURE__*/_interopDefault(path2);
11
+
12
+ // src/output/output-impl.ts
13
+ var OutputImpl = class {
14
+ constructor(config) {
15
+ this.config = config;
16
+ }
17
+ // Getters
18
+ get mode() {
19
+ return this.config.mode;
20
+ }
21
+ get verbosity() {
22
+ return this.config.verbosity;
23
+ }
24
+ get isQuiet() {
25
+ return this.config.verbosity === "quiet";
26
+ }
27
+ get isVerbose() {
28
+ return ["verbose", "debug", "inspect"].includes(this.config.verbosity);
29
+ }
30
+ get isDebug() {
31
+ return ["debug", "inspect"].includes(this.config.verbosity);
32
+ }
33
+ get isJSON() {
34
+ return this.config.json;
35
+ }
36
+ get isAIFormat() {
37
+ return this.config.format === "ai";
38
+ }
39
+ get ui() {
40
+ return {
41
+ box: sharedCliUi.box,
42
+ sideBox: sharedCliUi.sideBorderBox,
43
+ table: (rows, headers) => {
44
+ if (headers && headers.length > 0) {
45
+ return table.formatTable(
46
+ headers.map((h) => ({
47
+ header: h,
48
+ width: void 0,
49
+ align: "left"
50
+ })),
51
+ rows.map((r) => r.map(String)),
52
+ { header: true }
53
+ );
54
+ }
55
+ return sharedCliUi.table(rows.map((r) => r.map(String)));
56
+ },
57
+ keyValue: sharedCliUi.keyValue,
58
+ spinner: (text, jsonMode) => sharedCliUi.createSpinner(text, jsonMode || this.isJSON),
59
+ colors: {
60
+ info: sharedCliUi.safeColors.info,
61
+ warn: sharedCliUi.safeColors.warning,
62
+ error: sharedCliUi.safeColors.error,
63
+ success: sharedCliUi.safeColors.success,
64
+ muted: sharedCliUi.safeColors.muted,
65
+ bold: sharedCliUi.safeColors.bold,
66
+ primary: sharedCliUi.safeColors.primary,
67
+ accent: sharedCliUi.safeColors.accent
68
+ },
69
+ symbols: {
70
+ success: sharedCliUi.safeSymbols.success,
71
+ error: sharedCliUi.safeSymbols.error,
72
+ warning: sharedCliUi.safeSymbols.warning,
73
+ info: sharedCliUi.safeSymbols.info,
74
+ bullet: sharedCliUi.safeSymbols.bullet
75
+ }
76
+ };
77
+ }
78
+ // Main methods
79
+ success(message, data) {
80
+ if (this.isJSON) {
81
+ this.json({ ok: true, message, ...data });
82
+ return;
83
+ }
84
+ if (this.isQuiet) {
85
+ return;
86
+ }
87
+ const output = `${sharedCliUi.safeSymbols.success} ${message}`;
88
+ console.log(sharedCliUi.safeColors.success(output));
89
+ this.config.logger.info(message, data);
90
+ }
91
+ error(error, options) {
92
+ const message = error instanceof Error ? error.message : error;
93
+ const stack = error instanceof Error ? error.stack : void 0;
94
+ if (this.isJSON) {
95
+ this.json({
96
+ ok: false,
97
+ error: {
98
+ message,
99
+ code: options?.code,
100
+ context: options?.context,
101
+ suggestions: options?.suggestions
102
+ }
103
+ });
104
+ return;
105
+ }
106
+ const lines = [];
107
+ if (options?.title) {
108
+ lines.push(
109
+ sharedCliUi.safeColors.error(`${sharedCliUi.safeSymbols.error} ${options.title}`)
110
+ );
111
+ }
112
+ lines.push(sharedCliUi.safeColors.error(message));
113
+ if (options?.code) {
114
+ lines.push(sharedCliUi.safeColors.muted(`Code: ${options.code}`));
115
+ }
116
+ if (options?.context && Object.keys(options.context).length > 0) {
117
+ lines.push("");
118
+ lines.push(sharedCliUi.safeColors.bold("Context:"));
119
+ lines.push(
120
+ ...sharedCliUi.keyValue(
121
+ Object.fromEntries(
122
+ Object.entries(options.context).map(([k, v]) => [
123
+ k,
124
+ String(v)
125
+ ])
126
+ )
127
+ )
128
+ );
129
+ }
130
+ if (options?.suggestions && options.suggestions.length > 0) {
131
+ lines.push("");
132
+ lines.push(sharedCliUi.safeColors.bold("Suggestions:"));
133
+ options.suggestions.forEach((s) => {
134
+ lines.push(` ${sharedCliUi.safeSymbols.bullet} ${s}`);
135
+ });
136
+ }
137
+ if (options?.docs) {
138
+ lines.push("");
139
+ lines.push(sharedCliUi.safeColors.info(`Documentation: ${options.docs}`));
140
+ }
141
+ const boxed = sharedCliUi.box("Error", lines);
142
+ console.error(boxed);
143
+ const errorMeta = {
144
+ code: options?.code,
145
+ context: options?.context
146
+ };
147
+ if (stack) {
148
+ errorMeta.stack = stack;
149
+ }
150
+ if (error instanceof Error) {
151
+ this.config.logger.error(message, error);
152
+ } else {
153
+ this.config.logger.error(message, void 0, errorMeta);
154
+ }
155
+ }
156
+ warn(message, hint) {
157
+ if (this.isQuiet) {
158
+ return;
159
+ }
160
+ const output = `${sharedCliUi.safeSymbols.warning} ${message}`;
161
+ console.warn(sharedCliUi.safeColors.warning(output));
162
+ if (hint) {
163
+ console.warn(sharedCliUi.safeColors.muted(` ${hint}`));
164
+ }
165
+ this.config.logger.warn(message, { hint });
166
+ }
167
+ progress(stage, details) {
168
+ if (this.isQuiet) {
169
+ return;
170
+ }
171
+ let output = stage;
172
+ if (details?.current !== void 0 && details?.total !== void 0) {
173
+ const percent = Math.round(
174
+ details.current / details.total * 100
175
+ );
176
+ output += ` (${details.current}/${details.total}, ${percent}%)`;
177
+ }
178
+ if (details?.message) {
179
+ output += ` - ${details.message}`;
180
+ }
181
+ console.log(sharedCliUi.safeColors.info(output));
182
+ this.config.logger.info(output, details);
183
+ }
184
+ spinner(text) {
185
+ return sharedCliUi.createSpinner(text, this.isJSON || this.isQuiet);
186
+ }
187
+ info(message, meta) {
188
+ if (!this.isVerbose) {
189
+ return;
190
+ }
191
+ console.log(message);
192
+ this.config.logger.info(message, meta);
193
+ }
194
+ debug(message, meta) {
195
+ if (!this.isDebug) {
196
+ return;
197
+ }
198
+ console.log(sharedCliUi.safeColors.muted(message));
199
+ this.config.logger.debug(message, meta);
200
+ }
201
+ trace(message, meta) {
202
+ if (this.verbosity !== "inspect") {
203
+ return;
204
+ }
205
+ console.log(sharedCliUi.safeColors.muted(`[TRACE] ${message}`));
206
+ this.config.logger.debug(message, { ...meta, trace: true });
207
+ }
208
+ json(data) {
209
+ console.log(JSON.stringify(data, null, 2));
210
+ }
211
+ write(text) {
212
+ if (this.isQuiet) {
213
+ return;
214
+ }
215
+ console.log(text);
216
+ }
217
+ group(name) {
218
+ if (this.isDebug) {
219
+ console.group(name);
220
+ }
221
+ }
222
+ groupEnd() {
223
+ if (this.isDebug) {
224
+ console.groupEnd();
225
+ }
226
+ }
227
+ // Internal method для форматированного вывода через ConsoleSink
228
+ // Используется только для UI вывода, не для записи в файлы
229
+ logToConsoleSink(level, msg, meta) {
230
+ const record = {
231
+ time: (/* @__PURE__ */ new Date()).toISOString(),
232
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
233
+ level,
234
+ category: this.config.category,
235
+ msg,
236
+ meta: { ...this.config.context, ...meta }
237
+ };
238
+ for (const sink of this.config.sinks) {
239
+ try {
240
+ void sink.handle(record);
241
+ } catch (err) {
242
+ console.error("Sink error:", err);
243
+ }
244
+ }
245
+ }
246
+ };
247
+
248
+ // src/output/factory.ts
249
+ var ConsoleLogger = class _ConsoleLogger {
250
+ constructor(level, bindings = {}) {
251
+ this.level = level;
252
+ this.bindings = bindings;
253
+ }
254
+ canLog(target) {
255
+ const rank = {
256
+ silent: 0,
257
+ error: 1,
258
+ warn: 2,
259
+ info: 3,
260
+ debug: 4,
261
+ trace: 5
262
+ };
263
+ return rank[target] <= rank[this.level];
264
+ }
265
+ withMeta(meta) {
266
+ const merged = { ...this.bindings, ...meta ?? {} };
267
+ return Object.keys(merged).length > 0 ? ` ${JSON.stringify(merged)}` : "";
268
+ }
269
+ info(message, meta) {
270
+ if (this.canLog("info")) {
271
+ console.log(`[INFO] ${message}${this.withMeta(meta)}`);
272
+ }
273
+ }
274
+ warn(message, meta) {
275
+ if (this.canLog("warn")) {
276
+ console.warn(`[WARN] ${message}${this.withMeta(meta)}`);
277
+ }
278
+ }
279
+ error(message, error, meta) {
280
+ if (this.canLog("error")) {
281
+ const payload = error ? { ...meta, error: { message: error.message, stack: error.stack } } : meta;
282
+ console.error(`[ERROR] ${message}${this.withMeta(payload)}`);
283
+ }
284
+ }
285
+ debug(message, meta) {
286
+ if (this.canLog("debug")) {
287
+ console.debug(`[DEBUG] ${message}${this.withMeta(meta)}`);
288
+ }
289
+ }
290
+ child(bindings) {
291
+ return new _ConsoleLogger(this.level, { ...this.bindings, ...bindings });
292
+ }
293
+ };
294
+ function createOutput(config = {}) {
295
+ const mode = config.mode || detectMode();
296
+ const verbosity = config.verbosity || "normal";
297
+ const format = config.format || (config.json ? "ai" : "human");
298
+ const sinks = config.sinks || [];
299
+ const loggerLevel = verbosity === "inspect" ? "trace" : verbosity === "debug" ? "debug" : verbosity === "verbose" ? "info" : verbosity === "quiet" ? "silent" : "info";
300
+ const logger = new ConsoleLogger(loggerLevel, {
301
+ category: config.category || "output",
302
+ ...config.context || {}
303
+ });
304
+ return new OutputImpl({
305
+ mode,
306
+ verbosity,
307
+ format,
308
+ json: config.json || false,
309
+ sinks,
310
+ // Только ConsoleSink для UI
311
+ logger,
312
+ // Глобальный logger для записи в файлы
313
+ category: config.category,
314
+ context: config.context
315
+ });
316
+ }
317
+ function detectMode() {
318
+ if (process.env.CI === "true") {
319
+ return "ci";
320
+ }
321
+ if (process.stdout.isTTY) {
322
+ return "tty";
323
+ }
324
+ return "pipe";
325
+ }
326
+ function toAbsolute(baseDir, maybeRelative) {
327
+ if (!maybeRelative) {
328
+ return baseDir;
329
+ }
330
+ return path2__default.default.isAbsolute(maybeRelative) ? maybeRelative : path2__default.default.join(baseDir, maybeRelative);
331
+ }
332
+ async function findRepoRoot(startDir = process.cwd()) {
333
+ const markersPriority = ["pnpm-workspace.yaml", ".git", "package.json"];
334
+ for (const marker of markersPriority) {
335
+ let dir = path2__default.default.resolve(startDir);
336
+ while (true) {
337
+ try {
338
+ await fs.promises.access(path2__default.default.join(dir, marker));
339
+ return dir;
340
+ } catch {
341
+ }
342
+ const parent = path2__default.default.dirname(dir);
343
+ if (parent === dir) {
344
+ break;
345
+ }
346
+ dir = parent;
347
+ }
348
+ }
349
+ return path2__default.default.resolve(startDir);
350
+ }
351
+
352
+ exports.createOutput = createOutput;
353
+ exports.findRepoRoot = findRepoRoot;
354
+ exports.toAbsolute = toAbsolute;
355
+ //# sourceMappingURL=index.cjs.map
356
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/output/output-impl.ts","../src/output/factory.ts","../src/fs/fs.ts","../src/repo/repo.ts"],"names":["box","sideBorderBox","formatTable","table","keyValue","createSpinner","safeColors","safeSymbols","path","fsp"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * @module @kb-labs/core-sys/output/output-impl\n * Output implementation\n */\n\nimport type {\n Output,\n OutputMode,\n VerbosityLevel,\n DebugFormat,\n OutputLogSink,\n OutputLogRecord,\n OutputLogger,\n ErrorOptions,\n ProgressDetails,\n UIUtilities,\n Spinner,\n} from \"./types\";\nimport {\n box,\n keyValue,\n table,\n createSpinner,\n safeColors,\n safeSymbols,\n sideBorderBox,\n} from \"@kb-labs/shared-cli-ui\";\nimport { formatTable } from \"@kb-labs/shared-cli-ui/table\";\n\nexport class OutputImpl implements Output {\n constructor(\n private config: {\n mode: OutputMode;\n verbosity: VerbosityLevel;\n format: DebugFormat;\n json: boolean;\n sinks: OutputLogSink[]; // Только для форматированного вывода (ConsoleSink)\n logger: OutputLogger; // Глобальный logger для записи в файлы\n category?: string;\n context?: Record<string, unknown>;\n }\n ) {}\n\n // Getters\n get mode(): OutputMode {\n return this.config.mode;\n }\n\n get verbosity(): VerbosityLevel {\n return this.config.verbosity;\n }\n\n get isQuiet(): boolean {\n return this.config.verbosity === \"quiet\";\n }\n\n get isVerbose(): boolean {\n return [\"verbose\", \"debug\", \"inspect\"].includes(this.config.verbosity);\n }\n\n get isDebug(): boolean {\n return [\"debug\", \"inspect\"].includes(this.config.verbosity);\n }\n\n get isJSON(): boolean {\n return this.config.json;\n }\n\n get isAIFormat(): boolean {\n return this.config.format === \"ai\";\n }\n\n get ui(): UIUtilities {\n return {\n box,\n sideBox: sideBorderBox,\n table: (rows, headers) => {\n if (headers && headers.length > 0) {\n return formatTable(\n headers.map((h) => ({\n header: h,\n width: undefined,\n align: \"left\" as const,\n })),\n rows.map((r) => r.map(String)),\n { header: true }\n );\n }\n return table(rows.map((r) => r.map(String)));\n },\n keyValue,\n spinner: (text: string, jsonMode?: boolean) =>\n createSpinner(text, jsonMode || this.isJSON),\n colors: {\n info: safeColors.info,\n warn: safeColors.warning,\n error: safeColors.error,\n success: safeColors.success,\n muted: safeColors.muted,\n bold: safeColors.bold,\n primary: safeColors.primary,\n accent: safeColors.accent,\n },\n symbols: {\n success: safeSymbols.success,\n error: safeSymbols.error,\n warning: safeSymbols.warning,\n info: safeSymbols.info,\n bullet: safeSymbols.bullet,\n },\n };\n }\n\n // Main methods\n success(message: string, data?: Record<string, unknown>): void {\n if (this.isJSON) {\n this.json({ ok: true, message, ...data });\n return;\n }\n\n if (this.isQuiet) {return;}\n\n const output = `${safeSymbols.success} ${message}`;\n console.log(safeColors.success(output));\n // Использовать глобальный logger для записи в файлы\n this.config.logger.info(message, data);\n }\n\n error(error: Error | string, options?: ErrorOptions): void {\n const message = error instanceof Error ? error.message : error;\n const stack = error instanceof Error ? error.stack : undefined;\n\n if (this.isJSON) {\n this.json({\n ok: false,\n error: {\n message,\n code: options?.code,\n context: options?.context,\n suggestions: options?.suggestions,\n },\n });\n return;\n }\n\n // Красивое форматирование ошибки\n const lines: string[] = [];\n\n if (options?.title) {\n lines.push(\n safeColors.error(`${safeSymbols.error} ${options.title}`)\n );\n }\n\n lines.push(safeColors.error(message));\n\n if (options?.code) {\n lines.push(safeColors.muted(`Code: ${options.code}`));\n }\n\n if (options?.context && Object.keys(options.context).length > 0) {\n lines.push(\"\");\n lines.push(safeColors.bold(\"Context:\"));\n lines.push(\n ...keyValue(\n Object.fromEntries(\n Object.entries(options.context).map(([k, v]) => [\n k,\n String(v),\n ])\n )\n )\n );\n }\n\n if (options?.suggestions && options.suggestions.length > 0) {\n lines.push(\"\");\n lines.push(safeColors.bold(\"Suggestions:\"));\n options.suggestions.forEach((s) => {\n lines.push(` ${safeSymbols.bullet} ${s}`);\n });\n }\n\n if (options?.docs) {\n lines.push(\"\");\n lines.push(safeColors.info(`Documentation: ${options.docs}`));\n }\n\n const boxed = box(\"Error\", lines);\n console.error(boxed);\n\n // Использовать глобальный logger для записи в файлы\n const errorMeta: Record<string, unknown> = {\n code: options?.code,\n context: options?.context,\n };\n if (stack) {\n errorMeta.stack = stack;\n }\n if (error instanceof Error) {\n this.config.logger.error(message, error);\n } else {\n this.config.logger.error(message, undefined, errorMeta);\n }\n }\n\n warn(message: string, hint?: string): void {\n if (this.isQuiet) {return;}\n\n const output = `${safeSymbols.warning} ${message}`;\n console.warn(safeColors.warning(output));\n\n if (hint) {\n console.warn(safeColors.muted(` ${hint}`));\n }\n\n // Использовать глобальный logger для записи в файлы\n this.config.logger.warn(message, { hint });\n }\n\n progress(stage: string, details?: ProgressDetails): void {\n if (this.isQuiet) {return;}\n\n let output = stage;\n if (details?.current !== undefined && details?.total !== undefined) {\n const percent = Math.round(\n (details.current / details.total) * 100\n );\n output += ` (${details.current}/${details.total}, ${percent}%)`;\n }\n\n if (details?.message) {\n output += ` - ${details.message}`;\n }\n\n console.log(safeColors.info(output));\n // Использовать глобальный logger для записи в файлы\n this.config.logger.info(output, details as Record<string, unknown>);\n }\n\n spinner(text: string): Spinner {\n return createSpinner(text, this.isJSON || this.isQuiet);\n }\n\n info(message: string, meta?: Record<string, unknown>): void {\n if (!this.isVerbose) {return;}\n\n console.log(message);\n // Использовать глобальный logger для записи в файлы\n this.config.logger.info(message, meta);\n }\n\n debug(message: string, meta?: Record<string, unknown>): void {\n if (!this.isDebug) {return;}\n\n console.log(safeColors.muted(message));\n // Использовать глобальный logger для записи в файлы\n this.config.logger.debug(message, meta);\n }\n\n trace(message: string, meta?: Record<string, unknown>): void {\n if (this.verbosity !== \"inspect\") {return;}\n\n console.log(safeColors.muted(`[TRACE] ${message}`));\n // Использовать глобальный logger для записи в файлы (trace → debug)\n this.config.logger.debug(message, { ...meta, trace: true } as Record<string, unknown>);\n }\n\n json(data: unknown): void {\n console.log(JSON.stringify(data, null, 2));\n }\n\n write(text: string): void {\n if (this.isQuiet) {return;}\n console.log(text);\n }\n\n group(name: string): void {\n if (this.isDebug) {\n console.group(name);\n }\n }\n\n groupEnd(): void {\n if (this.isDebug) {\n console.groupEnd();\n }\n }\n\n // Internal method для форматированного вывода через ConsoleSink\n // Используется только для UI вывода, не для записи в файлы\n private logToConsoleSink(\n level: OutputLogRecord[\"level\"],\n msg: string,\n meta?: Record<string, unknown>\n ): void {\n const record: OutputLogRecord = {\n time: new Date().toISOString(),\n ts: new Date().toISOString(),\n level,\n category: this.config.category,\n msg,\n meta: { ...this.config.context, ...meta },\n };\n\n // Отправить только в ConsoleSink для форматированного вывода\n // Запись в файлы идет через глобальный logger\n for (const sink of this.config.sinks) {\n try {\n void sink.handle(record);\n } catch (err) {\n // Sink failures should not break execution\n console.error(\"Sink error:\", err);\n }\n }\n }\n}\n","/**\n * @module @kb-labs/core-sys/output/factory\n * Output factory with auto-detection\n */\n\nimport type { Output, OutputMode, VerbosityLevel, DebugFormat, OutputLogSink, OutputLogger } from \"./types\";\nimport { OutputImpl } from \"./output-impl\";\n\ntype LogLevel = \"trace\" | \"debug\" | \"info\" | \"warn\" | \"error\" | \"silent\";\n\nclass ConsoleLogger implements OutputLogger {\n constructor(\n private readonly level: LogLevel,\n private readonly bindings: Record<string, unknown> = {}\n ) {}\n\n private canLog(target: LogLevel): boolean {\n const rank: Record<LogLevel, number> = {\n silent: 0,\n error: 1,\n warn: 2,\n info: 3,\n debug: 4,\n trace: 5,\n };\n return rank[target] <= rank[this.level];\n }\n\n private withMeta(meta?: Record<string, unknown>): string {\n const merged = { ...this.bindings, ...(meta ?? {}) };\n return Object.keys(merged).length > 0 ? ` ${JSON.stringify(merged)}` : \"\";\n }\n\n info(message: string, meta?: Record<string, unknown>): void {\n if (this.canLog(\"info\")) {\n console.log(`[INFO] ${message}${this.withMeta(meta)}`);\n }\n }\n\n warn(message: string, meta?: Record<string, unknown>): void {\n if (this.canLog(\"warn\")) {\n console.warn(`[WARN] ${message}${this.withMeta(meta)}`);\n }\n }\n\n error(message: string, error?: Error, meta?: Record<string, unknown>): void {\n if (this.canLog(\"error\")) {\n const payload = error\n ? { ...meta, error: { message: error.message, stack: error.stack } }\n : meta;\n console.error(`[ERROR] ${message}${this.withMeta(payload)}`);\n }\n }\n\n debug(message: string, meta?: Record<string, unknown>): void {\n if (this.canLog(\"debug\")) {\n console.debug(`[DEBUG] ${message}${this.withMeta(meta)}`);\n }\n }\n\n child(bindings: Record<string, unknown>): OutputLogger {\n return new ConsoleLogger(this.level, { ...this.bindings, ...bindings });\n }\n}\n\nexport interface OutputConfig {\n verbosity?: VerbosityLevel; // Из флагов\n mode?: OutputMode; // Auto-detect или explicit\n format?: DebugFormat; // 'human' | 'ai'\n json?: boolean; // --json флаг\n sinks?: OutputLogSink[]; // Дополнительные sinks\n category?: string; // Категория для логов\n context?: {\n // Контекст команды\n plugin?: string;\n command?: string;\n trace?: string;\n };\n}\n\nexport function createOutput(config: OutputConfig = {}): Output {\n // Auto-detect mode\n const mode: OutputMode = config.mode || detectMode();\n\n // Verbosity из конфига или normal по умолчанию\n const verbosity: VerbosityLevel = config.verbosity || \"normal\";\n\n // Format\n const format: DebugFormat =\n config.format || (config.json ? \"ai\" : \"human\");\n\n // Создать sinks только для форматированного вывода пользователю\n const sinks: OutputLogSink[] = config.sinks || [];\n\n const loggerLevel =\n verbosity === \"inspect\"\n ? \"trace\"\n : verbosity === \"debug\"\n ? \"debug\"\n : verbosity === \"verbose\"\n ? \"info\"\n : verbosity === \"quiet\"\n ? \"silent\"\n : \"info\";\n const logger = new ConsoleLogger(loggerLevel, {\n category: config.category || \"output\",\n ...(config.context || {}),\n });\n\n // Создать Output implementation\n return new OutputImpl({\n mode,\n verbosity,\n format,\n json: config.json || false,\n sinks, // Только ConsoleSink для UI\n logger, // Глобальный logger для записи в файлы\n category: config.category,\n context: config.context,\n });\n}\n\nfunction detectMode(): OutputMode {\n // CI environment\n if (process.env.CI === \"true\") {\n return \"ci\";\n }\n\n // TTY\n if (process.stdout.isTTY) {\n return \"tty\";\n }\n\n // Pipe\n return \"pipe\";\n}\n","/**\n * @module @kb-labs/core/sys/fs\n * Safe path helpers with explicit bases.\n */\n\nimport path from \"node:path\";\n\nexport function toAbsolute(baseDir: string, maybeRelative?: string): string {\n if (!maybeRelative) { return baseDir; }\n return path.isAbsolute(maybeRelative) ? maybeRelative : path.join(baseDir, maybeRelative);\n}","/**\n * @module @kb-labs/core/sys/repo\n * Repository root discovery. Pure infrastructure, no domain keys.\n */\n\nimport path from \"node:path\";\nimport { promises as fsp } from \"node:fs\";\n\n/**\n * Find repository root by searching for markers in priority order.\n * First searches entire tree for pnpm-workspace.yaml (monorepo root),\n * then .git, then package.json as fallback.\n */\nexport async function findRepoRoot(startDir = process.cwd()): Promise<string> {\n const markersPriority = [\"pnpm-workspace.yaml\", \".git\", \"package.json\"];\n\n // Try each marker in priority order, searching entire tree each time\n for (const marker of markersPriority) {\n let dir = path.resolve(startDir);\n while (true) {\n try {\n await fsp.access(path.join(dir, marker));\n return dir; // Found it!\n } catch {\n // Continue searching upward\n }\n\n const parent = path.dirname(dir);\n if (parent === dir) {\n // Reached filesystem root without finding this marker\n break;\n }\n dir = parent;\n }\n }\n\n // Fallback: return current directory if nothing found\n return path.resolve(startDir);\n}"]}
@@ -0,0 +1,166 @@
1
+ interface FindNearestConfigOpts {
2
+ startDir?: string;
3
+ stopDir?: string;
4
+ filenames: string[];
5
+ }
6
+
7
+ /**
8
+ * @module @kb-labs/core-sys/output/types
9
+ * Unified Output interface for KB Labs platform
10
+ */
11
+ type VerbosityLevel = "quiet" | "normal" | "verbose" | "debug" | "inspect";
12
+ type OutputMode = "tty" | "pipe" | "ci";
13
+ type DebugFormat = "human" | "ai";
14
+ type OutputLogLevel = "trace" | "debug" | "info" | "warn" | "error" | "fatal";
15
+ interface OutputLogRecord {
16
+ time: string;
17
+ ts: string;
18
+ level: OutputLogLevel;
19
+ category?: string;
20
+ msg: string;
21
+ meta?: Record<string, unknown>;
22
+ }
23
+ interface OutputLogSink {
24
+ handle(record: OutputLogRecord): void | Promise<void>;
25
+ }
26
+ interface OutputLogger {
27
+ info(message: string, meta?: Record<string, unknown>): void;
28
+ warn(message: string, meta?: Record<string, unknown>): void;
29
+ error(message: string, error?: Error, meta?: Record<string, unknown>): void;
30
+ debug(message: string, meta?: Record<string, unknown>): void;
31
+ child(bindings: Record<string, unknown>): OutputLogger;
32
+ }
33
+ /**
34
+ * Spinner interface for progress indicators
35
+ */
36
+ interface Spinner {
37
+ start(): void;
38
+ stop(): void;
39
+ update(options: {
40
+ text?: string;
41
+ }): void;
42
+ succeed(message?: string): void;
43
+ fail(message?: string): void;
44
+ }
45
+ /**
46
+ * Progress details for progress() method
47
+ */
48
+ interface ProgressDetails {
49
+ current?: number;
50
+ total?: number;
51
+ message?: string;
52
+ [key: string]: unknown;
53
+ }
54
+ /**
55
+ * Error options for error() method
56
+ */
57
+ interface ErrorOptions {
58
+ title?: string;
59
+ code?: string;
60
+ suggestions?: string[];
61
+ docs?: string;
62
+ context?: Record<string, unknown>;
63
+ report?: boolean;
64
+ }
65
+ /**
66
+ * UI utilities interface
67
+ */
68
+ interface UIUtilities {
69
+ box: (title: string, content?: string[], maxWidth?: number) => string;
70
+ sideBox: (options: {
71
+ title: string;
72
+ sections: Array<{
73
+ header?: string;
74
+ items: string[];
75
+ }>;
76
+ footer?: string;
77
+ status?: 'success' | 'error' | 'warning' | 'info';
78
+ timing?: number;
79
+ }) => string;
80
+ table: (rows: (string | number)[][], headers?: string[]) => string[];
81
+ keyValue: (pairs: Record<string, string | number>, options?: {
82
+ padKeys?: boolean;
83
+ }) => string[];
84
+ spinner: (text: string, jsonMode?: boolean) => Spinner;
85
+ colors: {
86
+ info: (text: string) => string;
87
+ warn: (text: string) => string;
88
+ error: (text: string) => string;
89
+ success: (text: string) => string;
90
+ muted: (text: string) => string;
91
+ bold: (text: string) => string;
92
+ primary: (text: string) => string;
93
+ accent: (text: string) => string;
94
+ };
95
+ symbols: {
96
+ success: string;
97
+ error: string;
98
+ warning: string;
99
+ info: string;
100
+ bullet: string;
101
+ };
102
+ }
103
+ /**
104
+ * Unified Output interface for plugins and CLI
105
+ */
106
+ interface Output {
107
+ success(message: string, data?: Record<string, unknown>): void;
108
+ error(error: Error | string, options?: ErrorOptions): void;
109
+ warn(message: string, hint?: string): void;
110
+ progress(stage: string, details?: ProgressDetails): void;
111
+ spinner(text: string): Spinner;
112
+ info(message: string, meta?: Record<string, unknown>): void;
113
+ debug(message: string, meta?: Record<string, unknown>): void;
114
+ trace(message: string, meta?: Record<string, unknown>): void;
115
+ json(data: unknown): void;
116
+ write(text: string): void;
117
+ ui: UIUtilities;
118
+ group(name: string): void;
119
+ groupEnd(): void;
120
+ readonly mode: OutputMode;
121
+ readonly verbosity: VerbosityLevel;
122
+ readonly isQuiet: boolean;
123
+ readonly isVerbose: boolean;
124
+ readonly isDebug: boolean;
125
+ readonly isJSON: boolean;
126
+ readonly isAIFormat: boolean;
127
+ }
128
+
129
+ /**
130
+ * @module @kb-labs/core-sys/output/factory
131
+ * Output factory with auto-detection
132
+ */
133
+
134
+ interface OutputConfig {
135
+ verbosity?: VerbosityLevel;
136
+ mode?: OutputMode;
137
+ format?: DebugFormat;
138
+ json?: boolean;
139
+ sinks?: OutputLogSink[];
140
+ category?: string;
141
+ context?: {
142
+ plugin?: string;
143
+ command?: string;
144
+ trace?: string;
145
+ };
146
+ }
147
+ declare function createOutput(config?: OutputConfig): Output;
148
+
149
+ /**
150
+ * @module @kb-labs/core/sys/fs
151
+ * Safe path helpers with explicit bases.
152
+ */
153
+ declare function toAbsolute(baseDir: string, maybeRelative?: string): string;
154
+
155
+ /**
156
+ * @module @kb-labs/core/sys/repo
157
+ * Repository root discovery. Pure infrastructure, no domain keys.
158
+ */
159
+ /**
160
+ * Find repository root by searching for markers in priority order.
161
+ * First searches entire tree for pnpm-workspace.yaml (monorepo root),
162
+ * then .git, then package.json as fallback.
163
+ */
164
+ declare function findRepoRoot(startDir?: string): Promise<string>;
165
+
166
+ export { type DebugFormat, type ErrorOptions, type FindNearestConfigOpts, type Output, type OutputConfig, type OutputLogLevel, type OutputLogRecord, type OutputLogSink, type OutputLogger, type OutputMode, type ProgressDetails, type Spinner, type UIUtilities, type VerbosityLevel, createOutput, findRepoRoot, toAbsolute };
@@ -0,0 +1,166 @@
1
+ interface FindNearestConfigOpts {
2
+ startDir?: string;
3
+ stopDir?: string;
4
+ filenames: string[];
5
+ }
6
+
7
+ /**
8
+ * @module @kb-labs/core-sys/output/types
9
+ * Unified Output interface for KB Labs platform
10
+ */
11
+ type VerbosityLevel = "quiet" | "normal" | "verbose" | "debug" | "inspect";
12
+ type OutputMode = "tty" | "pipe" | "ci";
13
+ type DebugFormat = "human" | "ai";
14
+ type OutputLogLevel = "trace" | "debug" | "info" | "warn" | "error" | "fatal";
15
+ interface OutputLogRecord {
16
+ time: string;
17
+ ts: string;
18
+ level: OutputLogLevel;
19
+ category?: string;
20
+ msg: string;
21
+ meta?: Record<string, unknown>;
22
+ }
23
+ interface OutputLogSink {
24
+ handle(record: OutputLogRecord): void | Promise<void>;
25
+ }
26
+ interface OutputLogger {
27
+ info(message: string, meta?: Record<string, unknown>): void;
28
+ warn(message: string, meta?: Record<string, unknown>): void;
29
+ error(message: string, error?: Error, meta?: Record<string, unknown>): void;
30
+ debug(message: string, meta?: Record<string, unknown>): void;
31
+ child(bindings: Record<string, unknown>): OutputLogger;
32
+ }
33
+ /**
34
+ * Spinner interface for progress indicators
35
+ */
36
+ interface Spinner {
37
+ start(): void;
38
+ stop(): void;
39
+ update(options: {
40
+ text?: string;
41
+ }): void;
42
+ succeed(message?: string): void;
43
+ fail(message?: string): void;
44
+ }
45
+ /**
46
+ * Progress details for progress() method
47
+ */
48
+ interface ProgressDetails {
49
+ current?: number;
50
+ total?: number;
51
+ message?: string;
52
+ [key: string]: unknown;
53
+ }
54
+ /**
55
+ * Error options for error() method
56
+ */
57
+ interface ErrorOptions {
58
+ title?: string;
59
+ code?: string;
60
+ suggestions?: string[];
61
+ docs?: string;
62
+ context?: Record<string, unknown>;
63
+ report?: boolean;
64
+ }
65
+ /**
66
+ * UI utilities interface
67
+ */
68
+ interface UIUtilities {
69
+ box: (title: string, content?: string[], maxWidth?: number) => string;
70
+ sideBox: (options: {
71
+ title: string;
72
+ sections: Array<{
73
+ header?: string;
74
+ items: string[];
75
+ }>;
76
+ footer?: string;
77
+ status?: 'success' | 'error' | 'warning' | 'info';
78
+ timing?: number;
79
+ }) => string;
80
+ table: (rows: (string | number)[][], headers?: string[]) => string[];
81
+ keyValue: (pairs: Record<string, string | number>, options?: {
82
+ padKeys?: boolean;
83
+ }) => string[];
84
+ spinner: (text: string, jsonMode?: boolean) => Spinner;
85
+ colors: {
86
+ info: (text: string) => string;
87
+ warn: (text: string) => string;
88
+ error: (text: string) => string;
89
+ success: (text: string) => string;
90
+ muted: (text: string) => string;
91
+ bold: (text: string) => string;
92
+ primary: (text: string) => string;
93
+ accent: (text: string) => string;
94
+ };
95
+ symbols: {
96
+ success: string;
97
+ error: string;
98
+ warning: string;
99
+ info: string;
100
+ bullet: string;
101
+ };
102
+ }
103
+ /**
104
+ * Unified Output interface for plugins and CLI
105
+ */
106
+ interface Output {
107
+ success(message: string, data?: Record<string, unknown>): void;
108
+ error(error: Error | string, options?: ErrorOptions): void;
109
+ warn(message: string, hint?: string): void;
110
+ progress(stage: string, details?: ProgressDetails): void;
111
+ spinner(text: string): Spinner;
112
+ info(message: string, meta?: Record<string, unknown>): void;
113
+ debug(message: string, meta?: Record<string, unknown>): void;
114
+ trace(message: string, meta?: Record<string, unknown>): void;
115
+ json(data: unknown): void;
116
+ write(text: string): void;
117
+ ui: UIUtilities;
118
+ group(name: string): void;
119
+ groupEnd(): void;
120
+ readonly mode: OutputMode;
121
+ readonly verbosity: VerbosityLevel;
122
+ readonly isQuiet: boolean;
123
+ readonly isVerbose: boolean;
124
+ readonly isDebug: boolean;
125
+ readonly isJSON: boolean;
126
+ readonly isAIFormat: boolean;
127
+ }
128
+
129
+ /**
130
+ * @module @kb-labs/core-sys/output/factory
131
+ * Output factory with auto-detection
132
+ */
133
+
134
+ interface OutputConfig {
135
+ verbosity?: VerbosityLevel;
136
+ mode?: OutputMode;
137
+ format?: DebugFormat;
138
+ json?: boolean;
139
+ sinks?: OutputLogSink[];
140
+ category?: string;
141
+ context?: {
142
+ plugin?: string;
143
+ command?: string;
144
+ trace?: string;
145
+ };
146
+ }
147
+ declare function createOutput(config?: OutputConfig): Output;
148
+
149
+ /**
150
+ * @module @kb-labs/core/sys/fs
151
+ * Safe path helpers with explicit bases.
152
+ */
153
+ declare function toAbsolute(baseDir: string, maybeRelative?: string): string;
154
+
155
+ /**
156
+ * @module @kb-labs/core/sys/repo
157
+ * Repository root discovery. Pure infrastructure, no domain keys.
158
+ */
159
+ /**
160
+ * Find repository root by searching for markers in priority order.
161
+ * First searches entire tree for pnpm-workspace.yaml (monorepo root),
162
+ * then .git, then package.json as fallback.
163
+ */
164
+ declare function findRepoRoot(startDir?: string): Promise<string>;
165
+
166
+ export { type DebugFormat, type ErrorOptions, type FindNearestConfigOpts, type Output, type OutputConfig, type OutputLogLevel, type OutputLogRecord, type OutputLogSink, type OutputLogger, type OutputMode, type ProgressDetails, type Spinner, type UIUtilities, type VerbosityLevel, createOutput, findRepoRoot, toAbsolute };
package/dist/index.js ADDED
@@ -0,0 +1,348 @@
1
+ import { safeSymbols, safeColors, createSpinner, keyValue, sideBorderBox, box, table } from '@kb-labs/shared-cli-ui';
2
+ import { formatTable } from '@kb-labs/shared-cli-ui/table';
3
+ import path2 from 'path';
4
+ import { promises } from 'fs';
5
+
6
+ // src/output/output-impl.ts
7
+ var OutputImpl = class {
8
+ constructor(config) {
9
+ this.config = config;
10
+ }
11
+ // Getters
12
+ get mode() {
13
+ return this.config.mode;
14
+ }
15
+ get verbosity() {
16
+ return this.config.verbosity;
17
+ }
18
+ get isQuiet() {
19
+ return this.config.verbosity === "quiet";
20
+ }
21
+ get isVerbose() {
22
+ return ["verbose", "debug", "inspect"].includes(this.config.verbosity);
23
+ }
24
+ get isDebug() {
25
+ return ["debug", "inspect"].includes(this.config.verbosity);
26
+ }
27
+ get isJSON() {
28
+ return this.config.json;
29
+ }
30
+ get isAIFormat() {
31
+ return this.config.format === "ai";
32
+ }
33
+ get ui() {
34
+ return {
35
+ box,
36
+ sideBox: sideBorderBox,
37
+ table: (rows, headers) => {
38
+ if (headers && headers.length > 0) {
39
+ return formatTable(
40
+ headers.map((h) => ({
41
+ header: h,
42
+ width: void 0,
43
+ align: "left"
44
+ })),
45
+ rows.map((r) => r.map(String)),
46
+ { header: true }
47
+ );
48
+ }
49
+ return table(rows.map((r) => r.map(String)));
50
+ },
51
+ keyValue,
52
+ spinner: (text, jsonMode) => createSpinner(text, jsonMode || this.isJSON),
53
+ colors: {
54
+ info: safeColors.info,
55
+ warn: safeColors.warning,
56
+ error: safeColors.error,
57
+ success: safeColors.success,
58
+ muted: safeColors.muted,
59
+ bold: safeColors.bold,
60
+ primary: safeColors.primary,
61
+ accent: safeColors.accent
62
+ },
63
+ symbols: {
64
+ success: safeSymbols.success,
65
+ error: safeSymbols.error,
66
+ warning: safeSymbols.warning,
67
+ info: safeSymbols.info,
68
+ bullet: safeSymbols.bullet
69
+ }
70
+ };
71
+ }
72
+ // Main methods
73
+ success(message, data) {
74
+ if (this.isJSON) {
75
+ this.json({ ok: true, message, ...data });
76
+ return;
77
+ }
78
+ if (this.isQuiet) {
79
+ return;
80
+ }
81
+ const output = `${safeSymbols.success} ${message}`;
82
+ console.log(safeColors.success(output));
83
+ this.config.logger.info(message, data);
84
+ }
85
+ error(error, options) {
86
+ const message = error instanceof Error ? error.message : error;
87
+ const stack = error instanceof Error ? error.stack : void 0;
88
+ if (this.isJSON) {
89
+ this.json({
90
+ ok: false,
91
+ error: {
92
+ message,
93
+ code: options?.code,
94
+ context: options?.context,
95
+ suggestions: options?.suggestions
96
+ }
97
+ });
98
+ return;
99
+ }
100
+ const lines = [];
101
+ if (options?.title) {
102
+ lines.push(
103
+ safeColors.error(`${safeSymbols.error} ${options.title}`)
104
+ );
105
+ }
106
+ lines.push(safeColors.error(message));
107
+ if (options?.code) {
108
+ lines.push(safeColors.muted(`Code: ${options.code}`));
109
+ }
110
+ if (options?.context && Object.keys(options.context).length > 0) {
111
+ lines.push("");
112
+ lines.push(safeColors.bold("Context:"));
113
+ lines.push(
114
+ ...keyValue(
115
+ Object.fromEntries(
116
+ Object.entries(options.context).map(([k, v]) => [
117
+ k,
118
+ String(v)
119
+ ])
120
+ )
121
+ )
122
+ );
123
+ }
124
+ if (options?.suggestions && options.suggestions.length > 0) {
125
+ lines.push("");
126
+ lines.push(safeColors.bold("Suggestions:"));
127
+ options.suggestions.forEach((s) => {
128
+ lines.push(` ${safeSymbols.bullet} ${s}`);
129
+ });
130
+ }
131
+ if (options?.docs) {
132
+ lines.push("");
133
+ lines.push(safeColors.info(`Documentation: ${options.docs}`));
134
+ }
135
+ const boxed = box("Error", lines);
136
+ console.error(boxed);
137
+ const errorMeta = {
138
+ code: options?.code,
139
+ context: options?.context
140
+ };
141
+ if (stack) {
142
+ errorMeta.stack = stack;
143
+ }
144
+ if (error instanceof Error) {
145
+ this.config.logger.error(message, error);
146
+ } else {
147
+ this.config.logger.error(message, void 0, errorMeta);
148
+ }
149
+ }
150
+ warn(message, hint) {
151
+ if (this.isQuiet) {
152
+ return;
153
+ }
154
+ const output = `${safeSymbols.warning} ${message}`;
155
+ console.warn(safeColors.warning(output));
156
+ if (hint) {
157
+ console.warn(safeColors.muted(` ${hint}`));
158
+ }
159
+ this.config.logger.warn(message, { hint });
160
+ }
161
+ progress(stage, details) {
162
+ if (this.isQuiet) {
163
+ return;
164
+ }
165
+ let output = stage;
166
+ if (details?.current !== void 0 && details?.total !== void 0) {
167
+ const percent = Math.round(
168
+ details.current / details.total * 100
169
+ );
170
+ output += ` (${details.current}/${details.total}, ${percent}%)`;
171
+ }
172
+ if (details?.message) {
173
+ output += ` - ${details.message}`;
174
+ }
175
+ console.log(safeColors.info(output));
176
+ this.config.logger.info(output, details);
177
+ }
178
+ spinner(text) {
179
+ return createSpinner(text, this.isJSON || this.isQuiet);
180
+ }
181
+ info(message, meta) {
182
+ if (!this.isVerbose) {
183
+ return;
184
+ }
185
+ console.log(message);
186
+ this.config.logger.info(message, meta);
187
+ }
188
+ debug(message, meta) {
189
+ if (!this.isDebug) {
190
+ return;
191
+ }
192
+ console.log(safeColors.muted(message));
193
+ this.config.logger.debug(message, meta);
194
+ }
195
+ trace(message, meta) {
196
+ if (this.verbosity !== "inspect") {
197
+ return;
198
+ }
199
+ console.log(safeColors.muted(`[TRACE] ${message}`));
200
+ this.config.logger.debug(message, { ...meta, trace: true });
201
+ }
202
+ json(data) {
203
+ console.log(JSON.stringify(data, null, 2));
204
+ }
205
+ write(text) {
206
+ if (this.isQuiet) {
207
+ return;
208
+ }
209
+ console.log(text);
210
+ }
211
+ group(name) {
212
+ if (this.isDebug) {
213
+ console.group(name);
214
+ }
215
+ }
216
+ groupEnd() {
217
+ if (this.isDebug) {
218
+ console.groupEnd();
219
+ }
220
+ }
221
+ // Internal method для форматированного вывода через ConsoleSink
222
+ // Используется только для UI вывода, не для записи в файлы
223
+ logToConsoleSink(level, msg, meta) {
224
+ const record = {
225
+ time: (/* @__PURE__ */ new Date()).toISOString(),
226
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
227
+ level,
228
+ category: this.config.category,
229
+ msg,
230
+ meta: { ...this.config.context, ...meta }
231
+ };
232
+ for (const sink of this.config.sinks) {
233
+ try {
234
+ void sink.handle(record);
235
+ } catch (err) {
236
+ console.error("Sink error:", err);
237
+ }
238
+ }
239
+ }
240
+ };
241
+
242
+ // src/output/factory.ts
243
+ var ConsoleLogger = class _ConsoleLogger {
244
+ constructor(level, bindings = {}) {
245
+ this.level = level;
246
+ this.bindings = bindings;
247
+ }
248
+ canLog(target) {
249
+ const rank = {
250
+ silent: 0,
251
+ error: 1,
252
+ warn: 2,
253
+ info: 3,
254
+ debug: 4,
255
+ trace: 5
256
+ };
257
+ return rank[target] <= rank[this.level];
258
+ }
259
+ withMeta(meta) {
260
+ const merged = { ...this.bindings, ...meta ?? {} };
261
+ return Object.keys(merged).length > 0 ? ` ${JSON.stringify(merged)}` : "";
262
+ }
263
+ info(message, meta) {
264
+ if (this.canLog("info")) {
265
+ console.log(`[INFO] ${message}${this.withMeta(meta)}`);
266
+ }
267
+ }
268
+ warn(message, meta) {
269
+ if (this.canLog("warn")) {
270
+ console.warn(`[WARN] ${message}${this.withMeta(meta)}`);
271
+ }
272
+ }
273
+ error(message, error, meta) {
274
+ if (this.canLog("error")) {
275
+ const payload = error ? { ...meta, error: { message: error.message, stack: error.stack } } : meta;
276
+ console.error(`[ERROR] ${message}${this.withMeta(payload)}`);
277
+ }
278
+ }
279
+ debug(message, meta) {
280
+ if (this.canLog("debug")) {
281
+ console.debug(`[DEBUG] ${message}${this.withMeta(meta)}`);
282
+ }
283
+ }
284
+ child(bindings) {
285
+ return new _ConsoleLogger(this.level, { ...this.bindings, ...bindings });
286
+ }
287
+ };
288
+ function createOutput(config = {}) {
289
+ const mode = config.mode || detectMode();
290
+ const verbosity = config.verbosity || "normal";
291
+ const format = config.format || (config.json ? "ai" : "human");
292
+ const sinks = config.sinks || [];
293
+ const loggerLevel = verbosity === "inspect" ? "trace" : verbosity === "debug" ? "debug" : verbosity === "verbose" ? "info" : verbosity === "quiet" ? "silent" : "info";
294
+ const logger = new ConsoleLogger(loggerLevel, {
295
+ category: config.category || "output",
296
+ ...config.context || {}
297
+ });
298
+ return new OutputImpl({
299
+ mode,
300
+ verbosity,
301
+ format,
302
+ json: config.json || false,
303
+ sinks,
304
+ // Только ConsoleSink для UI
305
+ logger,
306
+ // Глобальный logger для записи в файлы
307
+ category: config.category,
308
+ context: config.context
309
+ });
310
+ }
311
+ function detectMode() {
312
+ if (process.env.CI === "true") {
313
+ return "ci";
314
+ }
315
+ if (process.stdout.isTTY) {
316
+ return "tty";
317
+ }
318
+ return "pipe";
319
+ }
320
+ function toAbsolute(baseDir, maybeRelative) {
321
+ if (!maybeRelative) {
322
+ return baseDir;
323
+ }
324
+ return path2.isAbsolute(maybeRelative) ? maybeRelative : path2.join(baseDir, maybeRelative);
325
+ }
326
+ async function findRepoRoot(startDir = process.cwd()) {
327
+ const markersPriority = ["pnpm-workspace.yaml", ".git", "package.json"];
328
+ for (const marker of markersPriority) {
329
+ let dir = path2.resolve(startDir);
330
+ while (true) {
331
+ try {
332
+ await promises.access(path2.join(dir, marker));
333
+ return dir;
334
+ } catch {
335
+ }
336
+ const parent = path2.dirname(dir);
337
+ if (parent === dir) {
338
+ break;
339
+ }
340
+ dir = parent;
341
+ }
342
+ }
343
+ return path2.resolve(startDir);
344
+ }
345
+
346
+ export { createOutput, findRepoRoot, toAbsolute };
347
+ //# sourceMappingURL=index.js.map
348
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/output/output-impl.ts","../src/output/factory.ts","../src/fs/fs.ts","../src/repo/repo.ts"],"names":["path","fsp"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @module @kb-labs/core-sys/output/output-impl\n * Output implementation\n */\n\nimport type {\n Output,\n OutputMode,\n VerbosityLevel,\n DebugFormat,\n OutputLogSink,\n OutputLogRecord,\n OutputLogger,\n ErrorOptions,\n ProgressDetails,\n UIUtilities,\n Spinner,\n} from \"./types\";\nimport {\n box,\n keyValue,\n table,\n createSpinner,\n safeColors,\n safeSymbols,\n sideBorderBox,\n} from \"@kb-labs/shared-cli-ui\";\nimport { formatTable } from \"@kb-labs/shared-cli-ui/table\";\n\nexport class OutputImpl implements Output {\n constructor(\n private config: {\n mode: OutputMode;\n verbosity: VerbosityLevel;\n format: DebugFormat;\n json: boolean;\n sinks: OutputLogSink[]; // Только для форматированного вывода (ConsoleSink)\n logger: OutputLogger; // Глобальный logger для записи в файлы\n category?: string;\n context?: Record<string, unknown>;\n }\n ) {}\n\n // Getters\n get mode(): OutputMode {\n return this.config.mode;\n }\n\n get verbosity(): VerbosityLevel {\n return this.config.verbosity;\n }\n\n get isQuiet(): boolean {\n return this.config.verbosity === \"quiet\";\n }\n\n get isVerbose(): boolean {\n return [\"verbose\", \"debug\", \"inspect\"].includes(this.config.verbosity);\n }\n\n get isDebug(): boolean {\n return [\"debug\", \"inspect\"].includes(this.config.verbosity);\n }\n\n get isJSON(): boolean {\n return this.config.json;\n }\n\n get isAIFormat(): boolean {\n return this.config.format === \"ai\";\n }\n\n get ui(): UIUtilities {\n return {\n box,\n sideBox: sideBorderBox,\n table: (rows, headers) => {\n if (headers && headers.length > 0) {\n return formatTable(\n headers.map((h) => ({\n header: h,\n width: undefined,\n align: \"left\" as const,\n })),\n rows.map((r) => r.map(String)),\n { header: true }\n );\n }\n return table(rows.map((r) => r.map(String)));\n },\n keyValue,\n spinner: (text: string, jsonMode?: boolean) =>\n createSpinner(text, jsonMode || this.isJSON),\n colors: {\n info: safeColors.info,\n warn: safeColors.warning,\n error: safeColors.error,\n success: safeColors.success,\n muted: safeColors.muted,\n bold: safeColors.bold,\n primary: safeColors.primary,\n accent: safeColors.accent,\n },\n symbols: {\n success: safeSymbols.success,\n error: safeSymbols.error,\n warning: safeSymbols.warning,\n info: safeSymbols.info,\n bullet: safeSymbols.bullet,\n },\n };\n }\n\n // Main methods\n success(message: string, data?: Record<string, unknown>): void {\n if (this.isJSON) {\n this.json({ ok: true, message, ...data });\n return;\n }\n\n if (this.isQuiet) {return;}\n\n const output = `${safeSymbols.success} ${message}`;\n console.log(safeColors.success(output));\n // Использовать глобальный logger для записи в файлы\n this.config.logger.info(message, data);\n }\n\n error(error: Error | string, options?: ErrorOptions): void {\n const message = error instanceof Error ? error.message : error;\n const stack = error instanceof Error ? error.stack : undefined;\n\n if (this.isJSON) {\n this.json({\n ok: false,\n error: {\n message,\n code: options?.code,\n context: options?.context,\n suggestions: options?.suggestions,\n },\n });\n return;\n }\n\n // Красивое форматирование ошибки\n const lines: string[] = [];\n\n if (options?.title) {\n lines.push(\n safeColors.error(`${safeSymbols.error} ${options.title}`)\n );\n }\n\n lines.push(safeColors.error(message));\n\n if (options?.code) {\n lines.push(safeColors.muted(`Code: ${options.code}`));\n }\n\n if (options?.context && Object.keys(options.context).length > 0) {\n lines.push(\"\");\n lines.push(safeColors.bold(\"Context:\"));\n lines.push(\n ...keyValue(\n Object.fromEntries(\n Object.entries(options.context).map(([k, v]) => [\n k,\n String(v),\n ])\n )\n )\n );\n }\n\n if (options?.suggestions && options.suggestions.length > 0) {\n lines.push(\"\");\n lines.push(safeColors.bold(\"Suggestions:\"));\n options.suggestions.forEach((s) => {\n lines.push(` ${safeSymbols.bullet} ${s}`);\n });\n }\n\n if (options?.docs) {\n lines.push(\"\");\n lines.push(safeColors.info(`Documentation: ${options.docs}`));\n }\n\n const boxed = box(\"Error\", lines);\n console.error(boxed);\n\n // Использовать глобальный logger для записи в файлы\n const errorMeta: Record<string, unknown> = {\n code: options?.code,\n context: options?.context,\n };\n if (stack) {\n errorMeta.stack = stack;\n }\n if (error instanceof Error) {\n this.config.logger.error(message, error);\n } else {\n this.config.logger.error(message, undefined, errorMeta);\n }\n }\n\n warn(message: string, hint?: string): void {\n if (this.isQuiet) {return;}\n\n const output = `${safeSymbols.warning} ${message}`;\n console.warn(safeColors.warning(output));\n\n if (hint) {\n console.warn(safeColors.muted(` ${hint}`));\n }\n\n // Использовать глобальный logger для записи в файлы\n this.config.logger.warn(message, { hint });\n }\n\n progress(stage: string, details?: ProgressDetails): void {\n if (this.isQuiet) {return;}\n\n let output = stage;\n if (details?.current !== undefined && details?.total !== undefined) {\n const percent = Math.round(\n (details.current / details.total) * 100\n );\n output += ` (${details.current}/${details.total}, ${percent}%)`;\n }\n\n if (details?.message) {\n output += ` - ${details.message}`;\n }\n\n console.log(safeColors.info(output));\n // Использовать глобальный logger для записи в файлы\n this.config.logger.info(output, details as Record<string, unknown>);\n }\n\n spinner(text: string): Spinner {\n return createSpinner(text, this.isJSON || this.isQuiet);\n }\n\n info(message: string, meta?: Record<string, unknown>): void {\n if (!this.isVerbose) {return;}\n\n console.log(message);\n // Использовать глобальный logger для записи в файлы\n this.config.logger.info(message, meta);\n }\n\n debug(message: string, meta?: Record<string, unknown>): void {\n if (!this.isDebug) {return;}\n\n console.log(safeColors.muted(message));\n // Использовать глобальный logger для записи в файлы\n this.config.logger.debug(message, meta);\n }\n\n trace(message: string, meta?: Record<string, unknown>): void {\n if (this.verbosity !== \"inspect\") {return;}\n\n console.log(safeColors.muted(`[TRACE] ${message}`));\n // Использовать глобальный logger для записи в файлы (trace → debug)\n this.config.logger.debug(message, { ...meta, trace: true } as Record<string, unknown>);\n }\n\n json(data: unknown): void {\n console.log(JSON.stringify(data, null, 2));\n }\n\n write(text: string): void {\n if (this.isQuiet) {return;}\n console.log(text);\n }\n\n group(name: string): void {\n if (this.isDebug) {\n console.group(name);\n }\n }\n\n groupEnd(): void {\n if (this.isDebug) {\n console.groupEnd();\n }\n }\n\n // Internal method для форматированного вывода через ConsoleSink\n // Используется только для UI вывода, не для записи в файлы\n private logToConsoleSink(\n level: OutputLogRecord[\"level\"],\n msg: string,\n meta?: Record<string, unknown>\n ): void {\n const record: OutputLogRecord = {\n time: new Date().toISOString(),\n ts: new Date().toISOString(),\n level,\n category: this.config.category,\n msg,\n meta: { ...this.config.context, ...meta },\n };\n\n // Отправить только в ConsoleSink для форматированного вывода\n // Запись в файлы идет через глобальный logger\n for (const sink of this.config.sinks) {\n try {\n void sink.handle(record);\n } catch (err) {\n // Sink failures should not break execution\n console.error(\"Sink error:\", err);\n }\n }\n }\n}\n","/**\n * @module @kb-labs/core-sys/output/factory\n * Output factory with auto-detection\n */\n\nimport type { Output, OutputMode, VerbosityLevel, DebugFormat, OutputLogSink, OutputLogger } from \"./types\";\nimport { OutputImpl } from \"./output-impl\";\n\ntype LogLevel = \"trace\" | \"debug\" | \"info\" | \"warn\" | \"error\" | \"silent\";\n\nclass ConsoleLogger implements OutputLogger {\n constructor(\n private readonly level: LogLevel,\n private readonly bindings: Record<string, unknown> = {}\n ) {}\n\n private canLog(target: LogLevel): boolean {\n const rank: Record<LogLevel, number> = {\n silent: 0,\n error: 1,\n warn: 2,\n info: 3,\n debug: 4,\n trace: 5,\n };\n return rank[target] <= rank[this.level];\n }\n\n private withMeta(meta?: Record<string, unknown>): string {\n const merged = { ...this.bindings, ...(meta ?? {}) };\n return Object.keys(merged).length > 0 ? ` ${JSON.stringify(merged)}` : \"\";\n }\n\n info(message: string, meta?: Record<string, unknown>): void {\n if (this.canLog(\"info\")) {\n console.log(`[INFO] ${message}${this.withMeta(meta)}`);\n }\n }\n\n warn(message: string, meta?: Record<string, unknown>): void {\n if (this.canLog(\"warn\")) {\n console.warn(`[WARN] ${message}${this.withMeta(meta)}`);\n }\n }\n\n error(message: string, error?: Error, meta?: Record<string, unknown>): void {\n if (this.canLog(\"error\")) {\n const payload = error\n ? { ...meta, error: { message: error.message, stack: error.stack } }\n : meta;\n console.error(`[ERROR] ${message}${this.withMeta(payload)}`);\n }\n }\n\n debug(message: string, meta?: Record<string, unknown>): void {\n if (this.canLog(\"debug\")) {\n console.debug(`[DEBUG] ${message}${this.withMeta(meta)}`);\n }\n }\n\n child(bindings: Record<string, unknown>): OutputLogger {\n return new ConsoleLogger(this.level, { ...this.bindings, ...bindings });\n }\n}\n\nexport interface OutputConfig {\n verbosity?: VerbosityLevel; // Из флагов\n mode?: OutputMode; // Auto-detect или explicit\n format?: DebugFormat; // 'human' | 'ai'\n json?: boolean; // --json флаг\n sinks?: OutputLogSink[]; // Дополнительные sinks\n category?: string; // Категория для логов\n context?: {\n // Контекст команды\n plugin?: string;\n command?: string;\n trace?: string;\n };\n}\n\nexport function createOutput(config: OutputConfig = {}): Output {\n // Auto-detect mode\n const mode: OutputMode = config.mode || detectMode();\n\n // Verbosity из конфига или normal по умолчанию\n const verbosity: VerbosityLevel = config.verbosity || \"normal\";\n\n // Format\n const format: DebugFormat =\n config.format || (config.json ? \"ai\" : \"human\");\n\n // Создать sinks только для форматированного вывода пользователю\n const sinks: OutputLogSink[] = config.sinks || [];\n\n const loggerLevel =\n verbosity === \"inspect\"\n ? \"trace\"\n : verbosity === \"debug\"\n ? \"debug\"\n : verbosity === \"verbose\"\n ? \"info\"\n : verbosity === \"quiet\"\n ? \"silent\"\n : \"info\";\n const logger = new ConsoleLogger(loggerLevel, {\n category: config.category || \"output\",\n ...(config.context || {}),\n });\n\n // Создать Output implementation\n return new OutputImpl({\n mode,\n verbosity,\n format,\n json: config.json || false,\n sinks, // Только ConsoleSink для UI\n logger, // Глобальный logger для записи в файлы\n category: config.category,\n context: config.context,\n });\n}\n\nfunction detectMode(): OutputMode {\n // CI environment\n if (process.env.CI === \"true\") {\n return \"ci\";\n }\n\n // TTY\n if (process.stdout.isTTY) {\n return \"tty\";\n }\n\n // Pipe\n return \"pipe\";\n}\n","/**\n * @module @kb-labs/core/sys/fs\n * Safe path helpers with explicit bases.\n */\n\nimport path from \"node:path\";\n\nexport function toAbsolute(baseDir: string, maybeRelative?: string): string {\n if (!maybeRelative) { return baseDir; }\n return path.isAbsolute(maybeRelative) ? maybeRelative : path.join(baseDir, maybeRelative);\n}","/**\n * @module @kb-labs/core/sys/repo\n * Repository root discovery. Pure infrastructure, no domain keys.\n */\n\nimport path from \"node:path\";\nimport { promises as fsp } from \"node:fs\";\n\n/**\n * Find repository root by searching for markers in priority order.\n * First searches entire tree for pnpm-workspace.yaml (monorepo root),\n * then .git, then package.json as fallback.\n */\nexport async function findRepoRoot(startDir = process.cwd()): Promise<string> {\n const markersPriority = [\"pnpm-workspace.yaml\", \".git\", \"package.json\"];\n\n // Try each marker in priority order, searching entire tree each time\n for (const marker of markersPriority) {\n let dir = path.resolve(startDir);\n while (true) {\n try {\n await fsp.access(path.join(dir, marker));\n return dir; // Found it!\n } catch {\n // Continue searching upward\n }\n\n const parent = path.dirname(dir);\n if (parent === dir) {\n // Reached filesystem root without finding this marker\n break;\n }\n dir = parent;\n }\n }\n\n // Fallback: return current directory if nothing found\n return path.resolve(startDir);\n}"]}
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@kb-labs/core-sys",
3
+ "version": "1.0.0",
4
+ "description": "Core system utilities for KB Labs, including file system operations and path resolution",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js",
12
+ "require": "./dist/index.cjs"
13
+ },
14
+ "./output": {
15
+ "types": "./dist/index.d.ts",
16
+ "import": "./dist/index.js",
17
+ "require": "./dist/index.cjs"
18
+ }
19
+ },
20
+ "files": [
21
+ "dist",
22
+ "README.md",
23
+ "LICENSE"
24
+ ],
25
+ "sideEffects": false,
26
+ "dependencies": {
27
+ "@kb-labs/shared-cli-ui": "link:../../../kb-labs-shared/packages/shared-cli-ui"
28
+ },
29
+ "devDependencies": {
30
+ "@types/node": "^24.3.3",
31
+ "@types/picomatch": "^4",
32
+ "rimraf": "^6.0.1",
33
+ "tsup": "^8.5.0",
34
+ "typescript": "^5.6.3",
35
+ "vitest": "^3.2.4",
36
+ "@kb-labs/devkit": "link:../../../kb-labs-devkit"
37
+ },
38
+ "module": "./dist/index.js",
39
+ "engines": {
40
+ "node": ">=20.0.0",
41
+ "pnpm": ">=9.0.0"
42
+ },
43
+ "publishConfig": {
44
+ "access": "public"
45
+ },
46
+ "scripts": {
47
+ "clean": "rimraf dist",
48
+ "build": "pnpm clean && tsup --config tsup.config.ts",
49
+ "dev": "tsup --config tsup.config.ts --watch",
50
+ "type-check": "tsc --noEmit",
51
+ "test": "vitest run --passWithNoTests",
52
+ "lint": "eslint . --ignore-pattern 'dist/**' --ignore-pattern 'coverage/**'",
53
+ "lint:fix": "eslint . --fix --ignore-pattern 'dist/**' --ignore-pattern 'coverage/**'",
54
+ "test:watch": "vitest"
55
+ }
56
+ }