@herodevs/cli 1.0.0-beta.2 → 1.2.0-beta.1

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.
Files changed (45) hide show
  1. package/README.md +30 -325
  2. package/bin/dev.js +6 -6
  3. package/bin/run.js +3 -2
  4. package/dist/api/client.d.ts +0 -2
  5. package/dist/api/client.js +19 -18
  6. package/dist/api/nes/nes.client.d.ts +4 -0
  7. package/dist/api/nes/nes.client.js +11 -0
  8. package/dist/api/queries/nes/sbom.js +5 -0
  9. package/dist/api/types/nes.types.d.ts +17 -3
  10. package/dist/api/types/nes.types.js +11 -1
  11. package/dist/commands/report/committers.d.ts +3 -2
  12. package/dist/commands/report/committers.js +75 -33
  13. package/dist/commands/report/purls.d.ts +4 -2
  14. package/dist/commands/report/purls.js +51 -31
  15. package/dist/commands/scan/eol.d.ts +13 -4
  16. package/dist/commands/scan/eol.js +112 -37
  17. package/dist/commands/scan/sbom.d.ts +4 -1
  18. package/dist/commands/scan/sbom.js +86 -33
  19. package/dist/hooks/prerun.js +8 -0
  20. package/dist/service/committers.svc.js +24 -3
  21. package/dist/service/eol/cdx.svc.d.ts +52 -0
  22. package/dist/service/eol/cdx.svc.js +58 -62
  23. package/dist/service/eol/eol.svc.d.ts +0 -21
  24. package/dist/service/eol/eol.svc.js +2 -62
  25. package/dist/service/eol/sbom.worker.d.ts +1 -0
  26. package/dist/service/eol/sbom.worker.js +26 -0
  27. package/dist/service/error.svc.d.ts +8 -0
  28. package/dist/service/error.svc.js +28 -0
  29. package/dist/service/log.svc.d.ts +5 -8
  30. package/dist/service/log.svc.js +5 -18
  31. package/dist/service/nes/nes.svc.js +4 -3
  32. package/dist/service/purls.svc.js +1 -1
  33. package/dist/ui/date.ui.d.ts +1 -0
  34. package/dist/ui/date.ui.js +15 -0
  35. package/dist/ui/eol.ui.d.ts +4 -3
  36. package/dist/ui/eol.ui.js +56 -15
  37. package/dist/ui/shared.us.d.ts +3 -0
  38. package/dist/ui/shared.us.js +13 -0
  39. package/package.json +13 -14
  40. package/dist/hooks/init/update.d.ts +0 -2
  41. package/dist/hooks/init/update.js +0 -5
  42. package/dist/hooks/prerun/CommandContextHook.js +0 -8
  43. package/dist/service/line.svc.d.ts +0 -24
  44. package/dist/service/line.svc.js +0 -61
  45. /package/dist/hooks/{prerun/CommandContextHook.d.ts → prerun.d.ts} +0 -0
@@ -2,15 +2,16 @@ import { spawnSync } from 'node:child_process';
2
2
  import { Command, Flags } from '@oclif/core';
3
3
  import fs from 'node:fs';
4
4
  import path from 'node:path';
5
- import { calculateOverallStats, formatOutputBasedOnFlag, groupCommitsByMonth, parseGitLogOutput, } from "../../service/committers.svc.js";
5
+ import { calculateOverallStats, formatAsCsv, formatAsText, groupCommitsByMonth, parseGitLogOutput, } from "../../service/committers.svc.js";
6
+ import { getErrorMessage, isErrnoException } from "../../service/error.svc.js";
6
7
  export default class Committers extends Command {
7
8
  static description = 'Generate report of committers to a git repository';
8
9
  static enableJsonFlag = true;
9
10
  static examples = [
10
11
  '<%= config.bin %> <%= command.id %>',
11
- '<%= config.bin %> <%= command.id %> -o csv -s',
12
- '<%= config.bin %> <%= command.id %> --output=json',
13
- '<%= config.bin %> <%= command.id %> --output=csv',
12
+ '<%= config.bin %> <%= command.id %> --csv -s',
13
+ '<%= config.bin %> <%= command.id %> --json',
14
+ '<%= config.bin %> <%= command.id %> --csv',
14
15
  ];
15
16
  static flags = {
16
17
  months: Flags.integer({
@@ -18,11 +19,10 @@ export default class Committers extends Command {
18
19
  description: 'The number of months of git history to review',
19
20
  default: 12,
20
21
  }),
21
- output: Flags.string({
22
- char: 'o',
23
- description: 'Output format: text, json, or csv',
24
- options: ['text', 'json', 'csv'],
25
- default: 'text',
22
+ csv: Flags.boolean({
23
+ char: 'c',
24
+ description: 'Output in CSV format',
25
+ default: false,
26
26
  }),
27
27
  save: Flags.boolean({
28
28
  char: 's',
@@ -32,24 +32,63 @@ export default class Committers extends Command {
32
32
  };
33
33
  async run() {
34
34
  const { flags } = await this.parse(Committers);
35
- const { months, output, save } = flags;
35
+ const { months, csv, save } = flags;
36
+ const isJson = this.jsonEnabled();
36
37
  const sinceDate = `${months} months ago`;
38
+ this.log('Starting committers report with flags: %O', flags);
37
39
  try {
38
40
  // Generate structured report data
39
41
  const entries = this.fetchGitCommitData(sinceDate);
42
+ this.log('Fetched %d commit entries', entries.length);
40
43
  const reportData = this.generateReportData(entries);
41
- const formattedOutput = formatOutputBasedOnFlag(output, reportData);
42
- // Output to file or stdout
44
+ // Handle different output scenarios
45
+ if (isJson) {
46
+ // JSON mode
47
+ if (save) {
48
+ try {
49
+ fs.writeFileSync(path.resolve('nes.committers.json'), JSON.stringify(reportData, null, 2));
50
+ this.log('Report written to json');
51
+ }
52
+ catch (error) {
53
+ this.error(`Failed to save JSON report: ${getErrorMessage(error)}`);
54
+ }
55
+ }
56
+ return reportData;
57
+ }
58
+ const textOutput = formatAsText(reportData);
59
+ if (csv) {
60
+ // CSV mode
61
+ const csvOutput = formatAsCsv(reportData);
62
+ if (save) {
63
+ try {
64
+ fs.writeFileSync(path.resolve('nes.committers.csv'), csvOutput);
65
+ this.log('Report written to csv');
66
+ }
67
+ catch (error) {
68
+ this.error(`Failed to save CSV report: ${getErrorMessage(error)}`);
69
+ }
70
+ }
71
+ else {
72
+ this.log(textOutput);
73
+ }
74
+ return csvOutput;
75
+ }
43
76
  if (save) {
44
- fs.writeFileSync(path.resolve(`nes.committers.${output}`), formattedOutput);
45
- this.log(`Report written to ${output}`);
77
+ try {
78
+ fs.writeFileSync(path.resolve('nes.committers.txt'), textOutput);
79
+ this.log('Report written to txt');
80
+ }
81
+ catch (error) {
82
+ this.error(`Failed to save txt report: ${getErrorMessage(error)}`);
83
+ }
46
84
  }
47
85
  else {
48
- this.log(formattedOutput);
86
+ this.log(textOutput);
49
87
  }
88
+ return textOutput;
50
89
  }
51
90
  catch (error) {
52
- this.error(`Failed to generate report: ${error.message}`);
91
+ this.error(`Failed to generate report: ${getErrorMessage(error)}`);
53
92
  }
54
93
  }
55
94
  /**
@@ -80,25 +119,28 @@ export default class Committers extends Command {
80
119
  * @param sinceDate - Date range for git log
81
120
  */
82
121
  fetchGitCommitData(sinceDate) {
83
- try {
84
- const logProcess = spawnSync('git', [
85
- 'log',
86
- '--all', // Include committers on all branches in the repo
87
- '--format="%ad|%an"', // Format: date|author
88
- '--date=format:%Y-%m', // Format date as YYYY-MM
89
- `--since="${sinceDate}"`,
90
- ], { encoding: 'utf-8' });
91
- if (logProcess.error) {
92
- throw new Error(`Git command failed: ${logProcess.error.message}`);
122
+ const logProcess = spawnSync('git', [
123
+ 'log',
124
+ '--all', // Include committers on all branches in the repo
125
+ '--format="%ad|%an"', // Format: date|author
126
+ '--date=format:%Y-%m', // Format date as YYYY-MM
127
+ `--since="${sinceDate}"`,
128
+ ], { encoding: 'utf-8' });
129
+ if (logProcess.error) {
130
+ if (isErrnoException(logProcess.error)) {
131
+ if (logProcess.error.code === 'ENOENT') {
132
+ this.error('Git command not found. Please ensure git is installed and available in your PATH.');
133
+ }
134
+ this.error(`Git command failed: ${getErrorMessage(logProcess.error)}`);
93
135
  }
94
- if (!logProcess.stdout) {
95
- return [];
96
- }
97
- return parseGitLogOutput(logProcess.stdout);
136
+ this.error(`Git command failed: ${getErrorMessage(logProcess.error)}`);
98
137
  }
99
- catch (error) {
100
- this.error(`Failed to fetch git data: ${error.message}`);
101
- return []; // This line won't execute due to this.error() above
138
+ if (logProcess.status !== 0) {
139
+ this.error(`Git command failed with status ${logProcess.status}: ${logProcess.stderr}`);
140
+ }
141
+ if (!logProcess.stdout) {
142
+ return [];
102
143
  }
144
+ return parseGitLogOutput(logProcess.stdout);
103
145
  }
104
146
  }
@@ -7,7 +7,9 @@ export default class ReportPurls extends Command {
7
7
  file: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
8
8
  dir: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
9
9
  save: import("@oclif/core/interfaces").BooleanFlag<boolean>;
10
- output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
10
+ csv: import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
11
  };
12
- run(): Promise<string[]>;
12
+ run(): Promise<{
13
+ purls: string[];
14
+ }>;
13
15
  }
@@ -1,16 +1,18 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { Command, Flags, ux } from '@oclif/core';
4
+ import { getErrorMessage, isErrnoException } from "../../service/error.svc.js";
4
5
  import { extractPurls, getPurlOutput } from "../../service/purls.svc.js";
5
- import SbomScan from "../scan/sbom.js";
6
+ import ScanSbom from "../scan/sbom.js";
6
7
  export default class ReportPurls extends Command {
7
8
  static description = 'Generate a list of purls from a sbom';
8
9
  static enableJsonFlag = true;
9
10
  static examples = [
11
+ '<%= config.bin %> <%= command.id %> --json -s',
10
12
  '<%= config.bin %> <%= command.id %> --dir=./my-project',
11
13
  '<%= config.bin %> <%= command.id %> --file=path/to/sbom.json',
12
14
  '<%= config.bin %> <%= command.id %> --dir=./my-project --save',
13
- '<%= config.bin %> <%= command.id %> --save --output=csv',
15
+ '<%= config.bin %> <%= command.id %> --save --csv',
14
16
  ];
15
17
  static flags = {
16
18
  file: Flags.string({
@@ -26,41 +28,59 @@ export default class ReportPurls extends Command {
26
28
  default: false,
27
29
  description: 'Save the list of purls as nes.purls.<output>',
28
30
  }),
29
- output: Flags.string({
30
- char: 'o',
31
- options: ['json', 'csv'],
32
- default: 'json',
33
- description: 'The format of the saved file (when using --save)',
31
+ csv: Flags.boolean({
32
+ char: 'c',
33
+ default: false,
34
+ description: 'Save output in CSV format (only applies when using --save)',
34
35
  }),
35
36
  };
36
37
  async run() {
37
38
  const { flags } = await this.parse(ReportPurls);
38
- const { dir: _dirFlag, file: _fileFlag, save, output } = flags;
39
- // Load the SBOM: Only pass the file, dir, and save flags to SbomScan
40
- const sbomArgs = SbomScan.getSbomArgs(flags);
41
- const sbomCommand = new SbomScan(sbomArgs, this.config);
42
- const sbom = await sbomCommand.run();
43
- // Extract purls from SBOM
44
- const purls = await extractPurls(sbom);
45
- ux.action.stop('Scan completed');
46
- // Print the purls
47
- this.log('Found purls:');
48
- for (const purl of purls) {
49
- this.log(purl);
50
- }
51
- // Save if requested
52
- if (save) {
53
- try {
54
- const outputPath = path.join(_dirFlag || process.cwd(), `nes.purls.${output}`);
55
- const purlOutput = getPurlOutput(purls, output);
56
- fs.writeFileSync(outputPath, purlOutput);
57
- this.log(`\nPurls saved to ${outputPath}`);
39
+ const { dir: _dirFlag, file: _fileFlag, save, csv } = flags;
40
+ try {
41
+ const sbom = await ScanSbom.loadSbom(flags, this.config);
42
+ const purls = await extractPurls(sbom);
43
+ this.log('Extracted %d purls from SBOM', purls.length);
44
+ ux.action.stop('Scan completed');
45
+ // Print the purls
46
+ for (const purl of purls) {
47
+ this.log(purl);
58
48
  }
59
- catch (error) {
60
- const errorMessage = error && typeof error === 'object' && 'message' in error ? error.message : 'Unknown error';
61
- this.warn(`Failed to save purls: ${errorMessage}`);
49
+ // Save if requested
50
+ if (save) {
51
+ try {
52
+ const outputFile = csv && !this.jsonEnabled() ? 'csv' : 'json';
53
+ const outputPath = path.join(_dirFlag || process.cwd(), `nes.purls.${outputFile}`);
54
+ const purlOutput = getPurlOutput(purls, outputFile);
55
+ fs.writeFileSync(outputPath, purlOutput);
56
+ this.log('Purls saved to %s', outputPath);
57
+ }
58
+ catch (error) {
59
+ if (isErrnoException(error)) {
60
+ switch (error.code) {
61
+ case 'EACCES':
62
+ this.error('Permission denied: Cannot write to output file');
63
+ break;
64
+ case 'ENOSPC':
65
+ this.error('No space left on device');
66
+ break;
67
+ case 'EISDIR':
68
+ this.error('Cannot write to output file: Is a directory');
69
+ break;
70
+ default:
71
+ this.error(`Failed to save purls: ${getErrorMessage(error)}`);
72
+ }
73
+ }
74
+ this.error(`Failed to save purls: ${getErrorMessage(error)}`);
75
+ }
62
76
  }
77
+ // Return wrapped object with metadata
78
+ return {
79
+ purls,
80
+ };
81
+ }
82
+ catch (error) {
83
+ this.error(`Failed to generate PURLs: ${getErrorMessage(error)}`);
63
84
  }
64
- return purls;
65
85
  }
66
86
  }
@@ -1,5 +1,5 @@
1
1
  import { Command } from '@oclif/core';
2
- import type { ScanResult } from '../../api/types/nes.types.ts';
2
+ import type { ScanResultComponent } from '../../api/types/nes.types.ts';
3
3
  export default class ScanEol extends Command {
4
4
  static description: string;
5
5
  static enableJsonFlag: boolean;
@@ -8,9 +8,18 @@ export default class ScanEol extends Command {
8
8
  file: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
9
9
  dir: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
10
  save: import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
+ all: import("@oclif/core/interfaces").BooleanFlag<boolean>;
12
+ getCustomerSupport: import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
13
  };
12
- run(): Promise<ScanResult | {
13
- components: [];
14
+ run(): Promise<{
15
+ components: ScanResultComponent[];
14
16
  }>;
15
- private checkEolScanDisabled;
17
+ private scanSbom;
18
+ private getFilteredComponents;
19
+ private saveReport;
20
+ private displayResults;
21
+ private displayNoComponentsMessage;
22
+ private logLine;
23
+ private displayStatusSection;
24
+ private logLegend;
16
25
  }
@@ -1,13 +1,18 @@
1
+ import fs from 'node:fs';
1
2
  import { Command, Flags, ux } from '@oclif/core';
2
- import { prepareRows, scanForEol } from "../../service/eol/eol.svc.js";
3
- import { promptComponentDetails } from "../../ui/eol.ui.js";
4
- import SbomScan from "./sbom.js";
3
+ import { submitScan } from "../../api/nes/nes.client.js";
4
+ import { getErrorMessage, isErrnoException } from "../../service/error.svc.js";
5
+ import { extractPurls } from "../../service/purls.svc.js";
6
+ import { createStatusDisplay } from "../../ui/eol.ui.js";
7
+ import { INDICATORS, STATUS_COLORS } from "../../ui/shared.us.js";
8
+ import ScanSbom from "./sbom.js";
5
9
  export default class ScanEol extends Command {
6
10
  static description = 'Scan a given sbom for EOL data';
7
11
  static enableJsonFlag = true;
8
12
  static examples = [
9
13
  '<%= config.bin %> <%= command.id %> --dir=./my-project',
10
14
  '<%= config.bin %> <%= command.id %> --file=path/to/sbom.json',
15
+ '<%= config.bin %> <%= command.id %> -a --dir=./my-project',
11
16
  ];
12
17
  static flags = {
13
18
  file: Flags.string({
@@ -23,49 +28,119 @@ export default class ScanEol extends Command {
23
28
  default: false,
24
29
  description: 'Save the generated SBOM as nes.sbom.json in the scanned directory',
25
30
  }),
31
+ all: Flags.boolean({
32
+ char: 'a',
33
+ description: 'Show all components (default is EOL and LTS only)',
34
+ default: false,
35
+ }),
36
+ getCustomerSupport: Flags.boolean({
37
+ char: 'c',
38
+ description: 'Get Never-Ending Support for End-of-Life components',
39
+ default: false,
40
+ }),
26
41
  };
27
42
  async run() {
28
- this.checkEolScanDisabled();
29
43
  const { flags } = await this.parse(ScanEol);
30
- const { dir: _dirFlag, file: _fileFlag } = flags;
31
- // Load the SBOM: Only pass the file, dir, and save flags to SbomScan
32
- const sbomArgs = SbomScan.getSbomArgs(flags);
33
- const sbomCommand = new SbomScan(sbomArgs, this.config);
34
- const sbom = await sbomCommand.run();
35
- // Scan the SBOM for EOL information
36
- const { purls, scan } = await scanForEol(sbom);
37
- ux.action.stop('Scan completed');
38
- if (!scan?.components) {
39
- if (_fileFlag) {
40
- throw new Error(`Scan failed to generate for file path: ${_fileFlag}`);
44
+ if (flags.getCustomerSupport) {
45
+ this.log(ux.colorize('yellow', 'Never-Ending Support is on the way. Please stay tuned for this feature.'));
46
+ }
47
+ const sbom = await ScanSbom.loadSbom(flags, this.config);
48
+ const scan = await this.scanSbom(sbom);
49
+ ux.action.stop('\nScan completed');
50
+ const filteredComponents = this.getFilteredComponents(scan, flags.all);
51
+ if (flags.save) {
52
+ await this.saveReport(filteredComponents);
53
+ }
54
+ if (this.jsonEnabled()) {
55
+ return { components: filteredComponents };
56
+ }
57
+ await this.displayResults(scan, flags.all);
58
+ return { components: filteredComponents };
59
+ }
60
+ async scanSbom(sbom) {
61
+ let scan;
62
+ let purls;
63
+ try {
64
+ purls = await extractPurls(sbom);
65
+ }
66
+ catch (error) {
67
+ this.error(`Failed to extract purls from sbom. ${getErrorMessage(error)}`);
68
+ }
69
+ try {
70
+ scan = await submitScan(purls);
71
+ }
72
+ catch (error) {
73
+ this.error(`Failed to submit scan to NES from sbom. ${getErrorMessage(error)}`);
74
+ }
75
+ if (scan.components.size === 0) {
76
+ this.warn('No components found in scan');
77
+ }
78
+ return scan;
79
+ }
80
+ getFilteredComponents(scan, all) {
81
+ return Array.from(scan.components.entries())
82
+ .filter(([_, component]) => all || ['EOL', 'LTS'].includes(component.info.status))
83
+ .map(([_, component]) => component);
84
+ }
85
+ async saveReport(components) {
86
+ try {
87
+ fs.writeFileSync('nes.eol.json', JSON.stringify({ components }, null, 2));
88
+ this.log('Report saved to nes.eol.json');
89
+ }
90
+ catch (error) {
91
+ if (isErrnoException(error)) {
92
+ switch (error.code) {
93
+ case 'EACCES':
94
+ this.error('Permission denied. Unable to save report to nes.eol.json');
95
+ break;
96
+ case 'ENOSPC':
97
+ this.error('No space left on device. Unable to save report to nes.eol.json');
98
+ break;
99
+ default:
100
+ this.error(`Failed to save report: ${getErrorMessage(error)}`);
101
+ }
41
102
  }
42
- if (_dirFlag) {
43
- throw new Error(`Scan failed to generate for dir: ${_dirFlag}`);
103
+ else {
104
+ this.error(`Failed to save report: ${getErrorMessage(error)}`);
44
105
  }
45
- throw new Error('Scan failed to generate components.');
46
106
  }
47
- const lines = await prepareRows(purls, scan);
48
- if (lines?.length === 0) {
49
- this.log('No dependencies found');
50
- return { components: [] };
107
+ }
108
+ async displayResults(scan, all) {
109
+ const { UNKNOWN, OK, LTS, EOL } = createStatusDisplay(scan.components, all);
110
+ if (!UNKNOWN.length && !OK.length && !LTS.length && !EOL.length) {
111
+ this.displayNoComponentsMessage(all);
112
+ return;
113
+ }
114
+ this.log(ux.colorize('bold', 'Here are the results of the scan:'));
115
+ this.logLine();
116
+ // Display sections in order of increasing severity
117
+ for (const components of [UNKNOWN, OK, LTS, EOL]) {
118
+ this.displayStatusSection(components);
51
119
  }
52
- const r = await promptComponentDetails(lines);
53
- this.log('What now %o', r);
54
- return scan;
120
+ this.logLegend();
55
121
  }
56
- checkEolScanDisabled(override = true) {
57
- // Check if running in beta version or pre v1.0.0
58
- const version = this.config.version;
59
- const [major] = version.split('.').map(Number);
60
- if (version.includes('beta') || major < 1) {
61
- this.log(`VERSION=${version}`);
62
- throw new Error('The EOL scan feature is not available in beta releases. Please wait for the stable release.');
122
+ displayNoComponentsMessage(all) {
123
+ if (!all) {
124
+ this.log(ux.colorize('yellow', 'No End-of-Life or Long Term Support components found in scan.'));
125
+ this.log(ux.colorize('yellow', 'Use --all flag to view all components.'));
126
+ }
127
+ else {
128
+ this.log(ux.colorize('yellow', 'No components found in scan.'));
63
129
  }
64
- // Just in case the beta check fails
65
- if (override) {
66
- this.log(`VERSION=${version}`);
67
- this.log('EOL scan is disabled');
68
- return { components: [] };
130
+ }
131
+ logLine() {
132
+ this.log(ux.colorize('bold', '-'.repeat(50)));
133
+ }
134
+ displayStatusSection(components) {
135
+ if (components.length > 0) {
136
+ this.log(components.join('\n'));
137
+ this.logLine();
69
138
  }
70
139
  }
140
+ logLegend() {
141
+ this.log(ux.colorize(`${STATUS_COLORS.UNKNOWN}`, `${INDICATORS.UNKNOWN} = No Known Issues`));
142
+ this.log(ux.colorize(`${STATUS_COLORS.OK}`, `${INDICATORS.OK} = OK`));
143
+ this.log(ux.colorize(`${STATUS_COLORS.LTS}`, `${INDICATORS.LTS}= Long Term Support (LTS)`));
144
+ this.log(ux.colorize(`${STATUS_COLORS.EOL}`, `${INDICATORS.EOL} = End of Life (EOL)`));
145
+ }
71
146
  }
@@ -8,11 +8,14 @@ export default class ScanSbom extends Command {
8
8
  file: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
9
9
  dir: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
10
  save: import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
+ background: import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
12
  };
13
+ static loadSbom(flags: Record<string, string>, config: Command['config']): Promise<Sbom>;
12
14
  static getSbomArgs(flags: Record<string, string>): string[];
13
15
  getScanOptions(): {};
14
- run(): Promise<Sbom>;
16
+ run(): Promise<Sbom | undefined>;
15
17
  private _getSbomFromScan;
18
+ private _getSbomInBackground;
16
19
  private _getSbomFromFile;
17
20
  private _saveSbom;
18
21
  }