@ai-ecoverse/slicc-agent 5.8.2 → 5.9.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 +21 -14
- package/bin/agent +3 -1
- package/dist/gelatiere/index.js +16 -19
- package/dist/gelatiere/index.js.map +2 -2
- package/dist/kernel/agent-users.js +11 -0
- package/dist/kernel/agent-users.js.map +2 -2
- package/dist/licks/boot.js +10 -1
- package/dist/licks/boot.js.map +2 -2
- package/dist/licks/config.js +0 -37
- package/dist/licks/config.js.map +3 -3
- package/dist/licks/crontab.js +141 -0
- package/dist/licks/crontab.js.map +7 -0
- package/dist/licks/extension.js +4 -69
- package/dist/licks/extension.js.map +2 -2
- package/dist/licks/index.js +3 -5
- package/dist/licks/index.js.map +2 -2
- package/dist/licks/sources.js +42 -14
- package/dist/licks/sources.js.map +2 -2
- package/dist/main.js +1 -1
- package/dist/main.js.map +2 -2
- package/dist/scoops/cli.js +32 -0
- package/dist/scoops/cli.js.map +2 -2
- package/dist/scoops/index.js +7 -5
- package/dist/scoops/index.js.map +2 -2
- package/dist/scoops/requests.js +22 -7
- package/dist/scoops/requests.js.map +2 -2
- package/dist/spectrum/approvals-port.js +1 -1
- package/dist/spectrum/approvals-port.js.map +2 -2
- package/dist/spectrum/guest-port.js.map +2 -2
- package/dist/spectrum/monitor-port.js +0 -1
- package/dist/spectrum/monitor-port.js.map +2 -2
- package/dist/types/gelatiere/index.d.ts +2 -1
- package/dist/types/kernel/agent-users.d.ts +2 -0
- package/dist/types/licks/boot.d.ts +12 -1
- package/dist/types/licks/config.d.ts +0 -7
- package/dist/types/licks/crontab.d.ts +37 -0
- package/dist/types/licks/extension.d.ts +1 -17
- package/dist/types/licks/index.d.ts +1 -1
- package/dist/types/licks/sources.d.ts +1 -3
- package/dist/types/scoops/cli.d.ts +2 -0
- package/dist/types/scoops/requests.d.ts +5 -1
- package/dist/types/spectrum/guest-port.d.ts +2 -5
- package/package.json +7 -7
- package/packages/vfs-root/skills/gelatiere/SKILL.md +2 -2
- package/packages/vfs-root/skills/licks/SKILL.md +16 -12
- package/dist/licks/cron.js +0 -120
- package/dist/licks/cron.js.map +0 -7
- package/dist/licks/schedules.js +0 -50
- package/dist/licks/schedules.js.map +0 -7
- package/dist/types/licks/cron.d.ts +0 -16
- package/dist/types/licks/schedules.d.ts +0 -25
package/README.md
CHANGED
|
@@ -100,9 +100,9 @@ With users, each cone and each scoop is a kernel user, and works as that user:
|
|
|
100
100
|
| skills for every agent | `/usr/share/skills/` (root, `0755`), as without users |
|
|
101
101
|
| an agent's own skills | `~/.pi/agent/skills` and `~/.agents/skills` in its home; only that agent sees them |
|
|
102
102
|
| memory | `/root/.pi/agent/memory/` and `/root/.pi/agent/agent-memory/` (root; agents use `memory_write` and `memory`) |
|
|
103
|
-
| licks | each cone's `~/.slicc`, whose
|
|
103
|
+
| licks | each cone's `~/.slicc`, whose `cone` target is that cone; root's `/root/.slicc`, whose `cone` is the active cone. Schedules are each user's kernel crontab: a cone's, a scoop's own, and root's |
|
|
104
104
|
| sprinkles | each cone's `~/sprinkles`, every cone's in the rail, with the id `<cone>/<name>` (the cone's id, such as `cone-2`) and the cone as `agentId`; `panel open sprinkle:<cone>/<name>` opens one, and spectrum scopes the rest by cone. welcome and suggestions keep their plain ids. spectrum ≥ 1.56.0 groups the rail by cone, with the selected cone first; an older spectrum lists them ungrouped. A sprinkle's files are read as its owner, inside the owner's home |
|
|
105
|
-
| the gelatiere | its procedure
|
|
105
|
+
| the gelatiere | its procedure in the first cone's home, written as that cone, and its nightly line in the gelatiere scoop's own crontab; `gelatiere install` and `suggest` run as the caller |
|
|
106
106
|
| scoop reports | the cone's `~/.slicc/reports/<handle>/` |
|
|
107
107
|
| sync transcripts | `/tmp/agent-sessions/<user>/` (`0700`), or `~/sessions/` with `--persist-session` |
|
|
108
108
|
| the suggestions store and catalog cache, the welcome flag and profile | `/var/lib/slicc/agent/shared/` (root, `0700`). The built-in welcome and suggestions sprinkles read it as `/shared/…`, through the worker and only inside that folder; a user's sprinkle reads `/shared/…` as its owner's home |
|
|
@@ -159,7 +159,7 @@ app.model = { ...createKernelModel({ kernel, root }), ...createAgentModel(agent,
|
|
|
159
159
|
|
|
160
160
|
The adapter keeps the replicated transcript and maps it on every update. User, assistant and compaction entries become messages; tool results fill in the tool calls they answer; the generation in flight shows as a streaming message; retries and running compactions show as system messages. A failed generation ends in an error card whose action fits the error: credential errors (an invalid or missing key, 401/403, not authorized) open settings, a model the account can't use offers the model picker, and anything else offers Retry. A content-filter stop is different: every later request resends the content that tripped the filter, so Retry, and any new message, would be stopped again. Content-filter stops are Bedrock's `content_filtered` and `guardrail_intervened`, Anthropic's `sensitive` and refusals, and OpenAI's `content_filter`. Their card leads with "The model's content filter stopped this reply." and offers **Drop the last turn** (spectrum ≥ 1.12.0). `AgentControl.rewind(messageId)` finds the user turn before that message and forks the cone's conversation at the entry before it (`Conversation.fork`, so `pi.agent` comes back as it was there). It points the cone at the fork and returns the turn's prompt, which spectrum puts back into the composer. Forking the very first turn creates a fresh conversation with the same model and thinking level. The filtered branch stays in storage, off the active path. The fork starts with a `slicc.rewound` entry that shows as a "Rewound 1 turn" notice, and clicking the card of an earlier filtered turn rewinds that turn.
|
|
161
161
|
|
|
162
|
-
Each cone's active conversation is in the session document `slicc.agents` (the root until the first rewind). The host's transcript follows it across forks. Rewinding is refused while the cone itself is running or has queued input, because a fork starts with an empty inbox, but never because its scoops are busy (see Cones and scoops). A background compaction still running on the old branch finishes there. A fork also starts with fresh `pi.usage`. Credential and model errors lead with a plain sentence ("Bedrock rejected the API key.", "This model isn't available with the current account.") and keep the provider's raw error as `detail`, which spectrum (≥ 1.11.0) shows underneath. `busy()` and `queue()` read durable's live and inbox documents. Steering is the default (#4): a send or a steer goes out with `whenBusy: 'steer'`, so while a run is going it joins after the current tool round, and a `queue` send is a follow-up. User messages carry `delivered` from the host's deliveries; entries the host didn't record (from before a reload) count as steered when they follow a tool result. Cones and scoops are below; the freezer and questions come later. Licks show as spectrum's lick cards (below). slicc-spectrum is an optional peer dependency (≥ 1.
|
|
162
|
+
Each cone's active conversation is in the session document `slicc.agents` (the root until the first rewind). The host's transcript follows it across forks. Rewinding is refused while the cone itself is running or has queued input, because a fork starts with an empty inbox, but never because its scoops are busy (see Cones and scoops). A background compaction still running on the old branch finishes there. A fork also starts with fresh `pi.usage`. Credential and model errors lead with a plain sentence ("Bedrock rejected the API key.", "This model isn't available with the current account.") and keep the provider's raw error as `detail`, which spectrum (≥ 1.11.0) shows underneath. `busy()` and `queue()` read durable's live and inbox documents. Steering is the default (#4): a send or a steer goes out with `whenBusy: 'steer'`, so while a run is going it joins after the current tool round, and a `queue` send is a follow-up. User messages carry `delivered` from the host's deliveries; entries the host didn't record (from before a reload) count as steered when they follow a tool result. Cones and scoops are below; the freezer and questions come later. Licks show as spectrum's lick cards (below). slicc-spectrum is an optional peer dependency (≥ 1.84.0, the lowest whose monitor, tray, panel, guest seat and guest approval types match the agent's; `npm run typecheck` fails on anything older), used for types only, so package managers don't install it next to the agent.
|
|
163
163
|
|
|
164
164
|
Each agent in `list()` has a real `contextFill` and `unread`:
|
|
165
165
|
- **`contextFill`** is the context the agent uses, as a share of its model's `contextWindow` from the settings' model list. The tokens are those of the newest assistant's usage after the active head, counted the way pi-ai's `calculateContextTokens` does (`totalTokens`, or input, output and both cache counts). Aborted and failed turns don't count. After a compaction, the kept turns' usage no longer counts. Until the next turn reports its usage, the fill is estimated the way pi does it, at four characters a token, over the summary and the kept entries (without the system prompt and tools). An unknown model also reads 0. The Monitor's "Fullest context" and its context alerts use the same functions (`src/context.ts`).
|
|
@@ -201,21 +201,28 @@ gone /home/notes/old.md
|
|
|
201
201
|
|
|
202
202
|
**Stop.** pi's `Conversation.abort()` withdraws every queued steer and follow-up, so a lick that wasn't placed yet is withdrawn with them, and the events merged behind it are dropped too: Stop leaves the cone quiet. Events that arrive after Stop are delivered as usual, and an idle cone starts a run for them.
|
|
203
203
|
|
|
204
|
-
**Configuration** lives in files under `~/.slicc` (`/home/.slicc`), which the user and the agent edit with any tool. The worker watches the folder and reconciles on every change. Each malformed line or file becomes one lick naming the file, the line and the problem, once per distinct problem, with `severity="error"`; the entry is ignored until it's fixed. Names are 1–64 of `a-z 0-9 . _ -`, starting with a letter or digit. A target is `cone` (the active cone) or `scoop:<handle>`; a lick for a scoop that is stopped or gone goes to the cone, and webhooks always go to the cone. Files starting with `.` or ending in `~` are skipped; any other file that isn't `<name>.json` in `watches/` or `webhooks/` is an error.
|
|
204
|
+
**Configuration** of watches and webhooks lives in files under `~/.slicc` (`/home/.slicc`), which the user and the agent edit with any tool. The worker watches the folder and reconciles on every change. Each malformed line or file becomes one lick naming the file, the line and the problem, once per distinct problem, with `severity="error"`; the entry is ignored until it's fixed. Names are 1–64 of `a-z 0-9 . _ -`, starting with a letter or digit. A target is `cone` (the active cone) or `scoop:<handle>`; a lick for a scoop that is stopped or gone goes to the cone, and webhooks always go to the cone. Files starting with `.` or ending in `~` are skipped; any other file that isn't `<name>.json` in `watches/` or `webhooks/` is an error.
|
|
205
205
|
|
|
206
|
-
- `~/.slicc/crontab`, one job per line: `<schedule> <name> [<target>] [<message>]`. The schedule is five fields (minute, hour, day of month, month, day of week, with `*`, ranges, steps, lists and `jan`–`dec`/`sun`–`sat` names; 7 is Sunday, and a job whose day of month and day of week are both set runs on either) or `@yearly`, `@monthly`, `@weekly`, `@daily`, `@hourly`. Times are the browser's local time. Blank lines and `#` comments are ignored.
|
|
207
|
-
```
|
|
208
|
-
*/15 9-17 * * mon-fri standup Summarize what changed in ~/notes since the last standup
|
|
209
|
-
@daily backup scoop:ops
|
|
210
|
-
```
|
|
211
206
|
- `~/.slicc/watches/<name>.json`: `{ "path": "~/notes", "glob": "**/*.md", "target": "cone", "message": "…", "debounce": 500 }`. `path` is absolute or starts with `~/`; `glob` (default `**`) is matched against paths relative to it, with `*`, `**`, `?`, `[…]` and `{a,b}`. `debounce` is 100–60000 ms. `node_modules` and `.git` are never scanned.
|
|
212
207
|
- `~/.slicc/webhooks/<name>.json`: `{ "target": "cone", "message": "…" }`. The URL comes from the tray hub (milestone E); until then, `AgentControl.webhook(name, { id, headers, body })` is how a delivery arrives.
|
|
213
208
|
|
|
209
|
+
**Schedules** are the kernel's crontab (slicc-kernel ≥ 1.110.0), not the agent's: each user's table in `/var/spool/cron/crontabs/<user>`, installed with `crontab -` and listed with `crontab -l`. The kernel runs each due job as its user, with `$SHELL -c` in `$HOME`, and a job that runs `agent send` comes back as a cron lick:
|
|
210
|
+
```
|
|
211
|
+
# name: standup
|
|
212
|
+
*/15 9-17 * * mon-fri agent send cone "Summarize what changed in ~/notes since the last standup"
|
|
213
|
+
# name: backup
|
|
214
|
+
@daily agent send scoop:ops
|
|
215
|
+
```
|
|
216
|
+
- **`agent send` under `SLICC_CRON=1`** (the kernel sets it for every job, with `SLICC_CRON_JOB`, `SLICC_CRON_DUE` and `SLICC_CRON_MISSED`) delivers `<lick channel="cron">` instead of a message: source and title are the job's `# name:` (the kernel's hash of the line without one), the text says when it was due (`standup fired at 2026-10-17 11:00`), the message is the body, and `count` is 1 plus the missed runs (`standup was due at 2026-10-17 14:00; 2 more fires were missed while seven was closed`). Its id is `<job>@<due>`, so a run is delivered once. The `agent` script passes the four variables in its request (protocol `slicc-agent/2`; `slicc-agent/1` requests still parse).
|
|
217
|
+
- **Which agent:** a job's environment is a login's, so `SLICC_AGENT` and the page's variables don't reach it. The `agent` script needs only `$USER`: it writes to `/var/lib/slicc/agent/requests/$USER/`, the folder of that kernel user, so the job's user decides who it is. In a cone's crontab, `agent send cone` wakes that cone and `agent send <handle>` one of its scoops (a scoop the cone doesn't have falls back to the cone); in root's, `cone` is the active cone; a scoop's own crontab can only wake the scoop itself. A frozen cone's job is skipped with the usual `warn` lick.
|
|
218
|
+
- **Missed runs, overlap, several tabs and logs** are the kernel's: missed runs fold into one, at most once per due time, one tab per storage root fires, and each run's output goes to `/var/log/cron/<user>/<name>.log`.
|
|
219
|
+
- **Moving `~/.slicc/crontab`:** the agent no longer schedules anything. At start and whenever the file changes, each `~/.slicc/crontab` (`<schedule> <name> [<target>] [<message>]` per line) is moved into the kernel crontab: its jobs become `# name: <name>` and `<schedule> agent send <target> '<message>'`, replacing jobs of the same names and keeping the rest of the table. A line aimed at a live scoop goes into that scoop's own user's crontab; the others go into the crontab of the file's owner (the cone's user, or root's for `/root/.slicc` and without kernel users). Then the file is kept as `~/.slicc/crontab.migrated` and removed. A line that doesn't parse, or a table `crontab` refuses (it exits 1 and keeps the old table), becomes a `cron` lick with `severity="error"` naming the line and the problem, and the file stays until it's fixed. Durable `slicc.cron` tasks from earlier versions are aborted at start.
|
|
220
|
+
|
|
214
221
|
**Triage.** A watch or webhook file can add `"triage": "<which events the agent should see>"`, a sentence of 1–1000 characters such as `"pushes to main that touch src/"`. Then each of its events (a debounced batch of changes, or a webhook request) first goes to Clef Flash (`adobe/clef-flash`, see Classifiers) with the channel, source, title, text, body (cut at 4000 characters) and up to 50 paths. One `choice` question asks whether the event matches that sentence: `act` or `ignore`. When the answer is `ignore` with a probability of at least 0.75 (`TRIAGE_SKIP`), the lick isn't delivered and starts no turn. Instead, a passive `slicc.lick-triage` entry goes into the target's transcript. It has no model message, so neither the model nor the chat sees it, and it records the would-be lick with the triage sentence, the decision, Clef's confidence and probabilities, the model and the cost. An event whose delivery id was already seen isn't triaged again. A skipped one is remembered only after its record is written, under a `requestId` taken from the delivery id, so a crash in between neither loses the record nor writes it twice. Triage fails open: without an Adobe sign-in, or when the proxy errors, times out (15 s) or returns any other answer, the lick is delivered as usual. Watch notices (stopped, overflow), config errors, frozen notices, crontab jobs and boot licks are never triaged. A small webhook event is about 220 input tokens, which is $0.00002 against the weekly budget; a 4000-character body is about $0.0001.
|
|
215
222
|
|
|
216
223
|
**Sources.**
|
|
217
224
|
- `fswatch`: the kernel environment's `watch()` reports changed paths; those matching the glob are collected for `debounce` ms and delivered as one lick with `changed` or `gone` per path. A watch that overflows or stops says so in a lick (a stopped one with `severity="error"`, an overflow with `severity="warn"`), and saving its file restarts it. Changes made while no worker runs aren't reported. **The agent's own changes are dropped**, so it never licks itself: the kernel environment records every path its file tools write, edit, move or remove, and the time its `bash` commands run; a change to such a path within 2 s, or any change while an agent command runs or within 2 s after it, counts as the agent's. A change the user makes while an agent command runs is therefore dropped too. Background processes the agent started (`&`) aren't tracked, so their changes do lick.
|
|
218
|
-
- `cron`:
|
|
225
|
+
- `cron`: `agent send` from a kernel cron job (see Schedules).
|
|
219
226
|
- `webhook`: each request is its own lick, with the headers and the body; a delivery `id` makes retries idempotent.
|
|
220
227
|
- `upgrade`: when the worker starts with a different slicc-agent version than the session recorded, with the release notes link. Every change of version is its own lick, also back and forth.
|
|
221
228
|
- `session-reload`: when the kernel's boot time (`btime` in `/proc/stat`) differs from the last worker start and the cone ran `bash` since then. The page reloaded, so the kernel's processes are gone; the lick lists background commands (`&`, `nohup`, `setsid`, `disown`) that are no longer running. Durable itself resumes an interrupted run.
|
|
@@ -378,7 +385,7 @@ The `memory` section, read before every request, holds the first 200 lines (at m
|
|
|
378
385
|
**Extraction.** Durable compacts a long conversation into a summary; before it does, a `beforeCompact` hook (which never declines or replaces the summary) schedules a `slicc.memory-extract` task for the cone. A cone that has been idle for `memory.idleMinutes` (30 by default, `0` turns the idle trigger off) gets the same task. The task runs only when there is something new since the last extraction (a cursor per conversation in the session document `slicc.memory-extract`), makes one model call, with the cone's model unless `memory.extractModel` names a cheaper one (`provider/model`), and writes the proposed entries through `memory_write`'s writer into the cone's memory file, within its 16 KB. The transcript it sends is redacted first, its prompt forbids secrets, and the writer redacts again. `"memory": { "extract": false }` in `~/.pi/agent/settings.json` turns extraction off. v6's curator scoop, three-way merge, curation ledger and dreamer aren't ported.
|
|
379
386
|
|
|
380
387
|
**The gelatiere.** SLICC's resident advisor, as in v6, is a scoop with the built-in `gelatiere` role. That role has its own memory (`memory: { scope: user, path: gelatiere }`), so it keeps its notes there.
|
|
381
|
-
- `gelatiere init` starts the scoop in the first cone, writes `~/.pi/agent/GELATIERE.md` (its procedure, which the user can edit) unless it exists, and
|
|
388
|
+
- `gelatiere init` starts the scoop in the first cone, writes `~/.pi/agent/GELATIERE.md` (its procedure, which the user can edit) unless it exists, and installs one job `# name: gelatiere` / `0 3 * * * agent send scoop:<handle> 'Nightly pass: …'` in the scoop's own crontab (root's without kernel users), replacing an older one. `gelatiere status` shows its schedule from there.
|
|
382
389
|
- **Procedure updates:** at every boot, an existing GELATIERE.md that is a shipped version (its sha-256 is in `SHIPPED`, or matches `GELATIERE.md.sha256`, written whenever the agent writes the file) is replaced by the built-in one. A file with the user's edits is kept, the new built-in one goes to `~/.pi/agent/GELATIERE.new.md`, and `gelatiere status` says so.
|
|
383
390
|
- On each pass it reads memory, the installed skills, the roles and the lick files, and writes at most three suggestions as JSON. `gelatiere suggest <file>` validates them and folds them into `/home/.gelatiere/suggestions.json` by id:
|
|
384
391
|
- kinds `skill`, `use-case`, `tip`, `skill-idea` and `issue`;
|
|
@@ -611,7 +618,7 @@ Every approval, of a guest's prompt, of a tool call in a run a guest started, or
|
|
|
611
618
|
- **Lifetime:** an item waits 5 minutes unless its requester sets `expiresAt`, then settles `unanswered`. Pending guest items survive a reload of the worker; pending `sudo` items are withdrawn (`restart`), because a reload ends the kernel's processes. The document keeps every pending item and the last 100 settled ones.
|
|
612
619
|
- **In the worker,** `AgentHost.approvals` has `request(draft, ctx)`, `decide(id, answer, reason, by, ctx)` (`by` is a `DecidedBy`, or `{ by, device }` to record the deciding device), `settled(id, ctx)` (resolves when the item leaves `pending`), `withdraw(id, reason, ctx)` and `withdrawSeat(seat, ctx)`, which withdraws a revoked seat's pending items.
|
|
613
620
|
- **Over the link,** `AgentTranscript.approvals` replicates the items, and `AgentControl.decide(id, decision, reason, ctx)` answers one, for every owner device: the owner's pages and followers with or without Control, all with the same powers. `decidedBy` comes from the link's seat (`owner` for the owner's pages, `follower` for the others), and is only a record of who answered. A guest never gets `decide`.
|
|
614
|
-
- **In spectrum** (1.
|
|
621
|
+
- **In spectrum** (1.84 on, which shows guest approvals in `<slicc-approvals>` with Always allow when `always` is true, as notices without `decide`, and an `unsure` verdict), `createAgentModel` returns `approvals`, an `ApprovalsAdapter` for `SliccModel.approvals`. `list()` has the pending `user` items, oldest first, as spectrum's `Approval`s, with the cone's name as `agentName` and the item's own `always`, so a guest approval offers Always allow only when the policy did when it was asked. `decide(id, decision, reason?)` rejects with the agent's message, and `ended` reports `answered`, `expired` or `withdrawn` for an item that left without this tab's decision. Every owner device's adapter has `decide`; a guest connection's doesn't. So a notice instead of a dialog shows only where nothing can answer.
|
|
615
622
|
- **Kernel sudo:** `AgentOwner.approve(req, { signal, where? })` from `startAgent` takes slicc-kernel's sudo request as it comes to the kernel's `approve` hook and resolves `once`, `always` or `deny`. bios hands its hook to it while the agent runs, and to its own dialog otherwise. It rejects with `code: 'EAGAIN'` before anything is recorded when the agent can't take the request (released, restarting, or an older worker), so that's when to fall back; any other rejection is a deny. The request goes through `slicc.agent.sudo`, a service only the owner's pages get, and becomes a `sudo` item on the `user` tier with the kernel's `expiresAt`:
|
|
616
623
|
- **Requester** comes from the kernel's process tag: `{ kind: 'agent', agentId }` is the cone or scoop by its name, `{ kind: 'user', where }` is the kernel user with `where` (`terminal:…` reads "a terminal", `follower:<device>` the `where` the page passes, such as "on Pat's phone", or "a linked device", with the device id kept as `requester.device`), and anything else is the kernel user alone.
|
|
617
624
|
- **Detail:** the command as the kernel resolved it (`path` and the arguments, shell-quoted), `target`, `cwd`, and `alwaysScope: 'cwd'` when the request offers Always (`req.always === true`, which the page sets from its own checks), since the kernel's Always writes a rule for that directory.
|
|
@@ -666,7 +673,7 @@ All the limits on approvals and guests live in one owner-changeable policy, the
|
|
|
666
673
|
|
|
667
674
|
A guest seat (plan D13, PR 19) is a revocable seat on one cone: the guest sees that cone's live transcript and has a composer, and nothing else.
|
|
668
675
|
|
|
669
|
-
- **Minting.** The tray hub mints the seat and its one-time URL (v6's routes, D10); the page hands the agent adapter its routes: `createAgentModel(connection, { guests: { mint({ label, expiresAt, gates, agentId }) → { id, url }, revoke(id) } })`. Its `guests` port (spectrum's `GuestPort`) mints through the hub, then opens the seat in the worker with `AgentControl.guestOpen({ id, label, agentId, expiresAt, gates })`; if the worker refuses, the hub's seat is revoked again. `list()` is the transcript's `guests` state (`{ id, label, agentId, createdAt, expiresAt, gates, connected, pending, alwaysTools }`), and the URL is returned once and never kept. `unavailable()` says "Inviting guests needs the tray hub." without a hub, and "Only the owner's devices can invite guests." on a guest. Every owner device can invite, with or without Control. `gates()` lists the gates the approval policy allows for messages and tools, in display order,
|
|
676
|
+
- **Minting.** The tray hub mints the seat and its one-time URL (v6's routes, D10); the page hands the agent adapter its routes: `createAgentModel(connection, { guests: { mint({ label, expiresAt, gates, agentId }) → { id, url }, revoke(id) } })`. Its `guests` port (spectrum's `GuestPort`) mints through the hub, then opens the seat in the worker with `AgentControl.guestOpen({ id, label, agentId, expiresAt, gates })`; if the worker refuses, the hub's seat is revoked again. `list()` is the transcript's `guests` state (`{ id, label, agentId, createdAt, expiresAt, gates, connected, pending, alwaysTools }`), and the URL is returned once and never kept. `unavailable()` says "Inviting guests needs the tray hub." without a hub, and "Only the owner's devices can invite guests." on a guest. Every owner device can invite, with or without Control. `gates()` (spectrum's `GuestPort.gates?()`) lists the gates the approval policy allows for messages and tools, in display order, for the invite pickers; `scoop:*`, for "any scoop", shows only when the policy offers the scoop tier.
|
|
670
677
|
- **The record.** Seats live in the session document `slicc.guests`, so they survive reloads and restarts: id, label (control characters stripped, at most 64 characters), cone, expiry (at most the policy's `guests.maxSeatDays`, 30 by default), the two gates (`user`, `agent`, `cone`, `scoop:<name>` or `off`, fixed when the seat is opened and checked then against the policy's `allowedMessageGates` and `allowedToolGates`; by default the tools gate can't be `off` or `cone`, from any caller: "A guest's tool calls need a review: by a person, the judge or a scoop.") and an epoch. Revoking (`guestRevoke(id)`) keeps a tombstone, bumps the epoch, withdraws the guest's messages still queued in the cone, and ends every guest link of the seat (`invalidatePrincipal`). An expired seat ends the same way at its expiry. Tombstones go 365 days after they end, the longest a seat can be opened for.
|
|
671
678
|
- **Joining.** The hub resolves the guest's token to the seat's id and label, and the owner page opens `owner.port({ guest: { id, label } })` and bridges it like a follower's. Before Chord sees the link, the worker checks that the seat exists, isn't revoked or expired, and has that label; otherwise it closes the port. The link's principal is `{ seat: 'guest', link, guest: { id, name, epoch } }`, and anything else the port asks for (`readOnly: false`, `pages`) is ignored.
|
|
672
679
|
- **What a guest gets.** Every contract served from the agent's host refuses a guest principal (`forbidden`) unless its factory is opened with `openToGuests`, so a contract added later is closed to guests until someone opens it. The only open one is `slicc.agent.guest`: its `guest` variant has the shared cone's transcript (its user, assistant, tool and compaction entries; `pi.live`; `pi.agent`'s model and thinking level; and only the guest's own queued messages) and the seat, plus `propose({ text, requestId })`. Everyone else gets its empty `none` variant.
|
|
@@ -700,7 +707,7 @@ The agent never holds a secret's value. Values live in the vault (`vault.sliccy.
|
|
|
700
707
|
|
|
701
708
|
## The kernel
|
|
702
709
|
|
|
703
|
-
`@ai-ecoverse/slicc-kernel` is a peer dependency (`>=1.
|
|
710
|
+
`@ai-ecoverse/slicc-kernel` is a peer dependency (`>=1.110.0 <2`; until 3.31.0 the floor was 1.26.3, then 1.47.1, then 1.81.0, then 1.90.0): the agent only calls `attachKernel`, the client end of the page kernel's port, so it must match the kernel the page runs. Seven chooses that version: slicc-bios pins the certified kernel next to the agent in `src/packages/agent/package.json`, and pnpm fills the peer from that pin. The floor is 1.110.0, the first kernel with its own cron and `crontab`, which the agent's schedules need; it is ahead of the certified kernel, so slicc-bios must pin 1.110.0 or later with this agent. The kernel and the `wasm-*` commands are devDependencies, pinned to certified versions except the kernel (1.110.0, for its cron), and CI runs the unit and integration tests on them in one leg. If the port protocol ever breaks within 1.x, a patch release narrows the upper bound. Renovate opens PRs for the kernel, `wasi-pnpm`, the `wasm-*` packages and `slicc-cdp` but never merges them, because they move only after the homescoop coordinator certifies them; such a PR is merged once the cert lane has certified its version.
|
|
704
711
|
|
|
705
712
|
## Patched dependencies
|
|
706
713
|
|
package/bin/agent
CHANGED
|
@@ -6,13 +6,15 @@ case "$as" in subagent|memory|gelatiere|freezer|models|panel) ;; *) as=agent ;;
|
|
|
6
6
|
[ -d "$dir/in" ] && [ -d "$dir/out" ] || mkdir -p "$dir/in" "$dir/out" 2>/dev/null
|
|
7
7
|
who="${SLICC_AGENT:-}"
|
|
8
8
|
if [ -z "$who" ] && [ -n "${SLICC_TAB:-}" ]; then who="tab:$SLICC_TAB"; fi
|
|
9
|
+
cron=""
|
|
10
|
+
if [ "${SLICC_CRON:-}" = 1 ]; then cron="${SLICC_CRON_JOB:-} ${SLICC_CRON_DUE:-} ${SLICC_CRON_MISSED:-0}"; fi
|
|
9
11
|
|
|
10
12
|
submit() {
|
|
11
13
|
local id="$1"
|
|
12
14
|
shift
|
|
13
15
|
local tmp="$dir/in/.tmp-$id"
|
|
14
16
|
{
|
|
15
|
-
printf '%s\0' "slicc-agent/
|
|
17
|
+
printf '%s\0' "slicc-agent/2" "$as" "$who" "$PWD" "$$" "$cron" "$#"
|
|
16
18
|
if [ $# -gt 0 ]; then printf '%s\0' "$@"; fi
|
|
17
19
|
if [ "$stdin" = 1 ]; then cat; fi
|
|
18
20
|
} > "$tmp" && mv "$tmp" "$dir/in/$id"
|
package/dist/gelatiere/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { BACKGROUND_CONTEXT } from "@earendil-works/chord/context";
|
|
2
2
|
import { live } from "../agents.js";
|
|
3
|
+
import { ROOT_USER } from "../layout.js";
|
|
4
|
+
import { installJobs, readTable, scheduleOf, sendCommand } from "../licks/crontab.js";
|
|
3
5
|
import { skillFromText } from "../skills/skills.js";
|
|
4
6
|
import {
|
|
5
7
|
CATALOG_BASE,
|
|
@@ -40,13 +42,7 @@ const USAGE = `usage:
|
|
|
40
42
|
|
|
41
43
|
The store is ${STORE}; the suggestions sprinkle shows it.
|
|
42
44
|
`;
|
|
43
|
-
|
|
44
|
-
return `${SCHEDULE} ${ROLE} scoop:${handle} Nightly pass: read ~/.pi/agent/GELATIERE.md and follow it.`;
|
|
45
|
-
}
|
|
46
|
-
const JOB = new RegExp(`^((?:\\S+\\s+){4}\\S+|@\\w+)\\s+${ROLE}(?:\\s|$)`);
|
|
47
|
-
function scheduleOf(entry) {
|
|
48
|
-
return JOB.exec(entry.trim())?.[1]?.replace(/\s+/g, " ");
|
|
49
|
-
}
|
|
45
|
+
const PASS = "Nightly pass: read ~/.pi/agent/GELATIERE.md and follow it.";
|
|
50
46
|
function handleOf(agents) {
|
|
51
47
|
const found = Object.entries(agents.state().scoops).find(
|
|
52
48
|
([, record]) => record.role === ROLE && live(record)
|
|
@@ -62,14 +58,15 @@ async function callerOf(g, context) {
|
|
|
62
58
|
}
|
|
63
59
|
const fail = (out) => ({ code: 1, out: `gelatiere: ${out}
|
|
64
60
|
` });
|
|
61
|
+
async function cronUserOf(g, handle) {
|
|
62
|
+
return await g.options.cronUser?.(handle) ?? ROOT_USER;
|
|
63
|
+
}
|
|
65
64
|
async function schedule(g, handle, context) {
|
|
66
|
-
const
|
|
67
|
-
const
|
|
68
|
-
const
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
await env.writeFile(g.crontab, `${[...kept, line(handle)].join("\n")}
|
|
72
|
-
`, context);
|
|
65
|
+
const command = sendCommand(`scoop:${handle}`, PASS);
|
|
66
|
+
const user = await cronUserOf(g, handle);
|
|
67
|
+
const job = { name: ROLE, schedule: SCHEDULE, command };
|
|
68
|
+
const problems = await installJobs(g.options.env, user, [job], context);
|
|
69
|
+
return problems.length ? problems.map((problem) => problem.error).join("; ") : void 0;
|
|
73
70
|
}
|
|
74
71
|
const SHIPPED = [
|
|
75
72
|
"53bc19daa486dec24116d8cf0558a498d8476dc4e18874f8a3e9ccb9defb15bd",
|
|
@@ -132,7 +129,8 @@ async function init(g, context) {
|
|
|
132
129
|
if (spawned.code !== 0) return { code: 1, out: `gelatiere: ${spawned.out}` };
|
|
133
130
|
handle = spawned.out.trim();
|
|
134
131
|
}
|
|
135
|
-
await schedule(g, handle, context);
|
|
132
|
+
const refused = await schedule(g, handle, context);
|
|
133
|
+
if (refused) return fail(`couldn't install the crontab line of scoop ${handle}: ${refused}`);
|
|
136
134
|
return {
|
|
137
135
|
code: 0,
|
|
138
136
|
out: `the gelatiere is scoop ${handle}; it runs at ${SCHEDULE} (crontab) and with gelatiere run, following ${g.procedure}
|
|
@@ -374,8 +372,8 @@ async function status(g, context) {
|
|
|
374
372
|
const { env, agents } = g.options;
|
|
375
373
|
const store = await readStore(env, context, g.store);
|
|
376
374
|
const handle = handleOf(agents);
|
|
377
|
-
const
|
|
378
|
-
const scheduled =
|
|
375
|
+
const table = handle ? await readTable(env, await cronUserOf(g, handle), context) : "";
|
|
376
|
+
const scheduled = typeof table === "string" ? scheduleOf(table, ROLE) : void 0;
|
|
379
377
|
const counts = store ? `${open(store).length} open, ${store.filter((item) => item.takenAt).length} taken, ${store.filter((item) => item.dismissedAt).length} dismissed` : "none yet";
|
|
380
378
|
const pending = await g.files.readTextFile(g.pending, context);
|
|
381
379
|
const lines = [
|
|
@@ -419,7 +417,6 @@ function attachGelatiere(options) {
|
|
|
419
417
|
serial,
|
|
420
418
|
options,
|
|
421
419
|
now,
|
|
422
|
-
crontab: `${home}/.slicc/crontab`,
|
|
423
420
|
procedure: `${home}/.pi/agent/GELATIERE.md`,
|
|
424
421
|
pending: `${home}/.pi/agent/GELATIERE.new.md`,
|
|
425
422
|
files: options.files ?? env,
|
|
@@ -475,6 +472,7 @@ function lateGelatiere() {
|
|
|
475
472
|
}
|
|
476
473
|
export {
|
|
477
474
|
INSTALLER,
|
|
475
|
+
PASS,
|
|
478
476
|
PROCEDURE,
|
|
479
477
|
ROLE,
|
|
480
478
|
SCHEDULE,
|
|
@@ -483,7 +481,6 @@ export {
|
|
|
483
481
|
USAGE,
|
|
484
482
|
attachGelatiere,
|
|
485
483
|
lateGelatiere,
|
|
486
|
-
scheduleOf,
|
|
487
484
|
upskillScript
|
|
488
485
|
};
|
|
489
486
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/gelatiere/index.ts"],
|
|
4
|
-
"sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { ExecutionEnv } from '@earendil-works/pi-durable/env';\nimport { type Agents, live } from '../agents.ts';\nimport type { Licks } from '../licks/licks.ts';\nimport type { Roles } from '../roles/roles.ts';\nimport type { Scoops } from '../scoops/service.ts';\nimport { skillFromText } from '../skills/skills.ts';\nimport {\n CATALOG_BASE,\n CATALOG_DIR,\n type Fetcher,\n merge,\n PROFILE,\n type Profile,\n parseSkills,\n parseUseCases,\n profileOf,\n type Sheet,\n score,\n sheet,\n slugifyCompany,\n} from './catalog.ts';\nimport {\n fold,\n open,\n readStore,\n STORE,\n type Suggestion,\n storeOf,\n validate,\n writeStore,\n} from './store.ts';\n\nexport type Answer = { code: number; out: string };\n\nexport const ROLE = 'gelatiere';\nexport const SPRINKLE = 'suggestions';\nexport const PROCEDURE = 'packages/vfs-root/gelatiere/GELATIERE.md';\nexport const SCHEDULE = '0 3 * * *';\n\nexport interface GelatiereAttach {\n agents: Agents;\n licks: Licks;\n env: ExecutionEnv;\n home: string;\n scoops: Scoops;\n roles: (context: Context) => Promise<Roles>;\n assets?: (path: string) => Promise<string>;\n now?: () => number;\n fetch?: Fetcher;\n catalog?: string;\n skills?: () => readonly { name: string }[];\n files?: ExecutionEnv;\n profile?: string;\n shared?: string;\n as?: (caller: string | null, context: Context) => Promise<Caller | undefined>;\n}\n\nexport interface Caller {\n env: ExecutionEnv;\n home: string;\n}\n\nexport interface GelatiereRuntime {\n command(argv: readonly string[], caller: string | null, context: Context): Promise<Answer>;\n intercept(action: string, data: unknown, context: Context): Promise<boolean>;\n readonly seeded: Promise<Seeded>;\n}\n\nexport const USAGE = `usage:\n gelatiere init start the gelatiere scoop and its nightly crontab line\n gelatiere run ask the gelatiere for a pass now\n gelatiere suggest <file> fold a JSON array of suggestions into the store\n gelatiere deliver lick each cone with the suggestions that are new for it\n gelatiere catalog [--refresh] [--all] [--json]\n rank the www.sliccy.com skill and use-case catalog for this user\n gelatiere install <id> install a suggested skill with upskill into ~/.pi/agent/skills\n gelatiere list [--all] [--json]\n gelatiere dismiss <id> mark a suggestion as not wanted\n gelatiere status\n\nThe store is ${STORE}; the suggestions sprinkle shows it.\n`;\n\nfunction line(handle: string): string {\n return `${SCHEDULE} ${ROLE} scoop:${handle} Nightly pass: read ~/.pi/agent/GELATIERE.md and follow it.`;\n}\n\nconst JOB = new RegExp(`^((?:\\\\S+\\\\s+){4}\\\\S+|@\\\\w+)\\\\s+${ROLE}(?:\\\\s|$)`);\n\nexport function scheduleOf(entry: string): string | undefined {\n return JOB.exec(entry.trim())?.[1]?.replace(/\\s+/g, ' ');\n}\n\nfunction handleOf(agents: Agents): string | undefined {\n const found = Object.entries(agents.state().scoops).find(\n ([, record]) => record.role === ROLE && live(record)\n );\n return found?.[1].folder;\n}\n\nfunction row(item: Suggestion): string {\n const state = item.takenAt ? 'taken' : item.dismissedAt ? 'dismissed' : 'open';\n return `${item.id}\\t${item.kind}\\t${state}\\t${item.title}`;\n}\n\ntype G = {\n serial: <T>(work: () => Promise<T>) => Promise<T>;\n options: GelatiereAttach;\n now: () => number;\n crontab: string;\n procedure: string;\n pending: string;\n load: (context: Context) => Promise<Suggestion[]>;\n mark: (id: string, field: 'dismissedAt' | 'takenAt', context: Context) => Promise<boolean>;\n files: ExecutionEnv;\n caller: string | null;\n store: string;\n catalog: string;\n};\n\nasync function callerOf(g: G, context: Context): Promise<Caller> {\n return (await g.options.as?.(g.caller, context)) ?? { env: g.options.env, home: g.options.home };\n}\n\nconst fail = (out: string): Answer => ({ code: 1, out: `gelatiere: ${out}\\n` });\n\nasync function schedule(g: G, handle: string, context: Context): Promise<void> {\n const { home } = g.options;\n const env = g.files;\n const read = await env.readTextFile(g.crontab, context);\n const kept = (read.ok ? read.value : '')\n .split('\\n')\n .filter((entry) => entry.trim() && !scheduleOf(entry));\n await env.createDir(`${home}/.slicc`, { recursive: true }, context);\n await env.writeFile(g.crontab, `${[...kept, line(handle)].join('\\n')}\\n`, context);\n}\n\nexport const SHIPPED = [\n '53bc19daa486dec24116d8cf0558a498d8476dc4e18874f8a3e9ccb9defb15bd',\n '1c16654b93bc01179a71ec907919f45132b2e9f1a9ac331b213655c66387b4e5',\n '3bdd8ae18831c37996413cb0277df7141fcd0dff2d056c7b7053c34f0a3beaac',\n '23a063c8156fda9fb0ffdea20172a7f64c1576d1c009a28456c095e2866fc0e9',\n];\n\nexport type Seeded = 'written' | 'updated' | 'current' | 'kept' | 'none';\n\nasync function sha256(text: string): Promise<string> {\n const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(text));\n return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, '0')).join('');\n}\n\nasync function seed(g: G, context: Context, create: boolean): Promise<Seeded> {\n const { assets } = g.options;\n const env = g.files;\n const text = assets ? await assets(PROCEDURE).catch(() => undefined) : undefined;\n if (text === undefined) return 'none';\n const bundled = await sha256(text);\n const marker = `${g.procedure}.sha256`;\n const must = (result: { ok: boolean; error?: { message: string } }) => {\n if (!result.ok) throw new Error(result.error?.message ?? 'write failed');\n };\n const write = async (state: Seeded): Promise<Seeded> => {\n must(await env.writeFile(g.procedure, text, context));\n must(await env.writeFile(marker, `${bundled}\\n`, context));\n must(await env.remove(g.pending, { force: true }, context));\n return state;\n };\n const read = await env.readTextFile(g.procedure, context);\n if (!read.ok) return create ? write('written') : 'none';\n const mine = await sha256(read.value);\n if (mine === bundled) return write('current');\n const last = await env.readTextFile(marker, context);\n if ((last.ok && last.value.trim() === mine) || SHIPPED.includes(mine)) return write('updated');\n must(await env.writeFile(g.pending, text, context));\n return 'kept';\n}\n\nasync function init(g: G, context: Context): Promise<Answer> {\n const { options } = g;\n await seed(g, context, true);\n let handle = handleOf(options.agents);\n if (!handle) {\n const roles = await options.roles(context);\n const role = roles.roles.find((entry) => entry.name === ROLE);\n if (!role) return fail('the gelatiere role is missing');\n const spawned = await options.scoops.spawn(\n {\n cone: 'cone',\n kind: 'async',\n name: ROLE,\n role,\n prompts: [],\n target: null,\n fromAgent: false,\n request: `gelatiere-init-${g.now()}`,\n limits: roles.limits,\n },\n context\n );\n if (spawned.code !== 0) return { code: 1, out: `gelatiere: ${spawned.out}` };\n handle = spawned.out.trim();\n }\n await schedule(g, handle, context);\n return {\n code: 0,\n out: `the gelatiere is scoop ${handle}; it runs at ${SCHEDULE} (crontab) and with gelatiere run, following ${g.procedure}\\n`,\n };\n}\n\nasync function run(g: G, context: Context): Promise<Answer> {\n const handle = handleOf(g.options.agents);\n if (!handle) return fail('there is no gelatiere yet; run gelatiere init');\n await g.options.licks.deliver(\n {\n channel: 'sprinkle',\n source: 'sprinkle:gelatiere',\n title: 'Gelatiere',\n text: 'run',\n body: `Run a pass now: read ${g.procedure} and follow it.`,\n target: `scoop:${handle}`,\n },\n context\n );\n return { code: 0, out: `asked scoop ${handle} for a pass\\n` };\n}\n\nasync function suggest(g: G, path: string | undefined, context: Context): Promise<Answer> {\n if (!path) return { code: 2, out: USAGE };\n const read = await (await callerOf(g, context)).env.readTextFile(path, context);\n if (!read.ok) return fail(`can't read ${path}`);\n let parsed: unknown;\n try {\n parsed = JSON.parse(read.value);\n } catch (error) {\n return fail(`${path} is not JSON (${(error as Error).message})`);\n }\n const folded = fold(await g.load(context), parsed, g.now());\n await writeStore(g.options.env, folded.store, context, g.store);\n const rejected = folded.rejected.map((reason) => `rejected ${reason}\\n`).join('');\n return {\n code: 0,\n out: `added ${folded.added}, updated ${folded.updated}, rejected ${folded.rejected.length}\\n${rejected}`,\n };\n}\n\nasync function deliver(g: G, context: Context): Promise<Answer> {\n const store = await g.load(context);\n const fresh = open(store).filter((item) => !item.deliveredAt);\n const cones = Object.keys(g.options.agents.state().cones);\n const byCone = new Map<string, Suggestion[]>();\n for (const item of fresh) {\n const named = (item.cones ?? []).filter((cone) => cones.includes(cone));\n for (const cone of named.length ? named : [g.options.agents.activeCone()])\n byCone.set(cone, [...(byCone.get(cone) ?? []), item]);\n }\n for (const [cone, items] of byCone) {\n const body = {\n added: items.length,\n open: open(store).length,\n suggestions: items.map(({ id, kind, title, body: text }) => ({\n id,\n kind,\n title,\n body: text,\n })),\n path: g.store,\n };\n await g.options.licks.deliver(\n {\n channel: 'sprinkle',\n source: `sprinkle:${SPRINKLE}`,\n title: 'Suggestions',\n text: 'gelatiere-suggestions',\n body: JSON.stringify(body, null, 2),\n target: `cone:${cone}`,\n },\n context\n );\n }\n for (const item of fresh) item.deliveredAt = g.now();\n if (fresh.length) await writeStore(g.options.env, store, context, g.store);\n return {\n code: 0,\n out: `delivered ${fresh.length} to ${[...byCone.keys()].join(', ') || 'nobody'}\\n`,\n };\n}\n\nexport const INSTALLER = 'https://raw.githubusercontent.com/ai-ecoverse/gh-upskill/main/install.sh';\n\nexport function upskillScript(\n repo: string,\n skill: string | undefined,\n where: { path?: string; all?: boolean } = {}\n): string {\n const from = where.path ? ` --path '${where.path}'` : '';\n const which = where.all ? ' --all' : ` --skill '${skill}'`;\n return [\n 'bin=\"${PNPM_HOME:-$HOME/.local/share/pnpm}/bin\"',\n `{ command -v upskill >/dev/null 2>&1 || curl -fsSL ${INSTALLER} | bash -s -- --bin-dir \"$bin\"; }`,\n `upskill '${repo}'${from}${which} --dest-path \"$HOME/.pi/agent/skills\"`,\n ].join(' && ');\n}\n\nasync function skillsIn(\n env: ExecutionEnv,\n home: string,\n context: Context\n): Promise<Map<string, string>> {\n const root = `${home}/.pi/agent/skills`;\n const found = new Map<string, string>();\n const listed = await env.listDir(root, context);\n for (const info of listed.ok ? listed.value : []) {\n const path = `${root}/${info.name}/SKILL.md`;\n const read = await env.readTextFile(path, context);\n const name = read.ok ? skillFromText(read.value, path, 'user').skills[0]?.name : undefined;\n if (name) found.set(name, path);\n }\n return found;\n}\n\nasync function install(g: G, id: string, context: Context): Promise<Answer> {\n const { env, home } = await callerOf(g, context);\n const item = (await g.load(context)).find((entry) => entry.id === id && entry.kind === 'skill');\n const checked = item ? validate(item) : `there is no skill suggestion ${id}`;\n if (typeof checked === 'string') return fail(checked);\n const { skill, repo, path, all } = checked as Suggestion & { repo: string };\n const what = all ? `the skills${path ? ` in ${path}` : ''}` : (skill as string);\n const before = await skillsIn(env, home, context);\n const existing = skill ? before.get(skill) : undefined;\n if (!all && existing) return fail(`${skill} is already installed in ${existing}`);\n const lines: string[] = [];\n const ran = await env.exec(\n upskillScript(repo, skill, { ...(path ? { path } : {}), ...(all ? { all } : {}) }),\n { cwd: home, onOutput: (text) => void lines.push(text) },\n context\n );\n const output = lines.join('').trim().split('\\n').slice(-8).join('\\n');\n const after = await skillsIn(env, home, context);\n const added = all\n ? [...after].filter(([name, at]) => before.get(name) !== at)\n : [...after].filter(([name]) => name === skill);\n if (!ran.ok || ran.value.exitCode !== 0 || !added.length)\n return fail(\n `upskill couldn't install ${what} from github.com/${repo}${output ? `:\\n${output}` : ''}`\n );\n await g.mark(id, 'takenAt', context);\n const names = added.map(([name]) => name).sort();\n return {\n code: 0,\n out: all\n ? `installed ${names.join(', ')} in ${home}/.pi/agent/skills; ${names.map((name) => `/skill:${name}`).join(', ')} once the skills reload\\n`\n : `installed ${skill} in ${added[0]?.[1]}; it is /skill:${skill} once the skills reload\\n`,\n };\n}\n\ninterface Candidate {\n id: string;\n kind: 'skill' | 'use-case';\n title: string;\n body: string;\n evidence: string;\n score: number;\n skill?: string;\n repo?: string;\n path?: string;\n all?: boolean;\n prompt?: string;\n skills?: string[];\n}\n\nasync function profileFor(g: G, context: Context): Promise<Profile | undefined> {\n const read = await g.options.env.readTextFile(\n `${g.options.profile ?? g.options.home}/${PROFILE}`,\n context\n );\n if (!read.ok) return undefined;\n try {\n return profileOf(JSON.parse(read.value));\n } catch {\n return undefined;\n }\n}\n\nfunction sourceLine(label: string, found: Sheet): string {\n const at = found.fetchedAt ? `, fetched ${new Date(found.fetchedAt).toISOString()}` : '';\n return `${label}: ${found.state} (${found.url}${at})`;\n}\n\nasync function catalog(g: G, argv: readonly string[], context: Context): Promise<Answer> {\n const { env } = g.options;\n const home = g.options.profile ?? g.options.home;\n const mine = await callerOf(g, context);\n const base = g.options.catalog ?? CATALOG_BASE;\n const fetcher: Fetcher = g.options.fetch ?? ((url, init) => globalThis.fetch(url, init));\n const options = { env, fetcher, now: g.now(), refresh: argv.includes('--refresh') };\n const profile = await profileFor(g, context);\n const slug = slugifyCompany(profile?.company);\n const company = slug && !['catalog', 'use-cases'].includes(slug) ? slug : null;\n const [global, own, cases] = await Promise.all([\n sheet(options, `${base}catalog.json`, `${g.catalog}/catalog.json`, context),\n company\n ? sheet(options, `${base}${company}.json`, `${g.catalog}/company-${company}.json`, context)\n : undefined,\n sheet(options, `${base}use-cases.json`, `${g.catalog}/use-cases.json`, context),\n ]);\n const store = await g.load(context);\n const closed = new Set(store.filter((item) => item.dismissedAt || item.takenAt).map((i) => i.id));\n const have = new Set([\n ...(await skillsIn(mine.env, mine.home, context)).keys(),\n ...(g.options.skills?.() ?? []).map((entry) => entry.name),\n ]);\n const evidence = (reasons: string[]) =>\n `www.sliccy.com catalog: ${reasons.length ? reasons.join(', ') : 'featured'}`;\n const skills: Candidate[] = merge(parseSkills(global.rows), parseSkills(own?.rows ?? []))\n .filter((entry) => !entry.skill || !have.has(entry.skill))\n .map((entry) => {\n const ranked = score(entry, profile);\n return {\n id: `catalog-${entry.name}`,\n kind: 'skill',\n title: entry.title,\n body: entry.description || entry.title,\n evidence: evidence(ranked.reasons),\n score: ranked.score,\n ...(entry.skill ? { skill: entry.skill } : {}),\n repo: entry.repo,\n ...(entry.path ? { path: entry.path } : {}),\n ...(entry.all ? { all: true } : {}),\n };\n });\n const uses: Candidate[] = parseUseCases(cases.rows).map((entry) => {\n const ranked = score(entry, profile);\n return {\n id: `catalog-use-${entry.name}`,\n kind: 'use-case',\n title: entry.title,\n body: entry.description || entry.title,\n evidence: evidence(ranked.reasons),\n score: ranked.score,\n prompt: entry.prompt,\n ...(entry.skills.length ? { skills: entry.skills } : {}),\n };\n });\n const all = argv.includes('--all');\n const ranked = [...skills, ...uses]\n .filter((item) => !closed.has(item.id) && (all || item.score > 0))\n .sort((a, b) => b.score - a.score || a.id.localeCompare(b.id));\n const sources = [\n sourceLine('skills', global),\n ...(own ? [sourceLine(`company ${company}`, own)] : []),\n sourceLine('use cases', cases),\n ];\n const who = profile\n ? `profile: ${home}/${PROFILE} (${[profile.role, profile.purpose].filter(Boolean).join(', ') || 'empty'})`\n : `profile: none (${home}/${PROFILE}); ranked by boost only`;\n if (argv.includes('--json'))\n return {\n code: 0,\n out: `${JSON.stringify({ sources, profile: Boolean(profile), candidates: ranked }, null, 2)}\\n`,\n };\n const rows = ranked.map(\n (item) => `${item.score}\\t${item.id}\\t${item.kind}\\t${item.title}\\t${item.evidence}`\n );\n return {\n code: 0,\n out: `${[...sources, who, ...(rows.length ? rows : ['no catalog entries match'])].join('\\n')}\\n`,\n };\n}\n\nasync function list(g: G, argv: readonly string[], context: Context): Promise<Answer> {\n const store = await g.load(context);\n const shown = argv.includes('--all') ? store : open(store);\n if (argv.includes('--json')) return { code: 0, out: `${JSON.stringify(shown, null, 2)}\\n` };\n return { code: 0, out: shown.length ? `${shown.map(row).join('\\n')}\\n` : 'no suggestions\\n' };\n}\n\nasync function status(g: G, context: Context): Promise<Answer> {\n const { env, agents } = g.options;\n const store = await readStore(env, context, g.store);\n const handle = handleOf(agents);\n const read = await g.files.readTextFile(g.crontab, context);\n const scheduled = (read.ok ? read.value : '').split('\\n').map(scheduleOf).find(Boolean);\n const counts = store\n ? `${open(store).length} open, ${store.filter((item) => item.takenAt).length} taken, ${store.filter((item) => item.dismissedAt).length} dismissed`\n : 'none yet';\n const pending = await g.files.readTextFile(g.pending, context);\n const lines = [\n `scoop: ${handle ?? 'none (gelatiere init)'}`,\n `schedule: ${scheduled ?? 'none'}`,\n `store: ${counts}`,\n ...(pending.ok\n ? [\n `procedure: ${g.procedure} has your edits, so it was kept; the new built-in one is ${g.pending}`,\n ]\n : []),\n ];\n return { code: 0, out: `${lines.join('\\n')}\\n` };\n}\n\nasync function dismiss(g: G, id: string, context: Context): Promise<Answer> {\n return (await g.mark(id, 'dismissedAt', context))\n ? { code: 0, out: `dismissed ${id}\\n` }\n : fail(`there is no suggestion ${id}`);\n}\n\nconst VERBS: Record<string, (g: G, argv: readonly string[], context: Context) => Promise<Answer>> =\n {\n init: (g, _argv, context) => init(g, context),\n run: (g, _argv, context) => run(g, context),\n suggest: (g, argv, context) => g.serial(() => suggest(g, argv[1], context)),\n deliver: (g, _argv, context) => g.serial(() => deliver(g, context)),\n install: (g, argv, context) => install(g, argv[1] ?? '', context),\n catalog: (g, argv, context) => catalog(g, argv, context),\n list: (g, argv, context) => list(g, argv, context),\n status: (g, _argv, context) => status(g, context),\n dismiss: (g, argv, context) => dismiss(g, argv[1] ?? '', context),\n };\n\nexport function attachGelatiere(options: GelatiereAttach): GelatiereRuntime {\n const { env, home } = options;\n const now = options.now ?? Date.now;\n const storeFile = options.shared ? storeOf(options.shared) : STORE;\n const load = async (context: Context) => (await readStore(env, context, storeFile)) ?? [];\n let chain: Promise<unknown> = Promise.resolve();\n const serial = <T>(work: () => Promise<T>): Promise<T> => {\n const next = chain.catch(() => undefined).then(work);\n chain = next;\n return next;\n };\n const g: G = {\n serial,\n options,\n now,\n crontab: `${home}/.slicc/crontab`,\n procedure: `${home}/.pi/agent/GELATIERE.md`,\n pending: `${home}/.pi/agent/GELATIERE.new.md`,\n files: options.files ?? env,\n caller: null,\n store: storeFile,\n catalog: options.shared ? `${options.shared}/.gelatiere/catalog` : CATALOG_DIR,\n load,\n mark: (id, field, context) =>\n serial(async () => {\n const store = await load(context);\n const item = store.find((entry) => entry.id === id);\n if (!item) return false;\n item[field] ??= now();\n await writeStore(env, store, context, storeFile);\n return true;\n }),\n };\n const seeded = seed(g, BACKGROUND_CONTEXT, false).catch((): Seeded => 'none');\n return {\n seeded,\n async command(argv, caller, context) {\n const verb = argv[0] ?? 'help';\n const handler = VERBS[verb];\n await seeded;\n if (handler) return handler({ ...g, caller }, argv, context);\n return { code: verb === 'help' || verb === '--help' ? 0 : 2, out: USAGE };\n },\n async intercept(action, data, context) {\n const id = String((data as { id?: unknown } | null)?.id ?? '');\n if (action === 'gelatiere-dismiss') {\n await g.mark(id, 'dismissedAt', context);\n return true;\n }\n if (action === 'gelatiere-install' || action === 'gelatiere-try')\n await g.mark(id, 'takenAt', context);\n return false;\n },\n };\n}\n\nexport function lateGelatiere() {\n let runtime: GelatiereRuntime | undefined;\n return {\n async intercept(\n id: string,\n payload: { action: string; data: unknown },\n context: Context\n ): Promise<boolean> {\n return id === SPRINKLE && runtime !== undefined\n ? runtime.intercept(payload.action, payload.data, context)\n : false;\n },\n command(argv: readonly string[], caller: string | null, context: Context): Promise<Answer> {\n return runtime\n ? runtime.command(argv, caller, context)\n : Promise.resolve({ code: 1, out: 'gelatiere: not ready yet\\n' });\n },\n attach(options: GelatiereAttach): GelatiereRuntime {\n runtime = attachGelatiere(options);\n return runtime;\n },\n };\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 { ExecutionEnv } from '@earendil-works/pi-durable/env';\nimport { type Agents, live } from '../agents.ts';\nimport { ROOT_USER } from '../layout.ts';\nimport { installJobs, readTable, scheduleOf, sendCommand } from '../licks/crontab.ts';\nimport type { Licks } from '../licks/licks.ts';\nimport type { Roles } from '../roles/roles.ts';\nimport type { Scoops } from '../scoops/service.ts';\nimport { skillFromText } from '../skills/skills.ts';\nimport {\n CATALOG_BASE,\n CATALOG_DIR,\n type Fetcher,\n merge,\n PROFILE,\n type Profile,\n parseSkills,\n parseUseCases,\n profileOf,\n type Sheet,\n score,\n sheet,\n slugifyCompany,\n} from './catalog.ts';\nimport {\n fold,\n open,\n readStore,\n STORE,\n type Suggestion,\n storeOf,\n validate,\n writeStore,\n} from './store.ts';\n\nexport type Answer = { code: number; out: string };\n\nexport const ROLE = 'gelatiere';\nexport const SPRINKLE = 'suggestions';\nexport const PROCEDURE = 'packages/vfs-root/gelatiere/GELATIERE.md';\nexport const SCHEDULE = '0 3 * * *';\n\nexport interface GelatiereAttach {\n agents: Agents;\n licks: Licks;\n env: ExecutionEnv;\n home: string;\n scoops: Scoops;\n roles: (context: Context) => Promise<Roles>;\n assets?: (path: string) => Promise<string>;\n now?: () => number;\n fetch?: Fetcher;\n catalog?: string;\n skills?: () => readonly { name: string }[];\n files?: ExecutionEnv;\n profile?: string;\n shared?: string;\n as?: (caller: string | null, context: Context) => Promise<Caller | undefined>;\n cronUser?: (folder: string) => Promise<string>;\n}\n\nexport interface Caller {\n env: ExecutionEnv;\n home: string;\n}\n\nexport interface GelatiereRuntime {\n command(argv: readonly string[], caller: string | null, context: Context): Promise<Answer>;\n intercept(action: string, data: unknown, context: Context): Promise<boolean>;\n readonly seeded: Promise<Seeded>;\n}\n\nexport const USAGE = `usage:\n gelatiere init start the gelatiere scoop and its nightly crontab line\n gelatiere run ask the gelatiere for a pass now\n gelatiere suggest <file> fold a JSON array of suggestions into the store\n gelatiere deliver lick each cone with the suggestions that are new for it\n gelatiere catalog [--refresh] [--all] [--json]\n rank the www.sliccy.com skill and use-case catalog for this user\n gelatiere install <id> install a suggested skill with upskill into ~/.pi/agent/skills\n gelatiere list [--all] [--json]\n gelatiere dismiss <id> mark a suggestion as not wanted\n gelatiere status\n\nThe store is ${STORE}; the suggestions sprinkle shows it.\n`;\n\nexport const PASS = 'Nightly pass: read ~/.pi/agent/GELATIERE.md and follow it.';\n\nfunction handleOf(agents: Agents): string | undefined {\n const found = Object.entries(agents.state().scoops).find(\n ([, record]) => record.role === ROLE && live(record)\n );\n return found?.[1].folder;\n}\n\nfunction row(item: Suggestion): string {\n const state = item.takenAt ? 'taken' : item.dismissedAt ? 'dismissed' : 'open';\n return `${item.id}\\t${item.kind}\\t${state}\\t${item.title}`;\n}\n\ntype G = {\n serial: <T>(work: () => Promise<T>) => Promise<T>;\n options: GelatiereAttach;\n now: () => number;\n procedure: string;\n pending: string;\n load: (context: Context) => Promise<Suggestion[]>;\n mark: (id: string, field: 'dismissedAt' | 'takenAt', context: Context) => Promise<boolean>;\n files: ExecutionEnv;\n caller: string | null;\n store: string;\n catalog: string;\n};\n\nasync function callerOf(g: G, context: Context): Promise<Caller> {\n return (await g.options.as?.(g.caller, context)) ?? { env: g.options.env, home: g.options.home };\n}\n\nconst fail = (out: string): Answer => ({ code: 1, out: `gelatiere: ${out}\\n` });\n\nasync function cronUserOf(g: G, handle: string): Promise<string> {\n return (await g.options.cronUser?.(handle)) ?? ROOT_USER;\n}\n\nasync function schedule(g: G, handle: string, context: Context): Promise<string | undefined> {\n const command = sendCommand(`scoop:${handle}`, PASS);\n const user = await cronUserOf(g, handle);\n const job = { name: ROLE, schedule: SCHEDULE, command };\n const problems = await installJobs(g.options.env, user, [job], context);\n return problems.length ? problems.map((problem) => problem.error).join('; ') : undefined;\n}\n\nexport const SHIPPED = [\n '53bc19daa486dec24116d8cf0558a498d8476dc4e18874f8a3e9ccb9defb15bd',\n '1c16654b93bc01179a71ec907919f45132b2e9f1a9ac331b213655c66387b4e5',\n '3bdd8ae18831c37996413cb0277df7141fcd0dff2d056c7b7053c34f0a3beaac',\n '23a063c8156fda9fb0ffdea20172a7f64c1576d1c009a28456c095e2866fc0e9',\n];\n\nexport type Seeded = 'written' | 'updated' | 'current' | 'kept' | 'none';\n\nasync function sha256(text: string): Promise<string> {\n const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(text));\n return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, '0')).join('');\n}\n\nasync function seed(g: G, context: Context, create: boolean): Promise<Seeded> {\n const { assets } = g.options;\n const env = g.files;\n const text = assets ? await assets(PROCEDURE).catch(() => undefined) : undefined;\n if (text === undefined) return 'none';\n const bundled = await sha256(text);\n const marker = `${g.procedure}.sha256`;\n const must = (result: { ok: boolean; error?: { message: string } }) => {\n if (!result.ok) throw new Error(result.error?.message ?? 'write failed');\n };\n const write = async (state: Seeded): Promise<Seeded> => {\n must(await env.writeFile(g.procedure, text, context));\n must(await env.writeFile(marker, `${bundled}\\n`, context));\n must(await env.remove(g.pending, { force: true }, context));\n return state;\n };\n const read = await env.readTextFile(g.procedure, context);\n if (!read.ok) return create ? write('written') : 'none';\n const mine = await sha256(read.value);\n if (mine === bundled) return write('current');\n const last = await env.readTextFile(marker, context);\n if ((last.ok && last.value.trim() === mine) || SHIPPED.includes(mine)) return write('updated');\n must(await env.writeFile(g.pending, text, context));\n return 'kept';\n}\n\nasync function init(g: G, context: Context): Promise<Answer> {\n const { options } = g;\n await seed(g, context, true);\n let handle = handleOf(options.agents);\n if (!handle) {\n const roles = await options.roles(context);\n const role = roles.roles.find((entry) => entry.name === ROLE);\n if (!role) return fail('the gelatiere role is missing');\n const spawned = await options.scoops.spawn(\n {\n cone: 'cone',\n kind: 'async',\n name: ROLE,\n role,\n prompts: [],\n target: null,\n fromAgent: false,\n request: `gelatiere-init-${g.now()}`,\n limits: roles.limits,\n },\n context\n );\n if (spawned.code !== 0) return { code: 1, out: `gelatiere: ${spawned.out}` };\n handle = spawned.out.trim();\n }\n const refused = await schedule(g, handle, context);\n if (refused) return fail(`couldn't install the crontab line of scoop ${handle}: ${refused}`);\n return {\n code: 0,\n out: `the gelatiere is scoop ${handle}; it runs at ${SCHEDULE} (crontab) and with gelatiere run, following ${g.procedure}\\n`,\n };\n}\n\nasync function run(g: G, context: Context): Promise<Answer> {\n const handle = handleOf(g.options.agents);\n if (!handle) return fail('there is no gelatiere yet; run gelatiere init');\n await g.options.licks.deliver(\n {\n channel: 'sprinkle',\n source: 'sprinkle:gelatiere',\n title: 'Gelatiere',\n text: 'run',\n body: `Run a pass now: read ${g.procedure} and follow it.`,\n target: `scoop:${handle}`,\n },\n context\n );\n return { code: 0, out: `asked scoop ${handle} for a pass\\n` };\n}\n\nasync function suggest(g: G, path: string | undefined, context: Context): Promise<Answer> {\n if (!path) return { code: 2, out: USAGE };\n const read = await (await callerOf(g, context)).env.readTextFile(path, context);\n if (!read.ok) return fail(`can't read ${path}`);\n let parsed: unknown;\n try {\n parsed = JSON.parse(read.value);\n } catch (error) {\n return fail(`${path} is not JSON (${(error as Error).message})`);\n }\n const folded = fold(await g.load(context), parsed, g.now());\n await writeStore(g.options.env, folded.store, context, g.store);\n const rejected = folded.rejected.map((reason) => `rejected ${reason}\\n`).join('');\n return {\n code: 0,\n out: `added ${folded.added}, updated ${folded.updated}, rejected ${folded.rejected.length}\\n${rejected}`,\n };\n}\n\nasync function deliver(g: G, context: Context): Promise<Answer> {\n const store = await g.load(context);\n const fresh = open(store).filter((item) => !item.deliveredAt);\n const cones = Object.keys(g.options.agents.state().cones);\n const byCone = new Map<string, Suggestion[]>();\n for (const item of fresh) {\n const named = (item.cones ?? []).filter((cone) => cones.includes(cone));\n for (const cone of named.length ? named : [g.options.agents.activeCone()])\n byCone.set(cone, [...(byCone.get(cone) ?? []), item]);\n }\n for (const [cone, items] of byCone) {\n const body = {\n added: items.length,\n open: open(store).length,\n suggestions: items.map(({ id, kind, title, body: text }) => ({\n id,\n kind,\n title,\n body: text,\n })),\n path: g.store,\n };\n await g.options.licks.deliver(\n {\n channel: 'sprinkle',\n source: `sprinkle:${SPRINKLE}`,\n title: 'Suggestions',\n text: 'gelatiere-suggestions',\n body: JSON.stringify(body, null, 2),\n target: `cone:${cone}`,\n },\n context\n );\n }\n for (const item of fresh) item.deliveredAt = g.now();\n if (fresh.length) await writeStore(g.options.env, store, context, g.store);\n return {\n code: 0,\n out: `delivered ${fresh.length} to ${[...byCone.keys()].join(', ') || 'nobody'}\\n`,\n };\n}\n\nexport const INSTALLER = 'https://raw.githubusercontent.com/ai-ecoverse/gh-upskill/main/install.sh';\n\nexport function upskillScript(\n repo: string,\n skill: string | undefined,\n where: { path?: string; all?: boolean } = {}\n): string {\n const from = where.path ? ` --path '${where.path}'` : '';\n const which = where.all ? ' --all' : ` --skill '${skill}'`;\n return [\n 'bin=\"${PNPM_HOME:-$HOME/.local/share/pnpm}/bin\"',\n `{ command -v upskill >/dev/null 2>&1 || curl -fsSL ${INSTALLER} | bash -s -- --bin-dir \"$bin\"; }`,\n `upskill '${repo}'${from}${which} --dest-path \"$HOME/.pi/agent/skills\"`,\n ].join(' && ');\n}\n\nasync function skillsIn(\n env: ExecutionEnv,\n home: string,\n context: Context\n): Promise<Map<string, string>> {\n const root = `${home}/.pi/agent/skills`;\n const found = new Map<string, string>();\n const listed = await env.listDir(root, context);\n for (const info of listed.ok ? listed.value : []) {\n const path = `${root}/${info.name}/SKILL.md`;\n const read = await env.readTextFile(path, context);\n const name = read.ok ? skillFromText(read.value, path, 'user').skills[0]?.name : undefined;\n if (name) found.set(name, path);\n }\n return found;\n}\n\nasync function install(g: G, id: string, context: Context): Promise<Answer> {\n const { env, home } = await callerOf(g, context);\n const item = (await g.load(context)).find((entry) => entry.id === id && entry.kind === 'skill');\n const checked = item ? validate(item) : `there is no skill suggestion ${id}`;\n if (typeof checked === 'string') return fail(checked);\n const { skill, repo, path, all } = checked as Suggestion & { repo: string };\n const what = all ? `the skills${path ? ` in ${path}` : ''}` : (skill as string);\n const before = await skillsIn(env, home, context);\n const existing = skill ? before.get(skill) : undefined;\n if (!all && existing) return fail(`${skill} is already installed in ${existing}`);\n const lines: string[] = [];\n const ran = await env.exec(\n upskillScript(repo, skill, { ...(path ? { path } : {}), ...(all ? { all } : {}) }),\n { cwd: home, onOutput: (text) => void lines.push(text) },\n context\n );\n const output = lines.join('').trim().split('\\n').slice(-8).join('\\n');\n const after = await skillsIn(env, home, context);\n const added = all\n ? [...after].filter(([name, at]) => before.get(name) !== at)\n : [...after].filter(([name]) => name === skill);\n if (!ran.ok || ran.value.exitCode !== 0 || !added.length)\n return fail(\n `upskill couldn't install ${what} from github.com/${repo}${output ? `:\\n${output}` : ''}`\n );\n await g.mark(id, 'takenAt', context);\n const names = added.map(([name]) => name).sort();\n return {\n code: 0,\n out: all\n ? `installed ${names.join(', ')} in ${home}/.pi/agent/skills; ${names.map((name) => `/skill:${name}`).join(', ')} once the skills reload\\n`\n : `installed ${skill} in ${added[0]?.[1]}; it is /skill:${skill} once the skills reload\\n`,\n };\n}\n\ninterface Candidate {\n id: string;\n kind: 'skill' | 'use-case';\n title: string;\n body: string;\n evidence: string;\n score: number;\n skill?: string;\n repo?: string;\n path?: string;\n all?: boolean;\n prompt?: string;\n skills?: string[];\n}\n\nasync function profileFor(g: G, context: Context): Promise<Profile | undefined> {\n const read = await g.options.env.readTextFile(\n `${g.options.profile ?? g.options.home}/${PROFILE}`,\n context\n );\n if (!read.ok) return undefined;\n try {\n return profileOf(JSON.parse(read.value));\n } catch {\n return undefined;\n }\n}\n\nfunction sourceLine(label: string, found: Sheet): string {\n const at = found.fetchedAt ? `, fetched ${new Date(found.fetchedAt).toISOString()}` : '';\n return `${label}: ${found.state} (${found.url}${at})`;\n}\n\nasync function catalog(g: G, argv: readonly string[], context: Context): Promise<Answer> {\n const { env } = g.options;\n const home = g.options.profile ?? g.options.home;\n const mine = await callerOf(g, context);\n const base = g.options.catalog ?? CATALOG_BASE;\n const fetcher: Fetcher = g.options.fetch ?? ((url, init) => globalThis.fetch(url, init));\n const options = { env, fetcher, now: g.now(), refresh: argv.includes('--refresh') };\n const profile = await profileFor(g, context);\n const slug = slugifyCompany(profile?.company);\n const company = slug && !['catalog', 'use-cases'].includes(slug) ? slug : null;\n const [global, own, cases] = await Promise.all([\n sheet(options, `${base}catalog.json`, `${g.catalog}/catalog.json`, context),\n company\n ? sheet(options, `${base}${company}.json`, `${g.catalog}/company-${company}.json`, context)\n : undefined,\n sheet(options, `${base}use-cases.json`, `${g.catalog}/use-cases.json`, context),\n ]);\n const store = await g.load(context);\n const closed = new Set(store.filter((item) => item.dismissedAt || item.takenAt).map((i) => i.id));\n const have = new Set([\n ...(await skillsIn(mine.env, mine.home, context)).keys(),\n ...(g.options.skills?.() ?? []).map((entry) => entry.name),\n ]);\n const evidence = (reasons: string[]) =>\n `www.sliccy.com catalog: ${reasons.length ? reasons.join(', ') : 'featured'}`;\n const skills: Candidate[] = merge(parseSkills(global.rows), parseSkills(own?.rows ?? []))\n .filter((entry) => !entry.skill || !have.has(entry.skill))\n .map((entry) => {\n const ranked = score(entry, profile);\n return {\n id: `catalog-${entry.name}`,\n kind: 'skill',\n title: entry.title,\n body: entry.description || entry.title,\n evidence: evidence(ranked.reasons),\n score: ranked.score,\n ...(entry.skill ? { skill: entry.skill } : {}),\n repo: entry.repo,\n ...(entry.path ? { path: entry.path } : {}),\n ...(entry.all ? { all: true } : {}),\n };\n });\n const uses: Candidate[] = parseUseCases(cases.rows).map((entry) => {\n const ranked = score(entry, profile);\n return {\n id: `catalog-use-${entry.name}`,\n kind: 'use-case',\n title: entry.title,\n body: entry.description || entry.title,\n evidence: evidence(ranked.reasons),\n score: ranked.score,\n prompt: entry.prompt,\n ...(entry.skills.length ? { skills: entry.skills } : {}),\n };\n });\n const all = argv.includes('--all');\n const ranked = [...skills, ...uses]\n .filter((item) => !closed.has(item.id) && (all || item.score > 0))\n .sort((a, b) => b.score - a.score || a.id.localeCompare(b.id));\n const sources = [\n sourceLine('skills', global),\n ...(own ? [sourceLine(`company ${company}`, own)] : []),\n sourceLine('use cases', cases),\n ];\n const who = profile\n ? `profile: ${home}/${PROFILE} (${[profile.role, profile.purpose].filter(Boolean).join(', ') || 'empty'})`\n : `profile: none (${home}/${PROFILE}); ranked by boost only`;\n if (argv.includes('--json'))\n return {\n code: 0,\n out: `${JSON.stringify({ sources, profile: Boolean(profile), candidates: ranked }, null, 2)}\\n`,\n };\n const rows = ranked.map(\n (item) => `${item.score}\\t${item.id}\\t${item.kind}\\t${item.title}\\t${item.evidence}`\n );\n return {\n code: 0,\n out: `${[...sources, who, ...(rows.length ? rows : ['no catalog entries match'])].join('\\n')}\\n`,\n };\n}\n\nasync function list(g: G, argv: readonly string[], context: Context): Promise<Answer> {\n const store = await g.load(context);\n const shown = argv.includes('--all') ? store : open(store);\n if (argv.includes('--json')) return { code: 0, out: `${JSON.stringify(shown, null, 2)}\\n` };\n return { code: 0, out: shown.length ? `${shown.map(row).join('\\n')}\\n` : 'no suggestions\\n' };\n}\n\nasync function status(g: G, context: Context): Promise<Answer> {\n const { env, agents } = g.options;\n const store = await readStore(env, context, g.store);\n const handle = handleOf(agents);\n const table = handle ? await readTable(env, await cronUserOf(g, handle), context) : '';\n const scheduled = typeof table === 'string' ? scheduleOf(table, ROLE) : undefined;\n const counts = store\n ? `${open(store).length} open, ${store.filter((item) => item.takenAt).length} taken, ${store.filter((item) => item.dismissedAt).length} dismissed`\n : 'none yet';\n const pending = await g.files.readTextFile(g.pending, context);\n const lines = [\n `scoop: ${handle ?? 'none (gelatiere init)'}`,\n `schedule: ${scheduled ?? 'none'}`,\n `store: ${counts}`,\n ...(pending.ok\n ? [\n `procedure: ${g.procedure} has your edits, so it was kept; the new built-in one is ${g.pending}`,\n ]\n : []),\n ];\n return { code: 0, out: `${lines.join('\\n')}\\n` };\n}\n\nasync function dismiss(g: G, id: string, context: Context): Promise<Answer> {\n return (await g.mark(id, 'dismissedAt', context))\n ? { code: 0, out: `dismissed ${id}\\n` }\n : fail(`there is no suggestion ${id}`);\n}\n\nconst VERBS: Record<string, (g: G, argv: readonly string[], context: Context) => Promise<Answer>> =\n {\n init: (g, _argv, context) => init(g, context),\n run: (g, _argv, context) => run(g, context),\n suggest: (g, argv, context) => g.serial(() => suggest(g, argv[1], context)),\n deliver: (g, _argv, context) => g.serial(() => deliver(g, context)),\n install: (g, argv, context) => install(g, argv[1] ?? '', context),\n catalog: (g, argv, context) => catalog(g, argv, context),\n list: (g, argv, context) => list(g, argv, context),\n status: (g, _argv, context) => status(g, context),\n dismiss: (g, argv, context) => dismiss(g, argv[1] ?? '', context),\n };\n\nexport function attachGelatiere(options: GelatiereAttach): GelatiereRuntime {\n const { env, home } = options;\n const now = options.now ?? Date.now;\n const storeFile = options.shared ? storeOf(options.shared) : STORE;\n const load = async (context: Context) => (await readStore(env, context, storeFile)) ?? [];\n let chain: Promise<unknown> = Promise.resolve();\n const serial = <T>(work: () => Promise<T>): Promise<T> => {\n const next = chain.catch(() => undefined).then(work);\n chain = next;\n return next;\n };\n const g: G = {\n serial,\n options,\n now,\n procedure: `${home}/.pi/agent/GELATIERE.md`,\n pending: `${home}/.pi/agent/GELATIERE.new.md`,\n files: options.files ?? env,\n caller: null,\n store: storeFile,\n catalog: options.shared ? `${options.shared}/.gelatiere/catalog` : CATALOG_DIR,\n load,\n mark: (id, field, context) =>\n serial(async () => {\n const store = await load(context);\n const item = store.find((entry) => entry.id === id);\n if (!item) return false;\n item[field] ??= now();\n await writeStore(env, store, context, storeFile);\n return true;\n }),\n };\n const seeded = seed(g, BACKGROUND_CONTEXT, false).catch((): Seeded => 'none');\n return {\n seeded,\n async command(argv, caller, context) {\n const verb = argv[0] ?? 'help';\n const handler = VERBS[verb];\n await seeded;\n if (handler) return handler({ ...g, caller }, argv, context);\n return { code: verb === 'help' || verb === '--help' ? 0 : 2, out: USAGE };\n },\n async intercept(action, data, context) {\n const id = String((data as { id?: unknown } | null)?.id ?? '');\n if (action === 'gelatiere-dismiss') {\n await g.mark(id, 'dismissedAt', context);\n return true;\n }\n if (action === 'gelatiere-install' || action === 'gelatiere-try')\n await g.mark(id, 'takenAt', context);\n return false;\n },\n };\n}\n\nexport function lateGelatiere() {\n let runtime: GelatiereRuntime | undefined;\n return {\n async intercept(\n id: string,\n payload: { action: string; data: unknown },\n context: Context\n ): Promise<boolean> {\n return id === SPRINKLE && runtime !== undefined\n ? runtime.intercept(payload.action, payload.data, context)\n : false;\n },\n command(argv: readonly string[], caller: string | null, context: Context): Promise<Answer> {\n return runtime\n ? runtime.command(argv, caller, context)\n : Promise.resolve({ code: 1, out: 'gelatiere: not ready yet\\n' });\n },\n attach(options: GelatiereAttach): GelatiereRuntime {\n runtime = attachGelatiere(options);\n return runtime;\n },\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["init", "ranked"]
|
|
7
7
|
}
|
|
@@ -9,10 +9,12 @@ import {
|
|
|
9
9
|
SHARED_DIR,
|
|
10
10
|
usersLayout
|
|
11
11
|
} from "../layout.js";
|
|
12
|
+
import { findScoop } from "../scoops/service.js";
|
|
12
13
|
import {
|
|
13
14
|
CONE_PREFIX,
|
|
14
15
|
createAccounts,
|
|
15
16
|
homeOf,
|
|
17
|
+
scoopUser,
|
|
16
18
|
wanted
|
|
17
19
|
} from "./accounts.js";
|
|
18
20
|
import { HOME, quote, SliccKernelEnv } from "./env.js";
|
|
@@ -120,6 +122,10 @@ function agentUsers(pool, client, root, agents) {
|
|
|
120
122
|
const env = caller ? await this.envOfAgent(caller) : void 0;
|
|
121
123
|
const home = caller ? accounts.home(caller) : void 0;
|
|
122
124
|
return env && home ? { env, home } : { env: root2, home: ROOT_HOME };
|
|
125
|
+
},
|
|
126
|
+
cronUser: async (folder) => {
|
|
127
|
+
await this.envOfAgent(`scoop:${folder}`);
|
|
128
|
+
return scoopUser(folder);
|
|
123
129
|
}
|
|
124
130
|
};
|
|
125
131
|
},
|
|
@@ -133,6 +139,11 @@ function agentUsers(pool, client, root, agents) {
|
|
|
133
139
|
}
|
|
134
140
|
return out;
|
|
135
141
|
},
|
|
142
|
+
cronUser(target, place) {
|
|
143
|
+
if (!target.startsWith("scoop:")) return void 0;
|
|
144
|
+
const found = findScoop(state(), target, place.cone);
|
|
145
|
+
return found ? scoopUser(found[1].folder) : void 0;
|
|
146
|
+
},
|
|
136
147
|
follow(runtimes) {
|
|
137
148
|
listeners.add(() => {
|
|
138
149
|
for (const runtime of runtimes)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/kernel/agent-users.ts"],
|
|
4
|
-
"sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { Agents, AgentsState } from '../agents.ts';\nimport { FIRST_CONE } from '../agents.ts';\nimport type { GelatiereAttach } from '../gelatiere/index.ts';\nimport {\n AGENT_DIR,\n type Layout,\n LEGACY,\n ROOT_HOME,\n ROOT_USER,\n SESSIONS,\n SHARED_DIR,\n usersLayout,\n} from '../layout.ts';\nimport type { LickDir } from '../licks/sources.ts';\nimport type { Spools } from '../scoops/index.ts';\nimport type { SkillPeople } from '../skills/index.ts';\nimport type { SprinklePlace, SprinklesAttach } from '../sprinkles/index.ts';\nimport {\n type Accounts,\n CONE_PREFIX,\n createAccounts,\n homeOf,\n type UsersMode,\n wanted,\n} from './accounts.ts';\nimport type { KernelClient } from './client.ts';\nimport { type EnvRoute, type EnvTargetLike, HOME, quote, SliccKernelEnv } from './env.ts';\nimport type { UserClients } from './users.ts';\n\nexport interface AgentUsers {\n readonly accounts: Accounts;\n readonly layout: Layout;\n readonly spools: Spools;\n readonly enforced: boolean;\n readonly people: SkillPeople;\n follow(\n runtimes: readonly {\n reload?(context: Context): Promise<void>;\n reconcile?(context: Context): Promise<void>;\n }[]\n ): void;\n lickDirs(): Promise<LickDir[]>;\n sprinklePlaces(): SprinklePlace[];\n sprinkles(): Partial<SprinklesAttach>;\n envOfAgent(agentId: string): Promise<SliccKernelEnv | undefined>;\n gelatiere(root: SliccKernelEnv): Promise<Partial<GelatiereAttach>>;\n route(target: EnvTargetLike): Promise<EnvRoute | undefined>;\n start(agents: Agents): Promise<void>;\n close(): void;\n}\n\nexport function modeOf(client: KernelClient): UsersMode {\n const mode = (client as { users?: unknown }).users;\n return mode === 'report' || mode === 'enforce' ? mode : 'off';\n}\n\nexport async function missingSupport(\n pool: UserClients | undefined,\n client: KernelClient,\n requested: boolean | undefined\n): Promise<string[]> {\n if (!pool) return requested === true ? ['admin (the page passed no KernelSource.users)'] : [];\n const missing: string[] = [];\n if (\n !(await pool.users.list().then(\n () => true,\n () => false\n ))\n )\n missing.push('users');\n if ((client as { users?: unknown }).users === undefined)\n missing.push('the users mode (kernel 1.57)');\n if (\n !(await pool.groups.list().then(\n () => true,\n () => false\n ))\n )\n missing.push('groups and homeMode (kernel 1.60 and KernelSource.groups)');\n return missing;\n}\n\nexport async function warnSupport(\n pool: UserClients | undefined,\n client: KernelClient,\n requested: boolean | undefined,\n report: (message: string) => void = (message) => console.error(message)\n): Promise<void> {\n const missing = await missingSupport(pool, client, requested);\n if (missing.length)\n report(\n `slicc-agent: kernel users were requested, but this kernel or page lacks ${missing.join(', ')}`\n );\n}\n\nexport function legacyCwd(state: Readonly<AgentsState>, agentId: string, cwd: string): boolean {\n if (cwd === HOME) return true;\n const record = state.scoops[agentId];\n return record !== undefined && cwd === LEGACY.workspace(record.folder);\n}\n\nexport function spoolScript(user: string, dir: string): string {\n const at = quote(dir);\n const made = `mkdir -p ${at}/in ${at}/out`;\n if (user === ROOT_USER) return made;\n return `${made} && chown -R ${quote(`${user}:${user}`)} ${at} && chmod 700 ${at} ${at}/in ${at}/out`;\n}\n\nexport function agentUsers(\n pool: UserClients,\n client: KernelClient,\n root: SliccKernelEnv,\n agents: () => Agents | undefined\n): AgentUsers {\n const mode = modeOf(client);\n const accounts = createAccounts(pool, agents, mode, pool.groups);\n const state = () => agents()?.state() ?? { cones: {}, active: 'cone', next: 2, scoops: {} };\n const envOf = async (agentId: string, home: string) =>\n new SliccKernelEnv(await accounts.client(agentId), { cwd: home });\n const layout = usersLayout(state, envOf, root);\n let ready: () => void = () => undefined;\n const started = new Promise<void>((resolve) => {\n ready = resolve;\n });\n let off: () => void = () => undefined;\n const homes = () => wanted(state()).map((entry) => homeOf(entry.spec.name));\n const listeners = new Set<() => void>();\n let known = '';\n const changed = () => {\n const key = homes().join('\\n');\n if (key === known) return;\n known = key;\n for (const listener of listeners) listener();\n };\n return {\n accounts,\n layout,\n enforced: mode === 'enforce',\n people: {\n homes,\n homeOfAgent(agentId) {\n return accounts.home(agentId) ?? accounts.home(`${CONE_PREFIX}${agentId}`);\n },\n homeOf(conversationId) {\n const agentId = accounts.agentOf(conversationId);\n return agentId ? accounts.home(agentId) : undefined;\n },\n async envOf(at) {\n const user = wanted(state()).find((entry) => homeOf(entry.spec.name) === at);\n return user ? envOf(user.agentId, at).catch(() => undefined) : undefined;\n },\n },\n sprinklePlaces() {\n return wanted(state())\n .filter((entry) => !entry.cone)\n .map((entry) => ({ dir: `${homeOf(entry.spec.name)}/sprinkles`, cone: entry.spec.name }));\n },\n sprinkles() {\n return {\n places: () => this.sprinklePlaces(),\n envOf: (agentId: string) => this.envOfAgent(agentId),\n homeOf: (agentId: string) => accounts.home(agentId),\n shared: SHARED_DIR,\n };\n },\n async envOfAgent(agentId) {\n const home = accounts.home(agentId);\n return home ? envOf(agentId, home).catch(() => undefined) : undefined;\n },\n async gelatiere(root) {\n const first = `${CONE_PREFIX}${FIRST_CONE}`;\n const files = await this.envOfAgent(first);\n return {\n home: homeOf(FIRST_CONE),\n profile: SHARED_DIR,\n shared: SHARED_DIR,\n ...(files ? { files } : {}),\n as: async (caller) => {\n const env = caller ? await this.envOfAgent(caller) : undefined;\n const home = caller ? accounts.home(caller) : undefined;\n return env && home ? { env, home } : { env: root, home: ROOT_HOME };\n },\n };\n },\n async lickDirs() {\n const cones = wanted(state()).filter((entry) => !entry.cone);\n const out: LickDir[] = [{ dir: `${ROOT_HOME}/.slicc`, home: ROOT_HOME, cone: null }];\n for (const entry of cones) {\n const home = homeOf(entry.spec.name);\n const env = await envOf(entry.agentId, home).catch(() => undefined);\n out.push({ dir: `${home}/.slicc`, home, cone: entry.spec.name, ...(env ? { env } : {}) });\n }\n return out;\n },\n follow(runtimes) {\n listeners.add(() => {\n for (const runtime of runtimes)\n void (runtime.reconcile ?? runtime.reload)\n ?.call(runtime, BACKGROUND_CONTEXT)\n .catch(() => undefined);\n });\n },\n spools: {\n users: () => [ROOT_USER, ...wanted(state()).map((entry) => entry.spec.name)],\n async prepare(user, dir, context) {\n await root.exec(spoolScript(user, dir), undefined, context);\n },\n },\n async route(target) {\n await started;\n const agentId = accounts.agentOf(target.conversationId);\n const home = agentId ? accounts.home(agentId) : undefined;\n if (!agentId || !home) return undefined;\n const legacy = target.cwd !== undefined && legacyCwd(state(), agentId, target.cwd);\n return { client: await accounts.client(agentId), home, ...(legacy ? { cwd: home } : {}) };\n },\n async start(opened) {\n await root.exec(\n `mkdir -p ${SESSIONS.tmp} ${AGENT_DIR} ${SHARED_DIR} && chmod 1777 ${SESSIONS.tmp} && chmod 755 ${AGENT_DIR} && chmod 700 ${SHARED_DIR}`,\n undefined,\n BACKGROUND_CONTEXT\n );\n await accounts.boot();\n known = homes().join('\\n');\n off = opened.onChange(() => {\n void accounts.reconcile();\n changed();\n });\n ready();\n },\n close() {\n off();\n },\n };\n}\n"],
|
|
5
|
-
"mappings": "AACA,SAAS,0BAA0B;AAEnC,SAAS,kBAAkB;AAE3B;AAAA,EACE;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;
|
|
4
|
+
"sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { Agents, AgentsState } from '../agents.ts';\nimport { FIRST_CONE } from '../agents.ts';\nimport type { GelatiereAttach } from '../gelatiere/index.ts';\nimport {\n AGENT_DIR,\n type Layout,\n LEGACY,\n ROOT_HOME,\n ROOT_USER,\n SESSIONS,\n SHARED_DIR,\n usersLayout,\n} from '../layout.ts';\nimport type { LickTarget } from '../licks/lick.ts';\nimport type { LickDir } from '../licks/sources.ts';\nimport type { Spools } from '../scoops/index.ts';\nimport { findScoop } from '../scoops/service.ts';\nimport type { SkillPeople } from '../skills/index.ts';\nimport type { SprinklePlace, SprinklesAttach } from '../sprinkles/index.ts';\nimport {\n type Accounts,\n CONE_PREFIX,\n createAccounts,\n homeOf,\n scoopUser,\n type UsersMode,\n wanted,\n} from './accounts.ts';\nimport type { KernelClient } from './client.ts';\nimport { type EnvRoute, type EnvTargetLike, HOME, quote, SliccKernelEnv } from './env.ts';\nimport type { UserClients } from './users.ts';\n\nexport interface AgentUsers {\n readonly accounts: Accounts;\n readonly layout: Layout;\n readonly spools: Spools;\n readonly enforced: boolean;\n readonly people: SkillPeople;\n follow(\n runtimes: readonly {\n reload?(context: Context): Promise<void>;\n reconcile?(context: Context): Promise<void>;\n }[]\n ): void;\n lickDirs(): Promise<LickDir[]>;\n cronUser(target: LickTarget, place: LickDir): string | undefined;\n sprinklePlaces(): SprinklePlace[];\n sprinkles(): Partial<SprinklesAttach>;\n envOfAgent(agentId: string): Promise<SliccKernelEnv | undefined>;\n gelatiere(root: SliccKernelEnv): Promise<Partial<GelatiereAttach>>;\n route(target: EnvTargetLike): Promise<EnvRoute | undefined>;\n start(agents: Agents): Promise<void>;\n close(): void;\n}\n\nexport function modeOf(client: KernelClient): UsersMode {\n const mode = (client as { users?: unknown }).users;\n return mode === 'report' || mode === 'enforce' ? mode : 'off';\n}\n\nexport async function missingSupport(\n pool: UserClients | undefined,\n client: KernelClient,\n requested: boolean | undefined\n): Promise<string[]> {\n if (!pool) return requested === true ? ['admin (the page passed no KernelSource.users)'] : [];\n const missing: string[] = [];\n if (\n !(await pool.users.list().then(\n () => true,\n () => false\n ))\n )\n missing.push('users');\n if ((client as { users?: unknown }).users === undefined)\n missing.push('the users mode (kernel 1.57)');\n if (\n !(await pool.groups.list().then(\n () => true,\n () => false\n ))\n )\n missing.push('groups and homeMode (kernel 1.60 and KernelSource.groups)');\n return missing;\n}\n\nexport async function warnSupport(\n pool: UserClients | undefined,\n client: KernelClient,\n requested: boolean | undefined,\n report: (message: string) => void = (message) => console.error(message)\n): Promise<void> {\n const missing = await missingSupport(pool, client, requested);\n if (missing.length)\n report(\n `slicc-agent: kernel users were requested, but this kernel or page lacks ${missing.join(', ')}`\n );\n}\n\nexport function legacyCwd(state: Readonly<AgentsState>, agentId: string, cwd: string): boolean {\n if (cwd === HOME) return true;\n const record = state.scoops[agentId];\n return record !== undefined && cwd === LEGACY.workspace(record.folder);\n}\n\nexport function spoolScript(user: string, dir: string): string {\n const at = quote(dir);\n const made = `mkdir -p ${at}/in ${at}/out`;\n if (user === ROOT_USER) return made;\n return `${made} && chown -R ${quote(`${user}:${user}`)} ${at} && chmod 700 ${at} ${at}/in ${at}/out`;\n}\n\nexport function agentUsers(\n pool: UserClients,\n client: KernelClient,\n root: SliccKernelEnv,\n agents: () => Agents | undefined\n): AgentUsers {\n const mode = modeOf(client);\n const accounts = createAccounts(pool, agents, mode, pool.groups);\n const state = () => agents()?.state() ?? { cones: {}, active: 'cone', next: 2, scoops: {} };\n const envOf = async (agentId: string, home: string) =>\n new SliccKernelEnv(await accounts.client(agentId), { cwd: home });\n const layout = usersLayout(state, envOf, root);\n let ready: () => void = () => undefined;\n const started = new Promise<void>((resolve) => {\n ready = resolve;\n });\n let off: () => void = () => undefined;\n const homes = () => wanted(state()).map((entry) => homeOf(entry.spec.name));\n const listeners = new Set<() => void>();\n let known = '';\n const changed = () => {\n const key = homes().join('\\n');\n if (key === known) return;\n known = key;\n for (const listener of listeners) listener();\n };\n return {\n accounts,\n layout,\n enforced: mode === 'enforce',\n people: {\n homes,\n homeOfAgent(agentId) {\n return accounts.home(agentId) ?? accounts.home(`${CONE_PREFIX}${agentId}`);\n },\n homeOf(conversationId) {\n const agentId = accounts.agentOf(conversationId);\n return agentId ? accounts.home(agentId) : undefined;\n },\n async envOf(at) {\n const user = wanted(state()).find((entry) => homeOf(entry.spec.name) === at);\n return user ? envOf(user.agentId, at).catch(() => undefined) : undefined;\n },\n },\n sprinklePlaces() {\n return wanted(state())\n .filter((entry) => !entry.cone)\n .map((entry) => ({ dir: `${homeOf(entry.spec.name)}/sprinkles`, cone: entry.spec.name }));\n },\n sprinkles() {\n return {\n places: () => this.sprinklePlaces(),\n envOf: (agentId: string) => this.envOfAgent(agentId),\n homeOf: (agentId: string) => accounts.home(agentId),\n shared: SHARED_DIR,\n };\n },\n async envOfAgent(agentId) {\n const home = accounts.home(agentId);\n return home ? envOf(agentId, home).catch(() => undefined) : undefined;\n },\n async gelatiere(root) {\n const first = `${CONE_PREFIX}${FIRST_CONE}`;\n const files = await this.envOfAgent(first);\n return {\n home: homeOf(FIRST_CONE),\n profile: SHARED_DIR,\n shared: SHARED_DIR,\n ...(files ? { files } : {}),\n as: async (caller) => {\n const env = caller ? await this.envOfAgent(caller) : undefined;\n const home = caller ? accounts.home(caller) : undefined;\n return env && home ? { env, home } : { env: root, home: ROOT_HOME };\n },\n cronUser: async (folder) => {\n await this.envOfAgent(`scoop:${folder}`);\n return scoopUser(folder);\n },\n };\n },\n async lickDirs() {\n const cones = wanted(state()).filter((entry) => !entry.cone);\n const out: LickDir[] = [{ dir: `${ROOT_HOME}/.slicc`, home: ROOT_HOME, cone: null }];\n for (const entry of cones) {\n const home = homeOf(entry.spec.name);\n const env = await envOf(entry.agentId, home).catch(() => undefined);\n out.push({ dir: `${home}/.slicc`, home, cone: entry.spec.name, ...(env ? { env } : {}) });\n }\n return out;\n },\n cronUser(target, place) {\n if (!target.startsWith('scoop:')) return undefined;\n const found = findScoop(state(), target, place.cone);\n return found ? scoopUser(found[1].folder) : undefined;\n },\n follow(runtimes) {\n listeners.add(() => {\n for (const runtime of runtimes)\n void (runtime.reconcile ?? runtime.reload)\n ?.call(runtime, BACKGROUND_CONTEXT)\n .catch(() => undefined);\n });\n },\n spools: {\n users: () => [ROOT_USER, ...wanted(state()).map((entry) => entry.spec.name)],\n async prepare(user, dir, context) {\n await root.exec(spoolScript(user, dir), undefined, context);\n },\n },\n async route(target) {\n await started;\n const agentId = accounts.agentOf(target.conversationId);\n const home = agentId ? accounts.home(agentId) : undefined;\n if (!agentId || !home) return undefined;\n const legacy = target.cwd !== undefined && legacyCwd(state(), agentId, target.cwd);\n return { client: await accounts.client(agentId), home, ...(legacy ? { cwd: home } : {}) };\n },\n async start(opened) {\n await root.exec(\n `mkdir -p ${SESSIONS.tmp} ${AGENT_DIR} ${SHARED_DIR} && chmod 1777 ${SESSIONS.tmp} && chmod 755 ${AGENT_DIR} && chmod 700 ${SHARED_DIR}`,\n undefined,\n BACKGROUND_CONTEXT\n );\n await accounts.boot();\n known = homes().join('\\n');\n off = opened.onChange(() => {\n void accounts.reconcile();\n changed();\n });\n ready();\n },\n close() {\n off();\n },\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["root"]
|
|
7
7
|
}
|
package/dist/licks/boot.js
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
defineDoc
|
|
3
|
+
} from "@earendil-works/pi-durable";
|
|
4
|
+
const LicksHostDoc = defineDoc({
|
|
5
|
+
kind: "slicc.licks.host",
|
|
6
|
+
version: 1,
|
|
7
|
+
scope: "session",
|
|
8
|
+
initial: () => ({ cron: {}, agent: null, boot: null, mark: 0, upgrades: 0 })
|
|
9
|
+
});
|
|
2
10
|
const BACKGROUND = /(?:&\s*$|&\s*disown\b|\bnohup\b|\bsetsid\b)/m;
|
|
3
11
|
function bashCommands(entries, after) {
|
|
4
12
|
const commands = [];
|
|
@@ -60,6 +68,7 @@ async function bootLicks(harness, cone, deliver, facts, context) {
|
|
|
60
68
|
}, context);
|
|
61
69
|
}
|
|
62
70
|
export {
|
|
71
|
+
LicksHostDoc,
|
|
63
72
|
bashCommands,
|
|
64
73
|
bootLicks
|
|
65
74
|
};
|