Liking cljdoc? Tell your friends :D

com.blockether.vis.internal.foundation.shell

shell/ compatibility extension — a DROPPABLE classpath plug-in (drop the jar, drop the feature). Bound only when the user-owned shell toggle is ON (default ON; flip it OFF in Settings or in vis.yml via toggles: {shell: false} to drop the tools). The OS process jail is the containment layer while active.

ONE model-facing entry point — the shell PYTHON verb, bound BARE in the flat sandbox next to ls / grep, and NO native tool: a process is started from Python and nowhere else, because every verb after the spawn is a method on the handle the call returns. EVERY run is a background run: the call spawns under a real pty and returns the HANDLE now, so there is no wait on the request and no number that can select a second mode. ONE call runs ONE command: an ordered batch was a second budget, a second result shape and a second failure mode for what && already says.

  1. sh = await shell("ls")bash -lc in the workspace root, spawned under a REAL pty, its merged output streamed verbatim to a log FILE and registered as a session RESOURCE. sh.wait(30) is what fills exit/stdout. Output is bounded at READ time to a head+tail budget per stream, so only the MIDDLE of a huge stream is dropped, never its start or end. A non-zero exit is DATA the model reads, not an error.

  2. A server, watcher or long build is the SAME call — you simply do not wait for it, or you wait for less than it takes. A wait that expires is never a lost process: it keeps running under its id and its log keeps filling.

  3. The log OUTLIVES the run. Every shell keeps its log file and its index row by id for as long as the session does, so "what did that build print" is answerable a turn later from the id alone. That retention is the feature, not a leak to reap.

The result IS the HANDLE: every shell answer is a dict-with-methods in the sandbox, so the process is driven on the object the call already returned — sh.logs(-50) reads the last 50 LINES (or a byte OFFSET) and returns NOW, sh.wait(30) is the bounded poll loop written once in the engine, sh.type("y") types into the pty and sh.stop() kills the tree. There are no id-taking verbs to re-type an id into; re-issuing a LIVE id gives the same handle back.

STATUS is not a stage of its own: EVERY answer of EVERY stage already says what the shell is doing — status/exit, started_at/finished_at/uptime_ms, log_path, and the live cpu_ms/cpu_percent/rss_bytes of its process tree — so "is it done yet" is read off the result already in hand and never costs a second call.

shell-dispatch survives as the INTERNAL grammar the Python-extension entry points use, since those hand-author an options map and genuinely need an op.

EVERY result of EVERY stage — including an argv run, which uses the same runner — is the one [[shell-result-base]] key set: stage names the producer and is the only thing that varies. A key a stage has nothing to say about is nil / false / 0 instead of absent, so model Python indexes any of them without a KeyError, and a run answers with its command and that command's own bytes at the TOP level — there is no entry to unwrap and no second shape to learn.

The shell toggle is registered HERE, extension-owned under the vis namespace. It closes the MODEL's door only: an installed extension keeps its own trusted process boundary (vis.shell, subprocess), which the toggle does not gate.

`shell/` compatibility extension — a DROPPABLE classpath plug-in (drop the
jar, drop the feature). Bound only when the user-owned `shell` toggle is ON
(default ON; flip it OFF in Settings or in `vis.yml` via `toggles: {shell: false}`
to drop the tools). The OS process jail is the containment layer while active.

ONE model-facing entry point — the `shell` PYTHON verb, bound BARE in the flat
sandbox next to `ls` / `grep`, and NO native tool: a process is started from
Python and nowhere else, because every verb after the spawn is a method on the
handle the call returns. EVERY run is a background run: the call spawns
under a real pty and returns the HANDLE now, so there is no `wait` on the
request and no number that can select a second mode. ONE call runs ONE command:
an ordered batch was a second budget, a second result shape and a second failure
mode for what `&&` already says.

1. `sh = await shell("ls")` — `bash -lc` in the workspace root, spawned under
   a REAL pty, its merged output streamed verbatim to a log FILE and registered
   as a session RESOURCE. `sh.wait(30)` is what fills `exit`/`stdout`. Output is
   bounded at READ time to a head+tail budget per stream, so only the MIDDLE of a
   huge stream is dropped, never its start or end. A non-zero exit is DATA the
   model reads, not an error.

2. A server, watcher or long build is the SAME call — you simply do not wait for
   it, or you wait for less than it takes. A wait that expires is never a lost
   process: it keeps running under its id and its log keeps filling.

3. The log OUTLIVES the run. Every shell keeps its log file and its index row by
   id for as long as the session does, so "what did that build print" is
   answerable a turn later from the id alone. That retention is the feature, not
   a leak to reap.

The result IS the HANDLE: every shell answer is a dict-with-methods in the
sandbox, so the process is driven on the object the call already returned —
`sh.logs(-50)` reads the last 50 LINES (or a byte OFFSET) and returns NOW,
`sh.wait(30)` is the bounded poll loop written once in the engine, `sh.type("y")`
types into the pty and `sh.stop()` kills the tree. There are no id-taking verbs to
re-type an id into; re-issuing a LIVE id gives the same handle back.

STATUS is not a stage of its own: EVERY answer of EVERY stage already says what the
shell is doing — `status`/`exit`, `started_at`/`finished_at`/`uptime_ms`, `log_path`,
and the live `cpu_ms`/`cpu_percent`/`rss_bytes` of its process tree — so "is it done
yet" is read off the result already in hand and never costs a second call.

`shell-dispatch` survives as the INTERNAL grammar the Python-extension entry
points use, since those hand-author an options map and genuinely need an `op`.

EVERY result of EVERY stage — including an argv run, which uses the same runner
— is the one [[shell-result-base]] key set: `stage` names the producer and is
the only thing that varies. A key a stage has nothing to say about is nil /
false / 0 instead of absent, so model Python indexes any of them without a
KeyError, and a run answers with its `command` and that command's own bytes at
the TOP level — there is no entry to unwrap and no second shape to learn.


The `shell` toggle is registered HERE, extension-owned under the vis
namespace. It closes the MODEL's door only: an installed extension keeps its
own trusted process boundary (`vis.shell`, `subprocess`), which the toggle
does not gate.
raw docstring

jailed-shellclj

(jailed-shell env opts)

Run vis.jailed_shell through a strict policy read from the latest merged on-disk configuration at every process spawn. Works with or without a session; invalid current config refuses that spawn instead of using a snapshot.

Run `vis.jailed_shell` through a strict policy read from the latest merged
on-disk configuration at every process spawn. Works with or without a session;
invalid current config refuses that spawn instead of using a snapshot.
sourceraw docstring

render-shell-run-resultclj

(render-shell-run-result r)

shell op run → REPL-style collapsed/expanded card. The ONE surviving op-card renderer, and it is called DIRECTLY: the !cmd bang path in the loop PRINTS a command's output, so this card IS its whole answer. No registry, no symbol key — every other result is painted from the result's own data.

Collapsed: $ npm test (success) · 1.2s or $ grep x missing (failure) · exit 2 · 34ms. Expanded: labeled COMMAND / STATUS / STDOUT sections. The body is always present so shell cards are collapsible even when the command produced no output; the full command and metadata stay available behind the disclosure.

shell op `run` → REPL-style collapsed/expanded card. The ONE surviving op-card
renderer, and it is called DIRECTLY: the `!cmd` bang path in the loop PRINTS a
command's output, so this card IS its whole answer. No registry, no symbol key
— every other result is painted from the result's own data.

Collapsed: `$ npm test (success) · 1.2s` or
`$ grep x missing (failure) · exit 2 · 34ms`.
Expanded: labeled COMMAND / STATUS / STDOUT sections. The body is
always present so shell cards are collapsible even when the command produced no
output; the full command and metadata stay available behind the disclosure.
sourceraw docstring

run-argvclj

(run-argv env argv)
(run-argv env argv opts)

Run ONE literal argv through the SAME bounded machinery shell runs its own command with: cwd authorization, process-jail policy, head+tail capped capture, timeout and kill-tree. Returns that command's own total entry — the SAME [[shell-result-base]] map shell itself answers a foreground call with, carrying the request's :dir/:timeout-secs as metadata, so an argv run and shell have ONE result shape and there is no envelope to unwrap.

No shell is involved — each element reaches the process verbatim, so nothing needs quoting. An argv caller is a USER of this: every argv command is a bounded shell command, so both tools share one runner, one jail and one capture policy.

Run ONE literal argv through the SAME bounded machinery `shell` runs its own
command with: cwd authorization, process-jail policy, head+tail capped
capture, timeout and kill-tree. Returns that command's own total entry — the
SAME [[shell-result-base]] map `shell` itself answers a foreground call with,
carrying the request's `:dir`/`:timeout-secs` as metadata, so an argv run and `shell`
have ONE result shape and there is no envelope to unwrap.

No shell is involved — each element reaches the process verbatim, so nothing
needs quoting. An argv caller is a USER of this: every argv command is a
bounded shell command, so both tools share one runner, one jail and one
capture policy.
sourceraw docstring

run-blockingclj

(run-blocking env command opts)

INTERNAL blocking runner — NOT the tool. Run ONE bounded foreground command and answer the tool's own total result: the command's own run-stage map with the handle's identity merged on, so r["exit"], r["stdout"] and r["command"] are read at the top level and there is no entry to index into. One call is one command — an ordered batch is what && and a second call are for — so there is no shared budget to divide and no "never started" entry to explain.

EVERY run IS a handle. It claims its id and its log file BEFORE it waits, so the result carries that id whether the command finished or not, and a wait that expires is no longer a lost process: it keeps running under its id, sh.logs(offset=0) reads everything the timed-out call never saw, and sh.stop() ends it. A command that finished inside its wait drops the registry entry — there is no live process to account for — while its log file stays readable by id for as long as the session does.

INTERNAL blocking runner — NOT the tool. Run ONE bounded foreground command and answer the tool's own total result: the
command's own `run`-stage map with the handle's identity merged on, so `r["exit"]`,
`r["stdout"]` and `r["command"]` are read at the top level and there is no
entry to index into. One call is one command — an ordered batch is what `&&`
and a second call are for — so there is no shared budget to divide and no
"never started" entry to explain.

EVERY run IS a handle. It claims its `id` and its log file BEFORE it waits, so
the result carries that id whether the command finished or not, and a wait that
expires is no longer a lost process: it keeps running under its id,
`sh.logs(offset=0)` reads everything the timed-out call never saw, and
`sh.stop()` ends it. A command that finished inside its wait drops the
registry entry — there is no live process to account for — while its log file
stays readable by id for as long as the session does.
sourceraw docstring

session-jailed-shellclj

(session-jailed-shell env opts)

Run vis.jailed_shell_session through the invoking session's immutable jail snapshot. Requires a live session and never re-reads configuration.

Run `vis.jailed_shell_session` through the invoking session's immutable jail
snapshot. Requires a live session and never re-reads configuration.
sourceraw docstring

shellclj

(shell command)
(shell command opts)

sh = await shell("npm test") — spawn ONE bash line under a pty and return the HANDLE now. Every run is a background run; waiting is sh.wait(secs), the only wait there is. The handle reads (sh.logs(offset=0)), types (sh.type(text)) and kills (sh.stop()), and its log file outlives the call, so nothing is ever lost to a deadline or to a call that already returned.

`sh = await shell("npm test")` — spawn ONE bash line under a pty and return
the HANDLE now. Every run is a background run; waiting is `sh.wait(secs)`, the
only wait there is. The handle reads
(`sh.logs(offset=0)`), types
(`sh.type(text)`) and kills (`sh.stop()`), and its log file outlives the call,
so nothing is ever lost to a deadline or to a call that already returned.
sourceraw docstring

shell-attach-commandclj

(shell-attach-command _parsed residual)

vis-agent extension shell attach <id> — the human-side passthrough: join a live background shell's PTY in your OWN terminal (finish a browser OAuth, answer a prompt only a person can), then Ctrl-] to detach with the child untouched. --socket PATH targets an explicit socket; otherwise the newest shell whose id matches. Returns the attach exit code.

`vis-agent extension shell attach <id>` — the human-side passthrough: join a live
background shell's PTY in your OWN terminal (finish a browser OAuth, answer a
prompt only a person can), then Ctrl-] to detach with the child untouched.
`--socket PATH` targets an explicit socket; otherwise the newest shell whose
id matches. Returns the attach exit code.
sourceraw docstring

shell-cliclj

CLI surface mounted under vis-agent extension shell. Only attach for now — the human passthrough onto a background PTY the agent spawned.

CLI surface mounted under `vis-agent extension shell`. Only `attach` for now — the human
passthrough onto a background PTY the agent spawned.
sourceraw docstring

shell-dispatchclj

(shell-dispatch env opts)

INTERNAL shell lifecycle grammar, kept for the Python-extension entry points (trusted-extension-shell, jailed-shell, session-jailed-shell) whose caller authors an options map by hand and therefore genuinely needs an op discriminator. The MODEL never reaches this: it calls the shell PYTHON verb — one call that spawns one command — and drives what came back through the HANDLE's own methods (sh.logs(), sh.wait(), sh.type("y"), sh.stop()), so one disambiguate.

INTERNAL shell lifecycle grammar, kept for the Python-extension entry points
(`trusted-extension-shell`, `jailed-shell`, `session-jailed-shell`) whose
caller authors an options map by hand and therefore genuinely needs an `op`
discriminator. The MODEL never reaches this: it calls the `shell` PYTHON verb —
one call that spawns one command — and drives what came back through the
HANDLE's own methods (`sh.logs()`, `sh.wait()`, `sh.type("y")`, `sh.stop()`), so one
disambiguate.
sourceraw docstring

shell-logsclj

(shell-logs id)
(shell-logs id opts)

sh.logs() — read a background shell's log from a byte offset, or the last n LINES with a negative one (sh.logs(-50)), and return NOW. Nothing blocks on your behalf: a wait is a bounded loop you write in python_execution and break on what you actually read.

`sh.logs()` — read a background shell's log from a byte offset, or the last
n LINES with a negative one (`sh.logs(-50)`), and return NOW. Nothing blocks
on your behalf: a wait is a bounded loop you write in `python_execution` and
break on what you actually read.
sourceraw docstring

shell-logs-symbolclj

source

shell-stopclj

(shell-stop id)

sh.stop() — kill the process tree and drop the retained logs and session resource.

`sh.stop()` — kill the process tree and drop the retained logs and
session resource.
sourceraw docstring

shell-stop-symbolclj

source

shell-symbolclj

source

shell-symbolsclj

source

shell-typeclj

(shell-type id text)
(shell-type id text opts)

sh.type("y") — type keystrokes at a background shell's stdin. is_enter (default true) submits the line, which is what an interactive prompt waits for; read the response with sh.logs().

`sh.type("y")` — type keystrokes at a background shell's stdin.
`is_enter` (default true) submits the line, which is what an interactive prompt
waits for; read the response with `sh.logs()`.
sourceraw docstring

shell-type-symbolclj

source

shell-waitclj

(shell-wait id)
(shell-wait id seconds)
(shell-wait id seconds opts)

sh.wait(secs) — the ONLY wait there is. Block until the shell exits or the deadline passes, and answer the accumulated stdout plus the final exit. timed_out true means the WAIT expired; the process runs on under its id.

`sh.wait(secs)` — the ONLY wait there is. Block until the shell exits or the
deadline passes, and answer the accumulated `stdout` plus the final `exit`.
`timed_out` true means the WAIT expired; the process runs on under its id.
sourceraw docstring

shell-wait-symbolclj

source

trusted-extension-shellclj

(trusted-extension-shell env opts)

Run a trusted Python extension's ordinary vis.shell request without applying a process jail. The extension context already has direct, unrestricted subprocess access; this is the result-shaped convenience API for the same trust boundary. Foreground calls therefore work outside a session too.

Run a trusted Python extension's ordinary `vis.shell` request without applying
a process jail. The extension context already has direct, unrestricted
subprocess access; this is the result-shaped convenience API for the same trust
boundary. Foreground calls therefore work outside a session too.
sourceraw docstring

vis-extensionclj

source

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close