@iinm/plain-agent 1.11.0 → 1.11.2
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 +13 -11
- package/package.json +6 -4
- package/src/toolInputValidator.mjs +4 -5
package/README.md
CHANGED
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
# Plain Agent
|
|
2
2
|
|
|
3
3
|
[](https://deepwiki.com/iinm/plain-agent)
|
|
4
|
+
[](https://www.npmjs.com/package/@iinm/plain-agent)
|
|
5
|
+
[](https://packagephobia.com/result?p=@iinm/plain-agent)
|
|
6
|
+
[](https://socket.dev/npm/package/@iinm/plain-agent)
|
|
4
7
|
[](https://github.com/iinm/plain-agent/actions/workflows/github-code-scanning/codeql)
|
|
5
|
-
[](https://socket.dev/npm/package/@iinm/plain-agent)
|
|
6
8
|
|
|
7
9
|
A lightweight terminal-based coding agent focused on safety and low token cost
|
|
8
10
|
|
|
9
11
|
## Table of Contents
|
|
10
12
|
|
|
11
13
|
- [Design](#design)
|
|
12
|
-
- [Multi-
|
|
13
|
-
- [Auto-
|
|
14
|
+
- [Multi-Provider Support](#multi-provider-support)
|
|
15
|
+
- [Auto-Approval](#auto-approval)
|
|
14
16
|
- [Path Validation](#path-validation)
|
|
15
17
|
- [Sandbox](#sandbox)
|
|
16
|
-
- [Memory
|
|
18
|
+
- [Memory File](#memory-file)
|
|
17
19
|
- [Token Efficiency](#token-efficiency)
|
|
18
20
|
- [Claude Code Compatibility](#claude-code-compatibility)
|
|
19
21
|
- [Requirements](#requirements)
|
|
@@ -29,7 +31,7 @@ A lightweight terminal-based coding agent focused on safety and low token cost
|
|
|
29
31
|
|
|
30
32
|
## Design
|
|
31
33
|
|
|
32
|
-
### Multi-
|
|
34
|
+
### Multi-Provider Support
|
|
33
35
|
|
|
34
36
|
Supports Claude, OpenAI, Gemini, and any OpenAI-compatible provider. Bedrock, Vertex AI, and Azure are also supported for teams working in environments restricted to managed cloud providers.
|
|
35
37
|
|
|
@@ -84,10 +86,12 @@ Models are identified by `name+variant` (e.g., `claude-sonnet-4-6+thinking-high`
|
|
|
84
86
|
|
|
85
87
|
You can also add entries to `platforms` and `models` to use any OpenAI-compatible endpoint, such as Ollama or Fireworks. See the Quick Start section for examples.
|
|
86
88
|
|
|
87
|
-
### Auto-
|
|
89
|
+
### Auto-Approval
|
|
88
90
|
|
|
89
91
|
Configure what the agent can do automatically using a small DSL with regex matching. Below is an excerpt from the [default config](https://github.com/iinm/plain-agent/blob/main/config/config.predefined.json).
|
|
90
92
|
|
|
93
|
+
**Note**: Commands are executed without a shell — shell operators like `&&`, `|`, `;`, and redirects are not interpreted unless the agent explicitly uses `bash -c`. This makes each argument a discrete token that can be validated individually.
|
|
94
|
+
|
|
91
95
|
```js
|
|
92
96
|
{
|
|
93
97
|
"autoApproval": {
|
|
@@ -163,8 +167,6 @@ String values in tool inputs are treated as file paths and validated against the
|
|
|
163
167
|
- Symlinks are resolved to their real path before validation — a symlink inside the working directory that points outside is rejected. Broken and circular symlinks are also rejected.
|
|
164
168
|
- The file must be tracked by Git (not ignored)
|
|
165
169
|
|
|
166
|
-
Commands are executed without a shell — shell operators like `&&`, `|`, `;`, and redirects are not interpreted unless the agent explicitly uses `bash -c`. This makes each argument a discrete token that can be validated individually.
|
|
167
|
-
|
|
168
170
|
Compound arguments are decomposed before validation — embedded paths are extracted and checked individually:
|
|
169
171
|
|
|
170
172
|
| Pattern | Example | Extracted |
|
|
@@ -173,11 +175,11 @@ Compound arguments are decomposed before validation — embedded paths are extra
|
|
|
173
175
|
| `--opt=<val>` | `--prefix=/tmp/foo` | `/tmp/foo` |
|
|
174
176
|
| `-X<val>` | `-I/usr/include` | `/usr/include` |
|
|
175
177
|
| `VAR=<val>` | `OUTPUT=/etc/passwd` | `/etc/passwd` |
|
|
176
|
-
| `proto://…` | `file:///etc/passwd` | `/etc/passwd` |
|
|
178
|
+
| `proto://…` | `file:///etc/passwd` | `/etc/passwd` (only `file:` is treated as a local path; `http(s)://` URLs are always allowed) |
|
|
177
179
|
|
|
178
180
|
`--opt=<val>`, `-X<val>`, and `VAR=<val>` are checked recursively, so chained patterns like `-DINSTALL_DIR=/etc` decompose fully (`-D` → `INSTALL_DIR=/etc` → `/etc`).
|
|
179
181
|
|
|
180
|
-
**Note**:
|
|
182
|
+
**Note**: Validation only applies when the agent explicitly passes file paths to tools. It cannot catch file access inside scripts the agent writes — something like `bash -c "rm -rf /"` is beyond its reach. Always use a sandbox when auto-approving script execution.
|
|
181
183
|
|
|
182
184
|
### Sandbox
|
|
183
185
|
|
|
@@ -217,7 +219,7 @@ A Docker-based wrapper called `plain-sandbox` is included, but the interface is
|
|
|
217
219
|
}
|
|
218
220
|
```
|
|
219
221
|
|
|
220
|
-
### Memory
|
|
222
|
+
### Memory File
|
|
221
223
|
|
|
222
224
|
The agent maintains a memory file (`.plain-agent/memory/`) for each session to:
|
|
223
225
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iinm/plain-agent",
|
|
3
|
-
"version": "1.11.
|
|
3
|
+
"version": "1.11.2",
|
|
4
4
|
"description": "A lightweight terminal-based coding agent focused on safety and low token cost",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -32,9 +32,10 @@
|
|
|
32
32
|
"node": ">=22"
|
|
33
33
|
},
|
|
34
34
|
"scripts": {
|
|
35
|
-
"check": "npm run lint && tsc && npm run test && npm run test:predefined-approval",
|
|
36
|
-
"test": "node --test",
|
|
37
|
-
"
|
|
35
|
+
"check": "npm run lint && tsc && npm run test && npm run test:e2e && npm run test:predefined-approval",
|
|
36
|
+
"test": "node --test 'src/**/*.test.mjs'",
|
|
37
|
+
"test:e2e": "node --test --test-timeout=30000 'e2e/**/*.test.mjs'",
|
|
38
|
+
"coverage": "c8 --exclude='src/**/*.test.mjs' --exclude='e2e/**' node --test --test-force-exit 'src/**/*.test.mjs' 'e2e/**/*.test.mjs'",
|
|
38
39
|
"test:predefined-approval": "bash -c 'set -e; mkdir -p tmp; cd tmp; env HOME=. ../bin/plain test-approval'",
|
|
39
40
|
"lint": "npx @biomejs/biome check",
|
|
40
41
|
"fix": "npx @biomejs/biome check --fix",
|
|
@@ -44,6 +45,7 @@
|
|
|
44
45
|
"devDependencies": {
|
|
45
46
|
"@biomejs/biome": "^2.4.12",
|
|
46
47
|
"@types/node": "^22.19.17",
|
|
48
|
+
"c8": "^11.0.0",
|
|
47
49
|
"typescript": "^6.0.2"
|
|
48
50
|
}
|
|
49
51
|
}
|
|
@@ -108,19 +108,18 @@ export function isSafeToolInputItem(
|
|
|
108
108
|
);
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
//
|
|
112
|
-
const
|
|
113
|
-
if (
|
|
111
|
+
// file:// pattern — references the local filesystem
|
|
112
|
+
const fileMatch = arg.match(/^file:\/\/(.+)$/i);
|
|
113
|
+
if (fileMatch) {
|
|
114
114
|
return (
|
|
115
115
|
isSafeToolInputItemRaw(arg, allowedPaths, allowGitUnmanagedFiles) &&
|
|
116
116
|
isSafeToolInputItemRaw(
|
|
117
|
-
`/${
|
|
117
|
+
`/${fileMatch[1]}`,
|
|
118
118
|
allowedPaths,
|
|
119
119
|
allowGitUnmanagedFiles,
|
|
120
120
|
)
|
|
121
121
|
);
|
|
122
122
|
}
|
|
123
|
-
|
|
124
123
|
return isSafeToolInputItemRaw(arg, allowedPaths, allowGitUnmanagedFiles);
|
|
125
124
|
}
|
|
126
125
|
|