logicstamp-context 0.2.6 → 0.3.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 (63) hide show
  1. package/LLM_CONTEXT.md +2 -2
  2. package/README.md +79 -36
  3. package/dist/cli/commands/context.d.ts.map +1 -1
  4. package/dist/cli/commands/context.js +36 -10
  5. package/dist/cli/commands/context.js.map +1 -1
  6. package/dist/cli/commands/ignore.d.ts +16 -0
  7. package/dist/cli/commands/ignore.d.ts.map +1 -0
  8. package/dist/cli/commands/ignore.js +61 -0
  9. package/dist/cli/commands/ignore.js.map +1 -0
  10. package/dist/cli/commands/init.d.ts +4 -0
  11. package/dist/cli/commands/init.d.ts.map +1 -1
  12. package/dist/cli/commands/init.js +83 -9
  13. package/dist/cli/commands/init.js.map +1 -1
  14. package/dist/cli/commands/security.d.ts +37 -0
  15. package/dist/cli/commands/security.d.ts.map +1 -0
  16. package/dist/cli/commands/security.js +304 -0
  17. package/dist/cli/commands/security.js.map +1 -0
  18. package/dist/cli/handlers/ignoreHandler.d.ts +5 -0
  19. package/dist/cli/handlers/ignoreHandler.d.ts.map +1 -0
  20. package/dist/cli/handlers/ignoreHandler.js +23 -0
  21. package/dist/cli/handlers/ignoreHandler.js.map +1 -0
  22. package/dist/cli/handlers/securityHandler.d.ts +5 -0
  23. package/dist/cli/handlers/securityHandler.d.ts.map +1 -0
  24. package/dist/cli/handlers/securityHandler.js +41 -0
  25. package/dist/cli/handlers/securityHandler.js.map +1 -0
  26. package/dist/cli/parser/argumentParser.d.ts +9 -0
  27. package/dist/cli/parser/argumentParser.d.ts.map +1 -1
  28. package/dist/cli/parser/argumentParser.js +50 -0
  29. package/dist/cli/parser/argumentParser.js.map +1 -1
  30. package/dist/cli/parser/helpText.d.ts +3 -0
  31. package/dist/cli/parser/helpText.d.ts.map +1 -1
  32. package/dist/cli/parser/helpText.js +492 -348
  33. package/dist/cli/parser/helpText.js.map +1 -1
  34. package/dist/cli/stamp.js +61 -1
  35. package/dist/cli/stamp.js.map +1 -1
  36. package/dist/core/pack/builder.d.ts.map +1 -1
  37. package/dist/core/pack/builder.js +25 -5
  38. package/dist/core/pack/builder.js.map +1 -1
  39. package/dist/core/pack/loader.d.ts +14 -0
  40. package/dist/core/pack/loader.d.ts.map +1 -1
  41. package/dist/core/pack/loader.js +86 -2
  42. package/dist/core/pack/loader.js.map +1 -1
  43. package/dist/core/pack.d.ts.map +1 -1
  44. package/dist/core/pack.js +15 -2
  45. package/dist/core/pack.js.map +1 -1
  46. package/dist/utils/codeSanitizer.d.ts +24 -0
  47. package/dist/utils/codeSanitizer.d.ts.map +1 -0
  48. package/dist/utils/codeSanitizer.js +234 -0
  49. package/dist/utils/codeSanitizer.js.map +1 -0
  50. package/dist/utils/gitignore.d.ts +30 -2
  51. package/dist/utils/gitignore.d.ts.map +1 -1
  52. package/dist/utils/gitignore.js +132 -20
  53. package/dist/utils/gitignore.js.map +1 -1
  54. package/dist/utils/secretDetector.d.ts +21 -0
  55. package/dist/utils/secretDetector.d.ts.map +1 -0
  56. package/dist/utils/secretDetector.js +145 -0
  57. package/dist/utils/secretDetector.js.map +1 -0
  58. package/dist/utils/stampignore.d.ts +49 -0
  59. package/dist/utils/stampignore.d.ts.map +1 -0
  60. package/dist/utils/stampignore.js +211 -0
  61. package/dist/utils/stampignore.js.map +1 -0
  62. package/package.json +1 -1
  63. package/schema/logicstamp.context.schema.json +1 -1
@@ -0,0 +1,145 @@
1
+ /**
2
+ * Simple secret detection utilities
3
+ * Detects common patterns for API keys, tokens, passwords, etc.
4
+ */
5
+ /**
6
+ * Common secret patterns to detect
7
+ */
8
+ const SECRET_PATTERNS = [
9
+ // API Keys
10
+ {
11
+ name: 'API Key',
12
+ pattern: /['"`]?(?:api[_-]?key|apikey)['"`]?\s*[=:]\s*['"`]?([a-zA-Z0-9_\-]{20,})['"`]?/i,
13
+ severity: 'high',
14
+ },
15
+ // AWS Access Keys
16
+ {
17
+ name: 'AWS Access Key',
18
+ // Pattern obfuscated to avoid GitHub secret scanning false positives
19
+ // This is a detection pattern, not an actual secret
20
+ pattern: (() => {
21
+ const part1 = 'A'.concat('K');
22
+ const part2 = 'I'.concat('A');
23
+ return new RegExp(part1 + part2 + '[0-9A-Z]{16}');
24
+ })(),
25
+ severity: 'high',
26
+ },
27
+ // GitHub Tokens
28
+ {
29
+ name: 'GitHub Token',
30
+ // Pattern obfuscated to avoid GitHub secret scanning false positives
31
+ // This is a detection pattern, not an actual secret
32
+ pattern: (() => {
33
+ const prefixes = [
34
+ 'g'.concat('h').concat('p_'),
35
+ 'g'.concat('h').concat('o_'),
36
+ 'g'.concat('h').concat('u_'),
37
+ 'g'.concat('h').concat('s_'),
38
+ 'g'.concat('h').concat('r_'),
39
+ ];
40
+ return new RegExp(prefixes.map(prefix => `${prefix}[a-zA-Z0-9]{36}`).join('|'));
41
+ })(),
42
+ severity: 'high',
43
+ },
44
+ // Private Keys
45
+ {
46
+ name: 'Private Key',
47
+ pattern: /-----BEGIN\s+(?:RSA\s+)?PRIVATE\s+KEY-----/,
48
+ severity: 'high',
49
+ },
50
+ // Passwords
51
+ {
52
+ name: 'Password',
53
+ pattern: /['"`]?(?:password|passwd|pwd)['"`]?\s*[=:]\s*['"`]?([^\s'"`]{8,})['"`]?/i,
54
+ severity: 'high',
55
+ },
56
+ // Tokens
57
+ {
58
+ name: 'Token',
59
+ pattern: /['"`]?(?:token|bearer)['"`]?\s*[=:]\s*['"`]?([a-zA-Z0-9_\-]{20,})['"`]?/i,
60
+ severity: 'high',
61
+ },
62
+ // OAuth Secrets
63
+ {
64
+ name: 'OAuth Secret',
65
+ pattern: /['"`]?(?:oauth[_-]?secret|client[_-]?secret)['"`]?\s*[=:]\s*['"`]?([a-zA-Z0-9_\-]{16,})['"`]?/i,
66
+ severity: 'high',
67
+ },
68
+ // Database URLs with credentials
69
+ {
70
+ name: 'Database URL with Credentials',
71
+ pattern: /(?:postgres|mysql|mongodb):\/\/[^:]+:[^@]+@/i,
72
+ severity: 'high',
73
+ },
74
+ // JWT Secrets
75
+ {
76
+ name: 'JWT Secret',
77
+ pattern: /['"`]?(?:jwt[_-]?secret|jwt[_-]?key)['"`]?\s*[=:]\s*['"`]?([a-zA-Z0-9_\-]{16,})['"`]?/i,
78
+ severity: 'high',
79
+ },
80
+ // Generic secrets
81
+ {
82
+ name: 'Secret',
83
+ pattern: /['"`]?(?:secret|secret[_-]?key)['"`]?\s*[=:]\s*['"`]?([a-zA-Z0-9_\-]{16,})['"`]?/i,
84
+ severity: 'medium',
85
+ },
86
+ ];
87
+ /**
88
+ * Scan a file for secrets
89
+ */
90
+ export function scanFileForSecrets(filePath, content) {
91
+ const matches = [];
92
+ const lines = content.split('\n');
93
+ for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
94
+ const line = lines[lineIndex];
95
+ for (const { name, pattern, severity } of SECRET_PATTERNS) {
96
+ const regex = new RegExp(pattern.source, pattern.flags);
97
+ let match;
98
+ while ((match = regex.exec(line)) !== null) {
99
+ // Extract snippet (first 100 chars around match)
100
+ const matchStart = Math.max(0, match.index - 20);
101
+ const matchEnd = Math.min(line.length, match.index + match[0].length + 20);
102
+ const snippet = line.slice(matchStart, matchEnd).trim();
103
+ matches.push({
104
+ file: filePath,
105
+ line: lineIndex + 1,
106
+ column: match.index + 1,
107
+ type: name,
108
+ snippet,
109
+ severity,
110
+ });
111
+ // Prevent infinite loops
112
+ if (!pattern.global) {
113
+ break;
114
+ }
115
+ }
116
+ }
117
+ }
118
+ return matches;
119
+ }
120
+ /**
121
+ * Filter out false positives (common patterns that look like secrets but aren't)
122
+ */
123
+ export function filterFalsePositives(matches) {
124
+ return matches.filter(match => {
125
+ // Skip if snippet contains common false positive patterns
126
+ const snippet = match.snippet.toLowerCase();
127
+ // Skip example/test patterns
128
+ if (snippet.includes('example') || snippet.includes('test') || snippet.includes('sample')) {
129
+ return false;
130
+ }
131
+ // Skip if it's clearly a comment or documentation
132
+ if (snippet.includes('//') || snippet.includes('/*') || snippet.includes('*')) {
133
+ // But keep if it's an actual assignment
134
+ if (!snippet.includes('=') && !snippet.includes(':')) {
135
+ return false;
136
+ }
137
+ }
138
+ // Skip very short matches (likely false positives)
139
+ if (match.type === 'Secret' && match.snippet.length < 20) {
140
+ return false;
141
+ }
142
+ return true;
143
+ });
144
+ }
145
+ //# sourceMappingURL=secretDetector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secretDetector.js","sourceRoot":"","sources":["../../src/utils/secretDetector.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAWH;;GAEG;AACH,MAAM,eAAe,GAIhB;IACH,WAAW;IACX;QACE,IAAI,EAAE,SAAS;QACf,OAAO,EAAE,gFAAgF;QACzF,QAAQ,EAAE,MAAM;KACjB;IACD,kBAAkB;IAClB;QACE,IAAI,EAAE,gBAAgB;QACtB,qEAAqE;QACrE,oDAAoD;QACpD,OAAO,EAAE,CAAC,GAAG,EAAE;YACb,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC9B,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC9B,OAAO,IAAI,MAAM,CAAC,KAAK,GAAG,KAAK,GAAG,cAAc,CAAC,CAAC;QACpD,CAAC,CAAC,EAAE;QACJ,QAAQ,EAAE,MAAM;KACjB;IACD,gBAAgB;IAChB;QACE,IAAI,EAAE,cAAc;QACpB,qEAAqE;QACrE,oDAAoD;QACpD,OAAO,EAAE,CAAC,GAAG,EAAE;YACb,MAAM,QAAQ,GAAG;gBACf,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC;gBAC5B,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC;gBAC5B,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC;gBAC5B,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC;gBAC5B,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC;aAC7B,CAAC;YACF,OAAO,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,MAAM,iBAAiB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QAClF,CAAC,CAAC,EAAE;QACJ,QAAQ,EAAE,MAAM;KACjB;IACD,eAAe;IACf;QACE,IAAI,EAAE,aAAa;QACnB,OAAO,EAAE,4CAA4C;QACrD,QAAQ,EAAE,MAAM;KACjB;IACD,YAAY;IACZ;QACE,IAAI,EAAE,UAAU;QAChB,OAAO,EAAE,0EAA0E;QACnF,QAAQ,EAAE,MAAM;KACjB;IACD,SAAS;IACT;QACE,IAAI,EAAE,OAAO;QACb,OAAO,EAAE,0EAA0E;QACnF,QAAQ,EAAE,MAAM;KACjB;IACD,gBAAgB;IAChB;QACE,IAAI,EAAE,cAAc;QACpB,OAAO,EAAE,gGAAgG;QACzG,QAAQ,EAAE,MAAM;KACjB;IACD,iCAAiC;IACjC;QACE,IAAI,EAAE,+BAA+B;QACrC,OAAO,EAAE,8CAA8C;QACvD,QAAQ,EAAE,MAAM;KACjB;IACD,cAAc;IACd;QACE,IAAI,EAAE,YAAY;QAClB,OAAO,EAAE,wFAAwF;QACjG,QAAQ,EAAE,MAAM;KACjB;IACD,kBAAkB;IAClB;QACE,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,mFAAmF;QAC5F,QAAQ,EAAE,QAAQ;KACnB;CACF,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAChC,QAAgB,EAChB,OAAe;IAEf,MAAM,OAAO,GAAkB,EAAE,CAAC;IAClC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAElC,KAAK,IAAI,SAAS,GAAG,CAAC,EAAE,SAAS,GAAG,KAAK,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,CAAC;QAC9D,MAAM,IAAI,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC;QAE9B,KAAK,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,eAAe,EAAE,CAAC;YAC1D,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;YACxD,IAAI,KAA6B,CAAC;YAElC,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;gBAC3C,iDAAiD;gBACjD,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,GAAG,EAAE,CAAC,CAAC;gBACjD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;gBAC3E,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;gBAExD,OAAO,CAAC,IAAI,CAAC;oBACX,IAAI,EAAE,QAAQ;oBACd,IAAI,EAAE,SAAS,GAAG,CAAC;oBACnB,MAAM,EAAE,KAAK,CAAC,KAAK,GAAG,CAAC;oBACvB,IAAI,EAAE,IAAI;oBACV,OAAO;oBACP,QAAQ;iBACT,CAAC,CAAC;gBAEH,yBAAyB;gBACzB,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;oBACpB,MAAM;gBACR,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAAsB;IACzD,OAAO,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;QAC5B,0DAA0D;QAC1D,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;QAE5C,6BAA6B;QAC7B,IAAI,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC1F,OAAO,KAAK,CAAC;QACf,CAAC;QAED,kDAAkD;QAClD,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC9E,wCAAwC;YACxC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;gBACrD,OAAO,KAAK,CAAC;YACf,CAAC;QACH,CAAC;QAED,mDAAmD;QACnD,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;YACzD,OAAO,KAAK,CAAC;QACf,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Utilities for managing .stampignore files
3
+ * Similar to .gitignore, but for LogicStamp context generation
4
+ */
5
+ export interface StampIgnoreConfig {
6
+ /**
7
+ * Array of file paths or glob patterns to ignore
8
+ * Paths are relative to the project root
9
+ */
10
+ ignore: string[];
11
+ }
12
+ /**
13
+ * Default .stampignore filename
14
+ */
15
+ export declare const STAMPIGNORE_FILENAME = ".stampignore";
16
+ /**
17
+ * Check if .stampignore exists in the given directory
18
+ */
19
+ export declare function stampignoreExists(targetDir: string): Promise<boolean>;
20
+ /**
21
+ * Read .stampignore content
22
+ */
23
+ export declare function readStampignore(targetDir: string): Promise<StampIgnoreConfig | null>;
24
+ /**
25
+ * Write .stampignore content
26
+ */
27
+ export declare function writeStampignore(targetDir: string, config: StampIgnoreConfig): Promise<void>;
28
+ /**
29
+ * Add paths to .stampignore
30
+ * Creates the file if it doesn't exist
31
+ */
32
+ export declare function addToStampignore(targetDir: string, pathsToAdd: string[]): Promise<{
33
+ added: boolean;
34
+ created: boolean;
35
+ }>;
36
+ /**
37
+ * Check if a file path matches any ignore pattern
38
+ * Supports glob patterns and exact paths
39
+ */
40
+ export declare function matchesIgnorePattern(filePath: string, patterns: string[], projectRoot: string): boolean;
41
+ /**
42
+ * Filter files based on .stampignore patterns
43
+ */
44
+ export declare function filterIgnoredFiles(files: string[], patterns: string[], projectRoot: string): string[];
45
+ /**
46
+ * Delete .stampignore file
47
+ */
48
+ export declare function deleteStampignore(targetDir: string): Promise<boolean>;
49
+ //# sourceMappingURL=stampignore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stampignore.d.ts","sourceRoot":"","sources":["../../src/utils/stampignore.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;GAEG;AACH,eAAO,MAAM,oBAAoB,iBAAiB,CAAC;AAEnD;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO3E;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAsC1F;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,iBAAiB,GACxB,OAAO,CAAC,IAAI,CAAC,CA+Bf;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAAE,GACnB,OAAO,CAAC;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,CAuB/C;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAAE,EAClB,WAAW,EAAE,MAAM,GAClB,OAAO,CAgET;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,EAAE,EACf,QAAQ,EAAE,MAAM,EAAE,EAClB,WAAW,EAAE,MAAM,GAClB,MAAM,EAAE,CAMV;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAmB3E"}
@@ -0,0 +1,211 @@
1
+ /**
2
+ * Utilities for managing .stampignore files
3
+ * Similar to .gitignore, but for LogicStamp context generation
4
+ */
5
+ import { readFile, writeFile, access, unlink } from 'node:fs/promises';
6
+ import { join, isAbsolute } from 'node:path';
7
+ import { debugError } from './debug.js';
8
+ import { normalizeEntryId, getRelativePath } from './fsx.js';
9
+ /**
10
+ * Default .stampignore filename
11
+ */
12
+ export const STAMPIGNORE_FILENAME = '.stampignore';
13
+ /**
14
+ * Check if .stampignore exists in the given directory
15
+ */
16
+ export async function stampignoreExists(targetDir) {
17
+ try {
18
+ await access(join(targetDir, STAMPIGNORE_FILENAME));
19
+ return true;
20
+ }
21
+ catch {
22
+ return false;
23
+ }
24
+ }
25
+ /**
26
+ * Read .stampignore content
27
+ */
28
+ export async function readStampignore(targetDir) {
29
+ const stampignorePath = join(targetDir, STAMPIGNORE_FILENAME);
30
+ try {
31
+ const content = await readFile(stampignorePath, 'utf-8');
32
+ const config = JSON.parse(content);
33
+ // Validate structure
34
+ if (!config || typeof config !== 'object') {
35
+ debugError('stampignore', 'readStampignore', {
36
+ stampignorePath,
37
+ message: 'Invalid config structure',
38
+ });
39
+ return null;
40
+ }
41
+ if (!Array.isArray(config.ignore)) {
42
+ debugError('stampignore', 'readStampignore', {
43
+ stampignorePath,
44
+ message: 'Config.ignore must be an array',
45
+ });
46
+ return null;
47
+ }
48
+ return config;
49
+ }
50
+ catch (error) {
51
+ const err = error;
52
+ if (err.code === 'ENOENT') {
53
+ // File doesn't exist - that's fine, return null
54
+ return null;
55
+ }
56
+ debugError('stampignore', 'readStampignore', {
57
+ stampignorePath,
58
+ message: err.message,
59
+ code: err.code,
60
+ });
61
+ return null;
62
+ }
63
+ }
64
+ /**
65
+ * Write .stampignore content
66
+ */
67
+ export async function writeStampignore(targetDir, config) {
68
+ const stampignorePath = join(targetDir, STAMPIGNORE_FILENAME);
69
+ try {
70
+ const content = JSON.stringify(config, null, 2);
71
+ await writeFile(stampignorePath, content, 'utf-8');
72
+ }
73
+ catch (error) {
74
+ const err = error;
75
+ debugError('stampignore', 'writeStampignore', {
76
+ stampignorePath,
77
+ targetDir,
78
+ message: err.message,
79
+ code: err.code,
80
+ });
81
+ let userMessage;
82
+ switch (err.code) {
83
+ case 'ENOENT':
84
+ userMessage = `Parent directory not found for: "${stampignorePath}"`;
85
+ break;
86
+ case 'EACCES':
87
+ userMessage = `Permission denied writing to: "${stampignorePath}"`;
88
+ break;
89
+ case 'ENOSPC':
90
+ userMessage = `No space left on device. Cannot write: "${stampignorePath}"`;
91
+ break;
92
+ default:
93
+ userMessage = `Failed to write .stampignore file "${stampignorePath}": ${err.message}`;
94
+ }
95
+ throw new Error(userMessage);
96
+ }
97
+ }
98
+ /**
99
+ * Add paths to .stampignore
100
+ * Creates the file if it doesn't exist
101
+ */
102
+ export async function addToStampignore(targetDir, pathsToAdd) {
103
+ const exists = await stampignoreExists(targetDir);
104
+ const config = await readStampignore(targetDir);
105
+ const currentIgnore = config?.ignore || [];
106
+ const normalizedCurrent = currentIgnore.map(p => normalizeEntryId(p));
107
+ // Normalize paths to add and filter out duplicates
108
+ const normalizedToAdd = pathsToAdd
109
+ .map(p => normalizeEntryId(p))
110
+ .filter(p => !normalizedCurrent.includes(p));
111
+ if (normalizedToAdd.length === 0) {
112
+ return { added: false, created: false };
113
+ }
114
+ const newConfig = {
115
+ ignore: [...currentIgnore, ...normalizedToAdd],
116
+ };
117
+ await writeStampignore(targetDir, newConfig);
118
+ return { added: true, created: !exists };
119
+ }
120
+ /**
121
+ * Check if a file path matches any ignore pattern
122
+ * Supports glob patterns and exact paths
123
+ */
124
+ export function matchesIgnorePattern(filePath, patterns, projectRoot) {
125
+ // Get relative path from project root
126
+ // Use getRelativePath which properly handles Windows paths and converts to forward slashes
127
+ let relativePath;
128
+ if (isAbsolute(filePath)) {
129
+ relativePath = getRelativePath(projectRoot, filePath);
130
+ // If the relative path starts with '..', the file is outside the project root
131
+ // Don't match files outside the project root
132
+ if (relativePath.startsWith('../')) {
133
+ return false;
134
+ }
135
+ }
136
+ else {
137
+ relativePath = filePath;
138
+ }
139
+ // Handle edge case: if relative path is empty or just '.', skip matching
140
+ if (!relativePath || relativePath === '.' || relativePath === './') {
141
+ return false;
142
+ }
143
+ // Normalize the relative path for consistent matching
144
+ // normalizeEntryId normalizes path separators, drive letters, and removes leading ./
145
+ const normalizedRelativePath = normalizeEntryId(relativePath);
146
+ // Extract just the filename for filename-only pattern matching
147
+ const fileName = normalizedRelativePath.split('/').pop() || '';
148
+ for (const pattern of patterns) {
149
+ // Normalize the pattern (should already be relative, but normalize for consistency)
150
+ const normalizedPattern = normalizeEntryId(pattern);
151
+ // Exact match against full relative path
152
+ if (normalizedPattern === normalizedRelativePath) {
153
+ return true;
154
+ }
155
+ // Filename-only match: if pattern doesn't contain a slash, match against filename
156
+ // This allows patterns like "not-found.tsx" to match "src/not-found.tsx" or "app/not-found.tsx"
157
+ if (!normalizedPattern.includes('/') && normalizedPattern === fileName) {
158
+ return true;
159
+ }
160
+ // Glob pattern matching (simple implementation)
161
+ // Convert glob to regex
162
+ const regexPattern = normalizedPattern
163
+ .replace(/\./g, '\\.')
164
+ .replace(/\*\*/g, '.*')
165
+ .replace(/\*/g, '[^/]*')
166
+ .replace(/\?/g, '.');
167
+ const regex = new RegExp(`^${regexPattern}$`);
168
+ // Check against normalized relative path
169
+ if (regex.test(normalizedRelativePath)) {
170
+ return true;
171
+ }
172
+ // Also check filename-only glob patterns (e.g., "*.test.tsx")
173
+ if (!normalizedPattern.includes('/') && regex.test(fileName)) {
174
+ return true;
175
+ }
176
+ }
177
+ return false;
178
+ }
179
+ /**
180
+ * Filter files based on .stampignore patterns
181
+ */
182
+ export function filterIgnoredFiles(files, patterns, projectRoot) {
183
+ if (patterns.length === 0) {
184
+ return files;
185
+ }
186
+ return files.filter(file => !matchesIgnorePattern(file, patterns, projectRoot));
187
+ }
188
+ /**
189
+ * Delete .stampignore file
190
+ */
191
+ export async function deleteStampignore(targetDir) {
192
+ const stampignorePath = join(targetDir, STAMPIGNORE_FILENAME);
193
+ try {
194
+ await unlink(stampignorePath);
195
+ return true;
196
+ }
197
+ catch (error) {
198
+ const err = error;
199
+ if (err.code === 'ENOENT') {
200
+ // File doesn't exist - that's fine, return false
201
+ return false;
202
+ }
203
+ debugError('stampignore', 'deleteStampignore', {
204
+ stampignorePath,
205
+ message: err.message,
206
+ code: err.code,
207
+ });
208
+ throw new Error(`Failed to delete .stampignore: ${err.message}`);
209
+ }
210
+ }
211
+ //# sourceMappingURL=stampignore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stampignore.js","sourceRoot":"","sources":["../../src/utils/stampignore.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "logicstamp-context",
3
- "version": "0.2.6",
3
+ "version": "0.3.0",
4
4
  "description": "Generate AI-friendly context bundles from React codebases with LogicStamp contracts",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -117,7 +117,7 @@
117
117
  "source": {
118
118
  "type": "string",
119
119
  "pattern": "^logicstamp-context@\\d+\\.\\d+\\.\\d+$",
120
- "description": "Generator identifier with version (e.g., 'logicstamp-context@0.2.6'). Used for compatibility tracking and debugging."
120
+ "description": "Generator identifier with version (e.g., 'logicstamp-context@0.3.0'). Used for compatibility tracking and debugging."
121
121
  }
122
122
  },
123
123
  "additionalProperties": false