ai-fs-permissions 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 (58) hide show
  1. package/README.md +223 -0
  2. package/dist/checker.d.ts +6 -0
  3. package/dist/checker.d.ts.map +1 -0
  4. package/dist/checker.js +86 -0
  5. package/dist/checker.js.map +1 -0
  6. package/dist/cli-args.d.ts +25 -0
  7. package/dist/cli-args.d.ts.map +1 -0
  8. package/dist/cli-args.js +79 -0
  9. package/dist/cli-args.js.map +1 -0
  10. package/dist/cli-help.d.ts +2 -0
  11. package/dist/cli-help.d.ts.map +1 -0
  12. package/dist/cli-help.js +54 -0
  13. package/dist/cli-help.js.map +1 -0
  14. package/dist/cli.d.ts +9 -0
  15. package/dist/cli.d.ts.map +1 -0
  16. package/dist/cli.js +83 -0
  17. package/dist/cli.js.map +1 -0
  18. package/dist/config/loader.d.ts +22 -0
  19. package/dist/config/loader.d.ts.map +1 -0
  20. package/dist/config/loader.js +133 -0
  21. package/dist/config/loader.js.map +1 -0
  22. package/dist/config/schema.d.ts +102 -0
  23. package/dist/config/schema.d.ts.map +1 -0
  24. package/dist/config/schema.js +24 -0
  25. package/dist/config/schema.js.map +1 -0
  26. package/dist/exit-codes.d.ts +12 -0
  27. package/dist/exit-codes.d.ts.map +1 -0
  28. package/dist/exit-codes.js +12 -0
  29. package/dist/exit-codes.js.map +1 -0
  30. package/dist/index.d.ts +16 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +21 -0
  33. package/dist/index.js.map +1 -0
  34. package/dist/matcher/glob.d.ts +5 -0
  35. package/dist/matcher/glob.d.ts.map +1 -0
  36. package/dist/matcher/glob.js +18 -0
  37. package/dist/matcher/glob.js.map +1 -0
  38. package/dist/matcher/index.d.ts +8 -0
  39. package/dist/matcher/index.d.ts.map +1 -0
  40. package/dist/matcher/index.js +14 -0
  41. package/dist/matcher/index.js.map +1 -0
  42. package/dist/matcher/regex.d.ts +5 -0
  43. package/dist/matcher/regex.d.ts.map +1 -0
  44. package/dist/matcher/regex.js +16 -0
  45. package/dist/matcher/regex.js.map +1 -0
  46. package/dist/output.d.ts +18 -0
  47. package/dist/output.d.ts.map +1 -0
  48. package/dist/output.js +44 -0
  49. package/dist/output.js.map +1 -0
  50. package/dist/stdin.d.ts +21 -0
  51. package/dist/stdin.d.ts.map +1 -0
  52. package/dist/stdin.js +127 -0
  53. package/dist/stdin.js.map +1 -0
  54. package/dist/types.d.ts +60 -0
  55. package/dist/types.d.ts.map +1 -0
  56. package/dist/types.js +12 -0
  57. package/dist/types.js.map +1 -0
  58. package/package.json +75 -0
@@ -0,0 +1,133 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ import { parse as parseYaml } from 'yaml';
4
+ import { ConfigSchema } from './schema.js';
5
+ /**
6
+ * Default config file names to search for
7
+ */
8
+ const CONFIG_FILE_NAMES = ['.ai-fs-permissions.yaml', '.ai-fs-permissions.yml'];
9
+ /**
10
+ * User config directory
11
+ */
12
+ const USER_CONFIG_DIR = path.join(process.env.HOME ?? process.env.USERPROFILE ?? '', '.config', 'ai-fs-permissions');
13
+ /**
14
+ * Converts a raw rule from YAML to internal Rule format
15
+ */
16
+ function normalizeRule(raw) {
17
+ const rules = [];
18
+ const paths = raw.paths ?? [raw.path];
19
+ for (const p of paths) {
20
+ const negated = p.startsWith('!');
21
+ const cleanPath = negated ? p.slice(1) : p;
22
+ rules.push({
23
+ path: cleanPath,
24
+ type: (raw.type ?? 'glob'),
25
+ access: raw.access,
26
+ reason: raw.reason,
27
+ negated,
28
+ });
29
+ }
30
+ return rules;
31
+ }
32
+ /**
33
+ * Loads a config file from a path
34
+ */
35
+ export function loadConfigFile(filePath) {
36
+ try {
37
+ if (!fs.existsSync(filePath)) {
38
+ return null;
39
+ }
40
+ const content = fs.readFileSync(filePath, 'utf8');
41
+ const parsed = parseYaml(content);
42
+ const validated = ConfigSchema.parse(parsed);
43
+ const rules = [];
44
+ for (const rawRule of validated.rules) {
45
+ rules.push(...normalizeRule(rawRule));
46
+ }
47
+ return {
48
+ version: validated.version,
49
+ extends: validated.extends,
50
+ rules,
51
+ };
52
+ }
53
+ catch {
54
+ return null;
55
+ }
56
+ }
57
+ /**
58
+ * Finds config file by walking up the directory tree (gitignore-style)
59
+ */
60
+ export function findConfigFile(startDir) {
61
+ let currentDir = path.resolve(startDir);
62
+ const root = path.parse(currentDir).root;
63
+ while (currentDir !== root) {
64
+ for (const fileName of CONFIG_FILE_NAMES) {
65
+ const filePath = path.join(currentDir, fileName);
66
+ if (fs.existsSync(filePath)) {
67
+ return filePath;
68
+ }
69
+ }
70
+ currentDir = path.dirname(currentDir);
71
+ }
72
+ return null;
73
+ }
74
+ /**
75
+ * Gets the user config file path
76
+ */
77
+ export function getUserConfigPath() {
78
+ for (const fileName of CONFIG_FILE_NAMES) {
79
+ const filePath = path.join(USER_CONFIG_DIR, fileName.replace(/^\./, ''));
80
+ if (fs.existsSync(filePath)) {
81
+ return filePath;
82
+ }
83
+ }
84
+ // Also check for config.yaml
85
+ const configPath = path.join(USER_CONFIG_DIR, 'config.yaml');
86
+ if (fs.existsSync(configPath)) {
87
+ return configPath;
88
+ }
89
+ return null;
90
+ }
91
+ /**
92
+ * Merges multiple configs (later configs override earlier ones)
93
+ */
94
+ export function mergeConfigs(...configs) {
95
+ const merged = {
96
+ version: 1,
97
+ extends: true,
98
+ rules: [],
99
+ };
100
+ for (const config of configs) {
101
+ if (config === null)
102
+ continue;
103
+ merged.version = config.version;
104
+ merged.extends = config.extends;
105
+ merged.rules = [...merged.rules, ...config.rules];
106
+ }
107
+ return merged;
108
+ }
109
+ /**
110
+ * Loads and merges all applicable configs
111
+ */
112
+ export function loadConfig(cwd, explicitPath) {
113
+ // If explicit path provided, only use that
114
+ if (explicitPath) {
115
+ const config = loadConfigFile(explicitPath);
116
+ return config ?? { version: 1, extends: true, rules: [] };
117
+ }
118
+ // Load user config
119
+ const userConfigPath = getUserConfigPath();
120
+ const userConfig = userConfigPath ? loadConfigFile(userConfigPath) : null;
121
+ // Find and load project config
122
+ const projectConfigPath = findConfigFile(cwd);
123
+ const projectConfig = projectConfigPath
124
+ ? loadConfigFile(projectConfigPath)
125
+ : null;
126
+ // Check if project config wants to extend user config
127
+ if (projectConfig && !projectConfig.extends) {
128
+ return projectConfig;
129
+ }
130
+ // Merge configs (user first, project overrides)
131
+ return mergeConfigs(userConfig, projectConfig);
132
+ }
133
+ //# sourceMappingURL=loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,102 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Schema for a single permission rule
4
+ */
5
+ export declare const RuleSchema: z.ZodEffects<z.ZodObject<{
6
+ path: z.ZodString;
7
+ paths: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
8
+ type: z.ZodDefault<z.ZodEnum<["glob", "regex"]>>;
9
+ access: z.ZodEnum<["none", "read", "write", "readwrite"]>;
10
+ reason: z.ZodOptional<z.ZodString>;
11
+ }, "strip", z.ZodTypeAny, {
12
+ path: string;
13
+ type: "glob" | "regex";
14
+ access: "none" | "read" | "write" | "readwrite";
15
+ paths?: string[] | undefined;
16
+ reason?: string | undefined;
17
+ }, {
18
+ path: string;
19
+ access: "none" | "read" | "write" | "readwrite";
20
+ type?: "glob" | "regex" | undefined;
21
+ paths?: string[] | undefined;
22
+ reason?: string | undefined;
23
+ }>, {
24
+ path: string;
25
+ type: "glob" | "regex";
26
+ access: "none" | "read" | "write" | "readwrite";
27
+ paths?: string[] | undefined;
28
+ reason?: string | undefined;
29
+ }, {
30
+ path: string;
31
+ access: "none" | "read" | "write" | "readwrite";
32
+ type?: "glob" | "regex" | undefined;
33
+ paths?: string[] | undefined;
34
+ reason?: string | undefined;
35
+ }>;
36
+ /**
37
+ * Schema for the configuration file
38
+ */
39
+ export declare const ConfigSchema: z.ZodObject<{
40
+ version: z.ZodDefault<z.ZodNumber>;
41
+ extends: z.ZodDefault<z.ZodBoolean>;
42
+ rules: z.ZodDefault<z.ZodArray<z.ZodEffects<z.ZodObject<{
43
+ path: z.ZodString;
44
+ paths: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
45
+ type: z.ZodDefault<z.ZodEnum<["glob", "regex"]>>;
46
+ access: z.ZodEnum<["none", "read", "write", "readwrite"]>;
47
+ reason: z.ZodOptional<z.ZodString>;
48
+ }, "strip", z.ZodTypeAny, {
49
+ path: string;
50
+ type: "glob" | "regex";
51
+ access: "none" | "read" | "write" | "readwrite";
52
+ paths?: string[] | undefined;
53
+ reason?: string | undefined;
54
+ }, {
55
+ path: string;
56
+ access: "none" | "read" | "write" | "readwrite";
57
+ type?: "glob" | "regex" | undefined;
58
+ paths?: string[] | undefined;
59
+ reason?: string | undefined;
60
+ }>, {
61
+ path: string;
62
+ type: "glob" | "regex";
63
+ access: "none" | "read" | "write" | "readwrite";
64
+ paths?: string[] | undefined;
65
+ reason?: string | undefined;
66
+ }, {
67
+ path: string;
68
+ access: "none" | "read" | "write" | "readwrite";
69
+ type?: "glob" | "regex" | undefined;
70
+ paths?: string[] | undefined;
71
+ reason?: string | undefined;
72
+ }>, "many">>;
73
+ }, "strip", z.ZodTypeAny, {
74
+ version: number;
75
+ extends: boolean;
76
+ rules: {
77
+ path: string;
78
+ type: "glob" | "regex";
79
+ access: "none" | "read" | "write" | "readwrite";
80
+ paths?: string[] | undefined;
81
+ reason?: string | undefined;
82
+ }[];
83
+ }, {
84
+ version?: number | undefined;
85
+ extends?: boolean | undefined;
86
+ rules?: {
87
+ path: string;
88
+ access: "none" | "read" | "write" | "readwrite";
89
+ type?: "glob" | "regex" | undefined;
90
+ paths?: string[] | undefined;
91
+ reason?: string | undefined;
92
+ }[] | undefined;
93
+ }>;
94
+ /**
95
+ * Raw rule type from YAML
96
+ */
97
+ export type RawRule = z.infer<typeof RuleSchema>;
98
+ /**
99
+ * Raw config type from YAML
100
+ */
101
+ export type RawConfig = z.infer<typeof ConfigSchema>;
102
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/config/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB;;GAEG;AACH,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAUnB,CAAA;AAEJ;;GAEG;AACH,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAIvB,CAAA;AAEF;;GAEG;AACH,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAA;AAEhD;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAA"}
@@ -0,0 +1,24 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Schema for a single permission rule
4
+ */
5
+ export const RuleSchema = z
6
+ .object({
7
+ path: z.string().min(1),
8
+ paths: z.array(z.string().min(1)).optional(),
9
+ type: z.enum(['glob', 'regex']).default('glob'),
10
+ access: z.enum(['none', 'read', 'write', 'readwrite']),
11
+ reason: z.string().optional(),
12
+ })
13
+ .refine(data => data.path || (data.paths && data.paths.length > 0), {
14
+ message: 'Either path or paths must be provided',
15
+ });
16
+ /**
17
+ * Schema for the configuration file
18
+ */
19
+ export const ConfigSchema = z.object({
20
+ version: z.number().int().positive().default(1),
21
+ extends: z.boolean().default(true),
22
+ rules: z.array(RuleSchema).default([]),
23
+ });
24
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/config/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB;;GAEG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC;KACxB,MAAM,CAAC;IACN,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACvB,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IAC5C,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;IAC/C,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;IACtD,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC9B,CAAC;KACD,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE;IAClE,OAAO,EAAE,uCAAuC;CACjD,CAAC,CAAA;AAEJ;;GAEG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IACnC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAC/C,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IAClC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;CACvC,CAAC,CAAA"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Exit codes for the CLI
3
+ */
4
+ export declare const EXIT_CODES: {
5
+ /** Operation is allowed to proceed */
6
+ readonly ALLOWED: 0;
7
+ /** Operation is blocked */
8
+ readonly BLOCKED: 2;
9
+ /** An error occurred */
10
+ readonly ERROR: 1;
11
+ };
12
+ //# sourceMappingURL=exit-codes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exit-codes.d.ts","sourceRoot":"","sources":["../src/exit-codes.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,UAAU;IACrB,sCAAsC;;IAEtC,2BAA2B;;IAE3B,wBAAwB;;CAEhB,CAAA"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Exit codes for the CLI
3
+ */
4
+ export const EXIT_CODES = {
5
+ /** Operation is allowed to proceed */
6
+ ALLOWED: 0,
7
+ /** Operation is blocked */
8
+ BLOCKED: 2,
9
+ /** An error occurred */
10
+ ERROR: 1,
11
+ };
12
+ //# sourceMappingURL=exit-codes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exit-codes.js","sourceRoot":"","sources":["../src/exit-codes.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,sCAAsC;IACtC,OAAO,EAAE,CAAC;IACV,2BAA2B;IAC3B,OAAO,EAAE,CAAC;IACV,wBAAwB;IACxB,KAAK,EAAE,CAAC;CACA,CAAA"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * ai-fs-permissions
3
+ *
4
+ * A platform-agnostic security tool that enforces file system permissions
5
+ * for AI agents. Protects sensitive files and folders from unauthorized access.
6
+ */
7
+ export type { AccessLevel, Operation, PatternType, Rule, Config, CheckResult, } from './types.js';
8
+ export { TOOL_OPERATIONS } from './types.js';
9
+ export { EXIT_CODES } from './exit-codes.js';
10
+ export { loadConfig, loadConfigFile, findConfigFile } from './config/loader.js';
11
+ export { ConfigSchema, RuleSchema } from './config/schema.js';
12
+ export { matchPath, matchGlob, matchRegex } from './matcher/index.js';
13
+ export { checkPermission } from './checker.js';
14
+ export { formatBlockedMessage, formatAllowedMessage, formatResultJson, outputResult, } from './output.js';
15
+ export { parseStdin, readStdin } from './stdin.js';
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,YAAY,EACV,WAAW,EACX,SAAS,EACT,WAAW,EACX,IAAI,EACJ,MAAM,EACN,WAAW,GACZ,MAAM,YAAY,CAAA;AAEnB,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAG5C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAG5C,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAC/E,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAG7D,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAGrE,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAG9C,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,gBAAgB,EAChB,YAAY,GACb,MAAM,aAAa,CAAA;AAGpB,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,21 @@
1
+ /**
2
+ * ai-fs-permissions
3
+ *
4
+ * A platform-agnostic security tool that enforces file system permissions
5
+ * for AI agents. Protects sensitive files and folders from unauthorized access.
6
+ */
7
+ export { TOOL_OPERATIONS } from './types.js';
8
+ // Exit codes
9
+ export { EXIT_CODES } from './exit-codes.js';
10
+ // Config
11
+ export { loadConfig, loadConfigFile, findConfigFile } from './config/loader.js';
12
+ export { ConfigSchema, RuleSchema } from './config/schema.js';
13
+ // Matchers
14
+ export { matchPath, matchGlob, matchRegex } from './matcher/index.js';
15
+ // Core
16
+ export { checkPermission } from './checker.js';
17
+ // Output
18
+ export { formatBlockedMessage, formatAllowedMessage, formatResultJson, outputResult, } from './output.js';
19
+ // Stdin
20
+ export { parseStdin, readStdin } from './stdin.js';
21
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAYH,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAE5C,aAAa;AACb,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAE5C,SAAS;AACT,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAC/E,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAE7D,WAAW;AACX,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAErE,OAAO;AACP,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAE9C,SAAS;AACT,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,gBAAgB,EAChB,YAAY,GACb,MAAM,aAAa,CAAA;AAEpB,QAAQ;AACR,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Tests if a path matches a glob pattern (gitignore-style)
3
+ */
4
+ export declare function matchGlob(pattern: string, filePath: string): boolean;
5
+ //# sourceMappingURL=glob.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"glob.d.ts","sourceRoot":"","sources":["../../src/matcher/glob.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAcpE"}
@@ -0,0 +1,18 @@
1
+ import picomatch from 'picomatch';
2
+ /**
3
+ * Tests if a path matches a glob pattern (gitignore-style)
4
+ */
5
+ export function matchGlob(pattern, filePath) {
6
+ // Normalize path separators
7
+ const normalizedPath = filePath.replace(/\\/g, '/');
8
+ const normalizedPattern = pattern.replace(/\\/g, '/');
9
+ // Create matcher with gitignore-like options
10
+ const isMatch = picomatch(normalizedPattern, {
11
+ dot: true, // Match dotfiles
12
+ bash: true, // Enable bash-like globbing
13
+ nobrace: false, // Enable brace expansion
14
+ noglobstar: false, // Enable **
15
+ });
16
+ return isMatch(normalizedPath);
17
+ }
18
+ //# sourceMappingURL=glob.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"glob.js","sourceRoot":"","sources":["../../src/matcher/glob.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,WAAW,CAAA;AAEjC;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,OAAe,EAAE,QAAgB;IACzD,4BAA4B;IAC5B,MAAM,cAAc,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;IACnD,MAAM,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;IAErD,6CAA6C;IAC7C,MAAM,OAAO,GAAG,SAAS,CAAC,iBAAiB,EAAE;QAC3C,GAAG,EAAE,IAAI,EAAE,iBAAiB;QAC5B,IAAI,EAAE,IAAI,EAAE,4BAA4B;QACxC,OAAO,EAAE,KAAK,EAAE,yBAAyB;QACzC,UAAU,EAAE,KAAK,EAAE,YAAY;KAChC,CAAC,CAAA;IAEF,OAAO,OAAO,CAAC,cAAc,CAAC,CAAA;AAChC,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { PatternType } from '../types.js';
2
+ /**
3
+ * Tests if a path matches a pattern of the specified type
4
+ */
5
+ export declare function matchPath(pattern: string, type: PatternType, filePath: string): boolean;
6
+ export { matchGlob } from './glob.js';
7
+ export { matchRegex } from './regex.js';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/matcher/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAI9C;;GAEG;AACH,wBAAgB,SAAS,CACvB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,WAAW,EACjB,QAAQ,EAAE,MAAM,GACf,OAAO,CAKT;AAED,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AACrC,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA"}
@@ -0,0 +1,14 @@
1
+ import { matchGlob } from './glob.js';
2
+ import { matchRegex } from './regex.js';
3
+ /**
4
+ * Tests if a path matches a pattern of the specified type
5
+ */
6
+ export function matchPath(pattern, type, filePath) {
7
+ if (type === 'regex') {
8
+ return matchRegex(pattern, filePath);
9
+ }
10
+ return matchGlob(pattern, filePath);
11
+ }
12
+ export { matchGlob } from './glob.js';
13
+ export { matchRegex } from './regex.js';
14
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/matcher/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AACrC,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAEvC;;GAEG;AACH,MAAM,UAAU,SAAS,CACvB,OAAe,EACf,IAAiB,EACjB,QAAgB;IAEhB,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;QACrB,OAAO,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAA;IACtC,CAAC;IACD,OAAO,SAAS,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAA;AACrC,CAAC;AAED,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AACrC,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Tests if a path matches a regex pattern
3
+ */
4
+ export declare function matchRegex(pattern: string, filePath: string): boolean;
5
+ //# sourceMappingURL=regex.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"regex.d.ts","sourceRoot":"","sources":["../../src/matcher/regex.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAUrE"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Tests if a path matches a regex pattern
3
+ */
4
+ export function matchRegex(pattern, filePath) {
5
+ try {
6
+ const regex = new RegExp(pattern);
7
+ // Normalize path separators for consistent matching
8
+ const normalizedPath = filePath.replace(/\\/g, '/');
9
+ return regex.test(normalizedPath);
10
+ }
11
+ catch {
12
+ // Invalid regex pattern
13
+ return false;
14
+ }
15
+ }
16
+ //# sourceMappingURL=regex.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"regex.js","sourceRoot":"","sources":["../../src/matcher/regex.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,OAAe,EAAE,QAAgB;IAC1D,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,OAAO,CAAC,CAAA;QACjC,oDAAoD;QACpD,MAAM,cAAc,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;QACnD,OAAO,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAA;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,wBAAwB;QACxB,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC"}
@@ -0,0 +1,18 @@
1
+ import type { Operation, Rule, CheckResult } from './types.js';
2
+ /**
3
+ * Formats a blocked message with clear instructions for LLMs
4
+ */
5
+ export declare function formatBlockedMessage(path: string, operation: Operation, rule: Rule): string;
6
+ /**
7
+ * Formats an allowed message
8
+ */
9
+ export declare function formatAllowedMessage(path: string, operation: Operation): string;
10
+ /**
11
+ * Formats the check result as JSON for stdout
12
+ */
13
+ export declare function formatResultJson(result: CheckResult): string;
14
+ /**
15
+ * Outputs the result to stdout/stderr as appropriate
16
+ */
17
+ export declare function outputResult(result: CheckResult): void;
18
+ //# sourceMappingURL=output.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAE9D;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,SAAS,EACpB,IAAI,EAAE,IAAI,GACT,MAAM,CAeR;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,SAAS,GACnB,MAAM,CAER;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAE5D;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAStD"}
package/dist/output.js ADDED
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Formats a blocked message with clear instructions for LLMs
3
+ */
4
+ export function formatBlockedMessage(path, operation, rule) {
5
+ const operationVerb = operation === 'read' ? 'Reading from' : 'Writing to';
6
+ const reason = rule.reason ?? 'Access restricted by project configuration';
7
+ return `PERMISSION DENIED: ${operationVerb} '${path}' is blocked.
8
+
9
+ Reason: ${reason}
10
+
11
+ This rule is configured by the project owner and cannot be overridden.
12
+ Do NOT attempt to:
13
+ - Use Bash commands to bypass this restriction
14
+ - Suggest workarounds that modify this path
15
+ - Ask the user to disable this protection
16
+
17
+ If this file must be modified, ask the user to do it manually.`;
18
+ }
19
+ /**
20
+ * Formats an allowed message
21
+ */
22
+ export function formatAllowedMessage(path, operation) {
23
+ return `Operation permitted: ${operation} on '${path}'`;
24
+ }
25
+ /**
26
+ * Formats the check result as JSON for stdout
27
+ */
28
+ export function formatResultJson(result) {
29
+ return JSON.stringify(result, null, 2);
30
+ }
31
+ /**
32
+ * Outputs the result to stdout/stderr as appropriate
33
+ */
34
+ export function outputResult(result) {
35
+ const json = formatResultJson(result);
36
+ if (result.allowed) {
37
+ console.log(json);
38
+ }
39
+ else {
40
+ // Output to stderr for blocked operations
41
+ console.error(json);
42
+ }
43
+ }
44
+ //# sourceMappingURL=output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.js","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAClC,IAAY,EACZ,SAAoB,EACpB,IAAU;IAEV,MAAM,aAAa,GAAG,SAAS,KAAK,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,YAAY,CAAA;IAC1E,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,4CAA4C,CAAA;IAE1E,OAAO,sBAAsB,aAAa,KAAK,IAAI;;UAE3C,MAAM;;;;;;;;+DAQ+C,CAAA;AAC/D,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAClC,IAAY,EACZ,SAAoB;IAEpB,OAAO,wBAAwB,SAAS,QAAQ,IAAI,GAAG,CAAA;AACzD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAmB;IAClD,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;AACxC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,MAAmB;IAC9C,MAAM,IAAI,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAA;IAErC,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IACnB,CAAC;SAAM,CAAC;QACN,0CAA0C;QAC1C,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IACrB,CAAC;AACH,CAAC"}
@@ -0,0 +1,21 @@
1
+ import { type Operation } from './types.js';
2
+ /**
3
+ * Result of parsing stdin input
4
+ */
5
+ export interface StdinParseResult {
6
+ /** The file path extracted from input */
7
+ path: string | null;
8
+ /** The tool name if detected */
9
+ tool?: string;
10
+ /** The inferred operation based on tool */
11
+ inferredOperation?: Operation;
12
+ }
13
+ /**
14
+ * Parses stdin input and extracts file path
15
+ */
16
+ export declare function parseStdin(input: string): StdinParseResult;
17
+ /**
18
+ * Reads stdin asynchronously
19
+ */
20
+ export declare function readStdin(): Promise<string>;
21
+ //# sourceMappingURL=stdin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stdin.d.ts","sourceRoot":"","sources":["../src/stdin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,SAAS,EAAE,MAAM,YAAY,CAAA;AAE5D;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,yCAAyC;IACzC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,gCAAgC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,2CAA2C;IAC3C,iBAAiB,CAAC,EAAE,SAAS,CAAA;CAC9B;AA2FD;;GAEG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,CAqB1D;AAED;;GAEG;AACH,wBAAsB,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC,CAsBjD"}