@nmakarov/cli-toolkit 0.4.0 → 0.6.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/dist/index.js CHANGED
@@ -734,6 +734,10 @@ var Params = class {
734
734
  var paramsInstance = null;
735
735
  var getParamsInstance = () => paramsInstance;
736
736
 
737
+ // src/screen/index.ts
738
+ import React5, { useState as useState3, useEffect as useEffect3, useRef as useRef3, useMemo, useCallback, createElement as createElement2 } from "react";
739
+ import { Box as Box5, Text as Text5, useInput as useInput2 } from "ink";
740
+
737
741
  // src/screen/screens.ts
738
742
  import { useState as useState2, createElement as h3 } from "react";
739
743
  import { render, useInput, Text as Text3 } from "ink";
@@ -2896,8 +2900,291 @@ var Db = class {
2896
2900
  return this.isConnected && this.knexInstance !== null;
2897
2901
  }
2898
2902
  };
2903
+
2904
+ // src/logger/index.ts
2905
+ import chalk from "chalk";
2906
+ import util from "util";
2907
+
2908
+ // src/logger/transports.ts
2909
+ var ConsoleTransport = class {
2910
+ write(payload) {
2911
+ console.info(payload);
2912
+ }
2913
+ };
2914
+ var ParentProcessTransport = class {
2915
+ write(payload) {
2916
+ if (process.env.VITEST || process.env.NODE_ENV === "test") {
2917
+ console.info(payload);
2918
+ return;
2919
+ }
2920
+ if (typeof process.send === "function" && process.connected === true) {
2921
+ process.send(payload);
2922
+ } else {
2923
+ console.info(payload);
2924
+ }
2925
+ }
2926
+ };
2927
+
2928
+ // src/logger/index.ts
2929
+ var ALL_LEVELS = [
2930
+ "silly",
2931
+ "debug",
2932
+ "logic",
2933
+ "info",
2934
+ "notice",
2935
+ "warn",
2936
+ "error",
2937
+ "results",
2938
+ "request",
2939
+ "response",
2940
+ "progress"
2941
+ ];
2942
+ var LEVEL_COLORS = {
2943
+ error: chalk.red.bold,
2944
+ warn: chalk.rgb(255, 165, 0),
2945
+ notice: chalk.cyan,
2946
+ info: chalk.white.bold,
2947
+ logic: chalk.gray,
2948
+ debug: chalk.gray,
2949
+ silly: chalk.gray,
2950
+ request: chalk.green,
2951
+ response: chalk.yellow,
2952
+ progress: chalk.green,
2953
+ results: chalk.magenta
2954
+ };
2955
+ var CliToolkitLogger = class {
2956
+ options;
2957
+ transport;
2958
+ startTimes = {};
2959
+ lastProgressTimes = {};
2960
+ constructor(options = {}) {
2961
+ this.options = this.normalizeOptions(options);
2962
+ this.transport = this.options.route === "ipc" ? new ParentProcessTransport() : new ConsoleTransport();
2963
+ }
2964
+ setMode(mode) {
2965
+ if (!this.isValidMode(mode)) {
2966
+ throw new Error(`Unsupported logger mode: ${mode}`);
2967
+ }
2968
+ this.options.mode = mode;
2969
+ }
2970
+ debug(message, ...chunks) {
2971
+ this.out({ level: "debug", message, chunks });
2972
+ }
2973
+ info(message, ...chunks) {
2974
+ this.out({ level: "info", message, chunks });
2975
+ }
2976
+ notice(message, ...chunks) {
2977
+ this.out({ level: "notice", message, chunks });
2978
+ }
2979
+ warn(message, ...chunks) {
2980
+ this.out({ level: "warn", message, chunks });
2981
+ }
2982
+ error(message, ...chunks) {
2983
+ this.out({ level: "error", message, chunks });
2984
+ }
2985
+ logic(message, ...chunks) {
2986
+ this.out({ level: "logic", message, chunks });
2987
+ }
2988
+ silly(message, ...chunks) {
2989
+ this.out({ level: "silly", message, chunks });
2990
+ }
2991
+ results(results) {
2992
+ this.out({ level: "results", message: "results", results });
2993
+ }
2994
+ request(operation, ...chunks) {
2995
+ const message = this.inspectChunks([operation, ...chunks]);
2996
+ this.out({ level: "request", message });
2997
+ }
2998
+ response(operation, ...chunks) {
2999
+ const message = this.inspectChunks([operation, ...chunks]);
3000
+ this.out({ level: "response", message });
3001
+ }
3002
+ progress(message, opts) {
3003
+ const { prefix, count, total } = opts;
3004
+ const paddedTotal = String(total).length;
3005
+ const paddedCount = String(count).padStart(paddedTotal, " ");
3006
+ const payload = {
3007
+ level: "progress",
3008
+ message,
3009
+ count: paddedCount,
3010
+ total,
3011
+ prefix
3012
+ };
3013
+ if (!this.startTimes[prefix ?? ""]) {
3014
+ this.startTimes[prefix ?? ""] = Date.now();
3015
+ }
3016
+ if (this.options.progressTimes) {
3017
+ const elapsedSeconds = (Date.now() - this.startTimes[prefix ?? ""]) / 1e3;
3018
+ let remaining = -1;
3019
+ if (count > 1) {
3020
+ const rate = elapsedSeconds / (count - 1);
3021
+ remaining = (total - count) * rate;
3022
+ }
3023
+ payload.elapsed = this.round(elapsedSeconds, 2);
3024
+ payload.remaining = remaining >= 0 ? this.round(remaining, 2) : remaining;
3025
+ }
3026
+ if (count >= total) {
3027
+ delete this.startTimes[prefix ?? ""];
3028
+ delete this.lastProgressTimes[prefix ?? ""];
3029
+ }
3030
+ if (this.shouldOutputProgress(prefix ?? "", count, total)) {
3031
+ this.out(payload);
3032
+ if (this.options.progressThrottle && prefix) {
3033
+ this.lastProgressTimes[prefix] = Date.now();
3034
+ }
3035
+ }
3036
+ }
3037
+ shouldOutputProgress(prefix, count, total) {
3038
+ if (!this.options.progressThrottle) {
3039
+ return true;
3040
+ }
3041
+ if (count === 1 || count === total || !prefix) {
3042
+ return true;
3043
+ }
3044
+ const lastTime = this.lastProgressTimes[prefix];
3045
+ if (!lastTime) {
3046
+ return true;
3047
+ }
3048
+ return Date.now() - lastTime >= this.options.progressThrottle;
3049
+ }
3050
+ out(struct) {
3051
+ if (this.options.silent) {
3052
+ return;
3053
+ }
3054
+ if (!this.options.levels.includes(struct.level)) {
3055
+ return;
3056
+ }
3057
+ if (this.options.prefix && !struct.prefix) {
3058
+ struct.prefix = this.options.prefix;
3059
+ }
3060
+ const output = this.options.mode === "json" ? struct : this.formatLog(struct);
3061
+ this.transport.write(output);
3062
+ }
3063
+ formatLog(struct) {
3064
+ const parts = [];
3065
+ const now = /* @__PURE__ */ new Date();
3066
+ if (this.options.timestamp) {
3067
+ parts.push(now.toISOString());
3068
+ }
3069
+ if (this.options.showLevel) {
3070
+ parts.push(struct.level.toUpperCase());
3071
+ }
3072
+ if (struct.level === "progress") {
3073
+ if (struct.prefix) {
3074
+ parts.push(LEVEL_COLORS[struct.level].bold(struct.prefix));
3075
+ }
3076
+ if (struct.count !== void 0 && struct.total !== void 0) {
3077
+ parts.push(LEVEL_COLORS[struct.level](`${struct.count}/${struct.total}`));
3078
+ }
3079
+ } else if (struct.prefix) {
3080
+ parts.push(chalk.cyan(`[${struct.prefix}]`));
3081
+ }
3082
+ if (struct.message) {
3083
+ const formatter = LEVEL_COLORS[struct.level] ?? chalk.white;
3084
+ parts.push(formatter.bold(struct.message));
3085
+ }
3086
+ if (struct.level === "progress") {
3087
+ if (struct.elapsed !== void 0 && struct.remaining !== void 0) {
3088
+ const formatter = LEVEL_COLORS[struct.level];
3089
+ parts.push(formatter(`${struct.elapsed}/${struct.remaining}`));
3090
+ }
3091
+ }
3092
+ if (struct.chunks && struct.chunks.length) {
3093
+ parts.push(this.inspectChunks(struct.chunks));
3094
+ }
3095
+ if (struct.results) {
3096
+ const formatter = LEVEL_COLORS[struct.level] ?? chalk.white;
3097
+ parts.push(formatter(JSON.stringify(struct.results, null, 4)));
3098
+ }
3099
+ return parts.join(" ");
3100
+ }
3101
+ inspectChunks(chunks) {
3102
+ return chunks.map((chunk) => util.inspect(chunk, { colors: true, depth: null })).join(" ");
3103
+ }
3104
+ normalizeOptions(options) {
3105
+ const { route, mode, prefix, silent, showLevel, timestamp, levels, progress } = options;
3106
+ const shouldUseIpc = this.shouldUseIpcRoute();
3107
+ const normalized = {
3108
+ mode: this.isValidMode(mode) ? mode : "text",
3109
+ route: route ?? (shouldUseIpc ? "ipc" : "console"),
3110
+ prefix,
3111
+ silent: silent ?? false,
3112
+ showLevel: showLevel ?? true,
3113
+ timestamp: timestamp ?? false,
3114
+ levels: this.normalizeLevels(levels),
3115
+ progressTimes: progress?.withTimes ?? false,
3116
+ progressThrottle: progress?.throttleMs
3117
+ };
3118
+ return normalized;
3119
+ }
3120
+ shouldUseIpcRoute() {
3121
+ if (process.env.VITEST || process.env.NODE_ENV === "test") {
3122
+ return false;
3123
+ }
3124
+ return typeof process.send === "function" && process.connected === true;
3125
+ }
3126
+ normalizeLevels(levels) {
3127
+ if (!levels || !levels.length) {
3128
+ return ALL_LEVELS;
3129
+ }
3130
+ const includes = levels.filter((level) => !level.startsWith("-"));
3131
+ const excludes = levels.filter((level) => level.startsWith("-")).map((level) => level.slice(1));
3132
+ const unknown = [...includes, ...excludes].filter((level) => !ALL_LEVELS.includes(level));
3133
+ if (unknown.length) {
3134
+ console.warn(`[Logger] Unknown level(s): ${unknown.join(", ")}`);
3135
+ }
3136
+ const base = includes.length ? includes : ALL_LEVELS;
3137
+ return base.filter((level) => !excludes.includes(level));
3138
+ }
3139
+ isValidMode(mode) {
3140
+ return mode === void 0 || mode === null || mode === "text" || mode === "json";
3141
+ }
3142
+ round(value, places) {
3143
+ const factor = Math.pow(10, places);
3144
+ return Math.round(value * factor) / factor;
3145
+ }
3146
+ };
3147
+
3148
+ // src/init/index.ts
3149
+ import { EventEmitter } from "events";
3150
+ function setup(opts = {}) {
3151
+ const args = new Args({
3152
+ overrides: opts.overrides || {},
3153
+ defaults: opts.defaults || {}
3154
+ });
3155
+ const params = new Params({ args }, opts.overrides || {});
3156
+ const loggerOptions = opts.logger || {};
3157
+ const logger = new CliToolkitLogger({
3158
+ mode: loggerOptions.mode || "text",
3159
+ route: loggerOptions.route || "console",
3160
+ prefix: loggerOptions.prefix,
3161
+ silent: loggerOptions.silent,
3162
+ showLevel: loggerOptions.showLevel,
3163
+ timestamp: loggerOptions.timestamp,
3164
+ levels: loggerOptions.levels
3165
+ });
3166
+ const cleanupFunctions = [];
3167
+ const context = {
3168
+ args,
3169
+ params,
3170
+ logger,
3171
+ emitter: new EventEmitter(),
3172
+ isStop: () => false,
3173
+ // Will be set in init function
3174
+ cleanupFunctions,
3175
+ registerCleanup: (fn) => {
3176
+ cleanupFunctions.push(fn);
3177
+ }
3178
+ };
3179
+ logger.debug("[setup] completed successfully");
3180
+ return context;
3181
+ }
3182
+ function setupContext(opts = {}) {
3183
+ return setup(opts);
3184
+ }
2899
3185
  export {
2900
3186
  Args,
3187
+ Box5 as Box,
2901
3188
  Db,
2902
3189
  Divider,
2903
3190
  FileDatabase,
@@ -2910,12 +3197,14 @@ export {
2910
3197
  MultiColumnListComponent,
2911
3198
  MultiColumnListWithPreviewComponent,
2912
3199
  Params,
3200
+ React5 as React,
2913
3201
  ScreenBody,
2914
3202
  ScreenContainer,
2915
3203
  ScreenDivider,
2916
3204
  ScreenFooter,
2917
3205
  ScreenRow,
2918
3206
  ScreenTitle,
3207
+ Text5 as Text,
2919
3208
  TextBlock,
2920
3209
  buildBreadcrumb,
2921
3210
  buildDetailBreadcrumb,
@@ -2924,14 +3213,22 @@ export {
2924
3213
  defaultVersionSynopsisFunction,
2925
3214
  getArgsInstance,
2926
3215
  getParamsInstance,
3216
+ createElement2 as h,
2927
3217
  joiEdateType,
2928
3218
  joiStringArrayType,
2929
3219
  organizeFooterMessages,
3220
+ setupContext,
2930
3221
  showListScreen,
2931
3222
  showMenuScreen,
2932
3223
  showMultiColumnListScreen,
2933
3224
  showMultiColumnListWithPreviewScreen,
2934
3225
  showScreen,
2935
- showWordGridScreen
3226
+ showWordGridScreen,
3227
+ useCallback,
3228
+ useEffect3 as useEffect,
3229
+ useInput2 as useInput,
3230
+ useMemo,
3231
+ useRef3 as useRef,
3232
+ useState3 as useState
2936
3233
  };
2937
3234
  //# sourceMappingURL=index.js.map