pi-landstrip 0.5.0 → 0.5.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.
Files changed (2) hide show
  1. package/index.ts +28 -8
  2. package/package.json +1 -1
package/index.ts CHANGED
@@ -356,6 +356,12 @@ function extractBlockedPath(output: string, cwd: string): string | null {
356
356
  );
357
357
  if (match) return normalizeBlockedPath(match[1], cwd);
358
358
 
359
+ // Landstrip structured error format with file field
360
+ const landstripErrors = parseLandstripErrors(output);
361
+ for (const error of landstripErrors) {
362
+ if (error.file) return normalizeBlockedPath(error.file, cwd);
363
+ }
364
+
359
365
  return null;
360
366
  }
361
367
 
@@ -606,12 +612,15 @@ function promptDomainBlock(ctx: ExtensionContext, domain: string): Promise<Permi
606
612
  );
607
613
  }
608
614
 
609
- function promptReadBlock(ctx: ExtensionContext, filePath: string): Promise<PermissionChoice> {
610
- return showPermissionPrompt(
611
- ctx,
612
- `Read blocked: "${filePath}" is not in allowRead`,
613
- PERMISSION_OPTIONS,
614
- );
615
+ function promptReadBlock(
616
+ ctx: ExtensionContext,
617
+ filePath: string,
618
+ reason?: string,
619
+ ): Promise<PermissionChoice> {
620
+ const title = reason
621
+ ? `Read blocked: "${filePath}" is in denyRead (${reason})`
622
+ : `Read blocked: "${filePath}" is not in allowRead`;
623
+ return showPermissionPrompt(ctx, title, PERMISSION_OPTIONS);
615
624
  }
616
625
 
617
626
  function promptWriteBlock(ctx: ExtensionContext, filePath: string): Promise<PermissionChoice> {
@@ -1039,6 +1048,7 @@ export function createLandstripIntegration(
1039
1048
  const blockedPath = extractBlockedPath(stderrAcc, cwd);
1040
1049
  if (blockedPath && ctx.hasUI) {
1041
1050
  const config = loadConfig(cwd);
1051
+ const isDeniedByDenyRead = matchesPattern(blockedPath, config.filesystem.denyRead);
1042
1052
  const isReadAllowed = matchesPattern(blockedPath, getEffectiveAllowRead(cwd));
1043
1053
  const isWriteAllowed = !shouldPromptForWrite(
1044
1054
  blockedPath,
@@ -1046,13 +1056,23 @@ export function createLandstripIntegration(
1046
1056
  matchesPattern,
1047
1057
  );
1048
1058
 
1049
- if (!isReadAllowed) {
1050
- const choice = await promptReadBlock(ctx, blockedPath);
1059
+ if (isDeniedByDenyRead || !isReadAllowed) {
1060
+ const choice = await promptReadBlock(
1061
+ ctx,
1062
+ blockedPath,
1063
+ isDeniedByDenyRead ? 'denyRead overrides allowRead' : undefined,
1064
+ );
1051
1065
  if (choice !== 'abort') await applyReadChoice(choice, blockedPath, cwd);
1052
1066
  } else if (!isWriteAllowed) {
1053
1067
  const choice = await promptWriteBlock(ctx, blockedPath);
1054
1068
  if (choice !== 'abort') await applyWriteChoice(choice, blockedPath, cwd);
1055
1069
  }
1070
+ } else if (!blockedPath && ctx.hasUI) {
1071
+ const landstripErrors = parseLandstripErrors(stderrAcc);
1072
+ if (landstripErrors.length > 0) {
1073
+ const formatted = formatLandstripErrors(landstripErrors);
1074
+ ctx.ui.notify(`Sandbox blocked an operation: ${formatted}`, 'warning');
1075
+ }
1056
1076
  }
1057
1077
 
1058
1078
  resolvePromise({ exitCode: code });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-landstrip",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "description": "Landlock-based sandboxing for pi with interactive permission prompts",
5
5
  "keywords": [
6
6
  "landstrip",