@herodevs/cli 2.0.0-beta.12 → 2.0.0-beta.13

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 CHANGED
@@ -43,11 +43,11 @@ npm install -g @herodevs/cli@beta
43
43
  HeroDevs CLI is available as a binary installation, without requiring `npm`. To do that, you may either download and run the script manually, or use the following cURL or Wget command:
44
44
 
45
45
  ```sh
46
- curl -o- https://raw.githubusercontent.com/herodevs/cli/v2.0.0-beta.12/scripts/install.sh | bash
46
+ curl -o- https://raw.githubusercontent.com/herodevs/cli/v2.0.0-beta.13/scripts/install.sh | bash
47
47
  ```
48
48
 
49
49
  ```sh
50
- wget -qO- https://raw.githubusercontent.com/herodevs/cli/v2.0.0-beta.12/scripts/install.sh | bash
50
+ wget -qO- https://raw.githubusercontent.com/herodevs/cli/v2.0.0-beta.13/scripts/install.sh | bash
51
51
  ```
52
52
 
53
53
  ## Scanning Behavior
@@ -72,7 +72,7 @@ $ npm install -g @herodevs/cli@beta
72
72
  $ hd COMMAND
73
73
  running command...
74
74
  $ hd (--version)
75
- @herodevs/cli/2.0.0-beta.10 darwin-arm64 node-v22.18.0
75
+ @herodevs/cli/2.0.0-beta.12 darwin-arm64 node-v24.10.0
76
76
  $ hd --help [COMMAND]
77
77
  USAGE
78
78
  $ hd COMMAND
@@ -82,6 +82,7 @@ USAGE
82
82
  ## Commands
83
83
  <!-- commands -->
84
84
  * [`hd help [COMMAND]`](#hd-help-command)
85
+ * [`hd report committers`](#hd-report-committers)
85
86
  * [`hd scan eol`](#hd-scan-eol)
86
87
  * [`hd update [CHANNEL]`](#hd-update-channel)
87
88
  * **NOTE:** Only applies to [binary installation method](#binary-installation). NPM users should use [`npm install`](#global-npm-installation) to update to the latest version.
@@ -95,7 +96,7 @@ USAGE
95
96
  $ hd help [COMMAND...] [-n]
96
97
 
97
98
  ARGUMENTS
98
- COMMAND... Command to show help for.
99
+ [COMMAND...] Command to show help for.
99
100
 
100
101
  FLAGS
101
102
  -n, --nested-commands Include all nested commands in the output.
@@ -104,7 +105,38 @@ DESCRIPTION
104
105
  Display help for hd.
105
106
  ```
106
107
 
107
- _See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/v6.2.33/src/commands/help.ts)_
108
+ _See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/v6.2.34/src/commands/help.ts)_
109
+
110
+ ## `hd report committers`
111
+
112
+ Generate report of committers to a git repository
113
+
114
+ ```
115
+ USAGE
116
+ $ hd report committers [--json] [-m <value>] [-c] [-s]
117
+
118
+ FLAGS
119
+ -c, --csv Output in CSV format
120
+ -m, --months=<value> [default: 12] The number of months of git history to review
121
+ -s, --save Save the committers report as herodevs.committers.<output>
122
+
123
+ GLOBAL FLAGS
124
+ --json Format output as json.
125
+
126
+ DESCRIPTION
127
+ Generate report of committers to a git repository
128
+
129
+ EXAMPLES
130
+ $ hd report committers
131
+
132
+ $ hd report committers --csv -s
133
+
134
+ $ hd report committers --json
135
+
136
+ $ hd report committers --csv
137
+ ```
138
+
139
+ _See code: [src/commands/report/committers.ts](https://github.com/herodevs/cli/blob/v2.0.0-beta.12/src/commands/report/committers.ts)_
108
140
 
109
141
  ## `hd scan eol`
110
142
 
@@ -112,18 +144,20 @@ Scan a given SBOM for EOL data
112
144
 
113
145
  ```
114
146
  USAGE
115
- $ hd scan eol [--json] [-f <value> | -d <value>] [-s] [-o <value>] [--saveSbom] [--sbomOutput <value>] [--saveTrimmedSbom] [--hideReportUrl] [--version]
147
+ $ hd scan eol [--json] [-f <value> | -d <value>] [-s] [-o <value>] [--saveSbom] [--sbomOutput <value>]
148
+ [--saveTrimmedSbom] [--hideReportUrl] [--version]
116
149
 
117
150
  FLAGS
118
- -d, --dir=<value> [default: <current directory>] The directory to scan in order to scan for EOL
119
- -f, --file=<value> The file path of an existing SBOM to scan for EOL (supports CycloneDX and SPDX 2.3 formats)
120
- -s, --save Save the generated report as herodevs.report.json in the scanned directory
121
- -o, --output=<value> Save the generated report to a custom path (requires --save, defaults to herodevs.report.json when not provided)
122
- --hideReportUrl Hide the generated web report URL for this scan
123
- --saveSbom Save the generated SBOM as herodevs.sbom.json in the scanned directory
124
- --sbomOutput=<value> Save the generated SBOM to a custom path (requires --saveSbom, defaults to herodevs.sbom.json when not provided)
125
- --saveTrimmedSbom Save the trimmed SBOM as herodevs.sbom-trimmed.json in the scanned directory
126
- --version Show CLI version.
151
+ -d, --dir=<value> [default: <current directory>] The directory to scan in order to create a cyclonedx SBOM
152
+ -f, --file=<value> The file path of an existing SBOM to scan for EOL (supports CycloneDX and SPDX 2.3 formats)
153
+ -o, --output=<value> Save the generated report to a custom path (defaults to herodevs.report.json when not
154
+ provided)
155
+ -s, --save Save the generated report as herodevs.report.json in the scanned directory
156
+ --hideReportUrl Hide the generated web report URL for this scan
157
+ --saveSbom Save the generated SBOM as herodevs.sbom.json in the scanned directory
158
+ --saveTrimmedSbom Save the trimmed SBOM as herodevs.sbom-trimmed.json in the scanned directory
159
+ --sbomOutput=<value> Save the generated SBOM to a custom path (defaults to herodevs.sbom.json when not provided)
160
+ --version Show CLI version.
127
161
 
128
162
  GLOBAL FLAGS
129
163
  --json Format output as json.
@@ -157,7 +191,7 @@ EXAMPLES
157
191
  $ hd scan eol --json
158
192
  ```
159
193
 
160
- _See code: [src/commands/scan/eol.ts](https://github.com/herodevs/cli/blob/v2.0.0-beta.10/src/commands/scan/eol.ts)_
194
+ _See code: [src/commands/scan/eol.ts](https://github.com/herodevs/cli/blob/v2.0.0-beta.12/src/commands/scan/eol.ts)_
161
195
 
162
196
  ## `hd update [CHANNEL]`
163
197
 
@@ -197,7 +231,7 @@ EXAMPLES
197
231
  $ hd update --available
198
232
  ```
199
233
 
200
- _See code: [@oclif/plugin-update](https://github.com/oclif/plugin-update/blob/v4.7.8/src/commands/update.ts)_
234
+ _See code: [@oclif/plugin-update](https://github.com/oclif/plugin-update/blob/v4.7.13/src/commands/update.ts)_
201
235
  <!-- commandsstop -->
202
236
 
203
237
  ## CI/CD Usage
@@ -0,0 +1,23 @@
1
+ import { Command } from '@oclif/core';
2
+ import { type ReportData } from '../../service/committers.svc.ts';
3
+ export default class Committers extends Command {
4
+ static description: string;
5
+ static enableJsonFlag: boolean;
6
+ static examples: string[];
7
+ static flags: {
8
+ months: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
9
+ csv: import("@oclif/core/interfaces").BooleanFlag<boolean>;
10
+ save: import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
+ };
12
+ run(): Promise<ReportData | string>;
13
+ /**
14
+ * Generates structured report data
15
+ * @param entries - parsed git log output for commits
16
+ */
17
+ private generateReportData;
18
+ /**
19
+ * Fetches git commit data with month and author information
20
+ * @param sinceDate - Date range for git log
21
+ */
22
+ private fetchGitCommitData;
23
+ }
@@ -0,0 +1,147 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { Command, Flags } from '@oclif/core';
5
+ import { filenamePrefix } from "../../config/constants.js";
6
+ import { calculateOverallStats, formatAsCsv, formatAsText, groupCommitsByMonth, parseGitLogOutput, } from "../../service/committers.svc.js";
7
+ import { getErrorMessage, isErrnoException } from "../../service/error.svc.js";
8
+ export default class Committers extends Command {
9
+ static description = 'Generate report of committers to a git repository';
10
+ static enableJsonFlag = true;
11
+ static examples = [
12
+ '<%= config.bin %> <%= command.id %>',
13
+ '<%= config.bin %> <%= command.id %> --csv -s',
14
+ '<%= config.bin %> <%= command.id %> --json',
15
+ '<%= config.bin %> <%= command.id %> --csv',
16
+ ];
17
+ static flags = {
18
+ months: Flags.integer({
19
+ char: 'm',
20
+ description: 'The number of months of git history to review',
21
+ default: 12,
22
+ }),
23
+ csv: Flags.boolean({
24
+ char: 'c',
25
+ description: 'Output in CSV format',
26
+ default: false,
27
+ }),
28
+ save: Flags.boolean({
29
+ char: 's',
30
+ description: `Save the committers report as ${filenamePrefix}.committers.<output>`,
31
+ default: false,
32
+ }),
33
+ };
34
+ async run() {
35
+ const { flags } = await this.parse(Committers);
36
+ const { months, csv, save } = flags;
37
+ const isJson = this.jsonEnabled();
38
+ const sinceDate = `${months} months ago`;
39
+ this.log('Starting committers report with flags: %O', flags);
40
+ try {
41
+ // Generate structured report data
42
+ const entries = this.fetchGitCommitData(sinceDate);
43
+ this.log('Fetched %d commit entries', entries.length);
44
+ const reportData = this.generateReportData(entries);
45
+ // Handle different output scenarios
46
+ if (isJson) {
47
+ // JSON mode
48
+ if (save) {
49
+ try {
50
+ fs.writeFileSync(path.resolve(`${filenamePrefix}.committers.json`), JSON.stringify(reportData, null, 2));
51
+ this.log('Report written to json');
52
+ }
53
+ catch (error) {
54
+ this.error(`Failed to save JSON report: ${getErrorMessage(error)}`);
55
+ }
56
+ }
57
+ return reportData;
58
+ }
59
+ const textOutput = formatAsText(reportData);
60
+ if (csv) {
61
+ // CSV mode
62
+ const csvOutput = formatAsCsv(reportData);
63
+ if (save) {
64
+ try {
65
+ fs.writeFileSync(path.resolve(`${filenamePrefix}.committers.csv`), csvOutput);
66
+ this.log('Report written to csv');
67
+ }
68
+ catch (error) {
69
+ this.error(`Failed to save CSV report: ${getErrorMessage(error)}`);
70
+ }
71
+ }
72
+ else {
73
+ this.log(textOutput);
74
+ }
75
+ return csvOutput;
76
+ }
77
+ if (save) {
78
+ try {
79
+ fs.writeFileSync(path.resolve(`${filenamePrefix}.committers.txt`), textOutput);
80
+ this.log('Report written to txt');
81
+ }
82
+ catch (error) {
83
+ this.error(`Failed to save txt report: ${getErrorMessage(error)}`);
84
+ }
85
+ }
86
+ else {
87
+ this.log(textOutput);
88
+ }
89
+ return textOutput;
90
+ }
91
+ catch (error) {
92
+ this.error(`Failed to generate report: ${getErrorMessage(error)}`);
93
+ }
94
+ }
95
+ /**
96
+ * Generates structured report data
97
+ * @param entries - parsed git log output for commits
98
+ */
99
+ generateReportData(entries) {
100
+ if (entries.length === 0) {
101
+ return { monthly: {}, overall: { total: 0 } };
102
+ }
103
+ const monthlyData = groupCommitsByMonth(entries);
104
+ const overallStats = calculateOverallStats(entries);
105
+ const grandTotal = entries.length;
106
+ // Format into a structured report data object
107
+ const report = {
108
+ monthly: {},
109
+ overall: { ...overallStats, total: grandTotal },
110
+ };
111
+ // Add monthly totals
112
+ for (const [month, authors] of Object.entries(monthlyData)) {
113
+ const monthTotal = Object.values(authors).reduce((sum, count) => sum + count, 0);
114
+ report.monthly[month] = { ...authors, total: monthTotal };
115
+ }
116
+ return report;
117
+ }
118
+ /**
119
+ * Fetches git commit data with month and author information
120
+ * @param sinceDate - Date range for git log
121
+ */
122
+ fetchGitCommitData(sinceDate) {
123
+ const logProcess = spawnSync('git', [
124
+ 'log',
125
+ '--all', // Include committers on all branches in the repo
126
+ '--format="%ad|%an"', // Format: date|author
127
+ '--date=format:%Y-%m', // Format date as YYYY-MM
128
+ `--since="${sinceDate}"`,
129
+ ], { encoding: 'utf-8' });
130
+ if (logProcess.error) {
131
+ if (isErrnoException(logProcess.error)) {
132
+ if (logProcess.error.code === 'ENOENT') {
133
+ this.error('Git command not found. Please ensure git is installed and available in your PATH.');
134
+ }
135
+ this.error(`Git command failed: ${getErrorMessage(logProcess.error)}`);
136
+ }
137
+ this.error(`Git command failed: ${getErrorMessage(logProcess.error)}`);
138
+ }
139
+ if (logProcess.status !== 0) {
140
+ this.error(`Git command failed with status ${logProcess.status}: ${logProcess.stderr}`);
141
+ }
142
+ if (!logProcess.stdout) {
143
+ return [];
144
+ }
145
+ return parseGitLogOutput(logProcess.stdout);
146
+ }
147
+ }
@@ -0,0 +1,70 @@
1
+ export interface CommitEntry {
2
+ month: string;
3
+ author: string;
4
+ }
5
+ export interface AuthorCommitCounts {
6
+ [author: string]: number;
7
+ }
8
+ export interface MonthlyData {
9
+ [month: string]: AuthorCommitCounts;
10
+ }
11
+ export interface ReportData {
12
+ monthly: {
13
+ [month: string]: {
14
+ [author: string]: number;
15
+ total: number;
16
+ };
17
+ };
18
+ overall: {
19
+ [author: string]: number;
20
+ total: number;
21
+ };
22
+ }
23
+ /**
24
+ * Parses git log output into structured data
25
+ * @param output - Git log command output
26
+ * @returns Parsed commit entries
27
+ */
28
+ export declare function parseGitLogOutput(output: string): CommitEntry[];
29
+ /**
30
+ * Groups commit data by month
31
+ * @param entries - Commit entries
32
+ * @returns Object with months as keys and author commit counts as values
33
+ */
34
+ export declare function groupCommitsByMonth(entries: CommitEntry[]): MonthlyData;
35
+ /**
36
+ * Calculates overall commit statistics by author
37
+ * @param entries - Commit entries
38
+ * @returns Object with authors as keys and total commit counts as values
39
+ */
40
+ export declare function calculateOverallStats(entries: CommitEntry[]): AuthorCommitCounts;
41
+ /**
42
+ * Formats monthly report sections
43
+ * @param monthlyData - Grouped commit data by month
44
+ * @returns Formatted monthly report sections
45
+ */
46
+ export declare function formatMonthlyReport(monthlyData: MonthlyData): string;
47
+ /**
48
+ * Formats overall statistics section
49
+ * @param overallStats - Overall commit counts by author
50
+ * @param grandTotal - Total number of commits
51
+ * @returns Formatted overall statistics section
52
+ */
53
+ export declare function formatOverallStats(overallStats: AuthorCommitCounts, grandTotal: number): string;
54
+ /**
55
+ * Formats the report data as CSV
56
+ * @param data - The structured report data
57
+ */
58
+ export declare function formatAsCsv(data: ReportData): string;
59
+ /**
60
+ * Formats the report data as text
61
+ * @param data - The structured report data
62
+ */
63
+ export declare function formatAsText(data: ReportData): string;
64
+ /**
65
+ * Format output based on user preference
66
+ * @param output
67
+ * @param reportData
68
+ * @returns
69
+ */
70
+ export declare function formatOutputBasedOnFlag(output: string, reportData: ReportData): string;
@@ -0,0 +1,196 @@
1
+ /**
2
+ * Parses git log output into structured data
3
+ * @param output - Git log command output
4
+ * @returns Parsed commit entries
5
+ */
6
+ export function parseGitLogOutput(output) {
7
+ return output
8
+ .split('\n')
9
+ .filter(Boolean)
10
+ .map((line) => {
11
+ // Remove surrounding double quotes if present (e.g. "March|John Doe" → March|John Doe)
12
+ const [month, author] = line.replace(/^"(.*)"$/, '$1').split('|');
13
+ return { month, author };
14
+ });
15
+ }
16
+ /**
17
+ * Groups commit data by month
18
+ * @param entries - Commit entries
19
+ * @returns Object with months as keys and author commit counts as values
20
+ */
21
+ export function groupCommitsByMonth(entries) {
22
+ const result = {};
23
+ // Group commits by month
24
+ const commitsByMonth = entries.reduce((acc, entry) => {
25
+ const monthKey = entry.month;
26
+ if (!acc[monthKey]) {
27
+ acc[monthKey] = [];
28
+ }
29
+ acc[monthKey].push(entry);
30
+ return acc;
31
+ }, {});
32
+ // Process each month
33
+ for (const [month, commits] of Object.entries(commitsByMonth)) {
34
+ if (!commits) {
35
+ result[month] = {};
36
+ continue;
37
+ }
38
+ // Count commits per author for this month
39
+ const commitsByAuthor = commits.reduce((acc, entry) => {
40
+ const authorKey = entry.author;
41
+ if (!acc[authorKey]) {
42
+ acc[authorKey] = [];
43
+ }
44
+ acc[authorKey].push(entry);
45
+ return acc;
46
+ }, {});
47
+ const authorCounts = {};
48
+ for (const [author, authorCommits] of Object.entries(commitsByAuthor)) {
49
+ authorCounts[author] = authorCommits?.length ?? 0;
50
+ }
51
+ result[month] = authorCounts;
52
+ }
53
+ return result;
54
+ }
55
+ /**
56
+ * Calculates overall commit statistics by author
57
+ * @param entries - Commit entries
58
+ * @returns Object with authors as keys and total commit counts as values
59
+ */
60
+ export function calculateOverallStats(entries) {
61
+ const commitsByAuthor = entries.reduce((acc, entry) => {
62
+ const authorKey = entry.author;
63
+ if (!acc[authorKey]) {
64
+ acc[authorKey] = [];
65
+ }
66
+ acc[authorKey].push(entry);
67
+ return acc;
68
+ }, {});
69
+ const result = {};
70
+ // Count commits for each author
71
+ for (const author in commitsByAuthor) {
72
+ result[author] = commitsByAuthor[author]?.length ?? 0;
73
+ }
74
+ return result;
75
+ }
76
+ /**
77
+ * Formats monthly report sections
78
+ * @param monthlyData - Grouped commit data by month
79
+ * @returns Formatted monthly report sections
80
+ */
81
+ export function formatMonthlyReport(monthlyData) {
82
+ const sortedMonths = Object.keys(monthlyData).sort();
83
+ let report = '';
84
+ for (const month of sortedMonths) {
85
+ report += `\n## ${month}\n`;
86
+ const authors = Object.entries(monthlyData[month]).sort((a, b) => b[1] - a[1]);
87
+ for (const [author, count] of authors) {
88
+ report += `${count.toString().padStart(6)} ${author}\n`;
89
+ }
90
+ const monthTotal = authors.reduce((sum, [_, count]) => sum + count, 0);
91
+ report += `${monthTotal.toString().padStart(6)} TOTAL\n`;
92
+ }
93
+ return report;
94
+ }
95
+ /**
96
+ * Formats overall statistics section
97
+ * @param overallStats - Overall commit counts by author
98
+ * @param grandTotal - Total number of commits
99
+ * @returns Formatted overall statistics section
100
+ */
101
+ export function formatOverallStats(overallStats, grandTotal) {
102
+ let report = '\n## Overall Statistics\n';
103
+ const sortedStats = Object.entries(overallStats).sort((a, b) => b[1] - a[1]);
104
+ for (const [author, count] of sortedStats) {
105
+ report += `${count.toString().padStart(6)} ${author}\n`;
106
+ }
107
+ report += `${grandTotal.toString().padStart(6)} GRAND TOTAL\n`;
108
+ return report;
109
+ }
110
+ /**
111
+ * Formats the report data as CSV
112
+ * @param data - The structured report data
113
+ */
114
+ export function formatAsCsv(data) {
115
+ // First prepare all author names (for columns)
116
+ const allAuthors = new Set();
117
+ // Collect all unique author names
118
+ for (const monthData of Object.values(data.monthly)) {
119
+ for (const author of Object.keys(monthData)) {
120
+ if (author !== 'total')
121
+ allAuthors.add(author);
122
+ }
123
+ }
124
+ const authors = Array.from(allAuthors).sort();
125
+ // Create CSV header
126
+ let csv = `Month,${authors.join(',')},Total\n`;
127
+ // Add monthly data rows
128
+ const sortedMonths = Object.keys(data.monthly).sort();
129
+ for (const month of sortedMonths) {
130
+ csv += month;
131
+ // Add data for each author
132
+ for (const author of authors) {
133
+ const count = data.monthly[month][author] || 0;
134
+ csv += `,${count}`;
135
+ }
136
+ // Add monthly total
137
+ csv += `,${`${data.monthly[month].total}\n`}`;
138
+ }
139
+ // Add overall totals row
140
+ csv += 'Overall';
141
+ for (const author of authors) {
142
+ const count = data.overall[author] || 0;
143
+ csv += `,${count}`;
144
+ }
145
+ csv += `,${data.overall.total}\n`;
146
+ return csv;
147
+ }
148
+ /**
149
+ * Formats the report data as text
150
+ * @param data - The structured report data
151
+ */
152
+ export function formatAsText(data) {
153
+ let report = 'Monthly Commit Report\n';
154
+ // Monthly sections
155
+ const sortedMonths = Object.keys(data.monthly).sort();
156
+ for (const month of sortedMonths) {
157
+ report += `\n## ${month}\n`;
158
+ const authors = Object.entries(data.monthly[month])
159
+ .filter(([author]) => author !== 'total')
160
+ .sort((a, b) => b[1] - a[1]);
161
+ for (const [author, count] of authors) {
162
+ report += `${count.toString().padStart(6)} ${author}\n`;
163
+ }
164
+ report += `${data.monthly[month].total.toString().padStart(6)} TOTAL\n`;
165
+ }
166
+ // Overall statistics
167
+ report += '\n## Overall Statistics\n';
168
+ const sortedEntries = Object.entries(data.overall)
169
+ .filter(([author]) => author !== 'total')
170
+ .sort((a, b) => b[1] - a[1]);
171
+ for (const [author, count] of sortedEntries) {
172
+ report += `${count.toString().padStart(6)} ${author}\n`;
173
+ }
174
+ report += `${data.overall.total.toString().padStart(6)} GRAND TOTAL\n`;
175
+ return report;
176
+ }
177
+ /**
178
+ * Format output based on user preference
179
+ * @param output
180
+ * @param reportData
181
+ * @returns
182
+ */
183
+ export function formatOutputBasedOnFlag(output, reportData) {
184
+ let formattedOutput;
185
+ switch (output) {
186
+ case 'json':
187
+ formattedOutput = JSON.stringify(reportData, null, 2);
188
+ break;
189
+ case 'csv':
190
+ formattedOutput = formatAsCsv(reportData);
191
+ break;
192
+ default:
193
+ formattedOutput = formatAsText(reportData);
194
+ }
195
+ return formattedOutput;
196
+ }
@@ -0,0 +1,8 @@
1
+ export declare const isError: (error: unknown) => error is Error;
2
+ export declare const isErrnoException: (error: unknown) => error is NodeJS.ErrnoException;
3
+ export declare const isApolloError: (error: unknown) => error is ApolloError;
4
+ export declare const getErrorMessage: (error: unknown) => string;
5
+ export declare class ApolloError extends Error {
6
+ readonly originalError?: unknown;
7
+ constructor(message: string, original?: unknown);
8
+ }
@@ -0,0 +1,28 @@
1
+ export const isError = (error) => {
2
+ return error instanceof Error;
3
+ };
4
+ export const isErrnoException = (error) => {
5
+ return isError(error) && 'code' in error;
6
+ };
7
+ export const isApolloError = (error) => {
8
+ return error instanceof ApolloError;
9
+ };
10
+ export const getErrorMessage = (error) => {
11
+ if (isError(error)) {
12
+ return error.message;
13
+ }
14
+ return 'Unknown error';
15
+ };
16
+ export class ApolloError extends Error {
17
+ originalError;
18
+ constructor(message, original) {
19
+ if (isError(original)) {
20
+ super(`${message}: ${original.message}`);
21
+ }
22
+ else {
23
+ super(`${message}: ${String(original)}`);
24
+ }
25
+ this.name = 'ApolloError';
26
+ this.originalError = original;
27
+ }
28
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@herodevs/cli",
3
- "version": "2.0.0-beta.12",
3
+ "version": "2.0.0-beta.13",
4
4
  "author": "HeroDevs, Inc",
5
5
  "bin": {
6
6
  "hd": "./bin/run.js"
@@ -39,11 +39,11 @@
39
39
  "herodevs cli"
40
40
  ],
41
41
  "dependencies": {
42
- "@amplitude/analytics-node": "^1.5.20",
42
+ "@amplitude/analytics-node": "^1.5.21",
43
43
  "@apollo/client": "^3.13.8",
44
44
  "@cyclonedx/cdxgen": "^11.11.0",
45
- "@herodevs/eol-shared": "github:herodevs/eol-shared#v0.1.11",
46
- "@oclif/core": "^4.5.3",
45
+ "@herodevs/eol-shared": "github:herodevs/eol-shared#v0.1.12",
46
+ "@oclif/core": "^4.8.0",
47
47
  "@oclif/plugin-help": "^6.2.32",
48
48
  "@oclif/plugin-update": "^4.7.13",
49
49
  "node-machine-id": "^1.1.12",
@@ -53,10 +53,10 @@
53
53
  "update-notifier": "^7.3.1"
54
54
  },
55
55
  "devDependencies": {
56
- "@biomejs/biome": "^2.2.2",
56
+ "@biomejs/biome": "^2.3.3",
57
57
  "@oclif/test": "^4.1.13",
58
58
  "@types/inquirer": "^9.0.9",
59
- "@types/node": "^24.9.2",
59
+ "@types/node": "^24.10.0",
60
60
  "@types/sinon": "^17.0.4",
61
61
  "@types/update-notifier": "^6.0.8",
62
62
  "globstar": "^1.0.0",
@@ -110,4 +110,4 @@
110
110
  }
111
111
  },
112
112
  "types": "dist/index.d.ts"
113
- }
113
+ }