pi-landstrip 0.14.2 → 0.15.0
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/index.ts +46 -43
- package/package.json +2 -2
package/index.ts
CHANGED
|
@@ -464,53 +464,56 @@ function extractBlockedReadPath(output: string, cwd: string): string | null {
|
|
|
464
464
|
return extractNativeDeniedPath(output, cwd);
|
|
465
465
|
}
|
|
466
466
|
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
function stringTuple(value: unknown, length: number): string[] | null {
|
|
470
|
-
if (!Array.isArray(value) || value.length < length) return null;
|
|
471
|
-
const head = value.slice(0, length);
|
|
472
|
-
return head.every((item) => typeof item === 'string') ? (head as string[]) : null;
|
|
467
|
+
function asString(value: unknown): string | null {
|
|
468
|
+
return typeof value === 'string' ? value : null;
|
|
473
469
|
}
|
|
474
470
|
|
|
475
|
-
// landstrip emits each trap as a
|
|
476
|
-
//
|
|
477
|
-
//
|
|
471
|
+
// landstrip emits each trap as a flat JSON record tagged by a `kind`
|
|
472
|
+
// discriminant (`filesystem`, `network`, `launch`, `usage`, `internal`)
|
|
473
|
+
// alongside a stable `code` and variant-specific fields.
|
|
478
474
|
function parseLandstripTrap(obj: Record<string, unknown>): LandstripTrap | null {
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
475
|
+
switch (obj.kind) {
|
|
476
|
+
case 'filesystem': {
|
|
477
|
+
const operation = obj.operation;
|
|
478
|
+
const file = asString(obj.path);
|
|
479
|
+
if ((operation === 'read' || operation === 'write') && file !== null) {
|
|
480
|
+
return { kind: 'filesystem', operation, file, mechanism: asString(obj.mechanism) ?? '' };
|
|
481
|
+
}
|
|
482
|
+
return null;
|
|
484
483
|
}
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
if (typeof obj.Usage === 'string') {
|
|
501
|
-
return { kind: 'usage', message: obj.Usage };
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
const internal = obj.Internal;
|
|
505
|
-
if (typeof internal === 'object' && internal !== null && !Array.isArray(internal)) {
|
|
506
|
-
const detail: Record<string, string> = {};
|
|
507
|
-
for (const [key, value] of Object.entries(internal)) {
|
|
508
|
-
if (typeof value === 'string') detail[key] = value;
|
|
484
|
+
case 'network': {
|
|
485
|
+
const operation = asString(obj.operation);
|
|
486
|
+
const target = asString(obj.target);
|
|
487
|
+
if (operation !== null && target !== null) {
|
|
488
|
+
return { kind: 'network', operation, target, mechanism: asString(obj.mechanism) ?? '' };
|
|
489
|
+
}
|
|
490
|
+
return null;
|
|
491
|
+
}
|
|
492
|
+
case 'launch': {
|
|
493
|
+
const program = asString(obj.program);
|
|
494
|
+
const source = asString(obj.message);
|
|
495
|
+
if (program !== null && source !== null) {
|
|
496
|
+
return { kind: 'launch', program, source };
|
|
497
|
+
}
|
|
498
|
+
return null;
|
|
509
499
|
}
|
|
510
|
-
|
|
500
|
+
case 'usage': {
|
|
501
|
+
const message = asString(obj.message);
|
|
502
|
+
return message !== null ? { kind: 'usage', message } : null;
|
|
503
|
+
}
|
|
504
|
+
case 'internal': {
|
|
505
|
+
const detail: Record<string, string> = {};
|
|
506
|
+
const raw = obj.detail;
|
|
507
|
+
if (typeof raw === 'object' && raw !== null && !Array.isArray(raw)) {
|
|
508
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
509
|
+
if (typeof value === 'string') detail[key] = value;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
return { kind: 'internal', detail };
|
|
513
|
+
}
|
|
514
|
+
default:
|
|
515
|
+
return null;
|
|
511
516
|
}
|
|
512
|
-
|
|
513
|
-
return null;
|
|
514
517
|
}
|
|
515
518
|
|
|
516
519
|
function parseLandstripTraps(output: string): LandstripTrap[] {
|
|
@@ -1233,7 +1236,7 @@ export function createLandstripIntegration(
|
|
|
1233
1236
|
const choice = await promptReadBlock(
|
|
1234
1237
|
ctx,
|
|
1235
1238
|
blockedPath,
|
|
1236
|
-
isDeniedByDenyRead ? '
|
|
1239
|
+
isDeniedByDenyRead ? 'granting allowRead will override it' : undefined,
|
|
1237
1240
|
);
|
|
1238
1241
|
if (choice !== 'abort') await applyReadChoice(choice, blockedPath, cwd);
|
|
1239
1242
|
} else if (!isWriteAllowed) {
|
|
@@ -1331,7 +1334,7 @@ export function createLandstripIntegration(
|
|
|
1331
1334
|
ctx,
|
|
1332
1335
|
blockedPath,
|
|
1333
1336
|
matchesPattern(blockedPath, config.filesystem.denyRead)
|
|
1334
|
-
? '
|
|
1337
|
+
? 'granting allowRead will override it'
|
|
1335
1338
|
: undefined,
|
|
1336
1339
|
);
|
|
1337
1340
|
if (choice === 'abort') return null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-landstrip",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"description": "Landlock-based sandboxing for pi with interactive permission prompts",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"landstrip",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@earendil-works/pi-tui": "^0.78.0",
|
|
34
|
-
"@landstrip/landstrip": "^0.
|
|
34
|
+
"@landstrip/landstrip": "^0.15.1"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@earendil-works/pi-coding-agent": "^0.78.0",
|