sapper-ai 0.5.0 → 0.6.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 (43) hide show
  1. package/dist/auth.d.ts +11 -0
  2. package/dist/auth.d.ts.map +1 -0
  3. package/dist/auth.js +102 -0
  4. package/dist/cli.d.ts.map +1 -1
  5. package/dist/cli.js +316 -32
  6. package/dist/harden.d.ts +28 -0
  7. package/dist/harden.d.ts.map +1 -0
  8. package/dist/harden.js +309 -0
  9. package/dist/mcp/jsonc.d.ts +3 -0
  10. package/dist/mcp/jsonc.d.ts.map +1 -0
  11. package/dist/mcp/jsonc.js +119 -0
  12. package/dist/mcp/wrapConfig.d.ts +22 -0
  13. package/dist/mcp/wrapConfig.d.ts.map +1 -0
  14. package/dist/mcp/wrapConfig.js +192 -0
  15. package/dist/policyYaml.d.ts +3 -0
  16. package/dist/policyYaml.d.ts.map +1 -0
  17. package/dist/policyYaml.js +27 -0
  18. package/dist/postinstall.d.ts.map +1 -1
  19. package/dist/postinstall.js +11 -2
  20. package/dist/quarantine.d.ts +13 -0
  21. package/dist/quarantine.d.ts.map +1 -0
  22. package/dist/quarantine.js +22 -0
  23. package/dist/report.d.ts.map +1 -1
  24. package/dist/report.js +1061 -59
  25. package/dist/scan.d.ts +15 -0
  26. package/dist/scan.d.ts.map +1 -1
  27. package/dist/scan.js +179 -178
  28. package/dist/utils/env.d.ts +3 -0
  29. package/dist/utils/env.d.ts.map +1 -0
  30. package/dist/utils/env.js +25 -0
  31. package/dist/utils/format.d.ts +22 -0
  32. package/dist/utils/format.d.ts.map +1 -0
  33. package/dist/utils/format.js +97 -0
  34. package/dist/utils/fs.d.ts +7 -0
  35. package/dist/utils/fs.d.ts.map +1 -0
  36. package/dist/utils/fs.js +47 -0
  37. package/dist/utils/repoRoot.d.ts +2 -0
  38. package/dist/utils/repoRoot.d.ts.map +1 -0
  39. package/dist/utils/repoRoot.js +20 -0
  40. package/dist/utils/semver.d.ts +2 -0
  41. package/dist/utils/semver.d.ts.map +1 -0
  42. package/dist/utils/semver.js +7 -0
  43. package/package.json +5 -7
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/utils/format.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,MAAM;IACrB,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;CACd;AAQD,wBAAgB,YAAY,CAC1B,OAAO,GAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IAAC,WAAW,CAAC,EAAE,OAAO,CAAA;CAAO,GAClF,MAAM,CAkBR;AAGD,wBAAgB,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAG9D;AAGD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAI9D;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAStE;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAG5D;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAIlE;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAG3D;AAID,wBAAgB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAsBjF"}
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createColors = createColors;
4
+ exports.header = header;
5
+ exports.riskColor = riskColor;
6
+ exports.stripAnsi = stripAnsi;
7
+ exports.truncateToWidth = truncateToWidth;
8
+ exports.padRight = padRight;
9
+ exports.padRightVisual = padRightVisual;
10
+ exports.padLeft = padLeft;
11
+ exports.table = table;
12
+ function supportsTruecolor(env) {
13
+ const value = env.COLORTERM?.toLowerCase();
14
+ if (!value)
15
+ return false;
16
+ return value.includes('truecolor') || value.includes('24bit');
17
+ }
18
+ function createColors(options = {}) {
19
+ const env = options.env ?? process.env;
20
+ const stdoutIsTTY = options.stdoutIsTTY ?? process.stdout.isTTY;
21
+ const disabled = env.NO_COLOR !== undefined || options.noColor === true || stdoutIsTTY !== true;
22
+ if (disabled) {
23
+ return { olive: '', dim: '', bold: '', red: '', yellow: '', reset: '' };
24
+ }
25
+ const olive = supportsTruecolor(env) ? '\x1b[38;2;107;142;35m' : '\x1b[32m';
26
+ return {
27
+ olive,
28
+ dim: '\x1b[2m',
29
+ bold: '\x1b[1m',
30
+ red: '\x1b[31m',
31
+ yellow: '\x1b[33m',
32
+ reset: '\x1b[0m',
33
+ };
34
+ }
35
+ // Header: " sapper-ai <command>"
36
+ function header(command, colors) {
37
+ const name = colors.olive ? `${colors.olive}sapper-ai${colors.reset}` : 'sapper-ai';
38
+ return ` ${name} ${command}`;
39
+ }
40
+ // Risk color by value (>= 0.8 red+bold, 0.5~0.8 yellow, < 0.5 dim)
41
+ function riskColor(risk, colors) {
42
+ if (risk >= 0.8)
43
+ return `${colors.bold}${colors.red}`;
44
+ if (risk >= 0.5)
45
+ return colors.yellow;
46
+ return colors.dim;
47
+ }
48
+ function stripAnsi(text) {
49
+ return text.replace(/\x1b\[[0-9;]*m/g, '');
50
+ }
51
+ function truncateToWidth(text, maxWidth) {
52
+ if (maxWidth <= 0)
53
+ return '';
54
+ if (text.length <= maxWidth)
55
+ return text;
56
+ if (maxWidth <= 3) {
57
+ return '.'.repeat(maxWidth);
58
+ }
59
+ return `...${text.slice(text.length - (maxWidth - 3))}`;
60
+ }
61
+ function padRight(text, width) {
62
+ if (text.length >= width)
63
+ return text;
64
+ return text + ' '.repeat(width - text.length);
65
+ }
66
+ function padRightVisual(text, width) {
67
+ const visLen = stripAnsi(text).length;
68
+ if (visLen >= width)
69
+ return text;
70
+ return text + ' '.repeat(width - visLen);
71
+ }
72
+ function padLeft(text, width) {
73
+ if (text.length >= width)
74
+ return text;
75
+ return ' '.repeat(width - text.length) + text;
76
+ }
77
+ // Aligned table (Vercel style, no box borders).
78
+ // ANSI-aware: stripAnsi based visible width.
79
+ function table(headers, rows, colors) {
80
+ const columnCount = headers.length;
81
+ const normalizedRows = rows.map((row) => {
82
+ const out = row.slice(0, columnCount);
83
+ while (out.length < columnCount)
84
+ out.push('');
85
+ return out;
86
+ });
87
+ const headerRow = headers.map((h) => (colors.dim ? `${colors.dim}${h}${colors.reset}` : h));
88
+ const all = [headerRow, ...normalizedRows];
89
+ const widths = headers.map((_, col) => Math.max(0, ...all.map((r) => stripAnsi(r[col] ?? '').length)));
90
+ const sep = ' ';
91
+ const lines = [];
92
+ lines.push(` ${headerRow.map((cell, i) => padRightVisual(cell, widths[i])).join(sep)}`.trimEnd());
93
+ for (const row of normalizedRows) {
94
+ lines.push(` ${row.map((cell, i) => padRightVisual(cell, widths[i])).join(sep)}`.trimEnd());
95
+ }
96
+ return lines.join('\n');
97
+ }
@@ -0,0 +1,7 @@
1
+ export declare function readFileIfExists(filePath: string): Promise<string | null>;
2
+ export declare function ensureDir(dirPath: string): Promise<void>;
3
+ export declare function backupFile(originalPath: string): Promise<string>;
4
+ export declare function atomicWriteFile(filePath: string, content: string, options?: {
5
+ mode?: number;
6
+ }): Promise<void>;
7
+ //# sourceMappingURL=fs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../../src/utils/fs.ts"],"names":[],"mappings":"AAIA,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAM/E;AAED,wBAAsB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE9D;AAkBD,wBAAsB,UAAU,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAKtE;AAED,wBAAsB,eAAe,CACnC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAO,GAC9B,OAAO,CAAC,IAAI,CAAC,CASf"}
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.readFileIfExists = readFileIfExists;
4
+ exports.ensureDir = ensureDir;
5
+ exports.backupFile = backupFile;
6
+ exports.atomicWriteFile = atomicWriteFile;
7
+ const node_fs_1 = require("node:fs");
8
+ const promises_1 = require("node:fs/promises");
9
+ const node_path_1 = require("node:path");
10
+ async function readFileIfExists(filePath) {
11
+ try {
12
+ return await (0, promises_1.readFile)(filePath, 'utf8');
13
+ }
14
+ catch {
15
+ return null;
16
+ }
17
+ }
18
+ async function ensureDir(dirPath) {
19
+ await (0, promises_1.mkdir)(dirPath, { recursive: true });
20
+ }
21
+ function nextBackupPath(originalPath) {
22
+ const first = `${originalPath}.bak`;
23
+ if (!(0, node_fs_1.existsSync)(first)) {
24
+ return first;
25
+ }
26
+ for (let i = 1; i < 1000; i += 1) {
27
+ const candidate = `${originalPath}.bak.${i}`;
28
+ if (!(0, node_fs_1.existsSync)(candidate)) {
29
+ return candidate;
30
+ }
31
+ }
32
+ throw new Error(`Unable to find free backup path for ${originalPath}`);
33
+ }
34
+ async function backupFile(originalPath) {
35
+ const backupPath = nextBackupPath(originalPath);
36
+ await ensureDir((0, node_path_1.dirname)(backupPath));
37
+ await (0, promises_1.copyFile)(originalPath, backupPath);
38
+ return backupPath;
39
+ }
40
+ async function atomicWriteFile(filePath, content, options = {}) {
41
+ const dir = (0, node_path_1.dirname)(filePath);
42
+ await ensureDir(dir);
43
+ const tmpName = `.${(0, node_path_1.basename)(filePath)}.tmp.${process.pid}.${Date.now()}`;
44
+ const tmpPath = (0, node_path_1.join)(dir, tmpName);
45
+ await (0, promises_1.writeFile)(tmpPath, content, { encoding: 'utf8', mode: options.mode });
46
+ await (0, promises_1.rename)(tmpPath, filePath);
47
+ }
@@ -0,0 +1,2 @@
1
+ export declare function findRepoRoot(startDir: string): string;
2
+ //# sourceMappingURL=repoRoot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repoRoot.d.ts","sourceRoot":"","sources":["../../src/utils/repoRoot.ts"],"names":[],"mappings":"AAGA,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAiBrD"}
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.findRepoRoot = findRepoRoot;
4
+ const node_fs_1 = require("node:fs");
5
+ const node_path_1 = require("node:path");
6
+ function findRepoRoot(startDir) {
7
+ const start = (0, node_path_1.resolve)(startDir);
8
+ let current = start;
9
+ while (true) {
10
+ const gitPath = (0, node_path_1.resolve)(current, '.git');
11
+ if ((0, node_fs_1.existsSync)(gitPath)) {
12
+ return current;
13
+ }
14
+ const parent = (0, node_path_1.dirname)(current);
15
+ if (parent === current) {
16
+ return start;
17
+ }
18
+ current = parent;
19
+ }
20
+ }
@@ -0,0 +1,2 @@
1
+ export declare function isSemver(version: string): boolean;
2
+ //# sourceMappingURL=semver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"semver.d.ts","sourceRoot":"","sources":["../../src/utils/semver.ts"],"names":[],"mappings":"AAGA,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEjD"}
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isSemver = isSemver;
4
+ const SEMVER_RE = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/;
5
+ function isSemver(version) {
6
+ return SEMVER_RE.test(version.trim());
7
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sapper-ai",
3
- "version": "0.5.0",
3
+ "version": "0.6.1",
4
4
  "description": "AI security guardrails - single install, sensible defaults",
5
5
  "keywords": [
6
6
  "security",
@@ -39,18 +39,16 @@
39
39
  "access": "public"
40
40
  },
41
41
  "dependencies": {
42
+ "@inquirer/password": "^4.0.0",
42
43
  "@inquirer/select": "^4.0.0",
43
- "@sapper-ai/core": "0.2.1",
44
+ "@sapper-ai/core": "0.2.2",
45
+ "@sapper-ai/mcp": "0.3.1",
44
46
  "@sapper-ai/types": "0.2.1"
45
47
  },
46
48
  "peerDependencies": {
47
- "@sapper-ai/mcp": "^0.2.1",
48
- "@sapper-ai/openai": "^0.2.1"
49
+ "@sapper-ai/openai": "^0.2.2"
49
50
  },
50
51
  "peerDependenciesMeta": {
51
- "@sapper-ai/mcp": {
52
- "optional": true
53
- },
54
52
  "@sapper-ai/openai": {
55
53
  "optional": true
56
54
  }