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.
- package/README.md +223 -0
- package/dist/checker.d.ts +6 -0
- package/dist/checker.d.ts.map +1 -0
- package/dist/checker.js +86 -0
- package/dist/checker.js.map +1 -0
- package/dist/cli-args.d.ts +25 -0
- package/dist/cli-args.d.ts.map +1 -0
- package/dist/cli-args.js +79 -0
- package/dist/cli-args.js.map +1 -0
- package/dist/cli-help.d.ts +2 -0
- package/dist/cli-help.d.ts.map +1 -0
- package/dist/cli-help.js +54 -0
- package/dist/cli-help.js.map +1 -0
- package/dist/cli.d.ts +9 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +83 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/loader.d.ts +22 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +133 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/schema.d.ts +102 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +24 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/exit-codes.d.ts +12 -0
- package/dist/exit-codes.d.ts.map +1 -0
- package/dist/exit-codes.js +12 -0
- package/dist/exit-codes.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/matcher/glob.d.ts +5 -0
- package/dist/matcher/glob.d.ts.map +1 -0
- package/dist/matcher/glob.js +18 -0
- package/dist/matcher/glob.js.map +1 -0
- package/dist/matcher/index.d.ts +8 -0
- package/dist/matcher/index.d.ts.map +1 -0
- package/dist/matcher/index.js +14 -0
- package/dist/matcher/index.js.map +1 -0
- package/dist/matcher/regex.d.ts +5 -0
- package/dist/matcher/regex.d.ts.map +1 -0
- package/dist/matcher/regex.js +16 -0
- package/dist/matcher/regex.js.map +1 -0
- package/dist/output.d.ts +18 -0
- package/dist/output.d.ts.map +1 -0
- package/dist/output.js +44 -0
- package/dist/output.js.map +1 -0
- package/dist/stdin.d.ts +21 -0
- package/dist/stdin.d.ts.map +1 -0
- package/dist/stdin.js +127 -0
- package/dist/stdin.js.map +1 -0
- package/dist/types.d.ts +60 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +12 -0
- package/dist/types.js.map +1 -0
- package/package.json +75 -0
package/README.md
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
# ai-fs-permissions
|
|
2
|
+
|
|
3
|
+
A platform-agnostic security tool that enforces file system permissions for AI agents. Designed to protect sensitive files and folders from unauthorized access by AI coding assistants.
|
|
4
|
+
|
|
5
|
+
## Why?
|
|
6
|
+
|
|
7
|
+
When using AI coding assistants like Claude Code, Gemini CLI, or Cursor, you might want to:
|
|
8
|
+
- Protect configuration folders (`.centy`, `.claude`, `.github`)
|
|
9
|
+
- Make certain files read-only (lock files, configs)
|
|
10
|
+
- Block access to sensitive files (`.env`, secrets, keys)
|
|
11
|
+
- Allow read but block write to specific paths
|
|
12
|
+
|
|
13
|
+
This package provides a CLI that can enforce these permissions, working with any AI tool that supports command hooks.
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pnpm add -g ai-fs-permissions
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Or use without installation via `pnpm dlx ai-fs-permissions` or `npx ai-fs-permissions`.
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# Check if writing to .centy is allowed
|
|
27
|
+
ai-fs-permissions --op write --path ".centy/config.json"
|
|
28
|
+
# Exit code: 2 (blocked if configured)
|
|
29
|
+
|
|
30
|
+
# Check if reading is allowed
|
|
31
|
+
ai-fs-permissions --op read --path "src/index.ts"
|
|
32
|
+
# Exit code: 0 (allowed)
|
|
33
|
+
|
|
34
|
+
# Show current configuration
|
|
35
|
+
ai-fs-permissions --show-config
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Configuration
|
|
39
|
+
|
|
40
|
+
Create `.ai-fs-permissions.yaml` in your project root:
|
|
41
|
+
|
|
42
|
+
```yaml
|
|
43
|
+
version: 1
|
|
44
|
+
|
|
45
|
+
rules:
|
|
46
|
+
# Protect centy configuration (read-only)
|
|
47
|
+
- path: ".centy/**"
|
|
48
|
+
access: read
|
|
49
|
+
reason: "Configuration folder - modifications may break tooling"
|
|
50
|
+
|
|
51
|
+
# Protect AI agent settings
|
|
52
|
+
- path: ".claude/**"
|
|
53
|
+
access: read
|
|
54
|
+
reason: "AI agent settings - must be modified by user only"
|
|
55
|
+
|
|
56
|
+
# Block all access to env files
|
|
57
|
+
- path: "**/.env*"
|
|
58
|
+
access: none
|
|
59
|
+
reason: "Environment secrets - sensitive data"
|
|
60
|
+
|
|
61
|
+
# Block key files using regex
|
|
62
|
+
- path: "^.*\\.key$"
|
|
63
|
+
type: regex
|
|
64
|
+
access: none
|
|
65
|
+
reason: "Key files contain sensitive credentials"
|
|
66
|
+
|
|
67
|
+
# Allow specific file within protected folder (negation)
|
|
68
|
+
- path: "!.centy/user-config.yaml"
|
|
69
|
+
access: readwrite
|
|
70
|
+
reason: "User-editable config"
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Access Levels
|
|
74
|
+
|
|
75
|
+
| Level | Read | Write | Description |
|
|
76
|
+
|-------|------|-------|-------------|
|
|
77
|
+
| `none` | Blocked | Blocked | Fully blocked |
|
|
78
|
+
| `read` | Allowed | Blocked | Read-only |
|
|
79
|
+
| `write` | Blocked | Allowed | Write-only (rare) |
|
|
80
|
+
| `readwrite` | Allowed | Allowed | Full access |
|
|
81
|
+
|
|
82
|
+
### Config Discovery
|
|
83
|
+
|
|
84
|
+
Configs are discovered gitignore-style and merged:
|
|
85
|
+
|
|
86
|
+
1. `~/.config/ai-fs-permissions/config.yaml` (user defaults)
|
|
87
|
+
2. Walk up from cwd to find `.ai-fs-permissions.yaml` (project)
|
|
88
|
+
3. `./.ai-fs-permissions.yaml` (current directory, highest priority)
|
|
89
|
+
|
|
90
|
+
Set `extends: false` in project config to ignore user defaults.
|
|
91
|
+
|
|
92
|
+
## Platform Integration
|
|
93
|
+
|
|
94
|
+
### Claude Code
|
|
95
|
+
|
|
96
|
+
Add to your `.claude/settings.json`:
|
|
97
|
+
|
|
98
|
+
```json
|
|
99
|
+
{
|
|
100
|
+
"hooks": {
|
|
101
|
+
"PreToolUse": [
|
|
102
|
+
{
|
|
103
|
+
"matcher": "Read|Glob|Grep",
|
|
104
|
+
"hooks": [
|
|
105
|
+
{
|
|
106
|
+
"type": "command",
|
|
107
|
+
"command": "npx ai-fs-permissions --op read"
|
|
108
|
+
}
|
|
109
|
+
]
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"matcher": "Edit|Write|NotebookEdit",
|
|
113
|
+
"hooks": [
|
|
114
|
+
{
|
|
115
|
+
"type": "command",
|
|
116
|
+
"command": "npx ai-fs-permissions --op write"
|
|
117
|
+
}
|
|
118
|
+
]
|
|
119
|
+
}
|
|
120
|
+
]
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Gemini CLI
|
|
126
|
+
|
|
127
|
+
Add to your `.gemini/settings.json`:
|
|
128
|
+
|
|
129
|
+
```json
|
|
130
|
+
{
|
|
131
|
+
"hooks": {
|
|
132
|
+
"BeforeTool": [
|
|
133
|
+
{
|
|
134
|
+
"matcher": "read_file",
|
|
135
|
+
"hooks": [
|
|
136
|
+
{
|
|
137
|
+
"type": "command",
|
|
138
|
+
"command": "npx ai-fs-permissions --op read"
|
|
139
|
+
}
|
|
140
|
+
]
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
"matcher": "write_file|edit_file",
|
|
144
|
+
"hooks": [
|
|
145
|
+
{
|
|
146
|
+
"type": "command",
|
|
147
|
+
"command": "npx ai-fs-permissions --op write"
|
|
148
|
+
}
|
|
149
|
+
]
|
|
150
|
+
}
|
|
151
|
+
]
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Cursor
|
|
157
|
+
|
|
158
|
+
Create `.cursor/hooks.json`:
|
|
159
|
+
|
|
160
|
+
```json
|
|
161
|
+
{
|
|
162
|
+
"version": 1,
|
|
163
|
+
"hooks": {
|
|
164
|
+
"beforeShellExecution": [
|
|
165
|
+
{
|
|
166
|
+
"command": "npx ai-fs-permissions --op write"
|
|
167
|
+
}
|
|
168
|
+
]
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## CLI Options
|
|
174
|
+
|
|
175
|
+
```
|
|
176
|
+
ai-fs-permissions [options] [path]
|
|
177
|
+
|
|
178
|
+
Options:
|
|
179
|
+
--op <type> Operation to check: read, write (required)
|
|
180
|
+
--path <path> File path to check
|
|
181
|
+
--config <path> Use specific config file (skip discovery)
|
|
182
|
+
--show-config Show merged configuration and exit
|
|
183
|
+
--validate Validate config file and exit
|
|
184
|
+
--help, -h Show help message
|
|
185
|
+
--version, -v Show version
|
|
186
|
+
|
|
187
|
+
Input Methods:
|
|
188
|
+
1. Command line: ai-fs-permissions --op write --path ".centy/config.json"
|
|
189
|
+
2. Stdin (JSON): echo '{"tool_input":{"file_path":"..."}}' | ai-fs-permissions --op write
|
|
190
|
+
3. Stdin (plain): echo ".centy/config.json" | ai-fs-permissions --op write
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Exit Codes
|
|
194
|
+
|
|
195
|
+
- `0` - Operation allowed
|
|
196
|
+
- `2` - Operation blocked
|
|
197
|
+
- `1` - Error occurred
|
|
198
|
+
|
|
199
|
+
## Blocked Message
|
|
200
|
+
|
|
201
|
+
When an operation is blocked, a clear message is output to guide the AI agent:
|
|
202
|
+
|
|
203
|
+
```
|
|
204
|
+
PERMISSION DENIED: Writing to '.centy/settings.json' is blocked.
|
|
205
|
+
|
|
206
|
+
Reason: Configuration folder - modifications may break tooling
|
|
207
|
+
|
|
208
|
+
This rule is configured by the project owner and cannot be overridden.
|
|
209
|
+
Do NOT attempt to:
|
|
210
|
+
- Use Bash commands to bypass this restriction
|
|
211
|
+
- Suggest workarounds that modify this path
|
|
212
|
+
- Ask the user to disable this protection
|
|
213
|
+
|
|
214
|
+
If this file must be modified, ask the user to do it manually.
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## License
|
|
218
|
+
|
|
219
|
+
MIT
|
|
220
|
+
|
|
221
|
+
## Related Projects
|
|
222
|
+
|
|
223
|
+
- [block-no-verify](https://github.com/tupe12334/block-no-verify) - Block `--no-verify` flag in git commands
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Config, Operation, CheckResult } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Checks if an operation on a path is allowed
|
|
4
|
+
*/
|
|
5
|
+
export declare function checkPermission(config: Config, filePath: string, operation: Operation): CheckResult;
|
|
6
|
+
//# sourceMappingURL=checker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checker.d.ts","sourceRoot":"","sources":["../src/checker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,MAAM,EAEN,SAAS,EAET,WAAW,EACZ,MAAM,YAAY,CAAA;AA8CnB;;GAEG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,SAAS,GACnB,WAAW,CAsDb"}
|
package/dist/checker.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { matchPath } from './matcher/index.js';
|
|
2
|
+
import { formatBlockedMessage, formatAllowedMessage } from './output.js';
|
|
3
|
+
/**
|
|
4
|
+
* Checks if an access level allows the given operation
|
|
5
|
+
*/
|
|
6
|
+
function isOperationAllowed(access, operation) {
|
|
7
|
+
switch (access) {
|
|
8
|
+
case 'none':
|
|
9
|
+
return false;
|
|
10
|
+
case 'read':
|
|
11
|
+
return operation === 'read';
|
|
12
|
+
case 'write':
|
|
13
|
+
return operation === 'write';
|
|
14
|
+
case 'readwrite':
|
|
15
|
+
return true;
|
|
16
|
+
default:
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Finds the matching rule for a path
|
|
22
|
+
* Rules are evaluated in order, with later rules overriding earlier ones
|
|
23
|
+
* Negation rules (!) grant access back
|
|
24
|
+
*/
|
|
25
|
+
function findMatchingRule(rules, filePath) {
|
|
26
|
+
let lastMatch = null;
|
|
27
|
+
for (let i = 0; i < rules.length; i++) {
|
|
28
|
+
const rule = rules[i];
|
|
29
|
+
if (matchPath(rule.path, rule.type, filePath)) {
|
|
30
|
+
lastMatch = { rule, index: i };
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return lastMatch;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Checks if an operation on a path is allowed
|
|
37
|
+
*/
|
|
38
|
+
export function checkPermission(config, filePath, operation) {
|
|
39
|
+
// Normalize path (remove leading ./ if present)
|
|
40
|
+
const normalizedPath = filePath.replace(/^\.\//, '');
|
|
41
|
+
// Find matching rule
|
|
42
|
+
const match = findMatchingRule(config.rules, normalizedPath);
|
|
43
|
+
// No matching rule = passthrough (allowed)
|
|
44
|
+
if (match === null) {
|
|
45
|
+
return {
|
|
46
|
+
allowed: true,
|
|
47
|
+
path: normalizedPath,
|
|
48
|
+
operation,
|
|
49
|
+
message: formatAllowedMessage(normalizedPath, operation),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
const { rule } = match;
|
|
53
|
+
// Negation rules grant access back
|
|
54
|
+
if (rule.negated) {
|
|
55
|
+
return {
|
|
56
|
+
allowed: true,
|
|
57
|
+
path: normalizedPath,
|
|
58
|
+
operation,
|
|
59
|
+
rule: `!${rule.path}`,
|
|
60
|
+
access: rule.access,
|
|
61
|
+
message: formatAllowedMessage(normalizedPath, operation),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
// Check if operation is allowed by the access level
|
|
65
|
+
const allowed = isOperationAllowed(rule.access, operation);
|
|
66
|
+
if (allowed) {
|
|
67
|
+
return {
|
|
68
|
+
allowed: true,
|
|
69
|
+
path: normalizedPath,
|
|
70
|
+
operation,
|
|
71
|
+
rule: rule.path,
|
|
72
|
+
access: rule.access,
|
|
73
|
+
message: formatAllowedMessage(normalizedPath, operation),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
// Operation is blocked
|
|
77
|
+
return {
|
|
78
|
+
allowed: false,
|
|
79
|
+
path: normalizedPath,
|
|
80
|
+
operation,
|
|
81
|
+
rule: rule.path,
|
|
82
|
+
access: rule.access,
|
|
83
|
+
message: formatBlockedMessage(normalizedPath, operation, rule),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=checker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checker.js","sourceRoot":"","sources":["../src/checker.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAC9C,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAExE;;GAEG;AACH,SAAS,kBAAkB,CACzB,MAAmB,EACnB,SAAoB;IAEpB,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,MAAM;YACT,OAAO,KAAK,CAAA;QACd,KAAK,MAAM;YACT,OAAO,SAAS,KAAK,MAAM,CAAA;QAC7B,KAAK,OAAO;YACV,OAAO,SAAS,KAAK,OAAO,CAAA;QAC9B,KAAK,WAAW;YACd,OAAO,IAAI,CAAA;QACb;YACE,OAAO,IAAI,CAAA;IACf,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,SAAS,gBAAgB,CACvB,KAAa,EACb,QAAgB;IAEhB,IAAI,SAAS,GAAyC,IAAI,CAAA;IAE1D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;QACrB,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,CAAC;YAC9C,SAAS,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,CAAA;QAChC,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAA;AAClB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAC7B,MAAc,EACd,QAAgB,EAChB,SAAoB;IAEpB,gDAAgD;IAChD,MAAM,cAAc,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAA;IAEpD,qBAAqB;IACrB,MAAM,KAAK,GAAG,gBAAgB,CAAC,MAAM,CAAC,KAAK,EAAE,cAAc,CAAC,CAAA;IAE5D,2CAA2C;IAC3C,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACnB,OAAO;YACL,OAAO,EAAE,IAAI;YACb,IAAI,EAAE,cAAc;YACpB,SAAS;YACT,OAAO,EAAE,oBAAoB,CAAC,cAAc,EAAE,SAAS,CAAC;SACzD,CAAA;IACH,CAAC;IAED,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,CAAA;IAEtB,mCAAmC;IACnC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QACjB,OAAO;YACL,OAAO,EAAE,IAAI;YACb,IAAI,EAAE,cAAc;YACpB,SAAS;YACT,IAAI,EAAE,IAAI,IAAI,CAAC,IAAI,EAAE;YACrB,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,OAAO,EAAE,oBAAoB,CAAC,cAAc,EAAE,SAAS,CAAC;SACzD,CAAA;IACH,CAAC;IAED,oDAAoD;IACpD,MAAM,OAAO,GAAG,kBAAkB,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;IAE1D,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO;YACL,OAAO,EAAE,IAAI;YACb,IAAI,EAAE,cAAc;YACpB,SAAS;YACT,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,OAAO,EAAE,oBAAoB,CAAC,cAAc,EAAE,SAAS,CAAC;SACzD,CAAA;IACH,CAAC;IAED,uBAAuB;IACvB,OAAO;QACL,OAAO,EAAE,KAAK;QACd,IAAI,EAAE,cAAc;QACpB,SAAS;QACT,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,OAAO,EAAE,oBAAoB,CAAC,cAAc,EAAE,SAAS,EAAE,IAAI,CAAC;KAC/D,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Operation } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Parsed CLI arguments
|
|
4
|
+
*/
|
|
5
|
+
export interface CliArgs {
|
|
6
|
+
/** Operation to check (read/write) */
|
|
7
|
+
operation: Operation | null;
|
|
8
|
+
/** File path to check */
|
|
9
|
+
path: string | null;
|
|
10
|
+
/** Custom config file path */
|
|
11
|
+
configPath: string | null;
|
|
12
|
+
/** Show help */
|
|
13
|
+
showHelp: boolean;
|
|
14
|
+
/** Show version */
|
|
15
|
+
showVersion: boolean;
|
|
16
|
+
/** Show merged config (debug) */
|
|
17
|
+
showConfig: boolean;
|
|
18
|
+
/** Validate config file */
|
|
19
|
+
validate: boolean;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Parses command line arguments
|
|
23
|
+
*/
|
|
24
|
+
export declare function parseArgs(args: string[], onError: (message: string) => never): CliArgs;
|
|
25
|
+
//# sourceMappingURL=cli-args.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-args.d.ts","sourceRoot":"","sources":["../src/cli-args.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAE3C;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB,sCAAsC;IACtC,SAAS,EAAE,SAAS,GAAG,IAAI,CAAA;IAC3B,yBAAyB;IACzB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,8BAA8B;IAC9B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,gBAAgB;IAChB,QAAQ,EAAE,OAAO,CAAA;IACjB,mBAAmB;IACnB,WAAW,EAAE,OAAO,CAAA;IACpB,iCAAiC;IACjC,UAAU,EAAE,OAAO,CAAA;IACnB,2BAA2B;IAC3B,QAAQ,EAAE,OAAO,CAAA;CAClB;AAED;;GAEG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,KAAK,GAClC,OAAO,CAqFT"}
|
package/dist/cli-args.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parses command line arguments
|
|
3
|
+
*/
|
|
4
|
+
export function parseArgs(args, onError) {
|
|
5
|
+
const result = {
|
|
6
|
+
operation: null,
|
|
7
|
+
path: null,
|
|
8
|
+
configPath: null,
|
|
9
|
+
showHelp: false,
|
|
10
|
+
showVersion: false,
|
|
11
|
+
showConfig: false,
|
|
12
|
+
validate: false,
|
|
13
|
+
};
|
|
14
|
+
let i = 0;
|
|
15
|
+
while (i < args.length) {
|
|
16
|
+
const arg = args[i];
|
|
17
|
+
if (arg === '--help' || arg === '-h') {
|
|
18
|
+
result.showHelp = true;
|
|
19
|
+
i++;
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
if (arg === '--version' || arg === '-v') {
|
|
23
|
+
result.showVersion = true;
|
|
24
|
+
i++;
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
if (arg === '--show-config') {
|
|
28
|
+
result.showConfig = true;
|
|
29
|
+
i++;
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
if (arg === '--validate') {
|
|
33
|
+
result.validate = true;
|
|
34
|
+
i++;
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
if (arg === '--op') {
|
|
38
|
+
const value = args[i + 1];
|
|
39
|
+
if (!value || value.startsWith('-')) {
|
|
40
|
+
onError('--op requires a value (read or write)');
|
|
41
|
+
}
|
|
42
|
+
if (value !== 'read' && value !== 'write') {
|
|
43
|
+
onError(`Invalid operation: ${value}. Must be 'read' or 'write'`);
|
|
44
|
+
}
|
|
45
|
+
result.operation = value;
|
|
46
|
+
i += 2;
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if (arg === '--path') {
|
|
50
|
+
const value = args[i + 1];
|
|
51
|
+
if (!value || value.startsWith('-')) {
|
|
52
|
+
onError('--path requires a value');
|
|
53
|
+
}
|
|
54
|
+
result.path = value;
|
|
55
|
+
i += 2;
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
if (arg === '--config') {
|
|
59
|
+
const value = args[i + 1];
|
|
60
|
+
if (!value || value.startsWith('-')) {
|
|
61
|
+
onError('--config requires a value');
|
|
62
|
+
}
|
|
63
|
+
result.configPath = value;
|
|
64
|
+
i += 2;
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
// Unknown argument
|
|
68
|
+
if (arg.startsWith('-')) {
|
|
69
|
+
onError(`Unknown option: ${arg}`);
|
|
70
|
+
}
|
|
71
|
+
// Positional argument (treat as path if not set)
|
|
72
|
+
if (result.path === null) {
|
|
73
|
+
result.path = arg;
|
|
74
|
+
}
|
|
75
|
+
i++;
|
|
76
|
+
}
|
|
77
|
+
return result;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=cli-args.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-args.js","sourceRoot":"","sources":["../src/cli-args.ts"],"names":[],"mappings":"AAsBA;;GAEG;AACH,MAAM,UAAU,SAAS,CACvB,IAAc,EACd,OAAmC;IAEnC,MAAM,MAAM,GAAY;QACtB,SAAS,EAAE,IAAI;QACf,IAAI,EAAE,IAAI;QACV,UAAU,EAAE,IAAI;QAChB,QAAQ,EAAE,KAAK;QACf,WAAW,EAAE,KAAK;QAClB,UAAU,EAAE,KAAK;QACjB,QAAQ,EAAE,KAAK;KAChB,CAAA;IAED,IAAI,CAAC,GAAG,CAAC,CAAA;IACT,OAAO,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QACvB,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;QAEnB,IAAI,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YACrC,MAAM,CAAC,QAAQ,GAAG,IAAI,CAAA;YACtB,CAAC,EAAE,CAAA;YACH,SAAQ;QACV,CAAC;QAED,IAAI,GAAG,KAAK,WAAW,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YACxC,MAAM,CAAC,WAAW,GAAG,IAAI,CAAA;YACzB,CAAC,EAAE,CAAA;YACH,SAAQ;QACV,CAAC;QAED,IAAI,GAAG,KAAK,eAAe,EAAE,CAAC;YAC5B,MAAM,CAAC,UAAU,GAAG,IAAI,CAAA;YACxB,CAAC,EAAE,CAAA;YACH,SAAQ;QACV,CAAC;QAED,IAAI,GAAG,KAAK,YAAY,EAAE,CAAC;YACzB,MAAM,CAAC,QAAQ,GAAG,IAAI,CAAA;YACtB,CAAC,EAAE,CAAA;YACH,SAAQ;QACV,CAAC;QAED,IAAI,GAAG,KAAK,MAAM,EAAE,CAAC;YACnB,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;YACzB,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;gBACpC,OAAO,CAAC,uCAAuC,CAAC,CAAA;YAClD,CAAC;YACD,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,OAAO,EAAE,CAAC;gBAC1C,OAAO,CAAC,sBAAsB,KAAK,6BAA6B,CAAC,CAAA;YACnE,CAAC;YACD,MAAM,CAAC,SAAS,GAAG,KAAkB,CAAA;YACrC,CAAC,IAAI,CAAC,CAAA;YACN,SAAQ;QACV,CAAC;QAED,IAAI,GAAG,KAAK,QAAQ,EAAE,CAAC;YACrB,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;YACzB,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;gBACpC,OAAO,CAAC,yBAAyB,CAAC,CAAA;YACpC,CAAC;YACD,MAAM,CAAC,IAAI,GAAG,KAAK,CAAA;YACnB,CAAC,IAAI,CAAC,CAAA;YACN,SAAQ;QACV,CAAC;QAED,IAAI,GAAG,KAAK,UAAU,EAAE,CAAC;YACvB,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;YACzB,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;gBACpC,OAAO,CAAC,2BAA2B,CAAC,CAAA;YACtC,CAAC;YACD,MAAM,CAAC,UAAU,GAAG,KAAK,CAAA;YACzB,CAAC,IAAI,CAAC,CAAA;YACN,SAAQ;QACV,CAAC;QAED,mBAAmB;QACnB,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACxB,OAAO,CAAC,mBAAmB,GAAG,EAAE,CAAC,CAAA;QACnC,CAAC;QAED,iDAAiD;QACjD,IAAI,MAAM,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;YACzB,MAAM,CAAC,IAAI,GAAG,GAAG,CAAA;QACnB,CAAC;QACD,CAAC,EAAE,CAAA;IACL,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare const HELP_TEXT = "ai-fs-permissions - File system permissions for AI agents\n\nUSAGE\n ai-fs-permissions [options] [path]\n\nOPTIONS\n --op <type> Operation to check: read, write (required unless using stdin)\n --path <path> File path to check (can also be positional argument)\n --config <path> Use specific config file (skip discovery)\n --show-config Show merged configuration and exit\n --validate Validate config file and exit\n --help, -h Show this help message\n --version, -v Show version\n\nINPUT METHODS\n 1. Command line: ai-fs-permissions --op write --path \".centy/config.json\"\n 2. Stdin (JSON): echo '{\"tool_input\":{\"file_path\":\".centy/x\"}}' | ai-fs-permissions --op write\n 3. Stdin (plain): echo \".centy/config.json\" | ai-fs-permissions --op write\n\nCONFIG FILE (.ai-fs-permissions.yaml)\n version: 1\n rules:\n - path: \".centy/**\"\n access: read\n reason: \"Configuration folder\"\n - path: \"**/.env*\"\n access: none\n reason: \"Environment secrets\"\n\nACCESS LEVELS\n none Block all access (read and write)\n read Allow read, block write\n write Allow write, block read\n readwrite Allow both read and write\n\nEXIT CODES\n 0 Operation allowed\n 2 Operation blocked\n 1 Error (invalid config, missing arguments, etc.)\n\nEXAMPLES\n # Check if writing to .centy is allowed\n ai-fs-permissions --op write --path \".centy/settings.json\"\n\n # Use with Claude Code hooks (stdin JSON)\n echo '{\"tool_input\":{\"file_path\":\"src/index.ts\"}}' | ai-fs-permissions --op write\n\n # Show merged config for debugging\n ai-fs-permissions --show-config\n\n # Validate config file\n ai-fs-permissions --validate\n";
|
|
2
|
+
//# sourceMappingURL=cli-help.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-help.d.ts","sourceRoot":"","sources":["../src/cli-help.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,SAAS,quDAoDrB,CAAA"}
|
package/dist/cli-help.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export const HELP_TEXT = `ai-fs-permissions - File system permissions for AI agents
|
|
2
|
+
|
|
3
|
+
USAGE
|
|
4
|
+
ai-fs-permissions [options] [path]
|
|
5
|
+
|
|
6
|
+
OPTIONS
|
|
7
|
+
--op <type> Operation to check: read, write (required unless using stdin)
|
|
8
|
+
--path <path> File path to check (can also be positional argument)
|
|
9
|
+
--config <path> Use specific config file (skip discovery)
|
|
10
|
+
--show-config Show merged configuration and exit
|
|
11
|
+
--validate Validate config file and exit
|
|
12
|
+
--help, -h Show this help message
|
|
13
|
+
--version, -v Show version
|
|
14
|
+
|
|
15
|
+
INPUT METHODS
|
|
16
|
+
1. Command line: ai-fs-permissions --op write --path ".centy/config.json"
|
|
17
|
+
2. Stdin (JSON): echo '{"tool_input":{"file_path":".centy/x"}}' | ai-fs-permissions --op write
|
|
18
|
+
3. Stdin (plain): echo ".centy/config.json" | ai-fs-permissions --op write
|
|
19
|
+
|
|
20
|
+
CONFIG FILE (.ai-fs-permissions.yaml)
|
|
21
|
+
version: 1
|
|
22
|
+
rules:
|
|
23
|
+
- path: ".centy/**"
|
|
24
|
+
access: read
|
|
25
|
+
reason: "Configuration folder"
|
|
26
|
+
- path: "**/.env*"
|
|
27
|
+
access: none
|
|
28
|
+
reason: "Environment secrets"
|
|
29
|
+
|
|
30
|
+
ACCESS LEVELS
|
|
31
|
+
none Block all access (read and write)
|
|
32
|
+
read Allow read, block write
|
|
33
|
+
write Allow write, block read
|
|
34
|
+
readwrite Allow both read and write
|
|
35
|
+
|
|
36
|
+
EXIT CODES
|
|
37
|
+
0 Operation allowed
|
|
38
|
+
2 Operation blocked
|
|
39
|
+
1 Error (invalid config, missing arguments, etc.)
|
|
40
|
+
|
|
41
|
+
EXAMPLES
|
|
42
|
+
# Check if writing to .centy is allowed
|
|
43
|
+
ai-fs-permissions --op write --path ".centy/settings.json"
|
|
44
|
+
|
|
45
|
+
# Use with Claude Code hooks (stdin JSON)
|
|
46
|
+
echo '{"tool_input":{"file_path":"src/index.ts"}}' | ai-fs-permissions --op write
|
|
47
|
+
|
|
48
|
+
# Show merged config for debugging
|
|
49
|
+
ai-fs-permissions --show-config
|
|
50
|
+
|
|
51
|
+
# Validate config file
|
|
52
|
+
ai-fs-permissions --validate
|
|
53
|
+
`;
|
|
54
|
+
//# sourceMappingURL=cli-help.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-help.js","sourceRoot":"","sources":["../src/cli-help.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,SAAS,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoDxB,CAAA"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;GAKG"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* ai-fs-permissions CLI
|
|
4
|
+
*
|
|
5
|
+
* A platform-agnostic tool to enforce file system permissions for AI agents.
|
|
6
|
+
* Works with Claude Code, Gemini CLI, Cursor, and other AI coding tools.
|
|
7
|
+
*/
|
|
8
|
+
import { parseArgs } from './cli-args.js';
|
|
9
|
+
import { HELP_TEXT } from './cli-help.js';
|
|
10
|
+
import { loadConfig } from './config/loader.js';
|
|
11
|
+
import { checkPermission } from './checker.js';
|
|
12
|
+
import { outputResult } from './output.js';
|
|
13
|
+
import { parseStdin, readStdin } from './stdin.js';
|
|
14
|
+
import { EXIT_CODES } from './exit-codes.js';
|
|
15
|
+
const VERSION = '0.1.0';
|
|
16
|
+
function handleError(message) {
|
|
17
|
+
console.error(`Error: ${message}`);
|
|
18
|
+
console.error('Use --help for usage information');
|
|
19
|
+
process.exit(EXIT_CODES.ERROR);
|
|
20
|
+
}
|
|
21
|
+
async function main() {
|
|
22
|
+
try {
|
|
23
|
+
const args = parseArgs(process.argv.slice(2), handleError);
|
|
24
|
+
if (args.showHelp) {
|
|
25
|
+
console.log(HELP_TEXT);
|
|
26
|
+
process.exit(EXIT_CODES.ALLOWED);
|
|
27
|
+
}
|
|
28
|
+
if (args.showVersion) {
|
|
29
|
+
console.log(VERSION);
|
|
30
|
+
process.exit(EXIT_CODES.ALLOWED);
|
|
31
|
+
}
|
|
32
|
+
const cwd = process.cwd();
|
|
33
|
+
const config = loadConfig(cwd, args.configPath ?? undefined);
|
|
34
|
+
if (args.showConfig) {
|
|
35
|
+
console.log(JSON.stringify(config, null, 2));
|
|
36
|
+
process.exit(EXIT_CODES.ALLOWED);
|
|
37
|
+
}
|
|
38
|
+
if (args.validate) {
|
|
39
|
+
if (config.rules.length === 0) {
|
|
40
|
+
console.log('No config file found or config has no rules');
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
console.log(`Config valid: ${config.rules.length} rule(s) loaded`);
|
|
44
|
+
}
|
|
45
|
+
process.exit(EXIT_CODES.ALLOWED);
|
|
46
|
+
}
|
|
47
|
+
// Get path and operation from args or stdin
|
|
48
|
+
let filePath = args.path;
|
|
49
|
+
let operation = args.operation;
|
|
50
|
+
// If no path from args, try stdin
|
|
51
|
+
if (filePath === null) {
|
|
52
|
+
const stdinInput = await readStdin();
|
|
53
|
+
if (stdinInput.trim()) {
|
|
54
|
+
const parsed = parseStdin(stdinInput);
|
|
55
|
+
filePath = parsed.path;
|
|
56
|
+
// Infer operation from tool if not provided
|
|
57
|
+
if (operation === null && parsed.inferredOperation) {
|
|
58
|
+
operation = parsed.inferredOperation;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// Validate required arguments
|
|
63
|
+
if (filePath === null || filePath.trim() === '') {
|
|
64
|
+
// No path provided and no stdin - this is OK, just allow
|
|
65
|
+
// This handles cases where hooks are called but no file is involved
|
|
66
|
+
process.exit(EXIT_CODES.ALLOWED);
|
|
67
|
+
}
|
|
68
|
+
if (operation === null) {
|
|
69
|
+
handleError('Operation required. Use --op read or --op write');
|
|
70
|
+
}
|
|
71
|
+
// Check permission
|
|
72
|
+
const result = checkPermission(config, filePath, operation);
|
|
73
|
+
outputResult(result);
|
|
74
|
+
process.exit(result.allowed ? EXIT_CODES.ALLOWED : EXIT_CODES.BLOCKED);
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
78
|
+
console.error('Error:', message);
|
|
79
|
+
process.exit(EXIT_CODES.ERROR);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
main();
|
|
83
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAG5C,MAAM,OAAO,GAAG,OAAO,CAAA;AAEvB,SAAS,WAAW,CAAC,OAAe;IAClC,OAAO,CAAC,KAAK,CAAC,UAAU,OAAO,EAAE,CAAC,CAAA;IAClC,OAAO,CAAC,KAAK,CAAC,kCAAkC,CAAC,CAAA;IACjD,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAA;AAChC,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,CAAA;QAE1D,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;YACtB,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAA;QAClC,CAAC;QAED,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;YACpB,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAA;QAClC,CAAC;QAED,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAA;QACzB,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,UAAU,IAAI,SAAS,CAAC,CAAA;QAE5D,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACpB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA;YAC5C,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAA;QAClC,CAAC;QAED,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC9B,OAAO,CAAC,GAAG,CAAC,6CAA6C,CAAC,CAAA;YAC5D,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,GAAG,CAAC,iBAAiB,MAAM,CAAC,KAAK,CAAC,MAAM,iBAAiB,CAAC,CAAA;YACpE,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAA;QAClC,CAAC;QAED,4CAA4C;QAC5C,IAAI,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAA;QACxB,IAAI,SAAS,GAAqB,IAAI,CAAC,SAAS,CAAA;QAEhD,kCAAkC;QAClC,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;YACtB,MAAM,UAAU,GAAG,MAAM,SAAS,EAAE,CAAA;YACpC,IAAI,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC;gBACtB,MAAM,MAAM,GAAG,UAAU,CAAC,UAAU,CAAC,CAAA;gBACrC,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAA;gBAEtB,4CAA4C;gBAC5C,IAAI,SAAS,KAAK,IAAI,IAAI,MAAM,CAAC,iBAAiB,EAAE,CAAC;oBACnD,SAAS,GAAG,MAAM,CAAC,iBAAiB,CAAA;gBACtC,CAAC;YACH,CAAC;QACH,CAAC;QAED,8BAA8B;QAC9B,IAAI,QAAQ,KAAK,IAAI,IAAI,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YAChD,yDAAyD;YACzD,oEAAoE;YACpE,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAA;QAClC,CAAC;QAED,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;YACvB,WAAW,CAAC,iDAAiD,CAAC,CAAA;QAChE,CAAC;QAED,mBAAmB;QACnB,MAAM,MAAM,GAAG,eAAe,CAAC,MAAM,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAA;QAC3D,YAAY,CAAC,MAAM,CAAC,CAAA;QAEpB,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAA;IACxE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QACtE,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;QAChC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAA;IAChC,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAA"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Config } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Loads a config file from a path
|
|
4
|
+
*/
|
|
5
|
+
export declare function loadConfigFile(filePath: string): Config | null;
|
|
6
|
+
/**
|
|
7
|
+
* Finds config file by walking up the directory tree (gitignore-style)
|
|
8
|
+
*/
|
|
9
|
+
export declare function findConfigFile(startDir: string): string | null;
|
|
10
|
+
/**
|
|
11
|
+
* Gets the user config file path
|
|
12
|
+
*/
|
|
13
|
+
export declare function getUserConfigPath(): string | null;
|
|
14
|
+
/**
|
|
15
|
+
* Merges multiple configs (later configs override earlier ones)
|
|
16
|
+
*/
|
|
17
|
+
export declare function mergeConfigs(...configs: (Config | null)[]): Config;
|
|
18
|
+
/**
|
|
19
|
+
* Loads and merges all applicable configs
|
|
20
|
+
*/
|
|
21
|
+
export declare function loadConfig(cwd: string, explicitPath?: string): Config;
|
|
22
|
+
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAqB,MAAM,aAAa,CAAA;AAuC5D;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAuB9D;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAe9D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,GAAG,IAAI,CAejD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,GAAG,OAAO,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,GAAG,MAAM,CAgBlE;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAwBrE"}
|