@ai-ecoverse/slicc-spectrum 1.108.1 → 1.108.3

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
@@ -462,7 +462,7 @@ Settings › Secrets from the model's `vault`.
462
462
  It never shows a value or a placeholder.
463
463
  Value fields are `type=password` with no reveal toggle, are read once on submit and cleared at once (on success, refusal, error, cancel, close and disconnect), and are checked before the vault is called: under 8 UTF-8 bytes, CR, LF or NUL, or containing `fnox_proxy_` are refused with the vault's own wording.
464
464
  Values go only to `vault.put` and are never kept on the element or put in an event.
465
- The head shows **Locked** or **Unlocked** and the lock mode ("Unlocks automatically in this browser", "Unlocks with a passkey" or "Unlocks with a passphrase"); locked, the vault's **Unlock** button (`slicc-vault-button[data-action=unlock]`); unlocked, **Lock** (`data-action="lock"`, with `lock`) and the vault's **Protect with a passkey** (lock `auto`) or **Change protection** button (`data-action="protect"`).
465
+ The head shows **Locked** or **Unlocked**, then, when `status.policy` marks a file `paused`, a second light (`[data-paused]`) "Paused: {file} is missing" ("Paused: {file} and 1 more are missing" for both), and the lock mode ("Unlocks automatically in this browser", "Unlocks with a passkey" or "Unlocks with a passphrase"); locked, the vault's **Unlock** button (`slicc-vault-button[data-action=unlock]`); unlocked, **Lock** (`data-action="lock"`, with `lock`) and the vault's **Protect with a passkey** (lock `auto`) or **Change protection** button (`data-action="protect"`).
466
466
  A status line (`[data-availability]`) says "Waiting for the vault" while `availability()` is `connecting` or `waiting` (or `status()` is `null` without it), and "Unlock the vault to continue" while `scrub.needed` and not `scrub.ready`.
467
467
  Waiting requests show under **Waiting for you** (`[data-request]`, the agent's `prompt` as plain text under "From the agent, not checked by SLICC:", capped at 200 characters, and "Expires in N min"), with **Enter value** (`data-action="answer"`, which fires `value-request` with `{ id, vault }` for the `<slicc-value-request>` on the same vault) for `value` requests and **Cancel request** (`data-action="cancel-request"`); `oauth`, `jerk-seal`, `jerk` and `unseal` requests say what they ask for and offer Cancel request only.
468
468
  With `backupReminder: 'due'`, an alert (`[data-backup]`) offers **Export backup** (`data-action="export"`) and **Not now** (`data-action="dismiss-backup"`, with `dismissBackupReminder`).
@@ -470,9 +470,9 @@ With `backupReminder: 'due'`, an alert (`[data-backup]`) offers **Export backup*
470
470
  Saved shows "Saved NAME in the vault" (`[data-said]`).
471
471
  The secrets, sorted by name (`li[data-secret][data-state]`, with `[data-rules]`, `[data-exits]` only when restricted, `[data-exec]` (any command, the listed commands, every bash) and how often programs were given it today, `[data-source]`, `[data-used]`, `[data-expires]`; a model record or an MCP token no rule names reads “Used for” (`[data-used-for]`, model requests to its provider or requests to its MCP server, by the agent) instead of where it's sent, with its account's state as its light, and shows its Provider (`[data-provider]`, the account's name) or Server (`[data-server]`)) offer **Replace value** (`data-action="replace"`, for `settings`, `process` and `import:*` secrets that aren't sign-ins) and **Remove** (`data-action="remove"`, behind a confirmation, passing the secret's `kind`), and removed ones, under **Removed**, **Restore** (`data-action="restore"`; ENOENT reads "Removed too long ago to restore").
472
472
  Locked, every form (Add secret, Replace value, Import, Export) says "Unlock the vault first" (`p[data-locked]`) next to the vault's own small **Unlock** button (`slicc-vault-button[data-action=unlock]`) and disables its submit; once unlocked, the form stays open with what was typed and its submit enables.
473
- Vault errors show their message, EACCES as "Unlock the vault first" and ENOTSUP as "This arrives with a later vault version".
473
+ Vault errors show their message, EACCES as "Unlock the vault first", an EACCES with `cause: 'policy-paused'` as "Secrets are paused until the missing policy file is back", and ENOTSUP as "This arrives with a later vault version".
474
474
  Each action shows only when the port has its method.
475
- Then **Rules SLICC refused** (`[data-refused]`), where the rules live (`[data-policy]`) and **Activity** (`ol.audit li[data-seq][data-type]`; an entry with `uid` and `tag` both `null` reads "by you", a `refresh` entry "Refreshed automatically" (with the sign-in it used), an `endpoints` entry (vault-originated, no "by …") one part per field it carries: (1.91.0's `EndpointsEntry` had a required `purged` with `url`; no vault wrote it before 1.13.0, so the shape was corrected rather than kept, with `purged` optional and `host` replacing `url`) `purged` "Removed custom model URLs an agent set, automatically: {provider name} at {host}, …. Only you can set a model URL now, in Settings › Accounts" (the provider's name from `settings.accounts()`, else its id), `adopted` "Kept the MCP servers your tokens use, automatically: {server} at {host}, …", `pinned` "{name} pinned to {host} automatically, on first use" with **Unpin** (`data-action=unpin`, calling the vault port's optional `unpin([name])`; disabled while the vault is locked; a failure shows in the row as `[data-error=unpin]`, in the same words as other vault failures; it's hidden once a newer `unpinned` entry for that name is in the log), and `unpinned` "{name} unpinned from {host}; the next use pins it again", an `mcp` entry "Sent to the MCP server SERVER at DOMAIN" with its request and exit, a `session` entry (a value the vault handed the kernel for a verified TLS session, vault 1.15.0) "Sent over {HTTP/1.1, SMTP or Postgres} to {domain}:{port}, {trusted by public roots, or trusted by its pinned anchor}, through {exit}" (no trust part when an older entry has no `verifiedBy` or a newer vault sends one spectrum doesn't know; a protocol it doesn't know reads as its raw name), and a policy entry lists its changes, its warning and, when accepted, how to change the file back; **Only reveals to programs**, `data-action="reveals"`, and **Show older**, `data-action="older"`).
475
+ Then **Rules SLICC refused** (`[data-refused]`), where the rules live (`[data-policy]`) and **Activity** (`ol.audit li[data-seq][data-type]`; an entry with `uid` and `tag` both `null` reads "by you", a `refresh` entry "Refreshed automatically" (with the sign-in it used), an `endpoints` entry (vault-originated, no "by …") one part per field it carries: (1.91.0's `EndpointsEntry` had a required `purged` with `url`; no vault wrote it before 1.13.0, so the shape was corrected rather than kept, with `purged` optional and `host` replacing `url`) `purged` "Removed custom model URLs an agent set, automatically: {provider name} at {host}, …. Only you can set a model URL now, in Settings › Accounts" (the provider's name from `settings.accounts()`, else its id), `adopted` "Kept the MCP servers your tokens use, automatically: {server} at {host}, …", `pinned` "{name} pinned to {host} automatically, on first use" with **Unpin** (`data-action=unpin`, calling the vault port's optional `unpin([name])`; disabled while the vault is locked; a failure shows in the row as `[data-error=unpin]`, in the same words as other vault failures; it's hidden once a newer `unpinned` entry for that name is in the log), and `unpinned` "{name} unpinned from {host}; the next use pins it again", an `mcp` entry "Sent to the MCP server SERVER at DOMAIN" with its request and exit, a `session` entry (a value the vault handed the kernel for a verified TLS session, vault 1.15.0) "Sent over {HTTP/1.1, SMTP or Postgres} to {domain}:{port}, {trusted by public roots, or trusted by its pinned anchor}, through {exit}" (no trust part when an older entry has no `verifiedBy` or a newer vault sends one spectrum doesn't know; a protocol it doesn't know reads as its raw name), and a policy entry lists its changes, its warning and, when accepted, how to change the file back, except that an entry with `absent` reads "{file} was removed. Secrets are paused until it’s back." and the accepted entry that ends its pause reads "{file} is back. Secrets are running again." ("Secrets stay paused until the other file is back." while the other file is still missing), neither with the way back; **Only reveals to programs**, `data-action="reveals"`, and **Show older**, `data-action="older"`).
476
476
  The section's `data-vault` is `locked`, `unlocked` or `loading`.
477
477
  A popup the browser blocked shows how to allow it (`[data-popup=blocked]`).
478
478
  Widened-rule notices aren't shown.
@@ -912,7 +912,7 @@ Later backed by: BIOS.
912
912
  `list()` returns `Notice`s for quiet, dismissible in-line notices at the top of every chat panel, above the transcript, in list order: `id`, `tone` (`info` reads as informative, `warning` as a notice), `title`, a plain-text `body` and `actions` (`{ id, label }`).
913
913
  Title, body and labels are text only.
914
914
  Notices use `role="status"` and never take focus.
915
- An action is a secondary button that stays pending until `act(id, action)` settles; a rejection shows its message under the body.
915
+ An action is a secondary button that stays pending until `act(id, action)` settles; a rejection shows its message under the body (`[data-error]`), in the notice's text colour after a warning icon in the notice's tone.
916
916
  The close button, labelled "Dismiss: <title>", hides the notice at once and calls `dismiss(id)` synchronously; it shows again only if the port drops the notice from `list()` and brings it back later.
917
917
  Emit `notices` whenever they change.
918
918
  A notice with `dismissible: false` has no close button and stays until the port drops it.
@@ -1037,7 +1037,7 @@ New join URL changes the URL, and `model.network.setLinks()` switches scenarios.
1037
1037
  `guestsFixtures`, `guestsPolicy`, `guestsUnavailable`, `guestsRefused` and `DummyGuests` are exported from `/dummy`.
1038
1038
  `createDummyModel({ changes: 'files' | 'git' | 'nogit' })` (or `?changes=` on `/ui/`, default `files`) adds a git `changes` port: `git` lists the pending changes under `/workspace/harbor` and `/workspace/skills` with their `repo` and no author, and `nogit` reports git as unavailable.
1039
1039
  `DummyChanges` is exported from `/dummy`.
1040
- `createDummyModel({ notices: 'storage' | 'mixed' | 'fail' | 'off' })` (or `?notices=` on `/ui/`, off by default) adds an invented storage warning with Try again, which clears it after a short wait (`mixed` adds an informative notice without actions, and `fail` makes Try again fail).
1040
+ `createDummyModel({ notices: 'storage' | 'mixed' | 'fail' | 'off' })` (or `?notices=` on `/ui/`, off by default) adds an invented storage warning with Try again, which clears it after a short wait (`mixed` adds an informative notice without actions, and `fail` adds an informative backup notice with Download and makes both actions fail).
1041
1041
  `noticeFixtures` and `DummyNotices` are exported from `/dummy`.
1042
1042
  `createDummyModel({ browser: 'idle' | 'driving' | 'off' })` (or `?browser=` on `/ui/`, default `idle`) sets the dummy browser: `idle` has a history of invented actions (about 180 on harbor's tab, enough for Show more) and no driven tab, `driving` has harbor and quiet-otter driving two tabs, with harbor's last click still running and frames every 500 ms while watched, and `off` has no tabs.
1043
1043
  Stopping an agent releases its tabs.
@@ -1089,7 +1089,7 @@ Like slicc-agent's snapshot, the dummy's vitals are the budget, Spend, Active ag
1089
1089
  `createDummyModel({ asks: 'long' })` (`?asks=long`) adds a pending sudo request with that seven-line command to kitchen-sink (`k-long`).
1090
1090
  Decisions are recorded in `model.approvals.decisions`, and `model.approvals.end(id, reason)` ends a request.
1091
1091
 
1092
- `createDummyModel({ vault: 'empty' | 'secrets' | 'policy' | 'locked' | 'request' | 'backup' | 'waiting' | 'purged' | 'session' | 'endpoints-fail' | 'off' })` (`?vault=` on `/ui/`, off by default; `notice` is kept as another name for `policy`) adds an invented vault: no secrets yet; five secrets (an API key, a jerk lease from pier-nuc revealed to `pier publish`, a Tide Mail sign-in, one without a rule and a removed one) with an activity log that pages back once; the same with a refused rule and a policy change in the log; locked before the first unlock, with a waiting request from docs-pass; unlocked with a `fnox set` request for `TIDE_STATION_TOKEN`; the secrets with a due backup reminder; or a vault that hasn't answered yet (`model.vault.arrive()` brings it); Cloudflare's Account ID and AI Gateway ID and Azure's endpoint carry `vaultSetting`s; the dummy vault keeps `settings` on its records, logs each `settings` call in `model.vault.settingsCalls`, and refuses a setting whose value starts with `bad` (“The vault refused {KEY}. Check that value and try again.”). `endpoints-fail` is the secrets with an `endpoints` that refuses (an MCP URL with “The vault refused {url} for this token. Check the server's address, then try again.”, a model URL with “The vault refused that endpoint. Check the address and try again.”). The dummy vault records each `endpoints` change in `model.vault.endpointChanges`.
1092
+ `createDummyModel({ vault: 'empty' | 'secrets' | 'policy' | 'locked' | 'paused' | 'request' | 'backup' | 'waiting' | 'purged' | 'session' | 'endpoints-fail' | 'off' })` (`?vault=` on `/ui/`, off by default; `notice` is kept as another name for `policy`) adds an invented vault: no secrets yet; five secrets (an API key, a jerk lease from pier-nuc revealed to `pier publish`, a Tide Mail sign-in, one without a rule and a removed one) with an activity log that pages back once; the same with a refused rule and a policy change in the log; locked before the first unlock, with a waiting request from docs-pass; the secrets with `/etc/slicc/secrets-policy.toml` missing and an earlier pause of `/etc/fnox/config.toml` in the log; unlocked with a `fnox set` request for `TIDE_STATION_TOKEN`; the secrets with a due backup reminder; or a vault that hasn't answered yet (`model.vault.arrive()` brings it); Cloudflare's Account ID and AI Gateway ID and Azure's endpoint carry `vaultSetting`s; the dummy vault keeps `settings` on its records, logs each `settings` call in `model.vault.settingsCalls`, and refuses a setting whose value starts with `bad` (“The vault refused {KEY}. Check that value and try again.”). `endpoints-fail` is the secrets with an `endpoints` that refuses (an MCP URL with “The vault refused {url} for this token. Check the server's address, then try again.”, a model URL with “The vault refused that endpoint. Check the address and try again.”). The dummy vault records each `endpoints` change in `model.vault.endpointChanges`.
1093
1093
  `purged` is `secrets` plus two `endpoints` audit entries: one with `purged` and `adopted`, and one `pinned` (`DOCS_MCP_TOKEN` on docs.example) that Unpin turns into an `unpinned` entry; `vaultPurged` and `vaultPinned` are exported. `session` is `secrets` plus three `session` audit entries (`vaultSessions`, exported): SMTP trusted by public roots, Postgres trusted by a pinned anchor through pier-nuc, and HTTP/1.1 with no `verifiedBy`.
1094
1094
  It implements every op with the vault's checks, and keeps only names: `model.vault.puts` records `{ name, request? }`, `cancelled` the cancelled requests, `imports` each import's kind, size and pick, and `exported` the exports.
1095
1095
  Import offers five invented candidates (one replaces a secret, one is a model key, one is refused with a reason that the done stage repeats; KeePass adds a `_2` duplicate), six answers ENOTSUP, page ops are recorded with `uid: null, tag: null`, and value ops while locked answer EACCES.
@@ -10,17 +10,21 @@ function valueProblem(value) {
10
10
  function nameProblem(name) {
11
11
  return /^[A-Z_][A-Z0-9_]*$/.test(name) ? null : "Names use A to Z, 0 to 9 and _, and don't start with a digit";
12
12
  }
13
- function vaultFailure(code, message) {
14
- return Object.assign(new Error(message), { code });
13
+ function vaultFailure(code, message, cause) {
14
+ return Object.assign(new Error(message), { code }, cause ? { cause } : {});
15
15
  }
16
16
  function isVaultFailure(error) {
17
17
  return error instanceof Error && typeof error.code === "string";
18
18
  }
19
+ function isPolicyPaused(error) {
20
+ return isVaultFailure(error) && error.cause === "policy-paused";
21
+ }
19
22
 
20
23
  export {
21
24
  valueProblem,
22
25
  nameProblem,
23
26
  vaultFailure,
24
- isVaultFailure
27
+ isVaultFailure,
28
+ isPolicyPaused
25
29
  };
26
- //# sourceMappingURL=chunk-XQHRTHDQ.js.map
30
+ //# sourceMappingURL=chunk-BUSDBLS7.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/model/values.ts"],
4
- "sourcesContent": ["import type { ErrorCode, VaultFailure } from './types.ts';\n\nexport function valueProblem(value: string): string | null {\n if (new TextEncoder().encode(value).length < 8)\n return \"Values shorter than 8 bytes can't be protected from the model\";\n if (/[\\r\\n\\0]/.test(value)) return \"Values can't contain line breaks or NUL characters\";\n if (value.includes('fnox_proxy_'))\n return \"That's a placeholder, not a value. Paste the real value\";\n return null;\n}\n\nexport function nameProblem(name: string): string | null {\n return /^[A-Z_][A-Z0-9_]*$/.test(name)\n ? null\n : \"Names use A to Z, 0 to 9 and _, and don't start with a digit\";\n}\n\nexport function vaultFailure(code: ErrorCode, message: string): VaultFailure {\n return Object.assign(new Error(message), { code });\n}\n\nexport function isVaultFailure(error: unknown): error is VaultFailure {\n return error instanceof Error && typeof (error as Partial<VaultFailure>).code === 'string';\n}\n"],
5
- "mappings": ";AAEO,SAAS,aAAa,OAA8B;AACzD,MAAI,IAAI,YAAY,EAAE,OAAO,KAAK,EAAE,SAAS;AAC3C,WAAO;AACT,MAAI,WAAW,KAAK,KAAK,EAAG,QAAO;AACnC,MAAI,MAAM,SAAS,aAAa;AAC9B,WAAO;AACT,SAAO;AACT;AAEO,SAAS,YAAY,MAA6B;AACvD,SAAO,qBAAqB,KAAK,IAAI,IACjC,OACA;AACN;AAEO,SAAS,aAAa,MAAiB,SAA+B;AAC3E,SAAO,OAAO,OAAO,IAAI,MAAM,OAAO,GAAG,EAAE,KAAK,CAAC;AACnD;AAEO,SAAS,eAAe,OAAuC;AACpE,SAAO,iBAAiB,SAAS,OAAQ,MAAgC,SAAS;AACpF;",
4
+ "sourcesContent": ["import type { ErrorCode, VaultFailure } from './types.ts';\n\nexport function valueProblem(value: string): string | null {\n if (new TextEncoder().encode(value).length < 8)\n return \"Values shorter than 8 bytes can't be protected from the model\";\n if (/[\\r\\n\\0]/.test(value)) return \"Values can't contain line breaks or NUL characters\";\n if (value.includes('fnox_proxy_'))\n return \"That's a placeholder, not a value. Paste the real value\";\n return null;\n}\n\nexport function nameProblem(name: string): string | null {\n return /^[A-Z_][A-Z0-9_]*$/.test(name)\n ? null\n : \"Names use A to Z, 0 to 9 and _, and don't start with a digit\";\n}\n\nexport function vaultFailure(\n code: ErrorCode,\n message: string,\n cause?: VaultFailure['cause']\n): VaultFailure {\n return Object.assign(new Error(message), { code }, cause ? { cause } : {}) as VaultFailure;\n}\n\nexport function isVaultFailure(error: unknown): error is VaultFailure {\n return error instanceof Error && typeof (error as Partial<VaultFailure>).code === 'string';\n}\n\nexport function isPolicyPaused(error: unknown): boolean {\n return isVaultFailure(error) && error.cause === 'policy-paused';\n}\n"],
5
+ "mappings": ";AAEO,SAAS,aAAa,OAA8B;AACzD,MAAI,IAAI,YAAY,EAAE,OAAO,KAAK,EAAE,SAAS;AAC3C,WAAO;AACT,MAAI,WAAW,KAAK,KAAK,EAAG,QAAO;AACnC,MAAI,MAAM,SAAS,aAAa;AAC9B,WAAO;AACT,SAAO;AACT;AAEO,SAAS,YAAY,MAA6B;AACvD,SAAO,qBAAqB,KAAK,IAAI,IACjC,OACA;AACN;AAEO,SAAS,aACd,MACA,SACA,OACc;AACd,SAAO,OAAO,OAAO,IAAI,MAAM,OAAO,GAAG,EAAE,KAAK,GAAG,QAAQ,EAAE,MAAM,IAAI,CAAC,CAAC;AAC3E;AAEO,SAAS,eAAe,OAAuC;AACpE,SAAO,iBAAiB,SAAS,OAAQ,MAAgC,SAAS;AACpF;AAEO,SAAS,eAAe,OAAyB;AACtD,SAAO,eAAe,KAAK,KAAK,MAAM,UAAU;AAClD;",
6
6
  "names": []
7
7
  }
@@ -2,7 +2,7 @@ import {
2
2
  nameProblem,
3
3
  valueProblem,
4
4
  vaultFailure
5
- } from "./chunk-XQHRTHDQ.js";
5
+ } from "./chunk-BUSDBLS7.js";
6
6
  import {
7
7
  DummySettings,
8
8
  accounts,
@@ -4794,6 +4794,13 @@ var noticeFixtures = {
4794
4794
  body: "Seven keeps your files and chats on this computer. Nothing is uploaded unless you send it.",
4795
4795
  actions: []
4796
4796
  },
4797
+ backup: {
4798
+ id: "backup",
4799
+ tone: "info",
4800
+ title: "A backup of your chats is ready",
4801
+ body: "Seven saved a copy of your files and chats. Download it to keep one outside this browser.",
4802
+ actions: [{ id: "download", label: "Download" }]
4803
+ },
4797
4804
  readonly: {
4798
4805
  id: "readonly",
4799
4806
  tone: "warning",
@@ -4819,7 +4826,7 @@ var DummyNotices = class extends Emitter {
4819
4826
  super();
4820
4827
  this.#scenario = scenario;
4821
4828
  this.#time = time;
4822
- this.#notices = scenario === "mixed" ? [noticeFixtures.storage, noticeFixtures.welcome] : scenario === "readonly" || scenario === "starting" ? [noticeFixtures[scenario]] : [noticeFixtures.storage];
4829
+ this.#notices = scenario === "mixed" ? [noticeFixtures.storage, noticeFixtures.welcome] : scenario === "readonly" || scenario === "starting" ? [noticeFixtures[scenario]] : scenario === "fail" ? [noticeFixtures.storage, noticeFixtures.backup] : [noticeFixtures.storage];
4823
4830
  }
4824
4831
  list() {
4825
4832
  return this.#notices;
@@ -4827,7 +4834,9 @@ var DummyNotices = class extends Emitter {
4827
4834
  async act(id, action) {
4828
4835
  await this.#time.sleep(10);
4829
4836
  if (this.#scenario === "fail") {
4830
- throw new Error("The browser declined again. Bookmark this page, then try again.");
4837
+ throw new Error(
4838
+ id === "backup" ? "The browser blocked the download. Allow downloads for this page, then try again." : "The browser declined again. Bookmark this page, then try again."
4839
+ );
4831
4840
  }
4832
4841
  if (id === "storage" && action === "retry") this.#remove(id);
4833
4842
  }
@@ -6304,6 +6313,41 @@ function vaultPolicy(now2 = Date.now()) {
6304
6313
  warning: "One rule was refused; it is listed under Rules SLICC refused."
6305
6314
  };
6306
6315
  }
6316
+ function vaultPaused(now2 = Date.now()) {
6317
+ const entry = {
6318
+ type: "policy",
6319
+ accepted: true,
6320
+ changes: []
6321
+ };
6322
+ return [
6323
+ {
6324
+ ...entry,
6325
+ seq: 15,
6326
+ id: "audit-15",
6327
+ at: now2 - minute3,
6328
+ file: "/etc/slicc/secrets-policy.toml",
6329
+ sha256: null,
6330
+ absent: true
6331
+ },
6332
+ {
6333
+ ...entry,
6334
+ seq: 14,
6335
+ id: "audit-14",
6336
+ at: now2 - 2 * minute3,
6337
+ file: "/etc/fnox/config.toml",
6338
+ sha256: "a87ff679a2f3e71d9181a67b7542122c"
6339
+ },
6340
+ {
6341
+ ...entry,
6342
+ seq: 13,
6343
+ id: "audit-13",
6344
+ at: now2 - 3 * minute3,
6345
+ file: "/etc/fnox/config.toml",
6346
+ sha256: null,
6347
+ absent: true
6348
+ }
6349
+ ];
6350
+ }
6307
6351
  function vaultNotice(now2 = Date.now()) {
6308
6352
  return {
6309
6353
  id: "notice-widened",
@@ -6355,6 +6399,7 @@ function vaultFixtures(scenario, now2 = Date.now()) {
6355
6399
  const empty = scenario === "empty";
6356
6400
  const policy = scenario === "policy" || scenario === "notice";
6357
6401
  const backup = scenario === "backup";
6402
+ const paused = scenario === "paused";
6358
6403
  const status2 = {
6359
6404
  version: "0.1.0",
6360
6405
  protocol: 1,
@@ -6363,7 +6408,25 @@ function vaultFixtures(scenario, now2 = Date.now()) {
6363
6408
  lock: "passkey",
6364
6409
  scrub: { needed: !empty, version: 3, ready: scenario !== "locked" },
6365
6410
  waiting: waiting(scenario, now2),
6366
- ...backup ? { backupReminder: "due", exportedAt: null } : {}
6411
+ ...backup ? { backupReminder: "due", exportedAt: null } : {},
6412
+ ...paused ? {
6413
+ policy: [
6414
+ {
6415
+ path: "/etc/fnox/config.toml",
6416
+ sha256: "a87ff679a2f3e71d9181a67b7542122c",
6417
+ accepted: true,
6418
+ warnings: []
6419
+ },
6420
+ {
6421
+ path: "/etc/slicc/secrets-policy.toml",
6422
+ sha256: null,
6423
+ accepted: true,
6424
+ warnings: [],
6425
+ absent: true,
6426
+ paused: true
6427
+ }
6428
+ ]
6429
+ } : {}
6367
6430
  };
6368
6431
  const quay = { domain: "quay.harbor.example", header: "Authorization", methods: [], paths: [] };
6369
6432
  const secrets = (empty ? [] : vaultSecrets(now2)).map(
@@ -6374,6 +6437,7 @@ function vaultFixtures(scenario, now2 = Date.now()) {
6374
6437
  refused: policy ? vaultRefused() : [],
6375
6438
  audit: empty ? [] : [
6376
6439
  ...policy ? [vaultPolicy(now2)] : [],
6440
+ ...paused ? vaultPaused(now2) : [],
6377
6441
  ...scenario === "purged" ? [vaultPinned(now2), vaultPurged(now2)] : [],
6378
6442
  ...scenario === "session" ? vaultSessions(now2) : [],
6379
6443
  ...vaultAudit(now2)
@@ -6522,13 +6586,13 @@ var DummyVault = class extends Emitter {
6522
6586
  this.emit("status", this.#status);
6523
6587
  this.emit("list", this.#list);
6524
6588
  }
6525
- fail(code, message) {
6526
- this.#fail = { code, message };
6589
+ fail(code, message, cause) {
6590
+ this.#fail = { code, message, cause };
6527
6591
  }
6528
6592
  #failed() {
6529
6593
  const fail = this.#fail;
6530
6594
  this.#fail = null;
6531
- if (fail) throw vaultFailure(fail.code, fail.message);
6595
+ if (fail) throw vaultFailure(fail.code, fail.message, fail.cause);
6532
6596
  }
6533
6597
  async acknowledge(notice) {
6534
6598
  await this.#time.sleep(5);
@@ -7000,6 +7064,7 @@ export {
7000
7064
  vaultFixtures,
7001
7065
  vaultNotice,
7002
7066
  vaultOlder,
7067
+ vaultPaused,
7003
7068
  vaultPinned,
7004
7069
  vaultPolicy,
7005
7070
  vaultPurged,