@demicodes/shell 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.
- package/dist/host-fs.d.mts +16 -3
- package/dist/host-fs.mjs +10 -5
- package/dist/index.d.mts +23 -2
- package/dist/index.mjs +42 -10
- package/package.json +2 -2
package/dist/host-fs.d.mts
CHANGED
|
@@ -15,14 +15,27 @@ type VirtualFileSystemNode = {
|
|
|
15
15
|
interface VirtualFileSystemProvider {
|
|
16
16
|
lookup(path: string): Promise<VirtualFileSystemNode | null> | VirtualFileSystemNode | null;
|
|
17
17
|
}
|
|
18
|
+
interface HostBackedFileSystemOptions {
|
|
19
|
+
lookup?: VirtualFileSystemProvider['lookup'];
|
|
20
|
+
/**
|
|
21
|
+
* Ceiling for a single file read through this filesystem. Portable commands
|
|
22
|
+
* (cat/grep/rg/head/...) run in-process and load files whole, so one read of
|
|
23
|
+
* an oversized file becomes resident memory in the embedding host — a broad
|
|
24
|
+
* scan over a large tree can balloon the process by gigabytes. Oversized
|
|
25
|
+
* files fail loudly instead; real-process routes (`bash -c`) stay available
|
|
26
|
+
* for genuinely large files.
|
|
27
|
+
*/
|
|
28
|
+
maxFileReadBytes?: number;
|
|
29
|
+
}
|
|
18
30
|
/** Builds a virtual directory node; entry names containing a dot are treated as files. */
|
|
19
31
|
declare function virtualDirectory(names: string[]): VirtualFileSystemNode;
|
|
20
32
|
/** Builds a virtual file node from raw bytes. */
|
|
21
33
|
declare function virtualFile(content: Uint8Array): VirtualFileSystemNode;
|
|
22
34
|
declare class HostBackedFileSystem implements IFileSystem {
|
|
23
35
|
private readonly host;
|
|
24
|
-
private readonly
|
|
25
|
-
|
|
36
|
+
private readonly options;
|
|
37
|
+
private readonly maxFileReadBytes;
|
|
38
|
+
constructor(host: Host, options?: HostBackedFileSystemOptions);
|
|
26
39
|
readFile(path: string, options?: ReadFileOptions | BufferEncoding): Promise<string>;
|
|
27
40
|
readFileBuffer(path: string): Promise<Uint8Array>;
|
|
28
41
|
writeFile(path: string, content: FileContent, options?: WriteFileOptions | BufferEncoding): Promise<void>;
|
|
@@ -48,4 +61,4 @@ declare class HostBackedFileSystem implements IFileSystem {
|
|
|
48
61
|
private assertWritablePath;
|
|
49
62
|
}
|
|
50
63
|
//#endregion
|
|
51
|
-
export { HostBackedFileSystem, VirtualFileSystemNode, VirtualFileSystemProvider, virtualDirectory, virtualFile };
|
|
64
|
+
export { HostBackedFileSystem, HostBackedFileSystemOptions, VirtualFileSystemNode, VirtualFileSystemProvider, virtualDirectory, virtualFile };
|
package/dist/host-fs.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { decodeUtf8, encodeUtf8, isAbsolutePath, normalizePath } from "@demicodes/utils";
|
|
2
2
|
//#region src/host-fs.ts
|
|
3
|
+
const DEFAULT_FILE_READ_LIMIT_BYTES = 67108864;
|
|
3
4
|
/** Builds a virtual directory node; entry names containing a dot are treated as files. */
|
|
4
5
|
function virtualDirectory(names) {
|
|
5
6
|
return {
|
|
@@ -21,10 +22,12 @@ function virtualFile(content) {
|
|
|
21
22
|
}
|
|
22
23
|
var HostBackedFileSystem = class {
|
|
23
24
|
host;
|
|
24
|
-
|
|
25
|
-
|
|
25
|
+
options;
|
|
26
|
+
maxFileReadBytes;
|
|
27
|
+
constructor(host, options = {}) {
|
|
26
28
|
this.host = host;
|
|
27
|
-
this.
|
|
29
|
+
this.options = options;
|
|
30
|
+
this.maxFileReadBytes = options.maxFileReadBytes ?? DEFAULT_FILE_READ_LIMIT_BYTES;
|
|
28
31
|
}
|
|
29
32
|
async readFile(path, options) {
|
|
30
33
|
return decodeBytes(await this.readFileBuffer(path), encodingFrom(options));
|
|
@@ -35,6 +38,8 @@ var HostBackedFileSystem = class {
|
|
|
35
38
|
if (virtual.kind !== "file") throw new Error(`EISDIR: illegal operation on a directory, read '${path}'`);
|
|
36
39
|
return virtual.content;
|
|
37
40
|
}
|
|
41
|
+
const stat = await this.host.fs.stat(path, { cwd: this.host.defaultCwd });
|
|
42
|
+
if (stat.isFile && stat.size > this.maxFileReadBytes) throw new Error(`EFBIG: file exceeds the ${this.maxFileReadBytes}-byte in-shell read limit (${stat.size} bytes), read '${path}'; read a slice instead, or process it with a real process via 'bash -c'`);
|
|
38
43
|
return this.host.fs.readFile(path, { cwd: this.host.defaultCwd });
|
|
39
44
|
}
|
|
40
45
|
async writeFile(path, content, options) {
|
|
@@ -151,8 +156,8 @@ var HostBackedFileSystem = class {
|
|
|
151
156
|
await this.host.fs.utimes(path, atime, mtime, { cwd: this.host.defaultCwd });
|
|
152
157
|
}
|
|
153
158
|
async lookupVirtual(path) {
|
|
154
|
-
if (!this.
|
|
155
|
-
return await this.
|
|
159
|
+
if (!this.options.lookup || !isVirtualPath(path)) return null;
|
|
160
|
+
return await this.options.lookup(normalizePath(path)) ?? null;
|
|
156
161
|
}
|
|
157
162
|
assertWritablePath(path) {
|
|
158
163
|
if (isVirtualPath(path)) throw new Error(`EROFS: read-only virtual filesystem, '${path}'`);
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as HostProcess, c as HostSpawnHandle, i as HostFileSystem, l as HostSpawnParams, n as HostDirent, o as HostProcessOutputChunk, r as HostFileStat, s as HostSpawnExit, t as Host, u as HostStore } from "./host-DIg4RxcL.mjs";
|
|
2
|
-
import { HostBackedFileSystem, VirtualFileSystemNode, VirtualFileSystemProvider, virtualDirectory, virtualFile } from "./host-fs.mjs";
|
|
2
|
+
import { HostBackedFileSystem, HostBackedFileSystemOptions, VirtualFileSystemNode, VirtualFileSystemProvider, virtualDirectory, virtualFile } from "./host-fs.mjs";
|
|
3
3
|
import { _ as runRegisteredCommand, a as CommandIO, c as CommandRegistry, d as CommandStdin, f as CommandStorage, g as renderCommandHelp, h as parseCommandInput, i as CommandExecutionContext, l as CommandRunContext, m as emptyStdin, n as COMMAND_HELP_DEFAULTS, o as CommandInputSpec, p as ParsedCommandInput, r as Command, s as CommandOutputSpec, t as AgentSessionCommandStorage, u as CommandRunResult } from "./storage-CNMBL9_j.mjs";
|
|
4
4
|
import { CommandName } from "@demicodes/just-bash/commands";
|
|
5
5
|
import { Interpreter, InterpreterState } from "@demicodes/just-bash/interpreter";
|
|
@@ -38,6 +38,9 @@ interface BackgroundJob {
|
|
|
38
38
|
handle: HostSpawnHandle;
|
|
39
39
|
stdoutBuffer: string;
|
|
40
40
|
stderrBuffer: string;
|
|
41
|
+
/** Chars discarded from the head of each buffer once it outgrew the capture limit. */
|
|
42
|
+
droppedStdoutChars: number;
|
|
43
|
+
droppedStderrChars: number;
|
|
41
44
|
stdoutPump: Promise<void>;
|
|
42
45
|
stderrPump: Promise<void>;
|
|
43
46
|
exitPromise: Promise<{
|
|
@@ -66,6 +69,10 @@ interface ForegroundProcess {
|
|
|
66
69
|
/** Interleaved visible chunks with running byte offsets, for merged replay. */
|
|
67
70
|
outputChunks: ShellOutputRecordChunk[];
|
|
68
71
|
outputBytes: number;
|
|
72
|
+
/** Total bytes ingested across both streams; the capture limit judges this. */
|
|
73
|
+
capturedBytes: number;
|
|
74
|
+
/** Set when the capture limit was breached: the process is killed and further chunks dropped. */
|
|
75
|
+
captureOverflowed: boolean;
|
|
69
76
|
audit: BashAuditEvent[];
|
|
70
77
|
stdoutPump: Promise<void>;
|
|
71
78
|
stderrPump: Promise<void>;
|
|
@@ -106,6 +113,19 @@ interface BashEnvironmentOptions {
|
|
|
106
113
|
* above, where models are known.
|
|
107
114
|
*/
|
|
108
115
|
maxBinaryBytes?: number;
|
|
116
|
+
/**
|
|
117
|
+
* Ceiling for the bytes a single command's output capture may ingest.
|
|
118
|
+
*
|
|
119
|
+
* Distinct from `maxOutputBytes`, which sizes the rendered view: capture is
|
|
120
|
+
* what the environment holds in memory while a command runs, and it holds
|
|
121
|
+
* several copies (raw bytes for the pipe, text renders, replay chunks). A
|
|
122
|
+
* foreground process that produces more than this is SIGKILLed and the
|
|
123
|
+
* command fails with an explicit error; a background job keeps only the most
|
|
124
|
+
* recent bytes within the ceiling. Without this ceiling one stray
|
|
125
|
+
* `rg`/`cat` over a large tree balloons the embedding process by tens of
|
|
126
|
+
* gigabytes until the kernel OOM-kills it.
|
|
127
|
+
*/
|
|
128
|
+
maxCaptureBytes?: number;
|
|
109
129
|
}
|
|
110
130
|
interface ShellExecInput {
|
|
111
131
|
script: string;
|
|
@@ -246,6 +266,7 @@ declare class BashEnvironment {
|
|
|
246
266
|
private readonly initialEnv;
|
|
247
267
|
private readonly defaultOutputLimitBytes;
|
|
248
268
|
private readonly defaultBinaryLimitBytes;
|
|
269
|
+
private readonly captureLimitBytes;
|
|
249
270
|
private readonly shells;
|
|
250
271
|
private readonly defaultShellByAgentSessionId;
|
|
251
272
|
private readonly commandsById;
|
|
@@ -321,4 +342,4 @@ declare function shellQuote(value: string): string;
|
|
|
321
342
|
/** Picks a heredoc delimiter that does not collide with any line already in `body`. */
|
|
322
343
|
declare function heredocDelimiter(body: string): string;
|
|
323
344
|
//#endregion
|
|
324
|
-
export { AgentSessionCommandStorage, BashAuditEvent, BashEnvironment, BashEnvironmentOptions, BinaryStdout, COMMAND_HELP_DEFAULTS, Command, CommandExecutionContext, CommandIO, CommandInputSpec, CommandMetadataRecord, CommandOutputSpec, CommandRegistry, CommandRunContext, CommandRunResult, CommandStdin, CommandStorage, DEMI_PORTABLE_COMMANDS, Host, HostBackedFileSystem, HostDirent, HostFileStat, HostFileSystem, HostProcess, HostProcessOutputChunk, HostSpawnExit, HostSpawnHandle, HostSpawnParams, HostStore, MAX_TIMEOUT_MS, ParsedCommandInput, RESERVED_COMMAND_NAMES, ShellAbortInput, ShellCommandStatus, ShellExecInput, ShellOutputChunk, ShellOutputRecordChunk, ShellOutputView, ShellStatusInput, ShellStreamView, ShellWriteInput, VirtualFileSystemNode, VirtualFileSystemProvider, emptyStdin, heredocDelimiter, parseCommandInput, renderCommandHelp, runRegisteredCommand, shellQuote, virtualDirectory, virtualFile };
|
|
345
|
+
export { AgentSessionCommandStorage, BashAuditEvent, BashEnvironment, BashEnvironmentOptions, BinaryStdout, COMMAND_HELP_DEFAULTS, Command, CommandExecutionContext, CommandIO, CommandInputSpec, CommandMetadataRecord, CommandOutputSpec, CommandRegistry, CommandRunContext, CommandRunResult, CommandStdin, CommandStorage, DEMI_PORTABLE_COMMANDS, Host, HostBackedFileSystem, HostBackedFileSystemOptions, HostDirent, HostFileStat, HostFileSystem, HostProcess, HostProcessOutputChunk, HostSpawnExit, HostSpawnHandle, HostSpawnParams, HostStore, MAX_TIMEOUT_MS, ParsedCommandInput, RESERVED_COMMAND_NAMES, ShellAbortInput, ShellCommandStatus, ShellExecInput, ShellOutputChunk, ShellOutputRecordChunk, ShellOutputView, ShellStatusInput, ShellStreamView, ShellWriteInput, VirtualFileSystemNode, VirtualFileSystemProvider, emptyStdin, heredocDelimiter, parseCommandInput, renderCommandHelp, runRegisteredCommand, shellQuote, virtualDirectory, virtualFile };
|
package/dist/index.mjs
CHANGED
|
@@ -501,7 +501,16 @@ function createOutputSinks(fs, cwd, redirections) {
|
|
|
501
501
|
}
|
|
502
502
|
return routes;
|
|
503
503
|
}
|
|
504
|
-
function recordForegroundChunk(foreground, sourceFd, chunk) {
|
|
504
|
+
function recordForegroundChunk(foreground, sourceFd, chunk, captureLimitBytes) {
|
|
505
|
+
if (foreground.captureOverflowed) return;
|
|
506
|
+
if (foreground.capturedBytes + chunk.byteLength > captureLimitBytes) {
|
|
507
|
+
foreground.captureOverflowed = true;
|
|
508
|
+
foreground.rawStdoutBuffer = "";
|
|
509
|
+
foreground.rawStdoutBytes = [];
|
|
510
|
+
foreground.handle.kill("SIGKILL").catch(() => {});
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
foreground.capturedBytes += chunk.byteLength;
|
|
505
514
|
const text = decodeUtf8(chunk);
|
|
506
515
|
foreground.lastOutputAt = Date.now();
|
|
507
516
|
if (sourceFd === 1) {
|
|
@@ -778,6 +787,13 @@ const DEFAULT_OUTPUT_LIMIT_BYTES = 1048576;
|
|
|
778
787
|
* while still bounding a runaway producer.
|
|
779
788
|
*/
|
|
780
789
|
const DEFAULT_BINARY_LIMIT_BYTES = 16777216;
|
|
790
|
+
/**
|
|
791
|
+
* Ceiling for a single command's in-memory output capture. Sized to the same
|
|
792
|
+
* order as the in-shell file read limit: the execution model buffers whole
|
|
793
|
+
* command outputs (in several copies), so this is a hard memory-safety bound
|
|
794
|
+
* on the embedding process, not a view budget.
|
|
795
|
+
*/
|
|
796
|
+
const DEFAULT_CAPTURE_LIMIT_BYTES = 67108864;
|
|
781
797
|
/** Upper bound for a single exec observation window (also the command-bridge wait ceiling). */
|
|
782
798
|
const MAX_TIMEOUT_MS = 6e5;
|
|
783
799
|
var BashEnvironment = class {
|
|
@@ -788,6 +804,7 @@ var BashEnvironment = class {
|
|
|
788
804
|
initialEnv;
|
|
789
805
|
defaultOutputLimitBytes;
|
|
790
806
|
defaultBinaryLimitBytes;
|
|
807
|
+
captureLimitBytes;
|
|
791
808
|
shells = /* @__PURE__ */ new Map();
|
|
792
809
|
defaultShellByAgentSessionId = /* @__PURE__ */ new Map();
|
|
793
810
|
commandsById = /* @__PURE__ */ new Map();
|
|
@@ -801,6 +818,7 @@ var BashEnvironment = class {
|
|
|
801
818
|
this.initialEnv = options.initialEnv ?? {};
|
|
802
819
|
this.defaultOutputLimitBytes = options.maxOutputBytes ?? DEFAULT_OUTPUT_LIMIT_BYTES;
|
|
803
820
|
this.defaultBinaryLimitBytes = options.maxBinaryBytes ?? DEFAULT_BINARY_LIMIT_BYTES;
|
|
821
|
+
this.captureLimitBytes = options.maxCaptureBytes ?? DEFAULT_CAPTURE_LIMIT_BYTES;
|
|
804
822
|
}
|
|
805
823
|
getShell(shellId) {
|
|
806
824
|
return this.shells.get(shellId) ?? null;
|
|
@@ -1025,7 +1043,7 @@ var BashEnvironment = class {
|
|
|
1025
1043
|
for (const command of this.commands.list()) forkCommands.set(command.name, commandToForkCommand(session, command, storage, this.host));
|
|
1026
1044
|
session.abortController = new AbortController();
|
|
1027
1045
|
const limits = resolveLimits({
|
|
1028
|
-
maxOutputSize:
|
|
1046
|
+
maxOutputSize: this.captureLimitBytes,
|
|
1029
1047
|
maxCommandCount: 1e6,
|
|
1030
1048
|
maxLoopIterations: 1e6,
|
|
1031
1049
|
maxCallDepth: 1e3,
|
|
@@ -1135,15 +1153,26 @@ var BashEnvironment = class {
|
|
|
1135
1153
|
handle,
|
|
1136
1154
|
stdoutBuffer: "",
|
|
1137
1155
|
stderrBuffer: "",
|
|
1156
|
+
droppedStdoutChars: 0,
|
|
1157
|
+
droppedStderrChars: 0,
|
|
1138
1158
|
stdoutPump: Promise.resolve(),
|
|
1139
1159
|
stderrPump: Promise.resolve(),
|
|
1140
1160
|
exitPromise: handle.wait()
|
|
1141
1161
|
};
|
|
1162
|
+
const retainLimit = this.defaultOutputLimitBytes;
|
|
1142
1163
|
job.stdoutPump = pumpStream(handle.stdout, (chunk) => {
|
|
1143
1164
|
job.stdoutBuffer += decodeUtf8(chunk);
|
|
1165
|
+
if (job.stdoutBuffer.length > retainLimit) {
|
|
1166
|
+
job.droppedStdoutChars += job.stdoutBuffer.length - retainLimit;
|
|
1167
|
+
job.stdoutBuffer = job.stdoutBuffer.slice(-retainLimit);
|
|
1168
|
+
}
|
|
1144
1169
|
});
|
|
1145
1170
|
job.stderrPump = pumpStream(handle.stderr, (chunk) => {
|
|
1146
1171
|
job.stderrBuffer += decodeUtf8(chunk);
|
|
1172
|
+
if (job.stderrBuffer.length > retainLimit) {
|
|
1173
|
+
job.droppedStderrChars += job.stderrBuffer.length - retainLimit;
|
|
1174
|
+
job.stderrBuffer = job.stderrBuffer.slice(-retainLimit);
|
|
1175
|
+
}
|
|
1147
1176
|
});
|
|
1148
1177
|
session.backgroundJobs.set(id, job);
|
|
1149
1178
|
session.state.lastBackgroundPid = id;
|
|
@@ -1191,7 +1220,8 @@ var BashEnvironment = class {
|
|
|
1191
1220
|
await Promise.allSettled([job.stdoutPump, job.stderrPump]);
|
|
1192
1221
|
session.backgroundJobs.delete(id);
|
|
1193
1222
|
const exitCode = exit.exitCode ?? 127;
|
|
1194
|
-
const
|
|
1223
|
+
const stdout = job.droppedStdoutChars > 0 ? `[... dropped ${job.droppedStdoutChars} chars of earlier stdout over the capture limit ...]\n${job.stdoutBuffer}` : job.stdoutBuffer;
|
|
1224
|
+
const stderr = exit.exitCode === null && job.stderrBuffer.length === 0 ? `${job.command}: ${exit.signal ?? "command not found"}\n` : job.droppedStderrChars > 0 ? `[... dropped ${job.droppedStderrChars} chars of earlier stderr over the capture limit ...]\n${job.stderrBuffer}` : job.stderrBuffer;
|
|
1195
1225
|
session.accumulator.audit.push({
|
|
1196
1226
|
kind: "system-command",
|
|
1197
1227
|
name: job.command,
|
|
@@ -1200,7 +1230,7 @@ var BashEnvironment = class {
|
|
|
1200
1230
|
exitCode
|
|
1201
1231
|
});
|
|
1202
1232
|
return {
|
|
1203
|
-
stdout
|
|
1233
|
+
stdout,
|
|
1204
1234
|
stderr,
|
|
1205
1235
|
exitCode
|
|
1206
1236
|
};
|
|
@@ -1321,6 +1351,8 @@ var BashEnvironment = class {
|
|
|
1321
1351
|
stderrBuffer: "",
|
|
1322
1352
|
outputChunks: [],
|
|
1323
1353
|
outputBytes: 0,
|
|
1354
|
+
capturedBytes: 0,
|
|
1355
|
+
captureOverflowed: false,
|
|
1324
1356
|
audit: [{
|
|
1325
1357
|
kind: "system-command",
|
|
1326
1358
|
name: command,
|
|
@@ -1340,18 +1372,18 @@ var BashEnvironment = class {
|
|
|
1340
1372
|
if (opts.stdinProvided) await handle.closeStdin();
|
|
1341
1373
|
if (handle.output) {
|
|
1342
1374
|
foreground.stdoutPump = pumpOutputStream(handle.output, (chunk) => {
|
|
1343
|
-
recordForegroundChunk(foreground, chunk.stream === "stdout" ? 1 : 2, chunk.chunk);
|
|
1375
|
+
recordForegroundChunk(foreground, chunk.stream === "stdout" ? 1 : 2, chunk.chunk, this.captureLimitBytes);
|
|
1344
1376
|
});
|
|
1345
1377
|
foreground.stderrPump = Promise.resolve();
|
|
1346
1378
|
} else {
|
|
1347
|
-
foreground.stdoutPump = pumpStream(handle.stdout, (chunk) => recordForegroundChunk(foreground, 1, chunk));
|
|
1348
|
-
foreground.stderrPump = pumpStream(handle.stderr, (chunk) => recordForegroundChunk(foreground, 2, chunk));
|
|
1379
|
+
foreground.stdoutPump = pumpStream(handle.stdout, (chunk) => recordForegroundChunk(foreground, 1, chunk, this.captureLimitBytes));
|
|
1380
|
+
foreground.stderrPump = pumpStream(handle.stderr, (chunk) => recordForegroundChunk(foreground, 2, chunk, this.captureLimitBytes));
|
|
1349
1381
|
}
|
|
1350
1382
|
const exit = await foreground.exitPromise;
|
|
1351
1383
|
await Promise.allSettled([foreground.stdoutPump, foreground.stderrPump]);
|
|
1352
|
-
const stdout = decodeLatin1(concatBytes(foreground.rawStdoutBytes));
|
|
1353
|
-
const exitCode = exit.exitCode ?? 127;
|
|
1354
|
-
const stderr = exit.exitCode === null && foreground.rawStderrBuffer.length === 0 ? `${command}: ${exit.signal ?? "command not found"}\n` : foreground.rawStderrBuffer;
|
|
1384
|
+
const stdout = foreground.captureOverflowed ? "" : decodeLatin1(concatBytes(foreground.rawStdoutBytes));
|
|
1385
|
+
const exitCode = foreground.captureOverflowed ? 137 : exit.exitCode ?? 127;
|
|
1386
|
+
const stderr = foreground.captureOverflowed ? `${command}: output exceeded the ${this.captureLimitBytes}-byte capture limit and the process was killed; the shell buffers whole command outputs in memory — narrow the output at the source (filters, head, tighter paths)\n` : exit.exitCode === null && foreground.rawStderrBuffer.length === 0 ? `${command}: ${exit.signal ?? "command not found"}\n` : foreground.rawStderrBuffer;
|
|
1355
1387
|
foreground.audit[0] = {
|
|
1356
1388
|
kind: "system-command",
|
|
1357
1389
|
name: command,
|
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.14.
|
|
4
|
+
"version": "0.14.2",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
7
7
|
"exports": {
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"@demicodes/just-bash": "^3.0.1-demi.5",
|
|
23
|
-
"@demicodes/utils": "^0.14.
|
|
23
|
+
"@demicodes/utils": "^0.14.2",
|
|
24
24
|
"zod": "^4.0.0"
|
|
25
25
|
},
|
|
26
26
|
"license": "Apache-2.0",
|