@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 +109 -0
- package/dist/index.cjs +356 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +166 -0
- package/dist/index.d.ts +166 -0
- package/dist/index.js +348 -0
- package/dist/index.js.map +1 -0
- package/package.json +56 -0
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)
|
|
6
|
+
[](https://nodejs.org/)
|
|
7
|
+
[](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}"]}
|
package/dist/index.d.cts
ADDED
|
@@ -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.d.ts
ADDED
|
@@ -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
|
+
}
|