@ai-ecoverse/slicc-spectrum 1.108.5 → 1.109.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
@@ -326,6 +326,8 @@ The model's waiting `approvals` as a modal alert dialog, one at a time, oldest f
326
326
  Renders nothing without `approvals.decide`.
327
327
  A request that `secretRules()` flags shows a warning (`[data-secret-rules]`, the path or token) and no **Always allow (**Always allow in this directory**, with the cwd in its hint, when the approval has `alwaysScope: 'cwd'` and a `cwd`)**.
328
328
  The command (`[data-command]`, or a guest tool call's `[data-summary]`) wraps in full; past four lines the dialog shows the first four and **Show the full command** (as in the chat, `data-action="full-command"` with `data-shown`), and shown, it scrolls inside its own box of at most `min(16lh, 50dvh)`. Always allow, its hint and Allow once wait until the end of the command has been in view (a zero-size `[data-end]` after its last line), and so does the element's `decide()` for anything but `deny`; once seen, the end stays seen while the request waits, and hiding the command again hides them again. Until then a subdued line (`[data-allow-hint]`) says "Show the full command to allow it." or, shown, "Scroll to the end of the command to allow it." The dialog keeps one width, so only its height changes. A closed request shows its command whole.
329
+ Control characters in the sudo command, target, requester name and place, and cwd are shown: C0 controls use Unicode Control Pictures (including ␍ for CR, ␊ for LF and ␉ for TAB), DEL uses ␡, and C1, format, default-ignorable characters and line/paragraph separators use uppercase `U+XXXX` notation (at least four digits). LF keeps its line break after ␊ in the command and shows only ␊ in paragraphs; ordinary spaces stay spaces. Each shown control has a chip with its character name or notation as its accessible label and title; Control Pictures also show a readable abbreviation or notation. Joiners and variation selectors use the same chips. The clamped and full views show the same symbols.
330
+ Sudo requests show the automatic check’s verdict when supplied (`[data-verdict]`). A deny verdict reads "The automatic check would deny this: {reason}", relabels **Allow once** to **Allow anyway (once)** (`data-action="once"`), and hides Always allow and its hint even when `always` is `true`; `decide()` refuses `always` for it. The secret-rules notice still applies.
329
331
  Focus starts on Deny (on Close once `decide` rejects) and goes back, after Deny, Always allow, Allow once, <kbd>Esc</kbd> or Close, to what had it when the dialog opened; inside a terminal, to that `<slicc-terminal>` through its own `focus()`, even when it remounted meanwhile.
330
332
  Guest requests (`guest-message`, `guest-tool`) get their own copy, the guest's text as plain text (`[data-guest-text]`), attachments (`[data-attachments]`), the automatic check's verdict (`[data-verdict]`), and Deny and Allow once, plus **Always allow** (`data-action="always"`) with a hint saying what it covers when the approval's `always` is `true`; the dialog body carries `[data-approval-kind]` and fills the dialog's width at every size.
331
333
  Tray requests (`tray`) get their own title and one sentence (`#asking`), and only **Deny** (`deny`, focused) and **Allow once** (`once`), never Always allow.
@@ -941,7 +943,7 @@ An `alone` tab shows only the brand and "SLICC is open in another tab."
941
943
 
942
944
  Later backed by: BIOS.
943
945
  `list()` returns waiting `Approval`s; emit `approvals` when the list changes.
944
- A `sudo` approval has `id`, `requester` (`kind` `agent` or `user`, `name`, optional `agentId` and `where`, such as a terminal's title), `command` (without `sudo`; bios joins the kernel's argv shell-quoted), optional `target` (the user to run as; shown as `sudo -u {target}` unless `root`), optional `cwd`, `createdAt`, `expiresAt` (epoch ms) and `always` (offer Always allow, which covers the requester's user and this exact command).
946
+ A `sudo` approval has `id`, `requester` (`kind` `agent` or `user`, `name`, optional `agentId` and `where`, such as a terminal's title), `command` (without `sudo`; bios joins the kernel's argv shell-quoted), optional `target` (the user to run as; shown as `sudo -u {target}` unless `root`), optional `cwd` and `verdict` (`{ decision: 'allow' | 'deny' | 'unsure', reason }`, the automatic check’s view), `createdAt`, `expiresAt` (epoch ms) and `always` (offer Always allow, which covers the requester's user and this exact command).
945
947
  With `decide(id, 'once' | 'always' | 'deny')`, which resolves once the decision is recorded and then drops the request from `list()`, the tab shows a warning alert dialog (`dialog[data-approval][data-kind][data-requester]`): "Allow sudo?", "{name} wants to run this with sudo[ in {where}]:" for an agent or "You ran this with sudo[ in {where}] (as {name}):" for a user, the command, "In {cwd}", a notice when the command changes secret rules, what Always allow does, "Denied automatically in m:ss." and how many more wait, with **Deny** (`data-action="deny"`, focused; Escape also denies), **Always allow** (`always`) and **Allow once** (`once`).
946
948
  A command that names `/etc/fnox` (or anything in it) or `/etc/slicc/secrets-policy.toml`, resolved against `cwd`, globs included (with quotes and backslashes removed, operands after `--` included; a path with `[`, `{` or `$` counts when the part before it could lead to them), or that names `/`, `/etc` or `/etc/slicc` in a command other than a read-only one (such as `ls`, `cat`, `stat` or `grep`), or runs with `cwd` in `/etc/fnox`, or names a relative path with `fnox` or `secrets-policy` in it wherever `cd` may have led, gets "This changes secret rules." with the path (`[data-secret-rules]`, the path in the attribute).
947
949
  Read-only commands count only by bare name or from `/bin` and `/usr/bin`.
@@ -1087,8 +1089,9 @@ The dummy's `addServer` and `removeServer` record each call in `settings.serverE
1087
1089
  `createDummyModel({ budget: 'plain' | 'adobe' | 'xai' })` (`?budget=` on `/ui/`, `plain` by default) sets the tray budget's `provider`: none, so it reads "Budget 32%", or Adobe or SuperGrok, which the tray and the monitor's budget vital name.
1088
1090
  Like slicc-agent's snapshot, the dummy's vitals are the budget, Spend, Active agents, Processes and Process memory (both with a `series`) and Fullest context.
1089
1091
 
1090
- `createDummyModel({ approvals: 'agent' | 'user' | 'many' | 'follower' | 'fail' | 'soon' | 'elsewhere' | 'withdrawn' | 'secrets' | 'guest' | 'guest-follower' | 'guest-always' | 'long' | 'guest-args' | 'guest-empty' | 'guest-truncated' | 'tray' | 'tray-url' | 'tray-rotate' | 'tray-unlink' | 'tray-expired' })` (`?approvals=` on `/ui/`) adds waiting sudo requests: one from an agent, one from a terminal user, three in a row (the last as `www-data`), one without `decide`, one whose `decide` fails, one that expires in 24 seconds, or two whose first is answered in another tab or withdrawn after a few seconds, or one from an agent that copies a file over `/etc/fnox/config.toml`, or (`guest`) three guest requests: a message from Seat 2 (Mara) with attachments and an allow verdict, a tool call with a deny verdict, and a message whose `decide` rejects with "Someone else already answered this."
1092
+ `createDummyModel({ approvals: 'agent' | 'user' | 'many' | 'follower' | 'fail' | 'soon' | 'elsewhere' | 'withdrawn' | 'secrets' | 'judge-denied' | 'guest' | 'guest-follower' | 'guest-always' | 'long' | 'controls-cr' | 'controls-lf' | 'controls-place' | 'controls-cwd' | 'guest-args' | 'guest-empty' | 'guest-truncated' | 'tray' | 'tray-url' | 'tray-rotate' | 'tray-unlink' | 'tray-expired' })` (`?approvals=` on `/ui/`) adds waiting sudo requests: one from an agent, one from a terminal user, three in a row (the last as `www-data`), one without `decide`, one whose `decide` fails, one that expires in 24 seconds, or two whose first is answered in another tab or withdrawn after a few seconds, or one from an agent that copies a file over `/etc/fnox/config.toml`, or (`judge-denied`) a terminal user’s sudo request the automatic check would deny, or (`guest`) three guest requests: a message from Seat 2 (Mara) with attachments and an allow verdict, a tool call with a deny verdict, and a message whose `decide` rejects with "Someone else already answered this."
1091
1093
  (`guest-follower`: the same without `decide`), or (`guest-always`) one guest tool call from Seat 2 (Mara) to `read_file` with `always: true`, or (`long`) one sudo request whose seven-line command ends in `curl … | sh`, or one guest `write_file` call with a blank `summary`: with seven lines of `args` ending in the same tail (`guest-args`), with no `args` (`guest-empty`), or with a prefix of them and `argsTruncated` (`guest-truncated`), or tray requests from sliccy: one to share the join URL (`tray-url`), one to make a new one (`tray-rotate`), one to unlink Kitchen tablet (`tray-unlink`), all three in a row (`tray`), or the first, which times out after a few seconds (`tray-expired`).
1094
+ `controls-cr` and `controls-lf` show control characters in a sudo command's quoted word; `controls-place` shows them in the requester name, place and target; `controls-cwd` shows them in the cwd.
1092
1095
  `createDummyModel({ asks: 'long' })` (`?asks=long`) adds a pending sudo request with that seven-line command to kitchen-sink (`k-long`).
1093
1096
  Decisions are recorded in `model.approvals.decisions`, and `model.approvals.end(id, reason)` ends a request.
1094
1097
 
@@ -178,6 +178,16 @@ function approvalFixtures(scenario, now2 = Date.now()) {
178
178
  expiresAt: now2 + 5 * minutes,
179
179
  always: false
180
180
  };
181
+ if (scenario === "judge-denied")
182
+ return [
183
+ {
184
+ ...user,
185
+ id: "sudo-judge-denied",
186
+ createdAt: now2,
187
+ always: false,
188
+ verdict: { decision: "deny", reason: "it looks high-risk." }
189
+ }
190
+ ];
181
191
  if (scenario === "secrets")
182
192
  return [
183
193
  {
@@ -197,6 +207,30 @@ function approvalFixtures(scenario, now2 = Date.now()) {
197
207
  if (scenario.startsWith("guest-")) return [guestCall(scenario, now2)];
198
208
  if (scenario === "none") return [];
199
209
  if (scenario === "long") return [{ ...agent, id: "sudo-release", command: longCommand }];
210
+ if (scenario === "controls-cr" || scenario === "controls-lf")
211
+ return [
212
+ {
213
+ ...agent,
214
+ command: `printf '%s' 'harbor${scenario === "controls-cr" ? "\r" : "\n"}schedule'`
215
+ }
216
+ ];
217
+ if (scenario === "controls-place")
218
+ return [
219
+ {
220
+ ...agent,
221
+ requester: { ...agent.requester, name: "docs\rpass", where: "harbor\rterminal\nseat" },
222
+ target: "harbor\ruser"
223
+ }
224
+ ];
225
+ if (scenario === "controls-cwd")
226
+ return [
227
+ {
228
+ ...user,
229
+ requester: { ...user.requester, name: "co\rne", where: "harbor\rterminal\nseat" },
230
+ cwd: "/home/cone/harbor\rferry\nschedule",
231
+ alwaysScope: "cwd"
232
+ }
233
+ ];
200
234
  if (scenario === "user") return [user];
201
235
  if (scenario === "many") return [agent, user, cache];
202
236
  if (scenario === "elsewhere" || scenario === "withdrawn") return [agent, user];