@ai-ecoverse/slicc-agent 3.42.2 → 3.43.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/README.md CHANGED
@@ -186,7 +186,7 @@ A **cone** is a top-level agent the user talks to; a **scoop** is a helper agent
186
186
 
187
187
  Each scoop is owned by a background durable task, its **anchor**, so Stop in its cone doesn't end it; `agent stop` and Drop do. They keep its transcript in durable storage and its reports in `/scoops/<handle>/reports/`, which report licks point at, and remove its working folder `/scoops/<handle>/workspace`. Each request handed to a scoop gets a **reporter** task that waits for the run, writes the answer to `/scoops/<handle>/reports/<task id>.md` and reports it to whoever asked. Requests from a cone's or a scoop's bash report into that agent's `pi.inbox` as a lick, through the licks outbox, so they steer and coalesce like any lick; requests from a terminal report nowhere, and a user typing in a scoop's chat gets the answer there. In a scoop's chat, a request someone else sent shows who sent it (`UserMessage.from`): the asking cone's or scoop's name, with `origin: 'agent'` so spectrum (≥ 1.26.0) shows it as that agent's request with an "Agent" badge, or `terminal` without an origin. Once the request is placed, the reporter appends a `slicc.from` entry (`{ from, entry }`) without model messages, and the adapter sets `from` on that entry's message. A request withdrawn before it was placed leaves no entry. The report lick's text is `[scoop <name> (<role>) <status>]`, and its body has the report's path and line count and a 1,000-character preview. A scoop's prompt has a `scoop` section with its name, its cone, its folders and its limits. The `agent` command is taught by the built-in `agent` skill (below), whose description says that roles exist and that `agent list --agents` lists them.
188
188
 
189
- **The `agent` command.** One bash script is installed under eight names, `agent`, `subagent`, `sprinkle`, `memory`, `gelatiere`, `freezer`, `models` and `panel`, in `/usr/local/bin`, mode `0755`, which is on every user's `PATH`, so the user, a cone or a scoop runs it in any bash. A file at one of those paths that isn't slicc-agent's (it lacks the `slicc-agent/1` request marker), such as a root global package's `memory`, is left alone, with one warning per boot in the worker's console. Root's `$PNPM_HOME/bin` (`/usr/local/share/pnpm/bin`) is on root's `PATH` only: other users find root's installed packages in `/usr/bin`, but not loose scripts. Copies that earlier versions put in the kernel's `$PNPM_HOME/bin` are removed, so they can't shadow the new ones for root. It writes a request (NUL-separated fields: `slicc-agent/1`, the name it was called by, `$SLICC_AGENT`, or `tab:$SLICC_TAB` from a terminal that has only that, the working directory, its pid, argc, the arguments and stdin) to `/var/lib/slicc/agent/requests/in/` and polls `out/` for the answer and exit code (with an optional `<id>.err`, the answer's stdout is `<id>.out` and its stderr `<id>.err`); the worker writes `<id>.ack` when it picks a request up, and the script gives up after 20 s without one ("the SLICC agent isn't running", exit 1). The kernel environment exports `SLICC_AGENT`, `PI_PROVIDER`, `PI_MODEL` and `PI_REASONING_LEVEL` into every agent command, so the worker knows the caller. `/var/lib/slicc/agent/scoops/<handle>/metadata.json` mirrors each scoop's state for scripts.
189
+ **The `agent` command.** One bash script is installed under seven names, `agent`, `subagent`, `memory`, `gelatiere`, `freezer`, `models` and `panel`, in `/usr/local/bin`, mode `0755`, which is on every user's `PATH`, so the user, a cone or a scoop runs it in any bash. A file at one of those paths that isn't slicc-agent's (it lacks the `slicc-agent/1` request marker), such as a root global package's `memory`, is left alone, with one warning per boot in the worker's console. Root's `$PNPM_HOME/bin` (`/usr/local/share/pnpm/bin`) is on root's `PATH` only: other users find root's installed packages in `/usr/bin`, but not loose scripts. Copies that earlier versions put in the kernel's `$PNPM_HOME/bin` are removed, so they can't shadow the new ones for root. It writes a request (NUL-separated fields: `slicc-agent/1`, the name it was called by, `$SLICC_AGENT`, or `tab:$SLICC_TAB` from a terminal that has only that, the working directory, its pid, argc, the arguments and stdin) to `/var/lib/slicc/agent/requests/in/` and polls `out/` for the answer and exit code (with an optional `<id>.err`, the answer's stdout is `<id>.out` and its stderr `<id>.err`); the worker writes `<id>.ack` when it picks a request up, and the script gives up after 20 s without one ("the SLICC agent isn't running", exit 1). The kernel environment exports `SLICC_AGENT`, `PI_PROVIDER`, `PI_MODEL` and `PI_REASONING_LEVEL` into every agent command, so the worker knows the caller. `/var/lib/slicc/agent/scoops/<handle>/metadata.json` mirrors each scoop's state for scripts.
190
190
  - `agent [options] --prompt <text>` (or `--file <path>`, or `-` for stdin, or v6's `agent <cwd> <allowed-commands> <prompt>`) is **synchronous**: an ephemeral scoop runs, and the command prints its final answer and exits 0, or prints the reason on stderr and exits 1. Afterwards the scoop is stopped, its folder removed, its conversation marked dropped and its transcript archived as Markdown in `/tmp/agent-sessions/<handle>.md` (`/home/sessions/` with `--persist-session`, nowhere with `--no-persist-session`). The script traps TERM, INT and HUP and cancels the scoop, and the worker checks the script's pid in the kernel's process table every second for a SIGKILL. If the caller's run is still going when the bash call dies (a bash timeout), the scoop continues and its answer arrives as a `bash` lick; `--background-after <seconds>` does the same on purpose. Sync calls nest up to three deep. Allowed commands in v6's form are told to the scoop, not enforced.
191
191
  - `agent --async …` (= `subagent spawn …`) starts a persistent scoop and prints its handle; only cones start them. `list [--agents]`, `status`, `rename`, `send [--follow-up]`, `wait [--timeout <s>] [--notify]` (30 s by default; `--notify` returns at once and brings the answers together in one `scoop-wait` lick) and `stop` manage them. From a scoop, `agent send parent "<note>"` posts a progress note to its cone as a lick, coalesced per scoop.
192
192
  - Options: `--name`, `--agent <role>`, `--model <provider/model>`, `--thinking <level>` or `--effort low|medium|high|max`, `--tools <a,b>` (or `auto`/`full`), `--read-only <paths>`, `--system-prompt[-file]`. `--schema-b64`, `--tools output`, `--session`, `--resume`, `--image`, `--no-escalate`, `--minimal` and `--usage` answer "not supported in SLICC yet".
@@ -337,7 +337,7 @@ The `memory` section, read before every request, holds the first 200 lines (at m
337
337
  - secrets redacted;
338
338
  - at most 50 open;
339
339
  - dismissed and taken ids are never reopened.
340
- - `gelatiere deliver` sends each cone named in a suggestion's `cones` (or the first cone) one `sprinkle` lick with the action `gelatiere-suggestions`. The built-in `gelatiere` skill answers it with `sprinkle show suggestions`, and looks ids up in the store before installing or trying anything.
340
+ - `gelatiere deliver` sends each cone named in a suggestion's `cones` (or the first cone) one `sprinkle` lick with the action `gelatiere-suggestions`. The built-in `gelatiere` skill answers it with `panel open sprinkle:suggestions`, and looks ids up in the store before installing or trying anything.
341
341
  - `gelatiere install <id>` is what a card's Install leads to. It installs [upskill](https://github.com/ai-ecoverse/gh-upskill) if it's missing (`command -v upskill || curl -fsSL …/install.sh | bash`, into `$PNPM_HOME`), runs `upskill <repo> [--path <folder>] (--skill <name> | --all) --dest-path ~/.pi/agent/skills`, checks that the skill (or, with `all`, at least one new skill) is there for the skills loader, and marks the suggestion taken. It refuses a single skill that's already installed. A `skill` suggestion may carry `path` (a folder in the repo) and `all: true` instead of `skill`. In seven, upskill reaches GitHub through the page's fetch, which `raw.githubusercontent.com` and `api.github.com` allow with CORS; `GITHUB_TOKEN` raises GitHub's rate limit. Before anyone clicks, the card shows where the skill comes from: "Installs github from github.com/example/skills".
342
342
  - `gelatiere run`, `list [--all] [--json]`, `dismiss <id>` and `status` complete the command.
343
343
  - `gelatiere catalog [--refresh] [--all] [--json]` reads v6's catalog: `https://www.sliccy.com/skills/catalog.json`, the company's `<slug>.json` and the optional `use-cases.json`. Each is the Edge Delivery sheet shape `{ data: [rows] }` with string fields.
@@ -484,7 +484,7 @@ A sprinkle is a small HTML panel next to the chat. pi has nothing for this; it's
484
484
 
485
485
  **Files.** Every `.shtml` file in `/home/sprinkles`, as `<name>.shtml` or `<name>/<name>.shtml`, is a sprinkle. `<name>` is 1–64 of `a-z 0-9 . _ -`, and `welcome` is reserved for the built-in one. Its `<title>` and `<link rel="icon" href="<lucide name>">` give its title and rail icon (default `sparkles`). The worker watches the folder: the transcript service's `sprinkles` lists every one with its HTML, so spectrum gives each a rail button, and editing a file reloads its panel. Deleting the file retires it.
486
486
 
487
- **Owners.** Each sprinkle talks to one agent, its owner. The owner is whoever first showed it, or the agent named with `sprinkle own`, otherwise the active cone at the time of the send. Owners live in the session document `slicc.sprinkles`.
487
+ **Owners.** Each sprinkle talks to one agent, its owner. The first `panel open sprinkle:<name>` from a cone or a scoop makes the caller's cone its owner; until then it's the active cone at the time of the send. Nothing reassigns an owner afterwards, and `suggestions` always follows the active cone. Owners live in the session document `slicc.sprinkles`.
488
488
 
489
489
  **Talking back.**
490
490
  - **Sends.** `SprinklePort.send(id, { action, data, target })` becomes `AgentControl.sprinkleSend`, then a lick on the `sprinkle` channel for the owner: source `sprinkle:<name>`, the action as its text and the data as JSON in its body. It steers and coalesces per sprinkle like any lick.
@@ -493,33 +493,33 @@ A sprinkle is a small HTML panel next to the chat. pi has nothing for this; it's
493
493
  - `getState` and `setState` keep one JSON value per sprinkle in `slicc.sprinkles`;
494
494
  - there's no `exec`: a sprinkle that asks for one gets an error telling it to send the agent a message with `slicc.lick()` instead, so every command goes through an agent and its transcript.
495
495
 
496
- **The `sprinkle` command** is the same script as `agent`, installed as `sprinkle`:
497
- - `sprinkle list`;
498
- - `sprinkle show <name>`: posts a `slicc.sprinkle` entry in the caller's chat, which the adapter shows as an inline sprinkle;
499
- - `sprinkle own <name> [<agent>]`.
500
-
501
- `sprinkle open <name>` and `sprinkle close <name>` forward to `panel open|close sprinkle:<name>` (see Panels). v6's `reload`, `send` and `chat` answer with what to do instead.
496
+ **There's no `sprinkle` command.** An agent opens a sprinkle with `panel open sprinkle:<name>` and lists them with `panel list` (see Panels). An agent version that installed `sprinkle` leaves a copy in `/usr/local/bin` or `$PNPM_HOME/bin`; the worker removes it when that copy is slicc-agent's.
502
497
 
503
498
  **Shipped sprinkles.** Only `welcome` and `suggestions`, with slicc-spectrum's reviewed copy.
504
- - **Welcome.** The worker posts it inline in the first cone's chat once per session. Its `onboarding-complete` send writes `/home/.welcomed`, which the card checks, and the profile to `/home/.welcome.json` for the gelatiere's catalog ranking, and the built-in `welcome` skill answers the lick.
499
+ - **Welcome.** The worker posts it inline in the first cone's chat once per session, as a `slicc.sprinkle` entry that the adapter shows as an inline sprinkle. It's the only inline sprinkle. Its `onboarding-complete` send writes `/home/.welcomed`, which the card checks, and the profile to `/home/.welcome.json` for the gelatiere's catalog ranking, and the built-in `welcome` skill answers the lick.
505
500
  - **Suggestions.** It's listed once the gelatiere's store `/home/.gelatiere/suggestions.json` exists, and owned by the active cone. Its `gelatiere-dismiss` send marks the suggestion in the store and never reaches an agent; `gelatiere-install` and `gelatiere-try` mark it taken and go to the owner as licks. Its `exec` for use cases is refused, so it shows its static empty state.
506
501
 
507
- The built-in `sprinkles` skill teaches the files, the bridge and the command.
502
+ The built-in `sprinkles` skill teaches the files, the bridge and `panel open sprinkle:<name>`.
508
503
 
509
504
  ### Panels
510
505
 
511
- The `panel` command lets an agent, or the user in a terminal, list, open, close, focus and move the panels of a SLICC tab. slicc-spectrum owns the command: `panelCommand(app, argv, caller)` parses argv, knows the panel ids and the guard rails, and answers `{ stdout, stderr, code }` with codes 0, 1, 2 and 5. The agent only carries the request to one tab and brings the answer back, so new verbs and flags need no agent release. pi has nothing for this; it's SLICC's UI.
506
+ The `panel` command lets an agent, or the user in a terminal, list, open, close, focus and move the panels of a SLICC tab, sprinkles included as `sprinkle:<name>`. slicc-spectrum owns the command: `panelCommand(app, argv, caller)` parses argv, knows the panel ids and the guard rails, and answers `{ stdout, stderr, code }` with codes 0, 1, 2 and 5. The agent only carries the request to one tab and brings the answer back, so new verbs and flags need no agent release. pi has nothing for this; it's SLICC's UI.
512
507
 
513
- **The command** is the same script as `agent`, installed as `panel`. It forwards argv untouched with the caller `{ agentId, cone, readOnly: false }`:
508
+ **The command** is the same script as `agent`, installed as `panel`. It forwards argv with the caller `{ agentId, cone, readOnly: false }`, untouched apart from `--tab`:
514
509
  - `agentId` is the calling cone or scoop (`cone`, `cone-2`, `scoop:<id>`), or `null` from a terminal;
515
510
  - `cone` is the caller's cone: a scoop's own cone, or the active cone for a terminal;
516
511
  - a terminal with `SLICC_TAB` set (bios sets it in each tab's terminals) sends that tab's id, and the request goes to that tab, with its cone.
517
512
 
513
+ The agent reads three things itself:
514
+ - **`panel tabs [--json]`** never reaches a tab: the agent answers it from the bridge's registered tabs, one line per tab with its id, cone, `visible` or `hidden`, `focused` or `-`, and how long ago it was last active, best first; `--json` prints `[{ tab, cone, visible, focused, lastActive }]`. A cone or a scoop sees only the tabs showing its cone, the user at a terminal sees every tab.
515
+ - **`--tab <tab>`** or `--tab=<tab>`, anywhere in argv, sends the command to that tab and is removed before argv is forwarded. It overrides `SLICC_TAB`. A cone or a scoop can only name a tab showing its own cone; the user at a terminal can name any tab, and the tab's cone becomes the caller's cone. A tab that isn't open, or isn't on the caller's cone, exits 3 with a sentence that points to `panel tabs`; `--tab` without a value exits 2.
516
+ - **`panel open sprinkle:<name>`** from a cone or a scoop sets the sprinkle's owner to the caller's cone first, if it has none (see Sprinkles).
517
+
518
518
  It prints the tab's stdout and stderr on their own streams and exits with its code. The script transport has an optional `.err` file next to `.out` for this. The agent owns two codes:
519
- - **3:** no open tab shows the caller's cone ("panel: no open SLICC tab shows cone <cone>; …"). Nothing is queued;
519
+ - **3:** no open tab shows the caller's cone ("panel: no open SLICC tab shows cone <cone>; …"), or the `--tab` tab isn't open or reachable. Nothing is queued;
520
520
  - **4:** the tab didn't pick the request up within 5 s, didn't answer within 5 s more, or went away meanwhile. Late answers are dropped.
521
521
 
522
- **The bridge** is the `slicc.agent.pages` service, a sibling of `slicc.agent.remote` with the same long-poll stream: `open(tab)`, `report(stream, tab)`, `next(stream, waitMs)`, `answer(stream, id, result)` and `close(stream)`. A tab reports `{ tab, kinds: ['panel'], cone, visible, focused, lastActive }`. Each request goes to exactly one tab and is never retried elsewhere: the `SLICC_TAB` tab if it's open, otherwise the tab on the caller's cone that is visible and focused, then visible, then the latest active. A tab is dropped when it closes its stream, when its attachment goes, or after 30 s without a poll, and each attachment reaches only its own streams.
522
+ **The bridge** is the `slicc.agent.pages` service, a sibling of `slicc.agent.remote` with the same long-poll stream: `open(tab)`, `report(stream, tab)`, `next(stream, waitMs)`, `answer(stream, id, result)` and `close(stream)`. A tab reports `{ tab, kinds: ['panel'], cone, visible, focused, lastActive }`. Each request goes to exactly one tab and is never retried elsewhere: the `--tab` tab, the `SLICC_TAB` tab if it's open, otherwise the tab on the caller's cone that is visible and focused, then visible, then the latest active. A tab is dropped when it closes its stream, when its attachment goes, or after 30 s without a poll, and each attachment reaches only its own streams.
523
523
 
524
524
  **The page side.** `createAgentModel(connection, { page: { tab, run } })` starts a `PageAdapter`. It reports the tab's selected cone (`AgentAdapter.active()`, or a scoop's cone), `document.visibilityState`, `document.hasFocus()` and the time of the last pointer or key event, debounced by 250 ms. It answers each request with `run(argv, caller)`, which bios points at spectrum's `panelCommand` (≥ 1.59.0). `PageRun` uses the agent's own types, so the peer range stays `^1.39.0`, and `test/integration/panel-run.ts` type-checks `(argv, caller) => panelCommand(app, argv, caller)` against it. The integration test runs the real `panelCommand` on a `<slicc-app>` with the dummy model under the agent's ports. Without `run` the tab never registers, so the bridge works with older spectrums too.
525
525
 
package/bin/agent CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/bin/bash
2
2
  dir=/var/lib/slicc/agent/requests
3
- as=$(basename "$0")
4
- case "$as" in subagent|sprinkle|memory|gelatiere|freezer|models|panel) ;; *) as=agent ;; esac
5
- mkdir -p "$dir/in" "$dir/out" 2>/dev/null
3
+ as="${0##*/}"
4
+ case "$as" in subagent|memory|gelatiere|freezer|models|panel) ;; *) as=agent ;; esac
5
+ [ -d "$dir/in" ] && [ -d "$dir/out" ] || mkdir -p "$dir/in" "$dir/out" 2>/dev/null
6
6
  who="${SLICC_AGENT:-}"
7
7
  if [ -z "$who" ] && [ -n "${SLICC_TAB:-}" ]; then who="tab:$SLICC_TAB"; fi
8
8
 
@@ -22,7 +22,7 @@ for arg in "$@"; do
22
22
  if [ "$arg" = "-" ]; then stdin=1; fi
23
23
  done
24
24
 
25
- id="$(date +%s%N)-$$-$RANDOM"
25
+ id="${EPOCHREALTIME/[.,]/}-$$-$RANDOM"
26
26
  submit "$id" "$@" || exit 1
27
27
  stdin=0
28
28
 
@@ -33,7 +33,7 @@ case "${1:-}" in
33
33
  esac
34
34
 
35
35
  cancel() {
36
- submit "$(date +%s%N)-$$-$RANDOM" __cancel "$id"
36
+ submit "${EPOCHREALTIME/[.,]/}-$$-$RANDOM" __cancel "$id"
37
37
  exit 130
38
38
  }
39
39
  if [ $sync = 1 ]; then trap cancel TERM INT HUP; fi
@@ -64,11 +64,11 @@ while [ ! -f "$dir/out/$id.code" ]; do
64
64
  exit 1
65
65
  fi
66
66
  if [ -n "$after" ] && [ $count -ge $((after * 10)) ]; then
67
- submit "$(date +%s%N)-$$-$RANDOM" __detach "$id"
67
+ submit "${EPOCHREALTIME/[.,]/}-$$-$RANDOM" __detach "$id"
68
68
  after=""
69
69
  fi
70
70
  done
71
- code=$(cat "$dir/out/$id.code")
71
+ read -r code < "$dir/out/$id.code"
72
72
  if [ -f "$dir/out/$id.err" ]; then
73
73
  cat "$dir/out/$id.out"
74
74
  cat "$dir/out/$id.err" >&2
package/dist/main.js CHANGED
@@ -193,7 +193,7 @@ async function start(scope, ports, options) {
193
193
  });
194
194
  licks.licks.guard(freezer.frozenTarget);
195
195
  const settings = await createAgentSettings(models, credentials, providers, { mcp: mcpRuntime });
196
- const pages = createPages();
196
+ const pages = createPages({ claim: sprinkles.claim });
197
197
  const runtime = await scoops.attach(
198
198
  {
199
199
  harness: agent.harness,
@@ -203,7 +203,6 @@ async function start(scope, ports, options) {
203
203
  home: HOME,
204
204
  alive: alive(client),
205
205
  reads: skillsRuntime.dirs,
206
- sprinkle: sprinkles.command,
207
206
  memory: memoryRuntime.command,
208
207
  gelatiere: gelatiere.command,
209
208
  freezer: freezer.command,
package/dist/main.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/main.ts"],
4
- "sourcesContent": ["import { attachKernel } from '@ai-ecoverse/slicc-kernel';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { CredentialStore, Provider } from '@earendil-works/pi-ai';\nimport {\n createRegistry,\n type ModelRef,\n type Storage,\n type ToolRegistration,\n} from '@earendil-works/pi-durable';\nimport { CodingTools } from '@earendil-works/pi-durable/tools';\nimport { type Agent, openAgent } from './agent.ts';\nimport { browserGuard } from './browser/guard.ts';\nimport { attachChanges, CHANGES_MS } from './changes/index.ts';\nimport {\n codemodeExtension,\n codemodeTool,\n disabledBySettings,\n locateWasm,\n sandboxFactory,\n} from './codemode/index.ts';\nimport { EncryptedCredentialStore } from './credentials.ts';\nimport { attachFreezer } from './freezer/index.ts';\nimport { settingsText, titler } from './freezer/title.ts';\nimport { lateGelatiere } from './gelatiere/index.ts';\nimport { type AgentHost, hostAgent } from './host.ts';\nimport { imageReads } from './images/index.ts';\nimport { createActivity } from './kernel/activity.ts';\nimport type { KernelClient } from './kernel/client.ts';\nimport { HOME, kernelEnvironment, SliccKernelEnv } from './kernel/env.ts';\nimport { processGroups } from './kernel/groups.ts';\nimport { adminOver, type UserClient, type UserClients, userClients } from './kernel/users.ts';\nimport { setupLicks } from './licks/index.ts';\nimport { lickTriage } from './licks/triage.ts';\nimport { setupMcp } from './mcp/index.ts';\nimport { setupMemory } from './memory/index.ts';\nimport { modelsCommand } from './models/index.ts';\nimport { type Transport, transportFetch } from './net.ts';\nimport { sliccPrompt } from './prompt.ts';\nimport { createPages } from './remote/pages.ts';\nimport { identity } from './scoops/identity.ts';\nimport { type Assets, packageAssets, type ScoopsRuntime, setupScoops } from './scoops/index.ts';\nimport {\n createAgentSettings,\n createSliccModels,\n DEFAULT_MODEL,\n sliccProviders,\n} from './settings.ts';\nimport { RELOAD_MS, setupSkills } from './skills/index.ts';\nimport { setupSprinkles } from './sprinkles/index.ts';\nimport { openOpfsSqliteStorage } from './sqlite.ts';\nimport {\n agentVersion,\n browserConnected,\n commandsOnPath,\n kernelBoot,\n transportName,\n} from './system.ts';\nimport { type KernelPorts, kernelPorts, serveConnections, type WorkerScope } from './worker.ts';\n\nexport interface AgentWorkerScope extends WorkerScope {\n fetch: typeof fetch;\n location: { origin: string };\n}\n\nexport type KernelAttach = (port: MessagePort) => Promise<KernelClient & { transport: Transport }>;\n\nexport interface AgentWorkerOptions {\n model?: ModelRef;\n providers?: Provider[];\n attach?: KernelAttach;\n credentials?: () => Promise<CredentialStore>;\n storage?: () => Promise<Storage>;\n assets?: Assets;\n codemodeWasm?: () => Promise<WebAssembly.Module | undefined>;\n codemodeWorker?: string | URL;\n catalog?: string;\n users?: boolean;\n mcpRedirect?: string;\n}\n\nexport function usersOf(\n admin: MessagePort | undefined,\n wanted: boolean | undefined,\n attach: KernelAttach\n): UserClients | undefined {\n if (!admin) return undefined;\n if (wanted === false) {\n admin.close();\n return undefined;\n }\n return userClients(adminOver(admin), attach as (port: MessagePort) => Promise<UserClient>);\n}\n\nexport const STORE_DIR = '/.slicc';\n\nasync function attached(ports: Promise<KernelPorts>, options: AgentWorkerOptions) {\n const attach: KernelAttach = options.attach ?? attachKernel;\n const { kernel, admin } = await ports;\n const client = await attach(kernel);\n return { client, users: usersOf(admin, options.users, attach) };\n}\n\nfunction privateStore(env: SliccKernelEnv): Promise<unknown> {\n return env.exec(`mkdir -p ${STORE_DIR} && chmod 700 ${STORE_DIR}`, undefined, BACKGROUND_CONTEXT);\n}\n\nasync function codemodeTools(\n client: KernelClient,\n options: AgentWorkerOptions,\n native: typeof fetch,\n extra: Parameters<typeof codemodeTool>[0]['extra']\n) {\n const settings = await client.fs\n .readFile(`${HOME}/.pi/agent/settings.json`)\n .catch(() => undefined);\n if (disabledBySettings(settings === undefined ? undefined : new TextDecoder().decode(settings)))\n return [];\n const sandbox = sandboxFactory(\n options.codemodeWasm ?? (() => locateWasm(native, new URL(import.meta.url))),\n options.codemodeWorker\n );\n return [\n codemodeTool({ declared: CodingTools.tools as readonly ToolRegistration[], sandbox, extra }),\n ];\n}\n\nexport const MCP_CALLBACK = '/oauth/mcp-callback';\n\nasync function start(\n scope: AgentWorkerScope,\n ports: Promise<KernelPorts>,\n options: AgentWorkerOptions\n): Promise<AgentHost> {\n const { client, users } = await attached(ports, options);\n const home = new SliccKernelEnv(client, { cwd: HOME });\n await privateStore(home);\n const native = scope.fetch.bind(scope);\n scope.fetch = transportFetch(client.transport, scope.location.origin, native);\n const facts = {\n version: await agentVersion((url) => native(url)),\n commands: await commandsOnPath(client),\n transport: transportName(client.transport),\n browser: await browserConnected(client),\n };\n const credentials = await (options.credentials ?? (() => EncryptedCredentialStore.open()))();\n const providers = options.providers ?? sliccProviders();\n const models = createSliccModels(credentials, providers);\n const registry = createRegistry();\n registry.install(CodingTools);\n registry.install(sliccPrompt(facts));\n registry.install(\n imageReads(\n (CodingTools.tools as readonly ToolRegistration[]).find(\n (tool) => tool.name === 'read'\n ) as ToolRegistration\n )\n );\n const memory = setupMemory(registry);\n const coding = CodingTools.tools as readonly ToolRegistration[];\n registry.install(browserGuard([scope.location.origin], coding));\n const mcp = setupMcp(registry);\n const codemode = await codemodeTools(client, options, native, mcp.codemode);\n registry.install(codemodeExtension(codemode));\n const licks = setupLicks(registry);\n licks.licks.triage(lickTriage(models));\n const scoops = setupScoops(registry, licks.licks, [...coding, ...codemode, ...memory.tools]);\n const skills = setupSkills(registry, licks.licks);\n const activity = createActivity();\n const groups = processGroups(client);\n const model = options.model ?? DEFAULT_MODEL;\n let opened: Agent | undefined;\n const environment = kernelEnvironment(client, {\n activity,\n groups,\n identify: identity(() => opened?.agents, model),\n });\n const agent = await openAgent({\n models,\n model,\n storage: await (options.storage ?? (() => openOpfsSqliteStorage()))(),\n registry,\n env: environment,\n });\n opened = agent;\n const sources = licks.attach(agent, { env: home, home: HOME, activity });\n await sources.start(BACKGROUND_CONTEXT);\n await sources.boot(\n { version: facts.version, boot: await kernelBoot(client) },\n BACKGROUND_CONTEXT\n );\n const skillsRuntime = await skills.attach(\n { env: home, home: HOME, assets: options.assets ?? packageAssets(), reloadMs: RELOAD_MS },\n BACKGROUND_CONTEXT\n );\n const mcpRuntime = await mcp.attach(\n {\n env: home,\n home: HOME,\n credentials,\n licks: licks.licks,\n fetch: scope.fetch,\n version: facts.version,\n reloadMs: RELOAD_MS,\n codemode: codemode.length > 0,\n cors: client.transport.traits?.crossOrigin === 'cors',\n redirect: options.mcpRedirect ?? new URL(MCP_CALLBACK, scope.location.origin).href,\n },\n BACKGROUND_CONTEXT\n );\n const gelatiere = lateGelatiere();\n const sprinkles = await setupSprinkles().attach(\n {\n intercept: gelatiere.intercept,\n harness: agent.harness,\n agents: agent.agents,\n licks: licks.licks,\n env: home,\n assets: options.assets ?? packageAssets(),\n reloadMs: RELOAD_MS,\n },\n BACKGROUND_CONTEXT\n );\n let roles: ScoopsRuntime | undefined;\n const memoryRuntime = await memory.attach(\n {\n harness: agent.harness,\n agents: agent.agents,\n env: home,\n home: HOME,\n reloadMs: RELOAD_MS,\n roles: async (using) => roles?.roles(using),\n },\n BACKGROUND_CONTEXT\n );\n const freezer = attachFreezer({\n harness: agent.harness,\n agents: agent.agents,\n env: home,\n extract: memory.extract,\n title: titler(models, settingsText(home, HOME)),\n });\n licks.licks.guard(freezer.frozenTarget);\n const settings = await createAgentSettings(models, credentials, providers, { mcp: mcpRuntime });\n const pages = createPages();\n const runtime = await scoops.attach(\n {\n harness: agent.harness,\n agents: agent.agents,\n groups,\n env: home,\n home: HOME,\n alive: alive(client),\n reads: skillsRuntime.dirs,\n sprinkle: sprinkles.command,\n memory: memoryRuntime.command,\n gelatiere: gelatiere.command,\n freezer: freezer.command,\n models: modelsCommand({ agents: agent.agents, settings, catalog: models }),\n panel: pages.command,\n mcp: mcp.direct,\n ...(options.assets ? { assets: options.assets } : {}),\n },\n BACKGROUND_CONTEXT\n );\n roles = runtime;\n gelatiere.attach({\n agents: agent.agents,\n licks: licks.licks,\n env: home,\n home: HOME,\n scoops: scoops.scoops,\n roles: runtime.roles,\n assets: options.assets ?? packageAssets(),\n fetch: scope.fetch,\n skills: skillsRuntime.skills,\n ...(options.catalog ? { catalog: options.catalog } : {}),\n });\n await memoryRuntime.reload(BACKGROUND_CONTEXT).catch(() => undefined);\n const changes = attachChanges({ agents: agent.agents, env: home, reloadMs: CHANGES_MS });\n return hostAgent(agent, {\n settings,\n licks: { licks: licks.licks, sources },\n scoops: { scoops: scoops.scoops, runtime },\n skills: skillsRuntime,\n sprinkles,\n memory: memoryRuntime,\n freezer,\n changes,\n pages,\n mcp: mcpRuntime,\n ...(users ? { users } : {}),\n monitor: {\n kernel: client,\n groups,\n ...(users ? { users: () => users.users.list() } : {}),\n secrets: () => mcpRuntime.secrets(),\n },\n });\n}\n\nexport function alive(client: KernelClient) {\n return async (pid: number): Promise<boolean> => {\n if (!client.ps) return true;\n return (await client.ps()).some((process) => process.pid === pid);\n };\n}\n\nexport function runAgentWorker(\n scope: AgentWorkerScope,\n options: AgentWorkerOptions = {}\n): Promise<AgentHost> {\n const host = start(scope, kernelPorts(scope), options);\n host.catch(() => undefined);\n serveConnections(scope, host);\n return host;\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { attachKernel } from '@ai-ecoverse/slicc-kernel';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { CredentialStore, Provider } from '@earendil-works/pi-ai';\nimport {\n createRegistry,\n type ModelRef,\n type Storage,\n type ToolRegistration,\n} from '@earendil-works/pi-durable';\nimport { CodingTools } from '@earendil-works/pi-durable/tools';\nimport { type Agent, openAgent } from './agent.ts';\nimport { browserGuard } from './browser/guard.ts';\nimport { attachChanges, CHANGES_MS } from './changes/index.ts';\nimport {\n codemodeExtension,\n codemodeTool,\n disabledBySettings,\n locateWasm,\n sandboxFactory,\n} from './codemode/index.ts';\nimport { EncryptedCredentialStore } from './credentials.ts';\nimport { attachFreezer } from './freezer/index.ts';\nimport { settingsText, titler } from './freezer/title.ts';\nimport { lateGelatiere } from './gelatiere/index.ts';\nimport { type AgentHost, hostAgent } from './host.ts';\nimport { imageReads } from './images/index.ts';\nimport { createActivity } from './kernel/activity.ts';\nimport type { KernelClient } from './kernel/client.ts';\nimport { HOME, kernelEnvironment, SliccKernelEnv } from './kernel/env.ts';\nimport { processGroups } from './kernel/groups.ts';\nimport { adminOver, type UserClient, type UserClients, userClients } from './kernel/users.ts';\nimport { setupLicks } from './licks/index.ts';\nimport { lickTriage } from './licks/triage.ts';\nimport { setupMcp } from './mcp/index.ts';\nimport { setupMemory } from './memory/index.ts';\nimport { modelsCommand } from './models/index.ts';\nimport { type Transport, transportFetch } from './net.ts';\nimport { sliccPrompt } from './prompt.ts';\nimport { createPages } from './remote/pages.ts';\nimport { identity } from './scoops/identity.ts';\nimport { type Assets, packageAssets, type ScoopsRuntime, setupScoops } from './scoops/index.ts';\nimport {\n createAgentSettings,\n createSliccModels,\n DEFAULT_MODEL,\n sliccProviders,\n} from './settings.ts';\nimport { RELOAD_MS, setupSkills } from './skills/index.ts';\nimport { setupSprinkles } from './sprinkles/index.ts';\nimport { openOpfsSqliteStorage } from './sqlite.ts';\nimport {\n agentVersion,\n browserConnected,\n commandsOnPath,\n kernelBoot,\n transportName,\n} from './system.ts';\nimport { type KernelPorts, kernelPorts, serveConnections, type WorkerScope } from './worker.ts';\n\nexport interface AgentWorkerScope extends WorkerScope {\n fetch: typeof fetch;\n location: { origin: string };\n}\n\nexport type KernelAttach = (port: MessagePort) => Promise<KernelClient & { transport: Transport }>;\n\nexport interface AgentWorkerOptions {\n model?: ModelRef;\n providers?: Provider[];\n attach?: KernelAttach;\n credentials?: () => Promise<CredentialStore>;\n storage?: () => Promise<Storage>;\n assets?: Assets;\n codemodeWasm?: () => Promise<WebAssembly.Module | undefined>;\n codemodeWorker?: string | URL;\n catalog?: string;\n users?: boolean;\n mcpRedirect?: string;\n}\n\nexport function usersOf(\n admin: MessagePort | undefined,\n wanted: boolean | undefined,\n attach: KernelAttach\n): UserClients | undefined {\n if (!admin) return undefined;\n if (wanted === false) {\n admin.close();\n return undefined;\n }\n return userClients(adminOver(admin), attach as (port: MessagePort) => Promise<UserClient>);\n}\n\nexport const STORE_DIR = '/.slicc';\n\nasync function attached(ports: Promise<KernelPorts>, options: AgentWorkerOptions) {\n const attach: KernelAttach = options.attach ?? attachKernel;\n const { kernel, admin } = await ports;\n const client = await attach(kernel);\n return { client, users: usersOf(admin, options.users, attach) };\n}\n\nfunction privateStore(env: SliccKernelEnv): Promise<unknown> {\n return env.exec(`mkdir -p ${STORE_DIR} && chmod 700 ${STORE_DIR}`, undefined, BACKGROUND_CONTEXT);\n}\n\nasync function codemodeTools(\n client: KernelClient,\n options: AgentWorkerOptions,\n native: typeof fetch,\n extra: Parameters<typeof codemodeTool>[0]['extra']\n) {\n const settings = await client.fs\n .readFile(`${HOME}/.pi/agent/settings.json`)\n .catch(() => undefined);\n if (disabledBySettings(settings === undefined ? undefined : new TextDecoder().decode(settings)))\n return [];\n const sandbox = sandboxFactory(\n options.codemodeWasm ?? (() => locateWasm(native, new URL(import.meta.url))),\n options.codemodeWorker\n );\n return [\n codemodeTool({ declared: CodingTools.tools as readonly ToolRegistration[], sandbox, extra }),\n ];\n}\n\nexport const MCP_CALLBACK = '/oauth/mcp-callback';\n\nasync function start(\n scope: AgentWorkerScope,\n ports: Promise<KernelPorts>,\n options: AgentWorkerOptions\n): Promise<AgentHost> {\n const { client, users } = await attached(ports, options);\n const home = new SliccKernelEnv(client, { cwd: HOME });\n await privateStore(home);\n const native = scope.fetch.bind(scope);\n scope.fetch = transportFetch(client.transport, scope.location.origin, native);\n const facts = {\n version: await agentVersion((url) => native(url)),\n commands: await commandsOnPath(client),\n transport: transportName(client.transport),\n browser: await browserConnected(client),\n };\n const credentials = await (options.credentials ?? (() => EncryptedCredentialStore.open()))();\n const providers = options.providers ?? sliccProviders();\n const models = createSliccModels(credentials, providers);\n const registry = createRegistry();\n registry.install(CodingTools);\n registry.install(sliccPrompt(facts));\n registry.install(\n imageReads(\n (CodingTools.tools as readonly ToolRegistration[]).find(\n (tool) => tool.name === 'read'\n ) as ToolRegistration\n )\n );\n const memory = setupMemory(registry);\n const coding = CodingTools.tools as readonly ToolRegistration[];\n registry.install(browserGuard([scope.location.origin], coding));\n const mcp = setupMcp(registry);\n const codemode = await codemodeTools(client, options, native, mcp.codemode);\n registry.install(codemodeExtension(codemode));\n const licks = setupLicks(registry);\n licks.licks.triage(lickTriage(models));\n const scoops = setupScoops(registry, licks.licks, [...coding, ...codemode, ...memory.tools]);\n const skills = setupSkills(registry, licks.licks);\n const activity = createActivity();\n const groups = processGroups(client);\n const model = options.model ?? DEFAULT_MODEL;\n let opened: Agent | undefined;\n const environment = kernelEnvironment(client, {\n activity,\n groups,\n identify: identity(() => opened?.agents, model),\n });\n const agent = await openAgent({\n models,\n model,\n storage: await (options.storage ?? (() => openOpfsSqliteStorage()))(),\n registry,\n env: environment,\n });\n opened = agent;\n const sources = licks.attach(agent, { env: home, home: HOME, activity });\n await sources.start(BACKGROUND_CONTEXT);\n await sources.boot(\n { version: facts.version, boot: await kernelBoot(client) },\n BACKGROUND_CONTEXT\n );\n const skillsRuntime = await skills.attach(\n { env: home, home: HOME, assets: options.assets ?? packageAssets(), reloadMs: RELOAD_MS },\n BACKGROUND_CONTEXT\n );\n const mcpRuntime = await mcp.attach(\n {\n env: home,\n home: HOME,\n credentials,\n licks: licks.licks,\n fetch: scope.fetch,\n version: facts.version,\n reloadMs: RELOAD_MS,\n codemode: codemode.length > 0,\n cors: client.transport.traits?.crossOrigin === 'cors',\n redirect: options.mcpRedirect ?? new URL(MCP_CALLBACK, scope.location.origin).href,\n },\n BACKGROUND_CONTEXT\n );\n const gelatiere = lateGelatiere();\n const sprinkles = await setupSprinkles().attach(\n {\n intercept: gelatiere.intercept,\n harness: agent.harness,\n agents: agent.agents,\n licks: licks.licks,\n env: home,\n assets: options.assets ?? packageAssets(),\n reloadMs: RELOAD_MS,\n },\n BACKGROUND_CONTEXT\n );\n let roles: ScoopsRuntime | undefined;\n const memoryRuntime = await memory.attach(\n {\n harness: agent.harness,\n agents: agent.agents,\n env: home,\n home: HOME,\n reloadMs: RELOAD_MS,\n roles: async (using) => roles?.roles(using),\n },\n BACKGROUND_CONTEXT\n );\n const freezer = attachFreezer({\n harness: agent.harness,\n agents: agent.agents,\n env: home,\n extract: memory.extract,\n title: titler(models, settingsText(home, HOME)),\n });\n licks.licks.guard(freezer.frozenTarget);\n const settings = await createAgentSettings(models, credentials, providers, { mcp: mcpRuntime });\n const pages = createPages({ claim: sprinkles.claim });\n const runtime = await scoops.attach(\n {\n harness: agent.harness,\n agents: agent.agents,\n groups,\n env: home,\n home: HOME,\n alive: alive(client),\n reads: skillsRuntime.dirs,\n memory: memoryRuntime.command,\n gelatiere: gelatiere.command,\n freezer: freezer.command,\n models: modelsCommand({ agents: agent.agents, settings, catalog: models }),\n panel: pages.command,\n mcp: mcp.direct,\n ...(options.assets ? { assets: options.assets } : {}),\n },\n BACKGROUND_CONTEXT\n );\n roles = runtime;\n gelatiere.attach({\n agents: agent.agents,\n licks: licks.licks,\n env: home,\n home: HOME,\n scoops: scoops.scoops,\n roles: runtime.roles,\n assets: options.assets ?? packageAssets(),\n fetch: scope.fetch,\n skills: skillsRuntime.skills,\n ...(options.catalog ? { catalog: options.catalog } : {}),\n });\n await memoryRuntime.reload(BACKGROUND_CONTEXT).catch(() => undefined);\n const changes = attachChanges({ agents: agent.agents, env: home, reloadMs: CHANGES_MS });\n return hostAgent(agent, {\n settings,\n licks: { licks: licks.licks, sources },\n scoops: { scoops: scoops.scoops, runtime },\n skills: skillsRuntime,\n sprinkles,\n memory: memoryRuntime,\n freezer,\n changes,\n pages,\n mcp: mcpRuntime,\n ...(users ? { users } : {}),\n monitor: {\n kernel: client,\n groups,\n ...(users ? { users: () => users.users.list() } : {}),\n secrets: () => mcpRuntime.secrets(),\n },\n });\n}\n\nexport function alive(client: KernelClient) {\n return async (pid: number): Promise<boolean> => {\n if (!client.ps) return true;\n return (await client.ps()).some((process) => process.pid === pid);\n };\n}\n\nexport function runAgentWorker(\n scope: AgentWorkerScope,\n options: AgentWorkerOptions = {}\n): Promise<AgentHost> {\n const host = start(scope, kernelPorts(scope), options);\n host.catch(() => undefined);\n serveConnections(scope, host);\n return host;\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -41,6 +41,52 @@ function noAnswer(cone) {
41
41
  code: 4
42
42
  };
43
43
  }
44
+ function noSuchTab(tab, cone) {
45
+ const err = cone === null ? `panel: there is no open SLICC tab ${tab}; panel tabs lists them
46
+ ` : `panel: no open SLICC tab ${tab} shows cone ${cone}; panel tabs lists the ones that do
47
+ `;
48
+ return { code: 3, out: "", err };
49
+ }
50
+ const usage = (err) => ({ code: 2, out: "", err: `panel: ${err}
51
+ ` });
52
+ function tabFlag(argv) {
53
+ const rest = [];
54
+ let tab;
55
+ for (let at = 0; at < argv.length; at++) {
56
+ const arg = argv[at];
57
+ if (arg === "--tab") {
58
+ const value = argv[++at];
59
+ if (!value) return usage("--tab needs a tab id; panel tabs lists them");
60
+ tab = value;
61
+ } else if (arg.startsWith("--tab=")) {
62
+ if (arg === "--tab=") return usage("--tab needs a tab id; panel tabs lists them");
63
+ tab = arg.slice("--tab=".length);
64
+ } else rest.push(arg);
65
+ }
66
+ return tab === void 0 ? { argv: rest } : { argv: rest, tab };
67
+ }
68
+ function ago(lastActive, now) {
69
+ return lastActive ? `${Math.max(0, Math.round((now - lastActive) / 1e3))}s ago` : "never";
70
+ }
71
+ function tabsOf(argv, reachable, now) {
72
+ const json = argv.includes("--json");
73
+ if (argv.some((arg) => arg !== "--json")) return usage("usage: panel tabs [--json]");
74
+ const rows = reachable.sort((a, b) => rank(b) - rank(a) || b.tab.lastActive - a.tab.lastActive || b.serial - a.serial).map(({ tab }) => ({
75
+ tab: tab.tab,
76
+ cone: tab.cone,
77
+ visible: tab.visible,
78
+ focused: tab.focused,
79
+ lastActive: tab.lastActive
80
+ }));
81
+ if (json) return { code: 0, out: `${JSON.stringify(rows, null, 2)}
82
+ ` };
83
+ if (!rows.length) return { code: 0, out: "no tabs\n" };
84
+ const lines = rows.map(
85
+ (row) => `${row.tab} ${row.cone ?? "-"} ${row.visible ? "visible" : "hidden"} ${row.focused ? "focused" : "-"} ${ago(row.lastActive, now)}`
86
+ );
87
+ return { code: 0, out: `${lines.join("\n")}
88
+ ` };
89
+ }
44
90
  function ownedPages(pages) {
45
91
  const mine = /* @__PURE__ */ new Set();
46
92
  return {
@@ -98,7 +144,9 @@ function createPages(options = {}) {
98
144
  };
99
145
  const choose = (ask) => {
100
146
  const live = [...entries.values()].filter((entry) => entry.tab.kinds.includes(ask.kind));
101
- const named = ask.tab ? live.filter((entry) => entry.tab.tab === ask.tab).sort((a, b) => b.serial - a.serial)[0] : void 0;
147
+ const named = ask.tab ? live.filter(
148
+ (entry) => entry.tab.tab === ask.tab && (ask.agentId === null || entry.tab.cone === ask.cone)
149
+ ).sort((a, b) => b.serial - a.serial)[0] : void 0;
102
150
  if (named) return named;
103
151
  return live.filter((entry) => entry.tab.cone === ask.cone).sort(
104
152
  (a, b) => rank(b) - rank(a) || b.tab.lastActive - a.tab.lastActive || b.serial - a.serial
@@ -189,8 +237,26 @@ function createPages(options = {}) {
189
237
  drop(id);
190
238
  },
191
239
  request,
192
- async command(argv, caller) {
193
- const result = await request({ kind: "panel", argv, ...caller });
240
+ async command(argv, caller, context) {
241
+ const parsed = tabFlag(argv);
242
+ if ("code" in parsed) return parsed;
243
+ sweep();
244
+ const reachable = [...entries.values()].filter(
245
+ (entry) => entry.tab.kinds.includes("panel") && (caller.agentId === null || entry.tab.cone === caller.cone)
246
+ );
247
+ if (parsed.argv[0] === "tabs") return tabsOf(parsed.argv.slice(1), reachable, now());
248
+ if (parsed.tab !== void 0 && !reachable.some((entry) => entry.tab.tab === parsed.tab))
249
+ return noSuchTab(parsed.tab, caller.agentId === null ? null : caller.cone);
250
+ const [verb, id] = parsed.argv;
251
+ if (caller.agentId !== null && verb === "open" && id?.startsWith("sprinkle:"))
252
+ await options.claim?.(id.slice("sprinkle:".length), caller.cone, context);
253
+ const result = await request({
254
+ kind: "panel",
255
+ argv: parsed.argv,
256
+ agentId: caller.agentId,
257
+ cone: caller.cone,
258
+ tab: parsed.tab ?? caller.tab
259
+ });
194
260
  return { code: result.code, out: result.stdout, err: result.stderr };
195
261
  },
196
262
  tabs: () => [...entries.values()].map((entry) => ({ ...entry.tab })),
@@ -210,7 +276,9 @@ export {
210
276
  PICK_MS,
211
277
  createPages,
212
278
  noAnswer,
279
+ noSuchTab,
213
280
  noTab,
214
- ownedPages
281
+ ownedPages,
282
+ tabFlag
215
283
  };
216
284
  //# sourceMappingURL=pages.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/remote/pages.ts"],
4
- "sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { Answer } from '../scoops/service.ts';\nimport { Stream } from './host.ts';\n\nexport const PAGES_IDLE_MS = 30000;\nexport const PICK_MS = 5000;\nexport const ANSWER_MS = 5000;\nexport const MAX_PENDING = 100;\n\nexport interface PageTab {\n tab: string;\n kinds: string[];\n cone: string | null;\n visible: boolean;\n focused: boolean;\n lastActive: number;\n}\n\nexport interface PageCaller {\n agentId: string | null;\n cone: string;\n readOnly?: boolean;\n}\n\nexport interface PageRequest {\n id: string;\n kind: 'panel';\n argv: string[];\n caller: PageCaller;\n}\n\nexport interface PageResult {\n stdout: string;\n stderr: string;\n code: number;\n}\n\nexport type PagesOpened = { stream: string } | { error: string };\n\nexport interface PageBatch {\n requests: PageRequest[];\n done: boolean;\n}\n\nexport interface AgentPages {\n open(tab: PageTab, context: Context): Promise<PagesOpened>;\n report(stream: string, tab: PageTab, context: Context): Promise<void>;\n next(stream: string, waitMs: number, context: Context): Promise<PageBatch>;\n answer(stream: string, id: string, result: PageResult, context: Context): Promise<void>;\n close(stream: string, context: Context): Promise<void>;\n}\n\nexport interface PageAsk {\n kind: 'panel';\n argv: readonly string[];\n agentId: string | null;\n cone: string;\n tab: string | null;\n}\n\nexport interface Pages extends AgentPages {\n request(ask: PageAsk): Promise<PageResult>;\n command(\n argv: readonly string[],\n caller: { agentId: string | null; cone: string; tab: string | null },\n context: Context\n ): Promise<Answer>;\n tabs(): PageTab[];\n dispose(): Promise<void>;\n}\n\nexport interface PagesOptions {\n now?: () => number;\n idleMs?: number;\n sweepMs?: number;\n pickMs?: number;\n answerMs?: number;\n}\n\ninterface Pending {\n stream: string;\n cone: string;\n timer: ReturnType<typeof setTimeout>;\n settle(result: PageResult): void;\n}\n\ninterface Entry {\n id: string;\n stream: Stream<PageRequest>;\n tab: PageTab;\n serial: number;\n}\n\nfunction tabOf(value: PageTab): PageTab {\n return {\n tab: String(value?.tab ?? ''),\n kinds: Array.isArray(value?.kinds) ? value.kinds.map(String) : [],\n cone: typeof value?.cone === 'string' ? value.cone : null,\n visible: value?.visible === true,\n focused: value?.focused === true,\n lastActive: Number.isFinite(value?.lastActive) ? Number(value.lastActive) : 0,\n };\n}\n\nfunction resultOf(value: PageResult): PageResult {\n return {\n stdout: typeof value?.stdout === 'string' ? value.stdout : '',\n stderr: typeof value?.stderr === 'string' ? value.stderr : '',\n code: Number.isInteger(value?.code) ? value.code : 1,\n };\n}\n\nfunction rank(entry: Entry): number {\n if (entry.tab.visible && entry.tab.focused) return 2;\n return entry.tab.visible ? 1 : 0;\n}\n\nexport function noTab(cone: string): PageResult {\n return {\n stdout: '',\n stderr: `panel: no open SLICC tab shows cone ${cone}; open SLICC or switch a tab to ${cone}\\n`,\n code: 3,\n };\n}\n\nexport function noAnswer(cone: string): PageResult {\n return {\n stdout: '',\n stderr: `panel: the tab showing cone ${cone} didn't answer; try again\\n`,\n code: 4,\n };\n}\n\nexport function ownedPages(pages: AgentPages): AgentPages & { release(): void } {\n const mine = new Set<string>();\n return {\n async open(tab, context) {\n const opened = await pages.open(tab, context);\n if ('stream' in opened) mine.add(opened.stream);\n return opened;\n },\n async report(stream, tab, context) {\n if (mine.has(stream)) await pages.report(stream, tab, context);\n },\n async next(stream, waitMs, context) {\n if (!mine.has(stream)) return { requests: [], done: true };\n const batch = await pages.next(stream, waitMs, context);\n if (batch.done) mine.delete(stream);\n return batch;\n },\n async answer(stream, id, result, context) {\n if (mine.has(stream)) await pages.answer(stream, id, result, context);\n },\n async close(stream, context) {\n if (mine.delete(stream)) await pages.close(stream, context);\n },\n release() {\n for (const stream of mine) void pages.close(stream, BACKGROUND_CONTEXT);\n mine.clear();\n },\n };\n}\n\nexport function createPages(options: PagesOptions = {}): Pages {\n const now = options.now ?? Date.now;\n const idleMs = options.idleMs ?? PAGES_IDLE_MS;\n const pickMs = options.pickMs ?? PICK_MS;\n const answerMs = options.answerMs ?? ANSWER_MS;\n const entries = new Map<string, Entry>();\n const pending = new Map<string, Pending>();\n let serial = 0;\n let timer: ReturnType<typeof setInterval> | undefined;\n\n const drop = (id: string) => {\n const entry = entries.get(id);\n if (!entry) return;\n entries.delete(id);\n void entry.stream.finish();\n };\n const sweep = () => {\n for (const [id, entry] of entries) if (now() - entry.stream.touched > idleMs) drop(id);\n if (!entries.size && timer !== undefined) {\n clearInterval(timer);\n timer = undefined;\n }\n };\n const fail = (stream: string) => {\n for (const waiting of [...pending.values()])\n if (waiting.stream === stream) waiting.settle(noAnswer(waiting.cone));\n };\n const choose = (ask: PageAsk): Entry | undefined => {\n const live = [...entries.values()].filter((entry) => entry.tab.kinds.includes(ask.kind));\n const named = ask.tab\n ? live.filter((entry) => entry.tab.tab === ask.tab).sort((a, b) => b.serial - a.serial)[0]\n : undefined;\n if (named) return named;\n return live\n .filter((entry) => entry.tab.cone === ask.cone)\n .sort(\n (a, b) => rank(b) - rank(a) || b.tab.lastActive - a.tab.lastActive || b.serial - a.serial\n )[0];\n };\n const request = (ask: PageAsk): Promise<PageResult> => {\n sweep();\n const entry = choose(ask);\n const cone = entry?.tab.cone ?? ask.cone;\n if (!entry) return Promise.resolve(noTab(cone));\n const id = `p${++serial}-${crypto.randomUUID()}`;\n const item: PageRequest = {\n id,\n kind: ask.kind,\n argv: [...ask.argv],\n caller: { agentId: ask.agentId, cone, readOnly: false },\n };\n return new Promise((resolve) => {\n const settle = (result: PageResult) => {\n const waiting = pending.get(id);\n if (!waiting) return;\n clearTimeout(waiting.timer);\n pending.delete(id);\n const at = entry.stream.queue.indexOf(item);\n if (at >= 0) entry.stream.queue.splice(at, 1);\n resolve(result);\n };\n pending.set(id, {\n stream: entry.id,\n cone,\n timer: setTimeout(() => settle(noAnswer(cone)), pickMs),\n settle,\n });\n entry.stream.push([item]);\n });\n };\n const pages: Pages = {\n async open(tab) {\n sweep();\n const id = `t${++serial}-${crypto.randomUUID()}`;\n const stream = new Stream<PageRequest>(\n async () => {\n entries.delete(id);\n fail(id);\n },\n now(),\n MAX_PENDING,\n []\n );\n entries.set(id, { id, stream, tab: tabOf(tab), serial });\n timer ??= setInterval(sweep, options.sweepMs ?? idleMs / 4);\n return { stream: id };\n },\n async report(id, tab) {\n const entry = entries.get(id);\n if (!entry) return;\n entry.tab = tabOf(tab);\n entry.stream.touched = now();\n },\n async next(id, waitMs, context) {\n const entry = entries.get(id);\n if (!entry) return { requests: [], done: true };\n entry.stream.touched = now();\n const signal = context.abortSignal;\n await entry.stream.wait(Math.max(0, Math.min(waitMs, idleMs / 2)), signal);\n if (signal?.aborted) {\n drop(id);\n signal.throwIfAborted();\n }\n entry.stream.touched = now();\n const requests = entry.stream.queue.splice(0);\n for (const item of requests) {\n const waiting = pending.get(item.id);\n if (!waiting) continue;\n clearTimeout(waiting.timer);\n waiting.timer = setTimeout(() => waiting.settle(noAnswer(waiting.cone)), answerMs);\n }\n const done = entry.stream.done;\n if (done) entries.delete(id);\n return { requests, done };\n },\n async answer(id, request, result) {\n const waiting = pending.get(request);\n if (waiting?.stream !== id) return;\n waiting.settle(resultOf(result));\n },\n async close(id) {\n drop(id);\n },\n request,\n async command(argv, caller) {\n const result = await request({ kind: 'panel', argv, ...caller });\n return { code: result.code, out: result.stdout, err: result.stderr };\n },\n tabs: () => [...entries.values()].map((entry) => ({ ...entry.tab })),\n async dispose() {\n clearInterval(timer);\n timer = undefined;\n const all = [...entries.keys()];\n for (const id of all) drop(id);\n },\n };\n return pages;\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { Answer } from '../scoops/service.ts';\nimport { Stream } from './host.ts';\n\nexport const PAGES_IDLE_MS = 30000;\nexport const PICK_MS = 5000;\nexport const ANSWER_MS = 5000;\nexport const MAX_PENDING = 100;\n\nexport interface PageTab {\n tab: string;\n kinds: string[];\n cone: string | null;\n visible: boolean;\n focused: boolean;\n lastActive: number;\n}\n\nexport interface PageCaller {\n agentId: string | null;\n cone: string;\n readOnly?: boolean;\n}\n\nexport interface PageRequest {\n id: string;\n kind: 'panel';\n argv: string[];\n caller: PageCaller;\n}\n\nexport interface PageResult {\n stdout: string;\n stderr: string;\n code: number;\n}\n\nexport type PagesOpened = { stream: string } | { error: string };\n\nexport interface PageBatch {\n requests: PageRequest[];\n done: boolean;\n}\n\nexport interface AgentPages {\n open(tab: PageTab, context: Context): Promise<PagesOpened>;\n report(stream: string, tab: PageTab, context: Context): Promise<void>;\n next(stream: string, waitMs: number, context: Context): Promise<PageBatch>;\n answer(stream: string, id: string, result: PageResult, context: Context): Promise<void>;\n close(stream: string, context: Context): Promise<void>;\n}\n\nexport interface PageAsk {\n kind: 'panel';\n argv: readonly string[];\n agentId: string | null;\n cone: string;\n tab: string | null;\n}\n\nexport interface Pages extends AgentPages {\n request(ask: PageAsk): Promise<PageResult>;\n command(\n argv: readonly string[],\n caller: { agentId: string | null; cone: string; tab: string | null },\n context: Context\n ): Promise<Answer>;\n tabs(): PageTab[];\n dispose(): Promise<void>;\n}\n\nexport interface PagesOptions {\n now?: () => number;\n idleMs?: number;\n sweepMs?: number;\n pickMs?: number;\n answerMs?: number;\n claim?: (sprinkle: string, cone: string, context: Context) => Promise<void>;\n}\n\ninterface Pending {\n stream: string;\n cone: string;\n timer: ReturnType<typeof setTimeout>;\n settle(result: PageResult): void;\n}\n\ninterface Entry {\n id: string;\n stream: Stream<PageRequest>;\n tab: PageTab;\n serial: number;\n}\n\nfunction tabOf(value: PageTab): PageTab {\n return {\n tab: String(value?.tab ?? ''),\n kinds: Array.isArray(value?.kinds) ? value.kinds.map(String) : [],\n cone: typeof value?.cone === 'string' ? value.cone : null,\n visible: value?.visible === true,\n focused: value?.focused === true,\n lastActive: Number.isFinite(value?.lastActive) ? Number(value.lastActive) : 0,\n };\n}\n\nfunction resultOf(value: PageResult): PageResult {\n return {\n stdout: typeof value?.stdout === 'string' ? value.stdout : '',\n stderr: typeof value?.stderr === 'string' ? value.stderr : '',\n code: Number.isInteger(value?.code) ? value.code : 1,\n };\n}\n\nfunction rank(entry: Entry): number {\n if (entry.tab.visible && entry.tab.focused) return 2;\n return entry.tab.visible ? 1 : 0;\n}\n\nexport function noTab(cone: string): PageResult {\n return {\n stdout: '',\n stderr: `panel: no open SLICC tab shows cone ${cone}; open SLICC or switch a tab to ${cone}\\n`,\n code: 3,\n };\n}\n\nexport function noAnswer(cone: string): PageResult {\n return {\n stdout: '',\n stderr: `panel: the tab showing cone ${cone} didn't answer; try again\\n`,\n code: 4,\n };\n}\n\nexport function noSuchTab(tab: string, cone: string | null): Answer {\n const err =\n cone === null\n ? `panel: there is no open SLICC tab ${tab}; panel tabs lists them\\n`\n : `panel: no open SLICC tab ${tab} shows cone ${cone}; panel tabs lists the ones that do\\n`;\n return { code: 3, out: '', err };\n}\n\nconst usage = (err: string): Answer => ({ code: 2, out: '', err: `panel: ${err}\\n` });\n\nexport function tabFlag(argv: readonly string[]): { argv: string[]; tab?: string } | Answer {\n const rest: string[] = [];\n let tab: string | undefined;\n for (let at = 0; at < argv.length; at++) {\n const arg = argv[at] as string;\n if (arg === '--tab') {\n const value = argv[++at];\n if (!value) return usage('--tab needs a tab id; panel tabs lists them');\n tab = value;\n } else if (arg.startsWith('--tab=')) {\n if (arg === '--tab=') return usage('--tab needs a tab id; panel tabs lists them');\n tab = arg.slice('--tab='.length);\n } else rest.push(arg);\n }\n return tab === undefined ? { argv: rest } : { argv: rest, tab };\n}\n\nfunction ago(lastActive: number, now: number): string {\n return lastActive ? `${Math.max(0, Math.round((now - lastActive) / 1000))}s ago` : 'never';\n}\n\nfunction tabsOf(argv: readonly string[], reachable: Entry[], now: number): Answer {\n const json = argv.includes('--json');\n if (argv.some((arg) => arg !== '--json')) return usage('usage: panel tabs [--json]');\n const rows = reachable\n .sort((a, b) => rank(b) - rank(a) || b.tab.lastActive - a.tab.lastActive || b.serial - a.serial)\n .map(({ tab }) => ({\n tab: tab.tab,\n cone: tab.cone,\n visible: tab.visible,\n focused: tab.focused,\n lastActive: tab.lastActive,\n }));\n if (json) return { code: 0, out: `${JSON.stringify(rows, null, 2)}\\n` };\n if (!rows.length) return { code: 0, out: 'no tabs\\n' };\n const lines = rows.map(\n (row) =>\n `${row.tab}\\t${row.cone ?? '-'}\\t${row.visible ? 'visible' : 'hidden'}\\t${row.focused ? 'focused' : '-'}\\t${ago(row.lastActive, now)}`\n );\n return { code: 0, out: `${lines.join('\\n')}\\n` };\n}\n\nexport function ownedPages(pages: AgentPages): AgentPages & { release(): void } {\n const mine = new Set<string>();\n return {\n async open(tab, context) {\n const opened = await pages.open(tab, context);\n if ('stream' in opened) mine.add(opened.stream);\n return opened;\n },\n async report(stream, tab, context) {\n if (mine.has(stream)) await pages.report(stream, tab, context);\n },\n async next(stream, waitMs, context) {\n if (!mine.has(stream)) return { requests: [], done: true };\n const batch = await pages.next(stream, waitMs, context);\n if (batch.done) mine.delete(stream);\n return batch;\n },\n async answer(stream, id, result, context) {\n if (mine.has(stream)) await pages.answer(stream, id, result, context);\n },\n async close(stream, context) {\n if (mine.delete(stream)) await pages.close(stream, context);\n },\n release() {\n for (const stream of mine) void pages.close(stream, BACKGROUND_CONTEXT);\n mine.clear();\n },\n };\n}\n\nexport function createPages(options: PagesOptions = {}): Pages {\n const now = options.now ?? Date.now;\n const idleMs = options.idleMs ?? PAGES_IDLE_MS;\n const pickMs = options.pickMs ?? PICK_MS;\n const answerMs = options.answerMs ?? ANSWER_MS;\n const entries = new Map<string, Entry>();\n const pending = new Map<string, Pending>();\n let serial = 0;\n let timer: ReturnType<typeof setInterval> | undefined;\n\n const drop = (id: string) => {\n const entry = entries.get(id);\n if (!entry) return;\n entries.delete(id);\n void entry.stream.finish();\n };\n const sweep = () => {\n for (const [id, entry] of entries) if (now() - entry.stream.touched > idleMs) drop(id);\n if (!entries.size && timer !== undefined) {\n clearInterval(timer);\n timer = undefined;\n }\n };\n const fail = (stream: string) => {\n for (const waiting of [...pending.values()])\n if (waiting.stream === stream) waiting.settle(noAnswer(waiting.cone));\n };\n const choose = (ask: PageAsk): Entry | undefined => {\n const live = [...entries.values()].filter((entry) => entry.tab.kinds.includes(ask.kind));\n const named = ask.tab\n ? live\n .filter(\n (entry) =>\n entry.tab.tab === ask.tab && (ask.agentId === null || entry.tab.cone === ask.cone)\n )\n .sort((a, b) => b.serial - a.serial)[0]\n : undefined;\n if (named) return named;\n return live\n .filter((entry) => entry.tab.cone === ask.cone)\n .sort(\n (a, b) => rank(b) - rank(a) || b.tab.lastActive - a.tab.lastActive || b.serial - a.serial\n )[0];\n };\n const request = (ask: PageAsk): Promise<PageResult> => {\n sweep();\n const entry = choose(ask);\n const cone = entry?.tab.cone ?? ask.cone;\n if (!entry) return Promise.resolve(noTab(cone));\n const id = `p${++serial}-${crypto.randomUUID()}`;\n const item: PageRequest = {\n id,\n kind: ask.kind,\n argv: [...ask.argv],\n caller: { agentId: ask.agentId, cone, readOnly: false },\n };\n return new Promise((resolve) => {\n const settle = (result: PageResult) => {\n const waiting = pending.get(id);\n if (!waiting) return;\n clearTimeout(waiting.timer);\n pending.delete(id);\n const at = entry.stream.queue.indexOf(item);\n if (at >= 0) entry.stream.queue.splice(at, 1);\n resolve(result);\n };\n pending.set(id, {\n stream: entry.id,\n cone,\n timer: setTimeout(() => settle(noAnswer(cone)), pickMs),\n settle,\n });\n entry.stream.push([item]);\n });\n };\n const pages: Pages = {\n async open(tab) {\n sweep();\n const id = `t${++serial}-${crypto.randomUUID()}`;\n const stream = new Stream<PageRequest>(\n async () => {\n entries.delete(id);\n fail(id);\n },\n now(),\n MAX_PENDING,\n []\n );\n entries.set(id, { id, stream, tab: tabOf(tab), serial });\n timer ??= setInterval(sweep, options.sweepMs ?? idleMs / 4);\n return { stream: id };\n },\n async report(id, tab) {\n const entry = entries.get(id);\n if (!entry) return;\n entry.tab = tabOf(tab);\n entry.stream.touched = now();\n },\n async next(id, waitMs, context) {\n const entry = entries.get(id);\n if (!entry) return { requests: [], done: true };\n entry.stream.touched = now();\n const signal = context.abortSignal;\n await entry.stream.wait(Math.max(0, Math.min(waitMs, idleMs / 2)), signal);\n if (signal?.aborted) {\n drop(id);\n signal.throwIfAborted();\n }\n entry.stream.touched = now();\n const requests = entry.stream.queue.splice(0);\n for (const item of requests) {\n const waiting = pending.get(item.id);\n if (!waiting) continue;\n clearTimeout(waiting.timer);\n waiting.timer = setTimeout(() => waiting.settle(noAnswer(waiting.cone)), answerMs);\n }\n const done = entry.stream.done;\n if (done) entries.delete(id);\n return { requests, done };\n },\n async answer(id, request, result) {\n const waiting = pending.get(request);\n if (waiting?.stream !== id) return;\n waiting.settle(resultOf(result));\n },\n async close(id) {\n drop(id);\n },\n request,\n async command(argv, caller, context) {\n const parsed = tabFlag(argv);\n if ('code' in parsed) return parsed;\n sweep();\n const reachable = [...entries.values()].filter(\n (entry) =>\n entry.tab.kinds.includes('panel') &&\n (caller.agentId === null || entry.tab.cone === caller.cone)\n );\n if (parsed.argv[0] === 'tabs') return tabsOf(parsed.argv.slice(1), reachable, now());\n if (parsed.tab !== undefined && !reachable.some((entry) => entry.tab.tab === parsed.tab))\n return noSuchTab(parsed.tab, caller.agentId === null ? null : caller.cone);\n const [verb, id] = parsed.argv;\n if (caller.agentId !== null && verb === 'open' && id?.startsWith('sprinkle:'))\n await options.claim?.(id.slice('sprinkle:'.length), caller.cone, context);\n const result = await request({\n kind: 'panel',\n argv: parsed.argv,\n agentId: caller.agentId,\n cone: caller.cone,\n tab: parsed.tab ?? caller.tab,\n });\n return { code: result.code, out: result.stdout, err: result.stderr };\n },\n tabs: () => [...entries.values()].map((entry) => ({ ...entry.tab })),\n async dispose() {\n clearInterval(timer);\n timer = undefined;\n const all = [...entries.keys()];\n for (const id of all) drop(id);\n },\n };\n return pages;\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["request"]
7
7
  }
@@ -344,20 +344,9 @@ function panelCaller(request, who) {
344
344
  const agentId = who.scoop ?? (who.fromAgent ? who.cone : null);
345
345
  return { agentId, cone: who.cone, tab: agentId === null ? request.tab ?? null : null };
346
346
  }
347
- const ALIASES = /* @__PURE__ */ new Set(["open", "close"]);
348
- function panelArgv(request) {
349
- if (request.as === "panel") return request.argv;
350
- const [verb, name, ...rest] = request.argv;
351
- if (request.as !== "sprinkle" || !ALIASES.has(verb ?? "")) return void 0;
352
- if (!name) return [verb];
353
- return [verb, name.startsWith("sprinkle:") ? name : `sprinkle:${name}`, ...rest];
354
- }
355
347
  async function dispatch(deps, request, who, context) {
356
- const forwarded = panelArgv(request);
357
- if (forwarded)
358
- return deps.panel ? deps.panel(forwarded, panelCaller(request, who), context) : { code: 1, out: "panel: panels are not available in this agent\n" };
359
- if (request.as === "sprinkle")
360
- return deps.sprinkle ? deps.sprinkle(request.argv, who.id, context) : fail("sprinkles are not available in this agent");
348
+ if (request.as === "panel")
349
+ return deps.panel ? deps.panel(request.argv, panelCaller(request, who), context) : { code: 1, out: "panel: panels are not available in this agent\n" };
361
350
  if (request.as === "memory")
362
351
  return deps.memory ? deps.memory(request.argv, who.id, context) : fail("memory is not available in this agent");
363
352
  if (request.as === "gelatiere")
@@ -392,7 +381,7 @@ function createCli(options) {
392
381
  const deps = { ...options, now: options.now ?? Date.now, sync: { pending: /* @__PURE__ */ new Map() } };
393
382
  return {
394
383
  blocking(request) {
395
- if (panelArgv(request)) return true;
384
+ if (request.as === "panel") return true;
396
385
  const first = request.argv[0] ?? "";
397
386
  if (BLOCKING.has(first)) return true;
398
387
  return request.as === "agent" && !VERBS[first] && !request.argv.includes("--async");