pi-landstrip 0.14.1 → 0.14.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 +61 -6
  2. package/package.json +1 -1
package/index.ts CHANGED
@@ -454,6 +454,16 @@ function extractBlockedWritePath(output: string, cwd: string): string | null {
454
454
  return extractNativeWriteDeniedPath(output, cwd);
455
455
  }
456
456
 
457
+ function extractBlockedReadPath(output: string, cwd: string): string | null {
458
+ for (const error of parseLandstripTraps(output).filter(isFilesystemTrap)) {
459
+ if (error.operation === 'read') {
460
+ return normalizeBlockedPath(error.file, cwd);
461
+ }
462
+ }
463
+
464
+ return extractNativeDeniedPath(output, cwd);
465
+ }
466
+
457
467
  // Returns the first `length` elements of a string tuple, or null if `value` is
458
468
  // not an array of at least that many strings.
459
469
  function stringTuple(value: unknown, length: number): string[] | null {
@@ -1310,17 +1320,54 @@ export function createLandstripIntegration(
1310
1320
  return run();
1311
1321
  };
1312
1322
 
1323
+ const retryWithReadAccess = async (
1324
+ blockedPath: string,
1325
+ ): Promise<AgentToolResult<BashToolDetails | undefined> | null> => {
1326
+ if (!ctx.hasUI) return null;
1327
+
1328
+ if (!matchesPattern(blockedPath, getEffectiveAllowRead(ctx.cwd))) {
1329
+ const config = loadConfig(ctx.cwd);
1330
+ const choice = await promptReadBlock(
1331
+ ctx,
1332
+ blockedPath,
1333
+ matchesPattern(blockedPath, config.filesystem.denyRead)
1334
+ ? 'denyRead overrides allowRead'
1335
+ : undefined,
1336
+ );
1337
+ if (choice === 'abort') return null;
1338
+ await applyReadChoice(choice, blockedPath, ctx.cwd);
1339
+ }
1340
+
1341
+ onUpdate?.({
1342
+ content: [
1343
+ { type: 'text', text: `\n--- Read access granted for "${blockedPath}", retrying ---\n` },
1344
+ ],
1345
+ details: {},
1346
+ });
1347
+ landstripErrorOutput = '';
1348
+ stderrOutput = '';
1349
+ return run();
1350
+ };
1351
+
1313
1352
  let result: AgentToolResult<BashToolDetails | undefined>;
1314
1353
  try {
1315
1354
  result = await run();
1316
1355
  } catch (error) {
1317
1356
  const errorText = error instanceof Error ? error.message : String(error);
1318
1357
  const fallbackOutput = `${stderrOutput}\n${errorText}`;
1319
- const blockedPath =
1358
+ const blockedWritePath =
1320
1359
  extractBlockedWritePath(landstripErrorOutput, ctx.cwd) ??
1321
1360
  extractBlockedWritePath(fallbackOutput, ctx.cwd);
1322
- if (blockedPath) {
1323
- const retryResult = await retryWithWriteAccess(blockedPath);
1361
+ if (blockedWritePath) {
1362
+ const retryResult = await retryWithWriteAccess(blockedWritePath);
1363
+ if (retryResult) return retryResult;
1364
+ }
1365
+
1366
+ const blockedReadPath =
1367
+ extractBlockedReadPath(landstripErrorOutput, ctx.cwd) ??
1368
+ extractBlockedReadPath(fallbackOutput, ctx.cwd);
1369
+ if (blockedReadPath) {
1370
+ const retryResult = await retryWithReadAccess(blockedReadPath);
1324
1371
  if (retryResult) return retryResult;
1325
1372
  }
1326
1373
 
@@ -1335,12 +1382,20 @@ export function createLandstripIntegration(
1335
1382
  const message = formatLandstripTraps(landstripErrors);
1336
1383
  result.content.unshift({ type: 'text', text: `\n${message}\n` });
1337
1384
  }
1338
- const blockedPath =
1385
+ const blockedWritePath =
1339
1386
  extractBlockedWritePath(landstripErrorOutput, ctx.cwd) ??
1340
1387
  extractBlockedWritePath(stderrOutput, ctx.cwd);
1341
- if (!blockedPath) return result;
1388
+ if (blockedWritePath) {
1389
+ const retryResult = await retryWithWriteAccess(blockedWritePath);
1390
+ if (retryResult) return retryResult;
1391
+ }
1392
+
1393
+ const blockedReadPath =
1394
+ extractBlockedReadPath(landstripErrorOutput, ctx.cwd) ??
1395
+ extractBlockedReadPath(stderrOutput, ctx.cwd);
1396
+ if (!blockedReadPath) return result;
1342
1397
 
1343
- const retryResult = await retryWithWriteAccess(blockedPath);
1398
+ const retryResult = await retryWithReadAccess(blockedReadPath);
1344
1399
  return retryResult ?? result;
1345
1400
  }
1346
1401
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-landstrip",
3
- "version": "0.14.1",
3
+ "version": "0.14.2",
4
4
  "description": "Landlock-based sandboxing for pi with interactive permission prompts",
5
5
  "keywords": [
6
6
  "landstrip",