@contentstack/cli-utilities 1.15.0 → 1.16.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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2024 Contentstack
3
+ Copyright (c) 2026 Contentstack
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -114,7 +114,7 @@ class AuthHandler {
114
114
  await this.openOAuthURL();
115
115
  }
116
116
  catch (error) {
117
- this.logger.error('OAuth login failed', error.message);
117
+ this.logger.error('OAuth login failed!', error.message);
118
118
  throw error;
119
119
  }
120
120
  }
@@ -123,20 +123,20 @@ class AuthHandler {
123
123
  const server = http_1.default.createServer(async (req, res) => {
124
124
  const queryObject = url_1.default.parse(req.url, true).query;
125
125
  if (!queryObject.code) {
126
- cli_ux_1.default.error('Error occoured while login with OAuth, please login with command - csdx auth:login --oauth');
126
+ cli_ux_1.default.error('Error occurred while logging in with OAuth!');
127
127
  return sendErrorResponse(res);
128
128
  }
129
129
  cli_ux_1.default.print('Auth code successfully fetched.');
130
130
  try {
131
131
  await this.getAccessToken(queryObject.code);
132
132
  await this.setOAuthBaseURL();
133
- cli_ux_1.default.print('Access token fetched using auth code successfully.');
133
+ cli_ux_1.default.print('Access token successfully fetched using auth code.');
134
134
  cli_ux_1.default.print(`You can review the access permissions on the page - ${this.OAuthBaseURL}/#!/marketplace/authorized-apps`);
135
135
  sendSuccessResponse(res);
136
136
  stopServer();
137
137
  }
138
138
  catch (error) {
139
- cli_ux_1.default.error('Error occoured while login with OAuth, please login with command - csdx auth:login --oauth');
139
+ cli_ux_1.default.error('Error occurred while logging in with OAuth!');
140
140
  cli_ux_1.default.error(error);
141
141
  sendErrorResponse(res);
142
142
  stopServer();
@@ -301,8 +301,8 @@ class AuthHandler {
301
301
  }
302
302
  }
303
303
  else {
304
- cli_ux_1.default.error('Invalid/Empty access token.');
305
- throw new Error('Invalid/Empty access token');
304
+ cli_ux_1.default.error('Invalid or empty access token.');
305
+ throw new Error('Invalid or empty access token.');
306
306
  }
307
307
  }
308
308
  async oauthLogout() {
@@ -346,7 +346,7 @@ class AuthHandler {
346
346
  const oauthValidUpto = new Date();
347
347
  oauthValidUpto.setTime(oauthDate.getTime() + 59 * 60 * 1000);
348
348
  if (force) {
349
- cli_ux_1.default.print('Force refreshing the token');
349
+ cli_ux_1.default.print('Forcing token refresh...');
350
350
  return this.refreshToken();
351
351
  }
352
352
  else {
@@ -373,7 +373,7 @@ class AuthHandler {
373
373
  }
374
374
  }
375
375
  else {
376
- cli_ux_1.default.print('No OAuth set');
376
+ cli_ux_1.default.print('No OAuth configuration set.');
377
377
  this.unsetConfigData();
378
378
  }
379
379
  }
@@ -50,12 +50,6 @@ class AuthenticationHandler {
50
50
  }
51
51
  async refreshAccessToken(error, maxRetryCount = 1) {
52
52
  var _a, _b;
53
- // Add configurable delay only for CI/CD pipelines
54
- const delayMs = process.env.DELAY_MS;
55
- if (delayMs) {
56
- const delay = parseInt(delayMs, 10);
57
- await new Promise((resolve) => setTimeout(resolve, delay));
58
- }
59
53
  if (error.response && error.response.status) {
60
54
  switch (error.response.status) {
61
55
  case 401:
@@ -47,7 +47,7 @@ class Config {
47
47
  }
48
48
  }
49
49
  catch (error) {
50
- console.log('No data to be imported from Old config file');
50
+ console.log('No data to import from old configuration file.');
51
51
  }
52
52
  this.set(OLD_CONFIG_BACKUP_FLAG, true);
53
53
  }
@@ -13,4 +13,3 @@ export declare const levelColors: {
13
13
  info: string;
14
14
  debug: string;
15
15
  };
16
- export declare const PROGRESS_SUPPORTED_MODULES: readonly ["export", "import"];
@@ -1,13 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PROGRESS_SUPPORTED_MODULES = exports.levelColors = exports.logLevels = void 0;
3
+ exports.levelColors = exports.logLevels = void 0;
4
4
  exports.logLevels = {
5
5
  error: 0,
6
6
  warn: 1,
7
7
  info: 2,
8
8
  success: 2,
9
9
  debug: 3,
10
- verbose: 4,
10
+ verbose: 4
11
11
  };
12
12
  // 2. Create color mappings (for console only)
13
13
  exports.levelColors = {
@@ -15,6 +15,5 @@ exports.levelColors = {
15
15
  warn: 'yellow',
16
16
  success: 'green',
17
17
  info: 'white',
18
- debug: 'blue',
18
+ debug: 'blue'
19
19
  };
20
- exports.PROGRESS_SUPPORTED_MODULES = ['export', 'import'];
@@ -19,6 +19,7 @@ class ManagementSDKInitiator {
19
19
  maxRequests: 10,
20
20
  retryLimit: 3,
21
21
  timeout: 60000,
22
+ delayMs: config.delayMs,
22
23
  httpsAgent: new node_https_1.Agent({
23
24
  maxSockets: 100,
24
25
  maxFreeSockets: 10,
@@ -36,6 +37,7 @@ class ManagementSDKInitiator {
36
37
  case 401:
37
38
  case 429:
38
39
  case 408:
40
+ case 422:
39
41
  return true;
40
42
  default:
41
43
  return false;
@@ -22,17 +22,17 @@ function default_1(deprecatedFlags = [], suggestions = [], customMessage) {
22
22
  }
23
23
  });
24
24
  if (isCommandHasDeprecationFlag) {
25
- let depreactionMessage = '';
25
+ let deprecationMessage = '';
26
26
  if (customMessage) {
27
- depreactionMessage = customMessage;
27
+ deprecationMessage = customMessage;
28
28
  }
29
29
  else {
30
- depreactionMessage = `WARNING!!! You're using the old (soon to be deprecated) Contentstack CLI flags (${deprecatedFlags.join(', ')}).`;
30
+ deprecationMessage = `WARNING!!! You're using the old (soon to be deprecated) Contentstack CLI flags (${deprecatedFlags.join(', ')}).`;
31
31
  if (suggestions.length > 0) {
32
- depreactionMessage += ` We recommend you to use the updated flags (${suggestions.join(', ')}).`;
32
+ deprecationMessage += ` We recommend you to use the updated flags (${suggestions.join(', ')}).`;
33
33
  }
34
34
  }
35
- cli_ux_1.default.print(depreactionMessage, { color: 'yellow' });
35
+ cli_ux_1.default.print(deprecationMessage, { color: 'yellow' });
36
36
  }
37
37
  return input;
38
38
  };
package/lib/helpers.d.ts CHANGED
@@ -27,4 +27,28 @@ export declare const formatError: (error: any) => string;
27
27
  * from.
28
28
  */
29
29
  export declare const redactObject: (obj: any) => any;
30
- export declare function clearProgressModuleSetting(): void;
30
+ /**
31
+ * Get authentication method from config
32
+ * @returns Authentication method string ('OAuth', 'Basic Auth', or empty string)
33
+ */
34
+ export declare function getAuthenticationMethod(): string;
35
+ /**
36
+ * Creates a standardized context object for logging
37
+ * This context contains all session-level metadata that should be in session.json
38
+ * The apiKey is stored in configHandler so it's available for session.json generation
39
+ *
40
+ * @param commandId - The command ID (e.g., 'cm:stacks:export')
41
+ * @param apiKey - The API key for the stack (will be stored in configHandler for session.json)
42
+ * @param authenticationMethod - Optional authentication method
43
+ * @returns Context object with all session-level metadata
44
+ */
45
+ export declare function createLogContext(commandId: string, apiKey: string, authenticationMethod?: string): {
46
+ command: string;
47
+ module: string;
48
+ userId: string;
49
+ email: string;
50
+ sessionId: string;
51
+ apiKey: string;
52
+ orgId: string;
53
+ authenticationMethod: string;
54
+ };
package/lib/helpers.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.clearProgressModuleSetting = exports.redactObject = exports.formatError = exports.validateRegex = exports.validateFileName = exports.validateUids = exports.sanitizePath = exports.escapeRegExp = exports.validatePath = exports.createDeveloperHubUrl = exports.isManagementTokenValid = exports.getBranchFromAlias = exports.doesBranchExist = exports.isAuthenticated = void 0;
3
+ exports.createLogContext = exports.getAuthenticationMethod = exports.redactObject = exports.formatError = exports.validateRegex = exports.validateFileName = exports.validateUids = exports.sanitizePath = exports.escapeRegExp = exports.validatePath = exports.createDeveloperHubUrl = exports.isManagementTokenValid = exports.getBranchFromAlias = exports.doesBranchExist = exports.isAuthenticated = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const recheck_1 = require("recheck");
6
6
  const traverse_1 = tslib_1.__importDefault(require("traverse"));
@@ -185,8 +185,8 @@ const formatError = function (error) {
185
185
  // If message is in JSON format, parse it to extract the actual message string
186
186
  try {
187
187
  const parsedMessage = JSON.parse(message);
188
- if (typeof parsedMessage === 'object' && parsedMessage !== null) {
189
- message = (parsedMessage === null || parsedMessage === void 0 ? void 0 : parsedMessage.message) || (parsedMessage === null || parsedMessage === void 0 ? void 0 : parsedMessage.errorMessage) || (parsedMessage === null || parsedMessage === void 0 ? void 0 : parsedMessage.error) || message;
188
+ if (typeof parsedMessage === 'object') {
189
+ message = (parsedMessage === null || parsedMessage === void 0 ? void 0 : parsedMessage.message) || message;
190
190
  }
191
191
  }
192
192
  catch (e) {
@@ -238,11 +238,48 @@ const sensitiveKeys = [
238
238
  /management[-._]?token/i,
239
239
  /delivery[-._]?token/i,
240
240
  ];
241
- function clearProgressModuleSetting() {
242
- const logConfig = _1.configHandler.get('log') || {};
243
- if (logConfig === null || logConfig === void 0 ? void 0 : logConfig.progressSupportedModule) {
244
- delete logConfig.progressSupportedModule;
245
- _1.configHandler.set('log', logConfig);
241
+ /**
242
+ * Get authentication method from config
243
+ * @returns Authentication method string ('OAuth', 'Basic Auth', or empty string)
244
+ */
245
+ function getAuthenticationMethod() {
246
+ const authType = _1.configHandler.get('authorisationType');
247
+ if (authType === 'OAUTH') {
248
+ return 'OAuth';
249
+ }
250
+ else if (authType === 'BASIC') {
251
+ return 'Basic Auth';
252
+ }
253
+ // Management token detection is command-specific and not stored globally
254
+ // Return empty string if unknown
255
+ return '';
256
+ }
257
+ exports.getAuthenticationMethod = getAuthenticationMethod;
258
+ /**
259
+ * Creates a standardized context object for logging
260
+ * This context contains all session-level metadata that should be in session.json
261
+ * The apiKey is stored in configHandler so it's available for session.json generation
262
+ *
263
+ * @param commandId - The command ID (e.g., 'cm:stacks:export')
264
+ * @param apiKey - The API key for the stack (will be stored in configHandler for session.json)
265
+ * @param authenticationMethod - Optional authentication method
266
+ * @returns Context object with all session-level metadata
267
+ */
268
+ function createLogContext(commandId, apiKey, authenticationMethod) {
269
+ // Store apiKey in configHandler so it's available for session.json
270
+ if (apiKey) {
271
+ _1.configHandler.set('apiKey', apiKey);
246
272
  }
273
+ const authMethod = authenticationMethod || getAuthenticationMethod();
274
+ return {
275
+ command: commandId,
276
+ module: '',
277
+ userId: _1.configHandler.get('clientId') || '',
278
+ email: _1.configHandler.get('email') || '',
279
+ sessionId: _1.configHandler.get('sessionId') || '',
280
+ apiKey: apiKey || '',
281
+ orgId: _1.configHandler.get('oauthOrgUid') || '',
282
+ authenticationMethod: authMethod,
283
+ };
247
284
  }
248
- exports.clearProgressModuleSetting = clearProgressModuleSetting;
285
+ exports.createLogContext = createLogContext;
@@ -225,6 +225,13 @@ export declare class HttpClient implements IHttpClient {
225
225
  * @returns {Request}
226
226
  */
227
227
  createAndSendRequest(method: HttpMethod, url: string): Promise<AxiosResponse>;
228
+ /**
229
+ * Get the axios instance for interceptor access
230
+ */
231
+ get interceptors(): {
232
+ request: import("axios").AxiosInterceptorManager<import("axios").InternalAxiosRequestConfig<any>>;
233
+ response: import("axios").AxiosInterceptorManager<AxiosResponse<any, any, {}>>;
234
+ };
228
235
  /**
229
236
  * Returns the request payload depending on the selected request payload format.
230
237
  */
@@ -334,6 +334,12 @@ class HttpClient {
334
334
  return await this.axiosInstance(Object.assign(Object.assign({ url,
335
335
  method, withCredentials: true }, this.request), { data: this.prepareRequestPayload() }));
336
336
  }
337
+ /**
338
+ * Get the axios instance for interceptor access
339
+ */
340
+ get interceptors() {
341
+ return this.axiosInstance.interceptors;
342
+ }
337
343
  /**
338
344
  * Returns the request payload depending on the selected request payload format.
339
345
  */
package/lib/index.d.ts CHANGED
@@ -13,6 +13,7 @@ export * from './fs-utility';
13
13
  export { default as NodeCrypto } from './encrypter';
14
14
  export { Args as args, Flags as flags, Command } from './cli-ux';
15
15
  export * from './helpers';
16
+ export { createLogContext } from './helpers';
16
17
  export * from './interfaces';
17
18
  export * from './date-time';
18
19
  export * from './add-locale';
@@ -25,4 +26,3 @@ export { default as TablePrompt } from './inquirer-table-prompt';
25
26
  export { Logger };
26
27
  export { default as authenticationHandler } from './authentication-handler';
27
28
  export { v2Logger as log, cliErrorHandler, handleAndLogError, getLogPath } from './logger/log';
28
- export { CLIProgressManager, SummaryManager, PrimaryProcessStrategy, ProgressStrategyRegistry, CustomProgressStrategy, DefaultProgressStrategy } from './progress-summary';
package/lib/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DefaultProgressStrategy = exports.CustomProgressStrategy = exports.ProgressStrategyRegistry = exports.PrimaryProcessStrategy = exports.SummaryManager = exports.CLIProgressManager = exports.getLogPath = exports.handleAndLogError = exports.cliErrorHandler = exports.log = exports.authenticationHandler = exports.Logger = exports.TablePrompt = exports.execute = exports.ux = exports.flush = exports.settings = exports.toConfiguredId = exports.toStandardizedId = exports.run = exports.Plugin = exports.Parser = exports.Interfaces = exports.HelpBase = exports.Help = exports.loadHelpClass = exports.Flags = exports.Errors = exports.Config = exports.CommandHelp = exports.Args = exports.marketplaceSDKInitiator = exports.MarketplaceSDKInitiator = exports.marketplaceSDKClient = exports.CLITable = exports.Command = exports.flags = exports.args = exports.NodeCrypto = exports.printFlagDeprecation = exports.managementSDKInitiator = exports.managementSDKClient = exports.configHandler = exports.authHandler = exports.messageHandler = exports.CLIError = exports.cliux = exports.LoggerService = void 0;
3
+ exports.getLogPath = exports.handleAndLogError = exports.cliErrorHandler = exports.log = exports.authenticationHandler = exports.Logger = exports.TablePrompt = exports.execute = exports.ux = exports.flush = exports.settings = exports.toConfiguredId = exports.toStandardizedId = exports.run = exports.Plugin = exports.Parser = exports.Interfaces = exports.HelpBase = exports.Help = exports.loadHelpClass = exports.Flags = exports.Errors = exports.Config = exports.CommandHelp = exports.Args = exports.marketplaceSDKInitiator = exports.MarketplaceSDKInitiator = exports.marketplaceSDKClient = exports.CLITable = exports.createLogContext = exports.Command = exports.flags = exports.args = exports.NodeCrypto = exports.printFlagDeprecation = exports.managementSDKInitiator = exports.managementSDKClient = exports.configHandler = exports.authHandler = exports.messageHandler = exports.CLIError = exports.cliux = exports.LoggerService = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const logger_1 = tslib_1.__importDefault(require("./logger"));
6
6
  exports.Logger = logger_1.default;
@@ -34,6 +34,8 @@ Object.defineProperty(exports, "args", { enumerable: true, get: function () { re
34
34
  Object.defineProperty(exports, "flags", { enumerable: true, get: function () { return cli_ux_2.Flags; } });
35
35
  Object.defineProperty(exports, "Command", { enumerable: true, get: function () { return cli_ux_2.Command; } });
36
36
  tslib_1.__exportStar(require("./helpers"), exports);
37
+ var helpers_1 = require("./helpers");
38
+ Object.defineProperty(exports, "createLogContext", { enumerable: true, get: function () { return helpers_1.createLogContext; } });
37
39
  tslib_1.__exportStar(require("./interfaces"), exports);
38
40
  tslib_1.__exportStar(require("./date-time"), exports);
39
41
  tslib_1.__exportStar(require("./add-locale"), exports);
@@ -69,10 +71,3 @@ Object.defineProperty(exports, "log", { enumerable: true, get: function () { ret
69
71
  Object.defineProperty(exports, "cliErrorHandler", { enumerable: true, get: function () { return log_1.cliErrorHandler; } });
70
72
  Object.defineProperty(exports, "handleAndLogError", { enumerable: true, get: function () { return log_1.handleAndLogError; } });
71
73
  Object.defineProperty(exports, "getLogPath", { enumerable: true, get: function () { return log_1.getLogPath; } });
72
- var progress_summary_1 = require("./progress-summary");
73
- Object.defineProperty(exports, "CLIProgressManager", { enumerable: true, get: function () { return progress_summary_1.CLIProgressManager; } });
74
- Object.defineProperty(exports, "SummaryManager", { enumerable: true, get: function () { return progress_summary_1.SummaryManager; } });
75
- Object.defineProperty(exports, "PrimaryProcessStrategy", { enumerable: true, get: function () { return progress_summary_1.PrimaryProcessStrategy; } });
76
- Object.defineProperty(exports, "ProgressStrategyRegistry", { enumerable: true, get: function () { return progress_summary_1.ProgressStrategyRegistry; } });
77
- Object.defineProperty(exports, "CustomProgressStrategy", { enumerable: true, get: function () { return progress_summary_1.CustomProgressStrategy; } });
78
- Object.defineProperty(exports, "DefaultProgressStrategy", { enumerable: true, get: function () { return progress_summary_1.DefaultProgressStrategy; } });
@@ -1,5 +1,4 @@
1
- import { logLevels } from '../constants/logging';
2
- import ProgressBar from 'cli-progress';
1
+ import { logLevels } from "../constants/logging";
3
2
  export interface IPromptOptions {
4
3
  prompt?: string;
5
4
  type?: 'normal' | 'mask' | 'hide' | 'single';
@@ -102,51 +101,3 @@ export interface ErrorContextBase {
102
101
  export type ErrorContext = ErrorContextBase & {
103
102
  [key: string]: unknown;
104
103
  };
105
- export interface Failure {
106
- item: string;
107
- error: string | null;
108
- process?: string;
109
- }
110
- export interface ProcessProgress {
111
- name: string;
112
- total: number;
113
- current: number;
114
- status: 'pending' | 'active' | 'completed' | 'failed';
115
- successCount: number;
116
- failureCount: number;
117
- failures: Failure[];
118
- progressBar?: ProgressBar.SingleBar;
119
- }
120
- export interface ProgressManagerOptions {
121
- showConsoleLogs?: boolean;
122
- total?: number;
123
- moduleName?: string;
124
- enableNestedProgress?: boolean;
125
- }
126
- export interface ModuleResult {
127
- name: string;
128
- status: 'pending' | 'running' | 'completed' | 'failed';
129
- startTime?: number;
130
- endTime?: number;
131
- totalItems: number;
132
- successCount: number;
133
- failureCount: number;
134
- failures: Array<{
135
- item: string;
136
- error: string;
137
- }>;
138
- processes?: Array<{
139
- processName: string;
140
- [key: string]: any;
141
- }>;
142
- }
143
- export interface SummaryOptions {
144
- operationName: string;
145
- context?: any;
146
- branchName?: string;
147
- }
148
- export interface ProgressResult {
149
- total: number;
150
- success: number;
151
- failures: number;
152
- }
@@ -114,7 +114,8 @@ class CLIErrorHandler {
114
114
  if (typeof error === 'object') {
115
115
  try {
116
116
  const errorObj = error;
117
- const normalizedError = new Error('Error occurred');
117
+ const message = errorObj.message || errorObj.error || errorObj.statusText || 'Unknown error';
118
+ const normalizedError = new Error(message);
118
119
  // Only copy essential properties
119
120
  const essentialProps = [
120
121
  'code',
@@ -29,4 +29,5 @@ declare function handleAndLogError(error: unknown, context?: ErrorContext, error
29
29
  * 4. Home directory (~/contentstack/logs) (fallback)
30
30
  */
31
31
  declare function getLogPath(): string;
32
+ export { getSessionLogPath } from './session-path';
32
33
  export { v2Logger, cliErrorHandler, handleAndLogError, getLogPath };
package/lib/logger/log.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getLogPath = exports.handleAndLogError = exports.cliErrorHandler = exports.v2Logger = void 0;
3
+ exports.getLogPath = exports.handleAndLogError = exports.cliErrorHandler = exports.v2Logger = exports.getSessionLogPath = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const fs = tslib_1.__importStar(require("fs"));
6
6
  const os = tslib_1.__importStar(require("os"));
@@ -13,7 +13,7 @@ function createLoggerInstance() {
13
13
  var _a;
14
14
  const logConfig = __1.configHandler.get('log');
15
15
  const logLevel = (logConfig === null || logConfig === void 0 ? void 0 : logConfig.level) || 'info';
16
- const showConsoleLogs = (_a = logConfig === null || logConfig === void 0 ? void 0 : logConfig.showConsoleLogs) !== null && _a !== void 0 ? _a : false;
16
+ const showConsoleLogs = (_a = logConfig === null || logConfig === void 0 ? void 0 : logConfig['show-console-logs']) !== null && _a !== void 0 ? _a : false;
17
17
  const config = {
18
18
  basePath: getLogPath(),
19
19
  logLevel: logLevel,
@@ -103,3 +103,6 @@ function getLogPath() {
103
103
  return path.join(os.homedir(), 'contentstack', 'logs');
104
104
  }
105
105
  exports.getLogPath = getLogPath;
106
+ // Re-export getSessionLogPath for external use
107
+ var session_path_1 = require("./session-path");
108
+ Object.defineProperty(exports, "getSessionLogPath", { enumerable: true, get: function () { return session_path_1.getSessionLogPath; } });
@@ -6,7 +6,7 @@ const full_1 = require("klona/full");
6
6
  const path_1 = require("path");
7
7
  const winston = tslib_1.__importStar(require("winston"));
8
8
  const logging_1 = require("../constants/logging");
9
- const __1 = require("..");
9
+ const session_path_1 = require("./session-path");
10
10
  class Logger {
11
11
  constructor(config) {
12
12
  this.consoleSensitiveKeys = [
@@ -32,57 +32,40 @@ class Logger {
32
32
  };
33
33
  }
34
34
  getLoggerInstance(level = 'info') {
35
- const filePath = (0, path_1.normalize)(process.env.CS_CLI_LOG_PATH || this.config.basePath).replace(/^(\.\.(\/|\\|$))+/, '');
35
+ // Use session-based path for date-organized logging
36
+ const sessionPath = (0, session_path_1.getSessionLogPath)();
37
+ const filePath = (0, path_1.normalize)(sessionPath).replace(/^(\.\.(\/|\\|$))+/, '');
36
38
  return this.createLogger(level === 'hidden' ? 'error' : level, filePath);
37
39
  }
38
40
  get loggerOptions() {
39
41
  return {
40
42
  filename: '',
41
- maxFiles: 20,
43
+ maxFiles: 50,
42
44
  tailable: true,
43
- maxsize: 1000000,
45
+ maxsize: 5000000, // 5MB
44
46
  };
45
47
  }
46
48
  createLogger(level, filePath) {
47
- var _a;
48
- const transports = [
49
- new winston.transports.File(Object.assign(Object.assign({}, this.loggerOptions), { filename: `${filePath}/${level}.log`, format: winston.format.combine(winston.format.timestamp(), winston.format.printf((info) => {
50
- // Apply minimal redaction for files (debugging info preserved)
51
- const redactedInfo = this.redact(info, false);
52
- return JSON.stringify(redactedInfo);
53
- })) })),
54
- ];
55
- // Determine console logging based on configuration
56
- let showConsoleLogs = true;
57
- if (__1.configHandler && typeof __1.configHandler.get === 'function') {
58
- const logConfig = __1.configHandler.get('log') || {};
59
- const currentModule = logConfig.progressSupportedModule;
60
- const hasProgressSupport = currentModule && logging_1.PROGRESS_SUPPORTED_MODULES.includes(currentModule);
61
- if (hasProgressSupport) {
62
- // Plugin has progress bars - respect user's showConsoleLogs setting
63
- showConsoleLogs = (_a = logConfig.showConsoleLogs) !== null && _a !== void 0 ? _a : true;
64
- }
65
- else {
66
- // Plugin doesn't have progress support - always show console logs
67
- showConsoleLogs = true;
68
- }
69
- }
70
- if (showConsoleLogs) {
71
- transports.push(new winston.transports.Console({
72
- format: winston.format.combine(winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), winston.format.printf((info) => {
73
- // Apply full redaction for console (user-facing)
74
- const redactedInfo = this.redact(info, true);
75
- const colorizer = winston.format.colorize();
76
- const levelText = redactedInfo.level.toUpperCase();
77
- const { timestamp, message } = redactedInfo;
78
- return colorizer.colorize(redactedInfo.level, `[${timestamp}] ${levelText}: ${message}`);
79
- })),
80
- }));
81
- }
82
49
  return winston.createLogger({
83
50
  levels: logging_1.logLevels,
84
51
  level,
85
- transports,
52
+ transports: [
53
+ new winston.transports.File(Object.assign(Object.assign({}, this.loggerOptions), { filename: `${filePath}/${level}.log`, format: winston.format.combine(winston.format.timestamp(), winston.format.printf((info) => {
54
+ // Apply minimal redaction for files (debugging info preserved)
55
+ const redactedInfo = this.redact(info, false);
56
+ return JSON.stringify(redactedInfo);
57
+ })) })),
58
+ new winston.transports.Console({
59
+ format: winston.format.combine(winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), winston.format.printf((info) => {
60
+ // Apply full redaction for console (user-facing)
61
+ const redactedInfo = this.redact(info, true);
62
+ const colorizer = winston.format.colorize();
63
+ const levelText = redactedInfo.level.toUpperCase();
64
+ const { timestamp, message } = redactedInfo;
65
+ return colorizer.colorize(redactedInfo.level, `[${timestamp}] ${levelText}: ${message}`);
66
+ })),
67
+ }),
68
+ ],
86
69
  });
87
70
  }
88
71
  isSensitiveKey(keyStr, consoleMode = false) {
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Get the session-based log path for date-organized logging
3
+ * Structure: {basePath}/{YYYY-MM-DD}/{command}-{YYYYMMDD-HHMMSS}-{sessionId}/
4
+ *
5
+ * @returns The session-specific log directory path
6
+ */
7
+ export declare function getSessionLogPath(): string;
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getSessionLogPath = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const fs = tslib_1.__importStar(require("fs"));
6
+ const os = tslib_1.__importStar(require("os"));
7
+ const path = tslib_1.__importStar(require("path"));
8
+ const __1 = require("..");
9
+ const log_1 = require("./log");
10
+ /**
11
+ * Extract module name from command ID
12
+ * Example: "cm:stacks:audit" -> "audit"
13
+ */
14
+ function extractModule(commandId) {
15
+ if (!commandId || commandId === 'unknown') {
16
+ return '';
17
+ }
18
+ // Split by colon and get the last part
19
+ const parts = commandId.split(':');
20
+ return parts[parts.length - 1] || '';
21
+ }
22
+ /**
23
+ * Generate session metadata object for session.json
24
+ * Uses createLogContext() to get base context, then adds session-specific metadata
25
+ */
26
+ function generateSessionMetadata(commandId, sessionId, startTimestamp) {
27
+ const originalCommandId = __1.configHandler.get('currentCommandId') || commandId;
28
+ const module = extractModule(originalCommandId);
29
+ const apiKey = __1.configHandler.get('apiKey') || '';
30
+ const baseContext = (0, __1.createLogContext)(originalCommandId, apiKey);
31
+ return Object.assign(Object.assign({}, baseContext), { module: module, sessionId: sessionId, startTimestamp: startTimestamp.toISOString(), MachineEnvironment: {
32
+ nodeVersion: process.version,
33
+ os: os.platform(),
34
+ hostname: os.hostname(),
35
+ CLI_VERSION: __1.configHandler.get('CLI_VERSION') || '',
36
+ } });
37
+ }
38
+ /**
39
+ * Create session.json metadata file in the session directory
40
+ */
41
+ function createSessionMetadataFile(sessionPath, metadata) {
42
+ const metadataPath = path.join(sessionPath, 'session.json');
43
+ try {
44
+ fs.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2), 'utf8');
45
+ }
46
+ catch (error) {
47
+ // Silently fail if metadata file cannot be created
48
+ // Logging here would cause circular dependency
49
+ // The session folder and logs will still be created
50
+ }
51
+ }
52
+ /**
53
+ * Get the session-based log path for date-organized logging
54
+ * Structure: {basePath}/{YYYY-MM-DD}/{command}-{YYYYMMDD-HHMMSS}-{sessionId}/
55
+ *
56
+ * @returns The session-specific log directory path
57
+ */
58
+ function getSessionLogPath() {
59
+ // Get base log path
60
+ const basePath = (0, log_1.getLogPath)();
61
+ // Get current date in YYYY-MM-DD format
62
+ const now = new Date();
63
+ const dateStr = now.toISOString().split('T')[0]; // YYYY-MM-DD
64
+ // Get command ID (fallback to 'unknown' if not set)
65
+ let commandId = __1.configHandler.get('currentCommandId') || 'unknown';
66
+ // Sanitize command ID - remove colons and replace with hyphens for folder name
67
+ commandId = commandId === null || commandId === void 0 ? void 0 : commandId.replace(/:/g, '-');
68
+ // Use helper methods to format date and time
69
+ const dateStrFormatted = (0, __1.formatDate)(now); // YYYYMMDD
70
+ const timeStrFormatted = (0, __1.formatTime)(now); // HHMMSS
71
+ const timestamp = `${dateStrFormatted}-${timeStrFormatted}`; // YYYYMMDD-HHMMSS
72
+ let sessionId = __1.configHandler.get('sessionId');
73
+ if (!sessionId) {
74
+ // Format: first 8 chars of command + timestamp (YYYYMMDDHHMMSS)
75
+ const timestampForId = `${dateStrFormatted}${timeStrFormatted}`; // YYYYMMDDHHMMSS
76
+ const commandHash = commandId.substring(0, 8).padEnd(8, '0'); // Use first 8 chars of command
77
+ sessionId = `${commandHash}-${timestampForId}`;
78
+ }
79
+ // Create session folder name: command-YYYYMMDD-HHMMSS-sessionId
80
+ const sessionFolderName = `${commandId}-${timestamp}-${sessionId}`;
81
+ // Build full session path
82
+ const sessionPath = path.join(basePath, dateStr, sessionFolderName);
83
+ // Ensure directory exists
84
+ const isNewSession = !fs.existsSync(sessionPath);
85
+ if (isNewSession) {
86
+ fs.mkdirSync(sessionPath, { recursive: true });
87
+ }
88
+ // Create session.json metadata file for new sessions
89
+ // This ensures metadata is created before any logs are written
90
+ if (isNewSession) {
91
+ const metadata = generateSessionMetadata(__1.configHandler.get('currentCommandId') || commandId, sessionId, now);
92
+ createSessionMetadataFile(sessionPath, metadata);
93
+ }
94
+ return sessionPath;
95
+ }
96
+ exports.getSessionLogPath = getSessionLogPath;
package/lib/logger.js CHANGED
@@ -26,7 +26,7 @@ class LoggerService {
26
26
  stringifiedParam = JSON.stringify(info.obj);
27
27
  }
28
28
  catch (error) {
29
- console.log('warning: failed to log the result');
29
+ console.log('Warning: Failed to log the result');
30
30
  }
31
31
  // parse message
32
32
  info.message = index_1.messageHandler.parse(info.message);