@shipsafe/cli 0.1.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.
Files changed (166) hide show
  1. package/README.md +167 -0
  2. package/dist/bin/shipsafe.d.ts +3 -0
  3. package/dist/bin/shipsafe.d.ts.map +1 -0
  4. package/dist/bin/shipsafe.js +33 -0
  5. package/dist/bin/shipsafe.js.map +1 -0
  6. package/dist/src/autofix/pr-generator.d.ts +48 -0
  7. package/dist/src/autofix/pr-generator.d.ts.map +1 -0
  8. package/dist/src/autofix/pr-generator.js +359 -0
  9. package/dist/src/autofix/pr-generator.js.map +1 -0
  10. package/dist/src/autofix/scaffolding.d.ts +26 -0
  11. package/dist/src/autofix/scaffolding.d.ts.map +1 -0
  12. package/dist/src/autofix/scaffolding.js +249 -0
  13. package/dist/src/autofix/scaffolding.js.map +1 -0
  14. package/dist/src/autofix/secret-fixer.d.ts +27 -0
  15. package/dist/src/autofix/secret-fixer.d.ts.map +1 -0
  16. package/dist/src/autofix/secret-fixer.js +138 -0
  17. package/dist/src/autofix/secret-fixer.js.map +1 -0
  18. package/dist/src/claude-md/manager.d.ts +17 -0
  19. package/dist/src/claude-md/manager.d.ts.map +1 -0
  20. package/dist/src/claude-md/manager.js +143 -0
  21. package/dist/src/claude-md/manager.js.map +1 -0
  22. package/dist/src/cli/activate.d.ts +4 -0
  23. package/dist/src/cli/activate.d.ts.map +1 -0
  24. package/dist/src/cli/activate.js +53 -0
  25. package/dist/src/cli/activate.js.map +1 -0
  26. package/dist/src/cli/config.d.ts +21 -0
  27. package/dist/src/cli/config.d.ts.map +1 -0
  28. package/dist/src/cli/config.js +128 -0
  29. package/dist/src/cli/config.js.map +1 -0
  30. package/dist/src/cli/connect.d.ts +36 -0
  31. package/dist/src/cli/connect.d.ts.map +1 -0
  32. package/dist/src/cli/connect.js +107 -0
  33. package/dist/src/cli/connect.js.map +1 -0
  34. package/dist/src/cli/init.d.ts +12 -0
  35. package/dist/src/cli/init.d.ts.map +1 -0
  36. package/dist/src/cli/init.js +45 -0
  37. package/dist/src/cli/init.js.map +1 -0
  38. package/dist/src/cli/license-check.d.ts +7 -0
  39. package/dist/src/cli/license-check.d.ts.map +1 -0
  40. package/dist/src/cli/license-check.js +69 -0
  41. package/dist/src/cli/license-check.js.map +1 -0
  42. package/dist/src/cli/license-gate.d.ts +9 -0
  43. package/dist/src/cli/license-gate.d.ts.map +1 -0
  44. package/dist/src/cli/license-gate.js +25 -0
  45. package/dist/src/cli/license-gate.js.map +1 -0
  46. package/dist/src/cli/scan.d.ts +9 -0
  47. package/dist/src/cli/scan.d.ts.map +1 -0
  48. package/dist/src/cli/scan.js +75 -0
  49. package/dist/src/cli/scan.js.map +1 -0
  50. package/dist/src/cli/setup.d.ts +27 -0
  51. package/dist/src/cli/setup.d.ts.map +1 -0
  52. package/dist/src/cli/setup.js +134 -0
  53. package/dist/src/cli/setup.js.map +1 -0
  54. package/dist/src/cli/status.d.ts +4 -0
  55. package/dist/src/cli/status.d.ts.map +1 -0
  56. package/dist/src/cli/status.js +52 -0
  57. package/dist/src/cli/status.js.map +1 -0
  58. package/dist/src/cli/upload-sourcemaps.d.ts +13 -0
  59. package/dist/src/cli/upload-sourcemaps.d.ts.map +1 -0
  60. package/dist/src/cli/upload-sourcemaps.js +157 -0
  61. package/dist/src/cli/upload-sourcemaps.js.map +1 -0
  62. package/dist/src/config/manager.d.ts +37 -0
  63. package/dist/src/config/manager.d.ts.map +1 -0
  64. package/dist/src/config/manager.js +131 -0
  65. package/dist/src/config/manager.js.map +1 -0
  66. package/dist/src/constants.d.ts +28 -0
  67. package/dist/src/constants.d.ts.map +1 -0
  68. package/dist/src/constants.js +34 -0
  69. package/dist/src/constants.js.map +1 -0
  70. package/dist/src/engines/graph/data-flow.d.ts +36 -0
  71. package/dist/src/engines/graph/data-flow.d.ts.map +1 -0
  72. package/dist/src/engines/graph/data-flow.js +189 -0
  73. package/dist/src/engines/graph/data-flow.js.map +1 -0
  74. package/dist/src/engines/graph/index.d.ts +20 -0
  75. package/dist/src/engines/graph/index.d.ts.map +1 -0
  76. package/dist/src/engines/graph/index.js +100 -0
  77. package/dist/src/engines/graph/index.js.map +1 -0
  78. package/dist/src/engines/graph/parser.d.ts +13 -0
  79. package/dist/src/engines/graph/parser.d.ts.map +1 -0
  80. package/dist/src/engines/graph/parser.js +620 -0
  81. package/dist/src/engines/graph/parser.js.map +1 -0
  82. package/dist/src/engines/graph/queries.d.ts +11 -0
  83. package/dist/src/engines/graph/queries.d.ts.map +1 -0
  84. package/dist/src/engines/graph/queries.js +196 -0
  85. package/dist/src/engines/graph/queries.js.map +1 -0
  86. package/dist/src/engines/graph/store.d.ts +35 -0
  87. package/dist/src/engines/graph/store.d.ts.map +1 -0
  88. package/dist/src/engines/graph/store.js +284 -0
  89. package/dist/src/engines/graph/store.js.map +1 -0
  90. package/dist/src/engines/pattern/gitleaks.d.ts +4 -0
  91. package/dist/src/engines/pattern/gitleaks.d.ts.map +1 -0
  92. package/dist/src/engines/pattern/gitleaks.js +78 -0
  93. package/dist/src/engines/pattern/gitleaks.js.map +1 -0
  94. package/dist/src/engines/pattern/index.d.ts +11 -0
  95. package/dist/src/engines/pattern/index.d.ts.map +1 -0
  96. package/dist/src/engines/pattern/index.js +111 -0
  97. package/dist/src/engines/pattern/index.js.map +1 -0
  98. package/dist/src/engines/pattern/semgrep.d.ts +4 -0
  99. package/dist/src/engines/pattern/semgrep.d.ts.map +1 -0
  100. package/dist/src/engines/pattern/semgrep.js +83 -0
  101. package/dist/src/engines/pattern/semgrep.js.map +1 -0
  102. package/dist/src/engines/pattern/trivy.d.ts +4 -0
  103. package/dist/src/engines/pattern/trivy.d.ts.map +1 -0
  104. package/dist/src/engines/pattern/trivy.js +90 -0
  105. package/dist/src/engines/pattern/trivy.js.map +1 -0
  106. package/dist/src/github/api.d.ts +19 -0
  107. package/dist/src/github/api.d.ts.map +1 -0
  108. package/dist/src/github/api.js +75 -0
  109. package/dist/src/github/api.js.map +1 -0
  110. package/dist/src/github/app-manifest.d.ts +28 -0
  111. package/dist/src/github/app-manifest.d.ts.map +1 -0
  112. package/dist/src/github/app-manifest.js +27 -0
  113. package/dist/src/github/app-manifest.js.map +1 -0
  114. package/dist/src/github/checks.d.ts +36 -0
  115. package/dist/src/github/checks.d.ts.map +1 -0
  116. package/dist/src/github/checks.js +90 -0
  117. package/dist/src/github/checks.js.map +1 -0
  118. package/dist/src/github/scanner.d.ts +20 -0
  119. package/dist/src/github/scanner.d.ts.map +1 -0
  120. package/dist/src/github/scanner.js +78 -0
  121. package/dist/src/github/scanner.js.map +1 -0
  122. package/dist/src/github/webhook.d.ts +39 -0
  123. package/dist/src/github/webhook.d.ts.map +1 -0
  124. package/dist/src/github/webhook.js +80 -0
  125. package/dist/src/github/webhook.js.map +1 -0
  126. package/dist/src/hooks/installer.d.ts +4 -0
  127. package/dist/src/hooks/installer.d.ts.map +1 -0
  128. package/dist/src/hooks/installer.js +146 -0
  129. package/dist/src/hooks/installer.js.map +1 -0
  130. package/dist/src/mcp/server.d.ts +2 -0
  131. package/dist/src/mcp/server.d.ts.map +1 -0
  132. package/dist/src/mcp/server.js +96 -0
  133. package/dist/src/mcp/server.js.map +1 -0
  134. package/dist/src/mcp/tools/check-package.d.ts +30 -0
  135. package/dist/src/mcp/tools/check-package.d.ts.map +1 -0
  136. package/dist/src/mcp/tools/check-package.js +196 -0
  137. package/dist/src/mcp/tools/check-package.js.map +1 -0
  138. package/dist/src/mcp/tools/fix.d.ts +41 -0
  139. package/dist/src/mcp/tools/fix.d.ts.map +1 -0
  140. package/dist/src/mcp/tools/fix.js +98 -0
  141. package/dist/src/mcp/tools/fix.js.map +1 -0
  142. package/dist/src/mcp/tools/graph-query.d.ts +7 -0
  143. package/dist/src/mcp/tools/graph-query.d.ts.map +1 -0
  144. package/dist/src/mcp/tools/graph-query.js +139 -0
  145. package/dist/src/mcp/tools/graph-query.js.map +1 -0
  146. package/dist/src/mcp/tools/production-errors.d.ts +23 -0
  147. package/dist/src/mcp/tools/production-errors.d.ts.map +1 -0
  148. package/dist/src/mcp/tools/production-errors.js +46 -0
  149. package/dist/src/mcp/tools/production-errors.js.map +1 -0
  150. package/dist/src/mcp/tools/scan.d.ts +7 -0
  151. package/dist/src/mcp/tools/scan.d.ts.map +1 -0
  152. package/dist/src/mcp/tools/scan.js +9 -0
  153. package/dist/src/mcp/tools/scan.js.map +1 -0
  154. package/dist/src/mcp/tools/status.d.ts +9 -0
  155. package/dist/src/mcp/tools/status.d.ts.map +1 -0
  156. package/dist/src/mcp/tools/status.js +18 -0
  157. package/dist/src/mcp/tools/status.js.map +1 -0
  158. package/dist/src/mcp/tools/verify-resolution.d.ts +12 -0
  159. package/dist/src/mcp/tools/verify-resolution.d.ts.map +1 -0
  160. package/dist/src/mcp/tools/verify-resolution.js +45 -0
  161. package/dist/src/mcp/tools/verify-resolution.js.map +1 -0
  162. package/dist/src/types.d.ts +136 -0
  163. package/dist/src/types.d.ts.map +1 -0
  164. package/dist/src/types.js +2 -0
  165. package/dist/src/types.js.map +1 -0
  166. package/package.json +53 -0
@@ -0,0 +1,53 @@
1
+ import chalk from 'chalk';
2
+ import { loadGlobalConfig, saveGlobalConfig, getApiEndpoint } from '../config/manager.js';
3
+ export async function handleActivateAction(licenseKey) {
4
+ const config = await loadGlobalConfig();
5
+ // First save the license key
6
+ await saveGlobalConfig({ ...config, licenseKey });
7
+ // Attempt online validation
8
+ const apiEndpoint = getApiEndpoint(config);
9
+ try {
10
+ const response = await fetch(`${apiEndpoint}/v1/license/validate`, {
11
+ method: 'POST',
12
+ headers: { 'Content-Type': 'application/json' },
13
+ body: JSON.stringify({ license_key: licenseKey }),
14
+ });
15
+ if (!response.ok) {
16
+ const body = (await response.json().catch(() => ({})));
17
+ const message = typeof body['message'] === 'string' ? body['message'] : 'Invalid license key.';
18
+ console.log(chalk.red(`\nLicense validation failed: ${message}`));
19
+ const { licenseKey: _removed, ...rest } = { ...config, licenseKey };
20
+ void _removed;
21
+ await saveGlobalConfig(rest);
22
+ return;
23
+ }
24
+ const data = (await response.json());
25
+ if (!data.valid) {
26
+ console.log(chalk.red(`\nLicense key is not valid.`));
27
+ const { licenseKey: _removed, ...rest } = { ...config, licenseKey };
28
+ void _removed;
29
+ await saveGlobalConfig(rest);
30
+ return;
31
+ }
32
+ await saveGlobalConfig({
33
+ ...config,
34
+ licenseKey,
35
+ licenseValidatedAt: new Date().toISOString(),
36
+ licenseTier: data.tier,
37
+ });
38
+ console.log(chalk.green(`\nShipSafe Pro activated successfully!`));
39
+ console.log(`License key saved. Thank you for supporting ShipSafe.\n`);
40
+ }
41
+ catch {
42
+ console.log(chalk.yellow(`\nCould not validate online. License saved locally.`));
43
+ }
44
+ }
45
+ export function registerActivateCommand(program) {
46
+ program
47
+ .command('activate <license-key>')
48
+ .description('Activate ShipSafe Pro with a license key')
49
+ .action(async (licenseKey) => {
50
+ await handleActivateAction(licenseKey);
51
+ });
52
+ }
53
+ //# sourceMappingURL=activate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"activate.js","sourceRoot":"","sources":["../../../src/cli/activate.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE1F,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,UAAkB;IAC3D,MAAM,MAAM,GAAG,MAAM,gBAAgB,EAAE,CAAC;IAExC,6BAA6B;IAC7B,MAAM,gBAAgB,CAAC,EAAE,GAAG,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;IAElD,4BAA4B;IAC5B,MAAM,WAAW,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IAC3C,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,WAAW,sBAAsB,EAAE;YACjE,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC;SAClD,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAA4B,CAAC;YAClF,MAAM,OAAO,GACX,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,sBAAsB,CAAC;YACjF,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,gCAAgC,OAAO,EAAE,CAAC,CAAC,CAAC;YAClE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,MAAM,EAAE,UAAU,EAAE,CAAC;YACpE,KAAK,QAAQ,CAAC;YACd,MAAM,gBAAgB,CAAC,IAAI,CAAC,CAAC;YAC7B,OAAO;QACT,CAAC;QAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAKlC,CAAC;QAEF,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YAChB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC,CAAC;YACtD,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,MAAM,EAAE,UAAU,EAAE,CAAC;YACpE,KAAK,QAAQ,CAAC;YACd,MAAM,gBAAgB,CAAC,IAAI,CAAC,CAAC;YAC7B,OAAO;QACT,CAAC;QAED,MAAM,gBAAgB,CAAC;YACrB,GAAG,MAAM;YACT,UAAU;YACV,kBAAkB,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YAC5C,WAAW,EAAE,IAAI,CAAC,IAAI;SACvB,CAAC,CAAC;QAEH,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAC,CAAC;QACnE,OAAO,CAAC,GAAG,CAAC,yDAAyD,CAAC,CAAC;IACzE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,MAAM,CAAC,qDAAqD,CAAC,CACpE,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,OAAgB;IACtD,OAAO;SACJ,OAAO,CAAC,wBAAwB,CAAC;SACjC,WAAW,CAAC,0CAA0C,CAAC;SACvD,MAAM,CAAC,KAAK,EAAE,UAAkB,EAAE,EAAE;QACnC,MAAM,oBAAoB,CAAC,UAAU,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,21 @@
1
+ import { Command } from 'commander';
2
+ export interface ConfigSetOptions {
3
+ global: boolean;
4
+ }
5
+ /**
6
+ * Shows the full merged config (defaults < global < project).
7
+ */
8
+ export declare function handleConfigList(): Promise<void>;
9
+ /**
10
+ * Gets a specific config value by dot-notation key.
11
+ * Exits with code 1 if the key is not found.
12
+ */
13
+ export declare function handleConfigGet(key: string): Promise<void>;
14
+ /**
15
+ * Sets a config value by dot-notation key.
16
+ * Reads the existing config, merges the new value, and saves.
17
+ * Saves to global config if --global flag is set, otherwise project config.
18
+ */
19
+ export declare function handleConfigSet(key: string, rawValue: string, options: ConfigSetOptions): Promise<void>;
20
+ export declare function registerConfigCommand(program: Command): void;
21
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/cli/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASpC,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,OAAO,CAAC;CACjB;AA8DD;;GAEG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAGtD;AAED;;;GAGG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAWhE;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,IAAI,CAAC,CAsBf;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA0B5D"}
@@ -0,0 +1,128 @@
1
+ import { loadConfig, loadGlobalConfig, saveGlobalConfig, saveProjectConfig, } from '../config/manager.js';
2
+ /**
3
+ * Traverses a nested object using dot-separated key path.
4
+ * Returns the value at the path, or undefined if any segment is missing.
5
+ */
6
+ function getNestedValue(obj, keyPath) {
7
+ const segments = keyPath.split('.');
8
+ let current = obj;
9
+ for (const segment of segments) {
10
+ if (current === null || current === undefined || typeof current !== 'object' || Array.isArray(current)) {
11
+ return undefined;
12
+ }
13
+ current = current[segment];
14
+ }
15
+ return current;
16
+ }
17
+ /**
18
+ * Sets a value on a nested object using dot-separated key path.
19
+ * Creates intermediate objects as needed.
20
+ */
21
+ function setNestedValue(obj, keyPath, value) {
22
+ const segments = keyPath.split('.');
23
+ let current = obj;
24
+ for (let i = 0; i < segments.length - 1; i++) {
25
+ const segment = segments[i];
26
+ if (current[segment] === null || current[segment] === undefined || typeof current[segment] !== 'object' || Array.isArray(current[segment])) {
27
+ current[segment] = {};
28
+ }
29
+ current = current[segment];
30
+ }
31
+ current[segments[segments.length - 1]] = value;
32
+ }
33
+ /**
34
+ * Parses a string value into the appropriate type:
35
+ * "true" → true, "false" → false, numeric strings → numbers, otherwise string.
36
+ */
37
+ function parseValue(raw) {
38
+ if (raw === 'true')
39
+ return true;
40
+ if (raw === 'false')
41
+ return false;
42
+ const num = Number(raw);
43
+ if (!isNaN(num) && raw.trim() !== '')
44
+ return num;
45
+ return raw;
46
+ }
47
+ /**
48
+ * Formats a value for console output:
49
+ * Objects/arrays → JSON.stringify, primitives → String().
50
+ */
51
+ function formatValue(value) {
52
+ if (value !== null && value !== undefined && typeof value === 'object') {
53
+ return JSON.stringify(value, null, 2);
54
+ }
55
+ return String(value);
56
+ }
57
+ /**
58
+ * Shows the full merged config (defaults < global < project).
59
+ */
60
+ export async function handleConfigList() {
61
+ const config = await loadConfig();
62
+ console.log(JSON.stringify(config, null, 2));
63
+ }
64
+ /**
65
+ * Gets a specific config value by dot-notation key.
66
+ * Exits with code 1 if the key is not found.
67
+ */
68
+ export async function handleConfigGet(key) {
69
+ const config = await loadConfig();
70
+ const value = getNestedValue(config, key);
71
+ if (value === undefined) {
72
+ console.log(`Key not found: ${key}`);
73
+ process.exit(1);
74
+ return;
75
+ }
76
+ console.log(formatValue(value));
77
+ }
78
+ /**
79
+ * Sets a config value by dot-notation key.
80
+ * Reads the existing config, merges the new value, and saves.
81
+ * Saves to global config if --global flag is set, otherwise project config.
82
+ */
83
+ export async function handleConfigSet(key, rawValue, options) {
84
+ const parsedValue = parseValue(rawValue);
85
+ const location = options.global ? 'global' : 'project';
86
+ let existing;
87
+ if (options.global) {
88
+ existing = await loadGlobalConfig();
89
+ }
90
+ else {
91
+ existing = await loadConfig();
92
+ }
93
+ // Deep-clone to avoid mutating the returned config object
94
+ const config = JSON.parse(JSON.stringify(existing));
95
+ setNestedValue(config, key, parsedValue);
96
+ if (options.global) {
97
+ await saveGlobalConfig(config);
98
+ }
99
+ else {
100
+ await saveProjectConfig(config);
101
+ }
102
+ console.log(`Set ${key} = ${formatValue(parsedValue)} in ${location} config`);
103
+ }
104
+ export function registerConfigCommand(program) {
105
+ const configCmd = program
106
+ .command('config')
107
+ .description('View and set ShipSafe configuration');
108
+ configCmd
109
+ .command('list')
110
+ .description('Show merged config (all values)')
111
+ .action(async () => {
112
+ await handleConfigList();
113
+ });
114
+ configCmd
115
+ .command('get <key>')
116
+ .description('Get a specific config value (supports dot notation: monitoring.enabled)')
117
+ .action(async (key) => {
118
+ await handleConfigGet(key);
119
+ });
120
+ configCmd
121
+ .command('set <key> <value>')
122
+ .description('Set a config value (supports dot notation; use --global for global config)')
123
+ .option('--global', 'Save to global config (~/.shipsafe/config.json)', false)
124
+ .action(async (key, value, options) => {
125
+ await handleConfigSet(key, value, options);
126
+ });
127
+ }
128
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/cli/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ import { Command } from 'commander';
2
+ export interface GitHubConnectionConfig {
3
+ connected: boolean;
4
+ connectedAt: string;
5
+ appUrl: string;
6
+ }
7
+ /**
8
+ * Get the path to the global ShipSafe config directory.
9
+ */
10
+ export declare function getGlobalConfigDir(): string;
11
+ /**
12
+ * Get the path to the GitHub connection config file.
13
+ */
14
+ export declare function getGitHubConfigPath(): string;
15
+ /**
16
+ * Check if the GitHub App is already connected.
17
+ */
18
+ export declare function isConnected(): Promise<boolean>;
19
+ /**
20
+ * Save the GitHub connection config.
21
+ */
22
+ export declare function saveConnectionConfig(): Promise<void>;
23
+ /**
24
+ * Open a URL in the default browser.
25
+ * Uses platform-appropriate command.
26
+ */
27
+ export declare function openInBrowser(url: string): void;
28
+ /**
29
+ * Main connect action — guides user through GitHub App installation.
30
+ */
31
+ export declare function handleConnectAction(): Promise<void>;
32
+ /**
33
+ * Register the 'connect' command with the CLI program.
34
+ */
35
+ export declare function registerConnectCommand(program: Command): void;
36
+ //# sourceMappingURL=connect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connect.d.ts","sourceRoot":"","sources":["../../../src/cli/connect.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C;AAED;;GAEG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,CASpD;AAED;;GAEG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC,CAW1D;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAmB/C;AAED;;GAEG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAwBzD;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAO7D"}
@@ -0,0 +1,107 @@
1
+ import * as fs from 'node:fs/promises';
2
+ import * as path from 'node:path';
3
+ import { homedir } from 'node:os';
4
+ import { execFile } from 'node:child_process';
5
+ import chalk from 'chalk';
6
+ import { GLOBAL_DIR_NAME } from '../constants.js';
7
+ const GITHUB_APP_URL = 'https://github.com/apps/shipsafe';
8
+ const CONFIG_FILE_NAME = 'github.json';
9
+ /**
10
+ * Get the path to the global ShipSafe config directory.
11
+ */
12
+ export function getGlobalConfigDir() {
13
+ return path.join(homedir(), GLOBAL_DIR_NAME);
14
+ }
15
+ /**
16
+ * Get the path to the GitHub connection config file.
17
+ */
18
+ export function getGitHubConfigPath() {
19
+ return path.join(getGlobalConfigDir(), CONFIG_FILE_NAME);
20
+ }
21
+ /**
22
+ * Check if the GitHub App is already connected.
23
+ */
24
+ export async function isConnected() {
25
+ try {
26
+ const configPath = getGitHubConfigPath();
27
+ const raw = await fs.readFile(configPath, 'utf-8');
28
+ const config = JSON.parse(raw);
29
+ return config.connected === true;
30
+ }
31
+ catch {
32
+ return false;
33
+ }
34
+ }
35
+ /**
36
+ * Save the GitHub connection config.
37
+ */
38
+ export async function saveConnectionConfig() {
39
+ const configDir = getGlobalConfigDir();
40
+ await fs.mkdir(configDir, { recursive: true });
41
+ const config = {
42
+ connected: true,
43
+ connectedAt: new Date().toISOString(),
44
+ appUrl: GITHUB_APP_URL,
45
+ };
46
+ await fs.writeFile(getGitHubConfigPath(), JSON.stringify(config, null, 2) + '\n', 'utf-8');
47
+ }
48
+ /**
49
+ * Open a URL in the default browser.
50
+ * Uses platform-appropriate command.
51
+ */
52
+ export function openInBrowser(url) {
53
+ const platform = process.platform;
54
+ let command;
55
+ let args;
56
+ if (platform === 'darwin') {
57
+ command = 'open';
58
+ args = [url];
59
+ }
60
+ else if (platform === 'win32') {
61
+ command = 'cmd';
62
+ args = ['/c', 'start', '', url];
63
+ }
64
+ else {
65
+ command = 'xdg-open';
66
+ args = [url];
67
+ }
68
+ execFile(command, args, () => {
69
+ // Silently ignore errors — user can open the URL manually
70
+ });
71
+ }
72
+ /**
73
+ * Main connect action — guides user through GitHub App installation.
74
+ */
75
+ export async function handleConnectAction() {
76
+ // 1. Check if already connected
77
+ const alreadyConnected = await isConnected();
78
+ if (alreadyConnected) {
79
+ console.log(chalk.green('GitHub App is already connected!'));
80
+ console.log(`PRs will be scanned automatically.`);
81
+ console.log(`\nTo reinstall, visit: ${GITHUB_APP_URL}`);
82
+ return;
83
+ }
84
+ // 2. Print instructions
85
+ console.log(chalk.bold('Connect ShipSafe to GitHub\n'));
86
+ console.log(`Install the ShipSafe GitHub App to enable automatic PR scanning.`);
87
+ console.log(`\nVisit: ${chalk.cyan(GITHUB_APP_URL)}`);
88
+ // 3. Open the URL in the default browser
89
+ openInBrowser(GITHUB_APP_URL);
90
+ console.log(`\nOpening browser...`);
91
+ // 4. Save connection info (the user will complete setup on GitHub)
92
+ await saveConnectionConfig();
93
+ // 5. Print confirmation
94
+ console.log(chalk.green('\nGitHub App connected! PRs will now be scanned automatically.'));
95
+ }
96
+ /**
97
+ * Register the 'connect' command with the CLI program.
98
+ */
99
+ export function registerConnectCommand(program) {
100
+ program
101
+ .command('connect')
102
+ .description('Connect ShipSafe to GitHub (install GitHub App)')
103
+ .action(async () => {
104
+ await handleConnectAction();
105
+ });
106
+ }
107
+ //# sourceMappingURL=connect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connect.js","sourceRoot":"","sources":["../../../src/cli/connect.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { Command } from 'commander';
2
+ export interface InitOptions {
3
+ projectDir?: string;
4
+ skipSetup?: boolean;
5
+ }
6
+ /**
7
+ * Main init action — bootstraps a project with a project ID, config file,
8
+ * and optional setup (hooks, MCP, CLAUDE.md).
9
+ */
10
+ export declare function handleInitAction(options: InitOptions): Promise<void>;
11
+ export declare function registerInitCommand(program: Command): void;
12
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/init.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,MAAM,WAAW,WAAW;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAkC1E;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAU1D"}
@@ -0,0 +1,45 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import chalk from 'chalk';
3
+ import { loadProjectConfig, saveProjectConfig } from '../config/manager.js';
4
+ import { handleSetupAction } from './setup.js';
5
+ /**
6
+ * Main init action — bootstraps a project with a project ID, config file,
7
+ * and optional setup (hooks, MCP, CLAUDE.md).
8
+ */
9
+ export async function handleInitAction(options) {
10
+ const { projectDir, skipSetup = false } = options;
11
+ // Load existing config to check for an existing projectId
12
+ const existingConfig = await loadProjectConfig(projectDir);
13
+ if (existingConfig.projectId) {
14
+ console.warn(chalk.yellow('⚠') +
15
+ ` ShipSafe is already initialized (projectId: ${existingConfig.projectId}). Skipping config creation.`);
16
+ return;
17
+ }
18
+ // Generate a new project ID
19
+ const projectId = `proj_${randomUUID().slice(0, 12)}`;
20
+ // Write the project config
21
+ await saveProjectConfig({ projectId }, projectDir);
22
+ console.log(chalk.green('✓') + ` Created shipsafe.config.json (projectId: ${projectId})`);
23
+ // Run setup unless explicitly skipped
24
+ if (!skipSetup) {
25
+ await handleSetupAction({});
26
+ }
27
+ // Print getting-started instructions
28
+ console.log('');
29
+ console.log(chalk.bold('ShipSafe initialized! Next steps:'));
30
+ console.log(' 1. Run ' + chalk.cyan('shipsafe scan') + ' to run your first security scan');
31
+ console.log(' 2. Run ' + chalk.cyan('shipsafe status') + ' to view your project security score');
32
+ console.log(' 3. Run ' + chalk.cyan('shipsafe activate') + ' to unlock full scanning with a license key');
33
+ }
34
+ export function registerInitCommand(program) {
35
+ program
36
+ .command('init')
37
+ .description('Initialize ShipSafe for the current project')
38
+ .option('--skip-setup', 'Skip hooks, MCP, and CLAUDE.md setup')
39
+ .action(async (options) => {
40
+ await handleInitAction({
41
+ skipSetup: options.skipSetup,
42
+ });
43
+ });
44
+ }
45
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../../src/cli/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAC5E,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAO/C;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,OAAoB;IACzD,MAAM,EAAE,UAAU,EAAE,SAAS,GAAG,KAAK,EAAE,GAAG,OAAO,CAAC;IAElD,0DAA0D;IAC1D,MAAM,cAAc,GAAG,MAAM,iBAAiB,CAAC,UAAU,CAAC,CAAC;IAE3D,IAAI,cAAc,CAAC,SAAS,EAAE,CAAC;QAC7B,OAAO,CAAC,IAAI,CACV,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC;YACf,gDAAgD,cAAc,CAAC,SAAS,8BAA8B,CACzG,CAAC;QACF,OAAO;IACT,CAAC;IAED,4BAA4B;IAC5B,MAAM,SAAS,GAAG,QAAQ,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;IAEtD,2BAA2B;IAC3B,MAAM,iBAAiB,CAAC,EAAE,SAAS,EAAE,EAAE,UAAU,CAAC,CAAC;IACnD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,6CAA6C,SAAS,GAAG,CAAC,CAAC;IAE1F,sCAAsC;IACtC,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,iBAAiB,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC;IAED,qCAAqC;IACrC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,mCAAmC,CAAC,CAAC,CAAC;IAC7D,OAAO,CAAC,GAAG,CAAC,WAAW,GAAG,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,GAAG,kCAAkC,CAAC,CAAC;IAC5F,OAAO,CAAC,GAAG,CAAC,WAAW,GAAG,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,GAAG,sCAAsC,CAAC,CAAC;IAClG,OAAO,CAAC,GAAG,CACT,WAAW,GAAG,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,GAAG,6CAA6C,CAC9F,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,OAAgB;IAClD,OAAO;SACJ,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,6CAA6C,CAAC;SAC1D,MAAM,CAAC,cAAc,EAAE,sCAAsC,CAAC;SAC9D,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;QACxB,MAAM,gBAAgB,CAAC;YACrB,SAAS,EAAE,OAAO,CAAC,SAAS;SAC7B,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,7 @@
1
+ export interface LicenseCheckResult {
2
+ valid: boolean;
3
+ tier: string;
4
+ reason?: string;
5
+ }
6
+ export declare function checkLicense(): Promise<LicenseCheckResult>;
7
+ //# sourceMappingURL=license-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"license-check.d.ts","sourceRoot":"","sources":["../../../src/cli/license-check.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAyBD,wBAAsB,YAAY,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAyDhE"}
@@ -0,0 +1,69 @@
1
+ import { loadGlobalConfig, saveGlobalConfig, getApiEndpoint } from '../config/manager.js';
2
+ const THIRTY_DAYS_MS = 30 * 24 * 60 * 60 * 1000;
3
+ async function validateOnline(apiEndpoint, licenseKey) {
4
+ try {
5
+ const response = await fetch(`${apiEndpoint}/v1/license/validate`, {
6
+ method: 'POST',
7
+ headers: { 'Content-Type': 'application/json' },
8
+ body: JSON.stringify({ license_key: licenseKey }),
9
+ });
10
+ if (!response.ok) {
11
+ return { valid: false, tier: 'free' };
12
+ }
13
+ const data = (await response.json());
14
+ return { valid: data.valid, tier: data.tier };
15
+ }
16
+ catch {
17
+ // Network error
18
+ return null;
19
+ }
20
+ }
21
+ export async function checkLicense() {
22
+ const config = await loadGlobalConfig();
23
+ // No license key at all
24
+ if (!config.licenseKey) {
25
+ return { valid: false, tier: 'free', reason: 'No license key' };
26
+ }
27
+ const now = Date.now();
28
+ if (config.licenseValidatedAt) {
29
+ const validatedAt = new Date(config.licenseValidatedAt).getTime();
30
+ const age = now - validatedAt;
31
+ if (age < THIRTY_DAYS_MS) {
32
+ // Fresh cache — return cached result
33
+ return { valid: true, tier: config.licenseTier ?? 'unknown' };
34
+ }
35
+ // Cache expired — try to re-validate online
36
+ const endpoint = getApiEndpoint(config);
37
+ const result = await validateOnline(endpoint, config.licenseKey);
38
+ if (result !== null) {
39
+ // Online validation succeeded — update cache
40
+ await saveGlobalConfig({
41
+ ...config,
42
+ licenseValidatedAt: new Date().toISOString(),
43
+ licenseTier: result.tier,
44
+ });
45
+ return { valid: result.valid, tier: result.tier };
46
+ }
47
+ // Offline with expired cache
48
+ return {
49
+ valid: false,
50
+ tier: config.licenseTier ?? 'unknown',
51
+ reason: 'License cache expired. Connect to internet to re-validate.',
52
+ };
53
+ }
54
+ // No licenseValidatedAt — try online validation, fallback to first-time grace
55
+ const endpoint = getApiEndpoint(config);
56
+ const onlineResult = await validateOnline(endpoint, config.licenseKey);
57
+ if (onlineResult !== null) {
58
+ // Online validation succeeded — update cache
59
+ await saveGlobalConfig({
60
+ ...config,
61
+ licenseValidatedAt: new Date().toISOString(),
62
+ licenseTier: onlineResult.tier,
63
+ });
64
+ return { valid: onlineResult.valid, tier: onlineResult.tier };
65
+ }
66
+ // No validation timestamp and offline — first-time grace
67
+ return { valid: true, tier: 'unknown' };
68
+ }
69
+ //# sourceMappingURL=license-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"license-check.js","sourceRoot":"","sources":["../../../src/cli/license-check.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ export type Feature = 'scan' | 'autofix' | 'knowledge_graph' | 'monitoring' | 'upload_sourcemaps' | 'github_app' | 'mcp_server';
2
+ export declare function tierHasFeature(tier: string, feature: Feature): boolean;
3
+ export interface GateResult {
4
+ allowed: boolean;
5
+ tier: string;
6
+ reason?: string;
7
+ }
8
+ export declare function gateFeature(feature: Feature): Promise<GateResult>;
9
+ //# sourceMappingURL=license-gate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"license-gate.d.ts","sourceRoot":"","sources":["../../../src/cli/license-gate.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,OAAO,GACf,MAAM,GACN,SAAS,GACT,iBAAiB,GACjB,YAAY,GACZ,mBAAmB,GACnB,YAAY,GACZ,YAAY,CAAC;AAUjB,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAGtE;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC,CAavE"}
@@ -0,0 +1,25 @@
1
+ import { checkLicense } from './license-check.js';
2
+ const TIER_FEATURES = {
3
+ free: ['scan'],
4
+ pro: ['scan', 'autofix', 'knowledge_graph', 'monitoring', 'mcp_server'],
5
+ team: ['scan', 'autofix', 'knowledge_graph', 'monitoring', 'upload_sourcemaps', 'github_app', 'mcp_server'],
6
+ agency: ['scan', 'autofix', 'knowledge_graph', 'monitoring', 'upload_sourcemaps', 'github_app', 'mcp_server'],
7
+ unknown: ['scan'], // first-time grace / offline fallback
8
+ };
9
+ export function tierHasFeature(tier, feature) {
10
+ const features = TIER_FEATURES[tier.toLowerCase()] ?? TIER_FEATURES['free'];
11
+ return features.includes(feature);
12
+ }
13
+ export async function gateFeature(feature) {
14
+ const license = await checkLicense();
15
+ const tier = license.tier;
16
+ if (tierHasFeature(tier, feature)) {
17
+ return { allowed: true, tier };
18
+ }
19
+ return {
20
+ allowed: false,
21
+ tier,
22
+ reason: `The "${feature}" feature requires a higher license tier. Current tier: ${tier}. Upgrade at https://shipsafe.org/pricing`,
23
+ };
24
+ }
25
+ //# sourceMappingURL=license-gate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"license-gate.js","sourceRoot":"","sources":["../../../src/cli/license-gate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAWlD,MAAM,aAAa,GAA8B;IAC/C,IAAI,EAAE,CAAC,MAAM,CAAC;IACd,GAAG,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,iBAAiB,EAAE,YAAY,EAAE,YAAY,CAAC;IACvE,IAAI,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,iBAAiB,EAAE,YAAY,EAAE,mBAAmB,EAAE,YAAY,EAAE,YAAY,CAAC;IAC3G,MAAM,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,iBAAiB,EAAE,YAAY,EAAE,mBAAmB,EAAE,YAAY,EAAE,YAAY,CAAC;IAC7G,OAAO,EAAE,CAAC,MAAM,CAAC,EAAE,sCAAsC;CAC1D,CAAC;AAEF,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,OAAgB;IAC3D,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,IAAI,aAAa,CAAC,MAAM,CAAE,CAAC;IAC7E,OAAO,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;AACpC,CAAC;AAQD,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,OAAgB;IAChD,MAAM,OAAO,GAAG,MAAM,YAAY,EAAE,CAAC;IACrC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAE1B,IAAI,cAAc,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC;QAClC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACjC,CAAC;IAED,OAAO;QACL,OAAO,EAAE,KAAK;QACd,IAAI;QACJ,MAAM,EAAE,QAAQ,OAAO,2DAA2D,IAAI,2CAA2C;KAClI,CAAC;AACJ,CAAC"}
@@ -0,0 +1,9 @@
1
+ import { Command } from 'commander';
2
+ export interface ScanOptions {
3
+ scope: string;
4
+ fix: boolean;
5
+ json: boolean;
6
+ }
7
+ export declare function handleScanAction(options: ScanOptions): Promise<void>;
8
+ export declare function registerScanCommand(program: Command): void;
9
+ //# sourceMappingURL=scan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../../../src/cli/scan.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,OAAO,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;CACf;AAoCD,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAmC1E;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAU1D"}