pi-landstrip 0.18.22 → 0.18.23
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/dist/index.ts +124 -2
- package/package.json +2 -2
package/dist/index.ts
CHANGED
|
@@ -5425,6 +5425,118 @@ function createLandstripIntegration(options = {}) {
|
|
|
5425
5425
|
writePaths: options2.writePaths ?? []
|
|
5426
5426
|
});
|
|
5427
5427
|
}
|
|
5428
|
+
function createProviderBashOps() {
|
|
5429
|
+
return {
|
|
5430
|
+
async exec(command, cwd, { onData, signal, timeout, env }) {
|
|
5431
|
+
if (!existsSync5(cwd))
|
|
5432
|
+
throw new Error(`Working directory does not exist: ${cwd}`);
|
|
5433
|
+
const provider = activeShellProvider();
|
|
5434
|
+
let invocation;
|
|
5435
|
+
try {
|
|
5436
|
+
invocation = await provider.prepare({
|
|
5437
|
+
command,
|
|
5438
|
+
cwd,
|
|
5439
|
+
env: shellEnvironment(env, cwd, null),
|
|
5440
|
+
signal
|
|
5441
|
+
});
|
|
5442
|
+
if (!invocation.executable.trim()) {
|
|
5443
|
+
throw new Error(`Shell provider "${provider.id}" returned an empty executable`);
|
|
5444
|
+
}
|
|
5445
|
+
if (signal?.aborted)
|
|
5446
|
+
throw new Error("aborted");
|
|
5447
|
+
const prepared = invocation;
|
|
5448
|
+
return await new Promise((resolvePromise, reject) => {
|
|
5449
|
+
let timeoutHandle;
|
|
5450
|
+
let timedOut = false;
|
|
5451
|
+
let settled = false;
|
|
5452
|
+
let childExited = false;
|
|
5453
|
+
let childExitCode = null;
|
|
5454
|
+
let postExitTimer;
|
|
5455
|
+
let stdoutEnded = false;
|
|
5456
|
+
let stderrEnded = false;
|
|
5457
|
+
const child = spawn2(prepared.executable, prepared.args, {
|
|
5458
|
+
cwd,
|
|
5459
|
+
env: createLandstripLauncherEnvironment(prepared.launcherEnv),
|
|
5460
|
+
detached: true,
|
|
5461
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
5462
|
+
});
|
|
5463
|
+
patchProcessGroupKill(child);
|
|
5464
|
+
const cleanup = async () => {
|
|
5465
|
+
if (timeoutHandle)
|
|
5466
|
+
clearTimeout(timeoutHandle);
|
|
5467
|
+
if (postExitTimer)
|
|
5468
|
+
clearTimeout(postExitTimer);
|
|
5469
|
+
signal?.removeEventListener("abort", onAbort);
|
|
5470
|
+
const toDispose = invocation;
|
|
5471
|
+
invocation = undefined;
|
|
5472
|
+
await toDispose?.dispose?.();
|
|
5473
|
+
};
|
|
5474
|
+
const finish = (code) => {
|
|
5475
|
+
if (settled)
|
|
5476
|
+
return;
|
|
5477
|
+
settled = true;
|
|
5478
|
+
child.stdout?.destroy();
|
|
5479
|
+
child.stderr?.destroy();
|
|
5480
|
+
cleanup().then(() => {
|
|
5481
|
+
if (signal?.aborted)
|
|
5482
|
+
reject(new Error("aborted"));
|
|
5483
|
+
else if (timedOut)
|
|
5484
|
+
reject(new Error(`timeout:${timeout}`));
|
|
5485
|
+
else
|
|
5486
|
+
resolvePromise({ exitCode: code });
|
|
5487
|
+
}, reject);
|
|
5488
|
+
};
|
|
5489
|
+
const maybeFinishAfterExit = () => {
|
|
5490
|
+
if (childExited && stdoutEnded && stderrEnded)
|
|
5491
|
+
finish(childExitCode);
|
|
5492
|
+
};
|
|
5493
|
+
const killChild = () => {
|
|
5494
|
+
child.kill("SIGKILL");
|
|
5495
|
+
};
|
|
5496
|
+
function onAbort() {
|
|
5497
|
+
killChild();
|
|
5498
|
+
}
|
|
5499
|
+
child.stdout?.on("data", onData);
|
|
5500
|
+
child.stderr?.on("data", onData);
|
|
5501
|
+
child.stdout?.once("end", () => {
|
|
5502
|
+
stdoutEnded = true;
|
|
5503
|
+
maybeFinishAfterExit();
|
|
5504
|
+
});
|
|
5505
|
+
child.stderr?.once("end", () => {
|
|
5506
|
+
stderrEnded = true;
|
|
5507
|
+
maybeFinishAfterExit();
|
|
5508
|
+
});
|
|
5509
|
+
child.once("error", (error) => {
|
|
5510
|
+
if (settled)
|
|
5511
|
+
return;
|
|
5512
|
+
settled = true;
|
|
5513
|
+
cleanup().then(() => reject(error), reject);
|
|
5514
|
+
});
|
|
5515
|
+
child.once("exit", (code) => {
|
|
5516
|
+
childExited = true;
|
|
5517
|
+
childExitCode = code;
|
|
5518
|
+
maybeFinishAfterExit();
|
|
5519
|
+
if (!settled)
|
|
5520
|
+
postExitTimer = setTimeout(() => finish(code), EXIT_STDIO_GRACE_MS);
|
|
5521
|
+
});
|
|
5522
|
+
child.once("close", (code) => finish(code));
|
|
5523
|
+
if (timeout !== undefined && timeout > 0) {
|
|
5524
|
+
timeoutHandle = setTimeout(() => {
|
|
5525
|
+
timedOut = true;
|
|
5526
|
+
killChild();
|
|
5527
|
+
}, timeout * 1000);
|
|
5528
|
+
}
|
|
5529
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
5530
|
+
if (signal?.aborted)
|
|
5531
|
+
onAbort();
|
|
5532
|
+
});
|
|
5533
|
+
} catch (error) {
|
|
5534
|
+
await invocation?.dispose?.();
|
|
5535
|
+
throw error;
|
|
5536
|
+
}
|
|
5537
|
+
}
|
|
5538
|
+
};
|
|
5539
|
+
}
|
|
5428
5540
|
function createLandstripBashOps(ctx, callbacks = {}, allowances = { domains: [], readPaths: [], writePaths: [], targets: [] }) {
|
|
5429
5541
|
return {
|
|
5430
5542
|
async exec(command, cwd, { onData, signal, timeout, env }) {
|
|
@@ -5920,9 +6032,16 @@ ${message}
|
|
|
5920
6032
|
if (!ctx)
|
|
5921
6033
|
throw new Error("Sandbox context is unavailable");
|
|
5922
6034
|
if (!ensureSandboxState(ctx)) {
|
|
5923
|
-
if (sandboxState === "unavailable") {
|
|
6035
|
+
if (sandboxState === "unavailable" && externalShellProvider === undefined) {
|
|
5924
6036
|
throw new Error("Sandbox is unavailable; refusing command");
|
|
5925
6037
|
}
|
|
6038
|
+
if (externalShellProvider !== undefined) {
|
|
6039
|
+
const providerBash = createBashToolDefinition(ctx.cwd, {
|
|
6040
|
+
operations: createProviderBashOps(),
|
|
6041
|
+
shellPath: SettingsManager.create(ctx.cwd).getShellPath()
|
|
6042
|
+
});
|
|
6043
|
+
return providerBash.execute(id, params, signal, onUpdate, ctx);
|
|
6044
|
+
}
|
|
5926
6045
|
return localBash.execute(id, params, signal, onUpdate, ctx);
|
|
5927
6046
|
}
|
|
5928
6047
|
return runBashWithOptionalRetry(id, params, signal, onUpdate, ctx);
|
|
@@ -5942,9 +6061,12 @@ ${message}
|
|
|
5942
6061
|
pi.registerTool(createBashTool(localCwd));
|
|
5943
6062
|
pi.on("user_bash", async (_event, ctx) => {
|
|
5944
6063
|
if (!ensureSandboxState(ctx)) {
|
|
5945
|
-
if (sandboxState === "unavailable") {
|
|
6064
|
+
if (sandboxState === "unavailable" && externalShellProvider === undefined) {
|
|
5946
6065
|
throw new Error("Sandbox is unavailable; refusing command");
|
|
5947
6066
|
}
|
|
6067
|
+
if (externalShellProvider !== undefined) {
|
|
6068
|
+
return { operations: createProviderBashOps() };
|
|
6069
|
+
}
|
|
5948
6070
|
return;
|
|
5949
6071
|
}
|
|
5950
6072
|
return { operations: createLandstripBashOps(ctx, { promptOnBlock: true }) };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-landstrip",
|
|
3
|
-
"version": "0.18.
|
|
3
|
+
"version": "0.18.23",
|
|
4
4
|
"description": "Sandboxed Bash and process-backed agents for Pi",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"landstrip",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"ci:test": "npm run test"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@landstrip/landstrip": "^0.18.
|
|
42
|
+
"@landstrip/landstrip": "^0.18.23",
|
|
43
43
|
"jsonc-parser": "^3.3.1",
|
|
44
44
|
"minimatch": "^10.2.5",
|
|
45
45
|
"yaml": "^2.9.0"
|