@ai-ecoverse/slicc-spectrum 1.100.0 → 1.101.1
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 +15 -3
- package/dist/slicc-dummy.js +156 -21
- package/dist/slicc-dummy.js.map +3 -3
- package/dist/slicc-ui.js +368 -145
- package/dist/slicc-ui.js.map +3 -3
- package/dist/types/app/composer.d.ts +11 -0
- package/dist/types/app/settings.d.ts +9 -0
- package/dist/types/app/updates.d.ts +3 -0
- package/dist/types/dummy/index.d.ts +3 -2
- package/dist/types/dummy/updates.d.ts +5 -0
- package/dist/types/dummy.d.ts +2 -2
- package/dist/types/model/types.d.ts +20 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -356,6 +356,7 @@ They're also kept in `sessionStorage` (`slicc-spectrum.starting`, so per origin
|
|
|
356
356
|
Only a reload of the same tab brings them back (the navigation's type is `reload`); any other load, such as a duplicated tab that got a copy of the storage, clears them, so nothing is sent twice.
|
|
357
357
|
After a reload the rows come back in order with their text; attachments can't be restored, so a row that had any isn't sent on its own.
|
|
358
358
|
A row with text and lost files is held (`[data-held]`): it shows an alert icon instead of the clock, a second, muted line "Not sent: tides.csv wasn’t kept after reload." (or "Not sent: 2 files weren’t kept after reload.", `[data-lost]`), **Put back** (`data-action="restore-starting"`), which puts its text into the field (after any draft, on a new line), focuses it and drops the row so the files can be attached again, and **Dismiss**.
|
|
359
|
+
After **Put back**, a muted line under the field with a paperclip icon (`[data-reattach]`) names what to attach: "Attach tides.csv again.", "Attach tides.csv and notes.txt again." and, with more than three, "Attach these 4 files again: …"; it's a quiet button (`data-action="reattach"`) that opens the file picker. It follows the listed files by name: attaching tides.csv leaves "Attach notes.txt again.", other files don't change it, and removing a listed file brings it back; it hides while all of them are attached, and goes once the field is cleared or the message is sent. The list is kept with each agent's draft, and a file is listed once.
|
|
359
360
|
A row that had only attachments shows the alert icon, its file names and "Not kept after reload", and reads "Not sent. Attach the files again." (`[data-unsent]`) with **Dismiss**.
|
|
360
361
|
Neither kind is sent on arrival or holds the other rows back, which still go in order; they stay until they're put back or dismissed.
|
|
361
362
|
Text typed but not sent while it starts is kept for the page the same way, and stays in the field once the agent arrives.
|
|
@@ -418,6 +419,7 @@ The Browser rail button carries a dot (`data-driven`) while a tab is in use.
|
|
|
418
419
|
#### `<slicc-settings>`
|
|
419
420
|
|
|
420
421
|
Theme, the model and thinking level for new cones, composer and diff preferences (push to talk only where the browser has speech recognition), and accounts to connect, reconnect or disconnect.
|
|
422
|
+
When the `updates` port has `setDeveloper`, an Updates row has the **Developer mode** switch (`sp-switch[data-setting=developer]`, `checked` from `developer()` on every `items`), described as "Check npm for newer releases that aren't certified yet, and offer them as betas in Install / Update."; while `setDeveloper(on)` is pending it is disabled with `aria-busy` and a progress circle, and a rejection shows its message under it (`[data-error]`).
|
|
421
423
|
An account whose status is `signing-in` (or a non-API-key account while its `connect` is pending) reads “Signing in…”; when the port has `cancel(id)`, its row offers Cancel (`data-action="cancel-sign-in"`), and the rejected `connect` that follows shows no error.
|
|
422
424
|
Accounts with `group: 'mcp'` (MCP servers) get their own **MCP servers** heading (`.accounts[data-group=mcp]`).
|
|
423
425
|
An `api-key` account asks for its `secret`: “{provider} API key” by default, “{provider} token” for `secret: 'token'`; when it is `expired` it reads **API key rejected** or **Token rejected**.
|
|
@@ -472,13 +474,18 @@ It closes, clearing the field, when the request leaves `waiting` or while the va
|
|
|
472
474
|
#### `<slicc-updates>`
|
|
473
475
|
|
|
474
476
|
Install / Update: component states, version changes, last checks, download and link counts, action buttons, failures with Retry, and collapsible install logs behind a quiet chevron, which stay open across a layout switch.
|
|
475
|
-
A row with a pending version change (`from → to`, or a package's `version → offered`) and release notes shows a What’s new disclosure after the row's actions (in package rows, after the command chips), next to the Install log, `details[data-releases]` with `summary[data-action="whats-new"]`, which stays open across a layout switch like the log. It lists every release after the installed version up to the new one, newest first, each as `.release[data-version]` with its version linking to the release page (`a[data-action="release-notes"]`, named "Kernel 1.13.0 release notes") and its notes rendered as markdown in strict mode (`markdown(text, { strict: true })`: raw HTML tags are dropped and their text kept as plain text, only `https:` links stay links, and an image becomes a link with its alt text, so nothing loads; the notes' headings sit one level under the release's, through `level`). Notes over 8 KB (8,192 characters) per release are cut at the last line break before that, with "…" and a Read the full notes link (`[data-cut]`, named "Read the full notes for Kernel 1.13.0"); a release whose `url` isn't `https:` shows its version as plain text. The `<!-- cert-verify -->` block is dropped, and a block that starts with "certified" shows as a subtle Certified badge (`[data-certified]`); a heading line naming the version is dropped too, since the link already shows it. Without notes in the range there is no disclosure.
|
|
477
|
+
A row with a pending version change (`from → to`, or a package's `version → offered`) and release notes shows a What’s new disclosure after the row's actions (in package rows, after the command chips), next to the Install log, `details[data-releases]` with `summary[data-action="whats-new"]`, which stays open across a layout switch like the log. It lists every release after the installed version up to the new one, newest first, each as `.release[data-version]` with its version linking to the release page (`a[data-action="release-notes"]`, named "Kernel 1.13.0 release notes"). Only the newest (`.release[data-newest]`) shows its notes; each older release is a collapsed header, `details.release` with `summary[data-action="release"]` holding the same chevron, its version link and badge across the full row and named "Kernel 1.12.2 notes, certified", that opens to its notes indented under its title and stays open across a layout switch like the disclosure (an older release without notes is a plain header). The notes are rendered as markdown in strict mode (`markdown(text, { strict: true })`: raw HTML tags are dropped and their text kept as plain text, only `https:` links stay links, and an image becomes a link with its alt text, so nothing loads; the notes' headings sit one level under the release's, through `level`). Notes over 8 KB (8,192 characters) per release are cut at the last line break before that, with "…" and a Read the full notes link (`[data-cut]`, named "Read the full notes for Kernel 1.13.0"); a release whose `url` isn't `https:` shows its version as plain text. The `<!-- cert-verify -->` block is dropped, and a block that starts with "certified" shows as a subtle Certified badge (`[data-certified]`); a heading line naming the version is dropped too, since the link already shows it. Without notes in the range there is no disclosure.
|
|
476
478
|
An up-to-date row (no pending change) links its installed release with Release notes next to the version; an installed optional package without one links its npm page instead (`a[data-action="npm-page"]`, named "npm page for Biome 2.2.4"). Pins and additions in Your packages show no link. Every link opens in a new tab.
|
|
477
479
|
An install shows one bar for update rows and package rows alike: it fills 0–50% while downloading and 50–100% while linking (`value` against `max-value="100"`). While the row runs it never goes back, not when pnpm's total grows and not when progress drops out between passes. While a download reports `bytes` with a total above 0, the first half fills by bytes and the value label reads "10.0 MB of 40.0 MB". Otherwise, and always while linking, the label falls back to the phase's "n of m" count. The bar starts at 0 again once the row settles.
|
|
478
480
|
Opens at boot until the agent is ready without failures.
|
|
479
481
|
Background updates stay in the header's update status; new failures reopen the panel, and after a reload into a boot that isn't ready yet such a panel closes once the agent is ready.
|
|
480
482
|
Every automatic close is saved to the layout.
|
|
481
483
|
When the port offers packages, an Optional packages section lists them below as compact rows, each with its state, version, download size, requirements, commands, progress, errors and Install log; packages never count in the header or keep the panel open at boot.
|
|
484
|
+
With a port that has `setDeveloper`, a row's `npm` check shows under its version: "npm: no newer release", "Checking npm…", its `reason` when the check failed (the state light stays), "{installed} (certified) · {latest} on npm, not offered: {reason}" (a certified update keeps its target, "6.6.0 (certified) → 6.7.0 · …", and so does a beta row, "6.13.5 beta · certified 6.6.0 → 6.7.0"), or, when `offered`, "{installed} (certified) · {latest} on npm, not certified" with "12 packages change in /opt/agent." (the folder in the label's parentheses; "1 package changes …"), followed by "@slicc/kernel-bridge and @slicc/vault stay at their certified versions." for `gated` ("… stays at its certified version." for one) and **Install beta**; `article[data-npm]` is the state.
|
|
485
|
+
A row with `beta` has a notice **Beta** badge by its name (`[data-beta]`), a notice "Beta installed" light while it is `current` or `installed` ("Up to date" means the certified version only; Ready to apply, Failed and the running states keep their words), reads "{version} beta · certified {certified}" and offers **Back to certified** next to its other actions; Install beta shows only while `npm` is `offered`.
|
|
486
|
+
While `npm` is `offered`, What’s new covers the releases from the installed version up to npm's `latest`, so an offered beta lists its own notes.
|
|
487
|
+
Install beta and Back to certified are secondary buttons and call `act`; without `setDeveloper` (a mirrored port) neither shows.
|
|
488
|
+
For now bios sets these on the agent row only; the other rows follow with bios.
|
|
482
489
|
Packages the user added with pnpm in `/opt/user`, or pinned, show up in their own Your packages section below it, under "Packages you added with pnpm in /opt/user. Seven’s updates keep them until you remove them." (plus "Pinned versions stay until you unpin them." while a row offers `unpin`), with a neutral Pinned light (a hold, not a success) or a positive Added light, their version against seven's, and Unpin or Remove.
|
|
483
490
|
Also available through View and the rails.
|
|
484
491
|
|
|
@@ -808,8 +815,10 @@ Emit `items` whenever rows or readiness change.
|
|
|
808
815
|
Use `queued` for a row that waits for another component before it starts; it reads "Waiting" and doesn't count as updating.
|
|
809
816
|
Use `starting` for an installed row that is only starting up: it reads "Starting" without a checked line, and the header shows a neutral "Starting" only when nothing is failed, updating or ready.
|
|
810
817
|
A `failed` row with an installed `from` version reads "Update failed".
|
|
811
|
-
`act(id, action)` resolves when dispatched or rejects with a displayed error; actions are `retry`, `update-now`, `restart-agent` and `
|
|
818
|
+
`act(id, action)` resolves when dispatched or rejects with a displayed error; actions are `retry`, `update-now`, `restart-agent`, `reload`, `install-beta` and `back-to-certified` (the embedder asks for confirmation itself).
|
|
812
819
|
A row's and a package's optional `releases` (`UpdateRelease[]`) lists the GitHub releases the embedder knows for it, each with its `version`, the release page `url` and optional `notes` (the release body, semantic-release markdown as GitHub returns it). Send every release after the installed version up to the new one, so the panel can show the whole range, plus the installed one for its link; spectrum orders them by version and never fetches them itself. Leave it out, or leave out `notes`, when there's nothing to show.
|
|
820
|
+
Optional `developer()` (false by default) and `setDeveloper(on)`, on the owner's page only, turn developer mode on and off; `setDeveloper` resolves once settled or rejects with a displayed error, and the port emits `items` when either changes.
|
|
821
|
+
A row's optional `beta` (`{ version, certified }`) is set while a beta is installed, and its optional `npm` (`{ state, latest?, reason?, changes?: { count, gated } }`, `state` one of `checking`, `current`, `offered`, `not-offered` or `failed`) is `null` while developer mode is off.
|
|
813
822
|
Missing ports preserve existing adapters and report disconnected information in the panel.
|
|
814
823
|
Optional `packages()` returns `PackageItem` rows for optional tools, each with a short catalog `id`, its npm `package` (shown in the name's tooltip and at the top of its Install log), `label`, a one-sentence `description`, the `commands` it provides, `requires` (other package ids, read as "Uses Python" while it's installed, or "Installs Python too" on a row that isn't installed yet; an installed row leaves out a requirement that isn't installed, since its warning says so), optional `notes` (short plain-text lines shown muted under the row, such as "1 untested dependency: …"; leave it out when there's nothing to say), optional `warnings` (lines with an alert icon, `data-warnings`, such as "Needs Python, which isn't installed.
|
|
815
824
|
Install Python again to use it."; the dummy adds that one when a required package is removed), `state` (`available`, `queued`, `installing`, `installed`, `outdated`, `updating`, `removing` or `failed`), the installed `version`, the `offered` version and its `size` in bytes, `progress` (`InstallProgress`, or `null` for an indeterminate bar), `error`, `actions` (`install`, `update`, `remove`, `retry`, `unpin`) and an optional `log`.
|
|
@@ -870,6 +879,7 @@ An action is a secondary button that stays pending until `act(id, action)` settl
|
|
|
870
879
|
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.
|
|
871
880
|
Emit `notices` whenever they change.
|
|
872
881
|
A notice with `dismissible: false` has no close button and stays until the port drops it.
|
|
882
|
+
An optional `session: true` marks a notice the embedder keeps for the session; the panel shows it like any other, and other fields pass through.
|
|
873
883
|
Hooks: `[data-notice="<id>"]`, buttons with `data-action`, `[data-dismiss]` and `[data-error]`.
|
|
874
884
|
|
|
875
885
|
#### `tabs` (optional)
|
|
@@ -966,7 +976,8 @@ Fixtures stay stable for inspection; `model.updates.setScenario('current')` comp
|
|
|
966
976
|
The dummy's kernel offers three releases from 1.12.0 to 1.13.0, two of them certified, the agent one release to 0.25.0, and the syntax grammars only their installed release; its uv package offers two releases, Python links its release and the other installed packages their npm pages.
|
|
967
977
|
Dummy Update now and Retry simulate download and link progress, and a dummy package install reports half its `size` in bytes on the way; Restart agent and Reload only change fixture state, never restart a real process or reload the browser.
|
|
968
978
|
`createDummyModel({ packages: 'mixed' | 'empty' | 'fail' | 'user' | 'elsewhere' | 'off' })` (or `?packages=` on `/ui/`, off by default) adds invented optional packages in every state: Install and Retry finish after a short wait and install missing requirements too, `fail` makes them fail, `user` adds a pinned agent-kit and two additions (one with a warning) that Unpin and Remove take out of the list, `elsewhere` has git installed for cone with pnpm and TypeScript there at an older version, whose Update keeps it in place, and Biome both from the panel and for cone, whose Remove leaves cone's copy, and removing Python while uv is installed asks through the `confirm` option (the `/ui/` page passes spectrum's `confirm`).
|
|
969
|
-
`
|
|
979
|
+
`createDummyModel({ beta: 'offered' | 'installed' | 'blocked' | 'failed' | 'off' })` (or `?beta=` on `/ui/`, off by default) turns developer mode on with an invented agent at 6.6.0 (certified) and 6.13.5 on npm, 12 packages and nothing gated: `offered` offers Install beta, `installed` runs the beta, `blocked` isn't offered because it needs a newer kernel, and `failed` is a failed beta install with Retry and Install beta; `setDeveloper` toggles it after a short wait (checking npm again when turned on), and Install beta and Back to certified simulate a short install.
|
|
980
|
+
`updateFixtures`, `betaFixtures`, `packageFixtures` and `DummyUpdates` are exported from `/dummy`.
|
|
970
981
|
`createDummyModel({ mounts: 'mount' | 'cancel' | 'fail' | 'needs' })` (or `?mounts=` on `/ui/`) turns on the optional mount members, which are off by default: `mountFolder` mounts invented files at `/mnt/photos`, resolves with `null`, or rejects, as `model.files.mount.scenario` says; `needs` also lists `/mnt/photos` in `needsFolder()` until a folder is inserted there.
|
|
971
982
|
`createDummyModel({ network: 'ok' | 'limited' | 'failing' | 'off' })` (or `?network=` on `/ui/`, default `limited`) sets the dummy network: slicc on this computer as a linked device (`route: 'link'`, with browser automation through it), the page fetch with CORS failures, or no route, all invented; `off` leaves out the port.
|
|
972
983
|
`model.network.setScenario()` switches it and Check again re-emits after a short wait.
|
|
@@ -1036,6 +1047,7 @@ Its buttons are plain Spectrum buttons that answer at once: Unlock unlocks, and
|
|
|
1036
1047
|
|
|
1037
1048
|
On phones the update status and the tray connection show only their status light (the tray's budget is hidden) and the network indicator a cloud icon, with the text in their labels and tooltips; the agent picker keeps room for the cone's name, cut with an ellipsis when long, and the bottom rail scrolls when needed.
|
|
1038
1049
|
The update status comes first so progress and failures remain reachable on narrow screens.
|
|
1050
|
+
While a row has `beta`, the update status shows a notice **Beta** badge (`[data-updates] [data-beta]`) after its light, or alone when nothing else applies, at every size; its tooltip and label add "{label} runs beta {version}, not certified", with the label's folder left out ("Agent runs beta 6.13.5, not certified").
|
|
1039
1051
|
|
|
1040
1052
|
### Kernel model
|
|
1041
1053
|
|
package/dist/slicc-dummy.js
CHANGED
|
@@ -1741,8 +1741,8 @@ var DummyAgent = class extends Emitter {
|
|
|
1741
1741
|
this.emit("message", { agentId, message: reply });
|
|
1742
1742
|
const steers = run.steers.splice(0);
|
|
1743
1743
|
for (const steer of steers) this.#post(agentId, this.#user(steer, "steer"));
|
|
1744
|
-
const
|
|
1745
|
-
({ steps, suggestion } = script(
|
|
1744
|
+
const latest2 = steers.at(-1);
|
|
1745
|
+
({ steps, suggestion } = script(latest2.text.trim(), latest2.attachments ?? []));
|
|
1746
1746
|
run.pace = this.#pace(agentId, steps);
|
|
1747
1747
|
reply = this.#reply(agent.model);
|
|
1748
1748
|
this.#post(agentId, reply);
|
|
@@ -5061,7 +5061,89 @@ function updateFixtures(scenario) {
|
|
|
5061
5061
|
}
|
|
5062
5062
|
return items;
|
|
5063
5063
|
}
|
|
5064
|
-
var
|
|
5064
|
+
var pin = "6.6.0";
|
|
5065
|
+
var latest = "6.13.5";
|
|
5066
|
+
var betaReleases = [
|
|
5067
|
+
tag(
|
|
5068
|
+
"harbor-agent",
|
|
5069
|
+
"6.13.5",
|
|
5070
|
+
notes(
|
|
5071
|
+
"harbor-agent",
|
|
5072
|
+
"6.13.5",
|
|
5073
|
+
"### Bug Fixes\n\n* **tools:** a tide table with a blank row no longer stops the import"
|
|
5074
|
+
)
|
|
5075
|
+
),
|
|
5076
|
+
tag(
|
|
5077
|
+
"harbor-agent",
|
|
5078
|
+
"6.10.0",
|
|
5079
|
+
notes(
|
|
5080
|
+
"harbor-agent",
|
|
5081
|
+
"6.10.0",
|
|
5082
|
+
"### Features\n\n* **chat:** answers can quote a buoy reading with its time and place"
|
|
5083
|
+
)
|
|
5084
|
+
),
|
|
5085
|
+
tag(
|
|
5086
|
+
"harbor-agent",
|
|
5087
|
+
"6.6.0",
|
|
5088
|
+
notes("harbor-agent", "6.6.0", "### Bug Fixes\n\n* **chat:** a pasted chart keeps its axes") + certified("harbor-agent", "6.6.0")
|
|
5089
|
+
)
|
|
5090
|
+
];
|
|
5091
|
+
var offered = { state: "offered", latest, changes: { count: 12, gated: [] } };
|
|
5092
|
+
var blocked = {
|
|
5093
|
+
state: "not-offered",
|
|
5094
|
+
latest,
|
|
5095
|
+
reason: "it needs kernel 1.14.0 or later"
|
|
5096
|
+
};
|
|
5097
|
+
var betaFailed = "Couldn\u2019t install the beta: pnpm stopped with an error, shown in the install log. Retry.";
|
|
5098
|
+
function betaActions(item) {
|
|
5099
|
+
return [
|
|
5100
|
+
...item.beta ? ["back-to-certified"] : [],
|
|
5101
|
+
...item.npm?.state === "offered" ? ["install-beta"] : []
|
|
5102
|
+
];
|
|
5103
|
+
}
|
|
5104
|
+
function withNpm(items, npm) {
|
|
5105
|
+
return items.map((item) => {
|
|
5106
|
+
if (item.kind !== "agent") return item;
|
|
5107
|
+
const next = { ...item, npm };
|
|
5108
|
+
const kept = item.actions.filter(
|
|
5109
|
+
(action) => action !== "install-beta" && action !== "back-to-certified"
|
|
5110
|
+
);
|
|
5111
|
+
return { ...next, actions: [...kept, ...betaActions(next)] };
|
|
5112
|
+
});
|
|
5113
|
+
}
|
|
5114
|
+
function betaFixtures(items, scenario) {
|
|
5115
|
+
return items.map((item) => {
|
|
5116
|
+
if (item.kind !== "agent") return item;
|
|
5117
|
+
const base = {
|
|
5118
|
+
...item,
|
|
5119
|
+
from: pin,
|
|
5120
|
+
to: pin,
|
|
5121
|
+
beta: null,
|
|
5122
|
+
npm: offered,
|
|
5123
|
+
releases: betaReleases
|
|
5124
|
+
};
|
|
5125
|
+
const next = scenario === "installed" ? {
|
|
5126
|
+
...base,
|
|
5127
|
+
from: latest,
|
|
5128
|
+
to: latest,
|
|
5129
|
+
beta: { version: latest, certified: pin },
|
|
5130
|
+
npm: { state: "current", latest }
|
|
5131
|
+
} : scenario === "blocked" ? { ...base, npm: blocked } : scenario === "failed" ? {
|
|
5132
|
+
...base,
|
|
5133
|
+
state: "failed",
|
|
5134
|
+
to: latest,
|
|
5135
|
+
error: betaFailed,
|
|
5136
|
+
log: `pnpm add @slicc/demo-agent@${latest}
|
|
5137
|
+
ERR_PNPM_FETCH_TIMEOUT Request timed out after 30000ms`
|
|
5138
|
+
} : base;
|
|
5139
|
+
const extra = betaActions(next);
|
|
5140
|
+
return {
|
|
5141
|
+
...next,
|
|
5142
|
+
actions: [...scenario === "failed" ? ["retry"] : item.actions, ...extra]
|
|
5143
|
+
};
|
|
5144
|
+
});
|
|
5145
|
+
}
|
|
5146
|
+
var offer = (id, label2, description, commands, offered2, size, requires) => ({
|
|
5065
5147
|
id,
|
|
5066
5148
|
package: `@harbor/${id}-wasm`,
|
|
5067
5149
|
label: label2,
|
|
@@ -5070,14 +5152,14 @@ var offer = (id, label2, description, commands, offered, size, requires) => ({
|
|
|
5070
5152
|
...requires ? { requires } : {},
|
|
5071
5153
|
state: "available",
|
|
5072
5154
|
version: null,
|
|
5073
|
-
offered,
|
|
5155
|
+
offered: offered2,
|
|
5074
5156
|
size,
|
|
5075
5157
|
progress: null,
|
|
5076
5158
|
error: null,
|
|
5077
5159
|
actions: ["install"]
|
|
5078
5160
|
});
|
|
5079
5161
|
var fetchFailed = "The download stopped. Check the connection and try again.";
|
|
5080
|
-
var yours = (project, name2, description, version,
|
|
5162
|
+
var yours = (project, name2, description, version, pin2, change = {}) => ({
|
|
5081
5163
|
id: `user:${project}:${name2}`,
|
|
5082
5164
|
package: name2,
|
|
5083
5165
|
label: name2.replace(/^@[^/]+\//, ""),
|
|
@@ -5088,9 +5170,9 @@ var yours = (project, name2, description, version, pin, change = {}) => ({
|
|
|
5088
5170
|
offered: null,
|
|
5089
5171
|
progress: null,
|
|
5090
5172
|
error: null,
|
|
5091
|
-
actions: [
|
|
5173
|
+
actions: [pin2.base === null ? "remove" : "unpin"],
|
|
5092
5174
|
origin: "user",
|
|
5093
|
-
pin: { ...
|
|
5175
|
+
pin: { ...pin2, project: `/opt/${project}` },
|
|
5094
5176
|
...change
|
|
5095
5177
|
});
|
|
5096
5178
|
var userPackages = () => [
|
|
@@ -5239,9 +5321,16 @@ var DummyUpdates = class extends Emitter {
|
|
|
5239
5321
|
#packages = [];
|
|
5240
5322
|
#fail = false;
|
|
5241
5323
|
#confirm;
|
|
5324
|
+
#beta;
|
|
5325
|
+
#developer = true;
|
|
5242
5326
|
constructor(scenario, clock2, options = {}) {
|
|
5243
5327
|
super();
|
|
5244
|
-
this.#
|
|
5328
|
+
this.#beta = options.beta;
|
|
5329
|
+
this.#items = this.#fixtures(scenario);
|
|
5330
|
+
if (options.beta) {
|
|
5331
|
+
this.developer = () => this.#developer;
|
|
5332
|
+
this.setDeveloper = (on) => this.#setDeveloper(on);
|
|
5333
|
+
}
|
|
5245
5334
|
this.#ready = scenario !== "boot" && scenario !== "starting";
|
|
5246
5335
|
this.#clock = clock2;
|
|
5247
5336
|
this.#confirm = options.confirm;
|
|
@@ -5371,8 +5460,32 @@ Done in 3.8s`
|
|
|
5371
5460
|
ready() {
|
|
5372
5461
|
return this.#ready;
|
|
5373
5462
|
}
|
|
5463
|
+
#fixtures(scenario) {
|
|
5464
|
+
const items = updateFixtures(scenario);
|
|
5465
|
+
if (!this.#beta) return items;
|
|
5466
|
+
const fixed = betaFixtures(items, this.#beta);
|
|
5467
|
+
return this.#developer ? fixed : withNpm(fixed, null);
|
|
5468
|
+
}
|
|
5469
|
+
async #setDeveloper(on) {
|
|
5470
|
+
await this.#clock.sleep(4);
|
|
5471
|
+
this.#developer = on;
|
|
5472
|
+
this.#npm(on ? { state: "checking" } : null);
|
|
5473
|
+
if (!on) return;
|
|
5474
|
+
await this.#clock.sleep(4);
|
|
5475
|
+
const agent = this.#items.find((item) => item.kind === "agent");
|
|
5476
|
+
this.#npm(this.#check(agent.from));
|
|
5477
|
+
}
|
|
5478
|
+
#check(version) {
|
|
5479
|
+
if (!this.#developer) return null;
|
|
5480
|
+
if (version === latest) return { state: "current", latest };
|
|
5481
|
+
return this.#beta === "blocked" ? blocked : offered;
|
|
5482
|
+
}
|
|
5483
|
+
#npm(npm) {
|
|
5484
|
+
this.#items = withNpm(this.#items, npm);
|
|
5485
|
+
this.emit("items", this.#items);
|
|
5486
|
+
}
|
|
5374
5487
|
setScenario(scenario) {
|
|
5375
|
-
this.#items =
|
|
5488
|
+
this.#items = this.#fixtures(scenario);
|
|
5376
5489
|
this.#ready = scenario !== "boot" && scenario !== "starting";
|
|
5377
5490
|
this.emit("items", this.#items);
|
|
5378
5491
|
}
|
|
@@ -5383,7 +5496,9 @@ Done in 3.8s`
|
|
|
5383
5496
|
async act(id, action) {
|
|
5384
5497
|
const item = this.#items.find((candidate) => candidate.id === id);
|
|
5385
5498
|
if (!item?.actions.includes(action)) throw new Error(`Update action unavailable: ${id}`);
|
|
5386
|
-
|
|
5499
|
+
const back = action === "back-to-certified";
|
|
5500
|
+
const beta = back || action === "install-beta" || action === "retry" && item.to === latest;
|
|
5501
|
+
if (action === "update-now" || action === "retry" || beta) {
|
|
5387
5502
|
this.#patch(id, {
|
|
5388
5503
|
state: "downloading",
|
|
5389
5504
|
progress: { phase: "download", done: 0, total: 95 },
|
|
@@ -5399,13 +5514,30 @@ Done in 3.8s`
|
|
|
5399
5514
|
});
|
|
5400
5515
|
await this.#clock.sleep(2);
|
|
5401
5516
|
}
|
|
5517
|
+
if (beta) {
|
|
5518
|
+
const version = back ? pin : latest;
|
|
5519
|
+
const next = {
|
|
5520
|
+
...this.#items.find((candidate) => candidate.id === id),
|
|
5521
|
+
state: "ready",
|
|
5522
|
+
from: version,
|
|
5523
|
+
to: version,
|
|
5524
|
+
progress: null,
|
|
5525
|
+
error: null,
|
|
5526
|
+
checkedAt,
|
|
5527
|
+
beta: back ? null : { version, certified: pin },
|
|
5528
|
+
npm: this.#check(version)
|
|
5529
|
+
};
|
|
5530
|
+
this.#patch(id, { ...next, actions: ["restart-agent", ...betaActions(next)] });
|
|
5531
|
+
return;
|
|
5532
|
+
}
|
|
5402
5533
|
const apply = action === "update-now" && ["agent", "bios", "kernel", "ui"].includes(item.kind);
|
|
5403
5534
|
this.#patch(id, {
|
|
5404
5535
|
state: apply ? "ready" : "installed",
|
|
5405
5536
|
from: apply ? item.from : item.to,
|
|
5406
5537
|
progress: null,
|
|
5407
5538
|
checkedAt,
|
|
5408
|
-
actions: apply ? [item.kind === "agent" ? "restart-agent" : "reload"] : []
|
|
5539
|
+
actions: apply ? [item.kind === "agent" ? "restart-agent" : "reload"] : [],
|
|
5540
|
+
...apply ? {} : { actions: betaActions(item) }
|
|
5409
5541
|
});
|
|
5410
5542
|
}
|
|
5411
5543
|
};
|
|
@@ -5512,7 +5644,7 @@ function refused(settings) {
|
|
|
5512
5644
|
if (bad)
|
|
5513
5645
|
throw vaultFailure("EINVAL", `The vault refused ${bad[0]}. Check that value and try again.`);
|
|
5514
5646
|
}
|
|
5515
|
-
function accountRecords(now2 = Date.now(),
|
|
5647
|
+
function accountRecords(now2 = Date.now(), pin2) {
|
|
5516
5648
|
return [
|
|
5517
5649
|
{
|
|
5518
5650
|
name: "MCP_DOCS_TOKEN",
|
|
@@ -5522,7 +5654,7 @@ function accountRecords(now2 = Date.now(), pin) {
|
|
|
5522
5654
|
source: "settings",
|
|
5523
5655
|
sourceDevice: null,
|
|
5524
5656
|
server: "docs",
|
|
5525
|
-
...
|
|
5657
|
+
...pin2 ? { url: pin2, pinned: true } : {},
|
|
5526
5658
|
domains: ["docs.example"],
|
|
5527
5659
|
rules: [{ domain: "docs.example", header: "Authorization", methods: [], paths: [] }],
|
|
5528
5660
|
exec: false,
|
|
@@ -6103,11 +6235,11 @@ var DummyVault = class extends Emitter {
|
|
|
6103
6235
|
await this.#time.sleep(5);
|
|
6104
6236
|
this.#unlocked();
|
|
6105
6237
|
for (const name2 of names) {
|
|
6106
|
-
const
|
|
6238
|
+
const pin2 = this.#list.audit.find(
|
|
6107
6239
|
(entry) => entry.type === "endpoints" && entry.pinned?.name === name2
|
|
6108
6240
|
);
|
|
6109
|
-
if (
|
|
6110
|
-
this.#log(name2, { type: "endpoints", unpinned:
|
|
6241
|
+
if (pin2?.type === "endpoints" && pin2.pinned)
|
|
6242
|
+
this.#log(name2, { type: "endpoints", unpinned: pin2.pinned });
|
|
6111
6243
|
}
|
|
6112
6244
|
this.emit("list", this.#list);
|
|
6113
6245
|
}
|
|
@@ -6144,20 +6276,20 @@ var DummyVault = class extends Emitter {
|
|
|
6144
6276
|
password: !!options.password,
|
|
6145
6277
|
...pick ? { pick: [...pick] } : {}
|
|
6146
6278
|
});
|
|
6147
|
-
const
|
|
6148
|
-
if (!pick) return { stage: "pick", candidates:
|
|
6279
|
+
const offered2 = kind === "keepass" ? [...candidates, duplicate] : candidates;
|
|
6280
|
+
if (!pick) return { stage: "pick", candidates: offered2.map((item) => ({ ...item })) };
|
|
6149
6281
|
const chosen = new Map(
|
|
6150
6282
|
pick.map(
|
|
6151
6283
|
(item) => typeof item === "string" ? [item, "secret"] : [item.name, item.kind]
|
|
6152
6284
|
)
|
|
6153
6285
|
);
|
|
6154
|
-
const taken =
|
|
6286
|
+
const taken = offered2.filter((item) => chosen.has(item.name) && !item.refused);
|
|
6155
6287
|
return {
|
|
6156
6288
|
stage: "done",
|
|
6157
6289
|
imported: taken.map((item) => this.#seal(item.name, `import:${kind}`, chosen.get(item.name))),
|
|
6158
|
-
skipped:
|
|
6290
|
+
skipped: offered2.filter((item) => !taken.includes(item)).map((item) => item.name),
|
|
6159
6291
|
reasons: Object.fromEntries(
|
|
6160
|
-
|
|
6292
|
+
offered2.flatMap((item) => item.refused ? [[item.name, item.refused]] : [])
|
|
6161
6293
|
)
|
|
6162
6294
|
};
|
|
6163
6295
|
}
|
|
@@ -6248,6 +6380,7 @@ function createDummyModel({
|
|
|
6248
6380
|
updates = "current",
|
|
6249
6381
|
packages = "off",
|
|
6250
6382
|
confirm,
|
|
6383
|
+
beta = "off",
|
|
6251
6384
|
mounts = "off",
|
|
6252
6385
|
network = "limited",
|
|
6253
6386
|
tailnet,
|
|
@@ -6328,6 +6461,7 @@ function createDummyModel({
|
|
|
6328
6461
|
tray: new DummyTray(tray, time),
|
|
6329
6462
|
updates: new DummyUpdates(updates, time, {
|
|
6330
6463
|
...packages === "off" ? {} : { packages },
|
|
6464
|
+
...beta === "off" ? {} : { beta },
|
|
6331
6465
|
confirm
|
|
6332
6466
|
}),
|
|
6333
6467
|
...network === "off" ? {} : { network: new DummyNetwork(network, time, tailnet, links, files3, leaders) },
|
|
@@ -6365,6 +6499,7 @@ export {
|
|
|
6365
6499
|
DummyVaultButton,
|
|
6366
6500
|
actionLimits,
|
|
6367
6501
|
approvalFixtures,
|
|
6502
|
+
betaFixtures,
|
|
6368
6503
|
browserHistory,
|
|
6369
6504
|
createDummyModel,
|
|
6370
6505
|
createGuestModel,
|