pi-landstrip 0.18.33 → 0.18.35
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 +42 -163
- package/api.ts +2 -4
- package/dist/index.ts +384 -421
- package/package.json +2 -2
- package/LICENSE +0 -201
package/README.md
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
# pi-landstrip
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
later.
|
|
3
|
+
Pi extension for sandboxed Bash, primary agents, and process-backed subagents.
|
|
4
|
+
Pi 0.82.0 and Node.js 22.19.0 or newer are required.
|
|
6
5
|
|
|
7
6
|
## Install
|
|
8
7
|
|
|
@@ -10,189 +9,69 @@ later.
|
|
|
10
9
|
pi install npm:pi-landstrip
|
|
11
10
|
```
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
```json
|
|
17
|
-
{
|
|
18
|
-
"packages": ["npm:pi-landstrip"]
|
|
19
|
-
}
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
The package includes Landstrip binaries for Linux, macOS, and Windows on x64 and
|
|
23
|
-
Arm64. If sandboxing is enabled but the binary or platform is unusable, Bash,
|
|
24
|
-
shell commands, and sandboxed workers fail closed. Only `--no-sandbox` or
|
|
25
|
-
`"enabled": false` permits execution without OS isolation.
|
|
12
|
+
The package includes Landstrip binaries for Linux, macOS, and Windows on x64
|
|
13
|
+
and Arm64. When sandboxing is enabled, an unusable binary or platform fails
|
|
14
|
+
closed. Use `--no-sandbox` or set `enabled` to `false` for unsandboxed execution.
|
|
26
15
|
|
|
27
16
|
## Permissions
|
|
28
17
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
| Category | Checked | Controls |
|
|
32
|
-
| -------- | --------------------------------------- | -------------------------------- |
|
|
33
|
-
| Agent | Before dispatch | Whether an agent may call a tool |
|
|
34
|
-
| Sandbox | Before file access and during processes | Filesystem and network resources |
|
|
35
|
-
|
|
36
|
-
Agent rules return `deny`, `ask`, or `allow`. An agent approval authorizes only
|
|
37
|
-
tool dispatch and cannot bypass a sandbox hard denial.
|
|
38
|
-
|
|
39
|
-
By default, primary `read`, `write`, `edit`, and `apply_patch` tools run in the
|
|
40
|
-
trusted Pi process and only agent permissions apply. Set
|
|
41
|
-
`toolFilesystemPolicy` to `"sandbox"` to preflight their paths against
|
|
42
|
-
`sandbox.json`. `denyWrite` remains a hard denial. If both agent and sandbox
|
|
43
|
-
approval are needed, Pi presents one prompt for the call.
|
|
44
|
-
|
|
45
|
-
AI Bash, `!`, `!!`, and subagent processes use OS isolation. Subagents rely on
|
|
46
|
-
that isolation instead of repeating file-tool preflight. Pi presents all agent
|
|
47
|
-
and sandbox requests through one FIFO prompt queue.
|
|
48
|
-
|
|
49
|
-
Sandbox approvals may apply once, for the session, to the project, or globally.
|
|
50
|
-
Persistent approvals update `.pi/sandbox.json` or
|
|
51
|
-
`~/.pi/agent/sandbox.json`. Headless requests that require approval are denied.
|
|
52
|
-
|
|
53
|
-
## Sandbox configuration
|
|
18
|
+
Agent permissions control tool dispatch. Sandbox permissions control filesystem
|
|
19
|
+
and network access. Agent approval never bypasses a sandbox hard denial.
|
|
54
20
|
|
|
55
|
-
|
|
21
|
+
AI Bash, `!`, `!!`, and subagents use OS isolation. Primary file tools use the
|
|
22
|
+
trusted Pi process unless `toolFilesystemPolicy` is `"sandbox"`. Persistent
|
|
23
|
+
sandbox approvals update `.pi/sandbox.json` or `~/.pi/agent/sandbox.json`.
|
|
56
24
|
|
|
57
|
-
|
|
58
|
-
2. `~/.pi/agent/sandbox.json`;
|
|
59
|
-
3. `.pi/sandbox.json` for a trusted project.
|
|
25
|
+
## Sandbox settings
|
|
60
26
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
27
|
+
Policy merges from bundled `sandbox.json`, global
|
|
28
|
+
`~/.pi/agent/sandbox.json`, then trusted-project `.pi/sandbox.json`.
|
|
29
|
+
`/settings` displays or toggles the effective policy.
|
|
64
30
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
| `network.allowUnixSockets` | `[]` |
|
|
77
|
-
| `network.allowedDomains` | `[]` |
|
|
78
|
-
| `network.deniedDomains` | `[]` |
|
|
79
|
-
| `windows.appContainerMode` | `"standard"` |
|
|
80
|
-
| `windows.allowLoopback` | `false` |
|
|
81
|
-
|
|
82
|
-
Filesystem and core network semantics follow the main
|
|
83
|
-
[Landstrip policy](https://github.com/landstrip/landstrip#policy). `allowedDomains`
|
|
84
|
-
and `deniedDomains` are plugin fields enforced by the local HTTP/HTTPS proxy.
|
|
85
|
-
|
|
86
|
-
`shell.readAccess: "host"` gives primary Bash and `!`/`!!` the trusted host read
|
|
87
|
-
view on Linux and macOS while retaining sandboxed writes. `"policy"` applies
|
|
88
|
-
`denyRead` and `allowRead`. Workers always use policy reads. Windows always uses
|
|
89
|
-
policy reads because it requires an explicit read allowlist.
|
|
90
|
-
|
|
91
|
-
With `enabled: false`, subagents remain separate processes but lose Landstrip OS
|
|
92
|
-
isolation; Pi warns once per session.
|
|
93
|
-
|
|
94
|
-
## Agent configuration
|
|
31
|
+
```json
|
|
32
|
+
{
|
|
33
|
+
"enabled": true,
|
|
34
|
+
"shell": { "readAccess": "host" },
|
|
35
|
+
"filesystem": {
|
|
36
|
+
"allowWrite": ["."],
|
|
37
|
+
"denyWrite": ["**/.env", "**/*.pem"]
|
|
38
|
+
},
|
|
39
|
+
"network": { "allowNetwork": false }
|
|
40
|
+
}
|
|
41
|
+
```
|
|
95
42
|
|
|
96
|
-
|
|
97
|
-
|
|
43
|
+
See [`sandbox.json`](sandbox.json) for exact defaults. Workers always use policy
|
|
44
|
+
reads. Windows requires an explicit read allowlist.
|
|
98
45
|
|
|
99
|
-
|
|
100
|
-
- `.pi/landstrip.json`
|
|
46
|
+
## Agents
|
|
101
47
|
|
|
102
|
-
|
|
103
|
-
|
|
48
|
+
Configure agents in `~/.pi/agent/landstrip.json`, `.pi/landstrip.json`, or a
|
|
49
|
+
`landstrip` object in the matching Pi settings file:
|
|
104
50
|
|
|
105
51
|
```json
|
|
106
52
|
{
|
|
107
53
|
"maxSubagents": 2,
|
|
108
54
|
"toolFilesystemPolicy": "sandbox",
|
|
109
|
-
"agent": {
|
|
110
|
-
"review": {
|
|
111
|
-
"description": "Review without modifying files",
|
|
112
|
-
"mode": "subagent",
|
|
113
|
-
"prompt": "Report concrete findings.",
|
|
114
|
-
"permission": {
|
|
115
|
-
"edit": "deny",
|
|
116
|
-
"bash": "ask"
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
},
|
|
120
55
|
"permission": {
|
|
121
|
-
"task": {
|
|
122
|
-
"*": "deny",
|
|
123
|
-
"review": "allow"
|
|
124
|
-
}
|
|
56
|
+
"task": { "*": "deny", "review": "allow" }
|
|
125
57
|
}
|
|
126
58
|
}
|
|
127
59
|
```
|
|
128
60
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
| `toolFilesystemPolicy` | `"host"` | `"host"` or `"sandbox"` |
|
|
133
|
-
| `agent` | built-in agents | named agent definitions |
|
|
134
|
-
| `permission` | built-in rules | global tool/resource rules |
|
|
135
|
-
|
|
136
|
-
Agent definitions accept `name`, `description`, `prompt`, `mode`, `model`,
|
|
137
|
-
`variant`, `temperature`, `top_p`, `steps`, `color`, `hidden`, `disable`,
|
|
138
|
-
`options`, and `permission`. `mode` is `primary`, `subagent`, or `all` and
|
|
139
|
-
defaults to `all`. `/agents` Primary lists only `mode: primary` agents. The
|
|
140
|
-
Subagent tab lists `mode: subagent` and `mode: all` agents, including JSON and
|
|
141
|
-
Markdown definitions.
|
|
142
|
-
|
|
143
|
-
The built-in primary agents are `build` and `plan`; built-in subagents are
|
|
144
|
-
`general`, `scout`, and `explore`. Pi also loads Markdown agents from
|
|
145
|
-
`~/.pi/agent/agents/` and `.pi/agents/`. Project definitions overlay global
|
|
146
|
-
definitions. Configured fields overlay Markdown agents with the same name, so a
|
|
147
|
-
model-only `landstrip.json` entry keeps the Markdown agent's mode, prompt, and
|
|
148
|
-
permissions.
|
|
61
|
+
`maxSubagents` accepts 0 through 16. Agent definitions can override model,
|
|
62
|
+
prompt, mode, options, and permissions. Global definitions load before trusted
|
|
63
|
+
project definitions.
|
|
149
64
|
|
|
150
65
|
## Commands and tasks
|
|
151
66
|
|
|
152
|
-
- `/
|
|
153
|
-
- `/
|
|
154
|
-
- `
|
|
155
|
-
|
|
156
|
-
The `task` tool requires `description`, `prompt`, and `subagent_type`. Optional
|
|
157
|
-
`task_id` continues a saved task, `command` records the originating command, and
|
|
158
|
-
`background: true` returns immediately. `/agents <task-id>` inspects a task.
|
|
159
|
-
Each invocation starts a fresh Pi RPC process; continuation restores its saved
|
|
160
|
-
session in a new process.
|
|
161
|
-
|
|
162
|
-
Workers use normal Pi resource and plugin discovery. Their model requests can
|
|
163
|
-
read Pi authentication and inherited credential environment variables. Install
|
|
164
|
-
only trusted worker plugins and use credentials appropriate for the sandboxed
|
|
165
|
-
task.
|
|
166
|
-
|
|
167
|
-
## Permission ask providers
|
|
168
|
-
|
|
169
|
-
A separate Pi extension can resolve agent permission rules that return `ask` by
|
|
170
|
-
registering one `LandstripPermissionAskProvider`:
|
|
171
|
-
|
|
172
|
-
```ts
|
|
173
|
-
import type { ExtensionAPI } from '@earendil-works/pi-coding-agent';
|
|
174
|
-
import { provideLandstripPermissionAsk } from 'pi-landstrip/api';
|
|
175
|
-
|
|
176
|
-
export default function permissionReviewer(pi: ExtensionAPI): void {
|
|
177
|
-
provideLandstripPermissionAsk(pi, {
|
|
178
|
-
id: 'example-reviewer',
|
|
179
|
-
async decide(request) {
|
|
180
|
-
if (request.toolName === 'bash' && request.input.command === 'git status') {
|
|
181
|
-
return { decision: 'allow' };
|
|
182
|
-
}
|
|
183
|
-
return { decision: 'abstain' };
|
|
184
|
-
},
|
|
185
|
-
});
|
|
186
|
-
}
|
|
187
|
-
```
|
|
67
|
+
- `/settings` opens a screen-wide pane with sandbox and agent settings.
|
|
68
|
+
- `/sandbox` opens the same pane on its sandbox section.
|
|
69
|
+
- `/agents` selects agents and lists task sessions.
|
|
70
|
+
- `Ctrl+Shift+A` cycles primary agents while Pi is idle.
|
|
188
71
|
|
|
189
|
-
The
|
|
190
|
-
|
|
191
|
-
`deny` blocks it, and `abstain` uses the normal UI prompt or headless denial.
|
|
192
|
-
Provider errors also fall back safely. Only one provider may be registered at a
|
|
193
|
-
time; the helper works regardless of extension load order and returns a disposer.
|
|
72
|
+
The `task` tool starts isolated workers. Set `background: true` to return
|
|
73
|
+
immediately and use `task_id` to continue a saved task.
|
|
194
74
|
|
|
195
|
-
##
|
|
75
|
+
## Licensing
|
|
196
76
|
|
|
197
|
-
|
|
198
|
-
licensed separately as `Apache-2.0 AND LGPL-2.1-or-later`.
|
|
77
|
+
[Apache 2.0](../../LICENSE-APACHE-2.0).
|
package/api.ts
CHANGED
|
@@ -6,6 +6,8 @@ import type { Readable, Writable } from 'node:stream';
|
|
|
6
6
|
|
|
7
7
|
import type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';
|
|
8
8
|
|
|
9
|
+
import { isRecord } from '@landstrip/landstrip/shared';
|
|
10
|
+
|
|
9
11
|
export const LANDSTRIP_CONTEXT_ENV = 'LANDSTRIP_CONTEXT';
|
|
10
12
|
export const LANDSTRIP_RUNTIME_VERSION = 2;
|
|
11
13
|
|
|
@@ -168,10 +170,6 @@ function eventBus(pi: ExtensionAPI): EventBusLike | undefined {
|
|
|
168
170
|
return (pi as ExtensionAPI & { events?: EventBusLike }).events;
|
|
169
171
|
}
|
|
170
172
|
|
|
171
|
-
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
172
|
-
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
173
|
function isRuntime(value: unknown): value is PiLandstripRuntimeV2 {
|
|
176
174
|
return (
|
|
177
175
|
isRecord(value) &&
|