@demicodes/shell 0.2.1 → 0.3.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 CHANGED
@@ -137,7 +137,7 @@ interface ShellAbortInput {
137
137
  commandId: string;
138
138
  maxOutputBytes?: number;
139
139
  }
140
- interface StreamArtifact {
140
+ interface ShellStreamView {
141
141
  path: string;
142
142
  offset: number;
143
143
  delta: string;
@@ -153,7 +153,7 @@ interface ShellOutputRecordChunk extends ShellOutputChunk {
153
153
  offset: number;
154
154
  bytes: number;
155
155
  }
156
- interface ShellOutputArtifact {
156
+ interface ShellOutputView {
157
157
  path: string;
158
158
  offset: number;
159
159
  text: string;
@@ -194,14 +194,14 @@ interface BinaryStdout {
194
194
  /** Total byte count of the un-capped stream. */
195
195
  totalBytes: number;
196
196
  }
197
- type ShellCommandSnapshot = {
197
+ type ShellCommandStatus = {
198
198
  status: 'exited';
199
199
  shellId: string;
200
200
  commandId: string;
201
201
  exitCode: number;
202
- stdout: StreamArtifact;
203
- stderr: StreamArtifact;
204
- output: ShellOutputArtifact;
202
+ stdout: ShellStreamView;
203
+ stderr: ShellStreamView;
204
+ output: ShellOutputView;
205
205
  runningMs: number;
206
206
  idleMs: number;
207
207
  audit: BashAuditEvent[];
@@ -212,18 +212,18 @@ type ShellCommandSnapshot = {
212
212
  status: 'running';
213
213
  shellId: string;
214
214
  commandId: string;
215
- stdout: StreamArtifact;
216
- stderr: StreamArtifact;
217
- output: ShellOutputArtifact;
215
+ stdout: ShellStreamView;
216
+ stderr: ShellStreamView;
217
+ output: ShellOutputView;
218
218
  runningMs: number;
219
219
  idleMs: number;
220
220
  } | {
221
221
  status: 'aborted';
222
222
  shellId: string;
223
223
  commandId: string;
224
- stdout: StreamArtifact;
225
- stderr: StreamArtifact;
226
- output: ShellOutputArtifact;
224
+ stdout: ShellStreamView;
225
+ stderr: ShellStreamView;
226
+ output: ShellOutputView;
227
227
  runningMs: number;
228
228
  idleMs: number;
229
229
  };
@@ -245,10 +245,10 @@ declare class BashEnvironment {
245
245
  getShell(shellId: string): ShellSession | null;
246
246
  registerCommand(command: Command): void;
247
247
  registeredCommands(): Command[];
248
- exec(input: ShellExecInput): Promise<ShellCommandSnapshot>;
249
- status(input: ShellStatusInput): Promise<ShellCommandSnapshot>;
250
- write(input: ShellWriteInput): Promise<ShellCommandSnapshot>;
251
- abort(input: ShellAbortInput): Promise<ShellCommandSnapshot>;
248
+ exec(input: ShellExecInput): Promise<ShellCommandStatus>;
249
+ status(input: ShellStatusInput): Promise<ShellCommandStatus>;
250
+ write(input: ShellWriteInput): Promise<ShellCommandStatus>;
251
+ abort(input: ShellAbortInput): Promise<ShellCommandStatus>;
252
252
  releaseCommand(commandId: string): Promise<boolean>;
253
253
  disposeShell(shellId: string): Promise<boolean>;
254
254
  disposeAllShells(): Promise<void>;
@@ -272,7 +272,7 @@ declare class BashEnvironment {
272
272
  private finishExited;
273
273
  private collectAborted;
274
274
  private collectAbortedWithoutForeground;
275
- private snapshotCommand;
275
+ private commandStatus;
276
276
  private lookupVirtualArtifact;
277
277
  private commandArtifactIds;
278
278
  private commandArtifact;
@@ -311,4 +311,4 @@ declare function shellQuote(value: string): string;
311
311
  /** Picks a heredoc delimiter that does not collide with any line already in `body`. */
312
312
  declare function heredocDelimiter(body: string): string;
313
313
  //#endregion
314
- 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, ShellCommandSnapshot, ShellExecInput, ShellOutputArtifact, ShellOutputChunk, ShellOutputRecordChunk, ShellStatusInput, ShellWriteInput, StreamArtifact, VirtualFileSystemNode, VirtualFileSystemProvider, emptyStdin, heredocDelimiter, parseCommandInput, renderCommandHelp, runRegisteredCommand, shellQuote, virtualDirectory, virtualFile };
314
+ 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 };
package/dist/index.mjs CHANGED
@@ -847,7 +847,7 @@ var BashEnvironment = class {
847
847
  }
848
848
  async status(input) {
849
849
  const record = this.requireCommand(input.commandId);
850
- return this.snapshotCommand(record, input);
850
+ return this.commandStatus(record, input);
851
851
  }
852
852
  async write(input) {
853
853
  const record = this.requireCommand(input.commandId);
@@ -857,11 +857,11 @@ var BashEnvironment = class {
857
857
  const data = typeof input.stdin === "string" ? encodeUtf8(input.stdin) : input.stdin;
858
858
  if (data.byteLength === 0) throw new Error("shell_write field \"stdin\" must not be empty; use shell_status to poll");
859
859
  await foreground.handle.writeStdin(data);
860
- return this.snapshotCommand(record, input);
860
+ return this.commandStatus(record, input);
861
861
  }
862
862
  async abort(input) {
863
863
  const record = this.requireCommand(input.commandId);
864
- if (record.status !== "running") return this.snapshotCommand(record, input);
864
+ if (record.status !== "running") return this.commandStatus(record, input);
865
865
  const session = this.requireShell(record.shellId);
866
866
  const foreground = this.requireForegroundCommand(session, record.id);
867
867
  foreground.abortController.abort();
@@ -1078,7 +1078,7 @@ var BashEnvironment = class {
1078
1078
  record.exitCode = 2;
1079
1079
  session.state.lastExitCode = 2;
1080
1080
  session.activeCommandId = void 0;
1081
- return this.snapshotCommand(record, input);
1081
+ return this.commandStatus(record, input);
1082
1082
  }
1083
1083
  throw error;
1084
1084
  }
@@ -1243,7 +1243,7 @@ var BashEnvironment = class {
1243
1243
  foreground = outcome.foreground;
1244
1244
  continue;
1245
1245
  }
1246
- if (outcome.kind === "timeout") return this.snapshotCommand(record, input);
1246
+ if (outcome.kind === "timeout") return this.commandStatus(record, input);
1247
1247
  if (outcome.kind === "aborted") {
1248
1248
  const activeForeground = foreground ?? session.foreground;
1249
1249
  if (!activeForeground) return this.collectAbortedWithoutForeground(session, record, input);
@@ -1389,7 +1389,7 @@ var BashEnvironment = class {
1389
1389
  };
1390
1390
  }
1391
1391
  collectExited(session, record, resultOrError, foreground, input = {}) {
1392
- if (record.status !== "running") return this.snapshotCommand(record, input);
1392
+ if (record.status !== "running") return this.commandStatus(record, input);
1393
1393
  if (resultOrError instanceof Error) {
1394
1394
  if (resultOrError instanceof ExitError) {
1395
1395
  session.exited = true;
@@ -1476,10 +1476,10 @@ var BashEnvironment = class {
1476
1476
  record.commandMetadata = [...session.accumulator.commandMetadata];
1477
1477
  session.pendingExec = void 0;
1478
1478
  if (session.activeCommandId === record.id) session.activeCommandId = void 0;
1479
- return this.snapshotCommand(record, input);
1479
+ return this.commandStatus(record, input);
1480
1480
  }
1481
1481
  async collectAborted(session, record, foreground, input = {}) {
1482
- if (record.status !== "running") return this.snapshotCommand(record, input);
1482
+ if (record.status !== "running") return this.commandStatus(record, input);
1483
1483
  foreground.abortController.abort();
1484
1484
  foreground.handle.kill("SIGTERM").catch(() => {});
1485
1485
  await flushForegroundSinks(session, foreground);
@@ -1491,10 +1491,10 @@ var BashEnvironment = class {
1491
1491
  session.foreground = void 0;
1492
1492
  session.pendingExec = void 0;
1493
1493
  if (session.activeCommandId === record.id) session.activeCommandId = void 0;
1494
- return this.snapshotCommand(record, input);
1494
+ return this.commandStatus(record, input);
1495
1495
  }
1496
1496
  collectAbortedWithoutForeground(session, record, input = {}) {
1497
- if (record.status !== "running") return this.snapshotCommand(record, input);
1497
+ if (record.status !== "running") return this.commandStatus(record, input);
1498
1498
  session.abortController?.abort();
1499
1499
  session.pendingExec = void 0;
1500
1500
  if (session.activeCommandId === record.id) session.activeCommandId = void 0;
@@ -1506,9 +1506,9 @@ var BashEnvironment = class {
1506
1506
  }
1507
1507
  record.lastOutputAt = Date.now();
1508
1508
  record.status = "aborted";
1509
- return this.snapshotCommand(record, input);
1509
+ return this.commandStatus(record, input);
1510
1510
  }
1511
- snapshotCommand(record, input = {}) {
1511
+ commandStatus(record, input = {}) {
1512
1512
  const foreground = this.shells.get(record.shellId)?.foreground;
1513
1513
  if (record.status === "running" && foreground?.commandId === record.id) {
1514
1514
  record.stdout = foreground.stdoutBuffer;
@@ -1517,9 +1517,9 @@ var BashEnvironment = class {
1517
1517
  record.lastOutputAt = foreground.lastOutputAt;
1518
1518
  }
1519
1519
  const maxOutputBytes = input.maxOutputBytes ?? this.defaultOutputLimitBytes;
1520
- const stdout = streamArtifact(record, "stdout", input.stdoutOffset, maxOutputBytes);
1521
- const stderr = streamArtifact(record, "stderr", input.stderrOffset, maxOutputBytes);
1522
- const output = streamOutputArtifact(record, input.outputOffset, maxOutputBytes);
1520
+ const stdout = streamView(record, "stdout", input.stdoutOffset, maxOutputBytes);
1521
+ const stderr = streamView(record, "stderr", input.stderrOffset, maxOutputBytes);
1522
+ const output = mergedOutputView(record, input.outputOffset, maxOutputBytes);
1523
1523
  const base = {
1524
1524
  shellId: record.shellId,
1525
1525
  commandId: record.id,
@@ -1590,16 +1590,16 @@ var BashEnvironment = class {
1590
1590
  const record = this.commandsById.get(commandId);
1591
1591
  if (record?.commandScopeId === scopeId) {
1592
1592
  this.syncRunningRecord(record);
1593
- return persistedArtifactFromRecord(record);
1593
+ return commandArtifactFromRecord(record);
1594
1594
  }
1595
1595
  const value = await this.artifacts.storageFor(scopeId).readJson(`commands/${commandId}/artifact.json`).catch(() => null);
1596
- return isPersistedShellCommandArtifact(value) ? value : null;
1596
+ return isCommandArtifact(value) ? value : null;
1597
1597
  }
1598
1598
  persistCommandArtifact(record) {
1599
1599
  const fingerprint = `${record.status}:${record.exitCode ?? ""}:${record.stdout.length}:${record.stderr.length}:${record.binaryStdout?.totalBytes ?? ""}`;
1600
1600
  if (record.persistedFingerprint === fingerprint) return;
1601
1601
  record.persistedFingerprint = fingerprint;
1602
- this.artifacts.persist(record.commandScopeId, record.id, persistedArtifactFromRecord(record));
1602
+ this.artifacts.persist(record.commandScopeId, record.id, commandArtifactFromRecord(record));
1603
1603
  }
1604
1604
  syncRunningRecord(record) {
1605
1605
  const foreground = this.shells.get(record.shellId)?.foreground;
@@ -1636,7 +1636,7 @@ function normalizeTimeoutMs(value) {
1636
1636
  if (!Number.isFinite(value) || value < 1 || value > 6e5) throw new Error(`timeoutMs must be between 1 and ${MAX_TIMEOUT_MS}`);
1637
1637
  return Math.floor(value);
1638
1638
  }
1639
- function streamArtifact(record, stream, explicitOffset, maxOutputBytes) {
1639
+ function streamView(record, stream, explicitOffset, maxOutputBytes) {
1640
1640
  const text = stream === "stdout" ? record.stdout : record.stderr;
1641
1641
  const totalBytes = utf8Bytes(text);
1642
1642
  const boundedOffset = clampOffset(explicitOffset ?? (stream === "stdout" ? record.stdoutOffset : record.stderrOffset), totalBytes);
@@ -1656,7 +1656,7 @@ function streamArtifact(record, stream, explicitOffset, maxOutputBytes) {
1656
1656
  truncated
1657
1657
  };
1658
1658
  }
1659
- function streamOutputArtifact(record, explicitOffset, maxOutputBytes) {
1659
+ function mergedOutputView(record, explicitOffset, maxOutputBytes) {
1660
1660
  const totalBytes = record.outputChunks.reduce((total, chunk) => total + chunk.bytes, 0);
1661
1661
  const offset = clampOffset(explicitOffset ?? record.outputOffset, totalBytes);
1662
1662
  const byteLimit = Math.max(0, Math.floor(maxOutputBytes));
@@ -1710,7 +1710,7 @@ function ensureRecordOutputCoverage(record) {
1710
1710
  appendRecordOutput(record, "stdout", record.stdout);
1711
1711
  appendRecordOutput(record, "stderr", record.stderr);
1712
1712
  }
1713
- function persistedArtifactFromRecord(record) {
1713
+ function commandArtifactFromRecord(record) {
1714
1714
  return {
1715
1715
  status: record.status,
1716
1716
  shellId: record.shellId,
@@ -1754,7 +1754,7 @@ function commandArtifactMeta(artifact) {
1754
1754
  } } : {}
1755
1755
  };
1756
1756
  }
1757
- function isPersistedShellCommandArtifact(value) {
1757
+ function isCommandArtifact(value) {
1758
1758
  if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
1759
1759
  const record = value;
1760
1760
  return (record.status === "running" || record.status === "exited" || record.status === "aborted") && typeof record.shellId === "string" && typeof record.commandId === "string" && typeof record.startedAt === "number" && typeof record.lastOutputAt === "number" && (typeof record.exitCode === "number" || record.exitCode === null) && typeof record.stdout === "string" && typeof record.stderr === "string";
package/dist/storage.mjs CHANGED
@@ -5,7 +5,7 @@ var AgentSessionCommandStorage = class {
5
5
  constructor(store, agentSessionId) {
6
6
  this.store = store;
7
7
  validateAgentSessionId(agentSessionId);
8
- this.agentSessionPrefix = `${agentSessionId}/`;
8
+ this.agentSessionPrefix = `agent-sessions/${agentSessionId}/`;
9
9
  }
10
10
  readJson(key) {
11
11
  return this.store.readJson(this.key(key));
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.2.1",
4
+ "version": "0.3.0",
5
5
  "private": false,
6
6
  "type": "module",
7
7
  "exports": {
@@ -22,8 +22,8 @@
22
22
  }
23
23
  },
24
24
  "dependencies": {
25
- "@demicodes/utils": "^0.2.1",
26
- "@demicodes/just-bash": "^3.0.1-demi.5",
25
+ "@demicodes/utils": "workspace:^",
26
+ "@demicodes/just-bash": "workspace:^",
27
27
  "zod": "^4.0.0"
28
28
  },
29
29
  "license": "Apache-2.0",