@demicodes/shell 0.8.0 → 0.9.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/dist/index.d.mts +18 -1
- package/dist/index.mjs +12 -3
- package/package.json +2 -2
package/dist/index.d.mts
CHANGED
|
@@ -91,7 +91,21 @@ interface BashEnvironmentOptions {
|
|
|
91
91
|
shellIdFactory?: () => string;
|
|
92
92
|
commandIdFactory?: () => string;
|
|
93
93
|
initialEnv?: Record<string, string>;
|
|
94
|
+
/** Cap on a command's text stdout. Guards against log floods. */
|
|
94
95
|
maxOutputBytes?: number;
|
|
96
|
+
/**
|
|
97
|
+
* Cap on a final stdout stream that is raw bytes rather than text.
|
|
98
|
+
*
|
|
99
|
+
* Separate from `maxOutputBytes` because the two guard different risks. Text
|
|
100
|
+
* costs context roughly in proportion to its bytes, so a tight cap is what
|
|
101
|
+
* stops a stray `cat` of a log file from flooding a window. Raw bytes are
|
|
102
|
+
* carried to be looked at — a picture, a clip — and there a megabyte buys far
|
|
103
|
+
* more than a megabyte of text does, so the same number would forbid the
|
|
104
|
+
* ordinary case. This layer deliberately stops at that distinction: which
|
|
105
|
+
* modality the bytes are, and what a given model should be shown, is decided
|
|
106
|
+
* above, where models are known.
|
|
107
|
+
*/
|
|
108
|
+
maxBinaryBytes?: number;
|
|
95
109
|
}
|
|
96
110
|
interface ShellExecInput {
|
|
97
111
|
script: string;
|
|
@@ -182,10 +196,12 @@ interface CommandMetadataRecord {
|
|
|
182
196
|
/** Final stdout stream that is not valid UTF-8: raw bytes for the boundary above. */
|
|
183
197
|
interface BinaryStdout {
|
|
184
198
|
data: Uint8Array;
|
|
185
|
-
/** True when the stream exceeded the
|
|
199
|
+
/** True when the stream exceeded the applicable cap; data is capped. */
|
|
186
200
|
truncated: boolean;
|
|
187
201
|
/** Total byte count of the un-capped stream. */
|
|
188
202
|
totalBytes: number;
|
|
203
|
+
/** The byte ceiling that applied, so the boundary above can name it. */
|
|
204
|
+
limitBytes: number;
|
|
189
205
|
}
|
|
190
206
|
type ShellCommandStatus = {
|
|
191
207
|
status: 'exited';
|
|
@@ -229,6 +245,7 @@ declare class BashEnvironment {
|
|
|
229
245
|
private readonly commandIdFactory;
|
|
230
246
|
private readonly initialEnv;
|
|
231
247
|
private readonly defaultOutputLimitBytes;
|
|
248
|
+
private readonly defaultBinaryLimitBytes;
|
|
232
249
|
private readonly shells;
|
|
233
250
|
private readonly defaultShellByAgentSessionId;
|
|
234
251
|
private readonly commandsById;
|
package/dist/index.mjs
CHANGED
|
@@ -784,6 +784,12 @@ function decodeForkStdin(stdin) {
|
|
|
784
784
|
//#region src/environment.ts
|
|
785
785
|
const DEFAULT_TIMEOUT_MS = 1e4;
|
|
786
786
|
const DEFAULT_OUTPUT_LIMIT_BYTES = 1024 * 1024;
|
|
787
|
+
/**
|
|
788
|
+
* Ceiling for a raw-byte final stream. Sized so an ordinary viewing-grade clip
|
|
789
|
+
* survives the shell and reaches the layer that decides what to do with it,
|
|
790
|
+
* while still bounding a runaway producer.
|
|
791
|
+
*/
|
|
792
|
+
const DEFAULT_BINARY_LIMIT_BYTES = 16 * 1024 * 1024;
|
|
787
793
|
/** Upper bound for a single exec observation window (also the command-bridge wait ceiling). */
|
|
788
794
|
const MAX_TIMEOUT_MS = 6e5;
|
|
789
795
|
var BashEnvironment = class {
|
|
@@ -793,6 +799,7 @@ var BashEnvironment = class {
|
|
|
793
799
|
commandIdFactory;
|
|
794
800
|
initialEnv;
|
|
795
801
|
defaultOutputLimitBytes;
|
|
802
|
+
defaultBinaryLimitBytes;
|
|
796
803
|
shells = /* @__PURE__ */ new Map();
|
|
797
804
|
defaultShellByAgentSessionId = /* @__PURE__ */ new Map();
|
|
798
805
|
commandsById = /* @__PURE__ */ new Map();
|
|
@@ -805,6 +812,7 @@ var BashEnvironment = class {
|
|
|
805
812
|
this.commandIdFactory = options.commandIdFactory ?? (() => globalThis.crypto.randomUUID());
|
|
806
813
|
this.initialEnv = options.initialEnv ?? {};
|
|
807
814
|
this.defaultOutputLimitBytes = options.maxOutputBytes ?? DEFAULT_OUTPUT_LIMIT_BYTES;
|
|
815
|
+
this.defaultBinaryLimitBytes = options.maxBinaryBytes ?? DEFAULT_BINARY_LIMIT_BYTES;
|
|
808
816
|
}
|
|
809
817
|
getShell(shellId) {
|
|
810
818
|
return this.shells.get(shellId) ?? null;
|
|
@@ -1426,14 +1434,15 @@ var BashEnvironment = class {
|
|
|
1426
1434
|
const strict = decodeUtf8Strict(bytes);
|
|
1427
1435
|
if (strict !== null) stdoutText = strict;
|
|
1428
1436
|
else {
|
|
1429
|
-
const cap =
|
|
1437
|
+
const cap = this.defaultBinaryLimitBytes;
|
|
1430
1438
|
const truncated = bytes.length > cap;
|
|
1431
1439
|
binary = {
|
|
1432
1440
|
data: truncated ? bytes.slice(0, cap) : bytes,
|
|
1433
1441
|
truncated,
|
|
1434
|
-
totalBytes: bytes.length
|
|
1442
|
+
totalBytes: bytes.length,
|
|
1443
|
+
limitBytes: cap
|
|
1435
1444
|
};
|
|
1436
|
-
stdoutText = `<binary stdout: ${bytes.length} bytes${truncated ? `, exceeds the ${cap}-byte
|
|
1445
|
+
stdoutText = `<binary stdout: ${bytes.length} bytes${truncated ? `, exceeds the ${cap}-byte binary limit` : ""}; raw bytes at /@/commands/${record.id}/stdout.bin>\n`;
|
|
1437
1446
|
}
|
|
1438
1447
|
}
|
|
1439
1448
|
const stderrText = foreground ? resultOrError.stderr : decodeBytesToUtf8(unsafeBytesFromLatin1(resultOrError.stderr));
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@demicodes/shell",
|
|
3
3
|
"description": "Sandboxable bash engine and Host contract for Demi.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.9.0",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
7
7
|
"exports": {
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
}
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@demicodes/utils": "^0.8.0",
|
|
23
22
|
"@demicodes/just-bash": "^3.1.0-demi.2",
|
|
23
|
+
"@demicodes/utils": "^0.9.0",
|
|
24
24
|
"zod": "^4.0.0"
|
|
25
25
|
},
|
|
26
26
|
"license": "Apache-2.0",
|