@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
package/README.md ADDED
@@ -0,0 +1,167 @@
1
+ # ShipSafe
2
+
3
+ Full-lifecycle security and reliability platform for vibe coders. Scan for vulnerabilities, auto-fix secrets, monitor production errors, and get AI-powered security insights — all from your terminal or IDE.
4
+
5
+ ## Features
6
+
7
+ - **Security scanning** — wraps Semgrep, Gitleaks, and Trivy into a single `shipsafe scan` command
8
+ - **Knowledge graph engine** — builds a call graph with Tree-sitter + KuzuDB to find attack paths, missing auth, and tainted data flows
9
+ - **Auto-fix** — moves hardcoded secrets to `.env` files automatically with `--fix`
10
+ - **MCP server** — 7 tools for Claude, Cursor, and other AI coding assistants
11
+ - **Production monitoring** — lightweight `@shipsafe/monitor` snippet captures errors and performance data
12
+ - **Git hooks** — pre-commit scanning to catch issues before they land
13
+ - **GitHub App** — PR checks and automated security reviews
14
+ - **License tiers** — FREE (scan), PRO (+ autofix, graph, monitoring, MCP), TEAM/AGENCY (+ sourcemaps, GitHub App)
15
+
16
+ ## Install
17
+
18
+ ```bash
19
+ npm install -g shipsafe
20
+ ```
21
+
22
+ ## Quick start
23
+
24
+ ```bash
25
+ # Initialize ShipSafe in your project
26
+ shipsafe init
27
+
28
+ # Scan for vulnerabilities (staged files by default)
29
+ shipsafe scan
30
+
31
+ # Scan all files
32
+ shipsafe scan --scope all
33
+
34
+ # Auto-fix hardcoded secrets
35
+ shipsafe scan --fix
36
+
37
+ # Activate a license
38
+ shipsafe activate SS-PRO-yourkeyhere
39
+
40
+ # Start the MCP server (for AI assistants)
41
+ shipsafe mcp-server
42
+ ```
43
+
44
+ ## Configuration
45
+
46
+ ShipSafe uses two config files merged together (project overrides global):
47
+
48
+ - **Global**: `~/.shipsafe/config.json`
49
+ - **Project**: `shipsafe.config.json`
50
+
51
+ ```bash
52
+ # View current config
53
+ shipsafe config list
54
+
55
+ # Set a value
56
+ shipsafe config set apiEndpoint https://api.shipsafe.org
57
+ shipsafe config set scan.severity_threshold medium
58
+
59
+ # Set globally
60
+ shipsafe config set licenseKey SS-PRO-abc123 --global
61
+ ```
62
+
63
+ ### Environment variables
64
+
65
+ | Variable | Description | Default |
66
+ |----------|-------------|---------|
67
+ | `SHIPSAFE_API_URL` | API endpoint override | `http://localhost:3747` |
68
+ | `SHIPSAFE_DB_PATH` | SQLite database path (API) | `~/.shipsafe/shipsafe.db` |
69
+
70
+ ## MCP Server
71
+
72
+ ShipSafe exposes an MCP server with 7 tools for AI coding assistants:
73
+
74
+ - `scan` — run security scan
75
+ - `status` — project security status
76
+ - `check_package` — check npm packages for vulnerabilities
77
+ - `production_errors` — fetch production errors
78
+ - `verify_resolution` — verify if an error is resolved
79
+ - `blast_radius` — analyze impact of changing a function
80
+ - `explain_finding` — get detailed explanation of a finding
81
+
82
+ Add to your Claude/Cursor MCP config:
83
+
84
+ ```json
85
+ {
86
+ "mcpServers": {
87
+ "shipsafe": {
88
+ "command": "shipsafe",
89
+ "args": ["mcp-server"]
90
+ }
91
+ }
92
+ }
93
+ ```
94
+
95
+ ## Monitor snippet
96
+
97
+ Capture production errors with `@shipsafe/monitor`:
98
+
99
+ ```bash
100
+ npm install @shipsafe/monitor
101
+ ```
102
+
103
+ ```typescript
104
+ import { init } from '@shipsafe/monitor';
105
+
106
+ const monitor = init({
107
+ projectId: 'your-project-id',
108
+ endpoint: 'https://api.shipsafe.org/v1/events', // optional
109
+ });
110
+ ```
111
+
112
+ Features: automatic error capture, PII scrubbing, sampling, batching with retries, auto-disable on repeated failures.
113
+
114
+ ## Cloud API
115
+
116
+ The ShipSafe API handles monitoring ingest, error processing, source map resolution, and license validation.
117
+
118
+ ```bash
119
+ cd packages/api
120
+
121
+ # Development
122
+ npm run dev
123
+
124
+ # Production (Docker)
125
+ docker compose up -d
126
+ ```
127
+
128
+ Runs on port 3747 by default.
129
+
130
+ ## Architecture
131
+
132
+ ```
133
+ bin/shipsafe.ts CLI entry point (Commander.js)
134
+ src/
135
+ engines/
136
+ pattern/ Semgrep, Gitleaks, Trivy wrappers
137
+ graph/ Tree-sitter + KuzuDB knowledge graph
138
+ cli/ CLI commands (scan, init, activate, config, etc.)
139
+ mcp/ MCP server + tools
140
+ autofix/ Auto-fix engine (secrets, scaffolding, PR generation)
141
+ github/ GitHub App (webhooks, PR scanner, checks)
142
+ hooks/ Git hook installer
143
+ config/ Config manager
144
+ packages/
145
+ api/ Hono cloud API with SQLite
146
+ monitor/ @shipsafe/monitor client snippet
147
+ ```
148
+
149
+ ## Development
150
+
151
+ ```bash
152
+ # Run tests
153
+ npm test
154
+
155
+ # Build
156
+ npm run build
157
+
158
+ # Run CLI locally
159
+ npm run dev -- scan
160
+ npm run dev -- init
161
+ ```
162
+
163
+ ## License
164
+
165
+ UNLICENSED — proprietary software by Connect Holdings LLC.
166
+
167
+ `@shipsafe/monitor` is MIT licensed.
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=shipsafe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shipsafe.d.ts","sourceRoot":"","sources":["../../bin/shipsafe.ts"],"names":[],"mappings":""}
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import { VERSION } from '../src/constants.js';
4
+ import { registerScanCommand } from '../src/cli/scan.js';
5
+ import { registerStatusCommand } from '../src/cli/status.js';
6
+ import { registerActivateCommand } from '../src/cli/activate.js';
7
+ import { registerSetupCommand } from '../src/cli/setup.js';
8
+ import { registerConnectCommand } from '../src/cli/connect.js';
9
+ import { registerUploadSourcemapsCommand } from '../src/cli/upload-sourcemaps.js';
10
+ import { registerConfigCommand } from '../src/cli/config.js';
11
+ import { registerInitCommand } from '../src/cli/init.js';
12
+ const program = new Command();
13
+ program
14
+ .name('shipsafe')
15
+ .description('Full-lifecycle security and reliability for vibe coders')
16
+ .version(VERSION);
17
+ registerScanCommand(program);
18
+ registerStatusCommand(program);
19
+ registerActivateCommand(program);
20
+ registerSetupCommand(program);
21
+ registerConnectCommand(program);
22
+ registerUploadSourcemapsCommand(program);
23
+ registerConfigCommand(program);
24
+ registerInitCommand(program);
25
+ program
26
+ .command('mcp-server')
27
+ .description('Start ShipSafe MCP server (stdio transport)')
28
+ .action(async () => {
29
+ const { startMcpServer } = await import('../src/mcp/server.js');
30
+ await startMcpServer();
31
+ });
32
+ program.parse();
33
+ //# sourceMappingURL=shipsafe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shipsafe.js","sourceRoot":"","sources":["../../bin/shipsafe.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,+BAA+B,EAAE,MAAM,iCAAiC,CAAC;AAClF,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAEzD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAC9B,OAAO;KACJ,IAAI,CAAC,UAAU,CAAC;KAChB,WAAW,CAAC,yDAAyD,CAAC;KACtE,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,mBAAmB,CAAC,OAAO,CAAC,CAAC;AAC7B,qBAAqB,CAAC,OAAO,CAAC,CAAC;AAC/B,uBAAuB,CAAC,OAAO,CAAC,CAAC;AACjC,oBAAoB,CAAC,OAAO,CAAC,CAAC;AAC9B,sBAAsB,CAAC,OAAO,CAAC,CAAC;AAChC,+BAA+B,CAAC,OAAO,CAAC,CAAC;AACzC,qBAAqB,CAAC,OAAO,CAAC,CAAC;AAC/B,mBAAmB,CAAC,OAAO,CAAC,CAAC;AAE7B,OAAO;KACJ,OAAO,CAAC,YAAY,CAAC;KACrB,WAAW,CAAC,6CAA6C,CAAC;KAC1D,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,MAAM,CAAC,sBAAsB,CAAC,CAAC;IAChE,MAAM,cAAc,EAAE,CAAC;AACzB,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,KAAK,EAAE,CAAC"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * A production error enriched by the cloud API pipeline.
3
+ */
4
+ export interface ProcessedError {
5
+ id: string;
6
+ message: string;
7
+ severity: string;
8
+ stack_trace?: string;
9
+ root_cause?: string;
10
+ suggested_fix?: string;
11
+ file?: string;
12
+ line?: number;
13
+ }
14
+ export interface AutoFixPrOptions {
15
+ error: ProcessedError;
16
+ repoFullName: string;
17
+ installationId: number;
18
+ baseBranch?: string;
19
+ }
20
+ export interface AutoFixResult {
21
+ status: 'pr_created' | 'fix_suggested' | 'cannot_fix';
22
+ prUrl?: string;
23
+ branchName?: string;
24
+ description: string;
25
+ filesModified: string[];
26
+ }
27
+ export interface FixPatch {
28
+ filePath: string;
29
+ original: string;
30
+ fixed: string;
31
+ description: string;
32
+ }
33
+ /**
34
+ * Analyze an error and generate a code fix (without creating a PR).
35
+ */
36
+ export declare function generateFix(error: ProcessedError, fileContent: string): FixPatch | null;
37
+ /**
38
+ * Parse a stack trace to extract file and line number.
39
+ */
40
+ export declare function parseStackTrace(stackTrace: string): {
41
+ file: string;
42
+ line: number;
43
+ } | null;
44
+ /**
45
+ * Generate a fix based on error analysis and create a PR via GitHub API.
46
+ */
47
+ export declare function generateAutoFixPr(options: AutoFixPrOptions): Promise<AutoFixResult>;
48
+ //# sourceMappingURL=pr-generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pr-generator.d.ts","sourceRoot":"","sources":["../../../src/autofix/pr-generator.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,cAAc,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,YAAY,GAAG,eAAe,GAAG,YAAY,CAAC;IACtD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACrB;AAmND;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CA0BvF;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAKzF;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,aAAa,CAAC,CAiIzF"}
@@ -0,0 +1,359 @@
1
+ import { getInstallationToken, githubApi } from '../github/api.js';
2
+ /**
3
+ * Extract the property name from a TypeError message like
4
+ * "Cannot read property 'foo' of null" or "Cannot read properties of undefined (reading 'bar')"
5
+ */
6
+ function extractPropertyName(message) {
7
+ // "Cannot read property 'X' of null/undefined"
8
+ const match1 = message.match(/Cannot read propert(?:y|ies) (?:of \w+ \(reading )?'(\w+)'/);
9
+ if (match1)
10
+ return match1[1];
11
+ // "Cannot read properties of undefined (reading 'X')"
12
+ const match2 = message.match(/reading '(\w+)'/);
13
+ if (match2)
14
+ return match2[1];
15
+ return null;
16
+ }
17
+ const FIX_PATTERNS = [
18
+ // 6. Missing await — ".then is not a function" means result is not a Promise
19
+ {
20
+ test: (msg) => /\.then is not a function/i.test(msg) || /is not a function.*promise/i.test(msg),
21
+ apply: (line) => {
22
+ // Find a function call pattern and prepend await
23
+ const match = line.match(/^(\s*(?:const|let|var)\s+\w+\s*=\s*)(\w+\()/);
24
+ if (match) {
25
+ return line.replace(match[2], `await ${match[2]}`);
26
+ }
27
+ // Try bare call: ` someFunc(...)`
28
+ const bareMatch = line.match(/^(\s*)(\w+\()/);
29
+ if (bareMatch) {
30
+ return `${bareMatch[1]}await ${line.trimStart()}`;
31
+ }
32
+ return null;
33
+ },
34
+ describe: () => 'Add missing await before Promise-returning function call to prevent .then TypeError',
35
+ },
36
+ // 7. Missing import — "Cannot find module 'X'"
37
+ {
38
+ test: (msg) => /Cannot find module '(.+)'/i.test(msg),
39
+ apply: (line, message) => {
40
+ const match = message.match(/Cannot find module '([^']+)'/i);
41
+ if (!match)
42
+ return null;
43
+ const moduleName = match[1];
44
+ const trimmed = line.trimStart();
45
+ const indent = line.slice(0, line.length - trimmed.length);
46
+ return `${indent}import {} from '${moduleName}'; // TODO: specify named imports\n${line}`;
47
+ },
48
+ describe: (msg) => {
49
+ const match = msg.match(/Cannot find module '([^']+)'/i);
50
+ return `Add missing import statement for module '${match?.[1] ?? 'unknown'}'`;
51
+ },
52
+ },
53
+ // 8. Array index out of bounds — "Cannot read properties of undefined (reading '0')"
54
+ // More specific: only when the reading key is a digit (array index)
55
+ {
56
+ test: (msg) => /Cannot read propert(?:y|ies).*of undefined/i.test(msg) &&
57
+ /reading '(\d+)'/.test(msg),
58
+ apply: (line) => {
59
+ const trimmed = line.trimStart();
60
+ const indent = line.slice(0, line.length - trimmed.length);
61
+ // Detect the array variable (e.g. `items[0]` → `items`)
62
+ const arrayMatch = trimmed.match(/(\w+)\[\d+\]/);
63
+ const arrName = arrayMatch ? arrayMatch[1] : 'arr';
64
+ return `${indent}if (${arrName} && ${arrName}.length > 0) { ${trimmed} }`;
65
+ },
66
+ describe: () => 'Add array bounds check to prevent undefined index access',
67
+ },
68
+ // 9. Missing null coalescing — "Cannot read properties of null (reading 'X')"
69
+ // Must come BEFORE pattern 1 so we handle null specifically here.
70
+ {
71
+ test: (msg) => /Cannot read propert(?:y|ies)/.test(msg) && /\bnull\b/.test(msg) && !/undefined/.test(msg),
72
+ apply: (line, message) => {
73
+ const prop = extractPropertyName(message);
74
+ if (!prop)
75
+ return null;
76
+ const pattern = new RegExp(`(?<!\\?)\\.(${prop})\\b`);
77
+ if (!pattern.test(line))
78
+ return null;
79
+ // Replace `.prop` with `?.prop ?? undefined`
80
+ return line.replace(pattern, `?.${prop} ?? undefined`);
81
+ },
82
+ describe: (msg) => {
83
+ const prop = extractPropertyName(msg);
84
+ return `Add optional chaining and nullish coalescing for null property '${prop ?? 'unknown'}' access`;
85
+ },
86
+ },
87
+ // 10. JSON parse error — "Unexpected token X in JSON"
88
+ {
89
+ test: (msg) => /Unexpected token.+JSON/i.test(msg) || /SyntaxError.*JSON/i.test(msg),
90
+ apply: (line) => {
91
+ if (!/JSON\.parse/.test(line))
92
+ return null;
93
+ const trimmed = line.trimStart();
94
+ const indent = line.slice(0, line.length - trimmed.length);
95
+ return [
96
+ `${indent}try {`,
97
+ `${indent} ${trimmed}`,
98
+ `${indent}} catch {`,
99
+ `${indent} /* handle JSON parse error */`,
100
+ `${indent}}`,
101
+ ].join('\n');
102
+ },
103
+ describe: () => 'Wrap JSON.parse in try/catch to handle malformed JSON input',
104
+ },
105
+ // 1. TypeError: Cannot read property 'X' of null/undefined → optional chaining
106
+ {
107
+ test: (msg) => /Cannot read propert(?:y|ies)/.test(msg) &&
108
+ /(?:null|undefined)/.test(msg),
109
+ apply: (line, message) => {
110
+ const prop = extractPropertyName(message);
111
+ if (!prop)
112
+ return null;
113
+ // Replace `.prop` with `?.prop` if not already optional-chained
114
+ const pattern = new RegExp(`(?<!\\?)\\.(${prop})\\b`);
115
+ if (!pattern.test(line))
116
+ return null;
117
+ return line.replace(pattern, `?.${prop}`);
118
+ },
119
+ describe: (msg) => {
120
+ const prop = extractPropertyName(msg);
121
+ return `Add optional chaining for property '${prop ?? 'unknown'}' to prevent TypeError on null/undefined`;
122
+ },
123
+ },
124
+ // 2. TypeError: X is not a function → guard with typeof check
125
+ {
126
+ test: (msg) => /is not a function/.test(msg),
127
+ apply: (line, message) => {
128
+ const match = message.match(/(\w+) is not a function/);
129
+ if (!match)
130
+ return null;
131
+ const fnName = match[1];
132
+ // Add typeof guard: `if (typeof fn === 'function') { fn(...) }`
133
+ const callPattern = new RegExp(`(${fnName})\\s*\\(`);
134
+ if (!callPattern.test(line))
135
+ return null;
136
+ const trimmed = line.trimStart();
137
+ const indent = line.slice(0, line.length - trimmed.length);
138
+ return `${indent}if (typeof ${fnName} === 'function') { ${trimmed} }`;
139
+ },
140
+ describe: (msg) => {
141
+ const match = msg.match(/(\w+) is not a function/);
142
+ return `Add typeof guard before calling '${match?.[1] ?? 'unknown'}' to prevent TypeError`;
143
+ },
144
+ },
145
+ // 3. ReferenceError: X is not defined → declare as undefined
146
+ {
147
+ test: (msg) => /is not defined/.test(msg) && msg.includes('ReferenceError'),
148
+ apply: (line, message) => {
149
+ const match = message.match(/(\w+) is not defined/);
150
+ if (!match)
151
+ return null;
152
+ const varName = match[1];
153
+ const trimmed = line.trimStart();
154
+ const indent = line.slice(0, line.length - trimmed.length);
155
+ return `${indent}const ${varName} = undefined; // TODO: provide correct value\n${line}`;
156
+ },
157
+ describe: (msg) => {
158
+ const match = msg.match(/(\w+) is not defined/);
159
+ return `Declare missing variable '${match?.[1] ?? 'unknown'}' — requires manual review`;
160
+ },
161
+ },
162
+ // 4. Unhandled promise rejection → wrap in try/catch
163
+ {
164
+ test: (msg) => /[Uu]nhandled.*(?:promise|rejection)/i.test(msg) ||
165
+ /UnhandledPromiseRejection/i.test(msg),
166
+ apply: (line) => {
167
+ const trimmed = line.trimStart();
168
+ const indent = line.slice(0, line.length - trimmed.length);
169
+ // Wrap the line in a try/catch
170
+ return [
171
+ `${indent}try {`,
172
+ `${indent} ${trimmed}`,
173
+ `${indent}} catch (err) {`,
174
+ `${indent} console.error('Caught previously unhandled rejection:', err);`,
175
+ `${indent}}`,
176
+ ].join('\n');
177
+ },
178
+ describe: () => 'Wrap unhandled async call in try/catch block',
179
+ },
180
+ // 5. SQL injection → parameterize
181
+ {
182
+ test: (msg) => /sql.*injection/i.test(msg),
183
+ apply: (line) => {
184
+ // Match template literal or string concatenation in SQL-like context
185
+ const templateMatch = line.match(/`([^`]*\$\{(\w+)\}[^`]*)`/);
186
+ if (templateMatch) {
187
+ const param = templateMatch[2];
188
+ const trimmed = line.trimStart();
189
+ const indent = line.slice(0, line.length - trimmed.length);
190
+ // Replace template literal with parameterized query
191
+ const safeSql = templateMatch[1].replace(`\${${param}}`, '?');
192
+ return `${indent}// FIXED: parameterized query to prevent SQL injection\n${indent}${line.replace(templateMatch[0], `'${safeSql}', [${param}]`)}`;
193
+ }
194
+ return null;
195
+ },
196
+ describe: () => 'Parameterize SQL query to prevent SQL injection',
197
+ },
198
+ ];
199
+ /**
200
+ * Analyze an error and generate a code fix (without creating a PR).
201
+ */
202
+ export function generateFix(error, fileContent) {
203
+ if (!error.file || !error.line)
204
+ return null;
205
+ const lines = fileContent.split('\n');
206
+ const lineIndex = error.line - 1;
207
+ if (lineIndex < 0 || lineIndex >= lines.length)
208
+ return null;
209
+ const targetLine = lines[lineIndex];
210
+ for (const pattern of FIX_PATTERNS) {
211
+ if (pattern.test(error.message)) {
212
+ const fixedLine = pattern.apply(targetLine, error.message);
213
+ if (fixedLine !== null && fixedLine !== targetLine) {
214
+ const fixedLines = [...lines];
215
+ fixedLines[lineIndex] = fixedLine;
216
+ return {
217
+ filePath: error.file,
218
+ original: fileContent,
219
+ fixed: fixedLines.join('\n'),
220
+ description: pattern.describe(error.message),
221
+ };
222
+ }
223
+ }
224
+ }
225
+ return null;
226
+ }
227
+ /**
228
+ * Parse a stack trace to extract file and line number.
229
+ */
230
+ export function parseStackTrace(stackTrace) {
231
+ // Match patterns like "at handler (/src/api/route.ts:42:10)" or "at /src/api/route.ts:42"
232
+ const match = stackTrace.match(/at\s+(?:\S+\s+)?(?:\()?([^:]+):(\d+)/);
233
+ if (!match)
234
+ return null;
235
+ return { file: match[1], line: parseInt(match[2], 10) };
236
+ }
237
+ /**
238
+ * Generate a fix based on error analysis and create a PR via GitHub API.
239
+ */
240
+ export async function generateAutoFixPr(options) {
241
+ const { error, repoFullName, installationId, baseBranch = 'main' } = options;
242
+ // 1. Determine the file and line from the error or its stack trace
243
+ let file = error.file;
244
+ let line = error.line;
245
+ if (!file && error.stack_trace) {
246
+ const parsed = parseStackTrace(error.stack_trace);
247
+ if (parsed) {
248
+ file = parsed.file;
249
+ line = parsed.line;
250
+ }
251
+ }
252
+ if (!file || !line) {
253
+ return {
254
+ status: 'cannot_fix',
255
+ description: 'Cannot determine the source file from this error. No stack trace or file info available.',
256
+ filesModified: [],
257
+ };
258
+ }
259
+ // Normalize file path (remove leading /)
260
+ const filePath = file.startsWith('/') ? file.slice(1) : file;
261
+ try {
262
+ // 2. Get an installation token
263
+ const token = await getInstallationToken(installationId);
264
+ // 3. Fetch file content from GitHub
265
+ const fileResponse = (await githubApi(`/repos/${repoFullName}/contents/${filePath}`, {
266
+ token,
267
+ method: 'GET',
268
+ }));
269
+ if (!fileResponse.content) {
270
+ return {
271
+ status: 'cannot_fix',
272
+ description: `File ${filePath} not found in repository.`,
273
+ filesModified: [],
274
+ };
275
+ }
276
+ const fileContent = Buffer.from(fileResponse.content, 'base64').toString('utf-8');
277
+ // 4. Generate the fix
278
+ const patch = generateFix({ ...error, file: filePath, line }, fileContent);
279
+ if (!patch) {
280
+ return {
281
+ status: 'fix_suggested',
282
+ description: error.suggested_fix ?? `Unable to auto-fix: ${error.message}`,
283
+ filesModified: [],
284
+ };
285
+ }
286
+ // 5. Create a new branch
287
+ const branchName = `shipsafe/fix-${error.id}`;
288
+ // Get the base branch SHA
289
+ const baseBranchRef = (await githubApi(`/repos/${repoFullName}/git/ref/heads/${baseBranch}`, {
290
+ token,
291
+ }));
292
+ const baseSha = baseBranchRef.object.sha;
293
+ // Create the new branch
294
+ await githubApi(`/repos/${repoFullName}/git/refs`, {
295
+ method: 'POST',
296
+ token,
297
+ body: {
298
+ ref: `refs/heads/${branchName}`,
299
+ sha: baseSha,
300
+ },
301
+ });
302
+ // 6. Commit the fix
303
+ await githubApi(`/repos/${repoFullName}/contents/${filePath}`, {
304
+ method: 'PUT',
305
+ token,
306
+ body: {
307
+ message: `fix: ${patch.description}`,
308
+ content: Buffer.from(patch.fixed).toString('base64'),
309
+ sha: fileResponse.sha,
310
+ branch: branchName,
311
+ },
312
+ });
313
+ // 7. Create the PR
314
+ const pr = (await githubApi(`/repos/${repoFullName}/pulls`, {
315
+ method: 'POST',
316
+ token,
317
+ body: {
318
+ title: `fix: ${truncate(error.message, 60)}`,
319
+ head: branchName,
320
+ base: baseBranch,
321
+ body: [
322
+ '## Auto-Fix by ShipSafe',
323
+ '',
324
+ `**Error:** ${error.message}`,
325
+ '',
326
+ `**Root cause:** ${error.root_cause ?? 'See error details'}`,
327
+ '',
328
+ `**Fix applied:** ${patch.description}`,
329
+ '',
330
+ `**File:** \`${filePath}\` (line ${line})`,
331
+ '',
332
+ '---',
333
+ '_This PR was automatically generated by ShipSafe. Please review before merging._',
334
+ ].join('\n'),
335
+ },
336
+ }));
337
+ return {
338
+ status: 'pr_created',
339
+ prUrl: pr.html_url,
340
+ branchName,
341
+ description: patch.description,
342
+ filesModified: [filePath],
343
+ };
344
+ }
345
+ catch (err) {
346
+ const message = err instanceof Error ? err.message : String(err);
347
+ return {
348
+ status: 'cannot_fix',
349
+ description: `Auto-fix PR failed: ${message}`,
350
+ filesModified: [],
351
+ };
352
+ }
353
+ }
354
+ function truncate(str, maxLen) {
355
+ if (str.length <= maxLen)
356
+ return str;
357
+ return str.slice(0, maxLen - 3) + '...';
358
+ }
359
+ //# sourceMappingURL=pr-generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pr-generator.js","sourceRoot":"","sources":["../../../src/autofix/pr-generator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ export interface ProjectTemplate {
2
+ framework: string;
3
+ recommendations: SecurityRecommendation[];
4
+ }
5
+ export interface SecurityRecommendation {
6
+ type: 'missing_helmet' | 'missing_cors' | 'missing_rate_limit' | 'missing_csp' | 'missing_env_config' | 'insecure_cookie';
7
+ description: string;
8
+ fix: string;
9
+ file: string;
10
+ priority: 'high' | 'medium' | 'low';
11
+ }
12
+ interface PackageJson {
13
+ dependencies?: Record<string, string>;
14
+ devDependencies?: Record<string, string>;
15
+ }
16
+ /**
17
+ * Detect the framework from package.json dependencies.
18
+ */
19
+ export declare function detectFramework(packageJson: PackageJson): string | null;
20
+ /**
21
+ * Detect the project framework and generate security recommendations.
22
+ * Returns null if the framework cannot be detected.
23
+ */
24
+ export declare function detectAndRecommend(projectDir?: string): Promise<ProjectTemplate | null>;
25
+ export {};
26
+ //# sourceMappingURL=scaffolding.d.ts.map