opencode-landstrip 0.19.12 → 0.19.14

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 CHANGED
@@ -9,37 +9,31 @@ opencode plugin install opencode-landstrip # project
9
9
  opencode plugin install opencode-landstrip --global # global
10
10
  ```
11
11
 
12
- Installation configures server and TUI plugins. `/landstrip` opens the management
13
- pane; Pi's agent/task subcommands are unavailable.
12
+ Installation configures server/TUI plugins; `/landstrip` opens the management pane.
14
13
 
15
14
  ## Permissions and configuration
16
15
 
17
- OpenCode authorizes tool dispatch; Landstrip enforces filesystem/network access.
18
- Approval never bypasses hard denials. Interactive requests without a live
19
- presenter remain denied. Only AI `bash` receives OS isolation: OpenCode's plugin
20
- API cannot replace direct user shell commands.
16
+ Only AI `bash` is OS-isolated; the plugin API cannot replace user shell commands.
17
+ Tool approval never overrides hard sandbox denials. Interactive requests without
18
+ a live presenter remain denied.
21
19
 
22
- Policy precedence: bundled [`sandbox.json`](sandbox.json) → global →
23
- `.opencode/sandbox.json` → plugin options. The global file is
24
- `$XDG_CONFIG_HOME/opencode/sandbox.json` (`~/.config` when unset, empty, or relative).
25
- Persistent approvals update the chosen project/global file.
20
+ Configuration: bundled [`sandbox.json`](sandbox.json) → global →
21
+ `.opencode/sandbox.json` → plugin options. Global:
22
+ `$XDG_CONFIG_HOME/opencode/sandbox.json`, with `~/.config` as fallback for an unset,
23
+ empty, or relative `XDG_CONFIG_HOME`. Arrays combine; later scalars win.
24
+ Persistent approvals update the selected global/project file.
26
25
 
27
- Arrays combine; later scalar values win. Defaults allow project writes, deny
28
- sensitive-file writes, and block network access. Enabled sandboxing fails closed
29
- on unusable binaries/platforms; `enabled: false` explicitly permits unsandboxed Bash.
26
+ Defaults allow project writes, deny sensitive-file writes, and block networking.
27
+ Unusable sandboxing fails closed; `enabled: false` permits unsandboxed Bash.
30
28
 
31
- `filesystem.denyReadAlways` and `filesystem.denyWriteAlways` block approvals and
32
- equal/nested grants. Non-empty hard-denial lists are unsupported on Windows.
33
-
34
- See [landstrip(1)](../landstrip/man/man1/landstrip.1) for native CLI/policy semantics.
35
- Runtime seccomp traps/query approval are Linux-only. Native macOS `--trap` reports
36
- setup/launch errors only and closes on successful exec—not runtime violations.
29
+ See [landstrip(1)](../landstrip/man/man1/landstrip.1) for hard-denial rules,
30
+ native traps, and platform limits.
37
31
 
38
32
  ## Development
39
33
 
40
- From this package: `npm ci`, then `npm run all` (format, lint, typecheck, tests).
41
- Read-only formatting check: `npm run ci:fmt`.
34
+ From this package: `npm ci && npm run all`; `npm run ci:fmt` checks formatting
35
+ without edits.
42
36
 
43
37
  ## License
44
38
 
45
- Apache-2.0; see [LICENSE](LICENSE).
39
+ [Apache-2.0](LICENSE).
package/index.ts CHANGED
@@ -21,7 +21,6 @@ import {
21
21
  allowsAllDomains,
22
22
  canonicalizePath,
23
23
  controlResponseLine,
24
- decodeLandstripTrap,
25
24
  evaluateDomainAccess,
26
25
  evaluateReadAccess,
27
26
  evaluateWriteAccess,
@@ -31,11 +30,13 @@ import {
31
30
  getConfigPaths,
32
31
  isDomainAllowed,
33
32
  isRecord,
33
+ isQueryTrap,
34
34
  buildLandstripPolicy,
35
35
  landstripBinaryPath,
36
36
  loadConfig,
37
37
  normalizeOptions,
38
38
  parseLandstripTraps,
39
+ parseTrapLine,
39
40
  readDiscoveryPort,
40
41
  writeLandstripPolicyFile,
41
42
  trapSessionHelloLine,
@@ -262,17 +263,8 @@ function startTrapServer(
262
263
  buffer = buffer.slice(nl + 1);
263
264
  nl = buffer.indexOf('\n');
264
265
  if (line.length === 0) continue;
265
- let trap: LandstripTrap | null = null;
266
- try {
267
- trap = decodeLandstripTrap(JSON.parse(line));
268
- } catch {
269
- trap = null;
270
- }
271
- if (
272
- (trap?.kind === 'filesystem' || trap?.kind === 'network') &&
273
- trap.state === 'query' &&
274
- trap.query_id
275
- ) {
266
+ const trap = parseTrapLine(line);
267
+ if (trap && isQueryTrap(trap)) {
276
268
  const queryId = trap.query_id;
277
269
  if (trap.kind === 'filesystem') {
278
270
  const path = canonicalizePath(trap.path, baseDirectory);
@@ -295,13 +287,8 @@ function startTrapServer(
295
287
  trapSocket.write(controlResponseLine(queryId, 'deny'));
296
288
  trapLines.push(line);
297
289
  }
298
- } else if (
299
- trap.kind === 'network' &&
300
- (trap.operation === 'connect' || trap.operation === 'bind')
301
- ) {
302
- trapSocket.write(controlResponseLine(queryId, 'deny'));
303
- trapLines.push(line);
304
290
  } else {
291
+ trapSocket.write(controlResponseLine(queryId, 'deny'));
305
292
  trapLines.push(line);
306
293
  }
307
294
  } else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-landstrip",
3
- "version": "0.19.12",
3
+ "version": "0.19.14",
4
4
  "description": "OS-level AI command sandboxing for OpenCode with Landstrip",
5
5
  "keywords": [
6
6
  "landlock",
@@ -48,7 +48,7 @@
48
48
  "ci:test": "npm test"
49
49
  },
50
50
  "dependencies": {
51
- "@landstrip/landstrip-api": "^0.19.12",
51
+ "@landstrip/landstrip-api": "^0.19.14",
52
52
  "@opentui/core": ">=0.5.12",
53
53
  "@opentui/solid": ">=0.5.12",
54
54
  "solid-js": "1.9.12"
package/shared.ts CHANGED
@@ -33,8 +33,10 @@ export {
33
33
  formatLandstripTrap,
34
34
  formatLandstripTraps,
35
35
  isRecord,
36
+ isQueryTrap,
36
37
  normalizePathSeparators,
37
38
  parseLandstripTraps,
39
+ parseTrapLine,
38
40
  pathUnderDirectory,
39
41
  resolveFilesystemPatterns,
40
42
  resolveFilesystemPolicy,
package/tui.ts CHANGED
@@ -16,6 +16,7 @@ import {
16
16
  controlResponseLine,
17
17
  decodeTrapSessionHello,
18
18
  getConfigPaths,
19
+ isQueryTrap,
19
20
  loadConfig,
20
21
  normalizeOptions,
21
22
  nextSandboxPermissionIndex,
@@ -576,8 +577,7 @@ const tui: TuiPlugin.Definition = {
576
577
 
577
578
  const allowances = sessionAllowancesFor(sessionAllowances, routeSessionID);
578
579
  for (const trap of parseLandstripTraps(line)) {
579
- if (trap.kind !== 'filesystem' && trap.kind !== 'network') continue;
580
- if (trap.state !== 'query') continue;
580
+ if (!isQueryTrap(trap)) continue;
581
581
  if (seen.has(trap.query_id)) continue;
582
582
  seen.add(trap.query_id);
583
583