pi-landstrip 0.3.0 → 0.3.1

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 +33 -13
  2. package/package.json +2 -2
package/index.ts CHANGED
@@ -72,12 +72,11 @@ interface LandstripErrorResponse {
72
72
  category: 'policy' | 'tool' | 'platform' | 'system';
73
73
  file?: string;
74
74
  program?: string;
75
- target?: 'filesystem' | 'network' | 'platform';
76
- kind?: 'launch' | 'encoding';
75
+ type?: 'filesystem' | 'network' | 'platform' | 'launch' | 'encoding';
77
76
  message: string;
78
77
  }
79
78
 
80
- const LANDSTRIP_VERSION = [0, 9, 2] as const;
79
+ const LANDSTRIP_VERSION = [0, 9, 5] as const;
81
80
  const SUPPORTED_PLATFORMS = new Set<NodeJS.Platform>(['linux', 'darwin', 'win32']);
82
81
 
83
82
  const DEFAULT_CONFIG: SandboxConfig = {
@@ -353,6 +352,9 @@ function parseLandstripErrors(output: string): LandstripErrorResponse[] {
353
352
  parsed !== null &&
354
353
  typeof parsed.category === 'string' &&
355
354
  ['policy', 'tool', 'platform', 'system'].includes(parsed.category) &&
355
+ (parsed.type === undefined ||
356
+ (typeof parsed.type === 'string' &&
357
+ ['filesystem', 'network', 'platform', 'launch', 'encoding'].includes(parsed.type))) &&
356
358
  typeof parsed.message === 'string' &&
357
359
  parsed.message.length > 0
358
360
  ) {
@@ -371,14 +373,14 @@ function formatLandstripErrors(errors: LandstripErrorResponse[]): string {
371
373
  .map((err) => {
372
374
  const parts: string[] = [`landstrip: ${err.category}`];
373
375
 
374
- if (err.target) {
375
- parts.push(`(${err.target})`);
376
+ if (err.file) {
377
+ parts.push(` (${err.file})`);
376
378
  }
377
379
  if (err.program) {
378
380
  parts.push(` ${err.program}`);
379
381
  }
380
- if (err.kind) {
381
- parts.push(`:${err.kind}`);
382
+ if (err.type) {
383
+ parts.push(`:${err.type}`);
382
384
  }
383
385
  parts.push(`: ${err.message}`);
384
386
 
@@ -828,7 +830,10 @@ export default function (pi: ExtensionAPI) {
828
830
  });
829
831
  }
830
832
 
831
- function createLandstripBashOps(ctx: ExtensionContext): BashOperations {
833
+ function createLandstripBashOps(
834
+ ctx: ExtensionContext,
835
+ onStderr: (data: Buffer) => void = () => {},
836
+ ): BashOperations {
832
837
  return {
833
838
  async exec(command, cwd, { onData, signal, timeout, env }) {
834
839
  if (!existsSync(cwd)) throw new Error(`Working directory does not exist: ${cwd}`);
@@ -881,7 +886,10 @@ export default function (pi: ExtensionAPI) {
881
886
 
882
887
  signal?.addEventListener('abort', onAbort, { once: true });
883
888
  child.stdout?.on('data', onData);
884
- child.stderr?.on('data', onData);
889
+ child.stderr?.on('data', (data: Buffer) => {
890
+ onStderr(data);
891
+ onData(data);
892
+ });
885
893
 
886
894
  child.on('error', (error) => {
887
895
  cleanup();
@@ -910,18 +918,30 @@ export default function (pi: ExtensionAPI) {
910
918
  onUpdate: AgentToolUpdateCallback<BashToolDetails | undefined> | undefined,
911
919
  ctx: ExtensionContext,
912
920
  ): Promise<AgentToolResult<BashToolDetails | undefined>> {
921
+ let landstripStderr = '';
913
922
  const sandboxedBash = createBashToolDefinition(localCwd, {
914
- operations: createLandstripBashOps(ctx),
923
+ operations: createLandstripBashOps(ctx, (data) => {
924
+ landstripStderr += data.toString('utf8');
925
+ }),
915
926
  shellPath: userShellPath,
916
927
  });
917
928
 
918
929
  const run = () => sandboxedBash.execute(id, params, signal, onUpdate, ctx);
919
- const result = await run();
930
+ let result: AgentToolResult<BashToolDetails | undefined>;
931
+ try {
932
+ result = await run();
933
+ } catch (error) {
934
+ const landstripErrors = parseLandstripErrors(landstripStderr);
935
+ if (landstripErrors.length > 0) {
936
+ throw new Error(formatLandstripErrors(landstripErrors));
937
+ }
938
+ throw error;
939
+ }
920
940
  const outputText = result.content
921
941
  .filter((content) => content.type === 'text')
922
942
  .map((content) => content.text)
923
943
  .join('\n');
924
- const landstripErrors = parseLandstripErrors(outputText);
944
+ const landstripErrors = parseLandstripErrors(landstripStderr);
925
945
  if (landstripErrors.length > 0) {
926
946
  const message = formatLandstripErrors(landstripErrors);
927
947
  result.content.unshift({ type: 'text', text: `\n${message}\n` });
@@ -1010,7 +1030,7 @@ export default function (pi: ExtensionAPI) {
1010
1030
  if (!hasMinimumVersion(version, LANDSTRIP_VERSION)) {
1011
1031
  sandboxEnabled = false;
1012
1032
  sandboxReady = false;
1013
- ctx.ui.notify(`landstrip 0.9.2 or newer is required; found: ${version}`, 'error');
1033
+ ctx.ui.notify(`landstrip 0.9.5 or newer is required; found: ${version}`, 'error');
1014
1034
  return false;
1015
1035
  }
1016
1036
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-landstrip",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Landlock-based sandboxing for pi with interactive permission prompts",
5
5
  "keywords": [
6
6
  "landstrip",
@@ -30,7 +30,7 @@
30
30
  },
31
31
  "dependencies": {
32
32
  "@earendil-works/pi-tui": "^0.78.0",
33
- "@jarkkojs/landstrip": "^0.9.2"
33
+ "@jarkkojs/landstrip": "^0.9.5"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@earendil-works/pi-coding-agent": "^0.78.0",