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.
Files changed (5) hide show
  1. package/README.md +42 -163
  2. package/api.ts +2 -4
  3. package/dist/index.ts +384 -421
  4. package/package.json +2 -2
  5. package/LICENSE +0 -201
package/README.md CHANGED
@@ -1,8 +1,7 @@
1
1
  # pi-landstrip
2
2
 
3
- `pi-landstrip` adds sandboxed Bash, primary agents, and process-backed subagents
4
- to [Pi](https://pi.dev/). It requires Pi 0.82.0 or later and Node.js 22.19.0 or
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
- For a manual global or trusted-project install, add the package to Pi's
14
- `settings.json`:
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
- Pi evaluates two permission categories:
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
- Sandbox policy merges in this order:
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
- 1. bundled [`sandbox.json`](./sandbox.json);
58
- 2. `~/.pi/agent/sandbox.json`;
59
- 3. `.pi/sandbox.json` for a trusted project.
25
+ ## Sandbox settings
60
26
 
61
- Objects merge recursively, arrays combine, and later scalar values replace
62
- earlier values. `/sandbox` displays or toggles the policy. It writes the project
63
- policy in a trusted project and the global policy otherwise.
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
- | Field | Bundled default |
66
- | ----------------------------- | -------------------------------------------------------------------------------------------------- |
67
- | `enabled` | `true` |
68
- | `shell.readAccess` | `"host"` |
69
- | `filesystem.denyRead` | `["/Users", "/home"]` |
70
- | `filesystem.allowRead` | `[".", "~/.gitconfig", "~/.config/git/config", "/dev/null"]` |
71
- | `filesystem.allowWrite` | `[".", "/dev/null"]` |
72
- | `filesystem.denyWrite` | `["**/.env", "**/.env.*", "**/*.pem", "**/*.key", ".pi/sandbox.json", "~/.pi/agent/sandbox.json"]` |
73
- | `network.allowNetwork` | `false` |
74
- | `network.allowLocalBinding` | `false` |
75
- | `network.allowAllUnixSockets` | `false` |
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
- Agent configuration merges built-ins, global configuration, then trusted-project
97
- configuration. Use either dedicated files:
43
+ See [`sandbox.json`](sandbox.json) for exact defaults. Workers always use policy
44
+ reads. Windows requires an explicit read allowlist.
98
45
 
99
- - `~/.pi/agent/landstrip.json`
100
- - `.pi/landstrip.json`
46
+ ## Agents
101
47
 
102
- or a top-level `landstrip` object in the matching `settings.json`. Using both
103
- forms at one scope is an error.
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
- | Field | Default | Values |
130
- | ---------------------- | --------------- | -------------------------------------------- |
131
- | `maxSubagents` | `1` | integer from 0 through 16; 0 disables `task` |
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
- - `/sandbox` inspects and toggles sandboxing.
153
- - `/agents` selects or edits agents and lists task sessions.
154
- - `Ctrl+Shift+A` cycles visible primary agents while Pi is idle.
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 provider receives the tool name and input, pending permission/resource pairs,
190
- the primary or subagent context, and an abort signal. `allow` approves that call,
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
- ## License
75
+ ## Licensing
196
76
 
197
- `pi-landstrip` is licensed under `Apache-2.0`. The bundled Landstrip package is
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) &&